diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index 176a458f94..0000000000 --- a/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -* text=auto diff --git a/.gitignore b/.gitignore index 4f9405a16a..dc5b9dab73 100644 --- a/.gitignore +++ b/.gitignore @@ -1,24 +1,25 @@ -/installed.xml -/indra/llcommon/llversionviewer.h /indra/build-* /indra/tools/vstool/obj/ *.aps *.suo *.vshost.exe +*/.vs /bin/ /bin-release/ /bin /bin-release +/indra/out/ /indra/viewer-* /indra/newview/vivox-runtime/ /indra/newview/dbghelp.dll +indra/newview/res/viewer_icon.* +indra/newview/res-sdl/viewer_icon.* /libraries/ /lib/ *.pyc *.orig *.rej *.bak -*~ *.DS_Store /LICENSES/ /edited-files.txt @@ -26,3 +27,4 @@ qtcreator-build/ /.pc /build-* /viewer-* +/Pipfile.lock diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000000..c32bcbe202 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,286 @@ +stages: + - build + - upload + +default: + interruptible: true + timeout: 4h + +variables: + AUTOBUILD_BUILD_ID: $CI_PIPELINE_ID + AUTOBUILD_INSTALLABLE_CACHE: "$CI_PROJECT_DIR/.cache/autobuild" + PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip" + VIEWER_USE_CRASHPAD: "TRUE" + VIEWER_CRASHPAD_URL: $SENTRY_DSN + +.win_build: + stage: build + tags: + - autobuild + - windows + cache: + key: + files: + - autobuild.xml + prefix: ${CI_JOB_NAME} + paths: + - .cache/autobuild + - .cache/pip + - .venv/ + when: 'always' + before_script: + - virtualenv .venv + - .\.venv\Scripts\activate.ps1 + - pip install --upgrade autobuild -i https://pkg.alchemyviewer.org/repository/autobuild/simple --extra-index-url https://pypi.org/simple + script: + - | + autobuild configure -c Release -- -DUSE_FMODSTUDIO=ON -DUSE_NVAPI=ON -DUSE_LTO=ON -DVS_DISABLE_FATAL_WARNINGS=ON -DREVISION_FROM_VCS=FALSE + autobuild build -c Release --no-configure + artifacts: + name: "$env:CI_COMMIT_REF_NAME-$env:CI_COMMIT_SHORT_SHA" + expire_in: 1 week + paths: + - build-vc-*/newview/Release/build_data.json + - build-vc-*/newview/Release/singularity-bin.exe + - build-vc-*/newview/Release/*.pdb + - build-vc-*/newview/Release/*.dll + - build-vc-*/newview/Release/Singularity_*_Setup.exe + +.linux_build: + stage: build + image: r.alchemyviewer.org/singularity/infrastructure/debian-build-image:latest + tags: + - linux + - docker + cache: + key: + files: + - autobuild.xml + prefix: ${CI_JOB_NAME} + paths: + - .cache/autobuild + - .cache/pip + - .venv + when: 'always' + before_script: + - virtualenv .venv -p python2 + - source .venv/bin/activate + - pip install --upgrade autobuild -i https://pkg.alchemyviewer.org/repository/autobuild/simple --extra-index-url https://pypi.org/simple + script: + - | + autobuild configure -c Release -- -DUSE_FMODSTUDIO=ON -DUSE_NVAPI=ON -DUSE_LTO=ON -DUNIX_DISABLE_FATAL_WARNINGS=ON -DREVISION_FROM_VCS=FALSE + autobuild build -c Release --no-configure + artifacts: + name: "$env:CI_COMMIT_REF_NAME-$env:CI_COMMIT_SHORT_SHA" + expire_in: 1 week + paths: + - build-linux-*/build_data.json + - build-linux-*/newview/Singularity_*.tar.xz + +.win32_build: + extends: .win_build + variables: + AUTOBUILD_ADDRSIZE: 32 + VIEWER_USE_CRASHPAD: "FALSE" + cache: + key: + prefix: windows32 + +.win64_build: + extends: .win_build + variables: + AUTOBUILD_ADDRSIZE: 64 + cache: + key: + prefix: windows64 + +.linux32_build: + extends: .linux_build + variables: + AUTOBUILD_ADDRSIZE: 32 + cache: + key: + prefix: linux32 + +.linux64_build: + extends: .linux_build + variables: + AUTOBUILD_ADDRSIZE: 64 + cache: + key: + prefix: linux64 + +.master_rules: + rules: + - if: $BUILD_CHANNEL || $CI_COMMIT_TAG + when: never + - if: '$CI_PIPELINE_SOURCE == "web"' + - if: '$CI_PIPELINE_SOURCE == "schedule"' + #- if: '$CI_COMMIT_BRANCH == "master" && $CI_PIPELINE_SOURCE == "push"' + # when: delayed + # start_in: '12 hours' + variables: + VIEWER_CHANNEL_TYPE: Test + VIEWER_USE_CRASHPAD: "FALSE" + +.project_rules: + rules: + - if: '$BUILD_CHANNEL == "Project" && ($CI_PIPELINE_SOURCE == "web" || $CI_PIPELINE_SOURCE == "schedule")' + - if: '$CI_COMMIT_TAG =~ /.*-project/' + variables: + VIEWER_CHANNEL_TYPE: Project + +.beta_rules: + rules: + - if: '$BUILD_CHANNEL == "Beta" && ($CI_PIPELINE_SOURCE == "web" || $CI_PIPELINE_SOURCE == "schedule")' + - if: '$CI_COMMIT_TAG =~ /.*-beta/' + variables: + VIEWER_CHANNEL_TYPE: Beta + +.release_rules: + rules: + - if: '$BUILD_CHANNEL == "Release" && ($CI_PIPELINE_SOURCE == "web" || $CI_PIPELINE_SOURCE == "schedule")' + - if: '$CI_COMMIT_TAG =~ /.*-release/' + variables: + VIEWER_CHANNEL_TYPE: Release + +.build:master:linux64: + extends: + - .linux64_build + - .master_rules + +build:master:windows32: + extends: + - .win32_build + - .master_rules + +build:master:windows64: + extends: + - .win64_build + - .master_rules + +.build:project:linux64: + extends: + - .linux64_build + - .project_rules + +build:project:windows32: + extends: + - .win32_build + - .project_rules + +build:project:windows64: + extends: + - .win64_build + - .project_rules + +.build:beta:linux64: + extends: + - .linux64_build + - .beta_rules + +build:beta:windows32: + extends: + - .win32_build + - .beta_rules + +build:beta:windows64: + extends: + - .win64_build + - .beta_rules + +.build:release:linux64: + extends: + - .linux64_build + - .release_rules + +build:release:windows32: + extends: + - .win32_build + - .release_rules + +build:release:windows64: + extends: + - .win64_build + - .release_rules + +.upload_template: + stage: upload + tags: + - autobuild + - windows + allow_failure: false + script: + - | + $BuildData = Get-Content .\build-vc-64\newview\Release\build_data.json | ConvertFrom-Json + $BuildChannelVersion = $BuildData."Channel" + ' ' + $BuildData."Version" + $UploadDestViewerDir = $BuildChannelVersion.ToLower().Replace(" ", "/") + $UploadDestURL = "https://pkg.alchemyviewer.org/repository/viewer/${UploadDestViewerDir}" + + $UploadParams = @{ UseBasicParsing = $true; + Method = "PUT"; + Headers = @{ + ContentType = "application/x-executable"; + Authorization = "Basic $([System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes("$env:AUTOBUILD_HTTP_USER`:$env:AUTOBUILD_HTTP_PASS")))"; }; + Verbose = $true; }; + + Function try_upload($build_type, $file_pattern) + { + $build_newview = ".\build-${build_type}\newview\" + If (Test-Path -LiteralPath $build_newview) + { + Push-Location $build_newview + $FileName = Get-ChildItem -Path . -Name -Include $file_pattern + Invoke-WebRequest @UploadParams -InFile .\$FileName -Uri "${UploadDestURL}/${FileName}" + + If (($env:VIEWER_USE_CRASHPAD -eq 'TRUE') -and ($build_type -eq "vc-64")) + { + sentry-cli upload-dif --include-sources singularity-bin.exe singularity-bin.pdb crashpad_handler.exe crashpad_handler.pdb fmod.dll libcrypto-1_1.dll libcrypto-1_1.pdb libssl-1_1.dll libssl-1_1.pdb libcrypto-1_1-x64.dll libcrypto-1_1-x64.pdb libssl-1_1-x64.dll libssl-1_1-x64.pdb vcruntime140.dll msvcp140.dll libhunspell.dll libhunspell.pdb glod.dll + } + Pop-Location + } + } + + try_upload("linux-64", "Singularity_*.tar.xz") + try_upload("vc-64", "Singularity_*_Setup.exe") + try_upload("vc-32", "Singularity_*_Setup.exe") + + If ($env:VIEWER_USE_CRASHPAD -eq 'TRUE') + { + sentry-cli releases new $BuildChannelVersion + sentry-cli releases set-commits --auto $BuildChannelVersion + sentry-cli releases finalize $BuildChannelVersion + } + +upload:project: + extends: + - .upload_template + rules: + - if: '$BUILD_CHANNEL == "Project" && ($CI_PIPELINE_SOURCE == "web" || $CI_PIPELINE_SOURCE == "schedule")' + when: manual + - if: '$CI_COMMIT_TAG =~ /.*-project/' + when: manual + environment: + name: qa + +upload:beta: + extends: + - .upload_template + rules: + - if: '$BUILD_CHANNEL == "Beta" && ($CI_PIPELINE_SOURCE == "web" || $CI_PIPELINE_SOURCE == "schedule")' + when: manual + - if: '$CI_COMMIT_TAG =~ /.*-beta/' + when: manual + environment: + name: beta + +upload:release: + extends: + - .upload_template + rules: + - if: '$BUILD_CHANNEL == "Release" && ($CI_PIPELINE_SOURCE == "web" || $CI_PIPELINE_SOURCE == "schedule")' + when: manual + - if: '$CI_COMMIT_TAG =~ /.*-release/' + when: manual + environment: + name: release diff --git a/AscentChangelog.txt b/AscentChangelog.txt deleted file mode 100644 index d7c9aff00c..0000000000 --- a/AscentChangelog.txt +++ /dev/null @@ -1,81 +0,0 @@ -->> Features implemented in Ascent: - -In-World: -------------------------------------------------- -* Alpha skins and Tattoo Layers -* Inventory Pre-caching -* Avatar Radar -* Multiple Attachment Points -* Idle time of avatars around you (Not perfect) -* Client tags/coloring for various clients, and extra client definitions -* Force Away button to fake being away if you really want to avoid someone :V -* Double-Click teleport (Not all the functionality of Emerald yet) -Preferences (Options are in Ascent Options): -* Disable Look At -* Disable Point At and beam end -* Fetch inventory in background on login (No waiting for caching when searching) -* Display your client tag to yourself -* Display your client tag color to yourself -* Rez objects as land group when possible -* Some settings can now be saved per account after changing an option in the preferences. Currently affected settings: - Edit Beam color - Client Tag Color -Communication Window: -- Friend List: - * Friend List Online/Total counts (Not perfect) - * Shows what rights your friends have given you (Mod, See on map, Online) - -Chat Bar: -* Emerald-style Chatbar as Commandline (See Preferences) -* MU-style poses. -* OOC Auto-close. - -Instant Messages: -* MU-style poses. -* OOC Auto-close. - -Advanced -> Ascent: -* Fake Away Status -* Force Ground Sit (Lets you sit anywhere) -* Phantom Avatar (Prevents you visually from being pushed.) -* Toggle IM Notification (Ability to hide '%n is typing...' notification from being sent.) -* Close All Dialogs -* Message Log -* Message Builder -* Sound Explorer -* Asset Blacklist -* AO options - -Object Pie Menus: -* Measure: Select on one object, then another, to get the exact distance between the two -* Data: Reports prim rotation and position in a format usable in LSL scripts. -* Script Counter - -Self Pie Menu: -* Animation Explorer - -Agent Pie Menus: -* Script Counter -* Copy Agent UUID -* Debug - -Parcel Window: -------------------------------------------------- -- General tab: -- Objects tab: - * In Sim/Online/Offline indicators for Parcel Object Owner listings (Online is currently wonky - This is an issue with SL, Emerald has the same problem.) - -Build Window: -------------------------------------------------- -- General tab: - * Last Owner shown in Build "General" Tab - * Group object is set to has a "View" button to see the group's profile - * Copy Object Key button -- Build Tab: - * Copy/Paste Position buttons - * Copy/Paste Size buttons - * Copy/Paste Rotation buttons - * Copy/Paste Primitive Parameters buttons - -Known issues: -Online/Total counts in the friends list sometimes go haywire. Not often or by a large margin, but it happens. \ No newline at end of file diff --git a/LICENSES/LEGAL-intel_matrixlib.txt b/LICENSES/LEGAL-intel_matrixlib.txt new file mode 100644 index 0000000000..7ab64f5955 --- /dev/null +++ b/LICENSES/LEGAL-intel_matrixlib.txt @@ -0,0 +1,29 @@ +INTEL LICENSE AGREEMENT + +IMPORTANT - READ BEFORE COPYING OR USING. +Do not use or load this library and any associated materials (collectively, +the "Software") until you have read the following terms and conditions. By +loading or using the Software, you agree to the terms of this Agreement. If +you do not wish to so agree, do not use the Software. + +LICENSE: Subject to the restrictions below, Intel Corporation ("Intel") +grants to you the permission to use, copy, distribute and prepare derivative +works of this Software for any purpose and without fee, provided, that +Intel's copyright notice appear in all copies of the Software files. +The distribution of derivative works of the Software is also subject to the +following limitations: you (i) are solely responsible to your customers for +any liability which may arise from the distribution, (ii) do not make any +statement that your product is "certified", or that its performance is +guaranteed, by Intel, and (iii) do not use Intel's name or trademarks to +market your product without written permission. + +EXCLUSION OF ALL WARRANTIES. The Software is provided "AS IS" without any +express or implies warranty of any kind including warranties of +merchantability, noninfringement, or fitness for a particular purpose. +Intel does not warrant or assume responsibility for the accuracy or +completeness of any information contained within the Software. +As this Software is given free of charge, in no event shall Intel be liable +for any damages whatsoever arising out of the use of or inability to use the +Software, even if Intel has been adviced of the possibility of such damages. +Intel does not assume any responsibility for any errors which may appear in +this Software nor any responsibility to update it. diff --git a/Pipfile b/Pipfile new file mode 100644 index 0000000000..81e20cec2d --- /dev/null +++ b/Pipfile @@ -0,0 +1,14 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[dev-packages] + +[packages] +llbase = "*" +certifi = "*" +autobuild = {git = "https://git.alchemyviewer.org/alchemy/autobuild.git"} + +[requires] +python_version = "2.7" diff --git a/README b/README index a441bfedfe..17136fb371 100644 --- a/README +++ b/README @@ -15,10 +15,10 @@ Singularity Viewer is a SecondLife(tm) protocol compatible client application. It can be used to access SecondLife services as well as a number of others such as those based upon the OpenSim platform. -Singulariy is maintained by a small group of volunteers who can be contacted -both, in-world (SingularityViewer group) as well on IRC (#SingularityViewer +Singularity is maintained by a small group of volunteers who can be contacted +both, in-world (SingularityViewer group) as well as on IRC (#SingularityViewer @ FreeNode). Bug requests and features requests can be submitted through our -Issue Tracker (http://code.google.com/p/singularity-viewer/issues/list or from +Issue Tracker (http://links.singularityviewer.org/?to=issues or from the viewer menu: Help --> Bug Reporting --> Singularity Issue Tracker...) diff --git a/autobuild.xml b/autobuild.xml new file mode 100644 index 0000000000..13549ba62a --- /dev/null +++ b/autobuild.xml @@ -0,0 +1,3030 @@ + + + + installables + + SDL + + copyright + Copyright (c) 2004, 2006-2013 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 + + linux + + archive + + hash + 8da309d24fb0bad8eaaa667fb04c6dc7 + url + http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3pl_3p-sdl-update/rev/290561/arch/Linux/installer/SDL-1.2.15-linux-20140602.tar.bz2 + + name + linux + + linux64 + + archive + + hash + 5c8df43ff04799f3f675b8a0f328f184 + hash_algorithm + md5 + url + http://depot.alchemyviewer.org/pub/linux64/lib-trusty/SDL-1.2.15-linux64-201603241005.tar.bz2 + + name + linux64 + + + version + 1.2.15 + + apr_suite + + copyright + Copyright © 2012 The Apache Software Foundation, Licensed under the Apache License, Version 2.0. + description + Apache portable runtime project + license + Apache 2.0 + license_file + LICENSES/apr_suite.txt + name + apr_suite + platforms + + darwin + + archive + + hash + 1eca2a268913083596127b46570779ab + hash_algorithm + md5 + url + https://bitbucket.org/alchemyviewer/publiclibs-darwin/downloads/apr_suite-1.5.2-darwin-201511222106.tar.bz2 + + name + darwin + + linux + + archive + + hash + f38c966a430012dc157fdc104f23a59b + url + http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-apr/rev/259951/arch/Linux/installer/apr_suite-1.4.5-linux-20120618.tar.bz2 + + name + linux + + linux64 + + archive + + hash + cd30af9b015c373bed5062b1642a1b3e + hash_algorithm + md5 + url + http://depot.alchemyviewer.org/pub/linux64/lib-trusty/apr_suite-1.5.2-linux64-201603240800.tar.bz2 + + name + linux64 + + windows + + archive + + hash + d0cf074a2c95a65b8833350dad77c0ae + hash_algorithm + md5 + url + https://depot.alchemyviewer.org/pub/windows/lib-vc141/apr_suite-1.5.2-windows-201703090634.tar.bz2 + + name + windows + + windows64 + + archive + + hash + 1e7eb1da6e3e792db85f59012680a877 + hash_algorithm + md5 + url + https://depot.alchemyviewer.org/pub/windows64/lib-vc142/apr_suite-1.6.3-1.6.1-1.2.2-windows64-201712260041.tar.bz2 + + name + windows64 + + + version + 1.6.3-1.6.1-1.2.2 + + ares + + copyright + Copyright 1998 by the Massachusetts Institute of Technology. + description + C-ares, an asynchronous resolver library. + license + c-ares + license_file + LICENSES/c-ares.txt + name + ares + platforms + + darwin + + archive + + hash + 9a42795b21203afe858db16703929436 + hash_algorithm + md5 + url + https://bitbucket.org/alchemyviewer/publiclibs-darwin/downloads/ares-1.10.0-darwin-201511222040.tar.bz2 + + name + darwin + + linux + + archive + + hash + 92f6a454d90b5740a38fb68e369cc13e + url + http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3pl_3p-ares-update/rev/290399/arch/Linux/installer/ares-1.10.0-linux-20140529.tar.bz2 + + name + linux + + linux64 + + archive + + hash + bef927b60affa6b5c0520f45c56b5cb3 + hash_algorithm + md5 + url + http://depot.alchemyviewer.org/pub/linux64/lib-trusty/ares-1.10.0-linux64-201603240702.tar.bz2 + + name + linux64 + + windows + + archive + + hash + 0c01eb6ae9b92365ace8e70cf3999bfc + hash_algorithm + md5 + url + http://depot.alchemyviewer.org/pub/windows/lib-vc14/ares-1.10.0-windows-201601150954.tar.bz2 + + name + windows + + windows64 + + archive + + hash + 6da2b095ad9616d8a8eae9a6a5b3f2c4 + hash_algorithm + md5 + url + http://depot.alchemyviewer.org/pub/windows64/lib-vc14/ares-1.10.0-windows64-201512122047.tar.bz2 + + name + windows64 + + + version + 1.10.0 + + boost + + copyright + (see individual source files) + description + Boost C++ Libraries + license + boost 1.0 + license_file + LICENSES/boost.txt + name + boost + platforms + + darwin + + archive + + hash + 5e6a0930ca5c9e3c26970ac8589a538c + hash_algorithm + md5 + url + https://bitbucket.org/alchemyviewer/publiclibs-darwin/downloads/boost-1.59.0-darwin-201601091139.tar.bz2 + + name + darwin + + linux + + archive + + hash + 2f076eae296600a1b810ce375dc4b42d + url + http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3pl_3p-boost-update/rev/290566/arch/Linux/installer/boost-1.55.0-linux-20140602.tar.bz2 + + name + linux + + linux64 + + archive + + hash + 74a88afa7ff50462059c17321f91a359 + hash_algorithm + md5 + url + http://depot.alchemyviewer.org/pub/linux64/lib-trusty/boost-1.60.0-linux64-201603241316.tar.bz2 + + name + linux64 + + windows + + archive + + hash + ae0998e5d108c77c5cea2a68ad928151 + hash_algorithm + md5 + url + https://depot.alchemyviewer.org/pub/windows/lib-vc141/boost-1.63.0-windows-201703281813.tar.bz2 + + name + windows + + windows64 + + archive + + hash + 6faba32dcfb80c26bafd4a3e06cff268 + hash_algorithm + md5 + url + https://depot.alchemyviewer.org/pub/windows64/lib-vc142/boost-1.66.0-windows64-201712260832.tar.bz2 + + name + windows64 + + + version + 1.66.0 + + colladadom + + copyright + Copyright 2006 Sony Computer Entertainment Inc. + license + SCEA + license_file + LICENSES/collada.txt + name + colladadom + platforms + + darwin + + archive + + hash + d6e279fb5ce9093c89819803be5562db + hash_algorithm + md5 + url + https://bitbucket.org/alchemyviewer/publiclibs-darwin/downloads/colladadom-2.3-darwin-201601091204.tar.bz2 + + name + darwin + + linux + + archive + + hash + bdec5fe5fd008da4328f84115128ee61 + url + http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3pl_3p-colladadom-update/rev/290576/arch/Linux/installer/colladadom-2.3-linux-20140602.tar.bz2 + + name + linux + + linux64 + + archive + + hash + c84d1be467d7198103d905f710fa31d3 + hash_algorithm + md5 + url + http://depot.alchemyviewer.org/pub/linux64/lib-trusty/colladadom-2.3-linux64-201603241731.tar.bz2 + + name + linux + + windows + + archive + + hash + 60bd2dbac5559141e05be6c424cf9cd0 + hash_algorithm + md5 + url + https://depot.alchemyviewer.org/pub/windows/lib-vc141/colladadom-2.3-windows-201703281922.tar.bz2 + + name + windows + + windows64 + + archive + + hash + 65628150b732274f0bdd0fa33d6ca650 + hash_algorithm + md5 + url + https://depot.alchemyviewer.org/pub/windows64/lib-vc142/colladadom-2.3-windows64-201712260938.tar.bz2 + + name + windows64 + + + version + 2.3 + + crashpad + + canonical_repo + https://git.alchemyviewer.org/alchemy/thirdparty/3p-crashpad + copyright + Copyright 2014 The Crashpad Authors. All rights reserved. + description + Crashpad is a crash-reporting system. + license + Apache 2.0 + license_file + LICENSES/crashpad.txt + name + crashpad + platforms + + windows + + archive + + hash + a96fda7ad5cee967823f5c94390ba35b + hash_algorithm + md5 + url + https://pkg.alchemyviewer.org/repository/autobuild-external/crashpad/windows/crashpad-c6d76a90.194-windows-194.tar.bz2 + + name + windows + + windows64 + + archive + + hash + 5ff95ca1007ed2dc300b59de17453201 + hash_algorithm + md5 + url + https://pkg.alchemyviewer.org/repository/autobuild-external/crashpad/windows64/crashpad-c6d76a90.194-windows64-194.tar.bz2 + + name + windows64 + + + version + c6d76a90.194 + + curl + + copyright + Copyright (c) 1996 - 2017, Daniel Stenberg,(daniel@haxx.se), and many contributors. + description + Library for transferring data specified with URL syntax + license + curl + license_file + LICENSES/curl.txt + name + curl + platforms + + darwin + + archive + + hash + cc59e267a98b1b433574470a07737609 + hash_algorithm + md5 + url + https://bitbucket.org/alchemyviewer/publiclibs-darwin/downloads/curl-7.48.0-darwin-201603231616.tar.bz2 + + name + darwin + + linux + + archive + + hash + 06149da3d7a34adf40853f813ae55328 + url + http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3pl_3p-curl-update/rev/295367/arch/Linux/installer/curl-7.38.0-linux-20141010.tar.bz2 + + name + linux + + linux64 + + archive + + hash + 24a88e015ee9c1806e7aeb46887d38f5 + hash_algorithm + md5 + url + http://depot.alchemyviewer.org/pub/linux64/lib-trusty/curl-7.48.0-linux64-201603240914.tar.bz2 + + name + linux64 + + windows + + archive + + hash + da5be630ca350a7ed4c0e99250451d41 + hash_algorithm + md5 + url + https://depot.alchemyviewer.org/pub/windows/lib-vc141/curl-7.56.1-windows-201711241310.tar.bz2 + + name + windows + + windows64 + + archive + + hash + c797cd1538ab1750adbc28b334a50005 + hash_algorithm + md5 + url + https://depot.alchemyviewer.org/pub/windows64/lib-vc1414/curl-7.61.0-windows64-201808061947.tar.bz2 + + name + windows64 + + + version + 7.57.0 + + dbus-glib + + copyright + Copyright (C) Red Hat Inc. + description + D-Bus bindings for glib + license + Academic Free License v. 2.1 + license_file + LICENSES/dbus-glib.txt + name + dbus-glib + platforms + + linux + + archive + + hash + 94b058b9a81114dc4567bd78e4335425 + url + http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/dbus_glib-0.76-linux-20110310.tar.bz2 + + name + linux + + linux64 + + archive + + hash + 84e51f2e14db023be5419e74ab3b51d3 + hash_algorithm + md5 + url + https://depot.alchemyviewer.org/pub/linux64/lib/dbus_glib-0.76-linux64-201501030130.tar.bz2 + + name + linux64 + + + version + 0.76 + + dictionaries + + copyright + Copyright 2014 Apache OpenOffice software + description + Spell checking dictionaries to bundled into the viewer + license + various open source + license_file + LICENSES/dictionaries.txt + name + dictionaries + platforms + + common + + archive + + hash + 078604ad9373fe35081a7d3e4892ae41 + hash_algorithm + md5 + url + https://depot.alchemyviewer.org/pub/common/lib/dictionaries-1-common-201412301501.tar.bz2 + + name + common + + + version + 1 + + discord-rpc + + canonical_repo + https://bitbucket.org/alchemyviewer/3p-discord-rpc + copyright + Copyright 2017 Discord, Inc. + description + Discord Remote Procedure Call library + license + MIT + license_file + LICENSES/discord-rpc.txt + name + discord-rpc + platforms + + windows64 + + archive + + hash + 76bd78e14034e9c518c1a201074d568a + hash_algorithm + md5 + url + http://depot.alchemyviewer.org/pub/packages/windows64/msvc-1916/discord_rpc-3.4.0.190570542-windows64-190570542.tar.bz2 + + name + windows64 + + + version + 3.4.0.190570542 + + dullahan + + copyright + Copyright (c) 2017, Linden Research, Inc. + description + A headless browser SDK that uses the Chromium Embedded Framework (CEF). It is designed to make it easier to write applications that render modern web content directly to a memory buffer, inject synthesized mouse and keyboard events as well as interact with web based features like JavaScript or cookies. + license + MPL + license_file + LICENSES/LICENSE.txt + name + dullahan + platforms + + darwin64 + + archive + + hash + 118987b1a5b56214cfdbd0c763e180da + url + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/15127/97748/dullahan-1.1.1080_3.3325.1750.gaabe4c4-darwin64-513449.tar.bz2 + + name + darwin64 + + linux64 + + archive + + hash + 695efb6fc548a56dc4ff34e8d9a37bfb + hash_algorithm + md5 + url + https://bitbucket.org/router_gray/3p-dullahan/downloads/dullahan-1.3.202002250830_79.1.38_gecefb59_chromium-79.0.3945.130-linux64-200580406.tar.bz2 + + name + linux64 + + windows + + archive + + hash + 1b278ff2535f428ea6536683d096fdd0 + hash_algorithm + md5 + url + https://pkg.alchemyviewer.org/repository/autobuild-external/dullahan/windows/dullahan-1.3.201911222116_78.3.7_gea7ef34_chromium-78.0.3904.108-windows-2.tar.bz2 + + name + windows + + windows64 + + archive + + hash + b9346fea7643b10308c7bd9a769ef5f7 + hash_algorithm + md5 + url + https://pkg.alchemyviewer.org/repository/autobuild-external/dullahan/windows64/dullahan-1.3.201911222103_78.3.7_gea7ef34_chromium-78.0.3904.108-windows64-2.tar.bz2 + + name + windows64 + + + version + 1.3.201911222103_78.3.7_gea7ef34_chromium-78.0.3904.108 + + elfio + + license + lgpl + license_file + LICENSES/elfio.txt + name + elfio + platforms + + linux + + archive + + hash + 031e6315a5c0829c9b9a2ec18aeb7ae3 + url + http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-elfio/rev/222074/arch/Linux/installer/elfio-1.0.3-linux-20110225.tar.bz2 + + name + linux + + + + expat + + copyright + Copyright (c) 1998-2000 Thai Open Source Software Center Ltd and Clark Cooper - Copyright (c) 2001-2017 Expat maintainers + description + Expat is an XML parser library written in C + license + expat + license_file + LICENSES/expat.txt + name + expat + platforms + + darwin + + archive + + hash + fc3e46e4737b326b0ca926534ddce9f3 + hash_algorithm + md5 + url + https://bitbucket.org/alchemyviewer/publiclibs-darwin/downloads/expat-2.1.1-darwin-201603271445.tar.bz2 + + name + darwin + + linux + + archive + + hash + 9bd79781b58e556ab1c36084ec4a1c0c + url + http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-expat/rev/221695/arch/Linux/installer/expat-2.0.1-linux-20110219.tar.bz2 + + name + linux + + linux64 + + archive + + hash + 3ed12f7d7b1a3bda07a3c6d8227a3bf2 + hash_algorithm + md5 + url + http://depot.alchemyviewer.org/pub/linux64/lib-trusty/expat-2.1.1-linux64-201603232308.tar.bz2 + + name + linux64 + + windows + + archive + + hash + f10218f7c28d63a3d9f1fb683d116bf8 + hash_algorithm + md5 + url + https://depot.alchemyviewer.org/pub/windows/lib-vc141/expat-2.2.0-windows-201703090626.tar.bz2 + + name + windows + + windows64 + + archive + + hash + db56a24bbac59d9ad8b98d40b7140c29 + hash_algorithm + md5 + url + https://depot.alchemyviewer.org/pub/windows64/lib-vc142/expat-2.2.5-windows64-201712251923.tar.bz2 + + name + windows64 + + + version + 2.2.5 + + fmodstudio + + copyright + FMOD Studio, Copyright (c) Firelight Technologies Pty Ltd. + description + FMOD Studio audio system library + license + fmodstudio + license_file + LICENSES/fmodstudio.txt + name + fmodstudio + platforms + + darwin64 + + archive + + creds + gitlab + hash + db27e5c974e41d822c75038a6816b07362d54f1b0a64f21a63f0b7076f94c4a34934145bc326a1cc946996abec4b9a5c47e8ef9c68a694e129f09876080d74ac + hash_algorithm + blake2b + url + https://git.alchemyviewer.org/api/v4/projects/49/packages/generic/fmodstudio/2.02.06.1475/fmodstudio-2.02.06-darwin64-1475.tar.zst + + name + darwin64 + + linux64 + + archive + + creds + gitlab + hash + f430175d7af2a8f5e084cd789df904944b117eebb462211eafa80ea5c7f23399449c5a52faf35b3b81a09c51fdff0273741fb32c55f9c615a51b1f15a5094ca5 + hash_algorithm + blake2b + url + https://git.alchemyviewer.org/api/v4/projects/49/packages/generic/fmodstudio/2.02.06.1475/fmodstudio-2.02.06-linux64-1475.tar.zst + + name + linux64 + + windows + + archive + + hash + 50ce25e855c10d3b39f5461f34661c7f + hash_algorithm + md5 + url + https://pkg.alchemyviewer.org/repository/autobuild-internal/fmodstudio/windows/fmodstudio-2.01.04.417-windows-417.tar.bz2 + + name + windows + + windows64 + + archive + + creds + gitlab + hash + 7ad5fe064e3a7f45234a3658315a86d80b85f5f49f8a1767e1453116bd23eda67a014c521cf26529fb6bbada3441e64ddffef98ddfa85ae846d8aec72ba6fc70 + hash_algorithm + blake2b + url + https://git.alchemyviewer.org/api/v4/projects/49/packages/generic/fmodstudio/2.02.06.1475/fmodstudio-2.02.06-windows64-1475.tar.zst + + name + windows64 + + + version + 2.02.06 + + fonts + + copyright + Copyright (c) 2003 by Bitstream, Inc. Copyright (c) 2012 Adobe, Inc. + description + Font collection + license + Various + license_file + LICENSES/fonts.txt + name + fonts + platforms + + common + + archive + + hash + b0172c35f6a8ac385c71604398966f80 + hash_algorithm + md5 + url + http://depot.alchemyviewer.org/pub/packages/common/fonts-20190402.1-common-190922141.tar.bz2 + + name + common + + + version + 20190402.1 + + freeglut + + copyright + Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + description + freeglut is a completely OpenSourced alternative to the OpenGL Utility Toolkit (GLUT) library. + license + freeglut + license_file + LICENSES/freeglut.txt + name + freeglut + platforms + + windows + + archive + + hash + f98709114cedcdfdce69c9df6a4ac2f4 + hash_algorithm + md5 + url + http://depot.alchemyviewer.org/pub/windows/lib-vc14/freeglut-3.0.0-windows-201601151006.tar.bz2 + + name + windows + + windows64 + + archive + + hash + f281e5b16b380c3e3a77aafa47ba5500 + hash_algorithm + md5 + url + http://depot.alchemyviewer.org/pub/windows64/lib-vc14/freeglut-3.0.0-windows64-201512130218.tar.bz2 + + name + windows64 + + + version + 3.0.0 + + freetype + + copyright + Copyright 2006-2018 by David Turner, Robert Wilhelm, and Werner Lemberg. + description + Font rendering library + license + FreeType + license_file + LICENSES/freetype.txt + name + freetype + platforms + + darwin + + archive + + hash + 8d41fe8cb821e7e080160586a53feec8 + hash_algorithm + md5 + url + https://bitbucket.org/alchemyviewer/publiclibs-darwin/downloads/freetype-2.6.1-darwin-201511222222.tar.bz2 + + name + darwin + + windows + + archive + + hash + bdbfc3b58cfc2f125881be748d092645 + hash_algorithm + md5 + url + https://depot.alchemyviewer.org/pub/windows/lib-vc141/freetype-2.8.0-windows-201710192344.tar.bz2 + + name + windows + + windows64 + + archive + + hash + 7c028ec152b1dee1313c084d96a5d276 + hash_algorithm + md5 + url + https://depot.alchemyviewer.org/pub/windows64/lib-vc142/freetype-2.8.1-windows64-201712260751.tar.bz2 + + name + windows64 + + + version + 2.8.1 + + glext + + copyright + Copyright (c) 2013-2014 The Khronos Group Inc. + description + glext headers define function prototypes and constants for OpenGL extensions + license + MIT + license_file + LICENSES/glext.txt + name + glext + platforms + + common + + archive + + hash + c00da9333b1bd0f9cc121ebc365fe360 + hash_algorithm + md5 + url + http://depot.alchemyviewer.org/pub/common/lib/glext-20150325-common-201504222056.tar.bz2 + + name + common + + + version + 20150325 + + glh-linear + + copyright + Copyright (c) 2000 Cass Everitt + description + glh - is a platform-indepenedent C++ OpenGL helper library + license + BSD + license_file + LICENSES/glh-linear.txt + name + glh-linear + platforms + + common + + archive + + hash + fed9e6e9de1ea8210b0519f54df81bef + hash_algorithm + md5 + url + http://depot.alchemyviewer.org/pub/common/lib/glh_linear-0.0.0-common-201412301528.tar.bz2 + + name + common + + + version + 0.0.0 + + glod + + copyright + Copyright 2003 Jonathan Cohen, Nat Duca, David Luebke, Brenden Schubert - Johns Hopkins University and University of Virginia + description + Geometric Level of Detail library + license + GLOD Open-Source License Version 1.0 + license_file + LICENSES/GLOD.txt + name + glod + platforms + + darwin + + archive + + hash + 71e678d70e276fc42a56926fc28a7abd + hash_algorithm + md5 + url + http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/glod_3p-update-glod/rev/296895/arch/Darwin/installer/glod-1.0pre4.296895-darwin-296895.tar.bz2 + + name + darwin + + darwin64 + + archive + + hash + 017ef34ddf14293099a90c6eaa3615ca + url + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/1626/3627/glod-1.0pre3.501614-darwin64-501614.tar.bz2 + + name + darwin64 + + linux + + archive + + hash + 58113bcbbacbaeb2d278f745867ae6f0 + hash_algorithm + md5 + url + http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/p64_3p-glod/rev/314201/arch/Linux/installer/glod-1.0pre4.314201-linux-314201.tar.bz2 + + name + linux + + linux64 + + archive + + hash + 9aef5cd576ace19568da01d9bc3db29c + url + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/1625/3628/glod-1.0pre3.501614-linux64-501614.tar.bz2 + + name + linux64 + + windows + + archive + + hash + 573e68f46f825a1c040daa4994ee2a61 + hash_algorithm + md5 + url + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/1627/3633/glod-1.0pre3.501614-windows-501614.tar.bz2 + + name + windows + + windows64 + + archive + + hash + c122ba644e8ec146b4742428b799d749 + hash_algorithm + md5 + url + http://depot.alchemyviewer.org/pub/packages/windows64/msvc-1916/glod-1.0pre3.190390340-windows64-190390340.tar.bz2 + + name + windows64 + + + version + 1.0pre3.190390340 + + gperftools + + copyright + Copyright (c) 2005, Google Inc. + description + Fast, multi-threaded malloc() and nifty performance analysis tools + license + BSD + license_file + LICENSES/gperftools.txt + name + gperftools + platforms + + linux + + archive + + hash + 8aedfdcf670348c18a9991ae1b384a61 + url + http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-google-perftools/rev/262672/arch/Linux/installer/gperftools-2.0-linux-20120727.tar.bz2 + + name + linux + + windows + + archive + + hash + e81d9e4526ceac49f1532d6518085985 + url + https://depot.alchemyviewer.org/pub/windows/lib/gperftools-2.1-windows-20140120.tar.bz2 + + name + windows + + windows64 + + archive + + hash + da6ec7472ed69fe3231eb95432a789d9 + url + https://bitbucket.org/alchemyviewer/publiclibs/downloads/gperftools-2.2-windows64-20140605.tar.bz2 + + name + windows + + + version + 2.0.297263 + + gstreamer + + copyright + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + license + LGPL + license_file + LICENSES/gstreamer.txt + name + gstreamer + platforms + + common + + archive + + hash + df57a59e832f9e3ca8ba31e37e383dfb + hash_algorithm + md5 + url + http://depot.alchemyviewer.org/pub/common/lib/gstreamer-0.10.6.201501032013-common-201501032013.tar.bz2 + + name + common + + + version + 0.10.6.201501032013 + + gtk-atk-pango-glib + + copyright + Copyright various(See license file) + description + gtk-atk-pango-glib + license + lgpl + license_file + LICENSES/gtk-atk-pango-glib.txt + name + gtk-atk-pango-glib + platforms + + linux + + archive + + hash + 03694ade27f53199229c03cbbda89214 + url + http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/gtk-atk-pango-glib-linux-20101001.tar.bz2 + + name + linux + + linux64 + + archive + + hash + 9678056c5ad714aa7ba1ba4ffcb09859 + hash_algorithm + md5 + url + http://depot.alchemyviewer.org/pub/linux64/lib-trusty/gtk_atk_pango_glib-0.0.2-linux64-201603241949.tar.bz2 + + name + linux64 + + + version + 0.0.2 + + jpeglib + + copyright + Copyright (C) 1991-2012, Thomas G. Lane, Guido Vollbeding. + description + JPEG encoding, decoding library + license + libjpeg-turbo + license_file + LICENSES/jpeglib.txt + name + jpeglib + platforms + + darwin + + archive + + hash + 5cf289747de86451b6a956adea468ac7 + hash_algorithm + md5 + url + https://bitbucket.org/alchemyviewer/publiclibs-darwin/downloads/jpeglib-1.4.2-darwin-201511222055.tar.bz2 + + name + darwin + + linux + + archive + + hash + dcca1db348831cdb7c6b26dc4076c597 + url + http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-jpeglib/rev/224895/arch/Linux/installer/jpeglib-8c-linux-20110323.tar.bz2 + + name + linux + + linux64 + + archive + + hash + 256812a20a66081e05578f91bab5b3e4 + hash_algorithm + md5 + url + http://depot.alchemyviewer.org/pub/linux64/lib-trusty/jpeglib-1.4.2-linux64-201603240711.tar.bz2 + + name + linux64 + + windows + + archive + + hash + a9a7af50c5c1b5319dfea82cd09fdd84 + hash_algorithm + md5 + url + https://depot.alchemyviewer.org/pub/windows/lib-vc141/jpeglib-1.5.1-windows-201703090615.tar.bz2 + + name + windows + + windows64 + + archive + + hash + d60f195778344b88cc47dc5e19af2cf8 + hash_algorithm + md5 + url + https://depot.alchemyviewer.org/pub/windows64/lib-vc142/jpeglib-1.5.3-windows64-201712251431.tar.bz2 + + name + windows64 + + + version + 1.5.3 + + libhunspell + + copyright + See hunspell.txt + description + Spell checking library + license + LGPL + license_file + LICENSES/hunspell.txt + name + libhunspell + platforms + + darwin + + archive + + hash + c897e44b3f5ac33436a028e6e3a5b29b + hash_algorithm + md5 + url + https://bitbucket.org/alchemyviewer/publiclibs-darwin/downloads/libhunspell-1.3.3-darwin-201511222015.tar.bz2 + + name + darwin + + linux + + archive + + hash + 0c432d2626aea2e91a56335879c92965 + url + http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-hunspell/rev/259874/arch/Linux/installer/libhunspell-1.3.2-linux-20120616.tar.bz2 + + name + linux + + linux64 + + archive + + hash + f58652f3217c1e897e9051aa19d99139 + hash_algorithm + md5 + url + http://depot.alchemyviewer.org/pub/linux64/lib-trusty/libhunspell-1.3.3-linux64-201603240026.tar.bz2 + + name + linux64 + + windows + + archive + + hash + cfce0b7d65b28b34fd0643cbcf7b0bac + hash_algorithm + md5 + url + https://depot.alchemyviewer.org/pub/windows/lib-vc141/libhunspell-1.6.0-windows-201703090619.tar.bz2 + + name + windows + + windows64 + + archive + + hash + 46e0276052dc614fe890f2a5d6f814b9 + hash_algorithm + md5 + url + https://depot.alchemyviewer.org/pub/windows64/lib-vc142/libhunspell-1.6.2-windows64-201712251236.tar.bz2 + + name + windows64 + + + version + 1.3.3 + + libidn + + copyright + Copyright (C) 2002-2013 Simon Josefsson + description + Libidn's purpose is to encode and decode internationalized domain names. + license + LGPL + license_file + LICENSES/libidn.txt + name + libidn + platforms + + darwin + + archive + + hash + 4c1f76a59c9abd7590b60b1507c16540 + hash_algorithm + md5 + url + https://bitbucket.org/alchemyviewer/publiclibs-darwin/downloads/libidn-1.32-darwin-201511222141.tar.bz2 + + name + darwin + + linux64 + + archive + + hash + e3d59bdb4418f50365fbae7a866b4e23 + hash_algorithm + md5 + url + http://depot.alchemyviewer.org/pub/linux64/lib-trusty/libidn-1.32-linux64-201603240734.tar.bz2 + + name + linux64 + + + version + 1.32 + + libndofdev + + copyright + Copyright (c) 2007, 3Dconnexion, Inc. - All rights reserved. + description + 3DConnexion SDK + license + BSD + license_file + LICENSES/libndofdev.txt + name + libndofdev + platforms + + darwin + + archive + + hash + 1d542606b146462cdfdc47a94f14eaf5 + hash_algorithm + md5 + url + https://bitbucket.org/alchemyviewer/publiclibs-darwin/downloads/libndofdev-0.1-darwin-201504232110.tar.bz2 + + name + darwin + + windows + + archive + + hash + e2927116641e2c74ada092bfb6b49a8d + hash_algorithm + md5 + url + https://depot.alchemyviewer.org/pub/windows/lib-vc141/libndofdev-0.1-windows-201703090613.tar.bz2 + + name + windows + + windows64 + + archive + + hash + 3ac8047b38b617ad686591e00100d6af + hash_algorithm + md5 + url + https://depot.alchemyviewer.org/pub/windows64/lib-vc142/libndofdev-0.1-windows64-201712251124.tar.bz2 + + name + windows64 + + + version + 0.1 + + libndofdev-open + + copyright + Copyright (c) 2008, Jan Ciger (jan.ciger (at) gmail.com) + description + 3DConnection SDK + license + BSD + license_file + LICENSES/libndofdev.txt + name + libndofdev-open + platforms + + linux64 + + archive + + hash + d3fd1dab78123c39391b0afb372e5cf1 + hash_algorithm + md5 + url + http://depot.alchemyviewer.org/pub/linux64/lib-trusty/libndofdev_open-0.8-linux64-201603241018.tar.bz2 + + name + linux64 + + + version + 0.8 + + libpng + + copyright + Copyright (c) 2000-2002, 2004, 2006-2017 Glenn Randers-Pehrson + description + PNG Reference library + license + libpng + license_file + LICENSES/libpng.txt + name + libpng + platforms + + darwin + + archive + + hash + 7c315d3fee9f9bf7e36c4251c41fa378 + hash_algorithm + md5 + url + https://bitbucket.org/alchemyviewer/publiclibs-darwin/downloads/libpng-1.6.19-darwin-201511222146.tar.bz2 + + name + darwin + + linux + + archive + + hash + 3368a25b361c22a03f7ec7e0f8d5ff9d + url + http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3pl_3p-libpng-update/rev/290558/arch/Linux/installer/libpng-1.6.8-linux-20140602.tar.bz2 + + name + linux + + linux64 + + archive + + hash + cd64cda7107b967279d5af03b0d46a8f + hash_algorithm + md5 + url + http://depot.alchemyviewer.org/pub/linux64/lib-trusty/libpng-1.6.21-linux64-201603240933.tar.bz2 + + name + linux64 + + windows + + archive + + hash + 9aad0afaf2c1895224454c1dc433f481 + hash_algorithm + md5 + url + https://depot.alchemyviewer.org/pub/windows/lib-vc141/libpng-1.6.34-windows-201710172201.tar.bz2 + + name + windows + + windows64 + + archive + + hash + 528889464c0766d762bd528cf82558db + hash_algorithm + md5 + url + https://depot.alchemyviewer.org/pub/windows64/lib-vc142/libpng-1.6.34-windows64-201712260746.tar.bz2 + + name + windows64 + + + version + 1.6.34 + + libxml2 + + copyright + Copyright (C) 1998-2012 Daniel Veillard. All Rights Reserved. + description + Libxml2 is the XML C parser and toolkit developed for the Gnome project. + license + MIT + license_file + LICENSES/libxml2.txt + name + libxml2 + platforms + + darwin + + archive + + hash + 242ffec9e9f8fca818b750c578eba0dd + hash_algorithm + md5 + url + https://bitbucket.org/alchemyviewer/publiclibs-darwin/downloads/libxml2-2.9.3-darwin-201511222121.tar.bz2 + + name + darwin + + linux + + archive + + hash + 7eb90f075730f8d7d176f8fb7bad5ef5 + url + http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3pl_3p-libxml-update/rev/290562/arch/Linux/installer/libxml2-2.9.1-linux-20140602.tar.bz2 + + name + linux + + linux64 + + archive + + hash + 61351b10787b06045a70c905a58ca2f6 + hash_algorithm + md5 + url + http://depot.alchemyviewer.org/pub/linux64/lib-trusty/libxml2-2.9.3-linux64-201603241216.tar.bz2 + + name + linux64 + + windows + + archive + + hash + a3f7c3421e9e4921dda3558c3b36dc59 + hash_algorithm + md5 + url + https://depot.alchemyviewer.org/pub/windows/lib-vc141/libxml2-2.9.4-windows-201703090740.tar.bz2 + + name + windows + + windows64 + + archive + + hash + f69b1d4ec7ffdeec4429413ea640583d + hash_algorithm + md5 + url + https://depot.alchemyviewer.org/pub/windows64/lib-vc142/libxml2-2.9.7-windows64-201712260755.tar.bz2 + + name + windows64 + + + version + 2.9.3 + + llphysicsextensions_stub + + copyright + Copyright (c) 2010, Linden Research, Inc. + license + internal + license_file + LICENSES/llphysicsextensions.txt + name + llphysicsextensions_stub + platforms + + darwin + + archive + + hash + 1175977a191ffc936fd0ccca433c8278 + hash_algorithm + md5 + url + http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/llphysicsextensions-stub_llphysicsextensions-update/rev/298370/arch/Darwin/installer/llphysicsextensions_stub-1.0.298370-darwin-298370.tar.bz2 + + name + darwin + + linux + + archive + + hash + d13d7927692eab2d6a63e36166b72a8a + url + http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/llphysicsextensions-stub_llphysicsextensions-update/rev/298370/arch/Linux/installer/llphysicsextensions_stub-1.0.298370-linux-298370.tar.bz2 + + name + linux + + linux64 + + archive + + hash + aa8a2f25e8629cf5e6a96cc0eb93de8e + url + http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/llphysicsextensions-stub/rev/263415/arch/Linux/installer/llphysicsextensions_stub-0.3-linux-20120814.tar.bz2 + + name + linux64 + + windows + + archive + + hash + 9594f6fd79ee924fe675a4a23e30516e + url + http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/llphysicsextensions-stub_llphysicsextensions-update/rev/298370/arch/CYGWIN/installer/llphysicsextensions_stub-1.0.298370-windows-298370.tar.bz2 + + name + windows + + windows64 + + archive + + hash + 50d7ea325063219a86d9439ce7458582 + hash_algorithm + md5 + url + http://depot.alchemyviewer.org/pub/windows64/lib/llphysicsextensions_stub-1.0.298370-windows64-298370.tar.bz2 + + name + windows64 + + + version + 1.0.298370 + + mesa + + license + mesa + license_file + LICENSES/mesa.txt + name + mesa + platforms + + linux + + archive + + hash + 22c50a5d362cad311b4f413cfcffbba2 + url + http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/mesa_3p-update-mesa/rev/297294/arch/Linux/installer/mesa-7.11.1.297294-linux-297294.tar.bz2 + + name + linux + + + version + 7.11.1.297294 + + nvapi + + copyright + Copyright (c) 2007- 2019 NVIDIA Corporation. All rights reserved. + license + nvapi + license_file + LICENSES/nvapi.txt + name + nvapi + platforms + + windows + + archive + + hash + 408eff309f6f3031d74da5491c1852a9 + hash_algorithm + md5 + url + https://pkg.alchemyviewer.org/repository/autobuild-internal/nvapi/windows/nvapi-R430.192211828-windows-192211828.tar.bz2 + + name + windows + + windows64 + + archive + + hash + 76a547f558b8499dc85135b8718eb18a + hash_algorithm + md5 + url + https://pkg.alchemyviewer.org/repository/autobuild-internal/nvapi/windows64/nvapi-R430.192211828-windows64-192211828.tar.bz2 + + name + windows64 + + + version + R430.192211828 + + ogg_vorbis + + copyright + Copyright (c) 2002, Xiph.org Foundation + description + Audio encoding library + license + ogg-vorbis + license_file + LICENSES/ogg-vorbis.txt + name + ogg_vorbis + platforms + + darwin + + archive + + hash + 83959618755a09d1af245e402f4b6232 + hash_algorithm + md5 + url + https://bitbucket.org/alchemyviewer/publiclibs-darwin/downloads/ogg_vorbis-1.3.2-1.3.5-darwin-201511222036.tar.bz2 + + name + darwin + + linux + + archive + + hash + 71eaa462eb0bf8842277a3436483a354 + url + http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-ogvorbis/rev/229529/arch/Linux/installer/ogg_vorbis-1.2.2-1.3.2-linux-20110511.tar.bz2 + + name + linux + + linux64 + + archive + + hash + d847ea384530e0bbb3774065dbdae65c + hash_algorithm + md5 + url + http://depot.alchemyviewer.org/pub/linux64/lib-trusty/ogg_vorbis-1.3.2-1.3.5-linux64-201603240037.tar.bz2 + + name + linux64 + + windows + + archive + + hash + 41d090321853ea941c5ca57ba0d471d0 + hash_algorithm + md5 + url + https://depot.alchemyviewer.org/pub/windows/lib-vc141/ogg_vorbis-1.3.2-1.3.5-windows-201703090612.tar.bz2 + + name + windows + + windows64 + + archive + + hash + 01ae2d298489ea66597c5e302e8e4525 + hash_algorithm + md5 + url + https://depot.alchemyviewer.org/pub/windows64/lib-vc142/ogg_vorbis-1.3.2-1.3.5-windows64-201712251411.tar.bz2 + + name + windows64 + + + version + 1.3.2-1.3.5 + + openal + + copyright + Creative Labs + description + OpenAL is a cross-platform 3D audio API appropriate for use with gaming applications and many other types of audio applications. + license + lgpl + license_file + LICENSES/openal.txt + name + openal + platforms + + darwin + + archive + + hash + 4c0dd5385dbd8787d134e5e91f82f04a + hash_algorithm + md5 + url + https://bitbucket.org/alchemyviewer/publiclibs-darwin/downloads/openal-1.16.0-1.1.0-darwin-201412160747.tar.bz2 + + name + darwin + + linux + + archive + + hash + fccdca18a950ac9363c6fb39118b80e1 + hash_algorithm + md5 + url + http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/openal-3ad86a1c-linux-20110114.tar.bz2 + + name + linux + + linux64 + + archive + + hash + 7fea13f8caab7bf9184e0790eab9c2f3 + hash_algorithm + md5 + url + http://depot.alchemyviewer.org/pub/linux64/lib-trusty/openal-1.17.2-1.1.0-linux64-201603232035.tar.bz2 + + name + linux64 + + windows + + archive + + hash + fa39ac8fe3714599293563fb7f964fca + hash_algorithm + md5 + url + http://depot.alchemyviewer.org/pub/windows/lib/openal-1.16.0-1.1.0-windows-201504270536.tar.bz2 + + name + windows + + windows64 + + archive + + hash + fec29528320a2a67ffa7b3900135592d + hash_algorithm + md5 + url + https://depot.alchemyviewer.org/pub/windows64/lib/openal-1.16.0-1.1.0-windows64-201504270534.tar.bz2 + + name + windows64 + + + version + 1.17.2-1.1.0 + + openssl + + copyright + Copyright (c) 1998-2016 The OpenSSL Project. All rights reserved; Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + description + Secure Sockets Layer (SSL v2/v3) and Transport Layer Security (TLS v1) Library + license + openssl + license_file + LICENSES/openssl.txt + name + openssl + platforms + + darwin + + archive + + hash + d415e218a7f3d0d1e3dd4f99d6129e6c + hash_algorithm + md5 + url + https://bitbucket.org/alchemyviewer/publiclibs-darwin/downloads/openssl-1.0.2g-darwin-201603010806.tar.bz2 + + name + darwin + + linux + + archive + + hash + 0665c18f8cdbe2f90cb0a2f088cfe1a6 + url + http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3pl_3p-openssl-update/rev/290662/arch/Linux/installer/openssl-1.0.1h-linux-20140605.tar.bz2 + + name + linux + + linux64 + + archive + + hash + 2a50dcb704f6af595fff44defc4b65df + hash_algorithm + md5 + url + http://depot.alchemyviewer.org/pub/linux64/lib-trusty/openssl-1.0.2g-linux64-201603240821.tar.bz2 + + name + linux64 + + windows + + archive + + hash + 0d25e1794f5d86b675484bf5eda799e4 + hash_algorithm + md5 + url + https://depot.alchemyviewer.org/pub/windows/lib-vc141/openssl-1.1.0g-windows-201711200028.tar.bz2 + + name + windows + + windows64 + + archive + + hash + bd35903f309ccf026a2c448fd8613cc0 + hash_algorithm + md5 + url + https://depot.alchemyviewer.org/pub/windows64/lib-vc142/openssl-1.1.0g-windows64-201712260729.tar.bz2 + + name + windows64 + + + version + 1.1.0g + + quicktime + + copyright + 2010 Apple + description + QuickTime 7.3 SDK for Windows + license + unknown + license_file + LICENSES/quicktime.txt + name + quicktime + platforms + + windows + + archive + + hash + 66600ab94087d295e48e326ec8961ac5 + hash_algorithm + md5 + url + http://depot.alchemyviewer.org/pub/windows/lib/quicktime-7.3-windows-201504280653.tar.bz2 + + name + windows + + + version + 7.3 + + slvoice + + copyright + 2010 Vivox, including audio coding using Polycom¨ Siren14TM (ITU-T Rec. G.722.1 Annex C) + description + Vivox SDK components + license + Mixed + license_file + LICENSES/slvoice.txt + name + slvoice + platforms + + darwin + + archive + + hash + b1b0134bc55f55a7c1a04ee78d70c64d + hash_algorithm + md5 + url + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/12438/73598/slvoice-4.9.0002.27586.511884-darwin64-511884.tar.bz2 + + name + darwin + + linux + + archive + + hash + 9f60e56aba35ec90b3045e9d049ac284 + url + http://depot.alchemyviewer.org/pub/linux/lib/slvoice-4.5.0009.17865-linux-20141214.tar.bz2 + + name + linux + + linux64 + + archive + + hash + df43d3df49296bfe93996ec537b9eddf + hash_algorithm + md5 + url + http://depot.alchemyviewer.org/pub/linux64/lib/slvoice-4.6.0009.20030-linux64-201501031918.tar.bz2 + + name + linux64 + + windows + + archive + + hash + ec50c31efce74bdedee470b5388aeeec + hash_algorithm + md5 + url + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/12434/73576/slvoice-4.9.0002.27586.511884-windows-511884.tar.bz2 + + name + windows + + windows64 + + archive + + hash + 4bf45d641bf5b2bd6b2cc39edcb01a6e + hash_algorithm + md5 + url + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/12433/73570/slvoice-4.9.0002.27586.511884-windows64-511884.tar.bz2 + + name + windows64 + + + version + 4.9.0002.27586.511884 + + tut + + copyright + Copyright 2002-2006 Vladimir Dyuzhev, Copyright 2007 Denis Kononenko, Copyright 2008-2009 Michał Rzechonek + description + TUT is a small and portable unit test framework for C++. + license + bsd + license_file + LICENSES/tut.txt + name + tut + platforms + + common + + archive + + hash + 56601f1217ccd206829e8834e5a1253b + hash_algorithm + md5 + url + https://depot.alchemyviewer.org/pub/common/lib/tut-2008.11.30-common-201504282317.tar.bz2 + + name + common + + + version + 2008.11.30 + + uriparser + + copyright + Copyright (C) 2007, Weijia Song <songweijia@gmail.com>, Sebastian Pipping <webmaster@hartwork.org> + description + uriparser is a strictly RFC 3986 compliant URI parsing and handling library written in C. uriparser is cross-platform, fast, supports Unicode and is licensed under the New BSD license. + license + New BSD license + license_file + LICENSES/uriparser.txt + name + uriparser + platforms + + darwin + + archive + + hash + 364cbc9a049acb2a0d2cd6719a02adf0 + hash_algorithm + md5 + url + https://depot.alchemyviewer.org/pub/darwin/lib/uriparser-0.8.4-darwin-201511221948.tar.bz2 + + name + darwin + + linux + + archive + + hash + 34306fb90364b182dc770375140d8557 + url + http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-uriparser/rev/294298/arch/Linux/installer/uriparser-0.8.0.1-linux-20140918.tar.bz2 + + name + linux + + linux64 + + archive + + hash + cf21d9f7ed7949d2230413e8a391fb73 + hash_algorithm + md5 + url + https://depot.alchemyviewer.org/pub/linux64/lib-xenial/uriparser-0.8.4-linux64-201609241428.tar.bz2 + + name + linux64 + + windows + + archive + + hash + 89f3fc7f3fe396439d306f099d1a12d3 + hash_algorithm + md5 + url + https://depot.alchemyviewer.org/pub/windows/lib-vc141/uriparser-0.8.4-windows-201703090606.tar.bz2 + + name + windows + + windows64 + + archive + + hash + ad1a435de73b7ee6d07f6c81a4cb1910 + hash_algorithm + md5 + url + https://depot.alchemyviewer.org/pub/windows64/lib-vc142/uriparser-0.8.4-windows64-201712251116.tar.bz2 + + name + windows64 + + + version + 0.8.4 + + vlc-bin + + copyright + Copyright (C) 1998-2020 VLC authors and VideoLAN + license + GPL2 + license_file + LICENSES/vlc.txt + name + vlc-bin + platforms + + darwin64 + + archive + + hash + e5635e173c75dc0675b48ab5f5e4868b + url + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/12143/71451/vlc_bin-2.2.8.511703-darwin64-511703.tar.bz2 + + name + darwin64 + + linux + + archive + + hash + 2f410640df3f9812d1abff02a414cfa8 + url + https://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-vlc-bin/rev/315283/arch/Linux/vlc_bin-2.2.3-linux-201606011750-r10.tar.bz2 + + name + linux + + windows + + archive + + hash + 3ff1d097e4f9b8f864a639aff974a506 + url + https://pkg.alchemyviewer.org/repository/autobuild-external/vlc-bin/windows/vlc_bin-3.0.8.189-windows-189.tar.bz2 + + name + windows + + windows64 + + archive + + hash + b890b109b526cc6ad211eadefed83316 + url + https://pkg.alchemyviewer.org/repository/autobuild-external/vlc-bin/windows64/vlc_bin-3.0.8.189-windows64-189.tar.bz2 + + name + windows64 + + + version + 3.0.8.189 + + xmlrpc-epi + + copyright + Copyright: (C) 2000 Epinions, Inc. + description + XMLRPC Library + license + xmlrpc-epi + license_file + LICENSES/xmlrpc-epi.txt + name + xmlrpc-epi + platforms + + darwin + + archive + + hash + 408e34531c6a8ac20ccc8c917435071f + hash_algorithm + md5 + url + https://bitbucket.org/alchemyviewer/publiclibs-darwin/downloads/xmlrpc_epi-0.54.2-darwin-201603271451.tar.bz2 + + name + darwin + + linux + + archive + + hash + 174ab797440157956eda7061dae37564 + url + http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/xmlrpc_epi-0.54.1-linux-20110314.tar.bz2 + + name + linux + + linux64 + + archive + + hash + 0465334ff0f1d57cf354867fd21ee137 + hash_algorithm + md5 + url + http://depot.alchemyviewer.org/pub/linux64/lib-trusty/xmlrpc_epi-0.54.2-linux64-201603240753.tar.bz2 + + name + linux64 + + windows + + archive + + hash + 4cd5d80362fef95fe486b5bc1c373174 + hash_algorithm + md5 + url + https://depot.alchemyviewer.org/pub/windows/lib-vc141/xmlrpc_epi-0.54.2-windows-201703090632.tar.bz2 + + name + windows + + windows64 + + archive + + hash + 59f0be2732e93eceaa155d98c2fcee9c + hash_algorithm + md5 + url + https://depot.alchemyviewer.org/pub/windows64/lib-vc142/xmlrpc_epi-0.54.2-windows64-201712260035.tar.bz2 + + name + windows64 + + + version + 0.54.2 + + zlib + + copyright + Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler + description + Zlib Data Compression Library + license + zlib + license_file + LICENSES/zlib.txt + name + zlib + platforms + + darwin + + archive + + hash + 635ee875ba478b17b6c64d9698cdf0dd + hash_algorithm + md5 + url + https://bitbucket.org/alchemyviewer/publiclibs-darwin/downloads/zlib-1.2.8-darwin-201511221937.tar.bz2 + + name + darwin + + linux + + archive + + hash + 63a62bb3cbef2aad3cca49cb6f2d0aeb + url + http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3pl_3p-zlib-update/rev/290556/arch/Linux/installer/zlib-1.2.8-linux-20140602.tar.bz2 + + name + linux + + linux64 + + archive + + hash + 1eaee9888043648d5f09716b771dcb4b + hash_algorithm + md5 + url + http://depot.alchemyviewer.org/pub/linux64/lib-trusty/zlib-1.2.8-linux64-201603240746.tar.bz2 + + name + linux64 + + windows + + archive + + hash + 75651f8b2fa45545461f73ba583180bb + hash_algorithm + md5 + url + https://depot.alchemyviewer.org/pub/windows/lib-vc141/zlib-1.2.11-windows-201703090604.tar.bz2 + + name + windows + + windows64 + + archive + + hash + ed6da4296e2fdfc132b4f12d35890ada + hash_algorithm + md5 + url + https://depot.alchemyviewer.org/pub/windows64/lib-vc142/zlib-1.2.11-windows64-201712260711.tar.bz2 + + name + windows64 + + + version + 1.2.11 + + + package_description + + copyright + Copyright (c) 2010-2016, Singularity Viewer Team + description + Singularity Viewer + license + LGPL + license_file + docs/LICENSE-source.txt + name + Singularity Viewer + platforms + + common + + configurations + + RelWithDebInfo + + configure + + arguments + + ../indra + + command + cmake + options + + -DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo + -DADDRESS_SIZE:STRING=$AUTOBUILD_ADDRSIZE + -DROOT_PROJECT_NAME:STRING=Singularity + -DINSTALL_PROPRIETARY=FALSE + + + name + RelWithDebInfo + + Release + + configure + + arguments + + ../indra + + command + cmake + options + + -DCMAKE_BUILD_TYPE:STRING=Release + -DADDRESS_SIZE:STRING=$AUTOBUILD_ADDRSIZE + -DROOT_PROJECT_NAME:STRING=Singularity + -DINSTALL_PROPRIETARY=FALSE + + + name + Release + + + name + common + + darwin + + build_directory + build-darwin-i386 + configurations + + RelWithDebInfo + + build + + command + xcodebuild + options + + -configuration RelWithDebInfo + -project Singularity.xcodeproj + + + configure + + options + + -G + 'Xcode' + + + default + True + name + RelWithDebInfo + + Release + + build + + command + xcodebuild + options + + -configuration Release + -project Singularity.xcodeproj + -DENABLE_SIGNING:BOOL=YES + -DSIGNING_IDENTITY:STRING="Developer ID Application: Linden Research, Inc." + + + configure + + options + + -G + 'Xcode' + + + name + Release + + + name + darwin + + linux + + build_directory + build-linux-i686 + configurations + + RelWithDebInfo + + build + + command + ninja + options + + -v + + + configure + + options + + -G + Ninja + + + default + True + name + RelWithDebInfo + + Release + + build + + command + ninja + options + + -v + + + configure + + options + + -G + Ninja + + + name + Release + + + name + linux + + linux64 + + build_directory + build-linux-x86_64 + configurations + + RelWithDebInfo + + build + + command + ninja + options + + -v + + + configure + + options + + -G + Ninja + -DADDRESS_SIZE:STRING=64 + + + default + True + name + RelWithDebInfo + + Release + + build + + command + ninja + options + + -v + + + configure + + options + + -G + Ninja + -DADDRESS_SIZE:STRING=64 + + + name + Release + + + name + linux64 + + windows + + build_directory + build-vc-$AUTOBUILD_ADDRSIZE + configurations + + RelWithDebInfo + + build + + arguments + + Singularity.sln + + command + msbuild.exe + options + + /p:Configuration=RelWithDebInfo + /p:Platform=Win32 + /t:Build + /p:useenv=true + /verbosity:normal + /m + + + configure + + arguments + + ..\indra + + options + + -G + ${AUTOBUILD_WIN_CMAKE_GEN|NOTWIN} + -A + ${AUTOBUILD_WIN_VSPLATFORM|NOTWIN} + -T + host=${AUTOBUILD_WIN_VSHOST|NOTWIN} + + + default + True + name + RelWithDebInfo + + Release + + build + + arguments + + Singularity.sln + + command + msbuild.exe + options + + /p:Configuration=Release + /p:Platform=${AUTOBUILD_WIN_VSPLATFORM|NOTWIN} + /t:Build + /p:PreferredToolArchitecture=x64 + /p:useenv=true + /verbosity:normal + /m + + + configure + + arguments + + ..\indra + + options + + -G + ${AUTOBUILD_WIN_CMAKE_GEN|NOTWIN} + -A + ${AUTOBUILD_WIN_VSPLATFORM|NOTWIN} + -T + host=${AUTOBUILD_WIN_VSHOST|NOTWIN} + -DINSTALL_PROPRIETARY=FALSE + + + name + Release + + + name + windows + + + version_file + newview/viewer_version.txt + + type + autobuild + version + 1.3 + + diff --git a/doc/asset_urls.txt b/doc/asset_urls.txt deleted file mode 100644 index e42a45c899..0000000000 --- a/doc/asset_urls.txt +++ /dev/null @@ -1,5 +0,0 @@ -SLASSET_LIBS_WIN32=http://automated-builds-secondlife-com.s3.amazonaws.com/oss-viewer/export/slviewer-win32-libs-oss-viewer-1.23.4.0.zip -SLASSET_MD5=http://automated-builds-secondlife-com.s3.amazonaws.com/oss-viewer/export/md5sums-oss-viewer-1.23.4.0.txt -SLASSET_LIBS_DARWIN=http://automated-builds-secondlife-com.s3.amazonaws.com/oss-viewer/export/slviewer-darwin-libs-oss-viewer-1.23.4.0.tar.gz -SLASSET_ART=http://automated-builds-secondlife-com.s3.amazonaws.com/oss-viewer/export/slviewer-artwork-oss-viewer-1.23.4.0.zip -SLASSET_LIBS_LINUXI386=http://automated-builds-secondlife-com.s3.amazonaws.com/oss-viewer/export/slviewer-linux-libs-oss-viewer-1.23.4.0.tar.gz diff --git a/doc/releasenotes-where.txt b/doc/releasenotes-where.txt deleted file mode 100644 index 4af5866905..0000000000 --- a/doc/releasenotes-where.txt +++ /dev/null @@ -1,5 +0,0 @@ -For full release notes, see: - http://wiki.secondlife.com/wiki/Release_Notes - -For a log of viewer changes, see: - doc/viewer-changes.txt diff --git a/doc/viewer-changes.txt b/doc/viewer-changes.txt deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/etc/message.xml b/etc/message.xml index fd019aa706..5f2c3aa068 100644 --- a/etc/message.xml +++ b/etc/message.xml @@ -236,6 +236,14 @@ false + ObjectAnimation + + flavor + template + trusted-sender + false + + AvatarAppearance flavor diff --git a/indra/CMakeLists.txt b/indra/CMakeLists.txt index fc7b0a8785..3bcd9e1618 100644 --- a/indra/CMakeLists.txt +++ b/indra/CMakeLists.txt @@ -3,19 +3,7 @@ # cmake_minimum_required should appear before any # other commands to guarantee full compatibility # with the version specified - -cmake_minimum_required(VERSION 2.6.2 FATAL_ERROR) - -# Eventually the third-party support modules (cmake/*.cmake) should -# know the full path to all libraries. Until that happens we need -# per-configuration link directory "libraries//lib/debug" for -# Debug and "libraries//lib/release" for Release, -# RelWithDebInfo, and MinSizeRel. CMake 2.6 does not directly support -# per-configuration link directory specification. However, we can set -# CMP0003 to OLD and link to one library (apr) on a per-configuration -# basis to convince CMake to add the proper link directory. This line -# can be removed when we use full paths for all libraries. -cmake_policy(SET CMP0003 OLD) +cmake_minimum_required(VERSION 3.14 FATAL_ERROR) set(ROOT_PROJECT_NAME "Singularity" CACHE STRING "The root project/makefile/solution name. Defaults to Singularity.") @@ -23,25 +11,20 @@ project(${ROOT_PROJECT_NAME}) set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") -include(Variables) +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD_REQUIRED ON) -# Load versions now. Install locations need them. -include(BuildVersion) - -include(UnixInstall) - -if (NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE Release CACHE STRING +if (NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Build type. One of: Debug Release RelWithDebInfo" FORCE) -endif (NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE) +endif (NOT CMAKE_BUILD_TYPE) + +include(Variables) +include(00-Common) +include(BuildVersion) +include(CTest) -# Create a 'prepare' target in which to perform setup actions. This -# must be the first target created so other targets can depend on it. -if(NOT STANDALONE) - # We prepare prebuilt binaries when not building standalone. - set(prepare_depends ${CMAKE_BINARY_DIR}/prepare/prebuilt) -endif(NOT STANDALONE) -add_custom_target(prepare DEPENDS ${prepare_depends}) +add_subdirectory(deps) add_subdirectory(cmake) add_subdirectory(${LIBS_OPEN_PREFIX}aistatemachine) @@ -64,69 +47,23 @@ add_subdirectory(${LIBS_OPEN_PREFIX}llvfs) add_subdirectory(${LIBS_OPEN_PREFIX}llwindow) add_subdirectory(${LIBS_OPEN_PREFIX}llxml) -if(STANDALONE) - add_subdirectory(${LIBS_OPEN_PREFIX}llqtwebkit) -endif(STANDALONE) - -#add_subdirectory(${LIBS_OPEN_PREFIX}lscript) - if (WINDOWS AND EXISTS ${LIBS_CLOSED_DIR}copy_win_scripts) add_subdirectory(${LIBS_CLOSED_PREFIX}copy_win_scripts) endif (WINDOWS AND EXISTS ${LIBS_CLOSED_DIR}copy_win_scripts) add_custom_target(viewer) -add_subdirectory(${LIBS_OPEN_PREFIX}llcrashlogger) add_subdirectory(${LIBS_OPEN_PREFIX}llplugin) add_subdirectory(${LIBS_OPEN_PREFIX}llui) # viewer plugins directory add_subdirectory(${LIBS_OPEN_PREFIX}plugins) -# llplugin testbed code (is this the right way to include it?) -#if (NOT LINUX) -# add_subdirectory(${VIEWER_PREFIX}test_apps/llplugintest) -#endif (NOT LINUX) - -if (LINUX) - add_subdirectory(${VIEWER_PREFIX}linux_crash_logger) - add_dependencies(viewer linux-crash-logger-strip-target) -elseif (DARWIN) - #add_subdirectory(${VIEWER_PREFIX}mac_crash_logger) - #add_subdirectory(${VIEWER_PREFIX}mac_updater) - add_dependencies(viewer mac-crash-logger) - #add_dependencies(viewer mac-updater) -elseif (WINDOWS) - add_subdirectory(${VIEWER_PREFIX}win_crash_logger) - # cmake EXISTS requires an absolute path, see indra/cmake/Variables.cmake - if (EXISTS ${VIEWER_DIR}win_setup) - add_subdirectory(${VIEWER_DIR}win_setup) - endif (EXISTS ${VIEWER_DIR}win_setup) - add_subdirectory(${VIEWER_PREFIX}win_updater) - add_dependencies(viewer windows-updater) - add_dependencies(viewer windows-crash-logger) -elseif (SOLARIS) - add_subdirectory(solaris_crash_logger) - add_dependencies(viewer solaris-crash-logger) -endif (LINUX) - add_subdirectory(${VIEWER_PREFIX}newview/statemachine) add_subdirectory(${VIEWER_PREFIX}newview) -add_dependencies(viewer secondlife-bin) - -# The use_prebuilt_binary macro in cmake/Prebuilt.cmake records -# packages in the PREBUILT property of the 'prepare' target. -get_property(PREBUILT_PACKAGES TARGET prepare PROPERTY PREBUILT) +add_dependencies(viewer ${VIEWER_BINARY_NAME}) -# Create a script to download the needed binaries. -configure_file(${CMAKE_SOURCE_DIR}/cmake/DownloadPrebuilt.cmake.in - ${CMAKE_BINARY_DIR}/DownloadPrebuilt.cmake @ONLY) -# Drive the download script at build time. Depend on 'install.xml' -# to aqcuire new binaries when needed. -add_custom_command( - COMMENT "Obtaining prebuilt binaries..." - OUTPUT ${CMAKE_BINARY_DIR}/prepare/prebuilt - COMMAND ${CMAKE_COMMAND} -P ${CMAKE_BINARY_DIR}/DownloadPrebuilt.cmake - DEPENDS ${CMAKE_SOURCE_DIR}/../install.xml - ${CMAKE_BINARY_DIR}/DownloadPrebuilt.cmake - ) +if (WINDOWS) + set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + PROPERTY VS_STARTUP_PROJECT ${VIEWER_BINARY_NAME}) +endif (WINDOWS) diff --git a/indra/aistatemachine/CMakeLists.txt b/indra/aistatemachine/CMakeLists.txt index 6db29a0073..42cfec5e2b 100644 --- a/indra/aistatemachine/CMakeLists.txt +++ b/indra/aistatemachine/CMakeLists.txt @@ -21,6 +21,7 @@ set(aistatemachine_SOURCE_FILES aistatemachine.cpp aistatemachinethread.cpp aitimer.cpp + aicondition.cpp ) set(aistatemachine_HEADER_FILES @@ -29,6 +30,7 @@ set(aistatemachine_HEADER_FILES aistatemachine.h aistatemachinethread.h aitimer.h + aicondition.h ) set_source_files_properties(${aistatemachine_HEADER_FILES} @@ -37,5 +39,9 @@ set_source_files_properties(${aistatemachine_HEADER_FILES} list(APPEND aistatemachine_SOURCE_FILES ${aistatemachine_HEADER_FILES}) add_library (aistatemachine ${aistatemachine_SOURCE_FILES}) -add_dependencies(aistatemachine prepare) +target_link_libraries( + aistatemachine + PUBLIC + llcommon + ) diff --git a/indra/aistatemachine/aicondition.cpp b/indra/aistatemachine/aicondition.cpp new file mode 100644 index 0000000000..2c9a4f8e8d --- /dev/null +++ b/indra/aistatemachine/aicondition.cpp @@ -0,0 +1,89 @@ +/** + * @file aicondition.cpp + * @brief Implementation of AICondition + * + * Copyright (c) 2013, Aleric Inglewood. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution. + * + * CHANGELOG + * and additional copyright holders. + * + * 14/10/2013 + * Initial version, written by Aleric Inglewood @ SL + */ + +#include "sys.h" +#include "aicondition.h" +#include "aistatemachine.h" + +void AIConditionBase::wait(AIStateMachine* state_machine) +{ + // The condition must be locked before calling AIStateMachine::wait(). + llassert(mutex().isSelfLocked()); + // Add the new state machine at the end. + mWaitingStateMachines.push_back(state_machine); +} + +void AIConditionBase::remove(AIStateMachine* state_machine) +{ + mutex().lock(); + // Remove all occurances of state_machine from the queue. + queue_t::iterator const end = mWaitingStateMachines.end(); + queue_t::iterator last = end; + for (queue_t::iterator iter = mWaitingStateMachines.begin(); iter != last; ++iter) + { + if (iter->get() == state_machine) + { + if (--last == iter) + { + break; + } + queue_t::value_type::swap(*iter, *last); + } + } + // This invalidates all iterators involved, including end, but not any iterators to the remaining elements. + mWaitingStateMachines.erase(last, end); + mutex().unlock(); +} + +void AIConditionBase::signal(int n) +{ + // The condition must be locked before calling AICondition::signal or AICondition::broadcast. + llassert(mutex().isSelfLocked()); + // Signal n state machines. + while (n > 0 && !mWaitingStateMachines.empty()) + { + LLPointer state_machine = mWaitingStateMachines.front(); + bool success = state_machine->signalled(); + // Only state machines that are actually still blocked should be in the queue: + // they are removed from the queue by calling AICondition::remove whenever + // they are unblocked for whatever reason... + llassert(success); + if (success) + { + ++n; + } + else + { + // We never get here... + remove(state_machine.get()); + } + } +} + diff --git a/indra/aistatemachine/aicondition.h b/indra/aistatemachine/aicondition.h new file mode 100644 index 0000000000..05dd9ea424 --- /dev/null +++ b/indra/aistatemachine/aicondition.h @@ -0,0 +1,110 @@ +/** + * @file aicondition.h + * @brief Condition variable for statemachines. + * + * Copyright (c) 2013, Aleric Inglewood. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution. + * + * CHANGELOG + * and additional copyright holders. + * + * 14/10/2013 + * Initial version, written by Aleric Inglewood @ SL + */ + +#ifndef AICONDITION_H +#define AICONDITION_H + +#include +#include +#include "aithreadsafe.h" + +class AIStateMachine; +class LLMutex; + +// class AICondition +// +// Call AIStateMachine::wait(AICondition&) in the multiplex_impl of a state machine to +// make the state machine go idle until some thread calls AICondition::signal(). +// +// If the state machine is no longer running or wasn't waiting anymore because +// something else woke it up, then AICondition::signal() will wake up another +// state machine (if any). +// +// Usage: +// +// struct Foo { bool met(); }; // Returns true when the condition is met. +// AICondition Condition_t; +// AIAccess Condition_wat; +// +// // Some thread-safe condition variable. +// Condition_t condition; +// +// // Inside the state machine: +// { +// ... +// state WAIT_FOR_CONDITION: +// { +// // Lock condition and check it. Wait if condition is not met yet. +// { +// Condition_wat condition_w(condition); +// if (!condition_w->met()) +// { +// wait(condition); +// break; +// } +// } +// set_state(CONDITION_MET); +// break; +// } +// CONDITION_MET: +// { +// + +class AIConditionBase +{ + public: + virtual ~AIConditionBase() { } + + void signal(int n = 1); // Call this when the condition was met to release n state machines. + void broadcast(void) { signal(mWaitingStateMachines.size()); } // Release all blocked state machines. + + private: + // These functions are called by AIStateMachine. + friend class AIStateMachine; + void wait(AIStateMachine* state_machine); + void remove(AIStateMachine* state_machine); + + protected: + virtual LLMutex& mutex(void) = 0; + + protected: + typedef std::deque > queue_t; + queue_t mWaitingStateMachines; +}; + +template +class AICondition : public AIThreadSafeSimpleDC, public AIConditionBase +{ + protected: + /*virtual*/ LLMutex& mutex(void) { return this->mMutex; } +}; + +#endif + diff --git a/indra/aistatemachine/aistatemachine.cpp b/indra/aistatemachine/aistatemachine.cpp index bf867fffd8..58c0518d50 100644 --- a/indra/aistatemachine/aistatemachine.cpp +++ b/indra/aistatemachine/aistatemachine.cpp @@ -33,6 +33,7 @@ #include "linden_common.h" #include "aistatemachine.h" +#include "aicondition.h" #include "lltimer.h" //================================================================== @@ -283,7 +284,7 @@ char const* HelloWorld::state_str_impl(state_type run_state) const void AIEngine::add(AIStateMachine* state_machine) { - Dout(dc::statemachine, "Adding state machine [" << (void*)state_machine << "] to " << mName); + Dout(dc::statemachine(state_machine->mSMDebug), "Adding state machine [" << (void*)state_machine << "] to " << mName); engine_state_type_wat engine_state_w(mEngineState); engine_state_w->list.push_back(QueueElement(state_machine)); if (engine_state_w->waiting) @@ -292,7 +293,36 @@ void AIEngine::add(AIStateMachine* state_machine) } } -extern void print_statemachine_diagnostics(U64 total_clocks, U64 max_delta, AIEngine::queued_type::const_reference slowest_state_machine); +#if STATE_MACHINE_PROFILING +// Called from AIStateMachine::mainloop +void print_statemachine_diagnostics(U64 total_clocks, AIStateMachine::StateTimerBase::TimeData& slowest_timer, AIEngine::queued_type::const_reference slowest_element) +{ + AIStateMachine const& slowest_state_machine = slowest_element.statemachine(); + F64 const tfactor = 1000 / calc_clock_frequency(); + std::ostringstream msg; + + U64 max_delta = slowest_timer.GetDuration(); + + if (total_clocks > max_delta) + { + msg << "AIStateMachine::mainloop did run for " << (total_clocks * tfactor) << " ms. The slowest "; + } + else + { + msg << "AIStateMachine::mainloop: A "; + } + msg << "state machine " << "(" << slowest_state_machine.getName() << ") " << "ran for " << (max_delta * tfactor) << " ms"; + if (slowest_state_machine.getRuntime() > max_delta) + { + msg << " (" << (slowest_state_machine.getRuntime() * tfactor) << " ms in total now)"; + } + msg << ".\n"; + + AIStateMachine::StateTimerBase::DumpTimers(msg); + + LL_WARNS() << msg.str() << LL_ENDL; +} +#endif // MAIN-THREAD void AIEngine::mainloop(void) @@ -304,33 +334,38 @@ void AIEngine::mainloop(void) queued_element = engine_state_w->list.begin(); } U64 total_clocks = 0; -#ifndef LL_RELEASE_FOR_DOWNLOAD - U64 max_delta = 0; +#if STATE_MACHINE_PROFILING queued_type::value_type slowest_element(NULL); + AIStateMachine::StateTimerRoot::TimeData slowest_timer; #endif while (queued_element != end) { AIStateMachine& state_machine(queued_element->statemachine()); - U64 start = get_clock_count(); - if (!state_machine.sleep(start)) + AIStateMachine::StateTimerBase::TimeData time_data; + if (!state_machine.sleep(get_clock_count())) { - state_machine.multiplex(AIStateMachine::normal_run); + AIStateMachine::StateTimerRoot timer(state_machine.getName()); + state_machine.multiplex(AIStateMachine::normal_run); + time_data = timer.GetTimerData(); } - U64 delta = get_clock_count() - start; - state_machine.add(delta); - total_clocks += delta; -#ifndef LL_RELEASE_FOR_DOWNLOAD - if (delta > max_delta) + if (U64 delta = time_data.GetDuration()) { - max_delta = delta; - slowest_element = *queued_element; - } + state_machine.add(delta); + total_clocks += delta; +#if STATE_MACHINE_PROFILING + if (delta > slowest_timer.GetDuration()) + { + slowest_element = *queued_element; + slowest_timer = time_data; + } #endif + } + bool active = state_machine.active(this); // This locks mState shortly, so it must be called before locking mEngineState because add() locks mEngineState while holding mState. engine_state_type_wat engine_state_w(mEngineState); if (!active) { - Dout(dc::statemachine, "Erasing state machine [" << (void*)&state_machine << "] from " << mName); + Dout(dc::statemachine(state_machine.mSMDebug), "Erasing state machine [" << (void*)&state_machine << "] from " << mName); engine_state_w->list.erase(queued_element++); } else @@ -339,8 +374,8 @@ void AIEngine::mainloop(void) } if (total_clocks >= sMaxCount) { -#ifndef LL_RELEASE_FOR_DOWNLOAD - print_statemachine_diagnostics(total_clocks, max_delta, slowest_element); +#if STATE_MACHINE_PROFILING + print_statemachine_diagnostics(total_clocks, slowest_timer, slowest_element); #endif Dout(dc::statemachine, "Sorting " << engine_state_w->list.size() << " state machines."); engine_state_w->list.sort(QueueElementComp()); @@ -372,7 +407,7 @@ void AIEngine::setMaxCount(F32 StateMachineMaxTime) sMaxCount = calc_clock_frequency() * StateMachineMaxTime / 1000; } -#if defined(CWDEBUG) || defined(DEBUG_CURLIO) +#ifdef CWDEBUG char const* AIStateMachine::event_str(event_type event) { switch(event) @@ -392,7 +427,7 @@ void AIStateMachine::multiplex(event_type event) // If this fails then you are using a pointer to a state machine instead of an LLPointer. llassert(event == initial_run || getNumRefs() > 0); - DoutEntering(dc::statemachine, "AIStateMachine::multiplex(" << event_str(event) << ") [" << (void*)this << "]"); + DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::multiplex(" << event_str(event) << ") [" << (void*)this << "]"); base_state_type state; state_type run_state; @@ -405,9 +440,9 @@ void AIStateMachine::multiplex(event_type event) // our need to run (by us having set need_run), so there is no need to run // ourselves. llassert(!mMultiplexMutex.isSelfLocked()); // We may never enter recursively! - if (!mMultiplexMutex.tryLock()) + if (!mMultiplexMutex.try_lock()) { - Dout(dc::statemachine, "Leaving because it is already being run [" << (void*)this << "]"); + Dout(dc::statemachine(mSMDebug), "Leaving because it is already being run [" << (void*)this << "]"); return; } @@ -421,7 +456,7 @@ void AIStateMachine::multiplex(event_type event) // we should indeed run, again. if (event == schedule_run && !sub_state_type_rat(mSubState)->need_run) { - Dout(dc::statemachine, "Leaving because it was already being run [" << (void*)this << "]"); + Dout(dc::statemachine(mSMDebug), "Leaving because it was already being run [" << (void*)this << "]"); return; } @@ -440,9 +475,9 @@ void AIStateMachine::multiplex(event_type event) { #ifdef CWDEBUG if (state == bs_multiplex) - Dout(dc::statemachine, "Running state bs_multiplex / " << state_str_impl(run_state) << " [" << (void*)this << "]"); + Dout(dc::statemachine(mSMDebug), "Running state bs_multiplex / " << state_str_impl(run_state) << " [" << (void*)this << "]"); else - Dout(dc::statemachine, "Running state " << state_str(state) << " [" << (void*)this << "]"); + Dout(dc::statemachine(mSMDebug), "Running state " << state_str(state) << " [" << (void*)this << "]"); #endif #ifdef SHOW_ASSERT @@ -503,7 +538,7 @@ void AIStateMachine::multiplex(event_type event) // run of bs_reset is not a problem because it happens to be a NoOp. state = (state == bs_initialize) ? bs_reset : bs_abort; #ifdef CWDEBUG - Dout(dc::statemachine, "Late abort detected! Running state " << state_str(state) << " instead [" << (void*)this << "]"); + Dout(dc::statemachine(mSMDebug), "Late abort detected! Running state " << state_str(state) << " instead [" << (void*)this << "]"); #endif } #ifdef SHOW_ASSERT @@ -665,7 +700,7 @@ void AIStateMachine::multiplex(event_type event) #ifdef CWDEBUG if (state != state_w->base_state) - Dout(dc::statemachine, "Base state changed from " << state_str(state) << " to " << state_str(state_w->base_state) << + Dout(dc::statemachine(mSMDebug), "Base state changed from " << state_str(state) << " to " << state_str(state_w->base_state) << "; need_new_run = " << (need_new_run ? "true" : "false") << " [" << (void*)this << "]"); #endif } @@ -699,11 +734,15 @@ void AIStateMachine::multiplex(event_type event) // Mark that we're added to this engine, and at the same time, that we're not added to the previous one. state_w->current_engine = engine; } +#ifdef SHOW_ASSERT + // We are leaving the loop, but we're not idle. The statemachine should re-enter the loop again. + mDebugShouldRun = true; +#endif } else { - // Remove this state machine from any engine. - // Cause the engine to remove us. + // Remove this state machine from any engine, + // causing the engine to remove us. state_w->current_engine = NULL; } @@ -723,7 +762,7 @@ void AIStateMachine::multiplex(event_type event) //========================================= // Release the lock on mMultiplexMutex *first*, before releasing the lock on mState, - // to avoid to ever call the tryLock() and fail, while this thread isn't still + // to avoid to ever call the try_lock() and fail, while this thread isn't still // BEFORE the critical area of mState! mMultiplexMutex.unlock(); @@ -747,9 +786,25 @@ void AIStateMachine::multiplex(event_type event) } } +#if STATE_MACHINE_PROFILING +std::vector AIStateMachine::StateTimerBase::mTimerStack; +AIStateMachine::StateTimerBase::TimeData AIStateMachine::StateTimerBase::TimeData::sRoot(""); +void AIStateMachine::StateTimer::TimeData::DumpTimer(std::ostringstream& msg, std::string prefix) +{ + F64 const tfactor = 1000 / calc_clock_frequency(); + msg << prefix << mName << " " << (mEnd - mStart)*tfactor << "ms" << std::endl; + prefix.push_back(' '); + std::vector::iterator it; + for (it = mChildren.begin(); it != mChildren.end(); ++it) + { + it->DumpTimer(msg, prefix); + } +} +#endif + AIStateMachine::state_type AIStateMachine::begin_loop(base_state_type base_state) { - DoutEntering(dc::statemachine, "AIStateMachine::begin_loop(" << state_str(base_state) << ") [" << (void*)this << "]"); + DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::begin_loop(" << state_str(base_state) << ") [" << (void*)this << "]"); sub_state_type_wat sub_state_w(mSubState); // Honor a subsequent call to idle() (only necessary in bs_multiplex, but it doesn't hurt to reset this flag in other states too). @@ -759,7 +814,7 @@ AIStateMachine::state_type AIStateMachine::begin_loop(base_state_type base_state // Honor previous calls to advance_state() (once run_state is initialized). if (base_state == bs_multiplex && sub_state_w->advance_state > sub_state_w->run_state) { - Dout(dc::statemachine, "Copying advance_state to run_state, because it is larger [" << state_str_impl(sub_state_w->advance_state) << " > " << state_str_impl(sub_state_w->run_state) << "]"); + Dout(dc::statemachine(mSMDebug), "Copying advance_state to run_state, because it is larger [" << state_str_impl(sub_state_w->advance_state) << " > " << state_str_impl(sub_state_w->run_state) << "]"); sub_state_w->run_state = sub_state_w->advance_state; } #ifdef SHOW_ASSERT @@ -789,7 +844,7 @@ AIStateMachine::state_type AIStateMachine::begin_loop(base_state_type base_state void AIStateMachine::run(AIStateMachine* parent, state_type new_parent_state, bool abort_parent, bool on_abort_signal_parent, AIEngine* default_engine) { - DoutEntering(dc::statemachine, "AIStateMachine::run(" << + DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::run(" << (void*)parent << ", " << (parent ? parent->state_str_impl(new_parent_state) : "NA") << ", abort_parent = " << (abort_parent ? "true" : "false") << @@ -839,7 +894,7 @@ void AIStateMachine::run(AIStateMachine* parent, state_type new_parent_state, bo void AIStateMachine::run(callback_type::signal_type::slot_type const& slot, AIEngine* default_engine) { - DoutEntering(dc::statemachine, "AIStateMachine::run(, default_engine = " << default_engine->name() << ") [" << (void*)this << "]"); + DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::run(, default_engine = " << default_engine->name() << ") [" << (void*)this << "]"); #ifdef SHOW_ASSERT { @@ -874,7 +929,7 @@ void AIStateMachine::run(callback_type::signal_type::slot_type const& slot, AIEn void AIStateMachine::callback(void) { - DoutEntering(dc::statemachine, "AIStateMachine::callback() [" << (void*)this << "]"); + DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::callback() [" << (void*)this << "]"); bool aborted = sub_state_type_rat(mSubState)->aborted; if (mParent) @@ -920,7 +975,7 @@ void AIStateMachine::force_killed(void) void AIStateMachine::kill(void) { - DoutEntering(dc::statemachine, "AIStateMachine::kill() [" << (void*)this << "]"); + DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::kill() [" << (void*)this << "]"); #ifdef SHOW_ASSERT { multiplex_state_type_rat state_r(mState); @@ -937,7 +992,7 @@ void AIStateMachine::kill(void) void AIStateMachine::reset() { - DoutEntering(dc::statemachine, "AIStateMachine::reset() [" << (void*)this << "]"); + DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::reset() [" << (void*)this << "]"); #ifdef SHOW_ASSERT mDebugAborted = false; mDebugContPending = false; @@ -960,6 +1015,8 @@ void AIStateMachine::reset() sub_state_w->reset = true; // Start running. sub_state_w->idle = false; + // We're not waiting for a condition. + sub_state_w->blocked = NULL; // Keep running till we reach at least bs_multiplex. sub_state_w->need_run = true; } @@ -972,7 +1029,7 @@ void AIStateMachine::reset() void AIStateMachine::set_state(state_type new_state) { - DoutEntering(dc::statemachine, "AIStateMachine::set_state(" << state_str_impl(new_state) << ") [" << (void*)this << "]"); + DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::set_state(" << state_str_impl(new_state) << ") [" << (void*)this << "]"); #ifdef SHOW_ASSERT { multiplex_state_type_rat state_r(mState); @@ -983,6 +1040,8 @@ void AIStateMachine::set_state(state_type new_state) } #endif sub_state_type_wat sub_state_w(mSubState); + // It should never happen that set_state() is called while we're blocked. + llassert(!sub_state_w->blocked); // Force current state to the requested state. sub_state_w->run_state = new_state; // Void last call to advance_state. @@ -999,13 +1058,13 @@ void AIStateMachine::set_state(state_type new_state) void AIStateMachine::advance_state(state_type new_state) { - DoutEntering(dc::statemachine, "AIStateMachine::advance_state(" << state_str_impl(new_state) << ") [" << (void*)this << "]"); + DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::advance_state(" << state_str_impl(new_state) << ") [" << (void*)this << "]"); { sub_state_type_wat sub_state_w(mSubState); // Ignore call to advance_state when the currently queued state is already greater or equal to the requested state. if (sub_state_w->advance_state >= new_state) { - Dout(dc::statemachine, "Ignored, because " << state_str_impl(sub_state_w->advance_state) << " >= " << state_str_impl(new_state) << "."); + Dout(dc::statemachine(mSMDebug), "Ignored, because " << state_str_impl(sub_state_w->advance_state) << " >= " << state_str_impl(new_state) << "."); return; } // Ignore call to advance_state when the current state is greater than the requested state: the new state would be @@ -1014,7 +1073,7 @@ void AIStateMachine::advance_state(state_type new_state) // the state change is and should be being ignored: the statemachine would start running it's current state (again). if (sub_state_w->run_state > new_state) { - Dout(dc::statemachine, "Ignored, because " << state_str_impl(sub_state_w->run_state) << " > " << state_str_impl(new_state) << " (current state)."); + Dout(dc::statemachine(mSMDebug), "Ignored, because " << state_str_impl(sub_state_w->run_state) << " > " << state_str_impl(new_state) << " (current state)."); return; } // Increment state. @@ -1023,6 +1082,13 @@ void AIStateMachine::advance_state(state_type new_state) sub_state_w->idle = false; // Ignore a call to idle if it occurs before we leave multiplex_impl(). sub_state_w->skip_idle = true; + // No longer say we woke up when signalled() is called. + if (sub_state_w->blocked) + { + Dout(dc::statemachine(mSMDebug), "Removing statemachine from condition " << (void*)sub_state_w->blocked); + sub_state_w->blocked->remove(this); + sub_state_w->blocked = NULL; + } // Mark that a re-entry of multiplex() is necessary. sub_state_w->need_run = true; #ifdef SHOW_ASSERT @@ -1048,7 +1114,7 @@ void AIStateMachine::advance_state(state_type new_state) void AIStateMachine::idle(void) { - DoutEntering(dc::statemachine, "AIStateMachine::idle() [" << (void*)this << "]"); + DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::idle() [" << (void*)this << "]"); #ifdef SHOW_ASSERT { multiplex_state_type_rat state_r(mState); @@ -1066,7 +1132,7 @@ void AIStateMachine::idle(void) // Ignore call to idle() when advance_state() was called since last call to set_state(). if (sub_state_w->skip_idle) { - Dout(dc::statemachine, "Ignored, because skip_idle is true (advance_state() was called last)."); + Dout(dc::statemachine(mSMDebug), "Ignored, because skip_idle is true (advance_state() was called last)."); return; } // Mark that we are idle. @@ -1075,13 +1141,54 @@ void AIStateMachine::idle(void) mSleep = 0; } +// This function is very much like idle(). +void AIStateMachine::wait(AIConditionBase& condition) +{ + DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::wait(" << (void*)&condition << ") [" << (void*)this << "]"); +#ifdef SHOW_ASSERT + { + multiplex_state_type_rat state_r(mState); + // wait() may only be called multiplex_impl(). + llassert(state_r->base_state == bs_multiplex); + // May only be called by the thread that is holding mMultiplexMutex. + llassert(mThreadId.equals_current_thread()); + } + // wait() following set_state() cancels the reason to run because of the call to set_state. + mDebugSetStatePending = false; +#endif + sub_state_type_wat sub_state_w(mSubState); + // As wait() may only be called from within the state machine, it should never happen that the state machine is already idle. + llassert(!sub_state_w->idle); + // Ignore call to wait() when advance_state() was called since last call to set_state(). + if (sub_state_w->skip_idle) + { + Dout(dc::statemachine(mSMDebug), "Ignored, because skip_idle is true (advance_state() was called last)."); + return; + } + // Register ourselves with the condition object. + condition.wait(this); + // Mark that we are idle. + sub_state_w->idle = true; + // Mark that we are waiting for a condition. + sub_state_w->blocked = &condition; + // Not sleeping (anymore). + mSleep = 0; +} + void AIStateMachine::cont(void) { - DoutEntering(dc::statemachine, "AIStateMachine::cont() [" << (void*)this << "]"); + DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::cont() [" << (void*)this << "]"); { sub_state_type_wat sub_state_w(mSubState); // Void last call to idle(), if any. sub_state_w->idle = false; + // No longer say we woke up when signalled() is called. + if (sub_state_w->blocked) + { + Dout(dc::statemachine(mSMDebug), "Removing statemachine from condition " << (void*)sub_state_w->blocked); + sub_state_w->blocked->remove(this); + sub_state_w->blocked = NULL; + } // Mark that a re-entry of multiplex() is necessary. sub_state_w->need_run = true; #ifdef SHOW_ASSERT @@ -1095,15 +1202,56 @@ void AIStateMachine::cont(void) } } +// This function is very much like cont(), except that it has no effect when we are not in a blocked state. +// Returns true if the state machine was unblocked, false if it was already unblocked. +bool AIStateMachine::signalled(void) +{ + DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::signalled() [" << (void*)this << "]"); + { + sub_state_type_wat sub_state_w(mSubState); + // Test if we are blocked or not. + if (sub_state_w->blocked) + { + Dout(dc::statemachine(mSMDebug), "Removing statemachine from condition " << (void*)sub_state_w->blocked); + sub_state_w->blocked->remove(this); + sub_state_w->blocked = NULL; + } + else + { + return false; + } + // Void last call to wait(). + sub_state_w->idle = false; + // Mark that a re-entry of multiplex() is necessary. + sub_state_w->need_run = true; +#ifdef SHOW_ASSERT + // From this moment. + mDebugContPending = true; +#endif + } + if (!mMultiplexMutex.isSelfLocked()) + { + multiplex(schedule_run); + } + return true; +} + void AIStateMachine::abort(void) { - DoutEntering(dc::statemachine, "AIStateMachine::abort() [" << (void*)this << "]"); + DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::abort() [" << (void*)this << "]"); bool is_waiting = false; { multiplex_state_type_rat state_r(mState); sub_state_type_wat sub_state_w(mSubState); // Mark that we are aborted, iff we didn't already finish. sub_state_w->aborted = !sub_state_w->finished; + // No longer say we woke up when signalled() is called. + if (sub_state_w->blocked) + { + Dout(dc::statemachine(mSMDebug), "Removing statemachine from condition " << (void*)sub_state_w->blocked); + sub_state_w->blocked->remove(this); + sub_state_w->blocked = NULL; + } // Mark that a re-entry of multiplex() is necessary. sub_state_w->need_run = true; // Schedule a new run when this state machine is waiting. @@ -1114,9 +1262,9 @@ void AIStateMachine::abort(void) multiplex(insert_abort); } // Block until the current run finished. - if (!mRunMutex.tryLock()) + if (!mRunMutex.try_lock()) { - llwarns << "AIStateMachine::abort() blocks because the statemachine is still executing code in another thread." << llendl; + LL_WARNS() << "AIStateMachine::abort() blocks because the statemachine is still executing code in another thread." << LL_ENDL; mRunMutex.lock(); } mRunMutex.unlock(); @@ -1128,7 +1276,7 @@ void AIStateMachine::abort(void) void AIStateMachine::finish(void) { - DoutEntering(dc::statemachine, "AIStateMachine::finish() [" << (void*)this << "]"); + DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::finish() [" << (void*)this << "]"); #ifdef SHOW_ASSERT { multiplex_state_type_rat state_r(mState); @@ -1147,7 +1295,7 @@ void AIStateMachine::finish(void) void AIStateMachine::yield(void) { - DoutEntering(dc::statemachine, "AIStateMachine::yield() [" << (void*)this << "]"); + DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::yield() [" << (void*)this << "]"); multiplex_state_type_rat state_r(mState); // yield() may only be called from multiplex_impl(). llassert(state_r->base_state == bs_multiplex); @@ -1160,7 +1308,7 @@ void AIStateMachine::yield(void) void AIStateMachine::yield(AIEngine* engine) { llassert(engine); - DoutEntering(dc::statemachine, "AIStateMachine::yield(" << engine->name() << ") [" << (void*)this << "]"); + DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::yield(" << engine->name() << ") [" << (void*)this << "]"); #ifdef SHOW_ASSERT { multiplex_state_type_rat state_r(mState); @@ -1173,9 +1321,19 @@ void AIStateMachine::yield(AIEngine* engine) mYieldEngine = engine; } +bool AIStateMachine::yield_if_not(AIEngine* engine) +{ + if (engine && multiplex_state_type_rat(mState)->current_engine != engine) + { + yield(engine); + return true; + } + return false; +} + void AIStateMachine::yield_frame(unsigned int frames) { - DoutEntering(dc::statemachine, "AIStateMachine::yield_frame(" << frames << ") [" << (void*)this << "]"); + DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::yield_frame(" << frames << ") [" << (void*)this << "]"); mSleep = -(S64)frames; // Sleeping is always done from the main thread. yield(&gMainThreadEngine); @@ -1183,7 +1341,7 @@ void AIStateMachine::yield_frame(unsigned int frames) void AIStateMachine::yield_ms(unsigned int ms) { - DoutEntering(dc::statemachine, "AIStateMachine::yield_ms(" << ms << ") [" << (void*)this << "]"); + DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::yield_ms(" << ms << ") [" << (void*)this << "]"); mSleep = get_clock_count() + calc_clock_frequency() * ms / 1000; // Sleeping is always done from the main thread. yield(&gMainThreadEngine); @@ -1233,7 +1391,7 @@ void AIEngine::threadloop(void) engine_state_type_wat engine_state_w(mEngineState); if (!active) { - Dout(dc::statemachine, "Erasing state machine [" << (void*)&state_machine << "] from " << mName); + Dout(dc::statemachine(state_machine.mSMDebug), "Erasing state machine [" << (void*)&state_machine << "] from " << mName); engine_state_w->list.erase(queued_element++); } else @@ -1305,6 +1463,6 @@ void stopEngineThread(void) { ms_sleep(10); } - llinfos << "State machine thread" << (!AIEngineThread::sInstance->isStopped() ? " not" : "") << " stopped after " << ((400 - count) * 10) << "ms." << llendl; + LL_INFOS() << "State machine thread" << (!AIEngineThread::sInstance->isStopped() ? " not" : "") << " stopped after " << ((400 - count) * 10) << "ms." << LL_ENDL; } diff --git a/indra/aistatemachine/aistatemachine.h b/indra/aistatemachine/aistatemachine.h index 2b019c91fd..f60430ed9a 100644 --- a/indra/aistatemachine/aistatemachine.h +++ b/indra/aistatemachine/aistatemachine.h @@ -36,9 +36,11 @@ #include "aithreadsafe.h" #include +#include "lltimer.h" #include #include +class AIConditionBase; class AIStateMachine; class AIEngine @@ -97,11 +99,143 @@ class AIEngine extern AIEngine gMainThreadEngine; extern AIEngine gStateMachineThreadEngine; +#ifndef STATE_MACHINE_PROFILING +#ifndef LL_RELEASE_FOR_DOWNLOAD +#define STATE_MACHINE_PROFILING 1 +#endif +#endif + class AIStateMachine : public LLThreadSafeRefCount { public: typedef U32 state_type; //!< The type of run_state + // A simple timer class that will calculate time delta between ctor and GetTimerData call. + // Time data is stored as a nested TimeData object. + // If STATE_MACHINE_PROFILING is defined then a stack of all StateTimers from root is maintained for debug output. + class StateTimerBase + { + public: + class TimeData + { + friend class StateTimerBase; + public: + TimeData() : mStart(-1), mEnd(-1) {} + U64 GetDuration() { return mEnd - mStart; } + private: + U64 mStart, mEnd; + +#if !STATE_MACHINE_PROFILING + TimeData(const std::string& name) : mStart(get_clock_count()), mEnd(get_clock_count()) {} +#else + TimeData(const std::string& name) : mName(name), mStart(get_clock_count()), mEnd(get_clock_count()) {} + void DumpTimer(std::ostringstream& msg, std::string prefix); + std::vector mChildren; + std::string mName; + static TimeData sRoot; +#endif + }; +#if !STATE_MACHINE_PROFILING + StateTimerBase(const std::string& name) : mData(name) {} + ~StateTimerBase() {} + protected: + TimeData mData; + // Return a copy of the underlying timer data. + // This allows the data live beyond the scope of the state timer. + public: + const TimeData GetTimerData() + { + mData.mEnd = get_clock_count(); //set mEnd to current time, since GetTimerData() will always be called before the dtor, obv. + return mData; + } +#else + protected: + // Ctors/dtors are hidden. Only StateTimerRoot and StateTimer are permitted to access them. + StateTimerBase() : mData(NULL) {} + ~StateTimerBase() + { + // If mData is null then the timer was not registered due to being in the wrong thread or the root timer wasn't in the expected state. + if (!mData) + return; + mData->mEnd = get_clock_count(); + mTimerStack.pop_back(); + } + + // Also hide internals from everything except StateTimerRoot and StateTimer + bool AddAsRoot(const std::string& name) + { + + if (!is_main_thread()) + return true; //Ignoring this timer, but pretending it was added. + if (!mTimerStack.empty()) + return false; + TimeData::sRoot = TimeData(name); + mData = &TimeData::sRoot; + mData->mChildren.clear(); + mTimerStack.push_back(this); + return true; + } + bool AddAsChild(const std::string& name) + { + if (!is_main_thread()) + return true; //Ignoring this timer, but pretending it was added. + if (mTimerStack.empty()) + return false; + mTimerStack.back()->mData->mChildren.push_back(TimeData(name)); + mData = &mTimerStack.back()->mData->mChildren.back(); + mTimerStack.push_back(this); + return true; + } + + TimeData* mData; + static std::vector mTimerStack; + + public: + // Debug spew + static void DumpTimers(std::ostringstream& msg) + { + TimeData::sRoot.DumpTimer(msg, ""); + } + + // Return a copy of the underlying timer data. + // This allows the data live beyond the scope of the state timer. + const TimeData GetTimerData() const + { + if (mData) + { + TimeData ret = *mData; + ret.mEnd = get_clock_count(); //set mEnd to current time, since GetTimerData() will always be called before the dtor, obv. + return ret; + } + return TimeData(); + } +#endif + }; +public: +#if !STATE_MACHINE_PROFILING + typedef StateTimerBase StateTimerRoot; + typedef StateTimerBase StateTimer; +#else + class StateTimerRoot : public StateTimerBase + { //A StateTimerRoot can become a child if a root already exists. + public: + StateTimerRoot(const std::string& name) + { + if(!AddAsRoot(name)) + AddAsChild(name); + } + }; + class StateTimer : public StateTimerBase + { //A StateTimer can never become a root + public: + StateTimer(const std::string& name) + { + AddAsChild(name); + } + }; +#endif + + protected: // The type of event that causes multiplex() to be called. enum event_type { @@ -132,6 +266,7 @@ class AIStateMachine : public LLThreadSafeRefCount struct sub_state_type { state_type run_state; state_type advance_state; + AIConditionBase* blocked; bool reset; bool need_run; bool idle; @@ -195,20 +330,36 @@ class AIStateMachine : public LLThreadSafeRefCount bool mDebugAdvanceStatePending; // True while advance_state() was called by not handled yet. bool mDebugRefCalled; // True when ref() is called (or will be called within the critial area of mMultiplexMutex). #endif +#ifdef CWDEBUG + protected: + bool mSMDebug; // Print debug output only when true. +#endif + private: U64 mRuntime; // Total time spent running in the main thread (in clocks). public: - AIStateMachine(void) : mCallback(NULL), mDefaultEngine(NULL), mYieldEngine(NULL), + AIStateMachine(CWD_ONLY(bool debug)) : mCallback(NULL), mDefaultEngine(NULL), mYieldEngine(NULL), #ifdef SHOW_ASSERT mThreadId(AIThreadID::none), mDebugLastState(bs_killed), mDebugShouldRun(false), mDebugAborted(false), mDebugContPending(false), mDebugSetStatePending(false), mDebugAdvanceStatePending(false), mDebugRefCalled(false), +#endif +#ifdef CWDEBUG + mSMDebug(debug), #endif mRuntime(0) { } protected: - // The user should call finish() (or abort(), or kill() from the call back when finish_impl() calls run()), not delete a class derived from AIStateMachine directly. - virtual ~AIStateMachine() { llassert(multiplex_state_type_rat(mState)->base_state == bs_killed); } + // The user should call finish() (or abort(), or kill() from the call back when finish_impl() calls run()), + // not delete a class derived from AIStateMachine directly. Deleting it directly before calling run() is + // ok however. + virtual ~AIStateMachine() + { +#ifdef SHOW_ASSERT + base_state_type state = multiplex_state_type_rat(mState)->base_state; + llassert(state == bs_killed || state == bs_reset); +#endif + } public: // These functions may be called directly after creation, or from within finish_impl(), or from the call back function. @@ -224,11 +375,13 @@ class AIStateMachine : public LLThreadSafeRefCount void set_state(state_type new_state); // Run this state the NEXT loop. // These functions can only be called from within multiplex_impl(). void idle(void); // Go idle unless cont() or advance_state() were called since the start of the current loop, or until they are called. + void wait(AIConditionBase& condition); // The same as idle(), but wake up when AICondition::signal() is called. void finish(void); // Mark that the state machine finished and schedule the call back. void yield(void); // Yield to give CPU to other state machines, but do not go idle. void yield(AIEngine* engine); // Yield to give CPU to other state machines, but do not go idle. Continue running from engine 'engine'. void yield_frame(unsigned int frames); // Run from the main-thread engine after at least 'frames' frames have passed. void yield_ms(unsigned int ms); // Run from the main-thread engine after roughly 'ms' miliseconds have passed. + bool yield_if_not(AIEngine* engine); // Do not really yield, unless the current engine is not 'engine'. Returns true if it switched engine. public: // This function can be called from multiplex_imp(), but also by a child state machine and @@ -236,11 +389,12 @@ class AIStateMachine : public LLThreadSafeRefCount // to access this state machine. void abort(void); // Abort the state machine (unsuccessful finish). - // These are the only two functions that can be called by any thread at any moment. + // These are the only three functions that can be called by any thread at any moment. // Those threads should use an LLPointer to access this state machine. void cont(void); // Guarantee at least one full run of multiplex() after this function is called. Cancels the last call to idle(). void advance_state(state_type new_state); // Guarantee at least one full run of multiplex() after this function is called // iff new_state is larger than the last state that was processed. + bool signalled(void); // Call cont() iff this state machine is still blocked after a call to wait(). Returns false if it already unblocked. public: // Accessors. @@ -274,19 +428,23 @@ class AIStateMachine : public LLThreadSafeRefCount // Return stringified state, for debugging purposes. char const* state_str(base_state_type state); -#if defined(CWDEBUG) || defined(DEBUG_CURLIO) +#ifdef CWDEBUG char const* event_str(event_type event); #endif void add(U64 count) { mRuntime += count; } U64 getRuntime(void) const { return mRuntime; } + // For diagnostics. Every derived class must override this. + virtual const char* getName() const = 0; + protected: virtual void initialize_impl(void) = 0; virtual void multiplex_impl(state_type run_state) = 0; virtual void abort_impl(void) { } virtual void finish_impl(void) { } virtual char const* state_str_impl(state_type run_state) const = 0; + virtual void force_killed(void); // Called from AIEngine::flush(). private: void reset(void); // Called from run() to (re)initialize a (re)start. @@ -303,7 +461,6 @@ class AIStateMachine : public LLThreadSafeRefCount mSleep = 0; return mSleep != 0; } - void force_killed(void); // Called from AIEngine::flush(). friend class AIEngine; // Calls multiplex() and force_killed(). }; diff --git a/indra/aistatemachine/aistatemachinethread.cpp b/indra/aistatemachine/aistatemachinethread.cpp index caeddea5cf..325869a7d0 100644 --- a/indra/aistatemachine/aistatemachinethread.cpp +++ b/indra/aistatemachine/aistatemachinethread.cpp @@ -149,7 +149,7 @@ void AIStateMachineThreadBase::abort_impl(void) { // The thread is still happily running (and will clean up itself). // Lets make sure we're not flooded with this situation. - llwarns << "Thread state machine aborted while the thread is still running. That is a waste of CPU and should be avoided." << llendl; + LL_WARNS() << "Thread state machine aborted while the thread is still running. That is a waste of CPU and should be avoided." << LL_ENDL; } } } diff --git a/indra/aistatemachine/aistatemachinethread.h b/indra/aistatemachine/aistatemachinethread.h index 780060bb6a..bf70be6c7b 100644 --- a/indra/aistatemachine/aistatemachinethread.h +++ b/indra/aistatemachine/aistatemachinethread.h @@ -34,6 +34,7 @@ #include "aistatemachine.h" #include "llthread.h" #include "aithreadsafe.h" +#include #ifdef EXAMPLE_CODE // undefined @@ -181,7 +182,11 @@ class AIStateMachineThreadBase : public AIStateMachine { static state_type const max_state = wait_stopped + 1; protected: - AIStateMachineThreadBase(void) { } + AIStateMachineThreadBase(CWD_ONLY(bool debug)) +#ifdef CWDEBUG + : AIStateMachine(debug) +#endif + { } private: // Handle initializing the object. @@ -217,7 +222,10 @@ class AIStateMachineThread : public AIStateMachineThreadBase { public: // Constructor. - AIStateMachineThread(void) + AIStateMachineThread(CWD_ONLY(bool debug)) +#ifdef CWDEBUG + : AIStateMachineThreadBase(debug) +#endif { *AIThreadImpl::StateMachineThread_wat(mThreadImpl.mStateMachineThread) = this; } @@ -225,6 +233,13 @@ class AIStateMachineThread : public AIStateMachineThreadBase { // Accessor. THREAD_IMPL& thread_impl(void) { return mThreadImpl; } + /*virtual*/ const char* getName() const + { +#define STRIZE(arg) #arg + return (boost::format("%1%%2%%3%") % "AIStateMachineThread<" % STRIZE(THREAD_IMPL) % ">").str().c_str(); +#undef STRIZE + } + protected: /*virtual*/ AIThreadImpl& impl(void) { return mThreadImpl; } }; diff --git a/indra/aistatemachine/aitimer.h b/indra/aistatemachine/aitimer.h index 5b028c6e0e..97f3b297e8 100644 --- a/indra/aistatemachine/aitimer.h +++ b/indra/aistatemachine/aitimer.h @@ -76,7 +76,11 @@ class AITimer : public AIStateMachine { F64 mInterval; //!< Input variable: interval after which the event will be generated, in seconds. public: - AITimer(void) : mInterval(0) { DoutEntering(dc::statemachine, "AITimer(void) [" << (void*)this << "]"); } + AITimer(CWD_ONLY(bool debug = false)) : +#ifdef CWDEBUG + AIStateMachine(debug), +#endif + mInterval(0) { DoutEntering(dc::statemachine(mSMDebug), "AITimer(void) [" << (void*)this << "]"); } /** * @brief Set the interval after which the timer should expire. @@ -94,9 +98,11 @@ class AITimer : public AIStateMachine { */ F64 getInterval(void) const { return mInterval; } + /*virtual*/ const char* getName() const { return "AITimer"; } + protected: // Call finish() (or abort()), not delete. - /*virtual*/ ~AITimer() { DoutEntering(dc::statemachine, "~AITimer() [" << (void*)this << "]"); mFrameTimer.cancel(); } + /*virtual*/ ~AITimer() { DoutEntering(dc::statemachine(mSMDebug), "~AITimer() [" << (void*)this << "]"); mFrameTimer.cancel(); } // Handle initializing the object. /*virtual*/ void initialize_impl(void); diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake index e8ce73f7da..1d0b7f1f60 100644 --- a/indra/cmake/00-Common.cmake +++ b/indra/cmake/00-Common.cmake @@ -5,37 +5,25 @@ if(NOT DEFINED ${CMAKE_CURRENT_LIST_FILE}_INCLUDED) set(${CMAKE_CURRENT_LIST_FILE}_INCLUDED "YES") +include(CheckCCompilerFlag) include(Variables) - # Portable compilation flags. set(CMAKE_CXX_FLAGS_DEBUG "-D_DEBUG -DLL_DEBUG=1") set(CMAKE_CXX_FLAGS_RELEASE - "-DLL_RELEASE=1 -DLL_RELEASE_FOR_DOWNLOAD=1 -D_SECURE_SCL=0 -DLL_SEND_CRASH_REPORTS=1 -DNDEBUG") + "-DLL_RELEASE=1 -DLL_RELEASE_FOR_DOWNLOAD=1 -D_SECURE_SCL=0 -DNDEBUG") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO - "-DLL_RELEASE=1 -D_SECURE_SCL=0 -DLL_SEND_CRASH_REPORTS=0 -DNDEBUG -DLL_RELEASE_WITH_DEBUG_INFO=1") + "-DLL_RELEASE=1 -D_SECURE_SCL=0 -DNDEBUG -DLL_RELEASE_WITH_DEBUG_INFO=1") # Don't bother with a MinSizeRel build. - set(CMAKE_CONFIGURATION_TYPES "RelWithDebInfo;Release;Debug" CACHE STRING "Supported build types." FORCE) # Platform-specific compilation flags. - if (WINDOWS) - # Various libs are compiler specific, generate some variables here we can just use - # when we require them instead of reimplementing the test each time. - if (MSVC10) - set(MSVC_DIR 10.0) - set(MSVC_SUFFIX 100) - endif (MSVC10) - - # Remove default /Zm1000 flag that cmake inserts - string (REPLACE "/Zm1000" " " CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") - # Don't build DLLs. set(BUILD_SHARED_LIBS OFF) @@ -45,44 +33,88 @@ if (WINDOWS) "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Od /Zi /MD /MP" CACHE STRING "C++ compiler release-with-debug options" FORCE) set(CMAKE_CXX_FLAGS_RELEASE - "${CMAKE_CXX_FLAGS_RELEASE} ${LL_CXX_FLAGS} /O2 /Zi /MD /MP /fp:fast -D_SECURE_STL=0 -D_HAS_ITERATOR_DEBUGGING=0" + "${CMAKE_CXX_FLAGS_RELEASE} ${LL_CXX_FLAGS} /O2 /Zi /Zo /MD /MP /Ob2 /Zc:inline /fp:fast -D_ITERATOR_DEBUG_LEVEL=0" CACHE STRING "C++ compiler release options" FORCE) set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${LL_C_FLAGS} /O2 /Zi /MD /MP /fp:fast" CACHE STRING "C compiler release options" FORCE) - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /LARGEADDRESSAWARE") + + if (ADDRESS_SIZE EQUAL 32) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /LARGEADDRESSAWARE") + endif (ADDRESS_SIZE EQUAL 32) + + if (FULL_DEBUG_SYMS OR USE_CRASHPAD) + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /DEBUG:FULL") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /DEBUG:FULL") + else () + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /DEBUG:FASTLINK") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /DEBUG:FASTLINK") + endif () + + if (USE_LTO) + if(INCREMENTAL_LINK) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /LTCG:INCREMENTAL") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /LTCG:INCREMENTAL") + set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} /LTCG:INCREMENTAL") + else(INCREMENTAL_LINK) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /LTCG") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /LTCG") + set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} /LTCG") + endif(INCREMENTAL_LINK) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /OPT:REF /OPT:ICF /LTCG") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /OPT:REF /OPT:ICF /LTCG") + set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} /LTCG") + elseif (INCREMENTAL_LINK) + set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS} /INCREMENTAL /VERBOSE:INCR") + set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS} /INCREMENTAL /VERBOSE:INCR") + else () + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /OPT:REF /INCREMENTAL:NO") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /OPT:REF /INCREMENTAL:NO") + endif () set(CMAKE_CXX_STANDARD_LIBRARIES "") set(CMAKE_C_STANDARD_LIBRARIES "") add_definitions( /DLL_WINDOWS=1 + /DNOMINMAX /DUNICODE - /D_UNICODE + /D_UNICODE + /DBOOST_CONFIG_SUPPRESS_OUTDATED_MESSAGE /GS /TP /W3 /c + /Zc:__cplusplus /Zc:forScope - /Zc:wchar_t- + /Zc:rvalueCast + /Zc:wchar_t /nologo /Oy- - /arch:SSE2 + /Zm140 + /wd4267 + /wd4244 ) - # configure win32 API for windows XP+ compatibility - set(WINVER "0x0501" CACHE STRING "Win32 API Target version (see http://msdn.microsoft.com/en-us/library/aa383745%28v=VS.85%29.aspx)") - add_definitions("/DWINVER=${WINVER}" "/D_WIN32_WINNT=${WINVER}") + if (USE_LTO) + add_compile_options( + /GL + /Gy + /Gw + ) + endif (USE_LTO) + + if (ADDRESS_SIZE EQUAL 32) + add_compile_options(/arch:SSE2) + endif (ADDRESS_SIZE EQUAL 32) - # Are we using the crummy Visual Studio KDU build workaround? if (NOT DISABLE_FATAL_WARNINGS) add_definitions(/WX) endif (NOT DISABLE_FATAL_WARNINGS) - SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /MANIFEST:NO") - SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /MANIFEST:NO") - SET(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} /MANIFEST:NO") - + # configure win32 API for windows Vista+ compatibility + set(WINVER "0x0600" CACHE STRING "Win32 API Target version (see http://msdn.microsoft.com/en-us/library/aa383745%28v=VS.85%29.aspx)") + add_definitions("/DWINVER=${WINVER}" "/D_WIN32_WINNT=${WINVER}") endif (WINDOWS) set (GCC_EXTRA_OPTIMIZATIONS "-ffast-math") @@ -90,20 +122,30 @@ set (GCC_EXTRA_OPTIMIZATIONS "-ffast-math") if (LINUX) set(CMAKE_SKIP_RPATH TRUE) + add_compile_options( + -fvisibility=hidden + -fexceptions + -fno-math-errno + -fno-strict-aliasing + -fsigned-char + -g + -pthread + ) + add_definitions( - -DLL_LINUX=1 - -DAPPID=secondlife - -D_REENTRANT - -fexceptions - -fno-math-errno - -fno-strict-aliasing - -fsigned-char - -fvisibility=hidden - -g - -pthread - ) + -DLL_LINUX=1 + -DAPPID=secondlife + -D_REENTRANT + -DGDK_DISABLE_DEPRECATED + -DGTK_DISABLE_DEPRECATED + -DGSEAL_ENABLE + -DGTK_DISABLE_SINGLE_INCLUDES + ) + + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++14") - set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -D_FORTIFY_SOURCE=2 ") + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2") # Don't catch SIGCHLD in our base application class for the viewer # some of our 3rd party libs may need their *own* SIGCHLD handler to work. Sigh! @@ -158,50 +200,40 @@ if (LINUX) # End of hacks. - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99") + CHECK_C_COMPILER_FLAG(-fstack-protector-strong HAS_STRONG_STACK_PROTECTOR) + if (${CMAKE_BUILD_TYPE} STREQUAL "Release") + if(HAS_STRONG_STACK_PROTECTOR) + add_compile_options(-fstack-protector-strong) + endif(HAS_STRONG_STACK_PROTECTOR) + endif (${CMAKE_BUILD_TYPE} STREQUAL "Release") - if (NOT STANDALONE) - # this stops us requiring a really recent glibc at runtime - add_definitions(-fno-stack-protector) - endif (NOT STANDALONE) if (${ARCH} STREQUAL "x86_64") - add_definitions(-DLINUX64=1 -pipe) - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fomit-frame-pointer -ffast-math -funroll-loops") - set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -fomit-frame-pointer -ffast-math -funroll-loops") - set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -ffast-math") - set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -ffast-math") + add_definitions(-pipe) + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -ffast-math -msse4.1") + set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -ffast-math -msse4.1") + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -ffast-math -msse4.1") + set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -ffast-math -msse4.1") else (${ARCH} STREQUAL "x86_64") if (NOT STANDALONE) set(MARCH_FLAG " -march=pentium4") endif (NOT STANDALONE) - set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}${MARCH_FLAG} -fno-inline -msse2") - set(CMAKE_C_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}${MARCH_FLAG} -fno-inline -msse2") - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}${MARCH_FLAG} -mfpmath=sse,387 -msse2 ${GCC_EXTRA_OPTIMIZATIONS}") - set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}${MARCH_FLAG} -mfpmath=sse,387 -msse2 ${GCC_EXTRA_OPTIMIZATIONS}") - set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}${MARCH_FLAG} -mfpmath=sse,387 -msse2 ${GCC_EXTRA_OPTIMIZATIONS}") - set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}${MARCH_FLAG} -mfpmath=sse,387 -msse2 ${GCC_EXTRA_OPTIMIZATIONS}") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}${MARCH_FLAG} -fno-inline -msse3") + set(CMAKE_C_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}${MARCH_FLAG} -fno-inline -msse3") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}${MARCH_FLAG} -mfpmath=sse,387 -msse3 ${GCC_EXTRA_OPTIMIZATIONS}") + set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}${MARCH_FLAG} -mfpmath=sse,387 -msse3 ${GCC_EXTRA_OPTIMIZATIONS}") + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}${MARCH_FLAG} -mfpmath=sse,387 -msse3 ${GCC_EXTRA_OPTIMIZATIONS}") + set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}${MARCH_FLAG} -mfpmath=sse,387 -msse3 ${GCC_EXTRA_OPTIMIZATIONS}") endif (${ARCH} STREQUAL "x86_64") elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") - if (NOT STANDALONE) - # this stops us requiring a really recent glibc at runtime - add_definitions(-fno-stack-protector) - endif (NOT STANDALONE) - - set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}${MARCH_FLAG} -fno-inline -msse2") - set(CMAKE_C_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}${MARCH_FLAG} -fno-inline -msse2") - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}${MARCH_FLAG} -msse2") - set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}${MARCH_FLAG} -msse2") - set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}${MARCH_FLAG} -msse2") - set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}${MARCH_FLAG} -msse2") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}${MARCH_FLAG} -fno-inline -msse3") + set(CMAKE_C_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}${MARCH_FLAG} -fno-inline -msse3") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}${MARCH_FLAG} -msse3") + set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}${MARCH_FLAG} -msse3") + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}${MARCH_FLAG} -msse3") + set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}${MARCH_FLAG} -msse3") elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel") - - if (NOT STANDALONE) - # this stops us requiring a really recent glibc at runtime - add_definitions(-fno-stack-protector) - endif (NOT STANDALONE) - if (NOT STANDALONE) - set(MARCH_FLAG " -axsse4.1 -msse2") + set(MARCH_FLAG " -axsse4.1 -msse3") endif (NOT STANDALONE) set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}${MARCH_FLAG} -fno-inline-functions") @@ -222,30 +254,28 @@ endif (LINUX) if (DARWIN) - add_definitions(-DLL_DARWIN=1 -D_XOPEN_SOURCE) - set(CMAKE_CXX_LINK_FLAGS "-Wl,-headerpad_max_install_names,-search_paths_first") + add_definitions(-DLL_DARWIN=1) + set(CMAKE_CXX_LINK_FLAGS "-Wl,-no_compact_unwind -Wl,-headerpad_max_install_names,-search_paths_first") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_CXX_LINK_FLAGS}") - - if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mlong-branch") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mlong-branch") - # NOTE: it's critical that the optimization flag is put in front. - # NOTE: it's critical to have both CXX_FLAGS and C_FLAGS covered. - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3 -msse3 -mtune=generic -mfpmath=sse ${GCC_EXTRA_OPTIMIZATIONS}") - set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O3 -msse3 -mtune=generic -mfpmath=sse ${GCC_EXTRA_OPTIMIZATIONS}") - set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -O3 -msse3 -mtune=generic -mfpmath=sse ${GCC_EXTRA_OPTIMIZATIONS}") - set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -O3 -msse3 -mtune=generic -mfpmath=sse ${GCC_EXTRA_OPTIMIZATIONS}") - elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") - # NOTE: it's critical that the optimization flag is put in front. - # NOTE: it's critical to have both CXX_FLAGS and C_FLAGS covered. - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3 -msse3") - set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O3 -msse3") - set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -O3 -msse3") - set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -O3 -msse3") - endif() + set(DARWIN_extra_cstar_flags "-g") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${DARWIN_extra_cstar_flags} -ftemplate-depth=256") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${DARWIN_extra_cstar_flags}") + # NOTE: it's critical that the optimization flag is put in front. + # NOTE: it's critical to have both CXX_FLAGS and C_FLAGS covered. + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O0 ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") + set(CMAKE_C_FLAGS_RELWITHDEBINFO "-O0 ${CMAKE_C_FLAGS_RELWITHDEBINFO}") + set(CMAKE_XCODE_ATTRIBUTE_CLANG_X86_VECTOR_INSTRUCTIONS SSE3) + set(CMAKE_XCODE_ATTRIBUTE_GCC_OPTIMIZATION_LEVEL -O3) + set(CMAKE_CXX_FLAGS_RELEASE "-O3 -msse3 ${CMAKE_CXX_FLAGS_RELEASE}") + set(CMAKE_C_FLAGS_RELEASE "-O3 -msse3 ${CMAKE_C_FLAGS_RELEASE}") + if (XCODE_VERSION GREATER 4.2) + set(ENABLE_SIGNING TRUE) + set(SIGNING_IDENTITY "Developer ID Application: Linden Research, Inc.") + endif (XCODE_VERSION GREATER 4.2) endif (DARWIN) + if (LINUX OR DARWIN) if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") add_definitions(-DLL_GNUC=1) @@ -253,13 +283,11 @@ if (LINUX OR DARWIN) set(UNIX_CXX_WARNINGS "${UNIX_WARNINGS} -Wno-reorder -Wno-non-virtual-dtor -Woverloaded-virtual") elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") add_definitions(-DLL_CLANG=1) - set(UNIX_WARNINGS "-Wall -Wno-sign-compare -Wno-trigraphs -Wno-tautological-compare -Wno-char-subscripts -Wno-gnu -Wno-logical-op-parentheses -Wno-non-virtual-dtor") - set(UNIX_WARNINGS "${UNIX_WARNINGS} -Woverloaded-virtual -Wno-parentheses-equality -Wno-reorder -Wno-unused-function -Wno-unused-value -Wno-unused-variable") + set(UNIX_WARNINGS "-Wall -Wno-sign-compare -Wno-trigraphs -Wno-tautological-compare -Wno-char-subscripts -Wno-gnu -Wno-logical-op-parentheses -Wno-logical-not-parentheses -Wno-non-virtual-dtor -Wno-deprecated") + set(UNIX_WARNINGS "${UNIX_WARNINGS} -Woverloaded-virtual -Wno-parentheses-equality -Wno-reorder -Wno-unused-function -Wno-unused-value -Wno-unused-variable -Wno-unused-private-field -Wno-parentheses") set(UNIX_CXX_WARNINGS "${UNIX_WARNINGS}") elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel") add_definitions(-DLL_ICC=1) - set(UNIX_WARNINGS "-wd327 -wd597 -wd858") - set(UNIX_CXX_WARNINGS "${UNIX_WARNINGS}") endif () if (NOT DISABLE_FATAL_WARNINGS) @@ -269,27 +297,35 @@ if (LINUX OR DARWIN) set(CMAKE_C_FLAGS "${UNIX_WARNINGS} ${CMAKE_C_FLAGS}") set(CMAKE_CXX_FLAGS "${UNIX_CXX_WARNINGS} ${CMAKE_CXX_FLAGS}") - if (WORD_SIZE EQUAL 32) + if (ADDRESS_SIZE EQUAL 32) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32") - elseif (WORD_SIZE EQUAL 64) + elseif (ADDRESS_SIZE EQUAL 64) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m64") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m64") - endif (WORD_SIZE EQUAL 32) + endif (ADDRESS_SIZE EQUAL 32) endif (LINUX OR DARWIN) if (STANDALONE) add_definitions(-DLL_STANDALONE=1) else (STANDALONE) + #Enforce compile-time correctness for fmt strings + add_definitions(-DFMT_STRING_ALIAS=1) + + if(USE_CRASHPAD) + add_definitions(-DUSE_CRASHPAD=1 -DCRASHPAD_URL="${CRASHPAD_URL}") + endif() + set(${ARCH}_linux_INCLUDES - ELFIO atk-1.0 + cairo glib-2.0 + gdk-pixbuf-2.0 gstreamer-0.10 gtk-2.0 - freetype2 pango-1.0 + pixman-1 ) endif (STANDALONE) diff --git a/indra/cmake/APR.cmake b/indra/cmake/APR.cmake index cdc9c32a83..447470a151 100644 --- a/indra/cmake/APR.cmake +++ b/indra/cmake/APR.cmake @@ -1,4 +1,3 @@ -include(BerkeleyDB) include(Linking) include(Prebuilt) @@ -13,36 +12,41 @@ if (STANDALONE) else (STANDALONE) use_prebuilt_binary(apr_suite) if (WINDOWS) + if (LLCOMMON_LINK_SHARED) + set(APR_selector "lib") + else (LLCOMMON_LINK_SHARED) + set(APR_selector "") + endif (LLCOMMON_LINK_SHARED) set(APR_LIBRARIES - debug ${ARCH_PREBUILT_DIRS_DEBUG}/libapr-1.lib - optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libapr-1.lib + debug ${ARCH_PREBUILT_DIRS_DEBUG}/${APR_selector}apr-1.lib + optimized ${ARCH_PREBUILT_DIRS_RELEASE}/${APR_selector}apr-1.lib ) set(APRICONV_LIBRARIES - debug ${ARCH_PREBUILT_DIRS_DEBUG}/libapriconv-1.lib - optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libapriconv-1.lib + debug ${ARCH_PREBUILT_DIRS_DEBUG}/${APR_selector}apriconv-1.lib + optimized ${ARCH_PREBUILT_DIRS_RELEASE}/${APR_selector}apriconv-1.lib ) set(APRUTIL_LIBRARIES - debug ${ARCH_PREBUILT_DIRS_DEBUG}/libaprutil-1.lib ${APRICONV_LIBRARIES} - optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libaprutil-1.lib ${APRICONV_LIBRARIES} + debug ${ARCH_PREBUILT_DIRS_DEBUG}/${APR_selector}aprutil-1.lib ${APRICONV_LIBRARIES} + optimized ${ARCH_PREBUILT_DIRS_RELEASE}/${APR_selector}aprutil-1.lib ${APRICONV_LIBRARIES} ) + if(NOT LLCOMMON_LINK_SHARED) + list(APPEND APR_LIBRARIES Rpcrt4) + endif(NOT LLCOMMON_LINK_SHARED) elseif (DARWIN) - set(APR_LIBRARIES - debug ${ARCH_PREBUILT_DIRS_DEBUG}/libapr-1.0.dylib - optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libapr-1.0.dylib - ) - set(APRUTIL_LIBRARIES - debug ${ARCH_PREBUILT_DIRS_DEBUG}/libaprutil-1.dylib - optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libaprutil-1.dylib - ) + if (LLCOMMON_LINK_SHARED) + set(APR_selector "0.dylib") + set(APRUTIL_selector "0.dylib") + else (LLCOMMON_LINK_SHARED) + set(APR_selector "a") + set(APRUTIL_selector "a") + endif (LLCOMMON_LINK_SHARED) + set(APR_LIBRARIES libapr-1.${APR_selector}) + set(APRUTIL_LIBRARIES libaprutil-1.${APRUTIL_selector}) set(APRICONV_LIBRARIES iconv) else (WINDOWS) set(APR_LIBRARIES apr-1) set(APRUTIL_LIBRARIES aprutil-1) set(APRICONV_LIBRARIES iconv) endif (WINDOWS) - set(APR_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/apr-1) - - if (LINUX) - list(APPEND APRUTIL_LIBRARIES ${DB_LIBRARIES}) - endif (LINUX) + set(APR_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/apr-1) endif (STANDALONE) diff --git a/indra/cmake/Audio.cmake b/indra/cmake/Audio.cmake index 3d78e6751a..ba9f712388 100644 --- a/indra/cmake/Audio.cmake +++ b/indra/cmake/Audio.cmake @@ -1,15 +1,15 @@ # -*- cmake -*- include(Prebuilt) -if (STANDALONE) +if (LINUX) include(FindPkgConfig) pkg_check_modules(OGG REQUIRED ogg) pkg_check_modules(VORBIS REQUIRED vorbis) pkg_check_modules(VORBISENC REQUIRED vorbisenc) pkg_check_modules(VORBISFILE REQUIRED vorbisfile) -else (STANDALONE) - use_prebuilt_binary(ogg-vorbis) - set(VORBIS_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include) +else (LINUX) + use_prebuilt_binary(ogg_vorbis) + set(VORBIS_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include) set(VORBISENC_INCLUDE_DIRS ${VORBIS_INCLUDE_DIRS}) set(VORBISFILE_INCLUDE_DIRS ${VORBIS_INCLUDE_DIRS}) @@ -32,7 +32,7 @@ else (STANDALONE) set(VORBISENC_LIBRARIES vorbisenc) set(VORBISFILE_LIBRARIES vorbisfile) endif (WINDOWS) -endif (STANDALONE) +endif (LINUX) link_directories( ${VORBIS_LIBRARY_DIRS} diff --git a/indra/cmake/BerkeleyDB.cmake b/indra/cmake/BerkeleyDB.cmake deleted file mode 100644 index 032dd510e0..0000000000 --- a/indra/cmake/BerkeleyDB.cmake +++ /dev/null @@ -1,17 +0,0 @@ -include(Prebuilt) - -set(DB_FIND_QUIETLY ON) -set(DB_FIND_REQUIRED ON) - -if (STANDALONE) - include(FindBerkeleyDB) -else (STANDALONE) - if (LINUX) - # Need to add dependency pthread explicitely to support ld.gold. - use_prebuilt_binary(db) - set(DB_LIBRARIES db-5.1 pthread) - else (LINUX) - set(DB_LIBRARIES db-4.2) - endif (LINUX) - set(DB_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include) -endif (STANDALONE) diff --git a/indra/cmake/Boost.cmake b/indra/cmake/Boost.cmake index 16d4d24619..844d5dc490 100644 --- a/indra/cmake/Boost.cmake +++ b/indra/cmake/Boost.cmake @@ -8,34 +8,77 @@ if (STANDALONE) include(FindBoost) set(Boost_USE_MULTITHREADED ON) - find_package(Boost 1.40.0 COMPONENTS date_time filesystem program_options regex system thread wave) + find_package(Boost 1.51.0 COMPONENTS date_time filesystem program_options regex system thread wave context) else (STANDALONE) use_prebuilt_binary(boost) - set(Boost_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include) + set(Boost_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include) + set(Boost_VERSION "1.60") if (WINDOWS) - set(BOOST_VERSION 1_45) - set(BOOST_OPTIM_SUFFIX mt) - set(BOOST_DEBUG_SUFFIX mt-gd) - + set(Boost_CONTEXT_LIBRARY + optimized libboost_context-mt + debug libboost_context-mt-gd) + set(Boost_FILESYSTEM_LIBRARY + optimized libboost_filesystem-mt + debug libboost_filesystem-mt-gd) set(Boost_PROGRAM_OPTIONS_LIBRARY - optimized libboost_program_options-vc${MSVC_SUFFIX}-${BOOST_OPTIM_SUFFIX}-${BOOST_VERSION} - debug libboost_program_options-vc${MSVC_SUFFIX}-${BOOST_DEBUG_SUFFIX}-${BOOST_VERSION}) + optimized libboost_program_options-mt + debug libboost_program_options-mt-gd) set(Boost_REGEX_LIBRARY - optimized libboost_regex-vc${MSVC_SUFFIX}-${BOOST_OPTIM_SUFFIX}-${BOOST_VERSION} - debug libboost_regex-vc${MSVC_SUFFIX}-${BOOST_DEBUG_SUFFIX}-${BOOST_VERSION}) - - elseif (DARWIN) - set(Boost_FILESYSTEM_LIBRARY boost_filesystem) - set(Boost_PROGRAM_OPTIONS_LIBRARY boost_program_options) - set(Boost_REGEX_LIBRARY boost_regex) - set(Boost_SYSTEM_LIBRARY boost_system) - set(Boost_DATE_TIME_LIBRARY boost_date_time) + optimized libboost_regex-mt + debug libboost_regex-mt-gd) + set(Boost_SIGNALS_LIBRARY + optimized libboost_signals-mt + debug libboost_signals-mt-gd) + set(Boost_SYSTEM_LIBRARY + optimized libboost_system-mt + debug libboost_system-mt-gd) + set(Boost_THREAD_LIBRARY + optimized libboost_thread-mt + debug libboost_thread-mt-gd) elseif (LINUX) - set(Boost_FILESYSTEM_LIBRARY boost_filesystem-mt) - set(Boost_PROGRAM_OPTIONS_LIBRARY boost_program_options-mt) - set(Boost_REGEX_LIBRARY boost_regex-mt) - set(Boost_SYSTEM_LIBRARY boost_system-mt) - set(Boost_DATE_TIME_LIBRARY boost_date_time-mt) + set(Boost_CONTEXT_LIBRARY + optimized boost_context-mt + debug boost_context-mt-d) + set(Boost_FILESYSTEM_LIBRARY + optimized boost_filesystem-mt + debug boost_filesystem-mt-d) + set(Boost_PROGRAM_OPTIONS_LIBRARY + optimized boost_program_options-mt + debug boost_program_options-mt-d) + set(Boost_REGEX_LIBRARY + optimized boost_regex-mt + debug boost_regex-mt-d) + set(Boost_SIGNALS_LIBRARY + optimized boost_signals-mt + debug boost_signals-mt-d) + set(Boost_SYSTEM_LIBRARY + optimized boost_system-mt + debug boost_system-mt-d) + set(Boost_THREAD_LIBRARY + optimized boost_thread-mt + debug boost_thread-mt-d) + elseif (DARWIN) + set(Boost_CONTEXT_LIBRARY + optimized boost_context-mt + debug boost_context-mt-d) + set(Boost_FILESYSTEM_LIBRARY + optimized boost_filesystem-mt + debug boost_filesystem-mt-d) + set(Boost_PROGRAM_OPTIONS_LIBRARY + optimized boost_program_options-mt + debug boost_program_options-mt-d) + set(Boost_REGEX_LIBRARY + optimized boost_regex-mt + debug boost_regex-mt-d) + set(Boost_SIGNALS_LIBRARY + optimized boost_signals-mt + debug boost_signals-mt-d) + set(Boost_SYSTEM_LIBRARY + optimized boost_system-mt + debug boost_system-mt-d) + set(Boost_THREAD_LIBRARY + optimized boost_thread-mt + debug boost_thread-mt-d) endif (WINDOWS) endif (STANDALONE) diff --git a/indra/cmake/BuildBranding.cmake b/indra/cmake/BuildBranding.cmake new file mode 100644 index 0000000000..4ab86234db --- /dev/null +++ b/indra/cmake/BuildBranding.cmake @@ -0,0 +1,38 @@ +# -*- cmake -*- +if (WINDOWS) + #message(WARNING, ${CMAKE_CURRENT_BINARY_DIR}/newview/viewerRes.rc.in) + configure_file( + ${CMAKE_SOURCE_DIR}/newview/res/viewerRes.rc.in + ${CMAKE_CURRENT_BINARY_DIR}/viewerRes.rc + ) +endif (WINDOWS) + +if (DARWIN) + configure_file( + ${CMAKE_SOURCE_DIR}/newview/English.lproj/InfoPlist.strings.in + ${CMAKE_CURRENT_BINARY_DIR}/English.lproj/InfoPlist.strings + ) +endif (DARWIN) + +if (LINUX) + configure_file( + ${CMAKE_SOURCE_DIR}/newview/linux_tools/wrapper.sh.in + ${CMAKE_CURRENT_BINARY_DIR}/linux_tools/wrapper.sh + @ONLY + ) + configure_file( + ${CMAKE_SOURCE_DIR}/newview/linux_tools/handle_secondlifeprotocol.sh.in + ${CMAKE_CURRENT_BINARY_DIR}/linux_tools/handle_secondlifeprotocol.sh + @ONLY + ) + configure_file( + ${CMAKE_SOURCE_DIR}/newview/linux_tools/install.sh.in + ${CMAKE_CURRENT_BINARY_DIR}/linux_tools/install.sh + @ONLY + ) + configure_file( + ${CMAKE_SOURCE_DIR}/newview/linux_tools/refresh_desktop_app_entry.sh.in + ${CMAKE_CURRENT_BINARY_DIR}/linux_tools/refresh_desktop_app_entry.sh + @ONLY + ) +endif (LINUX) diff --git a/indra/cmake/BuildPackagesInfo.cmake b/indra/cmake/BuildPackagesInfo.cmake new file mode 100644 index 0000000000..26088fcaf6 --- /dev/null +++ b/indra/cmake/BuildPackagesInfo.cmake @@ -0,0 +1,20 @@ +# -*- cmake -*- +# Construct the version and copyright information based on package data. +include(Python) +include(Variables) + +# packages-formatter.py runs autobuild install --versions, which needs to know +# the build_directory, which (on Windows) depends on AUTOBUILD_ADDRSIZE. +# Within an autobuild build, AUTOBUILD_ADDRSIZE is already set. But when +# building in an IDE, it probably isn't. Set it explicitly using +# run_build_test.py. +add_custom_command(OUTPUT packages-info.txt + COMMENT "Generating packages-info.txt for the about box" + MAIN_DEPENDENCY ${CMAKE_SOURCE_DIR}/../autobuild.xml + DEPENDS ${CMAKE_SOURCE_DIR}/../scripts/packages-formatter.py + ${CMAKE_SOURCE_DIR}/../autobuild.xml + COMMAND ${PYTHON_EXECUTABLE} + ${CMAKE_SOURCE_DIR}/cmake/run_build_test.py -DAUTOBUILD_ADDRSIZE=${ADDRESS_SIZE} + ${PYTHON_EXECUTABLE} + ${CMAKE_SOURCE_DIR}/../scripts/packages-formatter.py "${VIEWER_CHANNEL}" "${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION}" > packages-info.txt + ) diff --git a/indra/cmake/BuildVersion.cmake b/indra/cmake/BuildVersion.cmake index 041927f107..2f36e3ad1b 100644 --- a/indra/cmake/BuildVersion.cmake +++ b/indra/cmake/BuildVersion.cmake @@ -1,45 +1,55 @@ # -*- cmake -*- +# Construct the viewer version number based on the indra/VIEWER_VERSION file -# Read version components from the header file. -file(STRINGS ${LIBS_OPEN_DIR}/llcommon/llversionviewer.h.in lines - REGEX " LL_VERSION_") -foreach(line ${lines}) - string(REGEX REPLACE ".*LL_VERSION_([A-Z]+).*" "\\1" comp "${line}") - string(REGEX REPLACE ".* = ([0-9]+);.*" "\\1" value "${line}") - set(v${comp} "${value}") -endforeach(line) - -execute_process( - COMMAND git rev-list HEAD - OUTPUT_VARIABLE GIT_REV_LIST_STR - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - OUTPUT_STRIP_TRAILING_WHITESPACE -) - -if(GIT_REV_LIST_STR) - string(REPLACE "\n" ";" GIT_REV_LIST ${GIT_REV_LIST_STR}) -else() - string(REPLACE "\n" ";" GIT_REV_LIST "") -endif() - -if(GIT_REV_LIST) - list(LENGTH GIT_REV_LIST vBUILD) -else() - set(vBUILD 99) -endif() - -configure_file( - ${CMAKE_SOURCE_DIR}/llcommon/llversionviewer.h.in - ${CMAKE_SOURCE_DIR}/llcommon/llversionviewer.h -) - -# Compose the version. -set(viewer_VERSION "${vMAJOR}.${vMINOR}.${vPATCH}.${vBUILD}") -if (viewer_VERSION MATCHES "^[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+$") - message(STATUS "Version is ${viewer_VERSION}") -else (viewer_VERSION MATCHES "^[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+$") - message(FATAL_ERROR "Could not determine version (${viewer_VERSION})") -endif (viewer_VERSION MATCHES "^[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+$") - -# Report version to caller. -#set(viewer_VERSION "${viewer_VERSION}" PARENT_SCOPE) +if (NOT DEFINED VIEWER_SHORT_VERSION) # will be true in indra/, false in indra/newview/ + set(VIEWER_VERSION_BASE_FILE "${CMAKE_CURRENT_SOURCE_DIR}/newview/VIEWER_VERSION.txt") + + if ( EXISTS ${VIEWER_VERSION_BASE_FILE} ) + file(STRINGS ${VIEWER_VERSION_BASE_FILE} VIEWER_SHORT_VERSION REGEX "^[0-9]+\\.[0-9]+\\.[0-9]+") + string(REGEX REPLACE "^([0-9]+)\\.[0-9]+\\.[0-9]+" "\\1" VIEWER_VERSION_MAJOR ${VIEWER_SHORT_VERSION}) + string(REGEX REPLACE "^[0-9]+\\.([0-9]+)\\.[0-9]+" "\\1" VIEWER_VERSION_MINOR ${VIEWER_SHORT_VERSION}) + string(REGEX REPLACE "^[0-9]+\\.[0-9]+\\.([0-9]+)" "\\1" VIEWER_VERSION_PATCH ${VIEWER_SHORT_VERSION}) + + if (DEFINED ENV{revision}) + set(VIEWER_VERSION_REVISION $ENV{revision}) + message("Revision (from environment): ${VIEWER_VERSION_REVISION}") + + else (DEFINED ENV{revision}) + execute_process( + COMMAND git rev-list HEAD + OUTPUT_VARIABLE GIT_REV_LIST_STR + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + + if(GIT_REV_LIST_STR) + string(REPLACE "\n" ";" GIT_REV_LIST ${GIT_REV_LIST_STR}) + else() + string(REPLACE "\n" ";" GIT_REV_LIST "") + endif() + + if(GIT_REV_LIST) + list(LENGTH GIT_REV_LIST VIEWER_VERSION_REVISION) + else(GIT_REV_LIST) + set(VIEWER_VERSION_REVISION 99) + endif(GIT_REV_LIST) + endif (DEFINED ENV{revision}) + message("Building '${VIEWER_CHANNEL}' Version ${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION}") + else ( EXISTS ${VIEWER_VERSION_BASE_FILE} ) + message(SEND_ERROR "Cannot get viewer version from '${VIEWER_VERSION_BASE_FILE}'") + endif ( EXISTS ${VIEWER_VERSION_BASE_FILE} ) + + if ("${VIEWER_VERSION_REVISION}" STREQUAL "") + message("Ultimate fallback, revision was blank or not set: will use 0") + set(VIEWER_VERSION_REVISION 0) + endif ("${VIEWER_VERSION_REVISION}" STREQUAL "") + + set(VIEWER_CHANNEL_VERSION_DEFINES + "LL_VIEWER_CHANNEL=\"${VIEWER_CHANNEL}\"" + "LL_VIEWER_CHANNEL_GRK=L\"${VIEWER_CHANNEL_GRK}\"" + "LL_VIEWER_VERSION_MAJOR=${VIEWER_VERSION_MAJOR}" + "LL_VIEWER_VERSION_MINOR=${VIEWER_VERSION_MINOR}" + "LL_VIEWER_VERSION_PATCH=${VIEWER_VERSION_PATCH}" + "LL_VIEWER_VERSION_BUILD=${VIEWER_VERSION_REVISION}" + ) +endif (NOT DEFINED VIEWER_SHORT_VERSION) diff --git a/indra/cmake/CARes.cmake b/indra/cmake/CARes.cmake index d18e1ef1e6..02fad1f550 100644 --- a/indra/cmake/CARes.cmake +++ b/indra/cmake/CARes.cmake @@ -13,12 +13,12 @@ else (STANDALONE) add_definitions("-DCARES_STATICLIB") set(CARES_LIBRARIES areslib) elseif (DARWIN) - set(CARES_LIBRARIES - optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libcares.a - debug ${ARCH_PREBUILT_DIRS_DEBUG}/libcares.a + set(CARES_LIBRARIES + debug libcares.a + optimized libcares.a ) else (WINDOWS) set(CARES_LIBRARIES cares) endif (WINDOWS) - set(CARES_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/ares) + set(CARES_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include/ares) endif (STANDALONE) diff --git a/indra/cmake/CEFPlugin.cmake b/indra/cmake/CEFPlugin.cmake new file mode 100644 index 0000000000..7f90e6afa6 --- /dev/null +++ b/indra/cmake/CEFPlugin.cmake @@ -0,0 +1,45 @@ +# -*- cmake -*- +include(Linking) +include(Prebuilt) + +if (USESYSTEMLIBS) + set(CEFPLUGIN OFF CACHE BOOL + "CEFPLUGIN support for the llplugin/llmedia test apps.") +else (USESYSTEMLIBS) + use_prebuilt_binary(dullahan) + set(CEFPLUGIN ON CACHE BOOL + "CEFPLUGIN support for the llplugin/llmedia test apps.") + set(CEF_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/cef) +endif (USESYSTEMLIBS) + +if (WINDOWS) + set(CEF_PLUGIN_LIBRARIES + libcef.lib + libcef_dll_wrapper.lib + dullahan.lib + ) +elseif (DARWIN) + FIND_LIBRARY(APPKIT_LIBRARY AppKit) + if (NOT APPKIT_LIBRARY) + message(FATAL_ERROR "AppKit not found") + endif() + + FIND_LIBRARY(CEF_LIBRARY "Chromium Embedded Framework" ${ARCH_PREBUILT_DIRS_RELEASE}) + if (NOT CEF_LIBRARY) + message(FATAL_ERROR "CEF not found") + endif() + + set(CEF_PLUGIN_LIBRARIES + ${ARCH_PREBUILT_DIRS_RELEASE}/libcef_dll_wrapper.a + ${ARCH_PREBUILT_DIRS_RELEASE}/libdullahan.a + ${APPKIT_LIBRARY} + ${CEF_LIBRARY} + ) + +elseif (LINUX) + set(CEF_PLUGIN_LIBRARIES + dullahan + cef_dll_wrapper.a + cef + ) +endif (WINDOWS) diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt index 9eacfcada7..cfd982f96a 100644 --- a/indra/cmake/CMakeLists.txt +++ b/indra/cmake/CMakeLists.txt @@ -12,40 +12,37 @@ set(cmake_SOURCE_FILES APR.cmake Audio.cmake BasicPluginBase.cmake - BerkeleyDB.cmake Boost.cmake + BuildBranding.cmake BuildVersion.cmake CARes.cmake + CEFPlugin.cmake CMakeCopyIfDifferent.cmake - CURL.cmake Colladadom.cmake ConfigurePkgConfig.cmake - CopyBackToSource.cmake - CopyWinLibs.cmake + CURL.cmake + Copy3rdPartyLibs.cmake + CrashPad.cmake Cwdebug.cmake DBusGlib.cmake - DirectX.cmake - DownloadPrebuilt.cmake.in - ELFIO.cmake + DeploySharedLibs.cmake EXPAT.cmake ExamplePlugin.cmake - FMOD.cmake - FMODEX.cmake FindAPR.cmake - FindBerkeleyDB.cmake + FindAutobuild.cmake FindCARes.cmake FindColladadom.cmake - FindELFIO.cmake FindGLOD.cmake FindGooglePerfTools.cmake FindHunSpell.cmake - FindJsonCpp.cmake - FindLLQtWebkit.cmake FindNDOF.cmake FindOpenJPEG.cmake FindTut.cmake + FindURIPARSER.cmake FindXmlRpcEpi.cmake + FMODSTUDIO.cmake FreeType.cmake + GeneratePrecompiledHeader.cmake GLOD.cmake GStreamer010Plugin.cmake Glui.cmake @@ -53,13 +50,11 @@ set(cmake_SOURCE_FILES GooglePerfTools.cmake Hunspell.cmake JPEG.cmake - JsonCpp.cmake LLAddBuildTest.cmake LLAppearance.cmake LLAudio.cmake LLCharacter.cmake LLCommon.cmake - LLCrashLogger.cmake LLImage.cmake LLImageJ2COJ.cmake LLInventory.cmake @@ -69,8 +64,8 @@ set(cmake_SOURCE_FILES LLPlugin.cmake LLPrimitive.cmake LLPhysicsExtensions.cmake - LLQtWebkit.cmake LLRender.cmake + LLSharedLibs.cmake LLUI.cmake LLVFS.cmake LLWindow.cmake @@ -79,6 +74,7 @@ set(cmake_SOURCE_FILES Linking.cmake MediaPluginBase.cmake NDOF.cmake + NVAPI.cmake OPENAL.cmake OpenGL.cmake OpenJPEG.cmake @@ -88,17 +84,16 @@ set(cmake_SOURCE_FILES Prebuilt.cmake PulseAudio.cmake Python.cmake - Qt4.cmake - QuickTimePlugin.cmake - RunBuildTest.cmake StateMachine.cmake TemplateCheck.cmake Tut.cmake UI.cmake UnixInstall.cmake + URIPARSER.cmake Variables.cmake ViewerMiscLibs.cmake - WebKitLibPlugin.cmake + WinManifest.cmake + LibVLCPlugin.cmake XmlRpcEpi.cmake ZLIB.cmake ) @@ -107,7 +102,6 @@ source_group("Shared Rules" FILES ${cmake_SOURCE_FILES}) set(master_SOURCE_FILES ../CMakeLists.txt - ../develop.py ) source_group("Master Rules" FILES ${master_SOURCE_FILES}) diff --git a/indra/cmake/CURL.cmake b/indra/cmake/CURL.cmake index 10ef1b0b65..aed230279b 100644 --- a/indra/cmake/CURL.cmake +++ b/indra/cmake/CURL.cmake @@ -10,13 +10,11 @@ else (STANDALONE) use_prebuilt_binary(curl) if (WINDOWS) set(CURL_LIBRARIES - debug libcurld - optimized libcurl) + debug libcurl_a_debug + optimized libcurl_a) else (WINDOWS) - set(CURL_LIBRARIES curl) - if(LINUX AND WORD_SIZE EQUAL 64) - list(APPEND CURL_LIBRARIES idn) - endif(LINUX AND WORD_SIZE EQUAL 64) + use_prebuilt_binary(libidn) + set(CURL_LIBRARIES curl idn) endif (WINDOWS) - set(CURL_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include) + set(CURL_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include) endif (STANDALONE) diff --git a/indra/cmake/Colladadom.cmake b/indra/cmake/Colladadom.cmake index 1e4a9ed56b..e4eb71af01 100644 --- a/indra/cmake/Colladadom.cmake +++ b/indra/cmake/Colladadom.cmake @@ -1,6 +1,7 @@ # -*- cmake -*- include(Prebuilt) +include(Boost) set(COLLADADOM_FIND_QUIETLY OFF) set(COLLADADOM_FIND_REQUIRED ON) @@ -9,38 +10,22 @@ if (STANDALONE) include (FindColladadom) else (STANDALONE) use_prebuilt_binary(colladadom) - - if (NOT WINDOWS) - use_prebuilt_binary(pcre) - endif (NOT WINDOWS) - - if (NOT DARWIN AND NOT WINDOWS) - use_prebuilt_binary(libxml) - endif (NOT DARWIN AND NOT WINDOWS) - set(COLLADADOM_INCLUDE_DIRS - ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/collada - ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/collada/1.4 - ) + ${LIBS_PREBUILT_DIR}/include/collada + ${LIBS_PREBUILT_DIR}/include/collada/1.4 + ) if (WINDOWS) - add_definitions(-DDOM_DYNAMIC) - set(COLLADADOM_LIBRARIES - debug libcollada14dom22-d - optimized libcollada14dom22 - debug libboost_filesystem-vc100-mt-gd-1_45.lib - optimized libboost_filesystem-vc100-mt-1_45.lib - debug libboost_system-vc100-mt-gd-1_45.lib - optimized libboost_system-vc100-mt-1_45.lib - ) - else (WINDOWS) - set(COLLADADOM_LIBRARIES - collada14dom - minizip - xml2 - pcrecpp - pcre - ) + set(COLLADADOM_LIBRARIES + debug libcollada14dom23-sd + optimized libcollada14dom23-s + ) + else(WINDOWS) + set(COLLADADOM_LIBRARIES + debug collada14dom-d + optimized collada14dom + minizip + ) endif (WINDOWS) endif (STANDALONE) diff --git a/indra/cmake/ConfigurePkgConfig.cmake b/indra/cmake/ConfigurePkgConfig.cmake index 82ee3e7a5b..a2d5b31e25 100644 --- a/indra/cmake/ConfigurePkgConfig.cmake +++ b/indra/cmake/ConfigurePkgConfig.cmake @@ -6,17 +6,17 @@ SET(DEBUG_PKG_CONFIG "YES") IF("$ENV{PKG_CONFIG_LIBDIR}" STREQUAL "") # Guess at architecture-specific system library paths. - if (WORD_SIZE EQUAL 32) + if (ADDRESS_SIZE EQUAL 32) SET(PKG_CONFIG_NO_MULTI_GUESS /usr/lib32 /usr/lib) SET(PKG_CONFIG_NO_MULTI_LOCAL_GUESS /usr/local/lib32 /usr/local/lib) SET(PKG_CONFIG_MULTI_GUESS /usr/lib/i386-linux-gnu) SET(PKG_CONFIG_MULTI_LOCAL_GUESS /usr/local/lib/i386-linux-gnu) - else (WORD_SIZE EQUAL 32) + else (ADDRESS_SIZE EQUAL 32) SET(PKG_CONFIG_NO_MULTI_GUESS /usr/lib64 /usr/lib) SET(PKG_CONFIG_NO_MULTI_LOCAL_GUESS /usr/local/lib64 /usr/local/lib) - SET(PKG_CONFIG_MULTI_GUESS /usr/local/lib/x86_64-linux-gnu) + SET(PKG_CONFIG_MULTI_GUESS /usr/lib/x86_64-linux-gnu) SET(PKG_CONFIG_MULTI_LOCAL_GUESS /usr/local/lib/x86_64-linux-gnu) - endif (WORD_SIZE EQUAL 32) + endif (ADDRESS_SIZE EQUAL 32) # Use DPKG architecture, if available. IF (${DPKG_ARCH}) diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake new file mode 100644 index 0000000000..63ecf0cb1c --- /dev/null +++ b/indra/cmake/Copy3rdPartyLibs.cmake @@ -0,0 +1,255 @@ +# -*- cmake -*- + +# The copy_win_libs folder contains file lists and a script used to +# copy dlls, exes and such needed to run the SecondLife from within +# VisualStudio. + +include(CMakeCopyIfDifferent) +include(Linking) +include(Variables) +include(LLCommon) + +################################################################### +# set up platform specific lists of files that need to be copied +################################################################### +if(WINDOWS) + set(SHARED_LIB_STAGING_DIR_DEBUG "${SHARED_LIB_STAGING_DIR}/Debug") + set(SHARED_LIB_STAGING_DIR_RELWITHDEBINFO "${SHARED_LIB_STAGING_DIR}/RelWithDebInfo") + set(SHARED_LIB_STAGING_DIR_RELEASE "${SHARED_LIB_STAGING_DIR}/Release") + + #******************************* + # VIVOX - *NOTE: no debug version + set(vivox_src_dir "${ARCH_PREBUILT_DIRS_RELEASE}") + set(vivox_files + SLVoice.exe + vivoxplatform.dll + ) + if (ADDRESS_SIZE EQUAL 64) + list(APPEND vivox_files + vivoxsdk_x64.dll + ortp_x64.dll + ) + else (ADDRESS_SIZE EQUAL 64) + list(APPEND vivox_files + vivoxsdk.dll + ortp.dll + ) + endif (ADDRESS_SIZE EQUAL 64) + + #******************************* + # Misc shared libs + + set(debug_src_dir "${ARCH_PREBUILT_DIRS_DEBUG}") + set(debug_files + libapr-1.dll + libaprutil-1.dll + libapriconv-1.dll + glod.dll + libhunspell.dll + ) + + set(release_src_dir "${ARCH_PREBUILT_DIRS_RELEASE}") + set(release_files + libapr-1.dll + libaprutil-1.dll + libapriconv-1.dll + glod.dll + libhunspell.dll + ) + + if(ADDRESS_SIZE EQUAL 64) + list(APPEND debug_files + libcrypto-1_1-x64.dll + libssl-1_1-x64.dll + ) + list(APPEND release_files + libcrypto-1_1-x64.dll + libssl-1_1-x64.dll + ) + else(ADDRESS_SIZE EQUAL 64) + list(APPEND debug_files + libcrypto-1_1.dll + libssl-1_1.dll + ) + list(APPEND release_files + libcrypto-1_1.dll + libssl-1_1.dll + ) + endif(ADDRESS_SIZE EQUAL 64) + + if(NOT DISABLE_TCMALLOC) + list(APPEND debug_files libtcmalloc_minimal-debug.dll) + list(APPEND release_files libtcmalloc_minimal.dll) + endif(NOT DISABLE_TCMALLOC) + + if(OPENAL) + list(APPEND debug_files alut.dll OpenAL32.dll) + list(APPEND release_files alut.dll OpenAL32.dll) + endif(OPENAL) + + if (USE_FMODSTUDIO) + list(APPEND debug_files fmodL.dll) + list(APPEND release_files fmod.dll) + endif (USE_FMODSTUDIO) + +elseif(DARWIN) + set(SHARED_LIB_STAGING_DIR_DEBUG "${SHARED_LIB_STAGING_DIR}/Debug/Resources") + set(SHARED_LIB_STAGING_DIR_RELWITHDEBINFO "${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/Resources") + set(SHARED_LIB_STAGING_DIR_RELEASE "${SHARED_LIB_STAGING_DIR}/Release/Resources") + + set(vivox_src_dir "${ARCH_PREBUILT_DIRS_RELEASE}") + set(vivox_files + SLVoice + ca-bundle.crt + libsndfile.dylib + libvivoxoal.dylib + libortp.dylib + libvivoxplatform.dylib + libvivoxsdk.dylib + ) + set(debug_src_dir "${ARCH_PREBUILT_DIRS_DEBUG}") + set(debug_files + ) + set(release_src_dir "${ARCH_PREBUILT_DIRS_RELEASE}") + set(release_files + libapr-1.0.dylib + libapr-1.dylib + libaprutil-1.0.dylib + libaprutil-1.dylib + libexception_handler.dylib + libexpat.1.5.2.dylib + libexpat.dylib + libGLOD.dylib + libhunspell-1.3.0.dylib + libndofdev.dylib + ) + + if (USE_FMODSTUDIO) + list(APPEND debug_files libfmodL.dylib) + list(APPEND release_files libfmod.dylib) + endif (USE_FMODSTUDIO) + +elseif(LINUX) + # linux is weird, multiple side by side configurations aren't supported + # and we don't seem to have any debug shared libs built yet anyways... + set(SHARED_LIB_STAGING_DIR_DEBUG "${SHARED_LIB_STAGING_DIR}") + set(SHARED_LIB_STAGING_DIR_RELWITHDEBINFO "${SHARED_LIB_STAGING_DIR}") + set(SHARED_LIB_STAGING_DIR_RELEASE "${SHARED_LIB_STAGING_DIR}") + + set(vivox_src_dir "${ARCH_PREBUILT_DIRS_RELEASE}") + set(vivox_files + libsndfile.so.1 + libortp.so + libvivoxoal.so.1 + libvivoxplatform.so + libvivoxsdk.so + SLVoice + ) + # *TODO - update this to use LIBS_PREBUILT_DIR and LL_ARCH_DIR variables + # or ARCH_PREBUILT_DIRS + set(debug_src_dir "${ARCH_PREBUILT_DIRS_DEBUG}") + set(debug_files + ) + # *TODO - update this to use LIBS_PREBUILT_DIR and LL_ARCH_DIR variables + # or ARCH_PREBUILT_DIRS + set(release_src_dir "${ARCH_PREBUILT_DIRS_RELEASE}") + # *FIX - figure out what to do with duplicate libalut.so here -brad + set(release_files + libapr-1.so.0 + libaprutil-1.so.0 + libexpat.so + libexpat.so.1 + libGLOD.so + libopenal.so + ) + + if (USE_TCMALLOC) + list(APPEND release_files "libtcmalloc_minimal.so") + endif (USE_TCMALLOC) + + if (USE_FMODSTUDIO) + list(APPEND debug_files "libfmodL.so") + list(APPEND release_files "libfmod.so") + endif (USE_FMODSTUDIO) + +else(WINDOWS) + message(STATUS "WARNING: unrecognized platform for staging 3rd party libs, skipping...") + set(vivox_src_dir "${CMAKE_SOURCE_DIR}/newview/vivox-runtime/i686-linux") + set(vivox_files "") + # *TODO - update this to use LIBS_PREBUILT_DIR and LL_ARCH_DIR variables + # or ARCH_PREBUILT_DIRS + set(debug_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-linux/lib/debug") + set(debug_files "") + # *TODO - update this to use LIBS_PREBUILT_DIR and LL_ARCH_DIR variables + # or ARCH_PREBUILT_DIRS + set(release_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-linux/lib/release") + set(release_files "") + + set(debug_llkdu_src "") + set(debug_llkdu_dst "") + set(release_llkdu_src "") + set(release_llkdu_dst "") + set(relwithdebinfo_llkdu_dst "") +endif(WINDOWS) + + +################################################################ +# Done building the file lists, now set up the copy commands. +################################################################ + +copy_if_different( + ${vivox_src_dir} + "${SHARED_LIB_STAGING_DIR_DEBUG}" + out_targets + ${vivox_files} + ) +set(third_party_targets ${third_party_targets} ${out_targets}) + +copy_if_different( + ${vivox_src_dir} + "${SHARED_LIB_STAGING_DIR_RELEASE}" + out_targets + ${vivox_files} + ) +set(third_party_targets ${third_party_targets} ${out_targets}) + +copy_if_different( + ${vivox_src_dir} + "${SHARED_LIB_STAGING_DIR_RELWITHDEBINFO}" + out_targets + ${vivox_files} + ) +set(third_party_targets ${third_party_targets} ${out_targets}) + + + +#copy_if_different( +# ${debug_src_dir} +# "${SHARED_LIB_STAGING_DIR_DEBUG}" +# out_targets +# ${debug_files} +# ) +#set(third_party_targets ${third_party_targets} ${out_targets}) + +copy_if_different( + ${release_src_dir} + "${SHARED_LIB_STAGING_DIR_RELEASE}" + out_targets + ${release_files} + ) +set(third_party_targets ${third_party_targets} ${out_targets}) + +copy_if_different( + ${release_src_dir} + "${SHARED_LIB_STAGING_DIR_RELWITHDEBINFO}" + out_targets + ${release_files} + ) +set(third_party_targets ${third_party_targets} ${out_targets}) + +if(NOT USESYSTEMLIBS) + add_custom_target( + stage_third_party_libs ALL + DEPENDS ${third_party_targets} + ) +endif(NOT USESYSTEMLIBS) diff --git a/indra/cmake/CopyBackToSource.cmake b/indra/cmake/CopyBackToSource.cmake deleted file mode 100644 index d217df9aec..0000000000 --- a/indra/cmake/CopyBackToSource.cmake +++ /dev/null @@ -1,16 +0,0 @@ -# -*- cmake -*- -# Copies a binary back to the source directory - -MACRO(COPY_BACK_TO_SOURCE target) - GET_TARGET_PROPERTY(FROM ${target} LOCATION) - SET(TO ${CMAKE_CURRENT_SOURCE_DIR}) - #MESSAGE("TARGET ${target} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${FROM} ${TO}") - ADD_CUSTOM_COMMAND( - TARGET ${target} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy ${FROM} ${TO} - DEPENDS ${FROM} - COMMENT "Copying ${target} to ${CMAKE_CURRENT_BINARY_DIR}" - ) -ENDMACRO(COPY_BACK_TO_SOURCE) - - diff --git a/indra/cmake/CopyWinLibs.cmake b/indra/cmake/CopyWinLibs.cmake deleted file mode 100644 index 9d52499a1f..0000000000 --- a/indra/cmake/CopyWinLibs.cmake +++ /dev/null @@ -1,395 +0,0 @@ -# -*- cmake -*- - -# The copy_win_libs folder contains file lists and a script used to -# copy dlls, exes and such needed to run the SecondLife from within -# VisualStudio. - -include(CMakeCopyIfDifferent) - -set(vivox_src_dir "${CMAKE_SOURCE_DIR}/newview/vivox-runtime/i686-win32") -set(vivox_files - SLVoice.exe - alut.dll - vivoxsdk.dll - ortp.dll - wrap_oal.dll - ) -copy_if_different( - ${vivox_src_dir} - "${CMAKE_CURRENT_BINARY_DIR}/Debug" - out_targets - ${vivox_files} - ) -set(all_targets ${all_targets} ${out_targets}) - - -set(debug_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/debug") -set(debug_files - libhunspell.dll - libapr-1.dll - libaprutil-1.dll - libapriconv-1.dll - libeay32.dll - ssleay32.dll - libcollada14dom22-d.dll - glod.dll - ) - -copy_if_different( - ${debug_src_dir} - "${CMAKE_CURRENT_BINARY_DIR}/Debug" - out_targets - ${debug_files} - ) -set(all_targets ${all_targets} ${out_targets}) - -# Debug config runtime files required for the plugin test mule -set(plugintest_debug_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/debug") -set(plugintest_debug_files - libeay32.dll - qtcored4.dll - qtguid4.dll - qtnetworkd4.dll - qtopengld4.dll - qtwebkitd4.dll - ssleay32.dll - ) -copy_if_different( - ${plugintest_debug_src_dir} - "${CMAKE_CURRENT_BINARY_DIR}/../test_apps/llplugintest/Debug" - out_targets - ${plugintest_debug_files} - ) -set(all_targets ${all_targets} ${out_targets}) - -# Debug config runtime files required for the plugin test mule (Qt image format plugins) -set(plugintest_debug_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/debug/imageformats") -set(plugintest_debug_files - qgifd4.dll - qicod4.dll - qjpegd4.dll - qmngd4.dll - qsvgd4.dll - qtiffd4.dll - ) -copy_if_different( - ${plugintest_debug_src_dir} - "${CMAKE_CURRENT_BINARY_DIR}/../test_apps/llplugintest/Debug/imageformats" - out_targets - ${plugintest_debug_files} - ) -set(all_targets ${all_targets} ${out_targets}) - -copy_if_different( - ${plugintest_debug_src_dir} - "${CMAKE_CURRENT_BINARY_DIR}/llplugin/imageformats" - out_targets - ${plugintest_debug_files} - ) -set(all_targets ${all_targets} ${out_targets}) - -# Release & ReleaseDebInfo config runtime files required for the plugin test mule -set(plugintest_release_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/release") -set(plugintest_release_files - libeay32.dll - qtcore4.dll - qtgui4.dll - qtnetwork4.dll - qtopengl4.dll - qtwebkit4.dll - ssleay32.dll - ) -copy_if_different( - ${plugintest_release_src_dir} - "${CMAKE_CURRENT_BINARY_DIR}/../test_apps/llplugintest/Release" - out_targets - ${plugintest_release_files} - ) -set(all_targets ${all_targets} ${out_targets}) - -copy_if_different( - ${plugintest_release_src_dir} - "${CMAKE_CURRENT_BINARY_DIR}/../test_apps/llplugintest/RelWithDebInfo" - out_targets - ${plugintest_release_files} - ) -set(all_targets ${all_targets} ${out_targets}) - -# Release & ReleaseDebInfo config runtime files required for the plugin test mule (Qt image format plugins) -set(plugintest_release_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/release/imageformats") -set(plugintest_release_files - qgif4.dll - qico4.dll - qjpeg4.dll - qmng4.dll - qsvg4.dll - qtiff4.dll - ) -copy_if_different( - ${plugintest_release_src_dir} - "${CMAKE_CURRENT_BINARY_DIR}/../test_apps/llplugintest/Release/imageformats" - out_targets - ${plugintest_release_files} - ) -set(all_targets ${all_targets} ${out_targets}) - -copy_if_different( - ${plugintest_release_src_dir} - "${CMAKE_CURRENT_BINARY_DIR}/../test_apps/llplugintest/RelWithDebInfo/imageformats" - out_targets - ${plugintest_release_files} - ) -set(all_targets ${all_targets} ${out_targets}) - -copy_if_different( - ${plugintest_release_src_dir} - "${CMAKE_CURRENT_BINARY_DIR}/Release/llplugin/imageformats" - out_targets - ${plugintest_release_files} - ) -set(all_targets ${all_targets} ${out_targets}) - -copy_if_different( - ${plugintest_release_src_dir} - "${CMAKE_CURRENT_BINARY_DIR}/RelWithDebInfo/llplugin/imageformats" - out_targets - ${plugintest_release_files} - ) -set(all_targets ${all_targets} ${out_targets}) - -# Debug config runtime files required for the plugins -set(plugins_debug_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/debug") -set(plugins_debug_files - libeay32.dll - qtcored4.dll - qtguid4.dll - qtnetworkd4.dll - qtopengld4.dll - qtwebkitd4.dll - ssleay32.dll - ) -copy_if_different( - ${plugins_debug_src_dir} - "${CMAKE_CURRENT_BINARY_DIR}/Debug/llplugin" - out_targets - ${plugins_debug_files} - ) -set(all_targets ${all_targets} ${out_targets}) - -# Release & ReleaseDebInfo config runtime files required for the plugins -set(plugins_release_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/release") -set(plugins_release_files - libeay32.dll - qtcore4.dll - qtgui4.dll - qtnetwork4.dll - qtopengl4.dll - qtwebkit4.dll - ssleay32.dll - ) -copy_if_different( - ${plugins_release_src_dir} - "${CMAKE_CURRENT_BINARY_DIR}/Release/llplugin" - out_targets - ${plugins_release_files} - ) -set(all_targets ${all_targets} ${out_targets}) - -copy_if_different( - ${plugins_release_src_dir} - "${CMAKE_CURRENT_BINARY_DIR}/RelWithDebInfo/llplugin" - out_targets - ${plugins_release_files} - ) -set(all_targets ${all_targets} ${out_targets}) - -set(release_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/release") -set(release_files - libtcmalloc_minimal.dll - libhunspell.dll - libapr-1.dll - libaprutil-1.dll - libapriconv-1.dll - libeay32.dll - ssleay32.dll - libcollada14dom22.dll - glod.dll - ) - -if(FMODEX) - find_path(FMODEX_BINARY_DIR fmodex.dll - "${release_src_dir}" - "${FMODEX_SDK_DIR}/api" - "${FMODEX_SDK_DIR}" - NO_DEFAULT_PATH - ) - - if(FMODEX_BINARY_DIR) - copy_if_different("${FMODEX_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/Release" out_targets fmodex.dll) - set(all_targets ${all_targets} ${out_targets}) - copy_if_different("${FMODEX_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/RelWithDebInfo" out_targets fmodex.dll) - set(all_targets ${all_targets} ${out_targets}) - copy_if_different("${FMODEX_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/Debug" out_targets fmodex.dll) - set(all_targets ${all_targets} ${out_targets}) - endif(FMODEX_BINARY_DIR) -endif(FMODEX) - -if(FMOD) - find_path(FMOD_BINARY_DIR fmod.dll - ${release_src_dir} - ${FMOD_SDK_DIR}/api - ${FMOD_SDK_DIR} - ) - -if(FMOD_BINARY_DIR) - copy_if_different("${FMOD_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/Release" out_targets fmod.dll) - set(all_targets ${all_targets} ${out_targets}) - copy_if_different("${FMOD_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/RelWithDebInfo" out_targets fmod.dll) - set(all_targets ${all_targets} ${out_targets}) - copy_if_different("${FMOD_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/Debug" out_targets fmod.dll) - set(all_targets ${all_targets} ${out_targets}) - else(FMOD_BINARY_DIR) - list(APPEND release_files fmod.dll) #Required for compile. This will cause an error in copying binaries. - endif(FMOD_BINARY_DIR) -endif(FMOD) - -copy_if_different( - ${release_src_dir} - "${CMAKE_CURRENT_BINARY_DIR}/Release" - out_targets - ${release_files} - ) -set(all_targets ${all_targets} ${out_targets}) - -copy_if_different( - ${vivox_src_dir} - "${CMAKE_CURRENT_BINARY_DIR}/Release" - out_targets - ${vivox_files} - ) -set(all_targets ${all_targets} ${out_targets}) - -copy_if_different( - ${release_src_dir} - "${CMAKE_CURRENT_BINARY_DIR}/RelWithDebInfo" - out_targets - ${release_files} - ) -set(all_targets ${all_targets} ${out_targets}) - -copy_if_different( - ${vivox_src_dir} - "${CMAKE_CURRENT_BINARY_DIR}/RelWithDebInfo" - out_targets - ${vivox_files} - ) -set(all_targets ${all_targets} ${out_targets}) - -# Copy MS C runtime dlls, required for packaging. -# *TODO - Adapt this to support VC9 -if (MSVC80) - FIND_PATH(debug_msvc8_redist_path msvcr80d.dll - PATHS - [HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\8.0\\Setup\\VC;ProductDir]/redist/Debug_NonRedist/x86/Microsoft.VC80.DebugCRT - NO_DEFAULT_PATH - NO_DEFAULT_PATH - ) - - if(EXISTS ${debug_msvc8_redist_path}) - set(debug_msvc8_files - msvcr80d.dll - msvcp80d.dll - Microsoft.VC80.DebugCRT.manifest - ) - - copy_if_different( - ${debug_msvc8_redist_path} - "${CMAKE_CURRENT_BINARY_DIR}/Debug" - out_targets - ${debug_msvc8_files} - ) - set(all_targets ${all_targets} ${out_targets}) - - set(debug_appconfig_file ${CMAKE_CURRENT_BINARY_DIR}/Debug/${VIEWER_BINARY_NAME}.exe.config) - add_custom_command( - OUTPUT ${debug_appconfig_file} - COMMAND ${PYTHON_EXECUTABLE} - ARGS - ${CMAKE_CURRENT_SOURCE_DIR}/build_win32_appConfig.py - ${CMAKE_CURRENT_BINARY_DIR}/Debug/Microsoft.VC80.DebugCRT.manifest - ${CMAKE_CURRENT_SOURCE_DIR}/SecondLifeDebug.exe.config - ${debug_appconfig_file} - DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/Debug/Microsoft.VC80.DebugCRT.manifest - COMMENT "Creating debug app config file" - ) - - endif (EXISTS ${debug_msvc8_redist_path}) - - FIND_PATH(release_msvc8_redist_path msvcr80.dll - PATHS - [HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\8.0\\Setup\\VC;ProductDir]/redist/x86/Microsoft.VC80.CRT - NO_DEFAULT_PATH - NO_DEFAULT_PATH - ) - - if(EXISTS ${release_msvc8_redist_path}) - set(release_msvc8_files - msvcr80.dll - msvcp80.dll - Microsoft.VC80.CRT.manifest - ) - - copy_if_different( - ${release_msvc8_redist_path} - "${CMAKE_CURRENT_BINARY_DIR}/Release" - out_targets - ${release_msvc8_files} - ) - set(all_targets ${all_targets} ${out_targets}) - - copy_if_different( - ${release_msvc8_redist_path} - "${CMAKE_CURRENT_BINARY_DIR}/RelWithDebInfo" - out_targets - ${release_msvc8_files} - ) - set(all_targets ${all_targets} ${out_targets}) - - set(release_appconfig_file ${CMAKE_CURRENT_BINARY_DIR}/Release/${VIEWER_BINARY_NAME}.exe.config) - add_custom_command( - OUTPUT ${release_appconfig_file} - COMMAND ${PYTHON_EXECUTABLE} - ARGS - ${CMAKE_CURRENT_SOURCE_DIR}/build_win32_appConfig.py - ${CMAKE_CURRENT_BINARY_DIR}/Release/Microsoft.VC80.CRT.manifest - ${CMAKE_CURRENT_SOURCE_DIR}/SecondLife.exe.config - ${release_appconfig_file} - DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/Release/Microsoft.VC80.CRT.manifest - COMMENT "Creating release app config file" - ) - - set(relwithdebinfo_appconfig_file ${CMAKE_CURRENT_BINARY_DIR}/RelWithDebInfo/${VIEWER_BINARY_NAME}.exe.config) - add_custom_command( - OUTPUT ${relwithdebinfo_appconfig_file} - COMMAND ${PYTHON_EXECUTABLE} - ARGS - ${CMAKE_CURRENT_SOURCE_DIR}/build_win32_appConfig.py - ${CMAKE_CURRENT_BINARY_DIR}/RelWithDebInfo/Microsoft.VC80.CRT.manifest - ${CMAKE_CURRENT_SOURCE_DIR}/SecondLife.exe.config - ${relwithdebinfo_appconfig_file} - DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/RelWithDebInfo/Microsoft.VC80.CRT.manifest - COMMENT "Creating relwithdebinfo app config file" - ) - - endif (EXISTS ${release_msvc8_redist_path}) -endif (MSVC80) - -add_custom_target(copy_win_libs ALL - DEPENDS - ${all_targets} - ${release_appconfig_file} - ${relwithdebinfo_appconfig_file} - ${debug_appconfig_file} - ) -add_dependencies(copy_win_libs prepare) - diff --git a/indra/cmake/CrashPad.cmake b/indra/cmake/CrashPad.cmake new file mode 100644 index 0000000000..d3f4ed6b74 --- /dev/null +++ b/indra/cmake/CrashPad.cmake @@ -0,0 +1,22 @@ +# -*- cmake -*- +include(Prebuilt) +include(Variables) + +if(USE_CRASHPAD) + +if (USESYSTEMLIBS) +else (USESYSTEMLIBS) + use_prebuilt_binary(crashpad) + if (WINDOWS) + set(CRASHPAD_LIBRARIES + debug client.lib util.lib base.lib + optimized client.lib util.lib base.lib) + elseif (LINUX) + + else (DARWIN) + + endif () + set(CRASHPAD_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include/crashpad) +endif (USESYSTEMLIBS) + +endif() diff --git a/indra/cmake/DBusGlib.cmake b/indra/cmake/DBusGlib.cmake index 05266eb9cb..031796927c 100644 --- a/indra/cmake/DBusGlib.cmake +++ b/indra/cmake/DBusGlib.cmake @@ -1,24 +1,11 @@ # -*- cmake -*- -include(Prebuilt) -if (STANDALONE) +if (LINUX) include(FindPkgConfig) pkg_check_modules(DBUSGLIB REQUIRED dbus-glib-1) -elseif (LINUX) - use_prebuilt_binary(dbusglib) - set(DBUSGLIB_FOUND ON FORCE BOOL) - set(DBUSGLIB_INCLUDE_DIRS - ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/dbus - ) - # We don't need to explicitly link against dbus-glib itself, because - # the viewer probes for the system's copy at runtime. - set(DBUSGLIB_LIBRARIES - gobject-2.0 - glib-2.0 - ) -endif (STANDALONE) +endif (LINUX) if (DBUSGLIB_FOUND) set(DBUSGLIB ON CACHE BOOL "Build with dbus-glib message bus support.") diff --git a/indra/cmake/DeploySharedLibs.cmake b/indra/cmake/DeploySharedLibs.cmake new file mode 100644 index 0000000000..41b7e6a5bb --- /dev/null +++ b/indra/cmake/DeploySharedLibs.cmake @@ -0,0 +1,70 @@ +# DeploySharedLibs.cmake +# This is a script to be run at build time! Its not part of the cmake configuration! +# See indra/cmake/LLSharedLibs.cmake for a macro that simplifies adding a command to a target to run this script. + +# This script requires a few cmake variable to be set on the command line: +# BIN_NAME= The full path the the binary to search for dependecies. +# SEARCH_DIRS= The full paths to dirs to search for dependencies. +# DST_PATH= The full path where the dependecies will be copied. +get_filename_component(current_dir ${CMAKE_CURRENT_LIST_FILE} PATH) +include(GetPrerequisites) + +message("Getting recursive dependencies for file: ${BIN_NAME}") + +set(EXCLUDE_SYSTEM 1) +set(RECURSE 0) +get_filename_component(EXE_PATH ${BIN_NAME} PATH) + +get_prerequisites( ${BIN_NAME} RESULTS ${EXCLUDE_SYSTEM} ${RECURSE} "${EXE_PATH}" "${SEARCH_DIRS}" ) + +foreach(DEP ${RESULTS}) + Message("Processing dependency: ${DEP}") + get_filename_component(DEP_FILE ${DEP} NAME) + set(DEP_FILES ${DEP_FILES} ${DEP_FILE}) +endforeach(DEP) + +if(DEP_FILES) + list(REMOVE_DUPLICATES DEP_FILES) +endif(DEP_FILES) + +foreach(DEP_FILE ${DEP_FILES}) + if(FOUND_FILES) + list(FIND FOUND_FILES ${DEP_FILE} FOUND) + else(FOUND_FILES) + set(FOUND -1) + endif(FOUND_FILES) + + if(FOUND EQUAL -1) + find_path(DEP_PATH ${DEP_FILE} PATHS ${SEARCH_DIRS} NO_DEFAULT_PATH) + if(DEP_PATH) + set(FOUND_FILES ${FOUND_FILES} "${DEP_PATH}/${DEP_FILE}") + set(DEP_PATH NOTFOUND) #reset DEP_PATH for the next find_path call. + else(DEP_PATH) + set(MISSING_FILES ${MISSING_FILES} ${DEP_FILE}) + endif(DEP_PATH) + endif(FOUND EQUAL -1) +endforeach(DEP_FILE) + +if(MISSING_FILES) + message("Missing:") + foreach(FILE ${MISSING_FILES}) + message(" ${FILE}") + endforeach(FILE) + message("Searched in:") + foreach(SEARCH_DIR ${SEARCH_DIRS}) + message(" ${SEARCH_DIR}") + endforeach(SEARCH_DIR) + message(FATAL_ERROR "Failed") +endif(MISSING_FILES) + +if(FOUND_FILES) + foreach(FILE ${FOUND_FILES}) + get_filename_component(DST_FILE ${FILE} NAME) + set(DST_FILE "${DST_PATH}/${DST_FILE}") + message("Copying ${FILE} to ${DST_FILE}") + execute_process( + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${FILE} ${DST_FILE} + ) + endforeach(FILE ${FOUND_FILES}) +endif(FOUND_FILES) +message("Success!") diff --git a/indra/cmake/DirectX.cmake b/indra/cmake/DirectX.cmake deleted file mode 100644 index a0dc4b2b58..0000000000 --- a/indra/cmake/DirectX.cmake +++ /dev/null @@ -1,70 +0,0 @@ -# -*- cmake -*- - -include(Variables) - -if (WINDOWS) - if (WORD_SIZE EQUAL 32) - set (DIRECTX_ARCHITECTURE x86) - elseif (WORD_SIZE EQUAL 64) - set (DIRECTX_ARCHITECTURE x64) - else (WORD_SIZE EQUAL 32) - set (DIRECTX_ARCHITECTURE x86) - endif (WORD_SIZE EQUAL 32) - - find_path(DIRECTX_ROOT_DIR Include/dxdiag.h - PATHS - "$ENV{DXSDK_DIR}" - "$ENV{ProgramFiles}/Microsoft DirectX SDK (June 2010)" - "$ENV{ProgramFiles(x86)}/Microsoft DirectX SDK (June 2010)" - "$ENV{ProgramFiles}/Microsoft DirectX SDK (February 2010)" - "$ENV{ProgramFiles(x86)}/Microsoft DirectX SDK (February 2010)" - "$ENV{ProgramFiles}/Microsoft DirectX SDK (March 2009)" - "$ENV{ProgramFiles(x86)}/Microsoft DirectX SDK (March 2009)" - "$ENV{ProgramFiles}/Microsoft DirectX SDK (August 2008)" - "$ENV{ProgramFiles(x86)}/Microsoft DirectX SDK (August 2008)" - "$ENV{ProgramFiles}/Microsoft DirectX SDK (June 2008)" - "$ENV{ProgramFiles(x86)}/Microsoft DirectX SDK (June 2008)" - "$ENV{ProgramFiles}/Microsoft DirectX SDK (March 2008)" - "$ENV{ProgramFiles(x86)}/Microsoft DirectX SDK (March 2008)" - "$ENV{ProgramFiles}/Microsoft DirectX SDK (November 2007)" - "$ENV{ProgramFiles(x86)}/Microsoft DirectX SDK (November 2007)" - "$ENV{ProgramFiles}/Microsoft DirectX SDK (August 2007)" - "$ENV{ProgramFiles(x86)}/Microsoft DirectX SDK (August 2007)" - ) - - if (DIRECTX_ROOT_DIR) - set (DIRECTX_INCLUDE_DIR "${DIRECTX_ROOT_DIR}/Include") - set (DIRECTX_LIBRARY_DIR "${DIRECTX_ROOT_DIR}/Lib/${DIRECTX_ARCHITECTURE}") - else (DIRECTX_ROOT_DIR) - find_path (WIN_KIT_ROOT_DIR Include/um/windows.h - PATHS - "$ENV{ProgramFiles}/Windows Kits/8.1" - "$ENV{ProgramFiles(x86)}/Windows Kits/8.1" - "$ENV{ProgramFiles}/Windows Kits/8.0" - "$ENV{ProgramFiles(x86)}/Windows Kits/8.0" - ) - - if (WIN_KIT_ROOT_DIR) - set (DIRECTX_INCLUDE_DIR "${WIN_KIT_ROOT_DIR}/Include/um" "${WIN_KIT_ROOT_DIR}/Include/shared") - set (DIRECTX_LIBRARY_DIR "${WIN_KIT_ROOT_DIR}/Lib/Win8/um/${DIRECTX_ARCHITECTURE}") - endif (WIN_KIT_ROOT_DIR) - endif (DIRECTX_ROOT_DIR) - - if (DIRECTX_INCLUDE_DIR) - include_directories(${DIRECTX_INCLUDE_DIR}) - if (DIRECTX_FIND_QUIETLY) - message(STATUS "Found DirectX include: ${DIRECTX_INCLUDE_DIR}") - endif (DIRECTX_FIND_QUIETLY) - else (DIRECTX_INCLUDE_DIR) - message(FATAL_ERROR "Could not find DirectX SDK Include") - endif (DIRECTX_INCLUDE_DIR) - - if (DIRECTX_LIBRARY_DIR) - if (DIRECTX_FIND_QUIETLY) - message(STATUS "Found DirectX include: ${DIRECTX_LIBRARY_DIR}") - endif (DIRECTX_FIND_QUIETLY) - else (DIRECTX_LIBRARY_DIR) - message(FATAL_ERROR "Could not find DirectX SDK Libraries") - endif (DIRECTX_LIBRARY_DIR) - -endif (WINDOWS) diff --git a/indra/cmake/DownloadPrebuilt.cmake.in b/indra/cmake/DownloadPrebuilt.cmake.in deleted file mode 100644 index 7e4071d8a4..0000000000 --- a/indra/cmake/DownloadPrebuilt.cmake.in +++ /dev/null @@ -1,45 +0,0 @@ -# This script drives download of prebuilt packages during the build. -# The top-level CMakeLists.txt configures packages and tool locations. -set(packages "@PREBUILT_PACKAGES@") -set(python "@PYTHON_EXECUTABLE@") -set(install_dir "@CMAKE_SOURCE_DIR@/..") -set(scp "@SCP_EXECUTABLE@") -set(scripts_dir "@SCRIPTS_DIR@") -set(sentinel_dir "@CMAKE_BINARY_DIR@/prepare") -set(prebuilt_type "@PREBUILT_TYPE@") - -# In proprietary mode we use scp for download. -set(proprietary "@INSTALL_PROPRIETARY@") -if(proprietary) - set(scp_option "--scp=${scp}") - set(proprietary_message " proprietary") -endif(proprietary) - -foreach(package ${packages}) - if(${install_dir}/install.xml IS_NEWER_THAN ${sentinel_dir}/${package}_installed) - # This package is missing or out of date. - message(STATUS "Obtaining${proprietary_message} prebuilt '${package}'") - execute_process( - COMMAND ${python} install.py -p${prebuilt_type} --install-dir=${install_dir} ${scp_option} ${package} - WORKING_DIRECTORY ${scripts_dir} - RESULT_VARIABLE result - ) - if(result STREQUAL 0) - # Write a sentinel to avoid attempting a download again. - file(WRITE ${sentinel_dir}/${package}_installed "Obtained '${package}'") - else(result STREQUAL 0) - # Remove the sentinel to ensure a download is attempted again. - file(REMOVE ${sentinel_dir}/prebuilt - ${sentinel_dir}/${package}_installed) - message(FATAL_ERROR - "Failed to download or unpack prebuilt '${package}'. " - "Process returned: ${result}") - endif(result STREQUAL 0) - else(${install_dir}/install.xml IS_NEWER_THAN ${sentinel_dir}/${package}_installed) - # This package is ready. - message(STATUS "Prebuilt '${package}' is up-to-date") - endif(${install_dir}/install.xml IS_NEWER_THAN ${sentinel_dir}/${package}_installed) -endforeach(package) - -# Store a sentinel to avoid running this script unnecessarily. -file(WRITE ${sentinel_dir}/prebuilt "All prebuilts obtained successfully\n") diff --git a/indra/cmake/ELFIO.cmake b/indra/cmake/ELFIO.cmake deleted file mode 100644 index fbde783119..0000000000 --- a/indra/cmake/ELFIO.cmake +++ /dev/null @@ -1,19 +0,0 @@ -# -*- cmake -*- -include(Prebuilt) - -set(ELFIO_FIND_QUIETLY ON) - -if (STANDALONE) - include(FindELFIO) -elseif (LINUX) - use_prebuilt_binary(elfio) - set(ELFIO_LIBRARIES ELFIO) - set(ELFIO_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include) - set(ELFIO_FOUND "YES") -endif (STANDALONE) - -if (ELFIO_FOUND) - add_definitions(-DLL_ELFBIN=1) -else (ELFIO_FOUND) - set(ELFIO_INCLUDE_DIR "") -endif (ELFIO_FOUND) diff --git a/indra/cmake/EXPAT.cmake b/indra/cmake/EXPAT.cmake index 8a8f84526a..d11c6a9aff 100644 --- a/indra/cmake/EXPAT.cmake +++ b/indra/cmake/EXPAT.cmake @@ -9,9 +9,9 @@ if (STANDALONE) else (STANDALONE) use_prebuilt_binary(expat) if (WINDOWS) - set(EXPAT_LIBRARIES libexpatMT) + set(EXPAT_LIBRARIES expat) else (WINDOWS) set(EXPAT_LIBRARIES expat) endif (WINDOWS) - set(EXPAT_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include) + set(EXPAT_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include) endif (STANDALONE) diff --git a/indra/cmake/FMOD.cmake b/indra/cmake/FMOD.cmake deleted file mode 100644 index a2d9245ff2..0000000000 --- a/indra/cmake/FMOD.cmake +++ /dev/null @@ -1,52 +0,0 @@ -# -*- cmake -*- - -include(Linking) - -if(INSTALL_PROPRIETARY) - include(Prebuilt) - use_prebuilt_binary(fmod) -endif(INSTALL_PROPRIETARY) - -find_library(FMOD_LIBRARY - NAMES fmod fmodvc fmod-3.75 - PATHS - optimized ${ARCH_PREBUILT_DIRS_RELEASE} - debug ${ARCH_PREBUILT_DIRS_DEBUG} - ) - -if (NOT FMOD_LIBRARY) - set(FMOD_SDK_DIR CACHE PATH "Path to the FMOD SDK.") - if (FMOD_SDK_DIR) - find_library(FMOD_LIBRARY - NAMES fmodvc fmod-3.75 fmod - PATHS - ${FMOD_SDK_DIR}/api/lib - ${FMOD_SDK_DIR}/api - ${FMOD_SDK_DIR}/lib - ${FMOD_SDK_DIR} - ) - endif (FMOD_SDK_DIR) -endif (NOT FMOD_LIBRARY) - -find_path(FMOD_INCLUDE_DIR fmod.h - ${LIBS_PREBUILT_DIR}/include - ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include - ${FMOD_SDK_DIR}/api/inc - ${FMOD_SDK_DIR}/inc - ${FMOD_SDK_DIR} - ) - -if (FMOD_LIBRARY AND FMOD_INCLUDE_DIR) - set(FMOD ON CACHE BOOL "Use closed source FMOD sound library.") -else (FMOD_LIBRARY AND FMOD_INCLUDE_DIR) - set(FMOD_LIBRARY "") - set(FMOD_INCLUDE_DIR "") - if (FMOD) - message(STATUS "No support for FMOD audio (need to set FMOD_SDK_DIR?)") - endif (FMOD) - set(FMOD OFF CACHE BOOL "Use closed source FMOD sound library.") -endif (FMOD_LIBRARY AND FMOD_INCLUDE_DIR) - -if (FMOD) - message(STATUS "Building with FMOD audio support") -endif (FMOD) diff --git a/indra/cmake/FMODEX.cmake b/indra/cmake/FMODEX.cmake deleted file mode 100644 index dbac0ebacd..0000000000 --- a/indra/cmake/FMODEX.cmake +++ /dev/null @@ -1,72 +0,0 @@ -# -*- cmake -*- - -include(Linking) - -if (NOT FMODEX_LIBRARY) - set(FMODEX_SDK_DIR CACHE PATH "Path to the FMOD Ex SDK.") - if (FMODEX_SDK_DIR) - if(WORD_SIZE EQUAL 32) - find_library(FMODEX_LIBRARY - fmodex_vc fmodexL_vc fmodex fmodexL - PATHS - "${FMODEX_SDK_DIR}/api/lib" - "${FMODEX_SDK_DIR}/api" - "${FMODEX_SDK_DIR}/lib" - "${FMODEX_SDK_DIR}" - ) - elseif(WORD_SIZE EQUAL 64) - find_library(FMODEX_LIBRARY - fmodex64 fmodexL64 - PATHS - "${FMODEX_SDK_DIR}/api/lib" - "${FMODEX_SDK_DIR}/api" - "${FMODEX_SDK_DIR}/lib" - "${FMODEX_SDK_DIR}" - ) - endif(WORD_SIZE EQUAL 32) - endif(FMODEX_SDK_DIR) - if(WINDOWS AND NOT FMODEX_LIBRARY) - set(FMODEX_PROG_DIR "$ENV{PROGRAMFILES}/FMOD SoundSystem/FMOD Programmers API Windows") - find_library(FMODEX_LIBRARY - fmodex_vc fmodexL_vc - PATHS - "${FMODEX_PROG_DIR}/api/lib" - "${FMODEX_PROG_DIR}/api" - "${FMODEX_PROG_DIR}" - ) - if(FMODEX_LIBRARY) - message(STATUS "Found fmodex in ${FMODEX_PROG_DIR}") - set(FMODEX_SDK_DIR "${FMODEX_PROG_DIR}") - set(FMODEX_SDK_DIR "${FMODEX_PROG_DIR}" CACHE PATH "Path to the FMOD Ex SDK." FORCE) - endif(FMODEX_LIBRARY) - endif(WINDOWS AND NOT FMODEX_LIBRARY) -endif (NOT FMODEX_LIBRARY) - -find_path(FMODEX_INCLUDE_DIR fmod.hpp - "${LIBS_PREBUILT_DIR}/include/fmodex" - "${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/fmodex" - "${FMODEX_SDK_DIR}/api/inc" - "${FMODEX_SDK_DIR}/inc" - "${FMODEX_SDK_DIR}" - ) - -if(DARWIN) - set(FMODEX_ORIG_LIBRARY "${FMODEX_LIBRARY}") - set(FMODEX_LIBRARY "${CMAKE_CURRENT_BINARY_DIR}/libfmodex.dylib") -endif(DARWIN) - -if (FMODEX_LIBRARY AND FMODEX_INCLUDE_DIR) - set(FMODEX ON CACHE BOOL "Use closed source FMOD Ex sound library.") -else (FMODEX_LIBRARY AND FMODEX_INCLUDE_DIR) - set(FMODEX_LIBRARY "") - set(FMODEX_INCLUDE_DIR "") - if (FMODEX) - message(STATUS "No support for FMOD Ex audio (need to set FMODEX_SDK_DIR?)") - endif (FMODEX) - set(FMODEX OFF CACHE BOOL "Use closed source FMOD Ex sound library.") - set(FMODEX OFF) -endif (FMODEX_LIBRARY AND FMODEX_INCLUDE_DIR) - -if (FMODEX) - message(STATUS "Building with FMOD Ex audio support") -endif (FMODEX) diff --git a/indra/cmake/FMODSTUDIO.cmake b/indra/cmake/FMODSTUDIO.cmake new file mode 100644 index 0000000000..83ac0ac9c4 --- /dev/null +++ b/indra/cmake/FMODSTUDIO.cmake @@ -0,0 +1,50 @@ +# -*- cmake -*- + +include(Variables) +if (USE_FMODSTUDIO) + use_prebuilt_binary(fmodstudio) + if(WINDOWS) + set(lib_suffix .dll) + elseif(DARWIN) + set(lib_suffix .dylib) + else(WINDOWS) + set(lib_suffix .so) + endif(WINDOWS) + if(WINDOWS) + set(FMOD_LIBRARY_RELEASE ${LIBS_PREBUILT_DIR}/lib/release/fmod${lib_suffix}) + set(FMOD_LIBRARY_DEBUG ${LIBS_PREBUILT_DIR}/lib/debug/fmodL${lib_suffix}) + else(WINDOWS) + set(FMOD_LIBRARY_RELEASE ${LIBS_PREBUILT_DIR}/lib/release/libfmod${lib_suffix}) + set(FMOD_LIBRARY_DEBUG ${LIBS_PREBUILT_DIR}/lib/debug/libfmodL${lib_suffix}) + endif(WINDOWS) + set(FMOD_LINK_LIBRARY_RELEASE ${FMOD_LIBRARY_RELEASE}) + set(FMOD_LINK_LIBRARY_DEBUG ${FMOD_LIBRARY_DEBUG}) + + if(WINDOWS) + string(REPLACE ".dll" "_vc.lib" FMOD_LINK_LIBRARY_RELEASE ${FMOD_LIBRARY_RELEASE}) + string(REPLACE ".dll" "_vc.lib" FMOD_LINK_LIBRARY_DEBUG ${FMOD_LIBRARY_DEBUG}) + endif(WINDOWS) + + set (FMOD_LIBRARY + debug ${FMOD_LINK_LIBRARY_DEBUG} + optimized ${FMOD_LINK_LIBRARY_RELEASE} + ) + + set(FMODSTUDIO_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/fmodstudio) +endif(USE_FMODSTUDIO) + +if(FMOD_LIBRARY_RELEASE AND FMODSTUDIO_INCLUDE_DIR) + set(FMOD ON) + if (NOT FMOD_LIBRARY_DEBUG) #Use release library in debug configuration if debug library is absent. + set(FMOD_LIBRARY_DEBUG ${FMOD_LIBRARY_RELEASE}) + endif (NOT FMOD_LIBRARY_DEBUG) +else (FMOD_LIBRARY_RELEASE AND FMODSTUDIO_INCLUDE_DIR) + message(STATUS "No support for FMOD Studio audio (need to set FMODSTUDIO_SDK_DIR?)") + set(FMOD OFF) + set(USE_FMODSTUDIO OFF) +endif (FMOD_LIBRARY_RELEASE AND FMODSTUDIO_INCLUDE_DIR) + +if (FMOD) + message(STATUS "Building with FMOD Studio audio support") +endif (FMOD) + diff --git a/indra/cmake/FindAutobuild.cmake b/indra/cmake/FindAutobuild.cmake new file mode 100644 index 0000000000..ea5ad6d108 --- /dev/null +++ b/indra/cmake/FindAutobuild.cmake @@ -0,0 +1,43 @@ +# -*- cmake -*- +# +# Find the autobuild tool +# +# Output variables: +# +# AUTOBUILD_EXECUTABLE - path to autobuild executable + + + +IF (NOT AUTOBUILD_EXECUTABLE) + + # If cmake was executed by autobuild, autobuild will have set the AUTOBUILD env var + IF (DEFINED ENV{AUTOBUILD}) + SET(AUTOBUILD_EXECUTABLE $ENV{AUTOBUILD}) + ELSE (DEFINED ENV{AUTOBUILD}) + IF(WIN32) + SET(AUTOBUILD_EXE_NAMES autobuild.exe autobuild.cmd) + ELSE(WIN32) + SET(AUTOBUILD_EXE_NAMES autobuild) + ENDIF(WIN32) + + SET(AUTOBUILD_EXECUTABLE) + FIND_PROGRAM( + AUTOBUILD_EXECUTABLE + NAMES ${AUTOBUILD_EXE_NAMES} + PATHS + ENV PATH + ${CMAKE_SOURCE_DIR}/.. + ${CMAKE_SOURCE_DIR}/../.. + ${CMAKE_SOURCE_DIR}/../../.. + PATH_SUFFIXES "/autobuild/bin/" + ) + ENDIF (DEFINED ENV{AUTOBUILD}) + + IF (NOT AUTOBUILD_EXECUTABLE) + IF (AUTOBUILD_FIND_REQUIRED) + MESSAGE(FATAL_ERROR "Could not find autobuild executable") + ENDIF (AUTOBUILD_FIND_REQUIRED) + ENDIF (NOT AUTOBUILD_EXECUTABLE) + + MARK_AS_ADVANCED(AUTOBUILD_EXECUTABLE) +ENDIF (NOT AUTOBUILD_EXECUTABLE) diff --git a/indra/cmake/FindBerkeleyDB.cmake b/indra/cmake/FindBerkeleyDB.cmake deleted file mode 100644 index 2d633c74ec..0000000000 --- a/indra/cmake/FindBerkeleyDB.cmake +++ /dev/null @@ -1,50 +0,0 @@ -# -*- cmake -*- - -# - Find BerkeleyDB -# Find the BerkeleyDB includes and library -# This module defines -# DB_INCLUDE_DIR, where to find db.h, etc. -# DB_LIBRARIES, the libraries needed to use BerkeleyDB. -# DB_FOUND, If false, do not try to use BerkeleyDB. -# also defined, but not for general use are -# DB_LIBRARY, where to find the BerkeleyDB library. - -FIND_PATH(DB_INCLUDE_DIR db.h -/usr/local/include/db4 -/usr/local/include -/usr/include/db4 -/usr/include -) - -SET(DB_NAMES ${DB_NAMES} db) -FIND_LIBRARY(DB_LIBRARY - NAMES ${DB_NAMES} - PATHS /usr/lib /usr/local/lib - ) - -IF (DB_LIBRARY AND DB_INCLUDE_DIR) - SET(DB_LIBRARIES ${DB_LIBRARY}) - SET(DB_FOUND "YES") -ELSE (DB_LIBRARY AND DB_INCLUDE_DIR) - SET(DB_FOUND "NO") -ENDIF (DB_LIBRARY AND DB_INCLUDE_DIR) - - -IF (DB_FOUND) - IF (NOT DB_FIND_QUIETLY) - MESSAGE(STATUS "Found BerkeleyDB: ${DB_LIBRARIES}") - ENDIF (NOT DB_FIND_QUIETLY) -ELSE (DB_FOUND) - IF (DB_FIND_REQUIRED) - MESSAGE(FATAL_ERROR "Could not find BerkeleyDB library") - ENDIF (DB_FIND_REQUIRED) -ENDIF (DB_FOUND) - -# Deprecated declarations. -SET (NATIVE_DB_INCLUDE_PATH ${DB_INCLUDE_DIR} ) -GET_FILENAME_COMPONENT (NATIVE_DB_LIB_PATH ${DB_LIBRARY} PATH) - -MARK_AS_ADVANCED( - DB_LIBRARY - DB_INCLUDE_DIR - ) diff --git a/indra/cmake/FindELFIO.cmake b/indra/cmake/FindELFIO.cmake deleted file mode 100644 index 8a5421ab9c..0000000000 --- a/indra/cmake/FindELFIO.cmake +++ /dev/null @@ -1,48 +0,0 @@ -# -*- cmake -*- - -# - Find ELFIO -# Find the ELFIO includes and library -# This module defines -# ELFIO_INCLUDE_DIR, where to find elfio.h, etc. -# ELFIO_LIBRARIES, the libraries needed to use ELFIO. -# ELFIO_FOUND, If false, do not try to use ELFIO. -# also defined, but not for general use are -# ELFIO_LIBRARY, where to find the ELFIO library. - -FIND_PATH(ELFIO_INCLUDE_DIR ELFIO/ELFIO.h -/usr/local/include -/usr/include -) - -SET(ELFIO_NAMES ${ELFIO_NAMES} ELFIO) -FIND_LIBRARY(ELFIO_LIBRARY - NAMES ${ELFIO_NAMES} - PATHS /usr/lib /usr/local/lib - ) - -IF (ELFIO_LIBRARY AND ELFIO_INCLUDE_DIR) - SET(ELFIO_LIBRARIES ${ELFIO_LIBRARY}) - SET(ELFIO_FOUND "YES") -ELSE (ELFIO_LIBRARY AND ELFIO_INCLUDE_DIR) - SET(ELFIO_FOUND "NO") -ENDIF (ELFIO_LIBRARY AND ELFIO_INCLUDE_DIR) - - -IF (ELFIO_FOUND) - IF (NOT ELFIO_FIND_QUIETLY) - MESSAGE(STATUS "Found ELFIO: ${ELFIO_LIBRARIES}") - ENDIF (NOT ELFIO_FIND_QUIETLY) -ELSE (ELFIO_FOUND) - IF (ELFIO_FIND_REQUIRED) - MESSAGE(FATAL_ERROR "Could not find ELFIO library") - ENDIF (ELFIO_FIND_REQUIRED) -ENDIF (ELFIO_FOUND) - -# Deprecated declarations. -SET (NATIVE_ELFIO_INCLUDE_PATH ${ELFIO_INCLUDE_DIR} ) -GET_FILENAME_COMPONENT (NATIVE_ELFIO_LIB_PATH ${ELFIO_LIBRARY} PATH) - -MARK_AS_ADVANCED( - ELFIO_LIBRARY - ELFIO_INCLUDE_DIR - ) diff --git a/indra/cmake/FindJsonCpp.cmake b/indra/cmake/FindJsonCpp.cmake deleted file mode 100644 index a48c973964..0000000000 --- a/indra/cmake/FindJsonCpp.cmake +++ /dev/null @@ -1,39 +0,0 @@ -# -*- cmake -*- - -# - Find JSONCpp -# Find the JSONCpp includes and library -# This module defines -# JSONCPP_FOUND, System has libjsoncpp. -# JSONCPP_INCLUDE_DIRS - The libjsoncpp include directories. -# JSONCPP_LIBRARIES - The libraries needed to use libjsoncpp. -# JSONCPP_DEFINITIONS - Compiler switches required for using libjsoncpp. - -FIND_PACKAGE(PkgConfig) -PKG_CHECK_MODULES(PC_JSONCPP jsoncpp) -SET(JSONCPP_DEFINITIONS ${PC_JSONCPP_CFLAGS_OTHER}) - -FIND_PATH(JSONCPP_INCLUDE_DIR json/reader.h - HINTS ${PC_JSONCPP_INCLUDE_DIR} ${PC_JSONCPP_INCLUDE_DIRS} - PATH_SUFFIXES jsoncpp) - -# Get the GCC compiler version -EXEC_PROGRAM(${CMAKE_CXX_COMPILER} - ARGS ${CMAKE_CXX_COMPILER_ARG1} -dumpversion - OUTPUT_VARIABLE _gcc_COMPILER_VERSION - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - -# Try to find a library that was compiled with the same compiler version as we currently use. -FIND_LIBRARY(JSONCPP_LIBRARY - NAMES libjson_linux-gcc-${_gcc_COMPILER_VERSION}_libmt.so libjsoncpp.so - HINTS ${PC_JSONCPP_LIBDIR} ${PC_JSONCPP_LIBRARY_DIRS} - PATHS /usr/lib /usr/local/lib) - -SET(JSONCPP_LIBRARIES ${JSONCPP_LIBRARY}) -SET(JSONCPP_INCLUDE_DIRS ${JSONCPP_INCLUDE_DIR}) - -include(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(JSONCPP DEFAULT_MSG - JSONCPP_LIBRARY JSONCPP_INCLUDE_DIR) - -MARK_AS_ADVANCED(JSONCPP_LIBRARY JSONCPP_INCLUDE_DIR) diff --git a/indra/cmake/FindLLQtWebkit.cmake b/indra/cmake/FindLLQtWebkit.cmake deleted file mode 100644 index 731ae67d75..0000000000 --- a/indra/cmake/FindLLQtWebkit.cmake +++ /dev/null @@ -1,62 +0,0 @@ -# -*- cmake -*- - -# - Find llqtwebkit -# Find the llqtwebkit includes and library -# This module defines -# LLQTWEBKIT_INCLUDE_DIR, where to find llqtwebkit.h, etc. -# LLQTWEBKIT_LIBRARY, the llqtwebkit library with full path. -# LLQTWEBKIT_FOUND, If false, do not try to use llqtwebkit. -# also defined, but not for general use are -# LLQTWEBKIT_LIBRARIES, the libraries needed to use llqtwebkit. -# LLQTWEBKIT_LIBRARY_DIRS, where to find the llqtwebkit library. -# LLQTWEBKIT_DEFINITIONS - You should add_definitions(${LLQTWEBKIT_DEFINITIONS}) -# before compiling code that includes llqtwebkit library files. - -# Try to use pkg-config first. -# This allows to have two different libllqtwebkit packages installed: -# one for viewer 2.x and one for viewer 1.x. -include(FindPkgConfig) -if (PKG_CONFIG_FOUND) - if (LLQtWebkit_FIND_REQUIRED AND LLQtWebkit_FIND_VERSION) - set(_PACKAGE_ARGS libllqtwebkit>=${LLQtWebkit_FIND_VERSION} REQUIRED) - else (LLQtWebkit_FIND_REQUIRED AND LLQtWebkit_FIND_VERSION) - set(_PACKAGE_ARGS libllqtwebkit) - endif (LLQtWebkit_FIND_REQUIRED AND LLQtWebkit_FIND_VERSION) - if (NOT "${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" VERSION_LESS "2.8") - # As virtually nobody will have a pkg-config file for this, do this check always quiet. - # Unfortunately cmake 2.8 or higher is required for pkg_check_modules to have a 'QUIET'. - set(_PACKAGE_ARGS ${_PACKAGE_ARGS} QUIET) - endif () - pkg_check_modules(LLQTWEBKIT ${_PACKAGE_ARGS}) -endif (PKG_CONFIG_FOUND) -set(LLQTWEBKIT_DEFINITIONS ${LLQTWEBKIT_CFLAGS_OTHER}) - -find_path(LLQTWEBKIT_INCLUDE_DIR llqtwebkit.h NO_SYSTEM_ENVIRONMENT_PATH HINTS ${LLQTWEBKIT_INCLUDE_DIRS}) - -find_library(LLQTWEBKIT_LIBRARY NAMES llqtwebkit NO_SYSTEM_ENVIRONMENT_PATH HINTS ${LLQTWEBKIT_LIBRARY_DIRS}) - -if (NOT PKG_CONFIG_FOUND OR NOT LLQTWEBKIT_FOUND) # If pkg-config couldn't find it, pretend we don't have pkg-config. - set(LLQTWEBKIT_LIBRARIES llqtwebkit) - get_filename_component(LLQTWEBKIT_LIBRARY_DIRS ${LLQTWEBKIT_LIBRARY} PATH) -endif (NOT PKG_CONFIG_FOUND OR NOT LLQTWEBKIT_FOUND) - -# Handle the QUIETLY and REQUIRED arguments and set LLQTWEBKIT_FOUND -# to TRUE if all listed variables are TRUE. -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args( - LLQTWEBKIT - DEFAULT_MSG - LLQTWEBKIT_LIBRARY - LLQTWEBKIT_INCLUDE_DIR - LLQTWEBKIT_LIBRARIES - LLQTWEBKIT_LIBRARY_DIRS - ) - -mark_as_advanced( - LLQTWEBKIT_LIBRARY - LLQTWEBKIT_INCLUDE_DIR - LLQTWEBKIT_LIBRARIES - LLQTWEBKIT_LIBRARY_DIRS - LLQTWEBKIT_DEFINITIONS - ) - diff --git a/indra/cmake/FindURIPARSER.cmake b/indra/cmake/FindURIPARSER.cmake new file mode 100644 index 0000000000..05f2d17374 --- /dev/null +++ b/indra/cmake/FindURIPARSER.cmake @@ -0,0 +1,46 @@ +# -*- cmake -*- + +# - Find uriparser +# Find the URIPARSER includes and library +# This module defines +# URIPARSER_INCLUDE_DIRS, where to find uriparser.h, etc. +# URIPARSER_LIBRARY, the libraries needed to use uriparser. +# URIPARSER_FOUND, If false, do not try to use uriparser. +# +# This FindURIPARSER is about 43 times as fast the one provided with cmake (2.8.x), +# because it doesn't look up the version of uriparser, resulting in a dramatic +# speed up for configure (from 4 minutes 22 seconds to 6 seconds). +# +# Note: Since this file is only used for standalone, the windows +# specific parts were left out. + +FIND_PATH(URIPARSER_INCLUDE_DIR uriparser/Uri.h + NO_SYSTEM_ENVIRONMENT_PATH + ) + +FIND_LIBRARY(URIPARSER_LIBRARY uriparser) + +if (URIPARSER_LIBRARY AND URIPARSER_INCLUDE_DIR) + SET(URIPARSER_INCLUDE_DIRS ${URIPARSER_INCLUDE_DIR}) + SET(URIPARSER_LIBRARY ${URIPARSER_LIBRARY}) + SET(URIPARSER_FOUND "YES") +else (URIPARSER_LIBRARY AND URIPARSER_INCLUDE_DIR) + SET(URIPARSER_FOUND "NO") +endif (URIPARSER_LIBRARY AND URIPARSER_INCLUDE_DIR) + +if (URIPARSER_FOUND) + if (NOT URIPARSER_FIND_QUIETLY) + message(STATUS "Found URIPARSER: ${URIPARSER_LIBRARY}") + SET(URIPARSER_FIND_QUIETLY TRUE) + endif (NOT URIPARSER_FIND_QUIETLY) +else (URIPARSER_FOUND) + if (URIPARSER_FIND_REQUIRED) + message(FATAL_ERROR "Could not find URIPARSER library") + endif (URIPARSER_FIND_REQUIRED) +endif (URIPARSER_FOUND) + +mark_as_advanced( + URIPARSER_LIBRARY + URIPARSER_INCLUDE_DIR + ) + diff --git a/indra/cmake/FreeType.cmake b/indra/cmake/FreeType.cmake index e9d4d8093f..da122419d1 100644 --- a/indra/cmake/FreeType.cmake +++ b/indra/cmake/FreeType.cmake @@ -1,20 +1,14 @@ # -*- cmake -*- include(Prebuilt) -if (STANDALONE) +if (LINUX) include(FindPkgConfig) pkg_check_modules(FREETYPE REQUIRED freetype2) -else (STANDALONE) +else (LINUX) use_prebuilt_binary(freetype) - if (LINUX) - set(FREETYPE_INCLUDE_DIRS - ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include) - else (LINUX) - set(FREETYPE_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include) - endif (LINUX) - + set(FREETYPE_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include/freetype2) set(FREETYPE_LIBRARIES freetype) -endif (STANDALONE) +endif (LINUX) link_directories(${FREETYPE_LIBRARY_DIRS}) diff --git a/indra/cmake/GLOD.cmake b/indra/cmake/GLOD.cmake index e46a72c862..73881e17a1 100644 --- a/indra/cmake/GLOD.cmake +++ b/indra/cmake/GLOD.cmake @@ -7,7 +7,8 @@ set(GLOD_FIND_REQUIRED ON) if (STANDALONE) include(FindGLOD) else (STANDALONE) - use_prebuilt_binary(GLOD) - set(GLOD_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include) - set(GLOD_LIBRARIES glod) + use_prebuilt_binary(glod) + + set(GLOD_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/glod) + set(GLOD_LIBRARIES GLOD) endif (STANDALONE) diff --git a/indra/cmake/GStreamer010Plugin.cmake b/indra/cmake/GStreamer010Plugin.cmake index 90ed35c813..c9b071d1ea 100644 --- a/indra/cmake/GStreamer010Plugin.cmake +++ b/indra/cmake/GStreamer010Plugin.cmake @@ -1,27 +1,9 @@ # -*- cmake -*- include(Prebuilt) - -if (STANDALONE) include(FindPkgConfig) - pkg_check_modules(GSTREAMER010 REQUIRED gstreamer-0.10) pkg_check_modules(GSTREAMER010_PLUGINS_BASE REQUIRED gstreamer-plugins-base-0.10) -else (STANDALONE) - - # Possibly libxml and glib should have their own .cmake file instead... - use_prebuilt_binary(glib) # gstreamer needs glib - use_prebuilt_binary(libxml) - use_prebuilt_binary(gstreamer) - set(GSTREAMER010_FOUND ON FORCE BOOL) - set(GSTREAMER010_PLUGINS_BASE_FOUND ON FORCE BOOL) - set(GSTREAMER010_INCLUDE_DIRS - ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/gstreamer-0.10 - ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/glib-2.0 - ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/libxml2 - ) - -endif (STANDALONE) if (WINDOWS) # We don't need to explicitly link against gstreamer itself, because diff --git a/indra/cmake/GeneratePrecompiledHeader.cmake b/indra/cmake/GeneratePrecompiledHeader.cmake new file mode 100644 index 0000000000..67929d3a38 --- /dev/null +++ b/indra/cmake/GeneratePrecompiledHeader.cmake @@ -0,0 +1,116 @@ +# -*- cmake -*- + +# Distributed under the MIT Software License +# Copyright (c) 2015-2017 Borislav Stanimirov +# Modifications Copyright (c) 2019 Cinder Roxley. All rights reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +# target_precompiled_header +# +# Sets a precompiled header for a given target +# Args: +# TARGET_NAME - Name of the target. Only valid after add_library or add_executable +# PRECOMPILED_HEADER - Header file to precompile +# PRECOMPILED_SOURCE - MSVC specific source to do the actual precompilation. Ignored on other platforms +# + +macro(target_precompiled_header TARGET_NAME PRECOMPILED_HEADER PRECOMPILED_SOURCE) + get_filename_component(PRECOMPILED_HEADER_NAME ${PRECOMPILED_HEADER} NAME) + + if(MSVC) + get_filename_component(PRECOMPILED_SOURCE_NAME ${PRECOMPILED_SOURCE} NAME) + get_filename_component(PRECOMPILED_HEADER_PATH ${PRECOMPILED_HEADER} DIRECTORY) + target_include_directories(${TARGET_NAME} PRIVATE ${PRECOMPILED_HEADER_PATH}) # fixes occasional IntelliSense glitches + + get_filename_component(PRECOMPILED_HEADER_WE ${PRECOMPILED_HEADER} NAME_WE) + if(GEN_IS_MULTI_CONFIG) + set(PRECOMPILED_BINARY "$(IntDir)/${PRECOMPILED_HEADER_WE}.pch") + else() + set(PRECOMPILED_BINARY "${CMAKE_CURRENT_BINARY_DIR}/${PRECOMPILED_HEADER_WE}.pch") + endif() + + set_source_files_properties(${PRECOMPILED_SOURCE} PROPERTIES + COMPILE_OPTIONS "/Yc${PRECOMPILED_HEADER_NAME};/Fp${PRECOMPILED_BINARY}" + OBJECT_OUTPUTS "${PRECOMPILED_BINARY}") + + get_target_property(TARGET_SOURCES ${TARGET_NAME} SOURCES) + foreach(src ${TARGET_SOURCES}) + if(${src} MATCHES \\.\(cpp|cxx|cc\)$) + set_source_files_properties("${CMAKE_CURRENT_SOURCE_DIR}/${src}" PROPERTIES + COMPILE_OPTIONS "/Yu${PRECOMPILED_HEADER_NAME};/FI${PRECOMPILED_HEADER_NAME};/Fp${PRECOMPILED_BINARY}" + OBJECT_DEPENDS "${PRECOMPILED_BINARY}" + ) + endif() + endforeach() + #set_target_properties(${TARGET_NAME} PROPERTIES + # COMPILE_OPTIONS "/Yu${PRECOMPILED_HEADER_NAME};/FI${PRECOMPILED_HEADER_NAME};/Fp${PRECOMPILED_BINARY}") + + target_sources(${TARGET_NAME} PRIVATE ${PRECOMPILED_SOURCE} ${PRECOMPILED_HEADER}) + elseif(CMAKE_GENERATOR STREQUAL Xcode) + set_target_properties( + ${TARGET_NAME} + PROPERTIES + XCODE_ATTRIBUTE_GCC_PREFIX_HEADER "${PRECOMPILED_HEADER}" + XCODE_ATTRIBUTE_GCC_PRECOMPILE_PREFIX_HEADER "YES" + ) + elseif(CMAKE_COMPILER_IS_GNUCC OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") + # Create and set output directory. + set(OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/${PRECOMPILED_HEADER_NAME}.gch") + make_directory(${OUTPUT_DIR}) + set(OUTPUT_NAME "${OUTPUT_DIR}/${PRECOMPILED_HEADER_NAME}.gch") + + # Export compiler flags via a generator to a response file + set(PCH_FLAGS_FILE "${OUTPUT_DIR}/${PRECOMPILED_HEADER_NAME}.rsp") + set(_include_directories "$") + set(_compile_definitions "$") + set(_compile_flags "$") + set(_compile_options "$") + set(_include_directories "$<$:-I$\n>") + set(_compile_definitions "$<$:-D$\n>") + set(_compile_flags "$<$:$\n>") + set(_compile_options "$<$:$\n>") + file(GENERATE OUTPUT "${PCH_FLAGS_FILE}" CONTENT "${_compile_definitions}${_include_directories}${_compile_flags}${_compile_options}\n") + + # Gather global compiler options, definitions, etc. + string(TOUPPER "CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}" CXX_FLAGS) + set(COMPILER_FLAGS "${${CXX_FLAGS}} ${CMAKE_CXX_FLAGS}") + separate_arguments(COMPILER_FLAGS) + + # Add a custom target for building the precompiled header. + add_custom_command( + OUTPUT ${OUTPUT_NAME} + COMMAND ${CMAKE_CXX_COMPILER} @${PCH_FLAGS_FILE} ${COMPILER_FLAGS} -x c++-header -o ${OUTPUT_NAME} ${PRECOMPILED_HEADER} + DEPENDS ${PRECOMPILED_HEADER}) + add_custom_target(${TARGET_NAME}_gch DEPENDS ${OUTPUT_NAME}) + add_dependencies(${TARGET_NAME} ${TARGET_NAME}_gch) + + # set_target_properties(${TARGET_NAME} PROPERTIES COMPILE_FLAGS "-include ${PRECOMPILED_HEADER_NAME} -Winvalid-pch") + get_target_property(SOURCE_FILES ${TARGET_NAME} SOURCES) + get_target_property(asdf ${TARGET_NAME} COMPILE_FLAGS) + foreach(SOURCE_FILE ${SOURCE_FILES}) + if(SOURCE_FILE MATCHES \\.\(c|cc|cxx|cpp\)$) + set_source_files_properties(${SOURCE_FILE} PROPERTIES + COMPILE_FLAGS "-include ${OUTPUT_DIR}/${PRECOMPILED_HEADER_NAME} -Winvalid-pch" + ) + endif() + endforeach() + else() + message(FATAL_ERROR "Unknown generator for target_precompiled_header. [${CMAKE_CXX_COMPILER_ID}]") + endif() +endmacro(target_precompiled_header) + diff --git a/indra/cmake/GooglePerfTools.cmake b/indra/cmake/GooglePerfTools.cmake index d92c39ded5..d951bc55ea 100644 --- a/indra/cmake/GooglePerfTools.cmake +++ b/indra/cmake/GooglePerfTools.cmake @@ -2,16 +2,16 @@ include(Prebuilt) -if(WORD_SIZE EQUAL 64) +if(ADDRESS_SIZE EQUAL 64) set(DISABLE_TCMALLOC TRUE) -endif(WORD_SIZE EQUAL 64) +endif(ADDRESS_SIZE EQUAL 64) if (STANDALONE) include(FindGooglePerfTools) else (STANDALONE) - if (LINUX OR WINDOWS AND NOT WORD_SIZE EQUAL 64) + if (LINUX OR WINDOWS AND NOT ADDRESS_SIZE EQUAL 64) use_prebuilt_binary(gperftools) - endif (LINUX OR WINDOWS AND NOT WORD_SIZE EQUAL 64) + endif (LINUX OR WINDOWS AND NOT ADDRESS_SIZE EQUAL 64) if (WINDOWS AND NOT DISABLE_TCMALLOC) set(TCMALLOC_LIBRARIES libtcmalloc_minimal.lib) set(TCMALLOC_LINKER_FLAGS "/INCLUDE:\"__tcmalloc\"") @@ -25,7 +25,9 @@ else (STANDALONE) set(TCMALLOC_LIBRARIES tcmalloc_minimal) endif() set(GOOGLE_PERFTOOLS_INCLUDE_DIR - ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include) + ${LIBS_PREBUILT_DIR}/include + ${LIBS_PREBUILT_LEGACY_DIR}/include + ) endif (LINUX) endif (STANDALONE) diff --git a/indra/cmake/Hunspell.cmake b/indra/cmake/Hunspell.cmake index 363f061b56..83f9bc2fda 100644 --- a/indra/cmake/Hunspell.cmake +++ b/indra/cmake/Hunspell.cmake @@ -4,13 +4,13 @@ include(Prebuilt) if (STANDALONE) include(FindHunSpell) else (STANDALONE) - use_prebuilt_binary(hunspell) - - set(HUNSPELL_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/hunspell) + use_prebuilt_binary(libhunspell) - if (LINUX OR DARWIN) - set(HUNSPELL_LIBRARY hunspell-1.3) - else (LINUX OR DARWIN) - set(HUNSPELL_LIBRARY libhunspell) - endif (LINUX OR DARWIN) + if (LINUX OR DARWIN) + set(HUNSPELL_LIBRARY hunspell-1.3) + else (LINUX OR DARWIN) + set(HUNSPELL_LIBRARY libhunspell) + endif (LINUX OR DARWIN) + set(HUNSPELL_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/hunspell) + use_prebuilt_binary(dictionaries) endif (STANDALONE) diff --git a/indra/cmake/JPEG.cmake b/indra/cmake/JPEG.cmake index 5c55aedbbc..fd04fcce1b 100644 --- a/indra/cmake/JPEG.cmake +++ b/indra/cmake/JPEG.cmake @@ -13,11 +13,11 @@ else (STANDALONE) set(JPEG_LIBRARIES jpeg) elseif (DARWIN) set(JPEG_LIBRARIES - optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libjpeg.a - debug ${ARCH_PREBUILT_DIRS_DEBUG}/libjpeg.a + debug libjpeg.a + optimized libjpeg.a ) elseif (WINDOWS) set(JPEG_LIBRARIES jpeglib) endif (LINUX) - set(JPEG_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include) + set(JPEG_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include) endif (STANDALONE) diff --git a/indra/cmake/Json.cmake b/indra/cmake/Json.cmake new file mode 100644 index 0000000000..5c98370476 --- /dev/null +++ b/indra/cmake/Json.cmake @@ -0,0 +1,6 @@ +# -*- cmake -*- + +include(Prebuilt) + +use_prebuilt_binary(modernjson) +set(JSON_INCLUDE_DIR "${LIBS_PREBUILT_DIR}/include") diff --git a/indra/cmake/JsonCpp.cmake b/indra/cmake/JsonCpp.cmake deleted file mode 100644 index 4990898431..0000000000 --- a/indra/cmake/JsonCpp.cmake +++ /dev/null @@ -1,22 +0,0 @@ -# -*- cmake -*- - -include(Prebuilt) - -set(JSONCPP_FIND_QUIETLY OFF) -set(JSONCPP_FIND_REQUIRED ON) - -if (STANDALONE) - include(FindJsonCpp) -else (STANDALONE) - use_prebuilt_binary(jsoncpp) - if (WINDOWS) - set(JSONCPP_LIBRARIES - debug json_vc${MSVC_SUFFIX}d - optimized json_vc${MSVC_SUFFIX}) - elseif (DARWIN) - set(JSONCPP_LIBRARIES json_linux-gcc-4.0.1_libmt) - elseif (LINUX) - set(JSONCPP_LIBRARIES jsoncpp) - endif (WINDOWS) - set(JSONCPP_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/jsoncpp) -endif (STANDALONE) diff --git a/indra/cmake/LLAddBuildTest.cmake b/indra/cmake/LLAddBuildTest.cmake index 74f2e0cb18..7875e5bfc9 100644 --- a/indra/cmake/LLAddBuildTest.cmake +++ b/indra/cmake/LLAddBuildTest.cmake @@ -87,7 +87,7 @@ MACRO(ADD_BUILD_TEST_INTERNAL name parent libraries source_files) ${libraries} ) - GET_TARGET_PROPERTY(TEST_EXE ${name}_test LOCATION) + SET(TEST_EXE $) SET(TEST_OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${name}_test_ok.txt) IF ("${wrapper}" STREQUAL "") @@ -105,17 +105,6 @@ MACRO(ADD_BUILD_TEST_INTERNAL name parent libraries source_files) IF (NOT "$ENV{LD_LIBRARY_PATH}" STREQUAL "") SET(LD_LIBRARY_PATH "$ENV{LD_LIBRARY_PATH}:${LD_LIBRARY_PATH}") ENDIF (NOT "$ENV{LD_LIBRARY_PATH}" STREQUAL "") - ADD_CUSTOM_COMMAND( - OUTPUT ${TEST_OUTPUT} - COMMAND - ${CMAKE_COMMAND} - "-DLD_LIBRARY_PATH=${LD_LIBRARY_PATH}" - "-DTEST_CMD:STRING=${TEST_CMD}" - -P ${CMAKE_SOURCE_DIR}/cmake/RunBuildTest.cmake - DEPENDS ${name}_test - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - VERBATIM - ) ADD_CUSTOM_TARGET(${name}_test_ok ALL DEPENDS ${TEST_OUTPUT}) IF (${parent}) @@ -159,3 +148,23 @@ MACRO(ADD_VIEWER_COMM_BUILD_TEST name parent wrapper) ## MESSAGE(STATUS "ADD_VIEWER_COMM_BUILD_TEST ${name} wrapper = ${wrapper}") ADD_COMM_BUILD_TEST("${name}" "${parent}" "${wrapper}" llviewerprecompiledheaders.cpp) ENDMACRO(ADD_VIEWER_COMM_BUILD_TEST name parent wrapper) +MACRO(SET_TEST_PATH LISTVAR) + IF(WINDOWS) + # We typically build/package only Release variants of third-party + # libraries, so append the Release staging dir in case the library being + # sought doesn't have a debug variant. + set(${LISTVAR} ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR} ${SHARED_LIB_STAGING_DIR}/Release) + ELSEIF(DARWIN) + # We typically build/package only Release variants of third-party + # libraries, so append the Release staging dir in case the library being + # sought doesn't have a debug variant. + set(${LISTVAR} ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/Resources ${SHARED_LIB_STAGING_DIR}/Release/Resources /usr/lib) + ELSE(WINDOWS) + # Linux uses a single staging directory anyway. + IF (STANDALONE) + set(${LISTVAR} ${CMAKE_BINARY_DIR}/llcommon /usr/lib /usr/local/lib) + ELSE (STANDALONE) + set(${LISTVAR} ${SHARED_LIB_STAGING_DIR} /usr/lib) + ENDIF (STANDALONE) + ENDIF(WINDOWS) +ENDMACRO(SET_TEST_PATH) diff --git a/indra/cmake/LLAudio.cmake b/indra/cmake/LLAudio.cmake index 4400329678..3cd2b98d1c 100644 --- a/indra/cmake/LLAudio.cmake +++ b/indra/cmake/LLAudio.cmake @@ -1,11 +1,12 @@ # -*- cmake -*- include(Audio) +include(OPENAL) set(LLAUDIO_INCLUDE_DIRS ${LIBS_OPEN_DIR}/llaudio ) -add_definitions(-DOV_EXCLUDE_STATIC_CALLBACKS) +#add_definitions(-DOV_EXCLUDE_STATIC_CALLBACKS) set(LLAUDIO_LIBRARIES llaudio ${OPENAL_LIBRARIES}) diff --git a/indra/cmake/LLCommon.cmake b/indra/cmake/LLCommon.cmake index b1bb1b6a98..5f87e1e797 100644 --- a/indra/cmake/LLCommon.cmake +++ b/indra/cmake/LLCommon.cmake @@ -3,6 +3,7 @@ include(APR) include(Boost) include(EXPAT) +include(Linking) include(ZLIB) if (DARWIN) @@ -10,7 +11,6 @@ if (DARWIN) find_library(CORESERVICES_LIBRARY CoreServices) endif (DARWIN) - set(LLCOMMON_INCLUDE_DIRS ${LIBS_OPEN_DIR}/cwdebug ${LIBS_OPEN_DIR}/llcommon @@ -19,16 +19,11 @@ set(LLCOMMON_INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ) -if (LINUX) - # In order to support using ld.gold on linux, we need to explicitely - # specify all libraries that llcommon uses. - # llcommon uses `clock_gettime' which is provided by librt on linux. - set(LLCOMMON_LIBRARIES llcommon rt) -else (LINUX) - set(LLCOMMON_LIBRARIES llcommon) -endif (LINUX) +set(LLCOMMON_LIBRARIES llcommon + fmt::fmt + ) -set(LLCOMMON_LINK_SHARED ON CACHE BOOL "Build the llcommon target as a shared library.") +set(LLCOMMON_LINK_SHARED OFF CACHE BOOL "Build the llcommon target as a shared library.") if(LLCOMMON_LINK_SHARED) add_definitions(-DLL_COMMON_LINK_SHARED=1) endif(LLCOMMON_LINK_SHARED) diff --git a/indra/cmake/LLCrashLogger.cmake b/indra/cmake/LLCrashLogger.cmake deleted file mode 100644 index f2cb83eb8b..0000000000 --- a/indra/cmake/LLCrashLogger.cmake +++ /dev/null @@ -1,7 +0,0 @@ -# -*- cmake -*- - -set(LLCRASHLOGGER_INCLUDE_DIRS - ${LIBS_OPEN_DIR}/llcrashlogger - ) - -set(LLCRASHLOGGER_LIBRARIES llcrashlogger) diff --git a/indra/cmake/LLPlugin.cmake b/indra/cmake/LLPlugin.cmake index 399cb332dd..9722f16c3c 100644 --- a/indra/cmake/LLPlugin.cmake +++ b/indra/cmake/LLPlugin.cmake @@ -5,10 +5,4 @@ set(LLPLUGIN_INCLUDE_DIRS ${LIBS_OPEN_DIR}/llplugin ) -if (LINUX) - # In order to support using ld.gold on linux, we need to explicitely - # specify all libraries that llplugin uses. - set(LLPLUGIN_LIBRARIES llplugin pthread) -else (LINUX) - set(LLPLUGIN_LIBRARIES llplugin) -endif (LINUX) +set(LLPLUGIN_LIBRARIES llplugin) diff --git a/indra/cmake/LLPrimitive.cmake b/indra/cmake/LLPrimitive.cmake index dd1d806d5e..ee465dc8bd 100644 --- a/indra/cmake/LLPrimitive.cmake +++ b/indra/cmake/LLPrimitive.cmake @@ -1,22 +1,32 @@ # -*- cmake -*- +# these should be moved to their own cmake file +include(Prebuilt) +include(Boost) include(Colladadom) + +use_prebuilt_binary(libxml2) + set(LLPRIMITIVE_INCLUDE_DIRS ${LIBS_OPEN_DIR}/llprimitive ${COLLADADOM_INCLUDE_DIRS} ) if (WINDOWS) - set(LLPRIMITIVE_LIBRARIES - debug llprimitive - optimized llprimitive - ${COLLADADOM_LIBRARIES} - ) + set(LLPRIMITIVE_LIBRARIES + llprimitive + ${COLLADADOM_LIBRARIES} + libxml2_a + ${BOOST_SYSTEM_LIBRARIES} + ) else (WINDOWS) - set(LLPRIMITIVE_LIBRARIES - llprimitive - ${COLLADADOM_LIBRARIES} - ) + set(LLPRIMITIVE_LIBRARIES + llprimitive + ${COLLADADOM_LIBRARIES} + ${BOOST_SYSTEM_LIBRARIES} + minizip + xml2 + ) endif (WINDOWS) diff --git a/indra/cmake/LLQtWebkit.cmake b/indra/cmake/LLQtWebkit.cmake deleted file mode 100644 index cec7e22e9d..0000000000 --- a/indra/cmake/LLQtWebkit.cmake +++ /dev/null @@ -1,11 +0,0 @@ -# -*- cmake -*- - -if (STANDALONE) - set(LLQTWEBKIT_INCLUDE_DIR - ${LIBS_OPEN_DIR}/llqtwebkit - ) - - set(LLQTWEBKIT_LIBRARY - llqtwebkit - ) -endif (STANDALONE) diff --git a/indra/cmake/LLSharedLibs.cmake b/indra/cmake/LLSharedLibs.cmake new file mode 100644 index 0000000000..f69b45cd92 --- /dev/null +++ b/indra/cmake/LLSharedLibs.cmake @@ -0,0 +1,76 @@ +# ll_deploy_sharedlibs_command +# target_exe: the cmake target of the executable for which the shared libs will be deployed. +macro(ll_deploy_sharedlibs_command target_exe) + set(TARGET_LOCATION $) + get_filename_component(OUTPUT_PATH ${TARGET_LOCATION} PATH) + + # It's not clear that this does anything useful for us on Darwin. It has + # been broken for some time now; the BIN_NAME was being constructed as a + # ridiculous nonexistent path with duplicated segments. Fixing that only + # produces ominous spammy warnings: at the time the command below is run, we + # have not yet populated the nested mac-crash-logger.app/Contents/Resources + # with the .dylibs with which it was linked. Moreover, the form of the + # embedded @executable_path/../Resources/mumble.dylib pathname confuses the + # GetPrerequisites.cmake tool invoked by DeploySharedLibs.cmake. It seems + # clear that we have long since accomplished by other means what this was + # originally supposed to do. Skipping it only eliminates an annoying + # non-fatal error. + if(NOT DARWIN) + if(WINDOWS) + SET_TEST_PATH(SEARCH_DIRS) + LIST(APPEND SEARCH_DIRS "$ENV{SystemRoot}/system32") + elseif(LINUX) + SET_TEST_PATH(SEARCH_DIRS) + set(OUTPUT_PATH ${OUTPUT_PATH}/lib) + endif(WINDOWS) + + add_custom_command( + TARGET ${target_exe} POST_BUILD + COMMAND ${CMAKE_COMMAND} + ARGS + "-DBIN_NAME=\"${TARGET_LOCATION}\"" + "-DSEARCH_DIRS=\"${SEARCH_DIRS}\"" + "-DDST_PATH=\"${OUTPUT_PATH}\"" + "-P" + "${CMAKE_SOURCE_DIR}/cmake/DeploySharedLibs.cmake" + ) + endif(NOT DARWIN) + +endmacro(ll_deploy_sharedlibs_command) + +# ll_stage_sharedlib +# Performs config and adds a copy command for a sharedlib target. +macro(ll_stage_sharedlib DSO_TARGET) + # target gets written to the DLL staging directory. + # Also this directory is shared with RunBuildTest.cmake, y'know, for the tests. + set_target_properties(${DSO_TARGET} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${SHARED_LIB_STAGING_DIR}) + if(NOT WINDOWS) + get_target_property(DSO_PATH ${DSO_TARGET} LOCATION) + get_filename_component(DSO_FILE ${DSO_PATH} NAME) + if(DARWIN) + set(SHARED_LIB_STAGING_DIR_CONFIG ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/Resources) + else(DARWIN) + set(SHARED_LIB_STAGING_DIR_CONFIG ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}) + endif(DARWIN) + + # *TODO - maybe make this a symbolic link? -brad + add_custom_command( + TARGET ${DSO_TARGET} POST_BUILD + COMMAND ${CMAKE_COMMAND} + ARGS + -E + copy_if_different + ${DSO_PATH} + ${SHARED_LIB_STAGING_DIR_CONFIG}/${DSO_FILE} + COMMENT "Copying llcommon to the staging folder." + ) + endif(NOT WINDOWS) + + if (DARWIN) + set_target_properties(${DSO_TARGET} PROPERTIES + BUILD_WITH_INSTALL_RPATH 1 + INSTALL_NAME_DIR "@executable_path/../Resources" + ) + endif(DARWIN) + +endmacro(ll_stage_sharedlib) diff --git a/indra/cmake/LLWindow.cmake b/indra/cmake/LLWindow.cmake index a46d9c5922..2d78cd76a5 100644 --- a/indra/cmake/LLWindow.cmake +++ b/indra/cmake/LLWindow.cmake @@ -1,9 +1,8 @@ # -*- cmake -*- include(OpenGL) -include(Prebuilt) -if (STANDALONE) +if (LINUX) include(FindSDL) # This should be done by FindSDL. Sigh. @@ -12,19 +11,7 @@ if (STANDALONE) SDL_INCLUDE_DIR SDL_LIBRARY ) -else (STANDALONE) - if (LINUX) - use_prebuilt_binary(mesa) - use_prebuilt_binary(SDL) - set (SDL_FOUND TRUE) - set (SDL_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}) - if(WORD_SIZE EQUAL 64) - set (SDL_LIBRARY SDL) - else(WORD_SIZE EQUAL 64) - set (SDL_LIBRARY SDL directfb fusion direct) - endif(WORD_SIZE EQUAL 64) - endif (LINUX) -endif (STANDALONE) +endif (LINUX) if (SDL_FOUND) add_definitions(-DLL_SDL=1) diff --git a/indra/cmake/LibVLCPlugin.cmake b/indra/cmake/LibVLCPlugin.cmake new file mode 100644 index 0000000000..0787edd2c9 --- /dev/null +++ b/indra/cmake/LibVLCPlugin.cmake @@ -0,0 +1,30 @@ +# -*- cmake -*- +include(Linking) +include(Prebuilt) +include(Variables) + +if (LIBVLCPLUGIN) +if (USESYSTEMLIBS) +else (USESYSTEMLIBS) + use_prebuilt_binary(vlc-bin) + set(VLC_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/vlc) +endif (USESYSTEMLIBS) + +if (WINDOWS) + set(VLC_PLUGIN_LIBRARIES + libvlc.lib + libvlccore.lib + ) +elseif (DARWIN) + set(VLC_PLUGIN_LIBRARIES + libvlc.dylib + libvlccore.dylib + ) +elseif (LINUX) + # Specify a full path to make sure we get a static link + set(VLC_PLUGIN_LIBRARIES + ${LIBS_PREBUILT_DIR}/lib/libvlc.a + ${LIBS_PREBUILT_DIR}/lib/libvlccore.a + ) +endif (WINDOWS) +endif (LIBVLCPLUGIN) diff --git a/indra/cmake/Linking.cmake b/indra/cmake/Linking.cmake index 00754ec368..22e49fd0ba 100644 --- a/indra/cmake/Linking.cmake +++ b/indra/cmake/Linking.cmake @@ -1,32 +1,58 @@ # -*- cmake -*- + if(NOT DEFINED ${CMAKE_CURRENT_LIST_FILE}_INCLUDED) set(${CMAKE_CURRENT_LIST_FILE}_INCLUDED "YES") include(Variables) -if (NOT STANDALONE) - if (WINDOWS) - set(ARCH_PREBUILT_DIRS ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/lib) - set(ARCH_PREBUILT_DIRS_RELEASE ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/lib/release) - set(ARCH_PREBUILT_DIRS_DEBUG ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/lib/debug) - elseif (LINUX) - set(ARCH_PREBUILT_DIRS ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/lib/release) - set(ARCH_PREBUILT_DIRS_RELEASE ${ARCH_PREBUILT_DIRS}) - set(ARCH_PREBUILT_DIRS_DEBUG ${ARCH_PREBUILT_DIRS}) - elseif (DARWIN) - set(ARCH_PREBUILT_DIRS ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/lib) - set(ARCH_PREBUILT_DIRS_RELEASE ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/lib/release) - set(ARCH_PREBUILT_DIRS_DEBUG ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/lib/debug) - endif (WINDOWS) -endif (NOT STANDALONE) - -link_directories(${ARCH_PREBUILT_DIRS}) +set(ARCH_PREBUILT_DIRS ${AUTOBUILD_INSTALL_DIR}/lib) +set(ARCH_PREBUILT_DIRS_PLUGINS ${AUTOBUILD_INSTALL_DIR}/plugins) +set(ARCH_PREBUILT_DIRS_RELEASE ${AUTOBUILD_INSTALL_DIR}/lib/release) +set(ARCH_PREBUILT_DIRS_DEBUG ${AUTOBUILD_INSTALL_DIR}/lib/debug) +if (WINDOWS) + set(SHARED_LIB_STAGING_DIR ${CMAKE_BINARY_DIR}/sharedlibs) + set(EXE_STAGING_DIR ${CMAKE_BINARY_DIR}/sharedlibs) +elseif (LINUX) + set(SHARED_LIB_STAGING_DIR ${CMAKE_BINARY_DIR}/sharedlibs/lib) + set(EXE_STAGING_DIR ${CMAKE_BINARY_DIR}/sharedlibs/bin) +elseif (DARWIN) + set(SHARED_LIB_STAGING_DIR ${CMAKE_BINARY_DIR}/sharedlibs) + set(EXE_STAGING_DIR "${CMAKE_BINARY_DIR}/sharedlibs") +endif (WINDOWS) + +# Autobuild packages must provide 'release' versions of libraries, but may provide versions for +# specific build types. AUTOBUILD_LIBS_INSTALL_DIRS lists first the build type directory and then +# the 'release' directory (as a default fallback). +# *NOTE - we have to take special care to use CMAKE_CFG_INTDIR on IDE generators (like mac and +# windows) and CMAKE_BUILD_TYPE on Makefile based generators (like linux). The reason for this is +# that CMAKE_BUILD_TYPE is essentially meaningless at configuration time for IDE generators and +# CMAKE_CFG_INTDIR is meaningless at build time for Makefile generators +if(GEN_IS_MULTI_CONFIG) + # the cmake xcode and VS generators implicitly append ${CMAKE_CFG_INTDIR} to the library paths for us + # fortunately both windows and darwin are case insensitive filesystems so this works. + set(AUTOBUILD_LIBS_INSTALL_DIRS "${AUTOBUILD_INSTALL_DIR}/lib/") +else() + # else block is for linux and any other makefile based generators + string(TOLOWER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE_LOWER) + set(AUTOBUILD_LIBS_INSTALL_DIRS ${AUTOBUILD_INSTALL_DIR}/lib/${CMAKE_BUILD_TYPE_LOWER}) +endif() + +if (NOT "${CMAKE_BUILD_TYPE}" STREQUAL "Release") + # When we're building something other than Release, append the + # packages/lib/release directory to deal with autobuild packages that don't + # provide (e.g.) lib/debug libraries. + list(APPEND AUTOBUILD_LIBS_INSTALL_DIRS ${ARCH_PREBUILT_DIRS_RELEASE}) +endif (NOT "${CMAKE_BUILD_TYPE}" STREQUAL "Release") + +link_directories(${AUTOBUILD_LIBS_INSTALL_DIRS}) if (LINUX) set(DL_LIBRARY dl) + set(RT_LIBRARY rt) set(PTHREAD_LIBRARY pthread) else (LINUX) set(DL_LIBRARY "") + set(RT_LIBRARY "") set(PTHREAD_LIBRARY "") endif (LINUX) @@ -34,6 +60,7 @@ if (WINDOWS) set(WINDOWS_LIBRARIES advapi32 shell32 + ole32 ws2_32 mswsock psapi @@ -48,6 +75,6 @@ else (WINDOWS) set(WINDOWS_LIBRARIES "") endif (WINDOWS) -mark_as_advanced(DL_LIBRARY PTHREAD_LIBRARY WINDOWS_LIBRARIES) +mark_as_advanced(DL_LIBRARY RT_LIBRARY PTHREAD_LIBRARY WINDOWS_LIBRARIES) endif(NOT DEFINED ${CMAKE_CURRENT_LIST_FILE}_INCLUDED) diff --git a/indra/cmake/NDOF.cmake b/indra/cmake/NDOF.cmake index a4e2104054..20c1e97873 100644 --- a/indra/cmake/NDOF.cmake +++ b/indra/cmake/NDOF.cmake @@ -7,7 +7,11 @@ if (STANDALONE) message(STATUS "Building without N-DoF joystick support") endif(NOT NDOF_FOUND) else (STANDALONE) - use_prebuilt_binary(ndofdev) + if (WINDOWS OR DARWIN) + use_prebuilt_binary(libndofdev) + elseif (LINUX) + use_prebuilt_binary(libndofdev-open) + endif (WINDOWS OR DARWIN) if (WINDOWS) set(NDOF_LIBRARY libndofdev) @@ -15,7 +19,11 @@ else (STANDALONE) set(NDOF_LIBRARY ndofdev) endif (WINDOWS) - set(NDOF_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/ndofdev) + if (WINDOWS) + set(NDOF_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include) + else (WINDOWS) + set(NDOF_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/ndofdev) + endif (WINDOWS) set(NDOF_FOUND 1) endif (STANDALONE) @@ -23,6 +31,8 @@ if (NDOF_FOUND) add_definitions(-DLIB_NDOF=1) include_directories(${NDOF_INCLUDE_DIR}) else (NDOF_FOUND) + message(STATUS "Building without N-DoF joystick support") set(NDOF_INCLUDE_DIR "") set(NDOF_LIBRARY "") endif (NDOF_FOUND) + diff --git a/indra/cmake/NVAPI.cmake b/indra/cmake/NVAPI.cmake new file mode 100644 index 0000000000..3cdf5ca474 --- /dev/null +++ b/indra/cmake/NVAPI.cmake @@ -0,0 +1,19 @@ +# -*- cmake -*- +include(Prebuilt) +include(Variables) + +if (USE_NVAPI) + if (WINDOWS) + use_prebuilt_binary(nvapi) + if (ADDRESS_SIZE EQUAL 32) + set(NVAPI_LIBRARY nvapi) + elseif (ADDRESS_SIZE EQUAL 64) + set(NVAPI_LIBRARY nvapi64) + endif (ADDRESS_SIZE EQUAL 32) + else (WINDOWS) + set(NVAPI_LIBRARY "") + endif (WINDOWS) +else (USE_NVAPI) + set(NVAPI_LIBRARY "") +endif (USE_NVAPI) + diff --git a/indra/cmake/OPENAL.cmake b/indra/cmake/OPENAL.cmake index d5ab802d98..c25eb929ea 100644 --- a/indra/cmake/OPENAL.cmake +++ b/indra/cmake/OPENAL.cmake @@ -9,21 +9,25 @@ else (LINUX) endif (LINUX) if (OPENAL) + set(OPENAL_LIB_INCLUDE_DIRS "${LIBS_PREBUILT_DIR}/include/AL") if (STANDALONE) include(FindPkgConfig) include(FindOpenAL) pkg_check_modules(OPENAL_LIB REQUIRED openal) pkg_check_modules(FREEALUT_LIB REQUIRED freealut) else (STANDALONE) - use_prebuilt_binary(openal-soft) + use_prebuilt_binary(openal) endif (STANDALONE) + if(WINDOWS) set(OPENAL_LIBRARIES - openal + OpenAL32 alut ) - set(OPENAL_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include) -endif (OPENAL) - -if (OPENAL) + else() + set(OPENAL_LIBRARIES + openal + alut + ) + endif() message(STATUS "Building with OpenAL audio support") endif (OPENAL) diff --git a/indra/cmake/OpenGL.cmake b/indra/cmake/OpenGL.cmake index 0bfc1a3598..c77295f630 100644 --- a/indra/cmake/OpenGL.cmake +++ b/indra/cmake/OpenGL.cmake @@ -1,7 +1,14 @@ # -*- cmake -*- + +include(Variables) include(Prebuilt) if (NOT (STANDALONE OR DARWIN)) use_prebuilt_binary(glext) - set(GLEXT_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include) + set(GLEXT_INCLUDE_DIR + ${LIBS_PREBUILT_DIR}/include + ${LIBS_PREBUILT_LEGACY_DIR}/include + ) endif (NOT (STANDALONE OR DARWIN)) + +include(FindOpenGL) diff --git a/indra/cmake/OpenSSL.cmake b/indra/cmake/OpenSSL.cmake index fffe868fdb..8456fc1d72 100644 --- a/indra/cmake/OpenSSL.cmake +++ b/indra/cmake/OpenSSL.cmake @@ -7,15 +7,17 @@ set(OpenSSL_FIND_REQUIRED ON) if (STANDALONE OR USE_SYSTEM_OPENSSL) include(FindOpenSSL) else (STANDALONE OR USE_SYSTEM_OPENSSL) - use_prebuilt_binary(openSSL) + use_prebuilt_binary(openssl) if (WINDOWS) - set(OPENSSL_LIBRARIES ssleay32 libeay32) + set(OPENSSL_LIBRARIES libssl libcrypto) else (WINDOWS) set(OPENSSL_LIBRARIES ssl) endif (WINDOWS) - set(OPENSSL_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include) + set(OPENSSL_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include) endif (STANDALONE OR USE_SYSTEM_OPENSSL) -if (LINUX OR DARWIN) +if (LINUX) + set(CRYPTO_LIBRARIES crypto dl) +elseif (DARWIN) set(CRYPTO_LIBRARIES crypto) -endif (LINUX OR DARWIN) +endif (LINUX) diff --git a/indra/cmake/PNG.cmake b/indra/cmake/PNG.cmake index 011b87f640..3d02a5e4f3 100644 --- a/indra/cmake/PNG.cmake +++ b/indra/cmake/PNG.cmake @@ -9,11 +9,28 @@ if (STANDALONE) else (STANDALONE) use_prebuilt_binary(libpng) if (WINDOWS) - set(PNG_LIBRARIES libpng15) + set(PNG_LIBRARIES libpng16) elseif(DARWIN) set(PNG_LIBRARIES png15) else(LINUX) - set(PNG_LIBRARIES png15) + if (CMAKE_SIZEOF_VOID_P EQUAL 4) # Singu TODO: update png + set(PNG_LIBRARIES png15) + else () + # + # When we have updated static libraries in competition with older + # shared libraries and we want the former to win, we need to do some + # extra work. The *_PRELOAD_ARCHIVES settings are invoked early + # and will pull in the entire archive to the binary giving it + # priority in symbol resolution. Beware of cmake moving the + # achive load itself to another place on the link command line. If + # that happens, you can try something like -Wl,-lpng16 here to hide + # the archive. Also be aware that the linker will not tolerate a + # second whole-archive load of the archive. See viewer's + # CMakeLists.txt for more information. + # + set(PNG_PRELOAD_ARCHIVES -Wl,--whole-archive png16 -Wl,--no-whole-archive) + set(PNG_LIBRARIES png16) + endif () endif() - set(PNG_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/) + set(PNG_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include/libpng16) endif (STANDALONE) diff --git a/indra/cmake/Prebuilt.cmake b/indra/cmake/Prebuilt.cmake index 2295a75745..33a6d76916 100644 --- a/indra/cmake/Prebuilt.cmake +++ b/indra/cmake/Prebuilt.cmake @@ -3,14 +3,62 @@ if(NOT DEFINED ${CMAKE_CURRENT_LIST_FILE}_INCLUDED) set(${CMAKE_CURRENT_LIST_FILE}_INCLUDED "YES") +include(FindAutobuild) +if(INSTALL_PROPRIETARY) + include(FindSCP) +endif(INSTALL_PROPRIETARY) + +set(PREBUILD_TRACKING_DIR ${AUTOBUILD_INSTALL_DIR}/cmake_tracking) +# For the library installation process; +# see cmake/Prebuild.cmake for the counterpart code. +if ("${CMAKE_SOURCE_DIR}/../autobuild.xml" IS_NEWER_THAN "${PREBUILD_TRACKING_DIR}/sentinel_installed") + file(MAKE_DIRECTORY ${PREBUILD_TRACKING_DIR}) + file(WRITE ${PREBUILD_TRACKING_DIR}/sentinel_installed "0") +endif ("${CMAKE_SOURCE_DIR}/../autobuild.xml" IS_NEWER_THAN "${PREBUILD_TRACKING_DIR}/sentinel_installed") + +# The use_prebuilt_binary macro handles automated installation of package +# dependencies using autobuild. The goal is that 'autobuild install' should +# only be run when we know we need to install a new package. This should be +# the case in a clean checkout, or if autobuild.xml has been updated since the +# last run (encapsulated by the file ${PREBUILD_TRACKING_DIR}/sentinel_installed), +# or if a previous attempt to install the package has failed (the exit status +# of previous attempts is serialized in the file +# ${PREBUILD_TRACKING_DIR}/${_binary}_installed) macro (use_prebuilt_binary _binary) - if(NOT STANDALONE) - get_property(PREBUILT_PACKAGES TARGET prepare PROPERTY PREBUILT) - list(FIND PREBUILT_PACKAGES ${_binary} _index) - if(_index LESS 0) - set_property(TARGET prepare APPEND PROPERTY PREBUILT ${_binary}) - endif(_index LESS 0) - endif(NOT STANDALONE) + if (NOT DEFINED USESYSTEMLIBS_${_binary}) + set(USESYSTEMLIBS_${_binary} ${USESYSTEMLIBS}) + endif (NOT DEFINED USESYSTEMLIBS_${_binary}) + + if (NOT USESYSTEMLIBS_${_binary}) + if("${${_binary}_installed}" STREQUAL "" AND EXISTS "${PREBUILD_TRACKING_DIR}/${_binary}_installed") + file(READ ${PREBUILD_TRACKING_DIR}/${_binary}_installed "${_binary}_installed") + if(DEBUG_PREBUILT) + message(STATUS "${_binary}_installed: \"${${_binary}_installed}\"") + endif(DEBUG_PREBUILT) + endif("${${_binary}_installed}" STREQUAL "" AND EXISTS "${PREBUILD_TRACKING_DIR}/${_binary}_installed") + + if(${PREBUILD_TRACKING_DIR}/sentinel_installed IS_NEWER_THAN ${PREBUILD_TRACKING_DIR}/${_binary}_installed OR NOT ${${_binary}_installed} EQUAL 0) + if(DEBUG_PREBUILT) + message(STATUS "cd ${CMAKE_SOURCE_DIR} && ${AUTOBUILD_EXECUTABLE} install + --install-dir=${AUTOBUILD_INSTALL_DIR} + ${_binary} ") + endif(DEBUG_PREBUILT) + execute_process(COMMAND "${AUTOBUILD_EXECUTABLE}" + install + --install-dir=${AUTOBUILD_INSTALL_DIR} + ${_binary} + WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" + RESULT_VARIABLE ${_binary}_installed + ) + file(WRITE ${PREBUILD_TRACKING_DIR}/${_binary}_installed "${${_binary}_installed}") + endif(${PREBUILD_TRACKING_DIR}/sentinel_installed IS_NEWER_THAN ${PREBUILD_TRACKING_DIR}/${_binary}_installed OR NOT ${${_binary}_installed} EQUAL 0) + + if(NOT ${_binary}_installed EQUAL 0) + message(FATAL_ERROR + "Failed to download or unpack prebuilt '${_binary}'." + " Process returned ${${_binary}_installed}.") + endif (NOT ${_binary}_installed EQUAL 0) + endif (NOT USESYSTEMLIBS_${_binary}) endmacro (use_prebuilt_binary _binary) endif(NOT DEFINED ${CMAKE_CURRENT_LIST_FILE}_INCLUDED) diff --git a/indra/cmake/PulseAudio.cmake b/indra/cmake/PulseAudio.cmake index dafdd41634..360a971058 100644 --- a/indra/cmake/PulseAudio.cmake +++ b/indra/cmake/PulseAudio.cmake @@ -1,7 +1,7 @@ # -*- cmake -*- include(Prebuilt) -set(PULSEAUDIO ON CACHE BOOL "Build with PulseAudio support, if available.") +set(PULSEAUDIO OFF CACHE BOOL "Build with PulseAudio support, if available.") if (PULSEAUDIO) if (STANDALONE) @@ -13,7 +13,7 @@ if (PULSEAUDIO) use_prebuilt_binary(pulseaudio) set(PULSEAUDIO_FOUND ON FORCE BOOL) set(PULSEAUDIO_INCLUDE_DIRS - ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include + ${LIBS_PREBUILT_DIR}/include ) # We don't need to explicitly link against pulseaudio itself, because # the viewer probes for the system's copy at runtime. diff --git a/indra/cmake/Python.cmake b/indra/cmake/Python.cmake index 83a0690c64..9f24361f4b 100644 --- a/indra/cmake/Python.cmake +++ b/indra/cmake/Python.cmake @@ -5,25 +5,33 @@ set(PYTHONINTERP_FOUND) if (WINDOWS) # On Windows, explicitly avoid Cygwin Python. - find_program(PYTHON_EXECUTABLE - NAMES python25.exe python23.exe python.exe - NO_DEFAULT_PATH # added so that cmake does not find cygwin python - PATHS - [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.7\\InstallPath] - [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.6\\InstallPath] - [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.5\\InstallPath] - [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.4\\InstallPath] - [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.3\\InstallPath] - [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\2.7\\InstallPath] - [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\2.6\\InstallPath] - [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\2.5\\InstallPath] - [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\2.4\\InstallPath] - [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\2.3\\InstallPath] - ) - + if (DEFINED ENV{VIRTUAL_ENV}) + find_program(PYTHON_EXECUTABLE + NAMES python.exe + PATHS + "$ENV{VIRTUAL_ENV}\\scripts" + NO_DEFAULT_PATH + ) + else() + find_program(PYTHON_EXECUTABLE + NAMES python25.exe python23.exe python.exe + NO_DEFAULT_PATH # added so that cmake does not find cygwin python + PATHS + [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.7\\InstallPath] + [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.6\\InstallPath] + [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.5\\InstallPath] + [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.4\\InstallPath] + [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\2.3\\InstallPath] + [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\2.7\\InstallPath] + [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\2.6\\InstallPath] + [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\2.5\\InstallPath] + [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\2.4\\InstallPath] + [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\2.3\\InstallPath] + ) + endif() -elseif (EXISTS /etc/arch-release) - # On Archlinux, use Python 2 +elseif (EXISTS /usr/bin/python2) + # if this is there, use it find_program(PYTHON_EXECUTABLE python2 PATHS /usr/bin) diff --git a/indra/cmake/Qt4.cmake b/indra/cmake/Qt4.cmake deleted file mode 100644 index 37d2799a21..0000000000 --- a/indra/cmake/Qt4.cmake +++ /dev/null @@ -1,12 +0,0 @@ -# -*- cmake -*- -include(Prebuilt) - -if (STANDALONE) - set(Qt4_FIND_REQUIRED ON) - - include(FindQt4) - - find_package(Qt4 4.7.0 COMPONENTS QtCore QtGui QtNetwork QtOpenGL QtWebKit REQUIRED) - include(${QT_USE_FILE}) - add_definitions(${QT_DEFINITIONS}) -endif (STANDALONE) diff --git a/indra/cmake/QuickTimePlugin.cmake b/indra/cmake/QuickTimePlugin.cmake deleted file mode 100644 index 8afd8f304c..0000000000 --- a/indra/cmake/QuickTimePlugin.cmake +++ /dev/null @@ -1,46 +0,0 @@ -# -*- cmake -*- - -if(INSTALL_PROPRIETARY) - include(Prebuilt) - use_prebuilt_binary(quicktime) -endif(INSTALL_PROPRIETARY) - -if (DARWIN) - include(CMakeFindFrameworks) - find_library(QUICKTIME_LIBRARY QuickTime) -elseif (WINDOWS) - set(QUICKTIME_SDK_DIR "$ENV{PROGRAMFILES}/QuickTime SDK" - CACHE PATH "Location of the QuickTime SDK.") - - find_library(DEBUG_QUICKTIME_LIBRARY qtmlclient - PATHS - ${ARCH_PREBUILT_DIRS_DEBUG} - "${QUICKTIME_SDK_DIR}\\libraries" - ) - - find_library(RELEASE_QUICKTIME_LIBRARY qtmlclient - PATHS - ${ARCH_PREBUILT_DIRS_RELEASE} - "${QUICKTIME_SDK_DIR}\\libraries" - ) - - if (DEBUG_QUICKTIME_LIBRARY AND RELEASE_QUICKTIME_LIBRARY) - set(QUICKTIME_LIBRARY - optimized ${RELEASE_QUICKTIME_LIBRARY} - debug ${DEBUG_QUICKTIME_LIBRARY} - ) - - endif (DEBUG_QUICKTIME_LIBRARY AND RELEASE_QUICKTIME_LIBRARY) - - include_directories( - ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/quicktime - "${QUICKTIME_SDK_DIR}\\CIncludes" - ) -endif (DARWIN) - -mark_as_advanced(QUICKTIME_LIBRARY) - -if (QUICKTIME_LIBRARY) - set(QUICKTIME ON CACHE BOOL "Build with QuickTime streaming media support.") -endif (QUICKTIME_LIBRARY) - diff --git a/indra/cmake/RunBuildTest.cmake b/indra/cmake/RunBuildTest.cmake deleted file mode 100644 index dc6c942b78..0000000000 --- a/indra/cmake/RunBuildTest.cmake +++ /dev/null @@ -1,20 +0,0 @@ -#This cmake script is meant to be run as a build time custom command. -#The script is run using cmake w/ the -P option. -# parameters are passed to this scripts execution with the -D option. -# A full command line would look like this: -# cmake -D LD_LIBRARY_PATH=~/checkout/libraries -D TEST_CMD=./llunit_test -D ARGS=--touch=llunit_test_ok.txt -P RunBuildTest.cmake - -# Parameters: -# LD_LIBRARY_PATH: string, What to set the LD_LIBRARY_PATH env var. -# TEST_CMD: string list, command to run the unit test with, followed by its args. -set(ENV{LD_LIBRARY_PATH} ${LD_LIBRARY_PATH}) -#message("Running: ${TEST_CMD}") -execute_process( - COMMAND ${TEST_CMD} - RESULT_VARIABLE RES - ) - -if(NOT ${RES} STREQUAL 0) - message(STATUS "Failure running: ${TEST_CMD}") - message(FATAL_ERROR "Error: ${RES}") -endif(NOT ${RES} STREQUAL 0) \ No newline at end of file diff --git a/indra/cmake/TemplateCheck.cmake b/indra/cmake/TemplateCheck.cmake index 3b73dc82df..2fada2eda9 100644 --- a/indra/cmake/TemplateCheck.cmake +++ b/indra/cmake/TemplateCheck.cmake @@ -8,7 +8,7 @@ macro (check_message_template _target) PRE_LINK COMMAND ${PYTHON_EXECUTABLE} ARGS ${SCRIPTS_DIR}/template_verifier.py - --mode=development --cache_master - COMMENT "Verifying message template" + --mode=development --cache_master --master_url=${TEMPLATE_VERIFIER_MASTER_URL} ${TEMPLATE_VERIFIER_OPTIONS} + COMMENT "Verifying message template - See http://wiki.secondlife.com/wiki/Template_verifier.py" ) endmacro (check_message_template) diff --git a/indra/cmake/UI.cmake b/indra/cmake/UI.cmake index 679b5bf3a3..efdf80b3c8 100644 --- a/indra/cmake/UI.cmake +++ b/indra/cmake/UI.cmake @@ -1,10 +1,9 @@ # -*- cmake -*- -include(Prebuilt) +include(FreeType) -if (STANDALONE) +if (LINUX) include(FindPkgConfig) - - if (LINUX) + set(PKGCONFIG_PACKAGES atk cairo @@ -20,8 +19,8 @@ if (STANDALONE) pangox pangoxft sdl + x11 ) - endif (LINUX) foreach(pkg ${PKGCONFIG_PACKAGES}) pkg_check_modules(${pkg} REQUIRED ${pkg}) @@ -30,40 +29,6 @@ if (STANDALONE) list(APPEND UI_LIBRARIES ${${pkg}_LIBRARIES}) add_definitions(${${pkg}_CFLAGS_OTHERS}) endforeach(pkg) -else (STANDALONE) - if (LINUX) - use_prebuilt_binary(glib) # gtk-etc needs glib - use_prebuilt_binary(gtk-atk-pango-glib) - set(UI_LIBRARIES - atk-1.0 - X11 - gdk-x11-2.0 - gdk_pixbuf-2.0 - Xinerama - glib-2.0 - gio-2.0 - gmodule-2.0 - gobject-2.0 - gthread-2.0 - gtk-x11-2.0 - pango-1.0 - pangoft2-1.0 - pangox-1.0 - pangoxft-1.0 - pangocairo-1.0 - ) - endif (LINUX) - include_directories ( - ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include - ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/cairo - ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/pixman-1 - ) - foreach(include ${${LL_ARCH}_INCLUDES}) - include_directories(${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/${include}) - endforeach(include) -endif (STANDALONE) - -if (LINUX) add_definitions(-DLL_GTK=1 -DLL_X11=1) endif (LINUX) diff --git a/indra/cmake/URIPARSER.cmake b/indra/cmake/URIPARSER.cmake new file mode 100644 index 0000000000..47c3ccd376 --- /dev/null +++ b/indra/cmake/URIPARSER.cmake @@ -0,0 +1,20 @@ +# -*- cmake -*- + +set(URIPARSER_FIND_QUIETLY ON) +set(URIPARSER_FIND_REQUIRED ON) + +include(Prebuilt) + +if (USESYSTEMLIBS) + include(FindURIPARSER) +else (USESYSTEMLIBS) + use_prebuilt_binary(uriparser) + if (WINDOWS) + set(URIPARSER_LIBRARY + debug uriparserd + optimized uriparser) + elseif (DARWIN OR LINUX) + set(URIPARSER_LIBRARY uriparser) + endif (WINDOWS) + set(URIPARSER_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include/uriparser) +endif (USESYSTEMLIBS) diff --git a/indra/cmake/UnixInstall.cmake b/indra/cmake/UnixInstall.cmake index 630999d80e..f566aad3df 100644 --- a/indra/cmake/UnixInstall.cmake +++ b/indra/cmake/UnixInstall.cmake @@ -11,6 +11,6 @@ if (INSTALL) set(APP_BIN_DIR bin) endif(NOT APP_BIN_DIR) if(NOT APP_SHARE_DIR) - set(APP_SHARE_DIR share/secondlife-${viewer_VERSION}) + set(APP_SHARE_DIR share/secondlife-${${ROOT_PROJECT_NAME}_VERSION}) endif(NOT APP_SHARE_DIR) endif (INSTALL) diff --git a/indra/cmake/Variables.cmake b/indra/cmake/Variables.cmake index 10dd25ac2b..3b6ec6598c 100644 --- a/indra/cmake/Variables.cmake +++ b/indra/cmake/Variables.cmake @@ -9,9 +9,7 @@ # LINUX - Linux # WINDOWS - Windows - # Relative and absolute paths to subtrees. - if(NOT DEFINED ${CMAKE_CURRENT_LIST_FILE}_INCLUDED) set(${CMAKE_CURRENT_LIST_FILE}_INCLUDED "YES") @@ -19,58 +17,153 @@ if(NOT DEFINED COMMON_CMAKE_DIR) set(COMMON_CMAKE_DIR "${CMAKE_SOURCE_DIR}/cmake") endif(NOT DEFINED COMMON_CMAKE_DIR) +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# https://blog.kitware.com/upcoming-in-cmake-2-8-12-osx-rpath-support/ +set(CMAKE_MACOSX_RPATH ON) +set(CMAKE_BUILD_WITH_INSTALL_RPATH ON) +set(CMAKE_INSTALL_RPATH_USE_LINK_PATH OFF) + +set_property(GLOBAL PROPERTY USE_FOLDERS ON) + +get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +option(GEN_IS_MULTI_CONFIG "" ${_isMultiConfig}) +mark_as_advanced(GEN_IS_MULTI_CONFIG) + set(LIBS_CLOSED_PREFIX) set(LIBS_OPEN_PREFIX) set(SCRIPTS_PREFIX ../scripts) set(VIEWER_PREFIX) +set(INTEGRATION_TESTS_PREFIX) -set(LIBS_CLOSED_DIR ${CMAKE_SOURCE_DIR}/${LIBS_CLOSED_PREFIX}) -set(LIBS_OPEN_DIR ${CMAKE_SOURCE_DIR}/${LIBS_OPEN_PREFIX}) -set(SCRIPTS_DIR ${CMAKE_SOURCE_DIR}/${SCRIPTS_PREFIX}) -set(VIEWER_DIR ${CMAKE_SOURCE_DIR}/${VIEWER_PREFIX}) +option(LL_TESTS "Build and run unit and integration tests (disable for build timing runs to reduce variation" OFF) +option(BUILD_TESTING "Build test suite" OFF) +option(UNATTENDED "Disable use of uneeded tooling for automated builds" OFF) + +# Compiler and toolchain options +option(USESYSTEMLIBS "Use libraries from your system rather than Linden-supplied prebuilt libraries." OFF) +option(STANDALONE "Use libraries from your system rather than Linden-supplied prebuilt libraries." OFF) +if (USESYSTEMLIBS) + set(STANDALONE ON) +elseif (STANDALONE) + set(USESYSTEMLIBS ON) +endif (USESYSTEMLIBS) +option(INCREMENTAL_LINK "Use incremental linking on win32 builds (enable for faster links on some machines)" OFF) +option(USE_PRECOMPILED_HEADERS "Enable use of precompiled header directives where supported." ON) +option(USE_LTO "Enable global and interprocedural optimizations" OFF) + +# Configure crash reporting +option(USE_CRASHPAD "Build support for crashpad reporting engine" OFF) +if (DEFINED ENV{VIEWER_USE_CRASHPAD}) + set(USE_CRASHPAD $ENV{VIEWER_USE_CRASHPAD}) +endif() + +if (DEFINED ENV{VIEWER_CRASHPAD_URL}) + set(CRASHPAD_URL $ENV{VIEWER_CRASHPAD_URL} CACHE STRING "Viewer Channel Base Name") +else() + set(CRASHPAD_URL "" CACHE STRING "Crashpad endpoint url") +endif() + +set(VIEWER_SYMBOL_FILE "" CACHE STRING "Name of tarball into which to place symbol files") + +# Media Plugins +option(ENABLE_MEDIA_PLUGINS "Turn off building media plugins if they are imported by third-party library mechanism" ON) +option(LIBVLCPLUGIN "Turn off building support for libvlc plugin" ON) +if (${CMAKE_SYSTEM_NAME} MATCHES "Linux" OR ${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + set(LIBVLCPLUGIN OFF) +endif (${CMAKE_SYSTEM_NAME} MATCHES "Linux" OR ${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + +# Mallocs set(DISABLE_TCMALLOC OFF CACHE BOOL "Disable linkage of TCMalloc. (64bit builds automatically disable TCMalloc)") -set(LL_TESTS OFF CACHE BOOL "Build and run unit and integration tests (disable for build timing runs to reduce variation)") set(DISABLE_FATAL_WARNINGS TRUE CACHE BOOL "Set this to FALSE to enable fatal warnings.") -set(LIBS_PREBUILT_DIR ${CMAKE_SOURCE_DIR}/../libraries CACHE PATH +# Audio Engines +option(USE_FMODSTUDIO "Build with support for the FMOD Studio audio engine" OFF) + +# Proprietary Library Features +option(USE_NVAPI "Use nvapi driver interface library" OFF) + + +if(LIBS_CLOSED_DIR) + file(TO_CMAKE_PATH "${LIBS_CLOSED_DIR}" LIBS_CLOSED_DIR) +else(LIBS_CLOSED_DIR) + set(LIBS_CLOSED_DIR ${CMAKE_SOURCE_DIR}/${LIBS_CLOSED_PREFIX}) +endif(LIBS_CLOSED_DIR) +if(LIBS_COMMON_DIR) + file(TO_CMAKE_PATH "${LIBS_COMMON_DIR}" LIBS_COMMON_DIR) +else(LIBS_COMMON_DIR) + set(LIBS_COMMON_DIR ${CMAKE_SOURCE_DIR}/${LIBS_OPEN_PREFIX}) +endif(LIBS_COMMON_DIR) +set(LIBS_OPEN_DIR ${LIBS_COMMON_DIR}) + +set(SCRIPTS_DIR ${CMAKE_SOURCE_DIR}/${SCRIPTS_PREFIX}) +set(VIEWER_DIR ${CMAKE_SOURCE_DIR}/${VIEWER_PREFIX}) + +set(AUTOBUILD_INSTALL_DIR ${CMAKE_BINARY_DIR}/packages) + +set(LIBS_PREBUILT_DIR ${AUTOBUILD_INSTALL_DIR} CACHE PATH "Location of prebuilt libraries.") -if (${CMAKE_SYSTEM_NAME} MATCHES "Windows") - set(WINDOWS ON BOOL FORCE) +if (EXISTS ${CMAKE_SOURCE_DIR}/Server.cmake) + # We use this as a marker that you can try to use the proprietary libraries. + set(INSTALL_PROPRIETARY ON CACHE BOOL "Install proprietary binaries") +endif (EXISTS ${CMAKE_SOURCE_DIR}/Server.cmake) +set(TEMPLATE_VERIFIER_OPTIONS "" CACHE STRING "Options for scripts/template_verifier.py") +set(TEMPLATE_VERIFIER_MASTER_URL "https://git.alchemyviewer.org/alchemy/master-message-template/raw/master/message_template.msg" CACHE STRING "Location of the master message template") + +if (NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING + "Build type. One of: Debug Release RelWithDebInfo" FORCE) +endif (NOT CMAKE_BUILD_TYPE) + +# If someone has specified an address size, use that to determine the +# architecture. Otherwise, let the architecture specify the address size. +if (ADDRESS_SIZE EQUAL 32) + #message(STATUS "ADDRESS_SIZE is 32") set(ARCH i686) - set(LL_ARCH ${ARCH}_win32) - set(LL_ARCH_DIR ${ARCH}-win32) - set(WORD_SIZE 32) -endif (${CMAKE_SYSTEM_NAME} MATCHES "Windows") +elseif (ADDRESS_SIZE EQUAL 64) + #message(STATUS "ADDRESS_SIZE is 64") + set(ARCH x86_64) +else (ADDRESS_SIZE EQUAL 32) + #message(STATUS "ADDRESS_SIZE is UNDEFINED") + if (CMAKE_SIZEOF_VOID_P EQUAL 8) + message(STATUS "Size of void pointer is detected as 8; ARCH is 64-bit") + set(ARCH x86_64) + set(ADDRESS_SIZE 64) + elseif (CMAKE_SIZEOF_VOID_P EQUAL 4) + message(STATUS "Size of void pointer is detected as 4; ARCH is 32-bit") + set(ADDRESS_SIZE 32) + set(ARCH i686) + else() + message(FATAL_ERROR "Unkown Architecture!") + endif() +endif (ADDRESS_SIZE EQUAL 32) + +if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") + set(WINDOWS ON BOOL FORCE) + if (ADDRESS_SIZE EQUAL 64) + set(LL_ARCH ${ARCH}_win64) + set(LL_ARCH_DIR ${ARCH}-win64) + elseif (ADDRESS_SIZE EQUAL 32) + set(LL_ARCH ${ARCH}_win32) + set(LL_ARCH_DIR ${ARCH}-win32) + else() + message(FATAL_ERROR "Unkown Architecture!") + endif () +endif (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") - set(LINUX ON BOOl FORCE) - - # If someone has specified a word size, use that to determine the - # architecture. Otherwise, let the architecture specify the word size. - if (WORD_SIZE EQUAL 32) - set(ARCH i686) - elseif (WORD_SIZE EQUAL 64) - set(ARCH x86_64) - else (WORD_SIZE EQUAL 32) - if(CMAKE_SIZEOF_VOID_P MATCHES 4) - set(ARCH i686) - set(WORD_SIZE 32) - else(CMAKE_SIZEOF_VOID_P MATCHES 4) - set(ARCH x86_64) - set(WORD_SIZE 64) - endif(CMAKE_SIZEOF_VOID_P MATCHES 4) - endif (WORD_SIZE EQUAL 32) + set(LINUX ON BOOL FORCE) - if (NOT STANDALONE AND MULTIARCH_HACK) - if (WORD_SIZE EQUAL 32) + if (ADDRESS_SIZE EQUAL 32) set(DEB_ARCHITECTURE i386) set(FIND_LIBRARY_USE_LIB64_PATHS OFF) set(CMAKE_SYSTEM_LIBRARY_PATH /usr/lib32 ${CMAKE_SYSTEM_LIBRARY_PATH}) - else (WORD_SIZE EQUAL 32) + else (ADDRESS_SIZE EQUAL 32) set(DEB_ARCHITECTURE amd64) set(FIND_LIBRARY_USE_LIB64_PATHS ON) - endif (WORD_SIZE EQUAL 32) + endif (ADDRESS_SIZE EQUAL 32) execute_process(COMMAND dpkg-architecture -a${DEB_ARCHITECTURE} -qDEB_HOST_MULTIARCH RESULT_VARIABLE DPKG_RESULT @@ -83,64 +176,107 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") endif (DPKG_RESULT EQUAL 0) include(ConfigurePkgConfig) - endif (NOT STANDALONE AND MULTIARCH_HACK) set(LL_ARCH ${ARCH}_linux) set(LL_ARCH_DIR ${ARCH}-linux) endif (${CMAKE_SYSTEM_NAME} MATCHES "Linux") if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - set(DARWIN 1) - - if(${CMAKE_GENERATOR} MATCHES Xcode) - #SDK Compiler and Deployment targets for XCode - if (${XCODE_VERSION} VERSION_LESS 4.0.0) - set(CMAKE_OSX_SYSROOT /Developer/SDKs/MacOSX10.5.sdk) - set(CMAKE_OSX_DEPLOYMENT_TARGET 10.5) - else (${XCODE_VERSION} VERSION_LESS 4.0.0) - set(CMAKE_OSX_SYSROOT /Developer/SDKs/MacOSX10.6.sdk) - set(CMAKE_OSX_DEPLOYMENT_TARGET 10.6) - endif (${XCODE_VERSION} VERSION_LESS 4.0.0) - else(${CMAKE_GENERATOR} MATCHES Xcode) - set(CMAKE_OSX_SYSROOT /Developer/SDKs/MacOSX10.6.sdk) - set(CMAKE_OSX_DEPLOYMENT_TARGET 10.6) - endif(${CMAKE_GENERATOR} MATCHES Xcode) - - set(CMAKE_XCODE_ATTRIBUTE_GCC_VERSION "com.apple.compilers.llvmgcc42") - - set(CMAKE_XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT dwarf-with-dsym) - - # Build only for i386 by default, system default on MacOSX 10.6 is x86_64 - set(CMAKE_OSX_ARCHITECTURES i386) - set(ARCH i386) - set(WORD_SIZE 32) + set(DARWIN ON BOOL FORCE) + + # Architecture + set(CMAKE_OSX_SYSROOT macosx10.14) + set(CMAKE_OSX_ARCHITECTURES "x86_64") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS "x86_64") + + # Build Options + set(CMAKE_XCODE_ATTRIBUTE_GCC_VERSION "com.apple.compilers.llvm.clang.1_0") + set(CMAKE_XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT[variant=Debug] "dwarf") + set(CMAKE_XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT[variant=Release] "dwarf-with-dsym") + + # Deployment + set(CMAKE_OSX_DEPLOYMENT_TARGET 10.13) + + # Linking + set(CMAKE_XCODE_ATTRIBUTE_DEAD_CODE_STRIPPING YES) + + # Apple Clang - Code Gen + set(CMAKE_XCODE_ATTRIBUTE_GCC_GENERATE_DEBUGGING_SYMBOLS[variant=Release] YES) + set(CMAKE_XCODE_ATTRIBUTE_CLANG_X86_VECTOR_INSTRUCTIONS sse4.1) + set(CMAKE_XCODE_ATTRIBUTE_GCC_STRICT_ALIASING NO) + set(CMAKE_XCODE_ATTRIBUTE_GCC_OPTIMIZATION_LEVEL[variant=Debug] 0) + set(CMAKE_XCODE_ATTRIBUTE_GCC_OPTIMIZATION_LEVEL[variant=Release] 3) + set(CMAKE_XCODE_ATTRIBUTE_GCC_FAST_MATH NO) + + # Apple Clang - Custom Compiler Flags + set(CMAKE_XCODE_ATTRIBUTE_WARNING_CFLAGS "-Wall -Wextra -Wno-reorder -Wno-sign-compare -Wno-ignored-qualifiers -Wno-unused-local-typedef -Wno-unused-parameter") + + # Apple Clang - Language - C++ + set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD c++14) + set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++") + + # Apple Clang - Warning Policies + set(CMAKE_XCODE_ATTRIBUTE_GCC_TREAT_WARNINGS_AS_ERRORS YES) set(LL_ARCH ${ARCH}_darwin) set(LL_ARCH_DIR universal-darwin) endif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") +# Platform specific if (WINDOWS) - set(PREBUILT_TYPE windows) -elseif(DARWIN) - set(PREBUILT_TYPE darwin) -elseif(LINUX AND WORD_SIZE EQUAL 32) - set(PREBUILT_TYPE linux) -elseif(LINUX AND WORD_SIZE EQUAL 64) - set(PREBUILT_TYPE linux64) -endif(WINDOWS) + option(LLWINDOW_SDL2 "Use SDL2 for window and input handling. Windows only" OFF) +endif() # Default deploy grid set(GRID agni CACHE STRING "Target Grid") -set(VIEWER_CHANNEL "Singularity" CACHE STRING "Viewer Channel Name") -set(VIEWER_LOGIN_CHANNEL ${VIEWER_CHANNEL} CACHE STRING "Fake login channel for A/B Testing") -set(VIEWER_BRANDING_ID "singularity" CACHE STRING "Viewer branding id (currently secondlife|snowglobe)") +if (DEFINED ENV{VIEWER_CHANNEL_BASE}) + set(VIEWER_CHANNEL_BASE $ENV{VIEWER_CHANNEL_BASE} CACHE STRING "Viewer Channel Base Name" FORCE) +else() + set(VIEWER_CHANNEL_BASE "Singularity" CACHE STRING "Viewer Channel Base Name") +endif() + +if (DEFINED ENV{VIEWER_CHANNEL_TYPE}) + set(VIEWER_CHANNEL_TYPE $ENV{VIEWER_CHANNEL_TYPE} CACHE STRING "Viewer Channel Type Name" FORCE) +else() + set(VIEWER_CHANNEL_TYPE "Test" CACHE STRING "Viewer Channel Type Name") +endif() + +if (DEFINED ENV{VIEWER_CHANNEL_CODENAME}) + set(VIEWER_CHANNEL_CODENAME $ENV{VIEWER_CHANNEL_CODENAME} CACHE STRING "Viewer Channel Code Name for Project type" FORCE) +else() + set(VIEWER_CHANNEL_CODENAME "Default" CACHE STRING "Viewer Channel Code Name for Project type") +endif() + +if("${VIEWER_CHANNEL_TYPE}" STREQUAL "Project") + set(VIEWER_CHANNEL "${VIEWER_CHANNEL_BASE} ${VIEWER_CHANNEL_TYPE} ${VIEWER_CHANNEL_CODENAME}") +else() + set(VIEWER_CHANNEL "${VIEWER_CHANNEL_BASE} ${VIEWER_CHANNEL_TYPE}") +endif() + +string(TOLOWER "${VIEWER_CHANNEL_BASE}" VIEWER_BRANDING_ID) +string(REPLACE " " "-" VIEWER_BRANDING_ID ${VIEWER_BRANDING_ID}) +set(VIEWER_BINARY_NAME "${VIEWER_BRANDING_ID}-bin" CACHE STRING + "The name of the viewer executable to create.") + +string(REPLACE " " "" VIEWER_CHANNEL_ONEWORD ${VIEWER_CHANNEL}) +set(VIEWER_CHANNEL_NOSPACE ${VIEWER_CHANNEL_ONEWORD} CACHE STRING "Prefix used for resulting artifacts.") -# *TODO: break out proper Branding-secondlife.cmake, Branding-snowglobe.cmake, etc -set(VIEWER_BRANDING_NAME "Singularity") -set(VIEWER_BRANDING_NAME_CAMELCASE "Singularity") +option(VIEWER_CHANNEL_GRK "Greek character(s) to represent the viewer channel for support purposes, override only for special branches" "") +if (NOT VIEWER_CHANNEL_GRK) + if (VIEWER_CHANNEL_TYPE MATCHES "Test") + set(VIEWER_CHANNEL_GRK "\\u03C4") # "τ" + elseif (VIEWER_CHANNEL_TYPE MATCHES "Alpha") + set(VIEWER_CHANNEL_GRK "\\u03B1") # "α" + elseif (VIEWER_CHANNEL_TYPE MATCHES "Beta") + set(VIEWER_CHANNEL_GRK "\\u03B2") # "β" + else() + set(VIEWER_CHANNEL_GRK "") + endif () +endif (NOT VIEWER_CHANNEL_GRK) -set(STANDALONE OFF CACHE BOOL "Do not use Linden-supplied prebuilt libraries.") +option(ENABLE_SIGNING "Enable signing the viewer" OFF) +set(SIGNING_IDENTITY "" CACHE STRING "Specifies the signing identity to use, if necessary.") source_group("CMake Rules" FILES CMakeLists.txt) diff --git a/indra/cmake/ViewerMiscLibs.cmake b/indra/cmake/ViewerMiscLibs.cmake index 275b840a05..36ee514e91 100644 --- a/indra/cmake/ViewerMiscLibs.cmake +++ b/indra/cmake/ViewerMiscLibs.cmake @@ -2,14 +2,7 @@ include(Prebuilt) if (NOT STANDALONE) - use_prebuilt_binary(vivox) - if(LINUX) - use_prebuilt_binary(libuuid) - if (${ARCH} STREQUAL "x86_64") - use_prebuilt_binary(32bitcompatibilitylibs) - endif (${ARCH} STREQUAL "x86_64") - use_prebuilt_binary(fontconfig) - endif(LINUX) + use_prebuilt_binary(slvoice) else (NOT STANDALONE) # Download there even when using standalone. set(STANDALONE OFF) @@ -19,3 +12,10 @@ else (NOT STANDALONE) endif(LINUX AND ${ARCH} STREQUAL "x86_64") set(STANDALONE ON) endif(NOT STANDALONE) + +if(LINUX) + include(FindPkgConfig) + pkg_check_modules(FONTCONFIG REQUIRED fontconfig) +endif(LINUX) + +use_prebuilt_binary(fonts) diff --git a/indra/cmake/WebKitLibPlugin.cmake b/indra/cmake/WebKitLibPlugin.cmake deleted file mode 100644 index 5d1036c6f3..0000000000 --- a/indra/cmake/WebKitLibPlugin.cmake +++ /dev/null @@ -1,62 +0,0 @@ -# -*- cmake -*- -include(Linking) -include(Prebuilt) -include(LLQtWebkit) -include(Qt4) - -if (STANDALONE) - set(WEBKITLIBPLUGIN OFF CACHE BOOL - "WEBKITLIBPLUGIN support for the llplugin/llmedia test apps.") -else (STANDALONE) - use_prebuilt_binary(llqtwebkit) - set(WEBKITLIBPLUGIN ON CACHE BOOL - "WEBKITLIBPLUGIN support for the llplugin/llmedia test apps.") -endif (STANDALONE) - -if (WINDOWS) - set(WEBKIT_PLUGIN_LIBRARIES - debug llqtwebkitd - debug QtWebKitd4 - debug QtOpenGLd4 - debug QtNetworkd4 - debug QtGuid4 - debug QtCored4 - debug qtmaind - optimized llqtwebkit - optimized QtWebKit4 - optimized QtOpenGL4 - optimized QtNetwork4 - optimized QtGui4 - optimized QtCore4 - optimized qtmain - ) -elseif (DARWIN) - set(WEBKIT_PLUGIN_LIBRARIES - optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libllqtwebkit.dylib - debug ${ARCH_PREBUILT_DIRS_DEBUG}/libllqtwebkit.dylib - ) -elseif (LINUX) - if (STANDALONE) - set(WEBKIT_PLUGIN_LIBRARIES ${LLQTWEBKIT_LIBRARY} ${QT_LIBRARIES} ${QT_PLUGIN_LIBRARIES}) - else (STANDALONE) - set(WEBKIT_PLUGIN_LIBRARIES - llqtwebkit - QtWebKit - QtOpenGL - QtNetwork - QtGui - QtCore - crypto - ssl -# qgif -# qjpeg - jscore - jpeg - fontconfig - X11 - Xrender - Xext - GL - ) - endif (STANDALONE) -endif (WINDOWS) diff --git a/indra/cmake/WinManifest.cmake b/indra/cmake/WinManifest.cmake new file mode 100644 index 0000000000..39f4def75d --- /dev/null +++ b/indra/cmake/WinManifest.cmake @@ -0,0 +1,17 @@ +# - Embeds a specific manifest file in a Windows binary +# Defines the following: +# EMBED_MANIFEST - embed manifest in a windows binary with mt +# Parameters - _target is the target file, type - 1 for EXE, 2 for DLL + + MACRO(EMBED_MANIFEST _target type) + ADD_CUSTOM_COMMAND( + TARGET ${_target} + POST_BUILD + COMMAND "mt.exe" + ARGS + -manifest \"${CMAKE_SOURCE_DIR}\\tools\\manifests\\compatibility.manifest\" + -inputresource:\"$\"\;\#${type} + -outputresource:\"$\"\;\#${type} + COMMENT "Adding compatibility manifest to ${_target}" + ) + ENDMACRO(EMBED_MANIFEST _target type) diff --git a/indra/cmake/XmlRpcEpi.cmake b/indra/cmake/XmlRpcEpi.cmake index cbfe1e16fa..5d59c90dbc 100644 --- a/indra/cmake/XmlRpcEpi.cmake +++ b/indra/cmake/XmlRpcEpi.cmake @@ -8,6 +8,13 @@ if (STANDALONE) include(FindXmlRpcEpi) else (STANDALONE) use_prebuilt_binary(xmlrpc-epi) - set(XMLRPCEPI_LIBRARIES xmlrpc-epi) - set(XMLRPCEPI_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include) + if (WINDOWS) + set(XMLRPCEPI_LIBRARIES + debug xmlrpc-epid + optimized xmlrpc-epi + ) + else (WINDOWS) + set(XMLRPCEPI_LIBRARIES xmlrpc-epi) + endif (WINDOWS) + set(XMLRPCEPI_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include) endif (STANDALONE) diff --git a/indra/cmake/ZLIB.cmake b/indra/cmake/ZLIB.cmake index c133248bed..5b38fc1af4 100644 --- a/indra/cmake/ZLIB.cmake +++ b/indra/cmake/ZLIB.cmake @@ -13,10 +13,25 @@ else (STANDALONE) set(ZLIB_LIBRARIES debug zlibd optimized zlib) + elseif (LINUX) + # + # When we have updated static libraries in competition with older + # shared libraries and we want the former to win, we need to do some + # extra work. The *_PRELOAD_ARCHIVES settings are invoked early + # and will pull in the entire archive to the binary giving it + # priority in symbol resolution. Beware of cmake moving the + # achive load itself to another place on the link command line. If + # that happens, you can try something like -Wl,-lz here to hide + # the archive. Also be aware that the linker will not tolerate a + # second whole-archive load of the archive. See viewer's + # CMakeLists.txt for more information. + # + set(ZLIB_PRELOAD_ARCHIVES -Wl,--whole-archive z -Wl,--no-whole-archive) + set(ZLIB_LIBRARIES z) else (WINDOWS) set(ZLIB_LIBRARIES z) endif (WINDOWS) if (WINDOWS OR LINUX) - set(ZLIB_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/zlib) + set(ZLIB_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include/zlib) endif (WINDOWS OR LINUX) endif (STANDALONE) diff --git a/indra/cmake/cmake_dummy.cpp b/indra/cmake/cmake_dummy.cpp index 25191e2a18..ae4475a73e 100644 --- a/indra/cmake/cmake_dummy.cpp +++ b/indra/cmake/cmake_dummy.cpp @@ -1,30 +1,24 @@ /** * @file cmake_dummy.cpp * - * $LicenseInfo:firstyear=2008&license=viewergpl$ - * - * Copyright (c) 2008-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/cmake/run_build_test.py b/indra/cmake/run_build_test.py new file mode 100644 index 0000000000..9c7d2f5633 --- /dev/null +++ b/indra/cmake/run_build_test.py @@ -0,0 +1,340 @@ +#!/usr/bin/env python2 +"""\ +@file run_build_test.py +@author Nat Goodspeed +@date 2009-09-03 +@brief Helper script to allow CMake to run some command after setting + environment variables. + +CMake has commands to run an external program. But remember that each CMake +command must be backed by multiple build-system implementations. Unfortunately +it seems CMake can't promise that every target build system can set specified +environment variables before running the external program of interest. + +This helper script is a workaround. It simply sets the requested environment +variables and then executes the program specified on the rest of its command +line. + +Example: + +python run_build_test.py -DFOO=bar myprog somearg otherarg + +sets environment variable FOO=bar, then runs: +myprog somearg otherarg + +$LicenseInfo:firstyear=2009&license=viewerlgpl$ +Second Life Viewer Source Code +Copyright (C) 2009-2010, Linden Research, Inc. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; +version 2.1 of the License only. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +$/LicenseInfo$ +""" + +import os +import sys +import errno +import HTMLParser +import re +import signal +import subprocess +import logging + +def main(command, arguments=[], libpath=[], vars={}): + """Pass: + command is the command to be executed + + argument is a sequence (e.g. a list) of strings to be passed to command + + libpath is a sequence of directory pathnames. These will be appended to + the platform-specific dynamic library search path environment variable. + + vars is a dict of arbitrary (var, value) pairs to be added to the + environment before running 'command'. + + This function runs the specified command, waits for it to terminate and + returns its return code. This will be negative if the command terminated + with a signal, else it will be the process's specified exit code. + """ + # Handle platform-dependent libpath first. + if sys.platform == "win32": + lpvars = ["PATH"] + elif sys.platform == "darwin": + lpvars = ["LD_LIBRARY_PATH", "DYLD_LIBRARY_PATH"] + elif sys.platform.startswith("linux"): + lpvars = ["LD_LIBRARY_PATH"] + else: + # No idea what the right pathname might be! But only crump if this + # feature is requested. + if libpath: + raise RuntimeError("run_build_test: unknown platform %s" % sys.platform) + lpvars = [] + for var in lpvars: + # Split the existing path. Bear in mind that the variable in question + # might not exist; instead of KeyError, just use an empty string. + dirs = os.environ.get(var, "").split(os.pathsep) + # Append the sequence in libpath + log.info("%s += %r" % (var, libpath)) + for dir in libpath: + # append system paths at the end + if dir in ('/lib', '/usr/lib'): + dirs.append(dir) + # prepend non-system paths + else: + dirs.insert(0, dir) + + # Filter out some useless pieces + clean_dirs = [] + for dir in dirs: + if dir and dir not in ('', '.'): + clean_dirs.append(dir) + + # Now rebuild the path string. This way we use a minimum of separators + # -- and we avoid adding a pointless separator when libpath is empty. + os.environ[var] = os.pathsep.join(clean_dirs) + log.info("%s = %r" % (var, os.environ[var])) + # Now handle arbitrary environment variables. The tricky part is ensuring + # that all the keys and values we try to pass are actually strings. + if vars: + log.info("Setting: %s" % ("\n".join(["%s=%s" % (key, value) for key, value in vars.iteritems()]))) + os.environ.update(dict([(str(key), str(value)) for key, value in vars.iteritems()])) + # Run the child process. + command_list = [command] + command_list.extend(arguments) + log.info("Running: %s" % " ".join(command_list)) + # Make sure we see all relevant output *before* child-process output. + sys.stdout.flush() + try: + return subprocess.call(command_list) + except OSError as err: + # If the caller is trying to execute a test program that doesn't + # exist, we want to produce a reasonable error message rather than a + # traceback. This happens when the build is halted by errors, but + # CMake tries to proceed with testing anyway . However, do + # NOT attempt to handle any error but "doesn't exist." + if err.errno != errno.ENOENT: + raise + # In practice, the pathnames into CMake's build tree are so long as to + # obscure the name of the test program. Just log its basename. + log.warn("No such program %s; check for preceding build errors" % \ + os.path.basename(command[0])) + # What rc should we simulate for missing executable? Windows produces + # 9009. + return 9009 + +# swiped from vita, sigh, seems like a Bad Idea to introduce dependency +def translate_rc(rc): + """ + Accept an rc encoded as for subprocess.Popen.returncode: + None means still running + int >= 0 means terminated voluntarily with specified rc + int < 0 means terminated by signal (-rc) + + Return a string explaining the outcome. In case of a signal, try to + name the corresponding symbol from the 'signal' module. + """ + if rc is None: + return "still running" + + if rc >= 0: + return "terminated with rc %s" % rc + + if sys.platform.startswith("win"): + # From http://stackoverflow.com/questions/20629027/process-finished-with-exit-code-1073741571 + # [-1073741571] is the signed integer representation of Microsoft's + # "stack overflow/stack exhaustion" error code 0xC00000FD. + # Anytime you see strange, large negative exit codes in windows, convert + # them to hex and then look them up in the ntstatus error codes + # http://msdn.microsoft.com/en-us/library/cc704588.aspx + + # Python bends over backwards to give you all the integer precision + # you need, avoiding truncation. But only with 32-bit signed ints is + # -1073741571 equivalent to 0xC00000FD! Explicitly truncate before + # converting. + hexrc = "0x%X" % (rc & 0xFFFFFFFF) + # At this point, we're only trying to format the rc to make it easier + # for a human being to understand. Any exception here -- file doesn't + # exist, HTML parsing error, unrecognized table structure, unknown key + # -- should NOT kill the script! It should only cause us to shrug and + # present our caller with the best information available. + try: + table = get_windows_table() + symbol, desc = table[hexrc] + except Exception, err: + log.error("(%s -- carrying on)" % err) + log.error("terminated with rc %s (%s)" % (rc, hexrc)) + else: + log.info("terminated with rc %s: %s: %s" % (hexrc, symbol, desc)) + + else: + # On Posix, negative rc means the child was terminated by signal -rc. + rc = -rc + for attr in dir(signal): + if attr.startswith('SIG') and getattr(signal, attr) == rc: + strc = attr + break + else: + strc = str(rc) + return "terminated by signal %s" % strc + +class TableParser(HTMLParser.HTMLParser): + """ + This HTMLParser subclass is designed to parse the table we know exists + in windows-rcs.html, hopefully without building in too much knowledge of + the specific way that table is currently formatted. + """ + # regular expression matching any string containing only whitespace + whitespace = re.compile(r'\s*$') + + def __init__(self): + # Because Python 2.x's HTMLParser is an old-style class, we must use + # old-style syntax to forward the __init__() call -- not super(). + HTMLParser.HTMLParser.__init__(self) + # this will collect all the data, eventually + self.table = [] + # Stack whose top (last item) indicates where to append current + # element data. When empty, don't collect data at all. + self.dest = [] + + def handle_starttag(self, tag, attrs): + if tag == "table": + # This is the outermost tag we recognize. Collect nested elements + # within self.table. + self.dest.append(self.table) + elif tag in ("tr", "td"): + # Nested elements whose contents we want to capture as sublists. + # To the list currently designated by the top of the dest stack, + # append a new empty sublist. + self.dest[-1].append([]) + # Now push THAT new, empty list as the new top of the dest stack. + self.dest.append(self.dest[-1][-1]) + elif tag == "p": + # We could handle

...

just like or , but that + # introduces an unnecessary extra level of nesting. Just skip. + pass + else: + # For any tag we don't recognize (notably ), push a new, empty + # list to the top of the dest stack. This new list is NOT + # referenced by anything in self.table; thus, when we pop it, any + # data we've collected inside that list will be discarded. + self.dest.append([]) + + def handle_endtag(self, tag): + # Because we avoid pushing self.dest for

in handle_starttag(), we + # must refrain from popping it for

here. + if tag != "p": + # For everything else, including unrecognized tags, pop the dest + # stack, reverting to outer collection. + self.dest.pop() + + def handle_startendtag(self, tag, attrs): + # The table of interest contains entries of the form: + #

0x00000000
STATUS_SUCCESS

+ # The
is very useful -- we definitely want two different data + # items for "0x00000000" and "STATUS_SUCCESS" -- but we don't need or + # want it to push, then discard, an empty list as it would if we let + # the default HTMLParser.handle_startendtag() call handle_starttag() + # followed by handle_endtag(). Just ignore
or any other + # singleton tag. + pass + + def handle_data(self, data): + # Outside the of interest, self.dest is empty. Do not bother + # collecting data when self.dest is empty. + # HTMLParser calls handle_data() with every chunk of whitespace + # between tags. That would be lovely if our eventual goal was to + # reconstitute the original input stream with its existing formatting, + # but for us, whitespace only clutters the table. Ignore it. + if self.dest and not self.whitespace.match(data): + # Here we're within our
and we have non-whitespace data. + # Append it to the list designated by the top of the dest stack. + self.dest[-1].append(data) + +# cache for get_windows_table() +_windows_table = None + +def get_windows_table(): + global _windows_table + # If we already loaded _windows_table, no need to load it all over again. + if _windows_table: + return _windows_table + + # windows-rcs.html was fetched on 2015-03-24 with the following command: + # curl -o windows-rcs.html \ + # https://msdn.microsoft.com/en-us/library/cc704588.aspx + parser = TableParser() + with open(os.path.join(os.path.dirname(__file__), "windows-rcs.html")) as hf: + # We tried feeding the file data to TableParser in chunks, to avoid + # buffering the entire file as a single string. Unfortunately its + # handle_data() cannot tell the difference between distinct calls + # separated by HTML tags, and distinct calls necessitated by a chunk + # boundary. Sigh! Read in the whole file. At the time this was + # written, it was only 500KB anyway. + parser.feed(hf.read()) + parser.close() + table = parser.table + + # With our parser, any row leaves a table entry + # consisting only of an empty list. Remove any such. + while table and not table[0]: + table.pop(0) + + # We expect rows of the form: + # [['0x00000000', 'STATUS_SUCCESS'], + # ['The operation completed successfully.']] + # The latter list will have multiple entries if Microsoft embedded
+ # or

...

in the text, in which case joining with '\n' is + # appropriate. + # Turn that into a dict whose key is the hex string, and whose value is + # the pair (symbol, desc). + _windows_table = dict((key, (symbol, '\n'.join(desc))) + for (key, symbol), desc in table) + + return _windows_table + +log=logging.getLogger(__name__) +logging.basicConfig() + +if __name__ == "__main__": + import argparse + parser = argparse.ArgumentParser() + parser.add_argument("-d", "--debug", dest="loglevel", action="store_const", + const=logging.DEBUG, default=logging.INFO) + parser.add_argument("-D", "--define", dest="vars", default=[], action="append", + metavar="VAR=value", + help="Add VAR=value to the env variables defined") + parser.add_argument("-l", "--libpath", dest="libpath", default=[], action="append", + metavar="DIR", + help="Add DIR to the platform-dependent DLL search path") + parser.add_argument("command") + parser.add_argument('args', nargs=argparse.REMAINDER) + args = parser.parse_args() + + log.setLevel(args.loglevel) + + # What we have in opts.vars is a list of strings of the form "VAR=value" + # or possibly just "VAR". What we want is a dict. We can build that dict by + # constructing a list of ["VAR", "value"] pairs -- so split each + # "VAR=value" string on the '=' sign (but only once, in case we have + # "VAR=some=user=string"). To handle the case of just "VAR", append "" to + # the list returned by split(), then slice off anything after the pair we + # want. + rc = main(command=args.command, arguments=args.args, libpath=args.libpath, + vars=dict([(pair.split('=', 1) + [""])[:2] for pair in args.vars])) + if rc not in (None, 0): + log.error("Failure running: %s" % " ".join([args.command] + args.args)) + log.error("Error %s: %s" % (rc, translate_rc(rc))) + sys.exit((rc < 0) and 255 or rc) diff --git a/indra/copy_win_scripts/start-client.py b/indra/copy_win_scripts/start-client.py index 5f7ff2f293..63c765c2fa 100644 --- a/indra/copy_win_scripts/start-client.py +++ b/indra/copy_win_scripts/start-client.py @@ -1,4 +1,28 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 +"""\ +@file start-client.py + +$LicenseInfo:firstyear=2010&license=viewerlgpl$ +Second Life Viewer Source Code +Copyright (C) 2010-2011, Linden Research, Inc. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; +version 2.1 of the License only. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +$/LicenseInfo$ +""" import sys, getopt import os import llstart diff --git a/indra/cwdebug/debug.h b/indra/cwdebug/debug.h index 4167813eaf..93a037c929 100644 --- a/indra/cwdebug/debug.h +++ b/indra/cwdebug/debug.h @@ -28,95 +28,16 @@ #ifndef CWDEBUG #ifdef DEBUG_CURLIO - -// If CWDEBUG is not defined, but DEBUG_CURLIO is, then replace -// some of the cwd macro's with something that generates viewer -// specific debug output. Note that this generates a LOT of -// output and should not normally be defined. - -#include -#include "llpreprocessor.h" - -namespace debug { -namespace libcwd { - -struct buf2str { - buf2str(char const* buf, int size) : mBuf(buf), mSize(size) { } - char const* mBuf; - int mSize; -}; - -struct libcwd_do_type { - void on() const { } -}; -extern LL_COMMON_API libcwd_do_type const libcw_do; - -} // namespace libcwd - -enum print_thread_id_t { print_thread_id }; -inline void init() { } -struct Indent { - int M_indent; - static ll_thread_local int S_indentation; - enum LL_COMMON_API print_nt { print }; - LL_COMMON_API Indent(int indent); - LL_COMMON_API ~Indent(); -}; - -extern LL_COMMON_API std::ostream& operator<<(std::ostream& os, libcwd::buf2str const& b2s); -extern LL_COMMON_API std::ostream& operator<<(std::ostream& os, Indent::print_nt); -extern LL_COMMON_API std::ostream& operator<<(std::ostream& os, print_thread_id_t); - -namespace dc { - -struct fake_channel { - int mOn; - char const* mLabel; - fake_channel(int on, char const* label) : mOn(on), mLabel(label) { } - fake_channel(void) : mOn(0) { } - bool is_on() const { return !!mOn; } - bool is_off() const { return !mOn; } - void on() const { } - void off() const { } -}; -extern LL_COMMON_API fake_channel const warning; -extern LL_COMMON_API fake_channel const curl; -extern LL_COMMON_API fake_channel const curlio; -extern LL_COMMON_API fake_channel const curltr; -extern LL_COMMON_API fake_channel const statemachine; -extern LL_COMMON_API fake_channel const notice; -extern LL_COMMON_API fake_channel const snapshot; - -} // namespace dc -} // namespace debug - -#define LIBCWD_DEBUG_CHANNELS debug -#define LibcwDoutScopeBegin(a, b, c) do { using namespace debug; using namespace debug::libcwd; llinfos_nf << print_thread_id << (c).mLabel << ": " << Indent::print; -#define LibcwDoutStream llcont -#define LibcwDoutScopeEnd llcont << llendl; } while(0) - -#define Debug(x) do { using namespace debug; using namespace debug::libcwd; x; } while(0) -#define Dout(a, b) do { using namespace debug; using namespace debug::libcwd; if ((a).mOn) { llinfos_nf << print_thread_id << (a).mLabel << ": " << Indent::print << b << llendl; } } while(0) -#define DoutEntering(a, b) \ - int __slviewer_debug_indentation = 2; \ - { \ - using namespace debug; \ - using namespace debug::libcwd; \ - if ((a).mOn) \ - llinfos_nf << print_thread_id << (a).mLabel << ": " << Indent::print << "Entering " << b << llendl; \ - else \ - __slviewer_debug_indentation = 0; \ - } \ - debug::Indent __slviewer_debug_indent(__slviewer_debug_indentation); - -#else // !DEBUG_CURLIO +#error DEBUG_CURLIO is not supported without libcwd. +// In order to use DEBUG_CURLIO you must install and use libcwd. +// Download libcwd: +// git clone https://github.com/CarloWood/libcwd.git +#endif #define Debug(x) #define Dout(a, b) #define DoutEntering(a, b) -#endif // !DEBUG_CURLIO - #ifndef DOXYGEN // No need to document this. See http://libcwd.sourceforge.net/ for more info. #include @@ -144,6 +65,11 @@ extern LL_COMMON_API fake_channel const snapshot; #define CWDEBUG_MARKER 0 #define BACKTRACE do { } while(0) +#ifdef DEBUG_CURLIO +#define CWD_ONLY(...) __VA_ARGS__ +#else +#define CWD_ONLY(...) +#endif #endif // !DOXYGEN @@ -180,6 +106,7 @@ extern LL_COMMON_API fake_channel const snapshot; #include #define CWD_API __attribute__ ((visibility("default"))) +#define CWD_ONLY(...) __VA_ARGS__ //! Debug specific code. namespace debug { @@ -384,6 +311,40 @@ void InstanceTracker::dump(void) } // namespace debug +template +class AIDebugInstanceCounter +{ + public: + static int sInstanceCount; + + protected: + static void print_count(char const* name, int count, bool destruction); + + AIDebugInstanceCounter() + { + print_count(typeid(T).name(), ++sInstanceCount, false); + } + AIDebugInstanceCounter(AIDebugInstanceCounter const&) + { + print_count(typeid(T).name(), ++sInstanceCount, false); + } + ~AIDebugInstanceCounter() + { + print_count(typeid(T).name(), --sInstanceCount, true); + } +}; + +//static +template +int AIDebugInstanceCounter::sInstanceCount; + +//static +template +void AIDebugInstanceCounter::print_count(char const* name, int count, bool destruction) +{ + Dout(dc::notice, (destruction ? "Destructed " : "Constructing ") << name << ", now " << count << " instance" << ((count == 1) ? "." : "s.")); +} + //! Debugging macro. // // Print "Entering " << \a data to channel \a cntrl and increment diff --git a/indra/deps/CMakeLists.txt b/indra/deps/CMakeLists.txt new file mode 100644 index 0000000000..a8df464f19 --- /dev/null +++ b/indra/deps/CMakeLists.txt @@ -0,0 +1,62 @@ +project(deps) + +include(FetchContent) + +set(CMAKE_FOLDER "Third Party") +set(CMAKE_POSITION_INDEPENDENT_CODE ON) + +FetchContent_Declare( + Catch2 + GIT_REPOSITORY https://github.com/catchorg/Catch2.git + GIT_TAG v2.11.0 + GIT_SHALLOW TRUE + ) +FetchContent_Declare( + fmt + GIT_REPOSITORY https://github.com/fmtlib/fmt.git + GIT_TAG 8d78045e7cb44d39ad4cd95dd27816b8749e1944 + ) +FetchContent_Declare( + nlohmann_json + GIT_REPOSITORY https://github.com/nlohmann/json.git + GIT_TAG v3.7.3 + GIT_SHALLOW TRUE + ) +FetchContent_Declare( + absl + GIT_REPOSITORY https://github.com/abseil/abseil-cpp.git + GIT_TAG 768eb2ca2857342673fcd462792ce04b8bac3fa3 +) + +# This is a hack because absl has dumb cmake +set(OLD_BUILD_TEST ${BUILD_TESTING}) +set(BUILD_TESTING OFF) +FetchContent_MakeAvailable(absl) +set(BUILD_TESTING ${OLD_BUILD_TEST}) + +# Supress warnings inside abseil under MSVC +if(WINDOWS) + target_compile_options(absl_strings PRIVATE /wd4018) + target_compile_options(absl_str_format_internal PRIVATE /wd4018) + target_compile_options(absl_flags_usage_internal PRIVATE /wd4018) +endif() + + +if (BUILD_TESTING) + FetchContent_MakeAvailable(Catch2) +endif() + +#Download the rest of the libraries +FetchContent_MakeAvailable(fmt) + +# Typically you don't care so much for a third party library's tests to be +# run from your own project's code. +set(JSON_BuildTests OFF CACHE INTERNAL "") + +# If you only include this third party in PRIVATE source files, you do not +# need to install it when your main project gets installed. +set(JSON_Install OFF CACHE INTERNAL "") +FetchContent_MakeAvailable(nlohmann_json) + +unset(CMAKE_FOLDER) +unset(CMAKE_POSITION_INDEPENDENT_CODE) diff --git a/indra/develop.py b/indra/develop.py deleted file mode 100755 index 853c37e144..0000000000 --- a/indra/develop.py +++ /dev/null @@ -1,838 +0,0 @@ -#!/usr/bin/env python -# -# @file develop.py -# @authors Bryan O'Sullivan, Mark Palange, Aaron Brashears -# @brief Fire and forget script to appropriately configure cmake for SL. -# -# $LicenseInfo:firstyear=2007&license=viewergpl$ -# -# Copyright (c) 2007-2009, Linden Research, Inc. -# -# Second Life Viewer Source Code -# The source code in this file ("Source Code") is provided by Linden Lab -# to you under the terms of the GNU General Public License, version 2.0 -# ("GPL"), unless you have obtained a separate licensing agreement -# ("Other License"), formally executed by you and Linden Lab. Terms of -# the GPL can be found in doc/GPL-license.txt in this distribution, or -# online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 -# -# There are special exceptions to the terms and conditions of the GPL as -# it is applied to this Source Code. View the full text of the exception -# in the file doc/FLOSS-exception.txt in this software distribution, or -# online at -# http://secondlifegrid.net/programs/open_source/licensing/flossexception -# -# By copying, modifying or distributing this software, you acknowledge -# that you have read and understood your obligations described above, -# and agree to abide by those obligations. -# -# ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO -# WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, -# COMPLETENESS OR PERFORMANCE. -# $/LicenseInfo$ - - -import errno -import getopt -import os -import random -import re -import shutil -import socket -import sys -import commands - -class CommandError(Exception): - pass - -def mkdir(path): - try: - os.mkdir(path) - return path - except OSError, err: - if err.errno != errno.EEXIST or not os.path.isdir(path): - raise - -def prettyprint_path_for_cmake(path): - if 'a' <= path[0] <= 'z' and path[1] == ':': - # CMake wants DOS drive letters to be in uppercase. The above - # condition never asserts on platforms whose full path names - # always begin with a slash, so we don't need to test whether - # we are running on Windows. - path = path[0].upper() + path[1:] - return path - -def getcwd(): - return prettyprint_path_for_cmake(os.getcwd()) - -source_indra = prettyprint_path_for_cmake(os.path.dirname(os.path.realpath(__file__))) - -def quote(opts): - return '"' + '" "'.join([ opt.replace('"', '') for opt in opts ]) + '"' - -class PlatformSetup(object): - generator = None - build_types = {} - for t in ('Debug', 'Release', 'RelWithDebInfo'): - build_types[t.lower()] = t - - build_type = build_types['relwithdebinfo'] - standalone = 'OFF' - unattended = 'OFF' - universal = 'OFF' - project_name = 'Singularity' - distcc = True - cmake_opts = [] - word_size = 32 - using_express = False - - def __init__(self): - self.script_dir = os.path.realpath( - os.path.dirname(__import__(__name__).__file__)) - - def os(self): - '''Return the name of the OS.''' - - raise NotImplemented('os') - - def arch(self): - '''Return the CPU architecture.''' - - return None - - def platform(self): - '''Return a stringified two-tuple of the OS name and CPU - architecture.''' - - ret = self.os() - if self.arch(): - ret += '-' + self.arch() - return ret - - def build_dirs(self): - '''Return the top-level directories in which builds occur. - - This can return more than one directory, e.g. if doing a - 32-bit viewer and server build on Linux.''' - - return ['build-' + self.platform()] - - def cmake_commandline(self, src_dir, build_dir, opts, simple): - '''Return the command line to run cmake with.''' - - args = dict( - dir=src_dir, - generator=self.generator, - opts=quote(opts), - standalone=self.standalone, - unattended=self.unattended, - word_size=self.word_size, - type=self.build_type.upper(), - ) - #if simple: - # return 'cmake %(opts)s %(dir)r' % args - return ('cmake -DCMAKE_BUILD_TYPE:STRING=%(type)s ' - '-DSTANDALONE:BOOL=%(standalone)s ' - '-DUNATTENDED:BOOL=%(unattended)s ' - '-DWORD_SIZE:STRING=%(word_size)s ' - '-G %(generator)r %(opts)s %(dir)r' % args) - - def run_cmake(self, args=[]): - '''Run cmake.''' - - # do a sanity check to make sure we have a generator - if not hasattr(self, 'generator'): - raise "No generator available for '%s'" % (self.__name__,) - cwd = getcwd() - created = [] - try: - for d in self.build_dirs(): - simple = True - if mkdir(d): - created.append(d) - simple = False - try: - os.chdir(d) - cmd = self.cmake_commandline(source_indra, d, args, simple) - print 'Running %r in %r' % (cmd, d) - self.run(cmd, 'cmake') - finally: - os.chdir(cwd) - except: - # If we created a directory in which to run cmake and - # something went wrong, the directory probably just - # contains garbage, so delete it. - os.chdir(cwd) - for d in created: - print 'Cleaning %r' % d - shutil.rmtree(d) - raise - - def parse_build_opts(self, arguments): - opts, targets = getopt.getopt(arguments, 'o:', ['option=']) - build_opts = [] - for o, a in opts: - if o in ('-o', '--option'): - build_opts.append(a) - return build_opts, targets - - def run_build(self, opts, targets): - '''Build the default targets for this platform.''' - - raise NotImplemented('run_build') - - def cleanup(self): - '''Delete all build directories.''' - - cleaned = 0 - for d in self.build_dirs(): - if os.path.isdir(d): - print 'Cleaning %r' % d - shutil.rmtree(d) - cleaned += 1 - if not cleaned: - print 'Nothing to clean up!' - - def is_internal_tree(self): - '''Indicate whether we are building in an internal source tree.''' - - return os.path.isdir(os.path.join(self.script_dir, 'newsim')) - - def find_in_path(self, name, defval=None, basename=False): - for ext in self.exe_suffixes: - name_ext = name + ext - if os.sep in name_ext: - path = os.path.abspath(name_ext) - if os.access(path, os.X_OK): - return [basename and os.path.basename(path) or path] - for p in os.getenv('PATH', self.search_path).split(os.pathsep): - path = os.path.join(p, name_ext) - if os.access(path, os.X_OK): - return [basename and os.path.basename(path) or path] - if defval: - return [defval] - return [] - - -class UnixSetup(PlatformSetup): - '''Generic Unixy build instructions.''' - - search_path = '/usr/bin:/usr/local/bin' - exe_suffixes = ('',) - - def __init__(self): - super(UnixSetup, self).__init__() - self.generator = 'Unix Makefiles' - - def os(self): - return 'unix' - - def arch(self): - cpu = os.uname()[-1] - if cpu.endswith('386'): - cpu = 'i386' - elif cpu.endswith('86'): - cpu = 'i686' - elif cpu in ('athlon',): - cpu = 'i686' - elif cpu == 'Power Macintosh': - cpu = 'ppc' - elif cpu == 'x86_64' and self.word_size == 32: - cpu = 'i686' - return cpu - - def run(self, command, name=None): - '''Run a program. If the program fails, raise an exception.''' - ret = os.system(command) - if ret: - if name is None: - name = command.split(None, 1)[0] - if os.WIFEXITED(ret): - st = os.WEXITSTATUS(ret) - if st == 127: - event = 'was not found' - else: - event = 'exited with status %d' % st - elif os.WIFSIGNALED(ret): - event = 'was killed by signal %d' % os.WTERMSIG(ret) - else: - event = 'died unexpectedly (!?) with 16-bit status %d' % ret - raise CommandError('the command %r %s' % - (name, event)) - - -class LinuxSetup(UnixSetup): - def __init__(self): - super(LinuxSetup, self).__init__() - try: - self.debian_sarge = open('/etc/debian_version').read().strip() == '3.1' - except: - self.debian_sarge = False - - def os(self): - return 'linux' - - def build_dirs(self): - platform_build = '%s-%s' % (self.platform(), self.build_type.lower()) - - return ['viewer-' + platform_build] - - def cmake_commandline(self, src_dir, build_dir, opts, simple): - args = dict( - dir=src_dir, - generator=self.generator, - opts=quote(opts), - standalone=self.standalone, - unattended=self.unattended, - type=self.build_type.upper(), - project_name=self.project_name, - word_size=self.word_size, - cxx="g++" - ) - - cmd = (('cmake -DCMAKE_BUILD_TYPE:STRING=%(type)s ' - '-G %(generator)r -DSTANDALONE:BOOL=%(standalone)s ' - '-DWORD_SIZE:STRING=%(word_size)s ' - '-DROOT_PROJECT_NAME:STRING=%(project_name)s ' - '%(opts)s %(dir)r') - % args) - if 'CXX' not in os.environ: - args.update({'cmd':cmd}) - cmd = ('CXX=%(cxx)r %(cmd)s' % args) - return cmd - - def run_build(self, opts, targets): - job_count = None - - for i in range(len(opts)): - if opts[i].startswith('-j'): - try: - job_count = int(opts[i][2:]) - except ValueError: - try: - job_count = int(opts[i+1]) - except ValueError: - job_count = True - - def get_cpu_count(): - count = 0 - for line in open('/proc/cpuinfo'): - if re.match(r'processor\s*:', line): - count += 1 - return count - - def localhost(): - count = get_cpu_count() - return 'localhost/' + str(count), count - - def get_distcc_hosts(): - try: - hosts = [] - name = os.getenv('DISTCC_DIR', '/etc/distcc') + '/hosts' - for l in open(name): - l = l[l.find('#')+1:].strip() - if l: hosts.append(l) - return hosts - except IOError: - return (os.getenv('DISTCC_HOSTS', '').split() or - [localhost()[0]]) - - def count_distcc_hosts(): - cpus = 0 - hosts = 0 - for host in get_distcc_hosts(): - m = re.match(r'.*/(\d+)', host) - hosts += 1 - cpus += m and int(m.group(1)) or 1 - return hosts, cpus - - def mk_distcc_hosts(basename, range, num_cpus): - '''Generate a list of LL-internal machines to build on.''' - loc_entry, cpus = localhost() - hosts = [loc_entry] - dead = [] - stations = [s for s in xrange(range) if s not in dead] - random.shuffle(stations) - hosts += ['%s%d.lindenlab.com/%d,lzo' % (basename, s, num_cpus) for s in stations] - cpus += 2 * len(stations) - return ' '.join(hosts), cpus - - if job_count is None: - hosts, job_count = count_distcc_hosts() - if hosts == 1: - hostname = socket.gethostname() - if hostname.startswith('station'): - hosts, job_count = mk_distcc_hosts('station', 36, 2) - os.environ['DISTCC_HOSTS'] = hosts - if hostname.startswith('eniac'): - hosts, job_count = mk_distcc_hosts('eniac', 71, 2) - os.environ['DISTCC_HOSTS'] = hosts - if job_count > 4: - job_count = 4; - opts.extend(['-j', str(job_count)]) - - if targets: - targets = ' '.join(targets) - else: - targets = 'all' - - for d in self.build_dirs(): - cmd = 'make -C %r %s %s' % (d, ' '.join(opts), targets) - print 'Running %r' % cmd - self.run(cmd) - - -class DarwinSetup(UnixSetup): - def __init__(self): - super(DarwinSetup, self).__init__() - self.generator = 'Xcode' - - def os(self): - return 'darwin' - - def arch(self): - if self.universal == 'ON': - return 'universal' - else: - return UnixSetup.arch(self) - - def cmake_commandline(self, src_dir, build_dir, opts, simple): - args = dict( - dir=src_dir, - generator=self.generator, - opts=quote(opts), - standalone=self.standalone, - word_size=self.word_size, - unattended=self.unattended, - project_name=self.project_name, - universal=self.universal, - type=self.build_type.upper(), - ) - if self.universal == 'ON': - args['universal'] = '-DCMAKE_OSX_ARCHITECTURES:STRING=\'i386;ppc\'' - #if simple: - # return 'cmake %(opts)s %(dir)r' % args - return ('cmake -G %(generator)r ' - '-DCMAKE_BUILD_TYPE:STRING=%(type)s ' - '-DSTANDALONE:BOOL=%(standalone)s ' - '-DUNATTENDED:BOOL=%(unattended)s ' - '-DWORD_SIZE:STRING=%(word_size)s ' - '-DROOT_PROJECT_NAME:STRING=%(project_name)s ' - '%(universal)s ' - '%(opts)s %(dir)r' % args) - - def run_build(self, opts, targets): - cwd = getcwd() - if targets: - targets = ' '.join(['-target ' + repr(t) for t in targets]) - else: - targets = '' - cmd = ('xcodebuild -configuration %s %s %s' % - (self.build_type, ' '.join(opts), targets)) - for d in self.build_dirs(): - try: - os.chdir(d) - print 'Running %r in %r' % (cmd, d) - self.run(cmd) - finally: - os.chdir(cwd) - - -class WindowsSetup(PlatformSetup): - gens = { - 'vc100' : { - 'gen' : r'Visual Studio 10', - 'ver' : r'10.0' - } - } - gens['vs2010'] = gens['vc100'] - - search_path = r'C:\windows' - exe_suffixes = ('.exe', '.bat', '.com') - - def __init__(self): - super(WindowsSetup, self).__init__() - self._generator = None - self.incredibuild = False - - def _get_generator(self): - if self._generator is None: - for version in 'vc100'.split(): - if self.find_visual_studio(version): - self._generator = version - print 'Building with ', self.gens[version]['gen'] - break - else: - print >> sys.stderr, 'Cannot find a Visual Studio installation, testing for express editions' - for version in 'vc100'.split(): - if self.find_visual_studio_express(version): - self._generator = version - self.using_express = True - print 'Building with ', self.gens[version]['gen'] , "Express edition" - break - else: - for version in 'vc100'.split(): - if self.find_visual_studio_express_single(version): - self._generator = version - self.using_express = True - print 'Building with ', self.gens[version]['gen'] , "Express edition" - break - else: - print >> sys.stderr, 'Cannot find any Visual Studio installation' - sys.exit(1) - return self._generator - - def _set_generator(self, gen): - self._generator = gen - - generator = property(_get_generator, _set_generator) - - def os(self): - return 'win32' - - def build_dirs(self): - return ['build-' + self.generator] - - def cmake_commandline(self, src_dir, build_dir, opts, simple): - args = dict( - dir=src_dir, - generator=self.gens[self.generator.lower()]['gen'], - opts=quote(opts), - standalone=self.standalone, - unattended=self.unattended, - project_name=self.project_name, - word_size=self.word_size, - ) - #if simple: - # return 'cmake %(opts)s "%(dir)s"' % args - return ('cmake -G "%(generator)s" ' - '-DSTANDALONE:BOOL=%(standalone)s ' - '-DUNATTENDED:BOOL=%(unattended)s ' - '-DWORD_SIZE:STRING=%(word_size)s ' - '-DROOT_PROJECT_NAME:STRING=%(project_name)s ' - '%(opts)s "%(dir)s"' % args) - - def get_HKLM_registry_value(self, key_str, value_str): - import _winreg - reg = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE) - key = _winreg.OpenKey(reg, key_str) - value = _winreg.QueryValueEx(key, value_str)[0] - print 'Found: %s' % value - return value - - def find_visual_studio(self, gen=None): - if gen is None: - gen = self._generator - gen = gen.lower() - value_str = (r'EnvironmentDirectory') - key_str = (r'SOFTWARE\Microsoft\VisualStudio\%s\Setup\VS' % - self.gens[gen]['ver']) - print ('Reading VS environment from HKEY_LOCAL_MACHINE\%s\%s' % - (key_str, value_str)) - try: - return self.get_HKLM_registry_value(key_str, value_str) - except WindowsError, err: - key_str = (r'SOFTWARE\Wow6432Node\Microsoft\VisualStudio\%s\Setup\VS' % - self.gens[gen]['ver']) - - try: - return self.get_HKLM_registry_value(key_str, value_str) - except: - print >> sys.stderr, "Didn't find ", self.gens[gen]['gen'] - return '' - - def find_visual_studio_express(self, gen=None): - if gen is None: - gen = self._generator - gen = gen.lower() - try: - import _winreg - key_str = (r'SOFTWARE\Microsoft\VCEXpress\%s\Setup\VC' % - self.gens[gen]['ver']) - value_str = (r'ProductDir') - print ('Reading VS environment from HKEY_LOCAL_MACHINE\%s\%s' % - (key_str, value_str)) - print key_str - - reg = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE) - key = _winreg.OpenKey(reg, key_str) - value = _winreg.QueryValueEx(key, value_str)[0]+"IDE" - print 'Found: %s' % value - return value - except WindowsError, err: - print >> sys.stderr, "Didn't find ", self.gens[gen]['gen'] - return '' - - def find_visual_studio_express_single(self, gen=None): - if gen is None: - gen = self._generator - gen = gen.lower() - try: - import _winreg - key_str = (r'SOFTWARE\Microsoft\VCEXpress\%s_Config\Setup\VC' % - self.gens[gen]['ver']) - value_str = (r'ProductDir') - print ('Reading VS environment from HKEY_CURRENT_USER\%s\%s' % - (key_str, value_str)) - print key_str - - reg = _winreg.ConnectRegistry(None, _winreg.HKEY_CURRENT_USER) - key = _winreg.OpenKey(reg, key_str) - value = _winreg.QueryValueEx(key, value_str)[0]+"IDE" - print 'Found: %s' % value - return value - except WindowsError, err: - print >> sys.stderr, "Didn't find ", self.gens[gen]['gen'] - return '' - - def get_build_cmd(self): - if self.incredibuild: - config = self.build_type - if self.gens[self.generator]['ver'] in [ r'8.0', r'9.0' ]: - config = '\"%s|Win32\"' % config - - return "buildconsole %s.sln /build %s" % (self.project_name, config) - environment = self.find_visual_studio() - if environment == '': - environment = self.find_visual_studio_express() - if environment == '': - environment = self.find_visual_studio_express_single() - if environment == '': - print >> sys.stderr, "Something went very wrong during build stage, could not find a Visual Studio?" - else: - build_dirs=self.build_dirs() - print >> sys.stderr, "\nSolution generation complete, it can can now be found in:", build_dirs[0] - print >> sys.stderr, "\nAs you are using an Express Visual Studio, the build step cannot be automated" - print >> sys.stderr, "\nPlease see https://wiki.secondlife.com/wiki/Microsoft_Visual_Studio#Extra_steps_for_Visual_Studio_Express_editions for Visual Studio Express specific information" - exit(0) - - # devenv.com is CLI friendly, devenv.exe... not so much. - return ('"%sdevenv.com" %s.sln /build %s' % - (self.find_visual_studio(), self.project_name, self.build_type)) - - def run(self, command, name=None): - '''Run a program. If the program fails, raise an exception.''' - ret = os.system(command) - if ret: - if name is None: - name = command.split(None, 1)[0] - path = self.find_in_path(name) - if not path: - ret = 'was not found' - else: - ret = 'exited with status %d' % ret - raise CommandError('the command %r %s' % - (name, ret)) - - def run_cmake(self, args=[]): - '''Override to add the vstool.exe call after running cmake.''' - PlatformSetup.run_cmake(self, args) - if self.unattended == 'OFF': - if self.using_express == False: - self.run_vstool() - - def run_vstool(self): - for build_dir in self.build_dirs(): - stamp = os.path.join(build_dir, 'vstool.txt') - try: - prev_build = open(stamp).read().strip() - except IOError: - prev_build = '' - if prev_build == self.build_type: - # Only run vstool if the build type has changed. - continue - vstool_cmd = (os.path.join('tools','vstool','VSTool.exe') + - ' --solution ' + - os.path.join(build_dir,'Singularity.sln') + - ' --config ' + self.build_type + - ' --startup secondlife-bin') - print 'Running %r in %r' % (vstool_cmd, getcwd()) - self.run(vstool_cmd) - print >> open(stamp, 'w'), self.build_type - - def run_build(self, opts, targets): - cwd = getcwd() - build_cmd = self.get_build_cmd() - - for d in self.build_dirs(): - try: - os.chdir(d) - if targets: - for t in targets: - cmd = '%s /project %s %s' % (build_cmd, t, ' '.join(opts)) - print 'Running %r in %r' % (cmd, d) - self.run(cmd) - else: - cmd = '%s %s' % (build_cmd, ' '.join(opts)) - print 'Running %r in %r' % (cmd, d) - self.run(cmd) - finally: - os.chdir(cwd) - -class CygwinSetup(WindowsSetup): - def __init__(self): - super(CygwinSetup, self).__init__() - self.generator = 'vc80' - - def cmake_commandline(self, src_dir, build_dir, opts, simple): - dos_dir = commands.getoutput("cygpath -w %s" % src_dir) - args = dict( - dir=dos_dir, - generator=self.gens[self.generator.lower()]['gen'], - opts=quote(opts), - standalone=self.standalone, - unattended=self.unattended, - project_name=self.project_name, - word_size=self.word_size, - ) - #if simple: - # return 'cmake %(opts)s "%(dir)s"' % args - return ('cmake -G "%(generator)s" ' - '-DUNATTENDED:BOOl=%(unattended)s ' - '-DSTANDALONE:BOOL=%(standalone)s ' - '-DWORD_SIZE:STRING=%(word_size)s ' - '-DROOT_PROJECT_NAME:STRING=%(project_name)s ' - '%(opts)s "%(dir)s"' % args) - -setup_platform = { - 'darwin': DarwinSetup, - 'linux2': LinuxSetup, - 'linux3': LinuxSetup, - 'win32' : WindowsSetup, - 'cygwin' : CygwinSetup - } - - -usage_msg = ''' -Usage: develop.py [options] [command [command-options]] - -Options: - -h | --help print this help message - --standalone build standalone, without Linden prebuild libraries - --unattended build unattended, do not invoke any tools requiring - a human response - --universal build a universal binary on Mac OS X (unsupported) - -t | --type=NAME build type ("Debug", "Release", or "RelWithDebInfo") - -m32 | -m64 build architecture (32-bit or 64-bit) - -N | --no-distcc disable use of distcc - -G | --generator=NAME generator name - Windows: VC100 (VS2010) (default) - Mac OS X: Xcode (default), Unix Makefiles - Linux: Unix Makefiles (default), KDevelop3 - -p | --project=NAME set the root project name. (Doesn't effect makefiles) - -Commands: - build configure and build default target - clean delete all build directories, does not affect sources - configure configure project by running cmake (default if none given) - printbuilddirs print the build directory that will be used - -Command-options for "configure": - We use cmake variables to change the build configuration. - -DPACKAGE:BOOL=ON Create "package" target to make installers - -DLOCALIZESETUP:BOOL=ON Create one win_setup target per supported language - -DLL_TESTS:BOOL=OFF Don't generate unit test projects - -DEXAMPLEPLUGIN:BOOL=OFF Don't generate example plugin project - -DDISABLE_TCMALLOC:BOOL=ON Disable linkage of TCMalloc. (64bit builds automatically disable TCMalloc) - -Examples: - Set up a Visual Studio 2010 project with "package" target: - develop.py -G vc100 configure -DPACKAGE:BOOL=ON -''' - -def main(arguments): - setup = setup_platform[sys.platform]() - try: - opts, args = getopt.getopt( - arguments, - '?hNt:p:G:m:', - ['help', 'standalone', 'no-distcc', 'unattended', 'type=', 'incredibuild', 'generator=', 'project=']) - except getopt.GetoptError, err: - print >> sys.stderr, 'Error:', err - print >> sys.stderr, """ -Note: You must pass -D options to cmake after the "configure" command -For example: develop.py configure -DSERVER:BOOL=OFF""" - print >> sys.stderr, usage_msg.strip() - sys.exit(1) - - for o, a in opts: - if o in ('-?', '-h', '--help'): - print usage_msg.strip() - sys.exit(0) - elif o in ('--standalone',): - setup.standalone = 'ON' - elif o in ('--unattended',): - setup.unattended = 'ON' - elif o in ('-m',): - if a in ('32', '64'): - setup.word_size = int(a) - else: - print >> sys.stderr, 'Error: unknown word size', repr(a) - print >> sys.stderr, 'Supported word sizes: 32, 64' - sys.exit(1) - elif o in ('-t', '--type'): - try: - setup.build_type = setup.build_types[a.lower()] - except KeyError: - print >> sys.stderr, 'Error: unknown build type', repr(a) - print >> sys.stderr, 'Supported build types:' - types = setup.build_types.values() - types.sort() - for t in types: - print ' ', t - sys.exit(1) - elif o in ('-G', '--generator'): - setup.generator = a - elif o in ('-N', '--no-distcc'): - setup.distcc = False - elif o in ('-p', '--project'): - setup.project_name = a - elif o in ('--incredibuild'): - setup.incredibuild = True - else: - print >> sys.stderr, 'INTERNAL ERROR: unhandled option', repr(o) - sys.exit(1) - if not args: - setup.run_cmake() - return - try: - cmd = args.pop(0) - if cmd in ('cmake', 'configure'): - setup.run_cmake(args) - elif cmd == 'build': - if os.getenv('DISTCC_DIR') is None: - distcc_dir = os.path.join(getcwd(), '.distcc') - if not os.path.exists(distcc_dir): - os.mkdir(distcc_dir) - print "setting DISTCC_DIR to %s" % distcc_dir - os.environ['DISTCC_DIR'] = distcc_dir - else: - print "DISTCC_DIR is set to %s" % os.getenv('DISTCC_DIR') - for d in setup.build_dirs(): - if not os.path.exists(d): - raise CommandError('run "develop.py cmake" first') - setup.run_cmake() - opts, targets = setup.parse_build_opts(args) - setup.run_build(opts, targets) - elif cmd == 'clean': - if args: - raise CommandError('clean takes no arguments') - setup.cleanup() - elif cmd == 'printbuilddirs': - for d in setup.build_dirs(): - print >> sys.stdout, d - else: - print >> sys.stderr, 'Error: unknown subcommand', repr(cmd) - print >> sys.stderr, "(run 'develop.py --help' for help)" - sys.exit(1) - except getopt.GetoptError, err: - print >> sys.stderr, 'Error with %r subcommand: %s' % (cmd, err) - sys.exit(1) - - -if __name__ == '__main__': - try: - main(sys.argv[1:]) - except CommandError, err: - print >> sys.stderr, 'Error:', err - sys.exit(1) diff --git a/indra/lib/python/indra/__init__.py b/indra/lib/python/indra/__init__.py index 9daab34803..0c5053cf49 100644 --- a/indra/lib/python/indra/__init__.py +++ b/indra/lib/python/indra/__init__.py @@ -2,19 +2,24 @@ @file __init__.py @brief Initialization file for the indra module. -$LicenseInfo:firstyear=2006&license=internal$ +$LicenseInfo:firstyear=2006&license=viewerlgpl$ +Second Life Viewer Source Code +Copyright (C) 2006-2010, Linden Research, Inc. -Copyright (c) 2006-2009, 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. -The following source code is PROPRIETARY AND CONFIDENTIAL. Use of -this source code is governed by the Linden Lab Source Code Disclosure -Agreement ("Agreement") previously entered between you and Linden -Lab. By accessing, using, copying, modifying or distributing this -software, you acknowledge that you have been informed of your -obligations under the Agreement and agree to abide by those obligations. +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. -ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO -WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, -COMPLETENESS OR PERFORMANCE. +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$ """ diff --git a/indra/lib/python/indra/base/__init__.py b/indra/lib/python/indra/base/__init__.py deleted file mode 100644 index 2904fd3380..0000000000 --- a/indra/lib/python/indra/base/__init__.py +++ /dev/null @@ -1,27 +0,0 @@ -"""\ -@file __init__.py -@brief Initialization file for the indra.base module. - -$LicenseInfo:firstyear=2007&license=mit$ - -Copyright (c) 2007-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" diff --git a/indra/lib/python/indra/base/cllsd_test.py b/indra/lib/python/indra/base/cllsd_test.py deleted file mode 100644 index 3af59e741a..0000000000 --- a/indra/lib/python/indra/base/cllsd_test.py +++ /dev/null @@ -1,51 +0,0 @@ -from indra.base import llsd, lluuid -from datetime import datetime -import cllsd -import time, sys - -class myint(int): - pass - -values = ( - '&<>', - u'\u81acj', - llsd.uri('http://foo<'), - lluuid.LLUUID(), - llsd.LLSD(['thing']), - 1, - myint(31337), - sys.maxint + 10, - llsd.binary('foo'), - [], - {}, - {u'f&\u1212': 3}, - 3.1, - True, - None, - datetime.fromtimestamp(time.time()), - ) - -def valuator(values): - for v in values: - yield v - -longvalues = () # (values, list(values), iter(values), valuator(values)) - -for v in values + longvalues: - print '%r => %r' % (v, cllsd.llsd_to_xml(v)) - -a = [[{'a':3}]] * 1000000 - -s = time.time() -print hash(cllsd.llsd_to_xml(a)) -e = time.time() -t1 = e - s -print t1 - -s = time.time() -print hash(llsd.LLSDXMLFormatter()._format(a)) -e = time.time() -t2 = e - s -print t2 - -print 'Speedup:', t2 / t1 diff --git a/indra/lib/python/indra/base/config.py b/indra/lib/python/indra/base/config.py deleted file mode 100644 index adafa29b51..0000000000 --- a/indra/lib/python/indra/base/config.py +++ /dev/null @@ -1,266 +0,0 @@ -"""\ -@file config.py -@brief Utility module for parsing and accessing the indra.xml config file. - -$LicenseInfo:firstyear=2006&license=mit$ - -Copyright (c) 2006-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -import copy -import errno -import os -import traceback -import time -import types - -from os.path import dirname, getmtime, join, realpath -from indra.base import llsd - -_g_config = None - -class IndraConfig(object): - """ - IndraConfig loads a 'indra' xml configuration file - and loads into memory. This representation in memory - can get updated to overwrite values or add new values. - - The xml configuration file is considered a live file and changes - to the file are checked and reloaded periodically. If a value had - been overwritten via the update or set method, the loaded values - from the file are ignored (the values from the update/set methods - override) - """ - def __init__(self, indra_config_file): - self._indra_config_file = indra_config_file - self._reload_check_interval = 30 # seconds - self._last_check_time = 0 - self._last_mod_time = 0 - - self._config_overrides = {} - self._config_file_dict = {} - self._combined_dict = {} - - self._load() - - def _load(self): - # if you initialize the IndraConfig with None, no attempt - # is made to load any files - if self._indra_config_file is None: - return - - config_file = open(self._indra_config_file) - self._config_file_dict = llsd.parse(config_file.read()) - self._combine_dictionaries() - config_file.close() - - self._last_mod_time = self._get_last_modified_time() - self._last_check_time = time.time() # now - - def _get_last_modified_time(self): - """ - Returns the mtime (last modified time) of the config file, - if such exists. - """ - if self._indra_config_file is not None: - return os.path.getmtime(self._indra_config_file) - - return 0 - - def _combine_dictionaries(self): - self._combined_dict = {} - self._combined_dict.update(self._config_file_dict) - self._combined_dict.update(self._config_overrides) - - def _reload_if_necessary(self): - now = time.time() - - if (now - self._last_check_time) > self._reload_check_interval: - self._last_check_time = now - try: - modtime = self._get_last_modified_time() - if modtime > self._last_mod_time: - self._load() - except OSError, e: - if e.errno == errno.ENOENT: # file not found - # someone messed with our internal state - # or removed the file - - print 'WARNING: Configuration file has been removed ' + (self._indra_config_file) - print 'Disabling reloading of configuration file.' - - traceback.print_exc() - - self._indra_config_file = None - self._last_check_time = 0 - self._last_mod_time = 0 - else: - raise # pass the exception along to the caller - - def __getitem__(self, key): - self._reload_if_necessary() - - return self._combined_dict[key] - - def get(self, key, default = None): - try: - return self.__getitem__(key) - except KeyError: - return default - - def __setitem__(self, key, value): - """ - Sets the value of the config setting of key to be newval - - Once any key/value pair is changed via the set method, - that key/value pair will remain set with that value until - change via the update or set method - """ - self._config_overrides[key] = value - self._combine_dictionaries() - - def set(self, key, newval): - return self.__setitem__(key, newval) - - def update(self, new_conf): - """ - Load an XML file and apply its map as overrides or additions - to the existing config. Update can be a file or a dict. - - Once any key/value pair is changed via the update method, - that key/value pair will remain set with that value until - change via the update or set method - """ - if isinstance(new_conf, dict): - overrides = new_conf - else: - # assuming that it is a filename - config_file = open(new_conf) - overrides = llsd.parse(config_file.read()) - config_file.close() - - self._config_overrides.update(overrides) - self._combine_dictionaries() - - def as_dict(self): - """ - Returns immutable copy of the IndraConfig as a dictionary - """ - return copy.deepcopy(self._combined_dict) - -def load(config_xml_file = None): - global _g_config - - load_default_files = config_xml_file is None - if load_default_files: - ## going from: - ## "/opt/linden/indra/lib/python/indra/base/config.py" - ## to: - ## "/opt/linden/etc/indra.xml" - config_xml_file = realpath( - dirname(realpath(__file__)) + "../../../../../../etc/indra.xml") - - try: - _g_config = IndraConfig(config_xml_file) - except IOError: - # Failure to load passed in file - # or indra.xml default file - if load_default_files: - try: - config_xml_file = realpath( - dirname(realpath(__file__)) + "../../../../../../etc/globals.xml") - _g_config = IndraConfig(config_xml_file) - return - except IOError: - # Failure to load globals.xml - # fall to code below - pass - - # Either failed to load passed in file - # or failed to load all default files - _g_config = IndraConfig(None) - -def dump(indra_xml_file, indra_cfg = None, update_in_mem=False): - ''' - Dump config contents into a file - Kindof reverse of load. - Optionally takes a new config to dump. - Does NOT update global config unless requested. - ''' - global _g_config - - if not indra_cfg: - if _g_config is None: - return - - indra_cfg = _g_config.as_dict() - - if not indra_cfg: - return - - config_file = open(indra_xml_file, 'w') - _config_xml = llsd.format_xml(indra_cfg) - config_file.write(_config_xml) - config_file.close() - - if update_in_mem: - update(indra_cfg) - -def update(new_conf): - global _g_config - - if _g_config is None: - # To keep with how this function behaved - # previously, a call to update - # before the global is defined - # make a new global config which does not - # load data from a file. - _g_config = IndraConfig(None) - - return _g_config.update(new_conf) - -def get(key, default = None): - global _g_config - - if _g_config is None: - load() - - return _g_config.get(key, default) - -def set(key, newval): - """ - Sets the value of the config setting of key to be newval - - Once any key/value pair is changed via the set method, - that key/value pair will remain set with that value until - change via the update or set method or program termination - """ - global _g_config - - if _g_config is None: - _g_config = IndraConfig(None) - - _g_config.set(key, newval) - -def get_config(): - global _g_config - return _g_config diff --git a/indra/lib/python/indra/base/lllog.py b/indra/lib/python/indra/base/lllog.py deleted file mode 100644 index 31000fcb9a..0000000000 --- a/indra/lib/python/indra/base/lllog.py +++ /dev/null @@ -1,72 +0,0 @@ -"""\ -@file lllog.py -@brief Logging for event processing - -$LicenseInfo:firstyear=2008&license=mit$ - -Copyright (c) 2008-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -from indra.base.llsd import format_notation - -try: - import syslog -except ImportError: - # Windows - import sys - - class syslog(object): - _logfp = sys.stderr - - def syslog(msg): - _logfp.write(msg) - if not msg.endswith('\n'): - _logfp.write('\n') - - syslog = staticmethod(syslog) - -class Logger(object): - def __init__(self, name='indra'): - self._sequence = 0 - try: - syslog.openlog(name, syslog.LOG_CONS | syslog.LOG_PID, - syslog.LOG_LOCAL0) - except AttributeError: - # No syslog module on Windows - pass - - def next(self): - self._sequence += 1 - return self._sequence - - def log(self, msg, llsd): - payload = 'INFO: log: LLLOGMESSAGE (%d) %s %s' % (self.next(), msg, - format_notation(llsd)) - syslog.syslog(payload) - -_logger = None - -def log(msg, llsd): - global _logger - if _logger is None: - _logger = Logger() - _logger.log(msg, llsd) diff --git a/indra/lib/python/indra/base/llsd.py b/indra/lib/python/indra/base/llsd.py deleted file mode 100644 index 9534d5935e..0000000000 --- a/indra/lib/python/indra/base/llsd.py +++ /dev/null @@ -1,1046 +0,0 @@ -"""\ -@file llsd.py -@brief Types as well as parsing and formatting functions for handling LLSD. - -$LicenseInfo:firstyear=2006&license=mit$ - -Copyright (c) 2006-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -import datetime -import base64 -import string -import struct -import time -import types -import re - -from indra.util.fastest_elementtree import ElementTreeError, fromstring -from indra.base import lluuid - -# cllsd.c in server/server-1.25 has memory leaks, -# so disabling cllsd for now -#try: -# import cllsd -#except ImportError: -# cllsd = None -cllsd = None - -int_regex = re.compile(r"[-+]?\d+") -real_regex = re.compile(r"[-+]?(\d+(\.\d*)?|\d*\.\d+)([eE][-+]?\d+)?") -alpha_regex = re.compile(r"[a-zA-Z]+") -date_regex = re.compile(r"(?P\d{4})-(?P\d{2})-(?P\d{2})T" - r"(?P\d{2}):(?P\d{2}):(?P\d{2})" - r"(?P(\.\d+)?)Z") -#date: d"YYYY-MM-DDTHH:MM:SS.FFFFFFZ" - -class LLSDParseError(Exception): - pass - -class LLSDSerializationError(TypeError): - pass - - -class binary(str): - pass - -class uri(str): - pass - - -BOOL_TRUE = ('1', '1.0', 'true') -BOOL_FALSE = ('0', '0.0', 'false', '') - - -def format_datestr(v): - """ Formats a datetime object into the string format shared by xml and notation serializations.""" - return v.isoformat() + 'Z' - -def parse_datestr(datestr): - """Parses a datetime object from the string format shared by xml and notation serializations.""" - if datestr == "": - return datetime.datetime(1970, 1, 1) - - match = re.match(date_regex, datestr) - if not match: - raise LLSDParseError("invalid date string '%s'." % datestr) - - year = int(match.group('year')) - month = int(match.group('month')) - day = int(match.group('day')) - hour = int(match.group('hour')) - minute = int(match.group('minute')) - second = int(match.group('second')) - seconds_float = match.group('second_float') - microsecond = 0 - if seconds_float: - microsecond = int(float('0' + seconds_float) * 1e6) - return datetime.datetime(year, month, day, hour, minute, second, microsecond) - - -def bool_to_python(node): - val = node.text or '' - if val in BOOL_TRUE: - return True - else: - return False - -def int_to_python(node): - val = node.text or '' - if not val.strip(): - return 0 - return int(val) - -def real_to_python(node): - val = node.text or '' - if not val.strip(): - return 0.0 - return float(val) - -def uuid_to_python(node): - return lluuid.UUID(node.text) - -def str_to_python(node): - return node.text or '' - -def bin_to_python(node): - return binary(base64.decodestring(node.text or '')) - -def date_to_python(node): - val = node.text or '' - if not val: - val = "1970-01-01T00:00:00Z" - return parse_datestr(val) - - -def uri_to_python(node): - val = node.text or '' - if not val: - return None - return uri(val) - -def map_to_python(node): - result = {} - for index in range(len(node))[::2]: - result[node[index].text] = to_python(node[index+1]) - return result - -def array_to_python(node): - return [to_python(child) for child in node] - - -NODE_HANDLERS = dict( - undef=lambda x: None, - boolean=bool_to_python, - integer=int_to_python, - real=real_to_python, - uuid=uuid_to_python, - string=str_to_python, - binary=bin_to_python, - date=date_to_python, - uri=uri_to_python, - map=map_to_python, - array=array_to_python, - ) - -def to_python(node): - return NODE_HANDLERS[node.tag](node) - -class Nothing(object): - pass - - -class LLSDXMLFormatter(object): - def __init__(self): - self.type_map = { - type(None) : self.UNDEF, - bool : self.BOOLEAN, - int : self.INTEGER, - long : self.INTEGER, - float : self.REAL, - lluuid.UUID : self.UUID, - binary : self.BINARY, - str : self.STRING, - unicode : self.STRING, - uri : self.URI, - datetime.datetime : self.DATE, - list : self.ARRAY, - tuple : self.ARRAY, - types.GeneratorType : self.ARRAY, - dict : self.MAP, - LLSD : self.LLSD - } - - def elt(self, name, contents=None): - if(contents is None or contents is ''): - return "<%s />" % (name,) - else: - if type(contents) is unicode: - contents = contents.encode('utf-8') - return "<%s>%s" % (name, contents, name) - - def xml_esc(self, v): - if type(v) is unicode: - v = v.encode('utf-8') - return v.replace('&', '&').replace('<', '<').replace('>', '>') - - def LLSD(self, v): - return self.generate(v.thing) - def UNDEF(self, v): - return self.elt('undef') - def BOOLEAN(self, v): - if v: - return self.elt('boolean', 'true') - else: - return self.elt('boolean', 'false') - def INTEGER(self, v): - return self.elt('integer', v) - def REAL(self, v): - return self.elt('real', v) - def UUID(self, v): - if(v.isNull()): - return self.elt('uuid') - else: - return self.elt('uuid', v) - def BINARY(self, v): - return self.elt('binary', base64.encodestring(v)) - def STRING(self, v): - return self.elt('string', self.xml_esc(v)) - def URI(self, v): - return self.elt('uri', self.xml_esc(str(v))) - def DATE(self, v): - return self.elt('date', format_datestr(v)) - def ARRAY(self, v): - return self.elt('array', ''.join([self.generate(item) for item in v])) - def MAP(self, v): - return self.elt( - 'map', - ''.join(["%s%s" % (self.elt('key', key), self.generate(value)) - for key, value in v.items()])) - - typeof = type - def generate(self, something): - t = self.typeof(something) - if self.type_map.has_key(t): - return self.type_map[t](something) - else: - raise LLSDSerializationError("Cannot serialize unknown type: %s (%s)" % ( - t, something)) - - def _format(self, something): - return '' + self.elt("llsd", self.generate(something)) - - def format(self, something): - if cllsd: - return cllsd.llsd_to_xml(something) - return self._format(something) - -_g_xml_formatter = None -def format_xml(something): - global _g_xml_formatter - if _g_xml_formatter is None: - _g_xml_formatter = LLSDXMLFormatter() - return _g_xml_formatter.format(something) - -class LLSDXMLPrettyFormatter(LLSDXMLFormatter): - def __init__(self, indent_atom = None): - # Call the super class constructor so that we have the type map - super(LLSDXMLPrettyFormatter, self).__init__() - - # Override the type map to use our specialized formatters to - # emit the pretty output. - self.type_map[list] = self.PRETTY_ARRAY - self.type_map[tuple] = self.PRETTY_ARRAY - self.type_map[types.GeneratorType] = self.PRETTY_ARRAY, - self.type_map[dict] = self.PRETTY_MAP - - # Private data used for indentation. - self._indent_level = 1 - if indent_atom is None: - self._indent_atom = ' ' - else: - self._indent_atom = indent_atom - - def _indent(self): - "Return an indentation based on the atom and indentation level." - return self._indent_atom * self._indent_level - - def PRETTY_ARRAY(self, v): - rv = [] - rv.append('\n') - self._indent_level = self._indent_level + 1 - rv.extend(["%s%s\n" % - (self._indent(), - self.generate(item)) - for item in v]) - self._indent_level = self._indent_level - 1 - rv.append(self._indent()) - rv.append('') - return ''.join(rv) - - def PRETTY_MAP(self, v): - rv = [] - rv.append('\n') - self._indent_level = self._indent_level + 1 - keys = v.keys() - keys.sort() - rv.extend(["%s%s\n%s%s\n" % - (self._indent(), - self.elt('key', key), - self._indent(), - self.generate(v[key])) - for key in keys]) - self._indent_level = self._indent_level - 1 - rv.append(self._indent()) - rv.append('') - return ''.join(rv) - - def format(self, something): - data = [] - data.append('\n') - data.append(self.generate(something)) - data.append('\n') - return '\n'.join(data) - -def format_pretty_xml(something): - """@brief Serialize a python object as 'pretty' llsd xml. - - The output conforms to the LLSD DTD, unlike the output from the - standard python xml.dom DOM::toprettyxml() method which does not - preserve significant whitespace. - This function is not necessarily suited for serializing very large - objects. It is not optimized by the cllsd module, and sorts on - dict (llsd map) keys alphabetically to ease human reading. - """ - return LLSDXMLPrettyFormatter().format(something) - -class LLSDNotationFormatter(object): - def __init__(self): - self.type_map = { - type(None) : self.UNDEF, - bool : self.BOOLEAN, - int : self.INTEGER, - long : self.INTEGER, - float : self.REAL, - lluuid.UUID : self.UUID, - binary : self.BINARY, - str : self.STRING, - unicode : self.STRING, - uri : self.URI, - datetime.datetime : self.DATE, - list : self.ARRAY, - tuple : self.ARRAY, - types.GeneratorType : self.ARRAY, - dict : self.MAP, - LLSD : self.LLSD - } - - def LLSD(self, v): - return self.generate(v.thing) - def UNDEF(self, v): - return '!' - def BOOLEAN(self, v): - if v: - return 'true' - else: - return 'false' - def INTEGER(self, v): - return "i%s" % v - def REAL(self, v): - return "r%s" % v - def UUID(self, v): - return "u%s" % v - def BINARY(self, v): - return 'b64"' + base64.encodestring(v) + '"' - def STRING(self, v): - if isinstance(v, unicode): - v = v.encode('utf-8') - return "'%s'" % v.replace("\\", "\\\\").replace("'", "\\'") - def URI(self, v): - return 'l"%s"' % str(v).replace("\\", "\\\\").replace('"', '\\"') - def DATE(self, v): - return 'd"%s"' % format_datestr(v) - def ARRAY(self, v): - return "[%s]" % ','.join([self.generate(item) for item in v]) - def MAP(self, v): - def fix(key): - if isinstance(key, unicode): - return key.encode('utf-8') - return key - return "{%s}" % ','.join(["'%s':%s" % (fix(key).replace("\\", "\\\\").replace("'", "\\'"), self.generate(value)) - for key, value in v.items()]) - - def generate(self, something): - t = type(something) - handler = self.type_map.get(t) - if handler: - return handler(something) - else: - try: - return self.ARRAY(iter(something)) - except TypeError: - raise LLSDSerializationError( - "Cannot serialize unknown type: %s (%s)" % (t, something)) - - def format(self, something): - return self.generate(something) - -def format_notation(something): - return LLSDNotationFormatter().format(something) - -def _hex_as_nybble(hex): - if (hex >= '0') and (hex <= '9'): - return ord(hex) - ord('0') - elif (hex >= 'a') and (hex <='f'): - return 10 + ord(hex) - ord('a') - elif (hex >= 'A') and (hex <='F'): - return 10 + ord(hex) - ord('A'); - -class LLSDBinaryParser(object): - def __init__(self): - pass - - def parse(self, buffer, ignore_binary = False): - """ - This is the basic public interface for parsing. - - @param buffer the binary data to parse in an indexable sequence. - @param ignore_binary parser throws away data in llsd binary nodes. - @return returns a python object. - """ - self._buffer = buffer - self._index = 0 - self._keep_binary = not ignore_binary - return self._parse() - - def _parse(self): - cc = self._buffer[self._index] - self._index += 1 - if cc == '{': - return self._parse_map() - elif cc == '[': - return self._parse_array() - elif cc == '!': - return None - elif cc == '0': - return False - elif cc == '1': - return True - elif cc == 'i': - # 'i' = integer - idx = self._index - self._index += 4 - return struct.unpack("!i", self._buffer[idx:idx+4])[0] - elif cc == ('r'): - # 'r' = real number - idx = self._index - self._index += 8 - return struct.unpack("!d", self._buffer[idx:idx+8])[0] - elif cc == 'u': - # 'u' = uuid - idx = self._index - self._index += 16 - return lluuid.uuid_bits_to_uuid(self._buffer[idx:idx+16]) - elif cc == 's': - # 's' = string - return self._parse_string() - elif cc in ("'", '"'): - # delimited/escaped string - return self._parse_string_delim(cc) - elif cc == 'l': - # 'l' = uri - return uri(self._parse_string()) - elif cc == ('d'): - # 'd' = date in seconds since epoch - idx = self._index - self._index += 8 - seconds = struct.unpack("!d", self._buffer[idx:idx+8])[0] - return datetime.datetime.fromtimestamp(seconds) - elif cc == 'b': - binary = self._parse_string() - if self._keep_binary: - return binary - # *NOTE: maybe have a binary placeholder which has the - # length. - return None - else: - raise LLSDParseError("invalid binary token at byte %d: %d" % ( - self._index - 1, ord(cc))) - - def _parse_map(self): - rv = {} - size = struct.unpack("!i", self._buffer[self._index:self._index+4])[0] - self._index += 4 - count = 0 - cc = self._buffer[self._index] - self._index += 1 - key = '' - while (cc != '}') and (count < size): - if cc == 'k': - key = self._parse_string() - elif cc in ("'", '"'): - key = self._parse_string_delim(cc) - else: - raise LLSDParseError("invalid map key at byte %d." % ( - self._index - 1,)) - value = self._parse() - rv[key] = value - count += 1 - cc = self._buffer[self._index] - self._index += 1 - if cc != '}': - raise LLSDParseError("invalid map close token at byte %d." % ( - self._index,)) - return rv - - def _parse_array(self): - rv = [] - size = struct.unpack("!i", self._buffer[self._index:self._index+4])[0] - self._index += 4 - count = 0 - cc = self._buffer[self._index] - while (cc != ']') and (count < size): - rv.append(self._parse()) - count += 1 - cc = self._buffer[self._index] - if cc != ']': - raise LLSDParseError("invalid array close token at byte %d." % ( - self._index,)) - self._index += 1 - return rv - - def _parse_string(self): - size = struct.unpack("!i", self._buffer[self._index:self._index+4])[0] - self._index += 4 - rv = self._buffer[self._index:self._index+size] - self._index += size - return rv - - def _parse_string_delim(self, delim): - list = [] - found_escape = False - found_hex = False - found_digit = False - byte = 0 - while True: - cc = self._buffer[self._index] - self._index += 1 - if found_escape: - if found_hex: - if found_digit: - found_escape = False - found_hex = False - found_digit = False - byte <<= 4 - byte |= _hex_as_nybble(cc) - list.append(chr(byte)) - byte = 0 - else: - found_digit = True - byte = _hex_as_nybble(cc) - elif cc == 'x': - found_hex = True - else: - if cc == 'a': - list.append('\a') - elif cc == 'b': - list.append('\b') - elif cc == 'f': - list.append('\f') - elif cc == 'n': - list.append('\n') - elif cc == 'r': - list.append('\r') - elif cc == 't': - list.append('\t') - elif cc == 'v': - list.append('\v') - else: - list.append(cc) - found_escape = False - elif cc == '\\': - found_escape = True - elif cc == delim: - break - else: - list.append(cc) - return ''.join(list) - -class LLSDNotationParser(object): - """ Parse LLSD notation: - map: { string:object, string:object } - array: [ object, object, object ] - undef: ! - boolean: true | false | 1 | 0 | T | F | t | f | TRUE | FALSE - integer: i#### - real: r#### - uuid: u#### - string: "g\'day" | 'have a "nice" day' | s(size)"raw data" - uri: l"escaped" - date: d"YYYY-MM-DDTHH:MM:SS.FFZ" - binary: b##"ff3120ab1" | b(size)"raw data" - """ - def __init__(self): - pass - - def parse(self, buffer, ignore_binary = False): - """ - This is the basic public interface for parsing. - - @param buffer the notation string to parse. - @param ignore_binary parser throws away data in llsd binary nodes. - @return returns a python object. - """ - if buffer == "": - return False - - self._buffer = buffer - self._index = 0 - return self._parse() - - def _parse(self): - cc = self._buffer[self._index] - self._index += 1 - if cc == '{': - return self._parse_map() - elif cc == '[': - return self._parse_array() - elif cc == '!': - return None - elif cc == '0': - return False - elif cc == '1': - return True - elif cc in ('F', 'f'): - self._skip_alpha() - return False - elif cc in ('T', 't'): - self._skip_alpha() - return True - elif cc == 'i': - # 'i' = integer - return self._parse_integer() - elif cc == ('r'): - # 'r' = real number - return self._parse_real() - elif cc == 'u': - # 'u' = uuid - return self._parse_uuid() - elif cc in ("'", '"', 's'): - return self._parse_string(cc) - elif cc == 'l': - # 'l' = uri - delim = self._buffer[self._index] - self._index += 1 - val = uri(self._parse_string(delim)) - if len(val) == 0: - return None - return val - elif cc == ('d'): - # 'd' = date in seconds since epoch - return self._parse_date() - elif cc == 'b': - return self._parse_binary() - else: - raise LLSDParseError("invalid token at index %d: %d" % ( - self._index - 1, ord(cc))) - - def _parse_binary(self): - i = self._index - if self._buffer[i:i+2] == '64': - q = self._buffer[i+2] - e = self._buffer.find(q, i+3) - try: - return base64.decodestring(self._buffer[i+3:e]) - finally: - self._index = e + 1 - else: - raise LLSDParseError('random horrible binary format not supported') - - def _parse_map(self): - """ map: { string:object, string:object } """ - rv = {} - cc = self._buffer[self._index] - self._index += 1 - key = '' - found_key = False - while (cc != '}'): - if not found_key: - if cc in ("'", '"', 's'): - key = self._parse_string(cc) - found_key = True - elif cc.isspace() or cc == ',': - cc = self._buffer[self._index] - self._index += 1 - else: - raise LLSDParseError("invalid map key at byte %d." % ( - self._index - 1,)) - elif cc.isspace() or cc == ':': - cc = self._buffer[self._index] - self._index += 1 - continue - else: - self._index += 1 - value = self._parse() - rv[key] = value - found_key = False - cc = self._buffer[self._index] - self._index += 1 - - return rv - - def _parse_array(self): - """ array: [ object, object, object ] """ - rv = [] - cc = self._buffer[self._index] - while (cc != ']'): - if cc.isspace() or cc == ',': - self._index += 1 - cc = self._buffer[self._index] - continue - rv.append(self._parse()) - cc = self._buffer[self._index] - - if cc != ']': - raise LLSDParseError("invalid array close token at index %d." % ( - self._index,)) - self._index += 1 - return rv - - def _parse_uuid(self): - match = re.match(lluuid.UUID.uuid_regex, self._buffer[self._index:]) - if not match: - raise LLSDParseError("invalid uuid token at index %d." % self._index) - - (start, end) = match.span() - start += self._index - end += self._index - self._index = end - return lluuid.UUID(self._buffer[start:end]) - - def _skip_alpha(self): - match = re.match(alpha_regex, self._buffer[self._index:]) - if match: - self._index += match.end() - - def _parse_date(self): - delim = self._buffer[self._index] - self._index += 1 - datestr = self._parse_string(delim) - return parse_datestr(datestr) - - def _parse_real(self): - match = re.match(real_regex, self._buffer[self._index:]) - if not match: - raise LLSDParseError("invalid real token at index %d." % self._index) - - (start, end) = match.span() - start += self._index - end += self._index - self._index = end - return float( self._buffer[start:end] ) - - def _parse_integer(self): - match = re.match(int_regex, self._buffer[self._index:]) - if not match: - raise LLSDParseError("invalid integer token at index %d." % self._index) - - (start, end) = match.span() - start += self._index - end += self._index - self._index = end - return int( self._buffer[start:end] ) - - def _parse_string(self, delim): - """ string: "g\'day" | 'have a "nice" day' | s(size)"raw data" """ - rv = "" - - if delim in ("'", '"'): - rv = self._parse_string_delim(delim) - elif delim == 's': - rv = self._parse_string_raw() - else: - raise LLSDParseError("invalid string token at index %d." % self._index) - - return rv - - - def _parse_string_delim(self, delim): - """ string: "g'day 'un" | 'have a "nice" day' """ - list = [] - found_escape = False - found_hex = False - found_digit = False - byte = 0 - while True: - cc = self._buffer[self._index] - self._index += 1 - if found_escape: - if found_hex: - if found_digit: - found_escape = False - found_hex = False - found_digit = False - byte <<= 4 - byte |= _hex_as_nybble(cc) - list.append(chr(byte)) - byte = 0 - else: - found_digit = True - byte = _hex_as_nybble(cc) - elif cc == 'x': - found_hex = True - else: - if cc == 'a': - list.append('\a') - elif cc == 'b': - list.append('\b') - elif cc == 'f': - list.append('\f') - elif cc == 'n': - list.append('\n') - elif cc == 'r': - list.append('\r') - elif cc == 't': - list.append('\t') - elif cc == 'v': - list.append('\v') - else: - list.append(cc) - found_escape = False - elif cc == '\\': - found_escape = True - elif cc == delim: - break - else: - list.append(cc) - return ''.join(list) - - def _parse_string_raw(self): - """ string: s(size)"raw data" """ - # Read the (size) portion. - cc = self._buffer[self._index] - self._index += 1 - if cc != '(': - raise LLSDParseError("invalid string token at index %d." % self._index) - - rparen = self._buffer.find(')', self._index) - if rparen == -1: - raise LLSDParseError("invalid string token at index %d." % self._index) - - size = int(self._buffer[self._index:rparen]) - - self._index = rparen + 1 - delim = self._buffer[self._index] - self._index += 1 - if delim not in ("'", '"'): - raise LLSDParseError("invalid string token at index %d." % self._index) - - rv = self._buffer[self._index:(self._index + size)] - self._index += size - cc = self._buffer[self._index] - self._index += 1 - if cc != delim: - raise LLSDParseError("invalid string token at index %d." % self._index) - - return rv - -def format_binary(something): - return '\n' + _format_binary_recurse(something) - -def _format_binary_recurse(something): - def _format_list(something): - array_builder = [] - array_builder.append('[' + struct.pack('!i', len(something))) - for item in something: - array_builder.append(_format_binary_recurse(item)) - array_builder.append(']') - return ''.join(array_builder) - - if something is None: - return '!' - elif isinstance(something, LLSD): - return _format_binary_recurse(something.thing) - elif isinstance(something, bool): - if something: - return '1' - else: - return '0' - elif isinstance(something, (int, long)): - return 'i' + struct.pack('!i', something) - elif isinstance(something, float): - return 'r' + struct.pack('!d', something) - elif isinstance(something, lluuid.UUID): - return 'u' + something._bits - elif isinstance(something, binary): - return 'b' + struct.pack('!i', len(something)) + something - elif isinstance(something, str): - return 's' + struct.pack('!i', len(something)) + something - elif isinstance(something, unicode): - something = something.encode('utf-8') - return 's' + struct.pack('!i', len(something)) + something - elif isinstance(something, uri): - return 'l' + struct.pack('!i', len(something)) + something - elif isinstance(something, datetime.datetime): - seconds_since_epoch = time.mktime(something.timetuple()) - return 'd' + struct.pack('!d', seconds_since_epoch) - elif isinstance(something, (list, tuple)): - return _format_list(something) - elif isinstance(something, dict): - map_builder = [] - map_builder.append('{' + struct.pack('!i', len(something))) - for key, value in something.items(): - if isinstance(key, unicode): - key = key.encode('utf-8') - map_builder.append('k' + struct.pack('!i', len(key)) + key) - map_builder.append(_format_binary_recurse(value)) - map_builder.append('}') - return ''.join(map_builder) - else: - try: - return _format_list(list(something)) - except TypeError: - raise LLSDSerializationError( - "Cannot serialize unknown type: %s (%s)" % - (type(something), something)) - - -def parse_binary(something): - header = '\n' - if not something.startswith(header): - raise LLSDParseError('LLSD binary encoding header not found') - return LLSDBinaryParser().parse(something[len(header):]) - -def parse_xml(something): - try: - return to_python(fromstring(something)[0]) - except ElementTreeError, err: - raise LLSDParseError(*err.args) - -def parse_notation(something): - return LLSDNotationParser().parse(something) - -def parse(something): - try: - something = string.lstrip(something) #remove any pre-trailing whitespace - if something.startswith(''): - return parse_binary(something) - # This should be better. - elif something.startswith('<'): - return parse_xml(something) - else: - return parse_notation(something) - except KeyError, e: - raise Exception('LLSD could not be parsed: %s' % (e,)) - -class LLSD(object): - def __init__(self, thing=None): - self.thing = thing - - def __str__(self): - return self.toXML(self.thing) - - parse = staticmethod(parse) - toXML = staticmethod(format_xml) - toPrettyXML = staticmethod(format_pretty_xml) - toBinary = staticmethod(format_binary) - toNotation = staticmethod(format_notation) - - -undef = LLSD(None) - -XML_MIME_TYPE = 'application/llsd+xml' -BINARY_MIME_TYPE = 'application/llsd+binary' - -# register converters for llsd in mulib, if it is available -try: - from mulib import stacked, mu - stacked.NoProducer() # just to exercise stacked - mu.safe_load(None) # just to exercise mu -except: - # mulib not available, don't print an error message since this is normal - pass -else: - mu.add_parser(parse, XML_MIME_TYPE) - mu.add_parser(parse, 'application/llsd+binary') - - def llsd_convert_xml(llsd_stuff, request): - request.write(format_xml(llsd_stuff)) - - def llsd_convert_binary(llsd_stuff, request): - request.write(format_binary(llsd_stuff)) - - for typ in [LLSD, dict, list, tuple, str, int, long, float, bool, unicode, type(None)]: - stacked.add_producer(typ, llsd_convert_xml, XML_MIME_TYPE) - stacked.add_producer(typ, llsd_convert_xml, 'application/xml') - stacked.add_producer(typ, llsd_convert_xml, 'text/xml') - - stacked.add_producer(typ, llsd_convert_binary, 'application/llsd+binary') - - stacked.add_producer(LLSD, llsd_convert_xml, '*/*') - - # in case someone is using the legacy mu.xml wrapper, we need to - # tell mu to produce application/xml or application/llsd+xml - # (based on the accept header) from raw xml. Phoenix 2008-07-21 - stacked.add_producer(mu.xml, mu.produce_raw, XML_MIME_TYPE) - stacked.add_producer(mu.xml, mu.produce_raw, 'application/xml') - - - -# mulib wsgi stuff -# try: -# from mulib import mu, adapters -# -# # try some known attributes from mulib to be ultra-sure we've imported it -# mu.get_current -# adapters.handlers -# except: -# # mulib not available, don't print an error message since this is normal -# pass -# else: -# def llsd_xml_handler(content_type): -# def handle_llsd_xml(env, start_response): -# llsd_stuff, _ = mu.get_current(env) -# result = format_xml(llsd_stuff) -# start_response("200 OK", [('Content-Type', content_type)]) -# env['mu.negotiated_type'] = content_type -# yield result -# return handle_llsd_xml -# -# def llsd_binary_handler(content_type): -# def handle_llsd_binary(env, start_response): -# llsd_stuff, _ = mu.get_current(env) -# result = format_binary(llsd_stuff) -# start_response("200 OK", [('Content-Type', content_type)]) -# env['mu.negotiated_type'] = content_type -# yield result -# return handle_llsd_binary -# -# adapters.DEFAULT_PARSERS[XML_MIME_TYPE] = parse - -# for typ in [LLSD, dict, list, tuple, str, int, float, bool, unicode, type(None)]: -# for content_type in (XML_MIME_TYPE, 'application/xml'): -# adapters.handlers.set_handler(typ, llsd_xml_handler(content_type), content_type) -# -# adapters.handlers.set_handler(typ, llsd_binary_handler(BINARY_MIME_TYPE), BINARY_MIME_TYPE) -# -# adapters.handlers.set_handler(LLSD, llsd_xml_handler(XML_MIME_TYPE), '*/*') diff --git a/indra/lib/python/indra/base/lluuid.py b/indra/lib/python/indra/base/lluuid.py deleted file mode 100644 index cff1900878..0000000000 --- a/indra/lib/python/indra/base/lluuid.py +++ /dev/null @@ -1,320 +0,0 @@ -"""\ -@file lluuid.py -@brief UUID parser/generator. - -$LicenseInfo:firstyear=2004&license=mit$ - -Copyright (c) 2004-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -import random, socket, string, time, re -import uuid - -# *HACK: Necessary for python 2.4. Consider replacing this code wart -# after python >=2.5 has deployed everywhere. 2009-10-05 -try: - from hashlib import md5 -except ImportError: - from md5 import md5 - -def _int2binstr(i,l): - s='' - for a in range(l): - s=chr(i&0xFF)+s - i>>=8 - return s - -def _binstr2int(s): - i = long(0) - for c in s: - i = (i<<8) + ord(c) - return i - -class UUID(object): - """ - A class which represents a 16 byte integer. Stored as a 16 byte 8 - bit character string. - - The string version is to be of the form: - AAAAAAAA-AAAA-BBBB-BBBB-BBBBBBCCCCCC (a 128-bit number in hex) - where A=network address, B=timestamp, C=random. - """ - - NULL_STR = "00000000-0000-0000-0000-000000000000" - - # the UUIDREGEX_STRING is helpful for parsing UUID's in text - hex_wildcard = r"[0-9a-fA-F]" - word = hex_wildcard + r"{4,4}-" - long_word = hex_wildcard + r"{8,8}-" - very_long_word = hex_wildcard + r"{12,12}" - UUID_REGEX_STRING = long_word + word + word + word + very_long_word - uuid_regex = re.compile(UUID_REGEX_STRING) - - rand = random.Random() - ip = '' - try: - ip = socket.gethostbyname(socket.gethostname()) - except(socket.gaierror): - # no ip address, so just default to somewhere in 10.x.x.x - ip = '10' - for i in range(3): - ip += '.' + str(rand.randrange(1,254)) - hexip = ''.join(["%04x" % long(i) for i in ip.split('.')]) - lastid = '' - - def __init__(self, possible_uuid=None): - """ - Initialize to first valid UUID in argument (if a string), - or to null UUID if none found or argument is not supplied. - - If the argument is a UUID, the constructed object will be a copy of it. - """ - self._bits = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - if possible_uuid is None: - return - - if isinstance(possible_uuid, type(self)): - self.set(possible_uuid) - return - - uuid_match = UUID.uuid_regex.search(possible_uuid) - if uuid_match: - uuid_string = uuid_match.group() - s = string.replace(uuid_string, '-', '') - self._bits = _int2binstr(string.atol(s[:8],16),4) + \ - _int2binstr(string.atol(s[8:16],16),4) + \ - _int2binstr(string.atol(s[16:24],16),4) + \ - _int2binstr(string.atol(s[24:],16),4) - - def __len__(self): - """ - Used by the len() builtin. - """ - return 36 - - def __nonzero__(self): - return self._bits != "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - - def __str__(self): - uuid_string = self.toString() - return uuid_string - - __repr__ = __str__ - - def __getitem__(self, index): - return str(self)[index] - - def __eq__(self, other): - if isinstance(other, (str, unicode)): - return other == str(self) - return self._bits == getattr(other, '_bits', '') - - def __ne__(self, other): - return not self.__eq__(other) - - def __le__(self, other): - return self._bits <= other._bits - - def __ge__(self, other): - return self._bits >= other._bits - - def __lt__(self, other): - return self._bits < other._bits - - def __gt__(self, other): - return self._bits > other._bits - - def __hash__(self): - return hash(self._bits) - - def set(self, uuid): - self._bits = uuid._bits - - def setFromString(self, uuid_string): - """ - Given a string version of a uuid, set self bits - appropriately. Returns self. - """ - s = string.replace(uuid_string, '-', '') - self._bits = _int2binstr(string.atol(s[:8],16),4) + \ - _int2binstr(string.atol(s[8:16],16),4) + \ - _int2binstr(string.atol(s[16:24],16),4) + \ - _int2binstr(string.atol(s[24:],16),4) - return self - - def setFromMemoryDump(self, gdb_string): - """ - We expect to get gdb_string as four hex units. eg: - 0x147d54db 0xc34b3f1b 0x714f989b 0x0a892fd2 - Which will be translated to: - db547d14-1b3f4bc3-9b984f71-d22f890a - Returns self. - """ - s = string.replace(gdb_string, '0x', '') - s = string.replace(s, ' ', '') - t = '' - for i in range(8,40,8): - for j in range(0,8,2): - t = t + s[i-j-2:i-j] - self.setFromString(t) - - def toString(self): - """ - Return as a string matching the LL standard - AAAAAAAA-AAAA-BBBB-BBBB-BBBBBBCCCCCC (a 128-bit number in hex) - where A=network address, B=timestamp, C=random. - """ - return uuid_bits_to_string(self._bits) - - def getAsString(self): - """ - Return a different string representation of the form - AAAAAAAA-AAAABBBB-BBBBBBBB-BBCCCCCC (a 128-bit number in hex) - where A=network address, B=timestamp, C=random. - """ - i1 = _binstr2int(self._bits[0:4]) - i2 = _binstr2int(self._bits[4:8]) - i3 = _binstr2int(self._bits[8:12]) - i4 = _binstr2int(self._bits[12:16]) - return '%08lx-%08lx-%08lx-%08lx' % (i1,i2,i3,i4) - - def generate(self): - """ - Generate a new uuid. This algorithm is slightly different - from c++ implementation for portability reasons. - Returns self. - """ - m = md5() - m.update(uuid.uuid1().bytes) - self._bits = m.digest() - return self - - def isNull(self): - """ - Returns 1 if the uuid is null - ie, equal to default uuid. - """ - return (self._bits == "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0") - - def xor(self, rhs): - """ - xors self with rhs. - """ - v1 = _binstr2int(self._bits[0:4]) ^ _binstr2int(rhs._bits[0:4]) - v2 = _binstr2int(self._bits[4:8]) ^ _binstr2int(rhs._bits[4:8]) - v3 = _binstr2int(self._bits[8:12]) ^ _binstr2int(rhs._bits[8:12]) - v4 = _binstr2int(self._bits[12:16]) ^ _binstr2int(rhs._bits[12:16]) - self._bits = _int2binstr(v1,4) + \ - _int2binstr(v2,4) + \ - _int2binstr(v3,4) + \ - _int2binstr(v4,4) - - -# module-level null constant -NULL = UUID() - -def printTranslatedMemory(four_hex_uints): - """ - We expect to get the string as four hex units. eg: - 0x147d54db 0xc34b3f1b 0x714f989b 0x0a892fd2 - Which will be translated to: - db547d14-1b3f4bc3-9b984f71-d22f890a - """ - uuid = UUID() - uuid.setFromMemoryDump(four_hex_uints) - print uuid.toString() - -def isUUID(id_str): - """ - This function returns: - - 1 if the string passed is a UUID - - 0 is the string passed is not a UUID - - None if it neither of the if's below is satisfied - """ - if not id_str or len(id_str) < 5 or len(id_str) > 36: - return 0 - - if isinstance(id_str, UUID) or UUID.uuid_regex.match(id_str): - return 1 - - return None - -def isPossiblyID(id_str): - """ - This function returns 1 if the string passed has some uuid-like - characteristics. Otherwise returns 0. - """ - - is_uuid = isUUID(id_str) - if is_uuid is not None: - return is_uuid - - # build a string which matches every character. - hex_wildcard = r"[0-9a-fA-F]" - chars = len(id_str) - next = min(chars, 8) - matcher = hex_wildcard+"{"+str(next)+","+str(next)+"}" - chars = chars - next - if chars > 0: - matcher = matcher + "-" - chars = chars - 1 - for block in range(3): - next = max(min(chars, 4), 0) - if next: - matcher = matcher + hex_wildcard+"{"+str(next)+","+str(next)+"}" - chars = chars - next - if chars > 0: - matcher = matcher + "-" - chars = chars - 1 - if chars > 0: - next = min(chars, 12) - matcher = matcher + hex_wildcard+"{"+str(next)+","+str(next)+"}" - #print matcher - uuid_matcher = re.compile(matcher) - if uuid_matcher.match(id_str): - return 1 - return 0 - -def uuid_bits_to_string(bits): - i1 = _binstr2int(bits[0:4]) - i2 = _binstr2int(bits[4:6]) - i3 = _binstr2int(bits[6:8]) - i4 = _binstr2int(bits[8:10]) - i5 = _binstr2int(bits[10:12]) - i6 = _binstr2int(bits[12:16]) - return '%08lx-%04lx-%04lx-%04lx-%04lx%08lx' % (i1,i2,i3,i4,i5,i6) - -def uuid_bits_to_uuid(bits): - return UUID(uuid_bits_to_string(bits)) - - -try: - from mulib import stacked - stacked.NoProducer() # just to exercise stacked -except: - #print "Couldn't import mulib.stacked, not registering UUID converter" - pass -else: - def convertUUID(uuid, req): - req.write(str(uuid)) - - stacked.add_producer(UUID, convertUUID, "*/*") - stacked.add_producer(UUID, convertUUID, "text/html") diff --git a/indra/lib/python/indra/base/metrics.py b/indra/lib/python/indra/base/metrics.py deleted file mode 100644 index 8f2a85cf0e..0000000000 --- a/indra/lib/python/indra/base/metrics.py +++ /dev/null @@ -1,53 +0,0 @@ -"""\ -@file metrics.py -@author Phoenix -@date 2007-11-27 -@brief simple interface for logging metrics - -$LicenseInfo:firstyear=2007&license=mit$ - -Copyright (c) 2007-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -import sys -from indra.base import llsd - -_sequence_id = 0 - -def record_metrics(table, stats, dest=None): - "Write a standard metrics log" - _log("LLMETRICS", table, stats, dest) - -def record_event(table, data, dest=None): - "Write a standard logmessage log" - _log("LLLOGMESSAGE", table, data, dest) - -def _log(header, table, data, dest): - if dest is None: - # do this check here in case sys.stdout changes at some - # point. as a default parameter, it will never be - # re-evaluated. - dest = sys.stdout - global _sequence_id - print >>dest, header, "(" + str(_sequence_id) + ")", - print >>dest, table, llsd.format_notation(data) - _sequence_id += 1 diff --git a/indra/lib/python/indra/ipc/httputil.py b/indra/lib/python/indra/ipc/httputil.py deleted file mode 100644 index c4ac0a379d..0000000000 --- a/indra/lib/python/indra/ipc/httputil.py +++ /dev/null @@ -1,9 +0,0 @@ - -import warnings - -warnings.warn("indra.ipc.httputil has been deprecated; use eventlet.httpc instead", DeprecationWarning, 2) - -from eventlet.httpc import * - - -makeConnection = make_connection diff --git a/indra/lib/python/indra/ipc/llsdhttp.py b/indra/lib/python/indra/ipc/llsdhttp.py deleted file mode 100644 index cbe8ee1eca..0000000000 --- a/indra/lib/python/indra/ipc/llsdhttp.py +++ /dev/null @@ -1,100 +0,0 @@ -"""\ -@file llsdhttp.py -@brief Functions to ease moving llsd over http - -$LicenseInfo:firstyear=2006&license=mit$ - -Copyright (c) 2006-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -import os.path -import os -import urlparse - -from indra.base import llsd - -from eventlet import httpc - -suite = httpc.HttpSuite(llsd.format_xml, llsd.parse, 'application/llsd+xml') -delete = suite.delete -delete_ = suite.delete_ -get = suite.get -get_ = suite.get_ -head = suite.head -head_ = suite.head_ -post = suite.post -post_ = suite.post_ -put = suite.put -put_ = suite.put_ -request = suite.request -request_ = suite.request_ - -# import every httpc error exception into our namespace for convenience -for x in httpc.status_to_error_map.itervalues(): - globals()[x.__name__] = x -ConnectionError = httpc.ConnectionError -Retriable = httpc.Retriable - -for x in (httpc.ConnectionError,): - globals()[x.__name__] = x - - -def postFile(url, filename): - f = open(filename) - body = f.read() - f.close() - llsd_body = llsd.parse(body) - return post_(url, llsd_body) - - -# deprecated in favor of get_ -def getStatus(url, use_proxy=False): - status, _headers, _body = get_(url, use_proxy=use_proxy) - return status - -# deprecated in favor of put_ -def putStatus(url, data): - status, _headers, _body = put_(url, data) - return status - -# deprecated in favor of delete_ -def deleteStatus(url): - status, _headers, _body = delete_(url) - return status - -# deprecated in favor of post_ -def postStatus(url, data): - status, _headers, _body = post_(url, data) - return status - - -def postFileStatus(url, filename): - status, _headers, body = postFile(url, filename) - return status, body - - -def getFromSimulator(path, use_proxy=False): - return get('http://' + simulatorHostAndPort + path, use_proxy=use_proxy) - - -def postToSimulator(path, data=None): - return post('http://' + simulatorHostAndPort + path, data) diff --git a/indra/lib/python/indra/ipc/mysql_pool.py b/indra/lib/python/indra/ipc/mysql_pool.py deleted file mode 100644 index e5855a3091..0000000000 --- a/indra/lib/python/indra/ipc/mysql_pool.py +++ /dev/null @@ -1,81 +0,0 @@ -"""\ -@file mysql_pool.py -@brief Thin wrapper around eventlet.db_pool that chooses MySQLdb and Tpool. - -$LicenseInfo:firstyear=2007&license=mit$ - -Copyright (c) 2007-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -import MySQLdb -from eventlet import db_pool - -class DatabaseConnector(db_pool.DatabaseConnector): - def __init__(self, credentials, *args, **kwargs): - super(DatabaseConnector, self).__init__(MySQLdb, credentials, - conn_pool=db_pool.ConnectionPool, - *args, **kwargs) - - # get is extended relative to eventlet.db_pool to accept a port argument - def get(self, host, dbname, port=3306): - key = (host, dbname, port) - if key not in self._databases: - new_kwargs = self._kwargs.copy() - new_kwargs['db'] = dbname - new_kwargs['host'] = host - new_kwargs['port'] = port - new_kwargs.update(self.credentials_for(host)) - dbpool = ConnectionPool(*self._args, **new_kwargs) - self._databases[key] = dbpool - - return self._databases[key] - -class ConnectionPool(db_pool.TpooledConnectionPool): - """A pool which gives out saranwrapped MySQLdb connections from a pool - """ - - def __init__(self, *args, **kwargs): - super(ConnectionPool, self).__init__(MySQLdb, *args, **kwargs) - - def get(self): - conn = super(ConnectionPool, self).get() - # annotate the connection object with the details on the - # connection; this is used elsewhere to check that you haven't - # suddenly changed databases in midstream while making a - # series of queries on a connection. - arg_names = ['host','user','passwd','db','port','unix_socket','conv','connect_timeout', - 'compress', 'named_pipe', 'init_command', 'read_default_file', 'read_default_group', - 'cursorclass', 'use_unicode', 'charset', 'sql_mode', 'client_flag', 'ssl', - 'local_infile'] - # you could have constructed this connectionpool with a mix of - # keyword and non-keyword arguments, but we want to annotate - # the connection object with a dict so it's easy to check - # against so here we are converting the list of non-keyword - # arguments (in self._args) into a dict of keyword arguments, - # and merging that with the actual keyword arguments - # (self._kwargs). The arg_names variable lists the - # constructor arguments for MySQLdb Connection objects. - converted_kwargs = dict([ (arg_names[i], arg) for i, arg in enumerate(self._args) ]) - converted_kwargs.update(self._kwargs) - conn.connection_parameters = converted_kwargs - return conn - diff --git a/indra/lib/python/indra/ipc/russ.py b/indra/lib/python/indra/ipc/russ.py deleted file mode 100644 index 35d8afb158..0000000000 --- a/indra/lib/python/indra/ipc/russ.py +++ /dev/null @@ -1,165 +0,0 @@ -"""\ -@file russ.py -@brief Recursive URL Substitution Syntax helpers -@author Phoenix - -Many details on how this should work is available on the wiki: -https://wiki.secondlife.com/wiki/Recursive_URL_Substitution_Syntax - -Adding features to this should be reflected in that page in the -implementations section. - -$LicenseInfo:firstyear=2007&license=mit$ - -Copyright (c) 2007-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -import urllib -from indra.ipc import llsdhttp - -class UnbalancedBraces(Exception): - pass - -class UnknownDirective(Exception): - pass - -class BadDirective(Exception): - pass - -def format_value_for_path(value): - if type(value) in [list, tuple]: - # *NOTE: treat lists as unquoted path components so that the quoting - # doesn't get out-of-hand. This is a workaround for the fact that - # russ always quotes, even if the data it's given is already quoted, - # and it's not safe to simply unquote a path directly, so if we want - # russ to substitute urls parts inside other url parts we always - # have to do so via lists of unquoted path components. - return '/'.join([urllib.quote(str(item)) for item in value]) - else: - return urllib.quote(str(value)) - -def format(format_str, context): - """@brief Format format string according to rules for RUSS. -@see https://osiris.lindenlab.com/mediawiki/index.php/Recursive_URL_Substitution_Syntax -@param format_str The input string to format. -@param context A map used for string substitutions. -@return Returns the formatted string. If no match, the braces remain intact. -""" - while True: - #print "format_str:", format_str - all_matches = _find_sub_matches(format_str) - if not all_matches: - break - substitutions = 0 - while True: - matches = all_matches.pop() - # we work from right to left to make sure we do not - # invalidate positions earlier in format_str - matches.reverse() - for pos in matches: - # Use index since _find_sub_matches should have raised - # an exception, and failure to find now is an exception. - end = format_str.index('}', pos) - #print "directive:", format_str[pos+1:pos+5] - if format_str[pos + 1] == '$': - value = context[format_str[pos + 2:end]] - if value is not None: - value = format_value_for_path(value) - elif format_str[pos + 1] == '%': - value = _build_query_string( - context.get(format_str[pos + 2:end])) - elif format_str[pos+1:pos+5] == 'http' or format_str[pos+1:pos+5] == 'file': - value = _fetch_url_directive(format_str[pos + 1:end]) - else: - raise UnknownDirective, format_str[pos:end + 1] - if value is not None: - format_str = format_str[:pos]+str(value)+format_str[end+1:] - substitutions += 1 - - # If there were any substitutions at this depth, re-parse - # since this may have revealed new things to substitute - if substitutions: - break - if not all_matches: - break - - # If there were no substitutions at all, and we have exhausted - # the possible matches, bail. - if not substitutions: - break - return format_str - -def _find_sub_matches(format_str): - """@brief Find all of the substitution matches. -@param format_str the RUSS conformant format string. -@return Returns an array of depths of arrays of positional matches in input. -""" - depth = 0 - matches = [] - for pos in range(len(format_str)): - if format_str[pos] == '{': - depth += 1 - if not len(matches) == depth: - matches.append([]) - matches[depth - 1].append(pos) - continue - if format_str[pos] == '}': - depth -= 1 - continue - if not depth == 0: - raise UnbalancedBraces, format_str - return matches - -def _build_query_string(query_dict): - """\ - @breif given a dict, return a query string. utility wrapper for urllib. - @param query_dict input query dict - @returns Returns an urlencoded query string including leading '?'. - """ - if query_dict: - keys = query_dict.keys() - keys.sort() - def stringize(value): - if type(value) in (str,unicode): - return value - else: - return str(value) - query_list = [urllib.quote(str(key)) + '=' + urllib.quote(stringize(query_dict[key])) for key in keys] - return '?' + '&'.join(query_list) - else: - return '' - -def _fetch_url_directive(directive): - "*FIX: This only supports GET" - commands = directive.split('|') - resource = llsdhttp.get(commands[0]) - if len(commands) == 3: - resource = _walk_resource(resource, commands[2]) - return resource - -def _walk_resource(resource, path): - path = path.split('/') - for child in path: - if not child: - continue - resource = resource[child] - return resource diff --git a/indra/lib/python/indra/ipc/servicebuilder.py b/indra/lib/python/indra/ipc/servicebuilder.py deleted file mode 100644 index 04ccee7657..0000000000 --- a/indra/lib/python/indra/ipc/servicebuilder.py +++ /dev/null @@ -1,114 +0,0 @@ -"""\ -@file servicebuilder.py -@author Phoenix -@brief Class which will generate service urls. - -$LicenseInfo:firstyear=2007&license=mit$ - -Copyright (c) 2007-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -from indra.base import config -from indra.ipc import llsdhttp -from indra.ipc import russ - -# *NOTE: agent presence relies on this variable existing and being current, it is a huge hack -services_config = {} -try: - services_config = llsdhttp.get(config.get('services-config')) -except: - pass - -_g_builder = None -def build(name, context={}, **kwargs): - """ Convenience method for using a global, singleton, service builder. Pass arguments either via a dict or via python keyword arguments, or both! - - Example use: - > context = {'channel':'Second Life Release', 'version':'1.18.2.0'} - > servicebuilder.build('version-manager-version', context) - 'http://int.util.vaak.lindenlab.com/channel/Second%20Life%20Release/1.18.2.0' - > servicebuilder.build('version-manager-version', channel='Second Life Release', version='1.18.2.0') - 'http://int.util.vaak.lindenlab.com/channel/Second%20Life%20Release/1.18.2.0' - > servicebuilder.build('version-manager-version', context, version='1.18.1.2') - 'http://int.util.vaak.lindenlab.com/channel/Second%20Life%20Release/1.18.1.2' - """ - global _g_builder - if _g_builder is None: - _g_builder = ServiceBuilder() - return _g_builder.buildServiceURL(name, context, **kwargs) - -class ServiceBuilder(object): - def __init__(self, services_definition = services_config): - """\ - @brief - @brief Create a ServiceBuilder. - @param services_definition Complete services definition, services.xml. - """ - # no need to keep a copy of the services section of the - # complete services definition, but it doesn't hurt much. - self.services = services_definition['services'] - self.builders = {} - for service in self.services: - service_builder = service.get('service-builder') - if not service_builder: - continue - if isinstance(service_builder, dict): - # We will be constructing several builders - for name, builder in service_builder.items(): - full_builder_name = service['name'] + '-' + name - self.builders[full_builder_name] = builder - else: - self.builders[service['name']] = service_builder - - def buildServiceURL(self, name, context={}, **kwargs): - """\ - @brief given the environment on construction, return a service URL. - @param name The name of the service. - @param context A dict of name value lookups for the service. - @param kwargs Any keyword arguments are treated as members of the - context, this allows you to be all 31337 by writing shit like: - servicebuilder.build('name', param=value) - @returns Returns the - """ - context = context.copy() # shouldn't modify the caller's dictionary - context.update(kwargs) - base_url = config.get('services-base-url') - svc_path = russ.format(self.builders[name], context) - return base_url + svc_path - - -def on_in(query_name, host_key, schema_key): - """\ - @brief Constructs an on/in snippet (for running named queries) - from a schema name and two keys referencing values stored in - indra.xml. - - @param query_name Name of the query. - @param host_key Logical name of destination host. Will be - looked up in indra.xml. - @param schema_key Logical name of destination schema. Will - be looked up in indra.xml. - """ - host_name = config.get(host_key) - schema_name = config.get(schema_key) - return '/'.join( ('on', host_name, 'in', schema_name, query_name.lstrip('/')) ) - diff --git a/indra/lib/python/indra/ipc/siesta.py b/indra/lib/python/indra/ipc/siesta.py deleted file mode 100644 index b206f181c4..0000000000 --- a/indra/lib/python/indra/ipc/siesta.py +++ /dev/null @@ -1,402 +0,0 @@ -from indra.base import llsd -from webob import exc -import webob -import re, socket - -try: - from cStringIO import StringIO -except ImportError: - from StringIO import StringIO - -try: - import cjson - json_decode = cjson.decode - json_encode = cjson.encode - JsonDecodeError = cjson.DecodeError - JsonEncodeError = cjson.EncodeError -except ImportError: - import simplejson - json_decode = simplejson.loads - json_encode = simplejson.dumps - JsonDecodeError = ValueError - JsonEncodeError = TypeError - - -llsd_parsers = { - 'application/json': json_decode, - llsd.BINARY_MIME_TYPE: llsd.parse_binary, - 'application/llsd+notation': llsd.parse_notation, - llsd.XML_MIME_TYPE: llsd.parse_xml, - 'application/xml': llsd.parse_xml, - } - - -def mime_type(content_type): - '''Given a Content-Type header, return only the MIME type.''' - - return content_type.split(';', 1)[0].strip().lower() - -class BodyLLSD(object): - '''Give a webob Request or Response an llsd property. - - Getting the llsd property parses the body, and caches the result. - - Setting the llsd property formats a payload, and the body property - is set.''' - - def _llsd__get(self): - '''Get, set, or delete the LLSD value stored in this object.''' - - try: - return self._llsd - except AttributeError: - if not self.body: - raise AttributeError('No llsd attribute has been set') - else: - mtype = mime_type(self.content_type) - try: - parser = llsd_parsers[mtype] - except KeyError: - raise exc.HTTPUnsupportedMediaType( - 'Content type %s not supported' % mtype).exception - try: - self._llsd = parser(self.body) - except (llsd.LLSDParseError, JsonDecodeError, TypeError), err: - raise exc.HTTPBadRequest( - 'Could not parse body: %r' % err.args).exception - return self._llsd - - def _llsd__set(self, val): - req = getattr(self, 'request', None) - if req is not None: - formatter, ctype = formatter_for_request(req) - self.content_type = ctype - else: - formatter, ctype = formatter_for_mime_type( - mime_type(self.content_type)) - self.body = formatter(val) - - def _llsd__del(self): - if hasattr(self, '_llsd'): - del self._llsd - - llsd = property(_llsd__get, _llsd__set, _llsd__del) - - -class Response(webob.Response, BodyLLSD): - '''Response class with LLSD support. - - A sensible default content type is used. - - Setting the llsd property also sets the body. Getting the llsd - property parses the body if necessary. - - If you set the body property directly, the llsd property will be - deleted.''' - - default_content_type = 'application/llsd+xml' - - def _body__set(self, body): - if hasattr(self, '_llsd'): - del self._llsd - super(Response, self)._body__set(body) - - def cache_forever(self): - self.cache_expires(86400 * 365) - - body = property(webob.Response._body__get, _body__set, - webob.Response._body__del, - webob.Response._body__get.__doc__) - - -class Request(webob.Request, BodyLLSD): - '''Request class with LLSD support. - - Sensible content type and accept headers are used by default. - - Setting the llsd property also sets the body. Getting the llsd - property parses the body if necessary. - - If you set the body property directly, the llsd property will be - deleted.''' - - default_content_type = 'application/llsd+xml' - default_accept = ('application/llsd+xml; q=0.5, ' - 'application/llsd+notation; q=0.3, ' - 'application/llsd+binary; q=0.2, ' - 'application/xml; q=0.1, ' - 'application/json; q=0.0') - - def __init__(self, environ=None, *args, **kwargs): - if environ is None: - environ = {} - else: - environ = environ.copy() - if 'CONTENT_TYPE' not in environ: - environ['CONTENT_TYPE'] = self.default_content_type - if 'HTTP_ACCEPT' not in environ: - environ['HTTP_ACCEPT'] = self.default_accept - super(Request, self).__init__(environ, *args, **kwargs) - - def _body__set(self, body): - if hasattr(self, '_llsd'): - del self._llsd - super(Request, self)._body__set(body) - - def path_urljoin(self, *parts): - return '/'.join([path_url.rstrip('/')] + list(parts)) - - body = property(webob.Request._body__get, _body__set, - webob.Request._body__del, webob.Request._body__get.__doc__) - - def create_response(self, llsd=None, status='200 OK', - conditional_response=webob.NoDefault): - resp = self.ResponseClass(status=status, request=self, - conditional_response=conditional_response) - resp.llsd = llsd - return resp - - def curl(self): - '''Create and fill out a pycurl easy object from this request.''' - - import pycurl - c = pycurl.Curl() - c.setopt(pycurl.URL, self.url()) - if self.headers: - c.setopt(pycurl.HTTPHEADER, - ['%s: %s' % (k, self.headers[k]) for k in self.headers]) - c.setopt(pycurl.FOLLOWLOCATION, True) - c.setopt(pycurl.AUTOREFERER, True) - c.setopt(pycurl.MAXREDIRS, 16) - c.setopt(pycurl.NOSIGNAL, True) - c.setopt(pycurl.READFUNCTION, self.body_file.read) - c.setopt(pycurl.SSL_VERIFYHOST, 2) - - if self.method == 'POST': - c.setopt(pycurl.POST, True) - post301 = getattr(pycurl, 'POST301', None) - if post301 is not None: - # Added in libcurl 7.17.1. - c.setopt(post301, True) - elif self.method == 'PUT': - c.setopt(pycurl.PUT, True) - elif self.method != 'GET': - c.setopt(pycurl.CUSTOMREQUEST, self.method) - return c - -Request.ResponseClass = Response -Response.RequestClass = Request - - -llsd_formatters = { - 'application/json': json_encode, - 'application/llsd+binary': llsd.format_binary, - 'application/llsd+notation': llsd.format_notation, - 'application/llsd+xml': llsd.format_xml, - 'application/xml': llsd.format_xml, - } - - -def formatter_for_mime_type(mime_type): - '''Return a formatter that encodes to the given MIME type. - - The result is a pair of function and MIME type.''' - - try: - return llsd_formatters[mime_type], mime_type - except KeyError: - raise exc.HTTPInternalServerError( - 'Could not use MIME type %r to format response' % - mime_type).exception - - -def formatter_for_request(req): - '''Return a formatter that encodes to the preferred type of the client. - - The result is a pair of function and actual MIME type.''' - - for ctype in req.accept.best_matches('application/llsd+xml'): - try: - return llsd_formatters[ctype], ctype - except KeyError: - pass - else: - raise exc.HTTPNotAcceptable().exception - - -def wsgi_adapter(func, environ, start_response): - '''Adapt a Siesta callable to act as a WSGI application.''' - - try: - req = Request(environ) - resp = func(req, **req.urlvars) - if not isinstance(resp, webob.Response): - try: - formatter, ctype = formatter_for_request(req) - resp = req.ResponseClass(formatter(resp), content_type=ctype) - resp._llsd = resp - except (JsonEncodeError, TypeError), err: - resp = exc.HTTPInternalServerError( - detail='Could not format response') - except exc.HTTPException, e: - resp = e - except socket.error, e: - resp = exc.HTTPInternalServerError(detail=e.args[1]) - return resp(environ, start_response) - - -def llsd_callable(func): - '''Turn a callable into a Siesta application.''' - - def replacement(environ, start_response): - return wsgi_adapter(func, environ, start_response) - - return replacement - - -def llsd_method(http_method, func): - def replacement(environ, start_response): - if environ['REQUEST_METHOD'] == http_method: - return wsgi_adapter(func, environ, start_response) - return exc.HTTPMethodNotAllowed()(environ, start_response) - - return replacement - - -http11_methods = 'OPTIONS GET HEAD POST PUT DELETE TRACE CONNECT'.split() -http11_methods.sort() - -def llsd_class(cls): - '''Turn a class into a Siesta application. - - A new instance is created for each request. A HTTP method FOO is - turned into a call to the handle_foo method of the instance.''' - - def foo(req, **kwargs): - instance = cls() - method = req.method.lower() - try: - handler = getattr(instance, 'handle_' + method) - except AttributeError: - allowed = [m for m in http11_methods - if hasattr(instance, 'handle_' + m.lower())] - raise exc.HTTPMethodNotAllowed( - headers={'Allowed': ', '.join(allowed)}).exception - return handler(req, **kwargs) - - def replacement(environ, start_response): - return wsgi_adapter(foo, environ, start_response) - - return replacement - - -def curl(reqs): - import pycurl - - m = pycurl.CurlMulti() - curls = [r.curl() for r in reqs] - io = {} - for c in curls: - fp = StringIO() - hdr = StringIO() - c.setopt(pycurl.WRITEFUNCTION, fp.write) - c.setopt(pycurl.HEADERFUNCTION, hdr.write) - io[id(c)] = fp, hdr - m.handles = curls - try: - while True: - ret, num_handles = m.perform() - if ret != pycurl.E_CALL_MULTI_PERFORM: - break - finally: - m.close() - - for req, c in zip(reqs, curls): - fp, hdr = io[id(c)] - hdr.seek(0) - status = hdr.readline().rstrip() - headers = [] - name, values = None, None - - # XXX We don't currently handle bogus header data. - - for line in hdr.readlines(): - if not line[0].isspace(): - if name: - headers.append((name, ' '.join(values))) - name, value = line.strip().split(':', 1) - value = [value] - else: - values.append(line.strip()) - if name: - headers.append((name, ' '.join(values))) - - resp = c.ResponseClass(fp.getvalue(), status, headers, request=req) - - -route_re = re.compile(r''' - \{ # exact character "{" - (\w+) # variable name (restricted to a-z, 0-9, _) - (?:([:~])([^}]+))? # optional :type or ~regex part - \} # exact character "}" - ''', re.VERBOSE) - -predefined_regexps = { - 'uuid': r'[a-f0-9][a-f0-9-]{31,35}', - 'int': r'\d+', - } - -def compile_route(route): - fp = StringIO() - last_pos = 0 - for match in route_re.finditer(route): - fp.write(re.escape(route[last_pos:match.start()])) - var_name = match.group(1) - sep = match.group(2) - expr = match.group(3) - if expr: - if sep == ':': - expr = predefined_regexps[expr] - # otherwise, treat what follows '~' as a regexp - else: - expr = '[^/]+' - expr = '(?P<%s>%s)' % (var_name, expr) - fp.write(expr) - last_pos = match.end() - fp.write(re.escape(route[last_pos:])) - return '^%s$' % fp.getvalue() - -class Router(object): - '''WSGI routing class. Parses a URL and hands off a request to - some other WSGI application. If no suitable application is found, - responds with a 404.''' - - def __init__(self): - self.routes = [] - self.paths = [] - - def add(self, route, app, methods=None): - self.paths.append(route) - self.routes.append((re.compile(compile_route(route)), app, - methods and dict.fromkeys(methods))) - - def __call__(self, environ, start_response): - path_info = environ['PATH_INFO'] - request_method = environ['REQUEST_METHOD'] - allowed = [] - for regex, app, methods in self.routes: - m = regex.match(path_info) - if m: - if not methods or request_method in methods: - environ['paste.urlvars'] = m.groupdict() - return app(environ, start_response) - else: - allowed += methods - if allowed: - allowed = dict.fromkeys(allows).keys() - allowed.sort() - resp = exc.HTTPMethodNotAllowed( - headers={'Allowed': ', '.join(allowed)}) - else: - resp = exc.HTTPNotFound() - return resp(environ, start_response) diff --git a/indra/lib/python/indra/ipc/siesta_test.py b/indra/lib/python/indra/ipc/siesta_test.py deleted file mode 100644 index 177ea710d1..0000000000 --- a/indra/lib/python/indra/ipc/siesta_test.py +++ /dev/null @@ -1,214 +0,0 @@ -from indra.base import llsd, lluuid -from indra.ipc import siesta -import datetime, math, unittest -from webob import exc - - -class ClassApp(object): - def handle_get(self, req): - pass - - def handle_post(self, req): - return req.llsd - - -def callable_app(req): - if req.method == 'UNDERPANTS': - raise exc.HTTPMethodNotAllowed() - elif req.method == 'GET': - return None - return req.llsd - - -class TestBase: - def test_basic_get(self): - req = siesta.Request.blank('/') - self.assertEquals(req.get_response(self.server).body, - llsd.format_xml(None)) - - def test_bad_method(self): - req = siesta.Request.blank('/') - req.environ['REQUEST_METHOD'] = 'UNDERPANTS' - self.assertEquals(req.get_response(self.server).status_int, - exc.HTTPMethodNotAllowed.code) - - json_safe = { - 'none': None, - 'bool_true': True, - 'bool_false': False, - 'int_zero': 0, - 'int_max': 2147483647, - 'int_min': -2147483648, - 'long_zero': 0, - 'long_max': 2147483647L, - 'long_min': -2147483648L, - 'float_zero': 0, - 'float': math.pi, - 'float_huge': 3.14159265358979323846e299, - 'str_empty': '', - 'str': 'foo', - u'unic\u1e51de_empty': u'', - u'unic\u1e51de': u'\u1e4exx\u10480', - } - json_safe['array'] = json_safe.values() - json_safe['tuple'] = tuple(json_safe.values()) - json_safe['dict'] = json_safe.copy() - - json_unsafe = { - 'uuid_empty': lluuid.UUID(), - 'uuid_full': lluuid.UUID('dc61ab0530200d7554d23510559102c1a98aab1b'), - 'binary_empty': llsd.binary(), - 'binary': llsd.binary('f\0\xff'), - 'uri_empty': llsd.uri(), - 'uri': llsd.uri('http://www.secondlife.com/'), - 'datetime_empty': datetime.datetime(1970,1,1), - 'datetime': datetime.datetime(1999,9,9,9,9,9), - } - json_unsafe.update(json_safe) - json_unsafe['array'] = json_unsafe.values() - json_unsafe['tuple'] = tuple(json_unsafe.values()) - json_unsafe['dict'] = json_unsafe.copy() - json_unsafe['iter'] = iter(json_unsafe.values()) - - def _test_client_content_type_good(self, content_type, ll): - def run(ll): - req = siesta.Request.blank('/') - req.environ['REQUEST_METHOD'] = 'POST' - req.content_type = content_type - req.llsd = ll - req.accept = content_type - resp = req.get_response(self.server) - self.assertEquals(resp.status_int, 200) - return req, resp - - if False and isinstance(ll, dict): - def fixup(v): - if isinstance(v, float): - return '%.5f' % v - if isinstance(v, long): - return int(v) - if isinstance(v, (llsd.binary, llsd.uri)): - return v - if isinstance(v, (tuple, list)): - return [fixup(i) for i in v] - if isinstance(v, dict): - return dict([(k, fixup(i)) for k, i in v.iteritems()]) - return v - for k, v in ll.iteritems(): - l = [k, v] - req, resp = run(l) - self.assertEquals(fixup(resp.llsd), fixup(l)) - - run(ll) - - def test_client_content_type_json_good(self): - self._test_client_content_type_good('application/json', self.json_safe) - - def test_client_content_type_llsd_xml_good(self): - self._test_client_content_type_good('application/llsd+xml', - self.json_unsafe) - - def test_client_content_type_llsd_notation_good(self): - self._test_client_content_type_good('application/llsd+notation', - self.json_unsafe) - - def test_client_content_type_llsd_binary_good(self): - self._test_client_content_type_good('application/llsd+binary', - self.json_unsafe) - - def test_client_content_type_xml_good(self): - self._test_client_content_type_good('application/xml', - self.json_unsafe) - - def _test_client_content_type_bad(self, content_type): - req = siesta.Request.blank('/') - req.environ['REQUEST_METHOD'] = 'POST' - req.body = '\0invalid nonsense under all encodings' - req.content_type = content_type - self.assertEquals(req.get_response(self.server).status_int, - exc.HTTPBadRequest.code) - - def test_client_content_type_json_bad(self): - self._test_client_content_type_bad('application/json') - - def test_client_content_type_llsd_xml_bad(self): - self._test_client_content_type_bad('application/llsd+xml') - - def test_client_content_type_llsd_notation_bad(self): - self._test_client_content_type_bad('application/llsd+notation') - - def test_client_content_type_llsd_binary_bad(self): - self._test_client_content_type_bad('application/llsd+binary') - - def test_client_content_type_xml_bad(self): - self._test_client_content_type_bad('application/xml') - - def test_client_content_type_bad(self): - req = siesta.Request.blank('/') - req.environ['REQUEST_METHOD'] = 'POST' - req.body = 'XXX' - req.content_type = 'application/nonsense' - self.assertEquals(req.get_response(self.server).status_int, - exc.HTTPUnsupportedMediaType.code) - - def test_request_default_content_type(self): - req = siesta.Request.blank('/') - self.assertEquals(req.content_type, req.default_content_type) - - def test_request_default_accept(self): - req = siesta.Request.blank('/') - from webob import acceptparse - self.assertEquals(str(req.accept).replace(' ', ''), - req.default_accept.replace(' ', '')) - - def test_request_llsd_auto_body(self): - req = siesta.Request.blank('/') - req.llsd = {'a': 2} - self.assertEquals(req.body, '' - 'a2') - - def test_request_llsd_mod_body_changes_llsd(self): - req = siesta.Request.blank('/') - req.llsd = {'a': 2} - req.body = '1337' - self.assertEquals(req.llsd, 1337) - - def test_request_bad_llsd_fails(self): - def crashme(ctype): - def boom(): - class foo(object): pass - req = siesta.Request.blank('/') - req.content_type = ctype - req.llsd = foo() - for mime_type in siesta.llsd_parsers: - self.assertRaises(TypeError, crashme(mime_type)) - - -class ClassServer(TestBase, unittest.TestCase): - def __init__(self, *args, **kwargs): - unittest.TestCase.__init__(self, *args, **kwargs) - self.server = siesta.llsd_class(ClassApp) - - -class CallableServer(TestBase, unittest.TestCase): - def __init__(self, *args, **kwargs): - unittest.TestCase.__init__(self, *args, **kwargs) - self.server = siesta.llsd_callable(callable_app) - - -class RouterServer(unittest.TestCase): - def test_router(self): - def foo(req, quux): - print quux - - r = siesta.Router() - r.add('/foo/{quux:int}', siesta.llsd_callable(foo), methods=['GET']) - req = siesta.Request.blank('/foo/33') - req.get_response(r) - - req = siesta.Request.blank('/foo/bar') - self.assertEquals(req.get_response(r).status_int, - exc.HTTPNotFound.code) - -if __name__ == '__main__': - unittest.main() diff --git a/indra/lib/python/indra/ipc/webdav.py b/indra/lib/python/indra/ipc/webdav.py deleted file mode 100644 index 98b8499b6a..0000000000 --- a/indra/lib/python/indra/ipc/webdav.py +++ /dev/null @@ -1,597 +0,0 @@ -""" -@file webdav.py -@brief Classes to make manipulation of a webdav store easier. - -$LicenseInfo:firstyear=2007&license=mit$ - -Copyright (c) 2007-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -import sys, os, httplib, urlparse -import socket, time -import xml.dom.minidom -import syslog -# import signal - -__revision__ = '0' - -dav_debug = False - - -# def urlsafe_b64decode (enc): -# return base64.decodestring (enc.replace ('_', '/').replace ('-', '+')) - -# def urlsafe_b64encode (str): -# return base64.encodestring (str).replace ('+', '-').replace ('/', '_') - - -class DAVError (Exception): - """ Base class for exceptions in this module. """ - def __init__ (self, status=0, message='', body='', details=''): - self.status = status - self.message = message - self.body = body - self.details = details - Exception.__init__ (self, '%d:%s:%s%s' % (self.status, self.message, - self.body, self.details)) - - def print_to_stderr (self): - """ print_to_stderr docstring """ - print >> sys.stderr, str (self.status) + ' ' + self.message - print >> sys.stderr, str (self.details) - - -class Timeout (Exception): - """ Timeout docstring """ - def __init__ (self, arg=''): - Exception.__init__ (self, arg) - - -def alarm_handler (signum, frame): - """ alarm_handler docstring """ - raise Timeout ('caught alarm') - - -class WebDAV: - """ WebDAV docstring """ - def __init__ (self, url, proxy=None, retries_before_fail=6): - self.init_url = url - self.init_proxy = proxy - self.retries_before_fail = retries_before_fail - url_parsed = urlparse.urlsplit (url) - - self.top_path = url_parsed[ 2 ] - # make sure top_path has a trailing / - if self.top_path == None or self.top_path == '': - self.top_path = '/' - elif len (self.top_path) > 1 and self.top_path[-1:] != '/': - self.top_path += '/' - - if dav_debug: - syslog.syslog ('new WebDAV %s : %s' % (str (url), str (proxy))) - - if proxy: - proxy_parsed = urlparse.urlsplit (proxy) - self.host_header = url_parsed[ 1 ] - host_and_port = proxy_parsed[ 1 ].split (':') - self.host = host_and_port[ 0 ] - if len (host_and_port) > 1: - self.port = int(host_and_port[ 1 ]) - else: - self.port = 80 - else: # no proxy - host_and_port = url_parsed[ 1 ].split (':') - self.host_header = None - self.host = host_and_port[ 0 ] - if len (host_and_port) > 1: - self.port = int(host_and_port[ 1 ]) - else: - self.port = 80 - - self.connection = False - self.connect () - - - def log (self, msg, depth=0): - """ log docstring """ - if dav_debug and depth == 0: - host = str (self.init_url) - if host == 'http://int.tuco.lindenlab.com:80/asset/': - host = 'tuco' - if host == 'http://harriet.lindenlab.com/asset-keep/': - host = 'harriet/asset-keep' - if host == 'http://harriet.lindenlab.com/asset-flag/': - host = 'harriet/asset-flag' - if host == 'http://harriet.lindenlab.com/asset/': - host = 'harriet/asset' - if host == 'http://ozzy.lindenlab.com/asset/': - host = 'ozzy/asset' - if host == 'http://station11.lindenlab.com:12041/:': - host = 'station11:12041' - proxy = str (self.init_proxy) - if proxy == 'None': - proxy = '' - if proxy == 'http://int.tuco.lindenlab.com:3128/': - proxy = 'tuco' - syslog.syslog ('WebDAV (%s:%s) %s' % (host, proxy, str (msg))) - - - def connect (self): - """ connect docstring """ - self.log ('connect') - self.connection = httplib.HTTPConnection (self.host, self.port) - - def __err (self, response, details): - """ __err docstring """ - raise DAVError (response.status, response.reason, response.read (), - str (self.init_url) + ':' + \ - str (self.init_proxy) + ':' + str (details)) - - def request (self, method, path, body=None, headers=None, - read_all=True, body_hook = None, recurse=0, allow_cache=True): - """ request docstring """ - # self.log ('request %s %s' % (method, path)) - if headers == None: - headers = {} - if not allow_cache: - headers['Pragma'] = 'no-cache' - headers['cache-control'] = 'no-cache' - try: - if method.lower () != 'purge': - if path.startswith ('/'): - path = path[1:] - if self.host_header: # use proxy - headers[ 'host' ] = self.host_header - fullpath = 'http://%s%s%s' % (self.host_header, - self.top_path, path) - else: # no proxy - fullpath = self.top_path + path - else: - fullpath = path - - self.connection.request (method, fullpath, body, headers) - if body_hook: - body_hook () - - # signal.signal (signal.SIGALRM, alarm_handler) - # try: - # signal.alarm (120) - # signal.alarm (0) - # except Timeout, e: - # if recurse < 6: - # return self.retry_request (method, path, body, headers, - # read_all, body_hook, recurse) - # else: - # raise DAVError (0, 'timeout', self.host, - # (method, path, body, headers, recurse)) - - response = self.connection.getresponse () - - if read_all: - while len (response.read (1024)) > 0: - pass - if (response.status == 500 or \ - response.status == 503 or \ - response.status == 403) and \ - recurse < self.retries_before_fail: - return self.retry_request (method, path, body, headers, - read_all, body_hook, recurse) - return response - except (httplib.ResponseNotReady, - httplib.BadStatusLine, - socket.error): - # if the server hangs up on us (keepalive off, broken pipe), - # we need to reconnect and try again. - if recurse < self.retries_before_fail: - return self.retry_request (method, path, body, headers, - read_all, body_hook, recurse) - raise DAVError (0, 'reconnect failed', self.host, - (method, path, body, headers, recurse)) - - - def retry_request (self, method, path, body, headers, - read_all, body_hook, recurse): - """ retry_request docstring """ - time.sleep (10.0 * recurse) - self.connect () - return self.request (method, path, body, headers, - read_all, body_hook, recurse+1) - - - - def propfind (self, path, body=None, depth=1): - """ propfind docstring """ - # self.log ('propfind %s' % path) - headers = {'Content-Type':'text/xml; charset="utf-8"', - 'Depth':str(depth)} - response = self.request ('PROPFIND', path, body, headers, False) - if response.status == 207: - return response # Multi-Status - self.__err (response, ('PROPFIND', path, body, headers, 0)) - - - def purge (self, path): - """ issue a squid purge command """ - headers = {'Accept':'*/*'} - response = self.request ('PURGE', path, None, headers) - if response.status == 200 or response.status == 404: - # 200 if it was purge, 404 if it wasn't there. - return response - self.__err (response, ('PURGE', path, None, headers)) - - - def get_file_size (self, path): - """ - Use propfind to ask a webdav server what the size of - a file is. If used on a directory (collection) return 0 - """ - self.log ('get_file_size %s' % path) - # "getcontentlength" property - # 8.1.1 Example - Retrieving Named Properties - # http://docs.python.org/lib/module-xml.dom.html - nsurl = 'http://apache.org/dav/props/' - doc = xml.dom.minidom.Document () - propfind_element = doc.createElementNS (nsurl, "D:propfind") - propfind_element.setAttributeNS (nsurl, 'xmlns:D', 'DAV:') - doc.appendChild (propfind_element) - prop_element = doc.createElementNS (nsurl, "D:prop") - propfind_element.appendChild (prop_element) - con_len_element = doc.createElementNS (nsurl, "D:getcontentlength") - prop_element.appendChild (con_len_element) - - response = self.propfind (path, doc.toxml ()) - doc.unlink () - - resp_doc = xml.dom.minidom.parseString (response.read ()) - cln = resp_doc.getElementsByTagNameNS ('DAV:','getcontentlength')[ 0 ] - try: - content_length = int (cln.childNodes[ 0 ].nodeValue) - except IndexError: - return 0 - resp_doc.unlink () - return content_length - - - def file_exists (self, path): - """ - do an http head on the given file. return True if it succeeds - """ - self.log ('file_exists %s' % path) - expect_gzip = path.endswith ('.gz') - response = self.request ('HEAD', path) - got_gzip = response.getheader ('Content-Encoding', '').strip () - if got_gzip.lower () == 'x-gzip' and expect_gzip == False: - # the asset server fakes us out if we ask for the non-gzipped - # version of an asset, but the server has the gzipped version. - return False - return response.status == 200 - - - def mkdir (self, path): - """ mkdir docstring """ - self.log ('mkdir %s' % path) - headers = {} - response = self.request ('MKCOL', path, None, headers) - if response.status == 201: - return # success - if response.status == 405: - return # directory already existed? - self.__err (response, ('MKCOL', path, None, headers, 0)) - - - def delete (self, path): - """ delete docstring """ - self.log ('delete %s' % path) - headers = {'Depth':'infinity'} # collections require infinity - response = self.request ('DELETE', path, None, headers) - if response.status == 204: - return # no content - if response.status == 404: - return # hmm - self.__err (response, ('DELETE', path, None, headers, 0)) - - - def list_directory (self, path, dir_filter=None, allow_cache=True, - minimum_cache_time=False): - """ - Request an http directory listing and parse the filenames out of lines - like: '
  • X'. If a filter function is provided, - only return filenames that the filter returns True for. - - This is sort of grody, but it seems faster than other ways of getting - this information from an isilon. - """ - self.log ('list_directory %s' % path) - - def try_match (lline, before, after): - """ try_match docstring """ - try: - blen = len (before) - asset_start_index = lline.index (before) - asset_end_index = lline.index (after, asset_start_index + blen) - asset = line[ asset_start_index + blen : asset_end_index ] - - if not dir_filter or dir_filter (asset): - return [ asset ] - return [] - except ValueError: - return [] - - if len (path) > 0 and path[-1:] != '/': - path += '/' - - response = self.request ('GET', path, None, {}, False, - allow_cache=allow_cache) - - if allow_cache and minimum_cache_time: # XXX - print response.getheader ('Date') - # s = "2005-12-06T12:13:14" - # from datetime import datetime - # from time import strptime - # datetime(*strptime(s, "%Y-%m-%dT%H:%M:%S")[0:6]) - # datetime.datetime(2005, 12, 6, 12, 13, 14) - - if response.status != 200: - self.__err (response, ('GET', path, None, {}, 0)) - assets = [] - for line in response.read ().split ('\n'): - lline = line.lower () - if lline.find ("parent directory") == -1: - # isilon file - assets += try_match (lline, '
  • ') - # apache dir - assets += try_match (lline, 'alt="[dir]"> ') - # apache file - assets += try_match (lline, 'alt="[ ]"> ') - return assets - - - def __tmp_filename (self, path_and_file): - """ __tmp_filename docstring """ - head, tail = os.path.split (path_and_file) - if head != '': - return head + '/.' + tail + '.' + str (os.getpid ()) - else: - return head + '.' + tail + '.' + str (os.getpid ()) - - - def __put__ (self, filesize, body_hook, remotefile): - """ __put__ docstring """ - headers = {'Content-Length' : str (filesize)} - remotefile_tmp = self.__tmp_filename (remotefile) - response = self.request ('PUT', remotefile_tmp, None, - headers, True, body_hook) - if not response.status in (201, 204): # created, no content - self.__err (response, ('PUT', remotefile, None, headers, 0)) - if filesize != self.get_file_size (remotefile_tmp): - try: - self.delete (remotefile_tmp) - except: - pass - raise DAVError (0, 'tmp upload error', remotefile_tmp) - # move the file to its final location - try: - self.rename (remotefile_tmp, remotefile) - except DAVError, exc: - if exc.status == 403: # try to clean up the tmp file - try: - self.delete (remotefile_tmp) - except: - pass - raise - if filesize != self.get_file_size (remotefile): - raise DAVError (0, 'file upload error', str (remotefile_tmp)) - - - def put_string (self, strng, remotefile): - """ put_string docstring """ - self.log ('put_string %d -> %s' % (len (strng), remotefile)) - filesize = len (strng) - def body_hook (): - """ body_hook docstring """ - self.connection.send (strng) - self.__put__ (filesize, body_hook, remotefile) - - - def put_file (self, localfile, remotefile): - """ - Send a local file to a remote webdav store. First, upload to - a temporary filename. Next make sure the file is the size we - expected. Next, move the file to its final location. Next, - check the file size at the final location. - """ - self.log ('put_file %s -> %s' % (localfile, remotefile)) - filesize = os.path.getsize (localfile) - def body_hook (): - """ body_hook docstring """ - handle = open (localfile) - while True: - data = handle.read (1300) - if len (data) == 0: - break - self.connection.send (data) - handle.close () - self.__put__ (filesize, body_hook, remotefile) - - - def create_empty_file (self, remotefile): - """ create an empty file """ - self.log ('touch_file %s' % (remotefile)) - headers = {'Content-Length' : '0'} - response = self.request ('PUT', remotefile, None, headers) - if not response.status in (201, 204): # created, no content - self.__err (response, ('PUT', remotefile, None, headers, 0)) - if self.get_file_size (remotefile) != 0: - raise DAVError (0, 'file upload error', str (remotefile)) - - - def __get_file_setup (self, remotefile, check_size=True): - """ __get_file_setup docstring """ - if check_size: - remotesize = self.get_file_size (remotefile) - response = self.request ('GET', remotefile, None, {}, False) - if response.status != 200: - self.__err (response, ('GET', remotefile, None, {}, 0)) - try: - content_length = int (response.getheader ("Content-Length")) - except TypeError: - content_length = None - if check_size: - if content_length != remotesize: - raise DAVError (0, 'file DL size error', remotefile) - return (response, content_length) - - - def __get_file_read (self, writehandle, response, content_length): - """ __get_file_read docstring """ - if content_length != None: - so_far_length = 0 - while so_far_length < content_length: - data = response.read (content_length - so_far_length) - if len (data) == 0: - raise DAVError (0, 'short file download') - so_far_length += len (data) - writehandle.write (data) - while len (response.read ()) > 0: - pass - else: - while True: - data = response.read () - if (len (data) < 1): - break - writehandle.write (data) - - - def get_file (self, remotefile, localfile, check_size=True): - """ - Get a remote file from a webdav server. Download to a local - tmp file, then move into place. Sanity check file sizes as - we go. - """ - self.log ('get_file %s -> %s' % (remotefile, localfile)) - (response, content_length) = \ - self.__get_file_setup (remotefile, check_size) - localfile_tmp = self.__tmp_filename (localfile) - handle = open (localfile_tmp, 'w') - self.__get_file_read (handle, response, content_length) - handle.close () - if check_size: - if content_length != os.path.getsize (localfile_tmp): - raise DAVError (0, 'file DL size error', - remotefile+','+localfile) - os.rename (localfile_tmp, localfile) - - - def get_file_as_string (self, remotefile, check_size=True): - """ - download a file from a webdav server and return it as a string. - """ - self.log ('get_file_as_string %s' % remotefile) - (response, content_length) = \ - self.__get_file_setup (remotefile, check_size) - # (tmp_handle, tmp_filename) = tempfile.mkstemp () - tmp_handle = os.tmpfile () - self.__get_file_read (tmp_handle, response, content_length) - tmp_handle.seek (0) - ret = tmp_handle.read () - tmp_handle.close () - # os.unlink (tmp_filename) - return ret - - - def get_post_as_string (self, remotefile, body): - """ - Do an http POST, send body, get response and return it. - """ - self.log ('get_post_as_string %s' % remotefile) - # headers = {'Content-Type':'application/x-www-form-urlencoded'} - headers = {'Content-Type':'text/xml; charset="utf-8"'} - # b64body = urlsafe_b64encode (asset_url) - response = self.request ('POST', remotefile, body, headers, False) - if response.status != 200: - self.__err (response, ('POST', remotefile, body, headers, 0)) - try: - content_length = int (response.getheader ('Content-Length')) - except TypeError: - content_length = None - tmp_handle = os.tmpfile () - self.__get_file_read (tmp_handle, response, content_length) - tmp_handle.seek (0) - ret = tmp_handle.read () - tmp_handle.close () - return ret - - - def __destination_command (self, verb, remotesrc, dstdav, remotedst): - """ - self and dstdav should point to the same http server. - """ - if len (remotedst) > 0 and remotedst[ 0 ] == '/': - remotedst = remotedst[1:] - headers = {'Destination': 'http://%s:%d%s%s' % (dstdav.host, - dstdav.port, - dstdav.top_path, - remotedst)} - response = self.request (verb, remotesrc, None, headers) - if response.status == 201: - return # created - if response.status == 204: - return # no content - self.__err (response, (verb, remotesrc, None, headers, 0)) - - - def rename (self, remotesrc, remotedst): - """ rename a file on a webdav server """ - self.log ('rename %s -> %s' % (remotesrc, remotedst)) - self.__destination_command ('MOVE', remotesrc, self, remotedst) - def xrename (self, remotesrc, dstdav, remotedst): - """ rename a file on a webdav server """ - self.log ('xrename %s -> %s' % (remotesrc, remotedst)) - self.__destination_command ('MOVE', remotesrc, dstdav, remotedst) - - - def copy (self, remotesrc, remotedst): - """ copy a file on a webdav server """ - self.log ('copy %s -> %s' % (remotesrc, remotedst)) - self.__destination_command ('COPY', remotesrc, self, remotedst) - def xcopy (self, remotesrc, dstdav, remotedst): - """ copy a file on a webdav server """ - self.log ('xcopy %s -> %s' % (remotesrc, remotedst)) - self.__destination_command ('COPY', remotesrc, dstdav, remotedst) - - -def put_string (data, url): - """ - upload string s to a url - """ - url_parsed = urlparse.urlsplit (url) - dav = WebDAV ('%s://%s/' % (url_parsed[ 0 ], url_parsed[ 1 ])) - dav.put_string (data, url_parsed[ 2 ]) - - -def get_string (url, check_size=True): - """ - return the contents of a url as a string - """ - url_parsed = urlparse.urlsplit (url) - dav = WebDAV ('%s://%s/' % (url_parsed[ 0 ], url_parsed[ 1 ])) - return dav.get_file_as_string (url_parsed[ 2 ], check_size) diff --git a/indra/lib/python/indra/ipc/xml_rpc.py b/indra/lib/python/indra/ipc/xml_rpc.py deleted file mode 100644 index 47536c10c3..0000000000 --- a/indra/lib/python/indra/ipc/xml_rpc.py +++ /dev/null @@ -1,273 +0,0 @@ -"""\ -@file xml_rpc.py -@brief An implementation of a parser/generator for the XML-RPC xml format. - -$LicenseInfo:firstyear=2006&license=mit$ - -Copyright (c) 2006-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - - -from greenlet import greenlet - -from mulib import mu - -from xml.sax import handler -from xml.sax import parseString - - -# States -class Expected(object): - def __init__(self, tag): - self.tag = tag - - def __getattr__(self, name): - return type(self)(name) - - def __repr__(self): - return '%s(%r)' % ( - type(self).__name__, self.tag) - - -class START(Expected): - pass - - -class END(Expected): - pass - - -class STR(object): - tag = '' - - -START = START('') -END = END('') - - -class Malformed(Exception): - pass - - -class XMLParser(handler.ContentHandler): - def __init__(self, state_machine, next_states): - handler.ContentHandler.__init__(self) - self.state_machine = state_machine - if not isinstance(next_states, tuple): - next_states = (next_states, ) - self.next_states = next_states - self._character_buffer = '' - - def assertState(self, state, name, *rest): - if not isinstance(self.next_states, tuple): - self.next_states = (self.next_states, ) - for next in self.next_states: - if type(state) == type(next): - if next.tag and next.tag != name: - raise Malformed( - "Expected %s, got %s %s %s" % ( - next, state, name, rest)) - break - else: - raise Malformed( - "Expected %s, got %s %s %s" % ( - self.next_states, state, name, rest)) - - def startElement(self, name, attrs): - self.assertState(START, name.lower(), attrs) - self.next_states = self.state_machine.switch(START, (name.lower(), dict(attrs))) - - def endElement(self, name): - if self._character_buffer.strip(): - characters = self._character_buffer.strip() - self._character_buffer = '' - self.assertState(STR, characters) - self.next_states = self.state_machine.switch(characters) - self.assertState(END, name.lower()) - self.next_states = self.state_machine.switch(END, name.lower()) - - def error(self, exc): - self.bozo = 1 - self.exc = exc - - def fatalError(self, exc): - self.error(exc) - raise exc - - def characters(self, characters): - self._character_buffer += characters - - -def parse(what): - child = greenlet(xml_rpc) - me = greenlet.getcurrent() - startup_states = child.switch(me) - parser = XMLParser(child, startup_states) - try: - parseString(what, parser) - except Malformed: - print what - raise - return child.switch() - - -def xml_rpc(yielder): - yielder.switch(START.methodcall) - yielder.switch(START.methodname) - methodName = yielder.switch(STR) - yielder.switch(END.methodname) - - yielder.switch(START.params) - - root = None - params = [] - while True: - state, _ = yielder.switch(START.param, END.params) - if state == END: - break - - yielder.switch(START.value) - - params.append( - handle(yielder)) - - yielder.switch(END.value) - yielder.switch(END.param) - - yielder.switch(END.methodcall) - ## Resume parse - yielder.switch() - ## Return result to parse - return methodName.strip(), params - - -def handle(yielder): - _, (tag, attrs) = yielder.switch(START) - if tag in ['int', 'i4']: - result = int(yielder.switch(STR)) - elif tag == 'boolean': - result = bool(int(yielder.switch(STR))) - elif tag == 'string': - result = yielder.switch(STR) - elif tag == 'double': - result = float(yielder.switch(STR)) - elif tag == 'datetime.iso8601': - result = yielder.switch(STR) - elif tag == 'base64': - result = base64.b64decode(yielder.switch(STR)) - elif tag == 'struct': - result = {} - while True: - state, _ = yielder.switch(START.member, END.struct) - if state == END: - break - - yielder.switch(START.name) - key = yielder.switch(STR) - yielder.switch(END.name) - - yielder.switch(START.value) - result[key] = handle(yielder) - yielder.switch(END.value) - - yielder.switch(END.member) - ## We already handled above, don't want to handle it below - return result - elif tag == 'array': - result = [] - yielder.switch(START.data) - while True: - state, _ = yielder.switch(START.value, END.data) - if state == END: - break - - result.append(handle(yielder)) - - yielder.switch(END.value) - - yielder.switch(getattr(END, tag)) - - return result - - -VALUE = mu.tag_factory('value') -BOOLEAN = mu.tag_factory('boolean') -INT = mu.tag_factory('int') -STRUCT = mu.tag_factory('struct') -MEMBER = mu.tag_factory('member') -NAME = mu.tag_factory('name') -ARRAY = mu.tag_factory('array') -DATA = mu.tag_factory('data') -STRING = mu.tag_factory('string') -DOUBLE = mu.tag_factory('double') -METHODRESPONSE = mu.tag_factory('methodResponse') -PARAMS = mu.tag_factory('params') -PARAM = mu.tag_factory('param') - -mu.inline_elements['string'] = True -mu.inline_elements['boolean'] = True -mu.inline_elements['name'] = True - - -def _generate(something): - if isinstance(something, dict): - result = STRUCT() - for key, value in something.items(): - result[ - MEMBER[ - NAME[key], _generate(value)]] - return VALUE[result] - elif isinstance(something, list): - result = DATA() - for item in something: - result[_generate(item)] - return VALUE[ARRAY[[result]]] - elif isinstance(something, basestring): - return VALUE[STRING[something]] - elif isinstance(something, bool): - if something: - return VALUE[BOOLEAN['1']] - return VALUE[BOOLEAN['0']] - elif isinstance(something, int): - return VALUE[INT[something]] - elif isinstance(something, float): - return VALUE[DOUBLE[something]] - -def generate(*args): - params = PARAMS() - for arg in args: - params[PARAM[_generate(arg)]] - return METHODRESPONSE[params] - - -if __name__ == '__main__': - print parse(""" examples.getStateName 41 -""") - - - - - - - - - diff --git a/indra/lib/python/indra/util/fastest_elementtree.py b/indra/lib/python/indra/util/fastest_elementtree.py deleted file mode 100644 index 3e2189c4e7..0000000000 --- a/indra/lib/python/indra/util/fastest_elementtree.py +++ /dev/null @@ -1,65 +0,0 @@ -"""\ -@file fastest_elementtree.py -@brief Concealing some gnarly import logic in here. This should export the interface of elementtree. - -$LicenseInfo:firstyear=2008&license=mit$ - -Copyright (c) 2008-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -# The parsing exception raised by the underlying library depends -# on the ElementTree implementation we're using, so we provide an -# alias here. -# -# Use ElementTreeError as the exception type for catching parsing -# errors. - - -# Using cElementTree might cause some unforeseen problems, so here's a -# convenient off switch. - -use_celementree = True - -try: - if not use_celementree: - raise ImportError() - # Python 2.3 and 2.4. - from cElementTree import * - ElementTreeError = SyntaxError -except ImportError: - try: - if not use_celementree: - raise ImportError() - # Python 2.5 and above. - from xml.etree.cElementTree import * - ElementTreeError = SyntaxError - except ImportError: - # Pure Python code. - try: - # Python 2.3 and 2.4. - from elementtree.ElementTree import * - except ImportError: - # Python 2.5 and above. - from xml.etree.ElementTree import * - - # The pure Python ElementTree module uses Expat for parsing. - from xml.parsers.expat import ExpatError as ElementTreeError diff --git a/indra/lib/python/indra/util/helpformatter.py b/indra/lib/python/indra/util/helpformatter.py deleted file mode 100644 index ba5c9b67d1..0000000000 --- a/indra/lib/python/indra/util/helpformatter.py +++ /dev/null @@ -1,52 +0,0 @@ -"""\ -@file helpformatter.py -@author Phoenix -@brief Class for formatting optparse descriptions. - -$LicenseInfo:firstyear=2007&license=mit$ - -Copyright (c) 2007-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -import optparse -import textwrap - -class Formatter(optparse.IndentedHelpFormatter): - def __init__( - self, - p_indentIncrement = 2, - p_maxHelpPosition = 24, - p_width = 79, - p_shortFirst = 1) : - optparse.HelpFormatter.__init__( - self, - p_indentIncrement, - p_maxHelpPosition, - p_width, - p_shortFirst) - def format_description(self, p_description): - t_descWidth = self.width - self.current_indent - t_indent = " " * (self.current_indent + 2) - return "\n".join( - [textwrap.fill(descr, t_descWidth, initial_indent = t_indent, - subsequent_indent = t_indent) - for descr in p_description.split("\n")] ) diff --git a/indra/lib/python/indra/util/iterators.py b/indra/lib/python/indra/util/iterators.py deleted file mode 100644 index 9013fa6303..0000000000 --- a/indra/lib/python/indra/util/iterators.py +++ /dev/null @@ -1,63 +0,0 @@ -"""\ -@file iterators.py -@brief Useful general-purpose iterators. - -$LicenseInfo:firstyear=2008&license=mit$ - -Copyright (c) 2008-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -from __future__ import nested_scopes - -def iter_chunks(rows, aggregate_size=100): - """ - Given an iterable set of items (@p rows), produces lists of up to @p - aggregate_size items at a time, for example: - - iter_chunks([1,2,3,4,5,6,7,8,9,10], 3) - - Values for @p aggregate_size < 1 will raise ValueError. - - Will return a generator that produces, in the following order: - - [1, 2, 3] - - [4, 5, 6] - - [7, 8, 9] - - [10] - """ - if aggregate_size < 1: - raise ValueError() - - def iter_chunks_inner(): - row_iter = iter(rows) - done = False - agg = [] - while not done: - try: - row = row_iter.next() - agg.append(row) - except StopIteration: - done = True - if agg and (len(agg) >= aggregate_size or done): - yield agg - agg = [] - - return iter_chunks_inner() diff --git a/indra/lib/python/indra/util/iterators_test.py b/indra/lib/python/indra/util/iterators_test.py deleted file mode 100755 index 66928c8e7d..0000000000 --- a/indra/lib/python/indra/util/iterators_test.py +++ /dev/null @@ -1,72 +0,0 @@ -"""\ -@file iterators_test.py -@brief Test cases for iterators module. - -$LicenseInfo:firstyear=2008&license=mit$ - -Copyright (c) 2008-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -import unittest - -from indra.util.iterators import iter_chunks - -class TestIterChunks(unittest.TestCase): - """Unittests for iter_chunks""" - def test_bad_agg_size(self): - rows = [1,2,3,4] - self.assertRaises(ValueError, iter_chunks, rows, 0) - self.assertRaises(ValueError, iter_chunks, rows, -1) - - try: - for i in iter_chunks(rows, 0): - pass - except ValueError: - pass - else: - self.fail() - - try: - result = list(iter_chunks(rows, 0)) - except ValueError: - pass - else: - self.fail() - def test_empty(self): - rows = [] - result = list(iter_chunks(rows)) - self.assertEqual(result, []) - def test_small(self): - rows = [[1]] - result = list(iter_chunks(rows, 2)) - self.assertEqual(result, [[[1]]]) - def test_size(self): - rows = [[1],[2]] - result = list(iter_chunks(rows, 2)) - self.assertEqual(result, [[[1],[2]]]) - def test_multi_agg(self): - rows = [[1],[2],[3],[4],[5]] - result = list(iter_chunks(rows, 2)) - self.assertEqual(result, [[[1],[2]],[[3],[4]],[[5]]]) - -if __name__ == "__main__": - unittest.main() diff --git a/indra/lib/python/indra/util/llmanifest.py b/indra/lib/python/indra/util/llmanifest.py index 11945a2391..b285b46c7d 100644 --- a/indra/lib/python/indra/util/llmanifest.py +++ b/indra/lib/python/indra/util/llmanifest.py @@ -33,12 +33,26 @@ import fnmatch import getopt import glob +import itertools +import operator import os import re import shutil +import subprocess import sys import tarfile -import errno + +class ManifestError(RuntimeError): + """Use an exception more specific than generic Python RuntimeError""" + def __init__(self, msg): + self.msg = msg + super(ManifestError, self).__init__(self.msg) + +class MissingError(ManifestError): + """You specified a file that doesn't exist""" + def __init__(self, msg): + self.msg = msg + super(MissingError, self).__init__(self.msg) def path_ancestors(path): drive, path = os.path.splitdrive(os.path.normpath(path)) @@ -75,33 +89,11 @@ def get_default_platform(dummy): 'darwin':'darwin' }[sys.platform] -def get_default_version(srctree): - # look up llversion.h and parse out the version info - paths = [os.path.join(srctree, x, 'llversionviewer.h') for x in ['llcommon', '../llcommon', '../../indra/llcommon.h']] - for p in paths: - if os.path.exists(p): - contents = open(p, 'r').read() - major = re.search("LL_VERSION_MAJOR\s=\s([0-9]+)", contents).group(1) - minor = re.search("LL_VERSION_MINOR\s=\s([0-9]+)", contents).group(1) - patch = re.search("LL_VERSION_PATCH\s=\s([0-9]+)", contents).group(1) - build = re.search("LL_VERSION_BUILD\s=\s([0-9]+)", contents).group(1) - return major, minor, patch, build - -def get_channel(srctree): - # look up llversionserver.h and parse out the version info - paths = [os.path.join(srctree, x, 'llversionviewer.h') for x in ['llcommon', '../llcommon', '../../indra/llcommon.h']] - for p in paths: - if os.path.exists(p): - contents = open(p, 'r').read() - channel = re.search("LL_CHANNEL\s=\s\"(.+)\";\s*$", contents, flags = re.M).group(1) - return channel - - DEFAULT_SRCTREE = os.path.dirname(sys.argv[0]) -DEFAULT_CHANNEL = 'Second Life Release' -DEFAULT_CHANNEL_SNOWGLOBE = 'Snowglobe Release' +CHANNEL_VENDOR_BASE = 'Singularity' +RELEASE_CHANNEL = CHANNEL_VENDOR_BASE + ' Release' -ARGUMENTS=[ +BASE_ARGUMENTS=[ dict(name='actions', description="""This argument specifies the actions that are to be taken when the script is run. The meaningful actions are currently: @@ -119,28 +111,23 @@ def get_channel(srctree): Example use: %(name)s --arch=i686 On Linux this would try to use Linux_i686Manifest.""", default=""), + dict(name='artwork', description='Artwork directory.', default=DEFAULT_SRCTREE), + dict(name='branding_id', description="Identifier for the branding set to use.", default='singularity'), dict(name='build', description='Build directory.', default=DEFAULT_SRCTREE), - dict(name='buildtype', description="""The build type used. ('Debug', 'Release', or 'RelWithDebInfo') - Default is Release """, - default="Release"), - dict(name='branding_id', description="""Identifier for the branding set to - use. Currently, 'secondlife' or 'snowglobe')""", - default='secondlife'), + dict(name='buildtype', description='Build type (i.e. Debug, Release, RelWithDebInfo).', default=None), + dict(name='channel', + description="""The channel to use for updates, packaging, settings name, etc.""", + default='CHANNEL UNSET'), + dict(name='channel_suffix', + description="""Addition to the channel for packaging and channel value, + but not application name (used internally)""", + default=None), dict(name='configuration', - description="""The build configuration used. Only used on OS X for - now, but it could be used for other platforms as well.""", - default="Universal"), + description="""The build configuration used.""", + default="Release"), dict(name='dest', description='Destination directory.', default=DEFAULT_SRCTREE), dict(name='grid', - description="""Which grid the client will try to connect to. Even - though it's not strictly a grid, 'firstlook' is also an acceptable - value for this parameter.""", - default=""), - dict(name='channel', - description="""The channel to use for updates, packaging, settings name, etc.""", - default=get_channel), - dict(name='login_channel', - description="""The channel to use for login handshake/updates only.""", + description="""Which grid the client will try to connect to.""", default=None), dict(name='installer_name', description=""" The name of the file that the installer should be @@ -153,34 +140,33 @@ def get_channel(srctree): description="""The current platform, to be used for looking up which manifest class to run.""", default=get_default_platform), + dict(name='signature', + description="""This specifies an identity to sign the viewer with, if any. + If no value is supplied, the default signature will be used, if any. Currently + only used on Mac OS X.""", + default=None), dict(name='source', description='Source directory.', default=DEFAULT_SRCTREE), dict(name='standalone', description='Set to ON if this is a standalone build.', default="OFF"), - dict(name='artwork', description='Artwork directory.', default=DEFAULT_SRCTREE), dict(name='touch', description="""File to touch when action is finished. Touch file will contain the name of the final package in a form suitable for use by a .bat file.""", default=None), - dict(name='version', - description="""This specifies the version of Second Life that is - being packaged up.""", - default=get_default_version), - dict(name='extra_libraries', - description="""List of extra libraries to include in package""", - default=None) + dict(name='versionfile', + description="""The name of a file containing the full version number."""), ] -def usage(srctree=""): +def usage(arguments, srctree=""): nd = {'name':sys.argv[0]} print """Usage: %(name)s [options] [destdir] Options: """ % nd - for arg in ARGUMENTS: + for arg in arguments: default = arg['default'] if hasattr(default, '__call__'): default = "(computed value) \"" + str(default(srctree)) + '"' @@ -191,8 +177,15 @@ def usage(srctree=""): default, arg['description'] % nd) -def main(): - option_names = [arg['name'] + '=' for arg in ARGUMENTS] +def main(extra=[]): +## print ' '.join((("'%s'" % item) if ' ' in item else item) +## for item in itertools.chain([sys.executable], sys.argv)) + # Supplement our default command-line switches with any desired by + # application-specific caller. + arguments = list(itertools.chain(BASE_ARGUMENTS, extra)) + # Alphabetize them by option name in case we display usage. + arguments.sort(key=operator.itemgetter('name')) + option_names = [arg['name'] + '=' for arg in arguments] option_names.append('help') options, remainder = getopt.getopt(sys.argv[1:], "", option_names) @@ -215,11 +208,11 @@ def main(): # early out for help if 'help' in args: # *TODO: it is a huge hack to pass around the srctree like this - usage(args['source']) + usage(arguments, srctree=args['source']) return # defaults - for arg in ARGUMENTS: + for arg in arguments: if arg['name'] not in args: default = arg['default'] if hasattr(default, '__call__'): @@ -228,12 +221,17 @@ def main(): args[arg['name']] = default # fix up version - if isinstance(args.get('version'), str): - args['version'] = args['version'].split('.') - - # default and agni are default - if args['grid'] in ['default', 'agni']: - args['grid'] = '' + if isinstance(args.get('versionfile'), str): + try: # read in the version string + vf = open(args['versionfile'], 'r') + args['version'] = vf.read().strip().split('.') + except: + print "Unable to read versionfile '%s'" % args['versionfile'] + raise + + # unspecified, default, and agni are default + if args['grid'] in ['', 'default', 'agni']: + args['grid'] = None if 'actions' in args: args['actions'] = args['actions'].split() @@ -242,16 +240,69 @@ def main(): for opt in args: print "Option:", opt, "=", args[opt] + # pass in sourceid as an argument now instead of an environment variable + args['sourceid'] = os.environ.get("sourceid", "") + + # Build base package. + touch = args.get('touch') + if touch: + print '================ Creating base package' + else: + print '================ Starting base copy' wm = LLManifest.for_platform(args['platform'], args.get('arch'))(args) wm.do(*args['actions']) - + # Store package file for later if making touched file. + base_package_file = "" + if touch: + print '================ Created base package ', wm.package_file + base_package_file = "" + wm.package_file + else: + print '================ Finished base copy' + + # handle multiple packages if set + # ''.split() produces empty list + additional_packages = os.environ.get("additional_packages", "").split() + if additional_packages: + # Determine destination prefix / suffix for additional packages. + base_dest_parts = list(os.path.split(args['dest'])) + base_dest_parts.insert(-1, "{}") + base_dest_template = os.path.join(*base_dest_parts) + # Determine touched prefix / suffix for additional packages. + if touch: + base_touch_parts = list(os.path.split(touch)) + # Because of the special insert() logic below, we don't just want + # [dirpath, basename]; we want [dirpath, directory, basename]. + # Further split the dirpath and replace it in the list. + base_touch_parts[0:1] = os.path.split(base_touch_parts[0]) + if "arwin" in args['platform']: + base_touch_parts.insert(-1, "{}") + else: + base_touch_parts.insert(-2, "{}") + base_touch_template = os.path.join(*base_touch_parts) + for package_id in additional_packages: + args['channel_suffix'] = os.environ.get(package_id + "_viewer_channel_suffix") + args['sourceid'] = os.environ.get(package_id + "_sourceid") + args['dest'] = base_dest_template.format(package_id) + if touch: + print '================ Creating additional package for "', package_id, '" in ', args['dest'] + else: + print '================ Starting additional copy for "', package_id, '" in ', args['dest'] + try: + wm = LLManifest.for_platform(args['platform'], args.get('arch'))(args) + wm.do(*args['actions']) + except Exception as err: + sys.exit(str(err)) + if touch: + print '================ Created additional package ', wm.package_file, ' for ', package_id + with open(base_touch_template.format(package_id), 'w') as fp: + fp.write('set package_file=%s\n' % wm.package_file) + else: + print '================ Finished additional copy "', package_id, '" in ', args['dest'] # Write out the package file in this format, so that it can easily be called # and used in a .bat file - yeah, it sucks, but this is the simplest... - touch = args.get('touch') if touch: - fp = open(touch, 'w') - fp.write('set package_file=%s\n' % wm.package_file) - fp.close() + with open(touch, 'w') as fp: + fp.write('set package_file=%s\n' % base_package_file) print 'touched', touch return 0 @@ -267,7 +318,7 @@ class LLManifest(object): manifests = {} def for_platform(self, platform, arch = None): if arch: - platform = platform + '_' + arch + platform = platform + '_' + arch + '_' return self.manifests[platform.lower()] for_platform = classmethod(for_platform) @@ -284,18 +335,8 @@ def __init__(self, args): self.created_paths = [] self.package_name = "Unknown" - def default_grid(self): - return self.args.get('grid', None) == '' def default_channel(self): - return self.args.get('channel', None) == DEFAULT_CHANNEL - - def default_channel_for_brand(self): - if self.viewer_branding_id()=='secondlife': - return self.args.get('channel', None) == DEFAULT_CHANNEL - elif self.viewer_branding_id()=="snowglobe": - return self.args.get('channel', None) == DEFAULT_CHANNEL_SNOWGLOBE - else: - return True + return self.args.get('channel', None) == RELEASE_CHANNEL def construct(self): """ Meant to be overriden by LLManifest implementors with code that @@ -307,22 +348,113 @@ def exclude(self, glob): in the file list by path().""" self.excludes.append(glob) - def prefix(self, src='', build=None, dst=None): - """ Pushes a prefix onto the stack. Until end_prefix is - called, all relevant method calls (esp. to path()) will prefix - paths with the entire prefix stack. Source and destination - prefixes can be different, though if only one is provided they - are both equal. To specify a no-op, use an empty string, not - None.""" - if dst is None: - dst = src - if build is None: - build = src + def prefix(self, src='', build='', dst='', src_dst=None): + """ + Usage: + + with self.prefix(...args as described...): + self.path(...) + + For the duration of the 'with' block, pushes a prefix onto the stack. + Within that block, all relevant method calls (esp. to path()) will + prefix paths with the entire prefix stack. Source and destination + prefixes are independent; if omitted (or passed as the empty string), + the prefix has no effect. Thus: + + with self.prefix(src='foo'): + # no effect on dst + + with self.prefix(dst='bar'): + # no effect on src + + If you want to set both at once, use src_dst: + + with self.prefix(src_dst='subdir'): + # same as self.prefix(src='subdir', dst='subdir') + # Passing src_dst makes any src or dst argument in the same + # parameter list irrelevant. + + Also supports the older (pre-Python-2.5) syntax: + + if self.prefix(...args as described...): + self.path(...) + self.end_prefix(...) + + Before the arrival of the 'with' statement, one was required to code + self.prefix() and self.end_prefix() in matching pairs to push and to + pop the prefix stacks, respectively. The older prefix() method + returned True specifically so that the caller could indent the + relevant block of code with 'if', just for aesthetic purposes. + """ + if src_dst is not None: + src = src_dst + dst = src_dst self.src_prefix.append(src) self.artwork_prefix.append(src) self.build_prefix.append(build) self.dst_prefix.append(dst) - return True # so that you can wrap it in an if to get indentation + +## self.display_stacks() + + # The above code is unchanged from the original implementation. What's + # new is the return value. We're going to return an instance of + # PrefixManager that binds this LLManifest instance and Does The Right + # Thing on exit. + return self.PrefixManager(self) + + def display_stacks(self): + width = 1 + max(len(stack) for stack in self.PrefixManager.stacks) + for stack in self.PrefixManager.stacks: + print "{} {}".format((stack + ':').ljust(width), + os.path.join(*getattr(self, stack))) + + class PrefixManager(object): + # stack attributes we manage in this LLManifest (sub)class + # instance + stacks = ("src_prefix", "artwork_prefix", "build_prefix", "dst_prefix") + + def __init__(self, manifest): + self.manifest = manifest + # If the caller wrote: + # with self.prefix(...): + # as intended, then bind the state of each prefix stack as it was + # just BEFORE the call to prefix(). Since prefix() appended an + # entry to each prefix stack, capture len()-1. + self.prevlen = { stack: len(getattr(self.manifest, stack)) - 1 + for stack in self.stacks } + + def __nonzero__(self): + # If the caller wrote: + # if self.prefix(...): + # then a value of this class had better evaluate as 'True'. + return True + + def __enter__(self): + # nobody uses 'with self.prefix(...) as variable:' + return None + + def __exit__(self, type, value, traceback): + # First, if the 'with' block raised an exception, just propagate. + # Do NOT swallow it. + if type is not None: + return False + + # Okay, 'with' block completed successfully. Restore previous + # state of each of the prefix stacks in self.stacks. + # Note that we do NOT simply call pop() on them as end_prefix() + # does. This is to cope with the possibility that the coder + # changed 'if self.prefix(...):' to 'with self.prefix(...):' yet + # forgot to remove the self.end_prefix(...) call at the bottom of + # the block. In that case, calling pop() again would be Bad! But + # if we restore the length of each stack to what it was before the + # current prefix() block, it doesn't matter whether end_prefix() + # was called or not. + for stack, prevlen in self.prevlen.items(): + # find the attribute in 'self.manifest' named by 'stack', and + # truncate that list back to 'prevlen' + del getattr(self.manifest, stack)[prevlen:] + +## self.manifest.display_stacks() def end_prefix(self, descr=None): """Pops a prefix off the stack. If given an argument, checks @@ -369,6 +501,19 @@ def dst_path_of(self, relpath): relative to the destination directory.""" return os.path.join(self.get_dst_prefix(), relpath) + def _relative_dst_path(self, dstpath): + """ + Returns the path to a file or directory relative to the destination directory. + This should only be used for generating diagnostic output in the path method. + """ + dest_root=self.dst_prefix[0] + if dstpath.startswith(dest_root+os.path.sep): + return dstpath[len(dest_root)+1:] + elif dstpath.startswith(dest_root): + return dstpath[len(dest_root):] + else: + return dstpath + def ensure_src_dir(self, reldir): """Construct the path for a directory relative to the source path, and ensures that it exists. Returns the @@ -386,40 +531,42 @@ def ensure_dst_dir(self, reldir): return path def run_command(self, command): - """ Runs an external command, and returns the output. Raises - an exception if the command reurns a nonzero status code. For - debugging/informational purpoases, prints out the command's - output as it is received.""" + """ + Runs an external command. + Raises ManifestError exception if the command returns a nonzero status. + """ print "Running command:", command - fd = os.popen(command, 'r') - lines = [] - while True: - lines.append(fd.readline()) - if lines[-1] == '': - break - else: - print lines[-1], - output = ''.join(lines) - status = fd.close() - if status: - raise RuntimeError( - "Command %s returned non-zero status (%s) \noutput:\n%s" - % (command, status, output) ) - return output + sys.stdout.flush() + try: + subprocess.check_call(command) + except subprocess.CalledProcessError as err: + raise ManifestError( "Command %s returned non-zero status (%s)" + % (command, err.returncode) ) def created_path(self, path): """ Declare that you've created a path in order to a) verify that you really have created it b) schedule it for cleanup""" if not os.path.exists(path): - raise RuntimeError, "Should be something at path " + path + raise ManifestError, "Should be something at path " + path self.created_paths.append(path) - def put_in_file(self, contents, dst): + def put_in_file(self, contents, dst, src=None): # write contents as dst - f = open(self.dst_path_of(dst), "wb") - f.write(contents) - f.close() + dst_path = self.dst_path_of(dst) + self.cmakedirs(os.path.dirname(dst_path)) + f = open(dst_path, "wb") + try: + f.write(contents) + finally: + f.close() + + # Why would we create a file in the destination tree if not to include + # it in the installer? The default src=None (plus the fact that the + # src param is last) is to preserve backwards compatibility. + if src: + self.file_list.append([src, dst_path]) + return dst_path def replace_in(self, src, dst=None, searchdict={}): if dst == None: @@ -439,11 +586,7 @@ def copy_action(self, src, dst): # ensure that destination path exists self.cmakedirs(os.path.dirname(dst)) self.created_paths.append(dst) - if not os.path.isdir(src): - self.ccopy(src,dst) - else: - # src is a dir - self.ccopytree(src,dst) + self.ccopymumble(src, dst) else: print "Doesn't exist:", src @@ -473,9 +616,16 @@ def cleanup_finish(self): # *TODO is this gonna be useful? print "Cleaning up " + c + def process_either(self, src, dst): + # If it's a real directory, recurse through it -- + # but not a symlink! Handle those like files. + if os.path.isdir(src) and not os.path.islink(src): + return self.process_directory(src, dst) + else: + return self.process_file(src, dst) + def process_file(self, src, dst): if self.includes(src, dst): -# print src, "=>", dst for action in self.actions: methodname = action + "_action" method = getattr(self, methodname, None) @@ -500,10 +650,7 @@ def process_directory(self, src, dst): for name in names: srcname = os.path.join(src, name) dstname = os.path.join(dst, name) - if os.path.isdir(srcname): - count += self.process_directory(srcname, dstname) - else: - count += self.process_file(srcname, dstname) + count += self.process_either(srcname, dstname) return count def includes(self, src, dst): @@ -522,28 +669,43 @@ def remove(self, *paths): else: os.remove(path) - def ccopy(self, src, dst): - """ Copy a single file or symlink. Uses filecmp to skip copying for existing files.""" + def ccopymumble(self, src, dst): + """Copy a single symlink, file or directory.""" if os.path.islink(src): linkto = os.readlink(src) - if os.path.islink(dst) or os.path.exists(dst): + if os.path.islink(dst) or os.path.isfile(dst): os.remove(dst) # because symlinking over an existing link fails + elif os.path.isdir(dst): + shutil.rmtree(dst) os.symlink(linkto, dst) + elif os.path.isdir(src): + self.ccopytree(src, dst) else: - # Don't recopy file if it's up-to-date. - # If we seem to be not not overwriting files that have been - # updated, set the last arg to False, but it will take longer. - if os.path.exists(dst) and filecmp.cmp(src, dst, True): - return - # only copy if it's not excluded - if self.includes(src, dst): - try: - os.unlink(dst) - except OSError, err: - if err.errno != errno.ENOENT: - raise - - shutil.copy2(src, dst) + self.ccopyfile(src, dst) + # XXX What about devices, sockets etc.? + # YYY would we put such things into a viewer package?! + + def ccopyfile(self, src, dst): + """ Copy a single file. Uses filecmp to skip copying for existing files.""" + # Don't recopy file if it's up-to-date. + # If we seem to be not not overwriting files that have been + # updated, set the last arg to False, but it will take longer. +## reldst = (dst[len(self.dst_prefix[0]):] +## if dst.startswith(self.dst_prefix[0]) +## else dst).lstrip(r'\/') + if os.path.exists(dst) and filecmp.cmp(src, dst, True): +## print "{} (skipping, {} exists)".format(src, reldst) + return + # only copy if it's not excluded + if self.includes(src, dst): + try: + os.unlink(dst) + except OSError as err: + if err.errno != errno.ENOENT: + raise + +## print "{} => {}".format(src, reldst) + shutil.copy2(src, dst) def ccopytree(self, src, dst): """Direct copy of shutil.copytree with the additional @@ -559,15 +721,11 @@ def ccopytree(self, src, dst): srcname = os.path.join(src, name) dstname = os.path.join(dst, name) try: - if os.path.isdir(srcname): - self.ccopytree(srcname, dstname) - else: - self.ccopy(srcname, dstname) - # XXX What about devices, sockets etc.? - except (IOError, os.error), why: + self.ccopymumble(srcname, dstname) + except (IOError, os.error) as why: errors.append((srcname, dstname, why)) if errors: - raise RuntimeError, errors + raise ManifestError, errors def cmakedirs(self, path): @@ -615,11 +773,10 @@ def wildcard_regex(self, src_glob, dst_glob): def check_file_exists(self, path): if not os.path.exists(path) and not os.path.islink(path): - raise RuntimeError("Path %s doesn't exist" % ( - os.path.normpath(os.path.join(os.getcwd(), path)),)) + raise MissingError("Path %s doesn't exist" % (os.path.abspath(path),)) - wildcard_pattern = re.compile('\*') + wildcard_pattern = re.compile(r'\*') def expand_globs(self, src, dst): src_list = glob.glob(src) src_re, d_template = self.wildcard_regex(src.replace('\\', '/'), @@ -628,41 +785,64 @@ def expand_globs(self, src, dst): d = src_re.sub(d_template, s.replace('\\', '/')) yield os.path.normpath(s), os.path.normpath(d) + def path2basename(self, path, file): + """ + It is a common idiom to write: + self.path(os.path.join(somedir, somefile), somefile) + + So instead you can write: + self.path2basename(somedir, somefile) + + Note that this is NOT the same as: + self.path(os.path.join(somedir, somefile)) + + which is the same as: + temppath = os.path.join(somedir, somefile) + self.path(temppath, temppath) + """ + return self.path(os.path.join(path, file), file) + def path(self, src, dst=None): - sys.stdout.write("Processing %s => %s ... " % (src, dst)) sys.stdout.flush() if src == None: - raise RuntimeError("No source file, dst is " + dst) + raise ManifestError("No source file, dst is " + dst) if dst == None: dst = src dst = os.path.join(self.get_dst_prefix(), dst) - count = 0 - is_glob = False + sys.stdout.write("Processing %s => %s ... " % (src, self._relative_dst_path(dst))) - # look under each prefix for matching paths - paths = set([os.path.join(self.get_src_prefix(), src), - os.path.join(self.get_artwork_prefix(), src), - os.path.join(self.get_build_prefix(), src)]) - for path in paths: - if self.wildcard_pattern.search(path): - is_glob = True - for s,d in self.expand_globs(path, dst): + def try_path(src): + # expand globs + count = 0 + if self.wildcard_pattern.search(src): + for s,d in self.expand_globs(src, dst): assert(s != d) count += self.process_file(s, d) else: - # if it's a directory, recurse through it - if os.path.isdir(path): - count += self.process_directory(path, dst) - elif os.path.exists(path): - count += self.process_file(path, dst) - - # if we're specifying a single path (not a glob), - # we should error out if it doesn't exist - if count == 0 and not is_glob: - raise RuntimeError("No files match %s\n" % str(paths)) - + # if we're specifying a single path (not a glob), + # we should error out if it doesn't exist + self.check_file_exists(src) + count += self.process_either(src, dst) + return count + + try_prefixes = [self.get_src_prefix(), self.get_artwork_prefix(), self.get_build_prefix()] + tried=[] + count=0 + while not count and try_prefixes: + pfx = try_prefixes.pop(0) + try: + count = try_path(os.path.join(pfx, src)) + except MissingError: + tried.append(pfx) + if not try_prefixes: + # no more prefixes left to try + print "unable to find '%s'; looked in:\n %s" % (src, '\n '.join(tried)) print "%d files" % count + # Let caller check whether we processed as many files as expected. In + # particular, let caller notice 0. + return count + def do(self, *actions): self.actions = actions self.construct() diff --git a/indra/lib/python/indra/util/llperformance.py b/indra/lib/python/indra/util/llperformance.py deleted file mode 100755 index 7c52730b5e..0000000000 --- a/indra/lib/python/indra/util/llperformance.py +++ /dev/null @@ -1,158 +0,0 @@ -#!/usr/bin/python - -# ------------------------------------------------ -# Sim metrics utility functions. - -import glob, os, time, sys, stat, exceptions - -from indra.base import llsd - -gBlockMap = {} #Map of performance metric data with function hierarchy information. -gCurrentStatPath = "" - -gIsLoggingEnabled=False - -class LLPerfStat: - def __init__(self,key): - self.mTotalTime = 0 - self.mNumRuns = 0 - self.mName=key - self.mTimeStamp = int(time.time()*1000) - self.mUTCTime = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()) - - def __str__(self): - return "%f" % self.mTotalTime - - def start(self): - self.mStartTime = int(time.time() * 1000000) - self.mNumRuns += 1 - - def stop(self): - execution_time = int(time.time() * 1000000) - self.mStartTime - self.mTotalTime += execution_time - - def get_map(self): - results={} - results['name']=self.mName - results['utc_time']=self.mUTCTime - results['timestamp']=self.mTimeStamp - results['us']=self.mTotalTime - results['count']=self.mNumRuns - return results - -class PerfError(exceptions.Exception): - def __init__(self): - return - - def __Str__(self): - print "","Unfinished LLPerfBlock" - -class LLPerfBlock: - def __init__( self, key ): - global gBlockMap - global gCurrentStatPath - global gIsLoggingEnabled - - #Check to see if we're running metrics right now. - if gIsLoggingEnabled: - self.mRunning = True #Mark myself as running. - - self.mPreviousStatPath = gCurrentStatPath - gCurrentStatPath += "/" + key - if gCurrentStatPath not in gBlockMap: - gBlockMap[gCurrentStatPath] = LLPerfStat(key) - - self.mStat = gBlockMap[gCurrentStatPath] - self.mStat.start() - - def finish( self ): - global gBlockMap - global gIsLoggingEnabled - - if gIsLoggingEnabled: - self.mStat.stop() - self.mRunning = False - gCurrentStatPath = self.mPreviousStatPath - -# def __del__( self ): -# if self.mRunning: -# #SPATTERS FIXME -# raise PerfError - -class LLPerformance: - #-------------------------------------------------- - # Determine whether or not we want to log statistics - - def __init__( self, process_name = "python" ): - self.process_name = process_name - self.init_testing() - self.mTimeStamp = int(time.time()*1000) - self.mUTCTime = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()) - - def init_testing( self ): - global gIsLoggingEnabled - - host_performance_file = "/dev/shm/simperf/simperf_proc_config.llsd" - - #If file exists, open - if os.path.exists(host_performance_file): - file = open (host_performance_file,'r') - - #Read serialized LLSD from file. - body = llsd.parse(file.read()) - - #Calculate time since file last modified. - stats = os.stat(host_performance_file) - now = time.time() - mod = stats[stat.ST_MTIME] - age = now - mod - - if age < ( body['duration'] ): - gIsLoggingEnabled = True - - - def get ( self ): - global gIsLoggingEnabled - return gIsLoggingEnabled - - #def output(self,ptr,path): - # if 'stats' in ptr: - # stats = ptr['stats'] - # self.mOutputPtr[path] = stats.get_map() - - # if 'children' in ptr: - # children=ptr['children'] - - # curptr = self.mOutputPtr - # curchildren={} - # curptr['children'] = curchildren - - # for key in children: - # curchildren[key]={} - # self.mOutputPtr = curchildren[key] - # self.output(children[key],path + '/' + key) - - def done(self): - global gBlockMap - - if not self.get(): - return - - output_name = "/dev/shm/simperf/%s_proc.%d.llsd" % (self.process_name, os.getpid()) - output_file = open(output_name, 'w') - process_info = { - "name" : self.process_name, - "pid" : os.getpid(), - "ppid" : os.getppid(), - "timestamp" : self.mTimeStamp, - "utc_time" : self.mUTCTime, - } - output_file.write(llsd.format_notation(process_info)) - output_file.write('\n') - - for key in gBlockMap.keys(): - gBlockMap[key] = gBlockMap[key].get_map() - output_file.write(llsd.format_notation(gBlockMap)) - output_file.write('\n') - output_file.close() - diff --git a/indra/lib/python/indra/util/llsubprocess.py b/indra/lib/python/indra/util/llsubprocess.py deleted file mode 100644 index c4c40739ec..0000000000 --- a/indra/lib/python/indra/util/llsubprocess.py +++ /dev/null @@ -1,106 +0,0 @@ -"""\ -@file llsubprocess.py -@author Phoenix -@date 2008-01-18 -@brief The simplest possible wrapper for a common sub-process paradigm. - -$LicenseInfo:firstyear=2007&license=mit$ - -Copyright (c) 2007-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -import os -import popen2 -import time -import select - -class Timeout(RuntimeError): - "Exception raised when a subprocess times out." - pass - -def run(command, args=None, data=None, timeout=None): - """\ -@brief Run command with arguments - -This is it. This is the function I want to run all the time when doing -subprocces, but end up copying the code everywhere. none of the -standard commands are secure and provide a way to specify input, get -all the output, and get the result. -@param command A string specifying a process to launch. -@param args Arguments to be passed to command. Must be list, tuple or None. -@param data input to feed to the command. -@param timeout Maximum number of many seconds to run. -@return Returns (result, stdout, stderr) from process. -""" - cmd = [command] - if args: - cmd.extend([str(arg) for arg in args]) - #print "cmd: ","' '".join(cmd) - child = popen2.Popen3(cmd, True) - #print child.pid - out = [] - err = [] - result = -1 - time_left = timeout - tochild = [child.tochild.fileno()] - while True: - time_start = time.time() - #print "time:",time_left - p_in, p_out, p_err = select.select( - [child.fromchild.fileno(), child.childerr.fileno()], - tochild, - [], - time_left) - if p_in: - new_line = os.read(child.fromchild.fileno(), 32 * 1024) - if new_line: - #print "line:",new_line - out.append(new_line) - new_line = os.read(child.childerr.fileno(), 32 * 1024) - if new_line: - #print "error:", new_line - err.append(new_line) - if p_out: - if data: - #print "p_out" - bytes = os.write(child.tochild.fileno(), data) - data = data[bytes:] - if len(data) == 0: - data = None - tochild = [] - child.tochild.close() - result = child.poll() - if result != -1: - child.tochild.close() - child.fromchild.close() - child.childerr.close() - break - if time_left is not None: - time_left -= (time.time() - time_start) - if time_left < 0: - raise Timeout - #print "result:",result - out = ''.join(out) - #print "stdout:", out - err = ''.join(err) - #print "stderr:", err - return result, out, err diff --git a/indra/lib/python/indra/util/llversion.py b/indra/lib/python/indra/util/llversion.py deleted file mode 100644 index 770b861ddc..0000000000 --- a/indra/lib/python/indra/util/llversion.py +++ /dev/null @@ -1,95 +0,0 @@ -"""@file llversion.py -@brief Utility for parsing llcommon/llversion${server}.h - for the version string and channel string - Utility that parses svn info for branch and revision - -$LicenseInfo:firstyear=2006&license=mit$ - -Copyright (c) 2006-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -import re, sys, os, commands - -# Methods for gathering version information from -# llversionviewer.h and llversionserver.h - -def get_src_root(): - indra_lib_python_indra_path = os.path.dirname(__file__) - return os.path.abspath(os.path.realpath(indra_lib_python_indra_path + "/../../../../../")) - -def get_version_file_contents(version_type): - filepath = get_src_root() + '/indra/llcommon/llversion%s.h' % version_type - file = open(filepath,"r") - file_str = file.read() - file.close() - return file_str - -def get_version(version_type): - file_str = get_version_file_contents(version_type) - m = re.search('const S32 LL_VERSION_MAJOR = (\d+);', file_str) - VER_MAJOR = m.group(1) - m = re.search('const S32 LL_VERSION_MINOR = (\d+);', file_str) - VER_MINOR = m.group(1) - m = re.search('const S32 LL_VERSION_PATCH = (\d+);', file_str) - VER_PATCH = m.group(1) - m = re.search('const S32 LL_VERSION_BUILD = (\d+);', file_str) - VER_BUILD = m.group(1) - version = "%(VER_MAJOR)s.%(VER_MINOR)s.%(VER_PATCH)s.%(VER_BUILD)s" % locals() - return version - -def get_channel(version_type): - file_str = get_version_file_contents(version_type) - m = re.search('const char \* const LL_CHANNEL = "(.+)";', file_str) - return m.group(1) - -def get_viewer_version(): - return get_version('viewer') - -def get_server_version(): - return get_version('server') - -def get_viewer_channel(): - return get_channel('viewer') - -def get_server_channel(): - return get_channel('server') - -# Methods for gathering subversion information -def get_svn_status_matching(regular_expression): - # Get the subversion info from the working source tree - status, output = commands.getstatusoutput('svn info %s' % get_src_root()) - m = regular_expression.search(output) - if not m: - print "Failed to parse svn info output, resultfollows:" - print output - raise Exception, "No matching svn status in "+src_root - return m.group(1) - -def get_svn_branch(): - branch_re = re.compile('URL: (\S+)') - return get_svn_status_matching(branch_re) - -def get_svn_revision(): - last_rev_re = re.compile('Last Changed Rev: (\d+)') - return get_svn_status_matching(last_rev_re) - - diff --git a/indra/lib/python/indra/util/named_query.py b/indra/lib/python/indra/util/named_query.py deleted file mode 100644 index 192e59275a..0000000000 --- a/indra/lib/python/indra/util/named_query.py +++ /dev/null @@ -1,572 +0,0 @@ -"""\ -@file named_query.py -@author Ryan Williams, Phoenix -@date 2007-07-31 -@brief An API for running named queries. - -$LicenseInfo:firstyear=2007&license=mit$ - -Copyright (c) 2007-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -import errno -import MySQLdb -import MySQLdb.cursors -import os -import os.path -import re -import time - -from indra.base import llsd -from indra.base import config - -DEBUG = False - -NQ_FILE_SUFFIX = config.get('named-query-file-suffix', '.nq') -NQ_FILE_SUFFIX_LEN = len(NQ_FILE_SUFFIX) - -_g_named_manager = None - -def _init_g_named_manager(sql_dir = None): - """Initializes a global NamedManager object to point at a - specified named queries hierarchy. - - This function is intended entirely for testing purposes, - because it's tricky to control the config from inside a test.""" - if sql_dir is None: - sql_dir = config.get('named-query-base-dir') - - # extra fallback directory in case config doesn't return what we want - if sql_dir is None: - sql_dir = os.path.abspath( - os.path.join( - os.path.realpath(os.path.dirname(__file__)), "..", "..", "..", "..", "web", "dataservice", "sql")) - - global _g_named_manager - _g_named_manager = NamedQueryManager( - os.path.abspath(os.path.realpath(sql_dir))) - -def get(name): - "Get the named query object to be used to perform queries" - if _g_named_manager is None: - _init_g_named_manager() - return _g_named_manager.get(name) - -def sql(connection, name, params): - # use module-global NamedQuery object to perform default substitution - return get(name).sql(connection, params) - -def run(connection, name, params, expect_rows = None): - """\ -@brief given a connection, run a named query with the params - -Note that this function will fetch ALL rows. -@param connection The connection to use -@param name The name of the query to run -@param params The parameters passed into the query -@param expect_rows The number of rows expected. Set to 1 if return_as_map is true. Raises ExpectationFailed if the number of returned rows doesn't exactly match. Kind of a hack. -@return Returns the result set as a list of dicts. -""" - return get(name).run(connection, params, expect_rows) - -class ExpectationFailed(Exception): - """ Exception that is raised when an expectation for an sql query - is not met.""" - def __init__(self, message): - Exception.__init__(self, message) - self.message = message - -class NamedQuery(object): - def __init__(self, name, filename): - """ Construct a NamedQuery object. The name argument is an - arbitrary name as a handle for the query, and the filename is - a path to a file or a file-like object containing an llsd named - query document.""" - self._stat_interval_seconds = 5 # 5 seconds - self._name = name - if (filename is not None and isinstance(filename, (str, unicode)) - and NQ_FILE_SUFFIX != filename[-NQ_FILE_SUFFIX_LEN:]): - filename = filename + NQ_FILE_SUFFIX - self._location = filename - self._alternative = dict() - self._last_mod_time = 0 - self._last_check_time = 0 - self.deleted = False - self.load_contents() - - def name(self): - """ The name of the query. """ - return self._name - - def get_modtime(self): - """ Returns the mtime (last modified time) of the named query - filename. For file-like objects, expect a modtime of 0""" - if self._location and isinstance(self._location, (str, unicode)): - return os.path.getmtime(self._location) - return 0 - - def load_contents(self): - """ Loads and parses the named query file into self. Does - nothing if self.location is nonexistant.""" - if self._location: - if isinstance(self._location, (str, unicode)): - contents = llsd.parse(open(self._location).read()) - else: - # we probably have a file-like object. Godspeed! - contents = llsd.parse(self._location.read()) - self._reference_contents(contents) - # Check for alternative implementations - try: - for name, alt in self._contents['alternative'].items(): - nq = NamedQuery(name, None) - nq._reference_contents(alt) - self._alternative[name] = nq - except KeyError, e: - pass - self._last_mod_time = self.get_modtime() - self._last_check_time = time.time() - - def _reference_contents(self, contents): - "Helper method which builds internal structure from parsed contents" - self._contents = contents - self._ttl = int(self._contents.get('ttl', 0)) - self._return_as_map = bool(self._contents.get('return_as_map', False)) - self._legacy_dbname = self._contents.get('legacy_dbname', None) - - # reset these before doing the sql conversion because we will - # read them there. reset these while loading so we pick up - # changes. - self._around = set() - self._append = set() - self._integer = set() - self._options = self._contents.get('dynamic_where', {}) - for key in self._options: - if isinstance(self._options[key], basestring): - self._options[key] = self._convert_sql(self._options[key]) - elif isinstance(self._options[key], list): - lines = [] - for line in self._options[key]: - lines.append(self._convert_sql(line)) - self._options[key] = lines - else: - moreopt = {} - for kk in self._options[key]: - moreopt[kk] = self._convert_sql(self._options[key][kk]) - self._options[key] = moreopt - self._base_query = self._convert_sql(self._contents['base_query']) - self._query_suffix = self._convert_sql( - self._contents.get('query_suffix', '')) - - def _convert_sql(self, sql): - """convert the parsed sql into a useful internal structure. - - This function has to turn the named query format into a pyformat - style. It also has to look for %:name% and :name% and - ready them for use in LIKE statements""" - if sql: - # This first sub is to properly escape any % signs that - # are meant to be literally passed through to mysql in the - # query. It leaves any %'s that are used for - # like-expressions. - expr = re.compile("(?<=[^a-zA-Z0-9_-])%(?=[^:])") - sql = expr.sub('%%', sql) - - # This should tackle the rest of the %'s in the query, by - # converting them to LIKE clauses. - expr = re.compile("(%?):([a-zA-Z][a-zA-Z0-9_-]*)%") - sql = expr.sub(self._prepare_like, sql) - expr = re.compile("#:([a-zA-Z][a-zA-Z0-9_-]*)") - sql = expr.sub(self._prepare_integer, sql) - expr = re.compile(":([a-zA-Z][a-zA-Z0-9_-]*)") - sql = expr.sub("%(\\1)s", sql) - return sql - - def _prepare_like(self, match): - """This function changes LIKE statement replace behavior - - It works by turning %:name% to %(_name_around)s and :name% to - %(_name_append)s. Since a leading '_' is not a valid keyname - input (enforced via unit tests), it will never clash with - existing keys. Then, when building the statement, the query - runner will generate corrected strings.""" - if match.group(1) == '%': - # there is a leading % so this is treated as prefix/suffix - self._around.add(match.group(2)) - return "%(" + self._build_around_key(match.group(2)) + ")s" - else: - # there is no leading %, so this is suffix only - self._append.add(match.group(2)) - return "%(" + self._build_append_key(match.group(2)) + ")s" - - def _build_around_key(self, key): - return "_" + key + "_around" - - def _build_append_key(self, key): - return "_" + key + "_append" - - def _prepare_integer(self, match): - """This function adjusts the sql for #:name replacements - - It works by turning #:name to %(_name_as_integer)s. Since a - leading '_' is not a valid keyname input (enforced via unit - tests), it will never clash with existing keys. Then, when - building the statement, the query runner will generate - corrected strings.""" - self._integer.add(match.group(1)) - return "%(" + self._build_integer_key(match.group(1)) + ")s" - - def _build_integer_key(self, key): - return "_" + key + "_as_integer" - - def _strip_wildcards_to_list(self, value): - """Take string, and strip out the LIKE special characters. - - Technically, this is database dependant, but postgresql and - mysql use the same wildcards, and I am not aware of a general - way to handle this. I think you need a sql statement of the - form: - - LIKE_STRING( [ANY,ONE,str]... ) - - which would treat ANY as their any string, and ONE as their - single glyph, and str as something that needs database - specific encoding to not allow any % or _ to affect the query. - - As it stands, I believe it's impossible to write a named query - style interface which uses like to search the entire space of - text available. Imagine the query: - - % of brain used by average linden - - In order to search for %, it must be escaped, so once you have - escaped the string to not do wildcard searches, and be escaped - for the database, and then prepended the wildcard you come - back with one of: - - 1) %\% of brain used by average linden - 2) %%% of brain used by average linden - - Then, when passed to the database to be escaped to be database - safe, you get back: - - 1) %\\% of brain used by average linden - : which means search for any character sequence, followed by a - backslash, followed by any sequence, followed by ' of - brain...' - 2) %%% of brain used by average linden - : which (I believe) means search for a % followed by any - character sequence followed by 'of brain...' - - Neither of which is what we want! - - So, we need a vendor (or extention) for LIKE_STRING. Anyone - want to write it?""" - utf8_value = unicode(value, "utf-8") - esc_list = [] - remove_chars = set(u"%_") - for glyph in utf8_value: - if glyph in remove_chars: - continue - esc_list.append(glyph.encode("utf-8")) - return esc_list - - def delete(self): - """ Makes this query unusable by deleting all the members and - setting the deleted member. This is desired when the on-disk - query has been deleted but the in-memory copy remains.""" - # blow away all members except _name, _location, and deleted - name, location = self._name, self._location - for key in self.__dict__.keys(): - del self.__dict__[key] - self.deleted = True - self._name, self._location = name, location - - def ttl(self): - """ Estimated time to live of this query. Used for web - services to set the Expires header.""" - return self._ttl - - def legacy_dbname(self): - return self._legacy_dbname - - def return_as_map(self): - """ Returns true if this query is configured to return its - results as a single map (as opposed to a list of maps, the - normal behavior).""" - - return self._return_as_map - - def for_schema(self, db_name): - "Look trough the alternates and return the correct query" - try: - return self._alternative[db_name] - except KeyError, e: - pass - return self - - def run(self, connection, params, expect_rows = None, use_dictcursor = True): - """given a connection, run a named query with the params - - Note that this function will fetch ALL rows. We do this because it - opens and closes the cursor to generate the values, and this - isn't a generator so the cursor has no life beyond the method call. - - @param cursor The connection to use (this generates its own cursor for the query) - @param name The name of the query to run - @param params The parameters passed into the query - @param expect_rows The number of rows expected. Set to 1 if return_as_map is true. Raises ExpectationFailed if the number of returned rows doesn't exactly match. Kind of a hack. - @param use_dictcursor Set to false to use a normal cursor and manually convert the rows to dicts. - @return Returns the result set as a list of dicts, or, if the named query has return_as_map set to true, returns a single dict. - """ - if use_dictcursor: - cursor = connection.cursor(MySQLdb.cursors.DictCursor) - else: - cursor = connection.cursor() - - statement = self.sql(connection, params) - if DEBUG: - print "SQL:", statement - rows = cursor.execute(statement) - - # *NOTE: the expect_rows argument is a very cheesy way to get some - # validation on the result set. If you want to add more expectation - # logic, do something more object-oriented and flexible. Or use an ORM. - if(self._return_as_map): - expect_rows = 1 - if expect_rows is not None and rows != expect_rows: - cursor.close() - raise ExpectationFailed("Statement expected %s rows, got %s. Sql: %s" % ( - expect_rows, rows, statement)) - - # convert to dicts manually if we're not using a dictcursor - if use_dictcursor: - result_set = cursor.fetchall() - else: - if cursor.description is None: - # an insert or something - x = cursor.fetchall() - cursor.close() - return x - - names = [x[0] for x in cursor.description] - - result_set = [] - for row in cursor.fetchall(): - converted_row = {} - for idx, col_name in enumerate(names): - converted_row[col_name] = row[idx] - result_set.append(converted_row) - - cursor.close() - if self._return_as_map: - return result_set[0] - return result_set - - def sql(self, connection, params): - """ Generates an SQL statement from the named query document - and a dictionary of parameters. - - """ - self.refresh() - - # build the query from the options available and the params - base_query = [] - base_query.append(self._base_query) - for opt, extra_where in self._options.items(): - if type(extra_where) in (dict, list, tuple): - if opt in params: - base_query.append(extra_where[params[opt]]) - else: - if opt in params and params[opt]: - base_query.append(extra_where) - if self._query_suffix: - base_query.append(self._query_suffix) - full_query = '\n'.join(base_query) - - # Go through the query and rewrite all of the ones with the - # @:name syntax. - rewrite = _RewriteQueryForArray(params) - expr = re.compile("@%\(([a-zA-Z][a-zA-Z0-9_-]*)\)s") - full_query = expr.sub(rewrite.operate, full_query) - params.update(rewrite.new_params) - - # build out the params for like. We only have to do this - # parameters which were detected to have ued the where syntax - # during load. - # - # * treat the incoming string as utf-8 - # * strip wildcards - # * append or prepend % as appropriate - new_params = {} - for key in params: - if key in self._around: - new_value = ['%'] - new_value.extend(self._strip_wildcards_to_list(params[key])) - new_value.append('%') - new_params[self._build_around_key(key)] = ''.join(new_value) - if key in self._append: - new_value = self._strip_wildcards_to_list(params[key]) - new_value.append('%') - new_params[self._build_append_key(key)] = ''.join(new_value) - if key in self._integer: - new_params[self._build_integer_key(key)] = int(params[key]) - params.update(new_params) - - # do substitution using the mysql (non-standard) 'literal' - # function to do the escaping. - sql = full_query % connection.literal(params) - return sql - - def refresh(self): - """ Refresh self from the file on the filesystem. - - This is optimized to be callable as frequently as you wish, - without adding too much load. It does so by only stat-ing the - file every N seconds, where N defaults to 5 and is - configurable through the member _stat_interval_seconds. If the stat - reveals that the file has changed, refresh will re-parse the - contents of the file and use them to update the named query - instance. If the stat reveals that the file has been deleted, - refresh will call self.delete to make the in-memory - representation unusable.""" - now = time.time() - if(now - self._last_check_time > self._stat_interval_seconds): - self._last_check_time = now - try: - modtime = self.get_modtime() - if(modtime > self._last_mod_time): - self.load_contents() - except OSError, e: - if e.errno == errno.ENOENT: # file not found - self.delete() # clean up self - raise # pass the exception along to the caller so they know that this query disappeared - -class NamedQueryManager(object): - """ Manages the lifespan of NamedQuery objects, drawing from a - directory hierarchy of named query documents. - - In practice this amounts to a memory cache of NamedQuery objects.""" - - def __init__(self, named_queries_dir): - """ Initializes a manager to look for named queries in a - directory.""" - self._dir = os.path.abspath(os.path.realpath(named_queries_dir)) - self._cached_queries = {} - - def sql(self, connection, name, params): - nq = self.get(name) - return nq.sql(connection, params) - - def get(self, name): - """ Returns a NamedQuery instance based on the name, either - from memory cache, or by parsing from disk. - - The name is simply a relative path to the directory associated - with the manager object. Before returning the instance, the - NamedQuery object is cached in memory, so that subsequent - accesses don't have to read from disk or do any parsing. This - means that NamedQuery objects returned by this method are - shared across all users of the manager object. - NamedQuery.refresh is used to bring the NamedQuery objects in - sync with the actual files on disk.""" - nq = self._cached_queries.get(name) - if nq is None: - nq = NamedQuery(name, os.path.join(self._dir, name)) - self._cached_queries[name] = nq - else: - try: - nq.refresh() - except OSError, e: - if e.errno == errno.ENOENT: # file not found - del self._cached_queries[name] - raise # pass exception along to caller so they know that the query disappeared - - return nq - -class _RewriteQueryForArray(object): - "Helper class for rewriting queries with the @:name syntax" - def __init__(self, params): - self.params = params - self.new_params = dict() - - def operate(self, match): - "Given a match, return the string that should be in use" - key = match.group(1) - value = self.params[key] - if type(value) in (list,tuple): - rv = [] - for idx in range(len(value)): - # if the value@idx is array-like, we are - # probably dealing with a VALUES - new_key = "_%s_%s"%(key, str(idx)) - val_item = value[idx] - if type(val_item) in (list, tuple, dict): - if type(val_item) is dict: - # this is because in Python, the order of - # key, value retrieval from the dict is not - # guaranteed to match what the input intended - # and for VALUES, order is important. - # TODO: Implemented ordered dict in LLSD parser? - raise ExpectationFailed('Only lists/tuples allowed,\ - received dict') - values_keys = [] - for value_idx, item in enumerate(val_item): - # we want a key of the format : - # key_#replacement_#value_row_#value_col - # ugh... so if we are replacing 10 rows in user_note, - # the first values clause would read (for @:user_notes) :- - # ( :_user_notes_0_1_1, :_user_notes_0_1_2, :_user_notes_0_1_3 ) - # the input LLSD for VALUES will look like: - # ... - # - # user_notes - # - # - # ... - # ... - # ... - # - # ... - # - # - # ... - values_key = "%s_%s"%(new_key, value_idx) - self.new_params[values_key] = item - values_keys.append("%%(%s)s"%values_key) - # now collapse all these new place holders enclosed in () - # from [':_key_0_1_1', ':_key_0_1_2', ':_key_0_1_3,...] - # rv will have [ '(:_key_0_1_1, :_key_0_1_2, :_key_0_1_3)', ] - # which is flattened a few lines below join(rv) - rv.append('(%s)' % ','.join(values_keys)) - else: - self.new_params[new_key] = val_item - rv.append("%%(%s)s"%new_key) - return ','.join(rv) - else: - # not something that can be expanded, so just drop the - # leading @ in the front of the match. This will mean that - # the single value we have, be it a string, int, whatever - # (other than dict) will correctly show up, eg: - # - # where foo in (@:foobar) -- foobar is a string, so we get - # where foo in (:foobar) - return match.group(0)[1:] diff --git a/indra/lib/python/indra/util/shutil2.py b/indra/lib/python/indra/util/shutil2.py deleted file mode 100644 index 9e2e7a6ded..0000000000 --- a/indra/lib/python/indra/util/shutil2.py +++ /dev/null @@ -1,84 +0,0 @@ -''' -@file shutil2.py -@brief a better shutil.copytree replacement - -$LicenseInfo:firstyear=2007&license=mit$ - -Copyright (c) 2007-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -''' - -# -# shutil2.py -# Taken from http://www.scons.org/wiki/AccumulateBuilder -# the stock copytree sucks because it insists that the -# target dir not exist -# - -import os.path -import shutil - -def copytree(src, dest, symlinks=False): - """My own copyTree which does not fail if the directory exists. - - Recursively copy a directory tree using copy2(). - - If the optional symlinks flag is true, symbolic links in the - source tree result in symbolic links in the destination tree; if - it is false, the contents of the files pointed to by symbolic - links are copied. - - Behavior is meant to be identical to GNU 'cp -R'. - """ - def copyItems(src, dest, symlinks=False): - """Function that does all the work. - - It is necessary to handle the two 'cp' cases: - - destination does exist - - destination does not exist - - See 'cp -R' documentation for more details - """ - for item in os.listdir(src): - srcPath = os.path.join(src, item) - if os.path.isdir(srcPath): - srcBasename = os.path.basename(srcPath) - destDirPath = os.path.join(dest, srcBasename) - if not os.path.exists(destDirPath): - os.makedirs(destDirPath) - copyItems(srcPath, destDirPath) - elif os.path.islink(item) and symlinks: - linkto = os.readlink(item) - os.symlink(linkto, dest) - else: - shutil.copy2(srcPath, dest) - - # case 'cp -R src/ dest/' where dest/ already exists - if os.path.exists(dest): - destPath = os.path.join(dest, os.path.basename(src)) - if not os.path.exists(destPath): - os.makedirs(destPath) - # case 'cp -R src/ dest/' where dest/ does not exist - else: - os.makedirs(dest) - destPath = dest - # actually copy the files - copyItems(src, destPath) diff --git a/indra/lib/python/indra/util/simperf_host_xml_parser.py b/indra/lib/python/indra/util/simperf_host_xml_parser.py deleted file mode 100755 index 672c1050c2..0000000000 --- a/indra/lib/python/indra/util/simperf_host_xml_parser.py +++ /dev/null @@ -1,338 +0,0 @@ -#!/usr/bin/env python -"""\ -@file simperf_host_xml_parser.py -@brief Digest collector's XML dump and convert to simple dict/list structure - -$LicenseInfo:firstyear=2008&license=mit$ - -Copyright (c) 2008-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -""" - -import sys, os, getopt, time -import simplejson -from xml import sax - - -def usage(): - print "Usage:" - print sys.argv[0] + " [options]" - print " Convert RRD's XML dump to JSON. Script to convert the simperf_host_collector-" - print " generated RRD dump into JSON. Steps include converting selected named" - print " fields from GAUGE type to COUNTER type by computing delta with preceding" - print " values. Top-level named fields are:" - print - print " lastupdate Time (javascript timestamp) of last data sample" - print " step Time in seconds between samples" - print " ds Data specification (name/type) for each column" - print " database Table of data samples, one time step per row" - print - print "Options:" - print " -i, --in Input settings filename. (Default: stdin)" - print " -o, --out Output settings filename. (Default: stdout)" - print " -h, --help Print this message and exit." - print - print "Example: %s -i rrddump.xml -o rrddump.json" % sys.argv[0] - print - print "Interfaces:" - print " class SimPerfHostXMLParser() # SAX content handler" - print " def simperf_host_xml_fixup(parser) # post-parse value fixup" - -class SimPerfHostXMLParser(sax.handler.ContentHandler): - - def __init__(self): - pass - - def startDocument(self): - self.rrd_last_update = 0 # public - self.rrd_step = 0 # public - self.rrd_ds = [] # public - self.rrd_records = [] # public - self._rrd_level = 0 - self._rrd_parse_state = 0 - self._rrd_chars = "" - self._rrd_capture = False - self._rrd_ds_val = {} - self._rrd_data_row = [] - self._rrd_data_row_has_nan = False - - def endDocument(self): - pass - - # Nasty little ad-hoc state machine to extract the elements that are - # necessary from the 'rrdtool dump' XML output. The same element - # name '' is used for two different data sets so we need to pay - # some attention to the actual structure to get the ones we want - # and ignore the ones we don't. - - def startElement(self, name, attrs): - self._rrd_level = self._rrd_level + 1 - self._rrd_capture = False - if self._rrd_level == 1: - if name == "rrd" and self._rrd_parse_state == 0: - self._rrd_parse_state = 1 # In - self._rrd_capture = True - self._rrd_chars = "" - elif self._rrd_level == 2: - if self._rrd_parse_state == 1: - if name == "lastupdate": - self._rrd_parse_state = 2 # In - self._rrd_capture = True - self._rrd_chars = "" - elif name == "step": - self._rrd_parse_state = 3 # In - self._rrd_capture = True - self._rrd_chars = "" - elif name == "ds": - self._rrd_parse_state = 4 # In - self._rrd_ds_val = {} - self._rrd_chars = "" - elif name == "rra": - self._rrd_parse_state = 5 # In - elif self._rrd_level == 3: - if self._rrd_parse_state == 4: - if name == "name": - self._rrd_parse_state = 6 # In - self._rrd_capture = True - self._rrd_chars = "" - elif name == "type": - self._rrd_parse_state = 7 # In - self._rrd_capture = True - self._rrd_chars = "" - elif self._rrd_parse_state == 5: - if name == "database": - self._rrd_parse_state = 8 # In - elif self._rrd_level == 4: - if self._rrd_parse_state == 8: - if name == "row": - self._rrd_parse_state = 9 # In - self._rrd_data_row = [] - self._rrd_data_row_has_nan = False - elif self._rrd_level == 5: - if self._rrd_parse_state == 9: - if name == "v": - self._rrd_parse_state = 10 # In - self._rrd_capture = True - self._rrd_chars = "" - - def endElement(self, name): - self._rrd_capture = False - if self._rrd_parse_state == 10: - self._rrd_capture = self._rrd_level == 6 - if self._rrd_level == 5: - if self._rrd_chars == "NaN": - self._rrd_data_row_has_nan = True - else: - self._rrd_data_row.append(self._rrd_chars) - self._rrd_parse_state = 9 # In - elif self._rrd_parse_state == 9: - if self._rrd_level == 4: - if not self._rrd_data_row_has_nan: - self.rrd_records.append(self._rrd_data_row) - self._rrd_parse_state = 8 # In - elif self._rrd_parse_state == 8: - if self._rrd_level == 3: - self._rrd_parse_state = 5 # In - elif self._rrd_parse_state == 7: - if self._rrd_level == 3: - self._rrd_ds_val["type"] = self._rrd_chars - self._rrd_parse_state = 4 # In - elif self._rrd_parse_state == 6: - if self._rrd_level == 3: - self._rrd_ds_val["name"] = self._rrd_chars - self._rrd_parse_state = 4 # In - elif self._rrd_parse_state == 5: - if self._rrd_level == 2: - self._rrd_parse_state = 1 # In - elif self._rrd_parse_state == 4: - if self._rrd_level == 2: - self.rrd_ds.append(self._rrd_ds_val) - self._rrd_parse_state = 1 # In - elif self._rrd_parse_state == 3: - if self._rrd_level == 2: - self.rrd_step = long(self._rrd_chars) - self._rrd_parse_state = 1 # In - elif self._rrd_parse_state == 2: - if self._rrd_level == 2: - self.rrd_last_update = long(self._rrd_chars) - self._rrd_parse_state = 1 # In - elif self._rrd_parse_state == 1: - if self._rrd_level == 1: - self._rrd_parse_state = 0 # At top - - if self._rrd_level: - self._rrd_level = self._rrd_level - 1 - - def characters(self, content): - if self._rrd_capture: - self._rrd_chars = self._rrd_chars + content.strip() - -def _make_numeric(value): - try: - value = float(value) - except: - value = "" - return value - -def simperf_host_xml_fixup(parser, filter_start_time = None, filter_end_time = None): - # Fixup for GAUGE fields that are really COUNTS. They - # were forced to GAUGE to try to disable rrdtool's - # data interpolation/extrapolation for non-uniform time - # samples. - fixup_tags = [ "cpu_user", - "cpu_nice", - "cpu_sys", - "cpu_idle", - "cpu_waitio", - "cpu_intr", - # "file_active", - # "file_free", - # "inode_active", - # "inode_free", - "netif_in_kb", - "netif_in_pkts", - "netif_in_errs", - "netif_in_drop", - "netif_out_kb", - "netif_out_pkts", - "netif_out_errs", - "netif_out_drop", - "vm_page_in", - "vm_page_out", - "vm_swap_in", - "vm_swap_out", - #"vm_mem_total", - #"vm_mem_used", - #"vm_mem_active", - #"vm_mem_inactive", - #"vm_mem_free", - #"vm_mem_buffer", - #"vm_swap_cache", - #"vm_swap_total", - #"vm_swap_used", - #"vm_swap_free", - "cpu_interrupts", - "cpu_switches", - "cpu_forks" ] - - col_count = len(parser.rrd_ds) - row_count = len(parser.rrd_records) - - # Process the last row separately, just to make all values numeric. - for j in range(col_count): - parser.rrd_records[row_count - 1][j] = _make_numeric(parser.rrd_records[row_count - 1][j]) - - # Process all other row/columns. - last_different_row = row_count - 1 - current_row = row_count - 2 - while current_row >= 0: - # Check for a different value than the previous row. If everything is the same - # then this is probably just a filler/bogus entry. - is_different = False - for j in range(col_count): - parser.rrd_records[current_row][j] = _make_numeric(parser.rrd_records[current_row][j]) - if parser.rrd_records[current_row][j] != parser.rrd_records[last_different_row][j]: - # We're good. This is a different row. - is_different = True - - if not is_different: - # This is a filler/bogus entry. Just ignore it. - for j in range(col_count): - parser.rrd_records[current_row][j] = float('nan') - else: - # Some tags need to be converted into deltas. - for j in range(col_count): - if parser.rrd_ds[j]["name"] in fixup_tags: - parser.rrd_records[last_different_row][j] = \ - parser.rrd_records[last_different_row][j] - parser.rrd_records[current_row][j] - last_different_row = current_row - - current_row -= 1 - - # Set fixup_tags in the first row to 'nan' since they aren't useful anymore. - for j in range(col_count): - if parser.rrd_ds[j]["name"] in fixup_tags: - parser.rrd_records[0][j] = float('nan') - - # Add a timestamp to each row and to the catalog. Format and name - # chosen to match other simulator logging (hopefully). - start_time = parser.rrd_last_update - (parser.rrd_step * (row_count - 1)) - # Build a filtered list of rrd_records if we are limited to a time range. - filter_records = False - if filter_start_time is not None or filter_end_time is not None: - filter_records = True - filtered_rrd_records = [] - if filter_start_time is None: - filter_start_time = start_time * 1000 - if filter_end_time is None: - filter_end_time = parser.rrd_last_update * 1000 - - for i in range(row_count): - record_timestamp = (start_time + (i * parser.rrd_step)) * 1000 - parser.rrd_records[i].insert(0, record_timestamp) - if filter_records: - if filter_start_time <= record_timestamp and record_timestamp <= filter_end_time: - filtered_rrd_records.append(parser.rrd_records[i]) - - if filter_records: - parser.rrd_records = filtered_rrd_records - - parser.rrd_ds.insert(0, {"type": "GAUGE", "name": "javascript_timestamp"}) - - -def main(argv=None): - opts, args = getopt.getopt(sys.argv[1:], "i:o:h", ["in=", "out=", "help"]) - input_file = sys.stdin - output_file = sys.stdout - for o, a in opts: - if o in ("-i", "--in"): - input_file = open(a, 'r') - if o in ("-o", "--out"): - output_file = open(a, 'w') - if o in ("-h", "--help"): - usage() - sys.exit(0) - - # Using the SAX parser as it is at least 4X faster and far, far - # smaller on this dataset than the DOM-based interface in xml.dom.minidom. - # With SAX and a 5.4MB xml file, this requires about seven seconds of - # wall-clock time and 32MB VSZ. With the DOM interface, about 22 seconds - # and over 270MB VSZ. - - handler = SimPerfHostXMLParser() - sax.parse(input_file, handler) - if input_file != sys.stdin: - input_file.close() - - # Various format fixups: string-to-num, gauge-to-counts, add - # a time stamp, etc. - simperf_host_xml_fixup(handler) - - # Create JSONable dict with interesting data and format/print it - print >>output_file, simplejson.dumps({ "step" : handler.rrd_step, - "lastupdate": handler.rrd_last_update * 1000, - "ds" : handler.rrd_ds, - "database" : handler.rrd_records }) - - return 0 - -if __name__ == "__main__": - sys.exit(main()) diff --git a/indra/lib/python/indra/util/simperf_oprof_interface.py b/indra/lib/python/indra/util/simperf_oprof_interface.py deleted file mode 100755 index c8d0f7475a..0000000000 --- a/indra/lib/python/indra/util/simperf_oprof_interface.py +++ /dev/null @@ -1,160 +0,0 @@ -#!/usr/bin/env python -"""\ -@file simperf_oprof_interface.py -@brief Manage OProfile data collection on a host - -$LicenseInfo:firstyear=2008&license=internal$ - -Copyright (c) 2008-2009, Linden Research, Inc. - -The following source code is PROPRIETARY AND CONFIDENTIAL. Use of -this source code is governed by the Linden Lab Source Code Disclosure -Agreement ("Agreement") previously entered between you and Linden -Lab. By accessing, using, copying, modifying or distributing this -software, you acknowledge that you have been informed of your -obligations under the Agreement and agree to abide by those obligations. - -ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO -WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, -COMPLETENESS OR PERFORMANCE. -$/LicenseInfo$ -""" - -import sys, os, getopt -import simplejson - - -def usage(): - print "Usage:" - print sys.argv[0] + " [options]" - print " Digest the OProfile report forms that come out of the" - print " simperf_oprof_ctl program's -r/--report command. The result" - print " is an array of dictionaires with the following keys:" - print - print " symbol Name of sampled, calling, or called procedure" - print " file Executable or library where symbol resides" - print " percentage Percentage contribution to profile, calls or called" - print " samples Sample count" - print " calls Methods called by the method in question (full only)" - print " called_by Methods calling the method (full only)" - print - print " For 'full' reports the two keys 'calls' and 'called_by' are" - print " themselves arrays of dictionaries based on the first four keys." - print - print "Return Codes:" - print " None. Aggressively digests everything. Will likely mung results" - print " if a program or library has whitespace in its name." - print - print "Options:" - print " -i, --in Input settings filename. (Default: stdin)" - print " -o, --out Output settings filename. (Default: stdout)" - print " -h, --help Print this message and exit." - print - print "Interfaces:" - print " class SimPerfOProfileInterface()" - -class SimPerfOProfileInterface: - def __init__(self): - self.isBrief = True # public - self.isValid = False # public - self.result = [] # public - - def parse(self, input): - in_samples = False - for line in input: - if in_samples: - if line[0:6] == "------": - self.isBrief = False - self._parseFull(input) - else: - self._parseBrief(input, line) - self.isValid = True - return - try: - hd1, remain = line.split(None, 1) - if hd1 == "samples": - in_samples = True - except ValueError: - pass - - def _parseBrief(self, input, line1): - try: - fld1, fld2, fld3, fld4 = line1.split(None, 3) - self.result.append({"samples" : fld1, - "percentage" : fld2, - "file" : fld3, - "symbol" : fld4.strip("\n")}) - except ValueError: - pass - for line in input: - try: - fld1, fld2, fld3, fld4 = line.split(None, 3) - self.result.append({"samples" : fld1, - "percentage" : fld2, - "file" : fld3, - "symbol" : fld4.strip("\n")}) - except ValueError: - pass - - def _parseFull(self, input): - state = 0 # In 'called_by' section - calls = [] - called_by = [] - current = {} - for line in input: - if line[0:6] == "------": - if len(current): - current["calls"] = calls - current["called_by"] = called_by - self.result.append(current) - state = 0 - calls = [] - called_by = [] - current = {} - else: - try: - fld1, fld2, fld3, fld4 = line.split(None, 3) - tmp = {"samples" : fld1, - "percentage" : fld2, - "file" : fld3, - "symbol" : fld4.strip("\n")} - except ValueError: - continue - if line[0] != " ": - current = tmp - state = 1 # In 'calls' section - elif state == 0: - called_by.append(tmp) - else: - calls.append(tmp) - if len(current): - current["calls"] = calls - current["called_by"] = called_by - self.result.append(current) - - -def main(argv=None): - opts, args = getopt.getopt(sys.argv[1:], "i:o:h", ["in=", "out=", "help"]) - input_file = sys.stdin - output_file = sys.stdout - for o, a in opts: - if o in ("-i", "--in"): - input_file = open(a, 'r') - if o in ("-o", "--out"): - output_file = open(a, 'w') - if o in ("-h", "--help"): - usage() - sys.exit(0) - - oprof = SimPerfOProfileInterface() - oprof.parse(input_file) - if input_file != sys.stdin: - input_file.close() - - # Create JSONable dict with interesting data and format/print it - print >>output_file, simplejson.dumps(oprof.result) - - return 0 - -if __name__ == "__main__": - sys.exit(main()) diff --git a/indra/lib/python/indra/util/simperf_proc_interface.py b/indra/lib/python/indra/util/simperf_proc_interface.py deleted file mode 100755 index 62a63fa872..0000000000 --- a/indra/lib/python/indra/util/simperf_proc_interface.py +++ /dev/null @@ -1,164 +0,0 @@ -#!/usr/bin/python - -# ---------------------------------------------------- -# Utility to extract log messages from *..llsd -# files that contain performance statistics. - -# ---------------------------------------------------- -import sys, os - -if os.path.exists("setup-path.py"): - execfile("setup-path.py") - -from indra.base import llsd - -DEFAULT_PATH="/dev/shm/simperf/" - - -# ---------------------------------------------------- -# Pull out the stats and return a single document -def parse_logfile(filename, target_column=None, verbose=False): - full_doc = [] - # Open source temp log file. Let exceptions percolate up. - sourcefile = open( filename,'r') - - if verbose: - print "Reading " + filename - - # Parse and output all lines from the temp file - for line in sourcefile.xreadlines(): - partial_doc = llsd.parse(line) - if partial_doc is not None: - if target_column is None: - full_doc.append(partial_doc) - else: - trim_doc = { target_column: partial_doc[target_column] } - if target_column != "fps": - trim_doc[ 'fps' ] = partial_doc[ 'fps' ] - trim_doc[ '/total_time' ] = partial_doc[ '/total_time' ] - trim_doc[ 'utc_time' ] = partial_doc[ 'utc_time' ] - full_doc.append(trim_doc) - - sourcefile.close() - return full_doc - -# Extract just the meta info line, and the timestamp of the first/last frame entry. -def parse_logfile_info(filename, verbose=False): - # Open source temp log file. Let exceptions percolate up. - sourcefile = open(filename, 'rU') # U is to open with Universal newline support - - if verbose: - print "Reading " + filename - - # The first line is the meta info line. - info_line = sourcefile.readline() - if not info_line: - sourcefile.close() - return None - - # The rest of the lines are frames. Read the first and last to get the time range. - info = llsd.parse( info_line ) - info['start_time'] = None - info['end_time'] = None - first_frame = sourcefile.readline() - if first_frame: - try: - info['start_time'] = int(llsd.parse(first_frame)['timestamp']) - except: - pass - - # Read the file backwards to find the last two lines. - sourcefile.seek(0, 2) - file_size = sourcefile.tell() - offset = 1024 - num_attempts = 0 - end_time = None - if file_size < offset: - offset = file_size - while 1: - sourcefile.seek(-1*offset, 2) - read_str = sourcefile.read(offset) - # Remove newline at the end - if read_str[offset - 1] == '\n': - read_str = read_str[0:-1] - lines = read_str.split('\n') - full_line = None - if len(lines) > 2: # Got two line - try: - end_time = llsd.parse(lines[-1])['timestamp'] - except: - # We couldn't parse this line. Try once more. - try: - end_time = llsd.parse(lines[-2])['timestamp'] - except: - # Nope. Just move on. - pass - break - if len(read_str) == file_size: # Reached the beginning - break - offset += 1024 - - info['end_time'] = int(end_time) - - sourcefile.close() - return info - - -def parse_proc_filename(filename): - try: - name_as_list = filename.split(".") - cur_stat_type = name_as_list[0].split("_")[0] - cur_pid = name_as_list[1] - except IndexError, ValueError: - return (None, None) - return (cur_pid, cur_stat_type) - -# ---------------------------------------------------- -def get_simstats_list(path=None): - """ Return stats (pid, type) listed in _proc..llsd """ - if path is None: - path = DEFAULT_PATH - simstats_list = [] - for file_name in os.listdir(path): - if file_name.endswith(".llsd") and file_name != "simperf_proc_config.llsd": - simstats_info = parse_logfile_info(path + file_name) - if simstats_info is not None: - simstats_list.append(simstats_info) - return simstats_list - -def get_log_info_list(pid=None, stat_type=None, path=None, target_column=None, verbose=False): - """ Return data from all llsd files matching the pid and stat type """ - if path is None: - path = DEFAULT_PATH - log_info_list = {} - for file_name in os.listdir ( path ): - if file_name.endswith(".llsd") and file_name != "simperf_proc_config.llsd": - (cur_pid, cur_stat_type) = parse_proc_filename(file_name) - if cur_pid is None: - continue - if pid is not None and pid != cur_pid: - continue - if stat_type is not None and stat_type != cur_stat_type: - continue - log_info_list[cur_pid] = parse_logfile(path + file_name, target_column, verbose) - return log_info_list - -def delete_simstats_files(pid=None, stat_type=None, path=None): - """ Delete *..llsd files """ - if path is None: - path = DEFAULT_PATH - del_list = [] - for file_name in os.listdir(path): - if file_name.endswith(".llsd") and file_name != "simperf_proc_config.llsd": - (cur_pid, cur_stat_type) = parse_proc_filename(file_name) - if cur_pid is None: - continue - if pid is not None and pid != cur_pid: - continue - if stat_type is not None and stat_type != cur_stat_type: - continue - del_list.append(cur_pid) - # Allow delete related exceptions to percolate up if this fails. - os.unlink(os.path.join(DEFAULT_PATH, file_name)) - return del_list - diff --git a/indra/lib/python/indra/util/term.py b/indra/lib/python/indra/util/term.py deleted file mode 100644 index 8c316a1f12..0000000000 --- a/indra/lib/python/indra/util/term.py +++ /dev/null @@ -1,222 +0,0 @@ -''' -@file term.py -@brief a better shutil.copytree replacement - -$LicenseInfo:firstyear=2007&license=mit$ - -Copyright (c) 2007-2009, Linden Research, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -$/LicenseInfo$ -''' - -#http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/475116 - -import sys, re - -class TerminalController: - """ - A class that can be used to portably generate formatted output to - a terminal. - - `TerminalController` defines a set of instance variables whose - values are initialized to the control sequence necessary to - perform a given action. These can be simply included in normal - output to the terminal: - - >>> term = TerminalController() - >>> print 'This is '+term.GREEN+'green'+term.NORMAL - - Alternatively, the `render()` method can used, which replaces - '${action}' with the string required to perform 'action': - - >>> term = TerminalController() - >>> print term.render('This is ${GREEN}green${NORMAL}') - - If the terminal doesn't support a given action, then the value of - the corresponding instance variable will be set to ''. As a - result, the above code will still work on terminals that do not - support color, except that their output will not be colored. - Also, this means that you can test whether the terminal supports a - given action by simply testing the truth value of the - corresponding instance variable: - - >>> term = TerminalController() - >>> if term.CLEAR_SCREEN: - ... print 'This terminal supports clearning the screen.' - - Finally, if the width and height of the terminal are known, then - they will be stored in the `COLS` and `LINES` attributes. - """ - # Cursor movement: - BOL = '' #: Move the cursor to the beginning of the line - UP = '' #: Move the cursor up one line - DOWN = '' #: Move the cursor down one line - LEFT = '' #: Move the cursor left one char - RIGHT = '' #: Move the cursor right one char - - # Deletion: - CLEAR_SCREEN = '' #: Clear the screen and move to home position - CLEAR_EOL = '' #: Clear to the end of the line. - CLEAR_BOL = '' #: Clear to the beginning of the line. - CLEAR_EOS = '' #: Clear to the end of the screen - - # Output modes: - BOLD = '' #: Turn on bold mode - BLINK = '' #: Turn on blink mode - DIM = '' #: Turn on half-bright mode - REVERSE = '' #: Turn on reverse-video mode - NORMAL = '' #: Turn off all modes - - # Cursor display: - HIDE_CURSOR = '' #: Make the cursor invisible - SHOW_CURSOR = '' #: Make the cursor visible - - # Terminal size: - COLS = None #: Width of the terminal (None for unknown) - LINES = None #: Height of the terminal (None for unknown) - - # Foreground colors: - BLACK = BLUE = GREEN = CYAN = RED = MAGENTA = YELLOW = WHITE = '' - - # Background colors: - BG_BLACK = BG_BLUE = BG_GREEN = BG_CYAN = '' - BG_RED = BG_MAGENTA = BG_YELLOW = BG_WHITE = '' - - _STRING_CAPABILITIES = """ - BOL=cr UP=cuu1 DOWN=cud1 LEFT=cub1 RIGHT=cuf1 - CLEAR_SCREEN=clear CLEAR_EOL=el CLEAR_BOL=el1 CLEAR_EOS=ed BOLD=bold - BLINK=blink DIM=dim REVERSE=rev UNDERLINE=smul NORMAL=sgr0 - HIDE_CURSOR=cinvis SHOW_CURSOR=cnorm""".split() - _COLORS = """BLACK BLUE GREEN CYAN RED MAGENTA YELLOW WHITE""".split() - _ANSICOLORS = "BLACK RED GREEN YELLOW BLUE MAGENTA CYAN WHITE".split() - - def __init__(self, term_stream=sys.stdout): - """ - Create a `TerminalController` and initialize its attributes - with appropriate values for the current terminal. - `term_stream` is the stream that will be used for terminal - output; if this stream is not a tty, then the terminal is - assumed to be a dumb terminal (i.e., have no capabilities). - """ - # Curses isn't available on all platforms - try: import curses - except: return - - # If the stream isn't a tty, then assume it has no capabilities. - if not term_stream.isatty(): return - - # Check the terminal type. If we fail, then assume that the - # terminal has no capabilities. - try: curses.setupterm() - except: return - - # Look up numeric capabilities. - self.COLS = curses.tigetnum('cols') - self.LINES = curses.tigetnum('lines') - - # Look up string capabilities. - for capability in self._STRING_CAPABILITIES: - (attrib, cap_name) = capability.split('=') - setattr(self, attrib, self._tigetstr(cap_name) or '') - - # Colors - set_fg = self._tigetstr('setf') - if set_fg: - for i,color in zip(range(len(self._COLORS)), self._COLORS): - setattr(self, color, curses.tparm(set_fg, i) or '') - set_fg_ansi = self._tigetstr('setaf') - if set_fg_ansi: - for i,color in zip(range(len(self._ANSICOLORS)), self._ANSICOLORS): - setattr(self, color, curses.tparm(set_fg_ansi, i) or '') - set_bg = self._tigetstr('setb') - if set_bg: - for i,color in zip(range(len(self._COLORS)), self._COLORS): - setattr(self, 'BG_'+color, curses.tparm(set_bg, i) or '') - set_bg_ansi = self._tigetstr('setab') - if set_bg_ansi: - for i,color in zip(range(len(self._ANSICOLORS)), self._ANSICOLORS): - setattr(self, 'BG_'+color, curses.tparm(set_bg_ansi, i) or '') - - def _tigetstr(self, cap_name): - # String capabilities can include "delays" of the form "$<2>". - # For any modern terminal, we should be able to just ignore - # these, so strip them out. - import curses - cap = curses.tigetstr(cap_name) or '' - return re.sub(r'\$<\d+>[/*]?', '', cap) - - def render(self, template): - """ - Replace each $-substitutions in the given template string with - the corresponding terminal control string (if it's defined) or - '' (if it's not). - """ - return re.sub(r'\$\$|\${\w+}', self._render_sub, template) - - def _render_sub(self, match): - s = match.group() - if s == '$$': return s - else: return getattr(self, s[2:-1]) - -####################################################################### -# Example use case: progress bar -####################################################################### - -class ProgressBar: - """ - A 3-line progress bar, which looks like:: - - Header - 20% [===========----------------------------------] - progress message - - The progress bar is colored, if the terminal supports color - output; and adjusts to the width of the terminal. - """ - BAR = '%3d%% ${GREEN}[${BOLD}%s%s${NORMAL}${GREEN}]${NORMAL}\n' - HEADER = '${BOLD}${CYAN}%s${NORMAL}\n\n' - - def __init__(self, term, header): - self.term = term - if not (self.term.CLEAR_EOL and self.term.UP and self.term.BOL): - raise ValueError("Terminal isn't capable enough -- you " - "should use a simpler progress dispaly.") - self.width = self.term.COLS or 75 - self.bar = term.render(self.BAR) - self.header = self.term.render(self.HEADER % header.center(self.width)) - self.cleared = 1 #: true if we haven't drawn the bar yet. - self.update(0, '') - - def update(self, percent, message): - if self.cleared: - sys.stdout.write(self.header) - self.cleared = 0 - n = int((self.width-10)*percent) - sys.stdout.write( - self.term.BOL + self.term.UP + self.term.CLEAR_EOL + - (self.bar % (100*percent, '='*n, '-'*(self.width-10-n))) + - self.term.CLEAR_EOL + message.center(self.width)) - - def clear(self): - if not self.cleared: - sys.stdout.write(self.term.BOL + self.term.CLEAR_EOL + - self.term.UP + self.term.CLEAR_EOL + - self.term.UP + self.term.CLEAR_EOL) - self.cleared = 1 diff --git a/indra/lib/python/indra/util/test_win32_manifest.py b/indra/lib/python/indra/util/test_win32_manifest.py new file mode 100644 index 0000000000..9863b97778 --- /dev/null +++ b/indra/lib/python/indra/util/test_win32_manifest.py @@ -0,0 +1,146 @@ +#!/usr/bin/env python2 +"""\ +@file test_win32_manifest.py +@brief Test an assembly binding version and uniqueness in a windows dll or exe. + +$LicenseInfo:firstyear=2009&license=viewerlgpl$ +Second Life Viewer Source Code +Copyright (C) 2009-2011, Linden Research, Inc. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; +version 2.1 of the License only. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +$/LicenseInfo$ +""" +import sys, os +import tempfile +from xml.dom.minidom import parse + +class AssemblyTestException(Exception): + pass + +class NoManifestException(AssemblyTestException): + pass + +class MultipleBindingsException(AssemblyTestException): + pass + +class UnexpectedVersionException(AssemblyTestException): + pass + +class NoMatchingAssemblyException(AssemblyTestException): + pass + +def get_HKLM_registry_value(key_str, value_str): + import _winreg + reg = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE) + key = _winreg.OpenKey(reg, key_str) + value = _winreg.QueryValueEx(key, value_str)[0] + #print 'Found: %s' % value + return value + +def find_vc_dir(): + supported_versions = (r'8.0', r'9.0') + supported_products = (r'VisualStudio', r'VCExpress') + value_str = (r'ProductDir') + + for product in supported_products: + for version in supported_versions: + key_str = (r'SOFTWARE\Microsoft\%s\%s\Setup\VC' % + (product, version)) + try: + return get_HKLM_registry_value(key_str, value_str) + except WindowsError, err: + x64_key_str = (r'SOFTWARE\Wow6432Node\Microsoft\VisualStudio\%s\Setup\VS' % + version) + try: + return get_HKLM_registry_value(x64_key_str, value_str) + except: + print >> sys.stderr, "Didn't find MS %s version %s " % (product,version) + + raise + +def find_mt_path(): + vc_dir = find_vc_dir() + mt_path = '\"%sbin\\mt.exe\"' % vc_dir + return mt_path + +def test_assembly_binding(src_filename, assembly_name, assembly_ver): + print "checking %s dependency %s..." % (src_filename, assembly_name) + + (tmp_file_fd, tmp_file_name) = tempfile.mkstemp(suffix='.xml') + tmp_file = os.fdopen(tmp_file_fd) + tmp_file.close() + + mt_path = find_mt_path() + resource_id = "" + if os.path.splitext(src_filename)[1].lower() == ".dll": + resource_id = ";#2" + system_call = '%s -nologo -inputresource:%s%s -out:%s > NUL' % (mt_path, src_filename, resource_id, tmp_file_name) + print "Executing: %s" % system_call + mt_result = os.system(system_call) + if mt_result == 31: + print "No manifest found in %s" % src_filename + raise NoManifestException() + + manifest_dom = parse(tmp_file_name) + nodes = manifest_dom.getElementsByTagName('assemblyIdentity') + + versions = list() + for node in nodes: + if node.getAttribute('name') == assembly_name: + versions.append(node.getAttribute('version')) + + if len(versions) == 0: + print "No matching assemblies found in %s" % src_filename + raise NoMatchingAssemblyException() + + elif len(versions) > 1: + print "Multiple bindings to %s found:" % assembly_name + print versions + print + raise MultipleBindingsException(versions) + + elif versions[0] != assembly_ver: + print "Unexpected version found for %s:" % assembly_name + print "Wanted %s, found %s" % (assembly_ver, versions[0]) + print + raise UnexpectedVersionException(assembly_ver, versions[0]) + + os.remove(tmp_file_name) + + print "SUCCESS: %s OK!" % src_filename + print + +if __name__ == '__main__': + + print + print "Running test_win32_manifest.py..." + + usage = 'test_win32_manfest ' + + try: + src_filename = sys.argv[1] + assembly_name = sys.argv[2] + assembly_ver = sys.argv[3] + except: + print "Usage:" + print usage + print + raise + + test_assembly_binding(src_filename, assembly_name, assembly_ver) + + diff --git a/indra/lib/python/uuid.py b/indra/lib/python/uuid.py deleted file mode 100644 index 1c86c761b5..0000000000 --- a/indra/lib/python/uuid.py +++ /dev/null @@ -1,487 +0,0 @@ -r"""UUID objects (universally unique identifiers) according to RFC 4122. - -This module provides immutable UUID objects (class UUID) and the functions -uuid1(), uuid3(), uuid4(), uuid5() for generating version 1, 3, 4, and 5 -UUIDs as specified in RFC 4122. - -If all you want is a unique ID, you should probably call uuid1() or uuid4(). -Note that uuid1() may compromise privacy since it creates a UUID containing -the computer's network address. uuid4() creates a random UUID. - -Typical usage: - - >>> import uuid - - # make a UUID based on the host ID and current time - >>> uuid.uuid1() - UUID('a8098c1a-f86e-11da-bd1a-00112444be1e') - - # make a UUID using an MD5 hash of a namespace UUID and a name - >>> uuid.uuid3(uuid.NAMESPACE_DNS, 'python.org') - UUID('6fa459ea-ee8a-3ca4-894e-db77e160355e') - - # make a random UUID - >>> uuid.uuid4() - UUID('16fd2706-8baf-433b-82eb-8c7fada847da') - - # make a UUID using a SHA-1 hash of a namespace UUID and a name - >>> uuid.uuid5(uuid.NAMESPACE_DNS, 'python.org') - UUID('886313e1-3b8a-5372-9b90-0c9aee199e5d') - - # make a UUID from a string of hex digits (braces and hyphens ignored) - >>> x = uuid.UUID('{00010203-0405-0607-0809-0a0b0c0d0e0f}') - - # convert a UUID to a string of hex digits in standard form - >>> str(x) - '00010203-0405-0607-0809-0a0b0c0d0e0f' - - # get the raw 16 bytes of the UUID - >>> x.bytes - '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f' - - # make a UUID from a 16-byte string - >>> uuid.UUID(bytes=x.bytes) - UUID('00010203-0405-0607-0809-0a0b0c0d0e0f') - -This module works with Python 2.3 or higher.""" - -# *HACK: Necessary for python 2.4. Consider replacing this code wart -# after python >=2.5 has deployed everywhere. 2009-10-05 -try: - from hashlib import md5 -except ImportError: - from md5 import md5 - -__author__ = 'Ka-Ping Yee ' -__date__ = '$Date: 2006/06/12 23:15:40 $'.split()[1].replace('/', '-') -__version__ = '$Revision: 1.30 $'.split()[1] - -RESERVED_NCS, RFC_4122, RESERVED_MICROSOFT, RESERVED_FUTURE = [ - 'reserved for NCS compatibility', 'specified in RFC 4122', - 'reserved for Microsoft compatibility', 'reserved for future definition'] - -class UUID(object): - """Instances of the UUID class represent UUIDs as specified in RFC 4122. - UUID objects are immutable, hashable, and usable as dictionary keys. - Converting a UUID to a string with str() yields something in the form - '12345678-1234-1234-1234-123456789abc'. The UUID constructor accepts - four possible forms: a similar string of hexadecimal digits, or a - string of 16 raw bytes as an argument named 'bytes', or a tuple of - six integer fields (with 32-bit, 16-bit, 16-bit, 8-bit, 8-bit, and - 48-bit values respectively) as an argument named 'fields', or a single - 128-bit integer as an argument named 'int'. - - UUIDs have these read-only attributes: - - bytes the UUID as a 16-byte string - - fields a tuple of the six integer fields of the UUID, - which are also available as six individual attributes - and two derived attributes: - - time_low the first 32 bits of the UUID - time_mid the next 16 bits of the UUID - time_hi_version the next 16 bits of the UUID - clock_seq_hi_variant the next 8 bits of the UUID - clock_seq_low the next 8 bits of the UUID - node the last 48 bits of the UUID - - time the 60-bit timestamp - clock_seq the 14-bit sequence number - - hex the UUID as a 32-character hexadecimal string - - int the UUID as a 128-bit integer - - urn the UUID as a URN as specified in RFC 4122 - - variant the UUID variant (one of the constants RESERVED_NCS, - RFC_4122, RESERVED_MICROSOFT, or RESERVED_FUTURE) - - version the UUID version number (1 through 5, meaningful only - when the variant is RFC_4122) - """ - - def __init__(self, hex=None, bytes=None, fields=None, int=None, - version=None): - r"""Create a UUID from either a string of 32 hexadecimal digits, - a string of 16 bytes as the 'bytes' argument, a tuple of six - integers (32-bit time_low, 16-bit time_mid, 16-bit time_hi_version, - 8-bit clock_seq_hi_variant, 8-bit clock_seq_low, 48-bit node) as - the 'fields' argument, or a single 128-bit integer as the 'int' - argument. When a string of hex digits is given, curly braces, - hyphens, and a URN prefix are all optional. For example, these - expressions all yield the same UUID: - - UUID('{12345678-1234-5678-1234-567812345678}') - UUID('12345678123456781234567812345678') - UUID('urn:uuid:12345678-1234-5678-1234-567812345678') - UUID(bytes='\x12\x34\x56\x78'*4) - UUID(fields=(0x12345678, 0x1234, 0x5678, 0x12, 0x34, 0x567812345678)) - UUID(int=0x12345678123456781234567812345678) - - Exactly one of 'hex', 'bytes', 'fields', or 'int' must be given. - The 'version' argument is optional; if given, the resulting UUID - will have its variant and version number set according to RFC 4122, - overriding bits in the given 'hex', 'bytes', 'fields', or 'int'. - """ - - if [hex, bytes, fields, int].count(None) != 3: - raise TypeError('need just one of hex, bytes, fields, or int') - if hex is not None: - hex = hex.replace('urn:', '').replace('uuid:', '') - hex = hex.strip('{}').replace('-', '') - if len(hex) != 32: - raise ValueError('badly formed hexadecimal UUID string') - int = long(hex, 16) - if bytes is not None: - if len(bytes) != 16: - raise ValueError('bytes is not a 16-char string') - int = long(('%02x'*16) % tuple(map(ord, bytes)), 16) - if fields is not None: - if len(fields) != 6: - raise ValueError('fields is not a 6-tuple') - (time_low, time_mid, time_hi_version, - clock_seq_hi_variant, clock_seq_low, node) = fields - if not 0 <= time_low < 1<<32L: - raise ValueError('field 1 out of range (need a 32-bit value)') - if not 0 <= time_mid < 1<<16L: - raise ValueError('field 2 out of range (need a 16-bit value)') - if not 0 <= time_hi_version < 1<<16L: - raise ValueError('field 3 out of range (need a 16-bit value)') - if not 0 <= clock_seq_hi_variant < 1<<8L: - raise ValueError('field 4 out of range (need an 8-bit value)') - if not 0 <= clock_seq_low < 1<<8L: - raise ValueError('field 5 out of range (need an 8-bit value)') - if not 0 <= node < 1<<48L: - raise ValueError('field 6 out of range (need a 48-bit value)') - clock_seq = (clock_seq_hi_variant << 8L) | clock_seq_low - int = ((time_low << 96L) | (time_mid << 80L) | - (time_hi_version << 64L) | (clock_seq << 48L) | node) - if int is not None: - if not 0 <= int < 1<<128L: - raise ValueError('int is out of range (need a 128-bit value)') - if version is not None: - if not 1 <= version <= 5: - raise ValueError('illegal version number') - # Set the variant to RFC 4122. - int &= ~(0xc000 << 48L) - int |= 0x8000 << 48L - # Set the version number. - int &= ~(0xf000 << 64L) - int |= version << 76L - self.__dict__['int'] = int - - def __cmp__(self, other): - if isinstance(other, UUID): - return cmp(self.int, other.int) - return NotImplemented - - def __hash__(self): - return hash(self.int) - - def __int__(self): - return self.int - - def __repr__(self): - return 'UUID(%r)' % str(self) - - def __setattr__(self, name, value): - raise TypeError('UUID objects are immutable') - - def __str__(self): - hex = '%032x' % self.int - return '%s-%s-%s-%s-%s' % ( - hex[:8], hex[8:12], hex[12:16], hex[16:20], hex[20:]) - - def get_bytes(self): - bytes = '' - for shift in range(0, 128, 8): - bytes = chr((self.int >> shift) & 0xff) + bytes - return bytes - - bytes = property(get_bytes) - - def get_fields(self): - return (self.time_low, self.time_mid, self.time_hi_version, - self.clock_seq_hi_variant, self.clock_seq_low, self.node) - - fields = property(get_fields) - - def get_time_low(self): - return self.int >> 96L - - time_low = property(get_time_low) - - def get_time_mid(self): - return (self.int >> 80L) & 0xffff - - time_mid = property(get_time_mid) - - def get_time_hi_version(self): - return (self.int >> 64L) & 0xffff - - time_hi_version = property(get_time_hi_version) - - def get_clock_seq_hi_variant(self): - return (self.int >> 56L) & 0xff - - clock_seq_hi_variant = property(get_clock_seq_hi_variant) - - def get_clock_seq_low(self): - return (self.int >> 48L) & 0xff - - clock_seq_low = property(get_clock_seq_low) - - def get_time(self): - return (((self.time_hi_version & 0x0fffL) << 48L) | - (self.time_mid << 32L) | self.time_low) - - time = property(get_time) - - def get_clock_seq(self): - return (((self.clock_seq_hi_variant & 0x3fL) << 8L) | - self.clock_seq_low) - - clock_seq = property(get_clock_seq) - - def get_node(self): - return self.int & 0xffffffffffff - - node = property(get_node) - - def get_hex(self): - return '%032x' % self.int - - hex = property(get_hex) - - def get_urn(self): - return 'urn:uuid:' + str(self) - - urn = property(get_urn) - - def get_variant(self): - if not self.int & (0x8000 << 48L): - return RESERVED_NCS - elif not self.int & (0x4000 << 48L): - return RFC_4122 - elif not self.int & (0x2000 << 48L): - return RESERVED_MICROSOFT - else: - return RESERVED_FUTURE - - variant = property(get_variant) - - def get_version(self): - # The version bits are only meaningful for RFC 4122 UUIDs. - if self.variant == RFC_4122: - return int((self.int >> 76L) & 0xf) - - version = property(get_version) - -def _ifconfig_getnode(): - """Get the hardware address on Unix by running ifconfig.""" - import os - for dir in ['', '/sbin/', '/usr/sbin']: - try: - path = os.path.join(dir, 'ifconfig') - if os.path.exists(path): - pipe = os.popen(path) - else: - continue - except IOError: - continue - for line in pipe: - words = line.lower().split() - for i in range(len(words)): - if words[i] in ['hwaddr', 'ether']: - return int(words[i + 1].replace(':', ''), 16) - -def _ipconfig_getnode(): - """Get the hardware address on Windows by running ipconfig.exe.""" - import os, re - dirs = ['', r'c:\windows\system32', r'c:\winnt\system32'] - try: - import ctypes - buffer = ctypes.create_string_buffer(300) - ctypes.windll.kernel32.GetSystemDirectoryA(buffer, 300) - dirs.insert(0, buffer.value.decode('mbcs')) - except: - pass - for dir in dirs: - try: - pipe = os.popen(os.path.join(dir, 'ipconfig') + ' /all') - except IOError: - continue - for line in pipe: - value = line.split(':')[-1].strip().lower() - if re.match('([0-9a-f][0-9a-f]-){5}[0-9a-f][0-9a-f]', value): - return int(value.replace('-', ''), 16) - -def _netbios_getnode(): - """Get the hardware address on Windows using NetBIOS calls. - See http://support.microsoft.com/kb/118623 for details.""" - import win32wnet, netbios - ncb = netbios.NCB() - ncb.Command = netbios.NCBENUM - ncb.Buffer = adapters = netbios.LANA_ENUM() - adapters._pack() - if win32wnet.Netbios(ncb) != 0: - return - adapters._unpack() - for i in range(adapters.length): - ncb.Reset() - ncb.Command = netbios.NCBRESET - ncb.Lana_num = ord(adapters.lana[i]) - if win32wnet.Netbios(ncb) != 0: - continue - ncb.Reset() - ncb.Command = netbios.NCBASTAT - ncb.Lana_num = ord(adapters.lana[i]) - ncb.Callname = '*'.ljust(16) - ncb.Buffer = status = netbios.ADAPTER_STATUS() - if win32wnet.Netbios(ncb) != 0: - continue - status._unpack() - bytes = map(ord, status.adapter_address) - return ((bytes[0]<<40L) + (bytes[1]<<32L) + (bytes[2]<<24L) + - (bytes[3]<<16L) + (bytes[4]<<8L) + bytes[5]) - -# Thanks to Thomas Heller for ctypes and for his help with its use here. - -# If ctypes is available, use it to find system routines for UUID generation. -_uuid_generate_random = _uuid_generate_time = _UuidCreate = None -try: - import ctypes, ctypes.util - _buffer = ctypes.create_string_buffer(16) - - # The uuid_generate_* routines are provided by libuuid on at least - # Linux and FreeBSD, and provided by libc on Mac OS X. - for libname in ['uuid', 'c']: - try: - lib = ctypes.CDLL(ctypes.util.find_library(libname)) - except: - continue - if hasattr(lib, 'uuid_generate_random'): - _uuid_generate_random = lib.uuid_generate_random - if hasattr(lib, 'uuid_generate_time'): - _uuid_generate_time = lib.uuid_generate_time - - # On Windows prior to 2000, UuidCreate gives a UUID containing the - # hardware address. On Windows 2000 and later, UuidCreate makes a - # random UUID and UuidCreateSequential gives a UUID containing the - # hardware address. These routines are provided by the RPC runtime. - try: - lib = ctypes.windll.rpcrt4 - except: - lib = None - _UuidCreate = getattr(lib, 'UuidCreateSequential', - getattr(lib, 'UuidCreate', None)) -except: - pass - -def _unixdll_getnode(): - """Get the hardware address on Unix using ctypes.""" - _uuid_generate_time(_buffer) - return UUID(bytes=_buffer.raw).node - -def _windll_getnode(): - """Get the hardware address on Windows using ctypes.""" - if _UuidCreate(_buffer) == 0: - return UUID(bytes=_buffer.raw).node - -def _random_getnode(): - """Get a random node ID, with eighth bit set as suggested by RFC 4122.""" - import random - return random.randrange(0, 1<<48L) | 0x010000000000L - -_node = None - -def getnode(): - """Get the hardware address as a 48-bit integer. The first time this - runs, it may launch a separate program, which could be quite slow. If - all attempts to obtain the hardware address fail, we choose a random - 48-bit number with its eighth bit set to 1 as recommended in RFC 4122.""" - - global _node - if _node is not None: - return _node - - import sys - if sys.platform == 'win32': - getters = [_windll_getnode, _netbios_getnode, _ipconfig_getnode] - else: - getters = [_unixdll_getnode, _ifconfig_getnode] - - for getter in getters + [_random_getnode]: - try: - _node = getter() - except: - continue - if _node is not None: - return _node - -def uuid1(node=None, clock_seq=None): - """Generate a UUID from a host ID, sequence number, and the current time. - If 'node' is not given, getnode() is used to obtain the hardware - address. If 'clock_seq' is given, it is used as the sequence number; - otherwise a random 14-bit sequence number is chosen.""" - - # When the system provides a version-1 UUID generator, use it (but don't - # use UuidCreate here because its UUIDs don't conform to RFC 4122). - if _uuid_generate_time and node is clock_seq is None: - _uuid_generate_time(_buffer) - return UUID(bytes=_buffer.raw) - - import time - nanoseconds = int(time.time() * 1e9) - # 0x01b21dd213814000 is the number of 100-ns intervals between the - # UUID epoch 1582-10-15 00:00:00 and the Unix epoch 1970-01-01 00:00:00. - timestamp = int(nanoseconds/100) + 0x01b21dd213814000L - if clock_seq is None: - import random - clock_seq = random.randrange(1<<14L) # instead of stable storage - time_low = timestamp & 0xffffffffL - time_mid = (timestamp >> 32L) & 0xffffL - time_hi_version = (timestamp >> 48L) & 0x0fffL - clock_seq_low = clock_seq & 0xffL - clock_seq_hi_variant = (clock_seq >> 8L) & 0x3fL - if node is None: - node = getnode() - return UUID(fields=(time_low, time_mid, time_hi_version, - clock_seq_hi_variant, clock_seq_low, node), version=1) - -def uuid3(namespace, name): - """Generate a UUID from the MD5 hash of a namespace UUID and a name.""" - hash = md5(namespace.bytes + name).digest() - return UUID(bytes=hash[:16], version=3) - -def uuid4(): - """Generate a random UUID.""" - - # When the system provides a version-4 UUID generator, use it. - if _uuid_generate_random: - _uuid_generate_random(_buffer) - return UUID(bytes=_buffer.raw) - - # Otherwise, get randomness from urandom or the 'random' module. - try: - import os - return UUID(bytes=os.urandom(16), version=4) - except: - import random - bytes = [chr(random.randrange(256)) for i in range(16)] - return UUID(bytes=bytes, version=4) - -def uuid5(namespace, name): - """Generate a UUID from the SHA-1 hash of a namespace UUID and a name.""" - import sha - hash = sha.sha(namespace.bytes + name).digest() - return UUID(bytes=hash[:16], version=5) - -# The following standard UUIDs are for use with uuid3() or uuid5(). - -NAMESPACE_DNS = UUID('6ba7b810-9dad-11d1-80b4-00c04fd430c8') -NAMESPACE_URL = UUID('6ba7b811-9dad-11d1-80b4-00c04fd430c8') -NAMESPACE_OID = UUID('6ba7b812-9dad-11d1-80b4-00c04fd430c8') -NAMESPACE_X500 = UUID('6ba7b814-9dad-11d1-80b4-00c04fd430c8') diff --git a/indra/libhacd/hacdHACD.cpp b/indra/libhacd/hacdHACD.cpp index bce8cedd79..181e55199e 100644 --- a/indra/libhacd/hacdHACD.cpp +++ b/indra/libhacd/hacdHACD.cpp @@ -138,7 +138,11 @@ namespace HACD if (m_callBack) { char msg[1024]; - sprintf(msg, "nCC %lu\n", m_graph.m_nCCs); +#if _MSC_VER + sprintf(msg, "nCC %Iu\n", m_graph.m_nCCs); +#else + sprintf(msg, "nCC %zu\n", m_graph.m_nCCs); +#endif (*m_callBack)(msg, 0.0, 0.0, m_graph.GetNVertices()); } @@ -679,7 +683,11 @@ namespace HACD { if ((!condition1) && m_callBack) { - sprintf(msg, "\n-> %lu\t%f\t%f\t%f\n", m_pqueue.size(), m_graph.m_vertices[v1].m_surf*100.0/m_area, m_graph.m_vertices[v2].m_surf*100.0/m_area, m_graph.m_edges[currentEdge.m_name].m_concavity); +#if _MSC_VER + sprintf(msg, "\n-> %Iu\t%f\t%f\t%f\n", m_pqueue.size(), m_graph.m_vertices[v1].m_surf*100.0/m_area, m_graph.m_vertices[v2].m_surf*100.0/m_area, m_graph.m_edges[currentEdge.m_name].m_concavity); +#else + sprintf(msg, "\n-> %zu\t%f\t%f\t%f\n", m_pqueue.size(), m_graph.m_vertices[v1].m_surf*100.0/m_area, m_graph.m_vertices[v2].m_surf*100.0/m_area, m_graph.m_edges[currentEdge.m_name].m_concavity); +#endif (*m_callBack)(msg, progress, globalConcavity, m_graph.GetNVertices()); } globalConcavity = std::max(globalConcavity ,m_graph.m_edges[currentEdge.m_name].m_concavity); @@ -879,7 +887,11 @@ namespace HACD if (m_callBack) { char msg[1024]; - sprintf(msg, "\t CH(%lu) \t %lu \t %lf \t %lu \t %f \t %lu\n", v, static_cast(p), m_graph.m_vertices[v].m_concavity, m_graph.m_vertices[v].m_distPoints.Size(), m_graph.m_vertices[v].m_surf*100.0/m_area, m_graph.m_vertices[v].m_ancestors.size()); +#if _MSC_VER + sprintf(msg, "\t CH(%Iu) \t %Iu \t %lf \t %Iu \t %f \t %Iu\n", v, p, m_graph.m_vertices[v].m_concavity, m_graph.m_vertices[v].m_distPoints.Size(), m_graph.m_vertices[v].m_surf*100.0/m_area, m_graph.m_vertices[v].m_ancestors.size()); +#else + sprintf(msg, "\t CH(%zu) \t %zu \t %lf \t %zu \t %f \t %zu\n", v, p, m_graph.m_vertices[v].m_concavity, m_graph.m_vertices[v].m_distPoints.Size(), m_graph.m_vertices[v].m_surf*100.0/m_area, m_graph.m_vertices[v].m_ancestors.size()); +#endif (*m_callBack)(msg, 0.0, 0.0, m_nClusters); p++; } @@ -977,7 +989,8 @@ namespace HACD m_convexHulls[p].AddPoint(m_points[point.m_name], point.m_name); } } - m_convexHulls[p].SetDistPoints(0); //&m_graph.m_vertices[v].m_distPoints + if (p < m_nClusters) + m_convexHulls[p].SetDistPoints(0); //&m_graph.m_vertices[v].m_distPoints if (fullCH) { while (m_convexHulls[p].Process() == ICHullErrorInconsistent) // if we face problems when constructing the visual-hull. really ugly!!!! diff --git a/indra/libhacd/hacdHACD.h b/indra/libhacd/hacdHACD.h index 0c9f116537..fd9fd4301f 100644 --- a/indra/libhacd/hacdHACD.h +++ b/indra/libhacd/hacdHACD.h @@ -22,7 +22,9 @@ #include #include #include - +#if defined(_MSC_VER) && _MSC_VER >= 1700 +#include +#endif namespace HACD { const double sc_pi = 3.14159265; @@ -315,7 +317,7 @@ namespace HACD bool m_addFacesPoints; //>! specifies whether to add faces points or not bool m_addExtraDistPoints; //>! specifies whether to add extra points for concave shapes or not - friend HACD * const CreateHACD(HeapManager * heapManager = 0); + friend HACD * const CreateHACD(HeapManager * heapManager); friend void DestroyHACD(HACD * const hacd); }; inline HACD * const CreateHACD(HeapManager * heapManager) diff --git a/indra/libhacd/hacdMicroAllocator.cpp b/indra/libhacd/hacdMicroAllocator.cpp index 47562f6a4f..664b5e8c66 100644 --- a/indra/libhacd/hacdMicroAllocator.cpp +++ b/indra/libhacd/hacdMicroAllocator.cpp @@ -436,7 +436,7 @@ class MyMicroAllocator : public MicroAllocator, public MicroChunkUpdate, public } - ~MyMicroAllocator(void) + virtual ~MyMicroAllocator() { if ( mMicroChunks ) { @@ -746,7 +746,7 @@ class MyHeapManager : public MicroHeap, public HeapManager mMicro = createMicroAllocator(this,defaultChunkSize); } - ~MyHeapManager(void) + virtual ~MyHeapManager() { releaseMicroAllocator(mMicro); } diff --git a/indra/libhacd/hacdRaycastMesh.cpp b/indra/libhacd/hacdRaycastMesh.cpp index 5edd9adc31..28e1325a15 100644 --- a/indra/libhacd/hacdRaycastMesh.cpp +++ b/indra/libhacd/hacdRaycastMesh.cpp @@ -17,6 +17,10 @@ #include #include #include "hacdManifoldMesh.h" + +#if _MSC_VER >= 1800 +#include +#endif namespace HACD { bool BBox::Raycast(const Vec3 & origin, const Vec3 & dir, Float & distMin) const @@ -106,7 +110,7 @@ namespace HACD m_nMaxNodes = 0; for(size_t k = 0; k < maxDepth; k++) { - m_nMaxNodes += (1 << maxDepth); + m_nMaxNodes += (static_cast(1) << maxDepth); } m_nodes = new RMNode[m_nMaxNodes]; RMNode & root = m_nodes[AddNode()]; diff --git a/indra/libndhacd/CMakeLists.txt b/indra/libndhacd/CMakeLists.txt index bcc1973c01..ce520fbdc6 100644 --- a/indra/libndhacd/CMakeLists.txt +++ b/indra/libndhacd/CMakeLists.txt @@ -7,7 +7,7 @@ include(00-Common) include_directories(${LIBS_OPEN_DIR}/libhacd) set (libndhacd_SOURCE_FILES - LLConvexDecomposition.cpp + llconvexdecomposition.cpp nd_hacdConvexDecomposition.cpp nd_hacdStructs.cpp nd_hacdUtils.cpp @@ -16,12 +16,12 @@ set (libndhacd_SOURCE_FILES ) set (libndhacd_HEADER_FILES - LLConvexDecomposition.h + llconvexdecomposition.h ndConvexDecomposition.h nd_hacdConvexDecomposition.h nd_hacdStructs.h nd_StructTracer.h - LLConvexDecompositionStubImpl.h + llconvexdecompositionstubimpl.h nd_EnterExitTracer.h nd_hacdDefines.h nd_hacdUtils.h @@ -33,3 +33,8 @@ set_source_files_properties(${libndhacd_HEADER_FILES} add_library( nd_hacdConvexDecomposition STATIC ${libndhacd_SOURCE_FILES} ${libndhacd_HEADER_FILES}) +target_link_libraries( + nd_hacdConvexDecomposition + PUBLIC + llcommon + ) diff --git a/indra/libndhacd/LLConvexDecomposition.cpp b/indra/libndhacd/LLConvexDecomposition.cpp deleted file mode 100644 index 80ec5f4354..0000000000 --- a/indra/libndhacd/LLConvexDecomposition.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/** - * @file LLConvexDecomposition.cpp - * @author falcon@lindenlab.com - * @brief A stub implementation of LLConvexDecomposition interface - * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#if defined(_WINDOWS) -# include "windowsincludes.h" -#endif - -#ifndef NULL -#define NULL 0 -#endif - -#include "nd_hacdConvexDecomposition.h" - -#include "LLConvexDecomposition.h" - - -/*static */bool LLConvexDecomposition::s_isInitialized = false; - -/*static*/LLConvexDecomposition* LLConvexDecomposition::getInstance() -{ - if ( !s_isInitialized ) - { - return NULL; - } - else - { - return nd_hacdConvexDecomposition::getInstance(); - } -} - -/*static */LLCDResult LLConvexDecomposition::initSystem() -{ - LLCDResult result = nd_hacdConvexDecomposition::initSystem(); - if ( result == LLCD_OK ) - { - s_isInitialized = true; - } - return result; -} - -/*static */LLCDResult LLConvexDecomposition::initThread() -{ - return nd_hacdConvexDecomposition::initThread(); -} - -/*static */LLCDResult LLConvexDecomposition::quitThread() -{ - return nd_hacdConvexDecomposition::quitThread(); -} - -/*static */LLCDResult LLConvexDecomposition::quitSystem() -{ - return nd_hacdConvexDecomposition::quitSystem(); -} - - diff --git a/indra/libndhacd/LLConvexDecomposition.h b/indra/libndhacd/LLConvexDecomposition.h deleted file mode 100644 index 2d7f5aa3a3..0000000000 --- a/indra/libndhacd/LLConvexDecomposition.h +++ /dev/null @@ -1,231 +0,0 @@ -/** - * @file LLConvexDecomposition.cpp - * @brief LLConvexDecomposition interface definition - * - * $LicenseInfo:firstyear=2011&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2011, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_CONVEX_DECOMPOSITION -#define LL_CONVEX_DECOMPOSITION - -typedef int bool32; - -#if defined(_WIN32) || defined(_WIN64) -#define LLCD_CALL __cdecl -#else -#define LLCD_CALL -#endif - -struct LLCDParam -{ - enum LLCDParamType - { - LLCD_INVALID = 0, - LLCD_INTEGER, - LLCD_FLOAT, - LLCD_BOOLEAN, - LLCD_ENUM - }; - - struct LLCDEnumItem - { - const char* mName; - int mValue; - }; - - union LLCDValue - { - float mFloat; - int mIntOrEnumValue; - bool32 mBool; - }; - - union LLCDParamDetails - { - struct { - LLCDValue mLow; - LLCDValue mHigh; - LLCDValue mDelta; - } mRange; - - struct { - int mNumEnums; - LLCDEnumItem* mEnumsArray; - } mEnumValues; - }; - - const char* mName; - const char* mDescription; - LLCDParamType mType; - LLCDParamDetails mDetails; - LLCDValue mDefault; - int mStage; - - // WARNING: Only the LLConvexDecomposition implementation - // should change this value - int mReserved; -}; - -struct LLCDStageData -{ - const char* mName; - const char* mDescription; - bool32 mSupportsCallback; -}; - -struct LLCDMeshData -{ - enum IndexType - { - INT_16, - INT_32 - }; - - const float* mVertexBase; - int mVertexStrideBytes; - int mNumVertices; - const void* mIndexBase; - IndexType mIndexType; - int mIndexStrideBytes; - int mNumTriangles; -}; - -struct LLCDHull -{ - const float* mVertexBase; - int mVertexStrideBytes; - int mNumVertices; -}; - -enum LLCDResult -{ - LLCD_OK = 0, - LLCD_UNKOWN_ERROR, - LLCD_NULL_PTR, - LLCD_INVALID_STAGE, - LLCD_UNKNOWN_PARAM, - LLCD_BAD_VALUE, - LLCD_REQUEST_OUT_OF_RANGE, - LLCD_INVALID_MESH_DATA, - LLCD_INVALID_HULL_DATA, - LLCD_STAGE_NOT_READY, - LLCD_INVALID_THREAD, - LLCD_NOT_IMPLEMENTED -}; - -// This callback will receive a string describing the current subtask being performed -// as well as a pair of numbers indicating progress. (The values should not be interpreted -// as a completion percentage as 'current' may be greater than 'final'.) -// If the callback returns zero, the decomposition will be terminated -typedef int (LLCD_CALL *llcdCallbackFunc)(const char* description, int current, int final); - -class LLConvexDecomposition -{ -public: - // Obtain a pointer to the actual implementation - static LLConvexDecomposition* getInstance(); - - static LLCDResult initSystem(); - static LLCDResult initThread(); - static LLCDResult quitThread(); - static LLCDResult quitSystem(); - - // Generate a decomposition object handle - virtual void genDecomposition(int& decomp) = 0; - // Delete decomposition object handle - virtual void deleteDecomposition(int decomp) = 0; - // Bind given decomposition handle - // Commands operate on currently bound decomposition - virtual void bindDecomposition(int decomp) = 0; - - // Sets *paramsOut to the address of the LLCDParam array and returns - // the number of parameters - virtual int getParameters(const LLCDParam** paramsOut) = 0; - - - // Sets *stagesOut to the address of the LLCDStageData array and returns - // the number of stages - virtual int getStages(const LLCDStageData** stagesOut) = 0; - - - // Set a parameter by name. Pass enum values as integers. - virtual LLCDResult setParam(const char* name, float val) = 0; - virtual LLCDResult setParam(const char* name, int val) = 0; - virtual LLCDResult setParam(const char* name, bool val) = 0; - - - // Set incoming mesh data. Data is copied to local buffers and will - // persist until the next setMeshData call - virtual LLCDResult setMeshData( const LLCDMeshData* data, bool vertex_based ) = 0; - - - // Register a callback to be called periodically during the specified stage - // See the typedef above for more information - virtual LLCDResult registerCallback( int stage, llcdCallbackFunc callback ) = 0; - - - // Execute the specified decomposition stage - virtual LLCDResult executeStage(int stage) = 0; - virtual LLCDResult buildSingleHull() = 0 ; - - - // Gets the number of hulls generated by the specified decompositions stage - virtual int getNumHullsFromStage(int stage) = 0; - - - // Populates hullOut to reference the internal copy of the requested hull - // The data will persist only until the next executeStage call for that stage. - virtual LLCDResult getHullFromStage( int stage, int hull, LLCDHull* hullOut ) = 0; - virtual LLCDResult getSingleHull( LLCDHull* hullOut ) = 0 ; - - // TODO: Implement lock of some kind to disallow this call if data not yet ready - // Populates the meshDataOut to reference the utility's copy of the mesh geometry - // for the hull and stage specified. - // You must copy this data if you want to continue using it after the next executeStage - // call - virtual LLCDResult getMeshFromStage( int stage, int hull, LLCDMeshData* meshDataOut) = 0; - - - // Creates a mesh from hullIn and temporarily stores it internally in the utility. - // The mesh data persists only until the next call to getMeshFromHull - virtual LLCDResult getMeshFromHull( LLCDHull* hullIn, LLCDMeshData* meshOut ) = 0; - - // Takes meshIn, generates a single convex hull from it, converts that to a mesh - // stored internally, and populates meshOut to reference the internally stored data. - // The data is persistent only until the next call to generateSingleHullMeshFromMesh - virtual LLCDResult generateSingleHullMeshFromMesh( LLCDMeshData* meshIn, LLCDMeshData* meshOut) = 0; - - // - /// Debug - virtual void loadMeshData(const char* fileIn, LLCDMeshData** meshDataOut) = 0; - - virtual bool isFunctional()=0; - -private: - static bool s_isInitialized; -}; - -// Pull in our trace interface -#include "ndConvexDecomposition.h" - -#endif //LL_CONVEX_DECOMPOSITION - diff --git a/indra/libndhacd/LLConvexDecompositionStubImpl.cpp b/indra/libndhacd/LLConvexDecompositionStubImpl.cpp deleted file mode 100644 index 018143de16..0000000000 --- a/indra/libndhacd/LLConvexDecompositionStubImpl.cpp +++ /dev/null @@ -1,148 +0,0 @@ -/** - * @file LLConvexDecompositionStubImpl.cpp - * @author falcon@lindenlab.com - * @brief A stub implementation of LLConvexDecomposition - * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - - -#include -#include -#include "LLConvexDecompositionStubImpl.h" - -LLConvexDecomposition* LLConvexDecompositionImpl::getInstance() -{ - return NULL; -} - -LLCDResult LLConvexDecompositionImpl::initSystem() -{ - return LLCD_NOT_IMPLEMENTED; -} - -LLCDResult LLConvexDecompositionImpl::initThread() -{ - return LLCD_NOT_IMPLEMENTED; -} - -LLCDResult LLConvexDecompositionImpl::quitThread() -{ - return LLCD_NOT_IMPLEMENTED; -} - -LLCDResult LLConvexDecompositionImpl::quitSystem() -{ - return LLCD_NOT_IMPLEMENTED; -} - -void LLConvexDecompositionImpl::genDecomposition(int& decomp) -{ - -} - -void LLConvexDecompositionImpl::deleteDecomposition(int decomp) -{ - -} - -void LLConvexDecompositionImpl::bindDecomposition(int decomp) -{ - -} - -LLCDResult LLConvexDecompositionImpl::setParam(const char* name, float val) -{ - return LLCD_NOT_IMPLEMENTED; -} - -LLCDResult LLConvexDecompositionImpl::setParam(const char* name, bool val) -{ - return LLCD_NOT_IMPLEMENTED; -} - -LLCDResult LLConvexDecompositionImpl::setParam(const char* name, int val) -{ - return LLCD_NOT_IMPLEMENTED; -} - -LLCDResult LLConvexDecompositionImpl::setMeshData( const LLCDMeshData* data, bool vertex_based ) -{ - return LLCD_NOT_IMPLEMENTED; -} - -LLCDResult LLConvexDecompositionImpl::registerCallback(int stage, llcdCallbackFunc callback ) -{ - return LLCD_NOT_IMPLEMENTED; -} - -LLCDResult LLConvexDecompositionImpl::buildSingleHull() -{ - return LLCD_NOT_IMPLEMENTED; -} - -LLCDResult LLConvexDecompositionImpl::executeStage(int stage) -{ - return LLCD_NOT_IMPLEMENTED; -} - -int LLConvexDecompositionImpl::getNumHullsFromStage(int stage) -{ - return 0; -} - -LLCDResult LLConvexDecompositionImpl::getSingleHull( LLCDHull* hullOut ) -{ - memset( hullOut, 0, sizeof(LLCDHull) ); - return LLCD_NOT_IMPLEMENTED; -} - -LLCDResult LLConvexDecompositionImpl::getHullFromStage( int stage, int hull, LLCDHull* hullOut ) -{ - memset( hullOut, 0, sizeof(LLCDHull) ); - return LLCD_NOT_IMPLEMENTED; -} - -LLCDResult LLConvexDecompositionImpl::getMeshFromStage( int stage, int hull, LLCDMeshData* meshDataOut ) -{ - memset( meshDataOut, 0, sizeof(LLCDMeshData) ); - return LLCD_NOT_IMPLEMENTED; -} - -LLCDResult LLConvexDecompositionImpl::getMeshFromHull( LLCDHull* hullIn, LLCDMeshData* meshOut ) -{ - memset( meshOut, 0, sizeof(LLCDMeshData) ); - return LLCD_NOT_IMPLEMENTED; -} - -LLCDResult LLConvexDecompositionImpl::generateSingleHullMeshFromMesh(LLCDMeshData* meshIn, LLCDMeshData* meshOut) -{ - memset( meshOut, 0, sizeof(LLCDMeshData) ); - return LLCD_NOT_IMPLEMENTED; -} - -void LLConvexDecompositionImpl::loadMeshData(const char* fileIn, LLCDMeshData** meshDataOut) -{ - static LLCDMeshData meshData; - memset( &meshData, 0, sizeof(LLCDMeshData) ); - *meshDataOut = &meshData; -} diff --git a/indra/libndhacd/LLConvexDecompositionStubImpl.h b/indra/libndhacd/LLConvexDecompositionStubImpl.h deleted file mode 100644 index 9599175ef0..0000000000 --- a/indra/libndhacd/LLConvexDecompositionStubImpl.h +++ /dev/null @@ -1,97 +0,0 @@ -/** - * @file LLConvexDecompositionStubImpl.h - * @author falcon@lindenlab.com - * @brief A stub implementation of LLConvexDecomposition - * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - - -#ifndef LL_CONVEX_DECOMP_UTIL_H -#define LL_CONVEX_DECOMP_UTIL_H - -#include "LLConvexDecomposition.h" - -class LLConvexDecompositionImpl : public LLConvexDecomposition -{ - public: - - virtual ~LLConvexDecompositionImpl() {} - - static LLConvexDecomposition* getInstance(); - static LLCDResult initSystem(); - static LLCDResult initThread(); - static LLCDResult quitThread(); - static LLCDResult quitSystem(); - - // Generate a decomposition object handle - void genDecomposition(int& decomp); - // Delete decomposition object handle - void deleteDecomposition(int decomp); - // Bind given decomposition handle - // Commands operate on currently bound decomposition - void bindDecomposition(int decomp); - - // Sets *paramsOut to the address of the LLCDParam array and returns - // the length of the array - int getParameters(const LLCDParam** paramsOut) - { - *paramsOut = NULL; - return 0; - } - - int getStages(const LLCDStageData** stagesOut) - { - *stagesOut = NULL; - return 0; - } - - // Set a parameter by name. Returns false if out of bounds or unsupported parameter - LLCDResult setParam(const char* name, float val); - LLCDResult setParam(const char* name, int val); - LLCDResult setParam(const char* name, bool val); - LLCDResult setMeshData( const LLCDMeshData* data, bool vertex_based ); - LLCDResult registerCallback(int stage, llcdCallbackFunc callback ); - - LLCDResult executeStage(int stage); - LLCDResult buildSingleHull() ; - - int getNumHullsFromStage(int stage); - - LLCDResult getHullFromStage( int stage, int hull, LLCDHull* hullOut ); - LLCDResult getSingleHull( LLCDHull* hullOut ) ; - - // TODO: Implement lock of some kind to disallow this call if data not yet ready - LLCDResult getMeshFromStage( int stage, int hull, LLCDMeshData* meshDataOut); - LLCDResult getMeshFromHull( LLCDHull* hullIn, LLCDMeshData* meshOut ); - - // For visualizing convex hull shapes in the viewer physics shape display - LLCDResult generateSingleHullMeshFromMesh( LLCDMeshData* meshIn, LLCDMeshData* meshOut); - - /// Debug - void loadMeshData(const char* fileIn, LLCDMeshData** meshDataOut); - - private: - LLConvexDecompositionImpl() {} -}; - -#endif //LL_CONVEX_DECOMP_UTIL_H diff --git a/indra/libndhacd/llconvexdecomposition.cpp b/indra/libndhacd/llconvexdecomposition.cpp new file mode 100644 index 0000000000..2c1948629a --- /dev/null +++ b/indra/libndhacd/llconvexdecomposition.cpp @@ -0,0 +1,80 @@ +/** + * @file llconvexdecomposition.cpp + * @author falcon@lindenlab.com + * @brief A stub implementation of LLConvexDecomposition interface + * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#if defined(_WINDOWS) +# include "windowsincludes.h" +#endif + +#ifndef NULL +#define NULL 0 +#endif + +#include "nd_hacdConvexDecomposition.h" + +#include "llconvexdecomposition.h" + + +/*static */bool LLConvexDecomposition::s_isInitialized = false; + +/*static*/LLConvexDecomposition* LLConvexDecomposition::getInstance() +{ + if ( !s_isInitialized ) + { + return NULL; + } + else + { + return nd_hacdConvexDecomposition::getInstance(); + } +} + +/*static */LLCDResult LLConvexDecomposition::initSystem() +{ + LLCDResult result = nd_hacdConvexDecomposition::initSystem(); + if ( result == LLCD_OK ) + { + s_isInitialized = true; + } + return result; +} + +/*static */LLCDResult LLConvexDecomposition::initThread() +{ + return nd_hacdConvexDecomposition::initThread(); +} + +/*static */LLCDResult LLConvexDecomposition::quitThread() +{ + return nd_hacdConvexDecomposition::quitThread(); +} + +/*static */LLCDResult LLConvexDecomposition::quitSystem() +{ + return nd_hacdConvexDecomposition::quitSystem(); +} + + diff --git a/indra/libndhacd/llconvexdecomposition.h b/indra/libndhacd/llconvexdecomposition.h new file mode 100644 index 0000000000..9603c434f6 --- /dev/null +++ b/indra/libndhacd/llconvexdecomposition.h @@ -0,0 +1,231 @@ +/** + * @file llconvexdecomposition.cpp + * @brief LLConvexDecomposition interface definition + * + * $LicenseInfo:firstyear=2011&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2011, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_CONVEX_DECOMPOSITION +#define LL_CONVEX_DECOMPOSITION + +typedef int bool32; + +#if defined(_WIN32) || defined(_WIN64) +#define LLCD_CALL __cdecl +#else +#define LLCD_CALL +#endif + +struct LLCDParam +{ + enum LLCDParamType + { + LLCD_INVALID = 0, + LLCD_INTEGER, + LLCD_FLOAT, + LLCD_BOOLEAN, + LLCD_ENUM + }; + + struct LLCDEnumItem + { + const char* mName; + int mValue; + }; + + union LLCDValue + { + float mFloat; + int mIntOrEnumValue; + bool32 mBool; + }; + + union LLCDParamDetails + { + struct { + LLCDValue mLow; + LLCDValue mHigh; + LLCDValue mDelta; + } mRange; + + struct { + int mNumEnums; + LLCDEnumItem* mEnumsArray; + } mEnumValues; + }; + + const char* mName; + const char* mDescription; + LLCDParamType mType; + LLCDParamDetails mDetails; + LLCDValue mDefault; + int mStage; + + // WARNING: Only the LLConvexDecomposition implementation + // should change this value + int mReserved; +}; + +struct LLCDStageData +{ + const char* mName; + const char* mDescription; + bool32 mSupportsCallback; +}; + +struct LLCDMeshData +{ + enum IndexType + { + INT_16, + INT_32 + }; + + const float* mVertexBase; + int mVertexStrideBytes; + int mNumVertices; + const void* mIndexBase; + IndexType mIndexType; + int mIndexStrideBytes; + int mNumTriangles; +}; + +struct LLCDHull +{ + const float* mVertexBase; + int mVertexStrideBytes; + int mNumVertices; +}; + +enum LLCDResult +{ + LLCD_OK = 0, + LLCD_UNKOWN_ERROR, + LLCD_NULL_PTR, + LLCD_INVALID_STAGE, + LLCD_UNKNOWN_PARAM, + LLCD_BAD_VALUE, + LLCD_REQUEST_OUT_OF_RANGE, + LLCD_INVALID_MESH_DATA, + LLCD_INVALID_HULL_DATA, + LLCD_STAGE_NOT_READY, + LLCD_INVALID_THREAD, + LLCD_NOT_IMPLEMENTED +}; + +// This callback will receive a string describing the current subtask being performed +// as well as a pair of numbers indicating progress. (The values should not be interpreted +// as a completion percentage as 'current' may be greater than 'final'.) +// If the callback returns zero, the decomposition will be terminated +typedef int (LLCD_CALL *llcdCallbackFunc)(const char* description, int current, int final); + +class LLConvexDecomposition +{ +public: + // Obtain a pointer to the actual implementation + static LLConvexDecomposition* getInstance(); + + static LLCDResult initSystem(); + static LLCDResult initThread(); + static LLCDResult quitThread(); + static LLCDResult quitSystem(); + + // Generate a decomposition object handle + virtual void genDecomposition(int& decomp) = 0; + // Delete decomposition object handle + virtual void deleteDecomposition(int decomp) = 0; + // Bind given decomposition handle + // Commands operate on currently bound decomposition + virtual void bindDecomposition(int decomp) = 0; + + // Sets *paramsOut to the address of the LLCDParam array and returns + // the number of parameters + virtual int getParameters(const LLCDParam** paramsOut) = 0; + + + // Sets *stagesOut to the address of the LLCDStageData array and returns + // the number of stages + virtual int getStages(const LLCDStageData** stagesOut) = 0; + + + // Set a parameter by name. Pass enum values as integers. + virtual LLCDResult setParam(const char* name, float val) = 0; + virtual LLCDResult setParam(const char* name, int val) = 0; + virtual LLCDResult setParam(const char* name, bool val) = 0; + + + // Set incoming mesh data. Data is copied to local buffers and will + // persist until the next setMeshData call + virtual LLCDResult setMeshData( const LLCDMeshData* data, bool vertex_based ) = 0; + + + // Register a callback to be called periodically during the specified stage + // See the typedef above for more information + virtual LLCDResult registerCallback( int stage, llcdCallbackFunc callback ) = 0; + + + // Execute the specified decomposition stage + virtual LLCDResult executeStage(int stage) = 0; + virtual LLCDResult buildSingleHull() = 0 ; + + + // Gets the number of hulls generated by the specified decompositions stage + virtual int getNumHullsFromStage(int stage) = 0; + + + // Populates hullOut to reference the internal copy of the requested hull + // The data will persist only until the next executeStage call for that stage. + virtual LLCDResult getHullFromStage( int stage, int hull, LLCDHull* hullOut ) = 0; + virtual LLCDResult getSingleHull( LLCDHull* hullOut ) = 0 ; + + // TODO: Implement lock of some kind to disallow this call if data not yet ready + // Populates the meshDataOut to reference the utility's copy of the mesh geometry + // for the hull and stage specified. + // You must copy this data if you want to continue using it after the next executeStage + // call + virtual LLCDResult getMeshFromStage( int stage, int hull, LLCDMeshData* meshDataOut) = 0; + + + // Creates a mesh from hullIn and temporarily stores it internally in the utility. + // The mesh data persists only until the next call to getMeshFromHull + virtual LLCDResult getMeshFromHull( LLCDHull* hullIn, LLCDMeshData* meshOut ) = 0; + + // Takes meshIn, generates a single convex hull from it, converts that to a mesh + // stored internally, and populates meshOut to reference the internally stored data. + // The data is persistent only until the next call to generateSingleHullMeshFromMesh + virtual LLCDResult generateSingleHullMeshFromMesh( LLCDMeshData* meshIn, LLCDMeshData* meshOut) = 0; + + // + /// Debug + virtual void loadMeshData(const char* fileIn, LLCDMeshData** meshDataOut) = 0; + + virtual bool isFunctional()=0; + +private: + static bool s_isInitialized; +}; + +// Pull in our trace interface +#include "ndConvexDecomposition.h" + +#endif //LL_CONVEX_DECOMPOSITION + diff --git a/indra/libndhacd/llconvexdecompositionstubimpl.cpp b/indra/libndhacd/llconvexdecompositionstubimpl.cpp new file mode 100644 index 0000000000..d91f2ea860 --- /dev/null +++ b/indra/libndhacd/llconvexdecompositionstubimpl.cpp @@ -0,0 +1,148 @@ +/** + * @file llconvexdecompositionstubimpl.cpp + * @author falcon@lindenlab.com + * @brief A stub implementation of LLConvexDecomposition + * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + + +#include +#include +#include "llconvexdecompositionstubimpl.h" + +LLConvexDecomposition* LLConvexDecompositionImpl::getInstance() +{ + return NULL; +} + +LLCDResult LLConvexDecompositionImpl::initSystem() +{ + return LLCD_NOT_IMPLEMENTED; +} + +LLCDResult LLConvexDecompositionImpl::initThread() +{ + return LLCD_NOT_IMPLEMENTED; +} + +LLCDResult LLConvexDecompositionImpl::quitThread() +{ + return LLCD_NOT_IMPLEMENTED; +} + +LLCDResult LLConvexDecompositionImpl::quitSystem() +{ + return LLCD_NOT_IMPLEMENTED; +} + +void LLConvexDecompositionImpl::genDecomposition(int& decomp) +{ + +} + +void LLConvexDecompositionImpl::deleteDecomposition(int decomp) +{ + +} + +void LLConvexDecompositionImpl::bindDecomposition(int decomp) +{ + +} + +LLCDResult LLConvexDecompositionImpl::setParam(const char* name, float val) +{ + return LLCD_NOT_IMPLEMENTED; +} + +LLCDResult LLConvexDecompositionImpl::setParam(const char* name, bool val) +{ + return LLCD_NOT_IMPLEMENTED; +} + +LLCDResult LLConvexDecompositionImpl::setParam(const char* name, int val) +{ + return LLCD_NOT_IMPLEMENTED; +} + +LLCDResult LLConvexDecompositionImpl::setMeshData( const LLCDMeshData* data, bool vertex_based ) +{ + return LLCD_NOT_IMPLEMENTED; +} + +LLCDResult LLConvexDecompositionImpl::registerCallback(int stage, llcdCallbackFunc callback ) +{ + return LLCD_NOT_IMPLEMENTED; +} + +LLCDResult LLConvexDecompositionImpl::buildSingleHull() +{ + return LLCD_NOT_IMPLEMENTED; +} + +LLCDResult LLConvexDecompositionImpl::executeStage(int stage) +{ + return LLCD_NOT_IMPLEMENTED; +} + +int LLConvexDecompositionImpl::getNumHullsFromStage(int stage) +{ + return 0; +} + +LLCDResult LLConvexDecompositionImpl::getSingleHull( LLCDHull* hullOut ) +{ + memset( hullOut, 0, sizeof(LLCDHull) ); + return LLCD_NOT_IMPLEMENTED; +} + +LLCDResult LLConvexDecompositionImpl::getHullFromStage( int stage, int hull, LLCDHull* hullOut ) +{ + memset( hullOut, 0, sizeof(LLCDHull) ); + return LLCD_NOT_IMPLEMENTED; +} + +LLCDResult LLConvexDecompositionImpl::getMeshFromStage( int stage, int hull, LLCDMeshData* meshDataOut ) +{ + memset( meshDataOut, 0, sizeof(LLCDMeshData) ); + return LLCD_NOT_IMPLEMENTED; +} + +LLCDResult LLConvexDecompositionImpl::getMeshFromHull( LLCDHull* hullIn, LLCDMeshData* meshOut ) +{ + memset( meshOut, 0, sizeof(LLCDMeshData) ); + return LLCD_NOT_IMPLEMENTED; +} + +LLCDResult LLConvexDecompositionImpl::generateSingleHullMeshFromMesh(LLCDMeshData* meshIn, LLCDMeshData* meshOut) +{ + memset( meshOut, 0, sizeof(LLCDMeshData) ); + return LLCD_NOT_IMPLEMENTED; +} + +void LLConvexDecompositionImpl::loadMeshData(const char* fileIn, LLCDMeshData** meshDataOut) +{ + static LLCDMeshData meshData; + memset( &meshData, 0, sizeof(LLCDMeshData) ); + *meshDataOut = &meshData; +} diff --git a/indra/libndhacd/llconvexdecompositionstubimpl.h b/indra/libndhacd/llconvexdecompositionstubimpl.h new file mode 100644 index 0000000000..023bd7c239 --- /dev/null +++ b/indra/libndhacd/llconvexdecompositionstubimpl.h @@ -0,0 +1,97 @@ +/** + * @file llconvexdecompositionstubimpl.h + * @author falcon@lindenlab.com + * @brief A stub implementation of LLConvexDecomposition + * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + + +#ifndef LL_CONVEX_DECOMP_UTIL_H +#define LL_CONVEX_DECOMP_UTIL_H + +#include "llconvexdecomposition.h" + +class LLConvexDecompositionImpl : public LLConvexDecomposition +{ + public: + + virtual ~LLConvexDecompositionImpl() {} + + static LLConvexDecomposition* getInstance(); + static LLCDResult initSystem(); + static LLCDResult initThread(); + static LLCDResult quitThread(); + static LLCDResult quitSystem(); + + // Generate a decomposition object handle + void genDecomposition(int& decomp); + // Delete decomposition object handle + void deleteDecomposition(int decomp); + // Bind given decomposition handle + // Commands operate on currently bound decomposition + void bindDecomposition(int decomp); + + // Sets *paramsOut to the address of the LLCDParam array and returns + // the length of the array + int getParameters(const LLCDParam** paramsOut) + { + *paramsOut = NULL; + return 0; + } + + int getStages(const LLCDStageData** stagesOut) + { + *stagesOut = NULL; + return 0; + } + + // Set a parameter by name. Returns false if out of bounds or unsupported parameter + LLCDResult setParam(const char* name, float val); + LLCDResult setParam(const char* name, int val); + LLCDResult setParam(const char* name, bool val); + LLCDResult setMeshData( const LLCDMeshData* data, bool vertex_based ); + LLCDResult registerCallback(int stage, llcdCallbackFunc callback ); + + LLCDResult executeStage(int stage); + LLCDResult buildSingleHull() ; + + int getNumHullsFromStage(int stage); + + LLCDResult getHullFromStage( int stage, int hull, LLCDHull* hullOut ); + LLCDResult getSingleHull( LLCDHull* hullOut ) ; + + // TODO: Implement lock of some kind to disallow this call if data not yet ready + LLCDResult getMeshFromStage( int stage, int hull, LLCDMeshData* meshDataOut); + LLCDResult getMeshFromHull( LLCDHull* hullIn, LLCDMeshData* meshOut ); + + // For visualizing convex hull shapes in the viewer physics shape display + LLCDResult generateSingleHullMeshFromMesh( LLCDMeshData* meshIn, LLCDMeshData* meshOut); + + /// Debug + void loadMeshData(const char* fileIn, LLCDMeshData** meshDataOut); + + private: + LLConvexDecompositionImpl() {} +}; + +#endif //LL_CONVEX_DECOMP_UTIL_H diff --git a/indra/libndhacd/nd_StructTracer.h b/indra/libndhacd/nd_StructTracer.h index 6dbe3ce3e4..631bfd7880 100644 --- a/indra/libndhacd/nd_StructTracer.h +++ b/indra/libndhacd/nd_StructTracer.h @@ -21,7 +21,7 @@ #include "ndConvexDecomposition.h" -#include "LLConvexDecomposition.h" +#include "llconvexdecomposition.h" #include "nd_hacdStructs.h" namespace ndStructTracer diff --git a/indra/libndhacd/nd_hacdConvexDecomposition.h b/indra/libndhacd/nd_hacdConvexDecomposition.h index e31779c651..6b7c7f9520 100644 --- a/indra/libndhacd/nd_hacdConvexDecomposition.h +++ b/indra/libndhacd/nd_hacdConvexDecomposition.h @@ -19,7 +19,7 @@ #ifndef ND_HACD_CONVEXDECOMP_H #define ND_HACD_CONVEXDECOMP_H -#include "LLConvexDecomposition.h" +#include "llconvexdecomposition.h" #include #include diff --git a/indra/libndhacd/nd_hacdStructs.cpp b/indra/libndhacd/nd_hacdStructs.cpp index 4a5c9e6fbf..8d3a214627 100644 --- a/indra/libndhacd/nd_hacdStructs.cpp +++ b/indra/libndhacd/nd_hacdStructs.cpp @@ -17,7 +17,6 @@ */ #include "nd_hacdStructs.h" -#include "LLConvexDecomposition.h" void DecompHull::clear() { diff --git a/indra/libndhacd/nd_hacdStructs.h b/indra/libndhacd/nd_hacdStructs.h index 5097b74286..c295fedca9 100644 --- a/indra/libndhacd/nd_hacdStructs.h +++ b/indra/libndhacd/nd_hacdStructs.h @@ -21,7 +21,7 @@ #include "nd_hacdDefines.h" #include "hacdHACD.h" -#include "LLConvexDecomposition.h" +#include "llconvexdecomposition.h" #include struct LLCDHull; diff --git a/indra/libndhacd/nd_hacdUtils.h b/indra/libndhacd/nd_hacdUtils.h index e2d80e78d9..8a59125ab3 100644 --- a/indra/libndhacd/nd_hacdUtils.h +++ b/indra/libndhacd/nd_hacdUtils.h @@ -20,7 +20,6 @@ #define ND_HACD_UTILS_H #include "nd_hacdStructs.h" -#include "LLConvexDecomposition.h" tHACD* init( int nConcavity, int nClusters, int nMaxVerticesPerHull, double dMaxConnectDist, HACDDecoder *aData ); DecompData decompose( tHACD *aHACD ); diff --git a/indra/libopenjpeg/CMakeLists.txt b/indra/libopenjpeg/CMakeLists.txt index da21fe8dcb..9e41149eae 100644 --- a/indra/libopenjpeg/CMakeLists.txt +++ b/indra/libopenjpeg/CMakeLists.txt @@ -26,6 +26,7 @@ set(openjpeg_SOURCE_FILES mct.c mqc.c openjpeg.c + opj_malloc.c phix_manager.c pi.c ppix_manager.c diff --git a/indra/libopenjpeg/dwt.c b/indra/libopenjpeg/dwt.c index 0fbfc2033f..e641f15492 100644 --- a/indra/libopenjpeg/dwt.c +++ b/indra/libopenjpeg/dwt.c @@ -31,11 +31,16 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#define OPJ_SKIP_POISON +#include "opj_includes.h" + #ifdef __SSE__ #include #endif -#include "opj_includes.h" +#if defined(__GNUC__) +#pragma GCC poison malloc calloc realloc free +#endif /** @defgroup DWT DWT - Implementation of a discrete wavelet transform */ /*@{*/ @@ -499,7 +504,7 @@ void dwt_calc_explicit_stepsizes(opj_tccp_t * tccp, int prec) { /* */ /* Determine maximum computed resolution level for inverse wavelet transform */ /* */ -static int dwt_decode_max_resolution(opj_tcd_resolution_t* restrict r, int i) { +static int dwt_decode_max_resolution(opj_tcd_resolution_t* OPJ_RESTRICT r, int i) { int mr = 1; int w; while( --i ) { @@ -531,7 +536,7 @@ static void dwt_decode_tile(opj_tcd_tilecomp_t* tilec, int numres, DWT1DFN dwt_1 v.mem = h.mem; while( --numres) { - int * restrict tiledp = tilec->data; + int * OPJ_RESTRICT tiledp = tilec->data; int j; ++tr; @@ -565,48 +570,49 @@ static void dwt_decode_tile(opj_tcd_tilecomp_t* tilec, int numres, DWT1DFN dwt_1 opj_aligned_free(h.mem); } -static void v4dwt_interleave_h(v4dwt_t* restrict w, float* restrict a, int x, int size){ - float* restrict bi = (float*) (w->wavelet + w->cas); +static void v4dwt_interleave_h(v4dwt_t* OPJ_RESTRICT w, float* OPJ_RESTRICT a, int x, int size) { + float* OPJ_RESTRICT bi = (float*)(w->wavelet + w->cas); int count = w->sn; int i, k; - for(k = 0; k < 2; ++k){ - if (count + 3 * x < size && ((size_t) a & 0x0f) == 0 && ((size_t) bi & 0x0f) == 0 && (x & 0x0f) == 0) { + for (k = 0; k < 2; ++k) { + if (count + 3 * x < size && ((size_t)a & 0x0f) == 0 && ((size_t)bi & 0x0f) == 0 && (x & 0x0f) == 0) { /* Fast code path */ - for(i = 0; i < count; ++i){ + for (i = 0; i < count; ++i) { int j = i; - bi[i*8 ] = a[j]; + bi[i * 8] = a[j]; j += x; - bi[i*8 + 1] = a[j]; + bi[i * 8 + 1] = a[j]; j += x; - bi[i*8 + 2] = a[j]; + bi[i * 8 + 2] = a[j]; j += x; - bi[i*8 + 3] = a[j]; + bi[i * 8 + 3] = a[j]; } - } else { - /* Slow code path */ - for(i = 0; i < count; ++i){ - int j = i; - bi[i*8 ] = a[j]; - j += x; - if(j > size) continue; - bi[i*8 + 1] = a[j]; - j += x; - if(j > size) continue; - bi[i*8 + 2] = a[j]; - j += x; - if(j > size) continue; - bi[i*8 + 3] = a[j]; } + else { + /* Slow code path */ + for (i = 0; i < count; ++i) { + int j = i; + bi[i * 8] = a[j]; + j += x; + if (j > size) continue; + bi[i * 8 + 1] = a[j]; + j += x; + if (j > size) continue; + bi[i * 8 + 2] = a[j]; + j += x; + if (j > size) continue; + bi[i * 8 + 3] = a[j]; + } } - bi = (float*) (w->wavelet + 1 - w->cas); + bi = (float*)(w->wavelet + 1 - w->cas); a += w->sn; size -= w->sn; count = w->dn; } } -static void v4dwt_interleave_v(v4dwt_t* restrict v , float* restrict a , int x){ - v4* restrict bi = v->wavelet + v->cas; +static void v4dwt_interleave_v(v4dwt_t* OPJ_RESTRICT v , float* OPJ_RESTRICT a , int x){ + v4* OPJ_RESTRICT bi = v->wavelet + v->cas; int i; for(i = 0; i < v->sn; ++i){ memcpy(&bi[i*2], &a[i*x], 4 * sizeof(float)); @@ -621,7 +627,7 @@ static void v4dwt_interleave_v(v4dwt_t* restrict v , float* restrict a , int x){ #ifdef __SSE__ static void v4dwt_decode_step1_sse(v4* w, int count, const __m128 c){ - __m128* restrict vw = (__m128*) w; + __m128* OPJ_RESTRICT vw = (__m128*) w; int i; /* 4x unrolled loop */ for(i = 0; i < count >> 2; ++i){ @@ -642,22 +648,39 @@ static void v4dwt_decode_step1_sse(v4* w, int count, const __m128 c){ } static void v4dwt_decode_step2_sse(v4* l, v4* w, int k, int m, __m128 c){ - __m128* restrict vl = (__m128*) l; - __m128* restrict vw = (__m128*) w; + __m128* OPJ_RESTRICT vl = (__m128*) l; + __m128* OPJ_RESTRICT vw = (__m128*) w; int i; __m128 tmp1, tmp2, tmp3; tmp1 = vl[0]; - for(i = 0; i < m; ++i){ + for (i = 0; i < m - 3; i += 4) { + __m128 tmp4, tmp5, tmp6, tmp7, tmp8, tmp9; + tmp2 = vw[-1]; + tmp3 = vw[0]; + tmp4 = vw[1]; + tmp5 = vw[2]; + tmp6 = vw[3]; + tmp7 = vw[4]; + tmp8 = vw[5]; + tmp9 = vw[6]; + vw[-1] = _mm_add_ps(tmp2, _mm_mul_ps(_mm_add_ps(tmp1, tmp3), c)); + vw[1] = _mm_add_ps(tmp4, _mm_mul_ps(_mm_add_ps(tmp3, tmp5), c)); + vw[3] = _mm_add_ps(tmp6, _mm_mul_ps(_mm_add_ps(tmp5, tmp7), c)); + vw[5] = _mm_add_ps(tmp8, _mm_mul_ps(_mm_add_ps(tmp7, tmp9), c)); + tmp1 = tmp9; + vw += 8; + } + for ( ; i < m; ++i) { tmp2 = vw[-1]; tmp3 = vw[ 0]; vw[-1] = _mm_add_ps(tmp2, _mm_mul_ps(_mm_add_ps(tmp1, tmp3), c)); tmp1 = tmp3; vw += 2; } - vl = vw - 2; if(m >= k){ return; } + vl = vw - 2; c = _mm_add_ps(c, c); c = _mm_mul_ps(c, vl[0]); for(; m < k; ++m){ @@ -670,7 +693,7 @@ static void v4dwt_decode_step2_sse(v4* l, v4* w, int k, int m, __m128 c){ #else static void v4dwt_decode_step1(v4* w, int count, const float c){ - float* restrict fw = (float*) w; + float* OPJ_RESTRICT fw = (float*) w; int i; for(i = 0; i < count; ++i){ float tmp1 = fw[i*8 ]; @@ -685,8 +708,8 @@ static void v4dwt_decode_step1(v4* w, int count, const float c){ } static void v4dwt_decode_step2(v4* l, v4* w, int k, int m, float c){ - float* restrict fl = (float*) l; - float* restrict fw = (float*) w; + float* OPJ_RESTRICT fl = (float*) l; + float* OPJ_RESTRICT fw = (float*) w; int i; for(i = 0; i < m; ++i){ float tmp1_1 = fl[0]; @@ -737,42 +760,44 @@ static void v4dwt_decode_step2(v4* l, v4* w, int k, int m, float c){ /* */ /* Inverse 9-7 wavelet transform in 1-D. */ /* */ -static void v4dwt_decode(v4dwt_t* restrict dwt){ +static void v4dwt_decode(v4dwt_t* OPJ_RESTRICT dwt){ int a, b; if(dwt->cas == 0) { - if(!((dwt->dn > 0) || (dwt->sn > 1))){ + if (dwt->dn <= 0 && dwt->sn <= 1) { return; } a = 0; b = 1; }else{ - if(!((dwt->sn > 0) || (dwt->dn > 1))) { + if (dwt->sn <= 0 && dwt->dn <= 1) { return; } a = 1; b = 0; } + v4* OPJ_RESTRICT waveleta = dwt->wavelet + a; + v4* OPJ_RESTRICT waveletb = dwt->wavelet + b; #ifdef __SSE__ - v4dwt_decode_step1_sse(dwt->wavelet+a, dwt->sn, _mm_set1_ps(K)); - v4dwt_decode_step1_sse(dwt->wavelet+b, dwt->dn, _mm_set1_ps(c13318)); - v4dwt_decode_step2_sse(dwt->wavelet+b, dwt->wavelet+a+1, dwt->sn, int_min(dwt->sn, dwt->dn-a), _mm_set1_ps(dwt_delta)); - v4dwt_decode_step2_sse(dwt->wavelet+a, dwt->wavelet+b+1, dwt->dn, int_min(dwt->dn, dwt->sn-b), _mm_set1_ps(dwt_gamma)); - v4dwt_decode_step2_sse(dwt->wavelet+b, dwt->wavelet+a+1, dwt->sn, int_min(dwt->sn, dwt->dn-a), _mm_set1_ps(dwt_beta)); - v4dwt_decode_step2_sse(dwt->wavelet+a, dwt->wavelet+b+1, dwt->dn, int_min(dwt->dn, dwt->sn-b), _mm_set1_ps(dwt_alpha)); + v4dwt_decode_step1_sse(waveleta, dwt->sn, _mm_set1_ps(K)); + v4dwt_decode_step1_sse(waveletb, dwt->dn, _mm_set1_ps(c13318)); + v4dwt_decode_step2_sse(waveletb, waveleta + 1, dwt->sn, int_min(dwt->sn, dwt->dn-a), _mm_set1_ps(dwt_delta)); + v4dwt_decode_step2_sse(waveleta, waveletb + 1, dwt->dn, int_min(dwt->dn, dwt->sn-b), _mm_set1_ps(dwt_gamma)); + v4dwt_decode_step2_sse(waveletb, waveleta + 1, dwt->sn, int_min(dwt->sn, dwt->dn-a), _mm_set1_ps(dwt_beta)); + v4dwt_decode_step2_sse(waveleta, waveletb + 1, dwt->dn, int_min(dwt->dn, dwt->sn-b), _mm_set1_ps(dwt_alpha)); #else - v4dwt_decode_step1(dwt->wavelet+a, dwt->sn, K); - v4dwt_decode_step1(dwt->wavelet+b, dwt->dn, c13318); - v4dwt_decode_step2(dwt->wavelet+b, dwt->wavelet+a+1, dwt->sn, int_min(dwt->sn, dwt->dn-a), dwt_delta); - v4dwt_decode_step2(dwt->wavelet+a, dwt->wavelet+b+1, dwt->dn, int_min(dwt->dn, dwt->sn-b), dwt_gamma); - v4dwt_decode_step2(dwt->wavelet+b, dwt->wavelet+a+1, dwt->sn, int_min(dwt->sn, dwt->dn-a), dwt_beta); - v4dwt_decode_step2(dwt->wavelet+a, dwt->wavelet+b+1, dwt->dn, int_min(dwt->dn, dwt->sn-b), dwt_alpha); + v4dwt_decode_step1(waveleta, dwt->sn, K); + v4dwt_decode_step1(waveletb, dwt->dn, c13318); + v4dwt_decode_step2(waveletb, waveleta + 1, dwt->sn, int_min(dwt->sn, dwt->dn-a), dwt_delta); + v4dwt_decode_step2(waveleta, waveletb + 1, dwt->dn, int_min(dwt->dn, dwt->sn-b), dwt_gamma); + v4dwt_decode_step2(waveletb, waveleta + 1, dwt->sn, int_min(dwt->sn, dwt->dn-a), dwt_beta); + v4dwt_decode_step2(waveleta, waveletb + 1, dwt->dn, int_min(dwt->dn, dwt->sn-b), dwt_alpha); #endif } /* */ /* Inverse 9-7 wavelet transform in 2-D. */ /* */ -void dwt_decode_real(opj_tcd_tilecomp_t* restrict tilec, int numres){ +void dwt_decode_real(opj_tcd_tilecomp_t* OPJ_RESTRICT tilec, int numres){ v4dwt_t h; v4dwt_t v; @@ -787,7 +812,7 @@ void dwt_decode_real(opj_tcd_tilecomp_t* restrict tilec, int numres){ v.wavelet = h.wavelet; while( --numres) { - float * restrict aj = (float*) tilec->data; + float * OPJ_RESTRICT aj = (float*) tilec->data; int bufsize = (tilec->x1 - tilec->x0) * (tilec->y1 - tilec->y0); int j; diff --git a/indra/libopenjpeg/mct.c b/indra/libopenjpeg/mct.c index 870993b06d..d55a67062e 100644 --- a/indra/libopenjpeg/mct.c +++ b/indra/libopenjpeg/mct.c @@ -29,11 +29,16 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#define OPJ_SKIP_POISON +#include "opj_includes.h" + #ifdef __SSE__ #include #endif -#include "opj_includes.h" +#if defined(__GNUC__) +#pragma GCC poison malloc calloc realloc free +#endif /* */ /* This table contains the norms of the basis function of the reversible MCT. */ @@ -49,17 +54,38 @@ static const double mct_norms_real[3] = { 1.732, 1.805, 1.573 }; /* Foward reversible MCT. */ /* */ void mct_encode( - int* restrict c0, - int* restrict c1, - int* restrict c2, + int* OPJ_RESTRICT c0, + int* OPJ_RESTRICT c1, + int* OPJ_RESTRICT c2, int n) { - int i; - for(i = 0; i < n; ++i) { + int i = 0; +#ifdef __SSE2__ + /* Buffers are normally aligned on 16 bytes... */ + if (((size_t)c0 & 0xf) == 0 && ((size_t)c1 & 0xf) == 0 && ((size_t)c2 & 0xf) == 0) { + const int cnt = n & ~3U; + for (; i < cnt; i += 4) { + __m128i y, u, v; + __m128i r = _mm_load_si128((const __m128i*) & (c0[i])); + __m128i g = _mm_load_si128((const __m128i*) & (c1[i])); + __m128i b = _mm_load_si128((const __m128i*) & (c2[i])); + y = _mm_add_epi32(g, g); + y = _mm_add_epi32(y, b); + y = _mm_add_epi32(y, r); + y = _mm_srai_epi32(y, 2); + u = _mm_sub_epi32(b, g); + v = _mm_sub_epi32(r, g); + _mm_store_si128((__m128i*) & (c0[i]), y); + _mm_store_si128((__m128i*) & (c1[i]), u); + _mm_store_si128((__m128i*) & (c2[i]), v); + } + } +#endif + for (; i < n; ++i) { int r = c0[i]; int g = c1[i]; int b = c2[i]; - int y = (r + (g * 2) + b) >> 2; + int y = (r + g + g + b) >> 2; int u = b - g; int v = r - g; c0[i] = y; @@ -72,13 +98,32 @@ void mct_encode( /* Inverse reversible MCT. */ /* */ void mct_decode( - int* restrict c0, - int* restrict c1, - int* restrict c2, + int* OPJ_RESTRICT c0, + int* OPJ_RESTRICT c1, + int* OPJ_RESTRICT c2, int n) { - int i; - for (i = 0; i < n; ++i) { + int i = 0; +#ifdef __SSE2__ + /* Buffers are normally aligned on 16 bytes... */ + if (((size_t)c0 & 0xf) == 0 && ((size_t)c1 & 0xf) == 0 && ((size_t)c2 & 0xf) == 0) { + const int cnt = n & ~3U; + for (; i < cnt; i += 4) { + __m128i r, g, b; + __m128i y = _mm_load_si128((const __m128i*) & (c0[i])); + __m128i u = _mm_load_si128((const __m128i*) & (c1[i])); + __m128i v = _mm_load_si128((const __m128i*) & (c2[i])); + g = y; + g = _mm_sub_epi32(g, _mm_srai_epi32(_mm_add_epi32(u, v), 2)); + r = _mm_add_epi32(v, g); + b = _mm_add_epi32(u, g); + _mm_store_si128((__m128i*) & (c0[i]), r); + _mm_store_si128((__m128i*) & (c1[i]), g); + _mm_store_si128((__m128i*) & (c2[i]), b); +} + } +#endif + for (; i < n; ++i) { int y = c0[i]; int u = c1[i]; int v = c2[i]; @@ -102,13 +147,119 @@ double mct_getnorm(int compno) { /* Foward irreversible MCT. */ /* */ void mct_encode_real( - int* restrict c0, - int* restrict c1, - int* restrict c2, + int* OPJ_RESTRICT c0, + int* OPJ_RESTRICT c1, + int* OPJ_RESTRICT c2, int n) { - int i; - for(i = 0; i < n; ++i) { + int i = 0; +#ifdef __SSE4_1__ + /* Buffers are normally aligned on 16 bytes... */ + if (((size_t)c0 & 0xf) == 0 && ((size_t)c1 & 0xf) == 0 && ((size_t)c2 & 0xf) == 0) { + const int cnt = n & ~3U; + const __m128i ry = _mm_set1_epi32(2449); + const __m128i gy = _mm_set1_epi32(4809); + const __m128i by = _mm_set1_epi32(934); + const __m128i ru = _mm_set1_epi32(1382); + const __m128i gu = _mm_set1_epi32(2714); + const __m128i gv = _mm_set1_epi32(3430); + const __m128i bv = _mm_set1_epi32(666); + const __m128i mulround = _mm_shuffle_epi32(_mm_cvtsi32_si128(4096), _MM_SHUFFLE(1, 0, 1, 0)); + for (; i < cnt; i += 4) { + __m128i lo, hi, y, u, v; + __m128i r = _mm_load_si128((const __m128i*) & (c0[i])); + __m128i g = _mm_load_si128((const __m128i*) & (c1[i])); + __m128i b = _mm_load_si128((const __m128i*) & (c2[i])); + + hi = _mm_shuffle_epi32(r, _MM_SHUFFLE(3, 3, 1, 1)); + lo = _mm_mul_epi32(r, ry); + hi = _mm_mul_epi32(hi, ry); + lo = _mm_add_epi64(lo, mulround); + hi = _mm_add_epi64(hi, mulround); + lo = _mm_srli_epi64(lo, 13); + hi = _mm_slli_epi64(hi, 32 - 13); + y = _mm_blend_epi16(lo, hi, 0xCC); + + hi = _mm_shuffle_epi32(g, _MM_SHUFFLE(3, 3, 1, 1)); + lo = _mm_mul_epi32(g, gy); + hi = _mm_mul_epi32(hi, gy); + lo = _mm_add_epi64(lo, mulround); + hi = _mm_add_epi64(hi, mulround); + lo = _mm_srli_epi64(lo, 13); + hi = _mm_slli_epi64(hi, 32 - 13); + y = _mm_add_epi32(y, _mm_blend_epi16(lo, hi, 0xCC)); + + hi = _mm_shuffle_epi32(b, _MM_SHUFFLE(3, 3, 1, 1)); + lo = _mm_mul_epi32(b, by); + hi = _mm_mul_epi32(hi, by); + lo = _mm_add_epi64(lo, mulround); + hi = _mm_add_epi64(hi, mulround); + lo = _mm_srli_epi64(lo, 13); + hi = _mm_slli_epi64(hi, 32 - 13); + y = _mm_add_epi32(y, _mm_blend_epi16(lo, hi, 0xCC)); + _mm_store_si128((__m128i*) & (c0[i]), y); + + lo = _mm_cvtepi32_epi64(_mm_shuffle_epi32(b, _MM_SHUFFLE(3, 2, 2, 0))); + hi = _mm_cvtepi32_epi64(_mm_shuffle_epi32(b, _MM_SHUFFLE(3, 2, 3, 1))); + lo = _mm_slli_epi64(lo, 12); + hi = _mm_slli_epi64(hi, 12); + lo = _mm_add_epi64(lo, mulround); + hi = _mm_add_epi64(hi, mulround); + lo = _mm_srli_epi64(lo, 13); + hi = _mm_slli_epi64(hi, 32 - 13); + u = _mm_blend_epi16(lo, hi, 0xCC); + + hi = _mm_shuffle_epi32(r, _MM_SHUFFLE(3, 3, 1, 1)); + lo = _mm_mul_epi32(r, ru); + hi = _mm_mul_epi32(hi, ru); + lo = _mm_add_epi64(lo, mulround); + hi = _mm_add_epi64(hi, mulround); + lo = _mm_srli_epi64(lo, 13); + hi = _mm_slli_epi64(hi, 32 - 13); + u = _mm_sub_epi32(u, _mm_blend_epi16(lo, hi, 0xCC)); + + hi = _mm_shuffle_epi32(g, _MM_SHUFFLE(3, 3, 1, 1)); + lo = _mm_mul_epi32(g, gu); + hi = _mm_mul_epi32(hi, gu); + lo = _mm_add_epi64(lo, mulround); + hi = _mm_add_epi64(hi, mulround); + lo = _mm_srli_epi64(lo, 13); + hi = _mm_slli_epi64(hi, 32 - 13); + u = _mm_sub_epi32(u, _mm_blend_epi16(lo, hi, 0xCC)); + _mm_store_si128((__m128i*) & (c1[i]), u); + + lo = _mm_cvtepi32_epi64(_mm_shuffle_epi32(r, _MM_SHUFFLE(3, 2, 2, 0))); + hi = _mm_cvtepi32_epi64(_mm_shuffle_epi32(r, _MM_SHUFFLE(3, 2, 3, 1))); + lo = _mm_slli_epi64(lo, 12); + hi = _mm_slli_epi64(hi, 12); + lo = _mm_add_epi64(lo, mulround); + hi = _mm_add_epi64(hi, mulround); + lo = _mm_srli_epi64(lo, 13); + hi = _mm_slli_epi64(hi, 32 - 13); + v = _mm_blend_epi16(lo, hi, 0xCC); + + hi = _mm_shuffle_epi32(g, _MM_SHUFFLE(3, 3, 1, 1)); + lo = _mm_mul_epi32(g, gv); + hi = _mm_mul_epi32(hi, gv); + lo = _mm_add_epi64(lo, mulround); + hi = _mm_add_epi64(hi, mulround); + lo = _mm_srli_epi64(lo, 13); + hi = _mm_slli_epi64(hi, 32 - 13); + v = _mm_sub_epi32(v, _mm_blend_epi16(lo, hi, 0xCC)); + + hi = _mm_shuffle_epi32(b, _MM_SHUFFLE(3, 3, 1, 1)); + lo = _mm_mul_epi32(b, bv); + hi = _mm_mul_epi32(hi, bv); + lo = _mm_add_epi64(lo, mulround); + hi = _mm_add_epi64(hi, mulround); + lo = _mm_srli_epi64(lo, 13); + hi = _mm_slli_epi64(hi, 32 - 13); + v = _mm_sub_epi32(v, _mm_blend_epi16(lo, hi, 0xCC)); + _mm_store_si128((__m128i*) & (c2[i]), v); + } + } +#endif + for (; i < n; ++i) { int r = c0[i]; int g = c1[i]; int b = c2[i]; @@ -125,19 +276,21 @@ void mct_encode_real( /* Inverse irreversible MCT. */ /* */ void mct_decode_real( - float* restrict c0, - float* restrict c1, - float* restrict c2, + float* OPJ_RESTRICT c0, + float* OPJ_RESTRICT c1, + float* OPJ_RESTRICT c2, int n) { int i; #ifdef __SSE__ + int count; __m128 vrv, vgu, vgv, vbu; vrv = _mm_set1_ps(1.402f); vgu = _mm_set1_ps(0.34413f); vgv = _mm_set1_ps(0.71414f); vbu = _mm_set1_ps(1.772f); - for (i = 0; i < (n >> 3); ++i) { + count = n >> 3; + for (i = 0; i < count; ++i) { __m128 vy, vu, vv; __m128 vr, vg, vb; @@ -174,7 +327,7 @@ void mct_decode_real( float u = c1[i]; float v = c2[i]; float r = y + (v * 1.402f); - float g = y - (u * 0.34413f) - (v * (0.71414f)); + float g = y - (u * 0.34413f) - (v * 0.71414f); float b = y + (u * 1.772f); c0[i] = r; c1[i] = g; diff --git a/indra/libopenjpeg/openjpeg.h b/indra/libopenjpeg/openjpeg.h index 59147c8b3d..ba88114154 100644 --- a/indra/libopenjpeg/openjpeg.h +++ b/indra/libopenjpeg/openjpeg.h @@ -40,33 +40,71 @@ ========================================================== */ +/* +The inline keyword is supported by C99 but not by C90. +Most compilers implement their own version of this keyword ... +*/ +#ifndef INLINE +#if defined(_MSC_VER) +#define INLINE __forceinline +#elif defined(__GNUC__) +#define INLINE __inline__ +#elif defined(__MWERKS__) +#define INLINE inline +#else +/* add other compilers here ... */ +#define INLINE +#endif /* defined() */ +#endif /* INLINE */ #if defined(OPJ_STATIC) || !defined(_WIN32) #define OPJ_API #define OPJ_CALLCONV #else #define OPJ_CALLCONV __stdcall /* -The following ifdef block is the standard way of creating macros which make exporting +The following ifdef block is the standard way of creating macros which make exporting from a DLL simpler. All files within this DLL are compiled with the OPJ_EXPORTS symbol defined on the command line. this symbol should not be defined on any project -that uses this DLL. This way any other project whose source files include this file see -OPJ_API functions as being imported from a DLL, wheras this DLL sees symbols +that uses this DLL. This way any other project whose source files include this file see +OPJ_API functions as being imported from a DLL, whereas this DLL sees symbols defined with this macro as being exported. */ -#if defined(OPJ_EXPORTS) || defined(DLL_EXPORT) -#define OPJ_API __declspec(dllexport) -#else -#define OPJ_API __declspec(dllimport) -#endif /* OPJ_EXPORTS */ +# if defined(OPJ_EXPORTS) || defined(DLL_EXPORT) +# define OPJ_API __declspec(dllexport) +# else +# define OPJ_API __declspec(dllimport) +# endif /* OPJ_EXPORTS */ #endif /* !OPJ_STATIC || !_WIN32 */ typedef int opj_bool; #define OPJ_TRUE 1 #define OPJ_FALSE 0 +typedef char OPJ_CHAR; +typedef float OPJ_FLOAT32; +typedef double OPJ_FLOAT64; +typedef unsigned char OPJ_BYTE; + +#include "opj_stdint.h" + +typedef int8_t OPJ_INT8; +typedef uint8_t OPJ_UINT8; +typedef int16_t OPJ_INT16; +typedef uint16_t OPJ_UINT16; +typedef int32_t OPJ_INT32; +typedef uint32_t OPJ_UINT32; +typedef int64_t OPJ_INT64; +typedef uint64_t OPJ_UINT64; + +typedef int64_t OPJ_OFF_T; /* 64-bit file offset type */ + +#include +typedef size_t OPJ_SIZE_T; + /* Avoid compile-time warning because parameter is not used */ #define OPJ_ARG_NOT_USED(x) (void)(x) -/* + +/* ========================================================== Useful constant definitions ========================================================== diff --git a/indra/libopenjpeg/opj_includes.h b/indra/libopenjpeg/opj_includes.h index 2b5866a999..e4d2374da0 100644 --- a/indra/libopenjpeg/opj_includes.h +++ b/indra/libopenjpeg/opj_includes.h @@ -40,6 +40,8 @@ #include #include #include +#include +#include /* ========================================================== @@ -54,56 +56,115 @@ ========================================================== */ +/* Are restricted pointers available? (C99) */ +#if (__STDC_VERSION__ >= 199901L) +#define OPJ_RESTRICT restrict +#else +/* Not a C99 compiler */ +#if defined(__GNUC__) +#define OPJ_RESTRICT __restrict__ +#elif defined(_MSC_VER) && (_MSC_VER >= 1400) +#define OPJ_RESTRICT __restrict +#else +#define OPJ_RESTRICT /* restrict */ +#endif +#endif + /* Ignore GCC attributes if this is not GCC */ #ifndef __GNUC__ #define __attribute__(x) /* __attribute__(x) */ #endif -/* -The inline keyword is supported by C99 but not by C90. -Most compilers implement their own version of this keyword ... -*/ -#ifndef INLINE - #if defined(_MSC_VER) - #define INLINE __forceinline - #elif defined(__GNUC__) - #define INLINE __inline__ - #elif defined(__MWERKS__) - #define INLINE inline - #else - /* add other compilers here ... */ - #define INLINE - #endif /* defined() */ -#endif /* INLINE */ -/* Are restricted pointers available? (C99) */ -#if (__STDC_VERSION__ != 199901L) - /* Not a C99 compiler */ - #ifdef __GNUC__ - #define restrict __restrict__ - #else - #define restrict /* restrict */ - #endif -#endif +/* MSVC before 2013 and Borland C do not have lrintf */ +#if defined(_MSC_VER) +#include +static INLINE long opj_lrintf(float f) +{ +#ifdef _M_X64 + return _mm_cvt_ss2si(_mm_load_ss(&f)); -/* MSVC and Borland C do not have lrintf */ -#if defined(_MSC_VER) || defined(__BORLANDC__) -static INLINE long lrintf(float f){ + /* commented out line breaks many tests */ + /* return (long)((f>0.0f) ? (f + 0.5f):(f -0.5f)); */ +#elif defined(_M_IX86) + int i; + _asm{ + fld f + fistp i + }; + + return i; +#else + return (long)((f>0.0f) ? (f + 0.5f) : (f - 0.5f)); +#endif +} +#elif defined(__BORLANDC__) +static INLINE long opj_lrintf(float f) +{ #ifdef _M_X64 - return (long)((f>0.0f) ? (f + 0.5f):(f -0.5f)); + return (long)((f > 0.0f) ? (f + 0.5f) : (f - 0.5f)); #else int i; - - _asm{ + + _asm { fld f fistp i }; - + return i; #endif } +#else +static INLINE long opj_lrintf(float f) +{ + return lrintf(f); +} +#endif + +#if defined(_MSC_VER) && (_MSC_VER < 1400) +#define vsnprintf _vsnprintf +#endif + +/* MSVC x86 is really bad at doing int64 = int32 * int32 on its own. Use intrinsic. */ +#if defined(_MSC_VER) && (_MSC_VER >= 1400) && !defined(__INTEL_COMPILER) && defined(_M_IX86) +# include +# pragma intrinsic(__emul) +#endif + +/* Apparently Visual Studio doesn't define __SSE__ / __SSE2__ macros */ +#if defined(_M_X64) +/* Intel 64bit support SSE and SSE2 */ +# ifndef __SSE__ +# define __SSE__ 1 +# endif +# ifndef __SSE2__ +# define __SSE2__ 1 +# endif +# if !defined(__SSE4_1__) && defined(__AVX__) +# define __SSE4_1__ 1 +# endif #endif +/* For x86, test the value of the _M_IX86_FP macro. */ +/* See https://msdn.microsoft.com/en-us/library/b0084kay.aspx */ +#if defined(_M_IX86_FP) +# if _M_IX86_FP >= 1 +# ifndef __SSE__ +# define __SSE__ 1 +# endif +# endif +# if _M_IX86_FP >= 2 +# ifndef __SSE2__ +# define __SSE2__ 1 +# endif +# endif +#endif + +/* Type to use for bit-fields in internal headers */ +typedef unsigned int OPJ_BITFIELD; + +#define OPJ_UNUSED(x) (void)x + #include "j2k_lib.h" #include "opj_malloc.h" #include "event.h" diff --git a/indra/libopenjpeg/opj_malloc.c b/indra/libopenjpeg/opj_malloc.c new file mode 100644 index 0000000000..dca91bfcbe --- /dev/null +++ b/indra/libopenjpeg/opj_malloc.c @@ -0,0 +1,249 @@ +/* + * The copyright in this software is being made available under the 2-clauses + * BSD License, included below. This software may be subject to other third + * party and contributor rights, including patent rights, and no such rights + * are granted under this license. + * + * Copyright (c) 2015, Mathieu Malaterre + * Copyright (c) 2015, Matthieu Darbois + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#define OPJ_SKIP_POISON +#include "opj_includes.h" + +#if defined(OPJ_HAVE_MALLOC_H) && defined(OPJ_HAVE_MEMALIGN) +# include +#endif + +#ifndef SIZE_MAX +# define SIZE_MAX ((size_t) -1) +#endif + +static INLINE void *opj_aligned_alloc_n(size_t alignment, size_t size) +{ + void* ptr; + + /* alignment shall be power of 2 */ + assert((alignment != 0U) && ((alignment & (alignment - 1U)) == 0U)); + /* alignment shall be at least sizeof(void*) */ + assert(alignment >= sizeof(void*)); + + if (size == 0U) { /* prevent implementation defined behavior of realloc */ + return NULL; + } + +#if defined(OPJ_HAVE_POSIX_MEMALIGN) + /* aligned_alloc requires c11, restrict to posix_memalign for now. Quote: + * This function was introduced in POSIX 1003.1d. Although this function is + * superseded by aligned_alloc, it is more portable to older POSIX systems + * that do not support ISO C11. */ + if (posix_memalign(&ptr, alignment, size)) { + ptr = NULL; + } + /* older linux */ +#elif defined(OPJ_HAVE_MEMALIGN) + ptr = memalign(alignment, size); + /* _MSC_VER */ +#elif defined(OPJ_HAVE__ALIGNED_MALLOC) + ptr = _aligned_malloc(size, alignment); +#else + /* + * Generic aligned malloc implementation. + * Uses size_t offset for the integer manipulation of the pointer, + * as uintptr_t is not available in C89 to do + * bitwise operations on the pointer itself. + */ + alignment--; + { + size_t offset; + OPJ_UINT8 *mem; + + /* Room for padding and extra pointer stored in front of allocated area */ + size_t overhead = alignment + sizeof(void *); + + /* let's be extra careful */ + assert(alignment <= (SIZE_MAX - sizeof(void *))); + + /* Avoid integer overflow */ + if (size > (SIZE_MAX - overhead)) { + return NULL; + } + + mem = (OPJ_UINT8*)malloc(size + overhead); + if (mem == NULL) { + return mem; + } + /* offset = ((alignment + 1U) - ((size_t)(mem + sizeof(void*)) & alignment)) & alignment; */ + /* Use the fact that alignment + 1U is a power of 2 */ + offset = ((alignment ^ ((size_t)(mem + sizeof(void*)) & alignment)) + 1U) & + alignment; + ptr = (void *)(mem + sizeof(void*) + offset); + ((void**) ptr)[-1] = mem; + } +#endif + return ptr; +} +static INLINE void *opj_aligned_realloc_n(void *ptr, size_t alignment, + size_t new_size) +{ + void *r_ptr; + + /* alignment shall be power of 2 */ + assert((alignment != 0U) && ((alignment & (alignment - 1U)) == 0U)); + /* alignment shall be at least sizeof(void*) */ + assert(alignment >= sizeof(void*)); + + if (new_size == 0U) { /* prevent implementation defined behavior of realloc */ + return NULL; + } + + /* no portable aligned realloc */ +#if defined(OPJ_HAVE_POSIX_MEMALIGN) || defined(OPJ_HAVE_MEMALIGN) + /* glibc doc states one can mix aligned malloc with realloc */ + r_ptr = realloc(ptr, new_size); /* fast path */ + /* we simply use `size_t` to cast, since we are only interest in binary AND + * operator */ + if (((size_t)r_ptr & (alignment - 1U)) != 0U) { + /* this is non-trivial to implement a portable aligned realloc, so use a + * simple approach where we do not need a function that return the size of an + * allocated array (eg. _msize on Windows, malloc_size on MacOS, + * malloc_usable_size on systems with glibc) */ + void *a_ptr = opj_aligned_alloc_n(alignment, new_size); + if (a_ptr != NULL) { + memcpy(a_ptr, r_ptr, new_size); + } + free(r_ptr); + r_ptr = a_ptr; + } + /* _MSC_VER */ +#elif defined(OPJ_HAVE__ALIGNED_MALLOC) + r_ptr = _aligned_realloc(ptr, new_size, alignment); +#else + if (ptr == NULL) { + return opj_aligned_alloc_n(alignment, new_size); + } + alignment--; + { + void *oldmem; + OPJ_UINT8 *newmem; + size_t overhead = alignment + sizeof(void *); + + /* let's be extra careful */ + assert(alignment <= (SIZE_MAX - sizeof(void *))); + + /* Avoid integer overflow */ + if (new_size > SIZE_MAX - overhead) { + return NULL; + } + + oldmem = ((void**) ptr)[-1]; + newmem = (OPJ_UINT8*)realloc(oldmem, new_size + overhead); + if (newmem == NULL) { + return newmem; + } + + if (newmem == oldmem) { + r_ptr = ptr; + } else { + size_t old_offset; + size_t new_offset; + + /* realloc created a new copy, realign the copied memory block */ + old_offset = (size_t)((OPJ_UINT8*)ptr - (OPJ_UINT8*)oldmem); + + /* offset = ((alignment + 1U) - ((size_t)(mem + sizeof(void*)) & alignment)) & alignment; */ + /* Use the fact that alignment + 1U is a power of 2 */ + new_offset = ((alignment ^ ((size_t)(newmem + sizeof(void*)) & alignment)) + + 1U) & alignment; + new_offset += sizeof(void*); + r_ptr = (void *)(newmem + new_offset); + + if (new_offset != old_offset) { + memmove(newmem + new_offset, newmem + old_offset, new_size); + } + ((void**) r_ptr)[-1] = newmem; + } + } +#endif + return r_ptr; +} +void * opj_malloc(size_t size) +{ + if (size == 0U) { /* prevent implementation defined behavior of realloc */ + return NULL; + } + return malloc(size); +} +void * opj_calloc(size_t num, size_t size) +{ + if (num == 0 || size == 0) { + /* prevent implementation defined behavior of realloc */ + return NULL; + } + return calloc(num, size); +} + +void *opj_aligned_malloc(size_t size) +{ + return opj_aligned_alloc_n(16U, size); +} +void * opj_aligned_realloc(void *ptr, size_t size) +{ + return opj_aligned_realloc_n(ptr, 16U, size); +} + +void *opj_aligned_32_malloc(size_t size) +{ + return opj_aligned_alloc_n(32U, size); +} +void * opj_aligned_32_realloc(void *ptr, size_t size) +{ + return opj_aligned_realloc_n(ptr, 32U, size); +} + +void opj_aligned_free(void* ptr) +{ +#if defined(OPJ_HAVE_POSIX_MEMALIGN) || defined(OPJ_HAVE_MEMALIGN) + free(ptr); +#elif defined(OPJ_HAVE__ALIGNED_MALLOC) + _aligned_free(ptr); +#else + /* Generic implementation has malloced pointer stored in front of used area */ + if (ptr != NULL) { + free(((void**) ptr)[-1]); + } +#endif +} + +void * opj_realloc(void *ptr, size_t new_size) +{ + if (new_size == 0U) { /* prevent implementation defined behavior of realloc */ + return NULL; + } + return realloc(ptr, new_size); +} +void opj_free(void *ptr) +{ + free(ptr); +} diff --git a/indra/libopenjpeg/opj_malloc.h b/indra/libopenjpeg/opj_malloc.h index aef2ee3b8c..4eacfa152d 100644 --- a/indra/libopenjpeg/opj_malloc.h +++ b/indra/libopenjpeg/opj_malloc.h @@ -1,4 +1,9 @@ /* + * The copyright in this software is being made available under the 2-clauses + * BSD License, included below. This software may be subject to other third + * party and contributor rights, including patent rights, and no such rights + * are granted under this license. + * * Copyright (c) 2005, Herve Drolon, FreeImage Team * Copyright (c) 2007, Callum Lerwick * All rights reserved. @@ -24,8 +29,10 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ -#ifndef __OPJ_MALLOC_H -#define __OPJ_MALLOC_H +#ifndef OPJ_MALLOC_H +#define OPJ_MALLOC_H + +#include /** @file opj_malloc.h @brief Internal functions @@ -36,6 +43,17 @@ The functions in opj_malloc.h are internal utilities used for memory management. /** @defgroup MISC MISC - Miscellaneous internal functions */ /*@{*/ +/* FIXME: These should be set with cmake tests, but we're currently not requiring use of cmake */ +#ifdef _WIN32 +#define OPJ_HAVE__ALIGNED_MALLOC +#else /* Not _WIN32 */ +#if defined(__sun) +#define OPJ_HAVE_MEMALIGN +#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) +#define OPJ_HAVE_POSIX_MEMALIGN +#endif +#endif + /** @name Exported functions */ /*@{*/ /* ----------------------------------------------------------------------- */ @@ -45,90 +63,32 @@ Allocate an uninitialized memory block @param size Bytes to allocate @return Returns a void pointer to the allocated space, or NULL if there is insufficient memory available */ -#ifdef ALLOC_PERF_OPT -void * OPJ_CALLCONV opj_malloc(size_t size); -#else -#define opj_malloc(size) malloc(size) -#endif +void * opj_malloc(size_t size); /** Allocate a memory block with elements initialized to 0 -@param num Blocks to allocate -@param size Bytes per block to allocate +@param numOfElements Blocks to allocate +@param sizeOfElements Bytes per block to allocate @return Returns a void pointer to the allocated space, or NULL if there is insufficient memory available */ -#ifdef ALLOC_PERF_OPT -void * OPJ_CALLCONV opj_calloc(size_t _NumOfElements, size_t _SizeOfElements); -#else -#define opj_calloc(num, size) calloc(num, size) -#endif +void * opj_calloc(size_t numOfElements, size_t sizeOfElements); /** -Allocate memory aligned to a 16 byte boundry +Allocate memory aligned to a 16 byte boundary @param size Bytes to allocate @return Returns a void pointer to the allocated space, or NULL if there is insufficient memory available */ -/* FIXME: These should be set with cmake tests, but we're currently not requiring use of cmake */ -#ifdef _WIN32 - /* Someone should tell the mingw people that their malloc.h ought to provide _mm_malloc() */ - #ifdef __GNUC__ - #include - #define HAVE_MM_MALLOC - #else /* MSVC, Intel C++ */ - #include - #ifdef _mm_malloc - #define HAVE_MM_MALLOC - #endif - #endif -#else /* Not _WIN32 */ - #if defined(__sun) - #define HAVE_MEMALIGN - #elif defined(__FreeBSD__) - #define HAVE_POSIX_MEMALIGN - /* Linux x86_64 and OSX always align allocations to 16 bytes */ - #elif !defined(__amd64__) && !defined(__APPLE__) && !defined(_AIX) - #define HAVE_MEMALIGN - #include - #endif -#endif +void * opj_aligned_malloc(size_t size); +void * opj_aligned_realloc(void *ptr, size_t size); +void opj_aligned_free(void* ptr); -#define opj_aligned_malloc(size) malloc(size) -#define opj_aligned_free(m) free(m) - -#ifdef HAVE_MM_MALLOC - #undef opj_aligned_malloc - #define opj_aligned_malloc(size) _mm_malloc(size, 16) - #undef opj_aligned_free - #define opj_aligned_free(m) _mm_free(m) -#endif - -#ifdef HAVE_MEMALIGN - extern void* memalign(size_t, size_t); - #undef opj_aligned_malloc - #define opj_aligned_malloc(size) memalign(16, (size)) - #undef opj_aligned_free - #define opj_aligned_free(m) free(m) -#endif - -#ifdef HAVE_POSIX_MEMALIGN - #undef opj_aligned_malloc - extern int posix_memalign(void**, size_t, size_t); - - static INLINE void* __attribute__ ((malloc)) opj_aligned_malloc(size_t size){ - void* mem = NULL; - posix_memalign(&mem, 16, size); - return mem; - } - #undef opj_aligned_free - #define opj_aligned_free(m) free(m) -#endif - -#ifdef ALLOC_PERF_OPT - #undef opj_aligned_malloc - #define opj_aligned_malloc(size) opj_malloc(size) - #undef opj_aligned_free - #define opj_aligned_free(m) opj_free(m) -#endif +/** +Allocate memory aligned to a 32 byte boundary +@param size Bytes to allocate +@return Returns a void pointer to the allocated space, or NULL if there is insufficient memory available +*/ +void * opj_aligned_32_malloc(size_t size); +void * opj_aligned_32_realloc(void *ptr, size_t size); /** Reallocate memory blocks. @@ -136,23 +96,15 @@ Reallocate memory blocks. @param s New size in bytes @return Returns a void pointer to the reallocated (and possibly moved) memory block */ -#ifdef ALLOC_PERF_OPT -void * OPJ_CALLCONV opj_realloc(void * m, size_t s); -#else -#define opj_realloc(m, s) realloc(m, s) -#endif +void * opj_realloc(void * m, size_t s); /** Deallocates or frees a memory block. @param m Previously allocated memory block to be freed */ -#ifdef ALLOC_PERF_OPT -void OPJ_CALLCONV opj_free(void * m); -#else -#define opj_free(m) free(m) -#endif +void opj_free(void * m); -#ifdef __GNUC__ +#if defined(__GNUC__) && !defined(OPJ_SKIP_POISON) #pragma GCC poison malloc calloc realloc free #endif @@ -161,5 +113,5 @@ void OPJ_CALLCONV opj_free(void * m); /*@}*/ -#endif /* __OPJ_MALLOC_H */ +#endif /* OPJ_MALLOC_H */ diff --git a/indra/libopenjpeg/opj_stdint.h b/indra/libopenjpeg/opj_stdint.h new file mode 100644 index 0000000000..337ad85001 --- /dev/null +++ b/indra/libopenjpeg/opj_stdint.h @@ -0,0 +1,51 @@ +/* + * The copyright in this software is being made available under the 2-clauses + * BSD License, included below. This software may be subject to other third + * party and contributor rights, including patent rights, and no such rights + * are granted under this license. + * + * Copyright (c) 2012, Mathieu Malaterre + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef OPJ_STDINT_H +#define OPJ_STDINT_H + +#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || _MSC_VER >= 1900 +#include +#else +#if defined(_WIN32) +typedef signed __int8 int8_t; +typedef unsigned __int8 uint8_t; +typedef signed __int16 int16_t; +typedef unsigned __int16 uint16_t; +typedef signed __int32 int32_t; +typedef unsigned __int32 uint32_t; +typedef signed __int64 int64_t; +typedef unsigned __int64 uint64_t; +#else +#error unsupported platform +#endif +#endif + +#endif /* OPJ_STDINT_H */ diff --git a/indra/libopenjpeg/t1.c b/indra/libopenjpeg/t1.c index 93b997b799..6cb8acad15 100644 --- a/indra/libopenjpeg/t1.c +++ b/indra/libopenjpeg/t1.c @@ -1427,7 +1427,7 @@ void t1_encode_cblks( opj_tcd_resolution_t *res = &tilec->resolutions[resno]; for (bandno = 0; bandno < res->numbands; ++bandno) { - opj_tcd_band_t* restrict band = &res->bands[bandno]; + opj_tcd_band_t* OPJ_RESTRICT band = &res->bands[bandno]; int bandconst = 8192 * 8192 / ((int) floor(band->stepsize * 8192)); for (precno = 0; precno < res->pw * res->ph; ++precno) { @@ -1435,8 +1435,8 @@ void t1_encode_cblks( for (cblkno = 0; cblkno < prc->cw * prc->ch; ++cblkno) { opj_tcd_cblk_enc_t* cblk = &prc->cblks.enc[cblkno]; - int* restrict datap; - int* restrict tiledp; + int* OPJ_RESTRICT datap; + int* OPJ_RESTRICT tiledp; int cblk_w; int cblk_h; int i, j; @@ -1517,14 +1517,14 @@ void t1_decode_cblks( opj_tcd_resolution_t* res = &tilec->resolutions[resno]; for (bandno = 0; bandno < res->numbands; ++bandno) { - opj_tcd_band_t* restrict band = &res->bands[bandno]; + opj_tcd_band_t* OPJ_RESTRICT band = &res->bands[bandno]; for (precno = 0; precno < res->pw * res->ph; ++precno) { opj_tcd_precinct_t* precinct = &band->precincts[precno]; for (cblkno = 0; cblkno < precinct->cw * precinct->ch; ++cblkno) { opj_tcd_cblk_dec_t* cblk = &precinct->cblks.dec[cblkno]; - int* restrict datap; + int* OPJ_RESTRICT datap; int cblk_w, cblk_h; int x, y; int i, j; @@ -1566,7 +1566,7 @@ void t1_decode_cblks( } if (tccp->qmfbid == 1) { - int* restrict tiledp = &tilec->data[(y * tile_w) + x]; + int* OPJ_RESTRICT tiledp = &tilec->data[(y * tile_w) + x]; for (j = 0; j < cblk_h; ++j) { for (i = 0; i < cblk_w; ++i) { int tmp = datap[(j * cblk_w) + i]; @@ -1574,9 +1574,9 @@ void t1_decode_cblks( } } } else { /* if (tccp->qmfbid == 0) */ - float* restrict tiledp = (float*) &tilec->data[(y * tile_w) + x]; + float* OPJ_RESTRICT tiledp = (float*) &tilec->data[(y * tile_w) + x]; for (j = 0; j < cblk_h; ++j) { - float* restrict tiledp2 = tiledp; + float* OPJ_RESTRICT tiledp2 = tiledp; for (i = 0; i < cblk_w; ++i) { float tmp = *datap * band->stepsize; *tiledp2 = tmp; diff --git a/indra/libopenjpeg/t1_generate_luts.c b/indra/libopenjpeg/t1_generate_luts.c index 39880414fb..605709125a 100644 --- a/indra/libopenjpeg/t1_generate_luts.c +++ b/indra/libopenjpeg/t1_generate_luts.c @@ -194,7 +194,7 @@ int main(){ printf("/* This file was automatically generated by t1_generate_luts.c */\n\n"); - // lut_ctxno_zc + /* lut_ctxno_zc */ for (j = 0; j < 4; ++j) { for (i = 0; i < 256; ++i) { int orient = j; @@ -215,7 +215,7 @@ int main(){ } printf("%i\n};\n\n", lut_ctxno_zc[1023]); - // lut_ctxno_sc + /* lut_ctxno_sc */ printf("static char lut_ctxno_sc[256] = {\n "); for (i = 0; i < 255; ++i) { printf("0x%x, ", t1_init_ctxno_sc(i << 4)); @@ -224,7 +224,7 @@ int main(){ } printf("0x%x\n};\n\n", t1_init_ctxno_sc(255 << 4)); - // lut_spb + /* lut_spb */ printf("static char lut_spb[256] = {\n "); for (i = 0; i < 255; ++i) { printf("%i, ", t1_init_spb(i << 4)); diff --git a/indra/libopenjpeg/t2.c b/indra/libopenjpeg/t2.c index cae29f09b1..2585c3d56a 100644 --- a/indra/libopenjpeg/t2.c +++ b/indra/libopenjpeg/t2.c @@ -30,6 +30,7 @@ */ #include "opj_includes.h" +#include /** @defgroup T2 T2 - Implementation of a tier-2 coding */ /*@{*/ @@ -340,13 +341,15 @@ static int t2_decode_packet(opj_t2_t* t2, unsigned char *src, int len, opj_tcd_t int precno = pi->precno; /* precinct value */ int layno = pi->layno; /* quality layer value */ - opj_tcd_resolution_t* res = &tile->comps[compno].resolutions[resno]; - unsigned char *hd = NULL; int present; opj_bio_t *bio = NULL; /* BIO component */ - + + opj_tcd_resolution_t* res; + assert(&tile->comps[compno] != NULL); + res = &tile->comps[compno].resolutions[resno]; + if (layno == 0) { for (bandno = 0; bandno < res->numbands; bandno++) { opj_tcd_band_t *band = &res->bands[bandno]; diff --git a/indra/libopenjpeg/tcd.c b/indra/libopenjpeg/tcd.c index c19b3eb6a9..4ced7aaff3 100644 --- a/indra/libopenjpeg/tcd.c +++ b/indra/libopenjpeg/tcd.c @@ -1507,7 +1507,7 @@ opj_bool tcd_decode_tile(opj_tcd_t *tcd, unsigned char *src, int len, int tileno for(j = res->y0; j < res->y1; ++j) { for(i = res->x0; i < res->x1; ++i) { float tmp = ((float*)tilec->data)[i - res->x0 + (j - res->y0) * tw]; - int v = lrintf(tmp); + int v = opj_lrintf(tmp); v += adjust; imagec->data[(i - offset_x) + (j - offset_y) * w] = int_clamp(v, min, max); } diff --git a/indra/libpathing/CMakeLists.txt b/indra/libpathing/CMakeLists.txt index 35086c7160..aefe1a2acd 100644 --- a/indra/libpathing/CMakeLists.txt +++ b/indra/libpathing/CMakeLists.txt @@ -30,5 +30,8 @@ set_source_files_properties(${libpathing_HEADER_FILES} PROPERTIES HEADER_FILE_ONLY TRUE) add_library(nd_Pathing STATIC ${libpathing_SOURCE_FILES} ${libpathing_HEADER_FILES} ) -add_dependencies(nd_Pathing prepare) +target_link_libraries(nd_Pathing + PUBLIC + llcommon +) diff --git a/indra/libpathing/llpathinglib.cpp b/indra/libpathing/llpathinglib.cpp index 19c0bff0ff..041311de9a 100644 --- a/indra/libpathing/llpathinglib.cpp +++ b/indra/libpathing/llpathinglib.cpp @@ -1,4 +1,3 @@ -#include "sys.h" #include "llpathinglib.h" void LLPathingLib::initSystem() diff --git a/indra/linux_crash_logger/CMakeLists.txt b/indra/linux_crash_logger/CMakeLists.txt deleted file mode 100644 index d885e37043..0000000000 --- a/indra/linux_crash_logger/CMakeLists.txt +++ /dev/null @@ -1,72 +0,0 @@ -# -*- cmake -*- - -project(linux_crash_logger) - -include(00-Common) -include(LLCommon) -include(LLCrashLogger) -include(LLMath) -include(LLMessage) -include(LLVFS) -include(LLXML) -include(Linking) -include(UI) - -include_directories( - ${LLCOMMON_INCLUDE_DIRS} - ${LLCRASHLOGGER_INCLUDE_DIRS} - ${LLMATH_INCLUDE_DIRS} - ${LLVFS_INCLUDE_DIRS} - ${LLXML_INCLUDE_DIRS} - ) - -set(linux_crash_logger_SOURCE_FILES - linux_crash_logger.cpp - llcrashloggerlinux.cpp - ) - -set(linux_crash_logger_HEADER_FILES - CMakeLists.txt - - llcrashloggerlinux.h - ) - -set_source_files_properties(${linux_crash_logger_HEADER_FILES} - PROPERTIES HEADER_FILE_ONLY TRUE) - -list(APPEND linux_crash_logger_SOURCE_FILES - ${linux_crash_logger_HEADER_FILES} - ) - -set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--as-needed") - -add_executable(linux-crash-logger ${linux_crash_logger_SOURCE_FILES}) - -target_link_libraries(linux-crash-logger - ${LLCRASHLOGGER_LIBRARIES} - ${LLVFS_LIBRARIES} - ${LLXML_LIBRARIES} - ${LLMESSAGE_LIBRARIES} - ${LLUI_LIBRARIES} - ${LLVFS_LIBRARIES} - ${LLMATH_LIBRARIES} - ${LLCOMMON_LIBRARIES} - ${UI_LIBRARIES} - ${DB_LIBRARIES} - ${XMLRPCEPI_LIBRARIES} - ${CURL_LIBRARIES} - ${APR_LIBRARIES} - ${APRUTIL_LIBRARIES} - ${CRYPTO_LIBRARIES} - rt - ) - -add_custom_command( - OUTPUT linux-crash-logger-stripped - COMMAND strip - ARGS --strip-debug -o linux-crash-logger-stripped linux-crash-logger - DEPENDS linux-crash-logger - ) - -add_custom_target(linux-crash-logger-strip-target ALL - DEPENDS linux-crash-logger-stripped) diff --git a/indra/linux_crash_logger/linux_crash_logger.cpp b/indra/linux_crash_logger/linux_crash_logger.cpp deleted file mode 100644 index 97eec851b8..0000000000 --- a/indra/linux_crash_logger/linux_crash_logger.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/** - * @file linux_crash_logger.cpp - * @brief Linux crash logger implementation - * - * $LicenseInfo:firstyear=2003&license=viewergpl$ - * - * Copyright (c) 2003-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#include "llcrashloggerlinux.h" - -int main(int argc, char **argv) -{ - LLCrashLoggerLinux app; - app.parseCommandOptions(argc, argv); - app.init(); - app.mainLoop(); - app.cleanup(); - return 0; -} - - diff --git a/indra/linux_crash_logger/llcrashloggerlinux.cpp b/indra/linux_crash_logger/llcrashloggerlinux.cpp deleted file mode 100644 index 039b70ec4a..0000000000 --- a/indra/linux_crash_logger/llcrashloggerlinux.cpp +++ /dev/null @@ -1,148 +0,0 @@ -/** - * @file llcrashloggerlinux.cpp - * @brief Linux crash logger implementation - * - * $LicenseInfo:firstyear=2003&license=viewergpl$ - * - * Copyright (c) 2003-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#include "llcrashloggerlinux.h" - -#include - -#include "linden_common.h" - -#include "boost/tokenizer.hpp" - -#include "indra_constants.h" // CRASH_BEHAVIOR_ASK, CRASH_SETTING_NAME -#include "llerror.h" -#include "llfile.h" -#include "lltimer.h" -#include "llstring.h" -#include "lldir.h" -#include "llsdserialize.h" - -#if LL_GTK -# include "gtk/gtk.h" -#endif // LL_GTK - -#define MAX_LOADSTRING 100 - -// These need to be localized. -static const char dialog_text[] = -"Second Life appears to have crashed or frozen last time it ran.\n" -"This crash reporter collects information about your computer's hardware, operating system, and some Second Life logs, all of which are used for debugging purposes only.\n" -"\n" -"Send crash report?"; - -static const char dialog_title[] = -"Second Life Crash Logger"; - -#if LL_GTK -static void response_callback (GtkDialog *dialog, - gint arg1, - gpointer user_data) -{ - gint *response = (gint*)user_data; - *response = arg1; - gtk_widget_destroy(GTK_WIDGET(dialog)); - gtk_main_quit(); -} -#endif // LL_GTK - -static BOOL do_ask_dialog(void) -{ -#if LL_GTK - gtk_disable_setlocale(); - if (!gtk_init_check(NULL, NULL)) { - llinfos << "Could not initialize GTK for 'ask to send crash report' dialog; not sending report." << llendl; - return FALSE; - } - - GtkWidget *win = NULL; - GtkDialogFlags flags = GTK_DIALOG_MODAL; - GtkMessageType messagetype = GTK_MESSAGE_QUESTION; - GtkButtonsType buttons = GTK_BUTTONS_YES_NO; - gint response = GTK_RESPONSE_NONE; - - win = gtk_message_dialog_new(NULL, - flags, messagetype, buttons, - "%s", dialog_text); - gtk_window_set_type_hint(GTK_WINDOW(win), - GDK_WINDOW_TYPE_HINT_DIALOG); - gtk_window_set_title(GTK_WINDOW(win), dialog_title); - g_signal_connect (win, - "response", - G_CALLBACK (response_callback), - &response); - gtk_widget_show_all (win); - gtk_main(); - - return (GTK_RESPONSE_OK == response || - GTK_RESPONSE_YES == response || - GTK_RESPONSE_APPLY == response); -#else - return FALSE; -#endif // LL_GTK -} - -LLCrashLoggerLinux::LLCrashLoggerLinux(void) -{ -} - -LLCrashLoggerLinux::~LLCrashLoggerLinux(void) -{ -} - -void LLCrashLoggerLinux::gatherPlatformSpecificFiles() -{ - mFileMap["CrashLog"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log").c_str(); -} - -bool LLCrashLoggerLinux::mainLoop() -{ - bool send_logs = true; - if(CRASH_BEHAVIOR_ASK == getCrashBehavior()) - { - send_logs = do_ask_dialog(); - } - else if(CRASH_BEHAVIOR_NEVER_SEND == getCrashBehavior()) - { - send_logs = false; - } - - if(send_logs) - { - sendCrashLogs(); - } - return true; -} - -void LLCrashLoggerLinux::updateApplication(const std::string& message) -{ - LLCrashLogger::updateApplication(message); -} diff --git a/indra/linux_crash_logger/llcrashloggerlinux.h b/indra/linux_crash_logger/llcrashloggerlinux.h deleted file mode 100644 index 937d547f87..0000000000 --- a/indra/linux_crash_logger/llcrashloggerlinux.h +++ /dev/null @@ -1,50 +0,0 @@ -/** - * @file llcrashloggerlinux.h - * @brief Linux crash logger definition - * - * $LicenseInfo:firstyear=2003&license=viewergpl$ - * - * Copyright (c) 2003-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifndef LLCRASHLOGGERLINUX_H -#define LLCRASHLOGGERLINUX_H - -#include "linden_common.h" -#include "llcrashlogger.h" -#include "llstring.h" - -class LLCrashLoggerLinux : public LLCrashLogger -{ -public: - LLCrashLoggerLinux(void); - ~LLCrashLoggerLinux(void); - virtual bool mainLoop(); - virtual void updateApplication(const std::string& = LLStringUtil::null); - virtual void gatherPlatformSpecificFiles(); -}; - -#endif diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp index 1d05da7f35..0a85aff0e3 100644 --- a/indra/llappearance/llavatarappearance.cpp +++ b/indra/llappearance/llavatarappearance.cpp @@ -24,26 +24,23 @@ * $/LicenseInfo$ */ -#if LL_MSVC -// disable warning about boost::lexical_cast returning uninitialized data -// when it fails to parse the string -#pragma warning (disable:4701) -#endif #include "linden_common.h" #include "llavatarappearance.h" #include "llavatarappearancedefines.h" #include "llavatarjointmesh.h" +#include "llstl.h" #include "imageids.h" #include "lldir.h" -#include "lldeleteutils.h" #include "llpolymorph.h" #include "llpolymesh.h" #include "llpolyskeletaldistortion.h" #include "llstl.h" #include "lltexglobalcolor.h" #include "llwearabledata.h" +#include "boost/bind.hpp" +#include "boost/tokenizer.hpp" #if LL_MSVC @@ -51,8 +48,6 @@ #pragma warning (disable:4702) #endif -#include - using namespace LLAvatarAppearanceDefines; //----------------------------------------------------------------------------- @@ -81,13 +76,17 @@ class LLAvatarBoneInfo ~LLAvatarBoneInfo() { std::for_each(mChildList.begin(), mChildList.end(), DeletePointer()); + mChildList.clear(); } BOOL parseXml(LLXmlTreeNode* node); private: std::string mName; + std::string mSupport; + std::string mAliases; BOOL mIsJoint; LLVector3 mPos; + LLVector3 mEnd; LLVector3 mRot; LLVector3 mScale; LLVector3 mPivot; @@ -108,6 +107,7 @@ class LLAvatarSkeletonInfo ~LLAvatarSkeletonInfo() { std::for_each(mBoneInfoList.begin(), mBoneInfoList.end(), DeletePointer()); + mBoneInfoList.clear(); } BOOL parseXml(LLXmlTreeNode* node); S32 getNumBones() const { return mNumBones; } @@ -116,6 +116,7 @@ class LLAvatarSkeletonInfo private: S32 mNumBones; S32 mNumCollisionVolumes; + LLAvatarAppearance::joint_alias_map_t mJointAliasMap; typedef std::vector bone_info_list_t; bone_info_list_t mBoneInfoList; }; @@ -132,14 +133,25 @@ LLAvatarAppearance::LLAvatarXmlInfo::LLAvatarXmlInfo() LLAvatarAppearance::LLAvatarXmlInfo::~LLAvatarXmlInfo() { std::for_each(mMeshInfoList.begin(), mMeshInfoList.end(), DeletePointer()); + mMeshInfoList.clear(); + std::for_each(mSkeletalDistortionInfoList.begin(), mSkeletalDistortionInfoList.end(), DeletePointer()); + mSkeletalDistortionInfoList.clear(); + std::for_each(mAttachmentInfoList.begin(), mAttachmentInfoList.end(), DeletePointer()); - deleteAndClear(mTexSkinColorInfo); - deleteAndClear(mTexHairColorInfo); - deleteAndClear(mTexEyeColorInfo); + mAttachmentInfoList.clear(); + + delete_and_clear(mTexSkinColorInfo); + delete_and_clear(mTexHairColorInfo); + delete_and_clear(mTexEyeColorInfo); std::for_each(mLayerInfoList.begin(), mLayerInfoList.end(), DeletePointer()); + mLayerInfoList.clear(); + std::for_each(mDriverInfoList.begin(), mDriverInfoList.end(), DeletePointer()); + mDriverInfoList.clear(); + std::for_each(mMorphMaskInfoList.begin(), mMorphMaskInfoList.end(), DeletePointer()); + mMorphMaskInfoList.clear(); } @@ -167,7 +179,10 @@ LLAvatarAppearance::LLAvatarAppearance(LLWearableData* wearable_data) : mPelvisToFoot(0.f), mHeadOffset(), mRoot(NULL), - mWearableData(wearable_data) + mWearableData(wearable_data), + mNumBones(0), + mIsBuilt(FALSE), + mInitFlags(0) { llassert_always(mWearableData); mBakedTextureDatas.resize(LLAvatarAppearanceDefines::BAKED_NUM_INDICES); @@ -180,11 +195,6 @@ LLAvatarAppearance::LLAvatarAppearance(LLWearableData* wearable_data) : mBakedTextureDatas[i].mMaskTexName = 0; mBakedTextureDatas[i].mTextureIndex = LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::bakedToLocalTextureIndex((LLAvatarAppearanceDefines::EBakedTextureIndex)i); } - - mIsBuilt = FALSE; - - mNumCollisionVolumes = 0; - mCollisionVolumes = NULL; } // virtual @@ -196,8 +206,9 @@ void LLAvatarAppearance::initInstance() mRoot = createAvatarJoint(); mRoot->setName( "mRoot" ); - for (LLAvatarAppearanceDictionary::MeshEntries::const_iterator iter = LLAvatarAppearanceDictionary::getInstance()->getMeshEntries().begin(); - iter != LLAvatarAppearanceDictionary::getInstance()->getMeshEntries().end(); + const auto& mesh_entries = LLAvatarAppearanceDictionary::getInstance()->getMeshEntries(); + for (LLAvatarAppearanceDictionary::MeshEntries::const_iterator iter = mesh_entries.begin(); + iter != mesh_entries.end(); ++iter) { const EMeshIndex mesh_index = iter->first; @@ -214,14 +225,14 @@ void LLAvatarAppearance::initInstance() for (U32 lod = 0; lod < mesh_dict->mLOD; lod++) { LLAvatarJointMesh* mesh = createAvatarJointMesh(); - std::string mesh_name = "m" + mesh_dict->mName + boost::lexical_cast(lod); + std::string mesh_name = fmt::format(FMT_STRING("m{:s}{:d}"), mesh_dict->mName, lod); // We pre-pended an m - need to capitalize first character for camelCase mesh_name[1] = toupper(mesh_name[1]); mesh->setName(mesh_name); mesh->setMeshID(mesh_index); mesh->setPickName(mesh_dict->mPickName); mesh->setIsTransparent(FALSE); - switch((int)mesh_index) + switch((S32)mesh_index) { case MESH_ID_HAIR: mesh->setIsTransparent(TRUE); @@ -242,8 +253,8 @@ void LLAvatarAppearance::initInstance() //------------------------------------------------------------------------- // associate baked textures with meshes //------------------------------------------------------------------------- - for (LLAvatarAppearanceDictionary::MeshEntries::const_iterator iter = LLAvatarAppearanceDictionary::getInstance()->getMeshEntries().begin(); - iter != LLAvatarAppearanceDictionary::getInstance()->getMeshEntries().end(); + for (LLAvatarAppearanceDictionary::MeshEntries::const_iterator iter = mesh_entries.begin(); + iter != mesh_entries.end(); ++iter) { const EMeshIndex mesh_index = iter->first; @@ -257,7 +268,7 @@ void LLAvatarAppearance::initInstance() ++iter) { LLAvatarJointMesh* mesh = (*iter); - mBakedTextureDatas[(int)baked_texture_index].mJointMeshes.push_back(mesh); + mBakedTextureDatas[(S32)baked_texture_index].mJointMeshes.push_back(mesh); } } @@ -267,34 +278,39 @@ void LLAvatarAppearance::initInstance() } buildCharacter(); + mInitFlags |= 1<<0; + } // virtual LLAvatarAppearance::~LLAvatarAppearance() { - deleteAndClear(mTexSkinColor); - deleteAndClear(mTexHairColor); - deleteAndClear(mTexEyeColor); + delete_and_clear(mTexSkinColor); + delete_and_clear(mTexHairColor); + delete_and_clear(mTexEyeColor); for (U32 i = 0; i < mBakedTextureDatas.size(); i++) { - deleteAndClear(mBakedTextureDatas[i].mTexLayerSet); + delete_and_clear(mBakedTextureDatas[i].mTexLayerSet); mBakedTextureDatas[i].mJointMeshes.clear(); for (morph_list_t::iterator iter2 = mBakedTextureDatas[i].mMaskedMorphs.begin(); - iter2 != mBakedTextureDatas[i].mMaskedMorphs.end(); iter2++) + iter2 != mBakedTextureDatas[i].mMaskedMorphs.end(); ++iter2) { LLMaskedMorph* masked_morph = (*iter2); delete masked_morph; } } - if (mRoot) mRoot->removeAllChildren(); - deleteAndClear(mRoot); + if (mRoot) + { + mRoot->removeAllChildren(); + delete_and_clear(mRoot); + } mJointMap.clear(); clearSkeleton(); - deleteAndClearArray(mCollisionVolumes); + delete_and_clear(mCollisionVolumes); std::for_each(mPolyMeshes.begin(), mPolyMeshes.end(), DeletePairedPointer()); mPolyMeshes.clear(); @@ -314,36 +330,49 @@ LLAvatarAppearance::~LLAvatarAppearance() //static void LLAvatarAppearance::initClass() { - std::string xmlFile; + initClass("",""); +} - xmlFile = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,AVATAR_DEFAULT_CHAR) + "_lad.xml"; - BOOL success = sXMLTree.parseFile( xmlFile, FALSE ); +//static +void LLAvatarAppearance::initClass(const std::string& avatar_file_name_arg, const std::string& skeleton_file_name_arg) +{ + std::string avatar_file_name; + + if (!avatar_file_name_arg.empty()) + { + avatar_file_name = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,avatar_file_name_arg); + } + else + { + avatar_file_name = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,AVATAR_DEFAULT_CHAR + "_lad.xml"); + } + BOOL success = sXMLTree.parseFile( avatar_file_name, FALSE ); if (!success) { - llerrs << "Problem reading avatar configuration file:" << xmlFile << llendl; + LL_ERRS() << "Problem reading avatar configuration file:" << avatar_file_name << LL_ENDL; } // now sanity check xml file LLXmlTreeNode* root = sXMLTree.getRoot(); if (!root) { - llerrs << "No root node found in avatar configuration file: " << xmlFile << llendl; + LL_ERRS() << "No root node found in avatar configuration file: " << avatar_file_name << LL_ENDL; return; } //------------------------------------------------------------------------- - // (root) + // (root) //------------------------------------------------------------------------- if( !root->hasName( "linden_avatar" ) ) { - llerrs << "Invalid avatar file header: " << xmlFile << llendl; + LL_ERRS() << "Invalid avatar file header: " << avatar_file_name << LL_ENDL; } std::string version; static LLStdStringHandle version_string = LLXmlTree::addAttributeString("version"); - if( !root->getFastAttributeString( version_string, version ) || (version != "1.0") ) + if( !root->getFastAttributeString( version_string, version ) || ((version != "1.0") && (version != "2.0"))) { - llerrs << "Invalid avatar file version: " << version << " in file: " << xmlFile << llendl; + LL_ERRS() << "Invalid avatar file version: " << version << " in file: " << avatar_file_name << LL_ENDL; } S32 wearable_def_version = 1; @@ -351,27 +380,28 @@ void LLAvatarAppearance::initClass() root->getFastAttributeS32( wearable_definition_version_string, wearable_def_version ); LLWearable::setCurrentDefinitionVersion( wearable_def_version ); - std::string mesh_file_name; - LLXmlTreeNode* skeleton_node = root->getChildByName( "skeleton" ); if (!skeleton_node) { - llerrs << "No skeleton in avatar configuration file: " << xmlFile << llendl; + LL_ERRS() << "No skeleton in avatar configuration file: " << avatar_file_name << LL_ENDL; return; } - - std::string skeleton_file_name; - static LLStdStringHandle file_name_string = LLXmlTree::addAttributeString("file_name"); - if (!skeleton_node->getFastAttributeString(file_name_string, skeleton_file_name)) - { - llerrs << "No file name in skeleton node in avatar config file: " << xmlFile << llendl; - } + + std::string skeleton_file_name = skeleton_file_name_arg; + if (skeleton_file_name.empty()) + { + static LLStdStringHandle file_name_string = LLXmlTree::addAttributeString("file_name"); + if (!skeleton_node->getFastAttributeString(file_name_string, skeleton_file_name)) + { + LL_ERRS() << "No file name in skeleton node in avatar config file: " << avatar_file_name << LL_ENDL; + } + } std::string skeleton_path; skeleton_path = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,skeleton_file_name); if (!parseSkeletonFile(skeleton_path)) { - llerrs << "Error parsing skeleton file: " << skeleton_path << llendl; + LL_ERRS() << "Error parsing skeleton file: " << skeleton_path << LL_ENDL; } // Process XML data @@ -384,55 +414,100 @@ void LLAvatarAppearance::initClass() sAvatarSkeletonInfo = new LLAvatarSkeletonInfo; if (!sAvatarSkeletonInfo->parseXml(sSkeletonXMLTree.getRoot())) { - llerrs << "Error parsing skeleton XML file: " << skeleton_path << llendl; + LL_ERRS() << "Error parsing skeleton XML file: " << skeleton_path << LL_ENDL; } // parse avatar_lad.xml if (sAvatarXmlInfo) { //this can happen if a login attempt failed - deleteAndClear(sAvatarXmlInfo); + delete_and_clear(sAvatarXmlInfo); } sAvatarXmlInfo = new LLAvatarXmlInfo; if (!sAvatarXmlInfo->parseXmlSkeletonNode(root)) { - llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl; + LL_ERRS() << "Error parsing skeleton node in avatar XML file: " << skeleton_path << LL_ENDL; } if (!sAvatarXmlInfo->parseXmlMeshNodes(root)) { - llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl; + LL_ERRS() << "Error parsing skeleton node in avatar XML file: " << skeleton_path << LL_ENDL; } if (!sAvatarXmlInfo->parseXmlColorNodes(root)) { - llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl; + LL_ERRS() << "Error parsing skeleton node in avatar XML file: " << skeleton_path << LL_ENDL; } if (!sAvatarXmlInfo->parseXmlLayerNodes(root)) { - llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl; + LL_ERRS() << "Error parsing skeleton node in avatar XML file: " << skeleton_path << LL_ENDL; } if (!sAvatarXmlInfo->parseXmlDriverNodes(root)) { - llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl; + LL_ERRS() << "Error parsing skeleton node in avatar XML file: " << skeleton_path << LL_ENDL; } if (!sAvatarXmlInfo->parseXmlMorphNodes(root)) { - llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl; + LL_ERRS() << "Error parsing skeleton node in avatar XML file: " << skeleton_path << LL_ENDL; } } void LLAvatarAppearance::cleanupClass() { - deleteAndClear(sAvatarXmlInfo); - deleteAndClear(sAvatarSkeletonInfo); + delete_and_clear(sAvatarXmlInfo); + delete_and_clear(sAvatarSkeletonInfo); sSkeletonXMLTree.cleanup(); sXMLTree.cleanup(); } using namespace LLAvatarAppearanceDefines; +void LLAvatarAppearance::compareJointStateMaps(joint_state_map_t& last_state, + joint_state_map_t& curr_state) +{ + if (!last_state.empty() && (last_state != curr_state)) + { + S32 diff_count = 0; + joint_state_map_t::iterator it; + for (it=last_state.begin(); it != last_state.end(); ++it) + { + const std::string& key = it->first; + if (last_state[key] != curr_state[key]) + { + LL_DEBUGS("AvatarBodySize") << "BodySize change " << key << " " << last_state[key] << "->" << curr_state[key] << LL_ENDL; + diff_count++; + } + } + if (diff_count > 0) + { + LL_DEBUGS("AvatarBodySize") << "Total of BodySize changes " << diff_count << LL_ENDL; + } + + } +} + //------------------------------------------------------------------------ // The viewer can only suggest a good size for the agent, // the simulator will keep it inside a reasonable range. void LLAvatarAppearance::computeBodySize() { + mLastBodySizeState = mCurrBodySizeState; + + mCurrBodySizeState["mPelvis scale"] = mPelvisp->getScale(); + mCurrBodySizeState["mSkull pos"] = mSkullp->getPosition(); + mCurrBodySizeState["mSkull scale"] = mSkullp->getScale(); + mCurrBodySizeState["mNeck pos"] = mNeckp->getPosition(); + mCurrBodySizeState["mNeck scale"] = mNeckp->getScale(); + mCurrBodySizeState["mChest pos"] = mChestp->getPosition(); + mCurrBodySizeState["mChest scale"] = mChestp->getScale(); + mCurrBodySizeState["mHead pos"] = mHeadp->getPosition(); + mCurrBodySizeState["mHead scale"] = mHeadp->getScale(); + mCurrBodySizeState["mTorso pos"] = mTorsop->getPosition(); + mCurrBodySizeState["mTorso scale"] = mTorsop->getScale(); + mCurrBodySizeState["mHipLeft pos"] = mHipLeftp->getPosition(); + mCurrBodySizeState["mHipLeft scale"] = mHipLeftp->getScale(); + mCurrBodySizeState["mKneeLeft pos"] = mKneeLeftp->getPosition(); + mCurrBodySizeState["mKneeLeft scale"] = mKneeLeftp->getScale(); + mCurrBodySizeState["mAnkleLeft pos"] = mAnkleLeftp->getPosition(); + mCurrBodySizeState["mAnkleLeft scale"] = mAnkleLeftp->getScale(); + mCurrBodySizeState["mFootLeft pos"] = mFootLeftp->getPosition(); + LLVector3 pelvis_scale = mPelvisp->getScale(); // some of the joints have not been cached @@ -489,29 +564,11 @@ void LLAvatarAppearance::computeBodySize() mAvatarOffset.mV[VX] = 0.0f; mAvatarOffset.mV[VY] = 0.0f; - // Certain configurations of avatars can force the overall height (with offset) to go negative. - // Enforce a constraint to make sure we don't go below 0.1 meters. - // Camera positioning and other things start to break down when your avatar is "walking" while being fully underground - if (new_body_size.mV[VZ] + mAvatarOffset.mV[VZ] < 0.1f) - { - mAvatarOffset.mV[VZ] = -(new_body_size.mV[VZ] - 0.11f); // avoid floating point rounding making the above check continue to fail. - - llassert(new_body_size.mV[VZ] + mAvatarOffset.mV[VZ] >= 0.1f); - - if (mWearableData && isSelf()) - { - LLWearable* shape = mWearableData->getWearable(LLWearableType::WT_SHAPE, 0); - if (shape) - { - shape->setVisualParamWeight(AVATAR_HOVER, mAvatarOffset.mV[VZ], false); - } - } - } - if (new_body_size != mBodySize || old_offset != mAvatarOffset) { mBodySize = new_body_size; - bodySizeChanged(); + + compareJointStateMaps(mLastBodySizeState, mCurrBodySizeState); } } @@ -527,7 +584,7 @@ BOOL LLAvatarAppearance::parseSkeletonFile(const std::string& filename) if (!parsesuccess) { - llerrs << "Can't parse skeleton file: " << filename << llendl; + LL_ERRS() << "Can't parse skeleton file: " << filename << LL_ENDL; return FALSE; } @@ -535,21 +592,21 @@ BOOL LLAvatarAppearance::parseSkeletonFile(const std::string& filename) LLXmlTreeNode* root = sSkeletonXMLTree.getRoot(); if (!root) { - llerrs << "No root node found in avatar skeleton file: " << filename << llendl; + LL_ERRS() << "No root node found in avatar skeleton file: " << filename << LL_ENDL; return FALSE; } if( !root->hasName( "linden_skeleton" ) ) { - llerrs << "Invalid avatar skeleton file header: " << filename << llendl; + LL_ERRS() << "Invalid avatar skeleton file header: " << filename << LL_ENDL; return FALSE; } std::string version; static LLStdStringHandle version_string = LLXmlTree::addAttributeString("version"); - if( !root->getFastAttributeString( version_string, version ) || (version != "1.0") ) + if( !root->getFastAttributeString( version_string, version ) || ((version != "1.0") && (version != "2.0"))) { - llerrs << "Invalid avatar skeleton file version: " << version << " in file: " << filename << llendl; + LL_ERRS() << "Invalid avatar skeleton file version: " << version << " in file: " << filename << LL_ENDL; return FALSE; } @@ -563,50 +620,62 @@ BOOL LLAvatarAppearance::setupBone(const LLAvatarBoneInfo* info, LLJoint* parent { LLJoint* joint = NULL; + LL_DEBUGS("BVH") << "bone info: name " << info->mName + << " isJoint " << info->mIsJoint + << " volume_num " << volume_num + << " joint_num " << joint_num + << LL_ENDL; + if (info->mIsJoint) { joint = getCharacterJoint(joint_num); if (!joint) { - llwarns << "Too many bones" << llendl; + LL_WARNS() << "Too many bones" << LL_ENDL; return FALSE; } joint->setName( info->mName ); } else // collision volume { - if (volume_num >= (S32)mNumCollisionVolumes) + if (volume_num >= (S32)mCollisionVolumes.size()) { - llwarns << "Too many bones" << llendl; + LL_WARNS() << "Too many collision volumes" << LL_ENDL; return FALSE; } - joint = (&mCollisionVolumes[volume_num]); + joint = (mCollisionVolumes[volume_num]); joint->setName( info->mName ); } // add to parent - if (parent) + if (parent && (joint->getParent()!=parent)) { parent->addChild( joint ); } + // SL-315 joint->setPosition(info->mPos); + joint->setDefaultPosition(info->mPos); joint->setRotation(mayaQ(info->mRot.mV[VX], info->mRot.mV[VY], info->mRot.mV[VZ], LLQuaternion::XYZ)); joint->setScale(info->mScale); + joint->setDefaultScale(info->mScale); + joint->setSupport(info->mSupport); + joint->setEnd(info->mEnd); - joint->setDefaultFromCurrentXform(); - if (info->mIsJoint) { joint->setSkinOffset( info->mPivot ); + joint->setJointNum(joint_num); joint_num++; } else // collision volume { + joint->setJointNum(mNumBones+volume_num); volume_num++; } + // setup children LLAvatarBoneInfo::child_list_t::const_iterator iter; for (iter = info->mChildList.begin(); iter != info->mChildList.end(); ++iter) @@ -626,18 +695,12 @@ BOOL LLAvatarAppearance::setupBone(const LLAvatarBoneInfo* info, LLJoint* parent //----------------------------------------------------------------------------- BOOL LLAvatarAppearance::allocateCharacterJoints( U32 num ) { - clearSkeleton(); - - for(S32 joint_num = 0; joint_num < (S32)num; joint_num++) - { - mSkeleton.push_back(createAvatarJoint(joint_num)); - } - - - if (mSkeleton.empty() || !mSkeleton[0]) - { - return FALSE; - } + if (mSkeleton.size() != num) + { + clearSkeleton(); + mSkeleton = avatar_joint_list_t(num,NULL); + mNumBones = num; + } return TRUE; } @@ -650,12 +713,14 @@ BOOL LLAvatarAppearance::buildSkeleton(const LLAvatarSkeletonInfo *info) { if (!info) return FALSE; + LL_DEBUGS("BVH") << "numBones " << info->mNumBones << " numCollisionVolumes " << info->mNumCollisionVolumes << LL_ENDL; + //------------------------------------------------------------------------- // allocate joints //------------------------------------------------------------------------- if (!allocateCharacterJoints(info->mNumBones)) { - llerrs << "Can't allocate " << info->mNumBones << " joints" << llendl; + LL_ERRS() << "Can't allocate " << info->mNumBones << " joints" << LL_ENDL; return FALSE; } @@ -666,7 +731,7 @@ BOOL LLAvatarAppearance::buildSkeleton(const LLAvatarSkeletonInfo *info) { if (!allocateCollisionVolumes(info->mNumCollisionVolumes)) { - llerrs << "Can't allocate " << info->mNumCollisionVolumes << " collision volumes" << llendl; + LL_ERRS() << "Can't allocate " << info->mNumCollisionVolumes << " collision volumes" << LL_ENDL; return FALSE; } } @@ -676,10 +741,10 @@ BOOL LLAvatarAppearance::buildSkeleton(const LLAvatarSkeletonInfo *info) LLAvatarSkeletonInfo::bone_info_list_t::const_iterator iter; for (iter = info->mBoneInfoList.begin(); iter != info->mBoneInfoList.end(); ++iter) { - LLAvatarBoneInfo *info = *iter; - if (!setupBone(info, NULL, current_volume_num, current_joint_num)) + LLAvatarBoneInfo *bone_info = *iter; + if (!setupBone(bone_info, NULL, current_volume_num, current_joint_num)) { - llerrs << "Error parsing bone in skeleton file" << llendl; + LL_ERRS() << "Error parsing bone in skeleton file" << LL_ENDL; return FALSE; } } @@ -696,6 +761,42 @@ void LLAvatarAppearance::clearSkeleton() mSkeleton.clear(); } +//------------------------------------------------------------------------ +// addPelvisFixup +//------------------------------------------------------------------------ +void LLAvatarAppearance::addPelvisFixup( F32 fixup, const LLUUID& mesh_id ) +{ + LLVector3 pos(0.0,0.0,fixup); + mPelvisFixups.add(mesh_id,pos); +} + +//------------------------------------------------------------------------ +// addPelvisFixup +//------------------------------------------------------------------------ +void LLAvatarAppearance::removePelvisFixup( const LLUUID& mesh_id ) +{ + mPelvisFixups.remove(mesh_id); +} + +//------------------------------------------------------------------------ +// hasPelvisFixup +//------------------------------------------------------------------------ +bool LLAvatarAppearance::hasPelvisFixup( F32& fixup, LLUUID& mesh_id ) const +{ + LLVector3 pos; + if (mPelvisFixups.findActiveOverride(mesh_id,pos)) + { + fixup = pos[2]; + return true; + } + return false; +} + +bool LLAvatarAppearance::hasPelvisFixup( F32& fixup ) const +{ + LLUUID mesh_id; + return hasPelvisFixup( fixup, mesh_id ); +} //----------------------------------------------------------------------------- // LLAvatarAppearance::buildCharacter() // Deferred initialization and rebuild of the avatar. @@ -745,17 +846,17 @@ void LLAvatarAppearance::buildCharacter() } // gPrintMessagesThisFrame = TRUE; - lldebugs << "Avatar load took " << timer.getElapsedTimeF32() << " seconds." << llendl; + LL_DEBUGS() << "Avatar load took " << timer.getElapsedTimeF32() << " seconds." << LL_ENDL; if (!status) { if (isSelf()) { - llerrs << "Unable to load user's avatar" << llendl; + LL_ERRS() << "Unable to load user's avatar" << LL_ENDL; } else { - llwarns << "Unable to load other's avatar" << llendl; + LL_WARNS() << "Unable to load other's avatar" << LL_ENDL; } return; } @@ -804,7 +905,7 @@ void LLAvatarAppearance::buildCharacter() mEyeLeftp && mEyeRightp)) { - llerrs << "Failed to create avatar." << llendl; + LL_ERRS() << "Failed to create avatar." << LL_ENDL; return; } @@ -821,30 +922,30 @@ void LLAvatarAppearance::buildCharacter() //----------------------------------------------------------------------------- // loadAvatar() //----------------------------------------------------------------------------- -//static LLFastTimer::DeclareTimer FTM_LOAD_AVATAR("Load Avatar"); +//static LLTrace::BlockTimerStatHandle FTM_LOAD_AVATAR("Load Avatar"); BOOL LLAvatarAppearance::loadAvatar() { -// LLFastTimer t(FTM_LOAD_AVATAR); +// LL_RECORD_BLOCK_TIME(FTM_LOAD_AVATAR); // avatar_skeleton.xml if( !buildSkeleton(sAvatarSkeletonInfo) ) { - llwarns << "avatar file: buildSkeleton() failed" << llendl; + LL_WARNS() << "avatar file: buildSkeleton() failed" << LL_ENDL; return FALSE; } // avatar_lad.xml : if( !loadSkeletonNode() ) { - llwarns << "avatar file: loadNodeSkeleton() failed" << llendl; + LL_WARNS() << "avatar file: loadNodeSkeleton() failed" << LL_ENDL; return FALSE; } // avatar_lad.xml : if( !loadMeshNodes() ) { - llwarns << "avatar file: loadNodeMesh() failed" << llendl; + LL_WARNS() << "avatar file: loadNodeMesh() failed" << LL_ENDL; return FALSE; } @@ -854,13 +955,13 @@ BOOL LLAvatarAppearance::loadAvatar() mTexSkinColor = new LLTexGlobalColor( this ); if( !mTexSkinColor->setInfo( sAvatarXmlInfo->mTexSkinColorInfo ) ) { - llwarns << "avatar file: mTexSkinColor->setInfo() failed" << llendl; + LL_WARNS() << "avatar file: mTexSkinColor->setInfo() failed" << LL_ENDL; return FALSE; } } else { - llwarns << " name=\"skin_color\" not found" << llendl; + LL_WARNS() << " name=\"skin_color\" not found" << LL_ENDL; return FALSE; } if( sAvatarXmlInfo->mTexHairColorInfo ) @@ -868,13 +969,13 @@ BOOL LLAvatarAppearance::loadAvatar() mTexHairColor = new LLTexGlobalColor( this ); if( !mTexHairColor->setInfo( sAvatarXmlInfo->mTexHairColorInfo ) ) { - llwarns << "avatar file: mTexHairColor->setInfo() failed" << llendl; + LL_WARNS() << "avatar file: mTexHairColor->setInfo() failed" << LL_ENDL; return FALSE; } } else { - llwarns << " name=\"hair_color\" not found" << llendl; + LL_WARNS() << " name=\"hair_color\" not found" << LL_ENDL; return FALSE; } if( sAvatarXmlInfo->mTexEyeColorInfo ) @@ -882,26 +983,26 @@ BOOL LLAvatarAppearance::loadAvatar() mTexEyeColor = new LLTexGlobalColor( this ); if( !mTexEyeColor->setInfo( sAvatarXmlInfo->mTexEyeColorInfo ) ) { - llwarns << "avatar file: mTexEyeColor->setInfo() failed" << llendl; + LL_WARNS() << "avatar file: mTexEyeColor->setInfo() failed" << LL_ENDL; return FALSE; } } else { - llwarns << " name=\"eye_color\" not found" << llendl; + LL_WARNS() << " name=\"eye_color\" not found" << LL_ENDL; return FALSE; } // avatar_lad.xml : if (sAvatarXmlInfo->mLayerInfoList.empty()) { - llwarns << "avatar file: missing node" << llendl; + LL_WARNS() << "avatar file: missing node" << LL_ENDL; return FALSE; } if (sAvatarXmlInfo->mMorphMaskInfoList.empty()) { - llwarns << "avatar file: missing node" << llendl; + LL_WARNS() << "avatar file: missing node" << LL_ENDL; return FALSE; } @@ -941,16 +1042,16 @@ BOOL LLAvatarAppearance::loadAvatar() addVisualParam( driver_param ); driver_param->setParamLocation(isSelf() ? LOC_AV_SELF : LOC_AV_OTHER); LLVisualParam*(LLAvatarAppearance::*avatar_function)(S32)const = &LLAvatarAppearance::getVisualParam; - if( !driver_param->linkDrivenParams(boost::bind(avatar_function,(LLAvatarAppearance*)this,_1 ), false)) + if( !driver_param->linkDrivenParams(std::bind(avatar_function,(LLAvatarAppearance*)this, std::placeholders::_1 ), false)) { - llwarns << "could not link driven params for avatar " << this->getFullname() << " param id: " << driver_param->getID() << llendl; + LL_WARNS() << "could not link driven params for avatar " << getID().asString() << " param id: " << driver_param->getID() << LL_ENDL; continue; } } else { delete driver_param; - llwarns << "avatar file: driver_param->parseData() failed" << llendl; + LL_WARNS() << "avatar file: driver_param->parseData() failed" << LL_ENDL; return FALSE; } } @@ -983,19 +1084,19 @@ BOOL LLAvatarAppearance::loadSkeletonNode () mRoot->addChild(mMeshLOD[MESH_ID_SKIRT]); mRoot->addChild(mMeshLOD[MESH_ID_HEAD]); - LLAvatarJoint *skull = (LLAvatarJoint*)mRoot->findJoint("mSkull"); + LLJoint *skull = mRoot->findJoint("mSkull"); if (skull) { skull->addChild(mMeshLOD[MESH_ID_HAIR] ); } - LLAvatarJoint *eyeL = (LLAvatarJoint*)mRoot->findJoint("mEyeLeft"); + LLJoint *eyeL = mRoot->findJoint("mEyeLeft"); if (eyeL) { eyeL->addChild( mMeshLOD[MESH_ID_EYEBALL_LEFT] ); } - LLAvatarJoint *eyeR = (LLAvatarJoint*)mRoot->findJoint("mEyeRight"); + LLJoint *eyeR = mRoot->findJoint("mEyeRight"); if (eyeR) { eyeR->addChild( mMeshLOD[MESH_ID_EYEBALL_RIGHT] ); @@ -1070,17 +1171,17 @@ BOOL LLAvatarAppearance::loadMeshNodes() } else { - llwarns << "Avatar file: has invalid lod setting " << lod << llendl; + LL_WARNS() << "Avatar file: has invalid lod setting " << lod << LL_ENDL; return FALSE; } } - else + else { - llwarns << "Ignoring unrecognized mesh type: " << type << llendl; + LL_WARNS() << "Ignoring unrecognized mesh type: " << type << LL_ENDL; return FALSE; } - // llinfos << "Parsing mesh data for " << type << "..." << llendl; + // LL_INFOS() << "Parsing mesh data for " << type << "..." << LL_ENDL; // If this isn't set to white (1.0), avatars will *ALWAYS* be darker than their surroundings. // Do not touch!!! @@ -1100,6 +1201,7 @@ BOOL LLAvatarAppearance::loadMeshNodes() { // This should never happen LL_WARNS("Avatar") << "Could not find avatar mesh: " << info->mReferenceMeshName << LL_ENDL; + return FALSE; } } else @@ -1110,12 +1212,12 @@ BOOL LLAvatarAppearance::loadMeshNodes() if( !poly_mesh ) { - llwarns << "Failed to load mesh of type " << type << llendl; + LL_WARNS() << "Failed to load mesh of type " << type << LL_ENDL; return FALSE; } // Multimap insert - mPolyMeshes.insert(std::make_pair(info->mMeshFileName, poly_mesh)); + mPolyMeshes.emplace(info->mMeshFileName, poly_mesh); mesh->setMesh( poly_mesh ); mesh->setLOD( info->mMinPixelArea ); @@ -1170,7 +1272,7 @@ BOOL LLAvatarAppearance::loadLayersets() { stop_glerror(); delete layer_set; - llwarns << "avatar file: layer_set->setInfo() failed" << llendl; + LL_WARNS() << "avatar file: layer_set->setInfo() failed" << LL_ENDL; return FALSE; } @@ -1193,7 +1295,7 @@ BOOL LLAvatarAppearance::loadLayersets() // if no baked texture was found, warn and cleanup if (baked_index == BAKED_NUM_INDICES) { - llwarns << " has invalid body_region attribute" << llendl; + LL_WARNS() << " has invalid body_region attribute" << LL_ENDL; delete layer_set; return FALSE; } @@ -1211,7 +1313,7 @@ BOOL LLAvatarAppearance::loadLayersets() } else { - llwarns << "Could not find layer named " << morph->mLayer << " to set morph flag" << llendl; + LL_WARNS() << "Could not find layer named " << morph->mLayer << " to set morph flag" << LL_ENDL; success = FALSE; } } @@ -1236,6 +1338,10 @@ LLJoint *LLAvatarAppearance::getCharacterJoint( U32 num ) { return NULL; } + if (!mSkeleton[num]) + { + mSkeleton[num] = createAvatarJoint(); + } return mSkeleton[num]; } @@ -1250,28 +1356,28 @@ LLVector3 LLAvatarAppearance::getVolumePos(S32 joint_index, LLVector3& volume_of return LLVector3::zero; } - if (joint_index > mNumCollisionVolumes) + if (joint_index > (S32)mCollisionVolumes.size()) { return LLVector3::zero; } - return mCollisionVolumes[joint_index].getVolumePos(volume_offset); + return mCollisionVolumes[joint_index]->getVolumePos(volume_offset); } //----------------------------------------------------------------------------- // findCollisionVolume() //----------------------------------------------------------------------------- -LLJoint* LLAvatarAppearance::findCollisionVolume(U32 volume_id) +LLJoint* LLAvatarAppearance::findCollisionVolume(S32 volume_id) { //SNOW-488: As mNumCollisionVolumes is a S32 and we are casting from a U32 to a S32 //to compare we also need to be sure of the wrap around case producing (S32) <0 //or in terms of the U32 an out of bounds index in the array. - if ((S32)volume_id > mNumCollisionVolumes || (S32)volume_id<0) + if ((S32)volume_id > (S32)mCollisionVolumes.size() || volume_id<0) { return NULL; } - return &mCollisionVolumes[volume_id]; + return mCollisionVolumes[volume_id]; } //----------------------------------------------------------------------------- @@ -1279,9 +1385,9 @@ LLJoint* LLAvatarAppearance::findCollisionVolume(U32 volume_id) //----------------------------------------------------------------------------- S32 LLAvatarAppearance::getCollisionVolumeID(std::string &name) { - for (S32 i = 0; i < mNumCollisionVolumes; i++) + for (S32 i = 0; i < (S32)mCollisionVolumes.size(); i++) { - if (mCollisionVolumes[i].getName() == name) + if (mCollisionVolumes[i]->getName() == name) { return i; } @@ -1357,7 +1463,7 @@ void LLAvatarAppearance::getMeshInfo (mesh_info_t* mesh_info) else { // Should never happen - llwarns << "Duplicate mesh LOD " << type << " " << lod << " " << file << llendl; + LL_WARNS() << "Duplicate mesh LOD " << type << " " << lod << " " << file << LL_ENDL; } } } @@ -1370,7 +1476,7 @@ BOOL LLAvatarAppearance::isValid() const // This should only be called on ourself. if (!isSelf()) { - llerrs << "Called LLAvatarAppearance::isValid() on when isSelf() == false" << llendl; + LL_ERRS() << "Called LLAvatarAppearance::isValid() on when isSelf() == false" << LL_ENDL; } return TRUE; } @@ -1454,6 +1560,21 @@ BOOL LLAvatarAppearance::teToColorParams( ETextureIndex te, U32 *param_name ) param_name[1] = 1072; //"tattoo_green"; param_name[2] = 1073; //"tattoo_blue"; break; + case TEX_HEAD_UNIVERSAL_TATTOO: + case TEX_UPPER_UNIVERSAL_TATTOO: + case TEX_LOWER_UNIVERSAL_TATTOO: + case TEX_SKIRT_TATTOO: + case TEX_HAIR_TATTOO: + case TEX_EYES_TATTOO: + case TEX_LEFT_ARM_TATTOO: + case TEX_LEFT_LEG_TATTOO: + case TEX_AUX1_TATTOO: + case TEX_AUX2_TATTOO: + case TEX_AUX3_TATTOO: + param_name[0] = 1238; //"tattoo_universal_red"; + param_name[1] = 1239; //"tattoo_universal_green"; + param_name[2] = 1240; //"tattoo_universal_blue"; + break; default: llassert(0); @@ -1463,7 +1584,7 @@ BOOL LLAvatarAppearance::teToColorParams( ETextureIndex te, U32 *param_name ) return TRUE; } -void LLAvatarAppearance::setClothesColor( ETextureIndex te, const LLColor4& new_color, BOOL upload_bake ) +void LLAvatarAppearance::setClothesColor( ETextureIndex te, const LLColor4& new_color, bool upload_bake ) { U32 param_name[3]; if( teToColorParams( te, param_name ) ) @@ -1535,16 +1656,26 @@ LLTexLayerSet* LLAvatarAppearance::getAvatarLayerSet(EBakedTextureIndex baked_in //----------------------------------------------------------------------------- BOOL LLAvatarAppearance::allocateCollisionVolumes( U32 num ) { - deleteAndClearArray(mCollisionVolumes); - mNumCollisionVolumes = 0; - - mCollisionVolumes = new LLAvatarJointCollisionVolume[num]; - if (!mCollisionVolumes) + if(num != mCollisionVolumes.size() ) { - return FALSE; - } + delete_and_clear(mCollisionVolumes); + mCollisionVolumes.reserve(num); - mNumCollisionVolumes = num; + LLAvatarJointCollisionVolume* cv; + for (U32 i = 0; i < num; ++i) + { + cv = new LLAvatarJointCollisionVolume(); + if (cv) + { + mCollisionVolumes.push_back(cv); + } + else + { + delete_and_clear(mCollisionVolumes); + return false; + } + } + } return TRUE; } @@ -1559,9 +1690,12 @@ BOOL LLAvatarBoneInfo::parseXml(LLXmlTreeNode* node) static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name"); if (!node->getFastAttributeString(name_string, mName)) { - llwarns << "Bone without name" << llendl; + LL_WARNS() << "Bone without name" << LL_ENDL; return FALSE; } + + static LLStdStringHandle aliases_string = LLXmlTree::addAttributeString("aliases"); + node->getFastAttributeString(aliases_string, mAliases ); //Aliases are not required. } else if (node->hasName("collision_volume")) { @@ -1574,37 +1708,51 @@ BOOL LLAvatarBoneInfo::parseXml(LLXmlTreeNode* node) } else { - llwarns << "Invalid node " << node->getName() << llendl; + LL_WARNS() << "Invalid node " << node->getName() << LL_ENDL; return FALSE; } static LLStdStringHandle pos_string = LLXmlTree::addAttributeString("pos"); if (!node->getFastAttributeVector3(pos_string, mPos)) { - llwarns << "Bone without position" << llendl; + LL_WARNS() << "Bone without position" << LL_ENDL; return FALSE; } static LLStdStringHandle rot_string = LLXmlTree::addAttributeString("rot"); if (!node->getFastAttributeVector3(rot_string, mRot)) { - llwarns << "Bone without rotation" << llendl; + LL_WARNS() << "Bone without rotation" << LL_ENDL; return FALSE; } static LLStdStringHandle scale_string = LLXmlTree::addAttributeString("scale"); if (!node->getFastAttributeVector3(scale_string, mScale)) { - llwarns << "Bone without scale" << llendl; + LL_WARNS() << "Bone without scale" << LL_ENDL; return FALSE; } + static LLStdStringHandle end_string = LLXmlTree::addAttributeString("end"); + if (!node->getFastAttributeVector3(end_string, mEnd)) + { + LL_WARNS() << "Bone without end " << mName << LL_ENDL; + mEnd = LLVector3(0.0f, 0.0f, 0.0f); + } + + static LLStdStringHandle support_string = LLXmlTree::addAttributeString("support"); + if (!node->getFastAttributeString(support_string,mSupport)) + { + LL_WARNS() << "Bone without support " << mName << LL_ENDL; + mSupport = "base"; + } + if (mIsJoint) { static LLStdStringHandle pivot_string = LLXmlTree::addAttributeString("pivot"); if (!node->getFastAttributeVector3(pivot_string, mPivot)) { - llwarns << "Bone without pivot" << llendl; + LL_WARNS() << "Bone without pivot" << LL_ENDL; return FALSE; } } @@ -1632,7 +1780,7 @@ BOOL LLAvatarSkeletonInfo::parseXml(LLXmlTreeNode* node) static LLStdStringHandle num_bones_string = LLXmlTree::addAttributeString("num_bones"); if (!node->getFastAttributeS32(num_bones_string, mNumBones)) { - llwarns << "Couldn't find number of bones." << llendl; + LL_WARNS() << "Couldn't find number of bones." << LL_ENDL; return FALSE; } @@ -1646,7 +1794,7 @@ BOOL LLAvatarSkeletonInfo::parseXml(LLXmlTreeNode* node) if (!info->parseXml(child)) { delete info; - llwarns << "Error parsing bone in skeleton file" << llendl; + LL_WARNS() << "Error parsing bone in skeleton file" << LL_ENDL; return FALSE; } mBoneInfoList.push_back(info); @@ -1654,6 +1802,75 @@ BOOL LLAvatarSkeletonInfo::parseXml(LLXmlTreeNode* node) return TRUE; } +//Make aliases for joint and push to map. +void LLAvatarAppearance::makeJointAliases(LLAvatarBoneInfo *bone_info) +{ + if (! bone_info->mIsJoint ) + { + return; + } + + std::string bone_name = bone_info->mName; + mJointAliasMap[bone_name] = bone_name; //Actual name is a valid alias. + + std::string aliases = bone_info->mAliases; + + boost::char_separator sep(" "); + boost::tokenizer > tok(aliases, sep); + for(boost::tokenizer >::iterator i = tok.begin(); i != tok.end(); ++i) + { + if ( mJointAliasMap.find(*i) != mJointAliasMap.end() ) + { + LL_WARNS() << "avatar skeleton: Joint alias \"" << *i << "\" remapped from " << mJointAliasMap[*i] << " to " << bone_name << LL_ENDL; + } + mJointAliasMap[*i] = bone_name; + } + + LLAvatarBoneInfo::child_list_t::const_iterator iter; + for (iter = bone_info->mChildList.begin(); iter != bone_info->mChildList.end(); ++iter) + { + makeJointAliases( *iter ); + } +} + +const LLAvatarAppearance::joint_alias_map_t& LLAvatarAppearance::getJointAliases () +{ + LLAvatarAppearance::joint_alias_map_t alias_map; + if (mJointAliasMap.empty()) + { + + LLAvatarSkeletonInfo::bone_info_list_t::const_iterator iter; + for (iter = sAvatarSkeletonInfo->mBoneInfoList.begin(); + iter != sAvatarSkeletonInfo->mBoneInfoList.end(); + ++iter) + { + //LLAvatarBoneInfo *bone_info = *iter; + makeJointAliases( *iter ); + } + + LLAvatarXmlInfo::attachment_info_list_t::iterator attach_iter; + for (attach_iter = sAvatarXmlInfo->mAttachmentInfoList.begin(); + attach_iter != sAvatarXmlInfo->mAttachmentInfoList.end(); + ++attach_iter) + { + LLAvatarXmlInfo::LLAvatarAttachmentInfo *info = *attach_iter; + std::string bone_name = info->mName; + + // Also accept the name with spaces substituted with + // underscores. This gives a mechanism for referencing such joints + // in daes, which don't allow spaces. + std::string sub_space_to_underscore = bone_name; + LLStringUtil::replaceChar(sub_space_to_underscore, ' ', '_'); + if (sub_space_to_underscore != bone_name) + { + mJointAliasMap[sub_space_to_underscore] = bone_name; + } + } + } + + return mJointAliasMap; +} + //----------------------------------------------------------------------------- // parseXmlSkeletonNode(): parses nodes from XML tree @@ -1663,7 +1880,7 @@ BOOL LLAvatarAppearance::LLAvatarXmlInfo::parseXmlSkeletonNode(LLXmlTreeNode* ro LLXmlTreeNode* node = root->getChildByName( "skeleton" ); if( !node ) { - llwarns << "avatar file: missing " << llendl; + LL_WARNS() << "avatar file: missing " << LL_ENDL; return FALSE; } @@ -1678,13 +1895,13 @@ BOOL LLAvatarAppearance::LLAvatarXmlInfo::parseXmlSkeletonNode(LLXmlTreeNode* ro { if (child->getChildByName("param_morph")) { - llwarns << "Can't specify morph param in skeleton definition." << llendl; + LL_WARNS() << "Can't specify morph param in skeleton definition." << LL_ENDL; } else { - llwarns << "Unknown param type." << llendl; + LL_WARNS() << "Unknown param type." << LL_ENDL; } - continue; + return FALSE; } LLPolySkeletalDistortionInfo *info = new LLPolySkeletalDistortionInfo; @@ -1707,17 +1924,17 @@ BOOL LLAvatarAppearance::LLAvatarXmlInfo::parseXmlSkeletonNode(LLXmlTreeNode* ro static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name"); if (!child->getFastAttributeString(name_string, info->mName)) { - llwarns << "No name supplied for attachment point." << llendl; + LL_WARNS() << "No name supplied for attachment point." << LL_ENDL; delete info; - continue; + return FALSE; } static LLStdStringHandle joint_string = LLXmlTree::addAttributeString("joint"); if (!child->getFastAttributeString(joint_string, info->mJointName)) { - llwarns << "No bone declared in attachment point " << info->mName << llendl; + LL_WARNS() << "No bone declared in attachment point " << info->mName << LL_ENDL; delete info; - continue; + return FALSE; } static LLStdStringHandle position_string = LLXmlTree::addAttributeString("position"); @@ -1741,9 +1958,9 @@ BOOL LLAvatarAppearance::LLAvatarXmlInfo::parseXmlSkeletonNode(LLXmlTreeNode* ro static LLStdStringHandle id_string = LLXmlTree::addAttributeString("id"); if (!child->getFastAttributeS32(id_string, info->mAttachmentID)) { - llwarns << "No id supplied for attachment point " << info->mName << llendl; + LL_WARNS() << "No id supplied for attachment point " << info->mName << LL_ENDL; delete info; - continue; + return FALSE; } static LLStdStringHandle slot_string = LLXmlTree::addAttributeString("pie_slice"); @@ -1776,7 +1993,7 @@ BOOL LLAvatarAppearance::LLAvatarXmlInfo::parseXmlMeshNodes(LLXmlTreeNode* root) static LLStdStringHandle type_string = LLXmlTree::addAttributeString("type"); if( !node->getFastAttributeString( type_string, info->mType ) ) { - llwarns << "Avatar file: is missing type attribute. Ignoring element. " << llendl; + LL_WARNS() << "Avatar file: is missing type attribute. Ignoring element. " << LL_ENDL; delete info; return FALSE; // Ignore this element } @@ -1784,7 +2001,7 @@ BOOL LLAvatarAppearance::LLAvatarXmlInfo::parseXmlMeshNodes(LLXmlTreeNode* root) static LLStdStringHandle lod_string = LLXmlTree::addAttributeString("lod"); if (!node->getFastAttributeS32( lod_string, info->mLOD )) { - llwarns << "Avatar file: is missing lod attribute. Ignoring element. " << llendl; + LL_WARNS() << "Avatar file: is missing lod attribute. Ignoring element. " << LL_ENDL; delete info; return FALSE; // Ignore this element } @@ -1792,7 +2009,7 @@ BOOL LLAvatarAppearance::LLAvatarXmlInfo::parseXmlMeshNodes(LLXmlTreeNode* root) static LLStdStringHandle file_name_string = LLXmlTree::addAttributeString("file_name"); if( !node->getFastAttributeString( file_name_string, info->mMeshFileName ) ) { - llwarns << "Avatar file: is missing file_name attribute. Ignoring: " << info->mType << llendl; + LL_WARNS() << "Avatar file: is missing file_name attribute. Ignoring: " << info->mType << LL_ENDL; delete info; return FALSE; // Ignore this element } @@ -1823,13 +2040,13 @@ BOOL LLAvatarAppearance::LLAvatarXmlInfo::parseXmlMeshNodes(LLXmlTreeNode* root) { if (child->getChildByName("param_skeleton")) { - llwarns << "Can't specify skeleton param in a mesh definition." << llendl; + LL_WARNS() << "Can't specify skeleton param in a mesh definition." << LL_ENDL; } else { - llwarns << "Unknown param type." << llendl; + LL_WARNS() << "Unknown param type." << LL_ENDL; } - continue; + return FALSE; } LLPolyMorphTargetInfo *morphinfo = new LLPolyMorphTargetInfo(); @@ -1868,14 +2085,14 @@ BOOL LLAvatarAppearance::LLAvatarXmlInfo::parseXmlColorNodes(LLXmlTreeNode* root { if (mTexSkinColorInfo) { - llwarns << "avatar file: multiple instances of skin_color" << llendl; + LL_WARNS() << "avatar file: multiple instances of skin_color" << LL_ENDL; return FALSE; } mTexSkinColorInfo = new LLTexGlobalColorInfo; if( !mTexSkinColorInfo->parseXml( color_node ) ) { - deleteAndClear(mTexSkinColorInfo); - llwarns << "avatar file: mTexSkinColor->parseXml() failed" << llendl; + delete_and_clear(mTexSkinColorInfo); + LL_WARNS() << "avatar file: mTexSkinColor->parseXml() failed" << LL_ENDL; return FALSE; } } @@ -1883,14 +2100,14 @@ BOOL LLAvatarAppearance::LLAvatarXmlInfo::parseXmlColorNodes(LLXmlTreeNode* root { if (mTexHairColorInfo) { - llwarns << "avatar file: multiple instances of hair_color" << llendl; + LL_WARNS() << "avatar file: multiple instances of hair_color" << LL_ENDL; return FALSE; } mTexHairColorInfo = new LLTexGlobalColorInfo; if( !mTexHairColorInfo->parseXml( color_node ) ) { - deleteAndClear(mTexHairColorInfo); - llwarns << "avatar file: mTexHairColor->parseXml() failed" << llendl; + delete_and_clear(mTexHairColorInfo); + LL_WARNS() << "avatar file: mTexHairColor->parseXml() failed" << LL_ENDL; return FALSE; } } @@ -1898,13 +2115,13 @@ BOOL LLAvatarAppearance::LLAvatarXmlInfo::parseXmlColorNodes(LLXmlTreeNode* root { if (mTexEyeColorInfo) { - llwarns << "avatar file: multiple instances of eye_color" << llendl; + LL_WARNS() << "avatar file: multiple instances of eye_color" << LL_ENDL; return FALSE; } mTexEyeColorInfo = new LLTexGlobalColorInfo; if( !mTexEyeColorInfo->parseXml( color_node ) ) { - llwarns << "avatar file: mTexEyeColor->parseXml() failed" << llendl; + LL_WARNS() << "avatar file: mTexEyeColor->parseXml() failed" << LL_ENDL; return FALSE; } } @@ -1930,7 +2147,7 @@ BOOL LLAvatarAppearance::LLAvatarXmlInfo::parseXmlLayerNodes(LLXmlTreeNode* root else { delete layer_info; - llwarns << "avatar file: layer_set->parseXml() failed" << llendl; + LL_WARNS() << "avatar file: layer_set->parseXml() failed" << LL_ENDL; return FALSE; } } @@ -1959,7 +2176,7 @@ BOOL LLAvatarAppearance::LLAvatarXmlInfo::parseXmlDriverNodes(LLXmlTreeNode* roo else { delete driver_info; - llwarns << "avatar file: driver_param->parseXml() failed" << llendl; + LL_WARNS() << "avatar file: driver_param->parseXml() failed" << LL_ENDL; return FALSE; } } @@ -1988,25 +2205,25 @@ BOOL LLAvatarAppearance::LLAvatarXmlInfo::parseXmlMorphNodes(LLXmlTreeNode* root static LLStdStringHandle name_string = LLXmlTree::addAttributeString("morph_name"); if (!grand_child->getFastAttributeString(name_string, info->mName)) { - llwarns << "No name supplied for morph mask." << llendl; + LL_WARNS() << "No name supplied for morph mask." << LL_ENDL; delete info; - continue; + return FALSE; } static LLStdStringHandle region_string = LLXmlTree::addAttributeString("body_region"); if (!grand_child->getFastAttributeString(region_string, info->mRegion)) { - llwarns << "No region supplied for morph mask." << llendl; + LL_WARNS() << "No region supplied for morph mask." << LL_ENDL; delete info; - continue; + return FALSE; } static LLStdStringHandle layer_string = LLXmlTree::addAttributeString("layer"); if (!grand_child->getFastAttributeString(layer_string, info->mLayer)) { - llwarns << "No layer supplied for morph mask." << llendl; + LL_WARNS() << "No layer supplied for morph mask." << LL_ENDL; delete info; - continue; + return FALSE; } // optional parameter. don't throw a warning if not present. diff --git a/indra/llappearance/llavatarappearance.h b/indra/llappearance/llavatarappearance.h index b3a02e4106..3fa4c35137 100644 --- a/indra/llappearance/llavatarappearance.h +++ b/indra/llappearance/llavatarappearance.h @@ -35,6 +35,7 @@ #include "llviewervisualparam.h" #include "llxmltree.h" +#include // class LLTexLayerSet; class LLTexGlobalColor; class LLTexGlobalColorInfo; @@ -66,9 +67,11 @@ class LLAvatarAppearance : public LLCharacter LLAvatarAppearance(LLWearableData* wearable_data); virtual ~LLAvatarAppearance(); + static void initClass(const std::string& avatar_file_name, const std::string& skeleton_file_name); // initializes static members static void initClass(); // initializes static members static void cleanupClass(); // Cleanup data that's only init'd once per class. virtual void initInstance(); // Called after construction to initialize the instance. + S32 mInitFlags; virtual BOOL loadSkeletonNode(); BOOL loadMeshNodes(); BOOL loadLayersets(); @@ -91,7 +94,7 @@ class LLAvatarAppearance : public LLCharacter /*virtual*/ const char* getAnimationPrefix() { return "avatar"; } /*virtual*/ LLVector3 getVolumePos(S32 joint_index, LLVector3& volume_offset); - /*virtual*/ LLJoint* findCollisionVolume(U32 volume_id); + /*virtual*/ LLJoint* findCollisionVolume(S32 volume_id); /*virtual*/ S32 getCollisionVolumeID(std::string &name); /*virtual*/ LLPolyMesh* getHeadMesh(); /*virtual*/ LLPolyMesh* getUpperBodyMesh(); @@ -132,6 +135,7 @@ class LLAvatarAppearance : public LLCharacter virtual LLAvatarJoint* createAvatarJoint() = 0; virtual LLAvatarJoint* createAvatarJoint(S32 joint_num) = 0; virtual LLAvatarJointMesh* createAvatarJointMesh() = 0; + void makeJointAliases(LLAvatarBoneInfo *bone_info); public: F32 getPelvisToFoot() const { return mPelvisToFoot; } /*virtual*/ LLJoint* getRootJoint() { return mRoot; } @@ -139,17 +143,27 @@ class LLAvatarAppearance : public LLCharacter LLVector3 mHeadOffset; // current head position LLAvatarJoint *mRoot; - typedef std::map joint_map_t; + typedef std::vector > joint_map_t; joint_map_t mJointMap; - + + typedef std::map joint_state_map_t; + joint_state_map_t mLastBodySizeState; + joint_state_map_t mCurrBodySizeState; + void compareJointStateMaps(joint_state_map_t& last_state, + joint_state_map_t& curr_state); void computeBodySize(); +public: + typedef std::vector avatar_joint_list_t; + const avatar_joint_list_t& getSkeleton() { return mSkeleton; } + typedef std::map joint_alias_map_t; + const joint_alias_map_t& getJointAliases(); + protected: static BOOL parseSkeletonFile(const std::string& filename); virtual void buildCharacter(); virtual BOOL loadAvatar(); - virtual void bodySizeChanged() = 0; BOOL setupBone(const LLAvatarBoneInfo* info, LLJoint* parent, S32 ¤t_volume_num, S32 ¤t_joint_num); BOOL allocateCharacterJoints(U32 num); @@ -157,13 +171,20 @@ class LLAvatarAppearance : public LLCharacter protected: void clearSkeleton(); BOOL mIsBuilt; // state of deferred character building - typedef std::vector avatar_joint_list_t; + avatar_joint_list_t mSkeleton; - + LLVector3OverrideMap mPelvisFixups; + joint_alias_map_t mJointAliasMap; + //-------------------------------------------------------------------- // Pelvis height adjustment members. //-------------------------------------------------------------------- public: + void addPelvisFixup( F32 fixup, const LLUUID& mesh_id ); + void removePelvisFixup( const LLUUID& mesh_id ); + bool hasPelvisFixup( F32& fixup, LLUUID& mesh_id ) const; + bool hasPelvisFixup( F32& fixup ) const; + LLVector3 mBodySize; LLVector3 mAvatarOffset; protected: @@ -213,7 +234,7 @@ class LLAvatarAppearance : public LLCharacter ** RENDERING **/ public: - BOOL mIsDummy; // for special views + BOOL mIsDummy; // for special views and animated object controllers; local to viewer //-------------------------------------------------------------------- // Morph masks @@ -262,7 +283,7 @@ class LLAvatarAppearance : public LLCharacter // Clothing colors (convenience functions to access visual parameters) //-------------------------------------------------------------------- public: - void setClothesColor(LLAvatarAppearanceDefines::ETextureIndex te, const LLColor4& new_color, BOOL upload_bake); + void setClothesColor(LLAvatarAppearanceDefines::ETextureIndex te, const LLColor4& new_color, bool upload_bake = false); LLColor4 getClothesColor(LLAvatarAppearanceDefines::ETextureIndex te); static BOOL teToColorParams(LLAvatarAppearanceDefines::ETextureIndex te, U32 *param_name); @@ -271,7 +292,7 @@ class LLAvatarAppearance : public LLCharacter //-------------------------------------------------------------------- public: LLColor4 getGlobalColor(const std::string& color_name ) const; - virtual void onGlobalColorChanged(const LLTexGlobalColor* global_color, BOOL upload_bake) = 0; + virtual void onGlobalColorChanged(const LLTexGlobalColor* global_color, bool upload_bake = false) = 0; protected: LLTexGlobalColor* mTexSkinColor; LLTexGlobalColor* mTexHairColor; @@ -320,7 +341,7 @@ class LLAvatarAppearance : public LLCharacter bool mIsLoaded; bool mIsUsed; LLAvatarAppearanceDefines::ETextureIndex mTextureIndex; - U32 mMaskTexName; + LLImageGL::GLTextureName mMaskTexName; // Stores pointers to the joint meshes that this baked texture deals with avatar_joint_mesh_list_t mJointMeshes; morph_list_t mMaskedMorphs; @@ -337,8 +358,8 @@ class LLAvatarAppearance : public LLCharacter // Collision volumes //-------------------------------------------------------------------- public: - S32 mNumCollisionVolumes; - LLAvatarJointCollisionVolume* mCollisionVolumes; + S32 mNumBones; + std::vector mCollisionVolumes; protected: BOOL allocateCollisionVolumes(U32 num); diff --git a/indra/llappearance/llavatarappearancedefines.cpp b/indra/llappearance/llavatarappearancedefines.cpp index f1c78946a1..5f3c7cdaad 100644 --- a/indra/llappearance/llavatarappearancedefines.cpp +++ b/indra/llappearance/llavatarappearancedefines.cpp @@ -27,8 +27,11 @@ #include "linden_common.h" #include "llavatarappearancedefines.h" -const S32 LLAvatarAppearanceDefines::SCRATCH_TEX_WIDTH = 512; -const S32 LLAvatarAppearanceDefines::SCRATCH_TEX_HEIGHT = 512; +#include "indra_constants.h" +#include + +const S32 LLAvatarAppearanceDefines::SCRATCH_TEX_WIDTH = 1024; +const S32 LLAvatarAppearanceDefines::SCRATCH_TEX_HEIGHT = 1024; const S32 LLAvatarAppearanceDefines::IMPOSTOR_PERIOD = 2; using namespace LLAvatarAppearanceDefines; @@ -65,12 +68,30 @@ LLAvatarAppearanceDictionary::Textures::Textures() addEntry(TEX_UPPER_TATTOO, new TextureEntry("upper_tattoo", TRUE, BAKED_NUM_INDICES, "", LLWearableType::WT_TATTOO)); addEntry(TEX_LOWER_TATTOO, new TextureEntry("lower_tattoo", TRUE, BAKED_NUM_INDICES, "", LLWearableType::WT_TATTOO)); + addEntry(TEX_HEAD_UNIVERSAL_TATTOO, new TextureEntry("head_universal_tattoo", TRUE, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL)); + addEntry(TEX_UPPER_UNIVERSAL_TATTOO, new TextureEntry("upper_universal_tattoo", TRUE, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL)); + addEntry(TEX_LOWER_UNIVERSAL_TATTOO, new TextureEntry("lower_universal_tattoo", TRUE, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL)); + addEntry(TEX_SKIRT_TATTOO, new TextureEntry("skirt_tattoo", TRUE, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL)); + addEntry(TEX_HAIR_TATTOO, new TextureEntry("hair_tattoo", TRUE, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL)); + addEntry(TEX_EYES_TATTOO, new TextureEntry("eyes_tattoo", TRUE, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL)); + addEntry(TEX_LEFT_ARM_TATTOO, new TextureEntry("leftarm_tattoo", TRUE, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL)); + addEntry(TEX_LEFT_LEG_TATTOO, new TextureEntry("leftleg_tattoo", TRUE, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL)); + addEntry(TEX_AUX1_TATTOO, new TextureEntry("aux1_tattoo", TRUE, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL)); + addEntry(TEX_AUX2_TATTOO, new TextureEntry("aux2_tattoo", TRUE, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL)); + addEntry(TEX_AUX3_TATTOO, new TextureEntry("aux3_tattoo", TRUE, BAKED_NUM_INDICES, "", LLWearableType::WT_UNIVERSAL)); + + addEntry(TEX_HEAD_BAKED, new TextureEntry("head-baked", FALSE, BAKED_HEAD, "head")); addEntry(TEX_UPPER_BAKED, new TextureEntry("upper-baked", FALSE, BAKED_UPPER, "upper")); addEntry(TEX_LOWER_BAKED, new TextureEntry("lower-baked", FALSE, BAKED_LOWER, "lower")); addEntry(TEX_EYES_BAKED, new TextureEntry("eyes-baked", FALSE, BAKED_EYES, "eyes")); addEntry(TEX_HAIR_BAKED, new TextureEntry("hair-baked", FALSE, BAKED_HAIR, "hair")); addEntry(TEX_SKIRT_BAKED, new TextureEntry("skirt-baked", FALSE, BAKED_SKIRT, "skirt")); + addEntry(TEX_LEFT_ARM_BAKED, new TextureEntry("leftarm-baked", FALSE, BAKED_LEFT_ARM, "leftarm")); + addEntry(TEX_LEFT_LEG_BAKED, new TextureEntry("leftleg-baked", FALSE, BAKED_LEFT_LEG, "leftleg")); + addEntry(TEX_AUX1_BAKED, new TextureEntry("aux1-baked", FALSE, BAKED_AUX1, "aux1")); + addEntry(TEX_AUX2_BAKED, new TextureEntry("aux2-baked", FALSE, BAKED_AUX2, "aux2")); + addEntry(TEX_AUX3_BAKED, new TextureEntry("aux3-baked", FALSE, BAKED_AUX3, "aux3")); } LLAvatarAppearanceDictionary::BakedTextures::BakedTextures() @@ -78,35 +99,60 @@ LLAvatarAppearanceDictionary::BakedTextures::BakedTextures() // Baked textures addEntry(BAKED_HEAD, new BakedEntry(TEX_HEAD_BAKED, "head", "a4b9dc38-e13b-4df9-b284-751efb0566ff", - 3, TEX_HEAD_BODYPAINT, TEX_HEAD_TATTOO, TEX_HEAD_ALPHA, - 5, LLWearableType::WT_SHAPE, LLWearableType::WT_SKIN, LLWearableType::WT_HAIR, LLWearableType::WT_TATTOO, LLWearableType::WT_ALPHA)); + 4, TEX_HEAD_BODYPAINT, TEX_HEAD_TATTOO, TEX_HEAD_ALPHA, TEX_HEAD_UNIVERSAL_TATTOO, + 6, LLWearableType::WT_SHAPE, LLWearableType::WT_SKIN, LLWearableType::WT_HAIR, LLWearableType::WT_TATTOO, LLWearableType::WT_ALPHA, LLWearableType::WT_UNIVERSAL)); addEntry(BAKED_UPPER, new BakedEntry(TEX_UPPER_BAKED, "upper_body", "5943ff64-d26c-4a90-a8c0-d61f56bd98d4", - 7, TEX_UPPER_SHIRT,TEX_UPPER_BODYPAINT, TEX_UPPER_JACKET, - TEX_UPPER_GLOVES, TEX_UPPER_UNDERSHIRT, TEX_UPPER_TATTOO, TEX_UPPER_ALPHA, - 8, LLWearableType::WT_SHAPE, LLWearableType::WT_SKIN, LLWearableType::WT_SHIRT, LLWearableType::WT_JACKET, LLWearableType::WT_GLOVES, LLWearableType::WT_UNDERSHIRT, LLWearableType::WT_TATTOO, LLWearableType::WT_ALPHA)); + 8, TEX_UPPER_SHIRT,TEX_UPPER_BODYPAINT, TEX_UPPER_JACKET, + TEX_UPPER_GLOVES, TEX_UPPER_UNDERSHIRT, TEX_UPPER_TATTOO, TEX_UPPER_ALPHA, TEX_UPPER_UNIVERSAL_TATTOO, + 9, LLWearableType::WT_SHAPE, LLWearableType::WT_SKIN, LLWearableType::WT_SHIRT, LLWearableType::WT_JACKET, LLWearableType::WT_GLOVES, LLWearableType::WT_UNDERSHIRT, LLWearableType::WT_TATTOO, LLWearableType::WT_ALPHA, LLWearableType::WT_UNIVERSAL)); addEntry(BAKED_LOWER, new BakedEntry(TEX_LOWER_BAKED, "lower_body", "2944ee70-90a7-425d-a5fb-d749c782ed7d", - 8, TEX_LOWER_PANTS,TEX_LOWER_BODYPAINT,TEX_LOWER_SHOES, TEX_LOWER_SOCKS, - TEX_LOWER_JACKET, TEX_LOWER_UNDERPANTS, TEX_LOWER_TATTOO, TEX_LOWER_ALPHA, - 9, LLWearableType::WT_SHAPE, LLWearableType::WT_SKIN, LLWearableType::WT_PANTS, LLWearableType::WT_SHOES, LLWearableType::WT_SOCKS, LLWearableType::WT_JACKET, LLWearableType::WT_UNDERPANTS, LLWearableType::WT_TATTOO, LLWearableType::WT_ALPHA)); + 9, TEX_LOWER_PANTS,TEX_LOWER_BODYPAINT,TEX_LOWER_SHOES, TEX_LOWER_SOCKS, + TEX_LOWER_JACKET, TEX_LOWER_UNDERPANTS, TEX_LOWER_TATTOO, TEX_LOWER_ALPHA, TEX_LOWER_UNIVERSAL_TATTOO, + 10, LLWearableType::WT_SHAPE, LLWearableType::WT_SKIN, LLWearableType::WT_PANTS, LLWearableType::WT_SHOES, LLWearableType::WT_SOCKS, LLWearableType::WT_JACKET, LLWearableType::WT_UNDERPANTS, LLWearableType::WT_TATTOO, LLWearableType::WT_ALPHA, LLWearableType::WT_UNIVERSAL)); addEntry(BAKED_EYES, new BakedEntry(TEX_EYES_BAKED, "eyes", "27b1bc0f-979f-4b13-95fe-b981c2ba9788", - 2, TEX_EYES_IRIS, TEX_EYES_ALPHA, - 2, LLWearableType::WT_EYES, LLWearableType::WT_ALPHA)); + 3, TEX_EYES_IRIS, TEX_EYES_TATTOO, TEX_EYES_ALPHA, + 3, LLWearableType::WT_EYES, LLWearableType::WT_UNIVERSAL, LLWearableType::WT_ALPHA)); addEntry(BAKED_SKIRT, new BakedEntry(TEX_SKIRT_BAKED, "skirt", "03e7e8cb-1368-483b-b6f3-74850838ba63", - 1, TEX_SKIRT, - 1, LLWearableType::WT_SKIRT)); + 2, TEX_SKIRT, TEX_SKIRT_TATTOO, + 2, LLWearableType::WT_SKIRT, LLWearableType::WT_UNIVERSAL )); addEntry(BAKED_HAIR, new BakedEntry(TEX_HAIR_BAKED, "hair", "a60e85a9-74e8-48d8-8a2d-8129f28d9b61", - 2, TEX_HAIR, TEX_HAIR_ALPHA, - 2, LLWearableType::WT_HAIR, LLWearableType::WT_ALPHA)); + 3, TEX_HAIR, TEX_HAIR_TATTOO, TEX_HAIR_ALPHA, + 3, LLWearableType::WT_HAIR, LLWearableType::WT_UNIVERSAL, LLWearableType::WT_ALPHA)); + + addEntry(BAKED_LEFT_ARM, new BakedEntry(TEX_LEFT_ARM_BAKED, + "leftarm", "9f39febf-22d7-0087-79d1-e9e8c6c9ed19", + 1, TEX_LEFT_ARM_TATTOO, + 1, LLWearableType::WT_UNIVERSAL)); + + addEntry(BAKED_LEFT_LEG, new BakedEntry(TEX_LEFT_LEG_BAKED, + "leftleg", "054a7a58-8ed5-6386-0add-3b636fb28b78", + 1, TEX_LEFT_LEG_TATTOO, + 1, LLWearableType::WT_UNIVERSAL)); + + addEntry(BAKED_AUX1, new BakedEntry(TEX_AUX1_BAKED, + "aux1", "790c11be-b25c-c17e-b4d2-6a4ad786b752", + 1, TEX_AUX1_TATTOO, + 1, LLWearableType::WT_UNIVERSAL)); + + addEntry(BAKED_AUX2, new BakedEntry(TEX_AUX2_BAKED, + "aux2", "d78c478f-48c7-5928-5864-8d99fb1f521e", + 1, TEX_AUX2_TATTOO, + 1, LLWearableType::WT_UNIVERSAL)); + + addEntry(BAKED_AUX3, new BakedEntry(TEX_AUX3_BAKED, + "aux3", "6a95dd53-edd9-aac8-f6d3-27ed99f3c3eb", + 1, TEX_AUX3_TATTOO, + 1, LLWearableType::WT_UNIVERSAL)); } LLAvatarAppearanceDictionary::MeshEntries::MeshEntries() @@ -140,7 +186,7 @@ LLAvatarAppearanceDictionary::~LLAvatarAppearanceDictionary() // map it to the baked texture. void LLAvatarAppearanceDictionary::createAssociations() { - for (BakedTextures::const_iterator iter = mBakedTextures.begin(); iter != mBakedTextures.end(); iter++) + for (BakedTextures::const_iterator iter = mBakedTextures.begin(); iter != mBakedTextures.end(); ++iter) { const EBakedTextureIndex baked_index = (iter->first); const BakedEntry *dict = (iter->second); @@ -149,7 +195,7 @@ void LLAvatarAppearanceDictionary::createAssociations() // with this baked texture index. for (texture_vec_t::const_iterator local_texture_iter = dict->mLocalTextures.begin(); local_texture_iter != dict->mLocalTextures.end(); - local_texture_iter++) + ++local_texture_iter) { const ETextureIndex local_texture_index = (ETextureIndex) *local_texture_iter; mTextures[local_texture_index]->mIsUsedByBakedTexture = true; @@ -212,6 +258,7 @@ LLAvatarAppearanceDictionary::BakedEntry::BakedEntry(ETextureIndex tex_index, LLWearableType::EType t = (LLWearableType::EType)va_arg(argp,int); mWearables.push_back(t); } + va_end(argp); } // static @@ -221,7 +268,7 @@ ETextureIndex LLAvatarAppearanceDictionary::bakedToLocalTextureIndex(EBakedTextu } // static -EBakedTextureIndex LLAvatarAppearanceDictionary::findBakedByRegionName(std::string name) +EBakedTextureIndex LLAvatarAppearanceDictionary::findBakedByRegionName(const std::string& name) { U8 index = 0; while (index < BAKED_NUM_INDICES) @@ -239,7 +286,7 @@ EBakedTextureIndex LLAvatarAppearanceDictionary::findBakedByRegionName(std::stri } // static -EBakedTextureIndex LLAvatarAppearanceDictionary::findBakedByImageName(std::string name) +EBakedTextureIndex LLAvatarAppearanceDictionary::findBakedByImageName(const std::string& name) { U8 index = 0; while (index < BAKED_NUM_INDICES) @@ -266,3 +313,112 @@ LLWearableType::EType LLAvatarAppearanceDictionary::getTEWearableType(ETextureIn return getInstance()->getTexture(index)->mWearableType; } +// static +BOOL LLAvatarAppearanceDictionary::isBakedImageId(const LLUUID& id) +{ + if ((id == IMG_USE_BAKED_EYES) || (id == IMG_USE_BAKED_HAIR) || (id == IMG_USE_BAKED_HEAD) || (id == IMG_USE_BAKED_LOWER) || (id == IMG_USE_BAKED_SKIRT) || (id == IMG_USE_BAKED_UPPER) + || (id == IMG_USE_BAKED_LEFTARM) || (id == IMG_USE_BAKED_LEFTLEG) || (id == IMG_USE_BAKED_AUX1) || (id == IMG_USE_BAKED_AUX2) || (id == IMG_USE_BAKED_AUX3) ) + { + return TRUE; + } + + return FALSE; +} + +// static +EBakedTextureIndex LLAvatarAppearanceDictionary::assetIdToBakedTextureIndex(const LLUUID& id) +{ + if (id == IMG_USE_BAKED_EYES) + { + return BAKED_EYES; + } + else if (id == IMG_USE_BAKED_HAIR) + { + return BAKED_HAIR; + } + else if (id == IMG_USE_BAKED_HEAD) + { + return BAKED_HEAD; + } + else if (id == IMG_USE_BAKED_LOWER) + { + return BAKED_LOWER; + } + else if (id == IMG_USE_BAKED_SKIRT) + { + return BAKED_SKIRT; + } + else if (id == IMG_USE_BAKED_UPPER) + { + return BAKED_UPPER; + } + else if (id == IMG_USE_BAKED_LEFTARM) + { + return BAKED_LEFT_ARM; + } + else if (id == IMG_USE_BAKED_LEFTLEG) + { + return BAKED_LEFT_LEG; + } + else if (id == IMG_USE_BAKED_AUX1) + { + return BAKED_AUX1; + } + else if (id == IMG_USE_BAKED_AUX2) + { + return BAKED_AUX2; + } + else if (id == IMG_USE_BAKED_AUX3) + { + return BAKED_AUX3; + } + + return BAKED_NUM_INDICES; +} + +//static +LLUUID LLAvatarAppearanceDictionary::localTextureIndexToMagicId(ETextureIndex t) +{ + LLUUID id = LLUUID::null; + + switch (t) + { + case LLAvatarAppearanceDefines::TEX_HEAD_BAKED: + id = IMG_USE_BAKED_HEAD; + break; + case LLAvatarAppearanceDefines::TEX_UPPER_BAKED: + id = IMG_USE_BAKED_UPPER; + break; + case LLAvatarAppearanceDefines::TEX_LOWER_BAKED: + id = IMG_USE_BAKED_LOWER; + break; + case LLAvatarAppearanceDefines::TEX_EYES_BAKED: + id = IMG_USE_BAKED_EYES; + break; + case LLAvatarAppearanceDefines::TEX_SKIRT_BAKED: + id = IMG_USE_BAKED_SKIRT; + break; + case LLAvatarAppearanceDefines::TEX_HAIR_BAKED: + id = IMG_USE_BAKED_HAIR; + break; + case LLAvatarAppearanceDefines::TEX_LEFT_ARM_BAKED: + id = IMG_USE_BAKED_LEFTARM; + break; + case LLAvatarAppearanceDefines::TEX_LEFT_LEG_BAKED: + id = IMG_USE_BAKED_LEFTLEG; + break; + case LLAvatarAppearanceDefines::TEX_AUX1_BAKED: + id = IMG_USE_BAKED_AUX1; + break; + case LLAvatarAppearanceDefines::TEX_AUX2_BAKED: + id = IMG_USE_BAKED_AUX2; + break; + case LLAvatarAppearanceDefines::TEX_AUX3_BAKED: + id = IMG_USE_BAKED_AUX3; + break; + default: + break; + } + + return id; +} diff --git a/indra/llappearance/llavatarappearancedefines.h b/indra/llappearance/llavatarappearancedefines.h index 8a1d2c4707..444af9c050 100644 --- a/indra/llappearance/llavatarappearancedefines.h +++ b/indra/llappearance/llavatarappearancedefines.h @@ -1,3 +1,4 @@ + /** * @file llavatarappearancedefines.h * @brief Various LLAvatarAppearance related definitions @@ -78,6 +79,22 @@ enum ETextureIndex TEX_HEAD_TATTOO, TEX_UPPER_TATTOO, TEX_LOWER_TATTOO, + 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, + TEX_LEFT_ARM_BAKED, // Pre-composited + TEX_LEFT_LEG_BAKED, // Pre-composited + TEX_AUX1_BAKED, // Pre-composited + TEX_AUX2_BAKED, // Pre-composited + TEX_AUX3_BAKED, // Pre-composited TEX_NUM_INDICES }; @@ -89,6 +106,11 @@ enum EBakedTextureIndex BAKED_EYES, BAKED_SKIRT, BAKED_HAIR, + BAKED_LEFT_ARM, + BAKED_LEFT_LEG, + BAKED_AUX1, + BAKED_AUX2, + BAKED_AUX3, BAKED_NUM_INDICES }; @@ -218,12 +240,15 @@ class LLAvatarAppearanceDictionary : public LLSingletonsetValid(valid, TRUE); + LLAvatarJoint* joint = dynamic_cast(*iter); + if (joint) + joint->setValid(valid, TRUE); } } @@ -124,7 +124,8 @@ void LLAvatarJoint::setSkeletonComponents( U32 comp, BOOL recursive ) iter != mChildren.end(); ++iter) { LLAvatarJoint* joint = dynamic_cast(*iter); - joint->setSkeletonComponents(comp, recursive); + if (joint) + joint->setSkeletonComponents(comp, recursive); } } } @@ -138,8 +139,9 @@ void LLAvatarJoint::setVisible(BOOL visible, BOOL recursive) for (child_list_t::iterator iter = mChildren.begin(); iter != mChildren.end(); ++iter) { - LLAvatarJoint* joint = (LLAvatarJoint*)(*iter); - joint->setVisible(visible, recursive); + LLAvatarJoint* joint = dynamic_cast(*iter); + if(joint) + joint->setVisible(visible, recursive); } } } @@ -150,7 +152,8 @@ void LLAvatarJoint::updateFaceSizes(U32 &num_vertices, U32& num_indices, F32 pix iter != mChildren.end(); ++iter) { LLAvatarJoint* joint = dynamic_cast(*iter); - joint->updateFaceSizes(num_vertices, num_indices, pixel_area); + if (joint) + joint->updateFaceSizes(num_vertices, num_indices, pixel_area); } } @@ -160,7 +163,8 @@ void LLAvatarJoint::updateFaceData(LLFace *face, F32 pixel_area, BOOL damp_wind, iter != mChildren.end(); ++iter) { LLAvatarJoint* joint = dynamic_cast(*iter); - joint->updateFaceData(face, pixel_area, damp_wind, terse_update); + if (joint) + joint->updateFaceData(face, pixel_area, damp_wind, terse_update); } } @@ -170,7 +174,8 @@ void LLAvatarJoint::updateJointGeometry() iter != mChildren.end(); ++iter) { LLAvatarJoint* joint = dynamic_cast(*iter); - joint->updateJointGeometry(); + if (joint) + joint->updateJointGeometry(); } } @@ -184,23 +189,26 @@ BOOL LLAvatarJoint::updateLOD(F32 pixel_area, BOOL activate) iter != mChildren.end(); ++iter) { LLAvatarJoint* joint = dynamic_cast(*iter); - F32 jointLOD = joint->getLOD(); - - if (found_lod || jointLOD == DEFAULT_AVATAR_JOINT_LOD) + if (joint) { - // we've already found a joint to enable, so enable the rest as alternatives - lod_changed |= joint->updateLOD(pixel_area, TRUE); - } - else - { - if (pixel_area >= jointLOD || sDisableLOD) + F32 jointLOD = joint->getLOD(); + + if (found_lod || jointLOD == DEFAULT_AVATAR_JOINT_LOD) { + // we've already found a joint to enable, so enable the rest as alternatives lod_changed |= joint->updateLOD(pixel_area, TRUE); - found_lod = TRUE; } else { - lod_changed |= joint->updateLOD(pixel_area, FALSE); + if (pixel_area >= jointLOD || sDisableLOD) + { + lod_changed |= joint->updateLOD(pixel_area, TRUE); + found_lod = TRUE; + } + else + { + lod_changed |= joint->updateLOD(pixel_area, FALSE); + } } } } @@ -213,7 +221,8 @@ void LLAvatarJoint::dump() iter != mChildren.end(); ++iter) { LLAvatarJoint* joint = dynamic_cast(*iter); - joint->dump(); + if (joint) + joint->dump(); } } @@ -222,7 +231,7 @@ void LLAvatarJoint::setMeshesToChildren() { removeAllChildren(); for (avatar_joint_mesh_list_t::iterator iter = mMeshParts.begin(); - iter != mMeshParts.end(); iter++) + iter != mMeshParts.end(); ++iter) { addChild((*iter)); } @@ -239,7 +248,7 @@ LLAvatarJointCollisionVolume::LLAvatarJointCollisionVolume() /*virtual*/ U32 LLAvatarJointCollisionVolume::render( F32 pixelArea, BOOL first_pass, BOOL is_dummy ) { - llerrs << "Cannot call render() on LLAvatarJointCollisionVolume" << llendl; + LL_ERRS() << "Cannot call render() on LLAvatarJointCollisionVolume" << LL_ENDL; return 0; } @@ -260,7 +269,7 @@ void LLAvatarJointCollisionVolume::renderCollision() updateWorldMatrix(); gGL.pushMatrix(); - gGL.multMatrix( &mXform.getWorldMatrix().mMatrix[0][0] ); + gGL.multMatrix( mXform.getWorldMatrix() ); gGL.diffuseColor3f( 0.f, 0.f, 1.f ); diff --git a/indra/llappearance/llavatarjoint.h b/indra/llappearance/llavatarjoint.h index fec91503c7..95d5a124b8 100644 --- a/indra/llappearance/llavatarjoint.h +++ b/indra/llappearance/llavatarjoint.h @@ -52,7 +52,7 @@ class LLAvatarJoint : virtual ~LLAvatarJoint(); // Gets the validity of this joint - BOOL getValid() { return mValid; } + bool getValid() const { return mValid; } // Sets the validity of this joint virtual void setValid( BOOL valid, BOOL recursive=FALSE ); @@ -127,6 +127,16 @@ class LLAvatarJointCollisionVolume : public LLAvatarJoint LLAvatarJointCollisionVolume(); virtual ~LLAvatarJointCollisionVolume() {}; + void* operator new(size_t size) + { + return ll_aligned_malloc_16(size); + } + + void operator delete(void* ptr) + { + ll_aligned_free_16(ptr); + } + /*virtual*/ BOOL inheritScale() { return TRUE; } /*virtual*/ U32 render( F32 pixelArea, BOOL first_pass = TRUE, BOOL is_dummy = FALSE ); diff --git a/indra/llappearance/llavatarjointmesh.cpp b/indra/llappearance/llavatarjointmesh.cpp index 4a5cff1dc3..2cfcac4c18 100644 --- a/indra/llappearance/llavatarjointmesh.cpp +++ b/indra/llappearance/llavatarjointmesh.cpp @@ -57,6 +57,41 @@ #include "llmatrix4a.h" +// Utility functions added with Bento to simplify handling of extra +// spine joints, or other new joints internal to the original +// skeleton, and unknown to the system avatar. + +//----------------------------------------------------------------------------- +// getBaseSkeletonAncestor() +//----------------------------------------------------------------------------- +LLJoint *getBaseSkeletonAncestor(LLJoint* joint) +{ + LLJoint *ancestor = joint->getParent(); + while (ancestor->getParent() && (ancestor->getSupport() != LLJoint::SUPPORT_BASE)) + { + LL_DEBUGS("Avatar") << "skipping non-base ancestor " << ancestor->getName() << LL_ENDL; + ancestor = ancestor->getParent(); + } + return ancestor; +} + +//----------------------------------------------------------------------------- +// totalSkinOffset() +//----------------------------------------------------------------------------- +LLVector3 totalSkinOffset(LLJoint *joint) +{ + LLVector3 totalOffset; + while (joint) + { + if (joint->getSupport() == LLJoint::SUPPORT_BASE) + { + totalOffset += joint->getSkinOffset(); + } + joint = joint->getParent(); + } + return totalOffset; +} + //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // LLAvatarJointMesh::LLSkinJoint @@ -83,28 +118,22 @@ LLSkinJoint::~LLSkinJoint() //----------------------------------------------------------------------------- // LLSkinJoint::setupSkinJoint() //----------------------------------------------------------------------------- -BOOL LLSkinJoint::setupSkinJoint( LLAvatarJoint *joint) +BOOL LLSkinJoint::setupSkinJoint( LLJoint *joint) { // find the named joint - mJoint = joint; - if ( !mJoint ) + if (!(mJoint = dynamic_cast(joint))) { - llinfos << "Can't find joint" << llendl; + LL_INFOS() << "Can't find joint" << LL_ENDL; + return FALSE; } // compute the inverse root skin matrix - mRootToJointSkinOffset.clearVec(); - - LLVector3 rootSkinOffset; - while (joint) - { - rootSkinOffset += joint->getSkinOffset(); - joint = (LLAvatarJoint*)joint->getParent(); - } + mRootToJointSkinOffset = totalSkinOffset(mJoint); + mRootToJointSkinOffset = -mRootToJointSkinOffset; - mRootToJointSkinOffset = -rootSkinOffset; - mRootToParentJointSkinOffset = mRootToJointSkinOffset; - mRootToParentJointSkinOffset += mJoint->getSkinOffset(); + //mRootToParentJointSkinOffset = totalSkinOffset((LLAvatarJoint*)joint->getParent()); + mRootToParentJointSkinOffset = totalSkinOffset(getBaseSkeletonAncestor(mJoint)); + mRootToParentJointSkinOffset = -mRootToParentJointSkinOffset; return TRUE; } @@ -306,30 +335,27 @@ void LLAvatarJointMesh::setMesh( LLPolyMesh *mesh ) U32 jn; for (jn = 0; jn < numJointNames; jn++) { - //llinfos << "Setting up joint " << jointNames[jn] << llendl; - LLAvatarJoint* joint = (LLAvatarJoint*)(getRoot()->findJoint(jointNames[jn]) ); - mSkinJoints[jn].setupSkinJoint( joint ); + //LL_INFOS() << "Setting up joint " << jointNames[jn] << LL_ENDL; + mSkinJoints[jn].setupSkinJoint( getRoot()->findJoint(jointNames[jn]) ); } } // setup joint array if (!mMesh->isLOD()) { - setupJoint((LLAvatarJoint*)getRoot()); + setupJoint(getRoot()); + LL_DEBUGS("Avatar") << getName() << " joint render entries: " << mMesh->mJointRenderData.size() << LL_ENDL; } -// llinfos << "joint render entries: " << mMesh->mJointRenderData.count() << llendl; } //----------------------------------------------------------------------------- // setupJoint() //----------------------------------------------------------------------------- -void LLAvatarJointMesh::setupJoint(LLAvatarJoint* current_joint) +void LLAvatarJointMesh::setupJoint(LLJoint* current_joint) { -// llinfos << "Mesh: " << getName() << llendl; - -// S32 joint_count = 0; U32 sj; + for (sj=0; sjgetName() << " matches skinjoint " << sj << LL_ENDL; // is the last joint in the array our parent? - if(mMesh->mJointRenderData.count() && mMesh->mJointRenderData[mMesh->mJointRenderData.count() - 1]->mWorldMatrix == ¤t_joint->getParent()->getWorldMatrix()) + + std::vector &jrd = mMesh->mJointRenderData; + + // SL-287 - need to update this so the results are the same if + // additional extended-skeleton joints lie between this joint + // and the original parent. + LLJoint *ancestor = getBaseSkeletonAncestor(current_joint); + if(jrd.size() && jrd.back()->mWorldMatrix == &ancestor->getWorldMatrix()) { // ...then just add ourselves - LLAvatarJoint* jointp = js.mJoint; - mMesh->mJointRenderData.put(new LLJointRenderData(&jointp->getWorldMatrix(), &js)); -// llinfos << "joint " << joint_count << js.mJoint->getName() << llendl; -// joint_count++; + LLJoint* jointp = js.mJoint; + jrd.push_back(new LLJointRenderData(&jointp->getWorldMatrix(), &js)); + LL_DEBUGS("Avatar") << "add joint[" << (jrd.size()-1) << "] = " << js.mJoint->getName() << LL_ENDL; } - // otherwise add our parent and ourselves + // otherwise add our ancestor and ourselves else { - mMesh->mJointRenderData.put(new LLJointRenderData(¤t_joint->getParent()->getWorldMatrix(), NULL)); -// llinfos << "joint " << joint_count << current_joint->getParent()->getName() << llendl; -// joint_count++; - mMesh->mJointRenderData.put(new LLJointRenderData(¤t_joint->getWorldMatrix(), &js)); -// llinfos << "joint " << joint_count << current_joint->getName() << llendl; -// joint_count++; + jrd.push_back(new LLJointRenderData(&ancestor->getWorldMatrix(), NULL)); + LL_DEBUGS("Avatar") << "add2 ancestor joint[" << (jrd.size()-1) << "] = " << ancestor->getName() << LL_ENDL; + jrd.push_back(new LLJointRenderData(¤t_joint->getWorldMatrix(), &js)); + LL_DEBUGS("Avatar") << "add2 joint[" << (jrd.size()-1) << "] = " << current_joint->getName() << LL_ENDL; } } @@ -366,8 +397,9 @@ void LLAvatarJointMesh::setupJoint(LLAvatarJoint* current_joint) for (LLJoint::child_list_t::iterator iter = current_joint->mChildren.begin(); iter != current_joint->mChildren.end(); ++iter) { - LLAvatarJoint* child_joint = (LLAvatarJoint*)(*iter); - setupJoint(child_joint); + LLAvatarJoint* child_joint = dynamic_cast(*iter); + if(child_joint) + setupJoint(child_joint); } } diff --git a/indra/llappearance/llavatarjointmesh.h b/indra/llappearance/llavatarjointmesh.h index 53b82c50ab..3ee647103d 100644 --- a/indra/llappearance/llavatarjointmesh.h +++ b/indra/llappearance/llavatarjointmesh.h @@ -49,9 +49,9 @@ class LLSkinJoint public: LLSkinJoint(); ~LLSkinJoint(); - BOOL setupSkinJoint( LLAvatarJoint *joint); + BOOL setupSkinJoint( LLJoint *joint); - LLAvatarJoint *mJoint; + LLJoint* mJoint; LLVector3 mRootToJointSkinOffset; LLVector3 mRootToParentJointSkinOffset; }; @@ -122,7 +122,10 @@ class LLAvatarJointMesh : public virtual LLAvatarJoint void setMesh( LLPolyMesh *mesh ); // Sets up joint matrix data for rendering - void setupJoint(LLAvatarJoint* current_joint); + void setupJoint(LLJoint* current_joint); + + // Render time method to upload batches of joint matrices + void uploadJointMatrices(); // Sets ID for picking void setMeshID( S32 id ) {mMeshID = id;} diff --git a/indra/llappearance/lldriverparam.cpp b/indra/llappearance/lldriverparam.cpp index 8a3181702d..cf16074472 100644 --- a/indra/llappearance/lldriverparam.cpp +++ b/indra/llappearance/lldriverparam.cpp @@ -89,7 +89,7 @@ BOOL LLDriverParamInfo::parseXml(LLXmlTreeNode* node) } else { - llerrs << " Unable to resolve driven parameter: " << driven_id << llendl; + LL_ERRS() << " Unable to resolve driven parameter: " << driven_id << LL_ENDL; return FALSE; } } @@ -102,7 +102,7 @@ void LLDriverParamInfo::toStream(std::ostream &out) LLViewerVisualParamInfo::toStream(out); out << "driver" << "\t"; out << mDrivenInfoList.size() << "\t"; - for (entry_info_list_t::iterator iter = mDrivenInfoList.begin(); iter != mDrivenInfoList.end(); iter++) + for (entry_info_list_t::iterator iter = mDrivenInfoList.begin(); iter != mDrivenInfoList.end(); ++iter) { LLDrivenEntryInfo driven = *iter; out << driven.mDrivenID << "\t"; @@ -110,14 +110,26 @@ void LLDriverParamInfo::toStream(std::ostream &out) out << std::endl; - if(mDriverParam && mDriverParam->getAvatarAppearance()->isSelf() && - mDriverParam->getAvatarAppearance()->isValid()) + // FIXME - this mDriverParam backlink makes no sense, because the + // LLDriverParamInfos are static objects - there's only one copy + // for each param type, so the backlink will just reference the + // corresponding param in the most recently created + // avatar. Apparently these toStream() methods are not currently + // used anywhere, so it's not an urgent problem. + LL_WARNS_ONCE() << "Invalid usage of mDriverParam." << LL_ENDL; + + if (!mDriverParam) + return; + const auto& avatar_appearance = mDriverParam->getAvatarAppearance(); + + if(avatar_appearance->isSelf() && + avatar_appearance->isValid()) { - for (entry_info_list_t::iterator iter = mDrivenInfoList.begin(); iter != mDrivenInfoList.end(); iter++) + for (entry_info_list_t::iterator iter = mDrivenInfoList.begin(); iter != mDrivenInfoList.end(); ++iter) { LLDrivenEntryInfo driven = *iter; LLViewerVisualParam *param = - (LLViewerVisualParam*)mDriverParam->getAvatarAppearance()->getVisualParam(driven.mDrivenID); + (LLViewerVisualParam*) avatar_appearance->getVisualParam(driven.mDrivenID); if (param) { param->getInfo()->toStream(out); @@ -139,9 +151,9 @@ void LLDriverParamInfo::toStream(std::ostream &out) } else { - llwarns << "could not get parameter " << driven.mDrivenID << " from avatar " - << mDriverParam->getAvatarAppearance() - << " for driver parameter " << getID() << llendl; + LL_WARNS() << "could not get parameter " << driven.mDrivenID << " from avatar " + << avatar_appearance + << " for driver parameter " << getID() << LL_ENDL; } out << std::endl; } @@ -152,19 +164,31 @@ void LLDriverParamInfo::toStream(std::ostream &out) // LLDriverParam //----------------------------------------------------------------------------- -LLDriverParam::LLDriverParam(LLAvatarAppearance *appearance, LLWearable* wearable /* = NULL */) : +LLDriverParam::LLDriverParam(LLAvatarAppearance *appearance, LLWearable* wearable /* = NULL */) + : LLViewerVisualParam(), + mDefaultVec(), + mDriven(), mCurrentDistortionParam( NULL ), mAvatarAppearance(appearance), mWearablep(wearable) { llassert(mAvatarAppearance); - if (mWearablep) - { - llassert(mAvatarAppearance->isSelf()); - } + llassert((mWearablep == NULL) || mAvatarAppearance->isSelf()); mDefaultVec.clear(); } +LLDriverParam::LLDriverParam(const LLDriverParam& pOther) + : LLViewerVisualParam(pOther), + mDefaultVec(pOther.mDefaultVec), + mDriven(pOther.mDriven), + mCurrentDistortionParam(pOther.mCurrentDistortionParam), + mAvatarAppearance(pOther.mAvatarAppearance), + mWearablep(pOther.mWearablep) +{ + llassert(mAvatarAppearance); + llassert((mWearablep == NULL) || mAvatarAppearance->isSelf()); +} + LLDriverParam::~LLDriverParam() { } @@ -178,7 +202,7 @@ BOOL LLDriverParam::setInfo(LLDriverParamInfo *info) mID = info->mID; info->mDriverParam = this; - setWeight(getDefaultWeight(), FALSE ); + setWeight(getDefaultWeight()); return TRUE; } @@ -186,31 +210,10 @@ BOOL LLDriverParam::setInfo(LLDriverParamInfo *info) /*virtual*/ LLViewerVisualParam* LLDriverParam::cloneParam(LLWearable* wearable) const { llassert(wearable); - LLDriverParam *new_param = new LLDriverParam(mAvatarAppearance, wearable); - // FIXME DRANO this clobbers mWearablep, which means any code - // currently using mWearablep is wrong, or at least untested. - *new_param = *this; - //new_param->mWearablep = wearable; -// new_param->mDriven.clear(); // clear driven list to avoid overwriting avatar driven params from wearables. - return new_param; -} - -#if 0 // obsolete -BOOL LLDriverParam::parseData(LLXmlTreeNode* node) -{ - LLDriverParamInfo* info = new LLDriverParamInfo; - - info->parseXml(node); - if (!setInfo(info)) - { - delete info; - return FALSE; - } - return TRUE; + return new LLDriverParam(*this); } -#endif -void LLDriverParam::setWeight(F32 weight, BOOL upload_bake) +void LLDriverParam::setWeight(F32 weight, bool upload_bake) { F32 min_weight = getMinWeight(); F32 max_weight = getMaxWeight(); @@ -233,7 +236,7 @@ void LLDriverParam::setWeight(F32 weight, BOOL upload_bake) //-------|----|-------|----|-------> driver // | min1 max1 max2 min2 - for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ ) + for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); ++iter ) { LLDrivenEntry* driven = &(*iter); LLDrivenEntryInfo* info = driven->mInfo; @@ -306,7 +309,7 @@ void LLDriverParam::setWeight(F32 weight, BOOL upload_bake) F32 LLDriverParam::getTotalDistortion() { F32 sum = 0.f; - for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ ) + for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); ++iter ) { LLDrivenEntry* driven = &(*iter); sum += driven->mParam->getTotalDistortion(); @@ -321,7 +324,7 @@ const LLVector4a &LLDriverParam::getAvgDistortion() LLVector4a sum; sum.clear(); S32 count = 0; - for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ ) + for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); ++iter ) { LLDrivenEntry* driven = &(*iter); sum.add(driven->mParam->getAvgDistortion()); @@ -336,7 +339,7 @@ const LLVector4a &LLDriverParam::getAvgDistortion() F32 LLDriverParam::getMaxDistortion() { F32 max = 0.f; - for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ ) + for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); ++iter ) { LLDrivenEntry* driven = &(*iter); F32 param_max = driven->mParam->getMaxDistortion(); @@ -354,7 +357,7 @@ LLVector4a LLDriverParam::getVertexDistortion(S32 index, LLPolyMesh *poly_mesh) { LLVector4a sum; sum.clear(); - for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ ) + for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); ++iter ) { LLDrivenEntry* driven = &(*iter); sum.add(driven->mParam->getVertexDistortion( index, poly_mesh )); @@ -366,7 +369,7 @@ const LLVector4a* LLDriverParam::getFirstDistortion(U32 *index, LLPolyMesh **pol { mCurrentDistortionParam = NULL; const LLVector4a* v = NULL; - for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ ) + for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); ++iter ) { LLDrivenEntry* driven = &(*iter); v = driven->mParam->getFirstDistortion( index, poly_mesh ); @@ -392,7 +395,7 @@ const LLVector4a* LLDriverParam::getNextDistortion(U32 *index, LLPolyMesh **poly entry_list_t::iterator iter; // Set mDriven iteration to the right point - for( iter = mDriven.begin(); iter != mDriven.end(); iter++ ) + for( iter = mDriven.begin(); iter != mDriven.end(); ++iter ) { driven = &(*iter); if( driven->mParam == mCurrentDistortionParam ) @@ -413,7 +416,7 @@ const LLVector4a* LLDriverParam::getNextDistortion(U32 *index, LLPolyMesh **poly { // This param is finished, so start the next param. It might not have any // distortions, though, so we have to loop to find the next param that does. - for( iter++; iter != mDriven.end(); iter++ ) + for( ++iter; iter != mDriven.end(); ++iter ) { driven = &(*iter); v = driven->mParam->getFirstDistortion( index, poly_mesh ); @@ -445,11 +448,11 @@ const LLViewerVisualParam* LLDriverParam::getDrivenParam(S32 index) const //----------------------------------------------------------------------------- // setAnimationTarget() //----------------------------------------------------------------------------- -void LLDriverParam::setAnimationTarget( F32 target_value, BOOL upload_bake ) +void LLDriverParam::setAnimationTarget( F32 target_value, bool upload_bake ) { LLVisualParam::setAnimationTarget(target_value, upload_bake); - for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ ) + for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); ++iter ) { LLDrivenEntry* driven = &(*iter); F32 driven_weight = getDrivenWeight(driven, mTargetWeight); @@ -463,11 +466,11 @@ void LLDriverParam::setAnimationTarget( F32 target_value, BOOL upload_bake ) //----------------------------------------------------------------------------- // stopAnimating() //----------------------------------------------------------------------------- -void LLDriverParam::stopAnimating(BOOL upload_bake) +void LLDriverParam::stopAnimating(bool upload_bake) { LLVisualParam::stopAnimating(upload_bake); - for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ ) + for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); ++iter ) { LLDrivenEntry* driven = &(*iter); driven->mParam->setAnimating(FALSE); @@ -524,7 +527,7 @@ void LLDriverParam::updateCrossDrivenParams(LLWearableType::EType driven_type) bool needs_update = (getWearableType()==driven_type); // if the driver has a driven entry for the passed-in wearable type, we need to refresh the value - for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ ) + for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); ++iter ) { LLDrivenEntry* driven = &(*iter); if (driven && driven->mParam && driven->mParam->getCrossWearable() && driven->mParam->getWearableType() == driven_type) @@ -545,7 +548,7 @@ void LLDriverParam::updateCrossDrivenParams(LLWearableType::EType driven_type) LLWearable *wearable = mAvatarAppearance->getWearableData()->getTopWearable(driver_type); if (wearable) { - wearable->setVisualParamWeight(mID, wearable->getVisualParamWeight(mID), false); + wearable->setVisualParamWeight(mID, wearable->getVisualParamWeight(mID)); } } } diff --git a/indra/llappearance/lldriverparam.h b/indra/llappearance/lldriverparam.h index 65dd3cdde5..a7dec8acb3 100644 --- a/indra/llappearance/lldriverparam.h +++ b/indra/llappearance/lldriverparam.h @@ -29,6 +29,7 @@ #include "llviewervisualparam.h" #include "llwearabletype.h" +#include class LLAvatarAppearance; class LLDriverParam; @@ -112,12 +113,13 @@ class LLDriverParam : public LLViewerVisualParam // LLVisualParam Virtual functions ///*virtual*/ BOOL parseData(LLXmlTreeNode* node); /*virtual*/ void apply( ESex sex ) {} // apply is called separately for each driven param. - /*virtual*/ void setWeight(F32 weight, BOOL upload_bake); - /*virtual*/ void setAnimationTarget( F32 target_value, BOOL upload_bake ); - /*virtual*/ void stopAnimating(BOOL upload_bake); + /*virtual*/ void setWeight(F32 weight, bool upload_bake = false); + /*virtual*/ void setAnimationTarget( F32 target_value, bool upload_bake = false); + /*virtual*/ void stopAnimating(bool upload_bake = false); /*virtual*/ BOOL linkDrivenParams(visual_param_mapper mapper, BOOL only_cross_params); /*virtual*/ void resetDrivenParams(); - + /*virtual*/ char const* getTypeString(void) const { return "param_driver"; } + // LLViewerVisualParam Virtual functions /*virtual*/ F32 getTotalDistortion(); /*virtual*/ const LLVector4a& getAvgDistortion(); @@ -129,13 +131,17 @@ class LLDriverParam : public LLViewerVisualParam S32 getDrivenParamsCount() const; const LLViewerVisualParam* getDrivenParam(S32 index) const; + typedef std::vector entry_list_t; + entry_list_t& getDrivenList() { return mDriven; } + void setDrivenList(entry_list_t& driven_list) { mDriven = driven_list; } + protected: + LLDriverParam(const LLDriverParam& pOther); F32 getDrivenWeight(const LLDrivenEntry* driven, F32 input_weight); - void setDrivenWeight(LLDrivenEntry *driven, F32 driven_weight, bool upload_bake); + void setDrivenWeight(LLDrivenEntry *driven, F32 driven_weight, bool upload_bake = false); LL_ALIGN_16(LLVector4a mDefaultVec); // temp holder - typedef std::vector entry_list_t; entry_list_t mDriven; LLViewerVisualParam* mCurrentDistortionParam; // Backlink only; don't make this an LLPointer. diff --git a/indra/llappearance/lllocaltextureobject.cpp b/indra/llappearance/lllocaltextureobject.cpp index 7e36a06797..f0a789c467 100644 --- a/indra/llappearance/lllocaltextureobject.cpp +++ b/indra/llappearance/lllocaltextureobject.cpp @@ -64,7 +64,7 @@ LLLocalTextureObject::LLLocalTextureObject(const LLLocalTextureObject& lto) : LLTexLayer* original_layer = lto.getTexLayer(index); if (!original_layer) { - llerrs << "could not clone Local Texture Object: unable to extract texlayer!" << llendl; + LL_ERRS() << "could not clone Local Texture Object: unable to extract texlayer!" << LL_ENDL; continue; } @@ -76,6 +76,7 @@ LLLocalTextureObject::LLLocalTextureObject(const LLLocalTextureObject& lto) : LLLocalTextureObject::~LLLocalTextureObject() { + delete_and_clear(mTexLayers); } LLGLTexture* LLLocalTextureObject::getImage() const @@ -95,7 +96,7 @@ LLTexLayer* LLLocalTextureObject::getTexLayer(U32 index) const LLTexLayer* LLLocalTextureObject::getTexLayer(const std::string &name) { - for( tex_layer_vec_t::iterator iter = mTexLayers.begin(); iter != mTexLayers.end(); iter++) + for( tex_layer_vec_t::iterator iter = mTexLayers.begin(); iter != mTexLayers.end(); ++iter) { LLTexLayer *layer = *iter; if (layer->getName().compare(name) == 0) @@ -196,7 +197,7 @@ BOOL LLLocalTextureObject::removeTexLayer(U32 index) return TRUE; } -void LLLocalTextureObject::setID(LLUUID new_id) +void LLLocalTextureObject::setID(const LLUUID& new_id) { mID = new_id; } diff --git a/indra/llappearance/lllocaltextureobject.h b/indra/llappearance/lllocaltextureobject.h index 9b9f41fd19..699dbafcdc 100644 --- a/indra/llappearance/lllocaltextureobject.h +++ b/indra/llappearance/lllocaltextureobject.h @@ -61,7 +61,7 @@ class LLLocalTextureObject BOOL addTexLayer(LLTexLayerTemplate *new_tex_layer, LLWearable *wearable); BOOL removeTexLayer(U32 index); - void setID(LLUUID new_id); + void setID(const LLUUID& new_id); void setDiscard(S32 new_discard); void setBakedReady(BOOL ready); diff --git a/indra/llappearance/llpolymesh.cpp b/indra/llappearance/llpolymesh.cpp index a6290d02ab..529755819a 100644 --- a/indra/llappearance/llpolymesh.cpp +++ b/indra/llappearance/llpolymesh.cpp @@ -161,8 +161,8 @@ void LLPolyMeshSharedData::freeMeshData() // mVertFaceMap.deleteAllData(); } -// compate_int is used by the qsort function to sort the index array -int compare_int(const void *a, const void *b); +// compare_int is used by the qsort function to sort the index array +S32 compare_int(const void *a, const void *b); //----------------------------------------------------------------------------- // genIndices() @@ -231,9 +231,9 @@ BOOL LLPolyMeshSharedData::allocateVertexData( U32 numVertices ) mBaseCoords = (LLVector4a*) ll_aligned_malloc_16(numVertices*sizeof(LLVector4a)); mBaseNormals = (LLVector4a*) ll_aligned_malloc_16(numVertices*sizeof(LLVector4a)); mBaseBinormals = (LLVector4a*) ll_aligned_malloc_16(numVertices*sizeof(LLVector4a)); - mTexCoords = (LLVector2*) ll_aligned_malloc_16(numVertices*sizeof(LLVector2)); - mDetailTexCoords = (LLVector2*) ll_aligned_malloc_16(numVertices*sizeof(LLVector2)); - mWeights = (F32*) ll_aligned_malloc_16(numVertices*sizeof(F32)); + mTexCoords = (LLVector2*) ll_aligned_malloc_16((numVertices+numVertices%2)*sizeof(LLVector2)); + mDetailTexCoords = (LLVector2*) ll_aligned_malloc_16((numVertices+numVertices%2)*sizeof(LLVector2)); + mWeights = (F32*) ll_aligned_malloc_16(((numVertices)*sizeof(F32)+0xF) & ~0xF); for (i = 0; i < numVertices; i++) { mBaseCoords[i].clear(); @@ -277,13 +277,13 @@ BOOL LLPolyMeshSharedData::loadMesh( const std::string& fileName ) //------------------------------------------------------------------------- if(fileName.empty()) { - llerrs << "Filename is Empty!" << llendl; + LL_ERRS() << "Filename is Empty!" << LL_ENDL; return FALSE; } LLFILE* fp = LLFile::fopen(fileName, "rb"); /*Flawfinder: ignore*/ if (!fp) { - llerrs << "can't open: " << fileName << llendl; + LL_ERRS() << "can't open: " << fileName << LL_ENDL; return FALSE; } @@ -293,7 +293,7 @@ BOOL LLPolyMeshSharedData::loadMesh( const std::string& fileName ) char header[128]; /*Flawfinder: ignore*/ if (fread(header, sizeof(char), 128, fp) != 128) { - llwarns << "Short read" << llendl; + LL_WARNS() << "Short read" << LL_ENDL; } //------------------------------------------------------------------------- @@ -302,12 +302,16 @@ BOOL LLPolyMeshSharedData::loadMesh( const std::string& fileName ) BOOL status = FALSE; if ( strncmp(header, HEADER_BINARY, strlen(HEADER_BINARY)) == 0 ) /*Flawfinder: ignore*/ { - lldebugs << "Loading " << fileName << llendl; + LL_DEBUGS() << "Loading " << fileName << LL_ENDL; //---------------------------------------------------------------- // File Header (seek past it) //---------------------------------------------------------------- - fseek(fp, 24, SEEK_SET); + if (fseek(fp, 24, SEEK_SET) != 0) + { + LL_ERRS() << "can't seek past header from " << fileName << LL_ENDL; + return FALSE; + } //---------------------------------------------------------------- // HasWeights @@ -316,7 +320,7 @@ BOOL LLPolyMeshSharedData::loadMesh( const std::string& fileName ) size_t numRead = fread(&hasWeights, sizeof(U8), 1, fp); if (numRead != 1) { - llerrs << "can't read HasWeights flag from " << fileName << llendl; + LL_ERRS() << "can't read HasWeights flag from " << fileName << LL_ENDL; return FALSE; } if (!isLOD()) @@ -331,7 +335,7 @@ BOOL LLPolyMeshSharedData::loadMesh( const std::string& fileName ) numRead = fread(&hasDetailTexCoords, sizeof(U8), 1, fp); if (numRead != 1) { - llerrs << "can't read HasDetailTexCoords flag from " << fileName << llendl; + LL_ERRS() << "can't read HasDetailTexCoords flag from " << fileName << LL_ENDL; return FALSE; } @@ -343,7 +347,7 @@ BOOL LLPolyMeshSharedData::loadMesh( const std::string& fileName ) llendianswizzle(position.mV, sizeof(float), 3); if (numRead != 3) { - llerrs << "can't read Position from " << fileName << llendl; + LL_ERRS() << "can't read Position from " << fileName << LL_ENDL; return FALSE; } setPosition( position ); @@ -356,7 +360,7 @@ BOOL LLPolyMeshSharedData::loadMesh( const std::string& fileName ) llendianswizzle(rotationAngles.mV, sizeof(float), 3); if (numRead != 3) { - llerrs << "can't read RotationAngles from " << fileName << llendl; + LL_ERRS() << "can't read RotationAngles from " << fileName << LL_ENDL; return FALSE; } @@ -365,7 +369,7 @@ BOOL LLPolyMeshSharedData::loadMesh( const std::string& fileName ) if (numRead != 1) { - llerrs << "can't read RotationOrder from " << fileName << llendl; + LL_ERRS() << "can't read RotationOrder from " << fileName << LL_ENDL; return FALSE; } @@ -384,7 +388,7 @@ BOOL LLPolyMeshSharedData::loadMesh( const std::string& fileName ) llendianswizzle(scale.mV, sizeof(float), 3); if (numRead != 3) { - llerrs << "can't read Scale from " << fileName << llendl; + LL_ERRS() << "can't read Scale from " << fileName << LL_ENDL; return FALSE; } setScale( scale ); @@ -405,7 +409,7 @@ BOOL LLPolyMeshSharedData::loadMesh( const std::string& fileName ) llendianswizzle(&numVertices, sizeof(U16), 1); if (numRead != 1) { - llerrs << "can't read NumVertices from " << fileName << llendl; + LL_ERRS() << "can't read NumVertices from " << fileName << LL_ENDL; return FALSE; } @@ -420,7 +424,7 @@ BOOL LLPolyMeshSharedData::loadMesh( const std::string& fileName ) llendianswizzle(&mBaseCoords[i], sizeof(float), 3); if (numRead != 3) { - llerrs << "can't read Coordinates from " << fileName << llendl; + LL_ERRS() << "can't read Coordinates from " << fileName << LL_ENDL; return FALSE; } } @@ -434,7 +438,7 @@ BOOL LLPolyMeshSharedData::loadMesh( const std::string& fileName ) llendianswizzle(&mBaseNormals[i], sizeof(float), 3); if (numRead != 3) { - llerrs << " can't read Normals from " << fileName << llendl; + LL_ERRS() << " can't read Normals from " << fileName << LL_ENDL; return FALSE; } } @@ -448,7 +452,7 @@ BOOL LLPolyMeshSharedData::loadMesh( const std::string& fileName ) llendianswizzle(&mBaseBinormals[i], sizeof(float), 3); if (numRead != 3) { - llerrs << " can't read Binormals from " << fileName << llendl; + LL_ERRS() << " can't read Binormals from " << fileName << LL_ENDL; return FALSE; } } @@ -460,7 +464,7 @@ BOOL LLPolyMeshSharedData::loadMesh( const std::string& fileName ) llendianswizzle(mTexCoords, sizeof(float), 2*numVertices); if (numRead != numVertices) { - llerrs << "can't read TexCoords from " << fileName << llendl; + LL_ERRS() << "can't read TexCoords from " << fileName << LL_ENDL; return FALSE; } @@ -473,7 +477,7 @@ BOOL LLPolyMeshSharedData::loadMesh( const std::string& fileName ) llendianswizzle(mDetailTexCoords, sizeof(float), 2*numVertices); if (numRead != numVertices) { - llerrs << "can't read DetailTexCoords from " << fileName << llendl; + LL_ERRS() << "can't read DetailTexCoords from " << fileName << LL_ENDL; return FALSE; } } @@ -487,7 +491,7 @@ BOOL LLPolyMeshSharedData::loadMesh( const std::string& fileName ) llendianswizzle(mWeights, sizeof(float), numVertices); if (numRead != numVertices) { - llerrs << "can't read Weights from " << fileName << llendl; + LL_ERRS() << "can't read Weights from " << fileName << LL_ENDL; return FALSE; } } @@ -501,7 +505,7 @@ BOOL LLPolyMeshSharedData::loadMesh( const std::string& fileName ) llendianswizzle(&numFaces, sizeof(U16), 1); if (numRead != 1) { - llerrs << "can't read NumFaces from " << fileName << llendl; + LL_ERRS() << "can't read NumFaces from " << fileName << LL_ENDL; return FALSE; } allocateFaceData( numFaces ); @@ -519,7 +523,7 @@ BOOL LLPolyMeshSharedData::loadMesh( const std::string& fileName ) llendianswizzle(face, sizeof(U16), 3); if (numRead != 3) { - llerrs << "can't read Face[" << i << "] from " << fileName << llendl; + LL_ERRS() << "can't read Face[" << i << "] from " << fileName << LL_ENDL; return FALSE; } if (mReferenceData) @@ -547,22 +551,22 @@ BOOL LLPolyMeshSharedData::loadMesh( const std::string& fileName ) // S32 j; // for(j = 0; j < 3; j++) // { -// LLDynamicArray *face_list = mVertFaceMap.getIfThere(face[j]); +// std::vector *face_list = mVertFaceMap.getIfThere(face[j]); // if (!face_list) // { -// face_list = new LLDynamicArray; +// face_list = new std::vector; // mVertFaceMap.addData(face[j], face_list); // } -// face_list->put(i); +// face_list->push_back(i); // } numTris++; } - lldebugs << "verts: " << numVertices + LL_DEBUGS() << "verts: " << numVertices << ", faces: " << numFaces << ", tris: " << numTris - << llendl; + << LL_ENDL; //---------------------------------------------------------------- // NumSkinJoints @@ -576,7 +580,7 @@ BOOL LLPolyMeshSharedData::loadMesh( const std::string& fileName ) llendianswizzle(&numSkinJoints, sizeof(U16), 1); if (numRead != 1) { - llerrs << "can't read NumSkinJoints from " << fileName << llendl; + LL_ERRS() << "can't read NumSkinJoints from " << fileName << LL_ENDL; return FALSE; } allocateJointNames( numSkinJoints ); @@ -592,7 +596,7 @@ BOOL LLPolyMeshSharedData::loadMesh( const std::string& fileName ) jointName[sizeof(jointName)-1] = '\0'; // ensure nul-termination if (numRead != 1) { - llerrs << "can't read Skin[" << i << "].Name from " << fileName << llendl; + LL_ERRS() << "can't read Skin[" << i << "].Name from " << fileName << LL_ENDL; return FALSE; } @@ -605,7 +609,7 @@ BOOL LLPolyMeshSharedData::loadMesh( const std::string& fileName ) //------------------------------------------------------------------------- char morphName[64+1]; morphName[sizeof(morphName)-1] = '\0'; // ensure nul-termination - while(fread(&morphName, sizeof(char), 64, fp) == 64) + while(fread(morphName, sizeof(char), 64, fp) == 64) { if (!strcmp(morphName, "End Morphs")) { @@ -629,10 +633,6 @@ BOOL LLPolyMeshSharedData::loadMesh( const std::string& fileName ) mMorphData.insert(clone_morph_param_cleavage(morph_data, .75f, "Breast_Physics_LeftRight_Driven")); - } - - if (!strcmp(morphName, "Breast_Female_Cleavage")) - { mMorphData.insert(clone_morph_param_duplicate(morph_data, "Breast_Physics_InOut_Driven")); } @@ -668,9 +668,6 @@ BOOL LLPolyMeshSharedData::loadMesh( const std::string& fileName ) mMorphData.insert(clone_morph_param_direction(morph_data, LLVector3(0,0,0.05f), "Butt_Physics_UpDown_Driven")); - } - if (!strcmp(morphName, "Small_Butt")) - { mMorphData.insert(clone_morph_param_direction(morph_data, LLVector3(0,0.03f,0), "Butt_Physics_LeftRight_Driven")); @@ -687,12 +684,12 @@ BOOL LLPolyMeshSharedData::loadMesh( const std::string& fileName ) S32 remapDst; if (fread(&remapSrc, sizeof(S32), 1, fp) != 1) { - llerrs << "can't read source vertex in vertex remap data" << llendl; + LL_ERRS() << "can't read source vertex in vertex remap data" << LL_ENDL; break; } if (fread(&remapDst, sizeof(S32), 1, fp) != 1) { - llerrs << "can't read destination vertex in vertex remap data" << llendl; + LL_ERRS() << "can't read destination vertex in vertex remap data" << LL_ENDL; break; } llendianswizzle(&remapSrc, sizeof(S32), 1); @@ -707,7 +704,7 @@ BOOL LLPolyMeshSharedData::loadMesh( const std::string& fileName ) } else { - llerrs << "invalid mesh file header: " << fileName << llendl; + LL_ERRS() << "invalid mesh file header: " << fileName << LL_ENDL; status = FALSE; } @@ -808,15 +805,8 @@ LLPolyMesh::LLPolyMesh(LLPolyMeshSharedData *shared_data, LLPolyMesh *reference_ //----------------------------------------------------------------------------- LLPolyMesh::~LLPolyMesh() { - S32 i; - for (i = 0; i < mJointRenderData.count(); i++) - { - delete mJointRenderData[i]; - mJointRenderData[i] = NULL; - } - - ll_aligned_free_16(mVertexData); - + delete_and_clear(mJointRenderData); + ll_aligned_free_16(mVertexData); } @@ -831,7 +821,7 @@ LLPolyMesh *LLPolyMesh::getMesh(const std::string &name, LLPolyMesh* reference_m LLPolyMeshSharedData* meshSharedData = get_if_there(sGlobalSharedMeshList, name, (LLPolyMeshSharedData*)NULL); if (meshSharedData) { -// llinfos << "Polymesh " << name << " found in global mesh table." << llendl; +// LL_INFOS() << "Polymesh " << name << " found in global mesh table." << LL_ENDL; LLPolyMesh *poly_mesh = new LLPolyMesh(meshSharedData, reference_mesh); return poly_mesh; } @@ -855,7 +845,7 @@ LLPolyMesh *LLPolyMesh::getMesh(const std::string &name, LLPolyMesh* reference_m LLPolyMesh *poly_mesh = new LLPolyMesh(mesh_data, reference_mesh); -// llinfos << "Polymesh " << name << " added to global mesh table." << llendl; +// LL_INFOS() << "Polymesh " << name << " added to global mesh table." << LL_ENDL; sGlobalSharedMeshList[name] = poly_mesh->mSharedData; return poly_mesh; @@ -887,7 +877,7 @@ BOOL LLPolyMesh::saveLLM(LLFILE *fp) //------------------------------------------------------------------------- if (fwrite(HEADER_BINARY, 1, strlen(HEADER_BINARY), fp) != strlen(HEADER_BINARY)) { - llwarns << "Short write" << llendl; + LL_WARNS() << "Short write" << LL_ENDL; } if (strlen(HEADER_BINARY) < 24) @@ -896,7 +886,7 @@ BOOL LLPolyMesh::saveLLM(LLFILE *fp) int pad = 24 - strlen(HEADER_BINARY); if (fwrite(&padding, 1, pad, fp) != pad) { - llwarns << "Short write" << llendl; + LL_WARNS() << "Short write" << LL_ENDL; } } @@ -906,7 +896,7 @@ BOOL LLPolyMesh::saveLLM(LLFILE *fp) U8 hasWeights = (U8) mSharedData->mHasWeights; if (fwrite(&hasWeights, sizeof(U8), 1, fp) != 1) { - llwarns << "Short write" << llendl; + LL_WARNS() << "Short write" << LL_ENDL; } //---------------------------------------------------------------- @@ -915,7 +905,7 @@ BOOL LLPolyMesh::saveLLM(LLFILE *fp) U8 hasDetailTexCoords = (U8) mSharedData->mHasDetailTexCoords; if (fwrite(&hasDetailTexCoords, sizeof(U8), 1, fp) != 1) { - llwarns << "Short write" << llendl; + LL_WARNS() << "Short write" << LL_ENDL; } //---------------------------------------------------------------- @@ -925,7 +915,7 @@ BOOL LLPolyMesh::saveLLM(LLFILE *fp) llendianswizzle(position.mV, sizeof(float), 3); if (fwrite(position.mV, sizeof(float), 3, fp) != 3) { - llwarns << "Short write" << llendl; + LL_WARNS() << "Short write" << LL_ENDL; } //---------------------------------------------------------------- @@ -946,13 +936,13 @@ BOOL LLPolyMesh::saveLLM(LLFILE *fp) llendianswizzle(rotationAngles.mV, sizeof(float), 3); if (fwrite(rotationAngles.mV, sizeof(float), 3, fp) != 3) { - llwarns << "Short write" << llendl; + LL_WARNS() << "Short write" << LL_ENDL; } U8 rotationOrder = 0; if (fwrite(&rotationOrder, sizeof(U8), 1, fp) != 1) { - llwarns << "Short write" << llendl; + LL_WARNS() << "Short write" << LL_ENDL; } //---------------------------------------------------------------- @@ -962,7 +952,7 @@ BOOL LLPolyMesh::saveLLM(LLFILE *fp) llendianswizzle(scale.mV, sizeof(float), 3); if (fwrite(scale.mV, sizeof(float), 3, fp) != 3) { - llwarns << "Short write" << llendl; + LL_WARNS() << "Short write" << LL_ENDL; } //---------------------------------------------------------------- @@ -975,7 +965,7 @@ BOOL LLPolyMesh::saveLLM(LLFILE *fp) llendianswizzle(&numVertices, sizeof(U16), 1); if (fwrite(&numVertices, sizeof(U16), 1, fp) != 1) { - llwarns << "Short write" << llendl; + LL_WARNS() << "Short write" << LL_ENDL; } numVertices = mSharedData->mNumVertices; // without the swizzle again @@ -989,7 +979,7 @@ BOOL LLPolyMesh::saveLLM(LLFILE *fp) llendianswizzle(coords.getF32ptr(), sizeof(float), 3); if (fwrite(coords.getF32ptr(), 3*sizeof(float), 1, fp) != 1) { - llwarns << "Short write" << llendl; + LL_WARNS() << "Short write" << LL_ENDL; } llendianswizzle(coords.getF32ptr(), sizeof(float), 3); } @@ -1004,7 +994,7 @@ BOOL LLPolyMesh::saveLLM(LLFILE *fp) llendianswizzle(normals.getF32ptr(), sizeof(float), 3); if (fwrite(normals.getF32ptr(), 3*sizeof(float), 1, fp) != 1) { - llwarns << "Short write" << llendl; + LL_WARNS() << "Short write" << LL_ENDL; } llendianswizzle(normals.getF32ptr(), sizeof(float), 3); } @@ -1019,7 +1009,7 @@ BOOL LLPolyMesh::saveLLM(LLFILE *fp) llendianswizzle(binormals.getF32ptr(), sizeof(float), 3); if (fwrite(binormals.getF32ptr(), 3*sizeof(float), 1, fp) != 1) { - llwarns << "Short write" << llendl; + LL_WARNS() << "Short write" << LL_ENDL; } llendianswizzle(binormals.getF32ptr(), sizeof(float), 3); } @@ -1032,7 +1022,7 @@ BOOL LLPolyMesh::saveLLM(LLFILE *fp) llendianswizzle(tex, sizeof(float), 2*numVertices); if (fwrite(tex, 2*sizeof(float), numVertices, fp) != numVertices) { - llwarns << "Short write" << llendl; + LL_WARNS() << "Short write" << LL_ENDL; } llendianswizzle(tex, sizeof(float), 2*numVertices); @@ -1046,7 +1036,7 @@ BOOL LLPolyMesh::saveLLM(LLFILE *fp) llendianswizzle(detail, sizeof(float), 2*numVertices); if (fwrite(detail, 2*sizeof(float), numVertices, fp) != numVertices) { - llwarns << "Short write" << llendl; + LL_WARNS() << "Short write" << LL_ENDL; } llendianswizzle(detail, sizeof(float), 2*numVertices); } @@ -1061,7 +1051,7 @@ BOOL LLPolyMesh::saveLLM(LLFILE *fp) llendianswizzle(weights, sizeof(float), numVertices); if (fwrite(weights, sizeof(float), numVertices, fp) != numVertices) { - llwarns << "Short write" << llendl; + LL_WARNS() << "Short write" << LL_ENDL; } llendianswizzle(weights, sizeof(float), numVertices); } @@ -1075,7 +1065,7 @@ BOOL LLPolyMesh::saveLLM(LLFILE *fp) llendianswizzle(&numFaces, sizeof(U16), 1); if (fwrite(&numFaces, sizeof(U16), 1, fp) != 1) { - llwarns << "Short write" << llendl; + LL_WARNS() << "Short write" << LL_ENDL; } numFaces = mSharedData->mNumFaces; // without the swizzle again @@ -1094,7 +1084,7 @@ BOOL LLPolyMesh::saveLLM(LLFILE *fp) llendianswizzle(face, sizeof(U16), 3); if (fwrite(face, sizeof(U16), 3, fp) != 3) { - llwarns << "Short write" << llendl; + LL_WARNS() << "Short write" << LL_ENDL; } } @@ -1121,7 +1111,7 @@ BOOL LLPolyMesh::saveLLM(LLFILE *fp) llendianswizzle(&numSkinJoints, sizeof(U16), 1); if (fwrite(&numSkinJoints, sizeof(U16), 1, fp) != 1) { - llwarns << "Short write" << llendl; + LL_WARNS() << "Short write" << LL_ENDL; } llendianswizzle(&numSkinJoints, sizeof(U16), 1); @@ -1134,7 +1124,7 @@ BOOL LLPolyMesh::saveLLM(LLFILE *fp) jn = &mSharedData->mJointNames[i]; if (fwrite(jn->c_str(), 1, jn->length(), fp) != jn->length()) { - llwarns << "Short write" << llendl; + LL_WARNS() << "Short write" << LL_ENDL; } if (jn->length() < 64) @@ -1142,7 +1132,7 @@ BOOL LLPolyMesh::saveLLM(LLFILE *fp) int pad = 64 - jn->length(); if (fwrite(&padding, 1, pad, fp) != pad) { - llwarns << "Short write" << llendl; + LL_WARNS() << "Short write" << LL_ENDL; } } } @@ -1173,7 +1163,7 @@ BOOL LLPolyMesh::saveLLM(LLFILE *fp) if (fwrite(morph_name.c_str(), 1, morph_name.length(), fp) != morph_name.length()) { - llwarns << "Short write" << llendl; + LL_WARNS() << "Short write" << LL_ENDL; } if (morph_name.length() < 64) @@ -1181,20 +1171,20 @@ BOOL LLPolyMesh::saveLLM(LLFILE *fp) int pad = 64 - morph_name.length(); if (fwrite(&padding, 1, pad, fp) != pad) { - llwarns << "Short write" << llendl; + LL_WARNS() << "Short write" << LL_ENDL; } } if (!morph_data->saveLLM(fp)) { - llwarns << "Problem writing morph" << llendl; + LL_WARNS() << "Problem writing morph" << LL_ENDL; } } char end_morphs[64] = "End Morphs"; // padded with zeroes if (fwrite(end_morphs, sizeof(char), 64, fp) != 64) { - llwarns << "Short write" << llendl; + LL_WARNS() << "Short write" << LL_ENDL; } //------------------------------------------------------------------------- @@ -1204,7 +1194,7 @@ BOOL LLPolyMesh::saveLLM(LLFILE *fp) llendianswizzle(&numRemaps, sizeof(S32), 1); if (fwrite(&numRemaps, sizeof(S32), 1, fp) != 1) { - llwarns << "Short write" << llendl; + LL_WARNS() << "Short write" << LL_ENDL; } std::map::iterator remap_iter = mSharedData->mSharedVerts.begin(); @@ -1217,7 +1207,7 @@ BOOL LLPolyMesh::saveLLM(LLFILE *fp) llendianswizzle(&remapSrc, sizeof(S32), 1); if (fwrite(&remapSrc, sizeof(S32), 1, fp) != 1) { - llwarns << "Short write" << llendl; + LL_WARNS() << "Short write" << LL_ENDL; } S32 remapDst = remap_iter->second; @@ -1225,7 +1215,7 @@ BOOL LLPolyMesh::saveLLM(LLFILE *fp) llendianswizzle(&remapDst, sizeof(S32), 1); if (fwrite(&remapDst, sizeof(S32), 1, fp) != 1) { - llwarns << "Short write" << llendl; + LL_WARNS() << "Short write" << LL_ENDL; } } @@ -1257,7 +1247,7 @@ BOOL LLPolyMesh::saveOBJ(LLFILE *fp) coords[i].getF32ptr()[2]); if (fwrite(outstring.c_str(), 1, outstring.length(), fp) != outstring.length()) { - llwarns << "Short write" << llendl; + LL_WARNS() << "Short write" << LL_ENDL; } } @@ -1269,7 +1259,7 @@ BOOL LLPolyMesh::saveOBJ(LLFILE *fp) normals[i].getF32ptr()[2]); if (fwrite(outstring.c_str(), 1, outstring.length(), fp) != outstring.length()) { - llwarns << "Short write" << llendl; + LL_WARNS() << "Short write" << LL_ENDL; } } @@ -1280,7 +1270,7 @@ BOOL LLPolyMesh::saveOBJ(LLFILE *fp) tex[i][1]); if (fwrite(outstring.c_str(), 1, outstring.length(), fp) != outstring.length()) { - llwarns << "Short write" << llendl; + LL_WARNS() << "Short write" << LL_ENDL; } } @@ -1295,13 +1285,64 @@ BOOL LLPolyMesh::saveOBJ(LLFILE *fp) f3, f3, f3); if (fwrite(outstring.c_str(), 1, outstring.length(), fp) != outstring.length()) { - llwarns << "Short write" << llendl; + LL_WARNS() << "Short write" << LL_ENDL; } } return TRUE; } +// Finds binormal based on three vertices with texture coordinates. +// Fills in dummy values if the triangle has degenerate texture coordinates. +void calc_binormal_from_triangle(LLVector4a& binormal, + + const LLVector4a& pos0, + const LLVector2& tex0, + const LLVector4a& pos1, + const LLVector2& tex1, + const LLVector4a& pos2, + const LLVector2& tex2) +{ + LLVector4a rx0( pos0[VX], tex0.mV[VX], tex0.mV[VY] ); + LLVector4a rx1( pos1[VX], tex1.mV[VX], tex1.mV[VY] ); + LLVector4a rx2( pos2[VX], tex2.mV[VX], tex2.mV[VY] ); + + LLVector4a ry0( pos0[VY], tex0.mV[VX], tex0.mV[VY] ); + LLVector4a ry1( pos1[VY], tex1.mV[VX], tex1.mV[VY] ); + LLVector4a ry2( pos2[VY], tex2.mV[VX], tex2.mV[VY] ); + + LLVector4a rz0( pos0[VZ], tex0.mV[VX], tex0.mV[VY] ); + LLVector4a rz1( pos1[VZ], tex1.mV[VX], tex1.mV[VY] ); + LLVector4a rz2( pos2[VZ], tex2.mV[VX], tex2.mV[VY] ); + + LLVector4a lhs, rhs; + + LLVector4a r0; + lhs.setSub(rx0, rx1); rhs.setSub(rx0, rx2); + r0.setCross3(lhs, rhs); + + LLVector4a r1; + lhs.setSub(ry0, ry1); rhs.setSub(ry0, ry2); + r1.setCross3(lhs, rhs); + + LLVector4a r2; + lhs.setSub(rz0, rz1); rhs.setSub(rz0, rz2); + r2.setCross3(lhs, rhs); + + if( r0[VX] && r1[VX] && r2[VX] ) + { + binormal.set( + -r0[VZ] / r0[VX], + -r1[VZ] / r1[VX], + -r2[VZ] / r2[VX]); + // binormal.normVec(); + } + else + { + binormal.set( 0, 1 , 0 ); + } +} + //----------------------------------------------------------------------------- // LLPolyMesh::loadOBJ() //----------------------------------------------------------------------------- @@ -1353,12 +1394,12 @@ BOOL LLPolyMesh::loadOBJ(LLFILE *fp) values = sscanf (buffer," %255s %f %f %f", keyword, &tempX, &tempY, &tempZ); if (values != 4) { - llwarns << "Expecting v x y z, but found: " << buffer < mJointRenderData; + std::vector mJointRenderData; U32 mFaceVertexOffset; U32 mFaceVertexCount; diff --git a/indra/llappearance/llpolymorph.cpp b/indra/llappearance/llpolymorph.cpp index aeaf79f33d..626940b190 100644 --- a/indra/llappearance/llpolymorph.cpp +++ b/indra/llappearance/llpolymorph.cpp @@ -109,13 +109,13 @@ LLPolyMorphData::~LLPolyMorphData() BOOL LLPolyMorphData::loadBinary(LLFILE *fp, LLPolyMeshSharedData *mesh) { S32 numVertices; - S32 numRead; + size_t numRead; // numRead = fread(&numVertices, sizeof(S32), 1, fp); llendianswizzle(&numVertices, sizeof(S32), 1); if (numRead != 1) { - llwarns << "Can't read number of morph target vertices" << llendl; + LL_WARNS() << "Can't read number of morph target vertices" << LL_ENDL; return FALSE; } @@ -152,13 +152,13 @@ BOOL LLPolyMorphData::loadBinary(LLFILE *fp, LLPolyMeshSharedData *mesh) llendianswizzle(&mVertexIndices[v], sizeof(U32), 1); if (numRead != 1) { - llwarns << "Can't read morph target vertex number" << llendl; + LL_WARNS() << "Can't read morph target vertex number" << LL_ENDL; return FALSE; } if (mVertexIndices[v] > 10000) { - llerrs << "Bad morph index: " << mVertexIndices[v] << llendl; + LL_ERRS() << "Bad morph index: " << mVertexIndices[v] << LL_ENDL; } @@ -166,7 +166,7 @@ BOOL LLPolyMorphData::loadBinary(LLFILE *fp, LLPolyMeshSharedData *mesh) llendianswizzle(&mCoords[v], sizeof(F32), 3); if (numRead != 3) { - llwarns << "Can't read morph target vertex coordinates" << llendl; + LL_WARNS() << "Can't read morph target vertex coordinates" << LL_ENDL; return FALSE; } @@ -186,7 +186,7 @@ BOOL LLPolyMorphData::loadBinary(LLFILE *fp, LLPolyMeshSharedData *mesh) llendianswizzle(&mNormals[v], sizeof(F32), 3); if (numRead != 3) { - llwarns << "Can't read morph target normal" << llendl; + LL_WARNS() << "Can't read morph target normal" << LL_ENDL; return FALSE; } @@ -194,7 +194,7 @@ BOOL LLPolyMorphData::loadBinary(LLFILE *fp, LLPolyMeshSharedData *mesh) llendianswizzle(&mBinormals[v], sizeof(F32), 3); if (numRead != 3) { - llwarns << "Can't read morph target binormal" << llendl; + LL_WARNS() << "Can't read morph target binormal" << LL_ENDL; return FALSE; } @@ -203,7 +203,7 @@ BOOL LLPolyMorphData::loadBinary(LLFILE *fp, LLPolyMeshSharedData *mesh) llendianswizzle(&mTexCoords[v].mV, sizeof(F32), 2); if (numRead != 2) { - llwarns << "Can't read morph target uv" << llendl; + LL_WARNS() << "Can't read morph target uv" << LL_ENDL; return FALSE; } @@ -265,7 +265,7 @@ BOOL LLPolyMorphData::saveLLM(LLFILE *fp) llendianswizzle(&numVertices, sizeof(S32), 1); if (fwrite(&numVertices, sizeof(S32), 1, fp) != 1) { - llwarns << "Short write" << llendl; + LL_WARNS() << "Short write" << LL_ENDL; } numVertices = mNumIndices; // without the swizzle again @@ -277,35 +277,35 @@ BOOL LLPolyMorphData::saveLLM(LLFILE *fp) llendianswizzle(&mVertexIndices[v], sizeof(U32), 1); if (fwrite(&mVertexIndices[v], sizeof(U32), 1, fp) != 1) { - llwarns << "Short write" << llendl; + LL_WARNS() << "Short write" << LL_ENDL; } llendianswizzle(&mVertexIndices[v], sizeof(U32), 1); llendianswizzle(mCoords[v].getF32ptr(), sizeof(F32), 3); if (fwrite(mCoords[v].getF32ptr(), sizeof(F32), 3, fp) != 3) { - llwarns << "Short write" << llendl; + LL_WARNS() << "Short write" << LL_ENDL; } llendianswizzle(mCoords[v].getF32ptr(), sizeof(F32), 3); llendianswizzle(mNormals[v].getF32ptr(), sizeof(F32), 3); if (fwrite(mNormals[v].getF32ptr(), sizeof(F32), 3, fp) != 3) { - llwarns << "Short write" << llendl; + LL_WARNS() << "Short write" << LL_ENDL; } llendianswizzle(mNormals[v].getF32ptr(), sizeof(F32), 3); llendianswizzle(mBinormals[v].getF32ptr(), sizeof(F32), 3); if (fwrite(mBinormals[v].getF32ptr(), sizeof(F32), 3, fp) != 3) { - llwarns << "Short write" << llendl; + LL_WARNS() << "Short write" << LL_ENDL; } llendianswizzle(mBinormals[v].getF32ptr(), sizeof(F32), 3); llendianswizzle(&mTexCoords[v].mV, sizeof(F32), 2); if (fwrite(&mTexCoords[v].mV, sizeof(F32), 2, fp) != 2) { - llwarns << "Short write" << llendl; + LL_WARNS() << "Short write" << LL_ENDL; } llendianswizzle(&mTexCoords[v].mV, sizeof(F32), 2); } @@ -566,7 +566,7 @@ BOOL LLPolyMorphTargetInfo::parseXml(LLXmlTreeNode* node) static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name"); if( !node->getFastAttributeString( name_string, mMorphName ) ) { - llwarns << "Avatar file: is missing name attribute" << llendl; + LL_WARNS() << "Avatar file: is missing name attribute" << LL_ENDL; return FALSE; // Continue, ignoring this tag } @@ -577,8 +577,8 @@ BOOL LLPolyMorphTargetInfo::parseXml(LLXmlTreeNode* node) if (NULL == paramNode) { - llwarns << "Failed to getChildByName(\"param_morph\")" - << llendl; + LL_WARNS() << "Failed to getChildByName(\"param_morph\")" + << LL_ENDL; return FALSE; } @@ -612,10 +612,27 @@ BOOL LLPolyMorphTargetInfo::parseXml(LLXmlTreeNode* node) // LLPolyMorphTarget() //----------------------------------------------------------------------------- LLPolyMorphTarget::LLPolyMorphTarget(LLPolyMesh *poly_mesh) - : mMorphData(NULL), mMesh(poly_mesh), - mVertMask(NULL), - mLastSex(SEX_FEMALE), - mNumMorphMasksPending(0) + : LLViewerVisualParam(), + mMorphData(NULL), + mMesh(poly_mesh), + mVertMask(NULL), + mLastSex(SEX_FEMALE), + mNumMorphMasksPending(0), + mVolumeMorphs() +{ +} + +//----------------------------------------------------------------------------- +// LLPolyMorphTarget() +//----------------------------------------------------------------------------- +LLPolyMorphTarget::LLPolyMorphTarget(const LLPolyMorphTarget& pOther) + : LLViewerVisualParam(pOther), + mMorphData(pOther.mMorphData), + mMesh(pOther.mMesh), + mVertMask(pOther.mVertMask == NULL ? NULL : new LLPolyVertexMask(*pOther.mVertMask)), + mLastSex(pOther.mLastSex), + mNumMorphMasksPending(pOther.mNumMorphMasksPending), + mVolumeMorphs(pOther.mVolumeMorphs) { } @@ -624,10 +641,8 @@ LLPolyMorphTarget::LLPolyMorphTarget(LLPolyMesh *poly_mesh) //----------------------------------------------------------------------------- LLPolyMorphTarget::~LLPolyMorphTarget() { - if (mVertMask) - { - delete mVertMask; - } + delete mVertMask; + mVertMask = NULL; } //----------------------------------------------------------------------------- @@ -640,18 +655,18 @@ BOOL LLPolyMorphTarget::setInfo(LLPolyMorphTargetInfo* info) return FALSE; mInfo = info; mID = info->mID; - setWeight(getDefaultWeight(), FALSE ); + setWeight(getDefaultWeight()); LLAvatarAppearance* avatarp = mMesh->getAvatar(); LLPolyMorphTargetInfo::volume_info_list_t::iterator iter; for (iter = getInfo()->mVolumeInfoList.begin(); iter != getInfo()->mVolumeInfoList.end(); iter++) { LLPolyVolumeMorphInfo *volume_info = &(*iter); - for (S32 i = 0; i < avatarp->mNumCollisionVolumes; i++) + for (S32 i = 0; i < (S32)avatarp->mCollisionVolumes.size(); i++) { - if (avatarp->mCollisionVolumes[i].getName() == volume_info->mName) + if (avatarp->mCollisionVolumes[i]->getName() == volume_info->mName) { - mVolumeMorphs.push_back(LLPolyVolumeMorph(&avatarp->mCollisionVolumes[i], + mVolumeMorphs.push_back(LLPolyVolumeMorph(avatarp->mCollisionVolumes[i], volume_info->mScale, volume_info->mPos)); break; @@ -665,8 +680,8 @@ BOOL LLPolyMorphTarget::setInfo(LLPolyMorphTargetInfo* info) if (!mMorphData) { const std::string driven_tag = "_Driven"; - U32 pos = morph_param_name.find(driven_tag); - if (pos > 0) + size_t pos = morph_param_name.find(driven_tag); + if (pos != std::string::npos) { morph_param_name = morph_param_name.substr(0,pos); mMorphData = mMesh->getMorphData(morph_param_name); @@ -674,7 +689,7 @@ BOOL LLPolyMorphTarget::setInfo(LLPolyMorphTargetInfo* info) } if (!mMorphData) { - llwarns << "No morph target named " << morph_param_name << " found in mesh." << llendl; + LL_WARNS() << "No morph target named " << morph_param_name << " found in mesh." << LL_ENDL; return FALSE; // Continue, ignoring this tag } return TRUE; @@ -682,9 +697,7 @@ BOOL LLPolyMorphTarget::setInfo(LLPolyMorphTargetInfo* info) /*virtual*/ LLViewerVisualParam* LLPolyMorphTarget::cloneParam(LLWearable* wearable) const { - LLPolyMorphTarget *new_param = new LLPolyMorphTarget(mMesh); - *new_param = *this; - return new_param; + return new LLPolyMorphTarget(*this); } #if 0 // obsolete @@ -822,7 +835,7 @@ F32 LLPolyMorphTarget::getMaxDistortion() //----------------------------------------------------------------------------- // apply() //----------------------------------------------------------------------------- -static LLFastTimer::DeclareTimer FTM_APPLY_MORPH_TARGET("Apply Morph"); +static LLTrace::BlockTimerStatHandle FTM_APPLY_MORPH_TARGET("Apply Morph"); void LLPolyMorphTarget::apply( ESex avatar_sex ) { @@ -831,7 +844,7 @@ void LLPolyMorphTarget::apply( ESex avatar_sex ) return; } - LLFastTimer t(FTM_APPLY_MORPH_TARGET); + LL_RECORD_BLOCK_TIME(FTM_APPLY_MORPH_TARGET); mLastSex = avatar_sex; @@ -924,7 +937,7 @@ void LLPolyMorphTarget::apply( ESex avatar_sex ) } // now apply volume changes - for( volume_list_t::iterator iter = mVolumeMorphs.begin(); iter != mVolumeMorphs.end(); iter++ ) + for( volume_list_t::iterator iter = mVolumeMorphs.begin(); iter != mVolumeMorphs.end(); ++iter ) { LLPolyVolumeMorph* volume_morph = &(*iter); LLVector3 scale_delta = volume_morph->mScale * delta_weight; @@ -1014,15 +1027,44 @@ void LLPolyMorphTarget::applyMask(U8 *maskTextureData, S32 width, S32 height, S3 apply(mLastSex); } +void LLPolyMorphTarget::applyVolumeChanges(F32 delta_weight) +{ + // now apply volume changes + for( volume_list_t::iterator iter = mVolumeMorphs.begin(); iter != mVolumeMorphs.end(); ++iter ) + { + LLPolyVolumeMorph* volume_morph = &(*iter); + LLVector3 scale_delta = volume_morph->mScale * delta_weight; + LLVector3 pos_delta = volume_morph->mPos * delta_weight; + + volume_morph->mVolume->setScale(volume_morph->mVolume->getScale() + scale_delta); + // SL-315 + volume_morph->mVolume->setPosition(volume_morph->mVolume->getPosition() + pos_delta); + } +} //----------------------------------------------------------------------------- // LLPolyVertexMask() //----------------------------------------------------------------------------- LLPolyVertexMask::LLPolyVertexMask(LLPolyMorphData* morph_data) + : mWeights(new F32[morph_data->mNumIndices]), + mMorphData(morph_data), + mWeightsGenerated(FALSE) +{ + llassert(mMorphData != NULL); + llassert(mMorphData->mNumIndices > 0); +} + +//----------------------------------------------------------------------------- +// LLPolyVertexMask() +//----------------------------------------------------------------------------- +LLPolyVertexMask::LLPolyVertexMask(const LLPolyVertexMask& pOther) + : mWeights(new F32[pOther.mMorphData->mNumIndices]), + mMorphData(pOther.mMorphData), + mWeightsGenerated(pOther.mWeightsGenerated) { - mWeights = new F32[morph_data->mNumIndices]; - mMorphData = morph_data; - mWeightsGenerated = FALSE; + llassert(mMorphData != NULL); + llassert(mMorphData->mNumIndices > 0); + memcpy(mWeights, pOther.mWeights, sizeof(F32) * mMorphData->mNumIndices); } //----------------------------------------------------------------------------- @@ -1030,7 +1072,8 @@ LLPolyVertexMask::LLPolyVertexMask(LLPolyMorphData* morph_data) //----------------------------------------------------------------------------- LLPolyVertexMask::~LLPolyVertexMask() { - delete[] mWeights; + delete [] mWeights; + mWeights = NULL; } //----------------------------------------------------------------------------- diff --git a/indra/llappearance/llpolymorph.h b/indra/llappearance/llpolymorph.h index 03915d3dac..7c6dca9ec6 100644 --- a/indra/llappearance/llpolymorph.h +++ b/indra/llappearance/llpolymorph.h @@ -95,6 +95,7 @@ class LLPolyVertexMask { public: LLPolyVertexMask(LLPolyMorphData* morph_data); + LLPolyVertexMask(const LLPolyVertexMask& pOther); ~LLPolyVertexMask(); void generateMask(U8 *maskData, S32 width, S32 height, S32 num_components, BOOL invert, LLVector4a *clothing_weights); @@ -173,6 +174,7 @@ class LLPolyMorphTarget : public LLViewerVisualParam // LLVisualParam Virtual functions ///*virtual*/ BOOL parseData(LLXmlTreeNode* node); /*virtual*/ void apply( ESex sex ); + /*virtual*/ char const* getTypeString(void) const { return "param_morph"; } // LLViewerVisualParam Virtual functions /*virtual*/ F32 getTotalDistortion(); @@ -184,8 +186,21 @@ class LLPolyMorphTarget : public LLViewerVisualParam void applyMask(U8 *maskData, S32 width, S32 height, S32 num_components, BOOL invert); void addPendingMorphMask() { mNumMorphMasksPending++; } + void applyVolumeChanges(F32 delta_weight); // SL-315 - for resetSkeleton() + + void* operator new(size_t size) + { + return ll_aligned_malloc_16(size); + } + + void operator delete(void* ptr) + { + ll_aligned_free_16(ptr); + } protected: + LLPolyMorphTarget(const LLPolyMorphTarget& pOther); + LLPolyMorphData* mMorphData; LLPolyMesh* mMesh; LLPolyVertexMask * mVertMask; diff --git a/indra/llappearance/llpolyskeletaldistortion.cpp b/indra/llappearance/llpolyskeletaldistortion.cpp index efdf5c577a..a9debf4b47 100644 --- a/indra/llappearance/llpolyskeletaldistortion.cpp +++ b/indra/llappearance/llpolyskeletaldistortion.cpp @@ -61,8 +61,8 @@ BOOL LLPolySkeletalDistortionInfo::parseXml(LLXmlTreeNode* node) if (NULL == skeletalParam) { - llwarns << "Failed to getChildByName(\"param_skeleton\")" - << llendl; + LL_WARNS() << "Failed to getChildByName(\"param_skeleton\")" + << LL_ENDL; return FALSE; } @@ -78,14 +78,14 @@ BOOL LLPolySkeletalDistortionInfo::parseXml(LLXmlTreeNode* node) static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name"); if (!bone->getFastAttributeString(name_string, name)) { - llwarns << "No bone name specified for skeletal param." << llendl; + LL_WARNS() << "No bone name specified for skeletal param." << LL_ENDL; continue; } static LLStdStringHandle scale_string = LLXmlTree::addAttributeString("scale"); if (!bone->getFastAttributeVector3(scale_string, scale)) { - llwarns << "No scale specified for bone " << name << "." << llendl; + LL_WARNS() << "No scale specified for bone " << name << "." << LL_ENDL; continue; } @@ -99,7 +99,7 @@ BOOL LLPolySkeletalDistortionInfo::parseXml(LLXmlTreeNode* node) } else { - llwarns << "Unrecognized element " << bone->getName() << " in skeletal distortion" << llendl; + LL_WARNS() << "Unrecognized element " << bone->getName() << " in skeletal distortion" << LL_ENDL; continue; } } @@ -110,9 +110,25 @@ BOOL LLPolySkeletalDistortionInfo::parseXml(LLXmlTreeNode* node) // LLPolySkeletalDistortion() //----------------------------------------------------------------------------- LLPolySkeletalDistortion::LLPolySkeletalDistortion(LLAvatarAppearance *avatarp) + : LLViewerVisualParam(), + mDefaultVec(), + mJointScales(), + mJointOffsets(), + mAvatar(avatarp) +{ + mDefaultVec.splat(0.001f); +} + +//----------------------------------------------------------------------------- +// LLPolySkeletalDistortion() +//----------------------------------------------------------------------------- +LLPolySkeletalDistortion::LLPolySkeletalDistortion(const LLPolySkeletalDistortion &pOther) + : LLViewerVisualParam(pOther), + mDefaultVec(pOther.mDefaultVec), + mJointScales(pOther.mJointScales), + mJointOffsets(pOther.mJointOffsets), + mAvatar(pOther.mAvatar) { - mAvatar = avatarp; - mDefaultVec.splat(0.001f); } //----------------------------------------------------------------------------- @@ -125,104 +141,117 @@ LLPolySkeletalDistortion::~LLPolySkeletalDistortion() BOOL LLPolySkeletalDistortion::setInfo(LLPolySkeletalDistortionInfo *info) { llassert(mInfo == NULL); - if (info->mID < 0) - return FALSE; - mInfo = info; - mID = info->mID; - setWeight(getDefaultWeight(), FALSE ); - - LLPolySkeletalDistortionInfo::bone_info_list_t::iterator iter; - for (iter = getInfo()->mBoneInfoList.begin(); iter != getInfo()->mBoneInfoList.end(); iter++) + if (info->mID < 0) + { + return FALSE; + } + mInfo = info; + mID = info->mID; + setWeight(getDefaultWeight()); + + LLPolySkeletalDistortionInfo::bone_info_list_t::iterator iter; + for (iter = getInfo()->mBoneInfoList.begin(); iter != getInfo()->mBoneInfoList.end(); ++iter) + { + LLPolySkeletalBoneInfo *bone_info = &(*iter); + LLJoint* joint = mAvatar->getJoint(bone_info->mBoneName); + if (!joint) + { + // There's no point continuing after this error - means + // that either the skeleton or lad file is broken. + LL_WARNS() << "Joint " << bone_info->mBoneName << " not found." << LL_ENDL; + return FALSE; + } + + if (mJointScales.find(joint) != mJointScales.end()) { - LLPolySkeletalBoneInfo *bone_info = &(*iter); - LLJoint* joint = mAvatar->getJoint(bone_info->mBoneName); - if (!joint) - { - llwarns << "Joint " << bone_info->mBoneName << " not found." << llendl; - continue; - } - - if (mJointScales.find(joint) != mJointScales.end()) - { - llwarns << "Scale deformation already supplied for joint " << joint->getName() << "." << llendl; - } - - // store it - mJointScales[joint] = bone_info->mScaleDeformation; - - // apply to children that need to inherit it - for (LLJoint::child_list_t::iterator iter = joint->mChildren.begin(); - iter != joint->mChildren.end(); ++iter) - { - LLAvatarJoint* child_joint = (LLAvatarJoint*)(*iter); - if (child_joint->inheritScale()) - { - LLVector3 childDeformation = LLVector3(child_joint->getScale()); - childDeformation.scaleVec(bone_info->mScaleDeformation); - mJointScales[child_joint] = childDeformation; - } - } - - if (bone_info->mHasPositionDeformation) - { - if (mJointOffsets.find(joint) != mJointOffsets.end()) - { - llwarns << "Offset deformation already supplied for joint " << joint->getName() << "." << llendl; - } - mJointOffsets[joint] = bone_info->mPositionDeformation; - } + LL_WARNS() << "Scale deformation already supplied for joint " << joint->getName() << "." << LL_ENDL; } - return TRUE; + + // store it + mJointScales[joint] = bone_info->mScaleDeformation; + + // apply to children that need to inherit it + for (LLJoint::child_list_t::iterator iter = joint->mChildren.begin(); + iter != joint->mChildren.end(); ++iter) + { + LLAvatarJoint* child_joint = dynamic_cast(*iter); + if (child_joint && child_joint->inheritScale()) + { + LLVector3 childDeformation = LLVector3(child_joint->getScale()); + childDeformation.scaleVec(bone_info->mScaleDeformation); + mJointScales[child_joint] = childDeformation; + } + } + + if (bone_info->mHasPositionDeformation) + { + if (mJointOffsets.find(joint) != mJointOffsets.end()) + { + LL_WARNS() << "Offset deformation already supplied for joint " << joint->getName() << "." << LL_ENDL; + } + mJointOffsets[joint] = bone_info->mPositionDeformation; + } + } + return TRUE; } /*virtual*/ LLViewerVisualParam* LLPolySkeletalDistortion::cloneParam(LLWearable* wearable) const { - LLPolySkeletalDistortion *new_param = new LLPolySkeletalDistortion(mAvatar); - *new_param = *this; - return new_param; + return new LLPolySkeletalDistortion(*this); } //----------------------------------------------------------------------------- // apply() //----------------------------------------------------------------------------- -static LLFastTimer::DeclareTimer FTM_POLYSKELETAL_DISTORTION_APPLY("Skeletal Distortion"); +static LLTrace::BlockTimerStatHandle FTM_POLYSKELETAL_DISTORTION_APPLY("Skeletal Distortion"); void LLPolySkeletalDistortion::apply( ESex avatar_sex ) { - LLFastTimer t(FTM_POLYSKELETAL_DISTORTION_APPLY); + LL_RECORD_BLOCK_TIME(FTM_POLYSKELETAL_DISTORTION_APPLY); - F32 effective_weight = ( getSex() & avatar_sex ) ? mCurWeight : getDefaultWeight(); + F32 effective_weight = ( getSex() & avatar_sex ) ? mCurWeight : getDefaultWeight(); - LLJoint* joint; - joint_vec_map_t::iterator iter; + LLJoint* joint; + joint_vec_map_t::iterator iter; for (iter = mJointScales.begin(); iter != mJointScales.end(); - iter++) + ++iter) { joint = iter->first; LLVector3 newScale = joint->getScale(); - LLVector3 scaleDelta = iter->second; - newScale = newScale + (effective_weight * scaleDelta) - (mLastWeight * scaleDelta); - joint->setScale(newScale); + LLVector3 scaleDelta = iter->second; + LLVector3 offset = (effective_weight - mLastWeight) * scaleDelta; + newScale = newScale + offset; + //An aspect of attached mesh objects (which contain joint offsets) that need to be cleaned up when detached + // needed? + // joint->storeScaleForReset( newScale ); + + // BENTO for detailed stack tracing of params. + // std::stringstream ostr; + // ostr << "LLPolySkeletalDistortion::apply, id " << getID() << " " << getName() << " effective wt " << effective_weight << " last wt " << mLastWeight << " scaleDelta " << scaleDelta << " offset " << offset; + + joint->setScale(newScale, true); } - for (iter = mJointOffsets.begin(); - iter != mJointOffsets.end(); - iter++) - { - joint = iter->first; - LLVector3 newPosition = joint->getPosition(); - LLVector3 positionDelta = iter->second; + for (iter = mJointOffsets.begin(); + iter != mJointOffsets.end(); + ++iter) + { + joint = iter->first; + LLVector3 newPosition = joint->getPosition(); + LLVector3 positionDelta = iter->second; newPosition = newPosition + (effective_weight * positionDelta) - (mLastWeight * positionDelta); - joint->setPosition(newPosition); - } + // SL-315 + bool allow_attachment_pos_overrides = true; + joint->setPosition(newPosition, allow_attachment_pos_overrides); + } - if (mLastWeight != mCurWeight && !mIsAnimating) + if (mLastWeight != effective_weight && !mIsAnimating) { mAvatar->setSkeletonSerialNum(mAvatar->getSkeletonSerialNum() + 1); } - mLastWeight = mCurWeight; + mLastWeight = effective_weight; } diff --git a/indra/llappearance/llpolyskeletaldistortion.h b/indra/llappearance/llpolyskeletaldistortion.h index 774bc7dfa2..c915a822f0 100644 --- a/indra/llappearance/llpolyskeletaldistortion.h +++ b/indra/llappearance/llpolyskeletaldistortion.h @@ -39,7 +39,6 @@ //#include "llpolymorph.h" #include "lljoint.h" #include "llviewervisualparam.h" -//#include "lldarray.h" //class LLSkinJoint; class LLAvatarAppearance; @@ -74,15 +73,28 @@ class LLPolySkeletalDistortionInfo : public LLViewerVisualParamInfo /*virtual*/ BOOL parseXml(LLXmlTreeNode* node); + + + void* operator new(size_t size) + { + return ll_aligned_malloc_16(size); + } + + void operator delete(void* ptr) + { + ll_aligned_free_16(ptr); + } + + protected: typedef std::vector bone_info_list_t; bone_info_list_t mBoneInfoList; -}; - +} LL_ALIGN_POSTFIX(16); //----------------------------------------------------------------------------- // LLPolySkeletalDeformation // A set of joint scale data for deforming the avatar mesh //----------------------------------------------------------------------------- +LL_ALIGN_PREFIX(16) class LLPolySkeletalDistortion : public LLViewerVisualParam { public: @@ -109,7 +121,8 @@ class LLPolySkeletalDistortion : public LLViewerVisualParam // LLVisualParam Virtual functions ///*virtual*/ BOOL parseData(LLXmlTreeNode* node); /*virtual*/ void apply( ESex sex ); - + /*virtual*/ char const* getTypeString(void) const { return "param_skeleton"; } + // LLViewerVisualParam Virtual functions /*virtual*/ F32 getTotalDistortion() { return 0.1f; } /*virtual*/ const LLVector4a& getAvgDistortion() { return mDefaultVec; } @@ -119,6 +132,8 @@ class LLPolySkeletalDistortion : public LLViewerVisualParam /*virtual*/ const LLVector4a* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh){index = 0; poly_mesh = NULL; return NULL;}; protected: + LLPolySkeletalDistortion(const LLPolySkeletalDistortion& pOther); + LL_ALIGN_16(LLVector4a mDefaultVec); typedef std::map joint_vec_map_t; joint_vec_map_t mJointScales; diff --git a/indra/llappearance/lltexglobalcolor.cpp b/indra/llappearance/lltexglobalcolor.cpp index f38b982104..0df6981536 100644 --- a/indra/llappearance/lltexglobalcolor.cpp +++ b/indra/llappearance/lltexglobalcolor.cpp @@ -57,7 +57,7 @@ BOOL LLTexGlobalColor::setInfo(LLTexGlobalColorInfo *info) mParamGlobalColorList.reserve(mInfo->mParamColorInfoList.size()); for (param_color_info_list_t::iterator iter = mInfo->mParamColorInfoList.begin(); iter != mInfo->mParamColorInfoList.end(); - iter++) + ++iter) { LLTexParamGlobalColor* param_color = new LLTexParamGlobalColor(this); if (!param_color->setInfo(*iter, TRUE)) @@ -90,22 +90,37 @@ const std::string& LLTexGlobalColor::getName() const //----------------------------------------------------------------------------- // LLTexParamGlobalColor //----------------------------------------------------------------------------- -LLTexParamGlobalColor::LLTexParamGlobalColor(LLTexGlobalColor* tex_global_color) : - LLTexLayerParamColor(tex_global_color->getAvatarAppearance()), +LLTexParamGlobalColor::LLTexParamGlobalColor(LLTexGlobalColor* tex_global_color) + : LLTexLayerParamColor(tex_global_color->getAvatarAppearance()), mTexGlobalColor(tex_global_color) { } +//----------------------------------------------------------------------------- +// LLTexParamGlobalColor +//----------------------------------------------------------------------------- +LLTexParamGlobalColor::LLTexParamGlobalColor(const LLTexParamGlobalColor& pOther) + : LLTexLayerParamColor(pOther), + mTexGlobalColor(pOther.mTexGlobalColor) +{ +} + +//----------------------------------------------------------------------------- +// ~LLTexParamGlobalColor +//----------------------------------------------------------------------------- +LLTexParamGlobalColor::~LLTexParamGlobalColor() +{ +} + /*virtual*/ LLViewerVisualParam* LLTexParamGlobalColor::cloneParam(LLWearable* wearable) const { - LLTexParamGlobalColor *new_param = new LLTexParamGlobalColor(mTexGlobalColor); - *new_param = *this; - return new_param; + return new LLTexParamGlobalColor(*this); } void LLTexParamGlobalColor::onGlobalColorChanged(bool upload_bake) { - mAvatarAppearance->onGlobalColorChanged(mTexGlobalColor, upload_bake); + if (mAvatarAppearance) + mAvatarAppearance->onGlobalColorChanged(mTexGlobalColor, upload_bake); } //----------------------------------------------------------------------------- @@ -120,6 +135,7 @@ LLTexGlobalColorInfo::LLTexGlobalColorInfo() LLTexGlobalColorInfo::~LLTexGlobalColorInfo() { for_each(mParamColorInfoList.begin(), mParamColorInfoList.end(), DeletePointer()); + mParamColorInfoList.clear(); } BOOL LLTexGlobalColorInfo::parseXml(LLXmlTreeNode* node) @@ -128,7 +144,7 @@ BOOL LLTexGlobalColorInfo::parseXml(LLXmlTreeNode* node) static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name"); if (!node->getFastAttributeString(name_string, mName)) { - llwarns << " element is missing name attribute." << llendl; + LL_WARNS() << " element is missing name attribute." << LL_ENDL; return FALSE; } // sub-element diff --git a/indra/llappearance/lltexglobalcolor.h b/indra/llappearance/lltexglobalcolor.h index 2867479876..e32e08bf0d 100644 --- a/indra/llappearance/lltexglobalcolor.h +++ b/indra/llappearance/lltexglobalcolor.h @@ -73,9 +73,11 @@ class LLTexParamGlobalColor : public LLTexLayerParamColor { public: LLTexParamGlobalColor(LLTexGlobalColor *tex_color); + virtual ~LLTexParamGlobalColor(); /*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const; protected: - /*virtual*/ void onGlobalColorChanged(bool upload_bake); + LLTexParamGlobalColor(const LLTexParamGlobalColor& pOther); + /*virtual*/ void onGlobalColorChanged(bool upload_bake = false); private: LLTexGlobalColor* mTexGlobalColor; }; diff --git a/indra/llappearance/lltexlayer.cpp b/indra/llappearance/lltexlayer.cpp index c57bedd8f5..83a72eeb1c 100644 --- a/indra/llappearance/lltexlayer.cpp +++ b/indra/llappearance/lltexlayer.cpp @@ -43,6 +43,7 @@ #include "llwearabledata.h" #include "llvertexbuffer.h" #include "llviewervisualparam.h" +#include "lllocaltextureobject.h" //#include "../tools/imdebug/imdebug.h" @@ -155,7 +156,7 @@ BOOL LLTexLayerSetBuffer::renderTexLayerSet() gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.00f); } - LLVertexBuffer::unbind(); + //LLVertexBuffer::unbind(); // Composite the color data LLGLSUIDefault gls_ui; @@ -170,7 +171,7 @@ BOOL LLTexLayerSetBuffer::renderTexLayerSet() gAlphaMaskProgram.unbind(); } - LLVertexBuffer::unbind(); + //LLVertexBuffer::unbind(); // reset GL state gGL.setColorMask(true, true); @@ -209,7 +210,7 @@ BOOL LLTexLayerSetInfo::parseXml(LLXmlTreeNode* node) static LLStdStringHandle body_region_string = LLXmlTree::addAttributeString("body_region"); if( !node->getFastAttributeString( body_region_string, mBodyRegion ) ) { - llwarns << " is missing body_region attribute" << llendl; + LL_WARNS() << " is missing body_region attribute" << LL_ENDL; return FALSE; } @@ -255,7 +256,7 @@ void LLTexLayerSetInfo::createVisualParams(LLAvatarAppearance *appearance) //layer_info_list_t mLayerInfoList; for (layer_info_list_t::iterator layer_iter = mLayerInfoList.begin(); layer_iter != mLayerInfoList.end(); - layer_iter++) + ++layer_iter) { LLTexLayerInfo *layer_info = *layer_iter; layer_info->createVisualParams(appearance); @@ -298,7 +299,7 @@ BOOL LLTexLayerSet::setInfo(const LLTexLayerSetInfo *info) mLayerList.reserve(info->mLayerInfoList.size()); for (LLTexLayerSetInfo::layer_info_list_t::const_iterator iter = info->mLayerInfoList.begin(); iter != info->mLayerInfoList.end(); - iter++) + ++iter) { LLTexLayerInterface *layer = NULL; if ( (*iter)->isUserSettable() ) @@ -357,12 +358,12 @@ BOOL LLTexLayerSet::parseData(LLXmlTreeNode* node) void LLTexLayerSet::deleteCaches() { - for( layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); iter++ ) + for( layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); ++iter ) { LLTexLayerInterface* layer = *iter; layer->deleteCaches(); } - for (layer_list_t::iterator iter = mMaskLayerList.begin(); iter != mMaskLayerList.end(); iter++) + for (layer_list_t::iterator iter = mMaskLayerList.begin(); iter != mMaskLayerList.end(); ++iter) { LLTexLayerInterface* layer = *iter; layer->deleteCaches(); @@ -377,7 +378,7 @@ BOOL LLTexLayerSet::render( S32 x, S32 y, S32 width, S32 height ) if (mMaskLayerList.size() > 0) { - for (layer_list_t::iterator iter = mMaskLayerList.begin(); iter != mMaskLayerList.end(); iter++) + for (layer_list_t::iterator iter = mMaskLayerList.begin(); iter != mMaskLayerList.end(); ++iter) { LLTexLayerInterface* layer = *iter; if (layer->isInvisibleAlphaMask()) @@ -396,7 +397,7 @@ BOOL LLTexLayerSet::render( S32 x, S32 y, S32 width, S32 height ) // clear buffer area to ensure we don't pick up UI elements { gGL.flush(); - LLGLDisable no_alpha(GL_ALPHA_TEST); + LLGLDisable no_alpha; if (use_shaders) { gAlphaMaskProgram.setMinimumAlpha(0.0f); @@ -416,7 +417,7 @@ BOOL LLTexLayerSet::render( S32 x, S32 y, S32 width, S32 height ) if (mIsVisible) { // composite color layers - for( layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); iter++ ) + for( layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); ++iter ) { LLTexLayerInterface* layer = *iter; if (layer->getRenderPass() == LLTexLayer::RP_COLOR) @@ -436,7 +437,7 @@ BOOL LLTexLayerSet::render( S32 x, S32 y, S32 width, S32 height ) gGL.flush(); gGL.setSceneBlendType(LLRender::BT_REPLACE); - LLGLDisable no_alpha(GL_ALPHA_TEST); + LLGLDisable no_alpha; if (use_shaders) { gAlphaMaskProgram.setMinimumAlpha(0.f); @@ -520,13 +521,13 @@ const LLTexLayerSetBuffer* LLTexLayerSet::getComposite() const return mComposite; } -static LLFastTimer::DeclareTimer FTM_GATHER_MORPH_MASK_ALPHA("gatherMorphMaskAlpha"); +static LLTrace::BlockTimerStatHandle FTM_GATHER_MORPH_MASK_ALPHA("gatherMorphMaskAlpha"); void LLTexLayerSet::gatherMorphMaskAlpha(U8 *data, S32 origin_x, S32 origin_y, S32 width, S32 height) { - LLFastTimer t(FTM_GATHER_MORPH_MASK_ALPHA); + LL_RECORD_BLOCK_TIME(FTM_GATHER_MORPH_MASK_ALPHA); memset(data, 255, width * height); - for( layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); iter++ ) + for( layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); ++iter ) { LLTexLayerInterface* layer = *iter; layer->gatherAlphaMasks(data, origin_x, origin_y, width, height); @@ -536,10 +537,10 @@ void LLTexLayerSet::gatherMorphMaskAlpha(U8 *data, S32 origin_x, S32 origin_y, S renderAlphaMaskTextures(origin_x, origin_y, width, height, true); } -static LLFastTimer::DeclareTimer FTM_RENDER_ALPHA_MASK_TEXTURES("renderAlphaMaskTextures"); +static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_MASK_TEXTURES("renderAlphaMaskTextures"); void LLTexLayerSet::renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height, bool forceClear) { - LLFastTimer t(FTM_RENDER_ALPHA_MASK_TEXTURES); + LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK_TEXTURES); const LLTexLayerSetInfo *info = getInfo(); bool use_shaders = LLGLSLShader::sNoFixedFunction; @@ -567,7 +568,7 @@ void LLTexLayerSet::renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height, { // Set the alpha channel to one (clean up after previous blending) gGL.flush(); - LLGLDisable no_alpha(GL_ALPHA_TEST); + LLGLDisable no_alpha; if (use_shaders) { gAlphaMaskProgram.setMinimumAlpha(0.f); @@ -590,7 +591,7 @@ void LLTexLayerSet::renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height, { gGL.setSceneBlendType(LLRender::BT_MULT_ALPHA); gGL.getTexUnit(0)->setTextureBlendType( LLTexUnit::TB_REPLACE ); - for (layer_list_t::iterator iter = mMaskLayerList.begin(); iter != mMaskLayerList.end(); iter++) + for (layer_list_t::iterator iter = mMaskLayerList.begin(); iter != mMaskLayerList.end(); ++iter) { LLTexLayerInterface* layer = *iter; gGL.flush(); @@ -614,7 +615,7 @@ void LLTexLayerSet::applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_ BOOL LLTexLayerSet::isMorphValid() const { - for(layer_list_t::const_iterator iter = mLayerList.begin(); iter != mLayerList.end(); iter++ ) + for(layer_list_t::const_iterator iter = mLayerList.begin(); iter != mLayerList.end(); ++iter ) { const LLTexLayerInterface* layer = *iter; if (layer && !layer->isMorphValid()) @@ -627,7 +628,7 @@ BOOL LLTexLayerSet::isMorphValid() const void LLTexLayerSet::invalidateMorphMasks() { - for( layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); iter++ ) + for( layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); ++iter ) { LLTexLayerInterface* layer = *iter; if (layer) @@ -726,7 +727,7 @@ BOOL LLTexLayerInfo::parseXml(LLXmlTreeNode* node) mLocalTexture = TEX_NUM_INDICES; for (LLAvatarAppearanceDictionary::Textures::const_iterator iter = LLAvatarAppearanceDictionary::getInstance()->getTextures().begin(); iter != LLAvatarAppearanceDictionary::getInstance()->getTextures().end(); - iter++) + ++iter) { const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = iter->second; if (local_texture_name == texture_dict->mName) @@ -737,13 +738,13 @@ BOOL LLTexLayerInfo::parseXml(LLXmlTreeNode* node) } if (mLocalTexture == TEX_NUM_INDICES) { - llwarns << " element has invalid local_texture attribute: " << mName << " " << local_texture_name << llendl; + LL_WARNS() << " element has invalid local_texture attribute: " << mName << " " << local_texture_name << LL_ENDL; return FALSE; } } else { - llwarns << " element is missing a required attribute. " << mName << llendl; + LL_WARNS() << " element is missing a required attribute. " << mName << LL_ENDL; return FALSE; } } @@ -800,13 +801,13 @@ BOOL LLTexLayerInfo::createVisualParams(LLAvatarAppearance *appearance) BOOL success = TRUE; for (param_color_info_list_t::iterator color_info_iter = mParamColorInfoList.begin(); color_info_iter != mParamColorInfoList.end(); - color_info_iter++) + ++color_info_iter) { LLTexLayerParamColorInfo * color_info = *color_info_iter; LLTexLayerParamColor* param_color = new LLTexLayerParamColor(appearance); if (!param_color->setInfo(color_info, TRUE)) { - llwarns << "NULL TexLayer Color Param could not be added to visual param list. Deleting." << llendl; + LL_WARNS() << "NULL TexLayer Color Param could not be added to visual param list. Deleting." << LL_ENDL; delete param_color; success = FALSE; } @@ -814,13 +815,13 @@ BOOL LLTexLayerInfo::createVisualParams(LLAvatarAppearance *appearance) for (param_alpha_info_list_t::iterator alpha_info_iter = mParamAlphaInfoList.begin(); alpha_info_iter != mParamAlphaInfoList.end(); - alpha_info_iter++) + ++alpha_info_iter) { LLTexLayerParamAlphaInfo * alpha_info = *alpha_info_iter; LLTexLayerParamAlpha* param_alpha = new LLTexLayerParamAlpha(appearance); if (!param_alpha->setInfo(alpha_info, TRUE)) { - llwarns << "NULL TexLayer Alpha Param could not be added to visual param list. Deleting." << llendl; + LL_WARNS() << "NULL TexLayer Alpha Param could not be added to visual param list. Deleting." << LL_ENDL; delete param_alpha; success = FALSE; } @@ -853,7 +854,7 @@ BOOL LLTexLayerInterface::setInfo(const LLTexLayerInfo *info, LLWearable* wearab // Not a critical warning, but could be useful for debugging later issues. -Nyx if (mInfo != NULL) { - llwarns << "mInfo != NULL" << llendl; + LL_WARNS() << "mInfo != NULL" << LL_ENDL; } mInfo = info; //mID = info->mID; // No ID @@ -861,7 +862,7 @@ BOOL LLTexLayerInterface::setInfo(const LLTexLayerInfo *info, LLWearable* wearab mParamColorList.reserve(mInfo->mParamColorInfoList.size()); for (param_color_info_list_t::const_iterator iter = mInfo->mParamColorInfoList.begin(); iter != mInfo->mParamColorInfoList.end(); - iter++) + ++iter) { LLTexLayerParamColor* param_color; if (!wearable) @@ -888,7 +889,7 @@ BOOL LLTexLayerInterface::setInfo(const LLTexLayerInfo *info, LLWearable* wearab mParamAlphaList.reserve(mInfo->mParamAlphaInfoList.size()); for (param_alpha_info_list_t::const_iterator iter = mInfo->mParamAlphaInfoList.begin(); iter != mInfo->mParamAlphaInfoList.end(); - iter++) + ++iter) { LLTexLayerParamAlpha* param_alpha; if (!wearable) @@ -939,7 +940,7 @@ LLWearableType::EType LLTexLayerInterface::getWearableType() const param_color_list_t::const_iterator color_iter = mParamColorList.begin(); param_alpha_list_t::const_iterator alpha_iter = mParamAlphaList.begin(); - for (; color_iter != mParamColorList.end(); color_iter++) + for (; color_iter != mParamColorList.end(); ++color_iter) { LLTexLayerParamColor* param = *color_iter; if (param) @@ -956,7 +957,7 @@ LLWearableType::EType LLTexLayerInterface::getWearableType() const } } - for (; alpha_iter != mParamAlphaList.end(); alpha_iter++) + for (; alpha_iter != mParamAlphaList.end(); ++alpha_iter) { LLTexLayerParamAlpha* param = *alpha_iter; if (param) @@ -1058,7 +1059,7 @@ LLTexLayer::~LLTexLayer() //std::for_each(mParamColorList.begin(), mParamColorList.end(), DeletePointer()); for( alpha_cache_t::iterator iter = mAlphaCache.begin(); - iter != mAlphaCache.end(); iter++ ) + iter != mAlphaCache.end(); ++iter ) { U8* alpha_data = iter->second; delete [] alpha_data; @@ -1085,7 +1086,7 @@ BOOL LLTexLayer::setInfo(const LLTexLayerInfo* info, LLWearable* wearable ) void LLTexLayer::calculateTexLayerColor(const param_color_list_t ¶m_list, LLColor4 &net_color) { for (param_color_list_t::const_iterator iter = param_list.begin(); - iter != param_list.end(); iter++) + iter != param_list.end(); ++iter) { const LLTexLayerParamColor* param = *iter; LLColor4 param_net = param->getNetColor(); @@ -1113,7 +1114,7 @@ void LLTexLayer::calculateTexLayerColor(const param_color_list_t ¶m_list, LL { // Only need to delete caches for alpha params. Color params don't hold extra memory for (param_alpha_list_t::iterator iter = mParamAlphaList.begin(); - iter != mParamAlphaList.end(); iter++ ) + iter != mParamAlphaList.end(); ++iter ) { LLTexLayerParamAlpha* param = *iter; param->deleteCaches(); @@ -1122,11 +1123,11 @@ void LLTexLayer::calculateTexLayerColor(const param_color_list_t ¶m_list, LL BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height) { - LLGLEnable color_mat(GL_COLOR_MATERIAL); + LLGLEnable color_mat; // *TODO: Is this correct? //gPipeline.disableLights(); stop_glerror(); - glDisable(GL_LIGHTING); + LLGLDisable no_lighting(!LLGLSLShader::sNoFixedFunction); stop_glerror(); bool use_shaders = LLGLSLShader::sNoFixedFunction; @@ -1206,14 +1207,14 @@ BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height) } else { - llinfos << "lto not defined or image not defined: " << getInfo()->getLocalTexture() << " lto: " << mLocalTextureObject << llendl; + LL_INFOS() << "lto not defined or image not defined: " << getInfo()->getLocalTexture() << " lto: " << mLocalTextureObject << LL_ENDL; } // if( mTexLayerSet->getAvatarAppearance()->getLocalTextureGL((ETextureIndex)getInfo()->mLocalTexture, &image_gl ) ) { if( tex ) { bool no_alpha_test = getInfo()->mWriteAllChannels; - LLGLDisable alpha_test(no_alpha_test ? GL_ALPHA_TEST : 0); + LLGLDisable alpha_test(no_alpha_test); if (no_alpha_test) { if (use_shaders) @@ -1269,7 +1270,7 @@ BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height) getInfo()->mStaticImageFileName.empty() && color_specified ) { - LLGLDisable no_alpha(GL_ALPHA_TEST); + LLGLDisable no_alpha; if (use_shaders) { gAlphaMaskProgram.setMinimumAlpha(0.000f); @@ -1294,7 +1295,7 @@ BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height) if( !success ) { - llinfos << "LLTexLayer::render() partial: " << getInfo()->mName << llendl; + LL_INFOS() << "LLTexLayer::render() partial: " << getInfo()->mName << LL_ENDL; } return success; } @@ -1305,7 +1306,7 @@ const U8* LLTexLayer::getAlphaData() const const LLUUID& uuid = getUUID(); alpha_mask_crc.update((U8*)(&uuid.mData), UUID_BYTES); - for (param_alpha_list_t::const_iterator iter = mParamAlphaList.begin(); iter != mParamAlphaList.end(); iter++) + for (param_alpha_list_t::const_iterator iter = mParamAlphaList.begin(); iter != mParamAlphaList.end(); ++iter) { const LLTexLayerParamAlpha* param = *iter; // MULTI-WEARABLE: verify visual parameters used here @@ -1426,15 +1427,15 @@ BOOL LLTexLayer::blendAlphaTexture(S32 x, S32 y, S32 width, S32 height) addAlphaMask(data, originX, originY, width, height); } -static LLFastTimer::DeclareTimer FTM_RENDER_MORPH_MASKS("renderMorphMasks"); +static LLTrace::BlockTimerStatHandle FTM_RENDER_MORPH_MASKS("renderMorphMasks"); void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLColor4 &layer_color, bool force_render) { if (!force_render && !hasMorph()) { - lldebugs << "skipping renderMorphMasks for " << getUUID() << llendl; + LL_DEBUGS() << "skipping renderMorphMasks for " << getUUID() << LL_ENDL; return; } - LLFastTimer t(FTM_RENDER_MORPH_MASKS); + LL_RECORD_BLOCK_TIME(FTM_RENDER_MORPH_MASKS); BOOL success = TRUE; llassert( !mParamAlphaList.empty() ); @@ -1452,7 +1453,7 @@ void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC // Note: if the first param is a mulitply, multiply against the current buffer's alpha if( !first_param || !first_param->getMultiplyBlend() ) { - LLGLDisable no_alpha(GL_ALPHA_TEST); + LLGLDisable no_alpha; gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); // Clear the alpha @@ -1466,13 +1467,13 @@ void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC // Accumulate alphas LLGLSNoAlphaTest gls_no_alpha_test; gGL.color4f( 1.f, 1.f, 1.f, 1.f ); - for (param_alpha_list_t::iterator iter = mParamAlphaList.begin(); iter != mParamAlphaList.end(); iter++) + for (param_alpha_list_t::iterator iter = mParamAlphaList.begin(); iter != mParamAlphaList.end(); ++iter) { LLTexLayerParamAlpha* param = *iter; success &= param->render( x, y, width, height ); if (!success && !force_render) { - lldebugs << "Failed to render param " << param->getID() << " ; skipping morph mask." << llendl; + LL_DEBUGS() << "Failed to render param " << param->getID() << " ; skipping morph mask." << LL_ENDL; return; } } @@ -1514,8 +1515,8 @@ void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC } else { - llwarns << "Skipping rendering of " << getInfo()->mStaticImageFileName - << "; expected 1 or 4 components." << llendl; + LL_WARNS() << "Skipping rendering of " << getInfo()->mStaticImageFileName + << "; expected 1 or 4 components." << LL_ENDL; } } } @@ -1524,7 +1525,7 @@ void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC // Note: we're still using gGL.blendFunc( GL_DST_ALPHA, GL_ZERO ); if ( !is_approx_equal(layer_color.mV[VW], 1.f) ) { - LLGLDisable no_alpha(GL_ALPHA_TEST); + LLGLDisable no_alpha; gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); gGL.color4fv(layer_color.mV); gl_rect_2d_simple( width, height ); @@ -1545,7 +1546,7 @@ void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC const LLUUID& uuid = getUUID(); alpha_mask_crc.update((U8*)(&uuid.mData), UUID_BYTES); - for (param_alpha_list_t::const_iterator iter = mParamAlphaList.begin(); iter != mParamAlphaList.end(); iter++) + for (param_alpha_list_t::const_iterator iter = mParamAlphaList.begin(); iter != mParamAlphaList.end(); ++iter) { const LLTexLayerParamAlpha* param = *iter; F32 param_weight = param->getWeight(); @@ -1553,10 +1554,13 @@ void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC } U32 cache_index = alpha_mask_crc.getCRC(); - U8* alpha_data = get_if_there(mAlphaCache,cache_index,(U8*)NULL); - if (!alpha_data) + U8* alpha_data = NULL; + // We believe we need to generate morph masks, do not assume that the cached version is accurate. + // We can get bad morph masks during login, on minimize, and occasional gl errors. + // We should only be doing this when we believe something has changed with respect to the user's appearance. { - // clear out a slot if we have filled our cache + LL_DEBUGS("Avatar") << "gl alpha cache of morph mask not found, doing readback: " << getName() << LL_ENDL; + // clear out a slot if we have filled our cache S32 max_cache_entries = getTexLayerSet()->getAvatarAppearance()->isSelf() ? 4 : 1; while ((S32)mAlphaCache.size() >= max_cache_entries) { @@ -1566,8 +1570,12 @@ void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC mAlphaCache.erase(iter2); } alpha_data = new U8[width * height]; + U8* pixels_tmp = new U8[width * height * 4]; + glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels_tmp); + for (int i = 0; i < width * height; ++i) + alpha_data[i] = pixels_tmp[i * 4 + 3]; + delete[] pixels_tmp; mAlphaCache[cache_index] = alpha_data; - glReadPixels(x, y, width, height, GL_ALPHA, GL_UNSIGNED_BYTE, alpha_data); } getTexLayerSet()->getAvatarAppearance()->dirtyMesh(); @@ -1577,10 +1585,10 @@ void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC } } -static LLFastTimer::DeclareTimer FTM_ADD_ALPHA_MASK("addAlphaMask"); +static LLTrace::BlockTimerStatHandle FTM_ADD_ALPHA_MASK("addAlphaMask"); void LLTexLayer::addAlphaMask(U8 *data, S32 originX, S32 originY, S32 width, S32 height) { - LLFastTimer t(FTM_ADD_ALPHA_MASK); + LL_RECORD_BLOCK_TIME(FTM_ADD_ALPHA_MASK); S32 size = width * height; const U8* alphaData = getAlphaData(); if (!alphaData && hasAlphaParams()) @@ -1733,7 +1741,7 @@ LLTexLayer* LLTexLayerTemplate::getLayer(U32 i) const BOOL success = TRUE; updateWearableCache(); - for (wearable_cache_t::const_iterator iter = mWearableCache.begin(); iter!= mWearableCache.end(); iter++) + for (wearable_cache_t::const_iterator iter = mWearableCache.begin(); iter!= mWearableCache.end(); ++iter) { LLWearable* wearable = NULL; LLLocalTextureObject *lto = NULL; @@ -1776,13 +1784,11 @@ LLTexLayer* LLTexLayerTemplate::getLayer(U32 i) const /*virtual*/ void LLTexLayerTemplate::gatherAlphaMasks(U8 *data, S32 originX, S32 originY, S32 width, S32 height) { U32 num_wearables = updateWearableCache(); - for (U32 i = 0; i < num_wearables; i++) + U32 i = num_wearables - 1; // For rendering morph masks, we only want to use the top wearable + LLTexLayer *layer = getLayer(i); + if (layer) { - LLTexLayer *layer = getLayer(i); - if (layer) - { - layer->addAlphaMask(data, originX, originY, width, height); - } + layer->addAlphaMask(data, originX, originY, width, height); } } @@ -1837,7 +1843,7 @@ LLTexLayer* LLTexLayerTemplate::getLayer(U32 i) const //----------------------------------------------------------------------------- LLTexLayerInterface* LLTexLayerSet::findLayerByName(const std::string& name) { - for (layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); iter++ ) + for (layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); ++iter ) { LLTexLayerInterface* layer = *iter; if (layer->getName() == name) @@ -1845,7 +1851,7 @@ LLTexLayerInterface* LLTexLayerSet::findLayerByName(const std::string& name) return layer; } } - for (layer_list_t::iterator iter = mMaskLayerList.begin(); iter != mMaskLayerList.end(); iter++ ) + for (layer_list_t::iterator iter = mMaskLayerList.begin(); iter != mMaskLayerList.end(); ++iter ) { LLTexLayerInterface* layer = *iter; if (layer->getName() == name) @@ -1859,7 +1865,7 @@ LLTexLayerInterface* LLTexLayerSet::findLayerByName(const std::string& name) void LLTexLayerSet::cloneTemplates(LLLocalTextureObject *lto, LLAvatarAppearanceDefines::ETextureIndex tex_index, LLWearable *wearable) { // initialize all texlayers with this texture type for this LTO - for( LLTexLayerSet::layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); iter++ ) + for( LLTexLayerSet::layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); ++iter ) { LLTexLayerTemplate* layer = (LLTexLayerTemplate*)*iter; if (layer->getInfo()->getLocalTexture() == (S32) tex_index) @@ -1867,7 +1873,7 @@ void LLTexLayerSet::cloneTemplates(LLLocalTextureObject *lto, LLAvatarAppearance lto->addTexLayer(layer, wearable); } } - for( LLTexLayerSet::layer_list_t::iterator iter = mMaskLayerList.begin(); iter != mMaskLayerList.end(); iter++ ) + for( LLTexLayerSet::layer_list_t::iterator iter = mMaskLayerList.begin(); iter != mMaskLayerList.end(); ++iter ) { LLTexLayerTemplate* layer = (LLTexLayerTemplate*)*iter; if (layer->getInfo()->getLocalTexture() == (S32) tex_index) @@ -1894,18 +1900,18 @@ LLTexLayerStaticImageList::~LLTexLayerStaticImageList() void LLTexLayerStaticImageList::dumpByteCount() const { - llinfos << "Avatar Static Textures " << + LL_INFOS() << "Avatar Static Textures " << "KB GL:" << (mGLBytes / 1024) << - "KB TGA:" << (mTGABytes / 1024) << "KB" << llendl; + "KB TGA:" << (mTGABytes / 1024) << "KB" << LL_ENDL; } void LLTexLayerStaticImageList::deleteCachedImages() { if( mGLBytes || mTGABytes ) { - llinfos << "Clearing Static Textures " << + LL_INFOS() << "Clearing Static Textures " << "KB GL:" << (mGLBytes / 1024) << - "KB TGA:" << (mTGABytes / 1024) << "KB" << llendl; + "KB TGA:" << (mTGABytes / 1024) << "KB" << LL_ENDL; //mStaticImageLists uses LLPointers, clear() will cause deletion @@ -1923,10 +1929,10 @@ void LLTexLayerStaticImageList::deleteCachedImages() // Returns an LLImageTGA that contains the encoded data from a tga file named file_name. // Caches the result to speed identical subsequent requests. -static LLFastTimer::DeclareTimer FTM_LOAD_STATIC_TGA("getImageTGA"); +static LLTrace::BlockTimerStatHandle FTM_LOAD_STATIC_TGA("getImageTGA"); LLImageTGA* LLTexLayerStaticImageList::getImageTGA(const std::string& file_name) { - LLFastTimer t(FTM_LOAD_STATIC_TGA); + LL_RECORD_BLOCK_TIME(FTM_LOAD_STATIC_TGA); const char *namekey = mImageNames.addString(file_name); image_tga_map_t::const_iterator iter = mStaticImageListTGA.find(namekey); if( iter != mStaticImageListTGA.end() ) @@ -1953,10 +1959,10 @@ LLImageTGA* LLTexLayerStaticImageList::getImageTGA(const std::string& file_name) // Returns a GL Image (without a backing ImageRaw) that contains the decoded data from a tga file named file_name. // Caches the result to speed identical subsequent requests. -static LLFastTimer::DeclareTimer FTM_LOAD_STATIC_TEXTURE("getTexture"); +static LLTrace::BlockTimerStatHandle FTM_LOAD_STATIC_TEXTURE("getTexture"); LLGLTexture* LLTexLayerStaticImageList::getTexture(const std::string& file_name, BOOL is_mask) { - LLFastTimer t(FTM_LOAD_STATIC_TEXTURE); + LL_RECORD_BLOCK_TIME(FTM_LOAD_STATIC_TEXTURE); LLPointer tex; const char *namekey = mImageNames.addString(file_name); @@ -1984,7 +1990,7 @@ LLGLTexture* LLTexLayerStaticImageList::getTexture(const std::string& file_name, image_raw->copyUnscaledAlphaMask(alpha_image_raw, LLColor4U::black); } - tex->createGLTexture(0, image_raw, 0, TRUE, LLGLTexture::LOCAL); + tex->createGLTexture(0, image_raw, nullptr, TRUE, LLGLTexture::LOCAL); gGL.getTexUnit(0)->bind(tex); tex->setAddressMode(LLTexUnit::TAM_CLAMP); @@ -2003,10 +2009,10 @@ LLGLTexture* LLTexLayerStaticImageList::getTexture(const std::string& file_name, // Reads a .tga file, decodes it, and puts the decoded data in image_raw. // Returns TRUE if successful. -static LLFastTimer::DeclareTimer FTM_LOAD_IMAGE_RAW("loadImageRaw"); +static LLTrace::BlockTimerStatHandle FTM_LOAD_IMAGE_RAW("loadImageRaw"); BOOL LLTexLayerStaticImageList::loadImageRaw(const std::string& file_name, LLImageRaw* image_raw) { - LLFastTimer t(FTM_LOAD_IMAGE_RAW); + LL_RECORD_BLOCK_TIME(FTM_LOAD_IMAGE_RAW); BOOL success = FALSE; std::string path; path = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,file_name); diff --git a/indra/llappearance/lltexlayerparams.cpp b/indra/llappearance/lltexlayerparams.cpp index 64b3b62185..7f3f486ca3 100644 --- a/indra/llappearance/lltexlayerparams.cpp +++ b/indra/llappearance/lltexlayerparams.cpp @@ -39,7 +39,8 @@ //----------------------------------------------------------------------------- // LLTexLayerParam //----------------------------------------------------------------------------- -LLTexLayerParam::LLTexLayerParam(LLTexLayerInterface *layer) : +LLTexLayerParam::LLTexLayerParam(LLTexLayerInterface *layer) + : LLViewerVisualParam(), mTexLayer(layer), mAvatarAppearance(NULL) { @@ -49,16 +50,23 @@ LLTexLayerParam::LLTexLayerParam(LLTexLayerInterface *layer) : } else { - llerrs << "LLTexLayerParam constructor passed with NULL reference for layer!" << llendl; + LL_ERRS() << "LLTexLayerParam constructor passed with NULL reference for layer!" << LL_ENDL; } } -LLTexLayerParam::LLTexLayerParam(LLAvatarAppearance *appearance) : +LLTexLayerParam::LLTexLayerParam(LLAvatarAppearance *appearance) + : LLViewerVisualParam(), mTexLayer(NULL), mAvatarAppearance(appearance) { } +LLTexLayerParam::LLTexLayerParam(const LLTexLayerParam& pOther) + : LLViewerVisualParam(pOther), + mTexLayer(pOther.mTexLayer), + mAvatarAppearance(pOther.mAvatarAppearance) +{ +} BOOL LLTexLayerParam::setInfo(LLViewerVisualParamInfo *info, BOOL add_to_appearance) { @@ -86,7 +94,7 @@ void LLTexLayerParamAlpha::dumpCacheByteCount() { S32 gl_bytes = 0; getCacheByteCount( &gl_bytes); - llinfos << "Processed Alpha Texture Cache GL:" << (gl_bytes/1024) << "KB" << llendl; + LL_INFOS() << "Processed Alpha Texture Cache GL:" << (gl_bytes/1024) << "KB" << LL_ENDL; } // static @@ -95,7 +103,7 @@ void LLTexLayerParamAlpha::getCacheByteCount(S32* gl_bytes) *gl_bytes = 0; for (param_alpha_ptr_list_t::iterator iter = sInstances.begin(); - iter != sInstances.end(); iter++) + iter != sInstances.end(); ++iter) { LLTexLayerParamAlpha* instance = *iter; LLGLTexture* tex = instance->mCachedProcessedTexture; @@ -111,9 +119,11 @@ void LLTexLayerParamAlpha::getCacheByteCount(S32* gl_bytes) } } -LLTexLayerParamAlpha::LLTexLayerParamAlpha(LLTexLayerInterface* layer) : - LLTexLayerParam(layer), +LLTexLayerParamAlpha::LLTexLayerParamAlpha(LLTexLayerInterface* layer) + : LLTexLayerParam(layer), mCachedProcessedTexture(NULL), + mStaticImageTGA(), + mStaticImageRaw(), mNeedsCreateTexture(FALSE), mStaticImageInvalid(FALSE), mAvgDistortionVec(1.f, 1.f, 1.f), @@ -122,9 +132,11 @@ LLTexLayerParamAlpha::LLTexLayerParamAlpha(LLTexLayerInterface* layer) : sInstances.push_front(this); } -LLTexLayerParamAlpha::LLTexLayerParamAlpha(LLAvatarAppearance* appearance) : - LLTexLayerParam(appearance), +LLTexLayerParamAlpha::LLTexLayerParamAlpha(LLAvatarAppearance* appearance) + : LLTexLayerParam(appearance), mCachedProcessedTexture(NULL), + mStaticImageTGA(), + mStaticImageRaw(), mNeedsCreateTexture(FALSE), mStaticImageInvalid(FALSE), mAvgDistortionVec(1.f, 1.f, 1.f), @@ -133,6 +145,18 @@ LLTexLayerParamAlpha::LLTexLayerParamAlpha(LLAvatarAppearance* appearance) : sInstances.push_front(this); } +LLTexLayerParamAlpha::LLTexLayerParamAlpha(const LLTexLayerParamAlpha& pOther) + : LLTexLayerParam(pOther), + mCachedProcessedTexture(pOther.mCachedProcessedTexture), + mStaticImageTGA(pOther.mStaticImageTGA), + mStaticImageRaw(pOther.mStaticImageRaw), + mNeedsCreateTexture(pOther.mNeedsCreateTexture), + mStaticImageInvalid(pOther.mStaticImageInvalid), + mAvgDistortionVec(pOther.mAvgDistortionVec), + mCachedEffectiveWeight(pOther.mCachedEffectiveWeight) +{ + sInstances.push_front(this); +} LLTexLayerParamAlpha::~LLTexLayerParamAlpha() { @@ -142,9 +166,7 @@ LLTexLayerParamAlpha::~LLTexLayerParamAlpha() /*virtual*/ LLViewerVisualParam* LLTexLayerParamAlpha::cloneParam(LLWearable* wearable) const { - LLTexLayerParamAlpha *new_param = new LLTexLayerParamAlpha(mTexLayer); - *new_param = *this; - return new_param; + return new LLTexLayerParamAlpha(*this); } void LLTexLayerParamAlpha::deleteCaches() @@ -160,7 +182,7 @@ BOOL LLTexLayerParamAlpha::getMultiplyBlend() const return ((LLTexLayerParamAlphaInfo *)getInfo())->mMultiplyBlend; } -void LLTexLayerParamAlpha::setWeight(F32 weight, BOOL upload_bake) +void LLTexLayerParamAlpha::setWeight(F32 weight, bool upload_bake) { if (mIsAnimating || mTexLayer == NULL) { @@ -184,7 +206,7 @@ void LLTexLayerParamAlpha::setWeight(F32 weight, BOOL upload_bake) } } -void LLTexLayerParamAlpha::setAnimationTarget(F32 target_value, BOOL upload_bake) +void LLTexLayerParamAlpha::setAnimationTarget(F32 target_value, bool upload_bake) { // do not animate dummy parameters if (mIsDummy) @@ -202,7 +224,7 @@ void LLTexLayerParamAlpha::setAnimationTarget(F32 target_value, BOOL upload_bake } } -void LLTexLayerParamAlpha::animate(F32 delta, BOOL upload_bake) +void LLTexLayerParamAlpha::animate(F32 delta, bool upload_bake) { if (mNext) { @@ -238,10 +260,10 @@ BOOL LLTexLayerParamAlpha::getSkip() const } -static LLFastTimer::DeclareTimer FTM_TEX_LAYER_PARAM_ALPHA("alpha render"); +static LLTrace::BlockTimerStatHandle FTM_TEX_LAYER_PARAM_ALPHA("alpha render"); BOOL LLTexLayerParamAlpha::render(S32 x, S32 y, S32 width, S32 height) { - LLFastTimer t(FTM_TEX_LAYER_PARAM_ALPHA); + LL_RECORD_BLOCK_TIME(FTM_TEX_LAYER_PARAM_ALPHA); BOOL success = TRUE; if (!mTexLayer) @@ -278,7 +300,7 @@ BOOL LLTexLayerParamAlpha::render(S32 x, S32 y, S32 width, S32 height) if (mStaticImageTGA.isNull()) { - llwarns << "Unable to load static file: " << info->mStaticImageFileName << llendl; + LL_WARNS() << "Unable to load static file: " << info->mStaticImageFileName << LL_ENDL; mStaticImageInvalid = TRUE; // don't try again. return FALSE; } @@ -309,7 +331,7 @@ BOOL LLTexLayerParamAlpha::render(S32 x, S32 y, S32 width, S32 height) mStaticImageRaw = new LLImageRaw; mStaticImageTGA->decodeAndProcess(mStaticImageRaw, info->mDomain, effective_weight); mNeedsCreateTexture = TRUE; - lldebugs << "Built Cached Alpha: " << info->mStaticImageFileName << ": (" << mStaticImageRaw->getWidth() << ", " << mStaticImageRaw->getHeight() << ") " << "Domain: " << info->mDomain << " Weight: " << effective_weight << llendl; + LL_DEBUGS() << "Built Cached Alpha: " << info->mStaticImageFileName << ": (" << mStaticImageRaw->getWidth() << ", " << mStaticImageRaw->getHeight() << ") " << "Domain: " << info->mDomain << " Weight: " << effective_weight << LL_ENDL; } if (mCachedProcessedTexture) @@ -341,7 +363,7 @@ BOOL LLTexLayerParamAlpha::render(S32 x, S32 y, S32 width, S32 height) } else { - LLGLDisable no_alpha(GL_ALPHA_TEST); + LLGLDisable no_alpha; gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); gGL.color4f(0.f, 0.f, 0.f, effective_weight); gl_rect_2d_simple(width, height); @@ -380,7 +402,7 @@ BOOL LLTexLayerParamAlphaInfo::parseXml(LLXmlTreeNode* node) } // else // { -// llwarns << " element is missing tga_file attribute." << llendl; +// LL_WARNS() << " element is missing tga_file attribute." << LL_ENDL; // } static LLStdStringHandle multiply_blend_string = LLXmlTree::addAttributeString("multiply_blend"); @@ -398,27 +420,31 @@ BOOL LLTexLayerParamAlphaInfo::parseXml(LLXmlTreeNode* node) -LLTexLayerParamColor::LLTexLayerParamColor(LLTexLayerInterface* layer) : - LLTexLayerParam(layer), +LLTexLayerParamColor::LLTexLayerParamColor(LLTexLayerInterface* layer) + : LLTexLayerParam(layer), mAvgDistortionVec(1.f, 1.f, 1.f) { } -LLTexLayerParamColor::LLTexLayerParamColor(LLAvatarAppearance *appearance) : - LLTexLayerParam(appearance), +LLTexLayerParamColor::LLTexLayerParamColor(LLAvatarAppearance *appearance) + : LLTexLayerParam(appearance), mAvgDistortionVec(1.f, 1.f, 1.f) { } +LLTexLayerParamColor::LLTexLayerParamColor(const LLTexLayerParamColor& pOther) + : LLTexLayerParam(pOther), + mAvgDistortionVec(pOther.mAvgDistortionVec) +{ +} + LLTexLayerParamColor::~LLTexLayerParamColor() { } /*virtual*/ LLViewerVisualParam* LLTexLayerParamColor::cloneParam(LLWearable* wearable) const { - LLTexLayerParamColor *new_param = new LLTexLayerParamColor(mTexLayer); - *new_param = *this; - return new_param; + return new LLTexLayerParamColor(*this); } LLColor4 LLTexLayerParamColor::getNetColor() const @@ -449,14 +475,13 @@ LLColor4 LLTexLayerParamColor::getNetColor() const } } -void LLTexLayerParamColor::setWeight(F32 weight, BOOL upload_bake) +void LLTexLayerParamColor::setWeight(F32 weight, bool upload_bake) { if (mIsAnimating) { return; } - const LLTexLayerParamColorInfo *info = (LLTexLayerParamColorInfo *)getInfo(); F32 min_weight = getMinWeight(); F32 max_weight = getMaxWeight(); F32 new_weight = llclamp(weight, min_weight, max_weight); @@ -466,6 +491,8 @@ void LLTexLayerParamColor::setWeight(F32 weight, BOOL upload_bake) { mCurWeight = new_weight; + const LLTexLayerParamColorInfo *info = (LLTexLayerParamColorInfo *)getInfo(); + if (info->mNumColors <= 0) { // This will happen when we set the default weight the first time. @@ -481,11 +508,11 @@ void LLTexLayerParamColor::setWeight(F32 weight, BOOL upload_bake) } } -// llinfos << "param " << mName << " = " << new_weight << llendl; +// LL_INFOS() << "param " << mName << " = " << new_weight << LL_ENDL; } } -void LLTexLayerParamColor::setAnimationTarget(F32 target_value, BOOL upload_bake) +void LLTexLayerParamColor::setAnimationTarget(F32 target_value, bool upload_bake) { // set value first then set interpolating flag to ignore further updates mTargetWeight = target_value; @@ -497,7 +524,7 @@ void LLTexLayerParamColor::setAnimationTarget(F32 target_value, BOOL upload_bake } } -void LLTexLayerParamColor::animate(F32 delta, BOOL upload_bake) +void LLTexLayerParamColor::animate(F32 delta, bool upload_bake) { if (mNext) { @@ -556,13 +583,13 @@ BOOL LLTexLayerParamColorInfo::parseXml(LLXmlTreeNode *node) } if (!mNumColors) { - llwarns << " is missing sub-elements" << llendl; + LL_WARNS() << " is missing sub-elements" << LL_ENDL; return FALSE; } if ((mOperation == LLTexLayerParamColor::OP_BLEND) && (mNumColors != 1)) { - llwarns << " with operation\"blend\" must have exactly one " << llendl; + LL_WARNS() << " with operation\"blend\" must have exactly one " << LL_ENDL; return FALSE; } diff --git a/indra/llappearance/lltexlayerparams.h b/indra/llappearance/lltexlayerparams.h index b38d28d3eb..cadfd660a7 100644 --- a/indra/llappearance/lltexlayerparams.h +++ b/indra/llappearance/lltexlayerparams.h @@ -52,6 +52,8 @@ class LLTexLayerParam : public LLViewerVisualParam /*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const = 0; protected: + LLTexLayerParam(const LLTexLayerParam& pOther); + LLTexLayerInterface* mTexLayer; LLAvatarAppearance* mAvatarAppearance; }; @@ -83,9 +85,10 @@ class LLTexLayerParamAlpha : public LLTexLayerParam // LLVisualParam Virtual functions ///*virtual*/ BOOL parseData(LLXmlTreeNode* node); /*virtual*/ void apply( ESex avatar_sex ) {} - /*virtual*/ void setWeight(F32 weight, BOOL upload_bake); - /*virtual*/ void setAnimationTarget(F32 target_value, BOOL upload_bake); - /*virtual*/ void animate(F32 delta, BOOL upload_bake); + /*virtual*/ void setWeight(F32 weight, bool upload_bake = false); + /*virtual*/ void setAnimationTarget(F32 target_value, bool upload_bake = false); + /*virtual*/ void animate(F32 delta, bool upload_bake = false); + /*virtual*/ char const* getTypeString(void) const { return "param_alpha"; } // LLViewerVisualParam Virtual functions /*virtual*/ F32 getTotalDistortion() { return 1.f; } @@ -102,6 +105,8 @@ class LLTexLayerParamAlpha : public LLTexLayerParam BOOL getMultiplyBlend() const; private: + LLTexLayerParamAlpha(const LLTexLayerParamAlpha& pOther); + LLPointer mCachedProcessedTexture; LLPointer mStaticImageTGA; LLPointer mStaticImageRaw; @@ -174,10 +179,10 @@ class LLTexLayerParamColor : public LLTexLayerParam // LLVisualParam Virtual functions ///*virtual*/ BOOL parseData(LLXmlTreeNode* node); /*virtual*/ void apply( ESex avatar_sex ) {} - /*virtual*/ void setWeight(F32 weight, BOOL upload_bake); - /*virtual*/ void setAnimationTarget(F32 target_value, BOOL upload_bake); - /*virtual*/ void animate(F32 delta, BOOL upload_bake); - + /*virtual*/ void setWeight(F32 weight, bool upload_bake = false); + /*virtual*/ void setAnimationTarget(F32 target_value, bool upload_bake = false); + /*virtual*/ void animate(F32 delta, bool upload_bake = false); + /*virtual*/ char const* getTypeString(void) const { return "param_color"; } // LLViewerVisualParam Virtual functions /*virtual*/ F32 getTotalDistortion() { return 1.f; } @@ -190,7 +195,9 @@ class LLTexLayerParamColor : public LLTexLayerParam // New functions LLColor4 getNetColor() const; protected: - virtual void onGlobalColorChanged(bool upload_bake) {} + LLTexLayerParamColor(const LLTexLayerParamColor& pOther); + + virtual void onGlobalColorChanged(bool upload_bake = false) {} private: LL_ALIGN_16(LLVector4a mAvgDistortionVec); } LL_ALIGN_POSTFIX(16); diff --git a/indra/llappearance/lltexturemanagerbridge.cpp b/indra/llappearance/lltexturemanagerbridge.cpp index 939f6d620e..33f2185e4f 100644 --- a/indra/llappearance/lltexturemanagerbridge.cpp +++ b/indra/llappearance/lltexturemanagerbridge.cpp @@ -24,7 +24,6 @@ * $/LicenseInfo$ */ -#include "linden_common.h" #include "lltexturemanagerbridge.h" // Define a null texture manager bridge. Applications must provide their own bridge implementaton. diff --git a/indra/llappearance/lltexturemanagerbridge.h b/indra/llappearance/lltexturemanagerbridge.h index 355bcf02b9..101704b162 100644 --- a/indra/llappearance/lltexturemanagerbridge.h +++ b/indra/llappearance/lltexturemanagerbridge.h @@ -35,7 +35,8 @@ class LLTextureManagerBridge { public: - virtual ~LLTextureManagerBridge(){}; + virtual ~LLTextureManagerBridge() {} + virtual LLPointer getLocalTexture(BOOL usemipmaps = TRUE, BOOL generate_gl_tex = TRUE) = 0; virtual LLPointer getLocalTexture(const U32 width, const U32 height, const U8 components, BOOL usemipmaps, BOOL generate_gl_tex = TRUE) = 0; virtual LLGLTexture* getFetchedTexture(const LLUUID &image_id) = 0; diff --git a/indra/llappearance/llviewervisualparam.cpp b/indra/llappearance/llviewervisualparam.cpp index dd53312071..61e81ff586 100644 --- a/indra/llappearance/llviewervisualparam.cpp +++ b/indra/llappearance/llviewervisualparam.cpp @@ -76,7 +76,7 @@ BOOL LLViewerVisualParamInfo::parseXml(LLXmlTreeNode *node) static LLStdStringHandle edit_group_string = LLXmlTree::addAttributeString("edit_group"); if (!node->getFastAttributeString( edit_group_string, mEditGroup)) { - mEditGroup = ""; + mEditGroup.clear(); } static LLStdStringHandle cross_wearable_string = LLXmlTree::addAttributeString("cross_wearable"); @@ -125,6 +125,22 @@ BOOL LLViewerVisualParamInfo::parseXml(LLXmlTreeNode *node) // LLViewerVisualParam() //----------------------------------------------------------------------------- LLViewerVisualParam::LLViewerVisualParam() + : LLVisualParam() +{ +} + +//----------------------------------------------------------------------------- +// LLViewerVisualParam() +//----------------------------------------------------------------------------- +LLViewerVisualParam::LLViewerVisualParam(const LLViewerVisualParam& pOther) + : LLVisualParam(pOther) +{ +} + +//----------------------------------------------------------------------------- +// ~LLViewerVisualParam() +//----------------------------------------------------------------------------- +LLViewerVisualParam::~LLViewerVisualParam() { } @@ -139,10 +155,16 @@ BOOL LLViewerVisualParam::setInfo(LLViewerVisualParamInfo *info) return FALSE; mInfo = info; mID = info->mID; - setWeight(getDefaultWeight(), FALSE ); + setWeight(getDefaultWeight()); return TRUE; } +//virtual +std::string LLViewerVisualParam::getDumpWearableTypeName(void) const +{ + return LLWearableType::getTypeName(LLWearableType::EType(getInfo()->mWearableType)); +} + /* //============================================================================= // These virtual functions should always be overridden, diff --git a/indra/llappearance/llviewervisualparam.h b/indra/llappearance/llviewervisualparam.h index 64364c881b..eacd09dc3a 100644 --- a/indra/llappearance/llviewervisualparam.h +++ b/indra/llappearance/llviewervisualparam.h @@ -71,7 +71,7 @@ class LLViewerVisualParam : public LLVisualParam { public: LLViewerVisualParam(); - /*virtual*/ ~LLViewerVisualParam(){}; + virtual ~LLViewerVisualParam(); // Special: These functions are overridden by child classes LLViewerVisualParamInfo *getInfo() const { return (LLViewerVisualParamInfo*)mInfo; }; @@ -82,6 +82,7 @@ class LLViewerVisualParam : public LLVisualParam // LLVisualParam Virtual functions ///*virtual*/ BOOL parseData(LLXmlTreeNode* node); + /*virtual*/ std::string getDumpWearableTypeName(void) const; // New Virtual functions virtual F32 getTotalDistortion() = 0; @@ -107,6 +108,8 @@ class LLViewerVisualParam : public LLVisualParam BOOL getCrossWearable() const { return getInfo()->mCrossWearable; } +protected: + LLViewerVisualParam(const LLViewerVisualParam& pOther); } LL_ALIGN_POSTFIX(16); #endif // LL_LLViewerVisualParam_H diff --git a/indra/llappearance/llwearable.cpp b/indra/llappearance/llwearable.cpp index 6f163dd16d..31edbc67dc 100644 --- a/indra/llappearance/llwearable.cpp +++ b/indra/llappearance/llwearable.cpp @@ -43,15 +43,32 @@ S32 LLWearable::sCurrentDefinitionVersion = 1; // Private local functions static std::string terse_F32_to_string(F32 f); -LLWearable::LLWearable() : - mDefinitionVersion(0), - mType(LLWearableType::WT_INVALID) +LLWearable::LLWearable() + : mDefinitionVersion(-1), + mName(), + mDescription(), + mPermissions(), + mSaleInfo(), + mType(LLWearableType::WT_NONE), + mSavedVisualParamMap(), + mVisualParamIndexMap(), + mTEMap(), + mSavedTEMap() { } // virtual LLWearable::~LLWearable() { + for (visual_param_index_map_t::iterator vpIter = mVisualParamIndexMap.begin(); vpIter != mVisualParamIndexMap.end(); ++vpIter) + { + LLVisualParam* vp = vpIter->second; + vp->clearNextParam(); + delete vp; + vpIter->second = NULL; + } + + destroyTextures(); } const std::string& LLWearable::getTypeLabel() const @@ -69,10 +86,10 @@ LLAssetType::EType LLWearable::getAssetType() const return LLWearableType::getAssetType(mType); } -BOOL LLWearable::exportFile(LLFILE* fp) const +BOOL LLWearable::exportFile(const std::string& filename) const { - llofstream ofs(fp); - return exportStream(ofs); + llofstream ofs(filename.c_str(), std::ios_base::out | std::ios_base::trunc | std::ios_base::binary); + return ofs.is_open() && exportStream(ofs); } // virtual @@ -88,13 +105,13 @@ BOOL LLWearable::exportStream( std::ostream& output_stream ) const output_stream << mDescription << "\n"; // permissions - if( !mPermissions.exportStream( output_stream ) ) + if( !mPermissions.exportLegacyStream( output_stream ) ) { return FALSE; } // sale info - if( !mSaleInfo.exportStream( output_stream ) ) + if( !mSaleInfo.exportLegacyStream( output_stream ) ) { return FALSE; } @@ -152,11 +169,11 @@ void LLWearable::createVisualParams(LLAvatarAppearance *avatarp) // need this line to disambiguate between versions of LLCharacter::getVisualParam() LLVisualParam*(LLAvatarAppearance::*param_function)(S32)const = &LLAvatarAppearance::getVisualParam; param->resetDrivenParams(); - if(!param->linkDrivenParams(boost::bind(wearable_function,(LLWearable*)this, _1), false)) + if (!param->linkDrivenParams(std::bind(wearable_function,(LLWearable*)this, std::placeholders::_1), false)) { - if( !param->linkDrivenParams(boost::bind(param_function,avatarp,_1 ), true)) + if (!param->linkDrivenParams(std::bind(param_function,avatarp, std::placeholders::_1 ), true)) { - llwarns << "could not link driven params for wearable " << getName() << " id: " << param->getID() << llendl; + LL_WARNS() << "could not link driven params for wearable " << getName() << " id: " << param->getID() << LL_ENDL; continue; } } @@ -167,7 +184,7 @@ void LLWearable::createLayers(S32 te, LLAvatarAppearance *avatarp) { LLTexLayerSet *layer_set = NULL; const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = LLAvatarAppearanceDictionary::getInstance()->getTexture((ETextureIndex)te); - if (texture_dict->mIsUsedByBakedTexture) + if (texture_dict && texture_dict->mIsUsedByBakedTexture) { const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex; @@ -176,18 +193,19 @@ void LLWearable::createLayers(S32 te, LLAvatarAppearance *avatarp) if (layer_set) { - layer_set->cloneTemplates(mTEMap[te], (ETextureIndex)te, this); + layer_set->cloneTemplates(mTEMap[te], (ETextureIndex)te, this); } else { - llerrs << "could not find layerset for LTO in wearable!" << llendl; + LL_WARNS() << "could not find layerset for LTO in wearable!" << LL_ENDL; } } -LLWearable::EImportResult LLWearable::importFile(LLFILE* fp, LLAvatarAppearance* avatarp ) +LLWearable::EImportResult LLWearable::importFile(const std::string& filename, + LLAvatarAppearance* avatarp ) { - llifstream ifs(fp); - return importStream(ifs, avatarp); + llifstream ifs(filename.c_str(), std::ios_base::in | std::ios_base::binary); + return (! ifs.is_open())? FAILURE : importStream(ifs, avatarp); } // virtual @@ -214,7 +232,7 @@ LLWearable::EImportResult LLWearable::importStream( std::istream& input_stream, // read header and version if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE)) { - llwarns << "Failed to read wearable asset input stream." << llendl; + LL_WARNS() << "Failed to read wearable asset input stream." << LL_ENDL; return LLWearable::FAILURE; } if ( 1 != sscanf( /* Flawfinder: ignore */ @@ -232,25 +250,25 @@ LLWearable::EImportResult LLWearable::importStream( std::istream& input_stream, // these wearables get re-saved with version definition 22. if( mDefinitionVersion > LLWearable::sCurrentDefinitionVersion && mDefinitionVersion != 24 ) { - llwarns << "Wearable asset has newer version (" << mDefinitionVersion << ") than XML (" << LLWearable::sCurrentDefinitionVersion << ")" << llendl; + LL_WARNS() << "Wearable asset has newer version (" << mDefinitionVersion << ") than XML (" << LLWearable::sCurrentDefinitionVersion << ")" << LL_ENDL; return LLWearable::FAILURE; } - // name - if (!input_stream.good()) + // name may be empty + if (!input_stream.good()) { - llwarns << "Bad Wearable asset: early end of input stream " - << "while reading name" << llendl; + LL_WARNS() << "Bad Wearable asset: early end of input stream " + << "while reading name" << LL_ENDL; return LLWearable::FAILURE; } input_stream.getline(buffer, PARSE_BUFFER_SIZE); mName = buffer; - // description + // description may be empty if (!input_stream.good()) { - llwarns << "Bad Wearable asset: early end of input stream " - << "while reading description" << llendl; + LL_WARNS() << "Bad Wearable asset: early end of input stream " + << "while reading description" << LL_ENDL; return LLWearable::FAILURE; } input_stream.getline(buffer, PARSE_BUFFER_SIZE); @@ -259,18 +277,18 @@ LLWearable::EImportResult LLWearable::importStream( std::istream& input_stream, // permissions may have extra empty lines before the correct line if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE)) { - llwarns << "Bad Wearable asset: early end of input stream " - << "while reading permissions" << llendl; + LL_WARNS() << "Bad Wearable asset: early end of input stream " + << "while reading permissions" << LL_ENDL; return LLWearable::FAILURE; } S32 perm_version = -1; if ( 1 != sscanf( buffer, " permissions %d\n", &perm_version ) || perm_version != 0 ) { - llwarns << "Bad Wearable asset: missing valid permissions" << llendl; + LL_WARNS() << "Bad Wearable asset: missing valid permissions" << LL_ENDL; return LLWearable::FAILURE; } - if( !mPermissions.importStream( input_stream ) ) + if( !mPermissions.importLegacyStream( input_stream ) ) { return LLWearable::FAILURE; } @@ -278,15 +296,15 @@ LLWearable::EImportResult LLWearable::importStream( std::istream& input_stream, // sale info if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE)) { - llwarns << "Bad Wearable asset: early end of input stream " - << "while reading sale info" << llendl; + LL_WARNS() << "Bad Wearable asset: early end of input stream " + << "while reading sale info" << LL_ENDL; return LLWearable::FAILURE; } S32 sale_info_version = -1; if ( 1 != sscanf( buffer, " sale_info %d\n", &sale_info_version ) || sale_info_version != 0 ) { - llwarns << "Bad Wearable asset: missing valid sale_info" << llendl; + LL_WARNS() << "Bad Wearable asset: missing valid sale_info" << LL_ENDL; return LLWearable::FAILURE; } // Sale info used to contain next owner perm. It is now in the @@ -295,7 +313,7 @@ LLWearable::EImportResult LLWearable::importStream( std::istream& input_stream, // up the vast majority of the tasks. BOOL has_perm_mask = FALSE; U32 perm_mask = 0; - if( !mSaleInfo.importStream(input_stream, has_perm_mask, perm_mask) ) + if( !mSaleInfo.importLegacyStream(input_stream, has_perm_mask, perm_mask) ) { return LLWearable::FAILURE; } @@ -312,14 +330,14 @@ LLWearable::EImportResult LLWearable::importStream( std::istream& input_stream, // wearable type if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE)) { - llwarns << "Bad Wearable asset: early end of input stream " - << "while reading type" << llendl; + LL_WARNS() << "Bad Wearable asset: early end of input stream " + << "while reading type" << LL_ENDL; return LLWearable::FAILURE; } S32 type = -1; if ( 1 != sscanf( buffer, "type %d\n", &type ) ) { - llwarns << "Bad Wearable asset: bad type" << llendl; + LL_WARNS() << "Bad Wearable asset: bad type" << LL_ENDL; return LLWearable::FAILURE; } if( 0 <= type && type < LLWearableType::WT_COUNT ) @@ -329,36 +347,36 @@ LLWearable::EImportResult LLWearable::importStream( std::istream& input_stream, else { mType = LLWearableType::WT_COUNT; - llwarns << "Bad Wearable asset: bad type #" << type << llendl; + LL_WARNS() << "Bad Wearable asset: bad type #" << type << LL_ENDL; return LLWearable::FAILURE; } // parameters header if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE)) { - llwarns << "Bad Wearable asset: early end of input stream " - << "while reading parameters header" << llendl; + LL_WARNS() << "Bad Wearable asset: early end of input stream " + << "while reading parameters header" << LL_ENDL; return LLWearable::FAILURE; } S32 num_parameters = -1; if ( 1 != sscanf( buffer, "parameters %d\n", &num_parameters ) ) { - llwarns << "Bad Wearable asset: missing parameters block" << llendl; + LL_WARNS() << "Bad Wearable asset: missing parameters block" << LL_ENDL; return LLWearable::FAILURE; } if ( num_parameters > MAX_WEARABLE_ASSET_PARAMETERS ) { - llwarns << "Bad Wearable asset: too many parameters, " - << num_parameters << llendl; + LL_WARNS() << "Bad Wearable asset: too many parameters, " + << num_parameters << LL_ENDL; return LLWearable::FAILURE; } if( num_parameters != mVisualParamIndexMap.size() ) { - llwarns << "Wearable parameter mismatch. Reading in " + LL_WARNS() << "Wearable parameter mismatch. Reading in " << num_parameters << " from file, but created " << mVisualParamIndexMap.size() << " from avatar parameters. type: " - << getType() << llendl; + << getType() << LL_ENDL; } // parameters @@ -367,15 +385,15 @@ LLWearable::EImportResult LLWearable::importStream( std::istream& input_stream, { if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE)) { - llwarns << "Bad Wearable asset: early end of input stream " - << "while reading parameter #" << i << llendl; + LL_WARNS() << "Bad Wearable asset: early end of input stream " + << "while reading parameter #" << i << LL_ENDL; return LLWearable::FAILURE; } S32 param_id = 0; F32 param_weight = 0.f; if ( 2 != sscanf( buffer, "%d %f\n", ¶m_id, ¶m_weight ) ) { - llwarns << "Bad Wearable asset: bad parameter, #" << i << llendl; + LL_WARNS() << "Bad Wearable asset: bad parameter, #" << i << LL_ENDL; return LLWearable::FAILURE; } mSavedVisualParamMap[param_id] = param_weight; @@ -384,20 +402,20 @@ LLWearable::EImportResult LLWearable::importStream( std::istream& input_stream, // textures header if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE)) { - llwarns << "Bad Wearable asset: early end of input stream " - << "while reading textures header" << i << llendl; + LL_WARNS() << "Bad Wearable asset: early end of input stream " + << "while reading textures header" << i << LL_ENDL; return LLWearable::FAILURE; } S32 num_textures = -1; if ( 1 != sscanf( buffer, "textures %d\n", &num_textures) ) { - llwarns << "Bad Wearable asset: missing textures block" << llendl; + LL_WARNS() << "Bad Wearable asset: missing textures block" << LL_ENDL; return LLWearable::FAILURE; } if ( num_textures > MAX_WEARABLE_ASSET_TEXTURES ) { - llwarns << "Bad Wearable asset: too many textures, " - << num_textures << llendl; + LL_WARNS() << "Bad Wearable asset: too many textures, " + << num_textures << LL_ENDL; return LLWearable::FAILURE; } @@ -406,8 +424,8 @@ LLWearable::EImportResult LLWearable::importStream( std::istream& input_stream, { if (!getNextPopulatedLine(input_stream, buffer, PARSE_BUFFER_SIZE)) { - llwarns << "Bad Wearable asset: early end of input stream " - << "while reading textures #" << i << llendl; + LL_WARNS() << "Bad Wearable asset: early end of input stream " + << "while reading textures #" << i << LL_ENDL; return LLWearable::FAILURE; } S32 te = 0; @@ -416,14 +434,20 @@ LLWearable::EImportResult LLWearable::importStream( std::istream& input_stream, "%d %36s\n", &te, uuid_buffer) ) { - llwarns << "Bad Wearable asset: bad texture, #" << i << llendl; + LL_WARNS() << "Bad Wearable asset: bad texture, #" << i << LL_ENDL; return LLWearable::FAILURE; } + if (te >= ETextureIndex::TEX_NUM_INDICES) //createLayers() converts to ETextureIndex + { + LL_WARNS() << "Bad Wearable asset: bad texture index: " << te << LL_ENDL; + return LLWearable::FAILURE; + } + if( !LLUUID::validate( uuid_buffer ) ) { - llwarns << "Bad Wearable asset: bad texture uuid: " - << uuid_buffer << llendl; + LL_WARNS() << "Bad Wearable asset: bad texture uuid: " + << uuid_buffer << LL_ENDL; return LLWearable::FAILURE; } LLUUID id = LLUUID(uuid_buffer); @@ -626,17 +650,10 @@ void LLWearable::syncImages(te_map_t &src, te_map_t &dst) void LLWearable::destroyTextures() { - for( te_map_t::iterator iter = mTEMap.begin(); iter != mTEMap.end(); ++iter ) - { - LLLocalTextureObject *lto = iter->second; - delete lto; - } + std::for_each(mTEMap.begin(), mTEMap.end(), DeletePairedPointer()); mTEMap.clear(); - for( te_map_t::iterator iter = mSavedTEMap.begin(); iter != mSavedTEMap.end(); ++iter ) - { - LLLocalTextureObject *lto = iter->second; - delete lto; - } + + std::for_each(mSavedTEMap.begin(), mSavedTEMap.end(), DeletePairedPointer()); mSavedTEMap.clear(); } @@ -653,7 +670,7 @@ void LLWearable::addVisualParam(LLVisualParam *param) } -void LLWearable::setVisualParamWeight(S32 param_index, F32 value, BOOL upload_bake) +void LLWearable::setVisualParamWeight(S32 param_index, F32 value, bool upload_bake) { if( is_in_map(mVisualParamIndexMap, param_index ) ) { @@ -662,7 +679,7 @@ void LLWearable::setVisualParamWeight(S32 param_index, F32 value, BOOL upload_ba } else { - llerrs << "LLWearable::setVisualParam passed invalid parameter index: " << param_index << " for wearable type: " << this->getName() << llendl; + LL_ERRS() << "LLWearable::setVisualParam passed invalid parameter index: " << param_index << " for wearable type: " << this->getName() << LL_ENDL; } } @@ -675,7 +692,7 @@ F32 LLWearable::getVisualParamWeight(S32 param_index) const } else { - llwarns << "LLWerable::getVisualParam passed invalid parameter index: " << param_index << " for wearable type: " << this->getName() << llendl; + LL_WARNS() << "LLWerable::getVisualParam passed invalid parameter index: " << param_index << " for wearable type: " << this->getName() << LL_ENDL; } return (F32)-1.0; } @@ -700,7 +717,7 @@ void LLWearable::getVisualParams(visual_param_vec_t &list) } } -void LLWearable::animateParams(F32 delta, BOOL upload_bake) +void LLWearable::animateParams(F32 delta, bool upload_bake) { for(visual_param_index_map_t::iterator iter = mVisualParamIndexMap.begin(); iter != mVisualParamIndexMap.end(); @@ -725,7 +742,7 @@ LLColor4 LLWearable::getClothesColor(S32 te) const return color; } -void LLWearable::setClothesColor( S32 te, const LLColor4& new_color, BOOL upload_bake ) +void LLWearable::setClothesColor( S32 te, const LLColor4& new_color, bool upload_bake ) { U32 param_name[3]; if( LLAvatarAppearance::teToColorParams( (LLAvatarAppearanceDefines::ETextureIndex)te, param_name ) ) diff --git a/indra/llappearance/llwearable.h b/indra/llappearance/llwearable.h index b6049eb217..d9527b9e9c 100644 --- a/indra/llappearance/llwearable.h +++ b/indra/llappearance/llwearable.h @@ -28,18 +28,16 @@ #define LL_LLWEARABLE_H #include "llavatarappearancedefines.h" -#include "llextendedstatus.h" #include "llpermissions.h" #include "llsaleinfo.h" #include "llsortedvector.h" #include "llwearabletype.h" -#include "lllocaltextureobject.h" -class LLAPRFile; class LLMD5; class LLVisualParam; class LLTexGlobalColorInfo; class LLTexGlobalColor; +class LLLocalTextureObject; class LLAvatarAppearance; // Abstract class. @@ -84,8 +82,8 @@ class LLWearable SUCCESS, BAD_HEADER }; - BOOL exportFile(LLFILE* file) const; - EImportResult importFile(LLFILE* file, LLAvatarAppearance* avatarp ); + BOOL exportFile(const std::string& filename) const; + EImportResult importFile(const std::string& filename, LLAvatarAppearance* avatarp ); virtual BOOL exportStream( std::ostream& output_stream ) const; virtual EImportResult importStream( std::istream& input_stream, LLAvatarAppearance* avatarp ); @@ -98,14 +96,14 @@ class LLWearable void setLocalTextureObject(S32 index, LLLocalTextureObject <o); void addVisualParam(LLVisualParam *param); - void setVisualParamWeight(S32 index, F32 value, BOOL upload_bake); + void setVisualParamWeight(S32 index, F32 value, bool upload_bake = false); F32 getVisualParamWeight(S32 index) const; LLVisualParam* getVisualParam(S32 index) const; void getVisualParams(visual_param_vec_t &list); - void animateParams(F32 delta, BOOL upload_bake); + void animateParams(F32 delta, bool upload_bake = false); LLColor4 getClothesColor(S32 te) const; - void setClothesColor( S32 te, const LLColor4& new_color, BOOL upload_bake ); + void setClothesColor( S32 te, const LLColor4& new_color, bool upload_bake = false); virtual void revertValues(); virtual void saveValues(); @@ -116,6 +114,9 @@ class LLWearable // Update the baked texture hash. virtual void addToBakedTextureHash(LLMD5& hash) const = 0; + typedef LLSortedVector visual_param_index_map_t; + visual_param_index_map_t mVisualParamIndexMap; + protected: typedef std::map te_map_t; void syncImages(te_map_t &src, te_map_t &dst); @@ -135,9 +136,6 @@ class LLWearable typedef std::map param_map_t; param_map_t mSavedVisualParamMap; // last saved version of visual params - typedef LLSortedVector visual_param_index_map_t; - visual_param_index_map_t mVisualParamIndexMap; - te_map_t mTEMap; // maps TE to LocalTextureObject te_map_t mSavedTEMap; // last saved version of TEMap }; diff --git a/indra/llappearance/llwearabledata.cpp b/indra/llappearance/llwearabledata.cpp index 61b45a94dc..0e18ec1868 100644 --- a/indra/llappearance/llwearabledata.cpp +++ b/indra/llappearance/llwearabledata.cpp @@ -47,7 +47,6 @@ using namespace LLAvatarAppearanceDefines; LLWearable* LLWearableData::getWearable(const LLWearableType::EType type, U32 index) { - //llassert_always(index == 0); wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(type); if (wearable_iter == mWearableDatas.end()) { @@ -66,94 +65,70 @@ LLWearable* LLWearableData::getWearable(const LLWearableType::EType type, U32 in void LLWearableData::setWearable(const LLWearableType::EType type, U32 index, LLWearable *wearable) { - //llassert_always(index == 0); LLWearable *old_wearable = getWearable(type,index); if (!old_wearable) { pushWearable(type,wearable); return; } - + wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(type); if (wearable_iter == mWearableDatas.end()) { - llwarns << "invalid type, type " << type << " index " << index << llendl; + LL_WARNS() << "invalid type, type " << type << " index " << index << LL_ENDL; return; } wearableentry_vec_t& wearable_vec = wearable_iter->second; if (index>=wearable_vec.size()) { - llwarns << "invalid index, type " << type << " index " << index << llendl; + LL_WARNS() << "invalid index, type " << type << " index " << index << LL_ENDL; } else { wearable_vec[index] = wearable; - old_wearable->setUpdated(); + if (old_wearable != wearable) //Avoid redundant update + { + old_wearable->setUpdated(); + } const BOOL removed = FALSE; wearableUpdated(wearable, removed); } } -U32 LLWearableData::pushWearable(const LLWearableType::EType type, +void LLWearableData::pushWearable(const LLWearableType::EType type, LLWearable *wearable, bool trigger_updated /* = true */) { if (wearable == NULL) { // no null wearables please! - llwarns << "Null wearable sent for type " << type << llendl; - return MAX_CLOTHING_PER_TYPE; + LL_WARNS() << "Null wearable sent for type " << type << LL_ENDL; } -// [RLVa:KB] - Checked: 2010-06-08 (RLVa-1.2.0g) | Added: RLVa-1.2.0g - if ( (type < LLWearableType::WT_COUNT) && (mWearableDatas[type].size() < MAX_CLOTHING_PER_TYPE) ) + if (canAddWearable(type)) { - // Don't add the same wearable twice - U32 idxWearable = getWearableIndex(wearable); - llassert(MAX_CLOTHING_PER_TYPE == idxWearable); // pushWearable() on an already added wearable is a bug *somewhere* - if (MAX_CLOTHING_PER_TYPE == idxWearable) - { - mWearableDatas[type].push_back(wearable); - idxWearable = mWearableDatas[type].size() - 1; - } + // [RLVa:KB] - Checked: 2010-06-08 (RLVa-1.2.0g) | Added: RLVa-1.2.0g + if (std::find(mWearableDatas[type].begin(), mWearableDatas[type].end(), wearable) == mWearableDatas[type].end()) + // [/RLVa:KB] + mWearableDatas[type].push_back(wearable); if (trigger_updated) { const BOOL removed = FALSE; wearableUpdated(wearable, removed); } - return idxWearable; - } -// [/RLVa:KB] -// if (type < LLWearableType::WT_COUNT || mWearableDatas[type].size() < MAX_CLOTHING_PER_TYPE) -// { -// mWearableDatas[type].push_back(wearable); -// if (trigger_updated) -// { -// const BOOL removed = FALSE; -// wearableUpdated(wearable, removed); -// } -// return mWearableDatas[type].size()-1; -// } - return MAX_CLOTHING_PER_TYPE; + } } // virtual void LLWearableData::wearableUpdated(LLWearable *wearable, BOOL removed) { wearable->setUpdated(); - // FIXME DRANO avoid updating params via wearables when rendering server-baked appearance. -#if 0 - if (mAvatarAppearance->isUsingServerBakes() && !mAvatarAppearance->isUsingLocalAppearance()) - { - return; - } -#endif if (!removed) { pullCrossWearableValues(wearable->getType()); } } -void LLWearableData::popWearable(LLWearable *wearable) +void LLWearableData::eraseWearable(LLWearable *wearable) { if (wearable == NULL) { @@ -161,18 +136,17 @@ void LLWearableData::popWearable(LLWearable *wearable) return; } - U32 index = getWearableIndex(wearable); const LLWearableType::EType type = wearable->getType(); - if (index < MAX_CLOTHING_PER_TYPE && index < getWearableCount(type)) + U32 index; + if (getWearableIndex(wearable,index)) { - popWearable(type, index); + eraseWearable(type, index); } } -void LLWearableData::popWearable(const LLWearableType::EType type, U32 index) +void LLWearableData::eraseWearable(const LLWearableType::EType type, U32 index) { - //llassert_always(index == 0); LLWearable *wearable = getWearable(type, index); if (wearable) { @@ -202,8 +176,9 @@ bool LLWearableData::swapWearables(const LLWearableType::EType type, U32 index_a } wearableentry_vec_t& wearable_vec = wearable_iter->second; - if (0 > index_a || index_a >= wearable_vec.size()) return false; - if (0 > index_b || index_b >= wearable_vec.size()) return false; + // removed 0 > index_a and index_b comparisions - can never be true + if (index_a >= wearable_vec.size()) return false; + if (index_b >= wearable_vec.size()) return false; LLWearable* wearable = wearable_vec[index_a]; wearable_vec[index_a] = wearable_vec[index_b]; @@ -232,30 +207,62 @@ void LLWearableData::pullCrossWearableValues(const LLWearableType::EType type) } -U32 LLWearableData::getWearableIndex(const LLWearable *wearable) const +BOOL LLWearableData::getWearableIndex(const LLWearable *wearable, U32& index_found) const { if (wearable == NULL) { - return MAX_CLOTHING_PER_TYPE; + return FALSE; } const LLWearableType::EType type = wearable->getType(); wearableentry_map_t::const_iterator wearable_iter = mWearableDatas.find(type); if (wearable_iter == mWearableDatas.end()) { - llwarns << "tried to get wearable index with an invalid type!" << llendl; - return MAX_CLOTHING_PER_TYPE; + LL_WARNS() << "tried to get wearable index with an invalid type!" << LL_ENDL; + return FALSE; } const wearableentry_vec_t& wearable_vec = wearable_iter->second; for(U32 index = 0; index < wearable_vec.size(); index++) { if (wearable_vec[index] == wearable) { - return index; + index_found = index; + return TRUE; + } + } + + return FALSE; +} + +U32 LLWearableData::getClothingLayerCount() const +{ + U32 count = 0; + for (S32 i = 0; i < LLWearableType::WT_COUNT; i++) + { + LLWearableType::EType type = (LLWearableType::EType)i; + if (LLWearableType::getAssetType(type)==LLAssetType::AT_CLOTHING) + { + count += getWearableCount(type); } } + return count; +} - return MAX_CLOTHING_PER_TYPE; +BOOL LLWearableData::canAddWearable(const LLWearableType::EType type) const +{ + LLAssetType::EType a_type = LLWearableType::getAssetType(type); + if (a_type==LLAssetType::AT_CLOTHING) + { + return (getClothingLayerCount() < MAX_CLOTHING_LAYERS); + } + else if (a_type==LLAssetType::AT_BODYPART) + { + return (getWearableCount(type) < 1); + } + else + { + return FALSE; + } } BOOL LLWearableData::isOnTop(LLWearable* wearable) const diff --git a/indra/llappearance/llwearabledata.h b/indra/llappearance/llwearabledata.h index aeb9c1b26d..b83ba9a565 100644 --- a/indra/llappearance/llwearabledata.h +++ b/indra/llappearance/llwearabledata.h @@ -61,11 +61,13 @@ class LLWearableData const LLWearable* getBottomWearable(const LLWearableType::EType type) const; U32 getWearableCount(const LLWearableType::EType type) const; U32 getWearableCount(const U32 tex_index) const; - U32 getWearableIndex(const LLWearable *wearable) const; + BOOL getWearableIndex(const LLWearable *wearable, U32& index) const; + U32 getClothingLayerCount() const; + BOOL canAddWearable(const LLWearableType::EType type) const; BOOL isOnTop(LLWearable* wearable) const; - - static const U32 MAX_CLOTHING_PER_TYPE = 5; + + static const U32 MAX_CLOTHING_LAYERS = 60; //-------------------------------------------------------------------- // Setters @@ -73,11 +75,11 @@ class LLWearableData protected: // Low-level data structure setter - public access is via setWearableItem, etc. void setWearable(const LLWearableType::EType type, U32 index, LLWearable *wearable); - U32 pushWearable(const LLWearableType::EType type, LLWearable *wearable, + void pushWearable(const LLWearableType::EType type, LLWearable *wearable, bool trigger_updated = true); virtual void wearableUpdated(LLWearable *wearable, BOOL removed); - void popWearable(LLWearable *wearable); - void popWearable(const LLWearableType::EType type, U32 index); + void eraseWearable(LLWearable *wearable); + void eraseWearable(const LLWearableType::EType type, U32 index); void clearWearableType(const LLWearableType::EType type); bool swapWearables(const LLWearableType::EType type, U32 index_a, U32 index_b); @@ -103,7 +105,7 @@ class LLWearableData //Why this weird structure? LLWearableType::WT_COUNT small and known, therefore it's more efficient to make an array of vectors, indexed //by wearable type. This allows O(1) lookups. This structure simply lets us plug in this optimization without touching any code elsewhere. - typedef boost::array,LLWearableType::WT_COUNT> wearable_array_t; + typedef std::array, LLWearableType::WT_COUNT> wearable_array_t; struct wearableentry_map_t : public wearable_array_t { wearableentry_map_t() diff --git a/indra/llappearance/llwearabletype.cpp b/indra/llappearance/llwearabletype.cpp index 596486123e..b14107f9ea 100644 --- a/indra/llappearance/llwearabletype.cpp +++ b/indra/llappearance/llwearabletype.cpp @@ -27,18 +27,19 @@ #include "linden_common.h" #include "llwearabletype.h" #include "llinventorytype.h" +#include "llinventorydefines.h" -static LLTranslationBridge* sTrans = NULL; +static LLTranslationBridge::ptr_t sTrans = NULL; // static -void LLWearableType::initClass(LLTranslationBridge* trans) +void LLWearableType::initClass(LLTranslationBridge::ptr_t &trans) { sTrans = trans; } void LLWearableType::cleanupClass() { - delete sTrans; + sTrans.reset(); } struct WearableEntry : public LLDictionaryEntry @@ -52,8 +53,7 @@ struct WearableEntry : public LLDictionaryEntry LLDictionaryEntry(name), mAssetType(assetType), mDefaultNewName(default_new_name), - //*TODO:Translate - mLabel(/*sTrans->getString*/(name)), + mLabel(sTrans->getString(name)), mIconName(iconName), mDisableCameraSwitch(disable_camera_switch), mAllowMultiwear(allow_multiwear) @@ -98,11 +98,12 @@ LLWearableDictionary::LLWearableDictionary() addEntry(LLWearableType::WT_SKIRT, new WearableEntry("skirt", "New Skirt", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_SKIRT, FALSE, TRUE)); addEntry(LLWearableType::WT_ALPHA, new WearableEntry("alpha", "New Alpha", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_ALPHA, FALSE, TRUE)); addEntry(LLWearableType::WT_TATTOO, new WearableEntry("tattoo", "New Tattoo", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_TATTOO, FALSE, TRUE)); + addEntry(LLWearableType::WT_UNIVERSAL, new WearableEntry("universal", "New Universal", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_UNIVERSAL, FALSE, TRUE)); -// addEntry(LLWearableType::WT_PHYSICS, new WearableEntry("physics", "New Physics", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_PHYSICS, TRUE, TRUE)); // [SL:KB] - Patch: Appearance-Misc | Checked: 2011-05-29 (Catznip-2.6) addEntry(LLWearableType::WT_PHYSICS, new WearableEntry("physics", "New Physics", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_PHYSICS, TRUE, FALSE)); // [/SL:KB] +// addEntry(LLWearableType::WT_PHYSICS, new WearableEntry("physics", "New Physics", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_PHYSICS, TRUE, TRUE)); addEntry(LLWearableType::WT_UNKNOWN, new WearableEntry("unknown", "Clothing", LLAssetType::AT_CLOTHING, LLInventoryType::ICONNAME_CLOTHING_UNKNOWN, FALSE, TRUE)); addEntry(LLWearableType::WT_INVALID, new WearableEntry("invalid", "Invalid Wearable", LLAssetType::AT_NONE, LLInventoryType::ICONNAME_NONE, FALSE, FALSE)); @@ -180,3 +181,9 @@ BOOL LLWearableType::getAllowMultiwear(LLWearableType::EType type) return entry->mAllowMultiwear; } +// static +LLWearableType::EType LLWearableType::inventoryFlagsToWearableType(U32 flags) +{ + return (LLWearableType::EType)(flags & LLInventoryItemFlags::II_FLAGS_SUBTYPE_MASK); +} + diff --git a/indra/llappearance/llwearabletype.h b/indra/llappearance/llwearabletype.h index 8434a4fd8d..ec946d5ad3 100644 --- a/indra/llappearance/llwearabletype.h +++ b/indra/llappearance/llwearabletype.h @@ -31,14 +31,7 @@ #include "lldictionary.h" #include "llinventorytype.h" #include "llsingleton.h" - -class LLTranslationBridge -{ -public: - virtual ~LLTranslationBridge(){}; - virtual std::string getString(const std::string &xml_desc) = 0; -}; - +#include "llinvtranslationbrdg.h" class LLWearableType { @@ -61,16 +54,18 @@ class LLWearableType WT_ALPHA = 13, WT_TATTOO = 14, WT_PHYSICS = 15, - WT_UNKNOWN = 16, // Singu note: used for corrupt wearables that do not have their type set in the inventory database. + WT_UNIVERSAL = 16, + WT_UNKNOWN = 17, // Singu note: used for corrupt wearables that do not have their type set in the inventory database. // While all the above values are serialized and stored in the database, this value is local only: - // When a new item with value 16 is added by upstream, just increase this value to 17 (and WT_COUNT to 18). - WT_COUNT = 17, + // When a new item with value 17 is added by upstream, just increase this value to 18 (and WT_COUNT to 19). + // Keep WT_UNKNOWN and WT_COUNT in sync with llinventory.cpp + WT_COUNT = 18, WT_INVALID = 255, WT_NONE = -1, }; - static void initClass(LLTranslationBridge* trans); // initializes static members + static void initClass(LLTranslationBridge::ptr_t &trans); // initializes static members static void cleanupClass(); // initializes static members static const std::string& getTypeName(EType type); @@ -81,6 +76,7 @@ class LLWearableType static LLInventoryType::EIconName getIconName(EType type); static BOOL getDisableCameraSwitch(EType type); static BOOL getAllowMultiwear(EType type); + static EType inventoryFlagsToWearableType(U32 flags); protected: LLWearableType() {} diff --git a/indra/llaudio/CMakeLists.txt b/indra/llaudio/CMakeLists.txt index 22d814e038..92aa14ddc7 100644 --- a/indra/llaudio/CMakeLists.txt +++ b/indra/llaudio/CMakeLists.txt @@ -3,28 +3,13 @@ project(llaudio) include(00-Common) -include(Audio) -include(LLAudio) -if (FMODEX) - include(FMODEX) - set(FMOD OFF) -endif (FMODEX) -if (NOT FMODEX) - include(FMOD) -endif (NOT FMODEX) +include(FMODSTUDIO) include(OPENAL) include(LLCommon) include(LLMath) include(LLMessage) include(LLVFS) -if (FMODEX) - include_directories(${FMODEX_INCLUDE_DIR}) -endif(FMODEX) -if(FMOD) - include_directories(${FMOD_INCLUDE_DIR}) -endif (FMOD) - include_directories( ${LLAUDIO_INCLUDE_DIRS} ${LLCOMMON_INCLUDE_DIRS} @@ -35,7 +20,7 @@ include_directories( ${VORBISENC_INCLUDE_DIRS} ${VORBISFILE_INCLUDE_DIRS} ${VORBIS_INCLUDE_DIRS} - ${OPENAL_INCLUDE_DIRS} + ${OPENAL_LIB_INCLUDE_DIRS} ${FREEAULT_LIB_INCLUDE_DIRS} ) @@ -58,39 +43,22 @@ set(llaudio_HEADER_FILES llwindgen.h ) -if (FMODEX) - list(APPEND llaudio_SOURCE_FILES - llaudioengine_fmodex.cpp - lllistener_fmodex.cpp - llstreamingaudio_fmodex.cpp - ) - - list(APPEND llaudio_HEADER_FILES - llaudioengine_fmodex.h - lllistener_fmodex.h - llstreamingaudio_fmodex.h - ) -endif (FMODEX) -if (FMOD) +if (USE_FMODSTUDIO) + include_directories( + ${FMODSTUDIO_INCLUDE_DIR} + ) list(APPEND llaudio_SOURCE_FILES - llaudioengine_fmod.cpp - lllistener_fmod.cpp - llstreamingaudio_fmod.cpp + llaudioengine_fmodstudio.cpp + lllistener_fmodstudio.cpp + llstreamingaudio_fmodstudio.cpp ) list(APPEND llaudio_HEADER_FILES - llaudioengine_fmod.h - lllistener_fmod.h - llstreamingaudio_fmod.h + llaudioengine_fmodstudio.h + lllistener_fmodstudio.h + llstreamingaudio_fmodstudio.h ) - - if (LINUX) - if (${CXX_VERSION} MATCHES "4.[23]") - set_source_files_properties(llaudioengine_fmod.cpp - COMPILE_FLAGS -Wno-error=write-strings) - endif (${CXX_VERSION} MATCHES "4.[23]") - endif (LINUX) -endif (FMOD) +endif (USE_FMODSTUDIO) if (OPENAL) list(APPEND llaudio_SOURCE_FILES @@ -110,5 +78,9 @@ set_source_files_properties(${llaudio_HEADER_FILES} list(APPEND llaudio_SOURCE_FILES ${llaudio_HEADER_FILES}) add_library (llaudio ${llaudio_SOURCE_FILES}) -add_dependencies(llaudio prepare) +target_link_libraries( + llaudio + PUBLIC + llcommon + ) diff --git a/indra/llaudio/llaudiodecodemgr.cpp b/indra/llaudio/llaudiodecodemgr.cpp index 596a6dcffc..5f5696e376 100644 --- a/indra/llaudio/llaudiodecodemgr.cpp +++ b/indra/llaudio/llaudiodecodemgr.cpp @@ -33,7 +33,6 @@ #include "llaudiodecodemgr.h" -#include "llvorbisdecode.h" #include "llaudioengine.h" #include "lllfsthread.h" #include "llvfile.h" @@ -43,10 +42,12 @@ #include "llassetstorage.h" #include "llrefcount.h" +#include "llvorbisencode.h" + #include "vorbis/codec.h" #include "vorbis/vorbisfile.h" -#include "llvorbisencode.h" -#include //VS2010 +#include +#include extern LLAudioEngine *gAudiop; @@ -120,7 +121,7 @@ size_t vfs_read(void *ptr, size_t size, size_t nmemb, void *datasource) } } -int vfs_seek(void *datasource, ogg_int64_t offset, int whence) +S32 vfs_seek(void *datasource, ogg_int64_t offset, S32 whence) { LLVFile *file = (LLVFile *)datasource; @@ -142,7 +143,7 @@ int vfs_seek(void *datasource, ogg_int64_t offset, int whence) origin = -1; break; default: - llerrs << "Invalid whence argument to vfs_seek" << llendl; + LL_ERRS("AudioEngine") << "Invalid whence argument to vfs_seek" << LL_ENDL; return -1; } @@ -156,7 +157,7 @@ int vfs_seek(void *datasource, ogg_int64_t offset, int whence) } } -int vfs_close (void *datasource) +S32 vfs_close (void *datasource) { LLVFile *file = (LLVFile *)datasource; delete file; @@ -196,25 +197,25 @@ BOOL LLVorbisDecodeState::initDecode() vfs_callbacks.close_func = vfs_close; vfs_callbacks.tell_func = vfs_tell; - //llinfos << "Initing decode from vfile: " << mUUID << llendl; + LL_DEBUGS("AudioEngine") << "Initing decode from vfile: " << mUUID << LL_ENDL; mInFilep = new LLVFile(gVFS, mUUID, LLAssetType::AT_SOUND); if (!mInFilep || !mInFilep->getSize()) { - llwarns << "unable to open vorbis source vfile for reading" << llendl; + LL_WARNS("AudioEngine") << "unable to open vorbis source vfile for reading" << LL_ENDL; delete mInFilep; mInFilep = NULL; return FALSE; } - int r = ov_open_callbacks(mInFilep, &mVF, NULL, 0, vfs_callbacks); + S32 r = ov_open_callbacks(mInFilep, &mVF, NULL, 0, vfs_callbacks); if(r < 0) { - llwarns << r << " Input to vorbis decode does not appear to be an Ogg bitstream: " << mUUID << llendl; + LL_WARNS("AudioEngine") << r << " Input to vorbis decode does not appear to be an Ogg bitstream: " << mUUID << LL_ENDL; return(FALSE); } - S32 sample_count = ov_pcm_total(&mVF, -1); + S32 sample_count = (S32)ov_pcm_total(&mVF, -1); size_t size_guess = (size_t)sample_count; vorbis_info* vi = ov_info(&mVF, -1); size_guess *= (vi? vi->channels : 1); @@ -228,20 +229,20 @@ BOOL LLVorbisDecodeState::initDecode() if( vi->channels < 1 || vi->channels > LLVORBIS_CLIP_MAX_CHANNELS ) { abort_decode = true; - llwarns << "Bad channel count: " << vi->channels << llendl; + LL_WARNS("AudioEngine") << "Bad channel count: " << vi->channels << LL_ENDL; } } else // !vi { abort_decode = true; - llwarns << "No default bitstream found" << llendl; + LL_WARNS("AudioEngine") << "No default bitstream found" << LL_ENDL; } // // This magic value is equivalent to 150MiB of data. // Prevents griefers from utilizing a huge xbox sound the size of god to instafry the viewer if(size_guess >= 157286400) { - llwarns << "Bad sound caught by zmagic" << llendl; + LL_WARNS() << "Bad sound caught by zmagic" << LL_ENDL; abort_decode = true; } else if(!gAudiop->getAllowLargeSounds()) @@ -252,25 +253,25 @@ BOOL LLVorbisDecodeState::initDecode() (size_t)sample_count <= 0) { abort_decode = true; - llwarns << "Illegal sample count: " << sample_count << llendl; + LL_WARNS("AudioEngine") << "Illegal sample count: " << sample_count << LL_ENDL; } if( size_guess > LLVORBIS_CLIP_REJECT_SIZE || size_guess < 0) { abort_decode = true; - llwarns << "Illegal sample size: " << size_guess << llendl; + LL_WARNS("AudioEngine") << "Illegal sample size: " << size_guess << LL_ENDL; } // } // if( abort_decode ) { - llwarns << "Canceling initDecode. Bad asset: " << mUUID << llendl; + LL_WARNS("AudioEngine") << "Canceling initDecode. Bad asset: " << mUUID << LL_ENDL; vorbis_comment* comment = ov_comment(&mVF,-1); if (comment && comment->vendor) { - llwarns << "Bad asset encoded by: " << comment->vendor << llendl; + LL_WARNS("AudioEngine") << "Bad asset encoded by: " << comment->vendor << LL_ENDL; } delete mInFilep; mInFilep = NULL; @@ -287,7 +288,7 @@ BOOL LLVorbisDecodeState::initDecode() } catch(std::bad_alloc) { - llwarns << "bad_alloc" << llendl; + LL_WARNS() << "bad_alloc" << LL_ENDL; if(mInFilep) { delete mInFilep; @@ -388,12 +389,12 @@ BOOL LLVorbisDecodeState::decodeSection() { if (!mInFilep) { - llwarns << "No VFS file to decode in vorbis!" << llendl; + LL_WARNS("AudioEngine") << "No VFS file to decode in vorbis!" << LL_ENDL; return TRUE; } if (mDone) { -// llwarns << "Already done with decode, aborting!" << llendl; +// LL_WARNS() << "Already done with decode, aborting!" << LL_ENDL; return TRUE; } char pcmout[4096]; /*Flawfinder: ignore*/ @@ -406,14 +407,14 @@ BOOL LLVorbisDecodeState::decodeSection() eof = TRUE; mDone = TRUE; mValid = TRUE; -// llinfos << "Vorbis EOF" << llendl; +// LL_INFOS() << "Vorbis EOF" << LL_ENDL; } else if (ret < 0) { /* error in the stream. Not a problem, just reporting it in case we (the app) cares. In this case, we don't. */ - llwarns << "BAD vorbis decode in decodeSection." << llendl; + LL_WARNS("AudioEngine") << "BAD vorbis decode in decodeSection." << LL_ENDL; mValid = FALSE; mDone = TRUE; @@ -422,7 +423,7 @@ BOOL LLVorbisDecodeState::decodeSection() } else { -// llinfos << "Vorbis read " << ret << "bytes" << llendl; +// LL_INFOS() << "Vorbis read " << ret << "bytes" << LL_ENDL; /* we don't bother dealing with sample rate changes, etc, but. you'll have to*/ std::copy(pcmout, pcmout+ret, std::back_inserter(mWAVBuffer)); @@ -434,7 +435,7 @@ BOOL LLVorbisDecodeState::finishDecode() { if (!isValid()) { - llwarns << "Bogus vorbis decode state for " << getUUID() << ", aborting!" << llendl; + LL_WARNS("AudioEngine") << "Bogus vorbis decode state for " << getUUID() << ", aborting!" << LL_ENDL; return TRUE; // We've finished } @@ -515,7 +516,7 @@ BOOL LLVorbisDecodeState::finishDecode() if (36 == data_length) { - llwarns << "BAD Vorbis decode in finishDecode!" << llendl; + LL_WARNS("AudioEngine") << "BAD Vorbis decode in finishDecode!" << LL_ENDL; mValid = FALSE; return TRUE; // we've finished } @@ -532,7 +533,7 @@ BOOL LLVorbisDecodeState::finishDecode() { if (mBytesRead == 0) { - llwarns << "Unable to write file in LLVorbisDecodeState::finishDecode" << llendl; + LL_WARNS("AudioEngine") << "Unable to write file in LLVorbisDecodeState::finishDecode" << LL_ENDL; mValid = FALSE; return TRUE; // we've finished } @@ -550,7 +551,7 @@ BOOL LLVorbisDecodeState::finishDecode() LLVFile output(gVFS, mUUID, LLAssetType::AT_SOUND_WAV); output.write(&mWAVBuffer[0], mWAVBuffer.size()); #endif - //llinfos << "Finished decode for " << getUUID() << llendl; + LL_DEBUGS("AudioEngine") << "Finished decode for " << getUUID() << LL_ENDL; return TRUE; } @@ -559,7 +560,7 @@ void LLVorbisDecodeState::flushBadFile() { if (mInFilep) { - llwarns << "Flushing bad vorbis file from VFS for " << mUUID << llendl; + LL_WARNS("AudioEngine") << "Flushing bad vorbis file from VFS for " << mUUID << LL_ENDL; mInFilep->remove(); } } @@ -576,7 +577,7 @@ class LLAudioDecodeMgr::Impl void processQueue(const F32 num_secs = 0.005); protected: - LLLinkedQueue mDecodeQueue; + std::deque mDecodeQueue; LLPointer mCurrentDecodep; }; @@ -603,16 +604,22 @@ void LLAudioDecodeMgr::Impl::processQueue(const F32 num_secs) { // decodeSection does all of the work above } - /* */ }catch(std::bad_alloc){llerrs<<"bad_alloc whilst decoding"< */ + /* */ }catch(std::bad_alloc){LL_ERRS() << "bad_alloc whilst decoding" << LL_ENDL;} /* */ if (mCurrentDecodep->isDone() && !mCurrentDecodep->isValid()) { // We had an error when decoding, abort. - llwarns << mCurrentDecodep->getUUID() << " has invalid vorbis data, aborting decode" << llendl; + LL_WARNS("AudioEngine") << mCurrentDecodep->getUUID() << " has invalid vorbis data, aborting decode" << LL_ENDL; mCurrentDecodep->flushBadFile(); - LLAudioData *adp = gAudiop->getAudioData(mCurrentDecodep->getUUID()); - adp->setHasValidData(false); - adp->setHasCompletedDecode(true); + + if (gAudiop) + { + LLAudioData *adp = gAudiop->getAudioData(mCurrentDecodep->getUUID()); + if(adp) + { + adp->setLoadState(LLAudioData::STATE_LOAD_ERROR); + } + } mCurrentDecodep = NULL; done = TRUE; } @@ -624,29 +631,26 @@ void LLAudioDecodeMgr::Impl::processQueue(const F32 num_secs) } else if (mCurrentDecodep) { - if (mCurrentDecodep->finishDecode()) + if (gAudiop && mCurrentDecodep->finishDecode()) { // We finished! LLAudioData *adp = gAudiop->getAudioData(mCurrentDecodep->getUUID()); if (!adp) { - llwarns << "Missing LLAudioData for decode of " << mCurrentDecodep->getUUID() << llendl; + LL_WARNS("AudioEngine") << "Missing LLAudioData for decode of " << mCurrentDecodep->getUUID() << LL_ENDL; } else if (mCurrentDecodep->isValid() && mCurrentDecodep->isDone()) { - adp->setHasCompletedDecode(true); - adp->setHasDecodedData(true); - adp->setHasValidData(true); - + adp->setLoadState(LLAudioData::STATE_LOAD_READY); // At this point, we could see if anyone needs this sound immediately, but // I'm not sure that there's a reason to - we need to poll all of the playing // sounds anyway. - //llinfos << "Finished the vorbis decode, now what?" << llendl; + //LL_INFOS() << "Finished the vorbis decode, now what?" << LL_ENDL; } else { - adp->setHasCompletedDecode(true); - llinfos << "Vorbis decode failed for " << mCurrentDecodep->getUUID() << llendl; + adp->setLoadState(LLAudioData::STATE_LOAD_ERROR); + LL_INFOS("AudioEngine") << "Vorbis decode failed for " << mCurrentDecodep->getUUID() << LL_ENDL; } mCurrentDecodep = NULL; } @@ -656,7 +660,7 @@ void LLAudioDecodeMgr::Impl::processQueue(const F32 num_secs) if (!done) { - if (!mDecodeQueue.getLength()) + if (mDecodeQueue.empty()) { // Nothing else on the queue. done = TRUE; @@ -664,14 +668,15 @@ void LLAudioDecodeMgr::Impl::processQueue(const F32 num_secs) else { LLUUID uuid; - mDecodeQueue.pop(uuid); - if (gAudiop->hasDecodedFile(uuid)) + uuid = mDecodeQueue.front(); + mDecodeQueue.pop_front(); + if (!gAudiop || gAudiop->hasDecodedFile(uuid)) { // This file has already been decoded, don't decode it again. continue; } - lldebugs << "Decoding " << uuid << " from audio queue!" << llendl; + LL_DEBUGS() << "Decoding " << uuid << " from audio queue!" << LL_ENDL; std::string uuid_str; std::string d_path; @@ -685,6 +690,11 @@ void LLAudioDecodeMgr::Impl::processQueue(const F32 num_secs) mCurrentDecodep = new LLVorbisDecodeState(uuid, d_path); if (!mCurrentDecodep->initDecode()) { + LLAudioData *adp = gAudiop->getAudioData(uuid); + if(adp) + { + adp->setLoadState(LLAudioData::STATE_LOAD_ERROR); + } mCurrentDecodep = NULL; } } @@ -709,23 +719,28 @@ void LLAudioDecodeMgr::processQueue(const F32 num_secs) mImpl->processQueue(num_secs); } -BOOL LLAudioDecodeMgr::addDecodeRequest(const LLUUID &uuid) +bool LLAudioDecodeMgr::addDecodeRequest(const LLUUID &uuid) { - if (gAudiop->hasDecodedFile(uuid)) + if(uuid.isNull()) + { + return true; + } + + if (gAudiop && gAudiop->hasDecodedFile(uuid)) { // Already have a decoded version, don't need to decode it. - //llinfos << "addDecodeRequest for " << uuid << " has decoded file already" << llendl; - return TRUE; + LL_DEBUGS("AudioEngine") << "addDecodeRequest for " << uuid << " has decoded file already" << LL_ENDL; + return true; } - if (gAssetStorage->hasLocalAsset(uuid, LLAssetType::AT_SOUND)) + if (gAssetStorage && gAssetStorage->hasLocalAsset(uuid, LLAssetType::AT_SOUND)) { // Just put it on the decode queue. - //llinfos << "addDecodeRequest for " << uuid << " has local asset file already" << llendl; - mImpl->mDecodeQueue.push(uuid); - return TRUE; + LL_DEBUGS("AudioEngine") << "addDecodeRequest for " << uuid << " has local asset file already" << LL_ENDL; + mImpl->mDecodeQueue.push_back(uuid); + return true; } - //llinfos << "addDecodeRequest for " << uuid << " no file available" << llendl; - return FALSE; + LL_DEBUGS("AudioEngine") << "addDecodeRequest for " << uuid << " no file available" << LL_ENDL; + return false; } diff --git a/indra/llaudio/llaudiodecodemgr.h b/indra/llaudio/llaudiodecodemgr.h index e42fe8a40d..e2319a32fa 100644 --- a/indra/llaudio/llaudiodecodemgr.h +++ b/indra/llaudio/llaudiodecodemgr.h @@ -24,11 +24,10 @@ */ #ifndef LL_LLAUDIODECODEMGR_H -#define LL_LLAUDIODECODEMG_H +#define LL_LLAUDIODECODEMGR_H #include "stdtypes.h" -#include "lllinkedqueue.h" #include "lluuid.h" #include "llassettype.h" @@ -44,7 +43,7 @@ class LLAudioDecodeMgr ~LLAudioDecodeMgr(); void processQueue(const F32 num_secs = 0.005); - BOOL addDecodeRequest(const LLUUID &uuid); + bool addDecodeRequest(const LLUUID &uuid); void addAudioRequest(const LLUUID &uuid); protected: diff --git a/indra/llaudio/llaudioengine.cpp b/indra/llaudio/llaudioengine.cpp index f079658776..61aa25be1e 100644 --- a/indra/llaudio/llaudioengine.cpp +++ b/indra/llaudio/llaudioengine.cpp @@ -40,6 +40,9 @@ #include "llaudiodecodemgr.h" #include "llassetstorage.h" +#include +#include + // necessary for grabbing sounds from sim (implemented in viewer) extern void request_sound(const LLUUID &sound_guid); @@ -110,6 +113,8 @@ void LLAudioEngine::setDefaults() for (U32 i = 0; i < LLAudioEngine::AUDIO_TYPE_COUNT; i++) mSecondaryGain[i] = 1.0f; + mCurrentTransfer = NULL; + mAllowLargeSounds = false; } @@ -120,13 +125,11 @@ bool LLAudioEngine::init(const S32 num_channels, void* userdata) mNumChannels = num_channels; mUserData = userdata; - - allocateListener(); // Initialize the decode manager gAudioDecodeMgrp = new LLAudioDecodeMgr; - LL_INFOS("AudioEngine") << "LLAudioEngine::init() AudioEngine successfully initialized" << llendl; + LL_INFOS("AudioEngine") << "LLAudioEngine::init() AudioEngine successfully initialized" << LL_ENDL; return true; } @@ -171,6 +174,9 @@ void LLAudioEngine::shutdown() delete mBuffers[i]; mBuffers[i] = NULL; } + + delete mStreamingAudioImpl; + mStreamingAudioImpl = NULL; } @@ -276,11 +282,6 @@ void LLAudioEngine::updateChannels() } } llassert(found_buffer); - if(!mChannels[i]->mCurrentBufferp->mInUse) - { - llassert(!mChannels[i]->isPlaying()); - llassert(!mChannels[i]->isWaiting()); - } } #endif //SHOW_ASSERT } @@ -288,6 +289,17 @@ void LLAudioEngine::updateChannels() checkStates(); } +struct SourcePriorityComparator +{ + bool operator() (const LLAudioSource* lhs, const LLAudioSource* rhs) const + { + if(rhs->getPriority() != lhs->getPriority()) + return rhs->getPriority() > lhs->getPriority(); + else + return ((rhs->isSyncMaster() && !lhs->isSyncMaster()) || (rhs->isSyncSlave() && (!lhs->isSyncMaster() && !lhs->isSyncSlave()))); + } +}; + static const F32 default_max_decode_time = .002f; // 2 ms void LLAudioEngine::idle(F32 max_decode_time) { @@ -309,18 +321,34 @@ void LLAudioEngine::idle(F32 max_decode_time) } } - F32 max_priority = -1.f; - LLAudioSource *max_sourcep = NULL; // Maximum priority source without a channel - source_map::iterator iter; - for (iter = mAllSources.begin(); iter != mAllSources.end();) + //Iterate down all queued sources. Remove finished ones, sort active ones by priority. Find highest priority 'master' source if present. + LLAudioSource *sync_masterp = NULL; //Highest priority syncmaster + LLAudioSource *sync_slavep = NULL; //Highest priority syncslave + + //Priority queue that will be filled with soundsources that have a high likeleyhood of being able to start [re]playing this idle tick. + //Sort order: Primary: priority. Secondary: syncmaster. Tertiary: syncslave + std::priority_queue >,SourcePriorityComparator> queue; + + //Have to put syncslaves into a temporary list until the syncmaster state is determined. + //If the syncmaster might be started, or just looped, insert all pending/looping syncslaves into the priority queue. + //If the there is no active syncmaster, then stop any currently looping syncslaves and add none to the priority queue. + //This is necessary as any looping soundsources to be stopped, MUST be stopped before iterating down the priority queue. + static std::vector slave_list; + slave_list.clear(); + + //Iterate over all sources. Update their decode or 'done' state, as well as their priorities. + //Also add sources that might be able to start playing to the priority queue. + //Only sources without channels should be added to priority queue. + //Syncslaves must put into the slave list instead of the priority queue. + for (source_map::iterator iter = mAllSources.begin(); iter != mAllSources.end();) { LLAudioSource *sourcep = iter->second; - // Update this source + //Load/decode/queue pop sourcep->update(); - sourcep->updatePriority(); - if (sourcep->isDone()) + //Done after update, as failure to load might mark source as corrupt, which causes isDone to return true. + if (sourcep->isDone()) { // The source is done playing, clean it up. delete sourcep; @@ -328,166 +356,136 @@ void LLAudioEngine::idle(F32 max_decode_time) continue; } - if (sourcep->isMuted()) + // Increment iter here (it is not used anymore), so we can use continue below to move on to the next source. + ++iter; + + if(!sourcep->isLoop() && sourcep->mPlayedOnce && (!sourcep->mChannelp || !sourcep->mChannelp->isPlaying())) { - ++iter; - continue; + continue; } - if (!sourcep->getChannel() && sourcep->getCurrentBuffer()) + LLAudioData *adp = sourcep->getCurrentData(); + //If there is no current data at all, or if it hasn't loaded, we must skip this source. + if (!adp || !adp->getBuffer()) { - // We could potentially play this sound if its priority is high enough. - if (sourcep->getPriority() > max_priority) - { - max_priority = sourcep->getPriority(); - max_sourcep = sourcep; - } + continue; } - // Move on to the next source - iter++; - } + sourcep->updatePriority(); //Calculates current priority. 1.f=ambient. 0.f=muted. Otherwise based off of distance. - // Now, do priority-based organization of audio sources. - // All channels used, check priorities. - // Find channel with lowest priority - if (max_sourcep) - { - LLAudioChannel *channelp = getFreeChannel(max_priority); - if (channelp) + if (sourcep->getPriority() < F_APPROXIMATELY_ZERO) { - LL_DEBUGS("AudioEngine") << "Replacing source in channel due to priority!" << llendl; - llassert(max_sourcep->getChannel() == NULL); - - llassert(channelp->mCurrentBufferp == NULL); - channelp->setSource(max_sourcep); - - llassert(max_sourcep == channelp->getSource()); - llassert(channelp->mCurrentBufferp == max_sourcep->getCurrentBuffer()); - - if (max_sourcep->isSyncSlave()) + // Muted, or nothing queued, or too far, so we don't care. + continue; + } + else if(sourcep->isSyncMaster()) + { + if(!sync_masterp || sourcep->getPriority() > sync_masterp->getPriority()) { - // A sync slave, it doesn't start playing until it's synced up with the master. - // Flag this channel as waiting for sync, and return true. - channelp->setWaiting(true); + if(sync_masterp && !sync_masterp->getChannel()) + queue.push(sync_masterp); //Add lower-priority soundmaster to the queue as a normal sound. + sync_masterp = sourcep; + //Don't add master to the queue yet. + //Add it after highest-priority sound slave is found so we can outrank its priority. + continue; } - else + //Else fall through like a normal sound. + } + else if(sourcep->isSyncSlave()) + { + if(!sync_slavep || sourcep->getPriority() > sync_slavep->getPriority()) { - channelp->setWaiting(false); - channelp->play(); + sync_slavep = sourcep; } + //Don't add to the priority queue quite yet. Best primary syncmaster candidate may not have been determined yet. + slave_list.push_back(sourcep); + continue; + } + if(sourcep->getChannel()) + { + //If this is just a regular sound and is currently playing then do nothing special. + continue; } + //Add to our queue. Highest priority will be at the front. + queue.push(sourcep); } - // Do this BEFORE we update the channels // Update the channels to sync up with any changes that the source made, // such as changing what sound was playing. updateChannels(); - // Update queued sounds (switch to next queued data if the current has finished playing) - for (iter = mAllSources.begin(); iter != mAllSources.end(); ++iter) + //Loop over all syncsaves. If no syncmaster, stop looping ones, else add ones that need [re]started to the priority queue. + //Normally there are zero to one syncslaves, so this loop isn't typically expensive. + for(std::vector::iterator iter=slave_list.begin();iter!=slave_list.end();++iter) { - // This is lame, instead of this I could actually iterate through all the sources - // attached to each channel, since only those with active channels - // can have anything interesting happen with their queue? (Maybe not true) - LLAudioSource *sourcep = iter->second; - if (!sourcep->mQueuedDatap || sourcep->isMuted()) - { - // Muted, or nothing queued, so we don't care. - continue; - } - - LLAudioChannel *channelp = sourcep->getChannel(); - bool is_stopped = channelp && channelp->isPlaying(); - if (is_stopped || (sourcep->isLoop() && channelp->mLoopedThisFrame)) + if(!sync_masterp) { - // This sound isn't playing, so we just process move the queue - sourcep->mCurrentDatap = sourcep->mQueuedDatap; - sourcep->mQueuedDatap = NULL; - - if(is_stopped) + //Stop any looping syncslaves. I'm not sure this behavior is correct, but letting looping syncslaves run + //off on their own seems wrong. The lsl documentation is unclear. + if((*iter)->getChannel() && (*iter)->isLoop()) { - // Reset the timer so the source doesn't die. - sourcep->mAgeTimer.reset(); - // Make sure we have the buffer set up if we just decoded the data - if (sourcep->mCurrentDatap) - { - updateBufferForData(sourcep->mCurrentDatap); - } + (*iter)->getChannel()->cleanup(); } - - // Actually play the associated data. - sourcep->setupChannel(); - channelp = sourcep->getChannel(); - if (channelp) - { - channelp->updateBuffer(); - channelp->play(); - } - continue; + } + //If the syncmaster already has a channel and hasn't looped, then we can skip syncslaves this idle tick (there's nothing to do). + else if((!sync_masterp->getChannel() || sync_masterp->getChannel()->mLoopedThisFrame)) + { + //Add syncslaves that we might want to [re]start. + if(!(*iter)->getChannel() || (*iter)->isLoop()) + queue.push((*iter)); } } - // Lame, update the channels AGAIN. - // Update the channels to sync up with any changes that the source made, - // such as changing what sound was playing. - updateChannels(); - - // Hack! For now, just use a global sync master; - LLAudioSource *sync_masterp = NULL; - LLAudioChannel *master_channelp = NULL; - F32 max_sm_priority = -1.f; - for (iter = mAllSources.begin(); iter != mAllSources.end(); ++iter) + if(sync_masterp) { - LLAudioSource *sourcep = iter->second; - if (sourcep->isMuted()) + //Syncmaster must have priority greater than or equal to priority of highest priority syncslave. + //The case of slave priority equaling master priority is handled in the comparator (SourcePriorityComparator). + if(sync_slavep) + sync_masterp->setPriority(sync_slavep->getPriority()); + if(!sync_masterp->getChannel()) { - continue; - } - if (sourcep->isSyncMaster()) - { - if (sourcep->getPriority() > max_sm_priority) - { - sync_masterp = sourcep; - master_channelp = sync_masterp->getChannel(); - max_sm_priority = sourcep->getPriority(); - } + queue.push(sync_masterp); } } - if (master_channelp && master_channelp->mLoopedThisFrame) + // Dispatch all soundsources. + bool syncmaster_started = sync_masterp && sync_masterp->getChannel() && sync_masterp->getChannel()->mLoopedThisFrame; + while(!queue.empty()) { - // Synchronize loop slaves with their masters - // Update queued sounds (switch to next queued data if the current has finished playing) - for (iter = mAllSources.begin(); iter != mAllSources.end(); ++iter) + LLAudioSource *sourcep = queue.top(); + queue.pop(); + + //If the syncmaster hasn't just started playing, or hasn't just looped then skip this soundslave, + //as there's nothing to do with it yet. + if (sourcep->isSyncSlave() && !syncmaster_started) { - LLAudioSource *sourcep = iter->second; + continue; + } - if (!sourcep->isSyncSlave()) - { - // Not a loop slave, we don't need to do anything - continue; - } + LLAudioChannel *channelp = sourcep->getChannel(); - LLAudioChannel *channelp = sourcep->getChannel(); - if (!channelp) + if (!channelp) + { + //No more channels. We can break here, as in theory, any lower priority sounds should have had their + //channel already stolen. There should be nothing playing, nor playable, when iterating beyond this point. + if(!(channelp = getFreeChannel(sourcep->getPriority()))) { - // Not playing, don't need to bother. - continue; + break; } - if (!channelp->isPlaying()) - { - // Now we need to check if our loop master has just looped, and - // start playback if that's the case. - if (sync_masterp->getChannel()) - { - channelp->playSynced(master_channelp); - channelp->setWaiting(false); - } - } + //If this is the primary syncmaster that we just started, then [re]start syncslaves further down in the priority queue. + //Due to sorting and priority fudgery, the syncmaster is ALWAYS before any syncslaves in this loop. + syncmaster_started |= (sourcep == sync_masterp); + + //setSource calls updateBuffer and update3DPosition, and resets the source mAgeTimer + channelp->setSource(sourcep); } + + if(sourcep->isSyncSlave()) + channelp->playSynced(sync_masterp->getChannel()); + else + channelp->play(); } // Sync up everything that the audio engine needs done. @@ -500,7 +498,7 @@ void LLAudioEngine::idle(F32 max_decode_time) { if (!mBuffers[i]->mInUse && mBuffers[i]->mLastUseTimer.getElapsedTimeF32() > 30.f) { - LL_DEBUGS("AudioEngine") << "Flushing unused buffer!" << llendl; + LL_DEBUGS("AudioEngine") << "Flushing unused buffer!" << LL_ENDL; mBuffers[i]->mAudioDatap->mBufferp = NULL; delete mBuffers[i]; mBuffers[i] = NULL; @@ -521,50 +519,13 @@ void LLAudioEngine::idle(F32 max_decode_time) // Decode audio files gAudioDecodeMgrp->processQueue(max_decode_time); - // Call this every frame, just in case we somehow - // missed picking it up in all the places that can add - // or request new data. + // Just call here every frame. It makes little sense to call elsewhere, + // as it's throttled to one active preloading loading sound at a time anyhow startNextTransfer(); updateInternetStream(); } - - -bool LLAudioEngine::updateBufferForData(LLAudioData *adp, const LLUUID &audio_uuid) -{ - if (!adp) - { - return false; - } - - // Update the audio buffer first - load a sound if we have it. - // Note that this could potentially cause us to waste time updating buffers - // for sounds that actually aren't playing, although this should be mitigated - // by the fact that we limit the number of buffers, and we flush buffers based - // on priority. - if (!adp->getBuffer()) - { - if (adp->hasDecodedData()) - { - adp->load(); - } - else if (adp->hasLocalData()) - { - if (audio_uuid.notNull()) - { - gAudioDecodeMgrp->addDecodeRequest(audio_uuid); - } - } - else - { - return false; - } - } - return true; -} - - void LLAudioEngine::enableWind(bool enable) { if (enable && (!mEnableWind)) @@ -617,7 +578,7 @@ LLAudioBuffer * LLAudioEngine::getFreeBuffer() if (buffer_id >= 0) { - LL_DEBUGS("AudioEngine") << "Taking over unused buffer! max_age=" << max_age << llendl; + LL_DEBUGS("AudioEngine") << "Taking over unused buffer! max_age=" << max_age << LL_ENDL; mBuffers[buffer_id]->mAudioDatap->mBufferp = NULL; for (U32 i = 0; i < MAX_CHANNELS; i++) { @@ -652,14 +613,9 @@ LLAudioChannel * LLAudioEngine::getFreeChannel(const F32 priority) else { // Channel is allocated but not playing right now, use it. - if (!mChannels[i]->isPlaying() && !mChannels[i]->isWaiting()) + if (mChannels[i]->isFree()) { - LL_DEBUGS("AudioEngine") << "Replacing unused channel" << llendl; - mChannels[i]->cleanup(); - if (mChannels[i]->getSource()) - { - mChannels[i]->getSource()->setChannel(NULL); - } + LL_DEBUGS("AudioEngine") << "Replacing unused channel" << LL_ENDL; return mChannels[i]; } } @@ -681,13 +637,13 @@ LLAudioChannel * LLAudioEngine::getFreeChannel(const F32 priority) } } - if (min_priority > priority || !min_channelp) + if (!min_channelp || min_priority >= priority) { // All playing channels have higher priority, return. return NULL; } - LL_DEBUGS("AudioEngine") << "Flushing min channel" << llendl; + LL_DEBUGS("AudioEngine") << "Flushing min channel" << LL_ENDL; // Flush the minimum priority channel, and return it. min_channelp->cleanup(); return min_channelp; @@ -710,19 +666,22 @@ void LLAudioEngine::cleanupBuffer(LLAudioBuffer *bufferp) bool LLAudioEngine::preloadSound(const LLUUID &uuid) { - gAudiop->getAudioData(uuid); // We don't care about the return value, this is just to make sure - // that we have an entry, which will mean that the audio engine knows about this + if(uuid.isNull()) + return false; - if (gAudioDecodeMgrp->addDecodeRequest(uuid)) + if(getAudioData(uuid)->getLoadState() >= LLAudioData::STATE_LOAD_DECODING) { // This means that we do have a local copy, and we're working on decoding it. return true; } + LL_INFOS("AudioEngine") << "Preloading system sound " << uuid << LL_ENDL; + mPreloadSystemList.push_back(uuid); + // At some point we need to have the audio/asset system check the static VFS // before it goes off and fetches stuff from the server. - //llwarns << "Used internal preload for non-local sound" << llendl; - return false; + //LL_INFOS("AudioEngine") << "Used internal preload for non-local sound" << LL_ENDL; + return true; } @@ -854,8 +813,10 @@ void LLAudioEngine::triggerSound(const LLUUID &audio_uuid, const LLUUID& owner_i const S32 type, const LLVector3d &pos_global, const LLUUID source_object) // { + if(!mListenerp) + return; // Create a new source (since this can't be associated with an existing source. - //llinfos << "Localized: " << audio_uuid << llendl; + //LL_INFOS("AudioEngine") << "Localized: " << audio_uuid << LL_ENDL; if (mMuted || gain < FLT_EPSILON*2) { @@ -885,7 +846,10 @@ void LLAudioEngine::triggerSound(const LLUUID &audio_uuid, const LLUUID& owner_i void LLAudioEngine::setListenerPos(LLVector3 aVec) { - mListenerp->setPosition(aVec); + if (mListenerp) + { + mListenerp->setPosition(aVec); + } } @@ -893,7 +857,7 @@ LLVector3 LLAudioEngine::getListenerPos() { if (mListenerp) { - return(mListenerp->getPosition()); + return mListenerp->getPosition(); } else { @@ -904,24 +868,37 @@ LLVector3 LLAudioEngine::getListenerPos() void LLAudioEngine::setListenerVelocity(LLVector3 aVec) { - mListenerp->setVelocity(aVec); + if (mListenerp) + { + mListenerp->setVelocity(aVec); + } } void LLAudioEngine::translateListener(LLVector3 aVec) { - mListenerp->translate(aVec); + if (mListenerp) + { + mListenerp->translate(aVec); + } } void LLAudioEngine::orientListener(LLVector3 up, LLVector3 at) { - mListenerp->orient(up, at); + if (mListenerp) + { + mListenerp->orient(up, at); + } } void LLAudioEngine::setListener(LLVector3 pos, LLVector3 vel, LLVector3 up, LLVector3 at) { + if(!mListenerp) + { + allocateListener(); + } mListenerp->set(pos,vel,up,at); } @@ -972,7 +949,10 @@ F32 LLAudioEngine::getRolloffFactor() void LLAudioEngine::commitDeferredChanges() { - mListenerp->commitDeferredChanges(); + if(mListenerp) + { + mListenerp->commitDeferredChanges(); + } } @@ -1025,7 +1005,7 @@ LLAudioData * LLAudioEngine::getAudioData(const LLUUID &audio_uuid) LLAudioChannel* chan=sourcep->getChannel(); if(chan) { - LL_DEBUGS("AudioEngine") << "removeAudioData" << llendl; + LL_DEBUGS("AudioEngine") << "removeAudioData" << LL_ENDL; chan->cleanup(); } delete sourcep; @@ -1063,11 +1043,15 @@ void LLAudioEngine::cleanupAudioSource(LLAudioSource *asp) iter = mAllSources.find(asp->getID()); if (iter == mAllSources.end()) { - LL_WARNS("AudioEngine") << "Cleaning up unknown audio source!" << llendl; + LL_WARNS("AudioEngine") << "Cleaning up unknown audio source!" << LL_ENDL; return; } - delete asp; - mAllSources.erase(iter); + else + { + LL_DEBUGS("AudioEngine") << "Cleaning up audio sources for "<< asp->getID() <getExists(uuid, LLAssetType::AT_SOUND); -} - - void LLAudioEngine::startNextTransfer() { - //llinfos << "LLAudioEngine::startNextTransfer()" << llendl; - if (mCurrentTransfer.notNull() || getMuted()) + //LL_INFOS("AudioEngine") << "LLAudioEngine::startNextTransfer()" << LL_ENDL; + if (getMuted()) + { + return; + } + else if(mCurrentTransferTimer.getElapsedTimeF32() <= .1f) + { + return; + } + else if(mCurrentTransfer && mCurrentTransfer->isInPreload()) { - //llinfos << "Transfer in progress, aborting" << llendl; + //Keep updating until it either errors out or completes. + mCurrentTransfer->updateLoadState(); return; } + else + { + mCurrentTransfer = NULL; + } + + //Technically, mCurrentTransfer could end up pointing to an audiodata object that's already + //being transmitted/decoded if such was spawned via needing it for playback immediately. + //This will effectively block us from choosing a lower priority audiodata object until the + //immediate ones are done, but it's not a real problem. // Get the ID for the next asset that we want to transfer. // Pick one in the following order: - LLUUID asset_id; S32 i; LLAudioSource *asp = NULL; LLAudioData *adp = NULL; + LLAudioData *cur_adp = NULL; data_map::iterator data_iter; // Check all channels for currently playing sounds. @@ -1145,15 +1139,15 @@ void LLAudioEngine::startNextTransfer() continue; } - if (!adp->hasLocalData() && adp->hasValidData()) + if (adp->isInPreload()) { - asset_id = adp->getID(); max_pri = asp->getPriority(); + cur_adp = adp; } } // Check all channels for currently queued sounds. - if (asset_id.isNull()) + if (!cur_adp) { max_pri = -1.f; for (i = 0; i < MAX_CHANNELS; i++) @@ -1181,16 +1175,16 @@ void LLAudioEngine::startNextTransfer() continue; } - if (!adp->hasLocalData() && adp->hasValidData()) + if (adp->isInPreload()) { - asset_id = adp->getID(); max_pri = asp->getPriority(); + cur_adp = adp; } } } // Check all live channels for other sounds (preloads). - if (asset_id.isNull()) + if (!cur_adp) { max_pri = -1.f; for (i = 0; i < MAX_CHANNELS; i++) @@ -1221,17 +1215,17 @@ void LLAudioEngine::startNextTransfer() continue; } - if (!adp->hasLocalData() && adp->hasValidData()) + if (adp->isInPreload()) { - asset_id = adp->getID(); max_pri = asp->getPriority(); + cur_adp = adp; } } } } // Check all sources - if (asset_id.isNull()) + if (!cur_adp) { max_pri = -1.f; source_map::iterator source_iter; @@ -1249,18 +1243,18 @@ void LLAudioEngine::startNextTransfer() } adp = asp->getCurrentData(); - if (adp && !adp->hasLocalData() && adp->hasValidData()) + if (adp && adp->isInPreload()) { - asset_id = adp->getID(); max_pri = asp->getPriority(); + cur_adp = adp; continue; } adp = asp->getQueuedData(); - if (adp && !adp->hasLocalData() && adp->hasValidData()) + if (adp && adp->isInPreload()) { - asset_id = adp->getID(); max_pri = asp->getPriority(); + cur_adp = adp; continue; } @@ -1272,27 +1266,45 @@ void LLAudioEngine::startNextTransfer() continue; } - if (!adp->hasLocalData() && adp->hasValidData()) + if (adp->isInPreload()) { - asset_id = adp->getID(); max_pri = asp->getPriority(); + cur_adp = adp; break; } } } } - if (asset_id.notNull()) + if (!cur_adp) { - LL_DEBUGS("AudioEngine") << "Getting asset data for: " << asset_id << llendl; - gAudiop->mCurrentTransfer = asset_id; - gAudiop->mCurrentTransferTimer.reset(); - gAssetStorage->getAssetData(asset_id, LLAssetType::AT_SOUND, - assetCallback, NULL); + while(!mPreloadSystemList.empty()) + { + adp = getAudioData(mPreloadSystemList.front()); + mPreloadSystemList.pop_front(); + if(adp->isInPreload()) + { + cur_adp = adp; + break; + } + } + } + else if(cur_adp) + { + std::list::iterator it = std::find(mPreloadSystemList.begin(),mPreloadSystemList.end(),cur_adp->getID()); + if(it != mPreloadSystemList.end()) + mPreloadSystemList.erase(it); + } + + if (cur_adp) + { + mCurrentTransfer = cur_adp; + mCurrentTransferTimer.reset(); + mCurrentTransfer->updateLoadState(); } else { - //llinfos << "No pending transfers?" << llendl; + //LL_INFOS("AudioEngine") << "No pending transfers?" << LL_ENDL; } } @@ -1300,37 +1312,36 @@ void LLAudioEngine::startNextTransfer() // static void LLAudioEngine::assetCallback(LLVFS *vfs, const LLUUID &uuid, LLAssetType::EType type, void *user_data, S32 result_code, LLExtStat ext_status) { + if(!gAudiop) + return; + + LLAudioData *adp = gAudiop->getAudioData(uuid); + if (result_code) { - LL_INFOS("AudioEngine") << "Boom, error in audio file transfer: " << LLAssetStorage::getErrorString( result_code ) << " (" << result_code << ")" << llendl; + LL_INFOS("AudioEngine") << "Boom, error in audio file transfer: " << LLAssetStorage::getErrorString( result_code ) << " (" << result_code << ")" << LL_ENDL; // Need to mark data as bad to avoid constant rerequests. - LLAudioData *adp = gAudiop->getAudioData(uuid); + if (adp) - { // Make sure everything is cleared - adp->setHasValidData(false); - adp->setHasLocalData(false); - adp->setHasDecodedData(false); - adp->setHasCompletedDecode(true); + { + adp->setLoadState(LLAudioData::STATE_LOAD_ERROR); } } else { - LLAudioData *adp = gAudiop->getAudioData(uuid); if (!adp) { // Should never happen - LL_WARNS("AudioEngine") << "Got asset callback without audio data for " << uuid << llendl; + LL_WARNS("AudioEngine") << "Got asset callback without audio data for " << uuid << LL_ENDL; } else { - // llinfos << "Got asset callback with good audio data for " << uuid << ", making decode request" << llendl; - adp->setHasValidData(true); - adp->setHasLocalData(true); - gAudioDecodeMgrp->addDecodeRequest(uuid); + // LL_INFOS("AudioEngine") << "Got asset callback with good audio data for " << uuid << ", making decode request" << LL_ENDL; + adp->setLoadState(LLAudioData::STATE_LOAD_REQ_DECODE); + //Immediate decode. + adp->updateLoadState(); } } - gAudiop->mCurrentTransfer = LLUUID::null; - gAudiop->startNextTransfer(); } @@ -1392,6 +1403,9 @@ void LLAudioSource::setChannel(LLAudioChannel *channelp) return; } + //Either this channel just finished playing, or just started. Either way, reset the age timer. + mAgeTimer.reset(); + // if (!channelp) { @@ -1410,22 +1424,38 @@ void LLAudioSource::update() return ; //no need to update } - //if (!getCurrentBuffer()) // Same as !adp->getBuffer() + // If data is queued up and we aren't playing it, shuffle it to current and try to load it. + if(isQueueSounds() && mPlayedOnce && mQueuedDatap && !mChannelp) { - LLAudioData *adp = getCurrentData(); - if (adp && !adp->getBuffer()) + mCurrentDatap = mQueuedDatap; + mQueuedDatap = NULL; + + //Make sure this source looks like its brand new again to prevent removal. + mPlayedOnce = false; + mAgeTimer.reset(); + } + + LLAudioData *adp = getCurrentData(); + if (adp && !adp->getBuffer()) + { + if(adp->getLoadState() == LLAudioData::STATE_LOAD_ERROR) { - // Hack - try and load the sound. Will do this as a callback - // on decode later. - if (adp->load()) - { - play(adp->getID()); - } - else if (adp->hasCompletedDecode()) // Only mark corrupted after decode is done - { - LL_WARNS("AudioEngine") << "Marking LLAudioSource corrupted for " << adp->getID() << llendl; - mCorrupted = true ; - } + LL_WARNS("AudioEngine") << "Marking LLAudioSource corrupted for " << adp->getID() << LL_ENDL; + mCorrupted = true ; + } + else if(adp->getLoadState() == LLAudioData::STATE_LOAD_READY) + { + // Update the audio buffer first - load a sound if we have it. + // Note that this could potentially cause us to waste time updating buffers + // for sounds that actually aren't playing, although this should be mitigated + // by the fact that we limit the number of buffers, and we flush buffers based + // on priority. + adp->load(); //If it fails, just try again next update. + } + else + { + //The sound wasn't preloaded yet... so we must kick off the process. + adp->updateLoadState(); } } } @@ -1434,11 +1464,11 @@ void LLAudioSource::updatePriority() { if (isAmbient()) { - mPriority = 1.f; + setPriority(1.f); } else if (isMuted()) { - mPriority = 0.f; + setPriority(0.f); } else { @@ -1448,46 +1478,10 @@ void LLAudioSource::updatePriority() dist_vec -= gAudiop->getListenerPos(); F32 dist_squared = llmax(1.f, dist_vec.magVecSquared()); - mPriority = mGain / dist_squared; + setPriority(mGain / dist_squared); } } -bool LLAudioSource::setupChannel() -{ - LLAudioData *adp = getCurrentData(); - - if (!adp->getBuffer()) - { - // We're not ready to play back the sound yet, so don't try and allocate a channel for it. - //llwarns << "Aborting, no buffer" << llendl; - return false; - } - - - if (!mChannelp) - { - // Update the priority, in case we need to push out another channel. - updatePriority(); - - setChannel(gAudiop->getFreeChannel(getPriority())); - } - - if (!mChannelp) - { - // Ugh, we don't have any free channels. - // Now we have to reprioritize. - // For now, just don't play the sound. - //llwarns << "Aborting, no free channels" << llendl; - return false; - } - - mChannelp->setSource(this); - llassert(this == mChannelp->getSource()); - llassert(mChannelp->mCurrentBufferp == getCurrentBuffer()); - return true; -} - - bool LLAudioSource::play(const LLUUID &audio_uuid) { // Special abuse of play(); don't play a sound, but kill it. @@ -1496,7 +1490,7 @@ bool LLAudioSource::play(const LLUUID &audio_uuid) if (getChannel()) { llassert(this == getChannel()->getSource()); - getChannel()->setSource(NULL); + getChannel()->cleanup(); if (!isMuted()) { mCurrentDatap = NULL; @@ -1514,172 +1508,112 @@ bool LLAudioSource::play(const LLUUID &audio_uuid) mAgeTimer.reset(); LLAudioData *adp = gAudiop->getAudioData(audio_uuid); - addAudioData(adp); - if (isMuted()) + if (isQueueSounds()) { - return false; + if(mQueuedDatap) + { + // We already have a sound queued up. Ignore new request. + return false; + } + else if (adp == mCurrentDatap && isLoop()) + { + // No point in queuing the same sound if + // we're looping. + return true; + } + else if(mCurrentDatap) + { + mQueuedDatap = adp; + return true; + } } - - bool has_buffer = gAudiop->updateBufferForData(adp, audio_uuid); - if (!has_buffer) + else if(mCurrentDatap == adp) //Desired sound did not change. Just re-play it. { - // Don't bother trying to set up a channel or anything, we don't have an audio buffer. - return false; + if(getChannel() && getChannel()->isPlaying()) + getChannel()->play(); + return true; } - - if (!setupChannel()) + else //Desired sound did change. Release the old channel if set. { - return false; + if(getChannel()) + getChannel()->cleanup(); + mPlayedOnce = false; //Reset the played flag so the new sound is actually started up. } - if (isSyncSlave()) - { - // A sync slave, it doesn't start playing until it's synced up with the master. - // Flag this channel as waiting for sync, and return true. - getChannel()->setWaiting(true); - return true; - } + mCurrentDatap = adp; - getChannel()->play(); return true; } bool LLAudioSource::isDone() const { + static const F32 MAX_AGE = 60.f; + static const F32 MAX_UNPLAYED_AGE = 15.f; + static const F32 MAX_MUTED_AGE = 11.f; if(mCorrupted) { - return true ; + // If we decode bad data then just kill this source entirely. + return true; } - - const F32 MAX_AGE = 60.f; - const F32 MAX_UNPLAYED_AGE = 15.f; - const F32 MAX_MUTED_AGE = 11.f; - - if (isLoop()) + else if (isLoop()) { // Looped sources never die on their own. return false; } - - if (hasPendingPreloads()) + else if (hasPendingPreloads()) { + // If there are pending preload requests then keep it alive. return false; } - - if (mQueuedDatap) + else if (mQueuedDatap) { // Don't kill this sound if we've got something queued up to play. return false; } + else if(mPlayedOnce && (!mChannelp || !mChannelp->isPlaying())) + { + // This is a single-play source and it already did its thing. + return true; + } F32 elapsed = mAgeTimer.getElapsedTimeF32(); - // This is a single-play source if (!mChannelp) { - if ((elapsed > (mSourceMuted ? MAX_MUTED_AGE : MAX_UNPLAYED_AGE)) || mPlayedOnce) - { - // We don't have a channel assigned, and it's been - // over 15 seconds since we tried to play it. Don't bother. - //llinfos << "No channel assigned, source is done" << llendl; - return true; - } - else - { + LLAudioData* adp = mCurrentDatap; + + //Still decoding. + if(adp && adp->isInPreload()) return false; - } - } - if (mChannelp->isPlaying()) + // We don't have a channel assigned, and it's been + // over 15 seconds since we tried to play it. Don't bother. + return (elapsed > (mSourceMuted ? MAX_MUTED_AGE : MAX_UNPLAYED_AGE)); + } + else if (mChannelp->isPlaying()) { - if (elapsed > MAX_AGE) - { - // Arbitarily cut off non-looped sounds when they're old. - return true; - } - else - { - // Sound is still playing and we haven't timed out, don't kill it. - return false; - } + // Arbitarily cut off non-looped sounds when they're old. + return elapsed > MAX_AGE; } - - if ((elapsed > MAX_UNPLAYED_AGE) || mPlayedOnce) + else if(!isSyncSlave()) { - // The sound isn't playing back after 15 seconds or we're already done playing it, kill it. - return true; + // The sound isn't playing back after 15 seconds, kill it. + // This might happen if all channels are in use and this source is low-priority + return elapsed > MAX_UNPLAYED_AGE; } return false; } -void LLAudioSource::addAudioData(LLAudioData *adp, const bool set_current) +void LLAudioSource::preload(const LLUUID &audio_id) { - // Only handle a single piece of audio data associated with a source right now, - // until I implement prefetch. - if (set_current) - { - if (!mCurrentDatap) - { - mCurrentDatap = adp; - if (mChannelp) - { - mChannelp->updateBuffer(); - mChannelp->play(); - } - - // Make sure the audio engine knows that we want to request this sound. - gAudiop->startNextTransfer(); - return; - } - else if (mQueueSounds) - { - // If we have current data, and we're queuing, put - // the object onto the queue. - if (mQueuedDatap) - { - // We only queue one sound at a time, and it's a FIFO. - // Don't put it onto the queue. - return; - } - - if (adp == mCurrentDatap && isLoop()) - { - // No point in queueing the same sound if - // we're looping. - return; - } - mQueuedDatap = adp; - - // Make sure the audio engine knows that we want to request this sound. - gAudiop->startNextTransfer(); - } - else - { - if (mCurrentDatap != adp) - { - // Right now, if we're currently playing this sound in a channel, we - // update the buffer that the channel's associated with - // and play it. This may not be the correct behavior. - mCurrentDatap = adp; - if (mChannelp) - { - mChannelp->updateBuffer(); - mChannelp->play(); - } - // Make sure the audio engine knows that we want to request this sound. - gAudiop->startNextTransfer(); - } - } - } - else + if(audio_id.notNull()) { // Add it to the preload list. - mPreloadMap[adp->getID()] = adp; - gAudiop->startNextTransfer(); + mPreloadMap[audio_id] = gAudiop->getAudioData(audio_id); } } @@ -1697,7 +1631,7 @@ bool LLAudioSource::hasPendingPreloads() const { continue; } - if (!adp->hasDecodedData() && adp->hasValidData()) + if (adp->isInPreload()) { // This source is still waiting for a preload return true; @@ -1740,18 +1674,16 @@ LLAudioChannel::LLAudioChannel() : mCurrentSourcep(NULL), mCurrentBufferp(NULL), mLoopedThisFrame(false), - mWaiting(false), mSecondaryGain(1.0f) { } - LLAudioChannel::~LLAudioChannel() { llassert(mCurrentBufferp == NULL); // Need to disconnect any sources which are using this channel. - //llinfos << "Cleaning up audio channel" << llendl; + //LL_INFOS("AudioEngine") << "Cleaning up audio channel" << LL_ENDL; cleanup(); } @@ -1761,29 +1693,14 @@ void LLAudioChannel::cleanup() mCurrentSourcep->setChannel(NULL); mCurrentBufferp = NULL; mCurrentSourcep = NULL; - mWaiting = false; } void LLAudioChannel::setSource(LLAudioSource *sourcep) { - //llinfos << this << ": setSource(" << sourcep << ")" << llendl; - - if (!sourcep) - { - // Clearing the source for this channel, don't need to do anything. - LL_DEBUGS("AudioEngine") << "Clearing source for channel" << llendl; - cleanup(); - return; - } + llassert_always(sourcep); + llassert_always(!mCurrentSourcep); - if (sourcep == mCurrentSourcep) - { - // Don't reallocate the channel, this will make FMOD goofy. - LL_DEBUGS("AudioEngine") << "Calling setSource with same source!" << llendl; - } - - cleanup(); mCurrentSourcep = sourcep; mCurrentSourcep->setChannel(this); @@ -1808,42 +1725,16 @@ bool LLAudioChannel::updateBuffer() } LLAudioBuffer *bufferp = mCurrentSourcep->getCurrentBuffer(); - if (bufferp == mCurrentBufferp) - { - if (bufferp) - { - // The source hasn't changed what buffer it's playing - bufferp->mLastUseTimer.reset(); - bufferp->mInUse = true; - } - return false; - } - // - // The source changed what buffer it's playing. We need to clean up - // the existing channel - // - LLAudioSource* source = mCurrentSourcep; - cleanup(); - mCurrentSourcep = source; - mCurrentSourcep->setChannel(this); - - llassert(mCurrentBufferp == NULL); - - mCurrentBufferp = bufferp; + //This buffer is still in use, so mark it as such, and reset the use timer. if (bufferp) { bufferp->mLastUseTimer.reset(); bufferp->mInUse = true; } - if (!mCurrentBufferp) - { - // There's no new buffer to be played, so we just abort. - return false; - } - - return true; + //Return true if the buffer changed and is not null. + return bufferp != mCurrentBufferp && !!(mCurrentBufferp = bufferp); } @@ -1857,27 +1748,42 @@ bool LLAudioChannel::updateBuffer() LLAudioData::LLAudioData(const LLUUID &uuid) : mID(uuid), mBufferp(NULL), - mHasLocalData(false), - mHasDecodedData(false), - mHasCompletedDecode(false), - mHasValidData(true) + mLoadState(STATE_LOAD_ERROR) { if (uuid.isNull()) { // This is a null sound. return; } - - if (gAudiop && gAudiop->hasDecodedFile(uuid)) + + if(gAudiop->hasDecodedFile(getID())) + mLoadState = STATE_LOAD_READY; + else if(gAssetStorage && gAssetStorage->hasLocalAsset(getID(), LLAssetType::AT_SOUND)) + mLoadState = STATE_LOAD_REQ_DECODE; + else + mLoadState = STATE_LOAD_REQ_FETCH; +} + +void LLAudioData::updateLoadState() +{ + if(mLoadState == STATE_LOAD_REQ_DECODE && gAudioDecodeMgrp) { - // Already have a decoded version, don't need to decode it. - setHasLocalData(true); - setHasDecodedData(true); - setHasCompletedDecode(true); + if( gAudioDecodeMgrp->addDecodeRequest(getID()) ) + { + setLoadState(STATE_LOAD_DECODING); + LL_DEBUGS("AudioEngine") << "Decoding asset data for: " << getID() << LL_ENDL; + } + else + { + setLoadState(STATE_LOAD_ERROR); + } } - else if (gAssetStorage && gAssetStorage->hasLocalAsset(uuid, LLAssetType::AT_SOUND)) + else if(mLoadState == STATE_LOAD_REQ_FETCH && gAssetStorage && gAssetStorage->isUpstreamOK()) { - setHasLocalData(true); + LL_DEBUGS("AudioEngine") << "Fetching asset data for: " << getID() << LL_ENDL; + setLoadState(STATE_LOAD_FETCHING); + + gAssetStorage->getAssetData(getID(), LLAssetType::AT_SOUND, LLAudioEngine::assetCallback, NULL); } } @@ -1888,7 +1794,7 @@ bool LLAudioData::load() if (mBufferp) { // We already have this sound in a buffer, don't do anything. - LL_INFOS("AudioEngine") << "Already have a buffer for this sound, don't bother loading!" << llendl; + LL_INFOS("AudioEngine") << "Already have a buffer for this sound, don't bother loading!" << LL_ENDL; return true; } @@ -1896,7 +1802,7 @@ bool LLAudioData::load() if (!mBufferp) { // No free buffers, abort. - LL_DEBUGS("AudioEngine") << "Not able to allocate a new audio buffer, aborting." << llendl; + LL_DEBUGS("AudioEngine") << "Not able to allocate a new audio buffer, aborting." << LL_ENDL; return false; } diff --git a/indra/llaudio/llaudioengine.h b/indra/llaudio/llaudioengine.h index c739e37bfe..717e688df1 100644 --- a/indra/llaudio/llaudioengine.h +++ b/indra/llaudio/llaudioengine.h @@ -147,7 +147,7 @@ class LLAudioEngine const LLVector3d &pos_global = LLVector3d::zero, const LLUUID source_object = LLUUID::null); // - bool preloadSound(const LLUUID &id); + bool preloadSound(const LLUUID &id); //Preloads sounds without requiring a source. void addAudioSource(LLAudioSource *asp); void cleanupAudioSource(LLAudioSource *asp); @@ -177,9 +177,6 @@ class LLAudioEngine void cleanupBuffer(LLAudioBuffer *bufferp); bool hasDecodedFile(const LLUUID &uuid); - bool hasLocalFile(const LLUUID &uuid); - - bool updateBufferForData(LLAudioData *adp, const LLUUID &audio_uuid = LLUUID::null); void setAllowLargeSounds(bool allow) { mAllowLargeSounds = allow ;} bool getAllowLargeSounds() const {return mAllowLargeSounds;} @@ -229,7 +226,7 @@ class LLAudioEngine S32 mNumChannels; bool mEnableWind; - LLUUID mCurrentTransfer; // Audio file currently being transferred by the system + LLAudioData* mCurrentTransfer; // Audio file currently being transferred by the system LLFrameTimer mCurrentTransferTimer; // A list of all audio sources that are known to the viewer at this time. @@ -244,6 +241,7 @@ class LLAudioEngine source_map mAllSources; protected: data_map mAllData; + std::list mPreloadSystemList; LLAudioChannel *mChannels[MAX_CHANNELS]; // Buffers needs to change into a different data structure, as the number of buffers @@ -287,9 +285,7 @@ class LLAudioSource virtual void update(); // Update this audio source void updatePriority(); - void preload(const LLUUID &audio_id); // Only used for preloading UI sounds, now. - - void addAudioData(LLAudioData *adp, bool set_current = TRUE); + void preload(const LLUUID &audio_id); void setAmbient(const bool ambient) { mAmbient = ambient; } bool isAmbient() const { return mAmbient; } @@ -319,6 +315,7 @@ class LLAudioSource LLVector3d getPositionGlobal() const { return mPositionGlobal; } LLVector3 getVelocity() const { return mVelocity; } F32 getPriority() const { return mPriority; } + void setPriority(F32 priority) { mPriority = priority; } // Gain should always be clamped between 0 and 1. F32 getGain() const { return mGain; } @@ -402,25 +399,27 @@ class LLAudioData LLUUID getID() const { return mID; } LLAudioBuffer *getBuffer() const { return mBufferp; } - bool hasLocalData() const { return mHasLocalData; } - bool hasDecodedData() const { return mHasDecodedData; } - bool hasCompletedDecode() const { return mHasCompletedDecode; } - bool hasValidData() const { return mHasValidData; } + enum ELoadState + { + STATE_LOAD_ERROR, + STATE_LOAD_REQ_FETCH, + STATE_LOAD_FETCHING, + STATE_LOAD_REQ_DECODE, + STATE_LOAD_DECODING, + STATE_LOAD_READY + }; + ELoadState getLoadState() const { return mLoadState; } + ELoadState setLoadState(ELoadState state) { return mLoadState = state; } + bool isInPreload() const { return mLoadState > STATE_LOAD_ERROR && mLoadState < STATE_LOAD_READY; } - void setHasLocalData(const bool hld) { mHasLocalData = hld; } - void setHasDecodedData(const bool hdd) { mHasDecodedData = hdd; } - void setHasCompletedDecode(const bool hcd) { mHasCompletedDecode = hcd; } - void setHasValidData(const bool hvd) { mHasValidData = hvd; } + void updateLoadState(); friend class LLAudioEngine; // Severe laziness, bad. protected: LLUUID mID; LLAudioBuffer *mBufferp; // If this data is being used by the audio system, a pointer to the buffer will be set here. - bool mHasLocalData; // Set true if the sound asset file is available locally - bool mHasDecodedData; // Set true if the sound file has been decoded - bool mHasCompletedDecode; // Set true when the sound is decoded - bool mHasValidData; // Set false if decoding failed, meaning the sound asset is bad + ELoadState mLoadState; }; @@ -450,11 +449,10 @@ class LLAudioChannel virtual void play() = 0; virtual void playSynced(LLAudioChannel *channelp) = 0; virtual void cleanup(); - void setWaiting(bool waiting) { mWaiting = waiting; } public: virtual bool isPlaying() = 0; - bool isWaiting() const { return mWaiting; } + bool isFree() const { return mCurrentSourcep==NULL; } protected: virtual bool updateBuffer(); // Check to see if the buffer associated with the source changed, and update if necessary. @@ -465,7 +463,6 @@ class LLAudioChannel LLAudioSource *mCurrentSourcep; LLAudioBuffer *mCurrentBufferp; bool mLoopedThisFrame; - bool mWaiting; // Waiting for sync. F32 mSecondaryGain; }; diff --git a/indra/llaudio/llaudioengine_fmod.cpp b/indra/llaudio/llaudioengine_fmod.cpp deleted file mode 100644 index 4c4f4f48d5..0000000000 --- a/indra/llaudio/llaudioengine_fmod.cpp +++ /dev/null @@ -1,782 +0,0 @@ -/** - * @file audioengine_fmod.cpp - * @brief Implementation of LLAudioEngine class abstracting the audio support as a FMOD 3D implementation - * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include "llstreamingaudio.h" -#include "llstreamingaudio_fmod.h" - -#include "llaudioengine_fmod.h" -#include "lllistener_fmod.h" - -#include "llerror.h" -#include "llmath.h" -#include "llrand.h" - -#include "fmod.h" -#include "fmod_errors.h" -#include "lldir.h" -#include "llapr.h" - -#include "sound_ids.h" - - -extern "C" { - void * F_CALLBACKAPI windCallback(void *originalbuffer, void *newbuffer, int length, void* userdata); -} - - -LLAudioEngine_FMOD::LLAudioEngine_FMOD() -{ - mInited = false; - mWindGen = NULL; - mWindDSP = NULL; -} - - -LLAudioEngine_FMOD::~LLAudioEngine_FMOD() -{ -} - - -bool LLAudioEngine_FMOD::init(const S32 num_channels, void* userdata) -{ - LLAudioEngine::init(num_channels, userdata); - - // Reserve one extra channel for the http stream. - if (!FSOUND_SetMinHardwareChannels(num_channels + 1)) - { - LL_WARNS("AppInit") << "FMOD::init[0](), error: " << FMOD_ErrorString(FSOUND_GetError()) << LL_ENDL; - } - - LL_DEBUGS("AppInit") << "LLAudioEngine_FMOD::init() initializing FMOD" << LL_ENDL; - - F32 version = FSOUND_GetVersion(); - if (version < FMOD_VERSION) - { - LL_WARNS("AppInit") << "Error : You are using the wrong FMOD version (" << version - << ")! You should be using FMOD " << FMOD_VERSION << LL_ENDL; - //return false; - } - - U32 fmod_flags = 0x0; - -#if LL_WINDOWS - // Windows needs to know which window is frontmost. - // This must be called before FSOUND_Init() per the FMOD docs. - // This could be used to let FMOD handle muting when we lose focus, - // but we don't actually want to do that because we want to distinguish - // between minimized and not-focused states. - if (!FSOUND_SetHWND(userdata)) - { - LL_WARNS("AppInit") << "Error setting FMOD window: " - << FMOD_ErrorString(FSOUND_GetError()) << LL_ENDL; - return false; - } - // Play audio when we don't have focus. - // (For example, IM client on top of us.) - // This means we also try to play audio when minimized, - // so we manually handle muting in that case. JC - fmod_flags |= FSOUND_INIT_GLOBALFOCUS; - fmod_flags |= FSOUND_INIT_DSOUND_HRTF_FULL; -#endif - -#if LL_LINUX - // initialize the FMOD engine - - // This is a hack to use only FMOD's basic FPU mixer - // when the LL_VALGRIND environmental variable is set, - // otherwise valgrind will fall over on FMOD's MMX detection - if (getenv("LL_VALGRIND")) /*Flawfinder: ignore*/ - { - LL_INFOS("AppInit") << "Pacifying valgrind in FMOD init." << LL_ENDL; - FSOUND_SetMixer(FSOUND_MIXER_QUALITY_FPU); - } - - // If we don't set an output method, Linux FMOD always - // decides on OSS and fails otherwise. So we'll manually - // try ESD, then OSS, then ALSA. - // Why this order? See SL-13250, but in short, OSS emulated - // on top of ALSA is ironically more reliable than raw ALSA. - // Ack, and ESD has more reliable failure modes - but has worse - // latency - than all of them, so wins for now. - bool audio_ok = false; - - if (!audio_ok) - { - if (NULL == getenv("LL_BAD_FMOD_ESD")) /*Flawfinder: ignore*/ - { - LL_DEBUGS("AppInit") << "Trying ESD audio output..." << LL_ENDL; - if(FSOUND_SetOutput(FSOUND_OUTPUT_ESD) && - FSOUND_Init(44100, num_channels, fmod_flags)) - { - LL_DEBUGS("AppInit") << "ESD audio output initialized OKAY" - << LL_ENDL; - audio_ok = true; - } else { - LL_WARNS("AppInit") << "ESD audio output FAILED to initialize: " - << FMOD_ErrorString(FSOUND_GetError()) << LL_ENDL; - } - } else { - LL_DEBUGS("AppInit") << "ESD audio output SKIPPED" << LL_ENDL; - } - } - if (!audio_ok) - { - if (NULL == getenv("LL_BAD_FMOD_OSS")) /*Flawfinder: ignore*/ - { - LL_DEBUGS("AppInit") << "Trying OSS audio output..." << LL_ENDL; - if(FSOUND_SetOutput(FSOUND_OUTPUT_OSS) && - FSOUND_Init(44100, num_channels, fmod_flags)) - { - LL_DEBUGS("AppInit") << "OSS audio output initialized OKAY" << LL_ENDL; - audio_ok = true; - } else { - LL_WARNS("AppInit") << "OSS audio output FAILED to initialize: " - << FMOD_ErrorString(FSOUND_GetError()) << LL_ENDL; - } - } else { - LL_DEBUGS("AppInit") << "OSS audio output SKIPPED" << LL_ENDL; - } - } - if (!audio_ok) - { - if (NULL == getenv("LL_BAD_FMOD_ALSA")) /*Flawfinder: ignore*/ - { - LL_DEBUGS("AppInit") << "Trying ALSA audio output..." << LL_ENDL; - if(FSOUND_SetOutput(FSOUND_OUTPUT_ALSA) && - FSOUND_Init(44100, num_channels, fmod_flags)) - { - LL_DEBUGS("AppInit") << "ALSA audio output initialized OKAY" << LL_ENDL; - audio_ok = true; - } else { - LL_WARNS("AppInit") << "ALSA audio output FAILED to initialize: " - << FMOD_ErrorString(FSOUND_GetError()) << LL_ENDL; - } - } else { - LL_DEBUGS("AppInit") << "OSS audio output SKIPPED" << LL_ENDL; - } - } - if (!audio_ok) - { - LL_WARNS("AppInit") << "Overall audio init failure." << LL_ENDL; - return false; - } - - // On Linux, FMOD causes a SIGPIPE for some netstream error - // conditions (an FMOD bug); ignore SIGPIPE so it doesn't crash us. - // NOW FIXED in FMOD 3.x since 2006-10-01. - //signal(SIGPIPE, SIG_IGN); - - // We're interested in logging which output method we - // ended up with, for QA purposes. - switch (FSOUND_GetOutput()) - { - case FSOUND_OUTPUT_NOSOUND: LL_DEBUGS("AppInit") << "Audio output: NoSound" << LL_ENDL; break; - case FSOUND_OUTPUT_OSS: LL_DEBUGS("AppInit") << "Audio output: OSS" << LL_ENDL; break; - case FSOUND_OUTPUT_ESD: LL_DEBUGS("AppInit") << "Audio output: ESD" << LL_ENDL; break; - case FSOUND_OUTPUT_ALSA: LL_DEBUGS("AppInit") << "Audio output: ALSA" << LL_ENDL; break; - default: LL_INFOS("AppInit") << "Audio output: Unknown!" << LL_ENDL; break; - }; - -#else // LL_LINUX - - // initialize the FMOD engine - if (!FSOUND_Init(44100, num_channels, fmod_flags)) - { - LL_WARNS("AppInit") << "Error initializing FMOD: " - << FMOD_ErrorString(FSOUND_GetError()) << LL_ENDL; - return false; - } - -#endif - - // set up our favourite FMOD-native streaming audio implementation if none has already been added - if (!getStreamingAudioImpl()) // no existing implementation added - setStreamingAudioImpl(new LLStreamingAudio_FMOD()); - - LL_DEBUGS("AppInit") << "LLAudioEngine_FMOD::init() FMOD initialized correctly" << LL_ENDL; - - mInited = true; - - return true; -} - - -std::string LLAudioEngine_FMOD::getDriverName(bool verbose) -{ - if (verbose) - { - F32 version = FSOUND_GetVersion(); - return llformat("FMOD version %f", version); - } - else - { - return "FMOD"; - } -} - - -void LLAudioEngine_FMOD::allocateListener(void) -{ - mListenerp = (LLListener *) new LLListener_FMOD(); - if (!mListenerp) - { - llwarns << "Listener creation failed" << llendl; - } -} - - -void LLAudioEngine_FMOD::shutdown() -{ - if (mWindDSP) - { - FSOUND_DSP_SetActive(mWindDSP,false); - FSOUND_DSP_Free(mWindDSP); - } - - stopInternetStream(); - - LLAudioEngine::shutdown(); - - llinfos << "LLAudioEngine_FMOD::shutdown() closing FMOD" << llendl; - FSOUND_Close(); - llinfos << "LLAudioEngine_FMOD::shutdown() done closing FMOD" << llendl; - - delete mListenerp; - mListenerp = NULL; -} - - -LLAudioBuffer * LLAudioEngine_FMOD::createBuffer() -{ - return new LLAudioBufferFMOD(); -} - - -LLAudioChannel * LLAudioEngine_FMOD::createChannel() -{ - return new LLAudioChannelFMOD(); -} - - -bool LLAudioEngine_FMOD::initWind() -{ - if (!mWindGen) - { - bool enable; - - switch (FSOUND_GetMixer()) - { - case FSOUND_MIXER_MMXP5: - case FSOUND_MIXER_MMXP6: - case FSOUND_MIXER_QUALITY_MMXP5: - case FSOUND_MIXER_QUALITY_MMXP6: - enable = (typeid(MIXBUFFERFORMAT) == typeid(S16)); - break; - case FSOUND_MIXER_BLENDMODE: - enable = (typeid(MIXBUFFERFORMAT) == typeid(S32)); - break; - case FSOUND_MIXER_QUALITY_FPU: - enable = (typeid(MIXBUFFERFORMAT) == typeid(F32)); - break; - default: - // FSOUND_GetMixer() does not return a valid mixer type on Darwin - LL_INFOS("AppInit") << "Unknown FMOD mixer type, assuming default" << LL_ENDL; - enable = true; - break; - } - - if (enable) - { - mWindGen = new LLWindGen(FSOUND_GetOutputRate()); - } - else - { - LL_WARNS("AppInit") << "Incompatible FMOD mixer type, wind noise disabled" << LL_ENDL; - } - } - - mNextWindUpdate = 0.0; - - if (mWindGen && !mWindDSP) - { - mWindDSP = FSOUND_DSP_Create(&windCallback, FSOUND_DSP_DEFAULTPRIORITY_CLEARUNIT + 20, mWindGen); - } - if (mWindDSP) - { - FSOUND_DSP_SetActive(mWindDSP, true); - return true; - } - - return false; -} - - -void LLAudioEngine_FMOD::cleanupWind() -{ - if (mWindDSP) - { - FSOUND_DSP_SetActive(mWindDSP, false); - FSOUND_DSP_Free(mWindDSP); - mWindDSP = NULL; - } - - delete mWindGen; - mWindGen = NULL; -} - - -//----------------------------------------------------------------------- -void LLAudioEngine_FMOD::updateWind(LLVector3 wind_vec, F32 camera_height_above_water) -{ - LLVector3 wind_pos; - F64 pitch; - F64 center_freq; - - if (!mEnableWind) - { - return; - } - - if (mWindUpdateTimer.checkExpirationAndReset(LL_WIND_UPDATE_INTERVAL)) - { - - // wind comes in as Linden coordinate (+X = forward, +Y = left, +Z = up) - // need to convert this to the conventional orientation DS3D and OpenAL use - // where +X = right, +Y = up, +Z = backwards - - wind_vec.setVec(-wind_vec.mV[1], wind_vec.mV[2], -wind_vec.mV[0]); - - // cerr << "Wind update" << endl; - - pitch = 1.0 + mapWindVecToPitch(wind_vec); - center_freq = 80.0 * pow(pitch,2.5*(mapWindVecToGain(wind_vec)+1.0)); - - mWindGen->mTargetFreq = (F32)center_freq; - mWindGen->mTargetGain = (F32)mapWindVecToGain(wind_vec) * mMaxWindGain; - mWindGen->mTargetPanGainR = (F32)mapWindVecToPan(wind_vec); - } -} - -/* -//----------------------------------------------------------------------- -void LLAudioEngine_FMOD::setSourceMinDistance(U16 source_num, F64 distance) -{ - if (!mInited) - { - return; - } - if (mBuffer[source_num]) - { - mMinDistance[source_num] = (F32) distance; - if (!FSOUND_Sample_SetMinMaxDistance(mBuffer[source_num],mMinDistance[source_num], mMaxDistance[source_num])) - { - llwarns << "FMOD::setSourceMinDistance(" << source_num << "), error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl; - } - } -} - -//----------------------------------------------------------------------- -void LLAudioEngine_FMOD::setSourceMaxDistance(U16 source_num, F64 distance) -{ - if (!mInited) - { - return; - } - if (mBuffer[source_num]) - { - mMaxDistance[source_num] = (F32) distance; - if (!FSOUND_Sample_SetMinMaxDistance(mBuffer[source_num],mMinDistance[source_num], mMaxDistance[source_num])) - { - llwarns << "FMOD::setSourceMaxDistance(" << source_num << "), error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl; - } - } -} - -//----------------------------------------------------------------------- -void LLAudioEngine_FMOD::get3DParams(S32 source_num, S32 *volume, S32 *freq, S32 *inside, S32 *outside, LLVector3 *orient, S32 *out_volume, F32 *min_dist, F32 *max_dist) -{ - *volume = 0; - *freq = 0; - *inside = 0; - *outside = 0; - *orient = LLVector3::zero; - *out_volume = 0; - *min_dist = 0.f; - *max_dist = 0.f; -} - -*/ - - -//----------------------------------------------------------------------- -void LLAudioEngine_FMOD::setInternalGain(F32 gain) -{ - if (!mInited) - { - return; - } - - gain = llclamp( gain, 0.0f, 1.0f ); - FSOUND_SetSFXMasterVolume( llround( 255.0f * gain ) ); - - LLStreamingAudioInterface *saimpl = getStreamingAudioImpl(); - if ( saimpl ) - { - // fmod likes its streaming audio channel gain re-asserted after - // master volume change. - saimpl->setGain(saimpl->getGain()); - } -} - -// -// LLAudioChannelFMOD implementation -// - -LLAudioChannelFMOD::LLAudioChannelFMOD() : LLAudioChannel(), mChannelID(0), mLastSamplePos(0) -{ -} - - -LLAudioChannelFMOD::~LLAudioChannelFMOD() -{ - cleanup(); -} - - -bool LLAudioChannelFMOD::updateBuffer() -{ - if (LLAudioChannel::updateBuffer()) - { - // Base class update returned true, which means that we need to actually - // set up the channel for a different buffer. - - LLAudioBufferFMOD *bufferp = (LLAudioBufferFMOD *)mCurrentSourcep->getCurrentBuffer(); - - // Grab the FMOD sample associated with the buffer - FSOUND_SAMPLE *samplep = bufferp->getSample(); - if (!samplep) - { - // This is bad, there should ALWAYS be a sample associated with a legit - // buffer. - llerrs << "No FMOD sample!" << llendl; - return false; - } - - - // Actually play the sound. Start it off paused so we can do all the necessary - // setup. - mChannelID = FSOUND_PlaySoundEx(FSOUND_FREE, samplep, FSOUND_DSP_GetSFXUnit(), true); - - //llinfos << "Setting up channel " << std::hex << mChannelID << std::dec << llendl; - } - - // If we have a source for the channel, we need to update its gain. - if (mCurrentSourcep) - { - // SJB: warnings can spam and hurt framerate, disabling - if (!FSOUND_SetVolume(mChannelID, llround(getSecondaryGain() * mCurrentSourcep->getGain() * 255.0f))) - { -// llwarns << "LLAudioChannelFMOD::updateBuffer error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl; - } - - if (!FSOUND_SetLoopMode(mChannelID, mCurrentSourcep->isLoop() ? FSOUND_LOOP_NORMAL : FSOUND_LOOP_OFF)) - { -// llwarns << "Channel " << mChannelID << "Source ID: " << mCurrentSourcep->getID() -// << " at " << mCurrentSourcep->getPositionGlobal() << llendl; -// llwarns << "LLAudioChannelFMOD::updateBuffer error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl; - } - } - - return true; -} - - -void LLAudioChannelFMOD::update3DPosition() -{ - if (!mChannelID) - { - // We're not actually a live channel (i.e., we're not playing back anything) - return; - } - - LLAudioBufferFMOD *bufferp = (LLAudioBufferFMOD *)mCurrentBufferp; - if (!bufferp) - { - // We don't have a buffer associated with us (should really have been picked up - // by the above if. - return; - } - - if (mCurrentSourcep->isAmbient()) - { - // Ambient sound, don't need to do any positional updates. - bufferp->set3DMode(false); - } - else - { - // Localized sound. Update the position and velocity of the sound. - bufferp->set3DMode(true); - - LLVector3 float_pos; - float_pos.setVec(mCurrentSourcep->getPositionGlobal()); - if (!FSOUND_3D_SetAttributes(mChannelID, float_pos.mV, mCurrentSourcep->getVelocity().mV)) - { - LL_DEBUGS("FMOD") << "LLAudioChannelFMOD::update3DPosition error: " << FMOD_ErrorString(FSOUND_GetError()) << LL_ENDL; - } - } -} - - -void LLAudioChannelFMOD::updateLoop() -{ - if (!mChannelID) - { - // May want to clear up the loop/sample counters. - return; - } - - // - // Hack: We keep track of whether we looped or not by seeing when the - // sample position looks like it's going backwards. Not reliable; may - // yield false negatives. - // - U32 cur_pos = FSOUND_GetCurrentPosition(mChannelID); - if (cur_pos < (U32)mLastSamplePos) - { - mLoopedThisFrame = true; - } - mLastSamplePos = cur_pos; -} - - -void LLAudioChannelFMOD::cleanup() -{ - LLAudioChannel::cleanup(); - if (!mChannelID) - { - //llinfos << "Aborting cleanup with no channelID." << llendl; - return; - } - - //llinfos << "Cleaning up channel: " << mChannelID << llendl; - if (!FSOUND_StopSound(mChannelID)) - { - LL_DEBUGS("FMOD") << "LLAudioChannelFMOD::cleanup error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl; - } - - mChannelID = 0; -} - - -void LLAudioChannelFMOD::play() -{ - if (!mChannelID) - { - llwarns << "Playing without a channelID, aborting" << llendl; - return; - } - - if (!FSOUND_SetPaused(mChannelID, false)) - { - llwarns << "LLAudioChannelFMOD::play error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl; - } - getSource()->setPlayedOnce(true); -} - - -void LLAudioChannelFMOD::playSynced(LLAudioChannel *channelp) -{ - LLAudioChannelFMOD *fmod_channelp = (LLAudioChannelFMOD*)channelp; - if (!(fmod_channelp->mChannelID && mChannelID)) - { - // Don't have channels allocated to both the master and the slave - return; - } - - U32 position = FSOUND_GetCurrentPosition(fmod_channelp->mChannelID) % mCurrentBufferp->getLength(); - // Try to match the position of our sync master - if (!FSOUND_SetCurrentPosition(mChannelID, position)) - { - llwarns << "LLAudioChannelFMOD::playSynced unable to set current position" << llendl; - } - - // Start us playing - play(); -} - - -bool LLAudioChannelFMOD::isPlaying() -{ - if (!mChannelID) - { - return false; - } - - return FSOUND_IsPlaying(mChannelID) && (!FSOUND_GetPaused(mChannelID)); -} - - - -// -// LLAudioBufferFMOD implementation -// - - -LLAudioBufferFMOD::LLAudioBufferFMOD() : LLAudioBuffer() -{ - mSamplep = NULL; -} - - -LLAudioBufferFMOD::~LLAudioBufferFMOD() -{ - if (mSamplep) - { - // Clean up the associated FMOD sample if it exists. - FSOUND_Sample_Free(mSamplep); - mSamplep = NULL; - } -} - - -bool LLAudioBufferFMOD::loadWAV(const std::string& filename) -{ - // Try to open a wav file from disk. This will eventually go away, as we don't - // really want to block doing this. - if (filename.empty()) - { - // invalid filename, abort. - return false; - } - - if (!LLAPRFile::isExist(filename, LL_APR_RPB)) - { - // File not found, abort. - return false; - } - - if (mSamplep) - { - // If there's already something loaded in this buffer, clean it up. - FSOUND_Sample_Free(mSamplep); - mSamplep = NULL; - } - - // Load up the wav file into an fmod sample -#if LL_WINDOWS - // MikeS. - Loading the sound file manually and then handing it over to FMOD, - // since FMOD uses posix IO internally, - // which doesn't work with unicode file paths. - LLFILE* sound_file = LLFile::fopen(filename,"rb"); /* Flawfinder: ignore */ - if (sound_file) - { - fseek(sound_file,0,SEEK_END); - U32 file_length = ftell(sound_file); //Find the length of the file by seeking to the end and getting the offset - size_t read_count; - fseek(sound_file,0,SEEK_SET); //Seek back to the beginning - char* buffer = new char[file_length]; - llassert(buffer); - read_count = fread((void*)buffer,file_length,1,sound_file);//Load it.. - if(ferror(sound_file)==0 && (read_count == 1)){//No read error, and we got 1 chunk of our size... - unsigned int mode_flags = FSOUND_LOOP_NORMAL | FSOUND_LOADMEMORY; - //FSOUND_16BITS | FSOUND_MONO | FSOUND_LOADMEMORY | FSOUND_LOOP_NORMAL; - mSamplep = FSOUND_Sample_Load(FSOUND_UNMANAGED, buffer, mode_flags , 0, file_length); - } - delete[] buffer; - fclose(sound_file); - } -#else - mSamplep = FSOUND_Sample_Load(FSOUND_UNMANAGED, filename.c_str(), FSOUND_LOOP_NORMAL, 0, 0); -#endif - - if (!mSamplep) - { - // We failed to load the file for some reason. - llwarns << "Could not load data '" << filename << "': " - << FMOD_ErrorString(FSOUND_GetError()) << llendl; - - // - // If we EVER want to load wav files provided by end users, we need - // to rethink this! - // - // file is probably corrupt - remove it. - LLFile::remove(filename); - return false; - } - - // Everything went well, return true - return true; -} - - -U32 LLAudioBufferFMOD::getLength() -{ - if (!mSamplep) - { - return 0; - } - - return FSOUND_Sample_GetLength(mSamplep); -} - - -void LLAudioBufferFMOD::set3DMode(bool use3d) -{ - U16 current_mode = FSOUND_Sample_GetMode(mSamplep); - - if (use3d) - { - if (!FSOUND_Sample_SetMode(mSamplep, (current_mode & (~FSOUND_2D)))) - { - llwarns << "LLAudioBufferFMOD::set3DMode error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl; - } - } - else - { - if (!FSOUND_Sample_SetMode(mSamplep, current_mode | FSOUND_2D)) - { - llwarns << "LLAudioBufferFMOD::set3DMode error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl; - } - } -} - - -void * F_CALLBACKAPI windCallback(void *originalbuffer, void *newbuffer, int length, void* userdata) -{ - // originalbuffer = fmod's original mixbuffer. - // newbuffer = the buffer passed from the previous DSP unit. - // length = length in samples at this mix time. - // userdata = user parameter passed through in FSOUND_DSP_Create. - - LLWindGen *windgen = - (LLWindGen *)userdata; - - newbuffer = windgen->windGenerate((LLAudioEngine_FMOD::MIXBUFFERFORMAT *)newbuffer, length); - - return newbuffer; -} diff --git a/indra/llaudio/llaudioengine_fmod.h b/indra/llaudio/llaudioengine_fmod.h deleted file mode 100644 index 4582a5d57e..0000000000 --- a/indra/llaudio/llaudioengine_fmod.h +++ /dev/null @@ -1,124 +0,0 @@ -/** - * @file audioengine_fmod.h - * @brief Definition of LLAudioEngine class abstracting the audio - * support as a FMOD 3D implementation - * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_AUDIOENGINE_FMOD_H -#define LL_AUDIOENGINE_FMOD_H - -#include "llaudioengine.h" -#include "lllistener_fmod.h" -#include "llwindgen.h" - -#include "fmod.h" - -class LLAudioStreamManagerFMOD; - -class LLAudioEngine_FMOD : public LLAudioEngine -{ -public: - LLAudioEngine_FMOD(); - virtual ~LLAudioEngine_FMOD(); - - // initialization/startup/shutdown - virtual bool init(const S32 num_channels, void *user_data); - virtual std::string getDriverName(bool verbose); - virtual void allocateListener(); - - virtual void shutdown(); - - /*virtual*/ bool initWind(); - /*virtual*/ void cleanupWind(); - - /*virtual*/void updateWind(LLVector3 direction, F32 camera_height_above_water); - -#if LL_DARWIN - typedef S32 MIXBUFFERFORMAT; -#else - typedef S16 MIXBUFFERFORMAT; -#endif - -protected: - /*virtual*/ LLAudioBuffer *createBuffer(); // Get a free buffer, or flush an existing one if you have to. - /*virtual*/ LLAudioChannel *createChannel(); // Create a new audio channel. - - /*virtual*/ void setInternalGain(F32 gain); -protected: - static signed char F_CALLBACKAPI callbackMetaData(char* name, char* value, void* userdata); - - //F32 mMinDistance[MAX_BUFFERS]; - //F32 mMaxDistance[MAX_BUFFERS]; - - bool mInited; - - // On Windows, userdata is the HWND of the application window. - void* mUserData; - - LLWindGen *mWindGen; - FSOUND_DSPUNIT *mWindDSP; -}; - - -class LLAudioChannelFMOD : public LLAudioChannel -{ -public: - LLAudioChannelFMOD(); - virtual ~LLAudioChannelFMOD(); - -protected: - /*virtual*/ void play(); - /*virtual*/ void playSynced(LLAudioChannel *channelp); - /*virtual*/ void cleanup(); - /*virtual*/ bool isPlaying(); - - /*virtual*/ bool updateBuffer(); - /*virtual*/ void update3DPosition(); - /*virtual*/ void updateLoop(); - -protected: - int mChannelID; - S32 mLastSamplePos; -}; - - -class LLAudioBufferFMOD : public LLAudioBuffer -{ -public: - LLAudioBufferFMOD(); - virtual ~LLAudioBufferFMOD(); - - /*virtual*/ bool loadWAV(const std::string& filename); - /*virtual*/ U32 getLength(); - friend class LLAudioChannelFMOD; - - void set3DMode(bool use3d); -protected: - FSOUND_SAMPLE *getSample() { return mSamplep; } -protected: - FSOUND_SAMPLE *mSamplep; -}; - - -#endif // LL_AUDIOENGINE_FMOD_H diff --git a/indra/llaudio/llaudioengine_fmodex.cpp b/indra/llaudio/llaudioengine_fmodex.cpp deleted file mode 100644 index bfdda0957a..0000000000 --- a/indra/llaudio/llaudioengine_fmodex.cpp +++ /dev/null @@ -1,1037 +0,0 @@ -/** - * @file audioengine_FMODEX.cpp - * @brief Implementation of LLAudioEngine class abstracting the audio support as a FMOD 3D implementation - * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include "llstreamingaudio.h" -#include "llstreamingaudio_fmodex.h" - -#include "llaudioengine_fmodex.h" -#include "lllistener_fmodex.h" - -#include "llerror.h" -#include "llmath.h" -#include "llrand.h" - -#include "fmod.hpp" -#include "fmod_errors.h" -#include "lldir.h" -#include "llapr.h" - -#include "sound_ids.h" - -#if LL_WINDOWS //Some ugly code to make missing fmodex.dll not cause a fatal error. -#define WIN32_LEAN_AND_MEAN -#include "windows.h" -#include -#pragma comment(lib, "delayimp.lib") - -bool attemptDelayLoad() -{ - __try - { - if( FAILED( __HrLoadAllImportsForDll( "fmodex.dll" ) ) ) - return false; - } - __except( EXCEPTION_EXECUTE_HANDLER ) - { - return false; - } - return true; -} -#endif - -static bool sVerboseDebugging = false; - -FMOD_RESULT F_CALLBACK windCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int outchannels); - -FMOD::ChannelGroup *LLAudioEngine_FMODEX::mChannelGroups[LLAudioEngine::AUDIO_TYPE_COUNT] = {0}; - -//This class is designed to keep track of all sound<->channel assocations. -//Used to verify validity of sound and channel pointers, as well as catch cases were sounds -//are released with active channels still attached. -class CFMODSoundChecks -{ - typedef std::map > active_sounds_t; - typedef std::set dead_sounds_t; - typedef std::map active_channels_t; - typedef std::map dead_channels_t; - - active_sounds_t mActiveSounds; - dead_sounds_t mDeadSounds; - active_channels_t mActiveChannels; - dead_channels_t mDeadChannels; -public: - enum STATUS - { - ACTIVE, - DEAD, - UNKNOWN - }; - STATUS getPtrStatus(LLAudioChannelFMODEX* channel) - { - if(!channel) - return UNKNOWN; - return getPtrStatus(channel->mChannelp); - } - STATUS getPtrStatus(LLAudioBufferFMODEX* sound) - { - if(!sound) - return UNKNOWN; - return getPtrStatus(sound->mSoundp); - } - STATUS getPtrStatus(FMOD::Channel* channel) - { - if(!channel) - return UNKNOWN; - else if(mActiveChannels.find(channel) != mActiveChannels.end()) - return ACTIVE; - else if(mDeadChannels.find(channel) != mDeadChannels.end()) - return DEAD; - return UNKNOWN; - } - STATUS getPtrStatus(FMOD::Sound* sound) - { - if(!sound) - return UNKNOWN; - if(mActiveSounds.find(sound) != mActiveSounds.end()) - return ACTIVE; - else if(mDeadSounds.find(sound) != mDeadSounds.end()) - return DEAD; - return UNKNOWN; - } - void addNewSound(FMOD::Sound* sound) - { - llassert(getPtrStatus(sound) != ACTIVE); - - mDeadSounds.erase(sound); - mActiveSounds.insert(std::make_pair(sound,std::set())); - } - void removeSound(FMOD::Sound* sound) - { -#ifdef SHOW_ASSERT - STATUS status = getPtrStatus(sound); - llassert(status != DEAD); - llassert(status != UNKNOWN); -#endif - - active_sounds_t::const_iterator it = mActiveSounds.find(sound); - llassert(it != mActiveSounds.end()); - if(it != mActiveSounds.end()) - { - if(!it->second.empty()) - { -#ifdef LL_RELEASE_FOR_DOWNLOAD - LL_WARNS("AudioImpl") << "Removing sound " << sound << " with attached channels: \n"; -#else - LL_ERRS("AudioImpl") << "Removing sound " << sound << " with attached channels: \n"; -#endif - for(std::set::iterator it2 = it->second.begin(); it2 != it->second.end();++it2) - { - switch(getPtrStatus(*it2)) - { - case ACTIVE: - llcont << " Channel " << *it2 << " ACTIVE\n"; - break; - case DEAD: - llcont << " Channel " << *it2 << " DEAD\n"; - break; - default: - llcont << " Channel " << *it2 << " UNKNOWN\n"; - } - } - llcont << llendl; - } - mDeadSounds.insert(sound); - mActiveSounds.erase(sound); - } - } - void addNewChannelToSound(FMOD::Sound* sound,FMOD::Channel* channel) - { - STATUS status = getPtrStatus(sound); - llassert(status != DEAD); - llassert(status != UNKNOWN); - status = getPtrStatus(channel); - llassert(status != ACTIVE); - - mActiveSounds[sound].insert(channel); - mActiveChannels.insert(std::make_pair(channel,sound)); - } - void removeChannel(FMOD::Channel* channel) - { -#ifdef SHOW_ASSERT - STATUS status = getPtrStatus(channel); - llassert(status != DEAD); - llassert(status != UNKNOWN); -#endif - - active_channels_t::const_iterator it = mActiveChannels.find(channel); - llassert(it != mActiveChannels.end()); - if(it != mActiveChannels.end()) - { -#ifdef SHOW_ASSERT - STATUS status = getPtrStatus(it->second); - llassert(status != DEAD); - llassert(status != UNKNOWN); -#endif - - active_sounds_t::iterator it2 = mActiveSounds.find(it->second); - llassert(it2 != mActiveSounds.end()); - if(it2 != mActiveSounds.end()) - { - it2->second.erase(channel); - } - mDeadChannels.insert(*it); - mActiveChannels.erase(channel); - } - } -} gSoundCheck; - -bool isActive(LLAudioChannel* channel) -{ - return gSoundCheck.getPtrStatus(dynamic_cast(channel)) == CFMODSoundChecks::ACTIVE; -} -bool isActive(LLAudioBuffer* sound) -{ - return gSoundCheck.getPtrStatus(dynamic_cast(sound)) == CFMODSoundChecks::ACTIVE; -} - -#define CHECK_PTR(ptr) \ - if(sVerboseDebugging){\ - CFMODSoundChecks::STATUS chan = gSoundCheck.getPtrStatus(ptr); \ - if(chan == CFMODSoundChecks::DEAD) \ - LL_DEBUGS("AudioImpl") << __FUNCTION__ << ": Using dead " << typeid(ptr).name() << " " << ptr << llendl; \ - else if(chan == CFMODSoundChecks::UNKNOWN) \ - LL_DEBUGS("AudioImpl") << __FUNCTION__ << ": Using unknown " << typeid(ptr).name() << " " << ptr << llendl;} \ - -LLAudioEngine_FMODEX::LLAudioEngine_FMODEX(bool enable_profiler, bool verbose_debugging) -{ - sVerboseDebugging = verbose_debugging; - mInited = false; - mWindGen = NULL; - mWindDSP = NULL; - mSystem = NULL; - mEnableProfiler = enable_profiler; -} - - -LLAudioEngine_FMODEX::~LLAudioEngine_FMODEX() -{ -} - - -inline bool Check_FMOD_Error(FMOD_RESULT result, const char *string) -{ - if(result == FMOD_OK) - return false; - LL_WARNS("AudioImpl") << string << " Error: " << FMOD_ErrorString(result) << llendl; - return true; -} - -void* F_STDCALL decode_alloc(unsigned int size, FMOD_MEMORY_TYPE type, const char *sourcestr) -{ - if(type & FMOD_MEMORY_STREAM_DECODE) - { - LL_INFOS("AudioImpl") << "Decode buffer size: " << size << llendl; - } - else if(type & FMOD_MEMORY_STREAM_FILE) - { - LL_INFOS("AudioImpl") << "Stream buffer size: " << size << llendl; - } - return new char[size]; -} -void* F_STDCALL decode_realloc(void *ptr, unsigned int size, FMOD_MEMORY_TYPE type, const char *sourcestr) -{ - memset(ptr,0,size); - return ptr; -} -void F_STDCALL decode_dealloc(void *ptr, FMOD_MEMORY_TYPE type, const char *sourcestr) -{ - delete[] (char*)ptr; -} - -bool LLAudioEngine_FMODEX::init(const S32 num_channels, void* userdata) -{ - -#if LL_WINDOWS - if(!attemptDelayLoad()) - return false; -#endif - - U32 version; - FMOD_RESULT result; - - LL_DEBUGS("AppInit") << "LLAudioEngine_FMODEX::init() initializing FMOD" << LL_ENDL; - - //result = FMOD::Memory_Initialize(NULL, 0, &decode_alloc, &decode_realloc, &decode_dealloc, FMOD_MEMORY_STREAM_DECODE | FMOD_MEMORY_STREAM_FILE); - //if(Check_FMOD_Error(result, "FMOD::Memory_Initialize")) - // return false; - - result = FMOD::System_Create(&mSystem); - if(Check_FMOD_Error(result, "FMOD::System_Create")) - return false; - - //will call LLAudioEngine_FMODEX::allocateListener, which needs a valid mSystem pointer. - LLAudioEngine::init(num_channels, userdata); - - result = mSystem->getVersion(&version); - Check_FMOD_Error(result, "FMOD::System::getVersion"); - - if (version < FMOD_VERSION) - { - LL_WARNS("AppInit") << "Error : You are using the wrong FMOD Ex version (" << version - << ")! You should be using FMOD Ex" << FMOD_VERSION << LL_ENDL; - } - -// result = mSystem->setSoftwareFormat(44100, FMOD_SOUND_FORMAT_PCM16, 0, 0, FMOD_DSP_RESAMPLER_LINEAR); -// Check_FMOD_Error(result,"FMOD::System::setSoftwareFormat"); - - // In this case, all sounds, PLUS wind and stream will be software. - result = mSystem->setSoftwareChannels(num_channels + 2); - Check_FMOD_Error(result,"FMOD::System::setSoftwareChannels"); - - U32 fmod_flags = FMOD_INIT_NORMAL; - if(mEnableProfiler) - { - fmod_flags |= FMOD_INIT_ENABLE_PROFILE; - mSystem->createChannelGroup("None", &mChannelGroups[AUDIO_TYPE_NONE]); - mSystem->createChannelGroup("SFX", &mChannelGroups[AUDIO_TYPE_SFX]); - mSystem->createChannelGroup("UI", &mChannelGroups[AUDIO_TYPE_UI]); - mSystem->createChannelGroup("Ambient", &mChannelGroups[AUDIO_TYPE_AMBIENT]); - } - -#if LL_LINUX - bool audio_ok = false; - - if (!audio_ok) - { - if (NULL == getenv("LL_BAD_FMOD_PULSEAUDIO")) /*Flawfinder: ignore*/ - { - LL_DEBUGS("AppInit") << "Trying PulseAudio audio output..." << LL_ENDL; - if(mSystem->setOutput(FMOD_OUTPUTTYPE_PULSEAUDIO) == FMOD_OK && - (result = mSystem->init(num_channels + 2, fmod_flags, 0)) == FMOD_OK) - { - LL_DEBUGS("AppInit") << "PulseAudio output initialized OKAY" << LL_ENDL; - audio_ok = true; - } - else - { - Check_FMOD_Error(result, "PulseAudio audio output FAILED to initialize"); - } - } - else - { - LL_DEBUGS("AppInit") << "PulseAudio audio output SKIPPED" << LL_ENDL; - } - } - if (!audio_ok) - { - if (NULL == getenv("LL_BAD_FMOD_ALSA")) /*Flawfinder: ignore*/ - { - LL_DEBUGS("AppInit") << "Trying ALSA audio output..." << LL_ENDL; - if(mSystem->setOutput(FMOD_OUTPUTTYPE_ALSA) == FMOD_OK && - (result = mSystem->init(num_channels + 2, fmod_flags, 0)) == FMOD_OK) - { - LL_DEBUGS("AppInit") << "ALSA audio output initialized OKAY" << LL_ENDL; - audio_ok = true; - } - else - { - Check_FMOD_Error(result, "ALSA audio output FAILED to initialize"); - } - } - else - { - LL_DEBUGS("AppInit") << "ALSA audio output SKIPPED" << LL_ENDL; - } - } - if (!audio_ok) - { - if (NULL == getenv("LL_BAD_FMOD_OSS")) /*Flawfinder: ignore*/ - { - LL_DEBUGS("AppInit") << "Trying OSS audio output..." << LL_ENDL; - if(mSystem->setOutput(FMOD_OUTPUTTYPE_OSS) == FMOD_OK && - (result = mSystem->init(num_channels + 2, fmod_flags, 0)) == FMOD_OK) - { - LL_DEBUGS("AppInit") << "OSS audio output initialized OKAY" << LL_ENDL; - audio_ok = true; - } - else - { - Check_FMOD_Error(result, "OSS audio output FAILED to initialize"); - } - } - else - { - LL_DEBUGS("AppInit") << "OSS audio output SKIPPED" << LL_ENDL; - } - } - if (!audio_ok) - { - LL_WARNS("AppInit") << "Overall audio init failure." << LL_ENDL; - return false; - } - - // We're interested in logging which output method we - // ended up with, for QA purposes. - FMOD_OUTPUTTYPE output_type; - mSystem->getOutput(&output_type); - switch (output_type) - { - case FMOD_OUTPUTTYPE_NOSOUND: - LL_INFOS("AppInit") << "Audio output: NoSound" << LL_ENDL; break; - case FMOD_OUTPUTTYPE_PULSEAUDIO: - LL_INFOS("AppInit") << "Audio output: PulseAudio" << LL_ENDL; break; - case FMOD_OUTPUTTYPE_ALSA: - LL_INFOS("AppInit") << "Audio output: ALSA" << LL_ENDL; break; - case FMOD_OUTPUTTYPE_OSS: - LL_INFOS("AppInit") << "Audio output: OSS" << LL_ENDL; break; - default: - LL_INFOS("AppInit") << "Audio output: Unknown!" << LL_ENDL; break; - }; -#else // LL_LINUX - - // initialize the FMOD engine - result = mSystem->init( num_channels + 2, fmod_flags, 0); - if (result == FMOD_ERR_OUTPUT_CREATEBUFFER) - { - /* - Ok, the speaker mode selected isn't supported by this soundcard. Switch it - back to stereo... - */ - result = mSystem->setSpeakerMode(FMOD_SPEAKERMODE_STEREO); - Check_FMOD_Error(result,"Error falling back to stereo mode"); - /* - ... and re-init. - */ - result = mSystem->init( num_channels + 2, fmod_flags, 0); - } - if(Check_FMOD_Error(result, "Error initializing FMOD Ex")) - return false; -#endif - - // set up our favourite FMOD-native streaming audio implementation if none has already been added - if (!getStreamingAudioImpl()) // no existing implementation added - setStreamingAudioImpl(new LLStreamingAudio_FMODEX(mSystem)); - - LL_INFOS("AppInit") << "LLAudioEngine_FMODEX::init() FMOD Ex initialized correctly" << LL_ENDL; - - int r_numbuffers, r_samplerate, r_channels, r_bits; - unsigned int r_bufferlength; - char r_name[256]; - FMOD_SPEAKERMODE speaker_mode; - mSystem->getDSPBufferSize(&r_bufferlength, &r_numbuffers); - mSystem->getSoftwareFormat(&r_samplerate, NULL, &r_channels, NULL, NULL, &r_bits); - mSystem->getDriverInfo(0, r_name, 255, 0); - mSystem->getSpeakerMode(&speaker_mode); - std::string speaker_mode_str = "unknown"; - switch(speaker_mode) - { - #define SPEAKER_MODE_CASE(MODE) case MODE: speaker_mode_str = #MODE; break; - SPEAKER_MODE_CASE(FMOD_SPEAKERMODE_RAW) - SPEAKER_MODE_CASE(FMOD_SPEAKERMODE_MONO) - SPEAKER_MODE_CASE(FMOD_SPEAKERMODE_STEREO) - SPEAKER_MODE_CASE(FMOD_SPEAKERMODE_QUAD) - SPEAKER_MODE_CASE(FMOD_SPEAKERMODE_SURROUND) - SPEAKER_MODE_CASE(FMOD_SPEAKERMODE_5POINT1) - SPEAKER_MODE_CASE(FMOD_SPEAKERMODE_7POINT1) - SPEAKER_MODE_CASE(FMOD_SPEAKERMODE_SRS5_1_MATRIX) - SPEAKER_MODE_CASE(FMOD_SPEAKERMODE_MYEARS) - default:; - #undef SPEAKER_MODE_CASE - } - - r_name[255] = '\0'; - int latency = 1000.0 * r_bufferlength * r_numbuffers /r_samplerate; - - LL_INFOS("AppInit") << "FMOD device: "<< r_name << "\n" - << "Output mode: "<< speaker_mode_str << "\n" - << "FMOD Ex parameters: " << r_samplerate << " Hz * " << r_channels << " * " <getVersion(&version), "FMOD::System::getVersion")) - { - return llformat("FMOD Ex %1x.%02x.%02x", version >> 16, version >> 8 & 0x000000FF, version & 0x000000FF); - } - } - return "FMODEx"; -} - - -void LLAudioEngine_FMODEX::allocateListener(void) -{ - mListenerp = (LLListener *) new LLListener_FMODEX(mSystem); - if (!mListenerp) - { - LL_WARNS("AudioImpl") << "Listener creation failed" << llendl; - } -} - - -void LLAudioEngine_FMODEX::shutdown() -{ - stopInternetStream(); - - LL_INFOS("AudioImpl") << "About to LLAudioEngine::shutdown()" << llendl; - LLAudioEngine::shutdown(); - - LL_INFOS("AudioImpl") << "LLAudioEngine_FMODEX::shutdown() closing FMOD Ex" << llendl; - if ( mSystem ) // speculative fix for MAINT-2657 - { - mSystem->close(); - mSystem->release(); - } - LL_INFOS("AudioImpl") << "LLAudioEngine_FMODEX::shutdown() done closing FMOD Ex" << llendl; - - delete mListenerp; - mListenerp = NULL; -} - - -LLAudioBuffer * LLAudioEngine_FMODEX::createBuffer() -{ - return new LLAudioBufferFMODEX(mSystem); -} - - -LLAudioChannel * LLAudioEngine_FMODEX::createChannel() -{ - return new LLAudioChannelFMODEX(mSystem); -} - -bool LLAudioEngine_FMODEX::initWind() -{ - mNextWindUpdate = 0.0; - - if (!mWindDSP) - { - FMOD_DSP_DESCRIPTION dspdesc; - memset(&dspdesc, 0, sizeof(FMOD_DSP_DESCRIPTION)); //Set everything to zero - strncpy(dspdesc.name,"Wind Unit", sizeof(dspdesc.name)); //Set name to "Wind Unit" - dspdesc.channels=2; - dspdesc.read = &windCallback; //Assign callback. - if(Check_FMOD_Error(mSystem->createDSP(&dspdesc, &mWindDSP), "FMOD::createDSP")) - return false; - - if(mWindGen) - delete mWindGen; - - float frequency = 44100; - mWindDSP->getDefaults(&frequency,0,0,0); - mWindGen = new LLWindGen((U32)frequency); - mWindDSP->setUserData((void*)mWindGen); - } - - if (mWindDSP) - { - mSystem->playDSP(FMOD_CHANNEL_FREE, mWindDSP, false, 0); - return true; - } - return false; -} - - -void LLAudioEngine_FMODEX::cleanupWind() -{ - if (mWindDSP) - { - mWindDSP->remove(); - mWindDSP->release(); - mWindDSP = NULL; - } - - delete mWindGen; - mWindGen = NULL; -} - - -//----------------------------------------------------------------------- -void LLAudioEngine_FMODEX::updateWind(LLVector3 wind_vec, F32 camera_height_above_water) -{ - LLVector3 wind_pos; - F64 pitch; - F64 center_freq; - - if (!mEnableWind) - { - return; - } - - if (mWindUpdateTimer.checkExpirationAndReset(LL_WIND_UPDATE_INTERVAL)) - { - - // wind comes in as Linden coordinate (+X = forward, +Y = left, +Z = up) - // need to convert this to the conventional orientation DS3D and OpenAL use - // where +X = right, +Y = up, +Z = backwards - - wind_vec.setVec(-wind_vec.mV[1], wind_vec.mV[2], -wind_vec.mV[0]); - - // cerr << "Wind update" << endl; - - pitch = 1.0 + mapWindVecToPitch(wind_vec); - center_freq = 80.0 * pow(pitch,2.5*(mapWindVecToGain(wind_vec)+1.0)); - - mWindGen->mTargetFreq = (F32)center_freq; - mWindGen->mTargetGain = (F32)mapWindVecToGain(wind_vec) * mMaxWindGain; - mWindGen->mTargetPanGainR = (F32)mapWindVecToPan(wind_vec); - } -} - -//----------------------------------------------------------------------- -void LLAudioEngine_FMODEX::setInternalGain(F32 gain) -{ - if (!mInited) - { - return; - } - - gain = llclamp( gain, 0.0f, 1.0f ); - - FMOD::ChannelGroup *master_group; - mSystem->getMasterChannelGroup(&master_group); - - master_group->setVolume(gain); - - LLStreamingAudioInterface *saimpl = getStreamingAudioImpl(); - if ( saimpl ) - { - // fmod likes its streaming audio channel gain re-asserted after - // master volume change. - saimpl->setGain(saimpl->getGain()); - } -} - -// -// LLAudioChannelFMODEX implementation -// - -LLAudioChannelFMODEX::LLAudioChannelFMODEX(FMOD::System *system) : LLAudioChannel(), mSystemp(system), mChannelp(NULL), mLastSamplePos(0) -{ -} - - -LLAudioChannelFMODEX::~LLAudioChannelFMODEX() -{ - if(sVerboseDebugging) - LL_DEBUGS("AudioImpl") << "Destructing Audio Channel. mChannelp = " << mChannelp << llendl; - - cleanup(); -} - -static FMOD_RESULT F_CALLBACK channel_callback(FMOD_CHANNEL *channel, FMOD_CHANNEL_CALLBACKTYPE type, void *commanddata1, void *commanddata2) -{ - if(type == FMOD_CHANNEL_CALLBACKTYPE_END) - { - FMOD::Channel* chan = reinterpret_cast(channel); - LLAudioChannelFMODEX* audio_channel = NULL; - chan->getUserData((void**)&audio_channel); - if(audio_channel) - { - audio_channel->onRelease(); - } - } - return FMOD_OK; -} - -void LLAudioChannelFMODEX::onRelease() -{ - llassert(mChannelp); - if(sVerboseDebugging) - LL_DEBUGS("AudioImpl") << "Fmod signaled channel release for channel " << mChannelp << llendl; - gSoundCheck.removeChannel(mChannelp); - mChannelp = NULL; //Null out channel here so cleanup doesn't try to redundantly stop it. - cleanup(); -} - -bool LLAudioChannelFMODEX::updateBuffer() -{ - if (LLAudioChannel::updateBuffer()) - { - // Base class update returned true, which means that we need to actually - // set up the channel for a different buffer. - - LLAudioBufferFMODEX *bufferp = (LLAudioBufferFMODEX *)mCurrentSourcep->getCurrentBuffer(); - - llassert(mCurrentBufferp != NULL); - llassert(mCurrentBufferp == bufferp); - - // Grab the FMOD sample associated with the buffer - FMOD::Sound *soundp = bufferp->getSound(); - if (!soundp) - { - // This is bad, there should ALWAYS be a sound associated with a legit - // buffer. - LL_ERRS("AudioImpl") << "No FMOD sound!" << llendl; - return false; - } - - - // Actually play the sound. Start it off paused so we can do all the necessary - // setup. - if(!mChannelp) - { - llassert(!isActive(this)); - - FMOD_RESULT result = getSystem()->playSound(FMOD_CHANNEL_FREE, soundp, true, &mChannelp); - Check_FMOD_Error(result, "FMOD::System::playSound"); - if(result == FMOD_OK) - { - if(sVerboseDebugging) - LL_DEBUGS("AudioImpl") << "Created channel " << mChannelp << " for sound " << soundp << llendl; - - gSoundCheck.addNewChannelToSound(soundp,mChannelp); - mChannelp->setCallback(&channel_callback); - mChannelp->setUserData(this); - llassert(isActive(this)); - } - } - } - - // If we have a source for the channel, we need to update its gain. - if (mCurrentSourcep && mChannelp) - { - // SJB: warnings can spam and hurt framerate, disabling - FMOD_RESULT result; - - CHECK_PTR(mChannelp); - - result = mChannelp->setVolume(getSecondaryGain() * mCurrentSourcep->getGain()); - Check_FMOD_Error(result, "FMOD::Channel::setVolume"); - result = mChannelp->setMode(mCurrentSourcep->isLoop() ? FMOD_LOOP_NORMAL : FMOD_LOOP_OFF); - Check_FMOD_Error(result, "FMOD::Channel::setMode"); - } - - return true; -} - - -void LLAudioChannelFMODEX::update3DPosition() -{ - if (!mChannelp) - { - // We're not actually a live channel (i.e., we're not playing back anything) - return; - } - - LLAudioBufferFMODEX *bufferp = (LLAudioBufferFMODEX *)mCurrentBufferp; - if (!bufferp) - { - // We don't have a buffer associated with us (should really have been picked up - // by the above if. - return; - } - - CHECK_PTR(mChannelp); - - if (mCurrentSourcep->isAmbient()) - { - // Ambient sound, don't need to do any positional updates. - set3DMode(false); - } - else - { - // Localized sound. Update the position and velocity of the sound. - set3DMode(true); - - LLVector3 float_pos; - float_pos.setVec(mCurrentSourcep->getPositionGlobal()); - FMOD_RESULT result = mChannelp->set3DAttributes((FMOD_VECTOR*)float_pos.mV, (FMOD_VECTOR*)mCurrentSourcep->getVelocity().mV); - Check_FMOD_Error(result, "FMOD::Channel::set3DAttributes"); - } -} - - -void LLAudioChannelFMODEX::updateLoop() -{ - if (!mChannelp) - { - // May want to clear up the loop/sample counters. - return; - } - - CHECK_PTR(mChannelp); - - // - // Hack: We keep track of whether we looped or not by seeing when the - // sample position looks like it's going backwards. Not reliable; may - // yield false negatives. - // - U32 cur_pos; - Check_FMOD_Error(mChannelp->getPosition(&cur_pos,FMOD_TIMEUNIT_PCMBYTES),"FMOD::Channel::getPosition"); - - if (cur_pos < (U32)mLastSamplePos) - { - mLoopedThisFrame = true; - } - mLastSamplePos = cur_pos; -} - - -void LLAudioChannelFMODEX::cleanup() -{ - LLAudioChannel::cleanup(); - - if (!mChannelp) - { - llassert(!isActive(this)); - llassert(mCurrentBufferp == NULL); - //llinfos << "Aborting cleanup with no channel handle." << llendl; - return; - } - - CHECK_PTR(mChannelp); - - if(sVerboseDebugging) - LL_DEBUGS("AudioImpl") << "Stopping channel " << mChannelp << llendl; - - mChannelp->setCallback(NULL); - if(!Check_FMOD_Error(mChannelp->stop(),"FMOD::Channel::stop")) - { - gSoundCheck.removeChannel(mChannelp); - } - - mChannelp = NULL; - llassert(!isActive(this)); - -} - - -void LLAudioChannelFMODEX::play() -{ - if (!mChannelp) - { - LL_WARNS("AudioImpl") << "Playing without a channel handle, aborting" << llendl; - return; - } - - llassert(isActive(this)); - - CHECK_PTR(mChannelp); - - Check_FMOD_Error(mChannelp->setPaused(false), "FMOD::Channel::setPaused"); - - if(sVerboseDebugging) - LL_DEBUGS("AudioImpl") << "Playing channel " << mChannelp << llendl; - - getSource()->setPlayedOnce(true); - - if(LLAudioEngine_FMODEX::mChannelGroups[getSource()->getType()]) - Check_FMOD_Error(mChannelp->setChannelGroup(LLAudioEngine_FMODEX::mChannelGroups[getSource()->getType()]),"FMOD::Channel::setChannelGroup"); -} - - -void LLAudioChannelFMODEX::playSynced(LLAudioChannel *channelp) -{ - LLAudioChannelFMODEX *fmod_channelp = (LLAudioChannelFMODEX*)channelp; - if (!(fmod_channelp->mChannelp && mChannelp)) - { - // Don't have channels allocated to both the master and the slave - return; - } - - CHECK_PTR(mChannelp); - - U32 cur_pos; - if(Check_FMOD_Error(mChannelp->getPosition(&cur_pos,FMOD_TIMEUNIT_PCMBYTES), "Unable to retrieve current position")) - return; - - cur_pos %= mCurrentBufferp->getLength(); - - // Try to match the position of our sync master - Check_FMOD_Error(mChannelp->setPosition(cur_pos,FMOD_TIMEUNIT_PCMBYTES),"Unable to set current position"); - - // Start us playing - play(); -} - - -bool LLAudioChannelFMODEX::isPlaying() -{ - if (!mChannelp) - { - return false; - } - - CHECK_PTR(mChannelp); - - bool paused, playing; - Check_FMOD_Error(mChannelp->getPaused(&paused),"FMOD::Channel::getPaused"); - Check_FMOD_Error(mChannelp->isPlaying(&playing),"FMOD::Channel::isPlaying"); - return !paused && playing; -} - - -// -// LLAudioChannelFMODEX implementation -// - - -LLAudioBufferFMODEX::LLAudioBufferFMODEX(FMOD::System *system) : LLAudioBuffer(), mSystemp(system), mSoundp(NULL) -{ -} - - -LLAudioBufferFMODEX::~LLAudioBufferFMODEX() -{ - if(mSoundp) - { - if(sVerboseDebugging) - LL_DEBUGS("AudioImpl") << "Release sound " << mSoundp << llendl; - - CHECK_PTR(mSoundp); - Check_FMOD_Error(mSoundp->release(),"FMOD::Sound::Release"); - gSoundCheck.removeSound(mSoundp); - mSoundp = NULL; - } -} - - -bool LLAudioBufferFMODEX::loadWAV(const std::string& filename) -{ - // Try to open a wav file from disk. This will eventually go away, as we don't - // really want to block doing this. - if (filename.empty()) - { - // invalid filename, abort. - return false; - } - - if (!LLAPRFile::isExist(filename, LL_APR_RPB)) - { - // File not found, abort. - return false; - } - - if (mSoundp) - { - CHECK_PTR(mSoundp); - // If there's already something loaded in this buffer, clean it up. - Check_FMOD_Error(mSoundp->release(),"FMOD::Sound::release"); - gSoundCheck.removeSound(mSoundp); - mSoundp = NULL; - } - - FMOD_MODE base_mode = FMOD_LOOP_NORMAL | FMOD_SOFTWARE; - FMOD_CREATESOUNDEXINFO exinfo; - memset(&exinfo,0,sizeof(exinfo)); - exinfo.cbsize = sizeof(exinfo); - exinfo.suggestedsoundtype = FMOD_SOUND_TYPE_WAV; //Hint to speed up loading. - // Load up the wav file into an fmod sample -#if LL_WINDOWS - FMOD_RESULT result = getSystem()->createSound((const char*)utf8str_to_utf16str(filename).c_str(), base_mode | FMOD_UNICODE, &exinfo, &mSoundp); -#else - FMOD_RESULT result = getSystem()->createSound(filename.c_str(), base_mode, &exinfo, &mSoundp); -#endif - - if (result != FMOD_OK) - { - // We failed to load the file for some reason. - LL_WARNS("AudioImpl") << "Could not load data '" << filename << "': " << FMOD_ErrorString(result) << llendl; - - // - // If we EVER want to load wav files provided by end users, we need - // to rethink this! - // - // file is probably corrupt - remove it. - LLFile::remove(filename); - return false; - } - - gSoundCheck.addNewSound(mSoundp); - - // Everything went well, return true - return true; -} - - -U32 LLAudioBufferFMODEX::getLength() -{ - if (!mSoundp) - { - return 0; - } - - CHECK_PTR(mSoundp); - U32 length; - Check_FMOD_Error(mSoundp->getLength(&length, FMOD_TIMEUNIT_PCMBYTES),"FMOD::Sound::getLength"); - return length; -} - - -void LLAudioChannelFMODEX::set3DMode(bool use3d) -{ - CHECK_PTR(mChannelp); - - FMOD_MODE current_mode; - if(Check_FMOD_Error(mChannelp->getMode(¤t_mode),"FMOD::Channel::getMode")) - return; - FMOD_MODE new_mode = current_mode; - new_mode &= ~(use3d ? FMOD_2D : FMOD_3D); - new_mode |= use3d ? FMOD_3D : FMOD_2D; - - if(current_mode != new_mode) - { - Check_FMOD_Error(mChannelp->setMode(new_mode),"FMOD::Channel::setMode"); - } -} - - -FMOD_RESULT F_CALLBACK windCallback(FMOD_DSP_STATE *dsp_state, float *originalbuffer, float *newbuffer, unsigned int length, int inchannels, int outchannels) -{ - // originalbuffer = fmod's original mixbuffer. - // newbuffer = the buffer passed from the previous DSP unit. - // length = length in samples at this mix time. - // userdata = user parameter passed through in FSOUND_DSP_Create. - - LLWindGen *windgen; - FMOD::DSP *thisdsp = (FMOD::DSP *)dsp_state->instance; - - thisdsp->getUserData((void **)&windgen); - S32 channels, configwidth, configheight; - thisdsp->getInfo(0, 0, &channels, &configwidth, &configheight); - - windgen->windGenerate((LLAudioEngine_FMODEX::MIXBUFFERFORMAT *)newbuffer, length); - - return FMOD_OK; -} diff --git a/indra/llaudio/llaudioengine_fmodex.h b/indra/llaudio/llaudioengine_fmodex.h deleted file mode 100644 index 18b4d61a87..0000000000 --- a/indra/llaudio/llaudioengine_fmodex.h +++ /dev/null @@ -1,139 +0,0 @@ -/** - * @file audioengine_FMODEX.h - * @brief Definition of LLAudioEngine class abstracting the audio - * support as a FMOD 3D implementation - * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifndef LL_AUDIOENGINE_FMODEX_H -#define LL_AUDIOENGINE_FMODEX_H - -#include "llaudioengine.h" -#include "lllistener_fmod.h" -#include "llwindgen.h" - -//Stubs -class LLAudioStreamManagerFMODEX; -namespace FMOD -{ - class System; - class Channel; - class ChannelGroup; - class Sound; - class DSP; -} - -//Interfaces -class LLAudioEngine_FMODEX : public LLAudioEngine -{ -public: - LLAudioEngine_FMODEX(bool enable_profiler, bool verbose_debugging); - virtual ~LLAudioEngine_FMODEX(); - - // initialization/startup/shutdown - virtual bool init(const S32 num_channels, void *user_data); - virtual std::string getDriverName(bool verbose); - virtual void allocateListener(); - - virtual void shutdown(); - - /*virtual*/ bool initWind(); - /*virtual*/ void cleanupWind(); - - /*virtual*/void updateWind(LLVector3 direction, F32 camera_height_above_water); - - typedef F32 MIXBUFFERFORMAT; - - FMOD::System *getSystem() const {return mSystem;} -protected: - /*virtual*/ LLAudioBuffer *createBuffer(); // Get a free buffer, or flush an existing one if you have to. - /*virtual*/ LLAudioChannel *createChannel(); // Create a new audio channel. - - /*virtual*/ void setInternalGain(F32 gain); - - bool mInited; - - LLWindGen *mWindGen; - - FMOD::DSP *mWindDSP; - FMOD::System *mSystem; - bool mEnableProfiler; - -public: - static FMOD::ChannelGroup *mChannelGroups[LLAudioEngine::AUDIO_TYPE_COUNT]; -}; - - -class LLAudioChannelFMODEX : public LLAudioChannel -{ -public: - LLAudioChannelFMODEX(FMOD::System *audioengine); - virtual ~LLAudioChannelFMODEX(); - void onRelease(); -protected: - /*virtual*/ void play(); - /*virtual*/ void playSynced(LLAudioChannel *channelp); - /*virtual*/ void cleanup(); - /*virtual*/ bool isPlaying(); - - /*virtual*/ bool updateBuffer(); - /*virtual*/ void update3DPosition(); - /*virtual*/ void updateLoop(); - - void set3DMode(bool use3d); -protected: - FMOD::System *getSystem() const {return mSystemp;} - FMOD::System *mSystemp; - FMOD::Channel *mChannelp; - S32 mLastSamplePos; - - friend class CFMODSoundChecks; -}; - - -class LLAudioBufferFMODEX : public LLAudioBuffer -{ -public: - LLAudioBufferFMODEX(FMOD::System *audioengine); - virtual ~LLAudioBufferFMODEX(); - - /*virtual*/ bool loadWAV(const std::string& filename); - /*virtual*/ U32 getLength(); - friend class LLAudioChannelFMODEX; -protected: - FMOD::System *getSystem() const {return mSystemp;} - FMOD::System *mSystemp; - FMOD::Sound *getSound() const{ return mSoundp; } - FMOD::Sound *mSoundp; - - friend class CFMODSoundChecks; -}; - - -#endif // LL_AUDIOENGINE_FMODEX_H diff --git a/indra/llaudio/llaudioengine_fmodstudio.cpp b/indra/llaudio/llaudioengine_fmodstudio.cpp new file mode 100644 index 0000000000..823f51cbf2 --- /dev/null +++ b/indra/llaudio/llaudioengine_fmodstudio.cpp @@ -0,0 +1,979 @@ +/** + * @file audioengine_fmodstudio.cpp + * @brief Implementation of LLAudioEngine class abstracting the audio support as a FMOD 3D implementation + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + * + * Copyright (c) 2002-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llstreamingaudio.h" +#include "llstreamingaudio_fmodstudio.h" + +#include "llaudioengine_fmodstudio.h" +#include "lllistener_fmodstudio.h" + +#include "llerror.h" +#include "llmath.h" +#include "llrand.h" + +#include "fmod.hpp" +#include "fmod_errors.h" +#include "lldir.h" + +#include "sound_ids.h" + +#include + +#if LL_WINDOWS //Some ugly code to make missing fmod.dll not cause a fatal error. +#define WIN32_LEAN_AND_MEAN +#include "windows.h" +#include +#pragma comment(lib, "delayimp.lib") + +bool attemptDelayLoad() +{ + __try + { +#if defined(_WIN64) + if( FAILED( __HrLoadAllImportsForDll( "fmod64.dll" ) ) ) + return false; +#else + if( FAILED( __HrLoadAllImportsForDll( "fmod.dll" ) ) ) + return false; +#endif + } + __except( EXCEPTION_EXECUTE_HANDLER ) + { + return false; + } + return true; +} +#endif + +static bool sVerboseDebugging = false; + +FMOD_RESULT F_CALLBACK windDSPCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int *outchannels); + +FMOD::ChannelGroup *LLAudioEngine_FMODSTUDIO::mChannelGroups[LLAudioEngine::AUDIO_TYPE_COUNT] = {0}; + +//This class is designed to keep track of all sound<->channel assocations. +//Used to verify validity of sound and channel pointers, as well as catch cases were sounds +//are released with active channels still attached. +class CFMODSoundChecks +{ + typedef std::map > active_sounds_t; + typedef std::set dead_sounds_t; + typedef std::map active_channels_t; + typedef std::map dead_channels_t; + + active_sounds_t mActiveSounds; + dead_sounds_t mDeadSounds; + active_channels_t mActiveChannels; + dead_channels_t mDeadChannels; +public: + enum STATUS + { + ACTIVE, + DEAD, + UNKNOWN + }; + STATUS getPtrStatus(LLAudioChannel* channel) + { + if(!channel) + return UNKNOWN; + return getPtrStatus(dynamic_cast(channel)->mChannelp); + } + STATUS getPtrStatus(LLAudioBuffer* sound) + { + if(!sound) + return UNKNOWN; + return getPtrStatus(dynamic_cast(sound)->mSoundp); + } + STATUS getPtrStatus(FMOD::Channel* channel) + { + if(!channel) + return UNKNOWN; + else if(mActiveChannels.find(channel) != mActiveChannels.end()) + return ACTIVE; + else if(mDeadChannels.find(channel) != mDeadChannels.end()) + return DEAD; + return UNKNOWN; + } + STATUS getPtrStatus(FMOD::Sound* sound) + { + if(!sound) + return UNKNOWN; + if(mActiveSounds.find(sound) != mActiveSounds.end()) + return ACTIVE; + else if(mDeadSounds.find(sound) != mDeadSounds.end()) + return DEAD; + return UNKNOWN; + } + void addNewSound(FMOD::Sound* sound) + { + assertActiveState(sound,true,false); + + mDeadSounds.erase(sound); + mActiveSounds.insert(std::make_pair(sound,std::set())); + } + void removeSound(FMOD::Sound* sound) + { + assertActiveState(sound,true); + + active_sounds_t::const_iterator it = mActiveSounds.find(sound); + llassert(it != mActiveSounds.end()); + if(it != mActiveSounds.end()) + { + if(!it->second.empty()) + { + LL_WARNS("AudioImpl") << "Removing sound " << sound << " with attached channels: \n"; + for(std::set::iterator it2 = it->second.begin(); it2 != it->second.end();++it2) + { + switch(getPtrStatus(*it2)) + { + case ACTIVE: + LL_CONT << " Channel " << *it2 << " ACTIVE\n"; + break; + case DEAD: + LL_CONT << " Channel " << *it2 << " DEAD\n"; + break; + default: + LL_CONT << " Channel " << *it2 << " UNKNOWN\n"; + } + } + LL_CONT << LL_ENDL; + } + llassert(it->second.empty()); + mDeadSounds.insert(sound); + mActiveSounds.erase(sound); + } + } + void addNewChannelToSound(FMOD::Sound* sound,FMOD::Channel* channel) + { + assertActiveState(sound,true); + assertActiveState(channel,true,false); + + mActiveSounds[sound].insert(channel); + mActiveChannels.insert(std::make_pair(channel,sound)); + } + void removeChannel(FMOD::Channel* channel) + { + assertActiveState(channel,true); + + active_channels_t::const_iterator it = mActiveChannels.find(channel); + llassert(it != mActiveChannels.end()); + if(it != mActiveChannels.end()) + { +#ifdef SHOW_ASSERT + STATUS status = getPtrStatus(it->second); + llassert(status != DEAD); + llassert(status != UNKNOWN); +#endif + + active_sounds_t::iterator it2 = mActiveSounds.find(it->second); + llassert(it2 != mActiveSounds.end()); + if(it2 != mActiveSounds.end()) + { + it2->second.erase(channel); + } + mDeadChannels.insert(*it); + mActiveChannels.erase(channel); + } + } + + template + void assertActiveState(T ptr, bool try_log=false, bool active=true) + { +#ifndef SHOW_ASSERT + if(try_log && sVerboseDebugging) +#endif + { + CFMODSoundChecks::STATUS chan = getPtrStatus(ptr); + if(try_log && sVerboseDebugging) + { + if(active) + { + if(chan == CFMODSoundChecks::DEAD) + LL_WARNS("AudioImpl") << __FUNCTION__ << ": Using unexpectedly dead " << typeid(T*).name() << " " << ptr << LL_ENDL; + else if(chan == CFMODSoundChecks::UNKNOWN) + LL_WARNS("AudioImpl") << __FUNCTION__ << ": Using unexpectedly unknown " << typeid(T*).name() << " " << ptr << LL_ENDL; + } + else if(chan == CFMODSoundChecks::ACTIVE) + LL_WARNS("AudioImpl") << __FUNCTION__ << ": Using unexpectedly active " << typeid(T*).name() << " " << ptr << LL_ENDL; + } + llassert( active == (chan == CFMODSoundChecks::ACTIVE) ); + } + } +} gSoundCheck; + +LLAudioEngine_FMODSTUDIO::LLAudioEngine_FMODSTUDIO(bool enable_profiler, bool verbose_debugging) + : mInited(false) + , mWindGen(NULL) + , mWindDSPDesc(NULL) + , mWindDSP(NULL) + , mSystem(NULL) + , mEnableProfiler(enable_profiler) +{ + sVerboseDebugging = verbose_debugging; +} + +LLAudioEngine_FMODSTUDIO::~LLAudioEngine_FMODSTUDIO() +{ +} + +inline bool Check_FMOD_Error(FMOD_RESULT result, const char *string) +{ + if(result == FMOD_OK) + return false; + LL_WARNS("AudioImpl") << string << " Error: " << FMOD_ErrorString(result) << LL_ENDL; + return true; +} + +bool LLAudioEngine_FMODSTUDIO::init(const S32 num_channels, void* userdata) +{ + LL_WARNS("AudioImpl") << "BARKBARKBARK" << LL_ENDL; +#if 0 //LL_WINDOWS + if(!attemptDelayLoad()) + return false; +#endif + + U32 version = 0; + + FMOD_RESULT result; + + LL_DEBUGS("AppInit") << "LLAudioEngine_FMODSTUDIO::init() initializing FMOD" << LL_ENDL; + + result = FMOD::System_Create(&mSystem); + if(Check_FMOD_Error(result, "FMOD::System_Create")) + return false; + + //will call LLAudioEngine_FMODSTUDIO::allocateListener, which needs a valid mSystem pointer. + LLAudioEngine::init(num_channels, userdata); + + result = mSystem->getVersion(&version); + Check_FMOD_Error(result, "FMOD::System::getVersion"); + + if (version < FMOD_VERSION) + { + LL_WARNS("AppInit") << "Error : You are using the wrong FMOD Studio version (" << version + << ")! You should be using FMOD Studio" << FMOD_VERSION << LL_ENDL; + } + + // In this case, all sounds, PLUS wind and stream will be software. + result = mSystem->setSoftwareChannels(num_channels + 2); + Check_FMOD_Error(result,"FMOD::System::setSoftwareChannels"); + + U32 fmod_flags = FMOD_INIT_NORMAL | FMOD_INIT_3D_RIGHTHANDED | FMOD_INIT_THREAD_UNSAFE; + if(mEnableProfiler) + { + fmod_flags |= FMOD_INIT_PROFILE_ENABLE; + } + +#if LL_LINUX + bool audio_ok = false; + + if (!audio_ok) + { + if (NULL == getenv("LL_BAD_FMOD_PULSEAUDIO")) /*Flawfinder: ignore*/ + { + LL_DEBUGS("AppInit") << "Trying PulseAudio audio output..." << LL_ENDL; + if((result = mSystem->setOutput(FMOD_OUTPUTTYPE_PULSEAUDIO)) == FMOD_OK && + (result = mSystem->init(num_channels + 2, fmod_flags, 0)) == FMOD_OK) + { + LL_DEBUGS("AppInit") << "PulseAudio output initialized OKAY" << LL_ENDL; + audio_ok = true; + } + else + { + Check_FMOD_Error(result, "PulseAudio audio output FAILED to initialize"); + } + } + else + { + LL_DEBUGS("AppInit") << "PulseAudio audio output SKIPPED" << LL_ENDL; + } + } + if (!audio_ok) + { + if (NULL == getenv("LL_BAD_FMOD_ALSA")) /*Flawfinder: ignore*/ + { + LL_DEBUGS("AppInit") << "Trying ALSA audio output..." << LL_ENDL; + if((result = mSystem->setOutput(FMOD_OUTPUTTYPE_ALSA)) == FMOD_OK && + (result = mSystem->init(num_channels + 2, fmod_flags, 0)) == FMOD_OK) + { + LL_DEBUGS("AppInit") << "ALSA audio output initialized OKAY" << LL_ENDL; + audio_ok = true; + } + else + { + Check_FMOD_Error(result, "ALSA audio output FAILED to initialize"); + } + } + else + { + LL_DEBUGS("AppInit") << "ALSA audio output SKIPPED" << LL_ENDL; + } + } + if (!audio_ok) + { + LL_WARNS("AppInit") << "Overall audio init failure." << LL_ENDL; + return false; + } + + // We're interested in logging which output method we + // ended up with, for QA purposes. + FMOD_OUTPUTTYPE output_type; + if(!Check_FMOD_Error(mSystem->getOutput(&output_type), "FMOD::System::getOutput")) + { + switch (output_type) + { + case FMOD_OUTPUTTYPE_NOSOUND: + LL_INFOS("AppInit") << "Audio output: NoSound" << LL_ENDL; break; + case FMOD_OUTPUTTYPE_PULSEAUDIO: + LL_INFOS("AppInit") << "Audio output: PulseAudio" << LL_ENDL; break; + case FMOD_OUTPUTTYPE_ALSA: + LL_INFOS("AppInit") << "Audio output: ALSA" << LL_ENDL; break; + default: + LL_INFOS("AppInit") << "Audio output: Unknown!" << LL_ENDL; break; + }; + } +#else // LL_LINUX + + // initialize the FMOD engine + result = mSystem->init( num_channels + 2, fmod_flags, 0); + if (result == FMOD_ERR_OUTPUT_CREATEBUFFER) + { + /* + Ok, the speaker mode selected isn't supported by this soundcard. Switch it + back to stereo... + */ + result = mSystem->setSoftwareFormat(44100, FMOD_SPEAKERMODE_STEREO, 0); + Check_FMOD_Error(result,"Error falling back to stereo mode"); + /* + ... and re-init. + */ + result = mSystem->init( num_channels + 2, fmod_flags, 0); + } + if(Check_FMOD_Error(result, "Error initializing FMOD Studio")) + return false; +#endif + + if (mEnableProfiler) + { + Check_FMOD_Error(mSystem->createChannelGroup("None", &mChannelGroups[AUDIO_TYPE_NONE]), "FMOD::System::createChannelGroup"); + Check_FMOD_Error(mSystem->createChannelGroup("SFX", &mChannelGroups[AUDIO_TYPE_SFX]), "FMOD::System::createChannelGroup"); + Check_FMOD_Error(mSystem->createChannelGroup("UI", &mChannelGroups[AUDIO_TYPE_UI]), "FMOD::System::createChannelGroup"); + Check_FMOD_Error(mSystem->createChannelGroup("Ambient", &mChannelGroups[AUDIO_TYPE_AMBIENT]), "FMOD::System::createChannelGroup"); + } + + // set up our favourite FMOD-native streaming audio implementation if none has already been added + if (!getStreamingAudioImpl()) // no existing implementation added + setStreamingAudioImpl(new LLStreamingAudio_FMODSTUDIO(mSystem)); + + LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init() FMOD Studio initialized correctly" << LL_ENDL; + + int r_numbuffers, r_samplerate; + unsigned int r_bufferlength; + char r_name[256]; + FMOD_SPEAKERMODE speaker_mode; + if (!Check_FMOD_Error(mSystem->getDSPBufferSize(&r_bufferlength, &r_numbuffers), "FMOD::System::getDSPBufferSize") && + !Check_FMOD_Error(mSystem->getSoftwareFormat(&r_samplerate, &speaker_mode, NULL), "FMOD::System::getSoftwareFormat") && + !Check_FMOD_Error(mSystem->getDriverInfo(0, r_name, 255, NULL, NULL, &speaker_mode, NULL), "FMOD::System::getDriverInfo")) + { + std::string speaker_mode_str = "unknown"; + switch(speaker_mode) + { + #define SPEAKER_MODE_CASE(MODE) case MODE: speaker_mode_str = #MODE; break; + SPEAKER_MODE_CASE(FMOD_SPEAKERMODE_RAW) + SPEAKER_MODE_CASE(FMOD_SPEAKERMODE_MONO) + SPEAKER_MODE_CASE(FMOD_SPEAKERMODE_STEREO) + SPEAKER_MODE_CASE(FMOD_SPEAKERMODE_QUAD) + SPEAKER_MODE_CASE(FMOD_SPEAKERMODE_SURROUND) + SPEAKER_MODE_CASE(FMOD_SPEAKERMODE_5POINT1) + SPEAKER_MODE_CASE(FMOD_SPEAKERMODE_7POINT1) + default:; + #undef SPEAKER_MODE_CASE + } + + r_name[255] = '\0'; + int latency = 1000.0 * r_bufferlength * r_numbuffers /r_samplerate; + + LL_INFOS("AppInit") << "FMOD device: "<< r_name << "\n" + << "Output mode: "<< speaker_mode_str << "\n" + << "FMOD Studio parameters: " << r_samplerate << " Hz * " <<" bit\n" + << "\tbuffer " << r_bufferlength << " * " << r_numbuffers << " (" << latency <<"ms)" << LL_ENDL; + } + else + { + LL_WARNS("AppInit") << "Failed to retrieve FMOD device info!" << LL_ENDL; + } + mInited = true; + + return true; +} + + +std::string LLAudioEngine_FMODSTUDIO::getDriverName(bool verbose) +{ + llassert_always(mSystem); + if (verbose) + { + U32 version; + if(!Check_FMOD_Error(mSystem->getVersion(&version), "FMOD::System::getVersion")) + { + return llformat("FMOD Studio %1x.%02x.%02x", version >> 16, version >> 8 & 0x000000FF, version & 0x000000FF); + } + } + return "FMOD Studio"; +} + + +void LLAudioEngine_FMODSTUDIO::allocateListener(void) +{ + mListenerp = (LLListener *) new LLListener_FMODSTUDIO(mSystem); + if (!mListenerp) + { + LL_WARNS("AudioImpl") << "Listener creation failed" << LL_ENDL; + } +} + + +void LLAudioEngine_FMODSTUDIO::shutdown() +{ + LL_INFOS("AudioImpl") << "About to LLAudioEngine::shutdown()" << LL_ENDL; + LLAudioEngine::shutdown(); + + LL_INFOS("AudioImpl") << "LLAudioEngine_FMODSTUDIO::shutdown() closing FMOD Studio" << LL_ENDL; + if ( mSystem ) // speculative fix for MAINT-2657 + { + LL_INFOS("AudioImpl") << "LLAudioEngine_FMODSTUDIO::shutdown() Requesting FMOD Studio system closure" << LL_ENDL; + Check_FMOD_Error(mSystem->close(), "FMOD::System::close"); + LL_INFOS("AudioImpl") << "LLAudioEngine_FMODSTUDIO::shutdown() Requesting FMOD Studio system release" << LL_ENDL; + Check_FMOD_Error(mSystem->release(), "FMOD::System::release"); + } + LL_INFOS("AudioImpl") << "LLAudioEngine_FMODSTUDIO::shutdown() done closing FMOD Studio" << LL_ENDL; + + delete mListenerp; + mListenerp = NULL; +} + + +LLAudioBuffer * LLAudioEngine_FMODSTUDIO::createBuffer() +{ + return new LLAudioBufferFMODSTUDIO(mSystem); +} + + +LLAudioChannel * LLAudioEngine_FMODSTUDIO::createChannel() +{ + return new LLAudioChannelFMODSTUDIO(mSystem); +} + +bool LLAudioEngine_FMODSTUDIO::initWind() +{ + mNextWindUpdate = 0.0; + + cleanupWind(); + + mWindDSPDesc = new FMOD_DSP_DESCRIPTION(); + memset(mWindDSPDesc, 0, sizeof(*mWindDSPDesc)); //Set everything to zero + mWindDSPDesc->pluginsdkversion = FMOD_PLUGIN_SDK_VERSION; + strncpy(mWindDSPDesc->name, "Wind Unit", sizeof(mWindDSPDesc->name)); //Set name to "Wind Unit" + mWindDSPDesc->numoutputbuffers = 1; + mWindDSPDesc->read = &windDSPCallback; //Assign callback. + if (Check_FMOD_Error(mSystem->createDSP(mWindDSPDesc, &mWindDSP), "FMOD::createDSP") || !mWindDSP) + return false; + + int frequency = 44100; + FMOD_SPEAKERMODE mode; + if (!Check_FMOD_Error(mSystem->getSoftwareFormat(&frequency, &mode, NULL), "FMOD::System::getSoftwareFormat")) + { + mWindGen = new LLWindGen((U32)frequency); + + if (!Check_FMOD_Error(mWindDSP->setUserData((void*)mWindGen), "FMOD::DSP::setUserData") && + !Check_FMOD_Error(mSystem->getSoftwareFormat(NULL, &mode, NULL), "FMOD::System::getSoftwareFormat") && + !Check_FMOD_Error(mWindDSP->setChannelFormat(FMOD_CHANNELMASK_STEREO, 2, mode), "FMOD::DSP::setChannelFormat") && + !Check_FMOD_Error(mSystem->playDSP(mWindDSP, NULL, false, 0), "FMOD::System::playDSP")) + return true; //Success + } + + cleanupWind(); + return false; +} + + +void LLAudioEngine_FMODSTUDIO::cleanupWind() +{ + if (mWindDSP) + { + FMOD::ChannelGroup* mastergroup = NULL; + if (!Check_FMOD_Error(mSystem->getMasterChannelGroup(&mastergroup), "FMOD::System::getMasterChannelGroup") && mastergroup) + Check_FMOD_Error(mastergroup->removeDSP(mWindDSP), "FMOD::ChannelGroup::removeDSP"); + Check_FMOD_Error(mWindDSP->release(), "FMOD::DSP::release"); + mWindDSP = NULL; + } + + delete mWindDSPDesc; + mWindDSPDesc = NULL; + + delete mWindGen; + mWindGen = NULL; +} + + +//----------------------------------------------------------------------- +void LLAudioEngine_FMODSTUDIO::updateWind(LLVector3 wind_vec, F32 camera_height_above_water) +{ + LLVector3 wind_pos; + F64 pitch; + F64 center_freq; + + if (!mEnableWind) + { + return; + } + + if (mWindUpdateTimer.checkExpirationAndReset(LL_WIND_UPDATE_INTERVAL)) + { + + // wind comes in as Linden coordinate (+X = forward, +Y = left, +Z = up) + // need to convert this to the conventional orientation DS3D and OpenAL use + // where +X = right, +Y = up, +Z = backwards + + wind_vec.setVec(-wind_vec.mV[1], wind_vec.mV[2], -wind_vec.mV[0]); + + // cerr << "Wind update" << endl; + + pitch = 1.0 + mapWindVecToPitch(wind_vec); + center_freq = 80.0 * pow(pitch,2.5*(mapWindVecToGain(wind_vec)+1.0)); + + mWindGen->mTargetFreq = (F32)center_freq; + mWindGen->mTargetGain = (F32)mapWindVecToGain(wind_vec) * mMaxWindGain; + mWindGen->mTargetPanGainR = (F32)mapWindVecToPan(wind_vec); + } +} + +//----------------------------------------------------------------------- +void LLAudioEngine_FMODSTUDIO::setInternalGain(F32 gain) +{ + if (!mInited) + { + return; + } + + gain = llclamp( gain, 0.0f, 1.0f ); + + FMOD::ChannelGroup *master_group; + if(Check_FMOD_Error(mSystem->getMasterChannelGroup(&master_group), "FMOD::System::getMasterChannelGroup")) + return; + + master_group->setVolume(gain); + + LLStreamingAudioInterface *saimpl = getStreamingAudioImpl(); + if ( saimpl ) + { + // fmod likes its streaming audio channel gain re-asserted after + // master volume change. + saimpl->setGain(saimpl->getGain()); + } +} + +// +// LLAudioChannelFMODSTUDIO implementation +// + +LLAudioChannelFMODSTUDIO::LLAudioChannelFMODSTUDIO(FMOD::System *system) : LLAudioChannel(), mSystemp(system), mChannelp(NULL), mLastSamplePos(0) +{ +} + + +LLAudioChannelFMODSTUDIO::~LLAudioChannelFMODSTUDIO() +{ + if(sVerboseDebugging) + LL_DEBUGS("AudioImpl") << "Destructing Audio Channel. mChannelp = " << mChannelp << LL_ENDL; + + cleanup(); +} + +static FMOD_RESULT F_CALLBACK channel_callback(FMOD_CHANNELCONTROL *channel, FMOD_CHANNELCONTROL_TYPE controltype, FMOD_CHANNELCONTROL_CALLBACK_TYPE callbacktype, void *commanddata1, void *commanddata2) +{ + if (controltype == FMOD_CHANNELCONTROL_CHANNEL && + callbacktype == FMOD_CHANNELCONTROL_CALLBACK_END) + { + FMOD::Channel* chan = reinterpret_cast(channel); + LLAudioChannelFMODSTUDIO* audio_channel = NULL; + chan->getUserData((void**)&audio_channel); + if(audio_channel) + { + audio_channel->onRelease(); + } + } + return FMOD_OK; +} + +void LLAudioChannelFMODSTUDIO::onRelease() +{ + llassert(mChannelp); + if(sVerboseDebugging) + LL_DEBUGS("AudioImpl") << "Fmod signaled channel release for channel " << mChannelp << LL_ENDL; + gSoundCheck.removeChannel(mChannelp); + mChannelp = NULL; //Null out channel here so cleanup doesn't try to redundantly stop it. + cleanup(); +} + +bool LLAudioChannelFMODSTUDIO::updateBuffer() +{ + if (LLAudioChannel::updateBuffer()) + { + // Base class update returned true, which means the channel buffer was changed, and not is null. + + // Grab the FMOD sample associated with the buffer + FMOD::Sound *soundp = ((LLAudioBufferFMODSTUDIO*)mCurrentBufferp)->getSound(); + if (!soundp) + { + // This is bad, there should ALWAYS be a sound associated with a legit + // buffer. + LL_ERRS("AudioImpl") << "No FMOD sound!" << LL_ENDL; + return false; + } + + + // Actually play the sound. Start it off paused so we can do all the necessary + // setup. + if(!mChannelp) + { + FMOD_RESULT result = getSystem()->playSound(soundp, NULL, true, &mChannelp); + Check_FMOD_Error(result, "FMOD::System::playSound"); + if(result == FMOD_OK) + { + if(sVerboseDebugging) + LL_DEBUGS("AudioImpl") << "Created channel " << mChannelp << " for sound " << soundp << LL_ENDL; + + gSoundCheck.addNewChannelToSound(soundp,mChannelp); + mChannelp->setCallback(&channel_callback); + mChannelp->setUserData(this); + } + } + } + + // If we have a source for the channel, we need to update its gain. + if (mCurrentSourcep && mChannelp) + { + FMOD_RESULT result; + + gSoundCheck.assertActiveState(this); + result = mChannelp->setVolume(getSecondaryGain() * mCurrentSourcep->getGain()); + Check_FMOD_Error(result, "FMOD::Channel::setVolume"); + result = mChannelp->setMode(mCurrentSourcep->isLoop() ? FMOD_LOOP_NORMAL : FMOD_LOOP_OFF); + Check_FMOD_Error(result, "FMOD::Channel::setMode"); + } + + return true; +} + + +void LLAudioChannelFMODSTUDIO::update3DPosition() +{ + if (!mChannelp) + { + // We're not actually a live channel (i.e., we're not playing back anything) + return; + } + + LLAudioBufferFMODSTUDIO *bufferp = (LLAudioBufferFMODSTUDIO *)mCurrentBufferp; + if (!bufferp) + { + // We don't have a buffer associated with us (should really have been picked up + // by the above if. + return; + } + + gSoundCheck.assertActiveState(this); + + if (mCurrentSourcep->isAmbient()) + { + // Ambient sound, don't need to do any positional updates. + set3DMode(false); + } + else + { + // Localized sound. Update the position and velocity of the sound. + set3DMode(true); + + LLVector3 float_pos; + float_pos.setVec(mCurrentSourcep->getPositionGlobal()); + FMOD_RESULT result = mChannelp->set3DAttributes((FMOD_VECTOR*)float_pos.mV, (FMOD_VECTOR*)mCurrentSourcep->getVelocity().mV); + Check_FMOD_Error(result, "FMOD::Channel::set3DAttributes"); + } +} + + +void LLAudioChannelFMODSTUDIO::updateLoop() +{ + if (!mChannelp) + { + // May want to clear up the loop/sample counters. + return; + } + + gSoundCheck.assertActiveState(this); + + // + // Hack: We keep track of whether we looped or not by seeing when the + // sample position looks like it's going backwards. Not reliable; may + // yield false negatives. + // + U32 cur_pos; + Check_FMOD_Error(mChannelp->getPosition(&cur_pos,FMOD_TIMEUNIT_PCMBYTES),"FMOD::Channel::getPosition"); + + if (cur_pos < (U32)mLastSamplePos) + { + mLoopedThisFrame = true; + } + mLastSamplePos = cur_pos; +} + + +void LLAudioChannelFMODSTUDIO::cleanup() +{ + LLAudioChannel::cleanup(); + + if (!mChannelp) + { + llassert(mCurrentBufferp == NULL); + //LL_INFOS("AudioImpl") << "Aborting cleanup with no channel handle." << LL_ENDL; + return; + } + + if(sVerboseDebugging) + LL_DEBUGS("AudioImpl") << "Stopping channel " << mChannelp << LL_ENDL; + + gSoundCheck.removeChannel(mChannelp); + mChannelp->setCallback(NULL); + Check_FMOD_Error(mChannelp->stop(),"FMOD::Channel::stop"); + + mChannelp = NULL; + mLastSamplePos = 0; +} + + +void LLAudioChannelFMODSTUDIO::play() +{ + if (!mChannelp) + { + LL_WARNS("AudioImpl") << "Playing without a channel handle, aborting" << LL_ENDL; + return; + } + + gSoundCheck.assertActiveState(this,true); + + bool paused=true; + Check_FMOD_Error(mChannelp->getPaused(&paused), "FMOD::Channel::getPaused"); + if(!paused) + { + Check_FMOD_Error(mChannelp->setPaused(true), "FMOD::Channel::setPaused"); + Check_FMOD_Error(mChannelp->setPosition(0,FMOD_TIMEUNIT_PCMBYTES), "FMOD::Channel::setPosition"); + } + Check_FMOD_Error(mChannelp->setPaused(false), "FMOD::Channel::setPaused"); + + if(sVerboseDebugging) + LL_DEBUGS("AudioImpl") << "Playing channel " << mChannelp << LL_ENDL; + + getSource()->setPlayedOnce(true); + + if(LLAudioEngine_FMODSTUDIO::mChannelGroups[getSource()->getType()]) + Check_FMOD_Error(mChannelp->setChannelGroup(LLAudioEngine_FMODSTUDIO::mChannelGroups[getSource()->getType()]),"FMOD::Channel::setChannelGroup"); +} + + +void LLAudioChannelFMODSTUDIO::playSynced(LLAudioChannel *channelp) +{ + LLAudioChannelFMODSTUDIO *fmod_channelp = (LLAudioChannelFMODSTUDIO*)channelp; + if (!(fmod_channelp->mChannelp && mChannelp)) + { + // Don't have channels allocated to both the master and the slave + return; + } + + gSoundCheck.assertActiveState(this,true); + + U32 cur_pos; + if(Check_FMOD_Error(fmod_channelp->mChannelp->getPosition(&cur_pos,FMOD_TIMEUNIT_PCMBYTES), "Unable to retrieve current position")) + return; + + cur_pos %= mCurrentBufferp->getLength(); + + // Try to match the position of our sync master + Check_FMOD_Error(mChannelp->setPosition(cur_pos,FMOD_TIMEUNIT_PCMBYTES),"Unable to set current position"); + + // Start us playing + play(); +} + + +bool LLAudioChannelFMODSTUDIO::isPlaying() +{ + if (!mChannelp) + { + return false; + } + + gSoundCheck.assertActiveState(this); + + bool paused, playing; + Check_FMOD_Error(mChannelp->getPaused(&paused),"FMOD::Channel::getPaused"); + Check_FMOD_Error(mChannelp->isPlaying(&playing),"FMOD::Channel::isPlaying"); + return !paused && playing; +} + + +// +// LLAudioChannelFMODSTUDIO implementation +// + + +LLAudioBufferFMODSTUDIO::LLAudioBufferFMODSTUDIO(FMOD::System *system) : LLAudioBuffer(), mSystemp(system), mSoundp(NULL) +{ +} + + +LLAudioBufferFMODSTUDIO::~LLAudioBufferFMODSTUDIO() +{ + if(mSoundp) + { + if(sVerboseDebugging) + LL_DEBUGS("AudioImpl") << "Release sound " << mSoundp << LL_ENDL; + + gSoundCheck.removeSound(mSoundp); + Check_FMOD_Error(mSoundp->release(),"FMOD::Sound::Release"); + mSoundp = NULL; + } +} + + +bool LLAudioBufferFMODSTUDIO::loadWAV(const std::string& filename) +{ + // Try to open a wav file from disk. This will eventually go away, as we don't + // really want to block doing this. + if (filename.empty()) + { + // invalid filename, abort. + return false; + } + + if (!gDirUtilp->fileExists(filename)) + { + // File not found, abort. + return false; + } + + if (mSoundp) + { + gSoundCheck.removeSound(mSoundp); + // If there's already something loaded in this buffer, clean it up. + Check_FMOD_Error(mSoundp->release(),"FMOD::Sound::release"); + mSoundp = NULL; + } + + FMOD_MODE base_mode = FMOD_LOOP_NORMAL; + FMOD_CREATESOUNDEXINFO exinfo = { }; + exinfo.cbsize = sizeof(exinfo); + exinfo.suggestedsoundtype = FMOD_SOUND_TYPE_WAV; //Hint to speed up loading. + // Load up the wav file into an fmod sample + FMOD_RESULT result = getSystem()->createSound(filename.c_str(), base_mode, &exinfo, &mSoundp); + if (result != FMOD_OK) + { + // We failed to load the file for some reason. + LL_WARNS("AudioImpl") << "Could not load data '" << filename << "': " << FMOD_ErrorString(result) << LL_ENDL; + + // + // If we EVER want to load wav files provided by end users, we need + // to rethink this! + // + // file is probably corrupt - remove it. + LLFile::remove(filename); + return false; + } + + gSoundCheck.addNewSound(mSoundp); + + // Everything went well, return true + return true; +} + + +U32 LLAudioBufferFMODSTUDIO::getLength() +{ + if (!mSoundp) + { + return 0; + } + + gSoundCheck.assertActiveState(this); + U32 length; + Check_FMOD_Error(mSoundp->getLength(&length, FMOD_TIMEUNIT_PCMBYTES),"FMOD::Sound::getLength"); + return length; +} + + +void LLAudioChannelFMODSTUDIO::set3DMode(bool use3d) +{ + gSoundCheck.assertActiveState(this); + + FMOD_MODE current_mode; + if(Check_FMOD_Error(mChannelp->getMode(¤t_mode),"FMOD::Channel::getMode")) + return; + FMOD_MODE new_mode = current_mode; + new_mode &= ~(use3d ? FMOD_2D : FMOD_3D); + new_mode |= use3d ? FMOD_3D : FMOD_2D; + + if(current_mode != new_mode) + { + Check_FMOD_Error(mChannelp->setMode(new_mode),"FMOD::Channel::setMode"); + } +} + + +FMOD_RESULT F_CALLBACK windDSPCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int *outchannels) +{ + // inbuffer = incomming data. + // newbuffer = outgoing data. AKA this DSP's output. + // length = length in samples at this mix time. True buffer size, in bytes, would be (length * sizeof(float) * inchannels). + // userdata = user-provided data attached this DSP via FMOD::DSP::setUserData. + + LLWindGen *windgen; + FMOD::DSP *thisdsp = (FMOD::DSP *)dsp_state->instance; + + thisdsp->getUserData((void **)&windgen); + + if (windgen) + windgen->windGenerate((LLAudioEngine_FMODSTUDIO::MIXBUFFERFORMAT *)outbuffer, length); + + return FMOD_OK; +} diff --git a/indra/llaudio/llaudioengine_fmodstudio.h b/indra/llaudio/llaudioengine_fmodstudio.h new file mode 100644 index 0000000000..ff45d3ecb9 --- /dev/null +++ b/indra/llaudio/llaudioengine_fmodstudio.h @@ -0,0 +1,141 @@ +/** + * @file audioengine_FMODSTUDIO.h + * @brief Definition of LLAudioEngine class abstracting the audio + * support as a FMOD Studio 3D implementation + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + * + * Copyright (c) 2002-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_AUDIOENGINE_FMODSTUDIO_H +#define LL_AUDIOENGINE_FMODSTUDIO_H + +#include "llaudioengine.h" +#include "lllistener_fmodstudio.h" +#include "llwindgen.h" + +//Stubs +class LLAudioStreamManagerFMODSTUDIO; +namespace FMOD +{ + class System; + class Channel; + class ChannelGroup; + class Sound; + class DSP; +} +typedef struct FMOD_DSP_DESCRIPTION FMOD_DSP_DESCRIPTION; + +//Interfaces +class LLAudioEngine_FMODSTUDIO : public LLAudioEngine +{ +public: + LLAudioEngine_FMODSTUDIO(bool enable_profiler, bool verbose_debugging); + virtual ~LLAudioEngine_FMODSTUDIO(); + + // initialization/startup/shutdown + virtual bool init(const S32 num_channels, void *user_data); + virtual std::string getDriverName(bool verbose); + virtual void allocateListener(); + + virtual void shutdown(); + + /*virtual*/ bool initWind(); + /*virtual*/ void cleanupWind(); + + /*virtual*/void updateWind(LLVector3 direction, F32 camera_height_above_water); + + typedef F32 MIXBUFFERFORMAT; + + FMOD::System *getSystem() const {return mSystem;} +protected: + /*virtual*/ LLAudioBuffer *createBuffer(); // Get a free buffer, or flush an existing one if you have to. + /*virtual*/ LLAudioChannel *createChannel(); // Create a new audio channel. + + /*virtual*/ void setInternalGain(F32 gain); + + bool mInited; + + LLWindGen *mWindGen; + + FMOD_DSP_DESCRIPTION *mWindDSPDesc; + FMOD::DSP *mWindDSP; + FMOD::System *mSystem; + bool mEnableProfiler; + +public: + static FMOD::ChannelGroup *mChannelGroups[LLAudioEngine::AUDIO_TYPE_COUNT]; +}; + + +class LLAudioChannelFMODSTUDIO : public LLAudioChannel +{ +public: + LLAudioChannelFMODSTUDIO(FMOD::System *audioengine); + virtual ~LLAudioChannelFMODSTUDIO(); + void onRelease(); +protected: + /*virtual*/ void play(); + /*virtual*/ void playSynced(LLAudioChannel *channelp); + /*virtual*/ void cleanup(); + /*virtual*/ bool isPlaying(); + + /*virtual*/ bool updateBuffer(); + /*virtual*/ void update3DPosition(); + /*virtual*/ void updateLoop(); + + void set3DMode(bool use3d); +protected: + FMOD::System *getSystem() const {return mSystemp;} + FMOD::System *mSystemp; + FMOD::Channel *mChannelp; + S32 mLastSamplePos; + + friend class CFMODSoundChecks; +}; + + +class LLAudioBufferFMODSTUDIO : public LLAudioBuffer +{ +public: + LLAudioBufferFMODSTUDIO(FMOD::System *audioengine); + virtual ~LLAudioBufferFMODSTUDIO(); + + /*virtual*/ bool loadWAV(const std::string& filename); + /*virtual*/ U32 getLength(); + friend class LLAudioChannelFMODSTUDIO; +protected: + FMOD::System *getSystem() const {return mSystemp;} + FMOD::System *mSystemp; + FMOD::Sound *getSound() const{ return mSoundp; } + FMOD::Sound *mSoundp; + + friend class CFMODSoundChecks; +}; + + +#endif // LL_AUDIOENGINE_FMODSTUDIO_H diff --git a/indra/llaudio/llaudioengine_openal.cpp b/indra/llaudio/llaudioengine_openal.cpp index 10ce5e6ed4..0911cea3b1 100644 --- a/indra/llaudio/llaudioengine_openal.cpp +++ b/indra/llaudio/llaudioengine_openal.cpp @@ -65,33 +65,33 @@ bool LLAudioEngine_OpenAL::init(const S32 num_channels, void* userdata) if(!alutInit(NULL, NULL)) { - llwarns << "LLAudioEngine_OpenAL::init() ALUT initialization failed: " << alutGetErrorString (alutGetError ()) << llendl; + LL_WARNS() << "LLAudioEngine_OpenAL::init() ALUT initialization failed: " << alutGetErrorString (alutGetError ()) << LL_ENDL; return false; } - llinfos << "LLAudioEngine_OpenAL::init() OpenAL successfully initialized" << llendl; + LL_INFOS() << "LLAudioEngine_OpenAL::init() OpenAL successfully initialized" << LL_ENDL; - llinfos << "OpenAL version: " - << ll_safe_string(alGetString(AL_VERSION)) << llendl; - llinfos << "OpenAL vendor: " - << ll_safe_string(alGetString(AL_VENDOR)) << llendl; - llinfos << "OpenAL renderer: " - << ll_safe_string(alGetString(AL_RENDERER)) << llendl; + LL_INFOS() << "OpenAL version: " + << ll_safe_string(alGetString(AL_VERSION)) << LL_ENDL; + LL_INFOS() << "OpenAL vendor: " + << ll_safe_string(alGetString(AL_VENDOR)) << LL_ENDL; + LL_INFOS() << "OpenAL renderer: " + << ll_safe_string(alGetString(AL_RENDERER)) << LL_ENDL; ALint major = alutGetMajorVersion (); ALint minor = alutGetMinorVersion (); - llinfos << "ALUT version: " << major << "." << minor << llendl; + LL_INFOS() << "ALUT version: " << major << "." << minor << LL_ENDL; ALCdevice *device = alcGetContextsDevice(alcGetCurrentContext()); alcGetIntegerv(device, ALC_MAJOR_VERSION, 1, &major); alcGetIntegerv(device, ALC_MAJOR_VERSION, 1, &minor); - llinfos << "ALC version: " << major << "." << minor << llendl; + LL_INFOS() << "ALC version: " << major << "." << minor << LL_ENDL; - llinfos << "ALC default device: " + LL_INFOS() << "ALC default device: " << ll_safe_string(alcGetString(device, ALC_DEFAULT_DEVICE_SPECIFIER)) - << llendl; + << LL_ENDL; return true; } @@ -131,24 +131,24 @@ void LLAudioEngine_OpenAL::allocateListener() mListenerp = (LLListener *) new LLListener_OpenAL(); if(!mListenerp) { - llwarns << "LLAudioEngine_OpenAL::allocateListener() Listener creation failed" << llendl; + LL_WARNS() << "LLAudioEngine_OpenAL::allocateListener() Listener creation failed" << LL_ENDL; } } // virtual void LLAudioEngine_OpenAL::shutdown() { - llinfos << "About to LLAudioEngine::shutdown()" << llendl; + LL_INFOS() << "About to LLAudioEngine::shutdown()" << LL_ENDL; LLAudioEngine::shutdown(); - llinfos << "About to alutExit()" << llendl; + LL_INFOS() << "About to alutExit()" << LL_ENDL; if(!alutExit()) { - llwarns << "Nuts." << llendl; - llwarns << "LLAudioEngine_OpenAL::shutdown() ALUT shutdown failed: " << alutGetErrorString (alutGetError ()) << llendl; + LL_WARNS() << "Nuts." << LL_ENDL; + LL_WARNS() << "LLAudioEngine_OpenAL::shutdown() ALUT shutdown failed: " << alutGetErrorString (alutGetError ()) << LL_ENDL; } - llinfos << "LLAudioEngine_OpenAL::shutdown() OpenAL successfully shut down" << llendl; + LL_INFOS() << "LLAudioEngine_OpenAL::shutdown() OpenAL successfully shut down" << LL_ENDL; delete mListenerp; mListenerp = NULL; @@ -166,7 +166,7 @@ LLAudioChannel *LLAudioEngine_OpenAL::createChannel() void LLAudioEngine_OpenAL::setInternalGain(F32 gain) { - //llinfos << "LLAudioEngine_OpenAL::setInternalGain() Gain: " << gain << llendl; + //LL_INFOS() << "LLAudioEngine_OpenAL::setInternalGain() Gain: " << gain << LL_ENDL; alListenerf(AL_GAIN, gain); } @@ -189,21 +189,24 @@ void LLAudioChannelOpenAL::cleanup() LLAudioChannel::cleanup(); alSourceStop(mALSource); alSourcei(mALSource, AL_BUFFER, AL_NONE); + mLastSamplePos = 0; } void LLAudioChannelOpenAL::play() { if (mALSource == AL_NONE) { - llwarns << "Playing without a mALSource, aborting" << llendl; + LL_WARNS() << "Playing without a mALSource, aborting" << LL_ENDL; return; } - if(!isPlaying()) + if(isPlaying()) { - alSourcePlay(mALSource); - getSource()->setPlayedOnce(true); + alSourceStop(mALSource); } + + alSourcePlay(mALSource); + getSource()->setPlayedOnce(true); } void LLAudioChannelOpenAL::playSynced(LLAudioChannel *channelp) @@ -220,8 +223,8 @@ void LLAudioChannelOpenAL::playSynced(LLAudioChannel *channelp) alGetSourcef(masterchannelp->mALSource, AL_SEC_OFFSET, &master_offset); - llinfos << "Syncing with master at " << master_offset - << "sec" << llendl; + LL_INFOS() << "Syncing with master at " << master_offset + << "sec" << LL_ENDL; // *TODO: detect when this fails, maybe use AL_SAMPLE_ alSourcef(mALSource, AL_SEC_OFFSET, master_offset); } @@ -348,18 +351,18 @@ bool LLAudioBufferOpenAL::loadWAV(const std::string& filename) ALenum error = alutGetError(); if (gDirUtilp->fileExists(filename)) { - llwarns << + LL_WARNS() << "LLAudioBufferOpenAL::loadWAV() Error loading " << filename - << " " << alutGetErrorString(error) << llendl; + << " " << alutGetErrorString(error) << LL_ENDL; } else { // It's common for the file to not actually exist. - lldebugs << + LL_DEBUGS() << "LLAudioBufferOpenAL::loadWAV() Error loading " << filename - << " " << alutGetErrorString(error) << llendl; + << " " << alutGetErrorString(error) << LL_ENDL; } return false; } @@ -383,7 +386,7 @@ U32 LLAudioBufferOpenAL::getLength() bool LLAudioEngine_OpenAL::initWind() { ALenum error; - llinfos << "LLAudioEngine_OpenAL::initWind() start" << llendl; + LL_INFOS() << "LLAudioEngine_OpenAL::initWind() start" << LL_ENDL; mNumEmptyWindALBuffers = MAX_NUM_WIND_BUFFERS; @@ -393,7 +396,7 @@ bool LLAudioEngine_OpenAL::initWind() if((error=alGetError()) != AL_NO_ERROR) { - llwarns << "LLAudioEngine_OpenAL::initWind() Error creating wind sources: "<; @@ -406,18 +409,18 @@ bool LLAudioEngine_OpenAL::initWind() if(mWindBuf==NULL) { - llerrs << "LLAudioEngine_OpenAL::initWind() Error creating wind memory buffer" << llendl; + LL_ERRS() << "LLAudioEngine_OpenAL::initWind() Error creating wind memory buffer" << LL_ENDL; return false; } - llinfos << "LLAudioEngine_OpenAL::initWind() done" << llendl; + LL_INFOS() << "LLAudioEngine_OpenAL::initWind() done" << LL_ENDL; return true; } void LLAudioEngine_OpenAL::cleanupWind() { - llinfos << "LLAudioEngine_OpenAL::cleanupWind()" << llendl; + LL_INFOS() << "LLAudioEngine_OpenAL::cleanupWind()" << LL_ENDL; if (mWindSource != AL_NONE) { @@ -494,7 +497,7 @@ void LLAudioEngine_OpenAL::updateWind(LLVector3 wind_vec, F32 camera_altitude) mNumEmptyWindALBuffers = llmin(mNumEmptyWindALBuffers + processed * 3 - unprocessed, MAX_NUM_WIND_BUFFERS-unprocessed); mNumEmptyWindALBuffers = llmax(mNumEmptyWindALBuffers, 0); - //llinfos << "mNumEmptyWindALBuffers: " << mNumEmptyWindALBuffers <<" (" << unprocessed << ":" << processed << ")" << llendl; + //LL_INFOS() << "mNumEmptyWindALBuffers: " << mNumEmptyWindALBuffers <<" (" << unprocessed << ":" << processed << ")" << LL_ENDL; //delete the old wind buffers buffers = new ALuint[processed]; @@ -503,7 +506,7 @@ void LLAudioEngine_OpenAL::updateWind(LLVector3 wind_vec, F32 camera_altitude) error = alGetError(); if(error != AL_NO_ERROR) { - llwarns << "LLAudioEngine_OpenAL::updateWind() error swapping (unqueuing) buffers" << llendl; + LL_WARNS() << "LLAudioEngine_OpenAL::updateWind() error swapping (unqueuing) buffers" << LL_ENDL; } else { @@ -520,7 +523,7 @@ void LLAudioEngine_OpenAL::updateWind(LLVector3 wind_vec, F32 camera_altitude) alGenBuffers(mNumEmptyWindALBuffers,&buffers[0]); if((error=alGetError()) != AL_NO_ERROR) { - llwarns << "LLAudioEngine_OpenAL::updateWind() Error creating wind buffer: " << error << llendl; + LL_WARNS() << "LLAudioEngine_OpenAL::updateWind() Error creating wind buffer: " << error << LL_ENDL; //break; } @@ -537,7 +540,7 @@ void LLAudioEngine_OpenAL::updateWind(LLVector3 wind_vec, F32 camera_altitude) error = alGetError(); if(error != AL_NO_ERROR) { - llwarns << "LLAudioEngine_OpenAL::updateWind() error swapping (bufferdata) buffers" << llendl; + LL_WARNS() << "LLAudioEngine_OpenAL::updateWind() error swapping (bufferdata) buffers" << LL_ENDL; errors++; } } @@ -547,7 +550,7 @@ void LLAudioEngine_OpenAL::updateWind(LLVector3 wind_vec, F32 camera_altitude) error = alGetError(); if(error != AL_NO_ERROR) { - llwarns << "LLAudioEngine_OpenAL::updateWind() error swapping (queuing) buffers" << llendl; + LL_WARNS() << "LLAudioEngine_OpenAL::updateWind() error swapping (queuing) buffers" << LL_ENDL; } mNumEmptyWindALBuffers = errors; @@ -563,7 +566,7 @@ void LLAudioEngine_OpenAL::updateWind(LLVector3 wind_vec, F32 camera_altitude) { alSourcePlay(mWindSource); - lldebugs << "Wind had stopped - probably ran out of buffers - restarting: " << (unprocessed+mNumEmptyWindALBuffers) << " now queued." << llendl; + LL_DEBUGS() << "Wind had stopped - probably ran out of buffers - restarting: " << (unprocessed+mNumEmptyWindALBuffers) << " now queued." << LL_ENDL; } } diff --git a/indra/llaudio/lllistener.cpp b/indra/llaudio/lllistener.cpp index df2366c8c2..0723fdbebe 100644 --- a/indra/llaudio/lllistener.cpp +++ b/indra/llaudio/lllistener.cpp @@ -28,15 +28,18 @@ #include "lllistener.h" -#define DEFAULT_AT 0.0f,0.0f,-1.0f -#define DEFAULT_UP 0.0f,1.0f,0.0f +const LLVector3 DEFAULT_AT(0.0f, 0.0f, -1.0f); +const LLVector3 DEFAULT_UP(0.0f, 1.0f, 0.0f); //----------------------------------------------------------------------- // constructor //----------------------------------------------------------------------- LLListener::LLListener() + : mPosition(LLVector3::zero), + mListenAt(DEFAULT_AT), + mListenUp(DEFAULT_UP), + mVelocity(LLVector3::zero) { - init(); } //----------------------------------------------------------------------- @@ -44,15 +47,6 @@ LLListener::~LLListener() { } -//----------------------------------------------------------------------- -void LLListener::init(void) -{ - mPosition.zeroVec(); - mListenAt.setVec(DEFAULT_AT); - mListenUp.setVec(DEFAULT_UP); - mVelocity.zeroVec(); -} - //----------------------------------------------------------------------- void LLListener::translate(LLVector3 offset) { @@ -99,9 +93,6 @@ void LLListener::orient(LLVector3 up, LLVector3 at) //----------------------------------------------------------------------- void LLListener::set(LLVector3 pos, LLVector3 vel, LLVector3 up, LLVector3 at) { - mPosition = pos; - mVelocity = vel; - setPosition(pos); setVelocity(vel); orient(up,at); diff --git a/indra/llaudio/lllistener.h b/indra/llaudio/lllistener.h index 41836bf039..11c1ad2ae1 100644 --- a/indra/llaudio/lllistener.h +++ b/indra/llaudio/lllistener.h @@ -45,7 +45,6 @@ class LLListener public: LLListener(); virtual ~LLListener(); - virtual void init(); virtual void set(LLVector3 pos, LLVector3 vel, LLVector3 up, LLVector3 at); diff --git a/indra/llaudio/lllistener_fmod.cpp b/indra/llaudio/lllistener_fmod.cpp deleted file mode 100644 index 0138f4345e..0000000000 --- a/indra/llaudio/lllistener_fmod.cpp +++ /dev/null @@ -1,125 +0,0 @@ -/** - * @file listener_fmod.cpp - * @brief implementation of LISTENER class abstracting the audio - * support as a FMOD 3D implementation (windows only) - * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" -#include "llaudioengine.h" -#include "lllistener_fmod.h" -#include "fmod.h" - -//----------------------------------------------------------------------- -// constructor -//----------------------------------------------------------------------- -LLListener_FMOD::LLListener_FMOD() -{ - init(); -} - -//----------------------------------------------------------------------- -LLListener_FMOD::~LLListener_FMOD() -{ -} - -//----------------------------------------------------------------------- -void LLListener_FMOD::init(void) -{ - // do inherited - LLListener::init(); - mDopplerFactor = 1.0f; - mRolloffFactor = 1.0f; -} - -//----------------------------------------------------------------------- -void LLListener_FMOD::translate(LLVector3 offset) -{ - LLListener::translate(offset); - - FSOUND_3D_Listener_SetAttributes(mPosition.mV, NULL, mListenAt.mV[0],mListenAt.mV[1],mListenAt.mV[2], mListenUp.mV[0],mListenUp.mV[1],mListenUp.mV[2]); -} - -//----------------------------------------------------------------------- -void LLListener_FMOD::setPosition(LLVector3 pos) -{ - LLListener::setPosition(pos); - - FSOUND_3D_Listener_SetAttributes(pos.mV, NULL, mListenAt.mV[0],mListenAt.mV[1],mListenAt.mV[2], mListenUp.mV[0],mListenUp.mV[1],mListenUp.mV[2]); -} - -//----------------------------------------------------------------------- -void LLListener_FMOD::setVelocity(LLVector3 vel) -{ - LLListener::setVelocity(vel); - - FSOUND_3D_Listener_SetAttributes(NULL, vel.mV, mListenAt.mV[0],mListenAt.mV[1],mListenAt.mV[2], mListenUp.mV[0],mListenUp.mV[1],mListenUp.mV[2]); -} - -//----------------------------------------------------------------------- -void LLListener_FMOD::orient(LLVector3 up, LLVector3 at) -{ - LLListener::orient(up, at); - - // Welcome to the transition between right and left - // (coordinate systems, that is) - // Leaving the at vector alone results in a L/R reversal - // since DX is left-handed and we (LL, OpenGL, OpenAL) are right-handed - at = -at; - - FSOUND_3D_Listener_SetAttributes(NULL, NULL, at.mV[0],at.mV[1],at.mV[2], up.mV[0],up.mV[1],up.mV[2]); -} - -//----------------------------------------------------------------------- -void LLListener_FMOD::commitDeferredChanges() -{ - FSOUND_Update(); -} - - -void LLListener_FMOD::setRolloffFactor(F32 factor) -{ - mRolloffFactor = factor; - FSOUND_3D_SetRolloffFactor(factor); -} - - -F32 LLListener_FMOD::getRolloffFactor() -{ - return mRolloffFactor; -} - - -void LLListener_FMOD::setDopplerFactor(F32 factor) -{ - mDopplerFactor = factor; - FSOUND_3D_SetDopplerFactor(factor); -} - - -F32 LLListener_FMOD::getDopplerFactor() -{ - return mDopplerFactor; -} - - diff --git a/indra/llaudio/lllistener_fmod.h b/indra/llaudio/lllistener_fmod.h deleted file mode 100644 index 818da05d51..0000000000 --- a/indra/llaudio/lllistener_fmod.h +++ /dev/null @@ -1,58 +0,0 @@ -/** - * @file listener_fmod.h - * @brief Description of LISTENER class abstracting the audio support - * as an FMOD 3D implementation (windows and Linux) - * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LISTENER_FMOD_H -#define LL_LISTENER_FMOD_H - -#include "lllistener.h" - -class LLListener_FMOD : public LLListener -{ - public: - LLListener_FMOD(); - virtual ~LLListener_FMOD(); - virtual void init(); - - virtual void translate(LLVector3 offset); - virtual void setPosition(LLVector3 pos); - virtual void setVelocity(LLVector3 vel); - virtual void orient(LLVector3 up, LLVector3 at); - virtual void commitDeferredChanges(); - - virtual void setDopplerFactor(F32 factor); - virtual F32 getDopplerFactor(); - virtual void setRolloffFactor(F32 factor); - virtual F32 getRolloffFactor(); - - protected: - F32 mDopplerFactor; - F32 mRolloffFactor; -}; - -#endif - - diff --git a/indra/llaudio/lllistener_fmodex.cpp b/indra/llaudio/lllistener_fmodex.cpp deleted file mode 100644 index e70dc7c60c..0000000000 --- a/indra/llaudio/lllistener_fmodex.cpp +++ /dev/null @@ -1,141 +0,0 @@ -/** - * @file listener_fmod.cpp - * @brief implementation of LISTENER class abstracting the audio - * support as a FMOD 3D implementation (windows only) - * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#include "linden_common.h" -#include "llaudioengine.h" -#include "lllistener_fmodex.h" -#include "fmod.hpp" - -//----------------------------------------------------------------------- -// constructor -//----------------------------------------------------------------------- -LLListener_FMODEX::LLListener_FMODEX(FMOD::System *system) -{ - mSystem = system; - init(); -} - -//----------------------------------------------------------------------- -LLListener_FMODEX::~LLListener_FMODEX() -{ -} - -//----------------------------------------------------------------------- -void LLListener_FMODEX::init(void) -{ - // do inherited - LLListener::init(); - mDopplerFactor = 1.0f; - mRolloffFactor = 1.0f; -} - -//----------------------------------------------------------------------- -void LLListener_FMODEX::translate(LLVector3 offset) -{ - LLListener::translate(offset); - - mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV); -} - -//----------------------------------------------------------------------- -void LLListener_FMODEX::setPosition(LLVector3 pos) -{ - LLListener::setPosition(pos); - - mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV); -} - -//----------------------------------------------------------------------- -void LLListener_FMODEX::setVelocity(LLVector3 vel) -{ - LLListener::setVelocity(vel); - - mSystem->set3DListenerAttributes(0, NULL, (FMOD_VECTOR*)mVelocity.mV, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV); -} - -//----------------------------------------------------------------------- -void LLListener_FMODEX::orient(LLVector3 up, LLVector3 at) -{ - LLListener::orient(up, at); - - // Welcome to the transition between right and left - // (coordinate systems, that is) - // Leaving the at vector alone results in a L/R reversal - // since DX is left-handed and we (LL, OpenGL, OpenAL) are right-handed - at = -at; - - mSystem->set3DListenerAttributes(0, NULL, NULL, (FMOD_VECTOR*)at.mV, (FMOD_VECTOR*)up.mV); -} - -//----------------------------------------------------------------------- -void LLListener_FMODEX::commitDeferredChanges() -{ - mSystem->update(); -} - - -void LLListener_FMODEX::setRolloffFactor(F32 factor) -{ - //An internal FMODEx optimization skips 3D updates if there have not been changes to the 3D sound environment. - //Sadly, a change in rolloff is not accounted for, thus we must touch the listener properties as well. - //In short: Changing the position ticks a dirtyflag inside fmodex, which makes it not skip 3D processing next update call. - if(mRolloffFactor != factor) - { - LLVector3 pos = mVelocity - LLVector3(0.f,0.f,.1f); - mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)pos.mV, NULL, NULL, NULL); - mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mVelocity.mV, NULL, NULL, NULL); - } - mRolloffFactor = factor; - mSystem->set3DSettings(mDopplerFactor, 1.f, mRolloffFactor); -} - - -F32 LLListener_FMODEX::getRolloffFactor() -{ - return mRolloffFactor; -} - - -void LLListener_FMODEX::setDopplerFactor(F32 factor) -{ - mDopplerFactor = factor; - mSystem->set3DSettings(mDopplerFactor, 1.f, mRolloffFactor); -} - - -F32 LLListener_FMODEX::getDopplerFactor() -{ - return mDopplerFactor; -} - - diff --git a/indra/llaudio/lllistener_fmodex.h b/indra/llaudio/lllistener_fmodex.h deleted file mode 100644 index 8a91b3a2ed..0000000000 --- a/indra/llaudio/lllistener_fmodex.h +++ /dev/null @@ -1,71 +0,0 @@ -/** - * @file listener_fmod.h - * @brief Description of LISTENER class abstracting the audio support - * as an FMOD 3D implementation (windows and Linux) - * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifndef LL_LISTENER_FMODEX_H -#define LL_LISTENER_FMODEX_H - -#include "lllistener.h" - -//Stubs -namespace FMOD -{ - class System; -} - -//Interfaces -class LLListener_FMODEX : public LLListener -{ - public: - LLListener_FMODEX(FMOD::System *system); - virtual ~LLListener_FMODEX(); - virtual void init(); - - virtual void translate(LLVector3 offset); - virtual void setPosition(LLVector3 pos); - virtual void setVelocity(LLVector3 vel); - virtual void orient(LLVector3 up, LLVector3 at); - virtual void commitDeferredChanges(); - - virtual void setDopplerFactor(F32 factor); - virtual F32 getDopplerFactor(); - virtual void setRolloffFactor(F32 factor); - virtual F32 getRolloffFactor(); - protected: - FMOD::System *mSystem; - F32 mDopplerFactor; - F32 mRolloffFactor; -}; - -#endif - - diff --git a/indra/llaudio/lllistener_fmodstudio.cpp b/indra/llaudio/lllistener_fmodstudio.cpp new file mode 100644 index 0000000000..42d819ef66 --- /dev/null +++ b/indra/llaudio/lllistener_fmodstudio.cpp @@ -0,0 +1,133 @@ +/** + * @file listener_fmodstudio.cpp + * @brief implementation of LISTENER class abstracting the audio + * support as a FMOD 3D implementation (windows only) + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + * + * Copyright (c) 2002-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "llaudioengine.h" +#include "lllistener_fmodstudio.h" +#include "fmod.hpp" + +//----------------------------------------------------------------------- +// constructor +//----------------------------------------------------------------------- +LLListener_FMODSTUDIO::LLListener_FMODSTUDIO(FMOD::System *system) + : LLListener(), + mDopplerFactor(1.0f), + mRolloffFactor(1.0f) +{ + mSystem = system; +} + +//----------------------------------------------------------------------- +LLListener_FMODSTUDIO::~LLListener_FMODSTUDIO() +{ +} + +//----------------------------------------------------------------------- +void LLListener_FMODSTUDIO::translate(LLVector3 offset) +{ + LLListener::translate(offset); + + mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, NULL, NULL); +} + +//----------------------------------------------------------------------- +void LLListener_FMODSTUDIO::setPosition(LLVector3 pos) +{ + LLListener::setPosition(pos); + + mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, NULL, NULL); +} + +//----------------------------------------------------------------------- +void LLListener_FMODSTUDIO::setVelocity(LLVector3 vel) +{ + LLListener::setVelocity(vel); + + mSystem->set3DListenerAttributes(0, NULL, (FMOD_VECTOR*)mVelocity.mV, NULL, NULL); +} + +//----------------------------------------------------------------------- +void LLListener_FMODSTUDIO::orient(LLVector3 up, LLVector3 at) +{ + LLListener::orient(up, at); + + mSystem->set3DListenerAttributes(0, NULL, NULL, (FMOD_VECTOR*)at.mV, (FMOD_VECTOR*)up.mV); +} + +//----------------------------------------------------------------------- +void LLListener_FMODSTUDIO::commitDeferredChanges() +{ + if(!mSystem) + { + return; + } + + mSystem->update(); +} + + +void LLListener_FMODSTUDIO::setRolloffFactor(F32 factor) +{ + //An internal FMOD Studio optimization skips 3D updates if there have not been changes to the 3D sound environment. + //Sadly, a change in rolloff is not accounted for, thus we must touch the listener properties as well. + //In short: Changing the position ticks a dirtyflag inside fmod studio, which makes it not skip 3D processing next update call. + if(mRolloffFactor != factor) + { + LLVector3 tmp_pos = mPosition - LLVector3(0.f,0.f,.1f); + mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*) tmp_pos.mV, NULL, NULL, NULL); + mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*) mPosition.mV, NULL, NULL, NULL); + } + mRolloffFactor = factor; + mSystem->set3DSettings(mDopplerFactor, 1.f, mRolloffFactor); +} + + +F32 LLListener_FMODSTUDIO::getRolloffFactor() +{ + return mRolloffFactor; +} + + +void LLListener_FMODSTUDIO::setDopplerFactor(F32 factor) +{ + mDopplerFactor = factor; + mSystem->set3DSettings(mDopplerFactor, 1.f, mRolloffFactor); +} + + +F32 LLListener_FMODSTUDIO::getDopplerFactor() +{ + return mDopplerFactor; +} + + diff --git a/indra/llaudio/lllistener_fmodstudio.h b/indra/llaudio/lllistener_fmodstudio.h new file mode 100644 index 0000000000..de9a5e9ca6 --- /dev/null +++ b/indra/llaudio/lllistener_fmodstudio.h @@ -0,0 +1,70 @@ +/** + * @file listener_fmodstudio.h + * @brief Description of LISTENER class abstracting the audio support + * as an FMOD Studio 3D implementation (windows and Linux) + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + * + * Copyright (c) 2002-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LISTENER_FMODSTUDIO_H +#define LL_LISTENER_FMODSTUDIO_H + +#include "lllistener.h" + +//Stubs +namespace FMOD +{ + class System; +} + +//Interfaces +class LLListener_FMODSTUDIO : public LLListener +{ + public: + LLListener_FMODSTUDIO(FMOD::System *system); + virtual ~LLListener_FMODSTUDIO(); + + virtual void translate(LLVector3 offset); + virtual void setPosition(LLVector3 pos); + virtual void setVelocity(LLVector3 vel); + virtual void orient(LLVector3 up, LLVector3 at); + virtual void commitDeferredChanges(); + + virtual void setDopplerFactor(F32 factor); + virtual F32 getDopplerFactor(); + virtual void setRolloffFactor(F32 factor); + virtual F32 getRolloffFactor(); + protected: + FMOD::System *mSystem; + F32 mDopplerFactor; + F32 mRolloffFactor; +}; + +#endif + + diff --git a/indra/llaudio/lllistener_openal.cpp b/indra/llaudio/lllistener_openal.cpp index b3d4b02f09..d1734a930d 100644 --- a/indra/llaudio/lllistener_openal.cpp +++ b/indra/llaudio/lllistener_openal.cpp @@ -31,8 +31,9 @@ #include "lllistener_openal.h" LLListener_OpenAL::LLListener_OpenAL() + : LLListener(), + mRolloffFactor(1.f) { - init(); } LLListener_OpenAL::~LLListener_OpenAL() @@ -41,13 +42,13 @@ LLListener_OpenAL::~LLListener_OpenAL() void LLListener_OpenAL::translate(LLVector3 offset) { - //llinfos << "LLListener_OpenAL::translate() : " << offset << llendl; + //LL_INFOS() << "LLListener_OpenAL::translate() : " << offset << LL_ENDL; LLListener::translate(offset); } void LLListener_OpenAL::setPosition(LLVector3 pos) { - //llinfos << "LLListener_OpenAL::setPosition() : " << pos << llendl; + //LL_INFOS() << "LLListener_OpenAL::setPosition() : " << pos << LL_ENDL; LLListener::setPosition(pos); } @@ -58,24 +59,26 @@ void LLListener_OpenAL::setVelocity(LLVector3 vel) void LLListener_OpenAL::orient(LLVector3 up, LLVector3 at) { - //llinfos << "LLListener_OpenAL::orient() up: " << up << " at: " << at << llendl; + //LL_INFOS() << "LLListener_OpenAL::orient() up: " << up << " at: " << at << LL_ENDL; LLListener::orient(up, at); } void LLListener_OpenAL::commitDeferredChanges() { - ALfloat orientation[6]; - orientation[0] = mListenAt.mV[0]; - orientation[1] = mListenAt.mV[1]; - orientation[2] = mListenAt.mV[2]; - orientation[3] = mListenUp.mV[0]; - orientation[4] = mListenUp.mV[1]; - orientation[5] = mListenUp.mV[2]; - - ALfloat velocity[3]; - velocity[0] = mVelocity.mV[0]; - velocity[1] = mVelocity.mV[1]; - velocity[2] = mVelocity.mV[2]; + ALfloat orientation[] = { + mListenAt.mV[0], + mListenAt.mV[1], + mListenAt.mV[2], + mListenUp.mV[0], + mListenUp.mV[1], + mListenUp.mV[2], + }; + + ALfloat velocity[3] = { + mVelocity.mV[0], + mVelocity.mV[1], + mVelocity.mV[2], + }; alListenerfv(AL_ORIENTATION, orientation); alListenerfv(AL_POSITION, mPosition.mV); @@ -84,7 +87,7 @@ void LLListener_OpenAL::commitDeferredChanges() void LLListener_OpenAL::setDopplerFactor(F32 factor) { - //llinfos << "LLListener_OpenAL::setDopplerFactor() : " << factor << llendl; + //LL_INFOS() << "LLListener_OpenAL::setDopplerFactor() : " << factor << LL_ENDL; alDopplerFactor(factor); } @@ -92,7 +95,7 @@ F32 LLListener_OpenAL::getDopplerFactor() { ALfloat factor; factor = alGetFloat(AL_DOPPLER_FACTOR); - //llinfos << "LLListener_OpenAL::getDopplerFactor() : " << factor << llendl; + //LL_INFOS() << "LLListener_OpenAL::getDopplerFactor() : " << factor << LL_ENDL; return factor; } diff --git a/indra/llaudio/llstreamingaudio_fmod.cpp b/indra/llaudio/llstreamingaudio_fmod.cpp deleted file mode 100644 index 4036b8df69..0000000000 --- a/indra/llaudio/llstreamingaudio_fmod.cpp +++ /dev/null @@ -1,385 +0,0 @@ -/** - * @file streamingaudio_fmod.cpp - * @brief LLStreamingAudio_FMOD implementation - * - * $LicenseInfo:firstyear=2009&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include "llmath.h" - -#include "fmod.h" -#include "fmod_errors.h" - -#include "llstreamingaudio_fmod.h" - - -class LLAudioStreamManagerFMOD -{ -public: - LLAudioStreamManagerFMOD(const std::string& url); - int startStream(); - bool stopStream(); // Returns true if the stream was successfully stopped. - bool ready(); - - const std::string& getURL() { return mInternetStreamURL; } - - int getOpenState(); - - FSOUND_STREAM* getStream() { return mInternetStream; } -protected: - FSOUND_STREAM* mInternetStream; - bool mReady; - - std::string mInternetStreamURL; -}; - - - -//--------------------------------------------------------------------------- -// Internet Streaming -//--------------------------------------------------------------------------- -LLStreamingAudio_FMOD::LLStreamingAudio_FMOD() : - mCurrentInternetStreamp(NULL), - mFMODInternetStreamChannel(-1), - mGain(1.0f), - mMetaData(NULL) -{ - // Number of milliseconds of audio to buffer for the audio card. - // Must be larger than the usual Second Life frame stutter time. - FSOUND_Stream_SetBufferSize(200); - - // Here's where we set the size of the network buffer and some buffering - // parameters. In this case we want a network buffer of 16k, we want it - // to prebuffer 40% of that when we first connect, and we want it - // to rebuffer 80% of that whenever we encounter a buffer underrun. - - // Leave the net buffer properties at the default. - //FSOUND_Stream_Net_SetBufferProperties(20000, 40, 80); -} - - -LLStreamingAudio_FMOD::~LLStreamingAudio_FMOD() -{ - // nothing interesting/safe to do. -} - -signed char F_CALLBACKAPI MetaDataCallback(char *name, char *value, void *userdata) -{ - std::string szName(name); - if(szName == "TITLE" || szName=="TIT2" || szName=="Title") - (*(LLSD*)userdata)["TITLE"] = value; - if(szName == "ARTIST" || szName=="TPE1" || szName =="WM/AlbumTitle") - (*(LLSD*)userdata)["ARTIST"] = value; - else - (*(LLSD*)userdata)[std::string(name)] = value; - return true; -} - -void LLStreamingAudio_FMOD::start(const std::string& url) -{ - //if (!mInited) - //{ - // llwarns << "startInternetStream before audio initialized" << llendl; - // return; - //} - - // "stop" stream but don't clear url, etc. in case url == mInternetStreamURL - stop(); - - if (!url.empty()) - { - llinfos << "Starting internet stream: " << url << llendl; - mCurrentInternetStreamp = new LLAudioStreamManagerFMOD(url); - mURL = url; - if(mCurrentInternetStreamp->getStream()) - { - mMetaData = new LLSD; - } - } - else - { - llinfos << "Set internet stream to null" << llendl; - mURL.clear(); - } -} - - -void LLStreamingAudio_FMOD::update() -{ - // Kill dead internet streams, if possible - std::list::iterator iter; - for (iter = mDeadStreams.begin(); iter != mDeadStreams.end();) - { - LLAudioStreamManagerFMOD *streamp = *iter; - if (streamp->stopStream()) - { - llinfos << "Closed dead stream" << llendl; - delete streamp; - mDeadStreams.erase(iter++); - } - else - { - iter++; - } - } - - // Don't do anything if there are no streams playing - if (!mCurrentInternetStreamp) - { - return; - } - - int open_state = mCurrentInternetStreamp->getOpenState(); - - if (!open_state) - { - // Stream is live - - // start the stream if it's ready - if (mFMODInternetStreamChannel < 0) - { - mFMODInternetStreamChannel = mCurrentInternetStreamp->startStream(); - - if (mFMODInternetStreamChannel != -1) - { - // Reset volume to previously set volume - setGain(getGain()); - FSOUND_SetPaused(mFMODInternetStreamChannel, false); - if(mCurrentInternetStreamp->getStream() && mMetaData) - { - FSOUND_Stream_Net_SetMetadataCallback(mCurrentInternetStreamp->getStream(),&MetaDataCallback, mMetaData); - } - } - } - } - - switch(open_state) - { - default: - case 0: - // success - break; - case -1: - // stream handle is invalid - llwarns << "InternetStream - invalid handle" << llendl; - stop(); - return; - case -2: - // opening - break; - case -3: - // failed to open, file not found, perhaps - llwarns << "InternetStream - failed to open" << llendl; - stop(); - return; - case -4: - // connecting - break; - case -5: - // buffering - break; - } - -} - -void LLStreamingAudio_FMOD::stop() -{ - if(mMetaData) - { - if(mCurrentInternetStreamp && mCurrentInternetStreamp->getStream()) - FSOUND_Stream_Net_SetMetadataCallback(mCurrentInternetStreamp->getStream(),NULL,NULL); - delete mMetaData; - mMetaData = NULL; - } - if (mFMODInternetStreamChannel != -1) - { - FSOUND_SetPaused(mFMODInternetStreamChannel, true); - FSOUND_SetPriority(mFMODInternetStreamChannel, 0); - mFMODInternetStreamChannel = -1; - } - - if (mCurrentInternetStreamp) - { - llinfos << "Stopping internet stream: " << mCurrentInternetStreamp->getURL() << llendl; - if (mCurrentInternetStreamp->stopStream()) - { - delete mCurrentInternetStreamp; - } - else - { - llwarns << "Pushing stream to dead list: " << mCurrentInternetStreamp->getURL() << llendl; - mDeadStreams.push_back(mCurrentInternetStreamp); - } - mCurrentInternetStreamp = NULL; - //mURL.clear(); - } -} - -void LLStreamingAudio_FMOD::pause(int pauseopt) -{ - if (pauseopt < 0) - { - pauseopt = mCurrentInternetStreamp ? 1 : 0; - } - - if (pauseopt) - { - if (mCurrentInternetStreamp) - { - stop(); - } - } - else - { - start(getURL()); - } -} - - -// A stream is "playing" if it has been requested to start. That -// doesn't necessarily mean audio is coming out of the speakers. -int LLStreamingAudio_FMOD::isPlaying() -{ - if (mCurrentInternetStreamp) - { - return 1; // Active and playing - } - else if (!mURL.empty()) - { - return 2; // "Paused" - } - else - { - return 0; - } -} - - -F32 LLStreamingAudio_FMOD::getGain() -{ - return mGain; -} - - -std::string LLStreamingAudio_FMOD::getURL() -{ - return mURL; -} - - -void LLStreamingAudio_FMOD::setGain(F32 vol) -{ - mGain = vol; - - if (mFMODInternetStreamChannel != -1) - { - vol = llclamp(vol * vol, 0.f, 1.f); - int vol_int = llround(vol * 255.f); - FSOUND_SetVolumeAbsolute(mFMODInternetStreamChannel, vol_int); - } -} - - -/////////////////////////////////////////////////////// -// manager of possibly-multiple internet audio streams - -LLAudioStreamManagerFMOD::LLAudioStreamManagerFMOD(const std::string& url) : - mInternetStream(NULL), - mReady(false) -{ - mInternetStreamURL = url; - mInternetStream = FSOUND_Stream_Open(url.c_str(), FSOUND_NORMAL | FSOUND_NONBLOCKING, 0, 0); - if (!mInternetStream) - { - llwarns << "Couldn't open fmod stream, error " - << FMOD_ErrorString(FSOUND_GetError()) - << llendl; - mReady = false; - return; - } - - mReady = true; -} - -int LLAudioStreamManagerFMOD::startStream() -{ - // We need a live and opened stream before we try and play it. - if (!mInternetStream || getOpenState()) - { - llwarns << "No internet stream to start playing!" << llendl; - return -1; - } - - // Make sure the stream is set to 2D mode. - FSOUND_Stream_SetMode(mInternetStream, FSOUND_2D); - - return FSOUND_Stream_PlayEx(FSOUND_FREE, mInternetStream, NULL, true); -} - -bool LLAudioStreamManagerFMOD::stopStream() -{ - if (mInternetStream) - { - int read_percent = 0; - int status = 0; - int bitrate = 0; - unsigned int flags = 0x0; - FSOUND_Stream_Net_GetStatus(mInternetStream, &status, &read_percent, &bitrate, &flags); - - bool close = true; - switch (status) - { - case FSOUND_STREAM_NET_CONNECTING: - close = false; - break; - case FSOUND_STREAM_NET_NOTCONNECTED: - case FSOUND_STREAM_NET_BUFFERING: - case FSOUND_STREAM_NET_READY: - case FSOUND_STREAM_NET_ERROR: - default: - close = true; - } - - if (close) - { - FSOUND_Stream_Close(mInternetStream); - mInternetStream = NULL; - return true; - } - else - { - return false; - } - } - else - { - return true; - } -} - -int LLAudioStreamManagerFMOD::getOpenState() -{ - int open_state = FSOUND_Stream_GetOpenState(mInternetStream); - return open_state; -} diff --git a/indra/llaudio/llstreamingaudio_fmod.h b/indra/llaudio/llstreamingaudio_fmod.h deleted file mode 100644 index 4bb65c54d8..0000000000 --- a/indra/llaudio/llstreamingaudio_fmod.h +++ /dev/null @@ -1,68 +0,0 @@ -/** - * @file streamingaudio_fmod.h - * @author Tofu Linden - * @brief Definition of LLStreamingAudio_FMOD implementation - * - * $LicenseInfo:firstyear=2009&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_STREAMINGAUDIO_FMOD_H -#define LL_STREAMINGAUDIO_FMOD_H - -#include "stdtypes.h" // from llcommon - -#include "llstreamingaudio.h" - -class LLAudioStreamManagerFMOD; - -class LLStreamingAudio_FMOD : public LLStreamingAudioInterface -{ - public: - LLStreamingAudio_FMOD(); - /*virtual*/ ~LLStreamingAudio_FMOD(); - - /*virtual*/ void start(const std::string& url); - /*virtual*/ void stop(); - /*virtual*/ void pause(int pause); - /*virtual*/ void update(); - /*virtual*/ int isPlaying(); - /*virtual*/ void setGain(F32 vol); - /*virtual*/ F32 getGain(); - /*virtual*/ std::string getURL(); - - /*virtual*/ bool supportsMetaData(){return true;} - /*virtual*/ const LLSD *getMetaData(){return mMetaData;} //return NULL if not playing. - /*virtual*/ bool supportsWaveData(){return false;} - /*virtual*/ bool getWaveData(float* arr, S32 count, S32 stride = 1){return false;} -private: - LLAudioStreamManagerFMOD *mCurrentInternetStreamp; - int mFMODInternetStreamChannel; - std::list mDeadStreams; - - std::string mURL; - F32 mGain; - - LLSD *mMetaData; -}; - - -#endif // LL_STREAMINGAUDIO_FMOD_H diff --git a/indra/llaudio/llstreamingaudio_fmodex.cpp b/indra/llaudio/llstreamingaudio_fmodex.cpp deleted file mode 100644 index 9e3e406c75..0000000000 --- a/indra/llaudio/llstreamingaudio_fmodex.cpp +++ /dev/null @@ -1,514 +0,0 @@ -/** - * @file streamingaudio_fmod.cpp - * @brief LLStreamingAudio_FMODEX implementation - * - * $LicenseInfo:firstyear=2009&license=viewergpl$ - * - * Copyright (c) 2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include "llmath.h" - -#include "fmod.hpp" -#include "fmod_errors.h" - -#include "llstreamingaudio_fmodex.h" - - -class LLAudioStreamManagerFMODEX -{ -public: - LLAudioStreamManagerFMODEX(FMOD::System *system, const std::string& url); - FMOD::Channel* startStream(); - bool stopStream(); // Returns true if the stream was successfully stopped. - bool ready(); - - const std::string& getURL() { return mInternetStreamURL; } - - FMOD_OPENSTATE getOpenState(unsigned int* percentbuffered=NULL, bool* starving=NULL, bool* diskbusy=NULL); -protected: - FMOD::System* mSystem; - FMOD::Channel* mStreamChannel; - FMOD::Sound* mInternetStream; - bool mReady; - - std::string mInternetStreamURL; -}; - - - -//--------------------------------------------------------------------------- -// Internet Streaming -//--------------------------------------------------------------------------- -LLStreamingAudio_FMODEX::LLStreamingAudio_FMODEX(FMOD::System *system) : - mSystem(system), - mCurrentInternetStreamp(NULL), - mFMODInternetStreamChannelp(NULL), - mGain(1.0f), - mMetaData(NULL) -{ - // Number of milliseconds of audio to buffer for the audio card. - // Must be larger than the usual Second Life frame stutter time. - const U32 buffer_seconds = 10; //sec - const U32 estimated_bitrate = 128; //kbit/sec - mSystem->setStreamBufferSize(estimated_bitrate * buffer_seconds * 128/*bytes/kbit*/, FMOD_TIMEUNIT_RAWBYTES); - - // Here's where we set the size of the network buffer and some buffering - // parameters. In this case we want a network buffer of 16k, we want it - // to prebuffer 40% of that when we first connect, and we want it - // to rebuffer 80% of that whenever we encounter a buffer underrun. - - // Leave the net buffer properties at the default. - //FSOUND_Stream_Net_SetBufferProperties(20000, 40, 80); -} - - -LLStreamingAudio_FMODEX::~LLStreamingAudio_FMODEX() -{ - // nothing interesting/safe to do. -} - - -void LLStreamingAudio_FMODEX::start(const std::string& url) -{ - //if (!mInited) - //{ - // llwarns << "startInternetStream before audio initialized" << llendl; - // return; - //} - - // "stop" stream but don't clear url, etc. in case url == mInternetStreamURL - stop(); - - if (!url.empty()) - { - if(mDeadStreams.empty()) - { - llinfos << "Starting internet stream: " << url << llendl; - mCurrentInternetStreamp = new LLAudioStreamManagerFMODEX(mSystem,url); - mURL = url; - mMetaData = new LLSD; - } - else - { - llinfos << "Deferring stream load until buffer release: " << url << llendl; - mPendingURL = url; - } - } - else - { - llinfos << "Set internet stream to null" << llendl; - mURL.clear(); - } -} - - -void LLStreamingAudio_FMODEX::update() -{ - // Kill dead internet streams, if possible - std::list::iterator iter; - for (iter = mDeadStreams.begin(); iter != mDeadStreams.end();) - { - LLAudioStreamManagerFMODEX *streamp = *iter; - if (streamp->stopStream()) - { - llinfos << "Closed dead stream" << llendl; - delete streamp; - mDeadStreams.erase(iter++); - } - else - { - iter++; - } - } - - if(!mDeadStreams.empty()) - { - llassert_always(mCurrentInternetStreamp == NULL); - return; - } - - if(!mPendingURL.empty()) - { - llassert_always(mCurrentInternetStreamp == NULL); - llinfos << "Starting internet stream: " << mPendingURL << llendl; - mCurrentInternetStreamp = new LLAudioStreamManagerFMODEX(mSystem,mPendingURL); - mURL = mPendingURL; - mMetaData = new LLSD; - mPendingURL.clear(); - } - - // Don't do anything if there are no streams playing - if (!mCurrentInternetStreamp) - { - return; - } - - unsigned int progress; - bool starving; - bool diskbusy; - FMOD_OPENSTATE open_state = mCurrentInternetStreamp->getOpenState(&progress, &starving, &diskbusy); - - if (open_state == FMOD_OPENSTATE_READY) - { - // Stream is live - - // start the stream if it's ready - if (!mFMODInternetStreamChannelp && - (mFMODInternetStreamChannelp = mCurrentInternetStreamp->startStream())) - { - // Reset volume to previously set volume - setGain(getGain()); - mFMODInternetStreamChannelp->setPaused(false); - } - } - else if(open_state == FMOD_OPENSTATE_ERROR) - { - stop(); - return; - } - - if(mFMODInternetStreamChannelp) - { - if(!mMetaData) - mMetaData = new LLSD; - - FMOD::Sound *sound = NULL; - - if(mFMODInternetStreamChannelp->getCurrentSound(&sound) == FMOD_OK && sound) - { - FMOD_TAG tag; - S32 tagcount, dirtytagcount; - if(sound->getNumTags(&tagcount, &dirtytagcount) == FMOD_OK && dirtytagcount) - { - mMetaData->clear(); - - for(S32 i = 0; i < tagcount; ++i) - { - if(sound->getTag(NULL, i, &tag)!=FMOD_OK) - continue; - std::string name = tag.name; - switch(tag.type) //Crappy tag translate table. - { - case(FMOD_TAGTYPE_ID3V2): - if(name == "TIT2") name = "TITLE"; - else if(name == "TPE1") name = "ARTIST"; - break; - case(FMOD_TAGTYPE_ASF): - if(name == "Title") name = "TITLE"; - else if(name == "WM/AlbumArtist") name = "ARTIST"; - break; - case(FMOD_TAGTYPE_FMOD): - if (!strcmp(tag.name, "Sample Rate Change")) - { - llinfos << "Stream forced changing sample rate to " << *((float *)tag.data) << llendl; - mFMODInternetStreamChannelp->setFrequency(*((float *)tag.data)); - } - continue; - default: - break; - } - switch(tag.datatype) - { - case(FMOD_TAGDATATYPE_INT): - (*mMetaData)[name]=*(LLSD::Integer*)(tag.data); - llinfos << tag.name << ": " << *(int*)(tag.data) << llendl; - break; - case(FMOD_TAGDATATYPE_FLOAT): - (*mMetaData)[name]=*(LLSD::Float*)(tag.data); - llinfos << tag.name << ": " << *(float*)(tag.data) << llendl; - break; - case(FMOD_TAGDATATYPE_STRING): - { - std::string out = rawstr_to_utf8(std::string((char*)tag.data,tag.datalen)); - (*mMetaData)[name]=out; - llinfos << tag.name << ": " << out << llendl; - } - break; - case(FMOD_TAGDATATYPE_STRING_UTF16): - { - std::string out((char*)tag.data,tag.datalen); - (*mMetaData)[std::string(tag.name)]=out; - llinfos << tag.name << ": " << out << llendl; - } - break; - case(FMOD_TAGDATATYPE_STRING_UTF16BE): - { - std::string out((char*)tag.data,tag.datalen); - U16* buf = (U16*)out.c_str(); - for(U32 j = 0; j < out.size()/2; ++j) - (((buf[j] & 0xff)<<8) | ((buf[j] & 0xff00)>>8)); - (*mMetaData)[std::string(tag.name)]=out; - llinfos << tag.name << ": " << out << llendl; - } - default: - break; - } - } - } - if(starving) - { - bool paused = false; - mFMODInternetStreamChannelp->getPaused(&paused); - if(!paused) - { - llinfos << "Stream starvation detected! Pausing stream until buffer nearly full." << llendl; - llinfos << " (diskbusy="<setPaused(true); - } - } - else if(progress > 80) - { - mFMODInternetStreamChannelp->setPaused(false); - } - } - } -} - -void LLStreamingAudio_FMODEX::stop() -{ - mPendingURL.clear(); - - if(mMetaData) - { - delete mMetaData; - mMetaData = NULL; - } - if (mFMODInternetStreamChannelp) - { - mFMODInternetStreamChannelp->setPaused(true); - mFMODInternetStreamChannelp->setPriority(0); - mFMODInternetStreamChannelp = NULL; - } - - if (mCurrentInternetStreamp) - { - llinfos << "Stopping internet stream: " << mCurrentInternetStreamp->getURL() << llendl; - if (mCurrentInternetStreamp->stopStream()) - { - delete mCurrentInternetStreamp; - } - else - { - llwarns << "Pushing stream to dead list: " << mCurrentInternetStreamp->getURL() << llendl; - mDeadStreams.push_back(mCurrentInternetStreamp); - } - mCurrentInternetStreamp = NULL; - //mURL.clear(); - } -} - -void LLStreamingAudio_FMODEX::pause(int pauseopt) -{ - if (pauseopt < 0) - { - pauseopt = mCurrentInternetStreamp ? 1 : 0; - } - - if (pauseopt) - { - if (mCurrentInternetStreamp) - { - stop(); - } - } - else - { - start(getURL()); - } -} - - -// A stream is "playing" if it has been requested to start. That -// doesn't necessarily mean audio is coming out of the speakers. -int LLStreamingAudio_FMODEX::isPlaying() -{ - if (mCurrentInternetStreamp) - { - return 1; // Active and playing - } - else if (!mURL.empty() || !mPendingURL.empty()) - { - return 2; // "Paused" - } - else - { - return 0; - } -} - - -F32 LLStreamingAudio_FMODEX::getGain() -{ - return mGain; -} - - -std::string LLStreamingAudio_FMODEX::getURL() -{ - return mURL; -} - - -void LLStreamingAudio_FMODEX::setGain(F32 vol) -{ - mGain = vol; - - if (mFMODInternetStreamChannelp) - { - vol = llclamp(vol * vol, 0.f, 1.f); //should vol be squared here? - - mFMODInternetStreamChannelp->setVolume(vol); - } -} - -/*virtual*/ bool LLStreamingAudio_FMODEX::getWaveData(float* arr, S32 count, S32 stride/*=1*/) -{ - if(!mFMODInternetStreamChannelp || !mCurrentInternetStreamp) - return false; - - bool muted=false; - mFMODInternetStreamChannelp->getMute(&muted); - if(muted) - return false; - - static std::vector local_array(count); //Have to have an extra buffer to mix channels. Bleh. - if(count > (S32)local_array.size()) //Expand the array if needed. Try to minimize allocation calls, so don't ever shrink. - local_array.resize(count); - - if( mFMODInternetStreamChannelp->getWaveData(&local_array[0],count,0) == FMOD_OK && - mFMODInternetStreamChannelp->getWaveData(&arr[0],count,1) == FMOD_OK ) - { - for(S32 i = count-1;i>=0;i-=stride) - { - arr[i] += local_array[i]; - arr[i] *= .5f; - } - return true; - } - return false; -} - -/////////////////////////////////////////////////////// -// manager of possibly-multiple internet audio streams - -LLAudioStreamManagerFMODEX::LLAudioStreamManagerFMODEX(FMOD::System *system, const std::string& url) : - mSystem(system), - mStreamChannel(NULL), - mInternetStream(NULL), - mReady(false) -{ - mInternetStreamURL = url; - - /*FMOD_CREATESOUNDEXINFO exinfo; - memset(&exinfo,0,sizeof(exinfo)); - exinfo.cbsize = sizeof(exinfo); - exinfo.suggestedsoundtype = FMOD_SOUND_TYPE_OGGVORBIS; //Hint to speed up loading.*/ - - FMOD_RESULT result = mSystem->createStream(url.c_str(), FMOD_2D | FMOD_NONBLOCKING | FMOD_IGNORETAGS, 0, &mInternetStream); - - if (result!= FMOD_OK) - { - llwarns << "Couldn't open fmod stream, error " - << FMOD_ErrorString(result) - << llendl; - mReady = false; - return; - } - - mReady = true; -} - -FMOD::Channel *LLAudioStreamManagerFMODEX::startStream() -{ - // We need a live and opened stream before we try and play it. - if (!mInternetStream || getOpenState() != FMOD_OPENSTATE_READY) - { - llwarns << "No internet stream to start playing!" << llendl; - return NULL; - } - - if(mStreamChannel) - return mStreamChannel; //Already have a channel for this stream. - - mSystem->playSound(FMOD_CHANNEL_FREE, mInternetStream, true, &mStreamChannel); - return mStreamChannel; -} - -bool LLAudioStreamManagerFMODEX::stopStream() -{ - if (mInternetStream) - { - bool close = true; - switch (getOpenState()) - { - case FMOD_OPENSTATE_CONNECTING: - close = false; - break; - /*case FSOUND_STREAM_NET_NOTCONNECTED: - case FSOUND_STREAM_NET_BUFFERING: - case FSOUND_STREAM_NET_READY: - case FSOUND_STREAM_NET_ERROR:*/ - default: - close = true; - } - - if (close && mInternetStream->release() == FMOD_OK) - { - mStreamChannel = NULL; - mInternetStream = NULL; - return true; - } - else - { - return false; - } - } - else - { - return true; - } -} - -FMOD_OPENSTATE LLAudioStreamManagerFMODEX::getOpenState(unsigned int* percentbuffered, bool* starving, bool* diskbusy) -{ - FMOD_OPENSTATE state; - mInternetStream->getOpenState(&state,percentbuffered,starving,diskbusy); - return state; -} - -void LLStreamingAudio_FMODEX::setBufferSizes(U32 streambuffertime, U32 decodebuffertime) -{ - mSystem->setStreamBufferSize(streambuffertime/1000*128*128, FMOD_TIMEUNIT_RAWBYTES); - FMOD_ADVANCEDSETTINGS settings; - memset(&settings,0,sizeof(settings)); - settings.cbsize=sizeof(settings); - settings.defaultDecodeBufferSize = decodebuffertime;//ms - mSystem->setAdvancedSettings(&settings); -} diff --git a/indra/llaudio/llstreamingaudio_fmodex.h b/indra/llaudio/llstreamingaudio_fmodex.h deleted file mode 100644 index 8e8bb2da6d..0000000000 --- a/indra/llaudio/llstreamingaudio_fmodex.h +++ /dev/null @@ -1,87 +0,0 @@ -/** - * @file streamingaudio_fmod.h - * @author Tofu Linden - * @brief Definition of LLStreamingAudio_FMOD implementation - * - * $LicenseInfo:firstyear=2009&license=viewergpl$ - * - * Copyright (c) 2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifndef LL_STREAMINGAUDIO_FMOD_H -#define LL_STREAMINGAUDIO_FMOD_H - -#include "stdtypes.h" // from llcommon - -#include "llstreamingaudio.h" -#include "lltimer.h" - -//Stubs -class LLAudioStreamManagerFMODEX; -namespace FMOD -{ - class System; - class Channel; -} - -//Interfaces -class LLStreamingAudio_FMODEX : public LLStreamingAudioInterface -{ - public: - LLStreamingAudio_FMODEX(FMOD::System *system); - /*virtual*/ ~LLStreamingAudio_FMODEX(); - - /*virtual*/ void start(const std::string& url); - /*virtual*/ void stop(); - /*virtual*/ void pause(int pause); - /*virtual*/ void update(); - /*virtual*/ int isPlaying(); - /*virtual*/ void setGain(F32 vol); - /*virtual*/ F32 getGain(); - /*virtual*/ std::string getURL(); - - /*virtual*/ bool supportsMetaData(){return true;} - /*virtual*/ const LLSD *getMetaData(){return mMetaData;} //return NULL if not playing. - /*virtual*/ bool supportsWaveData(){return true;} - /*virtual*/ bool getWaveData(float* arr, S32 count, S32 stride = 1); - /*virtual*/ bool supportsAdjustableBufferSizes(){return true;} - /*virtual*/ void setBufferSizes(U32 streambuffertime, U32 decodebuffertime); -private: - FMOD::System *mSystem; - - LLAudioStreamManagerFMODEX *mCurrentInternetStreamp; - FMOD::Channel *mFMODInternetStreamChannelp; - std::list mDeadStreams; - - std::string mURL; - std::string mPendingURL; - F32 mGain; - - LLSD *mMetaData; -}; - - -#endif // LL_STREAMINGAUDIO_FMOD_H diff --git a/indra/llaudio/llstreamingaudio_fmodstudio.cpp b/indra/llaudio/llstreamingaudio_fmodstudio.cpp new file mode 100644 index 0000000000..d7c6b48b78 --- /dev/null +++ b/indra/llaudio/llstreamingaudio_fmodstudio.cpp @@ -0,0 +1,674 @@ +/** + * @file streamingaudio_fmodstudio.cpp + * @brief LLStreamingAudio_FMODSTUDIO implementation + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "llstreamingaudio_fmodstudio.h" + +#include "llmath.h" +#include "llthread.h" + +#include "fmod.hpp" +#include "fmod_errors.h" + +inline bool Check_FMOD_Error(FMOD_RESULT result, const char *string) +{ + if (result == FMOD_OK) + return false; + LL_WARNS("AudioImpl") << string << " Error: " << FMOD_ErrorString(result) << LL_ENDL; + return true; +} + +class LLAudioStreamManagerFMODSTUDIO +{ +public: + LLAudioStreamManagerFMODSTUDIO(FMOD::System *system, FMOD::ChannelGroup *group, const std::string& url); + FMOD::Channel* startStream(); + bool stopStream(); // Returns true if the stream was successfully stopped. + bool ready(); + + const std::string& getURL() { return mInternetStreamURL; } + + FMOD_RESULT getOpenState(FMOD_OPENSTATE& openstate, unsigned int* percentbuffered = NULL, bool* starving = NULL, bool* diskbusy = NULL); +protected: + FMOD::System* mSystem; + FMOD::ChannelGroup* mChannelGroup; + FMOD::Channel* mStreamChannel; + FMOD::Sound* mInternetStream; + bool mReady; + + std::string mInternetStreamURL; +}; + +LLGlobalMutex gWaveDataMutex; //Just to be extra strict. +const U32 WAVE_BUFFER_SIZE = 1024; +U32 gWaveBufferMinSize = 0; +F32 gWaveDataBuffer[WAVE_BUFFER_SIZE] = { 0.f }; +U32 gWaveDataBufferSize = 0; + +FMOD_RESULT F_CALLBACK waveDataCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int *outchannels) +{ + if (!length || !inchannels) + return FMOD_OK; + memcpy(outbuffer, inbuffer, length * inchannels * sizeof(float)); + + static std::vector local_buf; + if (local_buf.size() < length) + local_buf.resize(length, 0.f); + + for (U32 i = 0; i < length; ++i) + { + F32 total = 0.f; + for (S32 j = 0; j < inchannels; ++j) + { + total += inbuffer[i*inchannels + j]; + } + local_buf[i] = total / inchannels; + } + + { + LLMutexLock lock(gWaveDataMutex); + + for (U32 i = length; i > 0; --i) + { + if (++gWaveDataBufferSize > WAVE_BUFFER_SIZE) + { + if (gWaveBufferMinSize) + memcpy(gWaveDataBuffer + WAVE_BUFFER_SIZE - gWaveBufferMinSize, gWaveDataBuffer, gWaveBufferMinSize * sizeof(float)); + gWaveDataBufferSize = 1 + gWaveBufferMinSize; + } + gWaveDataBuffer[WAVE_BUFFER_SIZE - gWaveDataBufferSize] = local_buf[i - 1]; + } + } + + return FMOD_OK; +} + +//--------------------------------------------------------------------------- +// Internet Streaming +//--------------------------------------------------------------------------- +LLStreamingAudio_FMODSTUDIO::LLStreamingAudio_FMODSTUDIO(FMOD::System *system) : + mSystem(system), + mCurrentInternetStreamp(NULL), + mStreamDSP(NULL), + mStreamGroup(NULL), + mFMODInternetStreamChannelp(NULL), + mGain(1.0f), + mMetaData(NULL) +{ + FMOD_RESULT result; + + // Number of milliseconds of audio to buffer for the audio card. + // Must be larger than the usual Second Life frame stutter time. + const U32 buffer_seconds = 10; //sec + const U32 estimated_bitrate = 128; //kbit/sec + result = mSystem->setStreamBufferSize(estimated_bitrate * buffer_seconds * 128/*bytes/kbit*/, FMOD_TIMEUNIT_RAWBYTES); + Check_FMOD_Error(result, "FMOD::System::setStreamBufferSize"); + + // Here's where we set the size of the network buffer and some buffering + // parameters. In this case we want a network buffer of 16k, we want it + // to prebuffer 40% of that when we first connect, and we want it + // to rebuffer 80% of that whenever we encounter a buffer underrun. + + // Leave the net buffer properties at the default. + //FSOUND_Stream_Net_SetBufferProperties(20000, 40, 80); + + Check_FMOD_Error(system->createChannelGroup("stream", &mStreamGroup), "FMOD::System::createChannelGroup"); + + FMOD_DSP_DESCRIPTION dspdesc = { }; + dspdesc.pluginsdkversion = FMOD_PLUGIN_SDK_VERSION; + strncpy(dspdesc.name, "Waveform", sizeof(dspdesc.name)); + dspdesc.numoutputbuffers = 1; + dspdesc.read = &waveDataCallback; //Assign callback. + + Check_FMOD_Error(system->createDSP(&dspdesc, &mStreamDSP), "FMOD::System::createDSP"); +} + +LLStreamingAudio_FMODSTUDIO::~LLStreamingAudio_FMODSTUDIO() +{ + stop(); + for (U32 i = 0; i < 100; ++i) + { + if (releaseDeadStreams()) + break; + ms_sleep(10); + } + + cleanupWaveData(); +} + +void LLStreamingAudio_FMODSTUDIO::start(const std::string& url) +{ + //if (!mInited) + //{ + // LL_WARNS() << "startInternetStream before audio initialized" << LL_ENDL; + // return; + //} + + // "stop" stream but don't clear url, etc. in case url == mInternetStreamURL + stop(); + + if (!url.empty()) + { + if(mDeadStreams.empty()) + { + LL_INFOS() << "Starting internet stream: " << url << LL_ENDL; + mCurrentInternetStreamp = new LLAudioStreamManagerFMODSTUDIO(mSystem, mStreamGroup, url); + mURL = url; + mMetaData = new LLSD; + } + else + { + LL_INFOS() << "Deferring stream load until buffer release: " << url << LL_ENDL; + mPendingURL = url; + } + } + else + { + LL_INFOS() << "Set internet stream to null" << LL_ENDL; + mURL.clear(); + } +} + +enum utf_endian_type_t +{ + UTF16LE, + UTF16BE, + UTF16 +}; + +std::string utf16input_to_utf8(unsigned char* input, U32 len, utf_endian_type_t type) +{ + if (type == UTF16) + { + type = UTF16BE; //Default + if (len > 2) + { + //Parse and strip BOM. + if ((input[0] == 0xFE && input[1] == 0xFF) || + (input[0] == 0xFF && input[1] == 0xFE)) + { + input += 2; + len -= 2; + type = input[0] == 0xFE ? UTF16BE : UTF16LE; + } + } + } + llutf16string out_16((llutf16string::value_type*)input, len / 2); + if (len % 2) + { + out_16.push_back((input)[len - 1] << 8); + } + if (type == UTF16BE) + { + for (llutf16string::iterator i = out_16.begin(); i < out_16.end(); ++i) + { + llutf16string::value_type v = *i; + *i = ((v & 0x00FF) << 8) | ((v & 0xFF00) >> 8); + } + } + return utf16str_to_utf8str(out_16); +} + +void LLStreamingAudio_FMODSTUDIO::update() +{ + if (!releaseDeadStreams()) + { + llassert_always(mCurrentInternetStreamp == NULL); + return; + } + + if(!mPendingURL.empty()) + { + llassert_always(mCurrentInternetStreamp == NULL); + LL_INFOS() << "Starting internet stream: " << mPendingURL << LL_ENDL; + mCurrentInternetStreamp = new LLAudioStreamManagerFMODSTUDIO(mSystem, mStreamGroup, mPendingURL); + mURL = mPendingURL; + mMetaData = new LLSD; + mPendingURL.clear(); + } + + // Don't do anything if there are no streams playing + if (!mCurrentInternetStreamp) + { + return; + } + + unsigned int progress; + bool starving; + bool diskbusy; + FMOD_OPENSTATE open_state; + FMOD_RESULT result = mCurrentInternetStreamp->getOpenState(open_state, &progress, &starving, &diskbusy); + + if (result != FMOD_OK || open_state == FMOD_OPENSTATE_ERROR) + { + stop(); + return; + } + else if (open_state == FMOD_OPENSTATE_READY) + { + // Stream is live + + // start the stream if it's ready + if (!mFMODInternetStreamChannelp && + (mFMODInternetStreamChannelp = mCurrentInternetStreamp->startStream())) + { + // Reset volume to previously set volume + setGain(getGain()); + if (mStreamDSP) + { + Check_FMOD_Error(mFMODInternetStreamChannelp->addDSP(FMOD_CHANNELCONTROL_DSP_TAIL, mStreamDSP), "FMOD::Channel::addDSP"); + } + Check_FMOD_Error(mFMODInternetStreamChannelp->setPaused(false), "FMOD::Channel::setPaused"); + } + } + + + if(mFMODInternetStreamChannelp) + { + if(!mMetaData) + mMetaData = new LLSD; + + FMOD::Sound *sound = NULL; + + if(mFMODInternetStreamChannelp->getCurrentSound(&sound) == FMOD_OK && sound) + { + FMOD_TAG tag; + S32 tagcount, dirtytagcount; + if(sound->getNumTags(&tagcount, &dirtytagcount) == FMOD_OK && dirtytagcount) + { + mMetaData->clear(); + + for(S32 i = 0; i < tagcount; ++i) + { + if(sound->getTag(NULL, i, &tag)!=FMOD_OK) + continue; + + std::string name = tag.name; + switch(tag.type) //Crappy tag translate table. + { + case(FMOD_TAGTYPE_ID3V2): + if (!LLStringUtil::compareInsensitive(name, "TIT2")) name = "TITLE"; + else if(name == "TPE1") name = "ARTIST"; + break; + case(FMOD_TAGTYPE_ASF): + if (!LLStringUtil::compareInsensitive(name, "Title")) name = "TITLE"; + else if (!LLStringUtil::compareInsensitive(name, "WM/AlbumArtist")) name = "ARTIST"; + break; + case(FMOD_TAGTYPE_FMOD): + if (!LLStringUtil::compareInsensitive(name, "Sample Rate Change")) + { + LL_INFOS() << "Stream forced changing sample rate to " << *((float *)tag.data) << LL_ENDL; + Check_FMOD_Error(mFMODInternetStreamChannelp->setFrequency(*((float *)tag.data)), "FMOD::Channel::setFrequency"); + } + continue; + default: + if (!LLStringUtil::compareInsensitive(name, "TITLE") || + !LLStringUtil::compareInsensitive(name, "ARTIST")) + LLStringUtil::toUpper(name); + break; + } + + switch(tag.datatype) + { + case(FMOD_TAGDATATYPE_INT): + (*mMetaData)[name]=*(LLSD::Integer*)(tag.data); + LL_INFOS() << tag.name << ": " << *(int*)(tag.data) << LL_ENDL; + break; + case(FMOD_TAGDATATYPE_FLOAT): + (*mMetaData)[name]=*(LLSD::Float*)(tag.data); + LL_INFOS() << tag.name << ": " << *(float*)(tag.data) << LL_ENDL; + break; + case(FMOD_TAGDATATYPE_STRING): + { + std::string out = rawstr_to_utf8(std::string((char*)tag.data,tag.datalen)); + if (out.length() && out[out.size() - 1] == 0) + out.erase(out.size() - 1); + (*mMetaData)[name]=out; + LL_INFOS() << tag.name << "(RAW): " << out << LL_ENDL; + } + break; + case(FMOD_TAGDATATYPE_STRING_UTF8) : + { + U8 offs = 0; + if (tag.datalen > 3 && ((unsigned char*)tag.data)[0] == 0xEF && ((unsigned char*)tag.data)[1] == 0xBB && ((unsigned char*)tag.data)[2] == 0xBF) + offs = 3; + std::string out((char*)tag.data + offs, tag.datalen - offs); + if (out.length() && out[out.size() - 1] == 0) + out.erase(out.size() - 1); + (*mMetaData)[name] = out; + LL_INFOS() << tag.name << "(UTF8): " << out << LL_ENDL; + } + break; + case(FMOD_TAGDATATYPE_STRING_UTF16): + { + std::string out = utf16input_to_utf8((unsigned char*)tag.data, tag.datalen, UTF16); + if (out.length() && out[out.size() - 1] == 0) + out.erase(out.size() - 1); + (*mMetaData)[name] = out; + LL_INFOS() << tag.name << "(UTF16): " << out << LL_ENDL; + } + break; + case(FMOD_TAGDATATYPE_STRING_UTF16BE): + { + std::string out = utf16input_to_utf8((unsigned char*)tag.data, tag.datalen, UTF16BE); + if (out.length() && out[out.size() - 1] == 0) + out.erase(out.size() - 1); + (*mMetaData)[name] = out; + LL_INFOS() << tag.name << "(UTF16BE): " << out << LL_ENDL; + } + default: + break; + } + } + } + static bool was_starved = false; + if(starving) + { + bool paused = false; + if (mFMODInternetStreamChannelp->getPaused(&paused) == FMOD_OK && !paused) + { + LL_INFOS() << "Stream starvation detected! Pausing stream until buffer nearly full." << LL_ENDL; + LL_INFOS() << " (diskbusy="<setPaused(true), "FMOD::Channel::setPaused"); + } + was_starved = true; + } + else if(progress > 80 && was_starved) + { + was_starved = false; + Check_FMOD_Error(mFMODInternetStreamChannelp->setPaused(false), "FMOD::Channel::setPaused"); + } + } + } +} + +void LLStreamingAudio_FMODSTUDIO::stop() +{ + mPendingURL.clear(); + + if(mMetaData) + { + delete mMetaData; + mMetaData = NULL; + } + + if (mFMODInternetStreamChannelp) + { + Check_FMOD_Error(mFMODInternetStreamChannelp->setPaused(true), "FMOD::Channel::setPaused"); + Check_FMOD_Error(mFMODInternetStreamChannelp->setPriority(0), "FMOD::Channel::setPriority"); + if (mStreamDSP) + { + Check_FMOD_Error(mFMODInternetStreamChannelp->removeDSP(mStreamDSP), "FMOD::Channel::removeDSP"); + } + mFMODInternetStreamChannelp = NULL; + } + + if (mCurrentInternetStreamp) + { + LL_INFOS() << "Stopping internet stream: " << mCurrentInternetStreamp->getURL() << LL_ENDL; + if (mCurrentInternetStreamp->stopStream()) + { + delete mCurrentInternetStreamp; + } + else + { + LL_WARNS() << "Pushing stream to dead list: " << mCurrentInternetStreamp->getURL() << LL_ENDL; + mDeadStreams.push_back(mCurrentInternetStreamp); + } + mCurrentInternetStreamp = NULL; + } +} + +void LLStreamingAudio_FMODSTUDIO::pause(int pauseopt) +{ + if (pauseopt < 0) + { + pauseopt = mCurrentInternetStreamp ? 1 : 0; + } + + if (pauseopt) + { + if (mCurrentInternetStreamp) + { + stop(); + } + } + else + { + start(getURL()); + } +} + + +// A stream is "playing" if it has been requested to start. That +// doesn't necessarily mean audio is coming out of the speakers. +int LLStreamingAudio_FMODSTUDIO::isPlaying() +{ + if (mCurrentInternetStreamp) + { + return 1; // Active and playing + } + else if (!mURL.empty() || !mPendingURL.empty()) + { + return 2; // "Paused" + } + else + { + return 0; + } +} + + +F32 LLStreamingAudio_FMODSTUDIO::getGain() +{ + return mGain; +} + + +std::string LLStreamingAudio_FMODSTUDIO::getURL() +{ + return mURL; +} + + +void LLStreamingAudio_FMODSTUDIO::setGain(F32 vol) +{ + mGain = vol; + + if (mFMODInternetStreamChannelp) + { + vol = llclamp(vol * vol, 0.f, 1.f); //should vol be squared here? + + Check_FMOD_Error(mFMODInternetStreamChannelp->setVolume(vol), "FMOD::Channel::setVolume"); + } +} + +/* virtual */ +bool LLStreamingAudio_FMODSTUDIO::getWaveData(float* arr, S32 count, S32 stride/*=1*/) +{ + if (count > (WAVE_BUFFER_SIZE / 2)) + LL_ERRS("AudioImpl") << "Count=" << count << " exceeds WAVE_BUFFER_SIZE/2=" << WAVE_BUFFER_SIZE << LL_ENDL; + + if(!mFMODInternetStreamChannelp || !mCurrentInternetStreamp) + return false; + + bool muted = false; + FMOD_RESULT res = mFMODInternetStreamChannelp->getMute(&muted); + if(res != FMOD_OK || muted) + return false; + { + U32 buff_size; + { + LLMutexLock lock(gWaveDataMutex); + gWaveBufferMinSize = count; + buff_size = gWaveDataBufferSize; + if (!buff_size) + return false; + memcpy(arr, gWaveDataBuffer + WAVE_BUFFER_SIZE - buff_size, llmin(U32(count), buff_size) * sizeof(float)); + } + if (buff_size < U32(count)) + memset(arr + buff_size, 0, (count - buff_size) * sizeof(float)); + } + return true; +} + +/////////////////////////////////////////////////////// +// manager of possibly-multiple internet audio streams + +LLAudioStreamManagerFMODSTUDIO::LLAudioStreamManagerFMODSTUDIO(FMOD::System *system, FMOD::ChannelGroup *group, const std::string& url) : + mSystem(system), + mChannelGroup(group), + mStreamChannel(NULL), + mInternetStream(NULL), + mReady(false) +{ + mInternetStreamURL = url; + + FMOD_RESULT result = mSystem->createStream(url.c_str(), FMOD_2D | FMOD_NONBLOCKING | FMOD_IGNORETAGS, 0, &mInternetStream); + + if (result!= FMOD_OK) + { + LL_WARNS() << "Couldn't open fmod stream, error " + << FMOD_ErrorString(result) + << LL_ENDL; + mReady = false; + return; + } + + mReady = true; +} + +FMOD::Channel *LLAudioStreamManagerFMODSTUDIO::startStream() +{ + // We need a live and opened stream before we try and play it. + FMOD_OPENSTATE open_state; + if (getOpenState(open_state) != FMOD_OK || open_state != FMOD_OPENSTATE_READY) + { + LL_WARNS() << "No internet stream to start playing!" << LL_ENDL; + return NULL; + } + + if(mStreamChannel) + return mStreamChannel; //Already have a channel for this stream. + + Check_FMOD_Error(mSystem->playSound(mInternetStream, mChannelGroup, true, &mStreamChannel), "FMOD::System::playSound"); + return mStreamChannel; +} + +bool LLAudioStreamManagerFMODSTUDIO::stopStream() +{ + if (mInternetStream) + { + bool close = true; + FMOD_OPENSTATE open_state; + if (getOpenState(open_state) == FMOD_OK) + { + switch (open_state) + { + case FMOD_OPENSTATE_CONNECTING: + close = false; + break; + default: + close = true; + } + } + + if (close && mInternetStream->release() == FMOD_OK) + { + mStreamChannel = NULL; + mInternetStream = NULL; + return true; + } + else + { + return false; + } + } + else + { + return true; + } +} + +FMOD_RESULT LLAudioStreamManagerFMODSTUDIO::getOpenState(FMOD_OPENSTATE& state, unsigned int* percentbuffered, bool* starving, bool* diskbusy) +{ + if (!mInternetStream) + return FMOD_ERR_INVALID_HANDLE; + FMOD_RESULT result = mInternetStream->getOpenState(&state, percentbuffered, starving, diskbusy); + Check_FMOD_Error(result, "FMOD::Sound::getOpenState"); + return result; +} + +void LLStreamingAudio_FMODSTUDIO::setBufferSizes(U32 streambuffertime, U32 decodebuffertime) +{ + Check_FMOD_Error(mSystem->setStreamBufferSize(streambuffertime / 1000 * 128 * 128, FMOD_TIMEUNIT_RAWBYTES), "FMOD::System::setStreamBufferSize"); + FMOD_ADVANCEDSETTINGS settings = { }; + settings.cbSize=sizeof(settings); + settings.defaultDecodeBufferSize = decodebuffertime;//ms + Check_FMOD_Error(mSystem->setAdvancedSettings(&settings), "FMOD::System::setAdvancedSettings"); +} + +bool LLStreamingAudio_FMODSTUDIO::releaseDeadStreams() +{ + // Kill dead internet streams, if possible + std::list::iterator iter; + for (iter = mDeadStreams.begin(); iter != mDeadStreams.end();) + { + LLAudioStreamManagerFMODSTUDIO *streamp = *iter; + if (streamp->stopStream()) + { + LL_INFOS() << "Closed dead stream" << LL_ENDL; + delete streamp; + mDeadStreams.erase(iter++); + } + else + { + iter++; + } + } + + return mDeadStreams.empty(); +} + +void LLStreamingAudio_FMODSTUDIO::cleanupWaveData() +{ + if (mStreamGroup) + { + Check_FMOD_Error(mStreamGroup->release(), "FMOD::ChannelGroup::release"); + mStreamGroup = NULL; + } + + if(mStreamDSP) + Check_FMOD_Error(mStreamDSP->release(), "FMOD::DSP::release"); + mStreamDSP = NULL; +} diff --git a/indra/llaudio/llstreamingaudio_fmodstudio.h b/indra/llaudio/llstreamingaudio_fmodstudio.h new file mode 100644 index 0000000000..bb4a77e42f --- /dev/null +++ b/indra/llaudio/llstreamingaudio_fmodstudio.h @@ -0,0 +1,97 @@ +/** + * @file streamingaudio_fmodstudio.h + * @author Tofu Linden + * @brief Definition of LLStreamingAudio_FMODSTUDIO implementation + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_STREAMINGAUDIO_FMODSTUDIO_H +#define LL_STREAMINGAUDIO_FMODSTUDIO_H + +#include "stdtypes.h" // from llcommon + +#include "llstreamingaudio.h" +#include "lltimer.h" + +//Stubs +class LLAudioStreamManagerFMODSTUDIO; +namespace FMOD +{ + class System; + class Channel; + class ChannelGroup; + class ChannelGroup; + class DSP; +} + +//Interfaces +class LLStreamingAudio_FMODSTUDIO : public LLStreamingAudioInterface +{ + public: + LLStreamingAudio_FMODSTUDIO(FMOD::System *system); + /*virtual*/ ~LLStreamingAudio_FMODSTUDIO(); + + /*virtual*/ void start(const std::string& url); + /*virtual*/ void stop(); + /*virtual*/ void pause(int pause); + /*virtual*/ void update(); + /*virtual*/ int isPlaying(); + /*virtual*/ void setGain(F32 vol); + /*virtual*/ F32 getGain(); + /*virtual*/ std::string getURL(); + + /*virtual*/ bool supportsMetaData(){return true;} + /*virtual*/ const LLSD *getMetaData(){return mMetaData;} //return NULL if not playing. + /*virtual*/ bool supportsWaveData(){return true;} + /*virtual*/ bool getWaveData(float* arr, S32 count, S32 stride = 1); + /*virtual*/ bool supportsAdjustableBufferSizes(){return true;} + /*virtual*/ void setBufferSizes(U32 streambuffertime, U32 decodebuffertime); + +private: + bool releaseDeadStreams(); + void cleanupWaveData(); + + FMOD::System *mSystem; + + LLAudioStreamManagerFMODSTUDIO *mCurrentInternetStreamp; + FMOD::Channel *mFMODInternetStreamChannelp; + std::list mDeadStreams; + + std::string mURL; + std::string mPendingURL; + F32 mGain; + + LLSD *mMetaData; + + FMOD::ChannelGroup* mStreamGroup; + FMOD::DSP* mStreamDSP; +}; + + +#endif // LL_STREAMINGAUDIO_FMOD_H diff --git a/indra/llaudio/llvorbisdecode.cpp b/indra/llaudio/llvorbisdecode.cpp index 8055be96c4..b1f039dcf8 100644 --- a/indra/llaudio/llvorbisdecode.cpp +++ b/indra/llaudio/llvorbisdecode.cpp @@ -77,7 +77,7 @@ int vfs_seek(void *datasource, ogg_int64_t offset, int whence) origin = -1; break; default: - llerrs << "Invalid whence argument to vfs_seek" << llendl; + LL_ERRS() << "Invalid whence argument to vfs_seek" << LL_ENDL; return -1; } @@ -124,7 +124,7 @@ BOOL decode_vorbis_file(LLVFS *vfs, const LLUUID &in_uuid, char *out_fname) U32 data_length = 0; - llinfos << "Vorbis decode from vfile: " << in_uuid << llendl; + LL_INFOS() << "Vorbis decode from vfile: " << in_uuid << LL_ENDL; in_vfile = new LLVFile(vfs, in_uuid, LLAssetType::AT_SOUND); if (! in_vfile->getSize()) @@ -226,7 +226,7 @@ BOOL decode_vorbis_file(LLVFS *vfs, const LLUUID &in_uuid, char *out_fname) int r = ov_open_callbacks(in_vfile, &vf, NULL, 0, vfs_callbacks); if(r < 0) { - llwarns << r << " Input to vorbis decode does not appear to be an Ogg bitstream: " << in_uuid << llendl; + LL_WARNS() << r << " Input to vorbis decode does not appear to be an Ogg bitstream: " << in_uuid << LL_ENDL; return(FALSE); } @@ -247,7 +247,7 @@ BOOL decode_vorbis_file(LLVFS *vfs, const LLUUID &in_uuid, char *out_fname) if (ret == 0) { /* EOF */ eof=1; -// llinfos << "Vorbis EOF" << llendl; +// LL_INFOS() << "Vorbis EOF" << LL_ENDL; } else if (ret < 0) { /* error in the stream. Not a problem, just reporting it in case we (the app) cares. In this case, we don't. */ @@ -255,7 +255,7 @@ BOOL decode_vorbis_file(LLVFS *vfs, const LLUUID &in_uuid, char *out_fname) break; } else { -// llinfos << "Vorbis read " << ret << "bytes" << llendl; +// LL_INFOS() << "Vorbis read " << ret << "bytes" << LL_ENDL; /* we don't bother dealing with sample rate changes, etc, but. you'll have to*/ data_length += outfile.write(pcmout, ret); diff --git a/indra/llaudio/llvorbisencode.cpp b/indra/llaudio/llvorbisencode.cpp index dd301585dd..2e7fdb1db3 100644 --- a/indra/llaudio/llvorbisencode.cpp +++ b/indra/llaudio/llvorbisencode.cpp @@ -32,7 +32,6 @@ #include "llerror.h" #include "llrand.h" #include "llmath.h" -#include "llapr.h" //#if LL_DARWIN // MBW -- XXX -- Getting rid of SecondLifeVorbis for now -- no fmod means no name collisions. @@ -81,18 +80,20 @@ S32 check_for_invalid_wav_formats(const std::string& in_fname, std::string& erro error_msg.clear(); - // ******************************** - LLAPRFile infile ; - infile.open(in_fname,LL_APR_RB); - // ******************************** - if (!infile.getFileHandle()) + //******************************** + llifstream instream(in_fname, std::ios::in | std::ios::binary); + //******************************** + if (!instream.is_open()) { error_msg = "CannotUploadSoundFile"; return(LLVORBISENC_SOURCE_OPEN_ERR); } - infile.read(wav_header, 44); - physical_file_size = infile.seek(APR_END,0); + instream.read((char*)wav_header, 44); + + instream.seekg(0, instream.end); + physical_file_size = (U32) instream.tellg(); + instream.seekg(0, instream.beg); if (strncmp((char *)&(wav_header[0]),"RIFF",4)) { @@ -112,8 +113,8 @@ S32 check_for_invalid_wav_formats(const std::string& in_fname, std::string& erro while ((file_pos + 8)< physical_file_size) { - infile.seek(APR_SET,file_pos); - infile.read(wav_header, 44); + instream.seekg(file_pos); + instream.read((char*)wav_header, 44); chunk_length = ((U32) wav_header[7] << 24) + ((U32) wav_header[6] << 16) @@ -122,12 +123,12 @@ S32 check_for_invalid_wav_formats(const std::string& in_fname, std::string& erro if (chunk_length > physical_file_size - file_pos - 4) { - infile.close(); + instream.close(); error_msg = "SoundFileInvalidChunkSize"; return(LLVORBISENC_CHUNK_SIZE_ERR); } -// llinfos << "chunk found: '" << wav_header[0] << wav_header[1] << wav_header[2] << wav_header[3] << "'" << llendl; +// LL_INFOS() << "chunk found: '" << wav_header[0] << wav_header[1] << wav_header[2] << wav_header[3] << "'" << LL_ENDL; if (!(strncmp((char *)&(wav_header[0]),"fmt ",4))) { @@ -153,9 +154,9 @@ S32 check_for_invalid_wav_formats(const std::string& in_fname, std::string& erro file_pos += (chunk_length + 8); chunk_length = 0; } - // **************** - infile.close(); - // **************** + //**************** + instream.close(); + //**************** if (!uncompressed_pcm) { @@ -224,7 +225,7 @@ S32 encode_vorbis_file(const std::string& in_fname, const std::string& out_fname std::string error_msg; if ((format_error = check_for_invalid_wav_formats(in_fname, error_msg))) { - llwarns << error_msg << ": " << in_fname << llendl; + LL_WARNS() << error_msg << ": " << in_fname << LL_ENDL; return(format_error); } @@ -233,21 +234,19 @@ S32 encode_vorbis_file(const std::string& in_fname, const std::string& out_fname S32 data_left = 0; - LLAPRFile infile ; - infile.open(in_fname,LL_APR_RB); - if (!infile.getFileHandle()) + llifstream instream(in_fname, std::ios::in | std::ios::binary); + if (!instream.is_open()) { - llwarns << "Couldn't open temporary ogg file for writing: " << in_fname - << llendl; + LL_WARNS() << "Couldn't open temporary ogg file for reading: " << in_fname + << LL_ENDL; return(LLVORBISENC_SOURCE_OPEN_ERR); } - LLAPRFile outfile ; - outfile.open(out_fname,LL_APR_WPB); - if (!outfile.getFileHandle()) + llofstream outstream(out_fname, std::ios::out | std::ios::binary | std::ios::trunc); + if (!outstream.is_open()) { - llwarns << "Couldn't open upload sound file for reading: " << in_fname - << llendl; + LL_WARNS() << "Couldn't open upload sound file for writing: " << in_fname + << LL_ENDL; return(LLVORBISENC_DEST_OPEN_ERR); } @@ -255,17 +254,17 @@ S32 encode_vorbis_file(const std::string& in_fname, const std::string& out_fname U32 chunk_length = 0; U32 file_pos = 12; // start at the first chunk (usually fmt but not always) - while (infile.eof() != APR_EOF) + while (!instream.eof()) { - infile.seek(APR_SET,file_pos); - infile.read(wav_header, 44); + instream.seekg(file_pos); + instream.read((char*)wav_header, 44); chunk_length = ((U32) wav_header[7] << 24) + ((U32) wav_header[6] << 16) + ((U32) wav_header[5] << 8) + wav_header[4]; -// llinfos << "chunk found: '" << wav_header[0] << wav_header[1] << wav_header[2] << wav_header[3] << "'" << llendl; +// LL_INFOS() << "chunk found: '" << wav_header[0] << wav_header[1] << wav_header[2] << wav_header[3] << "'" << LL_ENDL; if (!(strncmp((char *)&(wav_header[0]),"fmt ",4))) { @@ -278,7 +277,7 @@ S32 encode_vorbis_file(const std::string& in_fname, const std::string& out_fname } else if (!(strncmp((char *)&(wav_header[0]),"data",4))) { - infile.seek(APR_SET,file_pos+8); + instream.seekg(file_pos + 8); // leave the file pointer at the beginning of the data chunk data data_left = chunk_length; break; @@ -308,8 +307,8 @@ S32 encode_vorbis_file(const std::string& in_fname, const std::string& out_fname // vorbis_encode_ctl(&vi,OV_ECTL_RATEMANAGE_AVG,NULL) || // vorbis_encode_setup_init(&vi)) { - llwarns << "unable to initialize vorbis codec at quality " << quality << llendl; - // llwarns << "unable to initialize vorbis codec at bitrate " << bitrate << llendl; + LL_WARNS() << "unable to initialize vorbis codec at quality " << quality << LL_ENDL; + // LL_WARNS() << "unable to initialize vorbis codec at bitrate " << bitrate << LL_ENDL; return(LLVORBISENC_DEST_OPEN_ERR); } @@ -351,8 +350,8 @@ S32 encode_vorbis_file(const std::string& in_fname, const std::string& out_fname while(!eos){ int result=ogg_stream_flush(&os,&og); if(result==0)break; - outfile.write(og.header, og.header_len); - outfile.write(og.body, og.body_len); + outstream.write((char*)og.header, og.header_len); + outstream.write((char*)og.body, og.body_len); } } @@ -362,7 +361,8 @@ S32 encode_vorbis_file(const std::string& in_fname, const std::string& out_fname { long bytes_per_sample = bits_per_sample/8; - long bytes=(long)infile.read(readbuffer,llclamp((S32)(READ_BUFFER*num_channels*bytes_per_sample),0,data_left)); /* stereo hardwired here */ + instream.read((char*)readbuffer, llclamp((S32) (READ_BUFFER*num_channels*bytes_per_sample), 0, data_left)); /* stereo hardwired here */ + long bytes = (long) instream.gcount(); if (bytes==0) { @@ -470,8 +470,8 @@ S32 encode_vorbis_file(const std::string& in_fname, const std::string& out_fname if(result==0) break; - outfile.write(og.header, og.header_len); - outfile.write(og.body, og.body_len); + outstream.write((char*)og.header, og.header_len); + outstream.write((char*)og.body, og.body_len); /* this could be set above, but for illustrative purposes, I do it here (to show that vorbis does know where the stream ends) */ @@ -498,7 +498,7 @@ S32 encode_vorbis_file(const std::string& in_fname, const std::string& out_fname libvorbis. They're never freed or manipulated directly */ // fprintf(stderr,"Vorbis encoding: Done.\n"); - llinfos << "Vorbis encoding: Done." << llendl; + LL_INFOS() << "Vorbis encoding: Done." << LL_ENDL; #endif return(LLVORBISENC_NOERR); diff --git a/indra/llcharacter/CMakeLists.txt b/indra/llcharacter/CMakeLists.txt index 6652333ef4..e95b924360 100644 --- a/indra/llcharacter/CMakeLists.txt +++ b/indra/llcharacter/CMakeLists.txt @@ -16,6 +16,10 @@ include_directories( ${LLVFS_INCLUDE_DIRS} ${LLXML_INCLUDE_DIRS} ) +include_directories(SYSTEM + ${LLCOMMON_SYSTEM_INCLUDE_DIRS} + ${LLXML_SYSTEM_INCLUDE_DIRS} + ) set(llcharacter_SOURCE_FILES llanimationstates.cpp @@ -29,7 +33,6 @@ set(llcharacter_SOURCE_FILES lljointsolverrp3.cpp llkeyframefallmotion.cpp llkeyframemotion.cpp - llkeyframemotionparam.cpp llkeyframestandmotion.cpp llkeyframewalkmotion.cpp llmotion.cpp @@ -57,7 +60,6 @@ set(llcharacter_HEADER_FILES lljointstate.h llkeyframefallmotion.h llkeyframemotion.h - llkeyframemotionparam.h llkeyframestandmotion.h llkeyframewalkmotion.h llmotion.h @@ -75,4 +77,9 @@ set_source_files_properties(${llcharacter_HEADER_FILES} list(APPEND llcharacter_SOURCE_FILES ${llcharacter_HEADER_FILES}) add_library (llcharacter ${llcharacter_SOURCE_FILES}) -add_dependencies(llcharacter prepare) + +target_link_libraries( + llcharacter + PUBLIC + llcommon + ) diff --git a/indra/llcharacter/llanimationstates.cpp b/indra/llcharacter/llanimationstates.cpp index 155226cf17..c16cae1bbc 100644 --- a/indra/llcharacter/llanimationstates.cpp +++ b/indra/llcharacter/llanimationstates.cpp @@ -46,7 +46,7 @@ LLUUID const ANIM_AGENT_BLOW_KISS ("db84829b-462c-ee83-1e27-9bbee66b LLUUID const ANIM_AGENT_BORED ("b906c4ba-703b-1940-32a3-0c7f7d791510"); LLUUID const ANIM_AGENT_BOW ("82e99230-c906-1403-4d9c-3889dd98daba"); LLUUID const ANIM_AGENT_BRUSH ("349a3801-54f9-bf2c-3bd0-1ac89772af01"); -LLUUID const ANIM_AGENT_BUSY ("efcf670c-2d18-8128-973a-034ebc806b67"); +LLUUID const ANIM_AGENT_DO_NOT_DISTURB ("efcf670c-2d18-8128-973a-034ebc806b67"); LLUUID const ANIM_AGENT_CLAP ("9b0c1c4e-8ac7-7969-1494-28c874c4f668"); LLUUID const ANIM_AGENT_COURTBOW ("9ba1c942-08be-e43a-fb29-16ad440efc50"); LLUUID const ANIM_AGENT_CROUCH ("201f3fdf-cb1f-dbec-201f-7333e328ae7c"); @@ -211,7 +211,7 @@ LLAnimationLibrary::LLAnimationLibrary() : mAnimMap[ANIM_AGENT_BORED]= mAnimStringTable.addString("express_bored"); mAnimMap[ANIM_AGENT_BOW]= mAnimStringTable.addString("bow"); mAnimMap[ANIM_AGENT_BRUSH]= mAnimStringTable.addString("brush"); - mAnimMap[ANIM_AGENT_BUSY]= mAnimStringTable.addString("busy"); + mAnimMap[ANIM_AGENT_DO_NOT_DISTURB]= mAnimStringTable.addString("busy"); mAnimMap[ANIM_AGENT_CLAP]= mAnimStringTable.addString("clap"); mAnimMap[ANIM_AGENT_COURTBOW]= mAnimStringTable.addString("courtbow"); mAnimMap[ANIM_AGENT_CROUCH]= mAnimStringTable.addString("crouch"); diff --git a/indra/llcharacter/llanimationstates.h b/indra/llcharacter/llanimationstates.h index aa6579ac8e..79cbcabdc1 100644 --- a/indra/llcharacter/llanimationstates.h +++ b/indra/llcharacter/llanimationstates.h @@ -29,7 +29,7 @@ #include -#include "string_table.h" +#include "llstringtable.h" #include "lluuid.h" //----------------------------------------------------------------------------- @@ -56,7 +56,7 @@ extern const LLUUID ANIM_AGENT_BLOW_KISS; extern const LLUUID ANIM_AGENT_BORED; extern const LLUUID ANIM_AGENT_BOW; extern const LLUUID ANIM_AGENT_BRUSH; -extern const LLUUID ANIM_AGENT_BUSY; +extern const LLUUID ANIM_AGENT_DO_NOT_DISTURB; extern const LLUUID ANIM_AGENT_CLAP; extern const LLUUID ANIM_AGENT_COURTBOW; extern const LLUUID ANIM_AGENT_CROUCH; diff --git a/indra/llcharacter/llbvhloader.cpp b/indra/llcharacter/llbvhloader.cpp index 2249d1622f..1c811a9244 100644 --- a/indra/llcharacter/llbvhloader.cpp +++ b/indra/llcharacter/llbvhloader.cpp @@ -35,10 +35,6 @@ #include "llkeyframemotion.h" #include "llquantize.h" #include "llstl.h" -#include "llapr.h" - - -//using namespace std; #define INCHES_TO_METERS 0.02540005f @@ -130,14 +126,14 @@ LLQuaternion::Order bvhStringToOrder( char *str ) if (mStatus == LLBVHLoader::ST_NO_XLT_FILE) { - llwarns << "NOTE: No translation table found." << llendl; + LL_WARNS() << "NOTE: No translation table found." << LL_ENDL; return; } else { if (mStatus != LLBVHLoader::ST_OK) { - llwarns << "ERROR: [line: " << getLineNumber() << "] " << mStatus << llendl; + LL_WARNS() << "ERROR: [line: " << getLineNumber() << "] " << mStatus << LL_ENDL; return; } } @@ -147,7 +143,7 @@ LLQuaternion::Order bvhStringToOrder( char *str ) mStatus = loadBVHFile(buffer, error_text, error_line); if (mStatus != LLBVHLoader::ST_OK) { - llwarns << "ERROR: [line: " << getLineNumber() << "] " << mStatus << llendl; + LL_WARNS() << "ERROR: [line: " << getLineNumber() << "] " << mStatus << LL_ENDL; return; } @@ -163,10 +159,10 @@ LLBVHLoader::LLBVHLoader(const char* buffer, ELoadStatus &loadStatus, S32 &error errorLine = 0; mStatus = loadTranslationTable("anim.ini"); loadStatus = mStatus; - llinfos<<"Load Status 00 : "<< loadStatus << llendl; + LL_INFOS() << "Load Status 00 : " << loadStatus << LL_ENDL; if (mStatus == E_ST_NO_XLT_FILE) { - //llwarns << "NOTE: No translation table found." << llendl; + //LL_WARNS() << "NOTE: No translation table found." << LL_ENDL; loadStatus = mStatus; return; } @@ -174,7 +170,7 @@ LLBVHLoader::LLBVHLoader(const char* buffer, ELoadStatus &loadStatus, S32 &error { if (mStatus != E_ST_OK) { - //llwarns << "ERROR: [line: " << getLineNumber() << "] " << mStatus << llendl; + //LL_WARNS() << "ERROR: [line: " << getLineNumber() << "] " << mStatus << LL_ENDL; errorLine = getLineNumber(); loadStatus = mStatus; return; @@ -187,7 +183,7 @@ LLBVHLoader::LLBVHLoader(const char* buffer, ELoadStatus &loadStatus, S32 &error if (mStatus != E_ST_OK) { - //llwarns << "ERROR: [line: " << getLineNumber() << "] " << mStatus << llendl; + //LL_WARNS() << "ERROR: [line: " << getLineNumber() << "] " << mStatus << LL_ENDL; loadStatus = mStatus; errorLine = getLineNumber(); return; @@ -219,12 +215,11 @@ ELoadStatus LLBVHLoader::loadTranslationTable(const char *fileName) //-------------------------------------------------------------------- std::string path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,fileName); - LLAPRFile infile(path, LL_APR_R); - apr_file_t *fp = infile.getFileHandle(); - if (!fp) + llifstream infstream(path); + if (!infstream.is_open()) return E_ST_NO_XLT_FILE; - llinfos << "NOTE: Loading translation table: " << fileName << llendl; + LL_INFOS() << "NOTE: Loading translation table: " << fileName << LL_ENDL; //-------------------------------------------------------------------- // register file to be closed on function exit @@ -233,7 +228,7 @@ ELoadStatus LLBVHLoader::loadTranslationTable(const char *fileName) //-------------------------------------------------------------------- // load header //-------------------------------------------------------------------- - if ( ! getLine(fp) ) + if ( ! getLine(infstream) ) return E_ST_EOF; if ( strncmp(mLine, "Translations 1.0", 16) ) return E_ST_NO_XLT_HEADER; @@ -243,7 +238,7 @@ ELoadStatus LLBVHLoader::loadTranslationTable(const char *fileName) //-------------------------------------------------------------------- BOOL loadingGlobals = FALSE; Translation *trans = NULL; - while ( getLine(fp) ) + while ( getLine(infstream) ) { //---------------------------------------------------------------- // check the 1st token on the line to determine if it's empty or a comment @@ -288,7 +283,7 @@ ELoadStatus LLBVHLoader::loadTranslationTable(const char *fileName) return E_ST_NO_XLT_EMOTE; mEmoteName.assign( emote_str ); -// llinfos << "NOTE: Emote: " << mEmoteName.c_str() << llendl; +// LL_INFOS() << "NOTE: Emote: " << mEmoteName.c_str() << LL_ENDL; continue; } @@ -303,7 +298,7 @@ ELoadStatus LLBVHLoader::loadTranslationTable(const char *fileName) return E_ST_NO_XLT_PRIORITY; mPriority = priority; -// llinfos << "NOTE: Priority: " << mPriority << llendl; +// LL_INFOS() << "NOTE: Priority: " << mPriority << LL_ENDL; continue; } @@ -660,7 +655,7 @@ ELoadStatus LLBVHLoader::loadTranslationTable(const char *fileName) } - infile.close() ; + infstream.close() ; return E_ST_OK; } @@ -696,7 +691,7 @@ ELoadStatus LLBVHLoader::loadBVHFile(const char *buffer, char* error_text, S32 & if ( !strstr(line.c_str(), "HIERARCHY") ) { -// llinfos << line << llendl; +// LL_INFOS() << line << LL_ENDL; return E_ST_NO_HIER; } @@ -1043,7 +1038,7 @@ void LLBVHLoader::applyTranslations() //---------------------------------------------------------------- if ( trans.mIgnore ) { - //llinfos << "NOTE: Ignoring " << joint->mName.c_str() << llendl; + //LL_INFOS() << "NOTE: Ignoring " << joint->mName.c_str() << LL_ENDL; joint->mIgnore = TRUE; continue; } @@ -1053,7 +1048,7 @@ void LLBVHLoader::applyTranslations() //---------------------------------------------------------------- if ( ! trans.mOutName.empty() ) { - //llinfos << "NOTE: Changing " << joint->mName.c_str() << " to " << trans.mOutName.c_str() << llendl; + //LL_INFOS() << "NOTE: Changing " << joint->mName.c_str() << " to " << trans.mOutName.c_str() << LL_ENDL; joint->mOutName = trans.mOutName; } @@ -1070,25 +1065,25 @@ void LLBVHLoader::applyTranslations() //---------------------------------------------------------------- if ( trans.mRelativePositionKey ) { -// llinfos << "NOTE: Removing 1st position offset from all keys for " << joint->mOutName.c_str() << llendl; +// LL_INFOS() << "NOTE: Removing 1st position offset from all keys for " << joint->mOutName.c_str() << LL_ENDL; joint->mRelativePositionKey = TRUE; } if ( trans.mRelativeRotationKey ) { -// llinfos << "NOTE: Removing 1st rotation from all keys for " << joint->mOutName.c_str() << llendl; +// LL_INFOS() << "NOTE: Removing 1st rotation from all keys for " << joint->mOutName.c_str() << LL_ENDL; joint->mRelativeRotationKey = TRUE; } if ( trans.mRelativePosition.magVec() > 0.0f ) { joint->mRelativePosition = trans.mRelativePosition; -// llinfos << "NOTE: Removing " << +// LL_INFOS() << "NOTE: Removing " << // joint->mRelativePosition.mV[0] << " " << // joint->mRelativePosition.mV[1] << " " << // joint->mRelativePosition.mV[2] << // " from all position keys in " << -// joint->mOutName.c_str() << llendl; +// joint->mOutName.c_str() << LL_ENDL; } //---------------------------------------------------------------- @@ -1102,9 +1097,9 @@ void LLBVHLoader::applyTranslations() //---------------------------------------------------------------- if ( ! trans.mMergeParentName.empty() ) { -// llinfos << "NOTE: Merging " << joint->mOutName.c_str() << +// LL_INFOS() << "NOTE: Merging " << joint->mOutName.c_str() << // " with parent " << -// trans.mMergeParentName.c_str() << llendl; +// trans.mMergeParentName.c_str() << LL_ENDL; joint->mMergeParentName = trans.mMergeParentName; } @@ -1113,8 +1108,8 @@ void LLBVHLoader::applyTranslations() //---------------------------------------------------------------- if ( ! trans.mMergeChildName.empty() ) { -// llinfos << "NOTE: Merging " << joint->mName.c_str() << -// " with child " << trans.mMergeChildName.c_str() << llendl; +// LL_INFOS() << "NOTE: Merging " << joint->mName.c_str() << +// " with child " << trans.mMergeChildName.c_str() << LL_ENDL; joint->mMergeChildName = trans.mMergeChildName; } @@ -1309,7 +1304,7 @@ void LLBVHLoader::optimize() // don't output joints with no motion if (!(pos_changed || rot_changed)) { - //llinfos << "Ignoring joint " << joint->mName << llendl; + //LL_INFOS() << "Ignoring joint " << joint->mName << LL_ENDL; joint->mIgnore = TRUE; } } @@ -1337,13 +1332,9 @@ void LLBVHLoader::reset() //------------------------------------------------------------------------ // LLBVHLoader::getLine() //------------------------------------------------------------------------ -BOOL LLBVHLoader::getLine(apr_file_t* fp) +BOOL LLBVHLoader::getLine(llifstream& stream) { - if (apr_file_eof(fp) == APR_EOF) - { - return FALSE; - } - if ( apr_file_gets(mLine, BVH_PARSER_LINE_SIZE, fp) == APR_SUCCESS) + if (stream.getline(mLine, BVH_PARSER_LINE_SIZE)) { mLineNumber++; return TRUE; diff --git a/indra/llcharacter/llbvhloader.h b/indra/llcharacter/llbvhloader.h index 38617bd6d4..d1c48e4469 100644 --- a/indra/llcharacter/llbvhloader.h +++ b/indra/llcharacter/llbvhloader.h @@ -2,31 +2,25 @@ * @file llbvhloader.h * @brief Translates a BVH files to LindenLabAnimation format. * - * $LicenseInfo:firstyear=2004&license=viewergpl$ - * - * Copyright (c) 2004-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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$ */ @@ -36,32 +30,11 @@ #include "v3math.h" #include "m3math.h" #include "llmath.h" -#include "llapr.h" #include "llbvhconsts.h" const S32 BVH_PARSER_LINE_SIZE = 2048; class LLDataPacker; -//------------------------------------------------------------------------ -// FileCloser -//------------------------------------------------------------------------ -class FileCloser -{ -public: - FileCloser( apr_file_t *file ) - { - mFile = file; - } - - ~FileCloser() - { - apr_file_close(mFile); - } -protected: - apr_file_t* mFile; -}; - - //------------------------------------------------------------------------ // Key //------------------------------------------------------------------------ @@ -304,7 +277,7 @@ class LLBVHLoader protected: // Consumes one line of input from file. - BOOL getLine(apr_file_t *fp); + BOOL getLine(llifstream& stream); // parser state char mLine[BVH_PARSER_LINE_SIZE]; /* Flawfinder: ignore */ diff --git a/indra/llcharacter/llcharacter.cpp b/indra/llcharacter/llcharacter.cpp index 888c20cd47..f2d2f0a95a 100644 --- a/indra/llcharacter/llcharacter.cpp +++ b/indra/llcharacter/llcharacter.cpp @@ -38,7 +38,6 @@ LLStringTable LLCharacter::sVisualParamNames(1024); std::vector< LLCharacter* > LLCharacter::sInstances; -BOOL LLCharacter::sAllowInstancesChange = TRUE ; //----------------------------------------------------------------------------- // LLCharacter() @@ -51,7 +50,6 @@ LLCharacter::LLCharacter() mAppearanceSerialNum( 0 ), mSkeletonSerialNum( 0 ) { - llassert_always(sAllowInstancesChange) ; sInstances.push_back(this); mMotionController.setCharacter( this ); @@ -72,21 +70,9 @@ LLCharacter::~LLCharacter() delete param; } - U32 i ; - U32 size = sInstances.size() ; - for(i = 0 ; i < size ; i++) - { - if(sInstances[i] == this) - { - break ; - } - } + bool erased = vector_replace_with_last(sInstances,this); - llassert_always(i < size) ; - - llassert_always(sAllowInstancesChange) ; - sInstances[i] = sInstances[size - 1] ; - sInstances.pop_back() ; + llassert_always(erased) ; } @@ -105,7 +91,7 @@ LLJoint *LLCharacter::getJoint( const std::string &name ) if (!joint) { - llwarns << "Failed to find joint." << llendl; + LL_WARNS() << "Failed to find joint." << LL_ENDL; } return joint; } @@ -136,7 +122,6 @@ LLMotion* LLCharacter::findMotion( const LLUUID &id ) //----------------------------------------------------------------------------- // createMotion() -// NOTE: Always assign the result to a LLPointer! //----------------------------------------------------------------------------- LLMotion* LLCharacter::createMotion( const LLUUID &id ) { @@ -180,27 +165,42 @@ BOOL LLCharacter::isMotionActive(const LLUUID& id) //----------------------------------------------------------------------------- void LLCharacter::requestStopMotion( LLMotion* motion) { -// llinfos << "DEBUG: Char::onDeactivateMotion( " << motionName << " )" << llendl; +// LL_INFOS() << "DEBUG: Char::onDeactivateMotion( " << motionName << " )" << LL_ENDL; } //----------------------------------------------------------------------------- // updateMotions() //----------------------------------------------------------------------------- -static LLFastTimer::DeclareTimer FTM_UPDATE_ANIMATION("Update Animation"); -static LLFastTimer::DeclareTimer FTM_UPDATE_HIDDEN_ANIMATION("Update Hidden Anim"); -static LLFastTimer::DeclareTimer FTM_UPDATE_MOTIONS("Update Motions"); +static LLTrace::BlockTimerStatHandle FTM_UPDATE_ANIMATION("Update Animation"); +static LLTrace::BlockTimerStatHandle FTM_UPDATE_HIDDEN_ANIMATION("Update Hidden Anim"); +static LLTrace::BlockTimerStatHandle FTM_UPDATE_MOTIONS("Update Motions"); void LLCharacter::updateMotions(e_update_t update_type) { if (update_type == HIDDEN_UPDATE) { - LLFastTimer t(FTM_UPDATE_HIDDEN_ANIMATION); + // + // Keep updating avatars that have at least one motion that is synchronized with a still running motion. + // This call tells the other controllers that we are in principle hidden. + // It returns false if we need to keep updating anyway. + if (!mMotionController.hidden(true)) + { + mMotionController.updateMotions(); + return; + } + // + LL_RECORD_BLOCK_TIME(FTM_UPDATE_HIDDEN_ANIMATION); mMotionController.updateMotionsMinimal(); } else { - LLFastTimer t(FTM_UPDATE_ANIMATION); + // + // This call tells the other controllers that we are visible and that they need + // to keep updating if they are synchronized with us, even if they are hidden. + mMotionController.hidden(false); + // + LL_RECORD_BLOCK_TIME(FTM_UPDATE_ANIMATION); // unpause if the number of outstanding pause requests has dropped to the initial one if (mMotionController.isPaused() && mPauseRequest->getNumRefs() == 1) { @@ -208,7 +208,7 @@ void LLCharacter::updateMotions(e_update_t update_type) } bool force_update = (update_type == FORCE_UPDATE); { - LLFastTimer t(FTM_UPDATE_MOTIONS); + LL_RECORD_BLOCK_TIME(FTM_UPDATE_MOTIONS); mMotionController.updateMotions(force_update); } } @@ -241,14 +241,14 @@ void LLCharacter::dumpCharacter( LLJoint* joint ) // handle top level entry into recursion if (joint == NULL) { - llinfos << "DEBUG: Dumping Character @" << this << llendl; + LL_INFOS() << "DEBUG: Dumping Character @" << this << LL_ENDL; dumpCharacter( getRootJoint() ); - llinfos << "DEBUG: Done." << llendl; + LL_INFOS() << "DEBUG: Done." << LL_ENDL; return; } // print joint info - llinfos << "DEBUG: " << joint->getName() << " (" << (joint->getParent()?joint->getParent()->getName():std::string("ROOT")) << ")" << llendl; + LL_INFOS() << "DEBUG: " << joint->getName() << " (" << (joint->getParent()?joint->getParent()->getName():std::string("ROOT")) << ")" << LL_ENDL; // recurse for (LLJoint::child_list_t::iterator iter = joint->mChildren.begin(); @@ -286,7 +286,7 @@ void LLCharacter::removeAnimationData(std::string name) //----------------------------------------------------------------------------- // setVisualParamWeight() //----------------------------------------------------------------------------- -BOOL LLCharacter::setVisualParamWeight(const LLVisualParam* which_param, F32 weight, BOOL upload_bake) +BOOL LLCharacter::setVisualParamWeight(const LLVisualParam* which_param, F32 weight, bool upload_bake) { S32 index = which_param->getID(); visual_param_index_map_t::iterator index_iter = mVisualParamIndexMap.find(index); @@ -301,7 +301,7 @@ BOOL LLCharacter::setVisualParamWeight(const LLVisualParam* which_param, F32 wei //----------------------------------------------------------------------------- // setVisualParamWeight() //----------------------------------------------------------------------------- -BOOL LLCharacter::setVisualParamWeight(const char* param_name, F32 weight, BOOL upload_bake) +BOOL LLCharacter::setVisualParamWeight(const char* param_name, F32 weight, bool upload_bake) { std::string tname(param_name); LLStringUtil::toLower(tname); @@ -312,14 +312,14 @@ BOOL LLCharacter::setVisualParamWeight(const char* param_name, F32 weight, BOOL name_iter->second->setWeight(weight, upload_bake); return TRUE; } - llwarns << "LLCharacter::setVisualParamWeight() Invalid visual parameter: " << param_name << llendl; + LL_WARNS() << "LLCharacter::setVisualParamWeight() Invalid visual parameter: " << param_name << LL_ENDL; return FALSE; } //----------------------------------------------------------------------------- // setVisualParamWeight() //----------------------------------------------------------------------------- -BOOL LLCharacter::setVisualParamWeight(S32 index, F32 weight, BOOL upload_bake) +BOOL LLCharacter::setVisualParamWeight(S32 index, F32 weight, bool upload_bake) { visual_param_index_map_t::iterator index_iter = mVisualParamIndexMap.find(index); if (index_iter != mVisualParamIndexMap.end()) @@ -327,7 +327,7 @@ BOOL LLCharacter::setVisualParamWeight(S32 index, F32 weight, BOOL upload_bake) index_iter->second->setWeight(weight, upload_bake); return TRUE; } - llwarns << "LLCharacter::setVisualParamWeight() Invalid visual parameter index: " << index << llendl; + LL_WARNS() << "LLCharacter::setVisualParamWeight() Invalid visual parameter index: " << index << LL_ENDL; return FALSE; } @@ -344,7 +344,7 @@ F32 LLCharacter::getVisualParamWeight(LLVisualParam *which_param) } else { - llwarns << "LLCharacter::getVisualParamWeight() Invalid visual parameter*, index= " << index << llendl; + LL_WARNS() << "LLCharacter::getVisualParamWeight() Invalid visual parameter*, index= " << index << LL_ENDL; return 0.f; } } @@ -362,7 +362,7 @@ F32 LLCharacter::getVisualParamWeight(const char* param_name) { return name_iter->second->getWeight(); } - llwarns << "LLCharacter::getVisualParamWeight() Invalid visual parameter: " << param_name << llendl; + LL_WARNS() << "LLCharacter::getVisualParamWeight() Invalid visual parameter: " << param_name << LL_ENDL; return 0.f; } @@ -378,7 +378,7 @@ F32 LLCharacter::getVisualParamWeight(S32 index) } else { - llwarns << "LLCharacter::getVisualParamWeight() Invalid visual parameter index: " << index << llendl; + LL_WARNS() << "LLCharacter::getVisualParamWeight() Invalid visual parameter index: " << index << LL_ENDL; return 0.f; } } @@ -433,7 +433,7 @@ LLVisualParam* LLCharacter::getVisualParam(const char *param_name) { return name_iter->second; } - llwarns << "LLCharacter::getVisualParam() Invalid visual parameter: " << param_name << llendl; + LL_WARNS() << "LLCharacter::getVisualParam() Invalid visual parameter: " << param_name << LL_ENDL; return NULL; } @@ -458,8 +458,8 @@ void LLCharacter::addSharedVisualParam(LLVisualParam *param) } else { - llwarns << "Shared visual parameter " << param->getName() << " does not already exist with ID " << - param->getID() << llendl; + LL_WARNS() << "Shared visual parameter " << param->getName() << " does not already exist with ID " << + param->getID() << LL_ENDL; } } @@ -475,8 +475,8 @@ void LLCharacter::addVisualParam(LLVisualParam *param) idxres = mVisualParamIndexMap.insert(visual_param_index_map_t::value_type(index, param)); if (!idxres.second) { - llwarns << "Visual parameter " << param->getName() << " already exists with same ID as " << - param->getName() << llendl; + LL_WARNS() << "Visual parameter " << param->getName() << " already exists with same ID as " << + param->getName() << LL_ENDL; visual_param_index_map_t::iterator index_iter = idxres.first; index_iter->second = param; } @@ -498,7 +498,7 @@ void LLCharacter::addVisualParam(LLVisualParam *param) name_iter->second = param; } } - //llinfos << "Adding Visual Param '" << param->getName() << "' ( " << index << " )" << llendl; + //LL_INFOS() << "Adding Visual Param '" << param->getName() << "' ( " << index << " )" << LL_ENDL; } //----------------------------------------------------------------------------- @@ -529,3 +529,17 @@ LLAnimPauseRequest LLCharacter::requestPause() return mPauseRequest; } +void LLCharacter::requestPause(std::vector& avatar_pause_handles) +{ + mMotionController.pauseAllMotions(); + avatar_pause_handles.push_back(mPauseRequest); +} + +void LLCharacter::pauseAllSyncedCharacters(std::vector& avatar_pause_handles) +{ + // Pause this avatar. + requestPause(avatar_pause_handles); + // Also pause all avatars with synchronized motions. + mMotionController.pauseAllSyncedCharacters(avatar_pause_handles); +} + diff --git a/indra/llcharacter/llcharacter.h b/indra/llcharacter/llcharacter.h index 2b872effa9..340b96a5e4 100644 --- a/indra/llcharacter/llcharacter.h +++ b/indra/llcharacter/llcharacter.h @@ -35,7 +35,7 @@ #include "lljoint.h" #include "llmotioncontroller.h" #include "llvisualparam.h" -#include "string_table.h" +#include "llstringtable.h" #include "llpointer.h" #include "llthread.h" #include "llsortedvector.h" @@ -146,6 +146,7 @@ class LLCharacter // is this motion active? BOOL isMotionActive( const LLUUID& id ); + bool isMotionActive(U32 bit) const { return mMotionController.isactive(bit); } // Event handler for motion deactivation. // Called when a motion has completely stopped and has been deactivated. @@ -158,6 +159,8 @@ class LLCharacter void updateMotions(e_update_t update_type); LLAnimPauseRequest requestPause(); + void requestPause(std::vector& avatar_pause_handles); + void pauseAllSyncedCharacters(std::vector& avatar_pause_handles); BOOL areAnimationsPaused() const { return mMotionController.isPaused(); } void setAnimTimeFactor(F32 factor) { mMotionController.setTimeFactor(factor); } void setTimeStep(F32 time_step) { mMotionController.setTimeStep(time_step); } @@ -179,7 +182,7 @@ class LLCharacter virtual LLVector3 getVolumePos(S32 joint_index, LLVector3& volume_offset) { return LLVector3::zero; } - virtual LLJoint* findCollisionVolume(U32 volume_id) { return NULL; } + virtual LLJoint* findCollisionVolume(S32 volume_id) { return NULL; } virtual S32 getCollisionVolumeID(std::string &name) { return -1; } @@ -192,9 +195,9 @@ class LLCharacter void addVisualParam(LLVisualParam *param); void addSharedVisualParam(LLVisualParam *param); - virtual BOOL setVisualParamWeight(const LLVisualParam *which_param, F32 weight, BOOL upload_bake = FALSE ); - virtual BOOL setVisualParamWeight(const char* param_name, F32 weight, BOOL upload_bake = FALSE ); - virtual BOOL setVisualParamWeight(S32 index, F32 weight, BOOL upload_bake = FALSE ); + virtual BOOL setVisualParamWeight(const LLVisualParam *which_param, F32 weight, bool upload_bake = false ); + virtual BOOL setVisualParamWeight(const char* param_name, F32 weight, bool upload_bake = false ); + virtual BOOL setVisualParamWeight(S32 index, F32 weight, bool upload_bake = false ); // get visual param weight by param or name F32 getVisualParamWeight(LLVisualParam *distortion); @@ -264,7 +267,9 @@ class LLCharacter void setSkeletonSerialNum( U32 num ) { mSkeletonSerialNum = num; } static std::vector< LLCharacter* > sInstances; - static BOOL sAllowInstancesChange ; //debug use + + virtual void setHoverOffset(const LLVector3& hover_offset, bool send_update=true) { mHoverOffset = hover_offset; } + const LLVector3& getHoverOffset() const { return mHoverOffset; } protected: LLMotionController mMotionController; @@ -290,6 +295,8 @@ class LLCharacter visual_param_index_map_t mVisualParamIndexMap; visual_param_name_map_t mVisualParamNameMap; static LLStringTable sVisualParamNames; + + LLVector3 mHoverOffset; }; #endif // LL_LLCHARACTER_H diff --git a/indra/llcharacter/lleditingmotion.cpp b/indra/llcharacter/lleditingmotion.cpp index cb283c9ecd..95580ac75d 100644 --- a/indra/llcharacter/lleditingmotion.cpp +++ b/indra/llcharacter/lleditingmotion.cpp @@ -49,7 +49,7 @@ S32 LLEditingMotion::sHandPosePriority = 3; // LLEditingMotion() // Class Constructor //----------------------------------------------------------------------------- -LLEditingMotion::LLEditingMotion( const LLUUID &id) : LLMotion(id) +LLEditingMotion::LLEditingMotion(LLUUID const& id, LLMotionController* controller) : AIMaskedMotion(id, controller, ANIM_AGENT_EDITING) { mCharacter = NULL; @@ -89,7 +89,7 @@ LLMotion::LLMotionInitStatus LLEditingMotion::onInitialize(LLCharacter *characte !mCharacter->getJoint("mElbowLeft") || !mCharacter->getJoint("mWristLeft")) { - llwarns << "Invalid skeleton for editing motion!" << llendl; + LL_WARNS() << "Invalid skeleton for editing motion!" << LL_ENDL; return STATUS_FAILURE; } @@ -102,7 +102,7 @@ LLMotion::LLMotionInitStatus LLEditingMotion::onInitialize(LLCharacter *characte if ( ! mParentState->getJoint() ) { - llinfos << getName() << ": Can't get parent joint." << llendl; + LL_INFOS() << getName() << ": Can't get parent joint." << LL_ENDL; return STATUS_FAILURE; } @@ -155,7 +155,7 @@ BOOL LLEditingMotion::onActivate() mShoulderJoint.setRotation( mShoulderState->getJoint()->getRotation() ); mElbowJoint.setRotation( mElbowState->getJoint()->getRotation() ); - return TRUE; + return AIMaskedMotion::onActivate(); } //----------------------------------------------------------------------------- @@ -214,13 +214,23 @@ BOOL LLEditingMotion::onUpdate(F32 time, U8* joint_mask) target = target * target_dist; if (!target.isFinite()) { - llwarns << "Non finite target in editing motion with target distance of " << target_dist << - " and focus point " << focus_pt << " and pointAtPt: " << *pointAtPt << llendl; + LL_WARNS() << "Non finite target in editing motion with target distance of " << target_dist << + " and focus point " << focus_pt << " and pointAtPt: "; + if (pointAtPt) + { + LL_CONT << *pointAtPt; + } + else + { + LL_CONT << "NULL"; + } + LL_CONT << LL_ENDL; + target.setVec(1.f, 1.f, 1.f); } mTarget.setPosition( target + mParentJoint.getPosition()); -// llinfos << "Point At: " << mTarget.getPosition() << llendl; +// LL_INFOS() << "Point At: " << mTarget.getPosition() << LL_ENDL; // update the ikSolver if (!mTarget.getPosition().isExactlyZero()) @@ -230,7 +240,7 @@ BOOL LLEditingMotion::onUpdate(F32 time, U8* joint_mask) mIKSolver.solve(); // use blending... - F32 slerp_amt = LLCriticalDamp::getInterpolant(TARGET_LAG_HALF_LIFE); + F32 slerp_amt = LLSmoothInterpolation::getInterpolant(TARGET_LAG_HALF_LIFE); shoulderRot = slerp(slerp_amt, mShoulderJoint.getRotation(), shoulderRot); elbowRot = slerp(slerp_amt, mElbowJoint.getRotation(), elbowRot); @@ -247,12 +257,4 @@ BOOL LLEditingMotion::onUpdate(F32 time, U8* joint_mask) return result; } -//----------------------------------------------------------------------------- -// LLEditingMotion::onDeactivate() -//----------------------------------------------------------------------------- -void LLEditingMotion::onDeactivate() -{ -} - - // End diff --git a/indra/llcharacter/lleditingmotion.h b/indra/llcharacter/lleditingmotion.h index 4a83d4b9fb..b06d2b7749 100644 --- a/indra/llcharacter/lleditingmotion.h +++ b/indra/llcharacter/lleditingmotion.h @@ -49,15 +49,25 @@ // class LLEditingMotion //----------------------------------------------------------------------------- class LLEditingMotion : - public LLMotion + public AIMaskedMotion { public: // Constructor - LLEditingMotion(const LLUUID &id); + LLEditingMotion(LLUUID const& id, LLMotionController* controller); // Destructor virtual ~LLEditingMotion(); + void* operator new(size_t size) + { + return ll_aligned_malloc_16(size); + } + + void operator delete(void* ptr) + { + ll_aligned_free_16(ptr); + } + public: //------------------------------------------------------------------------- // functions to support MotionController and MotionRegistry @@ -65,7 +75,7 @@ class LLEditingMotion : // static constructor // all subclasses must implement such a function and register it - static LLMotion *create(const LLUUID &id) { return new LLEditingMotion(id); } + static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLEditingMotion(id, controller); } public: //------------------------------------------------------------------------- @@ -107,9 +117,6 @@ class LLEditingMotion : // must return FALSE when the motion is completed. virtual BOOL onUpdate(F32 time, U8* joint_mask); - // called when a motion is deactivated - virtual void onDeactivate(); - public: //------------------------------------------------------------------------- // joint states to be animated diff --git a/indra/llcharacter/llgesture.cpp b/indra/llcharacter/llgesture.cpp index c23694639e..dd68622fb7 100644 --- a/indra/llcharacter/llgesture.cpp +++ b/indra/llcharacter/llgesture.cpp @@ -93,14 +93,14 @@ const LLGesture &LLGesture::operator =(const LLGesture &rhs) BOOL LLGesture::trigger(KEY key, MASK mask) { - llwarns << "Parent class trigger called: you probably didn't mean this." << llendl; + LL_WARNS() << "Parent class trigger called: you probably didn't mean this." << LL_ENDL; return FALSE; } BOOL LLGesture::trigger(const std::string& trigger_string) { - llwarns << "Parent class trigger called: you probably didn't mean this." << llendl; + LL_WARNS() << "Parent class trigger called: you probably didn't mean this." << LL_ENDL; return FALSE; } @@ -130,7 +130,7 @@ U8 *LLGesture::deserialize(U8 *buffer, S32 max_size) if (tmp + sizeof(mKey) + sizeof(mMask) + 16 > buffer + max_size) { - llwarns << "Attempt to read past end of buffer, bad data!!!!" << llendl; + LL_WARNS() << "Attempt to read past end of buffer, bad data!!!!" << LL_ENDL; return buffer; } @@ -155,7 +155,7 @@ U8 *LLGesture::deserialize(U8 *buffer, S32 max_size) if (tmp > buffer + max_size) { - llwarns << "Read past end of buffer, bad data!!!!" << llendl; + LL_WARNS() << "Read past end of buffer, bad data!!!!" << LL_ENDL; return tmp; } @@ -173,27 +173,7 @@ S32 LLGesture::getMaxSerialSize() LLGestureList::LLGestureList() : mList(0) -{ - // add some gestures for debugging -// LLGesture *gesture = NULL; -/* - gesture = new LLGesture(KEY_F2, MASK_NONE, ":-)", - SND_CHIRP, "dance2", ":-)" ); - mList.put(gesture); - - gesture = new LLGesture(KEY_F3, MASK_NONE, "/dance", - SND_OBJECT_CREATE, "dance3", "(dances)" ); - mList.put(gesture); - - gesture = new LLGesture(KEY_F4, MASK_NONE, "/boogie", - LLUUID::null, "dance4", LLStringUtil::null ); - mList.put(gesture); - - gesture = new LLGesture(KEY_F5, MASK_SHIFT, "/tongue", - LLUUID::null, "Express_Tongue_Out", LLStringUtil::null ); - mList.put(gesture); - */ -} +{} LLGestureList::~LLGestureList() { @@ -203,12 +183,7 @@ LLGestureList::~LLGestureList() void LLGestureList::deleteAll() { - S32 count = mList.count(); - for (S32 i = 0; i < count; i++) - { - delete mList.get(i); - } - mList.reset(); + delete_and_clear(mList); } // Iterates through space delimited tokens in string, triggering any gestures found. @@ -235,9 +210,9 @@ BOOL LLGestureList::triggerAndReviseString(const std::string &string, std::strin std::string cur_token_lower = *token_iter; LLStringUtil::toLower(cur_token_lower); - for (S32 i = 0; i < mList.count(); i++) + for (U32 i = 0; i < mList.size(); i++) { - gesture = mList.get(i); + gesture = mList.at(i); if (gesture->trigger(cur_token_lower)) { if( !gesture->getOutputString().empty() ) @@ -286,9 +261,9 @@ BOOL LLGestureList::triggerAndReviseString(const std::string &string, std::strin BOOL LLGestureList::trigger(KEY key, MASK mask) { - for (S32 i = 0; i < mList.count(); i++) + for (U32 i = 0; i < mList.size(); i++) { - LLGesture* gesture = mList.get(i); + LLGesture* gesture = mList.at(i); if( gesture ) { if (gesture->trigger(key, mask)) @@ -298,7 +273,7 @@ BOOL LLGestureList::trigger(KEY key, MASK mask) } else { - llwarns << "NULL gesture in gesture list (" << i << ")" << llendl; + LL_WARNS() << "NULL gesture in gesture list (" << i << ")" << LL_ENDL; } } return FALSE; @@ -308,11 +283,11 @@ BOOL LLGestureList::trigger(KEY key, MASK mask) U8 *LLGestureList::serialize(U8 *buffer) const { // a single S32 serves as the header that tells us how many to read - S32 count = mList.count(); + U32 count = mList.size(); htonmemcpy(buffer, &count, MVT_S32, 4); buffer += sizeof(count); - for (S32 i = 0; i < count; i++) + for (U32 i = 0; i < count; i++) { buffer = mList[i]->serialize(buffer); } @@ -331,7 +306,7 @@ U8 *LLGestureList::deserialize(U8 *buffer, S32 max_size) if (tmp + sizeof(count) > buffer + max_size) { - llwarns << "Invalid max_size" << llendl; + LL_WARNS() << "Invalid max_size" << LL_ENDL; return buffer; } @@ -339,20 +314,20 @@ U8 *LLGestureList::deserialize(U8 *buffer, S32 max_size) if (count > MAX_GESTURES) { - llwarns << "Unreasonably large gesture list count in deserialize: " << count << llendl; + LL_WARNS() << "Unreasonably large gesture list count in deserialize: " << count << LL_ENDL; return tmp; } tmp += sizeof(count); - mList.reserve_block(count); + mList.resize(count); for (S32 i = 0; i < count; i++) { mList[i] = create_gesture(&tmp, max_size - (S32)(tmp - buffer)); if (tmp - buffer > max_size) { - llwarns << "Deserialization read past end of buffer, bad data!!!!" << llendl; + LL_WARNS() << "Deserialization read past end of buffer, bad data!!!!" << LL_ENDL; return tmp; } } diff --git a/indra/llcharacter/llgesture.h b/indra/llcharacter/llgesture.h index 66b618c473..f2a2d95b06 100644 --- a/indra/llcharacter/llgesture.h +++ b/indra/llcharacter/llgesture.h @@ -31,7 +31,6 @@ #include "llanimationstates.h" #include "lluuid.h" #include "llstring.h" -#include "lldarray.h" class LLGesture { @@ -91,9 +90,9 @@ class LLGestureList BOOL triggerAndReviseString(const std::string &string, std::string* revised_string); // Used for construction from UI - S32 count() const { return mList.count(); } - virtual LLGesture* get(S32 i) const { return mList.get(i); } - virtual void put(LLGesture* gesture) { mList.put( gesture ); } + S32 count() const { return mList.size(); } + virtual LLGesture* get(S32 i) const { return mList.at(i); } + virtual void put(LLGesture* gesture) { mList.push_back( gesture ); } void deleteAll(); // non-endian-neutral serialization @@ -106,7 +105,7 @@ class LLGestureList virtual LLGesture *create_gesture(U8 **buffer, S32 max_size); protected: - LLDynamicArray mList; + std::vector mList; static const S32 SERIAL_HEADER_SIZE; }; diff --git a/indra/llcharacter/llhandmotion.cpp b/indra/llcharacter/llhandmotion.cpp index 696dba0d95..793393dfa8 100644 --- a/indra/llcharacter/llhandmotion.cpp +++ b/indra/llcharacter/llhandmotion.cpp @@ -61,7 +61,7 @@ const F32 HAND_MORPH_BLEND_TIME = 0.2f; // LLHandMotion() // Class Constructor //----------------------------------------------------------------------------- -LLHandMotion::LLHandMotion(const LLUUID &id) : LLMotion(id) +LLHandMotion::LLHandMotion(LLUUID const& id, LLMotionController* controller) : AIMaskedMotion(id, controller, ANIM_AGENT_HAND_MOTION) { mCharacter = NULL; mLastTime = 0.f; @@ -112,7 +112,7 @@ BOOL LLHandMotion::onActivate() mCharacter->setVisualParamWeight(gHandPoseNames[mCurrentPose], 1.f); mCharacter->updateVisualParams(); } - return TRUE; + return AIMaskedMotion::onActivate(); } @@ -192,7 +192,7 @@ BOOL LLHandMotion::onUpdate(F32 time, U8* joint_mask) } else { - llwarns << "Requested hand pose out of range. Ignoring requested pose." << llendl; + LL_WARNS() << "Requested hand pose out of range. Ignoring requested pose." << LL_ENDL; } } @@ -200,7 +200,7 @@ BOOL LLHandMotion::onUpdate(F32 time, U8* joint_mask) mCharacter->removeAnimationData("Hand Pose Priority"); // if (requestedHandPose) -// llinfos << "Hand Pose " << *requestedHandPose << llendl; +// LL_INFOS() << "Hand Pose " << *requestedHandPose << LL_ENDL; // if we are still blending... if (mCurrentPose != mNewPose) @@ -235,14 +235,6 @@ BOOL LLHandMotion::onUpdate(F32 time, U8* joint_mask) return TRUE; } - -//----------------------------------------------------------------------------- -// LLHandMotion::onDeactivate() -//----------------------------------------------------------------------------- -void LLHandMotion::onDeactivate() -{ -} - //----------------------------------------------------------------------------- // LLHandMotion::getHandPoseName() //----------------------------------------------------------------------------- diff --git a/indra/llcharacter/llhandmotion.h b/indra/llcharacter/llhandmotion.h index dcf169662c..012c3c6bed 100644 --- a/indra/llcharacter/llhandmotion.h +++ b/indra/llcharacter/llhandmotion.h @@ -45,7 +45,7 @@ // class LLHandMotion //----------------------------------------------------------------------------- class LLHandMotion : - public LLMotion + public AIMaskedMotion { public: typedef enum e_hand_pose @@ -68,7 +68,7 @@ class LLHandMotion : } eHandPose; // Constructor - LLHandMotion(const LLUUID &id); + LLHandMotion(LLUUID const& id, LLMotionController* controller); // Destructor virtual ~LLHandMotion(); @@ -80,7 +80,7 @@ class LLHandMotion : // static constructor // all subclasses must implement such a function and register it - static LLMotion *create(const LLUUID &id) { return new LLHandMotion(id); } + static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLHandMotion(id, controller); } public: //------------------------------------------------------------------------- @@ -122,9 +122,6 @@ class LLHandMotion : // must return FALSE when the motion is completed. virtual BOOL onUpdate(F32 time, U8* joint_mask); - // called when a motion is deactivated - virtual void onDeactivate(); - virtual BOOL canDeprecate() { return FALSE; } static std::string getHandPoseName(eHandPose pose); diff --git a/indra/llcharacter/llheadrotmotion.cpp b/indra/llcharacter/llheadrotmotion.cpp index 0ee378f3b8..0f11bd2951 100644 --- a/indra/llcharacter/llheadrotmotion.cpp +++ b/indra/llcharacter/llheadrotmotion.cpp @@ -76,17 +76,18 @@ const F32 EYE_BLINK_TIME_DELTA = 0.005f; // time between one eye starting a blin // LLHeadRotMotion() // Class Constructor //----------------------------------------------------------------------------- -LLHeadRotMotion::LLHeadRotMotion(const LLUUID &id) : - LLMotion(id), +LLHeadRotMotion::LLHeadRotMotion(LLUUID const& id, LLMotionController* controller) : + AIMaskedMotion(id, controller, ANIM_AGENT_HEAD_ROT), mCharacter(NULL), mTorsoJoint(NULL), - mHeadJoint(NULL) + mHeadJoint(NULL), + mRootJoint(NULL), + mPelvisJoint(NULL), + mHeadState(new LLJointState), + mTorsoState(new LLJointState), + mNeckState(new LLJointState) { mName = "head_rot"; - - mTorsoState = new LLJointState; - mNeckState = new LLJointState; - mHeadState = new LLJointState; } @@ -104,55 +105,58 @@ LLHeadRotMotion::~LLHeadRotMotion() LLMotion::LLMotionInitStatus LLHeadRotMotion::onInitialize(LLCharacter *character) { if (!character) + { + LL_WARNS() << "character is NULL." << LL_ENDL; return STATUS_FAILURE; + } mCharacter = character; mPelvisJoint = character->getJoint("mPelvis"); if ( ! mPelvisJoint ) { - llinfos << getName() << ": Can't get pelvis joint." << llendl; + LL_INFOS() << getName() << ": Can't get pelvis joint." << LL_ENDL; return STATUS_FAILURE; } mRootJoint = character->getJoint("mRoot"); if ( ! mRootJoint ) { - llinfos << getName() << ": Can't get root joint." << llendl; + LL_INFOS() << getName() << ": Can't get root joint." << LL_ENDL; return STATUS_FAILURE; } mTorsoJoint = character->getJoint("mTorso"); if ( ! mTorsoJoint ) { - llinfos << getName() << ": Can't get torso joint." << llendl; + LL_INFOS() << getName() << ": Can't get torso joint." << LL_ENDL; return STATUS_FAILURE; } mHeadJoint = character->getJoint("mHead"); if ( ! mHeadJoint ) { - llinfos << getName() << ": Can't get head joint." << llendl; + LL_INFOS() << getName() << ": Can't get head joint." << LL_ENDL; return STATUS_FAILURE; } mTorsoState->setJoint( character->getJoint("mTorso") ); if ( ! mTorsoState->getJoint() ) { - llinfos << getName() << ": Can't get torso joint." << llendl; + LL_INFOS() << getName() << ": Can't get torso joint." << LL_ENDL; return STATUS_FAILURE; } mNeckState->setJoint( character->getJoint("mNeck") ); if ( ! mNeckState->getJoint() ) { - llinfos << getName() << ": Can't get neck joint." << llendl; + LL_INFOS() << getName() << ": Can't get neck joint." << LL_ENDL; return STATUS_FAILURE; } mHeadState->setJoint( character->getJoint("mHead") ); if ( ! mHeadState->getJoint() ) { - llinfos << getName() << ": Can't get head joint." << llendl; + LL_INFOS() << getName() << ": Can't get head joint." << LL_ENDL; return STATUS_FAILURE; } @@ -169,16 +173,6 @@ LLMotion::LLMotionInitStatus LLHeadRotMotion::onInitialize(LLCharacter *characte return STATUS_SUCCESS; } - -//----------------------------------------------------------------------------- -// LLHeadRotMotion::onActivate() -//----------------------------------------------------------------------------- -BOOL LLHeadRotMotion::onActivate() -{ - return TRUE; -} - - //----------------------------------------------------------------------------- // LLHeadRotMotion::onUpdate() //----------------------------------------------------------------------------- @@ -188,8 +182,8 @@ BOOL LLHeadRotMotion::onUpdate(F32 time, U8* joint_mask) LLQuaternion currentRootRotWorld = mRootJoint->getWorldRotation(); LLQuaternion currentInvRootRotWorld = ~currentRootRotWorld; - F32 head_slerp_amt = LLCriticalDamp::getInterpolant(HEAD_LOOKAT_LAG_HALF_LIFE); - F32 torso_slerp_amt = LLCriticalDamp::getInterpolant(TORSO_LOOKAT_LAG_HALF_LIFE); + F32 head_slerp_amt = LLSmoothInterpolation::getInterpolant(HEAD_LOOKAT_LAG_HALF_LIFE); + F32 torso_slerp_amt = LLSmoothInterpolation::getInterpolant(TORSO_LOOKAT_LAG_HALF_LIFE); LLVector3* targetPos = (LLVector3*)mCharacter->getAnimationData("LookAtPoint"); @@ -197,7 +191,7 @@ BOOL LLHeadRotMotion::onUpdate(F32 time, U8* joint_mask) { LLVector3 headLookAt = *targetPos; -// llinfos << "Look At: " << headLookAt + mHeadJoint->getWorldPosition() << llendl; +// LL_INFOS() << "Look At: " << headLookAt + mHeadJoint->getWorldPosition() << LL_ENDL; F32 lookatDistance = headLookAt.normVec(); @@ -263,19 +257,11 @@ BOOL LLHeadRotMotion::onUpdate(F32 time, U8* joint_mask) } -//----------------------------------------------------------------------------- -// LLHeadRotMotion::onDeactivate() -//----------------------------------------------------------------------------- -void LLHeadRotMotion::onDeactivate() -{ -} - - //----------------------------------------------------------------------------- // LLEyeMotion() // Class Constructor //----------------------------------------------------------------------------- -LLEyeMotion::LLEyeMotion(const LLUUID &id) : LLMotion(id) +LLEyeMotion::LLEyeMotion(LLUUID const& id, LLMotionController* controller) : AIMaskedMotion(id, controller, ANIM_AGENT_EYE) { mCharacter = NULL; mEyeJitterTime = 0.f; @@ -294,7 +280,9 @@ LLEyeMotion::LLEyeMotion(const LLUUID &id) : LLMotion(id) mName = "eye_rot"; mLeftEyeState = new LLJointState; + mAltLeftEyeState = new LLJointState; mRightEyeState = new LLJointState; + mAltRightEyeState = new LLJointState; } @@ -316,53 +304,146 @@ LLMotion::LLMotionInitStatus LLEyeMotion::onInitialize(LLCharacter *character) mHeadJoint = character->getJoint("mHead"); if ( ! mHeadJoint ) { - llinfos << getName() << ": Can't get head joint." << llendl; + LL_INFOS() << getName() << ": Can't get head joint." << LL_ENDL; return STATUS_FAILURE; } mLeftEyeState->setJoint( character->getJoint("mEyeLeft") ); if ( ! mLeftEyeState->getJoint() ) { - llinfos << getName() << ": Can't get left eyeball joint." << llendl; + LL_INFOS() << getName() << ": Can't get left eyeball joint." << LL_ENDL; + return STATUS_FAILURE; + } + + mAltLeftEyeState->setJoint( character->getJoint("mFaceEyeAltLeft") ); + if ( ! mAltLeftEyeState->getJoint() ) + { + LL_INFOS() << getName() << ": Can't get alt left eyeball joint." << LL_ENDL; return STATUS_FAILURE; } mRightEyeState->setJoint( character->getJoint("mEyeRight") ); if ( ! mRightEyeState->getJoint() ) { - llinfos << getName() << ": Can't get Right eyeball joint." << llendl; + LL_INFOS() << getName() << ": Can't get right eyeball joint." << LL_ENDL; + return STATUS_FAILURE; + } + + mAltRightEyeState->setJoint( character->getJoint("mFaceEyeAltRight") ); + if ( ! mAltRightEyeState->getJoint() ) + { + LL_INFOS() << getName() << ": Can't get alt right eyeball joint." << LL_ENDL; return STATUS_FAILURE; } mLeftEyeState->setUsage(LLJointState::ROT); + mAltLeftEyeState->setUsage(LLJointState::ROT); + mRightEyeState->setUsage(LLJointState::ROT); + mAltRightEyeState->setUsage(LLJointState::ROT); addJointState( mLeftEyeState ); + addJointState( mAltLeftEyeState ); + addJointState( mRightEyeState ); + addJointState( mAltRightEyeState ); return STATUS_SUCCESS; } //----------------------------------------------------------------------------- -// LLEyeMotion::onActivate() +// LLEyeMotion::adjustEyeTarget() //----------------------------------------------------------------------------- -BOOL LLEyeMotion::onActivate() +void LLEyeMotion::adjustEyeTarget(LLVector3* targetPos, LLJointState& left_eye_state, LLJointState& right_eye_state) { - return TRUE; -} + // Compute eye rotation. + BOOL has_eye_target = FALSE; + LLQuaternion target_eye_rot; + LLVector3 eye_look_at; + F32 vergence; + + if (targetPos) + { + LLVector3 skyward(0.f, 0.f, 1.f); + LLVector3 left; + LLVector3 up; + + eye_look_at = *targetPos; + has_eye_target = TRUE; + F32 lookAtDistance = eye_look_at.normVec(); + + left.setVec(skyward % eye_look_at); + up.setVec(eye_look_at % left); + + target_eye_rot = LLQuaternion(eye_look_at, left, up); + // convert target rotation to head-local coordinates + target_eye_rot *= ~mHeadJoint->getWorldRotation(); + // eliminate any Euler roll - we're lucky that roll is applied last. + F32 roll, pitch, yaw; + target_eye_rot.getEulerAngles(&roll, &pitch, &yaw); + target_eye_rot.setQuat(0.0f, pitch, yaw); + // constrain target orientation to be in front of avatar's face + target_eye_rot.constrain(EYE_ROT_LIMIT_ANGLE); + + // calculate vergence + F32 interocular_dist = (left_eye_state.getJoint()->getWorldPosition() - right_eye_state.getJoint()->getWorldPosition()).magVec(); + vergence = -atan2((interocular_dist / 2.f), lookAtDistance); + vergence = llclamp(vergence, -F_PI_BY_TWO, 0.f); + } + else + { + target_eye_rot = LLQuaternion::DEFAULT; + vergence = 0.f; + } + + //RN: subtract 4 degrees to account for foveal angular offset relative to pupil + vergence += 4.f * DEG_TO_RAD; + + // calculate eye jitter + LLQuaternion eye_jitter_rot; + + // vergence not too high... + if (vergence > -0.05f) + { + //...go ahead and jitter + eye_jitter_rot.setQuat(0.f, mEyeJitterPitch + mEyeLookAwayPitch, mEyeJitterYaw + mEyeLookAwayYaw); + } + else + { + //...or don't + eye_jitter_rot.loadIdentity(); + } + + // calculate vergence of eyes as an object gets closer to the avatar's head + LLQuaternion vergence_quat; + + if (has_eye_target) + { + vergence_quat.setQuat(vergence, LLVector3(0.f, 0.f, 1.f)); + } + else + { + vergence_quat.loadIdentity(); + } + // calculate eye rotations + LLQuaternion left_eye_rot = target_eye_rot; + left_eye_rot = vergence_quat * eye_jitter_rot * left_eye_rot; + + LLQuaternion right_eye_rot = target_eye_rot; + vergence_quat.transQuat(); + right_eye_rot = vergence_quat * eye_jitter_rot * right_eye_rot; + + left_eye_state.setRotation( left_eye_rot ); + right_eye_state.setRotation( right_eye_rot ); +} //----------------------------------------------------------------------------- // LLEyeMotion::onUpdate() //----------------------------------------------------------------------------- BOOL LLEyeMotion::onUpdate(F32 time, U8* joint_mask) { - // Compute eye rotation. - LLQuaternion target_eye_rot; - LLVector3 eye_look_at; - F32 vergence; - //calculate jitter if (mEyeJitterTimer.getElapsedTimeF32() > mEyeJitterTime) { @@ -435,83 +516,10 @@ BOOL LLEyeMotion::onUpdate(F32 time, U8* joint_mask) } } - BOOL has_eye_target = FALSE; LLVector3* targetPos = (LLVector3*)mCharacter->getAnimationData("LookAtPoint"); - if (targetPos) - { - LLVector3 skyward(0.f, 0.f, 1.f); - LLVector3 left; - LLVector3 up; - - eye_look_at = *targetPos; - has_eye_target = TRUE; - F32 lookAtDistance = eye_look_at.normVec(); - - left.setVec(skyward % eye_look_at); - up.setVec(eye_look_at % left); - - target_eye_rot = LLQuaternion(eye_look_at, left, up); - // convert target rotation to head-local coordinates - target_eye_rot *= ~mHeadJoint->getWorldRotation(); - // eliminate any Euler roll - we're lucky that roll is applied last. - F32 roll, pitch, yaw; - target_eye_rot.getEulerAngles(&roll, &pitch, &yaw); - target_eye_rot.setQuat(0.0f, pitch, yaw); - // constrain target orientation to be in front of avatar's face - target_eye_rot.constrain(EYE_ROT_LIMIT_ANGLE); - - // calculate vergence - F32 interocular_dist = (mLeftEyeState->getJoint()->getWorldPosition() - mRightEyeState->getJoint()->getWorldPosition()).magVec(); - vergence = -atan2((interocular_dist / 2.f), lookAtDistance); - llclamp(vergence, -F_PI_BY_TWO, 0.f); - } - else - { - target_eye_rot = LLQuaternion::DEFAULT; - vergence = 0.f; - } - - //RN: subtract 4 degrees to account for foveal angular offset relative to pupil - vergence += 4.f * DEG_TO_RAD; - - // calculate eye jitter - LLQuaternion eye_jitter_rot; - - // vergence not too high... - if (vergence > -0.05f) - { - //...go ahead and jitter - eye_jitter_rot.setQuat(0.f, mEyeJitterPitch + mEyeLookAwayPitch, mEyeJitterYaw + mEyeLookAwayYaw); - } - else - { - //...or don't - eye_jitter_rot.loadIdentity(); - } - - // calculate vergence of eyes as an object gets closer to the avatar's head - LLQuaternion vergence_quat; - - if (has_eye_target) - { - vergence_quat.setQuat(vergence, LLVector3(0.f, 0.f, 1.f)); - } - else - { - vergence_quat.loadIdentity(); - } - - // calculate eye rotations - LLQuaternion left_eye_rot = target_eye_rot; - left_eye_rot = vergence_quat * eye_jitter_rot * left_eye_rot; - - LLQuaternion right_eye_rot = target_eye_rot; - vergence_quat.transQuat(); - right_eye_rot = vergence_quat * eye_jitter_rot * right_eye_rot; - - mLeftEyeState->setRotation( left_eye_rot ); - mRightEyeState->setRotation( right_eye_rot ); + adjustEyeTarget(targetPos, *mLeftEyeState, *mRightEyeState); + adjustEyeTarget(targetPos, *mAltLeftEyeState, *mAltRightEyeState); return TRUE; } @@ -528,11 +536,25 @@ void LLEyeMotion::onDeactivate() joint->setRotation(LLQuaternion::DEFAULT); } + joint = mAltLeftEyeState->getJoint(); + if (joint) + { + joint->setRotation(LLQuaternion::DEFAULT); + } + joint = mRightEyeState->getJoint(); if (joint) { joint->setRotation(LLQuaternion::DEFAULT); } + + joint = mAltRightEyeState->getJoint(); + if (joint) + { + joint->setRotation(LLQuaternion::DEFAULT); + } + + AIMaskedMotion::onDeactivate(); } // End diff --git a/indra/llcharacter/llheadrotmotion.h b/indra/llcharacter/llheadrotmotion.h index 97e61eac12..9b00c4c4cd 100644 --- a/indra/llcharacter/llheadrotmotion.h +++ b/indra/llcharacter/llheadrotmotion.h @@ -46,11 +46,11 @@ // class LLHeadRotMotion //----------------------------------------------------------------------------- class LLHeadRotMotion : - public LLMotion + public AIMaskedMotion { public: // Constructor - LLHeadRotMotion(const LLUUID &id); + LLHeadRotMotion(LLUUID const& id, LLMotionController* controller); // Destructor virtual ~LLHeadRotMotion(); @@ -62,7 +62,7 @@ class LLHeadRotMotion : // static constructor // all subclasses must implement such a function and register it - static LLMotion *create(const LLUUID &id) { return new LLHeadRotMotion(id); } + static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLHeadRotMotion(id, controller); } public: //------------------------------------------------------------------------- @@ -94,19 +94,11 @@ class LLHeadRotMotion : // must return true to indicate success and be available for activation virtual LLMotionInitStatus onInitialize(LLCharacter *character); - // called when a motion is activated - // must return TRUE to indicate success, or else - // it will be deactivated - virtual BOOL onActivate(); - // called per time step // must return TRUE while it is active, and // must return FALSE when the motion is completed. virtual BOOL onUpdate(F32 time, U8* joint_mask); - // called when a motion is deactivated - virtual void onDeactivate(); - public: //------------------------------------------------------------------------- // joint states to be animated @@ -129,11 +121,11 @@ class LLHeadRotMotion : // class LLEyeMotion //----------------------------------------------------------------------------- class LLEyeMotion : - public LLMotion + public AIMaskedMotion { public: // Constructor - LLEyeMotion(const LLUUID &id); + LLEyeMotion(LLUUID const& id, LLMotionController* controller); // Destructor virtual ~LLEyeMotion(); @@ -145,7 +137,7 @@ class LLEyeMotion : // static constructor // all subclasses must implement such a function and register it - static LLMotion *create( const LLUUID &id) { return new LLEyeMotion(id); } + static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLEyeMotion(id, controller); } public: //------------------------------------------------------------------------- @@ -177,10 +169,8 @@ class LLEyeMotion : // must return true to indicate success and be available for activation virtual LLMotionInitStatus onInitialize(LLCharacter *character); - // called when a motion is activated - // must return TRUE to indicate success, or else - // it will be deactivated - virtual BOOL onActivate(); + + void adjustEyeTarget(LLVector3* targetPos, LLJointState& left_eye_state, LLJointState& right_eye_state); // called per time step // must return TRUE while it is active, and @@ -199,6 +189,8 @@ class LLEyeMotion : LLJoint *mHeadJoint; LLPointer mLeftEyeState; LLPointer mRightEyeState; + LLPointer mAltLeftEyeState; + LLPointer mAltRightEyeState; LLFrameTimer mEyeJitterTimer; F32 mEyeJitterTime; diff --git a/indra/llcharacter/lljoint.cpp b/indra/llcharacter/lljoint.cpp index f2900d4a59..0aada2fe86 100644 --- a/indra/llcharacter/lljoint.cpp +++ b/indra/llcharacter/lljoint.cpp @@ -32,10 +32,68 @@ #include "lljoint.h" #include "llmath.h" +#include S32 LLJoint::sNumUpdates = 0; S32 LLJoint::sNumTouches = 0; +template +bool attachment_map_iter_compare_key(const T& a, const T& b) +{ + return a.first < b.first; +} + +bool LLVector3OverrideMap::findActiveOverride(LLUUID& mesh_id, LLVector3& pos) const +{ + pos = LLVector3(0,0,0); + mesh_id = LLUUID(); + bool found = false; + + map_type::const_iterator it = std::max_element(m_map.begin(), + m_map.end(), + attachment_map_iter_compare_key); + if (it != m_map.end()) + { + found = true; + pos = it->second; + mesh_id = it->first; + } + return found; +} + +void LLVector3OverrideMap::showJointVector3Overrides( std::ostringstream& os ) const +{ + map_type::const_iterator max_it = std::max_element(m_map.begin(), + m_map.end(), + attachment_map_iter_compare_key); + for (map_type::const_iterator it = m_map.begin(); + it != m_map.end(); ++it) + { + const LLVector3& pos = it->second; + os << " " << "[" << it->first <<": " << pos << "]" << ((it==max_it) ? "*" : ""); + } +} + +U32 LLVector3OverrideMap::count() const +{ + return m_map.size(); +} + +void LLVector3OverrideMap::add(const LLUUID& mesh_id, const LLVector3& pos) +{ + m_map[mesh_id] = pos; +} + +bool LLVector3OverrideMap::remove(const LLUUID& mesh_id) +{ + U32 remove_count = m_map.erase(mesh_id); + return (remove_count > 0); +} + +void LLVector3OverrideMap::clear() +{ + m_map.clear(); +} //----------------------------------------------------------------------------- // LLJoint() // Class Constructor @@ -50,6 +108,8 @@ void LLJoint::init() mXform.setScale(LLVector3(1.0f, 1.0f, 1.0f)); mDirtyFlags = MATRIX_DIRTY | ROTATION_DIRTY | POSITION_DIRTY; mUpdateXform = TRUE; + mSupport = SUPPORT_BASE; + mEnd = LLVector3(0.0f, 0.0f, 0.0f); } LLJoint::LLJoint() : @@ -57,7 +117,6 @@ LLJoint::LLJoint() : { init(); touch(); - mResetAfterRestoreOldXform = false; } LLJoint::LLJoint(S32 joint_num) : @@ -65,7 +124,6 @@ LLJoint::LLJoint(S32 joint_num) : { init(); touch(); - mResetAfterRestoreOldXform = false; } @@ -74,7 +132,7 @@ LLJoint::LLJoint(S32 joint_num) : // Class Constructor //----------------------------------------------------------------------------- LLJoint::LLJoint(const std::string &name, LLJoint *parent) : - mJointNum(0) + mJointNum(-2) { init(); mUpdateXform = FALSE; @@ -114,6 +172,27 @@ void LLJoint::setup(const std::string &name, LLJoint *parent) } } +//----------------------------------------------------------------------------- +// setSupport() +//----------------------------------------------------------------------------- +void LLJoint::setSupport(const std::string& support_name) +{ + if (support_name == "extended") + { + setSupport(SUPPORT_EXTENDED); + } + else if (support_name == "base") + { + setSupport(SUPPORT_BASE); + } + else + { + LL_WARNS() << "unknown support string " << support_name << LL_ENDL; + setSupport(SUPPORT_BASE); + } +} + + //----------------------------------------------------------------------------- // touch() // Sets all dirty flags for all children, recursively. @@ -139,6 +218,18 @@ void LLJoint::touch(U32 flags) } } +//----------------------------------------------------------------------------- +// setJointNum() +//----------------------------------------------------------------------------- +void LLJoint::setJointNum(S32 joint_num) +{ + mJointNum = joint_num; + if (mJointNum + 2 >= LL_CHARACTER_MAX_ANIMATED_JOINTS) + { + LL_INFOS() << "LL_CHARACTER_MAX_ANIMATED_JOINTS needs to be increased" << LL_ENDL; + LL_ERRS() << "joint_num " << joint_num << " + 2 is too large for " << LL_CHARACTER_MAX_ANIMATED_JOINTS << LL_ENDL; + } +} //----------------------------------------------------------------------------- // getRoot() //----------------------------------------------------------------------------- @@ -184,6 +275,7 @@ void LLJoint::addChild(LLJoint* joint) joint->mParent->removeChild(joint); mChildren.push_back(joint); + //LL_INFOS() << getName() << " +child " << joint->getName() << LL_ENDL; joint->mXform.setParent(&mXform); joint->mParent = this; joint->touch(); @@ -199,7 +291,7 @@ void LLJoint::removeChild(LLJoint* joint) if (iter != mChildren.end()) { mChildren.erase(iter); - + //LL_INFOS() << getName() << " -child " << joint->getName() << LL_ENDL; joint->mXform.setParent(NULL); joint->mParent = NULL; joint->touch(); @@ -218,6 +310,7 @@ void LLJoint::removeAllChildren() child_list_t::iterator curiter = iter++; LLJoint* joint = *curiter; mChildren.erase(curiter); + //LL_INFOS() << getName() << " -child " << joint->getName() << LL_ENDL; joint->mXform.setParent(NULL); joint->mParent = NULL; joint->touch(); @@ -233,54 +326,436 @@ const LLVector3& LLJoint::getPosition() return mXform.getPosition(); } +bool do_debug_joint(const std::string& name) +{ + if (std::find(LLJoint::s_debugJointNames.begin(), LLJoint::s_debugJointNames.end(),name) != LLJoint::s_debugJointNames.end()) + { + return true; + } + return false; +} //-------------------------------------------------------------------- // setPosition() //-------------------------------------------------------------------- -void LLJoint::setPosition( const LLVector3& pos ) +void LLJoint::setPosition( const LLVector3& requested_pos, bool apply_attachment_overrides ) { -// if (mXform.getPosition() != pos) + LLVector3 pos(requested_pos); + + LLVector3 active_override; + LLUUID mesh_id; + if (apply_attachment_overrides && m_attachmentPosOverrides.findActiveOverride(mesh_id,active_override)) + { + if (pos != active_override && do_debug_joint(getName())) + { + LL_DEBUGS("Avatar") << " joint " << getName() << " requested_pos " << requested_pos + << " overriden by attachment " << active_override << LL_ENDL; + } + pos = active_override; + } + if ((pos != getPosition()) && do_debug_joint(getName())) { - mXform.setPosition(pos); - touch(MATRIX_DIRTY | POSITION_DIRTY); + LL_DEBUGS("Avatar") << " joint " << getName() << " set pos " << pos << LL_ENDL; } + if (pos != getPosition()) + { + mXform.setPosition(pos); + touch(MATRIX_DIRTY | POSITION_DIRTY); + } +} + +void LLJoint::setDefaultPosition( const LLVector3& pos ) +{ + mDefaultPosition = pos; +} + +const LLVector3& LLJoint::getDefaultPosition() const +{ + return mDefaultPosition; +} + +void LLJoint::setDefaultScale( const LLVector3& scale ) +{ + mDefaultScale = scale; } +const LLVector3& LLJoint::getDefaultScale() const +{ + return mDefaultScale; +} + +void showJointPosOverrides( const LLJoint& joint, const std::string& note, const std::string& av_info ) +{ + std::ostringstream os; + os << joint.m_posBeforeOverrides; + joint.m_attachmentPosOverrides.showJointVector3Overrides(os); + LL_DEBUGS("Avatar") << av_info << " joint " << joint.getName() << " " << note << " " << os.str() << LL_ENDL; +} + +void showJointScaleOverrides( const LLJoint& joint, const std::string& note, const std::string& av_info ) +{ + std::ostringstream os; + os << joint.m_scaleBeforeOverrides; + joint.m_attachmentScaleOverrides.showJointVector3Overrides(os); + LL_DEBUGS("Avatar") << av_info << " joint " << joint.getName() << " " << note << " " << os.str() << LL_ENDL; +} + +bool LLJoint::aboveJointPosThreshold(const LLVector3& pos) const +{ + LLVector3 diff = pos - getDefaultPosition(); + const F32 max_joint_pos_offset = 0.0001f; // 0.1 mm + return diff.lengthSquared() > max_joint_pos_offset * max_joint_pos_offset; +} + +bool LLJoint::aboveJointScaleThreshold(const LLVector3& scale) const +{ + LLVector3 diff = scale - getDefaultScale(); + const F32 max_joint_scale_offset = 0.0001f; // 0.1 mm + return diff.lengthSquared() > max_joint_scale_offset * max_joint_scale_offset; +} //-------------------------------------------------------------------- -// setPosition() +// addAttachmentPosOverride() //-------------------------------------------------------------------- -void LLJoint::setDefaultFromCurrentXform( void ) +void LLJoint::addAttachmentPosOverride( const LLVector3& pos, const LLUUID& mesh_id, const std::string& av_info, bool& active_override_changed ) { - mDefaultXform = mXform; - touch(MATRIX_DIRTY | POSITION_DIRTY); - + active_override_changed = false; + if (mesh_id.isNull()) + { + return; + } + // BENTO + // Not clear pelvis overrides are meaningful/useful. + //if (mName == "mPelvis") + //{ + // return; + //} + + LLVector3 before_pos; + LLUUID before_mesh_id; + bool has_active_override_before = hasAttachmentPosOverride( before_pos, before_mesh_id ); + if (!m_attachmentPosOverrides.count()) + { + if (do_debug_joint(getName())) + { + LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " saving m_posBeforeOverrides " << getPosition() << LL_ENDL; + } + m_posBeforeOverrides = getPosition(); + } + m_attachmentPosOverrides.add(mesh_id,pos); + LLVector3 after_pos; + LLUUID after_mesh_id; + hasAttachmentPosOverride(after_pos, after_mesh_id); + if (!has_active_override_before || (after_pos != before_pos)) + { + active_override_changed = true; + if (do_debug_joint(getName())) + { + LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " addAttachmentPosOverride for mesh " << mesh_id << " pos " << pos << LL_ENDL; + } + updatePos(av_info); + } } //-------------------------------------------------------------------- -// storeCurrentXform() +// removeAttachmentPosOverride() //-------------------------------------------------------------------- -void LLJoint::storeCurrentXform( const LLVector3& pos ) +void LLJoint::removeAttachmentPosOverride( const LLUUID& mesh_id, const std::string& av_info, bool& active_override_changed ) { - mOldXform = mXform; - mResetAfterRestoreOldXform = true; - setPosition( pos ); + active_override_changed = false; + if (mesh_id.isNull()) + { + return; + } + LLVector3 before_pos; + LLUUID before_mesh_id; + hasAttachmentPosOverride( before_pos, before_mesh_id ); + if (m_attachmentPosOverrides.remove(mesh_id)) + { + LLVector3 after_pos; + LLUUID after_mesh_id; + bool has_active_override_after = hasAttachmentPosOverride(after_pos, after_mesh_id); + if (!has_active_override_after || (after_pos != before_pos)) + { + active_override_changed = true; + if (do_debug_joint(getName())) + { + LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() + << " removeAttachmentPosOverride for " << mesh_id << LL_ENDL; + showJointPosOverrides(*this, "remove", av_info); + } + updatePos(av_info); + } + } } + +//-------------------------------------------------------------------- + // hasAttachmentPosOverride() + //-------------------------------------------------------------------- +bool LLJoint::hasAttachmentPosOverride( LLVector3& pos, LLUUID& mesh_id ) const +{ + return m_attachmentPosOverrides.findActiveOverride(mesh_id,pos); +} + //-------------------------------------------------------------------- -// restoreOldXform() +// clearAttachmentPosOverrides() //-------------------------------------------------------------------- -void LLJoint::restoreOldXform( void ) +void LLJoint::clearAttachmentPosOverrides() { - mResetAfterRestoreOldXform = false; - mXform = mOldXform; + if (m_attachmentPosOverrides.count()) + { + m_attachmentPosOverrides.clear(); + setPosition(m_posBeforeOverrides); + } } + //-------------------------------------------------------------------- -// restoreOldXform() +// getAllAttachmentPosOverrides() //-------------------------------------------------------------------- -void LLJoint::restoreToDefaultXform( void ) -{ - mXform = mDefaultXform; - setPosition( mXform.getPosition() ); +void LLJoint::getAllAttachmentPosOverrides(S32& num_pos_overrides, + std::set& distinct_pos_overrides) +{ + num_pos_overrides = m_attachmentPosOverrides.count(); + LLVector3OverrideMap::map_type::const_iterator it = m_attachmentPosOverrides.getMap().begin(); + for (; it != m_attachmentPosOverrides.getMap().end(); ++it) + { + distinct_pos_overrides.insert(it->second); + } +} + +//-------------------------------------------------------------------- +// getAllAttachmentScaleOverrides() +//-------------------------------------------------------------------- +void LLJoint::getAllAttachmentScaleOverrides(S32& num_scale_overrides, + std::set& distinct_scale_overrides) +{ + num_scale_overrides = m_attachmentScaleOverrides.count(); + LLVector3OverrideMap::map_type::const_iterator it = m_attachmentScaleOverrides.getMap().begin(); + for (; it != m_attachmentScaleOverrides.getMap().end(); ++it) + { + distinct_scale_overrides.insert(it->second); + } +} + +//-------------------------------------------------------------------- +// showAttachmentPosOverrides() +//-------------------------------------------------------------------- +void LLJoint::showAttachmentPosOverrides(const std::string& av_info) const +{ + LLVector3 active_override; + bool has_active_override; + LLUUID mesh_id; + has_active_override = m_attachmentPosOverrides.findActiveOverride(mesh_id,active_override); + U32 count = m_attachmentPosOverrides.count(); + if (count==1) + { + LLVector3OverrideMap::map_type::const_iterator it = m_attachmentPosOverrides.getMap().begin(); + std::string highlight = (has_active_override && (it->second == active_override)) ? "*" : ""; + LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() + << " has single attachment pos override " << highlight << "" << it->second << " default " << mDefaultPosition << LL_ENDL; + } + else if (count>1) + { + LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " has " << count << " attachment pos overrides" << LL_ENDL; + std::set distinct_offsets; + LLVector3OverrideMap::map_type::const_iterator it = m_attachmentPosOverrides.getMap().begin(); + for (; it != m_attachmentPosOverrides.getMap().end(); ++it) + { + distinct_offsets.insert(it->second); + } + if (distinct_offsets.size()>1) + { + LL_DEBUGS("Avatar") << "CONFLICTS, " << distinct_offsets.size() << " different values" << LL_ENDL; + } + else + { + LL_DEBUGS("Avatar") << "no conflicts" << LL_ENDL; + } + std::set::iterator dit = distinct_offsets.begin(); + for ( ; dit != distinct_offsets.end(); ++dit) + { + std::string highlight = (has_active_override && *dit == active_override) ? "*" : ""; + LL_DEBUGS("Avatar") << " POS " << highlight << "" << (*dit) << " default " << mDefaultPosition << LL_ENDL; + } + } +} + +//-------------------------------------------------------------------- +// updatePos() +//-------------------------------------------------------------------- +void LLJoint::updatePos(const std::string& av_info) +{ + LLVector3 pos, found_pos; + LLUUID mesh_id; + if (m_attachmentPosOverrides.findActiveOverride(mesh_id,found_pos)) + { + if (do_debug_joint(getName())) + { + LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " updatePos, winner of " << m_attachmentPosOverrides.count() << " is mesh " << mesh_id << " pos " << found_pos << LL_ENDL; + } + pos = found_pos; + } + else + { + if (do_debug_joint(getName())) + { + LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " updatePos, winner is posBeforeOverrides " << m_posBeforeOverrides << LL_ENDL; + } + pos = m_posBeforeOverrides; + } + setPosition(pos); +} + +//-------------------------------------------------------------------- +// updateScale() +//-------------------------------------------------------------------- +void LLJoint::updateScale(const std::string& av_info) +{ + LLVector3 scale, found_scale; + LLUUID mesh_id; + if (m_attachmentScaleOverrides.findActiveOverride(mesh_id,found_scale)) + { + if (do_debug_joint(getName())) + { + LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " updateScale, winner of " << m_attachmentScaleOverrides.count() << " is mesh " << mesh_id << " scale " << found_scale << LL_ENDL; + } + scale = found_scale; + } + else + { + if (do_debug_joint(getName())) + { + LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " updateScale, winner is scaleBeforeOverrides " << m_scaleBeforeOverrides << LL_ENDL; + } + scale = m_scaleBeforeOverrides; + } + setScale(scale); +} + +//-------------------------------------------------------------------- +// addAttachmentScaleOverride() +//-------------------------------------------------------------------- +void LLJoint::addAttachmentScaleOverride( const LLVector3& scale, const LLUUID& mesh_id, const std::string& av_info ) +{ + if (mesh_id.isNull()) + { + return; + } + if (!m_attachmentScaleOverrides.count()) + { + if (do_debug_joint(getName())) + { + LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " saving m_scaleBeforeOverrides " << getScale() << LL_ENDL; + } + m_scaleBeforeOverrides = getScale(); + } + m_attachmentScaleOverrides.add(mesh_id,scale); + if (do_debug_joint(getName())) + { + LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " addAttachmentScaleOverride for mesh " << mesh_id << " scale " << scale << LL_ENDL; + } + updateScale(av_info); +} + +//-------------------------------------------------------------------- +// removeAttachmentScaleOverride() +//-------------------------------------------------------------------- +void LLJoint::removeAttachmentScaleOverride( const LLUUID& mesh_id, const std::string& av_info ) +{ + if (mesh_id.isNull()) + { + return; + } + if (m_attachmentScaleOverrides.remove(mesh_id)) + { + if (do_debug_joint(getName())) + { + LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() + << " removeAttachmentScaleOverride for " << mesh_id << LL_ENDL; + showJointScaleOverrides(*this, "remove", av_info); + } + updateScale(av_info); + } +} + +//-------------------------------------------------------------------- + // hasAttachmentScaleOverride() + //-------------------------------------------------------------------- +bool LLJoint::hasAttachmentScaleOverride( LLVector3& scale, LLUUID& mesh_id ) const +{ + return m_attachmentScaleOverrides.findActiveOverride(mesh_id,scale); +} + +//-------------------------------------------------------------------- +// clearAttachmentScaleOverrides() +//-------------------------------------------------------------------- +void LLJoint::clearAttachmentScaleOverrides() +{ + if (m_attachmentScaleOverrides.count()) + { + m_attachmentScaleOverrides.clear(); + setScale(m_scaleBeforeOverrides); + } +} + +//-------------------------------------------------------------------- +// showAttachmentScaleOverrides() +//-------------------------------------------------------------------- +void LLJoint::showAttachmentScaleOverrides(const std::string& av_info) const +{ + LLVector3 active_override; + bool has_active_override; + LLUUID mesh_id; + has_active_override = m_attachmentScaleOverrides.findActiveOverride(mesh_id,active_override); + U32 count = m_attachmentScaleOverrides.count(); + if (count==1) + { + LLVector3OverrideMap::map_type::const_iterator it = m_attachmentScaleOverrides.getMap().begin(); + std::string highlight = (has_active_override && (it->second == active_override)) ? "*" : ""; + LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() + << " has single attachment scale override " << highlight << "" << it->second << " default " << mDefaultScale << LL_ENDL; + } + else if (count>1) + { + LL_DEBUGS("Avatar") << "av " << av_info << " joint " << getName() << " has " << count << " attachment scale overrides" << LL_ENDL; + std::set distinct_offsets; + LLVector3OverrideMap::map_type::const_iterator it = m_attachmentScaleOverrides.getMap().begin(); + for (; it != m_attachmentScaleOverrides.getMap().end(); ++it) + { + distinct_offsets.insert(it->second); + } + if (distinct_offsets.size()>1) + { + LL_DEBUGS("Avatar") << "CONFLICTS, " << distinct_offsets.size() << " different values" << LL_ENDL; + } + else + { + LL_DEBUGS("Avatar") << "no conflicts" << LL_ENDL; + } + std::set::iterator dit = distinct_offsets.begin(); + for ( ; dit != distinct_offsets.end(); ++dit) + { + std::string highlight = (has_active_override && *dit == active_override) ? "*" : ""; + LL_DEBUGS("Avatar") << " POS " << highlight << "" << (*dit) << " default " << mDefaultScale << LL_ENDL; + } + } +} + +// init static +LLJoint::debug_joint_name_t LLJoint::s_debugJointNames = debug_joint_name_t(); + +//-------------------------------------------------------------------- +// setDebugJointNames +//-------------------------------------------------------------------- +void LLJoint::setDebugJointNames(const debug_joint_name_t& names) +{ + s_debugJointNames = names; +} +void LLJoint::setDebugJointNames(const std::string& names_string) +{ + debug_joint_name_t names; + boost::split(names, names_string, boost::is_any_of(" :,")); + setDebugJointNames(names); } //-------------------------------------------------------------------- @@ -312,19 +787,15 @@ void LLJoint::setWorldPosition( const LLVector3& pos ) return; } - LLMatrix4 temp_matrix = getWorldMatrix(); - temp_matrix.mMatrix[VW][VX] = pos.mV[VX]; - temp_matrix.mMatrix[VW][VY] = pos.mV[VY]; - temp_matrix.mMatrix[VW][VZ] = pos.mV[VZ]; + LLMatrix4a temp_matrix = getWorldMatrix(); + temp_matrix.setTranslate_affine(pos); - LLMatrix4 parentWorldMatrix = mParent->getWorldMatrix(); - LLMatrix4 invParentWorldMatrix = parentWorldMatrix.invert(); + LLMatrix4a invParentWorldMatrix = mParent->getWorldMatrix(); + invParentWorldMatrix.invert(); - temp_matrix *= invParentWorldMatrix; + invParentWorldMatrix.mul(temp_matrix); - LLVector3 localPos( temp_matrix.mMatrix[VW][VX], - temp_matrix.mMatrix[VW][VY], - temp_matrix.mMatrix[VW][VZ] ); + LLVector3 localPos( invParentWorldMatrix.getRow().getF32ptr() ); setPosition( localPos ); } @@ -383,19 +854,19 @@ void LLJoint::setWorldRotation( const LLQuaternion& rot ) this->setRotation( rot ); return; } + + LLMatrix4a parentWorldMatrix = mParent->getWorldMatrix(); + LLQuaternion2 rota(rot); + LLMatrix4a temp_mat(rota); - LLMatrix4 temp_mat(rot); - - LLMatrix4 parentWorldMatrix = mParent->getWorldMatrix(); - parentWorldMatrix.mMatrix[VW][VX] = 0; - parentWorldMatrix.mMatrix[VW][VY] = 0; - parentWorldMatrix.mMatrix[VW][VZ] = 0; + LLMatrix4a invParentWorldMatrix = mParent->getWorldMatrix(); + invParentWorldMatrix.setTranslate_affine(LLVector3(0.f)); - LLMatrix4 invParentWorldMatrix = parentWorldMatrix.invert(); + invParentWorldMatrix.invert(); - temp_mat *= invParentWorldMatrix; + invParentWorldMatrix.mul(temp_mat); - setRotation(LLQuaternion(temp_mat)); + setRotation(LLQuaternion(LLMatrix4(invParentWorldMatrix.getF32ptr()))); } @@ -410,13 +881,22 @@ const LLVector3& LLJoint::getScale() //-------------------------------------------------------------------- // setScale() //-------------------------------------------------------------------- -void LLJoint::setScale( const LLVector3& scale ) +void LLJoint::setScale( const LLVector3& requested_scale, bool apply_attachment_overrides ) { -// if (mXform.getScale() != scale) - { - mXform.setScale(scale); - touch(); - } + LLVector3 scale(requested_scale); + LLUUID mesh_id; + LLVector3 active_override; + if (apply_attachment_overrides && m_attachmentScaleOverrides.findActiveOverride(mesh_id,active_override)) + { + if (scale != active_override && do_debug_joint(getName())) + { + LL_DEBUGS("Avatar") << " joint " << getName() << " requested_scale " << requested_scale + << " overriden by attachment " << active_override << LL_ENDL; + } + scale = active_override; + } + mXform.setScale(scale); + touch(); } @@ -425,7 +905,7 @@ void LLJoint::setScale( const LLVector3& scale ) //-------------------------------------------------------------------- // getWorldMatrix() //-------------------------------------------------------------------- -const LLMatrix4 &LLJoint::getWorldMatrix() +const LLMatrix4a &LLJoint::getWorldMatrix() { updateWorldMatrixParent(); @@ -438,7 +918,7 @@ const LLMatrix4 &LLJoint::getWorldMatrix() //-------------------------------------------------------------------- void LLJoint::setWorldMatrix( const LLMatrix4& mat ) { -llinfos << "WARNING: LLJoint::setWorldMatrix() not correctly implemented yet" << llendl; +LL_INFOS() << "WARNING: LLJoint::setWorldMatrix() not correctly implemented yet" << LL_ENDL; // extract global translation LLVector3 trans( mat.mMatrix[VW][VX], mat.mMatrix[VW][VY], diff --git a/indra/llcharacter/lljoint.h b/indra/llcharacter/lljoint.h index fe14c1e445..6beffc9f6f 100644 --- a/indra/llcharacter/lljoint.h +++ b/indra/llcharacter/lljoint.h @@ -31,22 +31,55 @@ // Header Files //----------------------------------------------------------------------------- #include +#include -#include "linked_lists.h" #include "v3math.h" #include "v4math.h" #include "m4math.h" #include "llquaternion.h" #include "xform.h" -#include "lldarray.h" const S32 LL_CHARACTER_MAX_JOINTS_PER_MESH = 15; -const U32 LL_CHARACTER_MAX_JOINTS = 32; // must be divisible by 4! -const U32 LL_HAND_JOINT_NUM = 31; -const U32 LL_FACE_JOINT_NUM = 30; +// Need to set this to count of animate-able joints, +// currently = #bones + #collision_volumes + #attachments + 2, +// rounded to next multiple of 4. +const U32 LL_CHARACTER_MAX_ANIMATED_JOINTS = 216; // must be divisible by 4! +const U32 LL_MAX_JOINTS_PER_MESH_OBJECT = 110; + +// These should be higher than the joint_num of any +// other joint, to avoid conflicts in updateMotionsByType() +const U32 LL_HAND_JOINT_NUM = (LL_CHARACTER_MAX_ANIMATED_JOINTS-1); +const U32 LL_FACE_JOINT_NUM = (LL_CHARACTER_MAX_ANIMATED_JOINTS-2); const S32 LL_CHARACTER_MAX_PRIORITY = 7; const F32 LL_MAX_PELVIS_OFFSET = 5.f; +class LLVector3OverrideMap +{ +public: + LLVector3OverrideMap() {} + bool findActiveOverride(LLUUID& mesh_id, LLVector3& pos) const; + void showJointVector3Overrides(std::ostringstream& os) const; + U32 count() const; + void add(const LLUUID& mesh_id, const LLVector3& pos); + bool remove(const LLUUID& mesh_id); + void clear(); + + typedef std::map map_type; + const map_type& getMap() const { return m_map; } +private: + map_type m_map; +}; + +inline bool operator==(const LLVector3OverrideMap& a, const LLVector3OverrideMap& b) +{ + return a.getMap() == b.getMap(); +} + +inline bool operator!=(const LLVector3OverrideMap& a, const LLVector3OverrideMap& b) +{ + return !(a == b); +} + //----------------------------------------------------------------------------- // class LLJoint //----------------------------------------------------------------------------- @@ -72,27 +105,37 @@ class LLJoint POSITION_DIRTY = 0x1 << 2, ALL_DIRTY = 0x7 }; +public: + enum SupportCategory + { + SUPPORT_BASE, + SUPPORT_EXTENDED + }; protected: std::string mName; + SupportCategory mSupport; + // parent joint LLJoint *mParent; // explicit transformation members LLXformMatrix mXform; - LLXformMatrix mOldXform; - LLXformMatrix mDefaultXform; - LLUUID mId; + LLVector3 mDefaultPosition; + LLVector3 mDefaultScale; + public: U32 mDirtyFlags; BOOL mUpdateXform; - BOOL mResetAfterRestoreOldXform; - // describes the skin binding pose LLVector3 mSkinOffset; + // Endpoint of the bone, if applicable. This is only relevant for + // external programs like Blender, and for diagnostic display. + LLVector3 mEnd; + S32 mJointNum; // child joints @@ -102,6 +145,21 @@ class LLJoint // debug statics static S32 sNumTouches; static S32 sNumUpdates; + typedef std::set debug_joint_name_t; + static debug_joint_name_t s_debugJointNames; + static void setDebugJointNames(const debug_joint_name_t& names); + static void setDebugJointNames(const std::string& names_string); + + // Position overrides + LLVector3OverrideMap m_attachmentPosOverrides; + LLVector3 m_posBeforeOverrides; + + // Scale overrides + LLVector3OverrideMap m_attachmentScaleOverrides; + LLVector3 m_scaleBeforeOverrides; + + void updatePos(const std::string& av_info); + void updateScale(const std::string& av_info); public: LLJoint(); @@ -123,6 +181,19 @@ class LLJoint const std::string& getName() const { return mName; } void setName( const std::string &name ) { mName = name; } + // joint num + S32 getJointNum() const { return mJointNum; } + void setJointNum(S32 joint_num); + + // get/set support + SupportCategory getSupport() const { return mSupport; } + void setSupport( const SupportCategory& support) { mSupport = support; } + void setSupport( const std::string& support_string); + + // get/set end point + void setEnd( const LLVector3& end) { mEnd = end; } + const LLVector3& getEnd() const { return mEnd; } + // getParent LLJoint *getParent() { return mParent; } @@ -139,10 +210,16 @@ class LLJoint // get/set local position const LLVector3& getPosition(); - void setPosition( const LLVector3& pos ); - + void setPosition( const LLVector3& pos, bool apply_attachment_overrides = false ); + + // Tracks the default position defined by the skeleton void setDefaultPosition( const LLVector3& pos ); - + const LLVector3& getDefaultPosition() const; + + // Tracks the default scale defined by the skeleton + void setDefaultScale( const LLVector3& scale ); + const LLVector3& getDefaultScale() const; + // get/set world position LLVector3 getWorldPosition(); LLVector3 getLastWorldPosition(); @@ -159,10 +236,10 @@ class LLJoint // get/set local scale const LLVector3& getScale(); - void setScale( const LLVector3& scale ); + void setScale( const LLVector3& scale, bool apply_attachment_overrides = false ); // get/set world matrix - const LLMatrix4 &getWorldMatrix(); + const LLMatrix4a &getWorldMatrix(); void setWorldMatrix( const LLMatrix4& mat ); void updateWorldMatrixChildren(); @@ -182,26 +259,28 @@ class LLJoint virtual BOOL isAnimatable() const { return TRUE; } - S32 getJointNum() const { return mJointNum; } - - void restoreOldXform( void ); - void restoreToDefaultXform( void ); - void setDefaultFromCurrentXform( void ); - void storeCurrentXform( const LLVector3& pos ); - - //Accessor for the joint id - LLUUID getId( void ) { return mId; } - //Setter for the joints id - void setId( const LLUUID& id ) { mId = id;} - - //If the old transform flag has been set, then the reset logic in avatar needs to be aware(test) of it - const BOOL doesJointNeedToBeReset( void ) const { return mResetAfterRestoreOldXform; } - //Setter for joint reset flag - void setJointToBeReset( BOOL val ) { mResetAfterRestoreOldXform = val; } - - // - std::string exportString(U32 tabs = 0); - // + void addAttachmentPosOverride( const LLVector3& pos, const LLUUID& mesh_id, const std::string& av_info, bool& active_override_changed ); + void removeAttachmentPosOverride( const LLUUID& mesh_id, const std::string& av_info, bool& active_override_changed ); + bool hasAttachmentPosOverride( LLVector3& pos, LLUUID& mesh_id ) const; + void clearAttachmentPosOverrides(); + void showAttachmentPosOverrides(const std::string& av_info) const; + + void addAttachmentScaleOverride( const LLVector3& scale, const LLUUID& mesh_id, const std::string& av_info ); + void removeAttachmentScaleOverride( const LLUUID& mesh_id, const std::string& av_info ); + bool hasAttachmentScaleOverride( LLVector3& scale, LLUUID& mesh_id ) const; + void clearAttachmentScaleOverrides(); + void showAttachmentScaleOverrides(const std::string& av_info) const; + + void getAllAttachmentPosOverrides(S32& num_pos_overrides, + std::set& distinct_pos_overrides); + void getAllAttachmentScaleOverrides(S32& num_scale_overrides, + std::set& distinct_scale_overrides); + + // These are used in checks of whether a pos/scale override is considered significant. + bool aboveJointPosThreshold(const LLVector3& pos) const; + bool aboveJointScaleThreshold(const LLVector3& scale) const; + + std::string exportString(U32 tabs); }; #endif // LL_LLJOINT_H diff --git a/indra/llcharacter/lljointsolverrp3.cpp b/indra/llcharacter/lljointsolverrp3.cpp index 6599a76b16..2e0fda3ad3 100644 --- a/indra/llcharacter/lljointsolverrp3.cpp +++ b/indra/llcharacter/lljointsolverrp3.cpp @@ -141,8 +141,8 @@ void LLJointSolverRP3::setTwist( F32 twist ) //----------------------------------------------------------------------------- void LLJointSolverRP3::solve() { -// llinfos << llendl; -// llinfos << "LLJointSolverRP3::solve()" << llendl; +// LL_INFOS() << LL_ENDL; +// LL_INFOS() << "LLJointSolverRP3::solve()" << LL_ENDL; //------------------------------------------------------------------------- // setup joints in their base rotations @@ -158,25 +158,27 @@ void LLJointSolverRP3::solve() LLVector3 cPos = mJointC->getWorldPosition(); LLVector3 gPos = mJointGoal->getWorldPosition(); -// llinfos << "bPosLocal = " << mJointB->getPosition() << llendl; -// llinfos << "cPosLocal = " << mJointC->getPosition() << llendl; -// llinfos << "bRotLocal = " << mJointB->getRotation() << llendl; -// llinfos << "cRotLocal = " << mJointC->getRotation() << llendl; +// LL_INFOS() << "bPosLocal = " << mJointB->getPosition() << LL_ENDL; +// LL_INFOS() << "cPosLocal = " << mJointC->getPosition() << LL_ENDL; +// LL_INFOS() << "bRotLocal = " << mJointB->getRotation() << LL_ENDL; +// LL_INFOS() << "cRotLocal = " << mJointC->getRotation() << LL_ENDL; -// llinfos << "aPos : " << aPos << llendl; -// llinfos << "bPos : " << bPos << llendl; -// llinfos << "cPos : " << cPos << llendl; -// llinfos << "gPos : " << gPos << llendl; +// LL_INFOS() << "aPos : " << aPos << LL_ENDL; +// LL_INFOS() << "bPos : " << bPos << LL_ENDL; +// LL_INFOS() << "cPos : " << cPos << LL_ENDL; +// LL_INFOS() << "gPos : " << gPos << LL_ENDL; //------------------------------------------------------------------------- // get the poleVector in world space //------------------------------------------------------------------------- - LLMatrix4 worldJointAParentMat; + LLVector3 poleVec = mPoleVector; if ( mJointA->getParent() ) { - worldJointAParentMat = mJointA->getParent()->getWorldMatrix(); + LLVector4a pole_veca; + pole_veca.load3(mPoleVector.mV); + mJointA->getParent()->getWorldMatrix().rotate(pole_veca,pole_veca); + poleVec.set(pole_veca.getF32ptr()); } - LLVector3 poleVec = rotate_vector( mPoleVector, worldJointAParentMat ); //------------------------------------------------------------------------- // compute the following: @@ -190,10 +192,10 @@ void LLJointSolverRP3::solve() LLVector3 acVec = cPos - aPos; LLVector3 agVec = gPos - aPos; -// llinfos << "abVec : " << abVec << llendl; -// llinfos << "bcVec : " << bcVec << llendl; -// llinfos << "acVec : " << acVec << llendl; -// llinfos << "agVec : " << agVec << llendl; +// LL_INFOS() << "abVec : " << abVec << LL_ENDL; +// LL_INFOS() << "bcVec : " << bcVec << LL_ENDL; +// LL_INFOS() << "acVec : " << acVec << LL_ENDL; +// LL_INFOS() << "agVec : " << agVec << LL_ENDL; //------------------------------------------------------------------------- // compute needed lengths of those vectors @@ -202,16 +204,16 @@ void LLJointSolverRP3::solve() F32 bcLen = bcVec.magVec(); F32 agLen = agVec.magVec(); -// llinfos << "abLen : " << abLen << llendl; -// llinfos << "bcLen : " << bcLen << llendl; -// llinfos << "agLen : " << agLen << llendl; +// LL_INFOS() << "abLen : " << abLen << LL_ENDL; +// LL_INFOS() << "bcLen : " << bcLen << LL_ENDL; +// LL_INFOS() << "agLen : " << agLen << LL_ENDL; //------------------------------------------------------------------------- // compute component vector of (A->B) orthogonal to (A->C) //------------------------------------------------------------------------- LLVector3 abacCompOrthoVec = abVec - acVec * ((abVec * acVec)/(acVec * acVec)); -// llinfos << "abacCompOrthoVec : " << abacCompOrthoVec << llendl; +// LL_INFOS() << "abacCompOrthoVec : " << abacCompOrthoVec << LL_ENDL; //------------------------------------------------------------------------- // compute the normal of the original ABC plane (and store for later) @@ -279,13 +281,13 @@ void LLJointSolverRP3::solve() LLQuaternion bRot(theta - abbcAng, abbcOrthoVec); -// llinfos << "abbcAng : " << abbcAng << llendl; -// llinfos << "abbcOrthoVec : " << abbcOrthoVec << llendl; -// llinfos << "agLenSq : " << agLenSq << llendl; -// llinfos << "cosTheta : " << cosTheta << llendl; -// llinfos << "theta : " << theta << llendl; -// llinfos << "bRot : " << bRot << llendl; -// llinfos << "theta abbcAng theta-abbcAng: " << theta*180.0/F_PI << " " << abbcAng*180.0f/F_PI << " " << (theta - abbcAng)*180.0f/F_PI << llendl; +// LL_INFOS() << "abbcAng : " << abbcAng << LL_ENDL; +// LL_INFOS() << "abbcOrthoVec : " << abbcOrthoVec << LL_ENDL; +// LL_INFOS() << "agLenSq : " << agLenSq << LL_ENDL; +// LL_INFOS() << "cosTheta : " << cosTheta << LL_ENDL; +// LL_INFOS() << "theta : " << theta << LL_ENDL; +// LL_INFOS() << "bRot : " << bRot << LL_ENDL; +// LL_INFOS() << "theta abbcAng theta-abbcAng: " << theta*180.0/F_PI << " " << abbcAng*180.0f/F_PI << " " << (theta - abbcAng)*180.0f/F_PI << LL_ENDL; //------------------------------------------------------------------------- // compute rotation that rotates new A->C to A->G @@ -299,9 +301,9 @@ void LLJointSolverRP3::solve() LLQuaternion cgRot; cgRot.shortestArc( acVec, agVec ); -// llinfos << "bcVec : " << bcVec << llendl; -// llinfos << "acVec : " << acVec << llendl; -// llinfos << "cgRot : " << cgRot << llendl; +// LL_INFOS() << "bcVec : " << bcVec << LL_ENDL; +// LL_INFOS() << "acVec : " << acVec << LL_ENDL; +// LL_INFOS() << "cgRot : " << cgRot << LL_ENDL; // update A->B and B->C with rotation from C to G abVec = abVec * cgRot; @@ -359,18 +361,18 @@ void LLJointSolverRP3::solve() pRot.shortestArc( abcNorm, apgNorm ); } -// llinfos << "abcNorm = " << abcNorm << llendl; -// llinfos << "apgNorm = " << apgNorm << llendl; -// llinfos << "pRot = " << pRot << llendl; +// LL_INFOS() << "abcNorm = " << abcNorm << LL_ENDL; +// LL_INFOS() << "apgNorm = " << apgNorm << LL_ENDL; +// LL_INFOS() << "pRot = " << pRot << LL_ENDL; //------------------------------------------------------------------------- // compute twist rotation //------------------------------------------------------------------------- LLQuaternion twistRot( mTwist, agVec ); -// llinfos << "twist : " << mTwist*180.0/F_PI << llendl; -// llinfos << "agNormVec: " << agNormVec << llendl; -// llinfos << "twistRot : " << twistRot << llendl; +// LL_INFOS() << "twist : " << mTwist*180.0/F_PI << LL_ENDL; +// LL_INFOS() << "agNormVec: " << agNormVec << LL_ENDL; +// LL_INFOS() << "twistRot : " << twistRot << LL_ENDL; //------------------------------------------------------------------------- // compute rotation of A diff --git a/indra/llcharacter/lljointstate.h b/indra/llcharacter/lljointstate.h index e40cf2673f..120430ed16 100644 --- a/indra/llcharacter/lljointstate.h +++ b/indra/llcharacter/lljointstate.h @@ -70,22 +70,18 @@ class LLJointState : public LLRefCount public: // Constructor LLJointState() - { - mUsage = 0; - mJoint = NULL; - mUsage = 0; - mWeight = 0.f; - mPriority = LLJoint::USE_MOTION_PRIORITY; - } + : mJoint(NULL) + , mUsage(0) + , mWeight(0.f) + , mPriority(LLJoint::USE_MOTION_PRIORITY) + {} LLJointState(LLJoint* joint) - { - mUsage = 0; - mJoint = joint; - mUsage = 0; - mWeight = 0.f; - mPriority = LLJoint::USE_MOTION_PRIORITY; - } + : mJoint(joint) + , mUsage(0) + , mWeight(0.f) + , mPriority(LLJoint::USE_MOTION_PRIORITY) + {} // joint that this state is applied to LLJoint* getJoint() { return mJoint; } diff --git a/indra/llcharacter/llkeyframefallmotion.cpp b/indra/llcharacter/llkeyframefallmotion.cpp index 15ad1b9e9e..336d79e650 100644 --- a/indra/llcharacter/llkeyframefallmotion.cpp +++ b/indra/llcharacter/llkeyframefallmotion.cpp @@ -49,7 +49,7 @@ // LLKeyframeFallMotion() // Class Constructor //----------------------------------------------------------------------------- -LLKeyframeFallMotion::LLKeyframeFallMotion(const LLUUID &id) : LLKeyframeMotion(id) +LLKeyframeFallMotion::LLKeyframeFallMotion(LLUUID const& id, LLMotionController* controller) : LLKeyframeMotion(id, controller) { mVelocityZ = 0.f; mCharacter = NULL; diff --git a/indra/llcharacter/llkeyframefallmotion.h b/indra/llcharacter/llkeyframefallmotion.h index 495be977fd..0d2553ce3c 100644 --- a/indra/llcharacter/llkeyframefallmotion.h +++ b/indra/llcharacter/llkeyframefallmotion.h @@ -47,7 +47,7 @@ class LLKeyframeFallMotion : { public: // Constructor - LLKeyframeFallMotion(const LLUUID &id); + LLKeyframeFallMotion(LLUUID const& id, LLMotionController* controller); // Destructor virtual ~LLKeyframeFallMotion(); @@ -59,7 +59,7 @@ class LLKeyframeFallMotion : // static constructor // all subclasses must implement such a function and register it - static LLMotion *create(const LLUUID &id) { return new LLKeyframeFallMotion(id); } + static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLKeyframeFallMotion(id, controller); } public: //------------------------------------------------------------------------- diff --git a/indra/llcharacter/llkeyframemotion.cpp b/indra/llcharacter/llkeyframemotion.cpp index df10f984ac..1c842e6b8d 100644 --- a/indra/llcharacter/llkeyframemotion.cpp +++ b/indra/llcharacter/llkeyframemotion.cpp @@ -42,6 +42,7 @@ #include "llvfile.h" #include "m3math.h" #include "message.h" +#include //----------------------------------------------------------------------------- // Static Definitions @@ -84,293 +85,59 @@ LLKeyframeMotion::JointMotionList::~JointMotionList() for_each(mJointMotionArray.begin(), mJointMotionArray.end(), DeletePointer()); } -U32 LLKeyframeMotion::JointMotionList::dumpDiagInfo() +//Singu: add parameter 'silent'. +U32 LLKeyframeMotion::JointMotionList::dumpDiagInfo(bool silent) const { S32 total_size = sizeof(JointMotionList); for (U32 i = 0; i < getNumJointMotions(); i++) { - LLKeyframeMotion::JointMotion* joint_motion_p = mJointMotionArray[i]; + LLKeyframeMotion::JointMotion const* joint_motion_p = mJointMotionArray[i]; - llinfos << "\tJoint " << joint_motion_p->mJointName << llendl; + if (!silent) + { + LL_INFOS() << "\tJoint " << joint_motion_p->mJointName << LL_ENDL; + } if (joint_motion_p->mUsage & LLJointState::SCALE) { - llinfos << "\t" << joint_motion_p->mScaleCurve.mNumKeys << " scale keys at " - << joint_motion_p->mScaleCurve.mNumKeys * sizeof(ScaleKey) << " bytes" << llendl; - + if (!silent) + { + LL_INFOS() << "\t" << joint_motion_p->mScaleCurve.mNumKeys << " scale keys at " + << joint_motion_p->mScaleCurve.mNumKeys * sizeof(ScaleKey) << " bytes" << LL_ENDL; + } total_size += joint_motion_p->mScaleCurve.mNumKeys * sizeof(ScaleKey); } if (joint_motion_p->mUsage & LLJointState::ROT) { - llinfos << "\t" << joint_motion_p->mRotationCurve.mNumKeys << " rotation keys at " - << joint_motion_p->mRotationCurve.mNumKeys * sizeof(RotationKey) << " bytes" << llendl; - + if (!silent) + { + LL_INFOS() << "\t" << joint_motion_p->mRotationCurve.mNumKeys << " rotation keys at " + << joint_motion_p->mRotationCurve.mNumKeys * sizeof(RotationKey) << " bytes" << LL_ENDL; + } total_size += joint_motion_p->mRotationCurve.mNumKeys * sizeof(RotationKey); } if (joint_motion_p->mUsage & LLJointState::POS) { - llinfos << "\t" << joint_motion_p->mPositionCurve.mNumKeys << " position keys at " - << joint_motion_p->mPositionCurve.mNumKeys * sizeof(PositionKey) << " bytes" << llendl; - + if (!silent) + { + LL_INFOS() << "\t" << joint_motion_p->mPositionCurve.mNumKeys << " position keys at " + << joint_motion_p->mPositionCurve.mNumKeys * sizeof(PositionKey) << " bytes" << LL_ENDL; + } total_size += joint_motion_p->mPositionCurve.mNumKeys * sizeof(PositionKey); } } - llinfos << "Size: " << total_size << " bytes" << llendl; - - return total_size; -} - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -// ****Curve classes -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- - - -//----------------------------------------------------------------------------- -// ScaleCurve::ScaleCurve() -//----------------------------------------------------------------------------- -LLKeyframeMotion::ScaleCurve::ScaleCurve() -{ - mInterpolationType = LLKeyframeMotion::IT_LINEAR; - mNumKeys = 0; -} - -//----------------------------------------------------------------------------- -// ScaleCurve::~ScaleCurve() -//----------------------------------------------------------------------------- -LLKeyframeMotion::ScaleCurve::~ScaleCurve() -{ - mKeys.clear(); - mNumKeys = 0; -} - -//----------------------------------------------------------------------------- -// getValue() -//----------------------------------------------------------------------------- -LLVector3 LLKeyframeMotion::ScaleCurve::getValue(F32 time, F32 duration) -{ - LLVector3 value; - - if (mKeys.empty()) - { - value.clearVec(); - return value; - } - - key_map_t::iterator right = mKeys.lower_bound(time); - if (right == mKeys.end()) - { - // Past last key - --right; - value = right->second.mScale; - } - else if (right == mKeys.begin() || right->first == time) - { - // Before first key or exactly on a key - value = right->second.mScale; - } - else - { - // Between two keys - key_map_t::iterator left = right; --left; - F32 index_before = left->first; - F32 index_after = right->first; - ScaleKey& scale_before = left->second; - ScaleKey& scale_after = right->second; - if (right == mKeys.end()) - { - scale_after = mLoopInKey; - index_after = duration; - } - - F32 u = (time - index_before) / (index_after - index_before); - value = interp(u, scale_before, scale_after); - } - return value; -} - -//----------------------------------------------------------------------------- -// interp() -//----------------------------------------------------------------------------- -LLVector3 LLKeyframeMotion::ScaleCurve::interp(F32 u, ScaleKey& before, ScaleKey& after) -{ - switch (mInterpolationType) - { - case IT_STEP: - return before.mScale; - - default: - case IT_LINEAR: - case IT_SPLINE: - return lerp(before.mScale, after.mScale, u); - } -} - -//----------------------------------------------------------------------------- -// RotationCurve::RotationCurve() -//----------------------------------------------------------------------------- -LLKeyframeMotion::RotationCurve::RotationCurve() -{ - mInterpolationType = LLKeyframeMotion::IT_LINEAR; - mNumKeys = 0; -} - -//----------------------------------------------------------------------------- -// RotationCurve::~RotationCurve() -//----------------------------------------------------------------------------- -LLKeyframeMotion::RotationCurve::~RotationCurve() -{ - mKeys.clear(); - mNumKeys = 0; -} - -//----------------------------------------------------------------------------- -// RotationCurve::getValue() -//----------------------------------------------------------------------------- -LLQuaternion LLKeyframeMotion::RotationCurve::getValue(F32 time, F32 duration) -{ - LLQuaternion value; - - if (mKeys.empty()) - { - value = LLQuaternion::DEFAULT; - return value; - } - - key_map_t::iterator right = mKeys.lower_bound(time); - if (right == mKeys.end()) - { - // Past last key - --right; - value = right->second.mRotation; - } - else if (right == mKeys.begin() || right->first == time) - { - // Before first key or exactly on a key - value = right->second.mRotation; - } - else - { - // Between two keys - key_map_t::iterator left = right; --left; - F32 index_before = left->first; - F32 index_after = right->first; - RotationKey& rot_before = left->second; - RotationKey& rot_after = right->second; - if (right == mKeys.end()) - { - rot_after = mLoopInKey; - index_after = duration; - } - - F32 u = (time - index_before) / (index_after - index_before); - value = interp(u, rot_before, rot_after); - } - return value; -} - -//----------------------------------------------------------------------------- -// interp() -//----------------------------------------------------------------------------- -LLQuaternion LLKeyframeMotion::RotationCurve::interp(F32 u, RotationKey& before, RotationKey& after) -{ - switch (mInterpolationType) - { - case IT_STEP: - return before.mRotation; - - default: - case IT_LINEAR: - case IT_SPLINE: - return nlerp(u, before.mRotation, after.mRotation); - } -} - - -//----------------------------------------------------------------------------- -// PositionCurve::PositionCurve() -//----------------------------------------------------------------------------- -LLKeyframeMotion::PositionCurve::PositionCurve() -{ - mInterpolationType = LLKeyframeMotion::IT_LINEAR; - mNumKeys = 0; -} - -//----------------------------------------------------------------------------- -// PositionCurve::~PositionCurve() -//----------------------------------------------------------------------------- -LLKeyframeMotion::PositionCurve::~PositionCurve() -{ - mKeys.clear(); - mNumKeys = 0; -} - -//----------------------------------------------------------------------------- -// PositionCurve::getValue() -//----------------------------------------------------------------------------- -LLVector3 LLKeyframeMotion::PositionCurve::getValue(F32 time, F32 duration) -{ - LLVector3 value; - - if (mKeys.empty()) - { - value.clearVec(); - return value; - } - - key_map_t::iterator right = mKeys.lower_bound(time); - if (right == mKeys.end()) + //Singu: Also add memory used by the constraints. + S32 constraints_size = mConstraints.size() * sizeof(constraint_list_t::value_type); + total_size += constraints_size; + if (!silent) { - // Past last key - --right; - value = right->second.mPosition; - } - else if (right == mKeys.begin() || right->first == time) - { - // Before first key or exactly on a key - value = right->second.mPosition; - } - else - { - // Between two keys - key_map_t::iterator left = right; --left; - F32 index_before = left->first; - F32 index_after = right->first; - PositionKey& pos_before = left->second; - PositionKey& pos_after = right->second; - if (right == mKeys.end()) - { - pos_after = mLoopInKey; - index_after = duration; - } - - F32 u = (time - index_before) / (index_after - index_before); - value = interp(u, pos_before, pos_after); + LL_INFOS() << "\t" << mConstraints.size() << " constraints at " << constraints_size << " bytes" << LL_ENDL; + LL_INFOS() << "Size: " << total_size << " bytes" << LL_ENDL; } - llassert(value.isFinite()); - - return value; -} - -//----------------------------------------------------------------------------- -// interp() -//----------------------------------------------------------------------------- -LLVector3 LLKeyframeMotion::PositionCurve::interp(F32 u, PositionKey& before, PositionKey& after) -{ - switch (mInterpolationType) - { - case IT_STEP: - return before.mPosition; - default: - case IT_LINEAR: - case IT_SPLINE: - return lerp(before.mPosition, after.mPosition, u); - } + return total_size; } - //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // JointMotion class @@ -427,10 +194,11 @@ void LLKeyframeMotion::JointMotion::update(LLJointState* joint_state, F32 time, // LLKeyframeMotion() // Class Constructor //----------------------------------------------------------------------------- -LLKeyframeMotion::LLKeyframeMotion(const LLUUID &id) - : LLMotion(id), +LLKeyframeMotion::LLKeyframeMotion(const LLUUID &id, LLMotionController* controller) + : LLMotion(id, controller), mJointMotionList(NULL), mPelvisp(NULL), + mCharacter(NULL), mLastSkeletonSerialNum(0), mLastUpdateTime(0.f), mLastLoopedTime(0.f), @@ -452,9 +220,9 @@ LLKeyframeMotion::~LLKeyframeMotion() //----------------------------------------------------------------------------- // create() //----------------------------------------------------------------------------- -LLMotion *LLKeyframeMotion::create(const LLUUID &id) +LLMotion* LLKeyframeMotion::create(LLUUID const& id, LLMotionController* controller) { - return new LLKeyframeMotion(id); + return new LLKeyframeMotion(id, controller); } //----------------------------------------------------------------------------- @@ -466,7 +234,7 @@ LLPointer& LLKeyframeMotion::getJointState(U32 index) //llassert_always (index < (S32)mJointStates.size()); if(index >= (S32)mJointStates.size()) { - llwarns << "LLKeyframeMotion::getJointState: index >= size" << llendl; + LL_WARNS() << "LLKeyframeMotion::getJointState: index >= size" << LL_ENDL; index = (S32)mJointStates.size() - 1; } // @@ -484,7 +252,9 @@ LLJoint* LLKeyframeMotion::getJoint(U32 index) index = (S32)mJointStates.size() - 1; // LLJoint* joint = mJointStates[index]->getJoint(); - llassert_always (joint); + if(!joint) { + LL_WARNS_ONCE("Animation") << "Missing joint index:"<< index << " ID:" << mID << " Name:" << mName << LL_ENDL; + } return joint; } @@ -515,6 +285,7 @@ LLMotion::LLMotionInitStatus LLKeyframeMotion::onInitialize(LLCharacter *charact case ASSET_FETCHED: return STATUS_HOLD; case ASSET_FETCH_FAILED: + LL_WARNS() << "Trying to initialize a motion that failed to be fetched." << LL_ENDL; return STATUS_FAILURE; case ASSET_LOADED: return STATUS_SUCCESS; @@ -524,7 +295,7 @@ LLMotion::LLMotionInitStatus LLKeyframeMotion::onInitialize(LLCharacter *charact break; } - LLKeyframeMotion::JointMotionList* joint_motion_list = LLKeyframeDataCache::getKeyframeData(getID()); + LLKeyframeMotion::JointMotionListPtr joint_motion_list = LLKeyframeDataCache::getKeyframeData(getID()); if(joint_motion_list) { @@ -566,7 +337,7 @@ LLMotion::LLMotionInitStatus LLKeyframeMotion::onInitialize(LLCharacter *charact if (!sVFS) { - llerrs << "Must call LLKeyframeMotion::setVFS() first before loading a keyframe file!" << llendl; + LL_ERRS() << "Must call LLKeyframeMotion::setVFS() first before loading a keyframe file!" << LL_ENDL; } BOOL success = FALSE; @@ -592,18 +363,18 @@ LLMotion::LLMotionInitStatus LLKeyframeMotion::onInitialize(LLCharacter *charact if (!success) { - llwarns << "Can't open animation file " << mID << llendl; + LL_WARNS() << "Can't open animation file " << mID << LL_ENDL; mAssetStatus = ASSET_FETCH_FAILED; return STATUS_FAILURE; } - lldebugs << "Loading keyframe data for: " << getName() << ":" << getID() << " (" << anim_file_size << " bytes)" << llendl; + LL_DEBUGS() << "Loading keyframe data for: " << getName() << ":" << getID() << " (" << anim_file_size << " bytes)" << LL_ENDL; LLDataPackerBinaryBuffer dp(anim_data, anim_file_size); - if (!deserialize(dp)) + if (!deserialize(dp, getID())) { - llwarns << "Failed to decode asset for animation " << getName() << ":" << getID() << llendl; + LL_WARNS() << "Failed to decode asset for animation " << getName() << ":" << getID() << LL_ENDL; mAssetStatus = ASSET_FETCH_FAILED; return STATUS_FAILURE; } @@ -681,7 +452,8 @@ BOOL LLKeyframeMotion::onActivate() //----------------------------------------------------------------------------- BOOL LLKeyframeMotion::onUpdate(F32 time, U8* joint_mask) { - llassert(time >= 0.f); + // llassert(time >= 0.f); // This will fire + time = llmax(0.f, time); if (mJointMotionList->mLoop) { @@ -799,7 +571,44 @@ void LLKeyframeMotion::onDeactivate() //----------------------------------------------------------------------------- // setStopTime() //----------------------------------------------------------------------------- -// time is in seconds since character creation +// +// Consider a looping animation of 20 frames, where the loop in point is at 3 frames +// and the loop out point at 16 frames: +// +// The first 3 frames of the animation would be the "loop in" animation. +// The last 4 frames of the animation would be the "loop out" animation. +// Frames 4 through 15 would be the looping animation frames. +// +// If the animation would not be looping, all frames would just be played once sequentially: +// +// mActivationTimestamp -. +// v +// 0 3 15 16 20 +// | | \| | +// --------------------- +// <--> <-- mLoopInPoint (relative to mActivationTimestamp) +// <--------------> <-- mLoopOutPoint (relative to mActivationTimestamp) +// <----mDuration------> +// +// When looping the animation would repeat frames 3 to 16 (loop) a few times, for example: +// +// 0 3 15 3 15 3 15 3 15 16 20 +// | | loop 1 \| loop 2 \| loop 3 \| loop 4 \| | +// ------------------------------------------------------------ +//LOOP^ ^ LOOP +// IN | <----->| OUT +// start_loop_time loop_fraction_time-' time +// +// The time at which the animation is started corresponds to frame 0 and is stored +// in mActivationTimestamp (in seconds since character creation). +// +// If setStopTime() is called with a time somewhere inside loop 4, +// then 'loop_fraction_time' is the time from the beginning of +// loop 4 till 'time'. Thus 'time - loop_fraction_time' is the first +// frame of loop 4, and '(time - loop_fraction_time) + +// (mJointMotionList->mDuration - mJointMotionList->mLoopInPoint)' +// would correspond to frame 20. +// void LLKeyframeMotion::setStopTime(F32 time) { LLMotion::setStopTime(time); @@ -817,6 +626,8 @@ void LLKeyframeMotion::setStopTime(F32 time) loop_fraction_time = fmod(time - start_loop_time, mJointMotionList->mLoopOutPoint - mJointMotionList->mLoopInPoint); } + // This sets mStopTimestamp to the time that corresponds to the end of the animation (ie, frame 20 in the above example) + // minus the ease out duration, so that the animation eases out during the loop out and finishes exactly at the end. mStopTimestamp = llmax(time, (time - loop_fraction_time) + (mJointMotionList->mDuration - mJointMotionList->mLoopInPoint) - getEaseOutDuration()); } @@ -907,7 +718,7 @@ void LLKeyframeMotion::deactivateConstraint(JointConstraint *constraintp) constraintp->mSourceVolume->mUpdateXform = FALSE; } - if (!constraintp->mSharedData->mConstraintTargetType == CONSTRAINT_TARGET_TYPE_GROUND) + if (constraintp->mSharedData->mConstraintTargetType != CONSTRAINT_TARGET_TYPE_GROUND) { if (constraintp->mTargetVolume) { @@ -989,7 +800,8 @@ void LLKeyframeMotion::applyConstraint(JointConstraint* constraint, F32 time, U8 { case CONSTRAINT_TARGET_TYPE_GROUND: target_pos = mCharacter->getPosAgentFromGlobal(constraint->mGroundPos); -// llinfos << "Target Pos " << constraint->mGroundPos << " on " << mCharacter->findCollisionVolume(shared_data->mSourceConstraintVolume)->getName() << llendl; + //target_pos += mCharacter->getHoverOffset(); +// LL_INFOS() << "Target Pos " << constraint->mGroundPos << " on " << mCharacter->findCollisionVolume(shared_data->mSourceConstraintVolume)->getName() << LL_ENDL; break; case CONSTRAINT_TARGET_TYPE_BODY: target_pos = mCharacter->getVolumePos(shared_data->mTargetConstraintVolume, shared_data->mTargetConstraintOffset); @@ -1040,11 +852,11 @@ void LLKeyframeMotion::applyConstraint(JointConstraint* constraint, F32 time, U8 if (constraint->mSharedData->mChainLength != 0 && dist_vec_squared(root_pos, target_pos) * 0.95f > constraint->mTotalLength * constraint->mTotalLength) { - constraint->mWeight = lerp(constraint->mWeight, 0.f, LLCriticalDamp::getInterpolant(0.1f)); + constraint->mWeight = LLSmoothInterpolation::lerp(constraint->mWeight, 0.f, 0.1f); } else { - constraint->mWeight = lerp(constraint->mWeight, 1.f, LLCriticalDamp::getInterpolant(0.3f)); + constraint->mWeight = LLSmoothInterpolation::lerp(constraint->mWeight, 1.f, 0.3f); } F32 weight = constraint->mWeight * ((shared_data->mEaseOutStopTime == 0.f) ? 1.f : @@ -1053,7 +865,7 @@ void LLKeyframeMotion::applyConstraint(JointConstraint* constraint, F32 time, U8 LLVector3 source_to_target = target_pos - keyframe_source_pos; - S32 max_iteration_count = llround(clamp_rescale( + S32 max_iteration_count = ll_pos_round(clamp_rescale( mCharacter->getPixelArea(), MAX_PIXEL_AREA_CONSTRAINTS, MIN_PIXEL_AREA_CONSTRAINTS, @@ -1091,9 +903,9 @@ void LLKeyframeMotion::applyConstraint(JointConstraint* constraint, F32 time, U8 // convert intermediate joint positions to world coordinates positions[joint_num] = ( constraint->mPositions[joint_num] * mPelvisp->getWorldRotation()) + mPelvisp->getWorldPosition(); F32 time_constant = 1.f / clamp_rescale(constraint->mFixupDistanceRMS, 0.f, 0.5f, 0.2f, 8.f); -// llinfos << "Interpolant " << LLCriticalDamp::getInterpolant(time_constant, FALSE) << " and fixup distance " << constraint->mFixupDistanceRMS << " on " << mCharacter->findCollisionVolume(shared_data->mSourceConstraintVolume)->getName() << llendl; +// LL_INFOS() << "Interpolant " << LLSmoothInterpolation::getInterpolant(time_constant, FALSE) << " and fixup distance " << constraint->mFixupDistanceRMS << " on " << mCharacter->findCollisionVolume(shared_data->mSourceConstraintVolume)->getName() << LL_ENDL; positions[joint_num] = lerp(positions[joint_num], kinematic_position, - LLCriticalDamp::getInterpolant(time_constant, FALSE)); + LLSmoothInterpolation::getInterpolant(time_constant, FALSE)); } S32 iteration_count; @@ -1122,8 +934,8 @@ void LLKeyframeMotion::applyConstraint(JointConstraint* constraint, F32 time, U8 if ((iteration_count >= MIN_ITERATION_COUNT) && (num_joints_finished == shared_data->mChainLength - 1)) { -// llinfos << iteration_count << " iterations on " << -// mCharacter->findCollisionVolume(shared_data->mSourceConstraintVolume)->getName() << llendl; +// LL_INFOS() << iteration_count << " iterations on " << +// mCharacter->findCollisionVolume(shared_data->mSourceConstraintVolume)->getName() << LL_ENDL; break; } } @@ -1228,10 +1040,29 @@ void LLKeyframeMotion::applyConstraint(JointConstraint* constraint, F32 time, U8 //----------------------------------------------------------------------------- // deserialize() //----------------------------------------------------------------------------- -BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) +BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp, const LLUUID& asset_id) { BOOL old_version = FALSE; - mJointMotionList = new LLKeyframeMotion::JointMotionList; + + // + + // First add a new LLKeyframeMotion::JointMotionList to the cache, then assign a pointer + // to that to mJointMotionList. In LLs code the cache is never deleted again. Now it is + // is deleted when the last mJointMotionList pointer is destructed. + // + // It is possible that we get here for an already added animation, because animations can + // be requested multiple times (we get here from LLKeyframeMotion::onLoadComplete) when + // the animation was still downloading from a previous request for another LLMotionController + // object (avatar). In that case we just overwrite the old data while decoding it again. + mJointMotionList = LLKeyframeDataCache::getKeyframeData(getID()); + bool singu_new_joint_motion_list = !mJointMotionList; + if (singu_new_joint_motion_list) + { + // Create a new JointMotionList. + mJointMotionList = LLKeyframeDataCache::createKeyframeData(getID()); + } + + // //------------------------------------------------------------------------- // get base priority @@ -1242,13 +1073,13 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) if (!dp.unpackU16(version, "version")) { - llwarns << "can't read version number" << llendl; + LL_WARNS() << "can't read version number for animation " << asset_id << LL_ENDL; return FALSE; } if (!dp.unpackU16(sub_version, "sub_version")) { - llwarns << "can't read sub version number" << llendl; + LL_WARNS() << "can't read sub version number for animation " << asset_id << LL_ENDL; return FALSE; } @@ -1259,28 +1090,32 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) else if (version != KEYFRAME_MOTION_VERSION || sub_version != KEYFRAME_MOTION_SUBVERSION) { #if LL_RELEASE - llwarns << "Bad animation version " << version << "." << sub_version << llendl; + LL_WARNS() << "Bad animation version " << version << "." << sub_version + << " for animation " << asset_id << LL_ENDL; return FALSE; #else - llerrs << "Bad animation version " << version << "." << sub_version << llendl; + LL_ERRS() << "Bad animation version " << version << "." << sub_version + << " for animation " << asset_id << LL_ENDL; #endif } if (!dp.unpackS32(temp_priority, "base_priority")) { - llwarns << "can't read animation base_priority" << llendl; + LL_WARNS() << "can't read animation base_priority" + << " for animation " << asset_id << LL_ENDL; return FALSE; } mJointMotionList->mBasePriority = (LLJoint::JointPriority) temp_priority; if (mJointMotionList->mBasePriority >= LLJoint::ADDITIVE_PRIORITY) { - mJointMotionList->mBasePriority = (LLJoint::JointPriority)((int)LLJoint::ADDITIVE_PRIORITY-1); + mJointMotionList->mBasePriority = (LLJoint::JointPriority)((S32)LLJoint::ADDITIVE_PRIORITY-1); mJointMotionList->mMaxPriority = mJointMotionList->mBasePriority; } else if (mJointMotionList->mBasePriority < LLJoint::USE_MOTION_PRIORITY) { - llwarns << "bad animation base_priority " << mJointMotionList->mBasePriority << llendl; + LL_WARNS() << "bad animation base_priority " << mJointMotionList->mBasePriority + << " for animation " << asset_id << LL_ENDL; return FALSE; } @@ -1289,14 +1124,16 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) //------------------------------------------------------------------------- if (!dp.unpackF32(mJointMotionList->mDuration, "duration")) { - llwarns << "can't read duration" << llendl; + LL_WARNS() << "can't read duration" + << " for animation " << asset_id << LL_ENDL; return FALSE; } if (mJointMotionList->mDuration > MAX_ANIM_DURATION || - !llfinite(mJointMotionList->mDuration)) + !std::isfinite(mJointMotionList->mDuration)) { - llwarns << "invalid animation duration" << llendl; + LL_WARNS() << "invalid animation duration" + << " for animation " << asset_id << LL_ENDL; return FALSE; } @@ -1305,13 +1142,15 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) //------------------------------------------------------------------------- if (!dp.unpackString(mJointMotionList->mEmoteName, "emote_name")) { - llwarns << "can't read optional_emote_animation" << llendl; + LL_WARNS() << "can't read optional_emote_animation" + << " for animation " << asset_id << LL_ENDL; return FALSE; } if(mJointMotionList->mEmoteName==mID.asString()) { - llwarns << "Malformed animation mEmoteName==mID" << llendl; + LL_WARNS() << "Malformed animation mEmoteName==mID" + << " for animation " << asset_id << LL_ENDL; return FALSE; } @@ -1319,22 +1158,25 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) // get loop //------------------------------------------------------------------------- if (!dp.unpackF32(mJointMotionList->mLoopInPoint, "loop_in_point") || - !llfinite(mJointMotionList->mLoopInPoint)) + !std::isfinite(mJointMotionList->mLoopInPoint)) { - llwarns << "can't read loop point" << llendl; + LL_WARNS() << "can't read loop point" + << " for animation " << asset_id << LL_ENDL; return FALSE; } if (!dp.unpackF32(mJointMotionList->mLoopOutPoint, "loop_out_point") || - !llfinite(mJointMotionList->mLoopOutPoint)) + !std::isfinite(mJointMotionList->mLoopOutPoint)) { - llwarns << "can't read loop point" << llendl; + LL_WARNS() << "can't read loop point" + << " for animation " << asset_id << LL_ENDL; return FALSE; } if (!dp.unpackS32(mJointMotionList->mLoop, "loop")) { - llwarns << "can't read loop" << llendl; + LL_WARNS() << "can't read loop" + << " for animation " << asset_id << LL_ENDL; return FALSE; } @@ -1342,16 +1184,18 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) // get easeIn and easeOut //------------------------------------------------------------------------- if (!dp.unpackF32(mJointMotionList->mEaseInDuration, "ease_in_duration") || - !llfinite(mJointMotionList->mEaseInDuration)) + !std::isfinite(mJointMotionList->mEaseInDuration)) { - llwarns << "can't read easeIn" << llendl; + LL_WARNS() << "can't read easeIn" + << " for animation " << asset_id << LL_ENDL; return FALSE; } if (!dp.unpackF32(mJointMotionList->mEaseOutDuration, "ease_out_duration") || - !llfinite(mJointMotionList->mEaseOutDuration)) + !std::isfinite(mJointMotionList->mEaseOutDuration)) { - llwarns << "can't read easeOut" << llendl; + LL_WARNS() << "can't read easeOut" + << " for animation " << asset_id << LL_ENDL; return FALSE; } @@ -1361,13 +1205,15 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) U32 word; if (!dp.unpackU32(word, "hand_pose")) { - llwarns << "can't read hand pose" << llendl; + LL_WARNS() << "can't read hand pose" + << " for animation " << asset_id << LL_ENDL; return FALSE; } if(word > LLHandMotion::NUM_HAND_POSES) { - llwarns << "invalid LLHandMotion::eHandPose index: " << word << llendl; + LL_WARNS() << "invalid LLHandMotion::eHandPose index: " << word + << " for animation " << asset_id << LL_ENDL; return FALSE; } @@ -1379,23 +1225,28 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) U32 num_motions = 0; if (!dp.unpackU32(num_motions, "num_joints")) { - llwarns << "can't read number of joints" << llendl; + LL_WARNS() << "can't read number of joints" + << " for animation " << asset_id << LL_ENDL; return FALSE; } if (num_motions == 0) { - llwarns << "no joints in animation" << llendl; + LL_WARNS() << "no joints" + << " for animation " << asset_id << LL_ENDL; return FALSE; } - else if (num_motions > LL_CHARACTER_MAX_JOINTS) + else if (num_motions > LL_CHARACTER_MAX_ANIMATED_JOINTS) { - llwarns << "too many joints in animation" << llendl; + LL_WARNS() << "too many joints" + << " for animation " << asset_id << LL_ENDL; return FALSE; } - mJointMotionList->mJointMotionArray.clear(); - mJointMotionList->mJointMotionArray.reserve(num_motions); + if (singu_new_joint_motion_list) + { + mJointMotionList->mJointMotionArray.reserve(num_motions); + } mJointStates.clear(); mJointStates.reserve(num_motions); @@ -1405,19 +1256,26 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) for(U32 i=0; imJointMotionArray.push_back(joint_motion); + JointMotion* joint_motion = new JointMotion; + std::unique_ptr watcher(joint_motion); + if (singu_new_joint_motion_list) + { + // Pass ownership to mJointMotionList. + mJointMotionList->mJointMotionArray.push_back(watcher.release()); + } std::string joint_name; if (!dp.unpackString(joint_name, "joint_name")) { - llwarns << "can't read joint name" << llendl; + LL_WARNS() << "can't read joint name" + << " for animation " << asset_id << LL_ENDL; return FALSE; } if (joint_name == "mScreen" || joint_name == "mRoot") { - llwarns << "attempted to animate special " << joint_name << " joint" << llendl; + LL_WARNS() << "attempted to animate special " << joint_name << " joint" + << " for animation " << asset_id << LL_ENDL; return FALSE; } @@ -1427,7 +1285,16 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) LLJoint *joint = mCharacter->getJoint( joint_name ); if (joint) { -// llinfos << " joint: " << joint_name << llendl; + S32 joint_num = joint->getJointNum(); +// LL_INFOS() << " joint: " << joint_name << LL_ENDL; + if ((joint_num >= (S32)LL_CHARACTER_MAX_ANIMATED_JOINTS) || (joint_num < 0)) + { + LL_WARNS() << "Joint will be omitted from animation: joint_num " << joint_num + << " is outside of legal range [0-" + << LL_CHARACTER_MAX_ANIMATED_JOINTS << ") for joint " << joint->getName() + << " for animation " << asset_id << LL_ENDL; + joint = NULL; + } } else { @@ -1443,7 +1310,8 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) i++; } // - llwarns << "joint not found: " << joint_name << llendl; + LL_WARNS() << "invalid joint name: " << joint_name + << " for animation " << asset_id << LL_ENDL; //return FALSE; } @@ -1460,13 +1328,15 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) S32 joint_priority; if (!dp.unpackS32(joint_priority, "joint_priority")) { - llwarns << "can't read joint priority." << llendl; + LL_WARNS() << "can't read joint priority." + << " for animation " << asset_id << LL_ENDL; return FALSE; } if (joint_priority < LLJoint::USE_MOTION_PRIORITY) { - llwarns << "joint priority unknown - too low." << llendl; + LL_WARNS() << "joint priority unknown - too low." + << " for animation " << asset_id << LL_ENDL; return FALSE; } @@ -1484,7 +1354,8 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) //--------------------------------------------------------------------- if (!dp.unpackS32(joint_motion->mRotationCurve.mNumKeys, "num_rot_keys") || joint_motion->mRotationCurve.mNumKeys < 0) { - llwarns << "can't read number of rotation keys" << llendl; + LL_WARNS() << "can't read number of rotation keys" + << " for animation " << asset_id << LL_ENDL; return FALSE; } @@ -1507,9 +1378,10 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) if (old_version) { if (!dp.unpackF32(time, "time") || - !llfinite(time)) + !std::isfinite(time)) { - llwarns << "can't read rotation key (" << k << ")" << llendl; + LL_WARNS() << "can't read rotation key (" << k << ")" + << " for animation " << asset_id << LL_ENDL; return FALSE; } @@ -1518,7 +1390,8 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) { if (!dp.unpackU16(time_short, "time")) { - llwarns << "can't read rotation key (" << k << ")" << llendl; + LL_WARNS() << "can't read rotation key (" << k << ")" + << " for animation " << asset_id << LL_ENDL; return FALSE; } @@ -1526,7 +1399,8 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) if (time < 0 || time > mJointMotionList->mDuration) { - llwarns << "invalid frame time" << llendl; + LL_WARNS() << "invalid frame time" + << " for animation " << asset_id << LL_ENDL; return FALSE; } } @@ -1543,7 +1417,7 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) success = dp.unpackVector3(rot_angles, "rot_angles") && rot_angles.isFinite(); LLQuaternion::Order ro = StringToOrder("ZYX"); - rot_key.mRotation = mayaQ(rot_angles.mV[VX], rot_angles.mV[VY], rot_angles.mV[VZ], ro); + rot_key.mValue = mayaQ(rot_angles.mV[VX], rot_angles.mV[VY], rot_angles.mV[VZ], ro); } else { @@ -1555,30 +1429,35 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) rot_vec.mV[VX] = U16_to_F32(x, -1.f, 1.f); rot_vec.mV[VY] = U16_to_F32(y, -1.f, 1.f); rot_vec.mV[VZ] = U16_to_F32(z, -1.f, 1.f); - rot_key.mRotation.unpackFromVector3(rot_vec); + rot_key.mValue.unpackFromVector3(rot_vec); } - if( !(rot_key.mRotation.isFinite()) ) + if( !(rot_key.mValue.isFinite()) ) { - llwarns << "non-finite angle in rotation key" << llendl; + LL_WARNS() << "non-finite angle in rotation key" + << " for animation " << asset_id << LL_ENDL; success = FALSE; } if (!success) { - llwarns << "can't read rotation key (" << k << ")" << llendl; + LL_WARNS() << "can't read rotation key (" << k << ")" + << " for animation " << asset_id << LL_ENDL; return FALSE; } - rCurve->mKeys[time] = rot_key; + rCurve->mKeys.emplace_back(time, rot_key); } + std::sort(rCurve->mKeys.begin(), rCurve->mKeys.end(), [](const auto& a, const auto& b) { return a.first < b.first; }); + //--------------------------------------------------------------------- // scan position curve header //--------------------------------------------------------------------- if (!dp.unpackS32(joint_motion->mPositionCurve.mNumKeys, "num_pos_keys") || joint_motion->mPositionCurve.mNumKeys < 0) { - llwarns << "can't read number of position keys" << llendl; + LL_WARNS() << "can't read number of position keys" + << " for animation " << asset_id << LL_ENDL; return FALSE; } @@ -1601,9 +1480,10 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) if (old_version) { if (!dp.unpackF32(pos_key.mTime, "time") || - !llfinite(pos_key.mTime)) + !std::isfinite(pos_key.mTime)) { - llwarns << "can't read position key (" << k << ")" << llendl; + LL_WARNS() << "can't read position key (" << k << ")" + << " for animation " << asset_id << LL_ENDL; return FALSE; } } @@ -1611,7 +1491,8 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) { if (!dp.unpackU16(time_short, "time")) { - llwarns << "can't read position key (" << k << ")" << llendl; + LL_WARNS() << "can't read position key (" << k << ")" + << " for animation " << asset_id << LL_ENDL; return FALSE; } @@ -1622,7 +1503,13 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) if (old_version) { - success = dp.unpackVector3(pos_key.mPosition, "pos"); + success = dp.unpackVector3(pos_key.mValue, "pos"); + + //MAINT-6162 + pos_key.mValue.mV[VX] = llclamp( pos_key.mValue.mV[VX], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET); + pos_key.mValue.mV[VY] = llclamp( pos_key.mValue.mV[VY], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET); + pos_key.mValue.mV[VZ] = llclamp( pos_key.mValue.mV[VZ], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET); + } else { @@ -1632,31 +1519,36 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) success &= dp.unpackU16(y, "pos_y"); success &= dp.unpackU16(z, "pos_z"); - pos_key.mPosition.mV[VX] = U16_to_F32(x, -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET); - pos_key.mPosition.mV[VY] = U16_to_F32(y, -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET); - pos_key.mPosition.mV[VZ] = U16_to_F32(z, -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET); + pos_key.mValue.mV[VX] = U16_to_F32(x, -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET); + pos_key.mValue.mV[VY] = U16_to_F32(y, -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET); + pos_key.mValue.mV[VZ] = U16_to_F32(z, -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET); } - if( !(pos_key.mPosition.isFinite()) ) + if( !(pos_key.mValue.isFinite()) ) { - llwarns << "non-finite position in key" << llendl; + LL_WARNS() << "non-finite position in key" + << " for animation " << asset_id << LL_ENDL; success = FALSE; } if (!success) { - llwarns << "can't read position key (" << k << ")" << llendl; + LL_WARNS() << "can't read position key (" << k << ")" + << " for animation " << asset_id << LL_ENDL; return FALSE; } - pCurve->mKeys[pos_key.mTime] = pos_key; + pCurve->mKeys.emplace_back(pos_key.mTime, pos_key); if (is_pelvis) { - mJointMotionList->mPelvisBBox.addPoint(pos_key.mPosition); + mJointMotionList->mPelvisBBox.addPoint(pos_key.mValue); } + } + std::sort(pCurve->mKeys.begin(), pCurve->mKeys.end(), [](const auto& a, const auto& b) { return a.first < b.first; }); + joint_motion->mUsage = joint_state->getUsage(); } @@ -1666,13 +1558,15 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) S32 num_constraints = 0; if (!dp.unpackS32(num_constraints, "num_constraints")) { - llwarns << "can't read number of constraints" << llendl; + LL_WARNS() << "can't read number of constraints" + << " for animation " << asset_id << LL_ENDL; return FALSE; } if (num_constraints > MAX_CONSTRAINTS || num_constraints < 0) { - llwarns << "Bad number of constraints... ignoring: " << num_constraints << llendl; + LL_WARNS() << "Bad number of constraints... ignoring: " << num_constraints + << " for animation " << asset_id << LL_ENDL; } else { @@ -1683,35 +1577,36 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) for(S32 i = 0; i < num_constraints; ++i) { // read in constraint data - JointConstraintSharedData* constraintp = new JointConstraintSharedData; + auto constraintp = new JointConstraintSharedData; + std::unique_ptr watcher(constraintp); U8 byte = 0; if (!dp.unpackU8(byte, "chain_length")) { - llwarns << "can't read constraint chain length" << llendl; - delete constraintp; + LL_WARNS() << "can't read constraint chain length" + << " for animation " << asset_id << LL_ENDL; return FALSE; } constraintp->mChainLength = (S32) byte; if((U32)constraintp->mChainLength > mJointMotionList->getNumJointMotions()) { - llwarns << "invalid constraint chain length" << llendl; - delete constraintp; + LL_WARNS() << "invalid constraint chain length" + << " for animation " << asset_id << LL_ENDL; return FALSE; } if (!dp.unpackU8(byte, "constraint_type")) { - llwarns << "can't read constraint type" << llendl; - delete constraintp; + LL_WARNS() << "can't read constraint type" + << " for animation " << asset_id << LL_ENDL; return FALSE; } if( byte >= NUM_CONSTRAINT_TYPES ) { - llwarns << "invalid constraint type" << llendl; - delete constraintp; + LL_WARNS() << "invalid constraint type" + << " for animation " << asset_id << LL_ENDL; return FALSE; } constraintp->mConstraintType = (EConstraintType)byte; @@ -1720,42 +1615,39 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) U8 bin_data[BIN_DATA_LENGTH+1]; if (!dp.unpackBinaryDataFixed(bin_data, BIN_DATA_LENGTH, "source_volume")) { - llwarns << "can't read source volume name" << llendl; - delete constraintp; + LL_WARNS() << "can't read source volume name" + << " for animation " << asset_id << LL_ENDL; return FALSE; } bin_data[BIN_DATA_LENGTH] = 0; // Ensure null termination str = (char*)bin_data; constraintp->mSourceConstraintVolume = mCharacter->getCollisionVolumeID(str); - - // - if(constraintp->mSourceConstraintVolume == -1) + if (constraintp->mSourceConstraintVolume == -1) { - llwarns << "can't get source constraint volume" << llendl; - delete constraintp; + LL_WARNS() << "not a valid source constraint volume " << str + << " for animation " << asset_id << LL_ENDL; return FALSE; } - // if (!dp.unpackVector3(constraintp->mSourceConstraintOffset, "source_offset")) { - llwarns << "can't read constraint source offset" << llendl; - delete constraintp; + LL_WARNS() << "can't read constraint source offset" + << " for animation " << asset_id << LL_ENDL; return FALSE; } if( !(constraintp->mSourceConstraintOffset.isFinite()) ) { - llwarns << "non-finite constraint source offset" << llendl; - delete constraintp; + LL_WARNS() << "non-finite constraint source offset" + << " for animation " << asset_id << LL_ENDL; return FALSE; } if (!dp.unpackBinaryDataFixed(bin_data, BIN_DATA_LENGTH, "target_volume")) { - llwarns << "can't read target volume name" << llendl; - delete constraintp; + LL_WARNS() << "can't read target volume name" + << " for animation " << asset_id << LL_ENDL; return FALSE; } @@ -1770,33 +1662,39 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) { constraintp->mConstraintTargetType = CONSTRAINT_TARGET_TYPE_BODY; constraintp->mTargetConstraintVolume = mCharacter->getCollisionVolumeID(str); + if (constraintp->mTargetConstraintVolume == -1) + { + LL_WARNS() << "not a valid target constraint volume " << str + << " for animation " << asset_id << LL_ENDL; + return FALSE; + } } if (!dp.unpackVector3(constraintp->mTargetConstraintOffset, "target_offset")) { - llwarns << "can't read constraint target offset" << llendl; - delete constraintp; + LL_WARNS() << "can't read constraint target offset" + << " for animation " << asset_id << LL_ENDL; return FALSE; } if( !(constraintp->mTargetConstraintOffset.isFinite()) ) { - llwarns << "non-finite constraint target offset" << llendl; - delete constraintp; + LL_WARNS() << "non-finite constraint target offset" + << " for animation " << asset_id << LL_ENDL; return FALSE; } if (!dp.unpackVector3(constraintp->mTargetConstraintDir, "target_dir")) { - llwarns << "can't read constraint target direction" << llendl; - delete constraintp; + LL_WARNS() << "can't read constraint target direction" + << " for animation " << asset_id << LL_ENDL; return FALSE; } if( !(constraintp->mTargetConstraintDir.isFinite()) ) { - llwarns << "non-finite constraint target direction" << llendl; - delete constraintp; + LL_WARNS() << "non-finite constraint target direction" + << " for animation " << asset_id << LL_ENDL; return FALSE; } @@ -1806,38 +1704,41 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) // constraintp->mTargetConstraintDir *= constraintp->mSourceConstraintOffset.magVec(); } - if (!dp.unpackF32(constraintp->mEaseInStartTime, "ease_in_start") || !llfinite(constraintp->mEaseInStartTime)) + if (!dp.unpackF32(constraintp->mEaseInStartTime, "ease_in_start") || !std::isfinite(constraintp->mEaseInStartTime)) { - llwarns << "can't read constraint ease in start time" << llendl; - delete constraintp; + LL_WARNS() << "can't read constraint ease in start time" + << " for animation " << asset_id << LL_ENDL; return FALSE; } - if (!dp.unpackF32(constraintp->mEaseInStopTime, "ease_in_stop") || !llfinite(constraintp->mEaseInStopTime)) + if (!dp.unpackF32(constraintp->mEaseInStopTime, "ease_in_stop") || !std::isfinite(constraintp->mEaseInStopTime)) { - llwarns << "can't read constraint ease in stop time" << llendl; - delete constraintp; + LL_WARNS() << "can't read constraint ease in stop time" + << " for animation " << asset_id << LL_ENDL; return FALSE; } - if (!dp.unpackF32(constraintp->mEaseOutStartTime, "ease_out_start") || !llfinite(constraintp->mEaseOutStartTime)) + if (!dp.unpackF32(constraintp->mEaseOutStartTime, "ease_out_start") || !std::isfinite(constraintp->mEaseOutStartTime)) { - llwarns << "can't read constraint ease out start time" << llendl; - delete constraintp; + LL_WARNS() << "can't read constraint ease out start time" + << " for animation " << asset_id << LL_ENDL; return FALSE; } - if (!dp.unpackF32(constraintp->mEaseOutStopTime, "ease_out_stop") || !llfinite(constraintp->mEaseOutStopTime)) + if (!dp.unpackF32(constraintp->mEaseOutStopTime, "ease_out_stop") || !std::isfinite(constraintp->mEaseOutStopTime)) { - llwarns << "can't read constraint ease out stop time" << llendl; - delete constraintp; + LL_WARNS() << "can't read constraint ease out stop time" + << " for animation " << asset_id << LL_ENDL; return FALSE; } - mJointMotionList->mConstraints.push_front(constraintp); - constraintp->mJointStateIndices = new S32[constraintp->mChainLength + 1]; // note: mChainLength is size-limited - comes from a byte + if (singu_new_joint_motion_list) + { + mJointMotionList->mConstraints.push_front(watcher.release()); + } + LLJoint* joint = mCharacter->findCollisionVolume(constraintp->mSourceConstraintVolume); // get joint to which this collision volume is attached if (!joint) @@ -1849,8 +1750,9 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) LLJoint* parent = joint->getParent(); if (!parent) { - llwarns << "Joint with no parent: " << joint->getName() - << " Emote: " << mJointMotionList->mEmoteName << llendl; + LL_WARNS() << "Joint with no parent: " << joint->getName() + << " Emote: " << mJointMotionList->mEmoteName + << " for animation " << asset_id << LL_ENDL; return FALSE; } joint = parent; @@ -1861,7 +1763,8 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) if ( !constraint_joint ) { - llwarns << "Invalid joint " << j << llendl; + LL_WARNS() << "Invalid joint " << j + << " for animation " << asset_id << LL_ENDL; return FALSE; } @@ -1873,16 +1776,14 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp) } if (constraintp->mJointStateIndices[i] < 0 ) { - llwarns << "No joint index for constraint " << i << llendl; - delete constraintp; + LL_WARNS() << "No joint index for constraint " << i + << " for animation " << asset_id << LL_ENDL; return FALSE; } } } } - // *FIX: support cleanup of old keyframe data - LLKeyframeDataCache::addKeyframeData(getID(), mJointMotionList); mAssetStatus = ASSET_LOADED; setupPose(); @@ -1897,6 +1798,8 @@ BOOL LLKeyframeMotion::serialize(LLDataPacker& dp) const { BOOL success = TRUE; + LL_DEBUGS("BVH") << "serializing" << LL_ENDL; + success &= dp.packU16(KEYFRAME_MOTION_VERSION, "version"); success &= dp.packU16(KEYFRAME_MOTION_SUBVERSION, "sub_version"); success &= dp.packS32(mJointMotionList->mBasePriority, "base_priority"); @@ -1910,6 +1813,19 @@ BOOL LLKeyframeMotion::serialize(LLDataPacker& dp) const success &= dp.packU32(mJointMotionList->mHandPose, "hand_pose"); success &= dp.packU32(mJointMotionList->getNumJointMotions(), "num_joints"); + LL_DEBUGS("BVH") << "version " << KEYFRAME_MOTION_VERSION << LL_ENDL; + LL_DEBUGS("BVH") << "sub_version " << KEYFRAME_MOTION_SUBVERSION << LL_ENDL; + LL_DEBUGS("BVH") << "base_priority " << mJointMotionList->mBasePriority << LL_ENDL; + LL_DEBUGS("BVH") << "duration " << mJointMotionList->mDuration << LL_ENDL; + LL_DEBUGS("BVH") << "emote_name " << mJointMotionList->mEmoteName << LL_ENDL; + LL_DEBUGS("BVH") << "loop_in_point " << mJointMotionList->mLoopInPoint << LL_ENDL; + LL_DEBUGS("BVH") << "loop_out_point " << mJointMotionList->mLoopOutPoint << LL_ENDL; + LL_DEBUGS("BVH") << "loop " << mJointMotionList->mLoop << LL_ENDL; + LL_DEBUGS("BVH") << "ease_in_duration " << mJointMotionList->mEaseInDuration << LL_ENDL; + LL_DEBUGS("BVH") << "ease_out_duration " << mJointMotionList->mEaseOutDuration << LL_ENDL; + LL_DEBUGS("BVH") << "hand_pose " << mJointMotionList->mHandPose << LL_ENDL; + LL_DEBUGS("BVH") << "num_joints " << mJointMotionList->getNumJointMotions() << LL_ENDL; + for (U32 i = 0; i < mJointMotionList->getNumJointMotions(); i++) { JointMotion* joint_motionp = mJointMotionList->getJointMotion(i); @@ -1917,6 +1833,7 @@ BOOL LLKeyframeMotion::serialize(LLDataPacker& dp) const success &= dp.packS32(joint_motionp->mPriority, "joint_priority"); success &= dp.packS32(joint_motionp->mRotationCurve.mNumKeys, "num_rot_keys"); + LL_DEBUGS("BVH") << "Joint " << joint_motionp->mJointName << LL_ENDL; for (RotationCurve::key_map_t::iterator iter = joint_motionp->mRotationCurve.mKeys.begin(); iter != joint_motionp->mRotationCurve.mKeys.end(); ++iter) { @@ -1924,7 +1841,7 @@ BOOL LLKeyframeMotion::serialize(LLDataPacker& dp) const U16 time_short = F32_to_U16(rot_key.mTime, 0.f, mJointMotionList->mDuration); success &= dp.packU16(time_short, "time"); - LLVector3 rot_angles = rot_key.mRotation.packToVector3(); + LLVector3 rot_angles = rot_key.mValue.packToVector3(); U16 x, y, z; rot_angles.quantize16(-1.f, 1.f, -1.f, 1.f); @@ -1934,6 +1851,8 @@ BOOL LLKeyframeMotion::serialize(LLDataPacker& dp) const success &= dp.packU16(x, "rot_angle_x"); success &= dp.packU16(y, "rot_angle_y"); success &= dp.packU16(z, "rot_angle_z"); + + LL_DEBUGS("BVH") << " rot: t " << rot_key.mTime << " angles " << rot_angles.mV[VX] <<","<< rot_angles.mV[VY] <<","<< rot_angles.mV[VZ] << LL_ENDL; } success &= dp.packS32(joint_motionp->mPositionCurve.mNumKeys, "num_pos_keys"); @@ -1945,44 +1864,61 @@ BOOL LLKeyframeMotion::serialize(LLDataPacker& dp) const success &= dp.packU16(time_short, "time"); U16 x, y, z; - pos_key.mPosition.quantize16(-LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET, -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET); - x = F32_to_U16(pos_key.mPosition.mV[VX], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET); - y = F32_to_U16(pos_key.mPosition.mV[VY], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET); - z = F32_to_U16(pos_key.mPosition.mV[VZ], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET); + pos_key.mValue.quantize16(-LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET, -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET); + x = F32_to_U16(pos_key.mValue.mV[VX], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET); + y = F32_to_U16(pos_key.mValue.mV[VY], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET); + z = F32_to_U16(pos_key.mValue.mV[VZ], -LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET); success &= dp.packU16(x, "pos_x"); success &= dp.packU16(y, "pos_y"); success &= dp.packU16(z, "pos_z"); + + LL_DEBUGS("BVH") << " pos: t " << pos_key.mTime << " pos " << pos_key.mValue.mV[VX] <<","<< pos_key.mValue.mV[VY] <<","<< pos_key.mValue.mV[VZ] << LL_ENDL; } } success &= dp.packS32(mJointMotionList->mConstraints.size(), "num_constraints"); + LL_DEBUGS("BVH") << "num_constraints " << mJointMotionList->mConstraints.size() << LL_ENDL; for (JointMotionList::constraint_list_t::const_iterator iter = mJointMotionList->mConstraints.begin(); iter != mJointMotionList->mConstraints.end(); ++iter) { JointConstraintSharedData* shared_constraintp = *iter; success &= dp.packU8(shared_constraintp->mChainLength, "chain_length"); success &= dp.packU8(shared_constraintp->mConstraintType, "constraint_type"); - char volume_name[16]; /* Flawfinder: ignore */ - snprintf(volume_name, sizeof(volume_name), "%s", /* Flawfinder: ignore */ + char source_volume[16]; /* Flawfinder: ignore */ + snprintf(source_volume, sizeof(source_volume), "%s", /* Flawfinder: ignore */ mCharacter->findCollisionVolume(shared_constraintp->mSourceConstraintVolume)->getName().c_str()); - success &= dp.packBinaryDataFixed((U8*)volume_name, 16, "source_volume"); + + success &= dp.packBinaryDataFixed((U8*)source_volume, 16, "source_volume"); success &= dp.packVector3(shared_constraintp->mSourceConstraintOffset, "source_offset"); + char target_volume[16]; /* Flawfinder: ignore */ if (shared_constraintp->mConstraintTargetType == CONSTRAINT_TARGET_TYPE_GROUND) { - snprintf(volume_name,sizeof(volume_name), "%s", "GROUND"); /* Flawfinder: ignore */ + snprintf(target_volume,sizeof(target_volume), "%s", "GROUND"); /* Flawfinder: ignore */ } else { - snprintf(volume_name, sizeof(volume_name),"%s", /* Flawfinder: ignore */ + snprintf(target_volume, sizeof(target_volume),"%s", /* Flawfinder: ignore */ mCharacter->findCollisionVolume(shared_constraintp->mTargetConstraintVolume)->getName().c_str()); } - success &= dp.packBinaryDataFixed((U8*)volume_name, 16, "target_volume"); + success &= dp.packBinaryDataFixed((U8*)target_volume, 16, "target_volume"); success &= dp.packVector3(shared_constraintp->mTargetConstraintOffset, "target_offset"); success &= dp.packVector3(shared_constraintp->mTargetConstraintDir, "target_dir"); success &= dp.packF32(shared_constraintp->mEaseInStartTime, "ease_in_start"); success &= dp.packF32(shared_constraintp->mEaseInStopTime, "ease_in_stop"); success &= dp.packF32(shared_constraintp->mEaseOutStartTime, "ease_out_start"); success &= dp.packF32(shared_constraintp->mEaseOutStopTime, "ease_out_stop"); + + LL_DEBUGS("BVH") << " chain_length " << shared_constraintp->mChainLength << LL_ENDL; + LL_DEBUGS("BVH") << " constraint_type " << (S32)shared_constraintp->mConstraintType << LL_ENDL; + LL_DEBUGS("BVH") << " source_volume " << source_volume << LL_ENDL; + LL_DEBUGS("BVH") << " source_offset " << shared_constraintp->mSourceConstraintOffset << LL_ENDL; + LL_DEBUGS("BVH") << " target_volume " << target_volume << LL_ENDL; + LL_DEBUGS("BVH") << " target_offset " << shared_constraintp->mTargetConstraintOffset << LL_ENDL; + LL_DEBUGS("BVH") << " target_dir " << shared_constraintp->mTargetConstraintDir << LL_ENDL; + LL_DEBUGS("BVH") << " ease_in_start " << shared_constraintp->mEaseInStartTime << LL_ENDL; + LL_DEBUGS("BVH") << " ease_in_stop " << shared_constraintp->mEaseInStopTime << LL_ENDL; + LL_DEBUGS("BVH") << " ease_out_start " << shared_constraintp->mEaseOutStartTime << LL_ENDL; + LL_DEBUGS("BVH") << " ease_out_stop " << shared_constraintp->mEaseOutStopTime << LL_ENDL; } return success; @@ -2043,7 +1979,7 @@ void LLKeyframeMotion::setEmote(const LLUUID& emote_id) } else { - mJointMotionList->mEmoteName = ""; + mJointMotionList->mEmoteName.clear(); } } @@ -2114,9 +2050,9 @@ void LLKeyframeMotion::setLoopIn(F32 in_point) rot_curve->mLoopInKey.mTime = mJointMotionList->mLoopInPoint; scale_curve->mLoopInKey.mTime = mJointMotionList->mLoopInPoint; - pos_curve->mLoopInKey.mPosition = pos_curve->getValue(mJointMotionList->mLoopInPoint, mJointMotionList->mDuration); - rot_curve->mLoopInKey.mRotation = rot_curve->getValue(mJointMotionList->mLoopInPoint, mJointMotionList->mDuration); - scale_curve->mLoopInKey.mScale = scale_curve->getValue(mJointMotionList->mLoopInPoint, mJointMotionList->mDuration); + pos_curve->mLoopInKey.mValue = pos_curve->getValue(mJointMotionList->mLoopInPoint, mJointMotionList->mDuration); + rot_curve->mLoopInKey.mValue = rot_curve->getValue(mJointMotionList->mLoopInPoint, mJointMotionList->mDuration); + scale_curve->mLoopInKey.mValue = scale_curve->getValue(mJointMotionList->mLoopInPoint, mJointMotionList->mDuration); } } } @@ -2143,9 +2079,9 @@ void LLKeyframeMotion::setLoopOut(F32 out_point) rot_curve->mLoopOutKey.mTime = mJointMotionList->mLoopOutPoint; scale_curve->mLoopOutKey.mTime = mJointMotionList->mLoopOutPoint; - pos_curve->mLoopOutKey.mPosition = pos_curve->getValue(mJointMotionList->mLoopOutPoint, mJointMotionList->mDuration); - rot_curve->mLoopOutKey.mRotation = rot_curve->getValue(mJointMotionList->mLoopOutPoint, mJointMotionList->mDuration); - scale_curve->mLoopOutKey.mScale = scale_curve->getValue(mJointMotionList->mLoopOutPoint, mJointMotionList->mDuration); + pos_curve->mLoopOutKey.mValue = pos_curve->getValue(mJointMotionList->mLoopOutPoint, mJointMotionList->mDuration); + rot_curve->mLoopOutKey.mValue = rot_curve->getValue(mJointMotionList->mLoopOutPoint, mJointMotionList->mDuration); + scale_curve->mLoopOutKey.mValue = scale_curve->getValue(mJointMotionList->mLoopOutPoint, mJointMotionList->mDuration); } } } @@ -2178,7 +2114,7 @@ void LLKeyframeMotion::onLoadComplete(LLVFS *vfs, LLCharacter* character = *char_iter; // look for an existing instance of this motion - LLKeyframeMotion* motionp = (LLKeyframeMotion*) character->findMotion(asset_uuid); + LLKeyframeMotion* motionp = dynamic_cast (character->findMotion(asset_uuid)); if (motionp) { if (0 == status) @@ -2193,17 +2129,17 @@ void LLKeyframeMotion::onLoadComplete(LLVFS *vfs, U8* buffer = new U8[size]; file.read((U8*)buffer, size); /*Flawfinder: ignore*/ - - lldebugs << "Loading keyframe data for: " << motionp->getName() << ":" << motionp->getID() << " (" << size << " bytes)" << llendl; + + LL_DEBUGS("Animation") << "Loading keyframe data for: " << motionp->getName() << ":" << motionp->getID() << " (" << size << " bytes)" << LL_ENDL; LLDataPackerBinaryBuffer dp(buffer, size); - if (motionp->deserialize(dp)) + if (motionp->deserialize(dp, asset_uuid)) { motionp->mAssetStatus = ASSET_LOADED; } else { - llwarns << "Failed to decode asset for animation " << motionp->getName() << ":" << motionp->getID() << llendl; + LL_WARNS() << "Failed to decode asset for animation " << motionp->getName() << ":" << motionp->getID() << LL_ENDL; motionp->mAssetStatus = ASSET_FETCH_FAILED; } @@ -2211,29 +2147,37 @@ void LLKeyframeMotion::onLoadComplete(LLVFS *vfs, } else { - llwarns << "Failed to load asset for animation " << motionp->getName() << ":" << motionp->getID() << llendl; + LL_WARNS() << "Failed to load asset for animation " << motionp->getName() << ":" << motionp->getID() << LL_ENDL; motionp->mAssetStatus = ASSET_FETCH_FAILED; } } else { - llwarns << "No existing motion for asset data. UUID: " << asset_uuid << llendl; + LL_WARNS() << "No existing motion for asset data. UUID: " << asset_uuid << LL_ENDL; } } //-------------------------------------------------------------------- // LLKeyframeDataCache::dumpDiagInfo() //-------------------------------------------------------------------- -void LLKeyframeDataCache::dumpDiagInfo() +// +// quiet = 0 : print everything in detail. +// 1 : print the UUIDs of all animations in the cache and the total memory usage. +// 2 : only print the total memory usage. +// +void LLKeyframeDataCache::dumpDiagInfo(int quiet) { // keep track of totals U32 total_size = 0; char buf[1024]; /* Flawfinder: ignore */ - llinfos << "-----------------------------------------------------" << llendl; - llinfos << " Global Motion Table (DEBUG only)" << llendl; - llinfos << "-----------------------------------------------------" << llendl; + if (quiet < 2) + { + LL_INFOS() << "-----------------------------------------------------" << LL_ENDL; + LL_INFOS() << " Global Motion Table (DEBUG only)" << LL_ENDL; + LL_INFOS() << "-----------------------------------------------------" << LL_ENDL; + } // print each loaded mesh, and it's memory usage for (keyframe_data_map_t::iterator map_it = sKeyframeDataMap.begin(); @@ -2241,30 +2185,46 @@ void LLKeyframeDataCache::dumpDiagInfo() { U32 joint_motion_kb; - LLKeyframeMotion::JointMotionList *motion_list_p = map_it->second; - - llinfos << "Motion: " << map_it->first << llendl; + LLKeyframeMotion::JointMotionList const* motion_list_p = map_it->get(); - joint_motion_kb = motion_list_p->dumpDiagInfo(); + if (quiet < 2) + { + LL_INFOS() << "Motion: " << map_it->key() << LL_ENDL; + } - total_size += joint_motion_kb; + if (motion_list_p) + { + joint_motion_kb = motion_list_p->dumpDiagInfo(quiet); + total_size += joint_motion_kb; + } } - llinfos << "-----------------------------------------------------" << llendl; - llinfos << "Motions\tTotal Size" << llendl; + if (quiet < 2) + { + LL_INFOS() << "-----------------------------------------------------" << LL_ENDL; + } + LL_INFOS() << "Motions\tTotal Size" << LL_ENDL; snprintf(buf, sizeof(buf), "%d\t\t%d bytes", (S32)sKeyframeDataMap.size(), total_size ); /* Flawfinder: ignore */ - llinfos << buf << llendl; - llinfos << "-----------------------------------------------------" << llendl; + LL_INFOS() << buf << LL_ENDL; + if (quiet < 2) + { + LL_INFOS() << "-----------------------------------------------------" << LL_ENDL; + } } //-------------------------------------------------------------------- -// LLKeyframeDataCache::addKeyframeData() +// LLKeyframeDataCache::createKeyframeData() //-------------------------------------------------------------------- -void LLKeyframeDataCache::addKeyframeData(const LLUUID& id, LLKeyframeMotion::JointMotionList* joint_motion_listp) +// This function replaces LLKeyframeDataCache::addKeyframeData and was rewritten to fix a memory leak (aka, the usage of AICachedPointer). +LLKeyframeMotion::JointMotionListPtr LLKeyframeDataCache::createKeyframeData(LLUUID const& id) { - sKeyframeDataMap[id] = joint_motion_listp; + std::pair result = + sKeyframeDataMap.insert(AICachedPointer(id, new LLKeyframeMotion::JointMotionList, &sKeyframeDataMap)); + llassert(result.second); // id may not already exist in the cache. + return &*result.first; // Construct and return a JointMotionListPt from a pointer to the actually inserted AICachedPointer. } +// //-------------------------------------------------------------------- // LLKeyframeDataCache::removeKeyframeData() @@ -2274,7 +2234,6 @@ void LLKeyframeDataCache::removeKeyframeData(const LLUUID& id) keyframe_data_map_t::iterator found_data = sKeyframeDataMap.find(id); if (found_data != sKeyframeDataMap.end()) { - delete found_data->second; sKeyframeDataMap.erase(found_data); } } @@ -2282,14 +2241,14 @@ void LLKeyframeDataCache::removeKeyframeData(const LLUUID& id) //-------------------------------------------------------------------- // LLKeyframeDataCache::getKeyframeData() //-------------------------------------------------------------------- -LLKeyframeMotion::JointMotionList* LLKeyframeDataCache::getKeyframeData(const LLUUID& id) +LLKeyframeMotion::JointMotionListPtr LLKeyframeDataCache::getKeyframeData(const LLUUID& id) { keyframe_data_map_t::iterator found_data = sKeyframeDataMap.find(id); if (found_data == sKeyframeDataMap.end()) { return NULL; } - return found_data->second; + return &*found_data; // Construct and return a JointMotionListPt from a pointer to the found AICachedPointer. } //-------------------------------------------------------------------- @@ -2305,7 +2264,6 @@ LLKeyframeDataCache::~LLKeyframeDataCache() //----------------------------------------------------------------------------- void LLKeyframeDataCache::clear() { - for_each(sKeyframeDataMap.begin(), sKeyframeDataMap.end(), DeletePairedPointer()); sKeyframeDataMap.clear(); } diff --git a/indra/llcharacter/llkeyframemotion.h b/indra/llcharacter/llkeyframemotion.h index 50d9d05046..82244465bf 100644 --- a/indra/llcharacter/llkeyframemotion.h +++ b/indra/llcharacter/llkeyframemotion.h @@ -5,6 +5,7 @@ * $LicenseInfo:firstyear=2001&license=viewergpl$ * * Copyright (c) 2001-2009, Linden Research, Inc. + * AICachedPointer and AICachedPointPtr copyright (c) 2013, Aleric Inglewood. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab @@ -48,10 +49,12 @@ #include "v3dmath.h" #include "v3math.h" #include "llbvhconsts.h" +#include class LLKeyframeDataCache; class LLVFS; class LLDataPacker; +class LLMotionController; #define MIN_REQUIRED_PIXEL_AREA_KEYFRAME (40.f) #define MAX_CHAIN_LENGTH (4) @@ -59,16 +62,138 @@ class LLDataPacker; const S32 KEYFRAME_MOTION_VERSION = 1; const S32 KEYFRAME_MOTION_SUBVERSION = 0; +//----------------------------------------------------------------------------- +// + +template +class AICachedPointer; + +template +void intrusive_ptr_add_ref(AICachedPointer const* p); + +template +void intrusive_ptr_release(AICachedPointer const* p); + +template +class AICachedPointer +{ + public: + typedef std::set > container_type; + + private: + KEY mKey; // The unique key. + LLPointer mData; // The actual data pointer. + container_type* mCache; // Pointer to the underlaying cache. + mutable int mRefCount; // Number of AICachedPointerPtr's pointing to this object. + + public: + // Construct a NULL pointer. This is needed when adding a new entry to a std::set, it is always first default constructed. + AICachedPointer(void) : mCache(NULL) { } + + // Copy constructor. This is needed to replace the std::set inserted instance with its actual value. + AICachedPointer(AICachedPointer const& cptr) : mKey(cptr.mKey), mData(cptr.mData), mCache(cptr.mCache), mRefCount(0) { } + + // Construct a AICachedPointer that points to 'ptr' with key 'key'. + AICachedPointer(KEY const& key, T* ptr, container_type* cache) : mKey(key), mData(ptr), mCache(cache), mRefCount(-1) { } + + // Construct a temporary NULL pointer that can be used in a search for a key. + AICachedPointer(KEY const& key) : mKey(key), mCache(NULL) { } + + // Accessors for key and data. + KEY const& key(void) const { return mKey; } + T const* get(void) const { return mData.get(); } + T* get(void) { return mData.get(); } + + // Order only by key. + friend bool operator<(AICachedPointer const& cp1, AICachedPointer const& cp2) { return cp1.mKey < cp2.mKey; } + + private: + friend void intrusive_ptr_add_ref<>(AICachedPointer const* p); + friend void intrusive_ptr_release<>(AICachedPointer const* p); + + private: + AICachedPointer& operator=(AICachedPointer const&); +}; + +template +void intrusive_ptr_add_ref(AICachedPointer const* p) +{ + llassert(p->mCache); + if (p->mCache) + { + p->mRefCount++; + } +} + +template +void intrusive_ptr_release(AICachedPointer const* p) +{ + llassert(p->mCache); + if (p->mCache) + { + if (--p->mRefCount == 0) + { + p->mCache->erase(p->mKey); + } + } +} + +template +class AICachedPointerPtr +{ + private: + boost::intrusive_ptr const> mPtr; + static int sCnt; + + public: + AICachedPointerPtr(void) { ++sCnt; } + AICachedPointerPtr(AICachedPointerPtr const& cpp) : mPtr(cpp.mPtr) { ++sCnt; } + AICachedPointerPtr(AICachedPointer const* cp) : mPtr(cp) { ++sCnt; } + ~AICachedPointerPtr() { --sCnt; } + + typedef boost::intrusive_ptr const> const AICachedPointerPtr::* const bool_type; + operator bool_type() const { return mPtr ? &AICachedPointerPtr::mPtr : NULL; } + + T const* operator->() const { return mPtr->get(); } + T* operator->() { return const_cast&>(*mPtr).get(); } + T const& operator*() const { return *mPtr->get(); } + T& operator*() { return *const_cast&>(*mPtr).get(); } + + AICachedPointerPtr& operator=(AICachedPointerPtr const& cpp) { mPtr = cpp.mPtr; return *this; } +}; + +template +int AICachedPointerPtr::sCnt; + +// +//----------------------------------------------------------------------------- + //----------------------------------------------------------------------------- // class LLKeyframeMotion //----------------------------------------------------------------------------- + +namespace LLKeyframeMotionLerp +{ + template + inline T lerp(F32 t, const T& before, const T& after) + { + return ::lerp(before, after, t); + } + + template<> + inline LLQuaternion lerp(F32 t, const LLQuaternion& before, const LLQuaternion& after) + { + return nlerp(t, before, after); + } +} + class LLKeyframeMotion : public LLMotion { friend class LLKeyframeDataCache; public: // Constructor - LLKeyframeMotion(const LLUUID &id); + LLKeyframeMotion(const LLUUID &id, LLMotionController* controller); // Destructor virtual ~LLKeyframeMotion(); @@ -85,7 +210,7 @@ class LLKeyframeMotion : // static constructor // all subclasses must implement such a function and register it - static LLMotion *create(const LLUUID& id); + static LLMotion* create(LLUUID const& id, LLMotionController* controller); public: //------------------------------------------------------------------------- @@ -157,8 +282,8 @@ class LLKeyframeMotion : public: U32 getFileSize(); BOOL serialize(LLDataPacker& dp) const; - BOOL deserialize(LLDataPacker& dp); - BOOL isLoaded() { return mJointMotionList != NULL; } + BOOL deserialize(LLDataPacker& dp, const LLUUID& asset_id); + BOOL isLoaded() { return !!mJointMotionList; } // setters for modifying a keyframe animation @@ -278,101 +403,84 @@ class LLKeyframeMotion : enum InterpolationType { IT_STEP, IT_LINEAR, IT_SPLINE }; - //------------------------------------------------------------------------- - // ScaleKey - //------------------------------------------------------------------------- - class ScaleKey - { - public: - ScaleKey() { mTime = 0.0f; } - ScaleKey(F32 time, const LLVector3 &scale) { mTime = time; mScale = scale; } - - F32 mTime; - LLVector3 mScale; - }; - - //------------------------------------------------------------------------- - // RotationKey - //------------------------------------------------------------------------- - class RotationKey - { - public: - RotationKey() { mTime = 0.0f; } - RotationKey(F32 time, const LLQuaternion &rotation) { mTime = time; mRotation = rotation; } - - F32 mTime; - LLQuaternion mRotation; - }; - - //------------------------------------------------------------------------- - // PositionKey - //------------------------------------------------------------------------- - class PositionKey + template + struct Curve { - public: - PositionKey() { mTime = 0.0f; } - PositionKey(F32 time, const LLVector3 &position) { mTime = time; mPosition = position; } - - F32 mTime; - LLVector3 mPosition; - }; - - //------------------------------------------------------------------------- - // ScaleCurve - //------------------------------------------------------------------------- - class ScaleCurve - { - public: - ScaleCurve(); - ~ScaleCurve(); - LLVector3 getValue(F32 time, F32 duration); - LLVector3 interp(F32 u, ScaleKey& before, ScaleKey& after); - - InterpolationType mInterpolationType; - S32 mNumKeys; - typedef std::map key_map_t; + struct Key + { + Key() = default; + Key(F32 time, const T& value) { mTime = time; mValue = value; } + F32 mTime = 0; + T mValue; + }; + + T interp(F32 u, Key& before, Key& after) + { + switch (mInterpolationType) + { + case IT_STEP: + return before.mValue; + default: + case IT_LINEAR: + case IT_SPLINE: + return LLKeyframeMotionLerp::lerp(u, before.mValue, after.mValue); + } + } + + T getValue(F32 time, F32 duration) + { + if (mKeys.empty()) + { + return T(); + } + + T value; + typename key_map_t::iterator right = std::lower_bound(mKeys.begin(), mKeys.end(), time, [](const auto& a, const auto& b) { return a.first < b; }); + if (right == mKeys.end()) + { + // Past last key + --right; + value = right->second.mValue; + } + else if (right == mKeys.begin() || right->first == time) + { + // Before first key or exactly on a key + value = right->second.mValue; + } + else + { + // Between two keys + typename key_map_t::iterator left = right; --left; + F32 index_before = left->first; + F32 index_after = right->first; + Key& pos_before = left->second; + Key& pos_after = right->second; + if (right == mKeys.end()) + { + pos_after = mLoopInKey; + index_after = duration; + } + + F32 u = (time - index_before) / (index_after - index_before); + value = interp(u, pos_before, pos_after); + } + return value; + } + + InterpolationType mInterpolationType = LLKeyframeMotion::IT_LINEAR; + S32 mNumKeys = 0; + typedef std::vector< std::pair > key_map_t; key_map_t mKeys; - ScaleKey mLoopInKey; - ScaleKey mLoopOutKey; + Key mLoopInKey; + Key mLoopOutKey; }; - //------------------------------------------------------------------------- - // RotationCurve - //------------------------------------------------------------------------- - class RotationCurve - { - public: - RotationCurve(); - ~RotationCurve(); - LLQuaternion getValue(F32 time, F32 duration); - LLQuaternion interp(F32 u, RotationKey& before, RotationKey& after); - - InterpolationType mInterpolationType; - S32 mNumKeys; - typedef std::map key_map_t; - key_map_t mKeys; - RotationKey mLoopInKey; - RotationKey mLoopOutKey; - }; - - //------------------------------------------------------------------------- - // PositionCurve - //------------------------------------------------------------------------- - class PositionCurve - { - public: - PositionCurve(); - ~PositionCurve(); - LLVector3 getValue(F32 time, F32 duration); - LLVector3 interp(F32 u, PositionKey& before, PositionKey& after); - - InterpolationType mInterpolationType; - S32 mNumKeys; - typedef std::map key_map_t; - key_map_t mKeys; - PositionKey mLoopInKey; - PositionKey mLoopOutKey; - }; + typedef Curve ScaleCurve; + typedef ScaleCurve::Key ScaleKey; + typedef Curve RotationCurve; + typedef RotationCurve::Key RotationKey; + typedef Curve PositionCurve; + typedef PositionCurve::Key PositionKey; //------------------------------------------------------------------------- // JointMotion @@ -393,7 +501,7 @@ class LLKeyframeMotion : //------------------------------------------------------------------------- // JointMotionList //------------------------------------------------------------------------- - class JointMotionList + class JointMotionList : public LLRefCount { public: std::vector mJointMotionArray; @@ -416,19 +524,22 @@ class LLKeyframeMotion : public: JointMotionList(); ~JointMotionList(); - U32 dumpDiagInfo(); + U32 dumpDiagInfo(bool silent = false) const; JointMotion* getJointMotion(U32 index) const { llassert(index < mJointMotionArray.size()); return mJointMotionArray[index]; } U32 getNumJointMotions() const { return mJointMotionArray.size(); } }; + // Singu: Type of a pointer to the cached pointer (in LLKeyframeDataCache::sKeyframeDataMap) to a JointMotionList object. + typedef AICachedPointerPtr JointMotionListPtr; + protected: static LLVFS* sVFS; //------------------------------------------------------------------------- // Member Data //------------------------------------------------------------------------- - JointMotionList* mJointMotionList; + JointMotionListPtr mJointMotionList; // singu: automatically clean up cache entry when destructed. std::vector > mJointStates; LLJoint* mPelvisp; LLCharacter* mCharacter; @@ -442,21 +553,24 @@ class LLKeyframeMotion : class LLKeyframeDataCache { -public: - // *FIX: implement this as an actual singleton member of LLKeyframeMotion +private: + friend class LLKeyframeMotion; LLKeyframeDataCache(){}; ~LLKeyframeDataCache(); - typedef std::map keyframe_data_map_t; +public: + typedef AICachedPointer::container_type keyframe_data_map_t; // singu: add automatic cache cleanup. static keyframe_data_map_t sKeyframeDataMap; - static void addKeyframeData(const LLUUID& id, LLKeyframeMotion::JointMotionList*); - static LLKeyframeMotion::JointMotionList* getKeyframeData(const LLUUID& id); + // + static LLKeyframeMotion::JointMotionListPtr createKeyframeData(LLUUID const& id); // id may not exist. + static LLKeyframeMotion::JointMotionListPtr getKeyframeData(LLUUID const& id); // id may or may not exists. Returns a NULL pointer when it doesn't exist. + // static void removeKeyframeData(const LLUUID& id); //print out diagnostic info - static void dumpDiagInfo(); + static void dumpDiagInfo(int quiet = 0); // singu: added param 'quiet'. static void clear(); }; diff --git a/indra/llcharacter/llkeyframemotionparam.cpp b/indra/llcharacter/llkeyframemotionparam.cpp deleted file mode 100644 index 4df1ef46b3..0000000000 --- a/indra/llcharacter/llkeyframemotionparam.cpp +++ /dev/null @@ -1,456 +0,0 @@ -/** - * @file llkeyframemotionparam.cpp - * @brief Implementation of LLKeyframeMotion class. - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -//----------------------------------------------------------------------------- -// Header Files -//----------------------------------------------------------------------------- -#include "linden_common.h" - -#include "llkeyframemotionparam.h" -#include "llcharacter.h" -#include "llmath.h" -#include "m3math.h" -#include "lldir.h" -#include "llanimationstates.h" - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -// LLKeyframeMotionParam class -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- - -//----------------------------------------------------------------------------- -// LLKeyframeMotionParam() -// Class Constructor -//----------------------------------------------------------------------------- -LLKeyframeMotionParam::LLKeyframeMotionParam( const LLUUID &id) : LLMotion(id) -{ - mDefaultKeyframeMotion = NULL; - mCharacter = NULL; - - mEaseInDuration = 0.f; - mEaseOutDuration = 0.f; - mDuration = 0.f; - mPriority = LLJoint::LOW_PRIORITY; -} - - -//----------------------------------------------------------------------------- -// ~LLKeyframeMotionParam() -// Class Destructor -//----------------------------------------------------------------------------- -LLKeyframeMotionParam::~LLKeyframeMotionParam() -{ - for (motion_map_t::iterator iter = mParameterizedMotions.begin(); - iter != mParameterizedMotions.end(); ++iter) - { - motion_list_t& motionList = iter->second; - for (motion_list_t::iterator iter2 = motionList.begin(); iter2 != motionList.end(); ++iter2) - { - const ParameterizedMotion& paramMotion = *iter2; - delete paramMotion.mMotion; - } - motionList.clear(); - } - mParameterizedMotions.clear(); -} - -//----------------------------------------------------------------------------- -// LLKeyframeMotionParam::onInitialize(LLCharacter *character) -//----------------------------------------------------------------------------- -LLMotion::LLMotionInitStatus LLKeyframeMotionParam::onInitialize(LLCharacter *character) -{ - mCharacter = character; - - if (!loadMotions()) - { - return STATUS_FAILURE; - } - - for (motion_map_t::iterator iter = mParameterizedMotions.begin(); - iter != mParameterizedMotions.end(); ++iter) - { - motion_list_t& motionList = iter->second; - for (motion_list_t::iterator iter2 = motionList.begin(); iter2 != motionList.end(); ++iter2) - { - const ParameterizedMotion& paramMotion = *iter2; - LLMotion* motion = paramMotion.mMotion; - motion->onInitialize(character); - - if (motion->getDuration() > mEaseInDuration) - { - mEaseInDuration = motion->getEaseInDuration(); - } - - if (motion->getEaseOutDuration() > mEaseOutDuration) - { - mEaseOutDuration = motion->getEaseOutDuration(); - } - - if (motion->getDuration() > mDuration) - { - mDuration = motion->getDuration(); - } - - if (motion->getPriority() > mPriority) - { - mPriority = motion->getPriority(); - } - - LLPose *pose = motion->getPose(); - - mPoseBlender.addMotion(motion); - for (LLJointState *jsp = pose->getFirstJointState(); jsp; jsp = pose->getNextJointState()) - { - LLPose *blendedPose = mPoseBlender.getBlendedPose(); - blendedPose->addJointState(jsp); - } - } - } - - return STATUS_SUCCESS; -} - -//----------------------------------------------------------------------------- -// LLKeyframeMotionParam::onActivate() -//----------------------------------------------------------------------------- -BOOL LLKeyframeMotionParam::onActivate() -{ - for (motion_map_t::iterator iter = mParameterizedMotions.begin(); - iter != mParameterizedMotions.end(); ++iter) - { - motion_list_t& motionList = iter->second; - for (motion_list_t::iterator iter2 = motionList.begin(); iter2 != motionList.end(); ++iter2) - { - const ParameterizedMotion& paramMotion = *iter2; - paramMotion.mMotion->activate(mActivationTimestamp); - } - } - return TRUE; -} - - -//----------------------------------------------------------------------------- -// LLKeyframeMotionParam::onUpdate() -//----------------------------------------------------------------------------- -BOOL LLKeyframeMotionParam::onUpdate(F32 time, U8* joint_mask) -{ - F32 weightFactor = 1.f / (F32)mParameterizedMotions.size(); - - // zero out all pose weights - for (motion_map_t::iterator iter = mParameterizedMotions.begin(); - iter != mParameterizedMotions.end(); ++iter) - { - motion_list_t& motionList = iter->second; - for (motion_list_t::iterator iter2 = motionList.begin(); iter2 != motionList.end(); ++iter2) - { - const ParameterizedMotion& paramMotion = *iter2; -// llinfos << "Weight for pose " << paramMotion.mMotion->getName() << " is " << paramMotion.mMotion->getPose()->getWeight() << llendl; - paramMotion.mMotion->getPose()->setWeight(0.f); - } - } - - - for (motion_map_t::iterator iter = mParameterizedMotions.begin(); - iter != mParameterizedMotions.end(); ++iter) - { - const std::string& paramName = iter->first; - F32* paramValue = (F32 *)mCharacter->getAnimationData(paramName); - if (NULL == paramValue) // unexpected, but... - { - llwarns << "paramValue == NULL" << llendl; - continue; - } - - // DANGER! Do not modify mParameterizedMotions while using these pointers! - const ParameterizedMotion* firstMotion = NULL; - const ParameterizedMotion* secondMotion = NULL; - - motion_list_t& motionList = iter->second; - for (motion_list_t::iterator iter2 = motionList.begin(); iter2 != motionList.end(); ++iter2) - { - const ParameterizedMotion& paramMotion = *iter2; - paramMotion.mMotion->onUpdate(time, joint_mask); - - F32 distToParam = paramMotion.mParam - *paramValue; - - if ( distToParam <= 0.f) - { - // keep track of the motion closest to the parameter value - firstMotion = ¶mMotion; - } - else - { - // we've passed the parameter value - // so store the first motion we find as the second one we want to blend... - if (firstMotion && !secondMotion ) - { - secondMotion = ¶mMotion; - } - //...or, if we've seen no other motion so far, make sure we blend to this only - else if (!firstMotion) - { - firstMotion = ¶mMotion; - secondMotion = ¶mMotion; - } - } - } - - LLPose *firstPose; - LLPose *secondPose; - - if (firstMotion) - firstPose = firstMotion->mMotion->getPose(); - else - firstPose = NULL; - - if (secondMotion) - secondPose = secondMotion->mMotion->getPose(); - else - secondPose = NULL; - - // now modify weight of the subanim (only if we are blending between two motions) - if (firstMotion && secondMotion) - { - if (firstMotion == secondMotion) - { - firstPose->setWeight(weightFactor); - } - else if (firstMotion->mParam == secondMotion->mParam) - { - firstPose->setWeight(0.5f * weightFactor); - secondPose->setWeight(0.5f * weightFactor); - } - else - { - F32 first_weight = 1.f - - ((llclamp(*paramValue - firstMotion->mParam, 0.f, (secondMotion->mParam - firstMotion->mParam))) / - (secondMotion->mParam - firstMotion->mParam)); - first_weight = llclamp(first_weight, 0.f, 1.f); - - F32 second_weight = 1.f - first_weight; - - firstPose->setWeight(first_weight * weightFactor); - secondPose->setWeight(second_weight * weightFactor); - -// llinfos << "Parameter " << *paramName << ": " << *paramValue << llendl; -// llinfos << "Weights " << firstPose->getWeight() << " " << secondPose->getWeight() << llendl; - } - } - else if (firstMotion && !secondMotion) - { - firstPose->setWeight(weightFactor); - } - } - - // blend poses - mPoseBlender.blendAndApply(); - - llinfos << "Param Motion weight " << mPoseBlender.getBlendedPose()->getWeight() << llendl; - - return TRUE; -} - -//----------------------------------------------------------------------------- -// LLKeyframeMotionParam::onDeactivate() -//----------------------------------------------------------------------------- -void LLKeyframeMotionParam::onDeactivate() -{ - for (motion_map_t::iterator iter = mParameterizedMotions.begin(); - iter != mParameterizedMotions.end(); ++iter) - { - motion_list_t& motionList = iter->second; - for (motion_list_t::iterator iter2 = motionList.begin(); iter2 != motionList.end(); ++iter2) - { - const ParameterizedMotion& paramMotion = *iter2; - paramMotion.mMotion->onDeactivate(); - } - } -} - -//----------------------------------------------------------------------------- -// LLKeyframeMotionParam::addKeyframeMotion() -//----------------------------------------------------------------------------- -BOOL LLKeyframeMotionParam::addKeyframeMotion(char *name, const LLUUID &id, char *param, F32 value) -{ - LLMotion *newMotion = mCharacter->createMotion( id ); - - if (!newMotion) - { - return FALSE; - } - - newMotion->setName(name); - - // now add motion to this list - mParameterizedMotions[param].insert(ParameterizedMotion(newMotion, value)); - - return TRUE; -} - - -//----------------------------------------------------------------------------- -// LLKeyframeMotionParam::setDefaultKeyframeMotion() -//----------------------------------------------------------------------------- -void LLKeyframeMotionParam::setDefaultKeyframeMotion(char *name) -{ - for (motion_map_t::iterator iter = mParameterizedMotions.begin(); - iter != mParameterizedMotions.end(); ++iter) - { - motion_list_t& motionList = iter->second; - for (motion_list_t::iterator iter2 = motionList.begin(); iter2 != motionList.end(); ++iter2) - { - const ParameterizedMotion& paramMotion = *iter2; - if (paramMotion.mMotion->getName() == name) - { - mDefaultKeyframeMotion = paramMotion.mMotion; - } - } - } -} - -//----------------------------------------------------------------------------- -// loadMotions() -//----------------------------------------------------------------------------- -BOOL LLKeyframeMotionParam::loadMotions() -{ - //------------------------------------------------------------------------- - // Load named file by concatenating the character prefix with the motion name. - // Load data into a buffer to be parsed. - //------------------------------------------------------------------------- - //std::string path = gDirUtilp->getExpandedFilename(LL_PATH_MOTIONS,mCharacter->getAnimationPrefix()) - // + "_" + getName() + ".llp"; - //RN: deprecated unused reference to "motion" directory - std::string path; - - - //------------------------------------------------------------------------- - // open the file - //------------------------------------------------------------------------- - S32 fileSize = 0; - LLAPRFile infile(path, LL_APR_R, &fileSize); - apr_file_t* fp = infile.getFileHandle() ; - if (!fp || fileSize == 0) - { - llinfos << "ERROR: can't open: " << path << llendl; - return FALSE; - } - - // allocate a text buffer - try - { - std::vector text(fileSize+1); - - //------------------------------------------------------------------------- - // load data from file into buffer - //------------------------------------------------------------------------- - bool error = false; - char *p = &text[0]; - while ( 1 ) - { - if (apr_file_eof(fp) == APR_EOF) - { - break; - } - if (apr_file_gets(p, 1024, fp) != APR_SUCCESS) - { - error = true; - break; - } - while ( *(++p) ) - ; - } - - //------------------------------------------------------------------------- - // close the file - //------------------------------------------------------------------------- - infile.close(); - - //------------------------------------------------------------------------- - // check for error - //------------------------------------------------------------------------- - llassert( p <= (&text[0] + fileSize) ); - - if ( error ) - { - llinfos << "ERROR: error while reading from " << path << llendl; - return FALSE; - } - - llinfos << "Loading parametric keyframe data for: " << getName() << llendl; - - //------------------------------------------------------------------------- - // parse the text and build keyframe data structures - //------------------------------------------------------------------------- - p = &text[0]; - S32 num; - char strA[80]; /* Flawfinder: ignore */ - char strB[80]; /* Flawfinder: ignore */ - F32 floatA = 0.0f; - - - //------------------------------------------------------------------------- - // get priority - //------------------------------------------------------------------------- - BOOL isFirstMotion = TRUE; - num = sscanf(p, "%79s %79s %f", strA, strB, &floatA); /* Flawfinder: ignore */ - - while(1) - { - if (num == 0 || num == EOF) break; - if ((num != 3)) - { - llinfos << "WARNING: can't read parametric motion" << llendl; - return FALSE; - } - - addKeyframeMotion(strA, gAnimLibrary.stringToAnimState(std::string(strA)), strB, floatA); - if (isFirstMotion) - { - isFirstMotion = FALSE; - setDefaultKeyframeMotion(strA); - } - - p = strstr(p, "\n"); - if (!p) - { - break; - } - - p++; - num = sscanf(p, "%79s %79s %f", strA, strB, &floatA); /* Flawfinder: ignore */ - } - - return TRUE; - } - catch(std::bad_alloc) - { - llinfos << "ERROR: Unable to allocate keyframe text buffer." << llendl; - return FALSE; - } -} - -// End diff --git a/indra/llcharacter/llkeyframemotionparam.h b/indra/llcharacter/llkeyframemotionparam.h deleted file mode 100644 index f74aea2769..0000000000 --- a/indra/llcharacter/llkeyframemotionparam.h +++ /dev/null @@ -1,176 +0,0 @@ -/** - * @file llkeyframemotionparam.h - * @brief Implementation of LLKeframeMotionParam class. - * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifndef LL_LLKEYFRAMEMOTIONPARAM_H -#define LL_LLKEYFRAMEMOTIONPARAM_H - -//----------------------------------------------------------------------------- -// Header files -//----------------------------------------------------------------------------- - -#include - -#include "llmotion.h" -#include "lljointstate.h" -#include "v3math.h" -#include "llquaternion.h" -#include "linked_lists.h" -#include "llkeyframemotion.h" - -//----------------------------------------------------------------------------- -// class LLKeyframeMotionParam -//----------------------------------------------------------------------------- -class LLKeyframeMotionParam : - public LLMotion -{ -public: - // Constructor - LLKeyframeMotionParam(const LLUUID &id); - - // Destructor - virtual ~LLKeyframeMotionParam(); - -public: - //------------------------------------------------------------------------- - // functions to support MotionController and MotionRegistry - //------------------------------------------------------------------------- - - // static constructor - // all subclasses must implement such a function and register it - static LLMotion *create(const LLUUID &id) { return new LLKeyframeMotionParam(id); } - -public: - //------------------------------------------------------------------------- - // animation callbacks to be implemented by subclasses - //------------------------------------------------------------------------- - - // motions must specify whether or not they loop - virtual BOOL getLoop() { - return TRUE; - } - - // motions must report their total duration - virtual F32 getDuration() { - return mDuration; - } - - // motions must report their "ease in" duration - virtual F32 getEaseInDuration() { - return mEaseInDuration; - } - - // motions must report their "ease out" duration. - virtual F32 getEaseOutDuration() { - return mEaseOutDuration; - } - - // motions must report their priority - virtual LLJoint::JointPriority getPriority() { - return mPriority; - } - - virtual LLMotionBlendType getBlendType() { return NORMAL_BLEND; } - - // called to determine when a motion should be activated/deactivated based on avatar pixel coverage - virtual F32 getMinPixelArea() { return MIN_REQUIRED_PIXEL_AREA_KEYFRAME; } - - // run-time (post constructor) initialization, - // called after parameters have been set - // must return true to indicate success and be available for activation - virtual LLMotionInitStatus onInitialize(LLCharacter *character); - - // called when a motion is activated - // must return TRUE to indicate success, or else - // it will be deactivated - virtual BOOL onActivate(); - - // called per time step - // must return TRUE while it is active, and - // must return FALSE when the motion is completed. - virtual BOOL onUpdate(F32 time, U8* joint_mask); - - // called when a motion is deactivated - virtual void onDeactivate(); - - virtual LLPose* getPose() { return mPoseBlender.getBlendedPose();} - -protected: - //------------------------------------------------------------------------- - // new functions defined by this subclass - //------------------------------------------------------------------------- - struct ParameterizedMotion - { - ParameterizedMotion(LLMotion* motion, F32 param) : mMotion(motion), mParam(param) {} - LLMotion* mMotion; - F32 mParam; - }; - - // add a motion and associated parameter triplet - BOOL addKeyframeMotion(char *name, const LLUUID &id, char *param, F32 value); - - // set default motion for LOD and retrieving blend constants - void setDefaultKeyframeMotion(char *); - - BOOL loadMotions(); - -protected: - //------------------------------------------------------------------------- - // Member Data - //------------------------------------------------------------------------- - - struct compare_motions - { - bool operator() (const ParameterizedMotion& a, const ParameterizedMotion& b) const - { - if (a.mParam != b.mParam) - return (a.mParam < b.mParam); - else - return a.mMotion < b.mMotion; - } - }; - - typedef std::set < ParameterizedMotion, compare_motions > motion_list_t; - typedef std::map motion_map_t; - motion_map_t mParameterizedMotions; - LLMotion* mDefaultKeyframeMotion; - LLCharacter* mCharacter; - LLPoseBlender mPoseBlender; - - F32 mEaseInDuration; - F32 mEaseOutDuration; - F32 mDuration; - LLJoint::JointPriority mPriority; - - LLUUID mTransactionID; -}; - -#endif // LL_LLKEYFRAMEMOTIONPARAM_H diff --git a/indra/llcharacter/llkeyframestandmotion.cpp b/indra/llcharacter/llkeyframestandmotion.cpp index 1ae0ddeea0..0b0d05f9fa 100644 --- a/indra/llcharacter/llkeyframestandmotion.cpp +++ b/indra/llcharacter/llkeyframestandmotion.cpp @@ -50,7 +50,7 @@ const F32 POSITION_THRESHOLD = 0.1f; // LLKeyframeStandMotion() // Class Constructor //----------------------------------------------------------------------------- -LLKeyframeStandMotion::LLKeyframeStandMotion(const LLUUID &id) : LLKeyframeMotion(id) +LLKeyframeStandMotion::LLKeyframeStandMotion(LLUUID const& id, LLMotionController* controller) : LLKeyframeMotion(id, controller) { mFlipFeet = FALSE; mCharacter = NULL; @@ -125,7 +125,7 @@ LLMotion::LLMotionInitStatus LLKeyframeStandMotion::onInitialize(LLCharacter *ch !mKneeRightState || !mAnkleRightState ) { - llinfos << getName() << ": Can't find necessary joint states" << llendl; + LL_INFOS() << getName() << ": Can't find necessary joint states" << LL_ENDL; return STATUS_FAILURE; } @@ -286,40 +286,38 @@ BOOL LLKeyframeStandMotion::onUpdate(F32 time, U8* joint_mask) //------------------------------------------------------------------------- if ( mTrackAnkles ) { - LLVector4 dirLeft4 = mAnkleLeftJoint.getWorldMatrix().getFwdRow4(); - LLVector4 dirRight4 = mAnkleRightJoint.getWorldMatrix().getFwdRow4(); - LLVector3 dirLeft = vec4to3( dirLeft4 ); - LLVector3 dirRight = vec4to3( dirRight4 ); + const LLVector4a& dirLeft4 = mAnkleLeftJoint.getWorldMatrix().getRow(); + const LLVector4a& dirRight4 = mAnkleRightJoint.getWorldMatrix().getRow(); - LLVector3 up; - LLVector3 dir; - LLVector3 left; + LLVector4a up; + LLVector4a dir; + LLVector4a left; - up = mNormalLeft; - up.normVec(); + up.load3(mNormalLeft.mV); + up.normalize3fast(); if (mFlipFeet) { - up *= -1.0f; + up.negate(); } - dir = dirLeft; - dir.normVec(); - left = up % dir; - left.normVec(); - dir = left % up; - mRotationLeft = LLQuaternion( dir, left, up ); - - up = mNormalRight; - up.normVec(); + dir = dirLeft4; + dir.normalize3fast(); + left.setCross3(up,dir); + left.normalize3fast(); + dir.setCross3(left,up); + mRotationLeft = LLQuaternion( LLVector3(dir.getF32ptr()), LLVector3(left.getF32ptr()), LLVector3(up.getF32ptr())); + + up.load3(mNormalRight.mV); + up.normalize3fast(); if (mFlipFeet) { - up *= -1.0f; + up.negate(); } - dir = dirRight; - dir.normVec(); - left = up % dir; - left.normVec(); - dir = left % up; - mRotationRight = LLQuaternion( dir, left, up ); + dir = dirRight4; + dir.normalize3fast(); + left.setCross3(up,dir); + left.normalize3fast(); + dir.setCross3(left,up); + mRotationRight = LLQuaternion( LLVector3(dir.getF32ptr()), LLVector3(left.getF32ptr()), LLVector3(up.getF32ptr())); } mAnkleLeftJoint.setWorldRotation( mRotationLeft ); mAnkleRightJoint.setWorldRotation( mRotationRight ); @@ -335,9 +333,9 @@ BOOL LLKeyframeStandMotion::onUpdate(F32 time, U8* joint_mask) mKneeRightState->setRotation( mKneeRightJoint.getRotation() ); mAnkleRightState->setRotation( mAnkleRightJoint.getRotation() ); - //llinfos << "Stand drift amount " << (mCharacter->getCharacterPosition() - mLastGoodPosition).magVec() << llendl; + //LL_INFOS() << "Stand drift amount " << (mCharacter->getCharacterPosition() - mLastGoodPosition).magVec() << LL_ENDL; -// llinfos << "DEBUG: " << speed << " : " << mTrackAnkles << llendl; +// LL_INFOS() << "DEBUG: " << speed << " : " << mTrackAnkles << LL_ENDL; return TRUE; } diff --git a/indra/llcharacter/llkeyframestandmotion.h b/indra/llcharacter/llkeyframestandmotion.h index b0500dc8ec..c3a9ddd221 100644 --- a/indra/llcharacter/llkeyframestandmotion.h +++ b/indra/llcharacter/llkeyframestandmotion.h @@ -48,11 +48,21 @@ class LLKeyframeStandMotion : { public: // Constructor - LLKeyframeStandMotion(const LLUUID &id); + LLKeyframeStandMotion(LLUUID const& id, LLMotionController* controller); // Destructor virtual ~LLKeyframeStandMotion(); + void* operator new(size_t size) + { + return ll_aligned_malloc_16(size); + } + + void operator delete(void* ptr) + { + ll_aligned_free_16(ptr); + } + public: //------------------------------------------------------------------------- // functions to support MotionController and MotionRegistry @@ -60,7 +70,7 @@ class LLKeyframeStandMotion : // static constructor // all subclasses must implement such a function and register it - static LLMotion *create(const LLUUID &id) { return new LLKeyframeStandMotion(id); } + static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLKeyframeStandMotion(id, controller); } public: //------------------------------------------------------------------------- diff --git a/indra/llcharacter/llkeyframewalkmotion.cpp b/indra/llcharacter/llkeyframewalkmotion.cpp index 251ff3ed52..3ec5b2cba3 100644 --- a/indra/llcharacter/llkeyframewalkmotion.cpp +++ b/indra/llcharacter/llkeyframewalkmotion.cpp @@ -55,8 +55,8 @@ const F32 SPEED_ADJUST_TIME_CONSTANT = 0.1f; // time constant for speed adjustm // LLKeyframeWalkMotion() // Class Constructor //----------------------------------------------------------------------------- -LLKeyframeWalkMotion::LLKeyframeWalkMotion(const LLUUID &id) -: LLKeyframeMotion(id), +LLKeyframeWalkMotion::LLKeyframeWalkMotion(LLUUID const& id, LLMotionController* controller) +: LLKeyframeMotion(id, controller), mCharacter(NULL), mCyclePhase(0.0f), mRealTimeLast(0.0f), @@ -138,16 +138,20 @@ BOOL LLKeyframeWalkMotion::onUpdate(F32 time, U8* joint_mask) // LLWalkAdjustMotion() // Class Constructor //----------------------------------------------------------------------------- -LLWalkAdjustMotion::LLWalkAdjustMotion(const LLUUID &id) : - LLMotion(id), +LLWalkAdjustMotion::LLWalkAdjustMotion(LLUUID const& id, LLMotionController* controller) : + AIMaskedMotion(id, controller, ANIM_AGENT_WALK_ADJUST), + mCharacter(NULL), mLastTime(0.f), mAnimSpeed(0.f), mAdjustedSpeed(0.f), mRelativeDir(0.f), - mAnkleOffset(0.f) + mAnkleOffset(0.f), + mLeftAnkleJoint(NULL), + mRightAnkleJoint(NULL), + mPelvisJoint(NULL), + mPelvisState(new LLJointState) { mName = "walk_adjust"; - mPelvisState = new LLJointState; } //----------------------------------------------------------------------------- @@ -163,7 +167,7 @@ LLMotion::LLMotionInitStatus LLWalkAdjustMotion::onInitialize(LLCharacter *chara mPelvisState->setJoint( mPelvisJoint ); if ( !mPelvisJoint ) { - llwarns << getName() << ": Can't get pelvis joint." << llendl; + LL_WARNS() << getName() << ": Can't get pelvis joint." << LL_ENDL; return STATUS_FAILURE; } @@ -193,7 +197,7 @@ BOOL LLWalkAdjustMotion::onActivate() F32 rightAnkleOffset = (mRightAnkleJoint->getWorldPosition() - mCharacter->getCharacterPosition()).magVec(); mAnkleOffset = llmax(leftAnkleOffset, rightAnkleOffset); - return TRUE; + return AIMaskedMotion::onActivate(); } //----------------------------------------------------------------------------- @@ -258,7 +262,7 @@ BOOL LLWalkAdjustMotion::onUpdate(F32 time, U8* joint_mask) // but this will cause the animation playback rate calculation below to // kick in too slowly and sometimes start playing the animation in reverse. - //mPelvisOffset -= PELVIS_COMPENSATION_WIEGHT * (foot_slip_vector * world_to_avatar_rot);//lerp(LLVector3::zero, -1.f * (foot_slip_vector * world_to_avatar_rot), LLCriticalDamp::getInterpolant(0.1f)); + //mPelvisOffset -= PELVIS_COMPENSATION_WIEGHT * (foot_slip_vector * world_to_avatar_rot);//lerp(LLVector3::zero, -1.f * (foot_slip_vector * world_to_avatar_rot), LLSmoothInterpolation::getInterpolant(0.1f)); ////F32 drift_comp_max = DRIFT_COMP_MAX_TOTAL * (llclamp(speed, 0.f, DRIFT_COMP_MAX_SPEED) / DRIFT_COMP_MAX_SPEED); //F32 drift_comp_max = DRIFT_COMP_MAX_TOTAL; @@ -280,14 +284,14 @@ BOOL LLWalkAdjustMotion::onUpdate(F32 time, U8* joint_mask) avatar_movement_dir.normalize(); // planted foot speed is avatar velocity - foot slip amount along avatar movement direction - F32 foot_speed = speed - ((foot_slip_vector * avatar_movement_dir) / delta_time); + F32 foot_speed = llmax(0.f, speed - ((foot_slip_vector * avatar_movement_dir) / delta_time)); // multiply animation playback rate so that foot speed matches avatar speed F32 min_speed_multiplier = clamp_rescale(speed, 0.f, 1.f, 0.f, 0.1f); F32 desired_speed_multiplier = llclamp(speed / foot_speed, min_speed_multiplier, ANIM_SPEED_MAX); // blend towards new speed adjustment value - F32 new_speed_adjust = lerp(mAdjustedSpeed, desired_speed_multiplier, LLCriticalDamp::getInterpolant(SPEED_ADJUST_TIME_CONSTANT)); + F32 new_speed_adjust = LLSmoothInterpolation::lerp(mAdjustedSpeed, desired_speed_multiplier, SPEED_ADJUST_TIME_CONSTANT); // limit that rate at which the speed adjustment changes F32 speedDelta = llclamp(new_speed_adjust - mAdjustedSpeed, -SPEED_ADJUST_MAX_SEC * delta_time, SPEED_ADJUST_MAX_SEC * delta_time); @@ -305,8 +309,8 @@ BOOL LLWalkAdjustMotion::onUpdate(F32 time, U8* joint_mask) { // standing/turning // damp out speed adjustment to 0 - mAnimSpeed = lerp(mAnimSpeed, 1.f, LLCriticalDamp::getInterpolant(0.2f)); - //mPelvisOffset = lerp(mPelvisOffset, LLVector3::zero, LLCriticalDamp::getInterpolant(0.2f)); + mAnimSpeed = LLSmoothInterpolation::lerp(mAnimSpeed, 1.f, 0.2f); + //mPelvisOffset = lerp(mPelvisOffset, LLVector3::zero, LLSmoothInterpolation::getInterpolant(0.2f)); } // broadcast walk speed change @@ -325,13 +329,15 @@ BOOL LLWalkAdjustMotion::onUpdate(F32 time, U8* joint_mask) void LLWalkAdjustMotion::onDeactivate() { mCharacter->removeAnimationData("Walk Speed"); + AIMaskedMotion::onDeactivate(); } //----------------------------------------------------------------------------- // LLFlyAdjustMotion::LLFlyAdjustMotion() //----------------------------------------------------------------------------- -LLFlyAdjustMotion::LLFlyAdjustMotion(const LLUUID &id) - : LLMotion(id), +LLFlyAdjustMotion::LLFlyAdjustMotion(LLUUID const& id, LLMotionController* controller) + : AIMaskedMotion(id, controller, ANIM_AGENT_FLY_ADJUST), + mCharacter(NULL), mRoll(0.f) { mName = "fly_adjust"; @@ -350,7 +356,7 @@ LLMotion::LLMotionInitStatus LLFlyAdjustMotion::onInitialize(LLCharacter *charac mPelvisState->setJoint( pelvisJoint ); if ( !pelvisJoint ) { - llwarns << getName() << ": Can't get pelvis joint." << llendl; + LL_WARNS() << getName() << ": Can't get pelvis joint." << LL_ENDL; return STATUS_FAILURE; } @@ -368,7 +374,7 @@ BOOL LLFlyAdjustMotion::onActivate() mPelvisState->setPosition(LLVector3::zero); mPelvisState->setRotation(LLQuaternion::DEFAULT); mRoll = 0.f; - return TRUE; + return AIMaskedMotion::onActivate(); } //----------------------------------------------------------------------------- @@ -383,7 +389,7 @@ BOOL LLFlyAdjustMotion::onUpdate(F32 time, U8* joint_mask) F32 target_roll = llclamp(ang_vel.mV[VZ], -4.f, 4.f) * roll_factor; // roll is critically damped interpolation between current roll and angular velocity-derived target roll - mRoll = lerp(mRoll, target_roll, LLCriticalDamp::getInterpolant(0.1f)); + mRoll = LLSmoothInterpolation::lerp(mRoll, target_roll, U32Milliseconds(100)); LLQuaternion roll(mRoll, LLVector3(0.f, 0.f, 1.f)); mPelvisState->setRotation(roll); diff --git a/indra/llcharacter/llkeyframewalkmotion.h b/indra/llcharacter/llkeyframewalkmotion.h index b507e9423a..653c2b5392 100644 --- a/indra/llcharacter/llkeyframewalkmotion.h +++ b/indra/llcharacter/llkeyframewalkmotion.h @@ -52,7 +52,7 @@ class LLKeyframeWalkMotion : friend class LLWalkAdjustMotion; public: // Constructor - LLKeyframeWalkMotion(const LLUUID &id); + LLKeyframeWalkMotion(LLUUID const& id, LLMotionController* controller); // Destructor virtual ~LLKeyframeWalkMotion(); @@ -64,7 +64,7 @@ class LLKeyframeWalkMotion : // static constructor // all subclasses must implement such a function and register it - static LLMotion *create(const LLUUID &id) { return new LLKeyframeWalkMotion(id); } + static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLKeyframeWalkMotion(id, controller); } public: //------------------------------------------------------------------------- @@ -86,11 +86,11 @@ class LLKeyframeWalkMotion : S32 mDownFoot; }; -class LLWalkAdjustMotion : public LLMotion +class LLWalkAdjustMotion : public AIMaskedMotion { public: // Constructor - LLWalkAdjustMotion(const LLUUID &id); + LLWalkAdjustMotion(LLUUID const& id, LLMotionController* controller); public: //------------------------------------------------------------------------- @@ -99,7 +99,7 @@ class LLWalkAdjustMotion : public LLMotion // static constructor // all subclasses must implement such a function and register it - static LLMotion *create(const LLUUID &id) { return new LLWalkAdjustMotion(id); } + static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLWalkAdjustMotion(id, controller); } public: //------------------------------------------------------------------------- @@ -136,11 +136,11 @@ class LLWalkAdjustMotion : public LLMotion F32 mAnkleOffset; }; -class LLFlyAdjustMotion : public LLMotion +class LLFlyAdjustMotion : public AIMaskedMotion { public: // Constructor - LLFlyAdjustMotion(const LLUUID &id); + LLFlyAdjustMotion(LLUUID const& id, LLMotionController* controller); public: //------------------------------------------------------------------------- @@ -149,7 +149,7 @@ class LLFlyAdjustMotion : public LLMotion // static constructor // all subclasses must implement such a function and register it - static LLMotion *create(const LLUUID &id) { return new LLFlyAdjustMotion(id); } + static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLFlyAdjustMotion(id, controller); } public: //------------------------------------------------------------------------- @@ -157,7 +157,6 @@ class LLFlyAdjustMotion : public LLMotion //------------------------------------------------------------------------- virtual LLMotionInitStatus onInitialize(LLCharacter *character); virtual BOOL onActivate(); - virtual void onDeactivate() {}; virtual BOOL onUpdate(F32 time, U8* joint_mask); virtual LLJoint::JointPriority getPriority(){return LLJoint::HIGHER_PRIORITY;} virtual BOOL getLoop() { return TRUE; } diff --git a/indra/llcharacter/llmotion.cpp b/indra/llcharacter/llmotion.cpp index ce926a38ae..6a70c76b9a 100644 --- a/indra/llcharacter/llmotion.cpp +++ b/indra/llcharacter/llmotion.cpp @@ -37,6 +37,125 @@ #include "llmotion.h" #include "llcriticaldamp.h" +#include "llmotioncontroller.h" + +// +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// AISyncClientMotion class +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +AISyncKey* AISyncClientMotion::createSyncKey(AISyncKey const* from_key) const +{ + // The const cast is needed because getDuration() is non-const while it should have been. + AISyncClientMotion* self = const_cast(this); + // Only synchronize motions with the same duration and loop value. + return new AISyncKeyMotion(from_key, self->getDuration(), self->getLoop()); +} + +void AISyncClientMotion::aisync_loading(void) +{ + // Register the motion for (possible) synchronization: this marks the time at which is should have started. + unregister_client(); // In case it is already registered. Getting here means we are being (re)started now, we need to synchronize with other motions that start now. + register_client(); +} + +void AISyncClientMotion::aisync_loaded(void) +{ + AISyncServer* server = this->server(); + if (!server) + { + // Already expired without being synchronized (no other motion was started at the same time). + return; + } + AISyncKey const& key = server->key(); // The allocation of this is owned by server. + // There is no need to resync if there was not another motion started at the same time and the key already expired. + bool need_resync = !(server->never_synced() && key.expired()); + AISyncKey* new_key = NULL; + if (need_resync) + { + // Create a new key using the old start time. + new_key = createSyncKey(&key); + } + server->remove(this); // This resets mServer and might even delete server. + if (need_resync) + { + // Add the client to another server (based on the new key). This takes ownership of the key allocation. + AISyncServerMap::instance().register_client(this, new_key); + } +} + +F32 LLMotion::getRuntime(void) const +{ + llassert(mActive); + return mController->getAnimTime() - mActivationTimestamp; +} + +F32 LLMotion::getAnimTime(void) const +{ + return mController->getAnimTime(); +} + +F32 LLMotion::syncActivationTime(F32 time) +{ + AISyncServer* server = this->server(); + if (!server) + { + register_client(); + server = this->server(); + } + AISyncServer::client_list_t const& clients = server->getClients(); + if (clients.size() > 1) + { + // Look for the client with the smallest runtime. + AISyncClientMotion* motion_with_smallest_runtime = NULL; + F32 runtime = 1e10; + // Run over all motions in this to be synchronized group. + for (AISyncServer::client_list_t::const_iterator client = clients.begin(); client != clients.end(); ++client) + { + if ((client->mReadyEvents & 2)) // Is this motion active? Motions that aren't loaded yet are not active. + { + // Currently, if event 2 is set then this is an LLMotion. + llassert(dynamic_cast(client->mClientPtr)); + AISyncClientMotion* motion = static_cast(client->mClientPtr); + // Deactivated motions should have been deregistered, certainly not have event 2 set. + llassert(static_cast(motion)->isActive()); + if (motion->getRuntime() < runtime) + { + // This is a bit fuzzy since theoretically the runtime of all active motions in the list should be the same. + // Just use the smallest value to get rid of some randomness. We might even synchronizing with ourselves + // in which case 'time' would be set to a value such that mActivationTimestamp won't change. + // In practise however, this list will contain only two clients: this, being inactive, and our partner. + runtime = motion->getRuntime(); + motion_with_smallest_runtime = motion; + } + } + } + //----------------------------------------------------------------------------------------- + // Here is where the actual synchronization takes place. + // Current we only synchronize looped motions. + if (getLoop()) + { + if (motion_with_smallest_runtime) + { + // Pretend the motion was started in the past at the same time as the other motion(s). + time = getAnimTime() - runtime; + } + } + //----------------------------------------------------------------------------------------- + } + + return time; +} + +void AISyncClientMotion::deregistered(void) +{ +#ifdef SHOW_ASSERT + mReadyEvents = 0; +#endif +} +// //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- @@ -48,10 +167,11 @@ // LLMotion() // Class Constructor //----------------------------------------------------------------------------- -LLMotion::LLMotion( const LLUUID &id ) : +LLMotion::LLMotion(LLUUID const& id, LLMotionController* controller) : mStopped(TRUE), mActive(FALSE), mID(id), + mController(controller), mActivationTimestamp(0.f), mStopTimestamp(0.f), mSendStopTimestamp(F32_MAX), @@ -60,8 +180,8 @@ LLMotion::LLMotion( const LLUUID &id ) : mDeactivateCallback(NULL), mDeactivateCallbackUserData(NULL) { - for (int i=0; i<3; ++i) - memset(&mJointSignature[i][0], 0, sizeof(U8) * LL_CHARACTER_MAX_JOINTS); + for (S32 i=0; i<3; ++i) + memset(&mJointSignature[i][0], 0, sizeof(U8) * LL_CHARACTER_MAX_ANIMATED_JOINTS); } //----------------------------------------------------------------------------- @@ -79,7 +199,7 @@ void LLMotion::fadeOut() { if (mFadeWeight > 0.01f) { - mFadeWeight = lerp(mFadeWeight, 0.f, LLCriticalDamp::getInterpolant(0.15f)); + mFadeWeight = lerp(mFadeWeight, 0.f, LLSmoothInterpolation::getInterpolant(0.15f)); } else { @@ -94,7 +214,7 @@ void LLMotion::fadeIn() { if (mFadeWeight < 0.99f) { - mFadeWeight = lerp(mFadeWeight, 1.f, LLCriticalDamp::getInterpolant(0.15f)); + mFadeWeight = lerp(mFadeWeight, 1.f, LLSmoothInterpolation::getInterpolant(0.15f)); } else { @@ -117,9 +237,15 @@ void LLMotion::addJointState(const LLPointer& jointState) U32 usage = jointState->getUsage(); // for now, usage is everything - mJointSignature[0][jointState->getJoint()->getJointNum()] = (usage & LLJointState::POS) ? (0xff >> (7 - priority)) : 0; - mJointSignature[1][jointState->getJoint()->getJointNum()] = (usage & LLJointState::ROT) ? (0xff >> (7 - priority)) : 0; - mJointSignature[2][jointState->getJoint()->getJointNum()] = (usage & LLJointState::SCALE) ? (0xff >> (7 - priority)) : 0; + S32 joint_num = jointState->getJoint()->getJointNum(); + if ((joint_num >= (S32)LL_CHARACTER_MAX_ANIMATED_JOINTS) || (joint_num < 0)) + { + LL_WARNS() << "joint_num " << joint_num << " is outside of legal range [0-" << LL_CHARACTER_MAX_ANIMATED_JOINTS << ") for joint " << jointState->getJoint()->getName() << LL_ENDL; + return; + } + mJointSignature[0][joint_num] = (usage & LLJointState::POS) ? (0xff >> (7 - priority)) : 0; + mJointSignature[1][joint_num] = (usage & LLJointState::ROT) ? (0xff >> (7 - priority)) : 0; + mJointSignature[2][joint_num] = (usage & LLJointState::SCALE) ? (0xff >> (7 - priority)) : 0; } void LLMotion::setDeactivateCallback( void (*cb)(void *), void* userdata ) @@ -147,6 +273,19 @@ void LLMotion::activate(F32 time) { mActivationTimestamp = time; mStopped = FALSE; + // + if (mController && !mController->syncing_disabled()) // Avoid being registered when syncing is disabled for this motion. + { + if (mActive) + { + // If the motion is already active then we are being restarted. + // Unregister it first (if it is registered) so that the call to ready will cause it to be registered + // and be synchronized with other motions that are started at this moment. + unregister_client(); + } + ready(6, 2 | (mController->isHidden() ? 0 : 4)); // Signal that mActivationTimestamp is set/valid (2), and that this server has a visible motion (4) (or not). + } + // mActive = TRUE; onActivate(); } @@ -159,6 +298,14 @@ void LLMotion::deactivate() mActive = FALSE; mPose.setWeight(0.f); + // + if (server()) // Only when this motion is already registered. + { + ready(6, 0); // Signal that mActivationTimestamp is no longer valid. + unregister_client(); // No longer running, so no longer a part of this sync group. + } + // + if (mDeactivateCallback) { (*mDeactivateCallback)(mDeactivateCallbackUserData); @@ -174,4 +321,19 @@ BOOL LLMotion::canDeprecate() return TRUE; } +//----------------------------------------------------------------------------- +// AIMaskedMotion +//----------------------------------------------------------------------------- + +BOOL AIMaskedMotion::onActivate() +{ + mController->activated(mMaskBit); + return TRUE; +} + +void AIMaskedMotion::onDeactivate() +{ + mController->deactivated(mMaskBit); +} + // End diff --git a/indra/llcharacter/llmotion.h b/indra/llcharacter/llmotion.h index d6628fd99e..6448310b2c 100644 --- a/indra/llcharacter/llmotion.h +++ b/indra/llcharacter/llmotion.h @@ -38,16 +38,85 @@ //----------------------------------------------------------------------------- #include +#include "aisyncclient.h" #include "llerror.h" #include "llpose.h" #include "lluuid.h" class LLCharacter; +class LLMotionController; + +//----------------------------------------------------------------------------- +// class AISync* stuff +//----------------------------------------------------------------------------- + +class AISyncKeyMotion : public AISyncKey +{ + private: + F32 mDuration; + bool mLoop; + + public: + AISyncKeyMotion(AISyncKey const* from_key, F32 duration, bool loop) : AISyncKey(from_key), mDuration(duration), mLoop(loop) { } + + // Virtual functions of AISyncKey. + public: + /*virtual*/ synckeytype_t getkeytype(void) const + { + // Return a unique identifier for this class, where the low 8 bits represent the syncgroup. + return synckeytype_motion; + } + + /*virtual*/ bool equals(AISyncKey const& key) const + { + switch (key.getkeytype()) + { + case synckeytype_motion: + { + // The other key is of the same type. + AISyncKeyMotion const& motion_key = static_cast(key); + return mLoop == motion_key.mLoop && is_approx_equal(mDuration, motion_key.mDuration); + } + default: + // The keys must be in the same syncgroup. + break; + } + return false; + } +}; + +class AISyncClientMotion : public AISyncClient +{ + protected: + // Make sure that clients that are destroyed are first unregistered. + // This is needed, for example, when loading fails or when excess motions are being purged. + /*virtual*/ ~AISyncClientMotion() { unregister_client(); } + + // AISyncClient events. + /*virtual*/ AISyncKey* createSyncKey(AISyncKey const* from_key = NULL) const; + /*virtual*/ void event1_ready(void) { } + /*virtual*/ void event1_not_ready(void) { } + /*virtual*/ void deregistered(void); + + protected: + // This is called when the server sent us a message that it wants us to play this animation, but we can't because it isn't fully downloaded yet. + void aisync_loading(void); + // This is called when that motion is successfully loaded and it has to be re-registered because now the duration etc is known. + void aisync_loaded(void); + + public: + // Virtual functions of AISyncClientMotion. + // These are defined by classes derived from LLMotion (which is derived from this class). + virtual BOOL getLoop() = 0; + virtual F32 getDuration() = 0; + virtual F32 getAnimTime(void) const = 0; + virtual F32 getRuntime(void) const = 0; +}; //----------------------------------------------------------------------------- // class LLMotion //----------------------------------------------------------------------------- -class LLMotion +class LLMotion : public AISyncClientMotion { friend class LLMotionController; @@ -66,7 +135,7 @@ class LLMotion }; // Constructor - LLMotion(const LLUUID &id); + LLMotion(LLUUID const& id, LLMotionController* controller); // Destructor virtual ~LLMotion(); @@ -114,7 +183,22 @@ class LLMotion BOOL isActive() { return mActive; } public: void activate(F32 time); - + + // + // Returns the time that this motion has been running. + virtual F32 getRuntime(void) const; + + // Return the current time (in seconds since creation of the controller). + virtual F32 getAnimTime(void) const; + + // This is called when a motion is to be activated, but might need synchronization. + // It adjusts the start time to match that of other motions in the same synchronization group that were already started. + F32 syncActivationTime(F32 time); + + // Accessor. + LLMotionController* getController(void) const { return mController; } + // + public: //------------------------------------------------------------------------- // animation callbacks to be implemented by subclasses @@ -181,13 +265,16 @@ class LLMotion //------------------------------------------------------------------------- std::string mName; // instance name assigned by motion controller LLUUID mID; + // + LLMotionController* mController; + // F32 mActivationTimestamp; // time when motion was activated F32 mStopTimestamp; // time when motion was told to stop F32 mSendStopTimestamp; // time when simulator should be told to stop this motion F32 mResidualWeight; // blend weight at beginning of stop motion phase F32 mFadeWeight; // for fading in and out based on LOD - U8 mJointSignature[3][LL_CHARACTER_MAX_JOINTS]; // signature of which joints are animated at what priority + U8 mJointSignature[3][LL_CHARACTER_MAX_ANIMATED_JOINTS]; // signature of which joints are animated at what priority void (*mDeactivateCallback)(void* data); void* mDeactivateCallbackUserData; }; @@ -199,9 +286,9 @@ class LLMotion class LLTestMotion : public LLMotion { public: - LLTestMotion(const LLUUID &id) : LLMotion(id){} + LLTestMotion(LLUUID const& id, LLMotionController* controller) : LLMotion(id, controller){} ~LLTestMotion() {} - static LLMotion *create(const LLUUID& id) { return new LLTestMotion(id); } + static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLTestMotion(id, controller); } BOOL getLoop() { return FALSE; } F32 getDuration() { return 0.0f; } F32 getEaseInDuration() { return 0.0f; } @@ -210,10 +297,10 @@ class LLTestMotion : public LLMotion LLMotionBlendType getBlendType() { return NORMAL_BLEND; } F32 getMinPixelArea() { return 0.f; } - LLMotionInitStatus onInitialize(LLCharacter*) { llinfos << "LLTestMotion::onInitialize()" << llendl; return STATUS_SUCCESS; } - BOOL onActivate() { llinfos << "LLTestMotion::onActivate()" << llendl; return TRUE; } - BOOL onUpdate(F32 time, U8* joint_mask) { llinfos << "LLTestMotion::onUpdate(" << time << ")" << llendl; return TRUE; } - void onDeactivate() { llinfos << "LLTestMotion::onDeactivate()" << llendl; } + LLMotionInitStatus onInitialize(LLCharacter*) { LL_INFOS() << "LLTestMotion::onInitialize()" << LL_ENDL; return STATUS_SUCCESS; } + BOOL onActivate() { LL_INFOS() << "LLTestMotion::onActivate()" << LL_ENDL; return TRUE; } + BOOL onUpdate(F32 time, U8* joint_mask) { LL_INFOS() << "LLTestMotion::onUpdate(" << time << ")" << LL_ENDL; return TRUE; } + void onDeactivate() { LL_INFOS() << "LLTestMotion::onDeactivate()" << LL_ENDL; } }; @@ -223,9 +310,9 @@ class LLTestMotion : public LLMotion class LLNullMotion : public LLMotion { public: - LLNullMotion(const LLUUID &id) : LLMotion(id) {} + LLNullMotion(LLUUID const& id, LLMotionController* controller) : LLMotion(id, controller) {} ~LLNullMotion() {} - static LLMotion *create(const LLUUID &id) { return new LLNullMotion(id); } + static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLNullMotion(id, controller); } // motions must specify whether or not they loop /*virtual*/ BOOL getLoop() { return TRUE; } @@ -266,5 +353,41 @@ class LLNullMotion : public LLMotion // called when a motion is deactivated /*virtual*/ void onDeactivate() {} }; + + +//----------------------------------------------------------------------------- +// AIMaskedMotion +//----------------------------------------------------------------------------- + +// These motions have a bit assigned in LLMotionController::mActiveMask +// that is set and uset upon activation/deactivation. + +// This must be in the same order as ANIM_AGENT_BODY_NOISE_ID through ANIM_AGENT_WALK_ADJUST_ID in llvoavatar.cpp. +U32 const ANIM_AGENT_BODY_NOISE = 0x001; +U32 const ANIM_AGENT_BREATHE_ROT = 0x002; +U32 const ANIM_AGENT_PHYSICS_MOTION = 0x004; +U32 const ANIM_AGENT_EDITING = 0x008; +U32 const ANIM_AGENT_EYE = 0x010; +U32 const ANIM_AGENT_FLY_ADJUST = 0x020; +U32 const ANIM_AGENT_HAND_MOTION = 0x040; +U32 const ANIM_AGENT_HEAD_ROT = 0x080; +U32 const ANIM_AGENT_PELVIS_FIX = 0x100; +U32 const ANIM_AGENT_TARGET = 0x200; +U32 const ANIM_AGENT_WALK_ADJUST = 0x400; + +class AIMaskedMotion : public LLMotion +{ +private: + U32 mMaskBit; + +public: + AIMaskedMotion(LLUUID const& id, LLMotionController* controller, U32 mask_bit) : LLMotion(id, controller), mMaskBit(mask_bit) { } + + /*virtual*/ BOOL onActivate(); + /*virtual*/ void onDeactivate(); + + U32 getMaskBit(void) const { return mMaskBit; } +}; + #endif // LL_LLMOTION_H diff --git a/indra/llcharacter/llmotioncontroller.cpp b/indra/llcharacter/llmotioncontroller.cpp index 35dcc10570..3f5b65f527 100644 --- a/indra/llcharacter/llmotioncontroller.cpp +++ b/indra/llcharacter/llmotioncontroller.cpp @@ -42,7 +42,7 @@ #include "llanimationstates.h" #include "llstl.h" -const S32 NUM_JOINT_SIGNATURE_STRIDES = LL_CHARACTER_MAX_JOINTS / 4; +const S32 NUM_JOINT_SIGNATURE_STRIDES = LL_CHARACTER_MAX_ANIMATED_JOINTS / 4; const U32 MAX_MOTION_INSTANCES = 32; //----------------------------------------------------------------------------- @@ -82,8 +82,8 @@ LLMotionRegistry::~LLMotionRegistry() //----------------------------------------------------------------------------- BOOL LLMotionRegistry::registerMotion( const LLUUID& id, LLMotionConstructor constructor ) { - // llinfos << "Registering motion: " << name << llendl; - return mMotionTable.insert(std::make_pair(id,constructor)).second; + // LL_INFOS() << "Registering motion: " << name << LL_ENDL; + return mMotionTable.emplace(id, constructor).second; } //----------------------------------------------------------------------------- @@ -97,7 +97,7 @@ void LLMotionRegistry::markBad( const LLUUID& id ) //----------------------------------------------------------------------------- // createMotion() //----------------------------------------------------------------------------- -LLMotion *LLMotionRegistry::createMotion( const LLUUID &id ) +LLMotion* LLMotionRegistry::createMotion(LLUUID const& id, LLMotionController* controller) { LLMotionConstructor constructor = get_if_there(mMotionTable, id, LLMotionConstructor(NULL)); LLMotion* motion = NULL; @@ -105,11 +105,11 @@ LLMotion *LLMotionRegistry::createMotion( const LLUUID &id ) if ( constructor == NULL ) { // *FIX: need to replace with a better default scheme. RN - motion = LLKeyframeMotion::create(id); + motion = LLKeyframeMotion::create(id, controller); } else { - motion = constructor(id); + motion = constructor(id, controller); } return motion; @@ -129,11 +129,15 @@ LLMotionController::LLMotionController() : mTimeFactor(sCurrentTimeFactor), mCharacter(NULL), mAnimTime(0.f), + mActiveMask(0), + mDisableSyncing(0), + mHidden(false), + mHaveVisibleSyncedMotions(false), mPrevTimerElapsed(0.f), mLastTime(0.0f), mHasRunOnce(FALSE), mPaused(FALSE), - mPauseTime(0.f), + mPausedFrame(0), mTimeStep(0.f), mTimeStepCount(0), mLastInterp(0.f), @@ -168,7 +172,15 @@ void LLMotionController::deleteAllMotions() mLoadingMotions.clear(); mLoadedMotions.clear(); mActiveMotions.clear(); - + // + mActiveMask = 0; + for_each(mDeprecatedMotions.begin(), mDeprecatedMotions.end(), DeletePointer()); + mDeprecatedMotions.clear(); + for (motion_map_t::iterator iter = mAllMotions.begin(); iter != mAllMotions.end(); ++iter) + { + iter->second->unregister_client(); + } + // for_each(mAllMotions.begin(), mAllMotions.end(), DeletePairedPointer()); mAllMotions.clear(); } @@ -178,26 +190,19 @@ void LLMotionController::deleteAllMotions() //----------------------------------------------------------------------------- void LLMotionController::purgeExcessMotions() { - if (mLoadedMotions.size() > MAX_MOTION_INSTANCES) + // + // The old code attempted to remove non-active motions from mDeprecatedMotions, + // but that is nonsense: there are no motions in mDeprecatedMotions that are not active. + if (mLoadedMotions.size() <= MAX_MOTION_INSTANCES) { - // clean up deprecated motions - for (motion_set_t::iterator deprecated_motion_it = mDeprecatedMotions.begin(); - deprecated_motion_it != mDeprecatedMotions.end(); ) - { - motion_set_t::iterator cur_iter = deprecated_motion_it++; - LLMotion* cur_motionp = *cur_iter; - if (!isMotionActive(cur_motionp)) - { - // Motion is deprecated so we know it's not cannonical, - // we can safely remove the instance - removeMotionInstance(cur_motionp); // modifies mDeprecatedMotions - mDeprecatedMotions.erase(cur_iter); - } - } + // Speed up, no need to create motions_to_kill. + return; } + // + + uuid_set_t motions_to_kill; - std::set motions_to_kill; - if (mLoadedMotions.size() > MAX_MOTION_INSTANCES) + if (1) // Singu: leave indentation alone... { // too many motions active this frame, kill all blenders mPoseBlender.clearBlenders(); @@ -215,7 +220,7 @@ void LLMotionController::purgeExcessMotions() } // clean up all inactive, loaded motions - for (std::set::iterator motion_it = motions_to_kill.begin(); + for (auto motion_it = motions_to_kill.begin(); motion_it != motions_to_kill.end(); ++motion_it) { @@ -231,7 +236,7 @@ void LLMotionController::purgeExcessMotions() if (mLoadedMotions.size() > 2*MAX_MOTION_INSTANCES) { - LL_WARNS_ONCE("Animation") << "> " << 2*MAX_MOTION_INSTANCES << " Loaded Motions" << llendl; + LL_WARNS_ONCE("Animation") << "> " << 2*MAX_MOTION_INSTANCES << " Loaded Motions" << LL_ENDL; } } @@ -308,24 +313,44 @@ BOOL LLMotionController::registerMotion( const LLUUID& id, LLMotionConstructor c void LLMotionController::removeMotion( const LLUUID& id) { LLMotion* motionp = findMotion(id); - mAllMotions.erase(id); - removeMotionInstance(motionp); + // + // If a motion is erased from mAllMotions, it must be deleted. + if (motionp) + { + mAllMotions.erase(id); + removeMotionInstance(motionp); + delete motionp; + } + // } // removes instance of a motion from all runtime structures, but does // not erase entry by ID, as this could be a duplicate instance -// use removeMotion(id) to remove all references to a given motion by id. +// use removeMotion(id) to remove a reference to a given motion by id +// (that will not remove (active) deprecated motions). void LLMotionController::removeMotionInstance(LLMotion* motionp) { if (motionp) { llassert(findMotion(motionp->getID()) != motionp); - if (motionp->isActive()) - motionp->deactivate(); mLoadingMotions.erase(motionp); mLoadedMotions.erase(motionp); mActiveMotions.remove(motionp); - delete motionp; + // + // Deactivation moved here. Only delete motionp when it is being removed from mDeprecatedMotions. + if (motionp->isActive()) + { + motionp->deactivate(); + // If a motion is deactivated, it must be removed from mDeprecatedMotions if there. + motion_set_t::iterator found_it = mDeprecatedMotions.find(motionp); + if (found_it != mDeprecatedMotions.end()) + { + mDeprecatedMotions.erase(found_it); + // If a motion is erased from mDeprecatedMotions, it must be deleted. + delete motionp; + } + } + // } } @@ -341,7 +366,7 @@ LLMotion* LLMotionController::createMotion( const LLUUID &id ) if (!motion) { // look up constructor and create it - motion = sRegistry.createMotion(id); + motion = sRegistry.createMotion(id, this); if (!motion) { return NULL; @@ -359,7 +384,7 @@ LLMotion* LLMotionController::createMotion( const LLUUID &id ) switch(stat) { case LLMotion::STATUS_FAILURE: - llinfos << "Motion " << id << " init failed." << llendl; + LL_INFOS() << "Motion " << id << " init failed." << LL_ENDL; sRegistry.markBad(id); delete motion; return NULL; @@ -371,7 +396,7 @@ LLMotion* LLMotionController::createMotion( const LLUUID &id ) mLoadedMotions.insert(motion); break; default: - llerrs << "Invalid initialization status" << llendl; + LL_ERRS() << "Invalid initialization status" << LL_ENDL; break; } @@ -393,6 +418,7 @@ BOOL LLMotionController::startMotion(const LLUUID &id, F32 start_offset) if (motion && !mPaused && motion->canDeprecate() + && motion->isActive() // singu: do not deprecate motions that are not active. && motion->getFadeWeight() > 0.01f // not LOD-ed out && (motion->isBlending() || motion->getStopTime() != 0.f)) { @@ -417,8 +443,20 @@ BOOL LLMotionController::startMotion(const LLUUID &id, F32 start_offset) return TRUE; } -// llinfos << "Starting motion " << name << llendl; - return activateMotionInstance(motion, mAnimTime - start_offset); +// LL_INFOS() << "Starting motion " << name << LL_ENDL; + // + F32 start_time = mAnimTime - start_offset; + if (!mDisableSyncing) + { + start_time = motion->syncActivationTime(start_time); + } + ++mDisableSyncing; + // + BOOL res = activateMotionInstance(motion, start_time); + // + --mDisableSyncing; + // + return res; } @@ -429,7 +467,7 @@ BOOL LLMotionController::stopMotionLocally(const LLUUID &id, BOOL stop_immediate { // if already inactive, return false LLMotion *motion = findMotion(id); - return stopMotionInstance(motion, stop_immediate); + return stopMotionInstance(motion, stop_immediate||mPaused); } BOOL LLMotionController::stopMotionInstance(LLMotion* motion, BOOL stop_immediate) @@ -479,8 +517,8 @@ void LLMotionController::updateAdditiveMotions() //----------------------------------------------------------------------------- void LLMotionController::resetJointSignatures() { - memset(&mJointSignature[0][0], 0, sizeof(U8) * LL_CHARACTER_MAX_JOINTS); - memset(&mJointSignature[1][0], 0, sizeof(U8) * LL_CHARACTER_MAX_JOINTS); + memset(&mJointSignature[0][0], 0, sizeof(U8) * LL_CHARACTER_MAX_ANIMATED_JOINTS); + memset(&mJointSignature[1][0], 0, sizeof(U8) * LL_CHARACTER_MAX_ANIMATED_JOINTS); } //----------------------------------------------------------------------------- @@ -539,14 +577,12 @@ void LLMotionController::updateIdleActiveMotions() //----------------------------------------------------------------------------- // updateMotionsByType() //----------------------------------------------------------------------------- -static LLFastTimer::DeclareTimer FTM_MOTION_ON_UPDATE("Motion onUpdate"); +static LLTrace::BlockTimerStatHandle FTM_MOTION_ON_UPDATE("Motion onUpdate"); void LLMotionController::updateMotionsByType(LLMotion::LLMotionBlendType anim_type) { BOOL update_result = TRUE; - U8 last_joint_signature[LL_CHARACTER_MAX_JOINTS]; - - memset(&last_joint_signature, 0, sizeof(U8) * LL_CHARACTER_MAX_JOINTS); + U8 last_joint_signature[LL_CHARACTER_MAX_ANIMATED_JOINTS] = {0}; // iterate through active motions in chronological order for (motion_list_t::iterator iter = mActiveMotions.begin(); @@ -699,7 +735,7 @@ void LLMotionController::updateMotionsByType(LLMotion::LLMotionBlendType anim_ty // perform motion update { - LLFastTimer t(FTM_MOTION_ON_UPDATE); + LL_RECORD_BLOCK_TIME(FTM_MOTION_ON_UPDATE); update_result = motionp->onUpdate(mAnimTime - motionp->mActivationTimestamp, last_joint_signature); } } @@ -774,20 +810,35 @@ void LLMotionController::updateLoadingMotions() // this motion should be playing if (!motionp->isStopped()) { - activateMotionInstance(motionp, mAnimTime); + // + F32 start_time = mAnimTime; + if (!mDisableSyncing) + { + motionp->aisync_loaded(); + start_time = motionp->syncActivationTime(start_time); + } + ++mDisableSyncing; + // + activateMotionInstance(motionp, start_time); + // + --mDisableSyncing; + // } } else if (status == LLMotion::STATUS_FAILURE) { - llinfos << "Motion " << motionp->getID() << " init failed." << llendl; + LL_INFOS() << "Motion " << motionp->getID() << " init failed." << LL_ENDL; sRegistry.markBad(motionp->getID()); mLoadingMotions.erase(curiter); - motion_set_t::iterator found_it = mDeprecatedMotions.find(motionp); - if (found_it != mDeprecatedMotions.end()) - { - mDeprecatedMotions.erase(found_it); - } + // Singu note: a motion in mLoadingMotions will not be in mActiveMotions + // and therefore not be in mDeprecatedMotions. So, we don't have to + // check for it's existence there. + llassert(mDeprecatedMotions.find(motionp) == mDeprecatedMotions.end()); mAllMotions.erase(motionp->getID()); + // + // Make sure we're not registered anymore. + motionp->unregister_client(); + // delete motionp; } } @@ -821,8 +872,15 @@ void LLMotionController::updateMotions(bool force_update) { F32 time_interval = fmodf(update_time, mTimeStep); - // always animate *ahead* of actual time - S32 quantum_count = llmax(0, llfloor((update_time - time_interval) / mTimeStep)) + 1; + // + // This old code is nonsense. + //S32 quantum_count = llmax(0, ll_round((update_time - time_interval) / mTimeStep)) + 1; + // (update_time - time_interval) / mTimeStep is an integer! We need ll_round to get rid of floating point errors, not llfloor. + // Moreover, just rounding off to the nearest integer with ll_round(update_time / mTimeStep) makes a lot more sense: + // it is the best we can do to get as close to what we should draw as possible. + // However, mAnimTime may only be incremented; therefore make sure of that with the llmax. + S32 quantum_count = llmax(ll_pos_round(update_time / mTimeStep), llceil(mAnimTime / mTimeStep)); + // if (quantum_count == mTimeStepCount) { // we're still in same time quantum as before, so just interpolate and exit @@ -848,7 +906,8 @@ void LLMotionController::updateMotions(bool force_update) } else { - mAnimTime = update_time; + // Singu note: mAnimTime may never be set back in time. + mAnimTime = llmax(mAnimTime, update_time); } } @@ -880,7 +939,7 @@ void LLMotionController::updateMotions(bool force_update) } mHasRunOnce = TRUE; -// llinfos << "Motion controller time " << motionTimer.getElapsedTimeF32() << llendl; +// LL_INFOS() << "Motion controller time " << motionTimer.getElapsedTimeF32() << LL_ENDL; } //----------------------------------------------------------------------------- @@ -915,6 +974,12 @@ BOOL LLMotionController::activateMotionInstance(LLMotion *motion, F32 time) if (mLoadingMotions.find(motion) != mLoadingMotions.end()) { + // + if (!syncing_disabled()) + { + motion->aisync_loading(); + } + // // we want to start this motion, but we can't yet, so flag it as started motion->setStopped(FALSE); // report pending animations as activated @@ -970,18 +1035,16 @@ BOOL LLMotionController::activateMotionInstance(LLMotion *motion, F32 time) //----------------------------------------------------------------------------- BOOL LLMotionController::deactivateMotionInstance(LLMotion *motion) { - motion->deactivate(); - motion_set_t::iterator found_it = mDeprecatedMotions.find(motion); if (found_it != mDeprecatedMotions.end()) { // deprecated motions need to be completely excised - removeMotionInstance(motion); - mDeprecatedMotions.erase(found_it); + removeMotionInstance(motion); // singu note: this deactivates motion and removes it from mDeprecatedMotions. } else { // for motions that we are keeping, simply remove from active queue + motion->deactivate(); // singu note: moved here from the top of the function. mActiveMotions.remove(motion); } @@ -1036,7 +1099,7 @@ LLMotion* LLMotionController::findMotion(const LLUUID& id) const //----------------------------------------------------------------------------- void LLMotionController::dumpMotions() { - llinfos << "=====================================" << llendl; + LL_INFOS() << "=====================================" << LL_ENDL; for (motion_map_t::iterator iter = mAllMotions.begin(); iter != mAllMotions.end(); iter++) { @@ -1049,11 +1112,26 @@ void LLMotionController::dumpMotions() state_string += std::string("L"); if (std::find(mActiveMotions.begin(), mActiveMotions.end(), motion)!=mActiveMotions.end()) state_string += std::string("A"); - if (mDeprecatedMotions.find(motion) != mDeprecatedMotions.end()) - state_string += std::string("D"); - llinfos << gAnimLibrary.animationName(id) << " " << state_string << llendl; - + llassert(mDeprecatedMotions.find(motion) == mDeprecatedMotions.end()); // singu: it's impossible that a motion is in mAllMotions and mDeprecatedMotions at the same time. + LL_INFOS() << gAnimLibrary.animationName(id) << " " << state_string << LL_ENDL; + } + // + // Also dump the deprecated motions. + for (motion_set_t::iterator iter = mDeprecatedMotions.begin(); + iter != mDeprecatedMotions.end(); ++iter) + { + std::string state_string; + LLMotion* motion = *iter; + LLUUID id = motion->getID(); + llassert(mLoadingMotions.find(motion) == mLoadingMotions.end()); + if (mLoadedMotions.find(motion) != mLoadedMotions.end()) + state_string += std::string("L"); + if (std::find(mActiveMotions.begin(), mActiveMotions.end(), motion)!=mActiveMotions.end()) + state_string += std::string("A"); + state_string += "D"; + LL_INFOS() << gAnimLibrary.animationName(id) << " " << state_string << LL_ENDL; } + // } //----------------------------------------------------------------------------- @@ -1061,11 +1139,11 @@ void LLMotionController::dumpMotions() //----------------------------------------------------------------------------- void LLMotionController::deactivateAllMotions() { - for (motion_map_t::iterator iter = mAllMotions.begin(); - iter != mAllMotions.end(); iter++) + // Singu note: this must run over mActiveMotions: other motions are not active, + // and running over mAllMotions will miss the ones in mDeprecatedMotions. + for (motion_list_t::iterator iter = mActiveMotions.begin(); iter != mActiveMotions.end();) { - LLMotion* motionp = iter->second; - deactivateMotionInstance(motionp); + deactivateMotionInstance(*iter++); // This might invalidate iter by erasing it from mActiveMotions. } } @@ -1086,8 +1164,7 @@ void LLMotionController::flushAllMotions() active_motions.push_back(std::make_pair(motionp->getID(),dtime)); motionp->deactivate(); // don't call deactivateMotionInstance() because we are going to reactivate it } - mActiveMotions.clear(); - + // delete all motion instances deleteAllMotions(); @@ -1096,13 +1173,136 @@ void LLMotionController::flushAllMotions() mCharacter->removeAnimationData("Hand Pose"); // restart motions + // + // Because we called motionp->deactivate() above, instead of deactivateMotionInstance(), + // prevent calling AISyncClientMotion::activateInstance in startMotion below. + disable_syncing(); + // for (std::vector >::iterator iter = active_motions.begin(); iter != active_motions.end(); ++iter) { startMotion(iter->first, iter->second); } + // + enable_syncing(); + // +} + +// +//----------------------------------------------------------------------------- +// toggle_hidden() +//----------------------------------------------------------------------------- +void LLMotionController::toggle_hidden(void) +{ + mHaveVisibleSyncedMotions = mHidden; // Default is false if we just became invisible (otherwise this value isn't used). + mHidden = !mHidden; + synceventset_t const visible = mHidden ? 0 : 4; + + // Run over all motions. + for (motion_list_t::iterator iter = mActiveMotions.begin(); iter != mActiveMotions.end(); ++iter) + { + LLMotion* motionp = *iter; + AISyncServer* server = motionp->server(); + if (server && !server->never_synced() && motionp->isActive()) // Skip motions that aren't synchronized at all or that are not active. + { + bool visible_before = server->events_with_at_least_one_client_ready() & 4; + server->ready(4, visible, motionp); // Mark that now we are visible or no longer visible. + bool visible_after = server->events_with_at_least_one_client_ready() & 4; + if (visible_after) // Are there any synchronized motions (left) that ARE visible? + { + mHaveVisibleSyncedMotions = true; + } + if (visible_before != visible_after) + { + // The group as a whole now might need to change whether or not it is animated. + AISyncServer::client_list_t const& clients = server->getClients(); + for (AISyncServer::client_list_t::const_iterator client = clients.begin(); client != clients.end(); ++client) + { + LLMotion* motion = dynamic_cast(client->mClientPtr); + if (!motion) + { + continue; + } + LLMotionController* controller = motion->getController(); + if (controller == this) + { + continue; + } + if (visible_after) + { + // Us becoming visible means that all synchronized avatars need to be animated again too. + controller->setHaveVisibleSyncedMotions(); + } + else + { + // Us becoming hidden means that all synchronized avatars might stop animating. + controller->refresh_hidden(); // It is extremely unlikely, but harmless, to call this twice on the same controller. + } + } + } + } + } +} + +void LLMotionController::refresh_hidden(void) +{ + mHaveVisibleSyncedMotions = !mHidden; + + // Run over all motions. + for (motion_list_t::iterator iter = mActiveMotions.begin(); iter != mActiveMotions.end(); ++iter) + { + LLMotion* motionp = *iter; + AISyncServer* server = motionp->server(); + if (server && !server->never_synced() && motionp->isActive()) // Skip motions that aren't synchronized at all or that are not active. + { + bool visible_after = server->events_with_at_least_one_client_ready() & 4; + if (visible_after) // Are there any synchronized motions (left) that ARE visible? + { + mHaveVisibleSyncedMotions = true; + } + } + } +} + +void LLMotionController::pauseAllSyncedCharacters(std::vector& avatar_pause_handles) +{ + // Run over all motions. + for (motion_list_t::iterator iter = mActiveMotions.begin(); iter != mActiveMotions.end(); ++iter) + { + LLMotion* motionp = *iter; + AISyncServer* server = motionp->server(); + if (server && !server->never_synced() && motionp->isActive()) // Skip motions that aren't synchronized at all or that are not active. + { + // Run over all clients of the found servers. + AISyncServer::client_list_t const& clients = server->getClients(); + for (AISyncServer::client_list_t::const_iterator client = clients.begin(); client != clients.end(); ++client) + { + LLMotion* motion = dynamic_cast(client->mClientPtr); + if (!motion) + { + continue; + } + LLMotionController* controller = motion->getController(); + if (controller == this) + { + continue; + } + controller->requestPause(avatar_pause_handles); + } + } + } } +void LLMotionController::requestPause(std::vector& avatar_pause_handles) +{ + if (mCharacter) + { + mCharacter->requestPause(avatar_pause_handles); + } +} + +// + //----------------------------------------------------------------------------- // pause() //----------------------------------------------------------------------------- @@ -1110,8 +1310,9 @@ void LLMotionController::pauseAllMotions() { if (!mPaused) { - //llinfos << "Pausing animations..." << llendl; + //LL_INFOS() << "Pausing animations..." << LL_ENDL; mPaused = TRUE; + mPausedFrame = LLFrameTimer::getFrameCount(); } } @@ -1123,7 +1324,7 @@ void LLMotionController::unpauseAllMotions() { if (mPaused) { - //llinfos << "Unpausing animations..." << llendl; + //LL_INFOS() << "Unpausing animations..." << LL_ENDL; mPaused = FALSE; } } diff --git a/indra/llcharacter/llmotioncontroller.h b/indra/llcharacter/llmotioncontroller.h index 2de13aa36f..843cac4252 100644 --- a/indra/llcharacter/llmotioncontroller.h +++ b/indra/llcharacter/llmotioncontroller.h @@ -51,11 +51,14 @@ // This is necessary because llcharacter.h includes this file. //----------------------------------------------------------------------------- class LLCharacter; +class LLMotionController; +class LLPauseRequestHandle; +typedef LLPointer LLAnimPauseRequest; //----------------------------------------------------------------------------- // LLMotionRegistry //----------------------------------------------------------------------------- -typedef LLMotion*(*LLMotionConstructor)(const LLUUID &id); +typedef LLMotion* (*LLMotionConstructor)(LLUUID const& id, LLMotionController*); class LLMotionRegistry { @@ -72,7 +75,7 @@ class LLMotionRegistry // creates a new instance of a named motion // returns NULL motion is not registered - LLMotion *createMotion( const LLUUID &id ); + LLMotion* createMotion(LLUUID const& id, LLMotionController* controller); // initialization of motion failed, don't try to create this motion again void markBad( const LLUUID& id ); @@ -115,7 +118,6 @@ class LLMotionController // unregisters a motion with the controller // (actually just forwards call to motion registry) - // returns true if successfull void removeMotion( const LLUUID& id ); // start motion @@ -150,16 +152,30 @@ class LLMotionController //Flush is a liar. void deactivateAllMotions(); + // + void activated(U32 bit) { mActiveMask |= bit; } + void deactivated(U32 bit) { mActiveMask &= ~bit; } + bool isactive(U32 bit) const { return (mActiveMask & bit) != 0; } + // + // pause and continue all motions void pauseAllMotions(); void unpauseAllMotions(); BOOL isPaused() const { return mPaused; } + U64 getPausedFrame() const { return mPausedFrame; } + // + void requestPause(std::vector& avatar_pause_handles); + void pauseAllSyncedCharacters(std::vector& avatar_pause_handles); + // void setTimeStep(F32 step); + F32 getTimeStep() const { return mTimeStep; } void setTimeFactor(F32 time_factor); F32 getTimeFactor() const { return mTimeFactor; } + F32 getAnimTime() const { return mAnimTime; } + motion_list_t& getActiveMotions() { return mActiveMotions; } void incMotionCounts(S32& num_motions, S32& num_loading_motions, S32& num_loaded_motions, S32& num_active_motions, S32& num_deprecated_motions); @@ -180,7 +196,10 @@ class LLMotionController // internal operations act on motion instances directly // as there can be duplicate motions per id during blending overlap void deleteAllMotions(); + // singu: LLMotion needs access to activateMotionInstance. +public: BOOL activateMotionInstance(LLMotion *motion, F32 time); +protected: BOOL deactivateMotionInstance(LLMotion *motion); void deprecateMotionInstance(LLMotion* motion); BOOL stopMotionInstance(LLMotion *motion, BOOL stop_imemdiate); @@ -205,10 +224,13 @@ class LLMotionController // Life cycle of an animation: // // Animations are instantiated and immediately put in the mAllMotions map for their entire lifetime. +// Singu note: that is not true, they are moved to mDeprecatedMotions (often) for the last part of their lifetime. // If the animations depend on any asset data, the appropriate data is fetched from the data server, // and the animation is put on the mLoadingMotions list. // Once an animations is loaded, it will be initialized and put on the mLoadedMotions list. // Any animation that is currently playing also sits in the mActiveMotions list. +// Singu note: animations are only put in mDeprecatedMotions if and while they are playing, +// therefore animations in mDeprecatedMotions will be (must be) active and in mActiveMotions. typedef std::map motion_map_t; motion_map_t mAllMotions; @@ -217,19 +239,44 @@ class LLMotionController motion_set_t mLoadedMotions; motion_list_t mActiveMotions; motion_set_t mDeprecatedMotions; - + + // + U32 mActiveMask; + int mDisableSyncing; // Set while LLMotion::onActivate (and onDeactivate) are called for this controller. + bool mHidden; // The value of the last call to hidden(). + bool mHaveVisibleSyncedMotions; // Set when we are synchronized with one or more motions of a controller that is not hidden. + // LLFrameTimer mTimer; F32 mPrevTimerElapsed; F32 mAnimTime; F32 mLastTime; BOOL mHasRunOnce; BOOL mPaused; - F32 mPauseTime; + U64 mPausedFrame; F32 mTimeStep; S32 mTimeStepCount; F32 mLastInterp; - U8 mJointSignature[2][LL_CHARACTER_MAX_JOINTS]; + U8 mJointSignature[2][LL_CHARACTER_MAX_ANIMATED_JOINTS]; + + // +public: + // Internal administration for AISync. + void disable_syncing(void) { mDisableSyncing += 100; } + void enable_syncing(void) { mDisableSyncing -= 100; } + bool syncing_disabled(void) const { return mDisableSyncing >= 100; } + + // Accessors needed for synchronization. + bool isHidden(void) const { return mHidden; } + + // Called often. Should return false if we still need to keep updating our motions even if we're not visible. + bool hidden(bool not_visible) { if (mHidden != not_visible) toggle_hidden(); return !mHaveVisibleSyncedMotions; } + +private: + void toggle_hidden(void); + void refresh_hidden(void); + void setHaveVisibleSyncedMotions(void) { mHaveVisibleSyncedMotions = true; } + // }; //----------------------------------------------------------------------------- diff --git a/indra/llcharacter/llmultigesture.cpp b/indra/llcharacter/llmultigesture.cpp index d8290681a7..64de502b60 100644 --- a/indra/llcharacter/llmultigesture.cpp +++ b/indra/llcharacter/llmultigesture.cpp @@ -36,7 +36,7 @@ #include "lldatapacker.h" #include "llstl.h" -const S32 GESTURE_VERSION = 2; +constexpr S32 GESTURE_VERSION = 2; //--------------------------------------------------------------------------- // LLMultiGesture @@ -48,9 +48,10 @@ LLMultiGesture::LLMultiGesture() mTrigger(), mReplaceText(), mSteps(), - mPlaying(FALSE), + mPlaying(false), + mLocal(false), mCurrentStep(0), - mDoneCallback(NULL) + mDoneCallback(nullptr) { reset(); } @@ -62,12 +63,13 @@ LLMultiGesture::~LLMultiGesture() void LLMultiGesture::reset() { - mPlaying = FALSE; + mPlaying = false; + mLocal = false; mCurrentStep = 0; mWaitTimer.reset(); - mWaitingTimer = FALSE; - mWaitingAnimations = FALSE; - mWaitingAtEnd = FALSE; + mWaitingTimer = false; + mWaitingAnimations = false; + mWaitingAtEnd = false; mRequestedAnimIDs.clear(); mPlayingAnimIDs.clear(); } @@ -86,10 +88,8 @@ S32 LLMultiGesture::getMaxSerialSize() const max_size += 64; // step count S32 - std::vector::const_iterator it; - for (it = mSteps.begin(); it != mSteps.end(); ++it) + for (const auto& step : mSteps) { - LLGestureStep* step = *it; max_size += 64; // type S32 max_size += step->getMaxSerialSize(); } @@ -102,10 +102,8 @@ S32 LLMultiGesture::getMaxSerialSize() const max_size += sizeof(S32); // step count - std::vector::const_iterator it; - for (it = mSteps.begin(); it != mSteps.end(); ++it) + for (const auto& step : mSteps) { - LLGestureStep* step = *it; max_size += sizeof(S32); // type max_size += step->getMaxSerialSize(); } @@ -114,7 +112,7 @@ S32 LLMultiGesture::getMaxSerialSize() const return max_size; } -BOOL LLMultiGesture::serialize(LLDataPacker& dp) const +bool LLMultiGesture::serialize(LLDataPacker& dp) const { dp.packS32(GESTURE_VERSION, "version"); dp.packU8(mKey, "key"); @@ -124,110 +122,74 @@ BOOL LLMultiGesture::serialize(LLDataPacker& dp) const S32 count = (S32)mSteps.size(); dp.packS32(count, "step_count"); - S32 i; - for (i = 0; i < count; ++i) + for (const auto& step : mSteps) { - LLGestureStep* step = mSteps[i]; - dp.packS32(step->getType(), "step_type"); - BOOL ok = step->serialize(dp); - if (!ok) + if (!step->serialize(dp)) { - return FALSE; + return false; } } - return TRUE; + return true; } -BOOL LLMultiGesture::deserialize(LLDataPacker& dp) +bool LLMultiGesture::deserialize(LLDataPacker& dp) { S32 version; dp.unpackS32(version, "version"); if (version != GESTURE_VERSION) { - llwarns << "Bad LLMultiGesture version " << version + LL_WARNS() << "Bad LLMultiGesture version " << version << " should be " << GESTURE_VERSION - << llendl; - return FALSE; + << LL_ENDL; + return false; } dp.unpackU8(mKey, "key"); dp.unpackU32(mMask, "mask"); - - dp.unpackString(mTrigger, "trigger"); - dp.unpackString(mReplaceText, "replace"); S32 count; dp.unpackS32(count, "step_count"); if (count < 0) { - llwarns << "Bad LLMultiGesture step count " << count << llendl; - return FALSE; + LL_WARNS() << "Bad LLMultiGesture step count " << count << LL_ENDL; + return false; } - S32 i; - for (i = 0; i < count; ++i) + std::unique_ptr step; + for (S32 i = 0; i < count; ++i) { S32 type; dp.unpackS32(type, "step_type"); - EStepType step_type = (EStepType)type; - switch(step_type) + switch((EStepType)type) { - case STEP_ANIMATION: - { - LLGestureStepAnimation* step = new LLGestureStepAnimation(); - BOOL ok = step->deserialize(dp); - if (!ok) return FALSE; - mSteps.push_back(step); - break; - } - case STEP_SOUND: - { - LLGestureStepSound* step = new LLGestureStepSound(); - BOOL ok = step->deserialize(dp); - if (!ok) return FALSE; - mSteps.push_back(step); - break; - } - case STEP_CHAT: - { - LLGestureStepChat* step = new LLGestureStepChat(); - BOOL ok = step->deserialize(dp); - if (!ok) return FALSE; - mSteps.push_back(step); - break; - } - case STEP_WAIT: - { - LLGestureStepWait* step = new LLGestureStepWait(); - BOOL ok = step->deserialize(dp); - if (!ok) return FALSE; - mSteps.push_back(step); - break; - } + case STEP_ANIMATION: step.reset(new LLGestureStepAnimation); break; + case STEP_SOUND: step.reset(new LLGestureStepSound); break; + case STEP_CHAT: step.reset(new LLGestureStepChat); break; + case STEP_WAIT: step.reset(new LLGestureStepWait); break; default: { - llwarns << "Bad LLMultiGesture step type " << type << llendl; - return FALSE; + LL_WARNS() << "Bad LLMultiGesture step type " << type << LL_ENDL; + return false; } } + if (!step->deserialize(dp)) return false; + mSteps.push_back(step.release()); } - return TRUE; + return true; } void LLMultiGesture::dump() { - llinfos << "key " << S32(mKey) << " mask " << U32(mMask) + LL_INFOS() << "key " << S32(mKey) << " mask " << U32(mMask) << " trigger " << mTrigger << " replace " << mReplaceText - << llendl; - U32 i; - for (i = 0; i < mSteps.size(); ++i) + << LL_ENDL; + for (const auto& step : mSteps) { - LLGestureStep* step = mSteps[i]; step->dump(); } } @@ -262,21 +224,21 @@ S32 LLGestureStepAnimation::getMaxSerialSize() const return max_size; } -BOOL LLGestureStepAnimation::serialize(LLDataPacker& dp) const +bool LLGestureStepAnimation::serialize(LLDataPacker& dp) const { dp.packString(mAnimName, "anim_name"); dp.packUUID(mAnimAssetID, "asset_id"); dp.packU32(mFlags, "flags"); - return TRUE; + return true; } -BOOL LLGestureStepAnimation::deserialize(LLDataPacker& dp) +bool LLGestureStepAnimation::deserialize(LLDataPacker& dp) { dp.unpackString(mAnimName, "anim_name"); // Apparently an earlier version of the gesture code added \r to the end // of the animation names. Get rid of it. JC - if (!mAnimName.empty() && mAnimName[mAnimName.length() - 1] == '\r') + if (!mAnimName.empty() && mAnimName.back() == '\r') { // chop the last character mAnimName.resize(mAnimName.length() - 1); @@ -284,37 +246,26 @@ BOOL LLGestureStepAnimation::deserialize(LLDataPacker& dp) dp.unpackUUID(mAnimAssetID, "asset_id"); dp.unpackU32(mFlags, "flags"); - return TRUE; + return true; } // *NOTE: result is translated in LLPreviewGesture::getLabel() std::vector LLGestureStepAnimation::getLabel() const { - std::vector strings; - -// std::string label; +/* std::string label; if (mFlags & ANIM_FLAG_STOP) - { - strings.push_back( "AnimFlagStop"); - -// label = "Stop Animation: "; - } + label = "Stop Animation: "; else - { - strings.push_back( "AnimFlagStart"); - -// label = "Start Animation: "; - } - strings.push_back( mAnimName); -// label += mAnimName; - return strings; + label = "Start Animation: "; + label += mAnimName;*/ + return {mFlags & ANIM_FLAG_STOP ? "AnimFlagStop" : "AnimFlagStart", mAnimName}; } void LLGestureStepAnimation::dump() { - llinfos << "step animation " << mAnimName + LL_INFOS() << "step animation " << mAnimName << " id " << mAnimAssetID << " flags " << mFlags - << llendl; + << LL_ENDL; } //--------------------------------------------------------------------------- @@ -344,39 +295,36 @@ S32 LLGestureStepSound::getMaxSerialSize() const return max_size; } -BOOL LLGestureStepSound::serialize(LLDataPacker& dp) const +bool LLGestureStepSound::serialize(LLDataPacker& dp) const { dp.packString(mSoundName, "sound_name"); dp.packUUID(mSoundAssetID, "asset_id"); dp.packU32(mFlags, "flags"); - return TRUE; + return true; } -BOOL LLGestureStepSound::deserialize(LLDataPacker& dp) +bool LLGestureStepSound::deserialize(LLDataPacker& dp) { dp.unpackString(mSoundName, "sound_name"); dp.unpackUUID(mSoundAssetID, "asset_id"); dp.unpackU32(mFlags, "flags"); - return TRUE; + return true; } // *NOTE: result is translated in LLPreviewGesture::getLabel() std::vector LLGestureStepSound::getLabel() const { - std::vector strings; - strings.push_back( "Sound"); - strings.push_back( mSoundName); // std::string label("Sound: "); // label += mSoundName; - return strings; + return {"Sound", mSoundName}; } void LLGestureStepSound::dump() { - llinfos << "step sound " << mSoundName + LL_INFOS() << "step sound " << mSoundName << " id " << mSoundAssetID << " flags " << mFlags - << llendl; + << LL_ENDL; } @@ -404,34 +352,30 @@ S32 LLGestureStepChat::getMaxSerialSize() const return max_size; } -BOOL LLGestureStepChat::serialize(LLDataPacker& dp) const +bool LLGestureStepChat::serialize(LLDataPacker& dp) const { dp.packString(mChatText, "chat_text"); dp.packU32(mFlags, "flags"); - return TRUE; + return true; } -BOOL LLGestureStepChat::deserialize(LLDataPacker& dp) +bool LLGestureStepChat::deserialize(LLDataPacker& dp) { dp.unpackString(mChatText, "chat_text"); - dp.unpackU32(mFlags, "flags"); - return TRUE; + return true; } // *NOTE: result is translated in LLPreviewGesture::getLabel() std::vector LLGestureStepChat::getLabel() const { - std::vector strings; - strings.push_back("Chat"); - strings.push_back(mChatText); - return strings; + return {"Chat", mChatText}; } void LLGestureStepChat::dump() { - llinfos << "step chat " << mChatText + LL_INFOS() << "step chat " << mChatText << " flags " << mFlags - << llendl; + << LL_ENDL; } @@ -459,50 +403,32 @@ S32 LLGestureStepWait::getMaxSerialSize() const return max_size; } -BOOL LLGestureStepWait::serialize(LLDataPacker& dp) const +bool LLGestureStepWait::serialize(LLDataPacker& dp) const { dp.packF32(mWaitSeconds, "wait_seconds"); dp.packU32(mFlags, "flags"); - return TRUE; + return true; } -BOOL LLGestureStepWait::deserialize(LLDataPacker& dp) +bool LLGestureStepWait::deserialize(LLDataPacker& dp) { dp.unpackF32(mWaitSeconds, "wait_seconds"); dp.unpackU32(mFlags, "flags"); - return TRUE; + return true; } // *NOTE: result is translated in LLPreviewGesture::getLabel() std::vector LLGestureStepWait::getLabel() const { - std::vector strings; - strings.push_back( "Wait" ); - -// std::string label("--- Wait: "); - if (mFlags & WAIT_FLAG_TIME) - { - char buffer[64]; /* Flawfinder: ignore */ - snprintf(buffer, sizeof(buffer), "%.1f seconds", (double)mWaitSeconds); /* Flawfinder: ignore */ - strings.push_back(buffer); -// label += buffer; - } - else if (mFlags & WAIT_FLAG_ALL_ANIM) - { - strings.push_back("until animations are done"); - // label += "until animations are done"; - } - else - { - strings.push_back(""); - } - - return strings; + return {"Wait", + mFlags & WAIT_FLAG_TIME ? llformat("%.1f seconds", mWaitSeconds) + : mFlags & WAIT_FLAG_ALL_ANIM ? "until animations are done" + : LLStringUtil::null}; } void LLGestureStepWait::dump() { - llinfos << "step wait " << mWaitSeconds + LL_INFOS() << "step wait " << mWaitSeconds << " flags " << mFlags - << llendl; + << LL_ENDL; } diff --git a/indra/llcharacter/llmultigesture.h b/indra/llcharacter/llmultigesture.h index 4c5a29cf0f..68395465bf 100644 --- a/indra/llcharacter/llmultigesture.h +++ b/indra/llcharacter/llmultigesture.h @@ -27,7 +27,7 @@ #ifndef LL_LLMULTIGESTURE_H #define LL_LLMULTIGESTURE_H -#include +#include #include #include @@ -46,8 +46,8 @@ class LLMultiGesture // Maximum number of bytes this could hold once serialized. S32 getMaxSerialSize() const; - BOOL serialize(LLDataPacker& dp) const; - BOOL deserialize(LLDataPacker& dp); + bool serialize(LLDataPacker& dp) const; + bool deserialize(LLDataPacker& dp); void dump(); @@ -77,31 +77,34 @@ class LLMultiGesture std::vector mSteps; // Is the gesture currently playing? - BOOL mPlaying; + bool mPlaying; + + // Is the gesture to be played locally? + bool mLocal; // "instruction pointer" for steps S32 mCurrentStep; // We're waiting for triggered animations to stop playing - BOOL mWaitingAnimations; + bool mWaitingAnimations; // We're waiting a fixed amount of time - BOOL mWaitingTimer; + bool mWaitingTimer; // Waiting after the last step played for all animations to complete - BOOL mWaitingAtEnd; + bool mWaitingAtEnd; // Timer for waiting LLFrameTimer mWaitTimer; - boost::function mDoneCallback; + std::function mDoneCallback; // Animations that we requested to start - std::set mRequestedAnimIDs; + uuid_set_t mRequestedAnimIDs; // Once the animation starts playing (sim says to start playing) // the ID is moved from mRequestedAnimIDs to here. - std::set mPlayingAnimIDs; + uuid_set_t mPlayingAnimIDs; }; @@ -124,14 +127,14 @@ class LLGestureStep LLGestureStep() {} virtual ~LLGestureStep() {} - virtual EStepType getType() = 0; + virtual EStepType getType() const = 0; // Return a user-readable label for this step virtual std::vector getLabel() const = 0; virtual S32 getMaxSerialSize() const = 0; - virtual BOOL serialize(LLDataPacker& dp) const = 0; - virtual BOOL deserialize(LLDataPacker& dp) = 0; + virtual bool serialize(LLDataPacker& dp) const = 0; + virtual bool deserialize(LLDataPacker& dp) = 0; virtual void dump() = 0; }; @@ -139,7 +142,7 @@ class LLGestureStep // By default, animation steps start animations. // If the least significant bit is 1, it will stop animations. -const U32 ANIM_FLAG_STOP = 0x01; +constexpr U32 ANIM_FLAG_STOP = 0x01; class LLGestureStepAnimation : public LLGestureStep { @@ -147,15 +150,15 @@ class LLGestureStepAnimation : public LLGestureStep LLGestureStepAnimation(); virtual ~LLGestureStepAnimation(); - virtual EStepType getType() { return STEP_ANIMATION; } + EStepType getType() const override { return STEP_ANIMATION; } - virtual std::vector getLabel() const; + std::vector getLabel() const override; - virtual S32 getMaxSerialSize() const; - virtual BOOL serialize(LLDataPacker& dp) const; - virtual BOOL deserialize(LLDataPacker& dp); + S32 getMaxSerialSize() const override; + bool serialize(LLDataPacker& dp) const override; + bool deserialize(LLDataPacker& dp) override; - virtual void dump(); + void dump() override; public: std::string mAnimName; @@ -170,15 +173,15 @@ class LLGestureStepSound : public LLGestureStep LLGestureStepSound(); virtual ~LLGestureStepSound(); - virtual EStepType getType() { return STEP_SOUND; } + EStepType getType() const override { return STEP_SOUND; } - virtual std::vector getLabel() const; + std::vector getLabel() const override; - virtual S32 getMaxSerialSize() const; - virtual BOOL serialize(LLDataPacker& dp) const; - virtual BOOL deserialize(LLDataPacker& dp); + S32 getMaxSerialSize() const override; + bool serialize(LLDataPacker& dp) const override; + bool deserialize(LLDataPacker& dp) override; - virtual void dump(); + void dump() override; public: std::string mSoundName; @@ -193,15 +196,15 @@ class LLGestureStepChat : public LLGestureStep LLGestureStepChat(); virtual ~LLGestureStepChat(); - virtual EStepType getType() { return STEP_CHAT; } + EStepType getType() const override { return STEP_CHAT; } - virtual std::vector getLabel() const; + std::vector getLabel() const override; - virtual S32 getMaxSerialSize() const; - virtual BOOL serialize(LLDataPacker& dp) const; - virtual BOOL deserialize(LLDataPacker& dp); + S32 getMaxSerialSize() const override; + bool serialize(LLDataPacker& dp) const override; + bool deserialize(LLDataPacker& dp) override; - virtual void dump(); + void dump() override; public: std::string mChatText; @@ -209,8 +212,8 @@ class LLGestureStepChat : public LLGestureStep }; -const U32 WAIT_FLAG_TIME = 0x01; -const U32 WAIT_FLAG_ALL_ANIM = 0x02; +constexpr U32 WAIT_FLAG_TIME = 0x01; +constexpr U32 WAIT_FLAG_ALL_ANIM = 0x02; class LLGestureStepWait : public LLGestureStep { @@ -218,15 +221,15 @@ class LLGestureStepWait : public LLGestureStep LLGestureStepWait(); virtual ~LLGestureStepWait(); - virtual EStepType getType() { return STEP_WAIT; } + EStepType getType() const override { return STEP_WAIT; } - virtual std::vector getLabel() const; + std::vector getLabel() const override; - virtual S32 getMaxSerialSize() const; - virtual BOOL serialize(LLDataPacker& dp) const; - virtual BOOL deserialize(LLDataPacker& dp); + S32 getMaxSerialSize() const override; + bool serialize(LLDataPacker& dp) const override; + bool deserialize(LLDataPacker& dp) override; - virtual void dump(); + void dump() override; public: F32 mWaitSeconds; diff --git a/indra/llcharacter/llpose.h b/indra/llcharacter/llpose.h index 2b976b219d..63c0fdde43 100644 --- a/indra/llcharacter/llpose.h +++ b/indra/llcharacter/llpose.h @@ -96,6 +96,16 @@ class LLJointStateBlender public: LLJointStateBlender(); ~LLJointStateBlender(); + void* operator new(size_t size) + { + return ll_aligned_malloc_16(size); + } + + void operator delete(void* ptr) + { + ll_aligned_free_16(ptr); + } + void blendJointStates(BOOL apply_now = TRUE); BOOL addJointState(const LLPointer& joint_state, S32 priority, BOOL additive_blend); void interpolate(F32 u); diff --git a/indra/llcharacter/llstatemachine.cpp b/indra/llcharacter/llstatemachine.cpp index dcc4ff5f0e..099bb94589 100644 --- a/indra/llcharacter/llstatemachine.cpp +++ b/indra/llcharacter/llstatemachine.cpp @@ -88,7 +88,7 @@ BOOL LLStateDiagram::addTransition(LLFSMState& start_state, LLFSMState& end_stat Transitions::iterator transition_it = state_transitions->find(&transition); if (transition_it != state_transitions->end()) { - llerrs << "LLStateTable::addDirectedTransition() : transition already exists" << llendl; + LL_ERRS() << "LLStateTable::addDirectedTransition() : transition already exists" << LL_ENDL; return FALSE; // transition already exists } @@ -209,7 +209,7 @@ BOOL LLStateDiagram::saveDotFile(const std::string& filename) if (!dot_file) { - llwarns << "LLStateDiagram::saveDotFile() : Couldn't open " << filename << " to save state diagram." << llendl; + LL_WARNS() << "LLStateDiagram::saveDotFile() : Couldn't open " << filename << " to save state diagram." << LL_ENDL; return FALSE; } apr_file_printf(dot_file, "digraph StateMachine {\n\tsize=\"100,100\";\n\tfontsize=40;\n\tlabel=\"Finite State Machine\";\n\torientation=landscape\n\tratio=.77\n"); @@ -363,7 +363,7 @@ void LLStateMachine::processTransition(LLFSMTransition& transition, void* user_d if (NULL == mCurrentState) { - llwarns << "mCurrentState == NULL; aborting processTransition()" << llendl; + LL_WARNS() << "mCurrentState == NULL; aborting processTransition()" << LL_ENDL; return; } @@ -371,7 +371,7 @@ void LLStateMachine::processTransition(LLFSMTransition& transition, void* user_d if (NULL == new_state) { - llwarns << "new_state == NULL; aborting processTransition()" << llendl; + LL_WARNS() << "new_state == NULL; aborting processTransition()" << LL_ENDL; return; } @@ -384,9 +384,9 @@ void LLStateMachine::processTransition(LLFSMTransition& transition, void* user_d mCurrentState = new_state; mCurrentState->onEntry(user_data); #if FSM_PRINT_STATE_TRANSITIONS - llinfos << "Entering state " << mCurrentState->getName() << + LL_INFOS() << "Entering state " << mCurrentState->getName() << " on transition " << transition.getName() << " from state " << - mLastState->getName() << llendl; + mLastState->getName() << LL_ENDL; #endif } } diff --git a/indra/llcharacter/lltargetingmotion.cpp b/indra/llcharacter/lltargetingmotion.cpp index a330b22659..9dd581f308 100644 --- a/indra/llcharacter/lltargetingmotion.cpp +++ b/indra/llcharacter/lltargetingmotion.cpp @@ -52,7 +52,7 @@ const F32 TORSO_ROT_FRACTION = 0.5f; // LLTargetingMotion() // Class Constructor //----------------------------------------------------------------------------- -LLTargetingMotion::LLTargetingMotion(const LLUUID &id) : LLMotion(id) +LLTargetingMotion::LLTargetingMotion(LLUUID const& id, LLMotionController* controller) : AIMaskedMotion(id, controller, ANIM_AGENT_TARGET) { mCharacter = NULL; mName = "targeting"; @@ -86,7 +86,7 @@ LLMotion::LLMotionInitStatus LLTargetingMotion::onInitialize(LLCharacter *charac !mTorsoJoint || !mRightHandJoint) { - llwarns << "Invalid skeleton for targeting motion!" << llendl; + LL_WARNS() << "Invalid skeleton for targeting motion!" << LL_ENDL; return STATUS_FAILURE; } @@ -99,20 +99,12 @@ LLMotion::LLMotionInitStatus LLTargetingMotion::onInitialize(LLCharacter *charac return STATUS_SUCCESS; } -//----------------------------------------------------------------------------- -// LLTargetingMotion::onActivate() -//----------------------------------------------------------------------------- -BOOL LLTargetingMotion::onActivate() -{ - return TRUE; -} - //----------------------------------------------------------------------------- // LLTargetingMotion::onUpdate() //----------------------------------------------------------------------------- BOOL LLTargetingMotion::onUpdate(F32 time, U8* joint_mask) { - F32 slerp_amt = LLCriticalDamp::getInterpolant(TORSO_TARGET_HALF_LIFE); + F32 slerp_amt = LLSmoothInterpolation::getInterpolant(TORSO_TARGET_HALF_LIFE); LLVector3 target; LLVector3* lookAtPoint = (LLVector3*)mCharacter->getAnimationData("LookAtPoint"); @@ -166,12 +158,4 @@ BOOL LLTargetingMotion::onUpdate(F32 time, U8* joint_mask) return result; } -//----------------------------------------------------------------------------- -// LLTargetingMotion::onDeactivate() -//----------------------------------------------------------------------------- -void LLTargetingMotion::onDeactivate() -{ -} - - // End diff --git a/indra/llcharacter/lltargetingmotion.h b/indra/llcharacter/lltargetingmotion.h index 1ec9f80d60..f7b08ee69a 100644 --- a/indra/llcharacter/lltargetingmotion.h +++ b/indra/llcharacter/lltargetingmotion.h @@ -48,11 +48,11 @@ // class LLTargetingMotion //----------------------------------------------------------------------------- class LLTargetingMotion : - public LLMotion + public AIMaskedMotion { public: // Constructor - LLTargetingMotion(const LLUUID &id); + LLTargetingMotion(LLUUID const& id, LLMotionController* controller); // Destructor virtual ~LLTargetingMotion(); @@ -64,7 +64,7 @@ class LLTargetingMotion : // static constructor // all subclasses must implement such a function and register it - static LLMotion *create(const LLUUID &id) { return new LLTargetingMotion(id); } + static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLTargetingMotion(id, controller); } public: //------------------------------------------------------------------------- @@ -96,19 +96,11 @@ class LLTargetingMotion : // must return true to indicate success and be available for activation virtual LLMotionInitStatus onInitialize(LLCharacter *character); - // called when a motion is activated - // must return TRUE to indicate success, or else - // it will be deactivated - virtual BOOL onActivate(); - // called per time step // must return TRUE while it is active, and // must return FALSE when the motion is completed. virtual BOOL onUpdate(F32 time, U8* joint_mask); - // called when a motion is deactivated - virtual void onDeactivate(); - public: LLCharacter *mCharacter; diff --git a/indra/llcharacter/llvisualparam.cpp b/indra/llcharacter/llvisualparam.cpp index f7cb0f76b7..d7d4ebc952 100644 --- a/indra/llcharacter/llvisualparam.cpp +++ b/indra/llcharacter/llvisualparam.cpp @@ -79,7 +79,7 @@ BOOL LLVisualParamInfo::parseXml(LLXmlTreeNode *node) mDefaultWeight = llclamp( default_weight, mMinWeight, mMaxWeight ); if( default_weight != mDefaultWeight ) { - llwarns << "value_default attribute is out of range in node " << mName << " " << default_weight << llendl; + LL_WARNS() << "value_default attribute is out of range in node " << mName << " " << default_weight << LL_ENDL; } } @@ -101,7 +101,7 @@ BOOL LLVisualParamInfo::parseXml(LLXmlTreeNode *node) } else { - llwarns << "Avatar file: has invalid sex attribute: " << sex << llendl; + LL_WARNS() << "Avatar file: has invalid sex attribute: " << sex << LL_ENDL; return FALSE; } @@ -109,7 +109,7 @@ BOOL LLVisualParamInfo::parseXml(LLXmlTreeNode *node) static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name"); if( !node->getFastAttributeString( name_string, mName ) ) { - llwarns << "Avatar file: is missing name attribute" << llendl; + LL_WARNS() << "Avatar file: is missing name attribute" << LL_ENDL; return FALSE; } @@ -159,26 +159,42 @@ void LLVisualParamInfo::toStream(std::ostream &out) //----------------------------------------------------------------------------- // LLVisualParam() //----------------------------------------------------------------------------- -LLVisualParam::LLVisualParam() - : - mCurWeight( 0.f ), +LLVisualParam::LLVisualParam() + : mCurWeight( 0.f ), mLastWeight( 0.f ), mNext( NULL ), mTargetWeight( 0.f ), mIsAnimating( FALSE ), + mIsDummy(FALSE), mID( -1 ), mInfo( 0 ), - mIsDummy(FALSE), mParamLocation(LOC_UNKNOWN) { } +//----------------------------------------------------------------------------- +// LLVisualParam() +//----------------------------------------------------------------------------- +LLVisualParam::LLVisualParam(const LLVisualParam& pOther) + : mCurWeight(pOther.mCurWeight), + mLastWeight(pOther.mLastWeight), + mNext(pOther.mNext), + mTargetWeight(pOther.mTargetWeight), + mIsAnimating(pOther.mIsAnimating), + mIsDummy(pOther.mIsDummy), + mID(pOther.mID), + mInfo(pOther.mInfo), + mParamLocation(pOther.mParamLocation) +{ +} + //----------------------------------------------------------------------------- // ~LLVisualParam() //----------------------------------------------------------------------------- LLVisualParam::~LLVisualParam() { delete mNext; + mNext = NULL; } /* @@ -220,7 +236,7 @@ BOOL LLVisualParam::parseData(LLXmlTreeNode *node) //----------------------------------------------------------------------------- // setWeight() //----------------------------------------------------------------------------- -void LLVisualParam::setWeight(F32 weight, BOOL upload_bake) +void LLVisualParam::setWeight(F32 weight, bool upload_bake) { if (mIsAnimating) { @@ -245,7 +261,7 @@ void LLVisualParam::setWeight(F32 weight, BOOL upload_bake) //----------------------------------------------------------------------------- // setAnimationTarget() //----------------------------------------------------------------------------- -void LLVisualParam::setAnimationTarget(F32 target_value, BOOL upload_bake) +void LLVisualParam::setAnimationTarget(F32 target_value, bool upload_bake) { // don't animate dummy parameters if (mIsDummy) @@ -284,10 +300,18 @@ void LLVisualParam::setNextParam( LLVisualParam *next ) mNext = next; } +//----------------------------------------------------------------------------- +// clearNextParam() +//----------------------------------------------------------------------------- +void LLVisualParam::clearNextParam() +{ + mNext = NULL; +} + //----------------------------------------------------------------------------- // animate() //----------------------------------------------------------------------------- -void LLVisualParam::animate( F32 delta, BOOL upload_bake ) +void LLVisualParam::animate( F32 delta, bool upload_bake ) { if (mIsAnimating) { @@ -299,7 +323,7 @@ void LLVisualParam::animate( F32 delta, BOOL upload_bake ) //----------------------------------------------------------------------------- // stopAnimating() //----------------------------------------------------------------------------- -void LLVisualParam::stopAnimating(BOOL upload_bake) +void LLVisualParam::stopAnimating(bool upload_bake) { if (mIsAnimating && isTweakable()) { @@ -346,7 +370,7 @@ void LLVisualParam::setParamLocation(EParamLocation loc) } else { - lldebugs << "param location is already " << mParamLocation << ", not slamming to " << loc << llendl; + LL_DEBUGS() << "param location is already " << mParamLocation << ", not slamming to " << loc << LL_ENDL; } } diff --git a/indra/llcharacter/llvisualparam.h b/indra/llcharacter/llvisualparam.h index a5864c15ce..7a6f6a0a1d 100644 --- a/indra/llcharacter/llvisualparam.h +++ b/indra/llcharacter/llvisualparam.h @@ -30,7 +30,6 @@ #include "v3math.h" #include "llstring.h" #include "llxmltree.h" -#include class LLPolyMesh; class LLXmlTreeNode; @@ -47,6 +46,7 @@ enum EVisualParamGroup VISUAL_PARAM_GROUP_TWEAKABLE, VISUAL_PARAM_GROUP_ANIMATABLE, VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT, + VISUAL_PARAM_GROUP_TRANSMIT_NOT_TWEAKABLE, // deprecated params that used to be tweakable. NUM_VISUAL_PARAM_GROUPS }; @@ -99,14 +99,27 @@ class LLVisualParamInfo // An interface class for a generalized parametric modification of the avatar mesh // Contains data that is specific to each Avatar //----------------------------------------------------------------------------- +LL_ALIGN_PREFIX(16) class LLVisualParam { public: - typedef boost::function visual_param_mapper; + typedef std::function visual_param_mapper; LLVisualParam(); virtual ~LLVisualParam(); + // + void* operator new(size_t size) + { + return ll_aligned_malloc_16(size); + } + + void operator delete(void* ptr) + { + ll_aligned_free_16(ptr); + } + // + // Special: These functions are overridden by child classes // (They can not be virtual because they use specific derived Info classes) LLVisualParamInfo* getInfo() const { return mInfo; } @@ -118,10 +131,10 @@ class LLVisualParam //virtual BOOL parseData( LLXmlTreeNode *node ) = 0; virtual void apply( ESex avatar_sex ) = 0; // Default functions - virtual void setWeight(F32 weight, BOOL upload_bake); - virtual void setAnimationTarget( F32 target_value, BOOL upload_bake ); - virtual void animate(F32 delta, BOOL upload_bake); - virtual void stopAnimating(BOOL upload_bake); + virtual void setWeight(F32 weight, bool upload_bake = false); + virtual void setAnimationTarget(F32 target_value, bool upload_bake = false); + virtual void animate(F32 delta, bool upload_bake = false); + virtual void stopAnimating(bool upload_bake = false); virtual BOOL linkDrivenParams(visual_param_mapper mapper, BOOL only_cross_params); virtual void resetDrivenParams(); @@ -153,6 +166,7 @@ class LLVisualParam LLVisualParam* getNextParam() { return mNext; } void setNextParam( LLVisualParam *next ); + void clearNextParam(); virtual void setAnimating(BOOL is_animating) { mIsAnimating = is_animating && !mIsDummy; } BOOL getAnimating() const { return mIsAnimating; } @@ -162,7 +176,13 @@ class LLVisualParam void setParamLocation(EParamLocation loc); EParamLocation getParamLocation() const { return mParamLocation; } + // Singu extensions. Used for dumping the archtype. + virtual char const* getTypeString(void) const = 0; + virtual std::string getDumpWearableTypeName(void) const = 0; + protected: + LLVisualParam(const LLVisualParam& pOther); + F32 mCurWeight; // current weight F32 mLastWeight; // last weight LLVisualParam* mNext; // next param in a shared chain @@ -174,6 +194,6 @@ class LLVisualParam S32 mID; // id for storing weight/morphtarget compares compactly LLVisualParamInfo *mInfo; EParamLocation mParamLocation; // where does this visual param live? -}; +} LL_ALIGN_POSTFIX(16); #endif // LL_LLVisualParam_H diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index 6f93be79e5..ea99d74296 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -4,31 +4,43 @@ project(llcommon) include(Cwdebug) include(00-Common) +include(Linking) include(LLCommon) +include(EXPAT) include(APR) include(Linking) +include(Boost) +include(OpenSSL) +include(LLSharedLibs) +include(Copy3rdPartyLibs) +include(ZLIB) +include(URIPARSER) include_directories( ${EXPAT_INCLUDE_DIRS} ${LLCOMMON_INCLUDE_DIRS} + ${OPENSSL_INCLUDE_DIRS} + ${JSON_INCLUDE_DIR} ${ZLIB_INCLUDE_DIRS} + ${BREAKPAD_INCLUDE_DIRECTORIES} ) set(llcommon_SOURCE_FILES + aialert.cpp aiframetimer.cpp + aisyncclient.cpp aithreadid.cpp imageids.cpp indra_constants.cpp - ll_template_cast.h llallocator.cpp llallocator_heap_profile.cpp llapp.cpp llapr.cpp llaprpool.cpp llassettype.cpp - llavatarname.cpp llbase32.cpp llbase64.cpp + llcallbacklist.cpp llcommon.cpp llcommonutils.cpp llcoros.cpp @@ -51,11 +63,9 @@ set(llcommon_SOURCE_FILES llfile.cpp llfindlocale.cpp llfixedbuffer.cpp - llfoldertype.cpp llformat.cpp llframetimer.cpp llheartbeat.cpp - llindraconfigfile.cpp llinitparam.cpp llinstancetracker.cpp llliveappconfig.cpp @@ -67,6 +77,7 @@ set(llcommon_SOURCE_FILES llmetrics.cpp llmortician.cpp lloptioninterface.cpp + llpredicate.cpp llprocesslauncher.cpp llprocessor.cpp llptrto.cpp @@ -76,6 +87,7 @@ set(llcommon_SOURCE_FILES llrun.cpp llscopedvolatileaprpool.h llsd.cpp + llsdjson.cpp llsdparam.cpp llsdserialize.cpp llsdserialize_xml.cpp @@ -92,6 +104,7 @@ set(llcommon_SOURCE_FILES llthreadsafequeue.cpp lltimer.cpp lluri.cpp + lluriparser.cpp lluuid.cpp llworkerthread.cpp metaclass.cpp @@ -104,18 +117,20 @@ set(llcommon_SOURCE_FILES set(llcommon_HEADER_FILES CMakeLists.txt + aialert.h aiframetimer.h airecursive.h + aisyncclient.h aithreadid.h aithreadsafe.h bitpack.h ctype_workaround.h - doublelinkedlist.h + fix_macros.h imageids.h indra_constants.h linden_common.h - linked_lists.h llaccountingcost.h + llalignedarray.h llagentconstants.h llallocator.h llallocator_heap_profile.h @@ -126,10 +141,10 @@ set(llcommon_HEADER_FILES llassoclist.h llatomic.h llavatarconstants.h - llavatarname.h llbase32.h llbase64.h llboost.h + llcallbacklist.h llchat.h llclickaction.h llcommon.h @@ -138,21 +153,14 @@ set(llcommon_HEADER_FILES llcrc.h llcriticaldamp.h llcursortypes.h - lldarray.h - lldarrayptr.h lldate.h lldefs.h - lldeleteutils.h lldependencies.h lldepthstack.h lldictionary.h - lldlinked.h - lldqueueptr.h llendianswizzle.h - llenum.h llerror.h llerrorcontrol.h - llerrorlegacy.h llerrorthread.h llevent.h lleventapi.h @@ -168,15 +176,12 @@ set(llcommon_HEADER_FILES llfile.h llfindlocale.h llfixedbuffer.h - llfoldertype.h llformat.h llframetimer.h llhandle.h - llhash.h llheartbeat.h llhttpstatuscodes.h - llindexedqueue.h - llindraconfigfile.h + llindexedvector.h llinitparam.h llinstancetracker.h llkeythrottle.h @@ -195,12 +200,11 @@ set(llcommon_HEADER_FILES llnametable.h lloptioninterface.h llpointer.h + llpredicate.h llpreprocessor.h llpriqueuemap.h llprocesslauncher.h llprocessor.h - llptrskiplist.h - llptrskipmap.h llptrto.h llqueuedthread.h llrand.h @@ -209,6 +213,7 @@ set(llcommon_HEADER_FILES llrun.h llsafehandle.h llsd.h + llsdjson.h llsdparam.h llsdserialize.h llsdserialize_xml.h @@ -219,7 +224,6 @@ set(llcommon_HEADER_FILES llskiplist.h llskipmap.h llsortedvector.h - llstack.h llstacktrace.h llstat.h llstatenums.h @@ -228,16 +232,20 @@ set(llcommon_HEADER_FILES llstrider.h llstring.h llstringtable.h + llstaticstringtable.h llsys.h llthread.h llthreadsafequeue.h lltimer.h lltreeiterators.h + llunits.h + llunittype.h lltypeinfolookup.h lluri.h + lluriparser.h lluuid.h - sguuidhash.h - llversionviewer.h.in + llwin32headers.h + llwin32headerslean.h llworkerthread.h metaclass.h metaclasst.h @@ -245,10 +253,8 @@ set(llcommon_HEADER_FILES metapropertyt.h reflective.h reflectivet.h - roles_constants.h stdenums.h stdtypes.h - string_table.h stringize.h timer.h timing.h @@ -259,19 +265,44 @@ set_source_files_properties(${llcommon_HEADER_FILES} PROPERTIES HEADER_FILE_ONLY TRUE) list(APPEND llcommon_SOURCE_FILES ${cwdebug_SOURCE_FILES}) + list(APPEND llcommon_SOURCE_FILES ${llcommon_HEADER_FILES}) -add_library (llcommon SHARED ${llcommon_SOURCE_FILES}) -add_dependencies(llcommon prepare) +if(LLCOMMON_LINK_SHARED) + add_library (llcommon SHARED ${llcommon_SOURCE_FILES}) + if(WINDOWS) + # always generate llcommon.pdb, even for "Release" builds + set_target_properties(llcommon PROPERTIES LINK_FLAGS "/DEBUG") + endif(WINDOWS) + ll_stage_sharedlib(llcommon) +else(LLCOMMON_LINK_SHARED) + add_library (llcommon ${llcommon_SOURCE_FILES}) +endif(LLCOMMON_LINK_SHARED) + +set_target_properties(llcommon PROPERTIES POSITION_INDEPENDENT_CODE TRUE) + target_link_libraries( llcommon + PUBLIC + absl::hash ${APRUTIL_LIBRARIES} ${APR_LIBRARIES} ${EXPAT_LIBRARIES} + ${CRYPTO_LIBRARIES} + ${OPENSSL_LIBRARIES} + ${CRYPTO_LIBRARIES} ${ZLIB_LIBRARIES} ${WINDOWS_LIBRARIES} + ${Boost_CONTEXT_LIBRARY} ${Boost_REGEX_LIBRARY} + ${Boost_THREAD_LIBRARY} + ${Boost_SYSTEM_LIBRARY} ${CORESERVICES_LIBRARY} + ${URIPARSER_LIBRARY} + fmt::fmt + nlohmann_json::nlohmann_json + absl::strings + ${RT_LIBRARY} ) if (DARWIN) @@ -283,3 +314,5 @@ if (DARWIN) INSTALL_NAME_DIR "@executable_path/../Resources" ) endif (DARWIN) + +add_dependencies(llcommon stage_third_party_libs) diff --git a/indra/llcommon/aialert.cpp b/indra/llcommon/aialert.cpp new file mode 100644 index 0000000000..587a206bc1 --- /dev/null +++ b/indra/llcommon/aialert.cpp @@ -0,0 +1,82 @@ +/** + * @file aialert.cpp + * + * Copyright (c) 2013, Aleric Inglewood. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution. + * + * CHANGELOG + * and additional copyright holders. + * + * 02/11/2013 + * - Initial version, written by Aleric Inglewood @ SL + * + * 05/11/2013 + * Moved everything in namespace AIAlert, except AIArgs. + */ + +#include "aialert.h" + +namespace AIAlert +{ + +Error::Error(Prefix const& prefix, modal_nt type, + Error const& alert) : mLines(alert.mLines), mModal(type) +{ + if (alert.mModal == modal) mModal = modal; + if (prefix) mLines.push_front(Line(prefix)); +} + +Error::Error(Prefix const& prefix, modal_nt type, + std::string const& xml_desc, AIArgs const& args) : mModal(type) +{ + if (prefix) mLines.push_back(Line(prefix)); + mLines.push_back(Line(xml_desc, args)); +} + +Error::Error(Prefix const& prefix, modal_nt type, + Error const& alert, + std::string const& xml_desc, AIArgs const& args) : mLines(alert.mLines), mModal(type) +{ + if (alert.mModal == modal) mModal = modal; + if (prefix) mLines.push_back(Line(prefix, !mLines.empty())); + mLines.push_back(Line(xml_desc, args)); +} + +Error::Error(Prefix const& prefix, modal_nt type, + std::string const& xml_desc, + Error const& alert) : mLines(alert.mLines), mModal(type) +{ + if (alert.mModal == modal) mModal = modal; + if (!mLines.empty()) { mLines.front().set_newline(); } + mLines.push_front(Line(xml_desc)); + if (prefix) mLines.push_front(Line(prefix)); +} + +Error::Error(Prefix const& prefix, modal_nt type, + std::string const& xml_desc, AIArgs const& args, + Error const& alert) : mLines(alert.mLines), mModal(type) +{ + if (alert.mModal == modal) mModal = modal; + if (!mLines.empty()) { mLines.front().set_newline(); } + mLines.push_front(Line(xml_desc, args)); + if (prefix) mLines.push_front(Line(prefix)); +} + +} // namespace AIAlert + diff --git a/indra/llcommon/aialert.h b/indra/llcommon/aialert.h new file mode 100644 index 0000000000..17042cfcc3 --- /dev/null +++ b/indra/llcommon/aialert.h @@ -0,0 +1,306 @@ +/** + * @file aialert.h + * @brief Declaration of AIArgs and AIAlert classes. + * + * Copyright (c) 2013, Aleric Inglewood. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution. + * + * CHANGELOG + * and additional copyright holders. + * + * 02/11/2013 + * Initial version, written by Aleric Inglewood @ SL + * + * 05/11/2013 + * Moved everything in namespace AIAlert, except AIArgs. + */ + +#ifndef AI_ALERT +#define AI_ALERT + +#include "llpreprocessor.h" +#include "llstring.h" +#include +#include + +//=================================================================================================================================== +// Facility to throw errors that can easily be converted to an informative pop-up floater for the user. + +// Throw arbitrary class. +#define THROW_ALERT_CLASS(Alert, ...) throw Alert(AIAlert::Prefix(), AIAlert::not_modal, __VA_ARGS__) +#define THROW_MALERT_CLASS(Alert, ...) throw Alert(AIAlert::Prefix(), AIAlert::modal, __VA_ARGS__) +#ifdef __GNUC__ +#define THROW_FALERT_CLASS(Alert, ...) throw Alert(AIAlert::Prefix(__PRETTY_FUNCTION__, AIAlert::pretty_function_prefix), AIAlert::not_modal, __VA_ARGS__) +#define THROW_FMALERT_CLASS(Alert, ...) throw Alert(AIAlert::Prefix(__PRETTY_FUNCTION__, AIAlert::pretty_function_prefix), AIAlert::modal, __VA_ARGS__) +#else +#define THROW_FALERT_CLASS(Alert, ...) throw Alert(AIAlert::Prefix(__FUNCTION__, AIAlert::pretty_function_prefix), AIAlert::not_modal, __VA_ARGS__) +#define THROW_FMALERT_CLASS(Alert, ...) throw Alert(AIAlert::Prefix(__FUNCTION__, AIAlert::pretty_function_prefix), AIAlert::modal, __VA_ARGS__) +#endif + +// Shortcut to throw AIAlert::Error. +#define THROW_ALERT(...) THROW_ALERT_CLASS(AIAlert::Error, __VA_ARGS__) +#define THROW_MALERT(...) THROW_MALERT_CLASS(AIAlert::Error, __VA_ARGS__) +#define THROW_FALERT(...) THROW_FALERT_CLASS(AIAlert::Error, __VA_ARGS__) +#define THROW_FMALERT(...) THROW_FMALERT_CLASS(AIAlert::Error, __VA_ARGS__) + +// Shortcut to throw AIAlert::ErrorCode. +#define THROW_ALERTC(...) THROW_ALERT_CLASS(AIAlert::ErrorCode, __VA_ARGS__) +#define THROW_MALERTC(...) THROW_MALERT_CLASS(AIAlert::ErrorCode, __VA_ARGS__) +#define THROW_FALERTC(...) THROW_FALERT_CLASS(AIAlert::ErrorCode, __VA_ARGS__) +#define THROW_FMALERTC(...) THROW_FMALERT_CLASS(AIAlert::ErrorCode, __VA_ARGS__) + +// Shortcut to throw AIAlert::ErrorCode with errno as code. +#define THROW_ALERTE(...) do { int errn = errno; THROW_ALERT_CLASS(AIAlert::ErrorCode, errn, __VA_ARGS__); } while(0) +#define THROW_MALERTE(...) do { int errn = errno; THROW_MALERT_CLASS(AIAlert::ErrorCode, errn, __VA_ARGS__); } while(0) +#define THROW_FALERTE(...) do { int errn = errno; THROW_FALERT_CLASS(AIAlert::ErrorCode, errn, __VA_ARGS__); } while(0) +#define THROW_FMALERTE(...) do { int errn = errno; THROW_FMALERT_CLASS(AIAlert::ErrorCode, errn, __VA_ARGS__); } while(0) + +// Examples + +#ifdef EXAMPLE_CODE + + //---------------------------------------------------------- + // To show the alert box: + + catch (AIAlert::Error const& error) + { + AIAlert::add(error); // Optionally pass pretty_function_prefix as second parameter to *suppress* that output. + } + + // or, for example + + catch (AIAlert::ErrorCode const& error) + { + if (error.getCode() != EEXIST) + { + AIAlert::add(alert, AIAlert::pretty_function_prefix); + } + } + //---------------------------------------------------------- + // To throw alerts: + + THROW_ALERT("ExampleKey"); // A) Lookup "ExampleKey" in strings.xml and show translation. + THROW_ALERT("ExampleKey", AIArgs("[FIRST]", first)("[SECOND]", second)(...etc...)); // B) Same as A, but replace [FIRST] with first, [SECOND] with second, etc. + THROW_ALERT("ExampleKey", error); // C) As A, but followed by a colon and a newline, and then the text of 'error'. + THROW_ALERT(error, "ExampleKey"); // D) The text of 'error', followed by a colon and a newline and then as A. + THROW_ALERT("ExampleKey", AIArgs("[FIRST]", first)("[SECOND]", second), error); // E) As B, but followed by a colon and a newline, and then the text of 'error'. + THROW_ALERT(error, "ExampleKey", AIArgs("[FIRST]", first)("[SECOND]", second)); // F) The text of 'error', followed by a colon and a newline and then as B. + // where 'error' is a caught Error object (as above) in a rethrow. + // Prepend ALERT with M and/or F to make the alert box Modal and/or prepend the text with the current function name. + // For example, + THROW_MFALERT("ExampleKey", AIArgs("[FIRST]", first)); // Throw a Modal alert box that is prefixed with the current Function name. + // Append E after ALERT to throw an ErrorCode class that contains the current errno. + // For example, + THROW_FALERTE("ExampleKey", AIArgs("[FIRST]", first)); // Throw an alert box that is prefixed with the current Function name and pass errno to the catcher. + +#endif // EXAMPLE_CODE + +// +//=================================================================================================================================== + +// A wrapper around LLStringUtil::format_map_t to allow constructing a dictionary +// on one line by doing: +// +// AIArgs("[ARG1]", arg1)("[ARG2]", arg2)("[ARG3]", arg3)... + +class LL_COMMON_API AIArgs +{ + private: + LLStringUtil::format_map_t mArgs; // The underlying replacement map. + + public: + // Construct an empty map. + AIArgs(void) { } + // Construct a map with a single replacement. + AIArgs(char const* key, std::string const& replacement) { mArgs[key] = replacement; } + // Add another replacement. + AIArgs& operator()(char const* key, std::string const& replacement) { mArgs[key] = replacement; return *this; } + // The destructor may not throw. + ~AIArgs() noexcept { } + + // Accessor. + LLStringUtil::format_map_t const& operator*() const { return mArgs; } +}; + +namespace AIAlert +{ + +enum modal_nt +{ + not_modal, + modal +}; + +enum alert_line_type_nt +{ + normal = 0, + empty_prefix = 1, + pretty_function_prefix = 2 + // These must exist of single bits (a mask). +}; + +// An Prefix currently comes only in two flavors: +// +// empty_prefix : An empty prefix. +// pretty_function_prefix : A function name prefix, this is the function from which the alert was thrown. + +class LL_COMMON_API Prefix +{ + public: + Prefix(void) : mType(empty_prefix) { } + Prefix(char const* str, alert_line_type_nt type) : mStr(str), mType(type) { } + + operator bool(void) const { return mType != empty_prefix; } + alert_line_type_nt type(void) const { return mType; } + std::string const& str(void) const { return mStr; } + + private: + std::string mStr; // Literal text. For example a C++ function name. + alert_line_type_nt mType; // The type of this prefix. +}; + +// A class that represents one line with its replacements. +// The string mXmlDesc shall be looked up in strings.xml. +// This is not done as part of this class because LLTrans::getString +// is not part of llcommon. + +class LL_COMMON_API Line +{ + private: + bool mNewline; // Prepend this line with a newline if set. + std::string mXmlDesc; // The keyword to look up in string.xml. + AIArgs mArgs; // Replacement map. + alert_line_type_nt mType; // The type of this line: normal for normal lines, other for prefixes. + + public: + Line(std::string const& xml_desc, bool newline = false) : mNewline(newline), mXmlDesc(xml_desc), mType(normal) { } + Line(std::string const& xml_desc, AIArgs const& args, bool newline = false) : mNewline(newline), mXmlDesc(xml_desc), mArgs(args), mType(normal) { } + Line(Prefix const& prefix, bool newline = false) : mNewline(newline), mXmlDesc("AIPrefix"), mArgs("[PREFIX]", prefix.str()), mType(prefix.type()) { } + // The destructor may not throw. + ~Line() noexcept { } + + // Prepend a newline before this line. + void set_newline(void) { mNewline = true; } + + // These are to be used like: LLTrans::getString(line.getXmlDesc(), line.args()) and prepend with a \n if prepend_newline() returns true. + std::string getXmlDesc(void) const { return mXmlDesc; } + LLStringUtil::format_map_t const& args(void) const { return *mArgs; } + bool prepend_newline(void) const { return mNewline; } + + // Accessors. + bool suppressed(unsigned int suppress_mask) const { return (suppress_mask & mType) != 0; } + bool is_prefix(void) const { return mType != normal; } +}; + +// This class is used to throw an error that will cause +// an alert box to pop up for the user. +// +// An alert box only has text and an OK button. +// The alert box does not give feed back to the program; it is purely informational. + +// The class represents multiple lines, each line is to be translated and catenated, +// separated by newlines, and then written to an alert box. This is not done as part +// of this class because LLTrans::getString and LLNotification is not part of llcommon. +// Instead call LLNotificationUtil::add(Error const&). + +class LL_COMMON_API Error : public std::exception +{ + public: + typedef std::deque lines_type; + + // The destructor may not throw. + ~Error() noexcept { } + + // Accessors. + lines_type const& lines(void) const { return mLines; } + bool is_modal(void) const { return mModal == modal; } + + // Existing alert, just add a prefix and turn alert into modal if appropriate. + Error(Prefix const& prefix, modal_nt type, Error const& alert); + + // A string with zero or more replacements. + Error(Prefix const& prefix, modal_nt type, + std::string const& xml_desc, AIArgs const& args = AIArgs()); + + // Same as above bit prepending the message with the text of another alert. + Error(Prefix const& prefix, modal_nt type, + Error const& alert, + std::string const& xml_desc, AIArgs const& args = AIArgs()); + + // Same as above but appending the message with the text of another alert. + // (no args) + Error(Prefix const& prefix, modal_nt type, + std::string const& xml_desc, + Error const& alert); + // (with args) + Error(Prefix const& prefix, modal_nt type, + std::string const& xml_desc, AIArgs const& args, + Error const& alert); + + private: + lines_type mLines; // The lines (or prefixes) of text to be displayed, each consisting on a keyword (to be looked up in strings.xml) and a replacement map. + modal_nt mModal; // If true, make the alert box a modal floater. +}; + +// Same as Error but allows to pass an additional error code. + +class LL_COMMON_API ErrorCode : public Error +{ + private: + int mCode; + + public: + // The destructor may not throw. + ~ErrorCode() noexcept { } + + // Accessor. + int getCode(void) const { return mCode; } + + // Just an Error with a code. + ErrorCode(Prefix const& prefix, modal_nt type, int code, + Error const& alert) : + Error(prefix, type, alert), mCode(code) { } + + // A string with zero or more replacements. + ErrorCode(Prefix const& prefix, modal_nt type, int code, + std::string const& xml_desc, AIArgs const& args = AIArgs()) : + Error(prefix, type, xml_desc, args), mCode(code) { } + + // Same as above bit prepending the message with the text of another alert. + ErrorCode(Prefix const& prefix, modal_nt type, int code, + Error const& alert, + std::string const& xml_desc, AIArgs const& args = AIArgs()) : + Error(prefix, type, alert, xml_desc, args), mCode(code) { } + + // Same as above but appending the message with the text of another alert. + // (no args) + ErrorCode(Prefix const& prefix, modal_nt type, int code, + std::string const& xml_desc, + Error const& alert) : + Error(prefix, type, xml_desc, alert), mCode(code) { } + // (with args) + ErrorCode(Prefix const& prefix, modal_nt type, int code, + std::string const& xml_desc, AIArgs const& args, + Error const& alert) : + Error(prefix, type, xml_desc, args, alert), mCode(code) { } +}; + +} // namespace AIAlert + +#endif // AI_ALERT diff --git a/indra/llcommon/aiframetimer.cpp b/indra/llcommon/aiframetimer.cpp index 3c102a9c7b..4e5c104c1b 100644 --- a/indra/llcommon/aiframetimer.cpp +++ b/indra/llcommon/aiframetimer.cpp @@ -65,7 +65,7 @@ static F64 const NEVER = 1e16; // 317 million years. F64 AIFrameTimer::sNextExpiration; AIFrameTimer::timer_list_type AIFrameTimer::sTimerList; -LLMutex AIFrameTimer::sMutex; +LLGlobalMutex AIFrameTimer::sMutex; // Notes on thread-safety of AIRunningFrameTimer (continued from aiframetimer.h) // @@ -80,11 +80,10 @@ LLMutex AIFrameTimer::sMutex; void AIFrameTimer::create(F64 expiration, signal_type::slot_type const& slot) { AIRunningFrameTimer new_timer(expiration, this); - sMutex.lock(); + LLMutexLock lock(sMutex); llassert(mHandle.mRunningTimer == sTimerList.end()); // Create may only be called when the timer isn't already running. mHandle.init(sTimerList.insert(new_timer), slot); sNextExpiration = sTimerList.begin()->expiration(); - sMutex.unlock(); } void AIFrameTimer::cancel(void) @@ -95,18 +94,19 @@ void AIFrameTimer::cancel(void) // mHandle.mMutex lock), we start with trying to obtain // it here and as such wait till the callback function // returned. - mHandle.mMutex.lock(); + mHandle.mMutex.lock(); // Next we have to grab this lock in order to stop // AIFrameTimer::handleExpiration from even entering // in the case we manage to get it first. - sMutex.lock(); - if (mHandle.mRunningTimer != sTimerList.end()) { - sTimerList.erase(mHandle.mRunningTimer); - mHandle.mRunningTimer = sTimerList.end(); - sNextExpiration = sTimerList.empty() ? NEVER : sTimerList.begin()->expiration(); + LLMutexLock lock(sMutex); + if (mHandle.mRunningTimer != sTimerList.end()) + { + sTimerList.erase(mHandle.mRunningTimer); + mHandle.mRunningTimer = sTimerList.end(); + sNextExpiration = sTimerList.empty() ? NEVER : sTimerList.begin()->expiration(); + } } - sMutex.unlock(); mHandle.mMutex.unlock(); } @@ -164,7 +164,7 @@ void AIFrameTimer::handleExpiration(F64 current_frame_time) // // Note that if the other thread actually obtained the sMutex then we // can't be here: this is still inside the critical area of sMutex. - if (handle.mMutex.tryLock()) // If this fails then another thread is in the process of cancelling this timer, so do nothing. + if (handle.mMutex.try_lock()) // If this fails then another thread is in the process of cancelling this timer, so do nothing. { sMutex.unlock(); running_timer->do_callback(); // May not throw exceptions. diff --git a/indra/llcommon/aiframetimer.h b/indra/llcommon/aiframetimer.h index 366581c496..880b492ee5 100644 --- a/indra/llcommon/aiframetimer.h +++ b/indra/llcommon/aiframetimer.h @@ -96,7 +96,7 @@ class LL_COMMON_API AIFrameTimer typedef std::multiset timer_list_type; - static LLMutex sMutex; // Mutex for the two global variables below. + static LLGlobalMutex sMutex; // Mutex for the two global variables below. static timer_list_type sTimerList; // List with all running timers. static F64 sNextExpiration; // Cache of smallest value in sTimerList. friend class LLFrameTimer; // Access to sNextExpiration. diff --git a/indra/llcommon/aisyncclient.cpp b/indra/llcommon/aisyncclient.cpp new file mode 100644 index 0000000000..191a2627d4 --- /dev/null +++ b/indra/llcommon/aisyncclient.cpp @@ -0,0 +1,698 @@ +/** + * @file aisyncclient.cpp + * + * Copyright (c) 2013, Aleric Inglewood. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution. + * + * CHANGELOG + * and additional copyright holders. + * + * 13/12/2013 + * - Initial version, written by Aleric Inglewood @ SL + */ + +/* + * AISyncClient : the base class of a client object (LLMotion) that needs to be informed + * of the state of other such objects and/or to poll a server object about the state of + * other such objects, in order to be and stay synchronized with those other objects. + * In the case of an LLMotion (animation), all clients would be started and stopped at + * the same time, as long as they are part of the same synchronization group (AISyncServer). + * + * AISyncKey: object that determines what synchronization group a client belongs to. + * When a new client is created, a new AISyncKey is created too, using information from + * the client, the current frame number and the current frame time. If two AISyncKey + * compare equal, using operator==(AISyncKey const& key1, AISyncKey const& key2), + * then the clients that created them need to be synchronized. + * + * AISyncServer: object that represents a group of clients that need to be synchronized: + * it's a wrapper around a std::list with pointers to all the clients + * that need to be synchronized. It also stores the AISyncKey of the first (oldest) client + * that was added. Clients with keys that compare equal to that will be added. + * If a client is added with a synckeytype_t that is larger then it always replaces + * the existing key however. + * + * AISyncServerMap: A wrapper around std::list > + * that stores pointers to all currently existing AISyncServer objects. New entries + * are added at the end, so the oldest key is at the front. + * + * AISyncServerMap list + - - - - - - + - - - - - - + ... The AISyncServerMap is + * | | | a list with refcounted + * V V V pointers to AISyncServers. + * AISyncClient +--> AISyncServer + * | <--- list key ---> AISyncKey Each AISyncServer is a + * DerivedClient . list of normal pointers + * . AISyncClients and one + * <--- . pointer to a AISyncKey. + * Each AISyncClient is the + * base class of a DerivedClient + * and pointers back to the + * server with a refcounted + * pointer. + * + * A new client is passed to the AISyncServerMap to be stored in a new or existing AISyncServer + * object, using the key that the client produces. A boost::intrusive_ptr member + * of the client is set to point to this server. + * + * The lifetime of the server objects is determined by the intrusive_ptr objects that + * point to it: all the clients (which have an externally determined lifetime) and one + * pointer in the AISyncServerMap. However, regularly a check is done on all servers in + * the list to find expired servers: objects with keys older than two frames and older + * than 0.1 seconds; if such a server is found and it has zero or one client, then the + * client is unregistered and the pointer (and thus the server) removed from the + * AISyncServerMap. If it has two or more clients then the entry is kept until both + * clients are removed, which therefore can only be detected in intrusive_ptr_release + * which only has access to the server object. The server then is removed from the list + * by searching through it for the pointer to the server. + */ + +#include "sys.h" +#include "aisyncclient.h" +#include +#include +#include "debug.h" + +bool operator==(AISyncKey const& key1, AISyncKey const& key2) +{ + // Test if these keys match based on time. + if (std::abs((S64)(key1.mStartFrameCount - key2.mStartFrameCount)) > 1 && + std::abs(key1.mFrameTimer.getStartTime() - key2.mFrameTimer.getStartTime()) >= sSyncKeyExpirationTime) + { + return false; + } + // Time matches, let the derived classes determine if they also match otherwise. + return key1.equals(key2); +} + +#ifdef CWDEBUG +struct SyncEventSet { + synceventset_t mBits; + SyncEventSet(synceventset_t bits) : mBits(bits) { } +}; + +std::ostream& operator<<(std::ostream& os, SyncEventSet const& ses) +{ + for (int b = sizeof(ses.mBits) * 8 - 1; b >= 0; --b) + { + int m = 1 << b; + os << ((ses.mBits & m) ? '1' : '0'); + } + return os; +} + +void print_clients(AISyncServer const* server, AISyncServer::client_list_t const& client_list) +{ + Dout(dc::notice, "Clients of server " << server << ": "); + for (AISyncServer::client_list_t::const_iterator iter = client_list.begin(); iter != client_list.end(); ++ iter) + { + llassert(iter->mClientPtr->mReadyEvents == iter->mReadyEvents); + Dout(dc::notice, "-> " << iter->mClientPtr << " : " << SyncEventSet(iter->mReadyEvents)); + } +} +#endif + +void AISyncServerMap::register_client(AISyncClient* client, AISyncKey* new_key) +{ + // client must always be a new client that has to be stored somewhere. + llassert(client->server() == NULL); + // Obviously the client can't be ready for anything when it isn't registered yet. + llassert(!client->mReadyEvents); + + // Find if a server with this key already exists. + AISyncServer* server = NULL; + for (server_list_t::iterator iter = mServers.begin(); iter != mServers.end();) + { + boost::intrusive_ptr& server_ptr = *iter++; // Immediately increment iter because the call to unregister_last_client will erase it. + AISyncKey const& server_key(server_ptr->key()); + if (server_key.is_older_than(*new_key)) // This means that the server key is expired: a new key will never match. + { + if (server_ptr->never_synced()) // This means that it contains one or zero clients and will never contain more. + { + // Get rid of this server. + server_ptr->unregister_last_client(); // This will cause the server to be deleted, and erased from mServers. + } + continue; + } + if (*new_key == server_key) + { + server = server_ptr.get(); + // mServers stores new servers in strict order of the creation time of the keys, + // so once we find a server with a key that is equal, none of the remaining servers + // will have expired if they were never synced and we're done with the loop. + // Servers that synced might have been added later, but we don't unregister + // clients from those anyway because their sync partner might still show up. + break; + } + } + + if (server) + { + // A server already exists. + // Keep the oldest key, unless this new key has a synckeytype_t that is larger! + if (new_key->getkeytype() > server->key().getkeytype()) + { + server->swapkey(new_key); + } + delete new_key; + } + else + { + // Create a new server for this client. Transfers the ownership of the key allocation to the server. + server = new AISyncServer(new_key); + // Add it to mServers, before the last server that is younger then the new key. + server_list_t::iterator where = mServers.end(); // Insert the new server before 'where', + server_list_t::iterator new_where = where; + while (where != mServers.begin()) // unless there exists a server before that + { + --new_where; + if (new_key->getCreationTime() > (*new_where)->key().getCreationTime()) // and the new key is not younger then that, + { + break; + } + where = new_where; // then insert it before that element (etc). + } + // This method causes a single call to intrusive_ptr_add_ref and none to intrusive_ptr_release. + server_ptr_t server_ptr = server; + mServers.insert(where, server_ptr_t())->swap(server_ptr); + } + + // Add the client to the server. + server->add(client); +} + +#ifdef SYNC_TESTSUITE +void AISyncServer::sanity_check(void) const +{ + synceventset_t ready_events = (synceventset_t)-1; // All clients are ready. + client_list_t::const_iterator client_iter = mClients.begin(); + while (client_iter != mClients.end()) + { + ready_events &= client_iter->mReadyEvents; + ++client_iter; + } + synceventset_t pending_events = 0; // At least one client is ready. + client_iter = mClients.begin(); + while (client_iter != mClients.end()) + { + pending_events |= client_iter->mReadyEvents; + ++client_iter; + } + llassert(ready_events == mReadyEvents); + llassert(pending_events == mPendingEvents); +} +#endif + +void AISyncServer::add(AISyncClient* client) +{ +#ifdef SYNC_TESTSUITE + sanity_check(); +#endif + + // The client can't already be ready when it isn't even added to a server yet. + llassert(!client->mReadyEvents); + synceventset_t old_ready_events = mReadyEvents; + // A new client is not ready for anything. + mReadyEvents = 0; + // Set mSynchronized if after adding client we'll have more than 1 client (that prevents the + // server from being deleted unless all clients are actually destructed or explicitly unregistered). + if (!mSynchronized && mClients.size() > 0) + { + mSynchronized = true; + } + // Trigger the existing clients to be not-ready anymore (if we were before). + trigger(old_ready_events); + // Only then add the new client (so that it didn't get not-ready trigger). + mClients.push_back(client); + client->mServer = this; + +#ifdef SYNC_TESTSUITE + sanity_check(); +#endif +} + +void AISyncServer::remove(AISyncClient* client) +{ +#ifdef SYNC_TESTSUITE + sanity_check(); +#endif + + client_list_t::iterator client_iter = mClients.begin(); + synceventset_t remaining_ready_events = (synceventset_t)-1; // All clients are ready. + synceventset_t remaining_pending_events = 0; // At least one client is ready (waiting for the other clients thus). + client_list_t::iterator found_client = mClients.end(); + while (client_iter != mClients.end()) + { + if (client_iter->mClientPtr == client) + { + found_client = client_iter; + } + else + { + remaining_ready_events &= client_iter->mReadyEvents; + remaining_pending_events |= client_iter->mReadyEvents; + } + ++client_iter; + } + llassert(found_client != mClients.end()); + // This must be the same as client->mReadyEvents. + llassert(found_client->mReadyEvents == client->mReadyEvents); + mClients.erase(found_client); + synceventset_t old_ready_events = mReadyEvents; + mReadyEvents = remaining_ready_events; + mPendingEvents = remaining_pending_events; + trigger(old_ready_events); + client->mServer.reset(); + client->deregistered(); + +#ifdef SYNC_TESTSUITE + sanity_check(); +#endif +} + +void AISyncServer::unregister_last_client(void) +{ +#ifdef SYNC_TESTSUITE + sanity_check(); +#endif + + // This function may only be called for servers with exactly one client that was never (potentially) synchronized. + llassert(!mSynchronized && mClients.size() == 1); + AISyncClient* client = mClients.begin()->mClientPtr; + mClients.clear(); + client->mServer.reset(); + llassert(mReadyEvents == client->mReadyEvents); + llassert(mPendingEvents == mReadyEvents); + // No need to update mReadyEvents/mPendingEvents because the server is going to be deleted, + // but inform the client that is no longer has a server. + client->deregistered(); + +#ifdef SYNC_TESTSUITE + sanity_check(); +#endif +} + +void AISyncServer::trigger(synceventset_t old_ready_events) +{ + // If event 1 changed, informat all clients about it. + if (((old_ready_events ^ mReadyEvents) & 1)) + { + for (client_list_t::iterator client_iter = mClients.begin(); client_iter != mClients.end(); ++client_iter) + { + if ((mReadyEvents & 1)) + { + client_iter->mClientPtr->event1_ready(); + } + else + { + client_iter->mClientPtr->event1_not_ready(); + } + } + } +} + +void AISyncServer::ready(synceventset_t events, synceventset_t yesno, AISyncClient* client) +{ +#ifdef SYNC_TESTSUITE + sanity_check(); +#endif + + synceventset_t added_events = events & yesno; + synceventset_t removed_events = events & ~yesno; + + // Run over all clients to find the client and calculate the current state. + synceventset_t remaining_ready_events = (synceventset_t)-1; // All clients are ready. + synceventset_t remaining_pending_events = 0; // At least one client is ready (waiting for the other clients thus). + client_list_t::iterator found_client = mClients.end(); + for (client_list_t::iterator client_iter = mClients.begin(); client_iter != mClients.end(); ++client_iter) + { + if (client_iter->mClientPtr == client) + { + found_client = client_iter; + } + else + { + remaining_ready_events &= client_iter->mReadyEvents; + remaining_pending_events |= client_iter->mReadyEvents; + } + } + + llassert(mReadyEvents == (remaining_ready_events & found_client->mReadyEvents)); + llassert(mPendingEvents == (remaining_pending_events | found_client->mReadyEvents)); + + found_client->mReadyEvents &= ~removed_events; + found_client->mReadyEvents |= added_events; +#ifdef SHOW_ASSERT + client->mReadyEvents = found_client->mReadyEvents; +#endif + + synceventset_t old_ready_events = mReadyEvents; + + mReadyEvents = remaining_ready_events & found_client->mReadyEvents; + mPendingEvents = remaining_pending_events | found_client->mReadyEvents; + + trigger(old_ready_events); + +#ifdef SYNC_TESTSUITE + sanity_check(); +#endif +} + +void intrusive_ptr_add_ref(AISyncServer* server) +{ + server->mRefCount++; +} + +void intrusive_ptr_release(AISyncServer* server) +{ + llassert(server->mRefCount > 0); + server->mRefCount--; + if (server->mRefCount == 0) + { + delete server; + } + else if (server->mRefCount == 1) + { + // If the the last pointer to this server is in the the AISyncServerMap, then delete that too. + AISyncServerMap::instance().remove_server(server); + } +} + +void AISyncServerMap::remove_server(AISyncServer* server) +{ + for (server_list_t::iterator iter = mServers.begin(); iter != mServers.end(); ++iter) + { + if (server == iter->get()) + { + mServers.erase(iter); // This causes server to be deleted too. + return; + } + } + // The server must be found: this function is only called from intrusive_ptr_release for servers + // with just a single server_ptr_t left, which must be the one in mServers (otherwise it wasn't + // even registered properly!) + llassert(false); +} + + +//============================================================================= +// SYNC_TESTSUITE +//============================================================================= + +#ifdef SYNC_TESTSUITE +#include +#include +#include +#include + +//static +U64 LLFrameTimer::sFrameCount; + +double innerloop_count = 0; + +double LLFrameTimer::getCurrentTime() +{ + return innerloop_count * 0.001; +} + +template +class TestsuiteKey : public AISyncKey +{ + private: + int mIndex; + + public: + TestsuiteKey(int index) : mIndex(index) { } + + int getIndex(void) const { return mIndex; } + + // Virtual functions of AISyncKey. + public: + /*virtual*/ synckeytype_t getkeytype(void) const + { + // Return a unique identifier for this class, where the low 8 bits represent the syncgroup. + return synckeytype; + } + + /*virtual*/ bool equals(AISyncKey const& key) const + { + synckeytype_t const theotherkey = (synckeytype_t)(synckeytype ^ 0x100); + switch (key.getkeytype()) + { + case synckeytype: + { + // The other key is of the same type. + TestsuiteKey const& test_key = static_cast const&>(key); + return (mIndex & 1) == (test_key.mIndex & 1); + } + case theotherkey: + { + TestsuiteKey const& test_key = static_cast const&>(key); + return (mIndex & 2) == (test_key.getIndex() & 2); + } + default: + // The keys must be in the same syncgroup. + break; + } + return false; + } +}; + +template +class TestsuiteClient : public AISyncClient +{ + // AISyncClient events. + protected: + /*virtual*/ AISyncKey* createSyncKey(void) const + { + return new TestsuiteKey(mIndex); + } + + private: + int mIndex; + bool mRequestedRegistered; + synceventset_t mRequestedReady; + bool mActualReady1; + + public: + TestsuiteClient() : mIndex(-1), mRequestedRegistered(false), mRequestedReady(0), mActualReady1(false) { } + ~TestsuiteClient() { if (is_registered()) this->ready(mRequestedReady, (synceventset_t)0); } + + void setIndex(int index) { mIndex = index; } + + protected: + /*virtual*/ void event1_ready(void) + { +#ifdef DEBUG_SYNCOUTPUT + Dout(dc::notice, "Calling TestsuiteClient<" << synckeytype << ">::event1_ready() (mIndex = " << mIndex << ") of client " << this); +#endif + llassert(!mActualReady1); + mActualReady1 = true; + } + + /*virtual*/ void event1_not_ready(void) + { +#ifdef DEBUG_SYNCOUTPUT + Dout(dc::notice, "Calling TestsuiteClient<" << synckeytype << ">::event1_not_ready() (mIndex = " << mIndex << ") of client " << this); +#endif + llassert(mActualReady1); + mActualReady1 = false; + } + + // This is called when the server expired and we're the only client on it. + /*virtual*/ void deregistered(void) + { +#ifdef DEBUG_SYNCOUTPUT + DoutEntering(dc::notice, "TestsuiteClient<" << synckeytype << ">::deregistered(), with this = " << this); +#endif + mRequestedRegistered = false; + mRequestedReady = 0; + mActualReady1 = false; + this->mReadyEvents = 0; + } + + private: + bool is_registered(void) const { return this->server(); } + + public: + void change_state(unsigned long r); + bool getRequestedRegistered(void) const { return mRequestedRegistered; } + synceventset_t getRequestedReady(void) const { return mRequestedReady; } +}; + +TestsuiteClient* client1ap; +TestsuiteClient* client1bp; +TestsuiteClient* client2ap; +TestsuiteClient* client2bp; + +int const number_of_clients_per_syncgroup = 8; + +template +void TestsuiteClient::change_state(unsigned long r) +{ + bool change_registered = r & 1; + r >>= 1; + synceventset_t toggle_events = r & 15; + r >>= 4; + if (change_registered) + { + if (mRequestedRegistered && !mRequestedReady) + { + mRequestedRegistered = false; + this->unregister_client(); + } + } + else if (toggle_events) + { + mRequestedReady ^= toggle_events; + mRequestedRegistered = true; + this->ready(toggle_events, mRequestedReady & toggle_events); + } + llassert(mRequestedRegistered == is_registered()); + AISyncServer* server = this->server(); + if (mRequestedRegistered) + { + synceventset_t all_ready = synceventset_t(-1); + synceventset_t any_ready = 0; + int nr = 0; + for (int cl = 0; cl < number_of_clients_per_syncgroup; ++cl) + { + switch ((synckeytype & 0xff)) + { + case syncgroup_test1: + { + if (client1ap[cl].server() == server) + { + if (client1ap[cl].getRequestedRegistered()) + { + ++nr; + all_ready &= client1ap[cl].getRequestedReady(); + any_ready |= client1ap[cl].getRequestedReady(); + } + } + if (client1bp[cl].server() == server) + { + if (client1bp[cl].getRequestedRegistered()) + { + ++nr; + all_ready &= client1bp[cl].getRequestedReady(); + any_ready |= client1bp[cl].getRequestedReady(); + } + } + break; + } + case syncgroup_test2: + { + if (client2ap[cl].server() == server) + { + if (client2ap[cl].getRequestedRegistered()) + { + ++nr; + all_ready &= client2ap[cl].getRequestedReady(); + any_ready |= client2ap[cl].getRequestedReady(); + } + } + if (client2bp[cl].server() == server) + { + if (client2bp[cl].getRequestedRegistered()) + { + ++nr; + all_ready &= client2bp[cl].getRequestedReady(); + any_ready |= client2bp[cl].getRequestedReady(); + } + } + break; + } + } + } + llassert(nr == server->getClients().size()); + llassert(!!(all_ready & 1) == mActualReady1); + llassert(this->server()->events_with_all_clients_ready() == all_ready); + llassert(this->server()->events_with_at_least_one_client_ready() == any_ready); + llassert(nr == 0 || (any_ready & all_ready) == all_ready); + } + llassert(mRequestedReady == this->mReadyEvents); +} + +int main() +{ + Debug(libcw_do.on()); + Debug(dc::notice.on()); + Debug(libcw_do.set_ostream(&std::cout)); + Debug(list_channels_on(libcw_do)); + + unsigned short seed16v[3] = { 0x1234, 0xfedc, 0x7091 }; + + for (int k = 0;; ++k) + { + std::cout << "Loop: " << k << "; SEED: " << std::hex << seed16v[0] << ", " << seed16v[1] << ", " << seed16v[2] << std::dec << std::endl; + ++LLFrameTimer::sFrameCount; + + seed48(seed16v); + seed16v[0] = lrand48() & 0xffff; + seed16v[1] = lrand48() & 0xffff; + seed16v[2] = lrand48() & 0xffff; + + TestsuiteClient client1a[number_of_clients_per_syncgroup]; + TestsuiteClient client1b[number_of_clients_per_syncgroup]; + TestsuiteClient client2a[number_of_clients_per_syncgroup]; + TestsuiteClient client2b[number_of_clients_per_syncgroup]; + client1ap = client1a; + client1bp = client1b; + client2ap = client2a; + client2bp = client2b; + + for (int i = 0; i < number_of_clients_per_syncgroup; ++i) + { + client1a[i].setIndex(i); + client1b[i].setIndex(i); + client2a[i].setIndex(i); + client2b[i].setIndex(i); + } + + for (int j = 0; j < 1000000; ++j) + { + innerloop_count += 1; + +#ifdef DEBUG_SYNCOUTPUT + Dout(dc::notice, "Innerloop: " << j); +#endif + unsigned long r = lrand48(); + synckeytype_t keytype = (r & 1) ? ((r & 2) ? synckeytype_test1a : synckeytype_test1b) : ((r & 2) ? synckeytype_test2a : synckeytype_test2b); + r >>= 2; + int cl = (r & 255) % number_of_clients_per_syncgroup; + r >>= 8; + switch (keytype) + { + case synckeytype_test1a: + client1a[cl].change_state(r); + break; + case synckeytype_test1b: + client1b[cl].change_state(r); + break; + case synckeytype_test2a: + client2a[cl].change_state(r); + break; + case synckeytype_test2b: + client2b[cl].change_state(r); + break; + } + } + } +} + +#endif diff --git a/indra/llcommon/aisyncclient.h b/indra/llcommon/aisyncclient.h new file mode 100644 index 0000000000..eecad2924d --- /dev/null +++ b/indra/llcommon/aisyncclient.h @@ -0,0 +1,304 @@ +/** + * @file aisyncclient.h + * @brief Declaration of AISyncClient. + * + * Copyright (c) 2013, Aleric Inglewood. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution. + * + * CHANGELOG + * and additional copyright holders. + * + * 12/12/2013 + * Initial version, written by Aleric Inglewood @ SL + */ + +#ifndef AI_SYNC_CLIENT_H +#define AI_SYNC_CLIENT_H + +#ifdef SYNC_TESTSUITE +/* + * To compile the testsuite, run: + * + * cd indra/llcommon + * g++ -O3 -DCWDEBUG -DSYNC_TESTSUITE -I. -I../cwdebug aisyncclient.cpp -lcwd + */ + +#include +#include +typedef uint32_t U32; +typedef int32_t S32; +typedef uint64_t U64; +typedef float F32; +typedef double F64; +#define LL_COMMON_API +#define SHOW_ASSERT +#define ASSERT_ONLY_COMMA(...) , __VA_ARGS__ +#define llassert assert + +struct LLFrameTimer +{ + double mStartTime; + double mExpiry; + static double getCurrentTime(void); + static U64 sFrameCount; + static U64 getFrameCount() { return sFrameCount; } + F64 getStartTime() const { return mStartTime; } + void reset(double expiration) { mStartTime = getCurrentTime(); mExpiry = mStartTime + expiration; } + bool hasExpired(void) const { return getCurrentTime() > mExpiry; } +}; + +template +struct LLSingleton +{ + static T sInstance; + static T& instance(void) { return sInstance; } +}; + +template +T LLSingleton::sInstance; + +#else // !SYNC_TESTSUITE +#include "llsingleton.h" +#include "llframetimer.h" +#endif +#include +#include + +//--------------------------------------------------------------------------------------------------------------------- +// Keys with a different syncgroup are never equal (so they are never synchronized). +enum syncgroups +{ +#ifdef SYNC_TESTSUITE + syncgroup_test1, + syncgroup_test2, +#else + syncgroup_motions, // Syncgroup used for animations. +#endif + syncgroup_size +}; + +// Each key type must return a unique identifier that exists of its syncgroup (the least significant 8 bit) plus a few bit to make it unique (bit 9 and higher). +enum synckeytype_t +{ +#ifdef SYNC_TESTSUITE + synckeytype_test1a = 0x000 + syncgroup_test1, + synckeytype_test1b = 0x100 + syncgroup_test1, + synckeytype_test2a = 0x000 + syncgroup_test2, + synckeytype_test2b = 0x100 + syncgroup_test2, +#else + synckeytype_motion = syncgroup_motions // There is currently only one key type in the syncgroup_motions group: AISyncKeyMotion. +#endif +}; + +typedef U32 synceventset_t; // A mask where each bit represents a ready state. + +static F32 const sSyncKeyExpirationTime = 0.25; // In seconds. + +class LL_COMMON_API AISyncKey +{ + private: + LLFrameTimer mFrameTimer; // This timer is started at the moment the sync key is created. + U64 mStartFrameCount; // The frame count at which the timer was started. + + public: + // Constructor. + AISyncKey(AISyncKey const* from_key) : mStartFrameCount(from_key ? from_key->mStartFrameCount : LLFrameTimer::getFrameCount()) + { + if (from_key) + { + mFrameTimer.copy(from_key->mFrameTimer); + } + else + { + mFrameTimer.reset(sSyncKeyExpirationTime); + } + } + + // Destructor. + virtual ~AISyncKey() { } + + // Return true if this key expired. + bool expired(void) const + { + // The key has expired when sSyncKeyExpirationTime seconds have elapsed AND at least two frames have passed. + return mFrameTimer.getFrameCount() > mStartFrameCount + 1 && mFrameTimer.hasExpired(); + } + + // Returns true if this object and key would not compare equal based on time because this object is too old. + bool is_older_than(AISyncKey const& key) const + { + return key.mStartFrameCount > mStartFrameCount + 1 && key.mFrameTimer.getStartTime() > mFrameTimer.getStartTime() + sSyncKeyExpirationTime; + } + + // Return the creation time of this key (in number of seconds since application start). + F64 getCreationTime(void) const { return mFrameTimer.getStartTime(); } + + // Returns true if the two keys match, meaning that they should be synchronized. + friend bool operator==(AISyncKey const& key1, AISyncKey const& key2); + + // Returns an ID that uniquely identifies the derived type. + // Currently the only derived type is AISyncKeyMotion with ID synckeytype_motion. + virtual synckeytype_t getkeytype(void) const = 0; + + // Returns true if the data in the derived objects match, meaning that they should be synchronized. + virtual bool equals(AISyncKey const& key) const = 0; +}; + +// Forward declaration. +class AISyncClient; +class AISyncServer; +LL_COMMON_API extern void intrusive_ptr_add_ref(AISyncServer* server); +LL_COMMON_API extern void intrusive_ptr_release(AISyncServer* server); + +struct LL_COMMON_API AISyncClientData +{ + AISyncClient* mClientPtr; + synceventset_t mReadyEvents; + + AISyncClientData(AISyncClient* client) : mClientPtr(client), mReadyEvents(0) { } +}; + +class LL_COMMON_API AISyncServer +{ + public: + typedef std::list client_list_t; + + private: + int mRefCount; // Number of boost::intrusive_ptr objects pointing to this object. + AISyncKey* mKey; // The key of the first client that was added. + client_list_t mClients; // A list with pointers to all registered clients. + bool mSynchronized; // Set when a server gets more than one client, and not reset anymore after that. + synceventset_t mReadyEvents; // 0xFFFFFFFF bitwise-AND-ed with all clients. + synceventset_t mPendingEvents; // The bitwise-OR of all clients. + + public: + AISyncServer(AISyncKey* key) : mRefCount(0), mKey(key), mSynchronized(false), mReadyEvents((synceventset_t)-1), mPendingEvents(0) { } + ~AISyncServer() { delete mKey; } + + // Add a new client to this server. + void add(AISyncClient* client); + + // Remove a client from this server. + void remove(AISyncClient* client); + + // Return the key associated to this server (which is the key produced by the first client of the largest synckeytype_t that was added). + AISyncKey const& key(void) const { return *mKey; } + // Replace they key with another key (of larger synckeytype_t). + void swapkey(AISyncKey*& key_ptr) { AISyncKey* tmp = key_ptr; key_ptr = mKey; mKey = tmp; } + + // Returns true if this server never had more than one client. + bool never_synced(void) const { return !mSynchronized; } + + // Set readiness of all events at once. + void ready(synceventset_t events, synceventset_t yesno, AISyncClient* client); + + // Unregister the (only) client because it's own its own and will never need synchronization. + void unregister_last_client(void); + + // Return the events that all clients for. + synceventset_t events_with_all_clients_ready(void) const { return mReadyEvents; } + + // Return events that at least one client is ready for. + synceventset_t events_with_at_least_one_client_ready(void) const { return mPendingEvents; } + + // Return a list of all registered clients. + client_list_t const& getClients(void) const { return mClients; } + + private: + // Call event1_ready() or event1_not_ready() on all clients if the least significant bit of mReadyEvents changed. + void trigger(synceventset_t old_ready_events); + +#ifdef SYNC_TESTSUITE + void sanity_check(void) const; +#endif + + private: + friend LL_COMMON_API void intrusive_ptr_add_ref(AISyncServer* server); + friend LL_COMMON_API void intrusive_ptr_release(AISyncServer* server); +}; + +class LL_COMMON_API AISyncServerMap : public LLSingleton +{ + public: + typedef boost::intrusive_ptr server_ptr_t; // The type of a (stored) pointer to the server objects. + typedef std::list server_list_t; // The type of the list with pointers to the server objects. + + private: + server_list_t mServers; // A list with pointers to all server objects. + + public: + // Find or create a server object that the client belongs to and store the client in it. + // If a new server is created, it is stored in mServers. + void register_client(AISyncClient* client, AISyncKey* new_key); + + private: + friend LL_COMMON_API void intrusive_ptr_release(AISyncServer* server); + // Remove a server from the map, only called by intrusive_ptr_release when there is one pointer left; + // therefore, the server should not have any clients. + void remove_server(AISyncServer* server); +}; + +class LL_COMMON_API AISyncClient +{ + private: + friend class AISyncServer; + boost::intrusive_ptr mServer; // The server this client was registered with, or NULL when unregistered. + + public: +#ifdef SHOW_ASSERT + synceventset_t mReadyEvents; + AISyncClient(void) : mReadyEvents(0) { } +#endif + virtual ~AISyncClient() { llassert(!mServer); /* If this fails then you need to add unregister_client() to the top of the destructor of the derived class that implements deregistered(). */ } + virtual AISyncKey* createSyncKey(AISyncKey const* from_key = NULL) const = 0; + + virtual void event1_ready(void) = 0; + virtual void event1_not_ready(void) = 0; + + // Only client. Client was forcefully deregistered from expired server because it was the only client. + virtual void deregistered(void) + { +#ifdef SHOW_ASSERT + mReadyEvents = 0; +#endif + } + + AISyncServer* server(void) const { return mServer.get(); } + + // Add this client to a server with matching sync key. Optionally the server is first created. + void register_client(void) { AISyncServerMap::instance().register_client(this, createSyncKey()); } + + // Remove this client from its server, if any. + void unregister_client(void) { if (mServer) mServer->remove(this); } + + // Call 'ready' when you are ready (or not) to get a call to start(). + // Returns true if that call was made (immediately), otherwise it may happen later. + + // Set readiness of all events at once. + void ready(synceventset_t events, synceventset_t yesno) + { + if (!mServer) + { + register_client(); + } + mServer->ready(events, yesno, this); + } +}; + +#endif diff --git a/indra/llcommon/aithreadsafe.h b/indra/llcommon/aithreadsafe.h index bb0ac7e057..ac1531596e 100644 --- a/indra/llcommon/aithreadsafe.h +++ b/indra/llcommon/aithreadsafe.h @@ -96,16 +96,6 @@ #include "llthread.h" #include "llerror.h" -// g++ 4.2.x (and before?) have the bug that when you try to pass a temporary -// to a function taking a const reference, it still calls the copy constructor. -// Define this to hack around that. -// Note that the chosen solution ONLY works for copying an AI*Access object that -// is passed to a function: the lifetime of the copied object must not be longer -// than the original (or at least, it shouldn't be used anymore after the -// original is destructed). This will be guaranteed if the code also compiles -// on a compiler that doesn't need this hack. -#define AI_NEED_ACCESS_CC (defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ < 3)) || (__GNUC__ < 4))) - template struct AIReadAccessConst; template struct AIReadAccess; template struct AIWriteAccess; @@ -239,7 +229,7 @@ class AIThreadSafe : public AIThreadSafeBits // For use by AIThreadSafeDC AIThreadSafe(void) { } - AIThreadSafe(LLAPRPool& parent) : mRWLock(parent) { } + MUTEX_POOL(AIThreadSafe(LLAPRPool& parent) : mRWLock(parent){ }) public: // Only for use by AITHREADSAFE, see below. @@ -339,9 +329,6 @@ struct AIReadAccessConst AIReadAccessConst(AIThreadSafe const& wrapper, bool high_priority = false) : mWrapper(const_cast&>(wrapper)), mState(readlocked) -#if AI_NEED_ACCESS_CC - , mIsCopyConstructed(false) -#endif { mWrapper.mRWLock.rdlock(high_priority); } @@ -350,9 +337,6 @@ struct AIReadAccessConst // These should never be dynamically allocated, so there is no need to make this virtual. ~AIReadAccessConst() { -#if AI_NEED_ACCESS_CC - if (mIsCopyConstructed) return; -#endif if (mState == readlocked) mWrapper.mRWLock.rdunlock(); else if (mState == writelocked) @@ -371,23 +355,14 @@ struct AIReadAccessConst //! Constructor used by AIReadAccess. AIReadAccessConst(AIThreadSafe& wrapper, state_type state) : mWrapper(wrapper), mState(state) -#if AI_NEED_ACCESS_CC - , mIsCopyConstructed(false) -#endif { } AIThreadSafe& mWrapper; //!< Reference to the object that we provide access to. state_type const mState; //!< The lock state that mWrapper is in. -#if AI_NEED_ACCESS_CC - bool mIsCopyConstructed; -public: - AIReadAccessConst(AIReadAccessConst const& orig) : mWrapper(orig.mWrapper), mState(orig.mState), mIsCopyConstructed(true) { } -#else private: // Disallow copy constructing directly. AIReadAccessConst(AIReadAccessConst const&); -#endif }; /** @@ -473,7 +448,7 @@ class AIThreadSafeSimple : public AIThreadSafeBits friend struct AIRegisteredStateMachinesList; // For use by AIThreadSafeSimpleDC and AIRegisteredStateMachinesList. AIThreadSafeSimple(void) { } - AIThreadSafeSimple(LLAPRPool& parent) : mMutex(parent) { } + MUTEX_POOL(AIThreadSafeSimple(LLAPRPool& parent) : mMutex(parent) { }) public: // Only for use by AITHREADSAFESIMPLE, see below. @@ -551,7 +526,7 @@ class AIThreadSafeSimpleDC : public AIThreadSafeSimple protected: // For use by AIThreadSafeSimpleDCRootPool - AIThreadSafeSimpleDC(LLAPRRootPool& parent) : AIThreadSafeSimple(parent) { new (AIThreadSafeSimple::ptr()) T; } + AIThreadSafeSimpleDC(LLAPRRootPool& parent) : AIThreadSafeSimple(MUTEX_POOL(parent)) { new (AIThreadSafeSimple::ptr()) T; } }; // Helper class for AIThreadSafeSimpleDCRootPool to assure initialization of @@ -585,7 +560,7 @@ class AIThreadSafeSimpleDCRootPool : private AIThreadSafeSimpleDCRootPool_pbase, // as opposed to allocated from the current threads root pool. AIThreadSafeSimpleDCRootPool(void) : AIThreadSafeSimpleDCRootPool_pbase(), - AIThreadSafeSimpleDC(mRootPool) { } + AIThreadSafeSimpleDC(MUTEX_POOL(mRootPool)) { } }; /** @@ -596,9 +571,6 @@ struct AIAccessConst { //! Construct a AIAccessConst from a constant AIThreadSafeSimple. AIAccessConst(AIThreadSafeSimple const& wrapper) : mWrapper(const_cast&>(wrapper)) -#if AI_NEED_ACCESS_CC - , mIsCopyConstructed(false) -#endif { this->mWrapper.mMutex.lock(); } @@ -611,9 +583,6 @@ struct AIAccessConst ~AIAccessConst() { -#if AI_NEED_ACCESS_CC - if (mIsCopyConstructed) return; -#endif this->mWrapper.mMutex.unlock(); } @@ -625,15 +594,9 @@ struct AIAccessConst protected: AIThreadSafeSimple& mWrapper; //!< Reference to the object that we provide access to. -#if AI_NEED_ACCESS_CC - bool mIsCopyConstructed; -public: - AIAccessConst(AIAccessConst const& orig) : mWrapper(orig.mWrapper), mIsCopyConstructed(true) { } -#else private: // Disallow copy constructing directly. AIAccessConst(AIAccessConst const&); -#endif }; /** @@ -817,14 +780,9 @@ struct AISTAccessConst protected: AIThreadSafeSingleThread& mWrapper; //!< Reference to the object that we provide access to. -#if AI_NEED_ACCESS_CC -public: - AISTAccessConst(AISTAccessConst const& orig) : mWrapper(orig.mWrapper) { } -#else private: // Disallow copy constructing directly. AISTAccessConst(AISTAccessConst const&); -#endif }; /** diff --git a/indra/llcommon/bitpack.h b/indra/llcommon/bitpack.h index cb9c70c235..74e777f7eb 100644 --- a/indra/llcommon/bitpack.h +++ b/indra/llcommon/bitpack.h @@ -85,7 +85,7 @@ class LLBitPack *(mBuffer + mBufferSize++) = mLoad; if (mBufferSize > mMaxSize) { - llerror("mBufferSize exceeding mMaxSize!", 0); + LL_ERRS() << "mBufferSize exceeding mMaxSize!" << LL_ENDL; } mLoadSize = 0; mLoad = 0x00; @@ -128,7 +128,7 @@ class LLBitPack *(mBuffer + mBufferSize++) = mLoad; if (mBufferSize > mMaxSize) { - llerror("mBufferSize exceeding mMaxSize!", 0); + LL_ERRS() << "mBufferSize exceeding mMaxSize!" << LL_ENDL; } mLoadSize = 0; mLoad = 0x00; @@ -171,8 +171,8 @@ class LLBitPack #ifdef _DEBUG if (mBufferSize > mMaxSize) { - llerrs << "mBufferSize exceeding mMaxSize" << llendl; - llerrs << mBufferSize << " > " << mMaxSize << llendl; + LL_ERRS() << "mBufferSize exceeding mMaxSize" << LL_ENDL; + LL_ERRS() << mBufferSize << " > " << mMaxSize << LL_ENDL; } #endif mLoad = *(mBuffer + mBufferSize++); @@ -196,7 +196,7 @@ class LLBitPack *(mBuffer + mBufferSize++) = mLoad; if (mBufferSize > mMaxSize) { - llerror("mBufferSize exceeding mMaxSize!", 0); + LL_ERRS() << "mBufferSize exceeding mMaxSize!" << LL_ENDL; } mLoadSize = 0; } diff --git a/indra/llcommon/doublelinkedlist.h b/indra/llcommon/doublelinkedlist.h deleted file mode 100644 index f8aa9df802..0000000000 --- a/indra/llcommon/doublelinkedlist.h +++ /dev/null @@ -1,1403 +0,0 @@ -/** - * @file doublelinkedlist.h - * @brief Provides a standard doubly linked list for fun and profit. - * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifndef LL_DOUBLELINKEDLIST_H -#define LL_DOUBLELINKEDLIST_H - -#include "llerror.h" -#include "llrand.h" - -// node that actually contains the data -template class LLDoubleLinkedNode -{ -public: - DATA_TYPE *mDatap; - LLDoubleLinkedNode *mNextp; - LLDoubleLinkedNode *mPrevp; - - -public: - // assign the mDatap pointer - LLDoubleLinkedNode(DATA_TYPE *data); - - // destructor does not, by default, destroy associated data - // however, the mDatap must be NULL to ensure that we aren't causing memory leaks - ~LLDoubleLinkedNode(); - - // delete associated data and NULL out pointer - void deleteData(); - - // remove associated data and NULL out pointer - void removeData(); -}; - - -const U32 LLDOUBLE_LINKED_LIST_STATE_STACK_DEPTH = 4; - -template class LLDoubleLinkedList -{ -private: - LLDoubleLinkedNode mHead; // head node - LLDoubleLinkedNode mTail; // tail node - LLDoubleLinkedNode *mQueuep; // The node in the batter's box - LLDoubleLinkedNode *mCurrentp; // The node we're talking about - - // The state stack allows nested exploration of the LLDoubleLinkedList - // but should be used with great care - LLDoubleLinkedNode *mQueuepStack[LLDOUBLE_LINKED_LIST_STATE_STACK_DEPTH]; - LLDoubleLinkedNode *mCurrentpStack[LLDOUBLE_LINKED_LIST_STATE_STACK_DEPTH]; - U32 mStateStackDepth; - U32 mCount; - - // mInsertBefore is a pointer to a user-set function that returns - // TRUE if "first" should be located before "second" - // NOTE: mInsertBefore() should never return TRUE when ("first" == "second") - // or never-ending loops can occur - BOOL (*mInsertBefore)(DATA_TYPE *first, DATA_TYPE *second); - -public: - LLDoubleLinkedList(); - - // destructor destroys list and nodes, but not data in nodes - ~LLDoubleLinkedList(); - - // put data into a node and stick it at the front of the list - // set mCurrentp to mQueuep - void addData(DATA_TYPE *data); - - // put data into a node and stick it at the end of the list - // set mCurrentp to mQueuep - void addDataAtEnd(DATA_TYPE *data); - - S32 getLength() const; - // search the list starting at mHead.mNextp and remove the link with mDatap == data - // set mCurrentp to mQueuep - // return TRUE if found, FALSE if not found - BOOL removeData(const DATA_TYPE *data); - - // search the list starting at mHead.mNextp and delete the link with mDatap == data - // set mCurrentp to mQueuep - // return TRUE if found, FALSE if not found - BOOL deleteData(DATA_TYPE *data); - - // remove all nodes from the list and delete the associated data - void deleteAllData(); - - // remove all nodes from the list but do not delete data - void removeAllNodes(); - - BOOL isEmpty(); - - // check to see if data is in list - // set mCurrentp and mQueuep to the target of search if found, otherwise set mCurrentp to mQueuep - // return TRUE if found, FALSE if not found - BOOL checkData(const DATA_TYPE *data); - - // NOTE: This next two funtions are only included here - // for those too familiar with the LLLinkedList template class. - // They are deprecated. resetList() is unecessary while - // getCurrentData() is identical to getNextData() and has - // a misleading name. - // - // The recommended way to loop through a list is as follows: - // - // datap = list.getFirstData(); - // while (datap) - // { - // /* do stuff */ - // datap = list.getNextData(); - // } - - // place mQueuep on mHead node - void resetList(); - - // return the data currently pointed to, - // set mCurrentp to that node and bump mQueuep down the list - // NOTE: this function is identical to getNextData() - DATA_TYPE *getCurrentData(); - - - // reset the list and return the data currently pointed to, - // set mCurrentp to that node and bump mQueuep down the list - DATA_TYPE *getFirstData(); - - - // reset the list and return the data at position n, set mCurentp - // to that node and bump mQueuep down the list - // Note: n=0 will behave like getFirstData() - DATA_TYPE *getNthData(U32 n); - - // reset the list and return the last data in it, - // set mCurrentp to that node and bump mQueuep up the list - DATA_TYPE *getLastData(); - - // return data in mQueuep, - // set mCurrentp mQueuep and bump mQueuep down the list - DATA_TYPE *getNextData(); - - // return the data in mQueuep, - // set mCurrentp to mQueuep and bump mQueuep up the list - DATA_TYPE *getPreviousData(); - - // remove the Node at mCurrentp - // set mCurrentp to mQueuep - void removeCurrentData(); - - // delete the Node at mCurrentp - // set mCurrentp to mQueuep - void deleteCurrentData(); - - // remove the Node at mCurrentp and insert it into newlist - // set mCurrentp to mQueuep - void moveCurrentData(LLDoubleLinkedList *newlist); - - // insert the node in front of mCurrentp - // set mCurrentp to mQueuep - void insertNode(LLDoubleLinkedNode *node); - - // insert the data in front of mCurrentp - // set mCurrentp to mQueuep - void insertData(DATA_TYPE *data); - - // if mCurrentp has a previous node then : - // * swaps mCurrentp with its previous - // * set mCurrentp to mQueuep - // (convenient for forward bubble-sort) - // otherwise does nothing - void swapCurrentWithPrevious(); - - // if mCurrentp has a next node then : - // * swaps mCurrentp with its next - // * set mCurrentp to mQueuep - // (convenient for backwards bubble-sort) - // otherwise does nothing - void swapCurrentWithNext(); - - // move mCurrentp to the front of the list - // set mCurrentp to mQueuep - void moveCurrentToFront(); - - // move mCurrentp to the end of the list - // set mCurrentp to mQueuep - void moveCurrentToEnd(); - - // set mInsertBefore - void setInsertBefore(BOOL (*insert_before)(DATA_TYPE *first, DATA_TYPE *second)); - - // add data in front of first node for which mInsertBefore(datap, node->mDatap) returns TRUE - // set mCurrentp to mQueuep - BOOL addDataSorted(DATA_TYPE *datap); - - // sort the list using bubble-sort - // Yes, this is a different name than the same function in LLLinkedList. - // When it comes time for a name consolidation hopefully this one will win. - BOOL bubbleSort(); - - // does a single bubble sort pass on the list - BOOL lazyBubbleSort(); - - // returns TRUE if state successfully pushed (state stack not full) - BOOL pushState(); - - // returns TRUE if state successfully popped (state stack not empty) - BOOL popState(); - - // empties the state stack - void clearStateStack(); - - // randomly move the the links in the list for debug or (Discordian) purposes - // sets mCurrentp and mQueuep to top of list - void scramble(); - -private: - // add node to beginning of list - // set mCurrentp to mQueuep - void addNode(LLDoubleLinkedNode *node); - - // add node to end of list - // set mCurrentp to mQueuep - void addNodeAtEnd(LLDoubleLinkedNode *node); -}; - -//#endif - -//////////////////////////////////////////////////////////////////////////////////////////// - -// doublelinkedlist.cpp -// LLDoubleLinkedList template class implementation file. -// Provides a standard doubly linked list for fun and profit. -// -// Copyright 2001, Linden Research, Inc. - -//#include "llerror.h" -//#include "doublelinkedlist.h" - -////////////////////////////////////////////////////////////////////////////////////////// -// LLDoubleLinkedNode -////////////////////////////////////////////////////////////////////////////////////////// - - -// assign the mDatap pointer -template -LLDoubleLinkedNode::LLDoubleLinkedNode(DATA_TYPE *data) : - mDatap(data), mNextp(NULL), mPrevp(NULL) -{ -} - - -// destructor does not, by default, destroy associated data -// however, the mDatap must be NULL to ensure that we aren't causing memory leaks -template -LLDoubleLinkedNode::~LLDoubleLinkedNode() -{ - if (mDatap) - { - llerror("Attempting to call LLDoubleLinkedNode destructor with a non-null mDatap!", 1); - } -} - - -// delete associated data and NULL out pointer -template -void LLDoubleLinkedNode::deleteData() -{ - delete mDatap; - mDatap = NULL; -} - - -template -void LLDoubleLinkedNode::removeData() -{ - mDatap = NULL; -} - - -////////////////////////////////////////////////////////////////////////////////////// -// LLDoubleLinkedList -////////////////////////////////////////////////////////////////////////////////////// - -// <------- up ------- -// -// mCurrentp -// mQueuep | -// | | -// | | -// .------. .------. .------. .------. -// | |---->| |---->| |----->| |-----> NULL -// NULL <-----| |<----| |<----| |<-----| | -// _'------' '------' '------' '------:_ -// .------. /| | | |\ .------. -// NULL <-----|mHead |/ | mQueuep \|mTail |-----> NULL -// | | mCurrentp | | -// '------' '------' -// -------- down ---------> - -template -LLDoubleLinkedList::LLDoubleLinkedList() -: mHead(NULL), mTail(NULL), mQueuep(NULL) -{ - mCurrentp = mHead.mNextp; - mQueuep = mHead.mNextp; - mStateStackDepth = 0; - mCount = 0; - mInsertBefore = NULL; -} - - -// destructor destroys list and nodes, but not data in nodes -template -LLDoubleLinkedList::~LLDoubleLinkedList() -{ - removeAllNodes(); -} - - -// put data into a node and stick it at the front of the list -// doesn't change mCurrentp nor mQueuep -template -void LLDoubleLinkedList::addData(DATA_TYPE *data) -{ - // don't allow NULL to be passed to addData - if (!data) - { - llerror("NULL pointer passed to LLDoubleLinkedList::addData()", 0); - } - - // make the new node - LLDoubleLinkedNode *temp = new LLDoubleLinkedNode (data); - - // add the node to the front of the list - temp->mPrevp = NULL; - temp->mNextp = mHead.mNextp; - mHead.mNextp = temp; - - // if there's something in the list, fix its back pointer - if (temp->mNextp) - { - temp->mNextp->mPrevp = temp; - } - // otherwise, fix the tail of the list - else - { - mTail.mPrevp = temp; - } - - mCount++; -} - - -// put data into a node and stick it at the end of the list -template -void LLDoubleLinkedList::addDataAtEnd(DATA_TYPE *data) -{ - // don't allow NULL to be passed to addData - if (!data) - { - llerror("NULL pointer passed to LLDoubleLinkedList::addData()", 0); - } - - // make the new node - LLDoubleLinkedNode *nodep = new LLDoubleLinkedNode(data); - - addNodeAtEnd(nodep); - mCount++; -} - - -// search the list starting at mHead.mNextp and remove the link with mDatap == data -// set mCurrentp to mQueuep, or NULL if mQueuep points to node with mDatap == data -// return TRUE if found, FALSE if not found -template -BOOL LLDoubleLinkedList::removeData(const DATA_TYPE *data) -{ - BOOL b_found = FALSE; - // don't allow NULL to be passed to addData - if (!data) - { - llerror("NULL pointer passed to LLDoubleLinkedList::removeData()", 0); - } - - mCurrentp = mHead.mNextp; - - while (mCurrentp) - { - if (mCurrentp->mDatap == data) - { - b_found = TRUE; - - // if there is a next one, fix it - if (mCurrentp->mNextp) - { - mCurrentp->mNextp->mPrevp = mCurrentp->mPrevp; - } - else // we are at end of list - { - mTail.mPrevp = mCurrentp->mPrevp; - } - - // if there is a previous one, fix it - if (mCurrentp->mPrevp) - { - mCurrentp->mPrevp->mNextp = mCurrentp->mNextp; - } - else // we are at beginning of list - { - mHead.mNextp = mCurrentp->mNextp; - } - - // remove the node - mCurrentp->removeData(); - delete mCurrentp; - mCount--; - break; - } - mCurrentp = mCurrentp->mNextp; - } - - // reset the list back to where it was - if (mCurrentp == mQueuep) - { - mCurrentp = mQueuep = NULL; - } - else - { - mCurrentp = mQueuep; - } - - return b_found; -} - - -// search the list starting at mHead.mNextp and delete the link with mDatap == data -// set mCurrentp to mQueuep, or NULL if mQueuep points to node with mDatap == data -// return TRUE if found, FALSE if not found -template -BOOL LLDoubleLinkedList::deleteData(DATA_TYPE *data) -{ - BOOL b_found = FALSE; - // don't allow NULL to be passed to addData - if (!data) - { - llerror("NULL pointer passed to LLDoubleLinkedList::deleteData()", 0); - } - - mCurrentp = mHead.mNextp; - - while (mCurrentp) - { - if (mCurrentp->mDatap == data) - { - b_found = TRUE; - - // if there is a next one, fix it - if (mCurrentp->mNextp) - { - mCurrentp->mNextp->mPrevp = mCurrentp->mPrevp; - } - else // we are at end of list - { - mTail.mPrevp = mCurrentp->mPrevp; - } - - // if there is a previous one, fix it - if (mCurrentp->mPrevp) - { - mCurrentp->mPrevp->mNextp = mCurrentp->mNextp; - } - else // we are at beginning of list - { - mHead.mNextp = mCurrentp->mNextp; - } - - // remove the node - mCurrentp->deleteData(); - delete mCurrentp; - mCount--; - break; - } - mCurrentp = mCurrentp->mNextp; - } - - // reset the list back to where it was - if (mCurrentp == mQueuep) - { - mCurrentp = mQueuep = NULL; - } - else - { - mCurrentp = mQueuep; - } - - return b_found; -} - - -// remove all nodes from the list and delete the associated data -template -void LLDoubleLinkedList::deleteAllData() -{ - mCurrentp = mHead.mNextp; - - while (mCurrentp) - { - mQueuep = mCurrentp->mNextp; - mCurrentp->deleteData(); - delete mCurrentp; - mCurrentp = mQueuep; - } - - // reset mHead and mQueuep - mHead.mNextp = NULL; - mTail.mPrevp = NULL; - mCurrentp = mHead.mNextp; - mQueuep = mHead.mNextp; - mStateStackDepth = 0; - mCount = 0; -} - - -// remove all nodes from the list but do not delete associated data -template -void LLDoubleLinkedList::removeAllNodes() -{ - mCurrentp = mHead.mNextp; - - while (mCurrentp) - { - mQueuep = mCurrentp->mNextp; - mCurrentp->removeData(); - delete mCurrentp; - mCurrentp = mQueuep; - } - - // reset mHead and mCurrentp - mHead.mNextp = NULL; - mTail.mPrevp = NULL; - mCurrentp = mHead.mNextp; - mQueuep = mHead.mNextp; - mStateStackDepth = 0; - mCount = 0; -} - -template -S32 LLDoubleLinkedList::getLength() const -{ -// U32 length = 0; -// for (LLDoubleLinkedNode* temp = mHead.mNextp; temp != NULL; temp = temp->mNextp) -// { -// length++; -// } - return mCount; -} - -// check to see if data is in list -// set mCurrentp and mQueuep to the target of search if found, otherwise set mCurrentp to mQueuep -// return TRUE if found, FALSE if not found -template -BOOL LLDoubleLinkedList::checkData(const DATA_TYPE *data) -{ - mCurrentp = mHead.mNextp; - - while (mCurrentp) - { - if (mCurrentp->mDatap == data) - { - mQueuep = mCurrentp; - return TRUE; - } - mCurrentp = mCurrentp->mNextp; - } - - mCurrentp = mQueuep; - return FALSE; -} - -// NOTE: This next two funtions are only included here -// for those too familiar with the LLLinkedList template class. -// They are deprecated. resetList() is unecessary while -// getCurrentData() is identical to getNextData() and has -// a misleading name. -// -// The recommended way to loop through a list is as follows: -// -// datap = list.getFirstData(); -// while (datap) -// { -// /* do stuff */ -// datap = list.getNextData(); -// } - - // place mCurrentp and mQueuep on first node - template - void LLDoubleLinkedList::resetList() - { - mCurrentp = mHead.mNextp; - mQueuep = mHead.mNextp; - mStateStackDepth = 0; - } - - - // return the data currently pointed to, - // set mCurrentp to that node and bump mQueuep down the list - template - DATA_TYPE* LLDoubleLinkedList::getCurrentData() - { - if (mQueuep) - { - mCurrentp = mQueuep; - mQueuep = mQueuep->mNextp; - return mCurrentp->mDatap; - } - else - { - return NULL; - } - } - - -// reset the list and return the data currently pointed to, -// set mCurrentp to that node and bump mQueuep down the list -template -DATA_TYPE* LLDoubleLinkedList::getFirstData() -{ - mQueuep = mHead.mNextp; - mCurrentp = mQueuep; - if (mQueuep) - { - mQueuep = mQueuep->mNextp; - return mCurrentp->mDatap; - } - else - { - return NULL; - } -} - - -// reset the list and return the data at position n, set mCurentp -// to that node and bump mQueuep down the list -// Note: n=0 will behave like getFirstData() -template -DATA_TYPE* LLDoubleLinkedList::getNthData(U32 n) -{ - mCurrentp = mHead.mNextp; - - if (mCurrentp) - { - for (U32 i=0; imNextp; - if (!mCurrentp) - { - break; - } - } - } - - if (mCurrentp) - { - // bump mQueuep down the list - mQueuep = mCurrentp->mNextp; - return mCurrentp->mDatap; - } - else - { - mQueuep = NULL; - return NULL; - } -} - - -// reset the list and return the last data in it, -// set mCurrentp to that node and bump mQueuep up the list -template -DATA_TYPE* LLDoubleLinkedList::getLastData() -{ - mQueuep = mTail.mPrevp; - mCurrentp = mQueuep; - if (mQueuep) - { - mQueuep = mQueuep->mPrevp; - return mCurrentp->mDatap; - } - else - { - return NULL; - } -} - - -// return the data in mQueuep, -// set mCurrentp to mQueuep and bump mQueuep down the list -template -DATA_TYPE* LLDoubleLinkedList::getNextData() -{ - if (mQueuep) - { - mCurrentp = mQueuep; - mQueuep = mQueuep->mNextp; - return mCurrentp->mDatap; - } - else - { - return NULL; - } -} - - -// return the data in mQueuep, -// set mCurrentp to mQueuep and bump mQueuep up the list -template -DATA_TYPE* LLDoubleLinkedList::getPreviousData() -{ - if (mQueuep) - { - mCurrentp = mQueuep; - mQueuep = mQueuep->mPrevp; - return mCurrentp->mDatap; - } - else - { - return NULL; - } -} - - -// remove the Node at mCurrentp -// set mCurrentp to mQueuep, or NULL if (mCurrentp == mQueuep) -template -void LLDoubleLinkedList::removeCurrentData() -{ - if (mCurrentp) - { - // if there is a next one, fix it - if (mCurrentp->mNextp) - { - mCurrentp->mNextp->mPrevp = mCurrentp->mPrevp; - } - else // otherwise we are at end of list - { - mTail.mPrevp = mCurrentp->mPrevp; - } - - // if there is a previous one, fix it - if (mCurrentp->mPrevp) - { - mCurrentp->mPrevp->mNextp = mCurrentp->mNextp; - } - else // otherwise we are at beginning of list - { - mHead.mNextp = mCurrentp->mNextp; - } - - // remove the node - mCurrentp->removeData(); - delete mCurrentp; - mCount--; - - // check for redundant pointing - if (mCurrentp == mQueuep) - { - mCurrentp = mQueuep = NULL; - } - else - { - mCurrentp = mQueuep; - } - } -} - - -// delete the Node at mCurrentp -// set mCurrentp to mQueuep, or NULL if (mCurrentp == mQueuep) -template -void LLDoubleLinkedList::deleteCurrentData() -{ - if (mCurrentp) - { - // remove the node - // if there is a next one, fix it - if (mCurrentp->mNextp) - { - mCurrentp->mNextp->mPrevp = mCurrentp->mPrevp; - } - else // otherwise we are at end of list - { - mTail.mPrevp = mCurrentp->mPrevp; - } - - // if there is a previous one, fix it - if (mCurrentp->mPrevp) - { - mCurrentp->mPrevp->mNextp = mCurrentp->mNextp; - } - else // otherwise we are at beginning of list - { - mHead.mNextp = mCurrentp->mNextp; - } - - // remove the LLDoubleLinkedNode - mCurrentp->deleteData(); - delete mCurrentp; - mCount--; - - // check for redundant pointing - if (mCurrentp == mQueuep) - { - mCurrentp = mQueuep = NULL; - } - else - { - mCurrentp = mQueuep; - } - } -} - - -// remove the Node at mCurrentp and insert it into newlist -// set mCurrentp to mQueuep, or NULL if (mCurrentp == mQueuep) -template -void LLDoubleLinkedList::moveCurrentData(LLDoubleLinkedList *newlist) -{ - if (mCurrentp) - { - // remove the node - // if there is a next one, fix it - if (mCurrentp->mNextp) - { - mCurrentp->mNextp->mPrevp = mCurrentp->mPrevp; - } - else // otherwise we are at end of list - { - mTail.mPrevp = mCurrentp->mPrevp; - } - - // if there is a previous one, fix it - if (mCurrentp->mPrevp) - { - mCurrentp->mPrevp->mNextp = mCurrentp->mNextp; - } - else // otherwise we are at beginning of list - { - mHead.mNextp = mCurrentp->mNextp; - } - - // move the node to the new list - newlist->addNode(mCurrentp); - - // check for redundant pointing - if (mCurrentp == mQueuep) - { - mCurrentp = mQueuep = NULL; - } - else - { - mCurrentp = mQueuep; - } - } -} - - -// Inserts the node previous to mCurrentp -// set mCurrentp to mQueuep -template -void LLDoubleLinkedList::insertNode(LLDoubleLinkedNode *nodep) -{ - // don't allow pointer to NULL to be passed - if (!nodep) - { - llerror("NULL pointer passed to LLDoubleLinkedList::insertNode()", 0); - } - if (!nodep->mDatap) - { - llerror("NULL data pointer passed to LLDoubleLinkedList::insertNode()", 0); - } - - if (mCurrentp) - { - if (mCurrentp->mPrevp) - { - nodep->mPrevp = mCurrentp->mPrevp; - nodep->mNextp = mCurrentp; - mCurrentp->mPrevp->mNextp = nodep; - mCurrentp->mPrevp = nodep; - } - else // at beginning of list - { - nodep->mPrevp = NULL; - nodep->mNextp = mCurrentp; - mHead.mNextp = nodep; - mCurrentp->mPrevp = nodep; - } - mCurrentp = mQueuep; - } - else // add to front of list - { - addNode(nodep); - } -} - - -// insert the data in front of mCurrentp -// set mCurrentp to mQueuep -template -void LLDoubleLinkedList::insertData(DATA_TYPE *data) -{ - if (!data) - { - llerror("NULL data pointer passed to LLDoubleLinkedList::insertNode()", 0); - } - LLDoubleLinkedNode *node = new LLDoubleLinkedNode(data); - insertNode(node); - mCount++; -} - - -// if mCurrentp has a previous node then : -// * swaps mCurrentp with its previous -// * set mCurrentp to mQueuep -// otherwise does nothing -template -void LLDoubleLinkedList::swapCurrentWithPrevious() -{ - if (mCurrentp) - { - if (mCurrentp->mPrevp) - { - // Pull mCurrentp out of list - mCurrentp->mPrevp->mNextp = mCurrentp->mNextp; - if (mCurrentp->mNextp) - { - mCurrentp->mNextp->mPrevp = mCurrentp->mPrevp; - } - else // mCurrentp was at end of list - { - mTail.mPrevp = mCurrentp->mPrevp; - } - - // Fix mCurrentp's pointers - mCurrentp->mNextp = mCurrentp->mPrevp; - mCurrentp->mPrevp = mCurrentp->mNextp->mPrevp; - mCurrentp->mNextp->mPrevp = mCurrentp; - - if (mCurrentp->mPrevp) - { - // Fix the backward pointer of mCurrentp's new previous - mCurrentp->mPrevp->mNextp = mCurrentp; - } - else // mCurrentp is now at beginning of list - { - mHead.mNextp = mCurrentp; - } - - // Set the list back to the way it was - mCurrentp = mQueuep; - } - } -} - - -// if mCurrentp has a next node then : -// * swaps mCurrentp with its next -// * set mCurrentp to mQueuep -// otherwise does nothing -template -void LLDoubleLinkedList::swapCurrentWithNext() -{ - if (mCurrentp) - { - if (mCurrentp->mNextp) - { - // Pull mCurrentp out of list - mCurrentp->mNextp->mPrevp = mCurrentp->mPrevp; - if (mCurrentp->mPrevp) - { - mCurrentp->mPrevp->mNextp = mCurrentp->mNextp; - } - else // mCurrentp was at beginning of list - { - mHead.mNextp = mCurrentp->mNextp; - } - - // Fix mCurrentp's pointers - mCurrentp->mPrevp = mCurrentp->mNextp; - mCurrentp->mNextp = mCurrentp->mPrevp->mNextp; - mCurrentp->mPrevp->mNextp = mCurrentp; - - if (mCurrentp->mNextp) - { - // Fix the back pointer of mCurrentp's new next - mCurrentp->mNextp->mPrevp = mCurrentp; - } - else // mCurrentp is now at end of list - { - mTail.mPrevp = mCurrentp; - } - - // Set the list back to the way it was - mCurrentp = mQueuep; - } - } -} - -// move mCurrentp to the front of the list -// set mCurrentp to mQueuep -template -void LLDoubleLinkedList::moveCurrentToFront() -{ - if (mCurrentp) - { - // if there is a previous one, fix it - if (mCurrentp->mPrevp) - { - mCurrentp->mPrevp->mNextp = mCurrentp->mNextp; - } - else // otherwise we are at beginning of list - { - // check for redundant pointing - if (mCurrentp == mQueuep) - { - mCurrentp = mQueuep = NULL; - } - else - { - mCurrentp = mQueuep; - } - return; - } - - // if there is a next one, fix it - if (mCurrentp->mNextp) - { - mCurrentp->mNextp->mPrevp = mCurrentp->mPrevp; - } - else // otherwise we are at end of list - { - mTail.mPrevp = mCurrentp->mPrevp; - } - - // add mCurrentp to beginning of list - mCurrentp->mNextp = mHead.mNextp; - mHead.mNextp->mPrevp = mCurrentp; // mHead.mNextp MUST be valid, - // or the list had only one node - // and we would have returned already - mCurrentp->mPrevp = NULL; - mHead.mNextp = mCurrentp; - - // check for redundant pointing - if (mCurrentp == mQueuep) - { - mCurrentp = mQueuep = NULL; - } - else - { - mCurrentp = mQueuep; - } - } - -} - -// move mCurrentp to the end of the list -// set mCurrentp to mQueuep -template -void LLDoubleLinkedList::moveCurrentToEnd() -{ - if (mCurrentp) - { - // if there is a next one, fix it - if (mCurrentp->mNextp) - { - mCurrentp->mNextp->mPrevp = mCurrentp->mPrevp; - } - else // otherwise we are at end of list and we're done - { - // check for redundant pointing - if (mCurrentp == mQueuep) - { - mCurrentp = mQueuep = NULL; - } - else - { - mCurrentp = mQueuep; - } - return; - } - - // if there is a previous one, fix it - if (mCurrentp->mPrevp) - { - mCurrentp->mPrevp->mNextp = mCurrentp->mNextp; - } - else // otherwise we are at beginning of list - { - mHead.mNextp = mCurrentp->mNextp; - } - - // add mCurrentp to end of list - mCurrentp->mPrevp = mTail.mPrevp; - mTail.mPrevp->mNextp = mCurrentp; // mTail.mPrevp MUST be valid, - // or the list had only one node - // and we would have returned already - mCurrentp->mNextp = NULL; - mTail.mPrevp = mCurrentp; - - // check for redundant pointing - if (mCurrentp == mQueuep) - { - mCurrentp = mQueuep = NULL; - } - else - { - mCurrentp = mQueuep; - } - } -} - - -template -void LLDoubleLinkedList::setInsertBefore(BOOL (*insert_before)(DATA_TYPE *first, DATA_TYPE *second) ) -{ - mInsertBefore = insert_before; -} - - -// add data in front of the first node for which mInsertBefore(datap, node->mDatap) returns TRUE -// set mCurrentp to mQueuep -template -BOOL LLDoubleLinkedList::addDataSorted(DATA_TYPE *datap) -{ - // don't allow NULL to be passed to addData() - if (!datap) - { - llerror("NULL pointer passed to LLDoubleLinkedList::addDataSorted()", 0); - } - - // has mInsertBefore not been set? - if (!mInsertBefore) - { - addData(datap); - return FALSE; - } - - // is the list empty? - if (!mHead.mNextp) - { - addData(datap); - return TRUE; - } - - // Note: this step has been added so that the behavior of LLDoubleLinkedList - // is as rigorous as the LLLinkedList class about adding duplicate nodes. - // Duplicate nodes can cause a problem when sorting if mInsertBefore(foo, foo) - // returns TRUE. However, if mInsertBefore(foo, foo) returns FALSE, then there - // shouldn't be any reason to exclude duplicate nodes (as we do here). - if (checkData(datap)) - { - return FALSE; - } - - mCurrentp = mHead.mNextp; - while (mCurrentp) - { - // check to see if datap is already in the list - if (datap == mCurrentp->mDatap) - { - return FALSE; - } - else if (mInsertBefore(datap, mCurrentp->mDatap)) - { - insertData(datap); - return TRUE; - } - mCurrentp = mCurrentp->mNextp; - } - - addDataAtEnd(datap); - return TRUE; -} - - -// bubble-sort until sorted and return TRUE if anything was sorted -// leaves mQueuep pointing at last node that was swapped with its mNextp -// -// NOTE: if you find this function looping for really long times, then you -// probably need to check your implementation of mInsertBefore(a,b) and make -// sure it does not return TRUE when (a == b)! -template -BOOL LLDoubleLinkedList::bubbleSort() -{ - BOOL b_swapped = FALSE; - U32 count = 0; - while (lazyBubbleSort()) - { - b_swapped = TRUE; - if (count++ > 0x7FFFFFFF) - { - llwarning("LLDoubleLinkedList::bubbleSort() : too many passes...", 1); - llwarning(" make sure the mInsertBefore(a, b) does not return TRUE for a == b", 1); - break; - } - } - return b_swapped; -} - - -// do a single bubble-sort pass and return TRUE if anything was sorted -// leaves mQueuep pointing at last node that was swapped with its mNextp -template -BOOL LLDoubleLinkedList::lazyBubbleSort() -{ - // has mInsertBefore been set? - if (!mInsertBefore) - { - return FALSE; - } - - // is list empty? - mCurrentp = mHead.mNextp; - if (!mCurrentp) - { - return FALSE; - } - - BOOL b_swapped = FALSE; - - // the sort will exit after 0x7FFFFFFF nodes or the end of the list, whichever is first - S32 length = 0x7FFFFFFF; - S32 count = 0; - - while (mCurrentp && mCurrentp->mNextp && countmNextp->mDatap, mCurrentp->mDatap)) - { - b_swapped = TRUE; - mQueuep = mCurrentp; - swapCurrentWithNext(); // sets mCurrentp to mQueuep - } - count++; - mCurrentp = mCurrentp->mNextp; - } - - return b_swapped; -} - - -template -BOOL LLDoubleLinkedList::pushState() -{ - if (mStateStackDepth < LLDOUBLE_LINKED_LIST_STATE_STACK_DEPTH) - { - *(mQueuepStack + mStateStackDepth) = mQueuep; - *(mCurrentpStack + mStateStackDepth) = mCurrentp; - mStateStackDepth++; - return TRUE; - } - return FALSE; -} - - -template -BOOL LLDoubleLinkedList::popState() -{ - if (mStateStackDepth > 0) - { - mStateStackDepth--; - mQueuep = *(mQueuepStack + mStateStackDepth); - mCurrentp = *(mCurrentpStack + mStateStackDepth); - return TRUE; - } - return FALSE; -} - - -template -void LLDoubleLinkedList::clearStateStack() -{ - mStateStackDepth = 0; -} - -////////////////////////////////////////////////////////////////////////////////////////// -// private members -////////////////////////////////////////////////////////////////////////////////////////// - -// add node to beginning of list -// set mCurrentp to mQueuep -template -void LLDoubleLinkedList::addNode(LLDoubleLinkedNode *nodep) -{ - // add the node to the front of the list - nodep->mPrevp = NULL; - nodep->mNextp = mHead.mNextp; - mHead.mNextp = nodep; - - // if there's something in the list, fix its back pointer - if (nodep->mNextp) - { - nodep->mNextp->mPrevp = nodep; - } - else // otherwise fix the tail node - { - mTail.mPrevp = nodep; - } - - mCurrentp = mQueuep; -} - - -// add node to end of list -// set mCurrentp to mQueuep -template -void LLDoubleLinkedList::addNodeAtEnd(LLDoubleLinkedNode *node) -{ - // add the node to the end of the list - node->mNextp = NULL; - node->mPrevp = mTail.mPrevp; - mTail.mPrevp = node; - - // if there's something in the list, fix its back pointer - if (node->mPrevp) - { - node->mPrevp->mNextp = node; - } - else // otherwise fix the head node - { - mHead.mNextp = node; - } - - mCurrentp = mQueuep; -} - - -// randomly move nodes in the list for DEBUG (or Discordian) purposes -// sets mCurrentp and mQueuep to top of list -template -void LLDoubleLinkedList::scramble() -{ - S32 random_number; - DATA_TYPE *datap = getFirstData(); - while(datap) - { - random_number = ll_rand(5); - - if (0 == random_number) - { - removeCurrentData(); - addData(datap); - } - else if (1 == random_number) - { - removeCurrentData(); - addDataAtEnd(datap); - } - else if (2 == random_number) - { - swapCurrentWithPrevious(); - } - else if (3 == random_number) - { - swapCurrentWithNext(); - } - datap = getNextData(); - } - mQueuep = mHead.mNextp; - mCurrentp = mQueuep; -} - -template -BOOL LLDoubleLinkedList::isEmpty() -{ - return (mCount == 0); -} - - -#endif diff --git a/indra/llcommon/fix_macros.h b/indra/llcommon/fix_macros.h new file mode 100644 index 0000000000..ef959decff --- /dev/null +++ b/indra/llcommon/fix_macros.h @@ -0,0 +1,25 @@ +/** + * @file fix_macros.h + * @author Nat Goodspeed + * @date 2012-11-16 + * @brief The Mac system headers seem to #define macros with obnoxiously + * generic names, preventing any library from using those names. We've + * had to fix these in so many places that it's worth making a header + * file to handle it. + * + * $LicenseInfo:firstyear=2012&license=viewerlgpl$ + * Copyright (c) 2012, Linden Research, Inc. + * $/LicenseInfo$ + */ + +// DON'T use an #include guard: every time we encounter this header, #undef +// these macros all over again. + +// who injects MACROS with such generic names?! Grr. +#ifdef equivalent +#undef equivalent +#endif + +#ifdef check +#undef check +#endif diff --git a/indra/llcommon/indra_constants.cpp b/indra/llcommon/indra_constants.cpp index 64cbb1131c..daef52756b 100644 --- a/indra/llcommon/indra_constants.cpp +++ b/indra/llcommon/indra_constants.cpp @@ -45,3 +45,15 @@ const LLUUID GOVERNOR_LINDEN_ID("3d6181b0-6a4b-97ef-18d8-722652995cf1"); const LLUUID REALESTATE_LINDEN_ID("3d6181b0-6a4b-97ef-18d8-722652995cf1"); // Maintenance's group id. const LLUUID MAINTENANCE_GROUP_ID("dc7b21cd-3c89-fcaa-31c8-25f9ffd224cd"); + +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"); +const LLUUID IMG_USE_BAKED_EYES ("52cc6bb6-2ee5-e632-d3ad-50197b1dcb8a"); +const LLUUID IMG_USE_BAKED_SKIRT ("43529ce8-7faa-ad92-165a-bc4078371687"); +const LLUUID IMG_USE_BAKED_HAIR ("09aac1fb-6bce-0bee-7d44-caac6dbb6c63"); +const LLUUID IMG_USE_BAKED_LEFTARM ("ff62763f-d60a-9855-890b-0c96f8f8cd98"); +const LLUUID IMG_USE_BAKED_LEFTLEG ("8e915e25-31d1-cc95-ae08-d58a47488251"); +const LLUUID IMG_USE_BAKED_AUX1 ("9742065b-19b5-297c-858a-29711d539043"); +const LLUUID IMG_USE_BAKED_AUX2 ("03642e83-2bd1-4eb9-34b4-4c47ed586d2d"); +const LLUUID IMG_USE_BAKED_AUX3 ("edd51b77-fc10-ce7a-4b3d-011dfc349e4f"); diff --git a/indra/llcommon/indra_constants.h b/indra/llcommon/indra_constants.h index 3f0e8dd6c9..786e1bbd26 100644 --- a/indra/llcommon/indra_constants.h +++ b/indra/llcommon/indra_constants.h @@ -1,3 +1,4 @@ + /** * @file indra_constants.h * @brief some useful short term constants for Indra @@ -32,15 +33,6 @@ class LLUUID; -// At 45 Hz collisions seem stable and objects seem -// to settle down at a reasonable rate. -// JC 3/18/2003 - -// const F32 PHYSICS_TIMESTEP = 1.f / 45.f; -// This must be a #define due to anal retentive restrictions on const expressions -// CG 2008-06-05 -#define PHYSICS_TIMESTEP (1.f / 45.f) - const F32 COLLISION_TOLERANCE = 0.1f; const F32 HALF_COLLISION_TOLERANCE = 0.05f; @@ -140,14 +132,18 @@ const U32 DEFAULT_CGI_SERVICES_PORT = 12045; // on a single host for map tile generation. JC const U32 DEFAULT_MAPSERVER_PORT = 12124; -// For automatic port discovery when running multiple viewers on one host -const U32 PORT_DISCOVERY_RANGE_MIN = 13000; -const U32 PORT_DISCOVERY_RANGE_MAX = PORT_DISCOVERY_RANGE_MIN + 50; - -const char LAND_LAYER_CODE = 'L'; -const char WATER_LAYER_CODE = 'W'; -const char WIND_LAYER_CODE = '7'; -const char CLOUD_LAYER_CODE = '8'; +enum ETerrainBrushType +{ + // the valid brush numbers cannot be reordered, because they + // are used in the binary LSL format as arguments to llModifyLand() + E_LANDBRUSH_LEVEL = 0, + E_LANDBRUSH_RAISE = 1, + E_LANDBRUSH_LOWER = 2, + E_LANDBRUSH_SMOOTH = 3, + E_LANDBRUSH_NOISE = 4, + E_LANDBRUSH_REVERT = 5, + E_LANDBRUSH_INVALID = 6 +}; // keys // Bit masks for various keyboard modifier keys. @@ -248,7 +244,6 @@ const U8 SIM_ACCESS_DOWN = 254; const U8 SIM_ACCESS_MAX = SIM_ACCESS_ADULT; // attachment constants -const S32 MAX_AGENT_ATTACHMENTS = 38; const U8 ATTACHMENT_ADD = 0x80; // god levels @@ -299,13 +294,18 @@ const U32 START_LOCATION_ID_COUNT = 6; // group constants const U32 GROUP_MIN_SIZE = 2; -// gMaxAgentGroups is now sent by login.cgi, which -// looks it up from globals.xml. -// -// For now we need an old default value however, -// so the viewer can be deployed ahead of login.cgi. -// -const S32 DEFAULT_MAX_AGENT_GROUPS = 25; + +LL_COMMON_API extern const LLUUID IMG_USE_BAKED_HEAD; +LL_COMMON_API extern const LLUUID IMG_USE_BAKED_UPPER; +LL_COMMON_API extern const LLUUID IMG_USE_BAKED_LOWER; +LL_COMMON_API extern const LLUUID IMG_USE_BAKED_EYES; +LL_COMMON_API extern const LLUUID IMG_USE_BAKED_SKIRT; +LL_COMMON_API extern const LLUUID IMG_USE_BAKED_HAIR; +LL_COMMON_API extern const LLUUID IMG_USE_BAKED_LEFTARM; +LL_COMMON_API extern const LLUUID IMG_USE_BAKED_LEFTLEG; +LL_COMMON_API extern const LLUUID IMG_USE_BAKED_AUX1; +LL_COMMON_API extern const LLUUID IMG_USE_BAKED_AUX2; +LL_COMMON_API extern const LLUUID IMG_USE_BAKED_AUX3; // radius within which a chat message is fully audible const F32 CHAT_WHISPER_RADIUS = 10.f; @@ -337,18 +337,7 @@ const S32 SANDBOX_CLEAN_FREQ = 12; const F32 WIND_SCALE_HACK = 2.0f; // hack to make wind speeds more realistic -enum ETerrainBrushType -{ - // the valid brush numbers cannot be reordered, because they - // are used in the binary LSL format as arguments to llModifyLand() - E_LANDBRUSH_LEVEL = 0, - E_LANDBRUSH_RAISE = 1, - E_LANDBRUSH_LOWER = 2, - E_LANDBRUSH_SMOOTH = 3, - E_LANDBRUSH_NOISE = 4, - E_LANDBRUSH_REVERT = 5, - E_LANDBRUSH_INVALID = 6 -}; + // media commands const U32 PARCEL_MEDIA_COMMAND_STOP = 0; @@ -378,13 +367,6 @@ const U32 MAP_ITEM_CLASSIFIED = 0x08; const U32 MAP_ITEM_ADULT_EVENT = 0x09; const U32 MAP_ITEM_LAND_FOR_SALE_ADULT = 0x0a; -// Crash reporter behavior -const char* const CRASH_SETTINGS_FILE = "settings_crash_behavior.xml"; -const char* const CRASH_BEHAVIOR_SETTING = "CrashSubmitBehavior"; -const S32 CRASH_BEHAVIOR_ASK = 0; -const S32 CRASH_BEHAVIOR_ALWAYS_SEND = 1; -const S32 CRASH_BEHAVIOR_NEVER_SEND = 2; - // Export/Import return values const S32 EXPORT_SUCCESS = 0; const S32 EXPORT_ERROR_PERMISSIONS = -1; diff --git a/indra/llcommon/is_approx_equal_fraction.h b/indra/llcommon/is_approx_equal_fraction.h index d369fbc5b3..3c7f4e9282 100644 --- a/indra/llcommon/is_approx_equal_fraction.h +++ b/indra/llcommon/is_approx_equal_fraction.h @@ -49,9 +49,8 @@ * signatures. */ template -inline BOOL is_approx_equal_fraction_impl(FTYPE x, FTYPE y, U32 frac_bits) +inline bool is_approx_equal_fraction_impl(FTYPE x, FTYPE y, U32 frac_bits) { - BOOL ret = TRUE; FTYPE diff = (FTYPE) fabs(x - y); S32 diffInt = (S32) diff; @@ -64,20 +63,20 @@ inline BOOL is_approx_equal_fraction_impl(FTYPE x, FTYPE y, U32 frac_bits) // based on the number of bits used for packing decimal portion. if (diffInt != 0 || diffFracTolerance > 1) { - ret = FALSE; + return false; } - return ret; + return true; } /// F32 flavor -inline BOOL is_approx_equal_fraction(F32 x, F32 y, U32 frac_bits) +inline bool is_approx_equal_fraction(F32 x, F32 y, U32 frac_bits) { return is_approx_equal_fraction_impl(x, y, frac_bits); } /// F64 flavor -inline BOOL is_approx_equal_fraction(F64 x, F64 y, U32 frac_bits) +inline bool is_approx_equal_fraction(F64 x, F64 y, U32 frac_bits) { return is_approx_equal_fraction_impl(x, y, frac_bits); } diff --git a/indra/llcommon/linden_common.h b/indra/llcommon/linden_common.h index b6fdef4ca1..d44c318477 100644 --- a/indra/llcommon/linden_common.h +++ b/indra/llcommon/linden_common.h @@ -38,14 +38,14 @@ // Files included here are included in every library .cpp file and // are not precompiled. +#ifndef NO_CWDEBUG #include "cwdebug.h" +#endif #if defined(LL_WINDOWS) && defined(_DEBUG) -# if _MSC_VER >= 1400 // Visual C++ 2005 or later # define _CRTDBG_MAP_ALLOC # include # include -# endif #endif #include "llpreprocessor.h" @@ -66,5 +66,6 @@ #include "lldefs.h" #include "llerror.h" #include "llfile.h" +#include "llformat.h" #endif diff --git a/indra/llcommon/linked_lists.h b/indra/llcommon/linked_lists.h deleted file mode 100644 index 3d89a056e6..0000000000 --- a/indra/llcommon/linked_lists.h +++ /dev/null @@ -1,943 +0,0 @@ -/** - * @file linked_lists.h - * @brief LLLinkedList class header amd implementation file. - * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifndef LL_LINKED_LISTS_H -#define LL_LINKED_LISTS_H - -/** - * Provides a standard doubly linked list for fun and profit - * Utilizes a neat trick off of Flipcode where the back pointer is a - * pointer to a pointer, allowing easier transfer of nodes between lists, &c - * And a template class, of course - */ - -#include "llerror.h" - - -template class LLLinkedList -{ -public: - friend class LLLinkNode; - // External interface - - // basic constructor - LLLinkedList() : mHead(NULL), mCurrentp(NULL), mInsertBefore(NULL) - { - mCurrentp = mHead.mNextp; - mCurrentOperatingp = mHead.mNextp; - mCount = 0; - } - - // basic constructor - LLLinkedList(BOOL (*insert_before)(DATA_TYPE *data_new, DATA_TYPE *data_tested)) : mHead(NULL), mCurrentp(NULL), mInsertBefore(insert_before) - { - mCurrentp = mHead.mNextp; - mCurrentOperatingp = mHead.mNextp; - mCount = 0; - } - - // destructor destroys list and nodes, but not data in nodes - ~LLLinkedList() - { - removeAllNodes(); - } - - // set mInsertBefore - void setInsertBefore(BOOL (*insert_before)(DATA_TYPE *data_new, DATA_TYPE *data_tested)) - { - mInsertBefore = insert_before; - } - - // - // WARNING!!!!!!! - // addData and addDataSorted are NOT O(1) operations, but O(n) because they check - // for existence of the data in the linked list first. Why, I don't know - djs - // If you don't care about dupes, use addDataNoCheck - // - - // put data into a node and stick it at the front of the list - inline BOOL addData(DATA_TYPE *data); - - // put data into a node and sort into list by mInsertBefore() - // calls normal add if mInsertBefore isn't set - inline BOOL addDataSorted(DATA_TYPE *data); - - inline BOOL addDataNoCheck(DATA_TYPE *data); - - // bubbleSortList - // does an improved bubble sort of the list . . . works best with almost sorted data - // does nothing if mInsertBefore isn't set - // Nota Bene: Swaps are accomplished by swapping data pointers - inline void bubbleSortList(); - - // put data into a node and stick it at the end of the list - inline BOOL addDataAtEnd(DATA_TYPE *data); - - // returns number of items in the list - inline S32 getLength() const; - - inline BOOL isEmpty(); - - // search the list starting at mHead.mNextp and remove the link with mDatap == data - // leave mCurrentp and mCurrentOperatingp on the next entry - // return TRUE if found, FALSE if not found - inline BOOL removeData(DATA_TYPE *data); - - // search the list starting at mHead.mNextp and delete the link with mDatap == data - // leave mCurrentp and mCurrentOperatingp on the next entry - // return TRUE if found, FALSE if not found - inline BOOL deleteData(DATA_TYPE *data); - - // remove all nodes from the list and delete the associated data - inline void deleteAllData(); - - // remove all nodes from the list but do not delete data - inline void removeAllNodes(); - - // check to see if data is in list - // if TRUE then mCurrentp and mCurrentOperatingp point to data - inline BOOL checkData(DATA_TYPE *data); - - // place mCurrentp on first node - inline void resetList(); - - // return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp - inline DATA_TYPE *getCurrentData(); - - // same as getCurrentData() but a more intuitive name for the operation - inline DATA_TYPE *getNextData(); - - // reset the list and return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp - inline DATA_TYPE *getFirstData(); - - // reset the list and return the data at position n, set mCurentOperatingp to that node and bump mCurrentp - // Note: n is zero-based - inline DATA_TYPE *getNthData( U32 n); - - // reset the list and return the last data in it, set mCurentOperatingp to that node and bump mCurrentp - inline DATA_TYPE *getLastData(); - - // remove the Node at mCurentOperatingp - // leave mCurrentp and mCurentOperatingp on the next entry - inline void removeCurrentData(); - - // remove the Node at mCurentOperatingp and add it to newlist - // leave mCurrentp and mCurentOperatingp on the next entry - void moveCurrentData(LLLinkedList *newlist, BOOL b_sort); - - BOOL moveData(DATA_TYPE *data, LLLinkedList *newlist, BOOL b_sort); - - // delete the Node at mCurentOperatingp - // leave mCurrentp anf mCurentOperatingp on the next entry - void deleteCurrentData(); - -private: - // node that actually contains the data - class LLLinkNode - { - public: - // assign the mDatap pointer - LLLinkNode(DATA_TYPE *data) : mDatap(data), mNextp(NULL), mPrevpp(NULL) - { - } - - // destructor does not, by default, destroy associated data - // however, the mDatap must be NULL to ensure that we aren't causing memory leaks - ~LLLinkNode() - { - if (mDatap) - { - llerror("Attempting to call LLLinkNode destructor with a non-null mDatap!", 1); - } - } - - // delete associated data and NULL out pointer - void deleteData() - { - delete mDatap; - mDatap = NULL; - } - - // NULL out pointer - void removeData() - { - mDatap = NULL; - } - - DATA_TYPE *mDatap; - LLLinkNode *mNextp; - LLLinkNode **mPrevpp; - }; - - // add a node at the front of the list - void addData(LLLinkNode *node) - { - // don't allow NULL to be passed to addData - if (!node) - { - llerror("NULL pointer passed to LLLinkedList::addData", 0); - } - - // add the node to the front of the list - node->mPrevpp = &mHead.mNextp; - node->mNextp = mHead.mNextp; - - // if there's something in the list, fix its back pointer - if (node->mNextp) - { - node->mNextp->mPrevpp = &node->mNextp; - } - - mHead.mNextp = node; - } - - LLLinkNode mHead; // fake head node. . . makes pointer operations faster and easier - LLLinkNode *mCurrentp; // mCurrentp is the Node that getCurrentData returns - LLLinkNode *mCurrentOperatingp; // this is the node that the various mumbleCurrentData functions act on - BOOL (*mInsertBefore)(DATA_TYPE *data_new, DATA_TYPE *data_tested); // user function set to allow sorted lists - U32 mCount; -}; - -template -BOOL LLLinkedList::addData(DATA_TYPE *data) -{ - // don't allow NULL to be passed to addData - if (!data) - { - llerror("NULL pointer passed to LLLinkedList::addData", 0); - } - - LLLinkNode *tcurr = mCurrentp; - LLLinkNode *tcurrop = mCurrentOperatingp; - - if ( checkData(data)) - { - mCurrentp = tcurr; - mCurrentOperatingp = tcurrop; - return FALSE; - } - - // make the new node - LLLinkNode *temp = new LLLinkNode(data); - - // add the node to the front of the list - temp->mPrevpp = &mHead.mNextp; - temp->mNextp = mHead.mNextp; - - // if there's something in the list, fix its back pointer - if (temp->mNextp) - { - temp->mNextp->mPrevpp = &temp->mNextp; - } - - mHead.mNextp = temp; - mCurrentp = tcurr; - mCurrentOperatingp = tcurrop; - mCount++; - return TRUE; -} - - -template -BOOL LLLinkedList::addDataNoCheck(DATA_TYPE *data) -{ - // don't allow NULL to be passed to addData - if (!data) - { - llerror("NULL pointer passed to LLLinkedList::addData", 0); - } - - LLLinkNode *tcurr = mCurrentp; - LLLinkNode *tcurrop = mCurrentOperatingp; - - // make the new node - LLLinkNode *temp = new LLLinkNode(data); - - // add the node to the front of the list - temp->mPrevpp = &mHead.mNextp; - temp->mNextp = mHead.mNextp; - - // if there's something in the list, fix its back pointer - if (temp->mNextp) - { - temp->mNextp->mPrevpp = &temp->mNextp; - } - - mHead.mNextp = temp; - mCurrentp = tcurr; - mCurrentOperatingp = tcurrop; - mCount++; - return TRUE; -} - - -template -BOOL LLLinkedList::addDataSorted(DATA_TYPE *data) -{ - LLLinkNode *tcurr = mCurrentp; - LLLinkNode *tcurrop = mCurrentOperatingp; - // don't allow NULL to be passed to addData - if (!data) - { - llerror("NULL pointer passed to LLLinkedList::addDataSorted", 0); - } - - if (checkData(data)) - { - // restore - mCurrentp = tcurr; - mCurrentOperatingp = tcurrop; - return FALSE; - } - - // mInsertBefore not set? - if (!mInsertBefore) - { - addData(data); - // restore - mCurrentp = tcurr; - mCurrentOperatingp = tcurrop; - return FALSE; - } - - // empty list? - if (!mHead.mNextp) - { - addData(data); - // restore - mCurrentp = tcurr; - mCurrentOperatingp = tcurrop; - return TRUE; - } - - // make the new node - LLLinkNode *temp = new LLLinkNode(data); - - // walk the list until mInsertBefore returns true - mCurrentp = mHead.mNextp; - while (mCurrentp->mNextp) - { - if (mInsertBefore(data, mCurrentp->mDatap)) - { - // insert before the current one - temp->mPrevpp = mCurrentp->mPrevpp; - temp->mNextp = mCurrentp; - *(temp->mPrevpp) = temp; - mCurrentp->mPrevpp = &temp->mNextp; - // restore - mCurrentp = tcurr; - mCurrentOperatingp = tcurrop; - mCount++; - return TRUE; - } - else - { - mCurrentp = mCurrentp->mNextp; - } - } - - // on the last element, add before? - if (mInsertBefore(data, mCurrentp->mDatap)) - { - // insert before the current one - temp->mPrevpp = mCurrentp->mPrevpp; - temp->mNextp = mCurrentp; - *(temp->mPrevpp) = temp; - mCurrentp->mPrevpp = &temp->mNextp; - // restore - mCurrentp = tcurr; - mCurrentOperatingp = tcurrop; - } - else // insert after - { - temp->mPrevpp = &mCurrentp->mNextp; - temp->mNextp = NULL; - mCurrentp->mNextp = temp; - - // restore - mCurrentp = tcurr; - mCurrentOperatingp = tcurrop; - } - mCount++; - return TRUE; -} - -template -void LLLinkedList::bubbleSortList() -{ - // mInsertBefore not set - if (!mInsertBefore) - { - return; - } - - LLLinkNode *tcurr = mCurrentp; - LLLinkNode *tcurrop = mCurrentOperatingp; - - BOOL b_swapped = FALSE; - DATA_TYPE *temp; - - // Nota Bene: This will break if more than 0x7FFFFFFF members in list! - S32 length = 0x7FFFFFFF; - S32 count = 0; - do - { - b_swapped = FALSE; - mCurrentp = mHead.mNextp; - count = 0; - while ( (count + 1 < length) - &&(mCurrentp)) - { - if (mCurrentp->mNextp) - { - if (!mInsertBefore(mCurrentp->mDatap, mCurrentp->mNextp->mDatap)) - { - // swap data pointers! - temp = mCurrentp->mDatap; - mCurrentp->mDatap = mCurrentp->mNextp->mDatap; - mCurrentp->mNextp->mDatap = temp; - b_swapped = TRUE; - } - } - else - { - break; - } - count++; - mCurrentp = mCurrentp->mNextp; - } - length = count; - } while (b_swapped); - - // restore - mCurrentp = tcurr; - mCurrentOperatingp = tcurrop; -} - - -template -BOOL LLLinkedList::addDataAtEnd(DATA_TYPE *data) -{ - LLLinkNode *tcurr = mCurrentp; - LLLinkNode *tcurrop = mCurrentOperatingp; - - // don't allow NULL to be passed to addData - if (!data) - { - llerror("NULL pointer passed to LLLinkedList::addData", 0); - } - - if (checkData(data)) - { - mCurrentp = tcurr; - mCurrentOperatingp = tcurrop; - return FALSE; - } - - // make the new node - LLLinkNode *temp = new LLLinkNode(data); - - // add the node to the end of the list - - // if empty, add to the front and be done with it - if (!mHead.mNextp) - { - temp->mPrevpp = &mHead.mNextp; - temp->mNextp = NULL; - mHead.mNextp = temp; - } - else - { - // otherwise, walk to the end of the list - mCurrentp = mHead.mNextp; - while (mCurrentp->mNextp) - { - mCurrentp = mCurrentp->mNextp; - } - temp->mPrevpp = &mCurrentp->mNextp; - temp->mNextp = NULL; - mCurrentp->mNextp = temp; - } - - // restore - mCurrentp = tcurr; - mCurrentOperatingp = tcurrop; - mCount++; - return TRUE; -} - - -// returns number of items in the list -template -S32 LLLinkedList::getLength() const -{ -// S32 length = 0; -// for (LLLinkNode* temp = mHead.mNextp; temp != NULL; temp = temp->mNextp) -// { -// length++; -// } - return mCount; -} - - -template -BOOL LLLinkedList::isEmpty() -{ - return (mCount == 0); -} - - -// search the list starting at mHead.mNextp and remove the link with mDatap == data -// leave mCurrentp and mCurrentOperatingp on the next entry -// return TRUE if found, FALSE if not found -template -BOOL LLLinkedList::removeData(DATA_TYPE *data) -{ - BOOL b_found = FALSE; - // don't allow NULL to be passed to addData - if (!data) - { - llerror("NULL pointer passed to LLLinkedList::removeData", 0); - } - - LLLinkNode *tcurr = mCurrentp; - LLLinkNode *tcurrop = mCurrentOperatingp; - - mCurrentp = mHead.mNextp; - mCurrentOperatingp = mHead.mNextp; - - while (mCurrentOperatingp) - { - if (mCurrentOperatingp->mDatap == data) - { - b_found = TRUE; - - // remove the node - - // if there is a next one, fix it - if (mCurrentOperatingp->mNextp) - { - mCurrentOperatingp->mNextp->mPrevpp = mCurrentOperatingp->mPrevpp; - } - *(mCurrentOperatingp->mPrevpp) = mCurrentOperatingp->mNextp; - - // remove the LLLinkNode - - // if we were on the one we want to delete, bump the cached copies - if (mCurrentOperatingp == tcurrop) - { - tcurrop = tcurr = mCurrentOperatingp->mNextp; - } - else if (mCurrentOperatingp == tcurr) - { - tcurrop = tcurr = mCurrentOperatingp->mNextp; - } - - mCurrentp = mCurrentOperatingp->mNextp; - - mCurrentOperatingp->removeData(); - delete mCurrentOperatingp; - mCurrentOperatingp = mCurrentp; - mCount--; - break; - } - mCurrentOperatingp = mCurrentOperatingp->mNextp; - } - // restore - mCurrentp = tcurr; - mCurrentOperatingp = tcurrop; - return b_found; -} - -// search the list starting at mHead.mNextp and delete the link with mDatap == data -// leave mCurrentp and mCurrentOperatingp on the next entry -// return TRUE if found, FALSE if not found -template -BOOL LLLinkedList::deleteData(DATA_TYPE *data) -{ - BOOL b_found = FALSE; - // don't allow NULL to be passed to addData - if (!data) - { - llerror("NULL pointer passed to LLLinkedList::removeData", 0); - } - - LLLinkNode *tcurr = mCurrentp; - LLLinkNode *tcurrop = mCurrentOperatingp; - - mCurrentp = mHead.mNextp; - mCurrentOperatingp = mHead.mNextp; - - while (mCurrentOperatingp) - { - if (mCurrentOperatingp->mDatap == data) - { - b_found = TRUE; - - // remove the node - // if there is a next one, fix it - if (mCurrentOperatingp->mNextp) - { - mCurrentOperatingp->mNextp->mPrevpp = mCurrentOperatingp->mPrevpp; - } - *(mCurrentOperatingp->mPrevpp) = mCurrentOperatingp->mNextp; - - // delete the LLLinkNode - // if we were on the one we want to delete, bump the cached copies - if (mCurrentOperatingp == tcurrop) - { - tcurrop = tcurr = mCurrentOperatingp->mNextp; - } - - // and delete the associated data - llassert(mCurrentOperatingp); - mCurrentp = mCurrentOperatingp->mNextp; - mCurrentOperatingp->deleteData(); - delete mCurrentOperatingp; - mCurrentOperatingp = mCurrentp; - mCount--; - break; - } - mCurrentOperatingp = mCurrentOperatingp->mNextp; - } - // restore - mCurrentp = tcurr; - mCurrentOperatingp = tcurrop; - return b_found; -} - - // remove all nodes from the list and delete the associated data -template -void LLLinkedList::deleteAllData() -{ - LLLinkNode *temp; - // reset mCurrentp - mCurrentp = mHead.mNextp; - - while (mCurrentp) - { - temp = mCurrentp->mNextp; - mCurrentp->deleteData(); - delete mCurrentp; - mCurrentp = temp; - } - - // reset mHead and mCurrentp - mHead.mNextp = NULL; - mCurrentp = mHead.mNextp; - mCurrentOperatingp = mHead.mNextp; - mCount = 0; -} - -// remove all nodes from the list but do not delete data -template -void LLLinkedList::removeAllNodes() -{ - LLLinkNode *temp; - // reset mCurrentp - mCurrentp = mHead.mNextp; - - while (mCurrentp) - { - temp = mCurrentp->mNextp; - mCurrentp->removeData(); - delete mCurrentp; - mCurrentp = temp; - } - - // reset mHead and mCurrentp - mHead.mNextp = NULL; - mCurrentp = mHead.mNextp; - mCurrentOperatingp = mHead.mNextp; - mCount = 0; -} - -// check to see if data is in list -// if TRUE then mCurrentp and mCurrentOperatingp point to data -template -BOOL LLLinkedList::checkData(DATA_TYPE *data) -{ - // reset mCurrentp - mCurrentp = mHead.mNextp; - - while (mCurrentp) - { - if (mCurrentp->mDatap == data) - { - mCurrentOperatingp = mCurrentp; - return TRUE; - } - mCurrentp = mCurrentp->mNextp; - } - mCurrentOperatingp = mCurrentp; - return FALSE; -} - -// place mCurrentp on first node -template -void LLLinkedList::resetList() -{ - mCurrentp = mHead.mNextp; - mCurrentOperatingp = mHead.mNextp; -} - -// return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp -template -DATA_TYPE *LLLinkedList::getCurrentData() -{ - if (mCurrentp) - { - mCurrentOperatingp = mCurrentp; - mCurrentp = mCurrentp->mNextp; - return mCurrentOperatingp->mDatap; - } - else - { - return NULL; - } -} - -// same as getCurrentData() but a more intuitive name for the operation -template -DATA_TYPE *LLLinkedList::getNextData() -{ - if (mCurrentp) - { - mCurrentOperatingp = mCurrentp; - mCurrentp = mCurrentp->mNextp; - return mCurrentOperatingp->mDatap; - } - else - { - return NULL; - } -} - -// reset the list and return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp -template -DATA_TYPE *LLLinkedList::getFirstData() -{ - mCurrentp = mHead.mNextp; - mCurrentOperatingp = mHead.mNextp; - if (mCurrentp) - { - mCurrentOperatingp = mCurrentp; - mCurrentp = mCurrentp->mNextp; - return mCurrentOperatingp->mDatap; - } - else - { - return NULL; - } -} - -// Note: n is zero-based -template -DATA_TYPE *LLLinkedList::getNthData( U32 n ) -{ - mCurrentOperatingp = mHead.mNextp; - - // if empty, return NULL - if (!mCurrentOperatingp) - { - return NULL; - } - - for( U32 i = 0; i < n; i++ ) - { - mCurrentOperatingp = mCurrentOperatingp->mNextp; - if( !mCurrentOperatingp ) - { - return NULL; - } - } - - mCurrentp = mCurrentOperatingp->mNextp; - return mCurrentOperatingp->mDatap; -} - - -// reset the list and return the last data in it, set mCurentOperatingp to that node and bump mCurrentp -template -DATA_TYPE *LLLinkedList::getLastData() -{ - mCurrentOperatingp = mHead.mNextp; - - // if empty, return NULL - if (!mCurrentOperatingp) - return NULL; - - // walk until we're pointing at the last entry - while (mCurrentOperatingp->mNextp) - { - mCurrentOperatingp = mCurrentOperatingp->mNextp; - } - mCurrentp = mCurrentOperatingp->mNextp; - return mCurrentOperatingp->mDatap; -} - -// remove the Node at mCurentOperatingp -// leave mCurrentp and mCurentOperatingp on the next entry -// return TRUE if found, FALSE if not found -template -void LLLinkedList::removeCurrentData() -{ - if (mCurrentOperatingp) - { - // remove the node - // if there is a next one, fix it - if (mCurrentOperatingp->mNextp) - { - mCurrentOperatingp->mNextp->mPrevpp = mCurrentOperatingp->mPrevpp; - } - *(mCurrentOperatingp->mPrevpp) = mCurrentOperatingp->mNextp; - - // remove the LLLinkNode - mCurrentp = mCurrentOperatingp->mNextp; - - mCurrentOperatingp->removeData(); - delete mCurrentOperatingp; - mCount--; - mCurrentOperatingp = mCurrentp; - } -} - -// remove the Node at mCurentOperatingp and add it to newlist -// leave mCurrentp and mCurentOperatingp on the next entry -// return TRUE if found, FALSE if not found -template -void LLLinkedList::moveCurrentData(LLLinkedList *newlist, BOOL b_sort) -{ - if (mCurrentOperatingp) - { - // remove the node - // if there is a next one, fix it - if (mCurrentOperatingp->mNextp) - { - mCurrentOperatingp->mNextp->mPrevpp = mCurrentOperatingp->mPrevpp; - } - *(mCurrentOperatingp->mPrevpp) = mCurrentOperatingp->mNextp; - - // remove the LLLinkNode - mCurrentp = mCurrentOperatingp->mNextp; - // move the node to the new list - newlist->addData(mCurrentOperatingp); - if (b_sort) - bubbleSortList(); - mCurrentOperatingp = mCurrentp; - } -} - -template -BOOL LLLinkedList::moveData(DATA_TYPE *data, LLLinkedList *newlist, BOOL b_sort) -{ - BOOL b_found = FALSE; - // don't allow NULL to be passed to addData - if (!data) - { - llerror("NULL pointer passed to LLLinkedList::removeData", 0); - } - - LLLinkNode *tcurr = mCurrentp; - LLLinkNode *tcurrop = mCurrentOperatingp; - - mCurrentp = mHead.mNextp; - mCurrentOperatingp = mHead.mNextp; - - while (mCurrentOperatingp) - { - if (mCurrentOperatingp->mDatap == data) - { - b_found = TRUE; - - // remove the node - - // if there is a next one, fix it - if (mCurrentOperatingp->mNextp) - { - mCurrentOperatingp->mNextp->mPrevpp = mCurrentOperatingp->mPrevpp; - } - *(mCurrentOperatingp->mPrevpp) = mCurrentOperatingp->mNextp; - - // if we were on the one we want to delete, bump the cached copies - if ( (mCurrentOperatingp == tcurrop) - ||(mCurrentOperatingp == tcurr)) - { - tcurrop = tcurr = mCurrentOperatingp->mNextp; - } - - // remove the LLLinkNode - mCurrentp = mCurrentOperatingp->mNextp; - // move the node to the new list - newlist->addData(mCurrentOperatingp); - if (b_sort) - newlist->bubbleSortList(); - mCurrentOperatingp = mCurrentp; - break; - } - mCurrentOperatingp = mCurrentOperatingp->mNextp; - } - // restore - mCurrentp = tcurr; - mCurrentOperatingp = tcurrop; - return b_found; -} - -// delete the Node at mCurentOperatingp -// leave mCurrentp anf mCurentOperatingp on the next entry -// return TRUE if found, FALSE if not found -template -void LLLinkedList::deleteCurrentData() -{ - if (mCurrentOperatingp) - { - // remove the node - // if there is a next one, fix it - if (mCurrentOperatingp->mNextp) - { - mCurrentOperatingp->mNextp->mPrevpp = mCurrentOperatingp->mPrevpp; - } - *(mCurrentOperatingp->mPrevpp) = mCurrentOperatingp->mNextp; - - // remove the LLLinkNode - mCurrentp = mCurrentOperatingp->mNextp; - - mCurrentOperatingp->deleteData(); - if (mCurrentOperatingp->mDatap) - llerror("This is impossible!", 0); - delete mCurrentOperatingp; - mCurrentOperatingp = mCurrentp; - mCount--; - } -} - -#endif diff --git a/indra/llcommon/ll_template_cast.h b/indra/llcommon/ll_template_cast.h deleted file mode 100644 index c8f9a2f7eb..0000000000 --- a/indra/llcommon/ll_template_cast.h +++ /dev/null @@ -1,177 +0,0 @@ -/** - * @file ll_template_cast.h - * @author Nat Goodspeed - * @date 2009-11-21 - * @brief Define ll_template_cast function - * - * $LicenseInfo:firstyear=2009&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#if ! defined(LL_LL_TEMPLATE_CAST_H) -#define LL_LL_TEMPLATE_CAST_H - -/** - * Implementation for ll_template_cast() (q.v.). - * - * Default implementation: trying to cast two completely unrelated types - * returns 0. Typically you'd specify T and U as pointer types, but in fact T - * can be any type that can be initialized with 0. - */ -template -struct ll_template_cast_impl -{ - T operator()(U) - { - return 0; - } -}; - -/** - * ll_template_cast(some_value) is for use in a template function when - * some_value might be of arbitrary type, but you want to recognize type T - * specially. - * - * It's designed for use with pointer types. Example: - * @code - * struct SpecialClass - * { - * void someMethod(const std::string&) const; - * }; - * - * template - * void somefunc(const REALCLASS& instance) - * { - * const SpecialClass* ptr = ll_template_cast(&instance); - * if (ptr) - * { - * ptr->someMethod("Call method only available on SpecialClass"); - * } - * } - * @endcode - * - * Why is this better than dynamic_cast<>? Because unless OtherClass is - * polymorphic, the following won't even compile (gcc 4.0.1): - * @code - * OtherClass other; - * SpecialClass* ptr = dynamic_cast(&other); - * @endcode - * to say nothing of this: - * @code - * void function(int); - * SpecialClass* ptr = dynamic_cast(&function); - * @endcode - * ll_template_cast handles these kinds of cases by returning 0. - */ -template -T ll_template_cast(U value) -{ - return ll_template_cast_impl()(value); -} - -/** - * Implementation for ll_template_cast() (q.v.). - * - * Implementation for identical types: return same value. - */ -template -struct ll_template_cast_impl -{ - T operator()(T value) - { - return value; - } -}; - -/** - * LL_TEMPLATE_CONVERTIBLE(dest, source) asserts that, for a value @c s of - * type @c source, ll_template_cast(s) will return @c s -- - * presuming that @c source can be converted to @c dest by the normal rules of - * C++. - * - * By default, ll_template_cast(s) will return 0 unless @c s's - * type is literally identical to @c dest. (This is because of the - * straightforward application of template specialization rules.) That can - * lead to surprising results, e.g.: - * - * @code - * Foo myFoo; - * const Foo* fooptr = ll_template_cast(&myFoo); - * @endcode - * - * Here @c fooptr will be 0 because &myFoo is of type Foo* - * -- @em not const Foo*. (Declaring const Foo myFoo; would - * force the compiler to do the right thing.) - * - * More disappointingly: - * @code - * struct Base {}; - * struct Subclass: public Base {}; - * Subclass object; - * Base* ptr = ll_template_cast(&object); - * @endcode - * - * Here @c ptr will be 0 because &object is of type - * Subclass* rather than Base*. We @em want this cast to - * succeed, but without our help ll_template_cast can't recognize it. - * - * The following would suffice: - * @code - * LL_TEMPLATE_CONVERTIBLE(Base*, Subclass*); - * ... - * Base* ptr = ll_template_cast(&object); - * @endcode - * - * However, as noted earlier, this is easily fooled: - * @code - * const Base* ptr = ll_template_cast(&object); - * @endcode - * would still produce 0 because we haven't yet seen: - * @code - * LL_TEMPLATE_CONVERTIBLE(const Base*, Subclass*); - * @endcode - * - * @TODO - * This macro should use Boost type_traits facilities for stripping and - * re-adding @c const and @c volatile qualifiers so that invoking - * LL_TEMPLATE_CONVERTIBLE(dest, source) will automatically generate all - * permitted permutations. It's really not fair to the coder to require - * separate: - * @code - * LL_TEMPLATE_CONVERTIBLE(Base*, Subclass*); - * LL_TEMPLATE_CONVERTIBLE(const Base*, Subclass*); - * LL_TEMPLATE_CONVERTIBLE(const Base*, const Subclass*); - * @endcode - * - * (Naturally we omit LL_TEMPLATE_CONVERTIBLE(Base*, const Subclass*) - * because that's not permitted by normal C++ assignment anyway.) - */ -#define LL_TEMPLATE_CONVERTIBLE(DEST, SOURCE) \ -template <> \ -struct ll_template_cast_impl \ -{ \ - DEST operator()(SOURCE wrapper) \ - { \ - return wrapper; \ - } \ -} - -#endif /* ! defined(LL_LL_TEMPLATE_CAST_H) */ diff --git a/indra/llcommon/llalignedarray.h b/indra/llcommon/llalignedarray.h new file mode 100644 index 0000000000..d6ab5ed3dc --- /dev/null +++ b/indra/llcommon/llalignedarray.h @@ -0,0 +1,143 @@ +/** + * @file llalignedarray.h + * @brief A static array which obeys alignment restrictions and mimics std::vector accessors. + * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLALIGNEDARRAY_H +#define LL_LLALIGNEDARRAY_H + +#include "llmemory.h" + +template +class LLAlignedArray +{ +public: + T* mArray; + U32 mElementCount; + U32 mCapacity; + + LLAlignedArray(); + ~LLAlignedArray(); + + void push_back(const T& elem); + void pop_back() { if(!!mElementCount) --mElementCount; } + bool empty() const { return !mElementCount; } + T& front() { return operator[](0); } + T& back() { return operator[](mElementCount-1); } + U32 size() const { return mElementCount; } + void resize(U32 size); + T* append(S32 N); + T& operator[](int idx); + const T& operator[](int idx) const; +}; + +template +LLAlignedArray::LLAlignedArray() +{ + llassert(alignment >= 16); + mArray = NULL; + mElementCount = 0; + mCapacity = 0; +} + +template +LLAlignedArray::~LLAlignedArray() +{ + ll_aligned_free(mArray); + mArray = NULL; + mElementCount = 0; + mCapacity = 0; +} + +template +void LLAlignedArray::push_back(const T& elem) +{ + T* old_buf = NULL; + if (mCapacity <= mElementCount) + { + mCapacity++; + mCapacity *= 2; + T* new_buf = (T*) ll_aligned_malloc(mCapacity*sizeof(T)); + if (mArray) + { + ll_memcpy_nonaliased_aligned_16((char*)new_buf, (char*)mArray, sizeof(T)*mElementCount); + } + old_buf = mArray; + mArray = new_buf; + } + + mArray[mElementCount++] = elem; + + //delete old array here to prevent error on a.push_back(a[0]) + ll_aligned_free(old_buf); +} + +template +void LLAlignedArray::resize(U32 size) +{ + if (mCapacity < size) + { + mCapacity = size+mCapacity*2; + T* new_buf = mCapacity > 0 ? (T*) ll_aligned_malloc(mCapacity*sizeof(T)) : NULL; + if (mArray) + { + ll_memcpy_nonaliased_aligned_16((char*) new_buf, (char*) mArray, sizeof(T)*mElementCount); + ll_aligned_free(mArray); + } + + /*for (U32 i = mElementCount; i < mCapacity; ++i) + { + new(new_buf+i) T(); + }*/ + mArray = new_buf; + } + + mElementCount = size; +} + + +template +T& LLAlignedArray::operator[](int idx) +{ + llassert((U32)idx < mElementCount); + return mArray[idx]; +} + +template +const T& LLAlignedArray::operator[](int idx) const +{ + llassert((U32)idx < mElementCount); + return mArray[idx]; +} + +template +T* LLAlignedArray::append(S32 N) +{ + U32 sz = size(); + resize(sz+N); + return &((*this)[sz]); +} + +#endif + diff --git a/indra/llcommon/llallocator_heap_profile.cpp b/indra/llcommon/llallocator_heap_profile.cpp index b574ef668b..499d78ed64 100644 --- a/indra/llcommon/llallocator_heap_profile.cpp +++ b/indra/llcommon/llallocator_heap_profile.cpp @@ -40,7 +40,7 @@ #include #include -static const std::string HEAP_PROFILE_MAGIC_STR = "heap profile:"; +static const std::string HEAP_PROFILE_MAGIC_STR("heap profile:"); static bool is_separator(char c) { @@ -59,7 +59,7 @@ void LLAllocatorHeapProfile::parse(std::string const & prof_text) { // *TODO - determine if there should be some better error state than // mLines being empty. -brad - llwarns << "invalid heap profile data passed into parser." << llendl; + LL_WARNS() << "invalid heap profile data passed into parser." << LL_ENDL; return; } @@ -70,7 +70,7 @@ void LLAllocatorHeapProfile::parse(std::string const & prof_text) range_t prof_range(prof_begin, prof_text.end()); boost::algorithm::split(prof_lines, prof_range, - boost::bind(std::equal_to(), '\n', _1)); + std::bind(std::equal_to(), '\n', std::placeholders::_1)); std::vector< range_t >::const_iterator i; for(i = prof_lines.begin(); i != prof_lines.end() && !i->empty(); ++i) diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp index a11effc155..36c6b0f611 100644 --- a/indra/llcommon/llapp.cpp +++ b/indra/llcommon/llapp.cpp @@ -25,8 +25,15 @@ */ #include "linden_common.h" + #include "llapp.h" +#ifdef LL_DARWIN +#include +#include +#include +#endif + #include "llcommon.h" #include "llapr.h" #include "llerrorcontrol.h" @@ -35,6 +42,7 @@ #include "lllivefile.h" #include "llmemory.h" #include "llstl.h" // for DeletePointer() +#include "llstring.h" #include "lleventtimer.h" // @@ -43,13 +51,17 @@ // Windows uses structured exceptions, so it's handled a bit differently. // #if LL_WINDOWS +#include + LONG WINAPI default_windows_exception_handler(struct _EXCEPTION_POINTERS *exception_infop); BOOL ConsoleCtrlHandler(DWORD fdwCtrlType); #else # include # include // for fork() +# include "apr_signal.h" // for apr_signal_description_get(int signum) void setup_signals(); void default_unix_signal_handler(int signum, siginfo_t *info, void *); + # if LL_DARWIN /* OSX doesn't support SIGRT* */ S32 LL_SMACKDOWN_SIGNAL = SIGUSR1; @@ -66,7 +78,7 @@ S32 LL_HEARTBEAT_SIGNAL = (SIGRTMAX >= 0) ? (SIGRTMAX-0) : SIGUSR2; #endif // LL_WINDOWS // the static application instance -LLApp* LLApp::sApplication = NULL; +LLApp* LLApp::sApplication = nullptr; // Allows the generation of core files for post mortem under gdb // and disables crashlogger @@ -78,8 +90,7 @@ BOOL LLApp::sLogInSignal = FALSE; // static LLApp::EAppStatus LLApp::sStatus = LLApp::APP_STATUS_STOPPED; // Keeps track of application status -LLAppErrorHandler LLApp::sErrorHandler = NULL; -LLAppErrorHandler LLApp::sSyncErrorHandler = NULL; +LLAppErrorHandler LLApp::sErrorHandler = nullptr; BOOL LLApp::sErrorThreadRunning = FALSE; #if !LL_WINDOWS LLApp::child_map LLApp::sChildMap; @@ -88,7 +99,8 @@ LLAppChildCallback LLApp::sDefaultChildCallback = NULL; #endif -LLApp::LLApp() : mThreadErrorp(NULL) +LLApp::LLApp() + : mThreadErrorp(nullptr) { commonCtor(); } @@ -100,14 +112,6 @@ void LLApp::commonCtor() LLCommon::initClass(); -#if !LL_WINDOWS - // This must be initialized before the error handler. - sSigChildCount = new LLAtomicU32(0); -#endif - - // Setup error handling - setupErrorHandling(); - // initialize the options structure. We need to make this an array // because the structured data will not auto-allocate if we // reference an invalid location with the [] operator. @@ -118,8 +122,16 @@ void LLApp::commonCtor() mOptions.append(sd); } + // Make sure we clean up APR when we exit + // Don't need to do this if we're cleaning up APR in the destructor + //atexit(ll_cleanup_apr); + // Set the application to this instance. sApplication = this; + + // initialize the buffer to write the minidump filename to + // (this is used to avoid allocating memory in the crash handler) + mCrashReportPipeStr = L"\\\\.\\pipe\\LLCrashReporterPipe"; } LLApp::LLApp(LLErrorThread *error_thread) : @@ -131,10 +143,6 @@ LLApp::LLApp(LLErrorThread *error_thread) : LLApp::~LLApp() { -#if !LL_WINDOWS - delete sSigChildCount; - sSigChildCount = NULL; -#endif // reclaim live file memory std::for_each(mLiveFiles.begin(), mLiveFiles.end(), DeletePointer()); @@ -146,9 +154,9 @@ LLApp::~LLApp() if (mThreadErrorp) { delete mThreadErrorp; - mThreadErrorp = NULL; + mThreadErrorp = nullptr; } - + LLCommon::cleanupClass(); } @@ -162,8 +170,8 @@ LLApp* LLApp::instance() LLSD LLApp::getOption(const std::string& name) const { LLSD rv; - LLSD::array_const_iterator iter = mOptions.beginArray(); - LLSD::array_const_iterator end = mOptions.endArray(); + auto iter = mOptions.beginArray(); + auto end = mOptions.endArray(); for(; iter != end; ++iter) { rv = (*iter)[name]; @@ -181,8 +189,8 @@ bool LLApp::parseCommandOptions(int argc, char** argv) { if(argv[ii][0] != '-') { - llinfos << "Did not find option identifier while parsing token: " - << argv[ii] << llendl; + LL_INFOS() << "Did not find option identifier while parsing token: " + << argv[ii] << LL_ENDL; return false; } int offset = 1; @@ -207,6 +215,20 @@ bool LLApp::parseCommandOptions(int argc, char** argv) } ++ii; value.assign(argv[ii]); + +#if LL_WINDOWS + //Windows changed command line parsing. Deal with it. + size_t slen = value.length() - 1; + size_t start = 0; + size_t end = slen; + if (argv[ii][start]=='"')start++; + if (argv[ii][end]=='"')end--; + if (start!=0 || end!=slen) + { + value = value.substr (start,end); + } +#endif + commands[name] = value; } setOptionData(PRIORITY_COMMAND_LINE, commands); @@ -243,37 +265,50 @@ LLSD LLApp::getOptionData(OptionPriority level) return mOptions[level]; } +#if LL_WINDOWS +//The following code is needed for 32-bit apps on 64-bit windows to keep it from eating +//crashes. It is a lovely undocumented 'feature' in SP1 of Windows 7. An excellent +//in-depth article on the issue may be found here: http://randomascii.wordpress.com/2012/07/05/when-even-crashing-doesn-work/ +void EnableCrashingOnCrashes() +{ + typedef BOOL (WINAPI *tGetPolicy)(LPDWORD lpFlags); + typedef BOOL (WINAPI *tSetPolicy)(DWORD dwFlags); + const DWORD EXCEPTION_SWALLOWING = 0x1; + + HMODULE kernel32 = LoadLibraryA("kernel32.dll"); + tGetPolicy pGetPolicy = (tGetPolicy)GetProcAddress(kernel32, + "GetProcessUserModeExceptionPolicy"); + tSetPolicy pSetPolicy = (tSetPolicy)GetProcAddress(kernel32, + "SetProcessUserModeExceptionPolicy"); + if (pGetPolicy && pSetPolicy) + { + DWORD dwFlags; + if (pGetPolicy(&dwFlags)) + { + // Turn off the filter + pSetPolicy(dwFlags & ~EXCEPTION_SWALLOWING); + } + } +} +#endif + void LLApp::setupErrorHandling() { // Error handling is done by starting up an error handling thread, which just sleeps and // occasionally checks to see if the app is in an error state, and sees if it needs to be run. -#if LL_WINDOWS - // Windows doesn't have the same signal handling mechanisms as UNIX, thus APR doesn't provide - // a signal handling thread implementation. - // What we do is install an unhandled exception handler, which will try to do the right thing - // in the case of an error (generate a minidump) - - // Disable this until the viewer gets ported so server crashes can be JIT debugged. - //LPTOP_LEVEL_EXCEPTION_FILTER prev_filter; - //prev_filter = SetUnhandledExceptionFilter(default_windows_exception_handler); - - // This sets a callback to handle w32 signals to the console window. - // The viewer shouldn't be affected, sicne its a windowed app. - SetConsoleCtrlHandler( (PHANDLER_ROUTINE) ConsoleCtrlHandler, TRUE); - -#else +#if !LL_WINDOWS // // Start up signal handling. // // There are two different classes of signals. Synchronous signals are delivered to a specific // thread, asynchronous signals can be delivered to any thread (in theory) // - setup_signals(); - +#endif // ! LL_WINDOWS +#if !defined(USE_CRASHPAD) + startErrorThread(); #endif - } void LLApp::startErrorThread() @@ -284,7 +319,7 @@ void LLApp::startErrorThread() // if(!mThreadErrorp) { - llinfos << "Starting error thread" << llendl; + LL_INFOS() << "Starting error thread" << LL_ENDL; mThreadErrorp = new LLErrorThread(); mThreadErrorp->setUserData((void *) this); mThreadErrorp->start(); @@ -301,7 +336,7 @@ void LLApp::stopErrorThread() } if (mThreadErrorp && !mThreadErrorp->isStopped()) { - llwarns << "Failed to stop Error Thread." << llendl; + LL_WARNS() << "Failed to stop Error Thread." << LL_ENDL; } } @@ -310,21 +345,6 @@ void LLApp::setErrorHandler(LLAppErrorHandler handler) LLApp::sErrorHandler = handler; } - -void LLApp::setSyncErrorHandler(LLAppErrorHandler handler) -{ - LLApp::sSyncErrorHandler = handler; -} - -// static -void LLApp::runSyncErrorHandler() -{ - if (LLApp::sSyncErrorHandler) - { - LLApp::sSyncErrorHandler(); - } -} - // static void LLApp::runErrorHandler() { @@ -333,11 +353,10 @@ void LLApp::runErrorHandler() LLApp::sErrorHandler(); } - //llinfos << "App status now STOPPED" << llendl; + //LL_INFOS() << "App status now STOPPED" << LL_ENDL; LLApp::setStopped(); } - // static void LLApp::setStatus(EAppStatus status) { @@ -348,15 +367,15 @@ void LLApp::setStatus(EAppStatus status) // static void LLApp::setError() { - if (!isError()) - { - // perform any needed synchronous error-handling - runSyncErrorHandler(); - // set app status to ERROR so that the LLErrorThread notices - setStatus(APP_STATUS_ERROR); - } + // set app status to ERROR so that the LLErrorThread notices + setStatus(APP_STATUS_ERROR); } +void LLApp::setDebugFileNames(const std::string &path) +{ + mStaticDebugFileName = path + "static_debug_info.log"; + mDynamicDebugFileName = path + "dynamic_debug_info.log"; +} // static void LLApp::setQuitting() @@ -364,7 +383,7 @@ void LLApp::setQuitting() if (!isExiting()) { // If we're already exiting, we don't want to reset our state back to quitting. - llinfos << "Setting app state to QUITTING" << llendl; + LL_INFOS() << "Setting app state to QUITTING" << LL_ENDL; setStatus(APP_STATUS_QUITTING); } } @@ -407,12 +426,11 @@ bool LLApp::isQuitting() // static bool LLApp::isExiting() { - return isQuitting() || isError(); + return isQuitting() || isError() || isStopped(); } void LLApp::disableCrashlogger() { - // Disable Breakpad exception handler. sDisableCrashlogger = TRUE; } @@ -466,7 +484,7 @@ LONG WINAPI default_windows_exception_handler(struct _EXCEPTION_POINTERS *except if (LLApp::isError()) { - llwarns << "Got another fatal signal while in the error handler, die now!" << llendl; + LL_WARNS() << "Got another fatal signal while in the error handler, die now!" << LL_ENDL; retval = EXCEPTION_EXECUTE_HANDLER; return retval; } @@ -481,12 +499,6 @@ LONG WINAPI default_windows_exception_handler(struct _EXCEPTION_POINTERS *except ms_sleep(10); } - // - // Generate a minidump if we can. - // - // TODO: This needs to be ported over form the viewer-specific - // LLWinDebug class - // // At this point, we always want to exit the app. There's no graceful // recovery for an unhandled exception. @@ -512,7 +524,7 @@ BOOL ConsoleCtrlHandler(DWORD fdwCtrlType) // We're already trying to die, just ignore this signal if (LLApp::sLogInSignal) { - llinfos << "Signal handler - Already trying to quit, ignoring signal!" << llendl; + LL_INFOS() << "Signal handler - Already trying to quit, ignoring signal!" << LL_ENDL; } return TRUE; } @@ -544,8 +556,8 @@ pid_t LLApp::fork() if( pid < 0 ) { int system_error = errno; - llwarns << "Unable to fork! Operating system error code: " - << system_error << llendl; + LL_WARNS() << "Unable to fork! Operating system error code: " + << system_error << LL_ENDL; } else if (pid == 0) { @@ -558,7 +570,7 @@ pid_t LLApp::fork() } else { - llinfos << "Forked child process " << pid << llendl; + LL_INFOS() << "Forked child process " << pid << LL_ENDL; } return pid; } @@ -649,7 +661,7 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *) if (LLApp::sLogInSignal) { - llinfos << "Signal handler - Got signal " << signum << " - " << apr_signal_description_get(signum) << llendl; + LL_INFOS() << "Signal handler - Got signal " << signum << " - " << apr_signal_description_get(signum) << LL_ENDL; } @@ -658,7 +670,7 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *) case SIGCHLD: if (LLApp::sLogInSignal) { - llinfos << "Signal handler - Got SIGCHLD from " << info->si_pid << llendl; + LL_INFOS() << "Signal handler - Got SIGCHLD from " << info->si_pid << LL_ENDL; } // Check result code for all child procs for which we've @@ -679,7 +691,7 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *) // Abort just results in termination of the app, no funky error handling. if (LLApp::sLogInSignal) { - llwarns << "Signal handler - Got SIGABRT, terminating" << llendl; + LL_WARNS() << "Signal handler - Got SIGABRT, terminating" << LL_ENDL; } clear_signals(); raise(signum); @@ -689,7 +701,7 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *) case SIGTERM: if (LLApp::sLogInSignal) { - llwarns << "Signal handler - Got SIGINT, HUP, or TERM, exiting gracefully" << llendl; + LL_WARNS() << "Signal handler - Got SIGINT, HUP, or TERM, exiting gracefully" << LL_ENDL; } // Graceful exit // Just set our state to quitting, not error @@ -698,7 +710,7 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *) // We're already trying to die, just ignore this signal if (LLApp::sLogInSignal) { - llinfos << "Signal handler - Already trying to quit, ignoring signal!" << llendl; + LL_INFOS() << "Signal handler - Already trying to quit, ignoring signal!" << LL_ENDL; } return; } @@ -720,7 +732,7 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *) // Smackdown treated just like any other app termination, for now if (LLApp::sLogInSignal) { - llwarns << "Signal handler - Handling smackdown signal!" << llendl; + LL_WARNS() << "Signal handler - Handling smackdown signal!" << LL_ENDL; } else { @@ -734,7 +746,7 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *) if (LLApp::sLogInSignal) { - llwarns << "Signal handler - Handling fatal signal!" << llendl; + LL_WARNS() << "Signal handler - Handling fatal signal!" << LL_ENDL; } if (LLApp::isError()) { @@ -744,7 +756,7 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *) if (LLApp::sLogInSignal) { - llwarns << "Signal handler - Got another fatal signal while in the error handler, die now!" << llendl; + LL_WARNS() << "Signal handler - Got another fatal signal while in the error handler, die now!" << LL_ENDL; } raise(signum); return; @@ -752,13 +764,13 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *) if (LLApp::sLogInSignal) { - llwarns << "Signal handler - Flagging error status and waiting for shutdown" << llendl; + LL_WARNS() << "Signal handler - Flagging error status and waiting for shutdown" << LL_ENDL; } if (LLApp::isCrashloggerDisabled()) // Don't gracefully handle any signal, crash and core for a gdb post mortem { clear_signals(); - llwarns << "Fatal signal received, not handling the crash here, passing back to operating system" << llendl; + LL_WARNS() << "Fatal signal received, not handling the crash here, passing back to operating system" << LL_ENDL; raise(signum); return; } @@ -773,7 +785,7 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *) if (LLApp::sLogInSignal) { - llwarns << "Signal handler - App is stopped, reraising signal" << llendl; + LL_WARNS() << "Signal handler - App is stopped, reraising signal" << LL_ENDL; } clear_signals(); raise(signum); @@ -781,10 +793,9 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *) } else { if (LLApp::sLogInSignal) { - llinfos << "Signal handler - Unhandled signal " << signum << ", ignoring!" << llendl; + LL_INFOS() << "Signal handler - Unhandled signal " << signum << ", ignoring!" << LL_ENDL; } } } } - #endif // !WINDOWS diff --git a/indra/llcommon/llapp.h b/indra/llcommon/llapp.h index d56e20800c..2a8fddfa23 100644 --- a/indra/llcommon/llapp.h +++ b/indra/llcommon/llapp.h @@ -37,14 +37,10 @@ template class LLAtomic32; typedef LLAtomic32 LLAtomicU32; class LLErrorThread; class LLLiveFile; - - #if LL_LINUX - #include - //typedef struct siginfo siginfo_t; //Removed as per changes in glibc 2.16 - Drake Arconis +#include #endif - typedef void (*LLAppErrorHandler)(); typedef void (*LLAppChildCallback)(int pid, bool exited, int status); @@ -212,11 +208,32 @@ class LL_COMMON_API LLApp : public LLOptionInterface #endif static int getPid(); - // - // Error handling methods - // + /** @name Error handling methods */ + //@{ + /** + * @brief Do our generic platform-specific error-handling setup -- + * signals on unix, structured exceptions on windows. + * + * DO call this method if your app will either spawn children or be + * spawned by a launcher. + * Call just after app object construction. + * (Otherwise your app will crash when getting signals, + * and will not core dump.) + * + * DO NOT call this method if your application has specialized + * error handling code. + */ + void setupErrorHandling(); + void setErrorHandler(LLAppErrorHandler handler); - void setSyncErrorHandler(LLAppErrorHandler handler); + static void runErrorHandler(); // run shortly after we detect an error, ran in the relatively robust context of the LLErrorThread - preferred. + //@} + + void setDebugFileNames(const std::string &path); + + std::string* getStaticDebugFile() { return &mStaticDebugFileName; } + std::string* getDynamicDebugFile() { return &mDynamicDebugFileName; } + #if !LL_WINDOWS // // Child process handling (Unix only for now) @@ -236,6 +253,7 @@ class LL_COMMON_API LLApp : public LLOptionInterface pid_t fork(); #endif + public: typedef std::map string_map; string_map mOptionMap; // Contains all command-line options and arguments in a map @@ -246,6 +264,7 @@ class LL_COMMON_API LLApp : public LLOptionInterface static EAppStatus sStatus; // Reflects current application status static BOOL sErrorThreadRunning; // Set while the error thread is running static BOOL sDisableCrashlogger; // Let the OS handle crashes for us. + std::wstring mCrashReportPipeStr; //Name of pipe to use for crash reporting. #if !LL_WINDOWS static LLAtomicU32* sSigChildCount; // Number of SIGCHLDs received. @@ -254,26 +273,22 @@ class LL_COMMON_API LLApp : public LLOptionInterface static LLAppChildCallback sDefaultChildCallback; #endif - /** - * @ brief This method is called once as soon as logging is initialized. - */ - void startErrorThread(); /** * @brief This method is called at the end, just prior to deinitializing curl. */ void stopErrorThread(); private: - void setupErrorHandling(); // Do platform-specific error-handling setup (signals, structured exceptions) - static void runErrorHandler(); // run shortly after we detect an error, ran in the relatively robust context of the LLErrorThread - preferred. - static void runSyncErrorHandler(); // run IMMEDIATELY when we get an error, ran in the context of the faulting thread. + void startErrorThread(); + + std::string mStaticDebugFileName; + std::string mDynamicDebugFileName; // *NOTE: On Windows, we need a routine to reset the structured // exception handler when some evil driver has taken it over for // their own purposes typedef int(*signal_handler_func)(int signum); static LLAppErrorHandler sErrorHandler; - static LLAppErrorHandler sSyncErrorHandler; // Default application threads LLErrorThread* mThreadErrorp; // Waits for app to go to status ERROR, then runs the error callback @@ -288,11 +303,9 @@ class LL_COMMON_API LLApp : public LLOptionInterface std::vector mLiveFiles; //@} -private: // the static application instance if it was created. static LLApp* sApplication; - #if !LL_WINDOWS friend void default_unix_signal_handler(int signum, siginfo_t *info, void *); #endif diff --git a/indra/llcommon/llapr.cpp b/indra/llcommon/llapr.cpp index 4b86fecdf7..a1a445261a 100644 --- a/indra/llcommon/llapr.cpp +++ b/indra/llcommon/llapr.cpp @@ -29,60 +29,7 @@ #include "linden_common.h" #include "llapr.h" #include "llscopedvolatileaprpool.h" - -LLFastTimer::DeclareTimer FT_WAIT_FOR_SCOPEDLOCK("LLScopedLock"); - -//--------------------------------------------------------------------- -// -// LLScopedLock -// -LLScopedLock::LLScopedLock(apr_thread_mutex_t* mutex) : mMutex(mutex) -{ - mLocked = !!mutex; - if (LL_LIKELY(mutex)) - { - apr_status_t status = apr_thread_mutex_trylock(mMutex); - while (LL_UNLIKELY(status != APR_SUCCESS)) - { - if (APR_STATUS_IS_EBUSY(status)) - { - if (AIThreadID::in_main_thread_inline()) - { - LLFastTimer ft1(FT_WAIT_FOR_SCOPEDLOCK); - status = apr_thread_mutex_lock(mMutex); - } - else - { - status = apr_thread_mutex_lock(mMutex); - } - } - else - { - ll_apr_warn_status(status); - mLocked = false; - return; - } - } - } -} - -LLScopedLock::~LLScopedLock() -{ - unlock(); -} - -void LLScopedLock::unlock() -{ - if(mLocked) - { - if(!ll_apr_warn_status(apr_thread_mutex_unlock(mMutex))) - { - mLocked = false; - } - } -} - -//--------------------------------------------------------------------- +#include bool ll_apr_warn_status(apr_status_t status) { @@ -204,11 +151,11 @@ apr_status_t LLAPRFile::open(const std::string& filename, apr_int32_t flags, BOO return open(filename, flags, use_global_pool ? LLAPRFile::long_lived : LLAPRFile::short_lived); } // File I/O -S32 LLAPRFile::read(void *buf, S32 nbytes) +S32 LLAPRFile::read(void *buf, U64 nbytes) { if(!mFile) { - llwarns << "apr mFile is removed by somebody else. Can not read." << llendl ; + LL_WARNS() << "apr mFile is removed by somebody else. Can not read." << LL_ENDL ; return 0; } @@ -221,16 +168,16 @@ S32 LLAPRFile::read(void *buf, S32 nbytes) } else { - llassert_always(sz <= 0x7fffffff); + llassert_always(sz <= std::numeric_limits::max()); return (S32)sz; } } -S32 LLAPRFile::write(const void *buf, S32 nbytes) +S32 LLAPRFile::write(const void *buf, U64 nbytes) { if(!mFile) { - llwarns << "apr mFile is removed by somebody else. Can not write." << llendl ; + LL_WARNS() << "apr mFile is removed by somebody else. Can not write." << LL_ENDL ; return 0; } @@ -243,7 +190,7 @@ S32 LLAPRFile::write(const void *buf, S32 nbytes) } else { - llassert_always(sz <= 0x7fffffff); + llassert_always(sz <= std::numeric_limits::max()); return (S32)sz; } } diff --git a/indra/llcommon/llapr.h b/indra/llcommon/llapr.h index 97aa96e0bb..03a010d6c4 100644 --- a/indra/llcommon/llapr.h +++ b/indra/llcommon/llapr.h @@ -33,58 +33,17 @@ #include // Need PATH_MAX in APR headers... #endif +#include "llwin32headerslean.h" + #include #include "apr_thread_proc.h" -#include "apr_thread_mutex.h" #include "apr_getopt.h" -#include "apr_signal.h" -#include "apr_atomic.h" #include "llstring.h" class LLAPRPool; class LLVolatileAPRPool; -/** - * @class LLScopedLock - * @brief Small class to help lock and unlock mutexes. - * - * This class is used to have a stack level lock once you already have - * an apr mutex handy. The constructor handles the lock, and the - * destructor handles the unlock. Instances of this class are - * not thread safe. - */ -class LL_COMMON_API LLScopedLock : private boost::noncopyable -{ -public: - /** - * @brief Constructor which accepts a mutex, and locks it. - * - * @param mutex An allocated APR mutex. If you pass in NULL, - * this wrapper will not lock. - */ - LLScopedLock(apr_thread_mutex_t* mutex); - - /** - * @brief Destructor which unlocks the mutex if still locked. - */ - ~LLScopedLock(); - - /** - * @brief Check lock. - */ - bool isLocked() const { return mLocked; } - - /** - * @brief This method unlocks the mutex. - */ - void unlock(); - -protected: - bool mLocked; - apr_thread_mutex_t* mMutex; -}; - // File IO convenience functions. // Returns NULL if the file fails to open, sets *sizep to file size if not NULL // abbreviated flags @@ -135,8 +94,8 @@ class LL_COMMON_API LLAPRFile : boost::noncopyable apr_status_t eof() { return apr_file_eof(mFile);} // Returns bytes read/written, 0 if read/write fails: - S32 read(void* buf, S32 nbytes); - S32 write(const void* buf, S32 nbytes); + S32 read(void* buf, U64 nbytes); + S32 write(const void* buf, U64 nbytes); apr_file_t* getFileHandle() {return mFile;} diff --git a/indra/llcommon/llaprpool.cpp b/indra/llcommon/llaprpool.cpp index 3dffa83002..b065a58019 100644 --- a/indra/llcommon/llaprpool.cpp +++ b/indra/llcommon/llaprpool.cpp @@ -37,6 +37,7 @@ #include "llerror.h" #include "llaprpool.h" +#include "llatomic.h" #include "llthread.h" // Create a subpool from parent. @@ -110,23 +111,18 @@ LLAPRInitialization::LLAPRInitialization(void) } bool LLAPRRootPool::sCountInitialized = false; -apr_uint32_t volatile LLAPRRootPool::sCount; - -apr_thread_mutex_t* gLogMutexp; -apr_thread_mutex_t* gCallStacksLogMutexp; +LLAtomicS32 LLAPRRootPool::sCount; LLAPRRootPool::LLAPRRootPool(void) : LLAPRInitialization(), LLAPRPool(0) { // sCountInitialized don't need locking because when we get here there is still only a single thread. if (!sCountInitialized) { - // Initialize the logging mutex - apr_thread_mutex_create(&gLogMutexp, APR_THREAD_MUTEX_UNNESTED, mPool); - apr_thread_mutex_create(&gCallStacksLogMutexp, APR_THREAD_MUTEX_UNNESTED, mPool); - +#ifdef NEEDS_APR_ATOMICS apr_status_t status = apr_atomic_init(mPool); llassert_always(status == APR_SUCCESS); - apr_atomic_set32(&sCount, 1); // Set to 1 to account for the global root pool. +#endif + sCount = 1; // Set to 1 to account for the global root pool. sCountInitialized = true; // Initialize thread-local APR pool support. @@ -134,33 +130,16 @@ LLAPRRootPool::LLAPRRootPool(void) : LLAPRInitialization(), LLAPRPool(0) // it must be done last, so that sCount is already initialized. LLThreadLocalData::init(); } - apr_atomic_inc32(&sCount); + sCount++; } LLAPRRootPool::~LLAPRRootPool() { - if (!apr_atomic_dec32(&sCount)) + if (!--sCount) { // The last pool was destructed. Cleanup remainder of APR. LL_INFOS("APR") << "Cleaning up APR" << LL_ENDL; - if (gLogMutexp) - { - // Clean up the logging mutex - - // All other threads NEED to be done before we clean up APR, so this is okay. - apr_thread_mutex_destroy(gLogMutexp); - gLogMutexp = NULL; - } - if (gCallStacksLogMutexp) - { - // Clean up the logging mutex - - // All other threads NEED to be done before we clean up APR, so this is okay. - apr_thread_mutex_destroy(gCallStacksLogMutexp); - gCallStacksLogMutexp = NULL; - } - // Must destroy ALL, and therefore this last LLAPRRootPool, before terminating APR. static_cast(this)->destroy(); diff --git a/indra/llcommon/llaprpool.h b/indra/llcommon/llaprpool.h index 74af351e42..d3606d3964 100644 --- a/indra/llcommon/llaprpool.h +++ b/indra/llcommon/llaprpool.h @@ -47,9 +47,11 @@ #include "apr_portable.h" #include "apr_pools.h" +#include "llatomic.h" #include "llerror.h" #include "aithreadid.h" + extern void ll_init_apr(); /** @@ -104,8 +106,11 @@ class LL_COMMON_API LLAPRPool // NEVER destroy a pool that is returned by this function! apr_pool_t* operator()(void) const { - llassert(mPool); - llassert(mOwner.equals_current_thread()); + if (mParent) + { + llassert(mPool); + llassert(mOwner.equals_current_thread()); + } return mPool; } @@ -181,7 +186,7 @@ class LL_COMMON_API LLAPRRootPool : public LLAPRInitialization, public LLAPRPool private: // Keep track of how many root pools exist and when the last one is destructed. static bool sCountInitialized; - static apr_uint32_t volatile sCount; + static LLAtomicS32 sCount; public: // Return a global root pool that is independent of LLThreadLocalData. diff --git a/indra/llcommon/llassettype.cpp b/indra/llcommon/llassettype.cpp index 5b22d5babb..66602f4e74 100644 --- a/indra/llcommon/llassettype.cpp +++ b/indra/llcommon/llassettype.cpp @@ -101,6 +101,9 @@ LLAssetDictionary::LLAssetDictionary() addEntry(LLAssetType::AT_OUTFIT, new AssetEntry("OUTFIT", "outfit", "outfit", false, false, false)); addEntry(LLAssetType::AT_MY_OUTFITS, new AssetEntry("MY_OUTFITS", "my_otfts", "my outfits", false, false, false)); addEntry(LLAssetType::AT_MESH, new AssetEntry("MESH", "mesh", "mesh", false, true, true)); + addEntry(LLAssetType::AT_SETTINGS, new AssetEntry("SETTINGS", "settings", "settings blob", true, true, true)); + + addEntry(LLAssetType::AT_UNKNOWN, new AssetEntry("UNKNOWN", "invalid", NULL, false, false, false)); addEntry(LLAssetType::AT_NONE, new AssetEntry("NONE", "-1", NULL, false, false, false)); }; diff --git a/indra/llcommon/llassettype.h b/indra/llcommon/llassettype.h index e6fee54ca8..9435eeb2b0 100644 --- a/indra/llcommon/llassettype.h +++ b/indra/llcommon/llassettype.h @@ -122,6 +122,9 @@ class LL_COMMON_API LLAssetType AT_LINK_FOLDER = 25, // Inventory folder link + + AT_MARKETPLACE_FOLDER = 26, + // Marketplace folder. Same as an AT_CATEGORY but different display methods. AT_CURRENT_OUTFIT = 46, @@ -132,7 +135,16 @@ class LL_COMMON_API LLAssetType AT_MESH = 49, // Mesh data in our proprietary SLM format - AT_COUNT = 50, + AT_RESERVED_1 = 50, + AT_RESERVED_2 = 51, + AT_RESERVED_3 = 52, + AT_RESERVED_4 = 53, + AT_RESERVED_5 = 54, + AT_RESERVED_6 = 55, + + AT_SETTINGS = 56, // Collection of settings + + AT_COUNT = 57, // +*********************************************************+ // | TO ADD AN ELEMENT TO THIS ENUM: | @@ -143,7 +155,7 @@ class LL_COMMON_API LLAssetType // | 4. ADD TO LLViewerAssetType.cpp | // | 5. ADD TO DEFAULT_ASSET_FOR_INV in LLInventoryType.cpp | // +*********************************************************+ - + AT_UNKNOWN = 255, AT_NONE = -1 }; diff --git a/indra/llcommon/llatomic.h b/indra/llcommon/llatomic.h index 3cc5bcf386..e9a88a7b61 100644 --- a/indra/llcommon/llatomic.h +++ b/indra/llcommon/llatomic.h @@ -34,8 +34,29 @@ #ifndef LL_LLATOMIC_H #define LL_LLATOMIC_H -#include "apr_atomic.h" +#define USE_BOOST_ATOMIC + +//Internal definitions +#define NEEDS_APR_ATOMICS do_not_define_manually_thanks +#undef NEEDS_APR_ATOMICS + +#if defined(USE_BOOST_ATOMIC) +#include "boost/version.hpp" +#endif +//Prefer boost over stl over apr. + +#if defined(USE_BOOST_ATOMIC) && (BOOST_VERSION >= 105300) +#include "boost/atomic.hpp" +template +struct impl_atomic_type { typedef boost::atomic type; }; +#elif defined(USE_STD_ATOMIC) +#include +template +struct impl_atomic_type { typedef std::atomic type; }; +#else +#include "apr_atomic.h" +#define NEEDS_APR_ATOMICS template class LLAtomic32 { public: @@ -54,6 +75,27 @@ template class LLAtomic32 private: apr_uint32_t mData; }; +#endif +#if !defined(NEEDS_APR_ATOMICS) +template class LLAtomic32 +{ +public: + LLAtomic32(void) { } + LLAtomic32(LLAtomic32 const& atom) { mData = Type(atom.mData); } + LLAtomic32(Type x) { mData = x; } + LLAtomic32& operator=(LLAtomic32 const& atom) { mData = Type(atom.mData); return *this; } + + operator Type() const { return mData; } + void operator=(Type x) { mData = x; } + void operator-=(Type x) { mData -= x; } + void operator+=(Type x) { mData += x; } + Type operator++(int) { return mData++; } // Type++ + bool operator--() { return --mData; } // Returns (--Type != 0) + +private: + typename impl_atomic_type::type mData; +}; +#endif typedef LLAtomic32 LLAtomicU32; typedef LLAtomic32 LLAtomicS32; diff --git a/indra/llcommon/llavatarconstants.h b/indra/llcommon/llavatarconstants.h index 867d6bdbf3..6e7a492457 100644 --- a/indra/llcommon/llavatarconstants.h +++ b/indra/llcommon/llavatarconstants.h @@ -44,14 +44,6 @@ const char* const BLACKLIST_PROFILE_WEB_URL = "http://secondlife.com/app/webdisa // Maximum number of avatar picks const S32 MAX_AVATAR_PICKS = 10; -// For Flags in AvatarPropertiesReply -const U32 AVATAR_ALLOW_PUBLISH = 0x1 << 0; // whether profile is externally visible or not -const U32 AVATAR_MATURE_PUBLISH = 0x1 << 1; // profile is "mature" -const U32 AVATAR_IDENTIFIED = 0x1 << 2; // whether avatar has provided payment info -const U32 AVATAR_TRANSACTED = 0x1 << 3; // whether avatar has actively used payment info -const U32 AVATAR_ONLINE = 0x1 << 4; // the online status of this avatar, if known. -const U32 AVATAR_AGEVERIFIED = 0x1 << 5; // whether avatar has been age-verified - char const* const VISIBILITY_DEFAULT = "default"; char const* const VISIBILITY_HIDDEN = "hidden"; char const* const VISIBILITY_VISIBLE = "visible"; diff --git a/indra/llcommon/llavatarname.cpp b/indra/llcommon/llavatarname.cpp deleted file mode 100644 index cce8d33b40..0000000000 --- a/indra/llcommon/llavatarname.cpp +++ /dev/null @@ -1,115 +0,0 @@ -/** - * @file llavatarname.cpp - * @brief Represents name-related data for an avatar, such as the - * username/SLID ("bobsmith123" or "james.linden") and the display - * name ("James Cook") - * - * $LicenseInfo:firstyear=2010&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ -#include "linden_common.h" - -#include "llavatarname.h" - -#include "lldate.h" -#include "llsd.h" - -// Store these in pre-built std::strings to avoid memory allocations in -// LLSD map lookups -static const std::string USERNAME("username"); -static const std::string DISPLAY_NAME("display_name"); -static const std::string LEGACY_FIRST_NAME("legacy_first_name"); -static const std::string LEGACY_LAST_NAME("legacy_last_name"); -static const std::string IS_DISPLAY_NAME_DEFAULT("is_display_name_default"); -static const std::string DISPLAY_NAME_EXPIRES("display_name_expires"); -static const std::string DISPLAY_NAME_NEXT_UPDATE("display_name_next_update"); - -LLAvatarName::LLAvatarName() -: mUsername(), - mDisplayName(), - mLegacyFirstName(), - mLegacyLastName(), - mIsDisplayNameDefault(false), - mIsTemporaryName(false), - mExpires(F64_MAX), - mNextUpdate(0.0) -{ } - -bool LLAvatarName::operator<(const LLAvatarName& rhs) const -{ - if (mUsername == rhs.mUsername) - return mDisplayName < rhs.mDisplayName; - else - return mUsername < rhs.mUsername; -} - -LLSD LLAvatarName::asLLSD() const -{ - LLSD sd; - sd[USERNAME] = mUsername; - sd[DISPLAY_NAME] = mDisplayName; - sd[LEGACY_FIRST_NAME] = mLegacyFirstName; - sd[LEGACY_LAST_NAME] = mLegacyLastName; - sd[IS_DISPLAY_NAME_DEFAULT] = mIsDisplayNameDefault; - sd[DISPLAY_NAME_EXPIRES] = LLDate(mExpires); - sd[DISPLAY_NAME_NEXT_UPDATE] = LLDate(mNextUpdate); - return sd; -} - -void LLAvatarName::fromLLSD(const LLSD& sd) -{ - mUsername = sd[USERNAME].asString(); - mDisplayName = sd[DISPLAY_NAME].asString(); - mLegacyFirstName = sd[LEGACY_FIRST_NAME].asString(); - mLegacyLastName = sd[LEGACY_LAST_NAME].asString(); - mIsDisplayNameDefault = sd[IS_DISPLAY_NAME_DEFAULT].asBoolean(); - LLDate expires = sd[DISPLAY_NAME_EXPIRES]; - mExpires = expires.secondsSinceEpoch(); - LLDate next_update = sd[DISPLAY_NAME_NEXT_UPDATE]; - mNextUpdate = next_update.secondsSinceEpoch(); -} - -std::string LLAvatarName::getCompleteName(bool linefeed) const -{ - std::string name; - if (mUsername.empty() || mIsDisplayNameDefault) - // If the display name feature is off - // OR this particular display name is defaulted (i.e. based on user name), - // then display only the easier to read instance of the person's name. - { - name = mDisplayName; - } - else - { - name = mDisplayName + (linefeed ? "\n(" : " (") + mUsername + ")"; - } - return name; -} - -std::string LLAvatarName::getLegacyName() const -{ - std::string name; - name.reserve( mLegacyFirstName.size() + 1 + mLegacyLastName.size() ); - name = mLegacyFirstName; - name += " "; - name += mLegacyLastName; - return name; -} diff --git a/indra/llcommon/llavatarname.h b/indra/llcommon/llavatarname.h deleted file mode 100644 index ee3a680e5a..0000000000 --- a/indra/llcommon/llavatarname.h +++ /dev/null @@ -1,95 +0,0 @@ -/** - * @file llavatarname.h - * @brief Represents name-related data for an avatar, such as the - * username/SLID ("bobsmith123" or "james.linden") and the display - * name ("James Cook") - * - * $LicenseInfo:firstyear=2010&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ -#ifndef LLAVATARNAME_H -#define LLAVATARNAME_H - -#include - -class LLSD; - -class LL_COMMON_API LLAvatarName -{ -public: - LLAvatarName(); - - bool operator<(const LLAvatarName& rhs) const; - - LLSD asLLSD() const; - - void fromLLSD(const LLSD& sd); - - // For normal names, returns "James Linden (james.linden)" - // When display names are disabled returns just "James Linden" - std::string getCompleteName(bool linefeed = false) const; - - // Returns "James Linden" or "bobsmith123 Resident" for backwards - // compatibility with systems like voice and muting - // *TODO: Eliminate this in favor of username only - std::string getLegacyName() const; - - // "bobsmith123" or "james.linden", US-ASCII only - std::string mUsername; - - // "Jose' Sanchez" or "James Linden", UTF-8 encoded Unicode - // Contains data whether or not user has explicitly set - // a display name; may duplicate their username. - std::string mDisplayName; - - // For "James Linden", "James" - // For "bobsmith123", "bobsmith123" - // Used to communicate with legacy systems like voice and muting which - // rely on old-style names. - // *TODO: Eliminate this in favor of username only - std::string mLegacyFirstName; - - // For "James Linden", "Linden" - // For "bobsmith123", "Resident" - // see above for rationale - std::string mLegacyLastName; - - // If true, both display name and SLID were generated from - // a legacy first and last name, like "James Linden (james.linden)" - bool mIsDisplayNameDefault; - - // Under error conditions, we may insert "dummy" records with - // names like "???" into caches as placeholders. These can be - // shown in UI, but are not serialized. - bool mIsTemporaryName; - - // Names can change, so need to keep track of when name was - // last checked. - // Unix time-from-epoch seconds for efficiency - F64 mExpires; - - // You can only change your name every N hours, so record - // when the next update is allowed - // Unix time-from-epoch seconds - F64 mNextUpdate; -}; - -#endif diff --git a/indra/llcommon/llbase32.cpp b/indra/llcommon/llbase32.cpp index 5e6ced9ce1..59d150152e 100644 --- a/indra/llcommon/llbase32.cpp +++ b/indra/llcommon/llbase32.cpp @@ -237,8 +237,8 @@ std::string LLBase32::encode(const U8* input, size_t input_size) size_t encoded = base32_encode(&output[0], output_size, input, input_size); - llinfos << "encoded " << encoded << " into buffer of size " - << output_size << llendl; + LL_INFOS() << "encoded " << encoded << " into buffer of size " + << output_size << LL_ENDL; } return output; } diff --git a/indra/llcommon/llbase32.h b/indra/llcommon/llbase32.h index 0697f7b8e2..417cd930ad 100644 --- a/indra/llcommon/llbase32.h +++ b/indra/llcommon/llbase32.h @@ -3,31 +3,25 @@ * @brief base32 encoding that returns a std::string * @author James Cook * - * $LicenseInfo:firstyear=2007&license=viewergpl$ - * - * Copyright (c) 2007-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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$ */ diff --git a/indra/llcommon/llbase64.cpp b/indra/llcommon/llbase64.cpp index 7020a79a22..bab8b1a310 100644 --- a/indra/llcommon/llbase64.cpp +++ b/indra/llcommon/llbase64.cpp @@ -3,65 +3,103 @@ * @brief Wrapper for apr base64 encoding that returns a std::string * @author James Cook * - * $LicenseInfo:firstyear=2007&license=viewergpl$ - * - * Copyright (c) 2007-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #include "linden_common.h" #include "llbase64.h" +#include + +// static +std::string LLBase64::encode(const U8* input, size_t input_size) +{ + if (!(input && input_size > 0)) return LLStringUtil::null; + + BIO *b64 = BIO_new(BIO_f_base64()); + BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); + + BIO *bio = BIO_new(BIO_s_mem()); + BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); + bio = BIO_push(b64, bio); + BIO_write(bio, input, input_size); + + (void)BIO_flush(bio); + + char *new_data; + size_t bytes_written = BIO_get_mem_data(bio, &new_data); + std::string result(new_data, bytes_written); + BIO_free_all(bio); + + return result; +} -#include +// static +std::string LLBase64::encode(const std::string& in_str) +{ + size_t data_size = in_str.size(); + std::vector data; + data.resize(data_size); + memcpy(&data[0], in_str.c_str(), data_size); + return encode(&data[0], data_size); +} -#include "apr_base64.h" +// static +size_t LLBase64::decode(const std::string& input, U8 * buffer, size_t buffer_size) +{ + if (input.empty()) return 0; + + BIO *b64 = BIO_new(BIO_f_base64()); + BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); + + // BIO_new_mem_buf is not const aware, but it doesn't modify the buffer + BIO *bio = BIO_new_mem_buf(const_cast(input.c_str()), input.length()); + bio = BIO_push(b64, bio); + size_t bytes_written = BIO_read(bio, buffer, buffer_size); + BIO_free_all(bio); + + return bytes_written; +} +std::string LLBase64::decode(const std::string& input) +{ + U32 buffer_len = LLBase64::requiredDecryptionSpace(input); + std::vector buffer(buffer_len); + buffer_len = LLBase64::decode(input, &buffer[0], buffer_len); + buffer.resize(buffer_len); + return std::string(reinterpret_cast(&buffer[0]), buffer_len); +} // static -std::string LLBase64::encode(const U8* input, size_t input_size) +size_t LLBase64::requiredDecryptionSpace(const std::string& str) { - std::string output; - if (input - && input_size > 0) - { - // Yes, it returns int. - int b64_buffer_length = apr_base64_encode_len(input_size); - char* b64_buffer = new char[b64_buffer_length]; - - // This is faster than apr_base64_encode() if you know - // you're not on an EBCDIC machine. Also, the output is - // null terminated, even though the documentation doesn't - // specify. See apr_base64.c for details. JC - b64_buffer_length = apr_base64_encode_binary( - b64_buffer, - input, - input_size); - output.assign(b64_buffer); - delete[] b64_buffer; - } - return output; + size_t len = str.length(); + U32 padding = 0; + + if (str[len - 1] == '=' && str[len - 2] == '=') //last two chars are = + padding = 2; + else if (str[len - 1] == '=') //last char is = + padding = 1; + + return len * 0.75 - padding; } diff --git a/indra/llcommon/llbase64.h b/indra/llcommon/llbase64.h index c48fea2478..74e5b46452 100644 --- a/indra/llcommon/llbase64.h +++ b/indra/llcommon/llbase64.h @@ -3,31 +3,25 @@ * @brief Wrapper for apr base64 encoding that returns a std::string * @author James Cook * - * $LicenseInfo:firstyear=2007&license=viewergpl$ - * - * Copyright (c) 2007-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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$ */ @@ -37,7 +31,11 @@ class LL_COMMON_API LLBase64 { public: + static std::string encode(const std::string& in_str); static std::string encode(const U8* input, size_t input_size); + static size_t decode(const std::string& input, U8 * buffer, size_t buffer_size); + static std::string decode(const std::string& input); + static size_t requiredDecryptionSpace(const std::string& str); }; #endif diff --git a/indra/llcommon/llcallbacklist.cpp b/indra/llcommon/llcallbacklist.cpp new file mode 100644 index 0000000000..1876eedd18 --- /dev/null +++ b/indra/llcommon/llcallbacklist.cpp @@ -0,0 +1,229 @@ +/** + * @file llcallbacklist.cpp + * @brief A simple list of callback functions to call. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llcallbacklist.h" +#include "lleventtimer.h" +#include "llerrorlegacy.h" + +// Globals +// +LLCallbackList gIdleCallbacks; + +// +// Member functions +// + +LLCallbackList::LLCallbackList() +{ + // nothing +} + +LLCallbackList::~LLCallbackList() +{ +} + + +void LLCallbackList::addFunction( callback_t func, void *data) +{ + if (!func) + { + return; + } + + // only add one callback per func/data pair + // + if (containsFunction(func)) + { + return; + } + + callback_pair_t t(func, data); + mCallbackList.push_back(t); +} + +bool LLCallbackList::containsFunction( callback_t func, void *data) +{ + callback_list_t::iterator iter = find(func,data); + if (iter != mCallbackList.end()) + { + return TRUE; + } + else + { + return FALSE; + } +} + + +bool LLCallbackList::deleteFunction( callback_t func, void *data) +{ + callback_list_t::iterator iter = find(func,data); + if (iter != mCallbackList.end()) + { + mCallbackList.erase(iter); + return TRUE; + } + else + { + return FALSE; + } +} + +inline +LLCallbackList::callback_list_t::iterator +LLCallbackList::find(callback_t func, void *data) +{ + callback_pair_t t(func, data); + return std::find(mCallbackList.begin(), mCallbackList.end(), t); +} + +void LLCallbackList::deleteAllFunctions() +{ + mCallbackList.clear(); +} + + +void LLCallbackList::callFunctions() +{ + for (callback_list_t::iterator iter = mCallbackList.begin(); iter != mCallbackList.end(); ) + { + callback_list_t::iterator curiter = iter++; + curiter->first(curiter->second); + } +} + +// Shim class to allow arbitrary boost::bind +// expressions to be run as one-time idle callbacks. +class OnIdleCallbackOneTime +{ +public: + OnIdleCallbackOneTime(nullary_func_t callable): + mCallable(callable) + { + } + static void onIdle(void *data) + { + gIdleCallbacks.deleteFunction(onIdle, data); + OnIdleCallbackOneTime* self = reinterpret_cast(data); + self->call(); + delete self; + } + void call() + { + mCallable(); + } +private: + nullary_func_t mCallable; +}; + +void doOnIdleOneTime(nullary_func_t callable) +{ + OnIdleCallbackOneTime* cb_functor = new OnIdleCallbackOneTime(callable); + gIdleCallbacks.addFunction(&OnIdleCallbackOneTime::onIdle,cb_functor); +} + +// Shim class to allow generic boost functions to be run as +// recurring idle callbacks. Callable should return true when done, +// false to continue getting called. +class OnIdleCallbackRepeating +{ +public: + OnIdleCallbackRepeating(bool_func_t callable): + mCallable(callable) + { + } + // Will keep getting called until the callable returns true. + static void onIdle(void *data) + { + OnIdleCallbackRepeating* self = reinterpret_cast(data); + bool done = self->call(); + if (done) + { + gIdleCallbacks.deleteFunction(onIdle, data); + delete self; + } + } + bool call() + { + return mCallable(); + } +private: + bool_func_t mCallable; +}; + +void doOnIdleRepeating(bool_func_t callable) +{ + OnIdleCallbackRepeating* cb_functor = new OnIdleCallbackRepeating(callable); + gIdleCallbacks.addFunction(&OnIdleCallbackRepeating::onIdle,cb_functor); +} + +class NullaryFuncEventTimer: public LLEventTimer +{ +public: + NullaryFuncEventTimer(nullary_func_t callable, F32 seconds): + LLEventTimer(seconds), + mCallable(callable) + { + } + +private: + BOOL tick() + { + mCallable(); + return TRUE; + } + + nullary_func_t mCallable; +}; + +// Call a given callable once after specified interval. +void doAfterInterval(nullary_func_t callable, F32 seconds) +{ + new NullaryFuncEventTimer(callable, seconds); +} + +class BoolFuncEventTimer: public LLEventTimer +{ +public: + BoolFuncEventTimer(bool_func_t callable, F32 seconds): + LLEventTimer(seconds), + mCallable(callable) + { + } +private: + BOOL tick() + { + return mCallable(); + } + + bool_func_t mCallable; +}; + +// Call a given callable every specified number of seconds, until it returns true. +void doPeriodically(bool_func_t callable, F32 seconds) +{ + new BoolFuncEventTimer(callable, seconds); +} diff --git a/indra/newview/llcallbacklist.h b/indra/llcommon/llcallbacklist.h similarity index 76% rename from indra/newview/llcallbacklist.h rename to indra/llcommon/llcallbacklist.h index 0516c9cdb4..1fdb8ca095 100644 --- a/indra/newview/llcallbacklist.h +++ b/indra/llcommon/llcallbacklist.h @@ -28,27 +28,35 @@ #define LL_LLCALLBACKLIST_H #include "llstl.h" +#include +#include +#include "stdtypes.h" class LLCallbackList { public: typedef void (*callback_t)(void*); + + typedef std::pair< callback_t,void* > callback_pair_t; + // NOTE: It is confirmed that we DEPEND on the order provided by using a list :( + // + typedef std::list< callback_pair_t > callback_list_t; LLCallbackList(); ~LLCallbackList(); - void addFunction( callback_t func, void *data = NULL ); // register a callback, which will be called as func(data) - BOOL containsFunction( callback_t func, void *data = NULL ); // true if list already contains the function/data pair - BOOL deleteFunction( callback_t func, void *data = NULL ); // removes the first instance of this function/data pair from the list, false if not found - void callFunctions(); // calls all functions + void addFunction( callback_t func, void *data = NULL ); // register a callback, which will be called as func(data) + bool containsFunction( callback_t func, void *data = NULL ); // true if list already contains the function/data pair + bool deleteFunction( callback_t func, void *data = NULL ); // removes the first instance of this function/data pair from the list, false if not found + void callFunctions(); // calls all functions void deleteAllFunctions(); static void test(); protected: - // Use a list so that the callbacks are ordered in case that matters - typedef std::pair callback_pair_t; - typedef std::list callback_list_t; + + inline callback_list_t::iterator find(callback_t func, void *data); + callback_list_t mCallbackList; }; diff --git a/indra/llcommon/llcoros.cpp b/indra/llcommon/llcoros.cpp index 0b5829eb7e..baaddcaed1 100644 --- a/indra/llcommon/llcoros.cpp +++ b/indra/llcommon/llcoros.cpp @@ -39,7 +39,12 @@ #include "llerror.h" #include "stringize.h" -LLCoros::LLCoros() +LLCoros::LLCoros(): + // MAINT-2724: default coroutine stack size too small on Windows. + // Previously we used + // boost::context::guarded_stack_allocator::default_stacksize(); + // empirically this is 64KB on Windows and Linux. Try quadrupling. + mStackSize(256*1024) { // Register our cleanup() method for "mainloop" ticks LLEventPumps::instance().obtain("mainloop").listen( @@ -55,7 +60,7 @@ bool LLCoros::cleanup(const LLSD&) // since last tick? if (mi->second->exited()) { - LL_INFOS("LLCoros") << "LLCoros: cleaning up coroutine " << mi->first << LL_ENDL; + LL_INFOS("LLCoros") << "LLCoros: cleaning up coroutine " << mi->first << LL_ENDL; // The erase() call will invalidate its passed iterator value -- // so increment mi FIRST -- but pass its original value to // erase(). This is what postincrement is all about. @@ -89,7 +94,7 @@ std::string LLCoros::generateDistinctName(const std::string& prefix) const { if (mCoros.find(name) == mCoros.end()) { - LL_INFOS("LLCoros") << "LLCoros: launching coroutine " << name << LL_ENDL; + LL_INFOS("LLCoros") << "LLCoros: launching coroutine " << name << LL_ENDL; return name; } } @@ -115,7 +120,7 @@ std::string LLCoros::getNameByID(const void* self_id) const // passed to us comes. for (CoroMap::const_iterator mi(mCoros.begin()), mend(mCoros.end()); mi != mend; ++mi) { - namespace coro_private = boost::coroutines::detail; + namespace coro_private = boost::dcoroutines::detail; if (static_cast(coro_private::coroutine_accessor::get_impl(const_cast(*mi->second)).get()) == self_id) { @@ -125,6 +130,12 @@ std::string LLCoros::getNameByID(const void* self_id) const return ""; } +void LLCoros::setStackSize(S32 stacksize) +{ + LL_INFOS("LLCoros") << "Setting coroutine stack size to " << stacksize << LL_ENDL; + mStackSize = stacksize; +} + /***************************************************************************** * MUST BE LAST *****************************************************************************/ diff --git a/indra/llcommon/llcoros.h b/indra/llcommon/llcoros.h index d75f28ec1a..01ee11da1a 100644 --- a/indra/llcommon/llcoros.h +++ b/indra/llcommon/llcoros.h @@ -29,7 +29,7 @@ #if ! defined(LL_LLCOROS_H) #define LL_LLCOROS_H -#include +#include #include "llsingleton.h" #include #include @@ -78,8 +78,8 @@ class LL_COMMON_API LLCoros: public LLSingleton { public: - /// Canonical boost::coroutines::coroutine signature we use - typedef boost::coroutines::coroutine coro; + /// Canonical boost::dcoroutines::coroutine signature we use + typedef boost::dcoroutines::coroutine coro; /// Canonical 'self' type typedef coro::self self; @@ -125,7 +125,7 @@ class LL_COMMON_API LLCoros: public LLSingleton template std::string launch(const std::string& prefix, const CALLABLE& callable) { - return launchImpl(prefix, new coro(callable)); + return launchImpl(prefix, new coro(callable, mStackSize)); } /** @@ -152,6 +152,9 @@ class LL_COMMON_API LLCoros: public LLSingleton /// getName() by self.get_id() std::string getNameByID(const void* self_id) const; + /// for delayed initialization + void setStackSize(S32 stacksize); + private: friend class LLSingleton; LLCoros(); @@ -159,6 +162,7 @@ class LL_COMMON_API LLCoros: public LLSingleton std::string generateDistinctName(const std::string& prefix) const; bool cleanup(const LLSD&); + S32 mStackSize; typedef boost::ptr_map CoroMap; CoroMap mCoros; }; diff --git a/indra/llcommon/llcrc.cpp b/indra/llcommon/llcrc.cpp index 7f183dc9ae..515e07a4a5 100644 --- a/indra/llcommon/llcrc.cpp +++ b/indra/llcommon/llcrc.cpp @@ -168,7 +168,7 @@ void LLCRC::update(const std::string& filename) { if (filename.empty()) { - llerrs << "No filename specified" << llendl; + LL_ERRS() << "No filename specified" << LL_ENDL; return; } @@ -191,7 +191,7 @@ void LLCRC::update(const std::string& filename) if (nread < (size_t) size) { - llwarns << "Short read on " << filename << llendl; + LL_WARNS() << "Short read on " << filename << LL_ENDL; } update(data, nread); diff --git a/indra/llcommon/llcrc.h b/indra/llcommon/llcrc.h index 74369062cc..94d5b6a726 100644 --- a/indra/llcommon/llcrc.h +++ b/indra/llcommon/llcrc.h @@ -47,7 +47,7 @@ // crc.update(fgetc(fp)); // } // fclose(fp); -// llinfos << "File crc: " << crc.getCRC() << llendl; +// LL_INFOS() << "File crc: " << crc.getCRC() << LL_ENDL; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class LL_COMMON_API LLCRC diff --git a/indra/llcommon/llcriticaldamp.cpp b/indra/llcommon/llcriticaldamp.cpp index b6f715b0ce..6d27c6e209 100644 --- a/indra/llcommon/llcriticaldamp.cpp +++ b/indra/llcommon/llcriticaldamp.cpp @@ -33,63 +33,105 @@ #include "linden_common.h" #include "llcriticaldamp.h" +#include //----------------------------------------------------------------------------- // static members //----------------------------------------------------------------------------- -LLFrameTimer LLCriticalDamp::sInternalTimer; -std::map LLCriticalDamp::sInterpolants; -F32 LLCriticalDamp::sTimeDelta; +LLFrameTimer LLSmoothInterpolation::sInternalTimer; +std::vector LLSmoothInterpolation::sInterpolants; +F32 LLSmoothInterpolation::sTimeDelta; +std::pair sCachedEntry; + +// helper functors +struct LLSmoothInterpolation::CompareTimeConstants +{ + bool operator()(const F32& a, const LLSmoothInterpolation::Interpolant& b) const + { + return a < b.mTimeScale; + } + + bool operator()(const LLSmoothInterpolation::Interpolant& a, const F32& b) const + { + return a.mTimeScale < b; // bottom of a is higher than bottom of b + } + + bool operator()(const LLSmoothInterpolation::Interpolant& a, const LLSmoothInterpolation::Interpolant& b) const + { + return a.mTimeScale < b.mTimeScale; // bottom of a is higher than bottom of b + } +}; //----------------------------------------------------------------------------- -// LLCriticalDamp() +// LLSmoothInterpolation() //----------------------------------------------------------------------------- -LLCriticalDamp::LLCriticalDamp() +LLSmoothInterpolation::LLSmoothInterpolation() { sTimeDelta = 0.f; + sCachedEntry = std::pair(-1.f, -1.f); } // static //----------------------------------------------------------------------------- // updateInterpolants() //----------------------------------------------------------------------------- -void LLCriticalDamp::updateInterpolants() +void LLSmoothInterpolation::updateInterpolants() { sTimeDelta = sInternalTimer.getElapsedTimeAndResetF32(); - F32 time_constant; - - for (std::map::iterator iter = sInterpolants.begin(); - iter != sInterpolants.end(); iter++) + for (size_t i = 0; i < sInterpolants.size(); i++) { - time_constant = iter->first; - F32 new_interpolant = 1.f - pow(2.f, -sTimeDelta / time_constant); - new_interpolant = llclamp(new_interpolant, 0.f, 1.f); - sInterpolants[time_constant] = new_interpolant; + Interpolant& interp = sInterpolants[i]; + interp.mInterpolant = calcInterpolant(interp.mTimeScale); + if (sCachedEntry.first == interp.mTimeScale) + { + sCachedEntry.second = interp.mInterpolant; + } } } //----------------------------------------------------------------------------- // getInterpolant() //----------------------------------------------------------------------------- -F32 LLCriticalDamp::getInterpolant(const F32 time_constant, BOOL use_cache) +F32 LLSmoothInterpolation::getInterpolant(F32SecondsImplicit time_constant, bool use_cache) { if (time_constant == 0.f) { return 1.f; } - if (use_cache && sInterpolants.count(time_constant)) + if (use_cache) { - return sInterpolants[time_constant]; + if (sCachedEntry.first == time_constant) + { + return sCachedEntry.second; + } + interpolant_vec_t::iterator find_it = std::lower_bound(sInterpolants.begin(), sInterpolants.end(), time_constant.value(), CompareTimeConstants()); + if (find_it != sInterpolants.end() && find_it->mTimeScale == time_constant) + { + sCachedEntry = std::make_pair(time_constant.value(), find_it->mInterpolant); + return find_it->mInterpolant; + } + else + { + Interpolant interp; + interp.mTimeScale = time_constant.value(); + interp.mInterpolant = calcInterpolant(time_constant.value()); + sInterpolants.insert(find_it, interp); + sCachedEntry = std::make_pair(time_constant.value(), interp.mInterpolant); + return interp.mInterpolant; + } } - - F32 interpolant = 1.f - pow(2.f, -sTimeDelta / time_constant); - interpolant = llclamp(interpolant, 0.f, 1.f); - if (use_cache) + else { - sInterpolants[time_constant] = interpolant; + return calcInterpolant(time_constant.value()); } +} - return interpolant; +//----------------------------------------------------------------------------- +// calcInterpolant() +//----------------------------------------------------------------------------- +F32 LLSmoothInterpolation::calcInterpolant(F32 time_constant) +{ + return llclamp(1.f - powf(2.f, -sTimeDelta / time_constant), 0.f, 1.f); } diff --git a/indra/llcommon/llcriticaldamp.h b/indra/llcommon/llcriticaldamp.h index 13e37d8b78..d5c346d8ab 100644 --- a/indra/llcommon/llcriticaldamp.h +++ b/indra/llcommon/llcriticaldamp.h @@ -34,26 +34,46 @@ #ifndef LL_LLCRITICALDAMP_H #define LL_LLCRITICALDAMP_H -#include +#include #include "llframetimer.h" +#include "llunits.h" -class LL_COMMON_API LLCriticalDamp +class LL_COMMON_API LLSmoothInterpolation { public: - LLCriticalDamp(); + LLSmoothInterpolation(); // MANIPULATORS static void updateInterpolants(); // ACCESSORS - static F32 getInterpolant(const F32 time_constant, BOOL use_cache = TRUE); + static F32 getInterpolant(F32SecondsImplicit time_constant, bool use_cache = true); -protected: + template + static T lerp(T a, T b, F32SecondsImplicit time_constant, bool use_cache = true) + { + F32 interpolant = getInterpolant(time_constant, use_cache); + return ((a * (1.f - interpolant)) + + (b * interpolant)); + } + +protected: + static F32 calcInterpolant(F32 time_constant); + + struct CompareTimeConstants; static LLFrameTimer sInternalTimer; // frame timer for calculating deltas - static std::map sInterpolants; + struct Interpolant + { + F32 mTimeScale; + F32 mInterpolant; + }; + typedef std::vector interpolant_vec_t; + static interpolant_vec_t sInterpolants; static F32 sTimeDelta; }; +typedef LLSmoothInterpolation LLCriticalDamp; + #endif // LL_LLCRITICALDAMP_H diff --git a/indra/llcommon/lldarray.h b/indra/llcommon/lldarray.h deleted file mode 100644 index b6834796b0..0000000000 --- a/indra/llcommon/lldarray.h +++ /dev/null @@ -1,224 +0,0 @@ -/** - * @file lldarray.h - * @brief Wrapped std::vector for backward compatibility. - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLDARRAY_H -#define LL_LLDARRAY_H - -#include "llerror.h" - -#include -#include - -// class LLDynamicArray<>; // = std::vector + reserves elements -// class LLDynamicArrayIndexed<>; // = std::vector + std::map if indices, only supports operator[] and begin(),end() - -//-------------------------------------------------------- -// LLDynamicArray declaration -//-------------------------------------------------------- -// NOTE: BlockSize is used to reserve a minimal initial amount -template -class LLDynamicArray : public std::vector -{ -public: - enum - { - OKAY = 0, - FAIL = -1 - }; - - LLDynamicArray(S32 size=0) : std::vector(size) { if (size < BlockSize) std::vector::reserve(BlockSize); } - LLDynamicArray(const std::vector& copy) : std::vector(copy) {} - - void reset() { std::vector::clear(); } - - // ACCESSORS - const Type& get(S32 index) const { return std::vector::operator[](index); } - Type& get(S32 index) { return std::vector::operator[](index); } - S32 find(const Type &obj) const; - - S32 count() const { return std::vector::size(); } - S32 getLength() const { return std::vector::size(); } - S32 getMax() const { return std::vector::capacity(); } - - // MANIPULATE - S32 put(const Type &obj); // add to end of array, returns index -// Type* reserve(S32 num); // reserve a block of indices in advance - Type* reserve_block(U32 num); // reserve a block of indices in advance - - S32 remove(S32 index); // remove by index, no bounds checking - S32 removeObj(const Type &obj); // remove by object - S32 removeLast(); - - void operator+=(const LLDynamicArray &other); -}; - -//-------------------------------------------------------- -// LLDynamicArray implementation -//-------------------------------------------------------- - -template -inline S32 LLDynamicArray::find(const Type &obj) const -{ - typename std::vector::const_iterator iter = std::find(this->begin(), this->end(), obj); - if (iter != this->end()) - { - return iter - this->begin(); - } - return FAIL; -} - - -template -inline S32 LLDynamicArray::remove(S32 i) -{ - // This is a fast removal by swapping with the last element - S32 sz = this->size(); - if (i < 0 || i >= sz) - { - return FAIL; - } - if (i < sz-1) - { - this->operator[](i) = this->back(); - } - this->pop_back(); - return i; -} - -template -inline S32 LLDynamicArray::removeObj(const Type& obj) -{ - typename std::vector::iterator iter = std::find(this->begin(), this->end(), obj); - if (iter != this->end()) - { - S32 res = iter - this->begin(); - typename std::vector::iterator last = this->end(); - --last; - *iter = *last; - this->pop_back(); - return res; - } - return FAIL; -} - -template -inline S32 LLDynamicArray::removeLast() -{ - if (!this->empty()) - { - this->pop_back(); - return OKAY; - } - return FAIL; -} - -template -inline Type* LLDynamicArray::reserve_block(U32 num) -{ - U32 sz = this->size(); - this->resize(sz+num); - return &(this->operator[](sz)); -} - -template -inline S32 LLDynamicArray::put(const Type &obj) -{ - this->push_back(obj); - return this->size() - 1; -} - -template -inline void LLDynamicArray::operator+=(const LLDynamicArray &other) -{ - this->insert(this->end(), other.begin(), other.end()); -} - -//-------------------------------------------------------- -// LLDynamicArrayIndexed declaration -//-------------------------------------------------------- - -template -class LLDynamicArrayIndexed -{ -public: - typedef typename std::vector::iterator iterator; - typedef typename std::vector::const_iterator const_iterator; - typedef typename std::vector::reverse_iterator reverse_iterator; - typedef typename std::vector::const_reverse_iterator const_reverse_iterator; - typedef typename std::vector::size_type size_type; -protected: - std::vector mVector; - std::map mIndexMap; - -public: - LLDynamicArrayIndexed() { mVector.reserve(BlockSize); } - - iterator begin() { return mVector.begin(); } - const_iterator begin() const { return mVector.begin(); } - iterator end() { return mVector.end(); } - const_iterator end() const { return mVector.end(); } - - reverse_iterator rbegin() { return mVector.rbegin(); } - const_reverse_iterator rbegin() const { return mVector.rbegin(); } - reverse_iterator rend() { return mVector.rend(); } - const_reverse_iterator rend() const { return mVector.rend(); } - - void reset() { mVector.resize(0); mIndexMap.resize(0); } - bool empty() const { return mVector.empty(); } - size_type size() const { return mVector.size(); } - - Type& operator[](const Key& k) - { - typename std::map::const_iterator iter = mIndexMap.find(k); - if (iter == mIndexMap.end()) - { - U32 n = mVector.size(); - mIndexMap[k] = n; - mVector.push_back(Type()); - llassert(mVector.size() == mIndexMap.size()); - return mVector[n]; - } - else - { - return mVector[iter->second]; - } - } - - const_iterator find(const Key& k) const - { - typename std::map::const_iterator iter = mIndexMap.find(k); - if(iter == mIndexMap.end()) - { - return mVector.end(); - } - else - { - return mVector.begin() + iter->second; - } - } -}; - -#endif diff --git a/indra/llcommon/lldarrayptr.h b/indra/llcommon/lldarrayptr.h deleted file mode 100644 index 7fde52bdcd..0000000000 --- a/indra/llcommon/lldarrayptr.h +++ /dev/null @@ -1,42 +0,0 @@ -/** - * @file lldarrayptr.h - * @brief Wrapped std::vector for backward compatibility. - * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ -#ifndef LL_LLDARRAYPTR_H -#define LL_LLDARRAYPTR_H - -#include "lldarray.h" - -template -class LLDynamicArrayPtr : public LLDynamicArray -{ -}; - -#endif // LL_LLDARRAYPTR_H diff --git a/indra/llcommon/lldate.cpp b/indra/llcommon/lldate.cpp index b36bd0b658..56b19316f9 100644 --- a/indra/llcommon/lldate.cpp +++ b/indra/llcommon/lldate.cpp @@ -4,76 +4,67 @@ * @date 2006-02-05 * @brief Implementation of the date class * - * $LicenseInfo:firstyear=2006&license=viewergpl$ - * - * Copyright (c) 2006-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #include "linden_common.h" #include "lldate.h" -#include "apr_time.h" - #include #include #include #include +#include #include -#include "llfasttimer.h" #include "lltimer.h" #include "llstring.h" +#include "llfasttimer.h" -static const F64 DATE_EPOCH = 0.0; - -static const F64 LL_APR_USEC_PER_SEC = 1000000.0; - // should be APR_USEC_PER_SEC, but that relies on INT64_C which - // isn't defined in glib under our build set up for some reason +#if defined(LL_WINDOWS) && !defined(timegm) +# define timegm _mkgmtime +#endif +#define EPOCH_STR "1970-01-01T00:00:00Z" +static const F64 DATE_EPOCH = 0.0; +static std::string sPrevLocale = ""; LLDate::LLDate() : mSecondsSinceEpoch(DATE_EPOCH) -{ -} +{} LLDate::LLDate(const LLDate& date) : mSecondsSinceEpoch(date.mSecondsSinceEpoch) -{ -} +{} -LLDate::LLDate(F64 seconds_since_epoch) : - mSecondsSinceEpoch(seconds_since_epoch) -{ -} +LLDate::LLDate(F64SecondsImplicit seconds_since_epoch) : + mSecondsSinceEpoch(seconds_since_epoch.value()) +{} LLDate::LLDate(const std::string& iso8601_date) { if(!fromString(iso8601_date)) { - llwarns << "date " << iso8601_date << " failed to parse; " - << "ZEROING IT OUT" << llendl; + LL_WARNS() << "date " << iso8601_date << " failed to parse; " + << "ZEROING IT OUT" << LL_ENDL; mSecondsSinceEpoch = DATE_EPOCH; } } @@ -95,34 +86,40 @@ std::string LLDate::asRFC1123() const return toHTTPDateString (std::string ("%A, %d %b %Y %H:%M:%S GMT")); } -LLFastTimer::DeclareTimer FT_DATE_FORMAT("Date Format"); +LLTrace::BlockTimerStatHandle FT_DATE_FORMAT("Date Format"); -std::string LLDate::toHTTPDateString (std::string fmt) const +std::string LLDate::toHTTPDateString(const std::string& fmt) const { - LLFastTimer ft1(FT_DATE_FORMAT); + LL_RECORD_BLOCK_TIME(FT_DATE_FORMAT); - time_t locSeconds = (time_t) mSecondsSinceEpoch; - struct tm * gmt = gmtime (&locSeconds); + std::time_t locSeconds = (std::time_t) mSecondsSinceEpoch; + std::tm * gmt = gmtime (&locSeconds); + if (!gmt) + { + LL_WARNS() << "The impossible has happened!" << LL_ENDL; + return LLStringExplicit(EPOCH_STR); + } return toHTTPDateString(gmt, fmt); } -std::string LLDate::toHTTPDateString (tm * gmt, std::string fmt) +std::string LLDate::toHTTPDateString(tm * gmt, const std::string& fmt) { - LLFastTimer ft1(FT_DATE_FORMAT); + LL_RECORD_BLOCK_TIME(FT_DATE_FORMAT); // avoid calling setlocale() unnecessarily - it's expensive. - static std::string prev_locale = ""; std::string this_locale = LLStringUtil::getLocale(); - if (this_locale != prev_locale) + if (this_locale != sPrevLocale) { setlocale(LC_TIME, this_locale.c_str()); - prev_locale = this_locale; + sPrevLocale = this_locale; } // use strftime() as it appears to be faster than std::time_put - char buffer[128]; - strftime(buffer, 128, fmt.c_str(), gmt); + char buffer[128] = {}; + if (std::strftime(buffer, sizeof(buffer), fmt.c_str(), gmt) == 0) + return LLStringExplicit(EPOCH_STR); std::string res(buffer); + #if LL_WINDOWS // Convert from locale-dependant charset to UTF-8 (EXT-8524). res = ll_convert_string_to_utf8_string(res); @@ -132,12 +129,18 @@ std::string LLDate::toHTTPDateString (tm * gmt, std::string fmt) void LLDate::toStream(std::ostream& s) const { - apr_time_t time = (apr_time_t)(mSecondsSinceEpoch * LL_APR_USEC_PER_SEC); + std::ios::fmtflags f( s.flags() ); - apr_time_exp_t exp_time; - if (apr_time_exp_gmt(&exp_time, time) != APR_SUCCESS) + std::tm exp_time = {0}; + std::time_t time = static_cast(mSecondsSinceEpoch); + +#if LL_WINDOWS + if (gmtime_s(&exp_time, &time) != 0) +#else + if (!gmtime_r(&time, &exp_time)) +#endif { - s << "1970-01-01T00:00:00Z"; + s << EPOCH_STR; return; } @@ -153,22 +156,29 @@ void LLDate::toStream(std::ostream& s) const << 'T' << std::setw(2) << (exp_time.tm_hour) << ':' << std::setw(2) << (exp_time.tm_min) << ':' << std::setw(2) << (exp_time.tm_sec); - if (exp_time.tm_usec > 0) - { - s << '.' << std::setw(2) - << (int)(exp_time.tm_usec / (LL_APR_USEC_PER_SEC / 100)); - } s << 'Z' << std::setfill(' '); + + s.flags( f ); } bool LLDate::split(S32 *year, S32 *month, S32 *day, S32 *hour, S32 *min, S32 *sec) const { - apr_time_t time = (apr_time_t)(mSecondsSinceEpoch * LL_APR_USEC_PER_SEC); + std::tm exp_time = {0}; + std::time_t time = static_cast(mSecondsSinceEpoch); - apr_time_exp_t exp_time; - if (apr_time_exp_gmt(&exp_time, time) != APR_SUCCESS) +#if LL_WINDOWS + if (gmtime_s(&exp_time, &time) != 0) +#else + if (!gmtime_r(&time, &exp_time)) +#endif { + *year = 1970; + *month = 01; + *day = 01; + *hour = 00; + *min = 00; + *sec = 00; return false; } @@ -201,60 +211,63 @@ bool LLDate::fromString(const std::string& iso8601_date) bool LLDate::fromStream(std::istream& s) { - struct apr_time_exp_t exp_time; - apr_int32_t tm_part; + std::tm time = {0}; int c; - +#if LL_WINDOWS || LL_LINUX // GCC 4.8 lacks this Windows has broken std::get_time() Time for things to get ugly! + int32_t tm_part; s >> tm_part; - exp_time.tm_year = tm_part - 1900; + time.tm_year = tm_part - 1900; c = s.get(); // skip the hypen if (c != '-') { return false; } s >> tm_part; - exp_time.tm_mon = tm_part - 1; + time.tm_mon = tm_part - 1; c = s.get(); // skip the hypen if (c != '-') { return false; } s >> tm_part; - exp_time.tm_mday = tm_part; + time.tm_mday = tm_part; c = s.get(); // skip the T if (c != 'T') { return false; } s >> tm_part; - exp_time.tm_hour = tm_part; + time.tm_hour = tm_part; c = s.get(); // skip the : if (c != ':') { return false; } s >> tm_part; - exp_time.tm_min = tm_part; + time.tm_min = tm_part; c = s.get(); // skip the : if (c != ':') { return false; } s >> tm_part; - exp_time.tm_sec = tm_part; - - // zero out the unused fields - exp_time.tm_usec = 0; - exp_time.tm_wday = 0; - exp_time.tm_yday = 0; - exp_time.tm_isdst = 0; - exp_time.tm_gmtoff = 0; - - // generate a time_t from that - apr_time_t time; - if (apr_time_exp_gmt_get(&time, &exp_time) != APR_SUCCESS) - { - return false; - } - - F64 seconds_since_epoch = time / LL_APR_USEC_PER_SEC; + time.tm_sec = tm_part; - // check for fractional c = s.peek(); if(c == '.') { F64 fractional = 0.0; s >> fractional; - seconds_since_epoch += fractional; } +#else + std::string this_locale = LLStringUtil::getLocale(); + if (this_locale != sPrevLocale) + { + setlocale(LC_TIME, this_locale.c_str()); + sPrevLocale = this_locale; + } + + // Isn't stdlib nice? + s.imbue(std::locale(sPrevLocale.c_str())); + s >> std::get_time(&time, "%Y-%m-%dT%H:%M:%S"); + if (s.fail()) + { + return false; + } +#endif + std::time_t tm = timegm(&time); + if (tm == -1) + return false; + + F64 seconds_since_epoch = static_cast(tm); c = s.peek(); // check for offset if (c == '+' || c == '-') { @@ -270,7 +283,6 @@ bool LLDate::fromStream(std::istream& s) { s >> offset_minutes; } - offset_in_seconds = (offset_hours * 60 + offset_sign * offset_minutes) * 60; seconds_since_epoch -= offset_in_seconds; } @@ -282,7 +294,7 @@ bool LLDate::fromStream(std::istream& s) bool LLDate::fromYMDHMS(S32 year, S32 month, S32 day, S32 hour, S32 min, S32 sec) { - struct apr_time_exp_t exp_time; + std::tm exp_time = {0}; exp_time.tm_year = year - 1900; exp_time.tm_mon = month - 1; @@ -291,21 +303,11 @@ bool LLDate::fromYMDHMS(S32 year, S32 month, S32 day, S32 hour, S32 min, S32 sec exp_time.tm_min = min; exp_time.tm_sec = sec; - // zero out the unused fields - exp_time.tm_usec = 0; - exp_time.tm_wday = 0; - exp_time.tm_yday = 0; - exp_time.tm_isdst = 0; - exp_time.tm_gmtoff = 0; - - // generate a time_t from that - apr_time_t time; - if (apr_time_exp_gmt_get(&time, &exp_time) != APR_SUCCESS) - { + std::time_t tm = timegm(&exp_time); + if (tm == -1) return false; - } - mSecondsSinceEpoch = time / LL_APR_USEC_PER_SEC; + mSecondsSinceEpoch = static_cast(tm); return true; } diff --git a/indra/llcommon/lldate.h b/indra/llcommon/lldate.h index 7e8ae63687..999486ebb4 100644 --- a/indra/llcommon/lldate.h +++ b/indra/llcommon/lldate.h @@ -38,9 +38,8 @@ #include #include -#include "llpreprocessor.h" - #include "stdtypes.h" +#include "llunits.h" /** * @class LLDate @@ -64,9 +63,9 @@ class LL_COMMON_API LLDate /** * @brief Construct a date from a seconds since epoch value. * - * @pararm seconds_since_epoch The number of seconds since UTC epoch. + * @param seconds_since_epoch The number of seconds since UTC epoch. */ - LLDate(F64 seconds_since_epoch); + LLDate(F64SecondsImplicit seconds_since_epoch); /** * @brief Construct a date from a string representation @@ -87,8 +86,8 @@ class LL_COMMON_API LLDate std::string asRFC1123() const; void toStream(std::ostream&) const; bool split(S32 *year, S32 *month = NULL, S32 *day = NULL, S32 *hour = NULL, S32 *min = NULL, S32 *sec = NULL) const; - std::string toHTTPDateString (std::string fmt) const; - static std::string toHTTPDateString (tm * gmt, std::string fmt); + std::string toHTTPDateString (const std::string& fmt) const; + static std::string toHTTPDateString (tm * gmt, const std::string& fmt); /** * @brief Set the date from an ISO-8601 string. * @@ -163,4 +162,6 @@ LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLDate& date); // Helper function to stream in a date LL_COMMON_API std::istream& operator>>(std::istream& s, LLDate& date); + + #endif // LL_LLDATE_H diff --git a/indra/llcommon/lldeleteutils.h b/indra/llcommon/lldeleteutils.h deleted file mode 100644 index 8a8d3fd720..0000000000 --- a/indra/llcommon/lldeleteutils.h +++ /dev/null @@ -1,54 +0,0 @@ -/** - * @file lldeleteutils.h - * @brief Utility functions to simplify some common pointer-munging idioms. - * - * $LicenseInfo:firstyear=2009&license=viewergpl$ - * - * Copyright (c) 2009-2010, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlife.com/developers/opensource/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - * - */ -#ifndef LL_DELETE_UTILS_H -#define LL_DELETE_UTILS_H - -// Simple utility functions to eventually replace the common 2-line -// idiom scattered throughout the viewer codebase. Note that where -// possible we would rather be using smart pointers of some sort. - -template -inline void deleteAndClear(T*& ptr) -{ - delete ptr; - ptr = NULL; -} - -template -inline void deleteAndClearArray(T*& array_ptr) -{ - delete[] array_ptr; - array_ptr = NULL; -} - -#endif diff --git a/indra/llcommon/lldependencies.cpp b/indra/llcommon/lldependencies.cpp index 0e72c175cb..6a1f8ec51b 100644 --- a/indra/llcommon/lldependencies.cpp +++ b/indra/llcommon/lldependencies.cpp @@ -41,7 +41,7 @@ #include // other Linden headers -LLDependenciesBase::VertexList LLDependenciesBase::topo_sort(int vertices, const EdgeList& edges) const +LLDependenciesBase::VertexList LLDependenciesBase::topo_sort(std::size_t vertices, const EdgeList& edges) const { // Construct a Boost Graph Library graph according to the constraints // we've collected. It seems as though we ought to be able to capture diff --git a/indra/llcommon/lldependencies.h b/indra/llcommon/lldependencies.h index e0294e271b..a3200a0ca4 100644 --- a/indra/llcommon/lldependencies.h +++ b/indra/llcommon/lldependencies.h @@ -39,7 +39,10 @@ #include #include #include +#ifndef BOOST_FUNCTION_HPP_INCLUDED #include +#define BOOST_FUNCTION_HPP_INCLUDED +#endif #include /***************************************************************************** @@ -124,9 +127,9 @@ class LL_COMMON_API LLDependenciesBase virtual std::string describe(bool full=true) const; protected: - typedef std::vector< std::pair > EdgeList; - typedef std::vector VertexList; - VertexList topo_sort(int vertices, const EdgeList& edges) const; + typedef std::vector< std::pair > EdgeList; + typedef std::vector VertexList; + VertexList topo_sort(std::size_t vertices, const EdgeList& edges) const; /** * refpair is specifically intended to capture a pair of references. This @@ -508,7 +511,7 @@ class LLDependencies: public LLDependenciesBase // been explicitly added. Rely on std::map rejecting a second attempt // to insert the same key. Use the map's size() as the vertex number // to get a distinct value for each successful insertion. - typedef std::map VertexMap; + typedef std::map VertexMap; VertexMap vmap; // Nest each of these loops because !@#$%? MSVC warns us that its // former broken behavior has finally been fixed -- and our builds @@ -539,7 +542,7 @@ class LLDependencies: public LLDependenciesBase for (typename DepNodeMap::const_iterator nmi = mNodes.begin(), nmend = mNodes.end(); nmi != nmend; ++nmi) { - int thisnode = vmap[nmi->first]; + std::size_t thisnode = vmap[nmi->first]; // after dependencies: build edges from the named node to this one for (typename DepNode::dep_set::const_iterator ai = nmi->second.after.begin(), aend = nmi->second.after.end(); diff --git a/indra/llcommon/lldepthstack.h b/indra/llcommon/lldepthstack.h index accc11f57e..dec73e5d70 100644 --- a/indra/llcommon/lldepthstack.h +++ b/indra/llcommon/lldepthstack.h @@ -33,18 +33,19 @@ #ifndef LL_LLDEPTHSTACK_H #define LL_LLDEPTHSTACK_H -#include "linked_lists.h" +#include "llstl.h" template class LLDepthStack { private: - LLLinkedList mStack; + std::deque mStack; U32 mCurrentDepth; U32 mMaxDepth; public: - LLDepthStack() : mCurrentDepth(0), mMaxDepth(0) {} - ~LLDepthStack() {} + LLDepthStack() + : mCurrentDepth(0), mMaxDepth(0) + {} void setDepth(U32 depth) { @@ -60,24 +61,27 @@ template class LLDepthStack { if (mCurrentDepth < mMaxDepth) { - mStack.addData(data); + mStack.push_back(data); mCurrentDepth++; } else { // the last item falls off stack and is deleted - mStack.getLastData(); - mStack.deleteCurrentData(); - mStack.addData(data); + if (!mStack.empty()) + { + mStack.pop_front(); + } + mStack.push_back(data); } } DATA_TYPE *pop() { - DATA_TYPE *tempp = mStack.getFirstData(); - if (tempp) + DATA_TYPE *tempp = NULL; + if (!mStack.empty()) { - mStack.removeCurrentData(); + tempp = mStack.back(); + mStack.pop_back(); mCurrentDepth--; } return tempp; @@ -85,20 +89,13 @@ template class LLDepthStack DATA_TYPE *check() { - DATA_TYPE *tempp = mStack.getFirstData(); - return tempp; + return mStack.empty() ? NULL : mStack.back(); } - - void deleteAllData() - { - mCurrentDepth = 0; - mStack.deleteAllData(); - } - + void removeAllNodes() { mCurrentDepth = 0; - mStack.removeAllNodes(); + mStack.clear(); } }; diff --git a/indra/llcommon/lldictionary.h b/indra/llcommon/lldictionary.h index 7530b4fa7e..144931bb7a 100644 --- a/indra/llcommon/lldictionary.h +++ b/indra/llcommon/lldictionary.h @@ -2,33 +2,26 @@ * @file lldictionary.h * @brief Lldictionary class header file * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2010, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlife.com/developers/opensource/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ */ #ifndef LL_LLDICTIONARY_H @@ -37,6 +30,8 @@ #include #include +#include "llerror.h" + struct LL_COMMON_API LLDictionaryEntry { LLDictionaryEntry(const std::string &name); @@ -70,7 +65,7 @@ class LLDictionary : public std::map { for (const_iterator_t dictionary_iter = map_t::begin(); dictionary_iter != map_t::end(); - dictionary_iter++) + ++dictionary_iter) { const Entry *entry = dictionary_iter->second; if (entry->mName == name) @@ -94,7 +89,7 @@ class LLDictionary : public std::map { if (lookup(index)) { - llerrs << "Dictionary entry already added (attempted to add duplicate entry)" << llendl; + LL_ERRS() << "Dictionary entry already added (attempted to add duplicate entry)" << LL_ENDL; } (*this)[index] = entry; } diff --git a/indra/llcommon/lldlinked.h b/indra/llcommon/lldlinked.h deleted file mode 100644 index 8b6853212d..0000000000 --- a/indra/llcommon/lldlinked.h +++ /dev/null @@ -1,99 +0,0 @@ -/** - * @file lldlinked.h - * @brief Declaration of the LLDLinked class. - * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ -#ifndef LL_LLDLINKED_H -#define LL_LLDLINKED_H - -template class LLDLinked -{ - LLDLinked* mNextp; - LLDLinked* mPrevp; -public: - - Type* getNext() { return (Type*)mNextp; } - Type* getPrev() { return (Type*)mPrevp; } - Type* getFirst() { return (Type*)mNextp; } - - void init() - { - mNextp = mPrevp = NULL; - } - - void unlink() - { - if (mPrevp) mPrevp->mNextp = mNextp; - if (mNextp) mNextp->mPrevp = mPrevp; - } - - LLDLinked() { mNextp = mPrevp = NULL; } - virtual ~LLDLinked() { unlink(); } - - virtual void deleteAll() - { - Type *curp = getFirst(); - while(curp) - { - Type *nextp = curp->getNext(); - curp->unlink(); - delete curp; - curp = nextp; - } - } - - void relink(Type &after) - { - LLDLinked *afterp = (LLDLinked*)&after; - afterp->mPrevp = this; - mNextp = afterp; - } - - virtual void append(Type& after) - { - LLDLinked *afterp = (LLDLinked*)&after; - afterp->mPrevp = this; - afterp->mNextp = mNextp; - if (mNextp) mNextp->mPrevp = afterp; - mNextp = afterp; - } - - virtual void insert(Type& before) - { - LLDLinked *beforep = (LLDLinked*)&before; - beforep->mNextp = this; - beforep->mPrevp = mPrevp; - if (mPrevp) mPrevp->mNextp = beforep; - mPrevp = beforep; - } - - virtual void put(Type& obj) { append(obj); } -}; - -#endif diff --git a/indra/llcommon/lldqueueptr.h b/indra/llcommon/lldqueueptr.h deleted file mode 100644 index 77df47b1f3..0000000000 --- a/indra/llcommon/lldqueueptr.h +++ /dev/null @@ -1,358 +0,0 @@ -/** - * @file lldqueueptr.h - * @brief LLDynamicQueuePtr declaration - * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ -#ifndef LL_LLDQUEUEPTR_H -#define LL_LLDQUEUEPTR_H - -template -class LLDynamicQueuePtr -{ -public: - enum - { - OKAY = 0, - FAIL = -1 - }; - - LLDynamicQueuePtr(const S32 size=8); - ~LLDynamicQueuePtr(); - - void init(); - void destroy(); - void reset(); - void reallocate(U32 newsize); - - // ACCESSORS - const Type& get(const S32 index) const; // no bounds checking - Type& get(const S32 index); // no bounds checking - const Type& operator [] (const S32 index) const { return get(index); } - Type& operator [] (const S32 index) { return get(index); } - S32 find(const Type &obj) const; - - S32 count() const { return (mLastObj >= mFirstObj ? mLastObj - mFirstObj : mLastObj + mMaxObj - mFirstObj); } - S32 getMax() const { return mMaxObj; } - S32 getFirst() const { return mFirstObj; } - S32 getLast () const { return mLastObj; } - - // MANIPULATE - S32 push(const Type &obj); // add to end of Queue, returns index from start - S32 pull( Type &obj); // pull from Queue, returns index from start - - S32 remove (S32 index); // remove by index - S32 removeObj(const Type &obj); // remove by object - -protected: - S32 mFirstObj, mLastObj, mMaxObj; - Type* mMemory; - -public: - - void print() - { - /* - Convert this to llinfos if it's intended to be used - djs 08/30/02 - - printf("Printing from %d to %d (of %d): ",mFirstObj, mLastObj, mMaxObj); - - if (mFirstObj <= mLastObj) - { - for (S32 i=mFirstObj;i -inline LLDynamicQueuePtr::LLDynamicQueuePtr(const S32 size) -{ - init(); - reallocate(size); -} - -template -inline LLDynamicQueuePtr::~LLDynamicQueuePtr() -{ - destroy(); -} - -template -inline void LLDynamicQueuePtr::init() -{ - mFirstObj = 0; - mLastObj = 0; - mMaxObj = 0; - mMemory = NULL; -} - -template -inline void LLDynamicQueuePtr::reallocate(U32 newsize) -{ - if (newsize) - { - if (mFirstObj > mLastObj && newsize > mMaxObj) - { - Type* new_memory = new Type[newsize]; - - llassert(new_memory); - - S32 _count = count(); - S32 i, m = 0; - for (i=mFirstObj; i < mMaxObj; i++) - { - new_memory[m++] = mMemory[i]; - } - for (i=0; i <=mLastObj; i++) - { - new_memory[m++] = mMemory[i]; - } - - delete[] mMemory; - mMemory = new_memory; - - mFirstObj = 0; - mLastObj = _count; - } - else - { - Type* new_memory = new Type[newsize]; - - llassert(new_memory); - - S32 i, m = 0; - for (i=0; i < mLastObj; i++) - { - new_memory[m++] = mMemory[i]; - } - delete[] mMemory; - mMemory = new_memory; - } - } - else if (mMemory) - { - delete[] mMemory; - mMemory = NULL; - } - - mMaxObj = newsize; -} - -template -inline void LLDynamicQueuePtr::destroy() -{ - reset(); - delete[] mMemory; - mMemory = NULL; -} - - -template -void LLDynamicQueuePtr::reset() -{ - for (S32 i=0; i < mMaxObj; i++) - { - get(i) = NULL; // unrefs for pointers - } - - mFirstObj = 0; - mLastObj = 0; -} - - -template -inline S32 LLDynamicQueuePtr::find(const Type &obj) const -{ - S32 i; - if (mFirstObj <= mLastObj) - { - for ( i = mFirstObj; i < mLastObj; i++ ) - { - if (mMemory[i] == obj) - { - return i; - } - } - } - else - { - for ( i = mFirstObj; i < mMaxObj; i++ ) - { - if (mMemory[i] == obj) - { - return i; - } - } - for ( i = 0; i < mLastObj; i++ ) - { - if (mMemory[i] == obj) - { - return i; - } - } - } - - return FAIL; -} - -template -inline S32 LLDynamicQueuePtr::remove(S32 i) -{ - if (mFirstObj > mLastObj) - { - if (i >= mFirstObj && i < mMaxObj) - { - while( i > mFirstObj) - { - mMemory[i] = mMemory[i-1]; - i--; - } - mMemory[mFirstObj] = NULL; - mFirstObj++; - if (mFirstObj >= mMaxObj) mFirstObj = 0; - - return count(); - } - else if (i < mLastObj && i >= 0) - { - while(i < mLastObj) - { - mMemory[i] = mMemory[i+1]; - i++; - } - mMemory[mLastObj] = NULL; - mLastObj--; - if (mLastObj < 0) mLastObj = mMaxObj-1; - - return count(); - } - } - else if (i <= mLastObj && i >= mFirstObj) - { - while(i < mLastObj) - { - mMemory[i] = mMemory[i+1]; - i++; - } - mMemory[mLastObj] = NULL; - mLastObj--; - if (mLastObj < 0) mLastObj = mMaxObj-1; - - return count(); - } - - - return FAIL; -} - -template -inline S32 LLDynamicQueuePtr::removeObj(const Type& obj) -{ - S32 ind = find(obj); - if (ind >= 0) - { - return remove(ind); - } - return FAIL; -} - -template -inline S32 LLDynamicQueuePtr::push(const Type &obj) -{ - if (mMaxObj - count() <= 1) - { - reallocate(mMaxObj * 2); - } - - mMemory[mLastObj++] = obj; - - if (mLastObj >= mMaxObj) - { - mLastObj = 0; - } - - return count(); -} - -template -inline S32 LLDynamicQueuePtr::pull(Type &obj) -{ - obj = NULL; - - if (count() < 1) return -1; - - obj = mMemory[mFirstObj]; - mMemory[mFirstObj] = NULL; - - mFirstObj++; - - if (mFirstObj >= mMaxObj) - { - mFirstObj = 0; - } - - return count(); -} - -template -inline const Type& LLDynamicQueuePtr::get(const S32 i) const -{ - return mMemory[i]; -} - -template -inline Type& LLDynamicQueuePtr::get(const S32 i) -{ - return mMemory[i]; -} - - -#endif // LL_LLDQUEUEPTR_H diff --git a/indra/llcommon/llenum.h b/indra/llcommon/llenum.h deleted file mode 100644 index ac6d46baac..0000000000 --- a/indra/llcommon/llenum.h +++ /dev/null @@ -1,84 +0,0 @@ -/** - * @file llenum.h - * @author Tom Yedwab - * @brief Utility class for storing enum value <-> string lookup. - * - * $LicenseInfo:firstyear=2006&license=viewergpl$ - * - * Copyright (c) 2006-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifndef LL_LLENUM_H -#define LL_LLENUM_H - -class LLEnum -{ -public: - typedef std::pair enum_t; - enum - { - UNDEFINED = 0xffffffff, - }; - - LLEnum(const enum_t values_array[], const U32 length) - { - for (U32 i=0; i= mEnumArray.size()) - { - mEnumArray.resize(values_array[i].second+1); - } - mEnumArray[values_array[i].second] = values_array[i].first; - } - } - - U32 operator[](std::string str) - { - std::map::iterator itor; - itor = mEnumMap.find(str); - if (itor != mEnumMap.end()) - { - return itor->second; - } - return UNDEFINED; - } - - const std::string operator[](U32 index) - { - if (index < mEnumArray.size()) - { - return mEnumArray[index]; - } - return ""; - } - -private: - std::map mEnumMap; - std::vector mEnumArray; -}; - -#endif // LL_LLENUM_H diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp index 8b40edb40c..f6c58513b0 100644 --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -40,7 +40,6 @@ # include #endif // !LL_WINDOWS #include -#include #include "llapp.h" #include "llapr.h" @@ -54,7 +53,26 @@ #include "aithreadsafe.h" namespace { -#if !LL_WINDOWS +#if LL_WINDOWS + void debugger_print(const std::string& s) + { + // Be careful when calling OutputDebugString as it throws DBG_PRINTEXCEPTION_C + // which works just fine under the windows debugger, but can cause users who + // have enabled SEHOP exception chain validation to crash due to interactions + // between the Win 32-bit exception handling and boost coroutine fiber stacks. BUG-2707 + // + if (IsDebuggerPresent()) + { + // Need UTF16 for Unicode OutputDebugString + // + if (s.size()) + { + OutputDebugString(utf8str_to_utf16str(s).c_str()); + OutputDebugString(TEXT("\n")); + } + } + } +#else class RecordToSyslog : public LLError::Recorder { public: @@ -96,11 +114,13 @@ namespace { public: RecordToFile(const std::string& filename) { - mFile.open(filename, llofstream::out | llofstream::app); + mFile.open(filename.c_str(), std::ios_base::out | std::ios_base::app); if (!mFile) { - llinfos << "Error setting log file to " << filename << llendl; + LL_INFOS() << "Error setting log file to " << filename << LL_ENDL; } + mWantsTime = true; + mWantsTags = true; } ~RecordToFile() @@ -108,16 +128,12 @@ namespace { mFile.close(); } - bool okay() { return mFile; } - - virtual bool wantsTime() { return true; } + bool okay() { return mFile.good(); } virtual void recordMessage(LLError::ELevel level, const std::string& message) { mFile << message << std::endl; - // mFile.flush(); - // *FIX: should we do this? } private: @@ -128,9 +144,10 @@ namespace { class RecordToStderr : public LLError::Recorder { public: - RecordToStderr(bool timestamp) : mTimestamp(timestamp), mUseANSI(ANSI_PROBE) { } - - virtual bool wantsTime() { return mTimestamp; } + RecordToStderr(bool timestamp) : mUseANSI(ANSI_PROBE) + { + mWantsTime = timestamp; + } virtual void recordMessage(LLError::ELevel level, const std::string& message) @@ -172,14 +189,19 @@ namespace { } private: - bool mTimestamp; - enum ANSIState {ANSI_PROBE, ANSI_YES, ANSI_NO}; - ANSIState mUseANSI; + enum ANSIState + { + ANSI_PROBE, + ANSI_YES, + ANSI_NO + } mUseANSI; + void colorANSI(const std::string color) { // ANSI color code escape sequence fprintf(stderr, "\033[%sm", color.c_str() ); }; + bool checkANSI(void) { #if LL_LINUX || LL_DARWIN @@ -212,13 +234,13 @@ namespace { class RecordToWinDebug: public LLError::Recorder { public: + RecordToWinDebug() + {} + virtual void recordMessage(LLError::ELevel level, const std::string& message) { - llutf16string utf16str = - wstring_to_utf16str(utf8str_to_wstring(message)); - utf16str += '\n'; - OutputDebugString(utf16str.c_str()); + debugger_print(message); } }; #endif @@ -230,24 +252,14 @@ namespace std::string className(const std::type_info& type) { #ifdef __GNUC__ - // GCC: type_info::name() returns a mangled class name, must demangle - - static size_t abi_name_len = 100; - static char* abi_name_buf = (char*)malloc(abi_name_len); - // warning: above is voodoo inferred from the GCC manual, - // do NOT change - - int status; - // We don't use status, and shouldn't have to pass apointer to it - // but gcc 3.3 libstc++'s implementation of demangling is broken - // and fails without. - - char* name = abi::__cxa_demangle(type.name(), - abi_name_buf, &abi_name_len, &status); - // this call can realloc the abi_name_buf pointer (!) - - return name ? name : type.name(); - + // GCC: type_info::name() returns a mangled class name,st demangle + // passing nullptr, 0 forces allocation of a unique buffer we can free + // fixing MAINT-8724 on OSX 10.14 + int status = -1; + char* name = abi::__cxa_demangle(type.name(), nullptr, 0, &status); + std::string result(name ? name : type.name()); + free(name); + return result; #elif LL_WINDOWS // DevStudio: type_info::name() includes the text "class " at the start @@ -326,7 +338,7 @@ namespace LLSD configuration; { - llifstream file(filename()); + llifstream file(filename().c_str()); if (file.is_open()) { LLSDSerialize::fromXML(configuration, file); @@ -334,47 +346,52 @@ namespace if (configuration.isUndefined()) { - llwarns << filename() << " missing, ill-formed," + LL_WARNS() << filename() << " missing, ill-formed," " or simply undefined; not changing configuration" - << llendl; + << LL_ENDL; return false; } } LLError::configure(configuration); - llinfos << "logging reconfigured from " << filename() << llendl; + LL_INFOS() << "logging reconfigured from " << filename() << LL_ENDL; return true; } typedef std::map LevelMap; - typedef std::vector Recorders; + typedef std::vector Recorders; typedef std::vector CallSiteVector; class Globals { public: + std::ostringstream messageStream; bool messageStreamInUse; void addCallSite(LLError::CallSite&); void invalidateCallSites(); - + static AIThreadSafeSimple& get(); // return the one instance of the globals private: CallSiteVector callSites; - + friend class AIThreadSafeSimpleDC; // Calls constructor. friend class AIThreadSafeSimple; // Calls destructor. - - Globals() - : messageStreamInUse(false) - { } + Globals(); }; + Globals::Globals() + : messageStream(), + messageStreamInUse(false), + callSites() + { + } + void Globals::addCallSite(LLError::CallSite& site) { callSites.push_back(&site); @@ -391,12 +408,12 @@ namespace callSites.clear(); } - + AIThreadSafeSimple& Globals::get() { /* This pattern, of returning a reference to a static function variable, is to ensure that this global is constructed before - it is used, no matter what the global initialization sequence + it is used, no matter what the global initializeation sequence is. See C++ FAQ Lite, sections 10.12 through 10.14 */ @@ -407,112 +424,187 @@ namespace namespace LLError { - class Settings + class SettingsConfig : public LLRefCount { + friend class Settings; + public: - bool printLocation; + virtual ~SettingsConfig(); + + bool mPrintLocation; - LLError::ELevel defaultLevel; + LLError::ELevel mDefaultLevel; - LevelMap functionLevelMap; - LevelMap classLevelMap; - LevelMap fileLevelMap; - LevelMap tagLevelMap; - std::map uniqueLogMessages; + LevelMap mFunctionLevelMap; + LevelMap mClassLevelMap; + LevelMap mFileLevelMap; + LevelMap mTagLevelMap; + std::map mUniqueLogMessages; - LLError::FatalFunction crashFunction; - LLError::TimeFunction timeFunction; + LLError::FatalFunction mCrashFunction; + LLError::TimeFunction mTimeFunction; - Recorders recorders; - Recorder* fileRecorder; - Recorder* fixedBufferRecorder; - std::string fileRecorderFileName; + Recorders mRecorders; + RecorderPtr mFileRecorder; + RecorderPtr mFixedBufferRecorder; + std::string mFileRecorderFileName; - int shouldLogCallCounter; + int mShouldLogCallCounter; + private: + SettingsConfig(); + }; + + typedef LLPointer SettingsConfigPtr; + + class Settings + { + public: static AIThreadSafeSimple& get(); - - static void reset(); - static AIThreadSafeSimple* saveAndReset(); - static void restore(AIThreadSafeSimple*); + + SettingsConfigPtr getSettingsConfig(); + + void reset(); + SettingsStoragePtr saveAndReset(); + void restore(SettingsStoragePtr pSettingsStorage); private: friend class AIThreadSafeBits; // Calls destructor. friend class AIThreadSafeSimpleDC; // Calls constructor. - - Settings() - : printLocation(false), - defaultLevel(LLError::LEVEL_DEBUG), - crashFunction(NULL), - timeFunction(NULL), - fileRecorder(NULL), - fixedBufferRecorder(NULL), - shouldLogCallCounter(0) - { } + Settings(); - ~Settings() - { - for_each(recorders.begin(), recorders.end(), - DeletePointer()); - } - - static AIThreadSafeSimple* sSettings; + SettingsConfigPtr mSettingsConfig; }; + + SettingsConfig::SettingsConfig() + : LLRefCount(), + mPrintLocation(false), + mDefaultLevel(LLError::LEVEL_DEBUG), + mFunctionLevelMap(), + mClassLevelMap(), + mFileLevelMap(), + mTagLevelMap(), + mUniqueLogMessages(), + mCrashFunction(NULL), + mTimeFunction(NULL), + mRecorders(), + mFileRecorder(), + mFixedBufferRecorder(), + mFileRecorderFileName(), + mShouldLogCallCounter(0) + { + } + + SettingsConfig::~SettingsConfig() + { + mRecorders.clear(); + } - // Pointer to current AIThreadSafeSimple object if any (NULL otherwise). - AIThreadSafeSimple* Settings::sSettings; + Settings::Settings() + : mSettingsConfig(new SettingsConfig()) + { + } AIThreadSafeSimple& Settings::get() { - if (!sSettings) - { - reset(); - } - return *sSettings; + static AIThreadSafeSimpleDCRootPool* ts_globals_ptr = new AIThreadSafeSimpleDCRootPool; + return *ts_globals_ptr; + } + + SettingsConfigPtr Settings::getSettingsConfig() + { + return mSettingsConfig; } void Settings::reset() { AIAccess(Globals::get())->invalidateCallSites(); - delete sSettings; - sSettings = new AIThreadSafeSimpleDC; + mSettingsConfig = new SettingsConfig(); } - AIThreadSafeSimple* Settings::saveAndReset() + SettingsStoragePtr Settings::saveAndReset() { - AIAccess(Globals::get())->invalidateCallSites(); - AIThreadSafeSimple* originalSettings = sSettings; - sSettings = new AIThreadSafeSimpleDC; - return originalSettings; + SettingsStoragePtr oldSettingsConfig(mSettingsConfig.get()); + reset(); + return oldSettingsConfig; } - void Settings::restore(AIThreadSafeSimple* originalSettings) + void Settings::restore(SettingsStoragePtr pSettingsStorage) { AIAccess(Globals::get())->invalidateCallSites(); - delete sSettings; - sSettings = originalSettings; + SettingsConfigPtr newSettingsConfig(dynamic_cast(pSettingsStorage.get())); + mSettingsConfig = newSettingsConfig; } } namespace LLError { CallSite::CallSite(ELevel level, - const char* file, - int line, - const std::type_info& class_info, - const char* function, - const char* broadTag, - const char* narrowTag, - bool printOnce) - : mLevel(level), mFile(file), mLine(line), - mClassInfo(class_info), mFunction(function), - mCached(false), mShouldLog(false), - mBroadTag(broadTag), mNarrowTag(narrowTag), mPrintOnce(printOnce) - { } + const char* file, + int line, + const std::type_info& class_info, + const char* function, + bool printOnce, + const char** tags, + size_t tag_count) + : mLevel(level), + mFile(file), + mLine(line), + mClassInfo(class_info), + mFunction(function), + mCached(false), + mShouldLog(false), + mPrintOnce(printOnce), + mTags(new const char*[tag_count]), + mTagCount(tag_count) + { + for (size_t i = 0; i < tag_count; i++) + { + mTags[i] = tags[i]; + } + switch (mLevel) + { + case LEVEL_DEBUG: mLevelString = "DEBUG:"; break; + case LEVEL_INFO: mLevelString = "INFO:"; break; + case LEVEL_WARN: mLevelString = "WARNING:"; break; + case LEVEL_ERROR: mLevelString = "ERROR:"; break; + default: mLevelString = "XXX:"; break; + }; + + mLocationString = llformat("%s(%d) :", abbreviateFile(mFile).c_str(), mLine); + if (mFunction) + { +#if LL_WINDOWS + // DevStudio: __FUNCTION__ already includes the full class name +#else +#if LL_LINUX + // gross, but typeid comparison seems to always fail here with gcc4.1 + if (0 != strcmp(mClassInfo.name(), typeid(NoClassInfo).name())) +#else + if (mClassInfo != typeid(NoClassInfo)) +#endif // LL_LINUX + { + mFunctionString = className(mClassInfo) + "::"; + } +#endif + mFunctionString += std::string(mFunction) + ":"; + for (size_t i = 0; i < mTagCount; i++) + { + mTagString += std::string("#") + mTags[i] + ((i == mTagCount - 1) ? "" : ","); + } + } + } + + CallSite::~CallSite() + { + delete []mTags; + } void CallSite::invalidate() - { mCached = false; } + { + mCached = false; + } } namespace @@ -543,21 +635,24 @@ namespace } - void commonInit(const std::string& dir) + void commonInit(const std::string& dir, bool log_to_stderr = true) { - LLError::Settings::reset(); + AIAccess(LLError::Settings::get())->reset(); LLError::setDefaultLevel(LLError::LEVEL_INFO); LLError::setFatalFunction(LLError::crashAndLoop); LLError::setTimeFunction(LLError::utcTime); - if (shouldLogToStderr()) + // log_to_stderr is only false in the unit and integration tests to keep builds quieter + if (log_to_stderr && shouldLogToStderr()) { - LLError::addRecorder(new RecordToStderr(stderrLogWantsTime())); + LLError::RecorderPtr recordToStdErr(new RecordToStderr(stderrLogWantsTime())); + LLError::addRecorder(recordToStdErr); } #if LL_WINDOWS - LLError::addRecorder(new RecordToWinDebug); + LLError::RecorderPtr recordToWinDebug(new RecordToWinDebug()); + LLError::addRecorder(recordToWinDebug); #endif LogControlFile& e = LogControlFile::fromDirectory(dir); @@ -585,18 +680,19 @@ namespace LLError } commonInit(dir); #if !LL_WINDOWS - addRecorder(new RecordToSyslog(identity)); + LLError::RecorderPtr recordToSyslog(new RecordToSyslog(identity)); + addRecorder(recordToSyslog); #endif } - void initForApplication(const std::string& dir) + void initForApplication(const std::string& dir, bool log_to_stderr) { - commonInit(dir); + commonInit(dir, log_to_stderr); } void setPrintLocation(AIAccess const& settings_w, bool print) { - settings_w->printLocation = print; + settings_w->getSettingsConfig()->mPrintLocation = print; } void setPrintLocation(bool print) @@ -606,23 +702,23 @@ namespace LLError void setFatalFunction(const FatalFunction& f) { - AIAccess(Settings::get())->crashFunction = f; + AIAccess(Settings::get())->getSettingsConfig()->mCrashFunction = f; } FatalFunction getFatalFunction() { - return AIAccess(Settings::get())->crashFunction; + return AIAccess(Settings::get())->getSettingsConfig()->mCrashFunction; } void setTimeFunction(TimeFunction f) { - AIAccess(Settings::get())->timeFunction = f; + AIAccess(Settings::get())->getSettingsConfig()->mTimeFunction = f; } void setDefaultLevel(AIAccess const& settings_w, ELevel level) { AIAccess(Globals::get())->invalidateCallSites(); - settings_w->defaultLevel = level; + settings_w->getSettingsConfig()->mDefaultLevel = level; } void setDefaultLevel(ELevel level) @@ -633,29 +729,27 @@ namespace LLError void setFunctionLevel(const std::string& function_name, ELevel level) { AIAccess(Globals::get())->invalidateCallSites(); - AIAccess(Settings::get())->functionLevelMap[function_name] = level; + AIAccess(Settings::get())->getSettingsConfig()->mFunctionLevelMap[function_name] = level; } void setClassLevel(const std::string& class_name, ELevel level) { AIAccess(Globals::get())->invalidateCallSites(); - AIAccess(Settings::get())->classLevelMap[class_name] = level; + AIAccess(Settings::get())->getSettingsConfig()->mClassLevelMap[class_name] = level; } void setFileLevel(const std::string& file_name, ELevel level) { AIAccess(Globals::get())->invalidateCallSites(); - AIAccess(Settings::get())->fileLevelMap[file_name] = level; + AIAccess(Settings::get())->getSettingsConfig()->mFileLevelMap[file_name] = level; } void setTagLevel(const std::string& tag_name, ELevel level) { AIAccess(Globals::get())->invalidateCallSites(); - AIAccess(Settings::get())->tagLevelMap[tag_name] = level; + AIAccess(Settings::get())->getSettingsConfig()->mTagLevelMap[tag_name] = level; } -} -namespace { LLError::ELevel decodeLevel(std::string name) { static LevelMap level_names; @@ -674,13 +768,15 @@ namespace { LevelMap::const_iterator i = level_names.find(name); if (i == level_names.end()) { - llwarns << "unrecognized logging level: '" << name << "'" << llendl; + LL_WARNS() << "unrecognized logging level: '" << name << "'" << LL_ENDL; return LLError::LEVEL_INFO; } return i->second; } - +} + +namespace { void setLevels(LevelMap& map, const LLSD& list, LLError::ELevel level) { LLSD::array_const_iterator i, end; @@ -697,11 +793,13 @@ namespace LLError { AIAccess settings_w(Settings::get()); AIAccess(Globals::get())->invalidateCallSites(); - settings_w->functionLevelMap.clear(); - settings_w->classLevelMap.clear(); - settings_w->fileLevelMap.clear(); - settings_w->tagLevelMap.clear(); - settings_w->uniqueLogMessages.clear(); + SettingsConfigPtr s = settings_w->getSettingsConfig(); + + s->mFunctionLevelMap.clear(); + s->mClassLevelMap.clear(); + s->mFileLevelMap.clear(); + s->mTagLevelMap.clear(); + s->mUniqueLogMessages.clear(); setPrintLocation(settings_w, config["print-location"]); setDefaultLevel(settings_w, decodeLevel(config["default-level"])); @@ -714,10 +812,10 @@ namespace LLError ELevel level = decodeLevel(entry["level"]); - setLevels(settings_w->functionLevelMap, entry["functions"], level); - setLevels(settings_w->classLevelMap, entry["classes"], level); - setLevels(settings_w->fileLevelMap, entry["files"], level); - setLevels(settings_w->tagLevelMap, entry["tags"], level); + setLevels(s->mFunctionLevelMap, entry["functions"], level); + setLevels(s->mClassLevelMap, entry["classes"], level); + setLevels(s->mFileLevelMap, entry["files"], level); + setLevels(s->mTagLevelMap, entry["tags"], level); } } } @@ -725,41 +823,75 @@ namespace LLError namespace LLError { + Recorder::Recorder() + : mWantsTime(false), + mWantsTags(false), + mWantsLevel(true), + mWantsLocation(false), + mWantsFunctionName(true) + { + } + Recorder::~Recorder() - { } + { + } - // virtual bool Recorder::wantsTime() - { return false; } + { + return mWantsTime; + } + // virtual + bool Recorder::wantsTags() + { + return mWantsTags; + } + + // virtual + bool Recorder::wantsLevel() + { + return mWantsLevel; + } + + // virtual + bool Recorder::wantsLocation() + { + return mWantsLocation; + } + // virtual + bool Recorder::wantsFunctionName() + { + return mWantsFunctionName; + } - void addRecorder(AIAccess const& settings_w, Recorder* recorder) + void addRecorder(AIAccess const& settings_w, RecorderPtr recorder) { - if (recorder == NULL) + if (!recorder) { return; } - settings_w->recorders.push_back(recorder); + SettingsConfigPtr s = settings_w->getSettingsConfig(); + s->mRecorders.push_back(recorder); } - - void addRecorder(Recorder* recorder) + + void addRecorder(RecorderPtr recorder) { addRecorder(AIAccess(Settings::get()), recorder); } - void removeRecorder(AIAccess const& settings_w, Recorder* recorder) + void removeRecorder(AIAccess const& settings_w, RecorderPtr recorder) { - if (recorder == NULL) + if (!recorder) { return; } - settings_w->recorders.erase( - std::remove(settings_w->recorders.begin(), settings_w->recorders.end(), recorder), - settings_w->recorders.end()); + SettingsConfigPtr s = settings_w->getSettingsConfig(); + s->mRecorders.erase(std::remove(s->mRecorders.begin(), s->mRecorders.end(), recorder), + s->mRecorders.end()); } - void removeRecorder(Recorder* recorder) + void removeRecorder(RecorderPtr recorder) { removeRecorder(AIAccess(Settings::get()), recorder); } @@ -770,125 +902,148 @@ namespace LLError void logToFile(const std::string& file_name) { AIAccess settings_w(Settings::get()); + SettingsConfigPtr s = settings_w->getSettingsConfig(); - removeRecorder(settings_w, settings_w->fileRecorder); - delete settings_w->fileRecorder; - settings_w->fileRecorder = NULL; - settings_w->fileRecorderFileName.clear(); + removeRecorder(s->mFileRecorder); + s->mFileRecorder.reset(); + s->mFileRecorderFileName.clear(); if (file_name.empty()) { return; } - RecordToFile* f = new RecordToFile(file_name); - if (!f->okay()) + RecorderPtr recordToFile(new RecordToFile(file_name)); + if (boost::dynamic_pointer_cast(recordToFile)->okay()) { - delete f; - return; + s->mFileRecorderFileName = file_name; + s->mFileRecorder = recordToFile; + addRecorder(recordToFile); } - - settings_w->fileRecorderFileName = file_name; - settings_w->fileRecorder = f; - addRecorder(settings_w, f); } void logToFixedBuffer(LLLineBuffer* fixedBuffer) { AIAccess settings_w(Settings::get()); + SettingsConfigPtr s = settings_w->getSettingsConfig(); - removeRecorder(settings_w, settings_w->fixedBufferRecorder); - delete settings_w->fixedBufferRecorder; - settings_w->fixedBufferRecorder = NULL; + removeRecorder(s->mFixedBufferRecorder); + s->mFixedBufferRecorder.reset(); if (!fixedBuffer) { return; } - settings_w->fixedBufferRecorder = new RecordToFixedBuffer(fixedBuffer); - addRecorder(settings_w, settings_w->fixedBufferRecorder); + RecorderPtr recordToFixedBuffer(new RecordToFixedBuffer(fixedBuffer)); + s->mFixedBufferRecorder = recordToFixedBuffer; + addRecorder(recordToFixedBuffer); } std::string logFileName() { - return AIAccess(Settings::get())->fileRecorderFileName; + AIAccess settings_w(Settings::get()); + SettingsConfigPtr s = settings_w->getSettingsConfig(); + return s->mFileRecorderFileName; } } namespace { - void writeToRecorders(AIAccess const& settings_w, LLError::ELevel level, const std::string& message) + void writeToRecorders(AIAccess& settings_w, const LLError::CallSite& site, const std::string& message, bool show_location = true, bool show_time = true, bool show_tags = true, bool show_level = true, bool show_function = true) { - std::string messageWithTime; - - for (Recorders::const_iterator i = settings_w->recorders.begin(); - i != settings_w->recorders.end(); + LLError::ELevel level = site.mLevel; + LLError::SettingsConfigPtr s = settings_w->getSettingsConfig(); + + for (Recorders::const_iterator i = s->mRecorders.begin(); + i != s->mRecorders.end(); ++i) { - LLError::Recorder* r = *i; + LLError::RecorderPtr r = *i; - if (r->wantsTime() && settings_w->timeFunction != NULL) + std::ostringstream message_stream; + + if (show_location && (r->wantsLocation() || level == LLError::LEVEL_ERROR || s->mPrintLocation)) { - if (messageWithTime.empty()) - { - messageWithTime = settings_w->timeFunction() + " " + message; - } - - r->recordMessage(level, messageWithTime); + message_stream << site.mLocationString << " "; } - else + + if (show_time && r->wantsTime() && s->mTimeFunction != NULL) { - r->recordMessage(level, message); + message_stream << s->mTimeFunction() << " "; } - } - } -} + if (show_level && r->wantsLevel()) + { + message_stream << site.mLevelString; + } + + if (show_tags && r->wantsTags()) + { + message_stream << site.mTagString; + } -/* -Recorder formats: + if ((show_level && r->wantsLevel())|| + (show_tags && r->wantsTags())) + { + message_stream << " "; + } -$type = "ERROR" | "WARNING" | "ALERT" | "INFO" | "DEBUG" -$loc = "$file($line)" -$msg = "$loc : " if FATAL or printing loc - "" otherwise -$msg += "$type: " -$msg += contents of stringstream + if (show_function && r->wantsFunctionName()) + { + message_stream << site.mFunctionString << " "; + } -$time = "%Y-%m-%dT%H:%M:%SZ" if UTC - or "%Y-%m-%dT%H:%M:%S %Z" if local + message_stream << message; -syslog: "$msg" -file: "$time $msg\n" -stderr: "$time $msg\n" except on windows, "$msg\n" -fixedbuf: "$msg" -winddebug: "$msg\n" + r->recordMessage(level, message_stream.str()); + } + } +} -Note: if FATAL, an additional line gets logged first, with $msg set to - "$loc : error" - -You get: - llfoo.cpp(42) : error - llfoo.cpp(42) : ERROR: something - -*/ -extern apr_thread_mutex_t* gLogMutexp; -extern apr_thread_mutex_t* gCallStacksLogMutexp; +LLGlobalMutex gLogMutex; +LLGlobalMutex gCallStacksLogMutex; namespace { bool checkLevelMap(const LevelMap& map, const std::string& key, LLError::ELevel& level) { + bool stop_checking; LevelMap::const_iterator i = map.find(key); if (i == map.end()) { - return false; + return stop_checking = false; } level = i->second; - return true; + return stop_checking = true; + } + + bool checkLevelMap( const LevelMap& map, + const char *const * keys, + size_t count, + LLError::ELevel& level) + { + bool found_level = false; + + LLError::ELevel tag_level = LLError::LEVEL_NONE; + + for (size_t i = 0; i < count; i++) + { + LevelMap::const_iterator it = map.find(keys[i]); + if (it != map.end()) + { + found_level = true; + tag_level = llmin(tag_level, it->second); + } + } + + if (found_level) + { + level = tag_level; + } + return found_level; } class LogLock @@ -905,7 +1060,7 @@ namespace { LogLock::LogLock() : mLocked(false), mOK(false) { - if (!gLogMutexp) + if (!gLogMutex.isInitalized()) { mOK = true; return; @@ -914,8 +1069,7 @@ namespace { const int MAX_RETRIES = 5; for (int attempts = 0; attempts < MAX_RETRIES; ++attempts) { - apr_status_t s = apr_thread_mutex_trylock(gLogMutexp); - if (!APR_STATUS_IS_EBUSY(s)) + if (gLogMutex.try_lock()) { mLocked = true; mOK = true; @@ -937,7 +1091,7 @@ namespace { { if (mLocked) { - apr_thread_mutex_unlock(gLogMutexp); + gLogMutex.unlock(); } } } @@ -953,31 +1107,38 @@ namespace LLError } AIAccess settings_w(Settings::get()); + SettingsConfigPtr s = settings_w->getSettingsConfig(); - settings_w->shouldLogCallCounter += 1; + s->mShouldLogCallCounter++; - std::string class_name = className(site.mClassInfo); + const std::string& class_name = className(site.mClassInfo); std::string function_name; if (site.mFunction) { - function_name = functionName(site.mFunction); - if (site.mClassInfo != typeid(NoClassInfo)) - { - function_name = class_name + "::" + function_name; - } + function_name = functionName(site.mFunction); +#if LL_LINUX + // gross, but typeid comparison seems to always fail here with gcc4.1 + if (0 != strcmp(site.mClassInfo.name(), typeid(NoClassInfo).name())) +#else + if (site.mClassInfo != typeid(NoClassInfo)) +#endif // LL_LINUX + { + function_name = class_name + "::" + function_name; + } } - ELevel compareLevel = settings_w->defaultLevel; + ELevel compareLevel = s->mDefaultLevel; // The most specific match found will be used as the log level, // since the computation short circuits. // So, in increasing order of importance: - // Default < Broad Tag < File < Class < Function < Narrow Tag - ((site.mNarrowTag != NULL) ? checkLevelMap(settings_w->tagLevelMap, site.mNarrowTag, compareLevel) : false) - || (site.mFunction && checkLevelMap(settings_w->functionLevelMap, function_name, compareLevel)) - || checkLevelMap(settings_w->classLevelMap, class_name, compareLevel) - || checkLevelMap(settings_w->fileLevelMap, abbreviateFile(site.mFile), compareLevel) - || ((site.mBroadTag != NULL) ? checkLevelMap(settings_w->tagLevelMap, site.mBroadTag, compareLevel) : false); + // Default < Tags < File < Class < Function + checkLevelMap(s->mFunctionLevelMap, function_name, compareLevel) + || checkLevelMap(s->mClassLevelMap, class_name, compareLevel) + || checkLevelMap(s->mFileLevelMap, abbreviateFile(site.mFile), compareLevel) + || (site.mTagCount > 0 + ? checkLevelMap(s->mTagLevelMap, site.mTags, site.mTagCount, compareLevel) + : false); site.mCached = true; AIAccess(Globals::get())->addCallSite(site); @@ -990,16 +1151,16 @@ namespace LLError LogLock lock; if (lock.ok()) { - AIAccess globals(Globals::get()); + AIAccess g(Globals::get()); - if (!globals->messageStreamInUse) + if (!g->messageStreamInUse) { - globals->messageStreamInUse = true; - return &globals->messageStream; // Returns pointer to member of unlocked object, apparently "protected" by having set globals->messageStreamInUse. + g->messageStreamInUse = true; + return &g->messageStream; } } - return new std::ostringstream; // Holy memory leak. + return new std::ostringstream; } void Log::flush(std::ostringstream* out, char* message) @@ -1020,12 +1181,12 @@ namespace LLError message[127] = '\0' ; } - AIAccess globals(Globals::get()); - if (out == &globals->messageStream) + AIAccess g(Globals::get()); + if (out == &g->messageStream) { - globals->messageStream.clear(); - globals->messageStream.str(""); - globals->messageStreamInUse = false; + g->messageStream.clear(); + g->messageStream.str(""); + g->messageStreamInUse = false; } else { @@ -1043,14 +1204,13 @@ namespace LLError } std::string message = out->str(); - { - AIAccess globals(Globals::get()); - if (out == &globals->messageStream) + AIAccess g(Globals::get()); + if (out == &g->messageStream) { - globals->messageStream.clear(); - globals->messageStream.str(""); - globals->messageStreamInUse = false; + g->messageStream.clear(); + g->messageStream.str(""); + g->messageStreamInUse = false; } else { @@ -1059,98 +1219,40 @@ namespace LLError } AIAccess settings_w(Settings::get()); - + SettingsConfigPtr s = settings_w->getSettingsConfig(); + if (site.mLevel == LEVEL_ERROR) { - std::ostringstream fatalMessage; - fatalMessage << abbreviateFile(site.mFile) - << "(" << site.mLine << ") : error"; - - writeToRecorders(settings_w, site.mLevel, fatalMessage.str()); + writeToRecorders(settings_w, site, "error", true, true, true, false, false); } - - std::ostringstream prefix; - - switch (site.mLevel) - { - case LEVEL_DEBUG: prefix << "DEBUG"; break; - case LEVEL_INFO: prefix << "INFO"; break; - case LEVEL_WARN: prefix << "WARNING"; break; - case LEVEL_ERROR: prefix << "ERROR"; break; - default: prefix << "XXX"; break; - }; + std::ostringstream message_stream; bool need_function = site.mFunction; - if (need_function && site.mBroadTag && *site.mBroadTag != '\0') + if (need_function && !site.mTagString.empty()) { - prefix << "(\"" << site.mBroadTag << "\")"; #if LL_DEBUG // Suppress printing mFunction if mBroadTag is set, starts with // "Plugin " and ends with "child": a debug message from a plugin. - size_t taglen = strlen(site.mBroadTag); - if (taglen >= 12 && strncmp(site.mBroadTag, "Plugin ", 7) == 0 && - strcmp(site.mBroadTag + taglen - 5, "child") == 0) + size_t taglen = site.mTagString.length(); + if (taglen >= 12 && strncmp(site.mTagString.c_str(), "Plugin ", 7) == 0 && + strcmp(site.mTagString.c_str() + taglen - 5, "child") == 0) { need_function = false; } #endif } - prefix << ": "; - - if (need_function) - { - if (settings_w->printLocation) - { - prefix << abbreviateFile(site.mFile) - << "(" << site.mLine << ") : "; - } - -#if LL_WINDOWS - // DevStudio: __FUNCTION__ already includes the full class name -#else - if (site.mClassInfo != typeid(NoClassInfo)) - { - prefix << className(site.mClassInfo) << "::"; - } -#endif - prefix << site.mFunction << ": "; - } - - if (site.mPrintOnce) - { - std::map::iterator messageIter = settings_w->uniqueLogMessages.find(message); - if (messageIter != settings_w->uniqueLogMessages.end()) - { - messageIter->second++; - unsigned int num_messages = messageIter->second; - if (num_messages == 10 || num_messages == 50 || (num_messages % 100) == 0) - { - prefix << "ONCE (" << num_messages << "th time seen): "; - } - else - { - return; - } - } - else - { - prefix << "ONCE: "; - settings_w->uniqueLogMessages[message] = 1; - } - } - if (site.mPrintOnce) { - std::map::iterator messageIter = settings_w->uniqueLogMessages.find(message); - if (messageIter != settings_w->uniqueLogMessages.end()) + std::map::iterator messageIter = s->mUniqueLogMessages.find(message); + if (messageIter != s->mUniqueLogMessages.end()) { messageIter->second++; unsigned int num_messages = messageIter->second; if (num_messages == 10 || num_messages == 50 || (num_messages % 100) == 0) { - prefix << "ONCE (" << num_messages << "th time seen): "; + message_stream << "ONCE (" << num_messages << "th time seen): "; } else { @@ -1159,38 +1261,32 @@ namespace LLError } else { - prefix << "ONCE: "; - settings_w->uniqueLogMessages[message] = 1; + message_stream << "ONCE: "; + s->mUniqueLogMessages[message] = 1; } } - prefix << message; - message = prefix.str(); + message_stream << message; - writeToRecorders(settings_w, site.mLevel, message); + writeToRecorders(settings_w, site, message_stream.str(), true, true, true, true, need_function); - if (site.mLevel == LEVEL_ERROR && settings_w->crashFunction) + if (site.mLevel == LEVEL_ERROR && s->mCrashFunction) { - settings_w->crashFunction(message); + s->mCrashFunction(message_stream.str()); } } } - - - namespace LLError { - class ThreadSafeSettings { }; - - ThreadSafeSettings* saveAndResetSettings() + SettingsStoragePtr saveAndResetSettings() { - return reinterpret_cast(Settings::saveAndReset()); + return AIAccess(Settings::get())->saveAndReset(); } - void restoreSettings(ThreadSafeSettings* s) + void restoreSettings(SettingsStoragePtr pSettingsStorage) { - Settings::restore(reinterpret_cast*>(s)); + return AIAccess(Settings::get())->restore(pSettingsStorage); } std::string removePrefix(std::string& s, const std::string& p) @@ -1236,11 +1332,13 @@ namespace LLError int shouldLogCallCount() { - return AIAccess(Settings::get())->shouldLogCallCounter; + AIAccess settings_w(Settings::get()); + SettingsConfigPtr s = settings_w->getSettingsConfig(); + return s->mShouldLogCallCounter; } #if LL_WINDOWS - // VC80 was optimizing the error away. + // MSVC is optimizing the error away. #pragma optimize("", off) #endif void crashAndLoop(const std::string& message) @@ -1249,9 +1347,8 @@ namespace LLError DoutFatal(dc::core, message); #else // Now, we go kaboom! - int* make_me_crash = NULL; - - *make_me_crash = 0; + int* make_me_crash = nullptr; + *make_me_crash = 0xDEADBEEF; while(true) { @@ -1282,24 +1379,39 @@ namespace LLError namespace LLError { - char** LLCallStacks::sBuffer = NULL ; - S32 LLCallStacks::sIndex = 0 ; + char** LLCallStacks::sBuffer = NULL; + S32 LLCallStacks::sIndex = 0; + +#define SINGLE_THREADED 1 class CallStacksLogLock { public: CallStacksLogLock(); ~CallStacksLogLock(); + +#if SINGLE_THREADED + bool ok() const { return true; } +#else bool ok() const { return mOK; } private: bool mLocked; bool mOK; +#endif }; +#if SINGLE_THREADED + CallStacksLogLock::CallStacksLogLock() + { + } + CallStacksLogLock::~CallStacksLogLock() + { + } +#else CallStacksLogLock::CallStacksLogLock() : mLocked(false), mOK(false) { - if (!gCallStacksLogMutexp) + if (!gCallStacksLogMutex.isInitalized()) { mOK = true; return; @@ -1308,8 +1420,7 @@ namespace LLError const int MAX_RETRIES = 5; for (int attempts = 0; attempts < MAX_RETRIES; ++attempts) { - apr_status_t s = apr_thread_mutex_trylock(gCallStacksLogMutexp); - if (!APR_STATUS_IS_EBUSY(s)) + if (gCallStacksLogMutex.try_lock()) { mLocked = true; mOK = true; @@ -1328,20 +1439,15 @@ namespace LLError { if (mLocked) { - apr_thread_mutex_unlock(gCallStacksLogMutexp); + gCallStacksLogMutex.unlock(); } } +#endif //static - void LLCallStacks::push(const char* function, const int line) + void LLCallStacks::allocateStackBuffer() { - CallStacksLogLock lock; - if (!lock.ok()) - { - return; - } - - if(!sBuffer) + if(sBuffer == NULL) { sBuffer = new char*[512] ; sBuffer[0] = new char[512 * 128] ; @@ -1351,6 +1457,31 @@ namespace LLError } sIndex = 0 ; } + } + + void LLCallStacks::freeStackBuffer() + { + if(sBuffer != NULL) + { + delete [] sBuffer[0] ; + delete [] sBuffer ; + sBuffer = NULL ; + } + } + + //static + void LLCallStacks::push(const char* function, const int line) + { + CallStacksLogLock lock; + if (!lock.ok()) + { + return; + } + + if(sBuffer == NULL) + { + allocateStackBuffer(); + } if(sIndex > 511) { @@ -1382,15 +1513,9 @@ namespace LLError return; } - if(!sBuffer) + if(sBuffer == NULL) { - sBuffer = new char*[512] ; - sBuffer[0] = new char[512 * 128] ; - for(S32 i = 1 ; i < 512 ; i++) - { - sBuffer[i] = sBuffer[i-1] + 128 ; - } - sIndex = 0 ; + allocateStackBuffer(); } if(sIndex > 511) @@ -1412,20 +1537,18 @@ namespace LLError if(sIndex > 0) { - llinfos << " ************* PRINT OUT LL CALL STACKS ************* " << llendl ; + LL_INFOS() << " ************* PRINT OUT LL CALL STACKS ************* " << LL_ENDL; while(sIndex > 0) { sIndex-- ; - llinfos << sBuffer[sIndex] << llendl ; + LL_INFOS() << sBuffer[sIndex] << LL_ENDL; } - llinfos << " *************** END OF LL CALL STACKS *************** " << llendl ; + LL_INFOS() << " *************** END OF LL CALL STACKS *************** " << LL_ENDL; } - if(sBuffer) + if(sBuffer != NULL) { - delete[] sBuffer[0] ; - delete[] sBuffer ; - sBuffer = NULL ; + freeStackBuffer(); } } @@ -1434,5 +1557,11 @@ namespace LLError { sIndex = 0 ; } + + //static + void LLCallStacks::cleanup() + { + freeStackBuffer(); + } } diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h index f367d5e656..90ef40bf60 100644 --- a/indra/llcommon/llerror.h +++ b/indra/llcommon/llerror.h @@ -31,9 +31,72 @@ #include #include -#include "llerrorlegacy.h" #include "stdtypes.h" +#include "llpreprocessor.h" +#include + +const int LL_ERR_NOERR = 0; + +// Define one of these for different error levels in release... +// #define RELEASE_SHOW_DEBUG // Define this if you want your release builds to show lldebug output. +#define RELEASE_SHOW_INFO // Define this if you want your release builds to show llinfo output +#define RELEASE_SHOW_WARN // Define this if you want your release builds to show llwarn output. + +#ifdef _DEBUG +#define SHOW_DEBUG +#define SHOW_WARN +#define SHOW_INFO +#define SHOW_ASSERT +#else // _DEBUG + +#ifdef LL_RELEASE_WITH_DEBUG_INFO +#define SHOW_ASSERT +#endif // LL_RELEASE_WITH_DEBUG_INFO + +#ifdef RELEASE_SHOW_DEBUG +#define SHOW_DEBUG +#endif + +#ifdef RELEASE_SHOW_WARN +#define SHOW_WARN +#endif + +#ifdef RELEASE_SHOW_INFO +#define SHOW_INFO +#endif + +#ifdef RELEASE_SHOW_ASSERT +#define SHOW_ASSERT +#endif + +#endif // !_DEBUG + +inline const std::string liru_assert_strip(const std::string& file) { return file.substr(1+file.substr(0, file.find_last_of("/\\")).find_last_of("/\\")); } //return foo/bar.cpp or perhaps foo\bar.cpp + +#define llassert_always_msg(func, msg) if (LL_UNLIKELY(!(func))) LL_ERRS() << "ASSERT (" << msg << ")\nfile:" << liru_assert_strip(__FILE__) << " line:" << std::dec << __LINE__ << LL_ENDL + +#define llassert_always(func) llassert_always_msg(func, #func) + +#ifdef SHOW_ASSERT +#define llassert(func) llassert_always_msg(func, #func) +#define llverify(func) llassert_always_msg(func, #func) +#define ASSERT_ONLY(...) __VA_ARGS__ +#define ASSERT_ONLY_COMMA(...) , __VA_ARGS__ +#else +#define llassert(func) +#define llverify(func) do {if (func) {}} while(0) +#define ASSERT_ONLY(...) +#define ASSERT_ONLY_COMMA(...) +#endif + +#ifdef LL_WINDOWS +#define LL_STATIC_ASSERT(func, msg) static_assert(func, msg) +#define LL_BAD_TEMPLATE_INSTANTIATION(type, msg) static_assert(false, msg) +#else +#define LL_STATIC_ASSERT(func, msg) BOOST_STATIC_ASSERT(func) +#define LL_BAD_TEMPLATE_INSTANTIATION(type, msg) BOOST_STATIC_ASSERT(sizeof(type) != 0 && false); +#endif /** Error Logging Facility @@ -122,46 +185,62 @@ namespace LLError They are not intended for general use. */ - class CallSite; + struct CallSite; class LL_COMMON_API Log { public: static bool shouldLog(CallSite&); static std::ostringstream* out(); - static void flush(std::ostringstream* out, char* message) ; + static void flush(std::ostringstream* out, char* message); static void flush(std::ostringstream*, const CallSite&); }; - class LL_COMMON_API CallSite + struct LL_COMMON_API CallSite { // Represents a specific place in the code where a message is logged // This is public because it is used by the macros below. It is not // intended for public use. - public: - CallSite(ELevel, const char* file, int line, - const std::type_info& class_info, const char* function, const char* broadTag, const char* narrowTag, bool printOnce); - + CallSite(ELevel level, + const char* file, + int line, + const std::type_info& class_info, + const char* function, + bool print_once, + const char** tags, + size_t tag_count); + + ~CallSite(); + +#ifdef LL_LIBRARY_INCLUDE + bool shouldLog(); +#else // LL_LIBRARY_INCLUDE bool shouldLog() - { return mCached ? mShouldLog : Log::shouldLog(*this); } + { + return mCached + ? mShouldLog + : Log::shouldLog(*this); + } // this member function needs to be in-line for efficiency +#endif // LL_LIBRARY_INCLUDE void invalidate(); - private: // these describe the call site and never change const ELevel mLevel; const char* const mFile; - const int mLine; - const std::type_info& mClassInfo; + const int mLine; + const std::type_info& mClassInfo; const char* const mFunction; - const char* const mBroadTag; - const char* const mNarrowTag; - const bool mPrintOnce; - - // these implement a cache of the call to shouldLog() - bool mCached; - bool mShouldLog; + const char** mTags; + size_t mTagCount; + const bool mPrintOnce; + const char* mLevelString; + std::string mLocationString, + mFunctionString, + mTagString; + bool mCached, + mShouldLog; friend class Log; }; @@ -187,6 +266,9 @@ namespace LLError private: static char** sBuffer ; static S32 sIndex ; + + static void allocateStackBuffer(); + static void freeStackBuffer(); public: static void push(const char* function, const int line) ; @@ -194,21 +276,25 @@ namespace LLError static void print() ; static void clear() ; static void end(std::ostringstream* _out) ; + static void cleanup(); }; } //this is cheaper than llcallstacks if no need to output other variables to call stacks. -#define llpushcallstacks LLError::LLCallStacks::push(__FUNCTION__, __LINE__) -#define llcallstacks \ - {\ +#define LL_PUSH_CALLSTACKS() LLError::LLCallStacks::push(__FUNCTION__, __LINE__) + +#define llcallstacks \ + { \ std::ostringstream* _out = LLError::LLCallStacks::insert(__FUNCTION__, __LINE__) ; \ (*_out) -#define llcallstacksendl \ - LLError::End(); \ + +#define llcallstacksendl \ + LLError::End(); \ LLError::LLCallStacks::end(_out) ; \ } -#define llclearcallstacks LLError::LLCallStacks::clear() -#define llprintcallstacks LLError::LLCallStacks::print() + +#define LL_CLEAR_CALLSTACKS() LLError::LLCallStacks::clear() +#define LL_PRINT_CALLSTACKS() LLError::LLCallStacks::print() /* Class type information for logging @@ -222,83 +308,84 @@ typedef LLError::NoClassInfo _LL_CLASS_TO_LOG; // Outside a class declaration, or in class without LOG_CLASS(), this // typedef causes the messages to not be associated with any class. +///////////////////////////////// +// Error Logging Macros +// See top of file for common usage. +///////////////////////////////// +// this macro uses a one-shot do statement to avoid parsing errors when writing control flow statements +// without braces: +// if (condition) LL_INFOS() << "True" << LL_ENDL; else LL_INFOS()() << "False" << LL_ENDL +#define lllog(level, once, nofunction, ...) \ + do { \ + const char* tags[] = {"", ##__VA_ARGS__}; \ + ::size_t tag_count = LL_ARRAY_SIZE(tags) - 1; \ + static LLError::CallSite _site( \ + level, __FILE__, __LINE__, typeid(_LL_CLASS_TO_LOG), nofunction ? NULL : __FUNCTION__, once, &tags[1], tag_count);\ + if (LL_UNLIKELY(_site.shouldLog())) \ + { \ + std::ostringstream* _out = LLError::Log::out(); \ + (*_out) +//Use this construct if you need to do computation in the middle of a +//message: +// +// LL_INFOS("AgentGesture") << "the agent " << agend_id; +// switch (f) +// { +// case FOP_SHRUGS: LL_CONT << "shrugs"; break; +// case FOP_TAPS: LL_CONT << "points at " << who; break; +// case FOP_SAYS: LL_CONT << "says " << message; break; +// } +// LL_CONT << " for " << t << " seconds" << LL_ENDL; +// +//Such computation is done iff the message will be logged. +#define LL_CONT (*_out) -/* - Error Logging Macros - See top of file for common usage. -*/ +#define LL_NEWLINE '\n' -#define lllog(level, broadTag, narrowTag, once, nofunction) \ - do { \ - static LLError::CallSite _site( \ - level, __FILE__, __LINE__, typeid(_LL_CLASS_TO_LOG), nofunction ? NULL : __FUNCTION__, broadTag, narrowTag, once);\ - if (LL_UNLIKELY(_site.shouldLog())) \ - { \ - std::ostringstream* _out = LLError::Log::out(); \ - (*_out) - -// DEPRECATED: Don't call directly, use LL_ENDL instead, which actually looks like a macro -#define llendl \ - LLError::End(); \ +#define LL_ENDL \ + LLError::End(); \ LLError::Log::flush(_out, _site); \ - } \ + } \ } while(0) -// DEPRECATED: Use the new macros that allow tags and *look* like macros. -#define lldebugs lllog(LLError::LEVEL_DEBUG, NULL, NULL, false, false) -#define llinfos lllog(LLError::LEVEL_INFO, NULL, NULL, false, false) -#define llwarns lllog(LLError::LEVEL_WARN, NULL, NULL, false, false) -#define llerrs lllog(LLError::LEVEL_ERROR, NULL, NULL, false, false) -#define llcont (*_out) - -// No function name -#define lldebugs_nf lllog(LLError::LEVEL_DEBUG, NULL, NULL, false, true) -#define llinfos_nf lllog(LLError::LEVEL_INFO, NULL, NULL, false, true) -#define llwarns_nf lllog(LLError::LEVEL_WARN, NULL, NULL, false, true) -#define llerrs_nf lllog(LLError::LEVEL_ERROR, NULL, NULL, false, true) - // NEW Macros for debugging, allow the passing of a string tag -// One Tag -#define LL_DEBUGS(broadTag) lllog(LLError::LEVEL_DEBUG, broadTag, NULL, false, false) -#define LL_INFOS(broadTag) lllog(LLError::LEVEL_INFO, broadTag, NULL, false, false) -#define LL_WARNS(broadTag) lllog(LLError::LEVEL_WARN, broadTag, NULL, false, false) -#define LL_ERRS(broadTag) lllog(LLError::LEVEL_ERROR, broadTag, NULL, false, false) -// Two Tags -#define LL_DEBUGS2(broadTag, narrowTag) lllog(LLError::LEVEL_DEBUG, broadTag, narrowTag, false, false) -#define LL_INFOS2(broadTag, narrowTag) lllog(LLError::LEVEL_INFO, broadTag, narrowTag, false, false) -#define LL_WARNS2(broadTag, narrowTag) lllog(LLError::LEVEL_WARN, broadTag, narrowTag, false, false) -#define LL_ERRS2(broadTag, narrowTag) lllog(LLError::LEVEL_ERROR, broadTag, narrowTag, false, false) +#ifdef SHOW_DEBUG +#define DO_DEBUG_LOG +#else +#define DO_DEBUG_LOG if (false) +#endif + +// Pass comma separated list of tags (currently only supports up to 0, 1, or 2) +#define LL_DEBUGS(...) DO_DEBUG_LOG lllog(LLError::LEVEL_DEBUG, false, false, ##__VA_ARGS__) +#define LL_INFOS(...) lllog(LLError::LEVEL_INFO, false, false, ##__VA_ARGS__) +#define LL_WARNS(...) lllog(LLError::LEVEL_WARN, false, false, ##__VA_ARGS__) +#define LL_ERRS(...) lllog(LLError::LEVEL_ERROR, false, false, ##__VA_ARGS__) +// alternative to llassert_always that prints explanatory message +#define LL_ERRS_IF(exp, ...) if (exp) LL_ERRS(##__VA_ARGS__) << "(" #exp ")" // Only print the log message once (good for warnings or infos that would otherwise // spam the log file over and over, such as tighter loops). -#define LL_DEBUGS_ONCE(broadTag) lllog(LLError::LEVEL_DEBUG, broadTag, NULL, true, false) -#define LL_INFOS_ONCE(broadTag) lllog(LLError::LEVEL_INFO, broadTag, NULL, true, false) -#define LL_WARNS_ONCE(broadTag) lllog(LLError::LEVEL_WARN, broadTag, NULL, true, false) -#define LL_DEBUGS2_ONCE(broadTag, narrowTag) lllog(LLError::LEVEL_DEBUG, broadTag, narrowTag, true, false) -#define LL_INFOS2_ONCE(broadTag, narrowTag) lllog(LLError::LEVEL_INFO, broadTag, narrowTag, true, false) -#define LL_WARNS2_ONCE(broadTag, narrowTag) lllog(LLError::LEVEL_WARN, broadTag, narrowTag, true, false) - -#define LL_ENDL llendl -#define LL_CONT (*_out) +#define LL_DEBUGS_ONCE(...) DO_DEBUG_LOG lllog(LLError::LEVEL_DEBUG, true, false, ##__VA_ARGS__) +#define LL_INFOS_ONCE(...) lllog(LLError::LEVEL_INFO, true, false, ##__VA_ARGS__) +#define LL_WARNS_ONCE(...) lllog(LLError::LEVEL_WARN, true, false, ##__VA_ARGS__) + +// No function name +#define LL_DEBUGS_NF(...) DO_DEBUG_LOG {lllog(LLError::LEVEL_DEBUG, false, true, ##__VA_ARGS__) +#define LL_INFOS_NF(...) lllog(LLError::LEVEL_INFO, false, true, ##__VA_ARGS__) +#define LL_WARNS_NF(...) lllog(LLError::LEVEL_WARN, false, true, ##__VA_ARGS__) +#define LL_ERRS_NF(...) lllog(LLError::LEVEL_ERROR, false, true, ##__VA_ARGS__) + +// DEPRECATED: Use the new macros that allow tags and *look* like macros. +#define lldebugs LL_COMPILE_TIME_MESSAGE("Warning: lldebugs deprecated, use LL_DEBUGS() instead") LL_DEBUGS() +#define llinfos LL_COMPILE_TIME_MESSAGE("Warning: llinfos deprecated, use LL_INFOS() instead") LL_INFOS() +#define llwarns LL_COMPILE_TIME_MESSAGE("Warning: llwarns deprecated, use LL_WARNS() instead") LL_WARNS() +#define llerrs LL_COMPILE_TIME_MESSAGE("Warning: llerrs deprecated, use LL_ERRS() instead") LL_ERRS() +#define llcont LL_COMPILE_TIME_MESSAGE("Warning: llcont deprecated, use LL_CONT instead") LL_CONT +#define llendl LL_COMPILE_TIME_MESSAGE("Warning: llendl deprecated, use LL_ENDL instead") LL_ENDL - /* - Use this construct if you need to do computation in the middle of a - message: - - LL_INFOS("AgentGesture") << "the agent " << agend_id; - switch (f) - { - case FOP_SHRUGS: LL_CONT << "shrugs"; break; - case FOP_TAPS: LL_CONT << "points at " << who; break; - case FOP_SAYS: LL_CONT << "says " << message; break; - } - LL_CONT << " for " << t << " seconds" << LL_ENDL; - - Such computation is done iff the message will be logged. - */ #endif // LL_LLERROR_H diff --git a/indra/llcommon/llerrorcontrol.h b/indra/llcommon/llerrorcontrol.h index 58a7c9f212..56ac52e5de 100644 --- a/indra/llcommon/llerrorcontrol.h +++ b/indra/llcommon/llerrorcontrol.h @@ -29,7 +29,10 @@ #define LL_LLERRORCONTROL_H #include "llerror.h" +#include "llpointer.h" +#include "llrefcount.h" #include "boost/function.hpp" +#include "boost/shared_ptr.hpp" #include class LLSD; @@ -62,7 +65,7 @@ namespace LLError // logs to stderr, syslog, and windows debug log // the identity string is used for in the syslog - LL_COMMON_API void initForApplication(const std::string& dir); + LL_COMMON_API void initForApplication(const std::string& dir, bool log_to_stderr = true); // resets all logging settings to defaults needed by applicaitons // logs to stderr and windows debug log // sets up log configuration from the file logcontrol.xml in dir @@ -72,14 +75,16 @@ namespace LLError Settings that control what is logged. Setting a level means log messages at that level or above. */ - + LL_COMMON_API void setPrintLocation(bool); LL_COMMON_API void setDefaultLevel(LLError::ELevel); + LL_COMMON_API ELevel getDefaultLevel(); LL_COMMON_API void setFunctionLevel(const std::string& function_name, LLError::ELevel); LL_COMMON_API void setClassLevel(const std::string& class_name, LLError::ELevel); LL_COMMON_API void setFileLevel(const std::string& file_name, LLError::ELevel); LL_COMMON_API void setTagLevel(const std::string& file_name, LLError::ELevel); - + + LL_COMMON_API LLError::ELevel decodeLevel(std::string name); LL_COMMON_API void configure(const LLSD&); // the LLSD can configure all of the settings // usually read automatically from the live errorlog.xml file @@ -134,26 +139,34 @@ namespace LLError { // An object that handles the actual output or error messages. public: + Recorder(); virtual ~Recorder(); virtual void recordMessage(LLError::ELevel, const std::string& message) = 0; // use the level for better display, not for filtering - virtual bool wantsTime(); // default returns false - // override and return true if the recorder wants the time string - // included in the text of the message + bool wantsTime(); + bool wantsTags(); + bool wantsLevel(); + bool wantsLocation(); + bool wantsFunctionName(); + + protected: + bool mWantsTime, + mWantsTags, + mWantsLevel, + mWantsLocation, + mWantsFunctionName; }; + typedef boost::shared_ptr RecorderPtr; + /** - * @NOTE: addRecorder() conveys ownership to the underlying Settings - * object -- when destroyed, it will @em delete the passed Recorder*! - */ - LL_COMMON_API void addRecorder(Recorder*); - /** - * @NOTE: removeRecorder() reclaims ownership of the Recorder*: its - * lifespan becomes the caller's problem. + * @NOTE: addRecorder() and removeRecorder() uses the boost::shared_ptr to allow for shared ownership + * while still ensuring that the allocated memory is eventually freed */ - LL_COMMON_API void removeRecorder(Recorder*); + LL_COMMON_API void addRecorder(RecorderPtr); + LL_COMMON_API void removeRecorder(RecorderPtr); // each error message is passed to each recorder via recordMessage() LL_COMMON_API void logToFile(const std::string& filename); @@ -170,13 +183,12 @@ namespace LLError Utilities for use by the unit tests of LLError itself. */ - class ThreadSafeSettings; - LL_COMMON_API ThreadSafeSettings* saveAndResetSettings(); - LL_COMMON_API void restoreSettings(ThreadSafeSettings *); - + typedef LLPointer SettingsStoragePtr; + LL_COMMON_API SettingsStoragePtr saveAndResetSettings(); + LL_COMMON_API void restoreSettings(SettingsStoragePtr pSettingsStorage); + LL_COMMON_API std::string abbreviateFile(const std::string& filePath); LL_COMMON_API int shouldLogCallCount(); - }; #endif // LL_LLERRORCONTROL_H diff --git a/indra/llcommon/llerrorlegacy.h b/indra/llcommon/llerrorlegacy.h index 146aa9206c..31dd207008 100644 --- a/indra/llcommon/llerrorlegacy.h +++ b/indra/llcommon/llerrorlegacy.h @@ -28,117 +28,5 @@ #ifndef LL_LLERRORLEGACY_H #define LL_LLERRORLEGACY_H -#include "llpreprocessor.h" - -/* - LEGACY -- DO NOT USE THIS STUFF ANYMORE -*/ - -// Specific error codes -const int LL_ERR_NOERR = 0; -const int LL_ERR_ASSET_REQUEST_FAILED = -1; -//const int LL_ERR_ASSET_REQUEST_INVALID = -2; -const int LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE = -3; -const int LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE = -4; -const int LL_ERR_INSUFFICIENT_PERMISSIONS = -5; -const int LL_ERR_EOF = -39; -const int LL_ERR_CANNOT_OPEN_FILE = -42; -const int LL_ERR_FILE_NOT_FOUND = -43; -const int LL_ERR_FILE_EMPTY = -44; -const int LL_ERR_TCP_TIMEOUT = -23016; -const int LL_ERR_CIRCUIT_GONE = -23017; -const int LL_ERR_PRICE_MISMATCH = -23018; - - - -// Define one of these for different error levels in release... -// #define RELEASE_SHOW_DEBUG // Define this if you want your release builds to show lldebug output. -#define RELEASE_SHOW_INFO // Define this if you want your release builds to show llinfo output -#define RELEASE_SHOW_WARN // Define this if you want your release builds to show llwarn output. - - -////////////////////////////////////////// -// -// Implementation - ignore -// -// -#ifdef _DEBUG -#define SHOW_DEBUG -#define SHOW_WARN -#define SHOW_INFO -#define SHOW_ASSERT -#else // _DEBUG - -#ifdef LL_RELEASE_WITH_DEBUG_INFO -#define SHOW_ASSERT -#endif // LL_RELEASE_WITH_DEBUG_INFO - -#ifdef RELEASE_SHOW_DEBUG -#define SHOW_DEBUG -#endif - -#ifdef RELEASE_SHOW_WARN -#define SHOW_WARN -#endif - -#ifdef RELEASE_SHOW_INFO -#define SHOW_INFO -#endif - -#ifdef RELEASE_SHOW_ASSERT -#define SHOW_ASSERT -#endif - -#endif // _DEBUG - - - -#define lldebugst(type) lldebugs -#define llendflush llendl - - -#define llerror(msg, num) llerrs << "Error # " << num << ": " << msg << llendl; - -#define llwarning(msg, num) llwarns << "Warning # " << num << ": " << msg << llendl; - -#define liru_slashpos std::string(__FILE__).find_last_of("/\\") -#define liru_slashpos2 std::string(__FILE__).substr(0,liru_slashpos).find_last_of("/\\") -#define liru_assert_strip /*strip path down to lastlevel directory and filename for assert.*/\ - (liru_slashpos == std::string::npos ? std::string(__FILE__)/*just filename, print as is*/\ - : liru_slashpos2 == std::string::npos ? std::string(__FILE__)/*Apparently, we're in / or perhaps the top of the drive, print as is*/\ - : std::string(__FILE__).substr(1+liru_slashpos2))/*print foo/bar.cpp or perhaps foo\bar.cpp*/ - -#define llassert_always(func) do { if (LL_UNLIKELY(!(func))) llerrs << "\nASSERT(" #func ")\nfile:" << liru_assert_strip << " line:" << std::dec << __LINE__ << llendl; } while(0) - -#ifdef SHOW_ASSERT -#define llassert(func) llassert_always(func) -#define llverify(func) llassert_always(func) -#else -#define llassert(func) -#define llverify(func) do {if (func) {}} while(0) -#endif - -// This can be used for function parameters that are only used by llassert. -// The ellipsis is needed in case the parameter contains comma's (ie, as part of the type, -// or trailing comma). The first version can be used as first (or only) parameter of a function, -// or as parameter in the middle when adding a trailing comma, while the second version can be -// used as last parameter. -// -// Example usage: -// -// void foo(ASSERT_ONLY(int x)); -// void foo(x, ASSERT_ONLY(int y,) int z); -// void foo(x/*,*/ ASSERT_ONLY_COMMA(int y)); // The optional /*,*/ makes it just a bit better readable. -#ifdef SHOW_ASSERT -#define ASSERT_ONLY(...) __VA_ARGS__ -#define ASSERT_ONLY_COMMA(...) , __VA_ARGS__ -#else -#define ASSERT_ONLY(...) -#define ASSERT_ONLY_COMMA(...) -#endif - -// handy compile-time assert - enforce those template parameters! -#define cassert(expn) typedef char __C_ASSERT__[(expn)?1:-1] /* Flawfinder: ignore */ - //XXX: used in two places in llcommon/llskipmap.h #endif // LL_LLERRORLEGACY_H diff --git a/indra/llcommon/llerrorthread.cpp b/indra/llcommon/llerrorthread.cpp index e03faf0d18..c996f9da03 100644 --- a/indra/llcommon/llerrorthread.cpp +++ b/indra/llcommon/llerrorthread.cpp @@ -65,7 +65,7 @@ void get_child_status(const int waitpid_status, int &process_status, bool &exite exited = true; if (do_logging) { - llinfos << "get_child_status - Child exited cleanly with return of " << process_status << llendl; + LL_INFOS() << "get_child_status - Child exited cleanly with return of " << process_status << LL_ENDL; } return; } @@ -75,15 +75,15 @@ void get_child_status(const int waitpid_status, int &process_status, bool &exite exited = true; if (do_logging) { - llinfos << "get_child_status - Child died because of uncaught signal " << process_status << llendl; + LL_INFOS() << "get_child_status - Child died because of uncaught signal " << process_status << LL_ENDL; #ifdef WCOREDUMP if (WCOREDUMP(waitpid_status)) { - llinfos << "get_child_status - Child dumped core" << llendl; + LL_INFOS() << "get_child_status - Child dumped core" << LL_ENDL; } else { - llinfos << "get_child_status - Child didn't dump core" << llendl; + LL_INFOS() << "get_child_status - Child didn't dump core" << LL_ENDL; } #endif } @@ -93,7 +93,7 @@ void get_child_status(const int waitpid_status, int &process_status, bool &exite { // This is weird. I just dump the waitpid status into the status code, // not that there's any way of telling what it is... - llinfos << "get_child_status - Got SIGCHILD but child didn't exit" << llendl; + LL_INFOS() << "get_child_status - Got SIGCHILD but child didn't exit" << LL_ENDL; process_status = waitpid_status; } @@ -106,7 +106,7 @@ void LLErrorThread::run() // This thread sits and waits for the sole purpose // of waiting for the signal/exception handlers to flag the // application state as APP_STATUS_ERROR. - llinfos << "thread_error - Waiting for an error" << llendl; + LL_INFOS() << "thread_error - Waiting for an error" << LL_ENDL; S32 counter = 0; #if !LL_WINDOWS @@ -124,7 +124,7 @@ void LLErrorThread::run() last_sig_child_count = current_sig_child_count; if (LLApp::sLogInSignal) { - llinfos << "thread_error handling SIGCHLD #" << current_sig_child_count << llendl; + LL_INFOS() << "thread_error handling SIGCHLD #" << current_sig_child_count << LL_ENDL; } for (LLApp::child_map::iterator iter = LLApp::sChildMap.begin(); iter != LLApp::sChildMap.end();) { @@ -141,7 +141,7 @@ void LLErrorThread::run() { if (LLApp::sLogInSignal) { - llinfos << "Signal handler - Running child callback" << llendl; + LL_INFOS() << "Signal handler - Running child callback" << LL_ENDL; } child_info.mCallback(child_pid, exited, status); } @@ -172,7 +172,7 @@ void LLErrorThread::run() { if (LLApp::sLogInSignal) { - llinfos << "Signal handler - Running default child callback" << llendl; + LL_INFOS() << "Signal handler - Running default child callback" << LL_ENDL; } LLApp::sDefaultChildCallback(child_pid, true, status); } diff --git a/indra/llcommon/llevent.cpp b/indra/llcommon/llevent.cpp index f669d0e13f..7b3ba795af 100644 --- a/indra/llcommon/llevent.cpp +++ b/indra/llcommon/llevent.cpp @@ -226,7 +226,7 @@ bool LLSimpleDispatcher::fireEvent(LLPointer event, LLSD filter) for (itor=mListeners.begin(); itor!=mListeners.end(); ++itor) { LLListenerEntry& entry = *itor; - if (filter_string == "" || entry.filter.asString() == filter_string) + if (filter_string.empty() || entry.filter.asString() == filter_string) { (entry.listener)->handleEvent(event, (*itor).userdata); } diff --git a/indra/llcommon/lleventcoro.h b/indra/llcommon/lleventcoro.h index 88a5e6ec74..3aedb37b1b 100644 --- a/indra/llcommon/lleventcoro.h +++ b/indra/llcommon/lleventcoro.h @@ -29,8 +29,8 @@ #if ! defined(LL_LLEVENTCORO_H) #define LL_LLEVENTCORO_H -#include -#include +#include +#include #include #include #include @@ -67,7 +67,7 @@ class LLEventPumpOrPumpName LLEventPumpOrPumpName() {} operator LLEventPump& () const { return *mPump; } LLEventPump& getPump() const { return *mPump; } - operator bool() const { return mPump; } + operator bool() const { return !!mPump; } bool operator!() const { return ! mPump; } private: @@ -206,13 +206,13 @@ LLSD postAndWait(SELF& self, const LLSD& event, const LLEventPumpOrPumpName& req const LLEventPumpOrPumpName& replyPump, const LLSD& replyPumpNamePath=LLSD()) { // declare the future - boost::coroutines::future future(self); + boost::dcoroutines::future future(self); // make a callback that will assign a value to the future, and listen on // the specified LLEventPump with that callback std::string listenerName(LLEventDetail::listenerNameForCoro(self)); LLTempBoundListener connection( replyPump.getPump().listen(listenerName, - voidlistener(boost::coroutines::make_callback(future)))); + voidlistener(boost::dcoroutines::make_callback(future)))); // skip the "post" part if requestPump is default-constructed if (requestPump) { @@ -257,7 +257,7 @@ namespace LLEventDetail * This helper is specifically for the two-pump version of waitForEventOn(). * We use a single future object, but we want to listen on two pumps with it. * Since we must still adapt from (the callable constructed by) - * boost::coroutines::make_callback() (void return) to provide an event + * boost::dcoroutines::make_callback() (void return) to provide an event * listener (bool return), we've adapted LLVoidListener for the purpose. The * basic idea is that we construct a distinct instance of WaitForEventOnHelper * -- binding different instance data -- for each of the pumps. Then, when a @@ -331,16 +331,16 @@ LLEventWithID postAndWait2(SELF& self, const LLSD& event, const LLSD& replyPump1NamePath=LLSD()) { // declare the future - boost::coroutines::future future(self); + boost::dcoroutines::future future(self); // either callback will assign a value to this future; listen on // each specified LLEventPump with a callback std::string name(LLEventDetail::listenerNameForCoro(self)); LLTempBoundListener connection0( replyPump0.getPump().listen(name + "a", - LLEventDetail::wfeoh(boost::coroutines::make_callback(future), 0))); + LLEventDetail::wfeoh(boost::dcoroutines::make_callback(future), 0))); LLTempBoundListener connection1( replyPump1.getPump().listen(name + "b", - LLEventDetail::wfeoh(boost::coroutines::make_callback(future), 1))); + LLEventDetail::wfeoh(boost::dcoroutines::make_callback(future), 1))); // skip the "post" part if requestPump is default-constructed if (requestPump) { @@ -412,7 +412,7 @@ class LL_COMMON_API LLErrorEvent: public std::runtime_error std::runtime_error(what), mData(data) {} - virtual ~LLErrorEvent() throw() {} + virtual ~LLErrorEvent() noexcept {} LLSD getData() const { return mData; } diff --git a/indra/llcommon/lleventdispatcher.cpp b/indra/llcommon/lleventdispatcher.cpp index 5b6d4efbe9..b4ed63998e 100644 --- a/indra/llcommon/lleventdispatcher.cpp +++ b/indra/llcommon/lleventdispatcher.cpp @@ -381,10 +381,9 @@ std::string LLSDArgsMapper::formatlist(const LLSD& list) { std::ostringstream out; const char* delim = ""; - for (LLSD::array_const_iterator li(list.beginArray()), lend(list.endArray()); - li != lend; ++li) + for (auto const& entry : list.array()) { - out << delim << li->asString(); + out << delim << entry.asString(); delim = ", "; } return out.str(); @@ -449,7 +448,7 @@ struct LLEventDispatcher::ParamsDispatchEntry: public LLEventDispatcher::Dispatc virtual void call(const std::string& desc, const LLSD& event) const { LLSDArgsSource src(desc, event); - mInvoker(boost::bind(&LLSDArgsSource::next, boost::ref(src))); + mInvoker(std::bind(&LLSDArgsSource::next, std::ref(src))); } }; @@ -494,10 +493,9 @@ struct LLEventDispatcher::MapParamsDispatchEntry: public LLEventDispatcher::Para { // Build the set of all param keys, then delete the ones that are // optional. What's left are the ones that are required. - for (LLSD::array_const_iterator pi(params.beginArray()), pend(params.endArray()); - pi != pend; ++pi) + for (auto const& entry : params.array()) { - mRequired[pi->asString()] = LLSD(); + mRequired[entry.asString()] = LLSD(); } if (defaults.isArray() || defaults.isUndefined()) diff --git a/indra/llcommon/lleventdispatcher.h b/indra/llcommon/lleventdispatcher.h index 7acc61de4e..8f54bc2e52 100644 --- a/indra/llcommon/lleventdispatcher.h +++ b/indra/llcommon/lleventdispatcher.h @@ -57,16 +57,12 @@ static const int& nil(nil_); #endif #include -#include #include -#include #include #include #include #include #include -#include -#include #include #include #include @@ -300,7 +296,7 @@ class LL_COMMON_API LLEventDispatcher // subclass object. However, I definitely want DispatchMap to destroy // DispatchEntry if no references are outstanding at the time an entry is // removed. This looks like a job for boost::shared_ptr. - typedef std::map > DispatchMap; + typedef std::map > DispatchMap; public: /// We want the flexibility to redefine what data we store per name, @@ -427,7 +423,7 @@ struct LLEventDispatcher::invoker // Instead of grabbing the first item from argsrc and making an // LLSDParam of it, call getter() and pass that as the instance param. invoker::apply - ( func, argsrc, boost::fusion::push_back(boost::fusion::nil(), boost::ref(getter()))); + ( func, argsrc, boost::fusion::push_back(boost::fusion::nil(), std::ref(getter()))); } }; diff --git a/indra/llcommon/lleventfilter.cpp b/indra/llcommon/lleventfilter.cpp index d36a107254..bf0f215844 100644 --- a/indra/llcommon/lleventfilter.cpp +++ b/indra/llcommon/lleventfilter.cpp @@ -33,15 +33,14 @@ // STL headers // std headers // external library headers -#include // other Linden headers #include "llerror.h" // LL_ERRS #include "llsdutil.h" // llsd_matches() LLEventFilter::LLEventFilter(LLEventPump& source, const std::string& name, bool tweak): - LLEventStream(name, tweak) + LLEventStream(name, tweak), + mSource(source.listen(getName(), boost::bind(&LLEventFilter::post, this, _1))) { - source.listen(getName(), boost::bind(&LLEventFilter::post, this, _1)); } LLEventMatching::LLEventMatching(const LLSD& pattern): diff --git a/indra/llcommon/lleventfilter.h b/indra/llcommon/lleventfilter.h index e822a664f5..751aa463c8 100644 --- a/indra/llcommon/lleventfilter.h +++ b/indra/llcommon/lleventfilter.h @@ -32,7 +32,6 @@ #include "llevents.h" #include "stdtypes.h" #include "lltimer.h" -#include /** * Generic base class @@ -49,6 +48,9 @@ class LL_COMMON_API LLEventFilter: public LLEventStream /// Post an event to all listeners virtual bool post(const LLSD& event) = 0; + +private: + LLTempBoundListener mSource; }; /** @@ -86,7 +88,7 @@ class LL_COMMON_API LLEventTimeoutBase: public LLEventFilter LLEventTimeoutBase(LLEventPump& source); /// Callable, can be constructed with boost::bind() - typedef boost::function Action; + typedef std::function Action; /** * Start countdown timer for the specified number of @a seconds. Forward diff --git a/indra/llcommon/llevents.h b/indra/llcommon/llevents.h index 4f8fb1d3fc..7770ff4c55 100644 --- a/indra/llcommon/llevents.h +++ b/indra/llcommon/llevents.h @@ -56,12 +56,15 @@ #include #include // reference_wrapper #include +#ifndef BOOST_FUNCTION_HPP_INCLUDED #include +#define BOOST_FUNCTION_HPP_INCLUDED +#endif #include #include "llsd.h" #include "llsingleton.h" #include "lldependencies.h" -#include "ll_template_cast.h" +#include "llstl.h" /*==========================================================================*| // override this to allow binding free functions with more parameters @@ -179,10 +182,10 @@ class LL_COMMON_API LLListenerOrPumpName bool operator! () const { return ! mListener; } /// explicit accessor - const LLEventListener& getListener() const { return *mListener; } + const ::LLEventListener& getListener() const { return *mListener; } /// implicit conversion to LLEventListener - operator LLEventListener() const { return *mListener; } + operator ::LLEventListener() const { return *mListener; } /// allow calling directly bool operator()(const LLSD& event) const; @@ -274,7 +277,7 @@ namespace LLEventDetail /// Any callable capable of connecting an LLEventListener to an /// LLStandardSignal to produce an LLBoundListener can be mapped to this /// signature. - typedef boost::function ConnectFunc; + typedef boost::function ConnectFunc; /// overload of visit_and_connect() when we have a string identifier available template @@ -544,7 +547,7 @@ class LL_COMMON_API LLEventPump: public LLEventTrackable virtual void reset(); private: - virtual LLBoundListener listen_impl(const std::string& name, const LLEventListener&, + virtual LLBoundListener listen_impl(const std::string& name, const ::LLEventListener&, const NameList& after, const NameList& before); std::string mName; @@ -842,7 +845,7 @@ namespace LLEventDetail * Visitor binds a reference to LLEventListener so we can track() any * shared_ptrs we find in the argument list. */ - Visitor(LLEventListener& listener): + Visitor(::LLEventListener& listener): mListener(listener) { } @@ -985,7 +988,7 @@ namespace LLEventDetail |*==========================================================================*/ /// Bind a reference to the LLEventListener to call its track() method. - LLEventListener& mListener; + ::LLEventListener& mListener; }; /** @@ -1002,7 +1005,7 @@ namespace LLEventDetail const ConnectFunc& connect_func) { // Capture the listener - LLEventListener listener(raw_listener); + ::LLEventListener listener(raw_listener); // Define our Visitor, binding the listener so we can call // listener.track() if we discover any shared_ptr. LLEventDetail::Visitor visitor(listener); diff --git a/indra/llcommon/lleventtimer.cpp b/indra/llcommon/lleventtimer.cpp index a29a837a8b..c491e37cb4 100644 --- a/indra/llcommon/lleventtimer.cpp +++ b/indra/llcommon/lleventtimer.cpp @@ -65,7 +65,7 @@ LLEventTimer::~LLEventTimer() void LLEventTimer::updateClass() { std::list completed_timers; - for (instance_iter iter = beginInstances(); iter != endInstances(); ) + for (instance_iter iter = beginInstances(), end_iter = endInstances(); iter != end_iter;) { LLEventTimer& timer = *iter++; F32 et = timer.mEventTimer.getElapsedTimeF32(); diff --git a/indra/llcommon/llfasttimer_class.cpp b/indra/llcommon/llfasttimer_class.cpp index 07ea31a5aa..5cb7b2c253 100644 --- a/indra/llcommon/llfasttimer_class.cpp +++ b/indra/llcommon/llfasttimer_class.cpp @@ -157,6 +157,7 @@ #if LL_WINDOWS #include "lltimer.h" +#include #elif LL_LINUX || LL_SOLARIS #include #include @@ -184,7 +185,7 @@ LLMutex* LLFastTimer::sLogLock = NULL; std::queue LLFastTimer::sLogQueue; const int LLFastTimer::NamedTimer::HISTORY_NUM = 300; -#if LL_WINDOWS +#if defined(LL_WINDOWS) #define USE_RDTSC 1 #endif @@ -345,7 +346,7 @@ LLFastTimer::DeclareTimer::DeclareTimer(const std::string& name) void LLFastTimer::updateCachedPointers() { // Update DeclareTimer::mFrameState pointers. - for (DeclareTimer::instance_iter it = DeclareTimer::beginInstances(); it != DeclareTimer::endInstances(); ++it) + for (DeclareTimer::instance_iter it = DeclareTimer::beginInstances(), it_end = DeclareTimer::endInstances(); it != it_end; ++it) { // update cached pointer it->mFrameState = &it->mTimer.getFrameState(); @@ -537,7 +538,7 @@ void LLFastTimer::NamedTimer::buildHierarchy() // set up initial tree { - for (instance_iter it = beginInstances(); it != endInstances(); ++it) + for (instance_iter it = beginInstances(), it_end = endInstances(); it != it_end; ++it) { NamedTimer& timer = *it; if (&timer == NamedTimerFactory::instance().getRootTimer()) continue; @@ -569,8 +570,8 @@ void LLFastTimer::NamedTimer::buildHierarchy() { // since ancestors have already been visited, reparenting won't affect tree traversal //step up tree, bringing our descendants with us - //llinfos << "Moving " << timerp->getName() << " from child of " << timerp->getParent()->getName() << - // " to child of " << timerp->getParent()->getParent()->getName() << llendl; + //LL_INFOS() << "Moving " << timerp->getName() << " from child of " << timerp->getParent()->getName() << + // " to child of " << timerp->getParent()->getParent()->getName() << LL_ENDL; timerp->setParent(timerp->getParent()->getParent()); timerp->getFrameState().mMoveUpTree = false; @@ -662,12 +663,12 @@ void LLFastTimer::NamedTimer::resetFrame() static S32 call_count = 0; if (call_count % 100 == 0) { - llinfos << "countsPerSecond (32 bit): " << countsPerSecond() << llendl; - llinfos << "get_clock_count (64 bit): " << get_clock_count() << llendl; - llinfos << "LLProcessorInfo().getCPUFrequency() " << LLProcessorInfo().getCPUFrequency() << llendl; - llinfos << "getCPUClockCount32() " << getCPUClockCount32() << llendl; - llinfos << "getCPUClockCount64() " << getCPUClockCount64() << llendl; - llinfos << "elapsed sec " << ((F64)getCPUClockCount64())/((F64)LLProcessorInfo().getCPUFrequency()*1000000.0) << llendl; + LL_INFOS() << "countsPerSecond (32 bit): " << countsPerSecond() << LL_ENDL; + LL_INFOS() << "get_clock_count (64 bit): " << get_clock_count() << LL_ENDL; + LL_INFOS() << "LLProcessorInfo().getCPUFrequency() " << LLProcessorInfo().getCPUFrequency() << LL_ENDL; + LL_INFOS() << "getCPUClockCount32() " << getCPUClockCount32() << LL_ENDL; + LL_INFOS() << "getCPUClockCount64() " << getCPUClockCount64() << LL_ENDL; + LL_INFOS() << "elapsed sec " << ((F64)getCPUClockCount64())/((F64)LLProcessorInfo().getCPUFrequency()*1000000.0) << LL_ENDL; } call_count++; @@ -677,7 +678,7 @@ void LLFastTimer::NamedTimer::resetFrame() LLSD sd; { - for (instance_iter it = beginInstances(); it != endInstances(); ++it) + for (instance_iter it = beginInstances(), it_end = endInstances(); it != it_end; ++it) { NamedTimer& timer = *it; FrameState& info = timer.getFrameState(); @@ -721,7 +722,7 @@ void LLFastTimer::NamedTimer::resetFrame() // reset for next frame { - for (instance_iter it = beginInstances(); it != endInstances(); ++it) + for (instance_iter it = beginInstances(), it_end = endInstances(); it != it_end; ++it) { NamedTimer& timer = *it; @@ -765,7 +766,7 @@ void LLFastTimer::NamedTimer::reset() // reset all history { - for (instance_iter it = beginInstances(); it != endInstances(); ++it) + for (instance_iter it = beginInstances(), it_end = endInstances(); it != it_end; ++it) { NamedTimer& timer = *it; if (&timer != NamedTimerFactory::instance().getRootTimer()) @@ -851,7 +852,7 @@ void LLFastTimer::nextFrame() U64 frame_time = getCPUClockCount64(); if ((frame_time - sLastFrameTime) >> 8 > 0xffffffff) { - llinfos << "Slow frame, fast timers inaccurate" << llendl; + LL_INFOS() << "Slow frame, fast timers inaccurate" << LL_ENDL; } if (!sPauseHistory) @@ -896,7 +897,7 @@ void LLFastTimer::dumpCurTimes() << std::setprecision(3) << total_time_ms << " ms, " << timerp->getHistoricalCalls(0) << " calls"; - llinfos << out_str.str() << llendl; + LL_INFOS() << out_str.str() << LL_ENDL; } } @@ -952,34 +953,15 @@ LLFastTimer::LLFastTimer(LLFastTimer::FrameState* state) #if USE_RDTSC U32 LLFastTimer::getCPUClockCount32() { - U32 ret_val; - __asm - { - _emit 0x0f - _emit 0x31 - shr eax,8 - shl edx,24 - or eax, edx - mov dword ptr [ret_val], eax - } - return ret_val; + return (U32)(__rdtsc()>>8); } // return full timer value, *not* shifted by 8 bits U64 LLFastTimer::getCPUClockCount64() { - U64 ret_val; - __asm - { - _emit 0x0f - _emit 0x31 - mov eax,eax - mov edx,edx - mov dword ptr [ret_val+4], edx - mov dword ptr [ret_val], eax - } - return ret_val; + return (U64)__rdtsc(); } + #else //LL_COMMON_API U64 get_clock_count(); // in lltimer.cpp // These use QueryPerformanceCounter, which is arguably fine and also works on AMD architectures. diff --git a/indra/llcommon/llfasttimer_class.h b/indra/llcommon/llfasttimer_class.h index aa1f8ffacf..8967e64ac6 100644 --- a/indra/llcommon/llfasttimer_class.h +++ b/indra/llcommon/llfasttimer_class.h @@ -38,6 +38,8 @@ class LLMutex; #include #include "llsd.h" +#define LL_RECORD_BLOCK_TIME(timer_stat) LLFastTimer LL_GLUE_TOKENS(block_time_recorder, __LINE__)(timer_stat); + LL_COMMON_API void assert_main_thread(); class LL_COMMON_API LLFastTimer @@ -273,4 +275,9 @@ class LL_COMMON_API LLFastTimer }; +namespace LLTrace +{ + typedef LLFastTimer::DeclareTimer BlockTimerStatHandle; +} + #endif // LL_LLFASTTIMER_H diff --git a/indra/llcommon/llfile.cpp b/indra/llcommon/llfile.cpp index e0e9d3a27e..0b7677fade 100644 --- a/indra/llcommon/llfile.cpp +++ b/indra/llcommon/llfile.cpp @@ -28,7 +28,7 @@ */ #if LL_WINDOWS -#include +#include "llwin32headerslean.h" #include // Windows errno #else #include @@ -49,10 +49,12 @@ static std::string empty; #if LL_WINDOWS // On Windows, use strerror_s(). -std::string strerr(int errn) +//static +std::string LLFile::strerr(int errn) { char buffer[256]; strerror_s(buffer, errn); // infers sizeof(buffer) -- love it! + buffer[255] = 0; return buffer; } @@ -98,7 +100,8 @@ std::string message_from(int orig_errno, const char* buffer, size_t bufflen, << " (error " << stre_errno << ')'); } -std::string strerr(int errn) +//static +std::string LLFile::strerr(int errn) { char buffer[256]; // Select message_from() function matching the strerror_r() we have on hand. @@ -108,7 +111,8 @@ std::string strerr(int errn) #endif // ! LL_WINDOWS // On either system, shorthand call just infers global 'errno'. -std::string strerr() +//static +std::string LLFile::strerr() { return strerr(errno); } @@ -125,7 +129,7 @@ int warnif(const std::string& desc, const std::string& filename, int rc, int acc if (errn != accept) { LL_WARNS("LLFile") << "Couldn't " << desc << " '" << filename - << "' (errno " << errn << "): " << strerr(errn) << LL_ENDL; + << "' (errno " << errn << "): " << LLFile::strerr(errn) << LL_ENDL; } #if 0 && LL_WINDOWS // turn on to debug file-locking problems // If the problem is "Permission denied," maybe it's because another @@ -171,7 +175,7 @@ int warnif(const std::string& desc, const std::string& filename, int rc, int acc } // static -int LLFile::mkdir(const std::string& dirname, int perms) +int LLFile::mkdir_nowarn(const std::string& dirname, int perms) { #if LL_WINDOWS // permissions are ignored on Windows @@ -181,13 +185,19 @@ int LLFile::mkdir(const std::string& dirname, int perms) #else int rc = ::mkdir(dirname.c_str(), (mode_t)perms); #endif + return rc; +} + +int LLFile::mkdir(const std::string& dirname, int perms) +{ + int rc = LLFile::mkdir_nowarn(dirname, perms); // We often use mkdir() to ensure the existence of a directory that might // already exist. Don't spam the log if it does. return warnif("mkdir", dirname, rc, EEXIST); } // static -int LLFile::rmdir(const std::string& dirname) +int LLFile::rmdir_nowarn(const std::string& dirname) { #if LL_WINDOWS // permissions are ignored on Windows @@ -197,6 +207,12 @@ int LLFile::rmdir(const std::string& dirname) #else int rc = ::rmdir(dirname.c_str()); #endif + return rc; +} + +int LLFile::rmdir(const std::string& dirname) +{ + int rc = LLFile::rmdir_nowarn(dirname); return warnif("rmdir", dirname, rc); } @@ -238,8 +254,7 @@ int LLFile::close(LLFILE * file) return ret_value; } - -int LLFile::remove(const std::string& filename) +int LLFile::remove_nowarn(const std::string& filename) { #if LL_WINDOWS std::string utf8filename = filename; @@ -248,10 +263,16 @@ int LLFile::remove(const std::string& filename) #else int rc = ::remove(filename.c_str()); #endif - return warnif("remove", filename, rc); + return rc; +} + +int LLFile::remove(const std::string& filename, int supress_error) +{ + int rc = LLFile::remove_nowarn(filename); + return warnif("remove", filename, rc, supress_error); } -int LLFile::rename(const std::string& filename, const std::string& newname) +int LLFile::rename_nowarn(const std::string& filename, const std::string& newname) { #if LL_WINDOWS std::string utf8filename = filename; @@ -261,8 +282,19 @@ int LLFile::rename(const std::string& filename, const std::string& newname) int rc = _wrename(utf16filename.c_str(),utf16newname.c_str()); #else int rc = ::rename(filename.c_str(),newname.c_str()); + if (rc == -1 && errno == EXDEV) + { + rc = std::system(("mv '" + filename + "' '" + newname + '\'').data()); + errno = 0; + } #endif - return warnif(STRINGIZE("rename to '" << newname << "' from"), filename, rc); + return rc; +} + +int LLFile::rename(const std::string& filename, const std::string& newname, int supress_error) +{ + int rc = LLFile::rename_nowarn(filename, newname); + return warnif(STRINGIZE("rename to '" << newname << "' from"), filename, rc, supress_error); } int LLFile::stat(const std::string& filename, llstat* filestatus) @@ -390,679 +422,76 @@ LLFILE * LLFile::_Fiopen(const std::string& filename, #endif /* LL_WINDOWS */ -/************** llstdio file buffer ********************************/ - - -//llstdio_filebuf* llstdio_filebuf::open(const char *_Filename, -// ios_base::openmode _Mode) -//{ -//#if LL_WINDOWS -// _Filet *_File; -// if (is_open() || (_File = LLFILE::_Fiopen(_Filename, _Mode)) == 0) -// return (0); // open failed -// -// _Init(_File, _Openfl); -// _Initcvt(&_USE(_Mysb::getloc(), _Cvt)); -// return (this); // open succeeded -//#else -// std::filebuf* _file = std::filebuf::open(_Filename, _Mode); -// if (NULL == _file) return NULL; -// return this; -//#endif -//} - - -// *TODO: Seek the underlying c stream for better cross-platform compatibility? -#if !LL_WINDOWS -llstdio_filebuf::int_type llstdio_filebuf::overflow(llstdio_filebuf::int_type __c) -{ - int_type __ret = traits_type::eof(); - const bool __testeof = traits_type::eq_int_type(__c, __ret); - const bool __testout = _M_mode & ios_base::out; - if (__testout && !_M_reading) - { - if (this->pbase() < this->pptr()) - { - // If appropriate, append the overflow char. - if (!__testeof) - { - *this->pptr() = traits_type::to_char_type(__c); - this->pbump(1); - } - - // Convert pending sequence to external representation, - // and output. - if (_convert_to_external(this->pbase(), - this->pptr() - this->pbase())) - { - _M_set_buffer(0); - __ret = traits_type::not_eof(__c); - } - } - else if (_M_buf_size > 1) - { - // Overflow in 'uncommitted' mode: set _M_writing, set - // the buffer to the initial 'write' mode, and put __c - // into the buffer. - _M_set_buffer(0); - _M_writing = true; - if (!__testeof) - { - *this->pptr() = traits_type::to_char_type(__c); - this->pbump(1); - } - __ret = traits_type::not_eof(__c); - } - else - { - // Unbuffered. - char_type __conv = traits_type::to_char_type(__c); - if (__testeof || _convert_to_external(&__conv, 1)) - { - _M_writing = true; - __ret = traits_type::not_eof(__c); - } - } - } - return __ret; -} - -bool llstdio_filebuf::_convert_to_external(char_type* __ibuf, - std::streamsize __ilen) -{ - // Sizes of external and pending output. - streamsize __elen; - streamsize __plen; - if (__check_facet(_M_codecvt).always_noconv()) - { - //__elen = _M_file.xsputn(reinterpret_cast(__ibuf), __ilen); - __elen = fwrite(reinterpret_cast(__ibuf), 1, - __ilen, _M_file.file()); - __plen = __ilen; - } - else - { - // Worst-case number of external bytes needed. - // XXX Not done encoding() == -1. - streamsize __blen = __ilen * _M_codecvt->max_length(); - char* __buf = static_cast(__builtin_alloca(__blen)); - - char* __bend; - const char_type* __iend; - codecvt_base::result __r; - __r = _M_codecvt->out(_M_state_cur, __ibuf, __ibuf + __ilen, - __iend, __buf, __buf + __blen, __bend); - - if (__r == codecvt_base::ok || __r == codecvt_base::partial) - __blen = __bend - __buf; - else if (__r == codecvt_base::noconv) - { - // Same as the always_noconv case above. - __buf = reinterpret_cast(__ibuf); - __blen = __ilen; - } - else - __throw_ios_failure(__N("llstdio_filebuf::_convert_to_external " - "conversion error")); - - //__elen = _M_file.xsputn(__buf, __blen); - __elen = fwrite(__buf, 1, __blen, _M_file.file()); - __plen = __blen; - - // Try once more for partial conversions. - if (__r == codecvt_base::partial && __elen == __plen) - { - const char_type* __iresume = __iend; - streamsize __rlen = this->pptr() - __iend; - __r = _M_codecvt->out(_M_state_cur, __iresume, - __iresume + __rlen, __iend, __buf, - __buf + __blen, __bend); - if (__r != codecvt_base::error) - { - __rlen = __bend - __buf; - //__elen = _M_file.xsputn(__buf, __rlen); - __elen = fwrite(__buf, 1, __rlen, _M_file.file()); - __plen = __rlen; - } - else - { - __throw_ios_failure(__N("llstdio_filebuf::_convert_to_external " - "conversion error")); - } - } - } - return __elen == __plen; -} - -llstdio_filebuf::int_type llstdio_filebuf::underflow() -{ - int_type __ret = traits_type::eof(); - const bool __testin = _M_mode & ios_base::in; - if (__testin) - { - if (_M_writing) - { - if (overflow() == traits_type::eof()) - return __ret; - //_M_set_buffer(-1); - //_M_writing = false; - } - // Check for pback madness, and if so switch back to the - // normal buffers and jet outta here before expensive - // fileops happen... - _M_destroy_pback(); - - if (this->gptr() < this->egptr()) - return traits_type::to_int_type(*this->gptr()); - - // Get and convert input sequence. - const size_t __buflen = _M_buf_size > 1 ? _M_buf_size - 1 : 1; - - // Will be set to true if ::fread() returns 0 indicating EOF. - bool __got_eof = false; - // Number of internal characters produced. - streamsize __ilen = 0; - codecvt_base::result __r = codecvt_base::ok; - if (__check_facet(_M_codecvt).always_noconv()) - { - //__ilen = _M_file.xsgetn(reinterpret_cast(this->eback()), - // __buflen); - __ilen = fread(reinterpret_cast(this->eback()), 1, - __buflen, _M_file.file()); - if (__ilen == 0) - __got_eof = true; - } - else - { - // Worst-case number of external bytes. - // XXX Not done encoding() == -1. - const int __enc = _M_codecvt->encoding(); - streamsize __blen; // Minimum buffer size. - streamsize __rlen; // Number of chars to read. - if (__enc > 0) - __blen = __rlen = __buflen * __enc; - else - { - __blen = __buflen + _M_codecvt->max_length() - 1; - __rlen = __buflen; - } - const streamsize __remainder = _M_ext_end - _M_ext_next; - __rlen = __rlen > __remainder ? __rlen - __remainder : 0; - - // An imbue in 'read' mode implies first converting the external - // chars already present. - if (_M_reading && this->egptr() == this->eback() && __remainder) - __rlen = 0; - - // Allocate buffer if necessary and move unconverted - // bytes to front. - if (_M_ext_buf_size < __blen) - { - char* __buf = new char[__blen]; - if (__remainder) - __builtin_memcpy(__buf, _M_ext_next, __remainder); - - delete [] _M_ext_buf; - _M_ext_buf = __buf; - _M_ext_buf_size = __blen; - } - else if (__remainder) - __builtin_memmove(_M_ext_buf, _M_ext_next, __remainder); - - _M_ext_next = _M_ext_buf; - _M_ext_end = _M_ext_buf + __remainder; - _M_state_last = _M_state_cur; - - do - { - if (__rlen > 0) - { - // Sanity check! - // This may fail if the return value of - // codecvt::max_length() is bogus. - if (_M_ext_end - _M_ext_buf + __rlen > _M_ext_buf_size) - { - __throw_ios_failure(__N("llstdio_filebuf::underflow " - "codecvt::max_length() " - "is not valid")); - } - //streamsize __elen = _M_file.xsgetn(_M_ext_end, __rlen); - streamsize __elen = fread(_M_ext_end, 1, - __rlen, _M_file.file()); - if (__elen == 0) - __got_eof = true; - else if (__elen == -1) - break; - //_M_ext_end += __elen; - } - - char_type* __iend = this->eback(); - if (_M_ext_next < _M_ext_end) - { - __r = _M_codecvt->in(_M_state_cur, _M_ext_next, - _M_ext_end, _M_ext_next, - this->eback(), - this->eback() + __buflen, __iend); - } - if (__r == codecvt_base::noconv) - { - size_t __avail = _M_ext_end - _M_ext_buf; - __ilen = std::min(__avail, __buflen); - traits_type::copy(this->eback(), - reinterpret_cast - (_M_ext_buf), __ilen); - _M_ext_next = _M_ext_buf + __ilen; - } - else - __ilen = __iend - this->eback(); - - // _M_codecvt->in may return error while __ilen > 0: this is - // ok, and actually occurs in case of mixed encodings (e.g., - // XML files). - if (__r == codecvt_base::error) - break; - - __rlen = 1; - } while (__ilen == 0 && !__got_eof); - } - - if (__ilen > 0) - { - _M_set_buffer(__ilen); - _M_reading = true; - __ret = traits_type::to_int_type(*this->gptr()); - } - else if (__got_eof) - { - // If the actual end of file is reached, set 'uncommitted' - // mode, thus allowing an immediate write without an - // intervening seek. - _M_set_buffer(-1); - _M_reading = false; - // However, reaching it while looping on partial means that - // the file has got an incomplete character. - if (__r == codecvt_base::partial) - __throw_ios_failure(__N("llstdio_filebuf::underflow " - "incomplete character in file")); - } - else if (__r == codecvt_base::error) - __throw_ios_failure(__N("llstdio_filebuf::underflow " - "invalid byte sequence in file")); - else - __throw_ios_failure(__N("llstdio_filebuf::underflow " - "error reading the file")); - } - return __ret; -} - -std::streamsize llstdio_filebuf::xsgetn(char_type* __s, std::streamsize __n) -{ - // Clear out pback buffer before going on to the real deal... - streamsize __ret = 0; - if (_M_pback_init) - { - if (__n > 0 && this->gptr() == this->eback()) - { - *__s++ = *this->gptr(); - this->gbump(1); - __ret = 1; - --__n; - } - _M_destroy_pback(); - } - - // Optimization in the always_noconv() case, to be generalized in the - // future: when __n > __buflen we read directly instead of using the - // buffer repeatedly. - const bool __testin = _M_mode & ios_base::in; - const streamsize __buflen = _M_buf_size > 1 ? _M_buf_size - 1 : 1; - - if (__n > __buflen && __check_facet(_M_codecvt).always_noconv() - && __testin && !_M_writing) - { - // First, copy the chars already present in the buffer. - const streamsize __avail = this->egptr() - this->gptr(); - if (__avail != 0) - { - if (__avail == 1) - *__s = *this->gptr(); - else - traits_type::copy(__s, this->gptr(), __avail); - __s += __avail; - this->gbump(__avail); - __ret += __avail; - __n -= __avail; - } - - // Need to loop in case of short reads (relatively common - // with pipes). - streamsize __len; - for (;;) - { - //__len = _M_file.xsgetn(reinterpret_cast(__s), __n); - __len = fread(reinterpret_cast(__s), 1, - __n, _M_file.file()); - if (__len == -1) - __throw_ios_failure(__N("llstdio_filebuf::xsgetn " - "error reading the file")); - if (__len == 0) - break; - - __n -= __len; - __ret += __len; - if (__n == 0) - break; - - __s += __len; - } - - if (__n == 0) - { - _M_set_buffer(0); - _M_reading = true; - } - else if (__len == 0) - { - // If end of file is reached, set 'uncommitted' - // mode, thus allowing an immediate write without - // an intervening seek. - _M_set_buffer(-1); - _M_reading = false; - } - } - else - __ret += __streambuf_type::xsgetn(__s, __n); - - return __ret; -} - -std::streamsize llstdio_filebuf::xsputn(char_type const* __s, std::streamsize __n) -{ - // Optimization in the always_noconv() case, to be generalized in the - // future: when __n is sufficiently large we write directly instead of - // using the buffer. - streamsize __ret = 0; - const bool __testout = _M_mode & ios_base::out; - if (__check_facet(_M_codecvt).always_noconv() - && __testout && !_M_reading) - { - // Measurement would reveal the best choice. - const streamsize __chunk = 1ul << 10; - streamsize __bufavail = this->epptr() - this->pptr(); - - // Don't mistake 'uncommitted' mode buffered with unbuffered. - if (!_M_writing && _M_buf_size > 1) - __bufavail = _M_buf_size - 1; - - const streamsize __limit = std::min(__chunk, __bufavail); - if (__n >= __limit) - { - const streamsize __buffill = this->pptr() - this->pbase(); - const char* __buf = reinterpret_cast(this->pbase()); - //__ret = _M_file.xsputn_2(__buf, __buffill, - // reinterpret_cast(__s), __n); - if (__buffill) - { - __ret = fwrite(__buf, 1, __buffill, _M_file.file()); - } - if (__ret == __buffill) - { - __ret += fwrite(reinterpret_cast(__s), 1, - __n, _M_file.file()); - } - if (__ret == __buffill + __n) - { - _M_set_buffer(0); - _M_writing = true; - } - if (__ret > __buffill) - __ret -= __buffill; - else - __ret = 0; - } - else - __ret = __streambuf_type::xsputn(__s, __n); - } - else - __ret = __streambuf_type::xsputn(__s, __n); - return __ret; -} - -int llstdio_filebuf::sync() -{ - return (_M_file.sync() == 0 ? 0 : -1); -} -#endif +#if LL_WINDOWS /************** input file stream ********************************/ - -llifstream::llifstream() : _M_filebuf(), -#if LL_WINDOWS - std::istream(&_M_filebuf) {} -#else - std::istream() +llifstream::llifstream() : std::ifstream() { - this->init(&_M_filebuf); } -#endif // explicit -llifstream::llifstream(const std::string& _Filename, - ios_base::openmode _Mode) : _M_filebuf(), -#if LL_WINDOWS - std::istream(&_M_filebuf) -{ - if (_M_filebuf.open(_Filename.c_str(), _Mode | ios_base::in) == 0) - { - _Myios::setstate(ios_base::failbit); - } -} -#else - std::istream() +llifstream::llifstream(const std::string& _Filename, ios_base::openmode _Mode) : + std::ifstream(utf8str_to_utf16str(_Filename), + _Mode | ios_base::in) { - this->init(&_M_filebuf); - this->open(_Filename.c_str(), _Mode | ios_base::in); } -#endif // explicit -llifstream::llifstream(const char* _Filename, - ios_base::openmode _Mode) : _M_filebuf(), -#if LL_WINDOWS - std::istream(&_M_filebuf) -{ - if (_M_filebuf.open(_Filename, _Mode | ios_base::in) == 0) - { - _Myios::setstate(ios_base::failbit); - } -} -#else - std::istream() -{ - this->init(&_M_filebuf); - this->open(_Filename, _Mode | ios_base::in); -} -#endif +llifstream::llifstream(const char* _Filename, ios_base::openmode _Mode) : + std::ifstream(utf8str_to_utf16str(_Filename).c_str(), + _Mode | ios_base::in) - -// explicit -llifstream::llifstream(_Filet *_File, - ios_base::openmode _Mode, size_t _Size) : - _M_filebuf(_File, _Mode, _Size), -#if LL_WINDOWS - std::istream(&_M_filebuf) {} -#else - std::istream() { - this->init(&_M_filebuf); } -#endif -#if !LL_WINDOWS -// explicit -llifstream::llifstream(int __fd, - ios_base::openmode _Mode, size_t _Size) : - _M_filebuf(__fd, _Mode, _Size), - std::istream() +void llifstream::open(const std::string& _Filename, ios_base::openmode _Mode) { - this->init(&_M_filebuf); -} -#endif - -bool llifstream::is_open() const -{ // test if C stream has been opened - return _M_filebuf.is_open(); + std::ifstream::open(utf8str_to_utf16str(_Filename), + _Mode | ios_base::in); } void llifstream::open(const char* _Filename, ios_base::openmode _Mode) -{ // open a C stream with specified mode - if (_M_filebuf.open(_Filename, _Mode | ios_base::in) == 0) -#if LL_WINDOWS - { - _Myios::setstate(ios_base::failbit); - } - else - { - _Myios::clear(); - } -#else - { - this->setstate(ios_base::failbit); - } - else - { - this->clear(); - } -#endif -} - -void llifstream::close() -{ // close the C stream - if (_M_filebuf.close() == 0) - { -#if LL_WINDOWS - _Myios::setstate(ios_base::failbit); -#else - this->setstate(ios_base::failbit); -#endif - } +{ + std::ifstream::open(utf8str_to_utf16str(_Filename).c_str(), + _Mode | ios_base::in); } /************** output file stream ********************************/ -llofstream::llofstream() : _M_filebuf(), -#if LL_WINDOWS - std::ostream(&_M_filebuf) {} -#else - std::ostream() +llofstream::llofstream() : std::ofstream() { - this->init(&_M_filebuf); } -#endif // explicit -llofstream::llofstream(const std::string& _Filename, - ios_base::openmode _Mode) : _M_filebuf(), -#if LL_WINDOWS - std::ostream(&_M_filebuf) +llofstream::llofstream(const std::string& _Filename, ios_base::openmode _Mode) : + std::ofstream(utf8str_to_utf16str(_Filename), + _Mode | ios_base::out) { - if (_M_filebuf.open(_Filename.c_str(), _Mode | ios_base::out) == 0) - { - _Myios::setstate(ios_base::failbit); - } } -#else - std::ostream() -{ - this->init(&_M_filebuf); - this->open(_Filename.c_str(), _Mode | ios_base::out); -} -#endif // explicit -llofstream::llofstream(const char* _Filename, - ios_base::openmode _Mode) : _M_filebuf(), -#if LL_WINDOWS - std::ostream(&_M_filebuf) +llofstream::llofstream(const char* _Filename, ios_base::openmode _Mode) : + std::ofstream(utf8str_to_utf16str(_Filename).c_str(), + _Mode | ios_base::out) { - if (_M_filebuf.open(_Filename, _Mode | ios_base::out) == 0) - { - _Myios::setstate(ios_base::failbit); - } } -#else - std::ostream() -{ - this->init(&_M_filebuf); - this->open(_Filename, _Mode | ios_base::out); -} -#endif -// explicit -llofstream::llofstream(_Filet *_File, - ios_base::openmode _Mode, size_t _Size) : - _M_filebuf(_File, _Mode, _Size), -#if LL_WINDOWS - std::ostream(&_M_filebuf) {} -#else - std::ostream() -{ - this->init(&_M_filebuf); -} -#endif - -#if !LL_WINDOWS -// explicit -llofstream::llofstream(int __fd, - ios_base::openmode _Mode, size_t _Size) : - _M_filebuf(__fd, _Mode, _Size), - std::ostream() +void llofstream::open(const std::string& _Filename, ios_base::openmode _Mode) { - this->init(&_M_filebuf); -} -#endif - -bool llofstream::is_open() const -{ // test if C stream has been opened - return _M_filebuf.is_open(); + std::ofstream::open(utf8str_to_utf16str(_Filename), + _Mode | ios_base::out); } void llofstream::open(const char* _Filename, ios_base::openmode _Mode) -{ // open a C stream with specified mode - if (_M_filebuf.open(_Filename, _Mode | ios_base::out) == 0) -#if LL_WINDOWS - { - _Myios::setstate(ios_base::failbit); - } - else - { - _Myios::clear(); - } -#else - { - this->setstate(ios_base::failbit); - } - else - { - this->clear(); - } -#endif +{ + std::ofstream::open(utf8str_to_utf16str(_Filename).c_str(), + _Mode | ios_base::out); } -void llofstream::close() -{ // close the C stream - if (_M_filebuf.close() == 0) - { -#if LL_WINDOWS - _Myios::setstate(ios_base::failbit); -#else - this->setstate(ios_base::failbit); -#endif - } -} +#endif // LL_WINDOWS /************** helper functions ********************************/ diff --git a/indra/llcommon/llfile.h b/indra/llcommon/llfile.h index 12eb049321..f6bcf87287 100644 --- a/indra/llcommon/llfile.h +++ b/indra/llcommon/llfile.h @@ -30,23 +30,22 @@ #ifndef LL_LLFILE_H #define LL_LLFILE_H +#include +#include + /** * This class provides a cross platform interface to the filesystem. * Attempts to mostly mirror the POSIX style IO functions. */ -typedef FILE LLFILE; - -#include -#include +typedef FILE LLFILE; #if LL_WINDOWS // windows version of stat function and stat data structure are called _stat typedef struct _stat llstat; #else typedef struct stat llstat; -#include -#include +#include #endif #ifndef S_ISREG @@ -68,13 +67,19 @@ class LL_COMMON_API LLFile static int close(LLFILE * file); + // Singu extension: the same as below, but doesn't print a warning as to leave errno alone. + static int mkdir_nowarn(const std::string& filename, int perms); + static int rmdir_nowarn(const std::string& filename); + static int remove_nowarn(const std::string& filename); + static int rename_nowarn(const std::string& filename, const std::string& newname); + // perms is a permissions mask like 0777 or 0700. In most cases it will // be overridden by the user's umask. It is ignored on Windows. static int mkdir(const std::string& filename, int perms = 0700); static int rmdir(const std::string& filename); - static int remove(const std::string& filename); - static int rename(const std::string& filename,const std::string& newname); + static int remove(const std::string& filename, int supress_error = 0); + static int rename(const std::string& filename,const std::string& newname, int supress_error = 0); static int stat(const std::string& filename,llstat* file_status); static bool isdir(const std::string& filename); static bool isfile(const std::string& filename); @@ -82,137 +87,25 @@ class LL_COMMON_API LLFile std::ios::openmode mode); static const char * tmpdir(); -}; -/** - * @brief Provides a layer of compatibility for C/POSIX. - * - * This is taken from both the GNU __gnu_cxx::stdio_filebuf extension and - * VC's basic_filebuf implementation. - * This file buffer provides extensions for working with standard C FILE*'s - * and POSIX file descriptors for platforms that support this. -*/ -namespace -{ -#if LL_WINDOWS -//typedef std::filebuf _Myfb; -//Singu note: Wrap around std::filebuf to override the open procedure. -// The client encodes filepaths in UTF-8, however Windows uses UTF-16 encoding natively. -// Need to convert paths to UTF-16 before calling std::filebuf::open. -struct _Myfb : public std::filebuf -{ - _Myfb() : std::filebuf() {} - _Myfb(_Filet* file) : std::filebuf(file) {} - _Myt *open(const char *filename, std::ios_base::openmode mode, int prot = (int)std::ios_base::_Openprot) - { - return std::filebuf::open(utf8str_to_utf16str(filename).c_str(),mode,prot); - } + static std::string strerr(int errn); + static std::string strerr(); }; -#else -typedef __gnu_cxx::stdio_filebuf< char > _Myfb; -typedef std::__c_file _Filet; -#endif /* LL_WINDOWS */ -} - -class LL_COMMON_API llstdio_filebuf : public _Myfb -{ -public: - /** - * deferred initialization / destruction - */ - llstdio_filebuf() : _Myfb() {} - virtual ~llstdio_filebuf() {} - /** - * @param f An open @c FILE*. - * @param mode Same meaning as in a standard filebuf. - * @param size Optimal or preferred size of internal buffer, in chars. - * Defaults to system's @c BUFSIZ. - * - * This constructor associates a file stream buffer with an open - * C @c FILE*. The @c FILE* will not be automatically closed when the - * stdio_filebuf is closed/destroyed. - */ - llstdio_filebuf(_Filet* __f, std::ios_base::openmode __mode, - //size_t __size = static_cast(BUFSIZ)) : - size_t __size = static_cast(1)) : -#if LL_WINDOWS - _Myfb(__f) {} +#if !defined(LL_WINDOWS) +typedef std::ifstream llifstream; +typedef std::ofstream llofstream; #else - _Myfb(__f, __mode, __size) {} -#endif - - /** - * @brief Opens an external file. - * @param s The name of the file. - * @param mode The open mode flags. - * @return @c this on success, NULL on failure - * - * If a file is already open, this function immediately fails. - * Otherwise it tries to open the file named @a s using the flags - * given in @a mode. - */ - //llstdio_filebuf* open(const char *_Filename, - // std::ios_base::openmode _Mode); - - /** - * @param fd An open file descriptor. - * @param mode Same meaning as in a standard filebuf. - * @param size Optimal or preferred size of internal buffer, in chars. - * - * This constructor associates a file stream buffer with an open - * POSIX file descriptor. The file descriptor will be automatically - * closed when the stdio_filebuf is closed/destroyed. - */ -#if !LL_WINDOWS - llstdio_filebuf(int __fd, std::ios_base::openmode __mode, - //size_t __size = static_cast(BUFSIZ)) : - size_t __size = static_cast(1)) : - _Myfb(__fd, __mode, __size) {} -#endif - -// *TODO: Seek the underlying c stream for better cross-platform compatibility? -#if !LL_WINDOWS -protected: - /** underflow() and uflow() functions are called to get the next - * character from the real input source when the buffer is empty. - * Buffered input uses underflow() - */ - /*virtual*/ int_type underflow(); - - /* Convert internal byte sequence to external, char-based - * sequence via codecvt. - */ - bool _convert_to_external(char_type*, std::streamsize); - - /** The overflow() function is called to transfer characters to the - * real output destination when the buffer is full. A call to - * overflow(c) outputs the contents of the buffer plus the - * character c. - * Consume some sequence of the characters in the pending sequence. - */ - /*virtual*/ int_type overflow(int_type __c = traits_type::eof()); - - /** sync() flushes the underlying @c FILE* stream. - */ - /*virtual*/ int sync(); - - std::streamsize xsgetn(char_type*, std::streamsize); - std::streamsize xsputn(char_type const*, std::streamsize); -#endif -}; - /** * @brief Controlling input for files. * * This class supports reading from named files, using the inherited - * functions from std::basic_istream. To control the associated - * sequence, an instance of std::basic_filebuf (or a platform-specific derivative) - * which allows construction using a pre-exisintg file stream buffer. - * We refer to this std::basic_filebuf (or derivative) as @c sb. -*/ -class LL_COMMON_API llifstream : public std::istream + * functions from std::ifstream. The only added value is that our constructor + * Does The Right Thing when passed a non-ASCII pathname. Sadly, that isn't + * true of Microsoft's std::ifstream. + */ +class LL_COMMON_API llifstream : public std::ifstream { // input stream associated with a C stream public: @@ -238,56 +131,6 @@ class LL_COMMON_API llifstream : public std::istream explicit llifstream(const char* _Filename, ios_base::openmode _Mode = ios_base::in); - /** - * @brief Create a stream using an open c file stream. - * @param File An open @c FILE*. - @param Mode Same meaning as in a standard filebuf. - @param Size Optimal or preferred size of internal buffer, in chars. - Defaults to system's @c BUFSIZ. - */ - explicit llifstream(_Filet *_File, - ios_base::openmode _Mode = ios_base::in, - //size_t _Size = static_cast(BUFSIZ)); - size_t _Size = static_cast(1)); - - /** - * @brief Create a stream using an open file descriptor. - * @param fd An open file descriptor. - @param Mode Same meaning as in a standard filebuf. - @param Size Optimal or preferred size of internal buffer, in chars. - Defaults to system's @c BUFSIZ. - */ -#if !LL_WINDOWS - explicit llifstream(int __fd, - ios_base::openmode _Mode = ios_base::in, - //size_t _Size = static_cast(BUFSIZ)); - size_t _Size = static_cast(1)); -#endif - - /** - * @brief The destructor does nothing. - * - * The file is closed by the filebuf object, not the formatting - * stream. - */ - virtual ~llifstream() {} - - // Members: - /** - * @brief Accessing the underlying buffer. - * @return The current basic_filebuf buffer. - * - * This hides both signatures of std::basic_ios::rdbuf(). - */ - llstdio_filebuf* rdbuf() const - { return const_cast(&_M_filebuf); } - - /** - * @brief Wrapper to test for an open file. - * @return @c rdbuf()->is_open() - */ - bool is_open() const; - /** * @brief Opens an external file. * @param Filename The name of the file. @@ -297,34 +140,21 @@ class LL_COMMON_API llifstream : public std::istream * fails, @c failbit is set in the stream's error state. */ void open(const std::string& _Filename, - ios_base::openmode _Mode = ios_base::in) - { open(_Filename.c_str(), _Mode); } + ios_base::openmode _Mode = ios_base::in); void open(const char* _Filename, ios_base::openmode _Mode = ios_base::in); - - /** - * @brief Close the file. - * - * Calls @c llstdio_filebuf::close(). If that function - * fails, @c failbit is set in the stream's error state. - */ - void close(); - -private: - llstdio_filebuf _M_filebuf; }; /** * @brief Controlling output for files. * - * This class supports writing to named files, using the inherited - * functions from std::basic_ostream. To control the associated - * sequence, an instance of std::basic_filebuf (or a platform-specific derivative) - * which allows construction using a pre-exisintg file stream buffer. - * We refer to this std::basic_filebuf (or derivative) as @c sb. -*/ -class LL_COMMON_API llofstream : public std::ostream + * This class supports writing to named files, using the inherited functions + * from std::ofstream. The only added value is that our constructor Does The + * Right Thing when passed a non-ASCII pathname. Sadly, that isn't true of + * Microsoft's std::ofstream. + */ +class LL_COMMON_API llofstream : public std::ofstream { public: // Constructors: @@ -342,64 +172,13 @@ class LL_COMMON_API llofstream : public std::ostream * @param Filename String specifying the filename. * @param Mode Open file in specified mode (see std::ios_base). * - * @c ios_base::out|ios_base::trunc is automatically included in - * @a mode. + * @c ios_base::out is automatically included in @a mode. */ explicit llofstream(const std::string& _Filename, ios_base::openmode _Mode = ios_base::out|ios_base::trunc); explicit llofstream(const char* _Filename, ios_base::openmode _Mode = ios_base::out|ios_base::trunc); - /** - * @brief Create a stream using an open c file stream. - * @param File An open @c FILE*. - @param Mode Same meaning as in a standard filebuf. - @param Size Optimal or preferred size of internal buffer, in chars. - Defaults to system's @c BUFSIZ. - */ - explicit llofstream(_Filet *_File, - ios_base::openmode _Mode = ios_base::out, - //size_t _Size = static_cast(BUFSIZ)); - size_t _Size = static_cast(1)); - - /** - * @brief Create a stream using an open file descriptor. - * @param fd An open file descriptor. - @param Mode Same meaning as in a standard filebuf. - @param Size Optimal or preferred size of internal buffer, in chars. - Defaults to system's @c BUFSIZ. - */ -#if !LL_WINDOWS - explicit llofstream(int __fd, - ios_base::openmode _Mode = ios_base::out, - //size_t _Size = static_cast(BUFSIZ)); - size_t _Size = static_cast(1)); -#endif - - /** - * @brief The destructor does nothing. - * - * The file is closed by the filebuf object, not the formatting - * stream. - */ - virtual ~llofstream() {} - - // Members: - /** - * @brief Accessing the underlying buffer. - * @return The current basic_filebuf buffer. - * - * This hides both signatures of std::basic_ios::rdbuf(). - */ - llstdio_filebuf* rdbuf() const - { return const_cast(&_M_filebuf); } - - /** - * @brief Wrapper to test for an open file. - * @return @c rdbuf()->is_open() - */ - bool is_open() const; - /** * @brief Opens an external file. * @param Filename The name of the file. @@ -409,23 +188,11 @@ class LL_COMMON_API llofstream : public std::ostream * fails, @c failbit is set in the stream's error state. */ void open(const std::string& _Filename, - ios_base::openmode _Mode = ios_base::out|ios_base::trunc) - { open(_Filename.c_str(), _Mode); } + ios_base::openmode _Mode = ios_base::out | ios_base::trunc); void open(const char* _Filename, ios_base::openmode _Mode = ios_base::out|ios_base::trunc); - - /** - * @brief Close the file. - * - * Calls @c llstdio_filebuf::close(). If that function - * fails, @c failbit is set in the stream's error state. - */ - void close(); - -private: - llstdio_filebuf _M_filebuf; }; - +#endif /** * @breif filesize helpers. diff --git a/indra/llcommon/llfindlocale.cpp b/indra/llcommon/llfindlocale.cpp index 505f5c540b..d916209263 100644 --- a/indra/llcommon/llfindlocale.cpp +++ b/indra/llcommon/llfindlocale.cpp @@ -39,7 +39,7 @@ #include #ifdef WIN32 -#include +#include "llwin32headers.h" #include #endif @@ -183,7 +183,7 @@ canonise_fl(FL_Locale *l) { #define RML(pn,sn) MAKELANGID(LANG_##pn, SUBLANG_##sn) struct IDToCode { LANGID id; - char* code; + const char* code; }; static const IDToCode both_to_code[] = { {ML(ENGLISH,US), "en_US.ISO_8859-1"}, diff --git a/indra/llcommon/llfixedbuffer.cpp b/indra/llcommon/llfixedbuffer.cpp index 4b5cdbe288..bd4db8be84 100644 --- a/indra/llcommon/llfixedbuffer.cpp +++ b/indra/llcommon/llfixedbuffer.cpp @@ -30,7 +30,8 @@ LLFixedBuffer::LLFixedBuffer(const U32 max_lines) : LLLineBuffer(), - mMaxLines(max_lines) + mMaxLines(max_lines), + mMutex() { mTimer.reset(); } diff --git a/indra/llcommon/llformat.cpp b/indra/llcommon/llformat.cpp index f9f16006a5..834bcf753a 100644 --- a/indra/llcommon/llformat.cpp +++ b/indra/llcommon/llformat.cpp @@ -36,18 +36,38 @@ #include "llformat.h" #include +#include // common used function with va_list argument // wrapper for vsnprintf to be called from llformatXXX functions. -static void va_format(std::string& out, const char *fmt, va_list va) +static void va_format(std::string& out, const char *fmt, va_list& va) { - char tstr[1024]; /* Flawfinder: ignore */ -#if LL_WINDOWS - _vsnprintf(tstr, 1024, fmt, va); + if (!fmt || !fmt[0]) return; // Don't bother if null or empty c_str + + typedef typename std::vector> vec_t; + static thread_local vec_t charvector(1024); // Evolves into charveleon + #define vsnprintf(va) std::vsnprintf(charvector.data(), charvector.capacity(), fmt, va) +#ifdef LL_WINDOWS // We don't have to copy on windows + #define va2 va #else - vsnprintf(tstr, 1024, fmt, va); /* Flawfinder: ignore */ + va_list va2; + va_copy(va2, va); +#endif + const auto smallsize(charvector.capacity()); + const auto size = vsnprintf(va); + if (size < 0) + { + LL_ERRS() << "Encoding failed, code " << size << ". String hint: " << out << '/' << fmt << LL_ENDL; + } + else if (static_cast(size) >= smallsize) // Resize if we need more space + { + charvector.resize(1+size); // Use the String Stone + vsnprintf(va2); + } +#ifndef LL_WINDOWS + va_end(va2); #endif - out.assign(tstr); + out.assign(charvector.data()); } std::string llformat(const char *fmt, ...) diff --git a/indra/llcommon/llformat.h b/indra/llcommon/llformat.h index 1cf3bfcca9..084f07b718 100644 --- a/indra/llcommon/llformat.h +++ b/indra/llcommon/llformat.h @@ -34,8 +34,18 @@ #ifndef LL_LLFORMAT_H #define LL_LLFORMAT_H +#if defined(LL_CLANG) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated" +#endif +#include +#include +#if defined(LL_CLANG) +#pragma clang diagnostic pop +#endif + // Use as follows: -// llinfos << llformat("Test:%d (%.2f %.2f)", idx, x, y) << llendl; +// LL_INFOS() << llformat("Test:%d (%.2f %.2f)", idx, x, y) << LL_ENDL; // // *NOTE: buffer limited to 1024, (but vsnprintf prevents overrun) // should perhaps be replaced with boost::format. diff --git a/indra/llcommon/llframetimer.cpp b/indra/llcommon/llframetimer.cpp index c214f03a48..a79c470818 100644 --- a/indra/llcommon/llframetimer.cpp +++ b/indra/llcommon/llframetimer.cpp @@ -43,16 +43,18 @@ F64 LLFrameTimer::sTotalSeconds = // Current time in seconds since epoch U64_to_F64(LLFrameTimer::sTotalTime) * USEC_TO_SEC_F64; F64 LLFrameTimer::sFrameTime = 0.0; // Current time in seconds since application start, updated together with LLFrameTimer::sTotalTime. // Updated exactly once per frame: -S32 LLFrameTimer::sFrameCount = 0; // Current frame number (number of frames since application start). +U64 LLFrameTimer::sFrameCount = 0; // Current frame number (number of frames since application start). U64 LLFrameTimer::sPrevTotalTime = LLFrameTimer::sStartTotalTime; // Previous (frame) time in microseconds since epoch, updated once per frame. U64 LLFrameTimer::sFrameDeltaTime = 0; // Microseconds between last two calls to LLFrameTimer::updateFrameTimeAndCount. // Mutex for the above. -apr_thread_mutex_t* LLFrameTimer::sGlobalMutex; +LLGlobalMutex LLFrameTimer::sGlobalMutex; + +bool LLFrameTimer::sFirstFrameTimerCreated; // static void LLFrameTimer::global_initialization(void) { - apr_thread_mutex_create(&sGlobalMutex, APR_THREAD_MUTEX_UNNESTED, LLAPRRootPool::get()()); + sFirstFrameTimerCreated = true; AIFrameTimer::sNextExpiration = NEVER; } @@ -63,9 +65,9 @@ void LLFrameTimer::updateFrameTime(void) sTotalTime = totalTime(); sTotalSeconds = U64_to_F64(sTotalTime) * USEC_TO_SEC_F64; F64 new_frame_time = U64_to_F64(sTotalTime - sStartTotalTime) * USEC_TO_SEC_F64; - apr_thread_mutex_lock(sGlobalMutex); + sGlobalMutex.lock(); sFrameTime = new_frame_time; - apr_thread_mutex_unlock(sGlobalMutex); + sGlobalMutex.unlock(); } // static diff --git a/indra/llcommon/llframetimer.h b/indra/llcommon/llframetimer.h index b09937895f..d0787e9bb7 100644 --- a/indra/llcommon/llframetimer.h +++ b/indra/llcommon/llframetimer.h @@ -36,26 +36,27 @@ #include "lltimer.h" #include "timing.h" -#include -#ifdef SHOW_ASSERT -#include "aithreadid.h" // is_main_thread() -#endif +#include "llthread.h" class LL_COMMON_API LLFrameTimer { public: // Create an LLFrameTimer and start it. After creation it is running and in the state expired (hasExpired will return true). - LLFrameTimer(void) : mExpiry(0), mRunning(true), mPaused(false) { if (!sGlobalMutex) global_initialization(); setAge(0.0); } + LLFrameTimer(void) : mExpiry(0), mRunning(true), mPaused(false) { if (!sFirstFrameTimerCreated) global_initialization(); setAge(0.0); } + + // + void copy(LLFrameTimer const& timer) { mStartTime = timer.mStartTime; mExpiry = timer.mExpiry; mRunning = timer.mRunning; mPaused = timer.mPaused; } + // // Atomic reads of static variables. // Return the number of seconds since the start of the application. - static F64 getElapsedSeconds(void) + static F64SecondsImplicit getElapsedSeconds(void) { // Loses msec precision after ~4.5 hours... - apr_thread_mutex_lock(sGlobalMutex); + sGlobalMutex.lock(); F64 res = sFrameTime; - apr_thread_mutex_unlock(sGlobalMutex); + sGlobalMutex.unlock(); return res; } @@ -64,9 +65,9 @@ class LL_COMMON_API LLFrameTimer { // sTotalTime is only accessed by the main thread, so no locking is necessary. llassert(is_main_thread()); - //apr_thread_mutex_lock(sGlobalMutex); + //sGlobalMutex.lock(); U64 res = sTotalTime; - //apr_thread_mutex_unlock(sGlobalMutex); + //sGlobalMutex.unlock(); llassert(res); return res; } @@ -76,20 +77,20 @@ class LL_COMMON_API LLFrameTimer { // sTotalSeconds is only accessed by the main thread, so no locking is necessary. llassert(is_main_thread()); - //apr_thread_mutex_lock(sGlobalMutex); + //sGlobalMutex.lock(); F64 res = sTotalSeconds; - //apr_thread_mutex_unlock(sGlobalMutex); + //sGlobalMutex.unlock(); return res; } // Return current frame number (the number of frames since application start). - static U32 getFrameCount(void) + static U64 getFrameCount(void) { // sFrameCount is only accessed by the main thread, so no locking is necessary. llassert(is_main_thread()); - //apr_thread_mutex_lock(sGlobalMutex); - U32 res = sFrameCount; - //apr_thread_mutex_unlock(sGlobalMutex); + //sGlobalMutex.lock(); + U64 res = sFrameCount; + //sGlobalMutex.unlock(); return res; } @@ -127,6 +128,7 @@ class LL_COMMON_API LLFrameTimer mRunning = false; } + void resetWithExpiry(F32 expiration) { reset(); setTimerExpirySec(expiration); } void pause(); // Mark elapsed time so far. void unpause(); // Move 'start' time in order to decrement time between pause and unpause from ElapsedTime. @@ -141,6 +143,9 @@ class LL_COMMON_API LLFrameTimer bool hasExpired() const { return getElapsedSeconds() >= mExpiry; } F32 getElapsedTimeF32() const { llassert(mRunning); return mPaused ? (F32)mStartTime : (F32)(getElapsedSeconds() - mStartTime); } bool getStarted() const { return mRunning; } + // + F64 getStartTime() const { llassert(!mPaused); return mStartTime; } + // // return the seconds since epoch when this timer will expire. F64 expiresAt() const; @@ -162,7 +167,7 @@ class LL_COMMON_API LLFrameTimer // // More than one thread are accessing (some of) these variables, therefore we need locking. - static apr_thread_mutex_t* sGlobalMutex; + static LLGlobalMutex sGlobalMutex; // Current time in seconds since application start, updated together with sTotalTime. static F64 sFrameTime; @@ -180,7 +185,9 @@ class LL_COMMON_API LLFrameTimer static F64 sTotalSeconds; // Current frame number (number of frames since application start). - static S32 sFrameCount; + static U64 sFrameCount; + + static bool sFirstFrameTimerCreated; // // Member data diff --git a/indra/llcommon/llhandle.h b/indra/llcommon/llhandle.h index 6af5e198d6..92ec54a762 100644 --- a/indra/llcommon/llhandle.h +++ b/indra/llcommon/llhandle.h @@ -28,8 +28,7 @@ #define LLHANDLE_H #include "llpointer.h" -#include -#include +#include /** * Helper object for LLHandle. Don't instantiate these directly, used @@ -86,7 +85,7 @@ class LLHandle LLHandle() : mTombStone(getDefaultTombStone()) {} template - LLHandle(const LLHandle& other, typename boost::enable_if< typename boost::is_convertible >::type* dummy = 0) + LLHandle(const LLHandle& other, typename std::enable_if::value>::type* dummy = nullptr) : mTombStone(other.mTombStone) {} @@ -194,21 +193,20 @@ class LLHandleProvider return mHandle; } -protected: - typedef LLHandle handle_type_t; - LLHandleProvider() - { - // provided here to enforce T deriving from LLHandleProvider - } - template - LLHandle getDerivedHandle(typename boost::enable_if< typename boost::is_convertible >::type* dummy = 0) const + LLHandle getDerivedHandle(typename std::enable_if::value>::type* dummy = nullptr) const { LLHandle downcast_handle; downcast_handle.mTombStone = getHandle().mTombStone; return downcast_handle; } +protected: + typedef LLHandle handle_type_t; + LLHandleProvider() + { + // provided here to enforce T deriving from LLHandleProvider + } private: mutable LLRootHandle mHandle; diff --git a/indra/llcommon/llhash.h b/indra/llcommon/llhash.h deleted file mode 100644 index 748bc9291a..0000000000 --- a/indra/llcommon/llhash.h +++ /dev/null @@ -1,72 +0,0 @@ -/** - * @file llhash.h - * @brief Wrapper for a hash function. - * - * $LicenseInfo:firstyear=2004&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLHASH_H -#define LL_LLHASH_H - -#include "llpreprocessor.h" // for GCC_VERSION - -#if (LL_WINDOWS) -#include -#include -#elif LL_DARWIN || LL_LINUX -#if GCC_VERSION >= 40300 || LL_ICC || LL_CLANG// gcc 4.3 or icc 11 and up -# include -#elif GCC_VERSION >= 30400 // gcc 3.4 and up -# include -#elif __GNUC__ >= 3 -# include -#else -# include -#endif -#elif LL_SOLARIS -#include -#else -#error Please define your platform. -#endif - -// Warning - an earlier template-based version of this routine did not do -// the correct thing on Windows. Since this is only used to get -// a string hash, it was converted to a regular routine and -// unit tests added. - -inline size_t llhash( const char * value ) -{ -#if LL_WINDOWS - return stdext::hash_value(value); -#elif ( (defined _STLPORT_VERSION) || ((LL_LINUX) && (__GNUC__ <= 2)) ) - std::hash H; - return H(value); -#elif LL_DARWIN || LL_LINUX || LL_SOLARIS - __gnu_cxx::hash H; - return H(value); -#else -#error Please define your platform. -#endif -} - -#endif - diff --git a/indra/llcommon/llheartbeat.cpp b/indra/llcommon/llheartbeat.cpp index 0ae1d73cbc..f5b9aacd54 100644 --- a/indra/llcommon/llheartbeat.cpp +++ b/indra/llcommon/llheartbeat.cpp @@ -98,7 +98,7 @@ LLHeartbeat::rawSendWithTimeout(F32 timeout_sec) mTimeoutTimer.setTimerExpirySec(timeout_sec); do { result = rawSend(); - //llinfos << " HEARTSENDc=" << result << llendl; + //LL_INFOS() << " HEARTSENDc=" << result << LL_ENDL; } while (result==1 && !mTimeoutTimer.hasExpired()); return result; @@ -118,7 +118,7 @@ LLHeartbeat::send(F32 timeout_sec) // zero-timeout; we don't care too much whether our // heartbeat was digested. result = rawSend(); - //llinfos << " HEARTSENDb=" << result << llendl; + //LL_INFOS() << " HEARTSENDb=" << result << LL_ENDL; } } @@ -146,14 +146,14 @@ LLHeartbeat::send(F32 timeout_sec) // It's been ages since we successfully had a heartbeat // digested by the watchdog. Sit here and spin a while // in the hope that we can force it through. - llwarns << "Unable to deliver heartbeat to launcher for " << mPanicTimer.getElapsedTimeF32() << " seconds. Going to try very hard for up to " << mAggressiveHeartbeatMaxBlockingSecs << " seconds." << llendl; + LL_WARNS() << "Unable to deliver heartbeat to launcher for " << mPanicTimer.getElapsedTimeF32() << " seconds. Going to try very hard for up to " << mAggressiveHeartbeatMaxBlockingSecs << " seconds." << LL_ENDL; result = rawSendWithTimeout(mAggressiveHeartbeatMaxBlockingSecs); if (result == 0) { total_success = true; } else { // we couldn't even force it through. That's bad, // but we'll try again in a while. - llwarns << "Could not deliver heartbeat to launcher even after trying very hard for " << mAggressiveHeartbeatMaxBlockingSecs << " seconds." << llendl; + LL_WARNS() << "Could not deliver heartbeat to launcher even after trying very hard for " << mAggressiveHeartbeatMaxBlockingSecs << " seconds." << LL_ENDL; } // in any case, reset the panic timer. diff --git a/indra/llcommon/llindexedqueue.h b/indra/llcommon/llindexedqueue.h deleted file mode 100644 index 1b80e6eda4..0000000000 --- a/indra/llcommon/llindexedqueue.h +++ /dev/null @@ -1,161 +0,0 @@ -/** - * @file llindexedqueue.h - * @brief An indexed FIFO queue, where only one element with each key - * can be in the queue. - * - * $LicenseInfo:firstyear=2003&license=viewergpl$ - * - * Copyright (c) 2003-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifndef LL_LLINDEXEDQUEUE_H -#define LL_LLINDEXEDQUEUE_H - -// An indexed FIFO queue, where only one element with each key can be in the queue. -// This is ONLY used in the interest list, you'll probably want to review this code -// carefully if you want to use it elsewhere - Doug - -template -class LLIndexedQueue -{ -protected: - typedef std::deque type_deque; - type_deque mQueue; - std::set mKeySet; - -public: - LLIndexedQueue() {} - - // move_if_there is an O(n) operation - bool push_back(const Type &value, bool move_if_there = false) - { - if (mKeySet.find(value) != mKeySet.end()) - { - // Already on the queue - if (move_if_there) - { - // Remove the existing entry. - typename type_deque::iterator it; - for (it = mQueue.begin(); it != mQueue.end(); ++it) - { - if (*it == value) - { - break; - } - } - - // This HAS to succeed, otherwise there's a serious bug in the keyset implementation - // (although this isn't thread safe, at all) - - mQueue.erase(it); - } - else - { - // We're not moving it, leave it alone - return false; - } - } - else - { - // Doesn't exist, add it to the key set - mKeySet.insert(value); - } - - mQueue.push_back(value); - - // We succeeded in adding the new element. - return true; - } - - bool push_front(const Type &value, bool move_if_there = false) - { - if (mKeySet.find(value) != mKeySet.end()) - { - // Already on the queue - if (move_if_there) - { - // Remove the existing entry. - typename type_deque::iterator it; - for (it = mQueue.begin(); it != mQueue.end(); ++it) - { - if (*it == value) - { - break; - } - } - - // This HAS to succeed, otherwise there's a serious bug in the keyset implementation - // (although this isn't thread safe, at all) - - mQueue.erase(it); - } - else - { - // We're not moving it, leave it alone - return false; - } - } - else - { - // Doesn't exist, add it to the key set - mKeySet.insert(value); - } - - mQueue.push_front(value); - return true; - } - - void pop() - { - Type value = mQueue.front(); - mKeySet.erase(value); - mQueue.pop_front(); - } - - Type &front() - { - return mQueue.front(); - } - - S32 size() const - { - return mQueue.size(); - } - - bool empty() const - { - return mQueue.empty(); - } - - void clear() - { - // Clear out all elements on the queue - mQueue.clear(); - mKeySet.clear(); - } -}; - -#endif // LL_LLINDEXEDQUEUE_H diff --git a/indra/llcommon/llindexedvector.h b/indra/llcommon/llindexedvector.h new file mode 100644 index 0000000000..a1c388aa41 --- /dev/null +++ b/indra/llcommon/llindexedvector.h @@ -0,0 +1,202 @@ +/** + * @file lldarray.h + * @brief Wrapped std::vector for backward compatibility. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLDARRAY_H +#define LL_LLDARRAY_H + +#include "llerror.h" + +#include +#include + +//-------------------------------------------------------- +// LLIndexedVector +//-------------------------------------------------------- + +template +class LLIndexedVector1 +{ +public: + typedef typename std::vector > vec_type_t; + typedef typename vec_type_t::iterator iterator; + typedef typename vec_type_t::const_iterator const_iterator; + typedef typename vec_type_t::reverse_iterator reverse_iterator; + typedef typename vec_type_t::const_reverse_iterator const_reverse_iterator; + typedef typename vec_type_t::size_type size_type; +protected: + std::vector > mVector; + +public: + LLIndexedVector1() { mVector.reserve(BlockSize); } + + const Type& toValue(const_iterator& iter) const { return iter->second; } + Type& toValue(iterator& iter) { return iter->second; } + + iterator begin() { return mVector.begin(); } + const_iterator begin() const { return mVector.begin(); } + iterator end() { return mVector.end(); } + const_iterator end() const { return mVector.end(); } + + reverse_iterator rbegin() { return mVector.rbegin(); } + const_reverse_iterator rbegin() const { return mVector.rbegin(); } + reverse_iterator rend() { return mVector.rend(); } + const_reverse_iterator rend() const { return mVector.rend(); } + + void reset() { mVector.resize(0); } + bool empty() const { return mVector.empty(); } + size_type size() const { return mVector.size(); } + + Type& operator[](const Key& k) + { + return get_val_in_pair_vec(mVector, k); + } + + const_iterator find(const Key& k) const + { + return std::find_if(mVector.begin(), mVector.end(), [&k](const typename vec_type_t::value_type& e) { return e.first == k; }); + } + + using DeletePointer = ::DeletePairedPointer; +}; + +template +class LLIndexedVector2 +{ +public: + typedef typename std::vector::iterator iterator; + typedef typename std::vector::const_iterator const_iterator; + typedef typename std::vector::reverse_iterator reverse_iterator; + typedef typename std::vector::const_reverse_iterator const_reverse_iterator; + typedef typename std::vector::size_type size_type; +protected: + std::vector mVector; + std::map mIndexMap; +#ifdef DEBUG_LLINDEXEDVECTOR + LLIndexedVector1 mCopy; +#endif + +public: + LLIndexedVector2() { mVector.reserve(BlockSize); } + + const Type& toValue(const_iterator& iter) const { return *iter; } + Type& toValue(iterator& iter) { return *iter; } + + iterator begin() { return mVector.begin(); } + const_iterator begin() const { return mVector.begin(); } + iterator end() { return mVector.end(); } + const_iterator end() const { return mVector.end(); } + + reverse_iterator rbegin() { return mVector.rbegin(); } + const_reverse_iterator rbegin() const { return mVector.rbegin(); } + reverse_iterator rend() { return mVector.rend(); } + const_reverse_iterator rend() const { return mVector.rend(); } + + void reset() { +#ifdef DEBUG_LLINDEXEDVECTOR + mCopy.reset(); +#endif + mVector.resize(0); + mIndexMap.resize(0); + } + bool empty() const { return mVector.empty(); } + size_type size() const { return mVector.size(); } + + void verify() const + { +#ifdef DEBUG_LLINDEXEDVECTOR + llassert_always(mCopy.empty() == empty()); + llassert_always(mCopy.size() == size()); + auto it2 = mCopy.begin(); + int index = 0; + for (auto it1 = begin(); it1 != end(); ++it1) + { + llassert_always(it2->second == &*it1); + ++it2; + ++index; + } + for (auto it = mIndexMap.begin(); it != mIndexMap.end(); ++it) + { + auto i = it->second; + llassert_always((mCopy.begin() + i)->first == it->first); + llassert_always((mCopy.begin() + i)->second == &mVector[i]); + } +#endif + } + + Type& operator[](const Key& k) + { + verify(); + typename std::map::const_iterator iter = mIndexMap.find(k); + + if (iter == mIndexMap.end()) + { + U32 n = mVector.size(); + mIndexMap[k] = n; + mVector.push_back(Type()); + llassert(mVector.size() == mIndexMap.size()); +#ifdef DEBUG_LLINDEXEDVECTOR + mCopy[k] = &mVector[n]; + auto it2 = mCopy.begin(); + for (auto it1 = begin(); it1 != end(); ++it1) + { + it2->second = &(*it1); + ++it2; + } +#endif + return mVector[n]; + } + else + { + return mVector[iter->second]; + } + } + + const_iterator find(const Key& k) const + { + verify(); + typename std::map::const_iterator iter = mIndexMap.find(k); + + if(iter == mIndexMap.end()) + { + return mVector.end(); + } + else + { + return mVector.begin() + iter->second; + } + } + + using DeletePointer = ::DeletePointer; +}; + +template +#ifdef DEBUG_LLINDEXEDVECTOR +using LLIndexedVector = LLIndexedVector2; +#else +using LLIndexedVector = LLIndexedVector1; +#endif + +#endif diff --git a/indra/llcommon/llindraconfigfile.cpp b/indra/llcommon/llindraconfigfile.cpp deleted file mode 100644 index f0873450f6..0000000000 --- a/indra/llcommon/llindraconfigfile.cpp +++ /dev/null @@ -1,119 +0,0 @@ -/** - * @file llindraconfigfile.cpp - * - * - * This class is an LLLiveFile that has config info for indra - * Currently only whether it's blacklisted - * - * $LicenseInfo:firstyear=2007&license=viewergpl$ - * - * Copyright (c) 2007-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#include "llindraconfigfile.h" - -#include "llfile.h" -#include "llsd.h" -#include "llsdserialize.h" -#include "llframetimer.h" - -static std::string sConfigDir = ""; -static const char indraConfigFileName[] = "indra.xml"; - - -LLIndraConfigFile::LLIndraConfigFile() - : LLLiveFile(filename()), - mConfig(LLSD()) -{ -} - -//static -void LLIndraConfigFile::initClass(const std::string& config_dir) -{ - sConfigDir = config_dir; - llinfos << "LLIndraConfigFile::initClass config dir " - << config_dir << "/" << indraConfigFileName << llendl; -} - -LLSD LLIndraConfigFile::getConfig(const std::string& config_name) -{ - if (sConfigDir.empty()) - { - llerrs << "LLIndraConfigFile::initClass() not called" << llendl; - } - - LLFrameTimer::updateFrameTime(); - - static LLIndraConfigFile the_file; - the_file.checkAndReload(); - - return the_file.mConfig[config_name]; -} - -std::string LLIndraConfigFile::filename() -{ - std::ostringstream ostr; - - ostr << sConfigDir - << "/" << indraConfigFileName; - - return ostr.str(); -} - -/* virtual */ -bool LLIndraConfigFile::loadFile() -{ - llinfos << "LLIndraConfigFile::loadFile: reading from " - << filename() << llendl; - - LLSD config; - - { - llifstream file(filename()); - if (file.is_open()) - { - LLSDSerialize::fromXML(config, file); - } - - if (config.isUndefined()) - { - llinfos << "LLIndraConfigFile::loadFile: file missing, ill-formed," - " or simply undefined; not changing the blacklist" << llendl; - return false; - } - } - - if (config.isMap()) - { - mConfig = config; - return true; - } - else - { - llwarns << "LLIndraConfigFile: " << indraConfigFileName << " expects a map; wrong format" << llendl; - return false; - } -} diff --git a/indra/llcommon/llindraconfigfile.h b/indra/llcommon/llindraconfigfile.h deleted file mode 100644 index 17eda906eb..0000000000 --- a/indra/llcommon/llindraconfigfile.h +++ /dev/null @@ -1,61 +0,0 @@ -/** - * @file llindraconfigfile.h - * @brief manages configuration file for indra.xml - * - * $LicenseInfo:firstyear=2007&license=viewergpl$ - * - * Copyright (c) 2007-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifndef LL_LLINDRACONFIGFILE_H -#define LL_LLINDRACONFIGFILE_H - -#include "linden_common.h" -#include - -#include "lllivefile.h" -#include "llsd.h" - - -// To use, call LLIndraConfigFile::initClass(config_dir); -// Then whenever getConfig is called, it will check and reload automatically - -class LLIndraConfigFile : public LLLiveFile -{ -public: - LLIndraConfigFile(); - static void initClass(const std::string& config_dir); - static LLSD getConfig(const std::string& config_name); - -private: - static std::string filename(); - -protected: - /* virtual */ bool loadFile(); - LLSD mConfig; -}; - -#endif //LL_LLINDRACONFIGFILE_H diff --git a/indra/llcommon/llinitparam.cpp b/indra/llcommon/llinitparam.cpp index db72aa19b9..03a4d5bee1 100644 --- a/indra/llcommon/llinitparam.cpp +++ b/indra/llcommon/llinitparam.cpp @@ -28,10 +28,17 @@ #include "linden_common.h" #include "llinitparam.h" +#include "llformat.h" namespace LLInitParam { + + predicate_rule_t default_parse_rules() + { + return ll_make_predicate(PROVIDED) && !ll_make_predicate(EMPTY); + } + // // Param // @@ -40,7 +47,9 @@ namespace LLInitParam { const U8* my_addr = reinterpret_cast(this); const U8* block_addr = reinterpret_cast(enclosing_block); - mEnclosingBlockOffset = 0x7FFFffff & (U32)(my_addr - block_addr); + U32 enclosing_block_offset = 0x7FFFffff & (U32)(my_addr - block_addr); + mEnclosingBlockOffsetLow = enclosing_block_offset & 0x0000ffff; + mEnclosingBlockOffsetHigh = (enclosing_block_offset & 0x007f0000) >> 16; } // @@ -58,8 +67,8 @@ namespace LLInitParam mMergeFunc(merge_func), mDeserializeFunc(deserialize_func), mSerializeFunc(serialize_func), + mInspectFunc(inspect_func), mValidationFunc(validation_func), - mInspectFunc(inspect_func), mMinCount(min_count), mMaxCount(max_count), mUserData(NULL) @@ -70,8 +79,8 @@ namespace LLInitParam mMergeFunc(NULL), mDeserializeFunc(NULL), mSerializeFunc(NULL), + mInspectFunc(NULL), mValidationFunc(NULL), - mInspectFunc(NULL), mMinCount(0), mMaxCount(0), mUserData(NULL) @@ -91,13 +100,13 @@ namespace LLInitParam void Parser::parserWarning(const std::string& message) { if (mParseSilently) return; - llwarns << message << llendl; + LL_WARNS() << message << LL_ENDL; } void Parser::parserError(const std::string& message) { if (mParseSilently) return; - llerrs << message << llendl; + LL_ERRS() << message << LL_ENDL; } @@ -112,6 +121,35 @@ namespace LLInitParam std::copy(src_block_data.mAllParams.begin(), src_block_data.mAllParams.end(), std::back_inserter(mAllParams)); } + void BlockDescriptor::addParam(const ParamDescriptorPtr in_param, const char* char_name) + { + // create a copy of the param descriptor in mAllParams + // so other data structures can store a pointer to it + mAllParams.push_back(in_param); + ParamDescriptorPtr param(mAllParams.back()); + + std::string name(char_name); + if ((size_t)param->mParamHandle > mMaxParamOffset) + { + LL_ERRS() << "Attempted to register param with block defined for parent class, make sure to derive from LLInitParam::Block" << LL_ENDL; + } + + if (name.empty()) + { + mUnnamedParams.push_back(param); + } + else + { + // don't use insert, since we want to overwrite existing entries + mNamedParams[name] = param; + } + + if (param->mValidationFunc) + { + mValidationList.push_back(std::make_pair(param->mParamHandle, param->mValidationFunc)); + } + } + BlockDescriptor::BlockDescriptor() : mMaxParamOffset(0), mInitializationState(UNINITIALIZED), @@ -150,11 +188,17 @@ namespace LLInitParam bool BaseBlock::submitValue(Parser::name_stack_t& name_stack, Parser& p, bool silent) { - if (!deserializeBlock(p, std::make_pair(name_stack.begin(), name_stack.end()), true)) + Parser::name_stack_range_t range = std::make_pair(name_stack.begin(), name_stack.end()); + if (!deserializeBlock(p, range, true)) { if (!silent) { - p.parserWarning(llformat("Failed to parse parameter \"%s\"", p.getCurrentElementName().c_str())); + std::string file_name = p.getCurrentFileName(); + if(!file_name.empty()) + { + file_name = "in file: " + file_name; + } + p.parserWarning(llformat("Failed to parse parameter \"%s\" %s", p.getCurrentElementName().c_str(), file_name.c_str())); } return false; } @@ -164,6 +208,9 @@ namespace LLInitParam bool BaseBlock::validateBlock(bool emit_errors) const { + // only validate block when it hasn't already passed validation with current data + if (!mValidated) + { const BlockDescriptor& block_data = mostDerivedBlockDescriptor(); for (BlockDescriptor::param_validation_list_t::const_iterator it = block_data.mValidationList.begin(); it != block_data.mValidationList.end(); ++it) { @@ -172,16 +219,23 @@ namespace LLInitParam { if (emit_errors) { - llwarns << "Invalid param \"" << getParamName(block_data, param) << "\"" << llendl; + LL_WARNS() << "Invalid param \"" << getParamName(block_data, param) << "\"" << LL_ENDL; } return false; } } - return true; + mValidated = true; + } + return mValidated; } - void BaseBlock::serializeBlock(Parser& parser, Parser::name_stack_t& name_stack, const LLInitParam::BaseBlock* diff_block) const + bool BaseBlock::serializeBlock(Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const LLInitParam::BaseBlock* diff_block) const { + bool serialized = false; + if (!predicate_rule.check(ll_make_predicate(PROVIDED, isProvided()))) + { + return false; + } // named param is one like LLView::Params::follows // unnamed param is like LLView::Params::rect - implicit const BlockDescriptor& block_data = mostDerivedBlockDescriptor(); @@ -193,15 +247,10 @@ namespace LLInitParam param_handle_t param_handle = (*it)->mParamHandle; const Param* param = getParamFromHandle(param_handle); ParamDescriptor::serialize_func_t serialize_func = (*it)->mSerializeFunc; - if (serialize_func) + if (serialize_func && predicate_rule.check(ll_make_predicate(PROVIDED, param->anyProvided()))) { const Param* diff_param = diff_block ? diff_block->getParamFromHandle(param_handle) : NULL; - // each param descriptor remembers its serial number - // so we can inspect the same param under different names - // and see that it has the same number - name_stack.push_back(std::make_pair("", true)); - serialize_func(*param, parser, name_stack, diff_param); - name_stack.pop_back(); + serialized |= serialize_func(*param, parser, name_stack, predicate_rule, diff_param); } } @@ -212,7 +261,7 @@ namespace LLInitParam param_handle_t param_handle = it->second->mParamHandle; const Param* param = getParamFromHandle(param_handle); ParamDescriptor::serialize_func_t serialize_func = it->second->mSerializeFunc; - if (serialize_func && param->anyProvided()) + if (serialize_func && predicate_rule.check(ll_make_predicate(PROVIDED, param->anyProvided()))) { // Ensure this param has not already been serialized // Prevents from being serialized as its own tag. @@ -237,10 +286,17 @@ namespace LLInitParam name_stack.push_back(std::make_pair(it->first, !duplicate)); const Param* diff_param = diff_block ? diff_block->getParamFromHandle(param_handle) : NULL; - serialize_func(*param, parser, name_stack, diff_param); + serialized |= serialize_func(*param, parser, name_stack, predicate_rule, diff_param); name_stack.pop_back(); } } + + if (!serialized && predicate_rule.check(ll_make_predicate(EMPTY))) + { + serialized |= parser.writeValue(Flag(), name_stack); + } + // was anything serialized in this block? + return serialized; } bool BaseBlock::inspectBlock(Parser& parser, Parser::name_stack_t name_stack, S32 min_count, S32 max_count) const @@ -295,7 +351,7 @@ namespace LLInitParam return true; } - bool BaseBlock::deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack_range, bool ignored) + bool BaseBlock::deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool ignored) { BlockDescriptor& block_data = mostDerivedBlockDescriptor(); bool names_left = name_stack_range.first != name_stack_range.second; @@ -308,15 +364,12 @@ namespace LLInitParam { const std::string& top_name = name_stack_range.first->first; - ParamDescriptor::deserialize_func_t deserialize_func = NULL; - Param* paramp = NULL; - BlockDescriptor::param_map_t::iterator found_it = block_data.mNamedParams.find(top_name); if (found_it != block_data.mNamedParams.end()) { // find pointer to member parameter from offset table - paramp = getParamFromHandle(found_it->second->mParamHandle); - deserialize_func = found_it->second->mDeserializeFunc; + Param* paramp = getParamFromHandle(found_it->second->mParamHandle); + ParamDescriptor::deserialize_func_t deserialize_func = found_it->second->mDeserializeFunc; Parser::name_stack_range_t new_name_stack(name_stack_range.first, name_stack_range.second); ++new_name_stack.first; @@ -358,36 +411,6 @@ namespace LLInitParam return false; } - //static - void BaseBlock::addParam(BlockDescriptor& block_data, const ParamDescriptorPtr in_param, const char* char_name) - { - // create a copy of the param descriptor in mAllParams - // so other data structures can store a pointer to it - block_data.mAllParams.push_back(in_param); - ParamDescriptorPtr param(block_data.mAllParams.back()); - - std::string name(char_name); - if ((size_t)param->mParamHandle > block_data.mMaxParamOffset) - { - llerrs << "Attempted to register param with block defined for parent class, make sure to derive from LLInitParam::Block" << llendl; - } - - if (name.empty()) - { - block_data.mUnnamedParams.push_back(param); - } - else - { - // don't use insert, since we want to overwrite existing entries - block_data.mNamedParams[name] = param; - } - - if (param->mValidationFunc) - { - block_data.mValidationList.push_back(std::make_pair(param->mParamHandle, param->mValidationFunc)); - } - } - void BaseBlock::addSynonym(Param& param, const std::string& synonym) { BlockDescriptor& block_data = mostDerivedBlockDescriptor(); @@ -399,7 +422,7 @@ namespace LLInitParam // Block if ((size_t)handle > block_data.mMaxParamOffset) { - llerrs << "Attempted to register param with block defined for parent class, make sure to derive from LLInitParam::Block" << llendl; + LL_ERRS() << "Attempted to register param with block defined for parent class, make sure to derive from LLInitParam::Block" << LL_ENDL; } ParamDescriptorPtr param_descriptor = findParamDescriptor(param); @@ -460,7 +483,7 @@ namespace LLInitParam if (merge_func) { Param* paramp = getParamFromHandle((*it)->mParamHandle); - llassert(paramp->mEnclosingBlockOffset == (*it)->mParamHandle); + llassert(paramp->getEnclosingBlockOffset() == (*it)->mParamHandle); some_param_changed |= merge_func(*paramp, *other_paramp, overwrite); } } diff --git a/indra/llcommon/llinitparam.h b/indra/llcommon/llinitparam.h index b79417f969..cd58f49ddc 100644 --- a/indra/llcommon/llinitparam.h +++ b/indra/llcommon/llinitparam.h @@ -29,14 +29,79 @@ #define LL_LLPARAM_H #include +#include #include -#include -#include #include -#include #include "llerror.h" #include "llstl.h" +#include "llpredicate.h" +#include "llsd.h" + +namespace LLTypeTags +{ + template + struct TypeTagBase + { + typedef void is_tag_t; + typedef INNER_TYPE inner_t; + static const int SORT_ORDER=_SORT_ORDER; + }; + + template + struct GreaterThan + { + static const bool value = VAL1 > VAL2; + }; + + template::value > + struct Swap + { + typedef typename ITEM::template Cons::value_t value_t; + }; + + template + struct Swap + { + typedef typename REST::template Cons::value_t>::value_t value_t; + }; + + template + struct IsSortable + { + static const bool value = false; + }; + + template + struct IsSortable + { + static const bool value = true; + }; + + template::value> + struct InsertInto + { + typedef typename ITEM::template Cons::value_t value_t; + }; + + template + struct InsertInto + { + typedef typename Swap::value_t value_t; + }; + + template::value> + struct Sorted + { + typedef T value_t; + }; + + template + struct Sorted + { + typedef typename InsertInto::value_t>::value_t value_t; + }; +} namespace LLInitParam { @@ -45,7 +110,9 @@ namespace LLInitParam template const T& defaultValue() { static T value; return value; } - template ::value > + // wraps comparison operator between any 2 values of the same type + // specialize to handle cases where equality isn't defined well, or at all + template ::value > struct ParamCompare { static bool equals(const T &a, const T &b) @@ -79,24 +146,120 @@ namespace LLInitParam // helper functions and classes typedef ptrdiff_t param_handle_t; + struct IS_A_BLOCK {}; + struct NOT_BLOCK {}; + + // these templates allow us to distinguish between template parameters + // that derive from BaseBlock and those that don't + template + struct IsBlock + { + typedef NOT_BLOCK value_t; + }; + + template + struct IsBlock + { + typedef IS_A_BLOCK value_t; + }; + + // ParamValue class directly manages the wrapped value + // by holding on to a copy (scalar params) + // or deriving from it (blocks) + // has specializations for custom value behavior + // and "tag" values like Lazy and Atomic + template::value_t> + class ParamValue + { + typedef ParamValue self_t; + + public: + typedef T default_value_t; + typedef T value_t; + + ParamValue(): mValue() {} + ParamValue(const default_value_t& other) : mValue(other) {} + + void setValue(const value_t& val) + { + mValue = val; + } + + const value_t& getValue() const + { + return mValue; + } + + T& getValue() + { + return mValue; + } + + bool isValid() const { return true; } + + protected: + T mValue; + }; + + template + class ParamValue + : public T + { + typedef ParamValue self_t; + public: + typedef T default_value_t; + typedef T value_t; + + ParamValue() + : T() + {} + + ParamValue(const default_value_t& other) + : T(other) + {} + + void setValue(const value_t& val) + { + *this = val; + } + + const value_t& getValue() const + { + return *this; + } + + T& getValue() + { + return *this; + } + }; + // empty default implementation of key cache // leverages empty base class optimization template class TypeValues + : public ParamValue::value_t> { private: struct Inaccessable{}; public: typedef std::map value_name_map_t; typedef Inaccessable name_t; + typedef TypeValues type_value_t; + typedef ParamValue::value_t> param_value_t; + typedef typename param_value_t::value_t value_t; + + TypeValues(const typename param_value_t::value_t& val) + : param_value_t(val) + {} void setValueName(const std::string& key) {} std::string getValueName() const { return ""; } - std::string calcValueName(const T& value) const { return ""; } + std::string calcValueName(const value_t& value) const { return ""; } void clearValueName() const {} - static bool getValueFromName(const std::string& name, T& value) + static bool getValueFromName(const std::string& name, value_t& value) { return false; } @@ -111,15 +274,39 @@ namespace LLInitParam return NULL; } + void assignNamedValue(const Inaccessable& name) + {} + + operator const value_t&() const + { + return param_value_t::getValue(); + } + + const value_t& operator()() const + { + return param_value_t::getValue(); + } + static value_name_map_t* getValueNames() {return NULL;} }; - template > + // helper class to implement name value lookups + // and caching of last used name + template , bool IS_SPECIALIZED = true > class TypeValuesHelper + : public ParamValue::value_t> { + typedef TypeValuesHelper self_t; public: typedef typename std::map value_name_map_t; typedef std::string name_t; + typedef self_t type_value_t; + typedef ParamValue::value_t> param_value_t; + typedef typename param_value_t::value_t value_t; + + TypeValuesHelper(const typename param_value_t::value_t& val) + : param_value_t(val) + {} //TODO: cache key by index to save on param block size void setValueName(const std::string& value_name) @@ -132,7 +319,7 @@ namespace LLInitParam return mValueName; } - std::string calcValueName(const T& value) const + std::string calcValueName(const value_t& value) const { value_name_map_t* map = getValueNames(); for (typename value_name_map_t::iterator it = map->begin(), end_it = map->end(); @@ -153,7 +340,7 @@ namespace LLInitParam mValueName.clear(); } - static bool getValueFromName(const std::string& name, T& value) + static bool getValueFromName(const std::string& name, value_t& value) { value_name_map_t* map = getValueNames(); typename value_name_map_t::iterator found_it = map->find(name); @@ -195,24 +382,94 @@ namespace LLInitParam return &sValues; } - static void declare(const std::string& name, const T& value) + static void declare(const std::string& name, const value_t& value) { (*getValueNames())[name] = value; } + void operator ()(const std::string& name) + { + *this = name; + } + + void assignNamedValue(const std::string& name) + { + if (getValueFromName(name, param_value_t::getValue())) + { + setValueName(name); + } + } + + operator const value_t&() const + { + return param_value_t::getValue(); + } + + const value_t& operator()() const + { + return param_value_t::getValue(); + } + protected: - static void getName(const std::string& name, const T& value) + static void getName(const std::string& name, const value_t& value) {} mutable std::string mValueName; }; + // string types can support custom named values, but need + // to disambiguate in code between a string that is a named value + // and a string that is a name + template + class TypeValuesHelper + : public TypeValuesHelper + { + public: + typedef TypeValuesHelper self_t; + typedef TypeValuesHelper base_t; + typedef std::string value_t; + typedef std::string name_t; + typedef self_t type_value_t; + + TypeValuesHelper(const std::string& val) + : base_t::TypeValuesHelper(val) // Fix invalid blah gcc + {} + + void operator ()(const std::string& name) + { + *this = name; + } + + self_t& operator =(const std::string& name) + { + if (base_t::getValueFromName(name, ParamValue::getValue())) + { + base_t::setValueName(name); + } + else + { + ParamValue::setValue(name); + } + return *this; + } + + operator const value_t&() const + { + return ParamValue::getValue(); + } + + const value_t& operator()() const + { + return ParamValue::getValue(); + } + + }; + + // parser base class with mechanisms for registering readers/writers/inspectors of different types class LL_COMMON_API Parser { LOG_CLASS(Parser); - public: - typedef std::vector > name_stack_t; typedef std::pair name_stack_range_t; typedef std::vector possible_values_t; @@ -225,82 +482,58 @@ namespace LLInitParam typedef std::map parser_write_func_map_t; typedef std::map parser_inspect_func_map_t; - private: - template::value> - struct ReaderWriter + public: + + Parser(parser_read_func_map_t& read_map, parser_write_func_map_t& write_map, parser_inspect_func_map_t& inspect_map) + : mParseSilently(false), + mParserReadFuncs(&read_map), + mParserWriteFuncs(&write_map), + mParserInspectFuncs(&inspect_map) + {} + + virtual ~Parser(); + + template bool readValue(T& param, typename std::enable_if::value>::type* dummy = 0) { - static bool read(T& param, Parser* parser) + parser_read_func_map_t::iterator found_it = mParserReadFuncs->find(&typeid(T)); + if (found_it != mParserReadFuncs->end()) { - parser_read_func_map_t::iterator found_it = parser->mParserReadFuncs->find(&typeid(T)); - if (found_it != parser->mParserReadFuncs->end()) - { - return found_it->second(*parser, (void*)¶m); - } - return false; - } - - static bool write(const T& param, Parser* parser, name_stack_t& name_stack) - { - parser_write_func_map_t::iterator found_it = parser->mParserWriteFuncs->find(&typeid(T)); - if (found_it != parser->mParserWriteFuncs->end()) - { - return found_it->second(*parser, (const void*)¶m, name_stack); - } - return false; + return found_it->second(*this, (void*)¶m); } - }; - // read enums as ints - template - struct ReaderWriter + return false; + } + + template bool readValue(T& param, typename std::enable_if::value>::type* dummy = nullptr) { - static bool read(T& param, Parser* parser) + parser_read_func_map_t::iterator found_it = mParserReadFuncs->find(&typeid(T)); + if (found_it != mParserReadFuncs->end()) + { + return found_it->second(*this, (void*)¶m); + } + else { - // read all enums as ints - parser_read_func_map_t::iterator found_it = parser->mParserReadFuncs->find(&typeid(S32)); - if (found_it != parser->mParserReadFuncs->end()) + found_it = mParserReadFuncs->find(&typeid(S32)); + if (found_it != mParserReadFuncs->end()) { - S32 value; - if (found_it->second(*parser, (void*)&value)) - { - param = (T)value; - return true; - } + S32 int_value; + bool parsed = found_it->second(*this, (void*)&int_value); + param = (T)int_value; + return parsed; } - return false; } + return false; + } - static bool write(const T& param, Parser* parser, name_stack_t& name_stack) + template bool writeValue(const T& param, name_stack_t& name_stack) { - parser_write_func_map_t::iterator found_it = parser->mParserWriteFuncs->find(&typeid(S32)); - if (found_it != parser->mParserWriteFuncs->end()) + parser_write_func_map_t::iterator found_it = mParserWriteFuncs->find(&typeid(T)); + if (found_it != mParserWriteFuncs->end()) { - return found_it->second(*parser, (const void*)¶m, name_stack); + return found_it->second(*this, (const void*)¶m, name_stack); } return false; } - }; - - public: - - Parser(parser_read_func_map_t& read_map, parser_write_func_map_t& write_map, parser_inspect_func_map_t& inspect_map) - : mParseSilently(false), - mParserReadFuncs(&read_map), - mParserWriteFuncs(&write_map), - mParserInspectFuncs(&inspect_map) - {} - - virtual ~Parser(); - - template bool readValue(T& param) - { - return ReaderWriter::read(param, this); - } - - template bool writeValue(const T& param, name_stack_t& name_stack) - { - return ReaderWriter::write(param, this, name_stack); - } // dispatch inspection to registered inspection functions, for each parameter in a param block template bool inspectValue(name_stack_t& name_stack, S32 min_count, S32 max_count, const possible_values_t* possible_values) @@ -315,6 +548,7 @@ namespace LLInitParam } virtual std::string getCurrentElementName() = 0; + virtual std::string getCurrentFileName() = 0; virtual void parserWarning(const std::string& message); virtual void parserError(const std::string& message); void setParseSilently(bool silent) { mParseSilently = silent; } @@ -343,6 +577,19 @@ namespace LLInitParam class Param; + enum ESerializePredicates + { + PROVIDED, + REQUIRED, + VALID, + HAS_DEFAULT_VALUE, + EMPTY + }; + + typedef LLPredicate::Rule predicate_rule_t; + + LL_COMMON_API predicate_rule_t default_parse_rules(); + // various callbacks and constraints associated with an individual param struct LL_COMMON_API ParamDescriptor { @@ -352,8 +599,8 @@ namespace LLInitParam }; typedef bool(*merge_func_t)(Param&, const Param&, bool); - typedef bool(*deserialize_func_t)(Param&, Parser&, const Parser::name_stack_range_t&, bool); - typedef void(*serialize_func_t)(const Param&, Parser&, Parser::name_stack_t&, const Param* diff_param); + typedef bool(*deserialize_func_t)(Param&, Parser&, Parser::name_stack_range_t&, bool); + typedef bool(*serialize_func_t)(const Param&, Parser&, Parser::name_stack_t&, const predicate_rule_t rules, const Param* diff_param); typedef void(*inspect_func_t)(const Param&, Parser&, Parser::name_stack_t&, S32 min_count, S32 max_count); typedef bool(*validation_func_t)(const Param*); @@ -381,7 +628,7 @@ namespace LLInitParam UserData* mUserData; }; - typedef boost::shared_ptr ParamDescriptorPtr; + typedef std::shared_ptr ParamDescriptorPtr; // each derived Block class keeps a static data structure maintaining offsets to various params class LL_COMMON_API BlockDescriptor @@ -397,6 +644,7 @@ namespace LLInitParam } EInitializationState; void aggregateBlockData(BlockDescriptor& src_block_data); + void addParam(ParamDescriptorPtr param, const char* name); typedef boost::unordered_map param_map_t; typedef std::vector param_list_t; @@ -412,48 +660,58 @@ namespace LLInitParam class BaseBlock* mCurrentBlockPtr; // pointer to block currently being constructed }; - class LL_COMMON_API BaseBlock - { - public: //TODO: implement in terms of owned_ptr template - class Lazy + class LazyValue { public: - Lazy() + LazyValue() : mPtr(NULL) {} - ~Lazy() + ~LazyValue() { delete mPtr; } - Lazy(const Lazy& other) + LazyValue(const T& value) { - if (other.mPtr) + mPtr = new T(value); + } + + LazyValue(const LazyValue& other) + : mPtr(NULL) { - mPtr = new T(*other.mPtr); + *this = other; } - else + + LazyValue& operator = (const LazyValue& other) { + if (!other.mPtr) + { + delete mPtr; mPtr = NULL; - } } - - Lazy& operator = (const Lazy& other) + else { - if (other.mPtr) + if (!mPtr) { mPtr = new T(*other.mPtr); } else { - mPtr = NULL; + *mPtr = *(other.mPtr); + } } return *this; } + bool operator==(const LazyValue& other) const + { + if (empty() || other.empty()) return false; + return *mPtr == *other.mPtr; + } + bool empty() const { return mPtr == NULL; @@ -461,18 +719,29 @@ namespace LLInitParam void set(const T& other) { - delete mPtr; + if (!mPtr) + { mPtr = new T(other); } + else + { + *mPtr = other; + } + } const T& get() const { - return ensureInstance(); + return *ensureInstance(); } T& get() { - return ensureInstance(); + return *ensureInstance(); + } + + operator const T&() const + { + return get(); } private: @@ -487,13 +756,50 @@ namespace LLInitParam } private: - // if you get a compilation error with this, that means you are using a forward declared struct for T - // unfortunately, the type traits we rely on don't work with forward declared typed - //static const int dummy = sizeof(T); mutable T* mPtr; }; + // root class of all parameter blocks + + class LL_COMMON_API BaseBlock + { + public: + // lift block tags into baseblock namespace so derived classes do not need to qualify them + typedef LLInitParam::IS_A_BLOCK IS_A_BLOCK; + typedef LLInitParam::NOT_BLOCK NOT_A_BLOCK; + + template + struct Sequential : public LLTypeTags::TypeTagBase + { + template struct Cons { typedef Sequential > value_t; }; + template struct Cons > { typedef Sequential value_t; }; + }; + + template + struct Atomic : public LLTypeTags::TypeTagBase + { + template struct Cons { typedef Atomic > value_t; }; + template struct Cons > { typedef Atomic value_t; }; + }; + + template::value_t > + struct Lazy : public LLTypeTags::TypeTagBase + { + template struct Cons + { + typedef Lazy, BLOCK_T> value_t; + }; + template struct Cons > + { + typedef Lazy value_t; + }; + template struct Cons > + { + typedef Lazy value_t; + }; + }; + // "Multiple" constraint types, put here in root class to avoid ambiguity during use struct AnyAmount { @@ -534,12 +840,28 @@ namespace LLInitParam LOG_CLASS(BaseBlock); friend class Param; + BaseBlock() + : mValidated(false), + mParamProvided(false) + {} + virtual ~BaseBlock() {} bool submitValue(Parser::name_stack_t& name_stack, Parser& p, bool silent=false); param_handle_t getHandleFromParam(const Param* param) const; bool validateBlock(bool emit_errors = true) const; + bool isProvided() const + { + return mParamProvided; + } + + bool isValid() const + { + return validateBlock(false); + } + + Param* getParamFromHandle(const param_handle_t param_handle) { if (param_handle == 0) return NULL; @@ -557,14 +879,23 @@ namespace LLInitParam void addSynonym(Param& param, const std::string& synonym); // Blocks can override this to do custom tracking of changes - virtual void paramChanged(const Param& changed_param, bool user_provided) {} + virtual void paramChanged(const Param& changed_param, bool user_provided) + { + if (user_provided) + { + // a child param has been explicitly changed + // so *some* aspect of this block is now provided + mValidated = false; + mParamProvided = true; + } + } - bool deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack_range, bool new_name); - void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block = NULL) const; + bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name); + bool serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t rule, const BaseBlock* diff_block = NULL) const; bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const; - virtual const BlockDescriptor& mostDerivedBlockDescriptor() const { return selfBlockDescriptor(); } - virtual BlockDescriptor& mostDerivedBlockDescriptor() { return selfBlockDescriptor(); } + virtual const BlockDescriptor& mostDerivedBlockDescriptor() const { return getBlockDescriptor(); } + virtual BlockDescriptor& mostDerivedBlockDescriptor() { return getBlockDescriptor(); } // take all provided params from other and apply to self bool overwriteFrom(const BaseBlock& other) @@ -578,10 +909,17 @@ namespace LLInitParam return false; } - static void addParam(BlockDescriptor& block_data, ParamDescriptorPtr param, const char* name); - ParamDescriptorPtr findParamDescriptor(const Param& param); + // take all provided params from other and apply to self + bool mergeBlock(BlockDescriptor& block_data, const BaseBlock& other, bool overwrite); + + static BlockDescriptor& getBlockDescriptor() + { + static BlockDescriptor sBlockDescriptor; + return sBlockDescriptor; + } + protected: void init(BlockDescriptor& descriptor, BlockDescriptor& base_descriptor, size_t block_size); @@ -590,25 +928,14 @@ namespace LLInitParam { return mergeBlock(block_data, source, overwrite); } - // take all provided params from other and apply to self - bool mergeBlock(BlockDescriptor& block_data, const BaseBlock& other, bool overwrite); - static BlockDescriptor& selfBlockDescriptor() - { - static BlockDescriptor sBlockDescriptor; - return sBlockDescriptor; - } + mutable bool mValidated; // lazy validation flag + bool mParamProvided; private: const std::string& getParamName(const BlockDescriptor& block_data, const Param* paramp) const; }; - template - struct ParamCompare, false > - { - static bool equals(const BaseBlock::Lazy& a, const BaseBlock::Lazy& b) { return !a.empty() || !b.empty(); } - }; - class LL_COMMON_API Param { public: @@ -632,261 +959,75 @@ namespace LLInitParam // store pointer to enclosing block as offset to reduce space and allow for quick copying BaseBlock& enclosingBlock() const - { + { const U8* my_addr = reinterpret_cast(this); // get address of enclosing BLOCK class using stored offset to enclosing BaseBlock class return *const_cast (reinterpret_cast - (my_addr - (ptrdiff_t)(S32)mEnclosingBlockOffset)); - } - - private: - friend class BaseBlock; - - U32 mEnclosingBlockOffset:31; - U32 mIsProvided:1; - - }; - - // these templates allow us to distinguish between template parameters - // that derive from BaseBlock and those that don't - template - struct IsBlock - { - static const bool value = false; - struct EmptyBase {}; - typedef EmptyBase base_class_t; - }; - - template - struct IsBlock - { - static const bool value = true; - typedef BaseBlock base_class_t; - }; - - template - struct IsBlock, typename T::baseblock_base_class_t > - { - static const bool value = true; - typedef BaseBlock base_class_t; - }; - - template::value> - class ParamValue : public NAME_VALUE_LOOKUP - { - public: - typedef const T& value_assignment_t; - typedef T value_t; - typedef ParamValue self_t; - - ParamValue(): mValue() {} - ParamValue(value_assignment_t other) : mValue(other) {} - - void setValue(value_assignment_t val) - { - mValue = val; - } - - value_assignment_t getValue() const - { - return mValue; - } - - T& getValue() - { - return mValue; - } - - operator value_assignment_t() const - { - return mValue; - } - - value_assignment_t operator()() const - { - return mValue; - } - - void operator ()(const typename NAME_VALUE_LOOKUP::name_t& name) - { - *this = name; - } - - self_t& operator =(const typename NAME_VALUE_LOOKUP::name_t& name) - { - if (NAME_VALUE_LOOKUP::getValueFromName(name, mValue)) - { - setValueName(name); - } - - return *this; - } - - protected: - T mValue; - }; - - template - class ParamValue - : public T, - public NAME_VALUE_LOOKUP - { - public: - typedef const T& value_assignment_t; - typedef T value_t; - typedef ParamValue self_t; - - ParamValue() - : T(), - mValidated(false) - {} - - ParamValue(value_assignment_t other) - : T(other), - mValidated(false) - {} - - void setValue(value_assignment_t val) - { - *this = val; - } - - value_assignment_t getValue() const - { - return *this; - } - - T& getValue() - { - return *this; - } - - operator value_assignment_t() const - { - return *this; - } - - value_assignment_t operator()() const - { - return *this; - } - - void operator ()(const typename NAME_VALUE_LOOKUP::name_t& name) - { - *this = name; + (my_addr - (ptrdiff_t)getEnclosingBlockOffset())); } - self_t& operator =(const typename NAME_VALUE_LOOKUP::name_t& name) + U32 getEnclosingBlockOffset() const { - if (NAME_VALUE_LOOKUP::getValueFromName(name, *this)) - { - setValueName(name); - } - - return *this; - } - - protected: - mutable bool mValidated; // lazy validation flag - }; - - template - class ParamValue - : public NAME_VALUE_LOOKUP - { - public: - typedef const std::string& value_assignment_t; - typedef std::string value_t; - typedef ParamValue self_t; - - ParamValue(): mValue() {} - ParamValue(value_assignment_t other) : mValue(other) {} - - void setValue(value_assignment_t val) - { - if (NAME_VALUE_LOOKUP::getValueFromName(val, mValue)) - { - NAME_VALUE_LOOKUP::setValueName(val); - } - else - { - mValue = val; - } - } - - value_assignment_t getValue() const - { - return mValue; - } - - std::string& getValue() - { - return mValue; + return ((U32)mEnclosingBlockOffsetHigh << 16) | (U32)mEnclosingBlockOffsetLow; } - operator value_assignment_t() const - { - return mValue; - } + private: + friend class BaseBlock; - value_assignment_t operator()() const - { - return mValue; - } + //24 bits for member offset field and 1 bit for provided flag + U16 mEnclosingBlockOffsetLow; + U8 mEnclosingBlockOffsetHigh:7; + U8 mIsProvided:1; - protected: - std::string mValue; }; - template > struct ParamIterator { - typedef typename std::vector >::const_iterator const_iterator; - typedef typename std::vector >::iterator iterator; + typedef typename std::vector::const_iterator const_iterator; + typedef typename std::vector::iterator iterator; }; - // specialize for custom parsing/decomposition of specific classes - // e.g. TypedParam has left, top, right, bottom, etc... + // wrapper for parameter with a known type + // specialized to handle 4 cases: + // simple "scalar" value + // parameter that is itself a block + // multiple scalar values, stored in a vector + // multiple blocks, stored in a vector template, bool HAS_MULTIPLE_VALUES = false, - bool VALUE_IS_BLOCK = IsBlock >::value> + typename VALUE_IS_BLOCK = typename IsBlock::value_t> >::value_t> class TypedParam : public Param, - public ParamValue + public NAME_VALUE_LOOKUP::type_value_t { + protected: + typedef TypedParam self_t; + typedef ParamValue::value_t> param_value_t; + typedef typename param_value_t::default_value_t default_value_t; + typedef typename NAME_VALUE_LOOKUP::type_value_t named_value_t; public: - typedef TypedParam self_t; - typedef ParamValue param_value_t; - typedef typename param_value_t::value_assignment_t value_assignment_t; - typedef NAME_VALUE_LOOKUP name_value_lookup_t; + typedef typename param_value_t::value_t value_t; - using param_value_t::operator(); + using named_value_t::operator(); - TypedParam(BlockDescriptor& block_descriptor, const char* name, value_assignment_t value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count) - : Param(block_descriptor.mCurrentBlockPtr) + TypedParam(BlockDescriptor& block_descriptor, const char* name, const default_value_t& value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count) + : Param(block_descriptor.mCurrentBlockPtr), + named_value_t(value) { if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING)) { - ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor( - block_descriptor.mCurrentBlockPtr->getHandleFromParam(this), - &mergeWith, - &deserializeParam, - &serializeParam, - validate_func, - &inspectParam, - min_count, max_count)); - BaseBlock::addParam(block_descriptor, param_descriptor, name); + init(block_descriptor, validate_func, min_count, max_count, name); } - - this->setValue(value); } bool isProvided() const { return Param::anyProvided(); } - static bool deserializeParam(Param& param, Parser& parser, const Parser::name_stack_range_t& name_stack_range, bool new_name) + bool isValid() const { return true; } + + static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name) { self_t& typed_param = static_cast(param); // no further names in stack, attempt to parse value now @@ -895,9 +1036,9 @@ namespace LLInitParam std::string name; // try to parse a known named value - if(name_value_lookup_t::valueNamesExist() + if(named_value_t::valueNamesExist() && parser.readValue(name) - && name_value_lookup_t::getValueFromName(name, typed_param.getValue())) + && named_value_t::getValueFromName(name, typed_param.getValue())) { typed_param.setValueName(name); typed_param.setProvided(); @@ -914,10 +1055,23 @@ namespace LLInitParam return false; } - static void serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const Param* diff_param) + static bool serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const Param* diff_param) { + bool serialized = false; const self_t& typed_param = static_cast(param); - if (!typed_param.isProvided()) return; + const self_t* diff_typed_param = static_cast(diff_param); + + LLPredicate::Value predicate; + if (diff_typed_param && ParamCompare::equals(typed_param.getValue(), diff_typed_param->getValue())) + { + predicate.set(HAS_DEFAULT_VALUE); + } + + predicate.set(VALID, typed_param.isValid()); + predicate.set(PROVIDED, typed_param.anyProvided()); + predicate.set(EMPTY, false); + + if (!predicate_rule.check(predicate)) return false; if (!name_stack.empty()) { @@ -930,23 +1084,27 @@ namespace LLInitParam if (!key.empty()) { - if (!diff_param || !ParamCompare::equals(static_cast(diff_param)->getValueName(), key)) + if (!diff_typed_param || !ParamCompare::equals(diff_typed_param->getValueName(), key)) { - parser.writeValue(key, name_stack); + serialized = parser.writeValue(key, name_stack); } } // then try to serialize value directly - else if (!diff_param || !ParamCompare::equals(typed_param.getValue(), static_cast(diff_param)->getValue())) + else if (!diff_typed_param || ParamCompare::equals(typed_param.getValue(), diff_typed_param->getValue())) { - if (!parser.writeValue(typed_param.getValue(), name_stack)) + serialized = parser.writeValue(typed_param.getValue(), name_stack); + if (!serialized) { std::string calculated_key = typed_param.calcValueName(typed_param.getValue()); - if (!diff_param || !ParamCompare::equals(static_cast(diff_param)->getValueName(), calculated_key)) + if (calculated_key.size() + && (!diff_typed_param + || !ParamCompare::equals(static_cast(diff_param)->getValueName(), calculated_key))) { - parser.writeValue(calculated_key, name_stack); + serialized = parser.writeValue(calculated_key, name_stack); } } } + return serialized; } static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count) @@ -954,22 +1112,23 @@ namespace LLInitParam // tell parser about our actual type parser.inspectValue(name_stack, min_count, max_count, NULL); // then tell it about string-based alternatives ("red", "blue", etc. for LLColor4) - if (name_value_lookup_t::getPossibleValues()) + if (named_value_t::getPossibleValues()) { - parser.inspectValue(name_stack, min_count, max_count, name_value_lookup_t::getPossibleValues()); + parser.inspectValue(name_stack, min_count, max_count, named_value_t::getPossibleValues()); } } - void set(value_assignment_t val, bool flag_as_provided = true) + void set(const value_t& val, bool flag_as_provided = true) { - param_value_t::clearValueName(); - this->setValue(val); + named_value_t::clearValueName(); + named_value_t::setValue(val); setProvided(flag_as_provided); } - self_t& operator =(const typename NAME_VALUE_LOOKUP::name_t& name) + self_t& operator =(const typename named_value_t::name_t& name) { - return static_cast(param_value_t::operator =(name)); + named_value_t::assignNamedValue(name); + return *this; } protected: @@ -994,41 +1153,47 @@ namespace LLInitParam } return false; } + private: + void init( BlockDescriptor &block_descriptor, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count, const char* name ) + { + ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor( + block_descriptor.mCurrentBlockPtr->getHandleFromParam(this), + &mergeWith, + &deserializeParam, + &serializeParam, + validate_func, + &inspectParam, + min_count, max_count)); + block_descriptor.addParam(param_descriptor, name); + } }; // parameter that is a block - template - class TypedParam + template + class TypedParam : public Param, - public ParamValue + public NAME_VALUE_LOOKUP::type_value_t { + protected: + typedef ParamValue::value_t> param_value_t; + typedef typename param_value_t::default_value_t default_value_t; + typedef TypedParam self_t; + typedef typename NAME_VALUE_LOOKUP::type_value_t named_value_t; public: - typedef ParamValue param_value_t; - typedef typename param_value_t::value_assignment_t value_assignment_t; - typedef TypedParam self_t; - typedef NAME_VALUE_LOOKUP name_value_lookup_t; - - using param_value_t::operator(); + using named_value_t::operator(); + typedef typename param_value_t::value_t value_t; - TypedParam(BlockDescriptor& block_descriptor, const char* name, value_assignment_t value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count) + TypedParam(BlockDescriptor& block_descriptor, const char* name, const default_value_t& value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count) : Param(block_descriptor.mCurrentBlockPtr), - param_value_t(value) + named_value_t(value) { if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING)) { - ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor( - block_descriptor.mCurrentBlockPtr->getHandleFromParam(this), - &mergeWith, - &deserializeParam, - &serializeParam, - validate_func, - &inspectParam, - min_count, max_count)); - BaseBlock::addParam(block_descriptor, param_descriptor, name); + init(block_descriptor, validate_func, min_count, max_count, name); } } - static bool deserializeParam(Param& param, Parser& parser, const Parser::name_stack_range_t& name_stack_range, bool new_name) + static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name) { self_t& typed_param = static_cast(param); @@ -1036,9 +1201,9 @@ namespace LLInitParam { // try to parse a known named value std::string name; - if(name_value_lookup_t::valueNamesExist() + if(named_value_t::valueNamesExist() && parser.readValue(name) - && name_value_lookup_t::getValueFromName(name, typed_param.getValue())) + && named_value_t::getValueFromName(name, typed_param.getValue())) { typed_param.setValueName(name); typed_param.setProvided(); @@ -1057,10 +1222,16 @@ namespace LLInitParam return false; } - static void serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const Param* diff_param) + static bool serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const Param* diff_param) { const self_t& typed_param = static_cast(param); - if (!typed_param.isProvided()) return; + + LLPredicate::Value predicate; + + predicate.set(VALID, typed_param.isValid()); + predicate.set(PROVIDED, typed_param.anyProvided()); + + if (!predicate_rule.check(predicate)) return false; if (!name_stack.empty()) { @@ -1070,21 +1241,32 @@ namespace LLInitParam std::string key = typed_param.getValueName(); if (!key.empty()) { - if (!parser.writeValue(key, name_stack)) + if (!diff_param || !ParamCompare::equals(static_cast(diff_param)->getValueName(), key)) { - return; + parser.writeValue(key, name_stack); + return true; } } else { - typed_param.serializeBlock(parser, name_stack, static_cast(diff_param)); + return typed_param.serializeBlock(parser, name_stack, predicate_rule, static_cast(diff_param)); } + + return false; } static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count) { - // I am a param that is also a block, so just recurse into my contents const self_t& typed_param = static_cast(param); + + // tell parser about our actual type + parser.inspectValue(name_stack, min_count, max_count, NULL); + // then tell it about string-based alternatives ("red", "blue", etc. for LLColor4) + if (named_value_t::getPossibleValues()) + { + parser.inspectValue(name_stack, min_count, max_count, named_value_t::getPossibleValues()); + } + typed_param.inspectBlock(parser, name_stack, min_count, max_count); } @@ -1092,42 +1274,37 @@ namespace LLInitParam // *and* the block as a whole validates bool isProvided() const { - // only validate block when it hasn't already passed validation with current data - if (Param::anyProvided() && !param_value_t::mValidated) - { - // a sub-block is "provided" when it has been filled in enough to be valid - param_value_t::mValidated = param_value_t::validateBlock(false); - } - return Param::anyProvided() && param_value_t::mValidated; + return Param::anyProvided() && isValid(); + } + + bool isValid() const + { + return param_value_t::isValid(); } // assign block contents to this param-that-is-a-block - void set(value_assignment_t val, bool flag_as_provided = true) + void set(const value_t& val, bool flag_as_provided = true) { - this->setValue(val); - param_value_t::clearValueName(); - // force revalidation of block - // next call to isProvided() will update provision status based on validity - param_value_t::mValidated = false; + named_value_t::setValue(val); + named_value_t::clearValueName(); setProvided(flag_as_provided); } - self_t& operator =(const typename NAME_VALUE_LOOKUP::name_t& name) + self_t& operator =(const typename named_value_t::name_t& name) { - return static_cast(param_value_t::operator =(name)); + named_value_t::assignNamedValue(name); + return *this; } // propagate changed status up to enclosing block /*virtual*/ void paramChanged(const Param& changed_param, bool user_provided) { param_value_t::paramChanged(changed_param, user_provided); + if (user_provided) { - // a child param has been explicitly changed - // so *some* aspect of this block is now provided - param_value_t::mValidated = false; setProvided(); - param_value_t::clearValueName(); + named_value_t::clearValueName(); } else { @@ -1151,7 +1328,7 @@ namespace LLInitParam if (src_typed_param.anyProvided()) { - if (dst_typed_param.mergeBlockParam(src_typed_param.isProvided(), dst_typed_param.isProvided(), param_value_t::selfBlockDescriptor(), src_typed_param, overwrite)) + if (dst_typed_param.mergeBlockParam(src_typed_param.isProvided(), dst_typed_param.isProvided(), param_value_t::getBlockDescriptor(), src_typed_param, overwrite)) { dst_typed_param.clearValueName(); dst_typed_param.setProvided(true); @@ -1160,56 +1337,80 @@ namespace LLInitParam } return false; } + + private: + void init( BlockDescriptor &block_descriptor, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count, const char* name ) + { + ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor( + block_descriptor.mCurrentBlockPtr->getHandleFromParam(this), + &mergeWith, + &deserializeParam, + &serializeParam, + validate_func, + &inspectParam, + min_count, max_count)); + block_descriptor.addParam(param_descriptor, name); + } }; - // container of non-block parameters - template - class TypedParam + // list of non-block parameters + template + class TypedParam : public Param { - public: - typedef TypedParam self_t; - typedef ParamValue param_value_t; - typedef typename std::vector container_t; - typedef const container_t& value_assignment_t; + protected: + typedef TypedParam self_t; + typedef ParamValue::value_t> param_value_t; + typedef typename std::vector container_t; + typedef container_t default_value_t; + typedef typename NAME_VALUE_LOOKUP::type_value_t named_value_t; + public: typedef typename param_value_t::value_t value_t; - typedef NAME_VALUE_LOOKUP name_value_lookup_t; - TypedParam(BlockDescriptor& block_descriptor, const char* name, value_assignment_t value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count) - : Param(block_descriptor.mCurrentBlockPtr) + TypedParam(BlockDescriptor& block_descriptor, const char* name, const default_value_t& value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count) + : Param(block_descriptor.mCurrentBlockPtr), + mMinCount(min_count), + mMaxCount(max_count) { std::copy(value.begin(), value.end(), std::back_inserter(mValues)); if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING)) { - ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor( - block_descriptor.mCurrentBlockPtr->getHandleFromParam(this), - &mergeWith, - &deserializeParam, - &serializeParam, - validate_func, - &inspectParam, - min_count, max_count)); - BaseBlock::addParam(block_descriptor, param_descriptor, name); + init(block_descriptor, validate_func, min_count, max_count, name); + } } - bool isProvided() const { return Param::anyProvided(); } + bool isProvided() const { return Param::anyProvided() && isValid(); } - static bool deserializeParam(Param& param, Parser& parser, const Parser::name_stack_range_t& name_stack_range, bool new_name) + bool isValid() const { + size_t num_elements = numValidElements(); + return mMinCount < num_elements && num_elements < mMaxCount; + } + + static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name) + { + Parser::name_stack_range_t new_name_stack_range(name_stack_range); self_t& typed_param = static_cast(param); value_t value; + + // pop first element if empty string + if (new_name_stack_range.first != new_name_stack_range.second && new_name_stack_range.first->first.empty()) + { + ++new_name_stack_range.first; + } + // no further names in stack, attempt to parse value now - if (name_stack_range.first == name_stack_range.second) + if (new_name_stack_range.first == new_name_stack_range.second) { std::string name; // try to parse a known named value - if(name_value_lookup_t::valueNamesExist() + if(named_value_t::valueNamesExist() && parser.readValue(name) - && name_value_lookup_t::getValueFromName(name, value)) + && named_value_t::getValueFromName(name, value)) { typed_param.add(value); typed_param.mValues.back().setValueName(name); @@ -1224,17 +1425,26 @@ namespace LLInitParam return false; } - static void serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const Param* diff_param) + static bool serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const Param* diff_param) { + bool serialized = false; const self_t& typed_param = static_cast(param); - if (!typed_param.isProvided() || name_stack.empty()) return; + + LLPredicate::Value predicate; + + predicate.set(REQUIRED, typed_param.mMinCount > 0); + predicate.set(VALID, typed_param.isValid()); + predicate.set(PROVIDED, typed_param.anyProvided()); + predicate.set(EMPTY, typed_param.mValues.empty()); + + if (!predicate_rule.check(predicate)) return false; for (const_iterator it = typed_param.mValues.begin(), end_it = typed_param.mValues.end(); it != end_it; ++it) { std::string key = it->getValueName(); - name_stack.back().second = true; + name_stack.emplace_back(std::string(), true); if(key.empty()) // not parsed via name values, write out value directly @@ -1243,7 +1453,11 @@ namespace LLInitParam if (!value_written) { std::string calculated_key = it->calcValueName(it->getValue()); - if (!parser.writeValue(calculated_key, name_stack)) + if (parser.writeValue(calculated_key, name_stack)) + { + serialized = true; + } + else { break; } @@ -1251,24 +1465,30 @@ namespace LLInitParam } else { - if(!parser.writeValue(key, name_stack)) + if(parser.writeValue(key, name_stack)) + { + serialized = true; + } + else { break; } } } + + return serialized; } static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count) { - parser.inspectValue(name_stack, min_count, max_count, NULL); - if (name_value_lookup_t::getPossibleValues()) + parser.inspectValue(name_stack, min_count, max_count, NULL); + if (named_value_t::getPossibleValues()) { - parser.inspectValue(name_stack, min_count, max_count, name_value_lookup_t::getPossibleValues()); + parser.inspectValue(name_stack, min_count, max_count, named_value_t::getPossibleValues()); } } - void set(value_assignment_t val, bool flag_as_provided = true) + void set(const container_t& val, bool flag_as_provided = true) { mValues = val; setProvided(flag_as_provided); @@ -1276,26 +1496,24 @@ namespace LLInitParam param_value_t& add() { - mValues.push_back(param_value_t(value_t())); + mValues.emplace_back(value_t()); Param::setProvided(); return mValues.back(); } self_t& add(const value_t& item) { - param_value_t param_value; - param_value.setValue(item); - mValues.push_back(param_value); + mValues.push_back(item); setProvided(); return *this; } - self_t& add(const typename name_value_lookup_t::name_t& name) + self_t& add(const typename named_value_t::name_t& name) { value_t value; // try to parse a per type named value - if (name_value_lookup_t::getValueFromName(name, value)) + if (named_value_t::getValueFromName(name, value)) { add(value); mValues.back().setValueName(name); @@ -1305,9 +1523,9 @@ namespace LLInitParam } // implicit conversion - operator value_assignment_t() const { return mValues; } + operator const container_t&() const { return mValues; } // explicit conversion - value_assignment_t operator()() const { return mValues; } + const container_t& operator()() const { return mValues; } typedef typename container_t::iterator iterator; typedef typename container_t::const_iterator const_iterator; @@ -1318,7 +1536,7 @@ namespace LLInitParam bool empty() const { return mValues.empty(); } size_t size() const { return mValues.size(); } - U32 numValidElements() const + size_t numValidElements() const { return mValues.size(); } @@ -1348,73 +1566,109 @@ namespace LLInitParam } container_t mValues; + size_t mMinCount, + mMaxCount; + + private: + void init( BlockDescriptor &block_descriptor, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count, const char* name ) + { + ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor( + block_descriptor.mCurrentBlockPtr->getHandleFromParam(this), + &mergeWith, + &deserializeParam, + &serializeParam, + validate_func, + &inspectParam, + min_count, max_count)); + block_descriptor.addParam(param_descriptor, name); + } }; - // container of block parameters - template - class TypedParam + // list of block parameters + template + class TypedParam : public Param { + protected: + typedef TypedParam self_t; + typedef ParamValue::value_t> param_value_t; + typedef typename std::vector container_t; + typedef typename NAME_VALUE_LOOKUP::type_value_t named_value_t; + typedef container_t default_value_t; + typedef typename container_t::iterator iterator; + typedef typename container_t::const_iterator const_iterator; public: - typedef TypedParam self_t; - typedef ParamValue param_value_t; - typedef typename std::vector container_t; - typedef const container_t& value_assignment_t; typedef typename param_value_t::value_t value_t; - typedef NAME_VALUE_LOOKUP name_value_lookup_t; - TypedParam(BlockDescriptor& block_descriptor, const char* name, value_assignment_t value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count) - : Param(block_descriptor.mCurrentBlockPtr) + TypedParam(BlockDescriptor& block_descriptor, const char* name, const default_value_t& value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count) + : Param(block_descriptor.mCurrentBlockPtr), + mMinCount(min_count), + mMaxCount(max_count) { std::copy(value.begin(), value.end(), back_inserter(mValues)); if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING)) { - ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor( - block_descriptor.mCurrentBlockPtr->getHandleFromParam(this), - &mergeWith, - &deserializeParam, - &serializeParam, - validate_func, - &inspectParam, - min_count, max_count)); - BaseBlock::addParam(block_descriptor, param_descriptor, name); + init(block_descriptor, validate_func, min_count, max_count, name); } } - bool isProvided() const { return Param::anyProvided(); } + bool isProvided() const { return Param::anyProvided() && isValid(); } + + bool isValid() const + { + size_t num_elements = numValidElements(); + return mMinCount < num_elements && num_elements < mMaxCount; + } - static bool deserializeParam(Param& param, Parser& parser, const Parser::name_stack_range_t& name_stack_range, bool new_name) + + static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name) { + Parser::name_stack_range_t new_name_stack_range(name_stack_range); self_t& typed_param = static_cast(param); bool new_value = false; + bool new_array_value = false; + + // pop first element if empty string + if (new_name_stack_range.first != new_name_stack_range.second && new_name_stack_range.first->first.empty()) + { + new_array_value = new_name_stack_range.first->second; + ++new_name_stack_range.first; + } - if (new_name || typed_param.mValues.empty()) + if (new_name || new_array_value || typed_param.mValues.empty()) { new_value = true; typed_param.mValues.push_back(value_t()); } - param_value_t& value = typed_param.mValues.back(); - if (name_stack_range.first == name_stack_range.second) + if (new_name_stack_range.first == new_name_stack_range.second) { // try to parse a known named value std::string name; - if(name_value_lookup_t::valueNamesExist() + if(named_value_t::valueNamesExist() && parser.readValue(name) - && name_value_lookup_t::getValueFromName(name, value.getValue())) + && named_value_t::getValueFromName(name, value.getValue())) { typed_param.mValues.back().setValueName(name); typed_param.setProvided(); + if (new_array_value) + { + name_stack_range.first->second = false; + } return true; } } // attempt to parse block... - if(value.deserializeBlock(parser, name_stack_range, new_name)) + if(value.deserializeBlock(parser, new_name_stack_range, new_name)) { typed_param.setProvided(); + if (new_array_value) + { + name_stack_range.first->second = false; + } return true; } @@ -1427,38 +1681,64 @@ namespace LLInitParam return false; } - static void serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const Param* diff_param) + static bool serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const Param* diff_param) { + bool serialized = false; const self_t& typed_param = static_cast(param); - if (!typed_param.isProvided() || name_stack.empty()) return; + LLPredicate::Value predicate; + + predicate.set(REQUIRED, typed_param.mMinCount > 0); + predicate.set(VALID, typed_param.isValid()); + predicate.set(PROVIDED, typed_param.anyProvided()); + predicate.set(EMPTY, typed_param.mValues.empty()); + + if (!predicate_rule.check(predicate)) return false; for (const_iterator it = typed_param.mValues.begin(), end_it = typed_param.mValues.end(); it != end_it; ++it) { - name_stack.back().second = true; + name_stack.push_back(std::make_pair(std::string(), true)); std::string key = it->getValueName(); if (!key.empty()) { - parser.writeValue(key, name_stack); + serialized |= parser.writeValue(key, name_stack); } // Not parsed via named values, write out value directly - // NOTE: currently we don't worry about removing default values in Multiple + // NOTE: currently we don't do diffing of Multiples else { - it->serializeBlock(parser, name_stack, NULL); + serialized = it->serializeBlock(parser, name_stack, predicate_rule, NULL); } + + name_stack.pop_back(); + } + + if (!serialized && predicate_rule.check(ll_make_predicate(EMPTY))) + { + serialized |= parser.writeValue(Flag(), name_stack); } + + return serialized; } static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count) { - // I am a vector of blocks, so describe my contents recursively - param_value_t(value_t()).inspectBlock(parser, name_stack, min_count, max_count); + const param_value_t& value_param = param_value_t(value_t()); + + // tell parser about our actual type + parser.inspectValue(name_stack, min_count, max_count, NULL); + // then tell it about string-based alternatives ("red", "blue", etc. for LLColor4) + if (named_value_t::getPossibleValues()) + { + parser.inspectValue(name_stack, min_count, max_count, named_value_t::getPossibleValues()); + } + + value_param.inspectBlock(parser, name_stack, min_count, max_count); } - void set(value_assignment_t val, bool flag_as_provided = true) + void set(const container_t& val, bool flag_as_provided = true) { mValues = val; setProvided(flag_as_provided); @@ -1478,12 +1758,12 @@ namespace LLInitParam return *this; } - self_t& add(const typename name_value_lookup_t::name_t& name) + self_t& add(const typename named_value_t::name_t& name) { value_t value; // try to parse a per type named value - if (name_value_lookup_t::getValueFromName(name, value)) + if (named_value_t::getValueFromName(name, value)) { add(value); mValues.back().setValueName(name); @@ -1492,12 +1772,10 @@ namespace LLInitParam } // implicit conversion - operator value_assignment_t() const { return mValues; } + operator const container_t&() const { return mValues; } // explicit conversion - value_assignment_t operator()() const { return mValues; } + const container_t& operator()() const { return mValues; } - typedef typename container_t::iterator iterator; - typedef typename container_t::const_iterator const_iterator; iterator begin() { return mValues.begin(); } iterator end() { return mValues.end(); } const_iterator begin() const { return mValues.begin(); } @@ -1505,14 +1783,14 @@ namespace LLInitParam bool empty() const { return mValues.empty(); } size_t size() const { return mValues.size(); } - U32 numValidElements() const + size_t numValidElements() const { - U32 count = 0; + size_t count = 0; for (const_iterator it = mValues.begin(), end_it = mValues.end(); it != end_it; ++it) { - if(it->validateBlock(false)) count++; + if(it->isValid()) count++; } return count; } @@ -1544,6 +1822,22 @@ namespace LLInitParam } container_t mValues; + size_t mMinCount, + mMaxCount; + + private: + void init( BlockDescriptor &block_descriptor, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count, const char* name ) + { + ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor( + block_descriptor.mCurrentBlockPtr->getHandleFromParam(this), + &mergeWith, + &deserializeParam, + &serializeParam, + validate_func, + &inspectParam, + min_count, max_count)); + block_descriptor.addParam(param_descriptor, name); + } }; template @@ -1558,13 +1852,13 @@ namespace LLInitParam // take all provided params from other and apply to self bool overwriteFrom(const self_t& other) { - return static_cast(this)->mergeBlock(selfBlockDescriptor(), other, true); + return static_cast(this)->mergeBlock(getBlockDescriptor(), other, true); } // take all provided params that are not already provided, and apply to self bool fillFrom(const self_t& other) { - return static_cast(this)->mergeBlock(selfBlockDescriptor(), other, false); + return static_cast(this)->mergeBlock(getBlockDescriptor(), other, false); } bool mergeBlockParam(bool source_provided, bool dest_provided, BlockDescriptor& block_data, const self_t& source, bool overwrite) @@ -1582,7 +1876,7 @@ namespace LLInitParam bool mergeBlock(BlockDescriptor& block_data, const self_t& other, bool overwrite) { mCurChoice = other.mCurChoice; - return base_block_t::mergeBlock(selfBlockDescriptor(), other, overwrite); + return base_block_t::mergeBlock(getBlockDescriptor(), other, overwrite); } // clear out old choice when param has changed @@ -1603,38 +1897,38 @@ namespace LLInitParam base_block_t::paramChanged(changed_param, user_provided); } - virtual const BlockDescriptor& mostDerivedBlockDescriptor() const { return selfBlockDescriptor(); } - virtual BlockDescriptor& mostDerivedBlockDescriptor() { return selfBlockDescriptor(); } + virtual const BlockDescriptor& mostDerivedBlockDescriptor() const { return getBlockDescriptor(); } + virtual BlockDescriptor& mostDerivedBlockDescriptor() { return getBlockDescriptor(); } protected: ChoiceBlock() : mCurChoice(0) { - BaseBlock::init(selfBlockDescriptor(), base_block_t::selfBlockDescriptor(), sizeof(DERIVED_BLOCK)); + BaseBlock::init(getBlockDescriptor(), base_block_t::getBlockDescriptor(), sizeof(DERIVED_BLOCK)); } // Alternatives are mutually exclusive wrt other Alternatives in the same block. // One alternative in a block will always have isChosen() == true. // At most one alternative in a block will have isProvided() == true. - template > + template ::type_value_t > class Alternative : public TypedParam { + typedef TypedParam super_t; + typedef typename super_t::value_t value_t; + typedef typename super_t::default_value_t default_value_t; + public: friend class ChoiceBlock; - typedef Alternative self_t; - typedef TypedParam >::value> super_t; - typedef typename super_t::value_assignment_t value_assignment_t; - using super_t::operator =; - explicit Alternative(const char* name = "", value_assignment_t val = defaultValue()) - : super_t(DERIVED_BLOCK::selfBlockDescriptor(), name, val, NULL, 0, 1), + explicit Alternative(const char* name = "", const default_value_t& val = defaultValue()) + : super_t(DERIVED_BLOCK::getBlockDescriptor(), name, val, NULL, 0, 1), mOriginalValue(val) { // assign initial choice to first declared option - DERIVED_BLOCK* blockp = ((DERIVED_BLOCK*)DERIVED_BLOCK::selfBlockDescriptor().mCurrentBlockPtr); - if (LL_UNLIKELY(DERIVED_BLOCK::selfBlockDescriptor().mInitializationState == BlockDescriptor::INITIALIZING)) + DERIVED_BLOCK* blockp = ((DERIVED_BLOCK*)DERIVED_BLOCK::getBlockDescriptor().mCurrentBlockPtr); + if (LL_UNLIKELY(DERIVED_BLOCK::getBlockDescriptor().mInitializationState == BlockDescriptor::INITIALIZING)) { if(blockp->mCurChoice == 0) { @@ -1648,31 +1942,31 @@ namespace LLInitParam static_cast(Param::enclosingBlock()).paramChanged(*this, true); } - void chooseAs(value_assignment_t val) + void chooseAs(const value_t& val) { super_t::set(val); } - void operator =(value_assignment_t val) + void operator =(const value_t& val) { super_t::set(val); } - void operator()(typename super_t::value_assignment_t val) + void operator()(const value_t& val) { super_t::set(val); } - operator value_assignment_t() const + operator const value_t&() const { return (*this)(); } - value_assignment_t operator()() const + const value_t& operator()() const { if (static_cast(Param::enclosingBlock()).getCurrentChoice() == this) { - return super_t::getValue(); + return super_t::getValue(); } return mOriginalValue; } @@ -1683,11 +1977,11 @@ namespace LLInitParam } private: - T mOriginalValue; + default_value_t mOriginalValue; }; - protected: - static BlockDescriptor& selfBlockDescriptor() + public: + static BlockDescriptor& getBlockDescriptor() { static BlockDescriptor sBlockDescriptor; return sBlockDescriptor; @@ -1707,6 +2001,8 @@ namespace LLInitParam : public BASE_BLOCK { typedef Block self_t; + + protected: typedef Block block_t; public: @@ -1715,80 +2011,82 @@ namespace LLInitParam // take all provided params from other and apply to self bool overwriteFrom(const self_t& other) { - return static_cast(this)->mergeBlock(selfBlockDescriptor(), other, true); + return static_cast(this)->mergeBlock(getBlockDescriptor(), other, true); } // take all provided params that are not already provided, and apply to self bool fillFrom(const self_t& other) { - return static_cast(this)->mergeBlock(selfBlockDescriptor(), other, false); + return static_cast(this)->mergeBlock(getBlockDescriptor(), other, false); } - virtual const BlockDescriptor& mostDerivedBlockDescriptor() const { return selfBlockDescriptor(); } - virtual BlockDescriptor& mostDerivedBlockDescriptor() { return selfBlockDescriptor(); } + virtual const BlockDescriptor& mostDerivedBlockDescriptor() const { return getBlockDescriptor(); } + virtual BlockDescriptor& mostDerivedBlockDescriptor() { return getBlockDescriptor(); } protected: Block() { //#pragma message("Parsing LLInitParam::Block") - BaseBlock::init(selfBlockDescriptor(), BASE_BLOCK::selfBlockDescriptor(), sizeof(DERIVED_BLOCK)); + BaseBlock::init(getBlockDescriptor(), BASE_BLOCK::getBlockDescriptor(), sizeof(DERIVED_BLOCK)); } // // Nested classes for declaring parameters // - template > + template ::type_value_t > class Optional : public TypedParam { - public: - typedef TypedParam >::value> super_t; - typedef typename super_t::value_assignment_t value_assignment_t; + typedef TypedParam super_t; + typedef typename super_t::value_t value_t; + typedef typename super_t::default_value_t default_value_t; + public: using super_t::operator(); using super_t::operator =; - explicit Optional(const char* name = "", value_assignment_t val = defaultValue()) - : super_t(DERIVED_BLOCK::selfBlockDescriptor(), name, val, NULL, 0, 1) + explicit Optional(const char* name = "", const default_value_t& val = defaultValue()) + : super_t(DERIVED_BLOCK::getBlockDescriptor(), name, val, NULL, 0, 1) { //#pragma message("Parsing LLInitParam::Block::Optional") } - Optional& operator =(value_assignment_t val) + Optional& operator =(const value_t& val) { - this->set(val); + super_t::set(val); return *this; } - DERIVED_BLOCK& operator()(value_assignment_t val) + DERIVED_BLOCK& operator()(const value_t& val) { super_t::set(val); return static_cast(Param::enclosingBlock()); } }; - template > + template ::type_value_t > class Mandatory : public TypedParam { - public: - typedef TypedParam >::value> super_t; + typedef TypedParam super_t; typedef Mandatory self_t; - typedef typename super_t::value_assignment_t value_assignment_t; + typedef typename super_t::value_t value_t; + typedef typename super_t::default_value_t default_value_t; + public: using super_t::operator(); using super_t::operator =; // mandatory parameters require a name to be parseable - explicit Mandatory(const char* name = "", value_assignment_t val = defaultValue()) - : super_t(DERIVED_BLOCK::selfBlockDescriptor(), name, val, &validate, 1, 1) + explicit Mandatory(const char* name = "", const default_value_t& val = defaultValue()) + : super_t(DERIVED_BLOCK::getBlockDescriptor(), name, val, &validate, 1, 1) {} - Mandatory& operator =(value_assignment_t val) + Mandatory& operator =(const value_t& val) { - this->set(val); + super_t::set(val); return *this; } - DERIVED_BLOCK& operator()(typename super_t::value_assignment_t val) + DERIVED_BLOCK& operator()(const value_t& val) { super_t::set(val); return static_cast(Param::enclosingBlock()); @@ -1802,28 +2100,29 @@ namespace LLInitParam }; - template > + template ::type_value_t > class Multiple : public TypedParam { - public: - typedef TypedParam >::value> super_t; + typedef TypedParam super_t; typedef Multiple self_t; typedef typename super_t::container_t container_t; - typedef typename super_t::value_assignment_t value_assignment_t; + typedef typename super_t::value_t value_t; + + public: typedef typename super_t::iterator iterator; typedef typename super_t::const_iterator const_iterator; explicit Multiple(const char* name = "") - : super_t(DERIVED_BLOCK::selfBlockDescriptor(), name, container_t(), &validate, RANGE::minCount, RANGE::maxCount) + : super_t(DERIVED_BLOCK::getBlockDescriptor(), name, container_t(), &validate, RANGE::minCount, RANGE::maxCount) {} - Multiple& operator =(value_assignment_t val) + Multiple& operator =(const container_t& val) { - set(val); + super_t::set(val); return *this; } - DERIVED_BLOCK& operator()(typename super_t::value_assignment_t val) + DERIVED_BLOCK& operator()(const container_t& val) { super_t::set(val); return static_cast(Param::enclosingBlock()); @@ -1831,18 +2130,20 @@ namespace LLInitParam static bool validate(const Param* paramp) { - U32 num_valid = ((super_t*)paramp)->numValidElements(); + size_t num_valid = ((super_t*)paramp)->numValidElements(); return RANGE::minCount <= num_valid && num_valid <= RANGE::maxCount; } }; - class Deprecated : public Param + // can appear in data files, but will ignored during parsing + // cannot read or write in code + class Ignored : public Param { public: - explicit Deprecated(const char* name) - : Param(DERIVED_BLOCK::selfBlockDescriptor().mCurrentBlockPtr) + explicit Ignored(const char* name) + : Param(DERIVED_BLOCK::getBlockDescriptor().mCurrentBlockPtr) { - BlockDescriptor& block_descriptor = DERIVED_BLOCK::selfBlockDescriptor(); + BlockDescriptor& block_descriptor = DERIVED_BLOCK::getBlockDescriptor(); if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING)) { ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor( @@ -1853,11 +2154,11 @@ namespace LLInitParam NULL, NULL, 0, S32_MAX)); - BaseBlock::addParam(block_descriptor, param_descriptor, name); + block_descriptor.addParam(param_descriptor, name); } } - static bool deserializeParam(Param& param, Parser& parser, const Parser::name_stack_range_t& name_stack_range, bool new_name) + static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name) { if (name_stack_range.first == name_stack_range.second) { @@ -1870,19 +2171,46 @@ namespace LLInitParam } }; - // different semantics for documentation purposes, but functionally identical - typedef Deprecated Ignored; + // can appear in data files, or be written to in code, but data will be ignored + // cannot be read in code + class Deprecated : public Ignored + { + public: + explicit Deprecated(const char* name) : Ignored(name) {} - protected: - static BlockDescriptor& selfBlockDescriptor() + // dummy writer interfaces + template + Deprecated& operator =(const T& val) + { + // do nothing + return *this; + } + + template + DERIVED_BLOCK& operator()(const T& val) + { + // do nothing + return static_cast(Param::enclosingBlock()); + } + + template + void set(const T& val, bool flag_as_provided = true) + { + // do nothing + } + }; + + public: + static BlockDescriptor& getBlockDescriptor() { static BlockDescriptor sBlockDescriptor; return sBlockDescriptor; } - template + protected: + template void changeDefault(TypedParam& param, - typename TypedParam::value_assignment_t value) + const typename TypedParam::value_t& value) { if (!param.isProvided()) { @@ -1892,214 +2220,423 @@ namespace LLInitParam }; - template - class BatchBlock - : public Block + template + struct IsBlock, BLOCK_T >, void> + { + typedef IS_A_BLOCK value_t; + }; + + template + struct IsBlock, BLOCK_T >, void> + { + typedef NOT_BLOCK value_t; + }; + + template + struct IsBlock, typename IsBlock >::value_t >, BLOCK_IDENTIFIER> + { + typedef typename IsBlock::value_t value_t; + }; + + template + struct IsBlock, typename IsBlock >::value_t >, BLOCK_IDENTIFIER> + { + typedef typename IsBlock::value_t value_t; + }; + + + template + struct InnerMostType + { + typedef T value_t; + }; + + template + struct InnerMostType > + { + typedef typename InnerMostType::value_t value_t; + }; + + template + struct InnerMostType > + { + typedef typename InnerMostType::value_t value_t; + }; + + template + class ParamValue , BLOCK_T> { + typedef ParamValue , BLOCK_T> self_t; + public: - typedef BatchBlock self_t; - typedef Block super_t; + typedef typename InnerMostType::value_t value_t; + typedef T default_value_t; + + ParamValue() + : mValue() + {} - BatchBlock() + ParamValue(const default_value_t& value) + : mValue(value) {} - bool deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack_range, bool new_name) + void setValue(const value_t& val) + { + mValue.setValue(val); + } + + const value_t& getValue() const + { + return mValue.getValue(); + } + + value_t& getValue() + { + return mValue.getValue(); + } + + bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name) { if (new_name) { - // reset block - *static_cast(this) = defaultBatchValue(); + resetToDefault(); } - return super_t::deserializeBlock(p, name_stack_range, new_name); + return mValue.deserializeBlock(p, name_stack_range, new_name); } - bool mergeBlock(BlockDescriptor& block_data, const BaseBlock& other, bool overwrite) + bool serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const self_t* diff_block = NULL) const { - if (overwrite) + const BaseBlock* base_block = diff_block + ? &(diff_block->mValue) + : NULL; + return mValue.serializeBlock(p, name_stack, predicate_rule, base_block); + } + + bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const + { + return mValue.inspectBlock(p, name_stack, min_count, max_count); + } + + bool mergeBlockParam(bool source_provided, bool dst_provided, BlockDescriptor& block_data, const self_t& source, bool overwrite) + { + if ((overwrite && source_provided) // new values coming in on top or... + || (!overwrite && !dst_provided)) // values being pushed under with nothing already there { - *static_cast(this) = defaultBatchValue(); - // merge individual parameters into destination - return super_t::mergeBlock(super_t::selfBlockDescriptor(), other, overwrite); + // clear away what is there and take the new stuff as a whole + resetToDefault(); + return mValue.mergeBlock(block_data, source.getValue(), overwrite); } - return false; + return mValue.mergeBlock(block_data, source.getValue(), overwrite); } - protected: - static const DERIVED_BLOCK& defaultBatchValue() + + bool validateBlock(bool emit_errors = true) const + { + return mValue.validateBlock(emit_errors); + } + + bool isValid() const + { + return validateBlock(false); + } + + static BlockDescriptor& getBlockDescriptor() + { + return value_t::getBlockDescriptor(); + } + + + private: + void resetToDefault() { - static DERIVED_BLOCK default_value; - return default_value; + static T default_value; + mValue = default_value; } + + T mValue; }; - // FIXME: this specialization is not currently used, as it only matches against the BatchBlock base class - // and not the derived class with the actual params - template - class ParamValue , - NAME_VALUE_LOOKUP, - true> - : public NAME_VALUE_LOOKUP, - protected BatchBlock + template + class ParamValue , IS_A_BLOCK> { + typedef ParamValue , IS_A_BLOCK> self_t; + public: - typedef BatchBlock block_t; - typedef const BatchBlock& value_assignment_t; - typedef block_t value_t; + typedef typename InnerMostType::value_t value_t; + typedef T default_value_t; ParamValue() - : block_t(), - mValidated(false) - {} + : mValue() + { + mCurParam = getBlockDescriptor().mAllParams.begin(); + } - ParamValue(value_assignment_t other) - : block_t(other), - mValidated(false) + ParamValue(const default_value_t& value) + : mValue(value) { + mCurParam = getBlockDescriptor().mAllParams.begin(); } - void setValue(value_assignment_t val) + void setValue(const value_t& val) { - *this = val; + mValue.setValue(val); } - value_assignment_t getValue() const + const value_t& getValue() const { - return *this; + return mValue.getValue(); } - BatchBlock& getValue() + value_t& getValue() { - return *this; + return mValue.getValue(); } - operator value_assignment_t() const + bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name) { - return *this; + if (new_name) + { + mCurParam = getBlockDescriptor().mAllParams.begin(); + } + if (name_stack_range.first == name_stack_range.second + && mCurParam != getBlockDescriptor().mAllParams.end()) + { + // deserialize to mCurParam + ParamDescriptor& pd = *(*mCurParam); + ParamDescriptor::deserialize_func_t deserialize_func = pd.mDeserializeFunc; + Param* paramp = mValue.getParamFromHandle(pd.mParamHandle); + + if (deserialize_func + && paramp + && deserialize_func(*paramp, p, name_stack_range, new_name)) + { + ++mCurParam; + return true; + } + else + { + return false; + } + } + else + { + return mValue.deserializeBlock(p, name_stack_range, new_name); + } } - value_assignment_t operator()() const + bool serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const self_t* diff_block = NULL) const { - return *this; + const BaseBlock* base_block = diff_block + ? &(diff_block->mValue) + : NULL; + return mValue.serializeBlock(p, name_stack, predicate_rule, base_block); } - protected: - mutable bool mValidated; // lazy validation flag + bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const + { + return mValue.inspectBlock(p, name_stack, min_count, max_count); + } + + bool mergeBlockParam(bool source_provided, bool dst_provided, BlockDescriptor& block_data, const self_t& source, bool overwrite) + { + return mValue.mergeBlock(block_data, source.getValue(), overwrite); + } + + bool validateBlock(bool emit_errors = true) const + { + return mValue.validateBlock(emit_errors); + } + + bool isValid() const + { + return validateBlock(false); + } + + static BlockDescriptor& getBlockDescriptor() + { + return value_t::getBlockDescriptor(); + } + + private: + + BlockDescriptor::all_params_list_t::iterator mCurParam; + T mValue; }; - template - class ParamValue , - TypeValues, - IS_BLOCK> - : public IsBlock::base_class_t + template + class ParamValue , NOT_BLOCK> + : public T { + typedef ParamValue , NOT_BLOCK> self_t; + public: - typedef ParamValue , TypeValues, false> self_t; - typedef const T& value_assignment_t; - typedef T value_t; + typedef typename InnerMostType::value_t value_t; + typedef T default_value_t; + + ParamValue() + : T() + {} + + ParamValue(const default_value_t& value) + : T(value.getValue()) + {} + + bool isValid() const { return true; } + }; + + template + class ParamValue , BLOCK_T> + { + typedef ParamValue , BLOCK_T> self_t; + + public: + typedef typename InnerMostType::value_t value_t; + typedef LazyValue default_value_t; ParamValue() - : mValue(), - mValidated(false) + : mValue() + {} + + ParamValue(const default_value_t& other) + : mValue(other) {} - ParamValue(value_assignment_t other) - : mValue(other), - mValidated(false) + ParamValue(const T& value) + : mValue(value) {} - void setValue(value_assignment_t val) + void setValue(const value_t& val) { mValue.set(val); } - value_assignment_t getValue() const + const value_t& getValue() const { - return mValue.get(); + return mValue.get().getValue(); } - T& getValue() + value_t& getValue() { - return mValue.get(); + return mValue.get().getValue(); } - operator value_assignment_t() const + bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name) { - return mValue.get(); + return mValue.get().deserializeBlock(p, name_stack_range, new_name); } - value_assignment_t operator()() const + bool serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const self_t* diff_block = NULL) const { - return mValue.get(); + if (mValue.empty()) return false; + + const BaseBlock* base_block = (diff_block && !diff_block->mValue.empty()) + ? &(diff_block->mValue.get().getValue()) + : NULL; + return mValue.get().serializeBlock(p, name_stack, predicate_rule, base_block); } - bool deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack_range, bool new_name) + bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const { - return mValue.get().deserializeBlock(p, name_stack_range, new_name); + return mValue.get().inspectBlock(p, name_stack, min_count, max_count); + } + + bool mergeBlockParam(bool source_provided, bool dst_provided, BlockDescriptor& block_data, const self_t& source, bool overwrite) + { + return source.mValue.empty() || mValue.get().mergeBlock(block_data, source.getValue(), overwrite); + } + + bool validateBlock(bool emit_errors = true) const + { + return mValue.empty() || mValue.get().validateBlock(emit_errors); + } + + bool isValid() const + { + return validateBlock(false); + } + + static BlockDescriptor& getBlockDescriptor() + { + return value_t::getBlockDescriptor(); } - void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block = NULL) const + private: + LazyValue mValue; + }; + + template + class ParamValue , BLOCK_T> { - if (mValue.empty()) return; + typedef ParamValue , BLOCK_T> self_t; + + public: + typedef typename InnerMostType::value_t value_t; + typedef LazyValue default_value_t; + + ParamValue() + : mValue() + {} + + ParamValue(const default_value_t& other) + : mValue(other) + {} + + ParamValue(const T& value) + : mValue(value) + {} - mValue.get().serializeBlock(p, name_stack, diff_block); + void setValue(const value_t& val) + { + mValue.set(val); } - bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const + const value_t& getValue() const { - if (mValue.empty()) return false; + return mValue.get().getValue(); + } - return mValue.get().inspectBlock(p, name_stack, min_count, max_count); + value_t& getValue() + { + return mValue.get().getValue(); } - protected: - mutable bool mValidated; // lazy validation flag + bool isValid() const + { + return true; + } private: - BaseBlock::Lazy mValue; + LazyValue mValue; }; template <> - class ParamValue , - false> - : public TypeValues, - public BaseBlock + class ParamValue + : public BaseBlock { public: - typedef ParamValue, false> self_t; - typedef const LLSD& value_assignment_t; + typedef LLSD value_t; + typedef LLSD default_value_t; ParamValue() - : mValidated(false) {} - ParamValue(value_assignment_t other) - : mValue(other), - mValidated(false) + ParamValue(const default_value_t& other) + : mValue(other) {} - void setValue(value_assignment_t val) { mValue = val; } + void setValue(const value_t& val) { mValue = val; } - value_assignment_t getValue() const { return mValue; } + const value_t& getValue() const { return mValue; } LLSD& getValue() { return mValue; } - operator value_assignment_t() const { return mValue; } - value_assignment_t operator()() const { return mValue; } - - // block param interface - LL_COMMON_API bool deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack_range, bool new_name); - LL_COMMON_API void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block = NULL) const; + LL_COMMON_API bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name); + LL_COMMON_API bool serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const BaseBlock* diff_block = NULL) const; bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const { //TODO: implement LLSD params as schema type Any return true; } - protected: - mutable bool mValidated; // lazy validation flag - private: static void serializeElement(Parser& p, const LLSD& sd, Parser::name_stack_t& name_stack); @@ -2108,8 +2645,7 @@ namespace LLInitParam template class CustomParamValue - : public Block > >, - public TypeValues + : public Block > { public: typedef enum e_value_age @@ -2119,20 +2655,20 @@ namespace LLInitParam BLOCK_AUTHORITATIVE // mValue is derived from the block parameters, which are authoritative } EValueAge; - typedef ParamValue > derived_t; + typedef TypeValues derived_t; typedef CustomParamValue self_t; - typedef Block block_t; - typedef const T& value_assignment_t; + typedef Block > block_t; + typedef T default_value_t; typedef T value_t; + typedef void baseblock_base_class_t; - CustomParamValue(const T& value = T()) + CustomParamValue(const default_value_t& value = T()) : mValue(value), - mValueAge(VALUE_AUTHORITATIVE), - mValidated(false) + mValueAge(VALUE_AUTHORITATIVE) {} - bool deserializeBlock(Parser& parser, Parser::name_stack_range_t name_stack_range, bool new_name) + bool deserializeBlock(Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name) { derived_t& typed_param = static_cast(*this); // try to parse direct value T @@ -2143,8 +2679,6 @@ namespace LLInitParam typed_param.mValueAge = VALUE_AUTHORITATIVE; typed_param.updateBlockFromValue(false); - typed_param.clearValueName(); - return true; } } @@ -2153,26 +2687,30 @@ namespace LLInitParam return typed_param.BaseBlock::deserializeBlock(parser, name_stack_range, new_name); } - void serializeBlock(Parser& parser, Parser::name_stack_t& name_stack, const BaseBlock* diff_block = NULL) const + bool serializeBlock(Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const BaseBlock* diff_block = NULL) const { const derived_t& typed_param = static_cast(*this); const derived_t* diff_param = static_cast(diff_block); - std::string key = typed_param.getValueName(); - - // first try to write out name of name/value pair - if (!key.empty()) - { - if (!diff_param || !ParamCompare::equals(diff_param->getValueName(), key)) - { - parser.writeValue(key, name_stack); - } - } + //std::string key = typed_param.getValueName(); + + //// first try to write out name of name/value pair + //if (!key.empty()) + //{ + // if (!diff_param || !ParamCompare::equals(diff_param->getValueName(), key)) + // { + // return parser.writeValue(key, name_stack); + // } + //} // then try to serialize value directly - else if (!diff_param || !ParamCompare::equals(typed_param.getValue(), diff_param->getValue())) + if (!diff_param || !ParamCompare::equals(typed_param.getValue(), diff_param->getValue())) { - if (!parser.writeValue(typed_param.getValue(), name_stack)) + if (parser.writeValue(typed_param.getValue(), name_stack)) + { + return true; + } + else { //RN: *always* serialize provided components of BlockValue (don't pass diff_param on), // since these tend to be viewed as the constructor arguments for the value T. It seems @@ -2189,27 +2727,15 @@ namespace LLInitParam // and serialize those params derived_t copy(typed_param); copy.updateBlockFromValue(true); - copy.block_t::serializeBlock(parser, name_stack, NULL); + return copy.block_t::serializeBlock(parser, name_stack, predicate_rule, NULL); } else { - block_t::serializeBlock(parser, name_stack, NULL); + return block_t::serializeBlock(parser, name_stack, predicate_rule, NULL); } } } - } - - bool inspectBlock(Parser& parser, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const - { - // first, inspect with actual type... - parser.inspectValue(name_stack, min_count, max_count, NULL); - if (TypeValues::getPossibleValues()) - { - //...then inspect with possible string values... - parser.inspectValue(name_stack, min_count, max_count, TypeValues::getPossibleValues()); - } - // then recursively inspect contents... - return block_t::inspectBlock(parser, name_stack, min_count, max_count); + return false; } bool validateBlock(bool emit_errors = true) const @@ -2219,7 +2745,6 @@ namespace LLInitParam if (block_t::validateBlock(emit_errors)) { // clear stale keyword associated with old value - TypeValues::clearValueName(); mValueAge = BLOCK_AUTHORITATIVE; static_cast(const_cast(this))->updateValueFromBlock(); return true; @@ -2249,17 +2774,15 @@ namespace LLInitParam } } - void setValue(value_assignment_t val) + void setValue(const value_t& val) { - derived_t& typed_param = static_cast(*this); // set param version number to be up to date, so we ignore block contents mValueAge = VALUE_AUTHORITATIVE; mValue = val; - typed_param.clearValueName(); static_cast(this)->updateBlockFromValue(false); } - value_assignment_t getValue() const + const value_t& getValue() const { validateBlock(true); return mValue; @@ -2271,20 +2794,10 @@ namespace LLInitParam return mValue; } - operator value_assignment_t() const - { - return getValue(); - } - - value_assignment_t operator()() const - { - return getValue(); - } - protected: // use this from within updateValueFromBlock() to set the value without making it authoritative - void updateValue(value_assignment_t value) + void updateValue(const value_t& value) { mValue = value; } @@ -2314,8 +2827,6 @@ namespace LLInitParam return block_t::mergeBlock(block_data, source, overwrite); } - mutable bool mValidated; // lazy validation flag - private: mutable T mValue; mutable EValueAge mValueAge; diff --git a/indra/llcommon/llinstancetracker.h b/indra/llcommon/llinstancetracker.h index 3c096abe12..50bf367d1f 100644 --- a/indra/llcommon/llinstancetracker.h +++ b/indra/llcommon/llinstancetracker.h @@ -28,12 +28,16 @@ #ifndef LL_LLINSTANCETRACKER_H #define LL_LLINSTANCETRACKER_H -#include +#include #include -#include "string_table.h" +#include "llstringtable.h" +#include "llerror.h" // llassert_always #include +#ifndef BOOST_FUNCTION_HPP_INCLUDED #include +#define BOOST_FUNCTION_HPP_INCLUDED +#endif #include #include #include @@ -85,8 +89,7 @@ template class LLInstanceTracker : public LLInstanceTrackerBase { typedef LLInstanceTracker MyT; - typedef typename std::map InstanceMap; - typedef typename InstanceMap::iterator::difference_type difference_type; + typedef typename boost::unordered_map InstanceMap; struct StaticData: public StaticBase { InstanceMap sMap; @@ -117,10 +120,6 @@ class LLInstanceTracker : public LLInstanceTrackerBase void increment() { mIterator++; } void decrement() { --mIterator; } - difference_type distance_to(instance_iter const& other) const - { - return std::distance(mIterator, other.mIterator); - } bool equal(instance_iter const& other) const { return mIterator == other.mIterator; @@ -162,10 +161,6 @@ class LLInstanceTracker : public LLInstanceTrackerBase void increment() { mIterator++; } void decrement() { --mIterator; } - difference_type distance_to(instance_iter const& other) const - { - return std::distance(mIterator, other.mIterator); - } bool equal(key_iter const& other) const { return mIterator == other.mIterator; diff --git a/indra/llcommon/llkeythrottle.h b/indra/llcommon/llkeythrottle.h index 7544ab1d11..3271a5e33c 100644 --- a/indra/llcommon/llkeythrottle.h +++ b/indra/llcommon/llkeythrottle.h @@ -88,7 +88,7 @@ class LLKeyThrottleImpl } static U64 getFrame() // Return the current frame number { - return (U64) LLFrameTimer::getFrameCount(); + return LLFrameTimer::getFrameCount(); } }; diff --git a/indra/llcommon/llliveappconfig.cpp b/indra/llcommon/llliveappconfig.cpp index 75bdfee8b7..ceea02267f 100644 --- a/indra/llcommon/llliveappconfig.cpp +++ b/indra/llcommon/llliveappconfig.cpp @@ -53,8 +53,8 @@ LLLiveAppConfig::~LLLiveAppConfig() // virtual bool LLLiveAppConfig::loadFile() { - llinfos << "LLLiveAppConfig::loadFile(): reading from " - << filename() << llendl; + LL_INFOS() << "LLLiveAppConfig::loadFile(): reading from " + << filename() << LL_ENDL; llifstream file(filename()); LLSD config; if (file.is_open()) @@ -62,15 +62,15 @@ bool LLLiveAppConfig::loadFile() LLSDSerialize::fromXML(config, file); if(!config.isMap()) { - llwarns << "Live app config not an map in " << filename() - << " Ignoring the data." << llendl; + LL_WARNS() << "Live app config not an map in " << filename() + << " Ignoring the data." << LL_ENDL; return false; } file.close(); } else { - llinfos << "Live file " << filename() << " does not exit." << llendl; + LL_INFOS() << "Live file " << filename() << " does not exit." << LL_ENDL; } // *NOTE: we do not handle the else case here because we would not // have attempted to load the file unless LLLiveFile had diff --git a/indra/llcommon/lllivefile.cpp b/indra/llcommon/lllivefile.cpp index ce6ac4fac4..88274a91c5 100644 --- a/indra/llcommon/lllivefile.cpp +++ b/indra/llcommon/lllivefile.cpp @@ -88,46 +88,51 @@ LLLiveFile::~LLLiveFile() bool LLLiveFile::Impl::check() { - if (!mForceCheck && mRefreshTimer.getElapsedTimeF32() < mRefreshPeriod) + bool detected_change = false; + // Skip the check if not enough time has elapsed and we're not + // forcing a check of the file + if (mForceCheck || mRefreshTimer.getElapsedTimeF32() >= mRefreshPeriod) { - // Skip the check if not enough time has elapsed and we're not - // forcing a check of the file - return false; - } - mForceCheck = false; - mRefreshTimer.reset(); - - // Stat the file to see if it exists and when it was last modified. - llstat stat_data; - int res = LLFile::stat(mFilename, &stat_data); - - if (res) - { - // Couldn't stat the file, that means it doesn't exist or is - // broken somehow. Clear flags and return. - if (mLastExists) - { - mLastExists = false; - return true; // no longer existing is a change! - } - return false; - } - - // The file exists, decide if we want to load it. - if (mLastExists) - { - // The file existed last time, don't read it if it hasn't changed since - // last time. - if (stat_data.st_mtime <= mLastModTime) - { - return false; - } - } - - // We want to read the file. Update status info for the file. - mLastExists = true; - mLastStatTime = stat_data.st_mtime; - return true; + mForceCheck = false; // force only forces one check + mRefreshTimer.reset(); // don't check again until mRefreshPeriod has passed + + // Stat the file to see if it exists and when it was last modified. + llstat stat_data; + if (LLFile::stat(mFilename, &stat_data)) + { + // Couldn't stat the file, that means it doesn't exist or is + // broken somehow. + if (mLastExists) + { + mLastExists = false; + detected_change = true; // no longer existing is a change! + LL_DEBUGS() << "detected deleted file '" << mFilename << "'" << LL_ENDL; + } + } + else + { + // The file exists + if ( ! mLastExists ) + { + // last check, it did not exist - that counts as a change + LL_DEBUGS() << "detected created file '" << mFilename << "'" << LL_ENDL; + detected_change = true; + } + else if ( stat_data.st_mtime > mLastModTime ) + { + // file modification time is newer than last check + LL_DEBUGS() << "detected updated file '" << mFilename << "'" << LL_ENDL; + detected_change = true; + } + mLastExists = true; + mLastStatTime = stat_data.st_mtime; + } + } + if (detected_change) + { + LL_INFOS() << "detected file change '" << mFilename << "'" << LL_ENDL; + } + return detected_change; } void LLLiveFile::Impl::changed() diff --git a/indra/llcommon/lllocalidhashmap.h b/indra/llcommon/lllocalidhashmap.h index a58ae2e7e4..0d22dd1aa4 100644 --- a/indra/llcommon/lllocalidhashmap.h +++ b/indra/llcommon/lllocalidhashmap.h @@ -250,11 +250,11 @@ void LLLocalIDHashMap::dumpIter() { if (mIters[i]) { - llinfos << i << " " << mIters[i]->mCurHashNodep << " " << mIters[i]->mCurHashNodeKey << llendl; + LL_INFOS() << i << " " << mIters[i]->mCurHashNodep << " " << mIters[i]->mCurHashNodeKey << LL_ENDL; } else { - llinfos << i << "null" << llendl; + LL_INFOS() << i << "null" << LL_ENDL; } } } @@ -701,7 +701,7 @@ void LLLocalIDHashMap::removeIter(LLLocalIDHashMapIter @@ -717,7 +717,7 @@ void LLLocalIDHashMap::addIter(LLLocalIDHashMapIter> 3) & 0x3F); + buffer_index = (unsigned int)((mCount[0] >> 3) & 0x3F); // Update number of bits - if ( (count[0] += ((uint4) input_length << 3))<((uint4) input_length << 3) ) - count[1]++; + if ( (mCount[0] += ((uint4) input_length << 3))<((uint4) input_length << 3) ) + mCount[1]++; - count[1] += ((uint4)input_length >> 29); + mCount[1] += ((uint4)input_length >> 29); buffer_space = 64 - buffer_index; // how much space is left in buffer + // now, transform each 64-byte piece of the input, bypassing the buffer + if (input == NULL || input_length == 0){ + std::cerr << "LLMD5::update: Invalid input!" << std::endl; + return; + } + // Transform as many times as possible. if (input_length >= buffer_space) { // ie. we have enough to fill the buffer // fill the rest of the buffer and transform memcpy( /* Flawfinder: ignore */ - buffer + buffer_index, + mBuffer + buffer_index, input, buffer_space); - transform (buffer); - - // now, transform each 64-byte piece of the input, bypassing the buffer - if (input == NULL || input_length == 0){ - std::cerr << "LLMD5::update: Invalid input!" << std::endl; - return; - } + transform (mBuffer); for (input_index = buffer_space; input_index + 63 < input_length; input_index += 64) @@ -145,7 +145,7 @@ void LLMD5::update (const uint1 *input, const uint4 input_length) { // and here we do the buffering: - memcpy(buffer+buffer_index, input+input_index, input_length-input_index); /* Flawfinder: ignore */ + memcpy(mBuffer+buffer_index, input+input_index, input_length-input_index); /* Flawfinder: ignore */ } @@ -200,16 +200,16 @@ void LLMD5::finalize (){ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - if (finalized){ + if (mFinalized){ std::cerr << "LLMD5::finalize: Already finalized this digest!" << std::endl; return; } // Save number of bits - encode (bits, count, 8); + encode (bits, mCount, 8); // Pad out to 56 mod 64. - index = (uint4) ((count[0] >> 3) & 0x3f); + index = (uint4) ((mCount[0] >> 3) & 0x3f); padLen = (index < 56) ? (56 - index) : (120 - index); update (PADDING, padLen); @@ -217,12 +217,12 @@ void LLMD5::finalize (){ update (bits, 8); // Store state in digest - encode (digest, state, 16); + encode (mDigest, mState, 16); // Zeroize sensitive information - memset (buffer, 0, sizeof(*buffer)); + memset (mBuffer, 0, sizeof(mBuffer)); - finalized=1; + mFinalized=true; } @@ -269,7 +269,7 @@ LLMD5::LLMD5(const unsigned char *s) void LLMD5::raw_digest(unsigned char *s) const { - if (!finalized) + if (!mFinalized) { std::cerr << "LLMD5::raw_digest: Can't get digest if you haven't "<< "finalized the digest!" << std::endl; @@ -277,17 +277,22 @@ void LLMD5::raw_digest(unsigned char *s) const return; } - memcpy(s, digest, 16); /* Flawfinder: ignore */ + memcpy(s, mDigest, 16); /* Flawfinder: ignore */ return; } - +//Singu extension: the inverse of LLMD5::raw_digest. +void LLMD5::clone(unsigned char const* s) +{ + memcpy(mDigest, s, 16); + mFinalized = true; +} void LLMD5::hex_digest(char *s) const { int i; - if (!finalized) + if (!mFinalized) { std::cerr << "LLMD5::hex_digest: Can't get digest if you haven't "<< "finalized the digest!" <= '0' && c <= '9') ? c - '0' : c - 'a' + 10; + byte += nibble << ((1 - j) << 2); + } + mDigest[i] = byte; + } + mFinalized = 1; +} - - -std::ostream& operator<<(std::ostream &stream, LLMD5 context) +std::ostream& operator<<(std::ostream &stream, LLMD5 const& context) { char s[33]; /* Flawfinder: ignore */ context.hex_digest(s); @@ -318,37 +337,20 @@ std::ostream& operator<<(std::ostream &stream, LLMD5 context) return stream; } -bool operator==(const LLMD5& a, const LLMD5& b) -{ - unsigned char a_guts[16]; - unsigned char b_guts[16]; - a.raw_digest(a_guts); - b.raw_digest(b_guts); - if (memcmp(a_guts,b_guts,16)==0) - return true; - else - return false; -} - -bool operator!=(const LLMD5& a, const LLMD5& b) -{ - return !(a==b); -} - // PRIVATE METHODS: void LLMD5::init(){ - finalized=0; // we just started! + mFinalized=false; // we just started! // Nothing counted, so count=0 - count[0] = 0; - count[1] = 0; + mCount[0] = 0; + mCount[1] = 0; // Load magic initialization constants. - state[0] = 0x67452301; - state[1] = 0xefcdab89; - state[2] = 0x98badcfe; - state[3] = 0x10325476; + mState[0] = 0x67452301; + mState[1] = 0xefcdab89; + mState[2] = 0x98badcfe; + mState[3] = 0x10325476; } @@ -417,11 +419,11 @@ Rotation is separate from addition to prevent recomputation. // LLMD5 basic transformation. Transforms state based on block. void LLMD5::transform (const U8 block[64]){ - uint4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; + uint4 a = mState[0], b = mState[1], c = mState[2], d = mState[3], x[16]; decode (x, block, 64); - assert(!finalized); // not just a user error, since the method is private + assert(!mFinalized); // not just a user error, since the method is private /* Round 1 */ FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ @@ -495,10 +497,10 @@ void LLMD5::transform (const U8 block[64]){ II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ - state[0] += a; - state[1] += b; - state[2] += c; - state[3] += d; + mState[0] += a; + mState[1] += b; + mState[2] += c; + mState[3] += d; // Zeroize sensitive information. memset ( (uint1 *) x, 0, sizeof(x)); diff --git a/indra/llcommon/llmd5.h b/indra/llcommon/llmd5.h index 8bf715f14e..30c1838c81 100644 --- a/indra/llcommon/llmd5.h +++ b/indra/llcommon/llmd5.h @@ -32,6 +32,10 @@ #ifndef LL_LLMD5_H #define LL_LLMD5_H +#include "llpreprocessor.h" +#include +#include // memcmp + // LLMD5.CC - source code for the C++/object oriented translation and // modification of MD5. @@ -98,28 +102,37 @@ class LL_COMMON_API LLMD5 { void update (const std::string& str); void finalize (); + bool isFinalized() const { return mFinalized; } + // constructors for special circumstances. All these constructors finalize // the MD5 context. LLMD5 (const unsigned char *string); // digest string, finalize LLMD5 (std::istream& stream); // digest stream, finalize LLMD5 (FILE *file); // digest file, close, finalize LLMD5 (const unsigned char *string, const unsigned int number); + + // Singu extension: set digest directly, finalize. + void clone(unsigned char const* digest); // Inverse of raw_digest. + void clone(std::string const& hash_str); // Inverse of hex_digest. // methods to acquire finalized result void raw_digest(unsigned char *array) const; // provide 16-byte array for binary data void hex_digest(char *string) const; // provide 33-byte array for ascii-hex string - friend LL_COMMON_API std::ostream& operator<< (std::ostream&, LLMD5 context); + friend LL_COMMON_API std::ostream& operator<< (std::ostream&, LLMD5 const& context); + friend LL_COMMON_API bool operator==(const LLMD5& a, const LLMD5& b) { return std::memcmp(a.mDigest ,b.mDigest, 16) == 0; } + friend LL_COMMON_API bool operator!=(const LLMD5& a, const LLMD5& b) { return std::memcmp(a.mDigest,b.mDigest, 16) != 0; } + friend LL_COMMON_API bool operator<(const LLMD5& a, const LLMD5& b) { return std::memcmp(a.mDigest,b.mDigest, 16) < 0; } private: // next, the private data: - uint4 state[4]; - uint4 count[2]; // number of *bits*, mod 2^64 - uint1 buffer[64]; // input buffer - uint1 digest[16]; - uint1 finalized; + uint4 mState[4]; + uint4 mCount[2]; // number of *bits*, mod 2^64 + uint1 mBuffer[64]; // input buffer + uint1 mDigest[16]; + bool mFinalized; // last, the private methods, mostly static: void init (); // called by all constructors @@ -131,7 +144,4 @@ class LL_COMMON_API LLMD5 { }; -LL_COMMON_API bool operator==(const LLMD5& a, const LLMD5& b); -LL_COMMON_API bool operator!=(const LLMD5& a, const LLMD5& b); - #endif // LL_LLMD5_H diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index 05809d20b5..1b73507a14 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -32,7 +32,7 @@ //#endif #if defined(LL_WINDOWS) -//# include +#include "llwin32headerslean.h" # include #elif defined(LL_DARWIN) # include @@ -50,28 +50,24 @@ //static char* LLMemory::reserveMem = 0; -U32 LLMemory::sAvailPhysicalMemInKB = U32_MAX ; -U32 LLMemory::sMaxPhysicalMemInKB = 0; -U32 LLMemory::sAllocatedMemInKB = 0; -U32 LLMemory::sAllocatedPageSizeInKB = 0 ; -U32 LLMemory::sMaxHeapSizeInKB = U32_MAX ; +U32Kilobytes LLMemory::sAvailPhysicalMemInKB(U32_MAX); +U32Kilobytes LLMemory::sMaxPhysicalMemInKB(0); +U32Kilobytes LLMemory::sAllocatedMemInKB(0); +U32Kilobytes LLMemory::sAllocatedPageSizeInKB(0); +U32Kilobytes LLMemory::sMaxHeapSizeInKB(U32_MAX); BOOL LLMemory::sEnableMemoryFailurePrevention = FALSE; #if __DEBUG_PRIVATE_MEM__ LLPrivateMemoryPoolManager::mem_allocation_info_t LLPrivateMemoryPoolManager::sMemAllocationTracker; #endif -void ll_assert_aligned_func(uintptr_t ptr,U32 alignment) -{ #ifdef SHOW_ASSERT +void singu_alignment_check_failed(void) +{ // Redundant, place to set breakpoints. - if (ptr%alignment!=0) - { - llwarns << "alignment check failed" << llendl; - } - llassert(ptr%alignment==0); -#endif + llassert(false); } +#endif //static void LLMemory::initClass() @@ -97,48 +93,56 @@ void LLMemory::freeReserve() } //static -void LLMemory::initMaxHeapSizeGB(F32 max_heap_size_gb, BOOL prevent_heap_failure) +void LLMemory::initMaxHeapSizeGB(F32Gigabytes max_heap_size, BOOL prevent_heap_failure) { - sMaxHeapSizeInKB = (U32)(max_heap_size_gb * 1024 * 1024) ; + sMaxHeapSizeInKB = max_heap_size; sEnableMemoryFailurePrevention = prevent_heap_failure ; } //static void LLMemory::updateMemoryInfo() { -#if LL_WINDOWS - HANDLE self = GetCurrentProcess(); - PROCESS_MEMORY_COUNTERS counters; - - if (!GetProcessMemoryInfo(self, &counters, sizeof(counters))) +#if LL_WINDOWS + PROCESS_MEMORY_COUNTERS_EX counters; + counters.cb = sizeof(counters); + + if (!GetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS*) &counters, sizeof(counters))) { - llwarns << "GetProcessMemoryInfo failed" << llendl; - return ; + LL_WARNS() << "GetProcessMemoryInfo failed" << LL_ENDL; + return; } - sAllocatedMemInKB = (U32)(counters.WorkingSetSize / 1024) ; - sAllocatedPageSizeInKB = (U32)(counters.PagefileUsage / 1024) ; - - U32 avail_phys, avail_virtual; - LLMemoryInfo::getAvailableMemoryKB(avail_phys, avail_virtual) ; - sMaxPhysicalMemInKB = llmin(avail_phys + sAllocatedMemInKB, sMaxHeapSizeInKB); + sAllocatedMemInKB = U64Bytes(counters.WorkingSetSize); + sAllocatedPageSizeInKB = (counters.PagefileUsage != 0) ? U64Bytes(counters.PagefileUsage) : U64Bytes(counters.PrivateUsage); - if(sMaxPhysicalMemInKB > sAllocatedMemInKB) + MEMORYSTATUSEX memorystat; + memorystat.dwLength = sizeof(memorystat); + if (!GlobalMemoryStatusEx(&memorystat)) { - sAvailPhysicalMemInKB = sMaxPhysicalMemInKB - sAllocatedMemInKB ; + LL_WARNS() << "GlobalMemoryStatusEx failed" << LL_ENDL; + return; + } +#if (defined(_WIN64) || defined(__amd64__) || defined(__x86_64__)) + sMaxPhysicalMemInKB = U64Bytes(memorystat.ullTotalPhys); + sAvailPhysicalMemInKB = U64Bytes(memorystat.ullAvailPhys); +#else + sMaxPhysicalMemInKB = llmin(U32Kilobytes(U64Bytes(memorystat.ullTotalPhys)), sMaxHeapSizeInKB); + if (sMaxPhysicalMemInKB > sAllocatedMemInKB) + { + sAvailPhysicalMemInKB = U64Bytes(memorystat.ullAvailPhys);; } else { - sAvailPhysicalMemInKB = 0 ; + sAvailPhysicalMemInKB = U32Kilobytes(0); } +#endif + #else //not valid for other systems for now. - sAllocatedMemInKB = (U32)(LLMemory::getCurrentRSS() / 1024) ; - sMaxPhysicalMemInKB = U32_MAX ; - sAvailPhysicalMemInKB = U32_MAX ; + sAllocatedMemInKB = U64Bytes(LLMemory::getCurrentRSS()); + sMaxPhysicalMemInKB = U64Bytes(U32_MAX); + sAvailPhysicalMemInKB = U64Bytes(U32_MAX); #endif - - return ; } // @@ -156,13 +160,13 @@ void* LLMemory::tryToAlloc(void* address, U32 size) { if(!VirtualFree(address, 0, MEM_RELEASE)) { - llerrs << "error happens when free some memory reservation." << llendl ; + LL_ERRS() << "error happens when free some memory reservation." << LL_ENDL ; } } return address ; #else return (void*)0x01 ; //skip checking -#endif +#endif } //static @@ -174,14 +178,14 @@ void LLMemory::logMemoryInfo(BOOL update) LLPrivateMemoryPoolManager::getInstance()->updateStatistics() ; } - llinfos << "Current allocated physical memory(KB): " << sAllocatedMemInKB << llendl ; - llinfos << "Current allocated page size (KB): " << sAllocatedPageSizeInKB << llendl ; - llinfos << "Current availabe physical memory(KB): " << sAvailPhysicalMemInKB << llendl ; - llinfos << "Current max usable memory(KB): " << sMaxPhysicalMemInKB << llendl ; + LL_INFOS() << "Current allocated physical memory(KB): " << sAllocatedMemInKB << LL_ENDL ; + LL_INFOS() << "Current allocated page size (KB): " << sAllocatedPageSizeInKB << LL_ENDL ; + LL_INFOS() << "Current available physical memory(KB): " << sAvailPhysicalMemInKB << LL_ENDL ; + LL_INFOS() << "Current max usable memory(KB): " << sMaxPhysicalMemInKB << LL_ENDL ; - llinfos << "--- private pool information -- " << llendl ; - llinfos << "Total reserved (KB): " << LLPrivateMemoryPoolManager::getInstance()->mTotalReservedSize / 1024 << llendl ; - llinfos << "Total allocated (KB): " << LLPrivateMemoryPoolManager::getInstance()->mTotalAllocatedSize / 1024 << llendl ; + LL_INFOS() << "--- private pool information -- " << LL_ENDL ; + LL_INFOS() << "Total reserved (KB): " << LLPrivateMemoryPoolManager::getInstance()->mTotalReservedSize / 1024 << LL_ENDL ; + LL_INFOS() << "Total allocated (KB): " << LLPrivateMemoryPoolManager::getInstance()->mTotalAllocatedSize / 1024 << LL_ENDL ; } //return 0: everything is normal; @@ -190,8 +194,8 @@ void LLMemory::logMemoryInfo(BOOL update) //static bool LLMemory::isMemoryPoolLow() { - static const U32 LOW_MEMEOY_POOL_THRESHOLD_KB = 64 * 1024 ; //64 MB for emergency use - const static U32 MAX_SIZE_CHECKED_MEMORY_BLOCK = 64 * 1024 * 1024 ; //64 MB + static const U32Megabytes LOW_MEMORY_POOL_THRESHOLD(64); + const static U32Megabytes MAX_SIZE_CHECKED_MEMORY_BLOCK(64); static void* last_reserved_address = NULL ; if(!sEnableMemoryFailurePrevention) @@ -199,32 +203,32 @@ bool LLMemory::isMemoryPoolLow() return false ; //no memory failure prevention. } - if(sAvailPhysicalMemInKB < (LOW_MEMEOY_POOL_THRESHOLD_KB >> 2)) //out of physical memory + if(sAvailPhysicalMemInKB < (LOW_MEMORY_POOL_THRESHOLD / 4)) //out of physical memory { return true ; } - if(sAllocatedPageSizeInKB + (LOW_MEMEOY_POOL_THRESHOLD_KB >> 2) > sMaxHeapSizeInKB) //out of virtual address space. + if(sAllocatedPageSizeInKB + (LOW_MEMORY_POOL_THRESHOLD / 4) > sMaxHeapSizeInKB) //out of virtual address space. { return true ; } - bool is_low = (S32)(sAvailPhysicalMemInKB < LOW_MEMEOY_POOL_THRESHOLD_KB || - sAllocatedPageSizeInKB + LOW_MEMEOY_POOL_THRESHOLD_KB > sMaxHeapSizeInKB) ; + bool is_low = (S32)(sAvailPhysicalMemInKB < LOW_MEMORY_POOL_THRESHOLD + || sAllocatedPageSizeInKB + LOW_MEMORY_POOL_THRESHOLD > sMaxHeapSizeInKB) ; //check the virtual address space fragmentation if(!is_low) { if(!last_reserved_address) { - last_reserved_address = LLMemory::tryToAlloc(last_reserved_address, MAX_SIZE_CHECKED_MEMORY_BLOCK) ; + last_reserved_address = LLMemory::tryToAlloc(last_reserved_address, MAX_SIZE_CHECKED_MEMORY_BLOCK.value()) ; } else { - last_reserved_address = LLMemory::tryToAlloc(last_reserved_address, MAX_SIZE_CHECKED_MEMORY_BLOCK) ; + last_reserved_address = LLMemory::tryToAlloc(last_reserved_address, MAX_SIZE_CHECKED_MEMORY_BLOCK.value()) ; if(!last_reserved_address) //failed, try once more { - last_reserved_address = LLMemory::tryToAlloc(last_reserved_address, MAX_SIZE_CHECKED_MEMORY_BLOCK) ; + last_reserved_address = LLMemory::tryToAlloc(last_reserved_address, MAX_SIZE_CHECKED_MEMORY_BLOCK.value()) ; } } @@ -235,73 +239,45 @@ bool LLMemory::isMemoryPoolLow() } //static -U32 LLMemory::getAvailableMemKB() +U32Kilobytes LLMemory::getAvailableMemKB() { - return sAvailPhysicalMemInKB ; + return sAvailPhysicalMemInKB; } //static -U32 LLMemory::getMaxMemKB() +U32Kilobytes LLMemory::getMaxMemKB() { - return sMaxPhysicalMemInKB ; + return sMaxPhysicalMemInKB; } //static -U32 LLMemory::getAllocatedMemKB() +U32Kilobytes LLMemory::getAllocatedMemKB() { - return sAllocatedMemInKB ; + return sAllocatedMemInKB; } //---------------------------------------------------------------------------- #if defined(LL_WINDOWS) +//static U64 LLMemory::getCurrentRSS() { - HANDLE self = GetCurrentProcess(); PROCESS_MEMORY_COUNTERS counters; - - if (!GetProcessMemoryInfo(self, &counters, sizeof(counters))) + + if (!GetProcessMemoryInfo(GetCurrentProcess(), &counters, sizeof(counters))) { - llwarns << "GetProcessMemoryInfo failed" << llendl; + LL_WARNS() << "GetProcessMemoryInfo failed" << LL_ENDL; return 0; } return counters.WorkingSetSize; } -//static -U32 LLMemory::getWorkingSetSize() -{ - PROCESS_MEMORY_COUNTERS pmc ; - U32 ret = 0 ; - - if (GetProcessMemoryInfo( GetCurrentProcess(), &pmc, sizeof(pmc)) ) - { - ret = pmc.WorkingSetSize ; - } - - return ret ; -} - #elif defined(LL_DARWIN) - -/* - The API used here is not capable of dealing with 64-bit memory sizes, but is available before 10.4. - - Once we start requiring 10.4, we can use the updated API, which looks like this: - - task_basic_info_64_data_t basicInfo; - mach_msg_type_number_t basicInfoCount = TASK_BASIC_INFO_64_COUNT; - if (task_info(mach_task_self(), TASK_BASIC_INFO_64, (task_info_t)&basicInfo, &basicInfoCount) == KERN_SUCCESS) - - Of course, this doesn't gain us anything unless we start building the viewer as a 64-bit executable, since that's the only way - for our memory allocation to exceed 2^32. -*/ - // if (sysctl(ctl, 2, &page_size, &size, NULL, 0) == -1) // { -// llwarns << "Couldn't get page size" << llendl; +// LL_WARNS() << "Couldn't get page size" << LL_ENDL; // return 0; // } else { // return page_size; @@ -311,30 +287,24 @@ U32 LLMemory::getWorkingSetSize() U64 LLMemory::getCurrentRSS() { U64 residentSize = 0; - task_basic_info_data_t basicInfo; - mach_msg_type_number_t basicInfoCount = TASK_BASIC_INFO_COUNT; - if (task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&basicInfo, &basicInfoCount) == KERN_SUCCESS) + mach_task_basic_info_data_t basicInfo; + mach_msg_type_number_t basicInfoCount = MACH_TASK_BASIC_INFO_COUNT; + if (task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&basicInfo, &basicInfoCount) == KERN_SUCCESS) { - residentSize = basicInfo.resident_size; - - // If we ever wanted it, the process virtual size is also available as: - // virtualSize = basicInfo.virtual_size; - -// llinfos << "resident size is " << residentSize << llendl; +// residentSize = basicInfo.resident_size; + // Although this method is defined to return the "resident set size," + // in fact what callers want from it is the total virtual memory + // consumed by the application. + residentSize = basicInfo.virtual_size; } else { - llwarns << "task_info failed" << llendl; + LL_WARNS() << "task_info failed" << LL_ENDL; } return residentSize; } -U32 LLMemory::getWorkingSetSize() -{ - return 0 ; -} - #elif defined(LL_LINUX) U64 LLMemory::getCurrentRSS() @@ -345,8 +315,8 @@ U64 LLMemory::getCurrentRSS() if (fp == NULL) { - llwarns << "couldn't open " << statPath << llendl; - goto bail; + LL_WARNS() << "couldn't open " << statPath << LL_ENDL; + return rss; } // Eee-yew! See Documentation/filesystems/proc.txt in your @@ -358,56 +328,15 @@ U64 LLMemory::getCurrentRSS() &rss); if (ret != 1) { - llwarns << "couldn't parse contents of " << statPath << llendl; + LL_WARNS() << "couldn't parse contents of " << statPath << LL_ENDL; rss = 0; } } fclose(fp); -bail: return rss; } - -U32 LLMemory::getWorkingSetSize() -{ - return 0 ; -} - -#elif LL_SOLARIS -#include -#include -#include -#define _STRUCTURED_PROC 1 -#include - -U64 LLMemory::getCurrentRSS() -{ - char path [LL_MAX_PATH]; /* Flawfinder: ignore */ - - sprintf(path, "/proc/%d/psinfo", (int)getpid()); - int proc_fd = -1; - if((proc_fd = open(path, O_RDONLY)) == -1){ - llwarns << "LLmemory::getCurrentRSS() unable to open " << path << ". Returning 0 RSS!" << llendl; - return 0; - } - psinfo_t proc_psinfo; - if(read(proc_fd, &proc_psinfo, sizeof(psinfo_t)) != sizeof(psinfo_t)){ - llwarns << "LLmemory::getCurrentRSS() Unable to read from " << path << ". Returning 0 RSS!" << llendl; - close(proc_fd); - return 0; - } - - close(proc_fd); - - return((U64)proc_psinfo.pr_rssize * 1024); -} - -U32 LLMemory::getWorkingSetSize() -{ - return 0 ; -} - #else U64 LLMemory::getCurrentRSS() @@ -415,11 +344,6 @@ U64 LLMemory::getCurrentRSS() return 0; } -U32 LLMemory::getWorkingSetSize() -{ - return 0; -} - #endif //-------------------------------------------------------------------------------------------------- @@ -431,7 +355,7 @@ LLMemTracker* LLMemTracker::sInstance = NULL ; LLMemTracker::LLMemTracker() { - mLastAllocatedMem = LLMemory::getWorkingSetSize() ; + mLastAllocatedMem = LLMemory::getCurrentRSS() ; mCapacity = 128 ; mCurIndex = 0 ; mCounter = 0 ; @@ -484,7 +408,7 @@ void LLMemTracker::track(const char* function, const int line) return ; } - U32 allocated_mem = LLMemory::getWorkingSetSize() ; + U64 allocated_mem = LLMemory::getCurrentRSS() ; LLMutexLock lock(mMutexp) ; @@ -961,7 +885,7 @@ void LLPrivateMemoryPool::LLMemoryChunk::dump() total_size += blk_list[i]->getBufferSize() ; if((U32)blk_list[i]->getBuffer() < (U32)blk_list[i-1]->getBuffer() + blk_list[i-1]->getBufferSize()) { - llerrs << "buffer corrupted." << llendl ; + LL_ERRS() << "buffer corrupted." << LL_ENDL ; } } @@ -982,32 +906,32 @@ void LLPrivateMemoryPool::LLMemoryChunk::dump() } else { - llerrs << "gap happens" << llendl ; + LL_ERRS() << "gap happens" << LL_ENDL ; } } #endif #if 0 - llinfos << "---------------------------" << llendl ; - llinfos << "Chunk buffer: " << (U32)getBuffer() << " size: " << getBufferSize() << llendl ; + LL_INFOS() << "---------------------------" << LL_ENDL ; + LL_INFOS() << "Chunk buffer: " << (U32)getBuffer() << " size: " << getBufferSize() << LL_ENDL ; - llinfos << "available blocks ... " << llendl ; + LL_INFOS() << "available blocks ... " << LL_ENDL ; for(S32 i = 0 ; i < mBlockLevels ; i++) { LLMemoryBlock* blk = mAvailBlockList[i] ; while(blk) { - llinfos << "blk buffer " << (U32)blk->getBuffer() << " size: " << blk->getBufferSize() << llendl ; + LL_INFOS() << "blk buffer " << (U32)blk->getBuffer() << " size: " << blk->getBufferSize() << LL_ENDL ; blk = blk->mNext ; } } - llinfos << "free blocks ... " << llendl ; + LL_INFOS() << "free blocks ... " << LL_ENDL ; for(S32 i = 0 ; i < mPartitionLevels ; i++) { LLMemoryBlock* blk = mFreeSpaceList[i] ; while(blk) { - llinfos << "blk buffer " << (U32)blk->getBuffer() << " size: " << blk->getBufferSize() << llendl ; + LL_INFOS() << "blk buffer " << (U32)blk->getBuffer() << " size: " << blk->getBufferSize() << LL_ENDL ; blk = blk->mNext ; } } @@ -1403,7 +1327,7 @@ char* LLPrivateMemoryPool::allocate(U32 size) if(to_log) { - llwarns << "The memory pool overflows, now using heap directly!" << llendl ; + LL_WARNS() << "The memory pool overflows, now using heap directly!" << LL_ENDL ; to_log = false ; } @@ -1496,7 +1420,7 @@ void LLPrivateMemoryPool::destroyPool() if(mNumOfChunks > 0) { - llwarns << "There is some memory not freed when destroy the memory pool!" << llendl ; + LL_WARNS() << "There is some memory not freed when destroy the memory pool!" << LL_ENDL ; } mNumOfChunks = 0 ; @@ -1514,11 +1438,11 @@ bool LLPrivateMemoryPool::checkSize(U32 asked_size) { if(mReservedPoolSize + asked_size > mMaxPoolSize) { - llinfos << "Max pool size: " << mMaxPoolSize << llendl ; - llinfos << "Total reserved size: " << mReservedPoolSize + asked_size << llendl ; - llinfos << "Total_allocated Size: " << getTotalAllocatedSize() << llendl ; + LL_INFOS() << "Max pool size: " << mMaxPoolSize << LL_ENDL ; + LL_INFOS() << "Total reserved size: " << mReservedPoolSize + asked_size << LL_ENDL ; + LL_INFOS() << "Total_allocated Size: " << getTotalAllocatedSize() << LL_ENDL ; - //llerrs << "The pool is overflowing..." << llendl ; + //LL_ERRS() << "The pool is overflowing..." << LL_ENDL ; return false ; } @@ -1731,7 +1655,7 @@ void LLPrivateMemoryPool::removeFromHashTable(LLMemoryChunk* chunk) void LLPrivateMemoryPool::rehash() { - llinfos << "new hash factor: " << mHashFactor << llendl ; + LL_INFOS() << "new hash factor: " << mHashFactor << LL_ENDL ; mChunkHashList.clear() ; mChunkHashList.resize(mHashFactor) ; @@ -1811,7 +1735,7 @@ void LLPrivateMemoryPool::LLChunkHashElement::remove(LLPrivateMemoryPool::LLMemo } else { - llerrs << "This slot does not contain this chunk!" << llendl ; + LL_ERRS() << "This slot does not contain this chunk!" << LL_ENDL ; } } @@ -1843,12 +1767,12 @@ LLPrivateMemoryPoolManager::~LLPrivateMemoryPoolManager() #if __DEBUG_PRIVATE_MEM__ if(!sMemAllocationTracker.empty()) { - llwarns << "there is potential memory leaking here. The list of not freed memory blocks are from: " <first << " : " << iter->second << llendl ; + LL_INFOS() << k++ << ", " << (U32)iter->first << " : " << iter->second << LL_ENDL ; } sMemAllocationTracker.clear() ; } @@ -2044,7 +1968,7 @@ void LLPrivateMemoryPoolManager::freeMem(LLPrivateMemoryPool* poolp, void* addr } else { - llerrs << "private pool is used before initialized.!" << llendl ; + LL_ERRS() << "private pool is used before initialized.!" << LL_ENDL ; } } } @@ -2118,7 +2042,7 @@ void LLPrivateMemoryPoolTester::test(U32 min_size, U32 max_size, U32 stride, U32 //allocate space for p ; if(!(p = ::new char**[times]) || !(*p = ::new char*[times * levels])) { - llerrs << "memory initialization for p failed" << llendl ; + LL_ERRS() << "memory initialization for p failed" << LL_ENDL ; } //init @@ -2190,8 +2114,8 @@ void LLPrivateMemoryPoolTester::testAndTime(U32 size, U32 times) { LLTimer timer ; - llinfos << " -**********************- " << llendl ; - llinfos << "test size: " << size << " test times: " << times << llendl ; + LL_INFOS() << " -**********************- " << LL_ENDL ; + LL_INFOS() << "test size: " << size << " test times: " << times << LL_ENDL ; timer.reset() ; char** p = new char*[times] ; @@ -2203,7 +2127,7 @@ void LLPrivateMemoryPoolTester::testAndTime(U32 size, U32 times) p[i] = ALLOCATE_MEM(sPool, size) ; if(!p[i]) { - llerrs << "allocation failed" << llendl ; + LL_ERRS() << "allocation failed" << LL_ENDL ; } } //de-allocation @@ -2212,7 +2136,7 @@ void LLPrivateMemoryPoolTester::testAndTime(U32 size, U32 times) FREE_MEM(sPool, p[i]) ; p[i] = NULL ; } - llinfos << "time spent using customized memory pool: " << timer.getElapsedTimeF32() << llendl ; + LL_INFOS() << "time spent using customized memory pool: " << timer.getElapsedTimeF32() << LL_ENDL ; timer.reset() ; @@ -2223,7 +2147,7 @@ void LLPrivateMemoryPoolTester::testAndTime(U32 size, U32 times) p[i] = ::new char[size] ; if(!p[i]) { - llerrs << "allocation failed" << llendl ; + LL_ERRS() << "allocation failed" << LL_ENDL ; } } //de-allocation @@ -2232,7 +2156,7 @@ void LLPrivateMemoryPoolTester::testAndTime(U32 size, U32 times) ::delete[] p[i] ; p[i] = NULL ; } - llinfos << "time spent using standard allocator/de-allocator: " << timer.getElapsedTimeF32() << llendl ; + LL_INFOS() << "time spent using standard allocator/de-allocator: " << timer.getElapsedTimeF32() << LL_ENDL ; delete[] p; } diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h index 0762dc3f4c..18af01f65c 100644 --- a/indra/llcommon/llmemory.h +++ b/indra/llcommon/llmemory.h @@ -27,7 +27,8 @@ #define LLMEMORY_H #include "linden_common.h" - +#include "llunits.h" +#include "stdtypes.h" #include #include #if !LL_WINDOWS @@ -42,27 +43,130 @@ class LLMutex ; #define LL_CHECK_MEMORY #endif -inline void* ll_aligned_malloc( size_t size, int align ) -{ - void* mem = malloc( size + (align - 1) + sizeof(void*) ); - char* aligned = ((char*)mem) + sizeof(void*); - aligned += align - ((uintptr_t)aligned & (align - 1)); - ((void**)aligned)[-1] = mem; - return aligned; +#if LL_WINDOWS +#define LL_ALIGN_OF __alignof +#else +#define LL_ALIGN_OF __align_of__ +#endif + +#if LL_WINDOWS +#define LL_DEFAULT_HEAP_ALIGN 8 +#elif LL_DARWIN +#define LL_DEFAULT_HEAP_ALIGN 16 +#elif LL_LINUX +#define LL_DEFAULT_HEAP_ALIGN 8 +#endif + +// +// ll_assert_aligned seems to only exist to set breakpoints in case an alignment check fails. +// However, the implementation was horrible: the test was done using a integer modulo after +// calling a function; which is like 500 times slower then the below. That turned out to be +// significant compared to CPU cycles used to do vector calculations in side of which this test +// is used. +// +// This implementation uses a faster, inlined test, and then still calls a function when +// that fails to set a break point there if needed. +// +// This uses the fact that 'alignment' is literal int (aka, '16' or '64') that is a power of two. +// As a result, the modulo is converted by the compiler to a logical AND with alignment-1, what +// it cannot do if you don't inline the test. +#ifdef SHOW_ASSERT +LL_COMMON_API void singu_alignment_check_failed(void); + +#define ll_assert_aligned(ptr,alignment) \ + do \ + { \ + if (LL_UNLIKELY(reinterpret_cast(ptr) % alignment)) \ + { \ + singu_alignment_check_failed(); \ + } \ + } \ + while(0) +// +#else +#define ll_assert_aligned(ptr,alignment) +#endif + +#include + +template T* LL_NEXT_ALIGNED_ADDRESS(T* address) +{ + return reinterpret_cast( + (reinterpret_cast(address) + 0xF) & ~0xF); } -inline void ll_aligned_free( void* ptr ) -{ - free( ((void**)ptr)[-1] ); +template T* LL_NEXT_ALIGNED_ADDRESS_64(T* address) +{ + return reinterpret_cast( + (reinterpret_cast(address) + 0x3F) & ~0x3F); } +#if LL_LINUX || LL_DARWIN + +#define LL_ALIGN_PREFIX(x) +#define LL_ALIGN_POSTFIX(x) __attribute__((aligned(x))) + +#elif LL_WINDOWS + +#define LL_ALIGN_PREFIX(x) __declspec(align(x)) +#define LL_ALIGN_POSTFIX(x) + +#else +#error "LL_ALIGN_PREFIX and LL_ALIGN_POSTFIX undefined" +#endif + +#define LL_ALIGN_16(var) LL_ALIGN_PREFIX(16) var LL_ALIGN_POSTFIX(16) + +//------------------------------------------------------------------------------------------------ +//------------------------------------------------------------------------------------------------ + // for enable buffer overrun detection predefine LL_DEBUG_BUFFER_OVERRUN in current library + // change preprocessor code to: #if 1 && defined(LL_WINDOWS) + +#if 0 && defined(LL_WINDOWS) + void* ll_aligned_malloc_fallback( size_t size, int align ); + void ll_aligned_free_fallback( void* ptr ); +//------------------------------------------------------------------------------------------------ +#else + inline void* ll_aligned_malloc_fallback( size_t size, int align ) + { + #if defined(LL_WINDOWS) + return _aligned_malloc(size, align); + #else + char* aligned = NULL; + void* mem = malloc( size + (align - 1) + sizeof(void*) ); + if (mem) + { + aligned = ((char*)mem) + sizeof(void*); + aligned += align - ((uintptr_t)aligned & (align - 1)); + + ((void**)aligned)[-1] = mem; + } + return aligned; + #endif + } + + inline void ll_aligned_free_fallback( void* ptr ) + { + #if defined(LL_WINDOWS) + _aligned_free(ptr); + #else + if (ptr) + { + free( ((void**)ptr)[-1] ); + } + #endif + } +#endif +//------------------------------------------------------------------------------------------------ + +#if !LL_USE_TCMALLOC inline void* ll_aligned_malloc_16(size_t size) // returned hunk MUST be freed with ll_aligned_free_16(). { -#if (LL_DARWIN || LL_USE_TCMALLOC) - return malloc(size); // default osx malloc is 16 byte aligned. -#elif LL_WINDOWS +#if defined(LL_WINDOWS) return _aligned_malloc(size, 16); +#elif defined(LL_DARWIN) + return malloc(size); // default osx malloc is 16 byte aligned. #else void *rtn; if (LL_LIKELY(0 == posix_memalign(&rtn, 16, size))) @@ -74,10 +178,10 @@ inline void* ll_aligned_malloc_16(size_t size) // returned hunk MUST be freed wi inline void ll_aligned_free_16(void *p) { -#if (LL_DARWIN || LL_USE_TCMALLOC) - free(p); -#elif LL_WINDOWS +#if defined(LL_WINDOWS) _aligned_free(p); +#elif defined(LL_DARWIN) + return free(p); #else free(p); // posix_memalign() is compatible with heap deallocator #endif @@ -85,10 +189,10 @@ inline void ll_aligned_free_16(void *p) inline void* ll_aligned_realloc_16(void* ptr, size_t size, size_t old_size) // returned hunk MUST be freed with ll_aligned_free_16(). { -#if (LL_DARWIN || LL_USE_TCMALLOC) - return realloc(ptr,size); // default osx malloc is 16 byte aligned. -#elif LL_WINDOWS +#if defined(LL_WINDOWS) return _aligned_realloc(ptr, size, 16); +#elif defined(LL_DARWIN) + return realloc(ptr,size); // default osx malloc is 16 byte aligned. #else //FIXME: memcpy is SLOW void* ret = ll_aligned_malloc_16(size); @@ -105,12 +209,19 @@ inline void* ll_aligned_realloc_16(void* ptr, size_t size, size_t old_size) // r #endif } +#else // USE_TCMALLOC +// ll_aligned_foo_16 are not needed with tcmalloc +#define ll_aligned_malloc_16 ::malloc +#define ll_aligned_realloc_16(a,b,c) ::realloc(a,b) +#define ll_aligned_free_16 ::free +#endif // USE_TCMALLOC + inline void* ll_aligned_malloc_32(size_t size) // returned hunk MUST be freed with ll_aligned_free_32(). { -#if LL_WINDOWS +#if defined(LL_WINDOWS) return _aligned_malloc(size, 32); -#elif LL_DARWIN - return ll_aligned_malloc( size, 32 ); +#elif defined(LL_DARWIN) + return ll_aligned_malloc_fallback( size, 32 ); #else void *rtn; if (LL_LIKELY(0 == posix_memalign(&rtn, 32, size))) @@ -122,15 +233,129 @@ inline void* ll_aligned_malloc_32(size_t size) // returned hunk MUST be freed wi inline void ll_aligned_free_32(void *p) { -#if LL_WINDOWS +#if defined(LL_WINDOWS) _aligned_free(p); -#elif LL_DARWIN - ll_aligned_free( p ); +#elif defined(LL_DARWIN) + ll_aligned_free_fallback( p ); #else free(p); // posix_memalign() is compatible with heap deallocator #endif } +// general purpose dispatch functions that are forced inline so they can compile down to a single call +template +LL_FORCE_INLINE void* ll_aligned_malloc(size_t size) +{ + if (LL_DEFAULT_HEAP_ALIGN % ALIGNMENT == 0) + { + return malloc(size); + } + else if (ALIGNMENT == 16) + { + return ll_aligned_malloc_16(size); + } + else if (ALIGNMENT == 32) + { + return ll_aligned_malloc_32(size); + } + else + { + return ll_aligned_malloc_fallback(size, ALIGNMENT); + } +} + +template +LL_FORCE_INLINE void ll_aligned_free(void* ptr) +{ + if (ALIGNMENT == LL_DEFAULT_HEAP_ALIGN) + { + free(ptr); + } + else if (ALIGNMENT == 16) + { + ll_aligned_free_16(ptr); + } + else if (ALIGNMENT == 32) + { + return ll_aligned_free_32(ptr); + } + else + { + return ll_aligned_free_fallback(ptr); + } +} + +// Copy words 16-byte blocks from src to dst. Source and destination MUST NOT OVERLAP. +// Source and dest must be 16-byte aligned and size must be multiple of 16. +// +inline void ll_memcpy_nonaliased_aligned_16(char* __restrict dst, const char* __restrict src, size_t bytes) +{ + assert(src != NULL); + assert(dst != NULL); + assert(bytes > 0); + assert((bytes % sizeof(F32))== 0); + ll_assert_aligned(src,16); + ll_assert_aligned(dst,16); + assert((src < dst) ? ((src + bytes) <= dst) : ((dst + bytes) <= src)); + assert(bytes%16==0); + + char* end = dst + bytes; + + if (bytes > 64) + { + + // Find start of 64b aligned area within block + // + void* begin_64 = LL_NEXT_ALIGNED_ADDRESS_64(dst); + + //at least 64 bytes before the end of the destination, switch to 16 byte copies + void* end_64 = end-64; + + // Prefetch the head of the 64b area now + // + _mm_prefetch((char*)begin_64, _MM_HINT_NTA); + _mm_prefetch((char*)begin_64 + 64, _MM_HINT_NTA); + _mm_prefetch((char*)begin_64 + 128, _MM_HINT_NTA); + _mm_prefetch((char*)begin_64 + 192, _MM_HINT_NTA); + + // Copy 16b chunks until we're 64b aligned + // + while (dst < begin_64) + { + + _mm_store_ps((F32*)dst, _mm_load_ps((F32*)src)); + dst += 16; + src += 16; + } + + // Copy 64b chunks up to your tail + // + // might be good to shmoo the 512b prefetch offset + // (characterize performance for various values) + // + while (dst < end_64) + { + _mm_prefetch((char*)src + 512, _MM_HINT_NTA); + _mm_prefetch((char*)dst + 512, _MM_HINT_NTA); + _mm_store_ps((F32*)dst, _mm_load_ps((F32*)src)); + _mm_store_ps((F32*)(dst + 16), _mm_load_ps((F32*)(src + 16))); + _mm_store_ps((F32*)(dst + 32), _mm_load_ps((F32*)(src + 32))); + _mm_store_ps((F32*)(dst + 48), _mm_load_ps((F32*)(src + 48))); + dst += 64; + src += 64; + } + } + + // Copy remainder 16b tail chunks (or ALL 16b chunks for sub-64b copies) + // + while (dst < end) + { + _mm_store_ps((F32*)dst, _mm_load_ps((F32*)src)); + dst += 16; + src += 16; + } +} + #ifndef __DEBUG_PRIVATE_MEM__ #define __DEBUG_PRIVATE_MEM__ 0 #endif @@ -144,24 +369,23 @@ class LL_COMMON_API LLMemory // Return the resident set size of the current process, in bytes. // Return value is zero if not known. static U64 getCurrentRSS(); - static U32 getWorkingSetSize(); static void* tryToAlloc(void* address, U32 size); - static void initMaxHeapSizeGB(F32 max_heap_size_gb, BOOL prevent_heap_failure); + static void initMaxHeapSizeGB(F32Gigabytes max_heap_size, BOOL prevent_heap_failure); static void updateMemoryInfo() ; static void logMemoryInfo(BOOL update = FALSE); static bool isMemoryPoolLow(); - static U32 getAvailableMemKB() ; - static U32 getMaxMemKB() ; - static U32 getAllocatedMemKB() ; + static U32Kilobytes getAvailableMemKB() ; + static U32Kilobytes getMaxMemKB() ; + static U32Kilobytes getAllocatedMemKB() ; private: static char* reserveMem; - static U32 sAvailPhysicalMemInKB ; - static U32 sMaxPhysicalMemInKB ; - static U32 sAllocatedMemInKB; - static U32 sAllocatedPageSizeInKB ; + static U32Kilobytes sAvailPhysicalMemInKB ; + static U32Kilobytes sMaxPhysicalMemInKB ; + static U32Kilobytes sAllocatedMemInKB; + static U32Kilobytes sAllocatedPageSizeInKB ; - static U32 sMaxHeapSizeInKB; + static U32Kilobytes sMaxHeapSizeInKB; static BOOL sEnableMemoryFailurePrevention; }; @@ -534,14 +758,6 @@ void LLPrivateMemoryPoolTester::operator delete[](void* addr) #endif #endif -LL_COMMON_API void ll_assert_aligned_func(uintptr_t ptr,U32 alignment); - -#ifdef SHOW_ASSERT -#define ll_assert_aligned(ptr,alignment) ll_assert_aligned_func(reinterpret_cast(ptr),((U32)alignment)) -#else -#define ll_assert_aligned(ptr,alignment) -#endif - //EVENTUALLY REMOVE THESE: #include "llpointer.h" #include "llsingleton.h" diff --git a/indra/llcommon/llmemorystream.cpp b/indra/llcommon/llmemorystream.cpp index 5c01c955ae..9ba926db76 100644 --- a/indra/llcommon/llmemorystream.cpp +++ b/indra/llcommon/llmemorystream.cpp @@ -51,7 +51,7 @@ void LLMemoryStreamBuf::reset(const U8* start, S32 length) int LLMemoryStreamBuf::underflow() { - //lldebugs << "LLMemoryStreamBuf::underflow()" << llendl; + //LL_DEBUGS() << "LLMemoryStreamBuf::underflow()" << LL_ENDL; if(gptr() < egptr()) { return *gptr(); diff --git a/indra/llcommon/llmetrics.cpp b/indra/llcommon/llmetrics.cpp index 30e5d435ae..3d0982efc3 100644 --- a/indra/llcommon/llmetrics.cpp +++ b/indra/llcommon/llmetrics.cpp @@ -71,7 +71,7 @@ void LLMetricsImpl::recordEventDetails(const std::string& location, metrics["location"] = location; metrics["stats"] = stats; - llinfos << "LLMETRICS: " << (LLSDNotationStreamer(metrics)) << llendl; + LL_INFOS() << "LLMETRICS: " << (LLSDNotationStreamer(metrics)) << LL_ENDL; } // Store this: @@ -134,7 +134,7 @@ void LLMetricsImpl::printTotals(LLSD metadata) out_sd["stats"] = stats; - llinfos << "LLMETRICS: AGGREGATE: " << LLSDOStreamer(out_sd) << llendl; + LL_INFOS() << "LLMETRICS: AGGREGATE: " << LLSDOStreamer(out_sd) << LL_ENDL; } LLMetrics::LLMetrics() diff --git a/indra/llcommon/llmortician.h b/indra/llcommon/llmortician.h index 59d2841825..074e38fe4c 100644 --- a/indra/llcommon/llmortician.h +++ b/indra/llcommon/llmortician.h @@ -34,6 +34,7 @@ #define LLMORTICIAN_H #include "stdtypes.h" +#include class LL_COMMON_API LLMortician { diff --git a/indra/llcommon/llnametable.h b/indra/llcommon/llnametable.h index 335a191be3..6d36405268 100644 --- a/indra/llcommon/llnametable.h +++ b/indra/llcommon/llnametable.h @@ -35,7 +35,7 @@ #include -#include "string_table.h" +#include "llstringtable.h" template class LLNameTable diff --git a/indra/llcommon/llpointer.h b/indra/llcommon/llpointer.h index affa040602..6e08b01ccd 100644 --- a/indra/llcommon/llpointer.h +++ b/indra/llcommon/llpointer.h @@ -97,6 +97,126 @@ template class LLPointer LLPointer& operator =(Type* ptr) { + assign(ptr); + return *this; + } + + LLPointer& operator =(const LLPointer& ptr) + { + assign(ptr); + return *this; + } + + // support assignment up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. + template + LLPointer& operator =(const LLPointer& ptr) + { + assign(ptr.get()); + return *this; + } + + // Just exchange the pointers, which will not change the reference counts. + static void swap(LLPointer& a, LLPointer& b) + { + Type* temp = a.mPointer; + a.mPointer = b.mPointer; + b.mPointer = temp; + } + +protected: +#ifdef LL_LIBRARY_INCLUDE + void ref(); + void unref(); +#else + + void assign(const LLPointer& ptr) + { + if( mPointer != ptr.mPointer ) + { + unref(); + mPointer = ptr.mPointer; + ref(); + } + } + void ref() + { + if (mPointer) + { + mPointer->ref(); + } + } + + void unref() + { + if (mPointer) + { + Type *temp = mPointer; + mPointer = NULL; + temp->unref(); + if (mPointer != NULL) + { + LL_WARNS() << "Unreference did assignment to non-NULL because of destructor" << LL_ENDL; + unref(); + } + } + } +#endif +protected: + Type* mPointer; +}; + +template class LLConstPointer +{ +public: + LLConstPointer() : + mPointer(NULL) + { + } + + LLConstPointer(const Type* ptr) : + mPointer(ptr) + { + ref(); + } + + LLConstPointer(const LLConstPointer& ptr) : + mPointer(ptr.mPointer) + { + ref(); + } + + // support conversion up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. + template + LLConstPointer(const LLConstPointer& ptr) : + mPointer(ptr.get()) + { + ref(); + } + + ~LLConstPointer() + { + unref(); + } + + const Type* get() const { return mPointer; } + const Type* operator->() const { return mPointer; } + const Type& operator*() const { return *mPointer; } + + operator BOOL() const { return (mPointer != 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); } + + LLConstPointer& operator =(const Type* ptr) + { if( mPointer != ptr ) { unref(); @@ -107,7 +227,7 @@ template class LLPointer return *this; } - LLPointer& operator =(const LLPointer& ptr) + LLConstPointer& operator =(const LLConstPointer& ptr) { if( mPointer != ptr.mPointer ) { @@ -120,7 +240,7 @@ template class LLPointer // support assignment up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. template - LLPointer& operator =(const LLPointer& ptr) + LLConstPointer& operator =(const LLConstPointer& ptr) { if( mPointer != ptr.get() ) { @@ -132,14 +252,18 @@ template class LLPointer } // Just exchange the pointers, which will not change the reference counts. - static void swap(LLPointer& a, LLPointer& b) + static void swap(LLConstPointer& a, LLConstPointer& b) { - Type* temp = a.mPointer; + const Type* temp = a.mPointer; a.mPointer = b.mPointer; b.mPointer = temp; } protected: +#ifdef LL_LIBRARY_INCLUDE + void ref(); + void unref(); +#else void ref() { if (mPointer) @@ -152,19 +276,67 @@ template class LLPointer { if (mPointer) { - Type *tempp = mPointer; + const Type *tempp = mPointer; mPointer = NULL; tempp->unref(); if (mPointer != NULL) { - llwarns << "Unreference did assignment to non-NULL because of destructor" << llendl; + LL_WARNS() << "Unreference did assignment to non-NULL because of destructor" << LL_ENDL; unref(); } } } - +#endif protected: - Type* mPointer; + const Type* mPointer; +}; + +template +class LLCopyOnWritePointer : public LLPointer +{ +public: + typedef LLCopyOnWritePointer self_t; + typedef LLPointer pointer_t; + + LLCopyOnWritePointer() + : mStayUnique(false) + {} + + LLCopyOnWritePointer(Type* ptr) + : LLPointer(ptr), + mStayUnique(false) + {} + + LLCopyOnWritePointer(LLPointer& ptr) + : LLPointer(ptr), + mStayUnique(false) + { + if (ptr.mForceUnique) + { + makeUnique(); + } + } + + Type* write() + { + makeUnique(); + return pointer_t::mPointer; + } + + void makeUnique() + { + if (pointer_t::notNull() && pointer_t::mPointer->getNumRefs() > 1) + { + *(pointer_t* )(this) = new Type(*pointer_t::mPointer); + } + } + + const Type* operator->() const { return pointer_t::mPointer; } + const Type& operator*() const { return *pointer_t::mPointer; } + + void setStayUnique(bool stay) { makeUnique(); mStayUnique = stay; } +private: + bool mStayUnique; }; #endif diff --git a/indra/llcommon/llpredicate.cpp b/indra/llcommon/llpredicate.cpp new file mode 100644 index 0000000000..1278948e24 --- /dev/null +++ b/indra/llcommon/llpredicate.cpp @@ -0,0 +1,41 @@ +/** + * @file llpredicate.cpp + * @brief abstraction for filtering objects by predicates, with arbitrary boolean expressions + * + * $LicenseInfo:firstyear=2008&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ +#include "linden_common.h" + +#include "llpredicate.h" + +namespace LLPredicate +{ + const U32 cPredicateFlagsFromEnum[5] = + { + 0xAAAAaaaa, // 10101010101010101010101010101010 + 0xCCCCcccc, // 11001100110011001100110011001100 + 0xF0F0F0F0, // 11110000111100001111000011110000 + 0xFF00FF00, // 11111111000000001111111100000000 + 0xFFFF0000 // 11111111111111110000000000000000 + }; +} + diff --git a/indra/llcommon/llpredicate.h b/indra/llcommon/llpredicate.h new file mode 100644 index 0000000000..a8300fc9b6 --- /dev/null +++ b/indra/llcommon/llpredicate.h @@ -0,0 +1,210 @@ +/** + * @file llpredicate.h + * @brief abstraction for filtering objects by predicates, with arbitrary boolean expressions + * + * $LicenseInfo:firstyear=2008&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLPREDICATE_H +#define LL_LLPREDICATE_H + +#include "llerror.h" + +namespace LLPredicate +{ + template class Rule; + + extern LL_COMMON_API const U32 cPredicateFlagsFromEnum[5]; + + template + class Value + { + public: + typedef U32 predicate_flag_t; + static const S32 cMaxEnum = 5; + + Value(ENUM e, bool predicate_value = true) + : mPredicateFlags(predicate_value ? cPredicateFlagsFromEnum[e] : ~cPredicateFlagsFromEnum[e]) + { + llassert(0 <= e && e < cMaxEnum); + } + + Value() + : mPredicateFlags(0xFFFFffff) + {} + + Value operator!() const + { + Value new_value; + new_value.mPredicateFlags = ~mPredicateFlags; + return new_value; + } + + Value operator &&(const Value other) const + { + Value new_value; + new_value.mPredicateFlags = mPredicateFlags & other.mPredicateFlags; + return new_value; + } + + Value operator ||(const Value other) const + { + Value new_value; + new_value.mPredicateFlags = mPredicateFlags | other.mPredicateFlags; + return new_value; + } + + void set(ENUM e, bool value = true) + { + llassert(0 <= e && e < cMaxEnum); + predicate_flag_t flags_to_modify; + predicate_flag_t mask = cPredicateFlagsFromEnum[e]; + if (value) + { // add predicate "e" to flags that don't contain it already + flags_to_modify = (mPredicateFlags & ~mask); + // clear flags not containing e + mPredicateFlags &= mask; + // add back flags shifted to contain e + mPredicateFlags |= flags_to_modify << (0x1 << e); + } + else + { // remove predicate "e" from flags that contain it + flags_to_modify = (mPredicateFlags & mask); + // clear flags containing e + mPredicateFlags &= ~mask; + // add back flags shifted to not contain e + mPredicateFlags |= flags_to_modify >> (0x1 << e); + } + } + + void forget(ENUM e) + { + set(e, true); + U32 flags_with_predicate = mPredicateFlags; + set(e, false); + // ambiguous value is result of adding and removing predicate at the same time! + mPredicateFlags |= flags_with_predicate; + } + + bool allSet() const + { + return mPredicateFlags == ~0; + } + + bool noneSet() const + { + return mPredicateFlags == 0; + } + + bool someSet() const + { + return mPredicateFlags != 0; + } + + private: + predicate_flag_t mPredicateFlags; + }; + + template + class Rule + { + public: + Rule(ENUM value) + : mRule(value) + {} + + Rule(const Value other) + : mRule(other) + {} + + Rule() + {} + + void require(ENUM e, bool match) + { + mRule.set(e, match); + } + + void allow(ENUM e) + { + mRule.forget(e); + } + + bool check(const Value value) const + { + return (mRule && value).someSet(); + } + + bool requires(const Value value) const + { + return (mRule && value).someSet() && (!mRule && value).noneSet(); + } + + bool isAmbivalent(const Value value) const + { + return (mRule && value).someSet() && (!mRule && value).someSet(); + } + + bool acceptsAll() const + { + return mRule.allSet(); + } + + bool acceptsNone() const + { + return mRule.noneSet(); + } + + Rule operator!() const + { + Rule new_rule; + new_rule.mRule = !mRule; + return new_rule; + } + + Rule operator &&(const Rule other) const + { + Rule new_rule; + new_rule.mRule = mRule && other.mRule; + return new_rule; + } + + Rule operator ||(const Rule other) const + { + Rule new_rule; + new_rule.mRule = mRule || other.mRule; + return new_rule; + } + + private: + Value mRule; + }; +} + +template +LLPredicate::Value ll_make_predicate(ENUM e, bool predicate_value = true) +{ + return LLPredicate::Value(e, predicate_value); +} + + +#endif // LL_LLPREDICATE_H diff --git a/indra/llcommon/llpreprocessor.h b/indra/llcommon/llpreprocessor.h index a6f5f9fa9e..b299fd829f 100644 --- a/indra/llcommon/llpreprocessor.h +++ b/indra/llcommon/llpreprocessor.h @@ -80,8 +80,8 @@ #define LL_CLANG 1 #endif #elif defined (__ICC) - #ifndef LL_ICC - #define LL_ICC 1 + #ifndef LL_INTELC + #define LL_INTELC 1 #endif #elif defined(__GNUC__) #define GCC_VERSION (__GNUC__ * 10000 \ @@ -94,9 +94,6 @@ #ifndef LL_MSVC #define LL_MSVC 1 #endif - #if _MSC_VER < 1400 - #define LL_MSVC7 //Visual C++ 2003 or earlier - #endif #endif // Deal with minor differences on Unixy OSes. @@ -112,6 +109,16 @@ #endif +// Require C++11 support +#if __cplusplus < 201100L && _MSC_VER < 1800 +#error C++11 support is required to build this project. +#endif + +#if LL_WINDOWS +# define LL_THREAD_LOCAL __declspec(thread) +#else +# define LL_THREAD_LOCAL __thread +#endif // Static linking with apr on windows needs to be declared. #if LL_WINDOWS && !LL_COMMON_LINK_SHARED @@ -142,7 +149,7 @@ #pragma warning( 3 : 4265 ) // "class has virtual functions, but destructor is not virtual" #pragma warning( 3 : 4266 ) // 'function' : no override available for virtual member function from base 'type'; function is hidden #pragma warning (disable : 4180) // qualifier applied to function type has no meaning; ignored -#pragma warning( disable : 4284 ) // silly MS warning deep inside their include file +//#pragma warning( disable : 4284 ) // silly MS warning deep inside their include file #pragma warning( disable : 4503 ) // 'decorated name length exceeded, name was truncated'. Does not seem to affect compilation. #pragma warning( disable : 4800 ) // 'BOOL' : forcing value to bool 'true' or 'false' (performance warning) #pragma warning( disable : 4996 ) // warning: deprecated @@ -161,6 +168,12 @@ #pragma warning (disable : 4251) // member needs to have dll-interface to be used by clients of class #pragma warning (disable : 4275) // non dll-interface class used as base for dll-interface class +//#pragma warning (disable : 4018) // '<' : signed/unsigned mismatch + +#if _WIN64 +#pragma warning (disable : 4267) // member needs to have dll-interface to be used by clients of class +#endif + #endif // LL_MSVC #if LL_WINDOWS @@ -198,4 +211,19 @@ #endif #endif +#define LL_TYPEOF(exp) decltype(exp) + +#define LL_TO_STRING_HELPER(x) #x +#define LL_TO_STRING(x) LL_TO_STRING_HELPER(x) +#define LL_FILE_LINENO_MSG(msg) __FILE__ "(" LL_TO_STRING(__LINE__) ") : " msg +#define LL_GLUE_IMPL(x, y) x##y +#define LL_GLUE_TOKENS(x, y) LL_GLUE_IMPL(x, y) + +#if LL_WINDOWS +#define LL_COMPILE_TIME_MESSAGE(msg) __pragma(message(LL_FILE_LINENO_MSG(msg))) +#else +#define PRAGMA_MSG(x) _Pragma(#x) +#define LL_COMPILE_TIME_MESSAGE(msg) PRAGMA_MSG(message msg) +#endif + #endif // not LL_LINDEN_PREPROCESSOR_H diff --git a/indra/llcommon/llpriqueuemap.h b/indra/llcommon/llpriqueuemap.h index a861ac1be7..c4b5f2c32a 100644 --- a/indra/llcommon/llpriqueuemap.h +++ b/indra/llcommon/llpriqueuemap.h @@ -90,7 +90,7 @@ class LLPriQueueMap pqm_iter iter = mMap.find(LLPQMKey(priority, data)); if (iter != mMap.end()) { - llerrs << "Pushing already existing data onto queue!" << llendl; + LL_ERRS() << "Pushing already existing data onto queue!" << LL_ENDL; } #endif mMap.insert(pqm_pair(LLPQMKey(priority, data), data)); @@ -118,14 +118,14 @@ class LLPriQueueMap iter = mMap.find(cur_key); if (iter == mMap.end()) { - llwarns << "Data not on priority queue!" << llendl; + LL_WARNS() << "Data not on priority queue!" << LL_ENDL; // OK, try iterating through all of the data and seeing if we just screwed up the priority // somehow. for (iter = mMap.begin(); iter != mMap.end(); iter++) { if ((*(iter)).second == data) { - llerrs << "Data on priority queue but priority not matched!" << llendl; + LL_ERRS() << "Data on priority queue but priority not matched!" << LL_ENDL; } } return; diff --git a/indra/llcommon/llprocesslauncher.cpp b/indra/llcommon/llprocesslauncher.cpp index 8e146e0350..9940d37d6d 100644 --- a/indra/llcommon/llprocesslauncher.cpp +++ b/indra/llcommon/llprocesslauncher.cpp @@ -135,7 +135,7 @@ int LLProcessLauncher::launch(void) char message[256]; wcstombs(message, error_str, 256); message[255] = 0; - llwarns << "CreateProcessA failed: " << message << llendl; + LL_WARNS() << "CreateProcessA failed: " << message << LL_ENDL; LocalFree(error_str); } @@ -285,7 +285,7 @@ static std::string read_pipe(apr_file_t* in, bool timeout_ok = false) { return "TIMEOUT"; } - llwarns << "apr_file_read_full: " << apr_strerror(status, buf, sizeof(buf)) << llendl; + LL_WARNS() << "apr_file_read_full: " << apr_strerror(status, buf, sizeof(buf)) << LL_ENDL; assert(APR_STATUS_IS_EOF(status)); return "END OF FILE"; } @@ -293,13 +293,13 @@ static std::string read_pipe(apr_file_t* in, bool timeout_ok = false) status = apr_file_read_full(in, buf, bytes_to_read, &bytes_read); if (status != APR_SUCCESS) { - llwarns << "apr_file_read_full: " << apr_strerror(status, buf, sizeof(buf)) << llendl; + LL_WARNS() << "apr_file_read_full: " << apr_strerror(status, buf, sizeof(buf)) << LL_ENDL; assert(status == APR_SUCCESS); // Fail } assert(bytes_read == bytes_to_read); std::string received(buf, bytes_read); - llinfos << "Received: \"" << received << "\" (bytes read: " << bytes_read << ")" << llendl; + LL_INFOS() << "Received: \"" << received << "\" (bytes read: " << bytes_read << ")" << LL_ENDL; return received; } @@ -423,7 +423,7 @@ int LLProcessLauncher::launch(void) if (message != "TIMEOUT" && message != "END OF FILE") { // Most likely execv failed. - llwarns << message << llendl; + LL_WARNS() << message << LL_ENDL; assert(false); // Fail in debug mode. } } diff --git a/indra/llcommon/llprocesslauncher.h b/indra/llcommon/llprocesslauncher.h index 0b96f3f7b1..f9b15858f5 100644 --- a/indra/llcommon/llprocesslauncher.h +++ b/indra/llcommon/llprocesslauncher.h @@ -33,9 +33,7 @@ #ifndef LL_LLPROCESSLAUNCHER_H #define LL_LLPROCESSLAUNCHER_H -#if LL_WINDOWS -#include -#endif +#include "llwin32headerslean.h" /* diff --git a/indra/llcommon/llprocessor.cpp b/indra/llcommon/llprocessor.cpp index ce2c593c50..9754b05359 100644 --- a/indra/llcommon/llprocessor.cpp +++ b/indra/llcommon/llprocessor.cpp @@ -32,9 +32,7 @@ //#include #if LL_WINDOWS -# define WIN32_LEAN_AND_MEAN -# include -# include +# include "llwin32headerslean.h" # define _interlockedbittestandset _renamed_interlockedbittestandset # define _interlockedbittestandreset _renamed_interlockedbittestandreset # include @@ -49,10 +47,10 @@ # define LL_X86 1 #elif LL_MSVC && _M_IX86 # define LL_X86 1 -#elif LL_GNUC || LL_ICC || LL_CLANG && ( defined(__amd64__) || defined(__x86_64__) ) +#elif LL_GNUC || LL_CLANG || LL_INTELC && ( defined(__amd64__) || defined(__x86_64__) ) # define LL_X86_64 1 # define LL_X86 1 -#elif LL_GNUC || LL_ICC || LL_CLANG && ( defined(__i386__) ) +#elif LL_GNUC || LL_CLANG || LL_INTELC && ( defined(__i386__) ) # define LL_X86 1 #elif LL_GNUC && ( defined(__powerpc__) || defined(__ppc__) ) # define LL_PPC 1 @@ -202,10 +200,12 @@ namespace case 6: return "AMD K7"; case 0xF: return "AMD K8"; case 0x10: return "AMD K8L"; + case 0x15: return "AMD Bulldozer"; } return "Unknown"; } +#if LL_LINUX std::string compute_CPUFamilyName(const char* cpu_vendor, int composed_family) { const char* intel_string = "GenuineIntel"; @@ -221,6 +221,7 @@ namespace return "Unknown"; } +#else std::string compute_CPUFamilyName(const char* cpu_vendor, int family, int ext_family) { const char* intel_string = "GenuineIntel"; @@ -239,6 +240,7 @@ namespace } return "Unknown"; } +#endif } // end unnamed namespace @@ -415,7 +417,7 @@ static F64 calculate_cpu_frequency(U32 measure_msecs) HANDLE hThread = GetCurrentThread(); unsigned long dwCurPriorityClass = GetPriorityClass(hProcess); int iCurThreadPriority = GetThreadPriority(hThread); - unsigned long dwProcessMask, dwSystemMask, dwNewMask = 1; + DWORD_PTR dwProcessMask, dwSystemMask, dwNewMask = 1; // GetProcessAffinityMask(hProcess, &dwProcessMask, &dwSystemMask); SetPriorityClass(hProcess, REALTIME_PRIORITY_CLASS); @@ -487,8 +489,7 @@ class LLProcessorInfoWindowsImpl : public LLProcessorInfoImpl unsigned int ids = (unsigned int)cpu_info[0]; setConfig(eMaxID, (S32)ids); - char cpu_vendor[0x20]; - memset(cpu_vendor, 0, sizeof(cpu_vendor)); + char cpu_vendor[0x20] = {0}; *((int*)cpu_vendor) = cpu_info[1]; *((int*)(cpu_vendor+4)) = cpu_info[3]; *((int*)(cpu_vendor+8)) = cpu_info[2]; @@ -554,8 +555,7 @@ class LLProcessorInfoWindowsImpl : public LLProcessorInfoImpl unsigned int ext_ids = cpu_info[0]; setConfig(eMaxExtID, 0); - char cpu_brand_string[0x40]; - memset(cpu_brand_string, 0, sizeof(cpu_brand_string)); + char cpu_brand_string[0x40] = {0}; // Get the information associated with each extended ID. for(unsigned int i=0x80000000; i<=ext_ids; ++i) @@ -636,16 +636,14 @@ class LLProcessorInfoDarwinImpl : public LLProcessorInfoImpl { size_t len = 0; - char cpu_brand_string[0x40]; + char cpu_brand_string[0x40] = {0}; len = sizeof(cpu_brand_string); - memset(cpu_brand_string, 0, len); sysctlbyname("machdep.cpu.brand_string", (void*)cpu_brand_string, &len, NULL, 0); cpu_brand_string[0x3f] = 0; setInfo(eBrandName, cpu_brand_string); - char cpu_vendor[0x20]; + char cpu_vendor[0x20] = {0}; len = sizeof(cpu_vendor); - memset(cpu_vendor, 0, len); sysctlbyname("machdep.cpu.vendor", (void*)cpu_vendor, &len, NULL, 0); cpu_vendor[0x1f] = 0; setInfo(eVendor, cpu_vendor); @@ -702,7 +700,7 @@ class LLProcessorInfoDarwinImpl : public LLProcessorInfoImpl __cpuid(0x1, eax, ebx, ecx, edx); if(feature_infos[0] != (S32)edx) { - llerrs << "machdep.cpu.feature_bits doesn't match expected cpuid result!" << llendl; + LL_ERRS() << "machdep.cpu.feature_bits doesn't match expected cpuid result!" << LL_ENDL; } #endif // LL_RELEASE_FOR_DOWNLOAD @@ -733,8 +731,7 @@ class LLProcessorInfoLinuxImpl : public LLProcessorInfoImpl LLFILE* cpuinfo_fp = LLFile::fopen(CPUINFO_FILE, "rb"); if(cpuinfo_fp) { - char line[MAX_STRING]; - memset(line, 0, MAX_STRING); + char line[MAX_STRING] = {0}; while(fgets(line, MAX_STRING, cpuinfo_fp)) { // /proc/cpuinfo on Linux looks like: @@ -832,8 +829,7 @@ class LLProcessorInfoLinuxImpl : public LLProcessorInfoImpl LLFILE* cpuinfo = LLFile::fopen(CPUINFO_FILE, "rb"); if(cpuinfo) { - char line[MAX_STRING]; - memset(line, 0, MAX_STRING); + char line[MAX_STRING] = {0}; while(fgets(line, MAX_STRING, cpuinfo)) { line[strlen(line)-1] = ' '; @@ -877,7 +873,7 @@ LLProcessorInfo::LLProcessorInfo() : mImpl(NULL) LLProcessorInfo::~LLProcessorInfo() {} -F64 LLProcessorInfo::getCPUFrequency() const { return mImpl->getCPUFrequency(); } +F64MegahertzImplicit LLProcessorInfo::getCPUFrequency() const { return mImpl->getCPUFrequency(); } bool LLProcessorInfo::hasSSE() const { return mImpl->hasSSE(); } bool LLProcessorInfo::hasSSE2() const { return mImpl->hasSSE2(); } bool LLProcessorInfo::hasAltivec() const { return mImpl->hasAltivec(); } diff --git a/indra/llcommon/llprocessor.h b/indra/llcommon/llprocessor.h index fc2c8dacfb..681dd63144 100644 --- a/indra/llcommon/llprocessor.h +++ b/indra/llcommon/llprocessor.h @@ -33,6 +33,8 @@ #ifndef LLPROCESSOR_H #define LLPROCESSOR_H +#include "llunits.h" + class LLProcessorInfoImpl; class LL_COMMON_API LLProcessorInfo @@ -41,7 +43,7 @@ class LL_COMMON_API LLProcessorInfo LLProcessorInfo(); ~LLProcessorInfo(); - F64 getCPUFrequency() const; + F64MegahertzImplicit getCPUFrequency() const; bool hasSSE() const; bool hasSSE2() const; bool hasAltivec() const; diff --git a/indra/llcommon/llptrskiplist.h b/indra/llcommon/llptrskiplist.h deleted file mode 100644 index 68781657d7..0000000000 --- a/indra/llcommon/llptrskiplist.h +++ /dev/null @@ -1,730 +0,0 @@ -/** - * @file llptrskiplist.h - * @brief Skip list implementation. - * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifndef LL_LLPTRSKIPLIST_H -#define LL_LLPTRSKIPLIST_H - -#include "llerror.h" -#include "llrand.h" -//#include "vmath.h" -#include "llrand.h" - -///////////////////////////////////////////// -// -// LLPtrSkipList implementation - skip list for pointers to objects -// - -template -class LLPtrSkipList -{ -public: - friend class LLPtrSkipNode; - - // basic constructor - LLPtrSkipList(); - // basic constructor including sorter - LLPtrSkipList(BOOL (*insert_first)(DATA_TYPE *first, DATA_TYPE *second), - BOOL (*equals)(DATA_TYPE *first, DATA_TYPE *second)); - ~LLPtrSkipList(); - - inline void setInsertFirst(BOOL (*insert_first)(const DATA_TYPE *first, const DATA_TYPE *second)); - inline void setEquals(BOOL (*equals)(const DATA_TYPE *first, const DATA_TYPE *second)); - - inline BOOL addData(DATA_TYPE *data); - - inline BOOL checkData(const DATA_TYPE *data); - - inline S32 getLength(); // returns number of items in the list - NOT constant time! - - inline BOOL removeData(const DATA_TYPE *data); - - // note that b_sort is ignored - inline BOOL moveData(const DATA_TYPE *data, LLPtrSkipList *newlist, BOOL b_sort); - - inline BOOL moveCurrentData(LLPtrSkipList *newlist, BOOL b_sort); - - // resort -- use when the value we're sorting by changes - /* IW 12/6/02 - This doesn't work! - Instead, remove the data BEFORE you change it - Then re-insert it after you change it - BOOL resortData(DATA_TYPE *data) - */ - - // remove all nodes from the list but do not delete data - inline void removeAllNodes(); - - inline BOOL deleteData(const DATA_TYPE *data); - - // remove all nodes from the list and delete data - inline void deleteAllData(); - - // place mCurrentp on first node - inline void resetList(); - - // return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp - inline DATA_TYPE *getCurrentData(); - - // same as getCurrentData() but a more intuitive name for the operation - inline DATA_TYPE *getNextData(); - - // remove the Node at mCurentOperatingp - // leave mCurrentp and mCurentOperatingp on the next entry - inline void removeCurrentData(); - - // delete the Node at mCurentOperatingp - // leave mCurrentp and mCurentOperatingp on the next entry - inline void deleteCurrentData(); - - // reset the list and return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp - inline DATA_TYPE *getFirstData(); - - // TRUE if nodes are not in sorted order - inline BOOL corrupt(); - -protected: - class LLPtrSkipNode - { - public: - LLPtrSkipNode() - : mData(NULL) - { - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mForward[i] = NULL; - } - } - - LLPtrSkipNode(DATA_TYPE *data) - : mData(data) - { - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mForward[i] = NULL; - } - } - - ~LLPtrSkipNode() - { - if (mData) - { - llerror("Attempting to call LLPtrSkipNode destructor with a non-null mDatap!", 1); - } - } - - // delete associated data and NULLs out pointer - void deleteData() - { - delete mData; - mData = NULL; - } - - // NULLs out pointer - void removeData() - { - mData = NULL; - } - - DATA_TYPE *mData; - LLPtrSkipNode *mForward[BINARY_DEPTH]; - }; - - static BOOL defaultEquals(const DATA_TYPE *first, const DATA_TYPE *second) - { - return first == second; - } - - - LLPtrSkipNode mHead; - LLPtrSkipNode *mUpdate[BINARY_DEPTH]; - LLPtrSkipNode *mCurrentp; - LLPtrSkipNode *mCurrentOperatingp; - S32 mLevel; - BOOL (*mInsertFirst)(const DATA_TYPE *first, const DATA_TYPE *second); - BOOL (*mEquals)(const DATA_TYPE *first, const DATA_TYPE *second); -}; - - -// basic constructor -template -LLPtrSkipList::LLPtrSkipList() - : mInsertFirst(NULL), mEquals(defaultEquals) -{ - if (BINARY_DEPTH < 2) - { - llerrs << "Trying to create skip list with too little depth, " - "must be 2 or greater" << llendl; - } - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mUpdate[i] = NULL; - } - mLevel = 1; - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); -} - -// basic constructor including sorter -template -LLPtrSkipList::LLPtrSkipList(BOOL (*insert_first)(DATA_TYPE *first, DATA_TYPE *second), - BOOL (*equals)(DATA_TYPE *first, DATA_TYPE *second)) - :mInsertFirst(insert_first), mEquals(equals) -{ - if (BINARY_DEPTH < 2) - { - llerrs << "Trying to create skip list with too little depth, " - "must be 2 or greater" << llendl; - } - mLevel = 1; - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mHead.mForward[i] = NULL; - mUpdate[i] = NULL; - } - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); -} - -template -inline LLPtrSkipList::~LLPtrSkipList() -{ - removeAllNodes(); -} - -template -inline void LLPtrSkipList::setInsertFirst(BOOL (*insert_first)(const DATA_TYPE *first, const DATA_TYPE *second)) -{ - mInsertFirst = insert_first; -} - -template -inline void LLPtrSkipList::setEquals(BOOL (*equals)(const DATA_TYPE *first, const DATA_TYPE *second)) -{ - mEquals = equals; -} - -template -inline BOOL LLPtrSkipList::addData(DATA_TYPE *data) -{ - S32 level; - LLPtrSkipNode *current = &mHead; - LLPtrSkipNode *temp; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mData, data))) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mData < data)) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - - - // we're now just in front of where we want to be . . . take one step forward - current = *current->mForward; - - // now add the new node - S32 newlevel; - for (newlevel = 1; newlevel <= mLevel && newlevel < BINARY_DEPTH; newlevel++) - { - if (ll_frand() < 0.5f) - break; - } - - LLPtrSkipNode *snode = new LLPtrSkipNode(data); - - if (newlevel > mLevel) - { - mHead.mForward[mLevel] = NULL; - mUpdate[mLevel] = &mHead; - mLevel = newlevel; - } - - for (level = 0; level < newlevel; level++) - { - snode->mForward[level] = mUpdate[level]->mForward[level]; - mUpdate[level]->mForward[level] = snode; - } - return TRUE; -} - -template -inline BOOL LLPtrSkipList::checkData(const DATA_TYPE *data) -{ - S32 level; - LLPtrSkipNode *current = &mHead; - LLPtrSkipNode *temp; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mData, data))) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mData < data)) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - - - // we're now just in front of where we want to be . . . take one step forward - current = *current->mForward; - - if (current) - { - return mEquals(current->mData, data); - } - else - { - return FALSE; - } -} - -// returns number of items in the list -template -inline S32 LLPtrSkipList::getLength() -{ - U32 length = 0; - for (LLPtrSkipNode* temp = *(mHead.mForward); temp != NULL; temp = temp->mForward[0]) - { - length++; - } - return length; -} - -template -inline BOOL LLPtrSkipList::removeData(const DATA_TYPE *data) -{ - S32 level; - LLPtrSkipNode *current = &mHead; - LLPtrSkipNode *temp; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mData, data))) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mData < data)) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - - - // we're now just in front of where we want to be . . . take one step forward - current = *current->mForward; - - if (!current) - { - // empty list or beyond the end! - return FALSE; - } - - // is this the one we want? - if (!mEquals(current->mData, data)) - { - // nope! - return FALSE; - } - else - { - // yes it is! change pointers as required - for (level = 0; level < mLevel; level++) - { - if (mUpdate[level]->mForward[level] != current) - { - // cool, we've fixed all the pointers! - break; - } - mUpdate[level]->mForward[level] = current->mForward[level]; - } - - // clean up cuurent - current->removeData(); - delete current; - - // clean up mHead - while ( (mLevel > 1) - &&(!mHead.mForward[mLevel - 1])) - { - mLevel--; - } - } - return TRUE; -} - -// note that b_sort is ignored -template -inline BOOL LLPtrSkipList::moveData(const DATA_TYPE *data, LLPtrSkipList *newlist, BOOL b_sort) -{ - BOOL removed = removeData(data); - BOOL added = newlist->addData(data); - return removed && added; -} - -template -inline BOOL LLPtrSkipList::moveCurrentData(LLPtrSkipList *newlist, BOOL b_sort) -{ - if (mCurrentOperatingp) - { - mCurrentp = mCurrentOperatingp->mForward[0]; - BOOL removed = removeData(mCurrentOperatingp); - BOOL added = newlist->addData(mCurrentOperatingp); - mCurrentOperatingp = mCurrentp; - return removed && added; - } - return FALSE; -} - -// resort -- use when the value we're sorting by changes -/* IW 12/6/02 - This doesn't work! - Instead, remove the data BEFORE you change it - Then re-insert it after you change it -BOOL resortData(DATA_TYPE *data) -{ - removeData(data); - addData(data); -} -*/ - -// remove all nodes from the list but do not delete data -template -inline void LLPtrSkipList::removeAllNodes() -{ - LLPtrSkipNode *temp; - // reset mCurrentp - mCurrentp = *(mHead.mForward); - - while (mCurrentp) - { - temp = mCurrentp->mForward[0]; - mCurrentp->removeData(); - delete mCurrentp; - mCurrentp = temp; - } - - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mHead.mForward[i] = NULL; - mUpdate[i] = NULL; - } - - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); -} - -template -inline BOOL LLPtrSkipList::deleteData(const DATA_TYPE *data) -{ - S32 level; - LLPtrSkipNode *current = &mHead; - LLPtrSkipNode *temp; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mData, data))) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mData < data)) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - - - // we're now just in front of where we want to be . . . take one step forward - current = *current->mForward; - - if (!current) - { - // empty list or beyond the end! - return FALSE; - } - - // is this the one we want? - if (!mEquals(current->mData, data)) - { - // nope! - return FALSE; - } - else - { - // do we need to fix current or currentop? - if (current == mCurrentp) - { - mCurrentp = current->mForward[0]; - } - - if (current == mCurrentOperatingp) - { - mCurrentOperatingp = current->mForward[0]; - } - - // yes it is! change pointers as required - for (level = 0; level < mLevel; level++) - { - if (mUpdate[level]->mForward[level] != current) - { - // cool, we've fixed all the pointers! - break; - } - mUpdate[level]->mForward[level] = current->mForward[level]; - } - - // clean up cuurent - current->deleteData(); - delete current; - - // clean up mHead - while ( (mLevel > 1) - &&(!mHead.mForward[mLevel - 1])) - { - mLevel--; - } - } - return TRUE; -} - -// remove all nodes from the list and delete data -template -inline void LLPtrSkipList::deleteAllData() -{ - LLPtrSkipNode *temp; - // reset mCurrentp - mCurrentp = *(mHead.mForward); - - while (mCurrentp) - { - temp = mCurrentp->mForward[0]; - mCurrentp->deleteData(); - delete mCurrentp; - mCurrentp = temp; - } - - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mHead.mForward[i] = NULL; - mUpdate[i] = NULL; - } - - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); -} - -// place mCurrentp on first node -template -inline void LLPtrSkipList::resetList() -{ - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); -} - -// return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp -template -inline DATA_TYPE *LLPtrSkipList::getCurrentData() -{ - if (mCurrentp) - { - mCurrentOperatingp = mCurrentp; - mCurrentp = *mCurrentp->mForward; - return mCurrentOperatingp->mData; - } - else - { - //return NULL; // causes compile warning - return 0; // equivalent, but no warning - } -} - -// same as getCurrentData() but a more intuitive name for the operation -template -inline DATA_TYPE *LLPtrSkipList::getNextData() -{ - if (mCurrentp) - { - mCurrentOperatingp = mCurrentp; - mCurrentp = *mCurrentp->mForward; - return mCurrentOperatingp->mData; - } - else - { - //return NULL; // causes compile warning - return 0; // equivalent, but no warning - } -} - -// remove the Node at mCurentOperatingp -// leave mCurrentp and mCurentOperatingp on the next entry -template -inline void LLPtrSkipList::removeCurrentData() -{ - if (mCurrentOperatingp) - { - removeData(mCurrentOperatingp->mData); - } -} - -// delete the Node at mCurentOperatingp -// leave mCurrentp and mCurentOperatingp on the next entry -template -inline void LLPtrSkipList::deleteCurrentData() -{ - if (mCurrentOperatingp) - { - deleteData(mCurrentOperatingp->mData); - } -} - -// reset the list and return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp -template -inline DATA_TYPE *LLPtrSkipList::getFirstData() -{ - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); - if (mCurrentp) - { - mCurrentOperatingp = mCurrentp; - mCurrentp = mCurrentp->mForward[0]; - return mCurrentOperatingp->mData; - } - else - { - //return NULL; // causes compile warning - return 0; // equivalent, but no warning - } -} - -template -inline BOOL LLPtrSkipList::corrupt() -{ - LLPtrSkipNode *previous = mHead.mForward[0]; - - // Empty lists are not corrupt. - if (!previous) return FALSE; - - LLPtrSkipNode *current = previous->mForward[0]; - while(current) - { - if (!mInsertFirst(previous->mData, current->mData)) - { - // prev shouldn't be in front of cur! - return TRUE; - } - current = current->mForward[0]; - } - return FALSE; -} - -#endif diff --git a/indra/llcommon/llptrskipmap.h b/indra/llcommon/llptrskipmap.h deleted file mode 100644 index 20d0019901..0000000000 --- a/indra/llcommon/llptrskipmap.h +++ /dev/null @@ -1,1245 +0,0 @@ -/** - * @file llptrskipmap.h - * @brief Just like a LLSkipMap, but since it's pointers, you can call - * deleteAllData - * - * $LicenseInfo:firstyear=2003&license=viewergpl$ - * - * Copyright (c) 2003-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ -#ifndef LL_LLPTRSKIPMAP_H -#define LL_LLPTRSKIPMAP_H - -#include "llerror.h" -#include "llrand.h" - -template -class LLPtrSkipMapNode -{ -public: - LLPtrSkipMapNode() - { - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mForward[i] = NULL; - } - - U8 *zero = (U8 *)&mIndex; - - for (i = 0; i < (S32)sizeof(INDEX_T); i++) - { - *(zero + i) = 0; - } - - zero = (U8 *)&mData; - - for (i = 0; i < (S32)sizeof(DATA_T); i++) - { - *(zero + i) = 0; - } - } - - LLPtrSkipMapNode(const INDEX_T &index) - : mIndex(index) - { - - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mForward[i] = NULL; - } - - U8 *zero = (U8 *)&mData; - - for (i = 0; i < (S32)sizeof(DATA_T); i++) - { - *(zero + i) = 0; - } - } - - LLPtrSkipMapNode(const INDEX_T &index, DATA_T datap) - : mIndex(index) - { - - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mForward[i] = NULL; - } - - mData = datap; - } - - ~LLPtrSkipMapNode() - { - } - - // delete associated data and NULLs out pointer - void deleteData() - { - delete mData; - mData = 0; - } - - // NULLs out pointer - void removeData() - { - mData = 0; - } - - INDEX_T mIndex; - DATA_T mData; - LLPtrSkipMapNode *mForward[BINARY_DEPTH]; - -private: - // Disallow copying of LLPtrSkipMapNodes by not implementing these methods. - LLPtrSkipMapNode(const LLPtrSkipMapNode &); - LLPtrSkipMapNode &operator=(const LLPtrSkipMapNode &rhs); -}; - -//--------------------------------------------------------------------------- - -template -class LLPtrSkipMap -{ -public: - typedef BOOL (*compare)(const DATA_T& first, const DATA_T& second); - typedef compare insert_func; - typedef compare equals_func; - - void init(); - - // basic constructor - LLPtrSkipMap(); - - // basic constructor including sorter - LLPtrSkipMap(insert_func insert_first, equals_func equals); - - ~LLPtrSkipMap(); - - void setInsertFirst(insert_func insert_first); - void setEquals(equals_func equals); - - DATA_T &addData(const INDEX_T &index, DATA_T datap); - DATA_T &addData(const INDEX_T &index); - DATA_T &getData(const INDEX_T &index); - DATA_T &operator[](const INDEX_T &index); - - // If index present, returns data. - // If index not present, adds and returns NULL. - DATA_T &getData(const INDEX_T &index, BOOL &b_new_entry); - - // returns data entry before and after index - BOOL getInterval(const INDEX_T &index, INDEX_T &index_before, INDEX_T &index_after, - DATA_T &data_before, DATA_T &data_after ); - - // Returns TRUE if data present in map. - BOOL checkData(const INDEX_T &index); - - // Returns TRUE if key is present in map. This is useful if you - // are potentially storing NULL pointers in the map - BOOL checkKey(const INDEX_T &index); - - // If there, returns the data. - // If not, returns NULL. - // Never adds entries to the map. - DATA_T getIfThere(const INDEX_T &index); - - INDEX_T reverseLookup(const DATA_T datap); - - // returns number of items in the list - S32 getLength(); // WARNING! getLength is O(n), not O(1)! - - BOOL removeData(const INDEX_T &index); - BOOL deleteData(const INDEX_T &index); - - // remove all nodes from the list but do not delete data - void removeAllData(); - void deleteAllData(); - - // place mCurrentp on first node - void resetList(); - - // return the data currently pointed to - DATA_T getCurrentDataWithoutIncrement(); - - // return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp - DATA_T getCurrentData(); - - // same as getCurrentData() but a more intuitive name for the operation - DATA_T getNextData(); - - INDEX_T getNextKey(); - - // return the key currently pointed to - INDEX_T getCurrentKeyWithoutIncrement(); - - // remove the Node at mCurentOperatingp - // leave mCurrentp and mCurentOperatingp on the next entry - void removeCurrentData(); - - void deleteCurrentData(); - - // reset the list and return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp - DATA_T getFirstData(); - - INDEX_T getFirstKey(); - - static BOOL defaultEquals(const INDEX_T &first, const INDEX_T &second) - { - return first == second; - } - -private: - // don't generate implicit copy constructor or copy assignment - LLPtrSkipMap(const LLPtrSkipMap &); - LLPtrSkipMap &operator=(const LLPtrSkipMap &); - -private: - LLPtrSkipMapNode mHead; - LLPtrSkipMapNode *mUpdate[BINARY_DEPTH]; - LLPtrSkipMapNode *mCurrentp; - LLPtrSkipMapNode *mCurrentOperatingp; - S32 mLevel; - BOOL (*mInsertFirst)(const INDEX_T &first, const INDEX_T &second); - BOOL (*mEquals)(const INDEX_T &first, const INDEX_T &second); - S32 mNumberOfSteps; -}; - -////////////////////////////////////////////////// -// -// LLPtrSkipMap implementation -// -// - -template -inline LLPtrSkipMap::LLPtrSkipMap() - : mInsertFirst(NULL), - mEquals(defaultEquals), - mNumberOfSteps(0) -{ - if (BINARY_DEPTH < 2) - { - llerrs << "Trying to create skip list with too little depth, " - "must be 2 or greater" << llendl; - } - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mUpdate[i] = NULL; - } - mLevel = 1; - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); -} - -template -inline LLPtrSkipMap::LLPtrSkipMap(insert_func insert_first, - equals_func equals) -: mInsertFirst(insert_first), - mEquals(equals), - mNumberOfSteps(0) -{ - if (BINARY_DEPTH < 2) - { - llerrs << "Trying to create skip list with too little depth, " - "must be 2 or greater" << llendl; - } - mLevel = 1; - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mHead.mForward[i] = NULL; - mUpdate[i] = NULL; - } - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); -} - -template -inline LLPtrSkipMap::~LLPtrSkipMap() -{ - removeAllData(); -} - -template -inline void LLPtrSkipMap::setInsertFirst(insert_func insert_first) -{ - mInsertFirst = insert_first; -} - -template -inline void LLPtrSkipMap::setEquals(equals_func equals) -{ - mEquals = equals; -} - -template -inline DATA_T &LLPtrSkipMap::addData(const INDEX_T &index, DATA_T datap) -{ - S32 level; - LLPtrSkipMapNode *current = &mHead; - LLPtrSkipMapNode *temp; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mIndex, index))) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mIndex < index)) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - - // we're now just in front of where we want to be . . . take one step forward - current = *current->mForward; - - // replace the existing data if a node is already there - if ( (current) - &&(mEquals(current->mIndex, index))) - { - current->mData = datap; - return current->mData; - } - - // now add the new node - S32 newlevel; - for (newlevel = 1; newlevel <= mLevel && newlevel < BINARY_DEPTH; newlevel++) - { - if (ll_frand() < 0.5f) - { - break; - } - } - - LLPtrSkipMapNode *snode - = new LLPtrSkipMapNode(index, datap); - - if (newlevel > mLevel) - { - mHead.mForward[mLevel] = NULL; - mUpdate[mLevel] = &mHead; - mLevel = newlevel; - } - - for (level = 0; level < newlevel; level++) - { - snode->mForward[level] = mUpdate[level]->mForward[level]; - mUpdate[level]->mForward[level] = snode; - } - return snode->mData; -} - -template -inline DATA_T &LLPtrSkipMap::addData(const INDEX_T &index) -{ - S32 level; - LLPtrSkipMapNode *current = &mHead; - LLPtrSkipMapNode *temp; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mIndex, index))) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mIndex < index)) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - - // we're now just in front of where we want to be . . . take one step forward - current = *current->mForward; - - // now add the new node - S32 newlevel; - for (newlevel = 1; newlevel <= mLevel && newlevel < BINARY_DEPTH; newlevel++) - { - if (ll_frand() < 0.5f) - break; - } - - LLPtrSkipMapNode *snode - = new LLPtrSkipMapNode(index); - - if (newlevel > mLevel) - { - mHead.mForward[mLevel] = NULL; - mUpdate[mLevel] = &mHead; - mLevel = newlevel; - } - - for (level = 0; level < newlevel; level++) - { - snode->mForward[level] = mUpdate[level]->mForward[level]; - mUpdate[level]->mForward[level] = snode; - } - return snode->mData; -} - -template -inline DATA_T &LLPtrSkipMap::getData(const INDEX_T &index) -{ - S32 level; - LLPtrSkipMapNode *current = &mHead; - LLPtrSkipMapNode *temp; - - mNumberOfSteps = 0; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mIndex, index))) - { - current = temp; - temp = *(current->mForward + level); - mNumberOfSteps++; - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mIndex < index)) - { - current = temp; - temp = *(current->mForward + level); - mNumberOfSteps++; - } - *(mUpdate + level) = current; - } - } - - // we're now just in front of where we want to be . . . take one step forward - current = *current->mForward; - mNumberOfSteps++; - - if ( (current) - &&(mEquals(current->mIndex, index))) - { - - return current->mData; - } - - // now add the new node - S32 newlevel; - for (newlevel = 1; newlevel <= mLevel && newlevel < BINARY_DEPTH; newlevel++) - { - if (ll_frand() < 0.5f) - break; - } - - LLPtrSkipMapNode *snode - = new LLPtrSkipMapNode(index); - - if (newlevel > mLevel) - { - mHead.mForward[mLevel] = NULL; - mUpdate[mLevel] = &mHead; - mLevel = newlevel; - } - - for (level = 0; level < newlevel; level++) - { - snode->mForward[level] = mUpdate[level]->mForward[level]; - mUpdate[level]->mForward[level] = snode; - } - - return snode->mData; -} - -template -inline BOOL LLPtrSkipMap::getInterval(const INDEX_T &index, - INDEX_T &index_before, - INDEX_T &index_after, - DATA_T &data_before, - DATA_T &data_after) -{ - S32 level; - LLPtrSkipMapNode *current = &mHead; - LLPtrSkipMapNode *temp; - - mNumberOfSteps = 0; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mIndex, index))) - { - current = temp; - temp = *(current->mForward + level); - mNumberOfSteps++; - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mIndex < index)) - { - current = temp; - temp = *(current->mForward + level); - mNumberOfSteps++; - } - *(mUpdate + level) = current; - } - } - - BOOL both_found = TRUE; - - if (current != &mHead) - { - index_before = current->mIndex; - data_before = current->mData; - } - else - { - data_before = 0; - index_before = 0; - both_found = FALSE; - } - - // we're now just in front of where we want to be . . . take one step forward - mNumberOfSteps++; - current = *current->mForward; - - if (current) - { - data_after = current->mData; - index_after = current->mIndex; - } - else - { - data_after = 0; - index_after = 0; - both_found = FALSE; - } - - return both_found; -} - - -template -inline DATA_T &LLPtrSkipMap::operator[](const INDEX_T &index) -{ - - return getData(index); -} - -// If index present, returns data. -// If index not present, adds and returns NULL. -template -inline DATA_T &LLPtrSkipMap::getData(const INDEX_T &index, BOOL &b_new_entry) -{ - S32 level; - LLPtrSkipMapNode *current = &mHead; - LLPtrSkipMapNode *temp; - - mNumberOfSteps = 0; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mIndex, index))) - { - current = temp; - temp = *(current->mForward + level); - mNumberOfSteps++; - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mIndex < index)) - { - current = temp; - temp = *(current->mForward + level); - mNumberOfSteps++; - } - *(mUpdate + level) = current; - } - } - - // we're now just in front of where we want to be . . . take one step forward - mNumberOfSteps++; - current = *current->mForward; - - if ( (current) - &&(mEquals(current->mIndex, index))) - { - - return current->mData; - } - b_new_entry = TRUE; - addData(index); - - return current->mData; -} - -// Returns TRUE if data present in map. -template -inline BOOL LLPtrSkipMap::checkData(const INDEX_T &index) -{ - S32 level; - LLPtrSkipMapNode *current = &mHead; - LLPtrSkipMapNode *temp; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mIndex, index))) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mIndex < index)) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - - // we're now just in front of where we want to be . . . take one step forward - current = *current->mForward; - - if (current) - { - // Gets rid of some compiler ambiguity for the LLPointer<> templated class. - if (current->mData) - { - return mEquals(current->mIndex, index); - } - } - - return FALSE; -} - -// Returns TRUE if key is present in map. This is useful if you -// are potentially storing NULL pointers in the map -template -inline BOOL LLPtrSkipMap::checkKey(const INDEX_T &index) -{ - S32 level; - LLPtrSkipMapNode *current = &mHead; - LLPtrSkipMapNode *temp; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mIndex, index))) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mIndex < index)) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - - // we're now just in front of where we want to be . . . take one step forward - current = *current->mForward; - - if (current) - { - return mEquals(current->mIndex, index); - } - - return FALSE; -} - -// If there, returns the data. -// If not, returns NULL. -// Never adds entries to the map. -template -inline DATA_T LLPtrSkipMap::getIfThere(const INDEX_T &index) -{ - S32 level; - LLPtrSkipMapNode *current = &mHead; - LLPtrSkipMapNode *temp; - - mNumberOfSteps = 0; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mIndex, index))) - { - current = temp; - temp = *(current->mForward + level); - mNumberOfSteps++; - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mIndex < index)) - { - current = temp; - temp = *(current->mForward + level); - mNumberOfSteps++; - } - *(mUpdate + level) = current; - } - } - - // we're now just in front of where we want to be . . . take one step forward - mNumberOfSteps++; - current = *current->mForward; - - if (current) - { - if (mEquals(current->mIndex, index)) - { - return current->mData; - } - } - - // Avoid Linux compiler warning on returning NULL. - return (DATA_T)0; -} - -template -inline INDEX_T LLPtrSkipMap::reverseLookup(const DATA_T datap) -{ - LLPtrSkipMapNode *current = &mHead; - - while (current) - { - if (datap == current->mData) - { - - return current->mIndex; - } - current = *current->mForward; - } - - // not found! return NULL - return INDEX_T(); -} - -// returns number of items in the list -template -inline S32 LLPtrSkipMap::getLength() -{ - U32 length = 0; - LLPtrSkipMapNode* temp; - for (temp = *(mHead.mForward); temp != NULL; temp = temp->mForward[0]) - { - length++; - } - - return length; -} - -template -inline BOOL LLPtrSkipMap::removeData(const INDEX_T &index) -{ - S32 level; - LLPtrSkipMapNode *current = &mHead; - LLPtrSkipMapNode *temp; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mIndex, index))) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mIndex < index)) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - - // we're now just in front of where we want to be . . . take one step forward - current = *current->mForward; - - if (!current) - { - // empty list or beyond the end! - - return FALSE; - } - - // is this the one we want? - if (!mEquals(current->mIndex, index)) - { - // nope! - - return FALSE; - } - else - { - // do we need to fix current or currentop? - if (current == mCurrentp) - { - mCurrentp = *current->mForward; - } - - if (current == mCurrentOperatingp) - { - mCurrentOperatingp = *current->mForward; - } - // yes it is! change pointers as required - for (level = 0; level < mLevel; level++) - { - if (*((*(mUpdate + level))->mForward + level) != current) - { - // cool, we've fixed all the pointers! - break; - } - *((*(mUpdate + level))->mForward + level) = *(current->mForward + level); - } - - // clean up cuurent - current->removeData(); - delete current; - - // clean up mHead - while ( (mLevel > 1) - &&(!*(mHead.mForward + mLevel - 1))) - { - mLevel--; - } - } - - return TRUE; -} - -template -inline BOOL LLPtrSkipMap::deleteData(const INDEX_T &index) -{ - S32 level; - LLPtrSkipMapNode *current = &mHead; - LLPtrSkipMapNode *temp; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mIndex, index))) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mIndex < index)) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - - // we're now just in front of where we want to be . . . take one step forward - current = *current->mForward; - - if (!current) - { - // empty list or beyond the end! - - return FALSE; - } - - // is this the one we want? - if (!mEquals(current->mIndex, index)) - { - // nope! - - return FALSE; - } - else - { - // do we need to fix current or currentop? - if (current == mCurrentp) - { - mCurrentp = *current->mForward; - } - - if (current == mCurrentOperatingp) - { - mCurrentOperatingp = *current->mForward; - } - // yes it is! change pointers as required - for (level = 0; level < mLevel; level++) - { - if (*((*(mUpdate + level))->mForward + level) != current) - { - // cool, we've fixed all the pointers! - break; - } - *((*(mUpdate + level))->mForward + level) = *(current->mForward + level); - } - - // clean up cuurent - current->deleteData(); - delete current; - - // clean up mHead - while ( (mLevel > 1) - &&(!*(mHead.mForward + mLevel - 1))) - { - mLevel--; - } - } - - return TRUE; -} - -// remove all nodes from the list but do not delete data -template -void LLPtrSkipMap::removeAllData() -{ - LLPtrSkipMapNode *temp; - // reset mCurrentp - mCurrentp = *(mHead.mForward); - - while (mCurrentp) - { - temp = mCurrentp->mForward[0]; - mCurrentp->removeData(); - delete mCurrentp; - mCurrentp = temp; - } - - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mHead.mForward[i] = NULL; - mUpdate[i] = NULL; - } - - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); -} - -template -inline void LLPtrSkipMap::deleteAllData() -{ - LLPtrSkipMapNode *temp; - // reset mCurrentp - mCurrentp = *(mHead.mForward); - - while (mCurrentp) - { - temp = mCurrentp->mForward[0]; - mCurrentp->deleteData(); - delete mCurrentp; - mCurrentp = temp; - } - - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mHead.mForward[i] = NULL; - mUpdate[i] = NULL; - } - - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); -} - -// place mCurrentp on first node -template -inline void LLPtrSkipMap::resetList() -{ - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); -} - - -// return the data currently pointed to -template -inline DATA_T LLPtrSkipMap::getCurrentDataWithoutIncrement() -{ - if (mCurrentOperatingp) - { - return mCurrentOperatingp->mData; - } - else - { - //return NULL; // causes warning - return (DATA_T)0; // equivalent, but no warning - } -} - -// return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp -template -inline DATA_T LLPtrSkipMap::getCurrentData() -{ - if (mCurrentp) - { - mCurrentOperatingp = mCurrentp; - mCurrentp = mCurrentp->mForward[0]; - return mCurrentOperatingp->mData; - } - else - { - //return NULL; // causes warning - return (DATA_T)0; // equivalent, but no warning - } -} - -// same as getCurrentData() but a more intuitive name for the operation -template -inline DATA_T LLPtrSkipMap::getNextData() -{ - if (mCurrentp) - { - mCurrentOperatingp = mCurrentp; - mCurrentp = mCurrentp->mForward[0]; - return mCurrentOperatingp->mData; - } - else - { - //return NULL; // causes compile warning - return (DATA_T)0; // equivalent, but removes warning - } -} - -template -inline INDEX_T LLPtrSkipMap::getNextKey() -{ - if (mCurrentp) - { - mCurrentOperatingp = mCurrentp; - mCurrentp = mCurrentp->mForward[0]; - return mCurrentOperatingp->mIndex; - } - else - { - return mHead.mIndex; - } -} - -// return the key currently pointed to -template -inline INDEX_T LLPtrSkipMap::getCurrentKeyWithoutIncrement() -{ - if (mCurrentOperatingp) - { - return mCurrentOperatingp->mIndex; - } - else - { - //return NULL; // causes compile warning - return (INDEX_T)0; // equivalent, but removes warning - } -} - - -// remove the Node at mCurentOperatingp -// leave mCurrentp and mCurentOperatingp on the next entry -template -inline void LLPtrSkipMap::removeCurrentData() -{ - if (mCurrentOperatingp) - { - removeData(mCurrentOperatingp->mIndex); - } -} - -template -inline void LLPtrSkipMap::deleteCurrentData() -{ - if (mCurrentOperatingp) - { - deleteData(mCurrentOperatingp->mIndex); - } -} - -// reset the list and return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp -template -inline DATA_T LLPtrSkipMap::getFirstData() -{ - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); - if (mCurrentp) - { - mCurrentOperatingp = mCurrentp; - mCurrentp = mCurrentp->mForward[0]; - return mCurrentOperatingp->mData; - } - else - { - //return NULL; // causes compile warning - return (DATA_T)0; // equivalent, but removes warning - } -} - -template -inline INDEX_T LLPtrSkipMap::getFirstKey() -{ - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); - if (mCurrentp) - { - mCurrentOperatingp = mCurrentp; - mCurrentp = mCurrentp->mForward[0]; - return mCurrentOperatingp->mIndex; - } - else - { - return mHead.mIndex; - } -} - -#endif diff --git a/indra/llcommon/llptrto.h b/indra/llcommon/llptrto.h index 7091d36f6b..e1839beb56 100644 --- a/indra/llcommon/llptrto.h +++ b/indra/llcommon/llptrto.h @@ -31,12 +31,10 @@ #if ! defined(LL_LLPTRTO_H) #define LL_LLPTRTO_H +#include #include "llpointer.h" #include "llrefcount.h" // LLRefCount #include "llthread.h" // LLThreadSafeRefCount -#include -#include -#include /** * LLPtrTo::type is either of two things: @@ -56,14 +54,14 @@ struct LLPtrTo /// specialize for subclasses of LLRefCount template -struct LLPtrTo >::type> +struct LLPtrTo::value>::type> { typedef LLPointer type; }; /// specialize for subclasses of LLThreadSafeRefCount template -struct LLPtrTo >::type> +struct LLPtrTo::value>::type> { typedef LLPointer type; }; @@ -74,7 +72,7 @@ struct LLPtrTo struct LLRemovePointer { - typedef typename boost::remove_pointer::type type; + typedef typename std::remove_pointer::type type; }; /// specialize for LLPointer diff --git a/indra/llcommon/llqueuedthread.cpp b/indra/llcommon/llqueuedthread.cpp index e9c0a2493c..8fe3acf542 100644 --- a/indra/llcommon/llqueuedthread.cpp +++ b/indra/llcommon/llqueuedthread.cpp @@ -35,7 +35,7 @@ LLQueuedThread::LLQueuedThread(const std::string& name, bool threaded, bool should_pause) : LLThread(name), mThreaded(threaded), - mIdleThread(TRUE), + mIdleThread(true), mNextHandle(0), mStarted(FALSE) { @@ -80,7 +80,7 @@ void LLQueuedThread::shutdown() } if (timeout == 0) { - llwarns << "~LLQueuedThread (" << mName << ") timed out!" << llendl; + LL_WARNS() << "~LLQueuedThread (" << mName << ") timed out!" << LL_ENDL; } } else @@ -101,7 +101,7 @@ void LLQueuedThread::shutdown() } if (active_count) { - llwarns << "~LLQueuedThread() called with active requests: " << active_count << llendl; + LL_WARNS() << "~LLQueuedThread() called with active requests: " << active_count << LL_ENDL; } } @@ -198,11 +198,11 @@ void LLQueuedThread::printQueueStats() if (!mRequestQueue.empty()) { QueuedRequest *req = *mRequestQueue.begin(); - llinfos << llformat("Pending Requests:%d Current status:%d", mRequestQueue.size(), req->getStatus()) << llendl; + LL_INFOS() << llformat("Pending Requests:%d Current status:%d", mRequestQueue.size(), req->getStatus()) << LL_ENDL; } else { - llinfos << "Queued Thread Idle" << llendl; + LL_INFOS() << "Queued Thread Idle" << LL_ENDL; } unlockData(); } @@ -233,7 +233,7 @@ bool LLQueuedThread::addRequest(QueuedRequest* req) mRequestQueue.insert(req); mRequestHash.insert(req); #if _DEBUG -// llinfos << llformat("LLQueuedThread::Added req [%08d]",handle) << llendl; +// LL_INFOS() << llformat("LLQueuedThread::Added req [%08d]",handle) << LL_ENDL; #endif unlockData(); @@ -364,7 +364,7 @@ bool LLQueuedThread::completeRequest(handle_t handle) llassert_always(req->getStatus() != STATUS_QUEUED); llassert_always(req->getStatus() != STATUS_INPROGRESS); #if _DEBUG -// llinfos << llformat("LLQueuedThread::Completed req [%08d]",handle) << llendl; +// LL_INFOS() << llformat("LLQueuedThread::Completed req [%08d]",handle) << LL_ENDL; #endif if (!(req->getFlags() & FLAG_LOCKED)) { @@ -393,7 +393,7 @@ bool LLQueuedThread::check() { if (entry->getHashKey() > mNextHandle) { - llerrs << "Hash Error" << llendl; + LL_ERRS() << "Hash Error" << LL_ENDL; return false; } entry = entry->getNextEntry(); @@ -552,19 +552,20 @@ void LLQueuedThread::run() break; } - mIdleThread = FALSE; + mIdleThread = false; threadedUpdate(); - int res = processNextRequest(); - if (res == 0) + int pending_work = processNextRequest(); + + if (pending_work == 0) { - mIdleThread = TRUE; + mIdleThread = true; ms_sleep(1); } //LLThread::yield(); // thread should yield after each request } - llinfos << "LLQueuedThread " << mName << " EXITING." << llendl; + LL_INFOS() << "LLQueuedThread " << mName << " EXITING." << LL_ENDL; } // virtual diff --git a/indra/llcommon/llqueuedthread.h b/indra/llcommon/llqueuedthread.h index dda7bf69c1..2da59b8ed5 100644 --- a/indra/llcommon/llqueuedthread.h +++ b/indra/llcommon/llqueuedthread.h @@ -32,8 +32,6 @@ #include #include -#include "llapr.h" - #include "llthread.h" #include "llsimplehash.h" @@ -204,7 +202,7 @@ class LL_COMMON_API LLQueuedThread : public LLThread protected: BOOL mThreaded; // if false, run on main thread and do updates during update() BOOL mStarted; // required when mThreaded is false to call startThread() from update() - LLAtomic32 mIdleThread; // request queue is empty (or we are quitting) and the thread is idle + LLAtomic32 mIdleThread; // request queue is empty (or we are quitting) and the thread is idle typedef std::set request_queue_t; request_queue_t mRequestQueue; diff --git a/indra/llcommon/llrefcount.cpp b/indra/llcommon/llrefcount.cpp index 0956e16283..74f4c046f2 100644 --- a/indra/llcommon/llrefcount.cpp +++ b/indra/llcommon/llrefcount.cpp @@ -31,15 +31,15 @@ #if LL_REF_COUNT_DEBUG #include "llthread.h" -#include "llapr.h" #endif -LLRefCount::LLRefCount(const LLRefCount& other) -: mRef(0) -{ +LLRefCount::LLRefCount(const LLRefCount& other) : #if LL_REF_COUNT_DEBUG - mCrashAtUnlock = FALSE ; + mMutex(), + mCrashAtUnlock(FALSE), #endif + mRef(0) +{ } LLRefCount& LLRefCount::operator=(const LLRefCount&) @@ -49,18 +49,19 @@ LLRefCount& LLRefCount::operator=(const LLRefCount&) } LLRefCount::LLRefCount() : - mRef(0) -{ #if LL_REF_COUNT_DEBUG - mCrashAtUnlock = FALSE ; + mMutex(), + mCrashAtUnlock(FALSE), #endif + mRef(0) +{ } LLRefCount::~LLRefCount() { if (mRef != 0) { - llerrs << "deleting non-zero reference" << llendl; + LL_ERRS() << "deleting non-zero reference" << LL_ENDL; } } @@ -70,8 +71,8 @@ void LLRefCount::ref() const if(mMutex.isLocked()) { mCrashAtUnlock = TRUE ; - llerrs << "the mutex is locked by the thread: " << mLockedThreadID - << " Current thread: " << AIThreadID() << llendl ; + LL_ERRS() << "the mutex is locked by the thread: " << mLockedThreadID + << " Current thread: " << AIThreadID() << LL_ENDL ; } mMutex.lock() ; @@ -91,8 +92,8 @@ S32 LLRefCount::unref() const if(mMutex.isLocked()) { mCrashAtUnlock = TRUE ; - llerrs << "the mutex is locked by the thread: " << mLockedThreadID - << " Current thread: " << AIThreadID() << llendl ; + LL_ERRS() << "the mutex is locked by the thread: " << mLockedThreadID + << " Current thread: " << AIThreadID() << LL_ENDL ; } mMutex.lock() ; diff --git a/indra/llcommon/llrefcount.h b/indra/llcommon/llrefcount.h index b7831e7fa4..4df84028a8 100644 --- a/indra/llcommon/llrefcount.h +++ b/indra/llcommon/llrefcount.h @@ -27,6 +27,9 @@ #define LLREFCOUNT_H #include +#include "llpreprocessor.h" // LL_COMMON_API +#include "stdtypes.h" // S32 +#include "llerror.h" // llassert #define LL_REF_COUNT_DEBUG 0 #if LL_REF_COUNT_DEBUG diff --git a/indra/llcommon/llregistry.h b/indra/llcommon/llregistry.h index ca6d76a989..133cab5eef 100644 --- a/indra/llcommon/llregistry.h +++ b/indra/llcommon/llregistry.h @@ -29,7 +29,9 @@ #include -#include +//#include +#include +#include #include "llsingleton.h" #include "llstl.h" @@ -64,7 +66,7 @@ class LLRegistry { if (mMap.insert(std::make_pair(key, value)).second == false) { - llwarns << "Tried to register " << key << " but it was already registered!" << llendl; + LL_WARNS() << "Tried to register " << key << " but it was already registered!" << LL_ENDL; return false; } return true; @@ -307,8 +309,10 @@ class LLRegistrySingleton virtual ~StaticRegistrar() {} StaticRegistrar(ref_const_key_t key, ref_const_value_t value) { - if(!singleton_t::instance().mStaticScope) - mStaticScope = new ScopedRegistrar(); + if (singleton_t::instance().exists(key)) + { + LL_ERRS() << "Duplicate registry entry under key \"" << key << "\"" << LL_ENDL; + } singleton_t::instance().mStaticScope->add(key, value); } }; @@ -338,7 +342,7 @@ class LLRegistrySingleton virtual void initSingleton() { - //mStaticScope = new ScopedRegistrar(); + mStaticScope = new ScopedRegistrar(); } virtual ~LLRegistrySingleton() diff --git a/indra/llcommon/llrun.cpp b/indra/llcommon/llrun.cpp index e2f69ff13d..3edfef429e 100644 --- a/indra/llcommon/llrun.cpp +++ b/indra/llcommon/llrun.cpp @@ -53,7 +53,7 @@ LLRunner::~LLRunner() mRunEvery.clear(); } -S32 LLRunner::run() +size_t LLRunner::run() { // We collect all of the runnables which should be run. Since the // runnables are allowed to adjust the run list, we need to copy diff --git a/indra/llcommon/llrun.h b/indra/llcommon/llrun.h index 1fc9925df9..8cc524ce74 100644 --- a/indra/llcommon/llrun.h +++ b/indra/llcommon/llrun.h @@ -37,6 +37,8 @@ #include #include +#include "llpreprocessor.h" +#include "stdtypes.h" class LLRunnable; @@ -54,7 +56,7 @@ class LL_COMMON_API LLRunner /** * @brief The pointer to a runnable. */ - typedef boost::shared_ptr run_ptr_t; + typedef std::shared_ptr run_ptr_t; /** * @brief The handle for use in the API. @@ -91,7 +93,7 @@ class LL_COMMON_API LLRunner * * @return Returns the number of runnables run. */ - S32 run(); + size_t run(); /** * @brief Add a runnable to the run list. diff --git a/indra/llcommon/llsafehandle.h b/indra/llcommon/llsafehandle.h index 8d52d9bb15..4226bf04f0 100644 --- a/indra/llcommon/llsafehandle.h +++ b/indra/llcommon/llsafehandle.h @@ -134,7 +134,7 @@ class LLSafeHandle tempp->unref(); if (mPointer != NULL) { - llwarns << "Unreference did assignment to non-NULL because of destructor" << llendl; + LL_WARNS() << "Unreference did assignment to non-NULL because of destructor" << LL_ENDL; unref(); } } diff --git a/indra/llcommon/llsd.cpp b/indra/llcommon/llsd.cpp index 61c4ca08d1..73a0ab3e71 100644 --- a/indra/llcommon/llsd.cpp +++ b/indra/llcommon/llsd.cpp @@ -24,13 +24,16 @@ * $/LicenseInfo$ */ +// Must turn on conditional declarations in header file so definitions end up +// with proper linkage. +#define LLSD_DEBUG_INFO #include "linden_common.h" #include "llsd.h" #include "llerror.h" -#include "../llmath/llmath.h" #include "llformat.h" #include "llsdserialize.h" +#include "stringize.h" #ifndef LL_RELEASE_FOR_DOWNLOAD #define NAME_UNNAMED_NAMESPACE @@ -50,6 +53,18 @@ namespace using namespace LLSDUnnamedNamespace; #endif +namespace llsd +{ + +// statics +S32 sLLSDAllocationCount = 0; +S32 sLLSDNetObjects = 0; + +} // namespace llsd + +#define ALLOC_LLSD_OBJECT { llsd::sLLSDNetObjects++; llsd::sLLSDAllocationCount++; } +#define FREE_LLSD_OBJECT { llsd::sLLSDNetObjects--; } + class LLSD::Impl /**< This class is the abstract base class of the implementation of LLSD It provides the reference counting implementation, and the default @@ -58,13 +73,10 @@ class LLSD::Impl */ { -private: - U32 mUseCount; - protected: Impl(); - enum StaticAllocationMarker { STATIC }; + enum StaticAllocationMarker { STATIC_USAGE_COUNT = 0xFFFFFFFF }; Impl(StaticAllocationMarker); ///< This constructor is used for static objects and causes the // suppresses adjusting the debugging counters when they are @@ -72,8 +84,10 @@ class LLSD::Impl virtual ~Impl(); - bool shared() const { return mUseCount > 1; } + bool shared() const { return (mUseCount > 1) && (mUseCount != STATIC_USAGE_COUNT); } + U32 mUseCount; + public: static void reset(Impl*& var, Impl* impl); ///< safely set var to refer to the new impl (possibly shared) @@ -111,10 +125,13 @@ class LLSD::Impl virtual UUID asUUID() const { return LLUUID(); } virtual Date asDate() const { return LLDate(); } virtual URI asURI() const { return LLURI(); } - virtual Binary asBinary() const { return std::vector(); } + virtual const Binary& asBinary() const { static const std::vector empty; return empty; } + virtual const String& asStringRef() const { static const std::string empty; return empty; } + virtual bool has(const String&) const { return false; } virtual LLSD get(const String&) const { return LLSD(); } + virtual LLSD getKeys() const { return LLSD::emptyArray(); } virtual void erase(const String&) { } virtual const LLSD& ref(const String&) const{ return undef(); } @@ -123,10 +140,26 @@ class LLSD::Impl virtual void erase(Integer) { } virtual const LLSD& ref(Integer) const { return undef(); } - virtual LLSD::map_const_iterator beginMap() const { return endMap(); } - virtual LLSD::map_const_iterator endMap() const { static const std::map empty; return empty.end(); } - virtual LLSD::array_const_iterator beginArray() const { return endArray(); } - virtual LLSD::array_const_iterator endArray() const { static const std::vector empty; return empty.end(); } + virtual const std::map& map() const { static const std::map empty; return empty; } + virtual std::map& map() { static std::map empty; return empty; } + LLSD::map_const_iterator beginMap() const { return map().begin(); } + LLSD::map_const_iterator endMap() const { return map().end(); } + virtual const std::vector& array() const { static const std::vector empty; return empty; } + virtual std::vector& array() { static std::vector empty; return empty; } + LLSD::array_const_iterator beginArray() const { return array().begin(); } + LLSD::array_const_iterator endArray() const { return array().end(); } + + virtual void dumpStats() const; + virtual void calcStats(S32 type_counts[], S32 share_counts[]) const; + // Container subclasses contain LLSD objects, rather than directly + // containing Impl objects. This helper forwards through LLSD. + void calcStats(const LLSD& llsd, S32 type_counts[], S32 share_counts[]) const + { + safe(llsd.impl).calcStats(type_counts, share_counts); + } + + static const Impl& getImpl(const LLSD& llsd) { return safe(llsd.impl); } + static Impl& getImpl(LLSD& llsd) { return safe(llsd.impl); } static const LLSD& undef(); @@ -154,10 +187,11 @@ namespace public: ImplBase(DataRef value) : mValue(value) { } - virtual LLSD::Type type() const { return T; } + LLSD::Type type() const override { return T; } using LLSD::Impl::assign; // Unhiding base class virtuals... - virtual void assign(LLSD::Impl*& var, DataRef value) { + void assign(LLSD::Impl*& var, DataRef value) override + { if (shared()) { Impl::assign(var, value); @@ -170,16 +204,16 @@ namespace }; - class ImplBoolean + class ImplBoolean final : public ImplBase { public: ImplBoolean(LLSD::Boolean v) : Base(v) { } - virtual LLSD::Boolean asBoolean() const { return mValue; } - virtual LLSD::Integer asInteger() const { return mValue ? 1 : 0; } - virtual LLSD::Real asReal() const { return mValue ? 1 : 0; } - virtual LLSD::String asString() const; + LLSD::Boolean asBoolean() const override { return mValue; } + LLSD::Integer asInteger() const override { return mValue ? 1 : 0; } + LLSD::Real asReal() const override { return mValue ? 1 : 0; } + LLSD::String asString() const override; }; LLSD::String ImplBoolean::asString() const @@ -191,57 +225,59 @@ namespace { return mValue ? "true" : ""; } - class ImplInteger + class ImplInteger final : public ImplBase { public: ImplInteger(LLSD::Integer v) : Base(v) { } - virtual LLSD::Boolean asBoolean() const { return mValue != 0; } - virtual LLSD::Integer asInteger() const { return mValue; } - virtual LLSD::Real asReal() const { return mValue; } - virtual LLSD::String asString() const; + LLSD::Boolean asBoolean() const override { return mValue != 0; } + LLSD::Integer asInteger() const override { return mValue; } + LLSD::Real asReal() const override { return mValue; } + LLSD::String asString() const override; }; LLSD::String ImplInteger::asString() const { return llformat("%d", mValue); } - class ImplReal + class ImplReal final : public ImplBase { public: ImplReal(LLSD::Real v) : Base(v) { } - virtual LLSD::Boolean asBoolean() const; - virtual LLSD::Integer asInteger() const; - virtual LLSD::Real asReal() const { return mValue; } - virtual LLSD::String asString() const; + LLSD::Boolean asBoolean() const override; + LLSD::Integer asInteger() const override; + LLSD::Real asReal() const override { return mValue; } + LLSD::String asString() const override; }; LLSD::Boolean ImplReal::asBoolean() const - { return !llisnan(mValue) && mValue != 0.0; } + { return !std::isnan(mValue) && mValue != 0.0; } LLSD::Integer ImplReal::asInteger() const - { return !llisnan(mValue) ? (LLSD::Integer)mValue : 0; } + { return !std::isnan(mValue) ? (LLSD::Integer)mValue : 0; } LLSD::String ImplReal::asString() const { return llformat("%lg", mValue); } - class ImplString + class ImplString final : public ImplBase { public: ImplString(const LLSD::String& v) : Base(v) { } - virtual LLSD::Boolean asBoolean() const { return !mValue.empty(); } - virtual LLSD::Integer asInteger() const; - virtual LLSD::Real asReal() const; - virtual LLSD::String asString() const { return mValue; } - virtual LLSD::UUID asUUID() const { return LLUUID(mValue); } - virtual LLSD::Date asDate() const { return LLDate(mValue); } - virtual LLSD::URI asURI() const { return LLURI(mValue); } + LLSD::Boolean asBoolean() const override { return !mValue.empty(); } + LLSD::Integer asInteger() const override; + LLSD::Real asReal() const override; + LLSD::String asString() const override { return mValue; } + LLSD::UUID asUUID() const override { return LLUUID(mValue); } + LLSD::Date asDate() const override { return LLDate(mValue); } + LLSD::URI asURI() const override { return LLURI(mValue); } + int size() const override { return mValue.size(); } + const LLSD::String& asStringRef() const override { return mValue; } }; LLSD::Integer ImplString::asInteger() const @@ -271,18 +307,18 @@ namespace } - class ImplUUID + class ImplUUID final : public ImplBase { public: ImplUUID(const LLSD::UUID& v) : Base(v) { } - virtual LLSD::String asString() const{ return mValue.asString(); } - virtual LLSD::UUID asUUID() const { return mValue; } + LLSD::String asString() const override { return mValue.asString(); } + LLSD::UUID asUUID() const override { return mValue; } }; - class ImplDate + class ImplDate final : public ImplBase { public: @@ -290,41 +326,42 @@ namespace : ImplBase(v) { } - virtual LLSD::Integer asInteger() const + LLSD::Integer asInteger() const override { return (LLSD::Integer)(mValue.secondsSinceEpoch()); } - virtual LLSD::Real asReal() const + LLSD::Real asReal() const override { return mValue.secondsSinceEpoch(); } - virtual LLSD::String asString() const{ return mValue.asString(); } - virtual LLSD::Date asDate() const { return mValue; } + + LLSD::String asString() const override { return mValue.asString(); } + LLSD::Date asDate() const override { return mValue; } }; - class ImplURI + class ImplURI final : public ImplBase { public: ImplURI(const LLSD::URI& v) : Base(v) { } - virtual LLSD::String asString() const{ return mValue.asString(); } - virtual LLSD::URI asURI() const { return mValue; } + LLSD::String asString() const override { return mValue.asString(); } + LLSD::URI asURI() const override { return mValue; } }; - class ImplBinary + class ImplBinary final : public ImplBase { public: ImplBinary(const LLSD::Binary& v) : Base(v) { } - virtual LLSD::Binary asBinary() const{ return mValue; } + const LLSD::Binary& asBinary() const override { return mValue; } }; - class ImplMap : public LLSD::Impl + class ImplMap final : public LLSD::Impl { private: typedef std::map DataMap; @@ -337,29 +374,31 @@ namespace public: ImplMap() { } - virtual ImplMap& makeMap(LLSD::Impl*&); + ImplMap& makeMap(LLSD::Impl*&) override; - virtual LLSD::Type type() const { return LLSD::TypeMap; } + LLSD::Type type() const override { return LLSD::TypeMap; } - virtual LLSD::Boolean asBoolean() const { return !mData.empty(); } + LLSD::Boolean asBoolean() const override { return !mData.empty(); } - virtual bool has(const LLSD::String&) const; + bool has(const LLSD::String&) const override; using LLSD::Impl::get; // Unhiding get(LLSD::Integer) using LLSD::Impl::erase; // Unhiding erase(LLSD::Integer) using LLSD::Impl::ref; // Unhiding ref(LLSD::Integer) - virtual LLSD get(const LLSD::String&) const; + LLSD get(const LLSD::String&) const override; + LLSD getKeys() const override; void insert(const LLSD::String& k, const LLSD& v); - virtual void erase(const LLSD::String&); + void erase(const LLSD::String&) override; LLSD& ref(const LLSD::String&); - virtual const LLSD& ref(const LLSD::String&) const; + const LLSD& ref(const LLSD::String&) const override; - virtual int size() const { return mData.size(); } + int size() const override { return mData.size(); } - LLSD::map_iterator beginMap() { return mData.begin(); } - LLSD::map_iterator endMap() { return mData.end(); } - virtual LLSD::map_const_iterator beginMap() const { return mData.begin(); } - virtual LLSD::map_const_iterator endMap() const { return mData.end(); } + DataMap& map() final override { return mData; } + const DataMap& map() const final override { return mData; } + + void dumpStats() const override; + void calcStats(S32 type_counts[], S32 share_counts[]) const override; }; ImplMap& ImplMap::makeMap(LLSD::Impl*& var) @@ -388,6 +427,18 @@ namespace return (i != mData.end()) ? i->second : LLSD(); } + LLSD ImplMap::getKeys() const + { + LLSD keys = LLSD::emptyArray(); + DataMap::const_iterator iter = mData.begin(); + while (iter != mData.end()) + { + keys.append((*iter).first); + iter++; + } + return keys; + } + void ImplMap::insert(const LLSD::String& k, const LLSD& v) { mData.insert(DataMap::value_type(k, v)); @@ -414,7 +465,35 @@ namespace return i->second; } - class ImplArray : public LLSD::Impl + void ImplMap::dumpStats() const + { + std::cout << "Map size: " << mData.size() << std::endl; + + std::cout << "LLSD Net Objects: " << llsd::sLLSDNetObjects << std::endl; + std::cout << "LLSD allocations: " << llsd::sLLSDAllocationCount << std::endl; + + std::cout << "LLSD::Impl Net Objects: " << sOutstandingCount << std::endl; + std::cout << "LLSD::Impl allocations: " << sAllocationCount << std::endl; + + Impl::dumpStats(); + } + + void ImplMap::calcStats(S32 type_counts[], S32 share_counts[]) const + { + LLSD::map_const_iterator iter = beginMap(); + while (iter != endMap()) + { + //std::cout << " " << (*iter).first << ": " << (*iter).second << std::endl; + Impl::calcStats((*iter).second, type_counts, share_counts); + ++iter; + } + + // Add in the values for this map + Impl::calcStats(type_counts, share_counts); + } + + + class ImplArray final : public LLSD::Impl { private: typedef std::vector DataVector; @@ -427,28 +506,28 @@ namespace public: ImplArray() { } - virtual ImplArray& makeArray(Impl*&); + ImplArray& makeArray(Impl*&) override; - virtual LLSD::Type type() const { return LLSD::TypeArray; } + LLSD::Type type() const override { return LLSD::TypeArray; } - virtual LLSD::Boolean asBoolean() const { return !mData.empty(); } + LLSD::Boolean asBoolean() const override { return !mData.empty(); } using LLSD::Impl::get; // Unhiding get(LLSD::String) using LLSD::Impl::erase; // Unhiding erase(LLSD::String) using LLSD::Impl::ref; // Unhiding ref(LLSD::String) - virtual int size() const; - virtual LLSD get(LLSD::Integer) const; + int size() const override; + LLSD get(LLSD::Integer) const override; void set(LLSD::Integer, const LLSD&); void insert(LLSD::Integer, const LLSD&); - void append(const LLSD&); - virtual void erase(LLSD::Integer); + LLSD& append(const LLSD&); + void erase(LLSD::Integer) override; LLSD& ref(LLSD::Integer); - virtual const LLSD& ref(LLSD::Integer) const; + const LLSD& ref(LLSD::Integer) const override; - LLSD::array_iterator beginArray() { return mData.begin(); } - LLSD::array_iterator endArray() { return mData.end(); } - virtual LLSD::array_const_iterator beginArray() const { return mData.begin(); } - virtual LLSD::array_const_iterator endArray() const { return mData.end(); } + DataVector& array() final override { return mData; } + const DataVector& array() const final override { return mData; } + + void calcStats(S32 type_counts[], S32 share_counts[]) const override; }; ImplArray& ImplArray::makeArray(Impl*& var) @@ -504,9 +583,10 @@ namespace mData.insert(mData.begin() + index, v); } - void ImplArray::append(const LLSD& v) + LLSD& ImplArray::append(const LLSD& v) { mData.push_back(v); + return mData.back(); } void ImplArray::erase(LLSD::Integer i) @@ -544,6 +624,19 @@ namespace return mData[index]; } + + void ImplArray::calcStats(S32 type_counts[], S32 share_counts[]) const + { + LLSD::array_const_iterator iter = beginArray(); + while (iter != endArray()) + { // Add values for all items held in the array + Impl::calcStats((*iter), type_counts, share_counts); + ++iter; + } + + // Add in the values for this array + Impl::calcStats(type_counts, share_counts); + } } LLSD::Impl::Impl() @@ -565,8 +658,11 @@ LLSD::Impl::~Impl() void LLSD::Impl::reset(Impl*& var, Impl* impl) { - if (impl) ++impl->mUseCount; - if (var && --var->mUseCount == 0) + if (impl && impl->mUseCount != STATIC_USAGE_COUNT) + { + ++impl->mUseCount; + } + if (var && var->mUseCount != STATIC_USAGE_COUNT && --var->mUseCount == 0) { delete var; } @@ -575,13 +671,13 @@ void LLSD::Impl::reset(Impl*& var, Impl* impl) LLSD::Impl& LLSD::Impl::safe(Impl* impl) { - static Impl theUndefined(STATIC); + static Impl theUndefined(STATIC_USAGE_COUNT); return impl ? *impl : theUndefined; } const LLSD::Impl& LLSD::Impl::safe(const Impl* impl) { - static Impl theUndefined(STATIC); + static Impl theUndefined(STATIC_USAGE_COUNT); return impl ? *impl : theUndefined; } @@ -607,7 +703,7 @@ void LLSD::Impl::assign(Impl*& var, const Impl* other) void LLSD::Impl::assignUndefined(Impl*& var) { - reset(var, 0); + reset(var, nullptr); } void LLSD::Impl::assign(Impl*& var, LLSD::Boolean v) @@ -657,6 +753,41 @@ const LLSD& LLSD::Impl::undef() return immutableUndefined; } +void LLSD::Impl::dumpStats() const +{ + S32 type_counts[LLSD::TypeLLSDNumTypes + 1] = {0}; + + S32 share_counts[LLSD::TypeLLSDNumTypes + 1] = {0}; + + // Add info from all the values this object has + calcStats(type_counts, share_counts); + + S32 type_index = LLSD::TypeLLSDTypeBegin; + while (type_index != LLSD::TypeLLSDTypeEnd) + { + std::cout << LLSD::typeString((LLSD::Type)type_index) << " type " + << type_counts[type_index] << " objects, " + << share_counts[type_index] << " shared" + << std::endl; + type_index++; + } +} + + +void LLSD::Impl::calcStats(S32 type_counts[], S32 share_counts[]) const +{ + S32 tp = S32(type()); + if (0 <= tp && tp < LLSD::TypeLLSDNumTypes) + { + type_counts[tp]++; + if (shared()) + { + share_counts[tp]++; + } + } +} + + U32 LLSD::Impl::sAllocationCount = 0; U32 LLSD::Impl::sOutstandingCount = 0; @@ -682,10 +813,10 @@ namespace } -LLSD::LLSD() : impl(0) { } -LLSD::~LLSD() { Impl::reset(impl, 0); } +LLSD::LLSD() : impl(nullptr) { ALLOC_LLSD_OBJECT; } +LLSD::~LLSD() { FREE_LLSD_OBJECT; Impl::reset(impl, nullptr); } -LLSD::LLSD(const LLSD& other) : impl(0) { assign(other); } +LLSD::LLSD(const LLSD& other) : impl(nullptr) { ALLOC_LLSD_OBJECT; assign(other); } void LLSD::assign(const LLSD& other) { Impl::assign(impl, other.impl); } @@ -693,18 +824,18 @@ void LLSD::clear() { Impl::assignUndefined(impl); } LLSD::Type LLSD::type() const { return safe(impl).type(); } -// Scaler Constructors -LLSD::LLSD(Boolean v) : impl(0) { assign(v); } -LLSD::LLSD(Integer v) : impl(0) { assign(v); } -LLSD::LLSD(Real v) : impl(0) { assign(v); } -LLSD::LLSD(const UUID& v) : impl(0) { assign(v); } -LLSD::LLSD(const String& v) : impl(0) { assign(v); } -LLSD::LLSD(const Date& v) : impl(0) { assign(v); } -LLSD::LLSD(const URI& v) : impl(0) { assign(v); } -LLSD::LLSD(const Binary& v) : impl(0) { assign(v); } +// Scalar Constructors +LLSD::LLSD(Boolean v) : impl(nullptr) { ALLOC_LLSD_OBJECT; assign(v); } +LLSD::LLSD(Integer v) : impl(nullptr) { ALLOC_LLSD_OBJECT; assign(v); } +LLSD::LLSD(Real v) : impl(nullptr) { ALLOC_LLSD_OBJECT; assign(v); } +LLSD::LLSD(const UUID& v) : impl(nullptr) { ALLOC_LLSD_OBJECT; assign(v); } +LLSD::LLSD(const String& v) : impl(nullptr) { ALLOC_LLSD_OBJECT; assign(v); } +LLSD::LLSD(const Date& v) : impl(nullptr) { ALLOC_LLSD_OBJECT; assign(v); } +LLSD::LLSD(const URI& v) : impl(nullptr) { ALLOC_LLSD_OBJECT; assign(v); } +LLSD::LLSD(const Binary& v) : impl(nullptr) { ALLOC_LLSD_OBJECT; assign(v); } // Convenience Constructors -LLSD::LLSD(F32 v) : impl(0) { assign((Real)v); } +LLSD::LLSD(F32 v) : impl(nullptr) { ALLOC_LLSD_OBJECT; assign((Real)v); } // Scalar Assignment void LLSD::assign(Boolean v) { safe(impl).assign(impl, v); } @@ -724,10 +855,12 @@ LLSD::String LLSD::asString() const { return safe(impl).asString(); } LLSD::UUID LLSD::asUUID() const { return safe(impl).asUUID(); } LLSD::Date LLSD::asDate() const { return safe(impl).asDate(); } LLSD::URI LLSD::asURI() const { return safe(impl).asURI(); } -LLSD::Binary LLSD::asBinary() const { return safe(impl).asBinary(); } +const LLSD::Binary& LLSD::asBinary() const { return safe(impl).asBinary(); } + +const LLSD::String& LLSD::asStringRef() const { return safe(impl).asStringRef(); } // const char * helpers -LLSD::LLSD(const char* v) : impl(0) { assign(v); } +LLSD::LLSD(const char* v) : impl(nullptr) { ALLOC_LLSD_OBJECT; assign(v); } void LLSD::assign(const char* v) { if(v) assign(std::string(v)); @@ -744,6 +877,7 @@ LLSD LLSD::emptyMap() bool LLSD::has(const String& k) const { return safe(impl).has(k); } LLSD LLSD::get(const String& k) const { return safe(impl).get(k); } +LLSD LLSD::getKeys() const { return safe(impl).getKeys(); } void LLSD::insert(const String& k, const LLSD& v) { makeMap(impl).insert(k, v); } LLSD& LLSD::with(const String& k, const LLSD& v) @@ -777,7 +911,7 @@ LLSD& LLSD::with(Integer i, const LLSD& v) makeArray(impl).insert(i, v); return *this; } -void LLSD::append(const LLSD& v) { makeArray(impl).append(v); } +LLSD& LLSD::append(const LLSD& v) { return makeArray(impl).append(v); } void LLSD::erase(Integer i) { makeArray(impl).erase(i); } LLSD& LLSD::operator[](Integer i) @@ -785,9 +919,6 @@ LLSD& LLSD::operator[](Integer i) const LLSD& LLSD::operator[](Integer i) const { return safe(impl).ref(i); } -U32 LLSD::allocationCount() { return Impl::sAllocationCount; } -U32 LLSD::outstandingCount() { return Impl::sOutstandingCount; } - static const char *llsd_dump(const LLSD &llsd, bool useXMLFormat) { // sStorage is used to hold the string representation of the llsd last @@ -796,24 +927,18 @@ static const char *llsd_dump(const LLSD &llsd, bool useXMLFormat) // sStorage will point to the result of the last call. This will actually // be one leak, but since this is used only when running under the // debugger, it should not be an issue. - static char *sStorage = NULL; + static char *sStorage = nullptr; delete[] sStorage; std::string out_string; { std::ostringstream out; if (useXMLFormat) - { - LLSDXMLStreamer xml_streamer(llsd); - out << xml_streamer; - } + out << LLSDXMLStreamer(llsd); else - { - LLSDNotationStreamer notation_streamer(llsd); - out << notation_streamer; - } + out << LLSDNotationStreamer(llsd); out_string = out.str(); } - int len = out_string.length(); + size_t len = out_string.length(); sStorage = new char[len + 1]; memcpy(sStorage, out_string.c_str(), len); sStorage[len] = '\0'; @@ -832,12 +957,56 @@ const char *LLSD::dump(const LLSD &llsd) return llsd_dump(llsd, false); } -LLSD::map_iterator LLSD::beginMap() { return makeMap(impl).beginMap(); } -LLSD::map_iterator LLSD::endMap() { return makeMap(impl).endMap(); } -LLSD::map_const_iterator LLSD::beginMap() const { return safe(impl).beginMap(); } -LLSD::map_const_iterator LLSD::endMap() const { return safe(impl).endMap(); } +std::map& LLSD::map() { return makeMap(impl).map(); } +const std::map& LLSD::map() const { return safe(impl).map(); } + +LLSD::map_iterator LLSD::beginMap() { return map().begin(); } +LLSD::map_iterator LLSD::endMap() { return map().end(); } +LLSD::map_const_iterator LLSD::beginMap() const { return map().cbegin(); } +LLSD::map_const_iterator LLSD::endMap() const { return map().cend(); } + +std::vector& LLSD::array() { return makeArray(impl).array(); } +const std::vector& LLSD::array() const { return safe(impl).array(); } + +LLSD::array_iterator LLSD::beginArray() { return array().begin(); } +LLSD::array_iterator LLSD::endArray() { return array().end(); } +LLSD::array_const_iterator LLSD::beginArray() const{ return array().cbegin(); } +LLSD::array_const_iterator LLSD::endArray() const { return array().cend(); } + +LLSD::reverse_array_iterator LLSD::rbeginArray() { return array().rbegin(); } +LLSD::reverse_array_iterator LLSD::rendArray() { return array().rend(); } + +namespace llsd +{ + +U32 allocationCount() { return LLSD::Impl::sAllocationCount; } +U32 outstandingCount() { return LLSD::Impl::sOutstandingCount; } + +// Diagnostic dump of contents in an LLSD object +void dumpStats(const LLSD& llsd) { LLSD::Impl::getImpl(llsd).dumpStats(); } + +} // namespace llsd + +// static +std::string LLSD::typeString(Type type) +{ + static const char * sTypeNameArray[] = { + "Undefined", + "Boolean", + "Integer", + "Real", + "String", + "UUID", + "Date", + "URI", + "Binary", + "Map", + "Array" + }; -LLSD::array_iterator LLSD::beginArray() { return makeArray(impl).beginArray(); } -LLSD::array_iterator LLSD::endArray() { return makeArray(impl).endArray(); } -LLSD::array_const_iterator LLSD::beginArray() const{ return safe(impl).beginArray(); } -LLSD::array_const_iterator LLSD::endArray() const { return safe(impl).endArray(); } + if (0 <= type && type < LL_ARRAY_SIZE(sTypeNameArray)) + { + return sTypeNameArray[type]; + } + return STRINGIZE("** invalid type value " << type); +} diff --git a/indra/llcommon/llsd.h b/indra/llcommon/llsd.h index 6e242a1631..1d8950bfc0 100644 --- a/indra/llcommon/llsd.h +++ b/indra/llcommon/llsd.h @@ -251,7 +251,10 @@ class LL_COMMON_API LLSD UUID asUUID() const; Date asDate() const; URI asURI() const; - Binary asBinary() const; + const Binary& asBinary() const; + + // asStringRef on any non-string type will return a ref to an empty string. + const String& asStringRef() const; operator Boolean() const { return asBoolean(); } operator Integer() const { return asInteger(); } @@ -284,6 +287,7 @@ class LL_COMMON_API LLSD bool has(const String&) const; LLSD get(const String&) const; + LLSD getKeys() const; // Return an LLSD array with keys as strings void insert(const String&, const LLSD&); void erase(const String&); LLSD& with(const String&, const LLSD&); @@ -301,7 +305,7 @@ class LL_COMMON_API LLSD LLSD get(Integer) const; void set(Integer, const LLSD&); void insert(Integer, const LLSD&); - void append(const LLSD&); + LLSD& append(const LLSD&); void erase(Integer); LLSD& with(Integer, const LLSD&); @@ -316,6 +320,8 @@ class LL_COMMON_API LLSD typedef std::map::iterator map_iterator; typedef std::map::const_iterator map_const_iterator; + std::map& map(); + const std::map& map() const; map_iterator beginMap(); map_iterator endMap(); map_const_iterator beginMap() const; @@ -323,11 +329,17 @@ class LL_COMMON_API LLSD typedef std::vector::iterator array_iterator; typedef std::vector::const_iterator array_const_iterator; + typedef std::vector::reverse_iterator reverse_array_iterator; + std::vector& array(); + const std::vector& array() const; array_iterator beginArray(); array_iterator endArray(); array_const_iterator beginArray() const; array_const_iterator endArray() const; + + reverse_array_iterator rbeginArray(); + reverse_array_iterator rendArray(); //@} /** @name Type Testing */ @@ -377,9 +389,9 @@ class LL_COMMON_API LLSD using an arbitrary pointer or scalar type to std::string. */ //@{ - LLSD(const void*); ///< construct from aribrary pointers - void assign(const void*); ///< assign from arbitrary pointers - LLSD& operator=(const void*); ///< assign from arbitrary pointers + LLSD(const void*) = delete; ///< construct from aribrary pointers + void assign(const void*) = delete; ///< assign from arbitrary pointers + LLSD& operator=(const void*) = delete; ///< assign from arbitrary pointers bool has(Integer) const; ///< has() only works for Maps //@} @@ -390,13 +402,7 @@ class LL_COMMON_API LLSD class Impl; private: Impl* impl; - //@} - - /** @name Unit Testing Interface */ - //@{ -public: - static U32 allocationCount(); ///< how many Impls have been made - static U32 outstandingCount(); ///< how many Impls are still alive + friend class LLSD::Impl; //@} private: @@ -408,6 +414,10 @@ class LL_COMMON_API LLSD /// Returns Notation version of llsd -- only to be called from debugger static const char *dump(const LLSD &llsd); //@} + +public: + + static std::string typeString(Type type); // Return human-readable type as a string }; struct llsd_select_bool : public std::unary_function @@ -455,6 +465,29 @@ struct llsd_select_string : public std::unary_function LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLSD& llsd); +namespace llsd +{ + +#ifdef LLSD_DEBUG_INFO +/** @name Unit Testing Interface */ +//@{ + LL_COMMON_API void dumpStats(const LLSD&); ///< Output information on object and usage + + /// @warn THE FOLLOWING COUNTS WILL NOT BE ACCURATE IN A MULTI-THREADED + /// ENVIRONMENT. + /// + /// These counts track LLSD::Impl (hidden) objects. + LL_COMMON_API U32 allocationCount(); ///< how many Impls have been made + LL_COMMON_API U32 outstandingCount(); ///< how many Impls are still alive + + /// These counts track LLSD (public) objects. + LL_COMMON_API extern S32 sLLSDAllocationCount; ///< Number of LLSD objects ever created + LL_COMMON_API extern S32 sLLSDNetObjects; ///< Number of LLSD objects that exist +#endif +//@} + +} // namespace llsd + /** QUESTIONS & TO DOS - Would Binary be more convenient as unsigned char* buffer semantics? - Should Binary be convertible to/from String, and if so how? diff --git a/indra/llcommon/llsdjson.cpp b/indra/llcommon/llsdjson.cpp new file mode 100644 index 0000000000..a31128dd83 --- /dev/null +++ b/indra/llcommon/llsdjson.cpp @@ -0,0 +1,137 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +/** + * @file llsdjson.cpp + * @brief LLSD flexible data system + * + * $LicenseInfo:firstyear=2015&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2015, 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$ + */ + +// Must turn on conditional declarations in header file so definitions end up +// with proper linkage. +#define LLSD_DEBUG_INFO +#include "linden_common.h" + +#include "llsdjson.h" + +#include "llerror.h" + + +//========================================================================= +LLSD LlsdFromJson(const nlohmann::json &val) +{ + LLSD result; + + switch (val.type()) + { + default: + case nlohmann::json::value_t::null: + break; + case nlohmann::json::value_t::number_integer: + result = LLSD(val.get()); + break; + case nlohmann::json::value_t::number_unsigned: + result = LLSD(val.get()); + break; + case nlohmann::json::value_t::number_float: + result = LLSD(val.get()); + break; + case nlohmann::json::value_t::string: + result = LLSD(val.get()); + break; + case nlohmann::json::value_t::boolean: + result = LLSD(val.get()); + break; + case nlohmann::json::value_t::array: + result = LLSD::emptyArray(); + for (const auto &element : val) + { + result.append(LlsdFromJson(element)); + } + break; + case nlohmann::json::value_t::object: + result = LLSD::emptyMap(); + for (auto it = val.cbegin(); it != val.cend(); ++it) + { + result[it.key()] = LlsdFromJson(it.value()); + } + break; + } + return result; +} + +LLSD LlsdFromJsonString(const std::string& str) +{ + auto json = nlohmann::json::parse(str, nullptr, false); + if (json.is_discarded()) + { + LL_WARNS() << "Cannot parse invalid json string:\n" << str << LL_ENDL; + return LLSD(); + } + return LlsdFromJson(json); +} + +//========================================================================= +nlohmann::json LlsdToJson(const LLSD &val) +{ + nlohmann::json result; + + switch (val.type()) + { + case LLSD::TypeUndefined: + result = nullptr; + break; + case LLSD::TypeBoolean: + result = val.asBoolean(); + break; + case LLSD::TypeInteger: + result = val.asInteger(); + break; + case LLSD::TypeReal: + result = val.asReal(); + break; + case LLSD::TypeURI: + case LLSD::TypeDate: + case LLSD::TypeUUID: + case LLSD::TypeString: + result = val.asString(); + break; + case LLSD::TypeMap: + for (LLSD::map_const_iterator it = val.beginMap(); it != val.endMap(); ++it) + { + result[it->first] = LlsdToJson(it->second); + } + break; + case LLSD::TypeArray: + for (auto const& entry : val.array()) + { + result.push_back(LlsdToJson(entry)); + } + break; + case LLSD::TypeBinary: + default: + LL_ERRS("LlsdToJson") << "Unsupported conversion to JSON from LLSD type (" << val.type() << ")." << LL_ENDL; + break; + } + + return result; +} diff --git a/indra/llcommon/llsdjson.h b/indra/llcommon/llsdjson.h new file mode 100644 index 0000000000..5c45f697ee --- /dev/null +++ b/indra/llcommon/llsdjson.h @@ -0,0 +1,78 @@ +/** + * @file llsdjson.cpp + * @brief LLSD flexible data system + * + * $LicenseInfo:firstyear=2015&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2015, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLSDJSON_H +#define LL_LLSDJSON_H + +#include +#include +#include + +#include "stdtypes.h" + +#include "llsd.h" +#include + +/// Convert a parsed JSON structure into LLSD maintaining member names and +/// array indexes. +/// JSON/JavaScript types are converted as follows: +/// +/// JSON Type | LLSD Type +/// --------------+-------------- +/// null | undefined +/// integer | LLSD::Integer +/// unsigned | LLSD::Integer +/// real/numeric | LLSD::Real +/// string | LLSD::String +/// boolean | LLSD::Boolean +/// array | LLSD::Array +/// object | LLSD::Map +/// +/// For maps and arrays child entries will be converted and added to the structure. +/// Order is preserved for an array but not for objects. +LLSD LlsdFromJson(const nlohmann::json &val); +LLSD LlsdFromJsonString(const std::string& body); + +/// Convert an LLSD object into Parsed JSON object maintaining member names and +/// array indexs. +/// +/// Types are converted as follows: +/// LLSD Type | JSON Type +/// --------------+---------------- +/// TypeUndefined | null +/// TypeBoolean | boolean +/// TypeInteger | integer +/// TypeReal | real/numeric +/// TypeString | string +/// TypeURI | string +/// TypeDate | string +/// TypeUUID | string +/// TypeMap | object +/// TypeArray | array +/// TypeBinary | unsupported +nlohmann::json LlsdToJson(const LLSD &val); + +#endif // LL_LLSDJSON_H diff --git a/indra/llcommon/llsdparam.cpp b/indra/llcommon/llsdparam.cpp index 0e29873bb0..b64f3d0e4a 100644 --- a/indra/llcommon/llsdparam.cpp +++ b/indra/llcommon/llsdparam.cpp @@ -36,16 +36,15 @@ static LLInitParam::Parser::parser_write_func_map_t sWriteFuncs; static LLInitParam::Parser::parser_inspect_func_map_t sInspectFuncs; static const LLSD NO_VALUE_MARKER; -LLFastTimer::DeclareTimer FTM_SD_PARAM_ADAPTOR("LLSD to LLInitParam conversion"); +LLTrace::BlockTimerStatHandle FTM_SD_PARAM_ADAPTOR("LLSD to LLInitParam conversion"); // // LLParamSDParser // LLParamSDParser::LLParamSDParser() -: Parser(sReadFuncs, sWriteFuncs, sInspectFuncs) +: Parser(sReadFuncs, sWriteFuncs, sInspectFuncs), + mCurReadSD(NULL), mWriteRootSD(NULL) { - using boost::bind; - if (sReadFuncs.empty()) { registerParserFuncs(readFlag, &LLParamSDParser::writeFlag); @@ -98,17 +97,17 @@ void LLParamSDParser::readSD(const LLSD& sd, LLInitParam::BaseBlock& block, bool mNameStack.clear(); setParseSilently(silent); - LLParamSDParserUtilities::readSDValues(boost::bind(&LLParamSDParser::submit, this, boost::ref(block), _1, _2), sd, mNameStack); + LLParamSDParserUtilities::readSDValues(std::bind(&LLParamSDParser::submit, this, std::ref(block), std::placeholders::_1, std::placeholders::_2), sd, mNameStack); //readSDValues(sd, block); } -void LLParamSDParser::writeSD(LLSD& sd, const LLInitParam::BaseBlock& block) +void LLParamSDParser::writeSDImpl(LLSD& sd, const LLInitParam::BaseBlock& block, const LLInitParam::predicate_rule_t rules, const LLInitParam::BaseBlock* diff_block) { mNameStack.clear(); mWriteRootSD = &sd; name_stack_t name_stack; - block.serializeBlock(*this, name_stack); + block.serializeBlock(*this, name_stack, rules, diff_block); } /*virtual*/ std::string LLParamSDParser::getCurrentElementName() @@ -223,10 +222,14 @@ LLSD& LLParamSDParserUtilities::getSDWriteNode(LLSD& input, LLInitParam::Parser: { bool new_traversal = it->second; - LLSD* child_sd = it->first.empty() ? sd_to_write : &(*sd_to_write)[it->first]; - - if (child_sd->isArray()) + LLSD* child_sd; + if (it->first.empty()) { + child_sd = sd_to_write; + if (child_sd->isUndefined()) + { + *child_sd = LLSD::emptyArray(); + } if (new_traversal) { // write to new element at end @@ -240,22 +243,7 @@ LLSD& LLParamSDParserUtilities::getSDWriteNode(LLSD& input, LLInitParam::Parser: } else { - if (new_traversal - && child_sd->isDefined() - && !child_sd->isArray()) - { - // copy child contents into first element of an array - LLSD new_array = LLSD::emptyArray(); - new_array.append(*child_sd); - // assign array to slot that previously held the single value - *child_sd = new_array; - // return next element in that array - sd_to_write = &((*child_sd)[1]); - } - else - { - sd_to_write = child_sd; - } + sd_to_write = &(*sd_to_write)[it->first]; } it->second = false; } @@ -279,24 +267,23 @@ void LLParamSDParserUtilities::readSDValues(read_sd_cb_t cb, const LLSD& sd, LLI } else if (sd.isArray()) { - for (LLSD::array_const_iterator it = sd.beginArray(); - it != sd.endArray(); - ++it) + for (auto const& entry : sd.array()) { - stack.back().second = true; - readSDValues(cb, *it, stack); + stack.push_back(make_pair(std::string(), true)); + readSDValues(cb, entry, stack); + stack.pop_back(); } } else if (sd.isUndefined()) { - if (!cb.empty()) + if (cb) { cb(NO_VALUE_MARKER, stack); } } else { - if (!cb.empty()) + if (cb) { cb(sd, stack); } @@ -313,8 +300,14 @@ namespace LLInitParam { // LLSD specialization // block param interface - bool ParamValue, false>::deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack, bool new_name) + bool ParamValue::deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack, bool new_name) { + if (name_stack.first == name_stack.second + && p.readValue(mValue)) + { + return true; + } + LLSD& sd = LLParamSDParserUtilities::getSDWriteNode(mValue, name_stack); LLSD::String string; @@ -328,15 +321,19 @@ namespace LLInitParam } //static - void ParamValue, false>::serializeElement(Parser& p, const LLSD& sd, Parser::name_stack_t& name_stack) + void ParamValue::serializeElement(Parser& p, const LLSD& sd, Parser::name_stack_t& name_stack) { p.writeValue(sd.asString(), name_stack); } - void ParamValue, false>::serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block) const + bool ParamValue::serializeBlock(Parser& p, Parser::name_stack_t& name_stack_range, const predicate_rule_t predicate_rule, const BaseBlock* diff_block) const { - // read from LLSD value and serialize out to parser (which could be LLSD, XUI, etc) - Parser::name_stack_t stack; - LLParamSDParserUtilities::readSDValues(boost::bind(&serializeElement, boost::ref(p), _1, _2), mValue, stack); + // attempt to write LLSD out directly + if (!p.writeValue(mValue, name_stack_range)) + { + // otherwise read from LLSD value and serialize out to parser (which could be LLSD, XUI, etc) + LLParamSDParserUtilities::readSDValues(std::bind(&serializeElement, std::ref(p), std::placeholders::_1, std::placeholders::_2), mValue, name_stack_range); + } + return true; } } diff --git a/indra/llcommon/llsdparam.h b/indra/llcommon/llsdparam.h index 6ef5debd7b..87a4d90247 100644 --- a/indra/llcommon/llsdparam.h +++ b/indra/llcommon/llsdparam.h @@ -29,13 +29,13 @@ #define LL_LLSDPARAM_H #include "llinitparam.h" -#include "boost/function.hpp" +#include "llfasttimer.h" struct LL_COMMON_API LLParamSDParserUtilities { static LLSD& getSDWriteNode(LLSD& input, LLInitParam::Parser::name_stack_range_t& name_stack_range); - typedef boost::function read_sd_cb_t; + typedef std::function read_sd_cb_t; static void readSDValues(read_sd_cb_t cb, const LLSD& sd, LLInitParam::Parser::name_stack_t& stack); static void readSDValues(read_sd_cb_t cb, const LLSD& sd); }; @@ -50,11 +50,29 @@ typedef LLInitParam::Parser parser_t; public: LLParamSDParser(); void readSD(const LLSD& sd, LLInitParam::BaseBlock& block, bool silent = false); - void writeSD(LLSD& sd, const LLInitParam::BaseBlock& block); + template + void writeSD(LLSD& sd, + const BLOCK& block, + const LLInitParam::predicate_rule_t rules = LLInitParam::default_parse_rules(), + const LLInitParam::BaseBlock* diff_block = NULL) + { + if (!diff_block + && !rules.isAmbivalent(LLInitParam::HAS_DEFAULT_VALUE)) + { + diff_block = &LLInitParam::defaultValue(); + } + writeSDImpl(sd, block, rules, diff_block); + } /*virtual*/ std::string getCurrentElementName(); + /*virtual*/ std::string getCurrentFileName(){ return LLStringUtil::null; } private: + void writeSDImpl(LLSD& sd, + const LLInitParam::BaseBlock& block, + const LLInitParam::predicate_rule_t, + const LLInitParam::BaseBlock* diff_block); + void submit(LLInitParam::BaseBlock& block, const LLSD& sd, LLInitParam::Parser::name_stack_t& name_stack); template @@ -88,11 +106,10 @@ typedef LLInitParam::Parser parser_t; Parser::name_stack_t mNameStack; const LLSD* mCurReadSD; LLSD* mWriteRootSD; - LLSD* mCurWriteSD; }; -extern LL_COMMON_API LLFastTimer::DeclareTimer FTM_SD_PARAM_ADAPTOR; +extern LL_COMMON_API LLTrace::BlockTimerStatHandle FTM_SD_PARAM_ADAPTOR; template class LLSDParamAdapter : public T { @@ -100,7 +117,7 @@ class LLSDParamAdapter : public T LLSDParamAdapter() {} LLSDParamAdapter(const LLSD& sd) { - LLFastTimer _(FTM_SD_PARAM_ADAPTOR); + LL_RECORD_BLOCK_TIME(FTM_SD_PARAM_ADAPTOR); LLParamSDParser parser; // don't spam for implicit parsing of LLSD, as we want to allow arbitrary freeform data and ignore most of it bool parse_silently = true; diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp index ad4fce6f35..989aed77c5 100644 --- a/indra/llcommon/llsdserialize.cpp +++ b/indra/llcommon/llsdserialize.cpp @@ -30,9 +30,9 @@ #include "llsdserialize.h" #include "llpointer.h" #include "llstreamtools.h" // for fullread +#include "llbase64.h" #include -#include "apr_base64.h" #ifdef LL_STANDALONE # include @@ -43,6 +43,7 @@ #if !LL_WINDOWS #include // htonl & ntohl #endif +#include "apr_general.h" // for strncasecmp #include "lldate.h" #include "llsd.h" @@ -54,6 +55,7 @@ static const int MAX_HDR_LEN = 20; static const char LEGACY_NON_HEADER[] = ""; const std::string LLSD_BINARY_HEADER("LLSD/Binary"); const std::string LLSD_XML_HEADER("LLSD/XML"); +const std::string LLSD_NOTATION_HEADER("llsd/notation"); //used to deflate a gzipped asset (currently used for navmeshes) #define windowBits 15 @@ -80,8 +82,13 @@ void LLSDSerialize::serialize(const LLSD& sd, std::ostream& str, ELLSD_Serialize f = new LLSDXMLFormatter; break; + case LLSD_NOTATION: + str << "\n"; + f = new LLSDNotationFormatter; + break; + default: - llwarns << "serialize request for unknown ELLSD_Serialize" << llendl; + LL_WARNS() << "serialize request for unknown ELLSD_Serialize" << LL_ENDL; } if (f.notNull()) @@ -111,7 +118,7 @@ bool LLSDSerialize::deserialize(LLSD& sd, std::istream& str, S32 max_bytes) fail_if_not_legacy = true; } - if (!strncasecmp(LEGACY_NON_HEADER, hdr_buf, strlen(LEGACY_NON_HEADER))) /* Flawfinder: ignore */ + if (!strnicmp(LEGACY_NON_HEADER, hdr_buf, strlen(LEGACY_NON_HEADER))) /* Flawfinder: ignore */ { legacy_no_header = true; inbuf = (int)str.gcount(); @@ -134,9 +141,8 @@ bool LLSDSerialize::deserialize(LLSD& sd, std::istream& str, S32 max_bytes) } header = hdr_buf; - std::string::size_type start = std::string::npos; + std::string::size_type start = header.find_first_not_of(" value; if(len) { value.resize(len); - len = apr_base64_decode_binary(&value[0], encoded.c_str()); + len = LLBase64::decode(encoded, &value[0], len); value.resize(len); } data = value; @@ -873,7 +883,7 @@ S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data) const { /** * Undefined: '!'
    - * Boolean: 't' for true 'f' for false
    + * Boolean: '1' for true '0' for false
    * Integer: 'i' + 4 bytes network byte order
    * Real: 'r' + 8 bytes IEEE double
    * UUID: 'u' + 16 byte unsigned integer
    @@ -909,7 +919,7 @@ S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data) const } if(istr.fail()) { - llinfos << "STREAM FAILURE reading binary map." << llendl; + LL_INFOS() << "STREAM FAILURE reading binary map." << LL_ENDL; parse_count = PARSE_FAILURE; } break; @@ -928,7 +938,7 @@ S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data) const } if(istr.fail()) { - llinfos << "STREAM FAILURE reading binary array." << llendl; + LL_INFOS() << "STREAM FAILURE reading binary array." << LL_ENDL; parse_count = PARSE_FAILURE; } break; @@ -953,7 +963,7 @@ S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data) const data = (S32)ntohl(value_nbo); if(istr.fail()) { - llinfos << "STREAM FAILURE reading binary integer." << llendl; + LL_INFOS() << "STREAM FAILURE reading binary integer." << LL_ENDL; } break; } @@ -965,7 +975,7 @@ S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data) const data = ll_ntohd(real_nbo); if(istr.fail()) { - llinfos << "STREAM FAILURE reading binary real." << llendl; + LL_INFOS() << "STREAM FAILURE reading binary real." << LL_ENDL; } break; } @@ -977,7 +987,7 @@ S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data) const data = id; if(istr.fail()) { - llinfos << "STREAM FAILURE reading binary uuid." << llendl; + LL_INFOS() << "STREAM FAILURE reading binary uuid." << LL_ENDL; } break; } @@ -998,8 +1008,8 @@ S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data) const } if(istr.fail()) { - llinfos << "STREAM FAILURE reading binary (notation-style) string." - << llendl; + LL_INFOS() << "STREAM FAILURE reading binary (notation-style) string." + << LL_ENDL; parse_count = PARSE_FAILURE; } break; @@ -1018,7 +1028,7 @@ S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data) const } if(istr.fail()) { - llinfos << "STREAM FAILURE reading binary string." << llendl; + LL_INFOS() << "STREAM FAILURE reading binary string." << LL_ENDL; parse_count = PARSE_FAILURE; } break; @@ -1037,7 +1047,7 @@ S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data) const } if(istr.fail()) { - llinfos << "STREAM FAILURE reading binary link." << llendl; + LL_INFOS() << "STREAM FAILURE reading binary link." << LL_ENDL; parse_count = PARSE_FAILURE; } break; @@ -1050,7 +1060,7 @@ S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data) const data = LLDate(real); if(istr.fail()) { - llinfos << "STREAM FAILURE reading binary date." << llendl; + LL_INFOS() << "STREAM FAILURE reading binary date." << LL_ENDL; parse_count = PARSE_FAILURE; } break; @@ -1062,8 +1072,8 @@ S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data) const // the size, and read it. U32 size_nbo = 0; read(istr, (char*)&size_nbo, sizeof(U32)); /*Flawfinder: ignore*/ - S32 size = (S32)ntohl(size_nbo); - if(mCheckLimits && (size > mMaxBytesLeft)) + S32 size = (S32)ntohl(size_nbo); // Can return negative size if > 2^31. + if(size < 0 || mCheckLimits && (size > mMaxBytesLeft)) { parse_count = PARSE_FAILURE; } @@ -1079,7 +1089,7 @@ S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data) const } if(istr.fail()) { - llinfos << "STREAM FAILURE reading binary." << llendl; + LL_INFOS() << "STREAM FAILURE reading binary." << LL_ENDL; parse_count = PARSE_FAILURE; } break; @@ -1087,8 +1097,8 @@ S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data) const default: parse_count = PARSE_FAILURE; - llinfos << "Unrecognized character while parsing: int(" << (int)c - << ")" << llendl; + LL_INFOS() << "Unrecognized character while parsing: int(" << (int)c + << ")" << LL_ENDL; break; } if(PARSE_FAILURE == parse_count) @@ -1103,7 +1113,11 @@ S32 LLSDBinaryParser::parseMap(std::istream& istr, LLSD& map) const map = LLSD::emptyMap(); U32 value_nbo = 0; read(istr, (char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/ - S32 size = (S32)ntohl(value_nbo); + S32 size = (S32)ntohl(value_nbo); // Can return negative size if > 2^31. + if (size < 0) + { + return PARSE_FAILURE; + } S32 parse_count = 0; S32 count = 0; char c = get(istr); @@ -1157,7 +1171,11 @@ S32 LLSDBinaryParser::parseArray(std::istream& istr, LLSD& array) const array = LLSD::emptyArray(); U32 value_nbo = 0; read(istr, (char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/ - S32 size = (S32)ntohl(value_nbo); + S32 size = (S32)ntohl(value_nbo); // Can return negative size if > 2^31. + if (size < 0) + { + return PARSE_FAILURE; + } // *FIX: This would be a good place to reserve some space in the // array... @@ -1198,8 +1216,8 @@ bool LLSDBinaryParser::parseString( // *FIX: This is memory inefficient. U32 value_nbo = 0; read(istr, (char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/ - S32 size = (S32)ntohl(value_nbo); - if(mCheckLimits && (size > mMaxBytesLeft)) return false; + S32 size = (S32)ntohl(value_nbo); // Can return negative size if > 2^31. + if(size < 0 || mCheckLimits && (size > mMaxBytesLeft)) return false; std::vector buf; if(size) { @@ -1260,40 +1278,63 @@ std::string LLSDNotationFormatter::escapeString(const std::string& in) // virtual S32 LLSDNotationFormatter::format(const LLSD& data, std::ostream& ostr, U32 options) const +{ + S32 rv = format_impl(data, ostr, options, 0); + return rv; +} + +S32 LLSDNotationFormatter::format_impl(const LLSD& data, std::ostream& ostr, U32 options, U32 level) const { S32 format_count = 1; + std::string pre; + std::string post; + + if (options & LLSDFormatter::OPTIONS_PRETTY) + { + for (U32 i = 0; i < level; i++) + { + pre += " "; + } + post = "\n"; + } + switch(data.type()) { case LLSD::TypeMap: { + if (0 != level) ostr << post << pre; ostr << "{"; + std::string inner_pre; + if (options & LLSDFormatter::OPTIONS_PRETTY) + { + inner_pre = pre + " "; + } + bool need_comma = false; - LLSD::map_const_iterator iter = data.beginMap(); - LLSD::map_const_iterator end = data.endMap(); + auto iter = data.beginMap(); + auto end = data.endMap(); for(; iter != end; ++iter) { if(need_comma) ostr << ","; need_comma = true; - ostr << '\''; + ostr << post << inner_pre << '\''; serialize_string((*iter).first, ostr); ostr << "':"; - format_count += format((*iter).second, ostr); + format_count += format_impl((*iter).second, ostr, options, level + 2); } - ostr << "}"; + ostr << post << pre << "}"; break; } case LLSD::TypeArray: { - ostr << "["; + ostr << post << pre << "["; bool need_comma = false; - LLSD::array_const_iterator iter = data.beginArray(); - LLSD::array_const_iterator end = data.endArray(); - for(; iter != end; ++iter) + for (const auto& entry : data.array()) { - if(need_comma) ostr << ","; + if (need_comma) ostr << ","; need_comma = true; - format_count += format(*iter, ostr); + format_count += format_impl(entry, ostr, options, level + 1); } ostr << "]"; break; @@ -1304,13 +1345,7 @@ S32 LLSDNotationFormatter::format(const LLSD& data, std::ostream& ostr, U32 opti break; case LLSD::TypeBoolean: - if(mBoolAlpha || -#if( LL_WINDOWS || __GNUC__ > 2) - (ostr.flags() & std::ios::boolalpha) -#else - (ostr.flags() & 0x0100) -#endif - ) + if(mBoolAlpha || (ostr.flags() & std::ios::boolalpha)) { ostr << (data.asBoolean() ? NOTATION_TRUE_SERIAL : NOTATION_FALSE_SERIAL); @@ -1343,7 +1378,7 @@ S32 LLSDNotationFormatter::format(const LLSD& data, std::ostream& ostr, U32 opti case LLSD::TypeString: ostr << '\''; - serialize_string(data.asString(), ostr); + serialize_string(data.asStringRef(), ostr); ostr << '\''; break; @@ -1360,9 +1395,26 @@ S32 LLSDNotationFormatter::format(const LLSD& data, std::ostream& ostr, U32 opti case LLSD::TypeBinary: { // *FIX: memory inefficient. - std::vector buffer = data.asBinary(); + const std::vector& buffer = data.asBinary(); ostr << "b(" << buffer.size() << ")\""; - if(buffer.size()) ostr.write((const char*)&buffer[0], buffer.size()); + if(!buffer.empty()) + { + if (options & LLSDFormatter::OPTIONS_PRETTY_BINARY) + { + std::ios_base::fmtflags old_flags = ostr.flags(); + ostr.setf( std::ios::hex, std::ios::basefield ); + ostr << "0x"; + for (unsigned char i : buffer) + { + ostr << static_cast(i); + } + ostr.flags(old_flags); + } + else + { + ostr.write(reinterpret_cast(&buffer[0]), buffer.size()); + } + } ostr << "\""; break; } @@ -1397,9 +1449,9 @@ S32 LLSDBinaryFormatter::format(const LLSD& data, std::ostream& ostr, U32 option { ostr.put('{'); U32 size_nbo = htonl(data.size()); - ostr.write((const char*)(&size_nbo), sizeof(U32)); - LLSD::map_const_iterator iter = data.beginMap(); - LLSD::map_const_iterator end = data.endMap(); + ostr.write(reinterpret_cast(&size_nbo), sizeof(U32)); + auto iter = data.beginMap(); + auto end = data.endMap(); for(; iter != end; ++iter) { ostr.put('k'); @@ -1414,12 +1466,10 @@ S32 LLSDBinaryFormatter::format(const LLSD& data, std::ostream& ostr, U32 option { ostr.put('['); U32 size_nbo = htonl(data.size()); - ostr.write((const char*)(&size_nbo), sizeof(U32)); - LLSD::array_const_iterator iter = data.beginArray(); - LLSD::array_const_iterator end = data.endArray(); - for(; iter != end; ++iter) + ostr.write(reinterpret_cast(&size_nbo), sizeof(U32)); + for (const auto& entry : data.array()) { - format_count += format(*iter, ostr); + format_count += format(entry, ostr); } ostr.put(']'); break; @@ -1460,7 +1510,7 @@ S32 LLSDBinaryFormatter::format(const LLSD& data, std::ostream& ostr, U32 option case LLSD::TypeString: ostr.put('s'); - formatString(data.asString(), ostr); + formatString(data.asStringRef(), ostr); break; case LLSD::TypeDate: @@ -1478,12 +1528,11 @@ S32 LLSDBinaryFormatter::format(const LLSD& data, std::ostream& ostr, U32 option case LLSD::TypeBinary: { - // *FIX: memory inefficient. ostr.put('b'); - std::vector buffer = data.asBinary(); + const std::vector& buffer = data.asBinary(); U32 size_nbo = htonl(buffer.size()); ostr.write((const char*)(&size_nbo), sizeof(U32)); - if(buffer.size()) ostr.write((const char*)&buffer[0], buffer.size()); + if(!buffer.empty()) ostr.write((const char*)&buffer[0], buffer.size()); break; } @@ -1660,12 +1709,12 @@ int deserialize_string_raw( // *FIX: This is memory inefficient. S32 len = strtol(buf + 1, NULL, 0); if((max_bytes>0)&&(len>max_bytes)) return LLSDParser::PARSE_FAILURE; - std::vector buf; + std::vector buf2; if(len) { - buf.resize(len); - count += (int)fullread(istr, (char *)&buf[0], len); - value.assign(buf.begin(), buf.end()); + buf2.resize(len); + count += (int)fullread(istr, (char *)&buf2[0], len); + value.assign(buf2.begin(), buf2.end()); } c = istr.get(); ++count; @@ -2017,7 +2066,7 @@ std::string zip_llsd(LLSD& data) S32 ret = deflateInit(&strm, Z_BEST_COMPRESSION); if (ret != Z_OK) { - llwarns << "Failed to compress LLSD block." << llendl; + LL_WARNS() << "Failed to compress LLSD block." << LL_ENDL; return std::string(); } @@ -2044,19 +2093,30 @@ std::string zip_llsd(LLSD& data) if (strm.avail_out >= CHUNK) { free(output); - llwarns << "Failed to compress LLSD block." << llendl; + LL_WARNS() << "Failed to compress LLSD block." << LL_ENDL; return std::string(); } have = CHUNK-strm.avail_out; - output = (U8*) realloc(output, cur_size+have); + U8* new_output = (U8*) realloc(output, cur_size+have); + if (new_output == NULL) + { + LL_WARNS() << "Failed to compress LLSD block: can't reallocate memory, current size: " << cur_size << " bytes; requested " << cur_size + have << " bytes." << LL_ENDL; + deflateEnd(&strm); + if (output) + { + free(output); + } + return std::string(); + } + output = new_output; memcpy(output+cur_size, out, have); cur_size += have; } else { free(output); - llwarns << "Failed to compress LLSD block." << llendl; + LL_WARNS() << "Failed to compress LLSD block." << LL_ENDL; return std::string(); } } @@ -2068,18 +2128,10 @@ std::string zip_llsd(LLSD& data) deflateEnd(&strm); free(output); -#if 0 //verify results work with unzip_llsd - std::istringstream test(result); - LLSD test_sd; - if (!unzip_llsd(test_sd, test, result.size())) - { - llerrs << "Invalid compression result!" << llendl; - } -#endif - return result; } +// //decompress a block of LLSD from provided istream // not very efficient -- creats a copy of decompressed LLSD block in memory // and deserializes from that copy using LLSDSerialize @@ -2109,13 +2161,6 @@ bool unzip_llsd(LLSD& data, std::istream& is, S32 size) strm.avail_out = CHUNK; strm.next_out = out; ret = inflate(&strm, Z_NO_FLUSH); - if (ret == Z_STREAM_ERROR) - { - inflateEnd(&strm); - free(result); - delete [] in; - return false; - } switch (ret) { @@ -2123,6 +2168,7 @@ bool unzip_llsd(LLSD& data, std::istream& is, S32 size) ret = Z_DATA_ERROR; case Z_DATA_ERROR: case Z_MEM_ERROR: + case Z_STREAM_ERROR: inflateEnd(&strm); free(result); delete [] in; @@ -2132,7 +2178,19 @@ bool unzip_llsd(LLSD& data, std::istream& is, S32 size) U32 have = CHUNK-strm.avail_out; - result = (U8*) realloc(result, cur_size + have); + U8* new_result = (U8*)realloc(result, cur_size + have); + if (new_result == NULL) + { + LL_WARNS() << "Failed to unzip LLSD block: can't reallocate memory, current size: " << cur_size << " bytes; requested " << cur_size + have << " bytes." << LL_ENDL; + inflateEnd(&strm); + if (result) + { + free(result); + } + delete in; + return false; + } + result = new_result; memcpy(result+cur_size, out, have); cur_size += have; @@ -2163,7 +2221,7 @@ bool unzip_llsd(LLSD& data, std::istream& is, S32 size) if (!LLSDSerialize::fromBinary(data, istr, cur_size)) { - llwarns << "Failed to unzip LLSD block" << llendl; + LL_WARNS() << "Failed to unzip LLSD block" << LL_ENDL; free(result); return false; } @@ -2172,11 +2230,17 @@ bool unzip_llsd(LLSD& data, std::istream& is, S32 size) free(result); return true; } + //This unzip function will only work with a gzip header and trailer - while the contents //of the actual compressed data is the same for either format (gzip vs zlib ), the headers //and trailers are different for the formats. U8* unzip_llsdNavMesh( bool& valid, unsigned int& outsize, std::istream& is, S32 size ) { + if (size == 0) + { + LL_WARNS() << "No data to unzip." << LL_ENDL; + return NULL; + } U8* result = NULL; U32 cur_size = 0; z_stream strm; @@ -2201,30 +2265,38 @@ U8* unzip_llsdNavMesh( bool& valid, unsigned int& outsize, std::istream& is, S32 strm.avail_out = CHUNK; strm.next_out = out; ret = inflate(&strm, Z_NO_FLUSH); - if (ret == Z_STREAM_ERROR) - { - inflateEnd(&strm); - free(result); - delete [] in; - valid = false; - } - switch (ret) { case Z_NEED_DICT: ret = Z_DATA_ERROR; case Z_DATA_ERROR: case Z_MEM_ERROR: + case Z_STREAM_ERROR: inflateEnd(&strm); free(result); delete [] in; valid = false; - break; + return NULL; } - U32 have = CHUNK-strm.avail_out; - result = (U8*) realloc(result, cur_size + have); + U8* new_result = (U8*) realloc(result, cur_size + have); + if (new_result == NULL) + { + LL_WARNS() << "Failed to unzip LLSD NavMesh block: can't reallocate memory, current size: " << cur_size + << " bytes; requested " << cur_size + have + << " bytes; total syze: ." << size << " bytes." + << LL_ENDL; + inflateEnd(&strm); + if (result) + { + free(result); + } + delete [] in; + valid = false; + return NULL; + } + result = new_result; memcpy(result+cur_size, out, have); cur_size += have; @@ -2248,5 +2320,5 @@ U8* unzip_llsdNavMesh( bool& valid, unsigned int& outsize, std::istream& is, S32 return result; } - +// diff --git a/indra/llcommon/llsdserialize.h b/indra/llcommon/llsdserialize.h index 09150615cb..3b339355d3 100644 --- a/indra/llcommon/llsdserialize.h +++ b/indra/llcommon/llsdserialize.h @@ -4,31 +4,25 @@ * @date 2006-02-26 * @brief Declaration of parsers and formatters for LLSD * - * $LicenseInfo:firstyear=2006&license=viewergpl$ - * - * Copyright (c) 2006-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -306,7 +300,7 @@ class LL_COMMON_API LLSDXMLParser : public LLSDParser /** * @brief Constructor */ - LLSDXMLParser(); + LLSDXMLParser(bool emit_errors=true); protected: /** @@ -422,7 +416,8 @@ class LL_COMMON_API LLSDFormatter : public LLRefCount typedef enum e_formatter_options_type { OPTIONS_NONE = 0, - OPTIONS_PRETTY = 1 + OPTIONS_PRETTY = 1, + OPTIONS_PRETTY_BINARY = 2 } EFormatterOptions; /** @@ -513,6 +508,17 @@ class LL_COMMON_API LLSDNotationFormatter : public LLSDFormatter * @return Returns The number of LLSD objects fomatted out */ virtual S32 format(const LLSD& data, std::ostream& ostr, U32 options = LLSDFormatter::OPTIONS_NONE) const; + +protected: + + /** + * @brief Implementation to format the data. This is called recursively. + * + * @param data The data to write. + * @param ostr The destination stream for the data. + * @return Returns The number of LLSD objects fomatted out + */ + S32 format_impl(const LLSD& data, std::ostream& ostr, U32 options, U32 level) const; }; @@ -638,6 +644,11 @@ class LL_COMMON_API LLSDBinaryFormatter : public LLSDFormatter * params << "[{'version':i1}," << LLSDOStreamer(sd) * << "]"; * + * + * *NOTE - formerly this class inherited from its template parameter Formatter, + * but all instantiations passed in LLRefCount subclasses. This conflicted with + * the auto allocation intended for this class template (demonstrated in the + * example above). -brad */ template class LLSDOStreamer @@ -683,7 +694,7 @@ class LL_COMMON_API LLSDSerialize public: enum ELLSD_Serialize { - LLSD_BINARY, LLSD_XML + LLSD_BINARY, LLSD_XML, LLSD_NOTATION }; /** @@ -721,6 +732,18 @@ class LL_COMMON_API LLSDSerialize LLPointer f = new LLSDNotationFormatter; return f->format(sd, str, LLSDFormatter::OPTIONS_NONE); } + static S32 toPrettyNotation(const LLSD& sd, std::ostream& str) + { + LLPointer f = new LLSDNotationFormatter; + return f->format(sd, str, LLSDFormatter::OPTIONS_PRETTY); + } + static S32 toPrettyBinaryNotation(const LLSD& sd, std::ostream& str) + { + LLPointer f = new LLSDNotationFormatter; + return f->format(sd, str, + LLSDFormatter::OPTIONS_PRETTY | + LLSDFormatter::OPTIONS_PRETTY_BINARY); + } static S32 fromNotation(LLSD& sd, std::istream& str, S32 max_bytes) { LLPointer p = new LLSDNotationParser; @@ -748,25 +771,25 @@ class LL_COMMON_API LLSDSerialize return f->format(sd, str, LLSDFormatter::OPTIONS_PRETTY); } - static S32 fromXMLEmbedded(LLSD& sd, std::istream& str) + static S32 fromXMLEmbedded(LLSD& sd, std::istream& str, bool emit_errors=true) { // no need for max_bytes since xml formatting is not // subvertable by bad sizes. - LLPointer p = new LLSDXMLParser; + LLPointer p = new LLSDXMLParser(emit_errors); return p->parse(str, sd, LLSDSerialize::SIZE_UNLIMITED); } // Line oriented parser, 30% faster than fromXML(), but can // only be used when you know you have the complete XML // document available in the stream. - static S32 fromXMLDocument(LLSD& sd, std::istream& str) + static S32 fromXMLDocument(LLSD& sd, std::istream& str, bool emit_errors=true) { - LLPointer p = new LLSDXMLParser(); + LLPointer p = new LLSDXMLParser(emit_errors); return p->parseLines(str, sd); } - static S32 fromXML(LLSD& sd, std::istream& str) + static S32 fromXML(LLSD& sd, std::istream& str, bool emit_errors=true) { - return fromXMLEmbedded(sd, str); -// return fromXMLDocument(sd, str); + return fromXMLEmbedded(sd, str, emit_errors); +// return fromXMLDocument(sd, str, emit_errors); } /* diff --git a/indra/llcommon/llsdserialize_xml.cpp b/indra/llcommon/llsdserialize_xml.cpp index f0b4716ce3..4608fac889 100644 --- a/indra/llcommon/llsdserialize_xml.cpp +++ b/indra/llcommon/llsdserialize_xml.cpp @@ -26,11 +26,11 @@ #include "linden_common.h" #include "llsdserialize_xml.h" +#include "llbase64.h" #include #include -#include "apr_base64.h" #include extern "C" @@ -116,11 +116,9 @@ S32 LLSDXMLFormatter::format_impl(const LLSD& data, std::ostream& ostr, U32 opti else { ostr << pre << "" << post; - LLSD::array_const_iterator iter = data.beginArray(); - LLSD::array_const_iterator end = data.endArray(); - for(; iter != end; ++iter) + for (const auto& entry : data.array()) { - format_count += format_impl(*iter, ostr, options, level + 1); + format_count += format_impl(entry, ostr, options, level + 1); } ostr << pre << "" << post; } @@ -133,11 +131,7 @@ S32 LLSDXMLFormatter::format_impl(const LLSD& data, std::ostream& ostr, U32 opti case LLSD::TypeBoolean: ostr << pre << ""; if(mBoolAlpha || -#if( LL_WINDOWS || __GNUC__ > 2) (ostr.flags() & std::ios::boolalpha) -#else - (ostr.flags() & 0x0100) -#endif ) { ostr << (data.asBoolean() ? "true" : "false"); @@ -172,8 +166,8 @@ S32 LLSDXMLFormatter::format_impl(const LLSD& data, std::ostream& ostr, U32 opti break; case LLSD::TypeString: - if(data.asString().empty()) ostr << pre << "" << post; - else ostr << pre << "" << escapeString(data.asString()) <<"" << post; + if(data.asStringRef().empty()) ostr << pre << "" << post; + else ostr << pre << "" << escapeString(data.asStringRef()) <<"" << post; break; case LLSD::TypeDate: @@ -186,24 +180,15 @@ S32 LLSDXMLFormatter::format_impl(const LLSD& data, std::ostream& ostr, U32 opti case LLSD::TypeBinary: { - LLSD::Binary buffer = data.asBinary(); + const LLSD::Binary& buffer = data.asBinary(); if(buffer.empty()) { ostr << pre << "" << post; } else { - // *FIX: memory inefficient. - // *TODO: convert to use LLBase64 ostr << pre << ""; - int b64_buffer_length = apr_base64_encode_len(buffer.size()); - char* b64_buffer = new char[b64_buffer_length]; - b64_buffer_length = apr_base64_encode_binary( - b64_buffer, - &buffer[0], - buffer.size()); - ostr.write(b64_buffer, b64_buffer_length - 1); - delete[] b64_buffer; + ostr << LLBase64::encode(&buffer[0], buffer.size()); ostr << "" << post; } break; @@ -254,7 +239,7 @@ std::string LLSDXMLFormatter::escapeString(const std::string& in) class LLSDXMLParser::Impl { public: - Impl(); + Impl(bool emit_errors); ~Impl(); S32 parse(std::istream& input, LLSD& data); @@ -298,6 +283,7 @@ class LLSDXMLParser::Impl static const XML_Char* findAttribute(const XML_Char* name, const XML_Char** pairs); + bool mEmitErrors; XML_Parser mParser; @@ -319,7 +305,8 @@ class LLSDXMLParser::Impl }; -LLSDXMLParser::Impl::Impl() +LLSDXMLParser::Impl::Impl(bool emit_errors) + : mEmitErrors(emit_errors) { mParser = XML_ParserCreate(NULL); reset(); @@ -377,13 +364,10 @@ S32 LLSDXMLParser::Impl::parse(std::istream& input, LLSD& data) { break; } + count = get_till_eol(input, (char *)buffer, BUFFER_SIZE); + if (!count) { - - count = get_till_eol(input, (char *)buffer, BUFFER_SIZE); - if (!count) - { - break; - } + break; } status = XML_ParseBuffer(mParser, count, false); @@ -406,7 +390,10 @@ S32 LLSDXMLParser::Impl::parse(std::istream& input, LLSD& data) { ((char*) buffer)[count ? count - 1 : 0] = '\0'; } - llinfos << "LLSDXMLParser::Impl::parse: XML_STATUS_ERROR parsing:" << (char*) buffer << llendl; + if (mEmitErrors) + { + LL_INFOS() << "LLSDXMLParser::Impl::parse: XML_STATUS_ERROR parsing:" << (char*) buffer << LL_ENDL; + } data = LLSD(); return LLSDParser::PARSE_FAILURE; } @@ -484,7 +471,10 @@ S32 LLSDXMLParser::Impl::parseLines(std::istream& input, LLSD& data) if (status == XML_STATUS_ERROR && !mGracefullStop) { - llinfos << "LLSDXMLParser::Impl::parseLines: XML_STATUS_ERROR" << llendl; + if (mEmitErrors) + { + LL_INFOS() << "LLSDXMLParser::Impl::parseLines: XML_STATUS_ERROR" << LL_ENDL; + } return LLSDParser::PARSE_FAILURE; } @@ -508,12 +498,7 @@ void LLSDXMLParser::Impl::reset() mSkipping = false; -#if( LL_WINDOWS || __GNUC__ > 2) mCurrentKey.clear(); -#else - mCurrentKey = std::string(); -#endif - XML_ParserReset(mParser, "utf-8"); XML_SetUserData(mParser, this); @@ -550,7 +535,7 @@ void LLSDXMLParser::Impl::parsePart(const char* buf, int len) XML_Status status = XML_Parse(mParser, buf, len, false); if (status == XML_STATUS_ERROR) { - llinfos << "Unexpected XML parsing error at start" << llendl; + LL_INFOS() << "Unexpected XML parsing error at start" << LL_ENDL; } } } @@ -641,11 +626,7 @@ void LLSDXMLParser::Impl::startElementHandler(const XML_Char* name, const XML_Ch LLSD& newElement = map[mCurrentKey]; mStack.push_back(&newElement); -#if( LL_WINDOWS || __GNUC__ > 2) mCurrentKey.clear(); -#else - mCurrentKey = std::string(); -#endif } else if (mStack.back()->isArray()) { @@ -787,10 +768,10 @@ void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name) boost::regex r; r.assign("\\s"); std::string stripped = boost::regex_replace(mCurrentContent, r, ""); - S32 len = apr_base64_decode_len(stripped.c_str()); + size_t len = LLBase64::requiredDecryptionSpace(stripped); std::vector data; data.resize(len); - len = apr_base64_decode_binary(&data[0], stripped.c_str()); + len = LLBase64::decode(stripped, &data[0], len); data.resize(len); value = data; break; @@ -910,7 +891,7 @@ LLSDXMLParser::Impl::Element LLSDXMLParser::Impl::readElement(const XML_Char* na /** * LLSDXMLParser */ -LLSDXMLParser::LLSDXMLParser() : impl(* new Impl) +LLSDXMLParser::LLSDXMLParser(bool emit_errors /* = true */) : impl(* new Impl(emit_errors)) { } diff --git a/indra/llcommon/llsdutil.cpp b/indra/llcommon/llsdutil.cpp index 120bfa2c94..dd14984a5a 100644 --- a/indra/llcommon/llsdutil.cpp +++ b/indra/llcommon/llsdutil.cpp @@ -4,31 +4,25 @@ * @date 2006-05-24 * @brief Implementation of classes, functions, etc, for using structured data. * - * $LicenseInfo:firstyear=2006&license=viewergpl$ - * - * Copyright (c) 2006-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -51,7 +45,6 @@ #include #include -#include // U32 LLSD ll_sd_from_U32(const U32 val) @@ -188,7 +181,7 @@ char* ll_pretty_print_sd_ptr(const LLSD* sd) char* ll_pretty_print_sd(const LLSD& sd) { - const U32 bufferSize = 10 * 1024; + const U32 bufferSize = 100 * 1024; static char buffer[bufferSize]; std::ostringstream stream; //stream.rdbuf()->pubsetbuf(buffer, bufferSize); @@ -199,6 +192,14 @@ char* ll_pretty_print_sd(const LLSD& sd) return buffer; } +std::string ll_stream_notation_sd(const LLSD& sd) +{ + std::ostringstream stream; + stream << LLSDOStreamer(sd); + return stream.str(); +} + + //compares the structure of an LLSD to a template LLSD and stores the //"valid" values in a 3rd LLSD. Default values pulled from the template //if the tested LLSD does not contain the key/value pair. @@ -320,6 +321,180 @@ BOOL compare_llsd_with_template( return TRUE; } +// filter_llsd_with_template() is a direct clone (copy-n-paste) of +// compare_llsd_with_template with the following differences: +// (1) bool vs BOOL return types +// (2) A map with the key value "*" is a special value and maps any key in the +// test llsd that doesn't have an explicitly matching key in the template. +// (3) The element of an array with exactly one element is taken as a template +// for *all* the elements of the test array. If the template array is of +// different size, compare_llsd_with_template() semantics apply. +bool filter_llsd_with_template( + const LLSD & llsd_to_test, + const LLSD & template_llsd, + LLSD & resultant_llsd) +{ + if (llsd_to_test.isUndefined() && template_llsd.isDefined()) + { + resultant_llsd = template_llsd; + return true; + } + else if (llsd_to_test.type() != template_llsd.type()) + { + resultant_llsd = LLSD(); + return false; + } + + if (llsd_to_test.isArray()) + { + //they are both arrays + //we loop over all the items in the template + //verifying that the to_test has a subset (in the same order) + //any shortcoming in the testing_llsd are just taken + //to be the rest of the template + LLSD data; + LLSD::array_const_iterator test_iter; + LLSD::array_const_iterator template_iter; + + resultant_llsd = LLSD::emptyArray(); + test_iter = llsd_to_test.beginArray(); + + if (1 == template_llsd.size()) + { + // If the template has a single item, treat it as + // the template for *all* items in the test LLSD. + template_iter = template_llsd.beginArray(); + + for (; test_iter != llsd_to_test.endArray(); ++test_iter) + { + if (! filter_llsd_with_template(*test_iter, *template_iter, data)) + { + resultant_llsd = LLSD(); + return false; + } + else + { + resultant_llsd.append(data); + } + } + } + else + { + // Traditional compare_llsd_with_template matching + + for (template_iter = template_llsd.beginArray(); + template_iter != template_llsd.endArray() && + test_iter != llsd_to_test.endArray(); + ++template_iter, ++test_iter) + { + if (! filter_llsd_with_template(*test_iter, *template_iter, data)) + { + resultant_llsd = LLSD(); + return false; + } + else + { + resultant_llsd.append(data); + } + } + + //so either the test or the template ended + //we do another loop now to the end of the template + //grabbing the default values + for (; + template_iter != template_llsd.endArray(); + ++template_iter) + { + resultant_llsd.append(*template_iter); + } + } + } + else if (llsd_to_test.isMap()) + { + resultant_llsd = LLSD::emptyMap(); + + //now we loop over the keys of the two maps + //any excess is taken from the template + //excess is ignored in the test + + // Special tag for wildcarded LLSD map key templates + const LLSD::String wildcard_tag("*"); + + const bool template_has_wildcard = template_llsd.has(wildcard_tag); + LLSD wildcard_value; + LLSD value; + + const LLSD::map_const_iterator template_iter_end(template_llsd.endMap()); + for (LLSD::map_const_iterator template_iter(template_llsd.beginMap()); + template_iter_end != template_iter; + ++template_iter) + { + if (wildcard_tag == template_iter->first) + { + wildcard_value = template_iter->second; + } + else if (llsd_to_test.has(template_iter->first)) + { + //the test LLSD has the same key + if (! filter_llsd_with_template(llsd_to_test[template_iter->first], + template_iter->second, + value)) + { + resultant_llsd = LLSD(); + return false; + } + else + { + resultant_llsd[template_iter->first] = value; + } + } + else if (! template_has_wildcard) + { + // test llsd doesn't have it...take the + // template as default value + resultant_llsd[template_iter->first] = template_iter->second; + } + } + if (template_has_wildcard) + { + LLSD sub_value; + LLSD::map_const_iterator test_iter; + + for (test_iter = llsd_to_test.beginMap(); + test_iter != llsd_to_test.endMap(); + ++test_iter) + { + if (resultant_llsd.has(test_iter->first)) + { + // Final value has test key, assume more specific + // template matched and we shouldn't modify it again. + continue; + } + else if (! filter_llsd_with_template(test_iter->second, + wildcard_value, + sub_value)) + { + // Test value doesn't match wildcarded template + resultant_llsd = LLSD(); + return false; + } + else + { + // Test value matches template, add the actuals. + resultant_llsd[test_iter->first] = sub_value; + } + } + } + } + else + { + //of same type...take the test llsd's value + resultant_llsd = llsd_to_test; + } + + return true; +} + /***************************************************************************** * Helpers for llsd_matches() *****************************************************************************/ @@ -353,7 +528,7 @@ class TypeLookup public: TypeLookup() { - for (const Data *di(boost::begin(typedata)), *dend(boost::end(typedata)); di != dend; ++di) + for (const Data *di(std::begin(typedata)), *dend(std::end(typedata)); di != dend; ++di) { mMap[di->type] = di->name; } @@ -533,7 +708,7 @@ std::string llsd_matches(const LLSD& prototype, const LLSD& data, const std::str LLSD::TypeURI }; return match_types(prototype.type(), - TypeVector(boost::begin(accept), boost::end(accept)), + TypeVector(std::begin(accept), std::end(accept)), data.type(), pfx); } @@ -550,7 +725,7 @@ std::string llsd_matches(const LLSD& prototype, const LLSD& data, const std::str }; // Funny business: shuffle the set of acceptable types to include all // but the prototype's type. Get the acceptable types in a set. - std::set rest(boost::begin(all), boost::end(all)); + std::set rest(std::begin(all), std::end(all)); // Remove the prototype's type because we pass that separately. rest.erase(prototype.type()); return match_types(prototype.type(), @@ -566,7 +741,7 @@ std::string llsd_matches(const LLSD& prototype, const LLSD& data, const std::str LLSD::TypeString }; return match_types(prototype.type(), - TypeVector(boost::begin(accept), boost::end(accept)), + TypeVector(std::begin(accept), std::end(accept)), data.type(), pfx); } @@ -578,7 +753,7 @@ std::string llsd_matches(const LLSD& prototype, const LLSD& data, const std::str return match_types(prototype.type(), TypeVector(), data.type(), pfx); } -bool llsd_equals(const LLSD& lhs, const LLSD& rhs, unsigned bits) +bool llsd_equals(const LLSD& lhs, const LLSD& rhs, int bits) { // We're comparing strict equality of LLSD representation rather than // performing any conversions. So if the types aren't equal, the LLSD @@ -598,7 +773,7 @@ bool llsd_equals(const LLSD& lhs, const LLSD& rhs, unsigned bits) case LLSD::TypeReal: // This is where the 'bits' argument comes in handy. If passed // explicitly, it means to use is_approx_equal_fraction() to compare. - if (bits != -1) + if (bits >= 0) { return is_approx_equal_fraction(lhs.asReal(), rhs.asReal(), bits); } @@ -679,3 +854,104 @@ bool llsd_equals(const LLSD& lhs, const LLSD& rhs, unsigned bits) return false; // pacify the compiler } } + +// Construct a deep partial clone of of an LLSD object. primitive types share +// references, however maps, arrays and binary objects are duplicated. An optional +// filter may be include to exclude/include keys in a map. +LLSD llsd_clone(LLSD value, LLSD filter) +{ + LLSD clone; + bool has_filter(filter.isMap()); + + switch (value.type()) + { + case LLSD::TypeMap: + clone = LLSD::emptyMap(); + for (LLSD::map_const_iterator itm = value.beginMap(); itm != value.endMap(); ++itm) + { + if (has_filter) + { + if (filter.has((*itm).first)) + { + if (!filter[(*itm).first].asBoolean()) + continue; + } + else if (filter.has("*")) + { + if (!filter["*"].asBoolean()) + continue; + } + else + { + continue; + } + } + clone[(*itm).first] = llsd_clone((*itm).second, filter); + } + break; + case LLSD::TypeArray: + clone = LLSD::emptyArray(); + for (auto const& entry : value.array()) + { + clone.append(llsd_clone(entry, filter)); + } + break; + + case LLSD::TypeBinary: + { + LLSD::Binary bin(value.asBinary().begin(), value.asBinary().end()); + clone = LLSD::Binary(bin); + break; + } + default: + clone = value; + } + + return clone; +} + +LLSD llsd_shallow(LLSD value, LLSD filter) +{ + LLSD shallow; + bool has_filter(filter.isMap()); + + if (value.isMap()) + { + shallow = LLSD::emptyMap(); + for (LLSD::map_const_iterator itm = value.beginMap(); itm != value.endMap(); ++itm) + { + if (has_filter) + { + if (filter.has((*itm).first)) + { + if (!filter[(*itm).first].asBoolean()) + continue; + } + else if (filter.has("*")) + { + if (!filter["*"].asBoolean()) + continue; + } + else + { + continue; + } + } + shallow[(*itm).first] = (*itm).second; + } + } + else if (value.isArray()) + { + shallow = LLSD::emptyArray(); + for (auto const& entry : value.array()) + { + shallow.append(entry); + } + } + else + { + return value; + } + + return shallow; +} diff --git a/indra/llcommon/llsdutil.h b/indra/llcommon/llsdutil.h index 532d3f9341..e9c366212b 100644 --- a/indra/llcommon/llsdutil.h +++ b/indra/llcommon/llsdutil.h @@ -29,7 +29,8 @@ #ifndef LL_LLSDUTIL_H #define LL_LLSDUTIL_H -class LLSD; +#include "llsd.h" +#include // U32 LL_COMMON_API LLSD ll_sd_from_U32(const U32); @@ -56,6 +57,8 @@ LL_COMMON_API char* ll_print_sd(const LLSD& sd); LL_COMMON_API char* ll_pretty_print_sd_ptr(const LLSD* sd); LL_COMMON_API char* ll_pretty_print_sd(const LLSD& sd); +LL_COMMON_API std::string ll_stream_notation_sd(const LLSD& sd); + //compares the structure of an LLSD to a template LLSD and stores the //"valid" values in a 3rd LLSD. Default values //are pulled from the template. Extra keys/values in the test @@ -68,6 +71,19 @@ LL_COMMON_API BOOL compare_llsd_with_template( const LLSD& template_llsd, LLSD& resultant_llsd); +// filter_llsd_with_template() is a direct clone (copy-n-paste) of +// compare_llsd_with_template with the following differences: +// (1) bool vs BOOL return types +// (2) A map with the key value "*" is a special value and maps any key in the +// test llsd that doesn't have an explicitly matching key in the template. +// (3) The element of an array with exactly one element is taken as a template +// for *all* the elements of the test array. If the template array is of +// different size, compare_llsd_with_template() semantics apply. +bool filter_llsd_with_template( + const LLSD & llsd_to_test, + const LLSD & template_llsd, + LLSD & resultant_llsd); + /** * Recursively determine whether a given LLSD data block "matches" another * LLSD prototype. The returned string is empty() on success, non-empty() on @@ -126,7 +142,12 @@ LL_COMMON_API std::string llsd_matches(const LLSD& prototype, const LLSD& data, /// Deep equality. If you want to compare LLSD::Real values for approximate /// equality rather than bitwise equality, pass @a bits as for /// is_approx_equal_fraction(). -LL_COMMON_API bool llsd_equals(const LLSD& lhs, const LLSD& rhs, unsigned bits=-1); +LL_COMMON_API bool llsd_equals(const LLSD& lhs, const LLSD& rhs, int bits=-1); + +inline bool operator==(const LLSD& lhs, const LLSD& rhs) +{ + return llsd_equals(lhs, rhs, 8); +} // Simple function to copy data out of input & output iterators if // there is no need for casting. @@ -419,4 +440,87 @@ class inMap } // namespace llsd + +// Creates a deep clone of an LLSD object. Maps, Arrays and binary objects +// are duplicated, atomic primitives (Boolean, Integer, Real, etc) simply +// use a shared reference. +// Optionally a filter may be specified to control what is duplicated. The +// map takes the form "keyname/boolean". +// If the value is true the value will be duplicated otherwise it will be skipped +// when encountered in a map. A key name of "*" can be specified as a wild card +// and will specify the default behavior. If no wild card is given and the clone +// encounters a name not in the filter, that value will be skipped. +LLSD llsd_clone(LLSD value, LLSD filter = LLSD()); + +// Creates a shallow copy of a map or array. If passed any other type of LLSD +// object it simply returns that value. See llsd_clone for a description of +// the filter parameter. +LLSD llsd_shallow(LLSD value, LLSD filter = LLSD()); + + +// Specialization for generating a hash value from an LLSD block. +namespace boost { + template<> struct hash +{ + typedef LLSD argument_type; + typedef std::size_t result_type; + result_type operator()(argument_type const& s) const + { + result_type seed(0); + + LLSD::Type stype = s.type(); + boost::hash_combine(seed, (S32)stype); + + switch (stype) + { + case LLSD::TypeBoolean: + boost::hash_combine(seed, s.asBoolean()); + break; + case LLSD::TypeInteger: + boost::hash_combine(seed, s.asInteger()); + break; + case LLSD::TypeReal: + boost::hash_combine(seed, s.asReal()); + break; + case LLSD::TypeURI: + case LLSD::TypeString: + boost::hash_combine(seed, s.asString()); + break; + case LLSD::TypeUUID: + boost::hash_combine(seed, s.asUUID()); + break; + case LLSD::TypeDate: + boost::hash_combine(seed, s.asDate().secondsSinceEpoch()); + break; + case LLSD::TypeBinary: + { + const LLSD::Binary &b(s.asBinary()); + boost::hash_range(seed, b.begin(), b.end()); + break; + } + case LLSD::TypeMap: + { + for (LLSD::map_const_iterator itm = s.beginMap(); itm != s.endMap(); ++itm) + { + boost::hash_combine(seed, (*itm).first); + boost::hash_combine(seed, (*itm).second); + } + break; + } + case LLSD::TypeArray: + for (LLSD::array_const_iterator ita = s.beginArray(); ita != s.endArray(); ++ita) + { + boost::hash_combine(seed, (*ita)); + } + break; + case LLSD::TypeUndefined: + default: + break; + } + + return seed; + } +}; +} + #endif // LL_LLSDUTIL_H diff --git a/indra/llcommon/llsingleton.cpp b/indra/llcommon/llsingleton.cpp index eb8e2c9456..3d32d4771d 100644 --- a/indra/llcommon/llsingleton.cpp +++ b/indra/llcommon/llsingleton.cpp @@ -28,5 +28,5 @@ #include "llsingleton.h" -std::map * LLSingletonRegistry::sSingletonMap = NULL; +std::map* LLSingletonRegistry::sSingletonMap = NULL; diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h index 78b8f95bee..ff31487ec0 100644 --- a/indra/llcommon/llsingleton.h +++ b/indra/llcommon/llsingleton.h @@ -27,39 +27,31 @@ #include "llerror.h" // *TODO: eliminate this +#include #include #include /// @brief A global registry of all singletons to prevent duplicate allocations /// across shared library boundaries -class LL_COMMON_API LLSingletonRegistry { - private: - typedef std::map TypeMap; - static TypeMap * sSingletonMap; - - static void checkInit() - { - if(sSingletonMap == NULL) - { - sSingletonMap = new TypeMap(); - } - } - - public: - template static void * & get() - { - std::string name(typeid(T).name()); +class LL_COMMON_API LLSingletonRegistry +{ + typedef std::map TypeMap; + static TypeMap* sSingletonMap; - checkInit(); +public: + template static void * & get() + { + std::string name(typeid(T).name()); + if (!sSingletonMap) sSingletonMap = new TypeMap(); - // the first entry of the pair returned by insert will be either the existing - // iterator matching our key, or the newly inserted NULL initialized entry - // see "Insert element" in http://www.sgi.com/tech/stl/UniqueAssociativeContainer.html - TypeMap::iterator result = - sSingletonMap->insert(std::make_pair(name, (void*)NULL)).first; + // the first entry of the pair returned by insert will be either the existing + // iterator matching our key, or the newly inserted NULL initialized entry + // see "Insert element" in http://www.sgi.com/tech/stl/UniqueAssociativeContainer.html + TypeMap::iterator result = + sSingletonMap->insert(std::make_pair(name, (void*)NULL)).first; - return result->second; - } + return result->second; + } }; // LLSingleton implements the getInstance() method part of the Singleton @@ -89,7 +81,7 @@ class LL_COMMON_API LLSingletonRegistry { template class LLSingleton : private boost::noncopyable { - + private: typedef enum e_init_state { @@ -99,34 +91,46 @@ class LLSingleton : private boost::noncopyable INITIALIZED, DELETED } EInitState; - + + static DERIVED_TYPE* constructSingleton() + { + return new DERIVED_TYPE(); + } + + struct SingletonData; + // stores pointer to singleton instance - // and tracks initialization state of singleton - struct SingletonInstanceData + struct SingletonLifetimeManager { - EInitState mInitState; - DERIVED_TYPE* mSingletonInstance; - - SingletonInstanceData() - : mSingletonInstance(NULL), - mInitState(UNINITIALIZED) - {} - - ~SingletonInstanceData() + /*SingletonLifetimeManager() + { + construct(); + }*/ + + static void construct() + { + SingletonData& sData(getData()); + sData.mInitState = CONSTRUCTING; + sData.mInstance = constructSingleton(); + sData.mInitState = INITIALIZING; + } + + /*~SingletonLifetimeManager() { - if (mInitState != DELETED) + SingletonData& sData(getData()); + if (sData.mInitState != DELETED) { deleteSingleton(); } - } + }*/ }; - + public: virtual ~LLSingleton() { - SingletonInstanceData& data = getData(); - data.mSingletonInstance = NULL; - data.mInitState = DELETED; + SingletonData& sData(getData()); + sData.mInstance = NULL; + sData.mInitState = DELETED; } /** @@ -151,37 +155,61 @@ class LLSingleton : private boost::noncopyable */ static void deleteSingleton() { - DERIVED_TYPE* instance = getData().mSingletonInstance; - getData().mInitState = DELETED; - getData().mSingletonInstance = NULL; - delete instance; + SingletonData& sData(getData()); + delete sData.mInstance; + sData.mInstance = NULL; + sData.mInitState = DELETED; } - static SingletonInstanceData& getData() + static SingletonData& getData() { // this is static to cache the lookup results static void * & registry = LLSingletonRegistry::get(); // *TODO - look into making this threadsafe - if(NULL == registry) + if (!registry) { - static SingletonInstanceData data; + static SingletonData data; registry = &data; } - return *static_cast(registry); + return *static_cast(registry); } static DERIVED_TYPE* getInstance() { - SingletonInstanceData& data = getData(); + //static SingletonLifetimeManager sLifeTimeMgr; + SingletonData& sData(getData()); - if (data.mInitState != INITIALIZED) + switch (sData.mInitState) { - createInstance(data); + case CONSTRUCTING: + LL_ERRS() << "Tried to access singleton " << typeid(DERIVED_TYPE).name() << " from singleton constructor!" << LL_ENDL; + return NULL; + case INITIALIZING: + LL_WARNS() << "Using singleton " << typeid(DERIVED_TYPE).name() << " during its own initialization, before its initialization completed!" << LL_ENDL; + return sData.mInstance; + case INITIALIZED: + return sData.mInstance; + case DELETED: + LL_WARNS() << "Trying to access deleted singleton " << typeid(DERIVED_TYPE).name() << " creating new instance" << LL_ENDL; + case UNINITIALIZED: + // This must be the first time we get here. + SingletonLifetimeManager::construct(); + // same as first time construction + // Singu note: LL sets the state to INITIALIZED here *already* - which avoids the warning below, but is clearly total bullshit. + sData.mInstance->initSingleton(); + sData.mInitState = INITIALIZED; + return sData.mInstance; } - return data.mSingletonInstance; + return NULL; + } + + static DERIVED_TYPE* getIfExists() + { + SingletonData& sData(getData()); + return sData.mInstance; } // Reference version of getInstance() @@ -190,51 +218,34 @@ class LLSingleton : private boost::noncopyable { return *getInstance(); } - + // Has this singleton been created uet? // Use this to avoid accessing singletons before the can safely be constructed static bool instanceExists() { - return getData().mInitState == INITIALIZED; + SingletonData& sData(getData()); + return sData.mInitState == INITIALIZED; } - + // Has this singleton already been deleted? // Use this to avoid accessing singletons from a static object's destructor static bool destroyed() { - return getData().mInitState == DELETED; + SingletonData& sData(getData()); + return sData.mInitState == DELETED; } private: - static void createInstance(SingletonInstanceData& data); - virtual void initSingleton() {} -}; -// Moved this here cause it's too big to be inlined --Aleric. -template -void LLSingleton::createInstance(SingletonInstanceData& data) -{ - if (data.mInitState == CONSTRUCTING) - { - llerrs << "Tried to access singleton " << typeid(DERIVED_TYPE).name() << " from singleton constructor!" << llendl; - } + virtual void initSingleton() {} - if (data.mInitState == DELETED) - { - llwarns << "Trying to access deleted singleton " << typeid(DERIVED_TYPE).name() << " creating new instance" << llendl; - } - - if (data.mInitState == INITIALIZING) + struct SingletonData { - llerrs << "Tried to access singleton " << typeid(DERIVED_TYPE).name() << " from initSingleton(), using half-initialized object" << llendl; - return; - } - - data.mInitState = CONSTRUCTING; - data.mSingletonInstance = new DERIVED_TYPE(); - data.mInitState = INITIALIZING; - data.mSingletonInstance->initSingleton(); - data.mInitState = INITIALIZED; -} + // explicitly has a default constructor so that member variables are zero initialized in BSS + // and only changed by singleton logic, not constructor running during startup + EInitState mInitState; + DERIVED_TYPE* mInstance; + }; +}; #endif diff --git a/indra/llcommon/llstack.h b/indra/llcommon/llstack.h index 66175c7482..e6642ba21d 100644 --- a/indra/llcommon/llstack.h +++ b/indra/llcommon/llstack.h @@ -33,8 +33,6 @@ #ifndef LL_LLSTACK_H #define LL_LLSTACK_H -#include "linked_lists.h" - template class LLStack { private: diff --git a/indra/llcommon/llstacktrace.cpp b/indra/llcommon/llstacktrace.cpp index e0446c5d0d..8212a4a2ee 100644 --- a/indra/llcommon/llstacktrace.cpp +++ b/indra/llcommon/llstacktrace.cpp @@ -39,7 +39,7 @@ #include #include -#include "windows.h" +#include "llwin32headerslean.h" #include "Dbghelp.h" typedef USHORT NTAPI RtlCaptureStackBackTrace_Function( @@ -73,8 +73,7 @@ bool ll_get_stack_trace(std::vector& lines) if(symbolsLoaded) { // create the frames to hold the addresses - void* frames[MAX_STACK_DEPTH]; - memset(frames, 0, sizeof(void*)*MAX_STACK_DEPTH); + void* frames[MAX_STACK_DEPTH] = {0}; S32 depth = 0; // get the addresses @@ -110,7 +109,7 @@ bool ll_get_stack_trace(std::vector& lines) if(ret) { std::string file_name = line.FileName; - std::string::size_type index = file_name.rfind("\\"); + std::string::size_type index = file_name.rfind('\\'); stack_line << file_name.substr(index + 1, file_name.size()) << ":" << line.LineNumber; } diff --git a/indra/llcommon/llstat.cpp b/indra/llcommon/llstat.cpp index 6cc2246e23..cd62c04cbc 100644 --- a/indra/llcommon/llstat.cpp +++ b/indra/llcommon/llstat.cpp @@ -44,7 +44,6 @@ LLFrameTimer LLStat::sFrameTimer; void LLStat::reset() { mNumValues = 0; - mLastValue = 0.f; delete[] mBins; mBins = new ValueEntry[mNumBins]; mCurBin = mNumBins-1; @@ -57,8 +56,7 @@ LLStat::LLStat(std::string name, S32 num_bins, BOOL use_frame_timer) mName(name), mBins(NULL) { - llassert(mNumBins > 0); - mLastTime = 0.f; + llassert_always(mNumBins > 1); reset(); @@ -66,7 +64,7 @@ LLStat::LLStat(std::string name, S32 num_bins, BOOL use_frame_timer) { stat_map_t::iterator iter = getStatList().find(mName); if (iter != getStatList().end()) - llwarns << "LLStat with duplicate name: " << mName << llendl; + LL_WARNS() << "LLStat with duplicate name: " << mName << LL_ENDL; getStatList().insert(std::make_pair(mName, this)); } } @@ -115,16 +113,8 @@ void LLStat::addValue(const F32 value) } // Increment the bin counters. - mCurBin++; - if ((U32)mCurBin >= mNumBins) - { - mCurBin = 0; - } - mNextBin++; - if ((U32)mNextBin >= mNumBins) - { - mNextBin = 0; - } + mCurBin = (mCurBin+1) % mNumBins; + mNextBin = (mNextBin+1) % mNumBins; mBins[mCurBin].mValue = value; if (mUseFrameTimer) @@ -137,10 +127,6 @@ void LLStat::addValue(const F32 value) } mBins[mCurBin].mDT = (F32)(mBins[mCurBin].mTime - mBins[mCurBin].mBeginTime); - //this value is used to prime the min/max calls - mLastTime = mBins[mCurBin].mTime; - mLastValue = value; - // Set the begin time for the next stat segment. mBins[mNextBin].mBeginTime = mBins[mCurBin].mTime; mBins[mNextBin].mTime = mBins[mCurBin].mTime; @@ -150,36 +136,25 @@ void LLStat::addValue(const F32 value) F32 LLStat::getMax() const { - S32 i; - F32 current_max = mLastValue; - if (mNumBins == 0) + F32 current_max = getCurrent(); + for (S32 i = 0; i < (S32)mNumValues; i++) { - current_max = 0.f; - } - else - { - for (i = 0; (i < (S32)mNumBins) && (i < (S32)mNumValues); i++) + // Skip the bin we're currently filling. + if (i == mNextBin) { - // Skip the bin we're currently filling. - if (i == mNextBin) - { - continue; - } - if (mBins[i].mValue > current_max) - { - current_max = mBins[i].mValue; - } + continue; } + current_max = llmax(current_max, mBins[i].mValue); } + return current_max; } F32 LLStat::getMean() const { - S32 i; - F32 current_mean = 0.f; + F32 current_mean = 0.f; // Don't double-count current. S32 samples = 0; - for (i = 0; (i < (S32)mNumBins) && (i < (S32)mNumValues); i++) + for (S32 i = 0; i < (S32)mNumValues; i++) { // Skip the bin we're currently filling. if (i == mNextBin) @@ -195,37 +170,23 @@ F32 LLStat::getMean() const { current_mean /= samples; } - else - { - current_mean = 0.f; - } return current_mean; } F32 LLStat::getMin() const { - S32 i; - F32 current_min = mLastValue; + F32 current_min = getCurrent(); - if (mNumBins == 0) + for (S32 i = 0; i < (S32)mNumValues; i++) { - current_min = 0.f; - } - else - { - for (i = 0; (i < (S32)mNumBins) && (i < (S32)mNumValues); i++) + // Skip the bin we're currently filling. + if (i == mNextBin) { - // Skip the bin we're currently filling. - if (i == mNextBin) - { - continue; - } - if (mBins[i].mValue < current_min) - { - current_min = mBins[i].mValue; - } + continue; } + current_min = llmin(current_min, mBins[i].mValue); } + return current_min; } @@ -262,7 +223,7 @@ F32 LLStat::getPrevPerSec(S32 age) const // Bogus for bin we're currently working on. return 0.f; } - return mBins[bin].mValue / mBins[bin].mDT; + return (U32(bin) < mNumValues) ? (mBins[bin].mValue / mBins[bin].mDT) : 0.f; } F64 LLStat::getPrevBeginTime(S32 age) const @@ -316,7 +277,7 @@ F32 LLStat::getCurrent() const F32 LLStat::getCurrentPerSec() const { - return mBins[mCurBin].mValue / mBins[mCurBin].mDT; + return (U32(mCurBin) < mNumValues) ? (mBins[mCurBin].mValue / mBins[mCurBin].mDT) : 0.f; } F32 LLStat::getCurrentDuration() const @@ -324,13 +285,17 @@ F32 LLStat::getCurrentDuration() const return mBins[mCurBin].mDT; } +F64 LLStat::getCurrentTime() const +{ + return mBins[mCurBin].mTime; +} + F32 LLStat::getMeanPerSec() const { - S32 i; F32 value = 0.f; F32 dt = 0.f; - for (i = 0; (i < (S32)mNumBins) && (i < (S32)mNumValues); i++) + for (S32 i = 0; i < (S32)mNumValues; i++) { // Skip the bin we're currently filling. if (i == mNextBin) @@ -355,7 +320,7 @@ F32 LLStat::getMeanDuration() const { F32 dur = 0.0f; S32 count = 0; - for (S32 i=0; (i < (S32)mNumBins) && (i < (S32)mNumValues); i++) + for (S32 i=0; i < (S32)mNumValues; i++) { if (i == mNextBin) { @@ -378,22 +343,9 @@ F32 LLStat::getMeanDuration() const F32 LLStat::getMaxPerSec() const { - F32 value; - - if (mNextBin != 0) - { - value = mBins[0].mValue/mBins[0].mDT; - } - else if (mNumValues > 0) - { - value = mBins[1].mValue/mBins[1].mDT; - } - else - { - value = 0.f; - } + F32 value = 0.f; - for (S32 i = 0; (i < (S32)mNumBins) && (i < (S32)mNumValues); i++) + for (S32 i = 0; i < (S32)mNumValues; i++) { // Skip the bin we're currently filling. if (i == mNextBin) @@ -407,23 +359,9 @@ F32 LLStat::getMaxPerSec() const F32 LLStat::getMinPerSec() const { - S32 i; - F32 value; - - if (mNextBin != 0) - { - value = mBins[0].mValue/mBins[0].mDT; - } - else if (mNumValues > 0) - { - value = mBins[1].mValue/mBins[0].mDT; - } - else - { - value = 0.f; - } + F32 value = 0.f; - for (i = 0; (i < (S32)mNumBins) && (i < (S32)mNumValues); i++) + for (S32 i = 0; i < (S32)mNumValues; i++) { // Skip the bin we're currently filling. if (i == mNextBin) @@ -455,7 +393,3 @@ S32 LLStat::getNextBin() const return mNextBin; } -F64 LLStat::getLastTime() const -{ - return mLastTime; -} diff --git a/indra/llcommon/llstat.h b/indra/llcommon/llstat.h index 12737a8ce7..3014bd2463 100644 --- a/indra/llcommon/llstat.h +++ b/indra/llcommon/llstat.h @@ -61,7 +61,8 @@ class LL_COMMON_API LLStat F32 getCurrent() const; F32 getCurrentPerSec() const; F32 getCurrentDuration() const; - + F64 getCurrentTime() const; + F64 getPrevBeginTime(S32 age) const; F64 getPrevTime(S32 age) const; F64 getBinTime(S32 bin) const; @@ -77,13 +78,12 @@ class LL_COMMON_API LLStat U32 getNumValues() const; S32 getNumBins() const; - F64 getLastTime() const; + private: - BOOL mUseFrameTimer; + const BOOL mUseFrameTimer; + const U32 mNumBins; + U32 mNumValues; - U32 mNumBins; - F32 mLastValue; - F64 mLastTime; struct ValueEntry { @@ -102,7 +102,7 @@ class LL_COMMON_API LLStat S32 mCurBin; S32 mNextBin; - std::string mName; + const std::string mName; static LLTimer sTimer; static LLFrameTimer sFrameTimer; diff --git a/indra/llcommon/llstaticstringtable.h b/indra/llcommon/llstaticstringtable.h new file mode 100644 index 0000000000..537fa00f31 --- /dev/null +++ b/indra/llcommon/llstaticstringtable.h @@ -0,0 +1,82 @@ +/** + * @file llstringtable.h + * @brief The LLStringTable class provides a _fast_ method for finding + * unique copies of strings. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_STATIC_STRING_TABLE_H +#define LL_STATIC_STRING_TABLE_H + +#include "lldefs.h" +#include +#include "llstl.h" + +class LLStaticHashedString +{ +public: + + LLStaticHashedString(const std::string& s) + { + string_hash = makehash(s); + string = s; + } + + const std::string& String() const { return string; } + size_t Hash() const { return string_hash; } + + bool operator==(const LLStaticHashedString& b) const { return Hash() == b.Hash(); } + +protected: + + size_t makehash(const std::string& s) + { + size_t len = s.size(); + const char* c = s.c_str(); + size_t hashval = 0; + for (size_t i=0; i +class LLStaticStringTable + : public boost::unordered_map< LLStaticHashedString, MappedObject, LLStaticStringHasher > +{ +}; + +#endif + diff --git a/indra/llcommon/llstl.h b/indra/llcommon/llstl.h index ec98bb911c..34ca7dfce2 100644 --- a/indra/llcommon/llstl.h +++ b/indra/llcommon/llstl.h @@ -35,11 +35,13 @@ #include #include -#include +#include #include +#include #include -#include +#include #include +#include "stdtypes.h" // Use to compare the first element only of a pair // e.g. typedef std::set, compare_pair > some_pair_set_t; @@ -175,19 +177,55 @@ struct CopyNewPointer } }; +template +void delete_and_clear(std::list& list) +{ + std::for_each(list.begin(), list.end(), DeletePointer()); + list.clear(); +} + +template +void delete_and_clear(std::vector& vector) +{ + std::for_each(vector.begin(), vector.end(), DeletePointer()); + vector.clear(); +} + +template +void delete_and_clear(std::set& set) +{ + std::for_each(set.begin(), set.end(), DeletePointer()); + set.clear(); +} + +template +void delete_and_clear(std::map& map) +{ + std::for_each(map.begin(), map.end(), DeletePairedPointer()); + map.clear(); +} + +template +void delete_and_clear(T*& ptr) +{ + delete ptr; + ptr = NULL; +} + + +template +void delete_and_clear_array(T*& ptr) +{ + delete[] ptr; + ptr = NULL; +} + // helper function which returns true if key is in inmap. template //Singu note: This has been generalized to support a broader range of map-esque containers inline bool is_in_map(const T& inmap, typename T::key_type const& key) { - if(inmap.find(key) == inmap.end()) - { - return false; - } - else - { - return true; - } + return inmap.find(key) != inmap.end(); } // Similar to get_ptr_in_map, but for any type with a valid T(0) constructor. @@ -227,6 +265,24 @@ inline typename T::mapped_type get_ptr_in_map(const T& inmap, typename T::key_ty return get_if_there(inmap,key,NULL); }; +template +inline typename T::iterator get_in_vec(T& invec, P pred) +{ + return std::find_if(invec.begin(), invec.end(), pred); +} + +template +inline typename T::value_type::second_type& get_val_in_pair_vec(T& invec, K key) +{ + auto it = get_in_vec(invec, [&key](typename T::value_type& e) { return e.first == key; }); + if (it == invec.end()) + { + invec.emplace_back(key, typename T::value_type::second_type()); + return invec.back().second; + } + return it->second; +} + // Useful for replacing the removeObj() functionality of LLDynamicArray // Example: // for (std::vector::iterator iter = mList.begin(); iter != mList.end(); ) @@ -239,14 +295,14 @@ inline typename T::mapped_type get_ptr_in_map(const T& inmap, typename T::key_ty // //Singu note: This has been generalized to support a broader range of sequence containers template -inline typename T::iterator vector_replace_with_last(T& invec, typename T::iterator& iter) +inline typename T::iterator vector_replace_with_last(T& invec, typename T::iterator iter) { - typename T::iterator last = invec.end(); --last; + typename T::iterator last = invec.end(); if (iter == invec.end()) { return iter; } - else if (iter == last) + else if (iter == --last) { invec.pop_back(); return invec.end(); @@ -280,9 +336,9 @@ inline bool vector_replace_with_last(T& invec, typename T::value_type const& val // Append N elements to the vector and return a pointer to the first new element. template -inline T* vector_append(std::vector& invec, S32 N) +inline T* vector_append(std::vector& invec, size_t N) { - U32 sz = invec.size(); + size_t sz = invec.size(); invec.resize(sz+N); return &(invec[sz]); } @@ -353,7 +409,7 @@ OutputIter ll_transform_n( template struct _LLSelect1st : public std::unary_function<_Pair, typename _Pair::first_type> { const typename _Pair::first_type& operator()(const _Pair& __x) const { - return __x.first; + return __x.first; } }; @@ -361,7 +417,7 @@ template struct _LLSelect2nd : public std::unary_function<_Pair, typename _Pair::second_type> { const typename _Pair::second_type& operator()(const _Pair& __x) const { - return __x.second; + return __x.second; } }; @@ -381,10 +437,10 @@ class ll_unary_compose : _Operation2 __op2; public: ll_unary_compose(const _Operation1& __x, const _Operation2& __y) - : __op1(__x), __op2(__y) {} + : __op1(__x), __op2(__y) {} typename _Operation1::result_type operator()(const typename _Operation2::argument_type& __x) const { - return __op1(__op2(__x)); + return __op1(__op2(__x)); } }; @@ -406,20 +462,20 @@ class ll_binary_compose public: ll_binary_compose(const _Operation1& __x, const _Operation2& __y, const _Operation3& __z) - : _M_op1(__x), _M_op2(__y), _M_op3(__z) { } + : _M_op1(__x), _M_op2(__y), _M_op3(__z) { } typename _Operation1::result_type operator()(const typename _Operation2::argument_type& __x) const { - return _M_op1(_M_op2(__x), _M_op3(__x)); + return _M_op1(_M_op2(__x), _M_op3(__x)); } }; template inline ll_binary_compose<_Operation1, _Operation2, _Operation3> llcompose2(const _Operation1& __op1, const _Operation2& __op2, - const _Operation3& __op3) + const _Operation3& __op3) { return ll_binary_compose<_Operation1,_Operation2,_Operation3> - (__op1, __op2, __op3); + (__op1, __op2, __op3); } // helpers to deal with the fact that MSDev does not package @@ -434,7 +490,7 @@ class llbinder1st : public: llbinder1st(const _Operation& __x, const typename _Operation::first_argument_type& __y) - : op(__x), value(__y) {} + : op(__x), value(__y) {} typename _Operation::result_type operator()(const typename _Operation::second_argument_type& __x) const { return op(value, __x); @@ -481,18 +537,8 @@ llbind2nd(const _Operation& __oper, const _Tp& __x) inline bool before(const std::type_info* lhs, const std::type_info* rhs) { -#if LL_LINUX && defined(__GNUC__) && ((__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC_MINOR__ < 4)) - // If we're building on Linux with gcc, and it's either gcc 3.x or - // 4.{0,1,2,3}, then we have to use a workaround. Note that we use gcc on - // Mac too, and some people build with gcc on Windows (cygwin or mingw). - // On Linux, different load modules may produce different type_info* - // pointers for the same type. Have to compare name strings to get good - // results. - return strcmp(lhs->name(), rhs->name()) < 0; -#else // not Linux, or gcc 4.4+ // Just use before(), as we normally would - return lhs->before(*rhs); -#endif + return lhs->before(*rhs) ? true : false; } /** @@ -524,4 +570,151 @@ namespace std }; } // std + +/** + * Implementation for ll_template_cast() (q.v.). + * + * Default implementation: trying to cast two completely unrelated types + * returns 0. Typically you'd specify T and U as pointer types, but in fact T + * can be any type that can be initialized with 0. + */ +template +struct ll_template_cast_impl +{ + T operator()(U) + { + return 0; + } +}; + +/** + * ll_template_cast(some_value) is for use in a template function when + * some_value might be of arbitrary type, but you want to recognize type T + * specially. + * + * It's designed for use with pointer types. Example: + * @code + * struct SpecialClass + * { + * void someMethod(const std::string&) const; + * }; + * + * template + * void somefunc(const REALCLASS& instance) + * { + * const SpecialClass* ptr = ll_template_cast(&instance); + * if (ptr) + * { + * ptr->someMethod("Call method only available on SpecialClass"); + * } + * } + * @endcode + * + * Why is this better than dynamic_cast<>? Because unless OtherClass is + * polymorphic, the following won't even compile (gcc 4.0.1): + * @code + * OtherClass other; + * SpecialClass* ptr = dynamic_cast(&other); + * @endcode + * to say nothing of this: + * @code + * void function(int); + * SpecialClass* ptr = dynamic_cast(&function); + * @endcode + * ll_template_cast handles these kinds of cases by returning 0. + */ +template +T ll_template_cast(U value) +{ + return ll_template_cast_impl()(value); +} + +/** + * Implementation for ll_template_cast() (q.v.). + * + * Implementation for identical types: return same value. + */ +template +struct ll_template_cast_impl +{ + T operator()(T value) + { + return value; + } +}; + +/** + * LL_TEMPLATE_CONVERTIBLE(dest, source) asserts that, for a value @c s of + * type @c source, ll_template_cast(s) will return @c s -- + * presuming that @c source can be converted to @c dest by the normal rules of + * C++. + * + * By default, ll_template_cast(s) will return 0 unless @c s's + * type is literally identical to @c dest. (This is because of the + * straightforward application of template specialization rules.) That can + * lead to surprising results, e.g.: + * + * @code + * Foo myFoo; + * const Foo* fooptr = ll_template_cast(&myFoo); + * @endcode + * + * Here @c fooptr will be 0 because &myFoo is of type Foo* + * -- @em not const Foo*. (Declaring const Foo myFoo; would + * force the compiler to do the right thing.) + * + * More disappointingly: + * @code + * struct Base {}; + * struct Subclass: public Base {}; + * Subclass object; + * Base* ptr = ll_template_cast(&object); + * @endcode + * + * Here @c ptr will be 0 because &object is of type + * Subclass* rather than Base*. We @em want this cast to + * succeed, but without our help ll_template_cast can't recognize it. + * + * The following would suffice: + * @code + * LL_TEMPLATE_CONVERTIBLE(Base*, Subclass*); + * ... + * Base* ptr = ll_template_cast(&object); + * @endcode + * + * However, as noted earlier, this is easily fooled: + * @code + * const Base* ptr = ll_template_cast(&object); + * @endcode + * would still produce 0 because we haven't yet seen: + * @code + * LL_TEMPLATE_CONVERTIBLE(const Base*, Subclass*); + * @endcode + * + * @TODO + * This macro should use Boost type_traits facilities for stripping and + * re-adding @c const and @c volatile qualifiers so that invoking + * LL_TEMPLATE_CONVERTIBLE(dest, source) will automatically generate all + * permitted permutations. It's really not fair to the coder to require + * separate: + * @code + * LL_TEMPLATE_CONVERTIBLE(Base*, Subclass*); + * LL_TEMPLATE_CONVERTIBLE(const Base*, Subclass*); + * LL_TEMPLATE_CONVERTIBLE(const Base*, const Subclass*); + * @endcode + * + * (Naturally we omit LL_TEMPLATE_CONVERTIBLE(Base*, const Subclass*) + * because that's not permitted by normal C++ assignment anyway.) + */ +#define LL_TEMPLATE_CONVERTIBLE(DEST, SOURCE) \ +template <> \ +struct ll_template_cast_impl \ +{ \ + DEST operator()(SOURCE wrapper) \ + { \ + return wrapper; \ + } \ +} + + #endif // LL_LLSTL_H diff --git a/indra/llcommon/llstreamtools.cpp b/indra/llcommon/llstreamtools.cpp index 4ed2df58e0..b3c83dadc8 100644 --- a/indra/llcommon/llstreamtools.cpp +++ b/indra/llcommon/llstreamtools.cpp @@ -124,7 +124,7 @@ bool skip_to_next_word(std::istream& input_stream) bool skip_to_end_of_next_keyword(const char* keyword, std::istream& input_stream) { - int key_length = strlen(keyword); /*Flawfinder: ignore*/ + size_t key_length = strlen(keyword); /*Flawfinder: ignore*/ if (0 == key_length) { return false; @@ -139,7 +139,7 @@ bool skip_to_end_of_next_keyword(const char* keyword, std::istream& input_stream } else { - int key_index = 1; + size_t key_index = 1; while ( key_index < key_length && keyword[key_index - 1] == c && input_stream.good()) @@ -321,7 +321,7 @@ bool unget_line(const std::string& line, std::istream& input_stream) // returns true if removed last char bool remove_last_char(char c, std::string& line) { - int line_size = line.size(); + size_t line_size = line.size(); if (line_size > 1 && c == line[line_size - 1]) { diff --git a/indra/llcommon/llstrider.h b/indra/llcommon/llstrider.h index b4f310a512..cfded258b9 100644 --- a/indra/llcommon/llstrider.h +++ b/indra/llcommon/llstrider.h @@ -34,6 +34,17 @@ #include "stdtypes.h" +template +inline void copyArray(T* dst, const T* src, const U32 bytes) +{ + memcpy(dst, src, bytes); +} +template<> +inline void copyArray<>(LLVector4a* dst, const LLVector4a* src, const U32 bytes) +{ + LLVector4a::memcpyNonAliased16(dst->getF32ptr(), src->getF32ptr(), bytes); +} + template class LLStrider { union @@ -68,8 +79,22 @@ template class LLStrider Object* operator ++(int) { Object* old = mObjectp; mBytep += mSkip; return old; } Object* operator +=(int i) { mBytep += mSkip*i; return mObjectp; } - Object& operator[](U32 index) { return *(Object*)(mBytep + (mSkip * index)); } - + Object& operator[](size_t index) { return *(Object*)(mBytep + (mSkip * index)); } + + void copyArray(const U32 offset, const Object* src, const U32 length) + { + if (mSkip == sizeof(Object)) + { + ::copyArray(mObjectp + offset, src, length * sizeof(Object)); + } + else + { + for (U32 i = 0; i < length; i++) + { + (*this)[offset + i] = src[i]; + } + } + } }; #endif // LL_LLSTRIDER_H diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp index 8953a1089b..e55bb15639 100644 --- a/indra/llcommon/llstring.cpp +++ b/indra/llcommon/llstring.cpp @@ -1,3 +1,5 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com /** * @file llstring.cpp * @brief String utility functions and the std::string class. @@ -28,15 +30,15 @@ #include "llstring.h" #include "llerror.h" +#include "llfasttimer.h" +#include "llsd.h" #if LL_WINDOWS -#define WIN32_LEAN_AND_MEAN -#include -#include +#include "llwin32headerslean.h" #include // for WideCharToMultiByte #endif -LLFastTimer::DeclareTimer FT_STRING_FORMAT("String Format"); +LLTrace::BlockTimerStatHandle FT_STRING_FORMAT("String Format"); std::string ll_safe_string(const char* in) @@ -52,6 +54,23 @@ std::string ll_safe_string(const char* in, S32 maxlen) return std::string(); } +bool is_char_hex(char hex) +{ + if((hex >= '0') && (hex <= '9')) + { + return true; + } + else if((hex >= 'a') && (hex <='f')) + { + return true; + } + else if((hex >= 'A') && (hex <='F')) + { + return true; + } + return false; // uh - oh, not hex any more... +} + U8 hex_as_nybble(char hex) { if((hex >= '0') && (hex <= '9')) @@ -90,10 +109,10 @@ bool iswindividual(llwchar elem) bool _read_file_into_string(std::string& str, const std::string& filename) { - llifstream ifs(filename, llifstream::binary); + llifstream ifs(filename.c_str(), llifstream::binary); if (!ifs.is_open()) { - llinfos << "Unable to open file " << filename << llendl; + LL_INFOS() << "Unable to open file " << filename << LL_ENDL; return false; } @@ -171,16 +190,16 @@ S32 wchar_to_utf8chars(llwchar in_char, char* outchars) } else { - llwarns << "Invalid Unicode character " << cur_char << "!" << llendl; + LL_WARNS() << "Invalid Unicode character " << cur_char << "!" << LL_ENDL; *outchars++ = LL_UNKNOWN_CHAR; } return outchars - base; } -S32 utf16chars_to_wchar(const U16* inchars, llwchar* outchar) +S32 utf16chars_to_wchar(const utf16strtype* inchars, llwchar* outchar) { - const U16* base = inchars; - U16 cur_char = *inchars++; + const utf16strtype* base = inchars; + utf16strtype cur_char = *inchars++; llwchar char32 = cur_char; if ((cur_char >= 0xD800) && (cur_char <= 0xDFFF)) { @@ -214,7 +233,7 @@ llutf16string wstring_to_utf16str(const LLWString &utf32str, S32 len) { out += cur_char; } - i++; + ++i; } return out; } @@ -239,7 +258,7 @@ LLWString utf16str_to_wstring(const llutf16string &utf16str, S32 len) S32 i = 0; // craziness to make gcc happy (llutf16string.c_str() is tweaked on linux): - const U16* chars16 = &(*(utf16str.begin())); + const utf16strtype* chars16 = &(*(utf16str.begin())); while (i < len) { llwchar cur_char; @@ -260,18 +279,18 @@ S32 utf16str_wstring_length(const llutf16string &utf16str, const S32 utf16_len) { S32 surrogate_pairs = 0; // ... craziness to make gcc happy (llutf16string.c_str() is tweaked on linux): - const U16 *const utf16_chars = &(*(utf16str.begin())); + const utf16strtype *const utf16_chars = &(*(utf16str.begin())); S32 i = 0; while (i < utf16_len) { - const U16 c = utf16_chars[i++]; + const utf16strtype c = utf16_chars[i++]; if (c >= 0xD800 && c <= 0xDBFF) // See http://en.wikipedia.org/wiki/UTF-16 { // Have first byte of a surrogate pair if (i >= utf16_len) { break; } - const U16 d = utf16_chars[i]; + const utf16strtype d = utf16_chars[i]; if (d >= 0xDC00 && d <= 0xDFFF) { // Have valid second byte of a surrogate pair surrogate_pairs++; @@ -377,12 +396,12 @@ S32 wstring_utf8_length(const LLWString& wstr) LLWString utf8str_to_wstring(const std::string& utf8str, S32 len) { + llwchar unichar; LLWString wout; + wout.reserve(len); - S32 i = 0; - while (i < len) + for (S32 i = 0; i < len; i++) { - llwchar unichar; U8 cur_char = utf8str[i]; if (cur_char < 0x80) @@ -458,7 +477,6 @@ LLWString utf8str_to_wstring(const std::string& utf8str, S32 len) } wout += unichar; - ++i; } return wout; } @@ -471,16 +489,15 @@ LLWString utf8str_to_wstring(const std::string& utf8str) std::string wstring_to_utf8str(const LLWString& utf32str, S32 len) { + char tchars[8]; /* Flawfinder: ignore */ std::string out; + out.reserve(len); - S32 i = 0; - while (i < len) + for (S32 i = 0; i < len; ++i) { - char tchars[8]; /* Flawfinder: ignore */ S32 n = wchar_to_utf8chars(utf32str[i], tchars); tchars[n] = 0; out += tchars; - i++; } return out; } @@ -559,6 +576,105 @@ std::string utf8str_truncate(const std::string& utf8str, const S32 max_len) } } +// [RLVa:KB] - Checked: RLVa-2.1.0 +std::string utf8str_substr(const std::string& utf8str, const size_t index, const size_t max_len) +{ + if (0 == max_len) + { + return std::string(); + } + if (utf8str.length() - index <= max_len) + { + return utf8str.substr(index, max_len); + } + else + { + size_t cur_char = max_len; + + // If we're ASCII, we don't need to do anything + if ((U8)utf8str[index + cur_char] > 0x7f) + { + // If first two bits are (10), it's the tail end of a multibyte char. We need to shift back + // to the first character + while (0x80 == (0xc0 & utf8str[index + cur_char])) + { + cur_char--; + // Keep moving forward until we hit the first char; + if (cur_char == 0) + { + // Make sure we don't trash memory if we've got a bogus string. + break; + } + } + } + // The byte index we're on is one we want to get rid of, so we only want to copy up to (cur_char-1) chars + return utf8str.substr(index, cur_char); + } +} + +void utf8str_split(std::list& split_list, const std::string& utf8str, size_t maxlen, char split_token) +{ + split_list.clear(); + + std::string::size_type lenMsg = utf8str.length(), lenIt = 0; + + const char* pstrIt = utf8str.c_str(); std::string strTemp; + while (lenIt < lenMsg) + { + if (lenIt + maxlen < lenMsg) + { + // Find the last split character + const char* pstrTemp = pstrIt + maxlen; + while ( (pstrTemp > pstrIt) && (*pstrTemp != split_token) ) + pstrTemp--; + + if (pstrTemp > pstrIt) + strTemp = utf8str.substr(lenIt, pstrTemp - pstrIt); + else + strTemp = utf8str_substr(utf8str, lenIt, maxlen); + } + else + { + strTemp = utf8str.substr(lenIt, std::string::npos); + } + + split_list.push_back(strTemp); + + lenIt += strTemp.length(); + pstrIt = utf8str.c_str() + lenIt; + if (*pstrIt == split_token) + lenIt++; + } +} +// [/RLVa:KB] + +std::string utf8str_symbol_truncate(const std::string& utf8str, const size_t symbol_len) +{ + if (0 == symbol_len) + { + return std::string(); + } + if ((S32)utf8str.length() <= symbol_len) + { + return utf8str; + } + else + { + size_t len = 0, byteIndex = 0; + const char* aStr = utf8str.c_str(); + size_t origSize = utf8str.size(); + + for (byteIndex = 0; len < symbol_len && byteIndex < origSize; byteIndex++) + { + if ((aStr[byteIndex] & 0xc0) != 0x80) + { + len += 1; + } + } + return utf8str.substr(0, byteIndex); + } +} + std::string utf8str_substChar( const std::string& utf8str, const llwchar target_char, @@ -624,20 +740,10 @@ bool LLStringOps::isHexString(const std::string& str) } #if LL_WINDOWS -// documentation moved to header. Phoenix 2007-11-27 -namespace snprintf_hack -{ - int snprintf(char *str, size_t size, const char *format, ...) - { - va_list args; - va_start(args, format); - int num_written = _vsnprintf(str, size, format, args); /* Flawfinder: ignore */ - va_end(args); - - str[size-1] = '\0'; // always null terminate - return num_written; - } +std::string ll_convert_wide_to_string(const wchar_t* in) +{ + return ll_convert_wide_to_string(in, CP_UTF8); } std::string ll_convert_wide_to_string(const wchar_t* in, unsigned int code_page) @@ -651,10 +757,10 @@ std::string ll_convert_wide_to_string(const wchar_t* in, unsigned int code_page) 0, in, len_in, - NULL, - 0, + nullptr, 0, - 0); + nullptr, + nullptr); // We will need two more bytes for the double NULL ending // created in WideCharToMultiByte(). char* pout = new char [len_out + 2]; @@ -668,8 +774,8 @@ std::string ll_convert_wide_to_string(const wchar_t* in, unsigned int code_page) len_in, pout, len_out, - 0, - 0); + nullptr, + nullptr); out.assign(pout); delete[] pout; } @@ -677,6 +783,11 @@ std::string ll_convert_wide_to_string(const wchar_t* in, unsigned int code_page) return out; } +wchar_t* ll_convert_string_to_wide(const std::string& in) +{ + return ll_convert_string_to_wide(in, CP_UTF8); +} + wchar_t* ll_convert_string_to_wide(const std::string& in, unsigned int code_page) { // From review: @@ -690,14 +801,75 @@ wchar_t* ll_convert_string_to_wide(const std::string& in, unsigned int code_page // reserve place to NULL terminator int output_str_len = in.length(); wchar_t* w_out = new wchar_t[output_str_len + 1]; - memset(w_out, 0, output_str_len + 1); + int real_output_str_len = MultiByteToWideChar (code_page, 0, in.c_str(), in.length(), w_out, output_str_len); //looks like MultiByteToWideChar didn't add null terminator to converted string, see EXT-4858. w_out[real_output_str_len] = 0; return w_out; +// return {&w_out[0]}; +} + +S32 wchartchars_to_llwchar(const std::wstring::value_type* inchars, llwchar* outchar) +{ + const std::wstring::value_type* base = inchars; + std::wstring::value_type cur_char = *inchars++; + llwchar char32 = cur_char; + if ((cur_char >= 0xD800) && (cur_char <= 0xDFFF)) + { + // Surrogates + char32 = ((llwchar)(cur_char - 0xD800)) << 10; + cur_char = *inchars++; + char32 += (llwchar)(cur_char - 0xDC00) + 0x0010000UL; + } + else + { + char32 = (llwchar)cur_char; + } + *outchar = char32; + return inchars - base; +} + +LLWString ll_convert_wide_to_wstring(const std::wstring& in) +{ + LLWString wout; + auto len = in.size(); + if ((len <= 0) || in.empty()) return wout; + + size_t i = 0; + // craziness to make gcc happy (llutf16string.c_str() is tweaked on linux): + const std::wstring::value_type* chars16 = &(*(in.begin())); + while (i < len) + { + llwchar cur_char; + i += wchartchars_to_llwchar(chars16 + i, &cur_char); + wout += cur_char; + } + return wout; +} + +std::wstring ll_convert_wstring_to_wide(const LLWString& in) +{ + std::wstring out; + + size_t i = 0; + while (i < in.size()) + { + U32 cur_char = in[i]; + if (cur_char > 0xFFFF) + { + out += (0xD7C0 + (cur_char >> 10)); + out += (0xDC00 | (cur_char & 0x3FF)); + } + else + { + out += cur_char; + } + i++; + } + return out; } std::string ll_convert_string_to_utf8_string(const std::string& in) @@ -708,11 +880,112 @@ std::string ll_convert_string_to_utf8_string(const std::string& in) return out_utf8; } -#endif // LL_WINDOWS + +namespace +{ + +void HeapFree_deleter(void* ptr) +{ + // instead of LocalFree(), per https://stackoverflow.com/a/31541205 + HeapFree(GetProcessHeap(), NULL, ptr); +} + +} // anonymous namespace + +template<> +std::wstring windows_message(DWORD error) +{ + // derived from https://stackoverflow.com/a/455533 + wchar_t* rawptr = nullptr; + auto okay = FormatMessageW( + // use system message tables for GetLastError() codes + FORMAT_MESSAGE_FROM_SYSTEM | + // internally allocate buffer and return its pointer + FORMAT_MESSAGE_ALLOCATE_BUFFER | + // you cannot pass insertion parameters (thanks Gandalf) + FORMAT_MESSAGE_IGNORE_INSERTS | + // ignore line breaks in message definition text + FORMAT_MESSAGE_MAX_WIDTH_MASK, + NULL, // lpSource, unused with FORMAT_MESSAGE_FROM_SYSTEM + error, // dwMessageId + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // dwLanguageId + (LPWSTR)&rawptr, // lpBuffer: force-cast wchar_t** to wchar_t* + 0, // nSize, unused with FORMAT_MESSAGE_ALLOCATE_BUFFER + NULL); // Arguments, unused + + // make a unique_ptr from rawptr so it gets cleaned up properly + std::unique_ptr bufferptr(rawptr, HeapFree_deleter); + + if (okay && bufferptr) + { + // got the message, return it ('okay' is length in characters) + return { bufferptr.get(), okay }; + } + + // did not get the message, synthesize one + auto format_message_error = GetLastError(); + std::wostringstream out; + out << L"GetLastError() " << error << L" (FormatMessageW() failed with " + << format_message_error << L")"; + return out.str(); +} + +boost::optional llstring_getoptenv(const std::string& key) +{ + auto wkey = ll_convert_string_to_wide(key); + // Take a wild guess as to how big the buffer should be. + std::vector buffer(1024); + auto n = GetEnvironmentVariableW(wkey, &buffer[0], buffer.size()); + // If our initial guess was too short, n will indicate the size (in + // wchar_t's) that buffer should have been, including the terminating nul. + if (n > (buffer.size() - 1)) + { + // make it big enough + buffer.resize(n); + // and try again + n = GetEnvironmentVariableW(wkey, &buffer[0], buffer.size()); + } + // did that (ultimately) succeed? + if (n) + { + // great, return populated boost::optional + return boost::optional(&buffer[0]); + } + + // not successful + auto last_error = GetLastError(); + // Don't bother warning for NOT_FOUND; that's an expected case + if (last_error != ERROR_ENVVAR_NOT_FOUND) + { + LL_WARNS() << "GetEnvironmentVariableW('" << key << "') failed: " + << windows_message(last_error) << LL_ENDL; + } + // return empty boost::optional + return {}; +} + +#else // ! LL_WINDOWS + +boost::optional llstring_getoptenv(const std::string& key) +{ + auto found = getenv(key.c_str()); + if (found) + { + // return populated boost::optional + return boost::optional(found); + } + else + { + // return empty boost::optional + return {}; + } +} + +#endif // ! LL_WINDOWS long LLStringOps::sPacificTimeOffset = 0; long LLStringOps::sLocalTimeOffset = 0; -bool LLStringOps::sPacificDaylightTime = 0; +bool LLStringOps::sPacificDaylightTime = false; std::map LLStringOps::datetimeToCodes; std::vector LLStringOps::sWeekDayList; @@ -731,7 +1004,7 @@ S32 LLStringOps::collate(const llwchar* a, const llwchar* b) #if LL_WINDOWS // in Windows, wide string functions operator on 16-bit strings, // not the proper 32 bit wide string - return strcmp(wstring_to_utf8str(LLWString(a)).c_str(), wstring_to_utf8str(LLWString(b)).c_str()); + return strcoll(wstring_to_utf8str(LLWString(a)).c_str(), wstring_to_utf8str(LLWString(b)).c_str()); #else return wcscoll(a, b); #endif @@ -742,7 +1015,7 @@ void LLStringOps::setupDatetimeInfo (bool daylight) time_t nowT, localT, gmtT; struct tm * tmpT; - nowT = time (NULL); + nowT = time (nullptr); tmpT = gmtime (&nowT); gmtT = mktime (tmpT); @@ -822,7 +1095,7 @@ void LLStringOps::setupDayFormat(const std::string& data) } -std::string LLStringOps::getDatetimeCode (std::string key) +std::string LLStringOps::getDatetimeCode(const std::string& key) { std::map::iterator iter; @@ -833,11 +1106,31 @@ std::string LLStringOps::getDatetimeCode (std::string key) } else { - return std::string(""); + return std::string(); } } +std::string LLStringOps::getReadableNumber(F64 num) +{ + if (fabs(num)>=1e9) + { + return llformat("%.2lfB", num / 1e9); + } + else if (fabs(num)>=1e6) + { + return llformat("%.2lfM", num / 1e6); + } + else if (fabs(num)>=1e3) + { + return llformat("%.2lfK", num / 1e3); + } + else + { + return llformat("%.2lf", num); + } +} + namespace LLStringFn { // NOTE - this restricts output to ascii @@ -1047,7 +1340,8 @@ void LLStringUtil::formatNumber(std::string& numStr, std::string decimals) // std::locale() throws if the locale is unknown! (EXT-7926) try { - strStream.imbue(std::locale(sLocale.c_str())); + std::locale locale(sLocale.c_str()); + strStream.imbue(locale); } catch (const std::exception &) { LL_WARNS_ONCE("Locale") << "Cannot set locale to " << sLocale << LL_ENDL; @@ -1060,8 +1354,7 @@ void LLStringUtil::formatNumber(std::string& numStr, std::string decimals) if (convertToS32(numStr, intStr)) { - strStream << intStr; - numStr = strStream.str(); + numStr = fmt::to_string(intStr); } } else @@ -1104,7 +1397,7 @@ bool LLStringUtil::formatDatetime(std::string& replacement, std::string token, } else if (param == "local") { - replacement = ""; // user knows their own timezone + replacement.clear(); // user knows their own timezone } else { @@ -1141,14 +1434,14 @@ bool LLStringUtil::formatDatetime(std::string& replacement, std::string token, { struct tm * gmt = gmtime (&loc_seconds); LLStringUtil::format_map_t args; - args["[MDAY]"] = llformat ("%d", gmt->tm_mday); + args["[MDAY]"] = fmt::to_string(gmt->tm_mday); replacement = LLStringOps::sDayFormat; LLStringUtil::format(replacement, args); } else if (code == "%-d") { struct tm * gmt = gmtime (&loc_seconds); - replacement = llformat ("%d", gmt->tm_mday); // day of the month without leading zero + replacement = fmt::to_string(gmt->tm_mday); // day of the month without leading zero } else if( !LLStringOps::sAM.empty() && !LLStringOps::sPM.empty() && code == "%p" ) { @@ -1190,7 +1483,7 @@ bool LLStringUtil::formatDatetime(std::string& replacement, std::string token, template<> S32 LLStringUtil::format(std::string& s, const format_map_t& substitutions) { - LLFastTimer ft(FT_STRING_FORMAT); + LL_RECORD_BLOCK_TIME(FT_STRING_FORMAT); S32 res = 0; std::string output; @@ -1263,7 +1556,7 @@ S32 LLStringUtil::format(std::string& s, const format_map_t& substitutions) template<> S32 LLStringUtil::format(std::string& s, const LLSD& substitutions) { - LLFastTimer ft(FT_STRING_FORMAT); + LL_RECORD_BLOCK_TIME(FT_STRING_FORMAT); S32 res = 0; if (!substitutions.isMap()) @@ -1392,7 +1685,7 @@ void LLStringUtilBase::testHarness() s2.erase( 4, 1 ); llassert( s2 == "hell"); - s2.insert( 0, 1, 'y' ); + s2.insert( s2.begin(), 'y' ); llassert( s2 == "yhell"); s2.erase( 1, 3 ); llassert( s2 == "yl"); diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h index 35d20d2ee8..0b7d67232b 100644 --- a/indra/llcommon/llstring.h +++ b/indra/llcommon/llstring.h @@ -27,12 +27,29 @@ #ifndef LL_LLSTRING_H #define LL_LLSTRING_H +#include #include + +#if __cplusplus < 201606 +#include +namespace std { + typedef absl::string_view string_view; +} +#else + #include +#endif + #include -#include +//#include #include -#include "llsd.h" -#include "llfasttimer.h" +#include +#include +#include +#include "stdtypes.h" +#include "llpreprocessor.h" +// [RLVa:KB] - Checked: RLVa-2.1.0 +#include +// [/RLVa:KB] #if LL_LINUX || LL_SOLARIS #include @@ -49,6 +66,7 @@ #endif const char LL_UNKNOWN_CHAR = '?'; +class LLSD; #if LL_DARWIN || LL_LINUX || LL_SOLARIS // Template specialization of char_traits for U16s. Only necessary on Mac and Linux (exists on Windows already) @@ -209,7 +227,10 @@ class LL_COMMON_API LLStringOps // currently in daylight savings time? static bool getPacificDaylightTime(void) { return sPacificDaylightTime;} - static std::string getDatetimeCode (std::string key); + static std::string getDatetimeCode (const std::string& key); + + // Express a value like 1234567 as "1.23M" + static std::string getReadableNumber(F64 num); }; /** @@ -231,7 +252,9 @@ class LLFormatMapString operator std::string() const { return mString; } bool operator<(const LLFormatMapString& rhs) const { return mString < rhs.mString; } std::size_t length() const { return mString.length(); } - + // The destructor may not throw. + ~LLFormatMapString() noexcept { } + private: std::string mString; }; @@ -306,6 +329,7 @@ class LLStringUtilBase static void trimHead(string_type& string); static void trimTail(string_type& string); + static void trimTail(string_type& string, const string_type& tokens); static void trim(string_type& string) { trimHead(string); trimTail(string); } static void truncate(string_type& string, size_type count); @@ -333,8 +357,22 @@ class LLStringUtilBase const string_type& string, const string_type& substr); + /** + * get environment string value with proper Unicode handling + * (key is always UTF-8) + * detect absence by return value == dflt + */ + static string_type getenv(const std::string& key, const string_type& dflt=""); + /** + * get optional environment string value with proper Unicode handling + * (key is always UTF-8) + * detect absence by (! return value) + */ + static boost::optional getoptenv(const std::string& key); + static void addCRLF(string_type& string); static void removeCRLF(string_type& string); + static void removeWindowsCR(string_type& string); static void replaceTabsWithSpaces( string_type& string, size_type spaces_per_tab ); static void replaceNonstandardASCII( string_type& string, T replacement ); @@ -443,7 +481,7 @@ class LLStringExplicit : public std::string struct LLDictionaryLess { public: - bool operator()(const std::string& a, const std::string& b) + bool operator()(const std::string& a, const std::string& b) const { return (LLStringUtil::precedesDict(a, b) ? true : false); } @@ -473,6 +511,7 @@ inline std::string chop_tail_copy( * @brief This translates a nybble stored as a hex value from 0-f back * to a nybble in the low order bits of the return byte. */ +LL_COMMON_API bool is_char_hex(char hex); LL_COMMON_API U8 hex_as_nybble(char hex); /** @@ -491,6 +530,37 @@ LL_COMMON_API bool iswindividual(llwchar elem); * Unicode support */ +/// generic conversion aliases +template +struct ll_convert_impl +{ + // Don't even provide a generic implementation. We specialize for every + // combination we do support. + TO operator()(const FROM& in) const; +}; + +// Use a function template to get the nice ll_convert(from_value) API. +template +TO ll_convert(const FROM& in) +{ + return ll_convert_impl()(in); +} + +// degenerate case +template +struct ll_convert_impl +{ + T operator()(const T& in) const { return in; } +}; + +// specialize ll_convert_impl to return EXPR +#define ll_convert_alias(TO, FROM, EXPR) \ +template<> \ +struct ll_convert_impl \ +{ \ + TO operator()(const FROM& in) const { return EXPR; } \ +} + // Make the incoming string a utf8 string. Replaces any unknown glyph // with the UNKNOWN_CHARACTER. Once any unknown glyph is found, the rest // of the data may not be recovered. @@ -498,31 +568,95 @@ LL_COMMON_API std::string rawstr_to_utf8(const std::string& raw); // // We should never use UTF16 except when communicating with Win32! +// https://docs.microsoft.com/en-us/cpp/cpp/char-wchar-t-char16-t-char32-t +// nat 2018-12-14: I consider the whole llutf16string thing a mistake, because +// the Windows APIs we want to call are all defined in terms of wchar_t* +// (or worse, LPCTSTR). +// https://docs.microsoft.com/en-us/windows/desktop/winprog/windows-data-types + +// While there is no point coding for an ASCII-only world (! defined(UNICODE)), +// use of U16 and llutf16string for Windows APIs locks in /Zc:wchar_t-. Going +// forward, we should code in terms of wchar_t and std::wstring so as to +// support either setting of /Zc:wchar_t. + +// The first link above states that char can be used to hold ASCII or any +// multi-byte character set, and distinguishes wchar_t (UTF-16LE), char16_t +// (UTF-16) and char32_t (UTF-32). Nonetheless, within this code base: +// * char and std::string always hold UTF-8 (of which ASCII is a subset). It +// is a BUG if they are used to pass strings in any other multi-byte +// encoding. +// * wchar_t and std::wstring should be our interface to Windows wide-string +// APIs, and therefore hold UTF-16LE. +// * U16 and llutf16string are the previous but DEPRECATED UTF-16LE type. Do +// not introduce new uses of U16 or llutf16string for string data. +// * llwchar and LLWString hold UTF-32 strings. +// * Do not introduce char16_t or std::u16string. +// * Do not introduce char32_t or std::u32string. // -typedef std::basic_string llutf16string; +#if _WIN32 && _NATIVE_WCHAR_T_DEFINED +typedef wchar_t utf16strtype; +#else +typedef U16 utf16strtype; +#endif +typedef std::basic_string llutf16string; + +#if ! defined(LL_WCHAR_T_NATIVE) +// wchar_t is identical to U16, and std::wstring is identical to llutf16string. +// Defining an ll_convert alias involving llutf16string would collide with the +// comparable preferred alias involving std::wstring. (In this scenario, if +// you pass llutf16string, it will engage the std::wstring specialization.) +#define ll_convert_u16_alias(TO, FROM, EXPR) // nothing +#else // defined(LL_WCHAR_T_NATIVE) +// wchar_t is a distinct native type, so llutf16string is also a distinct +// type, and there IS a point to converting separately to/from llutf16string. +// (But why? Windows APIs are still defined in terms of wchar_t, and +// in this scenario llutf16string won't work for them!) +#define ll_convert_u16_alias(TO, FROM, EXPR) ll_convert_alias(TO, FROM, EXPR) + +#if LL_WINDOWS +// LL_WCHAR_T_NATIVE is defined on non-Windows systems because, in fact, +// wchar_t is native. Everywhere but Windows, we use it for llwchar (see +// stdtypes.h). That makes LLWString identical to std::wstring, so these +// aliases for std::wstring would collide with those for LLWString. Only +// define on Windows, where converting between std::wstring and llutf16string +// means copying chars. +ll_convert_alias(llutf16string, std::wstring, llutf16string(in.begin(), in.end())); +ll_convert_alias(std::wstring, llutf16string, std::wstring(in.begin(), in.end())); +#endif // LL_WINDOWS +#endif // defined(LL_WCHAR_T_NATIVE) LL_COMMON_API LLWString utf16str_to_wstring(const llutf16string &utf16str, S32 len); LL_COMMON_API LLWString utf16str_to_wstring(const llutf16string &utf16str); +ll_convert_u16_alias(LLWString, llutf16string, utf16str_to_wstring(in)); LL_COMMON_API llutf16string wstring_to_utf16str(const LLWString &utf32str, S32 len); LL_COMMON_API llutf16string wstring_to_utf16str(const LLWString &utf32str); +ll_convert_u16_alias(llutf16string, LLWString, wstring_to_utf16str(in)); LL_COMMON_API llutf16string utf8str_to_utf16str ( const std::string& utf8str, S32 len); LL_COMMON_API llutf16string utf8str_to_utf16str ( const std::string& utf8str ); +ll_convert_u16_alias(llutf16string, std::string, utf8str_to_utf16str(in)); LL_COMMON_API LLWString utf8str_to_wstring(const std::string &utf8str, S32 len); LL_COMMON_API LLWString utf8str_to_wstring(const std::string &utf8str); // Same function, better name. JC inline LLWString utf8string_to_wstring(const std::string& utf8_string) { return utf8str_to_wstring(utf8_string); } +// best name of all +ll_convert_alias(LLWString, std::string, utf8string_to_wstring(in)); // LL_COMMON_API S32 wchar_to_utf8chars(llwchar inchar, char* outchars); LL_COMMON_API std::string wstring_to_utf8str(const LLWString &utf32str, S32 len); LL_COMMON_API std::string wstring_to_utf8str(const LLWString &utf32str); - +ll_convert_alias(std::string, LLWString, wstring_to_utf8str(in)); LL_COMMON_API std::string utf16str_to_utf8str(const llutf16string &utf16str, S32 len); LL_COMMON_API std::string utf16str_to_utf8str(const llutf16string &utf16str); +ll_convert_u16_alias(std::string, llutf16string, utf16str_to_utf8str(in)); + +#if LL_WINDOWS +inline std::string wstring_to_utf8str(const llutf16string &utf16str) { return utf16str_to_utf8str(utf16str);} +#endif // Length of this UTF32 string in bytes when transformed to UTF8 LL_COMMON_API S32 wstring_utf8_length(const LLWString& wstr); @@ -539,7 +673,7 @@ LL_COMMON_API S32 utf16str_wstring_length(const llutf16string &utf16str, S32 len LL_COMMON_API S32 wstring_utf16_length(const LLWString & wstr, S32 woffset, S32 wlen); // Length in wstring (i.e., llwchar count) of a part of a wstring specified by utf16 length (i.e., utf16 units.) -LL_COMMON_API S32 wstring_wstring_length_from_utf16_length(const LLWString & wstr, S32 woffset, S32 utf16_length, BOOL *unaligned = NULL); +LL_COMMON_API S32 wstring_wstring_length_from_utf16_length(const LLWString & wstr, S32 woffset, S32 utf16_length, BOOL *unaligned = nullptr); /** * @brief Properly truncate a utf8 string to a maximum byte count. @@ -553,12 +687,28 @@ LL_COMMON_API S32 wstring_wstring_length_from_utf16_length(const LLWString & wst */ LL_COMMON_API std::string utf8str_truncate(const std::string& utf8str, const S32 max_len); +// [RLVa:KB] - Checked: RLVa-2.1.0 +LL_COMMON_API std::string utf8str_substr(const std::string& utf8str, const S32 index, const S32 max_len); +LL_COMMON_API void utf8str_split(std::list& split_list, const std::string& utf8str, size_t maxlen, char split_token); +// [/RLVa:KB] + LL_COMMON_API std::string utf8str_trim(const std::string& utf8str); LL_COMMON_API S32 utf8str_compare_insensitive( const std::string& lhs, const std::string& rhs); +/** +* @brief Properly truncate a utf8 string to a maximum character count. +* +* If symbol_len is longer than the string passed in, the return +* value == utf8str. +* @param utf8str A valid utf8 string to truncate. +* @param symbol_len The maximum number of symbols in the return value. +* @return Returns a valid utf8 string with symbol count <= max_len. +*/ +LL_COMMON_API std::string utf8str_symbol_truncate(const std::string& utf8str, const S32 symbol_len); + /** * @brief Replace all occurences of target_char with replace_char * @@ -585,53 +735,82 @@ LL_COMMON_API std::string utf8str_removeCRLF(const std::string& utf8str); //@{ /** - * @brief Implementation the expected snprintf interface. - * - * If the size of the passed in buffer is not large enough to hold the string, - * two bad things happen: - * 1. resulting formatted string is NOT null terminated - * 2. Depending on the platform, the return value could be a) the required - * size of the buffer to copy the entire formatted string or b) -1. - * On Windows with VS.Net 2003, it returns -1 e.g. - * - * safe_snprintf always adds a NULL terminator so that the caller does not - * need to check for return value or need to add the NULL terminator. - * It does not, however change the return value - to let the caller know - * that the passed in buffer size was not large enough to hold the - * formatted string. + * @brief Convert a wide string to std::string * + * This replaces the unsafe W2A macro from ATL. */ - -// Deal with the differeneces on Windows -namespace snprintf_hack +LL_COMMON_API std::string ll_convert_wide_to_string(const wchar_t* in, unsigned int code_page); +LL_COMMON_API std::string ll_convert_wide_to_string(const wchar_t* in); // default CP_UTF8 +inline std::string ll_convert_wide_to_string(const std::wstring& in, unsigned int code_page) +{ + return ll_convert_wide_to_string(in.c_str(), code_page); +} +inline std::string ll_convert_wide_to_string(const std::wstring& in) { - LL_COMMON_API int snprintf(char *str, size_t size, const char *format, ...); + return ll_convert_wide_to_string(in.c_str()); } +ll_convert_alias(std::string, std::wstring, ll_convert_wide_to_string(in)); -using snprintf_hack::snprintf; +/** + * Converts a string to wide string. + */ +LL_COMMON_API wchar_t* ll_convert_string_to_wide(const std::string& in, + unsigned int code_page); +LL_COMMON_API wchar_t* ll_convert_string_to_wide(const std::string& in); + // default CP_UTF8 +ll_convert_alias(wchar_t*, std::string, ll_convert_string_to_wide(in)); /** - * @brief Convert a wide string to std::string - * - * This replaces the unsafe W2A macro from ATL. + * Convert a Windows wide string to our LLWString */ -LL_COMMON_API std::string ll_convert_wide_to_string(const wchar_t* in, unsigned int code_page); +LL_COMMON_API LLWString ll_convert_wide_to_wstring(const std::wstring& in); +ll_convert_alias(LLWString, std::wstring, ll_convert_wide_to_wstring(in)); /** - * Converts a string to wide string. - * - * It will allocate memory for result string with "new []". Don't forget to release it with "delete []". + * Convert LLWString to Windows wide string */ -LL_COMMON_API wchar_t* ll_convert_string_to_wide(const std::string& in, unsigned int code_page); +LL_COMMON_API std::wstring ll_convert_wstring_to_wide(const LLWString& in); +ll_convert_alias(std::wstring, LLWString, ll_convert_wstring_to_wide(in)); /** - * Converts incoming string into urf8 string + * Converts incoming string into utf8 string * */ LL_COMMON_API std::string ll_convert_string_to_utf8_string(const std::string& in); +/// Get Windows message string for passed GetLastError() code +// VS 2013 doesn't let us forward-declare this template, which is what we +// started with, so the implementation could reference the specialization we +// haven't yet declared. Somewhat weirdly, just stating the generic +// implementation in terms of the specialization works, even in this order... + +// the general case is just a conversion from the sole implementation +// Microsoft says DWORD is a typedef for unsigned long +// https://docs.microsoft.com/en-us/windows/desktop/winprog/windows-data-types +// so rather than drag windows.h into everybody's include space... +template +STRING windows_message(unsigned long error) +{ + return ll_convert(windows_message(error)); +} + +/// There's only one real implementation +template<> +LL_COMMON_API std::wstring windows_message(unsigned long error); + +/// Get Windows message string, implicitly calling GetLastError() +template +STRING windows_message() { return windows_message(GetLastError()); } + //@} -#endif // LL_WINDOWS + +LL_COMMON_API boost::optional llstring_getoptenv(const std::string& key); + +#else // ! LL_WINDOWS + +LL_COMMON_API boost::optional llstring_getoptenv(const std::string& key); + +#endif // ! LL_WINDOWS /** * Many of the 'strip' and 'replace' methods of LLStringUtilBase need @@ -827,8 +1006,9 @@ class InEscString: public InString } /// This implementation uses the answer cached by setiter(). - virtual bool escaped() const { return mIsEsc; } - virtual T next() + bool escaped() const override { return mIsEsc; } + + T next() override { // If we're looking at the escape character of an escape sequence, // skip that character. This is the one time we can modify 'mIter' @@ -844,21 +1024,21 @@ class InEscString: public InString return result; } - virtual bool is(T ch) const + bool is(T ch) const override { // Like base-class is(), except that an escaped character matches // nothing. return (! done()) && (! mIsEsc) && *mIter == ch; } - virtual bool oneof(const string_type& delims) const + bool oneof(const string_type& delims) const override { // Like base-class oneof(), except that an escaped character matches // nothing. return (! done()) && (! mIsEsc) && LLStringUtilBase::contains(delims, *mIter); } - virtual bool collect_until(string_type& into, const_iterator from, T delim) + bool collect_until(string_type& into, const_iterator from, T delim) override { // Deal with escapes in the characters we collect; that is, an escaped // character must become just that character without the preceding @@ -1172,7 +1352,7 @@ BOOL LLStringUtilBase::precedesDict( const string_type& a, const string_type& { if( a.size() && b.size() ) { - return (LLStringUtilBase::compareDict(a.c_str(), b.c_str()) < 0); + return (LLStringUtilBase::compareDict(a, b) < 0); } else { @@ -1227,7 +1407,7 @@ void LLStringUtilBase::trimHead(string_type& string) template void LLStringUtilBase::trimTail(string_type& string) { - if( string.size() ) + if(!string.empty()) { size_type len = string.length(); size_type i = len; @@ -1240,12 +1420,31 @@ void LLStringUtilBase::trimTail(string_type& string) } } +template +void LLStringUtilBase::trimTail(string_type& string, const string_type& tokens) +{ + if(!string.empty()) + { + size_type len = string.length(); + size_type i = len; + while( i > 0 && (tokens.find_first_of(string[i-1]) != string_type::npos) ) + { + i--; + } + + string.erase( i, len - i ); + } +} + // Replace line feeds with carriage return-line feed pairs. //static template void LLStringUtilBase::addCRLF(string_type& string) { + if (string.empty()) + return; + const T LF = 10; const T CR = 13; @@ -1288,6 +1487,9 @@ void LLStringUtilBase::addCRLF(string_type& string) template void LLStringUtilBase::removeCRLF(string_type& string) { + if (string.empty()) + return; + const T CR = 13; size_type cr_count = 0; @@ -1307,6 +1509,32 @@ void LLStringUtilBase::removeCRLF(string_type& string) //static template +void LLStringUtilBase::removeWindowsCR(string_type& string) +{ + if (string.empty()) + { + return; + } + const T LF = 10; + const T CR = 13; + + size_type cr_count = 0; + size_type len = string.size(); + size_type i; + for( i = 0; i < len - cr_count - 1; i++ ) + { + if( string[i+cr_count] == CR && string[i+cr_count+1] == LF) + { + cr_count++; + } + + string[i] = string[i+cr_count]; + } + string.erase(i, cr_count); +} + +//static +template void LLStringUtilBase::replaceChar( string_type& string, T target, T replacement ) { size_type found_pos = 0; @@ -1390,6 +1618,7 @@ BOOL LLStringUtilBase::containsNonprintable(const string_type& string) return rv; } +// *TODO: reimplement in terms of algorithm //static template void LLStringUtilBase::stripNonprintable(string_type& string) @@ -1400,29 +1629,23 @@ void LLStringUtilBase::stripNonprintable(string_type& string) { return; } - size_t src_size = string.size(); - char* c_string = new char[src_size + 1]; - if(c_string == NULL) - { - return; - } - copy(c_string, string.c_str(), src_size+1); - char* write_head = &c_string[0]; + const size_t src_size = string.size(); + auto c_string = std::make_unique(src_size + 1); + + copy(c_string.get(), string.c_str(), src_size+1); for (size_type i = 0; i < src_size; i++) { - char* read_head = &string[i]; - write_head = &c_string[j]; - if(!(*read_head < MIN)) + if(string[i] >= MIN) { - *write_head = *read_head; + c_string[j] = string[i]; ++j; } } c_string[j]= '\0'; - string = c_string; - delete []c_string; + string.assign(c_string.get()); } +// *TODO: reimplement in terms of algorithm template std::basic_string LLStringUtilBase::quote(const string_type& str, const string_type& triggers, @@ -1444,7 +1667,9 @@ std::basic_string LLStringUtilBase::quote(const string_type& str, } // For whatever reason, we must quote this string. + auto needed_escapes = std::count(str.begin(), str.end(), '"'); string_type result; + result.reserve(len + (needed_escapes * escape.length())); result.push_back('"'); for (typename string_type::const_iterator ci(str.begin()), cend(str.end()); ci != cend; ++ci) { @@ -1559,6 +1784,37 @@ bool LLStringUtilBase::endsWith( return (idx == (string.size() - substr.size())); } +// static +template +auto LLStringUtilBase::getoptenv(const std::string& key) -> boost::optional +{ + auto found(llstring_getoptenv(key)); + if (found) + { + // return populated boost::optional + return { ll_convert(*found) }; + } + else + { + // empty boost::optional + return {}; + } +} + +// static +template +auto LLStringUtilBase::getenv(const std::string& key, const string_type& dflt) -> string_type +{ + auto found(getoptenv(key)); + if (found) + { + return *found; + } + else + { + return dflt; + } +} template BOOL LLStringUtilBase::convertToBOOL(const string_type& string, BOOL& value) diff --git a/indra/llcommon/llstringtable.cpp b/indra/llcommon/llstringtable.cpp index 2f3a994d8f..1844e7e803 100644 --- a/indra/llcommon/llstringtable.cpp +++ b/indra/llcommon/llstringtable.cpp @@ -264,7 +264,7 @@ LLStringTableEntry* LLStringTable::addStringEntry(const char *str) if (strlist) { string_list_t::iterator iter; - for (iter = strlist->begin(); iter != strlist->end(); iter++) + for (iter = strlist->begin(); iter != strlist->end(); ++iter) { entry = *iter; ret_val = entry->mString; @@ -323,7 +323,7 @@ void LLStringTable::removeString(const char *str) mUniqueEntries--; if (mUniqueEntries < 0) { - llerror("LLStringTable:removeString trying to remove too many strings!", 0); + LL_ERRS() << "LLStringTable:removeString trying to remove too many strings!" << LL_ENDL; } delete iter->second; mStringHash.erase(iter); @@ -338,7 +338,7 @@ void LLStringTable::removeString(const char *str) if (strlist) { string_list_t::iterator iter; - for (iter = strlist->begin(); iter != strlist->end(); iter++) + for (iter = strlist->begin(); iter != strlist->end(); ++iter) { entry = *iter; ret_val = entry->mString; @@ -349,7 +349,7 @@ void LLStringTable::removeString(const char *str) mUniqueEntries--; if (mUniqueEntries < 0) { - llerror("LLStringTable:removeString trying to remove too many strings!", 0); + LL_ERRS() << "LLStringTable:removeString trying to remove too many strings!" << LL_ENDL; } strlist->remove(entry); delete entry; diff --git a/indra/llcommon/llstringtable.h b/indra/llcommon/llstringtable.h index d40c9d8dfd..55bed71f21 100644 --- a/indra/llcommon/llstringtable.h +++ b/indra/llcommon/llstringtable.h @@ -150,7 +150,7 @@ class LL_COMMON_API LLStdStringTable for (S32 i = 0; i #include #include -#include #include -#include -#include -#include -#include using namespace llsd; #if LL_WINDOWS -# define WIN32_LEAN_AND_MEAN -# include -# include +# include "llwin32headerslean.h" # include // GetPerformanceInfo() et al. +# include #elif LL_DARWIN # include # include @@ -80,6 +74,7 @@ using namespace llsd; # include # include const char MEMINFO_FILE[] = "/proc/meminfo"; +# include #elif LL_SOLARIS # include # include @@ -93,8 +88,6 @@ const char MEMINFO_FILE[] = "/proc/meminfo"; extern int errno; #endif - -static const S32 CPUINFO_BUFFER_SIZE = 16383; LLCPUInfo gSysCPU; // Don't log memory info any more often than this. It also serves as our @@ -106,261 +99,173 @@ static const F32 MEM_INFO_THROTTLE = 20; // dropped below the login framerate, we'd have very little additional data. static const F32 MEM_INFO_WINDOW = 10*60; -#if LL_WINDOWS -#ifndef DLLVERSIONINFO -typedef struct _DllVersionInfo +// Wrap boost::regex_match() with a function that doesn't throw. +template +static bool regex_match_no_exc(const S& string, M& match, const R& regex) { - DWORD cbSize; - DWORD dwMajorVersion; - DWORD dwMinorVersion; - DWORD dwBuildNumber; - DWORD dwPlatformID; -}DLLVERSIONINFO; -#endif - -#ifndef DLLGETVERSIONPROC -typedef int (FAR WINAPI *DLLGETVERSIONPROC) (DLLVERSIONINFO *); -#endif + try + { + return boost::regex_match(string, match, regex); + } + catch (const std::runtime_error& e) + { + LL_WARNS("LLMemoryInfo") << "error matching with '" << regex.str() << "': " + << e.what() << ":\n'" << string << "'" << LL_ENDL; + return false; + } +} -bool get_shell32_dll_version(DWORD& major, DWORD& minor, DWORD& build_number) +// Wrap boost::regex_search() with a function that doesn't throw. +template +static bool regex_search_no_exc(const S& string, M& match, const R& regex) { - bool result = false; - const U32 BUFF_SIZE = 32767; - WCHAR tempBuf[BUFF_SIZE]; - if(GetSystemDirectory((LPWSTR)&tempBuf, BUFF_SIZE)) - { - - std::basic_string shell32_path(tempBuf); - - // Shell32.dll contains the DLLGetVersion function. - // according to msdn its not part of the API - // so you have to go in and get it. - // http://msdn.microsoft.com/en-us/library/bb776404(VS.85).aspx - shell32_path += TEXT("\\shell32.dll"); - - HMODULE hDllInst = LoadLibrary(shell32_path.c_str()); //load the DLL - if(hDllInst) - { // Could successfully load the DLL - DLLGETVERSIONPROC pDllGetVersion; - /* - You must get this function explicitly because earlier versions of the DLL - don't implement this function. That makes the lack of implementation of the - function a version marker in itself. - */ - pDllGetVersion = (DLLGETVERSIONPROC) GetProcAddress(hDllInst, - "DllGetVersion"); - - if(pDllGetVersion) - { - // DLL supports version retrieval function - DLLVERSIONINFO dvi; - - ZeroMemory(&dvi, sizeof(dvi)); - dvi.cbSize = sizeof(dvi); - HRESULT hr = (*pDllGetVersion)(&dvi); - - if(SUCCEEDED(hr)) - { // Finally, the version is at our hands - major = dvi.dwMajorVersion; - minor = dvi.dwMinorVersion; - build_number = dvi.dwBuildNumber; - result = true; - } - } - - FreeLibrary(hDllInst); // Release DLL - } - } - return result; + try + { + return boost::regex_search(string, match, regex); + } + catch (const std::runtime_error& e) + { + LL_WARNS("LLMemoryInfo") << "error searching with '" << regex.str() << "': " + << e.what() << ":\n'" << string << "'" << LL_ENDL; + return false; + } } -#endif // LL_WINDOWS LLOSInfo::LLOSInfo() : - mMajorVer(0), mMinorVer(0), mBuild(0) + mMajorVer(0), mMinorVer(0), mBuild(0), mOSVersionString("") { #if LL_WINDOWS - OSVERSIONINFOEX osvi; - BOOL bOsVersionInfoEx; - - // Try calling GetVersionEx using the OSVERSIONINFOEX structure. - ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); - osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); - if(!(bOsVersionInfoEx = GetVersionEx((OSVERSIONINFO *) &osvi))) + bool is_server = IsWindowsServer(); + std::string service_pack; + if (IsWindows10OrGreater()) { - // If OSVERSIONINFOEX doesn't work, try OSVERSIONINFO. - osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO); - if(!GetVersionEx( (OSVERSIONINFO *) &osvi)) - return; + if (is_server) + { + mOSStringSimple = "Microsoft Windows Server 2016 "; + } + else + { + mOSStringSimple = "Microsoft Windows 10 "; + } } - mMajorVer = osvi.dwMajorVersion; - mMinorVer = osvi.dwMinorVersion; - mBuild = osvi.dwBuildNumber; - - DWORD shell32_major, shell32_minor, shell32_build; - bool got_shell32_version = get_shell32_dll_version(shell32_major, - shell32_minor, - shell32_build); - - switch(osvi.dwPlatformId) + else if (IsWindows8Point1OrGreater()) { - case VER_PLATFORM_WIN32_NT: + if (is_server) { - // Test for the product. - if(osvi.dwMajorVersion <= 4) - { - mOSStringSimple = "Microsoft Windows NT "; - } - else if(osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) - { - mOSStringSimple = "Microsoft Windows 2000 "; - } - else if(osvi.dwMajorVersion ==5 && osvi.dwMinorVersion == 1) - { - mOSStringSimple = "Microsoft Windows XP "; - } - else if(osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2) - { - if(osvi.wProductType == VER_NT_WORKSTATION) - mOSStringSimple = "Microsoft Windows XP x64 Edition "; - else - mOSStringSimple = "Microsoft Windows Server 2003 "; - } - else if(osvi.dwMajorVersion == 6 && osvi.dwMinorVersion <= 2) - { - if(osvi.dwMinorVersion == 0) - { - if(osvi.wProductType == VER_NT_WORKSTATION) - mOSStringSimple = "Microsoft Windows Vista "; - else - mOSStringSimple = "Windows Server 2008 "; - } - else if(osvi.dwMinorVersion == 1) - { - if(osvi.wProductType == VER_NT_WORKSTATION) - mOSStringSimple = "Microsoft Windows 7 "; - else - mOSStringSimple = "Windows Server 2008 R2 "; - } - else if(osvi.dwMinorVersion == 2) - { - if(osvi.wProductType == VER_NT_WORKSTATION) - mOSStringSimple = "Microsoft Windows 8 "; - else - mOSStringSimple = "Windows Server 2012 "; - } - - ///get native system info if available.. - typedef void (WINAPI *PGNSI)(LPSYSTEM_INFO); ///function pointer for loading GetNativeSystemInfo - SYSTEM_INFO si; //System Info object file contains architecture info - PGNSI pGNSI; //pointer object - ZeroMemory(&si, sizeof(SYSTEM_INFO)); //zero out the memory in information - pGNSI = (PGNSI) GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "GetNativeSystemInfo"); //load kernel32 get function - if(NULL != pGNSI) //check if it has failed - pGNSI(&si); //success - else - GetSystemInfo(&si); //if it fails get regular system info - //(Warning: If GetSystemInfo it may result in incorrect information in a WOW64 machine, if the kernel fails to load) - - //msdn microsoft finds 32 bit and 64 bit flavors this way.. - //http://msdn.microsoft.com/en-us/library/ms724429(VS.85).aspx (example code that contains quite a few more flavors - //of windows than this code does (in case it is needed for the future) - if ( si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64 ) //check for 64 bit - { - mOSStringSimple += "64-bit "; - } - else if (si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_INTEL ) - { - mOSStringSimple += "32-bit "; - } - } - else // Use the registry on early versions of Windows NT. - { - mOSStringSimple = "Microsoft Windows (unrecognized) "; - - HKEY hKey; - WCHAR szProductType[80]; - DWORD dwBufLen; - RegOpenKeyEx( HKEY_LOCAL_MACHINE, - L"SYSTEM\\CurrentControlSet\\Control\\ProductOptions", - 0, KEY_QUERY_VALUE, &hKey ); - RegQueryValueEx( hKey, L"ProductType", NULL, NULL, - (LPBYTE) szProductType, &dwBufLen); - RegCloseKey( hKey ); - if ( lstrcmpi( L"WINNT", szProductType) == 0 ) - { - mOSStringSimple += "Professional "; - } - else if ( lstrcmpi( L"LANMANNT", szProductType) == 0 ) - { - mOSStringSimple += "Server "; - } - else if ( lstrcmpi( L"SERVERNT", szProductType) == 0 ) - { - mOSStringSimple += "Advanced Server "; - } - } - - std::string csdversion = utf16str_to_utf8str(osvi.szCSDVersion); - // Display version, service pack (if any), and build number. - std::string tmpstr; - if(osvi.dwMajorVersion <= 4) - { - tmpstr = llformat("version %d.%d %s (Build %d)", - osvi.dwMajorVersion, - osvi.dwMinorVersion, - csdversion.c_str(), - (osvi.dwBuildNumber & 0xffff)); - } - else - { - tmpstr = llformat("%s (Build %d)", - csdversion.c_str(), - (osvi.dwBuildNumber & 0xffff)); - } - - mOSString = mOSStringSimple + tmpstr; + mOSStringSimple = "Microsoft Windows Server 2012 R2 "; } - break; - - case VER_PLATFORM_WIN32_WINDOWS: - // Test for the Windows 95 product family. - if(osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0) + else { - mOSStringSimple = "Microsoft Windows 95 "; - if ( osvi.szCSDVersion[1] == 'C' || osvi.szCSDVersion[1] == 'B' ) - { - mOSStringSimple += "OSR2 "; - } - } - if(osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10) + mOSStringSimple = "Microsoft Windows 8.1 "; + } + } + else if (IsWindows8OrGreater()) + { + if (is_server) { - mOSStringSimple = "Microsoft Windows 98 "; - if ( osvi.szCSDVersion[1] == 'A' ) - { - mOSStringSimple += "SE "; - } - } - if(osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90) + mOSStringSimple = "Microsoft Windows Server 2012 "; + } + else { - mOSStringSimple = "Microsoft Windows Millennium Edition "; + mOSStringSimple = "Microsoft Windows 8 "; } - mOSString = mOSStringSimple; - break; } - - std::string compatibility_mode; - if(got_shell32_version) + else if (IsWindows7OrGreater()) { - if(osvi.dwMajorVersion != shell32_major || osvi.dwMinorVersion != shell32_minor) + if (is_server) + { + mOSStringSimple = "Microsoft Windows Server 2008 R2 "; + } + else { - compatibility_mode = llformat(" compatibility mode. real ver: %d.%d (Build %d)", - shell32_major, - shell32_minor, - shell32_build); + mOSStringSimple = "Microsoft Windows 7 "; + } + if (IsWindows7SP1OrGreater()) + { + service_pack = "Service Pack 1 "; } } - mOSString += compatibility_mode; + else if (IsWindowsVistaOrGreater()) + { + if (is_server) + { + mOSStringSimple = "Microsoft Windows Server 2008 "; + } + else + { + mOSStringSimple = "Microsoft Windows Vista "; + } + if (IsWindowsVistaSP2OrGreater()) + { + service_pack = "Service Pack 2 "; + } + else if (IsWindowsVistaSP1OrGreater()) + { + service_pack = "Service Pack 1 "; + } + } + else + { + mOSStringSimple = "Microsoft Windows (unrecognized) "; + } + + ///get native system info if available.. + typedef void (WINAPI *PGNSI)(LPSYSTEM_INFO); ///function pointer for loading GetNativeSystemInfo + SYSTEM_INFO si; //System Info object file contains architecture info + PGNSI pGNSI; //pointer object + ZeroMemory(&si, sizeof(SYSTEM_INFO)); //zero out the memory in information + pGNSI = (PGNSI)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "GetNativeSystemInfo"); //load kernel32 get function + if (NULL != pGNSI) //check if it has failed + pGNSI(&si); //success + else + GetSystemInfo(&si); //if it fails get regular system info + //(Warning: If GetSystemInfo it may result in incorrect information in a WOW64 machine, if the kernel fails to load) + + //msdn microsoft finds 32 bit and 64 bit flavors this way.. + //http://msdn.microsoft.com/en-us/library/ms724429(VS.85).aspx (example code that contains quite a few more flavors + //of windows than this code does (in case it is needed for the future) + if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) //check for 64 bit + { + mOSStringSimple += "64-bit "; + } + else if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL) + { + mOSStringSimple += "32-bit "; + } + + OSVERSIONINFOEX osvi; + BOOL bOsVersionInfoEx; + // Try calling GetVersionEx using the OSVERSIONINFOEX structure. + ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + if (!(bOsVersionInfoEx = GetVersionEx((OSVERSIONINFO *) &osvi))) + { + // If OSVERSIONINFOEX doesn't work, try OSVERSIONINFO. + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + bOsVersionInfoEx = GetVersionEx((OSVERSIONINFO *) &osvi); + } + + + std::string tmpstr; + if (bOsVersionInfoEx) + { + mMajorVer = osvi.dwMajorVersion; + mMinorVer = osvi.dwMinorVersion; + mBuild = osvi.dwBuildNumber; + tmpstr = llformat("%s(Build %d)", service_pack.c_str(), mBuild); + } + else + { + mMajorVer = 0; + mMinorVer = 0; + mBuild = 0; + tmpstr = llformat("%s(Build %d)", service_pack.c_str(), 0); + } + + // Display version, service pack (if any), and build number. + mOSString = mOSStringSimple + tmpstr; + LLStringUtil::trim(mOSStringSimple); #elif LL_DARWIN @@ -412,6 +317,102 @@ LLOSInfo::LLOSInfo() : mOSString = mOSStringSimple; } +#elif LL_LINUX + + struct utsname un; + if(uname(&un) != -1) + { + mOSStringSimple.append(un.sysname); + mOSStringSimple.append(" "); + mOSStringSimple.append(un.release); + + mOSString = mOSStringSimple; + mOSString.append(" "); + mOSString.append(un.version); + mOSString.append(" "); + mOSString.append(un.machine); + + // Simplify 'Simple' + std::string ostype = mOSStringSimple.substr(0, mOSStringSimple.find_first_of(" ", 0)); + if (ostype == "Linux") + { + // Only care about major and minor Linux versions, truncate at second '.' + std::string::size_type idx1 = mOSStringSimple.find_first_of(".", 0); + std::string::size_type idx2 = (idx1 != std::string::npos) ? mOSStringSimple.find_first_of(".", idx1+1) : std::string::npos; + std::string simple = mOSStringSimple.substr(0, idx2); + if (simple.length() > 0) + mOSStringSimple = simple; + } + } + else + { + mOSStringSimple.append("Unable to collect OS info"); + mOSString = mOSStringSimple; + } + + const char OS_VERSION_MATCH_EXPRESSION[] = "([0-9]+)\\.([0-9]+)(\\.([0-9]+))?"; + boost::regex os_version_parse(OS_VERSION_MATCH_EXPRESSION); + boost::smatch matched; + + std::string glibc_version(gnu_get_libc_version()); + if ( regex_match_no_exc(glibc_version, matched, os_version_parse) ) + { + LL_INFOS("AppInit") << "Using glibc version '" << glibc_version << "' as OS version" << LL_ENDL; + + std::string version_value; + + if ( matched[1].matched ) // Major version + { + version_value.assign(matched[1].first, matched[1].second); + if (sscanf(version_value.c_str(), "%d", &mMajorVer) != 1) + { + LL_WARNS("AppInit") << "failed to parse major version '" << version_value << "' as a number" << LL_ENDL; + } + } + else + { + LL_ERRS("AppInit") + << "OS version regex '" << OS_VERSION_MATCH_EXPRESSION + << "' returned true, but major version [1] did not match" + << LL_ENDL; + } + + if ( matched[2].matched ) // Minor version + { + version_value.assign(matched[2].first, matched[2].second); + if (sscanf(version_value.c_str(), "%d", &mMinorVer) != 1) + { + LL_ERRS("AppInit") << "failed to parse minor version '" << version_value << "' as a number" << LL_ENDL; + } + } + else + { + LL_ERRS("AppInit") + << "OS version regex '" << OS_VERSION_MATCH_EXPRESSION + << "' returned true, but minor version [1] did not match" + << LL_ENDL; + } + + if ( matched[4].matched ) // Build version (optional) - note that [3] includes the '.' + { + version_value.assign(matched[4].first, matched[4].second); + if (sscanf(version_value.c_str(), "%d", &mBuild) != 1) + { + LL_ERRS("AppInit") << "failed to parse build version '" << version_value << "' as a number" << LL_ENDL; + } + } + else + { + LL_INFOS("AppInit") + << "OS build version not provided; using zero" + << LL_ENDL; + } + } + else + { + LL_WARNS("AppInit") << "glibc version '" << glibc_version << "' cannot be parsed to three numbers; using all zeros" << LL_ENDL; + } + #else struct utsname un; @@ -444,8 +445,13 @@ LLOSInfo::LLOSInfo() : mOSStringSimple.append("Unable to collect OS info"); mOSString = mOSStringSimple; } + #endif + std::stringstream dotted_version_string; + dotted_version_string << mMajorVer << "." << mMinorVer << "." << mBuild; + mOSVersionString.append(dotted_version_string.str()); + } #ifndef LL_WINDOWS @@ -473,7 +479,7 @@ S32 LLOSInfo::getMaxOpenFiles() } else { - llerrs << "LLOSInfo::getMaxOpenFiles: sysconf error for _SC_OPEN_MAX" << llendl; + LL_ERRS() << "LLOSInfo::getMaxOpenFiles: sysconf error for _SC_OPEN_MAX" << LL_ENDL; } } } @@ -496,7 +502,10 @@ const std::string& LLOSInfo::getOSStringSimple() const return mOSStringSimple; } -const S32 STATUS_SIZE = 8192; +const std::string& LLOSInfo::getOSVersionString() const +{ + return mOSVersionString; +} //static U32 LLOSInfo::getProcessVirtualSizeKB() @@ -505,6 +514,7 @@ U32 LLOSInfo::getProcessVirtualSizeKB() #if LL_WINDOWS #endif #if LL_LINUX +# define STATUS_SIZE 2048 LLFILE* status_filep = LLFile::fopen("/proc/self/status", "rb"); if (status_filep) { @@ -527,12 +537,12 @@ U32 LLOSInfo::getProcessVirtualSizeKB() sprintf(proc_ps, "/proc/%d/psinfo", (int)getpid()); int proc_fd = -1; if((proc_fd = open(proc_ps, O_RDONLY)) == -1){ - llwarns << "unable to open " << proc_ps << llendl; + LL_WARNS() << "unable to open " << proc_ps << LL_ENDL; return 0; } psinfo_t proc_psinfo; if(read(proc_fd, &proc_psinfo, sizeof(psinfo_t)) != sizeof(psinfo_t)){ - llwarns << "Unable to read " << proc_ps << llendl; + LL_WARNS() << "Unable to read " << proc_ps << LL_ENDL; close(proc_fd); return 0; } @@ -573,12 +583,12 @@ U32 LLOSInfo::getProcessResidentSizeKB() sprintf(proc_ps, "/proc/%d/psinfo", (int)getpid()); int proc_fd = -1; if((proc_fd = open(proc_ps, O_RDONLY)) == -1){ - llwarns << "unable to open " << proc_ps << llendl; + LL_WARNS() << "unable to open " << proc_ps << LL_ENDL; return 0; } psinfo_t proc_psinfo; if(read(proc_fd, &proc_psinfo, sizeof(psinfo_t)) != sizeof(psinfo_t)){ - llwarns << "Unable to read " << proc_ps << llendl; + LL_WARNS() << "Unable to read " << proc_ps << LL_ENDL; close(proc_fd); return 0; } @@ -662,7 +672,7 @@ class Stats // Store every integer type as LLSD::Integer. template void add(const LLSD::String& name, const T& value, - typename boost::enable_if >::type* = 0) + typename std::enable_if::value>::type* = nullptr) { mStats[name] = LLSD::Integer(value); } @@ -670,7 +680,7 @@ class Stats // Store every floating-point type as LLSD::Real. template void add(const LLSD::String& name, const T& value, - typename boost::enable_if >::type* = 0) + typename std::enable_if::value>::type* = nullptr) { mStats[name] = LLSD::Real(value); } @@ -687,65 +697,15 @@ class Stats LLSD mStats; }; -// Wrap boost::regex_match() with a function that doesn't throw. -template -static bool regex_match_no_exc(const S& string, M& match, const R& regex) -{ - try - { - return boost::regex_match(string, match, regex); - } - catch (const std::runtime_error& e) - { - LL_WARNS("LLMemoryInfo") << "error matching with '" << regex.str() << "': " - << e.what() << ":\n'" << string << "'" << LL_ENDL; - return false; - } -} - -// Wrap boost::regex_search() with a function that doesn't throw. -template -static bool regex_search_no_exc(const S& string, M& match, const R& regex) -{ - try - { - return boost::regex_search(string, match, regex); - } - catch (const std::runtime_error& e) - { - LL_WARNS("LLMemoryInfo") << "error searching with '" << regex.str() << "': " - << e.what() << ":\n'" << string << "'" << LL_ENDL; - return false; - } -} - LLMemoryInfo::LLMemoryInfo() { refresh(); } -#if LL_WINDOWS -static U32 LLMemoryAdjustKBResult(U32 inKB) -{ - // Moved this here from llfloaterabout.cpp - - //! \bug - // For some reason, the reported amount of memory is always wrong. - // The original adjustment assumes it's always off by one meg, however - // errors of as much as 2520 KB have been observed in the value - // returned from the GetMemoryStatusEx function. Here we keep the - // original adjustment from llfoaterabout.cpp until this can be - // fixed somehow. - inKB += 1024; - - return inKB; -} -#endif - -U32 LLMemoryInfo::getPhysicalMemoryKB() const +U32Kilobytes LLMemoryInfo::getPhysicalMemoryKB() const { #if LL_WINDOWS - return LLMemoryAdjustKBResult(mStatsMap["Total Physical KB"].asInteger()); + return U32Kilobytes(mStatsMap["Total Physical KB"].asInteger()); #elif LL_DARWIN // This might work on Linux as well. Someone check... @@ -755,17 +715,12 @@ U32 LLMemoryInfo::getPhysicalMemoryKB() const size_t len = sizeof(phys); sysctl(mib, 2, &phys, &len, NULL, 0); - return (U32)(phys >> 10); + return U64Bytes(phys); #elif LL_LINUX U64 phys = 0; phys = (U64)(getpagesize()) * (U64)(get_phys_pages()); - return (U32)(phys >> 10); - -#elif LL_SOLARIS - U64 phys = 0; - phys = (U64)(getpagesize()) * (U64)(sysconf(_SC_PHYS_PAGES)); - return (U32)(phys >> 10); + return U64Bytes(phys); #else return 0; @@ -773,32 +728,16 @@ U32 LLMemoryInfo::getPhysicalMemoryKB() const #endif } -U32 LLMemoryInfo::getPhysicalMemoryClamped() const -{ - // Return the total physical memory in bytes, but clamp it - // to no more than U32_MAX - - U32 phys_kb = getPhysicalMemoryKB(); - if (phys_kb >= 4194304 /* 4GB in KB */) - { - return U32_MAX; - } - else - { - return phys_kb << 10; - } -} - //static -void LLMemoryInfo::getAvailableMemoryKB(U32& avail_physical_mem_kb, U32& avail_virtual_mem_kb) +void LLMemoryInfo::getAvailableMemoryKB(U32Kilobytes& avail_physical_mem_kb, U32Kilobytes& avail_virtual_mem_kb) { #if LL_WINDOWS - // Sigh, this shouldn't be a static method, then we wouldn't have to - // reload this data separately from refresh() - LLSD statsMap(loadStatsMap()); + MEMORYSTATUSEX state; + state.dwLength = sizeof(state); + GlobalMemoryStatusEx(&state); - avail_physical_mem_kb = statsMap["Avail Physical KB"].asInteger(); - avail_virtual_mem_kb = statsMap["Avail Virtual KB"].asInteger(); + avail_physical_mem_kb = U64Bytes(state.ullAvailPhys); + avail_virtual_mem_kb = U64Bytes(state.ullAvailVirtual); #elif LL_DARWIN // mStatsMap is derived from vm_stat, look for (e.g.) "kb free": @@ -815,8 +754,8 @@ void LLMemoryInfo::getAvailableMemoryKB(U32& avail_physical_mem_kb, U32& avail_v // Pageins: 2097212. // Pageouts: 41759. // Object cache: 841598 hits of 7629869 lookups (11% hit rate) - avail_physical_mem_kb = -1 ; - avail_virtual_mem_kb = -1 ; + avail_physical_mem_kb = (U32Kilobytes)-1 ; + avail_virtual_mem_kb = (U32Kilobytes)-1 ; #elif LL_LINUX // mStatsMap is derived from MEMINFO_FILE: @@ -867,15 +806,15 @@ void LLMemoryInfo::getAvailableMemoryKB(U32& avail_physical_mem_kb, U32& avail_v // DirectMap4k: 434168 kB // DirectMap2M: 477184 kB // (could also run 'free', but easier to read a file than run a program) - avail_physical_mem_kb = -1 ; - avail_virtual_mem_kb = -1 ; + avail_physical_mem_kb = (U32Kilobytes)-1 ; + avail_virtual_mem_kb = (U32Kilobytes)-1 ; #else //do not know how to collect available memory info for other systems. //leave it blank here for now. - avail_physical_mem_kb = -1 ; - avail_virtual_mem_kb = -1 ; + avail_physical_mem_kb = (U32Kilobytes)-1 ; + avail_virtual_mem_kb = (U32Kilobytes)-1 ; #endif } @@ -889,7 +828,7 @@ void LLMemoryInfo::stream(std::ostream& s) const // Max key length size_t key_width(0); - BOOST_FOREACH(const MapEntry& pair, inMap(mStatsMap)) + for (const MapEntry& pair : inMap(mStatsMap)) { size_t len(pair.first.length()); if (len > key_width) @@ -899,7 +838,7 @@ void LLMemoryInfo::stream(std::ostream& s) const } // Now stream stats - BOOST_FOREACH(const MapEntry& pair, inMap(mStatsMap)) + for (const MapEntry& pair : inMap(mStatsMap)) { s << pfx << std::setw(key_width+1) << (pair.first + ':') << ' '; LLSD value(pair.second); @@ -946,7 +885,7 @@ LLSD LLMemoryInfo::loadStatsMap() DWORDLONG div = 1024; - stats.add("Percent Memory use", state.dwMemoryLoad/div); + stats.add("Percent Memory use", state.dwMemoryLoad); stats.add("Total Physical KB", state.ullTotalPhys/div); stats.add("Avail Physical KB", state.ullAvailPhys/div); stats.add("Total page KB", state.ullTotalPageFile/div); @@ -995,27 +934,33 @@ LLSD LLMemoryInfo::loadStatsMap() stats.add("PrivateUsage KB", pmem.PrivateUsage/div); #elif LL_DARWIN - - const vm_size_t pagekb(vm_page_size / 1024); + vm_size_t page_size_kb; + if (host_page_size(mach_host_self(), &page_size_kb) != KERN_SUCCESS) + { + LL_WARNS() << "Unable to get host page size. Using default value." << LL_ENDL; + page_size_kb = 4096; + } + page_size_kb = page_size_kb / 1024; + // // Collect the vm_stat's // { - vm_statistics_data_t vmstat; - mach_msg_type_number_t vmstatCount = HOST_VM_INFO_COUNT; + vm_statistics64_data_t vmstat; + mach_msg_type_number_t vmstatCount = HOST_VM_INFO64_COUNT; - if (host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t) &vmstat, &vmstatCount) != KERN_SUCCESS) + if (host_statistics64(mach_host_self(), HOST_VM_INFO64, (host_info64_t) &vmstat, &vmstatCount) != KERN_SUCCESS) { LL_WARNS("LLMemoryInfo") << "Unable to collect memory information" << LL_ENDL; } else { - stats.add("Pages free KB", pagekb * vmstat.free_count); - stats.add("Pages active KB", pagekb * vmstat.active_count); - stats.add("Pages inactive KB", pagekb * vmstat.inactive_count); - stats.add("Pages wired KB", pagekb * vmstat.wire_count); + stats.add("Pages free KB", page_size_kb * vmstat.free_count); + stats.add("Pages active KB", page_size_kb * vmstat.active_count); + stats.add("Pages inactive KB", page_size_kb * vmstat.inactive_count); + stats.add("Pages wired KB", page_size_kb * vmstat.wire_count); stats.add("Pages zero fill", vmstat.zero_fill_count); stats.add("Page reactivations", vmstat.reactivations); @@ -1064,20 +1009,20 @@ LLSD LLMemoryInfo::loadStatsMap() // { - task_basic_info_64_data_t taskinfo; - unsigned taskinfoSize = sizeof(taskinfo); - - if (task_info(mach_task_self(), TASK_BASIC_INFO_64, (task_info_t) &taskinfo, &taskinfoSize) != KERN_SUCCESS) + mach_task_basic_info_data_t taskinfo; + mach_msg_type_number_t task_count = MACH_TASK_BASIC_INFO_COUNT; + if (task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t) &taskinfo, &task_count) != KERN_SUCCESS) { - LL_WARNS("LLMemoryInfo") << "Unable to collect task information" << LL_ENDL; - } - else - { - stats.add("Basic suspend count", taskinfo.suspend_count); - stats.add("Basic virtual memory KB", taskinfo.virtual_size / 1024); - stats.add("Basic resident memory KB", taskinfo.resident_size / 1024); - stats.add("Basic new thread policy", taskinfo.policy); - } + LL_WARNS("LLMemoryInfo") << "Unable to collect task information" << LL_ENDL; + } + else + { + stats.add("Basic virtual memory KB", taskinfo.virtual_size / 1024); + stats.add("Basic resident memory KB", taskinfo.resident_size / 1024); + stats.add("Basic max resident memory KB", taskinfo.resident_size_max / 1024); + stats.add("Basic new thread policy", taskinfo.policy); + stats.add("Basic suspend count", taskinfo.suspend_count); + } } #elif LL_SOLARIS @@ -1187,7 +1132,8 @@ class FrameWatcher // Hooking onto the "mainloop" event pump gets us one call per frame. mConnection(LLEventPumps::instance() .obtain("mainloop") - .listen("FrameWatcher", boost::bind(&FrameWatcher::tick, this, _1))), + .listen("FrameWatcher", std::bind(&FrameWatcher::tick, this, std::placeholders::_1))), + // Initializing mSampleStart to an invalid timestamp alerts us to skip // trying to compute framerate on the first call. mSampleStart(-1), @@ -1288,9 +1234,14 @@ class FrameWatcher LL_CONT << "slowest framerate for last " << int(prevSize * MEM_INFO_THROTTLE) << " seconds "; } + + std::streamsize precision = LL_CONT.precision(); // + LL_CONT << std::fixed << std::setprecision(1) << framerate << '\n' - << LLMemoryInfo() << LL_ENDL; + << LLMemoryInfo(); + LL_CONT.precision(precision); + LL_CONT << LL_ENDL; return false; } @@ -1323,21 +1274,25 @@ BOOL gunzip_file(const std::string& srcfile, const std::string& dstfile) const S32 UNCOMPRESS_BUFFER_SIZE = 32768; BOOL retval = FALSE; gzFile src = NULL; - U8 buffer[UNCOMPRESS_BUFFER_SIZE]; + std::array buffer; LLFILE *dst = NULL; S32 bytes = 0; tmpfile = dstfile + ".t"; +#if LL_WINDOWS + src = gzopen_w(utf8str_to_utf16str(srcfile).c_str(), "rb"); +#else src = gzopen(srcfile.c_str(), "rb"); +#endif if (! src) goto err; dst = LLFile::fopen(tmpfile, "wb"); /* Flawfinder: ignore */ if (! dst) goto err; do { - bytes = gzread(src, buffer, UNCOMPRESS_BUFFER_SIZE); - size_t nwrit = fwrite(buffer, sizeof(U8), bytes, dst); + bytes = gzread(src, buffer.data(), buffer.size()); + size_t nwrit = fwrite(buffer.data(), sizeof(U8), bytes, dst); if (nwrit < (size_t) bytes) { - llwarns << "Short write on " << tmpfile << ": Wrote " << nwrit << " of " << bytes << " bytes." << llendl; + LL_WARNS() << "Short write on " << tmpfile << ": Wrote " << nwrit << " of " << bytes << " bytes." << LL_ENDL; goto err; } } while(gzeof(src) == 0); @@ -1356,28 +1311,32 @@ BOOL gzip_file(const std::string& srcfile, const std::string& dstfile) const S32 COMPRESS_BUFFER_SIZE = 32768; std::string tmpfile; BOOL retval = FALSE; - U8 buffer[COMPRESS_BUFFER_SIZE]; + std::array buffer; gzFile dst = NULL; LLFILE *src = NULL; S32 bytes = 0; tmpfile = dstfile + ".t"; +#if LL_WINDOWS + dst = gzopen_w(utf8str_to_utf16str(tmpfile).c_str(), "wb"); +#else dst = gzopen(tmpfile.c_str(), "wb"); /* Flawfinder: ignore */ +#endif if (! dst) goto err; src = LLFile::fopen(srcfile, "rb"); /* Flawfinder: ignore */ if (! src) goto err; - while ((bytes = (S32)fread(buffer, sizeof(U8), COMPRESS_BUFFER_SIZE, src)) > 0) + while ((bytes = (S32)fread(buffer.data(), sizeof(U8), buffer.size(), src)) > 0) { - if (gzwrite(dst, buffer, bytes) <= 0) + if (gzwrite(dst, buffer.data(), bytes) <= 0) { - llwarns << "gzwrite failed: " << gzerror(dst, NULL) << llendl; + LL_WARNS() << "gzwrite failed: " << gzerror(dst, NULL) << LL_ENDL; goto err; } } if (ferror(src)) { - llwarns << "Error reading " << srcfile << llendl; + LL_WARNS() << "Error reading " << srcfile << LL_ENDL; goto err; } diff --git a/indra/llcommon/llsys.h b/indra/llcommon/llsys.h index fb39ef4da0..d963199419 100644 --- a/indra/llcommon/llsys.h +++ b/indra/llcommon/llsys.h @@ -33,9 +33,10 @@ // use an LLCPUInfo object: // // LLCPUInfo info; -// llinfos << info << llendl; +// LL_INFOS() << info << LL_ENDL; // +#include "llsd.h" #include #include @@ -48,6 +49,8 @@ class LL_COMMON_API LLOSInfo const std::string& getOSString() const; const std::string& getOSStringSimple() const; + const std::string& getOSVersionString() const; + S32 mMajorVer; S32 mMinorVer; S32 mBuild; @@ -61,6 +64,7 @@ class LL_COMMON_API LLOSInfo private: std::string mOSString; std::string mOSStringSimple; + std::string mOSVersionString; }; @@ -101,22 +105,17 @@ class LL_COMMON_API LLMemoryInfo Here's how you use an LLMemoryInfo: LLMemoryInfo info; -
    llinfos << info << llendl; +
    LL_INFOS() << info << LL_ENDL; */ { public: LLMemoryInfo(); ///< Default constructor void stream(std::ostream& s) const; ///< output text info to s - U32 getPhysicalMemoryKB() const; ///< Memory size in KiloBytes + U32Kilobytes getPhysicalMemoryKB() const; - /*! Memory size in bytes, if total memory is >= 4GB then U32_MAX will - ** be returned. - */ - U32 getPhysicalMemoryClamped() const; ///< Memory size in clamped bytes - //get the available memory infomation in KiloBytes. - static void getAvailableMemoryKB(U32& avail_physical_mem_kb, U32& avail_virtual_mem_kb); + static void getAvailableMemoryKB(U32Kilobytes& avail_physical_mem_kb, U32Kilobytes& avail_virtual_mem_kb); // Retrieve a map of memory statistics. The keys of the map are platform- // dependent. The values are in kilobytes to try to avoid integer overflow. diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp index 1c3fec608c..7b6fec9f27 100644 --- a/indra/llcommon/llthread.cpp +++ b/indra/llcommon/llthread.cpp @@ -68,7 +68,7 @@ LL_COMMON_API void assert_main_thread() { if (!AIThreadID::in_main_thread_inline()) { - llerrs << "Illegal execution outside main thread." << llendl; + LL_ERRS() << "Illegal execution outside main thread." << LL_ENDL; } } @@ -110,7 +110,7 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap // after the AICurlPrivate::curlthread::AICurlThread::run() function // exits and we actually change this variable (which really SHOULD // have been inside the critical area of the mSignal lock)]. - lldebugs << "LLThread::staticRun() Exiting: " << name << llendl; + LL_DEBUGS() << "LLThread::staticRun() Exiting: " << name << LL_ENDL; return NULL; } @@ -146,7 +146,7 @@ void LLThread::shutdown() // First, set the flag that indicates that we're ready to die setQuitting(); - llinfos << "LLThread::shutdown() Killing thread " << mName << " Status: " << mStatus << llendl; + LL_INFOS() << "LLThread::shutdown() Killing thread " << mName << " Status: " << mStatus << LL_ENDL; // Now wait a bit for the thread to exit // It's unclear whether I should even bother doing this - this destructor // should netver get called unless we're already stopped, really... @@ -168,7 +168,7 @@ void LLThread::shutdown() if (!isStopped()) { // This thread just wouldn't stop, even though we gave it time - llwarns << "LLThread::shutdown() exiting thread before clean exit!" << llendl; + LL_WARNS() << "LLThread::shutdown() exiting thread before clean exit!" << LL_ENDL; // Put a stake in its heart. apr_thread_exit(mAPRThreadp, -1); return; @@ -200,7 +200,7 @@ void LLThread::start() { --sRunning; mStatus = STOPPED; - llwarns << "failed to start thread " << mName << llendl; + LL_WARNS() << "failed to start thread " << mName << LL_ENDL; ll_apr_warn_status(status); } } @@ -364,138 +364,133 @@ LLThreadLocalData& LLThreadLocalData::tldata(void) //============================================================================ -LLCondition::LLCondition(LLAPRPool& parent) : LLMutex(parent) +#if defined(NEEDS_MUTEX_IMPL) +#if defined(USE_WIN32_THREAD) +LLMutexImpl::LLMutexImpl() { - apr_thread_cond_create(&mAPRCondp, mPool()); + InitializeCriticalSection(&mMutexImpl); //can throw STATUS_NO_MEMORY } - - -LLCondition::~LLCondition() +LLMutexImpl::~LLMutexImpl() { - apr_thread_cond_destroy(mAPRCondp); - mAPRCondp = NULL; + DeleteCriticalSection(&mMutexImpl); //nothrow } - -LLFastTimer::DeclareTimer FT_WAIT_FOR_CONDITION("LLCondition::wait()"); - -void LLCondition::wait() +void LLMutexImpl::lock() { - if (AIThreadID::in_main_thread_inline()) - { - LLFastTimer ft1(FT_WAIT_FOR_CONDITION); - apr_thread_cond_wait(mAPRCondp, mAPRMutexp); - } - else - { - apr_thread_cond_wait(mAPRCondp, mAPRMutexp); - } + EnterCriticalSection(&mMutexImpl); //can throw EXCEPTION_POSSIBLE_DEADLOCK } - -void LLCondition::signal() +void LLMutexImpl::unlock() { - apr_thread_cond_signal(mAPRCondp); + LeaveCriticalSection(&mMutexImpl); //nothrow } - -void LLCondition::broadcast() +bool LLMutexImpl::try_lock() { - apr_thread_cond_broadcast(mAPRCondp); + return !!TryEnterCriticalSection(&mMutexImpl); //nothrow } - -//============================================================================ -LLMutexBase::LLMutexBase() : - mCount(0), - mLockingThread(AIThreadID::sNone) +LLConditionVariableImpl::LLConditionVariableImpl() { + InitializeConditionVariable(&mConditionVariableImpl); } - -bool LLMutexBase::isSelfLocked() const +LLConditionVariableImpl::~LLConditionVariableImpl() { - return mLockingThread.equals_current_thread_inline(); + //There is no DeleteConditionVariable } - -LLFastTimer::DeclareTimer FT_WAIT_FOR_MUTEX("LLMutexBase::lock()"); - -void LLMutexBase::lock() -{ - if (mLockingThread.equals_current_thread_inline()) - { //redundant lock - mCount++; - return; - } - - if (APR_STATUS_IS_EBUSY(apr_thread_mutex_trylock(mAPRMutexp))) - { - if (AIThreadID::in_main_thread_inline()) - { - LLFastTimer ft1(FT_WAIT_FOR_MUTEX); - apr_thread_mutex_lock(mAPRMutexp); - } - else - { - apr_thread_mutex_lock(mAPRMutexp); - } - } - - mLockingThread.reset_inline(); +void LLConditionVariableImpl::notify_one() +{ + WakeConditionVariable(&mConditionVariableImpl); } +void LLConditionVariableImpl::notify_all() +{ + WakeAllConditionVariable(&mConditionVariableImpl); +} +void LLConditionVariableImpl::wait(LLMutex& lock) +{ + LLMutex::ImplAdoptMutex impl_adopted_mutex(lock); + SleepConditionVariableCS(&mConditionVariableImpl, &lock.native_handle(), INFINITE); +} +#else -bool LLMutexBase::tryLock() +void APRExceptionThrower(apr_status_t status) { - if (mLockingThread.equals_current_thread_inline()) - { //redundant lock - mCount++; - return true; - } - bool success = !APR_STATUS_IS_EBUSY(apr_thread_mutex_trylock(mAPRMutexp)); - if (success) + if(status != APR_SUCCESS) { - mLockingThread.reset_inline(); + static char buf[256]; + throw std::logic_error(apr_strerror(status,buf,sizeof(buf))); } - return success; } -// non-blocking, but does do a lock/unlock so not free -bool LLMutexBase::isLocked() const +LLMutexImpl::LLMutexImpl(native_pool_type& pool) : mPool(pool), mMutexImpl(NULL) { - if (mLockingThread.equals_current_thread_inline()) - return false; // A call to lock() won't block. - if (APR_STATUS_IS_EBUSY(apr_thread_mutex_trylock(mAPRMutexp))) - return true; - apr_thread_mutex_unlock(mAPRMutexp); - return false; + APRExceptionThrower(apr_thread_mutex_create(&mMutexImpl, APR_THREAD_MUTEX_UNNESTED, mPool())); } - -void LLMutexBase::unlock() +LLMutexImpl::~LLMutexImpl() { - if (mCount > 0) - { //not the root unlock - mCount--; - return; - } - mLockingThread = AIThreadID::sNone; - - apr_thread_mutex_unlock(mAPRMutexp); + APRExceptionThrower(apr_thread_mutex_destroy(mMutexImpl)); + mMutexImpl = NULL; } - -//---------------------------------------------------------------------------- - -LLThreadSafeRefCount::LLThreadSafeRefCount() : - mRef(0) +void LLMutexImpl::lock() +{ + APRExceptionThrower(apr_thread_mutex_lock(mMutexImpl)); +} +void LLMutexImpl::unlock() +{ + APRExceptionThrower(apr_thread_mutex_unlock(mMutexImpl)); +} +bool LLMutexImpl::try_lock() +{ + apr_status_t status = apr_thread_mutex_trylock(mMutexImpl); + if(APR_STATUS_IS_EBUSY(status)) + return false; + APRExceptionThrower(status); + return true; +} +LLConditionVariableImpl::LLConditionVariableImpl(native_pool_type& pool) : mPool(pool), mConditionVariableImpl(NULL) +{ + APRExceptionThrower(apr_thread_cond_create(&mConditionVariableImpl, mPool())); +} +LLConditionVariableImpl::~LLConditionVariableImpl() +{ + APRExceptionThrower(apr_thread_cond_destroy(mConditionVariableImpl)); +} +void LLConditionVariableImpl::notify_one() { + APRExceptionThrower(apr_thread_cond_signal(mConditionVariableImpl)); } +void LLConditionVariableImpl::notify_all() +{ + APRExceptionThrower(apr_thread_cond_broadcast(mConditionVariableImpl)); +} +void LLConditionVariableImpl::wait(LLMutex& lock) +{ + LLMutex::ImplAdoptMutex impl_adopted_mutex(lock); + APRExceptionThrower(apr_thread_cond_wait(mConditionVariableImpl, lock.native_handle())); +} +#endif +#endif -LLThreadSafeRefCount::~LLThreadSafeRefCount() -{ - if (mRef != 0) - { - llerrs << "deleting non-zero reference" << llendl; - } +LLTrace::BlockTimerStatHandle FT_WAIT_FOR_MUTEX("LLMutex::lock()"); +void LLMutex::lock_main(LLTrace::BlockTimerStatHandle* timer) +{ + llassert(!isSelfLocked()); + LL_RECORD_BLOCK_TIME(timer ? *timer : FT_WAIT_FOR_MUTEX); + LLMutexImpl::lock(); } -//============================================================================ +LLTrace::BlockTimerStatHandle FT_WAIT_FOR_CONDITION("LLCondition::wait()"); +void LLCondition::wait_main() +{ + llassert(isSelfLocked()); + LL_RECORD_BLOCK_TIME(FT_WAIT_FOR_CONDITION); + LLConditionVariableImpl::wait(*this); + llassert(isSelfLocked()); +} -LLResponder::~LLResponder() +LLTrace::BlockTimerStatHandle FT_WAIT_FOR_MUTEXLOCK("LLMutexLock::lock()"); +void LLMutexLock::lock() { + if (mMutex) + { + mMutex->lock(&FT_WAIT_FOR_MUTEXLOCK); + } } -//============================================================================ +//---------------------------------------------------------------------------- \ No newline at end of file diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h index 7d0cc593cc..bf0f26f778 100644 --- a/indra/llcommon/llthread.h +++ b/indra/llcommon/llthread.h @@ -27,18 +27,23 @@ #ifndef LL_LLTHREAD_H #define LL_LLTHREAD_H +#if !defined(_MSC_VER) || _MSC_VER >= 1700 +#define USE_BOOST_MUTEX 1 +#endif + +#define IS_LLCOMMON_INLINE (!LL_COMMON_LINK_SHARED || defined(llcommon_EXPORTS)) + #if LL_GNUC // Needed for is_main_thread() when compiling with optimization (relwithdebinfo). // It doesn't hurt to just always specify it though. -#pragma interface +//#pragma interface #endif #include "llapp.h" #include "llapr.h" -#include "llmemory.h" -#include "apr_thread_cond.h" #include "llaprpool.h" #include "llatomic.h" +#include "llmemory.h" #include "aithreadid.h" class LLThread; @@ -177,126 +182,315 @@ class LL_COMMON_API LLThread //============================================================================ -#define MUTEX_DEBUG (LL_DEBUG || LL_RELEASE_WITH_DEBUG_INFO) - -#ifdef MUTEX_DEBUG -// We really shouldn't be using recursive locks. Make sure of that in debug mode. -#define MUTEX_FLAG APR_THREAD_MUTEX_UNNESTED +#define MUTEX_POOL(arg) + +//Internal definitions +#define NEEDS_MUTEX_IMPL do_not_define_manually_thanks +#undef NEEDS_MUTEX_IMPL +#define NEEDS_MUTEX_RECURSION do_not_define_manually_thanks +#undef NEEDS_MUTEX_RECURSION + +//Prefer boost over stl over windows over apr. + +#if USE_BOOST_MUTEX && (BOOST_VERSION >= 103400) //condition_variable_any was added in boost 1.34 +//Define BOOST_SYSTEM_NO_DEPRECATED to avoid system_category() and generic_category() dependencies, as those won't be exported. +#define BOOST_SYSTEM_NO_DEPRECATED +#include +#include +#include +#include +typedef boost::recursive_mutex LLMutexImpl; +typedef boost::condition_variable_any LLConditionVariableImpl; +#elif defined(USE_STD_MUTEX) +#include +typedef std::recursive_mutex LLMutexImpl; +typedef std::condition_variable_any LLConditionVariableImpl; +#elif defined(USE_WIN32_MUTEX) +typedef CRITICAL_SECTION impl_mutex_handle_type; +typedef CONDITION_VARIABLE impl_cond_handle_type; +#define NEEDS_MUTEX_IMPL +#define NEEDS_MUTEX_RECURSION #else -// Use the fastest platform-optimal lock behavior (can be recursive or non-recursive). -#define MUTEX_FLAG APR_THREAD_MUTEX_DEFAULT +//----APR specific------ +#include "apr_thread_cond.h" +#include "apr_thread_mutex.h" +typedef LLAPRPool native_pool_type; +typedef apr_thread_mutex_t* impl_mutex_handle_type; +typedef apr_thread_cond_t* impl_cond_handle_type; +#undef MUTEX_POOL +#undef DEFAULT_POOL +#define MUTEX_POOL(arg) arg +#define NEEDS_MUTEX_IMPL +#define NEEDS_MUTEX_RECURSION +//END #endif +#include "llfasttimer.h" -class LL_COMMON_API LLMutexBase -{ -public: - LLMutexBase() ; - - void lock(); // blocks - void unlock(); - // Returns true if lock was obtained successfully. - bool tryLock(); +#ifdef NEEDS_MUTEX_IMPL - // Returns true if a call to lock() would block (returns false if self-locked()). - bool isLocked() const; +//Impl classes are not meant to be accessed directly. They must be utilized by a parent classes. +// They are designed to be 'clones' of their stl counterparts to facilitate simple drop-in +// replacement of underlying implementation (boost,std,apr,critical_sections,etc) +// Members and member functions are all private. +class LL_COMMON_API LLMutexImpl : private boost::noncopyable +{ + friend class LLMutex; + friend class LLCondition; + friend class LLConditionVariableImpl; - // Returns true if locked by this thread. - bool isSelfLocked() const; + typedef impl_mutex_handle_type native_handle_type; -protected: - // mAPRMutexp is initialized and uninitialized in the derived class. - apr_thread_mutex_t* mAPRMutexp; - mutable U32 mCount; - mutable AIThreadID mLockingThread; + LLMutexImpl(MUTEX_POOL(native_pool_type& pool)); + virtual ~LLMutexImpl(); + void lock(); + void unlock(); + bool try_lock(); + native_handle_type& native_handle() { return mMutexImpl; } private: - // Disallow copy construction and assignment. - LLMutexBase(LLMutexBase const&); - LLMutexBase& operator=(LLMutexBase const&); + native_handle_type mMutexImpl; + MUTEX_POOL(native_pool_type mPool); }; -class LL_COMMON_API LLMutex : public LLMutexBase +#endif + +class LL_COMMON_API LLMutex : public LLMutexImpl { +#ifdef NEEDS_MUTEX_IMPL + friend class LLConditionVariableImpl; +#endif public: - LLMutex(LLAPRPool& parent = LLThread::tldata().mRootPool) : mPool(parent) + LLMutex(MUTEX_POOL(native_pool_type& pool = LLThread::tldata().mRootPool)) : LLMutexImpl(MUTEX_POOL(pool)), +#ifdef NEEDS_MUTEX_RECURSION + mLockDepth(0), +#endif + mLockingThread(AIThreadID::sNone) + {} + ~LLMutex() + {} + + void lock(LLTrace::BlockTimerStatHandle* timer = NULL) // blocks { - apr_thread_mutex_create(&mAPRMutexp, MUTEX_FLAG, mPool()); + if (inc_lock_if_recursive()) + return; + +#if IS_LLCOMMON_INLINE + if (AIThreadID::in_main_thread_inline() && LLApp::isRunning()) +#else + if (AIThreadID::in_main_thread() && LLApp::isRunning()) +#endif + { + if (!LLMutexImpl::try_lock()) + { + lock_main(timer); + } + } + else + { + LLMutexImpl::lock(); + } +#if IS_LLCOMMON_INLINE + mLockingThread.reset_inline(); +#else + mLockingThread.reset(); +#endif } - ~LLMutex() + + void unlock() { - //this assertion erroneously triggers whenever an LLCondition is destroyed - //llassert(!isLocked()); // better not be locked! - apr_thread_mutex_destroy(mAPRMutexp); - mAPRMutexp = NULL; +#ifdef NEEDS_MUTEX_RECURSION + if (mLockDepth > 0) + { + --mLockDepth; + return; + } +#endif + mLockingThread = AIThreadID::sNone; + LLMutexImpl::unlock(); } -protected: - LLAPRPool mPool; + // Returns true if lock was obtained successfully. + bool try_lock() + { + if (inc_lock_if_recursive()) + return true; + if (!LLMutexImpl::try_lock()) + return false; +#if IS_LLCOMMON_INLINE + mLockingThread.reset_inline(); +#else + mLockingThread.reset(); +#endif + return true; + } + + // Returns true if locked not by this thread + bool isLocked() + { + if (isSelfLocked()) + return false; + if (LLMutexImpl::try_lock()) + { + LLMutexImpl::unlock(); + return false; + } + return true; + } + // Returns true if locked by this thread. + bool isSelfLocked() const + { +#if IS_LLCOMMON_INLINE + return mLockingThread.equals_current_thread_inline(); +#else + return mLockingThread.equals_current_thread(); +#endif + } + +#ifdef NEEDS_MUTEX_IMPL + //This is important for libraries that we cannot pass LLMutex into. + //For example, apr wait. apr wait unlocks and re-locks the thread, however + // it has no knowledge of LLMutex::mLockingThread and LLMutex::mLockDepth, + // and thus will leave those member variables set even after the wait internally releases the lock. + // Leaving those two variables set even when mutex has actually been unlocked via apr is BAD. + friend class ImplAdoptMutex; + class ImplAdoptMutex + { + friend class LLConditionVariableImpl; + ImplAdoptMutex(LLMutex& mutex) : mMutex(mutex), +#ifdef NEEDS_MUTEX_RECURSION + mLockDepth(mutex.mLockDepth), +#endif + mLockingThread(mutex.mLockingThread) + + { + mMutex.mLockingThread = AIThreadID::sNone; +#ifdef NEEDS_MUTEX_RECURSION + mMutex.mLockDepth = 0; +#endif + } + ~ImplAdoptMutex() + { + mMutex.mLockingThread = mLockingThread; +#ifdef NEEDS_MUTEX_RECURSION + mMutex.mLockDepth = mLockDepth; +#endif + } + LLMutex& mMutex; + AIThreadID mLockingThread; +#ifdef NEEDS_MUTEX_RECURSION + S32 mLockDepth; +#endif + }; +#endif + +private: + void lock_main(LLTrace::BlockTimerStatHandle* timer); + + bool inc_lock_if_recursive() + { +#ifdef NEEDS_MUTEX_RECURSION + if (isSelfLocked()) + { + mLockDepth++; + return true; + } +#endif + return false; + } + + mutable AIThreadID mLockingThread; +#ifdef NEEDS_MUTEX_RECURSION + LLAtomicS32 mLockDepth; +#endif }; -#if APR_HAS_THREADS -// No need to use a root pool in this case. -typedef LLMutex LLMutexRootPool; -#else // APR_HAS_THREADS -class LL_COMMON_API LLMutexRootPool : public LLMutexBase +class LLGlobalMutex : public LLMutex { public: - LLMutexRootPool(void) - { - apr_thread_mutex_create(&mAPRMutexp, MUTEX_FLAG, mRootPool()); - } - ~LLMutexRootPool() + LLGlobalMutex() : LLMutex(MUTEX_POOL(LLAPRRootPool::get())), mbInitalized(true) + {} + bool isInitalized() const { -#if APR_POOL_DEBUG - // It is allowed to destruct root pools from a different thread. - mRootPool.grab_ownership(); -#endif - llassert(!isLocked()); // better not be locked! - apr_thread_mutex_destroy(mAPRMutexp); - mAPRMutexp = NULL; + return mbInitalized; } +private: + bool mbInitalized; +}; -protected: - LLAPRRootPool mRootPool; +#ifdef NEEDS_MUTEX_IMPL +class LL_COMMON_API LLConditionVariableImpl : private boost::noncopyable +{ + friend class LLCondition; + + typedef impl_cond_handle_type native_handle_type; + + LLConditionVariableImpl(MUTEX_POOL(native_pool_type& pool)); + virtual ~LLConditionVariableImpl(); + void notify_one(); + void notify_all(); + void wait(LLMutex& lock); + native_handle_type& native_handle() { return mConditionVariableImpl; } + + native_handle_type mConditionVariableImpl; + MUTEX_POOL(native_pool_type mPool); }; -#endif // APR_HAS_THREADS +#endif + +typedef LLMutex LLMutexRootPool; // Actually a condition/mutex pair (since each condition needs to be associated with a mutex). -class LL_COMMON_API LLCondition : public LLMutex +class LLCondition : public LLConditionVariableImpl, public LLMutex { public: - LLCondition(LLAPRPool& parent = LLThread::tldata().mRootPool); - ~LLCondition(); - - void wait(); // blocks - void signal(); - void broadcast(); - -protected: - apr_thread_cond_t *mAPRCondp; + LLCondition(MUTEX_POOL(native_pool_type& pool = LLThread::tldata().mRootPool)) : + LLMutex(MUTEX_POOL(pool)), + LLConditionVariableImpl(MUTEX_POOL(pool)) + {} + ~LLCondition() + {} + void wait() + { +#if IS_LLCOMMON_INLINE + if (AIThreadID::in_main_thread_inline()) +#else + if (AIThreadID::in_main_thread()) +#endif + wait_main(); + else LLConditionVariableImpl::wait(*this); + } + void signal() { LLConditionVariableImpl::notify_one(); } + void broadcast() { LLConditionVariableImpl::notify_all(); } +private: + LL_COMMON_API void wait_main(); //Cannot be inline. Uses internal fasttimer. }; -class LL_COMMON_API LLMutexLock +class LLMutexLock { public: - LLMutexLock(LLMutexBase* mutex) + LLMutexLock(LLMutex* mutex) { mMutex = mutex; - if(mMutex) mMutex->lock(); + lock(); + } + LLMutexLock(LLMutex& mutex) + { + mMutex = &mutex; + lock(); } ~LLMutexLock() { - if(mMutex) mMutex->unlock(); + if (mMutex) mMutex->unlock(); } private: - LLMutexBase* mMutex; + LL_COMMON_API void lock(); //Cannot be inline. Uses internal fasttimer. + LLMutex* mMutex; }; -class LL_COMMON_API AIRWLock +class AIRWLock { public: AIRWLock(LLAPRPool& parent = LLThread::tldata().mRootPool) : - mWriterWaitingMutex(parent), mNoHoldersCondition(parent), mHoldersCount(0), mWriterIsWaiting(false) { } + mWriterWaitingMutex(MUTEX_POOL(parent)), mNoHoldersCondition(MUTEX_POOL(parent)), mHoldersCount(0), mWriterIsWaiting(false) { } private: LLMutex mWriterWaitingMutex; //!< This mutex is locked while some writer is waiting for access. @@ -398,7 +592,7 @@ class LL_COMMON_API AIRWLock }; #if LL_DEBUG -class LL_COMMON_API AINRLock +class AINRLock { private: int read_locked; @@ -409,15 +603,15 @@ class LL_COMMON_API AINRLock void accessed(void) const { - if (!mAccessed) - { - mAccessed = true; - mTheadID.reset(); - } - else - { - llassert_always(mTheadID.equals_current_thread()); - } + if (!mAccessed) + { + mAccessed = true; + mTheadID.reset(); + } + else + { + llassert_always(mTheadID.equals_current_thread()); + } } public: @@ -451,27 +645,34 @@ void LLThread::unlockData() // see llmemory.h for LLPointer<> definition -class LL_COMMON_API LLThreadSafeRefCount +class LLThreadSafeRefCount { private: LLThreadSafeRefCount(const LLThreadSafeRefCount&); // not implemented LLThreadSafeRefCount&operator=(const LLThreadSafeRefCount&); // not implemented protected: - virtual ~LLThreadSafeRefCount(); // use unref() - + virtual ~LLThreadSafeRefCount() // use unref() + { + if (mRef != 0) + { + LL_ERRS() << "deleting non-zero reference" << LL_ENDL; + } + } + public: - LLThreadSafeRefCount(); - + LLThreadSafeRefCount() : mRef(0) + {} + void ref() { - mRef++; - } + mRef++; + } void unref() { llassert(mRef > 0); - if (!--mRef) delete this; + if (--mRef == 0) delete this; } S32 getNumRefs() const { @@ -486,10 +687,10 @@ class LL_COMMON_API LLThreadSafeRefCount // Simple responder for self destructing callbacks // Pure virtual class -class LL_COMMON_API LLResponder : public LLThreadSafeRefCount +class LLResponder : public LLThreadSafeRefCount { protected: - virtual ~LLResponder(); + virtual ~LLResponder() {} public: virtual void completed(bool success) = 0; }; diff --git a/indra/llcommon/llthreadsafequeue.cpp b/indra/llcommon/llthreadsafequeue.cpp index 05d24944f3..427b55bb5a 100644 --- a/indra/llcommon/llthreadsafequeue.cpp +++ b/indra/llcommon/llthreadsafequeue.cpp @@ -46,7 +46,7 @@ LLThreadSafeQueueImplementation::LLThreadSafeQueueImplementation(unsigned int ca LLThreadSafeQueueImplementation::~LLThreadSafeQueueImplementation() { if(mQueue != 0) { - if(apr_queue_size(mQueue) != 0) llwarns << + if(apr_queue_size(mQueue) != 0) LL_WARNS() << "terminating queue which still contains " << apr_queue_size(mQueue) << " elements;" << "memory will be leaked" << LL_ENDL; apr_queue_term(mQueue); diff --git a/indra/llcommon/lltimer.cpp b/indra/llcommon/lltimer.cpp index e77d8b63a2..e458cc66a9 100644 --- a/indra/llcommon/lltimer.cpp +++ b/indra/llcommon/lltimer.cpp @@ -30,14 +30,10 @@ #include "u64.h" -#include "lldate.h" - #if LL_WINDOWS -# define WIN32_LEAN_AND_MEAN -# include -# include +# include "llwin32headerslean.h" #elif LL_LINUX || LL_SOLARIS || LL_DARWIN -# include +# include # include #else # error "architecture not supported" @@ -85,7 +81,7 @@ U32 micro_sleep(U64 us, U32 max_yields) { // max_yields is unused; just fiddle with it to avoid warnings. max_yields = 0; - ms_sleep(us / 1000); + ms_sleep((U32)(us / 1000)); return 0; } #elif LL_LINUX || LL_SOLARIS || LL_DARWIN @@ -105,8 +101,8 @@ static void _sleep_loop(struct timespec& thiswait) if (sleep_more) { if ( nextwait.tv_sec > thiswait.tv_sec || - (nextwait.tv_sec == thiswait.tv_sec && - nextwait.tv_nsec >= thiswait.tv_nsec) ) + (nextwait.tv_sec == thiswait.tv_sec && + nextwait.tv_nsec >= thiswait.tv_nsec) ) { // if the remaining time isn't actually going // down then we're being shafted by low clock @@ -132,31 +128,31 @@ static void _sleep_loop(struct timespec& thiswait) U32 micro_sleep(U64 us, U32 max_yields) { - U64 start = get_clock_count(); - // This is kernel dependent. Currently, our kernel generates software clock - // interrupts at 250 Hz (every 4,000 microseconds). - const U64 KERNEL_SLEEP_INTERVAL_US = 4000; - - S32 num_sleep_intervals = (us - (KERNEL_SLEEP_INTERVAL_US >> 1)) / KERNEL_SLEEP_INTERVAL_US; - if (num_sleep_intervals > 0) - { - U64 sleep_time = (num_sleep_intervals * KERNEL_SLEEP_INTERVAL_US) - (KERNEL_SLEEP_INTERVAL_US >> 1); - struct timespec thiswait; - thiswait.tv_sec = sleep_time / 1000000; - thiswait.tv_nsec = (sleep_time % 1000000) * 1000l; - _sleep_loop(thiswait); - } - - U64 current_clock = get_clock_count(); - U32 yields = 0; - while ( (yields < max_yields) - && (current_clock - start < us) ) - { - sched_yield(); - ++yields; - current_clock = get_clock_count(); - } - return yields; + U64 start = get_clock_count(); + // This is kernel dependent. Currently, our kernel generates software clock + // interrupts at 250 Hz (every 4,000 microseconds). + const U64 KERNEL_SLEEP_INTERVAL_US = 4000; + + S32 num_sleep_intervals = (us - (KERNEL_SLEEP_INTERVAL_US >> 1)) / KERNEL_SLEEP_INTERVAL_US; + if (num_sleep_intervals > 0) + { + U64 sleep_time = (num_sleep_intervals * KERNEL_SLEEP_INTERVAL_US) - (KERNEL_SLEEP_INTERVAL_US >> 1); + struct timespec thiswait; + thiswait.tv_sec = sleep_time / 1000000; + thiswait.tv_nsec = (sleep_time % 1000000) * 1000l; + _sleep_loop(thiswait); + } + + U64 current_clock = get_clock_count(); + U32 yields = 0; + while ( (yields < max_yields) + && (current_clock - start < us) ) + { + sched_yield(); + ++yields; + current_clock = get_clock_count(); + } + return yields; } void ms_sleep(U32 ms) @@ -165,7 +161,7 @@ void ms_sleep(U32 ms) struct timespec thiswait; thiswait.tv_sec = ms / 1000; thiswait.tv_nsec = (mslong % 1000) * 1000000l; - _sleep_loop(thiswait); + _sleep_loop(thiswait); } #else # error "architecture not supported" @@ -192,7 +188,7 @@ U64 get_clock_count() return clock_count.QuadPart - offset; } -F64 calc_clock_frequency(void) +F64 calc_clock_frequency() { __int64 freq; QueryPerformanceFrequency((LARGE_INTEGER *) &freq); @@ -203,9 +199,9 @@ F64 calc_clock_frequency(void) #if LL_LINUX || LL_DARWIN || LL_SOLARIS // Both Linux and Mac use gettimeofday for accurate time -F64 calc_clock_frequency(void) +F64 calc_clock_frequency() { - return 1000000.0; // microseconds, so 1 Mhz. + return 1000000.0; // microseconds, so 1 MHz. } U64 get_clock_count() @@ -218,56 +214,68 @@ U64 get_clock_count() #endif -void update_clock_frequencies() +TimerInfo::TimerInfo() +: mClockFrequency(0.0), + mTotalTimeClockCount(0), + mLastTotalTimeClockCount(0) +{} + +void TimerInfo::update() { - gClockFrequency = calc_clock_frequency(); - gClockFrequencyInv = 1.0/gClockFrequency; - gClocksToMicroseconds = gClockFrequencyInv * SEC_TO_MICROSEC; + mClockFrequency = calc_clock_frequency(); + mClockFrequencyInv = 1.0/mClockFrequency; + mClocksToMicroseconds = mClockFrequencyInv; } +TimerInfo& get_timer_info() +{ + static TimerInfo sTimerInfo; + return sTimerInfo; +} /////////////////////////////////////////////////////////////////////////////// // returns a U64 number that represents the number of -// microseconds since the unix epoch - Jan 1, 1970 -U64 totalTime() +// microseconds since the Unix epoch - Jan 1, 1970 +U64MicrosecondsImplicit totalTime() { U64 current_clock_count = get_clock_count(); - if (!gTotalTimeClockCount) + if (!get_timer_info().mTotalTimeClockCount || get_timer_info().mClocksToMicroseconds.value() == 0) { - update_clock_frequencies(); - gTotalTimeClockCount = current_clock_count; + get_timer_info().update(); + get_timer_info().mTotalTimeClockCount = current_clock_count; #if LL_WINDOWS - // Synch us up with local time (even though we PROBABLY don't need to, this is how it was implemented) + // Sync us up with local time (even though we PROBABLY don't need to, this is how it was implemented) // Unix platforms use gettimeofday so they are synced, although this probably isn't a good assumption to // make in the future. - gTotalTimeClockCount = (U64)(time(NULL) * gClockFrequency); + get_timer_info().mTotalTimeClockCount = (U64)(time(NULL) * get_timer_info().mClockFrequency); #endif // Update the last clock count - gLastTotalTimeClockCount = current_clock_count; + get_timer_info().mLastTotalTimeClockCount = current_clock_count; } else { - if (LL_LIKELY(current_clock_count >= gLastTotalTimeClockCount)) + if (current_clock_count >= get_timer_info().mLastTotalTimeClockCount) { // No wrapping, we're all okay. - gTotalTimeClockCount += current_clock_count - gLastTotalTimeClockCount; + get_timer_info().mTotalTimeClockCount += current_clock_count - get_timer_info().mLastTotalTimeClockCount; } else { // We've wrapped. Compensate correctly - gTotalTimeClockCount += (0xFFFFFFFFFFFFFFFFULL - gLastTotalTimeClockCount) + current_clock_count; + get_timer_info().mTotalTimeClockCount += (0xFFFFFFFFFFFFFFFFULL - get_timer_info().mLastTotalTimeClockCount) + current_clock_count; } // Update the last clock count - gLastTotalTimeClockCount = current_clock_count; + get_timer_info().mLastTotalTimeClockCount = current_clock_count; } // Return the total clock tick count in microseconds. - return (U64)(gTotalTimeClockCount*gClocksToMicroseconds); + U64Microseconds time(get_timer_info().mTotalTimeClockCount*get_timer_info().mClocksToMicroseconds); + return time; } @@ -275,9 +283,9 @@ U64 totalTime() LLTimer::LLTimer() { - if (!gClockFrequency) + if (!get_timer_info().mClockFrequency) { - update_clock_frequencies(); + get_timer_info().update(); } mStarted = TRUE; @@ -285,20 +293,32 @@ LLTimer::LLTimer() } LLTimer::~LLTimer() +{} + +// static +void LLTimer::initClass() { + if (!sTimer) sTimer = new LLTimer; } // static -U64 LLTimer::getTotalTime() +void LLTimer::cleanupClass() +{ + delete sTimer; sTimer = NULL; +} + +// static +U64MicrosecondsImplicit LLTimer::getTotalTime() { // simply call into the implementation function. - return totalTime(); + U64MicrosecondsImplicit total_time = totalTime(); + return total_time; } // static -F64 LLTimer::getTotalSeconds() +F64SecondsImplicit LLTimer::getTotalSeconds() { - return U64_to_F64(getTotalTime()) * USEC_TO_SEC_F64; + return F64Microseconds(U64_to_F64(getTotalTime())); } void LLTimer::reset() @@ -345,43 +365,43 @@ U64 getElapsedTimeAndUpdate(U64& lastClockCount) } -F64 LLTimer::getElapsedTimeF64() const +F64SecondsImplicit LLTimer::getElapsedTimeF64() const { U64 last = mLastClockCount; - return (F64)getElapsedTimeAndUpdate(last) * gClockFrequencyInv; + return (F64)getElapsedTimeAndUpdate(last) * get_timer_info().mClockFrequencyInv; } -F32 LLTimer::getElapsedTimeF32() const +F32SecondsImplicit LLTimer::getElapsedTimeF32() const { return (F32)getElapsedTimeF64(); } -F64 LLTimer::getElapsedTimeAndResetF64() +F64SecondsImplicit LLTimer::getElapsedTimeAndResetF64() { - return (F64)getElapsedTimeAndUpdate(mLastClockCount) * gClockFrequencyInv; + return (F64)getElapsedTimeAndUpdate(mLastClockCount) * get_timer_info().mClockFrequencyInv; } -F32 LLTimer::getElapsedTimeAndResetF32() +F32SecondsImplicit LLTimer::getElapsedTimeAndResetF32() { return (F32)getElapsedTimeAndResetF64(); } /////////////////////////////////////////////////////////////////////////////// -void LLTimer::setTimerExpirySec(F32 expiration) +void LLTimer::setTimerExpirySec(F32SecondsImplicit expiration) { mExpirationTicks = get_clock_count() - + (U64)((F32)(expiration * gClockFrequency)); + + (U64)((F32)(expiration * get_timer_info().mClockFrequency.value())); } -F32 LLTimer::getRemainingTimeF32() const +F32SecondsImplicit LLTimer::getRemainingTimeF32() const { U64 cur_ticks = get_clock_count(); if (cur_ticks > mExpirationTicks) { return 0.0f; } - return F32((mExpirationTicks - cur_ticks) * gClockFrequencyInv); + return F32((mExpirationTicks - cur_ticks) * get_timer_info().mClockFrequencyInv); } @@ -394,7 +414,7 @@ BOOL LLTimer::checkExpirationAndReset(F32 expiration) } mExpirationTicks = cur_ticks - + (U64)((F32)(expiration * gClockFrequency)); + + (U64)((F32)(expiration * get_timer_info().mClockFrequency)); return TRUE; } @@ -413,15 +433,15 @@ BOOL LLTimer::knownBadTimer() #if LL_WINDOWS WCHAR bad_pci_list[][10] = {L"1039:0530", - L"1039:0620", - L"10B9:0533", - L"10B9:1533", - L"1106:0596", - L"1106:0686", - L"1166:004F", - L"1166:0050", - L"8086:7110", - L"\0" + L"1039:0620", + L"10B9:0533", + L"10B9:1533", + L"1106:0596", + L"1106:0686", + L"1166:004F", + L"1166:0050", + L"8086:7110", + L"\0" }; HKEY hKey = NULL; @@ -450,7 +470,7 @@ BOOL LLTimer::knownBadTimer() { if (!wcscmp(pci_id, bad_pci_list[check])) { -// llwarns << "unreliable PCI chipset found!! " << pci_id << endl; +// LL_WARNS() << "unreliable PCI chipset found!! " << pci_id << endl; failed = TRUE; break; } @@ -493,20 +513,20 @@ BOOL is_daylight_savings() struct tm* utc_to_pacific_time(time_t utc_time, BOOL pacific_daylight_time) { - S32 pacific_offset_hours; + S32Hours pacific_offset_hours; if (pacific_daylight_time) { - pacific_offset_hours = 7; + pacific_offset_hours = S32Hours(7); } else { - pacific_offset_hours = 8; + pacific_offset_hours = S32Hours(8); } // We subtract off the PST/PDT offset _before_ getting // "UTC" time, because this will handle wrapping around // for 5 AM UTC -> 10 PM PDT of the previous day. - utc_time -= pacific_offset_hours * MIN_PER_HOUR * SEC_PER_MIN; + utc_time -= S32SecondsImplicit(pacific_offset_hours); // Internal buffer to PST/PDT (see above) struct tm* internal_time = gmtime(&utc_time); @@ -523,7 +543,7 @@ struct tm* utc_to_pacific_time(time_t utc_time, BOOL pacific_daylight_time) } -void microsecondsToTimecodeString(U64 current_time, std::string& tcstring) +void microsecondsToTimecodeString(U64MicrosecondsImplicit current_time, std::string& tcstring) { U64 hours; U64 minutes; @@ -545,9 +565,9 @@ void microsecondsToTimecodeString(U64 current_time, std::string& tcstring) } -void secondsToTimecodeString(F32 current_time, std::string& tcstring) +void secondsToTimecodeString(F32SecondsImplicit current_time, std::string& tcstring) { - microsecondsToTimecodeString((U64)((F64)(SEC_TO_MICROSEC*current_time)), tcstring); + microsecondsToTimecodeString(current_time, tcstring); } @@ -569,6 +589,3 @@ void timeStructToFormattedString(struct tm * time, std::string format, std::stri } - - - diff --git a/indra/llcommon/lltimer.h b/indra/llcommon/lltimer.h index 167784f3c2..d43267bb66 100644 --- a/indra/llcommon/lltimer.h +++ b/indra/llcommon/lltimer.h @@ -37,6 +37,7 @@ #include #include // units conversions +#include "llunits.h" #ifndef USEC_PER_SEC const U32 USEC_PER_SEC = 1000000; #endif @@ -55,27 +56,34 @@ class LL_COMMON_API LLTimer protected: U64 mLastClockCount; U64 mExpirationTicks; - BOOL mStarted; + bool mStarted; public: LLTimer(); ~LLTimer(); - static void initClass() { if (!sTimer) sTimer = new LLTimer; } - static void cleanupClass() { delete sTimer; sTimer = NULL; } + static void initClass(); + static void cleanupClass(); // Return a high precision number of seconds since the start of // this application instance. - static F64 getElapsedSeconds() + static F64SecondsImplicit getElapsedSeconds() + { + if (sTimer) { return sTimer->getElapsedTimeF64(); } + else + { + return 0; + } + } // Return a high precision usec since epoch - static U64 getTotalTime(); + static U64MicrosecondsImplicit getTotalTime(); // Return a high precision seconds since epoch - static F64 getTotalSeconds(); + static F64SecondsImplicit getTotalSeconds(); // MANIPULATORS @@ -83,21 +91,21 @@ class LL_COMMON_API LLTimer void stop() { mStarted = FALSE; } void reset(); // Resets the timer void setLastClockCount(U64 current_count); // Sets the timer so that the next elapsed call will be relative to this time - void setTimerExpirySec(F32 expiration); + void setTimerExpirySec(F32SecondsImplicit expiration); BOOL checkExpirationAndReset(F32 expiration); BOOL hasExpired() const; - F32 getElapsedTimeAndResetF32(); // Returns elapsed time in seconds with reset - F64 getElapsedTimeAndResetF64(); + F32SecondsImplicit getElapsedTimeAndResetF32(); // Returns elapsed time in seconds with reset + F64SecondsImplicit getElapsedTimeAndResetF64(); - F32 getRemainingTimeF32() const; + F32SecondsImplicit getRemainingTimeF32() const; static BOOL knownBadTimer(); // ACCESSORS - F32 getElapsedTimeF32() const; // Returns elapsed time in seconds - F64 getElapsedTimeF64() const; // Returns elapsed time in seconds + F32SecondsImplicit getElapsedTimeF32() const; // Returns elapsed time in seconds + F64SecondsImplicit getElapsedTimeF64() const; // Returns elapsed time in seconds - BOOL getStarted() const { return mStarted; } + bool getStarted() const { return mStarted; } static U64 getCurrentClockCount(); // Returns the raw clockticks @@ -106,6 +114,20 @@ class LL_COMMON_API LLTimer // // Various functions for initializing/accessing clock and timing stuff. Don't use these without REALLY knowing how they work. // +struct TimerInfo +{ + TimerInfo(); + void update(); + + F64HertzImplicit mClockFrequency; + F64SecondsImplicit mClockFrequencyInv; + F64MicrosecondsImplicit mClocksToMicroseconds; + U64 mTotalTimeClockCount; + U64 mLastTotalTimeClockCount; +}; + +TimerInfo& get_timer_info(); + LL_COMMON_API U64 get_clock_count(); LL_COMMON_API F64 calc_clock_frequency(); LL_COMMON_API void update_clock_frequencies(); @@ -160,10 +182,10 @@ LL_COMMON_API BOOL is_daylight_savings(); // struct tm* internal_time = utc_to_pacific_time(utc_time, gDaylight); LL_COMMON_API struct tm* utc_to_pacific_time(time_t utc_time, BOOL pacific_daylight_time); -LL_COMMON_API void microsecondsToTimecodeString(U64 current_time, std::string& tcstring); -LL_COMMON_API void secondsToTimecodeString(F32 current_time, std::string& tcstring); +LL_COMMON_API void microsecondsToTimecodeString(U64MicrosecondsImplicit current_time, std::string& tcstring); +LL_COMMON_API void secondsToTimecodeString(F32SecondsImplicit current_time, std::string& tcstring); LL_COMMON_API void timeToFormattedString(time_t time, std::string format, std::string ×tr); LL_COMMON_API void timeStructToFormattedString(struct tm * time, std::string format, std::string ×tr); -U64 LL_COMMON_API totalTime(); // Returns current system time in microseconds +U64MicrosecondsImplicit LL_COMMON_API totalTime(); // Returns current system time in microseconds #endif diff --git a/indra/llcommon/lltreeiterators.h b/indra/llcommon/lltreeiterators.h index ba861ae70b..19258a9642 100644 --- a/indra/llcommon/lltreeiterators.h +++ b/indra/llcommon/lltreeiterators.h @@ -63,7 +63,6 @@ #include #include #include -#include #include namespace LLTreeIter @@ -93,7 +92,7 @@ class LLBaseIter: public boost::iterator_facade::type ptr_type; /// function that advances from this node to next accepts a node pointer /// and returns another - typedef boost::function func_type; + typedef std::function func_type; typedef SELFTYPE self_type; }; @@ -330,7 +329,7 @@ class LLTreeDFSIter: public LLBaseIter, NODE> typedef typename super::ptr_type ptr_type; // The func_type is different for this: from a NODE pointer, we must // obtain a CHILDITER. - typedef boost::function func_type; + typedef std::function func_type; private: typedef std::vector list_type; public: @@ -435,7 +434,7 @@ class LLTreeDFSPostIter: public LLBaseIter, N typedef typename super::ptr_type ptr_type; // The func_type is different for this: from a NODE pointer, we must // obtain a CHILDITER. - typedef boost::function func_type; + typedef std::function func_type; private: // Upon reaching a given node in our pending list, we need to know whether // we've already pushed that node's children, so we must associate a bool @@ -500,14 +499,17 @@ class LLTreeDFSPostIter: public LLBaseIter, N // Once we've popped the last node, this becomes a no-op. if (mPending.empty()) return; + + auto& pending = mPending.back(); + // Here mPending.back() holds the node pointer we're proposing to // dereference next. Have we pushed that node's children yet? - if (mPending.back().second) + if (pending.second) return; // if so, it's okay to visit this node now // We haven't yet pushed this node's children. Do so now. Remember // that we did -- while the node in question is still back(). - mPending.back().second = true; - addChildren(mPending.back().first); + pending.second = true; + addChildren(pending.first); // Now, because we've just changed mPending.back(), make that new node // current. makeCurrent(); @@ -574,7 +576,7 @@ class LLTreeBFSIter: public LLBaseIter, NODE> typedef typename super::ptr_type ptr_type; // The func_type is different for this: from a NODE pointer, we must // obtain a CHILDITER. - typedef boost::function func_type; + typedef std::function func_type; private: // We need a FIFO queue rather than a LIFO stack. Use a deque rather than // a vector, since vector can't implement pop_front() efficiently. diff --git a/indra/llcommon/llunits.h b/indra/llcommon/llunits.h new file mode 100644 index 0000000000..0fcb8281a0 --- /dev/null +++ b/indra/llcommon/llunits.h @@ -0,0 +1,129 @@ +/** + * @file llunits.h + * @brief Unit definitions + * + * $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$ + */ + +#ifndef LL_LLUNITTYPE_H +#define LL_LLUNITTYPE_H + +#include "stdtypes.h" +#include "llunittype.h" + +// +// Unit declarations +// + +namespace LLUnits +{ +LL_DECLARE_BASE_UNIT(Bytes, "B"); +// technically, these are kibibytes, mibibytes, etc. but we should stick with commonly accepted terminology +LL_DECLARE_DERIVED_UNIT(Kilobytes, "KB", Bytes, / 1024); +LL_DECLARE_DERIVED_UNIT(Megabytes, "MB", Kilobytes, / 1024); +LL_DECLARE_DERIVED_UNIT(Gigabytes, "GB", Megabytes, / 1024); +} + +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Bytes); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Kilobytes); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Megabytes); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Gigabytes); + +namespace LLUnits +{ +// technically, these are kibibits, mibibits, etc. but we should stick with commonly accepted terminology +LL_DECLARE_DERIVED_UNIT(Bits, "b", Bytes, * 8 ); +LL_DECLARE_DERIVED_UNIT(Kilobits, "Kb", Bits, / 1024); +LL_DECLARE_DERIVED_UNIT(Megabits, "Mb", Kilobits, / 1024); +LL_DECLARE_DERIVED_UNIT(Gigabits, "Gb", Megabits, / 1024); +} + +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Bits); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Kilobits); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Megabits); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Gigabits); + +namespace LLUnits +{ +LL_DECLARE_BASE_UNIT(Seconds, "s"); +LL_DECLARE_DERIVED_UNIT(Minutes, "min", Seconds, / 60); +LL_DECLARE_DERIVED_UNIT(Hours, "h", Minutes, / 60); +LL_DECLARE_DERIVED_UNIT(Days, "d", Hours, / 24); +LL_DECLARE_DERIVED_UNIT(Milliseconds, "ms", Seconds, * 1000); +LL_DECLARE_DERIVED_UNIT(Microseconds, "\x09\x3cs", Milliseconds, * 1000); +LL_DECLARE_DERIVED_UNIT(Nanoseconds, "ns", Microseconds, * 1000); +} + +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Seconds); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Minutes); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Hours); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Days); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Milliseconds); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Microseconds); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Nanoseconds); + +namespace LLUnits +{ +LL_DECLARE_BASE_UNIT(Meters, "m"); +LL_DECLARE_DERIVED_UNIT(Kilometers, "km", Meters, / 1000); +LL_DECLARE_DERIVED_UNIT(Centimeters, "cm", Meters, * 100); +LL_DECLARE_DERIVED_UNIT(Millimeters, "mm", Meters, * 1000); +} + +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Meters); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Kilometers); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Centimeters); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Millimeters); + +namespace LLUnits +{ +// rare units +LL_DECLARE_BASE_UNIT(Hertz, "Hz"); +LL_DECLARE_DERIVED_UNIT(Kilohertz, "KHz", Hertz, / 1000); +LL_DECLARE_DERIVED_UNIT(Megahertz, "MHz", Kilohertz, / 1000); +LL_DECLARE_DERIVED_UNIT(Gigahertz, "GHz", Megahertz, / 1000); + +LL_DECLARE_BASE_UNIT(Radians, "rad"); +LL_DECLARE_DERIVED_UNIT(Degrees, "deg", Radians, * 57.29578f); + +LL_DECLARE_BASE_UNIT(Percent, "%"); +LL_DECLARE_DERIVED_UNIT(Ratio, "x", Percent, / 100); + +LL_DECLARE_BASE_UNIT(Triangles, "tris"); +LL_DECLARE_DERIVED_UNIT(Kilotriangles, "ktris", Triangles, / 1000); + +} // namespace LLUnits + +// rare units +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Hertz); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Kilohertz); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Megahertz); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Gigahertz); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Radians); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Degrees); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Percent); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Ratio); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Triangles); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Kilotriangles); + + +#endif // LL_LLUNITTYPE_H diff --git a/indra/llcommon/llunittype.h b/indra/llcommon/llunittype.h new file mode 100644 index 0000000000..81f244e422 --- /dev/null +++ b/indra/llcommon/llunittype.h @@ -0,0 +1,849 @@ +/** + * @file llunit.h + * @brief Unit conversion classes + * + * $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$ + */ + +#ifndef LL_UNITTYPE_H +#define LL_UNITTYPE_H + +#include "stdtypes.h" +#include "llpreprocessor.h" +#include "llerror.h" + +//lightweight replacement of type traits for simple type equality check +template +struct LLIsSameType +{ + static const bool value = false; +}; + +template +struct LLIsSameType +{ + static const bool value = true; +}; + +// workaround for decltype() not existing and typeof() not working inline in gcc 4.2 +template +struct LLResultTypeAdd +{ + typedef LL_TYPEOF(S() + T()) type_t; +}; + +template +struct LLResultTypeSubtract +{ + typedef LL_TYPEOF(S() - T()) type_t; +}; + +template +struct LLResultTypeMultiply +{ + typedef LL_TYPEOF(S() * T()) type_t; +}; + +template +struct LLResultTypeDivide +{ + typedef LL_TYPEOF(S() / T(1)) type_t; +}; + +template +struct LLResultTypePromote +{ + typedef LL_TYPEOF((true) ? S() : T()) type_t; +}; + +template +struct LLUnit +{ + typedef LLUnit self_t; + typedef STORAGE_TYPE storage_t; + typedef void is_unit_t; + + // value initialization + LL_FORCE_INLINE explicit LLUnit(storage_t value = storage_t()) + : mValue(value) + {} + + + LL_FORCE_INLINE static self_t convert(self_t v) + { + return v; + } + + template + LL_FORCE_INLINE static self_t convert(LLUnit v) + { + self_t result; + result.mValue = (STORAGE_TYPE)v.value(); + return result; + } + + template + LL_FORCE_INLINE static self_t convert(LLUnit v) + { + self_t result; + STORAGE_TYPE divisor = ll_convert_units(v, result); + result.mValue /= divisor; + return result; + } + + template + LL_FORCE_INLINE static self_t convert(LLUnit v) + { + typedef typename LLResultTypePromote::type_t result_storage_t; + LLUnit result; + result_storage_t divisor = ll_convert_units(v, result); + result.value(result.value() / divisor); + return self_t(result.value()); + } + + + // unit initialization and conversion + template + LL_FORCE_INLINE LLUnit(LLUnit other) + : mValue(convert(other).mValue) + {} + + LL_FORCE_INLINE storage_t value() const + { + return mValue; + } + + LL_FORCE_INLINE void value(const storage_t& value) + { + mValue = value; + } + + template + storage_t valueInUnits() const + { + return LLUnit(*this).value(); + } + + template + void valueInUnits(const storage_t& value) const + { + *this = LLUnit(value); + } + + LL_FORCE_INLINE operator storage_t() const + { + return value(); + } + + /*LL_FORCE_INLINE self_t& operator= (storage_t v) + { + value(v); + return *this; + }*/ + + LL_FORCE_INLINE void operator += (self_t other) + { + mValue += convert(other).mValue; + } + + LL_FORCE_INLINE void operator -= (self_t other) + { + mValue -= convert(other).mValue; + } + + LL_FORCE_INLINE void operator *= (const storage_t& multiplicand) + { + mValue *= multiplicand; + } + + LL_FORCE_INLINE void operator *= (const self_t& multiplicand) + { + // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template + LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "Multiplication of unit types not supported."); + } + + LL_FORCE_INLINE void operator /= (const storage_t& divisor) + { + mValue /= divisor; + } + + void operator /= (const self_t& divisor) + { + // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template + LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "Illegal in-place division of unit types."); + } + + template + LL_FORCE_INLINE bool operator == (const LLUnit& other) const + { + return mValue == convert(other).value(); + } + + template + LL_FORCE_INLINE bool operator != (const LLUnit& other) const + { + return mValue != convert(other).value(); + } + + template + LL_FORCE_INLINE bool operator < (const LLUnit& other) const + { + return mValue < convert(other).value(); + } + + template + LL_FORCE_INLINE bool operator <= (const LLUnit& other) const + { + return mValue <= convert(other).value(); + } + + template + LL_FORCE_INLINE bool operator > (const LLUnit& other) const + { + return mValue > convert(other).value(); + } + + template + LL_FORCE_INLINE bool operator >= (const LLUnit& other) const + { + return mValue >= convert(other).value(); + } + +protected: + storage_t mValue; +}; + +template +std::ostream& operator <<(std::ostream& s, const LLUnit& unit) +{ + s << unit.value() << UNITS::getUnitLabel(); + return s; +} + +template +std::istream& operator >>(std::istream& s, LLUnit& unit) +{ + STORAGE_TYPE val; + s >> val; + unit.value(val); + return s; +} + +template +struct LLUnitImplicit : public LLUnit +{ + typedef LLUnitImplicit self_t; + typedef typename LLUnit::storage_t storage_t; + typedef LLUnit base_t; + + LL_FORCE_INLINE LLUnitImplicit(storage_t value = storage_t()) + : base_t(value) + {} + + template + LL_FORCE_INLINE LLUnitImplicit(LLUnit other) + : base_t(other) + {} + + // unlike LLUnit, LLUnitImplicit is *implicitly* convertable to a POD value (F32, S32, etc) + // this allows for interoperability with legacy code + LL_FORCE_INLINE operator storage_t() const + { + return base_t::value(); + } + + using base_t::operator +=; + LL_FORCE_INLINE void operator += (storage_t value) + { + base_t::mValue += value; + } + + // this overload exists to explicitly catch use of another implicit unit + // without ambiguity between conversion to storage_t vs conversion to base_t + template + LL_FORCE_INLINE void operator += (LLUnitImplicit other) + { + base_t::mValue += base_t::convert(other).value(); + } + + using base_t::operator -=; + LL_FORCE_INLINE void operator -= (storage_t value) + { + base_t::mValue -= value; + } + + // this overload exists to explicitly catch use of another implicit unit + // without ambiguity between conversion to storage_t vs conversion to base_t + template + LL_FORCE_INLINE void operator -= (LLUnitImplicit other) + { + base_t::mValue -= base_t::convert(other).value(); + } + + template + LL_FORCE_INLINE bool operator == (LLUnit other) const + { + return base_t::mValue == base_t::convert(other).value(); + } + + template + LL_FORCE_INLINE bool operator == (LLUnitImplicit other) const + { + return base_t::mValue == base_t::convert(other).value(); + } + + template + LL_FORCE_INLINE bool operator == (STORAGE_T other) const + { + return base_t::mValue == other; + } + + template + LL_FORCE_INLINE bool operator != (LLUnit other) const + { + return base_t::mValue != convert(other).value(); + } + + template + LL_FORCE_INLINE bool operator != (LLUnitImplicit other) const + { + return base_t::mValue != base_t::convert(other).value(); + } + + template + LL_FORCE_INLINE bool operator != (STORAGE_T other) const + { + return base_t::mValue != other; + } + + template + LL_FORCE_INLINE bool operator < (LLUnit other) const + { + return base_t::mValue < base_t::convert(other).value(); + } + + template + LL_FORCE_INLINE bool operator < (LLUnitImplicit other) const + { + return base_t::mValue < base_t::convert(other).value(); + } + + template + LL_FORCE_INLINE bool operator < (STORAGE_T other) const + { + return base_t::mValue < other; + } + + template + LL_FORCE_INLINE bool operator <= (LLUnit other) const + { + return base_t::mValue <= base_t::convert(other).value(); + } + + template + LL_FORCE_INLINE bool operator <= (LLUnitImplicit other) const + { + return base_t::mValue <= base_t::convert(other).value(); + } + + template + LL_FORCE_INLINE bool operator <= (STORAGE_T other) const + { + return base_t::mValue <= other; + } + + template + LL_FORCE_INLINE bool operator > (LLUnit other) const + { + return base_t::mValue > base_t::convert(other).value(); + } + + template + LL_FORCE_INLINE bool operator > (LLUnitImplicit other) const + { + return base_t::mValue > base_t::convert(other).value(); + } + + template + LL_FORCE_INLINE bool operator > (STORAGE_T other) const + { + return base_t::mValue > other; + } + + template + LL_FORCE_INLINE bool operator >= (LLUnit other) const + { + return base_t::mValue >= base_t::convert(other).value(); + } + + template + LL_FORCE_INLINE bool operator >= (LLUnitImplicit other) const + { + return base_t::mValue >= base_t::convert(other).value(); + } + + template + LL_FORCE_INLINE bool operator >= (STORAGE_T other) const + { + return base_t::mValue >= other; + } +}; + +template +std::ostream& operator <<(std::ostream& s, const LLUnitImplicit& unit) +{ + s << unit.value() << UNITS::getUnitLabel(); + return s; +} + +template +std::istream& operator >>(std::istream& s, LLUnitImplicit& unit) +{ + STORAGE_TYPE val; + s >> val; + unit = val; + return s; +} + +template +LL_FORCE_INLINE S2 ll_convert_units(LLUnit in, LLUnit& out) +{ + S2 divisor(1); + + LL_STATIC_ASSERT((LLIsSameType::value + || !LLIsSameType::value + || !LLIsSameType::value), + "conversion requires compatible units"); + + if (LLIsSameType::value) + { + // T1 and T2 same type, just assign + out.value((S2)in.value()); + } + else if (T1::sLevel > T2::sLevel) + { + // reduce T1 + LLUnit new_in; + divisor *= (S2)ll_convert_units(in, new_in); + divisor *= (S2)ll_convert_units(new_in, out); + } + else + { + // reduce T2 + LLUnit new_out; + divisor *= (S2)ll_convert_units(in, new_out); + divisor *= (S2)ll_convert_units(new_out, out); + } + return divisor; +} + +template +struct LLStorageType +{ + typedef T type_t; +}; + +template +struct LLStorageType > +{ + typedef STORAGE_TYPE type_t; +}; + +// all of these operators need to perform type promotion on the storage type of the units, so they +// cannot be expressed as operations on identical types with implicit unit conversion +// e.g. typeof(S32Bytes(x) + F32Megabytes(y)) <==> F32Bytes + +// +// operator + +// +template +LL_FORCE_INLINE LLUnit::type_t, UNITS1> operator + (LLUnit first, LLUnit second) +{ + LLUnit::type_t, UNITS1> result(first); + result += second; + return result; +} + +template +LLUnit operator + (LLUnit first, UNITLESS second) +{ + LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "operator + requires compatible unit types"); + return LLUnit(0); +} + +template +LLUnit operator + (UNITLESS first, LLUnit second) +{ + LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "operator + requires compatible unit types"); + return LLUnit(0); +} + +template +LL_FORCE_INLINE LLUnitImplicit::type_t, UNITS1> operator + (LLUnitImplicit first, LLUnitImplicit second) +{ + LLUnitImplicit::type_t, UNITS1> result(first); + result += second; + return result; +} + +template +LL_FORCE_INLINE LLUnitImplicit::type_t, UNITS1> operator + (LLUnit first, LLUnitImplicit second) +{ + LLUnitImplicit::type_t, UNITS1> result(first); + result += second; + return result; +} + +template +LL_FORCE_INLINE LLUnitImplicit::type_t, UNITS1> operator + (LLUnitImplicit first, LLUnit second) +{ + LLUnitImplicit::type_t, UNITS1> result(first); + result += LLUnitImplicit(second); + return result; +} + +template +LL_FORCE_INLINE LLUnitImplicit::type_t>::type_t, UNITS> operator + (LLUnitImplicit first, UNITLESS_TYPE second) +{ + LLUnitImplicit::type_t>::type_t, UNITS> result(first); + result += second; + return result; +} + +template +LL_FORCE_INLINE LLUnitImplicit::type_t, STORAGE_TYPE>:: + type_t, UNITS> operator + (UNITLESS_TYPE first, LLUnitImplicit second) +{ + LLUnitImplicit::type_t, STORAGE_TYPE>::type_t, UNITS> result(first); + result += second; + return result; +} + +// +// operator - +// +template +LL_FORCE_INLINE LLUnit::type_t, UNITS1> operator - (LLUnit first, LLUnit second) +{ + LLUnit::type_t, UNITS1> result(first); + result -= second; + return result; +} + +template +LLUnit operator - (LLUnit first, UNITLESS second) +{ + LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "operator - requires compatible unit types"); + return LLUnit(0); +} + +template +LLUnit operator - (UNITLESS first, LLUnit second) +{ + LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "operator - requires compatible unit types"); + return LLUnit(0); +} + +template +LL_FORCE_INLINE LLUnitImplicit::type_t, UNITS1> operator - (LLUnitImplicit first, LLUnitImplicit second) +{ + LLUnitImplicit::type_t, UNITS1> result(first); + result -= second; + return result; +} + +template +LL_FORCE_INLINE LLUnitImplicit::type_t, UNITS1> operator - (LLUnit first, LLUnitImplicit second) +{ + LLUnitImplicit::type_t, UNITS1> result(first); + result -= second; + return result; +} + +template +LL_FORCE_INLINE LLUnitImplicit::type_t, UNITS1> operator - (LLUnitImplicit first, LLUnit second) +{ + LLUnitImplicit::type_t, UNITS1> result(first); + result -= LLUnitImplicit(second); + return result; +} + +template +LL_FORCE_INLINE LLUnitImplicit::type_t>::type_t, UNITS> operator - (LLUnitImplicit first, UNITLESS_TYPE second) +{ + LLUnitImplicit::type_t>::type_t, UNITS> result(first); + result -= second; + return result; +} + +template +LL_FORCE_INLINE LLUnitImplicit::type_t, STORAGE_TYPE>::type_t, UNITS> operator - (UNITLESS_TYPE first, LLUnitImplicit second) +{ + LLUnitImplicit::type_t, STORAGE_TYPE>::type_t, UNITS> result(first); + result -= second; + return result; +} + +// +// operator * +// +template +LLUnit operator * (LLUnit, LLUnit) +{ + // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template + LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE1, "multiplication of unit types results in new unit type - not supported."); + return LLUnit(); +} + +template +LL_FORCE_INLINE LLUnit::type_t>::type_t, UNITS> operator * (LLUnit first, UNITLESS_TYPE second) +{ + return LLUnit::type_t>::type_t, UNITS>(first.value() * second); +} + +template +LL_FORCE_INLINE LLUnit::type_t, STORAGE_TYPE>::type_t, UNITS> operator * (UNITLESS_TYPE first, LLUnit second) +{ + return LLUnit::type_t, STORAGE_TYPE>::type_t, UNITS>(first * second.value()); +} + +template +LLUnitImplicit operator * (LLUnitImplicit, LLUnitImplicit) +{ + // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template + LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE1, "multiplication of unit types results in new unit type - not supported."); + return LLUnitImplicit(); +} + +template +LL_FORCE_INLINE LLUnitImplicit::type_t>::type_t, UNITS> operator * (LLUnitImplicit first, UNITLESS_TYPE second) +{ + return LLUnitImplicit::type_t, UNITS>(first.value() * second); +} + +template +LL_FORCE_INLINE LLUnitImplicit::type_t, STORAGE_TYPE>::type_t, UNITS> operator * (UNITLESS_TYPE first, LLUnitImplicit second) +{ + return LLUnitImplicit::type_t, STORAGE_TYPE>::type_t, UNITS>(first * second.value()); +} + + +// +// operator / +// + +template +LL_FORCE_INLINE LLUnit::type_t>::type_t, UNITS> operator / (LLUnit first, UNITLESS_TYPE second) +{ + return LLUnit::type_t>::type_t, UNITS>(first.value() / second); +} + +template +LL_FORCE_INLINE typename LLResultTypeDivide::type_t operator / (LLUnit first, LLUnit second) +{ + return first.value() / first.convert(second).value(); +} + +template +LL_FORCE_INLINE LLUnitImplicit::type_t>::type_t, UNITS> operator / (LLUnitImplicit first, UNITLESS_TYPE second) +{ + return LLUnitImplicit::type_t>::type_t, UNITS>(first.value() / second); +} + +template +LL_FORCE_INLINE typename LLResultTypeDivide::type_t operator / (LLUnitImplicit first, LLUnitImplicit second) +{ + return (typename LLResultTypeDivide::type_t)(first.value() / first.convert(second).value()); +} + +template +LL_FORCE_INLINE typename LLResultTypeDivide::type_t operator / (LLUnit first, LLUnitImplicit second) +{ + return (typename LLResultTypeDivide::type_t)(first.value() / first.convert(second).value()); +} + +template +LL_FORCE_INLINE typename LLResultTypeDivide::type_t operator / (LLUnitImplicit first, LLUnit second) +{ + return (typename LLResultTypeDivide::type_t)(first.value() / first.convert(second).value()); +} + +template +struct LLGetUnitLabel +{ + static const char* getUnitLabel() { return ""; } +}; + +template +struct LLGetUnitLabel > +{ + static const char* getUnitLabel() { return T::getUnitLabel(); } +}; + +template +struct LLUnitLinearOps +{ + typedef LLUnitLinearOps self_t; + + LLUnitLinearOps(T val) + : mValue(val), + mDivisor(1) + {} + + template + self_t operator * (OTHER_T other) + { + return mValue * other; + } + + template + self_t operator / (OTHER_T other) + { + mDivisor *= other; + return *this; + } + + template + self_t operator + (OTHER_T other) + { + mValue += other * mDivisor; + return *this; + } + + template + self_t operator - (OTHER_T other) + { + mValue -= other * mDivisor; + return *this; + } + + T mValue; + T mDivisor; +}; + +template +struct LLUnitInverseLinearOps +{ + typedef LLUnitInverseLinearOps self_t; + + LLUnitInverseLinearOps(T val) + : mValue(val), + mDivisor(1), + mMultiplicand(1) + {} + + template + self_t operator * (OTHER_T other) + { + mDivisor *= other; + return *this; + } + + template + self_t operator / (OTHER_T other) + { + mValue *= other; + mMultiplicand *= other; + return *this; + } + + template + self_t operator + (OTHER_T other) + { + mValue -= other * mMultiplicand; + return *this; + } + + template + self_t operator - (OTHER_T other) + { + mValue += other * mMultiplicand; + return *this; + } + + T mValue; + T mDivisor; + T mMultiplicand; +}; + +#define LL_DECLARE_BASE_UNIT(base_unit_name, unit_label) \ +struct base_unit_name \ +{ \ + static const int sLevel = 0; \ + typedef base_unit_name base_unit_t; \ + static const char* getUnitLabel() { return unit_label; } \ + template \ + static LLUnit fromValue(T value) { return LLUnit(value); } \ + template \ + static LLUnit fromValue(LLUnit value) \ + { return LLUnit(value); } \ +} + + +#define LL_DECLARE_DERIVED_UNIT(unit_name, unit_label, base_unit_name, conversion_operation) \ +struct unit_name \ +{ \ + static const int sLevel = base_unit_name::sLevel + 1; \ + typedef base_unit_name base_unit_t; \ + static const char* getUnitLabel() { return unit_label; } \ + template \ + static LLUnit fromValue(T value) { return LLUnit(value); } \ + template \ + static LLUnit fromValue(LLUnit value) \ + { return LLUnit(value); } \ +}; \ + \ +template \ +LL_FORCE_INLINE S2 ll_convert_units(LLUnit in, LLUnit& out) \ +{ \ + typedef typename LLResultTypePromote::type_t result_storage_t; \ + LLUnitInverseLinearOps result = \ + LLUnitInverseLinearOps(in.value()) conversion_operation; \ + out = LLUnit((S2)result.mValue); \ + return result.mDivisor; \ +} \ + \ +template \ +LL_FORCE_INLINE S2 ll_convert_units(LLUnit in, LLUnit& out) \ +{ \ + typedef typename LLResultTypePromote::type_t result_storage_t; \ + LLUnitLinearOps result = \ + LLUnitLinearOps(in.value()) conversion_operation; \ + out = LLUnit((S2)result.mValue); \ + return result.mDivisor; \ +} + +#define LL_DECLARE_UNIT_TYPEDEFS(ns, unit_name) \ + typedef LLUnit F32##unit_name; \ + typedef LLUnitImplicit F32##unit_name##Implicit;\ + typedef LLUnit F64##unit_name; \ + typedef LLUnitImplicit F64##unit_name##Implicit;\ + typedef LLUnit S32##unit_name; \ + typedef LLUnitImplicit S32##unit_name##Implicit;\ + typedef LLUnit S64##unit_name; \ + typedef LLUnitImplicit S64##unit_name##Implicit;\ + typedef LLUnit U32##unit_name; \ + typedef LLUnitImplicit U32##unit_name##Implicit;\ + typedef LLUnit U64##unit_name; \ + typedef LLUnitImplicit U64##unit_name##Implicit + +#endif //LL_UNITTYPE_H diff --git a/indra/llcommon/lluri.cpp b/indra/llcommon/lluri.cpp index 33a5dd2a06..5f5a67a885 100644 --- a/indra/llcommon/lluri.cpp +++ b/indra/llcommon/lluri.cpp @@ -1,3 +1,5 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com /** * @file lluri.cpp * @author Phoenix @@ -40,7 +42,8 @@ #include #include -void encode_character(std::ostream& ostr, std::string::value_type val) +// static +void LLURI::encodeCharacter(std::ostream& ostr, std::string::value_type val) { ostr << "%" @@ -95,7 +98,7 @@ std::string LLURI::escape( } else { - encode_character(ostr, c); + encodeCharacter(ostr, c); } } } @@ -106,7 +109,7 @@ std::string LLURI::escape( c = *it; if(allowed.find(c) == std::string::npos) { - encode_character(ostr, c); + encodeCharacter(ostr, c); } else { @@ -129,11 +132,30 @@ std::string LLURI::unescape(const std::string& str) { ++it; if(it == end) break; - U8 c = hex_as_nybble(*it++); - c = c << 4; - if (it == end) break; - c |= hex_as_nybble(*it); - ostr.put((char)c); + + if(is_char_hex(*it)) + { + U8 c = hex_as_nybble(*it++); + + c = c << 4; + if (it == end) break; + + if(is_char_hex(*it)) + { + c |= hex_as_nybble(*it); + ostr.put((char)c); + } + else + { + ostr.put((char)c); + ostr.put(*it); + } + } + else + { + ostr.put('%'); + ostr.put(*it); + } } else { @@ -169,11 +191,10 @@ namespace { return LLURI::escape(s, unreserved() + ":@!$'()*+,="); } // sub_delims - "&;" + ":@" } -// *TODO: Consider using curl. After http textures gets merged everywhere. // static std::string LLURI::escape(const std::string& str) { - static std::string default_allowed(unreserved() + ":@!$'()*+,=/?&#;"); + static std::string default_allowed = unreserved(); static bool initialized = false; if(!initialized) { @@ -191,10 +212,9 @@ LLURI::LLURI(const std::string& escaped_str) { std::string::size_type delim_pos; delim_pos = escaped_str.find(':'); - std::string temp; if (delim_pos == std::string::npos) { - mScheme = ""; + mScheme.clear(); mEscapedOpaque = escaped_str; } else @@ -229,7 +249,8 @@ void LLURI::parseAuthorityAndPathUsingOpaque() { if (mScheme == "http" || mScheme == "https" || mScheme == "ftp" || mScheme == "secondlife" || - mScheme == "x-grid-location-info") + mScheme == "x-grid-info" || + mScheme == "x-grid-location-info") // legacy { if (mEscapedOpaque.substr(0,2) != "//") { @@ -244,7 +265,7 @@ void LLURI::parseAuthorityAndPathUsingOpaque() delim_pos2 == std::string::npos) { mEscapedAuthority = mEscapedOpaque.substr(2); - mEscapedPath = ""; + mEscapedPath.clear(); } // path exist, no query else if (delim_pos2 == std::string::npos) @@ -341,7 +362,7 @@ LLURI LLURI::buildHTTP(const std::string& prefix, it != path.endArray(); ++it) { - lldebugs << "PATH: inserting " << it->asString() << llendl; + LL_DEBUGS() << "PATH: inserting " << it->asString() << LL_ENDL; result.mEscapedPath += "/" + escapePathComponent(it->asString()); } } @@ -381,8 +402,8 @@ LLURI LLURI::buildHTTP(const std::string& prefix, } else { - llwarns << "Valid path arguments to buildHTTP are array, string, or undef, you passed type" - << path.type() << llendl; + LL_WARNS() << "Valid path arguments to buildHTTP are array, string, or undef, you passed type" + << path.type() << LL_ENDL; } result.mEscapedOpaque = "//" + result.mEscapedAuthority + result.mEscapedPath; @@ -402,6 +423,15 @@ LLURI LLURI::buildHTTP(const std::string& prefix, return uri; } +// static +LLURI LLURI::buildHTTP(const std::string& scheme, + const std::string& prefix, + const LLSD& path, + const LLSD& query) +{ + return buildHTTP(llformat("%s://%s", scheme.c_str(), prefix.c_str()), path, query); +} + // static LLURI LLURI::buildHTTP(const std::string& host, const U32& port, @@ -456,7 +486,7 @@ namespace { std::string::size_type start_pos = authority.find('@'); if (start_pos == std::string::npos) { - user = ""; + user.clear(); start_pos = 0; } else @@ -469,7 +499,7 @@ namespace { if (end_pos == std::string::npos) { host = authority.substr(start_pos); - port = ""; + port.clear(); } else { @@ -486,6 +516,14 @@ std::string LLURI::hostName() const return unescape(host); } +std::string LLURI::hostNameAndPort() const +{ + std::string user, host, port; + findAuthorityParts(mEscapedAuthority, user, host, port); + return port.empty() ? unescape(host) : unescape(host + ":" + port); +} + + std::string LLURI::userName() const { std::string user, userPass, host, port; @@ -529,7 +567,7 @@ U16 LLURI::hostPort() const return 21; return 0; } - return atoi(port.c_str()); + return static_cast(std::stoi(port)); } std::string LLURI::path() const @@ -566,7 +604,7 @@ LLSD LLURI::queryMap() const // static LLSD LLURI::queryMap(std::string escaped_query_string) { - lldebugs << "LLURI::queryMap query params: " << escaped_query_string << llendl; + LL_DEBUGS() << "LLURI::queryMap query params: " << escaped_query_string << LL_ENDL; LLSD result = LLSD::emptyArray(); while(!escaped_query_string.empty()) @@ -582,7 +620,7 @@ LLSD LLURI::queryMap(std::string escaped_query_string) else { tuple = escaped_query_string; - escaped_query_string = ""; + escaped_query_string .clear(); } if (tuple.empty()) continue; @@ -592,12 +630,12 @@ LLSD LLURI::queryMap(std::string escaped_query_string) { std::string key = unescape(tuple.substr(0,key_end)); std::string value = unescape(tuple.substr(key_end+1)); - lldebugs << "inserting key " << key << " value " << value << llendl; + LL_DEBUGS() << "inserting key " << key << " value " << value << LL_ENDL; result[key] = value; } else { - lldebugs << "inserting key " << unescape(tuple) << " value true" << llendl; + LL_DEBUGS() << "inserting key " << unescape(tuple) << " value true" << LL_ENDL; result[unescape(tuple)] = true; } } diff --git a/indra/llcommon/lluri.h b/indra/llcommon/lluri.h index 57bbedf422..591635a29d 100644 --- a/indra/llcommon/lluri.h +++ b/indra/llcommon/lluri.h @@ -4,31 +4,25 @@ * @date 2006-02-05 * @brief Declaration of the URI class. * - * $LicenseInfo:firstyear=2006&license=viewergpl$ - * - * Copyright (c) 2006-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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$ */ @@ -38,7 +32,6 @@ #include class LLSD; -class LLUUID; class LLApp; /** @@ -72,6 +65,13 @@ class LL_COMMON_API LLURI const std::string& prefix, const LLSD& path, const LLSD& query); + + static LLURI buildHTTP( + const std::string& scheme, + const std::string& prefix, + const LLSD& path, + const LLSD& query); + ///< prefix is either a full URL prefix of the form /// "http://example.com:8080", or it can be simply a host and /// optional port like "example.com" or "example.com:8080", in @@ -99,20 +99,21 @@ class LL_COMMON_API LLURI std::string scheme() const; ///< ex.: "http", note lack of colon std::string opaque() const; ///< everything after the colon - // for schemes that follow path like syntax (http, https, ftp) - std::string authority() const; // ex.: "host.com:80" - std::string hostName() const; // ex.: "host.com" - std::string userName() const; - std::string password() const; - U16 hostPort() const; // ex.: 80, will include implicit port - BOOL defaultPort() const; // true if port is default for scheme - const std::string& escapedPath() const { return mEscapedPath; } - std::string path() const; // ex.: "/abc/def", includes leading slash - LLSD pathArray() const; // above decoded into an array of strings - std::string query() const; // ex.: "x=34", section after "?" - const std::string& escapedQuery() const { return mEscapedQuery; } - LLSD queryMap() const; // above decoded into a map - static LLSD queryMap(std::string escaped_query_string); + // for schemes that follow path like syntax (http, https, ftp) + std::string authority() const; // ex.: "user:pass@host.com:80" + std::string hostName() const; // ex.: "host.com" + std::string hostNameAndPort() const; // ex.: "host.com:80" + std::string userName() const; + std::string password() const; + U16 hostPort() const; // ex.: 80, will include implicit port + BOOL defaultPort() const; // true if port is default for scheme + const std::string& escapedPath() const { return mEscapedPath; } + std::string path() const; // ex.: "/abc/def", includes leading slash + LLSD pathArray() const; // above decoded into an array of strings + std::string query() const; // ex.: "x=34", section after "?" + const std::string& escapedQuery() const { return mEscapedQuery; } + LLSD queryMap() const; // above decoded into a map + static LLSD queryMap(std::string escaped_query_string); /** * @brief given a name value map, return a serialized query string. @@ -127,27 +128,24 @@ class LL_COMMON_API LLURI /** @name Escaping Utilities */ //@{ /** - * @brief Escape a raw url with a reasonable set of allowed characters. + * @brief 'Escape' symbol into stream * - * The default set was chosen to match HTTP urls and general - * guidelines for naming resources. Passing in a raw url does not - * produce well defined results because you really need to know - * which segments are path parts because path parts are supposed - * to be escaped individually. The default set chosen is: + * @param ostr Output stream. + * @param val Symbol to encode. + */ + static void encodeCharacter(std::ostream& ostr, std::string::value_type val); + + /** + * @brief Escape the string passed except for unreserved * * ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz * 0123456789 * -._~ - * :@!$'()*+,=/?&#; * - * *NOTE: This API is basically broken because it does not - * allow you to specify significant path characters. For example, - * if the filename actually contained a /, then you cannot use - * this function to generate the serialized url for that - * resource. + * @see http://www.ietf.org/rfc/rfc1738.txt * * @param str The raw URI to escape. - * @return Returns the escaped uri or an empty string. + * @return Returns the rfc 1738 escaped uri or an empty string. */ static std::string escape(const std::string& str); diff --git a/indra/llcommon/lluriparser.cpp b/indra/llcommon/lluriparser.cpp new file mode 100644 index 0000000000..e32d9f5c0e --- /dev/null +++ b/indra/llcommon/lluriparser.cpp @@ -0,0 +1,266 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +/** + * @file lluriparser.cpp + * @author Protey + * @date 2014-10-07 + * @brief Implementation of the LLUriParser class. + * + * $LicenseInfo:firstyear=2014&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2014, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "lluriparser.h" + +LLUriParser::LLUriParser(const std::string& u) +: mRes(0) +, mTmpScheme(false) +, mNormalizedTmp(false) +{ + mState.uri = &mUri; + + if (u.find("://") == std::string::npos) + { + mNormalizedUri = "http://"; + mTmpScheme = true; + } + + mNormalizedUri += u; + + mRes = parse(); +} + +LLUriParser::~LLUriParser() +{ + uriFreeUriMembersA(&mUri); +} + +S32 LLUriParser::parse() +{ + mRes = uriParseUriA(&mState, mNormalizedUri.c_str()); + return mRes; +} + +const char * LLUriParser::scheme() const +{ + return mScheme.c_str(); +} + +void LLUriParser::scheme(const std::string& s) +{ + mTmpScheme = !s.size(); + mScheme = s; +} + +const char * LLUriParser::port() const +{ + return mPort.c_str(); +} + +void LLUriParser::port(const std::string& s) +{ + mPort = s; +} + +const char * LLUriParser::host() const +{ + return mHost.c_str(); +} + +void LLUriParser::host(const std::string& s) +{ + mHost = s; +} + +const char * LLUriParser::path() const +{ + return mPath.c_str(); +} + +void LLUriParser::path(const std::string& s) +{ + mPath = s; +} + +const char * LLUriParser::query() const +{ + return mQuery.c_str(); +} + +void LLUriParser::query(const std::string& s) +{ + mQuery = s; +} + +const char * LLUriParser::fragment() const +{ + return mFragment.c_str(); +} + +void LLUriParser::fragment(const std::string& s) +{ + mFragment = s; +} + +void LLUriParser::textRangeToString(UriTextRangeA& textRange, std::string& str) +{ + if (textRange.first != nullptr && textRange.afterLast != nullptr && textRange.first < textRange.afterLast) + { + const ptrdiff_t len = textRange.afterLast - textRange.first; + str.assign(textRange.first, static_cast(len)); + } + else + { + str = LLStringUtil::null; + } +} + +void LLUriParser::extractParts() +{ + if (mTmpScheme || mNormalizedTmp) + { + mScheme.clear(); + } + else + { + textRangeToString(mUri.scheme, mScheme); + } + + textRangeToString(mUri.hostText, mHost); + textRangeToString(mUri.portText, mPort); + textRangeToString(mUri.query, mQuery); + textRangeToString(mUri.fragment, mFragment); + + UriPathSegmentA * pathHead = mUri.pathHead; + while (pathHead) + { + std::string partOfPath; + textRangeToString(pathHead->text, partOfPath); + + mPath += '/'; + mPath += partOfPath; + + pathHead = pathHead->next; + } +} + +S32 LLUriParser::normalize() +{ + mNormalizedTmp = mTmpScheme; + if (!mRes) + { + mRes = uriNormalizeSyntaxExA(&mUri, URI_NORMALIZE_SCHEME | URI_NORMALIZE_HOST); + + if (!mRes) + { + S32 chars_required; + mRes = uriToStringCharsRequiredA(&mUri, &chars_required); + + if (!mRes) + { + chars_required++; + std::vector label_buf(chars_required); + mRes = uriToStringA(&label_buf[0], &mUri, chars_required, nullptr); + + if (!mRes) + { + mNormalizedUri = &label_buf[mTmpScheme ? 7 : 0]; + mTmpScheme = false; + } + } + } + } + + if(mTmpScheme) + { + mNormalizedUri = mNormalizedUri.substr(7); + mTmpScheme = false; + } + + return mRes; +} + +void LLUriParser::glue(std::string& uri) const +{ + std::string first_part; + glueFirst(first_part); + + std::string second_part; + glueSecond(second_part); + + uri = first_part + second_part; +} + +void LLUriParser::glueFirst(std::string& uri, bool use_scheme) const +{ + if (use_scheme && mScheme.size()) + { + uri = mScheme; + uri += "://"; + } + else + { + uri.clear(); + } + + uri += mHost; +} + +void LLUriParser::glueSecond(std::string& uri) const +{ + if (mPort.size()) + { + uri = ':'; + uri += mPort; + } + else + { + uri.clear(); + } + + uri += mPath; + + if (mQuery.size()) + { + uri += '?'; + uri += mQuery; + } + + if (mFragment.size()) + { + uri += '#'; + uri += mFragment; + } +} + +bool LLUriParser::test() const +{ + std::string uri; + glue(uri); + + return uri == mNormalizedUri; +} + +const char * LLUriParser::normalizedUri() const +{ + return mNormalizedUri.c_str(); +} diff --git a/indra/llcommon/lluriparser.h b/indra/llcommon/lluriparser.h new file mode 100644 index 0000000000..773d4189f5 --- /dev/null +++ b/indra/llcommon/lluriparser.h @@ -0,0 +1,87 @@ +/** + * @file lluriparser.h + * @author Protey + * @date 20146-10-07 + * @brief Declaration of the UriParser class. + * + * $LicenseInfo:firstyear=2014&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2014, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLURIPARSER_H +#define LL_LLURIPARSER_H + +#include +#include + +class LL_COMMON_API LLUriParser +{ +public: + LLUriParser(const std::string& u); + ~LLUriParser(); + + const char * scheme() const; + void scheme (const std::string& s); + + const char * port() const; + void port (const std::string& s); + + const char * host() const; + void host (const std::string& s); + + const char * path() const; + void path (const std::string& s); + + const char * query() const; + void query (const std::string& s); + + const char * fragment() const; + void fragment (const std::string& s); + + const char * normalizedUri() const; + + void extractParts(); + void glue(std::string& uri) const; + void glueFirst(std::string& uri, bool use_scheme = true) const; + void glueSecond(std::string& uri) const; + bool test() const; + S32 normalize(); + +private: + S32 parse(); + void textRangeToString(UriTextRangeA& textRange, std::string& str); + std::string mScheme; + std::string mHost; + std::string mPort; + std::string mPath; + std::string mQuery; + std::string mFragment; + std::string mNormalizedUri; + + UriParserStateA mState; + UriUriA mUri; + + S32 mRes; + bool mTmpScheme; + bool mNormalizedTmp; +}; + +#endif // LL_LLURIPARSER_H diff --git a/indra/llcommon/lluuid.cpp b/indra/llcommon/lluuid.cpp index 0182a370d5..5d80c19051 100644 --- a/indra/llcommon/lluuid.cpp +++ b/indra/llcommon/lluuid.cpp @@ -27,9 +27,8 @@ // We can't use WIN32_LEAN_AND_MEAN here, needs lots of includes. #if LL_WINDOWS -#undef WIN32_LEAN_AND_MEAN -#include -#include +#include "llwin32headers.h" +#include "nb30.h" #endif #include "lldefs.h" @@ -215,7 +214,7 @@ BOOL LLUUID::set(const std::string& in_string, BOOL emit) { if(emit) { - llwarns << "Warning! Using broken UUID string format" << llendl; + LL_WARNS() << "Warning! Using broken UUID string format" << LL_ENDL; } broken_format = TRUE; } @@ -225,7 +224,7 @@ BOOL LLUUID::set(const std::string& in_string, BOOL emit) if(emit) { //don't spam the logs because a resident can't spell. - llwarns << "Bad UUID string: " << in_string << llendl; + LL_WARNS() << "Bad UUID string: " << in_string << LL_ENDL; } setNull(); return FALSE; @@ -264,7 +263,7 @@ BOOL LLUUID::set(const std::string& in_string, BOOL emit) { if(emit) { - llwarns << "Invalid UUID string character" << llendl; + LL_WARNS() << "Invalid UUID string character" << LL_ENDL; } setNull(); return FALSE; @@ -289,7 +288,7 @@ BOOL LLUUID::set(const std::string& in_string, BOOL emit) { if(emit) { - llwarns << "Invalid UUID string character" << llendl; + LL_WARNS() << "Invalid UUID string character" << LL_ENDL; } setNull(); return FALSE; @@ -716,7 +715,7 @@ void LLUUID::getCurrentTime(uuid_time_t *timestamp) getSystemTime(&time_last); uuids_this_tick = uuids_per_tick; init = TRUE; - mMutex = new LLMutex; + mMutex = new LLMutex(); } uuid_time_t time_now = {0,0}; diff --git a/indra/llcommon/lluuid.h b/indra/llcommon/lluuid.h index e7b1f525e4..8e5f4e02af 100644 --- a/indra/llcommon/lluuid.h +++ b/indra/llcommon/lluuid.h @@ -28,8 +28,13 @@ #include #include +#include +#include +#include +#include #include "stdtypes.h" #include "llpreprocessor.h" +#include class LLMutex; @@ -53,10 +58,10 @@ class LL_COMMON_API LLUUID LLUUID(); explicit LLUUID(const char *in_string); // Convert from string. explicit LLUUID(const std::string& in_string); // Convert from string. - LLUUID(const LLUUID &in); - LLUUID &operator=(const LLUUID &rhs); + LLUUID(const LLUUID &in) = default; + LLUUID &operator=(const LLUUID &rhs) = default; - ~LLUUID(); + ~LLUUID() = default; // // MANIPULATORS @@ -70,7 +75,7 @@ class LL_COMMON_API LLUUID BOOL set(const std::string& in_string, BOOL emit = TRUE); // Convert from string, if emit is FALSE, do not emit warnings void setNull(); // Faster than setting to LLUUID::null. - S32 cmpTime(uuid_time_t *t1, uuid_time_t *t2); + S32 cmpTime(uuid_time_t *t1, uuid_time_t *t2); static void getSystemTime(uuid_time_t *timestamp); void getCurrentTime(uuid_time_t *timestamp); @@ -90,6 +95,11 @@ class LL_COMMON_API LLUUID bool operator<(const LLUUID &rhs) const; bool operator>(const LLUUID &rhs) const; + template + friend H AbslHashValue(H h, const LLUUID& id) { + return H::combine_contiguous(std::move(h), id.mData, UUID_BYTES); + } + // xor functions. Useful since any two random uuids xored together // will yield a determinate third random unique id that can be // used as a key in a single uuid that represents 2. @@ -115,6 +125,19 @@ class LL_COMMON_API LLUUID U16 getCRC16() const; U32 getCRC32() const; + inline size_t hash() const + { + size_t seed = 0; + for (U8 i = 0; i < 4; ++i) + { + seed ^= static_cast(mData[i * 4]) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + seed ^= static_cast(mData[i * 4 + 1]) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + seed ^= static_cast(mData[i * 4 + 2]) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + seed ^= static_cast(mData[i * 4 + 3]) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + } + return seed; + } + static BOOL validate(const std::string& in_string); // Validate that the UUID string is legal. static const LLUUID null; @@ -128,8 +151,6 @@ class LL_COMMON_API LLUUID U8 mData[UUID_BYTES]; }; -typedef std::vector uuid_vec_t; - // Construct inline LLUUID::LLUUID() { @@ -140,38 +161,20 @@ inline LLUUID::LLUUID() // Faster than copying from memory inline void LLUUID::setNull() { - U32 *word = (U32 *)mData; - word[0] = 0; - word[1] = 0; - word[2] = 0; - word[3] = 0; + memset(mData, 0, sizeof(mData)); // } // Compare inline bool LLUUID::operator==(const LLUUID& rhs) const { - U32 *tmp = (U32 *)mData; - U32 *rhstmp = (U32 *)rhs.mData; - // Note: binary & to avoid branching - return - (tmp[0] == rhstmp[0]) & - (tmp[1] == rhstmp[1]) & - (tmp[2] == rhstmp[2]) & - (tmp[3] == rhstmp[3]); + return !memcmp(mData, rhs.mData, sizeof(mData)); // } inline bool LLUUID::operator!=(const LLUUID& rhs) const { - U32 *tmp = (U32 *)mData; - U32 *rhstmp = (U32 *)rhs.mData; - // Note: binary | to avoid branching - return - (tmp[0] != rhstmp[0]) | - (tmp[1] != rhstmp[1]) | - (tmp[2] != rhstmp[2]) | - (tmp[3] != rhstmp[3]); + return !!memcmp(mData, rhs.mData, sizeof(mData)); // } /* @@ -186,49 +189,16 @@ inline LLUUID::operator bool() const inline BOOL LLUUID::notNull() const { - U32 *word = (U32 *)mData; - return (word[0] | word[1] | word[2] | word[3]) > 0; + return !!memcmp(mData, null.mData, sizeof(mData)); // } // Faster than == LLUUID::null because doesn't require // as much memory access. inline BOOL LLUUID::isNull() const { - U32 *word = (U32 *)mData; - // If all bits are zero, return !0 == TRUE - return !(word[0] | word[1] | word[2] | word[3]); -} - -// Copy constructor -inline LLUUID::LLUUID(const LLUUID& rhs) -{ - U32 *tmp = (U32 *)mData; - U32 *rhstmp = (U32 *)rhs.mData; - tmp[0] = rhstmp[0]; - tmp[1] = rhstmp[1]; - tmp[2] = rhstmp[2]; - tmp[3] = rhstmp[3]; + return !memcmp(mData, null.mData, sizeof(mData)); // } -inline LLUUID::~LLUUID() -{ -} - -// Assignment -inline LLUUID& LLUUID::operator=(const LLUUID& rhs) -{ - // No need to check the case where this==&rhs. The branch is slower than the write. - U32 *tmp = (U32 *)mData; - U32 *rhstmp = (U32 *)rhs.mData; - tmp[0] = rhstmp[0]; - tmp[1] = rhstmp[1]; - tmp[2] = rhstmp[2]; - tmp[3] = rhstmp[3]; - - return *this; -} - - inline LLUUID::LLUUID(const char *in_string) { if (!in_string || in_string[0] == 0) @@ -297,13 +267,27 @@ inline U16 LLUUID::getCRC16() const inline U32 LLUUID::getCRC32() const { - U32 *tmp = (U32*)mData; - return tmp[0] + tmp[1] + tmp[2] + tmp[3]; + // + U32 ret = 0; + for(U32 i = 0;i < 4;++i) + { + ret += (mData[i*4]) | (mData[i*4+1]) << 8 | (mData[i*4+2]) << 16 | (mData[i*4+3]) << 24; + } + return ret; + // } +static_assert(std::is_trivially_copyable::value, "LLUUID must be a trivially copyable type"); -// Helper structure for ordering lluuids in stl containers. -// eg: std::map widget_map; +typedef std::vector uuid_vec_t; +typedef boost::unordered_set uuid_set_t; + +// Helper structure for ordering lluuids in stl containers. eg: +// std::map widget_map; +// +// (isn't this the default behavior anyway? I think we could +// everywhere replace these with uuid_set_t, but someone should +// verify.) struct lluuid_less { bool operator()(const LLUUID& lhs, const LLUUID& rhs) const @@ -314,6 +298,26 @@ struct lluuid_less typedef std::set uuid_list_t; +namespace std { + template <> struct hash + { + size_t operator()(const LLUUID & id) const + { + return absl::Hash{}(id); + } + }; +} + +namespace boost { + template<> struct hash + { + size_t operator()(const LLUUID& id) const + { + return absl::Hash{}(id); + } + }; +} + /* * Sub-classes for keeping transaction IDs and asset IDs * straight. @@ -330,3 +334,5 @@ class LL_COMMON_API LLTransactionID : public LLUUID }; #endif + + diff --git a/indra/llcommon/llversionviewer.h.in b/indra/llcommon/llversionviewer.h.in deleted file mode 100644 index ec1ed2f31f..0000000000 --- a/indra/llcommon/llversionviewer.h.in +++ /dev/null @@ -1,48 +0,0 @@ -/** - * @file llversionviewer.h - * @brief - * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifndef LL_LLVERSIONVIEWER_H -#define LL_LLVERSIONVIEWER_H - -const S32 LL_VERSION_MAJOR = 1; -const S32 LL_VERSION_MINOR = 8; -const S32 LL_VERSION_PATCH = 2; -const S32 LL_VERSION_BUILD = ${vBUILD}; - -const char * const LL_CHANNEL = "${VIEWER_CHANNEL}"; - -#if LL_DARWIN -const char * const LL_VERSION_BUNDLE_ID = "org.singularityviewer.singularity"; -#endif - -#endif - diff --git a/indra/llcommon/llwin32headers.h b/indra/llcommon/llwin32headers.h new file mode 100644 index 0000000000..9d1e40d8cf --- /dev/null +++ b/indra/llcommon/llwin32headers.h @@ -0,0 +1,43 @@ +/** + * @file llwin32headers.h + * @brief sanitized include of windows header files + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLWINDOWS_H +#define LL_LLWINDOWS_H + +#ifdef LL_WINDOWS +#ifndef NOMINMAX +#define NOMINMAX +#endif +#undef WIN32_LEAN_AND_MEAN +#include +#include +#include +// reset to default, which is lean +#define WIN32_LEAN_AND_MEAN +#undef NOMINMAX +#endif + +#endif diff --git a/indra/llcommon/llwin32headerslean.h b/indra/llcommon/llwin32headerslean.h new file mode 100644 index 0000000000..d64c307ccf --- /dev/null +++ b/indra/llcommon/llwin32headerslean.h @@ -0,0 +1,41 @@ +/** + * @file llwin32headerslean.h + * @brief sanitized include of windows header files + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLWINDOWS_H +#define LL_LLWINDOWS_H + +#ifdef LL_WINDOWS +#ifndef NOMINMAX +#define NOMINMAX +#endif +#define WIN32_LEAN_AND_MEAN +#include +#include +#include +#undef NOMINMAX +#endif + +#endif diff --git a/indra/llcommon/llworkerthread.cpp b/indra/llcommon/llworkerthread.cpp index 8106113df9..20b99bdc82 100644 --- a/indra/llcommon/llworkerthread.cpp +++ b/indra/llcommon/llworkerthread.cpp @@ -37,7 +37,7 @@ LLWorkerThread::LLWorkerThread(const std::string& name, bool threaded, bool should_pause) : LLQueuedThread(name, threaded, should_pause) { - mDeleteMutex = new LLMutex; + mDeleteMutex = new LLMutex(); } LLWorkerThread::~LLWorkerThread() @@ -45,8 +45,8 @@ LLWorkerThread::~LLWorkerThread() // Delete any workers in the delete queue (should be safe - had better be!) if (!mDeleteList.empty()) { - llwarns << "Worker Thread: " << mName << " destroyed with " << mDeleteList.size() - << " entries in delete list." << llendl; + LL_WARNS() << "Worker Thread: " << mName << " destroyed with " << mDeleteList.size() + << " entries in delete list." << LL_ENDL; } delete mDeleteMutex; @@ -60,8 +60,8 @@ void LLWorkerThread::clearDeleteList() // Delete any workers in the delete queue (should be safe - had better be!) if (!mDeleteList.empty()) { - llwarns << "Worker Thread: " << mName << " destroyed with " << mDeleteList.size() - << " entries in delete list." << llendl; + LL_WARNS() << "Worker Thread: " << mName << " destroyed with " << mDeleteList.size() + << " entries in delete list." << LL_ENDL; mDeleteMutex->lock(); for (delete_list_t::iterator iter = mDeleteList.begin(); iter != mDeleteList.end(); ++iter) @@ -137,7 +137,7 @@ LLWorkerThread::handle_t LLWorkerThread::addWorkRequest(LLWorkerClass* workercla bool res = addRequest(req); if (!res) { - llerrs << "add called after LLWorkerThread::cleanupClass()" << llendl; + LL_ERRS() << "add called after LLWorkerThread::cleanupClass()" << LL_ENDL; req->deleteRequest(); handle = nullHandle(); } @@ -199,11 +199,12 @@ LLWorkerClass::LLWorkerClass(LLWorkerThread* workerthread, const std::string& na mWorkerClassName(name), mRequestHandle(LLWorkerThread::nullHandle()), mRequestPriority(LLWorkerThread::PRIORITY_NORMAL), + mMutex(), mWorkFlags(0) { if (!mWorkerThread) { - llerrs << "LLWorkerClass() called with NULL workerthread: " << name << llendl; + LL_ERRS() << "LLWorkerClass() called with NULL workerthread: " << name << LL_ENDL; } } @@ -217,13 +218,13 @@ LLWorkerClass::~LLWorkerClass() LLWorkerThread::WorkRequest* workreq = (LLWorkerThread::WorkRequest*)mWorkerThread->getRequest(mRequestHandle); if (!workreq) { - llerrs << "LLWorkerClass destroyed with stale work handle" << llendl; + LL_ERRS() << "LLWorkerClass destroyed with stale work handle" << LL_ENDL; } if (workreq->getStatus() != LLWorkerThread::STATUS_ABORTED && workreq->getStatus() != LLWorkerThread::STATUS_COMPLETE && !(workreq->getFlags() & LLWorkerThread::FLAG_LOCKED)) { - llerrs << "LLWorkerClass destroyed with active worker! Worker Status: " << workreq->getStatus() << llendl; + LL_ERRS() << "LLWorkerClass destroyed with active worker! Worker Status: " << workreq->getStatus() << LL_ENDL; } } } @@ -233,7 +234,7 @@ void LLWorkerClass::setWorkerThread(LLWorkerThread* workerthread) mMutex.lock(); if (mRequestHandle != LLWorkerThread::nullHandle()) { - llerrs << "LLWorkerClass attempt to change WorkerThread with active worker!" << llendl; + LL_ERRS() << "LLWorkerClass attempt to change WorkerThread with active worker!" << LL_ENDL; } mWorkerThread = workerthread; mMutex.unlock(); @@ -293,10 +294,10 @@ void LLWorkerClass::addWork(S32 param, U32 priority) llassert_always(!(mWorkFlags & (WCF_WORKING|WCF_HAVE_WORK))); if (mRequestHandle != LLWorkerThread::nullHandle()) { - llerrs << "LLWorkerClass attempt to add work with active worker!" << llendl; + LL_ERRS() << "LLWorkerClass attempt to add work with active worker!" << LL_ENDL; } #if _DEBUG -// llinfos << "addWork: " << mWorkerClassName << " Param: " << param << llendl; +// LL_INFOS() << "addWork: " << mWorkerClassName << " Param: " << param << LL_ENDL; #endif startWork(param); clearFlags(WCF_WORK_FINISHED|WCF_WORK_ABORTED); @@ -311,7 +312,7 @@ void LLWorkerClass::abortWork(bool autocomplete) #if _DEBUG // LLWorkerThread::WorkRequest* workreq = mWorkerThread->getRequest(mRequestHandle); // if (workreq) -// llinfos << "abortWork: " << mWorkerClassName << " Param: " << workreq->getParam() << llendl; +// LL_INFOS() << "abortWork: " << mWorkerClassName << " Param: " << workreq->getParam() << LL_ENDL; #endif if (mRequestHandle != LLWorkerThread::nullHandle()) { @@ -345,10 +346,14 @@ bool LLWorkerClass::checkWork(bool aborting) } LLQueuedThread::status_t status = workreq->getStatus(); - if (status == LLWorkerThread::STATUS_COMPLETE || status == LLWorkerThread::STATUS_ABORTED) + if (status == LLWorkerThread::STATUS_ABORTED) + { + complete = !(workreq->getFlags() & LLWorkerThread::FLAG_LOCKED); + abort = true; + } + else if (status == LLWorkerThread::STATUS_COMPLETE) { complete = !(workreq->getFlags() & LLWorkerThread::FLAG_LOCKED); - abort = status == LLWorkerThread::STATUS_ABORTED; } else { diff --git a/indra/llcommon/sguuidhash.h b/indra/llcommon/sguuidhash.h deleted file mode 100644 index b6b65aa0a6..0000000000 --- a/indra/llcommon/sguuidhash.h +++ /dev/null @@ -1,36 +0,0 @@ -/* Copyright (C) 2013 Siana Gearz - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * 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 */ - -#ifndef SGUUIDHASH_H -#define SGUUIDHASH_H - -#include "lluuid.h" -#include -#include - -namespace boost { - template<> class hash { - public: - size_t operator()(const LLUUID& id ) const - { - return *reinterpret_cast(id.mData); - } - }; -} - - -#endif diff --git a/indra/llcommon/stdenums.h b/indra/llcommon/stdenums.h index 16a4ee8544..6cb15e68b8 100644 --- a/indra/llcommon/stdenums.h +++ b/indra/llcommon/stdenums.h @@ -118,16 +118,6 @@ enum EAddPosition ADD_BOTTOM }; -enum LLGroupChange -{ - GC_PROPERTIES, - GC_MEMBER_DATA, - GC_ROLE_DATA, - GC_ROLE_MEMBER_DATA, - GC_TITLES, - GC_ALL -}; - //---------------------------------------------------------------------------- // DEPRECATED - create new, more specific files for shared enums/constants //---------------------------------------------------------------------------- diff --git a/indra/llcommon/stdtypes.h b/indra/llcommon/stdtypes.h index af0b4dd4ed..7eef3695e8 100644 --- a/indra/llcommon/stdtypes.h +++ b/indra/llcommon/stdtypes.h @@ -108,8 +108,16 @@ typedef U8 LLPCode; #define LL_ARRAY_SIZE( _kArray ) ( sizeof( (_kArray) ) / sizeof( _kArray[0] ) ) -#if LL_LINUX && __GNUC__ <= 2 -typedef int intptr_t; +#if __GNUG__ && __GNUC__ < 5 +namespace std +{ + template + struct is_trivially_copyable + { + static const bool value = __has_trivial_copy(T); + operator bool() { return value; } + }; +} #endif #endif diff --git a/indra/llcommon/string_table.h b/indra/llcommon/string_table.h deleted file mode 100644 index 176be21e6f..0000000000 --- a/indra/llcommon/string_table.h +++ /dev/null @@ -1,32 +0,0 @@ -/** - * @file string_table.h - * @brief Legacy wrapper header. - * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ -#include "llstringtable.h" diff --git a/indra/llcommon/u64.cpp b/indra/llcommon/u64.cpp index 01fe973a22..fbb1b97a05 100644 --- a/indra/llcommon/u64.cpp +++ b/indra/llcommon/u64.cpp @@ -42,7 +42,7 @@ U64 str_to_U64(const std::string& str) if (!aptr) { - llwarns << "str_to_U64: Bad string to U64 conversion attempt: format\n" << llendl; + LL_WARNS() << "str_to_U64: Bad string to U64 conversion attempt: format\n" << LL_ENDL; } else { diff --git a/indra/llcrashlogger/CMakeLists.txt b/indra/llcrashlogger/CMakeLists.txt deleted file mode 100644 index a20e42a8d1..0000000000 --- a/indra/llcrashlogger/CMakeLists.txt +++ /dev/null @@ -1,36 +0,0 @@ -# -*- cmake -*- - -project(llcrashlogger) - -include(00-Common) -include(LLCommon) -include(LLMath) -include(LLMessage) -include(LLVFS) -include(LLXML) - -include_directories( - ${LLCOMMON_INCLUDE_DIRS} - ${LLMATH_INCLUDE_DIRS} - ${LLMESSAGE_INCLUDE_DIRS} - ${LLVFS_INCLUDE_DIRS} - ${LLXML_INCLUDE_DIRS} - ) - -set(llcrashlogger_SOURCE_FILES - llcrashlogger.cpp - ) - -set(llcrashlogger_HEADER_FILES - CMakeLists.txt - - llcrashlogger.h - ) - -set_source_files_properties(${llcrashlogger_HEADER_FILES} - PROPERTIES HEADER_FILE_ONLY TRUE) - -list(APPEND llcrashlogger_SOURCE_FILES ${llcrashlogger_HEADER_FILES}) - -add_library(llcrashlogger ${llcrashlogger_SOURCE_FILES}) -add_dependencies(llcrashlogger prepare) diff --git a/indra/llcrashlogger/llcrashlogger.cpp b/indra/llcrashlogger/llcrashlogger.cpp deleted file mode 100644 index e072b5c799..0000000000 --- a/indra/llcrashlogger/llcrashlogger.cpp +++ /dev/null @@ -1,425 +0,0 @@ - /** -* @file llcrashlogger.cpp -* @brief Crash logger implementation -* -* $LicenseInfo:firstyear=2003&license=viewergpl$ -* -* Copyright (c) 2003-2009, Linden Research, Inc. -* -* Second Life Viewer Source Code -* The source code in this file ("Source Code") is provided by Linden Lab -* to you under the terms of the GNU General Public License, version 2.0 -* ("GPL"), unless you have obtained a separate licensing agreement -* ("Other License"), formally executed by you and Linden Lab. Terms of -* the GPL can be found in doc/GPL-license.txt in this distribution, or -* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 -* -* There are special exceptions to the terms and conditions of the GPL as -* it is applied to this Source Code. View the full text of the exception -* in the file doc/FLOSS-exception.txt in this software distribution, or -* online at -* http://secondlifegrid.net/programs/open_source/licensing/flossexception -* -* By copying, modifying or distributing this software, you acknowledge -* that you have read and understood your obligations described above, -* and agree to abide by those obligations. -* -* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO -* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, -* COMPLETENESS OR PERFORMANCE. -* $/LicenseInfo$ -*/ - -#include "linden_common.h" - -#include -#include -#include -#include - -#include "llcrashlogger.h" -#include "llstring.h" -#include "indra_constants.h" // CRASH_BEHAVIOR_ASK, CRASH_SETTING_NAME -#include "llerror.h" -#include "lltimer.h" -#include "lldir.h" -#include "llsdserialize.h" -#include "lliopipe.h" -#include "llpumpio.h" -#include "llhttpclient.h" -#include "llsdserialize.h" -#include "llcurl.h" -#include "aistatemachine.h" - -LLPumpIO* gServicePump; -BOOL gBreak = false; -BOOL gSent = false; - -class AIHTTPTimeoutPolicy; -extern AIHTTPTimeoutPolicy crashLoggerResponder_timeout; -extern void startEngineThread(void); - -class LLCrashLoggerResponder : public LLHTTPClient::ResponderWithResult -{ -public: - LLCrashLoggerResponder() - { - } - - /*virtual*/ void error(U32 status, const std::string& reason) - { - gBreak = true; - } - - /*virtual*/ void result(const LLSD& content) - { - gBreak = true; - gSent = true; - } - - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return crashLoggerResponder_timeout; } - /*virtual*/ char const* getName(void) const { return "LLCrashLoggerResponder"; } -}; - -bool LLCrashLoggerText::mainLoop() -{ - std::cout << "Entering main loop" << std::endl; - sendCrashLogs(); - return true; -} - -void LLCrashLoggerText::updateApplication(const std::string& message) -{ - LLCrashLogger::updateApplication(message); - std::cout << message << std::endl; -} - -LLCrashLogger::LLCrashLogger() : - mCrashBehavior(CRASH_BEHAVIOR_ASK), - mCrashInPreviousExec(false), - mSentCrashLogs(false), - mCrashHost(""), - mCrashSettings("CrashSettings") -{ - -} - -LLCrashLogger::~LLCrashLogger() -{ - -} - -// TRIM_SIZE must remain larger than LINE_SEARCH_SIZE. -const int TRIM_SIZE = 128000; -const int LINE_SEARCH_DIST = 500; -const std::string SKIP_TEXT = "\n ...Skipping... \n"; -void trimSLLog(std::string& sllog) -{ - if(sllog.length() > TRIM_SIZE * 2) - { - std::string::iterator head = sllog.begin() + TRIM_SIZE; - std::string::iterator tail = sllog.begin() + sllog.length() - TRIM_SIZE; - std::string::iterator new_head = std::find(head, head - LINE_SEARCH_DIST, '\n'); - if(new_head != head - LINE_SEARCH_DIST) - { - head = new_head; - } - - std::string::iterator new_tail = std::find(tail, tail + LINE_SEARCH_DIST, '\n'); - if(new_tail != tail + LINE_SEARCH_DIST) - { - tail = new_tail; - } - - sllog.erase(head, tail); - sllog.insert(head, SKIP_TEXT.begin(), SKIP_TEXT.end()); - } -} - -std::string getStartupStateFromLog(std::string& sllog) -{ - std::string startup_state = "STATE_FIRST"; - std::string startup_token = "Startup state changing from "; - - int index = sllog.rfind(startup_token); - if (index < 0 || index + startup_token.length() > sllog.length()) { - return startup_state; - } - - // find new line - char cur_char = sllog[index + startup_token.length()]; - std::string::size_type newline_loc = index + startup_token.length(); - while(cur_char != '\n' && newline_loc < sllog.length()) - { - newline_loc++; - cur_char = sllog[newline_loc]; - } - - // get substring and find location of " to " - std::string state_line = sllog.substr(index, newline_loc - index); - std::string::size_type state_index = state_line.find(" to "); - startup_state = state_line.substr(state_index + 4, state_line.length() - state_index - 4); - - return startup_state; -} - -void LLCrashLogger::gatherFiles() -{ - - /* - //TODO:This function needs to be reimplemented somewhere in here... - if(!previous_crash && is_crash_log) - { - // Make sure the file isn't too old. - double age = difftime(gLaunchTime, stat_data.st_mtimespec.tv_sec); - - // llinfos << "age is " << age << llendl; - - if(age > 60.0) - { - // The file was last modified more than 60 seconds before the crash reporter was launched. Assume it's stale. - llwarns << "File " << mFilename << " is too old!" << llendl; - return; - } - } - */ - - updateApplication("Gathering logs..."); - - // Figure out the filename of the debug log - std::string db_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"debug_info.log"); - std::ifstream debug_log_file(db_file_name.c_str()); - - // Look for it in the debug_info.log file - if (debug_log_file.is_open()) - { - LLSDSerialize::fromXML(mDebugLog, debug_log_file); - - mCrashInPreviousExec = mDebugLog["CrashNotHandled"].asBoolean(); - - mFileMap["SecondLifeLog"] = mDebugLog["SLLog"].asString(); - mFileMap["SettingsXml"] = mDebugLog["SettingsFilename"].asString(); - if(mDebugLog.has("CAFilename")) - { - LLCurl::setCAFile(mDebugLog["CAFilename"].asString()); - } - else - { - LLCurl::setCAFile(gDirUtilp->getCAFile()); - } - - llinfos << "Using log file from debug log " << mFileMap["SecondLifeLog"] << llendl; - llinfos << "Using settings file from debug log " << mFileMap["SettingsXml"] << llendl; - } - else - { - // Figure out the filename of the second life log - LLCurl::setCAFile(gDirUtilp->getCAFile()); - mFileMap["SecondLifeLog"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLife.log"); - mFileMap["SettingsXml"] = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,"settings.xml"); - } - -#if !LL_DARWIN - if(mCrashInPreviousExec) -#else -#endif - { - // Replace the log file ext with .old, since the - // instance that launched this process has overwritten - // SecondLife.log - std::string log_filename = mFileMap["SecondLifeLog"]; - log_filename.replace(log_filename.size() - 4, 4, ".old"); - mFileMap["SecondLifeLog"] = log_filename; - } - - gatherPlatformSpecificFiles(); - - //Use the debug log to reconstruct the URL to send the crash report to - if(mDebugLog.has("CurrentSimHost")) - { - mCrashHost = "https://"; - mCrashHost += mDebugLog["CurrentSimHost"].asString(); - mCrashHost += ":12043/crash/report"; - } - else if(mDebugLog.has("GridName")) - { - // This is a 'little' hacky, but its the best simple solution. - std::string grid_host = mDebugLog["GridName"].asString(); - LLStringUtil::toLower(grid_host); - - mCrashHost = "https://login."; - mCrashHost += grid_host; - mCrashHost += ".lindenlab.com:12043/crash/report"; - } - - // Use login servers as the alternate, since they are already load balanced and have a known name - mAltCrashHost = "https://login.agni.lindenlab.com:12043/crash/report"; - - mCrashInfo["DebugLog"] = mDebugLog; - mFileMap["StatsLog"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stats.log"); - mFileMap["StackTrace"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log"); - - updateApplication("Encoding files..."); - - for(std::map::iterator itr = mFileMap.begin(); itr != mFileMap.end(); ++itr) - { - std::ifstream f((*itr).second.c_str()); - if(!f.is_open()) - { - std::cout << "Can't find file " << (*itr).second << std::endl; - continue; - } - std::stringstream s; - s << f.rdbuf(); - - std::string crash_info = s.str(); - if(itr->first == "SecondLifeLog") - { - if(!mCrashInfo["DebugLog"].has("StartupState")) - { - mCrashInfo["DebugLog"]["StartupState"] = getStartupStateFromLog(crash_info); - } - trimSLLog(crash_info); - } - - mCrashInfo[(*itr).first] = rawstr_to_utf8(crash_info); - } -} - -LLSD LLCrashLogger::constructPostData() -{ - LLSD ret; - return mCrashInfo; -} - -S32 LLCrashLogger::loadCrashBehaviorSetting() -{ - std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, CRASH_SETTINGS_FILE); - - mCrashSettings.loadFromFile(filename); - - S32 value = mCrashSettings.getS32(CRASH_BEHAVIOR_SETTING); - - if (value < CRASH_BEHAVIOR_ASK || CRASH_BEHAVIOR_NEVER_SEND < value) return CRASH_BEHAVIOR_ASK; - - return value; -} - -bool LLCrashLogger::saveCrashBehaviorSetting(S32 crash_behavior) -{ - if (crash_behavior != CRASH_BEHAVIOR_ASK && crash_behavior != CRASH_BEHAVIOR_ALWAYS_SEND) return false; - - mCrashSettings.setS32(CRASH_BEHAVIOR_SETTING, crash_behavior); - std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, CRASH_SETTINGS_FILE); - - mCrashSettings.saveToFile(filename, FALSE); - - return true; -} - -bool LLCrashLogger::runCrashLogPost(std::string host, LLSD data, std::string msg, int retries) -{ - gBreak = false; - std::string status_message; - for(int i = 0; i < retries; ++i) - { - status_message = llformat("%s, try %d...", msg.c_str(), i+1); - LLHTTPClient::post(host, data, new LLCrashLoggerResponder); - while(!gBreak) - { - updateApplication(status_message); - } - if(gSent) - { - return gSent; - } - } - return gSent; -} - -bool LLCrashLogger::sendCrashLogs() -{ - gatherFiles(); - - LLSD post_data; - post_data = constructPostData(); - - updateApplication("Sending reports..."); - - std::string dump_path = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, - "SecondLifeCrashReport"); - std::string report_file = dump_path + ".log"; - - std::ofstream out_file(report_file.c_str()); - LLSDSerialize::toPrettyXML(post_data, out_file); - out_file.close(); - - bool sent = false; - - // *TODO: Translate - if(mCrashHost != "") - { - sent = runCrashLogPost(mCrashHost, post_data, std::string("Sending to server"), 3); - } - - if(!sent) - { - sent = runCrashLogPost(mAltCrashHost, post_data, std::string("Sending to alternate server"), 3); - } - - mSentCrashLogs = sent; - - return true; -} - -void LLCrashLogger::updateApplication(const std::string& message) -{ - gServicePump->pump(); - gServicePump->callback(); - gMainThreadEngine.mainloop(); -} - -bool LLCrashLogger::init() -{ - // Initialize curl - AICurlInterface::initCurl(); - - // Initialize state machine engines. - AIEngine::setMaxCount(100); // StateMachineMaxTime - - // Start state machine thread. - startEngineThread(); - - // We assume that all the logs we're looking for reside on the current drive - gDirUtilp->initAppDirs("SecondLife"); - - // Default to the product name "Second Life" (this is overridden by the -name argument) - mProductName = "Second Life"; - - mCrashSettings.declareS32(CRASH_BEHAVIOR_SETTING, CRASH_BEHAVIOR_ASK, "Controls behavior when viewer crashes " - "(0 = ask before sending crash report, 1 = always send crash report, 2 = never send crash report)"); - - llinfos << "Loading crash behavior setting" << llendl; - mCrashBehavior = loadCrashBehaviorSetting(); - - // If user doesn't want to send, bail out - if (mCrashBehavior == CRASH_BEHAVIOR_NEVER_SEND) - { - llinfos << "Crash behavior is never_send, quitting" << llendl; - return false; - } - - // Start curl thread. - AICurlInterface::startCurlThread(&mCrashSettings); - - gServicePump = new LLPumpIO; - - //If we've opened the crash logger, assume we can delete the marker file if it exists - if( gDirUtilp ) - { - std::string marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLife.exec_marker"); - LLAPRFile::remove( marker_file ); - } - - return true; -} diff --git a/indra/llcrashlogger/llcrashlogger.h b/indra/llcrashlogger/llcrashlogger.h deleted file mode 100644 index 08e4a5f9fa..0000000000 --- a/indra/llcrashlogger/llcrashlogger.h +++ /dev/null @@ -1,88 +0,0 @@ -/** -* @file llcrashlogger.h -* @brief Crash Logger Definition -* -* $LicenseInfo:firstyear=2003&license=viewergpl$ -* -* Copyright (c) 2003-2009, Linden Research, Inc. -* -* Second Life Viewer Source Code -* The source code in this file ("Source Code") is provided by Linden Lab -* to you under the terms of the GNU General Public License, version 2.0 -* ("GPL"), unless you have obtained a separate licensing agreement -* ("Other License"), formally executed by you and Linden Lab. Terms of -* the GPL can be found in doc/GPL-license.txt in this distribution, or -* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 -* -* There are special exceptions to the terms and conditions of the GPL as -* it is applied to this Source Code. View the full text of the exception -* in the file doc/FLOSS-exception.txt in this software distribution, or -* online at -* http://secondlifegrid.net/programs/open_source/licensing/flossexception -* -* By copying, modifying or distributing this software, you acknowledge -* that you have read and understood your obligations described above, -* and agree to abide by those obligations. -* -* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO -* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, -* COMPLETENESS OR PERFORMANCE. -* $/LicenseInfo$ -*/ -#ifndef LLCRASHLOGGER_H -#define LLCRASHLOGGER_H - -#include "linden_common.h" - -#include - -#include "llapp.h" -#include "llsd.h" -#include "llcontrol.h" - -class AIHTTPTimeoutPolicy; - -class LLCrashLogger : public LLApp -{ -public: - LLCrashLogger(); - virtual ~LLCrashLogger(); - S32 loadCrashBehaviorSetting(); - void gatherFiles(); - virtual void gatherPlatformSpecificFiles() {} - bool saveCrashBehaviorSetting(S32 crash_behavior); - bool sendCrashLogs(); - LLSD constructPostData(); - virtual void updateApplication(const std::string& message = LLStringUtil::null); - virtual bool init(); - virtual bool mainLoop() = 0; - virtual bool cleanup() { return true; } - void setUserText(const std::string& text) { mCrashInfo["UserNotes"] = text; } - S32 getCrashBehavior() { return mCrashBehavior; } - bool runCrashLogPost(std::string host, LLSD data, std::string msg, int retries); -protected: - S32 mCrashBehavior; - BOOL mCrashInPreviousExec; - std::map mFileMap; - std::string mGridName; - LLControlGroup mCrashSettings; - std::string mProductName; - LLSD mCrashInfo; - std::string mCrashHost; - std::string mAltCrashHost; - LLSD mDebugLog; - bool mSentCrashLogs; -}; - -class LLCrashLoggerText : public LLCrashLogger -{ -public: - LLCrashLoggerText(void) {} - ~LLCrashLoggerText(void) {} - - virtual bool mainLoop(); - virtual void updateApplication(const std::string& message = LLStringUtil::null); -}; - - -#endif //LLCRASHLOGGER_H diff --git a/indra/llimage/CMakeLists.txt b/indra/llimage/CMakeLists.txt index 431744c421..fb41880320 100644 --- a/indra/llimage/CMakeLists.txt +++ b/indra/llimage/CMakeLists.txt @@ -54,9 +54,11 @@ set_source_files_properties(${llimage_HEADER_FILES} list(APPEND llimage_SOURCE_FILES ${llimage_HEADER_FILES}) add_library (llimage ${llimage_SOURCE_FILES}) -add_dependencies(llimage prepare) + target_link_libraries( llimage + PUBLIC + llcommon ${JPEG_LIBRARIES} ${PNG_LIBRARIES} ${ZLIB_LIBRARIES} diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 6f3deba0c4..768958d2fa 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -124,12 +124,12 @@ void LLImageBase::destroyPrivatePool() // virtual void LLImageBase::dump() { - llinfos << "LLImageBase mComponents " << mComponents + LL_INFOS() << "LLImageBase mComponents " << mComponents << " mData " << mData << " mDataSize " << mDataSize << " mWidth " << mWidth << " mHeight " << mHeight - << llendl; + << LL_ENDL; } // virtual @@ -141,13 +141,13 @@ void LLImageBase::sanityCheck() || mComponents > (S8)MAX_IMAGE_COMPONENTS ) { - llerrs << "Failed LLImageBase::sanityCheck " + LL_ERRS() << "Failed LLImageBase::sanityCheck " << "width " << mWidth << "height " << mHeight << "datasize " << mDataSize << "components " << mComponents << "data " << mData - << llendl; + << LL_ENDL; } } @@ -167,7 +167,7 @@ U8* LLImageBase::allocateData(S32 size) size = mWidth * mHeight * mComponents; if (size <= 0) { - llerrs << llformat("LLImageBase::allocateData called with bad dimensions: %dx%dx%d",mWidth,mHeight,(S32)mComponents) << llendl; + LL_ERRS() << llformat("LLImageBase::allocateData called with bad dimensions: %dx%dx%d",mWidth,mHeight,(S32)mComponents) << LL_ENDL; } } @@ -175,14 +175,14 @@ U8* LLImageBase::allocateData(S32 size) static const U32 MAX_BUFFER_SIZE = 4096 * 4096 * 16 ; //256 MB if (size < 1 || size > MAX_BUFFER_SIZE) { - //llinfos << "width: " << mWidth << " height: " << mHeight << " components: " << mComponents << llendl ; + //LL_INFOS() << "width: " << mWidth << " height: " << mHeight << " components: " << mComponents << LL_ENDL ; if(mAllowOverSize) { - //llinfos << "Oversize: " << size << llendl ; + //LL_INFOS() << "Oversize: " << size << LL_ENDL ; } else { - llerrs << "LLImageBase::allocateData: bad size: " << size << llendl; + LL_ERRS() << "LLImageBase::allocateData: bad size: " << size << LL_ENDL; } } if (!mData || size != mDataSize) @@ -192,7 +192,7 @@ U8* LLImageBase::allocateData(S32 size) mData = (U8*)ALLOCATE_MEM(sPrivatePoolp, size); if (!mData) { - llwarns << "Failed to allocate image data size [" << size << "]" << llendl; + LL_WARNS() << "Failed to allocate image data size [" << size << "]" << LL_ENDL; size = 0 ; mWidth = mHeight = 0 ; mBadBufferAllocation = true ; @@ -211,12 +211,12 @@ U8* LLImageBase::reallocateData(S32 size) size = mWidth * mHeight * mComponents; if (size <= 0) { - llerrs << llformat("LLImageBase::reallocateData called with bad dimensions: %dx%dx%d", mWidth, mHeight, (S32)mComponents) << llendl; + LL_ERRS() << llformat("LLImageBase::reallocateData called with bad dimensions: %dx%dx%d", mWidth, mHeight, (S32)mComponents) << LL_ENDL; } } else if (size <= 0 || (size > 4096 * 4096 * 16 && !mAllowOverSize)) { - llerrs << "LLImageBase::reallocateData: bad size: " << size << llendl; + LL_ERRS() << "LLImageBase::reallocateData: bad size: " << size << LL_ENDL; } if(mData && (mDataSize == size)) @@ -225,7 +225,7 @@ U8* LLImageBase::reallocateData(S32 size) U8 *new_datap = (U8*)ALLOCATE_MEM(sPrivatePoolp, size); if (!new_datap) { - llwarns << "Out of memory in LLImageBase::reallocateData" << llendl; + LL_WARNS() << "Out of memory in LLImageBase::reallocateData" << LL_ENDL; return 0; } if (mData) @@ -243,7 +243,7 @@ const U8* LLImageBase::getData() const { if(mBadBufferAllocation) { - llerrs << "Bad memory allocation for the image buffer!" << llendl ; + LL_ERRS() << "Bad memory allocation for the image buffer!" << LL_ENDL ; } return mData; @@ -253,7 +253,7 @@ U8* LLImageBase::getData() { if(mBadBufferAllocation) { - llerrs << "Bad memory allocation for the image buffer!" << llendl ; + LL_ERRS() << "Bad memory allocation for the image buffer!" << LL_ENDL ; } return mData; @@ -281,7 +281,7 @@ U8* LLImageBase::allocateDataSize(S32 width, S32 height, S32 ncomponents, S32 si // LLImageRaw //--------------------------------------------------------------------------- -AIThreadSafeSimpleDC LLImageRaw::sGlobalRawMemory; +AIThreadSafeSimpleDC LLImageRaw::sGlobalRawMemory; S32 LLImageRaw::sRawImageCount = 0; S32 LLImageRaw::sRawImageCachedCount = 0; @@ -299,10 +299,15 @@ LLImageRaw::LLImageRaw(U16 width, U16 height, S8 components) ++sRawImageCount; } -LLImageRaw::LLImageRaw(U8 *data, U16 width, U16 height, S8 components) +LLImageRaw::LLImageRaw(U8 *data, U16 width, U16 height, S8 components, bool no_copy) : LLImageBase(), mCacheEntries(0) { - if(allocateDataSize(width, height, components) && data) + + if(no_copy) + { + setDataAndSize(data, width, height, components); + } + else if(allocateDataSize(width, height, components) && data) { memcpy(getData(), data, width*height*components); } @@ -353,7 +358,7 @@ LLImageRaw::~LLImageRaw() U8* LLImageRaw::allocateData(S32 size) { U8* res = LLImageBase::allocateData(size); - *AIAccess(sGlobalRawMemory) += getDataSize(); + *AIAccess(sGlobalRawMemory) += getDataSize(); return res; } @@ -362,7 +367,7 @@ U8* LLImageRaw::reallocateData(S32 size) { S32 old_data_size = getDataSize(); U8* res = LLImageBase::reallocateData(size); - *AIAccess(sGlobalRawMemory) += getDataSize() - old_data_size; + *AIAccess(sGlobalRawMemory) += getDataSize() - old_data_size; return res; } @@ -370,7 +375,7 @@ U8* LLImageRaw::reallocateData(S32 size) void LLImageRaw::deleteData() { { - *AIAccess(sGlobalRawMemory) -= getDataSize(); + *AIAccess(sGlobalRawMemory) -= getDataSize(); } LLImageBase::deleteData(); } @@ -387,7 +392,7 @@ void LLImageRaw::setDataAndSize(U8 *data, S32 width, S32 height, S8 components) LLImageBase::setSize(width, height, components) ; LLImageBase::setDataAndSize(data, width * height * components) ; - *AIAccess(sGlobalRawMemory) += getDataSize(); + *AIAccess(sGlobalRawMemory) += getDataSize(); } BOOL LLImageRaw::resize(U16 width, U16 height, S8 components) @@ -412,7 +417,7 @@ U8 * LLImageRaw::getSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height) const // Should do some simple bounds checking if (!data) { - llerrs << "Out of memory in LLImageRaw::getSubImage" << llendl; + LL_ERRS() << "Out of memory in LLImageRaw::getSubImage" << LL_ENDL; return NULL; } @@ -507,7 +512,7 @@ void LLImageRaw::verticalFlip() } catch(std::bad_alloc) { - llerrs << "Out of memory in LLImageRaw::verticalFlip()" << llendl; + LL_ERRS() << "Out of memory in LLImageRaw::verticalFlip()" << LL_ENDL; } } @@ -629,7 +634,7 @@ void LLImageRaw::composite( LLImageRaw* src ) // Src and dst can be any size. Src has 4 components. Dst has 3 components. void LLImageRaw::compositeScaled4onto3(LLImageRaw* src) { - llinfos << "compositeScaled4onto3" << llendl; + LL_INFOS() << "compositeScaled4onto3" << LL_ENDL; LLImageRaw* dst = this; // Just for clarity. @@ -655,7 +660,7 @@ void LLImageRaw::compositeScaled4onto3(LLImageRaw* src) } catch(std::bad_alloc) { - llerrs << "Out of memory in LLImageRaw::compositeScaled4onto3()" << llendl; + LL_ERRS() << "Out of memory in LLImageRaw::compositeScaled4onto3()" << LL_ENDL; } } @@ -762,15 +767,24 @@ void LLImageRaw::fill( const LLColor4U& color ) } } +LLPointer LLImageRaw::duplicate() +{ + if(getNumRefs() < 2) + { + return this; //nobody else refences to this image, no need to duplicate. + } - + //make a duplicate + LLPointer dup = new LLImageRaw(getData(), getWidth(), getHeight(), getComponents()); + return dup; +} // Src and dst can be any size. Src and dst can each have 3 or 4 components. void LLImageRaw::copy(LLImageRaw* src) { if (!src) { - llwarns << "LLImageRaw::copy called with a null src pointer" << llendl; + LL_WARNS() << "LLImageRaw::copy called with a null src pointer" << LL_ENDL; return; } @@ -934,7 +948,7 @@ void LLImageRaw::copyScaled( LLImageRaw* src ) } catch(std::bad_alloc) { - llerrs << "Out of memory in LLImageRaw::copyScaled()" << llendl; + LL_ERRS() << "Out of memory in LLImageRaw::copyScaled()" << LL_ENDL; } } @@ -1070,6 +1084,7 @@ void LLImageRaw::copyLineScaled( U8* in, U8* out, S32 in_pixel_len, S32 out_pixe S32 goff = components >= 2 ? 1 : 0; S32 boff = components >= 3 ? 2 : 0; + // This loop is awful. for( S32 x = 0; x < out_pixel_len; x++ ) { // Sample input pixels in range from sample0 to sample1. @@ -1158,19 +1173,15 @@ void LLImageRaw::copyLineScaled( U8* in, U8* out, S32 in_pixel_len, S32 out_pixe } } - r *= norm_factor; - g *= norm_factor; - b *= norm_factor; - a *= norm_factor; // skip conditional + U8 arr[] = { + U8(ll_pos_round(r * norm_factor)), + U8(ll_pos_round(g * norm_factor)), + U8(ll_pos_round(b * norm_factor)), + U8(ll_pos_round(a * norm_factor)) + }; // skip conditional S32 t4 = x * out_pixel_step * components; - out[t4 + 0] = U8(llround(r)); - if (components >= 2) - out[t4 + 1] = U8(llround(g)); - if (components >= 3) - out[t4 + 2] = U8(llround(b)); - if( components == 4) - out[t4 + 3] = U8(llround(a)); + memcpy(out + t4, arr, sizeof(U8) * components); } } } @@ -1245,10 +1256,10 @@ void LLImageRaw::compositeRowScaled4onto3( U8* in, U8* out, S32 in_pixel_len, S3 b *= norm_factor; a *= norm_factor; - in_scaled_r = U8(llround(r)); - in_scaled_g = U8(llround(g)); - in_scaled_b = U8(llround(b)); - in_scaled_a = U8(llround(a)); + in_scaled_r = U8(ll_pos_round(r)); + in_scaled_g = U8(ll_pos_round(g)); + in_scaled_b = U8(ll_pos_round(b)); + in_scaled_a = U8(ll_pos_round(a)); } if( in_scaled_a ) @@ -1352,7 +1363,7 @@ bool LLImageRaw::createFromFile(const std::string &filename, bool j2c_lowest_mip if (!ifs.is_open()) { // SJB: changed from llinfos to lldebugs to reduce spam - lldebugs << "Unable to open image file: " << name << llendl; + LL_DEBUGS() << "Unable to open image file: " << name << LL_ENDL; return false; } @@ -1366,7 +1377,7 @@ bool LLImageRaw::createFromFile(const std::string &filename, bool j2c_lowest_mip if (!length) { - llinfos << "Zero length file file: " << name << llendl; + LL_INFOS() << "Zero length file file: " << name << LL_ENDL; return false; } @@ -1402,7 +1413,7 @@ bool LLImageRaw::createFromFile(const std::string &filename, bool j2c_lowest_mip if (!success) { deleteData(); - llwarns << "Unable to decode image" << name << llendl; + LL_WARNS() << "Unable to decode image" << name << LL_ENDL; return false; } @@ -1506,11 +1517,11 @@ void LLImageFormatted::dump() { LLImageBase::dump(); - llinfos << "LLImageFormatted" + LL_INFOS() << "LLImageFormatted" << " mDecoding " << mDecoding << " mCodec " << S32(mCodec) << " mDecoded " << mDecoded - << llendl; + << LL_ENDL; } //---------------------------------------------------------------------------- @@ -1593,11 +1604,11 @@ void LLImageFormatted::sanityCheck() if (mCodec >= IMG_CODEC_EOF) { - llerrs << "Failed LLImageFormatted::sanityCheck " + LL_ERRS() << "Failed LLImageFormatted::sanityCheck " << "decoding " << S32(mDecoding) << "decoded " << S32(mDecoded) << "codec " << S32(mCodec) - << llendl; + << LL_ENDL; } } @@ -1770,7 +1781,7 @@ void LLImageBase::generateMip(const U8* indata, U8* mipdata, S32 width, S32 heig *(U8*)data = (U8)(((U32)(indata[0]) + indata[1] + indata[in_width] + indata[in_width+1])>>2); break; default: - llerrs << "generateMmip called with bad num channels" << llendl; + LL_ERRS() << "generateMmip called with bad num channels" << LL_ENDL; } indata += nchannels*2; data += nchannels; @@ -1827,17 +1838,17 @@ F32 LLImageBase::calc_download_priority(F32 virtual_size, F32 visible_pixels, S3 bytes_weight *= bytes_weight; - //llinfos << "VS: " << virtual_size << llendl; + //LL_INFOS() << "VS: " << virtual_size << LL_ENDL; F32 virtual_size_factor = virtual_size / (10.f*10.f); // The goal is for weighted priority to be <= 0 when we've reached a point where // we've sent enough data. - //llinfos << "BytesSent: " << bytes_sent << llendl; - //llinfos << "BytesWeight: " << bytes_weight << llendl; - //llinfos << "PreLog: " << bytes_weight * virtual_size_factor << llendl; + //LL_INFOS() << "BytesSent: " << bytes_sent << LL_ENDL; + //LL_INFOS() << "BytesWeight: " << bytes_weight << LL_ENDL; + //LL_INFOS() << "PreLog: " << bytes_weight * virtual_size_factor << LL_ENDL; w_priority = (F32)log10(bytes_weight * virtual_size_factor); - //llinfos << "PreScale: " << w_priority << llendl; + //LL_INFOS() << "PreScale: " << w_priority << LL_ENDL; // We don't want to affect how MANY bytes we send based on the visible pixels, but the order // in which they're sent. We post-multiply so we don't change the zero point. diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h index 012031338a..d77e0f39b6 100644 --- a/indra/llimage/llimage.h +++ b/indra/llimage/llimage.h @@ -173,7 +173,7 @@ class LLImageRaw : public LLImageBase public: LLImageRaw(); LLImageRaw(U16 width, U16 height, S8 components); - LLImageRaw(U8 *data, U16 width, U16 height, S8 components); + LLImageRaw(U8 *data, U16 width, U16 height, S8 components, bool no_copy = false); LLImageRaw(LLImageRaw const* src, U16 width, U16 height, U16 crop_offset, bool crop_vertically); // Construct using createFromFile (used by tools) //LLImageRaw(const std::string& filename, bool j2c_lowest_mip_only = false); @@ -204,6 +204,9 @@ class LLImageRaw : public LLImageBase // Copy operations + //duplicate this raw image if refCount > 1. + LLPointer duplicate(); + // Src and dst can be any size. Src and dst can each have 3 or 4 components. void copy( LLImageRaw* src ); @@ -241,6 +244,9 @@ class LLImageRaw : public LLImageBase // Src and dst are same size. Src has 4 components. Dst has 3 components. void compositeUnscaled4onto3( LLImageRaw* src ); + + std::string getComment() const { return mComment; } + std::string mComment; protected: // Create an image from a local file (generally used in tools) @@ -254,7 +260,7 @@ class LLImageRaw : public LLImageBase void setDataAndSize(U8 *data, S32 width, S32 height, S8 components) ; public: - static AIThreadSafeSimpleDC sGlobalRawMemory; + static AIThreadSafeSimpleDC sGlobalRawMemory; static S32 sRawImageCount; static S32 sRawImageCachedCount; diff --git a/indra/llimage/llimagebmp.cpp b/indra/llimage/llimagebmp.cpp index ceded296ae..b60f2064ca 100644 --- a/indra/llimage/llimagebmp.cpp +++ b/indra/llimage/llimagebmp.cpp @@ -1,31 +1,25 @@ /** * @file llimagebmp.cpp * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -81,7 +75,7 @@ LLImageBMP::LLImageBMP() : LLImageFormatted(IMG_CODEC_BMP), mColorPaletteColors( 0 ), - mColorPalette( NULL ), + mColorPalette(nullptr ), mBitmapOffset( 0 ), mBitsPerPixel( 0 ), mOriginAtTop( FALSE ) @@ -324,10 +318,13 @@ BOOL LLImageBMP::updateData() if( 0 != mColorPaletteColors ) { - mColorPalette = new U8[color_palette_size]; - if (!mColorPalette) + try + { + mColorPalette = new U8[color_palette_size]; + } + catch (const std::bad_alloc& e) { - llerrs << "Out of memory in LLImageBMP::updateData()" << llendl; + LL_WARNS() << "Failed to allocate bmp color date with exception: " << e.what() << LL_ENDL; return FALSE; } memcpy( mColorPalette, mdata + FILE_HEADER_SIZE + BITMAP_HEADER_SIZE + extension_size, color_palette_size ); /* Flawfinder: ignore */ @@ -449,6 +446,10 @@ BOOL LLImageBMP::decodeColorMask32( U8* dst, U8* src ) mBitfieldMask[2] = 0x000000FF; } + if (getWidth() * getHeight() * 4 > getDataSize() - mBitmapOffset) + { //here we have situation when data size in src less than actually needed + return FALSE; + } S32 src_row_span = getWidth() * 4; S32 alignment_bytes = (3 * src_row_span) % 4; // round up to nearest multiple of 4 @@ -482,6 +483,11 @@ BOOL LLImageBMP::decodeColorTable8( U8* dst, U8* src ) S32 src_row_span = getWidth() * 1; S32 alignment_bytes = (3 * src_row_span) % 4; // round up to nearest multiple of 4 + if ((getWidth() * getHeight()) + getHeight() * alignment_bytes > getDataSize() - mBitmapOffset) + { //here we have situation when data size in src less than actually needed + return FALSE; + } + for( S32 row = 0; row < getHeight(); row++ ) { for( S32 col = 0; col < getWidth(); col++ ) @@ -507,6 +513,11 @@ BOOL LLImageBMP::decodeTruecolor24( U8* dst, U8* src ) S32 src_row_span = getWidth() * 3; S32 alignment_bytes = (3 * src_row_span) % 4; // round up to nearest multiple of 4 + if ((getWidth() * getHeight() * 3) + getHeight() * alignment_bytes > getDataSize() - mBitmapOffset) + { //here we have situation when data size in src less than actually needed + return FALSE; + } + for( S32 row = 0; row < getHeight(); row++ ) { for( S32 col = 0; col < getWidth(); col++ ) @@ -534,7 +545,7 @@ BOOL LLImageBMP::encode(const LLImageRaw* raw_image, F32 encode_time) if( (2 == src_components) || (4 == src_components) ) { - llinfos << "Dropping alpha information during BMP encoding" << llendl; + LL_INFOS() << "Dropping alpha information during BMP encoding" << LL_ENDL; } setSize(raw_image->getWidth(), raw_image->getHeight(), dst_components); diff --git a/indra/llimage/llimagedxt.cpp b/indra/llimage/llimagedxt.cpp index 34c6793522..8f2a48a5ef 100644 --- a/indra/llimage/llimagedxt.cpp +++ b/indra/llimage/llimagedxt.cpp @@ -52,7 +52,7 @@ S32 LLImageDXT::formatBits(EFileFormat format) case FORMAT_RGB8: return 24; case FORMAT_RGBA8: return 32; default: - llerrs << "LLImageDXT::Unknown format: " << format << llendl; + LL_ERRS() << "LLImageDXT::Unknown format: " << format << LL_ENDL; return 0; } }; @@ -82,7 +82,7 @@ S32 LLImageDXT::formatComponents(EFileFormat format) case FORMAT_RGB8: return 3; case FORMAT_RGBA8: return 4; default: - llerrs << "LLImageDXT::Unknown format: " << format << llendl; + LL_ERRS() << "LLImageDXT::Unknown format: " << format << LL_ENDL; return 0; } }; @@ -207,7 +207,7 @@ BOOL LLImageDXT::updateData() if (data_size < mHeaderSize) { - llerrs << "LLImageDXT: not enough data" << llendl; + LL_ERRS() << "LLImageDXT: not enough data" << LL_ENDL; } S32 ncomponents = formatComponents(mFileFormat); setSize(width, height, ncomponents); @@ -224,7 +224,7 @@ S32 LLImageDXT::getMipOffset(S32 discard) { if (mFileFormat >= FORMAT_DXT1 && mFileFormat <= FORMAT_DXT5) { - llerrs << "getMipOffset called with old (unsupported) format" << llendl; + LL_ERRS() << "getMipOffset called with old (unsupported) format" << LL_ENDL; } S32 width = getWidth(), height = getHeight(); S32 num_mips = calcNumMips(width, height); @@ -251,7 +251,7 @@ void LLImageDXT::setFormat() { case 3: mFileFormat = FORMAT_DXR1; break; case 4: mFileFormat = FORMAT_DXR3; break; - default: llerrs << "LLImageDXT::setFormat called with ncomponents = " << ncomponents << llendl; + default: LL_ERRS() << "LLImageDXT::setFormat called with ncomponents = " << ncomponents << LL_ENDL; } mHeaderSize = calcHeaderSize(); } @@ -265,13 +265,13 @@ BOOL LLImageDXT::decode(LLImageRaw* raw_image, F32 time) if (mFileFormat >= FORMAT_DXT1 && mFileFormat <= FORMAT_DXR5) { - llwarns << "Attempt to decode compressed LLImageDXT to Raw (unsupported)" << llendl; + LL_WARNS() << "Attempt to decode compressed LLImageDXT to Raw (unsupported)" << LL_ENDL; return FALSE; } S32 width = getWidth(), height = getHeight(); S32 ncomponents = getComponents(); - U8* data = NULL; + U8* data = nullptr; if (mDiscardLevel >= 0) { data = getData() + getMipOffset(mDiscardLevel); @@ -303,7 +303,7 @@ BOOL LLImageDXT::getMipData(LLPointer& raw, S32 discard) } else if (discard < mDiscardLevel) { - llerrs << "Request for invalid discard level" << llendl; + LL_ERRS() << "Request for invalid discard level" << LL_ENDL; } U8* data = getData() + getMipOffset(discard); S32 width = 0; @@ -331,8 +331,8 @@ BOOL LLImageDXT::encodeDXT(const LLImageRaw* raw_image, F32 time, bool explicit_ format = FORMAT_RGBA8; break; default: - llerrs << "LLImageDXT::encode: Unhandled channel number: " << ncomponents << llendl; - return 0; + LL_ERRS() << "LLImageDXT::encode: Unhandled channel number: " << ncomponents << LL_ENDL; + return false; } S32 width = raw_image->getWidth(); @@ -371,7 +371,7 @@ BOOL LLImageDXT::encodeDXT(const LLImageRaw* raw_image, F32 time, bool explicit_ header->maxwidth = width; header->maxheight = height; - U8* prev_mipdata = 0; + U8* prev_mipdata = nullptr; w = width, h = height; for (S32 mip=0; mip 0); @@ -466,7 +466,7 @@ S32 LLImageDXT::calcDataSize(S32 discard_level) { if (mFileFormat == FORMAT_UNKNOWN) { - llerrs << "calcDataSize called with unloaded LLImageDXT" << llendl; + LL_ERRS() << "calcDataSize called with unloaded LLImageDXT" << LL_ENDL; return 0; } if (discard_level < 0) diff --git a/indra/llimage/llimagedxt.h b/indra/llimage/llimagedxt.h index 1a297536b4..10b619df3c 100644 --- a/indra/llimage/llimagedxt.h +++ b/indra/llimage/llimagedxt.h @@ -119,7 +119,7 @@ class LLImageDXT : public LLImageFormatted S32 getMipOffset(S32 discard); EFileFormat getFileFormat() { return mFileFormat; } - bool isCompressed() { return (mFileFormat >= FORMAT_DXT1 && mFileFormat <= FORMAT_DXR5); } + bool isCompressed() const { return (mFileFormat >= FORMAT_DXT1 && mFileFormat <= FORMAT_DXR5); } bool convertToDXR(); // convert from DXT to DXR diff --git a/indra/llimage/llimagejpeg.cpp b/indra/llimage/llimagejpeg.cpp index 79ea79cc07..8181c39d91 100644 --- a/indra/llimage/llimagejpeg.cpp +++ b/indra/llimage/llimagejpeg.cpp @@ -380,7 +380,7 @@ boolean LLImageJPEG::encodeEmptyOutputBuffer( j_compress_ptr cinfo ) U8* new_buffer = new U8[ new_buffer_size ]; if (!new_buffer) { - llerrs << "Out of memory in LLImageJPEG::encodeEmptyOutputBuffer( j_compress_ptr cinfo )" << llendl; + LL_ERRS() << "Out of memory in LLImageJPEG::encodeEmptyOutputBuffer( j_compress_ptr cinfo )" << LL_ENDL; return FALSE; } memcpy( new_buffer, self->mOutputBuffer, self->mOutputBufferSize ); /* Flawfinder: ignore */ @@ -471,7 +471,7 @@ void LLImageJPEG::errorOutputMessage( j_common_ptr cinfo ) LLImage::setLastError(error); BOOL is_decode = (cinfo->is_decompressor != 0); - llwarns << "LLImageJPEG " << (is_decode ? "decode " : "encode ") << " failed: " << buffer << llendl; + LL_WARNS() << "LLImageJPEG " << (is_decode ? "decode " : "encode ") << " failed: " << buffer << LL_ENDL; } BOOL LLImageJPEG::encode( const LLImageRaw* raw_image, F32 encode_time ) diff --git a/indra/llimage/llimagepng.cpp b/indra/llimage/llimagepng.cpp index 34f553ffc8..7735dc1379 100644 --- a/indra/llimage/llimagepng.cpp +++ b/indra/llimage/llimagepng.cpp @@ -67,7 +67,7 @@ BOOL LLImagePNG::updateData() } LLPngWrapper::ImageInfo infop; - if (! pngWrapper.readPng(getData(), NULL, &infop)) + if (! pngWrapper.readPng(getData(), getDataSize(), NULL, &infop)) { setLastError(pngWrapper.getErrorMessage()); return FALSE; @@ -102,7 +102,7 @@ BOOL LLImagePNG::decode(LLImageRaw* raw_image, F32 decode_time) return FALSE; } - if (! pngWrapper.readPng(getData(), raw_image)) + if (! pngWrapper.readPng(getData(), getDataSize(), raw_image)) { setLastError(pngWrapper.getErrorMessage()); return FALSE; @@ -122,53 +122,27 @@ BOOL LLImagePNG::encode(const LLImageRaw* raw_image, F32 encode_time) // Image logical size setSize(raw_image->getWidth(), raw_image->getHeight(), raw_image->getComponents()); + // Temporary buffer to hold the encoded image. Note: the final image + // size should be much smaller due to compression. U32 bufferSize = getWidth() * getHeight() * getComponents() + 1024; - - //New implementation - allocateData(bufferSize); //Set to largest possible size. - if(isBufferInvalid()) //Checking - { - setLastError("LLImagePNG::encode failed allocateData"); - return FALSE; - } - - // Delegate actual encoding work to wrapper - LLPngWrapper pngWrapper; - if (! pngWrapper.writePng(raw_image, getData())) - { - setLastError(pngWrapper.getErrorMessage()); - deleteData(); - return FALSE; - } - - // Resize internal buffer. - if(!reallocateData(pngWrapper.getFinalSize())) //Shrink. Returns NULL on failure. - { - setLastError("LLImagePNG::encode failed reallocateData"); - deleteData(); - return FALSE; - } - return TRUE; - - - /*U8* mTmpWriteBuffer = new U8[ bufferSize ]; + U8* tmpWriteBuffer = new U8[ bufferSize ]; // Delegate actual encoding work to wrapper LLPngWrapper pngWrapper; - if (! pngWrapper.writePng(raw_image, mTmpWriteBuffer)) + if (! pngWrapper.writePng(raw_image, tmpWriteBuffer)) { setLastError(pngWrapper.getErrorMessage()); - delete[] mTmpWriteBuffer; + delete[] tmpWriteBuffer; return FALSE; } // Resize internal buffer and copy from temp U32 encodedSize = pngWrapper.getFinalSize(); allocateData(encodedSize); - memcpy(getData(), mTmpWriteBuffer, encodedSize); + memcpy(getData(), tmpWriteBuffer, encodedSize); - delete[] mTmpWriteBuffer; + delete[] tmpWriteBuffer; - return TRUE;*/ + return TRUE; } diff --git a/indra/llimage/llimagetga.cpp b/indra/llimage/llimagetga.cpp index 58426d31fa..01b3c3243a 100644 --- a/indra/llimage/llimagetga.cpp +++ b/indra/llimage/llimagetga.cpp @@ -266,7 +266,7 @@ BOOL LLImageTGA::updateData() mColorMap = new U8[ color_map_bytes ]; if (!mColorMap) { - llerrs << "Out of Memory in BOOL LLImageTGA::updateData()" << llendl; + LL_ERRS() << "Out of Memory in BOOL LLImageTGA::updateData()" << LL_ENDL; return FALSE; } memcpy( mColorMap, getData() + mDataOffset, color_map_bytes ); /* Flawfinder: ignore */ @@ -437,7 +437,13 @@ BOOL LLImageTGA::decodeTruecolorNonRle( LLImageRaw* raw_image, BOOL &alpha_opaqu // Origin is the bottom left U8* dst = raw_image->getData(); U8* src = getData() + mDataOffset; + S32 pixels = getWidth() * getHeight(); + + if (pixels * (mIs15Bit ? 2 : getComponents()) > getDataSize() - (S32)mDataOffset) + { //here we have situation when data size in src less than actually needed + return FALSE; + } if (getComponents() == 4) { @@ -1043,7 +1049,7 @@ BOOL LLImageTGA::decodeAndProcess( LLImageRaw* raw_image, F32 domain, F32 weight // Only works for unflipped monochrome RLE images if( (getComponents() != 1) || (mImageType != 11) || mOriginTopBit || mOriginRightBit ) { - llerrs << "LLImageTGA trying to alpha-gradient process an image that's not a standard RLE, one component image" << llendl; + LL_ERRS() << "LLImageTGA trying to alpha-gradient process an image that's not a standard RLE, one component image" << LL_ENDL; return FALSE; } @@ -1151,11 +1157,11 @@ bool LLImageTGA::loadFile( const std::string& path ) LLFILE* file = LLFile::fopen(path, "rb"); /* Flawfinder: ignore */ if( !file ) { - llwarns << "Couldn't open file " << path << llendl; + LL_WARNS() << "Couldn't open file " << path << LL_ENDL; return false; } - S32 file_size = 0; + size_t file_size = 0; if (!fseek(file, 0, SEEK_END)) { file_size = ftell(file); @@ -1167,7 +1173,7 @@ bool LLImageTGA::loadFile( const std::string& path ) if( bytes_read != file_size ) { deleteData(); - llwarns << "Couldn't read file " << path << llendl; + LL_WARNS() << "Couldn't read file " << path << LL_ENDL; return false; } @@ -1175,7 +1181,7 @@ bool LLImageTGA::loadFile( const std::string& path ) if( !updateData() ) { - llwarns << "Couldn't decode file " << path << llendl; + LL_WARNS() << "Couldn't decode file " << path << LL_ENDL; deleteData(); return false; } diff --git a/indra/llimage/llimageworker.cpp b/indra/llimage/llimageworker.cpp index 161b25f5ea..c4b8c09943 100644 --- a/indra/llimage/llimageworker.cpp +++ b/indra/llimage/llimageworker.cpp @@ -35,18 +35,20 @@ LLImageDecodeThread::LLImageDecodeThread(bool threaded) : LLQueuedThread("imagedecode", threaded) { + mCreationMutex = new LLMutex(); } //virtual LLImageDecodeThread::~LLImageDecodeThread() { + delete mCreationMutex ; } // MAIN THREAD // virtual S32 LLImageDecodeThread::update(F32 max_time_ms) { - LLMutexLock lock(&mCreationMutex); + LLMutexLock lock(mCreationMutex); for (creation_list_t::iterator iter = mCreationList.begin(); iter != mCreationList.end(); ++iter) { @@ -58,7 +60,7 @@ S32 LLImageDecodeThread::update(F32 max_time_ms) bool res = addRequest(req); if (!res) { - llerrs << "request added after LLLFSThread::cleanupClass()" << llendl; + LL_ERRS() << "request added after LLLFSThread::cleanupClass()" << LL_ENDL; } } mCreationList.clear(); @@ -69,7 +71,7 @@ S32 LLImageDecodeThread::update(F32 max_time_ms) LLImageDecodeThread::handle_t LLImageDecodeThread::decodeImage(LLImageFormatted* image, U32 priority, S32 discard, BOOL needs_aux, Responder* responder) { - LLMutexLock lock(&mCreationMutex); + LLMutexLock lock(mCreationMutex); handle_t handle = generateHandle(); mCreationList.push_back(creation_info(handle, image, priority, discard, needs_aux, responder)); return handle; @@ -79,7 +81,7 @@ LLImageDecodeThread::handle_t LLImageDecodeThread::decodeImage(LLImageFormatted* // Returns the size of the mutex guarded list as an indication of sanity S32 LLImageDecodeThread::tut_size() { - LLMutexLock lock(&mCreationMutex); + LLMutexLock lock(mCreationMutex); S32 res = mCreationList.size(); return res; } diff --git a/indra/llimage/llimageworker.h b/indra/llimage/llimageworker.h index 6d9ae3fe9b..1bfb0ddfd3 100644 --- a/indra/llimage/llimageworker.h +++ b/indra/llimage/llimageworker.h @@ -98,7 +98,7 @@ class LLImageDecodeThread : public LLQueuedThread }; typedef std::list creation_list_t; creation_list_t mCreationList; - LLMutex mCreationMutex; + LLMutex* mCreationMutex; }; #endif diff --git a/indra/llimage/llpngwrapper.cpp b/indra/llimage/llpngwrapper.cpp index 0776e2ebda..f515076c0e 100644 --- a/indra/llimage/llpngwrapper.cpp +++ b/indra/llimage/llpngwrapper.cpp @@ -93,6 +93,12 @@ void LLPngWrapper::errorHandler(png_structp png_ptr, png_const_charp msg) void LLPngWrapper::readDataCallback(png_structp png_ptr, png_bytep dest, png_size_t length) { PngDataInfo *dataInfo = (PngDataInfo *) png_get_io_ptr(png_ptr); + if (S32(dataInfo->mOffset + length) > dataInfo->mDataSize) + { + png_error(png_ptr, "Data read error. Requested data size exceeds available data size."); + return; + } + U8 *src = &dataInfo->mData[dataInfo->mOffset]; memcpy(dest, src, length); dataInfo->mOffset += static_cast(length); @@ -120,7 +126,7 @@ void LLPngWrapper::writeFlush(png_structp png_ptr) // The scanline also begins at the bottom of // the image (per SecondLife conventions) instead of at the top, so we // must assign row-pointers in "reverse" order. -BOOL LLPngWrapper::readPng(U8* src, LLImageRaw* rawImage, ImageInfo *infop) +BOOL LLPngWrapper::readPng(U8* src, S32 dataSize, LLImageRaw* rawImage, ImageInfo *infop) { try { @@ -139,6 +145,7 @@ BOOL LLPngWrapper::readPng(U8* src, LLImageRaw* rawImage, ImageInfo *infop) PngDataInfo dataPtr; dataPtr.mData = src; dataPtr.mOffset = 0; + dataPtr.mDataSize = dataSize; png_set_read_fn(mReadPngPtr, &dataPtr, &readDataCallback); png_set_sig_bytes(mReadPngPtr, 0); @@ -252,6 +259,7 @@ void LLPngWrapper::normalizeImage() // Read out the image meta-data void LLPngWrapper::updateMetaData() { + png_set_interlace_handling(mReadPngPtr); // png_read_update_info(mReadPngPtr, mReadInfoPtr); mWidth = png_get_image_width(mReadPngPtr, mReadInfoPtr); mHeight = png_get_image_height(mReadPngPtr, mReadInfoPtr); diff --git a/indra/llimage/llpngwrapper.h b/indra/llimage/llpngwrapper.h index 5f3ad0d5a2..27d7df3bef 100644 --- a/indra/llimage/llpngwrapper.h +++ b/indra/llimage/llpngwrapper.h @@ -26,12 +26,7 @@ #ifndef LL_LLPNGWRAPPER_H #define LL_LLPNGWRAPPER_H -#ifdef LL_STANDALONE -#include -#else -// Workaround for wrongly packaged prebuilt. -#include "libpng15/png.h" -#endif +#include "png.h" #include "llimage.h" class LLPngWrapper @@ -49,7 +44,7 @@ class LLPngWrapper }; BOOL isValidPng(U8* src); - BOOL readPng(U8* src, LLImageRaw* rawImage, ImageInfo *infop = NULL); + BOOL readPng(U8* src, S32 dataSize, LLImageRaw* rawImage, ImageInfo *infop = NULL); BOOL writePng(const LLImageRaw* rawImage, U8* dst); U32 getFinalSize(); const std::string& getErrorMessage(); @@ -66,6 +61,7 @@ class LLPngWrapper { U8 *mData; U32 mOffset; + S32 mDataSize; }; static void writeFlush(png_structp png_ptr); diff --git a/indra/llimagej2coj/CMakeLists.txt b/indra/llimagej2coj/CMakeLists.txt index e8b87e5879..2d2a5c86fb 100644 --- a/indra/llimagej2coj/CMakeLists.txt +++ b/indra/llimagej2coj/CMakeLists.txt @@ -41,9 +41,11 @@ IF(WIN32) ENDIF(WIN32) add_library (llimagej2coj ${llimagej2coj_SOURCE_FILES}) -add_dependencies(llimagej2coj prepare) + target_link_libraries( llimagej2coj + PUBLIC + llcommon ${OPENJPEG_LIBRARIES} ) diff --git a/indra/llimagej2coj/llimagej2coj.cpp b/indra/llimagej2coj/llimagej2coj.cpp index 7de5ba69dd..bd88ac4df1 100644 --- a/indra/llimagej2coj/llimagej2coj.cpp +++ b/indra/llimagej2coj/llimagej2coj.cpp @@ -33,12 +33,7 @@ #include "lltimer.h" //#include "llmemory.h" -const char* fallbackEngineInfoLLImageJ2CImpl() -{ - static std::string version_string = std::string("OpenJPEG: ") + opj_version(); - return version_string.c_str(); -} - +// Factory function: see declaration in llimagej2c.cpp LLImageJ2CImpl* fallbackCreateLLImageJ2CImpl() { return new LLImageJ2COJ(); @@ -50,6 +45,13 @@ void fallbackDestroyLLImageJ2CImpl(LLImageJ2CImpl* impl) impl = NULL; } +const char* fallbackEngineInfoLLImageJ2CImpl() +{ + static std::string version_string = std::string("OpenJPEG: ") + + opj_version(); + return version_string.c_str(); +} + // Return string from message, eliminating final \n if present static std::string chomp(const char* msg) { @@ -71,21 +73,21 @@ sample error callback expecting a LLFILE* client object */ void error_callback(const char* msg, void*) { - lldebugs << "LLImageJ2COJ: " << chomp(msg) << llendl; + LL_DEBUGS() << "LLImageJ2COJ: " << chomp(msg) << LL_ENDL; } /** sample warning callback expecting a LLFILE* client object */ void warning_callback(const char* msg, void*) { - lldebugs << "LLImageJ2COJ: " << chomp(msg) << llendl; + LL_DEBUGS() << "LLImageJ2COJ: " << chomp(msg) << LL_ENDL; } /** sample debug callback expecting no client object */ void info_callback(const char* msg, void*) { - lldebugs << "LLImageJ2COJ: " << chomp(msg) << llendl; + LL_DEBUGS() << "LLImageJ2COJ: " << chomp(msg) << LL_ENDL; } // Divide a by 2 to the power of b and round upwards @@ -108,22 +110,57 @@ LLImageJ2COJ::~LLImageJ2COJ() BOOL LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count) { - // - // FIXME: Get the comment field out of the texture - // - LLTimer decode_timer; + /* Extract metadata */ + /* ---------------- */ + U8* c_data = base.getData(); + size_t c_size = base.getDataSize(); + size_t position = 0; + + while (position < 1024 && position < (c_size - 7)) // the comment field should be in the first 1024 bytes. + { + if (c_data[position] == 0xff && c_data[position + 1] == 0x64) + { + U8 high_byte = c_data[position + 2]; + U8 low_byte = c_data[position + 3]; + S32 c_length = (high_byte * 256) + low_byte; // This size also counts the markers, 00 01 and itself + if (c_length > 200) // sanity check + { + // While comments can be very long, anything longer then 200 is suspect. + break; + } + + if (position + 2 + c_length > c_size) + { + // comment extends past end of data, corruption, or all data not retrived yet. + break; + } + + // if the comment block does not end at the end of data, check to see if the next + // block starts with 0xFF + if (position + 2 + c_length < c_size && c_data[position + 2 + c_length] != 0xff) + { + // invalied comment block + break; + } + + // extract the comment minus the markers, 00 01 + raw_image.mComment.assign((char*)c_data + position + 6, c_length - 4); + break; + } + ++position; + } + opj_dparameters_t parameters; /* decompression parameters */ - opj_event_mgr_t event_mgr; /* event manager */ - opj_image_t *image = NULL; + opj_event_mgr_t event_mgr = { }; /* event manager */ + opj_image_t *image = nullptr; - opj_dinfo_t* dinfo = NULL; /* handle to a decompressor */ - opj_cio_t *cio = NULL; + opj_dinfo_t* dinfo = nullptr; /* handle to a decompressor */ + opj_cio_t *cio = nullptr; /* configure the event callbacks (not required) */ - memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); event_mgr.error_handler = error_callback; event_mgr.warning_handler = warning_callback; event_mgr.info_handler = info_callback; @@ -133,6 +170,26 @@ BOOL LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decod parameters.cp_reduce = base.getRawDiscardLevel(); + if(parameters.cp_reduce == 0 && *(U16*)(base.getData() + base.getDataSize() - 2) != 0xD9FF) + { + bool failed = true; + for(S32 i = base.getDataSize()-1; i > 42; --i) + { + if(base.getData()[i] != 0x00) + { + failed = *(U16*)(base.getData()+i-1) != 0xD9FF; + break; + } + } + if(failed) + { + opj_image_destroy(image); + base.decodeFailed(); + return TRUE; + } + } + + /* decode the code-stream */ /* ---------------------- */ @@ -148,19 +205,7 @@ BOOL LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decod opj_setup_decoder(dinfo, ¶meters); /* open a byte stream */ -#if 0 - std::vector data(base.getData(), base.getData()+base.getDataSize()); - S32 size = data.size(); - if (data[size-1] == 0xFF) { - data.push_back((U8)0xD9); - } else if (data[size-2] != 0xFF || data[size-1] != 0xD9) { - data.push_back((U8)0xFF); - data.push_back((U8)0xD9); - } - cio = opj_cio_open((opj_common_ptr)dinfo, &data[0], data.size()); -#else cio = opj_cio_open((opj_common_ptr)dinfo, base.getData(), base.getDataSize()); -#endif /* decode the stream and fill the image structure */ image = opj_decode(dinfo, cio); @@ -179,20 +224,11 @@ BOOL LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decod // dereference the array. if(!image || !image->numcomps) { - LL_WARNS("Texture") << "ERROR -> decodeImpl: failed to decode image!" << LL_ENDL; + LL_DEBUGS("Texture") << "ERROR -> decodeImpl: failed to decode image!" << LL_ENDL; if (image) { opj_image_destroy(image); } -#if 0 - std::stringstream filename; - filename << "err" << (int)base.getRawDiscardLevel() << "_" << rand() << ".jp2"; - FILE* file = fopen(filename.str().c_str(), "wb"); - if (file) { - fwrite(base.getData(), base.getDataSize(), 1, file); - fclose(file); - } -#endif base.decodeFailed(); return TRUE; // done } @@ -202,7 +238,6 @@ BOOL LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decod { if (image->comps[i].factor != base.getRawDiscardLevel()) { - LL_WARNS("Texture") << "Expected discard level not reached!" << llendl; // if we didn't get the discard level we're expecting, fail opj_image_destroy(image); base.decodeFailed(); @@ -212,7 +247,7 @@ BOOL LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decod if(image->numcomps <= first_channel) { - llwarns << "trying to decode more channels than are present in image: numcomps: " << image->numcomps << " first_channel: " << first_channel << llendl; + LL_WARNS("Texture") << "trying to decode more channels than are present in image: numcomps: " << image->numcomps << " first_channel: " << first_channel << LL_ENDL; if (image) { opj_image_destroy(image); @@ -242,6 +277,13 @@ BOOL LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decod S32 height = ceildivpow2(image->y1 - image->y0, f); raw_image.resize(width, height, channels); U8 *rawp = raw_image.getData(); + if (!rawp) + { + opj_image_destroy(image); + base.setLastError("Memory error"); + base.decodeFailed(); + return true; // done + } // first_channel is what channel to start copying from // dest is what channel to copy to. first_channel comes from the @@ -263,9 +305,11 @@ BOOL LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decod } else // Some rare OpenJPEG versions have this bug. { - LL_WARNS("Texture") << "ERROR -> decodeImpl: failed to decode image! (NULL comp data - OpenJPEG bug)" << llendl; - opj_image_destroy(image); - + LL_DEBUGS("Texture") << "ERROR -> decodeImpl: failed to decode image! (NULL comp data - OpenJPEG bug)" << LL_ENDL; + if (image) + { + opj_image_destroy(image); + } base.decodeFailed(); return TRUE; // done } @@ -282,14 +326,13 @@ BOOL LLImageJ2COJ::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, con { const S32 MAX_COMPS = 5; opj_cparameters_t parameters; /* compression parameters */ - opj_event_mgr_t event_mgr; /* event manager */ + opj_event_mgr_t event_mgr = { }; /* event manager */ /* configure the event callbacks (not required) setting of each callback is optional */ - memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); event_mgr.error_handler = error_callback; event_mgr.warning_handler = warning_callback; event_mgr.info_handler = info_callback; @@ -334,7 +377,7 @@ BOOL LLImageJ2COJ::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, con // OPJ_COLOR_SPACE color_space = CLRSPC_SRGB; opj_image_cmptparm_t cmptparm[MAX_COMPS]; - opj_image_t * image = NULL; + opj_image_t * image = nullptr; S32 numcomps = llmin((S32)raw_image.getComponents(), MAX_COMPS); S32 width = raw_image.getWidth(); S32 height = raw_image.getHeight(); @@ -378,7 +421,7 @@ BOOL LLImageJ2COJ::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, con /* ---------------------------- */ int codestream_length; - opj_cio_t *cio = NULL; + opj_cio_t *cio = nullptr; /* get a J2K compressor handle */ opj_cinfo_t* cinfo = opj_create_compress(CODEC_J2K); @@ -391,14 +434,14 @@ BOOL LLImageJ2COJ::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, con /* open a byte stream for writing */ /* allocate memory for all tiles */ - cio = opj_cio_open((opj_common_ptr)cinfo, NULL, 0); + cio = opj_cio_open((opj_common_ptr)cinfo, nullptr, 0); /* encode the image */ - bool bSuccess = opj_encode(cinfo, cio, image, NULL); + bool bSuccess = opj_encode(cinfo, cio, image, nullptr); if (!bSuccess) { opj_cio_close(cio); - LL_WARNS("Texture") << "Failed to encode image." << llendl; + LL_DEBUGS("Texture") << "Failed to encode image." << LL_ENDL; return FALSE; } codestream_length = cio_tell(cio); @@ -500,15 +543,14 @@ BOOL LLImageJ2COJ::getMetadata(LLImageJ2C &base) // Do it the old and slow way, decode the image with openjpeg opj_dparameters_t parameters; /* decompression parameters */ - opj_event_mgr_t event_mgr; /* event manager */ - opj_image_t *image = NULL; + opj_event_mgr_t event_mgr = { }; /* event manager */ + opj_image_t *image = nullptr; - opj_dinfo_t* dinfo = NULL; /* handle to a decompressor */ - opj_cio_t *cio = NULL; + opj_dinfo_t* dinfo = nullptr; /* handle to a decompressor */ + opj_cio_t *cio = nullptr; /* configure the event callbacks (not required) */ - memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); event_mgr.error_handler = error_callback; event_mgr.warning_handler = warning_callback; event_mgr.info_handler = info_callback; @@ -552,7 +594,7 @@ BOOL LLImageJ2COJ::getMetadata(LLImageJ2C &base) if(!image) { - llwarns << "ERROR -> getMetadata: failed to decode image!" << llendl; + LL_WARNS() << "ERROR -> getMetadata: failed to decode image!" << LL_ENDL; return FALSE; } diff --git a/indra/llinventory/CMakeLists.txt b/indra/llinventory/CMakeLists.txt index afd5de34f8..71909dc093 100644 --- a/indra/llinventory/CMakeLists.txt +++ b/indra/llinventory/CMakeLists.txt @@ -17,15 +17,20 @@ include_directories( set(llinventory_SOURCE_FILES llcategory.cpp - lleconomy.cpp + llfoldertype.cpp llinventory.cpp llinventorydefines.cpp + llinventorysettings.cpp llinventorytype.cpp lllandmark.cpp llnotecard.cpp llparcel.cpp llpermissions.cpp llsaleinfo.cpp + llsettingsbase.cpp + llsettingsdaycycle.cpp + llsettingssky.cpp + llsettingswater.cpp lltransactionflags.cpp lluserrelations.cpp ) @@ -34,10 +39,12 @@ set(llinventory_HEADER_FILES CMakeLists.txt llcategory.h - lleconomy.h + llfoldertype.h llinventory.h llinventorydefines.h + llinventorysettings.h llinventorytype.h + llinvtranslationbrdg.h lllandmark.h llnotecard.h llparcel.h @@ -45,6 +52,10 @@ set(llinventory_HEADER_FILES llpermissions.h llpermissionsflags.h llsaleinfo.h + llsettingsbase.h + llsettingsdaycycle.h + llsettingssky.h + llsettingswater.h lltransactionflags.h lltransactiontypes.h lluserrelations.h @@ -56,4 +67,9 @@ set_source_files_properties(${llinventory_HEADER_FILES} list(APPEND llinventory_SOURCE_FILES ${llinventory_HEADER_FILES}) add_library (llinventory ${llinventory_SOURCE_FILES}) -add_dependencies(llinventory prepare) + +target_link_libraries( + llinventory + PUBLIC + llcommon + ) diff --git a/indra/llinventory/llcategory.h b/indra/llinventory/llcategory.h index c8e2dac30d..378cd0d8d1 100644 --- a/indra/llinventory/llcategory.h +++ b/indra/llinventory/llcategory.h @@ -49,7 +49,7 @@ // S32 count = LLCategory::none.getSubCategoryCount(); // for(S32 i = 0; i < count; i++) // { -// llinfos << none.getSubCategory(i).lookupNmae() << llendl; +// LL_INFOS() << none.getSubCategory(i).lookupNmae() << LL_ENDL; // } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/indra/llinventory/lleconomy.cpp b/indra/llinventory/lleconomy.cpp deleted file mode 100644 index d643ea6ed9..0000000000 --- a/indra/llinventory/lleconomy.cpp +++ /dev/null @@ -1,288 +0,0 @@ -/** - * @file lleconomy.cpp - * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include "lleconomy.h" -#include "llerror.h" -#include "message.h" -#include "v3math.h" - - -LLGlobalEconomy::LLGlobalEconomy() -: mObjectCount( -1 ), - mObjectCapacity( -1 ), - mPriceObjectClaim( -1 ), - mPricePublicObjectDecay( -1 ), - mPricePublicObjectDelete( -1 ), - mPriceEnergyUnit( -1 ), - mPriceUpload( -1 ), - mPriceRentLight( -1 ), - mTeleportMinPrice( -1 ), - mTeleportPriceExponent( -1 ), - mPriceGroupCreate( -1 ) -{ } - -LLGlobalEconomy::~LLGlobalEconomy() -{ } - -void LLGlobalEconomy::addObserver(LLEconomyObserver* observer) -{ - mObservers.push_back(observer); -} - -void LLGlobalEconomy::removeObserver(LLEconomyObserver* observer) -{ - std::list::iterator it = - std::find(mObservers.begin(), mObservers.end(), observer); - if (it != mObservers.end()) - { - mObservers.erase(it); - } -} - -void LLGlobalEconomy::notifyObservers() -{ - for (std::list::iterator it = mObservers.begin(); - it != mObservers.end(); - ++it) - { - (*it)->onEconomyDataChange(); - } -} - -// static -void LLGlobalEconomy::processEconomyData(LLMessageSystem *msg, LLGlobalEconomy* econ_data) -{ - S32 i; - F32 f; - - msg->getS32Fast(_PREHASH_Info, _PREHASH_ObjectCapacity, i); - econ_data->setObjectCapacity(i); - msg->getS32Fast(_PREHASH_Info, _PREHASH_ObjectCount, i); - econ_data->setObjectCount(i); - msg->getS32Fast(_PREHASH_Info, _PREHASH_PriceEnergyUnit, i); - econ_data->setPriceEnergyUnit(i); - msg->getS32Fast(_PREHASH_Info, _PREHASH_PriceObjectClaim, i); - econ_data->setPriceObjectClaim(i); - msg->getS32Fast(_PREHASH_Info, _PREHASH_PricePublicObjectDecay, i); - econ_data->setPricePublicObjectDecay(i); - msg->getS32Fast(_PREHASH_Info, _PREHASH_PricePublicObjectDelete, i); - econ_data->setPricePublicObjectDelete(i); - msg->getS32Fast(_PREHASH_Info, _PREHASH_PriceUpload, i); - econ_data->setPriceUpload(i); -#if LL_LINUX - // We can optionally fake the received upload price for testing. - // Note that the server is within its rights to not obey our fake - // price. :) - const char* fakeprice_str = getenv("LL_FAKE_UPLOAD_PRICE"); - if (fakeprice_str) - { - S32 fakeprice = (S32)atoi(fakeprice_str); - llwarns << "LL_FAKE_UPLOAD_PRICE: Faking upload price as L$" << fakeprice << llendl; - econ_data->setPriceUpload(fakeprice); - } -#endif - msg->getS32Fast(_PREHASH_Info, _PREHASH_PriceRentLight, i); - econ_data->setPriceRentLight(i); - msg->getS32Fast(_PREHASH_Info, _PREHASH_TeleportMinPrice, i); - econ_data->setTeleportMinPrice(i); - msg->getF32Fast(_PREHASH_Info, _PREHASH_TeleportPriceExponent, f); - econ_data->setTeleportPriceExponent(f); - msg->getS32Fast(_PREHASH_Info, _PREHASH_PriceGroupCreate, i); - econ_data->setPriceGroupCreate(i); - - econ_data->notifyObservers(); -} - -S32 LLGlobalEconomy::calculateTeleportCost(F32 distance) const -{ - S32 min_cost = getTeleportMinPrice(); - F32 exponent = getTeleportPriceExponent(); - F32 divisor = 100.f * pow(3.f, exponent); - S32 cost = (U32)(distance * pow(log10(distance), exponent) / divisor); - if (cost < 0) - { - cost = 0; - } - else if (cost < min_cost) - { - cost = min_cost; - } - - return cost; -} - -S32 LLGlobalEconomy::calculateLightRent(const LLVector3& object_size) const -{ - F32 intensity_mod = llmax(object_size.magVec(), 1.f); - return (S32)(intensity_mod * getPriceRentLight()); -} - -void LLGlobalEconomy::print() -{ - llinfos << "Global Economy Settings: " << llendl; - llinfos << "Object Capacity: " << mObjectCapacity << llendl; - llinfos << "Object Count: " << mObjectCount << llendl; - llinfos << "Claim Price Per Object: " << mPriceObjectClaim << llendl; - llinfos << "Claim Price Per Public Object: " << mPricePublicObjectDecay << llendl; - llinfos << "Delete Price Per Public Object: " << mPricePublicObjectDelete << llendl; - llinfos << "Release Price Per Public Object: " << getPricePublicObjectRelease() << llendl; - llinfos << "Price Per Energy Unit: " << mPriceEnergyUnit << llendl; - llinfos << "Price Per Upload: " << mPriceUpload << llendl; - llinfos << "Light Base Price: " << mPriceRentLight << llendl; - llinfos << "Teleport Min Price: " << mTeleportMinPrice << llendl; - llinfos << "Teleport Price Exponent: " << mTeleportPriceExponent << llendl; - llinfos << "Price for group creation: " << mPriceGroupCreate << llendl; -} - -LLRegionEconomy::LLRegionEconomy() -: LLGlobalEconomy(), - mPriceObjectRent( -1.f ), - mPriceObjectScaleFactor( -1.f ), - mEnergyEfficiency( -1.f ), - mBasePriceParcelClaimDefault(-1), - mBasePriceParcelClaimActual(-1), - mPriceParcelClaimFactor(-1.f), - mBasePriceParcelRent(-1), - mAreaOwned(-1.f), - mAreaTotal(-1.f) -{ } - -LLRegionEconomy::~LLRegionEconomy() -{ } - -BOOL LLRegionEconomy::hasData() const -{ - return (mBasePriceParcelRent != -1); -} - -// static -void LLRegionEconomy::processEconomyData(LLMessageSystem *msg, void** user_data) -{ - S32 i; - F32 f; - - LLRegionEconomy *this_ptr = (LLRegionEconomy*)user_data; - - LLGlobalEconomy::processEconomyData(msg, this_ptr); - - msg->getS32Fast(_PREHASH_Info, _PREHASH_PriceParcelClaim, i); - this_ptr->setBasePriceParcelClaimDefault(i); - msg->getF32(_PREHASH_Info, _PREHASH_PriceParcelClaimFactor, f); - this_ptr->setPriceParcelClaimFactor(f); - msg->getF32Fast(_PREHASH_Info, _PREHASH_EnergyEfficiency, f); - this_ptr->setEnergyEfficiency(f); - msg->getF32Fast(_PREHASH_Info, _PREHASH_PriceObjectRent, f); - this_ptr->setPriceObjectRent(f); - msg->getF32Fast(_PREHASH_Info, _PREHASH_PriceObjectScaleFactor, f); - this_ptr->setPriceObjectScaleFactor(f); - msg->getS32Fast(_PREHASH_Info, _PREHASH_PriceParcelRent, i); - this_ptr->setBasePriceParcelRent(i); -} - -// static -void LLRegionEconomy::processEconomyDataRequest(LLMessageSystem *msg, void **user_data) -{ - LLRegionEconomy *this_ptr = (LLRegionEconomy*)user_data; - if (!this_ptr->hasData()) - { - llwarns << "Dropping EconomyDataRequest, because EconomyData message " - << "has not been processed" << llendl; - } - - msg->newMessageFast(_PREHASH_EconomyData); - msg->nextBlockFast(_PREHASH_Info); - msg->addS32Fast(_PREHASH_ObjectCapacity, this_ptr->getObjectCapacity()); - msg->addS32Fast(_PREHASH_ObjectCount, this_ptr->getObjectCount()); - msg->addS32Fast(_PREHASH_PriceEnergyUnit, this_ptr->getPriceEnergyUnit()); - msg->addS32Fast(_PREHASH_PriceObjectClaim, this_ptr->getPriceObjectClaim()); - msg->addS32Fast(_PREHASH_PricePublicObjectDecay, this_ptr->getPricePublicObjectDecay()); - msg->addS32Fast(_PREHASH_PricePublicObjectDelete, this_ptr->getPricePublicObjectDelete()); - msg->addS32Fast(_PREHASH_PriceParcelClaim, this_ptr->mBasePriceParcelClaimActual); - msg->addF32Fast(_PREHASH_PriceParcelClaimFactor, this_ptr->mPriceParcelClaimFactor); - msg->addS32Fast(_PREHASH_PriceUpload, this_ptr->getPriceUpload()); - msg->addS32Fast(_PREHASH_PriceRentLight, this_ptr->getPriceRentLight()); - msg->addS32Fast(_PREHASH_TeleportMinPrice, this_ptr->getTeleportMinPrice()); - msg->addF32Fast(_PREHASH_TeleportPriceExponent, this_ptr->getTeleportPriceExponent()); - - msg->addF32Fast(_PREHASH_EnergyEfficiency, this_ptr->getEnergyEfficiency()); - msg->addF32Fast(_PREHASH_PriceObjectRent, this_ptr->getPriceObjectRent()); - msg->addF32Fast(_PREHASH_PriceObjectScaleFactor, this_ptr->getPriceObjectScaleFactor()); - msg->addS32Fast(_PREHASH_PriceParcelRent, this_ptr->getPriceParcelRent()); - msg->addS32Fast(_PREHASH_PriceGroupCreate, this_ptr->getPriceGroupCreate()); - - msg->sendReliable(msg->getSender()); -} - - -S32 LLRegionEconomy::getPriceParcelClaim() const -{ - //return (S32)((F32)mBasePriceParcelClaim * (mAreaTotal / (mAreaTotal - mAreaOwned))); - return (S32)((F32)mBasePriceParcelClaimActual * mPriceParcelClaimFactor); -} - -S32 LLRegionEconomy::getPriceParcelRent() const -{ - return mBasePriceParcelRent; -} - - -void LLRegionEconomy::print() -{ - this->LLGlobalEconomy::print(); - - llinfos << "Region Economy Settings: " << llendl; - llinfos << "Land (square meters): " << mAreaTotal << llendl; - llinfos << "Owned Land (square meters): " << mAreaOwned << llendl; - llinfos << "Daily Object Rent: " << mPriceObjectRent << llendl; - llinfos << "Daily Land Rent (per meter): " << getPriceParcelRent() << llendl; - llinfos << "Energey Efficiency: " << mEnergyEfficiency << llendl; -} - - -void LLRegionEconomy::setBasePriceParcelClaimDefault(S32 val) -{ - mBasePriceParcelClaimDefault = val; - if(mBasePriceParcelClaimActual == -1) - { - mBasePriceParcelClaimActual = val; - } -} - -void LLRegionEconomy::setBasePriceParcelClaimActual(S32 val) -{ - mBasePriceParcelClaimActual = val; -} - -void LLRegionEconomy::setPriceParcelClaimFactor(F32 val) -{ - mPriceParcelClaimFactor = val; -} - -void LLRegionEconomy::setBasePriceParcelRent(S32 val) -{ - mBasePriceParcelRent = val; -} diff --git a/indra/llinventory/lleconomy.h b/indra/llinventory/lleconomy.h deleted file mode 100644 index eb2ecf71ba..0000000000 --- a/indra/llinventory/lleconomy.h +++ /dev/null @@ -1,159 +0,0 @@ -/** - * @file lleconomy.h - * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLECONOMY_H -#define LL_LLECONOMY_H - -#include "llsingleton.h" - -class LLMessageSystem; -class LLVector3; - -/** - * Register an observer to be notified of economy data updates coming from server. - */ -class LLEconomyObserver -{ -public: - virtual ~LLEconomyObserver() {} - virtual void onEconomyDataChange() = 0; -}; - -class LLGlobalEconomy -{ -public: - LLGlobalEconomy(); - virtual ~LLGlobalEconomy(); - - // This class defines its singleton internally as a typedef instead of inheriting from - // LLSingleton like most others because the LLRegionEconomy sub-class might also - // become a singleton and this pattern will more easily disambiguate them. - typedef LLSingleton Singleton; - - void initSingleton() { } - - virtual void print(); - - void addObserver(LLEconomyObserver* observer); - void removeObserver(LLEconomyObserver* observer); - void notifyObservers(); - - static void processEconomyData(LLMessageSystem *msg, LLGlobalEconomy* econ_data); - - S32 calculateTeleportCost(F32 distance) const; - S32 calculateLightRent(const LLVector3& object_size) const; - - S32 getObjectCount() const { return mObjectCount; } - S32 getObjectCapacity() const { return mObjectCapacity; } - S32 getPriceObjectClaim() const { return mPriceObjectClaim; } - S32 getPricePublicObjectDecay() const { return mPricePublicObjectDecay; } - S32 getPricePublicObjectDelete() const { return mPricePublicObjectDelete; } - S32 getPricePublicObjectRelease() const { return mPriceObjectClaim - mPricePublicObjectDelete; } - S32 getPriceEnergyUnit() const { return mPriceEnergyUnit; } - S32 getPriceUpload() const { return mPriceUpload; } - S32 getPriceRentLight() const { return mPriceRentLight; } - S32 getTeleportMinPrice() const { return mTeleportMinPrice; } - F32 getTeleportPriceExponent() const { return mTeleportPriceExponent; } - S32 getPriceGroupCreate() const { return mPriceGroupCreate; } - - - void setObjectCount(S32 val) { mObjectCount = val; } - void setObjectCapacity(S32 val) { mObjectCapacity = val; } - void setPriceObjectClaim(S32 val) { mPriceObjectClaim = val; } - void setPricePublicObjectDecay(S32 val) { mPricePublicObjectDecay = val; } - void setPricePublicObjectDelete(S32 val) { mPricePublicObjectDelete = val; } - void setPriceEnergyUnit(S32 val) { mPriceEnergyUnit = val; } - void setPriceUpload(S32 val) { mPriceUpload = val; } - void setPriceRentLight(S32 val) { mPriceRentLight = val; } - void setTeleportMinPrice(S32 val) { mTeleportMinPrice = val; } - void setTeleportPriceExponent(F32 val) { mTeleportPriceExponent = val; } - void setPriceGroupCreate(S32 val) { mPriceGroupCreate = val; } - -private: - S32 mObjectCount; - S32 mObjectCapacity; - S32 mPriceObjectClaim; // per primitive - S32 mPricePublicObjectDecay; // per primitive - S32 mPricePublicObjectDelete; // per primitive - S32 mPriceEnergyUnit; - S32 mPriceUpload; - S32 mPriceRentLight; - S32 mTeleportMinPrice; - F32 mTeleportPriceExponent; - S32 mPriceGroupCreate; - - std::list mObservers; -}; - - -class LLRegionEconomy : public LLGlobalEconomy -{ -public: - LLRegionEconomy(); - ~LLRegionEconomy(); - - static void processEconomyData(LLMessageSystem *msg, void **user_data); - static void processEconomyDataRequest(LLMessageSystem *msg, void **user_data); - - void print(); - - BOOL hasData() const; - F32 getPriceObjectRent() const { return mPriceObjectRent; } - F32 getPriceObjectScaleFactor() const {return mPriceObjectScaleFactor;} - F32 getEnergyEfficiency() const { return mEnergyEfficiency; } - S32 getPriceParcelClaim() const; - S32 getPriceParcelRent() const; - F32 getAreaOwned() const { return mAreaOwned; } - F32 getAreaTotal() const { return mAreaTotal; } - S32 getBasePriceParcelClaimActual() const { return mBasePriceParcelClaimActual; } - - void setPriceObjectRent(F32 val) { mPriceObjectRent = val; } - void setPriceObjectScaleFactor(F32 val) { mPriceObjectScaleFactor = val; } - void setEnergyEfficiency(F32 val) { mEnergyEfficiency = val; } - - void setBasePriceParcelClaimDefault(S32 val); - void setBasePriceParcelClaimActual(S32 val); - void setPriceParcelClaimFactor(F32 val); - void setBasePriceParcelRent(S32 val); - - void setAreaOwned(F32 val) { mAreaOwned = val; } - void setAreaTotal(F32 val) { mAreaTotal = val; } - -private: - F32 mPriceObjectRent; - F32 mPriceObjectScaleFactor; - F32 mEnergyEfficiency; - - S32 mBasePriceParcelClaimDefault; - S32 mBasePriceParcelClaimActual; - F32 mPriceParcelClaimFactor; - S32 mBasePriceParcelRent; - - F32 mAreaOwned; - F32 mAreaTotal; - -}; - -#endif diff --git a/indra/llcommon/llfoldertype.cpp b/indra/llinventory/llfoldertype.cpp similarity index 91% rename from indra/llcommon/llfoldertype.cpp rename to indra/llinventory/llfoldertype.cpp index 280606b4f6..f0a865f0d4 100644 --- a/indra/llcommon/llfoldertype.cpp +++ b/indra/llinventory/llfoldertype.cpp @@ -101,7 +101,16 @@ LLFolderDictionary::LLFolderDictionary() addEntry(LLFolderType::FT_INBOX, new FolderEntry("inbox", TRUE)); addEntry(LLFolderType::FT_OUTBOX, new FolderEntry("outbox", TRUE)); + addEntry(LLFolderType::FT_BASIC_ROOT, new FolderEntry("basic_rt", TRUE)); + + addEntry(LLFolderType::FT_MARKETPLACE_LISTINGS, new FolderEntry("merchant", TRUE)); + addEntry(LLFolderType::FT_MARKETPLACE_STOCK, new FolderEntry("stock", FALSE)); + addEntry(LLFolderType::FT_MARKETPLACE_VERSION, new FolderEntry("version", FALSE)); + + addEntry(LLFolderType::FT_SETTINGS, new FolderEntry("settings", TRUE)); + + addEntry(LLFolderType::FT_SUITCASE, new FolderEntry("suitcase", TRUE)); addEntry(LLFolderType::FT_NONE, new FolderEntry("-1", FALSE)); }; @@ -152,7 +161,7 @@ LLAssetType::EType LLFolderType::folderTypeToAssetType(LLFolderType::EType folde { if (LLAssetType::lookup(LLAssetType::EType(folder_type)) == LLAssetType::badLookup()) { - llwarns << "Converting to unknown asset type " << folder_type << llendl; + LL_WARNS() << "Converting to unknown asset type " << folder_type << LL_ENDL; } return (LLAssetType::EType)folder_type; } @@ -162,7 +171,7 @@ LLFolderType::EType LLFolderType::assetTypeToFolderType(LLAssetType::EType asset { if (LLFolderType::lookup(LLFolderType::EType(asset_type)) == LLFolderType::badLookup()) { - llwarns << "Converting to unknown folder type " << asset_type << llendl; + LL_WARNS() << "Converting to unknown folder type " << asset_type << LL_ENDL; } return (LLFolderType::EType)asset_type; } diff --git a/indra/llcommon/llfoldertype.h b/indra/llinventory/llfoldertype.h similarity index 91% rename from indra/llcommon/llfoldertype.h rename to indra/llinventory/llfoldertype.h index 7e7cfa2b9f..5f41578dd3 100644 --- a/indra/llcommon/llfoldertype.h +++ b/indra/llinventory/llfoldertype.h @@ -39,7 +39,7 @@ // This class handles folder types (similar to assettype, except for folders) // and operations on those. -class LL_COMMON_API LLFolderType +class LLFolderType { public: // ! BACKWARDS COMPATIBILITY ! Folder type enums must match asset type enums. @@ -94,6 +94,14 @@ class LL_COMMON_API LLFolderType FT_BASIC_ROOT = 52, + FT_MARKETPLACE_LISTINGS = 53, + FT_MARKETPLACE_STOCK = 54, + FT_MARKETPLACE_VERSION = 55, // Note: We actually *never* create folders with that type. This is used for icon override only. + + FT_SETTINGS = 56, + + FT_SUITCASE = 100, + FT_COUNT, FT_NONE = -1 diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp index 5e8b9e22a1..e14ae90271 100644 --- a/indra/llinventory/llinventory.cpp +++ b/indra/llinventory/llinventory.cpp @@ -34,7 +34,6 @@ #include "llsd.h" #include "message.h" #include -#include "../newview/hippogridmanager.h" #include "llsdutil.h" @@ -52,6 +51,7 @@ static const std::string INV_DESC_LABEL("desc"); static const std::string INV_PERMISSIONS_LABEL("permissions"); static const std::string INV_SHADOW_ID_LABEL("shadow_id"); static const std::string INV_ASSET_ID_LABEL("asset_id"); +static const std::string INV_LINKED_ID_LABEL("linked_id"); static const std::string INV_SALE_INFO_LABEL("sale_info"); static const std::string INV_FLAGS_LABEL("flags"); static const std::string INV_CREATION_DATE_LABEL("created_at"); @@ -77,13 +77,15 @@ LLInventoryObject::LLInventoryObject(const LLUUID& uuid, mUUID(uuid), mParentUUID(parent_uuid), mType(type), - mName(name) + mName(name), + mCreationDate(0) { correctInventoryName(mName); } LLInventoryObject::LLInventoryObject() : - mType(LLAssetType::AT_NONE) + mType(LLAssetType::AT_NONE), + mCreationDate(0) { } @@ -178,7 +180,7 @@ BOOL LLInventoryObject::importLegacyStream(std::istream& input_stream) while(input_stream.good()) { input_stream.getline(buffer, MAX_STRING); - sscanf(buffer, " %254s %254s", keyword, valuestr); /* Flawfinder: ignore */ + if (sscanf(buffer, " %254s %254s", keyword, valuestr) < 1) continue; if(0 == strcmp("{",keyword)) { continue; @@ -212,8 +214,8 @@ BOOL LLInventoryObject::importLegacyStream(std::istream& input_stream) } else { - llwarns << "unknown keyword '" << keyword - << "' in LLInventoryObject::importLegacyStream() for object " << mUUID << llendl; + LL_WARNS() << "unknown keyword '" << keyword + << "' in LLInventoryObject::importLegacyStream() for object " << mUUID << LL_ENDL; } } return TRUE; @@ -249,26 +251,19 @@ BOOL LLInventoryObject::exportLegacyStream(std::ostream& output_stream, BOOL) co return TRUE; } - -void LLInventoryObject::removeFromServer() -{ - // don't do nothin' - llwarns << "LLInventoryObject::removeFromServer() called. Doesn't do anything." << llendl; -} - void LLInventoryObject::updateParentOnServer(BOOL) const { // don't do nothin' - llwarns << "LLInventoryObject::updateParentOnServer() called. Doesn't do anything." << llendl; + LL_WARNS() << "LLInventoryObject::updateParentOnServer() called. Doesn't do anything." << LL_ENDL; } void LLInventoryObject::updateServer(BOOL) const { // don't do nothin' - llwarns << "LLInventoryObject::updateServer() called. Doesn't do anything." << llendl; + LL_WARNS() << "LLInventoryObject::updateServer() called. Doesn't do anything." << LL_ENDL; } -inline +// inline void LLInventoryObject::correctInventoryName(std::string& name) { LLStringUtil::replaceNonstandardASCII(name, ' '); @@ -277,6 +272,25 @@ void LLInventoryObject::correctInventoryName(std::string& name) LLStringUtil::truncate(name, DB_INV_ITEM_NAME_STR_LEN); } +time_t LLInventoryObject::getCreationDate() const +{ + return mCreationDate; +} + +void LLInventoryObject::setCreationDate(time_t creation_date_utc) +{ + mCreationDate = creation_date_utc; +} + +const std::string& LLInventoryItem::getDescription() const +{ + return mDescription; +} + +const std::string& LLInventoryItem::getActualDescription() const +{ + return mDescription; +} ///---------------------------------------------------------------------------- /// Class LLInventoryItem @@ -299,9 +313,9 @@ LLInventoryItem::LLInventoryItem(const LLUUID& uuid, mDescription(desc), mSaleInfo(sale_info), mInventoryType(inv_type), - mFlags(flags), - mCreationDate(creation_date_utc) + mFlags(flags) { + mCreationDate = creation_date_utc; LLStringUtil::replaceNonstandardASCII(mDescription, ' '); LLStringUtil::replaceChar(mDescription, '|', ' '); mPermissions.initMasks(inv_type); @@ -314,9 +328,9 @@ LLInventoryItem::LLInventoryItem() : mDescription(), mSaleInfo(), mInventoryType(LLInventoryType::IT_NONE), - mFlags(0), - mCreationDate(0) + mFlags(0) { + mCreationDate = (time_t)0; } LLInventoryItem::LLInventoryItem(const LLInventoryItem* other) : @@ -376,53 +390,43 @@ void LLInventoryItem::setAssetUUID(const LLUUID& asset_id) } -const std::string& LLInventoryItem::getDescription() const -{ - return mDescription; -} - -const std::string& LLInventoryItem::getActualDescription() const -{ - return mDescription; -} - -time_t LLInventoryItem::getCreationDate() const -{ - return mCreationDate; -} - U32 LLInventoryItem::getCRC32() const { // *FIX: Not a real crc - more of a checksum. // *NOTE: We currently do not validate the name or description, // but if they change in transit, it's no big deal. U32 crc = mUUID.getCRC32(); - //lldebugs << "1 crc: " << std::hex << crc << std::dec << llendl; + //LL_DEBUGS() << "1 crc: " << std::hex << crc << std::dec << LL_ENDL; crc += mParentUUID.getCRC32(); - //lldebugs << "2 crc: " << std::hex << crc << std::dec << llendl; + //LL_DEBUGS() << "2 crc: " << std::hex << crc << std::dec << LL_ENDL; crc += mPermissions.getCRC32(); - //lldebugs << "3 crc: " << std::hex << crc << std::dec << llendl; + //LL_DEBUGS() << "3 crc: " << std::hex << crc << std::dec << LL_ENDL; crc += mAssetUUID.getCRC32(); - //lldebugs << "4 crc: " << std::hex << crc << std::dec << llendl; + //LL_DEBUGS() << "4 crc: " << std::hex << crc << std::dec << LL_ENDL; crc += mType; - //lldebugs << "5 crc: " << std::hex << crc << std::dec << llendl; + //LL_DEBUGS() << "5 crc: " << std::hex << crc << std::dec << LL_ENDL; crc += mInventoryType; - //lldebugs << "6 crc: " << std::hex << crc << std::dec << llendl; + //LL_DEBUGS() << "6 crc: " << std::hex << crc << std::dec << LL_ENDL; crc += mFlags; - //lldebugs << "7 crc: " << std::hex << crc << std::dec << llendl; + //LL_DEBUGS() << "7 crc: " << std::hex << crc << std::dec << LL_ENDL; crc += mSaleInfo.getCRC32(); - //lldebugs << "8 crc: " << std::hex << crc << std::dec << llendl; + //LL_DEBUGS() << "8 crc: " << std::hex << crc << std::dec << LL_ENDL; crc += (U32)mCreationDate; - //lldebugs << "9 crc: " << std::hex << crc << std::dec << llendl; + //LL_DEBUGS() << "9 crc: " << std::hex << crc << std::dec << LL_ENDL; return crc; } +// static +void LLInventoryItem::correctInventoryDescription(std::string& desc) +{ + LLStringUtil::replaceNonstandardASCII(desc, ' '); + LLStringUtil::replaceChar(desc, '|', ' '); +} void LLInventoryItem::setDescription(const std::string& d) { std::string new_desc(d); - LLStringUtil::replaceNonstandardASCII(new_desc, ' '); - LLStringUtil::replaceChar(new_desc, '|', ' '); + LLInventoryItem::correctInventoryDescription(new_desc); if( new_desc != mDescription ) { mDescription = new_desc; @@ -447,11 +451,6 @@ void LLInventoryItem::setFlags(U32 flags) mFlags = flags; } -void LLInventoryItem::setCreationDate(time_t creation_date_utc) -{ - mCreationDate = creation_date_utc; -} - // Currently only used in the Viewer to handle calling cards // where the creator is actually used to store the target. void LLInventoryItem::setCreator(const LLUUID& creator) @@ -513,6 +512,12 @@ U32 LLInventoryItem::getFlags() const return mFlags; } +time_t LLInventoryItem::getCreationDate() const +{ + return mCreationDate; +} + + // virtual void LLInventoryItem::packMessage(LLMessageSystem* msg) const { @@ -544,10 +549,6 @@ BOOL LLInventoryItem::unpackMessage(LLMessageSystem* msg, const char* block, S32 S8 type; msg->getS8Fast(block, _PREHASH_Type, type, block_num); mType = static_cast(type); - if (mType == LLAssetType::AT_LINK || mType == LLAssetType::AT_LINK_FOLDER) - { - gHippoGridManager->getConnectedGrid()->setSupportsInvLinks(true); - } msg->getS8(block, "InvType", type, block_num); mInventoryType = static_cast(type); mPermissions.initMasks(mInventoryType); @@ -573,13 +574,13 @@ BOOL LLInventoryItem::unpackMessage(LLMessageSystem* msg, const char* block, S32 #ifdef CRC_CHECK if(local_crc == remote_crc) { - lldebugs << "crc matches" << llendl; + LL_DEBUGS() << "crc matches" << LL_ENDL; return TRUE; } else { - llwarns << "inventory crc mismatch: local=" << std::hex << local_crc - << " remote=" << remote_crc << std::dec << llendl; + LL_WARNS() << "inventory crc mismatch: local=" << std::hex << local_crc + << " remote=" << remote_crc << std::dec << LL_ENDL; return FALSE; } #else @@ -610,7 +611,7 @@ BOOL LLInventoryItem::importFile(LLFILE* fp) buffer[0] = '\0'; } - sscanf(buffer, " %254s %254s", keyword, valuestr); /* Flawfinder: ignore */ + if (sscanf(buffer, " %254s %254s", keyword, valuestr) < 1) continue; if(0 == strcmp("{",keyword)) { continue; @@ -715,7 +716,7 @@ BOOL LLInventoryItem::importFile(LLFILE* fp) const char *donkey = mDescription.c_str(); if (donkey[0] == '|') { - llerrs << "Donkey" << llendl; + LL_ERRS() << "Donkey" << LL_ENDL; } */ } @@ -727,8 +728,8 @@ BOOL LLInventoryItem::importFile(LLFILE* fp) } else { - llwarns << "unknown keyword '" << keyword - << "' in inventory import of item " << mUUID << llendl; + LL_WARNS() << "unknown keyword '" << keyword + << "' in inventory import of item " << mUUID << LL_ENDL; } } @@ -738,7 +739,7 @@ BOOL LLInventoryItem::importFile(LLFILE* fp) if((LLInventoryType::IT_NONE == mInventoryType) || !inventory_and_asset_types_match(mInventoryType, mType)) { - lldebugs << "Resetting inventory type for " << mUUID << llendl; + LL_DEBUGS() << "Resetting inventory type for " << mUUID << LL_ENDL; mInventoryType = LLInventoryType::defaultForAssetType(mType); } @@ -813,10 +814,10 @@ BOOL LLInventoryItem::importLegacyStream(std::istream& input_stream) while(success && input_stream.good()) { input_stream.getline(buffer, MAX_STRING); - sscanf( /* Flawfinder: ignore */ + if (sscanf( buffer, " %254s %254s", - keyword, valuestr); + keyword, valuestr) < 1) continue; if(0 == strcmp("{",keyword)) { continue; @@ -835,7 +836,7 @@ BOOL LLInventoryItem::importLegacyStream(std::istream& input_stream) } else if(0 == strcmp("permissions", keyword)) { - success = mPermissions.importStream(input_stream); + success = mPermissions.importLegacyStream(input_stream); } else if(0 == strcmp("sale_info", keyword)) { @@ -845,7 +846,7 @@ BOOL LLInventoryItem::importLegacyStream(std::istream& input_stream) // should pick up the vast majority of the tasks. BOOL has_perm_mask = FALSE; U32 perm_mask = 0; - success = mSaleInfo.importStream(input_stream, has_perm_mask, perm_mask); + success = mSaleInfo.importLegacyStream(input_stream, has_perm_mask, perm_mask); if(has_perm_mask) { if(perm_mask == PERM_NONE) @@ -921,7 +922,7 @@ BOOL LLInventoryItem::importLegacyStream(std::istream& input_stream) const char *donkey = mDescription.c_str(); if (donkey[0] == '|') { - llerrs << "Donkey" << llendl; + LL_ERRS() << "Donkey" << LL_ENDL; } */ } @@ -933,8 +934,8 @@ BOOL LLInventoryItem::importLegacyStream(std::istream& input_stream) } else { - llwarns << "unknown keyword '" << keyword - << "' in inventory import of item " << mUUID << llendl; + LL_WARNS() << "unknown keyword '" << keyword + << "' in inventory import of item " << mUUID << LL_ENDL; } } @@ -944,7 +945,7 @@ BOOL LLInventoryItem::importLegacyStream(std::istream& input_stream) if((LLInventoryType::IT_NONE == mInventoryType) || !inventory_and_asset_types_match(mInventoryType, mType)) { - lldebugs << "Resetting inventory type for " << mUUID << llendl; + LL_DEBUGS() << "Resetting inventory type for " << mUUID << LL_ENDL; mInventoryType = LLInventoryType::defaultForAssetType(mType); } @@ -961,7 +962,7 @@ BOOL LLInventoryItem::exportLegacyStream(std::ostream& output_stream, BOOL inclu output_stream << "\t\titem_id\t" << uuid_str << "\n"; mParentUUID.toString(uuid_str); output_stream << "\t\tparent_id\t" << uuid_str << "\n"; - mPermissions.exportStream(output_stream); + mPermissions.exportLegacyStream(output_stream); // Check for permissions to see the asset id, and if so write it // out as an asset id. Otherwise, apply our cheesy encryption. @@ -995,7 +996,7 @@ BOOL LLInventoryItem::exportLegacyStream(std::ostream& output_stream, BOOL inclu std::string buffer; buffer = llformat( "\t\tflags\t%08x\n", mFlags); output_stream << buffer; - mSaleInfo.exportStream(output_stream); + mSaleInfo.exportLegacyStream(output_stream); output_stream << "\t\tname\t" << mName.c_str() << "|\n"; output_stream << "\t\tdesc\t" << mDescription.c_str() << "|\n"; output_stream << "\t\tcreation_date\t" << mCreationDate << "\n"; @@ -1045,13 +1046,19 @@ void LLInventoryItem::asLLSD( LLSD& sd ) const sd[INV_CREATION_DATE_LABEL] = (S32) mCreationDate; } -LLFastTimer::DeclareTimer FTM_INVENTORY_SD_DESERIALIZE("Inventory SD Deserialize"); +LLTrace::BlockTimerStatHandle FTM_INVENTORY_SD_DESERIALIZE("Inventory SD Deserialize"); -bool LLInventoryItem::fromLLSD(const LLSD& sd) +bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new) { - LLFastTimer _(FTM_INVENTORY_SD_DESERIALIZE); - mInventoryType = LLInventoryType::IT_NONE; - mAssetUUID.setNull(); + + LL_RECORD_BLOCK_TIME(FTM_INVENTORY_SD_DESERIALIZE); + if (is_new) + { + // If we're adding LLSD to an existing object, need avoid + // clobbering these fields. + mInventoryType = LLInventoryType::IT_NONE; + mAssetUUID.setNull(); + } std::string w; w = INV_ITEM_ID_LABEL; @@ -1108,6 +1115,11 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd) { mAssetUUID = sd[w]; } + w = INV_LINKED_ID_LABEL; + if (sd.has(w)) + { + mAssetUUID = sd[w]; + } w = INV_ASSET_TYPE_LABEL; if (sd.has(w)) { @@ -1120,11 +1132,6 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd) S8 type = (U8)sd[w].asInteger(); mType = static_cast(type); } - - if (mType == LLAssetType::AT_LINK || mType == LLAssetType::AT_LINK_FOLDER) - { - gHippoGridManager->getConnectedGrid()->setSupportsInvLinks(true); - } } w = INV_INVENTORY_TYPE_LABEL; if (sd.has(w)) @@ -1158,18 +1165,20 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd) // mType, these are the two asset types that are IT_WEARABLE: static U32 AT_BODYPART = 13; // LLAssetType::AT_BODYPART // Viewer local values: - static U32 WT_UNKNOWN = 16; // LLWearableType::WT_UNKNOWN - static U32 WT_COUNT = 17; // LLWearableType::WT_COUNT + static U32 WT_UNKNOWN = 17; // LLWearableType::WT_UNKNOWN + static U32 WT_COUNT = 18; // LLWearableType::WT_COUNT + // Keep WT_UNKNOWN and WT_COUNT + // in sync with llwearabletype.h // The last 8 bits of mFlags contain the wearable type. - static U32 II_FLAGS_WEARABLES_MASK = 0xff; // LLInventoryItemFlags::II_FLAGS_WEARABLES_MASK + static U32 II_FLAGS_SUBTYPE_MASK = 0xff; // LLInventoryItemFlags::II_FLAGS_SUBTYPE_MASK // The wearable type is stored in the lower 8 bits of mFlags. - U32 wt = mFlags & II_FLAGS_WEARABLES_MASK; + U32 wt = mFlags & II_FLAGS_SUBTYPE_MASK; // Because WT_UNKNOWN now has locally a special meaning, make sure we don't receive it from the server. if (wt == WT_UNKNOWN) { - llwarns << "Received inventory item with wearable type WT_UNKNOWN from server! You should upgrade your viewer." << llendl; + LL_DEBUGS() << "Received inventory item with wearable type WT_UNKNOWN from server!" << LL_ENDL; // Change this new wearable type to WT_COUNT, as if when we had not inserted WT_UNKNOWN locally. mFlags += 1; wt = WT_COUNT; @@ -1210,7 +1219,7 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd) if((LLInventoryType::IT_NONE == mInventoryType) || !inventory_and_asset_types_match(mInventoryType, mType)) { - lldebugs << "Resetting inventory type for " << mUUID << llendl; + LL_DEBUGS() << "Resetting inventory type for " << mUUID << LL_ENDL; mInventoryType = LLInventoryType::defaultForAssetType(mType); } @@ -1283,7 +1292,7 @@ void LLInventoryItem::unpackBinaryBucket(U8* bin_bucket, S32 bin_bucket_size) if (NULL == bin_bucket) { - llerrs << "unpackBinaryBucket failed. bin_bucket is NULL." << llendl; + LL_ERRS() << "unpackBinaryBucket failed. bin_bucket is NULL." << LL_ENDL; return; } @@ -1293,7 +1302,7 @@ void LLInventoryItem::unpackBinaryBucket(U8* bin_bucket, S32 bin_bucket_size) item_buffer[bin_bucket_size] = '\0'; std::string str(&item_buffer[0]); - lldebugs << "item buffer: " << str << llendl; + LL_DEBUGS() << "item buffer: " << str << LL_ENDL; // Tokenize the string. typedef boost::tokenizer > tokenizer; @@ -1307,11 +1316,11 @@ void LLInventoryItem::unpackBinaryBucket(U8* bin_bucket, S32 bin_bucket_size) setUUID(item_id); LLAssetType::EType type; - type = (LLAssetType::EType)(atoi((*(iter++)).c_str())); + type = static_cast(std::stoi((*(iter++)))); setType( type ); LLInventoryType::EType inv_type; - inv_type = (LLInventoryType::EType)(atoi((*(iter++)).c_str())); + inv_type = static_cast(std::stoi((*(iter++)))); setInventoryType( inv_type ); std::string name((*(iter++)).c_str()); @@ -1330,7 +1339,7 @@ void LLInventoryItem::unpackBinaryBucket(U8* bin_bucket, S32 bin_bucket_size) perm.init(creator_id, owner_id, last_owner_id, group_id); perm.initMasks(mask_base, mask_owner, mask_group, mask_every, mask_next); setPermissions(perm); - //lldebugs << "perm: " << perm << llendl; + //LL_DEBUGS() << "perm: " << perm << LL_ENDL; LLUUID asset_id((*(iter++)).c_str()); setAssetUUID(asset_id); @@ -1339,8 +1348,8 @@ void LLInventoryItem::unpackBinaryBucket(U8* bin_bucket, S32 bin_bucket_size) setDescription(desc); LLSaleInfo::EForSale sale_type; - sale_type = (LLSaleInfo::EForSale)(atoi((*(iter++)).c_str())); - S32 price = atoi((*(iter++)).c_str()); + sale_type = static_cast(std::stoi((*(iter++)))); + S32 price = std::stoi(*(iter++)); LLSaleInfo sale_info(sale_type, price); setSaleInfo(sale_info); @@ -1409,6 +1418,10 @@ LLSD LLInventoryCategory::asLLSD() const return sd; } +bool LLInventoryCategory::isPreferredTypeRoot() const +{ + return (mPreferredType == LLFolderType::FT_ROOT_INVENTORY || mPreferredType == 9); +} // virtual void LLInventoryCategory::packMessage(LLMessageSystem* msg) const @@ -1489,10 +1502,10 @@ BOOL LLInventoryCategory::importFile(LLFILE* fp) buffer[0] = '\0'; } - sscanf( /* Flawfinder: ignore */ + if (sscanf( buffer, " %254s %254s", - keyword, valuestr); + keyword, valuestr) < 1) continue; if(0 == strcmp("{",keyword)) { continue; @@ -1531,8 +1544,8 @@ BOOL LLInventoryCategory::importFile(LLFILE* fp) } else { - llwarns << "unknown keyword '" << keyword - << "' in inventory import category " << mUUID << llendl; + LL_WARNS() << "unknown keyword '" << keyword + << "' in inventory import category " << mUUID << LL_ENDL; } } return TRUE; @@ -1568,10 +1581,10 @@ BOOL LLInventoryCategory::importLegacyStream(std::istream& input_stream) while(input_stream.good()) { input_stream.getline(buffer, MAX_STRING); - sscanf( /* Flawfinder: ignore */ + if (sscanf( buffer, " %254s %254s", - keyword, valuestr); + keyword, valuestr) < 1) continue; if(0 == strcmp("{",keyword)) { continue; @@ -1610,8 +1623,8 @@ BOOL LLInventoryCategory::importLegacyStream(std::istream& input_stream) } else { - llwarns << "unknown keyword '" << keyword - << "' in inventory import category " << mUUID << llendl; + LL_WARNS() << "unknown keyword '" << keyword + << "' in inventory import category " << mUUID << LL_ENDL; } } return TRUE; @@ -1642,8 +1655,8 @@ LLSD ll_create_sd_from_inventory_item(LLPointer item) if(item.isNull()) return rv; if (item->getType() == LLAssetType::AT_NONE) { - llwarns << "ll_create_sd_from_inventory_item() for item with AT_NONE" - << llendl; + LL_WARNS() << "ll_create_sd_from_inventory_item() for item with AT_NONE" + << LL_ENDL; return rv; } rv[INV_ITEM_ID_LABEL] = item->getUUID(); @@ -1668,8 +1681,8 @@ LLSD ll_create_sd_from_inventory_category(LLPointer cat) if(cat.isNull()) return rv; if (cat->getType() == LLAssetType::AT_NONE) { - llwarns << "ll_create_sd_from_inventory_category() for cat with AT_NONE" - << llendl; + LL_WARNS() << "ll_create_sd_from_inventory_category() for cat with AT_NONE" + << LL_ENDL; return rv; } rv[INV_FOLDER_ID_LABEL] = cat->getUUID(); diff --git a/indra/llinventory/llinventory.h b/indra/llinventory/llinventory.h index a88894da92..a4bb17b5ab 100644 --- a/indra/llinventory/llinventory.h +++ b/indra/llinventory/llinventory.h @@ -27,7 +27,6 @@ #ifndef LL_LLINVENTORY_H #define LL_LLINVENTORY_H -#include "lldarray.h" #include "llfoldertype.h" #include "llinventorytype.h" #include "llpermissions.h" @@ -48,6 +47,7 @@ class LLInventoryObject : public LLRefCount { public: typedef std::list > object_list_t; + typedef std::list > const_object_list_t; //-------------------------------------------------------------------- // Initialization @@ -73,6 +73,7 @@ class LLInventoryObject : public LLRefCount virtual LLAssetType::EType getType() const; LLAssetType::EType getActualType() const; // bypasses indirection for linked items BOOL getIsLinkType() const; + virtual time_t getCreationDate() const; //-------------------------------------------------------------------- // Mutators @@ -83,23 +84,23 @@ class LLInventoryObject : public LLRefCount virtual void rename(const std::string& new_name); void setParent(const LLUUID& new_parent); void setType(LLAssetType::EType type); + virtual void setCreationDate(time_t creation_date_utc); // only stored for items -private: +// [RLVa:KB] - Checked: 2014-01-07 (RLVa-1.4.10) // in place correction for inventory name string - void correctInventoryName(std::string& name); + static void correctInventoryName(std::string& name); +// [/RLVa:KB] //-------------------------------------------------------------------- // File Support // Implemented here so that a minimal information set can be transmitted // between simulator and viewer. //-------------------------------------------------------------------- -public: // virtual BOOL importFile(LLFILE* fp); virtual BOOL exportFile(LLFILE* fp, BOOL include_asset_key = TRUE) const; virtual BOOL importLegacyStream(std::istream& input_stream); virtual BOOL exportLegacyStream(std::ostream& output_stream, BOOL include_asset_key = TRUE) const; - virtual void removeFromServer(); virtual void updateParentOnServer(BOOL) const; virtual void updateServer(BOOL) const; @@ -111,6 +112,7 @@ class LLInventoryObject : public LLRefCount LLUUID mParentUUID; // Parent category. Root categories have LLUUID::NULL. LLAssetType::EType mType; std::string mName; + time_t mCreationDate; // seconds from 1/1/1970, UTC }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -121,7 +123,7 @@ class LLInventoryObject : public LLRefCount class LLInventoryItem : public LLInventoryObject { public: - typedef LLDynamicArray > item_array_t; + typedef std::vector > item_array_t; //-------------------------------------------------------------------- // Initialization @@ -171,12 +173,12 @@ class LLInventoryItem : public LLInventoryObject //-------------------------------------------------------------------- public: void setAssetUUID(const LLUUID& asset_id); + static void correctInventoryDescription(std::string& name); void setDescription(const std::string& new_desc); void setSaleInfo(const LLSaleInfo& sale_info); void setPermissions(const LLPermissions& perm); void setInventoryType(LLInventoryType::EType inv_type); void setFlags(U32 flags); - void setCreationDate(time_t creation_date_utc); void setCreator(const LLUUID& creator); // only used for calling cards // Check for changes in permissions masks and sale info @@ -210,7 +212,7 @@ class LLInventoryItem : public LLInventoryObject void unpackBinaryBucket(U8* bin_bucket, S32 bin_bucket_size); LLSD asLLSD() const; void asLLSD( LLSD& sd ) const; - bool fromLLSD(const LLSD& sd); + bool fromLLSD(const LLSD& sd, bool is_new = true); //-------------------------------------------------------------------- // Member Variables @@ -222,7 +224,6 @@ class LLInventoryItem : public LLInventoryObject LLSaleInfo mSaleInfo; LLInventoryType::EType mInventoryType; U32 mFlags; - time_t mCreationDate; // seconds from 1/1/1970, UTC }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -234,7 +235,7 @@ class LLInventoryItem : public LLInventoryObject class LLInventoryCategory : public LLInventoryObject { public: - typedef LLDynamicArray > cat_array_t; + typedef std::vector > cat_array_t; //-------------------------------------------------------------------- // Initialization @@ -257,6 +258,7 @@ class LLInventoryCategory : public LLInventoryObject void setPreferredType(LLFolderType::EType type); LLSD asLLSD() const; bool fromLLSD(const LLSD& sd); + bool isPreferredTypeRoot() const; //-------------------------------------------------------------------- // Messaging diff --git a/indra/llinventory/llinventorydefines.cpp b/indra/llinventory/llinventorydefines.cpp index 7def65a308..575331a263 100644 --- a/indra/llinventory/llinventorydefines.cpp +++ b/indra/llinventory/llinventorydefines.cpp @@ -2,33 +2,26 @@ * @file llinventorydefines.cpp * @brief Implementation of the inventory defines. * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2010, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlife.com/developers/opensource/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ */ #include "linden_common.h" diff --git a/indra/llinventory/llinventorydefines.h b/indra/llinventory/llinventorydefines.h index fc81d1f729..54562673f3 100644 --- a/indra/llinventory/llinventorydefines.h +++ b/indra/llinventory/llinventorydefines.h @@ -2,33 +2,26 @@ * @file llinventorydefines.h * @brief LLInventoryDefines * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2010, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlife.com/developers/opensource/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ */ #ifndef LL_LLINVENTORYDEFINES_H @@ -88,9 +81,10 @@ class LLInventoryItemFlags II_FLAGS_OBJECT_HAS_MULTIPLE_ITEMS = 0x200000, // Whether a returned object is composed of multiple items. - II_FLAGS_WEARABLES_MASK = 0xff, - // Wearables use the low order byte of flags to store the - // LLWearableType::EType enumeration found in newview/llwearable.h + II_FLAGS_SUBTYPE_MASK = 0x0000ff, + // Some items like Wearables and settings use the low order byte + // of flags to store the sub type of the inventory item. + // see LLWearableType::EType enumeration found in newview/llwearable.h II_FLAGS_PERM_OVERWRITE_MASK = (II_FLAGS_OBJECT_SLAM_PERM | II_FLAGS_OBJECT_SLAM_SALE | diff --git a/indra/llinventory/llinventorysettings.cpp b/indra/llinventory/llinventorysettings.cpp new file mode 100644 index 0000000000..bf8043d4d2 --- /dev/null +++ b/indra/llinventory/llinventorysettings.cpp @@ -0,0 +1,117 @@ +/** +* @file llinventorysettings.cpp +* @author optional +* @brief A base class for asset based settings groups. +* +* $LicenseInfo:2011&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2017, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#include "linden_common.h" +#include "llinventorysettings.h" +#include "llinventorytype.h" +#include "llinventorydefines.h" +#include "lldictionary.h" +#include "llsingleton.h" +#include "llinvtranslationbrdg.h" + +//========================================================================= +namespace { + LLTranslationBridge::ptr_t sTranslator; +} + +//========================================================================= +struct SettingsEntry : public LLDictionaryEntry +{ + SettingsEntry(const std::string &name, + const std::string& default_new_name, + LLInventoryType::EIconName iconName) : + LLDictionaryEntry(name), + mDefaultNewName(default_new_name), + mLabel(name), + mIconName(iconName) + { + std::string transdname = sTranslator->getString(mLabel); + if (!transdname.empty()) + { + mLabel = transdname; + } + } + + std::string mLabel; + std::string mDefaultNewName; //keep mLabel for backward compatibility + LLInventoryType::EIconName mIconName; +}; + +class LLSettingsDictionary : public LLSingleton, + public LLDictionary +{ + friend class LLSingleton; \ + LLSettingsDictionary(); + + void initSingleton(); +}; + +LLSettingsDictionary::LLSettingsDictionary() +{ +} + +void LLSettingsDictionary::initSingleton() +{ + addEntry(LLSettingsType::ST_SKY, new SettingsEntry("sky", "New Sky", LLInventoryType::ICONNAME_SETTINGS_SKY)); + addEntry(LLSettingsType::ST_WATER, new SettingsEntry("water", "New Water", LLInventoryType::ICONNAME_SETTINGS_WATER)); + addEntry(LLSettingsType::ST_DAYCYCLE, new SettingsEntry("day", "New Day", LLInventoryType::ICONNAME_SETTINGS_DAY)); + addEntry(LLSettingsType::ST_NONE, new SettingsEntry("none", "New Settings", LLInventoryType::ICONNAME_SETTINGS)); + addEntry(LLSettingsType::ST_INVALID, new SettingsEntry("invalid", "New Settings", LLInventoryType::ICONNAME_SETTINGS)); +} + +//========================================================================= + +LLSettingsType::type_e LLSettingsType::fromInventoryFlags(U32 flags) +{ + return (LLSettingsType::type_e)(flags & LLInventoryItemFlags::II_FLAGS_SUBTYPE_MASK); +} + +LLInventoryType::EIconName LLSettingsType::getIconName(LLSettingsType::type_e type) +{ + const SettingsEntry *entry = LLSettingsDictionary::instance().lookup(type); + if (!entry) + return getIconName(ST_INVALID); + return entry->mIconName; +} + +std::string LLSettingsType::getDefaultName(LLSettingsType::type_e type) +{ + const SettingsEntry *entry = LLSettingsDictionary::instance().lookup(type); + if (!entry) + return getDefaultName(ST_INVALID); + return entry->mDefaultNewName; +} + +void LLSettingsType::initClass(LLTranslationBridge::ptr_t &trans) +{ + sTranslator = trans; +} + +void LLSettingsType::cleanupClass() +{ + sTranslator.reset(); +} diff --git a/indra/llinventory/llinventorysettings.h b/indra/llinventory/llinventorysettings.h new file mode 100644 index 0000000000..906540689c --- /dev/null +++ b/indra/llinventory/llinventorysettings.h @@ -0,0 +1,56 @@ +/** +* @file llinventorysettings.h +* @author optional +* @brief A base class for asset based settings groups. +* +* $LicenseInfo:2011&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2017, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#ifndef LL_INVENTORY_SETTINGS_H +#define LL_INVENTORY_SETTINGS_H + +#include "llinventorytype.h" +#include "llinvtranslationbrdg.h" + +class LLSettingsType +{ +public: + enum type_e + { + ST_SKY = 0, + ST_WATER = 1, + ST_DAYCYCLE = 2, + + ST_INVALID = 255, + ST_NONE = -1 + }; + + static type_e fromInventoryFlags(U32 flags); + static LLInventoryType::EIconName getIconName(type_e type); + static std::string getDefaultName(type_e type); + + static void initClass(LLTranslationBridge::ptr_t &trans); + static void cleanupClass(); +}; + + +#endif diff --git a/indra/llinventory/llinventorytype.cpp b/indra/llinventory/llinventorytype.cpp index 1f30c771b5..30f98eb2a0 100644 --- a/indra/llinventory/llinventorytype.cpp +++ b/indra/llinventory/llinventorytype.cpp @@ -53,6 +53,7 @@ struct InventoryEntry : public LLDictionaryEntry LLAssetType::EType t = (LLAssetType::EType)va_arg(argp,int); mAssetTypes.push_back(t); } + va_end(argp); } const std::string mHumanName; @@ -84,6 +85,7 @@ LLInventoryDictionary::LLInventoryDictionary() addEntry(LLInventoryType::IT_ANIMATION, new InventoryEntry("animation", "animation", 1, LLAssetType::AT_ANIMATION)); addEntry(LLInventoryType::IT_GESTURE, new InventoryEntry("gesture", "gesture", 1, LLAssetType::AT_GESTURE)); addEntry(LLInventoryType::IT_MESH, new InventoryEntry("mesh", "mesh", 1, LLAssetType::AT_MESH)); + addEntry(LLInventoryType::IT_SETTINGS, new InventoryEntry("settings", "settings", 1, LLAssetType::AT_SETTINGS)); } @@ -144,6 +146,15 @@ DEFAULT_ASSET_FOR_INV_TYPE[LLAssetType::AT_COUNT] = LLInventoryType::IT_NONE, // 47 AT_NONE LLInventoryType::IT_NONE, // 48 AT_NONE LLInventoryType::IT_MESH, // 49 AT_MESH + + LLInventoryType::IT_NONE, // 50 AT_RESERVED_1 + LLInventoryType::IT_NONE, // 52 AT_RESERVED_2 + LLInventoryType::IT_NONE, // 53 AT_RESERVED_3 + LLInventoryType::IT_NONE, // 54 AT_RESERVED_4 + LLInventoryType::IT_NONE, // 55 AT_RESERVED_5 + LLInventoryType::IT_NONE, // 56 AT_RESERVED_6 + + LLInventoryType::IT_SETTINGS, // 57 AT_SETTINGS }; // static @@ -180,7 +191,7 @@ LLInventoryType::EType LLInventoryType::defaultForAssetType(LLAssetType::EType a } else { - return IT_NONE; + return IT_UNKNOWN; } } @@ -199,6 +210,12 @@ bool LLInventoryType::cannotRestrictPermissions(LLInventoryType::EType type) } } +// Should show permissions that apply only to objects rezed in world. +bool LLInventoryType::showInWorldPermissions(LLInventoryType::EType type) +{ + return (type != IT_SETTINGS); +} + bool inventory_and_asset_types_match(LLInventoryType::EType inventory_type, LLAssetType::EType asset_type) { diff --git a/indra/llinventory/llinventorytype.h b/indra/llinventory/llinventorytype.h index b444ecfa54..a7aa1dfbf5 100644 --- a/indra/llinventory/llinventorytype.h +++ b/indra/llinventory/llinventorytype.h @@ -62,8 +62,10 @@ class LLInventoryType IT_ANIMATION = 19, IT_GESTURE = 20, IT_MESH = 22, - IT_COUNT = 23, + IT_SETTINGS = 25, + IT_COUNT = 26, + IT_UNKNOWN = 255, IT_NONE = -1 }; @@ -98,6 +100,7 @@ class LLInventoryType ICONNAME_CLOTHING_SKIRT, ICONNAME_CLOTHING_ALPHA, ICONNAME_CLOTHING_TATTOO, + ICONNAME_CLOTHING_UNIVERSAL, ICONNAME_ANIMATION, ICONNAME_GESTURE, @@ -108,8 +111,14 @@ class LLInventoryType ICONNAME_LINKFOLDER, ICONNAME_MESH, + ICONNAME_SETTINGS, + ICONNAME_SETTINGS_SKY, + ICONNAME_SETTINGS_WATER, + ICONNAME_SETTINGS_DAY, + ICONNAME_CLOTHING_UNKNOWN, ICONNAME_INVALID, + ICONNAME_UNKNOWN, ICONNAME_COUNT, ICONNAME_NONE = -1 }; @@ -127,6 +136,8 @@ class LLInventoryType // true if this type cannot have restricted permissions. static bool cannotRestrictPermissions(EType type); + static bool showInWorldPermissions(EType type); + private: // don't instantiate or derive one of these objects LLInventoryType( void ); diff --git a/indra/llinventory/llinvtranslationbrdg.h b/indra/llinventory/llinvtranslationbrdg.h new file mode 100644 index 0000000000..715c60c30d --- /dev/null +++ b/indra/llinventory/llinvtranslationbrdg.h @@ -0,0 +1,43 @@ +/** +* @file llinvtranslationbrdg.h +* @brief Translation adapter for inventory. +* +* $LicenseInfo:firstyear=2002&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2010, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#ifndef LL_TRANSLATIONBRDG_H +#define LL_TRANSLATIONBRDG_H + +#include + +class LLTranslationBridge +{ +public: + typedef std::shared_ptr ptr_t; + + // clang needs this to be happy + virtual ~LLTranslationBridge() {} + + virtual std::string getString(const std::string &xml_desc) = 0; +}; + +#endif diff --git a/indra/llinventory/lllandmark.cpp b/indra/llinventory/lllandmark.cpp index 83b6392ca8..73166ff5c0 100644 --- a/indra/llinventory/lllandmark.cpp +++ b/indra/llinventory/lllandmark.cpp @@ -134,7 +134,7 @@ LLLandmark* LLLandmark::constructFromString(const char *buffer) goto error; } cur += chars_read; - // llinfos << "Landmark read: " << pos << llendl; + // LL_INFOS() << "Landmark read: " << pos << LL_ENDL; return new LLLandmark(pos); } @@ -161,7 +161,7 @@ LLLandmark* LLLandmark::constructFromString(const char *buffer) } error: - llinfos << "Bad Landmark Asset: bad _DATA_ block." << llendl; + LL_INFOS() << "Bad Landmark Asset: bad _DATA_ block." << LL_ENDL; return NULL; } @@ -182,7 +182,7 @@ void LLLandmark::requestRegionHandle( if(region_id.isNull()) { // don't bother with checking - it's 0. - lldebugs << "requestRegionHandle: null" << llendl; + LL_DEBUGS() << "requestRegionHandle: null" << LL_ENDL; if(callback) { const U64 U64_ZERO = 0; @@ -193,7 +193,7 @@ void LLLandmark::requestRegionHandle( { if(region_id == mLocalRegion.first) { - lldebugs << "requestRegionHandle: local" << llendl; + LL_DEBUGS() << "requestRegionHandle: local" << LL_ENDL; if(callback) { callback(region_id, mLocalRegion.second); @@ -204,14 +204,14 @@ void LLLandmark::requestRegionHandle( region_map_t::iterator it = mRegions.find(region_id); if(it == mRegions.end()) { - lldebugs << "requestRegionHandle: upstream" << llendl; + LL_DEBUGS() << "requestRegionHandle: upstream" << LL_ENDL; if(callback) { region_callback_map_t::value_type vt(region_id, callback); sRegionCallbackMap.insert(vt); } - lldebugs << "Landmark requesting information about: " - << region_id << llendl; + LL_DEBUGS() << "Landmark requesting information about: " + << region_id << LL_ENDL; msg->newMessage("RegionHandleRequest"); msg->nextBlock("RequestBlock"); msg->addUUID("RegionID", region_id); @@ -220,7 +220,7 @@ void LLLandmark::requestRegionHandle( else if(callback) { // we have the answer locally - just call the callack. - lldebugs << "requestRegionHandle: ready" << llendl; + LL_DEBUGS() << "requestRegionHandle: ready" << LL_ENDL; callback(region_id, (*it).second.mRegionHandle); } } @@ -254,8 +254,8 @@ void LLLandmark::processRegionIDAndHandle(LLMessageSystem* msg, void**) #if LL_DEBUG U32 grid_x, grid_y; grid_from_region_handle(info.mRegionHandle, &grid_x, &grid_y); - lldebugs << "Landmark got reply for region: " << region_id << " " - << grid_x << "," << grid_y << llendl; + LL_DEBUGS() << "Landmark got reply for region: " << region_id << " " + << grid_x << "," << grid_y << LL_ENDL; #endif // make all the callbacks here. diff --git a/indra/llinventory/lllandmark.h b/indra/llinventory/lllandmark.h index feaf1a0e9c..6d6f63b753 100644 --- a/indra/llinventory/lllandmark.h +++ b/indra/llinventory/lllandmark.h @@ -35,7 +35,10 @@ #define LL_LLLANDMARK_H #include +#ifndef BOOST_FUNCTION_HPP_INCLUDED #include +#define BOOST_FUNCTION_HPP_INCLUDED +#endif #include "llframetimer.h" #include "lluuid.h" #include "v3dmath.h" diff --git a/indra/llinventory/llnotecard.cpp b/indra/llinventory/llnotecard.cpp index 13ac4c9f09..0281df3f42 100644 --- a/indra/llinventory/llnotecard.cpp +++ b/indra/llinventory/llnotecard.cpp @@ -63,33 +63,33 @@ bool LLNotecard::importEmbeddedItemsStream(std::istream& str) str >> std::ws >> "LLEmbeddedItems version" >> mEmbeddedVersion >> "\n"; if (str.fail()) { - llwarns << "Invalid Linden text file header" << llendl; + LL_WARNS() << "Invalid Linden text file header" << LL_ENDL; goto import_file_failed; } if( 1 != mEmbeddedVersion ) { - llwarns << "Invalid LLEmbeddedItems version: " << mEmbeddedVersion << llendl; + LL_WARNS() << "Invalid LLEmbeddedItems version: " << mEmbeddedVersion << LL_ENDL; goto import_file_failed; } str >> std::ws >> "{\n"; if(str.fail()) { - llwarns << "Invalid Linden text file format: missing {" << llendl; + LL_WARNS() << "Invalid Linden text file format: missing {" << LL_ENDL; goto import_file_failed; } str >> std::ws >> "count " >> count >> "\n"; if(str.fail()) { - llwarns << "Invalid LLEmbeddedItems count" << llendl; + LL_WARNS() << "Invalid LLEmbeddedItems count" << LL_ENDL; goto import_file_failed; } if((count < 0)) { - llwarns << "Invalid LLEmbeddedItems count value: " << count << llendl; + LL_WARNS() << "Invalid LLEmbeddedItems count value: " << count << LL_ENDL; goto import_file_failed; } @@ -98,7 +98,7 @@ bool LLNotecard::importEmbeddedItemsStream(std::istream& str) str >> std::ws >> "{\n"; if(str.fail()) { - llwarns << "Invalid LLEmbeddedItems file format: missing {" << llendl; + LL_WARNS() << "Invalid LLEmbeddedItems file format: missing {" << LL_ENDL; goto import_file_failed; } @@ -106,21 +106,21 @@ bool LLNotecard::importEmbeddedItemsStream(std::istream& str) str >> std::ws >> "ext char index " >> index >> "\n"; if(str.fail()) { - llwarns << "Invalid LLEmbeddedItems file format: missing ext char index" << llendl; + LL_WARNS() << "Invalid LLEmbeddedItems file format: missing ext char index" << LL_ENDL; goto import_file_failed; } str >> std::ws >> "inv_item\t0\n"; if(str.fail()) { - llwarns << "Invalid LLEmbeddedItems file format: missing inv_item" << llendl; + LL_WARNS() << "Invalid LLEmbeddedItems file format: missing inv_item" << LL_ENDL; goto import_file_failed; } LLPointer item = new LLInventoryItem; if (!item->importLegacyStream(str)) { - llinfos << "notecard import failed" << llendl; + LL_INFOS() << "notecard import failed" << LL_ENDL; goto import_file_failed; } mItems.push_back(item); @@ -128,7 +128,7 @@ bool LLNotecard::importEmbeddedItemsStream(std::istream& str) str >> std::ws >> "}\n"; if(str.fail()) { - llwarns << "Invalid LLEmbeddedItems file format: missing }" << llendl; + LL_WARNS() << "Invalid LLEmbeddedItems file format: missing }" << LL_ENDL; goto import_file_failed; } } @@ -136,7 +136,7 @@ bool LLNotecard::importEmbeddedItemsStream(std::istream& str) str >> std::ws >> "}\n"; if(str.fail()) { - llwarns << "Invalid LLEmbeddedItems file format: missing }" << llendl; + LL_WARNS() << "Invalid LLEmbeddedItems file format: missing }" << LL_ENDL; goto import_file_failed; } @@ -167,20 +167,20 @@ bool LLNotecard::importStream(std::istream& str) str >> std::ws >> "Linden text version " >> mVersion >> "\n"; if(str.fail()) { - llwarns << "Invalid Linden text file header " << llendl; + LL_WARNS() << "Invalid Linden text file header " << LL_ENDL; return FALSE; } if( 1 != mVersion && 2 != mVersion) { - llwarns << "Invalid Linden text file version: " << mVersion << llendl; + LL_WARNS() << "Invalid Linden text file version: " << mVersion << LL_ENDL; return FALSE; } str >> std::ws >> "{\n"; if(str.fail()) { - llwarns << "Invalid Linden text file format" << llendl; + LL_WARNS() << "Invalid Linden text file format" << LL_ENDL; return FALSE; } @@ -193,7 +193,7 @@ bool LLNotecard::importStream(std::istream& str) str.getline(line_buf, STD_STRING_BUF_SIZE); if(str.fail()) { - llwarns << "Invalid Linden text length field" << llendl; + LL_WARNS() << "Invalid Linden text length field" << LL_ENDL; return FALSE; } line_buf[STD_STRING_STR_LEN] = '\0'; @@ -201,13 +201,13 @@ bool LLNotecard::importStream(std::istream& str) S32 text_len = 0; if( 1 != sscanf(line_buf, "Text length %d", &text_len) ) { - llwarns << "Invalid Linden text length field" << llendl; + LL_WARNS() << "Invalid Linden text length field" << LL_ENDL; return FALSE; } if(text_len > mMaxText || text_len < 0) { - llwarns << "Invalid Linden text length: " << text_len << llendl; + LL_WARNS() << "Invalid Linden text length: " << text_len << LL_ENDL; return FALSE; } @@ -217,7 +217,7 @@ bool LLNotecard::importStream(std::istream& str) fullread(str, text, text_len); if(str.fail()) { - llwarns << "Invalid Linden text: text shorter than text length: " << text_len << llendl; + LL_WARNS() << "Invalid Linden text: text shorter than text length: " << text_len << LL_ENDL; success = FALSE; } text[text_len] = '\0'; diff --git a/indra/llinventory/llparcel.cpp b/indra/llinventory/llparcel.cpp index 99a37acd57..158c2edc52 100644 --- a/indra/llinventory/llparcel.cpp +++ b/indra/llinventory/llparcel.cpp @@ -40,6 +40,8 @@ #include "llsdutil_math.h" #include "message.h" #include "u64.h" +#include "llregionflags.h" +#include static const F32 SOME_BIG_NUMBER = 1000.0f; static const F32 SOME_BIG_NEG_NUMBER = -1000.0f; @@ -137,7 +139,7 @@ LLParcel::LLParcel(const LLUUID &owner_id, // virtual LLParcel::~LLParcel() { - // user list cleaned up by LLDynamicArray destructor. + // user list cleaned up by std::vector destructor. } void LLParcel::init(const LLUUID &owner_id, @@ -230,6 +232,9 @@ void LLParcel::init(const LLUUID &owner_id, setAllowGroupAVSounds(TRUE); setAllowAnyAVSounds(TRUE); setHaveNewParcelLimitData(FALSE); + + setRegionAllowEnvironmentOverride(FALSE); + setParcelEnvironmentVersion(INVALID_PARCEL_ENVIRONMENT_VERSION); } void LLParcel::overrideOwner(const LLUUID& owner_id, BOOL is_group_owned) @@ -582,8 +587,8 @@ BOOL LLParcel::importAccessEntry(std::istream& input_stream, LLAccessEntry* entr } else { - llwarns << "Unknown keyword in parcel access entry section: <" - << keyword << ">" << llendl; + LL_WARNS() << "Unknown keyword in parcel access entry section: <" + << keyword << ">" << LL_ENDL; } } return input_stream.good(); @@ -739,8 +744,8 @@ void LLParcel::unpackMessage(LLMessageSystem* msg) void LLParcel::packAccessEntries(LLMessageSystem* msg, const std::map& list) { - access_map_const_iterator cit = list.begin(); - access_map_const_iterator end = list.end(); + LLAccessEntry::map::const_iterator cit = list.begin(); + LLAccessEntry::map::const_iterator end = list.end(); if (cit == end) { @@ -791,16 +796,35 @@ void LLParcel::unpackAccessEntries(LLMessageSystem* msg, } +void LLParcel::unpackExperienceEntries(LLMessageSystem* msg, U32 type) +{ + LLUUID id; + + S32 i; + S32 count = msg->getNumberOfBlocksFast(_PREHASH_List); + for (i = 0; i < count; i++) + { + msg->getUUIDFast(_PREHASH_List, _PREHASH_ID, id, i); + + if (id.notNull()) + { + mExperienceKeys[id] = type; + } + } +} + + + void LLParcel::expirePasses(S32 now) { - access_map_iterator itor = mAccessList.begin(); + LLAccessEntry::map::iterator itor = mAccessList.begin(); while (itor != mAccessList.end()) { const LLAccessEntry& entry = (*itor).second; if (entry.mTime != 0 && entry.mTime < now) { - mAccessList.erase(itor++); + itor = mAccessList.erase(itor); } else { @@ -883,7 +907,7 @@ BOOL LLParcel::addToAccessList(const LLUUID& agent_id, S32 time) // Can't add owner to these lists return FALSE; } - access_map_iterator itor = mAccessList.begin(); + LLAccessEntry::map::iterator itor = mAccessList.begin(); while (itor != mAccessList.end()) { const LLAccessEntry& entry = (*itor).second; @@ -891,7 +915,7 @@ BOOL LLParcel::addToAccessList(const LLUUID& agent_id, S32 time) { if (time == 0 || (entry.mTime != 0 && entry.mTime < time)) { - mAccessList.erase(itor++); + itor = mAccessList.erase(itor); } else { @@ -928,21 +952,24 @@ BOOL LLParcel::addToBanList(const LLUUID& agent_id, S32 time) return FALSE; } - access_map_iterator itor = mBanList.begin(); + LLAccessEntry::map::iterator itor = mBanList.begin(); while (itor != mBanList.end()) { const LLAccessEntry& entry = (*itor).second; if (entry.mID == agent_id) { - if (time == 0 || (entry.mTime != 0 && entry.mTime < time)) + // Singu Note: Allow amending ban time to be less without needing to remove + //if (time == 0 || (entry.mTime != 0 && entry.mTime < time)) { - mBanList.erase(itor++); + itor = mBanList.erase(itor); } +#if 0 else { // existing one expires later return FALSE; } +#endif } else { @@ -964,13 +991,13 @@ BOOL remove_from_access_array(std::map* list, const LLUUID& agent_id) { BOOL removed = FALSE; - access_map_iterator itor = list->begin(); + LLAccessEntry::map::iterator itor = list->begin(); while (itor != list->end()) { const LLAccessEntry& entry = (*itor).second; if (entry.mID == agent_id) { - list->erase(itor++); + itor = list->erase(itor); removed = TRUE; } else @@ -1083,9 +1110,9 @@ void LLParcel::startSale(const LLUUID& buyer_id, BOOL is_buyer_group) mGroupID.setNull(); } mSaleTimerExpires.start(); - mSaleTimerExpires.setTimerExpirySec(DEFAULT_USEC_SALE_TIMEOUT / SEC_TO_MICROSEC); + mSaleTimerExpires.setTimerExpirySec(U64Microseconds(DEFAULT_USEC_SALE_TIMEOUT)); mStatus = OS_LEASE_PENDING; - mClaimDate = time(NULL); + mClaimDate = time(nullptr); setAuctionID(0); // clear the autoreturn whenever land changes hands setCleanOtherTime(0); @@ -1208,9 +1235,9 @@ void LLParcel::clearParcel() void LLParcel::dump() { - llinfos << "parcel " << mLocalID << " area " << mArea << llendl; - llinfos << " name <" << mName << ">" << llendl; - llinfos << " desc <" << mDesc << ">" << llendl; + LL_INFOS() << "parcel " << mLocalID << " area " << mArea << LL_ENDL; + LL_INFOS() << " name <" << mName << ">" << LL_ENDL; + LL_INFOS() << " desc <" << mDesc << ">" << LL_ENDL; } const std::string& ownership_status_to_string(LLParcel::EOwnershipStatus status) @@ -1290,7 +1317,7 @@ LLParcel::ECategory category_string_to_category(const std::string& s) return (LLParcel::ECategory)i; } } - llwarns << "Parcel category outside of possibilities " << s << llendl; + LL_WARNS() << "Parcel category outside of possibilities " << s << LL_ENDL; return LLParcel::C_NONE; } @@ -1307,3 +1334,58 @@ LLParcel::ECategory category_ui_string_to_category(const std::string& s) // is a distinct option from "None" and "Other" return LLParcel::C_ANY; } + +LLAccessEntry::map LLParcel::getExperienceKeysByType(U32 type) const +{ + LLAccessEntry::map access; + LLAccessEntry entry; + xp_type_map_t::const_iterator it = mExperienceKeys.begin(); + for(/**/; it != mExperienceKeys.end(); ++it) + { + if(it->second == type) + { + entry.mID = it->first; + access[entry.mID] = entry; + } + } + return access; +} + +void LLParcel::clearExperienceKeysByType(U32 type) +{ + xp_type_map_t::iterator it = mExperienceKeys.begin(); + while(it != mExperienceKeys.end()) + { + if(it->second == type) + { + mExperienceKeys.erase(it++); + } + else + { + ++it; + } + } +} + +void LLParcel::setExperienceKeyType(const LLUUID& experience_key, U32 type) +{ + if (type == EXPERIENCE_KEY_TYPE_NONE) + { + mExperienceKeys.erase(experience_key); + } + else + { + if (countExperienceKeyType(type) < PARCEL_MAX_EXPERIENCE_LIST) + { + mExperienceKeys[experience_key] = type; + } + } +} + +U32 LLParcel::countExperienceKeyType(U32 type) +{ + return std::count_if( + boost::begin(mExperienceKeys | boost::adaptors::map_values), + boost::end(mExperienceKeys | boost::adaptors::map_values), + std::bind2nd(std::equal_to(), type)); +} diff --git a/indra/llinventory/llparcel.h b/indra/llinventory/llparcel.h index ce3e0eab17..c1322c3874 100644 --- a/indra/llinventory/llparcel.h +++ b/indra/llinventory/llparcel.h @@ -40,6 +40,7 @@ #include "llpermissions.h" #include "lltimer.h" #include "v3math.h" +#include "llsettingsdaycycle.h" // Grid out of which parcels taken is stepped every 4 meters. const F32 PARCEL_GRID_STEP_METERS = 4.f; @@ -59,6 +60,9 @@ const S32 PARCEL_MAX_ACCESS_LIST = 300; //for access/ban lists. const F32 PARCEL_MAX_ENTRIES_PER_PACKET = 48.f; +// Maximum number of experiences +const S32 PARCEL_MAX_EXPERIENCE_LIST = 24; + // Weekly charge for listing a parcel in the directory const S32 PARCEL_DIRECTORY_FEE = 30; @@ -105,6 +109,10 @@ const U32 RT_SELL = 0x1 << 5; const S32 INVALID_PARCEL_ID = -1; +const S32 INVALID_PARCEL_ENVIRONMENT_VERSION = -2; +// if Region settings are used, parcel env. version is -1 +const S32 UNSET_PARCEL_ENVIRONMENT_VERSION = -1; + // Timeouts for parcels // default is 21 days * 24h/d * 60m/h * 60s/m *1000000 usec/s = 1814400000000 const U64 DEFAULT_USEC_CONVERSION_TIMEOUT = U64L(1814400000000); @@ -136,9 +144,11 @@ class LLSD; class LLAccessEntry { public: + + typedef std::map map; + LLAccessEntry() - : mID(), - mTime(0), + : mTime(0), mFlags(0) {} @@ -147,8 +157,6 @@ class LLAccessEntry U32 mFlags; // Not used - currently should always be zero }; -typedef std::map::iterator access_map_iterator; -typedef std::map::const_iterator access_map_const_iterator; class LLParcel { @@ -326,6 +334,9 @@ class LLParcel void unpackAccessEntries(LLMessageSystem* msg, std::map* list); + void unpackExperienceEntries(LLMessageSystem* msg, U32 type); + + void setAABBMin(const LLVector3& min) { mAABBMin = min; } void setAABBMax(const LLVector3& max) { mAABBMax = max; } @@ -508,6 +519,13 @@ class LLParcel { return mRegionDenyAnonymousOverride; } BOOL getRegionDenyAgeUnverifiedOverride() const { return mRegionDenyAgeUnverifiedOverride; } + BOOL getRegionAllowAccessOverride() const + { return mRegionAllowAccessoverride; } + BOOL getRegionAllowEnvironmentOverride() const + { return mRegionAllowEnvironmentOverride; } + S32 getParcelEnvironmentVersion() const + { return mCurrentEnvironmentVersion; } + BOOL getAllowGroupAVSounds() const { return mAllowGroupAVSounds; } BOOL getAllowAnyAVSounds() const { return mAllowAnyAVSounds; } @@ -593,6 +611,10 @@ class LLParcel void setRegionPushOverride(BOOL override) {mRegionPushOverride = override; } void setRegionDenyAnonymousOverride(BOOL override) { mRegionDenyAnonymousOverride = override; } void setRegionDenyAgeUnverifiedOverride(BOOL override) { mRegionDenyAgeUnverifiedOverride = override; } + void setRegionAllowAccessOverride(BOOL override) { mRegionAllowAccessoverride = override; } + void setRegionAllowEnvironmentOverride(BOOL override) { mRegionAllowEnvironmentOverride = override; } + + void setParcelEnvironmentVersion(S32 version) { mCurrentEnvironmentVersion = version; } // Accessors for parcel sellWithObjects void setPreviousOwnerID(LLUUID prev_owner) { mPreviousOwnerID = prev_owner; } @@ -603,7 +625,6 @@ class LLParcel BOOL getPreviouslyGroupOwned() const { return mPreviouslyGroupOwned; } BOOL getSellWithObjects() const { return (mParcelFlags & PF_SELL_PARCEL_OBJECTS) ? TRUE : FALSE; } - protected: LLUUID mID; LLUUID mOwnerID; @@ -674,9 +695,13 @@ class LLParcel BOOL mRegionPushOverride; BOOL mRegionDenyAnonymousOverride; BOOL mRegionDenyAgeUnverifiedOverride; + BOOL mRegionAllowAccessoverride; + BOOL mRegionAllowEnvironmentOverride; BOOL mAllowGroupAVSounds; BOOL mAllowAnyAVSounds; + S32 mCurrentEnvironmentVersion; + bool mIsDefaultDayCycle; public: // HACK, make private @@ -688,6 +713,17 @@ class LLParcel std::map mTempBanList; std::map mTempAccessList; + typedef std::map xp_type_map_t; + + void setExperienceKeyType(const LLUUID& experience_key, U32 type); + U32 countExperienceKeyType(U32 type); + U32 getExperienceKeyType(const LLUUID& experience_key)const; + LLAccessEntry::map getExperienceKeysByType(U32 type)const; + void clearExperienceKeysByType(U32 type); + +private: + xp_type_map_t mExperienceKeys; + }; diff --git a/indra/llinventory/llparcelflags.h b/indra/llinventory/llparcelflags.h index 3430447276..fbfc2af1d2 100644 --- a/indra/llinventory/llparcelflags.h +++ b/indra/llinventory/llparcelflags.h @@ -1,31 +1,25 @@ /** * @file llparcelflags.h * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -68,7 +62,7 @@ const U32 PF_ALLOW_ALL_OBJECT_ENTRY = 1 << 27; // Allow all objects to enter a const U32 PF_ALLOW_GROUP_OBJECT_ENTRY = 1 << 28; // Only allow group (and owner) objects to enter the parcel const U32 PF_ALLOW_VOICE_CHAT = 1 << 29; // Allow residents to use voice chat on this parcel const U32 PF_USE_ESTATE_VOICE_CHAN = 1 << 30; -const U32 PF_DENY_AGEUNVERIFIED = 1 << 31; // Prevent residents who aren't age-verified +const U32 PF_DENY_AGEUNVERIFIED = 1U << 31; // Prevent residents who aren't age-verified // NOTE: At one point we have used all of the bits. // We have deprecated two of them in 1.19.0 which *could* be reused, // but only after we are certain there are no simstates using those bits. @@ -97,8 +91,10 @@ const U32 PF_DEFAULT = PF_ALLOW_FLY | PF_USE_ESTATE_VOICE_CHAN; // Access list flags -const U32 AL_ACCESS = (1 << 0); -const U32 AL_BAN = (1 << 1); +const U32 AL_ACCESS = (1 << 0); +const U32 AL_BAN = (1 << 1); +const U32 AL_ALLOW_EXPERIENCE = (1 << 3); +const U32 AL_BLOCK_EXPERIENCE = (1 << 4); //const U32 AL_RENTER = (1 << 2); // Block access return values. BA_ALLOWED is the only success case diff --git a/indra/llinventory/llpermissions.cpp b/indra/llinventory/llpermissions.cpp index fb5359a889..2316c635d2 100644 --- a/indra/llinventory/llpermissions.cpp +++ b/indra/llinventory/llpermissions.cpp @@ -31,7 +31,6 @@ // library includes #include "message.h" -#include "metapropertyt.h" #include "llsd.h" ///---------------------------------------------------------------------------- @@ -117,7 +116,7 @@ LLUUID LLPermissions::getSafeOwner() const } else { - llwarns << "LLPermissions::getSafeOwner() called with no valid owner!" << llendl; + LL_WARNS() << "LLPermissions::getSafeOwner() called with no valid owner!" << LL_ENDL; LLUUID unused_uuid; unused_uuid.generate(); @@ -535,7 +534,7 @@ void LLPermissions::packMessage(LLMessageSystem* msg) const msg->addBOOLFast(_PREHASH_GroupOwned, (BOOL)mIsGroupOwned); } -void LLPermissions::unpackMessage(LLSD perms) +void LLPermissions::unpackMessage(const LLSD& perms) { mCreator = perms["creator-id"]; mOwner = perms["owner-id"]; @@ -572,17 +571,143 @@ void LLPermissions::unpackMessage(LLMessageSystem* msg, const char* block, S32 b BOOL LLPermissions::importFile(LLFILE* fp) { - llifstream ifs(fp); - return importStream(ifs); + init(LLUUID::null, LLUUID::null, LLUUID::null, LLUUID::null); + const S32 BUFSIZE = 16384; + + // *NOTE: Changing the buffer size will require changing the scanf + // calls below. + char buffer[BUFSIZE]; /* Flawfinder: ignore */ + char keyword[256]; /* Flawfinder: ignore */ + char valuestr[256]; /* Flawfinder: ignore */ + char uuid_str[256]; /* Flawfinder: ignore */ + U32 mask; + + keyword[0] = '\0'; + valuestr[0] = '\0'; + + while (!feof(fp)) + { + if (fgets(buffer, BUFSIZE, fp) == NULL) + { + buffer[0] = '\0'; + } + + sscanf( /* Flawfinder: ignore */ + buffer, + " %255s %255s", + keyword, valuestr); + if (!strcmp("{", keyword)) + { + continue; + } + if (!strcmp("}",keyword)) + { + break; + } + else if (!strcmp("creator_mask", keyword)) + { + // legacy support for "creator" masks + sscanf(valuestr, "%x", &mask); + mMaskBase = mask; + fixFairUse(); + } + else if (!strcmp("base_mask", keyword)) + { + sscanf(valuestr, "%x", &mask); + mMaskBase = mask; + //fixFairUse(); + } + else if (!strcmp("owner_mask", keyword)) + { + sscanf(valuestr, "%x", &mask); + mMaskOwner = mask; + } + else if (!strcmp("group_mask", keyword)) + { + sscanf(valuestr, "%x", &mask); + mMaskGroup = mask; + } + else if (!strcmp("everyone_mask", keyword)) + { + sscanf(valuestr, "%x", &mask); + mMaskEveryone = mask; + } + else if (!strcmp("next_owner_mask", keyword)) + { + sscanf(valuestr, "%x", &mask); + mMaskNextOwner = mask; + } + else if (!strcmp("creator_id", keyword)) + { + sscanf(valuestr, "%255s", uuid_str); /* Flawfinder: ignore */ + mCreator.set(uuid_str); + } + else if (!strcmp("owner_id", keyword)) + { + sscanf(valuestr, "%255s", uuid_str); /* Flawfinder: ignore */ + mOwner.set(uuid_str); + } + else if (!strcmp("last_owner_id", keyword)) + { + sscanf(valuestr, "%255s", uuid_str); /* Flawfinder: ignore */ + mLastOwner.set(uuid_str); + } + else if (!strcmp("group_id", keyword)) + { + sscanf(valuestr, "%255s", uuid_str); /* Flawfinder: ignore */ + mGroup.set(uuid_str); + } + else if (!strcmp("group_owned", keyword)) + { + sscanf(valuestr, "%d", &mask); + if(mask) mIsGroupOwned = true; + else mIsGroupOwned = false; + } + else + { + LL_INFOS() << "unknown keyword " << keyword << " in permissions import" << LL_ENDL; + } + } + fix(); + return TRUE; } + BOOL LLPermissions::exportFile(LLFILE* fp) const { - llofstream ofs(fp); - return exportStream(ofs); + std::string uuid_str; + + fprintf(fp, "\tpermissions 0\n"); + fprintf(fp, "\t{\n"); + + fprintf(fp, "\t\tbase_mask\t%08x\n", mMaskBase); + fprintf(fp, "\t\towner_mask\t%08x\n", mMaskOwner); + fprintf(fp, "\t\tgroup_mask\t%08x\n", mMaskGroup); + fprintf(fp, "\t\teveryone_mask\t%08x\n", mMaskEveryone); + fprintf(fp, "\t\tnext_owner_mask\t%08x\n", mMaskNextOwner); + + mCreator.toString(uuid_str); + fprintf(fp, "\t\tcreator_id\t%s\n", uuid_str.c_str()); + + mOwner.toString(uuid_str); + fprintf(fp, "\t\towner_id\t%s\n", uuid_str.c_str()); + + mLastOwner.toString(uuid_str); + fprintf(fp, "\t\tlast_owner_id\t%s\n", uuid_str.c_str()); + + mGroup.toString(uuid_str); + fprintf(fp, "\t\tgroup_id\t%s\n", uuid_str.c_str()); + + if(mIsGroupOwned) + { + fprintf(fp, "\t\tgroup_owned\t1\n"); + } + fprintf(fp,"\t}\n"); + return TRUE; } -BOOL LLPermissions::importStream(std::istream& input_stream) + +BOOL LLPermissions::importLegacyStream(std::istream& input_stream) { init(LLUUID::null, LLUUID::null, LLUUID::null, LLUUID::null); const S32 BUFSIZE = 16384; @@ -601,18 +726,6 @@ BOOL LLPermissions::importStream(std::istream& input_stream) while (input_stream.good()) { input_stream.getline(buffer, BUFSIZE); - if (input_stream.eof()) - { - llwarns << "Bad permissions: early end of input stream" - << llendl; - return FALSE; - } - if (input_stream.fail()) - { - llwarns << "Bad permissions: failed to read from input stream" - << llendl; - return FALSE; - } sscanf( /* Flawfinder: ignore */ buffer, " %255s %255s", @@ -686,8 +799,8 @@ BOOL LLPermissions::importStream(std::istream& input_stream) } else { - llwarns << "unknown keyword " << keyword - << " in permissions import" << llendl; + LL_WARNS() << "unknown keyword " << keyword + << " in permissions import" << LL_ENDL; } } fix(); @@ -695,26 +808,36 @@ BOOL LLPermissions::importStream(std::istream& input_stream) } -BOOL LLPermissions::exportStream(std::ostream& output_stream) const +BOOL LLPermissions::exportLegacyStream(std::ostream& output_stream) const { - if (!output_stream.good()) return FALSE; + std::string uuid_str; + output_stream << "\tpermissions 0\n"; output_stream << "\t{\n"; - char prev_fill = output_stream.fill('0'); - output_stream << std::hex; - output_stream << "\t\tbase_mask\t" << std::setw(8) << mMaskBase << "\n"; - output_stream << "\t\towner_mask\t" << std::setw(8) << mMaskOwner << "\n"; - output_stream << "\t\tgroup_mask\t" << std::setw(8) << mMaskGroup << "\n"; - output_stream << "\t\teveryone_mask\t" << std::setw(8) << mMaskEveryone << "\n"; - output_stream << "\t\tnext_owner_mask\t" << std::setw(8) << mMaskNextOwner << "\n"; - output_stream << std::dec; - output_stream.fill(prev_fill); - - output_stream << "\t\tcreator_id\t" << mCreator << "\n"; - output_stream << "\t\towner_id\t" << mOwner << "\n"; - output_stream << "\t\tlast_owner_id\t" << mLastOwner << "\n"; - output_stream << "\t\tgroup_id\t" << mGroup << "\n"; + std::string buffer; + buffer = llformat( "\t\tbase_mask\t%08x\n", mMaskBase); + output_stream << buffer; + buffer = llformat( "\t\towner_mask\t%08x\n", mMaskOwner); + output_stream << buffer; + buffer = llformat( "\t\tgroup_mask\t%08x\n", mMaskGroup); + output_stream << buffer; + buffer = llformat( "\t\teveryone_mask\t%08x\n", mMaskEveryone); + output_stream << buffer; + buffer = llformat( "\t\tnext_owner_mask\t%08x\n", mMaskNextOwner); + output_stream << buffer; + + mCreator.toString(uuid_str); + output_stream << "\t\tcreator_id\t" << uuid_str << "\n"; + + mOwner.toString(uuid_str); + output_stream << "\t\towner_id\t" << uuid_str << "\n"; + + mLastOwner.toString(uuid_str); + output_stream << "\t\tlast_owner_id\t" << uuid_str << "\n"; + + mGroup.toString(uuid_str); + output_stream << "\t\tgroup_id\t" << uuid_str << "\n"; if(mIsGroupOwned) { @@ -772,21 +895,6 @@ std::ostream& operator<<(std::ostream &s, const LLPermissions &perm) return s; } -template <> -void LLMetaClassT::reflectProperties(LLMetaClass& meta_class) -{ - reflectProperty(meta_class, "mCreator", &LLPermissions::mCreator); - reflectProperty(meta_class, "mOwner", &LLPermissions::mOwner); - reflectProperty(meta_class, "mGroup", &LLPermissions::mGroup); - reflectProperty(meta_class, "mIsGroupOwned", &LLPermissions::mIsGroupOwned); -} - -// virtual -const LLMetaClass& LLPermissions::getMetaClass() const -{ - return LLMetaClassT::instance(); -} - ///---------------------------------------------------------------------------- /// Class LLAggregatePermissions ///---------------------------------------------------------------------------- @@ -874,8 +982,8 @@ void LLAggregatePermissions::aggregateBit(EPermIndex idx, BOOL allowed) mBits[idx] = allowed ? AP_ALL : AP_SOME; break; default: - llwarns << "Bad aggregateBit " << (S32)idx << " " - << (allowed ? "true" : "false") << llendl; + LL_WARNS() << "Bad aggregateBit " << (S32)idx << " " + << (allowed ? "true" : "false") << LL_ENDL; break; } } @@ -919,8 +1027,8 @@ void LLAggregatePermissions::aggregateIndex(EPermIndex idx, U8 bits) } break; default: - llwarns << "Bad aggregate index " << (S32)idx << " " - << (S32)bits << llendl; + LL_WARNS() << "Bad aggregate index " << (S32)idx << " " + << (S32)bits << LL_ENDL; break; } } @@ -1021,7 +1129,7 @@ void mask_to_string(U32 mask, char* str) else { *str = ' '; - } + } str++; if (mask & PERM_EXPORT) diff --git a/indra/llinventory/llpermissions.h b/indra/llinventory/llpermissions.h index e6284e542d..a69f6033df 100644 --- a/indra/llinventory/llpermissions.h +++ b/indra/llinventory/llpermissions.h @@ -31,7 +31,6 @@ #include "llsd.h" #include "lluuid.h" #include "llxmlnode.h" -#include "reflective.h" #include "llinventorytype.h" // prototypes @@ -89,7 +88,7 @@ enum ExportPolicy { // logical consistency. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLPermissions : public LLReflective +class LLPermissions { private: LLUUID mCreator; // null if object created by system @@ -319,7 +318,7 @@ class LLPermissions : public LLReflective // LLSD packMessage() const; - void unpackMessage(LLSD perms); + void unpackMessage(const LLSD& perms); // For messaging system support void packMessage(LLMessageSystem* msg) const; @@ -329,17 +328,14 @@ class LLPermissions : public LLReflective BOOL importFile(LLFILE* fp); BOOL exportFile(LLFILE* fp) const; - BOOL importStream(std::istream& input_stream); - BOOL exportStream(std::ostream& output_stream) const; + BOOL importLegacyStream(std::istream& input_stream); + BOOL exportLegacyStream(std::ostream& output_stream) const; bool operator==(const LLPermissions &rhs) const; bool operator!=(const LLPermissions &rhs) const; friend std::ostream& operator<<(std::ostream &s, const LLPermissions &perm); - // Reflection. - friend class LLMetaClassT; - virtual const LLMetaClass& getMetaClass() const; }; // Inlines diff --git a/indra/llinventory/llsaleinfo.cpp b/indra/llinventory/llsaleinfo.cpp index b39f02f6ad..021c1d9d35 100644 --- a/indra/llinventory/llsaleinfo.cpp +++ b/indra/llinventory/llsaleinfo.cpp @@ -87,13 +87,15 @@ U32 LLSaleInfo::getCRC32() const BOOL LLSaleInfo::exportFile(LLFILE* fp) const { - llofstream ofs(fp); - return exportStream(ofs); + fprintf(fp, "\tsale_info\t0\n\t{\n"); + fprintf(fp, "\t\tsale_type\t%s\n", lookup(mSaleType)); + fprintf(fp, "\t\tsale_price\t%d\n", mSalePrice); + fprintf(fp,"\t}\n"); + return TRUE; } -BOOL LLSaleInfo::exportStream(std::ostream& output_stream) const +BOOL LLSaleInfo::exportLegacyStream(std::ostream& output_stream) const { - if (!output_stream.good()) return FALSE; output_stream << "\tsale_info\t0\n\t{\n"; output_stream << "\t\tsale_type\t" << lookup(mSaleType) << "\n"; output_stream << "\t\tsale_price\t" << mSalePrice << "\n"; @@ -137,40 +139,81 @@ bool LLSaleInfo::fromLLSD(const LLSD& sd, BOOL& has_perm_mask, U32& perm_mask) // because I can't find any non-test code references to it. 2009-05-04 JC BOOL LLSaleInfo::importFile(LLFILE* fp, BOOL& has_perm_mask, U32& perm_mask) -{ - llifstream ifs(fp); - return importStream(ifs, has_perm_mask, perm_mask); -} - -BOOL LLSaleInfo::importStream(std::istream& input_stream, BOOL& has_perm_mask, U32& perm_mask) { has_perm_mask = FALSE; - const S32 BUFSIZE = 16384; - // *NOTE: Changing the buffer size will require changing the scanf // calls below. - char buffer[BUFSIZE]; /* Flawfinder: ignore */ - char keyword[255]; /* Flawfinder: ignore */ - char valuestr[255]; /* Flawfinder: ignore */ + char buffer[MAX_STRING]; /* Flawfinder: ignore */ + char keyword[MAX_STRING]; /* Flawfinder: ignore */ + char valuestr[MAX_STRING]; /* Flawfinder: ignore */ + BOOL success = TRUE; keyword[0] = '\0'; valuestr[0] = '\0'; - while(input_stream.good()) + while(success && (!feof(fp))) { - input_stream.getline(buffer, MAX_STRING); - if (input_stream.eof()) + if (fgets(buffer, MAX_STRING, fp) == NULL) + { + buffer[0] = '\0'; + } + + sscanf( /* Flawfinder: ignore */ + buffer, + " %254s %254s", + keyword, valuestr); + if(!keyword[0]) + { + continue; + } + if(0 == strcmp("{",keyword)) + { + continue; + } + if(0 == strcmp("}", keyword)) + { + break; + } + else if(0 == strcmp("sale_type", keyword)) { - llwarns << "Bad sale info: early end of input stream" - << llendl; - return FALSE; + mSaleType = lookup(valuestr); } - if (input_stream.fail()) + else if(0 == strcmp("sale_price", keyword)) { - llwarns << "Bad sale info: failed to read from input stream" - << llendl; - return FALSE; + sscanf(valuestr, "%d", &mSalePrice); + mSalePrice = llclamp(mSalePrice, 0, S32_MAX); } + else if (!strcmp("perm_mask", keyword)) + { + //LL_INFOS() << "found deprecated keyword perm_mask" << LL_ENDL; + has_perm_mask = TRUE; + sscanf(valuestr, "%x", &perm_mask); + } + else + { + LL_WARNS() << "unknown keyword '" << keyword + << "' in sale info import" << LL_ENDL; + } + } + return success; +} + +BOOL LLSaleInfo::importLegacyStream(std::istream& input_stream, BOOL& has_perm_mask, U32& perm_mask) +{ + has_perm_mask = FALSE; + + // *NOTE: Changing the buffer size will require changing the scanf + // calls below. + char buffer[MAX_STRING]; /* Flawfinder: ignore */ + char keyword[MAX_STRING]; /* Flawfinder: ignore */ + char valuestr[MAX_STRING]; /* Flawfinder: ignore */ + BOOL success = TRUE; + + keyword[0] = '\0'; + valuestr[0] = '\0'; + while(success && input_stream.good()) + { + input_stream.getline(buffer, MAX_STRING); sscanf( /* Flawfinder: ignore */ buffer, " %254s %254s", @@ -198,17 +241,17 @@ BOOL LLSaleInfo::importStream(std::istream& input_stream, BOOL& has_perm_mask, U } else if (!strcmp("perm_mask", keyword)) { - //llinfos << "found deprecated keyword perm_mask" << llendl; + //LL_INFOS() << "found deprecated keyword perm_mask" << LL_ENDL; has_perm_mask = TRUE; sscanf(valuestr, "%x", &perm_mask); } else { - llwarns << "unknown keyword '" << keyword - << "' in sale info import" << llendl; + LL_WARNS() << "unknown keyword '" << keyword + << "' in sale info import" << LL_ENDL; } } - return TRUE; + return success; } void LLSaleInfo::setSalePrice(S32 price) @@ -236,7 +279,7 @@ void LLSaleInfo::packMessage(LLMessageSystem* msg) const //msg->addU32Fast(_PREHASH_NextOwnerMask, mNextOwnerPermMask); } -void LLSaleInfo::unpackMessage(LLSD sales) +void LLSaleInfo::unpackMessage(const LLSD& sales) { U8 sale_type = (U8)sales["sale-type"].asInteger(); mSaleType = static_cast(sale_type); diff --git a/indra/llinventory/llsaleinfo.h b/indra/llinventory/llsaleinfo.h index 026e042bcf..262aeb3dd2 100644 --- a/indra/llinventory/llsaleinfo.h +++ b/indra/llinventory/llsaleinfo.h @@ -95,14 +95,14 @@ class LLSaleInfo BOOL exportFile(LLFILE* fp) const; BOOL importFile(LLFILE* fp, BOOL& has_perm_mask, U32& perm_mask); - BOOL exportStream(std::ostream& output_stream) const; + BOOL exportLegacyStream(std::ostream& output_stream) const; LLSD asLLSD() const; operator LLSD() const { return asLLSD(); } bool fromLLSD(const LLSD& sd, BOOL& has_perm_mask, U32& perm_mask); - BOOL importStream(std::istream& input_stream, BOOL& has_perm_mask, U32& perm_mask); + BOOL importLegacyStream(std::istream& input_stream, BOOL& has_perm_mask, U32& perm_mask); LLSD packMessage() const; - void unpackMessage(LLSD sales); + void unpackMessage(const LLSD& sales); // message serialization void packMessage(LLMessageSystem* msg) const; diff --git a/indra/llinventory/llsettingsbase.cpp b/indra/llinventory/llsettingsbase.cpp new file mode 100644 index 0000000000..978edbf2e5 --- /dev/null +++ b/indra/llinventory/llsettingsbase.cpp @@ -0,0 +1,758 @@ +/** +* @file llsettingsbase.cpp +* @author optional +* @brief A base class for asset based settings groups. +* +* $LicenseInfo:2011&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2017, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#include "llsettingsbase.h" + +#include "llmath.h" +#include + +#include "llsdserialize.h" + +//========================================================================= +namespace +{ + const LLSettingsBase::TrackPosition BREAK_POINT = 0.5; +} + +const LLSettingsBase::TrackPosition LLSettingsBase::INVALID_TRACKPOS(-1.0); + +//========================================================================= +std::ostream &operator <<(std::ostream& os, LLSettingsBase &settings) +{ + LLSDSerialize::serialize(settings.getSettings(), os, LLSDSerialize::LLSD_NOTATION); + + return os; +} + +//========================================================================= +const std::string LLSettingsBase::SETTING_ID("id"); +const std::string LLSettingsBase::SETTING_NAME("name"); +const std::string LLSettingsBase::SETTING_HASH("hash"); +const std::string LLSettingsBase::SETTING_TYPE("type"); +const std::string LLSettingsBase::SETTING_ASSETID("asset_id"); +const std::string LLSettingsBase::SETTING_FLAGS("flags"); + +const U32 LLSettingsBase::FLAG_NOCOPY(0x01 << 0); +const U32 LLSettingsBase::FLAG_NOMOD(0x01 << 1); +const U32 LLSettingsBase::FLAG_NOTRANS(0x01 << 2); + +const U32 LLSettingsBase::Validator::VALIDATION_PARTIAL(0x01 << 0); + +//========================================================================= +LLSettingsBase::LLSettingsBase(): + mSettings(LLSD::emptyMap()), + mDirty(true), + mAssetID(), + mBlendedFactor(0.0) +{ +} + +LLSettingsBase::LLSettingsBase(const LLSD setting) : + mSettings(setting), + mDirty(true), + mAssetID(), + mBlendedFactor(0.0) +{ +} + +//========================================================================= +void LLSettingsBase::lerpSettings(const LLSettingsBase &other, F64 mix) +{ + mSettings = interpolateSDMap(mSettings, other.mSettings, other.getParameterMap(), mix); + setDirtyFlag(true); +} + +LLSD LLSettingsBase::combineSDMaps(const LLSD &settings, const LLSD &other) const +{ + LLSD newSettings; + + for (LLSD::map_const_iterator it = settings.beginMap(); it != settings.endMap(); ++it) + { + std::string key_name = (*it).first; + LLSD value = (*it).second; + + LLSD::Type setting_type = value.type(); + switch (setting_type) + { + case LLSD::TypeMap: + newSettings[key_name] = combineSDMaps(value, LLSD()); + break; + case LLSD::TypeArray: + newSettings[key_name] = LLSD::emptyArray(); + for (auto const& entry : value.array()) + { + newSettings[key_name].append(entry); + } + break; + //case LLSD::TypeInteger: + //case LLSD::TypeReal: + //case LLSD::TypeBoolean: + //case LLSD::TypeString: + //case LLSD::TypeUUID: + //case LLSD::TypeURI: + //case LLSD::TypeDate: + //case LLSD::TypeBinary: + default: + newSettings[key_name] = value; + break; + } + } + + if (!other.isUndefined()) + { + for (LLSD::map_const_iterator it = other.beginMap(); it != other.endMap(); ++it) + { + std::string key_name = (*it).first; + LLSD value = (*it).second; + + LLSD::Type setting_type = value.type(); + switch (setting_type) + { + case LLSD::TypeMap: + newSettings[key_name] = combineSDMaps(value, LLSD()); + break; + case LLSD::TypeArray: + newSettings[key_name] = LLSD::emptyArray(); + for (auto const& entry : value.array()) + { + newSettings[key_name].append(entry); + } + break; + //case LLSD::TypeInteger: + //case LLSD::TypeReal: + //case LLSD::TypeBoolean: + //case LLSD::TypeString: + //case LLSD::TypeUUID: + //case LLSD::TypeURI: + //case LLSD::TypeDate: + //case LLSD::TypeBinary: + default: + newSettings[key_name] = value; + break; + } + } + } + + return newSettings; +} + +LLSD LLSettingsBase::interpolateSDMap(const LLSD &settings, const LLSD &other, const parammapping_t& defaults, F64 mix) const +{ + LLSD newSettings; + + stringset_t skip = getSkipInterpolateKeys(); + stringset_t slerps = getSlerpKeys(); + + for (LLSD::map_const_iterator it = settings.beginMap(); it != settings.endMap(); ++it) + { + std::string key_name = (*it).first; + LLSD value = (*it).second; + + if (skip.find(key_name) != skip.end()) + continue; + + LLSD other_value; + if (other.has(key_name)) + { + other_value = other[key_name]; + } + else + { + parammapping_t::const_iterator def_iter = defaults.find(key_name); + if (def_iter != defaults.end()) + { + other_value = def_iter->second.getDefaultValue(); + } + else if (value.type() == LLSD::TypeMap) + { + // interpolate in case there are defaults inside (part of legacy) + other_value = LLSDMap(); + } + else + { + // The other or defaults does not contain this setting, keep the original value + // TODO: Should I blend this out instead? + newSettings[key_name] = value; + continue; + } + } + + newSettings[key_name] = interpolateSDValue(key_name, value, other_value, defaults, mix, slerps); + } + + // Special handling cases + // Flags + if (settings.has(SETTING_FLAGS)) + { + U32 flags = (U32)settings[SETTING_FLAGS].asInteger(); + if (other.has(SETTING_FLAGS)) + flags |= (U32)other[SETTING_FLAGS].asInteger(); + + newSettings[SETTING_FLAGS] = LLSD::Integer(flags); + } + + // Now add anything that is in other but not in the settings + for (LLSD::map_const_iterator it = other.beginMap(); it != other.endMap(); ++it) + { + std::string key_name = (*it).first; + + if (skip.find(key_name) != skip.end()) + continue; + + if (settings.has(key_name)) + continue; + + parammapping_t::const_iterator def_iter = defaults.find(key_name); + if (def_iter != defaults.end()) + { + // Blend against default value + newSettings[key_name] = interpolateSDValue(key_name, def_iter->second.getDefaultValue(), (*it).second, defaults, mix, slerps); + } + else if ((*it).second.type() == LLSD::TypeMap) + { + // interpolate in case there are defaults inside (part of legacy) + newSettings[key_name] = interpolateSDValue(key_name, LLSDMap(), (*it).second, defaults, mix, slerps); + } + // else do nothing when no known defaults + // TODO: Should I blend this out instead? + } + + // Note: writes variables from skip list, bug? + for (LLSD::map_const_iterator it = other.beginMap(); it != other.endMap(); ++it) + { + // TODO: Should I blend this in instead? + if (skip.find((*it).first) == skip.end()) + continue; + + if (!settings.has((*it).first)) + continue; + + newSettings[(*it).first] = (*it).second; + } + + return newSettings; +} + +LLSD LLSettingsBase::interpolateSDValue(const std::string& key_name, const LLSD &value, const LLSD &other_value, const parammapping_t& defaults, BlendFactor mix, const stringset_t& slerps) const +{ + LLSD new_value; + + LLSD::Type setting_type = value.type(); + + if (other_value.type() != setting_type) + { + // The data type mismatched between this and other. Hard switch when we pass the break point + // but issue a warning. + LL_WARNS("SETTINGS") << "Setting lerp between mismatched types for '" << key_name << "'." << LL_ENDL; + new_value = (mix > BREAK_POINT) ? other_value : value; + } + + switch (setting_type) + { + case LLSD::TypeInteger: + // lerp between the two values rounding the result to the nearest integer. + new_value = LLSD::Integer(llroundf(lerp(value.asReal(), other_value.asReal(), mix))); + break; + case LLSD::TypeReal: + // lerp between the two values. + new_value = LLSD::Real(lerp(value.asReal(), other_value.asReal(), mix)); + break; + case LLSD::TypeMap: + // deep copy. + new_value = interpolateSDMap(value, other_value, defaults, mix); + break; + + case LLSD::TypeArray: + { + LLSD new_array(LLSD::emptyArray()); + + if (slerps.find(key_name) != slerps.end()) + { + LLQuaternion a(value); + LLQuaternion b(other_value); + LLQuaternion q = slerp(mix, a, b); + new_array = q.getValue(); + } + else + { // TODO: We could expand this to inspect the type and do a deep lerp based on type. + // for now assume a heterogeneous array of reals. + size_t len = std::max(value.size(), other_value.size()); + + for (size_t i = 0; i < len; ++i) + { + + new_array[i] = lerp(value[i].asReal(), other_value[i].asReal(), mix); + } + } + + new_value = new_array; + } + + break; + + case LLSD::TypeUUID: + new_value = value.asUUID(); + break; + + // case LLSD::TypeBoolean: + // case LLSD::TypeString: + // case LLSD::TypeURI: + // case LLSD::TypeBinary: + // case LLSD::TypeDate: + default: + // atomic or unknown data types. Lerping between them does not make sense so switch at the break. + new_value = (mix > BREAK_POINT) ? other_value : value; + break; + } + + return new_value; +} + +LLSettingsBase::stringset_t LLSettingsBase::getSkipInterpolateKeys() const +{ + static stringset_t skipSet; + + if (skipSet.empty()) + { + skipSet.insert(SETTING_FLAGS); + skipSet.insert(SETTING_HASH); + } + + return skipSet; +} + +LLSD LLSettingsBase::getSettings() const +{ + return mSettings; +} + +LLSD LLSettingsBase::cloneSettings() const +{ + return combineSDMaps(getSettings(), LLSD()); +} + +size_t LLSettingsBase::getHash() const +{ // get a shallow copy of the LLSD filtering out values to not include in the hash + LLSD hash_settings = llsd_shallow(getSettings(), + LLSDMap(SETTING_NAME, false)(SETTING_ID, false)(SETTING_HASH, false)("*", true)); + + boost::hash hasher; + return hasher(hash_settings); +} + +bool LLSettingsBase::validate() +{ + validation_list_t validations = getValidationList(); + + if (!mSettings.has(SETTING_TYPE)) + { + mSettings[SETTING_TYPE] = getSettingsType(); + } + + LLSD result = LLSettingsBase::settingValidation(mSettings, validations); + + if (result["errors"].size() > 0) + { + LL_WARNS("SETTINGS") << "Validation errors: " << result["errors"] << LL_ENDL; + } + if (result["warnings"].size() > 0) + { + LL_DEBUGS("SETTINGS") << "Validation warnings: " << result["warnings"] << LL_ENDL; + } + + return result["success"].asBoolean(); +} + +LLSD LLSettingsBase::settingValidation(LLSD &settings, validation_list_t &validations, bool partial) +{ + static Validator validateName(SETTING_NAME, false, LLSD::TypeString, boost::bind(&Validator::verifyStringLength, _1, 32)); + static Validator validateId(SETTING_ID, false, LLSD::TypeUUID); + static Validator validateHash(SETTING_HASH, false, LLSD::TypeInteger); + static Validator validateType(SETTING_TYPE, false, LLSD::TypeString); + static Validator validateAssetId(SETTING_ASSETID, false, LLSD::TypeUUID); + static Validator validateFlags(SETTING_FLAGS, false, LLSD::TypeInteger); + stringset_t validated; + stringset_t strip; + bool isValid(true); + LLSD errors(LLSD::emptyArray()); + LLSD warnings(LLSD::emptyArray()); + U32 flags(0); + + if (partial) + flags |= Validator::VALIDATION_PARTIAL; + + // Fields common to all settings. + if (!validateName.verify(settings, flags)) + { + errors.append( LLSD::String("Unable to validate 'name'.") ); + isValid = false; + } + validated.insert(validateName.getName()); + + if (!validateId.verify(settings, flags)) + { + errors.append( LLSD::String("Unable to validate 'id'.") ); + isValid = false; + } + validated.insert(validateId.getName()); + + if (!validateHash.verify(settings, flags)) + { + errors.append( LLSD::String("Unable to validate 'hash'.") ); + isValid = false; + } + validated.insert(validateHash.getName()); + + if (!validateAssetId.verify(settings, flags)) + { + errors.append(LLSD::String("Invalid asset Id")); + isValid = false; + } + validated.insert(validateAssetId.getName()); + + if (!validateType.verify(settings, flags)) + { + errors.append( LLSD::String("Unable to validate 'type'.") ); + isValid = false; + } + validated.insert(validateType.getName()); + + if (!validateFlags.verify(settings, flags)) + { + errors.append(LLSD::String("Unable to validate 'flags'.")); + isValid = false; + } + validated.insert(validateFlags.getName()); + + // Fields for specific settings. + for (validation_list_t::iterator itv = validations.begin(); itv != validations.end(); ++itv) + { +#ifdef VALIDATION_DEBUG + LLSD oldvalue; + if (settings.has((*itv).getName())) + { + oldvalue = llsd_clone(mSettings[(*itv).getName()]); + } +#endif + + if (!(*itv).verify(settings, flags)) + { + std::stringstream errtext; + + errtext << "Settings LLSD fails validation and could not be corrected for '" << (*itv).getName() << "'!\n"; + errors.append( errtext.str() ); + isValid = false; + } + validated.insert((*itv).getName()); + +#ifdef VALIDATION_DEBUG + if (!oldvalue.isUndefined()) + { + if (!compare_llsd(settings[(*itv).getName()], oldvalue)) + { + LL_WARNS("SETTINGS") << "Setting '" << (*itv).getName() << "' was changed: " << oldvalue << " -> " << settings[(*itv).getName()] << LL_ENDL; + } + } +#endif + } + + // strip extra entries + for (LLSD::map_const_iterator itm = settings.beginMap(); itm != settings.endMap(); ++itm) + { + if (validated.find((*itm).first) == validated.end()) + { + std::stringstream warntext; + + warntext << "Stripping setting '" << (*itm).first << "'"; + warnings.append( warntext.str() ); + strip.insert((*itm).first); + } + } + + for (stringset_t::iterator its = strip.begin(); its != strip.end(); ++its) + { + settings.erase(*its); + } + + return LLSDMap("success", LLSD::Boolean(isValid)) + ("errors", errors) + ("warnings", warnings); +} + +//========================================================================= + +bool LLSettingsBase::Validator::verify(LLSD &data, U32 flags) +{ + if (!data.has(mName) || (data.has(mName) && data[mName].isUndefined())) + { + if ((flags & VALIDATION_PARTIAL) != 0) // we are doing a partial validation. Do no attempt to set a default if missing (or fail even if required) + return true; + + if (!mDefault.isUndefined()) + { + data[mName] = mDefault; + return true; + } + if (mRequired) + LL_WARNS("SETTINGS") << "Missing required setting '" << mName << "' with no default." << LL_ENDL; + return !mRequired; + } + + if (data[mName].type() != mType) + { + LL_WARNS("SETTINGS") << "Setting '" << mName << "' is incorrect type." << LL_ENDL; + return false; + } + + if (!mVerify.empty() && !mVerify(data[mName])) + { + LL_WARNS("SETTINGS") << "Setting '" << mName << "' fails validation." << LL_ENDL; + return false; + } + + return true; +} + +bool LLSettingsBase::Validator::verifyColor(LLSD &value) +{ + return (value.size() == 3 || value.size() == 4); +} + +bool LLSettingsBase::Validator::verifyVector(LLSD &value, S32 length) +{ + return (value.size() == length); +} + +bool LLSettingsBase::Validator::verifyVectorNormalized(LLSD &value, S32 length) +{ + if (value.size() != length) + return false; + + LLSD newvector; + + switch (length) + { + case 2: + { + LLVector2 vect(value); + + if (is_approx_equal(vect.normalize(), 1.0f)) + return true; + newvector = vect.getValue(); + break; + } + case 3: + { + LLVector3 vect(value); + + if (is_approx_equal(vect.normalize(), 1.0f)) + return true; + newvector = vect.getValue(); + break; + } + case 4: + { + LLVector4 vect(value); + + if (is_approx_equal(vect.normalize(), 1.0f)) + return true; + newvector = vect.getValue(); + break; + } + default: + return false; + } + + return true; +} + +bool LLSettingsBase::Validator::verifyVectorMinMax(LLSD &value, LLSD minvals, LLSD maxvals) +{ + for (S32 index = 0; index < value.size(); ++index) + { + if (minvals[index].asString() != "*") + { + if (minvals[index].asReal() > value[index].asReal()) + { + value[index] = minvals[index].asReal(); + } + } + if (maxvals[index].asString() != "*") + { + if (maxvals[index].asReal() < value[index].asReal()) + { + value[index] = maxvals[index].asReal(); + } + } + } + + return true; +} + +bool LLSettingsBase::Validator::verifyQuaternion(LLSD &value) +{ + return (value.size() == 4); +} + +bool LLSettingsBase::Validator::verifyQuaternionNormal(LLSD &value) +{ + if (value.size() != 4) + return false; + + LLQuaternion quat(value); + + if (is_approx_equal(quat.normalize(), 1.0f)) + return true; + + LLSD newquat = quat.getValue(); + for (S32 index = 0; index < 4; ++index) + { + value[index] = newquat[index]; + } + return true; +} + +bool LLSettingsBase::Validator::verifyFloatRange(LLSD &value, LLSD range) +{ + F64 real = value.asReal(); + + F64 clampedval = llclamp(LLSD::Real(real), range[0].asReal(), range[1].asReal()); + + if (is_approx_equal(clampedval, real)) + return true; + + value = LLSD::Real(clampedval); + return true; +} + +bool LLSettingsBase::Validator::verifyIntegerRange(LLSD &value, LLSD range) +{ + S32 ival = value.asInteger(); + + S32 clampedval = llclamp(LLSD::Integer(ival), range[0].asInteger(), range[1].asInteger()); + + if (clampedval == ival) + return true; + + value = LLSD::Integer(clampedval); + return true; +} + +bool LLSettingsBase::Validator::verifyStringLength(LLSD &value, S32 length) +{ + std::string sval = value.asString(); + + if (!sval.empty()) + { + sval = sval.substr(0, length); + value = LLSD::String(sval); + } + return true; +} + +//========================================================================= +void LLSettingsBlender::update(const LLSettingsBase::BlendFactor& blendf) +{ + F64 res = setBlendFactor(blendf); + + if ((res >= 0.0001) && (res < 1.0)) + mTarget->update(); +} + +F64 LLSettingsBlender::setBlendFactor(const LLSettingsBase::BlendFactor& blendf_in) +{ + LLSettingsBase::TrackPosition blendf = blendf_in; + if (blendf >= 1.0) + { + triggerComplete(); + return 1.0; + } + blendf = llclamp(blendf, 0.0f, 1.0f); + + if (mTarget) + { + mTarget->replaceSettings(mInitial->getSettings()); + if (!mFinal || (mInitial == mFinal) || (blendf == 0.0)) + { // this is a trivial blend. Results will be identical to the initial. + return blendf; + } + mTarget->blend(mFinal, blendf); + } + else + { + LL_WARNS("SETTINGS") << "No target for settings blender." << LL_ENDL; + } + + return blendf; +} + +void LLSettingsBlender::triggerComplete() +{ + if (mTarget) + mTarget->replaceSettings(mFinal->getSettings()); + LLSettingsBlender::ptr_t hold = shared_from_this(); // prevents this from deleting too soon + mTarget->update(); + mOnFinished(shared_from_this()); +} + +//------------------------------------------------------------------------- +const LLSettingsBase::BlendFactor LLSettingsBlenderTimeDelta::MIN_BLEND_DELTA(0.001); + +LLSettingsBase::BlendFactor LLSettingsBlenderTimeDelta::calculateBlend(const LLSettingsBase::TrackPosition& spanpos, const LLSettingsBase::TrackPosition& spanlen) const +{ + return LLSettingsBase::BlendFactor(fmod((F64)spanpos, (F64)spanlen) / (F64)spanlen); +} + +bool LLSettingsBlenderTimeDelta::applyTimeDelta(const LLSettingsBase::Seconds& timedelta) +{ + mTimeSpent += timedelta; + mTimeDeltaPassed += timedelta; + + if (mTimeSpent > mBlendSpan) + { + mIgnoreTimeDelta = false; + triggerComplete(); + return false; + } + + if ((mTimeDeltaPassed < mTimeDeltaThreshold) && (!mIgnoreTimeDelta)) + { + return false; + } + + LLSettingsBase::BlendFactor blendf = calculateBlend(mTimeSpent, mBlendSpan); + mTimeDeltaPassed = LLSettingsBase::Seconds(0.0); + + if (fabs(mLastBlendF - blendf) < mBlendFMinDelta) + { + return false; + } + + mLastBlendF = blendf; + update(blendf); + return true; +} diff --git a/indra/llinventory/llsettingsbase.h b/indra/llinventory/llsettingsbase.h new file mode 100644 index 0000000000..592ae3478a --- /dev/null +++ b/indra/llinventory/llsettingsbase.h @@ -0,0 +1,538 @@ +/** +* @file llsettingsbase.h +* @author optional +* @brief A base class for asset based settings groups. +* +* $LicenseInfo:2011&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2017, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#ifndef LL_SETTINGS_BASE_H +#define LL_SETTINGS_BASE_H + +#include +#include +#include +#include + +#include "llsd.h" +#include "llsdutil.h" +#include "v2math.h" +#include "v3math.h" +#include "v4math.h" +#include "llquaternion.h" +#include "v4color.h" +#include "v3color.h" +#include "llunits.h" + +#include "llinventorysettings.h" + +#define PTR_NAMESPACE std +#define SETTINGS_OVERRIDE override + +class LLSettingsBase : + public PTR_NAMESPACE::enable_shared_from_this, + private boost::noncopyable +{ + friend class LLEnvironment; + friend class LLSettingsDay; + + friend std::ostream &operator <<(std::ostream& os, LLSettingsBase &settings); + +protected: + LOG_CLASS(LLSettingsBase); +public: + typedef F64Seconds Seconds; + typedef F64 BlendFactor; + typedef F32 TrackPosition; // 32-bit as these are stored in LLSD as such + static const TrackPosition INVALID_TRACKPOS; + + static const std::string SETTING_ID; + static const std::string SETTING_NAME; + static const std::string SETTING_HASH; + static const std::string SETTING_TYPE; + static const std::string SETTING_ASSETID; + static const std::string SETTING_FLAGS; + + static const U32 FLAG_NOCOPY; + static const U32 FLAG_NOMOD; + static const U32 FLAG_NOTRANS; + + class DefaultParam + { + public: + DefaultParam(S32 key, const LLSD& value) : mShaderKey(key), mDefaultValue(value) {} + DefaultParam() : mShaderKey(-1) {} + S32 getShaderKey() const { return mShaderKey; } + const LLSD getDefaultValue() const { return mDefaultValue; } + + private: + S32 mShaderKey; + LLSD mDefaultValue; + }; + // Contains settings' names (map key), related shader id-key and default + // value for revert in case we need to reset shader (no need to search each time) + typedef std::map parammapping_t; + + typedef PTR_NAMESPACE::shared_ptr ptr_t; + + virtual ~LLSettingsBase() { }; + + //--------------------------------------------------------------------- + virtual std::string getSettingsType() const = 0; + + virtual LLSettingsType::type_e getSettingsTypeValue() const = 0; + + //--------------------------------------------------------------------- + // Settings status + inline bool hasSetting(const std::string ¶m) const { return mSettings.has(param); } + virtual bool isDirty() const { return mDirty; } + virtual bool isVeryDirty() const { return mReplaced; } + inline void setDirtyFlag(bool dirty) { mDirty = dirty; clearAssetId(); } + + size_t getHash() const; // Hash will not include Name, ID or a previously stored Hash + + inline LLUUID getId() const + { + return getValue(SETTING_ID).asUUID(); + } + + inline std::string getName() const + { + return getValue(SETTING_NAME).asString(); + } + + inline void setName(std::string val) + { + setValue(SETTING_NAME, val); + } + + inline LLUUID getAssetId() const + { + if (mSettings.has(SETTING_ASSETID)) + return mSettings[SETTING_ASSETID].asUUID(); + return LLUUID(); + } + + inline U32 getFlags() const + { + if (mSettings.has(SETTING_FLAGS)) + return static_cast(mSettings[SETTING_FLAGS].asInteger()); + return 0; + } + + inline void setFlags(U32 value) + { + setLLSD(SETTING_FLAGS, LLSD::Integer(value)); + } + + inline bool getFlag(U32 flag) const + { + if (mSettings.has(SETTING_FLAGS)) + return ((U32)mSettings[SETTING_FLAGS].asInteger() & flag) == flag; + return false; + } + + inline void setFlag(U32 flag) + { + U32 flags((mSettings.has(SETTING_FLAGS)) ? (U32)mSettings[SETTING_FLAGS].asInteger() : 0); + + flags |= flag; + + if (flags) + mSettings[SETTING_FLAGS] = LLSD::Integer(flags); + else + mSettings.erase(SETTING_FLAGS); + } + + inline void clearFlag(U32 flag) + { + U32 flags((mSettings.has(SETTING_FLAGS)) ? (U32)mSettings[SETTING_FLAGS].asInteger() : 0); + + flags &= ~flag; + + if (flags) + mSettings[SETTING_FLAGS] = LLSD::Integer(flags); + else + mSettings.erase(SETTING_FLAGS); + } + + virtual void replaceSettings(LLSD settings) + { + mBlendedFactor = 0.0; + setDirtyFlag(true); + mReplaced = true; + mSettings = settings; + } + + virtual LLSD getSettings() const; + + //--------------------------------------------------------------------- + // + inline void setLLSD(const std::string &name, const LLSD &value) + { + mSettings[name] = value; + mDirty = true; + if (name != SETTING_ASSETID) + clearAssetId(); + } + + inline void setValue(const std::string &name, const LLSD &value) + { + setLLSD(name, value); + } + + inline LLSD getValue(const std::string &name, const LLSD &deflt = LLSD()) const + { + if (!mSettings.has(name)) + return deflt; + return mSettings[name]; + } + + inline void setValue(const std::string &name, F32 v) + { + setLLSD(name, LLSD::Real(v)); + } + + inline void setValue(const std::string &name, const LLVector2 &value) + { + setValue(name, value.getValue()); + } + + inline void setValue(const std::string &name, const LLVector3 &value) + { + setValue(name, value.getValue()); + } + + inline void setValue(const std::string &name, const LLVector4 &value) + { + setValue(name, value.getValue()); + } + + inline void setValue(const std::string &name, const LLQuaternion &value) + { + setValue(name, value.getValue()); + } + + inline void setValue(const std::string &name, const LLColor3 &value) + { + setValue(name, value.getValue()); + } + + inline void setValue(const std::string &name, const LLColor4 &value) + { + setValue(name, value.getValue()); + } + + inline BlendFactor getBlendFactor() const + { + return mBlendedFactor; + } + + // Note this method is marked const but may modify the settings object. + // (note the internal const cast). This is so that it may be called without + // special consideration from getters. + inline void update() const + { + if ((!mDirty) && (!mReplaced)) + return; + (const_cast(this))->updateSettings(); + } + + virtual void blend(const ptr_t &end, BlendFactor blendf) = 0; + + virtual bool validate(); + + virtual ptr_t buildDerivedClone() const = 0; + + class Validator + { + public: + static const U32 VALIDATION_PARTIAL; + + typedef boost::function verify_pr; + + Validator(std::string name, bool required, LLSD::Type type, verify_pr verify = verify_pr(), LLSD defval = LLSD()) : + mName(name), + mRequired(required), + mType(type), + mVerify(verify), + mDefault(defval) + { } + + std::string getName() const { return mName; } + bool isRequired() const { return mRequired; } + LLSD::Type getType() const { return mType; } + + bool verify(LLSD &data, U32 flags); + + // Some basic verifications + static bool verifyColor(LLSD &value); + static bool verifyVector(LLSD &value, S32 length); + static bool verifyVectorMinMax(LLSD &value, LLSD minvals, LLSD maxvals); + static bool verifyVectorNormalized(LLSD &value, S32 length); + static bool verifyQuaternion(LLSD &value); + static bool verifyQuaternionNormal(LLSD &value); + static bool verifyFloatRange(LLSD &value, LLSD range); + static bool verifyIntegerRange(LLSD &value, LLSD range); + static bool verifyStringLength(LLSD &value, S32 length); + + private: + std::string mName; + bool mRequired; + LLSD::Type mType; + verify_pr mVerify; + LLSD mDefault; + }; + typedef std::vector validation_list_t; + + static LLSD settingValidation(LLSD &settings, validation_list_t &validations, bool partial = false); + + inline void setAssetId(LLUUID value) + { // note that this skips setLLSD + mSettings[SETTING_ASSETID] = value; + } + + inline void clearAssetId() + { + if (mSettings.has(SETTING_ASSETID)) + mSettings.erase(SETTING_ASSETID); + } + + // Calculate any custom settings that may need to be cached. + virtual void updateSettings() { mDirty = false; mReplaced = false; } +protected: + + LLSettingsBase(); + LLSettingsBase(const LLSD setting); + + static LLSD settingValidation(LLSD settings); + + typedef std::set stringset_t; + + // combining settings objects. Customize for specific setting types + virtual void lerpSettings(const LLSettingsBase &other, BlendFactor mix); + + // combining settings maps where it can based on mix rate + // @settings initial value (mix==0) + // @other target value (mix==1) + // @defaults list of default values for legacy fields and (re)setting shaders + // @mix from 0 to 1, ratio or rate of transition from initial 'settings' to 'other' + // return interpolated and combined LLSD map + LLSD interpolateSDMap(const LLSD &settings, const LLSD &other, const parammapping_t& defaults, BlendFactor mix) const; + LLSD interpolateSDValue(const std::string& name, const LLSD &value, const LLSD &other, const parammapping_t& defaults, BlendFactor mix, const stringset_t& slerps) const; + + /// when lerping between settings, some may require special handling. + /// Get a list of these key to be skipped by the default settings lerp. + /// (handling should be performed in the override of lerpSettings. + virtual stringset_t getSkipInterpolateKeys() const; + + // A list of settings that represent quaternions and should be slerped + // rather than lerped. + virtual stringset_t getSlerpKeys() const { return stringset_t(); } + + virtual validation_list_t getValidationList() const = 0; + + // Apply any settings that need special handling. + virtual void applySpecial(void *) { }; + + virtual parammapping_t getParameterMap() const { return parammapping_t(); } + + LLSD mSettings; + bool mIsValid; + LLAssetID mAssetID; + + LLSD cloneSettings() const; + + inline void setBlendFactor(BlendFactor blendfactor) + { + mBlendedFactor = blendfactor; + } + + void replaceWith(LLSettingsBase::ptr_t other) + { + replaceSettings(other->cloneSettings()); + setBlendFactor(other->getBlendFactor()); + } + +private: + bool mDirty; + bool mReplaced; // super dirty! + + LLSD combineSDMaps(const LLSD &first, const LLSD &other) const; + + BlendFactor mBlendedFactor; +}; + + +class LLSettingsBlender : public PTR_NAMESPACE::enable_shared_from_this +{ + LOG_CLASS(LLSettingsBlender); +public: + typedef PTR_NAMESPACE::shared_ptr ptr_t; + typedef boost::signals2::signal finish_signal_t; + typedef boost::signals2::connection connection_t; + + LLSettingsBlender(const LLSettingsBase::ptr_t &target, + const LLSettingsBase::ptr_t &initsetting, const LLSettingsBase::ptr_t &endsetting) : + mOnFinished(), + mTarget(target), + mInitial(initsetting), + mFinal(endsetting) + { + if (mInitial && mTarget) + mTarget->replaceSettings(mInitial->getSettings()); + + if (!mFinal) + mFinal = mInitial; + } + + virtual ~LLSettingsBlender() {} + + virtual void reset( LLSettingsBase::ptr_t &initsetting, const LLSettingsBase::ptr_t &endsetting, const LLSettingsBase::TrackPosition&) + { + // note: the 'span' reset parameter is unused by the base class. + if (!mInitial) + LL_WARNS("BLENDER") << "Reseting blender with empty initial setting. Expect badness in the future." << LL_ENDL; + + mInitial = initsetting; + mFinal = endsetting; + + if (!mFinal) + mFinal = mInitial; + + if (mTarget) + mTarget->replaceSettings(mInitial->getSettings()); + } + + LLSettingsBase::ptr_t getTarget() const + { + return mTarget; + } + + LLSettingsBase::ptr_t getInitial() const + { + return mInitial; + } + + LLSettingsBase::ptr_t getFinal() const + { + return mFinal; + } + + connection_t setOnFinished(const finish_signal_t::slot_type &onfinished) + { + return mOnFinished.connect(onfinished); + } + + virtual void update(const LLSettingsBase::BlendFactor& blendf); + virtual bool applyTimeDelta(const LLSettingsBase::Seconds& timedelta) + { + llassert(false); + // your derived class needs to implement an override of this func + return false; + } + + virtual F64 setBlendFactor(const LLSettingsBase::BlendFactor& position); + + virtual void switchTrack(S32 trackno, const LLSettingsBase::TrackPosition& position) { /*NoOp*/ } + +protected: + void triggerComplete(); + + finish_signal_t mOnFinished; + + LLSettingsBase::ptr_t mTarget; + LLSettingsBase::ptr_t mInitial; + LLSettingsBase::ptr_t mFinal; +}; + +class LLSettingsBlenderTimeDelta : public LLSettingsBlender +{ + LOG_CLASS(LLSettingsBlenderTimeDelta); +public: + static const LLSettingsBase::BlendFactor MIN_BLEND_DELTA; + + LLSettingsBlenderTimeDelta(const LLSettingsBase::ptr_t &target, + const LLSettingsBase::ptr_t &initsetting, const LLSettingsBase::ptr_t &endsetting, const LLSettingsBase::Seconds& blend_span) : + LLSettingsBlender(target, initsetting, endsetting), + mBlendSpan(blend_span), + mLastUpdate(0.0f), + mTimeSpent(0.0f), + mTimeDeltaThreshold(0.0f), + mTimeDeltaPassed(0.0f), + mIgnoreTimeDelta(false), + mBlendFMinDelta(MIN_BLEND_DELTA), + mLastBlendF(-1.0f) + { + mTimeStart = LLSettingsBase::Seconds(LLDate::now().secondsSinceEpoch()); + mLastUpdate = mTimeStart; + } + + virtual ~LLSettingsBlenderTimeDelta() + { + } + + virtual void reset(LLSettingsBase::ptr_t &initsetting, const LLSettingsBase::ptr_t &endsetting, const LLSettingsBase::TrackPosition& blend_span) SETTINGS_OVERRIDE + { + LLSettingsBlender::reset(initsetting, endsetting, blend_span); + + mBlendSpan = blend_span; + mTimeStart = LLSettingsBase::Seconds(LLDate::now().secondsSinceEpoch()); + mLastUpdate = mTimeStart; + mTimeSpent = LLSettingsBase::Seconds(0.0f); + mTimeDeltaPassed = LLSettingsBase::Seconds(0.0f); + mLastBlendF = LLSettingsBase::BlendFactor(-1.0f); + } + + virtual bool applyTimeDelta(const LLSettingsBase::Seconds& timedelta) SETTINGS_OVERRIDE; + + inline void setTimeDeltaThreshold(const LLSettingsBase::Seconds time) + { + mTimeDeltaThreshold = time; + mTimeDeltaPassed = time + LLSettingsBase::Seconds(1.0); // take the next update call. + } + + inline LLSettingsBase::Seconds getTimeDeltaThreshold() const + { + return mTimeDeltaThreshold; + } + + inline void setIgnoreTimeDeltaThreshold(bool val) { mIgnoreTimeDelta = val; } + inline bool getIgnoreTimeDeltaThreshold() const { return mIgnoreTimeDelta; } + + inline void setTimeSpent(LLSettingsBase::Seconds time) { mTimeSpent = time; } +protected: + LLSettingsBase::BlendFactor calculateBlend(const LLSettingsBase::TrackPosition& spanpos, const LLSettingsBase::TrackPosition& spanlen) const; + + LLSettingsBase::TrackPosition mBlendSpan; + LLSettingsBase::Seconds mLastUpdate; + LLSettingsBase::Seconds mTimeSpent; + LLSettingsBase::Seconds mTimeStart; + LLSettingsBase::Seconds mTimeDeltaThreshold; + LLSettingsBase::Seconds mTimeDeltaPassed; + bool mIgnoreTimeDelta; + LLSettingsBase::BlendFactor mBlendFMinDelta; + LLSettingsBase::BlendFactor mLastBlendF; +}; + + +#endif diff --git a/indra/llinventory/llsettingsdaycycle.cpp b/indra/llinventory/llsettingsdaycycle.cpp new file mode 100644 index 0000000000..bfb755fd00 --- /dev/null +++ b/indra/llinventory/llsettingsdaycycle.cpp @@ -0,0 +1,891 @@ +/** +* @file llsettingsdaycycle.cpp +* @author optional +* @brief A base class for asset based settings groups. +* +* $LicenseInfo:2011&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2017, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#include "llsettingsdaycycle.h" +#include "llerror.h" +#include +#include +#include "llfasttimer.h" +#include "v3colorutil.h" + +#include "llsettingssky.h" +#include "llsettingswater.h" + +#include "llframetimer.h" + +//========================================================================= +namespace +{ + LLTrace::BlockTimerStatHandle FTM_BLEND_WATERVALUES("Blending Water Environment"); + LLTrace::BlockTimerStatHandle FTM_UPDATE_WATERVALUES("Update Water Environment"); + + template + inline T get_wrapping_distance(T begin, T end) + { + if (begin < end) + { + return end - begin; + } + else if (begin > end) + { + return T(1.0) - (begin - end); + } + + return 0; + } + + LLSettingsDay::CycleTrack_t::iterator get_wrapping_atafter(LLSettingsDay::CycleTrack_t &collection, const LLSettingsBase::TrackPosition& key) + { + if (collection.empty()) + return collection.end(); + + LLSettingsDay::CycleTrack_t::iterator it = collection.upper_bound(key); + + if (it == collection.end()) + { // wrap around + it = collection.begin(); + } + + return it; + } + + LLSettingsDay::CycleTrack_t::iterator get_wrapping_atbefore(LLSettingsDay::CycleTrack_t &collection, const LLSettingsBase::TrackPosition& key) + { + if (collection.empty()) + return collection.end(); + + LLSettingsDay::CycleTrack_t::iterator it = collection.lower_bound(key); + + if (it == collection.end()) + { // all keyframes are lower, take the last one. + --it; // we know the range is not empty + } + else if ((*it).first > key) + { // the keyframe we are interested in is smaller than the found. + if (it == collection.begin()) + it = collection.end(); + --it; + } + + return it; + } + + +} + +//========================================================================= +const std::string LLSettingsDay::SETTING_KEYID("key_id"); +const std::string LLSettingsDay::SETTING_KEYNAME("key_name"); +const std::string LLSettingsDay::SETTING_KEYKFRAME("key_keyframe"); +const std::string LLSettingsDay::SETTING_KEYHASH("key_hash"); +const std::string LLSettingsDay::SETTING_TRACKS("tracks"); +const std::string LLSettingsDay::SETTING_FRAMES("frames"); + +const LLSettingsDay::Seconds LLSettingsDay::MINIMUM_DAYLENGTH(14400); // 4 hours +const LLSettingsDay::Seconds LLSettingsDay::DEFAULT_DAYLENGTH(14400); // 4 hours +const LLSettingsDay::Seconds LLSettingsDay::MAXIMUM_DAYLENGTH(604800); // 7 days + +const LLSettingsDay::Seconds LLSettingsDay::MINIMUM_DAYOFFSET(0); +const LLSettingsDay::Seconds LLSettingsDay::DEFAULT_DAYOFFSET(57600); // +16 hours == -8 hours (SLT time offset) +const LLSettingsDay::Seconds LLSettingsDay::MAXIMUM_DAYOFFSET(86400); // 24 hours + +const S32 LLSettingsDay::TRACK_WATER(0); // water track is 0 +const S32 LLSettingsDay::TRACK_GROUND_LEVEL(1); +const S32 LLSettingsDay::TRACK_MAX(5); // 5 tracks, 4 skys, 1 water +const S32 LLSettingsDay::FRAME_MAX(56); + +const F32 LLSettingsDay::DEFAULT_FRAME_SLOP_FACTOR(0.02501f); + +const LLUUID LLSettingsDay::DEFAULT_ASSET_ID("78751d18-6c51-3c43-2887-3654cd427a42"); + +// Minimum value to prevent multislider in edit floaters from eating up frames that 'encroach' on one another's space +static const F32 DEFAULT_MULTISLIDER_INCREMENT(0.005f); +//========================================================================= +LLSettingsDay::LLSettingsDay(const LLSD &data) : + LLSettingsBase(data), + mInitialized(false) +{ + mDayTracks.resize(TRACK_MAX); +} + +LLSettingsDay::LLSettingsDay() : + LLSettingsBase(), + mInitialized(false) +{ + mDayTracks.resize(TRACK_MAX); +} + +//========================================================================= +LLSD LLSettingsDay::getSettings() const +{ + LLSD settings(LLSD::emptyMap()); + + if (mSettings.has(SETTING_NAME)) + settings[SETTING_NAME] = mSettings[SETTING_NAME]; + + if (mSettings.has(SETTING_ID)) + settings[SETTING_ID] = mSettings[SETTING_ID]; + + if (mSettings.has(SETTING_ASSETID)) + settings[SETTING_ASSETID] = mSettings[SETTING_ASSETID]; + + settings[SETTING_TYPE] = getSettingsType(); + + std::map in_use; + + LLSD tracks(LLSD::emptyArray()); + + for (CycleList_t::const_iterator itTrack = mDayTracks.begin(); itTrack != mDayTracks.end(); ++itTrack) + { + LLSD trackout(LLSD::emptyArray()); + + for (CycleTrack_t::const_iterator itFrame = (*itTrack).begin(); itFrame != (*itTrack).end(); ++itFrame) + { + F32 frame = (*itFrame).first; + LLSettingsBase::ptr_t data = (*itFrame).second; + size_t datahash = data->getHash(); + + std::stringstream keyname; + keyname << datahash; + + trackout.append(LLSD(LLSDMap(SETTING_KEYKFRAME, LLSD::Real(frame))(SETTING_KEYNAME, keyname.str()))); + in_use[keyname.str()] = data; + } + tracks.append(trackout); + } + settings[SETTING_TRACKS] = tracks; + + LLSD frames(LLSD::emptyMap()); + for (std::map::iterator itFrame = in_use.begin(); itFrame != in_use.end(); ++itFrame) + { + LLSD framesettings = llsd_clone((*itFrame).second->getSettings(), + LLSDMap("*", true)(SETTING_NAME, false)(SETTING_ID, false)(SETTING_HASH, false)); + + frames[(*itFrame).first] = framesettings; + } + settings[SETTING_FRAMES] = frames; + + return settings; +} + +bool LLSettingsDay::initialize(bool validate_frames) +{ + LLSD tracks = mSettings[SETTING_TRACKS]; + LLSD frames = mSettings[SETTING_FRAMES]; + + // save for later... + LLUUID assetid; + if (mSettings.has(SETTING_ASSETID)) + { + assetid = mSettings[SETTING_ASSETID].asUUID(); + } + + std::map used; + + for (LLSD::map_const_iterator itFrame = frames.beginMap(); itFrame != frames.endMap(); ++itFrame) + { + std::string name = (*itFrame).first; + LLSD data = (*itFrame).second; + LLSettingsBase::ptr_t keyframe; + + if (data[SETTING_TYPE].asString() == "sky") + { + keyframe = buildSky(data); + } + else if (data[SETTING_TYPE].asString() == "water") + { + keyframe = buildWater(data); + } + else + { + LL_WARNS("DAYCYCLE") << "Unknown child setting type '" << data[SETTING_TYPE].asString() << "' named '" << name << "'" << LL_ENDL; + } + if (!keyframe) + { + LL_WARNS("DAYCYCLE") << "Invalid frame data" << LL_ENDL; + continue; + } + + used[name] = keyframe; + } + + bool haswater(false); + bool hassky(false); + + for (S32 i = 0; (i < tracks.size()) && (i < TRACK_MAX); ++i) + { + mDayTracks[i].clear(); + LLSD curtrack = tracks[i]; + for (const auto& entry : curtrack.array()) + { + LLSettingsBase::TrackPosition keyframe = LLSettingsBase::TrackPosition(entry[SETTING_KEYKFRAME].asReal()); + keyframe = llclamp(keyframe, 0.0f, 1.0f); + LLSettingsBase::ptr_t setting; + + + if (entry.has(SETTING_KEYNAME)) + { + std::string key_name = entry[SETTING_KEYNAME]; + if (i == TRACK_WATER) + { + setting = used[key_name]; + if (setting && setting->getSettingsType() != "water") + { + LL_WARNS("DAYCYCLE") << "Water track referencing " << setting->getSettingsType() << " frame at " << keyframe << "." << LL_ENDL; + setting.reset(); + } + } + else + { + setting = used[key_name]; + if (setting && setting->getSettingsType() != "sky") + { + LL_WARNS("DAYCYCLE") << "Sky track #" << i << " referencing " << setting->getSettingsType() << " frame at " << keyframe << "." << LL_ENDL; + setting.reset(); + } + } + } + + if (setting) + { + if (i == TRACK_WATER) + haswater |= true; + else + hassky |= true; + + if (validate_frames && mDayTracks[i].size() > 0) + { + // check if we hit close to anything in the list + LLSettingsDay::CycleTrack_t::value_type frame = getSettingsNearKeyframe(keyframe, i, DEFAULT_FRAME_SLOP_FACTOR); + if (frame.second) + { + // figure out direction of search + LLSettingsBase::TrackPosition found = frame.first; + LLSettingsBase::TrackPosition new_frame = keyframe; + F32 total_frame_shift = 0; + // We consider frame DEFAULT_FRAME_SLOP_FACTOR away as still encroaching, so add minimum increment + F32 move_factor = DEFAULT_FRAME_SLOP_FACTOR + DEFAULT_MULTISLIDER_INCREMENT; + bool move_forward = true; + if ((new_frame < found && (found - new_frame) <= DEFAULT_FRAME_SLOP_FACTOR) + || (new_frame > found && (new_frame - found) > DEFAULT_FRAME_SLOP_FACTOR)) + { + move_forward = false; + } + + if (move_forward) + { + CycleTrack_t::iterator iter = mDayTracks[i].find(found); + new_frame = found; // for total_frame_shift + while (total_frame_shift < 1) + { + // calculate shifted position from previous found point + total_frame_shift += move_factor + (found >= new_frame ? found : found + 1) - new_frame; + new_frame = found + move_factor; + if (new_frame > 1) new_frame--; + + // we know that current point is too close, go for next one + iter++; + if (iter == mDayTracks[i].end()) + { + iter = mDayTracks[i].begin(); + } + + if (((iter->first >= (new_frame - DEFAULT_MULTISLIDER_INCREMENT)) && ((new_frame + DEFAULT_FRAME_SLOP_FACTOR) >= iter->first)) + || ((iter->first < new_frame) && ((new_frame + DEFAULT_FRAME_SLOP_FACTOR) >= (iter->first + 1)))) + { + // we are encroaching at new point as well + found = iter->first; + } + else // (new_frame + DEFAULT_FRAME_SLOP_FACTOR < iter->first) + { + //we found clear spot + break; + } + } + } + else + { + CycleTrack_t::reverse_iterator iter = mDayTracks[i].rbegin(); + while (iter->first != found) + { + iter++; + } + new_frame = found; // for total_frame_shift + while (total_frame_shift < 1) + { + // calculate shifted position from current found point + total_frame_shift += move_factor + new_frame - (found <= new_frame ? found : found - 1); + new_frame = found - move_factor; + if (new_frame < 0) new_frame++; + + // we know that current point is too close, go for next one + iter++; + if (iter == mDayTracks[i].rend()) + { + iter = mDayTracks[i].rbegin(); + } + + if ((iter->first <= (new_frame + DEFAULT_MULTISLIDER_INCREMENT) && (new_frame - DEFAULT_FRAME_SLOP_FACTOR) <= iter->first) + || ((iter->first > new_frame) && ((new_frame - DEFAULT_FRAME_SLOP_FACTOR) <= (iter->first - 1)))) + { + // we are encroaching at new point as well + found = iter->first; + } + else // (new_frame - DEFAULT_FRAME_SLOP_FACTOR > iter->first) + { + //we found clear spot + break; + } + } + + + } + + if (total_frame_shift >= 1) + { + LL_WARNS("SETTINGS") << "Could not fix frame position, adding as is to position: " << keyframe << LL_ENDL; + } + else + { + // Mark as new position + keyframe = new_frame; + } + } + } + mDayTracks[i][keyframe] = setting; + } + } + } + + if (!haswater || !hassky) + { + LL_WARNS("DAYCYCLE") << "Must have at least one water and one sky frame!" << LL_ENDL; + return false; + } + // these are no longer needed and just take up space now. + mSettings.erase(SETTING_TRACKS); + mSettings.erase(SETTING_FRAMES); + + if (!assetid.isNull()) + { + mSettings[SETTING_ASSETID] = assetid; + } + + mInitialized = true; + return true; +} + + +//========================================================================= +LLSD LLSettingsDay::defaults() +{ + static LLSD dfltsetting; + + if (dfltsetting.size() == 0) + { + dfltsetting[SETTING_NAME] = "_default_"; + dfltsetting[SETTING_TYPE] = "daycycle"; + + LLSD frames(LLSD::emptyMap()); + LLSD waterTrack; + LLSD skyTrack; + + + const U32 FRAME_COUNT = 8; + const F32 FRAME_STEP = 1.0f / F32(FRAME_COUNT); + F32 time = 0.0f; + for (U32 i = 0; i < FRAME_COUNT; i++) + { + std::string name("_default_"); + name += ('a' + i); + + std::string water_frame_name("water:"); + std::string sky_frame_name("sky:"); + + water_frame_name += name; + sky_frame_name += name; + + waterTrack[SETTING_KEYKFRAME] = time; + waterTrack[SETTING_KEYNAME] = water_frame_name; + + skyTrack[SETTING_KEYKFRAME] = time; + skyTrack[SETTING_KEYNAME] = sky_frame_name; + + frames[water_frame_name] = LLSettingsWater::defaults(time); + frames[sky_frame_name] = LLSettingsSky::defaults(time); + + time += FRAME_STEP; + } + + LLSD tracks; + tracks.append(LLSDArray(waterTrack)); + tracks.append(LLSDArray(skyTrack)); + + dfltsetting[SETTING_TRACKS] = tracks; + dfltsetting[SETTING_FRAMES] = frames; + } + + return dfltsetting; +} + +void LLSettingsDay::blend(const LLSettingsBase::ptr_t &other, F64 mix) +{ + LL_ERRS("DAYCYCLE") << "Day cycles are not blendable!" << LL_ENDL; +} + +namespace +{ + bool validateDayCycleTrack(LLSD &value) + { + // Trim extra tracks. + while (value.size() > LLSettingsDay::TRACK_MAX) + { + value.erase(value.size() - 1); + } + + S32 framecount(0); + + for (auto& entry : value.array()) + { + S32 index = 0; + while (index < entry.size()) + { + LLSD& elem = entry[index]; + + ++framecount; + if (index >= LLSettingsDay::FRAME_MAX) + { + entry.erase(index); + continue; + } + + if (!elem.has(LLSettingsDay::SETTING_KEYKFRAME)) + { + entry.erase(index); + continue; + } + + if (!elem[LLSettingsDay::SETTING_KEYKFRAME].isReal()) + { + entry.erase(index); + continue; + } + + if (!elem.has(LLSettingsDay::SETTING_KEYNAME) && + !elem.has(LLSettingsDay::SETTING_KEYID)) + { + entry.erase(index); + continue; + } + + LLSettingsBase::TrackPosition frame = elem[LLSettingsDay::SETTING_KEYKFRAME].asReal(); + if ((frame < 0.0) || (frame > 1.0)) + { + frame = llclamp(frame, 0.0f, 1.0f); + elem[LLSettingsDay::SETTING_KEYKFRAME] = frame; + } + ++index; + } + + } + + int waterTracks = value[0].size(); + int skyTracks = framecount - waterTracks; + + if (waterTracks < 1) + { + LL_WARNS("SETTINGS") << "Missing water track" << LL_ENDL; + return false; + } + + if (skyTracks < 1) + { + LL_WARNS("SETTINGS") << "Missing sky tracks" << LL_ENDL; + return false; + } + return true; + } + + bool validateDayCycleFrames(LLSD &value) + { + bool hasSky(false); + bool hasWater(false); + + for (LLSD::map_iterator itf = value.beginMap(); itf != value.endMap(); ++itf) + { + LLSD frame = (*itf).second; + + std::string ftype = frame[LLSettingsBase::SETTING_TYPE]; + if (ftype == "sky") + { + LLSettingsSky::validation_list_t valid_sky = LLSettingsSky::validationList(); + LLSD res_sky = LLSettingsBase::settingValidation(frame, valid_sky); + + if (res_sky["success"].asInteger() == 0) + { + LL_WARNS("SETTINGS") << "Sky setting named '" << (*itf).first << "' validation failed!: " << res_sky << LL_ENDL; + LL_WARNS("SETTINGS") << "Sky: " << frame << LL_ENDL; + continue; + } + hasSky |= true; + } + else if (ftype == "water") + { + LLSettingsWater::validation_list_t valid_h2o = LLSettingsWater::validationList(); + LLSD res_h2o = LLSettingsBase::settingValidation(frame, valid_h2o); + if (res_h2o["success"].asInteger() == 0) + { + LL_WARNS("SETTINGS") << "Water setting named '" << (*itf).first << "' validation failed!: " << res_h2o << LL_ENDL; + LL_WARNS("SETTINGS") << "Water: " << frame << LL_ENDL; + continue; + } + hasWater |= true; + } + else + { + LL_WARNS("SETTINGS") << "Unknown settings block of type '" << ftype << "' named '" << (*itf).first << "'" << LL_ENDL; + return false; + } + } + + if (!hasSky) + { + LL_WARNS("SETTINGS") << "No skies defined." << LL_ENDL; + return false; + } + + if (!hasWater) + { + LL_WARNS("SETTINGS") << "No waters defined." << LL_ENDL; + return false; + } + + return true; + } +} + +LLSettingsDay::validation_list_t LLSettingsDay::getValidationList() const +{ + return LLSettingsDay::validationList(); +} + +LLSettingsDay::validation_list_t LLSettingsDay::validationList() +{ + static validation_list_t validation; + + if (validation.empty()) + { + validation.push_back(Validator(SETTING_TRACKS, true, LLSD::TypeArray, + &validateDayCycleTrack)); + validation.push_back(Validator(SETTING_FRAMES, true, LLSD::TypeMap, + &validateDayCycleFrames)); + } + + return validation; +} + +LLSettingsDay::CycleTrack_t& LLSettingsDay::getCycleTrack(size_t track) +{ + static CycleTrack_t emptyTrack; + if (mDayTracks.size() <= track) + return emptyTrack; + + return mDayTracks[track]; +} + +const LLSettingsDay::CycleTrack_t& LLSettingsDay::getCycleTrackConst(size_t track) const +{ + static CycleTrack_t emptyTrack; + if (mDayTracks.size() <= track) + return emptyTrack; + + return mDayTracks[track]; +} + +bool LLSettingsDay::clearCycleTrack(S32 track) +{ + if ((track < 0) || (track >= TRACK_MAX)) + { + LL_WARNS("DAYCYCLE") << "Attempt to clear track (#" << track << ") out of range!" << LL_ENDL; + return false; + } + mDayTracks[track].clear(); + clearAssetId(); + setDirtyFlag(true); + return true; +} + +bool LLSettingsDay::replaceCycleTrack(S32 track, const CycleTrack_t &source) +{ + if (source.empty()) + { + LL_WARNS("DAYCYCLE") << "Attempt to copy an empty track." << LL_ENDL; + return false; + } + + { + LLSettingsBase::ptr_t first((*source.begin()).second); + std::string setting_type = first->getSettingsType(); + + if (((setting_type == "water") && (track != 0)) || + ((setting_type == "sky") && (track == 0))) + { + LL_WARNS("DAYCYCLE") << "Attempt to copy track missmatch" << LL_ENDL; + return false; + } + } + + if (!clearCycleTrack(track)) + return false; + + mDayTracks[track] = source; + return true; +} + + +bool LLSettingsDay::isTrackEmpty(S32 track) const +{ + if ((track < 0) || (track >= TRACK_MAX)) + { + LL_WARNS("DAYCYCLE") << "Attempt to test track (#" << track << ") out of range!" << LL_ENDL; + return true; + } + + return mDayTracks[track].empty(); +} + +//========================================================================= +void LLSettingsDay::startDayCycle() +{ + if (!mInitialized) + { + LL_WARNS("DAYCYCLE") << "Attempt to start day cycle on uninitialized object." << LL_ENDL; + return; + } +} + + +void LLSettingsDay::updateSettings() +{ +} + +//========================================================================= +LLSettingsDay::KeyframeList_t LLSettingsDay::getTrackKeyframes(S32 trackno) +{ + if ((trackno < 0) || (trackno >= TRACK_MAX)) + { + LL_WARNS("DAYCYCLE") << "Attempt get track (#" << trackno << ") out of range!" << LL_ENDL; + return KeyframeList_t(); + } + + KeyframeList_t keyframes; + CycleTrack_t &track = mDayTracks[trackno]; + + keyframes.reserve(track.size()); + + for (CycleTrack_t::iterator it = track.begin(); it != track.end(); ++it) + { + keyframes.push_back((*it).first); + } + + return keyframes; +} + +bool LLSettingsDay::moveTrackKeyframe(S32 trackno, const LLSettingsBase::TrackPosition& old_frame, const LLSettingsBase::TrackPosition& new_frame) +{ + if ((trackno < 0) || (trackno >= TRACK_MAX)) + { + LL_WARNS("DAYCYCLE") << "Attempt get track (#" << trackno << ") out of range!" << LL_ENDL; + return false; + } + + if (old_frame == new_frame) + { + return false; + } + + CycleTrack_t &track = mDayTracks[trackno]; + CycleTrack_t::iterator iter = track.find(old_frame); + if (iter != track.end()) + { + LLSettingsBase::ptr_t base = iter->second; + track.erase(iter); + track[llclamp(new_frame, 0.0f, 1.0f)] = base; + track[new_frame] = base; + return true; + } + + return false; + +} + +bool LLSettingsDay::removeTrackKeyframe(S32 trackno, const LLSettingsBase::TrackPosition& frame) +{ + if ((trackno < 0) || (trackno >= TRACK_MAX)) + { + LL_WARNS("DAYCYCLE") << "Attempt get track (#" << trackno << ") out of range!" << LL_ENDL; + return false; + } + + CycleTrack_t &track = mDayTracks[trackno]; + CycleTrack_t::iterator iter = track.find(frame); + if (iter != track.end()) + { + LLSettingsBase::ptr_t base = iter->second; + track.erase(iter); + return true; + } + + return false; +} + +void LLSettingsDay::setWaterAtKeyframe(const LLSettingsWaterPtr_t &water, const LLSettingsBase::TrackPosition& keyframe) +{ + setSettingsAtKeyframe(water, keyframe, TRACK_WATER); +} + +LLSettingsWater::ptr_t LLSettingsDay::getWaterAtKeyframe(const LLSettingsBase::TrackPosition& keyframe) const +{ + LLSettingsBase* p = getSettingsAtKeyframe(keyframe, TRACK_WATER).get(); + return LLSettingsWater::ptr_t((LLSettingsWater*)p); +} + +void LLSettingsDay::setSkyAtKeyframe(const LLSettingsSky::ptr_t &sky, const LLSettingsBase::TrackPosition& keyframe, S32 track) +{ + if ((track < 1) || (track >= TRACK_MAX)) + { + LL_WARNS("DAYCYCLE") << "Attempt to set sky track (#" << track << ") out of range!" << LL_ENDL; + return; + } + + setSettingsAtKeyframe(sky, keyframe, track); +} + +LLSettingsSky::ptr_t LLSettingsDay::getSkyAtKeyframe(const LLSettingsBase::TrackPosition& keyframe, S32 track) const +{ + if ((track < 1) || (track >= TRACK_MAX)) + { + LL_WARNS("DAYCYCLE") << "Attempt to set sky track (#" << track << ") out of range!" << LL_ENDL; + return LLSettingsSky::ptr_t(); + } + + return PTR_NAMESPACE::dynamic_pointer_cast(getSettingsAtKeyframe(keyframe, track)); +} + +void LLSettingsDay::setSettingsAtKeyframe(const LLSettingsBase::ptr_t &settings, const LLSettingsBase::TrackPosition& keyframe, S32 track) +{ + if ((track < 0) || (track >= TRACK_MAX)) + { + LL_WARNS("DAYCYCLE") << "Attempt to set track (#" << track << ") out of range!" << LL_ENDL; + return; + } + + std::string type = settings->getSettingsType(); + if ((track == TRACK_WATER) && (type != "water")) + { + LL_WARNS("DAYCYCLE") << "Attempt to add frame of type '" << type << "' to water track!" << LL_ENDL; + llassert(type == "water"); + return; + } + else if ((track != TRACK_WATER) && (type != "sky")) + { + LL_WARNS("DAYCYCLE") << "Attempt to add frame of type '" << type << "' to sky track!" << LL_ENDL; + llassert(type == "sky"); + return; + } + + mDayTracks[track][llclamp(keyframe, 0.0f, 1.0f)] = settings; + setDirtyFlag(true); +} + +LLSettingsBase::ptr_t LLSettingsDay::getSettingsAtKeyframe(const LLSettingsBase::TrackPosition& keyframe, S32 track) const +{ + if ((track < 0) || (track >= TRACK_MAX)) + { + LL_WARNS("DAYCYCLE") << "Attempt to set sky track (#" << track << ") out of range!" << LL_ENDL; + return LLSettingsBase::ptr_t(); + } + + // todo: better way to identify keyframes? + CycleTrack_t::const_iterator iter = mDayTracks[track].find(keyframe); + if (iter != mDayTracks[track].end()) + { + return iter->second; + } + + return LLSettingsBase::ptr_t(); +} + +LLSettingsDay::CycleTrack_t::value_type LLSettingsDay::getSettingsNearKeyframe(const LLSettingsBase::TrackPosition &keyframe, S32 track, F32 fudge) const +{ + if ((track < 0) || (track >= TRACK_MAX)) + { + LL_WARNS("DAYCYCLE") << "Attempt to get track (#" << track << ") out of range!" << LL_ENDL; + return CycleTrack_t::value_type(TrackPosition(INVALID_TRACKPOS), LLSettingsBase::ptr_t()); + } + + if (mDayTracks[track].empty()) + { + LL_INFOS("DAYCYCLE") << "Empty track" << LL_ENDL; + return CycleTrack_t::value_type(TrackPosition(INVALID_TRACKPOS), LLSettingsBase::ptr_t()); + } + + TrackPosition startframe(keyframe - fudge); + if (startframe < 0.0f) + startframe = 1.0f + startframe; + + CycleTrack_t::iterator it = get_wrapping_atafter(const_cast(mDayTracks[track]), startframe); + + F32 dist = get_wrapping_distance(startframe, (*it).first); + + if (dist <= (fudge * 2.0f)) + return (*it); + + return CycleTrack_t::value_type(TrackPosition(INVALID_TRACKPOS), LLSettingsBase::ptr_t()); +} + +LLSettingsBase::TrackPosition LLSettingsDay::getUpperBoundFrame(S32 track, const LLSettingsBase::TrackPosition& keyframe) +{ + return get_wrapping_atafter(mDayTracks[track], keyframe)->first; +} + +LLSettingsBase::TrackPosition LLSettingsDay::getLowerBoundFrame(S32 track, const LLSettingsBase::TrackPosition& keyframe) +{ + return get_wrapping_atbefore(mDayTracks[track], keyframe)->first; +} + +LLSettingsDay::TrackBound_t LLSettingsDay::getBoundingEntries(LLSettingsDay::CycleTrack_t &track, const LLSettingsBase::TrackPosition& keyframe) +{ + return TrackBound_t(get_wrapping_atbefore(track, keyframe), get_wrapping_atafter(track, keyframe)); +} + +LLUUID LLSettingsDay::GetDefaultAssetId() +{ + return DEFAULT_ASSET_ID; +} + +//========================================================================= diff --git a/indra/llinventory/llsettingsdaycycle.h b/indra/llinventory/llsettingsdaycycle.h new file mode 100644 index 0000000000..bc5f03fa16 --- /dev/null +++ b/indra/llinventory/llsettingsdaycycle.h @@ -0,0 +1,156 @@ +/** +* @file llsettingsdaycycle.h +* @author optional +* @brief A base class for asset based settings groups. +* +* $LicenseInfo:2011&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2017, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#ifndef LL_SETTINGS_DAYCYCLE_H +#define LL_SETTINGS_DAYCYCLE_H + +#include "llsettingsbase.h" + +class LLSettingsWater; +class LLSettingsSky; + +// These are alias for LLSettingsWater::ptr_t and LLSettingsSky::ptr_t respectively. +// Here for definitions only. +typedef PTR_NAMESPACE::shared_ptr LLSettingsWaterPtr_t; +typedef PTR_NAMESPACE::shared_ptr LLSettingsSkyPtr_t; + +class LLSettingsDay : public LLSettingsBase +{ +public: + // 32-bit as LLSD only supports that width at present + typedef S32Seconds Seconds; + + static const std::string SETTING_KEYID; + static const std::string SETTING_KEYNAME; + static const std::string SETTING_KEYKFRAME; + static const std::string SETTING_KEYHASH; + static const std::string SETTING_TRACKS; + static const std::string SETTING_FRAMES; + + static const Seconds MINIMUM_DAYLENGTH; + static const Seconds DEFAULT_DAYLENGTH; + static const Seconds MAXIMUM_DAYLENGTH; + + static const Seconds MINIMUM_DAYOFFSET; + static const Seconds DEFAULT_DAYOFFSET; + static const Seconds MAXIMUM_DAYOFFSET; + + static const S32 TRACK_WATER; + static const S32 TRACK_GROUND_LEVEL; + static const S32 TRACK_MAX; + static const S32 FRAME_MAX; + + static const F32 DEFAULT_FRAME_SLOP_FACTOR; + + static const LLUUID DEFAULT_ASSET_ID; + + typedef std::map CycleTrack_t; + typedef std::vector CycleList_t; + typedef PTR_NAMESPACE::shared_ptr ptr_t; + typedef PTR_NAMESPACE::weak_ptr wptr_t; + typedef std::vector KeyframeList_t; + typedef std::pair TrackBound_t; + + //--------------------------------------------------------------------- + LLSettingsDay(const LLSD &data); + virtual ~LLSettingsDay() { }; + + bool initialize(bool validate_frames = false); + + virtual ptr_t buildClone() const = 0; + virtual ptr_t buildDeepCloneAndUncompress() const = 0; + virtual LLSD getSettings() const SETTINGS_OVERRIDE; + virtual LLSettingsType::type_e getSettingsTypeValue() const SETTINGS_OVERRIDE { return LLSettingsType::ST_DAYCYCLE; } + + + //--------------------------------------------------------------------- + virtual std::string getSettingsType() const SETTINGS_OVERRIDE { return std::string("daycycle"); } + + // Settings status + virtual void blend(const LLSettingsBase::ptr_t &other, F64 mix) SETTINGS_OVERRIDE; + + static LLSD defaults(); + + //--------------------------------------------------------------------- + KeyframeList_t getTrackKeyframes(S32 track); + bool moveTrackKeyframe(S32 track, const LLSettingsBase::TrackPosition& old_frame, const LLSettingsBase::TrackPosition& new_frame); + bool removeTrackKeyframe(S32 track, const LLSettingsBase::TrackPosition& frame); + + void setWaterAtKeyframe(const LLSettingsWaterPtr_t &water, const LLSettingsBase::TrackPosition& keyframe); + LLSettingsWaterPtr_t getWaterAtKeyframe(const LLSettingsBase::TrackPosition& keyframe) const; + void setSkyAtKeyframe(const LLSettingsSkyPtr_t &sky, const LLSettingsBase::TrackPosition& keyframe, S32 track); + LLSettingsSkyPtr_t getSkyAtKeyframe(const LLSettingsBase::TrackPosition& keyframe, S32 track) const; + void setSettingsAtKeyframe(const LLSettingsBase::ptr_t &settings, const LLSettingsBase::TrackPosition& keyframe, S32 track); + LLSettingsBase::ptr_t getSettingsAtKeyframe(const LLSettingsBase::TrackPosition& keyframe, S32 track) const; + CycleTrack_t::value_type getSettingsNearKeyframe(const LLSettingsBase::TrackPosition &keyframe, S32 track, F32 fudge) const; + + //--------------------------------------------------------------------- + void startDayCycle(); + + virtual LLSettingsSkyPtr_t getDefaultSky() const = 0; + virtual LLSettingsWaterPtr_t getDefaultWater() const = 0; + + virtual LLSettingsSkyPtr_t buildSky(LLSD) const = 0; + virtual LLSettingsWaterPtr_t buildWater(LLSD) const = 0; + + void setInitialized(bool value = true) { mInitialized = value; } + CycleTrack_t & getCycleTrack(size_t track); + const CycleTrack_t & getCycleTrackConst(size_t track) const; + bool clearCycleTrack(S32 track); + bool replaceCycleTrack(S32 track, const CycleTrack_t &source); + bool isTrackEmpty(S32 track) const; + + virtual validation_list_t getValidationList() const SETTINGS_OVERRIDE; + static validation_list_t validationList(); + + virtual LLSettingsBase::ptr_t buildDerivedClone() const SETTINGS_OVERRIDE { return buildClone(); } + + LLSettingsBase::TrackPosition getUpperBoundFrame(S32 track, const LLSettingsBase::TrackPosition& keyframe); + LLSettingsBase::TrackPosition getLowerBoundFrame(S32 track, const LLSettingsBase::TrackPosition& keyframe); + + static LLUUID GetDefaultAssetId(); + +protected: + LLSettingsDay(); + + virtual void updateSettings() SETTINGS_OVERRIDE; + + bool mInitialized; + +private: + CycleList_t mDayTracks; + + LLSettingsBase::Seconds mLastUpdateTime; + + void parseFromLLSD(LLSD &data); + + static CycleTrack_t::iterator getEntryAtOrBefore(CycleTrack_t &track, const LLSettingsBase::TrackPosition& keyframe); + static CycleTrack_t::iterator getEntryAtOrAfter(CycleTrack_t &track, const LLSettingsBase::TrackPosition& keyframe); + TrackBound_t getBoundingEntries(CycleTrack_t &track, const LLSettingsBase::TrackPosition& keyframe); +}; + +#endif diff --git a/indra/llinventory/llsettingssky.cpp b/indra/llinventory/llsettingssky.cpp new file mode 100644 index 0000000000..8b93ebc00f --- /dev/null +++ b/indra/llinventory/llsettingssky.cpp @@ -0,0 +1,1692 @@ +/** +* @file llsettingssky.cpp +* @author optional +* @brief A base class for asset based settings groups. +* +* $LicenseInfo:2011&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2017, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#include "llsettingssky.h" +#include "indra_constants.h" +#include +#include "llfasttimer.h" +#include "v3colorutil.h" + +//========================================================================= +namespace { + const F32 NIGHTTIME_ELEVATION = 8.0f; // degrees + const F32 NIGHTTIME_ELEVATION_SIN = (F32)sinf(NIGHTTIME_ELEVATION * DEG_TO_RAD); + const LLUUID IMG_BLOOM1("3c59f7fe-9dc8-47f9-8aaf-a9dd1fbc3bef"); + const LLUUID IMG_RAINBOW("11b4c57c-56b3-04ed-1f82-2004363882e4"); + const LLUUID IMG_HALO("12149143-f599-91a7-77ac-b52a3c0f59cd"); +} + +namespace { + LLQuaternion convert_azimuth_and_altitude_to_quat(F32 azimuth, F32 altitude) + { + F32 sinTheta = sin(azimuth); + F32 cosTheta = cos(azimuth); + F32 sinPhi = sin(altitude); + F32 cosPhi = cos(altitude); + + LLVector3 dir; + // +x right, +z up, +y at... + dir.mV[0] = cosTheta * cosPhi; + dir.mV[1] = sinTheta * cosPhi; + dir.mV[2] = sinPhi; + + LLVector3 axis = LLVector3::x_axis % dir; + axis.normalize(); + + F32 angle = acos(LLVector3::x_axis * dir); + + LLQuaternion quat; + quat.setAngleAxis(angle, axis); + + return quat; + } +} + +static LLTrace::BlockTimerStatHandle FTM_BLEND_SKYVALUES("Blending Sky Environment"); +static LLTrace::BlockTimerStatHandle FTM_RECALCULATE_SKYVALUES("Recalculate Sky"); +static LLTrace::BlockTimerStatHandle FTM_RECALCULATE_BODIES("Recalculate Heavenly Bodies"); +static LLTrace::BlockTimerStatHandle FTM_RECALCULATE_LIGHTING("Recalculate Lighting"); + +//========================================================================= +const std::string LLSettingsSky::SETTING_AMBIENT("ambient"); +const std::string LLSettingsSky::SETTING_BLUE_DENSITY("blue_density"); +const std::string LLSettingsSky::SETTING_BLUE_HORIZON("blue_horizon"); +const std::string LLSettingsSky::SETTING_DENSITY_MULTIPLIER("density_multiplier"); +const std::string LLSettingsSky::SETTING_DISTANCE_MULTIPLIER("distance_multiplier"); +const std::string LLSettingsSky::SETTING_HAZE_DENSITY("haze_density"); +const std::string LLSettingsSky::SETTING_HAZE_HORIZON("haze_horizon"); + +const std::string LLSettingsSky::SETTING_BLOOM_TEXTUREID("bloom_id"); +const std::string LLSettingsSky::SETTING_RAINBOW_TEXTUREID("rainbow_id"); +const std::string LLSettingsSky::SETTING_HALO_TEXTUREID("halo_id"); +const std::string LLSettingsSky::SETTING_CLOUD_COLOR("cloud_color"); +const std::string LLSettingsSky::SETTING_CLOUD_POS_DENSITY1("cloud_pos_density1"); +const std::string LLSettingsSky::SETTING_CLOUD_POS_DENSITY2("cloud_pos_density2"); +const std::string LLSettingsSky::SETTING_CLOUD_SCALE("cloud_scale"); +const std::string LLSettingsSky::SETTING_CLOUD_SCROLL_RATE("cloud_scroll_rate"); +const std::string LLSettingsSky::SETTING_CLOUD_SHADOW("cloud_shadow"); +const std::string LLSettingsSky::SETTING_CLOUD_TEXTUREID("cloud_id"); +const std::string LLSettingsSky::SETTING_CLOUD_VARIANCE("cloud_variance"); + +const std::string LLSettingsSky::SETTING_DOME_OFFSET("dome_offset"); +const std::string LLSettingsSky::SETTING_DOME_RADIUS("dome_radius"); +const std::string LLSettingsSky::SETTING_GAMMA("gamma"); +const std::string LLSettingsSky::SETTING_GLOW("glow"); + +const std::string LLSettingsSky::SETTING_LIGHT_NORMAL("lightnorm"); +const std::string LLSettingsSky::SETTING_MAX_Y("max_y"); +const std::string LLSettingsSky::SETTING_MOON_ROTATION("moon_rotation"); +const std::string LLSettingsSky::SETTING_MOON_SCALE("moon_scale"); +const std::string LLSettingsSky::SETTING_MOON_TEXTUREID("moon_id"); +const std::string LLSettingsSky::SETTING_MOON_BRIGHTNESS("moon_brightness"); + +const std::string LLSettingsSky::SETTING_STAR_BRIGHTNESS("star_brightness"); +const std::string LLSettingsSky::SETTING_SUNLIGHT_COLOR("sunlight_color"); +const std::string LLSettingsSky::SETTING_SUN_ROTATION("sun_rotation"); +const std::string LLSettingsSky::SETTING_SUN_SCALE("sun_scale"); +const std::string LLSettingsSky::SETTING_SUN_TEXTUREID("sun_id"); + +const std::string LLSettingsSky::SETTING_LEGACY_EAST_ANGLE("east_angle"); +const std::string LLSettingsSky::SETTING_LEGACY_ENABLE_CLOUD_SCROLL("enable_cloud_scroll"); +const std::string LLSettingsSky::SETTING_LEGACY_SUN_ANGLE("sun_angle"); + +// these are new settings for the advanced atmospherics model +const std::string LLSettingsSky::SETTING_PLANET_RADIUS("planet_radius"); +const std::string LLSettingsSky::SETTING_SKY_BOTTOM_RADIUS("sky_bottom_radius"); +const std::string LLSettingsSky::SETTING_SKY_TOP_RADIUS("sky_top_radius"); +const std::string LLSettingsSky::SETTING_SUN_ARC_RADIANS("sun_arc_radians"); + +const std::string LLSettingsSky::SETTING_RAYLEIGH_CONFIG("rayleigh_config"); +const std::string LLSettingsSky::SETTING_MIE_CONFIG("mie_config"); +const std::string LLSettingsSky::SETTING_MIE_ANISOTROPY_FACTOR("anisotropy"); +const std::string LLSettingsSky::SETTING_ABSORPTION_CONFIG("absorption_config"); + +const std::string LLSettingsSky::KEY_DENSITY_PROFILE("density"); +const std::string LLSettingsSky::SETTING_DENSITY_PROFILE_WIDTH("width"); +const std::string LLSettingsSky::SETTING_DENSITY_PROFILE_EXP_TERM("exp_term"); +const std::string LLSettingsSky::SETTING_DENSITY_PROFILE_EXP_SCALE_FACTOR("exp_scale"); +const std::string LLSettingsSky::SETTING_DENSITY_PROFILE_LINEAR_TERM("linear_term"); +const std::string LLSettingsSky::SETTING_DENSITY_PROFILE_CONSTANT_TERM("constant_term"); + +const std::string LLSettingsSky::SETTING_SKY_MOISTURE_LEVEL("moisture_level"); +const std::string LLSettingsSky::SETTING_SKY_DROPLET_RADIUS("droplet_radius"); +const std::string LLSettingsSky::SETTING_SKY_ICE_LEVEL("ice_level"); + +const LLUUID LLSettingsSky::DEFAULT_ASSET_ID("eb3a7080-831f-9f37-10f0-7b1f9ea4043c"); + +static const LLUUID DEFAULT_SUN_ID("32bfbcea-24b1-fb9d-1ef9-48a28a63730f"); // dataserver +static const LLUUID DEFAULT_MOON_ID("d07f6eed-b96a-47cd-b51d-400ad4a1c428"); // dataserver +static const LLUUID DEFAULT_CLOUD_ID("1dc1368f-e8fe-f02d-a08d-9d9f11c1af6b"); + +const std::string LLSettingsSky::SETTING_LEGACY_HAZE("legacy_haze"); + +const F32 LLSettingsSky::DOME_OFFSET(0.96f); +const F32 LLSettingsSky::DOME_RADIUS(15000.f); + +namespace +{ + +LLSettingsSky::validation_list_t legacyHazeValidationList() +{ + static LLSettingsBase::validation_list_t legacyHazeValidation; + if (legacyHazeValidation.empty()) + { + legacyHazeValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_AMBIENT, false, LLSD::TypeArray, + boost::bind(&LLSettingsBase::Validator::verifyVectorMinMax, _1, + LLSD(LLSDArray(0.0f)(0.0f)(0.0f)("*")), + LLSD(LLSDArray(3.0f)(3.0f)(3.0f)("*"))))); + legacyHazeValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_BLUE_DENSITY, false, LLSD::TypeArray, + boost::bind(&LLSettingsBase::Validator::verifyVectorMinMax, _1, + LLSD(LLSDArray(0.0f)(0.0f)(0.0f)("*")), + LLSD(LLSDArray(3.0f)(3.0f)(3.0f)("*"))))); + legacyHazeValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_BLUE_HORIZON, false, LLSD::TypeArray, + boost::bind(&LLSettingsBase::Validator::verifyVectorMinMax, _1, + LLSD(LLSDArray(0.0f)(0.0f)(0.0f)("*")), + LLSD(LLSDArray(3.0f)(3.0f)(3.0f)("*"))))); + legacyHazeValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_HAZE_DENSITY, false, LLSD::TypeReal, + boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(5.0f))))); + legacyHazeValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_HAZE_HORIZON, false, LLSD::TypeReal, + boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(5.0f))))); + legacyHazeValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_MULTIPLIER, false, LLSD::TypeReal, + boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0001f)(2.0f))))); + legacyHazeValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DISTANCE_MULTIPLIER, false, LLSD::TypeReal, + boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0001f)(1000.0f))))); + } + return legacyHazeValidation; +} + +LLSettingsSky::validation_list_t rayleighValidationList() +{ + static LLSettingsBase::validation_list_t rayleighValidation; + if (rayleighValidation.empty()) + { + rayleighValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_WIDTH, false, LLSD::TypeReal, + boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(32768.0f))))); + + rayleighValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_EXP_TERM, false, LLSD::TypeReal, + boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(2.0f))))); + + rayleighValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_EXP_SCALE_FACTOR, false, LLSD::TypeReal, + boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(-1.0f)(1.0f))))); + + rayleighValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_LINEAR_TERM, false, LLSD::TypeReal, + boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(2.0f))))); + + rayleighValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_CONSTANT_TERM, false, LLSD::TypeReal, + boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f))))); + } + return rayleighValidation; +} + +LLSettingsSky::validation_list_t absorptionValidationList() +{ + static LLSettingsBase::validation_list_t absorptionValidation; + if (absorptionValidation.empty()) + { + absorptionValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_WIDTH, false, LLSD::TypeReal, + boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(32768.0f))))); + + absorptionValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_EXP_TERM, false, LLSD::TypeReal, + boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(2.0f))))); + + absorptionValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_EXP_SCALE_FACTOR, false, LLSD::TypeReal, + boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(-1.0f)(1.0f))))); + + absorptionValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_LINEAR_TERM, false, LLSD::TypeReal, + boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(2.0f))))); + + absorptionValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_CONSTANT_TERM, false, LLSD::TypeReal, + boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f))))); + } + return absorptionValidation; +} + +LLSettingsSky::validation_list_t mieValidationList() +{ + static LLSettingsBase::validation_list_t mieValidation; + if (mieValidation.empty()) + { + mieValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_WIDTH, false, LLSD::TypeReal, + boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(32768.0f))))); + + mieValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_EXP_TERM, false, LLSD::TypeReal, + boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(2.0f))))); + + mieValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_EXP_SCALE_FACTOR, false, LLSD::TypeReal, + boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(-1.0f)(1.0f))))); + + mieValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_LINEAR_TERM, false, LLSD::TypeReal, + boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(2.0f))))); + + mieValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_DENSITY_PROFILE_CONSTANT_TERM, false, LLSD::TypeReal, + boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f))))); + + mieValidation.push_back(LLSettingsBase::Validator(LLSettingsSky::SETTING_MIE_ANISOTROPY_FACTOR, false, LLSD::TypeReal, + boost::bind(&LLSettingsBase::Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f))))); + } + return mieValidation; +} + +bool validateLegacyHaze(LLSD &value) +{ + LLSettingsSky::validation_list_t legacyHazeValidations = legacyHazeValidationList(); + llassert(value.type() == LLSD::TypeMap); + LLSD result = LLSettingsBase::settingValidation(value, legacyHazeValidations); + if (result["errors"].size() > 0) + { + LL_WARNS("SETTINGS") << "Legacy Haze Config Validation errors: " << result["errors"] << LL_ENDL; + return false; + } + if (result["warnings"].size() > 0) + { + LL_WARNS("SETTINGS") << "Legacy Haze Config Validation warnings: " << result["warnings"] << LL_ENDL; + return false; + } + return true; +} + +bool validateRayleighLayers(LLSD &value) +{ + LLSettingsSky::validation_list_t rayleighValidations = rayleighValidationList(); + if (value.isArray()) + { + bool allGood = true; + for (LLSD::array_iterator itf = value.beginArray(); itf != value.endArray(); ++itf) + { + LLSD& layerConfig = (*itf); + if (layerConfig.type() == LLSD::TypeMap) + { + if (!validateRayleighLayers(layerConfig)) + { + allGood = false; + } + } + else if (layerConfig.type() == LLSD::TypeArray) + { + return validateRayleighLayers(layerConfig); + } + else + { + return LLSettingsBase::settingValidation(value, rayleighValidations); + } + } + return allGood; + } + llassert(value.type() == LLSD::TypeMap); + LLSD result = LLSettingsBase::settingValidation(value, rayleighValidations); + if (result["errors"].size() > 0) + { + LL_WARNS("SETTINGS") << "Rayleigh Config Validation errors: " << result["errors"] << LL_ENDL; + return false; + } + if (result["warnings"].size() > 0) + { + LL_WARNS("SETTINGS") << "Rayleigh Config Validation warnings: " << result["errors"] << LL_ENDL; + return false; + } + return true; +} + +bool validateAbsorptionLayers(LLSD &value) +{ + LLSettingsBase::validation_list_t absorptionValidations = absorptionValidationList(); + if (value.isArray()) + { + bool allGood = true; + for (LLSD::array_iterator itf = value.beginArray(); itf != value.endArray(); ++itf) + { + LLSD& layerConfig = (*itf); + if (layerConfig.type() == LLSD::TypeMap) + { + if (!validateAbsorptionLayers(layerConfig)) + { + allGood = false; + } + } + else if (layerConfig.type() == LLSD::TypeArray) + { + return validateAbsorptionLayers(layerConfig); + } + else + { + return LLSettingsBase::settingValidation(value, absorptionValidations); + } + } + return allGood; + } + llassert(value.type() == LLSD::TypeMap); + LLSD result = LLSettingsBase::settingValidation(value, absorptionValidations); + if (result["errors"].size() > 0) + { + LL_WARNS("SETTINGS") << "Absorption Config Validation errors: " << result["errors"] << LL_ENDL; + return false; + } + if (result["warnings"].size() > 0) + { + LL_WARNS("SETTINGS") << "Absorption Config Validation warnings: " << result["errors"] << LL_ENDL; + return false; + } + return true; +} + +bool validateMieLayers(LLSD &value) +{ + LLSettingsBase::validation_list_t mieValidations = mieValidationList(); + if (value.isArray()) + { + bool allGood = true; + for (LLSD::array_iterator itf = value.beginArray(); itf != value.endArray(); ++itf) + { + LLSD& layerConfig = (*itf); + if (layerConfig.type() == LLSD::TypeMap) + { + if (!validateMieLayers(layerConfig)) + { + allGood = false; + } + } + else if (layerConfig.type() == LLSD::TypeArray) + { + return validateMieLayers(layerConfig); + } + else + { + return LLSettingsBase::settingValidation(value, mieValidations); + } + } + return allGood; + } + LLSD result = LLSettingsBase::settingValidation(value, mieValidations); + if (result["errors"].size() > 0) + { + LL_WARNS("SETTINGS") << "Mie Config Validation errors: " << result["errors"] << LL_ENDL; + return false; + } + if (result["warnings"].size() > 0) + { + LL_WARNS("SETTINGS") << "Mie Config Validation warnings: " << result["warnings"] << LL_ENDL; + return false; + } + return true; +} + +} + +//========================================================================= +LLSettingsSky::LLSettingsSky(const LLSD &data) : + LLSettingsBase(data), + mNextSunTextureId(), + mNextMoonTextureId(), + mNextCloudTextureId(), + mNextBloomTextureId(), + mNextRainbowTextureId(), + mNextHaloTextureId() +{ +} + +LLSettingsSky::LLSettingsSky(): + LLSettingsBase(), + mNextSunTextureId(), + mNextMoonTextureId(), + mNextCloudTextureId(), + mNextBloomTextureId(), + mNextRainbowTextureId(), + mNextHaloTextureId() +{ +} + +void LLSettingsSky::replaceSettings(LLSD settings) +{ + LLSettingsBase::replaceSettings(settings); + mNextSunTextureId.setNull(); + mNextMoonTextureId.setNull(); + mNextCloudTextureId.setNull(); + mNextBloomTextureId.setNull(); + mNextRainbowTextureId.setNull(); + mNextHaloTextureId.setNull(); +} + +void LLSettingsSky::replaceWithSky(LLSettingsSky::ptr_t pother) +{ + replaceWith(pother); + + mNextSunTextureId = pother->mNextSunTextureId; + mNextMoonTextureId = pother->mNextMoonTextureId; + mNextCloudTextureId = pother->mNextCloudTextureId; + mNextBloomTextureId = pother->mNextBloomTextureId; + mNextRainbowTextureId = pother->mNextRainbowTextureId; + mNextHaloTextureId = pother->mNextHaloTextureId; +} + +void LLSettingsSky::blend(const LLSettingsBase::ptr_t &end, F64 blendf) +{ + llassert(getSettingsType() == end->getSettingsType()); + + LLSettingsSky::ptr_t other = PTR_NAMESPACE::dynamic_pointer_cast(end); + if (other) + { + if (other->mSettings.has(SETTING_LEGACY_HAZE)) + { + if (!mSettings.has(SETTING_LEGACY_HAZE) || !mSettings[SETTING_LEGACY_HAZE].has(SETTING_AMBIENT)) + { + // Special case since SETTING_AMBIENT is both in outer and legacy maps, we prioritize legacy one + // see getAmbientColor(), we are about to replaceSettings(), so we are free to set it + setAmbientColor(getAmbientColor()); + } + } + else + { + if (mSettings.has(SETTING_LEGACY_HAZE) && mSettings[SETTING_LEGACY_HAZE].has(SETTING_AMBIENT)) + { + // Special case due to ambient's duality + // We need to match 'other's' structure for interpolation. + // We are free to change mSettings, since we are about to reset it + mSettings[SETTING_AMBIENT] = getAmbientColor().getValue(); + mSettings[SETTING_LEGACY_HAZE].erase(SETTING_AMBIENT); + } + } + + LLUUID cloud_noise_id = getCloudNoiseTextureId(); + LLUUID cloud_noise_id_next = other->getCloudNoiseTextureId(); + F64 cloud_shadow = 0; + if (!cloud_noise_id.isNull() && cloud_noise_id_next.isNull()) + { + // If there is no cloud texture in destination, reduce coverage to imitate disappearance + // See LLDrawPoolWLSky::renderSkyClouds... we don't blend present texture with null + // Note: Probably can be done by shader + cloud_shadow = lerp(mSettings[SETTING_CLOUD_SHADOW].asReal(), (F64)0.f, blendf); + cloud_noise_id_next = cloud_noise_id; + } + else if (cloud_noise_id.isNull() && !cloud_noise_id_next.isNull()) + { + // Source has no cloud texture, reduce initial coverage to imitate appearance + // use same texture as destination + cloud_shadow = lerp((F64)0.f, other->mSettings[SETTING_CLOUD_SHADOW].asReal(), blendf); + setCloudNoiseTextureId(cloud_noise_id_next); + } + else + { + cloud_shadow = lerp(mSettings[SETTING_CLOUD_SHADOW].asReal(), other->mSettings[SETTING_CLOUD_SHADOW].asReal(), blendf); + } + + LLSD blenddata = interpolateSDMap(mSettings, other->mSettings, other->getParameterMap(), blendf); + blenddata[SETTING_CLOUD_SHADOW] = LLSD::Real(cloud_shadow); + replaceSettings(blenddata); + mNextSunTextureId = other->getSunTextureId(); + mNextMoonTextureId = other->getMoonTextureId(); + mNextCloudTextureId = cloud_noise_id_next; + mNextBloomTextureId = other->getBloomTextureId(); + mNextRainbowTextureId = other->getRainbowTextureId(); + mNextHaloTextureId = other->getHaloTextureId(); + } + else + { + LL_WARNS("SETTINGS") << "Could not cast end settings to sky. No blend performed." << LL_ENDL; + } + + setBlendFactor(blendf); +} + +LLSettingsSky::stringset_t LLSettingsSky::getSkipInterpolateKeys() const +{ + static stringset_t skipSet; + + if (skipSet.empty()) + { + skipSet = LLSettingsBase::getSkipInterpolateKeys(); + skipSet.insert(SETTING_RAYLEIGH_CONFIG); + skipSet.insert(SETTING_MIE_CONFIG); + skipSet.insert(SETTING_ABSORPTION_CONFIG); + skipSet.insert(SETTING_CLOUD_SHADOW); + } + + return skipSet; +} + +LLSettingsSky::stringset_t LLSettingsSky::getSlerpKeys() const +{ + static stringset_t slepSet; + + if (slepSet.empty()) + { + slepSet.insert(SETTING_SUN_ROTATION); + slepSet.insert(SETTING_MOON_ROTATION); + } + + return slepSet; +} + +LLSettingsSky::validation_list_t LLSettingsSky::getValidationList() const +{ + return LLSettingsSky::validationList(); +} + +LLSettingsSky::validation_list_t LLSettingsSky::validationList() +{ + static validation_list_t validation; + + if (validation.empty()) + { // Note the use of LLSD(LLSDArray()()()...) This is due to an issue with the + // copy constructor for LLSDArray. Directly binding the LLSDArray as + // a parameter without first wrapping it in a pure LLSD object will result + // in deeply nested arrays like this [[[[[[[[[[v1,v2,v3]]]]]]]]]] + validation.push_back(Validator(SETTING_BLOOM_TEXTUREID, true, LLSD::TypeUUID)); + validation.push_back(Validator(SETTING_RAINBOW_TEXTUREID, false, LLSD::TypeUUID)); + validation.push_back(Validator(SETTING_HALO_TEXTUREID, false, LLSD::TypeUUID)); + + validation.push_back(Validator(SETTING_CLOUD_COLOR, true, LLSD::TypeArray, + boost::bind(&Validator::verifyVectorMinMax, _1, + LLSD(LLSDArray(0.0f)(0.0f)(0.0f)("*")), + LLSD(LLSDArray(1.0f)(1.0f)(1.0f)("*"))))); + validation.push_back(Validator(SETTING_CLOUD_POS_DENSITY1, true, LLSD::TypeArray, + boost::bind(&Validator::verifyVectorMinMax, _1, + LLSD(LLSDArray(0.0f)(0.0f)(0.0f)("*")), + LLSD(LLSDArray(1.0f)(1.0f)(3.0f)("*"))))); + validation.push_back(Validator(SETTING_CLOUD_POS_DENSITY2, true, LLSD::TypeArray, + boost::bind(&Validator::verifyVectorMinMax, _1, + LLSD(LLSDArray(0.0f)(0.0f)(0.0f)("*")), + LLSD(LLSDArray(1.0f)(1.0f)(1.0f)("*"))))); + validation.push_back(Validator(SETTING_CLOUD_SCALE, true, LLSD::TypeReal, + boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.001f)(3.0f))))); + validation.push_back(Validator(SETTING_CLOUD_SCROLL_RATE, true, LLSD::TypeArray, + boost::bind(&Validator::verifyVectorMinMax, _1, + LLSD(LLSDArray(-50.0f)(-50.0f)), + LLSD(LLSDArray(50.0f)(50.0f))))); + validation.push_back(Validator(SETTING_CLOUD_SHADOW, true, LLSD::TypeReal, + boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f))))); + validation.push_back(Validator(SETTING_CLOUD_TEXTUREID, false, LLSD::TypeUUID)); + validation.push_back(Validator(SETTING_CLOUD_VARIANCE, false, LLSD::TypeReal, + boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f))))); + + validation.push_back(Validator(SETTING_DOME_OFFSET, false, LLSD::TypeReal, + boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f))))); + validation.push_back(Validator(SETTING_DOME_RADIUS, false, LLSD::TypeReal, + boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(1000.0f)(2000.0f))))); + validation.push_back(Validator(SETTING_GAMMA, true, LLSD::TypeReal, + boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(20.0f))))); + validation.push_back(Validator(SETTING_GLOW, true, LLSD::TypeArray, + boost::bind(&Validator::verifyVectorMinMax, _1, + LLSD(LLSDArray(0.2f)("*")(-10.0f)("*")), + LLSD(LLSDArray(40.0f)("*")(10.0f)("*"))))); + + validation.push_back(Validator(SETTING_MAX_Y, true, LLSD::TypeReal, + boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(10000.0f))))); + validation.push_back(Validator(SETTING_MOON_ROTATION, true, LLSD::TypeArray, &Validator::verifyQuaternionNormal)); + validation.push_back(Validator(SETTING_MOON_SCALE, false, LLSD::TypeReal, + boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.25f)(20.0f))), LLSD::Real(1.0))); + validation.push_back(Validator(SETTING_MOON_TEXTUREID, false, LLSD::TypeUUID)); + validation.push_back(Validator(SETTING_MOON_BRIGHTNESS, false, LLSD::TypeReal, + boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f))))); + + validation.push_back(Validator(SETTING_STAR_BRIGHTNESS, true, LLSD::TypeReal, + boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(500.0f))))); + validation.push_back(Validator(SETTING_SUNLIGHT_COLOR, true, LLSD::TypeArray, + boost::bind(&Validator::verifyVectorMinMax, _1, + LLSD(LLSDArray(0.0f)(0.0f)(0.0f)("*")), + LLSD(LLSDArray(3.0f)(3.0f)(3.0f)("*"))))); + validation.push_back(Validator(SETTING_SUN_ROTATION, true, LLSD::TypeArray, &Validator::verifyQuaternionNormal)); + validation.push_back(Validator(SETTING_SUN_SCALE, false, LLSD::TypeReal, + boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.25f)(20.0f))), LLSD::Real(1.0))); + validation.push_back(Validator(SETTING_SUN_TEXTUREID, false, LLSD::TypeUUID)); + + validation.push_back(Validator(SETTING_PLANET_RADIUS, true, LLSD::TypeReal, + boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(1000.0f)(32768.0f))))); + + validation.push_back(Validator(SETTING_SKY_BOTTOM_RADIUS, true, LLSD::TypeReal, + boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(1000.0f)(32768.0f))))); + + validation.push_back(Validator(SETTING_SKY_TOP_RADIUS, true, LLSD::TypeReal, + boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(1000.0f)(32768.0f))))); + + validation.push_back(Validator(SETTING_SUN_ARC_RADIANS, true, LLSD::TypeReal, + boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(0.1f))))); + + validation.push_back(Validator(SETTING_SKY_MOISTURE_LEVEL, false, LLSD::TypeReal, + boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f))))); + + validation.push_back(Validator(SETTING_SKY_DROPLET_RADIUS, false, LLSD::TypeReal, + boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(5.0f)(1000.0f))))); + + validation.push_back(Validator(SETTING_SKY_ICE_LEVEL, false, LLSD::TypeReal, + boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f))))); + + validation.push_back(Validator(SETTING_RAYLEIGH_CONFIG, true, LLSD::TypeArray, &validateRayleighLayers)); + validation.push_back(Validator(SETTING_ABSORPTION_CONFIG, true, LLSD::TypeArray, &validateAbsorptionLayers)); + validation.push_back(Validator(SETTING_MIE_CONFIG, true, LLSD::TypeArray, &validateMieLayers)); + validation.push_back(Validator(SETTING_LEGACY_HAZE, false, LLSD::TypeMap, &validateLegacyHaze)); + } + return validation; +} + +LLSD LLSettingsSky::createDensityProfileLayer( + F32 width, + F32 exponential_term, + F32 exponential_scale_factor, + F32 linear_term, + F32 constant_term, + F32 aniso_factor) +{ + LLSD dflt_layer; + dflt_layer[SETTING_DENSITY_PROFILE_WIDTH] = width; // 0 -> the entire atmosphere + dflt_layer[SETTING_DENSITY_PROFILE_EXP_TERM] = exponential_term; + dflt_layer[SETTING_DENSITY_PROFILE_EXP_SCALE_FACTOR] = exponential_scale_factor; + dflt_layer[SETTING_DENSITY_PROFILE_LINEAR_TERM] = linear_term; + dflt_layer[SETTING_DENSITY_PROFILE_CONSTANT_TERM] = constant_term; + + if (aniso_factor != 0.0f) + { + dflt_layer[SETTING_MIE_ANISOTROPY_FACTOR] = aniso_factor; + } + + return dflt_layer; +} + +LLSD LLSettingsSky::createSingleLayerDensityProfile( + F32 width, + F32 exponential_term, + F32 exponential_scale_factor, + F32 linear_term, + F32 constant_term, + F32 aniso_factor) +{ + LLSD dflt; + LLSD dflt_layer = createDensityProfileLayer(width, exponential_term, exponential_scale_factor, linear_term, constant_term, aniso_factor); + dflt.append(dflt_layer); + return dflt; +} + +LLSD LLSettingsSky::rayleighConfigDefault() +{ + return createSingleLayerDensityProfile(0.0f, 1.0f, -1.0f / 8000.0f, 0.0f, 0.0f); +} + +LLSD LLSettingsSky::absorptionConfigDefault() +{ +// absorption (ozone) has two linear ramping zones + LLSD dflt_absorption_layer_a = createDensityProfileLayer(25000.0f, 0.0f, 0.0f, -1.0f / 25000.0f, -2.0f / 3.0f); + LLSD dflt_absorption_layer_b = createDensityProfileLayer(0.0f, 0.0f, 0.0f, -1.0f / 15000.0f, 8.0f / 3.0f); + LLSD dflt_absorption; + dflt_absorption.append(dflt_absorption_layer_a); + dflt_absorption.append(dflt_absorption_layer_b); + return dflt_absorption; +} + +LLSD LLSettingsSky::mieConfigDefault() +{ + LLSD dflt_mie = createSingleLayerDensityProfile(0.0f, 1.0f, -1.0f / 1200.0f, 0.0f, 0.0f, 0.8f); + return dflt_mie; +} + +LLSD LLSettingsSky::defaults(const LLSettingsBase::TrackPosition& position) +{ + static LLSD dfltsetting; + + if (dfltsetting.size() == 0) + { + LLQuaternion sunquat; + LLQuaternion moonquat; + + F32 azimuth = (F_PI * position) + (80.0f * DEG_TO_RAD); + F32 altitude = (F_PI * position); + + // give the sun and moon slightly different tracks through the sky + // instead of positioning them at opposite poles from each other... + sunquat = convert_azimuth_and_altitude_to_quat(altitude, azimuth); + moonquat = convert_azimuth_and_altitude_to_quat(altitude + (F_PI * 0.125f), azimuth + (F_PI * 0.125f)); + + // Magic constants copied form dfltsetting.xml + dfltsetting[SETTING_CLOUD_COLOR] = LLColor4(0.4099f, 0.4099f, 0.4099f, 0.0f).getValue(); + dfltsetting[SETTING_CLOUD_POS_DENSITY1] = LLColor4(1.0000f, 0.5260f, 1.0000f, 0.0f).getValue(); + dfltsetting[SETTING_CLOUD_POS_DENSITY2] = LLColor4(1.0000f, 0.5260f, 1.0000f, 0.0f).getValue(); + dfltsetting[SETTING_CLOUD_SCALE] = LLSD::Real(0.4199); + dfltsetting[SETTING_CLOUD_SCROLL_RATE] = LLSDArray(0.0f)(0.0f); + dfltsetting[SETTING_CLOUD_SHADOW] = LLSD::Real(0.2699); + dfltsetting[SETTING_CLOUD_VARIANCE] = LLSD::Real(0.0); + + dfltsetting[SETTING_DOME_OFFSET] = LLSD::Real(0.96f); + dfltsetting[SETTING_DOME_RADIUS] = LLSD::Real(15000.f); + dfltsetting[SETTING_GAMMA] = LLSD::Real(1.0); + dfltsetting[SETTING_GLOW] = LLColor4(5.000f, 0.0010f, -0.4799f, 1.0f).getValue(); + + dfltsetting[SETTING_MAX_Y] = LLSD::Real(1605); + dfltsetting[SETTING_MOON_ROTATION] = moonquat.getValue(); + dfltsetting[SETTING_MOON_BRIGHTNESS] = LLSD::Real(0.5f); + + dfltsetting[SETTING_STAR_BRIGHTNESS] = LLSD::Real(256.0000); + dfltsetting[SETTING_SUNLIGHT_COLOR] = LLColor4(0.7342f, 0.7815f, 0.8999f, 0.0f).getValue(); + dfltsetting[SETTING_SUN_ROTATION] = sunquat.getValue(); + + dfltsetting[SETTING_BLOOM_TEXTUREID] = GetDefaultBloomTextureId(); + dfltsetting[SETTING_CLOUD_TEXTUREID] = GetDefaultCloudNoiseTextureId(); + dfltsetting[SETTING_MOON_TEXTUREID] = GetDefaultMoonTextureId(); + dfltsetting[SETTING_SUN_TEXTUREID] = GetDefaultSunTextureId(); + dfltsetting[SETTING_RAINBOW_TEXTUREID] = GetDefaultRainbowTextureId(); + dfltsetting[SETTING_HALO_TEXTUREID] = GetDefaultHaloTextureId(); + + dfltsetting[SETTING_TYPE] = "sky"; + + // defaults are for earth... + dfltsetting[SETTING_PLANET_RADIUS] = 6360.0f; + dfltsetting[SETTING_SKY_BOTTOM_RADIUS] = 6360.0f; + dfltsetting[SETTING_SKY_TOP_RADIUS] = 6420.0f; + dfltsetting[SETTING_SUN_ARC_RADIANS] = 0.00045f; + + dfltsetting[SETTING_SKY_MOISTURE_LEVEL] = 0.0f; + dfltsetting[SETTING_SKY_DROPLET_RADIUS] = 800.0f; + dfltsetting[SETTING_SKY_ICE_LEVEL] = 0.0f; + + dfltsetting[SETTING_RAYLEIGH_CONFIG] = rayleighConfigDefault(); + dfltsetting[SETTING_MIE_CONFIG] = mieConfigDefault(); + dfltsetting[SETTING_ABSORPTION_CONFIG] = absorptionConfigDefault(); + } + + return dfltsetting; +} + +LLSD LLSettingsSky::translateLegacyHazeSettings(const LLSD& legacy) +{ + LLSD legacyhazesettings; + +// AdvancedAtmospherics TODO +// These need to be translated into density profile info in the new settings format... +// LEGACY_ATMOSPHERICS + if (legacy.has(SETTING_AMBIENT)) + { + legacyhazesettings[SETTING_AMBIENT] = LLColor3(legacy[SETTING_AMBIENT]).getValue(); + } + if (legacy.has(SETTING_BLUE_DENSITY)) + { + legacyhazesettings[SETTING_BLUE_DENSITY] = LLColor3(legacy[SETTING_BLUE_DENSITY]).getValue(); + } + if (legacy.has(SETTING_BLUE_HORIZON)) + { + legacyhazesettings[SETTING_BLUE_HORIZON] = LLColor3(legacy[SETTING_BLUE_HORIZON]).getValue(); + } + if (legacy.has(SETTING_DENSITY_MULTIPLIER)) + { + legacyhazesettings[SETTING_DENSITY_MULTIPLIER] = LLSD::Real(legacy[SETTING_DENSITY_MULTIPLIER][0].asReal()); + } + if (legacy.has(SETTING_DISTANCE_MULTIPLIER)) + { + legacyhazesettings[SETTING_DISTANCE_MULTIPLIER] = LLSD::Real(legacy[SETTING_DISTANCE_MULTIPLIER][0].asReal()); + } + if (legacy.has(SETTING_HAZE_DENSITY)) + { + legacyhazesettings[SETTING_HAZE_DENSITY] = LLSD::Real(legacy[SETTING_HAZE_DENSITY][0].asReal()); + } + if (legacy.has(SETTING_HAZE_HORIZON)) + { + legacyhazesettings[SETTING_HAZE_HORIZON] = LLSD::Real(legacy[SETTING_HAZE_HORIZON][0].asReal()); + } + + return legacyhazesettings; +} + +LLSD LLSettingsSky::translateLegacySettings(const LLSD& legacy) +{ + bool converted_something(false); + LLSD newsettings(defaults()); + + // Move legacy haze parameters to an inner map + // allowing backward compat and simple conversion to legacy format + LLSD legacyhazesettings; + legacyhazesettings = translateLegacyHazeSettings(legacy); + if (legacyhazesettings.size() > 0) + { + newsettings[SETTING_LEGACY_HAZE] = legacyhazesettings; + converted_something |= true; + } + + if (legacy.has(SETTING_CLOUD_COLOR)) + { + newsettings[SETTING_CLOUD_COLOR] = LLColor3(legacy[SETTING_CLOUD_COLOR]).getValue(); + converted_something |= true; + } + if (legacy.has(SETTING_CLOUD_POS_DENSITY1)) + { + newsettings[SETTING_CLOUD_POS_DENSITY1] = LLColor3(legacy[SETTING_CLOUD_POS_DENSITY1]).getValue(); + converted_something |= true; + } + if (legacy.has(SETTING_CLOUD_POS_DENSITY2)) + { + newsettings[SETTING_CLOUD_POS_DENSITY2] = LLColor3(legacy[SETTING_CLOUD_POS_DENSITY2]).getValue(); + converted_something |= true; + } + if (legacy.has(SETTING_CLOUD_SCALE)) + { + newsettings[SETTING_CLOUD_SCALE] = LLSD::Real(legacy[SETTING_CLOUD_SCALE][0].asReal()); + converted_something |= true; + } + if (legacy.has(SETTING_CLOUD_SCROLL_RATE)) + { + LLVector2 cloud_scroll(legacy[SETTING_CLOUD_SCROLL_RATE]); + + cloud_scroll -= LLVector2(10, 10); + if (legacy.has(SETTING_LEGACY_ENABLE_CLOUD_SCROLL)) + { + LLSD enabled = legacy[SETTING_LEGACY_ENABLE_CLOUD_SCROLL]; + if (!enabled[0].asBoolean()) + cloud_scroll.mV[0] = 0.0f; + if (!enabled[1].asBoolean()) + cloud_scroll.mV[1] = 0.0f; + } + + newsettings[SETTING_CLOUD_SCROLL_RATE] = cloud_scroll.getValue(); + converted_something |= true; + } + if (legacy.has(SETTING_CLOUD_SHADOW)) + { + newsettings[SETTING_CLOUD_SHADOW] = LLSD::Real(legacy[SETTING_CLOUD_SHADOW][0].asReal()); + converted_something |= true; + } + + + if (legacy.has(SETTING_GAMMA)) + { + newsettings[SETTING_GAMMA] = legacy[SETTING_GAMMA][0].asReal(); + converted_something |= true; + } + if (legacy.has(SETTING_GLOW)) + { + newsettings[SETTING_GLOW] = LLColor3(legacy[SETTING_GLOW]).getValue(); + converted_something |= true; + } + + if (legacy.has(SETTING_MAX_Y)) + { + newsettings[SETTING_MAX_Y] = LLSD::Real(legacy[SETTING_MAX_Y][0].asReal()); + converted_something |= true; + } + if (legacy.has(SETTING_STAR_BRIGHTNESS)) + { + newsettings[SETTING_STAR_BRIGHTNESS] = LLSD::Real(legacy[SETTING_STAR_BRIGHTNESS].asReal() * 250.0f); + converted_something |= true; + } + if (legacy.has(SETTING_SUNLIGHT_COLOR)) + { + newsettings[SETTING_SUNLIGHT_COLOR] = LLColor4(legacy[SETTING_SUNLIGHT_COLOR]).getValue(); + converted_something |= true; + } + + if (legacy.has(SETTING_PLANET_RADIUS)) + { + newsettings[SETTING_PLANET_RADIUS] = LLSD::Real(legacy[SETTING_PLANET_RADIUS].asReal()); + converted_something |= true; + } + + if (legacy.has(SETTING_SKY_BOTTOM_RADIUS)) + { + newsettings[SETTING_SKY_BOTTOM_RADIUS] = LLSD::Real(legacy[SETTING_SKY_BOTTOM_RADIUS].asReal()); + converted_something |= true; + } + + if (legacy.has(SETTING_SKY_TOP_RADIUS)) + { + newsettings[SETTING_SKY_TOP_RADIUS] = LLSD::Real(legacy[SETTING_SKY_TOP_RADIUS].asReal()); + converted_something |= true; + } + + if (legacy.has(SETTING_SUN_ARC_RADIANS)) + { + newsettings[SETTING_SUN_ARC_RADIANS] = LLSD::Real(legacy[SETTING_SUN_ARC_RADIANS].asReal()); + converted_something |= true; + } + + if (legacy.has(SETTING_LEGACY_EAST_ANGLE) && legacy.has(SETTING_LEGACY_SUN_ANGLE)) + { + // get counter-clockwise radian angle from clockwise legacy WL east angle... + F32 azimuth = -legacy[SETTING_LEGACY_EAST_ANGLE].asReal(); + F32 altitude = legacy[SETTING_LEGACY_SUN_ANGLE].asReal(); + + LLQuaternion sunquat = convert_azimuth_and_altitude_to_quat(azimuth, altitude); + // original WL moon dir was diametrically opposed to the sun dir + LLQuaternion moonquat = convert_azimuth_and_altitude_to_quat(azimuth + F_PI, -altitude); + + newsettings[SETTING_SUN_ROTATION] = sunquat.getValue(); + newsettings[SETTING_MOON_ROTATION] = moonquat.getValue(); + converted_something |= true; + } + + if (!converted_something) + return LLSD(); + + return newsettings; +} + +void LLSettingsSky::updateSettings() +{ + LL_RECORD_BLOCK_TIME(FTM_RECALCULATE_SKYVALUES); + + // base class clears dirty flag so as to not trigger recursive update + LLSettingsBase::updateSettings(); + + // NOTE: these functions are designed to do nothing unless a dirty bit has been set + // so if you add new settings that are referenced by these update functions, + // you'll need to insure that your setter updates the dirty bits as well + calculateHeavenlyBodyPositions(); + calculateLightSettings(); +} + +F32 LLSettingsSky::getSunMoonGlowFactor() const +{ + LLVector3 sunDir = getSunDirection(); + LLVector3 moonDir = getMoonDirection(); + + // sun glow at full iff moon is not up + if (sunDir.mV[VZ] > -NIGHTTIME_ELEVATION_SIN) + { + if (moonDir.mV[2] <= 0.0f) + { + return 1.0f; + } + } + + if (moonDir.mV[2] > 0.0f) + { + return 0.25f; + } + + return 0.0f; +} + +bool LLSettingsSky::getIsSunUp() const +{ + LLVector3 sunDir = getSunDirection(); + return (sunDir.mV[2] >= 0.0f) || ((sunDir.mV[2] > -NIGHTTIME_ELEVATION_SIN) && !getIsMoonUp()); +} + +bool LLSettingsSky::getIsMoonUp() const +{ + LLVector3 moonDir = getMoonDirection(); + return moonDir.mV[2] > 0.0f; +} + +void LLSettingsSky::calculateHeavenlyBodyPositions() const +{ + LLQuaternion sunq = getSunRotation(); + LLQuaternion moonq = getMoonRotation(); + + mSunDirection = LLVector3::x_axis * sunq; + mMoonDirection = LLVector3::x_axis * moonq; + + mSunDirection.normalize(); + mMoonDirection.normalize(); + + if (mSunDirection.lengthSquared() < 0.01f) + LL_WARNS("SETTINGS") << "Zero length sun direction. Wailing and gnashing of teeth may follow... or not." << LL_ENDL; + if (mMoonDirection.lengthSquared() < 0.01f) + LL_WARNS("SETTINGS") << "Zero length moon direction. Wailing and gnashing of teeth may follow... or not." << LL_ENDL; +} + +LLVector3 LLSettingsSky::getLightDirection() const +{ + update(); + + // is the normal from the sun or the moon + if (getIsSunUp()) + { + return mSunDirection; + } + else if (getIsMoonUp()) + { + return mMoonDirection; + } + + return LLVector3::z_axis; +} + +LLColor3 LLSettingsSky::getLightDiffuse() const +{ + update(); + + // is the normal from the sun or the moon + if (getIsSunUp()) + { + return getSunDiffuse(); + } + else if (getIsMoonUp()) + { + return getMoonDiffuse(); + } + + return LLColor3::white; +} + +LLColor3 LLSettingsSky::getAmbientColor() const +{ + if (mSettings.has(SETTING_LEGACY_HAZE) && mSettings[SETTING_LEGACY_HAZE].has(SETTING_AMBIENT)) + { + return LLColor3(mSettings[SETTING_LEGACY_HAZE][SETTING_AMBIENT]); + } + if (mSettings.has(SETTING_AMBIENT)) + { + return LLColor3(mSettings[SETTING_AMBIENT]); + } + return LLColor3(0.25f, 0.25f, 0.25f); +} + +LLColor3 LLSettingsSky::getBlueDensity() const +{ + if (mSettings.has(SETTING_LEGACY_HAZE) && mSettings[SETTING_LEGACY_HAZE].has(SETTING_BLUE_DENSITY)) + { + return LLColor3(mSettings[SETTING_LEGACY_HAZE][SETTING_BLUE_DENSITY]); + } + return LLColor3(0.2447f, 0.4487f, 0.7599f); +} + +LLColor3 LLSettingsSky::getBlueHorizon() const +{ + if (mSettings.has(SETTING_LEGACY_HAZE) && mSettings[SETTING_LEGACY_HAZE].has(SETTING_BLUE_HORIZON)) + { + return LLColor3(mSettings[SETTING_LEGACY_HAZE][SETTING_BLUE_HORIZON]); + } + return LLColor3(0.4954f, 0.4954f, 0.6399f); +} + +F32 LLSettingsSky::getHazeDensity() const +{ + if (mSettings.has(SETTING_LEGACY_HAZE) && mSettings[SETTING_LEGACY_HAZE].has(SETTING_HAZE_DENSITY)) + { + return mSettings[SETTING_LEGACY_HAZE][SETTING_HAZE_DENSITY].asReal(); + } + return 0.7f; +} + +F32 LLSettingsSky::getHazeHorizon() const +{ + if (mSettings.has(SETTING_LEGACY_HAZE) && mSettings[SETTING_LEGACY_HAZE].has(SETTING_HAZE_HORIZON)) + { + return mSettings[SETTING_LEGACY_HAZE][SETTING_HAZE_HORIZON].asReal(); + } + return 0.19f; +} + +F32 LLSettingsSky::getDensityMultiplier() const +{ + F32 density_multiplier = 0.0001f; + if (mSettings.has(SETTING_LEGACY_HAZE) && mSettings[SETTING_LEGACY_HAZE].has(SETTING_DENSITY_MULTIPLIER)) + { + density_multiplier = mSettings[SETTING_LEGACY_HAZE][SETTING_DENSITY_MULTIPLIER].asReal(); + } + return density_multiplier; +} + +F32 LLSettingsSky::getDistanceMultiplier() const +{ + if (mSettings.has(SETTING_LEGACY_HAZE) && mSettings[SETTING_LEGACY_HAZE].has(SETTING_DISTANCE_MULTIPLIER)) + { + return mSettings[SETTING_LEGACY_HAZE][SETTING_DISTANCE_MULTIPLIER].asReal(); + } + return 0.8f; +} + +void LLSettingsSky::setPlanetRadius(F32 radius) +{ + mSettings[SETTING_PLANET_RADIUS] = radius; +} + +void LLSettingsSky::setSkyBottomRadius(F32 radius) +{ + mSettings[SETTING_SKY_BOTTOM_RADIUS] = radius; +} + +void LLSettingsSky::setSkyTopRadius(F32 radius) +{ + mSettings[SETTING_SKY_TOP_RADIUS] = radius; +} + +void LLSettingsSky::setSunArcRadians(F32 radians) +{ + mSettings[SETTING_SUN_ARC_RADIANS] = radians; +} + +void LLSettingsSky::setMieAnisotropy(F32 aniso_factor) +{ + getMieConfig()[SETTING_MIE_ANISOTROPY_FACTOR] = aniso_factor; +} + +void LLSettingsSky::setSkyMoistureLevel(F32 moisture_level) +{ + setValue(SETTING_SKY_MOISTURE_LEVEL, moisture_level); +} + +void LLSettingsSky::setSkyDropletRadius(F32 radius) +{ + setValue(SETTING_SKY_DROPLET_RADIUS,radius); +} + +void LLSettingsSky::setSkyIceLevel(F32 ice_level) +{ + setValue(SETTING_SKY_ICE_LEVEL, ice_level); +} + +void LLSettingsSky::setAmbientColor(const LLColor3 &val) +{ + mSettings[SETTING_LEGACY_HAZE][SETTING_AMBIENT] = val.getValue(); + setDirtyFlag(true); +} + +void LLSettingsSky::setBlueDensity(const LLColor3 &val) +{ + mSettings[SETTING_LEGACY_HAZE][SETTING_BLUE_DENSITY] = val.getValue(); + setDirtyFlag(true); +} + +void LLSettingsSky::setBlueHorizon(const LLColor3 &val) +{ + mSettings[SETTING_LEGACY_HAZE][SETTING_BLUE_HORIZON] = val.getValue(); + setDirtyFlag(true); +} + +void LLSettingsSky::setDensityMultiplier(F32 val) +{ + mSettings[SETTING_LEGACY_HAZE][SETTING_DENSITY_MULTIPLIER] = val; + setDirtyFlag(true); +} + +void LLSettingsSky::setDistanceMultiplier(F32 val) +{ + mSettings[SETTING_LEGACY_HAZE][SETTING_DISTANCE_MULTIPLIER] = val; + setDirtyFlag(true); +} + +void LLSettingsSky::setHazeDensity(F32 val) +{ + mSettings[SETTING_LEGACY_HAZE][SETTING_HAZE_DENSITY] = val; + setDirtyFlag(true); +} + +void LLSettingsSky::setHazeHorizon(F32 val) +{ + mSettings[SETTING_LEGACY_HAZE][SETTING_HAZE_HORIZON] = val; + setDirtyFlag(true); +} + +// Sunlight attenuation effect (hue and brightness) due to atmosphere +// this is used later for sunlight modulation at various altitudes +LLColor3 LLSettingsSky::getLightAttenuation(F32 distance) const +{ +// LEGACY_ATMOSPHERICS + LLColor3 blue_density = getBlueDensity(); + F32 haze_density = getHazeDensity(); + F32 density_multiplier = getDensityMultiplier(); + LLColor3 density = (blue_density * 1.0 + smear(haze_density * 0.25f)); + LLColor3 light_atten = density * density_multiplier * distance; + return light_atten; +} + +LLColor3 LLSettingsSky::getLightTransmittance() const +{ +// LEGACY_ATMOSPHERICS + LLColor3 blue_density = getBlueDensity(); + F32 haze_density = getHazeDensity(); + F32 density_multiplier = getDensityMultiplier(); + LLColor3 temp1 = blue_density + smear(haze_density); + // Transparency (-> temp1) + temp1 = componentExp((temp1 * -1.f) * density_multiplier); + return temp1; +} + +LLColor3 LLSettingsSky::gammaCorrect(const LLColor3& in) const +{ + F32 gamma = getGamma(); + LLColor3 v(in); + v.clamp(); + v= smear(1.0f) - v; + v = componentPow(v, gamma); + v = smear(1.0f) - v; + return v; +} + +LLVector3 LLSettingsSky::getSunDirection() const +{ + update(); + return mSunDirection; +} + +LLVector3 LLSettingsSky::getMoonDirection() const +{ + update(); + return mMoonDirection; +} + +LLColor4 LLSettingsSky::getMoonAmbient() const +{ + update(); + return mMoonAmbient; +} + +LLColor3 LLSettingsSky::getMoonDiffuse() const +{ + update(); + return mMoonDiffuse; +} + +LLColor4 LLSettingsSky::getSunAmbient() const +{ + update(); + return mSunAmbient; +} + +LLColor3 LLSettingsSky::getSunDiffuse() const +{ + update(); + return mSunDiffuse; +} + +LLColor4 LLSettingsSky::getTotalAmbient() const +{ + update(); + return mTotalAmbient; +} + +void LLSettingsSky::calculateLightSettings() const +{ + // Initialize temp variables + LLColor3 sunlight = getSunlightColor(); + LLColor3 ambient = getAmbientColor(); + F32 cloud_shadow = getCloudShadow(); + LLVector3 lightnorm = getLightDirection(); + + // Sunlight attenuation effect (hue and brightness) due to atmosphere + // this is used later for sunlight modulation at various altitudes + F32 max_y = getMaxY(); + LLColor3 light_atten = getLightAttenuation(max_y); + LLColor3 light_transmittance = getLightTransmittance(); + + // and vary_sunlight will work properly with moon light + F32 lighty = lightnorm[1]; + if(fabs(lighty) > 0.001f) + { + lighty = 1.f / lighty; + } + lighty = llmax(0.001f, lighty); + componentMultBy(sunlight, componentExp((light_atten * -1.f) * lighty)); + + //increase ambient when there are more clouds + LLColor3 tmpAmbient = ambient + (smear(1.f) - ambient) * cloud_shadow * 0.5f; + + //brightness of surface both sunlight and ambient + mSunDiffuse = gammaCorrect(componentMult(sunlight, light_transmittance)); + mSunAmbient = gammaCorrect(componentMult(tmpAmbient, light_transmittance) * 0.5); + + mMoonDiffuse = gammaCorrect(componentMult(LLColor3::white, light_transmittance) * 0.5f); + mMoonAmbient = gammaCorrect(componentMult(LLColor3::white, light_transmittance) * 0.25f); + mTotalAmbient = mSunAmbient; +} + +LLUUID LLSettingsSky::GetDefaultAssetId() +{ + return DEFAULT_ASSET_ID; +} + +LLUUID LLSettingsSky::GetDefaultSunTextureId() +{ + return LLUUID::null; +} + + +LLUUID LLSettingsSky::GetBlankSunTextureId() +{ + return DEFAULT_SUN_ID; +} + +LLUUID LLSettingsSky::GetDefaultMoonTextureId() +{ + return DEFAULT_MOON_ID; +} + +LLUUID LLSettingsSky::GetDefaultCloudNoiseTextureId() +{ + return DEFAULT_CLOUD_ID; +} + +LLUUID LLSettingsSky::GetDefaultBloomTextureId() +{ + return IMG_BLOOM1; +} + +LLUUID LLSettingsSky::GetDefaultRainbowTextureId() +{ + return IMG_RAINBOW; +} + +LLUUID LLSettingsSky::GetDefaultHaloTextureId() +{ + return IMG_HALO; +} + +F32 LLSettingsSky::getPlanetRadius() const +{ + return mSettings[SETTING_PLANET_RADIUS].asReal(); +} + +F32 LLSettingsSky::getSkyMoistureLevel() const +{ + return mSettings[SETTING_SKY_MOISTURE_LEVEL].asReal(); +} + +F32 LLSettingsSky::getSkyDropletRadius() const +{ + return mSettings[SETTING_SKY_DROPLET_RADIUS].asReal(); +} + +F32 LLSettingsSky::getSkyIceLevel() const +{ + return mSettings[SETTING_SKY_ICE_LEVEL].asReal(); +} + +F32 LLSettingsSky::getSkyBottomRadius() const +{ + return mSettings[SETTING_SKY_BOTTOM_RADIUS].asReal(); +} + +F32 LLSettingsSky::getSkyTopRadius() const +{ + return mSettings[SETTING_SKY_TOP_RADIUS].asReal(); +} + +F32 LLSettingsSky::getSunArcRadians() const +{ + return mSettings[SETTING_SUN_ARC_RADIANS].asReal(); +} + +F32 LLSettingsSky::getMieAnisotropy() const +{ + return getMieConfig()[SETTING_MIE_ANISOTROPY_FACTOR].asReal(); +} + +LLSD LLSettingsSky::getRayleighConfig() const +{ + LLSD copy = *(mSettings[SETTING_RAYLEIGH_CONFIG].beginArray()); + return copy; +} + +LLSD LLSettingsSky::getMieConfig() const +{ + LLSD copy = *(mSettings[SETTING_MIE_CONFIG].beginArray()); + return copy; +} + +LLSD LLSettingsSky::getAbsorptionConfig() const +{ + LLSD copy = *(mSettings[SETTING_ABSORPTION_CONFIG].beginArray()); + return copy; +} + +LLSD LLSettingsSky::getRayleighConfigs() const +{ + return mSettings[SETTING_RAYLEIGH_CONFIG]; +} + +LLSD LLSettingsSky::getMieConfigs() const +{ + return mSettings[SETTING_MIE_CONFIG]; +} + +LLSD LLSettingsSky::getAbsorptionConfigs() const +{ + return mSettings[SETTING_ABSORPTION_CONFIG]; +} + +void LLSettingsSky::setRayleighConfigs(const LLSD& rayleighConfig) +{ + mSettings[SETTING_RAYLEIGH_CONFIG] = rayleighConfig; +} + +void LLSettingsSky::setMieConfigs(const LLSD& mieConfig) +{ + mSettings[SETTING_MIE_CONFIG] = mieConfig; +} + +void LLSettingsSky::setAbsorptionConfigs(const LLSD& absorptionConfig) +{ + mSettings[SETTING_ABSORPTION_CONFIG] = absorptionConfig; +} + +LLUUID LLSettingsSky::getBloomTextureId() const +{ + return mSettings[SETTING_BLOOM_TEXTUREID].asUUID(); +} + +LLUUID LLSettingsSky::getRainbowTextureId() const +{ + return mSettings[SETTING_RAINBOW_TEXTUREID].asUUID(); +} + +LLUUID LLSettingsSky::getHaloTextureId() const +{ + return mSettings[SETTING_HALO_TEXTUREID].asUUID(); +} + +//--------------------------------------------------------------------- +LLColor3 LLSettingsSky::getCloudColor() const +{ + return LLColor3(mSettings[SETTING_CLOUD_COLOR]); +} + +void LLSettingsSky::setCloudColor(const LLColor3 &val) +{ + setValue(SETTING_CLOUD_COLOR, val); +} + +LLUUID LLSettingsSky::getCloudNoiseTextureId() const +{ + return mSettings[SETTING_CLOUD_TEXTUREID].asUUID(); +} + +void LLSettingsSky::setCloudNoiseTextureId(const LLUUID &id) +{ + setValue(SETTING_CLOUD_TEXTUREID, id); +} + +LLColor3 LLSettingsSky::getCloudPosDensity1() const +{ + return LLColor3(mSettings[SETTING_CLOUD_POS_DENSITY1]); +} + +void LLSettingsSky::setCloudPosDensity1(const LLColor3 &val) +{ + setValue(SETTING_CLOUD_POS_DENSITY1, val); +} + +LLColor3 LLSettingsSky::getCloudPosDensity2() const +{ + return LLColor3(mSettings[SETTING_CLOUD_POS_DENSITY2]); +} + +void LLSettingsSky::setCloudPosDensity2(const LLColor3 &val) +{ + setValue(SETTING_CLOUD_POS_DENSITY2, val); +} + +F32 LLSettingsSky::getCloudScale() const +{ + return mSettings[SETTING_CLOUD_SCALE].asReal(); +} + +void LLSettingsSky::setCloudScale(F32 val) +{ + setValue(SETTING_CLOUD_SCALE, val); +} + +LLVector2 LLSettingsSky::getCloudScrollRate() const +{ + return LLVector2(mSettings[SETTING_CLOUD_SCROLL_RATE]); +} + +void LLSettingsSky::setCloudScrollRate(const LLVector2 &val) +{ + setValue(SETTING_CLOUD_SCROLL_RATE, val); +} + +void LLSettingsSky::setCloudScrollRateX(F32 val) +{ + mSettings[SETTING_CLOUD_SCROLL_RATE][0] = val; + setDirtyFlag(true); +} + +void LLSettingsSky::setCloudScrollRateY(F32 val) +{ + mSettings[SETTING_CLOUD_SCROLL_RATE][1] = val; + setDirtyFlag(true); +} + +F32 LLSettingsSky::getCloudShadow() const +{ + return mSettings[SETTING_CLOUD_SHADOW].asReal(); +} + +void LLSettingsSky::setCloudShadow(F32 val) +{ + setValue(SETTING_CLOUD_SHADOW, val); +} + +F32 LLSettingsSky::getCloudVariance() const +{ + return mSettings[SETTING_CLOUD_VARIANCE].asReal(); +} + +void LLSettingsSky::setCloudVariance(F32 val) +{ + setValue(SETTING_CLOUD_VARIANCE, val); +} + +F32 LLSettingsSky::getDomeOffset() const +{ + //return mSettings[SETTING_DOME_OFFSET].asReal(); + return DOME_OFFSET; +} + +F32 LLSettingsSky::getDomeRadius() const +{ + //return mSettings[SETTING_DOME_RADIUS].asReal(); + return DOME_RADIUS; +} + +F32 LLSettingsSky::getGamma() const +{ + return mSettings[SETTING_GAMMA].asReal(); +} + +void LLSettingsSky::setGamma(F32 val) +{ + mSettings[SETTING_GAMMA] = LLSD::Real(val); + setDirtyFlag(true); +} + +LLColor3 LLSettingsSky::getGlow() const +{ + return LLColor3(mSettings[SETTING_GLOW]); +} + +void LLSettingsSky::setGlow(const LLColor3 &val) +{ + setValue(SETTING_GLOW, val); +} + +F32 LLSettingsSky::getMaxY() const +{ + return mSettings[SETTING_MAX_Y].asReal(); +} + +void LLSettingsSky::setMaxY(F32 val) +{ + setValue(SETTING_MAX_Y, val); +} + +LLQuaternion LLSettingsSky::getMoonRotation() const +{ + return LLQuaternion(mSettings[SETTING_MOON_ROTATION]); +} + +void LLSettingsSky::setMoonRotation(const LLQuaternion &val) +{ + setValue(SETTING_MOON_ROTATION, val); +} + +F32 LLSettingsSky::getMoonScale() const +{ + return mSettings[SETTING_MOON_SCALE].asReal(); +} + +void LLSettingsSky::setMoonScale(F32 val) +{ + setValue(SETTING_MOON_SCALE, val); +} + +LLUUID LLSettingsSky::getMoonTextureId() const +{ + return mSettings[SETTING_MOON_TEXTUREID].asUUID(); +} + +void LLSettingsSky::setMoonTextureId(LLUUID id) +{ + setValue(SETTING_MOON_TEXTUREID, id); +} + +F32 LLSettingsSky::getMoonBrightness() const +{ + return mSettings[SETTING_MOON_BRIGHTNESS].asReal(); +} + +void LLSettingsSky::setMoonBrightness(F32 brightness_factor) +{ + setValue(SETTING_MOON_BRIGHTNESS, brightness_factor); +} + +F32 LLSettingsSky::getStarBrightness() const +{ + return mSettings[SETTING_STAR_BRIGHTNESS].asReal(); +} + +void LLSettingsSky::setStarBrightness(F32 val) +{ + setValue(SETTING_STAR_BRIGHTNESS, val); +} + +LLColor3 LLSettingsSky::getSunlightColor() const +{ + return LLColor3(mSettings[SETTING_SUNLIGHT_COLOR]); +} + +void LLSettingsSky::setSunlightColor(const LLColor3 &val) +{ + setValue(SETTING_SUNLIGHT_COLOR, val); +} + +LLQuaternion LLSettingsSky::getSunRotation() const +{ + return LLQuaternion(mSettings[SETTING_SUN_ROTATION]); +} + +void LLSettingsSky::setSunRotation(const LLQuaternion &val) +{ + setValue(SETTING_SUN_ROTATION, val); +} + + +F32 LLSettingsSky::getSunScale() const +{ + return mSettings[SETTING_SUN_SCALE].asReal(); +} + +void LLSettingsSky::setSunScale(F32 val) +{ + setValue(SETTING_SUN_SCALE, val); +} + +LLUUID LLSettingsSky::getSunTextureId() const +{ + return mSettings[SETTING_SUN_TEXTUREID].asUUID(); +} + +void LLSettingsSky::setSunTextureId(LLUUID id) +{ + setValue(SETTING_SUN_TEXTUREID, id); +} + +LLUUID LLSettingsSky::getNextSunTextureId() const +{ + return mNextSunTextureId; +} + +LLUUID LLSettingsSky::getNextMoonTextureId() const +{ + return mNextMoonTextureId; +} + +LLUUID LLSettingsSky::getNextCloudNoiseTextureId() const +{ + return mNextCloudTextureId; +} + +LLUUID LLSettingsSky::getNextBloomTextureId() const +{ + return mNextBloomTextureId; +} + diff --git a/indra/llinventory/llsettingssky.h b/indra/llinventory/llsettingssky.h new file mode 100644 index 0000000000..cd173a6b18 --- /dev/null +++ b/indra/llinventory/llsettingssky.h @@ -0,0 +1,361 @@ +/** +* @file llsettingssky.h +* @author optional +* @brief A base class for asset based settings groups. +* +* $LicenseInfo:2011&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2017, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#ifndef LL_SETTINGS_SKY_H +#define LL_SETTINGS_SKY_H + +#include "llsettingsbase.h" +#include "v4coloru.h" + +const F32 EARTH_RADIUS = 6.370e6f; +const F32 SUN_RADIUS = 695.508e6f; +const F32 SUN_DIST = 149598.260e6f; +const F32 MOON_RADIUS = 1.737e6f; +const F32 MOON_DIST = 384.400e6f; + +class LLSettingsSky: public LLSettingsBase +{ +public: + static const std::string SETTING_AMBIENT; + static const std::string SETTING_BLOOM_TEXTUREID; + static const std::string SETTING_RAINBOW_TEXTUREID; + static const std::string SETTING_HALO_TEXTUREID; + static const std::string SETTING_BLUE_DENSITY; + static const std::string SETTING_BLUE_HORIZON; + static const std::string SETTING_DENSITY_MULTIPLIER; + static const std::string SETTING_DISTANCE_MULTIPLIER; + static const std::string SETTING_HAZE_DENSITY; + static const std::string SETTING_HAZE_HORIZON; + static const std::string SETTING_CLOUD_COLOR; + static const std::string SETTING_CLOUD_POS_DENSITY1; + static const std::string SETTING_CLOUD_POS_DENSITY2; + static const std::string SETTING_CLOUD_SCALE; + static const std::string SETTING_CLOUD_SCROLL_RATE; + static const std::string SETTING_CLOUD_SHADOW; + static const std::string SETTING_CLOUD_TEXTUREID; + static const std::string SETTING_CLOUD_VARIANCE; + + static const std::string SETTING_DOME_OFFSET; + static const std::string SETTING_DOME_RADIUS; + static const std::string SETTING_GAMMA; + static const std::string SETTING_GLOW; + static const std::string SETTING_LIGHT_NORMAL; + static const std::string SETTING_MAX_Y; + static const std::string SETTING_MOON_ROTATION; + static const std::string SETTING_MOON_SCALE; + static const std::string SETTING_MOON_TEXTUREID; + static const std::string SETTING_MOON_BRIGHTNESS; + + static const std::string SETTING_STAR_BRIGHTNESS; + static const std::string SETTING_SUNLIGHT_COLOR; + static const std::string SETTING_SUN_ROTATION; + static const std::string SETTING_SUN_SCALE; + static const std::string SETTING_SUN_TEXTUREID; + + static const std::string SETTING_PLANET_RADIUS; + static const std::string SETTING_SKY_BOTTOM_RADIUS; + static const std::string SETTING_SKY_TOP_RADIUS; + static const std::string SETTING_SUN_ARC_RADIANS; + static const std::string SETTING_MIE_ANISOTROPY_FACTOR; + + static const std::string SETTING_RAYLEIGH_CONFIG; + static const std::string SETTING_MIE_CONFIG; + static const std::string SETTING_ABSORPTION_CONFIG; + + static const std::string KEY_DENSITY_PROFILE; + static const std::string SETTING_DENSITY_PROFILE_WIDTH; + static const std::string SETTING_DENSITY_PROFILE_EXP_TERM; + static const std::string SETTING_DENSITY_PROFILE_EXP_SCALE_FACTOR; + static const std::string SETTING_DENSITY_PROFILE_LINEAR_TERM; + static const std::string SETTING_DENSITY_PROFILE_CONSTANT_TERM; + + static const std::string SETTING_SKY_MOISTURE_LEVEL; + static const std::string SETTING_SKY_DROPLET_RADIUS; + static const std::string SETTING_SKY_ICE_LEVEL; + + static const std::string SETTING_LEGACY_HAZE; + + static const LLUUID DEFAULT_ASSET_ID; + + typedef PTR_NAMESPACE::shared_ptr ptr_t; + + //--------------------------------------------------------------------- + LLSettingsSky(const LLSD &data); + virtual ~LLSettingsSky() { }; + + virtual ptr_t buildClone() const = 0; + + //--------------------------------------------------------------------- + virtual std::string getSettingsType() const SETTINGS_OVERRIDE { return std::string("sky"); } + virtual LLSettingsType::type_e getSettingsTypeValue() const SETTINGS_OVERRIDE { return LLSettingsType::ST_SKY; } + + // Settings status + virtual void blend(const LLSettingsBase::ptr_t &end, F64 blendf) SETTINGS_OVERRIDE; + + virtual void replaceSettings(LLSD settings) SETTINGS_OVERRIDE; + + void replaceWithSky(LLSettingsSky::ptr_t pother); + static LLSD defaults(const LLSettingsBase::TrackPosition& position = 0.0f); + + F32 getPlanetRadius() const; + F32 getSkyBottomRadius() const; + F32 getSkyTopRadius() const; + F32 getSunArcRadians() const; + F32 getMieAnisotropy() const; + + F32 getSkyMoistureLevel() const; + F32 getSkyDropletRadius() const; + F32 getSkyIceLevel() const; + + // Return first (only) profile layer represented in LLSD + LLSD getRayleighConfig() const; + LLSD getMieConfig() const; + LLSD getAbsorptionConfig() const; + + // Return entire LLSDArray of profile layers represented in LLSD + LLSD getRayleighConfigs() const; + LLSD getMieConfigs() const; + LLSD getAbsorptionConfigs() const; + + LLUUID getBloomTextureId() const; + LLUUID getRainbowTextureId() const; + LLUUID getHaloTextureId() const; + + void setRayleighConfigs(const LLSD& rayleighConfig); + void setMieConfigs(const LLSD& mieConfig); + void setAbsorptionConfigs(const LLSD& absorptionConfig); + + void setPlanetRadius(F32 radius); + void setSkyBottomRadius(F32 radius); + void setSkyTopRadius(F32 radius); + void setSunArcRadians(F32 radians); + void setMieAnisotropy(F32 aniso_factor); + + void setSkyMoistureLevel(F32 moisture_level); + void setSkyDropletRadius(F32 radius); + void setSkyIceLevel(F32 ice_level); + + //--------------------------------------------------------------------- + LLColor3 getAmbientColor() const; + void setAmbientColor(const LLColor3 &val); + + LLColor3 getCloudColor() const; + void setCloudColor(const LLColor3 &val); + + LLUUID getCloudNoiseTextureId() const; + void setCloudNoiseTextureId(const LLUUID &id); + + LLColor3 getCloudPosDensity1() const; + void setCloudPosDensity1(const LLColor3 &val); + + LLColor3 getCloudPosDensity2() const; + void setCloudPosDensity2(const LLColor3 &val); + + F32 getCloudScale() const; + void setCloudScale(F32 val); + + LLVector2 getCloudScrollRate() const; + void setCloudScrollRate(const LLVector2 &val); + + void setCloudScrollRateX(F32 val); + void setCloudScrollRateY(F32 val); + + F32 getCloudShadow() const; + void setCloudShadow(F32 val); + + F32 getCloudVariance() const; + void setCloudVariance(F32 val); + + F32 getDomeOffset() const; + F32 getDomeRadius() const; + + F32 getGamma() const; + + void setGamma(F32 val); + + LLColor3 getGlow() const; + void setGlow(const LLColor3 &val); + + F32 getMaxY() const; + + void setMaxY(F32 val); + + LLQuaternion getMoonRotation() const; + void setMoonRotation(const LLQuaternion &val); + + F32 getMoonScale() const; + void setMoonScale(F32 val); + + LLUUID getMoonTextureId() const; + void setMoonTextureId(LLUUID id); + + F32 getMoonBrightness() const; + void setMoonBrightness(F32 brightness_factor); + + F32 getStarBrightness() const; + void setStarBrightness(F32 val); + + LLColor3 getSunlightColor() const; + void setSunlightColor(const LLColor3 &val); + + LLQuaternion getSunRotation() const; + void setSunRotation(const LLQuaternion &val) ; + + F32 getSunScale() const; + void setSunScale(F32 val); + + LLUUID getSunTextureId() const; + void setSunTextureId(LLUUID id); + + //===================================================================== + // transient properties used in animations. + LLUUID getNextSunTextureId() const; + LLUUID getNextMoonTextureId() const; + LLUUID getNextCloudNoiseTextureId() const; + LLUUID getNextBloomTextureId() const; + + //===================================================================== + virtual void loadTextures() { }; + + //===================================================================== + virtual validation_list_t getValidationList() const SETTINGS_OVERRIDE; + static validation_list_t validationList(); + + static LLSD translateLegacySettings(const LLSD& legacy); + +// LEGACY_ATMOSPHERICS + static LLSD translateLegacyHazeSettings(const LLSD& legacy); + + LLColor3 getLightAttenuation(F32 distance) const; + LLColor3 getLightTransmittance() const; + LLColor3 gammaCorrect(const LLColor3& in) const; + + LLColor3 getBlueDensity() const; + LLColor3 getBlueHorizon() const; + F32 getHazeDensity() const; + F32 getHazeHorizon() const; + F32 getDensityMultiplier() const; + F32 getDistanceMultiplier() const; + + void setBlueDensity(const LLColor3 &val); + void setBlueHorizon(const LLColor3 &val); + void setDensityMultiplier(F32 val); + void setDistanceMultiplier(F32 val); + void setHazeDensity(F32 val); + void setHazeHorizon(F32 val); + +// Internal/calculated settings + bool getIsSunUp() const; + bool getIsMoonUp() const; + + // determines how much the haze glow effect occurs in rendering + F32 getSunMoonGlowFactor() const; + + LLVector3 getLightDirection() const; + LLColor3 getLightDiffuse() const; + + LLVector3 getSunDirection() const; + LLVector3 getMoonDirection() const; + + LLColor4 getMoonAmbient() const; + LLColor3 getMoonDiffuse() const; + LLColor4 getSunAmbient() const; + LLColor3 getSunDiffuse() const; + LLColor4 getTotalAmbient() const; + + virtual LLSettingsBase::ptr_t buildDerivedClone() const SETTINGS_OVERRIDE { return buildClone(); } + + static LLUUID GetDefaultAssetId(); + static LLUUID GetDefaultSunTextureId(); + static LLUUID GetBlankSunTextureId(); + static LLUUID GetDefaultMoonTextureId(); + static LLUUID GetDefaultCloudNoiseTextureId(); + static LLUUID GetDefaultBloomTextureId(); + static LLUUID GetDefaultRainbowTextureId(); + static LLUUID GetDefaultHaloTextureId(); + + static LLSD createDensityProfileLayer( + F32 width, + F32 exponential_term, + F32 exponential_scale_factor, + F32 linear_term, + F32 constant_term, + F32 aniso_factor = 0.0f); + + static LLSD createSingleLayerDensityProfile( + F32 width, + F32 exponential_term, + F32 exponential_scale_factor, + F32 linear_term, + F32 constant_term, + F32 aniso_factor = 0.0f); + + virtual void updateSettings() SETTINGS_OVERRIDE; +protected: + static const std::string SETTING_LEGACY_EAST_ANGLE; + static const std::string SETTING_LEGACY_ENABLE_CLOUD_SCROLL; + static const std::string SETTING_LEGACY_SUN_ANGLE; + + LLSettingsSky(); + + virtual stringset_t getSlerpKeys() const SETTINGS_OVERRIDE; + virtual stringset_t getSkipInterpolateKeys() const SETTINGS_OVERRIDE; + + LLUUID mNextSunTextureId; + LLUUID mNextMoonTextureId; + LLUUID mNextCloudTextureId; + LLUUID mNextBloomTextureId; + LLUUID mNextRainbowTextureId; + LLUUID mNextHaloTextureId; + +private: + static LLSD rayleighConfigDefault(); + static LLSD absorptionConfigDefault(); + static LLSD mieConfigDefault(); + + void calculateHeavenlyBodyPositions() const; + void calculateLightSettings() const; + + mutable LLVector3 mSunDirection; + mutable LLVector3 mMoonDirection; + mutable LLVector3 mLightDirection; + + static const F32 DOME_RADIUS; + static const F32 DOME_OFFSET; + + mutable LLColor4 mMoonAmbient; + mutable LLColor3 mMoonDiffuse; + mutable LLColor4 mSunAmbient; + mutable LLColor3 mSunDiffuse; + mutable LLColor4 mTotalAmbient; + + typedef std::map mapNameToUniformId_t; + + static mapNameToUniformId_t sNameToUniformMapping; +}; + +#endif diff --git a/indra/llinventory/llsettingswater.cpp b/indra/llinventory/llsettingswater.cpp new file mode 100644 index 0000000000..4af1a5dc08 --- /dev/null +++ b/indra/llinventory/llsettingswater.cpp @@ -0,0 +1,303 @@ +/** +* @file llsettingswater.h +* @author optional +* @brief A base class for asset based settings groups. +* +* $LicenseInfo:2011&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2017, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#include "llsettingswater.h" +#include +#include +#include "llfasttimer.h" +#include "v3colorutil.h" +#include "imageids.h" + +//========================================================================= +namespace +{ + LLTrace::BlockTimerStatHandle FTM_BLEND_WATERVALUES("Blending Water Environment"); + LLTrace::BlockTimerStatHandle FTM_UPDATE_WATERVALUES("Update Water Environment"); +} + +//========================================================================= +const std::string LLSettingsWater::SETTING_BLUR_MULTIPLIER("blur_multiplier"); +const std::string LLSettingsWater::SETTING_FOG_COLOR("water_fog_color"); +const std::string LLSettingsWater::SETTING_FOG_DENSITY("water_fog_density"); +const std::string LLSettingsWater::SETTING_FOG_MOD("underwater_fog_mod"); +const std::string LLSettingsWater::SETTING_FRESNEL_OFFSET("fresnel_offset"); +const std::string LLSettingsWater::SETTING_FRESNEL_SCALE("fresnel_scale"); +const std::string LLSettingsWater::SETTING_TRANSPARENT_TEXTURE("transparent_texture"); +const std::string LLSettingsWater::SETTING_NORMAL_MAP("normal_map"); +const std::string LLSettingsWater::SETTING_NORMAL_SCALE("normal_scale"); +const std::string LLSettingsWater::SETTING_SCALE_ABOVE("scale_above"); +const std::string LLSettingsWater::SETTING_SCALE_BELOW("scale_below"); +const std::string LLSettingsWater::SETTING_WAVE1_DIR("wave1_direction"); +const std::string LLSettingsWater::SETTING_WAVE2_DIR("wave2_direction"); + +const std::string LLSettingsWater::SETTING_LEGACY_BLUR_MULTIPLIER("blurMultiplier"); +const std::string LLSettingsWater::SETTING_LEGACY_FOG_COLOR("waterFogColor"); +const std::string LLSettingsWater::SETTING_LEGACY_FOG_DENSITY("waterFogDensity"); +const std::string LLSettingsWater::SETTING_LEGACY_FOG_MOD("underWaterFogMod"); +const std::string LLSettingsWater::SETTING_LEGACY_FRESNEL_OFFSET("fresnelOffset"); +const std::string LLSettingsWater::SETTING_LEGACY_FRESNEL_SCALE("fresnelScale"); +const std::string LLSettingsWater::SETTING_LEGACY_NORMAL_MAP("normalMap"); +const std::string LLSettingsWater::SETTING_LEGACY_NORMAL_SCALE("normScale"); +const std::string LLSettingsWater::SETTING_LEGACY_SCALE_ABOVE("scaleAbove"); +const std::string LLSettingsWater::SETTING_LEGACY_SCALE_BELOW("scaleBelow"); +const std::string LLSettingsWater::SETTING_LEGACY_WAVE1_DIR("wave1Dir"); +const std::string LLSettingsWater::SETTING_LEGACY_WAVE2_DIR("wave2Dir"); + +const LLUUID LLSettingsWater::DEFAULT_ASSET_ID("59d1a851-47e7-0e5f-1ed7-6b715154f41a"); + +static const LLUUID DEFAULT_TRANSPARENT_WATER_TEXTURE("2bfd3884-7e27-69b9-ba3a-3e673f680004"); +static const LLUUID DEFAULT_OPAQUE_WATER_TEXTURE("43c32285-d658-1793-c123-bf86315de055"); + +//========================================================================= +LLSettingsWater::LLSettingsWater(const LLSD &data) : + LLSettingsBase(data), + mNextNormalMapID() +{ +} + +LLSettingsWater::LLSettingsWater() : + LLSettingsBase(), + mNextNormalMapID() +{ +} + +//========================================================================= +LLSD LLSettingsWater::defaults(const LLSettingsBase::TrackPosition& position) +{ + static LLSD dfltsetting; + + if (dfltsetting.size() == 0) + { + // give the normal scale offset some variability over track time... + F32 normal_scale_offset = (position * 0.5f) - 0.25f; + + // Magic constants copied form defaults.xml + dfltsetting[SETTING_BLUR_MULTIPLIER] = LLSD::Real(0.04000f); + dfltsetting[SETTING_FOG_COLOR] = LLColor3(0.0156f, 0.1490f, 0.2509f).getValue(); + dfltsetting[SETTING_FOG_DENSITY] = LLSD::Real(2.0f); + dfltsetting[SETTING_FOG_MOD] = LLSD::Real(0.25f); + dfltsetting[SETTING_FRESNEL_OFFSET] = LLSD::Real(0.5f); + dfltsetting[SETTING_FRESNEL_SCALE] = LLSD::Real(0.3999); + dfltsetting[SETTING_TRANSPARENT_TEXTURE] = GetDefaultTransparentTextureAssetId(); + dfltsetting[SETTING_NORMAL_MAP] = GetDefaultWaterNormalAssetId(); + dfltsetting[SETTING_NORMAL_SCALE] = LLVector3(2.0f + normal_scale_offset, 2.0f + normal_scale_offset, 2.0f + normal_scale_offset).getValue(); + dfltsetting[SETTING_SCALE_ABOVE] = LLSD::Real(0.0299f); + dfltsetting[SETTING_SCALE_BELOW] = LLSD::Real(0.2000f); + dfltsetting[SETTING_WAVE1_DIR] = LLVector2(1.04999f, -0.42000f).getValue(); + dfltsetting[SETTING_WAVE2_DIR] = LLVector2(1.10999f, -1.16000f).getValue(); + + dfltsetting[SETTING_TYPE] = "water"; + } + + return dfltsetting; +} + +LLSD LLSettingsWater::translateLegacySettings(LLSD legacy) +{ + bool converted_something(false); + LLSD newsettings(defaults()); + + if (legacy.has(SETTING_LEGACY_BLUR_MULTIPLIER)) + { + newsettings[SETTING_BLUR_MULTIPLIER] = LLSD::Real(legacy[SETTING_LEGACY_BLUR_MULTIPLIER].asReal()); + converted_something |= true; + } + if (legacy.has(SETTING_LEGACY_FOG_COLOR)) + { + newsettings[SETTING_FOG_COLOR] = LLColor3(legacy[SETTING_LEGACY_FOG_COLOR]).getValue(); + converted_something |= true; + } + if (legacy.has(SETTING_LEGACY_FOG_DENSITY)) + { + newsettings[SETTING_FOG_DENSITY] = LLSD::Real(legacy[SETTING_LEGACY_FOG_DENSITY]); + converted_something |= true; + } + if (legacy.has(SETTING_LEGACY_FOG_MOD)) + { + newsettings[SETTING_FOG_MOD] = LLSD::Real(legacy[SETTING_LEGACY_FOG_MOD].asReal()); + converted_something |= true; + } + if (legacy.has(SETTING_LEGACY_FRESNEL_OFFSET)) + { + newsettings[SETTING_FRESNEL_OFFSET] = LLSD::Real(legacy[SETTING_LEGACY_FRESNEL_OFFSET].asReal()); + converted_something |= true; + } + if (legacy.has(SETTING_LEGACY_FRESNEL_SCALE)) + { + newsettings[SETTING_FRESNEL_SCALE] = LLSD::Real(legacy[SETTING_LEGACY_FRESNEL_SCALE].asReal()); + converted_something |= true; + } + if (legacy.has(SETTING_LEGACY_NORMAL_MAP)) + { + newsettings[SETTING_NORMAL_MAP] = LLSD::UUID(legacy[SETTING_LEGACY_NORMAL_MAP].asUUID()); + converted_something |= true; + } + if (legacy.has(SETTING_LEGACY_NORMAL_SCALE)) + { + newsettings[SETTING_NORMAL_SCALE] = LLVector3(legacy[SETTING_LEGACY_NORMAL_SCALE]).getValue(); + converted_something |= true; + } + if (legacy.has(SETTING_LEGACY_SCALE_ABOVE)) + { + newsettings[SETTING_SCALE_ABOVE] = LLSD::Real(legacy[SETTING_LEGACY_SCALE_ABOVE].asReal()); + converted_something |= true; + } + if (legacy.has(SETTING_LEGACY_SCALE_BELOW)) + { + newsettings[SETTING_SCALE_BELOW] = LLSD::Real(legacy[SETTING_LEGACY_SCALE_BELOW].asReal()); + converted_something |= true; + } + if (legacy.has(SETTING_LEGACY_WAVE1_DIR)) + { + newsettings[SETTING_WAVE1_DIR] = LLVector2(legacy[SETTING_LEGACY_WAVE1_DIR]).getValue(); + converted_something |= true; + } + if (legacy.has(SETTING_LEGACY_WAVE2_DIR)) + { + newsettings[SETTING_WAVE2_DIR] = LLVector2(legacy[SETTING_LEGACY_WAVE2_DIR]).getValue(); + converted_something |= true; + } + + if (!converted_something) + return LLSD(); + return newsettings; +} + +void LLSettingsWater::blend(const LLSettingsBase::ptr_t &end, F64 blendf) +{ + LLSettingsWater::ptr_t other = PTR_NAMESPACE::static_pointer_cast(end); + if (other) + { + LLSD blenddata = interpolateSDMap(mSettings, other->mSettings, other->getParameterMap(), blendf); + replaceSettings(blenddata); + mNextNormalMapID = other->getNormalMapID(); + mNextTransparentTextureID = other->getTransparentTextureID(); + } + else + { + LL_WARNS("SETTINGS") << "Could not cast end settings to water. No blend performed." << LL_ENDL; + } + setBlendFactor(blendf); +} + +void LLSettingsWater::replaceSettings(LLSD settings) +{ + LLSettingsBase::replaceSettings(settings); + mNextNormalMapID.setNull(); + mNextTransparentTextureID.setNull(); +} + +void LLSettingsWater::replaceWithWater(LLSettingsWater::ptr_t other) +{ + replaceWith(other); + + mNextNormalMapID = other->mNextNormalMapID; + mNextTransparentTextureID = other->mNextTransparentTextureID; +} + +LLSettingsWater::validation_list_t LLSettingsWater::getValidationList() const +{ + return LLSettingsWater::validationList(); +} + +LLSettingsWater::validation_list_t LLSettingsWater::validationList() +{ + static validation_list_t validation; + + if (validation.empty()) + { // Note the use of LLSD(LLSDArray()()()...) This is due to an issue with the + // copy constructor for LLSDArray. Directly binding the LLSDArray as + // a parameter without first wrapping it in a pure LLSD object will result + // in deeply nested arrays like this [[[[[[[[[[v1,v2,v3]]]]]]]]]] + + validation.push_back(Validator(SETTING_BLUR_MULTIPLIER, true, LLSD::TypeReal, + boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(-0.5f)(0.5f))))); + validation.push_back(Validator(SETTING_FOG_COLOR, true, LLSD::TypeArray, + boost::bind(&Validator::verifyVectorMinMax, _1, + LLSD(LLSDArray(0.0f)(0.0f)(0.0f)(1.0f)), + LLSD(LLSDArray(1.0f)(1.0f)(1.0f)(1.0f))))); + validation.push_back(Validator(SETTING_FOG_DENSITY, true, LLSD::TypeReal, + boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(-10.0f)(10.0f))))); + validation.push_back(Validator(SETTING_FOG_MOD, true, LLSD::TypeReal, + boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(20.0f))))); + validation.push_back(Validator(SETTING_FRESNEL_OFFSET, true, LLSD::TypeReal, + boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f))))); + validation.push_back(Validator(SETTING_FRESNEL_SCALE, true, LLSD::TypeReal, + boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(1.0f))))); + validation.push_back(Validator(SETTING_NORMAL_MAP, true, LLSD::TypeUUID)); + validation.push_back(Validator(SETTING_NORMAL_SCALE, true, LLSD::TypeArray, + boost::bind(&Validator::verifyVectorMinMax, _1, + LLSD(LLSDArray(0.0f)(0.0f)(0.0f)), + LLSD(LLSDArray(10.0f)(10.0f)(10.0f))))); + validation.push_back(Validator(SETTING_SCALE_ABOVE, true, LLSD::TypeReal, + boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(3.0f))))); + validation.push_back(Validator(SETTING_SCALE_BELOW, true, LLSD::TypeReal, + boost::bind(&Validator::verifyFloatRange, _1, LLSD(LLSDArray(0.0f)(3.0f))))); + validation.push_back(Validator(SETTING_WAVE1_DIR, true, LLSD::TypeArray, + boost::bind(&Validator::verifyVectorMinMax, _1, + LLSD(LLSDArray(-20.0f)(-20.0f)), + LLSD(LLSDArray(20.0f)(20.0f))))); + validation.push_back(Validator(SETTING_WAVE2_DIR, true, LLSD::TypeArray, + boost::bind(&Validator::verifyVectorMinMax, _1, + LLSD(LLSDArray(-20.0f)(-20.0f)), + LLSD(LLSDArray(20.0f)(20.0f))))); + } + + return validation; +} + +LLUUID LLSettingsWater::GetDefaultAssetId() +{ + return DEFAULT_ASSET_ID; +} + +LLUUID LLSettingsWater::GetDefaultWaterNormalAssetId() +{ + return DEFAULT_WATER_NORMAL; +} + +LLUUID LLSettingsWater::GetDefaultTransparentTextureAssetId() +{ + return DEFAULT_TRANSPARENT_WATER_TEXTURE; +} + +LLUUID LLSettingsWater::GetDefaultOpaqueTextureAssetId() +{ + return DEFAULT_OPAQUE_WATER_TEXTURE; +} + +F32 LLSettingsWater::getModifiedWaterFogDensity(bool underwater) const +{ + F32 fog_density = getWaterFogDensity(); + F32 underwater_fog_mod = getFogMod(); + if (underwater && underwater_fog_mod > 0.0f) + { + underwater_fog_mod = llclamp(underwater_fog_mod, 0.0f, 10.0f); + fog_density = pow(fog_density, underwater_fog_mod); + } + return fog_density; +} diff --git a/indra/llinventory/llsettingswater.h b/indra/llinventory/llsettingswater.h new file mode 100644 index 0000000000..e0bfd29f2d --- /dev/null +++ b/indra/llinventory/llsettingswater.h @@ -0,0 +1,249 @@ +/** +* @file llsettingssky.h +* @author optional +* @brief A base class for asset based settings groups. +* +* $LicenseInfo:2011&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2017, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#ifndef LL_SETTINGS_WATER_H +#define LL_SETTINGS_WATER_H + +#include "llsettingsbase.h" + +class LLSettingsWater : public LLSettingsBase +{ +public: + static const std::string SETTING_BLUR_MULTIPLIER; + static const std::string SETTING_FOG_COLOR; + static const std::string SETTING_FOG_DENSITY; + static const std::string SETTING_FOG_MOD; + static const std::string SETTING_FRESNEL_OFFSET; + static const std::string SETTING_FRESNEL_SCALE; + static const std::string SETTING_TRANSPARENT_TEXTURE; + static const std::string SETTING_NORMAL_MAP; + static const std::string SETTING_NORMAL_SCALE; + static const std::string SETTING_SCALE_ABOVE; + static const std::string SETTING_SCALE_BELOW; + static const std::string SETTING_WAVE1_DIR; + static const std::string SETTING_WAVE2_DIR; + + static const LLUUID DEFAULT_ASSET_ID; + + typedef PTR_NAMESPACE::shared_ptr ptr_t; + + //--------------------------------------------------------------------- + LLSettingsWater(const LLSD &data); + virtual ~LLSettingsWater() { }; + + virtual ptr_t buildClone() const = 0; + + //--------------------------------------------------------------------- + virtual std::string getSettingsType() const SETTINGS_OVERRIDE { return std::string("water"); } + virtual LLSettingsType::type_e getSettingsTypeValue() const SETTINGS_OVERRIDE { return LLSettingsType::ST_WATER; } + + // Settings status + virtual void blend(const LLSettingsBase::ptr_t &end, F64 blendf) SETTINGS_OVERRIDE; + + virtual void replaceSettings(LLSD settings) SETTINGS_OVERRIDE; + void replaceWithWater(LLSettingsWater::ptr_t other); + + static LLSD defaults(const LLSettingsBase::TrackPosition& position = 0.0f); + + //--------------------------------------------------------------------- + F32 getBlurMultiplier() const + { + return mSettings[SETTING_BLUR_MULTIPLIER].asReal(); + } + + void setBlurMultiplier(F32 val) + { + setValue(SETTING_BLUR_MULTIPLIER, val); + } + + LLColor3 getWaterFogColor() const + { + return LLColor3(mSettings[SETTING_FOG_COLOR]); + } + + void setWaterFogColor(LLColor3 val) + { + setValue(SETTING_FOG_COLOR, val); + } + + F32 getWaterFogDensity() const + { + return mSettings[SETTING_FOG_DENSITY].asReal(); + } + + F32 getModifiedWaterFogDensity(bool underwater) const; + + void setWaterFogDensity(F32 val) + { + setValue(SETTING_FOG_DENSITY, val); + } + + F32 getFogMod() const + { + return mSettings[SETTING_FOG_MOD].asReal(); + } + + void setFogMod(F32 val) + { + setValue(SETTING_FOG_MOD, val); + } + + F32 getFresnelOffset() const + { + return mSettings[SETTING_FRESNEL_OFFSET].asReal(); + } + + void setFresnelOffset(F32 val) + { + setValue(SETTING_FRESNEL_OFFSET, val); + } + + F32 getFresnelScale() const + { + return mSettings[SETTING_FRESNEL_SCALE].asReal(); + } + + void setFresnelScale(F32 val) + { + setValue(SETTING_FRESNEL_SCALE, val); + } + + LLUUID getTransparentTextureID() const + { + return mSettings[SETTING_TRANSPARENT_TEXTURE].asUUID(); + } + + void setTransparentTextureID(LLUUID val) + { + setValue(SETTING_TRANSPARENT_TEXTURE, val); + } + + LLUUID getNormalMapID() const + { + return mSettings[SETTING_NORMAL_MAP].asUUID(); + } + + void setNormalMapID(LLUUID val) + { + setValue(SETTING_NORMAL_MAP, val); + } + + LLVector3 getNormalScale() const + { + return LLVector3(mSettings[SETTING_NORMAL_SCALE]); + } + + void setNormalScale(LLVector3 val) + { + setValue(SETTING_NORMAL_SCALE, val); + } + + F32 getScaleAbove() const + { + return mSettings[SETTING_SCALE_ABOVE].asReal(); + } + + void setScaleAbove(F32 val) + { + setValue(SETTING_SCALE_ABOVE, val); + } + + F32 getScaleBelow() const + { + return mSettings[SETTING_SCALE_BELOW].asReal(); + } + + void setScaleBelow(F32 val) + { + setValue(SETTING_SCALE_BELOW, val); + } + + LLVector2 getWave1Dir() const + { + return LLVector2(mSettings[SETTING_WAVE1_DIR]); + } + + void setWave1Dir(LLVector2 val) + { + setValue(SETTING_WAVE1_DIR, val); + } + + LLVector2 getWave2Dir() const + { + return LLVector2(mSettings[SETTING_WAVE2_DIR]); + } + + void setWave2Dir(LLVector2 val) + { + setValue(SETTING_WAVE2_DIR, val); + } + + //------------------------------------------- + LLUUID getNextNormalMapID() const + { + return mNextNormalMapID; + } + + LLUUID getNextTransparentTextureID() const + { + return mNextTransparentTextureID; + } + + virtual validation_list_t getValidationList() const SETTINGS_OVERRIDE; + static validation_list_t validationList(); + + static LLSD translateLegacySettings(LLSD legacy); + + virtual LLSettingsBase::ptr_t buildDerivedClone() const SETTINGS_OVERRIDE { return buildClone(); } + + static LLUUID GetDefaultAssetId(); + static LLUUID GetDefaultWaterNormalAssetId(); + static LLUUID GetDefaultTransparentTextureAssetId(); + static LLUUID GetDefaultOpaqueTextureAssetId(); + +protected: + static const std::string SETTING_LEGACY_BLUR_MULTIPLIER; + static const std::string SETTING_LEGACY_FOG_COLOR; + static const std::string SETTING_LEGACY_FOG_DENSITY; + static const std::string SETTING_LEGACY_FOG_MOD; + static const std::string SETTING_LEGACY_FRESNEL_OFFSET; + static const std::string SETTING_LEGACY_FRESNEL_SCALE; + static const std::string SETTING_LEGACY_NORMAL_MAP; + static const std::string SETTING_LEGACY_NORMAL_SCALE; + static const std::string SETTING_LEGACY_SCALE_ABOVE; + static const std::string SETTING_LEGACY_SCALE_BELOW; + static const std::string SETTING_LEGACY_WAVE1_DIR; + static const std::string SETTING_LEGACY_WAVE2_DIR; + + LLSettingsWater(); + + LLUUID mNextTransparentTextureID; + LLUUID mNextNormalMapID; + +}; + +#endif diff --git a/indra/llinventory/lltransactionflags.cpp b/indra/llinventory/lltransactionflags.cpp index 084107c83e..c03945b0ae 100644 --- a/indra/llinventory/lltransactionflags.cpp +++ b/indra/llinventory/lltransactionflags.cpp @@ -94,11 +94,11 @@ std::string build_transfer_message_to_source( S32 transaction_type, const std::string& description) { - lldebugs << "build_transfer_message_to_source: " << amount << " " + LL_DEBUGS() << "build_transfer_message_to_source: " << amount << " " << source_id << " " << dest_id << " " << dest_name << " " << transaction_type << " " << (description.empty() ? "(no desc)" : description) - << llendl; + << LL_ENDL; if(source_id.isNull()) { return description; @@ -143,10 +143,10 @@ std::string build_transfer_message_to_destination( S32 transaction_type, const std::string& description) { - lldebugs << "build_transfer_message_to_dest: " << amount << " " + LL_DEBUGS() << "build_transfer_message_to_dest: " << amount << " " << dest_id << " " << source_id << " " << source_name << " " << transaction_type << " " << (description.empty() ? "(no desc)" : description) - << llendl; + << LL_ENDL; if(0 == amount) { return std::string(); diff --git a/indra/llmath/CMakeLists.txt b/indra/llmath/CMakeLists.txt index 1c43bb2183..e91d08a11c 100644 --- a/indra/llmath/CMakeLists.txt +++ b/indra/llmath/CMakeLists.txt @@ -13,20 +13,23 @@ set(llmath_SOURCE_FILES llbbox.cpp llbboxlocal.cpp llcalc.cpp + llcalcparser.cpp llcamera.cpp llcoordframe.cpp llline.cpp llmatrix3a.cpp + llmatrix4a.cpp llmodularmath.cpp llperlin.cpp llquaternion.cpp + llrigginginfo.cpp llrect.cpp - llsdutil_math.cpp llsphere.cpp llvector4a.cpp llvolume.cpp llvolumemgr.cpp llvolumeoctree.cpp + llsdutil_math.cpp m3math.cpp m4math.cpp raytrace.cpp @@ -66,7 +69,7 @@ set(llmath_HEADER_FILES llquaternion2.h llquaternion2.inl llrect.h - llsdutil_math.h + llrigginginfo.h llsimdmath.h llsimdtypes.h llsimdtypes.inl @@ -78,11 +81,13 @@ set(llmath_HEADER_FILES llvolume.h llvolumemgr.h llvolumeoctree.h + llsdutil_math.h m3math.h m4math.h raytrace.h v2math.h v3color.h + v3colorutil.h v3dmath.h v3math.h v4color.h @@ -97,4 +102,9 @@ set_source_files_properties(${llmath_HEADER_FILES} list(APPEND llmath_SOURCE_FILES ${llmath_HEADER_FILES}) add_library (llmath ${llmath_SOURCE_FILES}) -add_dependencies(llmath prepare) + +target_link_libraries( + llmath + PUBLIC + llcommon + ) diff --git a/indra/llmath/camera.h b/indra/llmath/camera.h index ce41f8781d..c8fa4c3af5 100644 --- a/indra/llmath/camera.h +++ b/indra/llmath/camera.h @@ -2,31 +2,25 @@ * @file camera.h * @brief Legacy wrapper header. * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llmath/coordframe.h b/indra/llmath/coordframe.h index b8a1c14abf..d078e4a734 100644 --- a/indra/llmath/coordframe.h +++ b/indra/llmath/coordframe.h @@ -2,31 +2,25 @@ * @file coordframe.h * @brief Legacy wrapper header. * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llmath/llbbox.cpp b/indra/llmath/llbbox.cpp index 0aea7190b8..9fd21514c9 100644 --- a/indra/llmath/llbbox.cpp +++ b/indra/llmath/llbbox.cpp @@ -2,36 +2,28 @@ * @file llbbox.cpp * @brief General purpose bounding box class (Not axis aligned) * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2010, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlife.com/developers/opensource/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ - * */ - #include "linden_common.h" // self include diff --git a/indra/llmath/llbbox.h b/indra/llmath/llbbox.h index 685704ccf8..ede5e3142b 100644 --- a/indra/llmath/llbbox.h +++ b/indra/llmath/llbbox.h @@ -2,36 +2,28 @@ * @file llbbox.h * @brief General purpose bounding box class * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2010, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlife.com/developers/opensource/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ - * */ - #ifndef LL_BBOX_H #define LL_BBOX_H diff --git a/indra/llmath/llbboxlocal.cpp b/indra/llmath/llbboxlocal.cpp index 3d0dbb0762..2582003b3f 100644 --- a/indra/llmath/llbboxlocal.cpp +++ b/indra/llmath/llbboxlocal.cpp @@ -2,31 +2,25 @@ * @file llbboxlocal.cpp * @brief General purpose bounding box class (Not axis aligned). * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llmath/llbboxlocal.h b/indra/llmath/llbboxlocal.h index 0d1e5a3ae5..6ad2a2785b 100644 --- a/indra/llmath/llbboxlocal.h +++ b/indra/llmath/llbboxlocal.h @@ -2,31 +2,25 @@ * @file llbboxlocal.h * @brief General purpose bounding box class. * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llmath/llcalc.cpp b/indra/llmath/llcalc.cpp index 331e363e76..edc6986cc9 100644 --- a/indra/llmath/llcalc.cpp +++ b/indra/llmath/llcalc.cpp @@ -28,61 +28,59 @@ #include "llcalc.h" +#include "llcalcparser.h" #include "llmath.h" -#include "llcalcparser.h" // Variable names for use in the build floater -// must be lower case for parser definition -// case-insensitive for actual parsing -const char* LLCalc::X_POS = "px"; -const char* LLCalc::Y_POS = "py"; -const char* LLCalc::Z_POS = "pz"; -const char* LLCalc::X_SCALE = "sx"; -const char* LLCalc::Y_SCALE = "sy"; -const char* LLCalc::Z_SCALE = "sz"; -const char* LLCalc::X_ROT = "rx"; -const char* LLCalc::Y_ROT = "ry"; -const char* LLCalc::Z_ROT = "rz"; -const char* LLCalc::HOLLOW = "hlw"; -const char* LLCalc::CUT_BEGIN = "cb"; -const char* LLCalc::CUT_END = "ce"; -const char* LLCalc::PATH_BEGIN = "pb"; -const char* LLCalc::PATH_END = "pe"; -const char* LLCalc::TWIST_BEGIN = "tb"; -const char* LLCalc::TWIST_END = "te"; -const char* LLCalc::X_SHEAR = "shx"; -const char* LLCalc::Y_SHEAR = "shy"; -const char* LLCalc::X_TAPER = "tpx"; -const char* LLCalc::Y_TAPER = "tpy"; -const char* LLCalc::RADIUS_OFFSET = "rof"; -const char* LLCalc::REVOLUTIONS = "rev"; -const char* LLCalc::SKEW = "skw"; -const char* LLCalc::X_HOLE = "hlx"; -const char* LLCalc::Y_HOLE = "hly"; -const char* LLCalc::TEX_U_SCALE = "tsu"; -const char* LLCalc::TEX_V_SCALE = "tsv"; -const char* LLCalc::TEX_U_OFFSET = "tou"; -const char* LLCalc::TEX_V_OFFSET = "tov"; -const char* LLCalc::TEX_ROTATION = "trot"; -const char* LLCalc::TEX_TRANSPARENCY = "trns"; -const char* LLCalc::TEX_GLOW = "glow"; +const char* LLCalc::X_POS = "PX"; +const char* LLCalc::Y_POS = "PY"; +const char* LLCalc::Z_POS = "PZ"; +const char* LLCalc::X_SCALE = "SX"; +const char* LLCalc::Y_SCALE = "SY"; +const char* LLCalc::Z_SCALE = "SZ"; +const char* LLCalc::X_ROT = "RX"; +const char* LLCalc::Y_ROT = "RY"; +const char* LLCalc::Z_ROT = "RZ"; +const char* LLCalc::HOLLOW = "HLW"; +const char* LLCalc::CUT_BEGIN = "CB"; +const char* LLCalc::CUT_END = "CE"; +const char* LLCalc::PATH_BEGIN = "PB"; +const char* LLCalc::PATH_END = "PE"; +const char* LLCalc::TWIST_BEGIN = "TB"; +const char* LLCalc::TWIST_END = "TE"; +const char* LLCalc::X_SHEAR = "SHX"; +const char* LLCalc::Y_SHEAR = "SHY"; +const char* LLCalc::X_TAPER = "TPX"; +const char* LLCalc::Y_TAPER = "TPY"; +const char* LLCalc::RADIUS_OFFSET = "ROF"; +const char* LLCalc::REVOLUTIONS = "REV"; +const char* LLCalc::SKEW = "SKW"; +const char* LLCalc::X_HOLE = "HLX"; +const char* LLCalc::Y_HOLE = "HLY"; +const char* LLCalc::TEX_U_SCALE = "TSU"; +const char* LLCalc::TEX_V_SCALE = "TSV"; +const char* LLCalc::TEX_U_OFFSET = "TOU"; +const char* LLCalc::TEX_V_OFFSET = "TOV"; +const char* LLCalc::TEX_ROTATION = "TROT"; +const char* LLCalc::TEX_TRANSPARENCY = "TRNS"; +const char* LLCalc::TEX_GLOW = "GLOW"; + LLCalc* LLCalc::sInstance = NULL; -//TODO: Make this a static global class LLCalc::LLCalc() : mLastErrorPos(0) { // Init table of constants - /*setVar("PI", F_PI); - setVar("TWO_PI", F_TWO_PI); - setVar("PI_BY_TWO", F_PI_BY_TWO); - setVar("SQRT_TWO_PI", F_SQRT_TWO_PI); - setVar("SQRT2", F_SQRT2); - setVar("SQRT3", F_SQRT3); - setVar("DEG_TO_RAD", DEG_TO_RAD); - setVar("RAD_TO_DEG", RAD_TO_DEG); - setVar("GRAVITY", GRAVITY);*/ + mConstants["PI"] = F_PI; + mConstants["TWO_PI"] = F_TWO_PI; + mConstants["PI_BY_TWO"] = F_PI_BY_TWO; + mConstants["SQRT_TWO_PI"] = F_SQRT_TWO_PI; + mConstants["SQRT2"] = F_SQRT2; + mConstants["SQRT3"] = F_SQRT3; + mConstants["DEG_TO_RAD"] = DEG_TO_RAD; + mConstants["RAD_TO_DEG"] = RAD_TO_DEG; + mConstants["GRAVITY"] = GRAVITY; } LLCalc::~LLCalc() @@ -99,7 +97,7 @@ void LLCalc::cleanUp() //static LLCalc* LLCalc::getInstance() { - if (!sInstance) sInstance = new LLCalc(); + if (!sInstance) sInstance = new LLCalc(); return sInstance; } @@ -118,35 +116,47 @@ void LLCalc::clearAllVariables() mVariables.clear(); } +/* +void LLCalc::updateVariables(LLSD& vars) +{ + LLSD::map_iterator cIt = vars.beginMap(); + for(; cIt != vars.endMap(); cIt++) + { + setVar(cIt->first, (F32)(LLSD::Real)cIt->second); + } +} +*/ + bool LLCalc::evalString(const std::string& expression, F32& result) { + std::string expr_upper = expression; + LLStringUtil::toUpper(expr_upper); + + LLCalcParser calc(result, &mConstants, &mVariables); + mLastErrorPos = 0; - std::string::const_iterator itr = expression.begin(); - expression::grammar calc; - calc.constant.add - ("pi", F_PI) - ("two_pi", F_TWO_PI) - ("pi_by_two", F_PI_BY_TWO) - ("sqrt_two_pi", F_SQRT_TWO_PI) - ("sqrt2", F_SQRT2) - ("sqrt3", F_SQRT3) - ("deg_to_rad", DEG_TO_RAD) - ("rad_to_deg", RAD_TO_DEG) - ("gravity", GRAVITY) - ; - for(calc_map_t::const_iterator iter = mVariables.begin(); - iter != mVariables.end(); - ++iter) + std::string::iterator start = expr_upper.begin(); + parse_info info; + + try { - calc.constant.add(iter->first, iter->second); + info = parse(start, expr_upper.end(), calc, space_p); + LL_DEBUGS() << "Math expression: " << expression << " = " << result << LL_ENDL; } - - if (!expression::parse(itr, expression.end(), calc, result) || itr != expression.end()) + catch(parser_error &e) + { + mLastErrorPos = e.where - expr_upper.begin(); + + LL_INFOS() << "Calc parser exception: " << e.descriptor << " at " << mLastErrorPos << " in expression: " << expression << LL_ENDL; + return false; + } + + if (!info.full) { - mLastErrorPos = itr - expression.begin(); - llinfos << "Unhandled syntax error at " << mLastErrorPos << " in expression: " << expression << llendl; + mLastErrorPos = info.stop - expr_upper.begin(); + LL_INFOS() << "Unhandled syntax error at " << mLastErrorPos << " in expression: " << expression << LL_ENDL; return false; } - lldebugs << "Math expression: " << expression << " = " << result << llendl; + return true; } diff --git a/indra/llmath/llcalc.h b/indra/llmath/llcalc.h index 8c71569f43..7f4c6e3178 100644 --- a/indra/llmath/llcalc.h +++ b/indra/llmath/llcalc.h @@ -86,6 +86,7 @@ class LLCalc private: std::string::size_type mLastErrorPos; + calc_map_t mConstants; calc_map_t mVariables; // "There shall be only one" diff --git a/indra/llmath/llcalcparser.cpp b/indra/llmath/llcalcparser.cpp new file mode 100644 index 0000000000..b4ca320659 --- /dev/null +++ b/indra/llmath/llcalcparser.cpp @@ -0,0 +1,63 @@ +/* + * LLCalcParser.cpp + * Copyright 2008 Aimee Walton. + * $LicenseInfo:firstyear=2008&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2008, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + * + */ + +#include "linden_common.h" + +#include "llcalcparser.h" +using namespace boost::spirit::classic; + +F32 LLCalcParser::lookup(const std::string::iterator& start, const std::string::iterator& end) const +{ + LLCalc::calc_map_t::iterator iter; + + std::string name(start, end); + + if (mConstants) + { + iter = mConstants->find(name); + if (iter != mConstants->end()) + { + return (*iter).second; + } + } + else + { + // This should never happen! + throw_(end, std::string("Missing constants table")); + } + + if (mVariables) + { + iter = mVariables->find(name); + if (iter != mVariables->end()) + { + return (*iter).second; + } + } + + throw_(end, std::string("Unknown symbol " + name)); + return 0.f; +} diff --git a/indra/llmath/llcalcparser.h b/indra/llmath/llcalcparser.h index e3eb2bdedc..05e7491fca 100644 --- a/indra/llmath/llcalcparser.h +++ b/indra/llmath/llcalcparser.h @@ -27,207 +27,162 @@ #ifndef LL_CALCPARSER_H #define LL_CALCPARSER_H -#include -#if !defined(SPIRIT_VERSION) || SPIRIT_VERSION < 0x2010 -#error "At least Spirit version 2.1 required" -#endif +#include +#include +#include +#include +#include +#include +using namespace boost::spirit::classic; -// Add this in if we want boost math constants. -//#include -#include -#include +#include "llcalc.h" +#include "llmath.h" -namespace expression { - - -//TODO: If we can find a better way to do this with boost::pheonix::bind lets do it -//namespace { // anonymous - -template -T min_glue(T a, T b) -{ - return std::min(a, b); -} - -template -T max_glue(T a, T b) +struct LLCalcParser : grammar { - return std::max(a, b); -} - -struct lazy_pow_ -{ - template - struct result { typedef X type; }; - - template - X operator()(X x, Y y) const + LLCalcParser(F32& result, LLCalc::calc_map_t* constants, LLCalc::calc_map_t* vars) : + mResult(result), mConstants(constants), mVariables(vars) {}; + + struct value_closure : closure { - return std::pow(x, y); - } -}; - -struct lazy_ufunc_ -{ - template - struct result { typedef A1 type; }; - - template - A1 operator()(F f, A1 a1) const - { - return f(a1); - } -}; - -struct lazy_bfunc_ -{ - template - struct result { typedef A1 type; }; - - template - A1 operator()(F f, A1 a1, A2 a2) const - { - return f(a1, a2); - } -}; - -//} // end namespace anonymous - -template -struct grammar - : boost::spirit::qi::grammar< - Iterator, FPT(), boost::spirit::ascii::space_type - > -{ - - // symbol table for constants - // to be added by the actual calculator - struct constant_ - : boost::spirit::qi::symbols< - typename std::iterator_traits::value_type, - FPT - > - { - constant_() - { - } - } constant; - - // symbol table for unary functions like "abs" - struct ufunc_ - : boost::spirit::qi::symbols< - typename std::iterator_traits::value_type, - FPT (*)(FPT) - > + member1 value; + }; + + template + struct definition { - ufunc_() + // Rule declarations + rule statement, identifier; + rule expression, term, + power, + unary_expr, + factor, + unary_func, + binary_func, + group; + + // start() should return the starting symbol + rule const& start() const { return statement; } + + definition(LLCalcParser const& self) { - this->add - ("abs" , (FPT (*)(FPT)) std::abs ) - ("acos" , (FPT (*)(FPT)) std::acos ) - ("asin" , (FPT (*)(FPT)) std::asin ) - ("atan" , (FPT (*)(FPT)) std::atan ) - ("ceil" , (FPT (*)(FPT)) std::ceil ) - ("cos" , (FPT (*)(FPT)) std::cos ) - ("cosh" , (FPT (*)(FPT)) std::cosh ) - ("exp" , (FPT (*)(FPT)) std::exp ) - ("floor" , (FPT (*)(FPT)) std::floor) - ("log" , (FPT (*)(FPT)) std::log ) - ("log10" , (FPT (*)(FPT)) std::log10) - ("sin" , (FPT (*)(FPT)) std::sin ) - ("sinh" , (FPT (*)(FPT)) std::sinh ) - ("sqrt" , (FPT (*)(FPT)) std::sqrt ) - ("tan" , (FPT (*)(FPT)) std::tan ) - ("tanh" , (FPT (*)(FPT)) std::tanh ) + using namespace phoenix; + + assertion assert_domain("Domain error"); +// assertion assert_symbol("Unknown symbol"); + assertion assert_syntax("Syntax error"); + + identifier = + lexeme_d[(alpha_p | '_') >> *(alnum_p | '_')] + ; + + group = + '(' >> expression[group.value = arg1] >> assert_syntax(ch_p(')')) ; - } - } ufunc; - // symbol table for binary functions like "pow" - struct bfunc_ - : boost::spirit::qi::symbols< - typename std::iterator_traits::value_type, - FPT (*)(FPT, FPT) - > - { - bfunc_() - { - using boost::bind; - this->add - ("pow" , (FPT (*)(FPT, FPT)) std::pow ) - ("atan2", (FPT (*)(FPT, FPT)) std::atan2) - ("min" , (FPT (*)(FPT, FPT)) min_glue) - ("max" , (FPT (*)(FPT, FPT)) max_glue) + unary_func = + ((str_p("SIN") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_sin)(self,arg1)]) | + (str_p("COS") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_cos)(self,arg1)]) | + (str_p("TAN") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_tan)(self,arg1)]) | + (str_p("ASIN") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_asin)(self,arg1)]) | + (str_p("ACOS") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_acos)(self,arg1)]) | + (str_p("ATAN") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_atan)(self,arg1)]) | + (str_p("SQRT") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_sqrt)(self,arg1)]) | + (str_p("LOG") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_log)(self,arg1)]) | + (str_p("EXP") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_exp)(self,arg1)]) | + (str_p("ABS") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_fabs)(self,arg1)]) | + (str_p("FLR") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_floor)(self,arg1)]) | + (str_p("CEIL") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_ceil)(self,arg1)]) + ) >> assert_syntax(ch_p(')')) ; - } - } bfunc; - - boost::spirit::qi::rule< - Iterator, FPT(), boost::spirit::ascii::space_type - > expression, term, factor, primary; - - grammar() : grammar::base_type(expression) - { - using boost::spirit::qi::real_parser; - using boost::spirit::qi::real_policies; - real_parser > real; - - using boost::spirit::qi::_1; - using boost::spirit::qi::_2; - using boost::spirit::qi::_3; - using boost::spirit::qi::no_case; - using boost::spirit::qi::_val; - - boost::phoenix::function lazy_pow; - boost::phoenix::function lazy_ufunc; - boost::phoenix::function lazy_bfunc; - - expression = - term [_val = _1] - >> *( ('+' >> term [_val += _1]) - | ('-' >> term [_val -= _1]) - ) + + binary_func = + ((str_p("ATAN2") >> '(' >> expression[binary_func.value = arg1] >> ',' >> + expression[binary_func.value = bind(&LLCalcParser::_atan2)(self, binary_func.value, arg1)]) | + (str_p("MIN") >> '(' >> expression[binary_func.value = arg1] >> ',' >> + expression[binary_func.value = bind(&LLCalcParser::_min)(self, binary_func.value, arg1)]) | + (str_p("MAX") >> '(' >> expression[binary_func.value = arg1] >> ',' >> + expression[binary_func.value = bind(&LLCalcParser::_max)(self, binary_func.value, arg1)]) + ) >> assert_syntax(ch_p(')')) ; - - term = - factor [_val = _1] - >> *( ('*' >> factor [_val *= _1]) - | ('/' >> factor [_val /= _1]) + + // *TODO: Localisation of the decimal point? + // Problem, LLLineEditor::postvalidateFloat accepts a comma when appropriate + // for the current locale. However to do that here could clash with using + // the comma as a separator when passing arguments to functions. + factor = + (ureal_p[factor.value = arg1] | + group[factor.value = arg1] | + unary_func[factor.value = arg1] | + binary_func[factor.value = arg1] | + // Lookup throws an Unknown Symbol error if it is unknown, while this works fine, + // would be "neater" to handle symbol lookup from here with an assertive parser. +// constants_p[factor.value = arg1]| + identifier[factor.value = bind(&LLCalcParser::lookup)(self, arg1, arg2)] + ) >> + // Detect and throw math errors. + assert_domain(eps_p(bind(&LLCalcParser::checkNaN)(self, factor.value))) + ; + + unary_expr = + !ch_p('+') >> factor[unary_expr.value = arg1] | + '-' >> factor[unary_expr.value = -arg1] + ; + + power = + unary_expr[power.value = arg1] >> + *('^' >> assert_syntax(unary_expr[power.value = bind(&powf)(power.value, arg1)])) + ; + + term = + power[term.value = arg1] >> + *(('*' >> assert_syntax(power[term.value *= arg1])) | + ('/' >> assert_syntax(power[term.value /= arg1])) | + ('%' >> assert_syntax(power[term.value = bind(&fmodf)(term.value, arg1)])) ) ; - - factor = - primary [_val = _1] - >> *( ("**" >> factor [_val = lazy_pow(_val, _1)]) + + expression = + assert_syntax(term[expression.value = arg1]) >> + *(('+' >> assert_syntax(term[expression.value += arg1])) | + ('-' >> assert_syntax(term[expression.value -= arg1])) ) ; - - primary = - real [_val = _1] - | '(' >> expression [_val = _1] >> ')' - | ('-' >> primary [_val = -_1]) - | ('+' >> primary [_val = _1]) - | (no_case[ufunc] >> '(' >> expression >> ')') - [_val = lazy_ufunc(_1, _2)] - | (no_case[bfunc] >> '(' >> expression >> ',' - >> expression >> ')') - [_val = lazy_bfunc(_1, _2, _3)] - | no_case[constant] [_val = _1] + + statement = + !ch_p('=') >> ( expression )[var(self.mResult) = arg1] >> (end_p) ; - - } + } + }; + +private: + // Member functions for semantic actions + F32 lookup(const std::string::iterator&, const std::string::iterator&) const; + F32 _min(const F32& a, const F32& b) const { return llmin(a, b); } + F32 _max(const F32& a, const F32& b) const { return llmax(a, b); } + + bool checkNaN(const F32& a) const { return !std::isnan(a); } + + //FIX* non ambiguous function fix making SIN() work for calc -Cryogenic Blitz + F32 _sin(const F32& a) const { return sin(DEG_TO_RAD * a); } + F32 _cos(const F32& a) const { return cos(DEG_TO_RAD * a); } + F32 _tan(const F32& a) const { return tan(DEG_TO_RAD * a); } + F32 _asin(const F32& a) const { return asin(a * RAD_TO_DEG); } + F32 _acos(const F32& a) const { return acos(a * RAD_TO_DEG); } + F32 _atan(const F32& a) const { return atan(a * RAD_TO_DEG); } + F32 _sqrt(const F32& a) const { return sqrt(a); } + F32 _log(const F32& a) const { return log(a); } + F32 _exp(const F32& a) const { return exp(a); } + F32 _fabs(const F32& a) const { return fabs(a); } + F32 _floor(const F32& a) const { return (F32)llfloor(a); } + F32 _ceil(const F32& a) const { return llceil(a); } + F32 _atan2(const F32& a,const F32& b) const { return atan2(a,b); } + + LLCalc::calc_map_t* mConstants; + LLCalc::calc_map_t* mVariables; +// LLCalc::calc_map_t* mUserVariables; + + F32& mResult; }; - -template -bool parse(Iterator &iter, - Iterator end, - const grammar &g, - FPT &result) -{ - return boost::spirit::qi::phrase_parse( - iter, end, g, boost::spirit::ascii::space, result); -} - -} // end namespace expression #endif // LL_CALCPARSER_H diff --git a/indra/llmath/llcamera.cpp b/indra/llmath/llcamera.cpp index 7ab6cdd5f9..9ea9f09935 100644 --- a/indra/llmath/llcamera.cpp +++ b/indra/llmath/llcamera.cpp @@ -2,31 +2,25 @@ * @file llcamera.cpp * @brief Implementation of the LLCamera class. * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -48,10 +42,14 @@ LLCamera::LLCamera() : mPlaneCount(6), mFrustumCornerDist(0.f) { + for (U32 i = 0; i < PLANE_MASK_NUM; i++) + { + mPlaneMask[i] = PLANE_MASK_NONE; + } + calculateFrustumPlanes(); } - LLCamera::LLCamera(F32 vertical_fov_rads, F32 aspect_ratio, S32 view_height_in_pixels, F32 near_plane, F32 far_plane) : LLCoordFrame(), mViewHeightInPixels(view_height_in_pixels), @@ -59,6 +57,11 @@ LLCamera::LLCamera(F32 vertical_fov_rads, F32 aspect_ratio, S32 view_height_in_p mPlaneCount(6), mFrustumCornerDist(0.f) { + for (U32 i = 0; i < PLANE_MASK_NUM; i++) + { + mPlaneMask[i] = PLANE_MASK_NONE; + } + mAspect = llclamp(aspect_ratio, MIN_ASPECT_RATIO, MAX_ASPECT_RATIO); mNearPlane = llclamp(near_plane, MIN_NEAR_PLANE, MAX_NEAR_PLANE); if(far_plane < 0) far_plane = DEFAULT_FAR_PLANE; @@ -90,18 +93,23 @@ F32 LLCamera::getMaxView() const : MAX_FIELD_OF_VIEW; // narrow views } +LLPlane LLCamera::getUserClipPlane() const +{ + return mAgentPlanes[AGENT_PLANE_USER_CLIP]; +} + // ---------------- LLCamera::setFoo() member functions ---------------- void LLCamera::setUserClipPlane(const LLPlane& plane) { - mPlaneCount = 7; - mAgentPlanes[6] = plane; - mPlaneMask[6] = plane.calcPlaneMask(); + mPlaneCount = AGENT_PLANE_USER_CLIP_NUM; + mAgentPlanes[AGENT_PLANE_USER_CLIP] = plane; + mPlaneMask[AGENT_PLANE_USER_CLIP] = plane.calcPlaneMask(); } void LLCamera::disableUserClipPlane() { - mPlaneCount = 6; + mPlaneCount = AGENT_PLANE_NO_USER_CLIP_NUM; } void LLCamera::setView(F32 vertical_fov_rads) @@ -168,31 +176,55 @@ size_t LLCamera::readFrustumFromBuffer(const char *buffer) // ---------------- test methods ---------------- -S32 LLCamera::AABBInFrustum(const LLVector4a ¢er, const LLVector4a& radius) +static const LLVector4a sFrustumScaler[] = +{ + LLVector4a(-1,-1,-1), + LLVector4a( 1,-1,-1), + LLVector4a(-1, 1,-1), + LLVector4a( 1, 1,-1), + LLVector4a(-1,-1, 1), + LLVector4a( 1,-1, 1), + LLVector4a(-1, 1, 1), + LLVector4a( 1, 1, 1) // 8 entries +}; + +bool LLCamera::isChanged() { - static const LLVector4a scaler[] = { - LLVector4a(-1,-1,-1), - LLVector4a( 1,-1,-1), - LLVector4a(-1, 1,-1), - LLVector4a( 1, 1,-1), - LLVector4a(-1,-1, 1), - LLVector4a( 1,-1, 1), - LLVector4a(-1, 1, 1), - LLVector4a( 1, 1, 1) - }; + bool changed = false; + for (U32 i = 0; i < mPlaneCount; i++) +{ + U8 mask = mPlaneMask[i]; + if (mask != 0xff && !changed) + { + changed = !mAgentPlanes[i].equal(mLastAgentPlanes[i]); + } + mLastAgentPlanes[i].set(mAgentPlanes[i]); + } + + return changed; +} + +S32 LLCamera::AABBInFrustum(const LLVector4a ¢er, const LLVector4a& radius, const LLPlane* planes) +{ + if(!planes) + { + //use agent space + planes = mAgentPlanes; + } U8 mask = 0; bool result = false; LLVector4a rscale, maxp, minp; LLSimdScalar d; - for (U32 i = 0; i < mPlaneCount; i++) + U32 max_planes = llmin(mPlaneCount, (U32) AGENT_PLANE_USER_CLIP_NUM); // mAgentPlanes[] size is 7 + for (U32 i = 0; i < max_planes; i++) { mask = mPlaneMask[i]; - if (mask != 0xff) + if (mask < PLANE_MASK_NUM) { - const LLPlane& p(mAgentPlanes[i]); + const LLPlane& p(planes[i]); p.getAt<3>(d); - rscale.setMul(radius, scaler[mask]); + rscale.setMul(radius, sFrustumScaler[mask]); minp.setSub(center, rscale); d = -d; if (p.dot3(minp).getF32() > d) @@ -211,32 +243,34 @@ S32 LLCamera::AABBInFrustum(const LLVector4a ¢er, const LLVector4a& radius) return result?1:2; } +//exactly same as the function AABBInFrustum(...) +//except uses mRegionPlanes instead of mAgentPlanes. +S32 LLCamera::AABBInRegionFrustum(const LLVector4a& center, const LLVector4a& radius) +{ + return AABBInFrustum(center, radius, mRegionPlanes); +} -S32 LLCamera::AABBInFrustumNoFarClip(const LLVector4a& center, const LLVector4a& radius) +S32 LLCamera::AABBInFrustumNoFarClip(const LLVector4a& center, const LLVector4a& radius, const LLPlane* planes) { - static const LLVector4a scaler[] = { - LLVector4a(-1,-1,-1), - LLVector4a( 1,-1,-1), - LLVector4a(-1, 1,-1), - LLVector4a( 1, 1,-1), - LLVector4a(-1,-1, 1), - LLVector4a( 1,-1, 1), - LLVector4a(-1, 1, 1), - LLVector4a( 1, 1, 1) - }; + if(!planes) + { + //use agent space + planes = mAgentPlanes; + } U8 mask = 0; bool result = false; LLVector4a rscale, maxp, minp; LLSimdScalar d; - for (U32 i = 0; i < mPlaneCount; i++) + U32 max_planes = llmin(mPlaneCount, (U32) AGENT_PLANE_USER_CLIP_NUM); // mAgentPlanes[] size is 7 + for (U32 i = 0; i < max_planes; i++) { mask = mPlaneMask[i]; - if ((i != 5) && (mask != 0xff)) + if ((i != 5) && (mask < PLANE_MASK_NUM)) { - const LLPlane& p(mAgentPlanes[i]); + const LLPlane& p(planes[i]); p.getAt<3>(d); - rscale.setMul(radius, scaler[mask]); + rscale.setMul(radius, sFrustumScaler[mask]); minp.setSub(center, rscale); d = -d; if (p.dot3(minp).getF32() > d) @@ -255,6 +289,13 @@ S32 LLCamera::AABBInFrustumNoFarClip(const LLVector4a& center, const LLVector4a& return result?1:2; } +//exactly same as the function AABBInFrustumNoFarClip(...) +//except uses mRegionPlanes instead of mAgentPlanes. +S32 LLCamera::AABBInRegionFrustumNoFarClip(const LLVector4a& center, const LLVector4a& radius) +{ + return AABBInFrustumNoFarClip(center, radius, mRegionPlanes); +} + int LLCamera::sphereInFrustumQuick(const LLVector3 &sphere_center, const F32 radius) { LLVector3 dist = sphere_center-mFrustCenter; @@ -376,7 +417,7 @@ int LLCamera::sphereInFrustum(const LLVector3 &sphere_center, const F32 radius) bool res = false; for (int i = 0; i < 6; i++) { - if (mPlaneMask[i] != 0xff) + if (mPlaneMask[i] != PLANE_MASK_NONE) { float d = mAgentPlanes[i].dist(sphere_center); @@ -548,13 +589,14 @@ void LLCamera::ignoreAgentFrustumPlane(S32 idx) return; } - mPlaneMask[idx] = 0xff; + mPlaneMask[idx] = PLANE_MASK_NONE; mAgentPlanes[idx].clear(); } void LLCamera::calcAgentFrustumPlanes(LLVector3* frust) { - for (int i = 0; i < 8; i++) + + for (int i = 0; i < AGENT_FRUSTRUM_NUM; i++) { mAgentFrustum[i] = frust[i]; } @@ -566,22 +608,22 @@ void LLCamera::calcAgentFrustumPlanes(LLVector3* frust) //order of planes is important, keep most likely to fail in the front of the list //near - frust[0], frust[1], frust[2] - mAgentPlanes[2] = planeFromPoints(frust[0], frust[1], frust[2]); + mAgentPlanes[AGENT_PLANE_NEAR] = planeFromPoints(frust[0], frust[1], frust[2]); //far - mAgentPlanes[5] = planeFromPoints(frust[5], frust[4], frust[6]); + mAgentPlanes[AGENT_PLANE_FAR] = planeFromPoints(frust[5], frust[4], frust[6]); //left - mAgentPlanes[0] = planeFromPoints(frust[4], frust[0], frust[7]); + mAgentPlanes[AGENT_PLANE_LEFT] = planeFromPoints(frust[4], frust[0], frust[7]); //right - mAgentPlanes[1] = planeFromPoints(frust[1], frust[5], frust[6]); + mAgentPlanes[AGENT_PLANE_RIGHT] = planeFromPoints(frust[1], frust[5], frust[6]); //top - mAgentPlanes[4] = planeFromPoints(frust[3], frust[2], frust[6]); + mAgentPlanes[AGENT_PLANE_TOP] = planeFromPoints(frust[3], frust[2], frust[6]); //bottom - mAgentPlanes[3] = planeFromPoints(frust[1], frust[0], frust[4]); + mAgentPlanes[AGENT_PLANE_BOTTOM] = planeFromPoints(frust[1], frust[0], frust[4]); //cache plane octant facing mask for use in AABBInFrustum for (U32 i = 0; i < mPlaneCount; i++) @@ -590,6 +632,47 @@ void LLCamera::calcAgentFrustumPlanes(LLVector3* frust) } } +//calculate regional planes from mAgentPlanes. +//vector "shift" is the vector of the region origin in the agent space. +void LLCamera::calcRegionFrustumPlanes(const LLVector3& shift, F32 far_clip_distance) +{ + F32 far_w; + { + LLVector3 p = getOrigin(); + LLVector3 n(mAgentPlanes[5][0], mAgentPlanes[5][1], mAgentPlanes[5][2]); + F32 dd = n * p; + if(dd + mAgentPlanes[5][3] < 0) //signed distance + { + far_w = -far_clip_distance - dd; + } + else + { + far_w = far_clip_distance - dd; + } + far_w += n * shift; + } + + F32 d; + LLVector3 n; + for(S32 i = 0 ; i < 7; i++) + { + if (mPlaneMask[i] != 0xff) + { + n.setVec(mAgentPlanes[i][0], mAgentPlanes[i][1], mAgentPlanes[i][2]); + + if(i != 5) + { + d = mAgentPlanes[i][3] + n * shift; + } + else + { + d = far_w; + } + mRegionPlanes[i].setVec(n, d); + } + } +} + void LLCamera::calculateFrustumPlanes(F32 left, F32 right, F32 top, F32 bottom) { LLVector3 a, b, c; @@ -641,7 +724,7 @@ void LLCamera::calculateWorldFrustumPlanes() LLVector3 center = mOrigin - mXAxis*mNearPlane; mWorldPlanePos = center; LLVector3 pnorm; - for (int p=0; p<4; p++) + for (int p = 0; p < PLANE_NUM; p++) { mLocalPlanes[p].getVector3(pnorm); LLVector3 norm = rotateToAbsolute(pnorm); diff --git a/indra/llmath/llcamera.h b/indra/llmath/llcamera.h index 97e56b2a2a..1495d05846 100644 --- a/indra/llmath/llcamera.h +++ b/indra/llmath/llcamera.h @@ -2,31 +2,25 @@ * @file llcamera.h * @brief Header file for the LLCamera class. * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -55,7 +49,7 @@ const F32 MIN_FAR_PLANE = 0.2f; // Min/Max FOV values for square views. Call getMin/MaxView to get extremes based on current aspect ratio. static const F32 MIN_FIELD_OF_VIEW = 5.0f * DEG_TO_RAD; -static const F32 MAX_FIELD_OF_VIEW = 175.f * DEG_TO_RAD; +static const F32 MAX_FIELD_OF_VIEW = 320.f * DEG_TO_RAD; // An LLCamera is an LLCoorFrame with a view frustum. // This means that it has several methods for moving it around @@ -82,26 +76,39 @@ class LLCamera PLANE_RIGHT = 1, PLANE_BOTTOM = 2, PLANE_TOP = 3, - PLANE_NUM = 4 + PLANE_NUM = 4, + PLANE_MASK_NONE = 0xff // Disable this plane }; enum { PLANE_LEFT_MASK = (1< #include #include +#include #include "lldefs.h" //#include "llstl.h" // *TODO: Remove when LLString is gone //#include "llstring.h" // *TODO: Remove when LLString is gone @@ -38,22 +41,6 @@ // llcommon depend on llmath. #include "is_approx_equal_fraction.h" -// work around for Windows & older gcc non-standard function names. -#if LL_WINDOWS -#include -#define llisnan(val) _isnan(val) -#define llfinite(val) _finite(val) -#elif (LL_LINUX && __GNUC__ <= 2) -#define llisnan(val) isnan(val) -#define llfinite(val) isfinite(val) -#elif LL_SOLARIS -#define llisnan(val) isnan(val) -#define llfinite(val) (val <= std::numeric_limits::max()) -#else -#define llisnan(val) std::isnan(val) -#define llfinite(val) std::isfinite(val) -#endif - // Single Precision Floating Point Routines // (There used to be more defined here, but they appeared to be redundant and // were breaking some other includes. Removed by Falcon, reviewed by Andrew, 11/25/09) @@ -61,28 +48,34 @@ #define tanf(x) ((F32)tan((F64)(x))) #endif*/ -const F32 GRAVITY = -9.8f; +constexpr F32 GRAVITY = -9.8f; // mathematical constants -const F32 F_PI = 3.1415926535897932384626433832795f; -const F32 F_TWO_PI = 6.283185307179586476925286766559f; -const F32 F_PI_BY_TWO = 1.5707963267948966192313216916398f; -const F32 F_SQRT_TWO_PI = 2.506628274631000502415765284811f; -const F32 F_E = 2.71828182845904523536f; -const F32 F_SQRT2 = 1.4142135623730950488016887242097f; -const F32 F_SQRT3 = 1.73205080756888288657986402541f; -const F32 OO_SQRT2 = 0.7071067811865475244008443621049f; -const F32 DEG_TO_RAD = 0.017453292519943295769236907684886f; -const F32 RAD_TO_DEG = 57.295779513082320876798154814105f; -const F32 F_APPROXIMATELY_ZERO = 0.00001f; -const F32 F_LN2 = 0.69314718056f; -const F32 OO_LN2 = 1.4426950408889634073599246810019f; - -const F32 F_ALMOST_ZERO = 0.0001f; -const F32 F_ALMOST_ONE = 1.0f - F_ALMOST_ZERO; +constexpr F32 F_PI = 3.1415926535897932384626433832795f; +constexpr F32 F_TWO_PI = 6.283185307179586476925286766559f; +constexpr F32 F_PI_BY_TWO = 1.5707963267948966192313216916398f; +constexpr F32 F_SQRT_TWO_PI = 2.506628274631000502415765284811f; +constexpr F32 F_E = 2.71828182845904523536f; +constexpr F32 F_SQRT2 = 1.4142135623730950488016887242097f; +constexpr F32 F_SQRT3 = 1.73205080756888288657986402541f; +constexpr F32 OO_SQRT2 = 0.7071067811865475244008443621049f; +constexpr F32 OO_SQRT3 = 0.577350269189625764509f; +constexpr F32 DEG_TO_RAD = 0.017453292519943295769236907684886f; +constexpr F32 RAD_TO_DEG = 57.295779513082320876798154814105f; +constexpr F32 F_APPROXIMATELY_ZERO = 0.00001f; +constexpr F32 F_LN10 = 2.3025850929940456840179914546844f; +constexpr F32 OO_LN10 = 0.43429448190325182765112891891661f; +constexpr F32 F_LN2 = 0.69314718056f; +constexpr F32 OO_LN2 = 1.4426950408889634073599246810019f; + +constexpr F32 F_ALMOST_ZERO = 0.0001f; +constexpr F32 F_ALMOST_ONE = 1.0f - F_ALMOST_ZERO; + +constexpr F32 GIMBAL_THRESHOLD = 0.000436f; // sets the gimballock threshold 0.025 away from +/-90 degrees +// formula: GIMBAL_THRESHOLD = sin(DEG_TO_RAD * gimbal_threshold_angle); // BUG: Eliminate in favor of F_APPROXIMATELY_ZERO above? -const F32 FP_MAG_THRESHOLD = 0.0000001f; +constexpr F32 FP_MAG_THRESHOLD = 0.0000001f; // TODO: Replace with logic like is_approx_equal inline bool is_approx_zero( F32 f ) { return (-F_APPROXIMATELY_ZERO < f) && (f < F_APPROXIMATELY_ZERO); } @@ -111,15 +104,21 @@ inline bool is_approx_zero( F32 f ) { return (-F_APPROXIMATELY_ZERO < f) && (f < // WARNING: Infinity is comparable with F32_MAX and negative // infinity is comparable with F32_MIN +// handles negative and positive zeros +inline bool is_zero(F32 x) +{ + return (*(U32*)(&x) & 0x7fffffff) == 0; +} + inline bool is_approx_equal(F32 x, F32 y) { - const S32 COMPARE_MANTISSA_UP_TO_BIT = 0x02; + constexpr S32 COMPARE_MANTISSA_UP_TO_BIT = 0x02; return (std::abs((S32) ((U32&)x - (U32&)y) ) < COMPARE_MANTISSA_UP_TO_BIT); } inline bool is_approx_equal(F64 x, F64 y) { - const S64 COMPARE_MANTISSA_UP_TO_BIT = 0x02; + constexpr S64 COMPARE_MANTISSA_UP_TO_BIT = 0x02; return (std::abs((S32) ((U64&)x - (U64&)y) ) < COMPARE_MANTISSA_UP_TO_BIT); } @@ -140,33 +139,17 @@ inline F64 llabs(const F64 a) inline S32 lltrunc( F32 f ) { -#if LL_WINDOWS && !defined( __INTEL_COMPILER ) - // Avoids changing the floating point control word. - // Add or subtract 0.5 - epsilon and then round - const static U32 zpfp[] = { 0xBEFFFFFF, 0x3EFFFFFF }; - S32 result; - __asm { - fld f - mov eax, f - shr eax, 29 - and eax, 4 - fadd dword ptr [zpfp + eax] - fistp result - } - return result; -#else - return (S32)f; -#endif + return (S32)trunc(f); } inline S32 lltrunc( F64 f ) { - return (S32)f; + return (S32)trunc(f); } inline S32 llfloor( F32 f ) { -#if LL_WINDOWS && !defined( __INTEL_COMPILER ) +#if LL_WINDOWS && !defined( __INTEL_COMPILER ) && !defined(_WIN64) // Avoids changing the floating point control word. // Accurate (unlike Stereopsis version) for all values between S32_MIN and S32_MAX and slightly faster than Stereopsis version. // Add -(0.5 - epsilon) and then round @@ -190,65 +173,26 @@ inline S32 llceil( F32 f ) return (S32)ceil(f); } - -#ifndef BOGUS_ROUND // Use this round. Does an arithmetic round (0.5 always rounds up) -inline S32 llround(const F32 val) -{ - return llfloor(val + 0.5f); -} - -#else // BOGUS_ROUND -// Old llround implementation - does banker's round (toward nearest even in the case of a 0.5. -// Not using this because we don't have a consistent implementation on both platforms, use -// llfloor(val + 0.5f), which is consistent on all platforms. -inline S32 llround(const F32 val) -{ - #if LL_WINDOWS - // Note: assumes that the floating point control word is set to rounding mode (the default) - S32 ret_val; - _asm fld val - _asm fistp ret_val; - return ret_val; - #elif LL_LINUX - // Note: assumes that the floating point control word is set - // to rounding mode (the default) - S32 ret_val; - __asm__ __volatile__( "flds %1 \n\t" - "fistpl %0 \n\t" - : "=m" (ret_val) - : "m" (val) ); - return ret_val; - #else - return llfloor(val + 0.5f); - #endif -} - -// A fast arithmentic round on intel, from Laurent de Soras http://ldesoras.free.fr -inline int round_int(double x) -{ - const float round_to_nearest = 0.5f; - int i; - __asm - { - fld x - fadd st, st (0) - fadd round_to_nearest - fistp i - sar i, 1 - } - return (i); +inline S32 ll_round(const F32 val) +{ + return (S32)round(val); +} + +// Singu Note: Quick round for values that are known to be >= 0. +inline S32 ll_pos_round(const F32 val) +{ + return val + .5f; } -#endif // BOGUS_ROUND -inline F32 llround( F32 val, F32 nearest ) +inline F32 ll_round(F32 val, F32 nearest) { - return F32(floor(val * (1.0f / nearest) + 0.5f)) * nearest; + return F32(round(val * (1.0f / nearest))) * nearest; } -inline F64 llround( F64 val, F64 nearest ) +inline F64 ll_round(F64 val, F64 nearest) { - return F64(floor(val * (1.0 / nearest) + 0.5)) * nearest; + return F64(round(val * (1.0 / nearest))) * nearest; } // these provide minimum peak error @@ -257,8 +201,8 @@ inline F64 llround( F64 val, F64 nearest ) // peak error = -31.4 dB // RMS error = -28.1 dB -const F32 FAST_MAG_ALPHA = 0.960433870103f; -const F32 FAST_MAG_BETA = 0.397824734759f; +constexpr F32 FAST_MAG_ALPHA = 0.960433870103f; +constexpr F32 FAST_MAG_BETA = 0.397824734759f; // these provide minimum RMS error // @@ -266,8 +210,8 @@ const F32 FAST_MAG_BETA = 0.397824734759f; // peak error = -32.6 dB // RMS error = -25.7 dB // -//const F32 FAST_MAG_ALPHA = 0.948059448969f; -//const F32 FAST_MAG_BETA = 0.392699081699f; +//constexpr F32 FAST_MAG_ALPHA = 0.948059448969f; +//constexpr F32 FAST_MAG_BETA = 0.392699081699f; inline F32 fastMagnitude(F32 a, F32 b) { @@ -284,8 +228,8 @@ inline F32 fastMagnitude(F32 a, F32 b) // // Culled from www.stereopsis.com/FPU.html -const F64 LL_DOUBLE_TO_FIX_MAGIC = 68719476736.0*1.5; //2^36 * 1.5, (52-_shiftamt=36) uses limited precisicion to floor -const S32 LL_SHIFT_AMOUNT = 16; //16.16 fixed point representation, +constexpr F64 LL_DOUBLE_TO_FIX_MAGIC = 68719476736.0*1.5; //2^36 * 1.5, (52-_shiftamt=36) uses limited precisicion to floor +constexpr S32 LL_SHIFT_AMOUNT = 16; //16.16 fixed point representation, // Endian dependent code #ifdef LL_LITTLE_ENDIAN @@ -296,7 +240,7 @@ const S32 LL_SHIFT_AMOUNT = 16; //16.16 fixed point represe #define LL_MAN_INDEX 1 #endif -/* Deprecated: use llround(), lltrunc(), or llfloor() instead +/* Deprecated: use ll_round(), lltrunc(), or llfloor() instead // ================================================================================================ // Real2Int // ================================================================================================ @@ -338,7 +282,7 @@ static union #define LL_EXP_A (1048576 * OO_LN2) // use 1512775 for integer #define LL_EXP_C (60801) // this value of C good for -4 < y < 4 -#define LL_FAST_EXP(y) (LLECO.n.i = llround(F32(LL_EXP_A*(y))) + (1072693248 - LL_EXP_C), LLECO.d) +#define LL_FAST_EXP(y) (LLECO.n.i = ll_round(F32(LL_EXP_A*(y))) + (1072693248 - LL_EXP_C), LLECO.d) @@ -357,8 +301,8 @@ inline F32 snap_to_sig_figs(F32 foo, S32 sig_figs) bar *= 10.f; } - //F32 new_foo = (F32)llround(foo * bar); - // the llround() implementation sucks. Don't us it. + //F32 new_foo = (F32)ll_round(foo * bar); + // the ll_round() implementation sucks. Don't us it. F32 sign = (foo > 0.f) ? 1.f : -1.f; F32 new_foo = F32( S64(foo * bar + sign * 0.5f)); @@ -451,7 +395,7 @@ inline U32 get_lower_power_two(U32 val, U32 max_power_two) { if(!max_power_two) { - max_power_two = 1 << 31 ; + max_power_two = 1U << 31 ; } if(max_power_two & (max_power_two - 1)) { @@ -473,7 +417,7 @@ inline U32 get_next_power_two(U32 val, U32 max_power_two) { if(!max_power_two) { - max_power_two = 1 << 31 ; + max_power_two = 1U << 31 ; } if(val >= max_power_two) diff --git a/indra/llmath/llmatrix3a.cpp b/indra/llmath/llmatrix3a.cpp index ad008e9d33..ab077abcb0 100644 --- a/indra/llmath/llmatrix3a.cpp +++ b/indra/llmath/llmatrix3a.cpp @@ -24,7 +24,6 @@ * $/LicenseInfo$ */ -#include "sys.h" #include "llmath.h" static LL_ALIGN_16(const F32 M_IDENT_3A[12]) = diff --git a/indra/llmath/llmatrix3a.h b/indra/llmath/llmatrix3a.h index 9916cfd2da..491fac5f24 100644 --- a/indra/llmath/llmatrix3a.h +++ b/indra/llmath/llmatrix3a.h @@ -40,6 +40,7 @@ // LLMatrix3a is the base class for LLRotation, which should be used instead any time you're dealing with a // rotation matrix. +LL_ALIGN_PREFIX(16) class LLMatrix3a { public: @@ -56,7 +57,7 @@ class LLMatrix3a ////////////////////////// // Ctor - LLMatrix3a() {} + LLMatrix3a() = default; // Ctor for setting by columns inline LLMatrix3a( const LLVector4a& c0, const LLVector4a& c1, const LLVector4a& c2 ); @@ -113,16 +114,24 @@ class LLMatrix3a LL_ALIGN_16(LLVector4a mColumns[3]); -}; +} LL_ALIGN_POSTFIX(16); +LL_ALIGN_PREFIX(16) class LLRotation : public LLMatrix3a { public: - LLRotation() {} + LLRotation() = default; // Returns true if this rotation is orthonormal with det ~= 1 inline bool isOkRotation() const; -}; +} LL_ALIGN_POSTFIX(16); +#if !defined(LL_DEBUG) +static_assert(std::is_trivial::value, "LLMatrix3a must be a trivial type"); +static_assert(std::is_standard_layout::value, "LLMatrix3a must be a standard layout type"); + +static_assert(std::is_trivial::value, "LLRotation must be a trivial type"); +static_assert(std::is_standard_layout::value, "LLRotation must be a standard layout type"); +#endif #endif diff --git a/indra/llmath/llmatrix3a.inl b/indra/llmath/llmatrix3a.inl index eaf58319da..37819fea3c 100644 --- a/indra/llmath/llmatrix3a.inl +++ b/indra/llmath/llmatrix3a.inl @@ -60,7 +60,7 @@ inline void LLMatrix3a::setTranspose(const LLMatrix3a& src) const LLQuad srcCol1 = src.mColumns[1]; const LLQuad unpacklo = _mm_unpacklo_ps( srcCol0, srcCol1 ); mColumns[0] = _mm_movelh_ps( unpacklo, src.mColumns[2] ); - mColumns[1] = _mm_shuffle_ps( unpacklo, src.mColumns[2], _MM_SHUFFLE(0, 1, 3, 2) ); + mColumns[1] = _mm_shuffle_ps( _mm_movehl_ps( srcCol0, unpacklo ), src.mColumns[2], _MM_SHUFFLE(0, 1, 1, 0) ); mColumns[2] = _mm_shuffle_ps( _mm_unpackhi_ps( srcCol0, srcCol1 ), src.mColumns[2], _MM_SHUFFLE(0, 2, 1, 0) ); } diff --git a/indra/llmath/llmatrix4a.cpp b/indra/llmath/llmatrix4a.cpp new file mode 100644 index 0000000000..fe8f0b98f3 --- /dev/null +++ b/indra/llmath/llmatrix4a.cpp @@ -0,0 +1,80 @@ +/** +* @file llmatrix4a.cpp +* @brief Functions for vectorized matrix/vector operations +* +* $LicenseInfo:firstyear=2018&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2018, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#include "llmath.h" +#include "llmatrix4a.h" + +// Convert a bounding box into other coordinate system. Should give +// the same results as transforming every corner of the bounding box +// and extracting the bounding box of that, although that's not +// necessarily the fastest way to implement. +void matMulBoundBox(const LLMatrix4a &mat, const LLVector4a *in_extents, LLVector4a *out_extents) +{ + //get 8 corners of bounding box + LLVector4Logical mask[6]; + + for (U32 i = 0; i < 6; ++i) + { + mask[i].clear(); + } + + mask[0].setElement<2>(); //001 + mask[1].setElement<1>(); //010 + mask[2].setElement<1>(); //011 + mask[2].setElement<2>(); + mask[3].setElement<0>(); //100 + mask[4].setElement<0>(); //101 + mask[4].setElement<2>(); + mask[5].setElement<0>(); //110 + mask[5].setElement<1>(); + + LLVector4a v[8]; + + v[6] = in_extents[0]; + v[7] = in_extents[1]; + + for (U32 i = 0; i < 6; ++i) + { + v[i].setSelectWithMask(mask[i], in_extents[0], in_extents[1]); + } + + LLVector4a tv[8]; + + //transform bounding box into drawable space + for (U32 i = 0; i < 8; ++i) + { + mat.affineTransform(v[i], tv[i]); + } + + //find bounding box + out_extents[0] = out_extents[1] = tv[0]; + + for (U32 i = 1; i < 8; ++i) + { + out_extents[0].setMin(out_extents[0], tv[i]); + out_extents[1].setMax(out_extents[1], tv[i]); + } +} diff --git a/indra/llmath/llmatrix4a.h b/indra/llmath/llmatrix4a.h index 94e5e54af8..024dbb6c53 100644 --- a/indra/llmath/llmatrix4a.h +++ b/indra/llmath/llmatrix4a.h @@ -31,10 +31,81 @@ #include "m4math.h" #include "m3math.h" +LL_ALIGN_PREFIX(16) class LLMatrix4a { -public: +private: LL_ALIGN_16(LLVector4a mMatrix[4]); +public: + enum + { + ROW_FWD = 0, + ROW_LEFT, + ROW_UP, + ROW_TRANS + }; + + void* operator new(size_t size) + { + return ll_aligned_malloc_16(size); + } + + void* operator new[](size_t size) + { + return ll_aligned_malloc_16(size); + } + + void operator delete(void* ptr) + { + ll_aligned_free_16(ptr); + } + + void operator delete[](void* ptr) + { + ll_aligned_free_16(ptr); + } + + LLMatrix4a() = default; + LLMatrix4a(const LLQuad& q1,const LLQuad& q2,const LLQuad& q3,const LLQuad& q4) + { + mMatrix[0] = q1; + mMatrix[1] = q2; + mMatrix[2] = q3; + mMatrix[3] = q4; + } + LLMatrix4a(const LLQuaternion2& quat) + { + const LLVector4a& xyzw = quat.getVector4a(); + LLVector4a nyxwz = _mm_shuffle_ps(xyzw, xyzw, _MM_SHUFFLE(2,3,0,1)); + nyxwz.negate(); + + const LLVector4a xnyynx = _mm_unpacklo_ps(xyzw,nyxwz); + const LLVector4a znwwnz = _mm_unpackhi_ps(xyzw,nyxwz); + + LLMatrix4a mata; + mata.setRow<0>(_mm_shuffle_ps(xyzw, xnyynx, _MM_SHUFFLE(0,1,2,3))); + mata.setRow<1>(_mm_shuffle_ps(znwwnz, xyzw, _MM_SHUFFLE(1,0,2,3))); + mata.setRow<2>(_mm_shuffle_ps(xnyynx, xyzw, _MM_SHUFFLE(2,3,3,2))); + mata.setRow<3>(_mm_shuffle_ps(xnyynx, znwwnz, _MM_SHUFFLE(2,3,1,3))); + + LLMatrix4a matb; + matb.setRow<0>(_mm_shuffle_ps(xyzw, xnyynx, _MM_SHUFFLE(3,1,2,3))); + matb.setRow<1>(_mm_shuffle_ps(znwwnz, xnyynx, _MM_SHUFFLE(1,0,2,3))); + matb.setRow<2>(_mm_shuffle_ps(xnyynx, znwwnz, _MM_SHUFFLE(3,2,3,2))); + matb.setRow<3>(xyzw); + + setMul(matb,mata); + } + + inline F32* getF32ptr() + { + return mMatrix[0].getF32ptr(); + } + + inline const F32* getF32ptr() const + { + return mMatrix[0].getF32ptr(); + } inline void clear() { @@ -44,13 +115,21 @@ class LLMatrix4a mMatrix[3].clear(); } + inline void setIdentity() + { + static __m128 ones = _mm_set_ps(1.f,0.f,0.f,1.f); + mMatrix[0] = _mm_movelh_ps(ones,_mm_setzero_ps()); + mMatrix[1] = _mm_movehl_ps(_mm_setzero_ps(),ones); + mMatrix[2] = _mm_movelh_ps(_mm_setzero_ps(),ones); + mMatrix[3] = _mm_movehl_ps(ones,_mm_setzero_ps()); + } + inline void loadu(const LLMatrix4& src) { - mMatrix[0] = _mm_loadu_ps(src.mMatrix[0]); - mMatrix[1] = _mm_loadu_ps(src.mMatrix[1]); - mMatrix[2] = _mm_loadu_ps(src.mMatrix[2]); - mMatrix[3] = _mm_loadu_ps(src.mMatrix[3]); - + mMatrix[0].loadua(src.mMatrix[0]); + mMatrix[1].loadua(src.mMatrix[1]); + mMatrix[2].loadua(src.mMatrix[2]); + mMatrix[3].loadua(src.mMatrix[3]); } inline void loadu(const LLMatrix3& src) @@ -61,6 +140,14 @@ class LLMatrix4a mMatrix[3].set(0,0,0,1.f); } + inline void loadu(const F32* src) + { + mMatrix[0].loadua(src+0); + mMatrix[1].loadua(src+4); + mMatrix[2].loadua(src+8); + mMatrix[3].loadua(src+12); + } + inline void add(const LLMatrix4a& rhs) { mMatrix[0].add(rhs.mMatrix[0]); @@ -69,6 +156,75 @@ class LLMatrix4a mMatrix[3].add(rhs.mMatrix[3]); } + inline void mul(const LLMatrix4a& rhs) + { + //Not using rotate4 to avoid extra copy of *this. + LLVector4a x0,y0,z0,w0; + LLVector4a x1,y1,z1,w1; + LLVector4a x2,y2,z2,w2; + LLVector4a x3,y3,z3,w3; + + //16 shuffles + x0.splat<0>(rhs.mMatrix[0]); + x1.splat<0>(rhs.mMatrix[1]); + x2.splat<0>(rhs.mMatrix[2]); + x3.splat<0>(rhs.mMatrix[3]); + + y0.splat<1>(rhs.mMatrix[0]); + y1.splat<1>(rhs.mMatrix[1]); + y2.splat<1>(rhs.mMatrix[2]); + y3.splat<1>(rhs.mMatrix[3]); + + z0.splat<2>(rhs.mMatrix[0]); + z1.splat<2>(rhs.mMatrix[1]); + z2.splat<2>(rhs.mMatrix[2]); + z3.splat<2>(rhs.mMatrix[3]); + + w0.splat<3>(rhs.mMatrix[0]); + w1.splat<3>(rhs.mMatrix[1]); + w2.splat<3>(rhs.mMatrix[2]); + w3.splat<3>(rhs.mMatrix[3]); + + //16 muls + x0.mul(mMatrix[0]); + x1.mul(mMatrix[0]); + x2.mul(mMatrix[0]); + x3.mul(mMatrix[0]); + + y0.mul(mMatrix[1]); + y1.mul(mMatrix[1]); + y2.mul(mMatrix[1]); + y3.mul(mMatrix[1]); + + z0.mul(mMatrix[2]); + z1.mul(mMatrix[2]); + z2.mul(mMatrix[2]); + z3.mul(mMatrix[2]); + + w0.mul(mMatrix[3]); + w1.mul(mMatrix[3]); + w2.mul(mMatrix[3]); + w3.mul(mMatrix[3]); + + //12 adds + x0.add(y0); + z0.add(w0); + + x1.add(y1); + z1.add(w1); + + x2.add(y2); + z2.add(w2); + + x3.add(y3); + z3.add(w3); + + mMatrix[0].setAdd(x0,z0); + mMatrix[1].setAdd(x1,z1); + mMatrix[2].setAdd(x2,z2); + mMatrix[3].setAdd(x3,z3); + } + inline void setRows(const LLVector4a& r0, const LLVector4a& r1, const LLVector4a& r2) { mMatrix[0] = r0; @@ -76,12 +232,59 @@ class LLMatrix4a mMatrix[2] = r2; } + template + inline void setRow(const LLVector4a& row) + { + mMatrix[N] = row; + } + + template + inline const LLVector4a& getRow() const + { + return mMatrix[N]; + } + + template + inline LLVector4a& getRow() + { + return mMatrix[N]; + } + + template + inline void setColumn(const LLVector4a& col) + { + mMatrix[0].copyComponent(col.getScalarAt<0>()); + mMatrix[1].copyComponent(col.getScalarAt<1>()); + mMatrix[2].copyComponent(col.getScalarAt<2>()); + mMatrix[3].copyComponent(col.getScalarAt<3>()); + } + + template + inline LLVector4a getColumn() + { + LLVector4a v; + v.copyComponent<0>(mMatrix[0].getScalarAt()); + v.copyComponent<1>(mMatrix[1].getScalarAt()); + v.copyComponent<2>(mMatrix[2].getScalarAt()); + v.copyComponent<3>(mMatrix[3].getScalarAt()); + return v; + } + inline void setMul(const LLMatrix4a& m, const F32 s) { - mMatrix[0].setMul(m.mMatrix[0], s); - mMatrix[1].setMul(m.mMatrix[1], s); - mMatrix[2].setMul(m.mMatrix[2], s); - mMatrix[3].setMul(m.mMatrix[3], s); + const LLVector4a ssss(s); + mMatrix[0].setMul(m.mMatrix[0], ssss); + mMatrix[1].setMul(m.mMatrix[1], ssss); + mMatrix[2].setMul(m.mMatrix[2], ssss); + mMatrix[3].setMul(m.mMatrix[3], ssss); + } + + inline void setMul(const LLMatrix4a& m0, const LLMatrix4a& m1) + { + m0.rotate4(m1.mMatrix[0],mMatrix[0]); + m0.rotate4(m1.mMatrix[1],mMatrix[1]); + m0.rotate4(m1.mMatrix[2],mMatrix[2]); + m0.rotate4(m1.mMatrix[3],mMatrix[3]); } inline void setLerp(const LLMatrix4a& a, const LLMatrix4a& b, F32 w) @@ -94,10 +297,11 @@ class LLMatrix4a // this = a + d*w - d0.mul(w); - d1.mul(w); - d2.mul(w); - d3.mul(w); + const LLVector4a wwww(w); + d0.mul(wwww); + d1.mul(wwww); + d2.mul(wwww); + d3.mul(wwww); mMatrix[0].setAdd(a.mMatrix[0],d0); mMatrix[1].setAdd(a.mMatrix[1],d1); @@ -107,13 +311,14 @@ class LLMatrix4a //Singu Note: Don't mess with this. It's intentionally different from LL's. // Note how res isn't manipulated until the very end. + //Fast(er). Treats v[VW] as 0.f inline void rotate(const LLVector4a& v, LLVector4a& res) const { LLVector4a x,y,z; - x = _mm_shuffle_ps(v, v, _MM_SHUFFLE(0, 0, 0, 0)); - y = _mm_shuffle_ps(v, v, _MM_SHUFFLE(1, 1, 1, 1)); - z = _mm_shuffle_ps(v, v, _MM_SHUFFLE(2, 2, 2, 2)); + x.splat<0>(v); + y.splat<1>(v); + z.splat<2>(v); x.mul(mMatrix[0]); y.mul(mMatrix[1]); @@ -123,14 +328,15 @@ class LLMatrix4a res.setAdd(x,z); } + //Proper. v[VW] as v[VW] inline void rotate4(const LLVector4a& v, LLVector4a& res) const { LLVector4a x,y,z,w; - x = _mm_shuffle_ps(v, v, _MM_SHUFFLE(0, 0, 0, 0)); - y = _mm_shuffle_ps(v, v, _MM_SHUFFLE(1, 1, 1, 1)); - z = _mm_shuffle_ps(v, v, _MM_SHUFFLE(2, 2, 2, 2)); - w = _mm_shuffle_ps(v, v, _MM_SHUFFLE(3, 3, 3, 3)); + x.splat<0>(v); + y.splat<1>(v); + z.splat<2>(v); + w.splat<3>(v); x.mul(mMatrix[0]); y.mul(mMatrix[1]); @@ -142,14 +348,44 @@ class LLMatrix4a res.setAdd(x,z); } + //Fast(er). Treats v[VW] as 1.f inline void affineTransform(const LLVector4a& v, LLVector4a& res) const { LLVector4a x,y,z; - x = _mm_shuffle_ps(v, v, _MM_SHUFFLE(0, 0, 0, 0)); - y = _mm_shuffle_ps(v, v, _MM_SHUFFLE(1, 1, 1, 1)); - z = _mm_shuffle_ps(v, v, _MM_SHUFFLE(2, 2, 2, 2)); - + x.splat<0>(v); + y.splat<1>(v); + z.splat<2>(v); + + x.mul(mMatrix[0]); + y.mul(mMatrix[1]); + z.mul(mMatrix[2]); + + x.add(y); + z.add(mMatrix[3]); + res.setAdd(x,z); + } + + inline void perspectiveTransform(const LLVector4a& v, LLVector4a& res) const + { + LLVector4a x,y,z,s,t,p,q; + + x.splat<0>(v); + y.splat<1>(v); + z.splat<2>(v); + + s.splat<3>(mMatrix[0]); + t.splat<3>(mMatrix[1]); + p.splat<3>(mMatrix[2]); + q.splat<3>(mMatrix[3]); + + s.mul(x); + t.mul(y); + p.mul(z); + q.add(s); + t.add(p); + q.add(t); + x.mul(mMatrix[0]); y.mul(mMatrix[1]); z.mul(mMatrix[2]); @@ -157,7 +393,333 @@ class LLMatrix4a x.add(y); z.add(mMatrix[3]); res.setAdd(x,z); + res.div(q); + } + + inline void transpose() + { + __m128 q1 = _mm_unpackhi_ps(mMatrix[0],mMatrix[1]); + __m128 q2 = _mm_unpacklo_ps(mMatrix[0],mMatrix[1]); + __m128 q3 = _mm_unpacklo_ps(mMatrix[2],mMatrix[3]); + __m128 q4 = _mm_unpackhi_ps(mMatrix[2],mMatrix[3]); + + mMatrix[0] = _mm_movelh_ps(q2,q3); + mMatrix[1] = _mm_movehl_ps(q3,q2); + mMatrix[2] = _mm_movelh_ps(q1,q4); + mMatrix[3] = _mm_movehl_ps(q4,q1); + } + +// Following procedure adapted from: +// http://software.intel.com/en-us/articles/optimized-matrix-library-for-use-with-the-intel-pentiumr-4-processors-sse2-instructions/ +// +// License/Copyright Statement: +// +// Copyright (c) 2001 Intel Corporation. +// +// Permition is granted to use, copy, distribute and prepare derivative works +// of this library for any purpose and without fee, provided, that the above +// copyright notice and this statement appear in all copies. +// Intel makes no representations about the suitability of this library for +// any purpose, and specifically disclaims all warranties. +// See LEGAL-intel_matrixlib.TXT for all the legal information. + inline float invert() + { + LL_ALIGN_16(const unsigned int Sign_PNNP[4]) = { 0x00000000, 0x80000000, 0x80000000, 0x00000000 }; + + // The inverse is calculated using "Divide and Conquer" technique. The + // original matrix is divide into four 2x2 sub-matrices. Since each + // register holds four matrix element, the smaller matrices are + // represented as a registers. Hence we get a better locality of the + // calculations. + + LLVector4a A = _mm_movelh_ps(mMatrix[0], mMatrix[1]), // the four sub-matrices + B = _mm_movehl_ps(mMatrix[1], mMatrix[0]), + C = _mm_movelh_ps(mMatrix[2], mMatrix[3]), + D = _mm_movehl_ps(mMatrix[3], mMatrix[2]); + LLVector4a iA, iB, iC, iD, // partial inverse of the sub-matrices + DC, AB; + LLSimdScalar dA, dB, dC, dD; // determinant of the sub-matrices + LLSimdScalar det, d, d1, d2; + LLVector4a rd; + + // AB = A# * B + AB.setMul(_mm_shuffle_ps(A,A,0x0F), B); + AB.sub(_mm_mul_ps(_mm_shuffle_ps(A,A,0xA5), _mm_shuffle_ps(B,B,0x4E))); + // DC = D# * C + DC.setMul(_mm_shuffle_ps(D,D,0x0F), C); + DC.sub(_mm_mul_ps(_mm_shuffle_ps(D,D,0xA5), _mm_shuffle_ps(C,C,0x4E))); + + // dA = |A| + dA = _mm_mul_ps(_mm_shuffle_ps(A, A, 0x5F),A); + dA -= _mm_movehl_ps(dA,dA); + // dB = |B| + dB = _mm_mul_ps(_mm_shuffle_ps(B, B, 0x5F),B); + dB -= _mm_movehl_ps(dB,dB); + + // dC = |C| + dC = _mm_mul_ps(_mm_shuffle_ps(C, C, 0x5F),C); + dC -= _mm_movehl_ps(dC,dC); + // dD = |D| + dD = _mm_mul_ps(_mm_shuffle_ps(D, D, 0x5F),D); + dD -= _mm_movehl_ps(dD,dD); + + // d = trace(AB*DC) = trace(A#*B*D#*C) + d = _mm_mul_ps(_mm_shuffle_ps(DC,DC,0xD8),AB); + + // iD = C*A#*B + iD.setMul(_mm_shuffle_ps(C,C,0xA0), _mm_movelh_ps(AB,AB)); + iD.add(_mm_mul_ps(_mm_shuffle_ps(C,C,0xF5), _mm_movehl_ps(AB,AB))); + // iA = B*D#*C + iA.setMul(_mm_shuffle_ps(B,B,0xA0), _mm_movelh_ps(DC,DC)); + iA.add(_mm_mul_ps(_mm_shuffle_ps(B,B,0xF5), _mm_movehl_ps(DC,DC))); + + // d = trace(AB*DC) = trace(A#*B*D#*C) [continue] + d = _mm_add_ps(d, _mm_movehl_ps(d, d)); + d += _mm_shuffle_ps(d, d, 1); + d1 = dA*dD; + d2 = dB*dC; + + // iD = D*|A| - C*A#*B + iD.setSub(_mm_mul_ps(D,_mm_shuffle_ps(dA,dA,0)), iD); + + // iA = A*|D| - B*D#*C; + iA.setSub(_mm_mul_ps(A,_mm_shuffle_ps(dD,dD,0)), iA); + + // det = |A|*|D| + |B|*|C| - trace(A#*B*D#*C) + det = d1+d2-d; + + __m128 is_zero_mask = _mm_cmpeq_ps(det,_mm_setzero_ps()); + rd = _mm_div_ss(_mm_set_ss(1.f),_mm_or_ps(_mm_andnot_ps(is_zero_mask, det), _mm_and_ps(is_zero_mask, _mm_set_ss(1.f)))); +#ifdef ZERO_SINGULAR + rd = _mm_and_ps(_mm_cmpneq_ss(det,_mm_setzero_ps()), rd); +#endif + + // iB = D * (A#B)# = D*B#*A + iB.setMul(D, _mm_shuffle_ps(AB,AB,0x33)); + iB.sub(_mm_mul_ps(_mm_shuffle_ps(D,D,0xB1), _mm_shuffle_ps(AB,AB,0x66))); + // iC = A * (D#C)# = A*C#*D + iC.setMul(A, _mm_shuffle_ps(DC,DC,0x33)); + iC.sub(_mm_mul_ps(_mm_shuffle_ps(A,A,0xB1), _mm_shuffle_ps(DC,DC,0x66))); + + rd = _mm_shuffle_ps(rd,rd,0); + rd = _mm_xor_ps(rd, _mm_load_ps((const float*)Sign_PNNP)); + + // iB = C*|B| - D*B#*A + iB.setSub(_mm_mul_ps(C,_mm_shuffle_ps(dB,dB,0)), iB); + + // iC = B*|C| - A*C#*D; + iC.setSub(_mm_mul_ps(B,_mm_shuffle_ps(dC,dC,0)), iC); + + + // iX = iX / det + iA.mul(rd); + iB.mul(rd); + iC.mul(rd); + iD.mul(rd); + + mMatrix[0] = _mm_shuffle_ps(iA,iB,0x77); + mMatrix[1] = _mm_shuffle_ps(iA,iB,0x22); + mMatrix[2] = _mm_shuffle_ps(iC,iD,0x77); + mMatrix[3] = _mm_shuffle_ps(iC,iD,0x22); + + F32 ret; + _mm_store_ss(&ret,det); + return ret; + } + + //=============Affine transformation matrix only========================= + + //Multiply matrix with a pure translation matrix. + inline void applyTranslation_affine(const F32& x, const F32& y, const F32& z) + { + const LLVector4a xyz0(x,y,z,0); //load + LLVector4a xxxx; + xxxx.splat<0>(xyz0); + LLVector4a yyyy; + yyyy.splat<1>(xyz0); + LLVector4a zzzz; + zzzz.splat<2>(xyz0); + + LLVector4a sum1; + LLVector4a sum2; + LLVector4a sum3; + + sum1.setMul(xxxx,mMatrix[0]); + sum2.setMul(yyyy,mMatrix[1]); + sum3.setMul(zzzz,mMatrix[2]); + + mMatrix[3].add(sum1); + mMatrix[3].add(sum2); + mMatrix[3].add(sum3); + } + + //Multiply matrix with a pure translation matrix. + inline void applyTranslation_affine(const LLVector3& trans) + { + applyTranslation_affine(trans.mV[VX],trans.mV[VY],trans.mV[VZ]); + } + + //Multiply matrix with a pure scale matrix. + inline void applyScale_affine(const F32& x, const F32& y, const F32& z) + { + const LLVector4a xyz0(x,y,z,0); //load + LLVector4a xxxx; + xxxx.splat<0>(xyz0); + LLVector4a yyyy; + yyyy.splat<1>(xyz0); + LLVector4a zzzz; + zzzz.splat<2>(xyz0); + + mMatrix[0].mul(xxxx); + mMatrix[1].mul(yyyy); + mMatrix[2].mul(zzzz); + } + + //Multiply matrix with a pure scale matrix. + inline void applyScale_affine(const LLVector3& scale) + { + applyScale_affine(scale.mV[VX],scale.mV[VY],scale.mV[VZ]); } -}; + //Multiply matrix with a pure scale matrix. + inline void applyScale_affine(const F32& s) + { + const LLVector4a scale(s); //load + mMatrix[0].mul(scale); + mMatrix[1].mul(scale); + mMatrix[2].mul(scale); + } + + //Direct addition to row3. + inline void translate_affine(const LLVector3& trans) + { + LLVector4a translation; + translation.load3(trans.mV); + mMatrix[3].add(translation); + } + + //Direct assignment of row3. + inline void setTranslate_affine(const LLVector3& trans) + { + static const LLVector4Logical mask = _mm_load_ps((F32*)&S_V4LOGICAL_MASK_TABLE[3*4]); + + LLVector4a translation; + translation.load3(trans.mV); + + mMatrix[3].setSelectWithMask(mask,mMatrix[3],translation); + } + + inline void mul_affine(const LLMatrix4a& rhs) + { + LLVector4a x0,y0,z0; + LLVector4a x1,y1,z1; + LLVector4a x2,y2,z2; + LLVector4a x3,y3,z3; + + //12 shuffles + x0.splat<0>(rhs.mMatrix[0]); + x1.splat<0>(rhs.mMatrix[1]); + x2.splat<0>(rhs.mMatrix[2]); + x3.splat<0>(rhs.mMatrix[3]); + + y0.splat<1>(rhs.mMatrix[0]); + y1.splat<1>(rhs.mMatrix[1]); + y2.splat<1>(rhs.mMatrix[2]); + y3.splat<1>(rhs.mMatrix[3]); + + z0.splat<2>(rhs.mMatrix[0]); + z1.splat<2>(rhs.mMatrix[1]); + z2.splat<2>(rhs.mMatrix[2]); + z3.splat<2>(rhs.mMatrix[3]); + + //12 muls + x0.mul(mMatrix[0]); + x1.mul(mMatrix[0]); + x2.mul(mMatrix[0]); + x3.mul(mMatrix[0]); + + y0.mul(mMatrix[1]); + y1.mul(mMatrix[1]); + y2.mul(mMatrix[1]); + y3.mul(mMatrix[1]); + + z0.mul(mMatrix[2]); + z1.mul(mMatrix[2]); + z2.mul(mMatrix[2]); + z3.mul(mMatrix[2]); + + //9 adds + x0.add(y0); + + x1.add(y1); + + x2.add(y2); + + x3.add(y3); + z3.add(mMatrix[3]); + + mMatrix[0].setAdd(x0,z0); + mMatrix[1].setAdd(x1,z1); + mMatrix[2].setAdd(x2,z2); + mMatrix[3].setAdd(x3,z3); + } + + inline void extractRotation_affine() + { + static const LLVector4Logical mask = _mm_load_ps((F32*)&S_V4LOGICAL_MASK_TABLE[3*4]); + mMatrix[0].setSelectWithMask(mask,_mm_setzero_ps(),mMatrix[0]); + mMatrix[1].setSelectWithMask(mask,_mm_setzero_ps(),mMatrix[1]); + mMatrix[2].setSelectWithMask(mask,_mm_setzero_ps(),mMatrix[2]); + mMatrix[3].setSelectWithMask(mask,LLVector4a(1.f),_mm_setzero_ps()); + } + + //======================Logic==================== +private: + template inline void init_foos(LLMatrix4a& foos) const + { + static bool done(false); + if (done) return; + const LLVector4a delta(0.0001f); + foos.setIdentity(); + foos.getRow<0>().sub(delta); + foos.getRow<1>().sub(delta); + foos.getRow<2>().sub(delta); + foos.getRow<3>().sub(delta); + done = true; + } + +public: + inline bool isIdentity() const + { + static LLMatrix4a mins; + static LLMatrix4a maxs; + + init_foos(mins); + init_foos(maxs); + + LLVector4a mask1 = _mm_and_ps(_mm_cmpgt_ps(mMatrix[0],mins.getRow<0>()), _mm_cmplt_ps(mMatrix[0],maxs.getRow<0>())); + LLVector4a mask2 = _mm_and_ps(_mm_cmpgt_ps(mMatrix[1],mins.getRow<1>()), _mm_cmplt_ps(mMatrix[1],maxs.getRow<1>())); + LLVector4a mask3 = _mm_and_ps(_mm_cmpgt_ps(mMatrix[2],mins.getRow<2>()), _mm_cmplt_ps(mMatrix[2],maxs.getRow<2>())); + LLVector4a mask4 = _mm_and_ps(_mm_cmpgt_ps(mMatrix[3],mins.getRow<3>()), _mm_cmplt_ps(mMatrix[3],maxs.getRow<3>())); + + mask1 = _mm_and_ps(mask1,mask2); + mask2 = _mm_and_ps(mask3,mask4); + + return _mm_movemask_epi8(_mm_castps_si128(_mm_and_ps(mask1, mask2))) == 0xFFFF; + } +} LL_ALIGN_POSTFIX(16); + + +inline std::ostream& operator<<(std::ostream& s, const LLMatrix4a& m) +{ + s << "[" << m.getF32ptr()[0] << ", " << m.getF32ptr()[1] << ", " << m.getF32ptr()[2] << ", " << m.getF32ptr()[3] << "]"; + return s; +} + +void matMulBoundBox(const LLMatrix4a &a, const LLVector4a *in_extents, LLVector4a *out_extents); + +#if !defined(LL_DEBUG) +static_assert(std::is_trivial::value, "LLMatrix4a must be a trivial type"); +static_assert(std::is_standard_layout::value, "LLMatrix4a must be a standard layout type"); +#endif #endif diff --git a/indra/llmath/llmodularmath.cpp b/indra/llmath/llmodularmath.cpp index e2d573fb0a..96ead2176d 100644 --- a/indra/llmath/llmodularmath.cpp +++ b/indra/llmath/llmodularmath.cpp @@ -2,36 +2,28 @@ * @file llmodularmath.cpp * @brief LLModularMath class implementation * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2010, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlife.com/developers/opensource/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ - * */ - #include "linden_common.h" // implementation is all in the header, this include dep ensures the unit test is rerun if the implementation changes. diff --git a/indra/llmath/llmodularmath.h b/indra/llmath/llmodularmath.h index 60095293c9..1caff880d7 100644 --- a/indra/llmath/llmodularmath.h +++ b/indra/llmath/llmodularmath.h @@ -2,31 +2,25 @@ * @file llmodularmath.h * @brief Useful modular math functions. * - * $LicenseInfo:firstyear=2008&license=viewergpl$ - * - * Copyright (c) 2008-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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$ */ diff --git a/indra/llmath/lloctree.h b/indra/llmath/lloctree.h index b5252d0550..f82a08f3ef 100644 --- a/indra/llmath/lloctree.h +++ b/indra/llmath/lloctree.h @@ -45,6 +45,7 @@ #endif extern U32 gOctreeMaxCapacity; +extern float gOctreeMinSize; extern U32 gOctreeReserveCapacity; #if LL_DEBUG #define LL_OCTREE_PARANOIA_CHECK 0 @@ -110,7 +111,7 @@ class OctreeStats : public LLSingleton } void dump() { - llinfos << llformat("Lifetime: Allocs:(+%u|-%u) Allocs/s: (+%lf|-%lf) Nodes: %u AccumSize: %llubytes Avg: %lf LargestSize: %u", + LL_INFOS() << llformat("Lifetime: Allocs:(+%u|-%u) Allocs/s: (+%lf|-%lf) Nodes: %u AccumSize: %llubytes Avg: %lf LargestSize: %u", mTotalAllocs, mTotalFrees, F64(mTotalAllocs)/mTotalTimer.getElapsedTimeF64(), @@ -119,8 +120,8 @@ class OctreeStats : public LLSingleton mTotalSize*sizeof(LLPointer), F64(mTotalSize)/F64(mTotalNodes), mLargestSize - ) << llendl; - llinfos << llformat("Timeslice: Allocs:(+%u|-%u) Allocs/s: (+%lf|-%lf) Nodes:(+%u|-%u) LargestSize: %u", + ) << LL_ENDL; + LL_INFOS() << llformat("Timeslice: Allocs:(+%u|-%u) Allocs/s: (+%lf|-%lf) Nodes:(+%u|-%u) LargestSize: %u", mPeriodAllocs, mPeriodFrees, F64(mPeriodAllocs)/mPeriodTimer.getElapsedTimeF64(), @@ -128,7 +129,7 @@ class OctreeStats : public LLSingleton mPeriodNodesCreated, mPeriodNodesDestroyed, mPeriodLargestSize - ) << llendl; + ) << LL_ENDL; mPeriodNodesCreated=0; mPeriodNodesDestroyed=0; @@ -197,7 +198,7 @@ struct OctreeGuard { if((*it)->mNode == node) { - OCT_ERRS << "!!! MANIPULATING OCTREE BRANCH DURING ITERATION !!!" << llendl; + OCT_ERRS << "!!! MANIPULATING OCTREE BRANCH DURING ITERATION !!!" << LL_ENDL; return true; } } @@ -404,7 +405,7 @@ class LLOctreeNode : public LLTreeNode F32 size = mSize[0]; F32 p_size = size * 2.f; - return (radius <= 0.001f && size <= 0.001f) || + return (radius <= gOctreeMinSize && size <= gOctreeMinSize) || (radius <= p_size && radius > size); } @@ -425,7 +426,7 @@ class LLOctreeNode : public LLTreeNode } void accept(oct_traveler* visitor) { visitor->visit(this); } - virtual bool isLeaf() const { return mChildCount == 0; } + bool isLeaf() const { return mChildCount == 0; } U32 getElementCount() const { return mData.size(); } bool isEmpty() const { return mData.size() == 0; } @@ -456,12 +457,12 @@ class LLOctreeNode : public LLTreeNode if (child->getOctant() != i) { - llerrs << "Invalid child map, bad octant data." << llendl; + LL_ERRS() << "Invalid child map, bad octant data." << LL_ENDL; } if (getOctant(child->getCenter()) != child->getOctant()) { - llerrs << "Invalid child octant compared to position data." << llendl; + LL_ERRS() << "Invalid child octant compared to position data." << LL_ENDL; } } } @@ -498,12 +499,12 @@ class LLOctreeNode : public LLTreeNode return node; } - virtual bool insert(T* data) + bool insert(T* data) override { OctreeGuard::checkGuarded(this); if (data == NULL || data->getBinIndex() != -1) { - OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE BRANCH !!!" << llendl; + OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE BRANCH !!!" << LL_ENDL; return false; } LLOctreeNode* parent = getOctParent(); @@ -511,7 +512,7 @@ class LLOctreeNode : public LLTreeNode //is it here? if (isInside(data->getPositionGroup())) { - if (((getElementCount() < gOctreeMaxCapacity && contains(data->getBinRadius())) || + if ((((getElementCount() < gOctreeMaxCapacity || getSize()[0] <= gOctreeMinSize) && contains(data->getBinRadius())) || (data->getBinRadius() > getSize()[0] && parent && parent->getElementCount() >= gOctreeMaxCapacity))) { //it belongs here /*mElementCount++; @@ -537,7 +538,7 @@ class LLOctreeNode : public LLTreeNode OctreeStats::getInstance()->realloc(old_cap,mData.capacity()); #endif - BaseType::insert(data); + LLOctreeNode::notifyAddition(data); return true; } else @@ -566,8 +567,9 @@ class LLOctreeNode : public LLTreeNode LLVector4a val; val.setSub(center, getCenter()); val.setAbs(val); - - S32 lt = val.lessThan(LLVector4a::getEpsilon()).getGatheredBits() & 0x7; + LLVector4a min_diff(gOctreeMinSize); + + S32 lt = val.lessThan(min_diff).getGatheredBits() & 0x7; if( lt == 0x7 ) { @@ -593,7 +595,7 @@ class LLOctreeNode : public LLTreeNode OctreeStats::getInstance()->realloc(old_cap,mData.capacity()); #endif - BaseType::insert(data); + LLOctreeNode::notifyAddition(data); return true; } @@ -601,7 +603,7 @@ class LLOctreeNode : public LLTreeNode if (getChildCount() == 8) { //this really isn't possible, something bad has happened - OCT_ERRS << "Octree detected floating point error and gave up." << llendl; + OCT_ERRS << "Octree detected floating point error and gave up." << LL_ENDL; return false; } @@ -610,12 +612,13 @@ class LLOctreeNode : public LLTreeNode { if (mChild[i]->getCenter().equals3(center)) { - OCT_ERRS << "Octree detected duplicate child center and gave up." << llendl; + OCT_ERRS << "Octree detected duplicate child center and gave up." << LL_ENDL; return false; } } #endif + llassert(size[0] >= gOctreeMinSize*0.5f); //make the new kid child = new LLOctreeNode(center, size, this); addChild(child); @@ -623,10 +626,10 @@ class LLOctreeNode : public LLTreeNode child->insert(data); } } - else + else if (parent) { //it's not in here, give it to the root - OCT_ERRS << "Octree insertion failed, starting over from root!" << llendl; + OCT_ERRS << "Octree insertion failed, starting over from root!" << LL_ENDL; oct_node* node = this; @@ -636,10 +639,14 @@ class LLOctreeNode : public LLTreeNode parent = node->getOctParent(); } - if(node != this) - { - node->insert(data); - } + node->insert(data); + } + else + { + // It's not in here, and we are root. + // LLOctreeRoot::insert() should have expanded + // root by now, something is wrong + OCT_ERRS << "Octree insertion failed! Root expansion failed." << LL_ENDL; } return false; @@ -692,14 +699,7 @@ class LLOctreeNode : public LLTreeNode (mData.size() > gOctreeReserveCapacity && mData.capacity() > gOctreeReserveCapacity + mData.size() - 1 - (mData.size() - gOctreeReserveCapacity - 1) % 4)) { //Shrink to lowest possible (reserve)+4*i size.. Say reserve is 5, here are [size,capacity] pairs. [10,13],[9,9],[8,9],[7,9],[6,9],[5,5],[4,5],[3,5],[2,5],[1,5],[0,5] - //For Windows: We always assume vs2010 or later, which support this c++11 feature with no configuration needed. - //For GCC: __cplusplus >= 201103L indicates C++11 support. __GXX_EXPERIMENTAL_CXX0X being set indicates experimental c++0x support. C++11 support replaces C++0x support. - // std::vector::shrink_to_fit was added to GCCs C++0x implementation in version 4.5.0. -#if defined(LL_WINDOWS) || __cplusplus >= 201103L || (defined(__GXX_EXPERIMENTAL_CXX0X) && __GNUC_MINOR__ >= 5) mData.shrink_to_fit(); -#else - std::vector >(mData.begin(), mData.end()).swap(mData); //Need to confirm this works on OSX.. -#endif } #ifdef LL_OCTREE_STATS if(old_cap != mData.capacity()) @@ -711,7 +711,7 @@ class LLOctreeNode : public LLTreeNode checkAlive(); } - bool remove(T* data) + bool remove(T* data) final override { OctreeGuard::checkGuarded(this); S32 i = data->getBinIndex(); @@ -752,7 +752,7 @@ class LLOctreeNode : public LLTreeNode } //node is now root - llwarns << "!!! OCTREE REMOVING ELEMENT BY ADDRESS, SEVERE PERFORMANCE PENALTY |||" << llendl; + LL_WARNS() << "!!! OCTREE REMOVING ELEMENT BY ADDRESS, SEVERE PERFORMANCE PENALTY |||" << LL_ENDL; node->removeByAddress(data); llassert(data->getBinIndex() == -1); return true; @@ -767,7 +767,7 @@ class LLOctreeNode : public LLTreeNode if (mData[i] == data) { //we have data _remove(data, i); - llwarns << "FOUND!" << llendl; + LL_WARNS() << "FOUND!" << LL_ENDL; return; } } @@ -796,7 +796,7 @@ class LLOctreeNode : public LLTreeNode mChild[i]->validate(); if (mChild[i]->getParent() != this) { - llerrs << "Octree child has invalid parent." << llendl; + LL_ERRS() << "Octree child has invalid parent." << LL_ENDL; } } #endif @@ -822,24 +822,24 @@ class LLOctreeNode : public LLTreeNode if (child->getSize().equals3(getSize())) { - OCT_ERRS << "Child size is same as parent size!" << llendl; + OCT_ERRS << "Child size is same as parent size!" << LL_ENDL; } for (U32 i = 0; i < getChildCount(); i++) { if(!mChild[i]->getSize().equals3(child->getSize())) { - OCT_ERRS <<"Invalid octree child size." << llendl; + OCT_ERRS <<"Invalid octree child size." << LL_ENDL; } if (mChild[i]->getCenter().equals3(child->getCenter())) { - OCT_ERRS <<"Duplicate octree child position." << llendl; + OCT_ERRS <<"Duplicate octree child position." << LL_ENDL; } } if (mChild.size() >= 8) { - OCT_ERRS <<"Octree node has too many children... why?" << llendl; + OCT_ERRS <<"Octree node has too many children... why?" << LL_ENDL; } #endif OctreeGuard::checkGuarded(this); @@ -852,10 +852,9 @@ class LLOctreeNode : public LLTreeNode if (!silent) { - for (U32 i = 0; i < this->getListenerCount(); i++) + for (auto& entry : this->mListeners) { - oct_listener* listener = getOctListener(i); - listener->handleChildAddition(this, child); + ((oct_listener*)entry.get())->handleChildAddition(this, child); } } } @@ -864,16 +863,17 @@ class LLOctreeNode : public LLTreeNode { OctreeGuard::checkGuarded(this); - for (U32 i = 0; i < this->getListenerCount(); i++) + oct_node* child = getChild(index); + + for (auto& entry : this->mListeners) { - oct_listener* listener = getOctListener(i); - listener->handleChildRemoval(this, getChild(index)); + ((oct_listener*)entry.get())->handleChildRemoval(this, child); } if (destroy) { - mChild[index]->destroy(); - delete mChild[index]; + child->destroy(); + delete child; } --mChildCount; @@ -916,7 +916,7 @@ class LLOctreeNode : public LLTreeNode } } - OCT_ERRS << "Octree failed to delete requested child." << llendl; + OCT_ERRS << "Octree failed to delete requested child." << LL_ENDL; } protected: @@ -928,10 +928,10 @@ class LLOctreeNode : public LLTreeNode MIN = 3 } eDName; - LLVector4a mCenter; - LLVector4a mSize; - LLVector4a mMax; - LLVector4a mMin; + LL_ALIGN_16(LLVector4a mCenter); + LL_ALIGN_16(LLVector4a mSize); + LL_ALIGN_16(LLVector4a mMax); + LL_ALIGN_16(LLVector4a mMin); oct_node* mParent; U8 mOctant; @@ -960,6 +960,26 @@ class LLOctreeRoot : public LLOctreeNode : BaseType(center, size, parent) { } + +#ifdef LL_OCTREE_POOLS + void* operator new(size_t size) + { + return LLOctreeNode::getPool(size).malloc(); + } + void operator delete(void* ptr) + { + LLOctreeNode::getPool(sizeof(LLOctreeNode)).free(ptr); + } +#else + void* operator new(size_t size) + { + return ll_aligned_malloc_16(size); + } + void operator delete(void* ptr) + { + ll_aligned_free_16(ptr); + } +#endif bool balance() { @@ -995,22 +1015,22 @@ class LLOctreeRoot : public LLOctreeNode } // LLOctreeRoot::insert - bool insert(T* data) + bool insert(T* data) final override { if (data == NULL) { - OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE ROOT !!!" << llendl; + OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE ROOT !!!" << LL_ENDL; return false; } if (data->getBinRadius() > 4096.0) { - OCT_ERRS << "!!! ELEMENT EXCEEDS MAXIMUM SIZE IN OCTREE ROOT !!!" << llendl; + OCT_ERRS << "!!! ELEMENT EXCEEDS MAXIMUM SIZE IN OCTREE ROOT !!!" << LL_ENDL; return false; } LLVector4a MAX_MAG; - MAX_MAG.splat(1024.f*1024.f); + MAX_MAG.splat(1024.f * 1024.f); const LLVector4a& v = data->getPositionGroup(); @@ -1021,7 +1041,7 @@ class LLOctreeRoot : public LLOctreeNode if (lt != 0x7) { - //OCT_ERRS << "!!! ELEMENT EXCEEDS RANGE OF SPATIAL PARTITION !!!" << llendl; + //OCT_ERRS << "!!! ELEMENT EXCEEDS RANGE OF SPATIAL PARTITION !!!" << LL_ENDL; return false; } @@ -1033,10 +1053,15 @@ class LLOctreeRoot : public LLOctreeNode { LLOctreeNode::insert(data); } - else + else if (node->isInside(data->getPositionGroup())) { node->insert(data); } + else + { + // calling node->insert(data) will return us to root + OCT_ERRS << "Failed to insert data at child node" << LL_ENDL; + } } else if (this->getChildCount() == 0) { @@ -1071,6 +1096,8 @@ class LLOctreeRoot : public LLOctreeNode this->setSize(size2); this->updateMinMax(); + llassert(size[0] >= gOctreeMinSize); + //copy our children to a new branch LLOctreeNode* newnode = new LLOctreeNode(center, size, this); diff --git a/indra/llmath/llperlin.cpp b/indra/llmath/llperlin.cpp index 9293d972a4..f0ecb38c3d 100644 --- a/indra/llmath/llperlin.cpp +++ b/indra/llmath/llperlin.cpp @@ -1,300 +1,57 @@ /** * @file llperlin.cpp * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #include "linden_common.h" -#include "llmath.h" - #include "llperlin.h" -#define B 0x100 -#define BM 0xff -#define N 0x1000 -#define NF32 (4096.f) -#define NP 12 /* 2^N */ -#define NM 0xfff - -static S32 p[B + B + 2]; -static F32 g3[B + B + 2][3]; -static F32 g2[B + B + 2][2]; -static F32 g1[B + B + 2]; - -bool LLPerlinNoise::sInitialized = 0; - -static void normalize2(F32 v[2]) -{ - F32 s = 1.f/(F32)sqrt(v[0] * v[0] + v[1] * v[1]); - v[0] = v[0] * s; - v[1] = v[1] * s; -} - -static void normalize3(F32 v[3]) -{ - F32 s = 1.f/(F32)sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); - v[0] = v[0] * s; - v[1] = v[1] * s; - v[2] = v[2] * s; -} - -static void fast_setup(F32 vec, U8 &b0, U8 &b1, F32 &r0, F32 &r1) -{ - S32 t_S32; - - r1 = vec + NF32; - t_S32 = lltrunc(r1); - b0 = (U8)t_S32; - b1 = b0 + 1; - r0 = r1 - t_S32; - r1 = r0 - 1.f; -} - - -void LLPerlinNoise::init(void) -{ - int i, j, k; - - for (i = 0 ; i < B ; i++) - { - p[i] = i; - - g1[i] = (F32)((rand() % (B + B)) - B) / B; - - for (j = 0 ; j < 2 ; j++) - g2[i][j] = (F32)((rand() % (B + B)) - B) / B; - normalize2(g2[i]); - - for (j = 0 ; j < 3 ; j++) - g3[i][j] = (F32)((rand() % (B + B)) - B) / B; - normalize3(g3[i]); - } - - while (--i) - { - k = p[i]; - p[i] = p[j = rand() % B]; - p[j] = k; - } - - for (i = 0 ; i < B + 2 ; i++) - { - p[B + i] = p[i]; - g1[B + i] = g1[i]; - for (j = 0 ; j < 2 ; j++) - g2[B + i][j] = g2[i][j]; - for (j = 0 ; j < 3 ; j++) - g3[B + i][j] = g3[i][j]; - } - - sInitialized = true; -} - - -//============================================================================ -// Noise functions - -#define s_curve(t) ( t * t * (3.f - 2.f * t) ) - -#define lerp_m(t, a, b) ( a + t * (b - a) ) - -F32 LLPerlinNoise::noise1(F32 x) -{ - int bx0, bx1; - F32 rx0, rx1, sx, t, u, v; - - if (!sInitialized) - init(); - - t = x + N; - bx0 = (lltrunc(t)) & BM; - bx1 = (bx0+1) & BM; - rx0 = t - lltrunc(t); - rx1 = rx0 - 1.f; - - sx = s_curve(rx0); - - u = rx0 * g1[ p[ bx0 ] ]; - v = rx1 * g1[ p[ bx1 ] ]; - - return lerp_m(sx, u, v); -} - -static F32 fast_at2(F32 rx, F32 ry, F32 *q) -{ - return rx * q[0] + ry * q[1]; -} - -F32 LLPerlinNoise::noise2(F32 x, F32 y) -{ - U8 bx0, bx1, by0, by1; - U32 b00, b10, b01, b11; - F32 rx0, rx1, ry0, ry1, *q, sx, sy, a, b, u, v; - S32 i, j; - - if (!sInitialized) - init(); - - fast_setup(x, bx0, bx1, rx0, rx1); - fast_setup(y, by0, by1, ry0, ry1); - - i = *(p + bx0); - j = *(p + bx1); - - b00 = *(p + i + by0); - b10 = *(p + j + by0); - b01 = *(p + i + by1); - b11 = *(p + j + by1); - - sx = s_curve(rx0); - sy = s_curve(ry0); - - - q = *(g2 + b00); - u = fast_at2(rx0, ry0, q); - q = *(g2 + b10); - v = fast_at2(rx1, ry0, q); - a = lerp_m(sx, u, v); - - q = *(g2 + b01); - u = fast_at2(rx0,ry1,q); - q = *(g2 + b11); - v = fast_at2(rx1,ry1,q); - b = lerp_m(sx, u, v); - - return lerp_m(sy, a, b); -} - -static F32 fast_at3(F32 rx, F32 ry, F32 rz, F32 *q) -{ - return rx * q[0] + ry * q[1] + rz * q[2]; -} - -F32 LLPerlinNoise::noise3(F32 x, F32 y, F32 z) -{ - U8 bx0, bx1, by0, by1, bz0, bz1; - S32 b00, b10, b01, b11; - F32 rx0, rx1, ry0, ry1, rz0, rz1, *q, sy, sz, a, b, c, d, t, u, v; - S32 i, j; - - if (!sInitialized) - init(); - - fast_setup(x, bx0,bx1, rx0,rx1); - fast_setup(y, by0,by1, ry0,ry1); - fast_setup(z, bz0,bz1, rz0,rz1); - - i = p[ bx0 ]; - j = p[ bx1 ]; - - b00 = p[ i + by0 ]; - b10 = p[ j + by0 ]; - b01 = p[ i + by1 ]; - b11 = p[ j + by1 ]; - - t = s_curve(rx0); - sy = s_curve(ry0); - sz = s_curve(rz0); - - q = g3[ b00 + bz0 ]; - u = fast_at3(rx0,ry0,rz0,q); - q = g3[ b10 + bz0 ]; - v = fast_at3(rx1,ry0,rz0,q); - a = lerp_m(t, u, v); - - q = g3[ b01 + bz0 ]; - u = fast_at3(rx0,ry1,rz0,q); - q = g3[ b11 + bz0 ]; - v = fast_at3(rx1,ry1,rz0,q); - b = lerp_m(t, u, v); - - c = lerp_m(sy, a, b); - - q = g3[ b00 + bz1 ]; - u = fast_at3(rx0,ry0,rz1,q); - q = g3[ b10 + bz1 ]; - v = fast_at3(rx1,ry0,rz1,q); - a = lerp_m(t, u, v); - - q = g3[ b01 + bz1 ]; - u = fast_at3(rx0,ry1,rz1,q); - q = g3[ b11 + bz1 ]; - v = fast_at3(rx1,ry1,rz1,q); - b = lerp_m(t, u, v); - - d = lerp_m(sy, a, b); - - return lerp_m(sz, c, d); -} - -F32 LLPerlinNoise::turbulence2(F32 x, F32 y, F32 freq) -{ - F32 t, lx, ly; - - for (t = 0.f ; freq >= 1.f ; freq *= 0.5f) - { - lx = freq * x; - ly = freq * y; - t += noise2(lx, ly)/freq; - } - return t; -} - -F32 LLPerlinNoise::turbulence3(F32 x, F32 y, F32 z, F32 freq) -{ - F32 t, lx, ly, lz; - - for (t = 0.f ; freq >= 1.f ; freq *= 0.5f) - { - lx = freq * x; - ly = freq * y; - lz = freq * z; - t += noise3(lx,ly,lz)/freq; -// t += fabs(noise3(lx,ly,lz)) / freq; // Like snow - bubbly at low frequencies -// t += sqrt(fabs(noise3(lx,ly,lz))) / freq; // Better at low freq -// t += (noise3(lx,ly,lz)*noise3(lx,ly,lz)) / freq; - } - return t; -} - -F32 LLPerlinNoise::clouds3(F32 x, F32 y, F32 z, F32 freq) -{ - F32 t, lx, ly, lz; - - for (t = 0.f ; freq >= 1.f ; freq *= 0.5f) - { - lx = freq * x; - ly = freq * y; - lz = freq * z; -// t += noise3(lx,ly,lz)/freq; -// t += fabs(noise3(lx,ly,lz)) / freq; // Like snow - bubbly at low frequencies -// t += sqrt(fabs(noise3(lx,ly,lz))) / freq; // Better at low freq - t += (noise3(lx,ly,lz)*noise3(lx,ly,lz)) / freq; - } - return t; -} +//Random values taken from http://mrl.nyu.edu/~perlin/noise/ +const U8 LLPerlinNoise::p[LLPerlinNoise::sPremutationCount] = +{ 151, 160, 137, 91, 90, 15, +131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, +190, 6, 148, 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, +88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, +77, 146, 158, 231, 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, +102, 143, 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196, +135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124, 123, +5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42, +223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9, +129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, 218, 246, 97, 228, +251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81, 51, 145, 235, 249, 14, 239, 107, +49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, +138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180, +151, 160, 137, 91, 90, 15, +131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, +190, 6, 148, 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, +88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, +77, 146, 158, 231, 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, +102, 143, 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196, +135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124, 123, +5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42, +223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9, +129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, 218, 246, 97, 228, +251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81, 51, 145, 235, 249, 14, 239, 107, +49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, +138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180 +}; diff --git a/indra/llmath/llperlin.h b/indra/llmath/llperlin.h index e8815ece58..c6e49178a5 100644 --- a/indra/llmath/llperlin.h +++ b/indra/llmath/llperlin.h @@ -1,31 +1,25 @@ /** * @file llperlin.h * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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$ */ @@ -33,20 +27,149 @@ #define LL_PERLIN_H #include "stdtypes.h" +#include "llmath.h" +#include "v2math.h" +#include "v3math.h" // namespace wrapper class LLPerlinNoise { public: - static F32 noise1(F32 x); - static F32 noise2(F32 x, F32 y); - static F32 noise3(F32 x, F32 y, F32 z); - static F32 turbulence2(F32 x, F32 y, F32 freq); - static F32 turbulence3(F32 x, F32 y, F32 z, F32 freq); - static F32 clouds3(F32 x, F32 y, F32 z, F32 freq); + static F32 noise(const F32& x, U32 wrap_at = 256) + { + U8 b[1][2]; + F32 r[1][2], s[1], u, v; + + fast_setup(&x, b, r, s, wrap_at); + + u = grad(p[b[VX][0]], r[VX][0]); + v = grad(p[b[VX][1]], r[VX][1]); + + return lerp(u, v, s[VX]); + } + static F32 noise(const LLVector2& vec, U32 wrap_at = 256) + { + U8 b[2][2]; + F32 r[2][2], s[2], u, v, A, B; + + fast_setup(vec.mV, b, r, s, wrap_at); + + u = grad(p[p[b[VX][0]] + b[VY][0]], r[VX][0], r[VY][0]); + v = grad(p[p[b[VX][1]] + b[VY][0]], r[VX][1], r[VY][0]); + A = lerp(u, v, s[VX]); + + u = grad(p[p[b[VX][0]] + b[VY][1]], r[VX][0], r[VY][1]); + v = grad(p[p[b[VX][1]] + b[VY][1]], r[VX][1], r[VY][1]); + B = lerp(u, v, s[VX]); + + return lerp(A, B, s[VY]); + } + static F32 noise(const LLVector3& vec, U32 wrap_at = 256) + { + U8 b[3][2]; + F32 r[3][2], s[3], u, v, A, B, C, D; + + fast_setup(vec.mV, b, r, s, wrap_at); + + u = grad(p[p[p[b[VX][0]] + b[VY][0]] + b[VZ][0]], r[VX][0], r[VY][0], r[VZ][0]); + v = grad(p[p[p[b[VX][1]] + b[VY][0]] + b[VZ][0]], r[VX][1], r[VY][0], r[VZ][0]); + A = lerp(u, v, s[VX]); + + u = grad(p[p[p[b[VX][0]] + b[VY][1]] + b[VZ][0]], r[VX][0], r[VY][1], r[VZ][0]); + v = grad(p[p[p[b[VX][1]] + b[VY][1]] + b[VZ][0]], r[VX][1], r[VY][1], r[VZ][0]); + B = lerp(u, v, s[VX]); + + C = lerp(A, B, s[VY]); + + u = grad(p[p[p[b[VX][0]] + b[VY][0]] + b[VZ][1]], r[VX][0], r[VY][0], r[VZ][1]); + v = grad(p[p[p[b[VX][1]] + b[VY][0]] + b[VZ][1]], r[VX][1], r[VY][0], r[VZ][1]); + A = lerp(u, v, s[VX]); + + u = grad(p[p[p[b[VX][0]] + b[VY][1]] + b[VZ][1]], r[VX][0], r[VY][1], r[VZ][1]); + v = grad(p[p[p[b[VX][1]] + b[VY][1]] + b[VZ][1]], r[VX][1], r[VY][1], r[VZ][1]); + B = lerp(u, v, s[VX]); + + D = lerp(A, B, s[VY]); + + return lerp(C, D, s[VZ]) * 0.77f; + } + template + static F32 turbulence(const T& vec, F32 freq, U32 wrap_at = 256) + { + F32 t; + for (t = 0.f; freq >= 1.f; freq *= 0.5f) + { + t += noise(vec * freq, wrap_at) / freq; + // t += fabs(noise(vec * freq)) / freq; // Like snow - bubbly at low frequencies + // t += sqrt(fabs(noise(vec * freq))) / freq; // Better at low freq + // t += (noise(vec * freq)*noise(vec * freq)) / freq; + } + return t; + } + template + static F32 clouds(const T& vec, F32 freq, U32 wrap_at = 256) + { + F32 t; + for (t = 0.f; freq >= 1.f; freq *= 0.5f) + { + // t += noise(vec * freq)/freq; + // t += fabs(noise(vec * freq)) / freq; // Like snow - bubbly at low frequencies + // t += sqrt(fabs(noise(vec * freq))) / freq; // Better at low freq + t += (noise(vec * freq, wrap_at)*noise(vec * freq, wrap_at)) / freq; + } + return t; + } private: - static bool sInitialized; - static void init(void); + static F32 s_curve(const F32 t) + { + return t * t * t * (t * (6.f * t - 15.f) + 10.f); //5th degree + //return t * t * (3.f - 2.f * t); //3rd degree + } + + static F32 grad(U32 hash, F32 x) + { + return x * (2.f*F32(hash) / 255.f - 1.f); + } + + static F32 grad(U32 hash, F32 x, F32 y) + { + //Rotated slightly off the axes. Reduces directional artifacts. + //Scaled to match the old perlin method's output range + static const F32 l[2] = { .466666667f, .933333332f }; + static const LLVector2 vecs[] = { + LLVector2(l[0], l[1]), LLVector2(l[0], -l[1]), LLVector2(-l[0], l[1]), LLVector2(-l[0], -l[1]), + LLVector2(l[1], l[0]), LLVector2(l[1], -l[0]), LLVector2(-l[1], l[0]), LLVector2(-l[1], -l[0]) }; + + return vecs[hash % LL_ARRAY_SIZE(vecs)] * LLVector2(x, y); + } + + static F32 grad(U32 hash, F32 x, F32 y, F32 z) + { + static const LLVector3 vecs[] = { + OO_SQRT3*LLVector3(1, 1, 0), OO_SQRT3*LLVector3(-1, 1, 0), OO_SQRT3*LLVector3(1, -1, 0), OO_SQRT3*LLVector3(-1, -1, 0), + OO_SQRT3*LLVector3(1, 0, 1), OO_SQRT3*LLVector3(-1, 0, 1), OO_SQRT3*LLVector3(1, 0, -1), OO_SQRT3*LLVector3(-1, 0, -1), + OO_SQRT3*LLVector3(0, 1, 1), OO_SQRT3*LLVector3(0, -1, 1), OO_SQRT3*LLVector3(0, 1, -1), OO_SQRT3*LLVector3(0, -1, -1) }; + + return vecs[hash % LL_ARRAY_SIZE(vecs)] * LLVector3(x, y, z); + } + + template + static void fast_setup(const F32* vec, U8 (&b)[N][2], F32 (&r)[N][2], F32 (&s)[N], const U32& wrap_at) + { + const U32 limit = llclamp(wrap_at, U32(1), U32(256)); + for (U32 i = 0; i < N; ++i) + { + const S32 t_S32 = llfloor(vec[i]); + b[i][0] = (t_S32) % limit; + b[i][1] = (t_S32 + 1) % limit; + r[i][0] = vec[i] - F32(t_S32); + r[i][1] = r[i][0] - 1.f; + s[i] = s_curve(r[i][0]); + } + } + + static const U32 sPremutationCount = 512; + static const U8 p[sPremutationCount]; }; #endif // LL_PERLIN_ diff --git a/indra/llmath/llplane.h b/indra/llmath/llplane.h index 44c8327f5b..e1aa741f12 100644 --- a/indra/llmath/llplane.h +++ b/indra/llmath/llplane.h @@ -1,31 +1,25 @@ /** * @file llplane.h * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -49,7 +43,7 @@ class LLPlane public: // Constructors - LLPlane() {}; // no default constructor + LLPlane() = default; // no default constructor LLPlane(const LLVector3 &p0, F32 d) { setVec(p0, d); } LLPlane(const LLVector3 &p0, const LLVector3 &n) { setVec(p0, n); } inline void setVec(const LLVector3 &p0, F32 d) { mV.set(p0[0], p0[1], p0[2], d); } @@ -100,10 +94,18 @@ class LLPlane return mV.greaterEqual(LLVector4a::getZero()).getGatheredBits() & LLVector4Logical::MASK_XYZ; } + //check if two planes are nearly same + bool equal(const LLPlane& p) const + { + return mV.equals4(p.mV); + } + private: - LLVector4a mV; + LL_ALIGN_16(LLVector4a mV); } LL_ALIGN_POSTFIX(16); - - +#if !defined(LL_DEBUG) +static_assert(std::is_trivial::value, "LLPlane must be a trivial type"); +static_assert(std::is_standard_layout::value, "LLPlane must be a standard layout type"); +#endif #endif // LL_LLPLANE_H diff --git a/indra/llmath/llquantize.h b/indra/llmath/llquantize.h index c043f7f752..9bcd2607d1 100644 --- a/indra/llmath/llquantize.h +++ b/indra/llmath/llquantize.h @@ -3,31 +3,25 @@ * @brief useful routines for quantizing floats to various length ints * and back out again * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -58,7 +52,7 @@ inline U16 F32_to_U16_ROUND(F32 val, F32 lower, F32 upper) val /= (upper - lower); // round the value. Sreturn the U16 - return (U16)(llround(val*U16MAX)); + return (U16)(ll_round(val*U16MAX)); } @@ -98,7 +92,7 @@ inline U8 F32_to_U8_ROUND(F32 val, F32 lower, F32 upper) val /= (upper - lower); // return the rounded U8 - return (U8)(llround(val*U8MAX)); + return (U8)(ll_round(val*U8MAX)); } diff --git a/indra/llmath/llquaternion.cpp b/indra/llmath/llquaternion.cpp index 73c5f4505e..1529b25876 100644 --- a/indra/llmath/llquaternion.cpp +++ b/indra/llmath/llquaternion.cpp @@ -2,31 +2,25 @@ * @file llquaternion.cpp * @brief LLQuaternion class implementation. * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -64,34 +58,40 @@ LLQuaternion::LLQuaternion(const LLMatrix3 &mat) LLQuaternion::LLQuaternion(F32 angle, const LLVector4 &vec) { - LLVector3 v(vec.mV[VX], vec.mV[VY], vec.mV[VZ]); - v.normalize(); - - F32 c, s; - c = cosf(angle*0.5f); - s = sinf(angle*0.5f); - - mQ[VX] = v.mV[VX] * s; - mQ[VY] = v.mV[VY] * s; - mQ[VZ] = v.mV[VZ] * s; - mQ[VW] = c; - normalize(); + F32 mag = sqrtf(vec.mV[VX] * vec.mV[VX] + vec.mV[VY] * vec.mV[VY] + vec.mV[VZ] * vec.mV[VZ]); + if (mag > FP_MAG_THRESHOLD) + { + angle *= 0.5; + F32 c = cosf(angle); + F32 s = sinf(angle) / mag; + mQ[VX] = vec.mV[VX] * s; + mQ[VY] = vec.mV[VY] * s; + mQ[VZ] = vec.mV[VZ] * s; + mQ[VW] = c; + } + else + { + loadIdentity(); + } } LLQuaternion::LLQuaternion(F32 angle, const LLVector3 &vec) { - LLVector3 v(vec); - v.normalize(); - - F32 c, s; - c = cosf(angle*0.5f); - s = sinf(angle*0.5f); - - mQ[VX] = v.mV[VX] * s; - mQ[VY] = v.mV[VY] * s; - mQ[VZ] = v.mV[VZ] * s; - mQ[VW] = c; - normalize(); + F32 mag = sqrtf(vec.mV[VX] * vec.mV[VX] + vec.mV[VY] * vec.mV[VY] + vec.mV[VZ] * vec.mV[VZ]); + if (mag > FP_MAG_THRESHOLD) + { + angle *= 0.5; + F32 c = cosf(angle); + F32 s = sinf(angle) / mag; + mQ[VX] = vec.mV[VX] * s; + mQ[VY] = vec.mV[VY] * s; + mQ[VZ] = vec.mV[VZ] * s; + mQ[VW] = c; + } + else + { + loadIdentity(); + } } LLQuaternion::LLQuaternion(const LLVector3 &x_axis, @@ -104,6 +104,11 @@ LLQuaternion::LLQuaternion(const LLVector3 &x_axis, normalize(); } +LLQuaternion::LLQuaternion(const LLSD &sd) +{ + setValue(sd); +} + // Quatizations void LLQuaternion::quantize16(F32 lower, F32 upper) { @@ -142,57 +147,61 @@ void LLQuaternion::quantize8(F32 lower, F32 upper) const LLQuaternion& LLQuaternion::setAngleAxis(F32 angle, F32 x, F32 y, F32 z) { - LLVector3 vec(x, y, z); - vec.normalize(); - - angle *= 0.5f; - F32 c, s; - c = cosf(angle); - s = sinf(angle); - - mQ[VX] = vec.mV[VX]*s; - mQ[VY] = vec.mV[VY]*s; - mQ[VZ] = vec.mV[VZ]*s; - mQ[VW] = c; - - normalize(); + F32 mag = sqrtf(x * x + y * y + z * z); + if (mag > FP_MAG_THRESHOLD) + { + angle *= 0.5; + F32 c = cosf(angle); + F32 s = sinf(angle) / mag; + mQ[VX] = x * s; + mQ[VY] = y * s; + mQ[VZ] = z * s; + mQ[VW] = c; + } + else + { + loadIdentity(); + } return (*this); } const LLQuaternion& LLQuaternion::setAngleAxis(F32 angle, const LLVector3 &vec) { - LLVector3 v(vec); - v.normalize(); - - angle *= 0.5f; - F32 c, s; - c = cosf(angle); - s = sinf(angle); - - mQ[VX] = v.mV[VX]*s; - mQ[VY] = v.mV[VY]*s; - mQ[VZ] = v.mV[VZ]*s; - mQ[VW] = c; - - normalize(); + F32 mag = sqrtf(vec.mV[VX] * vec.mV[VX] + vec.mV[VY] * vec.mV[VY] + vec.mV[VZ] * vec.mV[VZ]); + if (mag > FP_MAG_THRESHOLD) + { + angle *= 0.5; + F32 c = cosf(angle); + F32 s = sinf(angle) / mag; + mQ[VX] = vec.mV[VX] * s; + mQ[VY] = vec.mV[VY] * s; + mQ[VZ] = vec.mV[VZ] * s; + mQ[VW] = c; + } + else + { + loadIdentity(); + } return (*this); } const LLQuaternion& LLQuaternion::setAngleAxis(F32 angle, const LLVector4 &vec) { - LLVector3 v(vec.mV[VX], vec.mV[VY], vec.mV[VZ]); - v.normalize(); - - F32 c, s; - c = cosf(angle*0.5f); - s = sinf(angle*0.5f); - - mQ[VX] = v.mV[VX]*s; - mQ[VY] = v.mV[VY]*s; - mQ[VZ] = v.mV[VZ]*s; - mQ[VW] = c; - - normalize(); + F32 mag = sqrtf(vec.mV[VX] * vec.mV[VX] + vec.mV[VY] * vec.mV[VY] + vec.mV[VZ] * vec.mV[VZ]); + if (mag > FP_MAG_THRESHOLD) + { + angle *= 0.5; + F32 c = cosf(angle); + F32 s = sinf(angle) / mag; + mQ[VX] = vec.mV[VX] * s; + mQ[VY] = vec.mV[VY] * s; + mQ[VZ] = vec.mV[VZ] * s; + mQ[VW] = c; + } + else + { + loadIdentity(); + } return (*this); } @@ -225,68 +234,80 @@ const LLQuaternion& LLQuaternion::set(const LLMatrix4 &mat) // deprecated const LLQuaternion& LLQuaternion::setQuat(F32 angle, F32 x, F32 y, F32 z) { - LLVector3 vec(x, y, z); - vec.normalize(); - - angle *= 0.5f; - F32 c, s; - c = cosf(angle); - s = sinf(angle); - - mQ[VX] = vec.mV[VX]*s; - mQ[VY] = vec.mV[VY]*s; - mQ[VZ] = vec.mV[VZ]*s; - mQ[VW] = c; - - normalize(); + F32 mag = sqrtf(x * x + y * y + z * z); + if (mag > FP_MAG_THRESHOLD) + { + angle *= 0.5; + F32 c = cosf(angle); + F32 s = sinf(angle) / mag; + mQ[VX] = x * s; + mQ[VY] = y * s; + mQ[VZ] = z * s; + mQ[VW] = c; + } + else + { + loadIdentity(); + } return (*this); } // deprecated const LLQuaternion& LLQuaternion::setQuat(F32 angle, const LLVector3 &vec) { - LLVector3 v(vec); - v.normalize(); - - angle *= 0.5f; - F32 c, s; - c = cosf(angle); - s = sinf(angle); - - mQ[VX] = v.mV[VX]*s; - mQ[VY] = v.mV[VY]*s; - mQ[VZ] = v.mV[VZ]*s; - mQ[VW] = c; - - normalize(); + F32 mag = sqrtf(vec.mV[VX] * vec.mV[VX] + vec.mV[VY] * vec.mV[VY] + vec.mV[VZ] * vec.mV[VZ]); + if (mag > FP_MAG_THRESHOLD) + { + angle *= 0.5; + F32 c = cosf(angle); + F32 s = sinf(angle) / mag; + mQ[VX] = vec.mV[VX] * s; + mQ[VY] = vec.mV[VY] * s; + mQ[VZ] = vec.mV[VZ] * s; + mQ[VW] = c; + } + else + { + loadIdentity(); + } return (*this); } const LLQuaternion& LLQuaternion::setQuat(F32 angle, const LLVector4 &vec) { - LLVector3 v(vec.mV[VX], vec.mV[VY], vec.mV[VZ]); - v.normalize(); - - F32 c, s; - c = cosf(angle*0.5f); - s = sinf(angle*0.5f); - - mQ[VX] = v.mV[VX]*s; - mQ[VY] = v.mV[VY]*s; - mQ[VZ] = v.mV[VZ]*s; - mQ[VW] = c; - - normalize(); + F32 mag = sqrtf(vec.mV[VX] * vec.mV[VX] + vec.mV[VY] * vec.mV[VY] + vec.mV[VZ] * vec.mV[VZ]); + if (mag > FP_MAG_THRESHOLD) + { + angle *= 0.5; + F32 c = cosf(angle); + F32 s = sinf(angle) / mag; + mQ[VX] = vec.mV[VX] * s; + mQ[VY] = vec.mV[VY] * s; + mQ[VZ] = vec.mV[VZ] * s; + mQ[VW] = c; + } + else + { + loadIdentity(); + } return (*this); } const LLQuaternion& LLQuaternion::setQuat(F32 roll, F32 pitch, F32 yaw) { - LLMatrix3 rot_mat(roll, pitch, yaw); - rot_mat.orthogonalize(); - *this = rot_mat.quaternion(); - - normalize(); + roll *= 0.5f; + pitch *= 0.5f; + yaw *= 0.5f; + F32 sinX = sinf(roll); + F32 cosX = cosf(roll); + F32 sinY = sinf(pitch); + F32 cosY = cosf(pitch); + F32 sinZ = sinf(yaw); + F32 cosZ = cosf(yaw); + mQ[VW] = cosX * cosY * cosZ - sinX * sinY * sinZ; + mQ[VX] = sinX * cosY * cosZ + cosX * sinY * sinZ; + mQ[VY] = cosX * sinY * cosZ - sinX * cosY * sinZ; + mQ[VZ] = cosX * cosY * sinZ + sinX * sinY * cosZ; return (*this); } @@ -431,68 +452,44 @@ LLMatrix4 LLQuaternion::getMatrix4(void) const // calculate the shortest rotation from a to b void LLQuaternion::shortestArc(const LLVector3 &a, const LLVector3 &b) { - // Make a local copy of both vectors. - LLVector3 vec_a = a; - LLVector3 vec_b = b; - - // Make sure neither vector is zero length. Also normalize - // the vectors while we are at it. - F32 vec_a_mag = vec_a.normalize(); - F32 vec_b_mag = vec_b.normalize(); - if (vec_a_mag < F_APPROXIMATELY_ZERO || - vec_b_mag < F_APPROXIMATELY_ZERO) - { - // Can't calculate a rotation from this. - // Just return ZERO_ROTATION instead. - loadIdentity(); - return; - } - - // Create an axis to rotate around, and the cos of the angle to rotate. - LLVector3 axis = vec_a % vec_b; - F32 cos_theta = vec_a * vec_b; - - // Check the angle between the vectors to see if they are parallel or anti-parallel. - if (cos_theta > 1.0 - F_APPROXIMATELY_ZERO) - { - // a and b are parallel. No rotation is necessary. - loadIdentity(); - } - else if (cos_theta < -1.0 + F_APPROXIMATELY_ZERO) + F32 ab = a * b; // dotproduct + LLVector3 c = a % b; // crossproduct + F32 cc = c * c; // squared length of the crossproduct + if (ab * ab + cc) // test if the arguments have sufficient magnitude { - // a and b are anti-parallel. - // Rotate 180 degrees around some orthogonal axis. - // Find the projection of the x-axis onto a, and try - // using the vector between the projection and the x-axis - // as the orthogonal axis. - LLVector3 proj = vec_a.mV[VX] / (vec_a * vec_a) * vec_a; - LLVector3 ortho_axis(1.f, 0.f, 0.f); - ortho_axis -= proj; - - // Turn this into an orthonormal axis. - F32 ortho_length = ortho_axis.normalize(); - // If the axis' length is 0, then our guess at an orthogonal axis - // was wrong (a is parallel to the x-axis). - if (ortho_length < F_APPROXIMATELY_ZERO) + if (cc > 0.0f) // test if the arguments are (anti)parallel { - // Use the z-axis instead. - ortho_axis.setVec(0.f, 0.f, 1.f); + F32 s = sqrtf(ab * ab + cc) + ab; // note: don't try to optimize this line + F32 m = 1.0f / sqrtf(cc + s * s); // the inverted magnitude of the quaternion + mQ[VX] = c.mV[VX] * m; + mQ[VY] = c.mV[VY] * m; + mQ[VZ] = c.mV[VZ] * m; + mQ[VW] = s * m; + return; + } + if (ab < 0.0f) // test if the angle is bigger than PI/2 (anti parallel) + { + c = a - b; // the arguments are anti-parallel, we have to choose an axis + F32 m = sqrtf(c.mV[VX] * c.mV[VX] + c.mV[VY] * c.mV[VY]); // the length projected on the XY-plane + if (m > FP_MAG_THRESHOLD) + { + mQ[VX] = -c.mV[VY] / m; // return the quaternion with the axis in the XY-plane + mQ[VY] = c.mV[VX] / m; + mQ[VZ] = 0.0f; + mQ[VW] = 0.0f; + return; + } + else // the vectors are parallel to the Z-axis + { + mQ[VX] = 1.0f; // rotate around the X-axis + mQ[VY] = 0.0f; + mQ[VZ] = 0.0f; + mQ[VW] = 0.0f; + return; + } } - - // Construct a quaternion from this orthonormal axis. - mQ[VX] = ortho_axis.mV[VX]; - mQ[VY] = ortho_axis.mV[VY]; - mQ[VZ] = ortho_axis.mV[VZ]; - mQ[VW] = 0.f; - } - else - { - // a and b are NOT parallel or anti-parallel. - // Return the rotation between these vectors. - F32 theta = (F32)acos(cos_theta); - - setAngleAxis(theta, axis); } + loadIdentity(); } // constrains rotation to a cone angle specified in radians @@ -844,79 +841,102 @@ LLQuaternion::Order StringToOrder( const char *str ) void LLQuaternion::getAngleAxis(F32* angle, LLVector3 &vec) const { - F32 cos_a = mQ[VW]; - if (cos_a > 1.0f) cos_a = 1.0f; - if (cos_a < -1.0f) cos_a = -1.0f; - - F32 sin_a = (F32) sqrt( 1.0f - cos_a * cos_a ); - - if ( fabs( sin_a ) < 0.0005f ) - sin_a = 1.0f; - else - sin_a = 1.f/sin_a; - - F32 temp_angle = 2.0f * (F32) acos( cos_a ); - if (temp_angle > F_PI) - { - // The (angle,axis) pair should never have angles outside [PI, -PI] - // since we want the _shortest_ (angle,axis) solution. - // Since acos is defined for [0, PI], and we multiply by 2.0, we - // can push the angle outside the acceptible range. - // When this happens we set the angle to the other portion of a - // full 2PI rotation, and negate the axis, which reverses the - // direction of the rotation (by the right-hand rule). - *angle = 2.f * F_PI - temp_angle; - vec.mV[VX] = - mQ[VX] * sin_a; - vec.mV[VY] = - mQ[VY] * sin_a; - vec.mV[VZ] = - mQ[VZ] * sin_a; + F32 v = sqrtf(mQ[VX] * mQ[VX] + mQ[VY] * mQ[VY] + mQ[VZ] * mQ[VZ]); // length of the vector-component + if (v > FP_MAG_THRESHOLD) + { + F32 oomag = 1.0f / v; + F32 w = mQ[VW]; + if (mQ[VW] < 0.0f) + { + w = -w; // make VW positive + oomag = -oomag; // invert the axis + } + vec.mV[VX] = mQ[VX] * oomag; // normalize the axis + vec.mV[VY] = mQ[VY] * oomag; + vec.mV[VZ] = mQ[VZ] * oomag; + *angle = 2.0f * atan2f(v, w); // get the angle } else { - *angle = temp_angle; - vec.mV[VX] = mQ[VX] * sin_a; - vec.mV[VY] = mQ[VY] * sin_a; - vec.mV[VZ] = mQ[VZ] * sin_a; + *angle = 0.0f; // no rotation + vec.mV[VX] = 0.0f; // around some dummy axis + vec.mV[VY] = 0.0f; + vec.mV[VZ] = 1.0f; } } +const LLQuaternion& LLQuaternion::setFromAzimuthAndAltitude(F32 azimuthRadians, F32 altitudeRadians) +{ + // euler angle inputs are complements of azimuth/altitude which are measured from zenith + F32 pitch = llclamp(F_PI_BY_TWO - altitudeRadians, 0.0f, F_PI_BY_TWO); + F32 yaw = llclamp(F_PI_BY_TWO - azimuthRadians, 0.0f, F_PI_BY_TWO); + setEulerAngles(0.0f, pitch, yaw); + return *this; +} + +void LLQuaternion::getAzimuthAndAltitude(F32 &azimuthRadians, F32 &altitudeRadians) +{ + F32 rick_roll; + F32 pitch; + F32 yaw; + getEulerAngles(&rick_roll, &pitch, &yaw); + // make these measured from zenith + altitudeRadians = llclamp(F_PI_BY_TWO - pitch, 0.0f, F_PI_BY_TWO); + azimuthRadians = llclamp(F_PI_BY_TWO - yaw, 0.0f, F_PI_BY_TWO); +} // quaternion does not need to be normalized void LLQuaternion::getEulerAngles(F32 *roll, F32 *pitch, F32 *yaw) const { - LLMatrix3 rot_mat(*this); - rot_mat.orthogonalize(); - rot_mat.getEulerAngles(roll, pitch, yaw); - -// // NOTE: LLQuaternion's are actually inverted with respect to -// // the matrices, so this code also assumes inverted quaternions -// // (-x, -y, -z, w). The result is that roll,pitch,yaw are applied -// // in reverse order (yaw,pitch,roll). -// F32 x = -mQ[VX], y = -mQ[VY], z = -mQ[VZ], w = mQ[VW]; -// F64 m20 = 2.0*(x*z-y*w); -// if (1.0f - fabsf(m20) < F_APPROXIMATELY_ZERO) -// { -// *roll = 0.0f; -// *pitch = (F32)asin(m20); -// *yaw = (F32)atan2(2.0*(x*y-z*w), 1.0 - 2.0*(x*x+z*z)); -// } -// else -// { -// *roll = (F32)atan2(-2.0*(y*z+x*w), 1.0-2.0*(x*x+y*y)); -// *pitch = (F32)asin(m20); -// *yaw = (F32)atan2(-2.0*(x*y+z*w), 1.0-2.0*(y*y+z*z)); -// } + F32 sx = 2 * (mQ[VX] * mQ[VW] - mQ[VY] * mQ[VZ]); // sine of the roll + F32 sy = 2 * (mQ[VY] * mQ[VW] + mQ[VX] * mQ[VZ]); // sine of the pitch + F32 ys = mQ[VW] * mQ[VW] - mQ[VY] * mQ[VY]; // intermediate cosine 1 + F32 xz = mQ[VX] * mQ[VX] - mQ[VZ] * mQ[VZ]; // intermediate cosine 2 + F32 cx = ys - xz; // cosine of the roll + F32 cy = sqrtf(sx * sx + cx * cx); // cosine of the pitch + if (cy > GIMBAL_THRESHOLD) // no gimbal lock + { + *roll = atan2f(sx, cx); + *pitch = atan2f(sy, cy); + *yaw = atan2f(2 * (mQ[VZ] * mQ[VW] - mQ[VX] * mQ[VY]), ys + xz); + } + else // gimbal lock + { + if (sy > 0) + { + *pitch = F_PI_BY_TWO; + *yaw = 2 * atan2f(mQ[VZ] + mQ[VX], mQ[VW] + mQ[VY]); + } + else + { + *pitch = -F_PI_BY_TWO; + *yaw = 2 * atan2f(mQ[VZ] - mQ[VX], mQ[VW] - mQ[VY]); + } + *roll = 0; + } } // Saves space by using the fact that our quaternions are normalized LLVector3 LLQuaternion::packToVector3() const { + F32 x = mQ[VX]; + F32 y = mQ[VY]; + F32 z = mQ[VZ]; + F32 w = mQ[VW]; + F32 mag = sqrtf(x * x + y * y + z * z + w * w); + if (mag > FP_MAG_THRESHOLD) + { + x /= mag; + y /= mag; + z /= mag; // no need to normalize w, it's not used + } if( mQ[VW] >= 0 ) { - return LLVector3( mQ[VX], mQ[VY], mQ[VZ] ); + return LLVector3( x, y , z ); } else { - return LLVector3( -mQ[VX], -mQ[VY], -mQ[VZ] ); + return LLVector3( -x, -y, -z ); } } diff --git a/indra/llmath/llquaternion.h b/indra/llmath/llquaternion.h index a7bb09fae3..5cf7e20c83 100644 --- a/indra/llmath/llquaternion.h +++ b/indra/llmath/llquaternion.h @@ -2,31 +2,25 @@ * @file llquaternion.h * @brief LLQuaternion class header file. * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -34,6 +28,7 @@ #define LLQUATERNION_H #include +#include "llsd.h" #ifndef LLMATH_H //enforce specific include order to avoid tangling inline dependencies #error "Please include llmath.h first." @@ -69,6 +64,10 @@ class LLQuaternion LLQuaternion(const LLVector3 &x_axis, const LLVector3 &y_axis, const LLVector3 &z_axis); // Initializes Quaternion from Matrix3 = [x_axis ; y_axis ; z_axis] + explicit LLQuaternion(const LLSD &sd); // Initializes Quaternion from LLSD array. + + LLSD getValue() const; + void setValue(const LLSD& sd); BOOL isIdentity() const; BOOL isNotIdentity() const; @@ -77,11 +76,15 @@ class LLQuaternion void quantize8(F32 lower, F32 upper); // changes the vector to reflect quatization void loadIdentity(); // Loads the quaternion that represents the identity rotation + bool isEqualEps(const LLQuaternion &quat, F32 epsilon) const; + bool isNotEqualEps(const LLQuaternion &quat, F32 epsilon) const; + const LLQuaternion& set(F32 x, F32 y, F32 z, F32 w); // Sets Quaternion to normalize(x, y, z, w) const LLQuaternion& set(const LLQuaternion &quat); // Copies Quaternion const LLQuaternion& set(const F32 *q); // Sets Quaternion to normalize(quat[VX], quat[VY], quat[VZ], quat[VW]) const LLQuaternion& set(const LLMatrix3 &mat); // Sets Quaternion to mat2quat(mat) const LLQuaternion& set(const LLMatrix4 &mat); // Sets Quaternion to mat2quat(mat) + const LLQuaternion& setFromAzimuthAndAltitude(F32 azimuth, F32 altitude); const LLQuaternion& setAngleAxis(F32 angle, F32 x, F32 y, F32 z); // Sets Quaternion to axis_angle2quat(angle, x, y, z) const LLQuaternion& setAngleAxis(F32 angle, const LLVector3 &vec); // Sets Quaternion to axis_angle2quat(angle, vec) @@ -103,6 +106,7 @@ class LLQuaternion void getAngleAxis(F32* angle, F32* x, F32* y, F32* z) const; // returns rotation in radians about axis x,y,z void getAngleAxis(F32* angle, LLVector3 &vec) const; void getEulerAngles(F32 *roll, F32* pitch, F32 *yaw) const; + void getAzimuthAndAltitude(F32 &azimuth, F32 &altitude); F32 normalize(); // Normalizes Quaternion and returns magnitude F32 normQuat(); // deprecated @@ -169,10 +173,30 @@ class LLQuaternion //static U32 mMultCount; }; +inline LLSD LLQuaternion::getValue() const +{ + LLSD ret; + ret[0] = mQ[0]; + ret[1] = mQ[1]; + ret[2] = mQ[2]; + ret[3] = mQ[3]; + return ret; +} + +inline void LLQuaternion::setValue(const LLSD& sd) +{ + mQ[0] = sd[0].asReal(); + mQ[1] = sd[1].asReal(); + mQ[2] = sd[2].asReal(); + mQ[3] = sd[3].asReal(); +} + +static_assert(std::is_trivially_copyable::value, "LLQuaternion must be a trivially copyable type"); + // checker inline BOOL LLQuaternion::isFinite() const { - return (llfinite(mQ[VX]) && llfinite(mQ[VY]) && llfinite(mQ[VZ]) && llfinite(mQ[VS])); + return (std::isfinite(mQ[VX]) && std::isfinite(mQ[VY]) && std::isfinite(mQ[VZ]) && std::isfinite(mQ[VS])); } inline BOOL LLQuaternion::isIdentity() const @@ -245,6 +269,21 @@ inline void LLQuaternion::loadIdentity() mQ[VW] = 1.0f; } +inline bool LLQuaternion::isEqualEps(const LLQuaternion &quat, F32 epsilon) const +{ + return ( fabs(mQ[VX] - quat.mQ[VX]) < epsilon + && fabs(mQ[VY] - quat.mQ[VY]) < epsilon + && fabs(mQ[VZ] - quat.mQ[VZ]) < epsilon + && fabs(mQ[VS] - quat.mQ[VS]) < epsilon ); +} + +inline bool LLQuaternion::isNotEqualEps(const LLQuaternion &quat, F32 epsilon) const +{ + return ( fabs(mQ[VX] - quat.mQ[VX]) > epsilon + || fabs(mQ[VY] - quat.mQ[VY]) > epsilon + || fabs(mQ[VZ] - quat.mQ[VZ]) > epsilon + || fabs(mQ[VS] - quat.mQ[VS]) > epsilon ); +} inline const LLQuaternion& LLQuaternion::set(F32 x, F32 y, F32 z, F32 w) { @@ -310,43 +349,29 @@ inline const LLQuaternion& LLQuaternion::setQuat(const F32 *q) return (*this); } -// There may be a cheaper way that avoids the sqrt. -// Does sin_a = VX*VX + VY*VY + VZ*VZ? -// Copied from Matrix and Quaternion FAQ 1.12 inline void LLQuaternion::getAngleAxis(F32* angle, F32* x, F32* y, F32* z) const { - F32 cos_a = mQ[VW]; - if (cos_a > 1.0f) cos_a = 1.0f; - if (cos_a < -1.0f) cos_a = -1.0f; - - F32 sin_a = (F32) sqrt( 1.0f - cos_a * cos_a ); - - if ( fabs( sin_a ) < 0.0005f ) - sin_a = 1.0f; - else - sin_a = 1.f/sin_a; - - F32 temp_angle = 2.0f * (F32) acos( cos_a ); - if (temp_angle > F_PI) + F32 v = sqrtf(mQ[VX] * mQ[VX] + mQ[VY] * mQ[VY] + mQ[VZ] * mQ[VZ]); // length of the vector-component + if (v > FP_MAG_THRESHOLD) { - // The (angle,axis) pair should never have angles outside [PI, -PI] - // since we want the _shortest_ (angle,axis) solution. - // Since acos is defined for [0, PI], and we multiply by 2.0, we - // can push the angle outside the acceptible range. - // When this happens we set the angle to the other portion of a - // full 2PI rotation, and negate the axis, which reverses the - // direction of the rotation (by the right-hand rule). - *angle = 2.f * F_PI - temp_angle; - *x = - mQ[VX] * sin_a; - *y = - mQ[VY] * sin_a; - *z = - mQ[VZ] * sin_a; + F32 oomag = 1.0f / v; + F32 w = mQ[VW]; + if (w < 0.0f) + { + w = -w; // make VW positive + oomag = -oomag; // invert the axis + } + *x = mQ[VX] * oomag; // normalize the axis + *y = mQ[VY] * oomag; + *z = mQ[VZ] * oomag; + *angle = 2.0f * atan2f(v, w); // get the angle } else { - *angle = temp_angle; - *x = mQ[VX] * sin_a; - *y = mQ[VY] * sin_a; - *z = mQ[VZ] * sin_a; + *angle = 0.0f; // no rotation + *x = 0.0f; // around some dummy axis + *y = 0.0f; + *z = 1.0f; } } diff --git a/indra/llmath/llquaternion2.h b/indra/llmath/llquaternion2.h index fd9c0cf3ab..75b54be0eb 100644 --- a/indra/llmath/llquaternion2.h +++ b/indra/llmath/llquaternion2.h @@ -40,6 +40,7 @@ ///////////////////////////// #include "llquaternion.h" +LL_ALIGN_PREFIX(16) class LLQuaternion2 { public: @@ -49,7 +50,7 @@ class LLQuaternion2 ////////////////////////// // Ctor - LLQuaternion2() {} + LLQuaternion2() = default; // Ctor from LLQuaternion explicit LLQuaternion2( const class LLQuaternion& quat ); @@ -84,6 +85,8 @@ class LLQuaternion2 // Quantize this quaternion to 16 bit precision inline void quantize16(); + inline void mul(const LLQuaternion2& b); + ///////////////////////// // Quaternion inspection ///////////////////////// @@ -98,8 +101,13 @@ class LLQuaternion2 protected: - LLVector4a mQ; + LL_ALIGN_16(LLVector4a mQ); + +} LL_ALIGN_POSTFIX(16); -}; +#if !defined(LL_DEBUG) +static_assert(std::is_trivial::value, "LLQuaternion2 must be a trivial type"); +static_assert(std::is_standard_layout::value, "LLQuaternion2 must be a standard layout type"); +#endif #endif diff --git a/indra/llmath/llquaternion2.inl b/indra/llmath/llquaternion2.inl index 2a6987552d..52d67620f1 100644 --- a/indra/llmath/llquaternion2.inl +++ b/indra/llmath/llquaternion2.inl @@ -50,6 +50,39 @@ inline LLVector4a& LLQuaternion2::getVector4aRw() return mQ; } +inline void LLQuaternion2::mul(const LLQuaternion2& b) +{ + static LL_ALIGN_16(const unsigned int signMask[4]) = { 0x0, 0x0, 0x0, 0x80000000 }; + + LLVector4a sum1, sum2, prod1, prod2, prod3, prod4; + const LLVector4a& va = mQ; + const LLVector4a& vb = b.getVector4a(); + + // [VX] [VY] [VZ] [VW] + //prod1: +wx +wy +wz +ww Bwwww*Axyzw + //prod2: +xw +yw +zw -xx Bxyzx*Awwwx [VW] sign flip + //prod3: +yz +zx +xy -yy Byzxy*Azxyy [VW] sign flip + //prod4: -zy -xz -yx -zz Bzxyz*Ayzzz + + const LLVector4a Bwwww = _mm_shuffle_ps(vb,vb,_MM_SHUFFLE(3,3,3,3)); + const LLVector4a Bxyzx = _mm_shuffle_ps(vb,vb,_MM_SHUFFLE(0,2,1,0)); + const LLVector4a Awwwx = _mm_shuffle_ps(va,va,_MM_SHUFFLE(0,3,3,3)); + const LLVector4a Byzxy = _mm_shuffle_ps(vb,vb,_MM_SHUFFLE(1,0,2,1)); + const LLVector4a Azxyy = _mm_shuffle_ps(va,va,_MM_SHUFFLE(1,1,0,2)); + const LLVector4a Bzxyz = _mm_shuffle_ps(vb,vb,_MM_SHUFFLE(2,1,0,2)); + const LLVector4a Ayzxz = _mm_shuffle_ps(va,va,_MM_SHUFFLE(2,0,2,1)); + + prod1.setMul(Bwwww,va); + prod2.setMul(Bxyzx,Awwwx); + prod3.setMul(Byzxy,Azxyy); + prod4.setMul(Bzxyz,Ayzxz); + + sum1.setAdd(prod2,prod3); + sum1 = _mm_xor_ps(sum1, _mm_load_ps((const float*)signMask)); + sum2.setSub(prod1,prod4); + mQ.setAdd(sum1,sum2); +} + ///////////////////////// // Quaternion modification ///////////////////////// diff --git a/indra/llmath/llrect.cpp b/indra/llmath/llrect.cpp index 0db74f20fe..a87a476aa2 100644 --- a/indra/llmath/llrect.cpp +++ b/indra/llmath/llrect.cpp @@ -1,31 +1,26 @@ /** * @file llrect.cpp + * @brief LLRect class implementation * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llmath/llrigginginfo.cpp b/indra/llmath/llrigginginfo.cpp new file mode 100644 index 0000000000..0de07950c1 --- /dev/null +++ b/indra/llmath/llrigginginfo.cpp @@ -0,0 +1,159 @@ +/** +* @file llrigginginfo.cpp +* @brief Functions for tracking rigged box extents +* +* $LicenseInfo:firstyear=2018&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2018, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#include "llmath.h" +#include "llrigginginfo.h" + +//----------------------------------------------------------------------------- +// LLJointRiggingInfo +//----------------------------------------------------------------------------- +LLJointRiggingInfo::LLJointRiggingInfo() +{ + mRiggedExtents[0].clear(); + mRiggedExtents[1].clear(); + mIsRiggedTo = false; +} + +bool LLJointRiggingInfo::isRiggedTo() const +{ + return mIsRiggedTo; +} + +void LLJointRiggingInfo::setIsRiggedTo(bool val) +{ + mIsRiggedTo = val; +} + +LLVector4a *LLJointRiggingInfo::getRiggedExtents() +{ + return mRiggedExtents; +} + +const LLVector4a *LLJointRiggingInfo::getRiggedExtents() const +{ + return mRiggedExtents; +} + +// Combine two rigging info states. +// - isRiggedTo if either of the source infos are rigged to +// - box is union of the two sources +void LLJointRiggingInfo::merge(const LLJointRiggingInfo& other) +{ + if (other.mIsRiggedTo) + { + if (mIsRiggedTo) + { + // Combine existing boxes + update_min_max(mRiggedExtents[0], mRiggedExtents[1], other.mRiggedExtents[0]); + update_min_max(mRiggedExtents[0], mRiggedExtents[1], other.mRiggedExtents[1]); + } + else + { + // Initialize box + mIsRiggedTo = true; + mRiggedExtents[0] = other.mRiggedExtents[0]; + mRiggedExtents[1] = other.mRiggedExtents[1]; + } + } +} + +LLJointRiggingInfoTab::LLJointRiggingInfoTab(): + mRigInfoPtr(NULL), + mSize(0), + mNeedsUpdate(true) +{ +} + +LLJointRiggingInfoTab::~LLJointRiggingInfoTab() +{ + clear(); +} + +// This doesn't preserve data if the size changes. In practice +// this doesn't matter because the size is always either +// LL_CHARACTER_MAX_ANIMATED_JOINTS or 0. +void LLJointRiggingInfoTab::resize(S32 size) +{ + if (size != mSize) + { + clear(); + if (size > 0) + { + mRigInfoPtr = new LLJointRiggingInfo[size]; + mSize = size; + } + } +} + +void LLJointRiggingInfoTab::clear() +{ + if (mRigInfoPtr) + { + delete[](mRigInfoPtr); + mRigInfoPtr = NULL; + mSize = 0; + } +} + +void showDetails(const LLJointRiggingInfoTab& src, const std::string& str) +{ + S32 count_rigged = 0; + S32 count_box = 0; + LLVector4a zero_vec; + zero_vec.clear(); + for (S32 i=0; i size()) + { + resize(src.size()); + } + S32 min_size = llmin(size(), src.size()); + for (S32 i=0; i to avoid alignment issues. +class LLJointRiggingInfoTab +{ +public: + LLJointRiggingInfoTab(); + ~LLJointRiggingInfoTab(); + void resize(S32 size); + void clear(); + S32 size() const { return mSize; } + void merge(const LLJointRiggingInfoTab& src); + LLJointRiggingInfo& operator[](S32 i) { return mRigInfoPtr[i]; } + const LLJointRiggingInfo& operator[](S32 i) const { return mRigInfoPtr[i]; }; + bool needsUpdate() { return mNeedsUpdate; } + void setNeedsUpdate(bool val) { mNeedsUpdate = val; } +private: + // Not implemented + LLJointRiggingInfoTab& operator=(const LLJointRiggingInfoTab& src); + LLJointRiggingInfoTab(const LLJointRiggingInfoTab& src); + + LLJointRiggingInfo *mRigInfoPtr; + S32 mSize; + bool mNeedsUpdate; +}; + +#endif diff --git a/indra/llmath/llsdutil_math.cpp b/indra/llmath/llsdutil_math.cpp index 1bd12ae513..c35ee42f3c 100644 --- a/indra/llmath/llsdutil_math.cpp +++ b/indra/llmath/llsdutil_math.cpp @@ -4,31 +4,25 @@ * @date 2006-05-24 * @brief Implementation of classes, functions, etc, for using structured data. * - * $LicenseInfo:firstyear=2006&license=viewergpl$ - * - * Copyright (c) 2006-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llmath/llsdutil_math.h b/indra/llmath/llsdutil_math.h index 3644cab355..7607abf0ba 100644 --- a/indra/llmath/llsdutil_math.h +++ b/indra/llmath/llsdutil_math.h @@ -4,36 +4,28 @@ * @date 2009-05-19 * @brief Utility classes, functions, etc, for using structured data with math classes. * - * $LicenseInfo:firstyear=2009&license=viewergpl$ - * - * Copyright (c) 2009-2010, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlife.com/developers/opensource/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ - * */ - #ifndef LL_LLSDUTIL_MATH_H #define LL_LLSDUTIL_MATH_H diff --git a/indra/llmath/llsimdmath.h b/indra/llmath/llsimdmath.h index 01458521ec..798795a8b4 100644 --- a/indra/llmath/llsimdmath.h +++ b/indra/llmath/llsimdmath.h @@ -31,7 +31,7 @@ #error "Please include llmath.h before this file." #endif -#if ( ( LL_DARWIN || LL_LINUX ) && !(__SSE2__) ) || ( LL_WINDOWS && ( _M_IX86_FP < 2 ) ) +#if ( ( LL_DARWIN || LL_LINUX ) && !(__SSE2__) ) || ( LL_WINDOWS && ( _M_IX86_FP < 2 ) && !defined(_WIN64) ) #error SSE2 not enabled. LLVector4a and related class will not compile. #endif @@ -39,34 +39,6 @@ #include #endif -template T* LL_NEXT_ALIGNED_ADDRESS(T* address) -{ - return reinterpret_cast( - (reinterpret_cast(address) + 0xF) & ~0xF); -} - -template T* LL_NEXT_ALIGNED_ADDRESS_64(T* address) -{ - return reinterpret_cast( - (reinterpret_cast(address) + 0x3F) & ~0x3F); -} - -#if LL_LINUX || LL_DARWIN - -#define LL_ALIGN_PREFIX(x) -#define LL_ALIGN_POSTFIX(x) __attribute__((aligned(x))) - -#elif LL_WINDOWS - -#define LL_ALIGN_PREFIX(x) __declspec(align(x)) -#define LL_ALIGN_POSTFIX(x) - -#else -#error "LL_ALIGN_PREFIX and LL_ALIGN_POSTFIX undefined" -#endif - -#define LL_ALIGN_16(var) LL_ALIGN_PREFIX(16) var LL_ALIGN_POSTFIX(16) - #include #include diff --git a/indra/llmath/llsimdtypes.h b/indra/llmath/llsimdtypes.h index bd991d0e71..72f65a9d87 100644 --- a/indra/llmath/llsimdtypes.h +++ b/indra/llmath/llsimdtypes.h @@ -50,7 +50,7 @@ __forceinline const __m128i _mm_castps_si128( const __m128 a ) { return reinterp class LLBool32 { public: - inline LLBool32() {} + inline LLBool32() = default; inline LLBool32(int rhs) : m_bool(rhs) {} inline LLBool32(unsigned int rhs) : m_bool(rhs) {} inline LLBool32(bool rhs) { m_bool = static_cast(rhs); } @@ -70,7 +70,7 @@ class LLBool32 class LLSimdScalar { public: - inline LLSimdScalar() {} + inline LLSimdScalar() = default; inline LLSimdScalar(LLQuad q) { mQ = q; @@ -120,5 +120,9 @@ class LLSimdScalar private: LLQuad mQ; }; +static_assert(std::is_trivial::value, "LLBool32 must be a trivial type"); +static_assert(std::is_standard_layout::value, "LLBool32 must be a standard layout type"); +static_assert(std::is_trivial::value, "LLSimdScalar must be a trivial type"); +static_assert(std::is_standard_layout::value, "LLSimdScalar must be a standard layout type"); #endif //LL_SIMD_TYPES_H diff --git a/indra/llmath/llsphere.cpp b/indra/llmath/llsphere.cpp index b260c134a7..910b8772a6 100644 --- a/indra/llmath/llsphere.cpp +++ b/indra/llmath/llsphere.cpp @@ -3,31 +3,25 @@ * @author Andrew Meadows * @brief Simple line class that can compute nearest approach between two lines * - * $LicenseInfo:firstyear=2007&license=viewergpl$ - * - * Copyright (c) 2007-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llmath/llsphere.h b/indra/llmath/llsphere.h index 58df07a567..c16f1115c3 100644 --- a/indra/llmath/llsphere.h +++ b/indra/llmath/llsphere.h @@ -4,31 +4,25 @@ * @author Andrew Meadows * @brief Simple sphere implementation for basic geometric operations * - * $LicenseInfo:firstyear=2007&license=viewergpl$ - * - * Copyright (c) 2007-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llmath/lltreenode.h b/indra/llmath/lltreenode.h index ada1f00751..77b36a290b 100644 --- a/indra/llmath/lltreenode.h +++ b/indra/llmath/lltreenode.h @@ -1,31 +1,25 @@ /** * @file lltreenode.h * - * $LicenseInfo:firstyear=2005&license=viewergpl$ - * - * Copyright (c) 2005-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -36,6 +30,7 @@ #include "xform.h" #include "llpointer.h" #include "llrefcount.h" + #include template class LLTreeNode; @@ -49,7 +44,6 @@ class LLTreeListener: public LLRefCount virtual void handleInsertion(const LLTreeNode* node, T* data) = 0; virtual void handleRemoval(const LLTreeNode* node, T* data) = 0; virtual void handleDestruction(const LLTreeNode* node) = 0; - virtual void handleStateChange(const LLTreeNode* node) = 0; }; template @@ -58,12 +52,26 @@ class LLTreeNode public: virtual ~LLTreeNode(); - virtual bool insert(T* data); - virtual bool remove(T* data); - virtual void notifyRemoval(T* data); - virtual U32 getListenerCount() { return mListeners.size(); } - virtual LLTreeListener* getListener(U32 index) const { return mListeners[index]; } - virtual void addListener(LLTreeListener* listener) { mListeners.push_back(listener); } + virtual bool insert(T* data) = 0; + virtual bool remove(T* data) = 0; + bool notifyAddition(T* data); + void notifyRemoval(T* data); + U32 getListenerCount() const + { + return mListeners.size(); + } + LLTreeListener* getListener(U32 index) const + { + if(index < mListeners.size()) + { + return mListeners[index]; + } + return NULL; + } + void addListener(LLTreeListener* listener) + { + mListeners.push_back(listener); + } protected: void destroyListeners() @@ -95,7 +103,7 @@ LLTreeNode::~LLTreeNode() }; template -bool LLTreeNode::insert(T* data) +bool LLTreeNode::notifyAddition(T* data) { for (U32 i = 0; i < mListeners.size(); i++) { @@ -104,12 +112,6 @@ bool LLTreeNode::insert(T* data) return true; }; -template -bool LLTreeNode::remove(T* data) -{ - return true; -}; - template void LLTreeNode::notifyRemoval(T* data) { diff --git a/indra/llmath/llvector4a.cpp b/indra/llmath/llvector4a.cpp index 6edeb0fefe..570fa41a43 100644 --- a/indra/llmath/llvector4a.cpp +++ b/indra/llmath/llvector4a.cpp @@ -41,55 +41,7 @@ extern const LLVector4a LL_V4A_EPSILON = reinterpret_cast ( F /*static */void LLVector4a::memcpyNonAliased16(F32* __restrict dst, const F32* __restrict src, size_t bytes) { - assert(src != NULL); - assert(dst != NULL); - assert(bytes > 0); - assert((bytes % sizeof(F32))== 0); - ll_assert_aligned(src,16); - ll_assert_aligned(dst,16); - assert(bytes%16==0); - - F32* end = dst + (bytes / sizeof(F32) ); - - if (bytes > 64) - { - F32* begin_64 = LL_NEXT_ALIGNED_ADDRESS_64(dst); - - //at least 64 (16*4) bytes before the end of the destination, switch to 16 byte copies - F32* end_64 = end-16; - - _mm_prefetch((char*)begin_64, _MM_HINT_NTA); - _mm_prefetch((char*)begin_64 + 64, _MM_HINT_NTA); - _mm_prefetch((char*)begin_64 + 128, _MM_HINT_NTA); - _mm_prefetch((char*)begin_64 + 192, _MM_HINT_NTA); - - while (dst < begin_64) - { - copy4a(dst, src); - dst += 4; - src += 4; - } - - while (dst < end_64) - { - _mm_prefetch((char*)src + 512, _MM_HINT_NTA); - _mm_prefetch((char*)dst + 512, _MM_HINT_NTA); - copy4a(dst, src); - copy4a(dst+4, src+4); - copy4a(dst+8, src+8); - copy4a(dst+12, src+12); - - dst += 16; - src += 16; - } - } - - while (dst < end) - { - copy4a(dst, src); - dst += 4; - src += 4; - } + ll_memcpy_nonaliased_aligned_16((char*)dst, (char*)src, bytes); } void LLVector4a::setRotated( const LLRotation& rot, const LLVector4a& vec ) diff --git a/indra/llmath/llvector4a.h b/indra/llmath/llvector4a.h index 9de0e66774..b966718246 100644 --- a/indra/llmath/llvector4a.h +++ b/indra/llmath/llvector4a.h @@ -46,6 +46,7 @@ class LLRotation; // of this writing, July 08, 2010) about getting it implemented before you resort to // LLVector3/LLVector4. ///////////////////////////////// +class LLVector4a; LL_ALIGN_PREFIX(16) class LLVector4a @@ -84,6 +85,7 @@ class LLVector4a } // Copy words 16-byte blocks from src to dst. Source and destination must not overlap. + // Source and dest must be 16-byte aligned and size must be multiple of 16. static void memcpyNonAliased16(F32* __restrict dst, const F32* __restrict src, size_t bytes); //////////////////////////////////// @@ -91,15 +93,19 @@ class LLVector4a //////////////////////////////////// LLVector4a() +#if !defined(LL_DEBUG) + = default; +#else { //DO NOT INITIALIZE -- The overhead is completely unnecessary ll_assert_aligned(this,16); } - +#endif + LLVector4a(F32 x, F32 y, F32 z, F32 w = 0.f) { - set(x,y,z,w); + set(x, y, z, w); } - + LLVector4a(F32 x) { splat(x); @@ -126,7 +132,7 @@ class LLVector4a inline void loadua(const F32* src); // Load only three floats beginning at address 'src'. Slowest method. - inline void load3(const F32* src); + inline void load3(const F32* src, const F32 w=0.f); // Store to a 16-byte aligned memory address inline void store4a(F32* dst) const; @@ -168,6 +174,9 @@ class LLVector4a // Set all 4 elements to element i of v, with i NOT known at compile time inline void splat(const LLVector4a& v, U32 i); + + // Sets element N to that of src's element N. Much cleaner than.. {LLVector4Logical mask; mask.clear(); mask.setElement(); target.setSelectWithMask(mask,src,target);} + template inline void copyComponent(const LLVector4a& src); // Select bits from sourceIfTrue and sourceIfFalse according to bits in mask inline void setSelectWithMask( const LLVector4Logical& mask, const LLVector4a& sourceIfTrue, const LLVector4a& sourceIfFalse ); @@ -235,6 +244,11 @@ class LLVector4a // Note that this does not consider zero length vectors! inline void normalize3fast(); + // Normalize this vector with respect to the x, y, and z components only. Accurate only to 10-12 bits of precision. W component is destroyed + // Same as above except substitutes default vector contents if the vector is non-finite or degenerate due to zero length. + // + inline void normalize3fast_checked(LLVector4a* d = 0); + // Return true if this vector is normalized with respect to x,y,z up to tolerance inline LLBool32 isNormalized3( F32 tolerance = 1e-3 ) const; @@ -275,6 +289,8 @@ class LLVector4a void quantize8( const LLVector4a& low, const LLVector4a& high ); void quantize16( const LLVector4a& low, const LLVector4a& high ); + void negate(); + //////////////////////////////////// // LOGICAL //////////////////////////////////// @@ -308,9 +324,13 @@ class LLVector4a //////////////////////////////////// // Do NOT add aditional operators without consulting someone with SSE experience - inline const LLVector4a& operator= ( const LLVector4a& rhs ); + //inline const LLVector4a& operator= ( const LLVector4a& rhs ); + //{ + // mQ = rhs.mQ; + // return *this; + //} - inline const LLVector4a& operator= ( const LLQuad& rhs ); + inline const LLVector4a& operator= (const LLQuad& rhs); inline operator LLQuad() const; @@ -324,4 +344,14 @@ inline void update_min_max(LLVector4a& min, LLVector4a& max, const LLVector4a& p max.setMax(max, p); } +inline std::ostream& operator<<(std::ostream& s, const LLVector4a& v) +{ + s << "(" << v[0] << ", " << v[1] << ", " << v[2] << ", " << v[3] << ")"; + return s; +} + +#if !defined(LL_DEBUG) +static_assert(std::is_trivial::value, "LLVector4a must be a be a trivial type"); +static_assert(std::is_standard_layout::value, "LLVector4a must be a standard layout type"); +#endif #endif diff --git a/indra/llmath/llvector4a.inl b/indra/llmath/llvector4a.inl index 7ad22a5631..40d67c86b2 100644 --- a/indra/llmath/llvector4a.inl +++ b/indra/llmath/llvector4a.inl @@ -41,11 +41,11 @@ inline void LLVector4a::loadua(const F32* src) } // Load only three floats beginning at address 'src'. Slowest method. -inline void LLVector4a::load3(const F32* src) +inline void LLVector4a::load3(const F32* src, const F32 w) { // mQ = { 0.f, src[2], src[1], src[0] } = { W, Z, Y, X } // NB: This differs from the convention of { Z, Y, X, W } - mQ = _mm_set_ps(0.f, src[2], src[1], src[0]); + mQ = _mm_set_ps(w, src[2], src[1], src[0]); } // Store to a 16-byte aligned memory address @@ -154,6 +154,13 @@ inline void LLVector4a::splat(const LLVector4a& v, U32 i) } } +// Sets element N to that of src's element N +template inline void LLVector4a::copyComponent(const LLVector4a& src) +{ + static const LLVector4Logical mask = _mm_load_ps((F32*)&S_V4LOGICAL_MASK_TABLE[N*4]); + setSelectWithMask(mask,src,mQ); +} + // Select bits from sourceIfTrue and sourceIfFalse according to bits in mask inline void LLVector4a::setSelectWithMask( const LLVector4Logical& mask, const LLVector4a& sourceIfTrue, const LLVector4a& sourceIfFalse ) { @@ -409,6 +416,26 @@ inline void LLVector4a::normalize3fast() mQ = _mm_mul_ps( mQ, approxRsqrt ); } +inline void LLVector4a::normalize3fast_checked(LLVector4a* d) +{ + if (!isFinite3()) + { + *this = d ? *d : LLVector4a(0,1,0,1); + return; + } + + LLVector4a lenSqrd; lenSqrd.setAllDot3( *this, *this ); + + if (lenSqrd.getF32ptr()[0] <= FLT_EPSILON) + { + *this = d ? *d : LLVector4a(0,1,0,1); + return; + } + + const LLQuad approxRsqrt = _mm_rsqrt_ps(lenSqrd.mQ); + mQ = _mm_mul_ps( mQ, approxRsqrt ); +} + // Return true if this vector is normalized with respect to x,y,z up to tolerance inline LLBool32 LLVector4a::isNormalized3( F32 tolerance ) const { @@ -460,21 +487,19 @@ inline void LLVector4a::setMax(const LLVector4a& lhs, const LLVector4a& rhs) mQ = _mm_max_ps(lhs.mQ, rhs.mQ); } -// Set this to (c * lhs) + rhs * ( 1 - c) +// Set this to lhs + (rhs-lhs)*c inline void LLVector4a::setLerp(const LLVector4a& lhs, const LLVector4a& rhs, F32 c) { - LLVector4a a = lhs; - a.mul(c); - - LLVector4a b = rhs; - b.mul(1.f-c); - - setAdd(a, b); + LLVector4a t; + t.setSub(rhs,lhs); + t.mul(c); + setAdd(lhs, t); } inline LLBool32 LLVector4a::isFinite3() const { static LL_ALIGN_16(const U32 nanOrInfMask[4]) = { 0x7f800000, 0x7f800000, 0x7f800000, 0x7f800000 }; + ll_assert_aligned(nanOrInfMask,16); const __m128i nanOrInfMaskV = *reinterpret_cast (nanOrInfMask); const __m128i maskResult = _mm_and_si128( _mm_castps_si128(mQ), nanOrInfMaskV ); const LLVector4Logical equalityCheck = _mm_castsi128_ps(_mm_cmpeq_epi32( maskResult, nanOrInfMaskV )); @@ -511,6 +536,11 @@ inline void LLVector4a::clamp( const LLVector4a& low, const LLVector4a& high ) setSelectWithMask( lowMask, low, *this ); } +inline void LLVector4a::negate() +{ + static LL_ALIGN_16(const U32 signMask[4]) = {0x80000000, 0x80000000, 0x80000000, 0x80000000 }; + mQ = _mm_xor_ps(*reinterpret_cast(signMask), mQ); +} //////////////////////////////////// // LOGICAL @@ -575,13 +605,7 @@ inline bool LLVector4a::equals3(const LLVector4a& rhs, F32 tolerance ) const //////////////////////////////////// // Do NOT add aditional operators without consulting someone with SSE experience -inline const LLVector4a& LLVector4a::operator= ( const LLVector4a& rhs ) -{ - mQ = rhs.mQ; - return *this; -} - -inline const LLVector4a& LLVector4a::operator= ( const LLQuad& rhs ) +inline const LLVector4a& LLVector4a::operator= (const LLQuad& rhs) { mQ = rhs; return *this; diff --git a/indra/llmath/llvector4logical.h b/indra/llmath/llvector4logical.h index c5698f7cea..46b92a7b32 100644 --- a/indra/llmath/llvector4logical.h +++ b/indra/llmath/llvector4logical.h @@ -61,7 +61,7 @@ class LLVector4Logical }; // Empty default ctor - LLVector4Logical() {} + LLVector4Logical() = default; LLVector4Logical( const LLQuad& quad ) { @@ -79,7 +79,7 @@ class LLVector4Logical { static const LL_ALIGN_16(U32 allOnes[4]) = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }; ll_assert_aligned(allOnes,16); - mQ = _mm_andnot_ps( mQ, *(LLQuad*)(allOnes) ); + mQ = _mm_andnot_ps( mQ, _mm_load_ps((F32*)(allOnes))); return *this; } @@ -115,12 +115,14 @@ class LLVector4Logical template void setElement() { - mQ = _mm_or_ps( mQ, *reinterpret_cast(S_V4LOGICAL_MASK_TABLE + 4*N) ); + mQ = _mm_or_ps( mQ, _mm_load_ps( (F32*)&S_V4LOGICAL_MASK_TABLE[4*N] ) ); } private: LLQuad mQ; }; +static_assert(std::is_trivial::value, "LLVector4Logical must be a trivial type"); +static_assert(std::is_standard_layout::value, "LLVector4Logical must be a standard layout type"); #endif //LL_VECTOR4ALOGICAL_H diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index fdba388b1c..a974390443 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -44,13 +44,11 @@ #include "m3math.h" #include "llmatrix3a.h" #include "lloctree.h" -#include "lldarray.h" #include "llvolume.h" #include "llvolumeoctree.h" #include "llstl.h" #include "llsdserialize.h" #include "llvector4a.h" -#include "llmatrix4a.h" #include "lltimer.h" #define DEBUG_SILHOUETTE_BINORMALS 0 @@ -136,6 +134,83 @@ BOOL LLLineSegmentBoxIntersect(const F32* start, const F32* end, const F32* cent return true; } +// Finds tangent vec based on three vertices with texture coordinates. +// Fills in dummy values if the triangle has degenerate texture coordinates. +void calc_tangent_from_triangle( + LLVector4a& normal, + LLVector4a& tangent_out, + const LLVector4a& v1, + const LLVector2& w1, + const LLVector4a& v2, + const LLVector2& w2, + const LLVector4a& v3, + const LLVector2& w3) +{ + const F32* v1ptr = v1.getF32ptr(); + const F32* v2ptr = v2.getF32ptr(); + const F32* v3ptr = v3.getF32ptr(); + + float x1 = v2ptr[0] - v1ptr[0]; + float x2 = v3ptr[0] - v1ptr[0]; + float y1 = v2ptr[1] - v1ptr[1]; + float y2 = v3ptr[1] - v1ptr[1]; + float z1 = v2ptr[2] - v1ptr[2]; + float z2 = v3ptr[2] - v1ptr[2]; + + float s1 = w2.mV[0] - w1.mV[0]; + float s2 = w3.mV[0] - w1.mV[0]; + float t1 = w2.mV[1] - w1.mV[1]; + float t2 = w3.mV[1] - w1.mV[1]; + + F32 rd = s1*t2-s2*t1; + + float r = ((rd*rd) > FLT_EPSILON) ? (1.0f / rd) + : ((rd > 0.0f) ? 1024.f : -1024.f); //some made up large ratio for division by zero + + llassert(std::isfinite(r)); + llassert(!std::isnan(r)); + + LLVector4a sdir( + (t2 * x1 - t1 * x2) * r, + (t2 * y1 - t1 * y2) * r, + (t2 * z1 - t1 * z2) * r); + + LLVector4a tdir( + (s1 * x2 - s2 * x1) * r, + (s1 * y2 - s2 * y1) * r, + (s1 * z2 - s2 * z1) * r); + + LLVector4a n = normal; + LLVector4a t = sdir; + + LLVector4a ncrosst; + ncrosst.setCross3(n,t); + + // Gram-Schmidt orthogonalize + n.mul(n.dot3(t).getF32()); + + LLVector4a tsubn; + tsubn.setSub(t,n); + + if (tsubn.dot3(tsubn).getF32() > F_APPROXIMATELY_ZERO) + { + tsubn.normalize3fast_checked(); + + // Calculate handedness + F32 handedness = ncrosst.dot3(tdir).getF32() < 0.f ? -1.f : 1.f; + + tsubn.getF32ptr()[3] = handedness; + + tangent_out = tsubn; + } + else + { + // degenerate, make up a value + // + tangent_out.set(0,0,1,1); + } + +} // intersect test between triangle vert0, vert1, vert2 and a ray from orig in direction dir. @@ -350,7 +425,7 @@ class LLVolumeOctreeRebound : public LLOctreeTravelerDepthFirstgetChildCount(); ++i) @@ -442,8 +517,6 @@ S32 LLProfile::getNumNGonPoints(const LLProfileParams& params, S32 sides, F32 of t += t_step; } - t_fraction = (end - (t - t_step))*sides; - // Find the fraction that we need to add to the end point. t_fraction = (end - (t - t_step))*sides; if (t_fraction > 0.0001f) @@ -471,10 +544,10 @@ void LLProfile::genNGon(const LLProfileParams& params, S32 sides, F32 offset, F3 { // Generate an n-sided "circular" path. // 0 is (1,0), and we go counter-clockwise along a circular path from there. - const F32 tableScale[] = { 1, 1, 1, 0.5f, 0.707107f, 0.53f, 0.525f, 0.5f }; + static const F32 tableScale[] = { 1, 1, 1, 0.5f, 0.707107f, 0.53f, 0.525f, 0.5f }; F32 scale = 0.5f; F32 t, t_step, t_first, t_fraction, ang, ang_step; - LLVector3 pt1,pt2; + LLVector4a pt1,pt2; F32 begin = params.getBegin(); F32 end = params.getEnd(); @@ -484,7 +557,7 @@ void LLProfile::genNGon(const LLProfileParams& params, S32 sides, F32 offset, F3 // Scale to have size "match" scale. Compensates to get object to generally fill bounding box. - S32 total_sides = llround(sides / ang_scale); // Total number of sides all around + S32 total_sides = ll_pos_round(sides / ang_scale); // Total number of sides all around if (total_sides < 8) { @@ -497,20 +570,21 @@ void LLProfile::genNGon(const LLProfileParams& params, S32 sides, F32 offset, F3 // Starting t and ang values for the first face t = t_first; ang = 2.0f*F_PI*(t*ang_scale + offset); - pt1.setVec(cos(ang)*scale,sin(ang)*scale, t); + pt1.set(cos(ang)*scale,sin(ang)*scale, t); // Increment to the next point. // pt2 is the end point on the fractional face t += t_step; ang += ang_step; - pt2.setVec(cos(ang)*scale,sin(ang)*scale,t); + pt2.set(cos(ang)*scale,sin(ang)*scale,t); t_fraction = (begin - t_first)*sides; // Only use if it's not almost exactly on an edge. if (t_fraction < 0.9999f) { - LLVector3 new_pt = lerp(pt1, pt2, t_fraction); + LLVector4a new_pt; + new_pt.setLerp(pt1, pt2, t_fraction); mProfile.push_back(new_pt); } @@ -518,12 +592,17 @@ void LLProfile::genNGon(const LLProfileParams& params, S32 sides, F32 offset, F3 while (t < end) { // Iterate through all the integer steps of t. - pt1.setVec(cos(ang)*scale,sin(ang)*scale,t); + pt1.set(cos(ang)*scale,sin(ang)*scale,t); if (mProfile.size() > 0) { - LLVector3 p = mProfile[mProfile.size()-1]; + LLVector4a p = mProfile[mProfile.size()-1]; for (S32 i = 0; i < split && mProfile.size() > 0; i++) { - mProfile.push_back(p+(pt1-p) * 1.0f/(float)(split+1) * (float)(i+1)); + //mProfile.push_back(p+(pt1-p) * 1.0f/(float)(split+1) * (float)(i+1)); + LLVector4a new_pt; + new_pt.setSub(pt1, p); + new_pt.mul(1.0f/(float)(split+1) * (float)(i+1)); + new_pt.add(p); + mProfile.push_back(new_pt); } } mProfile.push_back(pt1); @@ -532,22 +611,27 @@ void LLProfile::genNGon(const LLProfileParams& params, S32 sides, F32 offset, F3 ang += ang_step; } - t_fraction = (end - (t - t_step))*sides; - // pt1 is the first point on the fractional face // pt2 is the end point on the fractional face - pt2.setVec(cos(ang)*scale,sin(ang)*scale,t); + pt2.set(cos(ang)*scale,sin(ang)*scale,t); // Find the fraction that we need to add to the end point. t_fraction = (end - (t - t_step))*sides; if (t_fraction > 0.0001f) { - LLVector3 new_pt = lerp(pt1, pt2, t_fraction); + LLVector4a new_pt; + new_pt.setLerp(pt1, pt2, t_fraction); if (mProfile.size() > 0) { - LLVector3 p = mProfile[mProfile.size()-1]; + LLVector4a p = mProfile[mProfile.size()-1]; for (S32 i = 0; i < split && mProfile.size() > 0; i++) { - mProfile.push_back(p+(new_pt-p) * 1.0f/(float)(split+1) * (float)(i+1)); + //mProfile.push_back(p+(new_pt-p) * 1.0f/(float)(split+1) * (float)(i+1)); + + LLVector4a pt1; + pt1.setSub(new_pt, p); + pt1.mul(1.0f/(float)(split+1) * (float)(i+1)); + pt1.add(p); + mProfile.push_back(pt1); } } mProfile.push_back(new_pt); @@ -568,7 +652,7 @@ void LLProfile::genNGon(const LLProfileParams& params, S32 sides, F32 offset, F3 if (params.getHollow() <= 0) { // put center point if not hollow. - mProfile.push_back(LLVector3(0,0,0)); + mProfile.push_back(LLVector4a(0,0,0)); } } else @@ -581,103 +665,6 @@ void LLProfile::genNGon(const LLProfileParams& params, S32 sides, F32 offset, F3 mTotal = mProfile.size(); } -void LLProfile::genNormals(const LLProfileParams& params) -{ - S32 count = mProfile.size(); - - S32 outer_count; - if (mTotalOut) - { - outer_count = mTotalOut; - } - else - { - outer_count = mTotal / 2; - } - - mEdgeNormals.resize(count * 2); - mEdgeCenters.resize(count * 2); - mNormals.resize(count); - - LLVector2 pt0,pt1; - - BOOL hollow = (params.getHollow() > 0); - - S32 i0, i1, i2, i3, i4; - - // Parametrically generate normal - for (i2 = 0; i2 < count; i2++) - { - mNormals[i2].mV[0] = mProfile[i2].mV[0]; - mNormals[i2].mV[1] = mProfile[i2].mV[1]; - if (hollow && (i2 >= outer_count)) - { - mNormals[i2] *= -1.f; - } - if (mNormals[i2].magVec() < 0.001) - { - // Special case for point at center, get adjacent points. - i1 = (i2 - 1) >= 0 ? i2 - 1 : count - 1; - i0 = (i1 - 1) >= 0 ? i1 - 1 : count - 1; - i3 = (i2 + 1) < count ? i2 + 1 : 0; - i4 = (i3 + 1) < count ? i3 + 1 : 0; - - pt0.setVec(mProfile[i1].mV[VX] + mProfile[i1].mV[VX] - mProfile[i0].mV[VX], - mProfile[i1].mV[VY] + mProfile[i1].mV[VY] - mProfile[i0].mV[VY]); - pt1.setVec(mProfile[i3].mV[VX] + mProfile[i3].mV[VX] - mProfile[i4].mV[VX], - mProfile[i3].mV[VY] + mProfile[i3].mV[VY] - mProfile[i4].mV[VY]); - - mNormals[i2] = pt0 + pt1; - mNormals[i2] *= 0.5f; - } - mNormals[i2].normVec(); - } - - S32 num_normal_sets = isConcave() ? 2 : 1; - for (S32 normal_set = 0; normal_set < num_normal_sets; normal_set++) - { - S32 point_num; - for (point_num = 0; point_num < mTotal; point_num++) - { - LLVector3 point_1 = mProfile[point_num]; - point_1.mV[VZ] = 0.f; - - LLVector3 point_2; - - if (isConcave() && normal_set == 0 && point_num == (mTotal - 1) / 2) - { - point_2 = mProfile[mTotal - 1]; - } - else if (isConcave() && normal_set == 1 && point_num == mTotal - 1) - { - point_2 = mProfile[(mTotal - 1) / 2]; - } - else - { - LLVector3 delta_pos; - S32 neighbor_point = (point_num + 1) % mTotal; - while(delta_pos.magVecSquared() < 0.01f * 0.01f) - { - point_2 = mProfile[neighbor_point]; - delta_pos = point_2 - point_1; - neighbor_point = (neighbor_point + 1) % mTotal; - if (neighbor_point == point_num) - { - break; - } - } - } - - point_2.mV[VZ] = 0.f; - LLVector3 face_normal = (point_2 - point_1) % LLVector3::z_axis; - face_normal.normVec(); - mEdgeNormals[normal_set * count + point_num] = face_normal; - mEdgeCenters[normal_set * count + point_num] = lerp(point_1, point_2, 0.5f); - } - } -} - - // Hollow is percent of the original bounding box, not of this particular // profile's geometry. Thus, a swept triangle needs lower hollow values than // a swept square. @@ -693,12 +680,13 @@ LLProfile::Face* LLProfile::addHole(const LLProfileParams& params, BOOL flat, F3 Face *face = addFace(mTotalOut, mTotal-mTotalOut,0,LL_FACE_INNER_SIDE, flat); - std::vector pt; + static LLAlignedArray pt; pt.resize(mTotal) ; for (S32 i=mTotalOut;i end - 0.01f) { - llwarns << "LLProfile::generate() assertion failed (begin >= end)" << llendl; + LL_WARNS() << "LLProfile::generate() assertion failed (begin >= end)" << LL_ENDL; return FALSE; } @@ -877,10 +865,13 @@ BOOL LLProfile::generate(const LLProfileParams& params, BOOL path_open,F32 detai addFace((face_num++) * (split +1), split+2, 1, LL_FACE_OUTER_SIDE_0 << i, TRUE); } + LLVector4a scale(1,1,4,1); + for (i = 0; i <(S32) mProfile.size(); i++) { // Scale by 4 to generate proper tex coords. - mProfile[i].mV[2] *= 4.f; + mProfile[i].mul(scale); + llassert(mProfile[i].isFinite3()); } if (hollow) @@ -913,10 +904,12 @@ BOOL LLProfile::generate(const LLProfileParams& params, BOOL path_open,F32 detai case LL_PCODE_PROFILE_EQUALTRI: { genNGon(params, 3,0, 0, 1, split); + LLVector4a scale(1,1,3,1); for (i = 0; i <(S32) mProfile.size(); i++) { // Scale by 3 to generate proper tex coords. - mProfile[i].mV[2] *= 3.f; + mProfile[i].mul(scale); + llassert(mProfile[i].isFinite3()); } if (path_open) @@ -1072,7 +1065,7 @@ BOOL LLProfile::generate(const LLProfileParams& params, BOOL path_open,F32 detai } break; default: - llerrs << "Unknown profile: getCurveType()=" << params.getCurveType() << llendl; + LL_ERRS() << "Unknown profile: getCurveType()=" << params.getCurveType() << LL_ENDL; break; }; @@ -1095,8 +1088,6 @@ BOOL LLProfile::generate(const LLProfileParams& params, BOOL path_open,F32 detai } } - //genNormals(params); - return TRUE; } @@ -1156,7 +1147,7 @@ BOOL LLProfileParams::importFile(LLFILE *fp) } else { - llwarns << "unknown keyword " << keyword << " in profile import" << llendl; + LL_WARNS() << "unknown keyword " << keyword << " in profile import" << LL_ENDL; } } @@ -1228,7 +1219,7 @@ BOOL LLProfileParams::importLegacyStream(std::istream& input_stream) } else { - llwarns << "unknown keyword " << keyword << " in profile import" << llendl; + LL_WARNS() << "unknown keyword " << keyword << " in profile import" << LL_ENDL; } } @@ -1310,7 +1301,7 @@ S32 LLPath::getNumNGonPoints(const LLPathParams& params, S32 sides, F32 startOff void LLPath::genNGon(const LLPathParams& params, S32 sides, F32 startOff, F32 end_scale, F32 twist_scale) { // Generates a circular path, starting at (1, 0, 0), counterclockwise along the xz plane. - const F32 tableScale[] = { 1, 1, 1, 0.5f, 0.707107f, 0.53f, 0.525f, 0.5f }; + static const F32 tableScale[] = { 1, 1, 1, 0.5f, 0.707107f, 0.53f, 0.525f, 0.5f }; F32 revolutions = params.getRevolutions(); F32 skew = params.getSkew(); @@ -1379,25 +1370,29 @@ void LLPath::genNGon(const LLPathParams& params, S32 sides, F32 startOff, F32 en // the path begins at the correct cut. F32 step= 1.0f / sides; F32 t = params.getBegin(); - pt = vector_append(mPath, 1); + pt = mPath.append(1); ang = 2.0f*F_PI*revolutions * t; s = sin(ang)*lerp(radius_start, radius_end, t); c = cos(ang)*lerp(radius_start, radius_end, t); - pt->mPos.setVec(0 + lerp(0,params.getShear().mV[0],s) + pt->mPos.set(0 + lerp(0,params.getShear().mV[0],s) + lerp(-skew ,skew, t) * 0.5f, c + lerp(0,params.getShear().mV[1],s), s); - pt->mScale.mV[VX] = hole_x * lerp(taper_x_begin, taper_x_end, t); - pt->mScale.mV[VY] = hole_y * lerp(taper_y_begin, taper_y_end, t); + pt->mScale.set(hole_x * lerp(taper_x_begin, taper_x_end, t), + hole_y * lerp(taper_y_begin, taper_y_end, t), + 0,1); pt->mTexT = t; - + // Twist rotates the path along the x,y plane (I think) - DJS 04/05/02 twist.setQuat (lerp(twist_begin,twist_end,t) * 2.f * F_PI - F_PI,0,0,1); // Rotate the point around the circle's center. qang.setQuat (ang,path_axis); - pt->mRot = twist * qang; + + LLMatrix3 rot(twist * qang); + + pt->mRot.loadu(rot); t+=step; @@ -1408,50 +1403,54 @@ void LLPath::genNGon(const LLPathParams& params, S32 sides, F32 startOff, F32 en // Run through the non-cut dependent points. while (t < params.getEnd()) { - pt = vector_append(mPath, 1); + pt = mPath.append(1); ang = 2.0f*F_PI*revolutions * t; c = cos(ang)*lerp(radius_start, radius_end, t); s = sin(ang)*lerp(radius_start, radius_end, t); - pt->mPos.setVec(0 + lerp(0,params.getShear().mV[0],s) + pt->mPos.set(0 + lerp(0,params.getShear().mV[0],s) + lerp(-skew ,skew, t) * 0.5f, c + lerp(0,params.getShear().mV[1],s), s); - pt->mScale.mV[VX] = hole_x * lerp(taper_x_begin, taper_x_end, t); - pt->mScale.mV[VY] = hole_y * lerp(taper_y_begin, taper_y_end, t); + pt->mScale.set(hole_x * lerp(taper_x_begin, taper_x_end, t), + hole_y * lerp(taper_y_begin, taper_y_end, t), + 0,1); pt->mTexT = t; // Twist rotates the path along the x,y plane (I think) - DJS 04/05/02 twist.setQuat (lerp(twist_begin,twist_end,t) * 2.f * F_PI - F_PI,0,0,1); // Rotate the point around the circle's center. qang.setQuat (ang,path_axis); - pt->mRot = twist * qang; + LLMatrix3 tmp(twist*qang); + pt->mRot.loadu(tmp); t+=step; } // Make one final pass for the end cut. t = params.getEnd(); - pt = vector_append(mPath, 1); + pt = mPath.append(1); ang = 2.0f*F_PI*revolutions * t; c = cos(ang)*lerp(radius_start, radius_end, t); s = sin(ang)*lerp(radius_start, radius_end, t); - pt->mPos.setVec(0 + lerp(0,params.getShear().mV[0],s) + pt->mPos.set(0 + lerp(0,params.getShear().mV[0],s) + lerp(-skew ,skew, t) * 0.5f, c + lerp(0,params.getShear().mV[1],s), s); - pt->mScale.mV[VX] = hole_x * lerp(taper_x_begin, taper_x_end, t); - pt->mScale.mV[VY] = hole_y * lerp(taper_y_begin, taper_y_end, t); + pt->mScale.set(hole_x * lerp(taper_x_begin, taper_x_end, t), + hole_y * lerp(taper_y_begin, taper_y_end, t), + 0,1); pt->mTexT = t; - + // Twist rotates the path along the x,y plane (I think) - DJS 04/05/02 twist.setQuat (lerp(twist_begin,twist_end,t) * 2.f * F_PI - F_PI,0,0,1); // Rotate the point around the circle's center. qang.setQuat (ang,path_axis); - pt->mRot = twist * qang; + LLMatrix3 tmp(twist*qang); + pt->mRot.loadu(tmp); mTotal = mPath.size(); } @@ -1542,14 +1541,14 @@ BOOL LLPath::generate(const LLPathParams& params, F32 detail, S32 split, if (detail < MIN_LOD) { - llinfos << "Generating path with LOD < MIN! Clamping to 1" << llendl; + LL_INFOS() << "Generating path with LOD < MIN! Clamping to 1" << LL_ENDL; detail = MIN_LOD; } mDirty = FALSE; S32 np = 2; // hardcode for line - mPath.clear(); + mPath.resize(0); mOpen = TRUE; // Is this 0xf0 mask really necessary? DK 03/02/05 @@ -1575,12 +1574,16 @@ BOOL LLPath::generate(const LLPathParams& params, F32 detail, S32 split, for (S32 i=0;iresizePath(length); mVolumeFaces.clear(); + setDirty(); } void LLVolume::regen() @@ -2079,9 +2091,9 @@ void LLVolume::regen() createVolumeFaces(); } -void LLVolume::genBinormals(S32 face) +void LLVolume::genTangents(S32 face) { - mVolumeFaces[face].createBinormals(); + mVolumeFaces[face].createTangents(); } LLVolume::~LLVolume() @@ -2128,32 +2140,21 @@ BOOL LLVolume::generate() F32 profile_detail = mDetail; F32 path_detail = mDetail; - - U8 path_type = mParams.getPathParams().getCurveType(); - U8 profile_type = mParams.getProfileParams().getCurveType(); - - if (path_type == LL_PCODE_PATH_LINE && profile_type == LL_PCODE_PROFILE_CIRCLE) - { //cylinders don't care about Z-Axis - mLODScaleBias.setVec(0.6f, 0.6f, 0.0f); - } - else if (path_type == LL_PCODE_PATH_CIRCLE) - { - mLODScaleBias.setVec(0.6f, 0.6f, 0.6f); - } - - //******************************************************************** - //debug info, to be removed - if((U32)(mPathp->mPath.size() * mProfilep->mProfile.size()) > (1u << 20)) - { - llinfos << "sizeS: " << mPathp->mPath.size() << " sizeT: " << mProfilep->mProfile.size() << llendl ; - llinfos << "path_detail : " << path_detail << " split: " << split << " profile_detail: " << profile_detail << llendl ; - llinfos << mParams << llendl ; - llinfos << "more info to check if mProfilep is deleted or not." << llendl ; - llinfos << mProfilep->mNormals.size() << " : " << mProfilep->mFaces.size() << " : " << mProfilep->mEdgeNormals.size() << " : " << mProfilep->mEdgeCenters.size() << llendl ; - llerrs << "LLVolume corrupted!" << llendl ; + if ((mParams.getSculptType() & LL_SCULPT_TYPE_MASK) != LL_SCULPT_TYPE_MESH) + { + U8 path_type = mParams.getPathParams().getCurveType(); + U8 profile_type = mParams.getProfileParams().getCurveType(); + if (path_type == LL_PCODE_PATH_LINE && profile_type == LL_PCODE_PROFILE_CIRCLE) + { + //cylinders don't care about Z-Axis + mLODScaleBias.setVec(0.6f, 0.6f, 0.0f); + } + else if (path_type == LL_PCODE_PATH_CIRCLE) + { + mLODScaleBias.setVec(0.6f, 0.6f, 0.6f); + } } - //******************************************************************** BOOL regenPath = mPathp->generate(mParams.getPathParams(), path_detail, split); BOOL regenProf = mProfilep->generate(mParams.getProfileParams(), mPathp->isOpen(),profile_detail, split); @@ -2163,21 +2164,6 @@ BOOL LLVolume::generate() S32 sizeS = mPathp->mPath.size(); S32 sizeT = mProfilep->mProfile.size(); - //******************************************************************** - //debug info, to be removed - if((U32)(sizeS * sizeT) > (1u << 20)) - { - llinfos << "regenPath: " << (S32)regenPath << " regenProf: " << (S32)regenProf << llendl ; - llinfos << "sizeS: " << sizeS << " sizeT: " << sizeT << llendl ; - llinfos << "path_detail : " << path_detail << " split: " << split << " profile_detail: " << profile_detail << llendl ; - llinfos << mParams << llendl ; - llinfos << "more info to check if mProfilep is deleted or not." << llendl ; - llinfos << mProfilep->mNormals.size() << " : " << mProfilep->mFaces.size() << " : " << mProfilep->mEdgeNormals.size() << " : " << mProfilep->mEdgeCenters.size() << llendl ; - - llerrs << "LLVolume corrupted!" << llendl ; - } - //******************************************************************** - sNumMeshPoints -= mMesh.size(); mMesh.resize(sizeT * sizeS); sNumMeshPoints += mMesh.size(); @@ -2185,22 +2171,44 @@ BOOL LLVolume::generate() //generate vertex positions // Run along the path. + LLVector4a* dst = mMesh.mArray; + for (S32 s = 0; s < sizeS; ++s) { - LLVector2 scale = mPathp->mPath[s].mScale; - LLQuaternion rot = mPathp->mPath[s].mRot; + F32* scale = mPathp->mPath[s].mScale.getF32ptr(); + + F32 sc [] = + { scale[0], 0, 0, 0, + 0, scale[1], 0, 0, + 0, 0, scale[2], 0, + 0, 0, 0, 1 }; + + LLMatrix4 rot(mPathp->mPath[s].mRot.getF32ptr()); + LLMatrix4 scale_mat(sc); + + scale_mat *= rot; + + LLMatrix4a rot_mat; + rot_mat.loadu(scale_mat); + + LLVector4a* profile = mProfilep->mProfile.mArray; + LLVector4a* end_profile = profile+sizeT; + LLVector4a offset = mPathp->mPath[s].mPos; + + if (!offset.isFinite3()) + { // MAINT-5660; don't know why this happens, does not affect Release builds + LL_WARNS() << "LLVolume using path with non-finite points. Resetting them to 0,0,0" << LL_ENDL; + offset.clear(); + } + + LLVector4a tmp; // Run along the profile. - for (S32 t = 0; t < sizeT; ++t) + while (profile < end_profile) { - S32 m = s*sizeT + t; - Point& pt = mMesh[m]; - - pt.mPos.mV[0] = mProfilep->mProfile[t].mV[0] * scale.mV[0]; - pt.mPos.mV[1] = mProfilep->mProfile[t].mV[1] * scale.mV[1]; - pt.mPos.mV[2] = 0.0f; - pt.mPos = pt.mPos * rot; - pt.mPos += mPathp->mPath[s].mPos; + rot_mat.rotate(*profile++, tmp); + dst->setAdd(tmp,offset); + ++dst; } } @@ -2368,7 +2376,7 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size) LLSD mdl; if (!unzip_llsd(mdl, is, size)) { - LL_DEBUGS("MeshStreaming") << "Failed to unzip LLSD blob for LoD, will probably fetch from sim again." << llendl; + LL_DEBUGS("MeshStreaming") << "Failed to unzip LLSD blob for LoD, will probably fetch from sim again." << LL_ENDL; return false; } @@ -2377,7 +2385,7 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size) if (face_count == 0) { //no faces unpacked, treat as failed decode - llwarns << "found no faces!" << llendl; + LL_WARNS() << "found no faces!" << LL_ENDL; return false; } @@ -2410,7 +2418,7 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size) if (idx.empty() || face.mNumIndices < 3) { //why is there an empty index list? - llwarns <<"Empty face present!" << llendl; + LL_WARNS() <<"Empty face present!" << LL_ENDL; continue; } @@ -2530,14 +2538,18 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size) U32 cur_influence = 0; LLVector4 wght(0,0,0,0); + U32 joints[4] = {0,0,0,0}; + LLVector4 joints_with_weights(0,0,0,0); while (joint != END_INFLUENCES && idx < weights.size()) { U16 influence = weights[idx++]; influence |= ((U16) weights[idx++] << 8); - F32 w = llclamp((F32) influence / 65535.f, 0.f, 0.99999f); - wght.mV[cur_influence++] = (F32) joint + w; + F32 w = llclamp((F32) influence / 65535.f, 0.001f, 0.999f); + wght.mV[cur_influence] = w; + joints[cur_influence] = joint; + cur_influence++; if (cur_influence >= 4) { @@ -2548,15 +2560,27 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size) joint = weights[idx++]; } } - - face.mWeights[cur_vertex].loadua(wght.mV); + F32 wsum = wght.mV[VX] + wght.mV[VY] + wght.mV[VZ] + wght.mV[VW]; + if (wsum <= 0.f) + { + wght = LLVector4(0.999f,0.f,0.f,0.f); + } + for (U32 k=0; k<4; k++) + { + F32 f_combined = (F32) joints[k] + wght[k]; + joints_with_weights[k] = f_combined; + // Any weights we added above should wind up non-zero and applied to a specific bone. + // A failure here would indicate a floating point precision error in the math. + llassert((k >= cur_influence) || (f_combined - S32(f_combined) > 0.0f)); + } + face.mWeights[cur_vertex].loadua(joints_with_weights.mV); cur_vertex++; } if (cur_vertex != num_verts || idx != weights.size()) { - llwarns << "Vertex weight count does not match vertex count!" << llendl; + LL_WARNS() << "Vertex weight count does not match vertex count!" << LL_ENDL; } } @@ -2677,6 +2701,17 @@ void LLVolume::setMeshAssetLoaded(BOOL loaded) mIsMeshAssetLoaded = loaded; } +void LLVolume::copyFacesTo(std::vector &faces) const +{ + faces = mVolumeFaces; +} + +void LLVolume::copyFacesFrom(const std::vector &faces) +{ + mVolumeFaces = faces; + mSculptLevel = 0; +} + void LLVolume::copyVolumeFaces(const LLVolume* volume) { mVolumeFaces = volume->mVolumeFaces; @@ -2722,7 +2757,7 @@ void LLVolume::createVolumeFaces() vf.mNumS = face.mCount; if (vf.mNumS < 0) { - llerrs << "Volume face corruption detected." << llendl; + LL_ERRS() << "Volume face corruption detected." << LL_ENDL; } vf.mBeginT = 0; @@ -2770,7 +2805,7 @@ void LLVolume::createVolumeFaces() vf.mNumS = vf.mNumS*2; if (vf.mNumS < 0) { - llerrs << "Volume face corruption detected." << llendl; + LL_ERRS() << "Volume face corruption detected." << LL_ENDL; } } } @@ -2790,13 +2825,15 @@ void LLVolume::createVolumeFaces() } -inline LLVector3 sculpt_rgb_to_vector(U8 r, U8 g, U8 b) +inline LLVector4a sculpt_rgb_to_vector(U8 r, U8 g, U8 b) { // maps RGB values to vector values [0..255] -> [-0.5..0.5] - LLVector3 value; - value.mV[VX] = r / 255.f - 0.5f; - value.mV[VY] = g / 255.f - 0.5f; - value.mV[VZ] = b / 255.f - 0.5f; + LLVector4a value; + LLVector4a sub(0.5f, 0.5f, 0.5f); + + value.set(r,g,b); + value.mul(1.f/255.f); + value.sub(sub); return value; } @@ -2817,21 +2854,21 @@ inline U32 sculpt_st_to_index(S32 s, S32 t, S32 size_s, S32 size_t, U16 sculpt_w } -inline LLVector3 sculpt_index_to_vector(U32 index, const U8* sculpt_data) +inline LLVector4a sculpt_index_to_vector(U32 index, const U8* sculpt_data) { - LLVector3 v = sculpt_rgb_to_vector(sculpt_data[index], sculpt_data[index+1], sculpt_data[index+2]); + LLVector4a v = sculpt_rgb_to_vector(sculpt_data[index], sculpt_data[index+1], sculpt_data[index+2]); return v; } -inline LLVector3 sculpt_st_to_vector(S32 s, S32 t, S32 size_s, S32 size_t, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data) +inline LLVector4a sculpt_st_to_vector(S32 s, S32 t, S32 size_s, S32 size_t, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data) { U32 index = sculpt_st_to_index(s, t, size_s, size_t, sculpt_width, sculpt_height, sculpt_components); return sculpt_index_to_vector(index, sculpt_data); } -inline LLVector3 sculpt_xy_to_vector(U32 x, U32 y, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data) +inline LLVector4a sculpt_xy_to_vector(U32 x, U32 y, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data) { U32 index = sculpt_xy_to_index(x, y, sculpt_width, sculpt_height, sculpt_components); @@ -2853,36 +2890,73 @@ F32 LLVolume::sculptGetSurfaceArea() for (S32 t = 0; t < sizeT-1; t++) { // get four corners of quad - LLVector3 p1 = mMesh[(s )*sizeT + (t )].mPos; - LLVector3 p2 = mMesh[(s+1)*sizeT + (t )].mPos; - LLVector3 p3 = mMesh[(s )*sizeT + (t+1)].mPos; - LLVector3 p4 = mMesh[(s+1)*sizeT + (t+1)].mPos; + LLVector4a& p1 = mMesh[(s )*sizeT + (t )]; + LLVector4a& p2 = mMesh[(s+1)*sizeT + (t )]; + LLVector4a& p3 = mMesh[(s )*sizeT + (t+1)]; + LLVector4a& p4 = mMesh[(s+1)*sizeT + (t+1)]; // compute the area of the quad by taking the length of the cross product of the two triangles - LLVector3 cross1 = (p1 - p2) % (p1 - p3); - LLVector3 cross2 = (p4 - p2) % (p4 - p3); - area += (cross1.magVec() + cross2.magVec()) / 2.f; + LLVector4a v0,v1,v2,v3; + v0.setSub(p1,p2); + v1.setSub(p1,p3); + v2.setSub(p4,p2); + v3.setSub(p4,p3); + + LLVector4a cross1, cross2; + cross1.setCross3(v0,v1); + cross2.setCross3(v2,v3); + + //LLVector3 cross1 = (p1 - p2) % (p1 - p3); + //LLVector3 cross2 = (p4 - p2) % (p4 - p3); + + area += (cross1.getLength3() + cross2.getLength3()).getF32() / 2.f; } } return area; } -// create placeholder shape -void LLVolume::sculptGeneratePlaceholder() +// create empty placeholder shape +void LLVolume::sculptGenerateEmptyPlaceholder() { S32 sizeS = mPathp->mPath.size(); S32 sizeT = mProfilep->mProfile.size(); - + + S32 line = 0; + + for (S32 s = 0; s < sizeS; s++) + { + for (S32 t = 0; t < sizeT; t++) + { + S32 i = t + line; + LLVector4a& pt = mMesh[i]; + + F32* p = pt.getF32ptr(); + + p[0] = 0; + p[1] = 0; + p[2] = 0; + + llassert(pt.isFinite3()); + } + line += sizeT; + } +} + +// create sphere placeholder shape +void LLVolume::sculptGenerateSpherePlaceholder() +{ + S32 sizeS = mPathp->mPath.size(); + S32 sizeT = mProfilep->mProfile.size(); + S32 line = 0; - // for now, this is a sphere. for (S32 s = 0; s < sizeS; s++) { for (S32 t = 0; t < sizeT; t++) { S32 i = t + line; - Point& pt = mMesh[i]; + LLVector4a& pt = mMesh[i]; F32 u = (F32)s/(sizeS-1); @@ -2890,9 +2964,13 @@ void LLVolume::sculptGeneratePlaceholder() const F32 RADIUS = (F32) 0.3; - pt.mPos.mV[0] = (F32)(sin(F_PI * v) * cos(2.0 * F_PI * u) * RADIUS); - pt.mPos.mV[1] = (F32)(sin(F_PI * v) * sin(2.0 * F_PI * u) * RADIUS); - pt.mPos.mV[2] = (F32)(cos(F_PI * v) * RADIUS); + F32* p = pt.getF32ptr(); + + p[0] = (F32)(sin(F_PI * v) * cos(2.0 * F_PI * u) * RADIUS); + p[1] = (F32)(sin(F_PI * v) * sin(2.0 * F_PI * u) * RADIUS); + p[2] = (F32)(cos(F_PI * v) * RADIUS); + + llassert(pt.isFinite3()); } line += sizeT; @@ -2917,7 +2995,7 @@ void LLVolume::sculptGenerateMapVertices(U16 sculpt_width, U16 sculpt_height, S8 for (S32 t = 0; t < sizeT; t++) { S32 i = t + line; - Point& pt = mMesh[i]; + LLVector4a& pt = mMesh[i]; S32 reversed_t = t; @@ -2974,12 +3052,15 @@ void LLVolume::sculptGenerateMapVertices(U16 sculpt_width, U16 sculpt_height, S8 } } - pt.mPos = sculpt_xy_to_vector(x, y, sculpt_width, sculpt_height, sculpt_components, sculpt_data); + pt = sculpt_xy_to_vector(x, y, sculpt_width, sculpt_height, sculpt_components, sculpt_data); if (sculpt_mirror) { - pt.mPos.mV[VX] *= -1.f; + LLVector4a scale(-1.f,1,1,1); + pt.mul(scale); } + + llassert(pt.isFinite3()); } line += sizeT; @@ -3078,7 +3159,7 @@ bool sculpt_calc_mesh_resolution(U16 width, U16 height, U8 type, F32 detail, S32 } // sculpt replaces generate() for sculpted surfaces -void LLVolume::sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, S32 sculpt_level) +void LLVolume::sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, S32 sculpt_level, bool visible_placeholder) { U8 sculpt_type = mParams.getSculptType(); @@ -3118,7 +3199,7 @@ void LLVolume::sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, // weird crash bug - DEV-11158 - trying to collect more data: if ((sizeS == 0) || (sizeT == 0)) { - llwarns << "sculpt bad mesh size " << sizeS << " " << sizeT << llendl; + LL_WARNS() << "sculpt bad mesh size " << sizeS << " " << sizeT << LL_ENDL; } sNumMeshPoints -= mMesh.size(); @@ -3142,13 +3223,22 @@ void LLVolume::sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, if (area < SCULPT_MIN_AREA || area > SCULPT_MAX_AREA) { data_is_empty = TRUE; + visible_placeholder = true; } } } if (data_is_empty) { - sculptGeneratePlaceholder(); + if (visible_placeholder) + { + // Object should be visible since there will be nothing else to display + sculptGenerateSpherePlaceholder(); + } + else + { + sculptGenerateEmptyPlaceholder(); + } } @@ -3513,16 +3603,16 @@ bool LLVolumeParams::setType(U8 profile, U8 path) // Bad profile. Make it square. profile = LL_PCODE_PROFILE_SQUARE; result = false; - llwarns << "LLVolumeParams::setType changing bad profile type (" << profile_type - << ") to be LL_PCODE_PROFILE_SQUARE" << llendl; + LL_WARNS() << "LLVolumeParams::setType changing bad profile type (" << profile_type + << ") to be LL_PCODE_PROFILE_SQUARE" << LL_ENDL; } else if (hole_type > LL_PCODE_HOLE_MAX) { // Bad hole. Make it the same. profile = profile_type; result = false; - llwarns << "LLVolumeParams::setType changing bad hole type (" << hole_type - << ") to be LL_PCODE_HOLE_SAME" << llendl; + LL_WARNS() << "LLVolumeParams::setType changing bad hole type (" << hole_type + << ") to be LL_PCODE_HOLE_SAME" << LL_ENDL; } if (path_type < LL_PCODE_PATH_MIN || @@ -3530,8 +3620,8 @@ bool LLVolumeParams::setType(U8 profile, U8 path) { // Bad path. Make it linear. result = false; - llwarns << "LLVolumeParams::setType changing bad path (" << path - << ") to be LL_PCODE_PATH_LINE" << llendl; + LL_WARNS() << "LLVolumeParams::setType changing bad path (" << path + << ") to be LL_PCODE_PATH_LINE" << LL_ENDL; path = LL_PCODE_PATH_LINE; } @@ -3599,769 +3689,125 @@ bool LLVolumeParams::validate(U8 prof_curve, F32 prof_begin, F32 prof_end, F32 h return true; } -S32 *LLVolume::getTriangleIndices(U32 &num_indices) const -{ - S32 expected_num_triangle_indices = getNumTriangleIndices(); - if (expected_num_triangle_indices > MAX_VOLUME_TRIANGLE_INDICES) +void LLVolume::getLoDTriangleCounts(const LLVolumeParams& params, S32* counts) +{ //attempt to approximate the number of triangles that will result from generating a volume LoD set for the + //supplied LLVolumeParams -- inaccurate, but a close enough approximation for determining streaming cost + F32 detail[] = {1.f, 1.5f, 2.5f, 4.f}; + for (S32 i = 0; i < 4; i++) { - // we don't allow LLVolumes with this many vertices - llwarns << "Couldn't allocate triangle indices" << llendl; - num_indices = 0; - return NULL; - } + S32 count = 0; + S32 path_points = LLPath::getNumPoints(params.getPathParams(), detail[i]); + S32 profile_points = LLProfile::getNumPoints(params.getProfileParams(), false, detail[i]); - S32* index = new S32[expected_num_triangle_indices]; - S32 count = 0; + count = (profile_points-1)*2*(path_points-1); + count += profile_points*2; - // Let's do this totally diffently, as we don't care about faces... - // Counter-clockwise triangles are forward facing... + counts[i] = count; + } +} - BOOL open = getProfile().isOpen(); - BOOL hollow = (mParams.getProfileParams().getHollow() > 0); - BOOL path_open = getPath().isOpen(); - S32 size_s, size_s_out, size_t; - S32 s, t, i; - size_s = getProfile().getTotal(); - size_s_out = getProfile().getTotalOut(); - size_t = getPath().mPath.size(); - // NOTE -- if the construction of the triangles below ever changes - // then getNumTriangleIndices() method may also have to be updated. +S32 LLVolume::getNumTriangles(S32* vcount) const +{ + U32 triangle_count = 0; + U32 vertex_count = 0; - if (open) /* Flawfinder: ignore */ + for (S32 i = 0; i < getNumVolumeFaces(); ++i) { - if (hollow) - { - // Open hollow -- much like the closed solid, except we - // we need to stitch up the gap between s=0 and s=size_s-1 + const LLVolumeFace& face = getVolumeFace(i); + triangle_count += face.mNumIndices/3; - for (t = 0; t < size_t - 1; t++) - { - // The outer face, first cut, and inner face - for (s = 0; s < size_s - 1; s++) - { - i = s + t*size_s; - index[count++] = i; // x,y - index[count++] = i + 1; // x+1,y - index[count++] = i + size_s; // x,y+1 + vertex_count += face.mNumVertices; + } + + + if (vcount) + { + *vcount = vertex_count; + } - index[count++] = i + size_s; // x,y+1 - index[count++] = i + 1; // x+1,y - index[count++] = i + size_s + 1; // x+1,y+1 - } + return triangle_count; +} + + +//----------------------------------------------------------------------------- +// generateSilhouetteVertices() +//----------------------------------------------------------------------------- +void LLVolume::generateSilhouetteVertices(std::vector &vertices, + std::vector &normals, + const LLVector3& obj_cam_vec_in, + const LLMatrix4a& mat_in, + const LLMatrix4a& norm_mat_in, + S32 face_mask) +{ + const LLMatrix4a& mat = mat_in; + + const LLMatrix4a& norm_mat = norm_mat_in; + + LLVector4a obj_cam_vec; + obj_cam_vec.load3(obj_cam_vec_in.mV); - // The other cut face - index[count++] = s + t*size_s; // x,y - index[count++] = 0 + t*size_s; // x+1,y - index[count++] = s + (t+1)*size_s; // x,y+1 + vertices.clear(); + normals.clear(); + + if ((mParams.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH) + { + return; + } - index[count++] = s + (t+1)*size_s; // x,y+1 - index[count++] = 0 + t*size_s; // x+1,y - index[count++] = 0 + (t+1)*size_s; // x+1,y+1 - } + S32 cur_index = 0; + //for each face + for (face_list_t::iterator iter = mVolumeFaces.begin(); + iter != mVolumeFaces.end(); ++iter) + { + const LLVolumeFace& face = *iter; + + if (!(face_mask & (0x1 << cur_index++)) || + face.mNumIndices == 0 || face.mEdge.empty()) + { + continue; + } - // Do the top and bottom caps, if necessary - if (path_open) - { - // Top cap - S32 pt1 = 0; - S32 pt2 = size_s-1; - S32 i = (size_t - 1)*size_s; + if (face.mTypeMask & (LLVolumeFace::CAP_MASK)) + { + LLVector4a* v = (LLVector4a*)face.mPositions; + LLVector4a* n = (LLVector4a*)face.mNormals; - while (pt2 - pt1 > 1) + for (U32 j = 0; j < (U32)face.mNumIndices / 3; j++) + { + for (S32 k = 0; k < 3; k++) { - // Use the profile points instead of the mesh, since you want - // the un-transformed profile distances. - LLVector3 p1 = getProfile().mProfile[pt1]; - LLVector3 p2 = getProfile().mProfile[pt2]; - LLVector3 pa = getProfile().mProfile[pt1+1]; - LLVector3 pb = getProfile().mProfile[pt2-1]; - - p1.mV[VZ] = 0.f; - p2.mV[VZ] = 0.f; - pa.mV[VZ] = 0.f; - pb.mV[VZ] = 0.f; - - // Use area of triangle to determine backfacing - F32 area_1a2, area_1ba, area_21b, area_2ab; - area_1a2 = (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) + - (pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) + - (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]); - - area_1ba = (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + - (pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) + - (pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]); - - area_21b = (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) + - (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + - (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); - - area_2ab = (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) + - (pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) + - (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); - - BOOL use_tri1a2 = TRUE; - BOOL tri_1a2 = TRUE; - BOOL tri_21b = TRUE; - - if (area_1a2 < 0) - { - tri_1a2 = FALSE; - } - if (area_2ab < 0) - { - // Can't use, because it contains point b - tri_1a2 = FALSE; - } - if (area_21b < 0) - { - tri_21b = FALSE; - } - if (area_1ba < 0) - { - // Can't use, because it contains point b - tri_21b = FALSE; - } + S32 index = face.mEdge[j * 3 + k]; - if (!tri_1a2) + if (index == -1) { - use_tri1a2 = FALSE; - } - else if (!tri_21b) - { - use_tri1a2 = TRUE; - } - else - { - LLVector3 d1 = p1 - pa; - LLVector3 d2 = p2 - pb; + // silhouette edge, currently only cubes, so no other conditions - if (d1.magVecSquared() < d2.magVecSquared()) - { - use_tri1a2 = TRUE; - } - else - { - use_tri1a2 = FALSE; - } - } + S32 v1 = face.mIndices[j * 3 + k]; + S32 v2 = face.mIndices[j * 3 + ((k + 1) % 3)]; - if (use_tri1a2) - { - index[count++] = pt1 + i; - index[count++] = pt1 + 1 + i; - index[count++] = pt2 + i; - pt1++; - } - else - { - index[count++] = pt1 + i; - index[count++] = pt2 - 1 + i; - index[count++] = pt2 + i; - pt2--; - } - } + LLVector4a t; + mat.affineTransform(v[v1], t); + vertices.push_back(LLVector3(t[0], t[1], t[2])); - // Bottom cap - pt1 = 0; - pt2 = size_s-1; - while (pt2 - pt1 > 1) - { - // Use the profile points instead of the mesh, since you want - // the un-transformed profile distances. - LLVector3 p1 = getProfile().mProfile[pt1]; - LLVector3 p2 = getProfile().mProfile[pt2]; - LLVector3 pa = getProfile().mProfile[pt1+1]; - LLVector3 pb = getProfile().mProfile[pt2-1]; - - p1.mV[VZ] = 0.f; - p2.mV[VZ] = 0.f; - pa.mV[VZ] = 0.f; - pb.mV[VZ] = 0.f; - - // Use area of triangle to determine backfacing - F32 area_1a2, area_1ba, area_21b, area_2ab; - area_1a2 = (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) + - (pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) + - (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]); - - area_1ba = (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + - (pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) + - (pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]); - - area_21b = (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) + - (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + - (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); - - area_2ab = (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) + - (pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) + - (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); - - BOOL use_tri1a2 = TRUE; - BOOL tri_1a2 = TRUE; - BOOL tri_21b = TRUE; - - if (area_1a2 < 0) - { - tri_1a2 = FALSE; - } - if (area_2ab < 0) - { - // Can't use, because it contains point b - tri_1a2 = FALSE; - } - if (area_21b < 0) - { - tri_21b = FALSE; - } - if (area_1ba < 0) - { - // Can't use, because it contains point b - tri_21b = FALSE; - } - - if (!tri_1a2) - { - use_tri1a2 = FALSE; - } - else if (!tri_21b) - { - use_tri1a2 = TRUE; - } - else - { - LLVector3 d1 = p1 - pa; - LLVector3 d2 = p2 - pb; - - if (d1.magVecSquared() < d2.magVecSquared()) - { - use_tri1a2 = TRUE; - } - else - { - use_tri1a2 = FALSE; - } - } - - if (use_tri1a2) - { - index[count++] = pt1; - index[count++] = pt2; - index[count++] = pt1 + 1; - pt1++; - } - else - { - index[count++] = pt1; - index[count++] = pt2; - index[count++] = pt2 - 1; - pt2--; - } - } - } - } - else - { - // Open solid - - for (t = 0; t < size_t - 1; t++) - { - // Outer face + 1 cut face - for (s = 0; s < size_s - 1; s++) - { - i = s + t*size_s; - - index[count++] = i; // x,y - index[count++] = i + 1; // x+1,y - index[count++] = i + size_s; // x,y+1 - - index[count++] = i + size_s; // x,y+1 - index[count++] = i + 1; // x+1,y - index[count++] = i + size_s + 1; // x+1,y+1 - } - - // The other cut face - index[count++] = (size_s - 1) + (t*size_s); // x,y - index[count++] = 0 + t*size_s; // x+1,y - index[count++] = (size_s - 1) + (t+1)*size_s; // x,y+1 - - index[count++] = (size_s - 1) + (t+1)*size_s; // x,y+1 - index[count++] = 0 + (t*size_s); // x+1,y - index[count++] = 0 + (t+1)*size_s; // x+1,y+1 - } - - // Do the top and bottom caps, if necessary - if (path_open) - { - for (s = 0; s < size_s - 2; s++) - { - index[count++] = s+1; - index[count++] = s; - index[count++] = size_s - 1; - } - - // We've got a top cap - S32 offset = (size_t - 1)*size_s; - for (s = 0; s < size_s - 2; s++) - { - // Inverted ordering from bottom cap. - index[count++] = offset + size_s - 1; - index[count++] = offset + s; - index[count++] = offset + s + 1; - } - } - } - } - else if (hollow) - { - // Closed hollow - // Outer face - - for (t = 0; t < size_t - 1; t++) - { - for (s = 0; s < size_s_out - 1; s++) - { - i = s + t*size_s; - - index[count++] = i; // x,y - index[count++] = i + 1; // x+1,y - index[count++] = i + size_s; // x,y+1 - - index[count++] = i + size_s; // x,y+1 - index[count++] = i + 1; // x+1,y - index[count++] = i + 1 + size_s; // x+1,y+1 - } - } - - // Inner face - // Invert facing from outer face - for (t = 0; t < size_t - 1; t++) - { - for (s = size_s_out; s < size_s - 1; s++) - { - i = s + t*size_s; - - index[count++] = i; // x,y - index[count++] = i + 1; // x+1,y - index[count++] = i + size_s; // x,y+1 - - index[count++] = i + size_s; // x,y+1 - index[count++] = i + 1; // x+1,y - index[count++] = i + 1 + size_s; // x+1,y+1 - } - } - - // Do the top and bottom caps, if necessary - if (path_open) - { - // Top cap - S32 pt1 = 0; - S32 pt2 = size_s-1; - S32 i = (size_t - 1)*size_s; - - while (pt2 - pt1 > 1) - { - // Use the profile points instead of the mesh, since you want - // the un-transformed profile distances. - LLVector3 p1 = getProfile().mProfile[pt1]; - LLVector3 p2 = getProfile().mProfile[pt2]; - LLVector3 pa = getProfile().mProfile[pt1+1]; - LLVector3 pb = getProfile().mProfile[pt2-1]; - - p1.mV[VZ] = 0.f; - p2.mV[VZ] = 0.f; - pa.mV[VZ] = 0.f; - pb.mV[VZ] = 0.f; - - // Use area of triangle to determine backfacing - F32 area_1a2, area_1ba, area_21b, area_2ab; - area_1a2 = (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) + - (pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) + - (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]); - - area_1ba = (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + - (pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) + - (pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]); - - area_21b = (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) + - (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + - (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); - - area_2ab = (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) + - (pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) + - (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); - - BOOL use_tri1a2 = TRUE; - BOOL tri_1a2 = TRUE; - BOOL tri_21b = TRUE; - - if (area_1a2 < 0) - { - tri_1a2 = FALSE; - } - if (area_2ab < 0) - { - // Can't use, because it contains point b - tri_1a2 = FALSE; - } - if (area_21b < 0) - { - tri_21b = FALSE; - } - if (area_1ba < 0) - { - // Can't use, because it contains point b - tri_21b = FALSE; - } - - if (!tri_1a2) - { - use_tri1a2 = FALSE; - } - else if (!tri_21b) - { - use_tri1a2 = TRUE; - } - else - { - LLVector3 d1 = p1 - pa; - LLVector3 d2 = p2 - pb; - - if (d1.magVecSquared() < d2.magVecSquared()) - { - use_tri1a2 = TRUE; - } - else - { - use_tri1a2 = FALSE; - } - } - - if (use_tri1a2) - { - index[count++] = pt1 + i; - index[count++] = pt1 + 1 + i; - index[count++] = pt2 + i; - pt1++; - } - else - { - index[count++] = pt1 + i; - index[count++] = pt2 - 1 + i; - index[count++] = pt2 + i; - pt2--; - } - } - - // Bottom cap - pt1 = 0; - pt2 = size_s-1; - while (pt2 - pt1 > 1) - { - // Use the profile points instead of the mesh, since you want - // the un-transformed profile distances. - LLVector3 p1 = getProfile().mProfile[pt1]; - LLVector3 p2 = getProfile().mProfile[pt2]; - LLVector3 pa = getProfile().mProfile[pt1+1]; - LLVector3 pb = getProfile().mProfile[pt2-1]; - - p1.mV[VZ] = 0.f; - p2.mV[VZ] = 0.f; - pa.mV[VZ] = 0.f; - pb.mV[VZ] = 0.f; - - // Use area of triangle to determine backfacing - F32 area_1a2, area_1ba, area_21b, area_2ab; - area_1a2 = (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) + - (pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) + - (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]); - - area_1ba = (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + - (pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) + - (pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]); - - area_21b = (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) + - (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + - (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); - - area_2ab = (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) + - (pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) + - (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); - - BOOL use_tri1a2 = TRUE; - BOOL tri_1a2 = TRUE; - BOOL tri_21b = TRUE; + norm_mat.rotate(n[v1], t); - if (area_1a2 < 0) - { - tri_1a2 = FALSE; - } - if (area_2ab < 0) - { - // Can't use, because it contains point b - tri_1a2 = FALSE; - } - if (area_21b < 0) - { - tri_21b = FALSE; - } - if (area_1ba < 0) - { - // Can't use, because it contains point b - tri_21b = FALSE; - } + t.normalize3fast(); + normals.push_back(LLVector3(t[0], t[1], t[2])); - if (!tri_1a2) - { - use_tri1a2 = FALSE; - } - else if (!tri_21b) - { - use_tri1a2 = TRUE; - } - else - { - LLVector3 d1 = p1 - pa; - LLVector3 d2 = p2 - pb; + mat.affineTransform(v[v2], t); + vertices.push_back(LLVector3(t[0], t[1], t[2])); - if (d1.magVecSquared() < d2.magVecSquared()) - { - use_tri1a2 = TRUE; - } - else - { - use_tri1a2 = FALSE; + norm_mat.rotate(n[v2], t); + t.normalize3fast(); + normals.push_back(LLVector3(t[0], t[1], t[2])); } } - - if (use_tri1a2) - { - index[count++] = pt1; - index[count++] = pt2; - index[count++] = pt1 + 1; - pt1++; - } - else - { - index[count++] = pt1; - index[count++] = pt2; - index[count++] = pt2 - 1; - pt2--; - } } - } - } - else - { - // Closed solid. Easy case. - for (t = 0; t < size_t - 1; t++) - { - for (s = 0; s < size_s - 1; s++) - { - // Should wrap properly, but for now... - i = s + t*size_s; - - index[count++] = i; // x,y - index[count++] = i + 1; // x+1,y - index[count++] = i + size_s; // x,y+1 - - index[count++] = i + size_s; // x,y+1 - index[count++] = i + 1; // x+1,y - index[count++] = i + size_s + 1; // x+1,y+1 - } - } - - // Do the top and bottom caps, if necessary - if (path_open) - { - // bottom cap - for (s = 1; s < size_s - 2; s++) - { - index[count++] = s+1; - index[count++] = s; - index[count++] = 0; - } - - // top cap - S32 offset = (size_t - 1)*size_s; - for (s = 1; s < size_s - 2; s++) - { - // Inverted ordering from bottom cap. - index[count++] = offset; - index[count++] = offset + s; - index[count++] = offset + s + 1; - } - } - } - -#ifdef LL_DEBUG - // assert that we computed the correct number of indices - if (count != expected_num_triangle_indices ) - { - llerrs << "bad index count prediciton:" - << " expected=" << expected_num_triangle_indices - << " actual=" << count << llendl; - } -#endif - -#if 0 - // verify that each index does not point beyond the size of the mesh - S32 num_vertices = mMesh.size(); - for (i = 0; i < count; i+=3) - { - llinfos << index[i] << ":" << index[i+1] << ":" << index[i+2] << llendl; - llassert(index[i] < num_vertices); - llassert(index[i+1] < num_vertices); - llassert(index[i+2] < num_vertices); - } -#endif - - num_indices = count; - return index; -} - -void LLVolume::getLoDTriangleCounts(const LLVolumeParams& params, S32* counts) -{ //attempt to approximate the number of triangles that will result from generating a volume LoD set for the - //supplied LLVolumeParams -- inaccurate, but a close enough approximation for determining streaming cost - F32 detail[] = {1.f, 1.5f, 2.5f, 4.f}; - for (S32 i = 0; i < 4; i++) - { - S32 count = 0; - S32 path_points = LLPath::getNumPoints(params.getPathParams(), detail[i]); - S32 profile_points = LLProfile::getNumPoints(params.getProfileParams(), false, detail[i]); - - count = (profile_points-1)*2*(path_points-1); - count += profile_points*2; - - counts[i] = count; - } -} - -S32 LLVolume::getNumTriangleIndices() const -{ - BOOL profile_open = getProfile().isOpen(); - BOOL hollow = (mParams.getProfileParams().getHollow() > 0); - BOOL path_open = getPath().isOpen(); - - S32 size_s, size_s_out, size_t; - size_s = getProfile().getTotal(); - size_s_out = getProfile().getTotalOut(); - size_t = getPath().mPath.size(); - - S32 count = 0; - if (profile_open) /* Flawfinder: ignore */ - { - if (hollow) - { - // Open hollow -- much like the closed solid, except we - // we need to stitch up the gap between s=0 and s=size_s-1 - count = (size_t - 1) * (((size_s -1) * 6) + 6); + } else { - count = (size_t - 1) * (((size_s -1) * 6) + 6); - } - } - else if (hollow) - { - // Closed hollow - // Outer face - count = (size_t - 1) * (size_s_out - 1) * 6; - - // Inner face - count += (size_t - 1) * ((size_s - 1) - size_s_out) * 6; - } - else - { - // Closed solid. Easy case. - count = (size_t - 1) * (size_s - 1) * 6; - } - - if (path_open) - { - S32 cap_triangle_count = size_s - 3; - if ( profile_open - || hollow ) - { - cap_triangle_count = size_s - 2; - } - if ( cap_triangle_count > 0 ) - { - // top and bottom caps - count += cap_triangle_count * 2 * 3; - } - } - return count; -} - - -S32 LLVolume::getNumTriangles(S32* vcount) const -{ - U32 triangle_count = 0; - U32 vertex_count = 0; - - for (S32 i = 0; i < getNumVolumeFaces(); ++i) - { - const LLVolumeFace& face = getVolumeFace(i); - triangle_count += face.mNumIndices/3; - - vertex_count += face.mNumVertices; - } - - - if (vcount) - { - *vcount = vertex_count; - } - - return triangle_count; -} - - -//----------------------------------------------------------------------------- -// generateSilhouetteVertices() -//----------------------------------------------------------------------------- -void LLVolume::generateSilhouetteVertices(std::vector &vertices, - std::vector &normals, - const LLVector3& obj_cam_vec_in, - const LLMatrix4& mat_in, - const LLMatrix3& norm_mat_in, - S32 face_mask) -{ - LLMatrix4a mat; - mat.loadu(mat_in); - - LLMatrix4a norm_mat; - norm_mat.loadu(norm_mat_in); - - LLVector4a obj_cam_vec; - obj_cam_vec.load3(obj_cam_vec_in.mV); - - vertices.clear(); - normals.clear(); - - if ((mParams.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH) - { - return; - } - - S32 cur_index = 0; - //for each face - for (face_list_t::iterator iter = mVolumeFaces.begin(); - iter != mVolumeFaces.end(); ++iter) - { - const LLVolumeFace& face = *iter; - - if (!(face_mask & (0x1 << cur_index++)) || - face.mNumIndices == 0 || face.mEdge.empty()) - { - continue; - } - - if (face.mTypeMask & (LLVolumeFace::CAP_MASK)) { - - } - else { //============================================== //DEBUG draw edge map instead of silhouette edge @@ -4430,7 +3876,7 @@ void LLVolume::generateSilhouetteVertices(std::vector &vertices, normals.push_back(LLVector3(0,0,1)); #if DEBUG_SILHOUETTE_BINORMALS vertices.push_back(face.mVertices[j].getPosition()); - vertices.push_back(face.mVertices[j].getPosition() + face.mVertices[j].mBinormal*0.1f); + vertices.push_back(face.mVertices[j].getPosition() + face.mVertices[j].mTangent*0.1f); normals.push_back(LLVector3(0,0,1)); normals.push_back(LLVector3(0,0,1)); #endif @@ -4545,22 +3991,9 @@ void LLVolume::generateSilhouetteVertices(std::vector &vertices, } } -S32 LLVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, - S32 face, - LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal) -{ - LLVector4a starta, enda; - starta.load3(start.mV); - enda.load3(end.mV); - - return lineSegmentIntersect(starta, enda, face, intersection, tex_coord, normal, bi_normal); - -} - - S32 LLVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, S32 face, - LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal) + LLVector4a* intersection,LLVector2* tex_coord, LLVector4a* normal, LLVector4a* tangent_out) { S32 hit_face = -1; @@ -4598,9 +4031,9 @@ S32 LLVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& en if (LLLineSegmentBoxIntersect(start, end, box_center, box_size)) { - if (bi_normal != NULL) // if the caller wants binormals, we may need to generate them + if (tangent_out != NULL) // if the caller wants tangents, we may need to generate them { - genBinormals(i); + genTangents(i); } if (isUnique()) @@ -4634,7 +4067,7 @@ S32 LLVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& en LLVector4a intersect = dir; intersect.mul(closest_t); intersect.add(start); - intersection->set(intersect.getF32ptr()); + *intersection = intersect; } @@ -4649,19 +4082,42 @@ S32 LLVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& en if (normal!= NULL) { - LLVector4* norm = (LLVector4*) face.mNormals; - - *normal = ((1.f - a - b) * LLVector3(norm[idx0]) + - a * LLVector3(norm[idx1]) + - b * LLVector3(norm[idx2])); + LLVector4a* norm = face.mNormals; + + LLVector4a n1,n2,n3; + n1 = norm[idx0]; + n1.mul(1.f-a-b); + + n2 = norm[idx1]; + n2.mul(a); + + n3 = norm[idx2]; + n3.mul(b); + + n1.add(n2); + n1.add(n3); + + *normal = n1; } - if (bi_normal != NULL) + if (tangent_out != NULL) { - LLVector4* binormal = (LLVector4*) face.mBinormals; - *bi_normal = ((1.f - a - b) * LLVector3(binormal[idx0]) + - a * LLVector3(binormal[idx1]) + - b * LLVector3(binormal[idx2])); + LLVector4a* tangents = face.mTangents; + + LLVector4a t1,t2,t3; + t1 = tangents[idx0]; + t1.mul(1.f-a-b); + + t2 = tangents[idx1]; + t2.mul(a); + + t3 = tangents[idx2]; + t3.mul(b); + + t1.add(t2); + t1.add(t3); + + *tangent_out = t1; } } } @@ -4674,7 +4130,7 @@ S32 LLVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& en face.createOctree(); } - LLOctreeTriangleRayIntersect intersect(start, dir, &face, &closest_t, intersection, tex_coord, normal, bi_normal); + LLOctreeTriangleRayIntersect intersect(start, dir, &face, &closest_t, intersection, tex_coord, normal, tangent_out); intersect.traverse(face.mOctree); if (intersect.mHitFace) { @@ -4789,7 +4245,7 @@ BOOL equalTriangle(const S32 *a, const S32 *b) BOOL LLVolumeParams::importFile(LLFILE *fp) { - //llinfos << "importing volume" << llendl; + //LL_INFOS() << "importing volume" << LL_ENDL; const S32 BUFSIZE = 16384; char buffer[BUFSIZE]; /* Flawfinder: ignore */ // *NOTE: changing the size or type of this buffer will require @@ -4823,7 +4279,7 @@ BOOL LLVolumeParams::importFile(LLFILE *fp) } else { - llwarns << "unknown keyword " << keyword << " in volume import" << llendl; + LL_WARNS() << "unknown keyword " << keyword << " in volume import" << LL_ENDL; } } @@ -4843,7 +4299,7 @@ BOOL LLVolumeParams::exportFile(LLFILE *fp) const BOOL LLVolumeParams::importLegacyStream(std::istream& input_stream) { - //llinfos << "importing volume" << llendl; + //LL_INFOS() << "importing volume" << LL_ENDL; const S32 BUFSIZE = 16384; // *NOTE: changing the size or type of this buffer will require // changing the sscanf below. @@ -4873,7 +4329,7 @@ BOOL LLVolumeParams::importLegacyStream(std::istream& input_stream) } else { - llwarns << "unknown keyword " << keyword << " in volume import" << llendl; + LL_WARNS() << "unknown keyword " << keyword << " in volume import" << LL_ENDL; } } @@ -5085,7 +4541,7 @@ LLFaceID LLVolume::generateFaceMask() } break; default: - llerrs << "Unknown profile!" << llendl; + LL_ERRS() << "Unknown profile!" << LL_ENDL; break; } @@ -5217,14 +4673,17 @@ LLVolumeFace::LLVolumeFace() : mNumS(0), mNumT(0), mNumVertices(0), + mNumAllocatedVertices(0), mNumIndices(0), mPositions(NULL), mNormals(NULL), - mBinormals(NULL), + mTangents(NULL), mTexCoords(NULL), mIndices(NULL), mWeights(NULL), - mOctree(NULL) + mWeightsScrubbed(FALSE), + mOctree(NULL), + mOptimized(FALSE) { mExtents = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*3); mExtents[0].splat(-0.5f); @@ -5240,14 +4699,17 @@ LLVolumeFace::LLVolumeFace(const LLVolumeFace& src) mNumS(0), mNumT(0), mNumVertices(0), + mNumAllocatedVertices(0), mNumIndices(0), mPositions(NULL), mNormals(NULL), - mBinormals(NULL), + mTangents(NULL), mTexCoords(NULL), mIndices(NULL), mWeights(NULL), - mOctree(NULL) + mWeightsScrubbed(FALSE), + mOctree(NULL), + mOptimized(FALSE) { mExtents = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*3); mCenter = mExtents+2; @@ -5277,8 +4739,6 @@ LLVolumeFace& LLVolumeFace::operator=(const LLVolumeFace& src) freeData(); - LLVector4a::memcpyNonAliased16((F32*) mExtents, (F32*) src.mExtents, 3*sizeof(LLVector4a)); - resizeVertices(src.mNumVertices); resizeIndices(src.mNumIndices); @@ -5288,40 +4748,29 @@ LLVolumeFace& LLVolumeFace::operator=(const LLVolumeFace& src) S32 tc_size = (mNumVertices*sizeof(LLVector2)+0xF) & ~0xF; LLVector4a::memcpyNonAliased16((F32*) mPositions, (F32*) src.mPositions, vert_size); - LLVector4a::memcpyNonAliased16((F32*) mNormals, (F32*) src.mNormals, vert_size); - if(src.mTexCoords) + if (src.mNormals) { - LLVector4a::memcpyNonAliased16((F32*) mTexCoords, (F32*) src.mTexCoords, tc_size); + LLVector4a::memcpyNonAliased16((F32*) mNormals, (F32*) src.mNormals, vert_size); } - else - { - ll_aligned_free_16(mTexCoords) ; - mTexCoords = NULL ; - } - - if (src.mBinormals) + if(src.mTexCoords) { - allocateBinormals(src.mNumVertices); - LLVector4a::memcpyNonAliased16((F32*) mBinormals, (F32*) src.mBinormals, vert_size); + LLVector4a::memcpyNonAliased16((F32*) mTexCoords, (F32*) src.mTexCoords, tc_size); } - else + + allocateTangents(src.mTangents ? src.mNumVertices : 0); + if (src.mTangents) { - ll_aligned_free_16(mBinormals); - mBinormals = NULL; + LLVector4a::memcpyNonAliased16((F32*)mTangents, (F32*)src.mTangents, vert_size); } + allocateWeights(src.mWeights ? src.mNumVertices : 0); if (src.mWeights) { - allocateWeights(src.mNumVertices); LLVector4a::memcpyNonAliased16((F32*) mWeights, (F32*) src.mWeights, vert_size); } - else - { - ll_aligned_free_16(mWeights); - mWeights = NULL; - } + mWeightsScrubbed = src.mWeightsScrubbed; } if (mNumIndices) @@ -5331,6 +4780,8 @@ LLVolumeFace& LLVolumeFace::operator=(const LLVolumeFace& src) LLVector4a::memcpyNonAliased16((F32*) mIndices, (F32*) src.mIndices, idx_size); } + mOptimized = src.mOptimized; + //delete return *this; } @@ -5339,24 +4790,17 @@ LLVolumeFace::~LLVolumeFace() { ll_aligned_free_16(mExtents); mExtents = NULL; + mCenter = NULL; freeData(); } void LLVolumeFace::freeData() { - ll_aligned_free_16(mPositions); - mPositions = NULL; - ll_aligned_free_16( mNormals); - mNormals = NULL; - ll_aligned_free_16(mTexCoords); - mTexCoords = NULL; - ll_aligned_free_16(mIndices); - mIndices = NULL; - ll_aligned_free_16(mBinormals); - mBinormals = NULL; - ll_aligned_free_16(mWeights); - mWeights = NULL; + allocateVertices(0); + allocateTangents(0); + allocateWeights(0); + allocateIndices(0); delete mOctree; mOctree = NULL; @@ -5379,39 +4823,7 @@ BOOL LLVolumeFace::create(LLVolume* volume, BOOL partial_build) } else { - llerrs << "Unknown/uninitialized face type!" << llendl; - } - - //update the range of the texture coordinates - if(ret) - { - mTexCoordExtents[0].setVec(1.f, 1.f) ; - mTexCoordExtents[1].setVec(0.f, 0.f) ; - - for(U32 i = 0 ; i < (U32)mNumVertices ; i++) - { - if(mTexCoordExtents[0].mV[0] > mTexCoords[i].mV[0]) - { - mTexCoordExtents[0].mV[0] = mTexCoords[i].mV[0] ; - } - if(mTexCoordExtents[1].mV[0] < mTexCoords[i].mV[0]) - { - mTexCoordExtents[1].mV[0] = mTexCoords[i].mV[0] ; - } - - if(mTexCoordExtents[0].mV[1] > mTexCoords[i].mV[1]) - { - mTexCoordExtents[0].mV[1] = mTexCoords[i].mV[1] ; - } - if(mTexCoordExtents[1].mV[1] < mTexCoords[i].mV[1]) - { - mTexCoordExtents[1].mV[1] = mTexCoords[i].mV[1] ; - } - } - mTexCoordExtents[0].mV[0] = llmax(0.f, mTexCoordExtents[0].mV[0]) ; - mTexCoordExtents[0].mV[1] = llmax(0.f, mTexCoordExtents[0].mV[1]) ; - mTexCoordExtents[1].mV[0] = llmin(1.f, mTexCoordExtents[1].mV[0]) ; - mTexCoordExtents[1].mV[1] = llmin(1.f, mTexCoordExtents[1].mV[1]) ; + LL_ERRS() << "Unknown/uninitialized face type!" << LL_ENDL; } return ret ; @@ -5529,22 +4941,28 @@ void LLVolumeFace::optimize(F32 angle_cutoff) } } - llassert(new_face.mNumIndices == mNumIndices); - llassert(new_face.mNumVertices <= mNumVertices); if (angle_cutoff > 1.f && !mNormals) { - ll_aligned_free_16(new_face.mNormals); + // Now alloc'd with positions + //ll_aligned_free_16(new_face.mNormals); new_face.mNormals = NULL; } if (!mTexCoords) { - ll_aligned_free_16(new_face.mTexCoords); + // Now alloc'd with positions + //ll_aligned_free_16(new_face.mTexCoords); new_face.mTexCoords = NULL; } - swapData(new_face); + // Only swap data if we've actually optimized the mesh + // + if (new_face.mNumVertices <= mNumVertices) + { + llassert(new_face.mNumIndices == mNumIndices); + swapData(new_face); + } } class LLVCacheTriangleData; @@ -5554,14 +4972,14 @@ class LLVCacheVertexData public: S32 mIdx; S32 mCacheTag; - F32 mScore; + F64 mScore; U32 mActiveTriangles; std::vector mTriangles; LLVCacheVertexData() { mCacheTag = -1; - mScore = 0.f; + mScore = 0.0; mActiveTriangles = 0; mIdx = -1; } @@ -5571,13 +4989,13 @@ class LLVCacheTriangleData { public: bool mActive; - F32 mScore; + F64 mScore; LLVCacheVertexData* mVertex[3]; LLVCacheTriangleData() { mActive = true; - mScore = 0.f; + mScore = 0.0; mVertex[0] = mVertex[1] = mVertex[2] = NULL; } @@ -5588,7 +5006,7 @@ class LLVCacheTriangleData { if (mVertex[i]) { - llassert_always(mVertex[i]->mActiveTriangles > 0); + llassert(mVertex[i]->mActiveTriangles > 0); mVertex[i]->mActiveTriangles--; } } @@ -5600,20 +5018,20 @@ class LLVCacheTriangleData } }; -const F32 FindVertexScore_CacheDecayPower = 1.5f; -const F32 FindVertexScore_LastTriScore = 0.75f; -const F32 FindVertexScore_ValenceBoostScale = 2.0f; -const F32 FindVertexScore_ValenceBoostPower = 0.5f; +const F64 FindVertexScore_CacheDecayPower = 1.5; +const F64 FindVertexScore_LastTriScore = 0.75; +const F64 FindVertexScore_ValenceBoostScale = 2.0; +const F64 FindVertexScore_ValenceBoostPower = 0.5; const U32 MaxSizeVertexCache = 32; +const F64 FindVertexScore_Scaler = 1.0/(MaxSizeVertexCache-3); -F32 find_vertex_score(LLVCacheVertexData& data) +F64 find_vertex_score(LLVCacheVertexData& data) { - if (data.mActiveTriangles == 0) - { //no triangle references this vertex - return -1.f; - } + F64 score = -1.0; - F32 score = 0.f; + if (data.mActiveTriangles >= 0) + { + score = 0.0; S32 cache_idx = data.mCacheTag; @@ -5629,15 +5047,15 @@ F32 find_vertex_score(LLVCacheVertexData& data) } else { //more points for being higher in the cache - F32 scaler = 1.f/(MaxSizeVertexCache-3); - score = 1.f-((cache_idx-3)*scaler); - score = powf(score, FindVertexScore_CacheDecayPower); + score = 1.0-((cache_idx-3)*FindVertexScore_Scaler); + score = pow(score, FindVertexScore_CacheDecayPower); } } //bonus points for having low valence - F32 valence_boost = powf((F32)data.mActiveTriangles, -FindVertexScore_ValenceBoostPower); + F64 valence_boost = pow((F64)data.mActiveTriangles, -FindVertexScore_ValenceBoostPower); score += FindVertexScore_ValenceBoostScale * valence_boost; + } return score; } @@ -5744,32 +5162,44 @@ class LLVCacheLRU void updateScores() { - for (U32 i = MaxSizeVertexCache; i < MaxSizeVertexCache+3; ++i) - { //trailing 3 vertices aren't actually in the cache for scoring purposes - if (mCache[i]) + LLVCacheVertexData** data_iter = mCache+MaxSizeVertexCache; + LLVCacheVertexData** end_data = mCache+MaxSizeVertexCache+3; + + while(data_iter != end_data) + { + LLVCacheVertexData* data = *data_iter++; + //trailing 3 vertices aren't actually in the cache for scoring purposes + if (data) { - mCache[i]->mCacheTag = -1; + data->mCacheTag = -1; } } - for (U32 i = 0; i < MaxSizeVertexCache; ++i) + data_iter = mCache; + end_data = mCache+MaxSizeVertexCache; + + while (data_iter != end_data) { //update scores of vertices in cache - if (mCache[i]) + LLVCacheVertexData* data = *data_iter++; + if (data) { - mCache[i]->mScore = find_vertex_score(*(mCache[i])); - llassert_always(mCache[i]->mCacheTag == i); + data->mScore = find_vertex_score(*data); } } mBestTriangle = NULL; //update triangle scores - for (U32 i = 0; i < MaxSizeVertexCache+3; ++i) + data_iter = mCache; + end_data = mCache+MaxSizeVertexCache+3; + + while (data_iter != end_data) { - if (mCache[i]) + LLVCacheVertexData* data = *data_iter++; + if (data) { - for (U32 j = 0; j < mCache[i]->mTriangles.size(); ++j) + for (std::vector::iterator iter = data->mTriangles.begin(), end_iter = data->mTriangles.end(); iter != end_iter; ++iter) { - LLVCacheTriangleData* tri = mCache[i]->mTriangles[j]; + LLVCacheTriangleData* tri = *iter; if (tri->mActive) { tri->mScore = tri->mVertex[0]->mScore; @@ -5786,13 +5216,17 @@ class LLVCacheLRU } //knock trailing 3 vertices off the cache - for (U32 i = MaxSizeVertexCache; i < MaxSizeVertexCache+3; ++i) + data_iter = mCache+MaxSizeVertexCache; + end_data = mCache+MaxSizeVertexCache+3; + while (data_iter != end_data) { - if (mCache[i]) + LLVCacheVertexData* data = *data_iter; + if (data) { - llassert_always(mCache[i]->mCacheTag == -1); - mCache[i] = NULL; + llassert(data->mCacheTag == -1); + *data_iter = NULL; } + ++data_iter; } } }; @@ -5801,9 +5235,12 @@ class LLVCacheLRU void LLVolumeFace::cacheOptimize() { //optimize for vertex cache according to Forsyth method: // http://home.comcast.net/~tom_forsyth/papers/fast_vert_cache_opt.html - + + llassert(!mOptimized); + mOptimized = TRUE; + LLVCacheLRU cache; - + if (mNumVertices < 3) { //nothing to do return; @@ -5815,17 +5252,17 @@ void LLVolumeFace::cacheOptimize() //mapping of triangles do vertices std::vector triangle_data; - triangle_data.resize(mNumIndices/3); + triangle_data.resize(mNumIndices / 3); vertex_data.resize(mNumVertices); for (U32 i = 0; i < (U32)mNumIndices; i++) { //populate vertex data and triangle data arrays U16 idx = mIndices[i]; - U32 tri_idx = i/3; + U32 tri_idx = i / 3; vertex_data[idx].mTriangles.push_back(&(triangle_data[tri_idx])); vertex_data[idx].mIdx = idx; - triangle_data[tri_idx].mVertex[i%3] = &(vertex_data[idx]); + triangle_data[tri_idx].mVertex[i % 3] = &(vertex_data[idx]); } /*F32 pre_acmr = 1.f; @@ -5847,12 +5284,14 @@ void LLVolumeFace::cacheOptimize() for (U32 i = 0; i < (U32)mNumVertices; i++) { //initialize score values (no cache -- might try a fifo cache here) - vertex_data[i].mScore = find_vertex_score(vertex_data[i]); - vertex_data[i].mActiveTriangles = vertex_data[i].mTriangles.size(); + LLVCacheVertexData& data = vertex_data[i]; - for (U32 j = 0; j < vertex_data[i].mTriangles.size(); ++j) + data.mScore = find_vertex_score(data); + data.mActiveTriangles = data.mTriangles.size(); + + for (U32 j = 0; j < data.mActiveTriangles; ++j) { - vertex_data[i].mTriangles[j]->mScore += vertex_data[i].mScore; + data.mTriangles[j]->mScore += data.mScore; } } @@ -5872,7 +5311,7 @@ void LLVolumeFace::cacheOptimize() tri->complete(); U32 breaks = 0; - for (U32 i = 1; i < (U32)mNumIndices/3; ++i) + for (U32 i = 1; i < (U32)mNumIndices / 3; ++i) { cache.updateScores(); tri = cache.mBestTriangle; @@ -5887,8 +5326,8 @@ void LLVolumeFace::cacheOptimize() break; } } - } - + } + cache.addTriangle(tri); new_indices.push_back(tri->mVertex[0]->mIdx); new_indices.push_back(tri->mVertex[1]->mIdx); @@ -5914,29 +5353,36 @@ void LLVolumeFace::cacheOptimize() { test_cache.addVertex(&vertex_data[mIndices[i]]); } - + post_acmr = (F32) test_cache.mMisses/(mNumIndices/3); }*/ //optimize for pre-TnL cache - + //allocate space for new buffer S32 num_verts = mNumVertices; - LLVector4a* pos = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts); - LLVector4a* norm = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts); - S32 size = ((num_verts*sizeof(LLVector2)) + 0xF) & ~0xF; - LLVector2* tc = (LLVector2*) ll_aligned_malloc_16(size); - LLVector4a* wght = NULL; - if (mWeights) + LLVector4a* old_pos = mPositions; + LLVector4a* old_norm = old_pos + num_verts; + LLVector2* old_tc = (LLVector2*)(old_norm + num_verts); + mPositions = NULL; + if (old_pos) { - wght = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts); + allocateVertices(num_verts); } - LLVector4a* binorm = NULL; - if (mBinormals) + LLVector4a* old_wght = mWeights; + mWeights = NULL; + if (old_wght) { - binorm = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts); + allocateWeights(num_verts); + } + + LLVector4a* old_binorm = mTangents; + mTangents = NULL; + if (old_binorm) + { + allocateTangents(num_verts); } //allocate mapping of old indices to new indices @@ -5952,16 +5398,16 @@ void LLVolumeFace::cacheOptimize() new_idx[idx] = cur_idx; //copy vertex data - pos[cur_idx] = mPositions[idx]; - norm[cur_idx] = mNormals[idx]; - tc[cur_idx] = mTexCoords[idx]; + mPositions[cur_idx] = old_pos[idx]; + mNormals[cur_idx] = old_norm[idx]; + mTexCoords[cur_idx] = old_tc[idx]; if (mWeights) { - wght[cur_idx] = mWeights[idx]; + mWeights[cur_idx] = old_wght[idx]; } - if (mBinormals) + if (mTangents) { - binorm[cur_idx] = mBinormals[idx]; + mTangents[cur_idx] = old_binorm[idx]; } cur_idx++; @@ -5973,20 +5419,14 @@ void LLVolumeFace::cacheOptimize() mIndices[i] = new_idx[mIndices[i]]; } - ll_aligned_free_16(mPositions); - ll_aligned_free_16(mNormals); - ll_aligned_free_16(mTexCoords); - ll_aligned_free_16(mWeights); - ll_aligned_free_16(mBinormals); + ll_aligned_free<64>(old_pos); + ll_aligned_free_16(old_binorm); + ll_aligned_free_16(old_wght); - mPositions = pos; - mNormals = norm; - mTexCoords = tc; - mWeights = wght; - mBinormals = binorm; + // DO NOT free mNormals and mTexCoords as they are part of mPositions buffer //std::string result = llformat("ACMR pre/post: %.3f/%.3f -- %d triangles %d breaks", pre_acmr, post_acmr, mNumIndices/3, breaks); - //llinfos << result << llendl; + //LL_INFOS() << result << LL_ENDL; } @@ -6064,7 +5504,7 @@ void LLVolumeFace::swapData(LLVolumeFace& rhs) { llswap(rhs.mPositions, mPositions); llswap(rhs.mNormals, mNormals); - llswap(rhs.mBinormals, mBinormals); + llswap(rhs.mTangents, mTangents); llswap(rhs.mTexCoords, mTexCoords); llswap(rhs.mIndices,mIndices); llswap(rhs.mNumVertices, mNumVertices); @@ -6097,8 +5537,9 @@ void LerpPlanarVertex(LLVolumeFace::VertexData& v0, BOOL LLVolumeFace::createUnCutCubeCap(LLVolume* volume, BOOL partial_build) { - const std::vector& mesh = volume->getMesh(); - const std::vector& profile = volume->getProfile().mProfile; + + const LLAlignedArray& mesh = volume->getMesh(); + const LLAlignedArray& profile = volume->getProfile().mProfile; S32 max_s = volume->getProfile().getTotal(); S32 max_t = volume->getPath().mPath.size(); @@ -6123,9 +5564,9 @@ BOOL LLVolumeFace::createUnCutCubeCap(LLVolume* volume, BOOL partial_build) VertexData baseVert; for(S32 t = 0; t < 4; t++) { - corners[t].getPosition().load3( mesh[offset + (grid_size*t)].mPos.mV); - corners[t].mTexCoord.mV[0] = profile[grid_size*t].mV[0]+0.5f; - corners[t].mTexCoord.mV[1] = 0.5f - profile[grid_size*t].mV[1]; + corners[t].getPosition().load4a(mesh[offset + (grid_size*t)].getF32ptr()); + corners[t].mTexCoord.mV[0] = profile[grid_size*t][0]+0.5f; + corners[t].mTexCoord.mV[1] = 0.5f - profile[grid_size*t][1]; } { @@ -6153,22 +5594,11 @@ BOOL LLVolumeFace::createUnCutCubeCap(LLVolume* volume, BOOL partial_build) corners[2].mTexCoord=swap; } - LLVector4a binormal; - - calc_binormal_from_triangle( binormal, - corners[0].getPosition(), corners[0].mTexCoord, - corners[1].getPosition(), corners[1].mTexCoord, - corners[2].getPosition(), corners[2].mTexCoord); - - binormal.normalize3fast(); - S32 size = (grid_size+1)*(grid_size+1); resizeVertices(size); - allocateBinormals(size); - + LLVector4a* pos = (LLVector4a*) mPositions; LLVector4a* norm = (LLVector4a*) mNormals; - LLVector4a* binorm = (LLVector4a*) mBinormals; LLVector2* tc = (LLVector2*) mTexCoords; for(int gx = 0;gxisMeshAssetLoaded()) + { + mEdge.resize(grid_size*grid_size * 6); + } U16* out = mIndices; - S32 idxs[] = {0,1,(grid_size+1)+1,(grid_size+1)+1,(grid_size+1),0}; - for(S32 gx = 0;gx=0;i--) + S32 idxs[] = {0,1,(grid_size+1)+1,(grid_size+1)+1,(grid_size+1),0}; + + int cur_edge = 0; + + for(S32 gx = 0;gx=0;i--) + { + *out++ = ((gy*(grid_size+1))+gx+idxs[i]); + } + + S32 edge_value = grid_size * 2 * gy + gx * 2; + + if (gx > 0) + { + mEdge[cur_edge++] = edge_value; + } + else + { + mEdge[cur_edge++] = -1; // Mark face to higlight it + } + + if (gy < grid_size - 1) + { + mEdge[cur_edge++] = edge_value; + } + else + { + mEdge[cur_edge++] = -1; + } + + mEdge[cur_edge++] = edge_value; + + if (gx < grid_size - 1) + { + mEdge[cur_edge++] = edge_value; + } + else + { + mEdge[cur_edge++] = -1; + } + + if (gy > 0) + { + mEdge[cur_edge++] = edge_value; + } + else + { + mEdge[cur_edge++] = -1; + } + + mEdge[cur_edge++] = edge_value; + } + else + { + for(S32 i=0;i<6;i++) + { + *out++ = ((gy*(grid_size+1))+gx+idxs[i]); + } + + S32 edge_value = grid_size * 2 * gy + gx * 2; + + if (gy > 0) + { + mEdge[cur_edge++] = edge_value; + } + else + { + mEdge[cur_edge++] = -1; + } + + if (gx < grid_size - 1) + { + mEdge[cur_edge++] = edge_value; + } + else + { + mEdge[cur_edge++] = -1; + } + + mEdge[cur_edge++] = edge_value; + + if (gy < grid_size - 1) + { + mEdge[cur_edge++] = edge_value; + } + else + { + mEdge[cur_edge++] = -1; + } + + if (gx > 0) { - *out++ = ((gy*(grid_size+1))+gx+idxs[i]); - } - } - else - { - for(S32 i=0;i<6;i++) + mEdge[cur_edge++] = edge_value; + } + else { - *out++ = ((gy*(grid_size+1))+gx+idxs[i]); + mEdge[cur_edge++] = -1; } + + mEdge[cur_edge++] = edge_value; } } } @@ -6254,8 +5774,8 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build) S32 num_vertices = 0, num_indices = 0; - const std::vector& mesh = volume->getMesh(); - const std::vector& profile = volume->getProfile().mProfile; + const LLAlignedArray& mesh = volume->getMesh(); + const LLAlignedArray& profile = volume->getProfile().mProfile; // All types of caps have the same number of vertices and indices num_vertices = profile.size(); @@ -6264,8 +5784,7 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build) if (!(mTypeMask & HOLLOW_MASK) && !(mTypeMask & OPEN_MASK)) { resizeVertices(num_vertices+1); - allocateBinormals(num_vertices+1); - + if (!partial_build) { resizeIndices(num_indices+3); @@ -6274,8 +5793,6 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build) else { resizeVertices(num_vertices); - allocateBinormals(num_vertices); - if (!partial_build) { resizeIndices(num_indices); @@ -6309,35 +5826,69 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build) LLVector2* tc = (LLVector2*) mTexCoords; LLVector4a* pos = (LLVector4a*) mPositions; LLVector4a* norm = (LLVector4a*) mNormals; - LLVector4a* binorm = (LLVector4a*) mBinormals; - + // Copy the vertices into the array - for (S32 i = 0; i < num_vertices; i++) + + const LLVector4a* src = mesh.mArray+offset; + const LLVector4a* end = src+num_vertices; + + min = *src; + max = min; + + + const LLVector4a* p = profile.mArray; + + if (mTypeMask & TOP_MASK) { - if (mTypeMask & TOP_MASK) + min_uv.set((*p)[0]+0.5f, + (*p)[1]+0.5f); + + max_uv = min_uv; + + while(src < end) { - tc[i].mV[0] = profile[i].mV[0]+0.5f; - tc[i].mV[1] = profile[i].mV[1]+0.5f; + tc->mV[0] = (*p)[0]+0.5f; + tc->mV[1] = (*p)[1]+0.5f; + + llassert(src->isFinite3()); + update_min_max(min,max,*src); + update_min_max(min_uv, max_uv, *tc); + + *pos = *src; + + llassert(pos->isFinite3()); + + ++p; + ++tc; + ++src; + ++pos; + } } else + { + + min_uv.set((*p)[0]+0.5f, + 0.5f - (*p)[1]); + max_uv = min_uv; + + while(src < end) { // Mirror for underside. - tc[i].mV[0] = profile[i].mV[0]+0.5f; - tc[i].mV[1] = 0.5f - profile[i].mV[1]; - } + tc->mV[0] = (*p)[0]+0.5f; + tc->mV[1] = 0.5f - (*p)[1]; + + llassert(src->isFinite3()); + update_min_max(min,max,*src); + update_min_max(min_uv, max_uv, *tc); - pos[i].load3(mesh[i + offset].mPos.mV); + *pos = *src; - if (i == 0) - { - max = pos[i]; - min = max; - min_uv = max_uv = tc[i]; - } - else - { - update_min_max(min,max,pos[i]); - update_min_max(min_uv, max_uv, tc[i]); + llassert(pos->isFinite3()); + + ++p; + ++tc; + ++src; + ++pos; } } @@ -6346,30 +5897,6 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build) cuv = (min_uv + max_uv)*0.5f; - LLVector4a binormal; - calc_binormal_from_triangle(binormal, - *mCenter, cuv, - pos[0], tc[0], - pos[1], tc[1]); - binormal.normalize3fast(); - - LLVector4a normal; - LLVector4a d0, d1; - - - d0.setSub(*mCenter, pos[0]); - d1.setSub(*mCenter, pos[1]); - - if (mTypeMask & TOP_MASK) - { - normal.setCross3(d0, d1); - } - else - { - normal.setCross3(d1, d0); - } - - normal.normalize3fast(); VertexData vd; vd.setPosition(*mCenter); @@ -6377,17 +5904,11 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build) if (!(mTypeMask & HOLLOW_MASK) && !(mTypeMask & OPEN_MASK)) { - pos[num_vertices] = *mCenter; - tc[num_vertices] = cuv; + *pos++ = *mCenter; + *tc++ = cuv; num_vertices++; } - for (S32 i = 0; i < num_vertices; i++) - { - binorm[i].load4a(binormal.getF32ptr()); - norm[i].load4a(normal.getF32ptr()); - } - if (partial_build) { return TRUE; @@ -6406,33 +5927,38 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build) { // Use the profile points instead of the mesh, since you want // the un-transformed profile distances. - LLVector3 p1 = profile[pt1]; - LLVector3 p2 = profile[pt2]; - LLVector3 pa = profile[pt1+1]; - LLVector3 pb = profile[pt2-1]; + const LLVector4a& p1 = profile[pt1]; + const LLVector4a& p2 = profile[pt2]; + const LLVector4a& pa = profile[pt1+1]; + const LLVector4a& pb = profile[pt2-1]; + + const F32* p1V = p1.getF32ptr(); + const F32* p2V = p2.getF32ptr(); + const F32* paV = pa.getF32ptr(); + const F32* pbV = pb.getF32ptr(); - p1.mV[VZ] = 0.f; - p2.mV[VZ] = 0.f; - pa.mV[VZ] = 0.f; - pb.mV[VZ] = 0.f; + //p1.mV[VZ] = 0.f; + //p2.mV[VZ] = 0.f; + //pa.mV[VZ] = 0.f; + //pb.mV[VZ] = 0.f; // Use area of triangle to determine backfacing F32 area_1a2, area_1ba, area_21b, area_2ab; - area_1a2 = (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) + - (pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) + - (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]); + area_1a2 = (p1V[0]*paV[1] - paV[0]*p1V[1]) + + (paV[0]*p2V[1] - p2V[0]*paV[1]) + + (p2V[0]*p1V[1] - p1V[0]*p2V[1]); - area_1ba = (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + - (pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) + - (pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]); + area_1ba = (p1V[0]*pbV[1] - pbV[0]*p1V[1]) + + (pbV[0]*paV[1] - paV[0]*pbV[1]) + + (paV[0]*p1V[1] - p1V[0]*paV[1]); - area_21b = (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) + - (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + - (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); + area_21b = (p2V[0]*p1V[1] - p1V[0]*p2V[1]) + + (p1V[0]*pbV[1] - pbV[0]*p1V[1]) + + (pbV[0]*p2V[1] - p2V[0]*pbV[1]); - area_2ab = (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) + - (pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) + - (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); + area_2ab = (p2V[0]*paV[1] - paV[0]*p2V[1]) + + (paV[0]*pbV[1] - pbV[0]*paV[1]) + + (pbV[0]*p2V[1] - p2V[0]*pbV[1]); BOOL use_tri1a2 = TRUE; BOOL tri_1a2 = TRUE; @@ -6467,10 +5993,13 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build) } else { - LLVector3 d1 = p1 - pa; - LLVector3 d2 = p2 - pb; + LLVector4a d1; + d1.setSub(p1, pa); + + LLVector4a d2; + d2.setSub(p2, pb); - if (d1.magVecSquared() < d2.magVecSquared()) + if (d1.dot3(d1) < d2.dot3(d2)) { use_tri1a2 = TRUE; } @@ -6509,33 +6038,33 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build) { // Use the profile points instead of the mesh, since you want // the un-transformed profile distances. - LLVector3 p1 = profile[pt1]; - LLVector3 p2 = profile[pt2]; - LLVector3 pa = profile[pt1+1]; - LLVector3 pb = profile[pt2-1]; + const LLVector4a& p1 = profile[pt1]; + const LLVector4a& p2 = profile[pt2]; + const LLVector4a& pa = profile[pt1+1]; + const LLVector4a& pb = profile[pt2-1]; - p1.mV[VZ] = 0.f; - p2.mV[VZ] = 0.f; - pa.mV[VZ] = 0.f; - pb.mV[VZ] = 0.f; + const F32* p1V = p1.getF32ptr(); + const F32* p2V = p2.getF32ptr(); + const F32* paV = pa.getF32ptr(); + const F32* pbV = pb.getF32ptr(); // Use area of triangle to determine backfacing F32 area_1a2, area_1ba, area_21b, area_2ab; - area_1a2 = (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) + - (pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) + - (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]); + area_1a2 = (p1V[0]*paV[1] - paV[0]*p1V[1]) + + (paV[0]*p2V[1] - p2V[0]*paV[1]) + + (p2V[0]*p1V[1] - p1V[0]*p2V[1]); - area_1ba = (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + - (pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) + - (pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]); + area_1ba = (p1V[0]*pbV[1] - pbV[0]*p1V[1]) + + (pbV[0]*paV[1] - paV[0]*pbV[1]) + + (paV[0]*p1V[1] - p1V[0]*paV[1]); - area_21b = (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) + - (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) + - (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); + area_21b = (p2V[0]*p1V[1] - p1V[0]*p2V[1]) + + (p1V[0]*pbV[1] - pbV[0]*p1V[1]) + + (pbV[0]*p2V[1] - p2V[0]*pbV[1]); - area_2ab = (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) + - (pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) + - (pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]); + area_2ab = (p2V[0]*paV[1] - paV[0]*p2V[1]) + + (paV[0]*pbV[1] - pbV[0]*paV[1]) + + (pbV[0]*p2V[1] - p2V[0]*pbV[1]); BOOL use_tri1a2 = TRUE; BOOL tri_1a2 = TRUE; @@ -6570,10 +6099,12 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build) } else { - LLVector3 d1 = p1 - pa; - LLVector3 d2 = p2 - pb; + LLVector4a d1; + d1.setSub(p1,pa); + LLVector4a d2; + d2.setSub(p2,pb); - if (d1.magVecSquared() < d2.magVecSquared()) + if (d1.dot3(d1) < d2.dot3(d2)) { use_tri1a2 = TRUE; } @@ -6622,63 +6153,71 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build) } - + + LLVector4a d0,d1; + + d0.setSub(mPositions[mIndices[1]], mPositions[mIndices[0]]); + d1.setSub(mPositions[mIndices[2]], mPositions[mIndices[0]]); + + LLVector4a normal; + normal.setCross3(d0,d1); + + if (normal.dot3(normal).getF32() > F_APPROXIMATELY_ZERO) + { + normal.normalize3fast(); + } + else + { //degenerate, make up a value + if(normal.getF32ptr()[2] >= 0) + normal.set(0.f,0.f,1.f); + else + normal.set(0.f,0.f,-1.f); + } + + llassert(std::isfinite(normal.getF32ptr()[0])); + llassert(std::isfinite(normal.getF32ptr()[1])); + llassert(std::isfinite(normal.getF32ptr()[2])); + + llassert(!std::isnan(normal.getF32ptr()[0])); + llassert(!std::isnan(normal.getF32ptr()[1])); + llassert(!std::isnan(normal.getF32ptr()[2])); + + for (S32 i = 0; i < num_vertices; i++) + { + norm[i].load4a(normal.getF32ptr()); + } + return TRUE; } -void LLVolumeFace::createBinormals() +void CalculateTangentArray(U32 vertexCount, const LLVector4a *vertex, const LLVector4a *normal, + const LLVector2 *texcoord, U32 triangleCount, const U16* index_array, LLVector4a *tangent); + +void LLVolumeFace::createTangents() { - if (!mBinormals) + if (!mTangents) { - allocateBinormals(mNumVertices); + allocateTangents(mNumVertices); - //generate binormals - LLVector4a* pos = mPositions; - LLVector2* tc = (LLVector2*) mTexCoords; - LLVector4a* binorm = (LLVector4a*) mBinormals; + //generate tangents + //LLVector4a* pos = mPositions; + //LLVector2* tc = (LLVector2*) mTexCoords; + LLVector4a* binorm = (LLVector4a*) mTangents; - LLVector4a* end = mBinormals+mNumVertices; + LLVector4a* end = mTangents+mNumVertices; while (binorm < end) { (*binorm++).clear(); } - binorm = mBinormals; + binorm = mTangents; - for (U32 i = 0; i < (U32)mNumIndices/3; i++) - { //for each triangle - const U16& i0 = mIndices[i*3+0]; - const U16& i1 = mIndices[i*3+1]; - const U16& i2 = mIndices[i*3+2]; - - //calculate binormal - LLVector4a binormal; - calc_binormal_from_triangle(binormal, - pos[i0], tc[i0], - pos[i1], tc[i1], - pos[i2], tc[i2]); - - - //add triangle normal to vertices - binorm[i0].add(binormal); - binorm[i1].add(binormal); - binorm[i2].add(binormal); - - //even out quad contributions - if (i % 2 == 0) - { - binorm[i2].add(binormal); - } - else - { - binorm[i1].add(binormal); - } - } + CalculateTangentArray(mNumVertices, mPositions, mNormals, mTexCoords, mNumIndices/3, mIndices, mTangents); - //normalize binormals - for (U32 i = 0; i < (U32)mNumVertices; i++) + //normalize tangents + for (S32 i = 0; i < mNumVertices; i++) { - binorm[i].normalize3fast(); + //binorm[i].normalize3fast(); //bump map/planar projection code requires normals to be normalized mNormals[i].normalize3fast(); } @@ -6687,33 +6226,12 @@ void LLVolumeFace::createBinormals() void LLVolumeFace::resizeVertices(S32 num_verts) { - ll_aligned_free_16(mPositions); - ll_aligned_free_16(mNormals); - ll_aligned_free_16(mBinormals); - ll_aligned_free_16(mTexCoords); - - mBinormals = NULL; - - if (num_verts) - { - mPositions = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts); - ll_assert_aligned(mPositions, 16); - mNormals = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts); - ll_assert_aligned(mNormals, 16); - - //pad texture coordinate block end to allow for QWORD reads - S32 size = ((num_verts*sizeof(LLVector2)) + 0xF) & ~0xF; - mTexCoords = (LLVector2*) ll_aligned_malloc_16(size); - ll_assert_aligned(mTexCoords, 16); - } - else - { - mPositions = NULL; - mNormals = NULL; - mTexCoords = NULL; - } - + allocateTangents(0); + allocateVertices(num_verts); mNumVertices = num_verts; + + // Force update + mJointRiggingInfoTab.clear(); } void LLVolumeFace::pushVertex(const LLVolumeFace::VertexData& cv) @@ -6724,27 +6242,15 @@ void LLVolumeFace::pushVertex(const LLVolumeFace::VertexData& cv) void LLVolumeFace::pushVertex(const LLVector4a& pos, const LLVector4a& norm, const LLVector2& tc) { S32 new_verts = mNumVertices+1; - S32 new_size = new_verts*16; - S32 old_size = mNumVertices*16; - //positions - mPositions = (LLVector4a*) ll_aligned_realloc_16(mPositions, new_size, old_size); - ll_assert_aligned(mPositions,16); - - //normals - mNormals = (LLVector4a*) ll_aligned_realloc_16(mNormals, new_size, old_size); - ll_assert_aligned(mNormals,16); - - //tex coords - new_size = ((new_verts*8)+0xF) & ~0xF; - old_size = ((mNumVertices*8)+0xF) & ~0xF; - mTexCoords = (LLVector2*) ll_aligned_realloc_16(mTexCoords, new_size, old_size); - ll_assert_aligned(mTexCoords,16); - + if (new_verts > mNumAllocatedVertices) + { + //double buffer size on expansion + allocateVertices(new_verts * 2, true); - //just clear binormals - ll_aligned_free_16(mBinormals); - mBinormals = NULL; + //just clear tangents + allocateTangents(0); + } mPositions[mNumVertices] = pos; mNormals[mNumVertices] = norm; @@ -6753,50 +6259,106 @@ void LLVolumeFace::pushVertex(const LLVector4a& pos, const LLVector4a& norm, con mNumVertices++; } -void LLVolumeFace::allocateBinormals(S32 num_verts) +void LLVolumeFace::allocateTangents(S32 num_verts) { - ll_aligned_free_16(mBinormals); - mBinormals = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts); + ll_aligned_free_16(mTangents); + mTangents = NULL; + if (num_verts) + { + mTangents = (LLVector4a*)ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts); + } } void LLVolumeFace::allocateWeights(S32 num_verts) { ll_aligned_free_16(mWeights); - mWeights = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts); + mWeights = NULL; + if (num_verts) + { + mWeights = (LLVector4a*)ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts); + } } -void LLVolumeFace::resizeIndices(S32 num_indices) +void LLVolumeFace::allocateVertices(S32 num_verts, bool copy) { - ll_aligned_free_16(mIndices); - - if (num_indices) + if (!copy || !num_verts) { - //pad index block end to allow for QWORD reads - S32 size = ((num_indices*sizeof(U16)) + 0xF) & ~0xF; - - mIndices = (U16*) ll_aligned_malloc_16(size); + ll_aligned_free<64>(mPositions); + mPositions = NULL; + mNormals = NULL; + mTexCoords = NULL; } - else + + if (num_verts) + { + const U32 new_vsize = num_verts * sizeof(LLVector4a); + const U32 new_nsize = new_vsize; + const U32 new_tcsize = (num_verts * sizeof(LLVector2) + 0xF) & ~0xF; + const U32 new_size = new_vsize + new_nsize + new_tcsize; + + //allocate new buffer space + LLVector4a* old_buf = mPositions; + mPositions = (LLVector4a*)ll_aligned_malloc<64>(new_size); + mNormals = mPositions + num_verts; + mTexCoords = (LLVector2*)(mNormals + num_verts); + + if (copy && old_buf) + { + U32 verts_to_copy = std::min(mNumVertices, num_verts); + if (verts_to_copy) + { + const U32 old_vsize = verts_to_copy * sizeof(LLVector4a); + const U32 old_nsize = old_vsize; + const U32 old_tcsize = (verts_to_copy * sizeof(LLVector2) + 0xF) & ~0xF; + + LLVector4a::memcpyNonAliased16((F32*)mPositions, (F32*)old_buf, old_vsize); + LLVector4a::memcpyNonAliased16((F32*)mNormals, (F32*)(old_buf + mNumVertices), old_nsize); + LLVector4a::memcpyNonAliased16((F32*)mTexCoords, (F32*)(old_buf + mNumVertices * 2), old_tcsize); + } + ll_aligned_free<64>(old_buf); + } + } + mNumAllocatedVertices = num_verts; +} + +void LLVolumeFace::allocateIndices(S32 num_indices, bool copy) +{ + if (num_indices == mNumIndices) { - mIndices = NULL; + return; + } + + S32 new_size = ((num_indices * sizeof(U16)) + 0xF) & ~0xF; + if (copy && num_indices && mIndices && mNumIndices) + { +#if !LL_USE_TCMALLOC + S32 old_size = ((mNumIndices * sizeof(U16)) + 0xF) & ~0xF; +#endif + + mIndices = (U16*)ll_aligned_realloc_16(mIndices, new_size, old_size); + + mNumIndices = num_indices; + return; + } + ll_aligned_free_16(mIndices); + mIndices = NULL; + if (num_indices) + { + mIndices = (U16*)ll_aligned_malloc_16(new_size); } mNumIndices = num_indices; } +void LLVolumeFace::resizeIndices(S32 num_indices) +{ + allocateIndices(num_indices); +} void LLVolumeFace::pushIndex(const U16& idx) { - S32 new_count = mNumIndices + 1; - S32 new_size = ((new_count*2)+0xF) & ~0xF; + allocateIndices(mNumIndices + 1, true); - S32 old_size = ((mNumIndices*2)+0xF) & ~0xF; - if (new_size != old_size) - { - mIndices = (U16*) ll_aligned_realloc_16(mIndices, new_size, old_size); - ll_assert_aligned(mIndices,16); - } - - mIndices[mNumIndices++] = idx; + mIndices[mNumIndices-1] = idx; } void LLVolumeFace::fillFromLegacyData(std::vector& v, std::vector& idx) @@ -6817,86 +6379,6 @@ void LLVolumeFace::fillFromLegacyData(std::vector& v, } } -void LLVolumeFace::appendFace(const LLVolumeFace& face, LLMatrix4& mat_in, LLMatrix4& norm_mat_in) -{ - U16 offset = mNumVertices; - - S32 new_count = face.mNumVertices + mNumVertices; - - if (new_count > 65536) - { - llerrs << "Cannot append face -- 16-bit overflow will occur." << llendl; - } - - if (face.mNumVertices == 0) - { - llerrs << "Cannot append empty face." << llendl; - } - - //allocate new buffer space - mPositions = (LLVector4a*) ll_aligned_realloc_16(mPositions, new_count*sizeof(LLVector4a), mNumVertices*sizeof(LLVector4a)); - ll_assert_aligned(mPositions, 16); - mNormals = (LLVector4a*) ll_aligned_realloc_16(mNormals, new_count*sizeof(LLVector4a), mNumVertices*sizeof(LLVector4a)); - ll_assert_aligned(mNormals, 16); - mTexCoords = (LLVector2*) ll_aligned_realloc_16(mTexCoords, (new_count*sizeof(LLVector2)+0xF) & ~0xF, (mNumVertices*sizeof(LLVector2)+0xF) & ~0xF); - ll_assert_aligned(mTexCoords, 16); - - mNumVertices = new_count; - - //get destination address of appended face - LLVector4a* dst_pos = mPositions+offset; - LLVector2* dst_tc = mTexCoords+offset; - LLVector4a* dst_norm = mNormals+offset; - - //get source addresses of appended face - const LLVector4a* src_pos = face.mPositions; - const LLVector2* src_tc = face.mTexCoords; - const LLVector4a* src_norm = face.mNormals; - - //load aligned matrices - LLMatrix4a mat, norm_mat; - mat.loadu(mat_in); - norm_mat.loadu(norm_mat_in); - - for (U32 i = 0; i < (U32)face.mNumVertices; ++i) - { - //transform appended face position and store - mat.affineTransform(src_pos[i], dst_pos[i]); - - //transform appended face normal and store - norm_mat.rotate(src_norm[i], dst_norm[i]); - dst_norm[i].normalize3fast(); - - //copy appended face texture coordinate - dst_tc[i] = src_tc[i]; - - if (offset == 0 && i == 0) - { //initialize bounding box - mExtents[0] = mExtents[1] = dst_pos[i]; - } - else - { - //stretch bounding box - update_min_max(mExtents[0], mExtents[1], dst_pos[i]); - } - } - - - new_count = mNumIndices + face.mNumIndices; - - //allocate new index buffer - mIndices = (U16*) ll_aligned_realloc_16(mIndices, (new_count*sizeof(U16)+0xF) & ~0xF, (mNumIndices*sizeof(U16)+0xF) & ~0xF); - - //get destination address into new index buffer - U16* dst_idx = mIndices+mNumIndices; - mNumIndices = new_count; - - for (U32 i = 0; i < (U32)face.mNumIndices; ++i) - { //copy indices, offsetting by old vertex count - dst_idx[i] = face.mIndices[i]+offset; - } -} - BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) { BOOL flat = mTypeMask & FLAT_MASK; @@ -6909,9 +6391,9 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) S32 num_vertices, num_indices; - const std::vector& mesh = volume->getMesh(); - const std::vector& profile = volume->getProfile().mProfile; - const std::vector& path_data = volume->getPath().mPath; + const LLAlignedArray& mesh = volume->getMesh(); + const LLAlignedArray& profile = volume->getProfile().mProfile; + const LLAlignedArray& path_data = volume->getPath().mPath; S32 max_s = volume->getProfile().getTotal(); @@ -6921,6 +6403,8 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) num_vertices = mNumS*mNumT; num_indices = (mNumS-1)*(mNumT-1)*6; + partial_build = (num_vertices > mNumVertices || num_indices > mNumIndices) ? FALSE : partial_build; + if (!partial_build) { resizeVertices(num_vertices); @@ -6932,15 +6416,18 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) } } + LLVector4a* pos = (LLVector4a*) mPositions; - LLVector4a* norm = (LLVector4a*) mNormals; LLVector2* tc = (LLVector2*) mTexCoords; - S32 begin_stex = llfloor( profile[mBeginS].mV[2] ); + F32 begin_stex = floorf(profile[mBeginS][2]); S32 num_s = ((mTypeMask & INNER_MASK) && (mTypeMask & FLAT_MASK) && mNumS > 2) ? mNumS/2 : mNumS; S32 cur_vertex = 0; + S32 end_t = mBeginT+mNumT; + bool test = (mTypeMask & INNER_MASK) && (mTypeMask & FLAT_MASK) && mNumS > 2; + // Copy the vertices into the array - for (t = mBeginT; t < mBeginT + mNumT; t++) + for (t = mBeginT; t < end_t; t++) { tt = path_data[t].mTexT; for (s = 0; s < num_s; s++) @@ -6961,11 +6448,11 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) // Get s value for tex-coord. if (!flat) { - ss = profile[mBeginS + s].mV[2]; + ss = profile[mBeginS + s][2]; } else { - ss = profile[mBeginS + s].mV[2] - begin_stex; + ss = profile[mBeginS + s][2] - begin_stex; } } @@ -6985,20 +6472,15 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) i = mBeginS + s + max_s*t; } - pos[cur_vertex].load3(mesh[i].mPos.mV); - tc[cur_vertex] = LLVector2(ss,tt); + mesh[i].store4a((F32*)(pos+cur_vertex)); + tc[cur_vertex].set(ss,tt); - norm[cur_vertex].clear(); cur_vertex++; - if ((mTypeMask & INNER_MASK) && (mTypeMask & FLAT_MASK) && mNumS > 2 && s > 0) + if (test && s > 0) { - - pos[cur_vertex].load3(mesh[i].mPos.mV); - tc[cur_vertex] = LLVector2(ss,tt); - - norm[cur_vertex].clear(); - + mesh[i].store4a((F32*)(pos+cur_vertex)); + tc[cur_vertex].set(ss,tt); cur_vertex++; } } @@ -7015,28 +6497,62 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) } i = mBeginS + s + max_s*t; - ss = profile[mBeginS + s].mV[2] - begin_stex; - pos[cur_vertex].load3(mesh[i].mPos.mV); - tc[cur_vertex] = LLVector2(ss,tt); - norm[cur_vertex].clear(); + ss = profile[mBeginS + s][2] - begin_stex; + + mesh[i].store4a((F32*)(pos+cur_vertex)); + tc[cur_vertex].set(ss,tt); cur_vertex++; } } + mCenter->clear(); + + LLVector4a* cur_pos = pos; + LLVector4a* end_pos = pos + mNumVertices; //get bounding box for this side - LLVector4a& face_min = mExtents[0]; - LLVector4a& face_max = mExtents[1]; - mCenter->clear(); + LLVector4a face_min; + LLVector4a face_max; + + face_min = face_max = *cur_pos++; + + while (cur_pos < end_pos) + { + update_min_max(face_min, face_max, *cur_pos++); + } + + mExtents[0] = face_min; + mExtents[1] = face_max; + + U32 tc_count = mNumVertices; + if (tc_count%2 == 1) + { //odd number of texture coordinates, duplicate last entry to padded end of array + tc_count++; + mTexCoords[mNumVertices] = mTexCoords[mNumVertices-1]; + } - face_min = face_max = pos[0]; + LLVector4a* cur_tc = (LLVector4a*) mTexCoords; + LLVector4a* end_tc = (LLVector4a*) (mTexCoords+tc_count); - for (U32 i = 1; i < (U32)mNumVertices; ++i) + LLVector4a tc_min; + LLVector4a tc_max; + + tc_min = tc_max = *cur_tc++; + + while (cur_tc < end_tc) { - update_min_max(face_min, face_max, pos[i]); + update_min_max(tc_min, tc_max, *cur_tc++); } + F32* minp = tc_min.getF32ptr(); + F32* maxp = tc_max.getF32ptr(); + + mTexCoordExtents[0].mV[0] = llmin(minp[0], minp[2]); + mTexCoordExtents[0].mV[1] = llmin(minp[1], minp[3]); + mTexCoordExtents[1].mV[0] = llmax(maxp[0], maxp[2]); + mTexCoordExtents[1].mV[1] = llmax(maxp[1], maxp[3]); + mCenter->setAdd(face_min, face_max); mCenter->mul(0.5f); @@ -7101,37 +6617,112 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) } } + //clear normals - for (U32 i = 0; i < (U32)mNumVertices; i++) + F32* dst = (F32*) mNormals; + F32* end = (F32*) (mNormals+mNumVertices); + LLVector4a zero = LLVector4a::getZero(); + + while (dst < end) { - mNormals[i].clear(); + zero.store4a(dst); + dst += 4; } //generate normals - for (U32 i = 0; i < (U32)mNumIndices/3; i++) //for each triangle + U32 count = mNumIndices/3; + + LLVector4a* norm = mNormals; + + static LLAlignedArray triangle_normals; + triangle_normals.resize(count); + LLVector4a* output = triangle_normals.mArray; + LLVector4a* end_output = output+count; + + U16* idx = mIndices; + + while (output < end_output) { - const U16* idx = &(mIndices[i*3]); + LLVector4a b,v1,v2; + b.load4a((F32*) (pos+idx[0])); + v1.load4a((F32*) (pos+idx[1])); + v2.load4a((F32*) (pos+idx[2])); + + //calculate triangle normal + LLVector4a a; + a.setSub(b, v1); + b.sub(v2); + - LLVector4a* v[] = - { pos+idx[0], pos+idx[1], pos+idx[2] }; + LLQuad& vector1 = *((LLQuad*) &v1); + LLQuad& vector2 = *((LLQuad*) &v2); - LLVector4a* n[] = - { norm+idx[0], norm+idx[1], norm+idx[2] }; + LLQuad& amQ = *((LLQuad*) &a); + LLQuad& bmQ = *((LLQuad*) &b); + + //v1.setCross3(t,v0); + //setCross3(const LLVector4a& a, const LLVector4a& b) + // Vectors are stored in memory in w, z, y, x order from high to low + // Set vector1 = { a[W], a[X], a[Z], a[Y] } + vector1 = _mm_shuffle_ps( amQ, amQ, _MM_SHUFFLE( 3, 0, 2, 1 )); + // Set vector2 = { b[W], b[Y], b[X], b[Z] } + vector2 = _mm_shuffle_ps( bmQ, bmQ, _MM_SHUFFLE( 3, 1, 0, 2 )); + // mQ = { a[W]*b[W], a[X]*b[Y], a[Z]*b[X], a[Y]*b[Z] } + vector2 = _mm_mul_ps( vector1, vector2 ); + // vector3 = { a[W], a[Y], a[X], a[Z] } + amQ = _mm_shuffle_ps( amQ, amQ, _MM_SHUFFLE( 3, 1, 0, 2 )); + // vector4 = { b[W], b[X], b[Z], b[Y] } + bmQ = _mm_shuffle_ps( bmQ, bmQ, _MM_SHUFFLE( 3, 0, 2, 1 )); + // mQ = { 0, a[X]*b[Y] - a[Y]*b[X], a[Z]*b[X] - a[X]*b[Z], a[Y]*b[Z] - a[Z]*b[Y] } + vector1 = _mm_sub_ps( vector2, _mm_mul_ps( amQ, bmQ )); + + llassert(v1.isFinite3()); + + v1.store4a((F32*) output); - //calculate triangle normal - LLVector4a a, b, c; - a.setSub(*v[0], *v[1]); - b.setSub(*v[0], *v[2]); - c.setCross3(a,b); + output++; + idx += 3; + } + + idx = mIndices; + + LLVector4a* src = triangle_normals.mArray; + + for (U32 i = 0; i < count; i++) //for each triangle + { + LLVector4a c; + c.load4a((F32*) (src++)); + + LLVector4a* n0p = norm+idx[0]; + LLVector4a* n1p = norm+idx[1]; + LLVector4a* n2p = norm+idx[2]; + + idx += 3; - n[0]->add(c); - n[1]->add(c); - n[2]->add(c); + LLVector4a n0,n1,n2; + n0.load4a((F32*) n0p); + n1.load4a((F32*) n1p); + n2.load4a((F32*) n2p); + n0.add(c); + n1.add(c); + n2.add(c); + + llassert(c.isFinite3()); + //even out quad contributions - n[i%2+1]->add(c); + switch (i%2+1) + { + case 0: n0.add(c); break; + case 1: n1.add(c); break; + case 2: n2.add(c); break; + }; + + n0.store4a((F32*) n0p); + n1.store4a((F32*) n1p); + n2.store4a((F32*) n2p); } // adjust normals based on wrapping and stitching @@ -7268,53 +6859,102 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) return TRUE; } -// Finds binormal based on three vertices with texture coordinates. -// Fills in dummy values if the triangle has degenerate texture coordinates. -void calc_binormal_from_triangle(LLVector4a& binormal, - - const LLVector4a& pos0, - const LLVector2& tex0, - const LLVector4a& pos1, - const LLVector2& tex1, - const LLVector4a& pos2, - const LLVector2& tex2) -{ - LLVector4a rx0( pos0[VX], tex0.mV[VX], tex0.mV[VY] ); - LLVector4a rx1( pos1[VX], tex1.mV[VX], tex1.mV[VY] ); - LLVector4a rx2( pos2[VX], tex2.mV[VX], tex2.mV[VY] ); - - LLVector4a ry0( pos0[VY], tex0.mV[VX], tex0.mV[VY] ); - LLVector4a ry1( pos1[VY], tex1.mV[VX], tex1.mV[VY] ); - LLVector4a ry2( pos2[VY], tex2.mV[VX], tex2.mV[VY] ); - - LLVector4a rz0( pos0[VZ], tex0.mV[VX], tex0.mV[VY] ); - LLVector4a rz1( pos1[VZ], tex1.mV[VX], tex1.mV[VY] ); - LLVector4a rz2( pos2[VZ], tex2.mV[VX], tex2.mV[VY] ); - - LLVector4a lhs, rhs; - - LLVector4a r0; - lhs.setSub(rx0, rx1); rhs.setSub(rx0, rx2); - r0.setCross3(lhs, rhs); +//adapted from Lengyel, Eric. "Computing Tangent Space Basis Vectors for an Arbitrary Mesh". Terathon Software 3D Graphics Library, 2001. http://www.terathon.com/code/tangent.html +void CalculateTangentArray(U32 vertexCount, const LLVector4a *vertex, const LLVector4a *normal, + const LLVector2 *texcoord, U32 triangleCount, const U16* index_array, LLVector4a *tangent) +{ + //LLVector4a *tan1 = new LLVector4a[vertexCount * 2]; + LLVector4a* tan1 = (LLVector4a*) ll_aligned_malloc_16(vertexCount*2*sizeof(LLVector4a)); + + LLVector4a* tan2 = tan1 + vertexCount; + + memset(tan1, 0, vertexCount*2*sizeof(LLVector4a)); + + for (U32 a = 0; a < triangleCount; a++) + { + U32 i1 = *index_array++; + U32 i2 = *index_array++; + U32 i3 = *index_array++; + + const LLVector4a& v1 = vertex[i1]; + const LLVector4a& v2 = vertex[i2]; + const LLVector4a& v3 = vertex[i3]; + + const LLVector2& w1 = texcoord[i1]; + const LLVector2& w2 = texcoord[i2]; + const LLVector2& w3 = texcoord[i3]; + + const F32* v1ptr = v1.getF32ptr(); + const F32* v2ptr = v2.getF32ptr(); + const F32* v3ptr = v3.getF32ptr(); - LLVector4a r1; - lhs.setSub(ry0, ry1); rhs.setSub(ry0, ry2); - r1.setCross3(lhs, rhs); - - LLVector4a r2; - lhs.setSub(rz0, rz1); rhs.setSub(rz0, rz2); - r2.setCross3(lhs, rhs); + float x1 = v2ptr[0] - v1ptr[0]; + float x2 = v3ptr[0] - v1ptr[0]; + float y1 = v2ptr[1] - v1ptr[1]; + float y2 = v3ptr[1] - v1ptr[1]; + float z1 = v2ptr[2] - v1ptr[2]; + float z2 = v3ptr[2] - v1ptr[2]; + + float s1 = w2.mV[0] - w1.mV[0]; + float s2 = w3.mV[0] - w1.mV[0]; + float t1 = w2.mV[1] - w1.mV[1]; + float t2 = w3.mV[1] - w1.mV[1]; + + F32 rd = s1*t2-s2*t1; + + float r = ((rd*rd) > FLT_EPSILON) ? (1.0f / rd) + : ((rd > 0.0f) ? 1024.f : -1024.f); //some made up large ratio for division by zero + + llassert(std::isfinite(r)); + llassert(!std::isnan(r)); + + LLVector4a sdir((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, + (t2 * z1 - t1 * z2) * r); + LLVector4a tdir((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, + (s1 * z2 - s2 * z1) * r); + + tan1[i1].add(sdir); + tan1[i2].add(sdir); + tan1[i3].add(sdir); + + tan2[i1].add(tdir); + tan2[i2].add(tdir); + tan2[i3].add(tdir); + } + + for (U32 a = 0; a < vertexCount; a++) + { + LLVector4a n = normal[a]; + + const LLVector4a& t = tan1[a]; + + LLVector4a ncrosst; + ncrosst.setCross3(n,t); + + // Gram-Schmidt orthogonalize + n.mul(n.dot3(t).getF32()); + + LLVector4a tsubn; + tsubn.setSub(t,n); + + if (tsubn.dot3(tsubn).getF32() > F_APPROXIMATELY_ZERO) + { + tsubn.normalize3fast(); + + // Calculate handedness + F32 handedness = ncrosst.dot3(tan2[a]).getF32() < 0.f ? -1.f : 1.f; + + tsubn.getF32ptr()[3] = handedness; - if( r0[VX] && r1[VX] && r2[VX] ) - { - binormal.set( - -r0[VZ] / r0[VX], - -r1[VZ] / r1[VX], - -r2[VZ] / r2[VX]); - // binormal.normVec(); - } - else - { - binormal.set( 0, 1 , 0 ); - } + tangent[a] = tsubn; + } + else + { //degenerate, make up a value + tangent[a].set(0,0,1,1); + } + } + + ll_aligned_free_16(tan1); } + + diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h index f6e9747743..80a5698ef1 100644 --- a/indra/llmath/llvolume.h +++ b/indra/llmath/llvolume.h @@ -27,6 +27,9 @@ #ifndef LL_LLVOLUME_H #define LL_LLVOLUME_H +#ifdef IN_PCH +#error "llvolume.h should not be in pch include chain." +#endif #include class LLProfileParams; @@ -35,14 +38,12 @@ class LLVolumeParams; class LLProfile; class LLPath; -template class LLOctreeNode; +template class LLOctreeRoot; -class LLVector4a; class LLVolumeFace; class LLVolume; class LLVolumeTriangle; -#include "lldarray.h" #include "lluuid.h" #include "v4color.h" //#include "vmath.h" @@ -50,12 +51,16 @@ class LLVolumeTriangle; #include "v3math.h" #include "v3dmath.h" #include "v4math.h" +#include "llvector4a.h" +#include "llmatrix4a.h" #include "llquaternion.h" #include "llstrider.h" #include "v4coloru.h" #include "llrefcount.h" #include "llpointer.h" #include "llfile.h" +#include "llalignedarray.h" +#include "llrigginginfo.h" //============================================================================ @@ -190,8 +195,12 @@ const U8 LL_SCULPT_TYPE_MESH = 5; const U8 LL_SCULPT_TYPE_MASK = LL_SCULPT_TYPE_SPHERE | LL_SCULPT_TYPE_TORUS | LL_SCULPT_TYPE_PLANE | LL_SCULPT_TYPE_CYLINDER | LL_SCULPT_TYPE_MESH; +// for value checks, assign new value after adding new types +const U8 LL_SCULPT_TYPE_MAX = LL_SCULPT_TYPE_MESH; + const U8 LL_SCULPT_FLAG_INVERT = 64; const U8 LL_SCULPT_FLAG_MIRROR = 128; +const U8 LL_SCULPT_FLAG_MASK = LL_SCULPT_FLAG_INVERT | LL_SCULPT_FLAG_MIRROR; const S32 LL_SCULPT_MESH_MAX_FACES = 8; @@ -709,16 +718,16 @@ class LLProfile LLFaceID mFaceID; }; - std::vector mProfile; - std::vector mNormals; + LLAlignedArray mProfile; + //LLAlignedArray mNormals; std::vector mFaces; - std::vector mEdgeNormals; - std::vector mEdgeCenters; + + //LLAlignedArray mEdgeNormals; + //LLAlignedArray mEdgeCenters; friend std::ostream& operator<<(std::ostream &s, const LLProfile &profile); protected: - void genNormals(const LLProfileParams& params); static S32 getNumNGonPoints(const LLProfileParams& params, S32 sides, F32 offset=0.0f, F32 bevel = 0.0f, F32 ang_scale = 1.f, S32 split = 0); void genNGon(const LLProfileParams& params, S32 sides, F32 offset=0.0f, F32 bevel = 0.0f, F32 ang_scale = 1.f, S32 split = 0); @@ -742,13 +751,29 @@ class LLProfile class LLPath { public: - struct PathPt + class PathPt { - LLVector3 mPos; - LLVector2 mScale; - LLQuaternion mRot; + public: + LL_ALIGN_16(LLMatrix4a mRot); + LL_ALIGN_16(LLVector4a mPos); + + LL_ALIGN_16(LLVector4a mScale); F32 mTexT; - PathPt() { mPos.setVec(0,0,0); mTexT = 0; mScale.setVec(0,0); mRot.loadIdentity(); } + F32 pad[3]; //for alignment + PathPt() + { + mPos.clear(); + mTexT = 0; + mScale.clear(); + mRot.setRows(LLVector4a(1,0,0,0), + LLVector4a(0,1,0,0), + LLVector4a(0,0,1,0)); + + //distinguished data in the pad for debugging + pad[0] = 3.14159f; + pad[1] = -3.14159f; + pad[2] = 0.585f; + } }; public: @@ -780,7 +805,7 @@ class LLPath friend std::ostream& operator<<(std::ostream &s, const LLPath &path); public: - std::vector mPath; + LLAlignedArray mPath; protected: BOOL mOpen; @@ -845,13 +870,13 @@ class LLVolumeFace public: BOOL create(LLVolume* volume, BOOL partial_build = FALSE); - void createBinormals(); - - void appendFace(const LLVolumeFace& face, LLMatrix4& transform, LLMatrix4& normal_tranform); + void createTangents(); void resizeVertices(S32 num_verts); - void allocateBinormals(S32 num_verts); + void allocateTangents(S32 num_verts); void allocateWeights(S32 num_verts); + void allocateVertices(S32 num_verts, bool copy = false); + void allocateIndices(S32 num_indices, bool copy = false); void resizeIndices(S32 num_indices); void fillFromLegacyData(std::vector& v, std::vector& idx); @@ -913,11 +938,12 @@ class LLVolumeFace LLVector2 mTexCoordExtents[2]; //minimum and maximum of texture coordinates of the face. S32 mNumVertices; + S32 mNumAllocatedVertices; S32 mNumIndices; LLVector4a* mPositions; LLVector4a* mNormals; - LLVector4a* mBinormals; + LLVector4a* mTangents; LLVector2* mTexCoords; U16* mIndices; @@ -931,8 +957,17 @@ class LLVolumeFace // format is mWeights[vertex_index].mV[influence] = . // mWeights.size() should be empty or match mVertices.size() LLVector4a* mWeights; - - LLOctreeNode* mOctree; + + mutable BOOL mWeightsScrubbed; + + // Which joints are rigged to, and the bounding box of any rigged + // vertices per joint. + LLJointRiggingInfoTab mJointRiggingInfoTab; + + LLOctreeRoot* mOctree; + + //whether or not face has been cache optimized + BOOL mOptimized; private: BOOL createUnCutCubeCap(LLVolume* volume, BOOL partial_build = FALSE); @@ -945,15 +980,11 @@ class LLVolume : public LLRefCount friend class LLVolumeLODGroup; protected: - LLVolume(const LLVolume&); // Don't implement ~LLVolume(); // use unref public: - struct Point - { - LLVector3 mPos; - }; - + typedef std::vector face_list_t; + struct FaceParams { LLFaceID mFaceID; @@ -976,13 +1007,13 @@ class LLVolume : public LLRefCount const LLProfile& getProfile() const { return *mProfilep; } LLPath& getPath() const { return *mPathp; } void resizePath(S32 length); - const std::vector& getMesh() const { return mMesh; } - const LLVector3& getMeshPt(const U32 i) const { return mMesh[i].mPos; } + const LLAlignedArray& getMesh() const { return mMesh; } + const LLVector4a& getMeshPt(const U32 i) const { return mMesh[i]; } void setDirty() { mPathp->setDirty(); mProfilep->setDirty(); } void regen(); - void genBinormals(S32 face); + void genTangents(S32 face); BOOL isConvex() const; BOOL isCap(S32 face); @@ -992,10 +1023,7 @@ class LLVolume : public LLRefCount S32 getSculptLevel() const { return mSculptLevel; } void setSculptLevel(S32 level) { mSculptLevel = level; } - S32 *getTriangleIndices(U32 &num_indices) const; - - // returns number of triangle indeces required for path/profile mesh - S32 getNumTriangleIndices() const; + static void getLoDTriangleCounts(const LLVolumeParams& params, S32* counts); S32 getNumTriangles(S32* vcount = NULL) const; @@ -1003,28 +1031,21 @@ class LLVolume : public LLRefCount void generateSilhouetteVertices(std::vector &vertices, std::vector &normals, const LLVector3& view_vec, - const LLMatrix4& mat, - const LLMatrix3& norm_mat, + const LLMatrix4a& mat, + const LLMatrix4a& norm_mat, S32 face_index); //get the face index of the face that intersects with the given line segment at the point //closest to start. Moves end to the point of intersection. Returns -1 if no intersection. //Line segment must be in volume space. - S32 lineSegmentIntersect(const LLVector3& start, const LLVector3& end, + S32 lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, S32 face = -1, // which face to check, -1 = ALL_SIDES - LLVector3* intersection = NULL, // return the intersection point + LLVector4a* intersection = NULL, // return the intersection point LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point - LLVector3* normal = NULL, // return the surface normal at the intersection point - LLVector3* bi_normal = NULL // return the surface bi-normal at the intersection point + LLVector4a* normal = NULL, // return the surface normal at the intersection point + LLVector4a* tangent = NULL // return the surface tangent at the intersection point ); - S32 lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, - S32 face = 1, - LLVector3* intersection = NULL, - LLVector2* tex_coord = NULL, - LLVector3* normal = NULL, - LLVector3* bi_normal = NULL); - LLFaceID generateFaceMask(); BOOL isFaceMaskValid(LLFaceID face_mask); @@ -1035,17 +1056,23 @@ class LLVolume : public LLRefCount // conversion if *(LLVolume*) to LLVolume& const LLVolumeFace &getVolumeFace(const S32 f) const {return mVolumeFaces[f];} // DO NOT DELETE VOLUME WHILE USING THIS REFERENCE, OR HOLD A POINTER TO THIS VOLUMEFACE + LLVolumeFace &getVolumeFace(const S32 f) {return mVolumeFaces[f];} // DO NOT DELETE VOLUME WHILE USING THIS REFERENCE, OR HOLD A POINTER TO THIS VOLUMEFACE + + face_list_t& getVolumeFaces() { return mVolumeFaces; } U32 mFaceMask; // bit array of which faces exist in this volume LLVector3 mLODScaleBias; // vector for biasing LOD based on scale - void sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, S32 sculpt_level); + void sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, S32 sculpt_level, bool visible_placeholder); void copyVolumeFaces(const LLVolume* volume); + void copyFacesTo(std::vector &faces) const; + void copyFacesFrom(const std::vector &faces); void cacheOptimize(); private: void sculptGenerateMapVertices(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, U8 sculpt_type); F32 sculptGetSurfaceArea(); - void sculptGeneratePlaceholder(); + void sculptGenerateEmptyPlaceholder(); + void sculptGenerateSpherePlaceholder(); void sculptCalcMeshResolution(U16 width, U16 height, U8 type, S32& s, S32& t); @@ -1068,10 +1095,10 @@ class LLVolume : public LLRefCount LLVolumeParams mParams; LLPath *mPathp; LLProfile *mProfilep; - std::vector mMesh; + LLAlignedArray mMesh; + BOOL mGenerateSingleFace; - typedef std::vector face_list_t; face_list_t mVolumeFaces; public: @@ -1083,21 +1110,12 @@ class LLVolume : public LLRefCount std::ostream& operator<<(std::ostream &s, const LLVolumeParams &volume_params); -void calc_binormal_from_triangle( - LLVector4a& binormal, - const LLVector4a& pos0, - const LLVector2& tex0, - const LLVector4a& pos1, - const LLVector2& tex1, - const LLVector4a& pos2, - const LLVector2& tex2); - BOOL LLLineSegmentBoxIntersect(const F32* start, const F32* end, const F32* center, const F32* size); BOOL LLLineSegmentBoxIntersect(const LLVector3& start, const LLVector3& end, const LLVector3& center, const LLVector3& size); BOOL LLLineSegmentBoxIntersect(const LLVector4a& start, const LLVector4a& end, const LLVector4a& center, const LLVector4a& size); -BOOL LLTriangleRayIntersect(const LLVector3& vert0, const LLVector3& vert1, const LLVector3& vert2, const LLVector3& orig, const LLVector3& dir, - F32& intersection_a, F32& intersection_b, F32& intersection_t, BOOL two_sided); +//BOOL LLTriangleRayIntersect(const LLVector3& vert0, const LLVector3& vert1, const LLVector3& vert2, const LLVector3& orig, const LLVector3& dir, +// F32& intersection_a, F32& intersection_b, F32& intersection_t, BOOL two_sided); BOOL LLTriangleRayIntersect(const LLVector4a& vert0, const LLVector4a& vert1, const LLVector4a& vert2, const LLVector4a& orig, const LLVector4a& dir, F32& intersection_a, F32& intersection_b, F32& intersection_t); diff --git a/indra/llmath/llvolumemgr.cpp b/indra/llmath/llvolumemgr.cpp index dcc2d81cf4..a8c2766cb3 100644 --- a/indra/llmath/llvolumemgr.cpp +++ b/indra/llmath/llvolumemgr.cpp @@ -27,6 +27,7 @@ #include "llvolumemgr.h" #include "llvolume.h" +#include "llthread.h" const F32 BASE_THRESHOLD = 0.03f; @@ -147,7 +148,7 @@ void LLVolumeMgr::unrefVolume(LLVolume *volumep) volume_lod_group_map_t::iterator iter = mVolumeLODGroups.find(params); if( iter == mVolumeLODGroups.end() ) { - llerrs << "Warning! Tried to cleanup unknown volume type! " << *params << llendl; + LL_ERRS() << "Warning! Tried to cleanup unknown volume type! " << *params << LL_ENDL; if (mDataMutex) { mDataMutex->unlock(); @@ -207,14 +208,14 @@ void LLVolumeMgr::dump() { mDataMutex->unlock(); } - llinfos << "Average usage of LODs " << avg << llendl; + LL_INFOS() << "Average usage of LODs " << avg << LL_ENDL; } void LLVolumeMgr::useMutex() { if (!mDataMutex) { - mDataMutex = new LLMutex; + mDataMutex = new LLMutex(); } } @@ -270,18 +271,18 @@ bool LLVolumeLODGroup::cleanupRefs() bool res = true; if (mRefs != 0) { - llwarns << "Volume group has remaining refs:" << getNumRefs() << llendl; + LL_WARNS() << "Volume group has remaining refs:" << getNumRefs() << LL_ENDL; mRefs = 0; for (S32 i = 0; i < NUM_LODS; i++) { if (mLODRefs[i] > 0) { - llwarns << " LOD " << i << " refs = " << mLODRefs[i] << llendl; + LL_WARNS() << " LOD " << i << " refs = " << mLODRefs[i] << LL_ENDL; mLODRefs[i] = 0; mVolumeLODs[i] = NULL; } } - llwarns << *getVolumeParams() << llendl; + LL_WARNS() << *getVolumeParams() << LL_ENDL; res = false; } return res; @@ -320,7 +321,7 @@ BOOL LLVolumeLODGroup::derefLOD(LLVolume *volumep) return TRUE; } } - llerrs << "Deref of non-matching LOD in volume LOD group" << llendl; + LL_ERRS() << "Deref of non-matching LOD in volume LOD group" << LL_ENDL; return FALSE; } @@ -393,7 +394,7 @@ F32 LLVolumeLODGroup::dump() std::string dump_str = llformat("%.3f %d %d %d %d", usage, mAccessCount[0], mAccessCount[1], mAccessCount[2], mAccessCount[3]); - llinfos << dump_str << llendl; + LL_INFOS() << dump_str << LL_ENDL; return usage; } diff --git a/indra/llmath/llvolumemgr.h b/indra/llmath/llvolumemgr.h index f5dc4cd748..c2953655a2 100644 --- a/indra/llmath/llvolumemgr.h +++ b/indra/llmath/llvolumemgr.h @@ -2,31 +2,25 @@ * @file llvolumemgr.h * @brief LLVolumeMgr class. * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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$ */ @@ -37,7 +31,6 @@ #include "llvolume.h" #include "llpointer.h" -#include "llthread.h" class LLVolumeParams; class LLVolumeLODGroup; diff --git a/indra/llmath/llvolumeoctree.cpp b/indra/llmath/llvolumeoctree.cpp index cf9aeece8e..617e0812a4 100644 --- a/indra/llmath/llvolumeoctree.cpp +++ b/indra/llmath/llvolumeoctree.cpp @@ -94,14 +94,14 @@ void LLVolumeOctreeListener::handleChildAddition(const LLOctreeNode { LLVolumeOctreeListener* vl = (LLVolumeOctreeListener*) node->getListener(0); - /*const F32* start = mStart.getF32(); - const F32* end = mEnd.getF32(); - const F32* center = vl->mBounds[0].getF32(); - const F32* size = vl->mBounds[1].getF32();*/ - - //if (LLLineSegmentBoxIntersect(mStart, mEnd, vl->mBounds[0], vl->mBounds[1])) - if (LLLineSegmentBoxIntersect(mStart.getF32ptr(), mEnd.getF32ptr(), vl->mBounds[0].getF32ptr(), vl->mBounds[1].getF32ptr())) + if (LLLineSegmentBoxIntersect(mStart, mEnd, vl->mBounds[0], vl->mBounds[1])) { node->accept(this); for (U32 i = 0; i < node->getChildCount(); ++i) @@ -152,34 +146,60 @@ void LLOctreeTriangleRayIntersect::visit(const LLOctreeNode* n LLVector4a intersect = mDir; intersect.mul(*mClosestT); intersect.add(mStart); - mIntersection->set(intersect.getF32ptr()); + *mIntersection = intersect; } + U32 idx0 = tri->mIndex[0]; + U32 idx1 = tri->mIndex[1]; + U32 idx2 = tri->mIndex[2]; if (mTexCoord != NULL) { LLVector2* tc = (LLVector2*) mFace->mTexCoords; - *mTexCoord = ((1.f - a - b) * tc[tri->mIndex[0]] + - a * tc[tri->mIndex[1]] + - b * tc[tri->mIndex[2]]); + *mTexCoord = ((1.f - a - b) * tc[idx0] + + a * tc[idx1] + + b * tc[idx2]); } if (mNormal != NULL) { - LLVector4* norm = (LLVector4*) mFace->mNormals; - - *mNormal = ((1.f - a - b) * LLVector3(norm[tri->mIndex[0]]) + - a * LLVector3(norm[tri->mIndex[1]]) + - b * LLVector3(norm[tri->mIndex[2]])); + LLVector4a* norm = mFace->mNormals; + + LLVector4a n1,n2,n3; + n1 = norm[idx0]; + n1.mul(1.f-a-b); + + n2 = norm[idx1]; + n2.mul(a); + + n3 = norm[idx2]; + n3.mul(b); + + n1.add(n2); + n1.add(n3); + + *mNormal = n1; } - if (mBinormal != NULL) + if (mTangent != NULL) { - LLVector4* binormal = (LLVector4*) mFace->mBinormals; - *mBinormal = ((1.f - a - b) * LLVector3(binormal[tri->mIndex[0]]) + - a * LLVector3(binormal[tri->mIndex[1]]) + - b * LLVector3(binormal[tri->mIndex[2]])); + LLVector4a* tangents = mFace->mTangents; + + LLVector4a t1,t2,t3; + t1 = tangents[idx0]; + t1.mul(1.f-a-b); + + t2 = tangents[idx1]; + t2.mul(a); + + t3 = tangents[idx2]; + t3.mul(b); + + t1.add(t2); + t1.add(t3); + + *mTangent = t1; } } } @@ -217,7 +237,7 @@ void LLVolumeOctreeValidate::visit(const LLOctreeNode* branch) if (!test_min.equals3(min, 0.001f) || !test_max.equals3(max, 0.001f)) { - llerrs << "Bad bounding box data found." << llendl; + LL_ERRS() << "Bad bounding box data found." << LL_ENDL; } test_min.sub(LLVector4a(0.001f)); @@ -231,7 +251,7 @@ void LLVolumeOctreeValidate::visit(const LLOctreeNode* branch) if (child->mExtents[0].lessThan(test_min).areAnySet(LLVector4Logical::MASK_XYZ) || child->mExtents[1].greaterThan(test_max).areAnySet(LLVector4Logical::MASK_XYZ)) { - llerrs << "Child protrudes from bounding box." << llendl; + LL_ERRS() << "Child protrudes from bounding box." << LL_ENDL; } } @@ -247,7 +267,7 @@ void LLVolumeOctreeValidate::visit(const LLOctreeNode* branch) if (tri->mV[i]->greaterThan(test_max).areAnySet(LLVector4Logical::MASK_XYZ) || tri->mV[i]->lessThan(test_min).areAnySet(LLVector4Logical::MASK_XYZ)) { - llerrs << "Triangle protrudes from node." << llendl; + LL_ERRS() << "Triangle protrudes from node." << LL_ENDL; } } } diff --git a/indra/llmath/llvolumeoctree.h b/indra/llmath/llvolumeoctree.h index 03f10814ea..0c8e1d2b80 100644 --- a/indra/llmath/llvolumeoctree.h +++ b/indra/llmath/llvolumeoctree.h @@ -58,7 +58,7 @@ class LLVolumeTriangle : public LLRefCount const LLVolumeTriangle& operator=(const LLVolumeTriangle& rhs) { - llerrs << "Illegal operation!" << llendl; + LL_ERRS() << "Illegal operation!" << LL_ENDL; return *this; } @@ -107,19 +107,18 @@ class LLVolumeOctreeListener : public LLOctreeListener const LLVolumeOctreeListener& operator=(const LLVolumeOctreeListener& rhs) { - llerrs << "Illegal operation!" << llendl; + LL_ERRS() << "Illegal operation!" << LL_ENDL; return *this; } //LISTENER FUNCTIONS - virtual void handleChildAddition(const LLOctreeNode* parent, - LLOctreeNode* child); - virtual void handleStateChange(const LLTreeNode* node) { } - virtual void handleChildRemoval(const LLOctreeNode* parent, - const LLOctreeNode* child) { } - virtual void handleInsertion(const LLTreeNode* node, LLVolumeTriangle* tri) { } - virtual void handleRemoval(const LLTreeNode* node, LLVolumeTriangle* tri) { } - virtual void handleDestruction(const LLTreeNode* node) { } + void handleChildAddition(const LLOctreeNode* parent, + LLOctreeNode* child) final override; + void handleChildRemoval(const LLOctreeNode* parent, + const LLOctreeNode* child) final override { } + void handleInsertion(const LLTreeNode* node, LLVolumeTriangle* tri) final override { } + void handleRemoval(const LLTreeNode* node, LLVolumeTriangle* tri) final override { } + void handleDestruction(const LLTreeNode* node) final override { } public: @@ -127,28 +126,29 @@ class LLVolumeOctreeListener : public LLOctreeListener LL_ALIGN_16(LLVector4a mExtents[2]); // extents (min, max) of this node and all its children }; +LL_ALIGN_PREFIX(16) class LLOctreeTriangleRayIntersect : public LLOctreeTraveler { public: const LLVolumeFace* mFace; - LLVector4a mStart; - LLVector4a mDir; - LLVector4a mEnd; - LLVector3* mIntersection; + LL_ALIGN_16(LLVector4a mStart); + LL_ALIGN_16(LLVector4a mDir); + LL_ALIGN_16(LLVector4a mEnd); + LLVector4a* mIntersection; LLVector2* mTexCoord; - LLVector3* mNormal; - LLVector3* mBinormal; + LLVector4a* mNormal; + LLVector4a* mTangent; F32* mClosestT; bool mHitFace; LLOctreeTriangleRayIntersect(const LLVector4a& start, const LLVector4a& dir, const LLVolumeFace* face, F32* closest_t, - LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal); + LLVector4a* intersection,LLVector2* tex_coord, LLVector4a* normal, LLVector4a* tangent); void traverse(const LLOctreeNode* node); virtual void visit(const LLOctreeNode* node); -}; +} LL_ALIGN_POSTFIX(16); class LLVolumeOctreeValidate : public LLOctreeTraveler { diff --git a/indra/llmath/m3math.cpp b/indra/llmath/m3math.cpp index 1b878c8f4d..fa5dfb62d2 100644 --- a/indra/llmath/m3math.cpp +++ b/indra/llmath/m3math.cpp @@ -2,31 +2,25 @@ * @file m3math.cpp * @brief LLMatrix3 class implementation. * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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$ */ diff --git a/indra/llmath/m3math.h b/indra/llmath/m3math.h index 3ac963e5aa..a25f3e906e 100644 --- a/indra/llmath/m3math.h +++ b/indra/llmath/m3math.h @@ -2,31 +2,25 @@ * @file m3math.h * @brief LLMatrix3 class header file. * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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$ */ @@ -150,6 +144,8 @@ class LLMatrix3 friend std::ostream& operator<<(std::ostream& s, const LLMatrix3 &a); // Stream a }; +static_assert(std::is_trivially_copyable::value, "LLMatrix3 must be a trivially copyable type"); + inline LLMatrix3::LLMatrix3(void) { mMatrix[0][0] = 1.f; diff --git a/indra/llmath/m4math.cpp b/indra/llmath/m4math.cpp index 108aeb118b..a225c51b13 100644 --- a/indra/llmath/m4math.cpp +++ b/indra/llmath/m4math.cpp @@ -2,31 +2,25 @@ * @file m4math.cpp * @brief LLMatrix4 class implementation. * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -158,10 +152,6 @@ LLMatrix4::LLMatrix4(const F32 roll, const F32 pitch, const F32 yaw) mMatrix[3][3] = 1.f; } -LLMatrix4::~LLMatrix4(void) -{ -} - // Clear and Assignment Functions const LLMatrix4& LLMatrix4::setZero() @@ -280,6 +270,19 @@ const LLMatrix4& LLMatrix4::invert(void) return *this; } +// Convenience func for simplifying comparison-heavy code by +// intentionally stomping values in [-FLT_EPS,FLT_EPS] to 0.0f +// +void LLMatrix4::condition(void) +{ + U32 i; + U32 j; + for (i = 0; i < 3;i++) + for (j = 0; j < 3;j++) + mMatrix[i][j] = ((mMatrix[i][j] > -FLT_EPSILON) + && (mMatrix[i][j] < FLT_EPSILON)) ? 0.0f : mMatrix[i][j]; +} + LLVector4 LLMatrix4::getFwdRow4() const { return LLVector4(mMatrix[VX][VX], mMatrix[VX][VY], mMatrix[VX][VZ], mMatrix[VX][VW]); @@ -684,37 +687,6 @@ const LLMatrix4& LLMatrix4::initMatrix(const LLMatrix3 &mat, const LLVector4 & // LLMatrix4 Operators - -/* Not implemented to help enforce code consistency with the syntax of - row-major notation. This is a Good Thing. -LLVector4 operator*(const LLMatrix4 &a, const LLVector4 &b) -{ - // Operate "to the right" on column-vector b - LLVector4 vec; - vec.mV[VX] = a.mMatrix[VX][VX] * b.mV[VX] + - a.mMatrix[VY][VX] * b.mV[VY] + - a.mMatrix[VZ][VX] * b.mV[VZ] + - a.mMatrix[VW][VX] * b.mV[VW]; - - vec.mV[VY] = a.mMatrix[VX][VY] * b.mV[VX] + - a.mMatrix[VY][VY] * b.mV[VY] + - a.mMatrix[VZ][VY] * b.mV[VZ] + - a.mMatrix[VW][VY] * b.mV[VW]; - - vec.mV[VZ] = a.mMatrix[VX][VZ] * b.mV[VX] + - a.mMatrix[VY][VZ] * b.mV[VY] + - a.mMatrix[VZ][VZ] * b.mV[VZ] + - a.mMatrix[VW][VZ] * b.mV[VW]; - - vec.mV[VW] = a.mMatrix[VX][VW] * b.mV[VX] + - a.mMatrix[VY][VW] * b.mV[VY] + - a.mMatrix[VZ][VW] * b.mV[VZ] + - a.mMatrix[VW][VW] * b.mV[VW]; - return vec; -} -*/ - - LLVector4 operator*(const LLVector4 &a, const LLMatrix4 &b) { // Operate "to the left" on row-vector a diff --git a/indra/llmath/m4math.h b/indra/llmath/m4math.h index 27e4be4b47..c4d37d0f73 100644 --- a/indra/llmath/m4math.h +++ b/indra/llmath/m4math.h @@ -2,31 +2,25 @@ * @file m4math.h * @brief LLMatrix4 class header file. * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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$ */ @@ -123,7 +117,7 @@ class LLMatrix4 const LLVector4 &pos); // Initializes Matrix with Euler angles LLMatrix4(const F32 roll, const F32 pitch, const F32 yaw); // Initializes Matrix with Euler angles - ~LLMatrix4(void); // Destructor + ~LLMatrix4() = default; // Destructor LLSD getValue() const; void setValue(const LLSD&); @@ -186,6 +180,11 @@ class LLMatrix4 const LLMatrix4& setTranslation(const LLVector4 &translation); const LLMatrix4& setTranslation(const LLVector3 &translation); + // Convenience func for simplifying comparison-heavy code by + // intentionally stomping values [-FLT_EPS,FLT_EPS] to 0.0 + // + void condition(void); + /////////////////////////// // // Get properties of a matrix @@ -229,9 +228,6 @@ class LLMatrix4 // Operators // -// Not implemented to enforce code that agrees with symbolic syntax -// friend LLVector4 operator*(const LLMatrix4 &a, const LLVector4 &b); // Apply rotation a to vector b - // friend inline LLMatrix4 operator*(const LLMatrix4 &a, const LLMatrix4 &b); // Return a * b friend LLVector4 operator*(const LLVector4 &a, const LLMatrix4 &b); // Return transform of vector a by matrix b friend const LLVector3 operator*(const LLVector3 &a, const LLMatrix4 &b); // Return full transform of a by matrix b @@ -250,6 +246,8 @@ class LLMatrix4 friend std::ostream& operator<<(std::ostream& s, const LLMatrix4 &a); // Stream a }; +static_assert(std::is_trivially_copyable::value, "LLMatrix4 must be a trivially copyable type"); + inline const LLMatrix4& LLMatrix4::setIdentity() { mMatrix[0][0] = 1.f; diff --git a/indra/llmath/raytrace.cpp b/indra/llmath/raytrace.cpp index a5eb0d2682..204d8f576a 100644 --- a/indra/llmath/raytrace.cpp +++ b/indra/llmath/raytrace.cpp @@ -2,31 +2,25 @@ * @file raytrace.cpp * @brief Functions called by box object scripts. * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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$ */ diff --git a/indra/llmath/raytrace.h b/indra/llmath/raytrace.h index b433e1769c..eb721a5e00 100644 --- a/indra/llmath/raytrace.h +++ b/indra/llmath/raytrace.h @@ -2,31 +2,25 @@ * @file raytrace.h * @brief Ray intersection tests for primitives. * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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$ */ diff --git a/indra/llmath/v2math.cpp b/indra/llmath/v2math.cpp index 2603127f75..e4706c75b5 100644 --- a/indra/llmath/v2math.cpp +++ b/indra/llmath/v2math.cpp @@ -2,31 +2,25 @@ * @file v2math.cpp * @brief LLVector2 class implementation. * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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$ */ @@ -124,7 +118,7 @@ LLSD LLVector2::getValue() const return ret; } -void LLVector2::setValue(LLSD& sd) +void LLVector2::setValue(const LLSD& sd) { mV[0] = (F32) sd[0].asReal(); mV[1] = (F32) sd[1].asReal(); diff --git a/indra/llmath/v2math.h b/indra/llmath/v2math.h index 35fd1b6048..d6fb004383 100644 --- a/indra/llmath/v2math.h +++ b/indra/llmath/v2math.h @@ -2,31 +2,25 @@ * @file v2math.h * @brief LLVector2 class header file. * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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$ */ @@ -55,6 +49,7 @@ class LLVector2 LLVector2(F32 x, F32 y); // Initializes LLVector2 to (x. y) LLVector2(const F32 *vec); // Initializes LLVector2 to (vec[0]. vec[1]) explicit LLVector2(const LLVector3 &vec); // Initializes LLVector2 to (vec[0]. vec[1]) + explicit LLVector2(const LLSD &sd); // Clears LLVector2 to (0, 0). DEPRECATED - prefer zeroVec. void clear(); @@ -67,7 +62,7 @@ class LLVector2 void set(const F32 *vec); // Sets LLVector2 to vec LLSD getValue() const; - void setValue(LLSD& sd); + void setValue(const LLSD& sd); void setVec(F32 x, F32 y); // deprecated void setVec(const LLVector2 &vec); // deprecated @@ -115,6 +110,7 @@ class LLVector2 friend std::ostream& operator<<(std::ostream& s, const LLVector2 &a); // Stream a }; +static_assert(std::is_trivially_copyable::value, "LLVector2 must be a trivially copyable type"); // Non-member functions @@ -151,6 +147,10 @@ inline LLVector2::LLVector2(const LLVector3 &vec) mV[VY] = vec.mV[VY]; } +inline LLVector2::LLVector2(const LLSD &sd) +{ + setValue(sd); +} // Clear and Assignment Functions @@ -256,7 +256,7 @@ inline F32 LLVector2::normalize(void) // checker inline bool LLVector2::isFinite() const { - return (llfinite(mV[VX]) && llfinite(mV[VY])); + return (std::isfinite(mV[VX]) && std::isfinite(mV[VY])); } // deprecated diff --git a/indra/llmath/v3color.cpp b/indra/llmath/v3color.cpp index b4cd410076..f4b4af34c9 100644 --- a/indra/llmath/v3color.cpp +++ b/indra/llmath/v3color.cpp @@ -2,31 +2,25 @@ * @file v3color.cpp * @brief LLColor3 class implementation. * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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$ */ diff --git a/indra/llmath/v3color.h b/indra/llmath/v3color.h index 95a3de8b62..b8a5fb95e3 100644 --- a/indra/llmath/v3color.h +++ b/indra/llmath/v3color.h @@ -2,31 +2,25 @@ * @file v3color.h * @brief LLColor3 class header file. * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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$ */ @@ -39,6 +33,7 @@ class LLVector4; #include "llerror.h" #include "llmath.h" #include "llsd.h" +#include // LLColor3 = |r g b| @@ -105,6 +100,23 @@ class LLColor3 const LLColor3& operator=(const LLColor4 &a); + LL_FORCE_INLINE LLColor3 divide(const LLColor3 &col2) + { + return LLColor3( + mV[0] / col2.mV[0], + mV[1] / col2.mV[1], + mV[2] / col2.mV[2] ); + } + + LL_FORCE_INLINE LLColor3 color_norm() const + { + F32 l = length(); + return LLColor3( + mV[0] / l, + mV[1] / l, + mV[2] / l ); + } + friend std::ostream& operator<<(std::ostream& s, const LLColor3 &a); // Print a friend LLColor3 operator+(const LLColor3 &a, const LLColor3 &b); // Return vector a + b friend LLColor3 operator-(const LLColor3 &a, const LLColor3 &b); // Return vector a minus b @@ -128,6 +140,8 @@ class LLColor3 inline void exp(); // Do an exponential on the color }; +static_assert(std::is_trivially_copyable::value, "LLColor3 must be a trivially copyable type"); + LLColor3 lerp(const LLColor3 &a, const LLColor3 &b, F32 u); diff --git a/indra/llmath/v3colorutil.h b/indra/llmath/v3colorutil.h new file mode 100644 index 0000000000..6d8cd9329b --- /dev/null +++ b/indra/llmath/v3colorutil.h @@ -0,0 +1,115 @@ +/** + * @file v3color.h + * @brief LLColor3 class header file. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_V3COLORUTIL_H +#define LL_V3COLORUTIL_H + +#include "v3color.h" + +inline LLColor3 componentDiv(LLColor3 const &left, LLColor3 const & right) +{ + return LLColor3(left.mV[0] / right.mV[0], + left.mV[1] / right.mV[1], + left.mV[2] / right.mV[2]); +} + + +inline LLColor3 componentMult(LLColor3 const &left, LLColor3 const & right) +{ + return LLColor3(left.mV[0] * right.mV[0], + left.mV[1] * right.mV[1], + left.mV[2] * right.mV[2]); +} + + +inline LLColor3 componentExp(LLColor3 const &v) +{ + return LLColor3(exp(v.mV[0]), + exp(v.mV[1]), + exp(v.mV[2])); +} + +inline LLColor3 componentPow(LLColor3 const &v, F32 exponent) +{ + return LLColor3(pow(v.mV[0], exponent), + pow(v.mV[1], exponent), + pow(v.mV[2], exponent)); +} + +inline LLColor3 componentSaturate(LLColor3 const &v) +{ + return LLColor3(std::max(std::min(v.mV[0], 1.f), 0.f), + std::max(std::min(v.mV[1], 1.f), 0.f), + std::max(std::min(v.mV[2], 1.f), 0.f)); +} + + +inline LLColor3 componentSqrt(LLColor3 const &v) +{ + return LLColor3(sqrt(v.mV[0]), + sqrt(v.mV[1]), + sqrt(v.mV[2])); +} + +inline void componentMultBy(LLColor3 & left, LLColor3 const & right) +{ + left.mV[0] *= right.mV[0]; + left.mV[1] *= right.mV[1]; + left.mV[2] *= right.mV[2]; +} + +inline LLColor3 colorMix(LLColor3 const & left, LLColor3 const & right, F32 amount) +{ + return (left + ((right - left) * amount)); +} + +inline LLColor3 smear(F32 val) +{ + return LLColor3(val, val, val); +} + +inline F32 color_intens(const LLColor3 &col) +{ + return col.mV[0] + col.mV[1] + col.mV[2]; +} + +inline F32 color_max(const LLColor3 &col) +{ + return llmax(col.mV[0], col.mV[1], col.mV[2]); +} + +inline F32 color_max(const LLColor4 &col) +{ + return llmax(col.mV[0], col.mV[1], col.mV[2]); +} + + +inline F32 color_min(const LLColor3 &col) +{ + return llmin(col.mV[0], col.mV[1], col.mV[2]); +} + +#endif diff --git a/indra/llmath/v3dmath.cpp b/indra/llmath/v3dmath.cpp index 2bcbf632b1..af5c8ef393 100644 --- a/indra/llmath/v3dmath.cpp +++ b/indra/llmath/v3dmath.cpp @@ -2,31 +2,25 @@ * @file v3dmath.cpp * @brief LLVector3d class implementation. * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llmath/v3dmath.h b/indra/llmath/v3dmath.h index 5cd6e4dfed..2efa5a500d 100644 --- a/indra/llmath/v3dmath.h +++ b/indra/llmath/v3dmath.h @@ -72,17 +72,22 @@ class LLVector3d BOOL clamp(const F64 min, const F64 max); // Clamps all values to (min,max), returns TRUE if data changed BOOL abs(); // sets all values to absolute value of original value (first octant), returns TRUE if changed - inline const LLVector3d& clearVec(); // Clears LLVector3d to (0, 0, 0, 1) + inline const LLVector3d& clear(); // Clears LLVector3d to (0, 0, 0, 1) + inline const LLVector3d& clearVec(); // deprecated inline const LLVector3d& setZero(); // Zero LLVector3d to (0, 0, 0, 0) inline const LLVector3d& zeroVec(); // deprecated - inline const LLVector3d& setVec(const F64 x, const F64 y, const F64 z); // Sets LLVector3d to (x, y, z, 1) - inline const LLVector3d& setVec(const LLVector3d &vec); // Sets LLVector3d to vec - inline const LLVector3d& setVec(const F64 *vec); // Sets LLVector3d to vec - inline const LLVector3d& setVec(const LLVector3 &vec); - - F64 magVec() const; // Returns magnitude of LLVector3d - F64 magVecSquared() const; // Returns magnitude squared of LLVector3d - inline F64 normVec(); // Normalizes and returns the magnitude of LLVector3d + inline const LLVector3d& set(const F64 x, const F64 y, const F64 z); // Sets LLVector3d to (x, y, z, 1) + inline const LLVector3d& set(const LLVector3d &vec); // Sets LLVector3d to vec + inline const LLVector3d& set(const F64 *vec); // Sets LLVector3d to vec + inline const LLVector3d& set(const LLVector3 &vec); + inline const LLVector3d& setVec(const F64 x, const F64 y, const F64 z); // deprecated + inline const LLVector3d& setVec(const LLVector3d &vec); // deprecated + inline const LLVector3d& setVec(const F64 *vec); // deprecated + inline const LLVector3d& setVec(const LLVector3 &vec); // deprecated + + F64 magVec() const; // deprecated + F64 magVecSquared() const; // deprecated + inline F64 normVec(); // deprecated F64 length() const; // Returns magnitude of LLVector3d F64 lengthSquared() const; // Returns magnitude squared of LLVector3d @@ -125,9 +130,19 @@ class LLVector3d }; +static_assert(std::is_trivially_copyable::value, "LLVector3d must be a trivially copyable type"); + typedef LLVector3d LLGlobalVec; -const LLVector3d &LLVector3d::setVec(const LLVector3 &vec) +inline const LLVector3d &LLVector3d::set(const LLVector3 &vec) +{ + mdV[0] = vec.mV[0]; + mdV[1] = vec.mV[1]; + mdV[2] = vec.mV[2]; + return *this; +} + +inline const LLVector3d &LLVector3d::setVec(const LLVector3 &vec) { mdV[0] = vec.mV[0]; mdV[1] = vec.mV[1]; @@ -178,12 +193,20 @@ inline LLVector3d::LLVector3d(const LLVector3d ©) // checker inline BOOL LLVector3d::isFinite() const { - return (llfinite(mdV[VX]) && llfinite(mdV[VY]) && llfinite(mdV[VZ])); + return (std::isfinite(mdV[VX]) && std::isfinite(mdV[VY]) && std::isfinite(mdV[VZ])); } // Clear and Assignment Functions +inline const LLVector3d& LLVector3d::clear(void) +{ + mdV[0] = 0.f; + mdV[1] = 0.f; + mdV[2]= 0.f; + return (*this); +} + inline const LLVector3d& LLVector3d::clearVec(void) { mdV[0] = 0.f; @@ -208,6 +231,30 @@ inline const LLVector3d& LLVector3d::zeroVec(void) return (*this); } +inline const LLVector3d& LLVector3d::set(const F64 x, const F64 y, const F64 z) +{ + mdV[VX] = x; + mdV[VY] = y; + mdV[VZ] = z; + return (*this); +} + +inline const LLVector3d& LLVector3d::set(const LLVector3d &vec) +{ + mdV[0] = vec.mdV[0]; + mdV[1] = vec.mdV[1]; + mdV[2] = vec.mdV[2]; + return (*this); +} + +inline const LLVector3d& LLVector3d::set(const F64 *vec) +{ + mdV[0] = vec[0]; + mdV[1] = vec[1]; + mdV[2] = vec[2]; + return (*this); +} + inline const LLVector3d& LLVector3d::setVec(const F64 x, const F64 y, const F64 z) { mdV[VX] = x; @@ -472,4 +519,15 @@ inline LLVector3d projected_vec(const LLVector3d &a, const LLVector3d &b) return project_axis * (a * project_axis); } +inline LLVector3d inverse_projected_vec(const LLVector3d& a, const LLVector3d& b) +{ + LLVector3d normalized_a = a; + normalized_a.normalize(); + LLVector3d normalized_b = b; + F64 b_length = normalized_b.normalize(); + + F64 dot_product = normalized_a * normalized_b; + return normalized_a * (b_length / dot_product); +} + #endif // LL_V3DMATH_H diff --git a/indra/llmath/v3math.cpp b/indra/llmath/v3math.cpp index daabbcc374..88e91e8d10 100644 --- a/indra/llmath/v3math.cpp +++ b/indra/llmath/v3math.cpp @@ -2,31 +2,25 @@ * @file v3math.cpp * @brief LLVector3 class implementation. * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -82,7 +76,7 @@ BOOL LLVector3::clampLength( F32 length_limit ) BOOL changed = FALSE; F32 len = length(); - if (llfinite(len)) + if (std::isfinite(len)) { if ( len > length_limit) { @@ -103,7 +97,7 @@ BOOL LLVector3::clampLength( F32 length_limit ) for (S32 i = 0; i < 3; ++i) { F32 abs_component = fabs(mV[i]); - if (llfinite(abs_component)) + if (std::isfinite(abs_component)) { if (abs_component > max_abs_component) { @@ -375,3 +369,39 @@ BOOL LLVector3::parseVector3(const std::string& buf, LLVector3* value) return FALSE; } + +// Displacement from query point to nearest neighbor point on bounding box. +// Returns zero vector for points within or on the box. +LLVector3 point_to_box_offset(LLVector3& pos, const LLVector3* box) +{ + LLVector3 offset; + for (S32 k=0; k<3; k++) + { + offset[k] = 0; + if (pos[k] < box[0][k]) + { + offset[k] = pos[k] - box[0][k]; + } + else if (pos[k] > box[1][k]) + { + offset[k] = pos[k] - box[1][k]; + } + } + return offset; +} + +bool box_valid_and_non_zero(const LLVector3* box) +{ + if (!box[0].isFinite() || !box[1].isFinite()) + { + return false; + } + LLVector3 zero_vec; + zero_vec.clear(); + if ((box[0] != zero_vec) || (box[1] != zero_vec)) + { + return true; + } + return false; +} + diff --git a/indra/llmath/v3math.h b/indra/llmath/v3math.h index 0e5b196ee9..35acead650 100644 --- a/indra/llmath/v3math.h +++ b/indra/llmath/v3math.h @@ -149,6 +149,8 @@ class LLVector3 static BOOL parseVector3(const std::string& buf, LLVector3* value); }; +static_assert(std::is_trivially_copyable::value, "LLVector3 must be a trivially copyable type"); + typedef LLVector3 LLSimLocalVec; // Non-member functions @@ -159,9 +161,12 @@ F32 dist_vec(const LLVector3 &a, const LLVector3 &b); // Returns distance betwe F32 dist_vec_squared(const LLVector3 &a, const LLVector3 &b);// Returns distance squared between a and b F32 dist_vec_squared2D(const LLVector3 &a, const LLVector3 &b);// Returns distance squared between a and b ignoring Z component LLVector3 projected_vec(const LLVector3 &a, const LLVector3 &b); // Returns vector a projected on vector b +LLVector3 inverse_projected_vec(const LLVector3 &a, const LLVector3 &b); // Returns vector a scaled such that projected_vec(inverse_projected_vec(a, b), b) == b; LLVector3 parallel_component(const LLVector3 &a, const LLVector3 &b); // Returns vector a projected on vector b (same as projected_vec) LLVector3 orthogonal_component(const LLVector3 &a, const LLVector3 &b); // Returns component of vector a not parallel to vector b (same as projected_vec) LLVector3 lerp(const LLVector3 &a, const LLVector3 &b, F32 u); // Returns a vector that is a linear interpolation between a and b +LLVector3 point_to_box_offset(LLVector3& pos, const LLVector3* box); // Displacement from query point to nearest point on bounding box. +bool box_valid_and_non_zero(const LLVector3* box); inline LLVector3::LLVector3(void) { @@ -198,7 +203,7 @@ inline LLVector3::LLVector3(const LLVector3 ©) // checker inline BOOL LLVector3::isFinite() const { - return (llfinite(mV[VX]) && llfinite(mV[VY]) && llfinite(mV[VZ])); + return (std::isfinite(mV[VX]) && std::isfinite(mV[VY]) && std::isfinite(mV[VZ])); } @@ -490,9 +495,27 @@ inline F32 dist_vec_squared2D(const LLVector3 &a, const LLVector3 &b) inline LLVector3 projected_vec(const LLVector3 &a, const LLVector3 &b) { - LLVector3 project_axis = b; - project_axis.normalize(); - return project_axis * (a * project_axis); + F32 bb = b * b; + if (bb > FP_MAG_THRESHOLD * FP_MAG_THRESHOLD) + { + return ((a * b) / bb) * b; + } + else + { + return b.zero; + } +} + +inline LLVector3 inverse_projected_vec(const LLVector3& a, const LLVector3& b) +{ + LLVector3 normalized_a = a; + normalized_a.normalize(); + LLVector3 normalized_b = b; + F32 b_length = normalized_b.normalize(); + + F32 dot_product = normalized_a * normalized_b; + //NB: if a _|_ b, then returns an infinite vector + return normalized_a * (b_length / dot_product); } inline LLVector3 parallel_component(const LLVector3 &a, const LLVector3 &b) @@ -556,15 +579,13 @@ inline void update_min_max(LLVector3& min, LLVector3& max, const F32* pos) inline F32 angle_between(const LLVector3& a, const LLVector3& b) { - LLVector3 an = a; - LLVector3 bn = b; - an.normalize(); - bn.normalize(); - F32 cosine = an * bn; - F32 angle = (cosine >= 1.0f) ? 0.0f : - (cosine <= -1.0f) ? F_PI : - (F32)acos(cosine); - return angle; + F32 ab = a * b; // dotproduct + if (ab == -0.0f) + { + ab = 0.0f; // get rid of negative zero + } + LLVector3 c = a % b; // crossproduct + return atan2f(sqrtf(c * c), ab); // return the angle } inline BOOL are_parallel(const LLVector3 &a, const LLVector3 &b, F32 epsilon) diff --git a/indra/llmath/v4color.cpp b/indra/llmath/v4color.cpp index 9131befd8a..6de5fb6329 100644 --- a/indra/llmath/v4color.cpp +++ b/indra/llmath/v4color.cpp @@ -124,11 +124,12 @@ LLColor4 LLColor4::cyan6(0.2f, 0.6f, 0.6f, 1.0f); // conversion LLColor4::operator const LLColor4U() const { + // Singu Note: Some optimization has been done here. return LLColor4U( - (U8)llclampb(llround(mV[VRED]*255.f)), - (U8)llclampb(llround(mV[VGREEN]*255.f)), - (U8)llclampb(llround(mV[VBLUE]*255.f)), - (U8)llclampb(llround(mV[VALPHA]*255.f))); + (U8)llmin((S32)(llmax(0.f,mV[VRED]*255.f) + .5f), 255), + (U8)llmin((S32)(llmax(0.f,mV[VGREEN]*255.f) + .5f), 255), + (U8)llmin((S32)(llmax(0.f,mV[VBLUE]*255.f) + .5f), 255), + (U8)llmin((S32)(llmax(0.f,mV[VALPHA]*255.f) + .5f), 255)); } LLColor4::LLColor4(const LLColor3 &vec, F32 a) @@ -245,7 +246,7 @@ void LLColor4::setValue(const LLSD& sd) if (out_of_range) { - llwarns << "LLSD color value out of range!" << llendl; + LL_WARNS() << "LLSD color value out of range!" << LL_ENDL; } #else mV[0] = (F32) sd[0].asReal(); @@ -417,7 +418,7 @@ BOOL LLColor4::parseColor(const std::string& buf, LLColor4* color) if (token_iter == tokens.end()) { // This is a malformed vector. - llwarns << "LLColor4::parseColor() malformed color " << buf << llendl; + LL_WARNS() << "LLColor4::parseColor() malformed color " << buf << LL_ENDL; } else { @@ -704,7 +705,7 @@ BOOL LLColor4::parseColor(const std::string& buf, LLColor4* color) } else { - llwarns << "invalid color " << color_name << llendl; + LL_WARNS() << "invalid color " << color_name << LL_ENDL; } } diff --git a/indra/llmath/v4color.h b/indra/llmath/v4color.h index 3f9e1efd8a..845160d3d1 100644 --- a/indra/llmath/v4color.h +++ b/indra/llmath/v4color.h @@ -114,9 +114,11 @@ class LLColor4 friend LLColor4 operator-(const LLColor4 &a, const LLColor4 &b); // Return vector a minus b friend LLColor4 operator*(const LLColor4 &a, const LLColor4 &b); // Return component wise a * b friend LLColor4 operator*(const LLColor4 &a, F32 k); // Return rgb times scaler k (no alpha change) + friend LLColor4 operator/(const LLColor4 &a, F32 k); // Return rgb divided by scalar k (no alpha change) friend LLColor4 operator*(F32 k, const LLColor4 &a); // Return rgb times scaler k (no alpha change) friend LLColor4 operator%(const LLColor4 &a, F32 k); // Return alpha times scaler k (no rgb change) friend LLColor4 operator%(F32 k, const LLColor4 &a); // Return alpha times scaler k (no rgb change) + friend bool operator==(const LLColor4 &a, const LLColor4 &b); // Return a == b friend bool operator!=(const LLColor4 &a, const LLColor4 &b); // Return a != b @@ -220,6 +222,7 @@ class LLColor4 inline void clamp(); }; +static_assert(std::is_trivially_copyable::value, "LLColor4 must be a trivially copyable type"); // Non-member functions F32 distVec(const LLColor4 &a, const LLColor4 &b); // Returns distance between a and b @@ -477,6 +480,15 @@ inline LLColor4 operator*(const LLColor4 &a, F32 k) a.mV[VW]); } +inline LLColor4 operator/(const LLColor4 &a, F32 k) +{ + return LLColor4( + a.mV[VX] / k, + a.mV[VY] / k, + a.mV[VZ] / k, + a.mV[VW]); +} + inline LLColor4 operator*(F32 k, const LLColor4 &a) { // only affects rgb (not a!) diff --git a/indra/llmath/v4coloru.cpp b/indra/llmath/v4coloru.cpp index 061b4970f7..23f53bb071 100644 --- a/indra/llmath/v4coloru.cpp +++ b/indra/llmath/v4coloru.cpp @@ -2,31 +2,25 @@ * @file v4coloru.cpp * @brief LLColor4U class implementation. * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llmath/v4coloru.h b/indra/llmath/v4coloru.h index fa1295441e..3a313759d3 100644 --- a/indra/llmath/v4coloru.h +++ b/indra/llmath/v4coloru.h @@ -139,6 +139,7 @@ class LLColor4U static LLColor4U blue; }; +static_assert(std::is_trivially_copyable::value, "LLColor4U must be a trivially copyable type"); // Non-member functions F32 distVec(const LLColor4U &a, const LLColor4U &b); // Returns distance between a and b @@ -353,10 +354,10 @@ inline LLColor4U LLColor4U::multAll(const F32 k) { // Round to nearest return LLColor4U( - (U8)llround(mV[VX] * k), - (U8)llround(mV[VY] * k), - (U8)llround(mV[VZ] * k), - (U8)llround(mV[VW] * k)); + (U8)ll_pos_round(mV[VX] * k), + (U8)ll_pos_round(mV[VY] * k), + (U8)ll_pos_round(mV[VZ] * k), + (U8)ll_pos_round(mV[VW] * k)); } /* inline LLColor4U operator*(const LLColor4U &a, U8 k) @@ -471,7 +472,7 @@ void LLColor4U::setVecScaleClamp(const LLColor4& color) color_scale_factor /= max_color; } const S32 MAX_COLOR = 255; - S32 r = llround(color.mV[0] * color_scale_factor); + S32 r = ll_pos_round(color.mV[0] * color_scale_factor); if (r > MAX_COLOR) { r = MAX_COLOR; @@ -482,7 +483,7 @@ void LLColor4U::setVecScaleClamp(const LLColor4& color) } mV[0] = r; - S32 g = llround(color.mV[1] * color_scale_factor); + S32 g = ll_pos_round(color.mV[1] * color_scale_factor); if (g > MAX_COLOR) { g = MAX_COLOR; @@ -493,7 +494,7 @@ void LLColor4U::setVecScaleClamp(const LLColor4& color) } mV[1] = g; - S32 b = llround(color.mV[2] * color_scale_factor); + S32 b = ll_pos_round(color.mV[2] * color_scale_factor); if (b > MAX_COLOR) { b = MAX_COLOR; @@ -505,7 +506,7 @@ void LLColor4U::setVecScaleClamp(const LLColor4& color) mV[2] = b; // Alpha shouldn't be scaled, just clamped... - S32 a = llround(color.mV[3] * MAX_COLOR); + S32 a = ll_pos_round(color.mV[3] * MAX_COLOR); if (a > MAX_COLOR) { a = MAX_COLOR; @@ -527,7 +528,7 @@ void LLColor4U::setVecScaleClamp(const LLColor3& color) } const S32 MAX_COLOR = 255; - S32 r = llround(color.mV[0] * color_scale_factor); + S32 r = ll_pos_round(color.mV[0] * color_scale_factor); if (r > MAX_COLOR) { r = MAX_COLOR; @@ -539,7 +540,7 @@ void LLColor4U::setVecScaleClamp(const LLColor3& color) } mV[0] = r; - S32 g = llround(color.mV[1] * color_scale_factor); + S32 g = ll_pos_round(color.mV[1] * color_scale_factor); if (g > MAX_COLOR) { g = MAX_COLOR; @@ -551,7 +552,7 @@ void LLColor4U::setVecScaleClamp(const LLColor3& color) } mV[1] = g; - S32 b = llround(color.mV[2] * color_scale_factor); + S32 b = ll_pos_round(color.mV[2] * color_scale_factor); if (b > MAX_COLOR) { b = MAX_COLOR; diff --git a/indra/llmath/v4math.cpp b/indra/llmath/v4math.cpp index b938480dd9..e9cc326322 100644 --- a/indra/llmath/v4math.cpp +++ b/indra/llmath/v4math.cpp @@ -2,31 +2,25 @@ * @file v4math.cpp * @brief LLVector4 class implementation. * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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$ */ diff --git a/indra/llmath/v4math.h b/indra/llmath/v4math.h index 72a477ed20..7356368053 100644 --- a/indra/llmath/v4math.h +++ b/indra/llmath/v4math.h @@ -2,31 +2,25 @@ * @file v4math.h * @brief LLVector4 class header file. * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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$ */ @@ -36,6 +30,7 @@ #include "llerror.h" #include "llmath.h" #include "v3math.h" +#include "v2math.h" class LLMatrix3; class LLMatrix4; @@ -52,8 +47,11 @@ class LLVector4 LLVector4(); // Initializes LLVector4 to (0, 0, 0, 1) explicit LLVector4(const F32 *vec); // Initializes LLVector4 to (vec[0]. vec[1], vec[2], vec[3]) explicit LLVector4(const F64 *vec); // Initialized LLVector4 to ((F32) vec[0], (F32) vec[1], (F32) vec[3], (F32) vec[4]); + explicit LLVector4(const LLVector2 &vec); + explicit LLVector4(const LLVector2 &vec, F32 z, F32 w); explicit LLVector4(const LLVector3 &vec); // Initializes LLVector4 to (vec, 1) explicit LLVector4(const LLVector3 &vec, F32 w); // Initializes LLVector4 to (vec, w) + explicit LLVector4(const LLSD &sd); LLVector4(F32 x, F32 y, F32 z); // Initializes LLVector4 to (x. y, z, 1) LLVector4(F32 x, F32 y, F32 z, F32 w); @@ -67,6 +65,15 @@ class LLVector4 return ret; } + void setValue(const LLSD& sd) + { + mV[0] = sd[0].asReal(); + mV[1] = sd[1].asReal(); + mV[2] = sd[2].asReal(); + mV[3] = sd[3].asReal(); + } + + inline BOOL isFinite() const; // checks to see if all values of LLVector3 are finite inline void clear(); // Clears LLVector4 to (0, 0, 0, 1) @@ -130,6 +137,8 @@ class LLVector4 friend LLVector4 operator-(const LLVector4 &a); // Return vector -a }; +static_assert(std::is_trivially_copyable::value, "LLVector4 must be a trivially copyable type"); + // Non-member functions F32 angle_between(const LLVector4 &a, const LLVector4 &b); // Returns angle (radians) between a and b BOOL are_parallel(const LLVector4 &a, const LLVector4 &b, F32 epsilon=F_APPROXIMATELY_ZERO); // Returns TRUE if a and b are very close to parallel @@ -181,6 +190,22 @@ inline LLVector4::LLVector4(const F64 *vec) mV[VW] = (F32) vec[VW]; } +inline LLVector4::LLVector4(const LLVector2 &vec) +{ + mV[VX] = vec[VX]; + mV[VY] = vec[VY]; + mV[VZ] = 0.f; + mV[VW] = 0.f; +} + +inline LLVector4::LLVector4(const LLVector2 &vec, F32 z, F32 w) +{ + mV[VX] = vec[VX]; + mV[VY] = vec[VY]; + mV[VZ] = z; + mV[VW] = w; +} + inline LLVector4::LLVector4(const LLVector3 &vec) { mV[VX] = vec.mV[VX]; @@ -197,10 +222,15 @@ inline LLVector4::LLVector4(const LLVector3 &vec, F32 w) mV[VW] = w; } +inline LLVector4::LLVector4(const LLSD &sd) +{ + setValue(sd); +} + inline BOOL LLVector4::isFinite() const { - return (llfinite(mV[VX]) && llfinite(mV[VY]) && llfinite(mV[VZ]) && llfinite(mV[VW])); + return (std::isfinite(mV[VX]) && std::isfinite(mV[VY]) && std::isfinite(mV[VZ]) && std::isfinite(mV[VW])); } // Clear and Assignment Functions diff --git a/indra/llmath/xform.cpp b/indra/llmath/xform.cpp index 7a8b0cf6a3..e7a9c9bdfb 100644 --- a/indra/llmath/xform.cpp +++ b/indra/llmath/xform.cpp @@ -1,31 +1,25 @@ /** * @file xform.cpp * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -42,10 +36,10 @@ LLXform::~LLXform() { } -// Link optimization - don't inline these llwarns +// Link optimization - don't inline these LL_WARNS() void LLXform::warn(const char* const msg) { - llwarns << msg << llendl; + LL_WARNS() << msg << LL_ENDL; } LLXform* LLXform::getRoot() const @@ -96,30 +90,29 @@ void LLXformMatrix::updateMatrix(BOOL update_bounds) { update(); - mWorldMatrix.initAll(mScale, mWorldRotation, mWorldPosition); + LLMatrix4 world_matrix; + world_matrix.initAll(mScale, mWorldRotation, mWorldPosition); + mWorldMatrix.loadu(world_matrix); if (update_bounds && (mChanged & MOVED)) { - mMin.mV[0] = mMax.mV[0] = mWorldMatrix.mMatrix[3][0]; - mMin.mV[1] = mMax.mV[1] = mWorldMatrix.mMatrix[3][1]; - mMin.mV[2] = mMax.mV[2] = mWorldMatrix.mMatrix[3][2]; - - F32 f0 = (fabs(mWorldMatrix.mMatrix[0][0])+fabs(mWorldMatrix.mMatrix[1][0])+fabs(mWorldMatrix.mMatrix[2][0])) * 0.5f; - F32 f1 = (fabs(mWorldMatrix.mMatrix[0][1])+fabs(mWorldMatrix.mMatrix[1][1])+fabs(mWorldMatrix.mMatrix[2][1])) * 0.5f; - F32 f2 = (fabs(mWorldMatrix.mMatrix[0][2])+fabs(mWorldMatrix.mMatrix[1][2])+fabs(mWorldMatrix.mMatrix[2][2])) * 0.5f; - - mMin.mV[0] -= f0; - mMin.mV[1] -= f1; - mMin.mV[2] -= f2; - - mMax.mV[0] += f0; - mMax.mV[1] += f1; - mMax.mV[2] += f2; + mMax = mMin = mWorldMatrix.getRow<3>(); + + LLVector4a total_sum,sum1,sum2; + total_sum.setAbs(mWorldMatrix.getRow<0>()); + sum1.setAbs(mWorldMatrix.getRow<1>()); + sum2.setAbs(mWorldMatrix.getRow<2>()); + sum1.add(sum2); + total_sum.add(sum1); + total_sum.mul(.5f); + + mMax.add(total_sum); + mMin.sub(total_sum); } } void LLXformMatrix::getMinMax(LLVector3& min, LLVector3& max) const { - min = mMin; - max = mMax; + min.set(mMin.getF32ptr()); + max.set(mMax.getF32ptr()); } diff --git a/indra/llmath/xform.h b/indra/llmath/xform.h index 299202d712..b07988e1b1 100644 --- a/indra/llmath/xform.h +++ b/indra/llmath/xform.h @@ -28,6 +28,7 @@ #include "v3math.h" #include "m4math.h" +#include "llmatrix4a.h" #include "llquaternion.h" const F32 MAX_OBJECT_Z = 4096.f; // should match REGION_HEIGHT_METERS, Pre-havok4: 768.f @@ -103,9 +104,9 @@ class LLXform inline void setRotation(const F32 x, const F32 y, const F32 z, const F32 s); // Above functions must be inline for speed, but also - // need to emit warnings. llwarns causes inline LLError::CallSite + // need to emit warnings. LL_WARNS() causes inline LLError::CallSite // static objects that make more work for the linker. - // Avoid inline llwarns by calling this function. + // Avoid inline LL_WARNS() by calling this function. void warn(const char* const msg); void setChanged(const U32 bits) { mChanged |= bits; } @@ -130,20 +131,21 @@ class LLXform const LLVector3& getWorldPosition() const { return mWorldPosition; } }; +LL_ALIGN_PREFIX(16) class LLXformMatrix : public LLXform { public: LLXformMatrix() : LLXform() {}; virtual ~LLXformMatrix(); - const LLMatrix4& getWorldMatrix() const { return mWorldMatrix; } - void setWorldMatrix (const LLMatrix4& mat) { mWorldMatrix = mat; } + const LLMatrix4a& getWorldMatrix() const { return mWorldMatrix; } + void setWorldMatrix (const LLMatrix4a& mat) { mWorldMatrix = mat; } void init() { mWorldMatrix.setIdentity(); - mMin.clearVec(); - mMax.clearVec(); + mMin.clear(); + mMax.clear(); LLXform::init(); } @@ -153,11 +155,11 @@ class LLXformMatrix : public LLXform void getMinMax(LLVector3& min,LLVector3& max) const; protected: - LLMatrix4 mWorldMatrix; - LLVector3 mMin; - LLVector3 mMax; + LL_ALIGN_16(LLMatrix4a mWorldMatrix); + LL_ALIGN_16(LLVector4a mMin); + LL_ALIGN_16(LLVector4a mMax); -}; +} LL_ALIGN_POSTFIX(16); BOOL LLXform::setParent(LLXform* parent) { @@ -198,7 +200,7 @@ void LLXform::setPosition(const LLVector3& pos) void LLXform::setPosition(const F32 x, const F32 y, const F32 z) { setChanged(TRANSLATED); - if (llfinite(x) && llfinite(y) && llfinite(z)) + if (std::isfinite(x) && std::isfinite(y) && std::isfinite(z)) mPosition.setVec(x,y,z); else { @@ -210,7 +212,7 @@ void LLXform::setPosition(const F32 x, const F32 y, const F32 z) void LLXform::setPositionX(const F32 x) { setChanged(TRANSLATED); - if (llfinite(x)) + if (std::isfinite(x)) mPosition.mV[VX] = x; else { @@ -222,7 +224,7 @@ void LLXform::setPositionX(const F32 x) void LLXform::setPositionY(const F32 y) { setChanged(TRANSLATED); - if (llfinite(y)) + if (std::isfinite(y)) mPosition.mV[VY] = y; else { @@ -234,7 +236,7 @@ void LLXform::setPositionY(const F32 y) void LLXform::setPositionZ(const F32 z) { setChanged(TRANSLATED); - if (llfinite(z)) + if (std::isfinite(z)) mPosition.mV[VZ] = z; else { @@ -266,7 +268,7 @@ void LLXform::setScale(const LLVector3& scale) void LLXform::setScale(const F32 x, const F32 y, const F32 z) { setChanged(SCALED); - if (llfinite(x) && llfinite(y) && llfinite(z)) + if (std::isfinite(x) && std::isfinite(y) && std::isfinite(z)) mScale.setVec(x,y,z); else { @@ -288,7 +290,7 @@ void LLXform::setRotation(const LLQuaternion& rot) void LLXform::setRotation(const F32 x, const F32 y, const F32 z) { setChanged(ROTATED); - if (llfinite(x) && llfinite(y) && llfinite(z)) + if (std::isfinite(x) && std::isfinite(y) && std::isfinite(z)) { mRotation.setQuat(x,y,z); } @@ -301,7 +303,7 @@ void LLXform::setRotation(const F32 x, const F32 y, const F32 z) void LLXform::setRotation(const F32 x, const F32 y, const F32 z, const F32 s) { setChanged(ROTATED); - if (llfinite(x) && llfinite(y) && llfinite(z) && llfinite(s)) + if (std::isfinite(x) && std::isfinite(y) && std::isfinite(z) && std::isfinite(s)) { mRotation.mQ[VX] = x; mRotation.mQ[VY] = y; mRotation.mQ[VZ] = z; mRotation.mQ[VS] = s; } diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt index 2f9963706d..44743b37ff 100644 --- a/indra/llmessage/CMakeLists.txt +++ b/indra/llmessage/CMakeLists.txt @@ -35,8 +35,8 @@ set(llmessage_SOURCE_FILES llares.cpp llareslistener.cpp llassetstorage.cpp + llavatarname.cpp llavatarnamecache.cpp - llblowfishcipher.cpp llbuffer.cpp llbufferstream.cpp llcachename.cpp @@ -45,6 +45,7 @@ set(llmessage_SOURCE_FILES llclassifiedflags.cpp lldatapacker.cpp lldispatcher.cpp + llexperiencecache.cpp llfiltersd2xmlrpc.cpp llhost.cpp llhttpclient.cpp @@ -56,7 +57,6 @@ set(llmessage_SOURCE_FILES lliopipe.cpp lliosocket.cpp llioutil.cpp - llmail.cpp llmessagebuilder.cpp llmessageconfig.cpp llmessagelog.cpp @@ -64,7 +64,6 @@ set(llmessage_SOURCE_FILES llmessagetemplate.cpp llmessagetemplateparser.cpp llmessagethrottle.cpp - llmime.cpp llnamevalue.cpp llnullcipher.cpp llpacketack.cpp @@ -125,8 +124,8 @@ set(llmessage_HEADER_FILES llares.h llareslistener.h llassetstorage.h + llavatarname.h llavatarnamecache.h - llblowfishcipher.h llbuffer.h llbufferstream.h llcachename.h @@ -134,11 +133,13 @@ set(llmessage_HEADER_FILES llcipher.h llcircuit.h llclassifiedflags.h + llcororesponder.h llcurl.h lldatapacker.h lldbstrings.h lldispatcher.h lleventflags.h + llexperiencecache.h llfiltersd2xmlrpc.h llfollowcamparams.h llhost.h @@ -154,7 +155,6 @@ set(llmessage_HEADER_FILES lliosocket.h llioutil.h llloginflags.h - llmail.h llmessagebuilder.h llmessageconfig.h llmessagelog.h @@ -162,7 +162,6 @@ set(llmessage_HEADER_FILES llmessagetemplate.h llmessagetemplateparser.h llmessagethrottle.h - llmime.h llmsgvariabletype.h llnamevalue.h llnullcipher.h @@ -218,15 +217,19 @@ set_source_files_properties(${llmessage_HEADER_FILES} list(APPEND llmessage_SOURCE_FILES ${llmessage_HEADER_FILES}) add_library (llmessage ${llmessage_SOURCE_FILES}) -add_dependencies(llmessage prepare) + target_link_libraries( llmessage + PUBLIC + llcommon ${CURL_LIBRARIES} ${CARES_LIBRARIES} + ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${CRYPTO_LIBRARIES} ${XMLRPCEPI_LIBRARIES} - ) + ${PTHREAD_LIBRARY} +) # tests if (LL_TESTS) @@ -236,7 +239,6 @@ if (LL_TESTS) include(Tut) SET(llmessage_TEST_SOURCE_FILES - llmime.cpp llnamevalue.cpp lltrustedmessageservice.cpp lltemplatemessagedispatcher.cpp diff --git a/indra/llmessage/aicurl.cpp b/indra/llmessage/aicurl.cpp index 04b9c5a16b..c969097727 100644 --- a/indra/llmessage/aicurl.cpp +++ b/indra/llmessage/aicurl.cpp @@ -52,7 +52,6 @@ #include "llsdserialize.h" #include "aithreadsafe.h" #include "llqueuedthread.h" -#include "lltimer.h" // ms_sleep #include "llproxy.h" #include "llhttpstatuscodes.h" #include "aihttpheaders.h" @@ -196,10 +195,10 @@ ssl_dyn_create_function_type old_ssl_dyn_create_function; ssl_dyn_destroy_function_type old_ssl_dyn_destroy_function; ssl_dyn_lock_function_type old_ssl_dyn_lock_function; -#if LL_WINDOWS +#if LL_WINDOWS && !HAVE_CRYPTO_THREADID static unsigned long __cdecl apr_os_thread_current_wrapper() { - return (unsigned long)apr_os_thread_current(); + return (unsigned long)(HANDLE)apr_os_thread_current(); } #endif @@ -220,9 +219,9 @@ void ssl_init(void) if (linked_openSSL_major != compiled_openSSL_major || (linked_openSSL_major == 0 && linked_openSSL_minor != compiled_openSSL_minor)) { - llerrs << "The viewer was compiled against " << OPENSSL_VERSION_TEXT << + LL_ERRS() << "The viewer was compiled against " << OPENSSL_VERSION_TEXT << " but linked against " << SSLeay_version(SSLEAY_VERSION) << - ". Those versions are not compatible." << llendl; + ". Those versions are not compatible." << LL_ENDL; } // Static locks vector. ssl_rwlock_array = new AIRWLock[CRYPTO_num_locks()]; @@ -252,8 +251,8 @@ void ssl_init(void) CRYPTO_set_dynlock_lock_callback(&ssl_dyn_lock_function); CRYPTO_set_dynlock_destroy_callback(&ssl_dyn_destroy_function); need_renegotiation_hack = (0x10001000UL <= ssleay); - llinfos << "Successful initialization of " << - SSLeay_version(SSLEAY_VERSION) << " (0x" << std::hex << SSLeay() << std::dec << ")." << llendl; + LL_INFOS() << "Successful initialization of " << + SSLeay_version(SSLEAY_VERSION) << " (0x" << std::hex << SSLeay() << std::dec << ")." << LL_ENDL; } // Cleanup OpenSSL library thread-safety. @@ -330,7 +329,7 @@ void initCurl(void) CURLcode res = curl_global_init(CURL_GLOBAL_ALL); if (res != CURLE_OK) { - llerrs << "curl_global_init(CURL_GLOBAL_ALL) failed." << llendl; + LL_ERRS() << "curl_global_init(CURL_GLOBAL_ALL) failed." << LL_ENDL; } // Print version and do some feature sanity checks. @@ -340,26 +339,26 @@ void initCurl(void) llassert_always(version_info->age >= 0); if (version_info->age < 1) { - llwarns << "libcurl's age is 0; no ares support." << llendl; + LL_WARNS() << "libcurl's age is 0; no ares support." << LL_ENDL; } llassert_always((version_info->features & CURL_VERSION_SSL)); // SSL support, added in libcurl 7.10. if (!(version_info->features & CURL_VERSION_ASYNCHDNS)) // Asynchronous name lookups (added in libcurl 7.10.7). { - llwarns << "libcurl was not compiled with support for asynchronous name lookups!" << llendl; + LL_WARNS() << "libcurl was not compiled with support for asynchronous name lookups!" << LL_ENDL; } if (!version_info->ssl_version) { - llerrs << "This libcurl has no SSL support!" << llendl; + LL_ERRS() << "This libcurl has no SSL support!" << LL_ENDL; } - llinfos << "Successful initialization of libcurl " << + LL_INFOS() << "Successful initialization of libcurl " << version_info->version << " (0x" << std::hex << version_info->version_num << std::dec << "), (" << version_info->ssl_version; if (version_info->libz_version) { - llcont << ", libz/" << version_info->libz_version; + LL_CONT << ", libz/" << version_info->libz_version; } - llcont << ")." << llendl; + LL_CONT << ")." << LL_ENDL; // Detect SSL library used. gSSLlib = ssl_unknown; @@ -367,7 +366,7 @@ void initCurl(void) if (ssl_version.find("OpenSSL") != std::string::npos) gSSLlib = ssl_openssl; // See http://www.openssl.org/docs/crypto/threads.html#DESCRIPTION else if (ssl_version.find("GnuTLS") != std::string::npos) - gSSLlib = ssl_gnutls; // See http://www.gnu.org/software/gnutls/manual/html_node/Thread-safety.html + gSSLlib = ssl_gnutls; // See http://www.gnutls.org/manual/html_node/Thread-safety.html#Thread-safety else if (ssl_version.find("NSS") != std::string::npos) gSSLlib = ssl_nss; // Supposedly thread-safe without any requirements. @@ -377,21 +376,21 @@ void initCurl(void) { case ssl_unknown: { - llerrs << "Unknown SSL library \"" << version_info->ssl_version << "\", required actions for thread-safe handling are unknown! Bailing out." << llendl; + LL_ERRS() << "Unknown SSL library \"" << version_info->ssl_version << "\", required actions for thread-safe handling are unknown! Bailing out." << LL_ENDL; } case ssl_openssl: { #ifndef OPENSSL_THREADS - llerrs << "OpenSSL was not configured with thread support! Bailing out." << llendl; + LL_ERRS() << "OpenSSL was not configured with thread support! Bailing out." << LL_ENDL; #endif ssl_init(); } case ssl_gnutls: { - // I don't think we ever get here, do we? --Aleric - llassert_always(gSSLlib != ssl_gnutls); - // If we do, then didn't curl_global_init already call gnutls_global_init? - // It seems there is nothing to do for us here. + // Prior to GnuTLS version 3.3.0 mutex locks are setup by calling gnutls_global_init, + // however curl_global_init already called that for us. + // There is nothing to do for us here. + break; } case ssl_nss: { @@ -403,7 +402,7 @@ void initCurl(void) gSetoptParamsNeedDup = (version_info->version_num < encoded_version(7, 17, 0)); if (gSetoptParamsNeedDup) { - llwarns << "Your libcurl version is too old." << llendl; + LL_WARNS() << "Your libcurl version is too old." << LL_ENDL; } llassert_always(!gSetoptParamsNeedDup); // Might add support later. } @@ -428,7 +427,7 @@ void cleanupCurl(void) stopCurlThread(); if (CurlMultiHandle::getTotalMultiHandles() != 0) - llwarns << "Not all CurlMultiHandle objects were destroyed!" << llendl; + LL_WARNS() << "Not all CurlMultiHandle objects were destroyed!" << LL_ENDL; gMainThreadEngine.flush(); // Not really related to curl, but why not. gStateMachineThreadEngine.flush(); clearCommandQueue(); @@ -471,20 +470,20 @@ U32 getNumHTTPRunning(void) void Stats::print(void) { int const easy_handles = easy_init_calls - easy_init_errors - easy_cleanup_calls; - llinfos_nf << "============ CURL STATS ============" << llendl; - llinfos_nf << " Curl multi errors/calls : " << std::dec << multi_errors << "/" << multi_calls << llendl; - llinfos_nf << " Curl easy errors/calls : " << std::dec << easy_errors << "/" << easy_calls << llendl; - llinfos_nf << " curl_easy_init() errors/calls : " << std::dec << easy_init_errors << "/" << easy_init_calls << llendl; - llinfos_nf << " Current number of curl easy handles: " << std::dec << easy_handles << llendl; + LL_INFOS_NF() << "============ CURL STATS ============" << LL_ENDL; + LL_INFOS_NF() << " Curl multi errors/calls : " << std::dec << multi_errors << "/" << multi_calls << LL_ENDL; + LL_INFOS_NF() << " Curl easy errors/calls : " << std::dec << easy_errors << "/" << easy_calls << LL_ENDL; + LL_INFOS_NF() << " curl_easy_init() errors/calls : " << std::dec << easy_init_errors << "/" << easy_init_calls << LL_ENDL; + LL_INFOS_NF() << " Current number of curl easy handles: " << std::dec << easy_handles << LL_ENDL; #ifdef DEBUG_CURLIO - llinfos_nf << " Current number of BufferedCurlEasyRequest objects: " << BufferedCurlEasyRequest_count << llendl; - llinfos_nf << " Current number of ThreadSafeBufferedCurlEasyRequest objects: " << ThreadSafeBufferedCurlEasyRequest_count << llendl; - llinfos_nf << " Current number of AICurlEasyRequest objects: " << AICurlEasyRequest_count << llendl; - llinfos_nf << " Current number of AICurlEasyRequestStateMachine objects: " << AICurlEasyRequestStateMachine_count << llendl; + LL_INFOS_NF() << " Current number of BufferedCurlEasyRequest objects: " << BufferedCurlEasyRequest_count << LL_ENDL; + LL_INFOS_NF() << " Current number of ThreadSafeBufferedCurlEasyRequest objects: " << ThreadSafeBufferedCurlEasyRequest_count << LL_ENDL; + LL_INFOS_NF() << " Current number of AICurlEasyRequest objects: " << AICurlEasyRequest_count << LL_ENDL; + LL_INFOS_NF() << " Current number of AICurlEasyRequestStateMachine objects: " << AICurlEasyRequestStateMachine_count << LL_ENDL; #endif - llinfos_nf << " Current number of Responders: " << ResponderBase_count << llendl; - llinfos_nf << " Received HTTP bodies LLSD / LLSD parse errors / non-LLSD: " << llsd_body_count << "/" << llsd_body_parse_error << "/" << raw_body_count << llendl; - llinfos_nf << " Received HTTP status codes: status (count) [...]: "; + LL_INFOS_NF() << " Current number of Responders: " << ResponderBase_count << LL_ENDL; + LL_INFOS_NF() << " Received HTTP bodies LLSD / LLSD parse errors / non-LLSD: " << llsd_body_count << "/" << llsd_body_parse_error << "/" << raw_body_count << LL_ENDL; + LL_INFOS_NF() << " Received HTTP status codes: status (count) [...]: "; bool first = true; for (U32 index = 0; index < 100; ++index) { @@ -492,17 +491,17 @@ void Stats::print(void) { if (!first) { - llcont << ", "; + LL_CONT << ", "; } else { first = false; } - llcont << index2status(index) << " (" << status_count[index] << ')'; + LL_CONT << index2status(index) << " (" << status_count[index] << ')'; } } - llcont << llendl; - llinfos_nf << "========= END OF CURL STATS =========" << llendl; + LL_CONT << LL_ENDL; + LL_INFOS_NF() << "========= END OF CURL STATS =========" << LL_ENDL; // Leak tests. // There is one easy handle per CurlEasyHandle, and BufferedCurlEasyRequest is derived from that. // It is not allowed to create CurlEasyHandle (or CurlEasyRequest) directly, only by creating a BufferedCurlEasyRequest, @@ -528,7 +527,7 @@ namespace AICurlPrivate { using AICurlInterface::Stats; -#if defined(CWDEBUG) || defined(DEBUG_CURLIO) +#ifdef CWDEBUG // CURLOPT_DEBUGFUNCTION function. extern int debug_callback(CURL*, curl_infotype infotype, char* buf, size_t size, void* user_ptr); #endif @@ -537,8 +536,8 @@ extern int debug_callback(CURL*, curl_infotype infotype, char* buf, size_t size, void handle_multi_error(CURLMcode code) { Stats::multi_errors++; - llinfos << "curl multi error detected: " << curl_multi_strerror(code) << - "; (errors/calls = " << Stats::multi_errors << "/" << Stats::multi_calls << ")" << llendl; + LL_INFOS() << "curl multi error detected: " << curl_multi_strerror(code) << + "; (errors/calls = " << Stats::multi_errors << "/" << Stats::multi_calls << ")" << LL_ENDL; } //============================================================================= @@ -553,13 +552,13 @@ void handle_multi_error(CURLMcode code) void CurlEasyHandle::handle_easy_error(CURLcode code) { char* error_buffer = LLThreadLocalData::tldata().mCurlErrorBuffer; - llinfos << "curl easy error detected: " << curl_easy_strerror(code); + LL_INFOS() << "curl easy error detected: " << curl_easy_strerror(code); if (error_buffer && *error_buffer != '\0') { - llcont << ": " << error_buffer; + LL_CONT << ": " << error_buffer; } Stats::easy_errors++; - llcont << "; (errors/calls = " << Stats::easy_errors << "/" << Stats::easy_calls << ")" << llendl; + LL_CONT << "; (errors/calls = " << Stats::easy_errors << "/" << Stats::easy_calls << ")" << LL_ENDL; } // Throws AICurlNoEasyHandle. @@ -638,7 +637,7 @@ void CurlEasyHandle::setErrorBuffer(void) const CURLcode res = curl_easy_setopt(mEasyHandle, CURLOPT_ERRORBUFFER, error_buffer); if (res != CURLE_OK) { - llwarns << "curl_easy_setopt(" << (void*)mEasyHandle << "CURLOPT_ERRORBUFFER, " << (void*)error_buffer << ") failed with error " << res << llendl; + LL_WARNS() << "curl_easy_setopt(" << (void*)mEasyHandle << "CURLOPT_ERRORBUFFER, " << (void*)error_buffer << ") failed with error " << res << LL_ENDL; mErrorBuffer = NULL; } } @@ -766,8 +765,8 @@ DEFINE_FUNCTION_SETOPT4(curl_write_callback, CURLOPT_HEADERFUNCTION, CURLOPT_WRI //DEFINE_FUNCTION_SETOPT1(curl_read_callback, CURLOPT_READFUNCTION) DEFINE_FUNCTION_SETOPT1(curl_ssl_ctx_callback, CURLOPT_SSL_CTX_FUNCTION) DEFINE_FUNCTION_SETOPT3(curl_conv_callback, CURLOPT_CONV_FROM_NETWORK_FUNCTION, CURLOPT_CONV_TO_NETWORK_FUNCTION, CURLOPT_CONV_FROM_UTF8_FUNCTION) -#if 0 // Not used by the viewer. DEFINE_FUNCTION_SETOPT1(curl_progress_callback, CURLOPT_PROGRESSFUNCTION) +#if 0 // Not used by the viewer. DEFINE_FUNCTION_SETOPT1(curl_seek_callback, CURLOPT_SEEKFUNCTION) DEFINE_FUNCTION_SETOPT1(curl_ioctl_callback, CURLOPT_IOCTLFUNCTION) DEFINE_FUNCTION_SETOPT1(curl_sockopt_callback, CURLOPT_SOCKOPTFUNCTION) @@ -804,6 +803,23 @@ void CurlEasyRequest::setPut(U32 size, bool keepalive) setopt(CURLOPT_INFILESIZE, size); } +void CurlEasyRequest::setPatch(U32 size, bool keepalive) +{ + DoutCurl("PATCH size is " << size << " bytes."); + mContentLength = size; + + // The server never replies with 100-continue, so suppress the "Expect: 100-continue" header that libcurl adds by default. + addHeader("Expect:"); + if (size > 0 && keepalive) + { + addHeader("Connection: keep-alive"); + addHeader("Keep-alive: 300"); + } + setopt(CURLOPT_UPLOAD, 1); + setopt(CURLOPT_INFILESIZE, size);\ + setopt(CURLOPT_CUSTOMREQUEST, "PATCH"); +} + void CurlEasyRequest::setPost(AIPostFieldPtr const& postdata, U32 size, bool keepalive) { llassert_always(postdata->data()); @@ -902,38 +918,62 @@ void CurlEasyRequest::setSSLCtxCallback(curl_ssl_ctx_callback callback, void* us setopt(CURLOPT_SSL_CTX_DATA, this); } -#define llmaybewarns lllog(LLApp::isExiting() ? LLError::LEVEL_INFO : LLError::LEVEL_WARN, NULL, NULL, false, true) +//static +int CurlEasyRequest::progressCallback(void* userdata, double dltotal, double dlnow, double ultotal, double ulnow) +{ + CurlEasyRequest* self = static_cast(userdata); + ThreadSafeBufferedCurlEasyRequest* lockobj = self->get_lockobj(); + AICurlEasyRequest_wat lock_self(*lockobj); + return self->mProgressCallback(self->mProgressCallbackUserData, dltotal, dlnow, ultotal, ulnow); +} + +void CurlEasyRequest::setProgressCallback(curl_progress_callback callback, void* userdata) +{ + mProgressCallback = callback; + mProgressCallbackUserData = userdata; + setopt(CURLOPT_PROGRESSFUNCTION, callback ? &CurlEasyRequest::progressCallback : NULL); + setopt(CURLOPT_PROGRESSDATA, userdata ? this : NULL); +} + +#define llmaybewarns lllog(LLApp::isExiting() ? LLError::LEVEL_INFO : LLError::LEVEL_WARN, false, true) static size_t noHeaderCallback(char* ptr, size_t size, size_t nmemb, void* userdata) { - llmaybewarns << "Calling noHeaderCallback(); curl session aborted." << llendl; + llmaybewarns << "Calling noHeaderCallback(); curl session aborted." << LL_ENDL; return 0; // Cause a CURLE_WRITE_ERROR } static size_t noWriteCallback(char* ptr, size_t size, size_t nmemb, void* userdata) { - llmaybewarns << "Calling noWriteCallback(); curl session aborted." << llendl; + llmaybewarns << "Calling noWriteCallback(); curl session aborted." << LL_ENDL; return 0; // Cause a CURLE_WRITE_ERROR } static size_t noReadCallback(char* ptr, size_t size, size_t nmemb, void* userdata) { - llmaybewarns << "Calling noReadCallback(); curl session aborted." << llendl; + llmaybewarns << "Calling noReadCallback(); curl session aborted." << LL_ENDL; return CURL_READFUNC_ABORT; // Cause a CURLE_ABORTED_BY_CALLBACK } static CURLcode noSSLCtxCallback(CURL* curl, void* sslctx, void* parm) { - llmaybewarns << "Calling noSSLCtxCallback(); curl session aborted." << llendl; + llmaybewarns << "Calling noSSLCtxCallback(); curl session aborted." << LL_ENDL; return CURLE_ABORTED_BY_CALLBACK; } +static int noProgressCallback(void* userdata, double, double, double, double) +{ + llmaybewarns << "Calling noProgressCallback(); curl session aborted." << LL_ENDL; + return -1; // Cause a CURLE_ABORTED_BY_CALLBACK +} + void CurlEasyRequest::revokeCallbacks(void) { if (mHeaderCallback == &noHeaderCallback && mWriteCallback == &noWriteCallback && mReadCallback == &noReadCallback && - mSSLCtxCallback == &noSSLCtxCallback) + mSSLCtxCallback == &noSSLCtxCallback && + mProgressCallback == &noProgressCallback) { // Already revoked. return; @@ -942,14 +982,16 @@ void CurlEasyRequest::revokeCallbacks(void) mWriteCallback = &noWriteCallback; mReadCallback = &noReadCallback; mSSLCtxCallback = &noSSLCtxCallback; + mProgressCallback = &noProgressCallback; if (active() && !no_warning()) { - llwarns << "Revoking callbacks on a still active CurlEasyRequest object!" << llendl; + LL_WARNS() << "Revoking callbacks on a still active CurlEasyRequest object!" << LL_ENDL; } curl_easy_setopt(getEasyHandle(), CURLOPT_HEADERFUNCTION, &noHeaderCallback); curl_easy_setopt(getEasyHandle(), CURLOPT_WRITEHEADER, &noWriteCallback); curl_easy_setopt(getEasyHandle(), CURLOPT_READFUNCTION, &noReadCallback); curl_easy_setopt(getEasyHandle(), CURLOPT_SSL_CTX_FUNCTION, &noSSLCtxCallback); + curl_easy_setopt(getEasyHandle(), CURLOPT_PROGRESSFUNCTION, &noProgressCallback); } CurlEasyRequest::~CurlEasyRequest() @@ -1035,7 +1077,7 @@ CURLcode CurlEasyRequest::curlCtxCallback(CURL* curl, void* sslctx, void* parm) // Also turn off SSL v2, which is highly broken and strongly discouraged[1]. // [1] http://www.openssl.org/docs/ssl/SSL_CTX_set_options.html#SECURE_RENEGOTIATION long options = SSL_OP_NO_SSLv2; -#ifdef SSL_OP_NO_TLSv1_1 // Only defined for openssl version 1.0.1 and up. +/*#ifdef SSL_OP_NO_TLSv1_1 // Only defined for openssl version 1.0.1 and up. if (need_renegotiation_hack) { // This option disables openssl to use TLS version 1.1. @@ -1053,7 +1095,7 @@ CURLcode CurlEasyRequest::curlCtxCallback(CURL* curl, void* sslctx, void* parm) // This is expected when you compile against the headers of a version < 1.0.1 and then link at runtime with version >= 1.0.1. // Don't do that. llassert_always(!need_renegotiation_hack); -#endif +#endif*/ SSL_CTX_set_options(ctx, options); return CURLE_OK; } @@ -1062,7 +1104,10 @@ void CurlEasyRequest::applyDefaultOptions(void) { CertificateAuthority_rat CertificateAuthority_r(gCertificateAuthority); setoptString(CURLOPT_CAINFO, CertificateAuthority_r->file); - setSSLCtxCallback(&curlCtxCallback, NULL); + if (gSSLlib == ssl_openssl) + { + setSSLCtxCallback(&curlCtxCallback, NULL); + } setopt(CURLOPT_NOSIGNAL, 1); // Cache DNS look ups an hour. If we set it smaller we risk frequent connect timeouts in cases where DNS look ups are slow. setopt(CURLOPT_DNS_CACHE_TIMEOUT, 3600); @@ -1078,6 +1123,8 @@ void CurlEasyRequest::applyDefaultOptions(void) setopt(CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); // Disable SSL/TLS session caching; some servers (aka id.secondlife.com) refuse connections when session ids are enabled. setopt(CURLOPT_SSL_SESSIONID_CACHE, 0); + // Call the progress callback funtion. + setopt(CURLOPT_NOPROGRESS, 0); // Set the CURL options for either SOCKS or HTTP proxy. applyProxySettings(); // Cause libcurl to print all it's I/O traffic on the debug channel. @@ -1096,6 +1143,7 @@ void CurlEasyRequest::finalizeRequest(std::string const& url, AIHTTPTimeoutPolic DoutCurlEntering("CurlEasyRequest::finalizeRequest(\"" << url << "\", " << policy.name() << ", " << (void*)state_machine << ")"); llassert(!mTimeoutPolicy); // May only call finalizeRequest once! mResult = CURLE_FAILED_INIT; // General error code; the final result code is stored here by MultiHandle::check_msg_queue when msg is CURLMSG_DONE. + mIsHttps = strncmp(url.c_str(), "https:", 6) == 0; #ifdef SHOW_ASSERT // Do a sanity check on the headers. int content_type_count = 0; @@ -1108,7 +1156,7 @@ void CurlEasyRequest::finalizeRequest(std::string const& url, AIHTTPTimeoutPolic } if (content_type_count > 1) { - llwarns << "Requesting: \"" << url << "\": " << content_type_count << " Content-Type: headers!" << llendl; + LL_WARNS() << "Requesting: \"" << url << "\": " << content_type_count << " Content-Type: headers!" << LL_ENDL; } #endif setopt(CURLOPT_HTTPHEADER, mHeaders); @@ -1140,14 +1188,20 @@ void CurlEasyRequest::finalizeRequest(std::string const& url, AIHTTPTimeoutPolic // // get less connect time, while it still (also) has to wait for this DNS lookup. void CurlEasyRequest::set_timeout_opts(void) { - setopt(CURLOPT_CONNECTTIMEOUT, mTimeoutPolicy->getConnectTimeout(getLowercaseHostname())); + U16 connect_timeout = mTimeoutPolicy->getConnectTimeout(getLowercaseHostname()); + if (mIsHttps && connect_timeout < 30) + { + DoutCurl("Incrementing CURLOPT_CONNECTTIMEOUT of \"" << mTimeoutPolicy->name() << "\" from " << connect_timeout << " to 30 seconds."); + connect_timeout = 30; + } + setopt(CURLOPT_CONNECTTIMEOUT, connect_timeout); setopt(CURLOPT_TIMEOUT, mTimeoutPolicy->getCurlTransaction()); } void CurlEasyRequest::create_timeout_object(void) { ThreadSafeBufferedCurlEasyRequest* lockobj = NULL; -#if defined(CWDEBUG) || defined(DEBUG_CURLIO) +#ifdef CWDEBUG lockobj = static_cast(this)->get_lockobj(); #endif mTimeout = new curlthread::HTTPTimeout(mTimeoutPolicy, lockobj); @@ -1262,10 +1316,11 @@ std::string CurlEasyRequest::getLowercaseHostname(void) const //----------------------------------------------------------------------------- // BufferedCurlEasyRequest -static int const HTTP_REDIRECTS_DEFAULT = 10; +static int const HTTP_REDIRECTS_DEFAULT = 16; // Singu note: I've seen up to 10 redirects, so setting the limit to 10 is cutting it. + // This limit is only here to avoid a redirect loop (infinite redirections). LLChannelDescriptors const BufferedCurlEasyRequest::sChannels; -LLMutex BufferedCurlEasyRequest::sResponderCallbackMutex; +LLGlobalMutex BufferedCurlEasyRequest::sResponderCallbackMutex; bool BufferedCurlEasyRequest::sShuttingDown = false; AIAverage BufferedCurlEasyRequest::sHTTPBandwidth(25); @@ -1275,7 +1330,7 @@ BufferedCurlEasyRequest::BufferedCurlEasyRequest() : AICurlInterface::Stats::BufferedCurlEasyRequest_count++; } -#define llmaybeerrs lllog(LLApp::isRunning() ? LLError::LEVEL_ERROR : LLError::LEVEL_WARN, NULL, NULL, false, true) +#define llmaybeerrs lllog(LLApp::isRunning() ? LLError::LEVEL_ERROR : LLError::LEVEL_WARN, false, true) BufferedCurlEasyRequest::~BufferedCurlEasyRequest() { @@ -1286,9 +1341,10 @@ BufferedCurlEasyRequest::~BufferedCurlEasyRequest() // If the responder is still alive, then that means that BufferedCurlEasyRequest::processOutput was // never called, which means that the removed_from_multi_handle event never happened. // This is definitely an internal error as it can only happen when libcurl is too slow, - // in which case AICurlEasyRequestStateMachine::mTimer times out, but that already - // calls BufferedCurlEasyRequest::timed_out(). - llmaybeerrs << "Calling ~BufferedCurlEasyRequest() with active responder!" << llendl; + // in which case AICurlEasyRequestStateMachine::mTimer times out, a socket goes bad, or + // the state machine is aborted, but those already call BufferedCurlEasyRequest::aborted() + // which sets mResponder to NULL. + llmaybeerrs << "Calling ~BufferedCurlEasyRequest() with active responder!" << LL_ENDL; if (!LLApp::isRunning()) { // It might happen if some BufferedCurlEasyRequest escaped clean up somehow :/ @@ -1297,33 +1353,26 @@ BufferedCurlEasyRequest::~BufferedCurlEasyRequest() else { // User chose to continue. - timed_out(); + aborted(HTTP_INTERNAL_ERROR_OTHER, "BufferedCurlEasyRequest destructed with active responder"); } } --AICurlInterface::Stats::BufferedCurlEasyRequest_count; } -void BufferedCurlEasyRequest::timed_out(void) -{ - mResponder->finished(CURLE_OK, HTTP_INTERNAL_ERROR_CURL_LOCKUP, "Request timeout, aborted.", sChannels, mOutput); - if (mResponder->needsHeaders()) - { - send_buffer_events_to(NULL); // Revoke buffer events: we send them to the responder. - } - mResponder = NULL; -} - -void BufferedCurlEasyRequest::bad_socket(void) +void BufferedCurlEasyRequest::aborted(U32 http_status, std::string const& reason) { - mResponder->finished(CURLE_OK, HTTP_INTERNAL_ERROR_CURL_BADSOCKET, "File descriptor went bad! Aborted.", sChannels, mOutput); - if (mResponder->needsHeaders()) + if (mResponder) { - send_buffer_events_to(NULL); // Revoke buffer events: we send them to the responder. + mResponder->finished(CURLE_OK, http_status, reason, sChannels, mOutput); + if (mResponder->needsHeaders()) + { + send_buffer_events_to(NULL); // Revoke buffer events: we send them to the responder. + } + mResponder = NULL; } - mResponder = NULL; } -#if defined(CWDEBUG) || defined(DEBUG_CURLIO) +#ifdef CWDEBUG static AIPerServicePtr sConnections[64]; void BufferedCurlEasyRequest::connection_established(int connectionnr) @@ -1382,7 +1431,7 @@ void BufferedCurlEasyRequest::print_diagnostics(CURLcode code) } else { - llwarns << "Curl returned error code " << code << " (" << curl_easy_strerror(code) << ") for HTTP request to \"" << eff_url << "\"." << llendl; + LL_WARNS() << "Curl returned error code " << code << " (" << curl_easy_strerror(code) << ") for HTTP request to \"" << eff_url << "\"." << LL_ENDL; } } @@ -1409,10 +1458,11 @@ void BufferedCurlEasyRequest::prepRequest(AICurlEasyRequest_wat& curl_easy_reque curl_easy_request_w->setWriteCallback(&curlWriteCallback, lockobj); curl_easy_request_w->setReadCallback(&curlReadCallback, lockobj); curl_easy_request_w->setHeaderCallback(&curlHeaderCallback, lockobj); + curl_easy_request_w->setProgressCallback(&curlProgressCallback, lockobj); bool allow_cookies = headers.hasHeader("Cookie"); - // Allow up to ten redirects. - if (responder->followRedir()) + // Allow up to sixteen redirects. + if (!responder->pass_redirect_status()) { curl_easy_request_w->setopt(CURLOPT_FOLLOWLOCATION, 1); curl_easy_request_w->setopt(CURLOPT_MAXREDIRS, HTTP_REDIRECTS_DEFAULT); @@ -1436,6 +1486,7 @@ void BufferedCurlEasyRequest::prepRequest(AICurlEasyRequest_wat& curl_easy_reque mResponder = responder; // Cache capability type, because it will be needed even after the responder was removed. mCapabilityType = responder->capability_type(); + mIsEventPoll = responder->is_event_poll(); // Send header events to responder if needed. if (mResponder->needsHeaders()) @@ -1479,7 +1530,7 @@ CurlMultiHandle::~CurlMultiHandle() } // namespace AICurlPrivate -#if LL_LINUX +#if LL_LINUX && !defined(__x86_64__) extern "C" { // Keep linker happy. diff --git a/indra/llmessage/aicurleasyrequeststatemachine.cpp b/indra/llmessage/aicurleasyrequeststatemachine.cpp index ed2bf820d2..6b7bcf6544 100644 --- a/indra/llmessage/aicurleasyrequeststatemachine.cpp +++ b/indra/llmessage/aicurleasyrequeststatemachine.cpp @@ -116,6 +116,16 @@ void AICurlEasyRequestStateMachine::multiplex_impl(state_type run_state) { set_state(AICurlEasyRequestStateMachine_waitAdded); idle(); // Wait till AICurlEasyRequestStateMachine::added_to_multi_handle() is called. + + // This is a work around for the case that this request had a bad url, in order to avoid a crash later on. + bool empty_url = AICurlEasyRequest_rat(*mCurlEasyRequest)->getLowercaseServicename().empty(); + if (empty_url) + { + AICurlEasyRequest_wat(*mCurlEasyRequest)->aborted(HTTP_INTERNAL_ERROR_OTHER, "Not a valid URL."); + abort(); + break; + } + // Only AFTER going idle, add request to curl thread; this is needed because calls to set_state() are // ignored when the statemachine is not idle, and theoretically the callbacks could be called // immediately after this call. @@ -186,16 +196,14 @@ void AICurlEasyRequestStateMachine::multiplex_impl(state_type run_state) case AICurlEasyRequestStateMachine_removed: { // The request was removed from the multi handle. - if (mTimedOut) - { - AICurlEasyRequest_wat easy_request_w(*mCurlEasyRequest); - easy_request_w->timed_out(); - } // We're done. If we timed out, abort -- or else the application will // think that getResult() will return a valid error code from libcurl. if (mTimedOut) + { + AICurlEasyRequest_wat(*mCurlEasyRequest)->aborted(HTTP_INTERNAL_ERROR_CURL_LOCKUP, "Request timeout, aborted."); abort(); + } else finish(); @@ -203,7 +211,7 @@ void AICurlEasyRequestStateMachine::multiplex_impl(state_type run_state) } case AICurlEasyRequestStateMachine_bad_file_descriptor: { - AICurlEasyRequest_wat(*mCurlEasyRequest)->bad_socket(); + AICurlEasyRequest_wat(*mCurlEasyRequest)->aborted(HTTP_INTERNAL_ERROR_CURL_BADSOCKET, "File descriptor went bad! Aborted."); abort(); } } @@ -215,7 +223,7 @@ void AICurlEasyRequestStateMachine::abort_impl(void) // Revert call to addRequest() if that was already called (and the request wasn't removed again already). if (mAdded) { - // Note that it's safe to call this even if the curl thread already removed it, or will removes it + // Note that it's safe to call this even if the curl thread already removed it, or will remove it // after we called this, before processing the remove command; only the curl thread calls // MultiHandle::remove_easy_request, which is a no-op when called twice for the same easy request. mAdded = false; @@ -241,10 +249,13 @@ void AICurlEasyRequestStateMachine::finish_impl(void) } } -AICurlEasyRequestStateMachine::AICurlEasyRequestStateMachine(void) : +AICurlEasyRequestStateMachine::AICurlEasyRequestStateMachine(CWD_ONLY(bool debug)) : +#ifdef CWDEBUG + AIStateMachine(debug), +#endif mTotalDelayTimeout(AIHTTPTimeoutPolicy::getDebugSettingsCurlTimeout().getTotalDelay()) { - Dout(dc::statemachine, "Calling AICurlEasyRequestStateMachine(void) [" << (void*)this << "] [" << (void*)mCurlEasyRequest.get() << "]"); + Dout(dc::statemachine(mSMDebug), "Calling AICurlEasyRequestStateMachine(void) [" << (void*)this << "] [" << (void*)mCurlEasyRequest.get() << "]"); AICurlInterface::Stats::AICurlEasyRequestStateMachine_count++; } @@ -255,7 +266,7 @@ void AICurlEasyRequestStateMachine::setTotalDelayTimeout(F32 totalDelayTimeout) AICurlEasyRequestStateMachine::~AICurlEasyRequestStateMachine() { - Dout(dc::statemachine, "Calling ~AICurlEasyRequestStateMachine() [" << (void*)this << "] [" << (void*)mCurlEasyRequest.get() << "]"); + Dout(dc::statemachine(mSMDebug), "Calling ~AICurlEasyRequestStateMachine() [" << (void*)this << "] [" << (void*)mCurlEasyRequest.get() << "]"); --AICurlInterface::Stats::AICurlEasyRequestStateMachine_count; } diff --git a/indra/llmessage/aicurleasyrequeststatemachine.h b/indra/llmessage/aicurleasyrequeststatemachine.h index 662efbe20e..9bab7166ba 100644 --- a/indra/llmessage/aicurleasyrequeststatemachine.h +++ b/indra/llmessage/aicurleasyrequeststatemachine.h @@ -52,7 +52,7 @@ // Construction of a AICurlEasyRequestStateMachine might throw AICurlNoEasyHandle. class AICurlEasyRequestStateMachine : public AIStateMachine, public AICurlEasyHandleEvents { public: - AICurlEasyRequestStateMachine(void); + AICurlEasyRequestStateMachine(CWD_ONLY(bool debug = false)); // Transparent access. AICurlEasyRequest mCurlEasyRequest; diff --git a/indra/llmessage/aicurlperservice.cpp b/indra/llmessage/aicurlperservice.cpp index 8a58e2c980..cfb4fc7094 100644 --- a/indra/llmessage/aicurlperservice.cpp +++ b/indra/llmessage/aicurlperservice.cpp @@ -75,6 +75,7 @@ AIPerService::AIPerService(void) : mConcurrentConnections(CurlConcurrentConnectionsPerService), mApprovedRequests(0), mTotalAdded(0), + mEventPolls(0), mEstablishedConnections(0), mUsedCT(0), mCTInUse(0) @@ -214,7 +215,7 @@ std::string AIPerService::extract_canonical_servicename(std::string const& url) } ++p; } - // Strip of any trailing ":80". + // Strip off any trailing ":80". if (p - 3 == port_colon && p[-1] == '0' && p[-2] == '8') { return servicename.substr(0, p - hostname - 3); @@ -335,24 +336,70 @@ bool AIPerService::throttled(AICapabilityType capability_type) const mCapabilityType[capability_type].mAdded >= mCapabilityType[capability_type].mConcurrentConnections; } -void AIPerService::added_to_multi_handle(AICapabilityType capability_type) +void AIPerService::added_to_multi_handle(AICapabilityType capability_type, bool event_poll) { + if (event_poll) + { + llassert(capability_type == cap_other); + // We want to mark this service as unused when only long polls have been added, because they + // are not counted towards the maximum number of connection for this service and therefore + // should not cause another capability type to get less connections. + // For example, if - like on opensim - Textures and Other capability types use the same + // service then it is nonsense to reserve 4 connections Other and only give 4 connections + // to Textures, only because there is a long poll connection (or any number of long poll + // connections). What we want is to see: 0-0-0,{0/7,0} for textures when Other is ONLY in + // use for the Event Poll. + // + // This translates to that, since we're adding an event_poll and are about to remove it from + // either the command queue OR the request queue, that when mAdded == 1 at the end of this function + // (and the rest of the pipeline is empty) we want to mark this capability type as unused. + // + // If mEventPolls > 0 at this point then mAdded will not be incremented. + // If mEventPolls == 0 then mAdded will be incremented and thus should be 0 now. + // In other words, if the number of mAdded requests is equal to the number of (counted) + // mEventPoll requests right now, then that will still be the case after we added another + // event poll request (the transition from used to unused only being necessary because + // event poll requests in the pipe line ARE counted; not because that is necessary but + // because it would be more complex to not do so). + // + // Moreover, when we get here then the request that is being added is still counted as being in + // the command queue, or the request queue, so that pipelined_requests() will return 1 more than + // the actual count. + U16 counted_event_polls = (mEventPolls == 0) ? 0 : 1; + if (mCapabilityType[capability_type].mAdded == counted_event_polls && + mCapabilityType[capability_type].pipelined_requests() == counted_event_polls + 1) + { + mark_unused(capability_type); + } + if (++mEventPolls > 1) + { + // This only happens on megaregions. Do not count the additional long poll connections against the maximum handles for this service. + return; + } + } ++mCapabilityType[capability_type].mAdded; ++mTotalAdded; } -void AIPerService::removed_from_multi_handle(AICapabilityType capability_type, bool downloaded_something, bool success) +void AIPerService::removed_from_multi_handle(AICapabilityType capability_type, bool event_poll, bool downloaded_something, bool success) { CapabilityType& ct(mCapabilityType[capability_type]); - llassert(mTotalAdded > 0 && ct.mAdded > 0); - bool done = --ct.mAdded == 0; + llassert(mTotalAdded > 0 && ct.mAdded > 0 && (!event_poll || mEventPolls)); + if (!event_poll || --mEventPolls == 0) + { + --ct.mAdded; + --mTotalAdded; + } if (downloaded_something) { llassert(ct.mDownloading > 0); --ct.mDownloading; } - --mTotalAdded; - if (done && ct.pipelined_requests() == 0) + // If the number of added request handles is equal to the number of counted event poll handles, + // in other words, when there are only long poll connections left, then mark the capability type + // as unused. + U16 counted_event_polls = (capability_type != cap_other || mEventPolls == 0) ? 0 : 1; + if (ct.mAdded == counted_event_polls && ct.pipelined_requests() == counted_event_polls) { mark_unused(capability_type); } @@ -467,6 +514,9 @@ void AIPerService::add_queued_to(curlthread::MultiHandle* multi_handle, bool onl break; } // Request was added, remove it from the queue. + // Note: AIPerService::added_to_multi_handle (called from add_easy_request above) relies on the fact that + // we first add the easy handle and then remove it from the request queue (which is necessary to avoid + // that another thread adds one just in between). ct.mQueuedRequests.pop_front(); // Mark that at least one request of this CT was successfully added. success |= mask; @@ -560,7 +610,7 @@ void AIPerService::purge(void) per_service_w->mCapabilityType[i].mQueuedRequests.clear(); if (is_approved((AICapabilityType)i)) { - llassert(total_queued_w->approved >= s); + llassert(total_queued_w->approved >= (S32)s); total_queued_w->approved -= s; } } @@ -608,6 +658,6 @@ void AIPerService::Approvement::honored(void) void AIPerService::Approvement::not_honored(void) { honored(); - llwarns << "Approvement for has not been honored." << llendl; + LL_WARNS() << "Approvement for has not been honored." << LL_ENDL; } diff --git a/indra/llmessage/aicurlperservice.h b/indra/llmessage/aicurlperservice.h index 188d383bf9..0dc29f5be7 100644 --- a/indra/llmessage/aicurlperservice.h +++ b/indra/llmessage/aicurlperservice.h @@ -80,7 +80,7 @@ typedef boost::intrusive_ptr AIPe enum AICapabilityType { // {Capabilities} [Responders] cap_texture = 0, // GetTexture [HTTPGetResponder] - cap_inventory = 1, // { FetchInventory2, FetchLib2 } [LLInventoryModel::fetchInventoryResponder], { FetchInventoryDescendents2, FetchLibDescendents2 } [LLInventoryModelFetchDescendentsResponder] + cap_inventory = 1, // { FetchInventory2, FetchLib2 } [LLInventoryModel::FetchItemHttpHandler], { FetchInventoryDescendents2, FetchLibDescendents2 } [GItemHttpHandler] cap_mesh = 2, // GetMesh [LLMeshSkinInfoResponder, LLMeshDecompositionResponder, LLMeshPhysicsShapeResponder, LLMeshHeaderResponder, LLMeshLODResponder] cap_other = 3, // All other capabilities @@ -145,7 +145,8 @@ class AIPerService { queued_request_type mQueuedRequests; // Waiting (throttled) requests. U16 mApprovedRequests; // The number of approved requests for this CT by approveHTTPRequestFor that were not added to the command queue yet. - U16 mQueuedCommands; // Number of add commands (minus remove commands), for this service, in the command queue. + S16 mQueuedCommands; // Number of add commands (minus remove commands), for this service, in the command queue. + // This value can temporarily become negative when remove commands are added to the queue for add requests that were already processed. U16 mAdded; // Number of active easy handles with this service. U16 mFlags; // ctf_empty: Set to true when the queue becomes precisely empty. // ctf_full : Set to true when the queue is popped and then still isn't empty; @@ -169,6 +170,7 @@ class AIPerService { int mConcurrentConnections; // The maximum number of allowed concurrent connections to this service. int mApprovedRequests; // The number of approved requests for this service by approveHTTPRequestFor that were not added to the command queue yet. int mTotalAdded; // Number of active easy handles with this service. + int mEventPolls; // Number of active event poll handles with this service. int mEstablishedConnections; // Number of connected sockets to this service. U32 mUsedCT; // Bit mask with one bit per capability type. A '1' means the capability was in use since the last resetUsedCT(). @@ -267,9 +269,10 @@ class AIPerService { public: void added_to_command_queue(AICapabilityType capability_type) { ++mCapabilityType[capability_type].mQueuedCommands; mark_inuse(capability_type); } - void removed_from_command_queue(AICapabilityType capability_type) { --mCapabilityType[capability_type].mQueuedCommands; llassert(mCapabilityType[capability_type].mQueuedCommands >= 0); } - void added_to_multi_handle(AICapabilityType capability_type); // Called when an easy handle for this service has been added to the multi handle. - void removed_from_multi_handle(AICapabilityType capability_type, bool downloaded_something, bool success); // Called when an easy handle for this service is removed again from the multi handle. + void removed_from_command_queue(AICapabilityType capability_type) { --mCapabilityType[capability_type].mQueuedCommands; } + void added_to_multi_handle(AICapabilityType capability_type, bool event_poll); // Called when an easy handle for this service has been added to the multi handle. + void removed_from_multi_handle(AICapabilityType capability_type, bool event_poll, + bool downloaded_something, bool success); // Called when an easy handle for this service is removed again from the multi handle. void download_started(AICapabilityType capability_type) { ++mCapabilityType[capability_type].mDownloading; } bool throttled(AICapabilityType capability_type) const; // Returns true if the maximum number of allowed requests for this service/capability type have been added to the multi handle. bool nothing_added(AICapabilityType capability_type) const { return mCapabilityType[capability_type].mAdded == 0; } diff --git a/indra/llmessage/aicurlprivate.h b/indra/llmessage/aicurlprivate.h index cbb9a293d6..18855fc944 100644 --- a/indra/llmessage/aicurlprivate.h +++ b/indra/llmessage/aicurlprivate.h @@ -83,8 +83,8 @@ class CurlEasyHandle : public boost::noncopyable, protected AICurlEasyHandleEven //DECLARE_SETOPT(curl_read_callback); Same type as curl_write_callback DECLARE_SETOPT(curl_ssl_ctx_callback); DECLARE_SETOPT(curl_conv_callback); -#if 0 // Not used by the viewer. DECLARE_SETOPT(curl_progress_callback); +#if 0 // Not used by the viewer. DECLARE_SETOPT(curl_seek_callback); DECLARE_SETOPT(curl_ioctl_callback); DECLARE_SETOPT(curl_sockopt_callback); @@ -222,6 +222,7 @@ class CurlEasyRequest : public CurlEasyHandle { void setPost_raw(U32 size, char const* data, bool keepalive); public: void setPut(U32 size, bool keepalive = true); + void setPatch(U32 size, bool keepalive = true); void setPost(U32 size, bool keepalive = true) { setPost_raw(size, NULL, keepalive); } void setPost(AIPostFieldPtr const& postdata, U32 size, bool keepalive = true); void setPost(char const* data, U32 size, bool keepalive = true) { setPost(new AIPostField(data), size, keepalive); } @@ -235,6 +236,7 @@ class CurlEasyRequest : public CurlEasyHandle { static size_t writeCallback(char* ptr, size_t size, size_t nmemb, void* userdata); static size_t readCallback(char* ptr, size_t size, size_t nmemb, void* userdata); static CURLcode SSLCtxCallback(CURL* curl, void* sslctx, void* userdata); + static int progressCallback(void* userdata, double, double, double, double); curl_write_callback mHeaderCallback; void* mHeaderCallbackUserData; @@ -244,12 +246,15 @@ class CurlEasyRequest : public CurlEasyHandle { void* mReadCallbackUserData; curl_ssl_ctx_callback mSSLCtxCallback; void* mSSLCtxCallbackUserData; + curl_progress_callback mProgressCallback; + void* mProgressCallbackUserData; public: void setHeaderCallback(curl_write_callback callback, void* userdata); void setWriteCallback(curl_write_callback callback, void* userdata); void setReadCallback(curl_read_callback callback, void* userdata); void setSSLCtxCallback(curl_ssl_ctx_callback callback, void* userdata); + void setProgressCallback(curl_progress_callback callback, void* userdata); // Call this if the set callbacks are about to be invalidated. void revokeCallbacks(void); @@ -315,7 +320,8 @@ class CurlEasyRequest : public CurlEasyHandle { AIPerServicePtr mPerServicePtr; // Pointer to the corresponding AIPerService. LLPointer mTimeout;// Timeout administration object associated with last created CurlSocketInfo. bool mTimeoutIsOrphan; // Set to true when mTimeout is not (yet) associated with a CurlSocketInfo. -#if defined(CWDEBUG) || defined(DEBUG_CURLIO) + bool mIsHttps; // Set if the url starts with "https:". +#ifdef CWDEBUG public: bool mDebugIsHeadOrGetMethod; #endif @@ -337,7 +343,7 @@ class CurlEasyRequest : public CurlEasyHandle { // This class may only be created as base class of BufferedCurlEasyRequest. // Throws AICurlNoEasyHandle. CurlEasyRequest(void) : mHeaders(NULL), mHandleEventsTarget(NULL), mContentLength(0), mResult(CURLE_FAILED_INIT), mTimeoutPolicy(NULL), mTimeoutIsOrphan(false) -#if defined(CWDEBUG) || defined(DEBUG_CURLIO) +#ifdef CWDEBUG , mDebugIsHeadOrGetMethod(false) #endif { applyDefaultOptions(); } @@ -385,11 +391,8 @@ class BufferedCurlEasyRequest : public CurlEasyRequest { buffer_ptr_t& getInput(void) { return mInput; } buffer_ptr_t& getOutput(void) { return mOutput; } - // Called if libcurl doesn't deliver within AIHTTPTimeoutPolicy::mMaximumTotalDelay seconds. - void timed_out(void); - - // Called if the underlaying socket went bad (ie, when accidently closed by a buggy library). - void bad_socket(void); + // Called if the state machine is (about to be) aborted due to some error. + void aborted(U32 http_status, std::string const& reason); // Called after removed_from_multi_handle was called. void processOutput(void); @@ -418,6 +421,7 @@ class BufferedCurlEasyRequest : public CurlEasyRequest { buffer_ptr_t mOutput; LLHTTPClient::ResponderPtr mResponder; AICapabilityType mCapabilityType; + bool mIsEventPoll; //U32 mBodyLimit; // From the old LLURLRequestDetail::mBodyLimit, but never used. U32 mStatus; // HTTP status, decoded from the first header line. std::string mReason; // The "reason" from the same header line. @@ -427,7 +431,7 @@ class BufferedCurlEasyRequest : public CurlEasyRequest { public: static LLChannelDescriptors const sChannels; // Channel object for mInput (channel out()) and mOutput (channel in()). - static LLMutex sResponderCallbackMutex; // Locked while calling back any overridden ResponderBase::finished and/or accessing sShuttingDown. + static LLGlobalMutex sResponderCallbackMutex; // Locked while calling back any overridden ResponderBase::finished and/or accessing sShuttingDown. static bool sShuttingDown; // If true, no additional calls to ResponderBase::finished will be made anymore. static AIAverage sHTTPBandwidth; // HTTP bandwidth usage of all services combined. @@ -442,6 +446,7 @@ class BufferedCurlEasyRequest : public CurlEasyRequest { static size_t curlWriteCallback(char* data, size_t size, size_t nmemb, void* user_data); static size_t curlReadCallback(char* data, size_t size, size_t nmemb, void* user_data); static size_t curlHeaderCallback(char* data, size_t size, size_t nmemb, void* user_data); + static int curlProgressCallback(void* user_data, double dltotal, double dlnow, double ultotal, double ulnow); // Called from curlHeaderCallback. void setStatusAndReason(U32 status, std::string const& reason); @@ -461,16 +466,17 @@ class BufferedCurlEasyRequest : public CurlEasyRequest { bool success(void) const { return mResult == CURLE_OK && mStatus >= 200 && mStatus < 400; } // Return true when prepRequest was already called and the object has not been - // invalidated as a result of calling timed_out(). - bool isValid(void) const { return mResponder; } + // invalidated as a result of calling aborted(). + bool isValid(void) const { return !!mResponder; } // Return the capability type of this request. AICapabilityType capability_type(void) const { llassert(mCapabilityType != number_of_capability_types); return mCapabilityType; } + bool is_event_poll(void) const { return mIsEventPoll; } // Return true if any data was received. bool received_data(void) const { return mTotalRawBytes > 0; } -#if defined(CWDEBUG) || defined(DEBUG_CURLIO) +#ifdef CWDEBUG // Connection accounting for debug purposes. void connection_established(int connectionnr); void connection_closed(int connectionnr); diff --git a/indra/llmessage/aicurlthread.cpp b/indra/llmessage/aicurlthread.cpp index 64a6b69fe0..c23beea844 100644 --- a/indra/llmessage/aicurlthread.cpp +++ b/indra/llmessage/aicurlthread.cpp @@ -563,7 +563,7 @@ refresh_t PollSet::refresh(void) // by not calculating mMaxFdSet here. if (mNrFds >= FD_SETSIZE) { - llwarns << "PollSet::reset: More than FD_SETSIZE (" << FD_SETSIZE << ") file descriptors active!" << llendl; + LL_WARNS() << "PollSet::reset: More than FD_SETSIZE (" << FD_SETSIZE << ") file descriptors active!" << LL_ENDL; #if !WINDOWS_CODE // Calculate mMaxFdSet. // Run over FD_SETSIZE - 1 elements, starting at mNext, wrapping to 0 when we reach the end. @@ -730,7 +730,7 @@ bool MergeIterator::next(curl_socket_t& fd_out, int& ev_bitmask_out) //----------------------------------------------------------------------------- // CurlSocketInfo -#if defined(CWDEBUG) || defined(DEBUG_CURLIO) +#ifdef CWDEBUG #undef AI_CASE_RETURN #define AI_CASE_RETURN(x) case x: return #x; static char const* action_str(int action) @@ -1020,20 +1020,20 @@ void AICurlThread::create_wakeup_fds(void) curl_socket_t socks[2]; if (dumb_socketpair(socks, false) == SOCKET_ERROR) { - llerrs << "Failed to generate wake-up socket pair" << formatWSAError() << llendl; + LL_ERRS() << "Failed to generate wake-up socket pair" << formatWSAError() << LL_ENDL; return; } u_long nonblocking_enable = TRUE; int error = ioctlsocket(socks[0], FIONBIO, &nonblocking_enable); if(error) { - llerrs << "Failed to set wake-up socket nonblocking: " << formatWSAError() << llendl; + LL_ERRS() << "Failed to set wake-up socket nonblocking: " << formatWSAError() << LL_ENDL; } llassert(nonblocking_enable); error = ioctlsocket(socks[1], FIONBIO, &nonblocking_enable); if(error) { - llerrs << "Failed to set wake-up input socket nonblocking: " << formatWSAError() << llendl; + LL_ERRS() << "Failed to set wake-up input socket nonblocking: " << formatWSAError() << LL_ENDL; } mWakeUpFd = socks[0]; mWakeUpFd_in = socks[1]; @@ -1041,14 +1041,14 @@ void AICurlThread::create_wakeup_fds(void) int pipefd[2]; if (pipe(pipefd)) { - llerrs << "Failed to create wakeup pipe: " << strerror(errno) << llendl; + LL_ERRS() << "Failed to create wakeup pipe: " << strerror(errno) << LL_ENDL; } int const flags = O_NONBLOCK; for (int i = 0; i < 2; ++i) { if (fcntl(pipefd[i], F_SETFL, flags)) { - llerrs << "Failed to set pipe to non-blocking: " << strerror(errno) << llendl; + LL_ERRS() << "Failed to set pipe to non-blocking: " << strerror(errno) << LL_ENDL; } } mWakeUpFd = pipefd[0]; // Read-end of the pipe. @@ -1066,7 +1066,7 @@ void AICurlThread::cleanup_wakeup_fds(void) int error = closesocket(mWakeUpFd); if (error) { - llwarns << "Error closing wake-up socket" << formatWSAError() << llendl; + LL_WARNS() << "Error closing wake-up socket" << formatWSAError() << LL_ENDL; } } if (mWakeUpFd_in != CURL_SOCKET_BAD) @@ -1074,7 +1074,7 @@ void AICurlThread::cleanup_wakeup_fds(void) int error = closesocket(mWakeUpFd_in); if (error) { - llwarns << "Error closing wake-up input socket" << formatWSAError() << llendl; + LL_WARNS() << "Error closing wake-up input socket" << formatWSAError() << LL_ENDL; } } #else @@ -1098,10 +1098,10 @@ void AICurlThread::wakeup_thread(bool stop_thread) if (stop_thread) mRunning = false; // Thread-safe because all other threads were already stopped. - // Note, we do not want this function to be blocking the calling thread; therefore we only use tryLock()s. + // Note, we do not want this function to be blocking the calling thread; therefore we only use try_lock()s. // Stop two threads running the following code concurrently. - if (!mWakeUpMutex.tryLock()) + if (!mWakeUpMutex.try_lock()) { // If we failed to obtain mWakeUpMutex then another thread is (or was) in AICurlThread::wakeup_thread, // or curl was holding the lock for a micro second at the start of process_commands. @@ -1115,7 +1115,7 @@ void AICurlThread::wakeup_thread(bool stop_thread) } // Try if curl thread is still awake and if so, pass the new commands directly. - if (mWakeUpFlagMutex.tryLock()) + if (mWakeUpFlagMutex.try_lock()) { mWakeUpFlag = true; mWakeUpFlagMutex.unlock(); @@ -1128,7 +1128,7 @@ void AICurlThread::wakeup_thread(bool stop_thread) int len = send(mWakeUpFd_in, "!", 1, 0); if (len == SOCKET_ERROR) { - llerrs << "Send to wake-up socket failed: " << formatWSAError() << llendl; + LL_ERRS() << "Send to wake-up socket failed: " << formatWSAError() << LL_ENDL; } llassert_always(len == 1); //SGTODO: handle EAGAIN if needed @@ -1153,7 +1153,7 @@ void AICurlThread::wakeup_thread(bool stop_thread) while(len == -1 && errno == EINTR); if (len == -1) { - llerrs << "write(3) to mWakeUpFd_in: " << strerror(errno) << llendl; + LL_ERRS() << "write(3) to mWakeUpFd_in: " << strerror(errno) << LL_ENDL; } llassert_always(len == 1); #endif @@ -1210,14 +1210,14 @@ void AICurlThread::wakeup(AICurlMultiHandle_wat const& multi_handle_w) } else { - llerrs << "read(3) from mWakeUpFd: " << formatWSAError() << llendl; + LL_ERRS() << "read(3) from mWakeUpFd: " << formatWSAError() << LL_ENDL; return; } } else { // pipe(2) returned 0. - llwarns << "read(3) from mWakeUpFd returned 0, indicating that the pipe on the other end was closed! Shutting down curl thread." << llendl; + LL_WARNS() << "read(3) from mWakeUpFd returned 0, indicating that the pipe on the other end was closed! Shutting down curl thread." << LL_ENDL; closesocket(mWakeUpFd); mWakeUpFd = CURL_SOCKET_BAD; mRunning = false; @@ -1258,14 +1258,14 @@ void AICurlThread::wakeup(AICurlMultiHandle_wat const& multi_handle_w) } else { - llerrs << "read(3) from mWakeUpFd: " << strerror(errno) << llendl; + LL_ERRS() << "read(3) from mWakeUpFd: " << strerror(errno) << LL_ENDL; return; } } else { // pipe(2) returned 0. - llwarns << "read(3) from mWakeUpFd returned 0, indicating that the pipe on the other end was closed! Shutting down curl thread." << llendl; + LL_WARNS() << "read(3) from mWakeUpFd returned 0, indicating that the pipe on the other end was closed! Shutting down curl thread." << LL_ENDL; close(mWakeUpFd); mWakeUpFd = CURL_SOCKET_BAD; mRunning = false; @@ -1312,7 +1312,7 @@ void AICurlThread::process_commands(AICurlMultiHandle_wat const& multi_handle_w) *command_being_processed_w = command_queue_w->commands.front(); command = command_being_processed_w->command(); } - // Update the size: the number netto number of pending requests in the command queue. + // Update the size: the netto number of pending requests in the command queue. command_queue_w->commands.pop_front(); if (command == cmd_add) { @@ -1340,6 +1340,9 @@ void AICurlThread::process_commands(AICurlMultiHandle_wat const& multi_handle_w) break; case cmd_add: { + // Note: AIPerService::added_to_multi_handle (called from add_easy_request) relies on the fact that + // we first add the easy handle and then remove it from the command queue (which is necessary to + // avoid that another thread adds one just in between). multi_handle_w->add_easy_request(AICurlEasyRequest(command_being_processed_r->easy_request()), false); PerService_wat(*per_service)->removed_from_command_queue(capability_type); break; @@ -1456,7 +1459,7 @@ void AICurlThread::run(void) if (mZeroTimeout >= 1000) { if (mZeroTimeout % 10000 == 0) - llwarns << "Detected " << mZeroTimeout << " zero-timeout calls of select() by curl thread (more than 101 seconds)!" << llendl; + LL_WARNS() << "Detected " << mZeroTimeout << " zero-timeout calls of select() by curl thread (more than 101 seconds)!" << LL_ENDL; timeout_ms = 10; } else if (mZeroTimeout >= 100) @@ -1467,7 +1470,7 @@ void AICurlThread::run(void) else { if (LL_UNLIKELY(mZeroTimeout >= 10000)) - llinfos << "Timeout of select() call by curl thread reset (to " << timeout_ms << " ms)." << llendl; + LL_INFOS() << "Timeout of select() call by curl thread reset (to " << timeout_ms << " ms)." << LL_ENDL; mZeroTimeout = 0; } timeout.tv_sec = timeout_ms / 1000; @@ -1521,7 +1524,7 @@ void AICurlThread::run(void) // or -1 when an error occurred. A value of 0 means that a timeout occurred. if (ready == -1) { - llwarns << "select() failed: " << errno << ", " << strerror(errno) << llendl; + LL_WARNS() << "select() failed: " << errno << ", " << strerror(errno) << LL_ENDL; if (errno == EBADF) { // Somewhere (fmodex?) one of our file descriptors was closed. Try to recover by finding out which. @@ -1641,7 +1644,7 @@ MultiHandle::MultiHandle(void) : mTimeout(-1), mReadPollSet(NULL), mWritePollSet MultiHandle::~MultiHandle() { - llinfos << "Destructing MultiHandle with " << mAddedEasyRequests.size() << " active curl easy handles." << llendl; + LL_INFOS() << "Destructing MultiHandle with " << mAddedEasyRequests.size() << " active curl easy handles." << LL_ENDL; // This thread was terminated. // Curl demands that all handles are removed from the multi session handle before calling curl_multi_cleanup. @@ -1747,10 +1750,12 @@ bool MultiHandle::add_easy_request(AICurlEasyRequest const& easy_request, bool f { bool throttled = true; // Default. AICapabilityType capability_type; + bool event_poll; AIPerServicePtr per_service; { AICurlEasyRequest_wat curl_easy_request_w(*easy_request); capability_type = curl_easy_request_w->capability_type(); + event_poll = curl_easy_request_w->is_event_poll(); per_service = curl_easy_request_w->getPerServicePtr(); if (!from_queue) { @@ -1782,7 +1787,7 @@ bool MultiHandle::add_easy_request(AICurlEasyRequest const& easy_request, bool f curl_easy_request_w->set_timeout_opts(); if (curl_easy_request_w->add_handle_to_multi(curl_easy_request_w, mMultiHandle) == CURLM_OK) { - per_service_w->added_to_multi_handle(capability_type); // (About to be) added to mAddedEasyRequests. + per_service_w->added_to_multi_handle(capability_type, event_poll); // (About to be) added to mAddedEasyRequests. throttled = false; // Fall through... } } @@ -1841,6 +1846,7 @@ CURLMcode MultiHandle::remove_easy_request(addedEasyRequests_type::iterator cons { CURLMcode res; AICapabilityType capability_type; + bool event_poll; AIPerServicePtr per_service; { AICurlEasyRequest_wat curl_easy_request_w(**iter); @@ -1848,8 +1854,9 @@ CURLMcode MultiHandle::remove_easy_request(addedEasyRequests_type::iterator cons bool success = curl_easy_request_w->success(); res = curl_easy_request_w->remove_handle_from_multi(curl_easy_request_w, mMultiHandle); capability_type = curl_easy_request_w->capability_type(); + event_poll = curl_easy_request_w->is_event_poll(); per_service = curl_easy_request_w->getPerServicePtr(); - PerService_wat(*per_service)->removed_from_multi_handle(capability_type, downloaded_something, success); // (About to be) removed from mAddedEasyRequests. + PerService_wat(*per_service)->removed_from_multi_handle(capability_type, event_poll, downloaded_something, success); // (About to be) removed from mAddedEasyRequests. #ifdef SHOW_ASSERT curl_easy_request_w->mRemovedPerCommand = as_per_command; #endif @@ -1899,7 +1906,7 @@ void MultiHandle::check_msg_queue(void) } else if (res == -2) { - llwarns << "Curl easy handle returned by curl_multi_info_read() that is not (anymore) in MultiHandle::mAddedEasyRequests!?!" << llendl; + LL_WARNS() << "Curl easy handle returned by curl_multi_info_read() that is not (anymore) in MultiHandle::mAddedEasyRequests!?!" << LL_ENDL; } // Destruction of easy_request at this point, causes the CurlEasyRequest to be deleted. } @@ -2034,7 +2041,7 @@ void stopCurlThread(void) // main thread) will have destroyed before it REALLY finished. AICurlThread::sInstance->join_thread(); // Wait till it is REALLY done. } - llinfos << "Curl thread" << (curlThreadIsRunning() ? " not" : "") << " stopped after " << ((400 - count) * 10) << "ms." << llendl; + LL_INFOS() << "Curl thread" << (curlThreadIsRunning() ? " not" : "") << " stopped after " << ((400 - count) * 10) << "ms." << LL_ENDL; } } @@ -2062,7 +2069,7 @@ void BufferedCurlEasyRequest::setStatusAndReason(U32 status, std::string const& // Sanity check. If the server replies with a redirect status then we better have that option turned on! if ((status >= 300 && status < 400) && mResponder && !mResponder->redirect_status_ok()) { - llerrs << "Received " << status << " (" << reason << ") for responder \"" << mResponder->getName() << "\" which has no followRedir()!" << llendl; + LL_ERRS() << "Received " << status << " (" << reason << ") for responder \"" << mResponder->getName() << "\" which does not allow redirection!" << LL_ENDL; } } @@ -2133,7 +2140,8 @@ void BufferedCurlEasyRequest::processOutput(void) sResponderCallbackMutex.unlock(); mResponder = NULL; - resetState(); + // Commented out because this easy handle is not going to be reused; it makes no sense to reset its state. + //resetState(); } //static @@ -2279,16 +2287,17 @@ size_t BufferedCurlEasyRequest::curlHeaderCallback(char* data, size_t size, size if (status == 0) { reason = "Header parse error."; - llwarns << "Received broken header line from server: \"" << header << "\"" << llendl; + LL_WARNS() << "Received broken header line from server: \"" << header << "\"" << LL_ENDL; } else { - reason = "Unexpected HTTP status."; - llwarns << "Received unexpected status value from server (" << status << "): \"" << header << "\"" << llendl; + //reason = "Unexpected HTTP status."; + LL_WARNS() << "Received unexpected status value from server (" << status << "): \"" << header << "\"" << LL_ENDL; } + // Singu TODO: WHAT THE HELL WAS THIS?! LYING? WHY WERE WE LYING???? Responders USE These Codes!!!!! // Either way, this status value is not understood (or taken into account). // Set it to internal error so that the rest of code treats it as an error. - status = HTTP_INTERNAL_ERROR_OTHER; + if (!status) status = HTTP_INTERNAL_ERROR_OTHER; } self_w->received_HTTP_header(); self_w->setStatusAndReason(status, reason); @@ -2340,14 +2349,32 @@ size_t BufferedCurlEasyRequest::curlHeaderCallback(char* data, size_t size, size LLStringUtil::trim(header); if (!header.empty()) { - llwarns << "Unable to parse header: " << header << llendl; + LL_WARNS() << "Unable to parse header: " << header << LL_ENDL; } } return header_len; } -#if defined(CWDEBUG) || defined(DEBUG_CURLIO) +//static +int BufferedCurlEasyRequest::curlProgressCallback(void* user_data, double dltotal, double dlnow, double ultotal, double ulnow) +{ + if (ultotal > 0) // Zero just means it isn't known yet. + { + ThreadSafeBufferedCurlEasyRequest* lockobj = static_cast(user_data); + DoutEntering(dc::curl, "BufferedCurlEasyRequest::curlProgressCallback(" << (void*)lockobj << ", " << dltotal << ", " << dlnow << ", " << ultotal << ", " << ulnow << ")"); + + if (ulnow == ultotal) // Everything uploaded? + { + AICurlEasyRequest_wat self_w(*lockobj); + self_w->httptimeout()->upload_finished(); + } + } + + return 0; +} + +#ifdef CWDEBUG int debug_callback(CURL* handle, curl_infotype infotype, char* buf, size_t size, void* user_ptr) { BufferedCurlEasyRequest* request = (BufferedCurlEasyRequest*)user_ptr; @@ -2415,7 +2442,6 @@ int debug_callback(CURL* handle, curl_infotype infotype, char* buf, size_t size, } #endif -#ifdef CWDEBUG using namespace ::libcwd; std::ostringstream marker; marker << (void*)request->get_lockobj() << ' '; @@ -2424,14 +2450,6 @@ int debug_callback(CURL* handle, curl_infotype infotype, char* buf, size_t size, if (!debug::channels::dc::curlio.is_on()) debug::channels::dc::curlio.on(); LibcwDoutScopeBegin(LIBCWD_DEBUGCHANNELS, libcw_do, dc::curlio|cond_nonewline_cf(infotype == CURLINFO_TEXT)) -#else - if (infotype == CURLINFO_TEXT) - { - while (size > 0 && (buf[size - 1] == '\r' || buf[size - 1] == '\n')) - --size; - } - LibcwDoutScopeBegin(LIBCWD_DEBUGCHANNELS, libcw_do, dc::curlio) -#endif switch (infotype) { case CURLINFO_TEXT: @@ -2509,12 +2527,10 @@ int debug_callback(CURL* handle, curl_infotype infotype, char* buf, size_t size, else LibcwDoutStream << size << " bytes"; LibcwDoutScopeEnd; -#ifdef CWDEBUG libcw_do.pop_marker(); -#endif return 0; } -#endif // defined(CWDEBUG) || defined(DEBUG_CURLIO) +#endif // CWDEBUG } // namespace AICurlPrivate @@ -2672,7 +2688,7 @@ bool handleCurlMaxTotalConcurrentConnections(LLSD const& newvalue) U32 old = curl_max_total_concurrent_connections; curl_max_total_concurrent_connections = newvalue.asInteger(); AIPerService::incrementMaxPipelinedRequests(curl_max_total_concurrent_connections - old); - llinfos << "CurlMaxTotalConcurrentConnections set to " << curl_max_total_concurrent_connections << llendl; + LL_INFOS() << "CurlMaxTotalConcurrentConnections set to " << curl_max_total_concurrent_connections << LL_ENDL; return true; } @@ -2691,7 +2707,7 @@ bool handleCurlConcurrentConnectionsPerService(LLSD const& newvalue) int increment = new_concurrent_connections - CurlConcurrentConnectionsPerService; CurlConcurrentConnectionsPerService = new_concurrent_connections; AIPerService::adjust_concurrent_connections(increment); - llinfos << "CurlConcurrentConnectionsPerService set to " << CurlConcurrentConnectionsPerService << llendl; + LL_INFOS() << "CurlConcurrentConnectionsPerService set to " << CurlConcurrentConnectionsPerService << LL_ENDL; } return true; } diff --git a/indra/llmessage/aicurlthread.h b/indra/llmessage/aicurlthread.h index 908456b130..7046af12b8 100644 --- a/indra/llmessage/aicurlthread.h +++ b/indra/llmessage/aicurlthread.h @@ -45,7 +45,7 @@ class PollSet; // For ordering a std::set with AICurlEasyRequest objects. struct AICurlEasyRequestCompare { - bool operator()(AICurlEasyRequest const& h1, AICurlEasyRequest const& h2) { return h1.get() < h2.get(); } + bool operator()(AICurlEasyRequest const& h1, AICurlEasyRequest const& h2) const { return h1.get() < h2.get(); } }; //----------------------------------------------------------------------------- diff --git a/indra/llmessage/aihttptimeout.cpp b/indra/llmessage/aihttptimeout.cpp index bfb0f767b5..bcc36df234 100644 --- a/indra/llmessage/aihttptimeout.cpp +++ b/indra/llmessage/aihttptimeout.cpp @@ -86,7 +86,7 @@ class BufferedCurlEasyRequest { #include "aihttptimeout.h" // If this is set, treat dc::curlio as off in the assertion below. -#if defined(CWDEBUG) || defined(DEBUG_CURLIO) +#ifdef CWDEBUG bool gCurlIo; #endif @@ -157,10 +157,11 @@ void HTTPTimeout::upload_starting(void) // | void HTTPTimeout::upload_finished(void) { - // Disable this assert when there isn't enough debug output to do anything with it. -#if defined(CWDEBUG) || defined(DEBUG_CURLIO) - llassert(!mUploadFinished); // If we get here twice, then the 'upload finished' detection failed. -#endif + // This function can be called more than once. Ignore the second call. + if (mUploadFinished) + { + return; + } mUploadFinished = true; // Only accept a call to upload_starting() if being_redirected() is called after this point. mBeingRedirected = false; @@ -179,7 +180,7 @@ void HTTPTimeout::upload_finished(void) // ^ ^ ^ ^ ^ ^ ^ ^ // | | | | | | | | bool HTTPTimeout::data_received(size_t n/*,*/ -#if defined(CWDEBUG) || defined(DEBUG_CURLIO) +#ifdef CWDEBUG ASSERT_ONLY_COMMA(bool upload_error_status) #else ASSERT_ONLY_COMMA(bool) @@ -308,13 +309,13 @@ bool HTTPTimeout::lowspeed(size_t bytes, bool finished) { if (finished) { - llwarns << + LL_WARNS() << #ifdef CWDEBUG (void*)get_lockobj() << ": " #endif "Transfer rate timeout (average transfer rate below " << low_speed_limit << " bytes/s for more than " << low_speed_time << " second" << ((low_speed_time == 1) ? "" : "s") << - ") but we just sent the LAST bytes! Waiting an additional 4 seconds." << llendl; + ") but we just sent the LAST bytes! Waiting an additional 4 seconds." << LL_ENDL; // Lets hope these last bytes will make it and do not time out on transfer speed anymore. // Just give these bytes 4 more seconds to be written to the socket (after which we'll // assume that the 'upload finished' detection failed and we'll wait another ReplyDelay @@ -324,12 +325,12 @@ bool HTTPTimeout::lowspeed(size_t bytes, bool finished) return false; } // The average transfer rate over the passed low_speed_time seconds is too low. Abort the transfer. - llwarns << + LL_WARNS() << #ifdef CWDEBUG (void*)get_lockobj() << ": " #endif "aborting slow connection (average transfer rate below " << low_speed_limit << - " bytes/s for more than " << low_speed_time << " second" << ((low_speed_time == 1) ? "" : "s") << ")." << llendl; + " bytes/s for more than " << low_speed_time << " second" << ((low_speed_time == 1) ? "" : "s") << ")." << LL_ENDL; // This causes curl to exit with CURLE_WRITE_ERROR. return true; } @@ -392,7 +393,7 @@ void HTTPTimeout::done(AICurlEasyRequest_wat const& curlEasyRequest_w, CURLcode if (code == CURLE_COULDNT_RESOLVE_HOST) { // Note that CURLINFO_OS_ERRNO returns 0; we don't know any more than this. - llwarns << "Failed to resolve hostname " << curlEasyRequest_w->getLowercaseHostname() << llendl; + LL_WARNS() << "Failed to resolve hostname " << curlEasyRequest_w->getLowercaseHostname() << LL_ENDL; dns_problem = true; } else if (mNothingReceivedYet) @@ -439,8 +440,8 @@ bool HTTPTimeout::maybe_upload_finished(void) void HTTPTimeout::print_diagnostics(CurlEasyRequest const* curl_easy_request, char const* eff_url) { #ifndef HTTPTIMEOUT_TESTSUITE - llwarns << "Request to \"" << curl_easy_request->getLowercaseServicename() << "\" timed out for " << curl_easy_request->getTimeoutPolicy()->name() << llendl; - llinfos << "Effective URL: \"" << eff_url << "\"." << llendl; + LL_WARNS() << "Request to \"" << curl_easy_request->getLowercaseServicename() << "\" timed out for " << curl_easy_request->getTimeoutPolicy()->name() << LL_ENDL; + LL_INFOS() << "Effective URL: \"" << eff_url << "\"." << LL_ENDL; double namelookup_time, connect_time, appconnect_time, pretransfer_time, starttransfer_time; curl_easy_request->getinfo(CURLINFO_NAMELOOKUP_TIME, &namelookup_time); curl_easy_request->getinfo(CURLINFO_CONNECT_TIME, &connect_time); @@ -454,9 +455,9 @@ void HTTPTimeout::print_diagnostics(CurlEasyRequest const* curl_easy_request, ch ) { #if LOWRESTIMER - llinfos << "Hostname seems to have been still in the DNS cache." << llendl; + LL_INFOS() << "Hostname seems to have been still in the DNS cache." << LL_ENDL; #else - llwarns << "Curl returned CURLE_OPERATION_TIMEDOUT and DNS lookup did not occur according to timings. Apparently the resolve attempt timed out (bad network?)" << llendl; + LL_WARNS() << "Curl returned CURLE_OPERATION_TIMEDOUT and DNS lookup did not occur according to timings. Apparently the resolve attempt timed out (bad network?)" << LL_ENDL; llassert(connect_time == 0); llassert(appconnect_time == 0); llassert(pretransfer_time == 0); @@ -468,14 +469,14 @@ void HTTPTimeout::print_diagnostics(CurlEasyRequest const* curl_easy_request, ch else if (namelookup_time < 500e-6) { #if LOWRESTIMER - llinfos << "Hostname was most likely still in DNS cache (or lookup occured in under ~10ms)." << llendl; + LL_INFOS() << "Hostname was most likely still in DNS cache (or lookup occured in under ~10ms)." << LL_ENDL; #else - llinfos << "Hostname was still in DNS cache." << llendl; + LL_INFOS() << "Hostname was still in DNS cache." << LL_ENDL; #endif } else { - llinfos << "DNS lookup of " << curl_easy_request->getLowercaseHostname() << " took " << namelookup_time << " seconds." << llendl; + LL_INFOS() << "DNS lookup of " << curl_easy_request->getLowercaseHostname() << " took " << namelookup_time << " seconds." << LL_ENDL; } if (connect_time == 0 #if LOWRESTIMER @@ -483,7 +484,7 @@ void HTTPTimeout::print_diagnostics(CurlEasyRequest const* curl_easy_request, ch #endif ) { - llwarns << "Curl returned CURLE_OPERATION_TIMEDOUT and connection did not occur according to timings: apparently the connect attempt timed out (bad network?)" << llendl; + LL_WARNS() << "Curl returned CURLE_OPERATION_TIMEDOUT and connection did not occur according to timings: apparently the connect attempt timed out (bad network?)" << LL_ENDL; llassert(appconnect_time == 0); llassert(pretransfer_time == 0); llassert(starttransfer_time == 0); @@ -493,68 +494,68 @@ void HTTPTimeout::print_diagnostics(CurlEasyRequest const* curl_easy_request, ch if (connect_time - namelookup_time <= 1e-5) { #if LOWRESTIMER // Assuming 10ms resolution. - llinfos << "The socket was most likely already connected (or you connected to a proxy with a connect time of under ~10 ms)." << llendl; + LL_INFOS() << "The socket was most likely already connected (or you connected to a proxy with a connect time of under ~10 ms)." << LL_ENDL; #else - llinfos << "The socket was already connected (to remote or proxy)." << llendl; + LL_INFOS() << "The socket was already connected (to remote or proxy)." << LL_ENDL; #endif // I'm assuming that the SSL/TLS handshake can be measured with a low res timer. if (appconnect_time == 0) { - llwarns << "The SSL/TLS handshake never occurred according to the timings!" << llendl; + LL_WARNS() << "The SSL/TLS handshake never occurred according to the timings!" << LL_ENDL; return; } // If appconnect_time is almost equal to connect_time, then it was just set because this is a connection re-use. if (appconnect_time - connect_time <= 1e-5) { - llinfos << "Connection with HTTP server was already established; this was a re-used connection." << llendl; + LL_INFOS() << "Connection with HTTP server was already established; this was a re-used connection." << LL_ENDL; } else { - llinfos << "SSL/TLS handshake with HTTP server took " << (appconnect_time - connect_time) << " seconds." << llendl; + LL_INFOS() << "SSL/TLS handshake with HTTP server took " << (appconnect_time - connect_time) << " seconds." << LL_ENDL; } } else { - llinfos << "Socket connected to remote host (or proxy) in " << (connect_time - namelookup_time) << " seconds." << llendl; + LL_INFOS() << "Socket connected to remote host (or proxy) in " << (connect_time - namelookup_time) << " seconds." << LL_ENDL; if (appconnect_time == 0) { - llwarns << "The SSL/TLS handshake never occurred according to the timings!" << llendl; + LL_WARNS() << "The SSL/TLS handshake never occurred according to the timings!" << LL_ENDL; return; } - llinfos << "SSL/TLS handshake with HTTP server took " << (appconnect_time - connect_time) << " seconds." << llendl; + LL_INFOS() << "SSL/TLS handshake with HTTP server took " << (appconnect_time - connect_time) << " seconds." << LL_ENDL; } if (pretransfer_time == 0) { - llwarns << "The transfer never happened because there was too much in the pipeline (apparently)." << llendl; + LL_WARNS() << "The transfer never happened because there was too much in the pipeline (apparently)." << LL_ENDL; return; } else if (pretransfer_time - appconnect_time >= 1e-5) { - llinfos << "Apparently there was a delay, due to waits in line for the pipeline, of " << (pretransfer_time - appconnect_time) << " seconds before the transfer began." << llendl; + LL_INFOS() << "Apparently there was a delay, due to waits in line for the pipeline, of " << (pretransfer_time - appconnect_time) << " seconds before the transfer began." << LL_ENDL; } if (starttransfer_time == 0) { - llwarns << "No data was ever received from the server according to the timings." << llendl; + LL_WARNS() << "No data was ever received from the server according to the timings." << LL_ENDL; } else { - llinfos << "The time it took to send the request to the server plus the time it took before the server started to reply was " << (starttransfer_time - pretransfer_time) << " seconds." << llendl; + LL_INFOS() << "The time it took to send the request to the server plus the time it took before the server started to reply was " << (starttransfer_time - pretransfer_time) << " seconds." << LL_ENDL; } if (mNothingReceivedYet) { - llinfos << "No data at all was actually received from the server." << llendl; + LL_INFOS() << "No data at all was actually received from the server." << LL_ENDL; } if (mUploadFinished) { - llinfos << "The request upload finished successfully." << llendl; + LL_INFOS() << "The request upload finished successfully." << LL_ENDL; } else if (mLastBytesSent) { - llinfos << "All bytes where sent to libcurl for upload." << llendl; + LL_INFOS() << "All bytes where sent to libcurl for upload." << LL_ENDL; } if (mLastSecond > 0 && mLowSpeedOn) { - llinfos << "The " << (mNothingReceivedYet ? "upload" : "download") << " did last " << mLastSecond << " second" << ((mLastSecond == 1) ? "" : "s") << ", before it timed out." << llendl; + LL_INFOS() << "The " << (mNothingReceivedYet ? "upload" : "download") << " did last " << mLastSecond << " second" << ((mLastSecond == 1) ? "" : "s") << ", before it timed out." << LL_ENDL; } #endif // HTTPTIMEOUT_TESTSUITE } diff --git a/indra/llmessage/aihttptimeout.h b/indra/llmessage/aihttptimeout.h index 1af96c9c79..9d894d16b3 100644 --- a/indra/llmessage/aihttptimeout.h +++ b/indra/llmessage/aihttptimeout.h @@ -91,14 +91,14 @@ class HTTPTimeout : public LLRefCount { static F64 const sClockWidth_10ms; // Time between two clock ticks in 10 ms units. static F64 const sClockWidth_40ms; // Time between two clock ticks in 40 ms units. static U64 sTime_10ms; // Time since the epoch in 10 ms units. -#if defined(CWDEBUG) || defined(DEBUG_CURLIO) +#ifdef CWDEBUG ThreadSafeBufferedCurlEasyRequest* mLockObj; #endif public: HTTPTimeout(AIHTTPTimeoutPolicy const* policy, ThreadSafeBufferedCurlEasyRequest* lock_obj) : mPolicy(policy), mNothingReceivedYet(true), mLowSpeedOn(false), mLastBytesSent(false), mBeingRedirected(false), mUploadFinished(false), mStalled((U64)-1) -#if defined(CWDEBUG) || defined(DEBUG_CURLIO) +#ifdef CWDEBUG , mLockObj(lock_obj) #endif { } @@ -127,7 +127,7 @@ class HTTPTimeout : public LLRefCount { // Called from BufferedCurlEasyRequest::processOutput if a timeout occurred. void print_diagnostics(CurlEasyRequest const* curl_easy_request, char const* eff_url); -#if defined(CWDEBUG) || defined(DEBUG_CURLIO) +#ifdef CWDEBUG void* get_lockobj(void) const { return mLockObj; } #endif @@ -146,7 +146,7 @@ class HTTPTimeout : public LLRefCount { } // namespace curlthread } // namespace AICurlPrivate -#if defined(CWDEBUG) || defined(DEBUG_CURLIO) +#ifdef CWDEBUG extern bool gCurlIo; #endif diff --git a/indra/llmessage/aihttptimeoutpolicy.cpp b/indra/llmessage/aihttptimeoutpolicy.cpp index aaf5bf8e12..80f659bae3 100644 --- a/indra/llmessage/aihttptimeoutpolicy.cpp +++ b/indra/llmessage/aihttptimeoutpolicy.cpp @@ -30,7 +30,6 @@ #include "sys.h" #include "aihttptimeoutpolicy.h" -#define NOMINMAX #include "llerror.h" #include "lldefs.h" #include "v3math.h" @@ -239,41 +238,41 @@ void AIHTTPTimeoutPolicy::base_changed(void) void AIHTTPTimeoutPolicy::setDefaultCurlTimeout(AIHTTPTimeoutPolicy const& timeout) { sDebugSettingsCurlTimeout = timeout; - llinfos << "CurlTimeout Debug Settings now" + LL_INFOS() << "CurlTimeout Debug Settings now" ": DNSLookup: " << sDebugSettingsCurlTimeout.mDNSLookupGrace << "; Connect: " << sDebugSettingsCurlTimeout.mMaximumConnectTime << "; ReplyDelay: " << sDebugSettingsCurlTimeout.mMaximumReplyDelay << "; LowSpeedTime: " << sDebugSettingsCurlTimeout.mLowSpeedTime << "; LowSpeedLimit: " << sDebugSettingsCurlTimeout.mLowSpeedLimit << "; MaxTransaction: " << sDebugSettingsCurlTimeout.mMaximumCurlTransaction << - "; MaxTotalDelay: " << sDebugSettingsCurlTimeout.mMaximumTotalDelay << llendl; + "; MaxTotalDelay: " << sDebugSettingsCurlTimeout.mMaximumTotalDelay << LL_ENDL; if (sDebugSettingsCurlTimeout.mDNSLookupGrace < AITP_default_DNS_lookup_grace) { - llwarns << "CurlTimeoutDNSLookup (" << sDebugSettingsCurlTimeout.mDNSLookupGrace << ") is lower than the built-in default value (" << AITP_default_DNS_lookup_grace << ")." << llendl; + LL_WARNS() << "CurlTimeoutDNSLookup (" << sDebugSettingsCurlTimeout.mDNSLookupGrace << ") is lower than the built-in default value (" << AITP_default_DNS_lookup_grace << ")." << LL_ENDL; } if (sDebugSettingsCurlTimeout.mMaximumConnectTime < AITP_default_maximum_connect_time) { - llwarns << "CurlTimeoutConnect (" << sDebugSettingsCurlTimeout.mMaximumConnectTime << ") is lower than the built-in default value (" << AITP_default_maximum_connect_time << ")." << llendl; + LL_WARNS() << "CurlTimeoutConnect (" << sDebugSettingsCurlTimeout.mMaximumConnectTime << ") is lower than the built-in default value (" << AITP_default_maximum_connect_time << ")." << LL_ENDL; } if (sDebugSettingsCurlTimeout.mMaximumReplyDelay < AITP_default_maximum_reply_delay) { - llwarns << "CurlTimeoutReplyDelay (" << sDebugSettingsCurlTimeout.mMaximumReplyDelay << ") is lower than the built-in default value (" << AITP_default_maximum_reply_delay << ")." << llendl; + LL_WARNS() << "CurlTimeoutReplyDelay (" << sDebugSettingsCurlTimeout.mMaximumReplyDelay << ") is lower than the built-in default value (" << AITP_default_maximum_reply_delay << ")." << LL_ENDL; } if (sDebugSettingsCurlTimeout.mLowSpeedTime < AITP_default_low_speed_time) { - llwarns << "CurlTimeoutLowSpeedTime (" << sDebugSettingsCurlTimeout.mLowSpeedTime << ") is lower than the built-in default value (" << AITP_default_low_speed_time << ")." << llendl; + LL_WARNS() << "CurlTimeoutLowSpeedTime (" << sDebugSettingsCurlTimeout.mLowSpeedTime << ") is lower than the built-in default value (" << AITP_default_low_speed_time << ")." << LL_ENDL; } if (sDebugSettingsCurlTimeout.mLowSpeedLimit > AITP_default_low_speed_limit) { - llwarns << "CurlTimeoutLowSpeedLimit (" << sDebugSettingsCurlTimeout.mLowSpeedLimit << ") is higher than the built-in default value (" << AITP_default_low_speed_limit << ")." << llendl; + LL_WARNS() << "CurlTimeoutLowSpeedLimit (" << sDebugSettingsCurlTimeout.mLowSpeedLimit << ") is higher than the built-in default value (" << AITP_default_low_speed_limit << ")." << LL_ENDL; } if (sDebugSettingsCurlTimeout.mMaximumCurlTransaction < AITP_default_maximum_curl_transaction) { - llwarns << "CurlTimeoutMaxTransaction (" << sDebugSettingsCurlTimeout.mMaximumCurlTransaction << ") is lower than the built-in default value (" << AITP_default_maximum_curl_transaction<< ")." << llendl; + LL_WARNS() << "CurlTimeoutMaxTransaction (" << sDebugSettingsCurlTimeout.mMaximumCurlTransaction << ") is lower than the built-in default value (" << AITP_default_maximum_curl_transaction<< ")." << LL_ENDL; } if (sDebugSettingsCurlTimeout.mMaximumTotalDelay < AITP_default_maximum_total_delay) { - llwarns << "CurlTimeoutMaxTotalDelay (" << sDebugSettingsCurlTimeout.mMaximumTotalDelay << ") is lower than the built-in default value (" << AITP_default_maximum_total_delay << ")." << llendl; + LL_WARNS() << "CurlTimeoutMaxTotalDelay (" << sDebugSettingsCurlTimeout.mMaximumTotalDelay << ") is lower than the built-in default value (" << AITP_default_maximum_total_delay << ")." << LL_ENDL; } } @@ -887,7 +886,7 @@ AIHTTPTimeoutPolicy const* AIHTTPTimeoutPolicy::getTimeoutPolicyByName(std::stri { if (!name.empty()) { - llwarns << "Cannot find AIHTTPTimeoutPolicy with name \"" << name << "\"." << llendl; + LL_WARNS() << "Cannot find AIHTTPTimeoutPolicy with name \"" << name << "\"." << LL_ENDL; } return &sDebugSettingsCurlTimeout; } @@ -905,48 +904,32 @@ AIHTTPTimeoutPolicy const* AIHTTPTimeoutPolicy::getTimeoutPolicyByName(std::stri #define P2(n, b) AIHTTPTimeoutPolicy n##_timeout(#n, b) // Policy name Policy -P(accountingCostResponder); -P(agentStateResponder); -P(appearanceChangeMetricsResponder); -P(assetUploadResponder); P(assetReportHandler); -P(asyncConsoleResponder); -P(avatarPickerResponder); P(authHandler); -P(avatarNameResponder); P2(baseCapabilitiesComplete, transfer_18s_connect_5s); +P2(baseCapabilitiesCompleteTracker, transfer_18s_connect_5s); P(blockingLLSDPost); P(blockingLLSDGet); P(blockingRawGet); -P(charactersResponder); -P(checkAgentAppearanceServiceResponder); P(classifiedStatsResponder); -P(consoleResponder); -P2(crashLoggerResponder, transfer_22s_connect_10s); -P(createInventoryCategoryResponder); P(emeraldDicDownloader); P(environmentApplyResponder); P(environmentRequestResponder); -P(estateChangeInfoResponder); P2(eventPollResponder, reply_60s); -P(fetchInventoryResponder); +P(FetchItemHttpHandler); P(fetchScriptLimitsAttachmentInfoResponder); P(fetchScriptLimitsRegionDetailsResponder); P(fetchScriptLimitsRegionInfoResponder); P(fetchScriptLimitsRegionSummaryResponder); P(fnPtrResponder); -P2(gamingDataReceived, transfer_22s_connect_10s); -P2(groupMemberDataResponder, transfer_300s); +P(floaterPermsResponder); P2(groupProposalBallotResponder, transfer_300s); P(homeLocationResponder); P2(HTTPGetResponder, reply_15s); P(iamHere); -P(iamHereVoice); -P2(inventoryModelFetchDescendentsResponder, transfer_300s); -P(inventoryModelFetchItemResponder); +P2(BGFolderHttpHandler, transfer_300s); +P(BGItemHttpHandler); P(lcl_responder); -P(MPImportGetResponder); -P(MPImportPostResponder); P(mapLayerResponder); P(materialsResponder); P2(maturityPreferences, transfer_30s_connect_10s); @@ -957,40 +940,25 @@ P2(meshHeaderResponder, connect_30s); P2(meshLODResponder, connect_30s); P2(meshPhysicsShapeResponder, connect_30s); P2(meshSkinInfoResponder, connect_30s); -P(mimeDiscoveryResponder); -P(moderationResponder); -P(navMeshRebakeResponder); -P(navMeshResponder); -P(navMeshStatusResponder); -P(newAgentInventoryVariablePriceResponder); P(objectCostResponder); -P(objectLinksetsResponder); P(physicsFlagsResponder); -P(placeAvatarTeleportResponder); P(productInfoRequestResponder); P(regionResponder); P(remoteParcelRequestResponder); P(requestAgentUpdateAppearance); P(responderIgnore); -P(sessionInviteResponder); P(setDisplayNameResponder); -P2(simulatorFeaturesReceived, transfer_22s_connect_10s); -P(startConferenceChatResponder); +P2(baseFeaturesReceived, transfer_22s_connect_10s); P2(startGroupVoteResponder, transfer_300s); -P(terrainLinksetsResponder); P(translationReceiver); P(uploadModelPremissionsResponder); -P(userReportResponder); P(verifiedDestinationResponder); P(viewerChatterBoxInvitationAcceptResponder); -P(viewerMediaOpenIDResponder); -P(viewerMediaWebProfileResponder); P(viewerStatsResponder); -P(vivoxVoiceAccountProvisionResponder); -P(vivoxVoiceClientCapResponder); P(voiceCallCapResponder); P(webProfileResponders); P(wholeModelFeeResponder); P(wholeModelUploadResponder); P2(XMLRPCResponder, connect_40s); - +P(getUpdateInfoResponder); +P2(AISAPIResponder, connect_60s); \ No newline at end of file diff --git a/indra/llmessage/aihttptimeoutpolicy.h b/indra/llmessage/aihttptimeoutpolicy.h index 6c8fa06832..ba5347482c 100644 --- a/indra/llmessage/aihttptimeoutpolicy.h +++ b/indra/llmessage/aihttptimeoutpolicy.h @@ -95,7 +95,7 @@ class AIHTTPTimeoutPolicy { void sanity_checks(void) const; // Accessors. - char const* name(void) const { return mName; } + char const* name(void) const { return mName ? mName : "AIHTTPTimeoutPolicyBase"; } U16 getConnectTimeout(std::string const& hostname) const; U16 getDNSLookup(void) const { return mDNSLookupGrace; } U16 getConnect(void) const { return mMaximumConnectTime; } diff --git a/indra/llmessage/debug_libcurl.cpp b/indra/llmessage/debug_libcurl.cpp index e07cc4ba42..d5c89d4af5 100644 --- a/indra/llmessage/debug_libcurl.cpp +++ b/indra/llmessage/debug_libcurl.cpp @@ -565,7 +565,7 @@ void debug_curl_remove_easy(CURL* handle) handles.erase(iter); Dout(dc::warning, "debug_curl_remove_easy(" << (void*)handle << "): removed"); } - llassert(!print_debug(handle)); + llassert(!gDebugCurlTerse || !print_debug(handle)); } bool debug_curl_print_debug(CURL* handle) @@ -577,34 +577,28 @@ extern "C" { void debug_curl_easy_cleanup(CURL* handle) { + Dout(dc::curltr(print_debug(handle)), "curl_easy_cleanup(" << (AICURL*)handle << ")"); curl_easy_cleanup(handle); - if (print_debug(handle)) - { - Dout(dc::curltr, "curl_easy_cleanup(" << (AICURL*)handle << ")"); - } } CURL* debug_curl_easy_duphandle(CURL* handle) { - CURL* ret; - ret = curl_easy_duphandle(handle); - if (!print_debug(handle)) return ret; - Dout(dc::curltr, "curl_easy_duphandle(" << (AICURL*)handle << ") = " << (AICURL*)ret); + Dout(dc::curltr(print_debug(handle))|continued_cf, "curl_easy_duphandle(" << (AICURL*)handle << ") = "); + CURL* ret = curl_easy_duphandle(handle); + Dout(dc::finish, (AICURL*)ret); return ret; } char* debug_curl_easy_escape(CURL* curl, char* url, int length) { - char* ret; - ret = curl_easy_escape(curl, url, length); - if (!print_debug(curl)) return ret; - Dout(dc::curltr, "curl_easy_escape(" << (AICURL*)curl << ", \"" << url << "\", " << length << ") = \"" << ret << '"'); + Dout(dc::curltr(print_debug(curl))|continued_cf, "curl_easy_escape(" << (AICURL*)curl << ", \"" << url << "\", " << length << ") = "); + char* ret = curl_easy_escape(curl, url, length); + Dout(dc::finish, '"' << ret << '"'); return ret; } CURLcode debug_curl_easy_getinfo(CURL* handle, CURLINFO info, ...) { - CURLcode ret; va_list ap; union param_type { void* some_ptr; @@ -616,27 +610,27 @@ CURLcode debug_curl_easy_getinfo(CURL* handle, CURLINFO info, ...) va_start(ap, info); param.some_ptr = va_arg(ap, void*); va_end(ap); - ret = curl_easy_getinfo(handle, info, param.some_ptr); - if (!print_debug(handle)) return ret; + Dout(dc::curltr(print_debug(handle))|continued_cf, "curl_easy_getinfo(" << (AICURL*)handle << ", " << info << ", "); + CURLcode ret = curl_easy_getinfo(handle, info, param.some_ptr); if (info == CURLINFO_PRIVATE) { - Dout(dc::curltr, "curl_easy_getinfo(" << (AICURL*)handle << ", " << info << ", 0x" << std::hex << (size_t)param.some_ptr << std::dec << ") = " << ret); + Dout(dc::finish, "0x" << std::hex << (size_t)param.some_ptr << std::dec << ") = " << ret); } else { switch((info & CURLINFO_TYPEMASK)) { case CURLINFO_STRING: - Dout(dc::curltr, "curl_easy_getinfo(" << (AICURL*)handle << ", " << info << ", (char**){ \"" << (ret == CURLE_OK ? *param.char_ptr : " ") << "\" }) = " << ret); + Dout(dc::finish, "(char**){ \"" << (ret == CURLE_OK ? *param.char_ptr : " ") << "\" }) = " << ret); break; case CURLINFO_LONG: - Dout(dc::curltr, "curl_easy_getinfo(" << (AICURL*)handle << ", " << info << ", (long*){ " << (ret == CURLE_OK ? *param.long_ptr : 0L) << "L }) = " << ret); + Dout(dc::finish, "(long*){ " << (ret == CURLE_OK ? *param.long_ptr : 0L) << "L }) = " << ret); break; case CURLINFO_DOUBLE: - Dout(dc::curltr, "curl_easy_getinfo(" << (AICURL*)handle << ", " << info << ", (double*){" << (ret == CURLE_OK ? *param.double_ptr : 0.) << "}) = " << ret); + Dout(dc::finish, "(double*){" << (ret == CURLE_OK ? *param.double_ptr : 0.) << "}) = " << ret); break; case CURLINFO_SLIST: - Dout(dc::curltr, "curl_easy_getinfo(" << (AICURL*)handle << ", " << info << ", (curl_slist**){ " << (ret == CURLE_OK ? **param.curl_slist_ptr : unchanged_slist) << " }) = " << ret); + Dout(dc::finish, "(curl_slist**){ " << (ret == CURLE_OK ? **param.curl_slist_ptr : unchanged_slist) << " }) = " << ret); break; } } @@ -645,36 +639,32 @@ CURLcode debug_curl_easy_getinfo(CURL* handle, CURLINFO info, ...) CURL* debug_curl_easy_init(void) { - CURL* ret; - ret = curl_easy_init(); - if (gDebugCurlTerse) return ret; - Dout(dc::curltr, "curl_easy_init() = " << (AICURL*)ret); + Dout(dc::curltr(!gDebugCurlTerse)|continued_cf, "curl_easy_init() = "); + CURL* ret = curl_easy_init(); + Dout(dc::finish, (AICURL*)ret); return ret; } CURLcode debug_curl_easy_pause(CURL* handle, int bitmask) { - CURLcode ret; - ret = curl_easy_pause(handle, bitmask); - if (!print_debug(handle)) return ret; - Dout(dc::curltr, "curl_easy_pause(" << (AICURL*)handle << ", 0x" << std::hex << bitmask << std::dec << ") = " << ret); + Dout(dc::curltr(print_debug(handle))|continued_cf, "curl_easy_pause(" << (AICURL*)handle << ", 0x" << std::hex << bitmask << std::dec << ") = "); + CURLcode ret = curl_easy_pause(handle, bitmask); + Dout(dc::finish, ret); return ret; } CURLcode debug_curl_easy_perform(CURL* handle) { - CURLcode ret; - ret = curl_easy_perform(handle); - if (!print_debug(handle)) return ret; - Dout(dc::curltr, "curl_easy_perform(" << (AICURL*)handle << ") = " << ret); + Dout(dc::curltr(print_debug(handle))|continued_cf, "curl_easy_perform(" << (AICURL*)handle << ") = "); + CURLcode ret = curl_easy_perform(handle); + Dout(dc::finish, ret); return ret; } void debug_curl_easy_reset(CURL* handle) { + Dout(dc::curltr(print_debug(handle)), "curl_easy_reset(" << (AICURL*)handle << ")"); curl_easy_reset(handle); - if (!print_debug(handle)) return; - Dout(dc::curltr, "curl_easy_reset(" << (AICURL*)handle << ")"); } CURLcode debug_curl_easy_setopt(CURL* handle, CURLoption option, ...) @@ -710,11 +700,9 @@ CURLcode debug_curl_easy_setopt(CURL* handle, CURLoption option, ...) { case CURLOPTTYPE_LONG: { + Dout(dc::curltr(print_debug(handle))|continued_cf, "curl_easy_setopt(" << (AICURL*)handle << ", " << option << ", " << param.along << "L) = "); ret = curl_easy_setopt(handle, option, param.along); - if (print_debug(handle)) - { - Dout(dc::curltr, "curl_easy_setopt(" << (AICURL*)handle << ", " << option << ", " << param.along << "L) = " << ret); - } + Dout(dc::finish, ret); if (option == CURLOPT_POSTFIELDSIZE) { postfieldsize = param.along; @@ -723,9 +711,7 @@ CURLcode debug_curl_easy_setopt(CURL* handle, CURLoption option, ...) } case CURLOPTTYPE_OBJECTPOINT: { - ret = curl_easy_setopt(handle, option, param.ptr); - if (!print_debug(handle)) break; - LibcwDoutScopeBegin(LIBCWD_DEBUGCHANNELS, libcwd::libcw_do, dc::curltr) + LibcwDoutScopeBegin(LIBCWD_DEBUGCHANNELS, libcwd::libcw_do, dc::curltr(print_debug(handle))|continued_cf) LibcwDoutStream << "curl_easy_setopt(" << (AICURL*)handle << ", " << option << ", "; // For a subset of all options that take a char*, print the string passed. if (option == CURLOPT_PROXY || // Set HTTP proxy to use. The parameter should be a char* to a zero terminated string holding the host name or dotted IP address. @@ -771,8 +757,10 @@ CURLcode debug_curl_easy_setopt(CURL* handle, CURLoption option, ...) { LibcwDoutStream << "(object*)0x" << std::hex << (size_t)param.ptr << std::dec << ")"; } - LibcwDoutStream << " = " << ret; + LibcwDoutStream << " = "; LibcwDoutScopeEnd; + ret = curl_easy_setopt(handle, option, param.ptr); + Dout(dc::finish, ret); if (option == CURLOPT_HTTPHEADER && param.ptr) { debug::Indent indent(2); @@ -787,19 +775,15 @@ CURLcode debug_curl_easy_setopt(CURL* handle, CURLoption option, ...) break; } case CURLOPTTYPE_FUNCTIONPOINT: + Dout(dc::curltr(print_debug(handle))|continued_cf, "curl_easy_setopt(" << (AICURL*)handle << ", " << option << ", (function*)0x" << std::hex << (size_t)param.ptr << std::dec << ") = "); ret = curl_easy_setopt(handle, option, param.ptr); - if (print_debug(handle)) - { - Dout(dc::curltr, "curl_easy_setopt(" << (AICURL*)handle << ", " << option << ", (function*)0x" << std::hex << (size_t)param.ptr << std::dec << ") = " << ret); - } + Dout(dc::finish, ret); break; case CURLOPTTYPE_OFF_T: { + Dout(dc::curltr(print_debug(handle))|continued_cf, "curl_easy_setopt(" << (AICURL*)handle << ", " << option << ", (curl_off_t)" << param.offset << ") = "); ret = curl_easy_setopt(handle, option, param.offset); - if (print_debug(handle)) - { - Dout(dc::curltr, "curl_easy_setopt(" << (AICURL*)handle << ", " << option << ", (curl_off_t)" << param.offset << ") = " << ret); - } + Dout(dc::finish, ret); if (option == CURLOPT_POSTFIELDSIZE_LARGE) { postfieldsize = (long)param.offset; @@ -814,103 +798,93 @@ CURLcode debug_curl_easy_setopt(CURL* handle, CURLoption option, ...) char const* debug_curl_easy_strerror(CURLcode errornum) { - char const* ret; - ret = curl_easy_strerror(errornum); - if (gDebugCurlTerse) return ret; - Dout(dc::curltr, "curl_easy_strerror(" << errornum << ") = \"" << ret << '"'); + Dout(dc::curltr(!gDebugCurlTerse)|continued_cf, "curl_easy_strerror(" << errornum << ") = "); + char const* ret = curl_easy_strerror(errornum); + Dout(dc::finish, '"' << ret << '"'); return ret; } char* debug_curl_easy_unescape(CURL* curl, char* url, int inlength, int* outlength) { - char* ret; - ret = curl_easy_unescape(curl, url, inlength, outlength); - if (!print_debug(curl)) return ret; - Dout(dc::curltr, "curl_easy_unescape(" << (AICURL*)curl << ", \"" << url << "\", " << inlength << ", " << ((ret && outlength) ? *outlength : 1) << ") = \"" << ret << '"'); + Dout(dc::curltr(print_debug(curl))|continued_cf, "curl_easy_unescape(" << (AICURL*)curl << ", \"" << url << "\", " << inlength << ", "); + char* ret = curl_easy_unescape(curl, url, inlength, outlength); + Dout(dc::finish, ((ret && outlength) ? *outlength : 1) << ") = \"" << ret << '"'); return ret; } void debug_curl_free(char* ptr) { + Dout(dc::curltr(!gDebugCurlTerse), "curl_free(0x" << std::hex << (size_t)ptr << std::dec << ")"); curl_free(ptr); - if (gDebugCurlTerse) return; - Dout(dc::curltr, "curl_free(0x" << std::hex << (size_t)ptr << std::dec << ")"); } time_t debug_curl_getdate(char const* datestring, time_t* now) { - time_t ret; - ret = curl_getdate(datestring, now); - if (gDebugCurlTerse) return ret; - Dout(dc::curltr, "curl_getdate(\"" << datestring << "\", " << (now == NULL ? "NULL" : "") << ") = " << ret); + Dout(dc::curltr(!gDebugCurlTerse)|continued_cf, "curl_getdate(\"" << datestring << "\", " << (now == NULL ? "NULL" : "") << ") = "); + time_t ret = curl_getdate(datestring, now); + Dout(dc::finish, ret); return ret; } void debug_curl_global_cleanup(void) { - curl_global_cleanup(); Dout(dc::curltr, "curl_global_cleanup()"); + curl_global_cleanup(); } CURLcode debug_curl_global_init(long flags) { - CURLcode ret; - ret = curl_global_init(flags); - Dout(dc::curltr, "curl_global_init(0x" << std::hex << flags << std::dec << ") = " << ret); + Dout(dc::curltr|continued_cf, "curl_global_init(0x" << std::hex << flags << std::dec << ") = "); + CURLcode ret = curl_global_init(flags); + Dout(dc::finish, ret); return ret; } CURLMcode debug_curl_multi_add_handle(CURLM* multi_handle, CURL* easy_handle) { - CURLMcode ret; - ret = curl_multi_add_handle(multi_handle, easy_handle); - if (gDebugCurlTerse) return ret; - Dout(dc::curltr, "curl_multi_add_handle(" << (AICURLM*)multi_handle << ", " << (AICURL*)easy_handle << ") = " << ret); + Dout(dc::curltr(!gDebugCurlTerse)|continued_cf, "curl_multi_add_handle(" << (AICURLM*)multi_handle << ", " << (AICURL*)easy_handle << ") = "); + CURLMcode ret = curl_multi_add_handle(multi_handle, easy_handle); + Dout(dc::finish, ret); return ret; } CURLMcode debug_curl_multi_assign(CURLM* multi_handle, curl_socket_t sockfd, void* sockptr) { - CURLMcode ret; - ret = curl_multi_assign(multi_handle, sockfd, sockptr); - if (gDebugCurlTerse) return ret; - Dout(dc::curltr, "curl_multi_assign(" << (AICURLM*)multi_handle << ", " << Socket(sockfd) << ", " << sockptr << ") = " << ret); + Dout(dc::curltr(!gDebugCurlTerse)|continued_cf, "curl_multi_assign(" << (AICURLM*)multi_handle << ", " << Socket(sockfd) << ", " << sockptr << ") = "); + CURLMcode ret = curl_multi_assign(multi_handle, sockfd, sockptr); + Dout(dc::finish, ret); return ret; } CURLMcode debug_curl_multi_cleanup(CURLM* multi_handle) { - CURLMcode ret; - ret = curl_multi_cleanup(multi_handle); - if (gDebugCurlTerse) return ret; - Dout(dc::curltr, "curl_multi_cleanup(" << (AICURLM*)multi_handle << ") = " << ret); + Dout(dc::curltr(!gDebugCurlTerse)|continued_cf, "curl_multi_cleanup(" << (AICURLM*)multi_handle << ") = "); + CURLMcode ret = curl_multi_cleanup(multi_handle); + Dout(dc::finish, ret); return ret; } CURLMsg* debug_curl_multi_info_read(CURLM* multi_handle, int* msgs_in_queue) { - CURLMsg* ret; - ret = curl_multi_info_read(multi_handle, msgs_in_queue); - if (gDebugCurlTerse) return ret; - Dout(dc::curltr, "curl_multi_info_read(" << (AICURLM*)multi_handle << ", {" << *msgs_in_queue << "}) = " << ret); + Dout(dc::curltr(!gDebugCurlTerse)|continued_cf, "curl_multi_info_read(" << (AICURLM*)multi_handle << ", "); + CURLMsg* ret = curl_multi_info_read(multi_handle, msgs_in_queue); + Dout(dc::finish, "{" << *msgs_in_queue << "}) = " << ret); return ret; } CURLM* debug_curl_multi_init(void) { - CURLM* ret; - ret = curl_multi_init(); - if (gDebugCurlTerse) return ret; - Dout(dc::curltr, "curl_multi_init() = " << (AICURLM*)ret); + Dout(dc::curltr(!gDebugCurlTerse)|continued_cf, "curl_multi_init() = "); + CURLM* ret = curl_multi_init(); + Dout(dc::finish, (AICURLM*)ret); return ret; } CURLMcode debug_curl_multi_remove_handle(CURLM* multi_handle, CURL* easy_handle) { - CURLMcode ret; - ret = curl_multi_remove_handle(multi_handle, easy_handle); - if (!print_debug(easy_handle)) return ret; - Dout(dc::curltr, "curl_multi_remove_handle(" << (AICURLM*)multi_handle << ", " << (AICURL*)easy_handle << ") = " << ret); + Dout(dc::curltr(print_debug(easy_handle))|continued_cf, "curl_multi_remove_handle(" << (AICURLM*)multi_handle << ", " << (AICURL*)easy_handle << ") = "); + CURLMcode ret = curl_multi_remove_handle(multi_handle, easy_handle); + Dout(dc::finish, ret); return ret; } @@ -945,24 +919,24 @@ CURLMcode debug_curl_multi_setopt(CURLM* multi_handle, CURLMoption option, ...) switch (param_type) { case CURLOPTTYPE_LONG: + Dout(dc::curltr(!gDebugCurlTerse)|continued_cf, "curl_easy_setopt(" << (AICURLM*)multi_handle << ", " << option << ", " << param.along << "L) = "); ret = curl_multi_setopt(multi_handle, option, param.along); - if (gDebugCurlTerse) break; - Dout(dc::curltr, "curl_easy_setopt(" << (AICURLM*)multi_handle << ", " << option << ", " << param.along << "L) = " << ret); + Dout(dc::finish, ret); break; case CURLOPTTYPE_OBJECTPOINT: + Dout(dc::curltr(!gDebugCurlTerse)|continued_cf, "curl_easy_setopt(" << (AICURLM*)multi_handle << ", " << option << ", (object*)0x" << std::hex << (size_t)param.ptr << std::dec << ") = "); ret = curl_multi_setopt(multi_handle, option, param.ptr); - if (gDebugCurlTerse) break; - Dout(dc::curltr, "curl_easy_setopt(" << (AICURLM*)multi_handle << ", " << option << ", (object*)0x" << std::hex << (size_t)param.ptr << std::dec << ") = " << ret); + Dout(dc::finish, ret); break; case CURLOPTTYPE_FUNCTIONPOINT: + Dout(dc::curltr(!gDebugCurlTerse)|continued_cf, "curl_easy_setopt(" << (AICURLM*)multi_handle << ", " << option << ", (function*)0x" << std::hex << (size_t)param.ptr << std::dec << ") = "); ret = curl_multi_setopt(multi_handle, option, param.ptr); - if (gDebugCurlTerse) break; - Dout(dc::curltr, "curl_easy_setopt(" << (AICURLM*)multi_handle << ", " << option << ", (function*)0x" << std::hex << (size_t)param.ptr << std::dec << ") = " << ret); + Dout(dc::finish, ret); break; case CURLOPTTYPE_OFF_T: + Dout(dc::curltr(!gDebugCurlTerse)|continued_cf, "curl_easy_setopt(" << (AICURLM*)multi_handle << ", " << option << ", (curl_off_t)" << param.offset << ") = "); ret = curl_multi_setopt(multi_handle, option, param.offset); - if (gDebugCurlTerse) break; - Dout(dc::curltr, "curl_easy_setopt(" << (AICURLM*)multi_handle << ", " << option << ", (curl_off_t)" << param.offset << ") = " << ret); + Dout(dc::finish, ret); break; default: // Stop compiler complaining about no default. break; @@ -972,54 +946,47 @@ CURLMcode debug_curl_multi_setopt(CURLM* multi_handle, CURLMoption option, ...) CURLMcode debug_curl_multi_socket_action(CURLM* multi_handle, curl_socket_t sockfd, int ev_bitmask, int* running_handles) { - CURLMcode ret; - ret = curl_multi_socket_action(multi_handle, sockfd, ev_bitmask, running_handles); - if (gDebugCurlTerse) return ret; - Dout(dc::curltr, "curl_multi_socket_action(" << (AICURLM*)multi_handle << ", " << Socket(sockfd) << - ", " << EvBitmask(ev_bitmask) << ", {" << (ret == CURLM_OK ? *running_handles : 0) << "}) = " << ret); + Dout(dc::curltr(!gDebugCurlTerse)|continued_cf, "curl_multi_socket_action(" << (AICURLM*)multi_handle << ", " << Socket(sockfd) << ", " << EvBitmask(ev_bitmask) << ", "); + CURLMcode ret = curl_multi_socket_action(multi_handle, sockfd, ev_bitmask, running_handles); + Dout(dc::finish, "{" << (ret == CURLM_OK ? *running_handles : 0) << "}) = " << ret); return ret; } char const* debug_curl_multi_strerror(CURLMcode errornum) { - char const* ret; - ret = curl_multi_strerror(errornum); - if (gDebugCurlTerse) return ret; - Dout(dc::curltr, "curl_multi_strerror(" << errornum << ") = \"" << ret << '"'); + Dout(dc::curltr(!gDebugCurlTerse)|continued_cf, "curl_multi_strerror(" << errornum << ") = "); + char const* ret = curl_multi_strerror(errornum); + Dout(dc::finish, '"' << ret << '"'); return ret; } struct curl_slist* debug_curl_slist_append(struct curl_slist* list, char const* string) { - struct curl_slist* ret; - ret = curl_slist_append(list, string); - if (gDebugCurlTerse) return ret; - Dout(dc::curltr, "curl_slist_append((curl_slist)@0x" << std::hex << (size_t)list << std::dec << ", \"" << string << "\") = " << *ret); + Dout(dc::curltr(!gDebugCurlTerse)|continued_cf, "curl_slist_append((curl_slist)@0x" << std::hex << (size_t)list << std::dec << ", \"" << string << "\") = "); + struct curl_slist* ret = curl_slist_append(list, string); + Dout(dc::finish, *ret); return ret; } void debug_curl_slist_free_all(struct curl_slist* list) { + Dout(dc::curltr(!gDebugCurlTerse), "curl_slist_free_all((curl_slist)@0x" << std::hex << (size_t)list << std::dec << ")"); curl_slist_free_all(list); - if (gDebugCurlTerse) return; - Dout(dc::curltr, "curl_slist_free_all((curl_slist)@0x" << std::hex << (size_t)list << std::dec << ")"); } char* debug_curl_unescape(char const* url, int length) { - char* ret; - ret = curl_unescape(url, length); - if (gDebugCurlTerse) return ret; - Dout(dc::curltr, "curl_unescape(\"" << url << "\", " << length << ") = \"" << ret << '"'); + Dout(dc::curltr(!gDebugCurlTerse)|continued_cf, "curl_unescape(\"" << url << "\", " << length << ") = "); + char* ret = curl_unescape(url, length); + Dout(dc::finish, '"' << ret << '"'); return ret; } char* debug_curl_version(void) { - char* ret; - ret = curl_version(); - if (gDebugCurlTerse) return ret; - Dout(dc::curltr, "curl_version() = \"" << ret << '"'); + Dout(dc::curltr(!gDebugCurlTerse)|continued_cf, "curl_version() = "); + char* ret = curl_version(); + Dout(dc::finish, '"' << ret << '"'); return ret; } diff --git a/indra/llmessage/llares.cpp b/indra/llmessage/llares.cpp index 91d13dac3e..6939a50298 100644 --- a/indra/llmessage/llares.cpp +++ b/indra/llmessage/llares.cpp @@ -56,13 +56,13 @@ LLAres::HostResponder::~HostResponder() void LLAres::HostResponder::hostResult(const hostent *ent) { - llinfos << "LLAres::HostResponder::hostResult not implemented" << llendl; + LL_INFOS() << "LLAres::HostResponder::hostResult not implemented" << LL_ENDL; } void LLAres::HostResponder::hostError(int code) { - llinfos << "LLAres::HostResponder::hostError " << code << ": " - << LLAres::strerror(code) << llendl; + LL_INFOS() << "LLAres::HostResponder::hostError " << code << ": " + << LLAres::strerror(code) << LL_ENDL; } LLAres::NameInfoResponder::~NameInfoResponder() @@ -72,14 +72,14 @@ LLAres::NameInfoResponder::~NameInfoResponder() void LLAres::NameInfoResponder::nameInfoResult(const char *node, const char *service) { - llinfos << "LLAres::NameInfoResponder::nameInfoResult not implemented" - << llendl; + LL_INFOS() << "LLAres::NameInfoResponder::nameInfoResult not implemented" + << LL_ENDL; } void LLAres::NameInfoResponder::nameInfoError(int code) { - llinfos << "LLAres::NameInfoResponder::nameInfoError " << code << ": " - << LLAres::strerror(code) << llendl; + LL_INFOS() << "LLAres::NameInfoResponder::nameInfoError " << code << ": " + << LLAres::strerror(code) << LL_ENDL; } LLAres::QueryResponder::~QueryResponder() @@ -88,14 +88,14 @@ LLAres::QueryResponder::~QueryResponder() void LLAres::QueryResponder::queryResult(const char *buf, size_t len) { - llinfos << "LLAres::QueryResponder::queryResult not implemented" - << llendl; + LL_INFOS() << "LLAres::QueryResponder::queryResult not implemented" + << LL_ENDL; } void LLAres::QueryResponder::queryError(int code) { - llinfos << "LLAres::QueryResponder::queryError " << code << ": " - << LLAres::strerror(code) << llendl; + LL_INFOS() << "LLAres::QueryResponder::queryError " << code << ": " + << LLAres::strerror(code) << LL_ENDL; } LLAres::LLAres() : @@ -106,7 +106,7 @@ LLAres::LLAres() : if (ares_library_init( ARES_LIB_INIT_ALL ) != ARES_SUCCESS || ares_init(&chan_) != ARES_SUCCESS) { - llwarns << "Could not succesfully initialize ares!" << llendl; + LL_WARNS() << "Could not succesfully initialize ares!" << LL_ENDL; return; } @@ -162,12 +162,26 @@ void LLAres::getSrvRecords(const std::string &name, SrvResponder *resp) } void LLAres::rewriteURI(const std::string &uri, UriRewriteResponder *resp) -{ - llinfos << "Rewriting " << uri << llendl; +{ + if (resp && uri.size()) + { + LLURI* pURI = new LLURI(uri); + + resp->mUri = *pURI; - resp->mUri = LLURI(uri); - search("_" + resp->mUri.scheme() + "._tcp." + resp->mUri.hostName(), - RES_SRV, resp); + delete pURI; + + if (!resp->mUri.scheme().size() || !resp->mUri.hostName().size()) + { + return; + } + + //LL_INFOS() << "LLAres::rewriteURI (" << uri << ") search: '" << "_" + resp->mUri.scheme() + "._tcp." + resp->mUri.hostName() << "'" << LL_ENDL; + + search("_" + resp->mUri.scheme() + "._tcp." + resp->mUri.hostName(), RES_SRV, resp); + + + } } LLQueryResponder::LLQueryResponder() @@ -237,8 +251,8 @@ int LLQueryResponder::parseRR(const char *buf, size_t len, const char *&pos, r = new LLSrvRecord(rrname, rrttl); break; default: - llinfos << "LLQueryResponder::parseRR got unknown RR type " << rrtype - << llendl; + LL_INFOS() << "LLQueryResponder::parseRR got unknown RR type " << rrtype + << LL_ENDL; return ARES_EBADRESP; } @@ -319,7 +333,7 @@ void LLQueryResponder::queryResult(const char *buf, size_t len) mType = (LLResType) t; break; default: - llinfos << "Cannot grok query type " << t << llendl; + LL_INFOS() << "Cannot grok query type " << t << LL_ENDL; ret = ARES_EBADQUERY; goto bail; } @@ -359,7 +373,7 @@ void LLQueryResponder::queryResult(const char *buf, size_t len) void LLQueryResponder::querySuccess() { - llinfos << "LLQueryResponder::queryResult not implemented" << llendl; + LL_INFOS() << "LLQueryResponder::queryResult not implemented" << LL_ENDL; } void LLAres::SrvResponder::querySuccess() @@ -379,23 +393,23 @@ void LLAres::SrvResponder::queryError(int code) void LLAres::SrvResponder::srvResult(const dns_rrs_t &ents) { - llinfos << "LLAres::SrvResponder::srvResult not implemented" << llendl; + LL_INFOS() << "LLAres::SrvResponder::srvResult not implemented" << LL_ENDL; for (size_t i = 0; i < ents.size(); i++) { const LLSrvRecord *s = (const LLSrvRecord *) ents[i].get(); - llinfos << "[" << i << "] " << s->host() << ":" << s->port() + LL_INFOS() << "[" << i << "] " << s->host() << ":" << s->port() << " priority " << s->priority() << " weight " << s->weight() - << llendl; + << LL_ENDL; } } void LLAres::SrvResponder::srvError(int code) { - llinfos << "LLAres::SrvResponder::srvError " << code << ": " - << LLAres::strerror(code) << llendl; + LL_INFOS() << "LLAres::SrvResponder::srvError " << code << ": " + << LLAres::strerror(code) << LL_ENDL; } static void nameinfo_callback_1_5(void *arg, int status, int timeouts, @@ -797,11 +811,11 @@ void LLAres::UriRewriteResponder::querySuccess() void LLAres::UriRewriteResponder::rewriteResult( const std::vector &uris) { - llinfos << "LLAres::UriRewriteResponder::rewriteResult not implemented" - << llendl; + LL_INFOS() << "LLAres::UriRewriteResponder::rewriteResult not implemented" + << LL_ENDL; for (size_t i = 0; i < uris.size(); i++) { - llinfos << "[" << i << "] " << uris[i] << llendl; + LL_INFOS() << "[" << i << "] " << uris[i] << LL_ENDL; } } diff --git a/indra/llmessage/llareslistener.cpp b/indra/llmessage/llareslistener.cpp index 58b8a05a9e..3d65906b98 100644 --- a/indra/llmessage/llareslistener.cpp +++ b/indra/llmessage/llareslistener.cpp @@ -93,5 +93,12 @@ class UriRewriteResponder: public LLAres::UriRewriteResponder void LLAresListener::rewriteURI(const LLSD& data) { - mAres->rewriteURI(data["uri"], new UriRewriteResponder(data)); + if (mAres) + { + mAres->rewriteURI(data["uri"], new UriRewriteResponder(data)); + } + else + { + LL_INFOS() << "LLAresListener::rewriteURI requested without Ares present. Ignoring: " << data << LL_ENDL; + } } diff --git a/indra/llmessage/llassetstorage.cpp b/indra/llmessage/llassetstorage.cpp index fd30f92495..5e139e7cb5 100644 --- a/indra/llmessage/llassetstorage.cpp +++ b/indra/llmessage/llassetstorage.cpp @@ -58,8 +58,40 @@ const LLUUID CATEGORIZE_LOST_AND_FOUND_ID(std::string("00000000-0000-0000-0000-0 const U64 TOXIC_ASSET_LIFETIME = (120 * 1000000); // microseconds -LLTempAssetStorage::~LLTempAssetStorage() +namespace { + bool operator == (const LLAssetStorage::LLGetAssetCallback &lhs, const LLAssetStorage::LLGetAssetCallback &rhs) + { + auto fnPtrLhs = lhs.target(); + auto fnPtrRhs = rhs.target(); + if (fnPtrLhs && fnPtrRhs) + return (*fnPtrLhs == *fnPtrRhs); + else if (!fnPtrLhs && !fnPtrRhs) + return true; + return false; + } + +// Rider: This is the general case of the operator declared above. The code compares the callback +// passed into the LLAssetStorage functions to determine if there are duplicated requests for an +// asset. Unfortunately std::function does not provide a direct way to compare two variables so +// we define the operator here. +// XCode is not very happy with the variadic temples in use below so we will just define the specific +// case of comparing two LLGetAssetCallback objects since that is all we really use. +// +// template +// bool operator == (const std::function &a, const std::function &b) +// { +// typedef T(fnType)(U...); +// +// auto fnPtrA = a.target(); +// auto fnPtrB = b.target(); +// if (fnPtrA && fnPtrB) +// return (*fnPtrA == *fnPtrB); +// else if (!fnPtrA && !fnPtrB) +// return true; +// return false; +// } + } ///---------------------------------------------------------------------------- @@ -149,33 +181,54 @@ void LLAssetInfo::setFromNameValue( const LLNameValue& nv ) setName( buf ); buf.assign( str, pos2, std::string::npos ); setDescription( buf ); - LL_DEBUGS("AssetStorage") << "uuid: " << mUuid << llendl; - LL_DEBUGS("AssetStorage") << "creator: " << mCreatorID << llendl; + LL_DEBUGS("AssetStorage") << "uuid: " << mUuid << LL_ENDL; + LL_DEBUGS("AssetStorage") << "creator: " << mCreatorID << LL_ENDL; } +///---------------------------------------------------------------------------- +/// LLBaseDownloadRequest +///---------------------------------------------------------------------------- + +LLBaseDownloadRequest::LLBaseDownloadRequest(const LLUUID &uuid, const LLAssetType::EType type) + : mUUID(uuid), + mType(type), + mDownCallback(), + mUserData(NULL), + mHost(), + mIsTemp(FALSE), + mIsPriority(FALSE), + mDataSentInFirstPacket(FALSE), + mDataIsInVFS(FALSE) +{ + // Need to guarantee that this time is up to date, we may be creating a circuit even though we haven't been + // running a message system loop. + mTime = LLMessageSystem::getMessageTimeSeconds(TRUE); +} + +// virtual +LLBaseDownloadRequest::~LLBaseDownloadRequest() +{ +} + +// virtual +LLBaseDownloadRequest* LLBaseDownloadRequest::getCopy() +{ + return new LLBaseDownloadRequest(*this); +} + + ///---------------------------------------------------------------------------- /// LLAssetRequest ///---------------------------------------------------------------------------- LLAssetRequest::LLAssetRequest(const LLUUID &uuid, const LLAssetType::EType type) -: mUUID(uuid), - mType(type), - mDownCallback( NULL ), - mUpCallback( NULL ), - mInfoCallback( NULL ), - mUserData( NULL ), - mHost(), - mIsTemp( FALSE ), - mIsLocal(FALSE), - mIsUserWaiting(FALSE), - mTimeout(LL_ASSET_STORAGE_TIMEOUT), - mIsPriority(FALSE), - mDataSentInFirstPacket(FALSE), - mDataIsInVFS( FALSE ) + : LLBaseDownloadRequest(uuid, type), + mUpCallback(), + mInfoCallback( NULL ), + mIsLocal(FALSE), + mIsUserWaiting(FALSE), + mTimeout(LL_ASSET_STORAGE_TIMEOUT) { - // Need to guarantee that this time is up to date, we may be creating a circuit even though we haven't been - // running a message system loop. - mTime = LLMessageSystem::getMessageTimeSeconds(TRUE); } // virtual @@ -190,8 +243,8 @@ LLSD LLAssetRequest::getTerseDetails() const sd["asset_id"] = getUUID(); sd["type_long"] = LLAssetType::lookupHumanReadable(getType()); sd["type"] = LLAssetType::lookup(getType()); - sd["time"] = mTime; - time_t timestamp = (time_t) mTime; + sd["time"] = mTime.value(); + time_t timestamp = (time_t) mTime.value(); std::ostringstream time_string; time_string << ctime(×tamp); sd["time_string"] = time_string.str(); @@ -213,56 +266,51 @@ LLSD LLAssetRequest::getFullDetails() const return sd; } +LLBaseDownloadRequest* LLAssetRequest::getCopy() +{ + return new LLAssetRequest(*this); +} + ///---------------------------------------------------------------------------- /// LLInvItemRequest ///---------------------------------------------------------------------------- LLInvItemRequest::LLInvItemRequest(const LLUUID &uuid, const LLAssetType::EType type) -: mUUID(uuid), - mType(type), - mDownCallback( NULL ), - mUserData( NULL ), - mHost(), - mIsTemp( FALSE ), - mIsPriority(FALSE), - mDataSentInFirstPacket(FALSE), - mDataIsInVFS( FALSE ) + : LLBaseDownloadRequest(uuid, type) { - // Need to guarantee that this time is up to date, we may be creating a circuit even though we haven't been - // running a message system loop. - mTime = LLMessageSystem::getMessageTimeSeconds(TRUE); } +// virtual LLInvItemRequest::~LLInvItemRequest() { } +LLBaseDownloadRequest* LLInvItemRequest::getCopy() +{ + return new LLInvItemRequest(*this); +} + ///---------------------------------------------------------------------------- /// LLEstateAssetRequest ///---------------------------------------------------------------------------- LLEstateAssetRequest::LLEstateAssetRequest(const LLUUID &uuid, const LLAssetType::EType atype, - EstateAssetType etype) -: mUUID(uuid), - mAType(atype), - mEstateAssetType(etype), - mDownCallback( NULL ), - mUserData( NULL ), - mHost(), - mIsTemp( FALSE ), - mIsPriority(FALSE), - mDataSentInFirstPacket(FALSE), - mDataIsInVFS( FALSE ) + EstateAssetType etype) + : LLBaseDownloadRequest(uuid, atype), + mEstateAssetType(etype) { - // Need to guarantee that this time is up to date, we may be creating a circuit even though we haven't been - // running a message system loop. - mTime = LLMessageSystem::getMessageTimeSeconds(TRUE); } +// Virtual LLEstateAssetRequest::~LLEstateAssetRequest() { } +LLBaseDownloadRequest* LLEstateAssetRequest::getCopy() +{ + return new LLEstateAssetRequest(*this); +} + ///---------------------------------------------------------------------------- /// LLAssetStorage @@ -282,14 +330,12 @@ LLAssetStorage::LLAssetStorage(LLMessageSystem *msg, LLXferManager *xfer, LLVFS _init(msg, xfer, vfs, static_vfs, upstream_host); } - LLAssetStorage::LLAssetStorage(LLMessageSystem *msg, LLXferManager *xfer, LLVFS *vfs, LLVFS *static_vfs) { _init(msg, xfer, vfs, static_vfs, LLHost::invalid); } - void LLAssetStorage::_init(LLMessageSystem *msg, LLXferManager *xfer, LLVFS *vfs, @@ -337,7 +383,7 @@ void LLAssetStorage::checkForTimeouts() void LLAssetStorage::_cleanupRequests(BOOL all, S32 error) { - F64 mt_secs = LLMessageSystem::getMessageTimeSeconds(); + F64Seconds mt_secs = LLMessageSystem::getMessageTimeSeconds(); request_list_t timed_out; S32 rt; @@ -356,10 +402,10 @@ void LLAssetStorage::_cleanupRequests(BOOL all, S32 error) || ((RT_DOWNLOAD == rt) && LL_ASSET_STORAGE_TIMEOUT < (mt_secs - tmp->mTime))) { - llwarns << "Asset " << getRequestName((ERequestType)rt) << " request " + LL_WARNS("AssetStorage") << "Asset " << getRequestName((ERequestType)rt) << " request " << (all ? "aborted" : "timed out") << " for " << tmp->getUUID() << "." - << LLAssetType::lookup(tmp->getType()) << llendl; + << LLAssetType::lookup(tmp->getType()) << LL_ENDL; timed_out.push_front(tmp); iter = requests->erase(curiter); @@ -420,8 +466,8 @@ bool LLAssetStorage::findInStaticVFSAndInvokeCallback(const LLUUID& uuid, LLAsse } else { - llwarns << "Asset vfile " << uuid << ":" << type - << " found in static cache with bad size " << file.getSize() << ", ignoring" << llendl; + LL_WARNS("AssetStorage") << "Asset vfile " << uuid << ":" << type + << " found in static cache with bad size " << file.getSize() << ", ignoring" << LL_ENDL; } } return false; @@ -432,11 +478,15 @@ bool LLAssetStorage::findInStaticVFSAndInvokeCallback(const LLUUID& uuid, LLAsse /////////////////////////////////////////////////////////////////////////// // IW - uuid is passed by value to avoid side effects, please don't re-add & -void LLAssetStorage::getAssetData(const LLUUID uuid, LLAssetType::EType type, LLGetAssetCallback callback, void *user_data, BOOL is_priority) +void LLAssetStorage::getAssetData(const LLUUID uuid, + LLAssetType::EType type, + LLAssetStorage::LLGetAssetCallback callback, + void *user_data, + BOOL is_priority) { - LL_DEBUGS("AssetStorage") << "LLAssetStorage::getAssetData() - " << uuid << "," << LLAssetType::lookup(type) << llendl; + LL_DEBUGS("AssetStorage") << "LLAssetStorage::getAssetData() - " << uuid << "," << LLAssetType::lookup(type) << LL_ENDL; - LL_DEBUGS("AssetStorage") << "ASSET_TRACE requesting " << uuid << " type " << LLAssetType::lookup(type) << llendl; + LL_DEBUGS("AssetStorage") << "ASSET_TRACE requesting " << uuid << " type " << LLAssetType::lookup(type) << LL_ENDL; if (user_data) { @@ -446,7 +496,7 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, LLAssetType::EType type, LL if (mShutDown) { - LL_DEBUGS("AssetStorage") << "ASSET_TRACE cancelled " << uuid << " type " << LLAssetType::lookup(type) << " shutting down" << llendl; + LL_DEBUGS("AssetStorage") << "ASSET_TRACE cancelled " << uuid << " type " << LLAssetType::lookup(type) << " shutting down" << LL_ENDL; if (callback) { @@ -468,7 +518,7 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, LLAssetType::EType type, LL /* */ if(std::find(mBlackListedAsset.begin(),mBlackListedAsset.end(),uuid) != mBlackListedAsset.end()) { - llinfos << "Blacklisted asset " << uuid.asString() << " was trying to be accessed!!!!!!" << llendl; + LL_INFOS() << "Blacklisted asset " << uuid.asString() << " was trying to be accessed!!!!!!" << LL_ENDL; if (callback) { callback(mVFS, uuid, type, user_data, LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE, LL_EXSTAT_NULL_UUID); @@ -480,7 +530,7 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, LLAssetType::EType type, LL // Try static VFS first. if (findInStaticVFSAndInvokeCallback(uuid,type,callback,user_data)) { - LL_DEBUGS("AssetStorage") << "ASSET_TRACE asset " << uuid << " found in static VFS" << llendl; + LL_DEBUGS("AssetStorage") << "ASSET_TRACE asset " << uuid << " found in static VFS" << LL_ENDL; return; } @@ -498,13 +548,13 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, LLAssetType::EType type, LL callback(mVFS, uuid, type, user_data, LL_ERR_NOERR, LL_EXSTAT_VFS_CACHED); } - LL_DEBUGS("AssetStorage") << "ASSET_TRACE asset " << uuid << " found in VFS" << llendl; + LL_DEBUGS("AssetStorage") << "ASSET_TRACE asset " << uuid << " found in VFS" << LL_ENDL; } else { if (exists) { - llwarns << "Asset vfile " << uuid << ":" << type << " found with bad size " << file.getSize() << ", removing" << llendl; + LL_WARNS("AssetStorage") << "Asset vfile " << uuid << ":" << type << " found with bad size " << file.getSize() << ", removing" << LL_ENDL; file.remove(); } @@ -520,8 +570,8 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, LLAssetType::EType type, LL if (callback == tmp->mDownCallback && user_data == tmp->mUserData) { // this is a duplicate from the same subsystem - throw it away - llwarns << "Discarding duplicate request for asset " << uuid - << "." << LLAssetType::lookup(type) << llendl; + LL_WARNS("AssetStorage") << "Discarding duplicate request for asset " << uuid + << "." << LLAssetType::lookup(type) << LL_ENDL; return; } @@ -533,7 +583,7 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, LLAssetType::EType type, LL if (duplicate) { LL_DEBUGS("AssetStorage") << "Adding additional non-duplicate request for asset " << uuid - << "." << LLAssetType::lookup(type) << llendl; + << "." << LLAssetType::lookup(type) << LL_ENDL; } // This can be overridden by subclasses @@ -542,136 +592,111 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, LLAssetType::EType type, LL } -// -// *NOTE: Logic here is replicated in LLViewerAssetStorage::_queueDataRequest. -// Changes here may need to be replicated in the viewer's derived class. -// -void LLAssetStorage::_queueDataRequest(const LLUUID& uuid, LLAssetType::EType atype, - LLGetAssetCallback callback, - void *user_data, BOOL duplicate, - BOOL is_priority) -{ - if (mUpstreamHost.isOk()) +// static +void LLAssetStorage::removeAndCallbackPendingDownloads(const LLUUID& file_id, LLAssetType::EType file_type, + const LLUUID& callback_id, LLAssetType::EType callback_type, + S32 result_code, LLExtStat ext_status) +{ + // find and callback ALL pending requests for this UUID + // SJB: We process the callbacks in reverse order, I do not know if this is important, + // but I didn't want to mess with it. + request_list_t requests; + for (request_list_t::iterator iter = gAssetStorage->mPendingDownloads.begin(); + iter != gAssetStorage->mPendingDownloads.end(); ) { - // stash the callback info so we can find it after we get the response message - LLAssetRequest *req = new LLAssetRequest(uuid, atype); - req->mDownCallback = callback; - req->mUserData = user_data; - req->mIsPriority = is_priority; - - mPendingDownloads.push_back(req); - - if (!duplicate) + request_list_t::iterator curiter = iter++; + LLAssetRequest* tmp = *curiter; + if ((tmp->getUUID() == file_id) && (tmp->getType()== file_type)) { - // send request message to our upstream data provider - // Create a new asset transfer. - LLTransferSourceParamsAsset spa; - spa.setAsset(uuid, atype); - - // Set our destination file, and the completion callback. - LLTransferTargetParamsVFile tpvf; - tpvf.setAsset(uuid, atype); - tpvf.setCallback(downloadCompleteCallback, req); - - //llinfos << "Starting transfer for " << uuid << llendl; - LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(mUpstreamHost, LLTCT_ASSET); - ttcp->requestTransfer(spa, tpvf, 100.f + (is_priority ? 1.f : 0.f)); + requests.push_front(tmp); + iter = gAssetStorage->mPendingDownloads.erase(curiter); } } - else + for (request_list_t::iterator iter = requests.begin(); + iter != requests.end(); ) { - // uh-oh, we shouldn't have gotten here - llwarns << "Attempt to move asset data request upstream w/o valid upstream provider" << llendl; - if (callback) + request_list_t::iterator curiter = iter++; + LLAssetRequest* tmp = *curiter; + if (tmp->mDownCallback) { - callback(mVFS, uuid, atype, user_data, LL_ERR_CIRCUIT_GONE, LL_EXSTAT_NO_UPSTREAM); + tmp->mDownCallback(gAssetStorage->mVFS, callback_id, callback_type, tmp->mUserData, result_code, ext_status); } + delete tmp; } } - void LLAssetStorage::downloadCompleteCallback( S32 result, const LLUUID& file_id, LLAssetType::EType file_type, - void* user_data, LLExtStat ext_status) + LLBaseDownloadRequest* user_data, + LLExtStat ext_status) { - LL_DEBUGS("AssetStorage") << "ASSET_TRACE asset " << file_id << " downloadCompleteCallback" << llendl; + LL_DEBUGS("AssetStorage") << "ASSET_TRACE asset " << file_id << " downloadCompleteCallback" << LL_ENDL; LL_DEBUGS("AssetStorage") << "LLAssetStorage::downloadCompleteCallback() for " << file_id - << "," << LLAssetType::lookup(file_type) << llendl; + << "," << LLAssetType::lookup(file_type) << LL_ENDL; LLAssetRequest* req = (LLAssetRequest*)user_data; if(!req) { - llwarns << "LLAssetStorage::downloadCompleteCallback called without" - "a valid request." << llendl; + LL_WARNS("AssetStorage") << "LLAssetStorage::downloadCompleteCallback called without" + "a valid request." << LL_ENDL; return; } if (!gAssetStorage) { - llwarns << "LLAssetStorage::downloadCompleteCallback called without any asset system, aborting!" << llendl; + LL_WARNS("AssetStorage") << "LLAssetStorage::downloadCompleteCallback called without any asset system, aborting!" << LL_ENDL; return; } - // Inefficient since we're doing a find through a list that may have thousands of elements. + LLUUID callback_id; + LLAssetType::EType callback_type; + + // Inefficient since we're doing a find through a list that may have thousands of elements. // This is due for refactoring; we will probably change mPendingDownloads into a set. - request_list_t::iterator download_iter = std::find(gAssetStorage->mPendingDownloads.begin(), - gAssetStorage->mPendingDownloads.end(), - req); - // If the LLAssetRequest doesn't exist in the downloads queue, then it either has already been deleted - // by _cleanupRequests, or it's a transfer. - if (download_iter != gAssetStorage->mPendingDownloads.end()) + // use findRequest instead. Legacy asset download gets a COPY of the request, thus pointer comparisons wont work here. + LLAssetRequest* download_req = LLAssetStorage::findRequest(&gAssetStorage->mPendingDownloads, req->getType(), req->getUUID() ); + + if (download_req) { - req->setUUID(file_id); - req->setType(file_type); - } + callback_id = file_id; + callback_type = file_type; + } + else + { + // either has already been deleted by _cleanupRequests or it's a transfer. + callback_id = req->getUUID(); + callback_type = req->getType(); + } if (LL_ERR_NOERR == result) { // we might have gotten a zero-size file - LLVFile vfile(gAssetStorage->mVFS, req->getUUID(), req->getType()); + LLVFile vfile(gAssetStorage->mVFS, callback_id, callback_type); if (vfile.getSize() <= 0) { - llwarns << "downloadCompleteCallback has non-existent or zero-size asset " << req->getUUID() << llendl; + LL_WARNS("AssetStorage") << "downloadCompleteCallback has non-existent or zero-size asset " << callback_id << LL_ENDL; result = LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE; vfile.remove(); } } - - // find and callback ALL pending requests for this UUID - // SJB: We process the callbacks in reverse order, I do not know if this is important, - // but I didn't want to mess with it. - request_list_t requests; - for (request_list_t::iterator iter = gAssetStorage->mPendingDownloads.begin(); - iter != gAssetStorage->mPendingDownloads.end(); ) - { - request_list_t::iterator curiter = iter++; - LLAssetRequest* tmp = *curiter; - if ((tmp->getUUID() == file_id) && (tmp->getType()== file_type)) - { - requests.push_front(tmp); - iter = gAssetStorage->mPendingDownloads.erase(curiter); - } - } - for (request_list_t::iterator iter = requests.begin(); - iter != requests.end(); ) - { - request_list_t::iterator curiter = iter++; - LLAssetRequest* tmp = *curiter; - if (tmp->mDownCallback) - { - tmp->mDownCallback(gAssetStorage->mVFS, req->getUUID(), req->getType(), tmp->mUserData, result, ext_status); - } - delete tmp; - } + + removeAndCallbackPendingDownloads(file_id, file_type, callback_id, callback_type, ext_status, result); } -void LLAssetStorage::getEstateAsset(const LLHost &object_sim, const LLUUID &agent_id, const LLUUID &session_id, - const LLUUID &asset_id, LLAssetType::EType atype, EstateAssetType etype, - LLGetAssetCallback callback, void *user_data, BOOL is_priority) +void LLAssetStorage::getEstateAsset( + const LLHost &object_sim, + const LLUUID &agent_id, + const LLUUID &session_id, + const LLUUID &asset_id, + LLAssetType::EType atype, + EstateAssetType etype, + LLGetAssetCallback callback, + void *user_data, + BOOL is_priority) { - lldebugs << "LLAssetStorage::getEstateAsset() - " << asset_id << "," << LLAssetType::lookup(atype) << ", estatetype " << etype << llendl; + LL_DEBUGS() << "LLAssetStorage::getEstateAsset() - " << asset_id << "," << LLAssetType::lookup(atype) << ", estatetype " << etype << LL_ENDL; // // Probably will get rid of this early out? @@ -710,7 +735,7 @@ void LLAssetStorage::getEstateAsset(const LLHost &object_sim, const LLUUID &agen { if (exists) { - llwarns << "Asset vfile " << asset_id << ":" << atype << " found with bad size " << file.getSize() << ", removing" << llendl; + LL_WARNS("AssetStorage") << "Asset vfile " << asset_id << ":" << atype << " found with bad size " << file.getSize() << ", removing" << LL_ENDL; file.remove(); } @@ -727,10 +752,10 @@ void LLAssetStorage::getEstateAsset(const LLHost &object_sim, const LLUUID &agen if (source_host.isOk()) { // stash the callback info so we can find it after we get the response message - LLEstateAssetRequest *req = new LLEstateAssetRequest(asset_id, atype, etype); - req->mDownCallback = callback; - req->mUserData = user_data; - req->mIsPriority = is_priority; + LLEstateAssetRequest req(asset_id, atype, etype); + req.mDownCallback = callback; + req.mUserData = user_data; + req.mIsPriority = is_priority; // send request message to our upstream data provider // Create a new asset transfer. @@ -743,14 +768,14 @@ void LLAssetStorage::getEstateAsset(const LLHost &object_sim, const LLUUID &agen tpvf.setAsset(asset_id, atype); tpvf.setCallback(downloadEstateAssetCompleteCallback, req); - LL_DEBUGS("AssetStorage") << "Starting transfer for " << asset_id << llendl; + LL_DEBUGS("AssetStorage") << "Starting transfer for " << asset_id << LL_ENDL; LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(source_host, LLTCT_ASSET); ttcp->requestTransfer(spe, tpvf, 100.f + (is_priority ? 1.f : 0.f)); } else { // uh-oh, we shouldn't have gotten here - llwarns << "Attempt to move asset data request upstream w/o valid upstream provider" << llendl; + LL_WARNS("AssetStorage") << "Attempt to move asset data request upstream w/o valid upstream provider" << LL_ENDL; if (callback) { callback(mVFS, asset_id, atype, user_data, LL_ERR_CIRCUIT_GONE, LL_EXSTAT_NO_UPSTREAM); @@ -763,20 +788,20 @@ void LLAssetStorage::downloadEstateAssetCompleteCallback( S32 result, const LLUUID& file_id, LLAssetType::EType file_type, - void* user_data, + LLBaseDownloadRequest* user_data, LLExtStat ext_status) { LLEstateAssetRequest *req = (LLEstateAssetRequest*)user_data; if(!req) { - llwarns << "LLAssetStorage::downloadEstateAssetCompleteCallback called" - " without a valid request." << llendl; + LL_WARNS("AssetStorage") << "LLAssetStorage::downloadEstateAssetCompleteCallback called" + " without a valid request." << LL_ENDL; return; } if (!gAssetStorage) { - llwarns << "LLAssetStorage::downloadEstateAssetCompleteCallback called" - " without any asset system, aborting!" << llendl; + LL_WARNS("AssetStorage") << "LLAssetStorage::downloadEstateAssetCompleteCallback called" + " without any asset system, aborting!" << LL_ENDL; return; } @@ -788,7 +813,7 @@ void LLAssetStorage::downloadEstateAssetCompleteCallback( LLVFile vfile(gAssetStorage->mVFS, req->getUUID(), req->getAType()); if (vfile.getSize() <= 0) { - llwarns << "downloadCompleteCallback has non-existent or zero-size asset!" << llendl; + LL_WARNS("AssetStorage") << "downloadCompleteCallback has non-existent or zero-size asset!" << LL_ENDL; result = LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE; vfile.remove(); @@ -798,25 +823,20 @@ void LLAssetStorage::downloadEstateAssetCompleteCallback( req->mDownCallback(gAssetStorage->mVFS, req->getUUID(), req->getAType(), req->mUserData, result, ext_status); } -void LLAssetStorage::getInvItemAsset(const LLHost &object_sim, const LLUUID &agent_id, const LLUUID &session_id, - const LLUUID &owner_id, const LLUUID &task_id, const LLUUID &item_id, - const LLUUID &asset_id, LLAssetType::EType atype, - LLGetAssetCallback callback, void *user_data, BOOL is_priority) +void LLAssetStorage::getInvItemAsset( + const LLHost &object_sim, + const LLUUID &agent_id, + const LLUUID &session_id, + const LLUUID &owner_id, + const LLUUID &task_id, + const LLUUID &item_id, + const LLUUID &asset_id, + LLAssetType::EType atype, + LLGetAssetCallback callback, + void *user_data, + BOOL is_priority) { - lldebugs << "LLAssetStorage::getInvItemAsset() - " << asset_id << "," << LLAssetType::lookup(atype) << llendl; - - // - // Probably will get rid of this early out? - // - //if (asset_id.isNull()) - //{ - // // Special case early out for NULL uuid - // if (callback) - // { - // callback(mVFS, asset_id, atype, user_data, LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE); - // } - // return; - //} + LL_DEBUGS() << "LLAssetStorage::getInvItemAsset() - " << asset_id << "," << LLAssetType::lookup(atype) << LL_ENDL; bool exists = false; U32 size = 0; @@ -834,7 +854,7 @@ void LLAssetStorage::getInvItemAsset(const LLHost &object_sim, const LLUUID &age size = exists ? file.getSize() : 0; if(exists && size < 1) { - llwarns << "Asset vfile " << asset_id << ":" << atype << " found with bad size " << file.getSize() << ", removing" << llendl; + LL_WARNS("AssetStorage") << "Asset vfile " << asset_id << ":" << atype << " found with bad size " << file.getSize() << ", removing" << LL_ENDL; file.remove(); } @@ -866,10 +886,10 @@ void LLAssetStorage::getInvItemAsset(const LLHost &object_sim, const LLUUID &age if (source_host.isOk()) { // stash the callback info so we can find it after we get the response message - LLInvItemRequest *req = new LLInvItemRequest(asset_id, atype); - req->mDownCallback = callback; - req->mUserData = user_data; - req->mIsPriority = is_priority; + LLInvItemRequest req(asset_id, atype); + req.mDownCallback = callback; + req.mUserData = user_data; + req.mIsPriority = is_priority; // send request message to our upstream data provider // Create a new asset transfer. @@ -885,14 +905,14 @@ void LLAssetStorage::getInvItemAsset(const LLHost &object_sim, const LLUUID &age LL_DEBUGS("AssetStorage") << "Starting transfer for inventory asset " << item_id << " owned by " << owner_id << "," << task_id - << llendl; + << LL_ENDL; LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(source_host, LLTCT_ASSET); ttcp->requestTransfer(spi, tpvf, 100.f + (is_priority ? 1.f : 0.f)); } else { // uh-oh, we shouldn't have gotten here - llwarns << "Attempt to move asset data request upstream w/o valid upstream provider" << llendl; + LL_WARNS("AssetStorage") << "Attempt to move asset data request upstream w/o valid upstream provider" << LL_ENDL; if (callback) { callback(mVFS, asset_id, atype, user_data, LL_ERR_CIRCUIT_GONE, LL_EXSTAT_NO_UPSTREAM); @@ -906,19 +926,19 @@ void LLAssetStorage::downloadInvItemCompleteCallback( S32 result, const LLUUID& file_id, LLAssetType::EType file_type, - void* user_data, + LLBaseDownloadRequest* user_data, LLExtStat ext_status) { LLInvItemRequest *req = (LLInvItemRequest*)user_data; if(!req) { - llwarns << "LLAssetStorage::downloadEstateAssetCompleteCallback called" - " without a valid request." << llendl; + LL_WARNS("AssetStorage") << "LLAssetStorage::downloadEstateAssetCompleteCallback called" + " without a valid request." << LL_ENDL; return; } if (!gAssetStorage) { - llwarns << "LLAssetStorage::downloadCompleteCallback called without any asset system, aborting!" << llendl; + LL_WARNS("AssetStorage") << "LLAssetStorage::downloadCompleteCallback called without any asset system, aborting!" << LL_ENDL; return; } @@ -930,7 +950,7 @@ void LLAssetStorage::downloadInvItemCompleteCallback( LLVFile vfile(gAssetStorage->mVFS, req->getUUID(), req->getType()); if (vfile.getSize() <= 0) { - llwarns << "downloadCompleteCallback has non-existent or zero-size asset!" << llendl; + LL_WARNS("AssetStorage") << "downloadCompleteCallback has non-existent or zero-size asset!" << LL_ENDL; result = LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE; vfile.remove(); @@ -945,11 +965,15 @@ void LLAssetStorage::downloadInvItemCompleteCallback( ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// // static -void LLAssetStorage::uploadCompleteCallback(const LLUUID& uuid, void *user_data, S32 result, LLExtStat ext_status) // StoreAssetData callback (fixed) +void LLAssetStorage::uploadCompleteCallback( + const LLUUID& uuid, + void *user_data, + S32 result, + LLExtStat ext_status) // StoreAssetData callback (fixed) { if (!gAssetStorage) { - llwarns << "LLAssetStorage::uploadCompleteCallback has no gAssetStorage!" << llendl; + LL_WARNS("AssetStorage") << "LLAssetStorage::uploadCompleteCallback has no gAssetStorage!" << LL_ENDL; return; } LLAssetRequest *req = (LLAssetRequest *)user_data; @@ -957,7 +981,7 @@ void LLAssetStorage::uploadCompleteCallback(const LLUUID& uuid, void *user_data, if (result) { - llwarns << "LLAssetStorage::uploadCompleteCallback " << result << ":" << getErrorString(result) << " trying to upload file to upstream provider" << llendl; + LL_WARNS("AssetStorage") << "LLAssetStorage::uploadCompleteCallback " << result << ":" << getErrorString(result) << " trying to upload file to upstream provider" << LL_ENDL; success = FALSE; } @@ -1039,7 +1063,7 @@ LLAssetStorage::request_list_t* LLAssetStorage::getRequestList(LLAssetStorage::E case RT_LOCALUPLOAD: return &mPendingLocalUploads; default: - llwarns << "Unable to find request list for request type '" << rt << "'" << llendl; + LL_WARNS("AssetStorage") << "Unable to find request list for request type '" << rt << "'" << LL_ENDL; return NULL; } } @@ -1055,7 +1079,7 @@ const LLAssetStorage::request_list_t* LLAssetStorage::getRequestList(LLAssetStor case RT_LOCALUPLOAD: return &mPendingLocalUploads; default: - llwarns << "Unable to find request list for request type '" << rt << "'" << llendl; + LL_WARNS("AssetStorage") << "Unable to find request list for request type '" << rt << "'" << LL_ENDL; return NULL; } } @@ -1072,7 +1096,7 @@ std::string LLAssetStorage::getRequestName(LLAssetStorage::ERequestType rt) case RT_LOCALUPLOAD: return "localupload"; default: - llwarns << "Unable to find request name for request type '" << rt << "'" << llendl; + LL_WARNS("AssetStorage") << "Unable to find request name for request type '" << rt << "'" << LL_ENDL; return ""; } } @@ -1225,7 +1249,7 @@ bool LLAssetStorage::deletePendingRequest(LLAssetStorage::ERequestType rt, { LL_DEBUGS("AssetStorage") << "Asset " << getRequestName(rt) << " request for " << asset_id << "." << LLAssetType::lookup(asset_type) - << " removed from pending queue." << llendl; + << " removed from pending queue." << LL_ENDL; return true; } return false; @@ -1303,23 +1327,33 @@ const char* LLAssetStorage::getErrorString(S32 status) } } - - -void LLAssetStorage::getAssetData(const LLUUID uuid, LLAssetType::EType type, void (*callback)(const char*, const LLUUID&, void *, S32, LLExtStat), void *user_data, BOOL is_priority) +void LLAssetStorage::getAssetData(const LLUUID uuid, + LLAssetType::EType type, + void (*callback)(const char*, + const LLUUID&, + void *, + S32, + LLExtStat), +void *user_data, +BOOL is_priority) { // check for duplicates here, since we're about to fool the normal duplicate checker for (request_list_t::iterator iter = mPendingDownloads.begin(); iter != mPendingDownloads.end(); ) { LLAssetRequest* tmp = *iter++; + + //void(*const* cbptr)(LLVFS *, const LLUUID &, LLAssetType::EType, void *, S32, LLExtStat) + auto cbptr = tmp->mDownCallback.target(); + if (type == tmp->getType() && uuid == tmp->getUUID() && - legacyGetDataCallback == tmp->mDownCallback && + (cbptr && (*cbptr == legacyGetDataCallback)) && callback == ((LLLegacyAssetRequest *)tmp->mUserData)->mDownCallback && user_data == ((LLLegacyAssetRequest *)tmp->mUserData)->mUserData) { // this is a duplicate from the same subsystem - throw it away - LL_DEBUGS("AssetStorage") << "Discarding duplicate request for UUID " << uuid << llendl; + LL_DEBUGS("AssetStorage") << "Discarding duplicate request for UUID " << uuid << LL_ENDL; return; } } @@ -1335,7 +1369,12 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, LLAssetType::EType type, vo } // static -void LLAssetStorage::legacyGetDataCallback(LLVFS *vfs, const LLUUID &uuid, LLAssetType::EType type, void *user_data, S32 status, LLExtStat ext_status) +void LLAssetStorage::legacyGetDataCallback(LLVFS *vfs, + const LLUUID &uuid, + LLAssetType::EType type, + void *user_data, + S32 status, + LLExtStat ext_status) { LLLegacyAssetRequest *legacy = (LLLegacyAssetRequest *)user_data; std::string filename; @@ -1379,78 +1418,6 @@ void LLAssetStorage::legacyGetDataCallback(LLVFS *vfs, const LLUUID &uuid, LLAss delete legacy; } -// this is overridden on the viewer and the sim, so it doesn't really do anything -// virtual -void LLAssetStorage::storeAssetData( - const LLTransactionID& tid, - LLAssetType::EType asset_type, - LLStoreAssetCallback callback, - void* user_data, - bool temp_file, - bool is_priority, - bool store_local, - bool user_waiting, - F64 timeout) -{ - llwarns << "storeAssetData: wrong version called" << llendl; - // LLAssetStorage metric: Virtual base call - reportMetric( LLUUID::null, asset_type, LLStringUtil::null, LLUUID::null, 0, MR_BAD_FUNCTION, __FILE__, __LINE__, "Illegal call to base: LLAssetStorage::storeAssetData 1" ); -} - -// virtual -// this does nothing, viewer and sim both override this. -void LLAssetStorage::storeAssetData( - const LLUUID& asset_id, - LLAssetType::EType asset_type, - LLStoreAssetCallback callback, - void* user_data, - bool temp_file , - bool is_priority, - bool store_local, - const LLUUID& requesting_agent_id, - bool user_waiting, - F64 timeout) -{ - llwarns << "storeAssetData: wrong version called" << llendl; - // LLAssetStorage metric: Virtual base call - reportMetric( asset_id, asset_type, LLStringUtil::null, requesting_agent_id, 0, MR_BAD_FUNCTION, __FILE__, __LINE__, "Illegal call to base: LLAssetStorage::storeAssetData 2" ); -} - -// virtual -// this does nothing, viewer and sim both override this. -void LLAssetStorage::storeAssetData( - const std::string& filename, - const LLUUID& asset_id, - LLAssetType::EType asset_type, - LLStoreAssetCallback callback, - void* user_data, - bool temp_file, - bool is_priority, - bool user_waiting, - F64 timeout) -{ - llwarns << "storeAssetData: wrong version called" << llendl; - // LLAssetStorage metric: Virtual base call - reportMetric( asset_id, asset_type, LLStringUtil::null, LLUUID::null, 0, MR_BAD_FUNCTION, __FILE__, __LINE__, "Illegal call to base: LLAssetStorage::storeAssetData 3" ); -} - -// virtual -// this does nothing, viewer and sim both override this. -void LLAssetStorage::storeAssetData( - const std::string& filename, - const LLTransactionID &transactoin_id, - LLAssetType::EType asset_type, - LLStoreAssetCallback callback, - void* user_data, - bool temp_file, - bool is_priority, - bool user_waiting, - F64 timeout) -{ - llwarns << "storeAssetData: wrong version called" << llendl; - // LLAssetStorage metric: Virtual base call - reportMetric( LLUUID::null, asset_type, LLStringUtil::null, LLUUID::null, 0, MR_BAD_FUNCTION, __FILE__, __LINE__, "Illegal call to base: LLAssetStorage::storeAssetData 4" ); -} // static void LLAssetStorage::legacyStoreDataCallback(const LLUUID &uuid, void *user_data, S32 status, LLExtStat ext_status) @@ -1463,38 +1430,6 @@ void LLAssetStorage::legacyStoreDataCallback(const LLUUID &uuid, void *user_data delete legacy; } -// virtual -void LLAssetStorage::addTempAssetData(const LLUUID& asset_id, const LLUUID& agent_id, const std::string& host_name) -{ } - -// virtual -BOOL LLAssetStorage::hasTempAssetData(const LLUUID& texture_id) const -{ return FALSE; } - -// virtual -std::string LLAssetStorage::getTempAssetHostName(const LLUUID& texture_id) const -{ return std::string(); } - -// virtual -LLUUID LLAssetStorage::getTempAssetAgentID(const LLUUID& texture_id) const -{ return LLUUID::null; } - -// virtual -void LLAssetStorage::removeTempAssetData(const LLUUID& asset_id) -{ } - -// virtual -void LLAssetStorage::removeTempAssetDataByAgentID(const LLUUID& agent_id) -{ } - -// virtual -void LLAssetStorage::dumpTempAssetData(const LLUUID& avatar_id) const -{ } - -// virtual -void LLAssetStorage::clearTempAssetData() -{ } - // static void LLAssetStorage::reportMetric( const LLUUID& asset_id, const LLAssetType::EType asset_type, const std::string& in_filename, const LLUUID& agent_id, S32 asset_size, EMetricResult result, @@ -1502,7 +1437,7 @@ void LLAssetStorage::reportMetric( const LLUUID& asset_id, const LLAssetType::ET { if( !metric_recipient ) { - LL_DEBUGS("AssetStorage") << "Couldn't store LLAssetStoreage::reportMetric - no metrics_recipient" << llendl; + LL_DEBUGS("AssetStorage") << "Couldn't store LLAssetStoreage::reportMetric - no metrics_recipient" << LL_ENDL; return; } diff --git a/indra/llmessage/llassetstorage.h b/indra/llmessage/llassetstorage.h index 0ad4dad1d8..0e29d9207e 100644 --- a/indra/llmessage/llassetstorage.h +++ b/indra/llmessage/llassetstorage.h @@ -29,6 +29,7 @@ #define LL_LLASSETSTORAGE_H #include +#include #include "lluuid.h" #include "lltimer.h" @@ -49,7 +50,24 @@ class LLSD; // anything that takes longer than this to download will abort. // HTTP Uploads also timeout if they take longer than this. -const F32 LL_ASSET_STORAGE_TIMEOUT = 5 * 60.0f; +const F32Minutes LL_ASSET_STORAGE_TIMEOUT(5); + + +// Specific error codes +const int LL_ERR_ASSET_REQUEST_FAILED = -1; +//const int LL_ERR_ASSET_REQUEST_INVALID = -2; +const int LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE = -3; +const int LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE = -4; +const int LL_ERR_INSUFFICIENT_PERMISSIONS = -5; +const int LL_ERR_PRICE_MISMATCH = -23018; + +// *TODO: these typedefs are passed into the VFS via a legacy C function pointer +// future project would be to convert these to C++ callables (std::function<>) so that +// we can use bind and remove the userData parameter. +// +typedef std::function LLGetAssetCallback; +typedef std::function LLStoreAssetCallback; + class LLAssetInfo { @@ -83,38 +101,54 @@ class LLAssetInfo }; -class LLAssetRequest +class LLBaseDownloadRequest { public: - LLAssetRequest(const LLUUID &uuid, const LLAssetType::EType at); - virtual ~LLAssetRequest(); - + LLBaseDownloadRequest(const LLUUID &uuid, const LLAssetType::EType at); + virtual ~LLBaseDownloadRequest(); + LLUUID getUUID() const { return mUUID; } LLAssetType::EType getType() const { return mType; } void setUUID(const LLUUID& id) { mUUID = id; } void setType(LLAssetType::EType type) { mType = type; } - void setTimeout (F64 timeout) { mTimeout = timeout; } + + virtual LLBaseDownloadRequest* getCopy(); protected: LLUUID mUUID; LLAssetType::EType mType; public: - void (*mDownCallback)(LLVFS*, const LLUUID&, LLAssetType::EType, void *, S32, LLExtStat); - void (*mUpCallback)(const LLUUID&, void *, S32, LLExtStat); - void (*mInfoCallback)(LLAssetInfo *, void *, S32); + LLGetAssetCallback mDownCallback; +// void(*mDownCallback)(LLVFS*, const LLUUID&, LLAssetType::EType, void *, S32, LLExtStat); void *mUserData; LLHost mHost; BOOL mIsTemp; - BOOL mIsLocal; - BOOL mIsUserWaiting; // We don't want to try forever if a user is waiting for a result. - F64 mTime; // Message system time - F64 mTimeout; // Amount of time before timing out. + F64Seconds mTime; // Message system time BOOL mIsPriority; BOOL mDataSentInFirstPacket; BOOL mDataIsInVFS; +}; + +class LLAssetRequest : public LLBaseDownloadRequest +{ +public: + LLAssetRequest(const LLUUID &uuid, const LLAssetType::EType at); + virtual ~LLAssetRequest(); + + void setTimeout(F64Seconds timeout) { mTimeout = timeout; } + + virtual LLBaseDownloadRequest* getCopy(); + + LLStoreAssetCallback mUpCallback; +// void (*mUpCallback)(const LLUUID&, void *, S32, LLExtStat); + void (*mInfoCallback)(LLAssetInfo *, void *, S32); + + BOOL mIsLocal; + BOOL mIsUserWaiting; // We don't want to try forever if a user is waiting for a result. + F64Seconds mTimeout; // Amount of time before timing out. LLUUID mRequestingAgentID; // Only valid for uploads from an agent virtual LLSD getTerseDetails() const; @@ -132,88 +166,43 @@ struct ll_asset_request_equal : public std::equal_to }; -class LLInvItemRequest +class LLInvItemRequest : public LLBaseDownloadRequest { public: LLInvItemRequest(const LLUUID &uuid, const LLAssetType::EType at); virtual ~LLInvItemRequest(); - LLUUID getUUID() const { return mUUID; } - LLAssetType::EType getType() const { return mType; } - - void setUUID(const LLUUID& id) { mUUID = id; } - void setType(LLAssetType::EType type) { mType = type; } - -protected: - LLUUID mUUID; - LLAssetType::EType mType; - -public: - void (*mDownCallback)(LLVFS*, const LLUUID&, LLAssetType::EType, void *, S32, LLExtStat); - - void *mUserData; - LLHost mHost; - BOOL mIsTemp; - F64 mTime; // Message system time - BOOL mIsPriority; - BOOL mDataSentInFirstPacket; - BOOL mDataIsInVFS; - + virtual LLBaseDownloadRequest* getCopy(); }; -class LLEstateAssetRequest +class LLEstateAssetRequest : public LLBaseDownloadRequest { public: LLEstateAssetRequest(const LLUUID &uuid, const LLAssetType::EType at, EstateAssetType et); virtual ~LLEstateAssetRequest(); - LLUUID getUUID() const { return mUUID; } - LLAssetType::EType getAType() const { return mAType; } + LLAssetType::EType getAType() const { return mType; } - void setUUID(const LLUUID& id) { mUUID = id; } - void setType(LLAssetType::EType type) { mAType = type; } + virtual LLBaseDownloadRequest* getCopy(); protected: - LLUUID mUUID; - LLAssetType::EType mAType; EstateAssetType mEstateAssetType; - -public: - void (*mDownCallback)(LLVFS*, const LLUUID&, LLAssetType::EType, void *, S32, LLExtStat); - - void *mUserData; - LLHost mHost; - BOOL mIsTemp; - F64 mTime; // Message system time - BOOL mIsPriority; - BOOL mDataSentInFirstPacket; - BOOL mDataIsInVFS; - }; // Map of known bad assets typedef std::map toxic_asset_map_t; -typedef void (*LLGetAssetCallback)(LLVFS *vfs, const LLUUID &asset_id, - LLAssetType::EType asset_type, void *user_data, S32 status, LLExtStat ext_status); -class LLTempAssetStorage -{ -public: - virtual ~LLTempAssetStorage() =0; - virtual void addTempAssetData(const LLUUID& asset_id, - const LLUUID& agent_id, - const std::string& host_name) = 0; -}; -class LLAssetStorage : public LLTempAssetStorage +class LLAssetStorage { public: // VFS member is public because static child methods need it :( LLVFS *mVFS; LLVFS *mStaticVFS; - typedef void (*LLStoreAssetCallback)(const LLUUID &asset_id, void *user_data, S32 status, LLExtStat ext_status); + typedef ::LLStoreAssetCallback LLStoreAssetCallback; + typedef ::LLGetAssetCallback LLGetAssetCallback; enum ERequestType { @@ -249,15 +238,18 @@ class LLAssetStorage : public LLTempAssetStorage virtual ~LLAssetStorage(); void setUpstream(const LLHost &upstream_host); + bool isUpstreamOK() const + { + return mUpstreamHost.isOk(); + } - virtual BOOL hasLocalAsset(const LLUUID &uuid, LLAssetType::EType type); + BOOL hasLocalAsset(const LLUUID &uuid, LLAssetType::EType type); // public interface methods // note that your callback may get called BEFORE the function returns - - virtual void getAssetData(const LLUUID uuid, LLAssetType::EType atype, LLGetAssetCallback cb, void *user_data, BOOL is_priority = FALSE); + void getAssetData(const LLUUID uuid, LLAssetType::EType atype, LLGetAssetCallback cb, void *user_data, BOOL is_priority = FALSE); - std::vector mBlackListedAsset; + uuid_vec_t mBlackListedAsset; /* * TransactionID version @@ -272,25 +264,10 @@ class LLAssetStorage : public LLTempAssetStorage bool is_priority = false, bool store_local = false, bool user_waiting= false, - F64 timeout=LL_ASSET_STORAGE_TIMEOUT); + F64Seconds timeout=LL_ASSET_STORAGE_TIMEOUT) = 0; - /* - * AssetID version - * Sim needs both store_local and requesting_agent_id. - */ - virtual void storeAssetData( - const LLUUID& asset_id, - LLAssetType::EType asset_type, - LLStoreAssetCallback callback, - void* user_data, - bool temp_file = false, - bool is_priority = false, - bool store_local = false, - const LLUUID& requesting_agent_id = LLUUID::null, - bool user_waiting= false, - F64 timeout=LL_ASSET_STORAGE_TIMEOUT); - virtual void checkForTimeouts(); + void checkForTimeouts(); void getEstateAsset(const LLHost &object_sim, const LLUUID &agent_id, const LLUUID &session_id, const LLUUID &asset_id, LLAssetType::EType atype, EstateAssetType etype, @@ -315,15 +292,15 @@ class LLAssetStorage : public LLTempAssetStorage bool findInStaticVFSAndInvokeCallback(const LLUUID& uuid, LLAssetType::EType type, LLGetAssetCallback callback, void *user_data); - virtual LLSD getPendingDetailsImpl(const request_list_t* requests, + LLSD getPendingDetailsImpl(const request_list_t* requests, LLAssetType::EType asset_type, const std::string& detail_prefix) const; - virtual LLSD getPendingRequestImpl(const request_list_t* requests, + LLSD getPendingRequestImpl(const request_list_t* requests, LLAssetType::EType asset_type, const LLUUID& asset_id) const; - virtual bool deletePendingRequestImpl(request_list_t* requests, + bool deletePendingRequestImpl(request_list_t* requests, LLAssetType::EType asset_type, const LLUUID& asset_id); @@ -344,35 +321,39 @@ class LLAssetStorage : public LLTempAssetStorage S32 getNumPendingLocalUploads(); S32 getNumPending(ERequestType rt) const; - virtual LLSD getPendingDetails(ERequestType rt, + LLSD getPendingDetails(ERequestType rt, LLAssetType::EType asset_type, const std::string& detail_prefix) const; - virtual LLSD getPendingRequest(ERequestType rt, + LLSD getPendingRequest(ERequestType rt, LLAssetType::EType asset_type, const LLUUID& asset_id) const; - virtual bool deletePendingRequest(ERequestType rt, + bool deletePendingRequest(ERequestType rt, LLAssetType::EType asset_type, const LLUUID& asset_id); + static void removeAndCallbackPendingDownloads( const LLUUID& file_id, LLAssetType::EType file_type, + const LLUUID& callback_id, LLAssetType::EType callback_type, + S32 result_code, LLExtStat ext_status); + // download process callbacks static void downloadCompleteCallback( S32 result, const LLUUID& file_id, LLAssetType::EType file_type, - void* user_data, LLExtStat ext_status); + LLBaseDownloadRequest* user_data, LLExtStat ext_status); static void downloadEstateAssetCompleteCallback( S32 result, const LLUUID& file_id, LLAssetType::EType file_type, - void* user_data, LLExtStat ext_status); + LLBaseDownloadRequest* user_data, LLExtStat ext_status); static void downloadInvItemCompleteCallback( S32 result, const LLUUID& file_id, LLAssetType::EType file_type, - void* user_data, LLExtStat ext_status); + LLBaseDownloadRequest* user_data, LLExtStat ext_status); // upload process callbacks static void uploadCompleteCallback(const LLUUID&, void *user_data, S32 result, LLExtStat ext_status); @@ -384,20 +365,6 @@ class LLAssetStorage : public LLTempAssetStorage // deprecated file-based methods void getAssetData(const LLUUID uuid, LLAssetType::EType type, void (*callback)(const char*, const LLUUID&, void *, S32, LLExtStat), void *user_data, BOOL is_priority = FALSE); - /* - * AssetID version. - */ - virtual void storeAssetData( - const std::string& filename, - const LLUUID& asset_id, - LLAssetType::EType type, - LLStoreAssetCallback callback, - void* user_data, - bool temp_file = false, - bool is_priority = false, - bool user_waiting = false, - F64 timeout = LL_ASSET_STORAGE_TIMEOUT); - /* * TransactionID version */ @@ -410,33 +377,21 @@ class LLAssetStorage : public LLTempAssetStorage bool temp_file = false, bool is_priority = false, bool user_waiting = false, - F64 timeout = LL_ASSET_STORAGE_TIMEOUT); + F64Seconds timeout = LL_ASSET_STORAGE_TIMEOUT) = 0; static void legacyGetDataCallback(LLVFS *vfs, const LLUUID &uuid, LLAssetType::EType, void *user_data, S32 status, LLExtStat ext_status); static void legacyStoreDataCallback(const LLUUID &uuid, void *user_data, S32 status, LLExtStat ext_status); - // Temp assets are stored on sim nodes, they have agent ID and location data associated with them. - // This is a no-op for non-http asset systems - virtual void addTempAssetData(const LLUUID& asset_id, const LLUUID& agent_id, const std::string& host_name); - virtual BOOL hasTempAssetData(const LLUUID& texture_id) const; - virtual std::string getTempAssetHostName(const LLUUID& texture_id) const; - virtual LLUUID getTempAssetAgentID(const LLUUID& texture_id) const; - virtual void removeTempAssetData(const LLUUID& asset_id); - virtual void removeTempAssetDataByAgentID(const LLUUID& agent_id); - // Pass LLUUID::null for all - virtual void dumpTempAssetData(const LLUUID& avatar_id) const; - virtual void clearTempAssetData(); - // add extra methods to handle metadata protected: void _cleanupRequests(BOOL all, S32 error); void _callUploadCallbacks(const LLUUID &uuid, const LLAssetType::EType asset_type, BOOL success, LLExtStat ext_status); - virtual void _queueDataRequest(const LLUUID& uuid, LLAssetType::EType type, - void (*callback)(LLVFS *vfs, const LLUUID&, LLAssetType::EType, void *, S32, LLExtStat), + virtual void _queueDataRequest(const LLUUID& uuid, LLAssetType::EType type, LLGetAssetCallback callback, +// void (*callback)(LLVFS *vfs, const LLUUID&, LLAssetType::EType, void *, S32, LLExtStat), void *user_data, BOOL duplicate, - BOOL is_priority); + BOOL is_priority) = 0; private: void _init(LLMessageSystem *msg, @@ -480,7 +435,7 @@ class LLLegacyAssetRequest { public: void (*mDownCallback)(const char *, const LLUUID&, void *, S32, LLExtStat); - LLAssetStorage::LLStoreAssetCallback mUpCallback; + LLStoreAssetCallback mUpCallback; void *mUserData; }; diff --git a/indra/llmessage/llavatarname.cpp b/indra/llmessage/llavatarname.cpp new file mode 100644 index 0000000000..a02d7c012d --- /dev/null +++ b/indra/llmessage/llavatarname.cpp @@ -0,0 +1,254 @@ +/** + * @file llavatarname.cpp + * @brief Represents name-related data for an avatar, such as the + * username/SLID ("bobsmith123" or "james.linden") and the display + * name ("James Cook") + * + * $LicenseInfo:firstyear=2010&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ +#include "linden_common.h" + +#include "llavatarname.h" + +#include "llcontrol.h" // For LLCachedControl +#include "lldate.h" +#include "llframetimer.h" +#include "llsd.h" + +// Store these in pre-built std::strings to avoid memory allocations in +// LLSD map lookups +static const std::string USERNAME("username"); +static const std::string DISPLAY_NAME("display_name"); +static const std::string LEGACY_FIRST_NAME("legacy_first_name"); +static const std::string LEGACY_LAST_NAME("legacy_last_name"); +static const std::string IS_DISPLAY_NAME_DEFAULT("is_display_name_default"); +static const std::string DISPLAY_NAME_EXPIRES("display_name_expires"); +static const std::string DISPLAY_NAME_NEXT_UPDATE("display_name_next_update"); + +bool LLAvatarName::sUseDisplayNames = true; +bool LLAvatarName::sUseUsernames = true; + +// Minimum time-to-live (in seconds) for a name entry. +// Avatar name should always guarantee to expire reasonably soon by default +// so if the failure to get a valid expiration time was due to something temporary +// we will eventually request and get the right data. +const F64 MIN_ENTRY_LIFETIME = 60.0; + +LLAvatarName::LLAvatarName() +: mUsername(), + mDisplayName(), + mLegacyFirstName(), + mLegacyLastName(), + mIsDisplayNameDefault(false), + mIsTemporaryName(false), + mExpires(F64_MAX), + mNextUpdate(0.0) +{ } + +bool LLAvatarName::operator<(const LLAvatarName& rhs) const +{ + if (mUsername == rhs.mUsername) + return mDisplayName < rhs.mDisplayName; + else + return mUsername < rhs.mUsername; +} + +//static +void LLAvatarName::setUseDisplayNames(bool use) +{ + sUseDisplayNames = use; +} +//static +bool LLAvatarName::useDisplayNames() +{ + return sUseDisplayNames; +} + +void LLAvatarName::setUseUsernames(bool use) +{ + sUseUsernames = use; +} + +bool LLAvatarName::useUsernames() +{ + return sUseUsernames; +} + +LLSD LLAvatarName::asLLSD() const +{ + LLSD sd; + sd[USERNAME] = mUsername; + sd[DISPLAY_NAME] = mDisplayName; + sd[LEGACY_FIRST_NAME] = mLegacyFirstName; + sd[LEGACY_LAST_NAME] = mLegacyLastName; + sd[IS_DISPLAY_NAME_DEFAULT] = mIsDisplayNameDefault; + sd[DISPLAY_NAME_EXPIRES] = LLDate(mExpires); + sd[DISPLAY_NAME_NEXT_UPDATE] = LLDate(mNextUpdate); + return sd; +} + +void LLAvatarName::fromLLSD(const LLSD& sd) +{ + mUsername = sd[USERNAME].asString(); + mDisplayName = sd[DISPLAY_NAME].asString(); + mLegacyFirstName = sd[LEGACY_FIRST_NAME].asString(); + mLegacyLastName = sd[LEGACY_LAST_NAME].asString(); + mIsDisplayNameDefault = sd[IS_DISPLAY_NAME_DEFAULT].asBoolean() || mUsername == mDisplayName; + LLDate expires = sd[DISPLAY_NAME_EXPIRES]; + mExpires = expires.secondsSinceEpoch(); + LLDate next_update = sd[DISPLAY_NAME_NEXT_UPDATE]; + mNextUpdate = next_update.secondsSinceEpoch(); + + // Some avatars don't have explicit display names set. Force a legible display name here. + if (mDisplayName.empty()) + { + mDisplayName = mUsername; + mIsDisplayNameDefault = true; + } +} + +// Transform a string (typically provided by the legacy service) into a decent +// avatar name instance. +void LLAvatarName::fromString(const std::string& full_name) +{ + mDisplayName = full_name; + std::string::size_type index = full_name.find(' '); + if (index != std::string::npos) + { + // The name is in 2 parts (first last) + mLegacyFirstName = full_name.substr(0, index); + mLegacyLastName = full_name.substr(index+1); + if (mLegacyLastName != "Resident") + { + mUsername = mLegacyFirstName + '.' + mLegacyLastName; + mDisplayName = full_name; + LLStringUtil::toLower(mUsername); + } + else + { + // Very old names do have a dummy "Resident" last name + // that we choose to hide from users. + mUsername = mLegacyFirstName; + mDisplayName = mLegacyFirstName; + } + } + else + { + mLegacyFirstName = full_name; + mLegacyLastName = ""; + mUsername = full_name; + mDisplayName = full_name; + } + mIsDisplayNameDefault = true; + mIsTemporaryName = true; + setExpires(MIN_ENTRY_LIFETIME); +} + +void LLAvatarName::setExpires(F64 expires) +{ + mExpires = LLFrameTimer::getTotalSeconds() + expires; +} + +std::string LLAvatarName::getCompleteName(bool linefeed) const +{ + std::string name; + if (sUseDisplayNames) + { + if (mUsername.empty() || mIsDisplayNameDefault) + { + // If this particular display name is defaulted (i.e. based on user name), + // then display only the easier to read instance of the person's name. + name = mDisplayName; + } + else + { + name = mDisplayName; + if (sUseUsernames) + { + name += (linefeed ? "\n(" : " (") + mUsername + ')'; + } + } + } + else + { + name = getUserName(); + } + return name; +} + +std::string LLAvatarName::getLegacyName() const +{ + if (mLegacyFirstName.empty() && mLegacyLastName.empty()) // display names disabled? + { + return mDisplayName; + } + + static const LLCachedControl show_resident("LiruShowLastNameResident", false); + if (show_resident || mLegacyLastName != "Resident") + return mLegacyFirstName + ' ' + mLegacyLastName; + return mLegacyFirstName; +} + +std::string LLAvatarName::getDisplayName() const +{ + if (sUseDisplayNames) + { + return mDisplayName; + } + else + { + return getUserName(); + } +} + +std::string LLAvatarName::getUserName() const +{ + std::string name; + if (mLegacyLastName.empty() /*|| (mLegacyLastName == "Resident")*/) // + { + if (mLegacyFirstName.empty()) + { + // If we cannot create a user name from the legacy strings, use the display name + name = mDisplayName; + } + else + { + // The last name might be empty if it defaulted to "Resident" + name = mLegacyFirstName; + } + } + else + { + name = mLegacyFirstName + ' ' + mLegacyLastName; + } + return name; +} + +void LLAvatarName::dump() const +{ + LL_DEBUGS("AvNameCache") << "LLAvatarName: " + << "user '" << mUsername << "' " + << "display '" << mDisplayName << "' " + << "expires in " << mExpires - LLFrameTimer::getTotalSeconds() << " seconds" + << LL_ENDL; +} + diff --git a/indra/llmessage/llavatarname.h b/indra/llmessage/llavatarname.h new file mode 100644 index 0000000000..4f0df57cc1 --- /dev/null +++ b/indra/llmessage/llavatarname.h @@ -0,0 +1,153 @@ +/** + * @file llavatarname.h + * @brief Represents name-related data for an avatar, such as the + * username/SLID ("bobsmith123" or "james.linden") and the display + * name ("James Cook") + * + * $LicenseInfo:firstyear=2010&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ +#ifndef LLAVATARNAME_H +#define LLAVATARNAME_H + +#include + +const S32& main_name_system(); + +class LLSD; + +class LLAvatarName +{ +public: + LLAvatarName(); + + bool operator<(const LLAvatarName& rhs) const; + + // Conversion to and from LLSD (cache file or server response) + LLSD asLLSD() const; + void fromLLSD(const LLSD& sd); + + // Used only in legacy mode when the display name capability is not provided server side + // or to otherwise create a temporary valid item. + void fromString(const std::string& full_name); + + // Set the name object to become invalid in "expires" seconds from now + void setExpires(F64 expires); + + // Set and get the display name flag set by the user in preferences. + static void setUseDisplayNames(bool use); + static bool useDisplayNames(); + + static void setUseUsernames(bool use); + static bool useUsernames(); + + // A name object is valid if not temporary and not yet expired (default is expiration not checked) + bool isValidName(F64 max_unrefreshed = 0.0f) const { return !mIsTemporaryName && (mExpires >= max_unrefreshed); } + + // Return true if the name is made up from legacy or temporary data + bool isDisplayNameDefault() const { return mIsDisplayNameDefault; } + + // For normal names, returns "James Linden (james.linden)" + // When display names are disabled returns just "James Linden" + std::string getCompleteName(bool linefeed = false) const; + + // Returns "James Linden" or "bobsmith123 Resident" for backwards + // compatibility with systems like voice and muting + // *TODO: Eliminate this in favor of username only + std::string getLegacyName() const; + + // "Jos Sanchez" or "James Linden", UTF-8 encoded Unicode + // Takes the display name preference into account. This is truly the name that should + // be used for all UI where an avatar name has to be used unless we truly want something else (rare) + std::string getDisplayName() const; + + // Returns "James Linden" or "bobsmith123 Resident" + // Used where we explicitely prefer or need a non UTF-8 legacy (ASCII) name + // Also used for backwards compatibility with systems like voice and muting + std::string getUserName() const; + + // Returns "james.linden" or the legacy name for very old names + std::string getAccountName() const { return mUsername; } + + // Returns name in the format desired according to name_system + std::string getNSName(const S32& name_system = main_name_system()) const + { + switch (name_system) + { + case 1 : return getCompleteName(); + case 2 : return getDisplayName(); + case 3 : return getLegacyName() + (mIsDisplayNameDefault ? "" : " (" + mDisplayName + ')'); break; + default : return getLegacyName(); + } + } + + // Debug print of the object + void dump() const; + + // Names can change, so need to keep track of when name was + // last checked. + // Unix time-from-epoch seconds for efficiency + F64 mExpires; + + // You can only change your name every N hours, so record + // when the next update is allowed + // Unix time-from-epoch seconds + F64 mNextUpdate; + +private: + // "bobsmith123" or "james.linden", US-ASCII only + std::string mUsername; + + // "Jos Sanchez" or "James Linden", UTF-8 encoded Unicode + // Contains data whether or not user has explicitly set + // a display name; may duplicate their username. + std::string mDisplayName; + + // For "James Linden", "James" + // For "bobsmith123", "bobsmith123" + // Used to communicate with legacy systems like voice and muting which + // rely on old-style names. + // *TODO: Eliminate this in favor of username only + std::string mLegacyFirstName; + + // For "James Linden", "Linden" + // For "bobsmith123", "Resident" + // see above for rationale + std::string mLegacyLastName; + + // If true, both display name and SLID were generated from + // a legacy first and last name, like "James Linden (james.linden)" + bool mIsDisplayNameDefault; + + // Under error conditions, we may insert "dummy" records with + // names like "???" into caches as placeholders. These can be + // shown in UI, but are not serialized. + bool mIsTemporaryName; + + // Global flag indicating if display name should be used or not + // This will affect the output of the high level "get" methods + static bool sUseDisplayNames; + + // Flag indicating if username should be shown after display name or not + static bool sUseUsernames; +}; + +#endif diff --git a/indra/llmessage/llavatarnamecache.cpp b/indra/llmessage/llavatarnamecache.cpp index 36d691a5d0..9fb2c978bf 100644 --- a/indra/llmessage/llavatarnamecache.cpp +++ b/indra/llmessage/llavatarnamecache.cpp @@ -44,10 +44,6 @@ namespace LLAvatarNameCache { use_display_name_signal_t mUseDisplayNamesSignal; - // Manual override for display names - can disable even if the region - // supports it. - bool sUseDisplayNames = true; - // [RLVa:KB] - Checked: 2010-12-08 (RLVa-1.4.0a) | Added: RLVa-1.2.2c // RLVa override for display names bool sForceDisplayNames = false; @@ -57,18 +53,22 @@ namespace LLAvatarNameCache // current region supports display names. bool sRunning = false; + // Use the People API (modern) for fetching name if true. Use the old legacy protocol if false. + // For testing, there's a UsePeopleAPI setting that can be flipped (must restart viewer). + bool sUsePeopleAPI = true; + // Base lookup URL for name service. // On simulator, loaded from indra.xml // On viewer, usually a simulator capability (at People API team's request) // Includes the trailing slash, like "http://pdp60.lindenlab.com:8000/agents/" std::string sNameLookupURL; - // accumulated agent IDs for next query against service - typedef std::set ask_queue_t; + // Accumulated agent IDs for next query against service + typedef uuid_set_t ask_queue_t; ask_queue_t sAskQueue; - // agent IDs that have been requested, but with no reply - // maps agent ID to frame time request was made + // Agent IDs that have been requested, but with no reply. + // Maps agent ID to frame time request was made. typedef std::map pending_queue_t; pending_queue_t sPendingQueue; @@ -79,21 +79,21 @@ namespace LLAvatarNameCache typedef std::map signal_map_t; signal_map_t sSignalMap; - // names we know about + // The cache at last, i.e. avatar names we know about. typedef std::map cache_t; cache_t sCache; - // Send bulk lookup requests a few times a second at most - // only need per-frame timing resolution + // Send bulk lookup requests a few times a second at most. + // Only need per-frame timing resolution. LLFrameTimer sRequestTimer; - /// Maximum time an unrefreshed cache entry is allowed + // Maximum time an unrefreshed cache entry is allowed. const F64 MAX_UNREFRESHED_TIME = 20.0 * 60.0; - /// Time when unrefreshed cached names were checked last + // Time when unrefreshed cached names were checked last. static F64 sLastExpireCheck; - /// Time-to-live for a temp cache entry. + // Time-to-live for a temp cache entry. const F64 TEMP_CACHE_ENTRY_LIFETIME = 60.0; //----------------------------------------------------------------------- @@ -101,26 +101,21 @@ namespace LLAvatarNameCache //----------------------------------------------------------------------- // Handle name response off network. - // Optionally skip adding to cache, used when this is a fallback to the - // legacy name system. void processName(const LLUUID& agent_id, - const LLAvatarName& av_name, - bool add_to_cache); + const LLAvatarName& av_name); void requestNamesViaCapability(); - // Legacy name system callback + // Legacy name system callbacks void legacyNameCallback(const LLUUID& agent_id, const std::string& full_name, - bool is_group - ); + bool is_group); + void legacyNameFetch(const LLUUID& agent_id, + const std::string& full_name, + bool is_group); void requestNamesViaLegacy(); - // Fill in an LLAvatarName with the legacy name data - void buildLegacyName(const std::string& full_name, - LLAvatarName* av_name); - // Do a single callback to a given slot void fireSignal(const LLUUID& agent_id, const callback_slot_t& slot, @@ -174,31 +169,37 @@ namespace LLAvatarNameCache */ -class AIHTTPTimeoutPolicy; -extern AIHTTPTimeoutPolicy avatarNameResponder_timeout; - class LLAvatarNameResponder : public LLHTTPClient::ResponderWithResult { + LOG_CLASS(LLAvatarNameResponder); private: // need to store agent ids that are part of this request in case of // an error, so we can flag them as unavailable - std::vector mAgentIDs; + uuid_vec_t mAgentIDs; // Need the headers to look up Expires: and Retry-After: - virtual bool needsHeaders(void) const { return true; } - + /*virtual*/ bool needsHeaders() const { return true; } + /*virtual*/ char const* getName() const { return "LLAvatarNameResponder"; } + public: - LLAvatarNameResponder(const std::vector& agent_ids) + LLAvatarNameResponder(const uuid_vec_t& agent_ids) : mAgentIDs(agent_ids) { } - /*virtual*/ void result(const LLSD& content) +protected: + /*virtual*/ void httpSuccess() { + const LLSD& content = getContent(); + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR_OTHER, "Malformed response contents", content); + return; + } // Pull expiration out of headers if available - F64 expires = LLAvatarNameCache::nameExpirationFromHeaders(mReceivedHeaders); + F64 expires = LLAvatarNameCache::nameExpirationFromHeaders(getResponseHeaders()); F64 now = LLFrameTimer::getTotalSeconds(); - LLSD agents = content["agents"]; + const LLSD& agents = content["agents"]; LLSD::array_const_iterator it = agents.beginArray(); for ( ; it != agents.endArray(); ++it) { @@ -211,24 +212,15 @@ class LLAvatarNameResponder : public LLHTTPClient::ResponderWithResult // Use expiration time from header av_name.mExpires = expires; - // Some avatars don't have explicit display names set - if (av_name.mDisplayName.empty()) - { - av_name.mDisplayName = av_name.mUsername; - } - - LL_DEBUGS("AvNameCache") << "LLAvatarNameResponder::result for " << agent_id << " " - << "user '" << av_name.mUsername << "' " - << "display '" << av_name.mDisplayName << "' " - << "expires in " << expires - now << " seconds" - << LL_ENDL; + LL_DEBUGS("AvNameCache") << "LLAvatarNameResponder::result for " << agent_id << LL_ENDL; + av_name.dump(); // cache it and fire signals - LLAvatarNameCache::processName(agent_id, av_name, true); + LLAvatarNameCache::processName(agent_id, av_name); } // Same logic as error response case - LLSD unresolved_agents = content["bad_ids"]; + const LLSD& unresolved_agents = content["bad_ids"]; S32 num_unresolved = unresolved_agents.size(); if (num_unresolved > 0) { @@ -252,26 +244,22 @@ class LLAvatarNameResponder : public LLHTTPClient::ResponderWithResult << LL_ENDL; } - /*virtual*/ void error(U32 status, const std::string& reason) + /*virtual*/ void httpFailure() { // If there's an error, it might be caused by PeopleApi, // or when loading textures on startup and using a very slow // network, this query may time out. // What we should do depends on whether or not we have a cached name - LL_WARNS("AvNameCache") << "LLAvatarNameResponder::error " << status << " " << reason - << LL_ENDL; + LL_WARNS("AvNameCache") << dumpResponse() << LL_ENDL; // Add dummy records for any agent IDs in this request that we do not have cached already - std::vector::const_iterator it = mAgentIDs.begin(); + auto it = mAgentIDs.begin(); for ( ; it != mAgentIDs.end(); ++it) { const LLUUID& agent_id = *it; LLAvatarNameCache::handleAgentError(agent_id); } } - - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return avatarNameResponder_timeout; } - /*virtual*/ char const* getName(void) const { return "LLAvatarNameResponder"; } }; // Provide some fallback for agents that return errors @@ -284,48 +272,34 @@ void LLAvatarNameCache::handleAgentError(const LLUUID& agent_id) LL_WARNS("AvNameCache") << "LLAvatarNameCache get legacy for agent " << agent_id << LL_ENDL; gCacheName->get(agent_id, false, // legacy compatibility - boost::bind(&LLAvatarNameCache::legacyNameCallback, - _1, _2, _3)); + boost::bind(&LLAvatarNameCache::legacyNameFetch, _1, _2, _3)); } else { - // we have a chached (but probably expired) entry - since that would have + // we have a cached (but probably expired) entry - since that would have // been returned by the get method, there is no need to signal anyone // Clear this agent from the pending list LLAvatarNameCache::sPendingQueue.erase(agent_id); LLAvatarName& av_name = existing->second; - LL_DEBUGS("AvNameCache") << "LLAvatarNameCache use cache for agent " - << agent_id - << "user '" << av_name.mUsername << "' " - << "display '" << av_name.mDisplayName << "' " - << "expires in " << av_name.mExpires - LLFrameTimer::getTotalSeconds() << " seconds" - << LL_ENDL; - av_name.mExpires = LLFrameTimer::getTotalSeconds() + TEMP_CACHE_ENTRY_LIFETIME; // reset expiry time so we don't constantly rerequest. + LL_DEBUGS("AvNameCache") << "LLAvatarNameCache use cache for agent " << agent_id << LL_ENDL; + av_name.dump(); + + // Reset expiry time so we don't constantly rerequest. + av_name.setExpires(TEMP_CACHE_ENTRY_LIFETIME); } } -void LLAvatarNameCache::processName(const LLUUID& agent_id, - const LLAvatarName& av_name, - bool add_to_cache) +void LLAvatarNameCache::processName(const LLUUID& agent_id, const LLAvatarName& av_name) { - if (add_to_cache) - { - // sCache[agent_id] = av_name; - // [SL:KB] - Patch: Agent-DisplayNames | Checked: 2010-12-28 (Catznip-2.4.0h) | Added: Catznip-2.4.0h - // Don't replace existing entries with dummies - cache_t::iterator itName = (av_name.mIsTemporaryName) ? sCache.find(agent_id) : sCache.end(); - if (sCache.end() != itName) - itName->second.mExpires = av_name.mExpires; - else - sCache[agent_id] = av_name; - // [/SL:KB] - } + // Add to the cache + sCache[agent_id] = av_name; + // Suppress request from the queue sPendingQueue.erase(agent_id); - // signal everyone waiting on this name + // Signal everyone waiting on this name signal_map_t::iterator sig_it = sSignalMap.find(agent_id); if (sig_it != sSignalMap.end()) { @@ -353,16 +327,15 @@ void LLAvatarNameCache::requestNamesViaCapability() std::string url; url.reserve(NAME_URL_MAX); - std::vector agent_ids; + uuid_vec_t agent_ids; agent_ids.reserve(128); - U32 id_total = sAskQueue.size(); U32 ids = 0; ask_queue_t::const_iterator it; while(!sAskQueue.empty()) { it = sAskQueue.begin(); - const LLUUID& agent_id = *it; + const LLUUID agent_id = *it; sAskQueue.erase(it); if (url.empty()) @@ -392,9 +365,7 @@ void LLAvatarNameCache::requestNamesViaCapability() if (!url.empty()) { - LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::requestNamesViaCapability requested " - << ids << "/" << id_total << "ids " - << LL_ENDL; + LL_INFOS("AvNameCache") << "LLAvatarNameCache::requestNamesViaCapability getting " << ids << " ids" << LL_ENDL; LLHTTPClient::get(url, new LLAvatarNameResponder(agent_ids)); } } @@ -403,22 +374,32 @@ void LLAvatarNameCache::legacyNameCallback(const LLUUID& agent_id, const std::string& full_name, bool is_group) { - // Construct a dummy record for this name. By convention, SLID is blank - // Never expires, but not written to disk, so lasts until end of session. - LLAvatarName av_name; - LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::legacyNameCallback " - << "agent " << agent_id << " " + // Put the received data in the cache + legacyNameFetch(agent_id, full_name, is_group); + + // Retrieve the name and set it to never (or almost never...) expire: when we are using the legacy + // protocol, we do not get an expiration date for each name and there's no reason to ask the + // data again and again so we set the expiration time to the largest value admissible. + std::map::iterator av_record = sCache.find(agent_id); + LLAvatarName& av_name = av_record->second; + av_name.setExpires(MAX_UNREFRESHED_TIME); +} + +void LLAvatarNameCache::legacyNameFetch(const LLUUID& agent_id, + const std::string& full_name, + bool is_group) +{ + LL_DEBUGS("AvNameCache") << "LLAvatarNameCache agent " << agent_id << " " << "full name '" << full_name << "'" << ( is_group ? " [group]" : "" ) << LL_ENDL; - buildLegacyName(full_name, &av_name); - // Add to cache, because if we don't we'll keep rerequesting the - // same record forever. buildLegacyName should always guarantee - // that these records expire reasonably soon - // (in TEMP_CACHE_ENTRY_LIFETIME seconds), so if the failure was due - // to something temporary we will eventually request and get the right data. - processName(agent_id, av_name, true); + // Construct an av_name record from this name. + LLAvatarName av_name; + av_name.fromString(full_name); + + // Add to cache: we're still using the new cache even if we're using the old (legacy) protocol. + processName(agent_id, av_name); } void LLAvatarNameCache::requestNamesViaLegacy() @@ -440,25 +421,29 @@ void LLAvatarNameCache::requestNamesViaLegacy() LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::requestNamesViaLegacy agent " << agent_id << LL_ENDL; gCacheName->get(agent_id, false, // legacy compatibility - boost::bind(&LLAvatarNameCache::legacyNameCallback, - _1, _2, _3)); + boost::bind(&LLAvatarNameCache::legacyNameCallback, _1, _2, _3)); } } -void LLAvatarNameCache::initClass(bool running) +void LLAvatarNameCache::initClass(bool running, bool usePeopleAPI) { sRunning = running; + sUsePeopleAPI = usePeopleAPI; } void LLAvatarNameCache::cleanupClass() { + sCache.clear(); } -void LLAvatarNameCache::importFile(std::istream& istr) +bool LLAvatarNameCache::importFile(std::istream& istr) { LLSD data; - S32 parse_count = LLSDSerialize::fromXMLDocument(data, istr); - if (parse_count < 1) return; + if (LLSDParser::PARSE_FAILURE == LLSDSerialize::fromXMLDocument(data, istr)) + { + LL_WARNS("AvNameCache") << "avatar name cache data xml parse failed" << LL_ENDL; + return false; + } // by convention LLSD storage is a map // we only store one entry in the map @@ -473,29 +458,32 @@ void LLAvatarNameCache::importFile(std::istream& istr) av_name.fromLLSD( it->second ); sCache[agent_id] = av_name; } - LL_INFOS("AvNameCache") << "loaded " << sCache.size() << LL_ENDL; - + LL_INFOS("AvNameCache") << "LLAvatarNameCache loaded " << sCache.size() << LL_ENDL; // Some entries may have expired since the cache was stored, // but they will be flushed in the first call to eraseUnrefreshed // from LLAvatarNameResponder::idle + + return true; } void LLAvatarNameCache::exportFile(std::ostream& ostr) { LLSD agents; F64 max_unrefreshed = LLFrameTimer::getTotalSeconds() - MAX_UNREFRESHED_TIME; + LL_INFOS("AvNameCache") << "LLAvatarNameCache at exit cache has " << sCache.size() << LL_ENDL; cache_t::const_iterator it = sCache.begin(); for ( ; it != sCache.end(); ++it) { const LLUUID& agent_id = it->first; const LLAvatarName& av_name = it->second; // Do not write temporary or expired entries to the stored cache - if (!av_name.mIsTemporaryName && av_name.mExpires >= max_unrefreshed) + if (av_name.isValidName(max_unrefreshed)) { // key must be a string agents[agent_id.asString()] = av_name.asLLSD(); } } + LL_INFOS("AvNameCache") << "LLAvatarNameCache returning " << agents.size() << LL_ENDL; LLSD data; data["agents"] = agents; LLSDSerialize::toPrettyXML(data, ostr); @@ -511,6 +499,11 @@ bool LLAvatarNameCache::hasNameLookupURL() return !sNameLookupURL.empty(); } +bool LLAvatarNameCache::usePeopleAPI() +{ + return hasNameLookupURL() && sUsePeopleAPI; +} + void LLAvatarNameCache::idle() { // By convention, start running at first idle() call @@ -527,13 +520,13 @@ void LLAvatarNameCache::idle() if (!sAskQueue.empty()) { - if (useDisplayNames()) + if (usePeopleAPI()) { requestNamesViaCapability(); } else { - // ...fall back to legacy name cache system + LL_WARNS_ONCE("AvNameCache") << "LLAvatarNameCache still using legacy api" << LL_ENDL; requestNamesViaLegacy(); } } @@ -541,7 +534,7 @@ void LLAvatarNameCache::idle() if (sAskQueue.empty()) { // cleared the list, reset the request timer. - sRequestTimer.reset(SECS_BETWEEN_REQUESTS); + sRequestTimer.resetWithExpiry(SECS_BETWEEN_REQUESTS); } // erase anything that has not been refreshed for more than MAX_UNREFRESHED_TIME @@ -571,51 +564,29 @@ void LLAvatarNameCache::eraseUnrefreshed() if (!sLastExpireCheck || sLastExpireCheck < max_unrefreshed) { sLastExpireCheck = now; - + S32 expired = 0; for (cache_t::iterator it = sCache.begin(); it != sCache.end();) { const LLAvatarName& av_name = it->second; if (av_name.mExpires < max_unrefreshed) { - const LLUUID& agent_id = it->first; - LL_DEBUGS("AvNameCache") << agent_id - << " user '" << av_name.mUsername << "' " + LL_DEBUGS("AvNameCacheExpired") << "LLAvatarNameCache " << it->first + << " user '" << av_name.getAccountName() << "' " << "expired " << now - av_name.mExpires << " secs ago" << LL_ENDL; sCache.erase(it++); + expired++; } else { ++it; } } - LL_INFOS("AvNameCache") << sCache.size() << " cached avatar names" << LL_ENDL; + LL_INFOS("AvNameCache") << "LLAvatarNameCache expired " << expired << " cached avatar names, " + << sCache.size() << " remaining" << LL_ENDL; } } -void LLAvatarNameCache::buildLegacyName(const std::string& full_name, - LLAvatarName* av_name) -{ - llassert(av_name); - av_name->mUsername = ""; - av_name->mDisplayName = full_name; - av_name->mIsDisplayNameDefault = true; - av_name->mIsTemporaryName = true; - av_name->mExpires = LLFrameTimer::getTotalSeconds() + TEMP_CACHE_ENTRY_LIFETIME; - LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::buildLegacyName " - << full_name - << LL_ENDL; - - // [Ansariel/Henri] - // Why ain't those set? In case of disabled display names - // we would have to parse LLAvatarName::mDisplayName to get - // first and lastname if we need them. So do it already here - // for convenience. - std::istringstream fname(full_name); - fname >> av_name->mLegacyFirstName >> av_name->mLegacyLastName; - // [/Ansariel/Henri] -} - // fills in av_name if it has it in the cache, even if expired (can check expiry time) // returns bool specifying if av_name was filled, false otherwise bool LLAvatarNameCache::get(const LLUUID& agent_id, LLAvatarName *av_name) @@ -623,36 +594,31 @@ bool LLAvatarNameCache::get(const LLUUID& agent_id, LLAvatarName *av_name) if (sRunning) { // ...only do immediate lookups when cache is running - if (useDisplayNames()) + std::map::iterator it = sCache.find(agent_id); + if (it != sCache.end()) { - // ...use display names cache - std::map::iterator it = sCache.find(agent_id); - if (it != sCache.end()) - { - *av_name = it->second; + *av_name = it->second; - // re-request name if entry is expired - if (av_name->mExpires < LLFrameTimer::getTotalSeconds()) + // re-request name if entry is expired + if (av_name->mExpires < LLFrameTimer::getTotalSeconds()) + { + if (!isRequestPending(agent_id)) { - if (!isRequestPending(agent_id)) - { - LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::get " - << "refresh agent " << agent_id - << LL_ENDL; - sAskQueue.insert(agent_id); - } + LL_DEBUGS("AvNameCache") << "LLAvatarNameCache refresh agent " << agent_id + << LL_ENDL; + sAskQueue.insert(agent_id); } - - return true; } + + return true; } - else + else if (!usePeopleAPI()) { - // ...use legacy names cache std::string full_name; if (gCacheName->getFullName(agent_id, full_name)) { - buildLegacyName(full_name, av_name); + av_name->fromString(full_name); + sCache[agent_id] = *av_name; return true; } } @@ -660,38 +626,29 @@ bool LLAvatarNameCache::get(const LLUUID& agent_id, LLAvatarName *av_name) if (!isRequestPending(agent_id)) { - LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::get " - << "queue request for agent " << agent_id - << LL_ENDL; + LL_DEBUGS("AvNameCache") << "LLAvatarNameCache queue request for agent " << agent_id << LL_ENDL; sAskQueue.insert(agent_id); } return false; } -// Return true when name has been set to Phoenix Name System Name, if not return false. -bool LLAvatarNameCache::getPNSName(const LLUUID& agent_id, std::string& name) +const S32& main_name_system() +{ + static const LLCachedControl name_system("PhoenixNameSystem", 0); + return name_system; +} + +// Return true when name has been set to Name System Name, if not return false. +bool LLAvatarNameCache::getNSName(const LLUUID& agent_id, std::string& name, const S32& name_system) { LLAvatarName avatar_name; if (get(agent_id, &avatar_name)) - getPNSName(avatar_name, name); + name = avatar_name.getNSName(name_system); else return false; return true; } -// get() with callback compatible version of getPNSName -void LLAvatarNameCache::getPNSName(const LLAvatarName& avatar_name, std::string& name) -{ - static LLCachedControl phoenix_name_system("PhoenixNameSystem", 0); - switch (phoenix_name_system) - { - case 0 : name = avatar_name.getLegacyName(); break; - case 1 : name = avatar_name.getCompleteName(); break; - case 2 : name = avatar_name.mDisplayName; break; - default : name = avatar_name.getLegacyName(); break; - } -} - void LLAvatarNameCache::fireSignal(const LLUUID& agent_id, const callback_slot_t& slot, const LLAvatarName& av_name) @@ -708,30 +665,14 @@ LLAvatarNameCache::callback_connection_t LLAvatarNameCache::get(const LLUUID& ag if (sRunning) { // ...only do immediate lookups when cache is running - if (useDisplayNames()) - { - // ...use new cache - std::map::iterator it = sCache.find(agent_id); - if (it != sCache.end()) - { - const LLAvatarName& av_name = it->second; - - if (av_name.mExpires > LLFrameTimer::getTotalSeconds()) - { - // ...name already exists in cache, fire callback now - fireSignal(agent_id, slot, av_name); - return connection; - } - } - } - else + std::map::iterator it = sCache.find(agent_id); + if (it != sCache.end()) { - // ...use old name system - std::string full_name; - if (gCacheName->getFullName(agent_id, full_name)) + const LLAvatarName& av_name = it->second; + + if (av_name.mExpires > LLFrameTimer::getTotalSeconds()) { - LLAvatarName av_name; - buildLegacyName(full_name, &av_name); + // ...name already exists in cache, fire callback now fireSignal(agent_id, slot, av_name); return connection; } @@ -772,7 +713,7 @@ bool LLAvatarNameCache::getForceDisplayNames() void LLAvatarNameCache::setForceDisplayNames(bool force) { sForceDisplayNames = force; - if ( (!sUseDisplayNames) && (force) ) + if ( (!LLAvatarName::useDisplayNames()) && (force) ) { setUseDisplayNames(true); } @@ -785,20 +726,20 @@ void LLAvatarNameCache::setUseDisplayNames(bool use) // We need to force the use of the "display names" cache when @shownames=n restricted (and disallow toggling it) use |= getForceDisplayNames(); // [/RLVa:KB] - if (use != sUseDisplayNames) + if (use != LLAvatarName::useDisplayNames()) { - sUseDisplayNames = use; - // flush our cache - sCache.clear(); - + LLAvatarName::setUseDisplayNames(use); mUseDisplayNamesSignal(); } } -bool LLAvatarNameCache::useDisplayNames() +void LLAvatarNameCache::setUseUsernames(bool use) { - // Must be both manually set on and able to look up names. - return sUseDisplayNames && !sNameLookupURL.empty(); + if (use != LLAvatarName::useUsernames()) + { + LLAvatarName::setUseUsernames(use); + mUseDisplayNamesSignal(); + } } void LLAvatarNameCache::erase(const LLUUID& agent_id) @@ -832,6 +773,7 @@ bool LLAvatarNameCache::expirationFromCacheControl(AIHTTPReceivedHeaders const& { bool fromCacheControl = false; F64 now = LLFrameTimer::getTotalSeconds(); + // Allow the header to override the default std::string cache_control; if (headers.getFirstValue("cache-control", cache_control)) @@ -843,7 +785,7 @@ bool LLAvatarNameCache::expirationFromCacheControl(AIHTTPReceivedHeaders const& fromCacheControl = true; } } - LL_DEBUGS("AvNameCache") + LL_DEBUGS("AvNameCache") << "LLAvatarNameCache " << ( fromCacheControl ? "expires based on cache control " : "default expiration " ) << "in " << *expires - now << " seconds" << LL_ENDL; diff --git a/indra/llmessage/llavatarnamecache.h b/indra/llmessage/llavatarnamecache.h index 99e3fba576..457adcfc11 100644 --- a/indra/llmessage/llavatarnamecache.h +++ b/indra/llmessage/llavatarnamecache.h @@ -32,45 +32,41 @@ #include -class LLUUID; class AIHTTPReceivedHeaders; +class LLUUID; namespace LLAvatarNameCache { - typedef boost::signals2::signal use_display_name_signal_t; // Until the cache is set running, immediate lookups will fail and // async lookups will be queued. This allows us to block requests // until we know if the first region supports display names. - void initClass(bool running); + void initClass(bool running, bool usePeopleAPI); void cleanupClass(); - void importFile(std::istream& istr); + // Import/export the name cache to file. + bool importFile(std::istream& istr); void exportFile(std::ostream& ostr); - // On the viewer, usually a simulator capabilitity - // If empty, name cache will fall back to using legacy name - // lookup system + // On the viewer, usually a simulator capabilitity. + // If empty, name cache will fall back to using legacy name lookup system. void setNameLookupURL(const std::string& name_lookup_url); - // Do we have a valid lookup URL, hence are we trying to use the - // new display name lookup system? + // Do we have a valid lookup URL, i.e. are we trying to use the + // more recent display name lookup system? bool hasNameLookupURL(); + bool usePeopleAPI(); // Periodically makes a batch request for display names not already in - // cache. Call once per frame. + // cache. Called once per frame. void idle(); // If name is in cache, returns true and fills in provided LLAvatarName - // otherwise returns false + // otherwise returns false. bool get(const LLUUID& agent_id, LLAvatarName *av_name); - // If get() succeeds, returns true and fills in name string - // via void function below, otherwise returns false - bool getPNSName(const LLUUID& agent_id, std::string& name); - // Perform a filling of name string according to Phoenix Name System, - // when we have an LLAvatarName already. - void getPNSName(const LLAvatarName& avatar_name, std::string& name); + // If get() succeeds, returns true and fills in name string via void function below, otherwise returns false + bool getNSName(const LLUUID& agent_id, std::string& name, const S32& name_system = main_name_system()); // Callback types for get() below typedef boost::signals2::signal< @@ -79,29 +75,29 @@ namespace LLAvatarNameCache typedef callback_signal_t::slot_type callback_slot_t; typedef boost::signals2::connection callback_connection_t; - // Fetches name information and calls callback. - // If name information is in cache, callback will be called immediately. + // Fetches name information and calls callbacks. + // If name information is in cache, callbacks will be called immediately. callback_connection_t get(const LLUUID& agent_id, callback_slot_t slot); - // Allow display names to be explicitly disabled for testing. + // Set display name: flips the switch and triggers the callbacks. void setUseDisplayNames(bool use); - bool useDisplayNames(); // [RLVa:KB] - Checked: 2010-12-08 (RLVa-1.4.0a) | Added: RLVa-1.2.2c bool getForceDisplayNames(); void setForceDisplayNames(bool force); // [/RLVa:KB] + void setUseUsernames(bool use); + + void insert(const LLUUID& agent_id, const LLAvatarName& av_name); void erase(const LLUUID& agent_id); - /// Provide some fallback for agents that return errors + /// Provide some fallback for agents that return errors. void handleAgentError(const LLUUID& agent_id); - void insert(const LLUUID& agent_id, const LLAvatarName& av_name); - // Compute name expiration time from HTTP Cache-Control header, // or return default value, in seconds from epoch. - F64 nameExpirationFromHeaders(AIHTTPReceivedHeaders const& headers); + F64 nameExpirationFromHeaders(const AIHTTPReceivedHeaders& headers); void addUseDisplayNamesCallback(const use_display_name_signal_t::slot_type& cb); } diff --git a/indra/llmessage/llblowfishcipher.cpp b/indra/llmessage/llblowfishcipher.cpp index 88aaf7c52a..0b5025a422 100644 --- a/indra/llmessage/llblowfishcipher.cpp +++ b/indra/llmessage/llblowfishcipher.cpp @@ -70,10 +70,10 @@ U32 LLBlowfishCipher::encrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len) int blocksize = EVP_CIPHER_CTX_block_size(&context); int keylen = EVP_CIPHER_CTX_key_length(&context); int iv_length = EVP_CIPHER_CTX_iv_length(&context); - lldebugs << "LLBlowfishCipher blocksize " << blocksize + LL_DEBUGS() << "LLBlowfishCipher blocksize " << blocksize << " keylen " << keylen << " iv_len " << iv_length - << llendl; + << LL_ENDL; int output_len = 0; int temp_len = 0; @@ -83,7 +83,7 @@ U32 LLBlowfishCipher::encrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len) src, src_len)) { - llwarns << "LLBlowfishCipher::encrypt EVP_EncryptUpdate failure" << llendl; + LL_WARNS() << "LLBlowfishCipher::encrypt EVP_EncryptUpdate failure" << LL_ENDL; goto ERROR; } @@ -91,7 +91,7 @@ U32 LLBlowfishCipher::encrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len) // not an exact multiple of the block size. if (!EVP_EncryptFinal_ex(&context, (unsigned char*)(dst + output_len), &temp_len)) { - llwarns << "LLBlowfishCipher::encrypt EVP_EncryptFinal failure" << llendl; + LL_WARNS() << "LLBlowfishCipher::encrypt EVP_EncryptFinal failure" << LL_ENDL; goto ERROR; } output_len += temp_len; @@ -107,7 +107,7 @@ U32 LLBlowfishCipher::encrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len) // virtual U32 LLBlowfishCipher::decrypt(const U8* src, U32 src_len, U8* dst, U32 dst_len) { - llerrs << "LLBlowfishCipher decrypt unsupported" << llendl; + LL_ERRS() << "LLBlowfishCipher decrypt unsupported" << LL_ENDL; return 0; } diff --git a/indra/llmessage/llbuffer.cpp b/indra/llmessage/llbuffer.cpp index 41db8be23d..7d99031526 100644 --- a/indra/llmessage/llbuffer.cpp +++ b/indra/llmessage/llbuffer.cpp @@ -180,8 +180,8 @@ bool LLHeapBuffer::reclaimSegment(const LLSegment& segment) } else if(mReclaimedBytes > mSize) { - llwarns << "LLHeapBuffer reclaimed more memory than allocated." - << " This is probably programmer error." << llendl; + LL_WARNS() << "LLHeapBuffer reclaimed more memory than allocated." + << " This is probably programmer error." << LL_ENDL; } return true; } diff --git a/indra/llmessage/llbuffer.h b/indra/llmessage/llbuffer.h index c7624bde30..b7b0fe0142 100644 --- a/indra/llmessage/llbuffer.h +++ b/indra/llmessage/llbuffer.h @@ -306,7 +306,7 @@ class LLBufferArray typedef std::list segment_list_t; typedef segment_list_t::const_iterator const_segment_iterator_t; typedef segment_list_t::iterator segment_iterator_t; - static size_t const npos = (size_t)-1; // (U8*)npos is used as a magic address. + enum { npos = 0xffffffff }; LLBufferArray(); ~LLBufferArray(); diff --git a/indra/llmessage/llbufferstream.cpp b/indra/llmessage/llbufferstream.cpp index a51a48edc3..15e90872a4 100644 --- a/indra/llmessage/llbufferstream.cpp +++ b/indra/llmessage/llbufferstream.cpp @@ -53,7 +53,7 @@ LLBufferStreamBuf::~LLBufferStreamBuf() // virtual int LLBufferStreamBuf::underflow() { - //lldebugs << "LLBufferStreamBuf::underflow()" << llendl; + //LL_DEBUGS() << "LLBufferStreamBuf::underflow()" << LL_ENDL; if(!mBuffer) { return EOF; @@ -233,17 +233,10 @@ int LLBufferStreamBuf::sync() } // virtual -#if( LL_WINDOWS || __GNUC__ > 2) LLBufferStreamBuf::pos_type LLBufferStreamBuf::seekoff( LLBufferStreamBuf::off_type off, std::ios::seekdir way, std::ios::openmode which) -#else -streampos LLBufferStreamBuf::seekoff( - streamoff off, - std::ios::seekdir way, - std::ios::openmode which) -#endif { if(!mBuffer || ((way == std::ios::beg) && (off < 0)) @@ -318,12 +311,8 @@ streampos LLBufferStreamBuf::seekoff( } } -#if( LL_WINDOWS || __GNUC__ > 2 ) S32 rv = (S32)(intptr_t)address; return (pos_type)rv; -#else - return (streampos)address; -#endif } diff --git a/indra/llmessage/llbufferstream.h b/indra/llmessage/llbufferstream.h index 723269307e..33ce6a68d6 100644 --- a/indra/llmessage/llbufferstream.h +++ b/indra/llmessage/llbufferstream.h @@ -48,10 +48,8 @@ class LLBufferStreamBuf : public std::streambuf virtual ~LLBufferStreamBuf(); protected: -#if( LL_WINDOWS || __GNUC__ > 2 ) typedef std::streambuf::pos_type pos_type; typedef std::streambuf::off_type off_type; -#endif /* @name streambuf vrtual implementations */ @@ -87,17 +85,10 @@ class LLBufferStreamBuf : public std::streambuf * or both masked together. * @return Returns the new position or an invalid position on failure. */ -#if( LL_WINDOWS || __GNUC__ > 2) virtual pos_type seekoff( off_type off, std::ios::seekdir way, std::ios::openmode which); -#else - virtual streampos seekoff( - streamoff off, - std::ios::seekdir way, - std::ios::openmode which); -#endif /* * @brief Get s sequence of characters from the input diff --git a/indra/llmessage/llcachename.cpp b/indra/llmessage/llcachename.cpp index e14993dcf1..6dfc69d6a2 100644 --- a/indra/llmessage/llcachename.cpp +++ b/indra/llmessage/llcachename.cpp @@ -185,7 +185,7 @@ void ReplySender::flush() } -typedef std::set AskQueue; +typedef uuid_set_t AskQueue; typedef std::list ReplyQueue; typedef std::map PendingQueue; typedef std::map Cache; @@ -262,6 +262,8 @@ LLCacheName::~LLCacheName() delete &impl; } +const ReverseCache& LLCacheName::getReverseMap() const { return impl.mReverseCache; } + LLCacheName::Impl::Impl(LLMessageSystem* msg) : mMsg(msg), mUpstreamHost(LLHost::invalid) { @@ -279,7 +281,9 @@ LLCacheName::Impl::Impl(LLMessageSystem* msg) LLCacheName::Impl::~Impl() { for_each(mCache.begin(), mCache.end(), DeletePairedPointer()); + mCache.clear(); for_each(mReplyQueue.begin(), mReplyQueue.end(), DeletePointer()); + mReplyQueue.clear(); } boost::signals2::connection LLCacheName::Impl::addPending(const LLUUID& id, const LLCacheNameCallback& callback) @@ -309,8 +313,10 @@ boost::signals2::connection LLCacheName::addObserver(const LLCacheNameCallback& bool LLCacheName::importFile(std::istream& istr) { LLSD data; - if(LLSDSerialize::fromXMLDocument(data, istr) < 1) + if(LLSDParser::PARSE_FAILURE == LLSDSerialize::fromXMLDocument(data, istr)) + { return false; + } // We'll expire entries more than a week old U32 now = (U32)time(NULL); @@ -340,7 +346,7 @@ bool LLCacheName::importFile(std::istream& istr) ++count; } - llinfos << "LLCacheName loaded " << count << " agent names" << llendl; + LL_INFOS() << "LLCacheName loaded " << count << " agent names" << LL_ENDL; count = 0; LLSD groups = data[GROUPS]; @@ -361,7 +367,7 @@ bool LLCacheName::importFile(std::istream& istr) impl.mReverseCache[entry->mGroupName] = id; ++count; } - llinfos << "LLCacheName loaded " << count << " group names" << llendl; + LL_INFOS() << "LLCacheName loaded " << count << " group names" << LL_ENDL; return true; } @@ -437,7 +443,7 @@ void LLCacheName::localizeCacheName(std::string key, std::string value) if (key!="" && value!= "" ) sCacheName[key]=value; else - llwarns<< " Error localizing cache key " << key << " To "<< value< we must ask for it - lldebugs << "LLCacheName queuing HACK group request: " << id << llendl; + LL_DEBUGS() << "LLCacheName queuing HACK group request: " << id << LL_ENDL; entry = NULL; } @@ -527,6 +533,7 @@ std::string LLCacheName::cleanFullName(const std::string& full_name) } //static +// Transform hard-coded name provided by server to a more legible username std::string LLCacheName::buildUsername(const std::string& full_name) { // rare, but handle hard-coded error names returned from server @@ -553,8 +560,9 @@ std::string LLCacheName::buildUsername(const std::string& full_name) return username; } - // if the input wasn't a correctly formatted legacy name just return it unchanged - return full_name; + // if the input wasn't a correctly formatted legacy name, just return it + // cleaned up from a potential terminal "Resident" + return cleanFullName(full_name); } //static @@ -562,13 +570,13 @@ std::string LLCacheName::buildLegacyName(const std::string& complete_name) { //boost::regexp was showing up in the crashreporter, so doing //painfully manual parsing using substr. LF - S32 open_paren = complete_name.rfind(" ("); - S32 close_paren = complete_name.rfind(')'); + size_t open_paren = complete_name.rfind(" ("); + size_t close_paren = complete_name.rfind(')'); if (open_paren != std::string::npos && close_paren == complete_name.length()-1) { - S32 length = close_paren - open_paren - 2; + size_t length = llmax(close_paren - open_paren - 2, (size_t)0); std::string legacy_name = complete_name.substr(open_paren+2, length); if (legacy_name.length() > 0) @@ -577,7 +585,7 @@ std::string LLCacheName::buildLegacyName(const std::string& complete_name) LLStringUtil::toUpper(cap_letter); legacy_name = cap_letter + legacy_name.substr(1); - S32 separator = legacy_name.find('.'); + size_t separator = legacy_name.find('.'); if (separator != std::string::npos) { @@ -668,32 +676,18 @@ boost::signals2::connection LLCacheName::get(const LLUUID& id, bool is_group, ol // bool LLCacheName::getIfThere(const LLUUID& id, std::string& fullname, BOOL& is_group) { - if(id.isNull()) - { - fullname = ""; - return false; - } - - LLCacheNameEntry* entry = get_ptr_in_map(impl.mCache, id ); - if (entry) + if (id.notNull()) + if (LLCacheNameEntry* entry = get_ptr_in_map(impl.mCache, id)) { - if (entry->mIsGroup) - { - fullname = entry->mGroupName; - } - else - { - fullname = entry->mFirstName + " " + entry->mLastName; - } - is_group = entry->mIsGroup; + fullname = (is_group = entry->mIsGroup) ? entry->mGroupName : entry->mFirstName + " " + entry->mLastName; return true; } + fullname = ""; return false; } // - void LLCacheName::processPending() { const F32 SECS_BETWEEN_PROCESS = 0.1f; @@ -704,8 +698,8 @@ void LLCacheName::processPending() if(!impl.mUpstreamHost.isOk()) { - lldebugs << "LLCacheName::processPending() - bad upstream host." - << llendl; + LL_DEBUGS() << "LLCacheName::processPending() - bad upstream host." + << LL_ENDL; return; } @@ -752,33 +746,33 @@ void LLCacheName::dump() LLCacheNameEntry* entry = iter->second; if (entry->mIsGroup) { - llinfos + LL_INFOS() << iter->first << " = (group) " << entry->mGroupName << " @ " << entry->mCreateTime - << llendl; + << LL_ENDL; } else { - llinfos + LL_INFOS() << iter->first << " = " << buildFullName(entry->mFirstName, entry->mLastName) << " @ " << entry->mCreateTime - << llendl; + << LL_ENDL; } } } void LLCacheName::dumpStats() { - llinfos << "Queue sizes: " + LL_INFOS() << "Queue sizes: " << " Cache=" << impl.mCache.size() << " AskName=" << impl.mAskNameQueue.size() << " AskGroup=" << impl.mAskGroupQueue.size() << " Pending=" << impl.mPendingQueue.size() << " Reply=" << impl.mReplyQueue.size() // << " Observers=" << impl.mSignal.size() - << llendl; + << LL_ENDL; } void LLCacheName::clear() @@ -914,7 +908,7 @@ void LLCacheName::Impl::processUUIDRequest(LLMessageSystem* msg, bool isGroup) // level, hence having an upstream provider. if (!mUpstreamHost.isOk()) { - llwarns << "LLCacheName - got UUID name/group request, but no upstream provider!" << llendl; + LL_WARNS() << "LLCacheName - got UUID name/group request, but no upstream provider!" << LL_ENDL; return; } @@ -931,11 +925,11 @@ void LLCacheName::Impl::processUUIDRequest(LLMessageSystem* msg, bool isGroup) { if (isGroup != entry->mIsGroup) { - llwarns << "LLCacheName - Asked for " + LL_WARNS() << "LLCacheName - Asked for " << (isGroup ? "group" : "user") << " name, " << "but found " << (entry->mIsGroup ? "group" : "user") - << ": " << id << llendl; + << ": " << id << LL_ENDL; } else { diff --git a/indra/llmessage/llcachename.h b/indra/llmessage/llcachename.h index 4c96ba0d33..58dcd3b4ef 100644 --- a/indra/llmessage/llcachename.h +++ b/indra/llmessage/llcachename.h @@ -40,7 +40,7 @@ typedef boost::signals2::signal LLCacheNameSignal; typedef LLCacheNameSignal::slot_type LLCacheNameCallback; -// Old callback with user data for compatability +// Old callback with user data for compatibility typedef void (*old_callback_t)(const LLUUID&, const std::string&, bool, void*); // Here's the theory: @@ -57,6 +57,8 @@ class LLCacheName LLCacheName(LLMessageSystem* msg, const LLHost& upstream_host); ~LLCacheName(); + const std::map& getReverseMap() const; + // registers the upstream host // for viewers, this is the currently connected simulator // for simulators, this is the data server @@ -107,7 +109,7 @@ class LLCacheName // otherwise, will request the data, and will call the callback when // available. There is no garuntee the callback will ever be called. boost::signals2::connection get(const LLUUID& id, bool is_group, const LLCacheNameCallback& callback); - + // bool getIfThere(const LLUUID& id, std::string& fullname, BOOL& is_group); // diff --git a/indra/llmessage/llcircuit.cpp b/indra/llmessage/llcircuit.cpp index 6bb435f537..3043f61e6c 100644 --- a/indra/llmessage/llcircuit.cpp +++ b/indra/llmessage/llcircuit.cpp @@ -61,12 +61,12 @@ const S32 PING_START_BLOCK = 3; // How many pings behind we have to be to consider ourself blocked. const S32 PING_RELEASE_BLOCK = 2; // How many pings behind we have to be to consider ourself unblocked. -const F32 TARGET_PERIOD_LENGTH = 5.f; // seconds -const F32 LL_DUPLICATE_SUPPRESSION_TIMEOUT = 60.f; //seconds - this can be long, as time-based cleanup is +const F32Seconds TARGET_PERIOD_LENGTH(5.f); +const F32Seconds LL_DUPLICATE_SUPPRESSION_TIMEOUT(60.f); //this can be long, as time-based cleanup is // only done when wrapping packetids, now... LLCircuitData::LLCircuitData(const LLHost &host, TPACKETID in_id, - const F32 circuit_heartbeat_interval, const F32 circuit_timeout) + const F32Seconds circuit_heartbeat_interval, const F32Seconds circuit_timeout) : mHost (host), mWrapID(0), mPacketsOutID(0), @@ -85,7 +85,7 @@ LLCircuitData::LLCircuitData(const LLHost &host, TPACKETID in_id, mPingsInTransit(0), mLastPingID(0), mPingDelay(INITIAL_PING_VALUE_MSEC), - mPingDelayAveraged((F32)INITIAL_PING_VALUE_MSEC), + mPingDelayAveraged(INITIAL_PING_VALUE_MSEC), mUnackedPacketCount(0), mUnackedPacketBytes(0), mLastPacketInTime(0.0), @@ -104,6 +104,7 @@ LLCircuitData::LLCircuitData(const LLHost &host, TPACKETID in_id, mPeakBPSOut(0.f), mPeriodTime(0.0), mExistenceTimer(), + mAckCreationTime(0.f), mCurrentResendCount(0), mLastPacketGap(0), mHeartbeatInterval(circuit_heartbeat_interval), @@ -111,13 +112,13 @@ LLCircuitData::LLCircuitData(const LLHost &host, TPACKETID in_id, { // Need to guarantee that this time is up to date, we may be creating a circuit even though we haven't been // running a message system loop. - F64 mt_sec = LLMessageSystem::getMessageTimeSeconds(TRUE); + F64Seconds mt_sec = LLMessageSystem::getMessageTimeSeconds(TRUE); F32 distribution_offset = ll_frand(); mPingTime = mt_sec; mLastPingSendTime = mt_sec + mHeartbeatInterval * distribution_offset; mLastPingReceivedTime = mt_sec; - mNextPingSendTime = mLastPingSendTime + 0.95*mHeartbeatInterval + ll_frand(0.1f*mHeartbeatInterval); + mNextPingSendTime = mLastPingSendTime + 0.95*mHeartbeatInterval + F32Seconds(ll_frand(0.1f*mHeartbeatInterval.value())); mPeriodTime = mt_sec; mLocalEndPointID.generate(); @@ -184,7 +185,7 @@ LLCircuitData::~LLCircuitData() std::ostream_iterator append(str, " "); str << "MSG: -> " << mHost << "\tABORTING RELIABLE:\t"; std::copy(doomed.begin(), doomed.end(), append); - llinfos << str.str() << llendl; + LL_INFOS() << str.str() << LL_ENDL; } } @@ -204,11 +205,11 @@ void LLCircuitData::ackReliablePacket(TPACKETID packet_num) std::ostringstream str; str << "MSG: <- " << packetp->mHost << "\tRELIABLE ACKED:\t" << packetp->mPacketID; - llinfos << str.str() << llendl; + LL_INFOS() << str.str() << LL_ENDL; } if (packetp->mCallback) { - if (packetp->mTimeout < 0.f) // negative timeout will always return timeout even for successful ack, for debugging + if (packetp->mTimeout < F32Seconds(0.f)) // negative timeout will always return timeout even for successful ack, for debugging { packetp->mCallback(packetp->mCallbackData,LL_ERR_TCP_TIMEOUT); } @@ -232,17 +233,17 @@ void LLCircuitData::ackReliablePacket(TPACKETID packet_num) if (iter != mFinalRetryPackets.end()) { packetp = iter->second; - // llinfos << "Packet " << packet_num << " removed from the pending list" << llendl; + // LL_INFOS() << "Packet " << packet_num << " removed from the pending list" << LL_ENDL; if(gMessageSystem->mVerboseLog) { std::ostringstream str; str << "MSG: <- " << packetp->mHost << "\tRELIABLE ACKED:\t" << packetp->mPacketID; - llinfos << str.str() << llendl; + LL_INFOS() << str.str() << LL_ENDL; } if (packetp->mCallback) { - if (packetp->mTimeout < 0.f) // negative timeout will always return timeout even for successful ack, for debugging + if (packetp->mTimeout < F32Seconds(0.f)) // negative timeout will always return timeout even for successful ack, for debugging { packetp->mCallback(packetp->mCallbackData,LL_ERR_TCP_TIMEOUT); } @@ -269,7 +270,7 @@ void LLCircuitData::ackReliablePacket(TPACKETID packet_num) -S32 LLCircuitData::resendUnackedPackets(const F64 now) +S32 LLCircuitData::resendUnackedPackets(const F64Seconds now) { S32 resent_packets = 0; LLReliablePacket *packetp; @@ -321,8 +322,8 @@ S32 LLCircuitData::resendUnackedPackets(const F64 now) if (mUnackedPacketBytes > 256000 && !(getPacketsOut() % 1024)) { // Warn if we've got a lot of resends waiting. - llwarns << mHost << " has " << mUnackedPacketBytes - << " bytes of reliable messages waiting" << llendl; + LL_WARNS() << mHost << " has " << mUnackedPacketBytes + << " bytes of reliable messages waiting" << LL_ENDL; } // Stop resending. There are less than 512000 unacked packets. break; @@ -342,7 +343,7 @@ S32 LLCircuitData::resendUnackedPackets(const F64 now) std::ostringstream str; str << "MSG: -> " << packetp->mHost << "\tRESENDING RELIABLE:\t" << packetp->mPacketID; - llinfos << str.str() << llendl; + LL_INFOS() << str.str() << LL_ENDL; } packetp->mBuffer[0] |= LL_RESENT_FLAG; // tag packet id as being a resend @@ -356,7 +357,7 @@ S32 LLCircuitData::resendUnackedPackets(const F64 now) // The new method, retry time based on ping if (packetp->mPingBasedRetry) { - packetp->mExpirationTime = now + llmax(LL_MINIMUM_RELIABLE_TIMEOUT_SECONDS, (LL_RELIABLE_TIMEOUT_FACTOR * getPingDelayAveraged())); + packetp->mExpirationTime = now + llmax(LL_MINIMUM_RELIABLE_TIMEOUT_SECONDS, F32Seconds(LL_RELIABLE_TIMEOUT_FACTOR * getPingDelayAveraged())); } else { @@ -391,10 +392,10 @@ S32 LLCircuitData::resendUnackedPackets(const F64 now) if (now > packetp->mExpirationTime) { // fail (too many retries) - //llinfos << "Packet " << packetp->mPacketID << " removed from the pending list: exceeded retry limit" << llendl; + //LL_INFOS() << "Packet " << packetp->mPacketID << " removed from the pending list: exceeded retry limit" << LL_ENDL; //if (packetp->mMessageName) //{ - // llinfos << "Packet name " << packetp->mMessageName << llendl; + // LL_INFOS() << "Packet name " << packetp->mMessageName << LL_ENDL; //} gMessageSystem->mFailedResendPackets++; @@ -403,7 +404,7 @@ S32 LLCircuitData::resendUnackedPackets(const F64 now) std::ostringstream str; str << "MSG: -> " << packetp->mHost << "\tABORTING RELIABLE:\t" << packetp->mPacketID; - llinfos << str.str() << llendl; + LL_INFOS() << str.str() << LL_ENDL; } if (packetp->mCallback) @@ -428,10 +429,11 @@ S32 LLCircuitData::resendUnackedPackets(const F64 now) } -LLCircuit::LLCircuit(const F32 circuit_heartbeat_interval, const F32 circuit_timeout) : mLastCircuit(NULL), - mHeartbeatInterval(circuit_heartbeat_interval), mHeartbeatTimeout(circuit_timeout) -{ -} +LLCircuit::LLCircuit(const F32Seconds circuit_heartbeat_interval, const F32Seconds circuit_timeout) +: mLastCircuit(NULL), + mHeartbeatInterval(circuit_heartbeat_interval), + mHeartbeatTimeout(circuit_timeout) +{} LLCircuit::~LLCircuit() { @@ -446,7 +448,7 @@ LLCircuit::~LLCircuit() LLCircuitData *LLCircuit::addCircuitData(const LLHost &host, TPACKETID in_id) { // This should really validate if one already exists - llinfos << "LLCircuit::addCircuitData for " << host << llendl; + LL_INFOS() << "LLCircuit::addCircuitData for " << host << LL_ENDL; LLCircuitData *tempp = new LLCircuitData(host, in_id, mHeartbeatInterval, mHeartbeatTimeout); mCircuitData.insert(circuit_data_map::value_type(host, tempp)); mPingSet.insert(tempp); @@ -457,7 +459,7 @@ LLCircuitData *LLCircuit::addCircuitData(const LLHost &host, TPACKETID in_id) void LLCircuit::removeCircuitData(const LLHost &host) { - llinfos << "LLCircuit::removeCircuitData for " << host << llendl; + LL_INFOS() << "LLCircuit::removeCircuitData for " << host << LL_ENDL; mLastCircuit = NULL; circuit_data_map::iterator it = mCircuitData.find(host); if(it != mCircuitData.end()) @@ -472,7 +474,7 @@ void LLCircuit::removeCircuitData(const LLHost &host) } else { - llwarns << "Couldn't find entry for next ping in ping set!" << llendl; + LL_WARNS() << "Couldn't find entry for next ping in ping set!" << LL_ENDL; } // Clean up from optimization maps @@ -522,17 +524,17 @@ void LLCircuitData::setAllowTimeout(BOOL allow) // Reset per-period counters if necessary. void LLCircuitData::checkPeriodTime() { - F64 mt_sec = LLMessageSystem::getMessageTimeSeconds(); - F64 period_length = mt_sec - mPeriodTime; + F64Seconds mt_sec = LLMessageSystem::getMessageTimeSeconds(); + F64Seconds period_length = mt_sec - mPeriodTime; if ( period_length > TARGET_PERIOD_LENGTH) { - F32 bps_in = (F32)(mBytesInThisPeriod * 8.f / period_length); + F32 bps_in = F32Bits(mBytesInThisPeriod).value() / period_length.value(); if (bps_in > mPeakBPSIn) { mPeakBPSIn = bps_in; } - F32 bps_out = (F32)(mBytesOutThisPeriod * 8.f / period_length); + F32 bps_out = F32Bits(mBytesOutThisPeriod).value() / period_length.value(); if (bps_out > mPeakBPSOut) { mPeakBPSOut = bps_out; @@ -540,23 +542,23 @@ void LLCircuitData::checkPeriodTime() mBytesInLastPeriod = mBytesInThisPeriod; mBytesOutLastPeriod = mBytesOutThisPeriod; - mBytesInThisPeriod = 0; - mBytesOutThisPeriod = 0; - mLastPeriodLength = (F32)period_length; + mBytesInThisPeriod = S32Bytes(0); + mBytesOutThisPeriod = S32Bytes(0); + mLastPeriodLength = F32Seconds::convert(period_length); mPeriodTime = mt_sec; } } -void LLCircuitData::addBytesIn(S32 bytes) +void LLCircuitData::addBytesIn(S32Bytes bytes) { mBytesIn += bytes; mBytesInThisPeriod += bytes; } -void LLCircuitData::addBytesOut(S32 bytes) +void LLCircuitData::addBytesOut(S32Bytes bytes) { mBytesOut += bytes; mBytesOutThisPeriod += bytes; @@ -585,7 +587,7 @@ void LLCircuitData::addReliablePacket(S32 mSocket, U8 *buf_ptr, S32 buf_len, LLR void LLCircuit::resendUnackedPackets(S32& unacked_list_length, S32& unacked_list_size) { - F64 now = LLMessageSystem::getMessageTimeSeconds(); + F64Seconds now = LLMessageSystem::getMessageTimeSeconds(); unacked_list_length = 0; unacked_list_size = 0; @@ -720,14 +722,14 @@ void LLCircuitData::checkPacketInID(TPACKETID id, BOOL receive_resent) { std::ostringstream str; str << "MSG: <- " << mHost << "\tRECOVERING LOST:\t" << id; - llinfos << str.str() << llendl; + LL_INFOS() << str.str() << LL_ENDL; } - // llinfos << "removing potential lost: " << id << llendl; + // LL_INFOS() << "removing potential lost: " << id << LL_ENDL; mPotentialLostPackets.erase(id); } else if (!receive_resent) // don't freak out over out-of-order reliable resends { - U64 time = LLMessageSystem::getMessageTimeUsecs(); + U64Microseconds time = LLMessageSystem::getMessageTimeUsecs(); TPACKETID index = mPacketsInID; S32 gap_count = 0; if ((index < id) && ((id - index) < 16)) @@ -739,10 +741,10 @@ void LLCircuitData::checkPacketInID(TPACKETID id, BOOL receive_resent) std::ostringstream str; str << "MSG: <- " << mHost << "\tPACKET GAP:\t" << index; - llinfos << str.str() << llendl; + LL_INFOS() << str.str() << LL_ENDL; } -// llinfos << "adding potential lost: " << index << llendl; +// LL_INFOS() << "adding potential lost: " << index << LL_ENDL; mPotentialLostPackets[index] = time; index++; index = index % LL_MAX_OUT_PACKET_ID; @@ -751,13 +753,13 @@ void LLCircuitData::checkPacketInID(TPACKETID id, BOOL receive_resent) } else { - llinfos << "packet_out_of_order - got packet " << id << " expecting " << index << " from " << mHost << llendl; + LL_INFOS() << "packet_out_of_order - got packet " << id << " expecting " << index << " from " << mHost << LL_ENDL; if(gMessageSystem->mVerboseLog) { std::ostringstream str; str << "MSG: <- " << mHost << "\tPACKET GAP:\t" << id << " expected " << index; - llinfos << str.str() << llendl; + LL_INFOS() << str.str() << LL_ENDL; } } @@ -766,11 +768,11 @@ void LLCircuitData::checkPacketInID(TPACKETID id, BOOL receive_resent) if (gap_count > 128) { - llwarns << "Packet loss gap filler running amok!" << llendl; + LL_WARNS() << "Packet loss gap filler running amok!" << LL_ENDL; } else if (gap_count > 16) { - llwarns << "Sustaining large amounts of packet loss!" << llendl; + LL_WARNS() << "Sustaining large amounts of packet loss!" << LL_ENDL; } } @@ -781,7 +783,7 @@ void LLCircuitData::checkPacketInID(TPACKETID id, BOOL receive_resent) void LLCircuit::updateWatchDogTimers(LLMessageSystem *msgsys) { - F64 cur_time = LLMessageSystem::getMessageTimeSeconds(); + F64Seconds cur_time = LLMessageSystem::getMessageTimeSeconds(); S32 count = mPingSet.size(); S32 cur = 0; @@ -819,7 +821,7 @@ void LLCircuit::updateWatchDogTimers(LLMessageSystem *msgsys) if (cdp->updateWatchDogTimers(msgsys)) { // Randomize our pings a bit by doing some up to 5% early or late - F64 dt = 0.95f*mHeartbeatInterval + ll_frand(0.1f*mHeartbeatInterval); + F64Seconds dt = 0.95f*mHeartbeatInterval + F32Seconds(ll_frand(0.1f*mHeartbeatInterval.value())); // Remove it, and reinsert it with the new next ping time. // Always remove before changing the sorting key. @@ -847,7 +849,7 @@ void LLCircuit::updateWatchDogTimers(LLMessageSystem *msgsys) BOOL LLCircuitData::updateWatchDogTimers(LLMessageSystem *msgsys) { - F64 cur_time = LLMessageSystem::getMessageTimeSeconds(); + F64Seconds cur_time = LLMessageSystem::getMessageTimeSeconds(); mLastPingSendTime = cur_time; if (!checkCircuitTimeout()) @@ -890,8 +892,8 @@ BOOL LLCircuitData::updateWatchDogTimers(LLMessageSystem *msgsys) wrapped_final = TRUE; } - //llinfos << mHost << " - unacked count " << mUnackedPackets.size() << llendl; - //llinfos << mHost << " - final count " << mFinalRetryPackets.size() << llendl; + //LL_INFOS() << mHost << " - unacked count " << mUnackedPackets.size() << LL_ENDL; + //LL_INFOS() << mHost << " - final count " << mFinalRetryPackets.size() << LL_ENDL; if (wrapped != wrapped_final) { // One of the "unacked" or "final" lists hasn't wrapped. Whichever one @@ -901,12 +903,12 @@ BOOL LLCircuitData::updateWatchDogTimers(LLMessageSystem *msgsys) // Hasn't wrapped, so the one on the // unacked packet list is older packet_id = iter->first; - //llinfos << mHost << ": nowrapped unacked" << llendl; + //LL_INFOS() << mHost << ": nowrapped unacked" << LL_ENDL; } else { packet_id = iter_final->first; - //llinfos << mHost << ": nowrapped final" << llendl; + //LL_INFOS() << mHost << ": nowrapped final" << LL_ENDL; } } else @@ -918,7 +920,7 @@ BOOL LLCircuitData::updateWatchDogTimers(LLMessageSystem *msgsys) // Send the ID of the last packet we sent out. // This will flush all of the destination's // unacked packets, theoretically. - //llinfos << mHost << ": No unacked!" << llendl; + //LL_INFOS() << mHost << ": No unacked!" << LL_ENDL; packet_id = getPacketOutID(); } else @@ -929,7 +931,7 @@ BOOL LLCircuitData::updateWatchDogTimers(LLMessageSystem *msgsys) // Unacked list has the lowest so far packet_id = iter->first; had_unacked = TRUE; - //llinfos << mHost << ": Unacked" << llendl; + //LL_INFOS() << mHost << ": Unacked" << LL_ENDL; } if (iter_final != mFinalRetryPackets.end()) @@ -939,13 +941,13 @@ BOOL LLCircuitData::updateWatchDogTimers(LLMessageSystem *msgsys) { // Both had a packet, use the lowest. packet_id = llmin(packet_id, iter_final->first); - //llinfos << mHost << ": Min of unacked/final" << llendl; + //LL_INFOS() << mHost << ": Min of unacked/final" << LL_ENDL; } else { // Only the final had a packet, use it. packet_id = iter_final->first; - //llinfos << mHost << ": Final!" << llendl; + //LL_INFOS() << mHost << ": Final!" << LL_ENDL; } } } @@ -964,12 +966,12 @@ BOOL LLCircuitData::updateWatchDogTimers(LLMessageSystem *msgsys) // be considered lost LLCircuitData::packet_time_map::iterator it; - U64 timeout = (U64)(1000000.0*llmin(LL_MAX_LOST_TIMEOUT, getPingDelayAveraged() * LL_LOST_TIMEOUT_FACTOR)); + U64Microseconds timeout = llmin(LL_MAX_LOST_TIMEOUT, F32Seconds(getPingDelayAveraged()) * LL_LOST_TIMEOUT_FACTOR); - U64 mt_usec = LLMessageSystem::getMessageTimeUsecs(); + U64Microseconds mt_usec = LLMessageSystem::getMessageTimeUsecs(); for (it = mPotentialLostPackets.begin(); it != mPotentialLostPackets.end(); ) { - U64 delta_t_usec = mt_usec - (*it).second; + U64Microseconds delta_t_usec = mt_usec - (*it).second; if (delta_t_usec > timeout) { // let's call this one a loss! @@ -980,7 +982,7 @@ BOOL LLCircuitData::updateWatchDogTimers(LLMessageSystem *msgsys) std::ostringstream str; str << "MSG: <- " << mHost << "\tLOST PACKET:\t" << (*it).first; - llinfos << str.str() << llendl; + LL_INFOS() << str.str() << LL_ENDL; } mPotentialLostPackets.erase(it++); } @@ -1000,8 +1002,8 @@ void LLCircuitData::clearDuplicateList(TPACKETID oldest_id) // we want to KEEP all x where oldest_id <= x <= last incoming packet, and delete everything else. - //llinfos << mHost << ": clearing before oldest " << oldest_id << llendl; - //llinfos << "Recent list before: " << mRecentlyReceivedReliablePackets.size() << llendl; + //LL_INFOS() << mHost << ": clearing before oldest " << oldest_id << LL_ENDL; + //LL_INFOS() << "Recent list before: " << mRecentlyReceivedReliablePackets.size() << LL_ENDL; if (oldest_id < mHighestPacketID) { // Clean up everything with a packet ID less than oldest_id. @@ -1015,7 +1017,7 @@ void LLCircuitData::clearDuplicateList(TPACKETID oldest_id) // Do timeout checks on everything with an ID > mHighestPacketID. // This should be empty except for wrapping IDs. Thus, this should be // highly rare. - U64 mt_usec = LLMessageSystem::getMessageTimeUsecs(); + U64Microseconds mt_usec = LLMessageSystem::getMessageTimeUsecs(); packet_time_map::iterator pit; for(pit = mRecentlyReceivedReliablePackets.upper_bound(mHighestPacketID); @@ -1024,14 +1026,14 @@ void LLCircuitData::clearDuplicateList(TPACKETID oldest_id) // Validate that the packet ID seems far enough away if ((pit->first - mHighestPacketID) < 100) { - llwarns << "Probably incorrectly timing out non-wrapped packets!" << llendl; + LL_WARNS() << "Probably incorrectly timing out non-wrapped packets!" << LL_ENDL; } - U64 delta_t_usec = mt_usec - (*pit).second; - F64 delta_t_sec = delta_t_usec * SEC_PER_USEC; + U64Microseconds delta_t_usec = mt_usec - (*pit).second; + F64Seconds delta_t_sec = delta_t_usec; if (delta_t_sec > LL_DUPLICATE_SUPPRESSION_TIMEOUT) { // enough time has elapsed we're not likely to get a duplicate on this one - llinfos << "Clearing " << pit->first << " from recent list" << llendl; + LL_INFOS() << "Clearing " << pit->first << " from recent list" << LL_ENDL; mRecentlyReceivedReliablePackets.erase(pit++); } else @@ -1039,27 +1041,27 @@ void LLCircuitData::clearDuplicateList(TPACKETID oldest_id) ++pit; } } - //llinfos << "Recent list after: " << mRecentlyReceivedReliablePackets.size() << llendl; + //LL_INFOS() << "Recent list after: " << mRecentlyReceivedReliablePackets.size() << LL_ENDL; } BOOL LLCircuitData::checkCircuitTimeout() { - F64 time_since_last_ping = LLMessageSystem::getMessageTimeSeconds() - mLastPingReceivedTime; + F64Seconds time_since_last_ping = LLMessageSystem::getMessageTimeSeconds() - mLastPingReceivedTime; // Nota Bene: This needs to be turned off if you are debugging multiple simulators if (time_since_last_ping > mHeartbeatTimeout) { - llwarns << "LLCircuitData::checkCircuitTimeout for " << mHost << " last ping " << time_since_last_ping << " seconds ago." <mAcks.size(); - if(count > 0) + F32 age = cd->getAgeInSeconds() - cd->mAckCreationTime; + if (age > collect_time || count == 0) { + if (count>0) + { // send the packet acks S32 acks_this_packet = 0; for(S32 i = 0; i < count; ++i) @@ -1122,16 +1132,17 @@ void LLCircuit::sendAcks() str << "MSG: -> " << cd->mHost << "\tPACKET ACKS:\t"; std::ostream_iterator append(str, " "); std::copy(cd->mAcks.begin(), cd->mAcks.end(), append); - llinfos << str.str() << llendl; + LL_INFOS() << str.str() << LL_ENDL; } - // empty out the acks list - cd->mAcks.clear(); + // empty out the acks list + cd->mAcks.clear(); + cd->mAckCreationTime = 0.f; + } + // remove data map + mSendAckMap.erase(cur_it); } } - - // All acks have been sent, clear the map - mSendAckMap.clear(); } @@ -1140,40 +1151,40 @@ std::ostream& operator<<(std::ostream& s, LLCircuitData& circuit) F32 age = circuit.mExistenceTimer.getElapsedTimeF32(); using namespace std; - s << "Circuit " << circuit.mHost << " "; - s << circuit.mRemoteID << " "; - s << (circuit.mbAlive ? "Alive" : "Not Alive") << " "; - s << (circuit.mbAllowTimeout ? "Timeout Allowed" : "Timeout Not Allowed"); - s << endl; - - s << " Packets Lost: " << circuit.mPacketsLost; - s << " Measured Ping: " << circuit.mPingDelay; - s << " Averaged Ping: " << circuit.mPingDelayAveraged; - s << endl; - - s << "Global In/Out " << S32(age) << " sec"; - s << " KBytes: " << circuit.mBytesIn / 1024 << "/" << circuit.mBytesOut / 1024; - s << " Kbps: "; - s << S32(circuit.mBytesIn * 8.f / circuit.mExistenceTimer.getElapsedTimeF32() / 1024.f); - s << "/"; - s << S32(circuit.mBytesOut * 8.f / circuit.mExistenceTimer.getElapsedTimeF32() / 1024.f); - s << " Packets: " << circuit.mPacketsIn << "/" << circuit.mPacketsOut; - s << endl; - - s << "Recent In/Out " << S32(circuit.mLastPeriodLength) << " sec"; - s << " KBytes: "; - s << circuit.mBytesInLastPeriod / 1024; - s << "/"; - s << circuit.mBytesOutLastPeriod / 1024; - s << " Kbps: "; - s << S32(circuit.mBytesInLastPeriod * 8.f / circuit.mLastPeriodLength / 1024.f); - s << "/"; - s << S32(circuit.mBytesOutLastPeriod * 8.f / circuit.mLastPeriodLength / 1024.f); - s << " Peak kbps: "; - s << S32(circuit.mPeakBPSIn / 1024.f); - s << "/"; - s << S32(circuit.mPeakBPSOut / 1024.f); - s << endl; + s << "Circuit " << circuit.mHost << " " + << circuit.mRemoteID << " " + << (circuit.mbAlive ? "Alive" : "Not Alive") << " " + << (circuit.mbAllowTimeout ? "Timeout Allowed" : "Timeout Not Allowed") + << endl; + + s << " Packets Lost: " << circuit.mPacketsLost + << " Measured Ping: " << circuit.mPingDelay + << " Averaged Ping: " << circuit.mPingDelayAveraged + << endl; + + s << "Global In/Out " << S32(age) << " sec" + << " KBytes: " << circuit.mBytesIn.valueInUnits() << "/" << circuit.mBytesOut.valueInUnits() + << " Kbps: " + << S32(circuit.mBytesIn.valueInUnits() / circuit.mExistenceTimer.getElapsedTimeF32().value()) + << "/" + << S32(circuit.mBytesOut.valueInUnits() / circuit.mExistenceTimer.getElapsedTimeF32().value()) + << " Packets: " << circuit.mPacketsIn << "/" << circuit.mPacketsOut + << endl; + + s << "Recent In/Out " << circuit.mLastPeriodLength + << " KBytes: " + << circuit.mBytesInLastPeriod.valueInUnits() + << "/" + << circuit.mBytesOutLastPeriod.valueInUnits() + << " Kbps: " + << (S32)(circuit.mBytesInLastPeriod.valueInUnits() / circuit.mLastPeriodLength.value()) + << "/" + << (S32)(circuit.mBytesOutLastPeriod.valueInUnits() / circuit.mLastPeriodLength.value()) + << " Peak kbps: " + << S32(circuit.mPeakBPSIn / 1024.f) + << "/" + << S32(circuit.mPeakBPSOut / 1024.f) + << endl; return s; } @@ -1189,7 +1200,7 @@ void LLCircuitData::dumpResendCountAndReset() { if (mCurrentResendCount) { - llinfos << "Circuit: " << mHost << " resent " << mCurrentResendCount << " packets" << llendl; + LL_INFOS() << "Circuit: " << mHost << " resent " << mCurrentResendCount << " packets" << LL_ENDL; mCurrentResendCount = 0; } } @@ -1268,11 +1279,11 @@ void LLCircuitData::setPacketInID(TPACKETID id) void LLCircuitData::pingTimerStop(const U8 ping_id) { - F64 mt_secs = LLMessageSystem::getMessageTimeSeconds(); + F64Seconds mt_secs = LLMessageSystem::getMessageTimeSeconds(); // Nota Bene: no averaging of ping times until we get a feel for how this works - F64 time = mt_secs - mPingTime; - if (time == 0.0) + F64Seconds time = mt_secs - mPingTime; + if (time == F32Seconds(0.0)) { // Ack, we got our ping response on the same frame! Sigh, let's get a real time otherwise // all of our ping calculations will be skewed. @@ -1288,7 +1299,7 @@ void LLCircuitData::pingTimerStop(const U8 ping_id) delta_ping += 256; } - U32 msec = (U32) ((delta_ping*mHeartbeatInterval + time) * 1000.f); + U32Milliseconds msec = delta_ping*mHeartbeatInterval + time; setPingDelay(msec); mPingsInTransit = delta_ping; @@ -1317,13 +1328,13 @@ U32 LLCircuitData::getPacketsIn() const } -S32 LLCircuitData::getBytesIn() const +S32Bytes LLCircuitData::getBytesIn() const { return mBytesIn; } -S32 LLCircuitData::getBytesOut() const +S32Bytes LLCircuitData::getBytesOut() const { return mBytesOut; } @@ -1365,41 +1376,41 @@ BOOL LLCircuitData::getAllowTimeout() const } -U32 LLCircuitData::getPingDelay() const +U32Milliseconds LLCircuitData::getPingDelay() const { return mPingDelay; } -F32 LLCircuitData::getPingInTransitTime() +F32Milliseconds LLCircuitData::getPingInTransitTime() { // This may be inaccurate in the case of a circuit that was "dead" and then revived, // but only until the first round trip ping is sent - djs - F32 time_since_ping_was_sent = 0; + F32Milliseconds time_since_ping_was_sent(0); if (mPingsInTransit) { - time_since_ping_was_sent = (F32)((mPingsInTransit*mHeartbeatInterval - 1) - + (LLMessageSystem::getMessageTimeSeconds() - mPingTime))*1000.f; + time_since_ping_was_sent = F32Milliseconds::convert(((mPingsInTransit*mHeartbeatInterval - F32Seconds(1)) + + (LLMessageSystem::getMessageTimeSeconds() - mPingTime))); } return time_since_ping_was_sent; } -void LLCircuitData::setPingDelay(U32 ping) +void LLCircuitData::setPingDelay(U32Milliseconds ping) { mPingDelay = ping; - mPingDelayAveraged = llmax((F32)ping, getPingDelayAveraged()); + mPingDelayAveraged = llmax((F32Milliseconds)ping, getPingDelayAveraged()); mPingDelayAveraged = ((1.f - LL_AVERAGED_PING_ALPHA) * mPingDelayAveraged) - + (LL_AVERAGED_PING_ALPHA * (F32) ping); + + (LL_AVERAGED_PING_ALPHA * (F32Milliseconds) ping); mPingDelayAveraged = llclamp(mPingDelayAveraged, LL_AVERAGED_PING_MIN, LL_AVERAGED_PING_MAX); } -F32 LLCircuitData::getPingDelayAveraged() +F32Milliseconds LLCircuitData::getPingDelayAveraged() { return llmin(llmax(getPingInTransitTime(), mPingDelayAveraged), LL_AVERAGED_PING_MAX); } diff --git a/indra/llmessage/llcircuit.h b/indra/llmessage/llcircuit.h index 13b0e9e49d..d3db967904 100644 --- a/indra/llmessage/llcircuit.h +++ b/indra/llmessage/llcircuit.h @@ -34,7 +34,6 @@ #include "llerror.h" #include "lltimer.h" -#include "timing.h" #include "net.h" #include "llhost.h" #include "llpacketack.h" @@ -45,12 +44,14 @@ // Constants // const F32 LL_AVERAGED_PING_ALPHA = 0.2f; // relaxation constant on ping running average -const F32 LL_AVERAGED_PING_MAX = 2000; // msec -const F32 LL_AVERAGED_PING_MIN = 100; // msec // IW: increased to avoid retransmits when a process is slow +const F32Milliseconds LL_AVERAGED_PING_MAX(2000); +const F32Milliseconds LL_AVERAGED_PING_MIN(100); // increased to avoid retransmits when a process is slow -const U32 INITIAL_PING_VALUE_MSEC = 1000; // initial value for the ping delay, or for ping delay for an unknown circuit +const U32Milliseconds INITIAL_PING_VALUE_MSEC(1000); // initial value for the ping delay, or for ping delay for an unknown circuit const TPACKETID LL_MAX_OUT_PACKET_ID = 0x01000000; +const int LL_ERR_CIRCUIT_GONE = -23017; +const int LL_ERR_TCP_TIMEOUT = -23016; // 0 - flags // [1,4] - packetid @@ -59,6 +60,7 @@ const U8 LL_PACKET_ID_SIZE = 6; const S32 LL_MAX_RESENT_PACKETS_PER_FRAME = 100; const S32 LL_MAX_ACKED_PACKETS_PER_FRAME = 200; +const F32 LL_COLLECT_ACK_TIME_MAX = 2.f; // // Prototypes and Predefines @@ -76,10 +78,10 @@ class LLCircuitData { public: LLCircuitData(const LLHost &host, TPACKETID in_id, - const F32 circuit_heartbeat_interval, const F32 circuit_timeout); + const F32Seconds circuit_heartbeat_interval, const F32Seconds circuit_timeout); ~LLCircuitData(); - S32 resendUnackedPackets(const F64 now); + S32 resendUnackedPackets(const F64Seconds now); void clearDuplicateList(TPACKETID oldest_id); @@ -105,18 +107,18 @@ class LLCircuitData // mLocalEndPointID should only ever be setup in the LLCircuitData constructor const LLUUID& getLocalEndPointID() const { return mLocalEndPointID; } - U32 getPingDelay() const; + U32Milliseconds getPingDelay() const; S32 getPingsInTransit() const { return mPingsInTransit; } // ACCESSORS BOOL isAlive() const; BOOL isBlocked() const; BOOL getAllowTimeout() const; - F32 getPingDelayAveraged(); - F32 getPingInTransitTime(); + F32Milliseconds getPingDelayAveraged(); + F32Milliseconds getPingInTransitTime(); U32 getPacketsIn() const; - S32 getBytesIn() const; - S32 getBytesOut() const; + S32Bytes getBytesIn() const; + S32Bytes getBytesOut() const; U32 getPacketsOut() const; U32 getPacketsLost() const; TPACKETID getPacketOutID() const; @@ -124,10 +126,10 @@ class LLCircuitData F32 getAgeInSeconds() const; S32 getUnackedPacketCount() const { return mUnackedPacketCount; } S32 getUnackedPacketBytes() const { return mUnackedPacketBytes; } - F64 getNextPingSendTime() const { return mNextPingSendTime; } + F64Seconds getNextPingSendTime() const { return mNextPingSendTime; } U32 getLastPacketGap() const { return mLastPacketGap; } LLHost getHost() const { return mHost; } - F64 getLastPacketInTime() const { return mLastPacketInTime; } + F64Seconds getLastPacketInTime() const { return mLastPacketInTime; } LLThrottleGroup &getThrottleGroup() { return mThrottles; } @@ -163,11 +165,11 @@ class LLCircuitData TPACKETID nextPacketOutID(); void setPacketInID(TPACKETID id); void checkPacketInID(TPACKETID id, BOOL receive_resent); - void setPingDelay(U32 ping); + void setPingDelay(U32Milliseconds ping); BOOL checkCircuitTimeout(); // Return FALSE if the circuit is dead and should be cleaned up - void addBytesIn(S32 bytes); - void addBytesOut(S32 bytes); + void addBytesIn(S32Bytes bytes); + void addBytesOut(S32Bytes bytes); U8 nextPingID() { mLastPingID++; return mLastPingID; } @@ -218,24 +220,25 @@ class LLCircuitData BOOL mBlocked; // Blocked is true if the circuit is hosed, i.e. far behind on pings // Not sure what the difference between this and mLastPingSendTime is - F64 mPingTime; // Time at which a ping was sent. + F64Seconds mPingTime; // Time at which a ping was sent. - F64 mLastPingSendTime; // Time we last sent a ping - F64 mLastPingReceivedTime; // Time we last received a ping - F64 mNextPingSendTime; // Time to try and send the next ping - S32 mPingsInTransit; // Number of pings in transit - U8 mLastPingID; // ID of the last ping that we sent out + F64Seconds mLastPingSendTime; // Time we last sent a ping + F64Seconds mLastPingReceivedTime; // Time we last received a ping + F64Seconds mNextPingSendTime; // Time to try and send the next ping + S32 mPingsInTransit; // Number of pings in transit + U8 mLastPingID; // ID of the last ping that we sent out // Used for determining the resend time for reliable resends. - U32 mPingDelay; // raw ping delay - F32 mPingDelayAveraged; // averaged ping delay (fast attack/slow decay) + U32Milliseconds mPingDelay; // raw ping delay + F32Milliseconds mPingDelayAveraged; // averaged ping delay (fast attack/slow decay) - typedef std::map packet_time_map; + typedef std::map packet_time_map; packet_time_map mPotentialLostPackets; packet_time_map mRecentlyReceivedReliablePackets; std::vector mAcks; + F32 mAckCreationTime; // first ack creation time typedef std::map reliable_map; typedef reliable_map::iterator reliable_iter; @@ -246,7 +249,7 @@ class LLCircuitData S32 mUnackedPacketCount; S32 mUnackedPacketBytes; - F64 mLastPacketInTime; // Time of last packet arrival + F64Seconds mLastPacketInTime; // Time of last packet arrival LLUUID mLocalEndPointID; @@ -258,24 +261,24 @@ class LLCircuitData U32 mPacketsOut; U32 mPacketsIn; S32 mPacketsLost; - S32 mBytesIn; - S32 mBytesOut; - - F32 mLastPeriodLength; // seconds - S32 mBytesInLastPeriod; - S32 mBytesOutLastPeriod; - S32 mBytesInThisPeriod; - S32 mBytesOutThisPeriod; + S32Bytes mBytesIn, + mBytesOut; + + F32Seconds mLastPeriodLength; + S32Bytes mBytesInLastPeriod; + S32Bytes mBytesOutLastPeriod; + S32Bytes mBytesInThisPeriod; + S32Bytes mBytesOutThisPeriod; F32 mPeakBPSIn; // bits per second, max of all period bps F32 mPeakBPSOut; // bits per second, max of all period bps - F64 mPeriodTime; + F64Seconds mPeriodTime; LLTimer mExistenceTimer; // initialized when circuit created, used to track bandwidth numbers S32 mCurrentResendCount; // Number of resent packets since last spam U32 mLastPacketGap; // Gap in sequence number of last packet. - const F32 mHeartbeatInterval; - const F32 mHeartbeatTimeout; + const F32Seconds mHeartbeatInterval; + const F32Seconds mHeartbeatTimeout; }; @@ -285,7 +288,7 @@ class LLCircuit { public: // CREATORS - LLCircuit(const F32 circuit_heartbeat_interval, const F32 circuit_timeout); + LLCircuit(const F32Seconds circuit_heartbeat_interval, const F32Seconds circuit_timeout); ~LLCircuit(); // ACCESSORS @@ -301,7 +304,7 @@ class LLCircuit // this method is called during the message system processAcks() // to send out any acks that did not get sent already. - void sendAcks(); + void sendAcks(F32 collect_time); friend std::ostream& operator<<(std::ostream& s, LLCircuit &circuit); void getInfo(LLSD& info) const; @@ -344,7 +347,7 @@ class LLCircuit mutable LLCircuitData* mLastCircuit; private: - const F32 mHeartbeatInterval; - const F32 mHeartbeatTimeout; + const F32Seconds mHeartbeatInterval; + const F32Seconds mHeartbeatTimeout; }; #endif diff --git a/indra/llmessage/llcororesponder.h b/indra/llmessage/llcororesponder.h new file mode 100644 index 0000000000..bacec85a89 --- /dev/null +++ b/indra/llmessage/llcororesponder.h @@ -0,0 +1,63 @@ +/** + * @file llcororesponder.h + * @brief A responder purposed to call coro functions, to ease transition to LLCoro + * + * $LicenseInfo:firstyear=2006&license=viewerlgpl$ + * Second Life Viewer Source Code + * + * Copyright (C) 2020, Liru Færs + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include +#include "llhttpclient.h" + +struct LLCoroResponderBase : public LLHTTPClient::ResponderWithCompleted +{ + const AIHTTPReceivedHeaders& getHeaders() const { return mReceivedHeaders; } + const LLSD& getContent() const { return mContent; } + + char const* getName() const override final { return "LLCoroResponder"; } +protected: + LLCoroResponderBase() {} +}; + +struct LLCoroResponder final : public LLCoroResponderBase +{ + typedef std::function cb_t; + LLCoroResponder(const cb_t& cb) : mCB(cb) {} + void httpCompleted() override { mCB(*this); } +private: + const cb_t mCB; +}; + +struct LLCoroResponderRaw final : public LLCoroResponderBase +{ + typedef std::function cb_t; + LLCoroResponderRaw(const cb_t& cb) : mCB(cb) {} + void completedRaw(const LLChannelDescriptors& channels, const buffer_ptr_t& buffer) override + { + std::string content; + decode_raw_body(channels, buffer, content); + mCB(*this, content); + } +private: + const cb_t mCB; +}; + diff --git a/indra/llmessage/lldatapacker.cpp b/indra/llmessage/lldatapacker.cpp index 3385d7c2e2..3510f93805 100644 --- a/indra/llmessage/lldatapacker.cpp +++ b/indra/llmessage/lldatapacker.cpp @@ -52,13 +52,13 @@ LLDataPacker::LLDataPacker() : mPassFlags(0), mWriteEnabled(FALSE) //virtual void LLDataPacker::reset() { - llerrs << "Using unimplemented datapacker reset!" << llendl; + LL_ERRS() << "Using unimplemented datapacker reset!" << LL_ENDL; } //virtual void LLDataPacker::dumpBufferToLog() { - llerrs << "dumpBufferToLog not implemented for this type!" << llendl; + LL_ERRS() << "dumpBufferToLog not implemented for this type!" << LL_ENDL; } BOOL LLDataPacker::packFixed(const F32 value, const char *name, @@ -108,7 +108,7 @@ BOOL LLDataPacker::packFixed(const F32 value, const char *name, } else { - llerrs << "Using fixed-point packing of " << total_bits << " bits, why?!" << llendl; + LL_ERRS() << "Using fixed-point packing of " << total_bits << " bits, why?!" << LL_ENDL; } return success; } @@ -117,7 +117,7 @@ BOOL LLDataPacker::unpackFixed(F32 &value, const char *name, const BOOL is_signed, const U32 int_bits, const U32 frac_bits) { //BOOL success = TRUE; - //llinfos << "unpackFixed:" << name << " int:" << int_bits << " frac:" << frac_bits << llendl; + //LL_INFOS() << "unpackFixed:" << name << " int:" << int_bits << " frac:" << frac_bits << LL_ENDL; BOOL ok = FALSE; S32 unsigned_bits = int_bits + frac_bits; S32 total_bits = unsigned_bits; @@ -158,10 +158,10 @@ BOOL LLDataPacker::unpackFixed(F32 &value, const char *name, else { fixed_val = 0; - llerrs << "Bad bit count: " << total_bits << llendl; + LL_ERRS() << "Bad bit count: " << total_bits << LL_ENDL; } - //llinfos << "Fixed_val:" << fixed_val << llendl; + //LL_INFOS() << "Fixed_val:" << fixed_val << LL_ENDL; fixed_val /= (F32)(1 << frac_bits); if (is_signed) @@ -169,7 +169,7 @@ BOOL LLDataPacker::unpackFixed(F32 &value, const char *name, fixed_val -= max_val; } value = fixed_val; - //llinfos << "Value: " << value << llendl; + //LL_INFOS() << "Value: " << value << LL_ENDL; return ok; } @@ -239,7 +239,7 @@ BOOL LLDataPackerBinaryBuffer::unpackBinaryData(U8 *value, S32 &size, const char } else { - llwarns << "LLDataPackerBinaryBuffer::unpackBinaryData would unpack invalid data, aborting!" << llendl; + LL_WARNS() << "LLDataPackerBinaryBuffer::unpackBinaryData would unpack invalid data, aborting!" << LL_ENDL; success = FALSE; } return success; @@ -550,7 +550,7 @@ const LLDataPackerBinaryBuffer& LLDataPackerBinaryBuffer::operator=(const LLData if (a.getBufferSize() > getBufferSize()) { // We've got problems, ack! - llerrs << "Trying to do an assignment with not enough room in the target." << llendl; + LL_ERRS() << "Trying to do an assignment with not enough room in the target." << LL_ENDL; } memcpy(mBufferp, a.mBufferp, a.getBufferSize()); /*Flawfinder: ignore*/ return *this; @@ -558,7 +558,7 @@ const LLDataPackerBinaryBuffer& LLDataPackerBinaryBuffer::operator=(const LLData void LLDataPackerBinaryBuffer::dumpBufferToLog() { - llwarns << "Binary Buffer Dump, size: " << mBufferSize << llendl; + LL_WARNS() << "Binary Buffer Dump, size: " << mBufferSize << LL_ENDL; char line_buffer[256]; /*Flawfinder: ignore*/ S32 i; S32 cur_line_pos = 0; @@ -571,13 +571,13 @@ void LLDataPackerBinaryBuffer::dumpBufferToLog() if (cur_line_pos >= 16) { cur_line_pos = 0; - llwarns << "Offset:" << std::hex << cur_line*16 << std::dec << " Data:" << line_buffer << llendl; + LL_WARNS() << "Offset:" << std::hex << cur_line*16 << std::dec << " Data:" << line_buffer << LL_ENDL; cur_line++; } } if (cur_line_pos) { - llwarns << "Offset:" << std::hex << cur_line*16 << std::dec << " Data:" << line_buffer << llendl; + LL_WARNS() << "Offset:" << std::hex << cur_line*16 << std::dec << " Data:" << line_buffer << LL_ENDL; } } @@ -608,7 +608,7 @@ BOOL LLDataPackerAsciiBuffer::packString(const std::string& value, const char *n { // *NOTE: I believe we need to mark a failure bit at this point. numCopied = getBufferSize()-getCurrentSize(); - llwarns << "LLDataPackerAsciiBuffer::packString: string truncated: " << value << llendl; + LL_WARNS() << "LLDataPackerAsciiBuffer::packString: string truncated: " << value << LL_ENDL; } mCurBufferp += numCopied; return success; @@ -647,7 +647,7 @@ BOOL LLDataPackerAsciiBuffer::packBinaryData(const U8 *value, S32 size, const ch if (numCopied < 0 || numCopied > getBufferSize()-getCurrentSize()) { numCopied = getBufferSize()-getCurrentSize(); - llwarns << "LLDataPackerAsciiBuffer::packBinaryData: number truncated: " << size << llendl; + LL_WARNS() << "LLDataPackerAsciiBuffer::packBinaryData: number truncated: " << size << LL_ENDL; } mCurBufferp += numCopied; @@ -660,7 +660,7 @@ BOOL LLDataPackerAsciiBuffer::packBinaryData(const U8 *value, S32 size, const ch if (numCopied < 0 || numCopied > getBufferSize()-getCurrentSize()) { numCopied = getBufferSize()-getCurrentSize(); - llwarns << "LLDataPackerAsciiBuffer::packBinaryData: data truncated: " << llendl; + LL_WARNS() << "LLDataPackerAsciiBuffer::packBinaryData: data truncated: " << LL_ENDL; bBufferFull = TRUE; } mCurBufferp += numCopied; @@ -672,7 +672,7 @@ BOOL LLDataPackerAsciiBuffer::packBinaryData(const U8 *value, S32 size, const ch if (numCopied < 0 || numCopied > getBufferSize()-getCurrentSize()) { numCopied = getBufferSize()-getCurrentSize(); - llwarns << "LLDataPackerAsciiBuffer::packBinaryData: newline truncated: " << llendl; + LL_WARNS() << "LLDataPackerAsciiBuffer::packBinaryData: newline truncated: " << LL_ENDL; } mCurBufferp += numCopied; } @@ -734,7 +734,7 @@ BOOL LLDataPackerAsciiBuffer::packBinaryDataFixed(const U8 *value, S32 size, con if (numCopied < 0 || numCopied > getBufferSize()-getCurrentSize()) { numCopied = getBufferSize()-getCurrentSize(); - llwarns << "LLDataPackerAsciiBuffer::packBinaryDataFixed: data truncated: " << llendl; + LL_WARNS() << "LLDataPackerAsciiBuffer::packBinaryDataFixed: data truncated: " << LL_ENDL; bBufferFull = TRUE; } mCurBufferp += numCopied; @@ -746,7 +746,7 @@ BOOL LLDataPackerAsciiBuffer::packBinaryDataFixed(const U8 *value, S32 size, con if (numCopied < 0 || numCopied > getBufferSize()-getCurrentSize()) { numCopied = getBufferSize()-getCurrentSize(); - llwarns << "LLDataPackerAsciiBuffer::packBinaryDataFixed: newline truncated: " << llendl; + LL_WARNS() << "LLDataPackerAsciiBuffer::packBinaryDataFixed: newline truncated: " << LL_ENDL; } mCurBufferp += numCopied; @@ -813,7 +813,7 @@ BOOL LLDataPackerAsciiBuffer::packU8(const U8 value, const char *name) if (numCopied < 0 || numCopied > getBufferSize()-getCurrentSize()) { numCopied = getBufferSize()-getCurrentSize(); - llwarns << "LLDataPackerAsciiBuffer::packU8: val truncated: " << llendl; + LL_WARNS() << "LLDataPackerAsciiBuffer::packU8: val truncated: " << LL_ENDL; } mCurBufferp += numCopied; @@ -860,7 +860,7 @@ BOOL LLDataPackerAsciiBuffer::packU16(const U16 value, const char *name) if (numCopied < 0 || numCopied > getBufferSize()-getCurrentSize()) { numCopied = getBufferSize()-getCurrentSize(); - llwarns << "LLDataPackerAsciiBuffer::packU16: val truncated: " << llendl; + LL_WARNS() << "LLDataPackerAsciiBuffer::packU16: val truncated: " << LL_ENDL; } mCurBufferp += numCopied; @@ -907,7 +907,7 @@ BOOL LLDataPackerAsciiBuffer::packU32(const U32 value, const char *name) if (numCopied < 0 || numCopied > getBufferSize()-getCurrentSize()) { numCopied = getBufferSize()-getCurrentSize(); - llwarns << "LLDataPackerAsciiBuffer::packU32: val truncated: " << llendl; + LL_WARNS() << "LLDataPackerAsciiBuffer::packU32: val truncated: " << LL_ENDL; } mCurBufferp += numCopied; @@ -951,7 +951,7 @@ BOOL LLDataPackerAsciiBuffer::packS32(const S32 value, const char *name) if (numCopied < 0 || numCopied > getBufferSize()-getCurrentSize()) { numCopied = getBufferSize()-getCurrentSize(); - llwarns << "LLDataPackerAsciiBuffer::packS32: val truncated: " << llendl; + LL_WARNS() << "LLDataPackerAsciiBuffer::packS32: val truncated: " << LL_ENDL; } mCurBufferp += numCopied; @@ -995,7 +995,7 @@ BOOL LLDataPackerAsciiBuffer::packF32(const F32 value, const char *name) if (numCopied < 0 || numCopied > getBufferSize()-getCurrentSize()) { numCopied = getBufferSize()-getCurrentSize(); - llwarns << "LLDataPackerAsciiBuffer::packF32: val truncated: " << llendl; + LL_WARNS() << "LLDataPackerAsciiBuffer::packF32: val truncated: " << LL_ENDL; } mCurBufferp += numCopied; @@ -1039,7 +1039,7 @@ BOOL LLDataPackerAsciiBuffer::packColor4(const LLColor4 &value, const char *name if (numCopied < 0 || numCopied > getBufferSize()-getCurrentSize()) { numCopied = getBufferSize()-getCurrentSize(); - llwarns << "LLDataPackerAsciiBuffer::packColor4: truncated: " << llendl; + LL_WARNS() << "LLDataPackerAsciiBuffer::packColor4: truncated: " << LL_ENDL; } mCurBufferp += numCopied; @@ -1082,7 +1082,7 @@ BOOL LLDataPackerAsciiBuffer::packColor4U(const LLColor4U &value, const char *na if (numCopied < 0 || numCopied > getBufferSize()-getCurrentSize()) { numCopied = getBufferSize()-getCurrentSize(); - llwarns << "LLDataPackerAsciiBuffer::packColor4U: truncated: " << llendl; + LL_WARNS() << "LLDataPackerAsciiBuffer::packColor4U: truncated: " << LL_ENDL; } mCurBufferp += numCopied; @@ -1132,7 +1132,7 @@ BOOL LLDataPackerAsciiBuffer::packVector2(const LLVector2 &value, const char *na if (numCopied < 0 || numCopied > getBufferSize()-getCurrentSize()) { numCopied = getBufferSize()-getCurrentSize(); - llwarns << "LLDataPackerAsciiBuffer::packVector2: truncated: " << llendl; + LL_WARNS() << "LLDataPackerAsciiBuffer::packVector2: truncated: " << LL_ENDL; } mCurBufferp += numCopied; @@ -1176,7 +1176,7 @@ BOOL LLDataPackerAsciiBuffer::packVector3(const LLVector3 &value, const char *na if (numCopied < 0 || numCopied > getBufferSize()-getCurrentSize()) { numCopied = getBufferSize()-getCurrentSize(); - llwarns << "LLDataPackerAsciiBuffer::packVector3: truncated: " << llendl; + LL_WARNS() << "LLDataPackerAsciiBuffer::packVector3: truncated: " << LL_ENDL; } mCurBufferp += numCopied; @@ -1219,7 +1219,7 @@ BOOL LLDataPackerAsciiBuffer::packVector4(const LLVector4 &value, const char *na if (numCopied < 0 || numCopied > getBufferSize()-getCurrentSize()) { numCopied = getBufferSize()-getCurrentSize(); - llwarns << "LLDataPackerAsciiBuffer::packVector4: truncated: " << llendl; + LL_WARNS() << "LLDataPackerAsciiBuffer::packVector4: truncated: " << LL_ENDL; } mCurBufferp += numCopied; @@ -1266,7 +1266,7 @@ BOOL LLDataPackerAsciiBuffer::packUUID(const LLUUID &value, const char *name) if (numCopied < 0 || numCopied > getBufferSize()-getCurrentSize()) { numCopied = getBufferSize()-getCurrentSize(); - llwarns << "LLDataPackerAsciiBuffer::packUUID: truncated: " << llendl; + LL_WARNS() << "LLDataPackerAsciiBuffer::packUUID: truncated: " << LL_ENDL; success = FALSE; } mCurBufferp += numCopied; @@ -1292,7 +1292,7 @@ BOOL LLDataPackerAsciiBuffer::unpackUUID(LLUUID &value, const char *name) void LLDataPackerAsciiBuffer::dump() { - llinfos << "Buffer: " << mBufferp << llendl; + LL_INFOS() << "Buffer: " << mBufferp << LL_ENDL; } void LLDataPackerAsciiBuffer::writeIndentedName(const char *name) @@ -1318,7 +1318,7 @@ void LLDataPackerAsciiBuffer::writeIndentedName(const char *name) if (numCopied < 0 || numCopied > getBufferSize()-getCurrentSize()) { numCopied = getBufferSize()-getCurrentSize(); - llwarns << "LLDataPackerAsciiBuffer::writeIndentedName: truncated: " << llendl; + LL_WARNS() << "LLDataPackerAsciiBuffer::writeIndentedName: truncated: " << LL_ENDL; } mCurBufferp += numCopied; @@ -1347,7 +1347,7 @@ BOOL LLDataPackerAsciiBuffer::getValueStr(const char *name, char *out_value, S32 if (strcmp(keyword, name)) { - llwarns << "Data packer expecting keyword of type " << name << ", got " << keyword << " instead!" << llendl; + LL_WARNS() << "Data packer expecting keyword of type " << name << ", got " << keyword << " instead!" << LL_ENDL; return FALSE; } } @@ -1904,7 +1904,7 @@ BOOL LLDataPackerAsciiFile::getValueStr(const char *name, char *out_value, S32 v fpos_t last_pos; if (0 != fgetpos(mFP, &last_pos)) // 0==success for fgetpos { - llwarns << "Data packer failed to fgetpos" << llendl; + LL_WARNS() << "Data packer failed to fgetpos" << LL_ENDL; return FALSE; } @@ -1917,13 +1917,13 @@ BOOL LLDataPackerAsciiFile::getValueStr(const char *name, char *out_value, S32 v if (!keyword[0]) { - llwarns << "Data packer could not get the keyword!" << llendl; + LL_WARNS() << "Data packer could not get the keyword!" << LL_ENDL; fsetpos(mFP, &last_pos); return FALSE; } if (strcmp(keyword, name)) { - llwarns << "Data packer expecting keyword of type " << name << ", got " << keyword << " instead!" << llendl; + LL_WARNS() << "Data packer expecting keyword of type " << name << ", got " << keyword << " instead!" << LL_ENDL; fsetpos(mFP, &last_pos); return FALSE; } @@ -1941,12 +1941,12 @@ BOOL LLDataPackerAsciiFile::getValueStr(const char *name, char *out_value, S32 v sscanf(buffer, "%511s %511[^\n]", keyword, value); /* Flawfinder: ignore */ if (!keyword[0]) { - llwarns << "Data packer could not get the keyword!" << llendl; + LL_WARNS() << "Data packer could not get the keyword!" << LL_ENDL; return FALSE; } if (strcmp(keyword, name)) { - llwarns << "Data packer expecting keyword of type " << name << ", got " << keyword << " instead!" << llendl; + LL_WARNS() << "Data packer expecting keyword of type " << name << ", got " << keyword << " instead!" << LL_ENDL; return FALSE; } diff --git a/indra/llmessage/lldatapacker.h b/indra/llmessage/lldatapacker.h index 2b6e574845..0237e7833d 100644 --- a/indra/llmessage/lldatapacker.h +++ b/indra/llmessage/lldatapacker.h @@ -170,6 +170,7 @@ class LLDataPackerBinaryBuffer : public LLDataPacker S32 getBufferSize() const { return mBufferSize; } const U8* getBuffer() const { return mBufferp; } void reset() { mCurBufferp = mBufferp; mWriteEnabled = (mCurBufferp != NULL); } + void shift(S32 offset) { reset(); mCurBufferp += offset;} void freeBuffer() { delete [] mBufferp; mBufferp = mCurBufferp = NULL; mBufferSize = 0; mWriteEnabled = FALSE; } void assignBuffer(U8 *bufferp, S32 size) { @@ -201,8 +202,8 @@ inline BOOL LLDataPackerBinaryBuffer::verifyLength(const S32 data_size, const ch { if (mWriteEnabled && (mCurBufferp - mBufferp) > mBufferSize - data_size) { - llwarns << "Buffer overflow in BinaryBuffer length verify, field name " << name << "!" << llendl; - llwarns << "Current pos: " << (int)(mCurBufferp - mBufferp) << " Buffer size: " << mBufferSize << " Data size: " << data_size << llendl; + LL_WARNS() << "Buffer overflow in BinaryBuffer length verify, field name " << name << "!" << LL_ENDL; + LL_WARNS() << "Current pos: " << (int)(mCurBufferp - mBufferp) << " Buffer size: " << mBufferSize << " Data size: " << data_size << LL_ENDL; return FALSE; } @@ -322,8 +323,8 @@ inline BOOL LLDataPackerAsciiBuffer::verifyLength(const S32 data_size, const cha { if (mWriteEnabled && (mCurBufferp - mBufferp) > mBufferSize - data_size) { - llwarns << "Buffer overflow in AsciiBuffer length verify, field name " << name << "!" << llendl; - llwarns << "Current pos: " << (int)(mCurBufferp - mBufferp) << " Buffer size: " << mBufferSize << " Data size: " << data_size << llendl; + LL_WARNS() << "Buffer overflow in AsciiBuffer length verify, field name " << name << "!" << LL_ENDL; + LL_WARNS() << "Current pos: " << (int)(mCurBufferp - mBufferp) << " Buffer size: " << mBufferSize << " Data size: " << data_size << LL_ENDL; return FALSE; } diff --git a/indra/llmessage/lldispatcher.cpp b/indra/llmessage/lldispatcher.cpp index b2dc414a68..ffcb68caee 100644 --- a/indra/llmessage/lldispatcher.cpp +++ b/indra/llmessage/lldispatcher.cpp @@ -29,6 +29,7 @@ #include "lldispatcher.h" #include +#include #include "llstl.h" #include "message.h" @@ -75,7 +76,7 @@ bool LLDispatcher::dispatch( LLDispatchHandler* func = (*it).second; return (*func)(this, name, invoice, strings); } - llwarns << "Unable to find handler for Generic message: " << name << llendl; + LL_WARNS() << "Unable to find handler for Generic message: " << name << LL_ENDL; return false; } @@ -145,3 +146,25 @@ bool LLDispatcher::unpackMessage( } return true; } + +// static +bool LLDispatcher::unpackLargeMessage( + LLMessageSystem* msg, + LLDispatcher::key_t& method, + LLUUID& invoice, + LLDispatcher::sparam_t& parameters) +{ + msg->getStringFast(_PREHASH_MethodData, _PREHASH_Method, method); + msg->getUUIDFast(_PREHASH_MethodData, _PREHASH_Invoice, invoice); + S32 count = msg->getNumberOfBlocksFast(_PREHASH_ParamList); + for (S32 i = 0; i < count; ++i) + { + // This method treats all Parameter List params as strings and unpacks + // them regardless of length. If there is binary data it is the callers + // responsibility to decode it. + std::string param; + msg->getStringFast(_PREHASH_ParamList, _PREHASH_Parameter, param, i); + parameters.push_back(param); + } + return true; +} diff --git a/indra/llmessage/lldispatcher.h b/indra/llmessage/lldispatcher.h index 9d1751f588..43c63ac4df 100644 --- a/indra/llmessage/lldispatcher.h +++ b/indra/llmessage/lldispatcher.h @@ -105,6 +105,12 @@ class LLDispatcher LLUUID& invoice, sparam_t& parameters); + static bool unpackLargeMessage( + LLMessageSystem* msg, + key_t& method, + LLUUID& invoice, + sparam_t& parameters); + protected: typedef std::map dispatch_map_t; dispatch_map_t mHandlers; diff --git a/indra/llmessage/llexperiencecache.cpp b/indra/llmessage/llexperiencecache.cpp new file mode 100644 index 0000000000..482b870910 --- /dev/null +++ b/indra/llmessage/llexperiencecache.cpp @@ -0,0 +1,921 @@ +/** + * @file llexperiencecache.cpp + * @brief llexperiencecache and related class definitions + * + * $LicenseInfo:firstyear=2012&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ +#include "llexperiencecache.h" + +#include "llavatarname.h" +#include "llcororesponder.h" +#include "llsdserialize.h" +#include "lleventfilter.h" +#include "lldir.h" +#include +#include +#include +#include +#include + +//========================================================================= +namespace LLExperienceCacheImpl +{ + void mapKeys(const LLSD& legacyKeys); + F64 getErrorRetryDeltaTime(S32 status, const AIHTTPReceivedHeaders& headers); + bool maxAgeFromCacheControl(const std::string& cache_control, S32 *max_age); + + static const std::string PRIVATE_KEY = "private_id"; + static const std::string EXPERIENCE_ID = "public_id"; + + static const std::string MAX_AGE("max-age"); + static const boost::char_separator EQUALS_SEPARATOR("="); + static const boost::char_separator COMMA_SEPARATOR(","); + + // *TODO$: this seems to be tied to mapKeys which is used by bootstrap.... but I don't think that bootstrap is used. + typedef std::map KeyMap; + KeyMap privateToPublicKeyMap; +} + +//========================================================================= +const std::string LLExperienceCache::PRIVATE_KEY = "private_id"; +const std::string LLExperienceCache::MISSING = "DoesNotExist"; + +const std::string LLExperienceCache::AGENT_ID = "agent_id"; +const std::string LLExperienceCache::GROUP_ID = "group_id"; +const std::string LLExperienceCache::EXPERIENCE_ID = "public_id"; +const std::string LLExperienceCache::NAME = "name"; +const std::string LLExperienceCache::PROPERTIES = "properties"; +const std::string LLExperienceCache::EXPIRES = "expiration"; +const std::string LLExperienceCache::DESCRIPTION = "description"; +const std::string LLExperienceCache::QUOTA = "quota"; +const std::string LLExperienceCache::MATURITY = "maturity"; +const std::string LLExperienceCache::METADATA = "extended_metadata"; +const std::string LLExperienceCache::SLURL = "slurl"; + +// should be in sync with experience-api/experiences/models.py +const int LLExperienceCache::PROPERTY_INVALID = 1 << 0; +const int LLExperienceCache::PROPERTY_PRIVILEGED = 1 << 3; +const int LLExperienceCache::PROPERTY_GRID = 1 << 4; +const int LLExperienceCache::PROPERTY_PRIVATE = 1 << 5; +const int LLExperienceCache::PROPERTY_DISABLED = 1 << 6; +const int LLExperienceCache::PROPERTY_SUSPENDED = 1 << 7; + +// default values +const F64 LLExperienceCache::DEFAULT_EXPIRATION = 600.0; +const S32 LLExperienceCache::DEFAULT_QUOTA = 128; // this is megabytes +const int LLExperienceCache::SEARCH_PAGE_SIZE = 30; + +//========================================================================= +LLExperienceCache::LLExperienceCache(): + mShutdown(false) +{ +} + +LLExperienceCache::~LLExperienceCache() +{ + +} + +void LLExperienceCache::initSingleton() +{ + mCacheFileName = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "experience_cache.xml"); + + LL_INFOS("ExperienceCache") << "Loading " << mCacheFileName << LL_ENDL; + llifstream cache_stream(mCacheFileName.c_str()); + + if (cache_stream.is_open()) + { + cache_stream >> (*this); + } +} + +void LLExperienceCache::cleanup() +{ + LL_INFOS("ExperienceCache") << "Saving " << mCacheFileName << LL_ENDL; + + llofstream cache_stream(mCacheFileName.c_str()); + if (cache_stream.is_open()) + { + cache_stream << (*this); + } + mShutdown = true; +} + +//------------------------------------------------------------------------- +void LLExperienceCache::importFile(std::istream& istr) +{ + LLSD data; + S32 parse_count = LLSDSerialize::fromXMLDocument(data, istr); + if (parse_count < 1) return; + + LLSD experiences = data["experiences"]; + + LLUUID public_key; + for (const auto& it : experiences.map()) + { + public_key.set(it.first); + mCache[public_key] = it.second; + } + + LL_DEBUGS("ExperienceCache") << "importFile() loaded " << mCache.size() << LL_ENDL; +} + +void LLExperienceCache::exportFile(std::ostream& ostr) const +{ + LLSD experiences; + + cache_t::const_iterator it = mCache.begin(); + for (; it != mCache.end(); ++it) + { + if (!it->second.has(EXPERIENCE_ID) || it->second[EXPERIENCE_ID].asUUID().isNull() || + it->second.has("DoesNotExist") || (it->second.has(PROPERTIES) && it->second[PROPERTIES].asInteger() & PROPERTY_INVALID)) + continue; + + experiences[it->first.asString()] = it->second; + } + + LLSD data; + data["experiences"] = experiences; + + LLSDSerialize::toPrettyXML(data, ostr); +} + +// *TODO$: Rider: This method does not seem to be used... it may be useful in testing. +void LLExperienceCache::bootstrap(const LLSD& legacyKeys, int initialExpiration) +{ + LLExperienceCacheImpl::mapKeys(legacyKeys); + for (auto experience : legacyKeys.array()) + { + if (experience.has(EXPERIENCE_ID)) + { + if (!experience.has(EXPIRES)) + { + experience[EXPIRES] = initialExpiration; + } + processExperience(experience[EXPERIENCE_ID].asUUID(), experience); + } + else + { + LL_WARNS("ExperienceCache") + << "Skipping bootstrap entry which is missing " << EXPERIENCE_ID + << LL_ENDL; + } + } +} + +LLUUID LLExperienceCache::getExperienceId(const LLUUID& private_key, bool null_if_not_found) +{ + if (private_key.isNull()) + return LLUUID::null; + + LLExperienceCacheImpl::KeyMap::const_iterator it = LLExperienceCacheImpl::privateToPublicKeyMap.find(private_key); + if (it == LLExperienceCacheImpl::privateToPublicKeyMap.end()) + { + if (null_if_not_found) + { + return LLUUID::null; + } + return private_key; + } + LL_WARNS("LLExperience") << "converted private key " << private_key << " to experience_id " << it->second << LL_ENDL; + return it->second; +} + +//========================================================================= +void LLExperienceCache::processExperience(const LLUUID& public_key, const LLSD& experience) +{ + LL_INFOS("ExperienceCache") << "Processing experience \"" << experience[NAME] << "\" with key " << public_key.asString() << LL_ENDL; + + mCache[public_key]=experience; + LLSD & row = mCache[public_key]; + + if(row.has(EXPIRES)) + { + row[EXPIRES] = row[EXPIRES].asReal() + LLFrameTimer::getTotalSeconds(); + } + + if(row.has(EXPERIENCE_ID)) + { + mPendingQueue.erase(row[EXPERIENCE_ID].asUUID()); + } + + //signal + signal_map_t::iterator sig_it = mSignalMap.find(public_key); + if (sig_it != mSignalMap.end()) + { + signal_ptr signal = sig_it->second; + (*signal)(experience); + + mSignalMap.erase(public_key); + } +} + +const LLExperienceCache::cache_t& LLExperienceCache::getCached() +{ + return mCache; +} + +void LLExperienceCache::requestExperiencesCoro(const LLCoroResponder& responder, RequestQueue_t requests) +{ + //LL_INFOS("requestExperiencesCoro") << "url: " << url << LL_ENDL; + + LLSD result = responder.getContent(); + auto status = responder.getStatus(); + + if (!responder.isGoodStatus(status)) + { + F64 now = LLFrameTimer::getTotalSeconds(); + + auto headers = responder.getHeaders(); + // build dummy entries for the failed requests + for (auto request : requests) + { + LLSD exp = get(request); + //leave the properties alone if we already have a cache entry for this xp + if (exp.isUndefined()) + { + exp[PROPERTIES] = PROPERTY_INVALID; + } + exp[EXPIRES] = now + LLExperienceCacheImpl::getErrorRetryDeltaTime(status, headers); + exp[EXPERIENCE_ID] = request; + exp["key_type"] = EXPERIENCE_ID; + exp["uuid"] = request; + exp["error"] = status; + exp[QUOTA] = DEFAULT_QUOTA; + + processExperience(request, exp); + } + return; + } + + LLSD experiences = result["experience_keys"]; + + for (const auto& row : experiences.array()) + { + LLUUID public_key = row[EXPERIENCE_ID].asUUID(); + + LL_DEBUGS("ExperienceCache") << "Received result for " << public_key + << " display '" << row[LLExperienceCache::NAME].asString() << "'" << LL_ENDL; + + processExperience(public_key, row); + } + + LLSD error_ids = result["error_ids"]; + + for (const auto& err : error_ids.array()) + { + LLUUID id = err.asUUID(); + LLSD exp; + exp[EXPIRES] = DEFAULT_EXPIRATION; + exp[EXPERIENCE_ID] = id; + exp[PROPERTIES] = PROPERTY_INVALID; + exp[MISSING] = true; + exp[QUOTA] = DEFAULT_QUOTA; + + processExperience(id, exp); + LL_WARNS("ExperienceCache") << "LLExperienceResponder::result() error result for " << id << LL_ENDL; + } + +} + +void LLExperienceCache::requestExperiences() +{ + if (mCapability == nullptr) + { + LL_WARNS("ExperienceCache") << "Capability query method not set." << LL_ENDL; + return; + } + + std::string urlBase = mCapability("GetExperienceInfo"); + if (urlBase.empty()) + { + LL_DEBUGS("ExperienceCache") << "No Experience capability." << LL_ENDL; + return; + } + + if (*urlBase.rbegin() != '/') + { + urlBase += "/"; + } + urlBase += "id/"; + + + F64 now = LLFrameTimer::getTotalSeconds(); + + const U32 EXP_URL_SEND_THRESHOLD = 3000; + constexpr U32 EXP_PAGE_SIZE = EXP_URL_SEND_THRESHOLD / UUID_STR_LENGTH; + + std::ostringstream ostr; + ostr << urlBase << "?page_size=" << EXP_PAGE_SIZE; + RequestQueue_t requests; + + while (!mRequestQueue.empty()) + { + RequestQueue_t::iterator it = mRequestQueue.begin(); + LLUUID key = (*it); + mRequestQueue.erase(it); + requests.insert(key); + + ostr << "&" << EXPERIENCE_ID << "=" << key.asString(); + mPendingQueue[key] = now; + + if (mRequestQueue.empty() || (ostr.tellp() > EXP_URL_SEND_THRESHOLD)) + { // request is placed in the coprocedure pool for the ExpCache cache. Throttling is done by the pool itself. + LLHTTPClient::get(ostr.str(), new LLCoroResponder( + boost::bind(&LLExperienceCache::requestExperiencesCoro, this, _1, requests) )); + + ostr.str(std::string()); + ostr << urlBase << "?page_size=" << EXP_PAGE_SIZE; + requests.clear(); + } + } + +} + + +bool LLExperienceCache::isRequestPending(const LLUUID& public_key) +{ + bool isPending = false; + const F64 PENDING_TIMEOUT_SECS = 5.0 * 60.0; + + PendingQueue_t::const_iterator it = mPendingQueue.find(public_key); + + if(it != mPendingQueue.end()) + { + F64 expire_time = LLFrameTimer::getTotalSeconds() - PENDING_TIMEOUT_SECS; + isPending = (it->second > expire_time); + } + + return isPending; +} + +void LLExperienceCache::setCapabilityQuery(LLExperienceCache::CapabilityQuery_t queryfn) +{ + mCapability = queryfn; +} + + +void LLExperienceCache::idleCoro() +{ + const F32 SECS_BETWEEN_REQUESTS = 0.5f; + const F32 ERASE_EXPIRED_TIMEOUT = 60.f; // seconds + + { + static LLFrameTimer sRequestTimer; + if (!sRequestTimer.checkExpirationAndReset(SECS_BETWEEN_REQUESTS)) return; + + if (mEraseExpiredTimer.checkExpirationAndReset(ERASE_EXPIRED_TIMEOUT)) + { + eraseExpired(); + } + + if (!mRequestQueue.empty()) + { + requestExperiences(); + } + } + + // The coroutine system will likely be shut down by the time we get to this point + // (or at least no further cycling will occur on it since the user has decided to quit.) +} + +void LLExperienceCache::erase(const LLUUID& key) +{ + cache_t::iterator it = mCache.find(key); + + if(it != mCache.end()) + { + mCache.erase(it); + } +} + +void LLExperienceCache::eraseExpired() +{ + F64 now = LLFrameTimer::getTotalSeconds(); + cache_t::iterator it = mCache.begin(); + while (it != mCache.end()) + { + cache_t::iterator cur = it; + LLSD& exp = cur->second; + ++it; + + //LL_INFOS("ExperienceCache") << "Testing experience \"" << exp[NAME] << "\" with exp time " << exp[EXPIRES].asReal() << "(now = " << now << ")" << LL_ENDL; + + if(exp.has(EXPIRES) && exp[EXPIRES].asReal() < now) + { + if(!exp.has(EXPERIENCE_ID)) + { + LL_WARNS("ExperienceCache") << "Removing experience with no id " << LL_ENDL ; + mCache.erase(cur); + } + else + { + LLUUID id = exp[EXPERIENCE_ID].asUUID(); + LLUUID private_key = exp.has(LLExperienceCache::PRIVATE_KEY) ? exp[LLExperienceCache::PRIVATE_KEY].asUUID():LLUUID::null; + if(private_key.notNull() || !exp.has("DoesNotExist")) + { + fetch(id, true); + } + else + { + LL_WARNS("ExperienceCache") << "Removing invalid experience " << id << LL_ENDL ; + mCache.erase(cur); + } + } + } + } +} + +bool LLExperienceCache::fetch(const LLUUID& key, bool refresh/* = true*/) +{ + if(!key.isNull() && !isRequestPending(key) && (refresh || mCache.find(key)==mCache.end())) + { + LL_DEBUGS("ExperienceCache") << " queue request for " << EXPERIENCE_ID << " " << key << LL_ENDL; + + mRequestQueue.insert(key); + return true; + } + return false; +} + +void LLExperienceCache::insert(const LLSD& experience_data) +{ + if(experience_data.has(EXPERIENCE_ID)) + { + processExperience(experience_data[EXPERIENCE_ID].asUUID(), experience_data); + } + else + { + LL_WARNS("ExperienceCache") << ": Ignoring cache insert of experience which is missing " << EXPERIENCE_ID << LL_ENDL; + } +} + +const LLSD& LLExperienceCache::get(const LLUUID& key) +{ + static const LLSD empty; + + if(key.isNull()) + return empty; + cache_t::const_iterator it = mCache.find(key); + + if (it != mCache.end()) + { + return it->second; + } + fetch(key); + + return empty; +} + +void LLExperienceCache::get(const LLUUID& key, LLExperienceCache::ExperienceGetFn_t slot) +{ + if(key.isNull()) + return; + + cache_t::const_iterator it = mCache.find(key); + if (it != mCache.end()) + { + // ...name already exists in cache, fire callback now + callback_signal_t signal; + signal.connect(slot); + + signal(it->second); + return; + } + + fetch(key); + + signal_ptr signal = boost::make_shared(); + + std::pair result = mSignalMap.insert(signal_map_t::value_type(key, signal)); + if (!result.second) + signal = (*result.first).second; + signal->connect(slot); +} + +//========================================================================= +void LLExperienceCache::fetchAssociatedExperience(const LLUUID& objectId, const LLUUID& itemId, std::string url, ExperienceGetFn_t fn) +{ + if (mCapability == nullptr) + { + LL_WARNS("ExperienceCache") << "Capability query method not set." << LL_ENDL; + return; + } + + + if (url.empty()) + { + url = mCapability("GetMetadata"); + + if (url.empty()) + { + LL_WARNS("ExperienceCache") << "No Metadata capability." << LL_ENDL; + return; + } + } + + LLSD fields; + fields.append("experience"); + LLSD data; + data["object-id"] = objectId; + data["item-id"] = itemId; + data["fields"] = fields; + + LLHTTPClient::post(url, data, new LLCoroResponder( + boost::bind(&LLExperienceCache::fetchAssociatedExperienceCoro, this, _1, fn))); +} + +void LLExperienceCache::fetchAssociatedExperienceCoro(const LLCoroResponder& responder, ExperienceGetFn_t fn) +{ + LLSD result = responder.getContent(); + auto status = responder.getStatus(); + + if (!responder.isGoodStatus(status) || !result.has("experience")) + { + LLSD failure; + if (!status) + { + failure["error"] = status; + failure["message"] = responder.getReason(); + } + else + { + failure["error"] = -1; + failure["message"] = "no experience"; + } + if (fn != nullptr) + fn(failure); + return; + } + + LLUUID expId = result["experience"].asUUID(); + get(expId, fn); +} + +//------------------------------------------------------------------------- +void LLExperienceCache::findExperienceByName(const std::string text, int page, ExperienceGetFn_t fn) +{ + if (mCapability == nullptr) + { + LL_WARNS("ExperienceCache") << "Capability query method not set." << LL_ENDL; + return; + } + + std::ostringstream url; + + url << mCapability("FindExperienceByName") << "?page=" << page << "&page_size=" << SEARCH_PAGE_SIZE << "&query=" << LLURI::escape(text); + + LLHTTPClient::get(url.str(), new LLCoroResponder( + boost::bind(&LLExperienceCache::findExperienceByNameCoro, this, _1, fn))); +} + +void LLExperienceCache::findExperienceByNameCoro(const LLCoroResponder& responder, ExperienceGetFn_t fn) +{ + LLSD result = responder.getContent(); + + if (!responder.isGoodStatus(responder.getStatus())) + { + fn(LLSD()); + return; + } + + const LLSD& experiences = result["experience_keys"]; + for (const auto& it : experiences.array()) + { + insert(it); + } + + fn(result); +} + +//------------------------------------------------------------------------- +void LLExperienceCache::getGroupExperiences(const LLUUID &groupId, ExperienceGetFn_t fn) +{ + if (mCapability == nullptr) + { + LL_WARNS("ExperienceCache") << "Capability query method not set." << LL_ENDL; + return; + } + + // search for experiences owned by the current group + std::string url = mCapability("GroupExperiences"); + if (url.empty()) + { + LL_WARNS("ExperienceCache") << "No Group Experiences capability" << LL_ENDL; + return; + } + + url += "?" + groupId.asString(); + + LLHTTPClient::get(url, new LLCoroResponder( + boost::bind(&LLExperienceCache::getGroupExperiencesCoro, this, _1, fn))); +} + +void LLExperienceCache::getGroupExperiencesCoro(const LLCoroResponder& responder, ExperienceGetFn_t fn) +{ + LLSD result = responder.getContent(); + + if (!responder.isGoodStatus(responder.getStatus())) + { + fn(LLSD()); + return; + } + + const LLSD& experienceIds = result["experience_ids"]; + fn(experienceIds); +} + +//------------------------------------------------------------------------- +void LLExperienceCache::getRegionExperiences(CapabilityQuery_t regioncaps, ExperienceGetFn_t fn) +{ + regionExperiences(regioncaps, LLSD(), false, fn); +} + +void LLExperienceCache::setRegionExperiences(CapabilityQuery_t regioncaps, const LLSD &experiences, ExperienceGetFn_t fn) +{ + regionExperiences(regioncaps, experiences, true, fn); +} + +void LLExperienceCache::regionExperiences(CapabilityQuery_t regioncaps, const LLSD &experiences, bool update, ExperienceGetFn_t fn) +{ + // search for experiences owned by the current group + std::string url = regioncaps("RegionExperiences"); + if (url.empty()) + { + LL_WARNS("ExperienceCache") << "No Region Experiences capability" << LL_ENDL; + return; + } + + auto httpRequest = new LLCoroResponder( + boost::bind(&LLExperienceCache::regionExperiencesCoro, this, _1, fn)); + + LLSD result; + if (update) + LLHTTPClient::post(url, experiences, httpRequest); + else + LLHTTPClient::get(url, httpRequest); +} + +void LLExperienceCache::regionExperiencesCoro(const LLCoroResponder& responder, ExperienceGetFn_t fn) +{ + LLSD result = responder.getContent(); + + if (!responder.isGoodStatus(responder.getStatus())) + { +// fn(LLSD()); + return; + } + + fn(result); + +} + +//------------------------------------------------------------------------- +void LLExperienceCache::getExperiencePermission(const LLUUID &experienceId, ExperienceGetFn_t fn) +{ + if (mCapability == nullptr) + { + LL_WARNS("ExperienceCache") << "Capability query method not set." << LL_ENDL; + return; + } + + std::string url = mCapability("ExperiencePreferences") + "?" + experienceId.asString(); + + LLHTTPClient::get(url, new LLCoroResponder( + boost::bind(&LLExperienceCache::experiencePermissionCoro, this, _1, fn))); +} + +void LLExperienceCache::setExperiencePermission(const LLUUID &experienceId, const std::string &permission, ExperienceGetFn_t fn) +{ + if (mCapability == nullptr) + { + LL_WARNS("ExperienceCache") << "Capability query method not set." << LL_ENDL; + return; + } + + std::string url = mCapability("ExperiencePreferences"); + if (url.empty()) + return; + LLSD permData; + LLSD data; + permData["permission"] = permission; + data[experienceId.asString()] = permData; + + LLHTTPClient::put(url, data, new LLCoroResponder( + boost::bind(&LLExperienceCache::experiencePermissionCoro, this, _1, fn))); +} + +void LLExperienceCache::forgetExperiencePermission(const LLUUID &experienceId, ExperienceGetFn_t fn) +{ + if (mCapability == nullptr) + { + LL_WARNS("ExperienceCache") << "Capability query method not set." << LL_ENDL; + return; + } + + std::string url = mCapability("ExperiencePreferences") + "?" + experienceId.asString(); + LLHTTPClient::del(url, new LLCoroResponder( + boost::bind(&LLExperienceCache::experiencePermissionCoro, this, _1, fn))); +} + +void LLExperienceCache::experiencePermissionCoro(const LLCoroResponder& responder, ExperienceGetFn_t fn) +{ + // search for experiences owned by the current group + + LLSD result = responder.getContent(); + + if (responder.isGoodStatus(responder.getStatus())) + { + fn(result); + } +} + +//------------------------------------------------------------------------- +void LLExperienceCache::getExperienceAdmin(const LLUUID &experienceId, ExperienceGetFn_t fn) +{ + if (mCapability == nullptr) + { + LL_WARNS("ExperienceCache") << "Capability query method not set." << LL_ENDL; + return; + } + + std::string url = mCapability("IsExperienceAdmin"); + if (url.empty()) + { + LL_WARNS("ExperienceCache") << "No Region Experiences capability" << LL_ENDL; + return; + } + url += "?experience_id=" + experienceId.asString(); + + LLHTTPClient::get(url, new LLCoroResponder( + boost::bind(fn, boost::bind(&LLCoroResponder::getContent, _1)))); +} + +//------------------------------------------------------------------------- +void LLExperienceCache::updateExperience(LLSD updateData, ExperienceGetFn_t fn) +{ + if (mCapability == nullptr) + { + LL_WARNS("ExperienceCache") << "Capability query method not set." << LL_ENDL; + return; + } + + std::string url = mCapability("UpdateExperience"); + if (url.empty()) + { + LL_WARNS("ExperienceCache") << "No Region Experiences capability" << LL_ENDL; + return; + } + + updateData.erase(LLExperienceCache::QUOTA); + updateData.erase(LLExperienceCache::EXPIRES); + updateData.erase(LLExperienceCache::AGENT_ID); + + LLHTTPClient::post(url, updateData, new LLCoroResponder( + boost::bind(fn, boost::bind(&LLCoroResponder::getContent, _1)))); +} + +//========================================================================= +void LLExperienceCacheImpl::mapKeys(const LLSD& legacyKeys) +{ + for (const auto& exp : legacyKeys.array()) + { + if (exp.has(LLExperienceCacheImpl::EXPERIENCE_ID) && exp.has(LLExperienceCacheImpl::PRIVATE_KEY)) + { + LLExperienceCacheImpl::privateToPublicKeyMap[exp[LLExperienceCacheImpl::PRIVATE_KEY].asUUID()] = + exp[LLExperienceCacheImpl::EXPERIENCE_ID].asUUID(); + } + } +} + +// Return time to retry a request that generated an error, based on +// error type and headers. Return value is seconds-since-epoch. +F64 LLExperienceCacheImpl::getErrorRetryDeltaTime(S32 status, const AIHTTPReceivedHeaders& headers) +{ + // Retry-After takes priority + std::string retry_afters; + if (headers.getFirstValue("retry-after", retry_afters)) + { + LLSD retry_after(retry_afters); + // We only support the delta-seconds type + S32 delta_seconds = retry_after.asInteger(); + if (delta_seconds > 0) + { + // ...valid delta-seconds + return F64(delta_seconds); + } + } + + // If no Retry-After, look for Cache-Control max-age + // Allow the header to override the default + std::string cache_control; + if (headers.getFirstValue("cache-control", cache_control)) + { + S32 max_age = 0; + if (LLExperienceCacheImpl::maxAgeFromCacheControl(cache_control, &max_age)) + { + LL_WARNS("ExperienceCache") + << "got EXPIRES from headers, max_age " << max_age + << LL_ENDL; + return (F64)max_age; + } + } + + // No information in header, make a guess + if (status == 503) + { + // ...service unavailable, retry soon + const F64 SERVICE_UNAVAILABLE_DELAY = 600.0; // 10 min + return SERVICE_UNAVAILABLE_DELAY; + } + else if (status == 499) + { + // ...we were probably too busy, retry quickly + const F64 BUSY_DELAY = 10.0; // 10 seconds + return BUSY_DELAY; + + } + else + { + // ...other unexpected error + const F64 DEFAULT_DELAY = 3600.0; // 1 hour + return DEFAULT_DELAY; + } +} + +bool LLExperienceCacheImpl::maxAgeFromCacheControl(const std::string& cache_control, S32 *max_age) +{ + // Split the string on "," to get a list of directives + typedef boost::tokenizer > tokenizer; + tokenizer directives(cache_control, COMMA_SEPARATOR); + + tokenizer::iterator token_it = directives.begin(); + for ( ; token_it != directives.end(); ++token_it) + { + // Tokens may have leading or trailing whitespace + std::string token = *token_it; + LLStringUtil::trim(token); + + if (token.compare(0, MAX_AGE.size(), MAX_AGE) == 0) + { + // ...this token starts with max-age, so let's chop it up by "=" + tokenizer subtokens(token, EQUALS_SEPARATOR); + tokenizer::iterator subtoken_it = subtokens.begin(); + + // Must have a token + if (subtoken_it == subtokens.end()) return false; + std::string subtoken = *subtoken_it; + + // Must exactly equal "max-age" + LLStringUtil::trim(subtoken); + if (subtoken != MAX_AGE) return false; + + // Must have another token + ++subtoken_it; + if (subtoken_it == subtokens.end()) return false; + subtoken = *subtoken_it; + + // Must be a valid integer + // *NOTE: atoi() returns 0 for invalid values, so we have to + // check the string first. + // *TODO: Do servers ever send "0000" for zero? We don't handle it + LLStringUtil::trim(subtoken); + if (subtoken == "0") + { + *max_age = 0; + return true; + } + S32 val = atoi( subtoken.c_str() ); + if (val > 0 && val < S32_MAX) + { + *max_age = val; + return true; + } + return false; + } + } + return false; +} + + + + diff --git a/indra/llmessage/llexperiencecache.h b/indra/llmessage/llexperiencecache.h new file mode 100644 index 0000000000..cddf5f67e6 --- /dev/null +++ b/indra/llmessage/llexperiencecache.h @@ -0,0 +1,181 @@ +/** + * @file llexperiencecache.h + * @brief Caches information relating to experience keys + * + * $LicenseInfo:firstyear=2012&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + + + +#ifndef LL_LLEXPERIENCECACHE_H +#define LL_LLEXPERIENCECACHE_H + +#include "linden_common.h" +#include "llsingleton.h" +#include "llframetimer.h" +#include "llsd.h" +#include + +struct LLCoroResponder; +class LLSD; +class LLUUID; + + +class LLExperienceCache final : public LLSingleton < LLExperienceCache > +{ + friend class LLSingleton; + LLExperienceCache(); + +public: + typedef std::function CapabilityQuery_t; + typedef std::function ExperienceGetFn_t; + + void idleCoro(); + void setCapabilityQuery(CapabilityQuery_t queryfn); + void cleanup(); + + //------------------------------------------- + // Cache methods + void erase(const LLUUID& key); + bool fetch(const LLUUID& key, bool refresh = false); + void insert(const LLSD& experience_data); + const LLSD& get(const LLUUID& key); + void get(const LLUUID& key, ExperienceGetFn_t slot); // If name information is in cache, callback will be called immediately. + + bool isRequestPending(const LLUUID& public_key); + + //------------------------------------------- + void fetchAssociatedExperience(const LLUUID& objectId, const LLUUID& itemId, ExperienceGetFn_t fn) { fetchAssociatedExperience(objectId, itemId, LLStringUtil::null, fn); } + void fetchAssociatedExperience(const LLUUID& objectId, const LLUUID& itemId, std::string url, ExperienceGetFn_t fn); + void findExperienceByName(const std::string text, int page, ExperienceGetFn_t fn); + void getGroupExperiences(const LLUUID &groupId, ExperienceGetFn_t fn); + + // the Get/Set Region Experiences take a CapabilityQuery to get the capability since + // the region being queried may not be the region that the agent is standing on. + void getRegionExperiences(CapabilityQuery_t regioncaps, ExperienceGetFn_t fn); + void setRegionExperiences(CapabilityQuery_t regioncaps, const LLSD &experiences, ExperienceGetFn_t fn); + + void getExperiencePermission(const LLUUID &experienceId, ExperienceGetFn_t fn); + void setExperiencePermission(const LLUUID &experienceId, const std::string &permission, ExperienceGetFn_t fn); + void forgetExperiencePermission(const LLUUID &experienceId, ExperienceGetFn_t fn); + + void getExperienceAdmin(const LLUUID &experienceId, ExperienceGetFn_t fn); + + void updateExperience(LLSD updateData, ExperienceGetFn_t fn); + //------------------------------------------- + static const std::string NAME; // "name" + static const std::string EXPERIENCE_ID; // "public_id" + static const std::string AGENT_ID; // "agent_id" + static const std::string GROUP_ID; // "group_id" + static const std::string PROPERTIES; // "properties" + static const std::string EXPIRES; // "expiration" + static const std::string DESCRIPTION; // "description" + static const std::string QUOTA; // "quota" + static const std::string MATURITY; // "maturity" + static const std::string METADATA; // "extended_metadata" + static const std::string SLURL; // "slurl" + + static const std::string MISSING; // "DoesNotExist" + + // should be in sync with experience-api/experiences/models.py + static const int PROPERTY_INVALID; // 1 << 0 + static const int PROPERTY_PRIVILEGED; // 1 << 3 + static const int PROPERTY_GRID; // 1 << 4 + static const int PROPERTY_PRIVATE; // 1 << 5 + static const int PROPERTY_DISABLED; // 1 << 6 + static const int PROPERTY_SUSPENDED; // 1 << 7 + +private: + virtual ~LLExperienceCache(); + + void initSingleton() override; + + // Callback types for get() + typedef boost::signals2::signal < void(const LLSD &) > callback_signal_t; + typedef boost::shared_ptr signal_ptr; + // May have multiple callbacks for a single ID, which are + // represented as multiple slots bound to the signal. + // Avoid copying signals via pointers. + typedef std::map signal_map_t; + typedef std::map cache_t; + + typedef uuid_set_t RequestQueue_t; + typedef std::map PendingQueue_t; + + //-------------------------------------------- + static const std::string PRIVATE_KEY; // "private_id" + + // default values + static const F64 DEFAULT_EXPIRATION; // 600.0 + static const S32 DEFAULT_QUOTA; // 128 this is megabytes + static const int SEARCH_PAGE_SIZE; + +//-------------------------------------------- + void processExperience(const LLUUID& public_key, const LLSD& experience); + +//-------------------------------------------- + cache_t mCache; + signal_map_t mSignalMap; + RequestQueue_t mRequestQueue; + PendingQueue_t mPendingQueue; + + LLFrameTimer mEraseExpiredTimer; // Periodically clean out expired entries from the cache + CapabilityQuery_t mCapability; + std::string mCacheFileName; + bool mShutdown; + + void eraseExpired(); + void requestExperiencesCoro(const LLCoroResponder& responder, RequestQueue_t); + void requestExperiences(); + + void fetchAssociatedExperienceCoro(const LLCoroResponder& responder, ExperienceGetFn_t); + void findExperienceByNameCoro(const LLCoroResponder& responder, ExperienceGetFn_t); + void getGroupExperiencesCoro(const LLCoroResponder& responder, ExperienceGetFn_t); + void regionExperiences(CapabilityQuery_t regioncaps, const LLSD& experiences, bool update, ExperienceGetFn_t fn); + void regionExperiencesCoro(const LLCoroResponder& responder, ExperienceGetFn_t fn); + void experiencePermissionCoro(const LLCoroResponder& responder, ExperienceGetFn_t fn); + + void bootstrap(const LLSD& legacyKeys, int initialExpiration); + void exportFile(std::ostream& ostr) const; + void importFile(std::istream& istr); + + // + const cache_t& getCached(); + + // maps an experience private key to the experience id + LLUUID getExperienceId(const LLUUID& private_key, bool null_if_not_found=false); + + //===================================================================== + inline friend std::ostream &operator << (std::ostream &os, const LLExperienceCache &cache) + { + cache.exportFile(os); + return os; + } + + inline friend std::istream &operator >> (std::istream &is, LLExperienceCache &cache) + { + cache.importFile(is); + return is; + } +}; + +#endif // LL_LLEXPERIENCECACHE_H diff --git a/indra/llmessage/llfiltersd2xmlrpc.cpp b/indra/llmessage/llfiltersd2xmlrpc.cpp index 9828a3e30a..b9f004a753 100644 --- a/indra/llmessage/llfiltersd2xmlrpc.cpp +++ b/indra/llmessage/llfiltersd2xmlrpc.cpp @@ -84,6 +84,7 @@ #include "llsd.h" #include "llsdserialize.h" #include "lluuid.h" +#include "llfasttimer.h" // spammy mode //#define LL_SPEW_STREAM_OUT_DEBUGGING 1 @@ -163,12 +164,12 @@ void LLFilterSD2XMLRPC::streamOut(std::ostream& ostr, const LLSD& sd) case LLSD::TypeMap: { #if LL_SPEW_STREAM_OUT_DEBUGGING - llinfos << "streamOut(map) BEGIN" << llendl; + LL_INFOS() << "streamOut(map) BEGIN" << LL_ENDL; #endif ostr << ""; if(ostr.fail()) { - llinfos << "STREAM FAILURE writing struct" << llendl; + LL_INFOS() << "STREAM FAILURE writing struct" << LL_ENDL; } LLSD::map_const_iterator it = sd.beginMap(); LLSD::map_const_iterator end = sd.endMap(); @@ -179,21 +180,21 @@ void LLFilterSD2XMLRPC::streamOut(std::ostream& ostr, const LLSD& sd) streamOut(ostr, (*it).second); if(ostr.fail()) { - llinfos << "STREAM FAILURE writing '" << (*it).first - << "' with sd type " << (*it).second.type() << llendl; + LL_INFOS() << "STREAM FAILURE writing '" << (*it).first + << "' with sd type " << (*it).second.type() << LL_ENDL; } ostr << ""; } ostr << ""; #if LL_SPEW_STREAM_OUT_DEBUGGING - llinfos << "streamOut(map) END" << llendl; + LL_INFOS() << "streamOut(map) END" << LL_ENDL; #endif break; } case LLSD::TypeArray: { #if LL_SPEW_STREAM_OUT_DEBUGGING - llinfos << "streamOut(array) BEGIN" << llendl; + LL_INFOS() << "streamOut(array) BEGIN" << LL_ENDL; #endif ostr << ""; LLSD::array_const_iterator it = sd.beginArray(); @@ -203,12 +204,12 @@ void LLFilterSD2XMLRPC::streamOut(std::ostream& ostr, const LLSD& sd) streamOut(ostr, *it); if(ostr.fail()) { - llinfos << "STREAM FAILURE writing array element sd type " - << (*it).type() << llendl; + LL_INFOS() << "STREAM FAILURE writing array element sd type " + << (*it).type() << LL_ENDL; } } #if LL_SPEW_STREAM_OUT_DEBUGGING - llinfos << "streamOut(array) END" << llendl; + LL_INFOS() << "streamOut(array) END" << LL_ENDL; #endif ostr << ""; break; @@ -217,31 +218,31 @@ void LLFilterSD2XMLRPC::streamOut(std::ostream& ostr, const LLSD& sd) // treat undefined as a bool with a false value. case LLSD::TypeBoolean: #if LL_SPEW_STREAM_OUT_DEBUGGING - llinfos << "streamOut(bool)" << llendl; + LL_INFOS() << "streamOut(bool)" << LL_ENDL; #endif ostr << "" << (sd.asBoolean() ? "1" : "0") << ""; break; case LLSD::TypeInteger: #if LL_SPEW_STREAM_OUT_DEBUGGING - llinfos << "streamOut(int)" << llendl; + LL_INFOS() << "streamOut(int)" << LL_ENDL; #endif ostr << "" << sd.asInteger() << ""; break; case LLSD::TypeReal: #if LL_SPEW_STREAM_OUT_DEBUGGING - llinfos << "streamOut(real)" << llendl; + LL_INFOS() << "streamOut(real)" << LL_ENDL; #endif ostr << "" << sd.asReal() << ""; break; case LLSD::TypeString: #if LL_SPEW_STREAM_OUT_DEBUGGING - llinfos << "streamOut(string)" << llendl; + LL_INFOS() << "streamOut(string)" << LL_ENDL; #endif ostr << "" << xml_escape_string(sd.asString()) << ""; break; case LLSD::TypeUUID: #if LL_SPEW_STREAM_OUT_DEBUGGING - llinfos << "streamOut(uuid)" << llendl; + LL_INFOS() << "streamOut(uuid)" << LL_ENDL; #endif // serialize it as a string ostr << "" << sd.asString() << ""; @@ -249,7 +250,7 @@ void LLFilterSD2XMLRPC::streamOut(std::ostream& ostr, const LLSD& sd) case LLSD::TypeURI: { #if LL_SPEW_STREAM_OUT_DEBUGGING - llinfos << "streamOut(uri)" << llendl; + LL_INFOS() << "streamOut(uri)" << LL_ENDL; #endif // serialize it as a string ostr << "" << xml_escape_string(sd.asString()) << ""; @@ -258,7 +259,7 @@ void LLFilterSD2XMLRPC::streamOut(std::ostream& ostr, const LLSD& sd) case LLSD::TypeBinary: { #if LL_SPEW_STREAM_OUT_DEBUGGING - llinfos << "streamOut(binary)" << llendl; + LL_INFOS() << "streamOut(binary)" << LL_ENDL; #endif // this is pretty inefficient, but we'll deal with that // problem when it becomes one. @@ -281,15 +282,15 @@ void LLFilterSD2XMLRPC::streamOut(std::ostream& ostr, const LLSD& sd) } case LLSD::TypeDate: #if LL_SPEW_STREAM_OUT_DEBUGGING - llinfos << "streamOut(date)" << llendl; + LL_INFOS() << "streamOut(date)" << LL_ENDL; #endif // no need to escape this since it will be alpha-numeric. ostr << "" << sd.asString() << ""; break; default: // unhandled type - llwarns << "Unhandled structured data type: " << sd.type() - << llendl; + LL_WARNS() << "Unhandled structured data type: " << sd.type() + << LL_ENDL; break; } ostr << "
    "; @@ -308,7 +309,7 @@ LLFilterSD2XMLRPCResponse::~LLFilterSD2XMLRPCResponse() } -static LLFastTimer::DeclareTimer FTM_PROCESS_SD2XMLRPC_RESPONSE("SD2XMLRPC Response"); +static LLTrace::BlockTimerStatHandle FTM_PROCESS_SD2XMLRPC_RESPONSE("SD2XMLRPC Response"); // virtual LLIOPipe::EStatus LLFilterSD2XMLRPCResponse::process_impl( const LLChannelDescriptors& channels, @@ -317,7 +318,7 @@ LLIOPipe::EStatus LLFilterSD2XMLRPCResponse::process_impl( LLSD& context, LLPumpIO* pump) { - LLFastTimer t(FTM_PROCESS_SD2XMLRPC_RESPONSE); + LL_RECORD_BLOCK_TIME(FTM_PROCESS_SD2XMLRPC_RESPONSE); PUMP_DEBUG; // This pipe does not work if it does not have everyting. This @@ -360,7 +361,7 @@ LLIOPipe::EStatus LLFilterSD2XMLRPCResponse::process_impl( } else { - llwarns << "Unable to determine the type of LLSD response." << llendl; + LL_WARNS() << "Unable to determine the type of LLSD response." << LL_ENDL; } PUMP_DEBUG; return rv; @@ -385,7 +386,7 @@ LLFilterSD2XMLRPCRequest::~LLFilterSD2XMLRPCRequest() { } -static LLFastTimer::DeclareTimer FTM_PROCESS_SD2XMLRPC_REQUEST("S22XMLRPC Request"); +static LLTrace::BlockTimerStatHandle FTM_PROCESS_SD2XMLRPC_REQUEST("S22XMLRPC Request"); // virtual LLIOPipe::EStatus LLFilterSD2XMLRPCRequest::process_impl( @@ -395,14 +396,14 @@ LLIOPipe::EStatus LLFilterSD2XMLRPCRequest::process_impl( LLSD& context, LLPumpIO* pump) { - LLFastTimer t(FTM_PROCESS_SD2XMLRPC_REQUEST); + LL_RECORD_BLOCK_TIME(FTM_PROCESS_SD2XMLRPC_REQUEST); // This pipe does not work if it does not have everyting. This // could be addressed by making a stream parser for llsd which // handled partial information. PUMP_DEBUG; if(!eos) { - llinfos << "!eos" << llendl; + LL_INFOS() << "!eos" << LL_ENDL; return STATUS_BREAK; } @@ -412,7 +413,7 @@ LLIOPipe::EStatus LLFilterSD2XMLRPCRequest::process_impl( LLSDSerialize::fromNotation(sd, stream, buffer->count(channels.in())); if(stream.fail()) { - llinfos << "STREAM FAILURE reading structure data." << llendl; + LL_INFOS() << "STREAM FAILURE reading structure data." << LL_ENDL; } PUMP_DEBUG; @@ -434,7 +435,7 @@ LLIOPipe::EStatus LLFilterSD2XMLRPCRequest::process_impl( } if(method.empty()) { - llwarns << "SD -> XML Request no method found." << llendl; + LL_WARNS() << "SD -> XML Request no method found." << LL_ENDL; return STATUS_ERROR; } @@ -445,13 +446,13 @@ LLIOPipe::EStatus LLFilterSD2XMLRPCRequest::process_impl( ostream.precision(DEFAULT_PRECISION); if(ostream.fail()) { - llinfos << "STREAM FAILURE setting precision" << llendl; + LL_INFOS() << "STREAM FAILURE setting precision" << LL_ENDL; } ostream << XML_HEADER << XMLRPC_REQUEST_HEADER_1 << xml_escape_string(method) << XMLRPC_REQUEST_HEADER_2; if(ostream.fail()) { - llinfos << "STREAM FAILURE writing method headers" << llendl; + LL_INFOS() << "STREAM FAILURE writing method headers" << LL_ENDL; } switch(param_sd.type()) { @@ -518,7 +519,7 @@ LLIOPipe::EStatus stream_out(std::ostream& ostr, XMLRPC_VALUE value) break; } case xmlrpc_type_boolean: - //lldebugs << "stream_out() bool" << llendl; + //LL_DEBUGS() << "stream_out() bool" << LL_ENDL; ostr << " " << (XMLRPC_GetValueBoolean(value) ? "true" : "false"); break; case xmlrpc_type_datetime: @@ -526,23 +527,23 @@ LLIOPipe::EStatus stream_out(std::ostream& ostr, XMLRPC_VALUE value) break; case xmlrpc_type_double: ostr << " r" << XMLRPC_GetValueDouble(value); - //lldebugs << "stream_out() double" << XMLRPC_GetValueDouble(value) - // << llendl; + //LL_DEBUGS() << "stream_out() double" << XMLRPC_GetValueDouble(value) + // << LL_ENDL; break; case xmlrpc_type_int: ostr << " i" << XMLRPC_GetValueInt(value); - //lldebugs << "stream_out() integer:" << XMLRPC_GetValueInt(value) - // << llendl; + //LL_DEBUGS() << "stream_out() integer:" << XMLRPC_GetValueInt(value) + // << LL_ENDL; break; case xmlrpc_type_string: - //lldebugs << "stream_out() string: " << str << llendl; + //LL_DEBUGS() << "stream_out() string: " << str << LL_ENDL; ostr << " s(" << XMLRPC_GetValueStringLen(value) << ")'" << XMLRPC_GetValueString(value) << "'"; break; case xmlrpc_type_array: // vector case xmlrpc_type_mixed: // vector { - //lldebugs << "stream_out() array" << llendl; + //LL_DEBUGS() << "stream_out() array" << LL_ENDL; ostr << " ["; U32 needs_comma = 0; XMLRPC_VALUE current = XMLRPC_VectorRewind(value); @@ -557,7 +558,7 @@ LLIOPipe::EStatus stream_out(std::ostream& ostr, XMLRPC_VALUE value) } case xmlrpc_type_struct: // still vector { - //lldebugs << "stream_out() struct" << llendl; + //LL_DEBUGS() << "stream_out() struct" << LL_ENDL; ostr << " {"; std::string name; U32 needs_comma = 0; @@ -577,7 +578,7 @@ LLIOPipe::EStatus stream_out(std::ostream& ostr, XMLRPC_VALUE value) case xmlrpc_type_none: default: status = LLIOPipe::STATUS_ERROR; - llwarns << "Found an empty xmlrpc type.." << llendl; + LL_WARNS() << "Found an empty xmlrpc type.." << LL_ENDL; // not much we can do here... break; }; @@ -592,7 +593,7 @@ LLFilterXMLRPCResponse2LLSD::~LLFilterXMLRPCResponse2LLSD() { } -static LLFastTimer::DeclareTimer FTM_PROCESS_XMLRPC2LLSD_RESPONSE("XMLRPC2LLSD Response"); +static LLTrace::BlockTimerStatHandle FTM_PROCESS_XMLRPC2LLSD_RESPONSE("XMLRPC2LLSD Response"); LLIOPipe::EStatus LLFilterXMLRPCResponse2LLSD::process_impl( const LLChannelDescriptors& channels, @@ -601,7 +602,7 @@ LLIOPipe::EStatus LLFilterXMLRPCResponse2LLSD::process_impl( LLSD& context, LLPumpIO* pump) { - LLFastTimer t(FTM_PROCESS_XMLRPC2LLSD_RESPONSE); + LL_RECORD_BLOCK_TIME(FTM_PROCESS_XMLRPC2LLSD_RESPONSE); PUMP_DEBUG; if(!eos) return STATUS_BREAK; @@ -617,7 +618,7 @@ LLIOPipe::EStatus LLFilterXMLRPCResponse2LLSD::process_impl( buf[bytes] = '\0'; buffer->readAfter(channels.in(), NULL, (U8*)buf, bytes); - //lldebugs << "xmlrpc response: " << buf << llendl; + //LL_DEBUGS() << "xmlrpc response: " << buf << LL_ENDL; PUMP_DEBUG; XMLRPC_REQUEST response = XMLRPC_REQUEST_FromXML( @@ -626,7 +627,7 @@ LLIOPipe::EStatus LLFilterXMLRPCResponse2LLSD::process_impl( NULL); if(!response) { - llwarns << "XML -> SD Response unable to parse xml." << llendl; + LL_WARNS() << "XML -> SD Response unable to parse xml." << LL_ENDL; delete[] buf; return STATUS_ERROR; } @@ -678,7 +679,7 @@ LLFilterXMLRPCRequest2LLSD::~LLFilterXMLRPCRequest2LLSD() { } -static LLFastTimer::DeclareTimer FTM_PROCESS_XMLRPC2LLSD_REQUEST("XMLRPC2LLSD Request"); +static LLTrace::BlockTimerStatHandle FTM_PROCESS_XMLRPC2LLSD_REQUEST("XMLRPC2LLSD Request"); LLIOPipe::EStatus LLFilterXMLRPCRequest2LLSD::process_impl( const LLChannelDescriptors& channels, buffer_ptr_t& buffer, @@ -686,7 +687,7 @@ LLIOPipe::EStatus LLFilterXMLRPCRequest2LLSD::process_impl( LLSD& context, LLPumpIO* pump) { - LLFastTimer t(FTM_PROCESS_XMLRPC2LLSD_REQUEST); + LL_RECORD_BLOCK_TIME(FTM_PROCESS_XMLRPC2LLSD_REQUEST); PUMP_DEBUG; if(!eos) return STATUS_BREAK; if(!buffer) return STATUS_ERROR; @@ -701,7 +702,7 @@ LLIOPipe::EStatus LLFilterXMLRPCRequest2LLSD::process_impl( buf[bytes] = '\0'; buffer->readAfter(channels.in(), NULL, (U8*)buf, bytes); - //lldebugs << "xmlrpc request: " << buf << llendl; + //LL_DEBUGS() << "xmlrpc request: " << buf << LL_ENDL; // Check the value in the buffer. XMLRPC_REQUEST_FromXML will report a error code 4 if // values that are less than 0x20 are passed to it, except @@ -728,7 +729,7 @@ LLIOPipe::EStatus LLFilterXMLRPCRequest2LLSD::process_impl( NULL); if(!request) { - llwarns << "XML -> SD Request process parse error." << llendl; + LL_WARNS() << "XML -> SD Request process parse error." << LL_ENDL; delete[] buf; return STATUS_ERROR; } diff --git a/indra/llmessage/llhost.cpp b/indra/llmessage/llhost.cpp index 61a84de8e3..3ded1a56d5 100644 --- a/indra/llmessage/llhost.cpp +++ b/indra/llmessage/llhost.cpp @@ -59,11 +59,12 @@ LLHost::LLHost(const std::string& ip_and_port) mIP = ip_string_to_u32(ip_str.c_str()); mPort = atol(port_str.c_str()); } + mHostNotFound = 0; } std::string LLHost::getString() const { - return llformat("%s:%u", u32_to_ip_string(mIP), mPort); + return llformat("%s:%hu", u32_to_ip_string(mIP), mPort); } @@ -84,19 +85,30 @@ std::string LLHost::getHostName() const hostent* he; if (INVALID_HOST_IP_ADDRESS == mIP) { - llwarns << "LLHost::getHostName() : Invalid IP address" << llendl; + LL_WARNS() << "LLHost::getHostName() : Invalid IP address" << LL_ENDL; + return std::string(); + } + if (mHostNotFound) + { + // We already checked this... avoid freezing the viewer 5 seconds again and again. + LL_WARNS() << "LLHost::getHostName() : Returning cached HOST_NOT_FOUND." << LL_ENDL; return std::string(); } he = gethostbyaddr((char *)&mIP, sizeof(mIP), AF_INET); if (!he) { #if LL_WINDOWS - llwarns << "LLHost::getHostName() : Couldn't find host name for address " << mIP << ", Error: " - << WSAGetLastError() << llendl; + int err = WSAGetLastError(); + int err_host_not_found = WSAHOST_NOT_FOUND; #else - llwarns << "LLHost::getHostName() : Couldn't find host name for address " << mIP << ", Error: " - << h_errno << llendl; + int err = h_errno; + int err_host_not_found = HOST_NOT_FOUND; #endif + LL_WARNS() << "LLHost::getHostName() : Couldn't find host name for address " << mIP << ", Error: " << err << LL_ENDL; + if (err == err_host_not_found) + { + mHostNotFound = 1; + } return std::string(); } else @@ -125,6 +137,7 @@ BOOL LLHost::setHostByName(const std::string& hostname) if (he) { mIP = *(U32 *)he->h_addr_list[0]; + mHostNotFound = 0; return TRUE; } else @@ -136,17 +149,17 @@ BOOL LLHost::setHostByName(const std::string& hostname) switch(error_number) { case TRY_AGAIN: // XXX how to handle this case? - llwarns << "LLHost::setAddress(): try again" << llendl; + LL_WARNS() << "LLHost::setAddress(): try again" << LL_ENDL; break; case HOST_NOT_FOUND: case NO_ADDRESS: // NO_DATA - llwarns << "LLHost::setAddress(): host not found" << llendl; + LL_WARNS() << "LLHost::setAddress(): host not found" << LL_ENDL; break; case NO_RECOVERY: - llwarns << "LLHost::setAddress(): unrecoverable error" << llendl; + LL_WARNS() << "LLHost::setAddress(): unrecoverable error" << LL_ENDL; break; default: - llwarns << "LLHost::setAddress(): unknown error - " << error_number << llendl; + LL_WARNS() << "LLHost::setAddress(): unknown error - " << error_number << LL_ENDL; break; } return FALSE; diff --git a/indra/llmessage/llhost.h b/indra/llmessage/llhost.h index 0cf52a4151..8d7f6be633 100644 --- a/indra/llmessage/llhost.h +++ b/indra/llmessage/llhost.h @@ -38,7 +38,8 @@ const U32 INVALID_HOST_IP_ADDRESS = 0x0; class LLHost { protected: - U32 mPort; + U16 mPort; + mutable U16 mHostNotFound; // Singularity addition; caches a failed IP -> hostname lookup. U32 mIP; public: @@ -47,17 +48,20 @@ class LLHost { // CREATORS LLHost() : mPort(INVALID_PORT), + mHostNotFound(1), mIP(INVALID_HOST_IP_ADDRESS) { } // STL's hash_map expect this T() LLHost( U32 ipv4_addr, U32 port ) - : mPort( port ) + : mPort(port), + mHostNotFound(0) { mIP = ipv4_addr; } LLHost( const std::string& ipv4_addr, U32 port ) - : mPort( port ) + : mPort(port), + mHostNotFound(0) { mIP = ip_string_to_u32(ipv4_addr.c_str()); } @@ -68,6 +72,7 @@ class LLHost { U32 port = (U32)(ip_port & (U64)0xFFFFFFFF); mIP = ip; mPort = port; + mHostNotFound = 0; } explicit LLHost(const std::string& ip_and_port); @@ -76,15 +81,15 @@ class LLHost { { } // MANIPULATORS - void set( U32 ip, U32 port ) { mIP = ip; mPort = port; } - void set( const std::string& ipstr, U32 port ) { mIP = ip_string_to_u32(ipstr.c_str()); mPort = port; } - void setAddress( const std::string& ipstr ) { mIP = ip_string_to_u32(ipstr.c_str()); } - void setAddress( U32 ip ) { mIP = ip; } + void set( U32 ip, U32 port ) { mIP = ip; mPort = port; mHostNotFound = 0; } + void set( const std::string& ipstr, U32 port ) { mIP = ip_string_to_u32(ipstr.c_str()); mPort = port; mHostNotFound = 0; } + void setAddress( const std::string& ipstr ) { mIP = ip_string_to_u32(ipstr.c_str()); mHostNotFound = 0; } + void setAddress( U32 ip ) { mIP = ip; mHostNotFound = 0; } void setPort( U32 port ) { mPort = port; } BOOL setHostByName(const std::string& hname); LLHost& operator=(const LLHost &rhs); - void invalidate() { mIP = INVALID_HOST_IP_ADDRESS; mPort = INVALID_PORT;}; + void invalidate() { mIP = INVALID_HOST_IP_ADDRESS; mPort = INVALID_PORT; mHostNotFound = 1; } // READERS U32 getAddress() const { return mIP; } diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp index dfbc9e2494..fbc576234d 100644 --- a/indra/llmessage/llhttpclient.cpp +++ b/indra/llmessage/llhttpclient.cpp @@ -110,7 +110,7 @@ class LLSDInjector : public Injector class RawInjector : public Injector { public: - RawInjector(char const* data, U32 size) : mData(data), mSize(size) { } + RawInjector(U8 const* data, U32 size) : mData(data), mSize(size) { } /*virtual*/ ~RawInjector() { delete [] mData; } /*virtual*/ char const* contentType(void) const { return "application/octet-stream"; } @@ -118,12 +118,12 @@ class RawInjector : public Injector /*virtual*/ U32 get_body(LLChannelDescriptors const& channels, buffer_ptr_t& buffer) { LLBufferStream ostream(channels, buffer.get()); - ostream.write(mData, mSize); + ostream.write((const char*)mData, mSize); ostream << std::flush; // Always flush a LLBufferStream when done writing to it. return mSize; } - char const* mData; + U8 const* mData; U32 mSize; }; @@ -229,7 +229,7 @@ void LLHTTPClient::request( } catch(AICurlNoEasyHandle& error) { - llwarns << "Failed to create LLURLRequest: " << error.what() << llendl; + LL_WARNS() << "Failed to create LLURLRequest: " << error.what() << LL_ENDL; // This is what the old LL code did: no recovery whatsoever (but also no leaks or crash). return ; } @@ -237,13 +237,23 @@ void LLHTTPClient::request( req->run(parent, new_parent_state, parent != NULL, true, default_engine); } -void LLHTTPClient::getByteRange(std::string const& url, S32 offset, S32 bytes, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug)) +bool LLHTTPClient::getByteRange(std::string const& url, AIHTTPHeaders& headers, S32 offset, S32 bytes, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug)) { - if(offset > 0 || bytes > 0) + try + { + if (offset > 0 || bytes > 0) + { + int const range_end = offset + bytes - 1; + char const* const range_format = (range_end >= HTTP_REQUESTS_RANGE_END_MAX) ? "bytes=%d-" : "bytes=%d-%d"; + headers.addHeader("Range", llformat(range_format, offset, range_end)); + } + request(url, HTTP_GET, NULL, responder, headers, NULL/*,*/ DEBUG_CURLIO_PARAM(debug)); + } + catch(AICurlNoEasyHandle const&) { - headers.addHeader("Range", llformat("bytes=%d-%d", offset, offset + bytes - 1)); + return false; } - request(url, HTTP_GET, NULL, responder, headers, NULL/*,*/ DEBUG_CURLIO_PARAM(debug)); + return true; } void LLHTTPClient::head(std::string const& url, ResponderHeadersOnly* responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug)) @@ -302,36 +312,36 @@ AIHTTPTimeoutPolicy const& LLHTTPClient::ResponderBase::getHTTPTimeoutPolicy(voi return AIHTTPTimeoutPolicy::getDebugSettingsCurlTimeout(); } -void LLHTTPClient::ResponderBase::decode_llsd_body(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer, LLSD& content) +void LLHTTPClient::ResponderBase::decode_llsd_body(LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) { AICurlInterface::Stats::llsd_body_count++; - if (is_internal_http_error(status)) + if (is_internal_http_error(mStatus)) { // In case of an internal error (ie, a curl error), a description of the (curl) error is the best we can do. // In any case, the body if anything was received at all, can not be relied upon. - content = reason; + mContent = mReason; return; } // If the status indicates success (and we get here) then we expect the body to be LLSD. - bool const should_be_llsd = (200 <= status && status < 300); + bool const should_be_llsd = isGoodStatus(mStatus); if (should_be_llsd) { LLBufferStream istr(channels, buffer.get()); - if (LLSDSerialize::fromXML(content, istr) == LLSDParser::PARSE_FAILURE) + if (LLSDSerialize::fromXML(mContent, istr) == LLSDParser::PARSE_FAILURE) { // Unfortunately we can't show the body of the message... I think this is a pretty serious error // though, so if this ever happens it has to be investigated by making a copy of the buffer // before serializing it, as is done below. - llwarns << "Failed to deserialize LLSD. " << mURL << " [" << status << "]: " << reason << llendl; + LL_WARNS() << "Failed to deserialize LLSD. " << mURL << " [" << mStatus << "]: " << mReason << LL_ENDL; AICurlInterface::Stats::llsd_body_parse_error++; } - // LLSDSerialize::fromXML destructed buffer, we can't initialize content now. + // LLSDSerialize::fromXML destructed buffer, we can't initialize mContent now. return; } - // Put the body in content as-is. + // Put the body in mContent as-is. std::stringstream ss; buffer->writeChannelTo(ss, channels.in()); - content = ss.str(); + mContent = ss.str(); #ifdef SHOW_ASSERT if (!should_be_llsd) { @@ -343,10 +353,11 @@ void LLHTTPClient::ResponderBase::decode_llsd_body(U32 status, std::string const strncmp(str, "cap not found:", 14) && // Most of the other 3%. str[0] && // Empty happens too and aint LLSD either. strncmp(str, "Not Found", 9) && + strncmp(str, "Upstream error: ", 16) && // Received by LLEventPollResponder every 50 seconds (see http://wiki.secondlife.com/wiki/EventQueueGet). LLSDSerialize::fromXML(dummy, ss) > 0; if (server_sent_llsd_with_http_error) { - llwarns << "The server sent us a response with http status " << status << " and LLSD(!) body: \"" << ss.str() << "\"!" << llendl; + LL_WARNS() << "The server sent us a response with http status " << mStatus << " and LLSD(!) body: \"" << ss.str() << "\"!" << LL_ENDL; } // This is not really an error, and it has been known to happen before. It just normally never happens (at the moment) // and therefore warrants an investigation. Linden Lab (or other grids) might start to send error messages @@ -359,14 +370,14 @@ void LLHTTPClient::ResponderBase::decode_llsd_body(U32 status, std::string const #endif } -void LLHTTPClient::ResponderBase::decode_raw_body(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer, std::string& content) +void LLHTTPClient::ResponderBase::decode_raw_body(LLChannelDescriptors const& channels, buffer_ptr_t const& buffer, std::string& content) { AICurlInterface::Stats::raw_body_count++; - if (is_internal_http_error(status)) + if (is_internal_http_error(mStatus)) { // In case of an internal error (ie, a curl error), a description of the (curl) error is the best we can do. // In any case, the body if anything was received at all, can not be relied upon. - content = reason; + content = mReason; return; } LLMutexLock lock(buffer->getMutex()); @@ -398,19 +409,43 @@ std::string const& LLHTTPClient::ResponderBase::get_cookie(std::string const& ke return empty_dummy; } +std::string LLHTTPClient::ResponderBase::dumpResponse(void) const +{ + std::ostringstream s; + s << "[responder:" << getName() << "] " + << "[URL:" << mURL << "] " + << "[status:" << mStatus << "] " + << "[reason:" << mReason << "] "; + + AIHTTPReceivedHeaders::range_type content_type; + if (mReceivedHeaders.getValues("content-type", content_type)) + { + for (AIHTTPReceivedHeaders::iterator_type iter = content_type.first; iter != content_type.second; ++iter) + { + s << "[content-type:" << iter->second << "] "; + } + } + + if (mContent.isDefined()) + { + s << "[content:" << LLSDOStreamer(mContent, LLSDFormatter::OPTIONS_PRETTY) << "]"; + } + + return s.str(); +} + // Called with HTML body. // virtual -void LLHTTPClient::ResponderWithCompleted::completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) +void LLHTTPClient::ResponderWithCompleted::completedRaw(LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) { - LLSD content; - decode_llsd_body(status, reason, channels, buffer, content); + decode_llsd_body(channels, buffer); // Allow derived class to override at this point. - completed(status, reason, content); + httpCompleted(); } // virtual -void LLHTTPClient::ResponderWithCompleted::completed(U32 status, std::string const& reason, LLSD const& content) +void LLHTTPClient::ResponderWithCompleted::httpCompleted(void) { // Either completedRaw() or this method must be overridden by the derived class. Hence, we should never get here. llassert_always(false); @@ -420,36 +455,31 @@ void LLHTTPClient::ResponderWithCompleted::completed(U32 status, std::string con void LLHTTPClient::ResponderWithResult::finished(CURLcode code, U32 http_status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) { mCode = code; + mStatus = http_status; + mReason = reason; - LLSD content; - decode_llsd_body(http_status, reason, channels, buffer, content); + // Fill mContent. + decode_llsd_body(channels, buffer); // HTTP status good? - if (200 <= http_status && http_status < 300) + if (isGoodStatus(http_status)) { // Allow derived class to override at this point. - result(content); + httpSuccess(); } else { // Allow derived class to override at this point. - errorWithContent(http_status, reason, content); + httpFailure(); } mFinished = true; } // virtual -void LLHTTPClient::ResponderWithResult::errorWithContent(U32 status, std::string const& reason, LLSD const&) +void LLHTTPClient::ResponderWithResult::httpFailure(void) { - // Allow derived class to override at this point. - error(status, reason); -} - -// virtual -void LLHTTPClient::ResponderWithResult::error(U32 status, std::string const& reason) -{ - llinfos << mURL << " [" << status << "]: " << reason << llendl; + LL_INFOS() << mURL << " [" << mStatus << "]: " << mReason << LL_ENDL; } // Friend functions. @@ -471,22 +501,20 @@ void intrusive_ptr_release(LLHTTPClient::ResponderBase* responder) // Blocking Responders. // -class BlockingResponder : public LLHTTPClient::LegacyPolledResponder { +class BlockingResponder : public LLHTTPClient::ResponderWithCompleted { private: LLCondition mSignal; // Wait condition to wait till mFinished is true. - static LLSD LLSD_dummy; static std::string Raw_dummy; public: void wait(void); // Blocks until mFinished is true. - virtual LLSD const& getLLSD(void) const { llassert(false); return LLSD_dummy; } virtual std::string const& getRaw(void) const { llassert(false); return Raw_dummy; } + /*virtual*/ LLSD const& getContent(void) const { llassert(false); return LLHTTPClient::ResponderWithCompleted::getContent(); } protected: void wakeup(void); // Call this at the end of completedRaw. }; -LLSD BlockingResponder::LLSD_dummy; std::string BlockingResponder::Raw_dummy; void BlockingResponder::wait(void) @@ -521,14 +549,11 @@ void BlockingResponder::wakeup(void) } class BlockingLLSDResponder : public BlockingResponder { -private: - LLSD mResponse; - protected: - /*virtual*/ LLSD const& getLLSD(void) const { llassert(mFinished && mCode == CURLE_OK && mStatus == HTTP_OK); return mResponse; } - /*virtual*/ void completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) + /*virtual*/ LLSD const& getContent(void) const { llassert(mFinished && mCode == CURLE_OK); return LLHTTPClient::ResponderWithCompleted::getContent(); } + /*virtual*/ void completedRaw(LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) { - decode_llsd_body(status, reason, channels, buffer, mResponse); // This puts the body asString() in mResponse in case of http error. + decode_llsd_body(channels, buffer); // This puts the body asString() in mContent in case of http error. wakeup(); } }; @@ -538,10 +563,10 @@ class BlockingRawResponder : public BlockingResponder { std::string mResponse; protected: - /*virtual*/ std::string const& getRaw(void) const { llassert(mFinished && mCode == CURLE_OK && mStatus == HTTP_OK); return mResponse; } - /*virtual*/ void completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) + /*virtual*/ std::string const& getRaw(void) const { llassert(mFinished && mCode == CURLE_OK); return mResponse; } + /*virtual*/ void completedRaw(LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) { - decode_raw_body(mCode, reason, channels, buffer, mResponse); + decode_raw_body(channels, buffer, mResponse); wakeup(); } }; @@ -597,7 +622,7 @@ static LLSD blocking_request( LLSD const& body/*,*/ // Only used for HTTP_LLSD_POST DEBUG_CURLIO_PARAM(EDebugCurl debug)) { - lldebugs << "blockingRequest of " << url << llendl; + LL_DEBUGS() << "blockingRequest of " << url << LL_ENDL; AIHTTPHeaders headers; boost::intrusive_ptr responder; @@ -621,7 +646,7 @@ static LLSD blocking_request( LLSD response = LLSD::emptyMap(); CURLcode result = responder->result_code(); - S32 http_status = responder->http_status(); + S32 http_status = responder->getStatus(); bool http_success = http_status >= 200 && http_status < 300; if (result == CURLE_OK && http_success) @@ -632,29 +657,29 @@ static LLSD blocking_request( } else { - response["body"] = responder->getLLSD(); + response["body"] = responder->getContent(); } } - else if (result == CURLE_OK) + else if (result == CURLE_OK && !is_internal_http_error(http_status)) { // We expect 404s, don't spam for them. if (http_status != 404) { - llwarns << "CURL REQ URL: " << url << llendl; - llwarns << "CURL REQ METHOD TYPE: " << method << llendl; - llwarns << "CURL REQ HEADERS: " << headers << llendl; + LL_WARNS() << "CURL REQ URL: " << url << LL_ENDL; + LL_WARNS() << "CURL REQ METHOD TYPE: " << method << LL_ENDL; + LL_WARNS() << "CURL REQ HEADERS: " << headers << LL_ENDL; if (method == HTTP_LLSD_POST) { - llwarns << "CURL REQ BODY: " << body.asString() << llendl; + LL_WARNS() << "CURL REQ BODY: " << body.asString() << LL_ENDL; } - llwarns << "CURL HTTP_STATUS: " << http_status << llendl; + LL_WARNS() << "CURL HTTP_STATUS: " << http_status << LL_ENDL; if (method == HTTP_RAW_GET) { - llwarns << "CURL ERROR BODY: " << responder->getRaw() << llendl; + LL_WARNS() << "CURL ERROR BODY: " << responder->getRaw() << LL_ENDL; } else { - llwarns << "CURL ERROR BODY: " << responder->getLLSD().asString() << llendl; + LL_WARNS() << "CURL ERROR BODY: " << responder->getContent().asString() << LL_ENDL; } } if (method == HTTP_RAW_GET) @@ -663,12 +688,12 @@ static LLSD blocking_request( } else { - response["body"] = responder->getLLSD().asString(); + response["body"] = responder->getContent().asString(); } } else { - response["body"] = responder->reason(); + response["body"] = responder->getReason(); } response["status"] = http_status; @@ -697,6 +722,16 @@ void LLHTTPClient::put(std::string const& url, LLSD const& body, ResponderPtr re request(url, HTTP_PUT, new LLSDInjector(body), responder, headers, NULL/*,*/ DEBUG_CURLIO_PARAM(debug), no_keep_alive, no_does_authentication, no_allow_compressed_reply); } +void LLHTTPClient::putRaw(const std::string& url, const U8* data, S32 size, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug)) +{ + request(url, HTTP_PUT, new RawInjector(data, size), responder, headers, NULL/*,*/ DEBUG_CURLIO_PARAM(debug), no_keep_alive, no_does_authentication, no_allow_compressed_reply); +} + +void LLHTTPClient::patch(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug), EKeepAlive keepalive, AIStateMachine* parent, AIStateMachine::state_type new_parent_state) +{ + request(url, HTTP_PATCH, new LLSDInjector(body), responder, headers, NULL/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive, no_does_authentication, allow_compressed_reply, parent, new_parent_state); +} + void LLHTTPClient::post(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug), EKeepAlive keepalive, AIStateMachine* parent, AIStateMachine::state_type new_parent_state) { request(url, HTTP_POST, new LLSDInjector(body), responder, headers, NULL/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive, no_does_authentication, allow_compressed_reply, parent, new_parent_state); @@ -723,7 +758,7 @@ void LLHTTPClient::postXMLRPC(std::string const& url, char const* method, XMLRPC request(url, HTTP_POST, new XMLRPCInjector(xmlrpc_request), responder, headers, NULL/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive, does_authentication, no_allow_compressed_reply); } -void LLHTTPClient::postRaw(std::string const& url, char const* data, S32 size, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug), EKeepAlive keepalive) +void LLHTTPClient::postRaw(std::string const& url, U8 const* data, S32 size, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug), EKeepAlive keepalive) { request(url, HTTP_POST, new RawInjector(data, size), responder, headers, NULL/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive); } @@ -750,3 +785,10 @@ void LLHTTPClient::move(std::string const& url, std::string const& destination, headers.addHeader("Destination", destination); request(url, HTTP_MOVE, NULL, responder, headers, NULL/*,*/ DEBUG_CURLIO_PARAM(debug)); } + +// static +void LLHTTPClient::copy(std::string const& url, std::string const& destination, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug)) +{ + headers.addHeader("Destination", destination); + request(url, HTTP_COPY, NULL, responder, headers, NULL/*,*/ DEBUG_CURLIO_PARAM(debug)); +} diff --git a/indra/llmessage/llhttpclient.h b/indra/llmessage/llhttpclient.h index b4ce6faccd..a7f4cb3eb5 100644 --- a/indra/llmessage/llhttpclient.h +++ b/indra/llmessage/llhttpclient.h @@ -55,6 +55,17 @@ typedef struct _xmlrpc_request* XMLRPC_REQUEST; typedef struct _xmlrpc_value* XMLRPC_VALUE; extern AIEngine gMainThreadEngine; +// In Viewer 3 this definition is in indra/newview/lltexturefetch.cpp, +// but we need it in two .cpp files, so it's moved here. +// +// BUG-3323/SH-4375 +// *NOTE: This is a heuristic value. Texture fetches have a habit of using a +// value of 32MB to indicate 'get the rest of the image'. Certain ISPs and +// network equipment get confused when they see this in a Range: header. So, +// if the request end is beyond this value, we issue an open-ended Range: +// request (e.g. 'Range: -') which seems to fix the problem. +static const S32 HTTP_REQUESTS_RANGE_END_MAX = 20000000; + // Output parameter of AICurlPrivate::CurlEasyRequest::getResult. // Used in XMLRPCResponder. struct AITransferInfo { @@ -110,6 +121,8 @@ class LLHTTPClient { HTTP_POST, HTTP_DELETE, HTTP_MOVE, // Caller will need to set 'Destination' header + HTTP_PATCH, + HTTP_COPY, REQUEST_ACTION_COUNT }; @@ -133,15 +146,23 @@ class LLHTTPClient { public: typedef boost::shared_ptr buffer_ptr_t; + /** + * @brief return true if the status code indicates success. + */ + static bool isGoodStatus(S32 status) + { + return((200 <= status) && (status < 300)); + } + protected: ResponderBase(void); virtual ~ResponderBase(); - // Read body from buffer and put it into content. If status indicates success, interpret it as LLSD, otherwise copy it as-is. - void decode_llsd_body(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer, LLSD& content); + // Read body from buffer and put it into mContent. If mStatus indicates success, interpret it as LLSD, otherwise copy it as-is. + void decode_llsd_body(LLChannelDescriptors const& channels, buffer_ptr_t const& buffer); // Read body from buffer and put it into content. Always copy it as-is. - void decode_raw_body(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer, std::string& content); + void decode_raw_body(LLChannelDescriptors const& channels, buffer_ptr_t const& buffer, std::string& content); protected: // Associated URL, used for debug output. @@ -153,6 +174,15 @@ class LLHTTPClient { // The curl result code. CURLcode mCode; + // HTTP status code, if any. + S32 mStatus; + + // Reason for error if mStatus is not good. + std::string mReason; + + // Content interpreted as LLSD. + LLSD mContent; + // Set when the transaction finished (with or without errors). bool mFinished; @@ -165,6 +195,29 @@ class LLHTTPClient { std::string const& getURL(void) const { return mURL; } CURLcode result_code(void) const { return mCode; } + protected: + // Short cut. + void setResult(S32 status, std::string const& reason, LLSD const& content) { mStatus = status; mReason = reason; mContent = content; mFinished = true; } + + // Call these only from the httpSuccess/httpFailure/httpComplete methods of derived classes. + + LLSD const& getContent(void) const { return mContent; } + // You can just access mReceivedHeaders directly from derived classes, but added this accessor + // for convenience because upstream introduced this method as part of a new API. + AIHTTPReceivedHeaders const& getResponseHeaders(void) const + { + // If this fails then you need to add '/*virtual*/ bool needsHeaders(void) const { return true; }' to the most derived class. + llassert(needsHeaders()); + return mReceivedHeaders; + } + // Another convenience method to match upstream. + std::string dumpResponse(void) const; + public: + // The next two are public because blocking_request() needs access too. + S32 getStatus(void) const { return mStatus; } + std::string const& getReason(void) const { return mReason; } + + public: // Called by BufferedCurlEasyRequest::timed_out or BufferedCurlEasyRequest::processOutput. virtual void finished(CURLcode code, U32 http_status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) = 0; @@ -207,7 +260,9 @@ class LLHTTPClient { // Called when the whole transaction is completed (also the body was received), but before the body is processed. /*virtual*/ void completed_headers(U32 status, std::string const& reason, AITransferInfo* info) { - completedHeaders(status, reason, mReceivedHeaders); + mStatus = status; + mReason = reason; + completedHeaders(); } // Extract cookie 'key' from mReceivedHeaders and return the string 'key=value', or an empty string if key does not exists. @@ -221,18 +276,21 @@ class LLHTTPClient { // The default is to keep connections open for possible reuse. virtual bool forbidReuse(void) const { return false; } - // A derived class should return true if curl should follow redirections. - // The default is not to follow redirections. - virtual bool followRedir(void) const { return false; } + // A derived class should return true if curl should not follow redirections, but instead pass redirection status codes to the responder. + // The default is to follow redirections and not pass them to the responder. + virtual bool pass_redirect_status(void) const { return false; } // If this function returns false then we generate an error when a redirect status (300..399) is received. - virtual bool redirect_status_ok(void) const { return followRedir(); } + virtual bool redirect_status_ok(void) const { return true; } + + // Overridden by LLEventPollResponder to return true. + virtual bool is_event_poll(void) const { return false; } // Returns the capability type used by this responder. virtual AICapabilityType capability_type(void) const { return cap_other; } // Timeout policy to use. - virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const = 0; + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const; // The name of the derived responder object. For debugging purposes. virtual char const* getName(void) const = 0; @@ -240,7 +298,7 @@ class LLHTTPClient { protected: // Derived classes can override this to get the HTML headers that were received, when the message is completed. // Only actually called for classes that implement a needsHeaders() that returns true. - virtual void completedHeaders(U32 status, std::string const& reason, AIHTTPReceivedHeaders const& headers) + virtual void completedHeaders(void) { // The default does nothing. } @@ -259,7 +317,6 @@ class LLHTTPClient { class ResponderHeadersOnly : public ResponderBase { private: /*virtual*/ bool needsHeaders(void) const { return true; } - /*virtual*/ bool followRedir(void) const { return true; } protected: // ResponderBase event @@ -268,8 +325,10 @@ class LLHTTPClient { /*virtual*/ void finished(CURLcode code, U32 http_status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) { mCode = code; + mStatus = http_status; + mReason = reason; // Allow classes derived from ResponderHeadersOnly to override completedHeaders. - completedHeaders(http_status, reason, mReceivedHeaders); + completedHeaders(); mFinished = true; } @@ -281,10 +340,9 @@ class LLHTTPClient { // warning when a class accidently tries to override them. enum YOU_MAY_ONLY_OVERRIDE_COMPLETED_HEADERS { }; virtual void completedRaw(YOU_MAY_ONLY_OVERRIDE_COMPLETED_HEADERS) { } - virtual void completed(YOU_MAY_ONLY_OVERRIDE_COMPLETED_HEADERS) { } - virtual void result(YOU_MAY_ONLY_OVERRIDE_COMPLETED_HEADERS) { } - virtual void errorWithContent(YOU_MAY_ONLY_OVERRIDE_COMPLETED_HEADERS) { } - virtual void error(YOU_MAY_ONLY_OVERRIDE_COMPLETED_HEADERS) { } + virtual void httpCompleted(YOU_MAY_ONLY_OVERRIDE_COMPLETED_HEADERS) { } + virtual void httpSuccess(YOU_MAY_ONLY_OVERRIDE_COMPLETED_HEADERS) { } + virtual void httpFailure(YOU_MAY_ONLY_OVERRIDE_COMPLETED_HEADERS) { } #endif }; @@ -300,9 +358,11 @@ class LLHTTPClient { /*virtual*/ void finished(CURLcode code, U32 http_status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) { mCode = code; + mStatus = http_status; + mReason = reason; // Allow classes derived from ResponderWithCompleted to override completedRaw // (if not they should override completed or be derived from ResponderWithResult instead). - completedRaw(http_status, reason, channels, buffer); + completedRaw(channels, buffer); mFinished = true; } @@ -310,13 +370,17 @@ class LLHTTPClient { // Events generated by this class. // Derived classes can override this to get the raw data of the body of the HTML message that was received. - // The default is to interpret the content as LLSD and call completed(). - virtual void completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer); + // The default is to interpret the content as LLSD and call httpCompleted(). + virtual void completedRaw(LLChannelDescriptors const& channels, buffer_ptr_t const& buffer); // ... or, derived classes can override this to get LLSD content when the message is completed. // The default aborts, as it should never be called (can't make it pure virtual though, so // classes that override completedRaw don't need to implement this function, too). - virtual void completed(U32 status, std::string const& reason, LLSD const& content); + virtual void httpCompleted(void); + + public: + // Ugly LL API... + void completeResult(S32 status, std::string const& reason, LLSD const& content) { mCode = CURLE_OK; setResult(status, reason, content); httpCompleted(); } #ifdef SHOW_ASSERT // Responders derived from this class must override either completedRaw or completed. @@ -324,9 +388,8 @@ class LLHTTPClient { // Define those functions here with different parameters in order to cause a compile // warning when a class accidently tries to override them. enum YOU_ARE_DERIVING_FROM_THE_WRONG_CLASS { }; - virtual void result(YOU_ARE_DERIVING_FROM_THE_WRONG_CLASS) { } - virtual void errorWithContent(YOU_ARE_DERIVING_FROM_THE_WRONG_CLASS) { } - virtual void error(YOU_ARE_DERIVING_FROM_THE_WRONG_CLASS) { } + virtual void httpSuccess(YOU_ARE_DERIVING_FROM_THE_WRONG_CLASS) { } + virtual void httpFailure(YOU_ARE_DERIVING_FROM_THE_WRONG_CLASS) { } #endif }; @@ -345,22 +408,18 @@ class LLHTTPClient { // Events generated by this class. // Derived classes must override this to receive the content of a body upon success. - virtual void result(LLSD const& content) = 0; - - // Derived classes can override this to get informed when a bad HTML status code is received. - // The default calls error(). - virtual void errorWithContent(U32 status, std::string const& reason, LLSD const& content); + virtual void httpSuccess(void) = 0; // ... or, derived classes can override this to get informed when a bad HTML status code is received. // The default prints the error to llinfos. - virtual void error(U32 status, std::string const& reason); + virtual void httpFailure(void); public: // Called from LLSDMessage::ResponderAdapter::listener. // LLSDMessage::ResponderAdapter is a hack, showing among others by fact that it needs these functions. - void pubErrorWithContent(CURLcode code, U32 status, std::string const& reason, LLSD const& content) { mCode = code; errorWithContent(status, reason, content); mFinished = true; } - void pubResult(LLSD const& content) { mCode = CURLE_OK; result(content); mFinished = true; } + void failureResult(U32 status, std::string const& reason, LLSD const& content, CURLcode code = CURLE_OK) { mCode = code; setResult(status, reason, content); httpFailure(); } + void successResult(LLSD const& content) { mCode = CURLE_OK; setResult(HTTP_OK, "", content); httpSuccess(); } #ifdef SHOW_ASSERT // Responders derived from this class must override result, and either errorWithContent or error. @@ -369,48 +428,16 @@ class LLHTTPClient { // warning when a class accidently tries to override them. enum YOU_ARE_DERIVING_FROM_THE_WRONG_CLASS { }; virtual void completedRaw(YOU_ARE_DERIVING_FROM_THE_WRONG_CLASS) { } - virtual void completed(YOU_ARE_DERIVING_FROM_THE_WRONG_CLASS) { } + virtual void httpCompleted(YOU_ARE_DERIVING_FROM_THE_WRONG_CLASS) { } #endif }; - /** - * @class LegacyPolledResponder - * @brief As ResponderWithCompleted but caches the result for polling. - * - * This class allows old polling code to poll if the transaction finished - * by calling is_finished() (from the main the thread) and then access the - * results-- as opposed to immediately digesting the results when any of - * the virtual functions are called. - */ - class LegacyPolledResponder : public ResponderWithCompleted { - protected: - U32 mStatus; - std::string mReason; - - protected: - // The responder finished. Do not override this function in derived classes. - /*virtual*/ void finished(CURLcode code, U32 http_status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) - { - mStatus = http_status; - mReason = reason; - // Call base class implementation. - ResponderWithCompleted::finished(code, http_status, reason, channels, buffer); - } - - public: - LegacyPolledResponder(void) : mStatus(HTTP_INTERNAL_ERROR_OTHER) { } - - // Accessors. - U32 http_status(void) const { return mStatus; } - std::string const& reason(void) const { return mReason; } - }; - /** * @class ResponderIgnoreBody * @brief Base class for responders that ignore the result body. */ class ResponderIgnoreBody : public ResponderWithResult { - void result(LLSD const&) { } + void httpSuccess(void) { } }; /** @@ -450,9 +477,9 @@ class LLHTTPClient { static void head(std::string const& url, ResponderHeadersOnly* responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off)) { AIHTTPHeaders headers; head(url, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug)); } - static void getByteRange(std::string const& url, S32 offset, S32 bytes, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off)); - static void getByteRange(std::string const& url, S32 offset, S32 bytes, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off)) - { AIHTTPHeaders headers; getByteRange(url, offset, bytes, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug)); } + static bool getByteRange(std::string const& url, AIHTTPHeaders& headers, S32 offset, S32 bytes, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off)); + static bool getByteRange(std::string const& url, S32 offset, S32 bytes, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off)) + { AIHTTPHeaders headers; return getByteRange(url, headers, offset, bytes, responder/*,*/ DEBUG_CURLIO_PARAM(debug)); } static void get(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off)); static void get(std::string const& url, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off)) @@ -466,10 +493,18 @@ class LLHTTPClient { static void put(std::string const& url, LLSD const& body, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off)) { AIHTTPHeaders headers; put(url, body, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug)); } + static void putRaw(const std::string& url, const U8* data, S32 size, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off)); + static void putRaw(const std::string& url, const U8* data, S32 size, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off)) + { AIHTTPHeaders headers; putRaw(url, data, size, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug)); } + static void getHeaderOnly(std::string const& url, ResponderHeadersOnly* responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off)); static void getHeaderOnly(std::string const& url, ResponderHeadersOnly* responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off)) { AIHTTPHeaders headers; getHeaderOnly(url, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug)); } + static void patch(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off), EKeepAlive keepalive = keep_alive, AIStateMachine* parent = NULL, U32 new_parent_state = 0); + static void patch(std::string const& url, LLSD const& body, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off), EKeepAlive keepalive = keep_alive, AIStateMachine* parent = NULL, U32 new_parent_state = 0) + { AIHTTPHeaders headers; patch(url, body, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive, parent, new_parent_state); } + static void post(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off), EKeepAlive keepalive = keep_alive, AIStateMachine* parent = NULL, U32 new_parent_state = 0); static void post(std::string const& url, LLSD const& body, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off), EKeepAlive keepalive = keep_alive, AIStateMachine* parent = NULL, U32 new_parent_state = 0) { AIHTTPHeaders headers; post(url, body, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive, parent, new_parent_state); } @@ -488,8 +523,8 @@ class LLHTTPClient { { AIHTTPHeaders headers; postXMLRPC(url, method, value, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive); } /** Takes ownership of data and deletes it when sent */ - static void postRaw(std::string const& url, const char* data, S32 size, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off), EKeepAlive keepalive = keep_alive); - static void postRaw(std::string const& url, const char* data, S32 size, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off), EKeepAlive keepalive = keep_alive) + static void postRaw(std::string const& url, const U8* data, S32 size, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off), EKeepAlive keepalive = keep_alive); + static void postRaw(std::string const& url, const U8* data, S32 size, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off), EKeepAlive keepalive = keep_alive) { AIHTTPHeaders headers; postRaw(url, data, size, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug), keepalive); } static void postFile(std::string const& url, std::string const& filename, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off), EKeepAlive keepalive = keep_alive); @@ -521,6 +556,12 @@ class LLHTTPClient { //@} + static void copy(std::string const& url, std::string const& destination, ResponderPtr responder, AIHTTPHeaders& headers/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off)); + static void copy(std::string const& url, std::string const& destination, ResponderPtr responder/*,*/ DEBUG_CURLIO_PARAM(EDebugCurl debug = debug_off)) + { + AIHTTPHeaders headers; copy(url, destination, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug)); + } + /** * @brief Blocking HTTP GET that returns an LLSD map of status and body. * diff --git a/indra/llmessage/llhttpnode.cpp b/indra/llmessage/llhttpnode.cpp index 5c2f73eccb..dfff84a564 100644 --- a/indra/llmessage/llhttpnode.cpp +++ b/indra/llmessage/llhttpnode.cpp @@ -172,7 +172,7 @@ LLSD LLHTTPNode::simpleDel(const LLSD&) const // virtual void LLHTTPNode::options(ResponsePtr response, const LLSD& context) const { - //llinfos << "options context: " << context << llendl; + //LL_INFOS() << "options context: " << context << LL_ENDL; // default implementation constructs an url to the documentation. std::string host( @@ -238,10 +238,10 @@ const LLHTTPNode* LLHTTPNode::traverse( LLHTTPNode* child = node->getChild(*iter, context); if(!child) { - lldebugs << "LLHTTPNode::traverse: Couldn't find '" << *iter << "'" << llendl; + LL_DEBUGS() << "LLHTTPNode::traverse: Couldn't find '" << *iter << "'" << LL_ENDL; break; } - lldebugs << "LLHTTPNode::traverse: Found '" << *iter << "'" << llendl; + LL_DEBUGS() << "LLHTTPNode::traverse: Found '" << *iter << "'" << LL_ENDL; node = child; } @@ -275,8 +275,8 @@ void LLHTTPNode::addNode(const std::string& path, LLHTTPNode* nodeToAdd) if (iter == end) { - llwarns << "LLHTTPNode::addNode: already a node that handles " - << path << llendl; + LL_WARNS() << "LLHTTPNode::addNode: already a node that handles " + << path << LL_ENDL; return; } diff --git a/indra/llmessage/llhttpsender.cpp b/indra/llmessage/llhttpsender.cpp index c48cbc42a6..5363088d79 100644 --- a/indra/llmessage/llhttpsender.cpp +++ b/indra/llmessage/llhttpsender.cpp @@ -38,7 +38,7 @@ namespace { typedef std::map SenderMap; static SenderMap senderMap; - static LLHTTPSender* defaultSender = new LLHTTPSender(); + static LLPointer defaultSender(new LLHTTPSender()); } //virtual @@ -54,14 +54,14 @@ void LLHTTPSender::send(const LLHost& host, const std::string& name, // Default implementation inserts sender, message and sends HTTP POST std::ostringstream stream; stream << "http://" << host << "/trusted-message/" << name; - llinfos << "LLHTTPSender::send: POST to " << stream.str() << llendl; + LL_INFOS() << "LLHTTPSender::send: POST to " << stream.str() << LL_ENDL; LLHTTPClient::post(stream.str(), body, response); } //static void LLHTTPSender::setSender(const LLHost& host, LLHTTPSender* sender) { - llinfos << "LLHTTPSender::setSender " << host << llendl; + LL_INFOS() << "LLHTTPSender::setSender " << host << LL_ENDL; senderMap[host] = sender; } @@ -90,6 +90,5 @@ void LLHTTPSender::clearSender(const LLHost& host) //static void LLHTTPSender::setDefaultSender(LLHTTPSender* sender) { - delete defaultSender; defaultSender = sender; } diff --git a/indra/llmessage/llhttpsender.h b/indra/llmessage/llhttpsender.h index 88920db24d..ff8fa2f95b 100644 --- a/indra/llmessage/llhttpsender.h +++ b/indra/llmessage/llhttpsender.h @@ -32,7 +32,7 @@ class LLHost; class LLSD; -class LLHTTPSender +class LLHTTPSender : public LLThreadSafeRefCount { public: diff --git a/indra/llmessage/llinstantmessage.cpp b/indra/llmessage/llinstantmessage.cpp index d68e0c423e..d5e7e4ffe1 100644 --- a/indra/llmessage/llinstantmessage.cpp +++ b/indra/llmessage/llinstantmessage.cpp @@ -58,103 +58,6 @@ const std::string SYSTEM_FROM("Second Life"); const std::string INTERACTIVE_SYSTEM_FROM("F387446C-37C4-45f2-A438-D99CBDBB563B"); const S32 IM_TTL = 1; - -/** - * LLIMInfo - */ -LLIMInfo::LLIMInfo() : - mFromGroup(FALSE), - mParentEstateID(0), - mOffline(0), - mViewerThinksToIsOnline(false), - mIMType(IM_NOTHING_SPECIAL), - mTimeStamp(0), - mSource(IM_FROM_SIM), - mTTL(IM_TTL) -{ -} - -LLIMInfo::LLIMInfo( - const LLUUID& from_id, - BOOL from_group, - const LLUUID& to_id, - EInstantMessage im_type, - const std::string& name, - const std::string& message, - const LLUUID& id, - U32 parent_estate_id, - const LLUUID& region_id, - const LLVector3& position, - LLSD data, - U8 offline, - U32 timestamp, - EIMSource source, - S32 ttl) : - mFromID(from_id), - mFromGroup(from_group), - mToID(to_id), - mParentEstateID(0), - mRegionID(region_id), - mPosition(position), - mOffline(offline), - mViewerThinksToIsOnline(false), - mIMType(im_type), - mID(id), - mTimeStamp(timestamp), - mName(name), - mMessage(message), - mData(data), - mSource(source), - mTTL(ttl) -{ -} - -LLIMInfo::LLIMInfo(LLMessageSystem* msg, EIMSource source, S32 ttl) : - mViewerThinksToIsOnline(false), - mSource(source), - mTTL(ttl) -{ - unpackMessageBlock(msg); -} - -LLIMInfo::~LLIMInfo() -{ -} - -void LLIMInfo::packInstantMessage(LLMessageSystem* msg) const -{ - lldebugs << "LLIMInfo::packInstantMessage()" << llendl; - msg->newMessageFast(_PREHASH_ImprovedInstantMessage); - packMessageBlock(msg); -} - -void LLIMInfo::packMessageBlock(LLMessageSystem* msg) const -{ - // Construct binary bucket - std::vector bucket; - if (mData.has("binary_bucket")) - { - bucket = mData["binary_bucket"].asBinary(); - } - pack_instant_message_block( - msg, - mFromID, - mFromGroup, - LLUUID::null, - mToID, - mName, - mMessage, - mOffline, - mIMType, - mID, - mParentEstateID, - mRegionID, - mPosition, - mTimeStamp, - &bucket[0], - bucket.size()); -} - void pack_instant_message( LLMessageSystem* msg, const LLUUID& from_id, @@ -173,7 +76,7 @@ void pack_instant_message( const U8* binary_bucket, S32 binary_bucket_size) { - lldebugs << "pack_instant_message()" << llendl; + LL_DEBUGS() << "pack_instant_message()" << LL_ENDL; msg->newMessageFast(_PREHASH_ImprovedInstantMessage); pack_instant_message_block( msg, @@ -240,7 +143,7 @@ void pack_instant_message_block( if (num_written < 0 || num_written >= MTUBYTES) { num_written = MTUBYTES - 1; - llwarns << "pack_instant_message_block: message truncated: " << message << llendl; + LL_WARNS() << "pack_instant_message_block: message truncated: " << message << LL_ENDL; } bytes_left -= num_written; @@ -264,124 +167,3 @@ void pack_instant_message_block( } msg->addBinaryDataFast(_PREHASH_BinaryBucket, bb, binary_bucket_size); } - -void LLIMInfo::unpackMessageBlock(LLMessageSystem* msg) -{ - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, mFromID); - msg->getBOOLFast(_PREHASH_MessageBlock, _PREHASH_FromGroup, mFromGroup); - msg->getUUIDFast(_PREHASH_MessageBlock, _PREHASH_ToAgentID, mToID); - msg->getU32Fast(_PREHASH_MessageBlock, _PREHASH_ParentEstateID, mParentEstateID); - msg->getUUIDFast(_PREHASH_MessageBlock, _PREHASH_RegionID, mRegionID); - msg->getVector3Fast(_PREHASH_MessageBlock, _PREHASH_Position, mPosition); - msg->getU8Fast(_PREHASH_MessageBlock, _PREHASH_Offline, mOffline); - U8 dialog; - msg->getU8Fast(_PREHASH_MessageBlock, _PREHASH_Dialog, dialog); - mIMType = (EInstantMessage) dialog; - msg->getUUIDFast(_PREHASH_MessageBlock, _PREHASH_ID, mID); - msg->getU32Fast(_PREHASH_MessageBlock, _PREHASH_Timestamp, mTimeStamp); - msg->getStringFast(_PREHASH_MessageBlock, _PREHASH_FromAgentName, mName); - - msg->getStringFast(_PREHASH_MessageBlock, _PREHASH_Message, mMessage); - - S32 binary_bucket_size = llmin( - MTUBYTES, - msg->getSizeFast( - _PREHASH_MessageBlock, - _PREHASH_BinaryBucket)); - if(binary_bucket_size > 0) - { - std::vector bucket; - bucket.resize(binary_bucket_size); - - msg->getBinaryDataFast( - _PREHASH_MessageBlock, - _PREHASH_BinaryBucket, - &bucket[0], - 0, - 0, - binary_bucket_size); - mData["binary_bucket"] = bucket; - } - else - { - mData.clear(); - } -} - -LLSD im_info_to_llsd(LLPointer im_info) -{ - LLSD param_version; - param_version["version"] = 1; - LLSD param_message; - param_message["from_id"] = im_info->mFromID; - param_message["from_group"] = im_info->mFromGroup; - param_message["to_id"] = im_info->mToID; - param_message["from_name"] = im_info->mName; - param_message["message"] = im_info->mMessage; - param_message["type"] = (S32)im_info->mIMType; - param_message["id"] = im_info->mID; - param_message["timestamp"] = (S32)im_info->mTimeStamp; - param_message["offline"] = (S32)im_info->mOffline; - param_message["parent_estate_id"] = (S32)im_info->mParentEstateID; - param_message["region_id"] = im_info->mRegionID; - param_message["position"] = ll_sd_from_vector3(im_info->mPosition); - param_message["data"] = im_info->mData; - param_message["source"]= im_info->mSource; - param_message["ttl"] = im_info->mTTL; - - LLSD param_agent; - param_agent["agent_id"] = im_info->mFromID; - - LLSD params; - params["version_params"] = param_version; - params["message_params"] = param_message; - params["agent_params"] = param_agent; - - return params; -} - -LLPointer llsd_to_im_info(const LLSD& im_info_sd) -{ - LLSD param_message = im_info_sd["message_params"]; - LLSD param_agent = im_info_sd["agent_params"]; - - LLPointer im_info = new LLIMInfo( - param_message["from_id"].asUUID(), - param_message["from_group"].asBoolean(), - param_message["to_id"].asUUID(), - (EInstantMessage) param_message["type"].asInteger(), - param_message["from_name"].asString(), - param_message["message"].asString(), - param_message["id"].asUUID(), - (U32) param_message["parent_estate_id"].asInteger(), - param_message["region_id"].asUUID(), - ll_vector3_from_sd(param_message["position"]), - param_message["data"], - (U8) param_message["offline"].asInteger(), - (U32) param_message["timestamp"].asInteger(), - (EIMSource)param_message["source"].asInteger(), - param_message["ttl"].asInteger()); - - return im_info; -} - -LLPointer LLIMInfo::clone() -{ - return new LLIMInfo( - mFromID, - mFromGroup, - mToID, - mIMType, - mName, - mMessage, - mID, - mParentEstateID, - mRegionID, - mPosition, - mData, - mOffline, - mTimeStamp, - mSource, - mTTL); -} - diff --git a/indra/llmessage/llinstantmessage.h b/indra/llmessage/llinstantmessage.h index febc59c4bc..c0d9bc55ba 100644 --- a/indra/llmessage/llinstantmessage.h +++ b/indra/llmessage/llinstantmessage.h @@ -225,62 +225,6 @@ extern const std::string INTERACTIVE_SYSTEM_FROM; // Number of retry attempts on sending the im. extern const S32 IM_TTL; - -class LLIMInfo : public LLRefCount -{ -protected: - LLIMInfo(); - ~LLIMInfo(); - -public: - LLIMInfo(LLMessageSystem* msg, - EIMSource source = IM_FROM_SIM, - S32 ttl = IM_TTL); - - LLIMInfo( - const LLUUID& from_id, - BOOL from_group, - const LLUUID& to_id, - EInstantMessage im_type, - const std::string& name, - const std::string& message, - const LLUUID& id, - U32 parent_estate_id, - const LLUUID& region_id, - const LLVector3& position, - LLSD data, - U8 offline, - U32 timestamp, - EIMSource source, - S32 ttl = IM_TTL); - - void packInstantMessage(LLMessageSystem* msg) const; - void packMessageBlock(LLMessageSystem* msg) const; - void unpackMessageBlock(LLMessageSystem* msg); - LLPointer clone(); -public: - LLUUID mFromID; - BOOL mFromGroup; - LLUUID mToID; - U32 mParentEstateID; - LLUUID mRegionID; - LLVector3 mPosition; - U8 mOffline; - bool mViewerThinksToIsOnline; - EInstantMessage mIMType; - LLUUID mID; - U32 mTimeStamp; - std::string mName; - std::string mMessage; - LLSD mData; - - EIMSource mSource; - S32 mTTL; -}; - -LLPointer llsd_to_im_info(const LLSD& im_info_sd); -LLSD im_info_to_llsd(LLPointer im_info); - void pack_instant_message( LLMessageSystem* msgsystem, const LLUUID& from_id, diff --git a/indra/llmessage/lliobuffer.cpp b/indra/llmessage/lliobuffer.cpp index ed00e230ac..bbd7b8777d 100644 --- a/indra/llmessage/lliobuffer.cpp +++ b/indra/llmessage/lliobuffer.cpp @@ -109,6 +109,6 @@ LLIOPipe::EStatus LLIOBuffer::process_impl( LLPumpIO* pump) { // no-op (I think) - llwarns << "You are using an LLIOBuffer which is deprecated." << llendl; + LL_WARNS() << "You are using an LLIOBuffer which is deprecated." << LL_ENDL; return STATUS_OK; } diff --git a/indra/llmessage/lliohttpserver.cpp b/indra/llmessage/lliohttpserver.cpp index 8037b005df..7f896469f1 100644 --- a/indra/llmessage/lliohttpserver.cpp +++ b/indra/llmessage/lliohttpserver.cpp @@ -139,11 +139,11 @@ class LLHTTPPipe : public LLIOPipe LLSD mHeaders; }; -static LLFastTimer::DeclareTimer FTM_PROCESS_HTTP_PIPE("HTTP Pipe"); -static LLFastTimer::DeclareTimer FTM_PROCESS_HTTP_GET("HTTP Get"); -static LLFastTimer::DeclareTimer FTM_PROCESS_HTTP_PUT("HTTP Put"); -static LLFastTimer::DeclareTimer FTM_PROCESS_HTTP_POST("HTTP Post"); -static LLFastTimer::DeclareTimer FTM_PROCESS_HTTP_DELETE("HTTP Delete"); +static LLTrace::BlockTimerStatHandle FTM_PROCESS_HTTP_PIPE("HTTP Pipe"); +static LLTrace::BlockTimerStatHandle FTM_PROCESS_HTTP_GET("HTTP Get"); +static LLTrace::BlockTimerStatHandle FTM_PROCESS_HTTP_PUT("HTTP Put"); +static LLTrace::BlockTimerStatHandle FTM_PROCESS_HTTP_POST("HTTP Post"); +static LLTrace::BlockTimerStatHandle FTM_PROCESS_HTTP_DELETE("HTTP Delete"); LLIOPipe::EStatus LLHTTPPipe::process_impl( const LLChannelDescriptors& channels, @@ -152,9 +152,9 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl( LLSD& context, LLPumpIO* pump) { - LLFastTimer t(FTM_PROCESS_HTTP_PIPE); + LL_RECORD_BLOCK_TIME(FTM_PROCESS_HTTP_PIPE); PUMP_DEBUG; - lldebugs << "LLSDHTTPServer::process_impl" << llendl; + LL_DEBUGS() << "LLSDHTTPServer::process_impl" << LL_ENDL; // Once we have all the data, We need to read the sd on // the the in channel, and respond on the out channel @@ -181,12 +181,12 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl( std::string verb = context[CONTEXT_REQUEST][CONTEXT_VERB]; if(verb == HTTP_VERB_GET) { - LLFastTimer _(FTM_PROCESS_HTTP_GET); + LL_RECORD_BLOCK_TIME(FTM_PROCESS_HTTP_GET); mNode.get(LLHTTPNode::ResponsePtr(mResponse), context); } else if(verb == HTTP_VERB_PUT) { - LLFastTimer _(FTM_PROCESS_HTTP_PUT); + LL_RECORD_BLOCK_TIME(FTM_PROCESS_HTTP_PUT); LLSD input; if (mNode.getContentType() == LLHTTPNode::CONTENT_TYPE_LLSD) { @@ -202,7 +202,7 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl( } else if(verb == HTTP_VERB_POST) { - LLFastTimer _(FTM_PROCESS_HTTP_POST); + LL_RECORD_BLOCK_TIME(FTM_PROCESS_HTTP_POST); LLSD input; if (mNode.getContentType() == LLHTTPNode::CONTENT_TYPE_LLSD) { @@ -218,7 +218,7 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl( } else if(verb == HTTP_VERB_DELETE) { - LLFastTimer _(FTM_PROCESS_HTTP_DELETE); + LL_RECORD_BLOCK_TIME(FTM_PROCESS_HTTP_DELETE); mNode.del(LLHTTPNode::ResponsePtr(mResponse), context); } else if(verb == HTTP_VERB_OPTIONS) @@ -245,15 +245,15 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl( // Log all HTTP transactions. // TODO: Add a way to log these to their own file instead of indra.log // It is just too spammy to be in indra.log. - lldebugs << verb << " " << context[CONTEXT_REQUEST]["path"].asString() + LL_DEBUGS() << verb << " " << context[CONTEXT_REQUEST]["path"].asString() << " " << mStatusCode << " " << mStatusMessage << " " << delta - << "s" << llendl; + << "s" << LL_ENDL; // Log Internal Server Errors //if(mStatusCode == 500) //{ - // llwarns << "LLHTTPPipe::process_impl:500:Internal Server Error" - // << llendl; + // LL_WARNS() << "LLHTTPPipe::process_impl:500:Internal Server Error" + // << LL_ENDL; //} } @@ -303,8 +303,8 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl( return STATUS_DONE; } default: - llwarns << "LLHTTPPipe::process_impl: unexpected state " - << mState << llendl; + LL_WARNS() << "LLHTTPPipe::process_impl: unexpected state " + << mState << LL_ENDL; return STATUS_BREAK; } @@ -333,7 +333,7 @@ void LLHTTPPipe::Response::result(const LLSD& r) { if(! mPipe) { - llwarns << "LLHTTPPipe::Response::result: NULL pipe" << llendl; + LL_WARNS() << "LLHTTPPipe::Response::result: NULL pipe" << LL_ENDL; return; } @@ -349,7 +349,7 @@ void LLHTTPPipe::Response::extendedResult(S32 code, const std::string& body, con { if(! mPipe) { - llwarns << "LLHTTPPipe::Response::status: NULL pipe" << llendl; + LL_WARNS() << "LLHTTPPipe::Response::status: NULL pipe" << LL_ENDL; return; } @@ -365,7 +365,7 @@ void LLHTTPPipe::Response::status(S32 code, const std::string& message) { if(! mPipe) { - llwarns << "LLHTTPPipe::Response::status: NULL pipe" << llendl; + LL_WARNS() << "LLHTTPPipe::Response::status: NULL pipe" << LL_ENDL; return; } @@ -436,7 +436,7 @@ class LLHTTPResponseHeader : public LLIOPipe * LLHTTPResponseHeader */ -static LLFastTimer::DeclareTimer FTM_PROCESS_HTTP_HEADER("HTTP Header"); +static LLTrace::BlockTimerStatHandle FTM_PROCESS_HTTP_HEADER("HTTP Header"); // virtual LLIOPipe::EStatus LLHTTPResponseHeader::process_impl( @@ -446,7 +446,7 @@ LLIOPipe::EStatus LLHTTPResponseHeader::process_impl( LLSD& context, LLPumpIO* pump) { - LLFastTimer t(FTM_PROCESS_HTTP_HEADER); + LL_RECORD_BLOCK_TIME(FTM_PROCESS_HTTP_HEADER); PUMP_DEBUG; if(eos) { @@ -596,7 +596,7 @@ LLHTTPResponder::LLHTTPResponder(const LLHTTPNode& tree, const LLSD& ctx) : // virtual LLHTTPResponder::~LLHTTPResponder() { - //lldebugs << "destroying LLHTTPResponder" << llendl; + //LL_DEBUGS() << "destroying LLHTTPResponder" << LL_ENDL; } bool LLHTTPResponder::readHeaderLine( @@ -613,7 +613,7 @@ bool LLHTTPResponder::readHeaderLine( { if(len) { - lldebugs << "readLine failed - too long maybe?" << llendl; + LL_DEBUGS() << "readLine failed - too long maybe?" << LL_ENDL; markBad(channels, buffer); } return false; @@ -636,7 +636,7 @@ void LLHTTPResponder::markBad( << "\n\n" << std::flush; } -static LLFastTimer::DeclareTimer FTM_PROCESS_HTTP_RESPONDER("HTTP Responder"); +static LLTrace::BlockTimerStatHandle FTM_PROCESS_HTTP_RESPONDER("HTTP Responder"); // virtual LLIOPipe::EStatus LLHTTPResponder::process_impl( @@ -646,7 +646,7 @@ LLIOPipe::EStatus LLHTTPResponder::process_impl( LLSD& context, LLPumpIO* pump) { - LLFastTimer t(FTM_PROCESS_HTTP_RESPONDER); + LL_RECORD_BLOCK_TIME(FTM_PROCESS_HTTP_RESPONDER); PUMP_DEBUG; LLIOPipe::EStatus status = STATUS_OK; @@ -669,8 +669,8 @@ LLIOPipe::EStatus LLHTTPResponder::process_impl( { memcpy(buf, (*seg_iter).data(), (*seg_iter).size()); /*Flawfinder: ignore*/ buf[(*seg_iter).size()] = '\0'; - llinfos << (*seg_iter).getChannel() << ": " << buf - << llendl; + LL_INFOS() << (*seg_iter).getChannel() << ": " << buf + << LL_ENDL; ++seg_iter; } } @@ -696,10 +696,10 @@ LLIOPipe::EStatus LLHTTPResponder::process_impl( header >> mAbsPathAndQuery; header >> mVersion; - lldebugs << "http request: " + LL_DEBUGS() << "http request: " << mVerb << " " << mAbsPathAndQuery - << " " << mVersion << llendl; + << " " << mVersion << LL_ENDL; std::string::size_type delimiter = mAbsPathAndQuery.find('?'); @@ -729,7 +729,7 @@ LLIOPipe::EStatus LLHTTPResponder::process_impl( { read_next_line = false; parse_all = false; - lldebugs << "unknown http verb: " << mVerb << llendl; + LL_DEBUGS() << "unknown http verb: " << mVerb << LL_ENDL; markBad(channels, buffer); } } @@ -764,7 +764,7 @@ LLIOPipe::EStatus LLHTTPResponder::process_impl( if(NULL == pos_colon) { keep_parsing = false; - lldebugs << "bad header: " << buf << llendl; + LL_DEBUGS() << "bad header: " << buf << LL_ENDL; markBad(channels, buffer); break; } @@ -775,7 +775,7 @@ LLIOPipe::EStatus LLHTTPResponder::process_impl( LLStringUtil::toLower(name); if("content-length" == name) { - lldebugs << "Content-Length: " << value << llendl; + LL_DEBUGS() << "Content-Length: " << value << LL_ENDL; mContentLength = atoi(value.c_str()); } else @@ -812,8 +812,8 @@ LLIOPipe::EStatus LLHTTPResponder::process_impl( const LLHTTPNode* node = mRootNode.traverse(mPath, context); if(node) { - //llinfos << "LLHTTPResponder::process_impl found node for " - // << mAbsPathAndQuery << llendl; + //LL_INFOS() << "LLHTTPResponder::process_impl found node for " + // << mAbsPathAndQuery << LL_ENDL; // Copy everything after mLast read to the out. LLBufferArray::segment_iterator_t seg_iter; @@ -833,8 +833,8 @@ LLIOPipe::EStatus LLHTTPResponder::process_impl( { memcpy(buf, (*seg_iter).data(), (*seg_iter).size()); /*Flawfinder: ignore*/ buf[(*seg_iter).size()] = '\0'; - llinfos << (*seg_iter).getChannel() << ": " << buf - << llendl; + LL_INFOS() << (*seg_iter).getChannel() << ": " << buf + << LL_ENDL; ++seg_iter; } #endif @@ -860,7 +860,7 @@ LLIOPipe::EStatus LLHTTPResponder::process_impl( = node->getProtocolHandler(); if (protocolHandler) { - lldebugs << "HTTP context: " << context << llendl; + LL_DEBUGS() << "HTTP context: " << context << LL_ENDL; protocolHandler->build(chain, context); } else @@ -919,8 +919,8 @@ LLIOPipe::EStatus LLHTTPResponder::process_impl( } else { - llwarns << "LLHTTPResponder::process_impl didn't find a node for " - << mAbsPathAndQuery << llendl; + LL_WARNS() << "LLHTTPResponder::process_impl didn't find a node for " + << mAbsPathAndQuery << LL_ENDL; LLBufferStream str(channels, buffer.get()); mState = STATE_SHORT_CIRCUIT; str << HTTP_VERSION_STR << " 404 Not Found\r\n\r\n\n" @@ -969,7 +969,7 @@ LLHTTPNode& LLIOHTTPServer::create(LLPumpIO& pump, U16 port) LLSocket::ptr_t socket = LLSocket::create(LLSocket::STREAM_TCP, port); if(!socket) { - llerrs << "Unable to initialize socket" << llendl; + LL_ERRS() << "Unable to initialize socket" << LL_ENDL; } LLHTTPResponseFactory* factory = new LLHTTPResponseFactory; diff --git a/indra/llmessage/lliopipe.cpp b/indra/llmessage/lliopipe.cpp index c8bef05c67..281da066d6 100644 --- a/indra/llmessage/lliopipe.cpp +++ b/indra/llmessage/lliopipe.cpp @@ -72,7 +72,7 @@ LLIOPipe::LLIOPipe() : LLIOPipe::~LLIOPipe() { - //lldebugs << "destroying LLIOPipe" << llendl; + //LL_DEBUGS() << "destroying LLIOPipe" << LL_ENDL; } //virtual diff --git a/indra/llmessage/lliosocket.cpp b/indra/llmessage/lliosocket.cpp index 065f457eee..b6e92e293e 100644 --- a/indra/llmessage/lliosocket.cpp +++ b/indra/llmessage/lliosocket.cpp @@ -74,7 +74,7 @@ void ll_debug_socket(const char* msg, apr_socket_t* apr_sock) #if LL_DEBUG_SOCKET_FILE_DESCRIPTORS if(!apr_sock) { - lldebugs << "Socket -- " << (msg?msg:"") << ": no socket." << llendl; + LL_DEBUGS() << "Socket -- " << (msg?msg:"") << ": no socket." << LL_ENDL; return; } // *TODO: Why doesn't this work? @@ -82,13 +82,13 @@ void ll_debug_socket(const char* msg, apr_socket_t* apr_sock) int os_sock; if(APR_SUCCESS == apr_os_sock_get(&os_sock, apr_sock)) { - lldebugs << "Socket -- " << (msg?msg:"") << " on fd " << os_sock - << " at " << apr_sock << llendl; + LL_DEBUGS() << "Socket -- " << (msg?msg:"") << " on fd " << os_sock + << " at " << apr_sock << LL_ENDL; } else { - lldebugs << "Socket -- " << (msg?msg:"") << " no fd " - << " at " << apr_sock << llendl; + LL_DEBUGS() << "Socket -- " << (msg?msg:"") << " no fd " + << " at " << apr_sock << LL_ENDL; } #endif } @@ -146,13 +146,13 @@ LLSocket::ptr_t LLSocket::create(EType type, U16 port) rv.reset(); return rv; } - lldebugs << "Bound " << ((DATAGRAM_UDP == type) ? "udp" : "tcp") - << " socket to port: " << sa->port << llendl; + LL_DEBUGS() << "Bound " << ((DATAGRAM_UDP == type) ? "udp" : "tcp") + << " socket to port: " << sa->port << LL_ENDL; if(STREAM_TCP == type) { // If it's a stream based socket, we need to tell the OS // to keep a queue of incoming connections for ACCEPT. - lldebugs << "Setting listen state for socket." << llendl; + LL_DEBUGS() << "Setting listen state for socket." << LL_ENDL; status = apr_socket_listen( rv->mSocket, LL_DEFAULT_LISTEN_BACKLOG); @@ -183,7 +183,7 @@ LLSocket::ptr_t LLSocket::create(apr_status_t& status, LLSocket::ptr_t& listen_s return LLSocket::ptr_t(); } LLSocket::ptr_t rv(new LLSocket); - lldebugs << "accepting socket" << llendl; + LL_DEBUGS() << "accepting socket" << LL_ENDL; status = apr_socket_accept(&rv->mSocket, listen_socket->getSocket(), rv->mPool()); if (status != APR_SUCCESS) { @@ -274,10 +274,10 @@ LLIOSocketReader::LLIOSocketReader(LLSocket::ptr_t socket) : LLIOSocketReader::~LLIOSocketReader() { - //lldebugs << "Destroying LLIOSocketReader" << llendl; + //LL_DEBUGS() << "Destroying LLIOSocketReader" << LL_ENDL; } -static LLFastTimer::DeclareTimer FTM_PROCESS_SOCKET_READER("Socket Reader"); +static LLTrace::BlockTimerStatHandle FTM_PROCESS_SOCKET_READER("Socket Reader"); // virtual LLIOPipe::EStatus LLIOSocketReader::process_impl( @@ -287,7 +287,7 @@ LLIOPipe::EStatus LLIOSocketReader::process_impl( LLSD& context, LLPumpIO* pump) { - LLFastTimer t(FTM_PROCESS_SOCKET_READER); + LL_RECORD_BLOCK_TIME(FTM_PROCESS_SOCKET_READER); PUMP_DEBUG; if(!mSource) return STATUS_PRECONDITION_NOT_MET; if(!mInitialized) @@ -299,8 +299,8 @@ LLIOPipe::EStatus LLIOSocketReader::process_impl( if(pump) { PUMP_DEBUG; - lldebugs << "Initializing poll descriptor for LLIOSocketReader." - << llendl; + LL_DEBUGS() << "Initializing poll descriptor for LLIOSocketReader." + << LL_ENDL; apr_pollfd_t poll_fd; poll_fd.p = NULL; poll_fd.desc_type = APR_POLL_SOCKET; @@ -327,7 +327,7 @@ LLIOPipe::EStatus LLIOSocketReader::process_impl( status = apr_socket_recv(mSource->getSocket(), read_buf, &len); buffer->append(channels.out(), (U8*)read_buf, len); } while((APR_SUCCESS == status) && (READ_BUFFER_SIZE == len)); - lldebugs << "socket read status: " << status << llendl; + LL_DEBUGS() << "socket read status: " << status << LL_ENDL; LLIOPipe::EStatus rv = STATUS_OK; PUMP_DEBUG; @@ -374,10 +374,10 @@ LLIOSocketWriter::LLIOSocketWriter(LLSocket::ptr_t socket) : LLIOSocketWriter::~LLIOSocketWriter() { - //lldebugs << "Destroying LLIOSocketWriter" << llendl; + //LL_DEBUGS() << "Destroying LLIOSocketWriter" << LL_ENDL; } -static LLFastTimer::DeclareTimer FTM_PROCESS_SOCKET_WRITER("Socket Writer"); +static LLTrace::BlockTimerStatHandle FTM_PROCESS_SOCKET_WRITER("Socket Writer"); // virtual LLIOPipe::EStatus LLIOSocketWriter::process_impl( const LLChannelDescriptors& channels, @@ -386,7 +386,7 @@ LLIOPipe::EStatus LLIOSocketWriter::process_impl( LLSD& context, LLPumpIO* pump) { - LLFastTimer t(FTM_PROCESS_SOCKET_WRITER); + LL_RECORD_BLOCK_TIME(FTM_PROCESS_SOCKET_WRITER); PUMP_DEBUG; if(!mDestination) return STATUS_PRECONDITION_NOT_MET; if(!mInitialized) @@ -398,8 +398,8 @@ LLIOPipe::EStatus LLIOSocketWriter::process_impl( if(pump) { PUMP_DEBUG; - lldebugs << "Initializing poll descriptor for LLIOSocketWriter." - << llendl; + LL_DEBUGS() << "Initializing poll descriptor for LLIOSocketWriter." + << LL_ENDL; apr_pollfd_t poll_fd; poll_fd.p = NULL; poll_fd.desc_type = APR_POLL_SOCKET; @@ -523,7 +523,7 @@ LLIOServerSocket::LLIOServerSocket( LLIOServerSocket::~LLIOServerSocket() { - //lldebugs << "Destroying LLIOServerSocket" << llendl; + //LL_DEBUGS() << "Destroying LLIOServerSocket" << LL_ENDL; } void LLIOServerSocket::setResponseTimeout(F32 timeout_secs) @@ -531,7 +531,7 @@ void LLIOServerSocket::setResponseTimeout(F32 timeout_secs) mResponseTimeout = timeout_secs; } -static LLFastTimer::DeclareTimer FTM_PROCESS_SERVER_SOCKET("Server Socket"); +static LLTrace::BlockTimerStatHandle FTM_PROCESS_SERVER_SOCKET("Server Socket"); // virtual LLIOPipe::EStatus LLIOServerSocket::process_impl( const LLChannelDescriptors& channels, @@ -540,11 +540,11 @@ LLIOPipe::EStatus LLIOServerSocket::process_impl( LLSD& context, LLPumpIO* pump) { - LLFastTimer t(FTM_PROCESS_SERVER_SOCKET); + LL_RECORD_BLOCK_TIME(FTM_PROCESS_SERVER_SOCKET); PUMP_DEBUG; if(!pump) { - llwarns << "Need a pump for server socket." << llendl; + LL_WARNS() << "Need a pump for server socket." << LL_ENDL; return STATUS_ERROR; } if(!mInitialized) @@ -553,8 +553,8 @@ LLIOPipe::EStatus LLIOServerSocket::process_impl( // This segment sets up the pump so that we do not call // process again until we have an incoming read, aka connect() // from a remote host. - lldebugs << "Initializing poll descriptor for LLIOServerSocket." - << llendl; + LL_DEBUGS() << "Initializing poll descriptor for LLIOServerSocket." + << LL_ENDL; apr_pollfd_t poll_fd; poll_fd.p = NULL; poll_fd.desc_type = APR_POLL_SOCKET; @@ -569,7 +569,7 @@ LLIOPipe::EStatus LLIOServerSocket::process_impl( // we are initialized, and told to process, so we must have a // socket waiting for a connection. - lldebugs << "accepting socket" << llendl; + LL_DEBUGS() << "accepting socket" << LL_ENDL; PUMP_DEBUG; apr_status_t status; @@ -598,13 +598,13 @@ LLIOPipe::EStatus LLIOServerSocket::process_impl( } else { - llwarns << "Unable to build reactor to socket." << llendl; + LL_WARNS() << "Unable to build reactor to socket." << LL_ENDL; } } else { char buf[256]; - llwarns << "Unable to accept linden socket: " << apr_strerror(status, buf, sizeof(buf)) << llendl; + LL_WARNS() << "Unable to accept linden socket: " << apr_strerror(status, buf, sizeof(buf)) << LL_ENDL; } PUMP_DEBUG; @@ -643,7 +643,7 @@ LLIODataSocket::LLIODataSocket( if(ll_apr_warn_status(status)) return; if(sa->port) { - lldebugs << "Bound datagram socket to port: " << sa->port << llendl; + LL_DEBUGS() << "Bound datagram socket to port: " << sa->port << LL_ENDL; mPort = sa->port; } else diff --git a/indra/llmessage/llioutil.cpp b/indra/llmessage/llioutil.cpp index 9fd49d23d4..b8443c0600 100644 --- a/indra/llmessage/llioutil.cpp +++ b/indra/llmessage/llioutil.cpp @@ -45,7 +45,7 @@ LLIOPipe::EStatus LLIOFlush::process_impl( } -static LLFastTimer::DeclareTimer FTM_PROCESS_SLEEP("IO Sleep"); +static LLTrace::BlockTimerStatHandle FTM_PROCESS_SLEEP("IO Sleep"); /** * @class LLIOSleep */ @@ -56,7 +56,7 @@ LLIOPipe::EStatus LLIOSleep::process_impl( LLSD& context, LLPumpIO* pump) { - LLFastTimer t(FTM_PROCESS_SLEEP); + LL_RECORD_BLOCK_TIME(FTM_PROCESS_SLEEP); if(mSeconds > 0.0) { if(pump) pump->sleepChain(mSeconds); @@ -66,7 +66,7 @@ LLIOPipe::EStatus LLIOSleep::process_impl( return STATUS_DONE; } -static LLFastTimer::DeclareTimer FTM_PROCESS_ADD_CHAIN("Add Chain"); +static LLTrace::BlockTimerStatHandle FTM_PROCESS_ADD_CHAIN("Add Chain"); /** * @class LLIOAddChain */ @@ -77,7 +77,7 @@ LLIOPipe::EStatus LLIOAddChain::process_impl( LLSD& context, LLPumpIO* pump) { - LLFastTimer t(FTM_PROCESS_ADD_CHAIN); + LL_RECORD_BLOCK_TIME(FTM_PROCESS_ADD_CHAIN); pump->addChain(mChain, mTimeout); return STATUS_DONE; } diff --git a/indra/llmessage/llmail.cpp b/indra/llmessage/llmail.cpp index 08b31e9c7a..5543d961b3 100644 --- a/indra/llmessage/llmail.cpp +++ b/indra/llmessage/llmail.cpp @@ -199,16 +199,16 @@ std::string LLMail::buildSMTPTransaction( { if(!from_address || !to_address) { - llinfos << "send_mail build_smtp_transaction reject: missing to and/or" - << " from address." << llendl; + LL_INFOS() << "send_mail build_smtp_transaction reject: missing to and/or" + << " from address." << LL_ENDL; return std::string(); } if(!valid_subject_chars(subject)) { - llinfos << "send_mail build_smtp_transaction reject: bad subject header: " + LL_INFOS() << "send_mail build_smtp_transaction reject: bad subject header: " << "to=<" << to_address << ">, from=<" << from_address << ">" - << llendl; + << LL_ENDL; return std::string(); } std::ostringstream from_fmt; @@ -265,8 +265,8 @@ bool LLMail::send( { if(!from_address || !to_address) { - llinfos << "send_mail reject: missing to and/or from address." - << llendl; + LL_INFOS() << "send_mail reject: missing to and/or from address." + << LL_ENDL; return false; } @@ -278,7 +278,7 @@ bool LLMail::send( std::string good_string = "\n..\n"; while (1) { - int index = message.find(bad_string); + size_t index = message.find(bad_string); if (index == std::string::npos) break; message.replace(index, bad_string.size(), good_string); } @@ -303,26 +303,26 @@ bool LLMail::send( if(!gMailEnabled) { - llinfos << "send_mail reject: mail system is disabled: to=<" + LL_INFOS() << "send_mail reject: mail system is disabled: to=<" << to_address << ">, from=<" << from_address - << ">" << llendl; + << ">" << LL_ENDL; // Any future interface to SMTP should return this as an // error. --mark return true; } if(!gSockAddr) { - llwarns << "send_mail reject: mail system not initialized: to=<" + LL_WARNS() << "send_mail reject: mail system not initialized: to=<" << to_address << ">, from=<" << from_address - << ">" << llendl; + << ">" << LL_ENDL; return false; } if(!connect_smtp()) { - llwarns << "send_mail reject: SMTP connect failure: to=<" + LL_WARNS() << "send_mail reject: SMTP connect failure: to=<" << to_address << ">, from=<" << from_address - << ">" << llendl; + << ">" << LL_ENDL; return false; } @@ -338,27 +338,27 @@ bool LLMail::send( disconnect_smtp(); if(ll_apr_warn_status(status)) { - llwarns << "send_mail socket failure: unable to write " + LL_WARNS() << "send_mail socket failure: unable to write " << "to=<" << to_address << ">, from=<" << from_address << ">" << ", bytes=" << original_size - << ", sent=" << send_size << llendl; + << ", sent=" << send_size << LL_ENDL; return false; } if(send_size >= LL_MAX_KNOWN_GOOD_MAIL_SIZE) { - llwarns << "send_mail message has been shown to fail in testing " + LL_WARNS() << "send_mail message has been shown to fail in testing " << "when sending messages larger than " << LL_MAX_KNOWN_GOOD_MAIL_SIZE - << " bytes. The next log about success is potentially a lie." << llendl; + << " bytes. The next log about success is potentially a lie." << LL_ENDL; } - lldebugs << "send_mail success: " + LL_DEBUGS() << "send_mail success: " << "to=<" << to_address << ">, from=<" << from_address << ">" << ", bytes=" << original_size - << ", sent=" << send_size << llendl; + << ", sent=" << send_size << LL_ENDL; #if LL_LOG_ENTIRE_MAIL_MESSAGE_ON_SEND - llinfos << rfc2822_msg.str() << llendl; + LL_INFOS() << rfc2822_msg.str() << LL_ENDL; #endif return true; } diff --git a/indra/llmessage/llmessagebuilder.h b/indra/llmessage/llmessagebuilder.h index bf5be929f2..9b1d3193d8 100644 --- a/indra/llmessage/llmessagebuilder.h +++ b/indra/llmessage/llmessagebuilder.h @@ -49,7 +49,6 @@ class LLMessageBuilder virtual void newMessage(const char* name) = 0; virtual void nextBlock(const char* blockname) = 0; - virtual BOOL removeLastBlock() = 0; // TODO: babbage: remove this horror /** All add* methods expect pointers to canonical strings. */ virtual void addBinaryData( diff --git a/indra/llmessage/llmessageconfig.cpp b/indra/llmessage/llmessageconfig.cpp index 539efc65f8..f8b2c8f5a6 100644 --- a/indra/llmessage/llmessageconfig.cpp +++ b/indra/llmessage/llmessageconfig.cpp @@ -145,9 +145,9 @@ void LLMessageConfigFile::loadMessages(const LLSD& data) std::ostringstream out; LLSDXMLFormatter *formatter = new LLSDXMLFormatter; formatter->format(mMessages, out); - llinfos << "loading ... " << out.str() + LL_INFOS() << "loading ... " << out.str() << " LLMessageConfigFile::loadMessages loaded " - << mMessages.size() << " messages" << llendl; + << mMessages.size() << " messages" << LL_ENDL; #endif } @@ -182,7 +182,7 @@ void LLMessageConfigFile::loadMessageBans(const LLSD& data) bool LLMessageConfigFile::isCapBanned(const std::string& cap_name) const { - lldebugs << "mCapBans is " << LLSDNotationStreamer(mCapBans) << llendl; + LL_DEBUGS() << "mCapBans is " << LLSDNotationStreamer(mCapBans) << LL_ENDL; return mCapBans[cap_name]; } @@ -268,7 +268,7 @@ bool LLMessageConfig::isValidMessage(const std::string& msg_name) { if (sServerName.empty()) { - llerrs << "LLMessageConfig::initClass() not called" << llendl; + LL_ERRS() << "LLMessageConfig::initClass() not called" << LL_ENDL; } LLMessageConfigFile& file = LLMessageConfigFile::instance(); return file.mMessages.has(msg_name); @@ -294,8 +294,8 @@ LLSD LLMessageConfig::getConfigForMessage(const std::string& msg_name) { if (sServerName.empty()) { - llerrs << "LLMessageConfig::isMessageTrusted(name) before" - << " LLMessageConfig::initClass()" << llendl; + LL_ERRS() << "LLMessageConfig::isMessageTrusted(name) before" + << " LLMessageConfig::initClass()" << LL_ENDL; } LLMessageConfigFile& file = LLMessageConfigFile::instance(); // LLSD for the CamelCase message name diff --git a/indra/llmessage/llmessagetemplate.cpp b/indra/llmessage/llmessagetemplate.cpp index d64123ad62..49ee1294b7 100644 --- a/indra/llmessage/llmessagetemplate.cpp +++ b/indra/llmessage/llmessagetemplate.cpp @@ -30,8 +30,12 @@ #include "message.h" +U32 sMsgDataAllocSize = 0; +U32 sMsgdataAllocCount = 0; + void LLMsgVarData::addData(const void *data, S32 size, EMsgVariableType type, S32 data_size) { + sMsgDataAllocSize += size; mSize = size; mDataSize = data_size; if ( (type != MVT_VARIABLE) && (type != MVT_FIXED) @@ -39,12 +43,13 @@ void LLMsgVarData::addData(const void *data, S32 size, EMsgVariableType type, S3 { if (mType != type) { - llwarns << "Type mismatch in LLMsgVarData::addData for " << mName - << llendl; + LL_WARNS() << "Type mismatch in LLMsgVarData::addData for " << mName + << LL_ENDL; } } if(size) { + ++sMsgdataAllocCount; delete[] mData; // Delete it if it already exists mData = new U8[size]; htonmemcpy(mData, data, mType, size); @@ -120,8 +125,8 @@ std::ostream& operator<<(std::ostream& s, LLMessageBlock &msg) for (LLMessageBlock::message_variable_map_t::iterator iter = msg.mMemberVariables.begin(); iter != msg.mMemberVariables.end(); iter++) { - LLMessageVariable& ci = *(*iter); - s << ci; + LLMessageVariable* ci = msg.mMemberVariables.toValue(iter); + s << *ci; } return s; @@ -164,7 +169,7 @@ std::ostream& operator<<(std::ostream& s, LLMessageTemplate &msg) for (LLMessageTemplate::message_block_map_t::iterator iter = msg.mMemberBlocks.begin(); iter != msg.mMemberBlocks.end(); iter++) { - LLMessageBlock* ci = *iter; + LLMessageBlock* ci = msg.mMemberBlocks.toValue(iter); s << *ci; } @@ -181,12 +186,12 @@ void LLMessageTemplate::banUdp() }; if (mDeprecation != MD_DEPRECATED) { - llinfos << "Setting " << mName << " to UDPBlackListed was " << deprecation[mDeprecation] << llendl; + LL_INFOS() << "Setting " << mName << " to UDPBlackListed was " << deprecation[mDeprecation] << LL_ENDL; mDeprecation = MD_UDPBLACKLISTED; } else { - llinfos << mName << " is already more deprecated than UDPBlackListed" << llendl; + LL_INFOS() << mName << " is already more deprecated than UDPBlackListed" << LL_ENDL; } } diff --git a/indra/llmessage/llmessagetemplate.h b/indra/llmessage/llmessagetemplate.h index a91a8f7757..7cc6d55446 100644 --- a/indra/llmessage/llmessagetemplate.h +++ b/indra/llmessage/llmessagetemplate.h @@ -27,11 +27,15 @@ #ifndef LL_LLMESSAGETEMPLATE_H #define LL_LLMESSAGETEMPLATE_H -#include "lldarray.h" #include "message.h" // TODO: babbage: Remove... #include "llstat.h" #include "llstl.h" +#include "llindexedvector.h" +#include + +extern U32 sMsgDataAllocSize; +extern U32 sMsgdataAllocCount; class LLMsgVarData { public: @@ -86,7 +90,7 @@ class LLMsgBlkData for (msg_var_data_map_t::iterator iter = mMemberVarData.begin(); iter != mMemberVarData.end(); iter++) { - iter->deleteData(); + mMemberVarData.toValue(iter).deleteData(); } } @@ -103,7 +107,7 @@ class LLMsgBlkData } S32 mBlockNumber; - typedef LLDynamicArrayIndexed msg_var_data_map_t; + typedef LLIndexedVector msg_var_data_map_t; msg_var_data_map_t mMemberVarData; char *mName; S32 mTotalSize; @@ -119,6 +123,7 @@ class LLMsgData ~LLMsgData() { for_each(mMemberBlocks.begin(), mMemberBlocks.end(), DeletePairedPointer()); + mMemberBlocks.clear(); } void addBlock(LLMsgBlkData *blockp) @@ -186,21 +191,21 @@ class LLMessageBlock ~LLMessageBlock() { - for_each(mMemberVariables.begin(), mMemberVariables.end(), DeletePointer()); + for_each(mMemberVariables.begin(), mMemberVariables.end(), message_variable_map_t::DeletePointer()); } void addVariable(char *name, const EMsgVariableType type, const S32 size) { - LLMessageVariable** varp = &mMemberVariables[name]; - if (*varp != NULL) + LLMessageVariable*& varp = mMemberVariables[name]; + if (varp != NULL) { - llerrs << name << " has already been used as a variable name!" << llendl; + LL_ERRS() << name << " has already been used as a variable name!" << LL_ENDL; } - *varp = new LLMessageVariable(name, type, size); - if (((*varp)->getType() != MVT_VARIABLE) - &&(mTotalSize != -1)) + varp = new LLMessageVariable(name, type, size); + if ((varp->getType() != MVT_VARIABLE) + && (mTotalSize != -1)) { - mTotalSize += (*varp)->getSize(); + mTotalSize += varp->getSize(); } else { @@ -221,12 +226,12 @@ class LLMessageBlock const LLMessageVariable* getVariable(char* name) const { message_variable_map_t::const_iterator iter = mMemberVariables.find(name); - return iter != mMemberVariables.end()? *iter : NULL; + return iter != mMemberVariables.end() ? mMemberVariables.toValue(iter) : NULL; } friend std::ostream& operator<<(std::ostream& s, LLMessageBlock &msg); - typedef LLDynamicArrayIndexed message_variable_map_t; + typedef LLIndexedVector message_variable_map_t; message_variable_map_t mMemberVariables; char *mName; EMsgBlockType mType; @@ -293,18 +298,18 @@ class LLMessageTemplate ~LLMessageTemplate() { - for_each(mMemberBlocks.begin(), mMemberBlocks.end(), DeletePointer()); + for_each(mMemberBlocks.begin(), mMemberBlocks.end(), message_block_map_t::DeletePointer()); } void addBlock(LLMessageBlock *blockp) { - LLMessageBlock** member_blockp = &mMemberBlocks[blockp->mName]; - if (*member_blockp != NULL) + LLMessageBlock*& member_blockp = mMemberBlocks[blockp->mName]; + if (member_blockp != NULL) { - llerrs << "Block " << blockp->mName - << "has already been used as a block name!" << llendl; + LL_ERRS() << "Block " << blockp->mName + << "has already been used as a block name!" << LL_ENDL; } - *member_blockp = blockp; + member_blockp = blockp; if ( (mTotalSize != -1) &&(blockp->mTotalSize != -1) &&( (blockp->mType == MBT_SINGLE) @@ -387,11 +392,11 @@ class LLMessageTemplate const LLMessageBlock* getBlock(char* name) const { message_block_map_t::const_iterator iter = mMemberBlocks.find(name); - return iter != mMemberBlocks.end()? *iter : NULL; + return iter != mMemberBlocks.end()? mMemberBlocks.toValue(iter): NULL; } public: - typedef LLDynamicArrayIndexed message_block_map_t; + typedef LLIndexedVector message_block_map_t; message_block_map_t mMemberBlocks; char *mName; EMsgFrequency mFrequency; diff --git a/indra/llmessage/llmessagetemplateparser.cpp b/indra/llmessage/llmessagetemplateparser.cpp index b0f19df47c..1f7c09dbe5 100644 --- a/indra/llmessage/llmessagetemplateparser.cpp +++ b/indra/llmessage/llmessagetemplateparser.cpp @@ -165,13 +165,13 @@ BOOL b_check_token(const char *token, const char *regexp) if (current_checker == -1) { - llerrs << "Invalid regular expression value!" << llendl; + LL_ERRS() << "Invalid regular expression value!" << LL_ENDL; return FALSE; } if (current_checker == 9999) { - llerrs << "Regular expression can't start with *!" << llendl; + LL_ERRS() << "Regular expression can't start with *!" << LL_ENDL; return FALSE; } @@ -179,7 +179,7 @@ BOOL b_check_token(const char *token, const char *regexp) { if (current_checker == -1) { - llerrs << "Input exceeds regular expression!\nDid you forget a *?" << llendl; + LL_ERRS() << "Input exceeds regular expression!\nDid you forget a *?" << LL_ENDL; return FALSE; } @@ -204,7 +204,7 @@ BOOL b_variable_ok(const char *token) { if (!b_check_token(token, "fv*")) { - llwarns << "Token '" << token << "' isn't a variable!" << llendl; + LL_WARNS() << "Token '" << token << "' isn't a variable!" << LL_ENDL; return FALSE; } return TRUE; @@ -215,7 +215,7 @@ BOOL b_integer_ok(const char *token) { if (!b_check_token(token, "sd*")) { - llwarns << "Token isn't an integer!" << llendl; + LL_WARNS() << "Token isn't an integer!" << LL_ENDL; return FALSE; } return TRUE; @@ -226,7 +226,7 @@ BOOL b_positive_integer_ok(const char *token) { if (!b_check_token(token, "d*")) { - llwarns << "Token isn't an integer!" << llendl; + LL_WARNS() << "Token isn't an integer!" << LL_ENDL; return FALSE; } return TRUE; @@ -359,13 +359,13 @@ void LLTemplateTokenizer::error(std::string message) const { if(atEOF()) { - llerrs << "Unexpected end of file: " << message << llendl; + LL_ERRS() << "Unexpected end of file: " << message << LL_ENDL; } else { - llerrs << "Problem parsing message template at line " + LL_ERRS() << "Problem parsing message template at line " << line() << ", with token '" << get() << "' : " - << message << llendl; + << message << LL_ENDL; } } @@ -383,12 +383,12 @@ LLTemplateParser::LLTemplateParser(LLTemplateTokenizer & tokens): std::string vers_string = tokens.next(); mVersion = (F32)atof(vers_string.c_str()); - llinfos << "### Message template version " << mVersion << " ###" << llendl; + LL_INFOS() << "### Message template version " << mVersion << " ###" << LL_ENDL; } else { - llerrs << "Version must be first in the message template, found " - << tokens.next() << llendl; + LL_ERRS() << "Version must be first in the message template, found " + << tokens.next() << LL_ENDL; } while(LLMessageTemplate * templatep = parseMessage(tokens)) @@ -405,8 +405,8 @@ LLTemplateParser::LLTemplateParser(LLTemplateTokenizer & tokens): if(!tokens.wantEOF()) { - llerrs << "Expected end of template or a message, instead found: " - << tokens.next() << " at " << tokens.line() << llendl; + LL_ERRS() << "Expected end of template or a message, instead found: " + << tokens.next() << " at " << tokens.line() << LL_ENDL; } } @@ -441,7 +441,7 @@ LLMessageTemplate * LLTemplateParser::parseMessage(LLTemplateTokenizer & tokens) // is name a legit C variable name if (!b_variable_ok(template_name.c_str())) { - llerrs << "Not legit variable name: " << template_name << " at " << tokens.line() << llendl; + LL_ERRS() << "Not legit variable name: " << template_name << " at " << tokens.line() << LL_ENDL; } // ok, now get Frequency ("High", "Medium", or "Low") @@ -461,7 +461,7 @@ LLMessageTemplate * LLTemplateParser::parseMessage(LLTemplateTokenizer & tokens) } else { - llerrs << "Expected frequency, got " << freq_string << " at " << tokens.line() << llendl; + LL_ERRS() << "Expected frequency, got " << freq_string << " at " << tokens.line() << LL_ENDL; } // TODO more explicit checking here pls @@ -477,7 +477,7 @@ LLMessageTemplate * LLTemplateParser::parseMessage(LLTemplateTokenizer & tokens) message_number = (255 << 24) | (255 << 16) | message_number; break; default: - llerrs << "Unknown frequency enum: " << frequency << llendl; + LL_ERRS() << "Unknown frequency enum: " << frequency << LL_ENDL; } templatep = new LLMessageTemplate( @@ -497,7 +497,7 @@ LLMessageTemplate * LLTemplateParser::parseMessage(LLTemplateTokenizer & tokens) } else { - llerrs << "Bad trust " << trust << " at " << tokens.line() << llendl; + LL_ERRS() << "Bad trust " << trust << " at " << tokens.line() << LL_ENDL; } // get encoding @@ -512,7 +512,7 @@ LLMessageTemplate * LLTemplateParser::parseMessage(LLTemplateTokenizer & tokens) } else { - llerrs << "Bad encoding " << encoding << " at " << tokens.line() << llendl; + LL_ERRS() << "Bad encoding " << encoding << " at " << tokens.line() << LL_ENDL; } // get deprecation @@ -544,8 +544,8 @@ LLMessageTemplate * LLTemplateParser::parseMessage(LLTemplateTokenizer & tokens) if(!tokens.want("}")) { - llerrs << "Expecting closing } for message " << template_name - << " at " << tokens.line() << llendl; + LL_ERRS() << "Expecting closing } for message " << template_name + << " at " << tokens.line() << LL_ENDL; } return templatep; } @@ -566,8 +566,8 @@ LLMessageBlock * LLTemplateParser::parseBlock(LLTemplateTokenizer & tokens) // is name a legit C variable name if (!b_variable_ok(block_name.c_str())) { - llerrs << "not a legal block name: " << block_name - << " at " << tokens.line() << llendl; + LL_ERRS() << "not a legal block name: " << block_name + << " at " << tokens.line() << LL_ENDL; } // now, block type ("Single", "Multiple", or "Variable") @@ -586,8 +586,8 @@ LLMessageBlock * LLTemplateParser::parseBlock(LLTemplateTokenizer & tokens) // is it a legal integer if (!b_positive_integer_ok(repeats.c_str())) { - llerrs << "not a legal integer for block multiple count: " - << repeats << " at " << tokens.line() << llendl; + LL_ERRS() << "not a legal integer for block multiple count: " + << repeats << " at " << tokens.line() << LL_ENDL; } // ok, we can create a block @@ -602,8 +602,8 @@ LLMessageBlock * LLTemplateParser::parseBlock(LLTemplateTokenizer & tokens) } else { - llerrs << "bad block type: " << block_type - << " at " << tokens.line() << llendl; + LL_ERRS() << "bad block type: " << block_type + << " at " << tokens.line() << LL_ENDL; } @@ -617,8 +617,8 @@ LLMessageBlock * LLTemplateParser::parseBlock(LLTemplateTokenizer & tokens) if(!tokens.want("}")) { - llerrs << "Expecting closing } for block " << block_name - << " at " << tokens.line() << llendl; + LL_ERRS() << "Expecting closing } for block " << block_name + << " at " << tokens.line() << LL_ENDL; } return blockp; @@ -637,8 +637,8 @@ LLMessageVariable * LLTemplateParser::parseVariable(LLTemplateTokenizer & tokens if (!b_variable_ok(var_name.c_str())) { - llerrs << "Not a legit variable name: " << var_name - << " at " << tokens.line() << llendl; + LL_ERRS() << "Not a legit variable name: " << var_name + << " at " << tokens.line() << LL_ENDL; } std::string var_type = tokens.next(); @@ -721,8 +721,8 @@ LLMessageVariable * LLTemplateParser::parseVariable(LLTemplateTokenizer & tokens if (!b_positive_integer_ok(variable_size.c_str())) { - llerrs << "not a legal integer variable size: " << variable_size - << " at " << tokens.line() << llendl; + LL_ERRS() << "not a legal integer variable size: " << variable_size + << " at " << tokens.line() << LL_ENDL; } EMsgVariableType type_enum; @@ -737,8 +737,8 @@ LLMessageVariable * LLTemplateParser::parseVariable(LLTemplateTokenizer & tokens else { type_enum = MVT_FIXED; // removes a warning - llerrs << "bad variable type: " << var_type - << " at " << tokens.line() << llendl; + LL_ERRS() << "bad variable type: " << var_type + << " at " << tokens.line() << LL_ENDL; } varp = new LLMessageVariable( @@ -748,14 +748,14 @@ LLMessageVariable * LLTemplateParser::parseVariable(LLTemplateTokenizer & tokens } else { - llerrs << "bad variable type:" << var_type - << " at " << tokens.line() << llendl; + LL_ERRS() << "bad variable type:" << var_type + << " at " << tokens.line() << LL_ENDL; } if(!tokens.want("}")) { - llerrs << "Expecting closing } for variable " << var_name - << " at " << tokens.line() << llendl; + LL_ERRS() << "Expecting closing } for variable " << var_name + << " at " << tokens.line() << LL_ENDL; } return varp; } diff --git a/indra/llmessage/llmessagethrottle.cpp b/indra/llmessage/llmessagethrottle.cpp index 579d6d7187..20d828f95e 100644 --- a/indra/llmessage/llmessagethrottle.cpp +++ b/indra/llmessage/llmessagethrottle.cpp @@ -26,24 +26,13 @@ #include "linden_common.h" -#include "llhash.h" - #include "llmessagethrottle.h" #include "llframetimer.h" -// This is used for the stl search_n function. -#if _MSC_VER >= 1500 // VC9 has a bug in search_n -struct eq_message_throttle_entry : public std::binary_function< LLMessageThrottleEntry, LLMessageThrottleEntry, bool > -{ - bool operator()(const LLMessageThrottleEntry& a, const LLMessageThrottleEntry& b) const - { - return a.getHash() == b.getHash(); - } -}; -#else +#include + bool eq_message_throttle_entry(LLMessageThrottleEntry a, LLMessageThrottleEntry b) { return a.getHash() == b.getHash(); } -#endif const U64 SEC_TO_USEC = 1000000; @@ -113,19 +102,14 @@ BOOL LLMessageThrottle::addViewerAlert(const LLUUID& to, const std::string& mesg std::ostringstream full_mesg; full_mesg << to << mesg; - // Create an entry for this message. - size_t hash = llhash(full_mesg.str().c_str()); + // Create an entry for this message.o.o + size_t hash = boost::hash()(full_mesg.str()); LLMessageThrottleEntry entry(hash, LLFrameTimer::getTotalTime()); // Check if this message is already in the list. -#if _MSC_VER >= 1500 // VC9 has a bug in search_n - // SJB: This *should* work but has not been tested yet *TODO: Test! - message_list_iterator_t found = std::find_if(message_list->begin(), message_list->end(), - std::bind2nd(eq_message_throttle_entry(), entry)); -#else message_list_iterator_t found = std::search_n(message_list->begin(), message_list->end(), 1, entry, eq_message_throttle_entry); -#endif + if (found == message_list->end()) { // This message was not found. Add it to the list. @@ -148,18 +132,12 @@ BOOL LLMessageThrottle::addAgentAlert(const LLUUID& agent, const LLUUID& task, c full_mesg << agent << task << mesg; // Create an entry for this message. - size_t hash = llhash(full_mesg.str().c_str()); + size_t hash = boost::hash()(full_mesg.str()); LLMessageThrottleEntry entry(hash, LLFrameTimer::getTotalTime()); // Check if this message is already in the list. -#if _MSC_VER >= 1500 // VC9 has a bug in search_n - // SJB: This *should* work but has not been tested yet *TODO: Test! - message_list_iterator_t found = std::find_if(message_list->begin(), message_list->end(), - std::bind2nd(eq_message_throttle_entry(), entry)); -#else message_list_iterator_t found = std::search_n(message_list->begin(), message_list->end(), 1, entry, eq_message_throttle_entry); -#endif if (found == message_list->end()) { diff --git a/indra/llmessage/llmime.cpp b/indra/llmessage/llmime.cpp deleted file mode 100644 index 9d9c4ebd68..0000000000 --- a/indra/llmessage/llmime.cpp +++ /dev/null @@ -1,629 +0,0 @@ -/** - * @file llmime.cpp - * @author Phoenix - * @date 2006-12-20 - * @brief Implementation of mime tools. - * - * $LicenseInfo:firstyear=2006&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" -#include "llmime.h" - -#include - -#include "llmemorystream.h" - -/** - * Useful constants. - */ -// Headers specified in rfc-2045 will be canonicalized below. -static const std::string CONTENT_LENGTH("Content-Length"); -static const std::string CONTENT_TYPE("Content-Type"); -static const S32 KNOWN_HEADER_COUNT = 6; -static const std::string KNOWN_HEADER[KNOWN_HEADER_COUNT] = -{ - CONTENT_LENGTH, - CONTENT_TYPE, - std::string("MIME-Version"), - std::string("Content-Transfer-Encoding"), - std::string("Content-ID"), - std::string("Content-Description"), -}; - -// parser helpers -static const std::string MULTIPART("multipart"); -static const std::string BOUNDARY("boundary"); -static const std::string END_OF_CONTENT_PARAMETER("\r\n ;\t"); -static const std::string SEPARATOR_PREFIX("--"); -//static const std::string SEPARATOR_SUFFIX("\r\n"); - -/* -Content-Type: multipart/mixed; boundary="segment" -Content-Length: 24832 - ---segment -Content-Type: image/j2c -Content-Length: 23715 - - - ---segment -Content-Type: text/xml; charset=UTF-8 - - -EOF - -*/ - -/** - * LLMimeIndex - */ - -/** - * @class LLMimeIndex::Impl - * @brief Implementation details of the mime index class. - * @see LLMimeIndex - */ -class LLMimeIndex::Impl -{ -public: - Impl() : mOffset(-1), mUseCount(1) - {} - Impl(LLSD headers, S32 offset) : - mHeaders(headers), mOffset(offset), mUseCount(1) - {} -public: - LLSD mHeaders; - S32 mOffset; - S32 mUseCount; - - typedef std::vector sub_part_t; - sub_part_t mAttachments; -}; - -LLSD LLMimeIndex::headers() const -{ - return mImpl->mHeaders; -} - -S32 LLMimeIndex::offset() const -{ - return mImpl->mOffset; -} - -S32 LLMimeIndex::contentLength() const -{ - // Find the content length in the headers. - S32 length = -1; - LLSD content_length = mImpl->mHeaders[CONTENT_LENGTH]; - if(content_length.isDefined()) - { - length = content_length.asInteger(); - } - return length; -} - -std::string LLMimeIndex::contentType() const -{ - std::string type; - LLSD content_type = mImpl->mHeaders[CONTENT_TYPE]; - if(content_type.isDefined()) - { - type = content_type.asString(); - } - return type; -} - -bool LLMimeIndex::isMultipart() const -{ - bool multipart = false; - LLSD content_type = mImpl->mHeaders[CONTENT_TYPE]; - if(content_type.isDefined()) - { - std::string type = content_type.asString(); - int comp = type.compare(0, MULTIPART.size(), MULTIPART); - if(0 == comp) - { - multipart = true; - } - } - return multipart; -} - -S32 LLMimeIndex::subPartCount() const -{ - return mImpl->mAttachments.size(); -} - -LLMimeIndex LLMimeIndex::subPart(S32 index) const -{ - LLMimeIndex part; - if((index >= 0) && (index < (S32)mImpl->mAttachments.size())) - { - part = mImpl->mAttachments[index]; - } - return part; -} - -LLMimeIndex::LLMimeIndex() : mImpl(new LLMimeIndex::Impl) -{ -} - -LLMimeIndex::LLMimeIndex(LLSD headers, S32 content_offset) : - mImpl(new LLMimeIndex::Impl(headers, content_offset)) -{ -} - -LLMimeIndex::LLMimeIndex(const LLMimeIndex& mime) : - mImpl(mime.mImpl) -{ - ++mImpl->mUseCount; -} - -LLMimeIndex::~LLMimeIndex() -{ - if(0 == --mImpl->mUseCount) - { - delete mImpl; - } -} - -LLMimeIndex& LLMimeIndex::operator=(const LLMimeIndex& mime) -{ - // Increment use count first so that we handle self assignment - // automatically. - ++mime.mImpl->mUseCount; - if(0 == --mImpl->mUseCount) - { - delete mImpl; - } - mImpl = mime.mImpl; - return *this; -} - -bool LLMimeIndex::attachSubPart(LLMimeIndex sub_part) -{ - // *FIX: Should we check for multi-part? - if(mImpl->mAttachments.size() < S32_MAX) - { - mImpl->mAttachments.push_back(sub_part); - return true; - } - return false; -} - -/** - * LLMimeParser - */ -/** - * @class LLMimeParser::Impl - * @brief Implementation details of the mime parser class. - * @see LLMimeParser - */ -class LLMimeParser::Impl -{ -public: - // @brief Constructor. - Impl(); - - // @brief Reset this for a new parse. - void reset(); - - /** - * @brief Parse a mime entity to find the index information. - * - * This method will scan the istr until a single complete mime - * entity is read, an EOF, or limit bytes have been scanned. The - * istr will be modified by this parsing, so pass in a temporary - * stream or rewind/reset the stream after this call. - * @param istr An istream which contains a mime entity. - * @param limit The maximum number of bytes to scan. - * @param separator The multipart separator if it is known. - * @param is_subpart Set true if parsing a multipart sub part. - * @param index[out] The parsed output. - * @return Returns true if an index was parsed and no errors occurred. - */ - bool parseIndex( - std::istream& istr, - S32 limit, - const std::string& separator, - bool is_subpart, - LLMimeIndex& index); - -protected: - /** - * @brief parse the headers. - * - * At the end of a successful parse, mScanCount will be at the - * start of the content. - * @param istr The input stream. - * @param limit maximum number of bytes to process - * @param headers[out] A map of the headers found. - * @return Returns true if the parse was successful. - */ - bool parseHeaders(std::istream& istr, S32 limit, LLSD& headers); - - /** - * @brief Figure out the separator string from a content type header. - * - * @param multipart_content_type The content type value from the headers. - * @return Returns the separator string. - */ - std::string findSeparator(std::string multipart_content_type); - - /** - * @brief Scan through istr past the separator. - * - * @param istr The input stream. - * @param limit Maximum number of bytes to scan. - * @param separator The multipart separator. - */ - void scanPastSeparator( - std::istream& istr, - S32 limit, - const std::string& separator); - - /** - * @brief Scan through istr past the content of the current mime part. - * - * @param istr The input stream. - * @param limit Maximum number of bytes to scan. - * @param headers The headers for this mime part. - * @param separator The multipart separator if known. - */ - void scanPastContent( - std::istream& istr, - S32 limit, - LLSD headers, - const std::string separator); - - /** - * @brief Eat CRLF. - * - * This method has no concept of the limit, so ensure you have at - * least 2 characters left to eat before hitting the limit. This - * method will increment mScanCount as it goes. - * @param istr The input stream. - * @return Returns true if CRLF was found and consumed off of istr. - */ - bool eatCRLF(std::istream& istr); - - // @brief Returns true if parsing should continue. - bool continueParse() const { return (!mError && mContinue); } - - // @brief anonymous enumeration for parse buffer size. - enum - { - LINE_BUFFER_LENGTH = 1024 - }; - -protected: - S32 mScanCount; - bool mContinue; - bool mError; - char mBuffer[LINE_BUFFER_LENGTH]; -}; - -LLMimeParser::Impl::Impl() -{ - reset(); -} - -void LLMimeParser::Impl::reset() -{ - mScanCount = 0; - mContinue = true; - mError = false; - mBuffer[0] = '\0'; -} - -bool LLMimeParser::Impl::parseIndex( - std::istream& istr, - S32 limit, - const std::string& separator, - bool is_subpart, - LLMimeIndex& index) -{ - LLSD headers; - bool parsed_something = false; - if(parseHeaders(istr, limit, headers)) - { - parsed_something = true; - LLMimeIndex mime(headers, mScanCount); - index = mime; - if(index.isMultipart()) - { - // Figure out the separator, scan past it, and recurse. - std::string ct = headers[CONTENT_TYPE].asString(); - std::string sep = findSeparator(ct); - scanPastSeparator(istr, limit, sep); - while(continueParse() && parseIndex(istr, limit, sep, true, mime)) - { - index.attachSubPart(mime); - } - } - else - { - // Scan to the end of content. - scanPastContent(istr, limit, headers, separator); - if(is_subpart) - { - scanPastSeparator(istr, limit, separator); - } - } - } - if(mError) return false; - return parsed_something; -} - -bool LLMimeParser::Impl::parseHeaders( - std::istream& istr, - S32 limit, - LLSD& headers) -{ - while(continueParse()) - { - // Get the next line. - // We subtract 1 from the limit so that we make sure - // not to read past limit when we get() the newline. - S32 max_get = llmin((S32)LINE_BUFFER_LENGTH, limit - mScanCount - 1); - istr.getline(mBuffer, max_get, '\r'); - mScanCount += (S32)istr.gcount(); - int c = istr.get(); - if(EOF == c) - { - mContinue = false; - return false; - } - ++mScanCount; - if(c != '\n') - { - mError = true; - return false; - } - if(mScanCount >= limit) - { - mContinue = false; - } - - // Check if that's the end of headers. - if('\0' == mBuffer[0]) - { - break; - } - - // Split out the name and value. - // *NOTE: The use of strchr() here is safe since mBuffer is - // guaranteed to be NULL terminated from the call to getline() - // above. - char* colon = strchr(mBuffer, ':'); - if(!colon) - { - mError = true; - return false; - } - - // Cononicalize the name part, and store the name: value in - // the headers structure. We do this by iterating through - // 'known' headers and replacing the value found with the - // correct one. - // *NOTE: Not so efficient, but iterating through a small - // subset should not be too much of an issue. - std::string name(mBuffer, colon++ - mBuffer); - while(isspace(*colon)) ++colon; - std::string value(colon); - for(S32 ii = 0; ii < KNOWN_HEADER_COUNT; ++ii) - { - if(0 == LLStringUtil::compareInsensitive(name, KNOWN_HEADER[ii])) - { - name = KNOWN_HEADER[ii]; - break; - } - } - headers[name] = value; - } - if(headers.isUndefined()) return false; - return true; -} - -std::string LLMimeParser::Impl::findSeparator(std::string header) -{ - // 01234567890 - //Content-Type: multipart/mixed; boundary="segment" - std::string separator; - std::string::size_type pos = header.find(BOUNDARY); - if(std::string::npos == pos) return separator; - pos += BOUNDARY.size() + 1; - std::string::size_type end; - if(header[pos] == '"') - { - // the boundary is quoted, find the end from pos, and take the - // substring. - end = header.find('"', ++pos); - if(std::string::npos == end) - { - // poorly formed boundary. - mError = true; - } - } - else - { - // otherwise, it's every character until a whitespace, end of - // line, or another parameter begins. - end = header.find_first_of(END_OF_CONTENT_PARAMETER, pos); - if(std::string::npos == end) - { - // it goes to the end of the string. - end = header.size(); - } - } - if(!mError) separator = header.substr(pos, end - pos); - return separator; -} - -void LLMimeParser::Impl::scanPastSeparator( - std::istream& istr, - S32 limit, - const std::string& sep) -{ - std::ostringstream ostr; - ostr << SEPARATOR_PREFIX << sep; - std::string separator = ostr.str(); - bool found_separator = false; - while(!found_separator && continueParse()) - { - // Subtract 1 from the limit so that we make sure not to read - // past limit when we get() the newline. - S32 max_get = llmin((S32)LINE_BUFFER_LENGTH, limit - mScanCount - 1); - istr.getline(mBuffer, max_get, '\r'); - mScanCount += (S32)istr.gcount(); - if(istr.gcount() >= LINE_BUFFER_LENGTH - 1) - { - // that's way too long to be a separator, so ignore it. - continue; - } - int c = istr.get(); - if(EOF == c) - { - mContinue = false; - return; - } - ++mScanCount; - if(c != '\n') - { - mError = true; - return; - } - if(mScanCount >= limit) - { - mContinue = false; - } - if(0 == LLStringUtil::compareStrings(std::string(mBuffer), separator)) - { - found_separator = true; - } - } -} - -void LLMimeParser::Impl::scanPastContent( - std::istream& istr, - S32 limit, - LLSD headers, - const std::string separator) -{ - if(headers.has(CONTENT_LENGTH)) - { - S32 content_length = headers[CONTENT_LENGTH].asInteger(); - // Subtract 2 here for the \r\n after the content. - S32 max_skip = llmin(content_length, limit - mScanCount - 2); - istr.ignore(max_skip); - mScanCount += max_skip; - - // *NOTE: Check for hitting the limit and eof here before - // checking for the trailing EOF, because our mime parser has - // to gracefully handle incomplete mime entites. - if((mScanCount >= limit) || istr.eof()) - { - mContinue = false; - } - else if(!eatCRLF(istr)) - { - mError = true; - return; - } - } -} - -bool LLMimeParser::Impl::eatCRLF(std::istream& istr) -{ - int c = istr.get(); - ++mScanCount; - if(c != '\r') - { - return false; - } - c = istr.get(); - ++mScanCount; - if(c != '\n') - { - return false; - } - return true; -} - - -LLMimeParser::LLMimeParser() : mImpl(* new LLMimeParser::Impl) -{ -} - -LLMimeParser::~LLMimeParser() -{ - delete & mImpl; -} - -void LLMimeParser::reset() -{ - mImpl.reset(); -} - -bool LLMimeParser::parseIndex(std::istream& istr, LLMimeIndex& index) -{ - std::string separator; - return mImpl.parseIndex(istr, S32_MAX, separator, false, index); -} - -bool LLMimeParser::parseIndex( - const std::vector& buffer, - LLMimeIndex& index) -{ - LLMemoryStream mstr(&buffer[0], buffer.size()); - return parseIndex(mstr, buffer.size() + 1, index); -} - -bool LLMimeParser::parseIndex( - std::istream& istr, - S32 limit, - LLMimeIndex& index) -{ - std::string separator; - return mImpl.parseIndex(istr, limit, separator, false, index); -} - -bool LLMimeParser::parseIndex(const U8* buffer, S32 length, LLMimeIndex& index) -{ - LLMemoryStream mstr(buffer, length); - return parseIndex(mstr, length + 1, index); -} - -/* -bool LLMimeParser::verify(std::istream& isr, LLMimeIndex& index) const -{ - return false; -} - -bool LLMimeParser::verify(U8* buffer, S32 length, LLMimeIndex& index) const -{ - LLMemoryStream mstr(buffer, length); - return verify(mstr, index); -} -*/ diff --git a/indra/llmessage/llmime.h b/indra/llmessage/llmime.h deleted file mode 100644 index e6617fb503..0000000000 --- a/indra/llmessage/llmime.h +++ /dev/null @@ -1,292 +0,0 @@ -/** - * @file llmime.h - * @author Phoenix - * @date 2006-12-20 - * @brief Declaration of mime tools. - * - * $LicenseInfo:firstyear=2006&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLMIME_H -#define LL_LLMIME_H - -#include -#include "llsd.h" - -/** - * This file declares various tools for parsing and creating MIME - * objects as described in RFCs 2045, 2046, 2047, 2048, and 2049. - */ - -/** - * @class LLMimeIndex - * @brief Skeletal information useful for handling mime packages. - * @see LLMimeParser - * - * An instance of this class is the parsed output from a LLMimeParser - * which then allows for easy access into a data stream to find and - * get what you want out of it. - * - * This class meant as a tool to quickly find what you seek in a - * parsed mime entity. As such, it does not have useful support for - * modification of a mime entity and specializes the interface toward - * querying data from a fixed mime entity. Modifying an instance of - * LLMimeIndx does not alter a mime entity and changes to a mime - * entity itself are not propogated into an instance of a LLMimeIndex. - * - * Usage:
    - * LLMimeIndex mime_index;
    - * std::ifstream fstr("package.mime", ios::binary);
    - * LLMimeParser parser;
    - * if(parser.parseIndex(fstr, mime_index))
    - * {
    - * std::vector content;
    - * content.resize(mime_index.contentLength());
    - * fstr.seekg(mime_index.offset(), ios::beg);
    - * // ...do work on fstr and content
    - * }
    - */ -class LLMimeIndex -{ -public: - /* @name Client interface. - */ - //@{ - /** - * @brief Get the full parsed headers for this. - * - * If there are any headers, it will be a map of header name to - * the value found on the line. The name is everything before the - * colon, and the value is the string found after the colon to the - * end of the line after trimming leading whitespace. So, for - * example: - * Content-Type: text/plain - * would become an entry in the headers of: - * headers["Content-Type"] == "text/plain" - * - * If this instance of an index was generated by the - * LLMimeParser::parseIndex() call, all header names in rfc2045 - * will be capitalized as in rfc, eg Content-Length and - * MIME-Version, not content-length and mime-version. - * @return Returns an LLSD map of header name to value. Returns - * undef if there are no headers. - */ - LLSD headers() const; - - /** - * @brief Get the content offset. - * - * @return Returns the number of bytes to the start of the data - * segment from the start of serialized mime entity. Returns -1 if - * offset is not known. - */ - S32 offset() const; - - /** - * @brief Get the length of the data segment for this mime part. - * - * @return Returns the content length in bytes. Returns -1 if - * length is not known. - */ - S32 contentLength() const; - - /** - * @brief Get the mime type associated with this node. - * - * @return Returns the mimetype. - */ - std::string contentType() const; - - /** - * @brief Helper method which simplifies parsing the return from type() - * - * @return Returns true if this is a multipart mime, and therefore - * getting subparts will succeed. - */ - bool isMultipart() const; - - /** - * @brief Get the number of atachments. - * - * @return Returns the number of sub-parts for this. - */ - S32 subPartCount() const; - - /** - * @brief Get the indicated attachment. - * - * @param index Value from 0 to (subPartCount() - 1). - * @return Returns the indicated sub-part, or an invalid mime - * index on failure. - */ - LLMimeIndex subPart(S32 index) const; - //@} - - /* @name Interface for building, testing, and helpers for typical use. - */ - //@{ - /** - * @brief Default constructor - creates a useless LLMimeIndex. - */ - LLMimeIndex(); - - /** - * @brief Full constructor. - * - * @param headers The complete headers. - * @param content_offset The number of bytes to the start of the - * data segment of this mime entity from the start of the stream - * or buffer. - */ - LLMimeIndex(LLSD headers, S32 content_offset); - - /** - * @brief Copy constructor. - * - * @param mime The other mime object. - */ - LLMimeIndex(const LLMimeIndex& mime); - - // @brief Destructor. - ~LLMimeIndex(); - - /* - * @breif Assignment operator. - * - * @param mime The other mime object. - * @return Returns this after assignment. - */ - LLMimeIndex& operator=(const LLMimeIndex& mime); - - /** - * @brief Add attachment information as a sub-part to a multipart mime. - * - * @param sub_part the part to attach. - * @return Returns true on success, false on failure. - */ - bool attachSubPart(LLMimeIndex sub_part); - //@} - -protected: - // Implementation. - class Impl; - Impl* mImpl; -}; - - -/** - * @class LLMimeParser - * @brief This class implements a MIME parser and verifier. - * - * THOROUGH_DESCRIPTION - */ -class LLMimeParser -{ -public: - // @brief Make a new mime parser. - LLMimeParser(); - - // @brief Mime parser Destructor. - ~LLMimeParser(); - - // @brief Reset internal state of this parser. - void reset(); - - - /* @name Index generation interface. - */ - //@{ - /** - * @brief Parse a stream to find the mime index information. - * - * This method will scan the istr until a single complete mime - * entity is read or EOF. The istr will be modified by this - * parsing, so pass in a temporary stream or rewind/reset the - * stream after this call. - * @param istr An istream which contains a mime entity. - * @param index[out] The parsed output. - * @return Returns true if an index was parsed and no errors occurred. - */ - bool parseIndex(std::istream& istr, LLMimeIndex& index); - - /** - * @brief Parse a vector to find the mime index information. - * - * @param buffer A vector with data to parse. - * @param index[out] The parsed output. - * @return Returns true if an index was parsed and no errors occurred. - */ - bool parseIndex(const std::vector& buffer, LLMimeIndex& index); - - /** - * @brief Parse a stream to find the mime index information. - * - * This method will scan the istr until a single complete mime - * entity is read, an EOF, or limit bytes have been scanned. The - * istr will be modified by this parsing, so pass in a temporary - * stream or rewind/reset the stream after this call. - * @param istr An istream which contains a mime entity. - * @param limit The maximum number of bytes to scan. - * @param index[out] The parsed output. - * @return Returns true if an index was parsed and no errors occurred. - */ - bool parseIndex(std::istream& istr, S32 limit, LLMimeIndex& index); - - /** - * @brief Parse a memory bufffer to find the mime index information. - * - * @param buffer The start of the buffer to parse. - * @param buffer_length The length of the buffer. - * @param index[out] The parsed output. - * @return Returns true if an index was parsed and no errors occurred. - */ - bool parseIndex(const U8* buffer, S32 buffer_length, LLMimeIndex& index); - //@} - - /** - * @brief - * - * @return - */ - //bool verify(std::istream& istr, LLMimeIndex& index) const; - - /** - * @brief - * - * @return - */ - //bool verify(U8* buffer, S32 buffer_length, LLMimeIndex& index) const; - -protected: - // Implementation. - class Impl; - Impl& mImpl; - -private: - // @brief Not implemneted to prevent copy consturction. - LLMimeParser(const LLMimeParser& parser); - - // @brief Not implemneted to prevent assignment. - LLMimeParser& operator=(const LLMimeParser& mime); -}; - -#endif // LL_LLMIME_H diff --git a/indra/llmessage/llnamevalue.cpp b/indra/llmessage/llnamevalue.cpp index d799403029..5e63228f1f 100644 --- a/indra/llmessage/llnamevalue.cpp +++ b/indra/llmessage/llnamevalue.cpp @@ -31,9 +31,8 @@ #include "llnamevalue.h" -#include "u64.h" #include "llstring.h" -#include "string_table.h" +#include "llstringtable.h" // Anonymous enumeration to provide constants in this file. // *NOTE: These values may be used in sscanf statements below as their @@ -149,7 +148,7 @@ void LLNameValue::init(const char *name, const char *data, const char *type, con else if (!strcmp(mStringType, "U64")) { mType = NVT_U64; - mNameValueReference.u64 = new U64(str_to_U64(ll_safe_string(data))); + mNameValueReference.u64 = new U64(std::stoull(data)); } else if (!strcmp(mStringType, "VEC3")) { @@ -168,7 +167,7 @@ void LLNameValue::init(const char *name, const char *data, const char *type, con } // finite checks - if (!llfinite(t1) || !llfinite(t2) || !llfinite(t3)) + if (!std::isfinite(t1) || !std::isfinite(t2) || !std::isfinite(t3)) { t1 = 0.f; t2 = 0.f; @@ -209,7 +208,7 @@ void LLNameValue::init(const char *name, const char *data, const char *type, con } else { - llwarns << "Unknown name value type string " << mStringType << " for " << mName << llendl; + LL_WARNS() << "Unknown name value type string " << mStringType << " for " << mName << LL_ENDL; mType = NVT_NULL; } @@ -261,8 +260,8 @@ void LLNameValue::init(const char *name, const char *data, const char *type, con } else { - llwarns << "LLNameValue::init() - unknown sendto field " - << nvsendto << " for NV " << mName << llendl; + LL_WARNS() << "LLNameValue::init() - unknown sendto field " + << nvsendto << " for NV " << mName << LL_ENDL; mSendto = NVS_NULL; mStringSendto = mNVNameTable->addString("S"); } @@ -332,7 +331,7 @@ LLNameValue::LLNameValue(const char *name, const char *type, const char *nvclass else { mType = NVT_NULL; - llinfos << "Unknown name-value type " << mStringType << llendl; + LL_INFOS() << "Unknown name-value type " << mStringType << LL_ENDL; } // Nota Bene: Whatever global structure manages this should have these in the name table already! @@ -580,7 +579,7 @@ char *LLNameValue::getString() } else { - llerrs << mName << " not a string!" << llendl; + LL_ERRS() << mName << " not a string!" << LL_ENDL; return NULL; } } @@ -593,7 +592,7 @@ const char *LLNameValue::getAsset() const } else { - llerrs << mName << " not an asset!" << llendl; + LL_ERRS() << mName << " not an asset!" << LL_ENDL; return NULL; } } @@ -606,7 +605,7 @@ F32 *LLNameValue::getF32() } else { - llerrs << mName << " not a F32!" << llendl; + LL_ERRS() << mName << " not a F32!" << LL_ENDL; return NULL; } } @@ -619,7 +618,7 @@ S32 *LLNameValue::getS32() } else { - llerrs << mName << " not a S32!" << llendl; + LL_ERRS() << mName << " not a S32!" << LL_ENDL; return NULL; } } @@ -632,7 +631,7 @@ U32 *LLNameValue::getU32() } else { - llerrs << mName << " not a U32!" << llendl; + LL_ERRS() << mName << " not a U32!" << LL_ENDL; return NULL; } } @@ -645,7 +644,7 @@ U64 *LLNameValue::getU64() } else { - llerrs << mName << " not a U64!" << llendl; + LL_ERRS() << mName << " not a U64!" << LL_ENDL; return NULL; } } @@ -658,7 +657,7 @@ void LLNameValue::getVec3(LLVector3 &vec) } else { - llerrs << mName << " not a Vec3!" << llendl; + LL_ERRS() << mName << " not a Vec3!" << LL_ENDL; } } @@ -670,7 +669,7 @@ LLVector3 *LLNameValue::getVec3() } else { - llerrs << mName << " not a Vec3!" << llendl; + LL_ERRS() << mName << " not a Vec3!" << LL_ENDL; return NULL; } } @@ -726,7 +725,7 @@ LLNameValue &LLNameValue::operator=(const LLNameValue &a) *mNameValueReference.u64 = *a.mNameValueReference.u64; break; default: - llerrs << "Unknown Name value type " << (U32)a.mType << llendl; + LL_ERRS() << "Unknown Name value type " << (U32)a.mType << LL_ENDL; break; } @@ -865,7 +864,7 @@ void LLNameValue::setU32(const U32 a) *mNameValueReference.f32 = (F32)a; break; default: - llerrs << "NameValue: Trying to set U32 into a " << mStringType << ", unknown conversion" << llendl; + LL_ERRS() << "NameValue: Trying to set U32 into a " << mStringType << ", unknown conversion" << LL_ENDL; break; } return; @@ -883,7 +882,7 @@ void LLNameValue::setVec3(const LLVector3 &a) *mNameValueReference.vec3 = a; break; default: - llerrs << "NameValue: Trying to set LLVector3 into a " << mStringType << ", unknown conversion" << llendl; + LL_ERRS() << "NameValue: Trying to set LLVector3 into a " << mStringType << ", unknown conversion" << LL_ENDL; break; } return; @@ -895,7 +894,7 @@ std::string LLNameValue::printNameValue() const std::string buffer; buffer = llformat("%s %s %s %s ", mName, mStringType, mStringClass, mStringSendto); buffer += printData(); -// llinfos << "Name Value Length: " << buffer.size() + 1 << llendl; +// LL_INFOS() << "Name Value Length: " << buffer.size() + 1 << LL_ENDL; return buffer; } @@ -919,16 +918,14 @@ std::string LLNameValue::printData() const break; case NVT_U64: { - char u64_string[U64_BUFFER_LEN]; /* Flawfinder: ignore */ - U64_to_str(*mNameValueReference.u64, u64_string, sizeof(u64_string)); - buffer = u64_string; + buffer = fmt::to_string(*mNameValueReference.u64); } break; case NVT_VEC3: buffer = llformat( "%f, %f, %f", mNameValueReference.vec3->mV[VX], mNameValueReference.vec3->mV[VY], mNameValueReference.vec3->mV[VZ]); break; default: - llerrs << "Trying to print unknown NameValue type " << mStringType << llendl; + LL_ERRS() << "Trying to print unknown NameValue type " << mStringType << LL_ENDL; break; } return buffer; @@ -952,17 +949,13 @@ std::ostream& operator<<(std::ostream& s, const LLNameValue &a) s << *(a.mNameValueReference.u32); break; case NVT_U64: - { - char u64_string[U64_BUFFER_LEN]; /* Flawfinder: ignore */ - U64_to_str(*a.mNameValueReference.u64, u64_string, sizeof(u64_string)); - s << u64_string; - } + s << (*a.mNameValueReference.u64); break; case NVT_VEC3: s << *(a.mNameValueReference.vec3); break; default: - llerrs << "Trying to print unknown NameValue type " << a.mStringType << llendl; + LL_ERRS() << "Trying to print unknown NameValue type " << a.mStringType << LL_ENDL; break; } return s; diff --git a/indra/llmessage/llnamevalue.h b/indra/llmessage/llnamevalue.h index 273de475f8..f8b556b5fe 100644 --- a/indra/llmessage/llnamevalue.h +++ b/indra/llmessage/llnamevalue.h @@ -41,7 +41,7 @@ // SitObject STRING // SitPosition VEC3 -#include "string_table.h" +#include "llstringtable.h" #include "llmath.h" #include "v3math.h" #include "lldbstrings.h" diff --git a/indra/llmessage/llpacketack.cpp b/indra/llmessage/llpacketack.cpp index f08d3404ea..c3c022c297 100644 --- a/indra/llmessage/llpacketack.cpp +++ b/indra/llmessage/llpacketack.cpp @@ -50,7 +50,7 @@ LLReliablePacket::LLReliablePacket( mHost = params->mHost; mRetries = params->mRetries; mPingBasedRetry = params->mPingBasedRetry; - mTimeout = params->mTimeout; + mTimeout = F32Seconds(params->mTimeout); mCallback = params->mCallback; mCallbackData = params->mCallbackData; mMessageName = params->mMessageName; @@ -59,13 +59,13 @@ LLReliablePacket::LLReliablePacket( { mRetries = 0; mPingBasedRetry = TRUE; - mTimeout = 0.f; + mTimeout = F32Seconds(0.f); mCallback = NULL; mCallbackData = NULL; mMessageName = NULL; } - mExpirationTime = (F64)((S64)totalTime())/1000000.0 + mTimeout; + mExpirationTime = (F64Seconds)totalTime() + mTimeout; mPacketID = ntohl(*((U32*)(&buf_ptr[PHL_PACKET_ID]))); mSocket = socket; diff --git a/indra/llmessage/llpacketack.h b/indra/llmessage/llpacketack.h index 2ef3c48e44..f0ed923f19 100644 --- a/indra/llmessage/llpacketack.h +++ b/indra/llmessage/llpacketack.h @@ -28,6 +28,7 @@ #define LL_LLPACKETACK_H #include "llhost.h" +#include "llunits.h" class LLReliablePacketParams { @@ -35,7 +36,7 @@ class LLReliablePacketParams LLHost mHost; S32 mRetries; BOOL mPingBasedRetry; - F32 mTimeout; + F32Seconds mTimeout; void (*mCallback)(void **,S32); void** mCallbackData; char* mMessageName; @@ -53,7 +54,7 @@ class LLReliablePacketParams mHost.invalidate(); mRetries = 0; mPingBasedRetry = TRUE; - mTimeout = 0.f; + mTimeout = F32Seconds(0.f); mCallback = NULL; mCallbackData = NULL; mMessageName = NULL; @@ -63,7 +64,7 @@ class LLReliablePacketParams const LLHost& host, S32 retries, BOOL ping_based_retry, - F32 timeout, + F32Seconds timeout, void (*callback)(void**,S32), void** callback_data, char* name) { @@ -98,7 +99,7 @@ class LLReliablePacket LLHost mHost; S32 mRetries; BOOL mPingBasedRetry; - F32 mTimeout; + F32Seconds mTimeout; void (*mCallback)(void**,S32); void** mCallbackData; char* mMessageName; @@ -108,7 +109,7 @@ class LLReliablePacket TPACKETID mPacketID; - F64 mExpirationTime; + F64Seconds mExpirationTime; }; #endif diff --git a/indra/llmessage/llpacketbuffer.cpp b/indra/llmessage/llpacketbuffer.cpp index e69631eb3b..ccf991b1a7 100644 --- a/indra/llmessage/llpacketbuffer.cpp +++ b/indra/llmessage/llpacketbuffer.cpp @@ -29,7 +29,7 @@ #include "llpacketbuffer.h" #include "net.h" -#include "timing.h" +#include "lltimer.h" #include "llhost.h" /////////////////////////////////////////////////////////// @@ -41,7 +41,7 @@ LLPacketBuffer::LLPacketBuffer(const LLHost &host, const char *datap, const S32 if (size > NET_BUFFER_SIZE) { - llerrs << "Sending packet > " << NET_BUFFER_SIZE << " of size " << size << llendl; + LL_ERRS() << "Sending packet > " << NET_BUFFER_SIZE << " of size " << size << LL_ENDL; } else { diff --git a/indra/llmessage/llpacketring.cpp b/indra/llmessage/llpacketring.cpp index d52a9435ce..93c458b37a 100644 --- a/indra/llmessage/llpacketring.cpp +++ b/indra/llmessage/llpacketring.cpp @@ -41,7 +41,6 @@ #include "llproxy.h" #include "llrand.h" #include "message.h" -#include "timing.h" #include "u64.h" // @@ -200,7 +199,7 @@ S32 LLPacketRing::receivePacket (S32 socket, char *datap) if (mInBufferLength + packetp->getSize() > mMaxBufferLength) { // Toss it. - llwarns << "Throwing away packet, overflowing buffer" << llendl; + LL_WARNS() << "Throwing away packet, overflowing buffer" << LL_ENDL; delete packetp; packetp = NULL; } @@ -332,7 +331,7 @@ BOOL LLPacketRing::sendPacket(int h_socket, char * send_buffer, S32 buf_size, LL { // Nuke this packet, we overflowed the buffer. // Toss it. - llwarns << "Throwing away outbound packet, overflowing buffer" << llendl; + LL_WARNS() << "Throwing away outbound packet, overflowing buffer" << LL_ENDL; } else { @@ -340,7 +339,7 @@ BOOL LLPacketRing::sendPacket(int h_socket, char * send_buffer, S32 buf_size, LL if ((mOutBufferLength > 4192) && queue_timer.getElapsedTimeF32() > 1.f) { // Add it to the queue - llinfos << "Outbound packet queue " << mOutBufferLength << " bytes" << llendl; + LL_INFOS() << "Outbound packet queue " << mOutBufferLength << " bytes" << LL_ENDL; queue_timer.reset(); } packetp = new LLPacketBuffer(host, send_buffer, buf_size); diff --git a/indra/llmessage/llpartdata.cpp b/indra/llmessage/llpartdata.cpp index de369dc3cb..a89fba530c 100644 --- a/indra/llmessage/llpartdata.cpp +++ b/indra/llmessage/llpartdata.cpp @@ -37,53 +37,46 @@ -const S32 PS_PART_DATA_BLOCK_SIZE = 4 + 2 + 4 + 4 + 2 + 2; // 18 -const S32 PS_DATA_BLOCK_SIZE = 68 + PS_PART_DATA_BLOCK_SIZE; // 68 + 18 = 86 +const S32 PS_PART_DATA_GLOW_SIZE = 2; +const S32 PS_PART_DATA_BLEND_SIZE = 2; +const S32 PS_LEGACY_PART_DATA_BLOCK_SIZE = 4 + 2 + 4 + 4 + 2 + 2; //18 +const S32 PS_SYS_DATA_BLOCK_SIZE = 68; +const S32 PS_MAX_DATA_BLOCK_SIZE = PS_SYS_DATA_BLOCK_SIZE+ + PS_LEGACY_PART_DATA_BLOCK_SIZE + + PS_PART_DATA_BLEND_SIZE + + PS_PART_DATA_GLOW_SIZE+ + 8; //two S32 size fields + +const S32 PS_LEGACY_DATA_BLOCK_SIZE = PS_SYS_DATA_BLOCK_SIZE + PS_LEGACY_PART_DATA_BLOCK_SIZE; + + +const U32 PART_DATA_MASK = LLPartData::LL_PART_DATA_GLOW | LLPartData::LL_PART_DATA_BLEND; + const F32 MAX_PART_SCALE = 4.f; -BOOL LLPartData::pack(LLDataPacker &dp) +bool LLPartData::hasGlow() const { - LLColor4U coloru; - dp.packU32(mFlags, "pdflags"); - dp.packFixed(mMaxAge, "pdmaxage", FALSE, 8, 8); - coloru.setVec(mStartColor); - dp.packColor4U(coloru, "pdstartcolor"); - coloru.setVec(mEndColor); - dp.packColor4U(coloru, "pdendcolor"); - dp.packFixed(mStartScale.mV[0], "pdstartscalex", FALSE, 3, 5); - dp.packFixed(mStartScale.mV[1], "pdstartscaley", FALSE, 3, 5); - dp.packFixed(mEndScale.mV[0], "pdendscalex", FALSE, 3, 5); - dp.packFixed(mEndScale.mV[1], "pdendscaley", FALSE, 3, 5); - return TRUE; + return mStartGlow > 0.f || mEndGlow > 0.f; } -LLSD LLPartData::asLLSD() const +bool LLPartData::hasBlendFunc() const { - LLSD sd = LLSD(); - sd["pdflags"] = ll_sd_from_U32(mFlags); - sd["pdmaxage"] = mMaxAge; - sd["pdstartcolor"] = ll_sd_from_color4(mStartColor); - sd["pdendcolor"] = ll_sd_from_color4(mEndColor); - sd["pdstartscale"] = ll_sd_from_vector2(mStartScale); - sd["pdendscale"] = ll_sd_from_vector2(mEndScale); - return sd; + return mBlendFuncSource != LLPartData::LL_PART_BF_SOURCE_ALPHA || mBlendFuncDest != LLPartData::LL_PART_BF_ONE_MINUS_SOURCE_ALPHA; } -bool LLPartData::fromLLSD(LLSD& sd) +S32 LLPartData::getSize() const { - mFlags = ll_U32_from_sd(sd["pdflags"]); - mMaxAge = (F32)sd["pdmaxage"].asReal(); - mStartColor = ll_color4_from_sd(sd["pdstartcolor"]); - mEndColor = ll_color4_from_sd(sd["pdendcolor"]); - mStartScale = ll_vector2_from_sd(sd["pdstartscale"]); - mEndScale = ll_vector2_from_sd(sd["pdendscale"]); - return true; + S32 size = PS_LEGACY_PART_DATA_BLOCK_SIZE; + if (hasGlow()) size += PS_PART_DATA_GLOW_SIZE; + if (hasBlendFunc()) size += PS_PART_DATA_BLEND_SIZE; + + return size; } -BOOL LLPartData::unpack(LLDataPacker &dp) +BOOL LLPartData::unpackLegacy(LLDataPacker &dp) { LLColor4U coloru; @@ -98,9 +91,70 @@ BOOL LLPartData::unpack(LLDataPacker &dp) dp.unpackFixed(mStartScale.mV[1], "pdstartscaley", FALSE, 3, 5); dp.unpackFixed(mEndScale.mV[0], "pdendscalex", FALSE, 3, 5); dp.unpackFixed(mEndScale.mV[1], "pdendscaley", FALSE, 3, 5); + + mStartGlow = 0.f; + mEndGlow = 0.f; + mBlendFuncSource = LLPartData::LL_PART_BF_SOURCE_ALPHA; + mBlendFuncDest = LLPartData::LL_PART_BF_ONE_MINUS_SOURCE_ALPHA; + return TRUE; } +BOOL LLPartData::unpack(LLDataPacker &dp) +{ + S32 size = 0; + dp.unpackS32(size, "partsize"); + + unpackLegacy(dp); + size -= PS_LEGACY_PART_DATA_BLOCK_SIZE; + + if (mFlags & LL_PART_DATA_GLOW) + { + if (size < PS_PART_DATA_GLOW_SIZE) return FALSE; + + U8 tmp_glow = 0; + dp.unpackU8(tmp_glow,"pdstartglow"); + mStartGlow = tmp_glow / 255.f; + dp.unpackU8(tmp_glow,"pdendglow"); + mEndGlow = tmp_glow / 255.f; + + size -= PS_PART_DATA_GLOW_SIZE; + } + else + { + mStartGlow = 0.f; + mEndGlow = 0.f; + } + + if (mFlags & LL_PART_DATA_BLEND) + { + if (size < PS_PART_DATA_BLEND_SIZE) return FALSE; + dp.unpackU8(mBlendFuncSource,"pdblendsource"); + dp.unpackU8(mBlendFuncDest,"pdblenddest"); + size -= PS_PART_DATA_BLEND_SIZE; + } + else + { + mBlendFuncSource = LLPartData::LL_PART_BF_SOURCE_ALPHA; + mBlendFuncDest = LLPartData::LL_PART_BF_ONE_MINUS_SOURCE_ALPHA; + } + + if (size > 0) + { //leftover bytes, unrecognized parameters + U8 feh = 0; + while (size > 0) + { //read remaining bytes in block + dp.unpackU8(feh, "whippang"); + size--; + } + + //this particle system won't display properly, better to not show anything + return FALSE; + } + + + return TRUE; +} void LLPartData::setFlags(const U32 flags) { @@ -148,6 +202,18 @@ void LLPartData::setEndAlpha(const F32 alpha) mEndColor.mV[3] = alpha; } +// static +bool LLPartData::validBlendFunc(S32 func) +{ + if (func >= 0 + && func < LL_PART_BF_COUNT + && func != UNSUPPORTED_DEST_ALPHA + && func != UNSUPPORTED_ONE_MINUS_DEST_ALPHA) + { + return true; + } + return false; +} LLPartSysData::LLPartSysData() { @@ -160,6 +226,10 @@ LLPartSysData::LLPartSysData() mPartData.mStartScale = LLVector2(1.f, 1.f); mPartData.mEndScale = LLVector2(1.f, 1.f); mPartData.mMaxAge = 10.0; + mPartData.mBlendFuncSource = LLPartData::LL_PART_BF_SOURCE_ALPHA; + mPartData.mBlendFuncDest = LLPartData::LL_PART_BF_ONE_MINUS_SOURCE_ALPHA; + mPartData.mStartGlow = 0.f; + mPartData.mEndGlow = 0.f; mMaxAge = 0.0; mStartAge = 0.0; @@ -175,38 +245,7 @@ LLPartSysData::LLPartSysData() mNumParticles = 0; } - -BOOL LLPartSysData::pack(LLDataPacker &dp) -{ - dp.packU32(mCRC, "pscrc"); - dp.packU32(mFlags, "psflags"); - dp.packU8(mPattern, "pspattern"); - dp.packFixed(mMaxAge, "psmaxage", FALSE, 8, 8); - dp.packFixed(mStartAge, "psstartage", FALSE, 8, 8); - dp.packFixed(mInnerAngle, "psinnerangle", FALSE, 3, 5); - dp.packFixed(mOuterAngle, "psouterangle", FALSE, 3, 5); - dp.packFixed(mBurstRate, "psburstrate", FALSE, 8, 8); - dp.packFixed(mBurstRadius, "psburstradius", FALSE, 8, 8); - dp.packFixed(mBurstSpeedMin, "psburstspeedmin", FALSE, 8, 8); - dp.packFixed(mBurstSpeedMax, "psburstspeedmax", FALSE, 8, 8); - dp.packU8(mBurstPartCount, "psburstpartcount"); - - dp.packFixed(mAngularVelocity.mV[0], "psangvelx", TRUE, 8, 7); - dp.packFixed(mAngularVelocity.mV[1], "psangvely", TRUE, 8, 7); - dp.packFixed(mAngularVelocity.mV[2], "psangvelz", TRUE, 8, 7); - - dp.packFixed(mPartAccel.mV[0], "psaccelx", TRUE, 8, 7); - dp.packFixed(mPartAccel.mV[1], "psaccely", TRUE, 8, 7); - dp.packFixed(mPartAccel.mV[2], "psaccelz", TRUE, 8, 7); - - dp.packUUID(mPartImageID, "psuuid"); - dp.packUUID(mTargetUUID, "pstargetuuid"); - mPartData.pack(dp); - return TRUE; -} - - -BOOL LLPartSysData::unpack(LLDataPacker &dp) +BOOL LLPartSysData::unpackSystem(LLDataPacker &dp) { dp.unpackU32(mCRC, "pscrc"); dp.unpackU32(mFlags, "psflags"); @@ -232,20 +271,58 @@ BOOL LLPartSysData::unpack(LLDataPacker &dp) dp.unpackUUID(mPartImageID, "psuuid"); dp.unpackUUID(mTargetUUID, "pstargetuuid"); - mPartData.unpack(dp); return TRUE; } +BOOL LLPartSysData::unpackLegacy(LLDataPacker &dp) +{ + unpackSystem(dp); + mPartData.unpackLegacy(dp); + + return TRUE; +} + +BOOL LLPartSysData::unpack(LLDataPacker &dp) +{ + // syssize is currently unused. Adding now when modifying the 'version to make extensible in the future + S32 size = 0; + dp.unpackS32(size, "syssize"); + + if (size != PS_SYS_DATA_BLOCK_SIZE) + { //unexpected size, this viewer doesn't know how to parse this particle system + + //skip to LLPartData block + U8 feh = 0; + + for (S32 i = 0; i < size; ++i) + { + dp.unpackU8(feh, "whippang"); + } + + dp.unpackS32(size, "partsize"); + //skip LLPartData block + for (S32 i = 0; i < size; ++i) + { + dp.unpackU8(feh, "whippang"); + } + return FALSE; + } + + unpackSystem(dp); + + return mPartData.unpack(dp); +} + std::ostream& operator<<(std::ostream& s, const LLPartSysData &data) { - s << "Flags: " << std::hex << data.mFlags << std::dec; - s << " Pattern: " << std::hex << (U32) data.mPattern << std::dec << "\n"; + s << "Flags: " << std::hex << data.mFlags; + s << " Pattern: " << std::hex << (U32) data.mPattern << "\n"; s << "Age: [" << data.mStartAge << ", " << data.mMaxAge << "]\n"; s << "Angle: [" << data.mInnerAngle << ", " << data.mOuterAngle << "]\n"; s << "Burst Rate: " << data.mBurstRate << "\n"; s << "Burst Radius: " << data.mBurstRadius << "\n"; s << "Burst Speed: [" << data.mBurstSpeedMin << ", " << data.mBurstSpeedMax << "]\n"; - s << "Burst Part Count: " << std::hex << (U32) data.mBurstPartCount << std::dec << "\n"; + s << "Burst Part Count: " << std::hex << (U32) data.mBurstPartCount << "\n"; s << "Angular Velocity: " << data.mAngularVelocity << "\n"; s << "Accel: " << data.mPartAccel; return s; @@ -253,7 +330,7 @@ std::ostream& operator<<(std::ostream& s, const LLPartSysData &data) BOOL LLPartSysData::isNullPS(const S32 block_num) { - U8 ps_data_block[PS_DATA_BLOCK_SIZE]; + U8 ps_data_block[PS_MAX_DATA_BLOCK_SIZE]; U32 crc; S32 size; @@ -264,14 +341,28 @@ BOOL LLPartSysData::isNullPS(const S32 block_num) { return TRUE; } - else if (size != PS_DATA_BLOCK_SIZE) + + if (size > PS_MAX_DATA_BLOCK_SIZE) { - llwarns << "PSBlock is wrong size for particle system data - got " << size << ", expecting " << PS_DATA_BLOCK_SIZE << llendl; + //size is too big, newer particle version unsupported return TRUE; } - gMessageSystem->getBinaryData("ObjectData", "PSBlock", ps_data_block, PS_DATA_BLOCK_SIZE, block_num, PS_DATA_BLOCK_SIZE); - LLDataPackerBinaryBuffer dp(ps_data_block, PS_DATA_BLOCK_SIZE); + gMessageSystem->getBinaryData("ObjectData", "PSBlock", ps_data_block, size, block_num, PS_MAX_DATA_BLOCK_SIZE); + + LLDataPackerBinaryBuffer dp(ps_data_block, size); + if (size > PS_LEGACY_DATA_BLOCK_SIZE) + { + // non legacy systems pack a size before the CRC + S32 tmp = 0; + dp.unpackS32(tmp, "syssize"); + + if (tmp > PS_SYS_DATA_BLOCK_SIZE) + { //unknown system data block size, don't know how to parse it, treat as NULL + return TRUE; + } + } + dp.unpackU32(crc, "crc"); if (crc == 0) @@ -281,50 +372,37 @@ BOOL LLPartSysData::isNullPS(const S32 block_num) return FALSE; } - -//static -BOOL LLPartSysData::packNull() -{ - U8 ps_data_block[PS_DATA_BLOCK_SIZE]; - gMessageSystem->addBinaryData("PSBlock", ps_data_block, 0); - return TRUE; -} - - -BOOL LLPartSysData::packBlock() -{ - U8 ps_data_block[PS_DATA_BLOCK_SIZE]; - - LLDataPackerBinaryBuffer dp(ps_data_block, PS_DATA_BLOCK_SIZE); - pack(dp); - - // Add to message - gMessageSystem->addBinaryData("PSBlock", ps_data_block, PS_DATA_BLOCK_SIZE); - - return TRUE; -} - - BOOL LLPartSysData::unpackBlock(const S32 block_num) { - U8 ps_data_block[PS_DATA_BLOCK_SIZE]; + U8 ps_data_block[PS_MAX_DATA_BLOCK_SIZE]; // Check size of block S32 size = gMessageSystem->getSize("ObjectData", block_num, "PSBlock"); - if (size != PS_DATA_BLOCK_SIZE) + if (size > PS_MAX_DATA_BLOCK_SIZE) { - llwarns << "PSBlock is wrong size for particle system data - got " << size << ", expecting " << PS_DATA_BLOCK_SIZE << llendl; + // Larger packets are newer and unsupported return FALSE; } // Get from message - gMessageSystem->getBinaryData("ObjectData", "PSBlock", ps_data_block, PS_DATA_BLOCK_SIZE, block_num, PS_DATA_BLOCK_SIZE); + gMessageSystem->getBinaryData("ObjectData", "PSBlock", ps_data_block, size, block_num, PS_MAX_DATA_BLOCK_SIZE); - LLDataPackerBinaryBuffer dp(ps_data_block, PS_DATA_BLOCK_SIZE); - unpack(dp); + LLDataPackerBinaryBuffer dp(ps_data_block, size); - return TRUE; + if (size == PS_LEGACY_DATA_BLOCK_SIZE) + { + return unpackLegacy(dp); + } + else + { + return unpack(dp); + } +} + +bool LLPartSysData::isLegacyCompatible() const +{ + return !mPartData.hasGlow() && !mPartData.hasBlendFunc(); } void LLPartSysData::clampSourceParticleRate() diff --git a/indra/llmessage/llpartdata.h b/indra/llmessage/llpartdata.h index a4ef058b30..ed5c1a6ac7 100644 --- a/indra/llmessage/llpartdata.h +++ b/indra/llmessage/llpartdata.h @@ -70,7 +70,12 @@ enum LLPSScriptFlags LLPS_SRC_TARGET_UUID, LLPS_SRC_OMEGA, LLPS_SRC_ANGLE_BEGIN, - LLPS_SRC_ANGLE_END + LLPS_SRC_ANGLE_END, + + LLPS_PART_BLEND_FUNC_SOURCE, + LLPS_PART_BLEND_FUNC_DEST, + LLPS_PART_START_GLOW, + LLPS_PART_END_GLOW }; @@ -83,11 +88,13 @@ class LLPartData mParameter(0.f) { } + BOOL unpackLegacy(LLDataPacker &dp); BOOL unpack(LLDataPacker &dp); + BOOL pack(LLDataPacker &dp); - LLSD asLLSD() const; - operator LLSD() const {return asLLSD(); } - bool fromLLSD(LLSD& sd); + + bool hasGlow() const; + bool hasBlendFunc() const; // Masks for the different particle flags enum @@ -102,17 +109,39 @@ class LLPartData LL_PART_TARGET_LINEAR_MASK = 0x80, // Particle uses a direct linear interpolation LL_PART_EMISSIVE_MASK = 0x100, // Particle is "emissive", instead of being lit LL_PART_BEAM_MASK = 0x200, // Particle is a "beam" connecting source and target + LL_PART_RIBBON_MASK = 0x400, // Particles are joined together into one continuous triangle strip // Not implemented yet! //LL_PART_RANDOM_ACCEL_MASK = 0x100, // Particles have random acceleration //LL_PART_RANDOM_VEL_MASK = 0x200, // Particles have random velocity shifts" //LL_PART_TRAIL_MASK = 0x400, // Particles have historical "trails" + //sYSTEM SET FLAGS + LL_PART_DATA_GLOW = 0x10000, + LL_PART_DATA_BLEND = 0x20000, + // Viewer side use only! LL_PART_HUD = 0x40000000, LL_PART_DEAD_MASK = 0x80000000, }; + enum + { + LL_PART_BF_ONE = 0, + LL_PART_BF_ZERO = 1, + LL_PART_BF_DEST_COLOR = 2, + LL_PART_BF_SOURCE_COLOR = 3, + LL_PART_BF_ONE_MINUS_DEST_COLOR = 4, + LL_PART_BF_ONE_MINUS_SOURCE_COLOR = 5, + UNSUPPORTED_DEST_ALPHA = 6, + LL_PART_BF_SOURCE_ALPHA = 7, + UNSUPPORTED_ONE_MINUS_DEST_ALPHA = 8, + LL_PART_BF_ONE_MINUS_SOURCE_ALPHA = 9, + LL_PART_BF_COUNT = 10 + }; + + static bool validBlendFunc(S32 func); + void setFlags(const U32 flags); void setMaxAge(const F32 max_age); void setStartScale(const F32 xs, F32 ys); @@ -126,6 +155,9 @@ class LLPartData friend class LLPartSysData; friend class LLViewerPartSourceScript; +private: + S32 getSize() const; + // These are public because I'm really lazy... public: U32 mFlags; // Particle state/interpolators in effect @@ -137,6 +169,12 @@ class LLPartData LLVector3 mPosOffset; // Offset from source if using FOLLOW_SOURCE F32 mParameter; // A single floating point parameter + + F32 mStartGlow; + F32 mEndGlow; + + U8 mBlendFuncSource; + U8 mBlendFuncDest; }; @@ -146,15 +184,13 @@ class LLPartSysData LLPartSysData(); BOOL unpack(LLDataPacker &dp); - BOOL pack(LLDataPacker &dp); - - + BOOL unpackLegacy(LLDataPacker &dp); BOOL unpackBlock(const S32 block_num); - BOOL packBlock(); - - static BOOL packNull(); + static BOOL isNullPS(const S32 block_num); // Returns FALSE if this is a "NULL" particle system (i.e. no system) + bool isLegacyCompatible() const; + // Different masks for effects on the source enum { @@ -187,7 +223,12 @@ class LLPartSysData void clampSourceParticleRate(); friend std::ostream& operator<<(std::ostream& s, const LLPartSysData &data); // Stream a + + S32 getdataBlockSize() const; +private: + BOOL unpackSystem(LLDataPacker &dp); + public: // Public because I'm lazy.... diff --git a/indra/llmessage/llproxy.cpp b/indra/llmessage/llproxy.cpp index 448b6606b3..97d97e742c 100644 --- a/indra/llmessage/llproxy.cpp +++ b/indra/llmessage/llproxy.cpp @@ -115,9 +115,9 @@ S32 LLProxy::proxyHandshake(LLHost proxy) U32 request_size = socks_username.size() + socks_password.size() + 3; char * password_auth = new char[request_size]; password_auth[0] = 0x01; - password_auth[1] = socks_username.size(); + password_auth[1] = static_cast(socks_username.size()); memcpy(&password_auth[2], socks_username.c_str(), socks_username.size()); - password_auth[socks_username.size() + 2] = socks_password.size(); + password_auth[socks_username.size() + 2] = static_cast(socks_password.size()); memcpy(&password_auth[socks_username.size() + 3], socks_password.c_str(), socks_password.size()); authmethod_password_reply_t password_reply; diff --git a/indra/llmessage/llpumpio.cpp b/indra/llmessage/llpumpio.cpp index 588265f97b..965a3d5b7f 100644 --- a/indra/llmessage/llpumpio.cpp +++ b/indra/llmessage/llpumpio.cpp @@ -56,7 +56,7 @@ // constants for poll timeout. if we are threading, we want to have a // longer poll timeout. -#if LL_THREADS_APR +#if LL_THREADS_PUMPIO static const S32 DEFAULT_POLL_TIMEOUT = 1000; #else static const S32 DEFAULT_POLL_TIMEOUT = 0; @@ -84,7 +84,7 @@ void ll_debug_poll_fd(const char* msg, const apr_pollfd_t* poll) #if LL_DEBUG_POLL_FILE_DESCRIPTORS if(!poll) { - lldebugs << "Poll -- " << (msg?msg:"") << ": no pollfd." << llendl; + LL_DEBUGS() << "Poll -- " << (msg?msg:"") << ": no pollfd." << LL_ENDL; return; } if(poll->desc.s) @@ -92,13 +92,13 @@ void ll_debug_poll_fd(const char* msg, const apr_pollfd_t* poll) apr_os_sock_t os_sock; if(APR_SUCCESS == apr_os_sock_get(&os_sock, poll->desc.s)) { - lldebugs << "Poll -- " << (msg?msg:"") << " on fd " << os_sock - << " at " << poll->desc.s << llendl; + LL_DEBUGS() << "Poll -- " << (msg?msg:"") << " on fd " << os_sock + << " at " << poll->desc.s << LL_ENDL; } else { - lldebugs << "Poll -- " << (msg?msg:"") << " no fd " - << " at " << poll->desc.s << llendl; + LL_DEBUGS() << "Poll -- " << (msg?msg:"") << " no fd " + << " at " << poll->desc.s << LL_ENDL; } } else if(poll->desc.f) @@ -106,18 +106,18 @@ void ll_debug_poll_fd(const char* msg, const apr_pollfd_t* poll) apr_os_file_t os_file; if(APR_SUCCESS == apr_os_file_get(&os_file, poll->desc.f)) { - lldebugs << "Poll -- " << (msg?msg:"") << " on fd " << os_file - << " at " << poll->desc.f << llendl; + LL_DEBUGS() << "Poll -- " << (msg?msg:"") << " on fd " << os_file + << " at " << poll->desc.f << LL_ENDL; } else { - lldebugs << "Poll -- " << (msg?msg:"") << " no fd " - << " at " << poll->desc.f << llendl; + LL_DEBUGS() << "Poll -- " << (msg?msg:"") << " no fd " + << " at " << poll->desc.f << LL_ENDL; } } else { - lldebugs << "Poll -- " << (msg?msg:"") << ": no descriptor." << llendl; + LL_DEBUGS() << "Poll -- " << (msg?msg:"") << ": no descriptor." << LL_ENDL; } #endif } @@ -168,27 +168,24 @@ LLPumpIO::LLPumpIO(void) : mPollset(NULL), mPollsetClientID(0), mNextLock(0), +#if LL_THREADS_PUMPIO + mPool(), + LLMutex mChainsMutex(initPool()), + LLMutex mCallbackMutex(initPool()), +#endif mCurrentPoolReallocCount(0), - mChainsMutex(NULL), - mCallbackMutex(NULL), mCurrentChain(mRunningChains.end()) { - mCurrentChain = mRunningChains.end(); - - initialize(); +#if !LL_THREADS_PUMPIO + initPool(); +#endif } LLPumpIO::~LLPumpIO() { -#if LL_THREADS_APR - if (mChainsMutex) apr_thread_mutex_destroy(mChainsMutex); - if (mCallbackMutex) apr_thread_mutex_destroy(mCallbackMutex); -#endif - mChainsMutex = NULL; - mCallbackMutex = NULL; if(mPollset) { -// lldebugs << "cleaning up pollset" << llendl; +// LL_DEBUGS() << "cleaning up pollset" << LL_ENDL; apr_pollset_destroy(mPollset); mPollset = NULL; } @@ -205,10 +202,10 @@ bool LLPumpIO::addChain(chain_t const& chain, F32 timeout) info.mData = LLIOPipe::buffer_ptr_t(new LLBufferArray); LLLinkInfo link; #if LL_DEBUG_PIPE_TYPE_IN_PUMP - lldebugs << "LLPumpIO::addChain() " << chain[0] << " '" - << typeid(*(chain[0])).name() << "'" << llendl; + LL_DEBUGS() << "LLPumpIO::addChain() " << chain[0] << " '" + << typeid(*(chain[0])).name() << "'" << LL_ENDL; #else - lldebugs << "LLPumpIO::addChain() " << chain[0] <reqevents) :"null") + LL_DEBUGS() << "Setting conditionals (" << (poll ? events_2_string(poll->reqevents) :"null") << ") " #if LL_DEBUG_PIPE_TYPE_IN_PUMP << "on pipe " << typeid(*pipe).name() #endif - << " at " << pipe << llendl; + << " at " << pipe << LL_ENDL; // remove any matching poll file descriptors for this pipe. LLIOPipe::ptr_t pipe_ptr(pipe); @@ -403,8 +400,8 @@ void LLPumpIO::clearLock(S32 key) // therefore won't be treading into deleted memory. I think we can // also clear the lock on the chain safely since the pump only // reads that value. -#if LL_THREADS_APR - LLScopedLock lock(mChainsMutex); +#if LL_THREADS_PUMPIO + LLMutexLock lock(mChainsMutex); #endif mClearLocks.insert(key); } @@ -443,8 +440,8 @@ void LLPumpIO::pump() pump(DEFAULT_POLL_TIMEOUT); } -static LLFastTimer::DeclareTimer FTM_PUMP_IO("Pump IO"); -static LLFastTimer::DeclareTimer FTM_PUMP_POLL("Pump Poll"); +static LLTrace::BlockTimerStatHandle FTM_PUMP_IO("Pump IO"); +static LLTrace::BlockTimerStatHandle FTM_PUMP_POLL("Pump Poll"); LLPumpIO::current_chain_t LLPumpIO::removeRunningChain(LLPumpIO::current_chain_t& run_chain) { @@ -458,8 +455,8 @@ LLPumpIO::current_chain_t LLPumpIO::removeRunningChain(LLPumpIO::current_chain_t //timeout is in microseconds void LLPumpIO::pump(const S32& poll_timeout) { - LLFastTimer t1(FTM_PUMP_IO); - //llinfos << "LLPumpIO::pump()" << llendl; + LL_RECORD_BLOCK_TIME(FTM_PUMP_IO); + //LL_INFOS() << "LLPumpIO::pump()" << LL_ENDL; // Run any pending runners. mRunner.run(); @@ -469,8 +466,8 @@ void LLPumpIO::pump(const S32& poll_timeout) PUMP_DEBUG; if(true) { -#if LL_THREADS_APR - LLScopedLock lock(mChainsMutex); +#if LL_THREADS_PUMPIO + LLMutexLock lock(mChainsMutex); #endif // bail if this pump is paused. if(PAUSING == mState) @@ -487,7 +484,7 @@ void LLPumpIO::pump(const S32& poll_timeout) if(!mPendingChains.empty()) { PUMP_DEBUG; - //lldebugs << "Pushing " << mPendingChains.size() << "." << llendl; + //LL_DEBUGS() << "Pushing " << mPendingChains.size() << "." << LL_ENDL; std::copy( mPendingChains.begin(), mPendingChains.end(), @@ -535,11 +532,11 @@ void LLPumpIO::pump(const S32& poll_timeout) if(mPollset) { PUMP_DEBUG; - //llinfos << "polling" << llendl; + //LL_INFOS() << "polling" << LL_ENDL; S32 count = 0; S32 client_id = 0; { - LLFastTimer _(FTM_PUMP_POLL); + LL_RECORD_BLOCK_TIME(FTM_PUMP_POLL); apr_pollset_poll(mPollset, poll_timeout, &count, &poll_fd); } PUMP_DEBUG; @@ -557,7 +554,7 @@ void LLPumpIO::pump(const S32& poll_timeout) signal_client_t::iterator not_signalled = signalled_client.end(); // Process everything as appropriate - //lldebugs << "Running chain count: " << mRunningChains.size() << llendl; + //LL_DEBUGS() << "Running chain count: " << mRunningChains.size() << LL_ENDL; running_chains_t::iterator run_chain = mRunningChains.begin(); bool process_this_chain = false; while( run_chain != mRunningChains.end() ) @@ -577,9 +574,9 @@ void LLPumpIO::pump(const S32& poll_timeout) && (*run_chain).mTimer.hasExpired()) { PUMP_DEBUG; - llinfos << "Error handler forgot to reset timeout. " + LL_INFOS() << "Error handler forgot to reset timeout. " << "Resetting to " << DEFAULT_CHAIN_EXPIRY_SECS - << " seconds." << llendl; + << " seconds." << LL_ENDL; (*run_chain).setTimeoutSeconds(DEFAULT_CHAIN_EXPIRY_SECS); } } @@ -589,15 +586,15 @@ void LLPumpIO::pump(const S32& poll_timeout) // it timed out and no one handled it, so we need to // retire the chain #if LL_DEBUG_PIPE_TYPE_IN_PUMP - lldebugs << "Removing chain " + LL_DEBUGS() << "Removing chain " << (*run_chain).mChainLinks[0].mPipe << " '" << typeid(*((*run_chain).mChainLinks[0].mPipe)).name() - << "' because it timed out." << llendl; + << "' because it timed out." << LL_ENDL; #else -// lldebugs << "Removing chain " +// LL_DEBUGS() << "Removing chain " // << (*run_chain).mChainLinks[0].mPipe -// << " because we reached the end." << llendl; +// << " because we reached the end." << LL_ENDL; #endif run_chain = removeRunningChain(run_chain); continue; @@ -622,12 +619,12 @@ void LLPumpIO::pump(const S32& poll_timeout) { // if there are no conditionals, just process this chain. process_this_chain = true; - //lldebugs << "no conditionals - processing" << llendl; + //LL_DEBUGS() << "no conditionals - processing" << LL_ENDL; } else { PUMP_DEBUG; - //lldebugs << "checking conditionals" << llendl; + //LL_DEBUGS() << "checking conditionals" << LL_ENDL; // Check if this run chain was signalled. If any file // descriptor is ready for something, then go ahead and // process this chian. @@ -667,7 +664,7 @@ void LLPumpIO::pump(const S32& poll_timeout) error_status = LLIOPipe::STATUS_ERROR; if(handleChainError(*run_chain, error_status)) break; ll_debug_poll_fd("Removing pipe", poll); - llwarns << "Removing pipe " + LL_WARNS() << "Removing pipe " << (*run_chain).mChainLinks[0].mPipe << " '" #if LL_DEBUG_PIPE_TYPE_IN_PUMP @@ -676,7 +673,7 @@ void LLPumpIO::pump(const S32& poll_timeout) #endif << "' because: " << events_2_string(poll->rtnevents) - << llendl; + << LL_ENDL; (*run_chain).mHead = (*run_chain).mChainLinks.end(); break; } @@ -704,13 +701,13 @@ void LLPumpIO::pump(const S32& poll_timeout) if((*run_chain).mHead == (*run_chain).mChainLinks.end()) { #if LL_DEBUG_PIPE_TYPE_IN_PUMP - lldebugs << "Removing chain " << (*run_chain).mChainLinks[0].mPipe + LL_DEBUGS() << "Removing chain " << (*run_chain).mChainLinks[0].mPipe << " '" << typeid(*((*run_chain).mChainLinks[0].mPipe)).name() - << "' because we reached the end." << llendl; + << "' because we reached the end." << LL_ENDL; #else -// lldebugs << "Removing chain " << (*run_chain).mChainLinks[0].mPipe -// << " because we reached the end." << llendl; +// LL_DEBUGS() << "Removing chain " << (*run_chain).mChainLinks[0].mPipe +// << " because we reached the end." << LL_ENDL; #endif PUMP_DEBUG; @@ -738,8 +735,8 @@ void LLPumpIO::pump(const S32& poll_timeout) //bool LLPumpIO::respond(const chain_t& pipes) //{ -//#if LL_THREADS_APR -// LLScopedLock lock(mCallbackMutex); +//#if LL_THREADS_PUMPIO +// LLMutexLock lock(mCallbackMutex); //#endif // LLChainInfo info; // links_t links; @@ -752,8 +749,8 @@ bool LLPumpIO::respond(LLIOPipe* pipe) { if(NULL == pipe) return false; -#if LL_THREADS_APR - LLScopedLock lock(mCallbackMutex); +#if LL_THREADS_PUMPIO + LLMutexLock lock(mCallbackMutex); #endif LLChainInfo info; LLLinkInfo link; @@ -773,8 +770,8 @@ bool LLPumpIO::respond( if(!data) return false; if(links.empty()) return false; -#if LL_THREADS_APR - LLScopedLock lock(mCallbackMutex); +#if LL_THREADS_PUMPIO + LLMutexLock lock(mCallbackMutex); #endif // Add the callback response @@ -786,15 +783,15 @@ bool LLPumpIO::respond( return true; } -static LLFastTimer::DeclareTimer FTM_PUMP_CALLBACK_CHAIN("Chain"); +static LLTrace::BlockTimerStatHandle FTM_PUMP_CALLBACK_CHAIN("Chain"); void LLPumpIO::callback() { - //llinfos << "LLPumpIO::callback()" << llendl; + //LL_INFOS() << "LLPumpIO::callback()" << LL_ENDL; if(true) { -#if LL_THREADS_APR - LLScopedLock lock(mCallbackMutex); +#if LL_THREADS_PUMPIO + LLMutexLock lock(mCallbackMutex); #endif std::copy( mPendingCallbacks.begin(), @@ -808,7 +805,7 @@ void LLPumpIO::callback() callbacks_t::iterator end = mCallbacks.end(); for(; it != end; ++it) { - LLFastTimer t(FTM_PUMP_CALLBACK_CHAIN); + LL_RECORD_BLOCK_TIME(FTM_PUMP_CALLBACK_CHAIN); // it's always the first and last time for respone chains (*it).mHead = (*it).mChainLinks.begin(); (*it).mInit = true; @@ -821,8 +818,8 @@ void LLPumpIO::callback() void LLPumpIO::control(LLPumpIO::EControl op) { -#if LL_THREADS_APR - LLScopedLock lock(mChainsMutex); +#if LL_THREADS_PUMPIO + LLMutexLock lock(mChainsMutex); #endif switch(op) { @@ -838,22 +835,19 @@ void LLPumpIO::control(LLPumpIO::EControl op) } } -void LLPumpIO::initialize(void) +LLAPRPool& LLPumpIO::initPool() { - mPool.create(); -#if LL_THREADS_APR - // SJB: Windows defaults to NESTED and OSX defaults to UNNESTED, so use UNNESTED explicitly. - apr_thread_mutex_create(&mChainsMutex, APR_THREAD_MUTEX_UNNESTED, mPool()); - apr_thread_mutex_create(&mCallbackMutex, APR_THREAD_MUTEX_UNNESTED, mPool()); -#endif + if (!mPool) + mPool.create(); + return mPool; } void LLPumpIO::rebuildPollset() { -// lldebugs << "LLPumpIO::rebuildPollset()" << llendl; +// LL_DEBUGS() << "LLPumpIO::rebuildPollset()" << LL_ENDL; if(mPollset) { - //lldebugs << "destroying pollset" << llendl; + //LL_DEBUGS() << "destroying pollset" << LL_ENDL; apr_pollset_destroy(mPollset); mPollset = NULL; } @@ -864,7 +858,7 @@ void LLPumpIO::rebuildPollset() { size += (*run_it).mDescriptors.size(); } - //lldebugs << "found " << size << " descriptors." << llendl; + //LL_DEBUGS() << "found " << size << " descriptors." << LL_ENDL; if(size) { // Recycle the memory pool @@ -909,10 +903,10 @@ void LLPumpIO::processChain(LLChainInfo& chain) { #if LL_DEBUG_PROCESS_LINK #if LL_DEBUG_PIPE_TYPE_IN_PUMP - llinfos << "Processing " << typeid(*((*it).mPipe)).name() << "." - << llendl; + LL_INFOS() << "Processing " << typeid(*((*it).mPipe)).name() << "." + << LL_ENDL; #else - llinfos << "Processing link " << (*it).mPipe << "." << llendl; + LL_INFOS() << "Processing link " << (*it).mPipe << "." << LL_ENDL; #endif #endif #if LL_DEBUG_SPEW_BUFFER_CHANNEL_IN @@ -929,15 +923,15 @@ void LLPumpIO::processChain(LLChainInfo& chain) (U8*)buf, bytes); buf[bytes] = '\0'; - llinfos << "CHANNEL IN(" << (*it).mChannels.in() << "): " - << buf << llendl; + LL_INFOS() << "CHANNEL IN(" << (*it).mChannels.in() << "): " + << buf << LL_ENDL; delete[] buf; buf = NULL; } else { - llinfos << "CHANNEL IN(" << (*it).mChannels.in()<< "): (null)" - << llendl; + LL_INFOS() << "CHANNEL IN(" << (*it).mChannels.in()<< "): (null)" + << LL_ENDL; } } #endif @@ -962,15 +956,15 @@ void LLPumpIO::processChain(LLChainInfo& chain) (U8*)buf, bytes); buf[bytes] = '\0'; - llinfos << "CHANNEL OUT(" << (*it).mChannels.out()<< "): " - << buf << llendl; + LL_INFOS() << "CHANNEL OUT(" << (*it).mChannels.out()<< "): " + << buf << LL_ENDL; delete[] buf; buf = NULL; } else { - llinfos << "CHANNEL OUT(" << (*it).mChannels.out()<< "): (null)" - << llendl; + LL_INFOS() << "CHANNEL OUT(" << (*it).mChannels.out()<< "): (null)" + << LL_ENDL; } } #endif @@ -980,11 +974,11 @@ void LLPumpIO::processChain(LLChainInfo& chain) // below. if(LLIOPipe::isSuccess(status)) { - llinfos << "Pipe returned: '" + LL_INFOS() << "Pipe returned: '" #if LL_DEBUG_PIPE_TYPE_IN_PUMP << typeid(*((*it).mPipe)).name() << "':'" #endif - << LLIOPipe::lookupStatusString(status) << "'" << llendl; + << LLIOPipe::lookupStatusString(status) << "'" << LL_ENDL; } #endif @@ -1024,12 +1018,12 @@ void LLPumpIO::processChain(LLChainInfo& chain) PUMP_DEBUG; if(LLIOPipe::isError(status)) { - llinfos << "Pump generated pipe err: '" + LL_INFOS() << "Pump generated pipe err: '" #if LL_DEBUG_PIPE_TYPE_IN_PUMP << typeid(*((*it).mPipe)).name() << "':'" #endif << LLIOPipe::lookupStatusString(status) - << "'" << llendl; + << "'" << LL_ENDL; #if LL_DEBUG_SPEW_BUFFER_CHANNEL_IN_ON_ERROR if(chain.mData) { @@ -1046,18 +1040,18 @@ void LLPumpIO::processChain(LLChainInfo& chain) (U8*)buf, bytes); buf[bytes] = '\0'; - llinfos << "Input After Error: " << buf << llendl; + LL_INFOS() << "Input After Error: " << buf << LL_ENDL; delete[] buf; buf = NULL; } else { - llinfos << "Input After Error: (null)" << llendl; + LL_INFOS() << "Input After Error: (null)" << LL_ENDL; } } else { - llinfos << "Input After Error: (null)" << llendl; + LL_INFOS() << "Input After Error: (null)" << LL_ENDL; } #endif keep_going = false; @@ -1069,8 +1063,8 @@ void LLPumpIO::processChain(LLChainInfo& chain) } else { - llinfos << "Unhandled status code: " << status << ":" - << LLIOPipe::lookupStatusString(status) << llendl; + LL_INFOS() << "Unhandled status code: " << status << ":" + << LLIOPipe::lookupStatusString(status) << LL_ENDL; } break; } @@ -1119,8 +1113,8 @@ bool LLPumpIO::handleChainError( do { #if LL_DEBUG_PIPE_TYPE_IN_PUMP - lldebugs << "Passing error to " << typeid(*((*rit).mPipe)).name() - << "." << llendl; + LL_DEBUGS() << "Passing error to " << typeid(*((*rit).mPipe)).name() + << "." << LL_ENDL; #endif error = (*rit).mPipe->handleError(error, this); switch(error) @@ -1134,8 +1128,8 @@ bool LLPumpIO::handleChainError( case LLIOPipe::STATUS_BREAK: case LLIOPipe::STATUS_NEED_PROCESS: #if LL_DEBUG_PIPE_TYPE_IN_PUMP - lldebugs << "Pipe " << typeid(*((*rit).mPipe)).name() - << " returned code to stop error handler." << llendl; + LL_DEBUGS() << "Pipe " << typeid(*((*rit).mPipe)).name() + << " returned code to stop error handler." << LL_ENDL; #endif keep_going = false; break; @@ -1145,8 +1139,8 @@ bool LLPumpIO::handleChainError( default: if(LLIOPipe::isSuccess(error)) { - llinfos << "Unhandled status code: " << error << ":" - << LLIOPipe::lookupStatusString(error) << llendl; + LL_INFOS() << "Unhandled status code: " << error << ":" + << LLIOPipe::lookupStatusString(error) << LL_ENDL; error = LLIOPipe::STATUS_ERROR; keep_going = false; } diff --git a/indra/llmessage/llpumpio.h b/indra/llmessage/llpumpio.h index 0d13872575..309792c803 100644 --- a/indra/llmessage/llpumpio.h +++ b/indra/llmessage/llpumpio.h @@ -42,7 +42,7 @@ #include "llrun.h" // Define this to enable use with the APR thread library. -//#define LL_THREADS_APR 1 +//#define LL_THREADS_PUMPIO 1 // some simple constants to help with timeouts extern const F32 DEFAULT_CHAIN_EXPIRY_SECS; @@ -382,16 +382,13 @@ class LLPumpIO LLAPRPool mCurrentPool; S32 mCurrentPoolReallocCount; -#if LL_THREADS_APR - apr_thread_mutex_t* mChainsMutex; - apr_thread_mutex_t* mCallbackMutex; -#else - int* mChainsMutex; - int* mCallbackMutex; +#if LL_THREADS_PUMPIO + LLMutex mChainsMutex; + LLMutex mCallbackMutex; #endif protected: - void initialize(); + LLAPRPool& initPool(); current_chain_t removeRunningChain(current_chain_t& chain) ; /** diff --git a/indra/llmessage/llregionflags.h b/indra/llmessage/llregionflags.h index 8d51207a95..95faff21b0 100644 --- a/indra/llmessage/llregionflags.h +++ b/indra/llmessage/llregionflags.h @@ -42,6 +42,9 @@ const U64 REGION_FLAGS_RESET_HOME_ON_TELEPORT = (1 << 3); // Does the sun move? const U64 REGION_FLAGS_SUN_FIXED = (1 << 4); +// Does the estate owner allow private parcels? +const U64 REGION_FLAGS_ALLOW_ACCESS_OVERRIDE = (1 << 5); + // Can't change the terrain heightfield, even on owned parcels, // but can plant trees and grass. const U64 REGION_FLAGS_BLOCK_TERRAFORM = (1 << 6); @@ -51,6 +54,9 @@ const U64 REGION_FLAGS_BLOCK_LAND_RESELL = (1 << 7); // All content wiped once per night const U64 REGION_FLAGS_SANDBOX = (1 << 8); + +const U64 REGION_FLAGS_ALLOW_ENVIRONMENT_OVERRIDE = (1 << 9); + const U64 REGION_FLAGS_GAMING = (1 << 10); // Denotes a gaming region on certain grids const U64 REGION_FLAGS_HIDE_FROM_SEARCH = (1 << 11); // Hides region from search on certain grids const U64 REGION_FLAGS_SKIP_COLLISIONS = (1 << 12); // Pin all non agent rigid bodies @@ -78,6 +84,8 @@ const U64 REGION_FLAGS_DENY_ANONYMOUS = (1 << 23); const U64 REGION_FLAGS_ALLOW_PARCEL_CHANGES = (1 << 26); +const U64 REGION_FLAGS_BLOCK_FLYOVER = (1 << 27); + const U64 REGION_FLAGS_ALLOW_VOICE = (1 << 28); const U64 REGION_FLAGS_BLOCK_PARCEL_SEARCH = (1 << 29); @@ -160,21 +168,22 @@ const U32 ESTATE_ACCESS_ALL = ESTATE_ACCESS_ALLOWED_AGENTS | ESTATE_ACCESS_BANNED_AGENTS | ESTATE_ACCESS_MANAGERS; -// for EstateOwnerRequest, estateaccessdelta message -const U32 ESTATE_ACCESS_APPLY_TO_ALL_ESTATES = 1 << 0; -const U32 ESTATE_ACCESS_APPLY_TO_MANAGED_ESTATES = 1 << 1; - -const U32 ESTATE_ACCESS_ALLOWED_AGENT_ADD = 1 << 2; -const U32 ESTATE_ACCESS_ALLOWED_AGENT_REMOVE = 1 << 3; -const U32 ESTATE_ACCESS_ALLOWED_GROUP_ADD = 1 << 4; -const U32 ESTATE_ACCESS_ALLOWED_GROUP_REMOVE = 1 << 5; -const U32 ESTATE_ACCESS_BANNED_AGENT_ADD = 1 << 6; -const U32 ESTATE_ACCESS_BANNED_AGENT_REMOVE = 1 << 7; -const U32 ESTATE_ACCESS_MANAGER_ADD = 1 << 8; -const U32 ESTATE_ACCESS_MANAGER_REMOVE = 1 << 9; -const U32 ESTATE_ACCESS_NO_REPLY = 1 << 10; - -const S32 ESTATE_MAX_MANAGERS = 10; +// for EstateOwnerRequest, estateaccessdelta, estateexperiencedelta messages +const U32 ESTATE_ACCESS_APPLY_TO_ALL_ESTATES = 1U << 0; +const U32 ESTATE_ACCESS_APPLY_TO_MANAGED_ESTATES = 1U << 1; + +const U32 ESTATE_ACCESS_ALLOWED_AGENT_ADD = 1U << 2; +const U32 ESTATE_ACCESS_ALLOWED_AGENT_REMOVE = 1U << 3; +const U32 ESTATE_ACCESS_ALLOWED_GROUP_ADD = 1U << 4; +const U32 ESTATE_ACCESS_ALLOWED_GROUP_REMOVE = 1U << 5; +const U32 ESTATE_ACCESS_BANNED_AGENT_ADD = 1U << 6; +const U32 ESTATE_ACCESS_BANNED_AGENT_REMOVE = 1U << 7; +const U32 ESTATE_ACCESS_MANAGER_ADD = 1U << 8; +const U32 ESTATE_ACCESS_MANAGER_REMOVE = 1U << 9; +const U32 ESTATE_ACCESS_NO_REPLY = 1U << 10; +const U32 ESTATE_ACCESS_FAILED_BAN_ESTATE_MANAGER = 1U << 11; + +const S32 ESTATE_MAX_MANAGERS = 15; const S32 ESTATE_MAX_ACCESS_IDS = 500; // max for access, banned const S32 ESTATE_MAX_GROUP_IDS = (S32) ESTATE_ACCESS_MAX_ENTRIES_PER_PACKET; @@ -183,6 +192,26 @@ const U32 SWD_OTHERS_LAND_ONLY = (1 << 0); const U32 SWD_ALWAYS_RETURN_OBJECTS = (1 << 1); const U32 SWD_SCRIPTED_ONLY = (1 << 2); +// Controls experience key validity in the estate +const U32 EXPERIENCE_KEY_TYPE_NONE = 0; +const U32 EXPERIENCE_KEY_TYPE_BLOCKED = 1; +const U32 EXPERIENCE_KEY_TYPE_ALLOWED = 2; +const U32 EXPERIENCE_KEY_TYPE_TRUSTED = 3; + +const U32 EXPERIENCE_KEY_TYPE_FIRST = EXPERIENCE_KEY_TYPE_BLOCKED; +const U32 EXPERIENCE_KEY_TYPE_LAST = EXPERIENCE_KEY_TYPE_TRUSTED; + +// +const U32 ESTATE_EXPERIENCE_TRUSTED_ADD = 1U << 2; +const U32 ESTATE_EXPERIENCE_TRUSTED_REMOVE = 1U << 3; +const U32 ESTATE_EXPERIENCE_ALLOWED_ADD = 1U << 4; +const U32 ESTATE_EXPERIENCE_ALLOWED_REMOVE = 1U << 5; +const U32 ESTATE_EXPERIENCE_BLOCKED_ADD = 1U << 6; +const U32 ESTATE_EXPERIENCE_BLOCKED_REMOVE = 1U << 7; + +const S32 ESTATE_MAX_EXPERIENCE_IDS = 8; + + #endif diff --git a/indra/llmessage/llregionhandle.h b/indra/llmessage/llregionhandle.h index c77794e4b8..085757dcbc 100644 --- a/indra/llmessage/llregionhandle.h +++ b/indra/llmessage/llregionhandle.h @@ -68,21 +68,21 @@ inline BOOL to_region_handle(const F32 x_pos, const F32 y_pos, U64 *region_handl U32 x_int, y_int; if (x_pos < 0.f) { -// llwarns << "to_region_handle:Clamping negative x position " << x_pos << " to zero!" << llendl; +// LL_WARNS() << "to_region_handle:Clamping negative x position " << x_pos << " to zero!" << LL_ENDL; return FALSE; } else { - x_int = (U32)llround(x_pos); + x_int = (U32)ll_round(x_pos); } if (y_pos < 0.f) { -// llwarns << "to_region_handle:Clamping negative y position " << y_pos << " to zero!" << llendl; +// LL_WARNS() << "to_region_handle:Clamping negative y position " << y_pos << " to zero!" << LL_ENDL; return FALSE; } else { - y_int = (U32)llround(y_pos); + y_int = (U32)ll_round(y_pos); } *region_handle = to_region_handle(x_int, y_int); return TRUE; diff --git a/indra/llmessage/llsdappservices.cpp b/indra/llmessage/llsdappservices.cpp index 8bab91b0c0..4103ece33a 100644 --- a/indra/llmessage/llsdappservices.cpp +++ b/indra/llmessage/llsdappservices.cpp @@ -119,8 +119,8 @@ class LLHTTPConfigRuntimeSingleService : public LLHTTPNode virtual bool validate(const std::string& name, LLSD& context) const { - //llinfos << "validate: " << name << ", " - // << LLSDOStreamer(context) << llendl; + //LL_INFOS() << "validate: " << name << ", " + // << LLSDOStreamer(context) << LL_ENDL; if((std::string("PUT") == context["request"]["verb"].asString()) && !name.empty()) { return true; @@ -257,8 +257,8 @@ class LLHTTPLiveConfigSingleService : public LLHTTPNode virtual bool validate(const std::string& name, LLSD& context) const { - llinfos << "LLHTTPLiveConfigSingleService::validate(" << name - << ")" << llendl; + LL_INFOS() << "LLHTTPLiveConfigSingleService::validate(" << name + << ")" << LL_ENDL; LLSD option = LLApp::instance()->getOption(name); if(option.isDefined()) return true; else return false; diff --git a/indra/llmessage/llsdmessage.cpp b/indra/llmessage/llsdmessage.cpp index dc091a543a..1841207eab 100644 --- a/indra/llmessage/llsdmessage.cpp +++ b/indra/llmessage/llsdmessage.cpp @@ -99,14 +99,14 @@ void LLSDMessage::EventResponder::setTimeoutPolicy(std::string const& name) mHTTPTimeoutPolicy = AIHTTPTimeoutPolicy::getTimeoutPolicyByName(name); } -void LLSDMessage::EventResponder::result(const LLSD& data) +void LLSDMessage::EventResponder::httpSuccess(void) { // If our caller passed an empty replyPump name, they're not // listening: this is a fire-and-forget message. Don't bother posting // to the pump whose name is "". if (! mReplyPump.empty()) { - LLSD response(data); + LLSD response(mContent); mReqID.stamp(response); mPumps.obtain(mReplyPump).post(response); } @@ -118,7 +118,7 @@ void LLSDMessage::EventResponder::result(const LLSD& data) } } -void LLSDMessage::EventResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void LLSDMessage::EventResponder::httpFailure(void) { // If our caller passed an empty errorPump name, they're not // listening: "default error handling is acceptable." Only post to an @@ -129,9 +129,9 @@ void LLSDMessage::EventResponder::errorWithContent(U32 status, const std::string info["target"] = mTarget; info["message"] = mMessage; info["code"] = mCode; - info["status"] = LLSD::Integer(status); - info["reason"] = reason; - info["content"] = content; + info["status"] = LLSD::Integer(mStatus); + info["reason"] = mReason; + info["content"] = mContent; mPumps.obtain(mErrorPump).post(info); } else // default error handling @@ -139,8 +139,8 @@ void LLSDMessage::EventResponder::errorWithContent(U32 status, const std::string // convention seems to be to use llinfos, but that seems a bit casual? LL_WARNS("LLSDMessage::EventResponder") << "'" << mMessage << "' to '" << mTarget - << "' failed with code " << status << ": " << reason << '\n' - << ll_pretty_print_sd(content) + << "' failed with code " << mStatus << ": " << mReason << '\n' + << ll_pretty_print_sd(mContent) << LL_ENDL; } } @@ -165,15 +165,15 @@ bool LLSDMessage::ResponderAdapter::listener(const LLSD& payload, bool success) LLHTTPClient::ResponderWithResult* responder = dynamic_cast(mResponder.get()); // If this assertion fails then ResponderAdapter has been used for a ResponderWithCompleted derived class, // which is not allowed because ResponderAdapter can only work for classes derived from Responder that - // implement result() and errorWithContent (or just error). + // implement httpSuccess() and httpFailure(). llassert_always(responder); if (success) { - responder->pubResult(payload); + responder->successResult(payload); } else { - responder->pubErrorWithContent((CURLcode)payload["code"].asInteger(), payload["status"].asInteger(), payload["reason"], payload["content"]); + responder->failureResult(payload["status"].asInteger(), payload["reason"], payload["content"], (CURLcode)payload["code"].asInteger()); } /*---------------- MUST BE LAST STATEMENT BEFORE RETURN ----------------*/ diff --git a/indra/llmessage/llsdmessage.h b/indra/llmessage/llsdmessage.h index 6e7530ddba..bd99fdb9e2 100644 --- a/indra/llmessage/llsdmessage.h +++ b/indra/llmessage/llsdmessage.h @@ -156,8 +156,8 @@ class LLSDMessage void setTimeoutPolicy(std::string const& name); - /*virtual*/ void result(const LLSD& data); - /*virtual*/ void errorWithContent(U32 status, const std::string& reason, const LLSD& content); + /*virtual*/ void httpSuccess(void); + /*virtual*/ void httpFailure(void); /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return *mHTTPTimeoutPolicy; } /*virtual*/ char const* getName(void) const { return "EventResponder"; } diff --git a/indra/llmessage/llsdmessagebuilder.cpp b/indra/llmessage/llsdmessagebuilder.cpp index 615221e0ad..d65ab1bcf7 100644 --- a/indra/llmessage/llsdmessagebuilder.cpp +++ b/indra/llmessage/llsdmessagebuilder.cpp @@ -91,17 +91,10 @@ void LLSDMessageBuilder::nextBlock(const char* blockname) } else { - llerrs << "existing block not array" << llendl; + LL_ERRS() << "existing block not array" << LL_ENDL; } } -// TODO: Remove this horror... -BOOL LLSDMessageBuilder::removeLastBlock() -{ - /* TODO: finish implementing this */ - return FALSE; -} - void LLSDMessageBuilder::addBinaryData( const char* varname, const void* data, @@ -264,7 +257,7 @@ void LLSDMessageBuilder::copyFromMessageData(const LLMsgData& data) for(; dit != dend; ++dit) { - const LLMsgVarData& mvci = *dit; + const LLMsgVarData& mvci = mbci->mMemberVarData.toValue(dit); const char* varname = mvci.getName(); switch(mvci.getType()) @@ -380,7 +373,7 @@ void LLSDMessageBuilder::copyFromMessageData(const LLMsgData& data) break; default: - llwarns << "Unknown type in conversion of message to LLSD" << llendl; + LL_WARNS() << "Unknown type in conversion of message to LLSD" << LL_ENDL; break; } } @@ -391,7 +384,7 @@ void LLSDMessageBuilder::copyFromMessageData(const LLMsgData& data) void LLSDMessageBuilder::copyFromLLSD(const LLSD& msg) { mCurrentMessage = msg; - lldebugs << LLSDNotationStreamer(mCurrentMessage) << llendl; + LL_DEBUGS() << LLSDNotationStreamer(mCurrentMessage) << LL_ENDL; } const LLSD& LLSDMessageBuilder::getMessage() const diff --git a/indra/llmessage/llsdmessagebuilder.h b/indra/llmessage/llsdmessagebuilder.h index 9c7c1bfde3..18c8588881 100644 --- a/indra/llmessage/llsdmessagebuilder.h +++ b/indra/llmessage/llsdmessagebuilder.h @@ -48,7 +48,6 @@ class LLSDMessageBuilder : public LLMessageBuilder virtual void newMessage(const char* name); virtual void nextBlock(const char* blockname); - virtual BOOL removeLastBlock(); // TODO: babbage: remove this horror... /** All add* methods expect pointers to canonical varname strings. */ virtual void addBinaryData( diff --git a/indra/llmessage/llsdmessagereader.cpp b/indra/llmessage/llsdmessagereader.cpp index 3d8ca2ad9f..a3085cbf57 100644 --- a/indra/llmessage/llsdmessagereader.cpp +++ b/indra/llmessage/llsdmessagereader.cpp @@ -57,12 +57,12 @@ LLSD getLLSD(const LLSD& input, const char* block, const char* var, S32 blocknum // LLTemplateMessageReader::getData behaviour if(NULL == block) { - llerrs << "NULL block name" << llendl; + LL_ERRS() << "NULL block name" << LL_ENDL; return LLSD(); } if(NULL == var) { - llerrs << "NULL var name" << llendl; + LL_ERRS() << "NULL var name" << LL_ENDL; return LLSD(); } if(! input[block].isArray()) @@ -70,7 +70,7 @@ LLSD getLLSD(const LLSD& input, const char* block, const char* var, S32 blocknum // NOTE: babbage: need to return default for missing blocks to allow // backwards/forwards compatibility - handlers must cope with default // values. - llwarns << "block " << block << " not found" << llendl; + LL_WARNS() << "block " << block << " not found" << LL_ENDL; return LLSD(); } @@ -80,7 +80,7 @@ LLSD getLLSD(const LLSD& input, const char* block, const char* var, S32 blocknum // NOTE: babbage: need to return default for missing vars to allow // backwards/forwards compatibility - handlers must cope with default // values. - llwarns << "var " << var << " not found" << llendl; + LL_WARNS() << "var " << var << " not found" << LL_ENDL; } return result; } @@ -238,7 +238,7 @@ void LLSDMessageReader::getString(const char *block, const char *var, { if(buffer_size <= 0) { - llwarns << "buffer_size <= 0" << llendl; + LL_WARNS() << "buffer_size <= 0" << LL_ENDL; return; } std::string data = getLLSD(mMessage, block, var, blocknum); diff --git a/indra/llmessage/lltemplatemessagebuilder.cpp b/indra/llmessage/lltemplatemessagebuilder.cpp index 9e8eb48460..ccc57796bb 100644 --- a/indra/llmessage/lltemplatemessagebuilder.cpp +++ b/indra/llmessage/lltemplatemessagebuilder.cpp @@ -81,7 +81,7 @@ void LLTemplateMessageBuilder::newMessage(const char *name) if (msg_template->getDeprecation() != MD_NOTDEPRECATED) { - llwarns << "Sending deprecated message " << namep << llendl; + LL_WARNS() << "Sending deprecated message " << namep << LL_ENDL; } LLMessageTemplate::message_block_map_t::const_iterator iter; @@ -89,14 +89,14 @@ void LLTemplateMessageBuilder::newMessage(const char *name) iter != msg_template->mMemberBlocks.end(); ++iter) { - LLMessageBlock* ci = *iter; + const LLMessageBlock* ci = msg_template->mMemberBlocks.toValue(iter); LLMsgBlkData* tblockp = new LLMsgBlkData(ci->mName, 0); mCurrentSMessageData->addBlock(tblockp); } } else { - llerrs << "newMessage - Message " << name << " not registered" << llendl; + LL_ERRS() << "newMessage - Message " << name << " not registered" << LL_ENDL; } } @@ -125,7 +125,7 @@ void LLTemplateMessageBuilder::nextBlock(const char* blockname) if (!mCurrentSMessageTemplate) { - llerrs << "newMessage not called prior to setBlock" << llendl; + LL_ERRS() << "newMessage not called prior to setBlock" << LL_ENDL; return; } @@ -133,8 +133,8 @@ void LLTemplateMessageBuilder::nextBlock(const char* blockname) const LLMessageBlock* template_data = mCurrentSMessageTemplate->getBlock(bnamep); if (!template_data) { - llerrs << "LLTemplateMessageBuilder::nextBlock " << bnamep - << " not a block in " << mCurrentSMessageTemplate->mName << llendl; + LL_ERRS() << "LLTemplateMessageBuilder::nextBlock " << bnamep + << " not a block in " << mCurrentSMessageTemplate->mName << LL_ENDL; return; } @@ -151,8 +151,8 @@ void LLTemplateMessageBuilder::nextBlock(const char* blockname) for (LLMessageBlock::message_variable_map_t::const_iterator iter = template_data->mMemberVariables.begin(); iter != template_data->mMemberVariables.end(); iter++) { - LLMessageVariable& ci = **iter; - mCurrentSDataBlock->addVariable(ci.getName(), ci.getType()); + const LLMessageVariable* ci = template_data->mMemberVariables.toValue(iter); + mCurrentSDataBlock->addVariable(ci->getName(), ci->getType()); } return; } @@ -164,8 +164,8 @@ void LLTemplateMessageBuilder::nextBlock(const char* blockname) // if the block is type MBT_SINGLE this is bad! if (template_data->mType == MBT_SINGLE) { - llerrs << "LLTemplateMessageBuilder::nextBlock called multiple times" - << " for " << bnamep << " but is type MBT_SINGLE" << llendl; + LL_ERRS() << "LLTemplateMessageBuilder::nextBlock called multiple times" + << " for " << bnamep << " but is type MBT_SINGLE" << LL_ENDL; return; } @@ -175,10 +175,10 @@ void LLTemplateMessageBuilder::nextBlock(const char* blockname) if ( (template_data->mType == MBT_MULTIPLE) &&(mCurrentSDataBlock->mBlockNumber == template_data->mNumber)) { - llerrs << "LLTemplateMessageBuilder::nextBlock called " + LL_ERRS() << "LLTemplateMessageBuilder::nextBlock called " << mCurrentSDataBlock->mBlockNumber << " times for " << bnamep << " exceeding " << template_data->mNumber - << " specified in type MBT_MULTIPLE." << llendl; + << " specified in type MBT_MULTIPLE." << LL_ENDL; return; } @@ -191,8 +191,8 @@ void LLTemplateMessageBuilder::nextBlock(const char* blockname) if (block_data->mBlockNumber > MAX_BLOCKS) { - llerrs << "Trying to pack too many blocks into MBT_VARIABLE type " - << "(limited to " << MAX_BLOCKS << ")" << llendl; + LL_ERRS() << "Trying to pack too many blocks into MBT_VARIABLE type " + << "(limited to " << MAX_BLOCKS << ")" << LL_ENDL; } // create new name @@ -212,76 +212,13 @@ void LLTemplateMessageBuilder::nextBlock(const char* blockname) end = template_data->mMemberVariables.end(); iter != end; iter++) { - LLMessageVariable& ci = **iter; - mCurrentSDataBlock->addVariable(ci.getName(), ci.getType()); + const LLMessageVariable* ci = template_data->mMemberVariables.toValue(iter); + mCurrentSDataBlock->addVariable(ci->getName(), ci->getType()); } return; } } -// TODO: Remove this horror... -BOOL LLTemplateMessageBuilder::removeLastBlock() -{ - if (mCurrentSBlockName) - { - if ( (mCurrentSMessageData) - &&(mCurrentSMessageTemplate)) - { - if (mCurrentSMessageData->mMemberBlocks[mCurrentSBlockName]->mBlockNumber >= 1) - { - // At least one block for the current block name. - - // Store the current block name for future reference. - char *block_name = mCurrentSBlockName; - - // Decrement the sent total by the size of the - // data in the message block that we're currently building. - - const LLMessageBlock* template_data = mCurrentSMessageTemplate->getBlock(mCurrentSBlockName); - - for (LLMessageBlock::message_variable_map_t::const_iterator iter = template_data->mMemberVariables.begin(); - iter != template_data->mMemberVariables.end(); iter++) - { - LLMessageVariable& ci = **iter; - mCurrentSendTotal -= ci.getSize(); - } - - - // Now we want to find the block that we're blowing away. - - // Get the number of blocks. - LLMsgBlkData* block_data = mCurrentSMessageData->mMemberBlocks[block_name]; - S32 num_blocks = block_data->mBlockNumber; - - // Use the same (suspect?) algorithm that's used to generate - // the names in the nextBlock method to find it. - char *block_getting_whacked = block_name + num_blocks - 1; - LLMsgBlkData* whacked_data = mCurrentSMessageData->mMemberBlocks[block_getting_whacked]; - delete whacked_data; - mCurrentSMessageData->mMemberBlocks.erase(block_getting_whacked); - - if (num_blocks <= 1) - { - // we just blew away the last one, so return FALSE - llwarns << "not blowing away the only block of message " - << mCurrentSMessageName - << ". Block: " << block_name - << ". Number: " << num_blocks - << llendl; - return FALSE; - } - else - { - // Decrement the counter. - block_data->mBlockNumber--; - return TRUE; - } - } - } - } - return FALSE; -} - // add data to variable in current block void LLTemplateMessageBuilder::addData(const char *varname, const void *data, EMsgVariableType type, S32 size) { @@ -290,14 +227,14 @@ void LLTemplateMessageBuilder::addData(const char *varname, const void *data, EM // do we have a current message? if (!mCurrentSMessageTemplate) { - llerrs << "newMessage not called prior to addData" << llendl; + LL_ERRS() << "newMessage not called prior to addData" << LL_ENDL; return; } // do we have a current block? if (!mCurrentSDataBlock) { - llerrs << "setBlock not called prior to addData" << llendl; + LL_ERRS() << "setBlock not called prior to addData" << LL_ENDL; return; } @@ -305,7 +242,7 @@ void LLTemplateMessageBuilder::addData(const char *varname, const void *data, EM const LLMessageVariable* var_data = mCurrentSMessageTemplate->getBlock(mCurrentSBlockName)->getVariable(vnamep); if (!var_data || !var_data->getName()) { - llerrs << vnamep << " not a variable in block " << mCurrentSBlockName << " of " << mCurrentSMessageTemplate->mName << llendl; + LL_ERRS() << vnamep << " not a variable in block " << mCurrentSBlockName << " of " << mCurrentSMessageTemplate->mName << LL_ENDL; return; } @@ -316,9 +253,9 @@ void LLTemplateMessageBuilder::addData(const char *varname, const void *data, EM if ((var_data->getSize() == 1) && (size > 255)) { - llwarns << "Field " << varname << " is a Variable 1 but program " + LL_WARNS() << "Field " << varname << " is a Variable 1 but program " << "attempted to stuff more than 255 bytes in " - << "(" << size << "). Clamping size and truncating data." << llendl; + << "(" << size << "). Clamping size and truncating data." << LL_ENDL; size = 255; char *truncate = (char *)data; truncate[254] = 0; // array size is 255 but the last element index is 254 @@ -332,8 +269,8 @@ void LLTemplateMessageBuilder::addData(const char *varname, const void *data, EM { if (size != var_data->getSize()) { - llerrs << varname << " is type MVT_FIXED but request size " << size << " doesn't match template size " - << var_data->getSize() << llendl; + LL_ERRS() << varname << " is type MVT_FIXED but request size " << size << " doesn't match template size " + << var_data->getSize() << LL_ENDL; return; } // alright, smash it in @@ -350,14 +287,14 @@ void LLTemplateMessageBuilder::addData(const char *varname, const void *data, EM // do we have a current message? if (!mCurrentSMessageTemplate) { - llerrs << "newMessage not called prior to addData" << llendl; + LL_ERRS() << "newMessage not called prior to addData" << LL_ENDL; return; } // do we have a current block? if (!mCurrentSDataBlock) { - llerrs << "setBlock not called prior to addData" << llendl; + LL_ERRS() << "setBlock not called prior to addData" << LL_ENDL; return; } @@ -365,7 +302,7 @@ void LLTemplateMessageBuilder::addData(const char *varname, const void *data, EM const LLMessageVariable* var_data = mCurrentSMessageTemplate->getBlock(mCurrentSBlockName)->getVariable(vnamep); if (!var_data->getName()) { - llerrs << vnamep << " not a variable in block " << mCurrentSBlockName << " of " << mCurrentSMessageTemplate->mName << llendl; + LL_ERRS() << vnamep << " not a variable in block " << mCurrentSBlockName << " of " << mCurrentSMessageTemplate->mName << LL_ENDL; return; } @@ -373,7 +310,7 @@ void LLTemplateMessageBuilder::addData(const char *varname, const void *data, EM if (var_data->getType() == MVT_VARIABLE) { // nope - llerrs << vnamep << " is type MVT_VARIABLE. Call using addData(name, data, size)" << llendl; + LL_ERRS() << vnamep << " is type MVT_VARIABLE. Call using addData(name, data, size)" << LL_ENDL; return; } else @@ -643,8 +580,8 @@ static S32 buildBlock(U8* buffer, S32 buffer_size, const LLMessageBlock* templat // Just reporting error is likely not enough. Need // to check how to abort or error out gracefully // from this function. XXXTBD - llerrs << "buildBlock failed. Message excedding " - << "sendBuffersize." << llendl; + LL_ERRS() << "buildBlock failed. Message excedding " + << "sendBuffersize." << LL_ENDL; } } else if (template_data->mType == MBT_MULTIPLE) @@ -652,10 +589,10 @@ static S32 buildBlock(U8* buffer, S32 buffer_size, const LLMessageBlock* templat if (block_count != template_data->mNumber) { // nope! need to fill it in all the way! - llerrs << "Block " << mbci->mName + LL_ERRS() << "Block " << mbci->mName << " is type MBT_MULTIPLE but only has data for " << block_count << " out of its " - << template_data->mNumber << " blocks" << llendl; + << template_data->mNumber << " blocks" << LL_ENDL; } } @@ -665,14 +602,14 @@ static S32 buildBlock(U8* buffer, S32 buffer_size, const LLMessageBlock* templat for (LLMsgBlkData::msg_var_data_map_t::const_iterator iter = mbci->mMemberVarData.begin(); iter != mbci->mMemberVarData.end(); iter++) { - const LLMsgVarData& mvci = *iter; + const LLMsgVarData& mvci = mbci->mMemberVarData.toValue(iter); if (mvci.getSize() == -1) { // oops, this variable wasn't ever set! - llerrs << "The variable " << mvci.getName() << " in block " + LL_ERRS() << "The variable " << mvci.getName() << " in block " << mbci->mName << " of message " << template_data->mName - << " wasn't set prior to buildMessage call" << llendl; + << " wasn't set prior to buildMessage call" << LL_ENDL; } else { @@ -699,7 +636,7 @@ static S32 buildBlock(U8* buffer, S32 buffer_size, const LLMessageBlock* templat htonmemcpy(&buffer[result], &size, MVT_S32, 4); break; default: - llerrs << "Attempting to build variable field with unknown size of " << size << llendl; + LL_ERRS() << "Attempting to build variable field with unknown size of " << size << LL_ENDL; break; } result += mvci.getDataSize(); @@ -721,11 +658,11 @@ static S32 buildBlock(U8* buffer, S32 buffer_size, const LLMessageBlock* templat // Just reporting error is likely not // enough. Need to check how to abort or error // out gracefully from this function. XXXTBD - llerrs << "buildBlock failed. " + LL_ERRS() << "buildBlock failed. " << "Attempted to pack " << (result + mvci.getSize()) << " bytes into a buffer with size " - << buffer_size << "." << llendl; + << buffer_size << "." << LL_ENDL; } } } @@ -760,7 +697,7 @@ U32 LLTemplateMessageBuilder::buildMessage( // do we have a current message? if (!mCurrentSMessageTemplate) { - llerrs << "newMessage not called prior to buildMessage" << llendl; + LL_ERRS() << "newMessage not called prior to buildMessage" << LL_ENDL; return 0; } @@ -809,7 +746,7 @@ U32 LLTemplateMessageBuilder::buildMessage( } else { - llerrs << "unexpected message frequency in buildMessage" << llendl; + LL_ERRS() << "unexpected message frequency in buildMessage" << LL_ENDL; return 0; } @@ -821,7 +758,8 @@ U32 LLTemplateMessageBuilder::buildMessage( iter != end; ++iter) { - result += buildBlock(buffer + result, buffer_size - result, *iter, mCurrentSMessageData); + const LLMessageBlock* block = mCurrentSMessageTemplate->mMemberBlocks.toValue(iter); + result += buildBlock(buffer + result, buffer_size - result, block, mCurrentSMessageData); } mbSBuilt = TRUE; @@ -864,7 +802,7 @@ void LLTemplateMessageBuilder::copyFromMessageData(const LLMsgData& data) for(; dit != dend; ++dit) { - const LLMsgVarData& mvci = *dit; + const LLMsgVarData& mvci = mbci->mMemberVarData.toValue(dit); addData(mvci.getName(), mvci.getData(), mvci.getType(), mvci.getSize()); } } diff --git a/indra/llmessage/lltemplatemessagebuilder.h b/indra/llmessage/lltemplatemessagebuilder.h index 4f614a4657..ce743974e9 100644 --- a/indra/llmessage/lltemplatemessagebuilder.h +++ b/indra/llmessage/lltemplatemessagebuilder.h @@ -49,7 +49,6 @@ class LLTemplateMessageBuilder : public LLMessageBuilder virtual void newMessage(const char* name); virtual void nextBlock(const char* blockname); - virtual BOOL removeLastBlock(); // TODO: babbage: remove this horror... /** All add* methods expect pointers to canonical varname strings. */ virtual void addBinaryData(const char *varname, const void *data, diff --git a/indra/llmessage/lltemplatemessagereader.cpp b/indra/llmessage/lltemplatemessagereader.cpp index bfce2ea298..306737fb70 100644 --- a/indra/llmessage/lltemplatemessagereader.cpp +++ b/indra/llmessage/lltemplatemessagereader.cpp @@ -68,13 +68,13 @@ void LLTemplateMessageReader::getData(const char *blockname, const char *varname // is there a message ready to go? if (mReceiveSize == -1) { - llerrs << "No message waiting for decode 2!" << llendl; + LL_ERRS() << "No message waiting for decode 2!" << LL_ENDL; return; } if (!mCurrentRMessageData) { - llerrs << "Invalid mCurrentMessageData in getData!" << llendl; + LL_ERRS() << "Invalid mCurrentMessageData in getData!" << LL_ENDL; return; } @@ -85,28 +85,30 @@ void LLTemplateMessageReader::getData(const char *blockname, const char *varname if (iter == mCurrentRMessageData->mMemberBlocks.end()) { - llerrs << "Block " << blockname << " #" << blocknum - << " not in message " << mCurrentRMessageData->mName << llendl; + LL_ERRS() << "Block " << blockname << " #" << blocknum + << " not in message " << mCurrentRMessageData->mName << LL_ENDL; return; } LLMsgBlkData *msg_block_data = iter->second; - LLMsgVarData& vardata = msg_block_data->mMemberVarData[vnamep]; + LLMsgBlkData::msg_var_data_map_t &var_data_map = msg_block_data->mMemberVarData; - if (!vardata.getName()) + if (var_data_map.find(vnamep) == var_data_map.end()) { - llerrs << "Variable "<< vnamep << " not in message " - << mCurrentRMessageData->mName<< " block " << bnamep << llendl; + LL_ERRS() << "Variable "<< vnamep << " not in message " + << mCurrentRMessageData->mName<< " block " << bnamep << LL_ENDL; return; } + LLMsgVarData& vardata = msg_block_data->mMemberVarData[vnamep]; + if (size && size != vardata.getSize()) { - llerrs << "Msg " << mCurrentRMessageData->mName + LL_ERRS() << "Msg " << mCurrentRMessageData->mName << " variable " << vnamep << " is size " << vardata.getSize() << " but copying into buffer of size " << size - << llendl; + << LL_ENDL; return; } @@ -136,11 +138,11 @@ void LLTemplateMessageReader::getData(const char *blockname, const char *varname } else { - llwarns << "Msg " << mCurrentRMessageData->mName + LL_WARNS() << "Msg " << mCurrentRMessageData->mName << " variable " << vnamep << " is size " << vardata.getSize() << " but truncated to max size of " << max_size - << llendl; + << LL_ENDL; memcpy(datap, vardata.getData(), max_size); } @@ -151,13 +153,13 @@ S32 LLTemplateMessageReader::getNumberOfBlocks(const char *blockname) // is there a message ready to go? if (mReceiveSize == -1) { - llerrs << "No message waiting for decode 3!" << llendl; + LL_ERRS() << "No message waiting for decode 3!" << LL_ENDL; return -1; } if (!mCurrentRMessageData) { - llerrs << "Invalid mCurrentRMessageData in getData!" << llendl; + LL_ERRS() << "Invalid mCurrentRMessageData in getData!" << LL_ENDL; return -1; } @@ -178,13 +180,13 @@ S32 LLTemplateMessageReader::getSize(const char *blockname, const char *varname) // is there a message ready to go? if (mReceiveSize == -1) { // This is a serious error - crash - llerrs << "No message waiting for decode 4!" << llendl; + LL_ERRS() << "No message waiting for decode 4!" << LL_ENDL; return LL_MESSAGE_ERROR; } if (!mCurrentRMessageData) { // This is a serious error - crash - llerrs << "Invalid mCurrentRMessageData in getData!" << llendl; + LL_ERRS() << "Invalid mCurrentRMessageData in getData!" << LL_ENDL; return LL_MESSAGE_ERROR; } @@ -194,8 +196,8 @@ S32 LLTemplateMessageReader::getSize(const char *blockname, const char *varname) if (iter == mCurrentRMessageData->mMemberBlocks.end()) { // don't crash - llinfos << "Block " << bnamep << " not in message " - << mCurrentRMessageData->mName << llendl; + LL_INFOS() << "Block " << bnamep << " not in message " + << mCurrentRMessageData->mName << LL_ENDL; return LL_BLOCK_NOT_IN_MESSAGE; } @@ -206,15 +208,15 @@ S32 LLTemplateMessageReader::getSize(const char *blockname, const char *varname) if (!vardata.getName()) { // don't crash - llinfos << "Variable " << varname << " not in message " - << mCurrentRMessageData->mName << " block " << bnamep << llendl; + LL_INFOS() << "Variable " << varname << " not in message " + << mCurrentRMessageData->mName << " block " << bnamep << LL_ENDL; return LL_VARIABLE_NOT_IN_BLOCK; } if (mCurrentRMessageTemplate->mMemberBlocks[bnamep]->mType != MBT_SINGLE) { // This is a serious error - crash - llerrs << "Block " << bnamep << " isn't type MBT_SINGLE," - " use getSize with blocknum argument!" << llendl; + LL_ERRS() << "Block " << bnamep << " isn't type MBT_SINGLE," + " use getSize with blocknum argument!" << LL_ENDL; return LL_MESSAGE_ERROR; } @@ -226,13 +228,13 @@ S32 LLTemplateMessageReader::getSize(const char *blockname, S32 blocknum, const // is there a message ready to go? if (mReceiveSize == -1) { // This is a serious error - crash - llerrs << "No message waiting for decode 5!" << llendl; + LL_ERRS() << "No message waiting for decode 5!" << LL_ENDL; return LL_MESSAGE_ERROR; } if (!mCurrentRMessageData) { // This is a serious error - crash - llerrs << "Invalid mCurrentRMessageData in getData!" << llendl; + LL_ERRS() << "Invalid mCurrentRMessageData in getData!" << LL_ENDL; return LL_MESSAGE_ERROR; } @@ -243,8 +245,8 @@ S32 LLTemplateMessageReader::getSize(const char *blockname, S32 blocknum, const if (iter == mCurrentRMessageData->mMemberBlocks.end()) { // don't crash - llinfos << "Block " << bnamep << " not in message " - << mCurrentRMessageData->mName << llendl; + LL_INFOS() << "Block " << bnamep << " not in message " + << mCurrentRMessageData->mName << LL_ENDL; return LL_BLOCK_NOT_IN_MESSAGE; } @@ -253,8 +255,8 @@ S32 LLTemplateMessageReader::getSize(const char *blockname, S32 blocknum, const if (!vardata.getName()) { // don't crash - llinfos << "Variable " << vnamep << " not in message " - << mCurrentRMessageData->mName << " block " << bnamep << llendl; + LL_INFOS() << "Variable " << vnamep << " not in message " + << mCurrentRMessageData->mName << " block " << bnamep << LL_ENDL; return LL_VARIABLE_NOT_IN_BLOCK; } @@ -284,7 +286,7 @@ void LLTemplateMessageReader::getU8(const char *block, const char *var, void LLTemplateMessageReader::getBOOL(const char *block, const char *var, BOOL &b, S32 blocknum ) { - U8 value; + U8 value(0); getData(block, var, &value, sizeof(U8), blocknum); b = (BOOL) value; } @@ -324,10 +326,10 @@ void LLTemplateMessageReader::getF32(const char *block, const char *var, { getData(block, var, &d, sizeof(F32), blocknum); - if( !llfinite( d ) ) + if( !std::isfinite( d ) ) { - llwarns << "non-finite in getF32Fast " << block << " " << var - << llendl; + LL_WARNS() << "non-finite in getF32Fast " << block << " " << var + << LL_ENDL; d = 0; } } @@ -337,10 +339,10 @@ void LLTemplateMessageReader::getF64(const char *block, const char *var, { getData(block, var, &d, sizeof(F64), blocknum); - if( !llfinite( d ) ) + if( !std::isfinite( d ) ) { - llwarns << "non-finite in getF64Fast " << block << " " << var - << llendl; + LL_WARNS() << "non-finite in getF64Fast " << block << " " << var + << LL_ENDL; d = 0; } } @@ -352,8 +354,8 @@ void LLTemplateMessageReader::getVector3(const char *block, const char *var, if( !v.isFinite() ) { - llwarns << "non-finite in getVector3Fast " << block << " " - << var << llendl; + LL_WARNS() << "non-finite in getVector3Fast " << block << " " + << var << LL_ENDL; v.zeroVec(); } } @@ -365,8 +367,8 @@ void LLTemplateMessageReader::getVector4(const char *block, const char *var, if( !v.isFinite() ) { - llwarns << "non-finite in getVector4Fast " << block << " " - << var << llendl; + LL_WARNS() << "non-finite in getVector4Fast " << block << " " + << var << LL_ENDL; v.zeroVec(); } } @@ -378,8 +380,8 @@ void LLTemplateMessageReader::getVector3d(const char *block, const char *var, if( !v.isFinite() ) { - llwarns << "non-finite in getVector3dFast " << block << " " - << var << llendl; + LL_WARNS() << "non-finite in getVector3dFast " << block << " " + << var << LL_ENDL; v.zeroVec(); } @@ -396,8 +398,8 @@ void LLTemplateMessageReader::getQuat(const char *block, const char *var, } else { - llwarns << "non-finite in getQuatFast " << block << " " << var - << llendl; + LL_WARNS() << "non-finite in getQuatFast " << block << " " << var + << LL_ENDL; q.loadIdentity(); } } @@ -450,7 +452,7 @@ BOOL LLTemplateMessageReader::decodeTemplate( // is there a message ready to go? if (buffer_size <= 0) { - llwarns << "No message waiting for decode!" << llendl; + LL_WARNS() << "No message waiting for decode!" << LL_ENDL; return(FALSE); } @@ -486,8 +488,8 @@ BOOL LLTemplateMessageReader::decodeTemplate( else // bogus packet received (too short) { if(!custom) - llwarns << "Packet with unusable length received (too short): " - << buffer_size << llendl; + LL_WARNS() << "Packet with unusable length received (too short): " + << buffer_size << LL_ENDL; return(FALSE); } @@ -499,9 +501,10 @@ BOOL LLTemplateMessageReader::decodeTemplate( else { if(!custom) { - llwarns << "Message #" << std::hex << num << std::dec - << " received but not registered!" << llendl; - gMessageSystem->callExceptionFunc(MX_UNREGISTERED_MESSAGE); + // MAINT-7482 - make viewer more tolerant of unknown messages. + LL_WARNS() << "Message #" << std::hex << num << std::dec + << " received but not registered!" << LL_ENDL; + //gMessageSystem->callExceptionFunc(MX_UNREGISTERED_MESSAGE); } return(FALSE); } @@ -512,23 +515,23 @@ BOOL LLTemplateMessageReader::decodeTemplate( void LLTemplateMessageReader::logRanOffEndOfPacket( const LLHost& host, const S32 where, const S32 wanted ) { // we've run off the end of the packet! - llwarns << "Ran off end of packet " << mCurrentRMessageTemplate->mName + LL_WARNS() << "Ran off end of packet " << mCurrentRMessageTemplate->mName // << " with id " << mCurrentRecvPacketID << " from " << host << " trying to read " << wanted << " bytes at position " << where << " going past packet end at " << mReceiveSize - << llendl; + << LL_ENDL; if(gMessageSystem->mVerboseLog) { - llinfos << "MSG: -> " << host << "\tREAD PAST END:\t" + LL_INFOS() << "MSG: -> " << host << "\tREAD PAST END:\t" // << mCurrentRecvPacketID << " " - << getMessageName() << llendl; + << getMessageName() << LL_ENDL; } gMessageSystem->callExceptionFunc(MX_RAN_OFF_END_OF_PACKET); } -static LLFastTimer::DeclareTimer FTM_PROCESS_MESSAGES("Process Messages"); +static LLTrace::BlockTimerStatHandle FTM_PROCESS_MESSAGES("Process Messages"); // decode a given message BOOL LLTemplateMessageReader::decodeData(const U8* buffer, const LLHost& sender, bool custom) @@ -552,7 +555,7 @@ BOOL LLTemplateMessageReader::decodeData(const U8* buffer, const LLHost& sender, iter != mCurrentRMessageTemplate->mMemberBlocks.end(); ++iter) { - LLMessageBlock* mbci = *iter; + const LLMessageBlock* mbci = mCurrentRMessageTemplate->mMemberBlocks.toValue(iter); U8 repeat_number; S32 i; @@ -590,7 +593,7 @@ BOOL LLTemplateMessageReader::decodeData(const U8* buffer, const LLHost& sender, else { if(!custom) - llerrs << "Unknown block type" << llendl; + LL_ERRS() << "Unknown block type" << LL_ENDL; return FALSE; } @@ -619,17 +622,17 @@ BOOL LLTemplateMessageReader::decodeData(const U8* buffer, const LLHost& sender, mbci->mMemberVariables.begin(); iter != mbci->mMemberVariables.end(); iter++) { - const LLMessageVariable& mvci = **iter; + const LLMessageVariable* mvci = mbci->mMemberVariables.toValue(iter); // ok, build out the variables // add variable block - cur_data_block->addVariable(mvci.getName(), mvci.getType()); + cur_data_block->addVariable(mvci->getName(), mvci->getType()); // what type of variable? - if (mvci.getType() == MVT_VARIABLE) + if (mvci->getType() == MVT_VARIABLE) { // variable, get the number of bytes to read from the template - S32 data_size = mvci.getSize(); + S32 data_size = mvci->getSize(); U8 tsizeb = 0; U16 tsizeh = 0; U32 tsize = 0; @@ -658,38 +661,38 @@ BOOL LLTemplateMessageReader::decodeData(const U8* buffer, const LLHost& sender, htonmemcpy(&tsize, &buffer[decode_pos], MVT_U32, 4); break; default: - llerrs << "Attempting to read variable field with unknown size of " << data_size << llendl; + LL_ERRS() << "Attempting to read variable field with unknown size of " << data_size << LL_ENDL; break; } } decode_pos += data_size; - cur_data_block->addData(mvci.getName(), &buffer[decode_pos], tsize, mvci.getType()); + cur_data_block->addData(mvci->getName(), &buffer[decode_pos], tsize, mvci->getType()); decode_pos += tsize; } else { // fixed! // so, copy data pointer and set data size to fixed size - if ((decode_pos + mvci.getSize()) > mReceiveSize) + if ((decode_pos + mvci->getSize()) > mReceiveSize) { if(!custom) - logRanOffEndOfPacket(sender, decode_pos, mvci.getSize()); + logRanOffEndOfPacket(sender, decode_pos, mvci->getSize()); // default to 0s. - U32 size = mvci.getSize(); + U32 size = mvci->getSize(); std::vector data(size, 0); - cur_data_block->addData(mvci.getName(), &(data[0]), - size, mvci.getType()); + cur_data_block->addData(mvci->getName(), &(data[0]), + size, mvci->getType()); } else { - cur_data_block->addData(mvci.getName(), + cur_data_block->addData(mvci->getName(), &buffer[decode_pos], - mvci.getSize(), - mvci.getType()); + mvci->getSize(), + mvci->getType()); } - decode_pos += mvci.getSize(); + decode_pos += mvci->getSize(); } } } @@ -698,7 +701,7 @@ BOOL LLTemplateMessageReader::decodeData(const U8* buffer, const LLHost& sender, if (mCurrentRMessageData->mMemberBlocks.empty() && !mCurrentRMessageTemplate->mMemberBlocks.empty()) { - lldebugs << "Empty message '" << mCurrentRMessageTemplate->mName << "' (no blocks)" << llendl; + LL_DEBUGS() << "Empty message '" << mCurrentRMessageTemplate->mName << "' (no blocks)" << LL_ENDL; return FALSE; } @@ -712,10 +715,10 @@ BOOL LLTemplateMessageReader::decodeData(const U8* buffer, const LLHost& sender, } { - LLFastTimer t(FTM_PROCESS_MESSAGES); + LL_RECORD_BLOCK_TIME(FTM_PROCESS_MESSAGES); if( !mCurrentRMessageTemplate->callHandlerFunc(gMessageSystem) ) { - llwarns << "Message from " << sender << " with no handler function received: " << mCurrentRMessageTemplate->mName << llendl; + LL_WARNS() << "Message from " << sender << " with no handler function received: " << mCurrentRMessageTemplate->mName << LL_ENDL; } } @@ -745,9 +748,9 @@ BOOL LLTemplateMessageReader::decodeData(const U8* buffer, const LLHost& sender, if(decode_time > LLMessageReader::getTimeDecodesSpamThreshold()) { - lldebugs << "--------- Message " << mCurrentRMessageTemplate->mName << " decode took " << decode_time << " seconds. (" << + LL_DEBUGS() << "--------- Message " << mCurrentRMessageTemplate->mName << " decode took " << decode_time << " seconds. (" << mCurrentRMessageTemplate->mMaxDecodeTimePerMsg << " max, " << - (mCurrentRMessageTemplate->mTotalDecodeTime / mCurrentRMessageTemplate->mTotalDecoded) << " avg)" << llendl; + (mCurrentRMessageTemplate->mTotalDecodeTime / mCurrentRMessageTemplate->mTotalDecoded) << " avg)" << LL_ENDL; } } } @@ -765,9 +768,9 @@ BOOL LLTemplateMessageReader::validateMessage(const U8* buffer, if(valid && !custom) { mCurrentRMessageTemplate->mReceiveCount++; - //lldebugs << "MessageRecvd:" + //LL_DEBUGS() << "MessageRecvd:" // << mCurrentRMessageTemplate->mName - // << " from " << sender << llendl; + // << " from " << sender << LL_ENDL; } if (valid && isBanned(trusted)) @@ -777,15 +780,15 @@ BOOL LLTemplateMessageReader::validateMessage(const U8* buffer, << getMessageName() << " from " << ((trusted) ? "trusted " : "untrusted ") - << sender << llendl; + << sender << LL_ENDL; valid = FALSE; } if(valid && isUdpBanned()) { - llwarns << "Received UDP black listed message " + LL_WARNS() << "Received UDP black listed message " << getMessageName() - << " from " << sender << llendl; + << " from " << sender << LL_ENDL; valid = FALSE; } return valid; diff --git a/indra/llmessage/llthrottle.cpp b/indra/llmessage/llthrottle.cpp index 64ebd51fec..edd230a8da 100644 --- a/indra/llmessage/llthrottle.cpp +++ b/indra/llmessage/llthrottle.cpp @@ -53,8 +53,8 @@ F32 LLThrottle::getAvailable() { // use a temporary bits_available // since we don't want to change mBitsAvailable every time - F32 elapsed_time = (F32)(LLMessageSystem::getMessageTimeSeconds() - mLastSendTime); - return mAvailable + (mRate * elapsed_time); + F32Seconds elapsed_time = LLMessageSystem::getMessageTimeSeconds() - mLastSendTime; + return mAvailable + (mRate * elapsed_time.value()); } BOOL LLThrottle::checkOverflow(const F32 amount) @@ -65,8 +65,8 @@ BOOL LLThrottle::checkOverflow(const F32 amount) // use a temporary bits_available // since we don't want to change mBitsAvailable every time - F32 elapsed_time = (F32)(LLMessageSystem::getMessageTimeSeconds() - mLastSendTime); - F32 amount_available = mAvailable + (mRate * elapsed_time); + F32Seconds elapsed_time = LLMessageSystem::getMessageTimeSeconds() - mLastSendTime; + F32 amount_available = mAvailable + (mRate * elapsed_time.value()); if ((amount_available >= lookahead_amount) || (amount_available > amount)) { @@ -80,17 +80,17 @@ BOOL LLThrottle::checkOverflow(const F32 amount) BOOL LLThrottle::throttleOverflow(const F32 amount) { - F32 elapsed_time; + F32Seconds elapsed_time; F32 lookahead_amount; BOOL retval = TRUE; lookahead_amount = mRate * mLookaheadSecs; - F64 mt_sec = LLMessageSystem::getMessageTimeSeconds(); - elapsed_time = (F32)(mt_sec - mLastSendTime); + F64Seconds mt_sec = LLMessageSystem::getMessageTimeSeconds(); + elapsed_time = mt_sec - mLastSendTime; mLastSendTime = mt_sec; - mAvailable += mRate * elapsed_time; + mAvailable += mRate * elapsed_time.value(); if (mAvailable >= lookahead_amount) { @@ -222,7 +222,7 @@ void LLThrottleGroup::unpackThrottle(LLDataPacker &dp) // into NOT resetting the system. void LLThrottleGroup::resetDynamicAdjust() { - F64 mt_sec = LLMessageSystem::getMessageTimeSeconds(); + F64Seconds mt_sec = LLMessageSystem::getMessageTimeSeconds(); S32 i; for (i = 0; i < TC_EOF; i++) { @@ -269,8 +269,8 @@ S32 LLThrottleGroup::getAvailable(S32 throttle_cat) // use a temporary bits_available // since we don't want to change mBitsAvailable every time - F32 elapsed_time = (F32)(LLMessageSystem::getMessageTimeSeconds() - mLastSendTime[throttle_cat]); - F32 bits_available = mBitsAvailable[throttle_cat] + (category_bps * elapsed_time); + F32Seconds elapsed_time = LLMessageSystem::getMessageTimeSeconds() - mLastSendTime[throttle_cat]; + F32 bits_available = mBitsAvailable[throttle_cat] + (category_bps * elapsed_time.value()); if (bits_available >= lookahead_bits) { @@ -294,8 +294,8 @@ BOOL LLThrottleGroup::checkOverflow(S32 throttle_cat, F32 bits) // use a temporary bits_available // since we don't want to change mBitsAvailable every time - F32 elapsed_time = (F32)(LLMessageSystem::getMessageTimeSeconds() - mLastSendTime[throttle_cat]); - F32 bits_available = mBitsAvailable[throttle_cat] + (category_bps * elapsed_time); + F32Seconds elapsed_time = LLMessageSystem::getMessageTimeSeconds() - mLastSendTime[throttle_cat]; + F32 bits_available = mBitsAvailable[throttle_cat] + (category_bps * elapsed_time.value()); if (bits_available >= lookahead_bits) { @@ -315,7 +315,7 @@ BOOL LLThrottleGroup::checkOverflow(S32 throttle_cat, F32 bits) BOOL LLThrottleGroup::throttleOverflow(S32 throttle_cat, F32 bits) { - F32 elapsed_time; + F32Seconds elapsed_time; F32 category_bps; F32 lookahead_bits; BOOL retval = TRUE; @@ -323,10 +323,10 @@ BOOL LLThrottleGroup::throttleOverflow(S32 throttle_cat, F32 bits) category_bps = mCurrentBPS[throttle_cat]; lookahead_bits = category_bps * THROTTLE_LOOKAHEAD_TIME; - F64 mt_sec = LLMessageSystem::getMessageTimeSeconds(); - elapsed_time = (F32)(mt_sec - mLastSendTime[throttle_cat]); + F64Seconds mt_sec = LLMessageSystem::getMessageTimeSeconds(); + elapsed_time = mt_sec - mLastSendTime[throttle_cat]; mLastSendTime[throttle_cat] = mt_sec; - mBitsAvailable[throttle_cat] += category_bps * elapsed_time; + mBitsAvailable[throttle_cat] += category_bps * elapsed_time.value(); if (mBitsAvailable[throttle_cat] >= lookahead_bits) { @@ -356,7 +356,7 @@ BOOL LLThrottleGroup::throttleOverflow(S32 throttle_cat, F32 bits) BOOL LLThrottleGroup::dynamicAdjust() { - const F32 DYNAMIC_ADJUST_TIME = 1.0f; // seconds + const F32Seconds DYNAMIC_ADJUST_TIME(1.0f); const F32 CURRENT_PERIOD_WEIGHT = .25f; // how much weight to give to last period while determining BPS utilization const F32 BUSY_PERCENT = 0.75f; // if use more than this fraction of BPS, you are busy const F32 IDLE_PERCENT = 0.70f; // if use less than this fraction, you are "idle" @@ -365,7 +365,7 @@ BOOL LLThrottleGroup::dynamicAdjust() S32 i; - F64 mt_sec = LLMessageSystem::getMessageTimeSeconds(); + F64Seconds mt_sec = LLMessageSystem::getMessageTimeSeconds(); // Only dynamically adjust every few seconds if ((mt_sec - mDynamicAdjustTime) < DYNAMIC_ADJUST_TIME) @@ -391,7 +391,7 @@ BOOL LLThrottleGroup::dynamicAdjust() } mBitsSentThisPeriod[i] = 0; - total += llround(mBitsSentHistory[i]); + total += ll_pos_round(mBitsSentHistory[i]); } // Look for busy channels @@ -405,7 +405,7 @@ BOOL LLThrottleGroup::dynamicAdjust() for (i = 0; i < TC_EOF; i++) { // Is this a busy channel? - if (mBitsSentHistory[i] >= BUSY_PERCENT * DYNAMIC_ADJUST_TIME * mCurrentBPS[i]) + if (mBitsSentHistory[i] >= BUSY_PERCENT * DYNAMIC_ADJUST_TIME.value() * mCurrentBPS[i]) { // this channel is busy channels_busy = TRUE; @@ -418,7 +418,7 @@ BOOL LLThrottleGroup::dynamicAdjust() } // Is this an idle channel? - if ((mBitsSentHistory[i] < IDLE_PERCENT * DYNAMIC_ADJUST_TIME * mCurrentBPS[i]) && + if ((mBitsSentHistory[i] < IDLE_PERCENT * DYNAMIC_ADJUST_TIME.value() * mCurrentBPS[i]) && (mBitsAvailable[i] > 0)) { channel_idle[i] = TRUE; @@ -440,8 +440,8 @@ BOOL LLThrottleGroup::dynamicAdjust() //if (total) //{ - // llinfos << i << ": B" << channel_busy[i] << " I" << channel_idle[i] << " N" << channel_over_nominal[i]; - // llcont << " Nom: " << mNominalBPS[i] << " Cur: " << mCurrentBPS[i] << " BS: " << mBitsSentHistory[i] << llendl; + // LL_INFOS() << i << ": B" << channel_busy[i] << " I" << channel_idle[i] << " N" << channel_over_nominal[i]; + // LL_CONT << " Nom: " << mNominalBPS[i] << " Cur: " << mCurrentBPS[i] << " BS: " << mBitsSentHistory[i] << LL_ENDL; //} } @@ -462,7 +462,7 @@ BOOL LLThrottleGroup::dynamicAdjust() // Therefore it's a candidate to give up some bandwidth. // Figure out how much bandwidth it has been using, and how // much is available to steal. - used_bps = mBitsSentHistory[i] / DYNAMIC_ADJUST_TIME; + used_bps = mBitsSentHistory[i] / DYNAMIC_ADJUST_TIME.value(); // CRO make sure to keep a minimum amount of throttle available // CRO NB: channels set to < MINIMUM_BPS will never give up bps, @@ -482,7 +482,7 @@ BOOL LLThrottleGroup::dynamicAdjust() avail_bps = mCurrentBPS[i] - used_bps; } - //llinfos << i << " avail " << avail_bps << llendl; + //LL_INFOS() << i << " avail " << avail_bps << LL_ENDL; // Historically, a channel could have used more than its current share, // even if it's idle right now. @@ -499,7 +499,7 @@ BOOL LLThrottleGroup::dynamicAdjust() } } - //llinfos << "Pool BPS: " << pool_bps << llendl; + //LL_INFOS() << "Pool BPS: " << pool_bps << LL_ENDL; // Now redistribute the bandwidth to busy channels. F32 unused_bps = 0.f; @@ -508,7 +508,7 @@ BOOL LLThrottleGroup::dynamicAdjust() if (channel_busy[i]) { F32 add_amount = pool_bps * (mNominalBPS[i] / busy_nominal_sum); - //llinfos << "Busy " << i << " gets " << pool_bps << llendl; + //LL_INFOS() << "Busy " << i << " gets " << pool_bps << LL_ENDL; mCurrentBPS[i] += add_amount; // CRO: make sure this doesn't get too huge diff --git a/indra/llmessage/llthrottle.h b/indra/llmessage/llthrottle.h index ed0aeb4602..e43e54f61b 100644 --- a/indra/llmessage/llthrottle.h +++ b/indra/llmessage/llthrottle.h @@ -50,7 +50,7 @@ class LLThrottle F32 mLookaheadSecs; // Seconds to look ahead, maximum F32 mRate; // BPS available, dynamically adjusted F32 mAvailable; // Bits available to send right now on each channel - F64 mLastSendTime; // Time since last send on this channel + F64Seconds mLastSendTime; // Time since last send on this channel }; typedef enum e_throttle_categories @@ -93,8 +93,8 @@ class LLThrottleGroup F32 mBitsSentThisPeriod[TC_EOF]; // Sent in this dynamic allocation period F32 mBitsSentHistory[TC_EOF]; // Sent before this dynamic allocation period, adjusted to one period length - F64 mLastSendTime[TC_EOF]; // Time since last send on this channel - F64 mDynamicAdjustTime; // Only dynamic adjust every 2 seconds or so. + F64Seconds mLastSendTime[TC_EOF]; // Time since last send on this channel + F64Seconds mDynamicAdjustTime; // Only dynamic adjust every 2 seconds or so. }; diff --git a/indra/llmessage/lltransfermanager.cpp b/indra/llmessage/lltransfermanager.cpp index 034680caf8..ec7b21d8b6 100644 --- a/indra/llmessage/lltransfermanager.cpp +++ b/indra/llmessage/lltransfermanager.cpp @@ -64,7 +64,7 @@ LLTransferManager::~LLTransferManager() { if (mValid) { - llwarns << "LLTransferManager::~LLTransferManager - Should have been cleaned up by message system shutdown process" << llendl; + LL_WARNS() << "LLTransferManager::~LLTransferManager - Should have been cleaned up by message system shutdown process" << LL_ENDL; cleanup(); } } @@ -74,7 +74,7 @@ void LLTransferManager::init() { if (mValid) { - llerrs << "Double initializing LLTransferManager!" << llendl; + LL_ERRS() << "Double initializing LLTransferManager!" << LL_ENDL; } mValid = TRUE; @@ -122,7 +122,7 @@ void LLTransferManager::cleanupConnection(const LLHost &host) { // This can happen legitimately if we've never done a transfer, and we're // cleaning up a circuit. - //llwarns << "Cleaning up nonexistent transfer connection to " << host << llendl; + //LL_WARNS() << "Cleaning up nonexistent transfer connection to " << host << LL_ENDL; return; } LLTransferConnection *connp = iter->second; @@ -203,7 +203,7 @@ LLTransferSource *LLTransferManager::findTransferSource(const LLUUID &transfer_i //static void LLTransferManager::processTransferRequest(LLMessageSystem *msgp, void **) { - //llinfos << "LLTransferManager::processTransferRequest" << llendl; + //LL_INFOS() << "LLTransferManager::processTransferRequest" << LL_ENDL; LLUUID transfer_id; LLTransferSourceType source_type; @@ -219,33 +219,33 @@ void LLTransferManager::processTransferRequest(LLMessageSystem *msgp, void **) if (!tscp) { - llwarns << "Source channel not found" << llendl; + LL_WARNS() << "Source channel not found" << LL_ENDL; return; } if (tscp->findTransferSource(transfer_id)) { - llwarns << "Duplicate request for transfer " << transfer_id << ", aborting!" << llendl; + LL_WARNS() << "Duplicate request for transfer " << transfer_id << ", aborting!" << LL_ENDL; return; } S32 size = msgp->getSize("TransferInfo", "Params"); if(size > MAX_PARAMS_SIZE) { - llwarns << "LLTransferManager::processTransferRequest params too big." - << llendl; + LL_WARNS() << "LLTransferManager::processTransferRequest params too big." + << LL_ENDL; return; } - //llinfos << transfer_id << ":" << source_type << ":" << channel_type << ":" << priority << llendl; + //LL_INFOS() << transfer_id << ":" << source_type << ":" << channel_type << ":" << priority << LL_ENDL; LLTransferSource* tsp = LLTransferSource::createSource( source_type, transfer_id, priority); if(!tsp) { - llwarns << "LLTransferManager::processTransferRequest couldn't create" - << " transfer source!" << llendl; + LL_WARNS() << "LLTransferManager::processTransferRequest couldn't create" + << " transfer source!" << LL_ENDL; return; } U8 tmp[MAX_PARAMS_SIZE]; @@ -258,8 +258,8 @@ void LLTransferManager::processTransferRequest(LLMessageSystem *msgp, void **) // This should only happen if the data is corrupt or // incorrectly packed. // *NOTE: We may want to call abortTransfer(). - llwarns << "LLTransferManager::processTransferRequest: bad parameters." - << llendl; + LL_WARNS() << "LLTransferManager::processTransferRequest: bad parameters." + << LL_ENDL; delete tsp; return; } @@ -272,7 +272,7 @@ void LLTransferManager::processTransferRequest(LLMessageSystem *msgp, void **) //static void LLTransferManager::processTransferInfo(LLMessageSystem *msgp, void **) { - //llinfos << "LLTransferManager::processTransferInfo" << llendl; + //LL_INFOS() << "LLTransferManager::processTransferInfo" << LL_ENDL; LLUUID transfer_id; LLTransferTargetType target_type; @@ -286,11 +286,11 @@ void LLTransferManager::processTransferInfo(LLMessageSystem *msgp, void **) msgp->getS32("TransferInfo", "Status", (S32 &)status); msgp->getS32("TransferInfo", "Size", size); - //llinfos << transfer_id << ":" << target_type<< ":" << channel_type << llendl; + //LL_INFOS() << transfer_id << ":" << target_type<< ":" << channel_type << LL_ENDL; LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(msgp->getSender(), channel_type); if (!ttcp) { - llwarns << "Target channel not found" << llendl; + LL_WARNS() << "Target channel not found" << LL_ENDL; // Should send a message to abort the transfer. return; } @@ -298,7 +298,7 @@ void LLTransferManager::processTransferInfo(LLMessageSystem *msgp, void **) LLTransferTarget *ttp = ttcp->findTransferTarget(transfer_id); if (!ttp) { - llwarns << "TransferInfo for unknown transfer! Not able to handle this yet!" << llendl; + LL_WARNS() << "TransferInfo for unknown transfer! Not able to handle this yet!" << LL_ENDL; // This could happen if we're doing a push transfer, although to avoid confusion, // maybe it should be a different message. return; @@ -306,7 +306,7 @@ void LLTransferManager::processTransferInfo(LLMessageSystem *msgp, void **) if (status != LLTS_OK) { - llwarns << transfer_id << ": Non-ok status, cleaning up" << llendl; + LL_WARNS() << transfer_id << ": Non-ok status, cleaning up" << LL_ENDL; ttp->completionCallback(status); // Clean up the transfer. ttcp->deleteTransfer(ttp); @@ -317,8 +317,8 @@ void LLTransferManager::processTransferInfo(LLMessageSystem *msgp, void **) S32 params_size = msgp->getSize("TransferInfo", "Params"); if(params_size > MAX_PARAMS_SIZE) { - llwarns << "LLTransferManager::processTransferInfo params too big." - << llendl; + LL_WARNS() << "LLTransferManager::processTransferInfo params too big." + << LL_ENDL; return; } else if(params_size > 0) @@ -330,15 +330,15 @@ void LLTransferManager::processTransferInfo(LLMessageSystem *msgp, void **) { // This should only happen if the data is corrupt or // incorrectly packed. - llwarns << "LLTransferManager::processTransferRequest: bad params." - << llendl; + LL_WARNS() << "LLTransferManager::processTransferRequest: bad params." + << LL_ENDL; ttp->abortTransfer(); ttcp->deleteTransfer(ttp); return; } } - //llinfos << "Receiving " << transfer_id << ", size " << size << " bytes" << llendl; + //LL_INFOS() << "Receiving " << transfer_id << ", size " << size << " bytes" << LL_ENDL; ttp->setSize(size); ttp->setGotInfo(TRUE); @@ -358,7 +358,7 @@ void LLTransferManager::processTransferInfo(LLMessageSystem *msgp, void **) { // Perhaps this stuff should be inside a method in LLTransferPacket? // I'm too lazy to do it now, though. -// llinfos << "Playing back delayed packet " << packet_id << llendl; +// LL_INFOS() << "Playing back delayed packet " << packet_id << LL_ENDL; LLTransferPacket *packetp = ttp->mDelayedPacketMap[packet_id]; // This is somewhat inefficient, but avoids us having to duplicate @@ -392,11 +392,11 @@ void LLTransferManager::processTransferInfo(LLMessageSystem *msgp, void **) { if (status != LLTS_DONE) { - llwarns << "LLTransferManager::processTransferInfo Error in playback!" << llendl; + LL_WARNS() << "LLTransferManager::processTransferInfo Error in playback!" << LL_ENDL; } else { - llinfos << "LLTransferManager::processTransferInfo replay FINISHED for " << transfer_id << llendl; + LL_INFOS() << "LLTransferManager::processTransferInfo replay FINISHED for " << transfer_id << LL_ENDL; } // This transfer is done, either via error or not. ttp->completionCallback(status); @@ -410,7 +410,7 @@ void LLTransferManager::processTransferInfo(LLMessageSystem *msgp, void **) //static void LLTransferManager::processTransferPacket(LLMessageSystem *msgp, void **) { - //llinfos << "LLTransferManager::processTransferPacket" << llendl; + //LL_INFOS() << "LLTransferManager::processTransferPacket" << LL_ENDL; LLUUID transfer_id; LLTransferChannelType channel_type; @@ -423,20 +423,20 @@ void LLTransferManager::processTransferPacket(LLMessageSystem *msgp, void **) msgp->getS32("TransferData", "Status", (S32 &)status); // Find the transfer associated with this packet. - //llinfos << transfer_id << ":" << channel_type << llendl; + //LL_INFOS() << transfer_id << ":" << channel_type << LL_ENDL; LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(msgp->getSender(), channel_type); if (!ttcp) { - llwarns << "Target channel not found" << llendl; + LL_WARNS() << "Target channel not found" << LL_ENDL; return; } LLTransferTarget *ttp = ttcp->findTransferTarget(transfer_id); if (!ttp) { - llwarns << "Didn't find matching transfer for " << transfer_id + LL_WARNS() << "Didn't find matching transfer for " << transfer_id << " processing packet " << packet_id - << " from " << msgp->getSender() << llendl; + << " from " << msgp->getSender() << LL_ENDL; return; } @@ -455,7 +455,7 @@ void LLTransferManager::processTransferPacket(LLMessageSystem *msgp, void **) if ((size < 0) || (size > MAX_PACKET_DATA_SIZE)) { - llwarns << "Invalid transfer packet size " << size << llendl; + LL_WARNS() << "Invalid transfer packet size " << size << LL_ENDL; return; } @@ -472,8 +472,8 @@ void LLTransferManager::processTransferPacket(LLMessageSystem *msgp, void **) if(!ttp->addDelayedPacket(packet_id, status, tmp_data, size)) { // Whoops - failed to add a delayed packet for some reason. - llwarns << "Too many delayed packets processing transfer " - << transfer_id << " from " << msgp->getSender() << llendl; + LL_WARNS() << "Too many delayed packets processing transfer " + << transfer_id << " from " << msgp->getSender() << LL_ENDL; ttp->abortTransfer(); ttcp->deleteTransfer(ttp); return; @@ -483,15 +483,15 @@ void LLTransferManager::processTransferPacket(LLMessageSystem *msgp, void **) const S32 LL_TRANSFER_WARN_GAP = 10; if(!ttp->gotInfo()) { - llwarns << "Got data packet before information in transfer " + LL_WARNS() << "Got data packet before information in transfer " << transfer_id << " from " << msgp->getSender() - << ", got " << packet_id << llendl; + << ", got " << packet_id << LL_ENDL; } else if((packet_id - ttp->getNextPacketID()) > LL_TRANSFER_WARN_GAP) { - llwarns << "Out of order packet in transfer " << transfer_id + LL_WARNS() << "Out of order packet in transfer " << transfer_id << " from " << msgp->getSender() << ", got " << packet_id - << " expecting " << ttp->getNextPacketID() << llendl; + << " expecting " << ttp->getNextPacketID() << LL_ENDL; } #endif return; @@ -516,11 +516,11 @@ void LLTransferManager::processTransferPacket(LLMessageSystem *msgp, void **) { if (status != LLTS_DONE) { - llwarns << "LLTransferManager::processTransferPacket Error in transfer!" << llendl; + LL_WARNS() << "LLTransferManager::processTransferPacket Error in transfer!" << LL_ENDL; } else { -// llinfos << "LLTransferManager::processTransferPacket done for " << transfer_id << llendl; +// LL_INFOS() << "LLTransferManager::processTransferPacket done for " << transfer_id << LL_ENDL; } // This transfer is done, either via error or not. ttp->completionCallback(status); @@ -534,7 +534,7 @@ void LLTransferManager::processTransferPacket(LLMessageSystem *msgp, void **) { // Perhaps this stuff should be inside a method in LLTransferPacket? // I'm too lazy to do it now, though. -// llinfos << "Playing back delayed packet " << packet_id << llendl; +// LL_INFOS() << "Playing back delayed packet " << packet_id << LL_ENDL; LLTransferPacket *packetp = ttp->mDelayedPacketMap[packet_id]; // This is somewhat inefficient, but avoids us having to duplicate @@ -564,7 +564,7 @@ void LLTransferManager::processTransferPacket(LLMessageSystem *msgp, void **) //static void LLTransferManager::processTransferAbort(LLMessageSystem *msgp, void **) { - //llinfos << "LLTransferManager::processTransferPacket" << llendl; + //LL_INFOS() << "LLTransferManager::processTransferPacket" << LL_ENDL; LLUUID transfer_id; LLTransferChannelType channel_type; @@ -598,7 +598,7 @@ void LLTransferManager::processTransferAbort(LLMessageSystem *msgp, void **) } } - llwarns << "Couldn't find transfer " << transfer_id << " to abort!" << llendl; + LL_WARNS() << "Couldn't find transfer " << transfer_id << " to abort!" << LL_ENDL; } @@ -606,16 +606,21 @@ void LLTransferManager::processTransferAbort(LLMessageSystem *msgp, void **) void LLTransferManager::reliablePacketCallback(void **user_data, S32 result) { LLUUID *transfer_idp = (LLUUID *)user_data; - if (result) + if (result && + transfer_idp != NULL) { - llwarns << "Aborting reliable transfer " << *transfer_idp << " due to failed reliable resends!" << llendl; LLTransferSource *tsp = gTransferManager.findTransferSource(*transfer_idp); if (tsp) { + LL_WARNS() << "Aborting reliable transfer " << *transfer_idp << " due to failed reliable resends!" << LL_ENDL; LLTransferSourceChannel *tscp = tsp->mChannelp; tsp->abortTransfer(); tscp->deleteTransfer(tsp); } + else + { + LL_WARNS() << "Aborting reliable transfer " << *transfer_idp << " but can't find the LLTransferSource object" << LL_ENDL; + } } delete transfer_idp; } @@ -758,7 +763,7 @@ void LLTransferSourceChannel::updateTransfers() // We DON'T want to send any packets if they're blocked, they'll just end up // piling up on the other end. - //llwarns << "Blocking transfers due to blocked circuit for " << getHost() << llendl; + //LL_WARNS() << "Blocking transfers due to blocked circuit for " << getHost() << LL_ENDL; return; } @@ -776,7 +781,7 @@ void LLTransferSourceChannel::updateTransfers() BOOL done = FALSE; for (iter = mTransferSources.mMap.begin(); (iter != mTransferSources.mMap.end()) && !done;) { - //llinfos << "LLTransferSourceChannel::updateTransfers()" << llendl; + //LL_INFOS() << "LLTransferSourceChannel::updateTransfers()" << LL_ENDL; // Do stuff. next = iter; next++; @@ -815,7 +820,7 @@ void LLTransferSourceChannel::updateTransfers() gMessageSystem->addS32("Status", status); gMessageSystem->addBinaryData("Data", datap, data_size); sent_bytes = gMessageSystem->getCurrentSendTotal(); - gMessageSystem->sendReliable(getHost(), LL_DEFAULT_RELIABLE_RETRIES, TRUE, 0.f, + gMessageSystem->sendReliable(getHost(), LL_DEFAULT_RELIABLE_RETRIES, TRUE, F32Seconds(0.f), LLTransferManager::reliablePacketCallback, (void**)cb_uuid); // Do bookkeeping for the throttle @@ -848,11 +853,11 @@ void LLTransferSourceChannel::updateTransfers() // We're OK, don't need to do anything. Keep sending data. break; case LLTS_ERROR: - llwarns << "Error in transfer dataCallback!" << llendl; + LL_WARNS() << "Error in transfer dataCallback!" << LL_ENDL; // fall through case LLTS_DONE: // We need to clean up this transfer source. - //llinfos << "LLTransferSourceChannel::updateTransfers() " << tsp->getID() << " done" << llendl; + //LL_INFOS() << "LLTransferSourceChannel::updateTransfers() " << tsp->getID() << " done" << LL_ENDL; tsp->completionCallback(status); delete tsp; @@ -860,7 +865,7 @@ void LLTransferSourceChannel::updateTransfers() iter = next; break; default: - llerrs << "Unknown transfer error code!" << llendl; + LL_ERRS() << "Unknown transfer error code!" << LL_ENDL; } // At this point, we should do priority adjustment (since some transfers like @@ -892,22 +897,26 @@ LLTransferSource *LLTransferSourceChannel::findTransferSource(const LLUUID &tran } -BOOL LLTransferSourceChannel::deleteTransfer(LLTransferSource *tsp) +void LLTransferSourceChannel::deleteTransfer(LLTransferSource *tsp) { - - LLPriQueueMap::pqm_iter iter; - for (iter = mTransferSources.mMap.begin(); iter != mTransferSources.mMap.end(); iter++) + if (tsp) { - if (iter->second == tsp) + LLPriQueueMap::pqm_iter iter; + for (iter = mTransferSources.mMap.begin(); iter != mTransferSources.mMap.end(); iter++) { - delete tsp; - mTransferSources.mMap.erase(iter); - return TRUE; + if (iter->second == tsp) + { + delete tsp; + mTransferSources.mMap.erase(iter); + return; + } } - } - llerrs << "Unable to find transfer source to delete!" << llendl; - return FALSE; + LL_WARNS() << "Unable to find transfer source id " + << tsp->getID() + << " to delete!" + << LL_ENDL; + } } @@ -947,7 +956,7 @@ void LLTransferTargetChannel::requestTransfer( source_params.getType()); if (!ttp) { - llwarns << "LLTransferManager::requestTransfer aborting due to target creation failure!" << llendl; + LL_WARNS() << "LLTransferManager::requestTransfer aborting due to target creation failure!" << LL_ENDL; return; } @@ -1008,21 +1017,26 @@ LLTransferTarget *LLTransferTargetChannel::findTransferTarget(const LLUUID &tran } -BOOL LLTransferTargetChannel::deleteTransfer(LLTransferTarget *ttp) +void LLTransferTargetChannel::deleteTransfer(LLTransferTarget *ttp) { - tt_iter iter; - for (iter = mTransferTargets.begin(); iter != mTransferTargets.end(); iter++) + if (ttp) { - if (*iter == ttp) + tt_iter iter; + for (iter = mTransferTargets.begin(); iter != mTransferTargets.end(); iter++) { - delete ttp; - mTransferTargets.erase(iter); - return TRUE; + if (*iter == ttp) + { + delete ttp; + mTransferTargets.erase(iter); + return; + } } - } - llerrs << "Unable to find transfer target to delete!" << llendl; - return FALSE; + LL_WARNS() << "Unable to find transfer target id " + << ttp->getID() + << " to delete!" + << LL_ENDL; + } } @@ -1083,7 +1097,7 @@ void LLTransferSource::sendTransferStatus(LLTSCode status) void LLTransferSource::abortTransfer() { // Send a message down, call the completion callback - llinfos << "LLTransferSource::Aborting transfer " << getID() << " to " << mChannelp->getHost() << llendl; + LL_INFOS() << "LLTransferSource::Aborting transfer " << getID() << " to " << mChannelp->getHost() << LL_ENDL; gMessageSystem->newMessage("TransferAbort"); gMessageSystem->nextBlock("TransferInfo"); gMessageSystem->addUUID("TransferID", getID()); @@ -1101,7 +1115,7 @@ void LLTransferSource::registerSourceType(const LLTransferSourceType stype, LLTr { // Disallow changing what class handles a source type // Unclear when you would want to do this, and whether it would work. - llerrs << "Reregistering source type " << stype << llendl; + LL_ERRS() << "Reregistering source type " << stype << LL_ENDL; } else { @@ -1129,7 +1143,7 @@ LLTransferSource *LLTransferSource::createSource(const LLTransferSourceType styp if (!sSourceCreateMap.count(stype)) { // Use the callback to create the source type if it's not there. - llwarns << "Unknown transfer source type: " << stype << llendl; + LL_WARNS() << "Unknown transfer source type: " << stype << LL_ENDL; return NULL; } return (sSourceCreateMap[stype])(id, priority); @@ -1216,7 +1230,7 @@ LLTransferTarget::~LLTransferTarget() void LLTransferTarget::abortTransfer() { // Send a message up, call the completion callback - llinfos << "LLTransferTarget::Aborting transfer " << getID() << " from " << mChannelp->getHost() << llendl; + LL_INFOS() << "LLTransferTarget::Aborting transfer " << getID() << " from " << mChannelp->getHost() << LL_ENDL; gMessageSystem->newMessage("TransferAbort"); gMessageSystem->nextBlock("TransferInfo"); gMessageSystem->addUUID("TransferID", getID()); @@ -1246,9 +1260,13 @@ bool LLTransferTarget::addDelayedPacket( size); #ifdef _DEBUG - if (mDelayedPacketMap.find(packet_id) != mDelayedPacketMap.end()) + transfer_packet_map::iterator iter = mDelayedPacketMap.find(packet_id); + if (iter != mDelayedPacketMap.end()) { - llerrs << "Packet ALREADY in delayed packet map!" << llendl; + if (!(iter->second->mSize == size) && !(iter->second->mDatap == datap)) + { + LL_ERRS() << "Packet ALREADY in delayed packet map!" << LL_ENDL; + } } #endif @@ -1269,7 +1287,7 @@ LLTransferTarget* LLTransferTarget::createTarget( case LLTTT_VFILE: return new LLTransferTargetVFile(id, source_type); default: - llwarns << "Unknown transfer target type: " << type << llendl; + LL_WARNS() << "Unknown transfer target type: " << type << LL_ENDL; return NULL; } } @@ -1304,7 +1322,7 @@ void LLTransferSourceParamsInvItem::setAsset(const LLUUID &asset_id, const LLAss void LLTransferSourceParamsInvItem::packParams(LLDataPacker &dp) const { - lldebugs << "LLTransferSourceParamsInvItem::packParams()" << llendl; + LL_DEBUGS() << "LLTransferSourceParamsInvItem::packParams()" << LL_ENDL; dp.packUUID(mAgentID, "AgentID"); dp.packUUID(mSessionID, "SessionID"); dp.packUUID(mOwnerID, "OwnerID"); diff --git a/indra/llmessage/lltransfermanager.h b/indra/llmessage/lltransfermanager.h index 252e05d1d1..6aad153c24 100644 --- a/indra/llmessage/lltransfermanager.h +++ b/indra/llmessage/lltransfermanager.h @@ -199,7 +199,7 @@ class LLTransferSourceChannel void addTransferSource(LLTransferSource *sourcep); LLTransferSource *findTransferSource(const LLUUID &transfer_id); - BOOL deleteTransfer(LLTransferSource *tsp); + void deleteTransfer(LLTransferSource *tsp); void setThrottleID(const S32 throttle_id) { mThrottleID = throttle_id; } @@ -232,7 +232,7 @@ class LLTransferTargetChannel const F32 priority); LLTransferTarget *findTransferTarget(const LLUUID &transfer_id); - BOOL deleteTransfer(LLTransferTarget *ttp); + void deleteTransfer(LLTransferTarget *ttp); LLTransferChannelType getChannelType() const { return mChannelType; } diff --git a/indra/llmessage/lltransfersourceasset.cpp b/indra/llmessage/lltransfersourceasset.cpp index 8537773a3f..80ed3340c6 100644 --- a/indra/llmessage/lltransfersourceasset.cpp +++ b/indra/llmessage/lltransfersourceasset.cpp @@ -66,18 +66,18 @@ void LLTransferSourceAsset::initTransfer() } else { - llwarns << "Attempted to request blocked asset " + LL_WARNS() << "Attempted to request blocked asset " << mParams.getAssetID() << ":" << LLAssetType::lookupHumanReadable(mParams.getAssetType()) - << llendl; + << LL_ENDL; sendTransferStatus(LLTS_ERROR); } } else { - llwarns << "Attempted to request asset " << mParams.getAssetID() + LL_WARNS() << "Attempted to request asset " << mParams.getAssetID() << ":" << LLAssetType::lookupHumanReadable(mParams.getAssetType()) - << " without an asset system!" << llendl; + << " without an asset system!" << LL_ENDL; sendTransferStatus(LLTS_ERROR); } } @@ -93,7 +93,7 @@ LLTSCode LLTransferSourceAsset::dataCallback(const S32 packet_id, S32 &returned_bytes, BOOL &delete_returned) { - //llinfos << "LLTransferSourceAsset::dataCallback" << llendl; + //LL_INFOS() << "LLTransferSourceAsset::dataCallback" << LL_ENDL; if (!mGotResponse) { return LLTS_SKIP; @@ -109,14 +109,14 @@ LLTSCode LLTransferSourceAsset::dataCallback(const S32 packet_id, if (packet_id != mLastPacketID + 1) { - llerrs << "Can't handle out of order file transfer yet!" << llendl; + LL_ERRS() << "Can't handle out of order file transfer yet!" << LL_ENDL; } // grab a buffer from the right place in the file if (!vf.seek(mCurPos, 0)) { - llwarns << "LLTransferSourceAsset Can't seek to " << mCurPos << " length " << vf.getSize() << llendl; - llwarns << "While sending " << mParams.getAssetID() << llendl; + LL_WARNS() << "LLTransferSourceAsset Can't seek to " << mCurPos << " length " << vf.getSize() << LL_ENDL; + LL_WARNS() << "While sending " << mParams.getAssetID() << LL_ENDL; return LLTS_ERROR; } @@ -160,13 +160,13 @@ void LLTransferSourceAsset::completionCallback(const LLTSCode status) void LLTransferSourceAsset::packParams(LLDataPacker& dp) const { - //llinfos << "LLTransferSourceAsset::packParams" << llendl; + //LL_INFOS() << "LLTransferSourceAsset::packParams" << LL_ENDL; mParams.packParams(dp); } BOOL LLTransferSourceAsset::unpackParams(LLDataPacker &dp) { - //llinfos << "LLTransferSourceAsset::unpackParams" << llendl; + //LL_INFOS() << "LLTransferSourceAsset::unpackParams" << LL_ENDL; return mParams.unpackParams(dp); } @@ -183,13 +183,13 @@ void LLTransferSourceAsset::responderCallback(LLVFS *vfs, const LLUUID& uuid, LL if (!tsap) { - llinfos << "Aborting transfer " << transfer_id << " callback, transfer source went away" << llendl; + LL_INFOS() << "Aborting transfer " << transfer_id << " callback, transfer source went away" << LL_ENDL; return; } if (result) { - llinfos << "AssetStorage: Error " << gAssetStorage->getErrorString(result) << " downloading uuid " << uuid << llendl; + LL_INFOS() << "AssetStorage: Error " << gAssetStorage->getErrorString(result) << " downloading uuid " << uuid << LL_ENDL; } LLTSCode status; diff --git a/indra/llmessage/lltransfersourcefile.cpp b/indra/llmessage/lltransfersourcefile.cpp index 43c9448fba..1f284a158d 100644 --- a/indra/llmessage/lltransfersourcefile.cpp +++ b/indra/llmessage/lltransfersourcefile.cpp @@ -43,7 +43,7 @@ LLTransferSourceFile::~LLTransferSourceFile() { if (mFP) { - llerrs << "Destructor called without the completion callback being called!" << llendl; + LL_ERRS() << "Destructor called without the completion callback being called!" << LL_ENDL; } } @@ -56,7 +56,7 @@ void LLTransferSourceFile::initTransfer() || (filename == "..") || (filename.find(delimiter[0]) != std::string::npos)) { - llwarns << "Attempting to transfer file " << filename << " with path delimiter, aborting!" << llendl; + LL_WARNS() << "Attempting to transfer file " << filename << " with path delimiter, aborting!" << LL_ENDL; sendTransferStatus(LLTS_ERROR); return; @@ -88,17 +88,17 @@ LLTSCode LLTransferSourceFile::dataCallback(const S32 packet_id, S32 &returned_bytes, BOOL &delete_returned) { - //llinfos << "LLTransferSourceFile::dataCallback" << llendl; + //LL_INFOS() << "LLTransferSourceFile::dataCallback" << LL_ENDL; if (!mFP) { - llerrs << "Data callback without file set!" << llendl; + LL_ERRS() << "Data callback without file set!" << LL_ENDL; return LLTS_ERROR; } if (packet_id != mLastPacketID + 1) { - llerrs << "Can't handle out of order file transfer yet!" << llendl; + LL_ERRS() << "Can't handle out of order file transfer yet!" << LL_ENDL; } // Grab up until the max number of bytes from the file. @@ -137,13 +137,13 @@ void LLTransferSourceFile::completionCallback(const LLTSCode status) void LLTransferSourceFile::packParams(LLDataPacker& dp) const { - //llinfos << "LLTransferSourceFile::packParams" << llendl; + //LL_INFOS() << "LLTransferSourceFile::packParams" << LL_ENDL; mParams.packParams(dp); } BOOL LLTransferSourceFile::unpackParams(LLDataPacker &dp) { - //llinfos << "LLTransferSourceFile::unpackParams" << llendl; + //LL_INFOS() << "LLTransferSourceFile::unpackParams" << LL_ENDL; return mParams.unpackParams(dp); } @@ -169,6 +169,6 @@ BOOL LLTransferSourceParamsFile::unpackParams(LLDataPacker &dp) dp.unpackU8(delete_flag, "Delete"); mDeleteOnCompletion = delete_flag; - llinfos << "Unpacked filename: " << mFilename << llendl; + LL_INFOS() << "Unpacked filename: " << mFilename << LL_ENDL; return TRUE; } diff --git a/indra/llmessage/lltransfertargetfile.cpp b/indra/llmessage/lltransfertargetfile.cpp index 560fc8b6e4..ca0318a2d6 100644 --- a/indra/llmessage/lltransfertargetfile.cpp +++ b/indra/llmessage/lltransfertargetfile.cpp @@ -44,7 +44,7 @@ LLTransferTargetFile::~LLTransferTargetFile() { if (mFP) { - llerrs << "LLTransferTargetFile::~LLTransferTargetFile - Should have been cleaned up in completion callback" << llendl; + LL_ERRS() << "LLTransferTargetFile::~LLTransferTargetFile - Should have been cleaned up in completion callback" << LL_ENDL; fclose(mFP); mFP = NULL; } @@ -61,7 +61,7 @@ void LLTransferTargetFile::applyParams(const LLTransferTargetParams ¶ms) { if (params.getType() != mType) { - llwarns << "Target parameter type doesn't match!" << llendl; + LL_WARNS() << "Target parameter type doesn't match!" << LL_ENDL; return; } @@ -70,8 +70,8 @@ void LLTransferTargetFile::applyParams(const LLTransferTargetParams ¶ms) LLTSCode LLTransferTargetFile::dataCallback(const S32 packet_id, U8 *in_datap, const S32 in_size) { - //llinfos << "LLTransferTargetFile::dataCallback" << llendl; - //llinfos << "Packet: " << packet_id << llendl; + //LL_INFOS() << "LLTransferTargetFile::dataCallback" << LL_ENDL; + //LL_INFOS() << "Packet: " << packet_id << LL_ENDL; if (!mFP) { @@ -79,7 +79,7 @@ LLTSCode LLTransferTargetFile::dataCallback(const S32 packet_id, U8 *in_datap, c if (!mFP) { - llwarns << "Failure opening " << mParams.mFilename << " for write by LLTransferTargetFile" << llendl; + LL_WARNS() << "Failure opening " << mParams.mFilename << " for write by LLTransferTargetFile" << LL_ENDL; return LLTS_ERROR; } } @@ -91,7 +91,7 @@ LLTSCode LLTransferTargetFile::dataCallback(const S32 packet_id, U8 *in_datap, c S32 count = (S32)fwrite(in_datap, 1, in_size, mFP); if (count != in_size) { - llwarns << "Failure in LLTransferTargetFile::dataCallback!" << llendl; + LL_WARNS() << "Failure in LLTransferTargetFile::dataCallback!" << LL_ENDL; return LLTS_ERROR; } return LLTS_OK; @@ -99,7 +99,7 @@ LLTSCode LLTransferTargetFile::dataCallback(const S32 packet_id, U8 *in_datap, c void LLTransferTargetFile::completionCallback(const LLTSCode status) { - llinfos << "LLTransferTargetFile::completionCallback" << llendl; + LL_INFOS() << "LLTransferTargetFile::completionCallback" << LL_ENDL; if (mFP) { fclose(mFP); @@ -113,7 +113,7 @@ void LLTransferTargetFile::completionCallback(const LLTSCode status) case LLTS_ABORT: case LLTS_ERROR: // We're aborting this transfer, we don't want to keep this file. - llwarns << "Aborting file transfer for " << mParams.mFilename << llendl; + LL_WARNS() << "Aborting file transfer for " << mParams.mFilename << LL_ENDL; if (mFP) { // Only need to remove file if we successfully opened it. diff --git a/indra/llmessage/lltransfertargetvfile.cpp b/indra/llmessage/lltransfertargetvfile.cpp index c78d9288b6..a572c68a7f 100644 --- a/indra/llmessage/lltransfertargetvfile.cpp +++ b/indra/llmessage/lltransfertargetvfile.cpp @@ -42,7 +42,7 @@ LLTransferTargetParamsVFile::LLTransferTargetParamsVFile() : LLTransferTargetParams(LLTTT_VFILE), mAssetType(LLAssetType::AT_NONE), mCompleteCallback(NULL), - mUserDatap(NULL), + mRequestDatap(NULL), mErrCode(0) { } @@ -55,10 +55,14 @@ void LLTransferTargetParamsVFile::setAsset( mAssetType = asset_type; } -void LLTransferTargetParamsVFile::setCallback(LLTTVFCompleteCallback cb, void *user_data) +void LLTransferTargetParamsVFile::setCallback(LLTTVFCompleteCallback cb, LLBaseDownloadRequest& request) { mCompleteCallback = cb; - mUserDatap = user_data; + if (mRequestDatap) + { + delete mRequestDatap; + } + mRequestDatap = request.getCopy(); } bool LLTransferTargetParamsVFile::unpackParams(LLDataPacker& dp) @@ -98,6 +102,12 @@ LLTransferTargetVFile::LLTransferTargetVFile( LLTransferTargetVFile::~LLTransferTargetVFile() { + if (mParams.mRequestDatap) + { + // TODO: Consider doing it in LLTransferTargetParamsVFile's destructor + delete mParams.mRequestDatap; + mParams.mRequestDatap = NULL; + } } @@ -115,7 +125,7 @@ void LLTransferTargetVFile::applyParams(const LLTransferTargetParams ¶ms) { if (params.getType() != mType) { - llwarns << "Target parameter type doesn't match!" << llendl; + LL_WARNS() << "Target parameter type doesn't match!" << LL_ENDL; return; } @@ -125,8 +135,8 @@ void LLTransferTargetVFile::applyParams(const LLTransferTargetParams ¶ms) LLTSCode LLTransferTargetVFile::dataCallback(const S32 packet_id, U8 *in_datap, const S32 in_size) { - //llinfos << "LLTransferTargetFile::dataCallback" << llendl; - //llinfos << "Packet: " << packet_id << llendl; + //LL_INFOS() << "LLTransferTargetFile::dataCallback" << LL_ENDL; + //LL_INFOS() << "Packet: " << packet_id << LL_ENDL; LLVFile vf(gAssetStorage->mVFS, mTempID, mParams.getAssetType(), LLVFile::APPEND); if (mNeedsCreate) @@ -142,7 +152,7 @@ LLTSCode LLTransferTargetVFile::dataCallback(const S32 packet_id, U8 *in_datap, if (!vf.write(in_datap, in_size)) { - llwarns << "Failure in LLTransferTargetVFile::dataCallback!" << llendl; + LL_WARNS() << "Failure in LLTransferTargetVFile::dataCallback!" << LL_ENDL; return LLTS_ERROR; } return LLTS_OK; @@ -151,11 +161,11 @@ LLTSCode LLTransferTargetVFile::dataCallback(const S32 packet_id, U8 *in_datap, void LLTransferTargetVFile::completionCallback(const LLTSCode status) { - //llinfos << "LLTransferTargetVFile::completionCallback" << llendl; + //LL_INFOS() << "LLTransferTargetVFile::completionCallback" << LL_ENDL; if (!gAssetStorage) { - llwarns << "Aborting vfile transfer after asset storage shut down!" << llendl; + LL_WARNS() << "Aborting vfile transfer after asset storage shut down!" << LL_ENDL; return; } @@ -169,14 +179,14 @@ void LLTransferTargetVFile::completionCallback(const LLTSCode status) LLVFile file(gAssetStorage->mVFS, mTempID, mParams.getAssetType(), LLVFile::WRITE); if (!file.rename(mParams.getAssetID(), mParams.getAssetType())) { - llerrs << "LLTransferTargetVFile: rename failed" << llendl; + LL_ERRS() << "LLTransferTargetVFile: rename failed" << LL_ENDL; } } err_code = LL_ERR_NOERR; - lldebugs << "LLTransferTargetVFile::completionCallback for " + LL_DEBUGS() << "LLTransferTargetVFile::completionCallback for " << mParams.getAssetID() << "," << LLAssetType::lookup(mParams.getAssetType()) - << " with temp id " << mTempID << llendl; + << " with temp id " << mTempID << LL_ENDL; break; case LLTS_ERROR: case LLTS_ABORT: @@ -184,7 +194,7 @@ void LLTransferTargetVFile::completionCallback(const LLTSCode status) default: { // We're aborting this transfer, we don't want to keep this file. - llwarns << "Aborting vfile transfer for " << mParams.getAssetID() << llendl; + LL_WARNS() << "Aborting vfile transfer for " << mParams.getAssetID() << LL_ENDL; LLVFile vf(gAssetStorage->mVFS, mTempID, mParams.getAssetType(), LLVFile::APPEND); vf.remove(); } @@ -208,12 +218,18 @@ void LLTransferTargetVFile::completionCallback(const LLTSCode status) err_code = LL_ERR_ASSET_REQUEST_FAILED; break; } - if (mParams.mCompleteCallback) - { - mParams.mCompleteCallback(err_code, - mParams.getAssetID(), - mParams.getAssetType(), - mParams.mUserDatap, - LL_EXSTAT_NONE); - } + + if (mParams.mRequestDatap) + { + if (mParams.mCompleteCallback) + { + mParams.mCompleteCallback(err_code, + mParams.getAssetID(), + mParams.getAssetType(), + mParams.mRequestDatap, + LL_EXSTAT_NONE); + } + delete mParams.mRequestDatap; + mParams.mRequestDatap = NULL; + } } diff --git a/indra/llmessage/lltransfertargetvfile.h b/indra/llmessage/lltransfertargetvfile.h index 23a65e4bb2..c819c1e2f2 100644 --- a/indra/llmessage/lltransfertargetvfile.h +++ b/indra/llmessage/lltransfertargetvfile.h @@ -39,7 +39,7 @@ typedef void (*LLTTVFCompleteCallback)( S32 status, const LLUUID& file_id, LLAssetType::EType file_type, - void* user_data, LLExtStat ext_status ); + LLBaseDownloadRequest* user_data, LLExtStat ext_status ); class LLTransferTargetParamsVFile : public LLTransferTargetParams { @@ -47,7 +47,7 @@ class LLTransferTargetParamsVFile : public LLTransferTargetParams LLTransferTargetParamsVFile(); void setAsset(const LLUUID& asset_id, LLAssetType::EType asset_type); - void setCallback(LLTTVFCompleteCallback cb, void* user_data); + void setCallback(LLTTVFCompleteCallback cb, LLBaseDownloadRequest& request); LLUUID getAssetID() const { return mAssetID; } LLAssetType::EType getAssetType() const { return mAssetType; } @@ -60,7 +60,7 @@ class LLTransferTargetParamsVFile : public LLTransferTargetParams LLAssetType::EType mAssetType; LLTTVFCompleteCallback mCompleteCallback; - void* mUserDatap; + LLBaseDownloadRequest* mRequestDatap; S32 mErrCode; }; diff --git a/indra/llmessage/lltrustedmessageservice.cpp b/indra/llmessage/lltrustedmessageservice.cpp index fea7fc72c4..151d02a156 100644 --- a/indra/llmessage/lltrustedmessageservice.cpp +++ b/indra/llmessage/lltrustedmessageservice.cpp @@ -63,7 +63,7 @@ void LLTrustedMessageService::post(LLHTTPNode::ResponsePtr response, { LL_WARNS("Messaging") << "trusted message POST to /trusted-message/" << name << " from unknown or untrusted sender " - << sender << llendl; + << sender << LL_ENDL; response->status(403, "Unknown or untrusted sender"); } else @@ -71,13 +71,13 @@ void LLTrustedMessageService::post(LLHTTPNode::ResponsePtr response, gMessageSystem->receivedMessageFromTrustedSender(); if (input.has("binary-template-data")) { - llinfos << "Dispatching template: " << input << llendl; + LL_INFOS() << "Dispatching template: " << input << LL_ENDL; // try and send this message using udp dispatch LLMessageSystem::dispatchTemplate(name, message_data, response); } else { - llinfos << "Dispatching without template: " << input << llendl; + LL_INFOS() << "Dispatching without template: " << input << LL_ENDL; LLMessageSystem::dispatch(name, message_data, response); } } diff --git a/indra/llmessage/llurlrequest.cpp b/indra/llmessage/llurlrequest.cpp index b10b0c3709..961e9196d5 100644 --- a/indra/llmessage/llurlrequest.cpp +++ b/indra/llmessage/llurlrequest.cpp @@ -78,7 +78,7 @@ LLURLRequest::LLURLRequest(LLURLRequest::ERequestAction action, std::string cons LLHTTPClient::ResponderPtr responder, AIHTTPHeaders& headers, AIPerService::Approvement* approved, bool keepalive, bool is_auth, bool compression) : mAction(action), mURL(url), mKeepAlive(keepalive), mIsAuth(is_auth), mNoCompression(!compression), - mBody(body), mResponder(responder), mHeaders(headers), mResponderNameCache(responder ? responder->getName() : "") + mBody(body), mResponder(responder), mHeaders(headers), mResponderNameCache(std::string("LLURLRequest:") + std::string(responder ? responder->getName() : "")) { if (approved) { @@ -97,7 +97,7 @@ void LLURLRequest::initialize_impl(void) useProxy(false); } - if (mAction == LLHTTPClient::HTTP_PUT || mAction == LLHTTPClient::HTTP_POST) + if (mAction == LLHTTPClient::HTTP_PUT || mAction == LLHTTPClient::HTTP_POST || mAction == LLHTTPClient::HTTP_PATCH) { // If the Content-Type header was passed in we defer to the caller's wisdom, // but if they did not specify a Content-Type, then ask the injector. @@ -132,7 +132,7 @@ void LLURLRequest::initialize_impl(void) } catch (AICurlNoBody const& error) { - llwarns << "Injector::get_body() failed: " << error.what() << llendl; + LL_WARNS() << "Injector::get_body() failed: " << error.what() << LL_ENDL; } if (success) @@ -146,6 +146,18 @@ void LLURLRequest::initialize_impl(void) } } +void LLURLRequest::force_killed(void) +{ + // Avoid destructing the responder, if any, because that might + // execute code that might crash now that the viewer is exiting. + if (mResponder) + { + intrusive_ptr_add_ref(mResponder.get()); + } + // Call base class. + AIStateMachine::force_killed(); +} + void LLURLRequest::addHeader(const char* header) { AICurlEasyRequest_wat curlEasyRequest_w(*mCurlEasyRequest); @@ -212,7 +224,7 @@ bool LLURLRequest::configure(AICurlEasyRequest_wat const& curlEasyRequest_w) curlEasyRequest_w->setopt(CURLOPT_HTTPGET, 1); // Set Accept-Encoding to allow response compression - curlEasyRequest_w->setoptString(CURLOPT_ENCODING, mNoCompression ? "identity" : ""); + curlEasyRequest_w->setopt(CURLOPT_ACCEPT_ENCODING, mNoCompression ? "identity" : nullptr); rv = true; break; @@ -222,17 +234,26 @@ bool LLURLRequest::configure(AICurlEasyRequest_wat const& curlEasyRequest_w) curlEasyRequest_w->setPut(mBodySize, mKeepAlive); // Set Accept-Encoding to allow response compression - curlEasyRequest_w->setoptString(CURLOPT_ENCODING, mNoCompression ? "identity" : ""); + curlEasyRequest_w->setopt(CURLOPT_ACCEPT_ENCODING, mNoCompression ? "identity" : nullptr); rv = true; break; + + + case LLHTTPClient::HTTP_PATCH: + curlEasyRequest_w->setPatch(mBodySize, mKeepAlive); + + curlEasyRequest_w->setopt(CURLOPT_ACCEPT_ENCODING, mNoCompression ? "identity" : nullptr); + rv = true; + break; + case LLHTTPClient::HTTP_POST: // Set the handle for an http post curlEasyRequest_w->setPost(mBodySize, mKeepAlive); // Set Accept-Encoding to allow response compression - curlEasyRequest_w->setoptString(CURLOPT_ENCODING, mNoCompression ? "identity" : ""); + curlEasyRequest_w->setopt(CURLOPT_ACCEPT_ENCODING, mNoCompression ? "identity" : nullptr); rv = true; break; @@ -242,6 +263,12 @@ bool LLURLRequest::configure(AICurlEasyRequest_wat const& curlEasyRequest_w) rv = true; break; + case LLHTTPClient::HTTP_COPY: + // Set the handle for an http copy + curlEasyRequest_w->setoptString(CURLOPT_CUSTOMREQUEST, "COPY"); + rv = true; + break; + case LLHTTPClient::HTTP_MOVE: // Set the handle for an http post curlEasyRequest_w->setoptString(CURLOPT_CUSTOMREQUEST, "MOVE"); @@ -249,7 +276,7 @@ bool LLURLRequest::configure(AICurlEasyRequest_wat const& curlEasyRequest_w) break; default: - llwarns << "Unhandled URLRequest action: " << mAction << llendl; + LL_WARNS() << "Unhandled URLRequest action: " << mAction << LL_ENDL; break; } if(rv) @@ -264,32 +291,4 @@ bool LLURLRequest::configure(AICurlEasyRequest_wat const& curlEasyRequest_w) return rv; } -// Called from AIStateMachine::mainloop, but put here because we don't want to include llurlrequest.h there of course. -void print_statemachine_diagnostics(U64 total_clocks, U64 max_delta, AIEngine::queued_type::const_reference slowest_element) -{ - AIStateMachine const& slowest_state_machine = slowest_element.statemachine(); - LLURLRequest const* request = dynamic_cast(&slowest_state_machine); - F64 const tfactor = 1000 / calc_clock_frequency(); - std::ostringstream msg; - if (total_clocks > max_delta) - { - msg << "AIStateMachine::mainloop did run for " << (total_clocks * tfactor) << " ms. The slowest "; - } - else - { - msg << "AIStateMachine::mainloop: A "; - } - msg << "state machine "; - if (request) - { - msg << "(" << request->getResponderName() << ") "; - } - msg << "ran for " << (max_delta * tfactor) << " ms"; - if (slowest_state_machine.getRuntime() > max_delta) - { - msg << " (" << (slowest_state_machine.getRuntime() * tfactor) << " ms in total now)"; - } - msg << "."; - llwarns << msg.str() << llendl; -} diff --git a/indra/llmessage/llurlrequest.h b/indra/llmessage/llurlrequest.h index de92156c6a..697b42b460 100644 --- a/indra/llmessage/llurlrequest.h +++ b/indra/llmessage/llurlrequest.h @@ -72,7 +72,7 @@ class LLURLRequest : public AICurlEasyRequestStateMachine { /** * @brief Cached value of responder->getName() as passed to the constructor. */ - char const* getResponderName(void) const { return mResponderNameCache; } + /*virtual*/ const char* getName() const { return mResponderNameCache.c_str(); } protected: // Call abort(), not delete. @@ -113,11 +113,14 @@ class LLURLRequest : public AICurlEasyRequestStateMachine { U32 mBodySize; LLHTTPClient::ResponderPtr mResponder; AIHTTPHeaders mHeaders; - char const* mResponderNameCache; + std::string mResponderNameCache; protected: // Handle initializing the object. /*virtual*/ void initialize_impl(void); + + // Called when statemachine was flushed (and killed) at viewer exit. + /*virtual*/ void force_killed(void); }; #endif // LL_LLURLREQUEST_H diff --git a/indra/llmessage/lluseroperation.cpp b/indra/llmessage/lluseroperation.cpp index a4a68d0c81..c506af19ce 100644 --- a/indra/llmessage/lluseroperation.cpp +++ b/indra/llmessage/lluseroperation.cpp @@ -100,7 +100,7 @@ LLUserOperationMgr::~LLUserOperationMgr() { if (mUserOperationList.size() > 0) { - llwarns << "Exiting with user operations pending." << llendl; + LL_WARNS() << "Exiting with user operations pending." << LL_ENDL; } } @@ -109,7 +109,7 @@ void LLUserOperationMgr::addOperation(LLUserOperation* op) { if(!op) { - llwarns << "Tried to add null op" << llendl; + LL_WARNS() << "Tried to add null op" << LL_ENDL; return; } LLUUID id = op->getTransactionID(); @@ -160,7 +160,7 @@ void LLUserOperationMgr::deleteExpiredOperations() op = (*it).second; if(op && op->isExpired()) { - lldebugs << "expiring: " << (*it).first << llendl; + LL_DEBUGS() << "expiring: " << (*it).first << LL_ENDL; op->expire(); mUserOperationList.erase(it++); delete op; diff --git a/indra/llmessage/llxfer.cpp b/indra/llmessage/llxfer.cpp index f8c55d52ad..81815edcf6 100644 --- a/indra/llmessage/llxfer.cpp +++ b/indra/llmessage/llxfer.cpp @@ -30,7 +30,6 @@ #include "lluuid.h" #include "llerror.h" #include "llmath.h" -#include "u64.h" //number of bytes sent in each message const U32 LL_XFER_CHUNK_SIZE = 1000; @@ -63,7 +62,6 @@ void LLXfer::init (S32 chunk_size) mXferSize = 0; mStatus = e_LL_XFER_UNINITIALIZED; - mNext = NULL; mWaitingForACK = FALSE; mCallback = NULL; @@ -99,7 +97,22 @@ void LLXfer::cleanup () S32 LLXfer::startSend (U64 xfer_id, const LLHost &remote_host) { - llwarns << "undifferentiated LLXfer::startSend for " << getFileName() << llendl; + LL_WARNS("Xfer") << "unexpected call to base class LLXfer::startSend for " << getFileName() << LL_ENDL; + return (-1); +} + +/////////////////////////////////////////////////////////// + +void LLXfer::closeFileHandle() +{ + LL_WARNS("Xfer") << "unexpected call to base class LLXfer::closeFileHandle for " << getFileName() << LL_ENDL; +} + +/////////////////////////////////////////////////////////// + +S32 LLXfer::reopenFileHandle() +{ + LL_WARNS("Xfer") << "unexpected call to base class LLXfer::reopenFileHandle for " << getFileName() << LL_ENDL; return (-1); } @@ -115,8 +128,8 @@ void LLXfer::setXferSize (S32 xfer_size) S32 LLXfer::startDownload() { - llwarns << "undifferentiated LLXfer::startDownload for " << getFileName() - << llendl; + LL_WARNS("Xfer") << "undifferentiated LLXfer::startDownload for " << getFileName() + << LL_ENDL; return (-1); } @@ -140,7 +153,7 @@ S32 LLXfer::receiveData (char *datap, S32 data_size) } else { - llerrs << "NULL data passed in receiveData" << llendl; + LL_ERRS("Xfer") << "NULL data passed in receiveData" << LL_ENDL; } } @@ -163,7 +176,7 @@ S32 LLXfer::flush() S32 LLXfer::suck(S32 start_position) { - llwarns << "Attempted to send a packet outside the buffer bounds in LLXfer::suck()" << llendl; + LL_WARNS("Xfer") << "Attempted to send a packet outside the buffer bounds in LLXfer::suck()" << LL_ENDL; return (-1); } @@ -196,7 +209,7 @@ void LLXfer::sendPacket(S32 packet_num) if (fdata_size < 0) { - llwarns << "negative data size in xfer send, aborting" << llendl; + LL_WARNS("Xfer") << "negative data size in xfer send, aborting" << LL_ENDL; abort(LL_ERR_EOF); return; } @@ -248,7 +261,12 @@ void LLXfer::sendPacket(S32 packet_num) gMessageSystem->nextBlockFast(_PREHASH_DataPacket); gMessageSystem->addBinaryDataFast(_PREHASH_Data, &fdata_buf,fdata_size); - gMessageSystem->sendMessage(mRemoteHost); + S32 sent_something = gMessageSystem->sendMessage(mRemoteHost); + if (sent_something == 0) + { + abort(LL_ERR_CIRCUIT_GONE); + return; + } ACKTimer.reset(); mWaitingForACK = TRUE; @@ -289,13 +307,13 @@ S32 LLXfer::processEOF() if (LL_ERR_NOERR == mCallbackResult) { - llinfos << "xfer from " << mRemoteHost << " complete: " << getFileName() - << llendl; + LL_INFOS("Xfer") << "xfer from " << mRemoteHost << " complete: " << getFileName() + << LL_ENDL; } else { - llinfos << "xfer from " << mRemoteHost << " failed, code " - << mCallbackResult << ": " << getFileName() << llendl; + LL_INFOS("Xfer") << "xfer from " << mRemoteHost << " failed, code " + << mCallbackResult << ": " << getFileName() << LL_ENDL; } if (mCallback) @@ -323,15 +341,18 @@ void LLXfer::abort (S32 result_code) { mCallbackResult = result_code; - llinfos << "Aborting xfer from " << mRemoteHost << " named " << getFileName() - << " - error: " << result_code << llendl; + LL_INFOS("Xfer") << "Aborting xfer from " << mRemoteHost << " named " << getFileName() + << " - error: " << result_code << LL_ENDL; - gMessageSystem->newMessageFast(_PREHASH_AbortXfer); - gMessageSystem->nextBlockFast(_PREHASH_XferID); - gMessageSystem->addU64Fast(_PREHASH_ID, mID); - gMessageSystem->addS32Fast(_PREHASH_Result, result_code); - - gMessageSystem->sendMessage(mRemoteHost); + if (result_code != LL_ERR_CIRCUIT_GONE) + { + gMessageSystem->newMessageFast(_PREHASH_AbortXfer); + gMessageSystem->nextBlockFast(_PREHASH_XferID); + gMessageSystem->addU64Fast(_PREHASH_ID, mID); + gMessageSystem->addS32Fast(_PREHASH_Result, result_code); + + gMessageSystem->sendMessage(mRemoteHost); + } mStatus = e_LL_XFER_ABORTED; } @@ -341,7 +362,7 @@ void LLXfer::abort (S32 result_code) std::string LLXfer::getFileName() { - return U64_to_str(mID); + return fmt::to_string(mID); } /////////////////////////////////////////////////////////// diff --git a/indra/llmessage/llxfer.h b/indra/llmessage/llxfer.h index f9348eb11f..064278afd4 100644 --- a/indra/llmessage/llxfer.h +++ b/indra/llmessage/llxfer.h @@ -32,6 +32,10 @@ #include "llextendedstatus.h" const S32 LL_XFER_LARGE_PAYLOAD = 7680; +const S32 LL_ERR_FILE_EMPTY = -44; +const int LL_ERR_FILE_NOT_FOUND = -43; +const int LL_ERR_CANNOT_OPEN_FILE = -42; +const int LL_ERR_EOF = -39; typedef enum ELLXferStatus { e_LL_XFER_UNINITIALIZED, @@ -50,7 +54,6 @@ class LLXfer S32 mChunkSize; public: - LLXfer *mNext; U64 mID; S32 mPacketNum; @@ -86,7 +89,9 @@ class LLXfer void init(S32 chunk_size); virtual void cleanup(); - virtual S32 startSend (U64 xfer_id, const LLHost &remote_host); + virtual S32 startSend(U64 xfer_id, const LLHost &remote_host); + virtual void closeFileHandle(); + virtual S32 reopenFileHandle(); virtual void sendPacket(S32 packet_num); virtual void sendNextPacket(); virtual void resendLastPacket(); diff --git a/indra/llmessage/llxfer_file.cpp b/indra/llmessage/llxfer_file.cpp index 9e02af2c3e..41d7dcd6c7 100644 --- a/indra/llmessage/llxfer_file.cpp +++ b/indra/llmessage/llxfer_file.cpp @@ -98,16 +98,16 @@ void LLXfer_File::cleanup () mFp = NULL; } - LLFile::remove(mTempFilename); + LLFile::remove(mTempFilename, ENOENT); if (mDeleteLocalOnCompletion) { - lldebugs << "Removing file: " << mLocalFilename << llendl; - LLFile::remove(mLocalFilename); + LL_DEBUGS("Xfer") << "Removing file: " << mLocalFilename << LL_ENDL; + LLFile::remove(mLocalFilename, ENOENT); } else { - lldebugs << "Keeping local file: " << mLocalFilename << llendl; + LL_DEBUGS("Xfer") << "Keeping local file: " << mLocalFilename << LL_ENDL; } LLXfer::cleanup(); @@ -139,7 +139,7 @@ S32 LLXfer_File::initializeRequest(U64 xfer_id, mCallbackDataHandle = user_data; mCallbackResult = LL_ERR_NOERR; - llinfos << "Requesting xfer from " << remote_host << " for file: " << mLocalFilename << llendl; + LL_INFOS("Xfer") << "Requesting xfer from " << remote_host << " for file: " << mLocalFilename << LL_ENDL; if (mBuffer) { @@ -182,7 +182,7 @@ S32 LLXfer_File::startDownload() } else { - llwarns << "Couldn't create file to be received!" << llendl; + LL_WARNS("Xfer") << "Couldn't create file to be received!" << LL_ENDL; retval = -1; } @@ -223,7 +223,7 @@ S32 LLXfer_File::startSend (U64 xfer_id, const LLHost &remote_host) } else { - llinfos << "Warning: " << mLocalFilename << " not found." << llendl; + LL_INFOS("Xfer") << "Warning: " << mLocalFilename << " not found." << LL_ENDL; return (LL_ERR_FILE_NOT_FOUND); } @@ -232,6 +232,36 @@ S32 LLXfer_File::startSend (U64 xfer_id, const LLHost &remote_host) return (retval); } +/////////////////////////////////////////////////////////// +void LLXfer_File::closeFileHandle() +{ + if (mFp) + { + fclose(mFp); + mFp = NULL; + } +} + +/////////////////////////////////////////////////////////// + +S32 LLXfer_File::reopenFileHandle() +{ + S32 retval = LL_ERR_NOERR; // presume success + + if (mFp == NULL) + { + mFp = LLFile::fopen(mLocalFilename,"rb"); /* Flawfinder : ignore */ + if (mFp == NULL) + { + LL_INFOS("Xfer") << "Warning: " << mLocalFilename << " not found when re-opening file" << LL_ENDL; + retval = LL_ERR_FILE_NOT_FOUND; + } + } + + return retval; +} + + /////////////////////////////////////////////////////////// S32 LLXfer_File::getMaxBufferSize () @@ -279,18 +309,21 @@ S32 LLXfer_File::flush() { if (mFp) { - llerrs << "Overwriting open file pointer!" << llendl; + LL_ERRS("Xfer") << "Overwriting open file pointer!" << LL_ENDL; } mFp = LLFile::fopen(mTempFilename,"a+b"); /* Flawfinder : ignore */ if (mFp) { - if (fwrite(mBuffer,1,mBufferLength,mFp) != mBufferLength) + S32 write_size = fwrite(mBuffer,1,mBufferLength,mFp); + if (write_size != mBufferLength) { - llwarns << "Short write" << llendl; + LL_WARNS("Xfer") << "Non-matching write size, requested " << mBufferLength + << " but wrote " << write_size + << LL_ENDL; } -// llinfos << "******* wrote " << mBufferLength << " bytes of file xfer" << llendl; +// LL_INFOS("Xfer") << "******* wrote " << mBufferLength << " bytes of file xfer" << LL_ENDL; fclose(mFp); mFp = NULL; @@ -298,7 +331,7 @@ S32 LLXfer_File::flush() } else { - llwarns << "LLXfer_File::flush() unable to open " << mTempFilename << " for writing!" << llendl; + LL_WARNS("Xfer") << "LLXfer_File::flush() unable to open " << mTempFilename << " for writing!" << LL_ENDL; retval = LL_ERR_CANNOT_OPEN_FILE; } } @@ -321,7 +354,7 @@ S32 LLXfer_File::processEOF() mCallbackResult = flushval; } - LLFile::remove(mLocalFilename); + LLFile::remove(mLocalFilename, ENOENT); if (!mCallbackResult) { @@ -329,37 +362,37 @@ S32 LLXfer_File::processEOF() { #if !LL_WINDOWS S32 error_number = errno; - llinfos << "Rename failure (" << error_number << ") - " - << mTempFilename << " to " << mLocalFilename << llendl; + LL_INFOS("Xfer") << "Rename failure (" << error_number << ") - " + << mTempFilename << " to " << mLocalFilename << LL_ENDL; if(EXDEV == error_number) { if(copy_file(mTempFilename, mLocalFilename) == 0) { - llinfos << "Rename across mounts; copying+unlinking the file instead." << llendl; + LL_INFOS("Xfer") << "Rename across mounts; copying+unlinking the file instead." << LL_ENDL; unlink(mTempFilename.c_str()); } else { - llwarns << "Copy failure - " << mTempFilename << " to " - << mLocalFilename << llendl; + LL_WARNS("Xfer") << "Copy failure - " << mTempFilename << " to " + << mLocalFilename << LL_ENDL; } } else { //LLFILE* fp = LLFile::fopen(mTempFilename, "r"); - //llwarns << "File " << mTempFilename << " does " - // << (!fp ? "not" : "" ) << " exit." << llendl; + //LL_WARNS() << "File " << mTempFilename << " does " + // << (!fp ? "not" : "" ) << " exit." << LL_ENDL; //if(fp) fclose(fp); //fp = LLFile::fopen(mLocalFilename, "r"); - //llwarns << "File " << mLocalFilename << " does " - // << (!fp ? "not" : "" ) << " exit." << llendl; + //LL_WARNS() << "File " << mLocalFilename << " does " + // << (!fp ? "not" : "" ) << " exit." << LL_ENDL; //if(fp) fclose(fp); - llwarns << "Rename fatally failed, can only handle EXDEV (" - << EXDEV << ")" << llendl; + LL_WARNS("Xfer") << "Rename fatally failed, can only handle EXDEV (" + << EXDEV << ")" << LL_ENDL; } #else - llwarns << "Rename failure - " << mTempFilename << " to " - << mLocalFilename << llendl; + LL_WARNS("Xfer") << "Rename failure - " << mTempFilename << " to " + << mLocalFilename << LL_ENDL; #endif } } diff --git a/indra/llmessage/llxfer_file.h b/indra/llmessage/llxfer_file.h index a37dda6732..ab9374549e 100644 --- a/indra/llmessage/llxfer_file.h +++ b/indra/llmessage/llxfer_file.h @@ -61,8 +61,10 @@ class LLXfer_File : public LLXfer virtual S32 startDownload(); virtual S32 processEOF(); - - virtual S32 startSend (U64 xfer_id, const LLHost &remote_host); + + virtual S32 startSend(U64 xfer_id, const LLHost &remote_host); + virtual void closeFileHandle(); + virtual S32 reopenFileHandle(); virtual S32 suck(S32 start_position); virtual S32 flush(); diff --git a/indra/llmessage/llxfer_mem.cpp b/indra/llmessage/llxfer_mem.cpp index 4c7e83c33d..78a3e4f558 100644 --- a/indra/llmessage/llxfer_mem.cpp +++ b/indra/llmessage/llxfer_mem.cpp @@ -80,28 +80,6 @@ void LLXfer_Mem::setXferSize (S32 xfer_size) /////////////////////////////////////////////////////////// -U64 LLXfer_Mem::registerXfer(U64 xfer_id, const void *datap, const S32 length) -{ - mID = xfer_id; - - if (datap) - { - setXferSize(length); - if (mBuffer) - { - memcpy(mBuffer,datap,length); /* Flawfinder : ignore */ - mBufferLength = length; - } - else - { - xfer_id = 0; - } - } - - mStatus = e_LL_XFER_REGISTERED; - return (xfer_id); -} - S32 LLXfer_Mem::startSend (U64 xfer_id, const LLHost &remote_host) { S32 retval = LL_ERR_NOERR; // presume success @@ -130,7 +108,7 @@ S32 LLXfer_Mem::processEOF() mStatus = e_LL_XFER_COMPLETE; - llinfos << "xfer complete: " << getFileName() << llendl; + LL_INFOS() << "xfer complete: " << getFileName() << LL_ENDL; if (mCallback) { @@ -164,7 +142,7 @@ S32 LLXfer_Mem::initializeRequest(U64 xfer_id, mRemotePath = remote_path; mDeleteRemoteOnCompletion = delete_remote_on_completion; - llinfos << "Requesting file: " << remote_filename << llendl; + LL_INFOS() << "Requesting file: " << remote_filename << LL_ENDL; delete [] mBuffer; mBuffer = NULL; diff --git a/indra/llmessage/llxfer_mem.h b/indra/llmessage/llxfer_mem.h index b5adf837df..d07779de87 100644 --- a/indra/llmessage/llxfer_mem.h +++ b/indra/llmessage/llxfer_mem.h @@ -53,7 +53,6 @@ class LLXfer_Mem : public LLXfer virtual void cleanup(); virtual S32 startSend (U64 xfer_id, const LLHost &remote_host); - virtual U64 registerXfer(U64 xfer_id, const void *datap, const S32 length); virtual void setXferSize (S32 data_size); virtual S32 initializeRequest(U64 xfer_id, diff --git a/indra/llmessage/llxfer_vfile.cpp b/indra/llmessage/llxfer_vfile.cpp index 751a69518c..988bb75134 100644 --- a/indra/llmessage/llxfer_vfile.cpp +++ b/indra/llmessage/llxfer_vfile.cpp @@ -79,8 +79,20 @@ void LLXfer_VFile::init (LLVFS *vfs, const LLUUID &local_id, LLAssetType::EType void LLXfer_VFile::cleanup () { - LLVFile file(mVFS, mTempID, mType, LLVFile::WRITE); - file.remove(); + if (mTempID.notNull() && + mDeleteTempFile) + { + if (mVFS->getExists(mTempID, mType)) + { + LLVFile file(mVFS, mTempID, mType, LLVFile::WRITE); + file.remove(); + } + else + { + LL_WARNS("Xfer") << "LLXfer_VFile::cleanup() can't open to delete VFS file " << mTempID << "." << LLAssetType::lookup(mType) + << ", mRemoteID is " << mRemoteID << LL_ENDL; + } + } delete mVFile; mVFile = NULL; @@ -118,7 +130,7 @@ S32 LLXfer_VFile::initializeRequest(U64 xfer_id, mName = llformat("VFile %s:%s", id_string.c_str(), LLAssetType::lookup(mType)); - llinfos << "Requesting " << mName << llendl; + LL_INFOS("Xfer") << "Requesting " << mName << LL_ENDL; if (mBuffer) { @@ -131,6 +143,7 @@ S32 LLXfer_VFile::initializeRequest(U64 xfer_id, mBufferLength = 0; mPacketNum = 0; mTempID.generate(); + mDeleteTempFile = TRUE; mStatus = e_LL_XFER_PENDING; return retval; } @@ -140,7 +153,8 @@ S32 LLXfer_VFile::initializeRequest(U64 xfer_id, S32 LLXfer_VFile::startDownload() { S32 retval = 0; // presume success - LLVFile file(mVFS, mTempID, mType, LLVFile::APPEND); + + // Don't need to create the file here, it will happen when data arrives gMessageSystem->newMessageFast(_PREHASH_RequestXfer); gMessageSystem->nextBlockFast(_PREHASH_XferID); @@ -184,6 +198,8 @@ S32 LLXfer_VFile::startSend (U64 xfer_id, const LLHost &remote_host) if (mVFile->getSize() <= 0) { + LL_WARNS("Xfer") << "LLXfer_VFile::startSend() VFS file " << mLocalID << "." << LLAssetType::lookup(mType) + << " has unexpected file size of " << mVFile->getSize() << LL_ENDL; delete mVFile; mVFile = NULL; @@ -198,6 +214,7 @@ S32 LLXfer_VFile::startSend (U64 xfer_id, const LLHost &remote_host) } else { + LL_WARNS("Xfer") << "LLXfer_VFile::startSend() can't read VFS file " << mLocalID << "." << LLAssetType::lookup(mType) << LL_ENDL; retval = LL_ERR_FILE_NOT_FOUND; } @@ -205,6 +222,41 @@ S32 LLXfer_VFile::startSend (U64 xfer_id, const LLHost &remote_host) } /////////////////////////////////////////////////////////// + +void LLXfer_VFile::closeFileHandle() +{ + if (mVFile) + { + delete mVFile; + mVFile = NULL; + } +} + +/////////////////////////////////////////////////////////// + +S32 LLXfer_VFile::reopenFileHandle() +{ + S32 retval = LL_ERR_NOERR; // presume success + + if (mVFile == NULL) + { + if (mVFS->getExists(mLocalID, mType)) + { + mVFile = new LLVFile(mVFS, mLocalID, mType, LLVFile::READ); + } + else + { + LL_WARNS("Xfer") << "LLXfer_VFile::reopenFileHandle() can't read VFS file " << mLocalID << "." << LLAssetType::lookup(mType) << LL_ENDL; + retval = LL_ERR_FILE_NOT_FOUND; + } + } + + return retval; +} + + +/////////////////////////////////////////////////////////// + void LLXfer_VFile::setXferSize (S32 xfer_size) { LLXfer::setXferSize(xfer_size); @@ -236,8 +288,8 @@ S32 LLXfer_VFile::suck(S32 start_position) // grab a buffer from the right place in the file if (! mVFile->seek(start_position, 0)) { - llwarns << "VFile Xfer Can't seek to position " << start_position << ", file length " << mVFile->getSize() << llendl; - llwarns << "While sending file " << mLocalID << llendl; + LL_WARNS("Xfer") << "VFile Xfer Can't seek to position " << start_position << ", file length " << mVFile->getSize() << LL_ENDL; + LL_WARNS("Xfer") << "While sending file " << mLocalID << LL_ENDL; return -1; } @@ -288,12 +340,31 @@ S32 LLXfer_VFile::processEOF() if (!mCallbackResult) { - LLVFile file(mVFS, mTempID, mType, LLVFile::WRITE); - if (! file.rename(mLocalID, mType)) + if (mVFS->getExists(mTempID, mType)) { - llinfos << "copy from temp file failed: unable to rename to " << mLocalID << llendl; + LLVFile file(mVFS, mTempID, mType, LLVFile::WRITE); + if (!file.rename(mLocalID, mType)) + { + LL_WARNS("Xfer") << "VFS rename of temp file failed: unable to rename " << mTempID << " to " << mLocalID << LL_ENDL; + } + else + { + #ifdef VFS_SPAM + // Debugging spam + LL_INFOS("Xfer") << "VFS rename of temp file done: renamed " << mTempID << " to " << mLocalID + << " LLVFile size is " << file.getSize() + << LL_ENDL; + #endif + + // Rename worked: the original file is gone. Clear mDeleteTempFile + // so we don't attempt to delete the file in cleanup() + mDeleteTempFile = FALSE; + } + } + else + { + LL_WARNS("Xfer") << "LLXfer_VFile::processEOF() can't open for renaming VFS file " << mTempID << "." << LLAssetType::lookup(mType) << LL_ENDL; } - } if (mVFile) diff --git a/indra/llmessage/llxfer_vfile.h b/indra/llmessage/llxfer_vfile.h index 048bf49dcc..5bf9a5cfba 100644 --- a/indra/llmessage/llxfer_vfile.h +++ b/indra/llmessage/llxfer_vfile.h @@ -47,6 +47,8 @@ class LLXfer_VFile : public LLXfer std::string mName; + BOOL mDeleteTempFile; + public: LLXfer_VFile (); LLXfer_VFile (LLVFS *vfs, const LLUUID &local_id, LLAssetType::EType type); @@ -66,8 +68,10 @@ class LLXfer_VFile : public LLXfer virtual S32 startDownload(); virtual S32 processEOF(); - - virtual S32 startSend (U64 xfer_id, const LLHost &remote_host); + + virtual S32 startSend(U64 xfer_id, const LLHost &remote_host); + virtual void closeFileHandle(); + virtual S32 reopenFileHandle(); virtual S32 suck(S32 start_position); virtual S32 flush(); diff --git a/indra/llmessage/llxfermanager.cpp b/indra/llmessage/llxfermanager.cpp index 9dbb774924..0918300648 100644 --- a/indra/llmessage/llxfermanager.cpp +++ b/indra/llmessage/llxfermanager.cpp @@ -35,7 +35,6 @@ #include "llerror.h" #include "lluuid.h" -#include "u64.h" const F32 LL_XFER_REGISTRATION_TIMEOUT = 60.0f; // timeout if a registered transfer hasn't been requested in 60 seconds const F32 LL_PACKET_TIMEOUT = 3.0f; // packet timeout at 3 s @@ -44,9 +43,15 @@ const S32 LL_PACKET_RETRY_LIMIT = 10; // packet retransmission limit const S32 LL_DEFAULT_MAX_SIMULTANEOUS_XFERS = 10; const S32 LL_DEFAULT_MAX_REQUEST_FIFO_XFERS = 1000; -#define LL_XFER_PROGRESS_MESSAGES 0 -#define LL_XFER_TEST_REXMIT 0 +// Kills the connection if a viewer download queue hits this many requests backed up +// Also set in simulator.xml at "hard_limit_outgoing_xfers_per_circuit" +const S32 LL_DEFAULT_MAX_HARD_LIMIT_SIMULTANEOUS_XFERS = 500; +// Use this to show sending some ConfirmXferPacket messages +//#define LL_XFER_PROGRESS_MESSAGES 1 + +// Use this for lots of diagnostic spam +//#define LL_XFER_DIAGNOISTIC_LOGGING 1 /////////////////////////////////////////////////////////// @@ -66,10 +71,10 @@ LLXferManager::~LLXferManager () void LLXferManager::init (LLVFS *vfs) { - mSendList = NULL; - mReceiveList = NULL; + cleanup(); setMaxOutgoingXfersPerCircuit(LL_DEFAULT_MAX_SIMULTANEOUS_XFERS); + setHardLimitOutgoingXfersPerCircuit(LL_DEFAULT_MAX_HARD_LIMIT_SIMULTANEOUS_XFERS); setMaxIncomingXfers(LL_DEFAULT_MAX_REQUEST_FIFO_XFERS); mVFS = vfs; @@ -83,29 +88,14 @@ void LLXferManager::init (LLVFS *vfs) void LLXferManager::cleanup () { - LLXfer *xferp; - LLXfer *delp; - for_each(mOutgoingHosts.begin(), mOutgoingHosts.end(), DeletePointer()); mOutgoingHosts.clear(); - delp = mSendList; - while (delp) - { - xferp = delp->mNext; - delete delp; - delp = xferp; - } - mSendList = NULL; + for_each(mSendList.begin(), mSendList.end(), DeletePointer()); + mSendList.clear(); - delp = mReceiveList; - while (delp) - { - xferp = delp->mNext; - delete delp; - delp = xferp; - } - mReceiveList = NULL; + for_each(mReceiveList.begin(), mReceiveList.end(), DeletePointer()); + mReceiveList.clear(); } /////////////////////////////////////////////////////////// @@ -122,6 +112,11 @@ void LLXferManager::setMaxOutgoingXfersPerCircuit(S32 max_num) mMaxOutgoingXfersPerCircuit = max_num; } +void LLXferManager::setHardLimitOutgoingXfersPerCircuit(S32 max_num) +{ + mHardLimitOutgoingXfersPerCircuit = max_num; +} + void LLXferManager::setUseAckThrottling(const BOOL use) { mUseAckThrottling = use; @@ -140,6 +135,11 @@ void LLXferManager::setAckThrottleBPS(const F32 bps) F32 actual_rate = llmax(min_bps*1.1f, bps); LL_DEBUGS("AppInit") << "LLXferManager ack throttle min rate: " << min_bps << LL_ENDL; LL_DEBUGS("AppInit") << "LLXferManager ack throttle actual rate: " << actual_rate << LL_ENDL; + #ifdef LL_XFER_DIAGNOISTIC_LOGGING + LL_INFOS("Xfer") << "LLXferManager ack throttle min rate: " << min_bps << LL_ENDL; + LL_INFOS("Xfer") << "LLXferManager ack throttle actual rate: " << actual_rate << LL_ENDL; + #endif // LL_XFER_DIAGNOISTIC_LOGGING + mAckThrottle.setRate(actual_rate); } @@ -148,45 +148,71 @@ void LLXferManager::setAckThrottleBPS(const F32 bps) void LLXferManager::updateHostStatus() { - LLXfer *xferp; - LLHostStatus *host_statusp = NULL; - + // Clear the outgoing host list for_each(mOutgoingHosts.begin(), mOutgoingHosts.end(), DeletePointer()); mOutgoingHosts.clear(); - - for (xferp = mSendList; xferp; xferp = xferp->mNext) + + // Loop through all outgoing xfers and re-build mOutgoingHosts + for (xfer_list_t::iterator send_iter = mSendList.begin(); + send_iter != mSendList.end(); ++send_iter) { + LLHostStatus *host_statusp = NULL; for (status_list_t::iterator iter = mOutgoingHosts.begin(); iter != mOutgoingHosts.end(); ++iter) { - host_statusp = *iter; - if (host_statusp->mHost == xferp->mRemoteHost) - { + if ((*iter)->mHost == (*send_iter)->mRemoteHost) + { // Already have this host + host_statusp = *iter; break; } } if (!host_statusp) - { + { // Don't have this host, so add it host_statusp = new LLHostStatus(); if (host_statusp) { - host_statusp->mHost = xferp->mRemoteHost; + host_statusp->mHost = (*send_iter)->mRemoteHost; mOutgoingHosts.push_front(host_statusp); } } if (host_statusp) - { - if (xferp->mStatus == e_LL_XFER_PENDING) + { // Do the accounting + if ((*send_iter)->mStatus == e_LL_XFER_PENDING) { host_statusp->mNumPending++; } - else if (xferp->mStatus == e_LL_XFER_IN_PROGRESS) + else if ((*send_iter)->mStatus == e_LL_XFER_IN_PROGRESS) { host_statusp->mNumActive++; } } - } + +#ifdef LL_XFER_DIAGNOISTIC_LOGGING + for (xfer_list_t::iterator send_iter = mSendList.begin(); + send_iter != mSendList.end(); ++send_iter) + { + LLXfer * xferp = *send_iter; + LL_INFOS("Xfer") << "xfer to host " << xferp->mRemoteHost + << " is " << xferp->mXferSize << " bytes" + << ", status " << (S32)(xferp->mStatus) + << ", waiting for ACK: " << (S32)(xferp->mWaitingForACK) + << " in frame " << LLFrameTimer::getFrameCount() + << LL_ENDL; + } + + for (status_list_t::iterator iter = mOutgoingHosts.begin(); + iter != mOutgoingHosts.end(); ++iter) + { + LL_INFOS("Xfer") << "LLXfer host " << (*iter)->mHost.getIPandPort() + << " has " << (*iter)->mNumActive + << " active, " << (*iter)->mNumPending + << " pending" + << " in frame " << LLFrameTimer::getFrameCount() + << LL_ENDL; + } +#endif // LL_XFER_DIAGNOISTIC_LOGGING + } /////////////////////////////////////////////////////////// @@ -196,27 +222,28 @@ void LLXferManager::printHostStatus() LLHostStatus *host_statusp = NULL; if (!mOutgoingHosts.empty()) { - llinfos << "Outgoing Xfers:" << llendl; + LL_INFOS("Xfer") << "Outgoing Xfers:" << LL_ENDL; for (status_list_t::iterator iter = mOutgoingHosts.begin(); iter != mOutgoingHosts.end(); ++iter) { host_statusp = *iter; - llinfos << " " << host_statusp->mHost << " active: " << host_statusp->mNumActive << " pending: " << host_statusp->mNumPending << llendl; + LL_INFOS("Xfer") << " " << host_statusp->mHost << " active: " << host_statusp->mNumActive << " pending: " << host_statusp->mNumPending << LL_ENDL; } } } /////////////////////////////////////////////////////////// -LLXfer *LLXferManager::findXfer (U64 id, LLXfer *list_head) +LLXfer * LLXferManager::findXferByID(U64 id, xfer_list_t & xfer_list) { - LLXfer *xferp; - for (xferp = list_head; xferp; xferp = xferp->mNext) + for (xfer_list_t::iterator iter = xfer_list.begin(); + iter != xfer_list.end(); + ++iter) { - if (xferp->mID == id) + if ((*iter)->mID == id) { - return(xferp); + return(*iter); } } return(NULL); @@ -225,29 +252,34 @@ LLXfer *LLXferManager::findXfer (U64 id, LLXfer *list_head) /////////////////////////////////////////////////////////// -void LLXferManager::removeXfer (LLXfer *delp, LLXfer **list_head) +// WARNING: this invalidates iterators from xfer_list +void LLXferManager::removeXfer(LLXfer *delp, xfer_list_t & xfer_list) { - // This function assumes that delp will only occur in the list - // zero or one times. if (delp) - { - if (*list_head == delp) + { + std::string direction = "send"; + if (&xfer_list == &mReceiveList) { - *list_head = delp->mNext; - delete (delp); + direction = "receive"; } - else + + // This assumes that delp will occur in the list once at most + // Find the pointer in the list + for (xfer_list_t::iterator iter = xfer_list.begin(); + iter != xfer_list.end(); + ++iter) { - LLXfer *xferp = *list_head; - while (xferp->mNext) + if ((*iter) == delp) { - if (xferp->mNext == delp) - { - xferp->mNext = delp->mNext; - delete (delp); - break; - } - xferp = xferp->mNext; + LL_DEBUGS("Xfer") << "Deleting xfer to host " << (*iter)->mRemoteHost + << " of " << (*iter)->mXferSize << " bytes" + << ", status " << (S32)((*iter)->mStatus) + << " from the " << direction << " list" + << LL_ENDL; + + xfer_list.erase(iter); + delete (delp); + break; } } } @@ -255,35 +287,30 @@ void LLXferManager::removeXfer (LLXfer *delp, LLXfer **list_head) /////////////////////////////////////////////////////////// -U32 LLXferManager::numActiveListEntries(LLXfer *list_head) +LLHostStatus * LLXferManager::findHostStatus(const LLHost &host) { - U32 num_entries = 0; + LLHostStatus *host_statusp = NULL; - while (list_head) + for (status_list_t::iterator iter = mOutgoingHosts.begin(); + iter != mOutgoingHosts.end(); ++iter) { - if (list_head->mStatus == e_LL_XFER_IN_PROGRESS) + host_statusp = *iter; + if (host_statusp->mHost == host) { - num_entries++; + return (host_statusp); } - list_head = list_head->mNext; } - return(num_entries); + return 0; } /////////////////////////////////////////////////////////// - + S32 LLXferManager::numPendingXfers(const LLHost &host) { - LLHostStatus *host_statusp = NULL; - - for (status_list_t::iterator iter = mOutgoingHosts.begin(); - iter != mOutgoingHosts.end(); ++iter) + LLHostStatus *host_statusp = findHostStatus(host); + if (host_statusp) { - host_statusp = *iter; - if (host_statusp->mHost == host) - { - return (host_statusp->mNumPending); - } + return host_statusp->mNumPending; } return 0; } @@ -292,16 +319,10 @@ S32 LLXferManager::numPendingXfers(const LLHost &host) S32 LLXferManager::numActiveXfers(const LLHost &host) { - LLHostStatus *host_statusp = NULL; - - for (status_list_t::iterator iter = mOutgoingHosts.begin(); - iter != mOutgoingHosts.end(); ++iter) + LLHostStatus *host_statusp = findHostStatus(host); + if (host_statusp) { - host_statusp = *iter; - if (host_statusp->mHost == host) - { - return (host_statusp->mNumActive); - } + return host_statusp->mNumActive; } return 0; } @@ -372,36 +393,7 @@ BOOL LLXferManager::isLastPacket(S32 packet_num) /////////////////////////////////////////////////////////// -U64 LLXferManager::registerXfer(const void *datap, const S32 length) -{ - LLXfer *xferp; - U64 xfer_id = getNextID(); - - xferp = (LLXfer *) new LLXfer_Mem(); - if (xferp) - { - xferp->mNext = mSendList; - mSendList = xferp; - - xfer_id = ((LLXfer_Mem *)xferp)->registerXfer(xfer_id, datap,length); - - if (!xfer_id) - { - removeXfer(xferp,&mSendList); - } - } - else - { - llerrs << "Xfer allocation error" << llendl; - xfer_id = 0; - } - - return(xfer_id); -} - -/////////////////////////////////////////////////////////// - -void LLXferManager::requestFile(const std::string& local_filename, +U64 LLXferManager::requestFile(const std::string& local_filename, const std::string& remote_filename, ELLPath remote_path, const LLHost& remote_host, @@ -411,28 +403,34 @@ void LLXferManager::requestFile(const std::string& local_filename, BOOL is_priority, BOOL use_big_packets) { - LLXfer *xferp; + LLXfer_File* file_xfer_p = NULL; - for (xferp = mReceiveList; xferp ; xferp = xferp->mNext) + // First check to see if it's already requested + for (xfer_list_t::iterator iter = mReceiveList.begin(); + iter != mReceiveList.end(); ++iter) { - if (xferp->getXferTypeTag() == LLXfer::XFER_FILE - && (((LLXfer_File*)xferp)->matchesLocalFilename(local_filename)) - && (((LLXfer_File*)xferp)->matchesRemoteFilename(remote_filename, remote_path)) - && (remote_host == xferp->mRemoteHost) - && (callback == xferp->mCallback) - && (user_data == xferp->mCallbackDataHandle)) - + if ((*iter)->getXferTypeTag() == LLXfer::XFER_FILE) { - // cout << "requested a xfer already in progress" << endl; - return; + file_xfer_p = (LLXfer_File*)(*iter); + if (file_xfer_p->matchesLocalFilename(local_filename) + && file_xfer_p->matchesRemoteFilename(remote_filename, remote_path) + && (remote_host == file_xfer_p->mRemoteHost) + && (callback == file_xfer_p->mCallback) + && (user_data == file_xfer_p->mCallbackDataHandle)) + { + // Already have the request (already in progress) + return (*iter)->mID; + } } } + U64 xfer_id = 0; + S32 chunk_size = use_big_packets ? LL_XFER_LARGE_PAYLOAD : -1; - xferp = (LLXfer *) new LLXfer_File(chunk_size); - if (xferp) + file_xfer_p = new LLXfer_File(chunk_size); + if (file_xfer_p) { - addToList(xferp, mReceiveList, is_priority); + addToList(file_xfer_p, mReceiveList, is_priority); // Remove any file by the same name that happens to be lying // around. @@ -441,10 +439,11 @@ void LLXferManager::requestFile(const std::string& local_filename, if(delete_remote_on_completion && (remote_filename.substr(remote_filename.length()-4) == ".tmp")) { - LLFile::remove(local_filename); + LLFile::remove(local_filename, ENOENT); } - ((LLXfer_File *)xferp)->initializeRequest( - getNextID(), + xfer_id = getNextID(); + file_xfer_p->initializeRequest( + xfer_id, local_filename, remote_filename, remote_path, @@ -455,36 +454,9 @@ void LLXferManager::requestFile(const std::string& local_filename, } else { - llerrs << "Xfer allocation error" << llendl; - } -} - -void LLXferManager::requestFile(const std::string& remote_filename, - ELLPath remote_path, - const LLHost& remote_host, - BOOL delete_remote_on_completion, - void (*callback)(void*,S32,void**,S32,LLExtStat), - void** user_data, - BOOL is_priority) -{ - LLXfer *xferp; - - xferp = (LLXfer *) new LLXfer_Mem(); - if (xferp) - { - addToList(xferp, mReceiveList, is_priority); - ((LLXfer_Mem *)xferp)->initializeRequest(getNextID(), - remote_filename, - remote_path, - remote_host, - delete_remote_on_completion, - callback, user_data); - startPendingDownloads(); - } - else - { - llerrs << "Xfer allocation error" << llendl; + LL_ERRS("Xfer") << "Xfer allocation error" << LL_ENDL; } + return xfer_id; } void LLXferManager::requestVFile(const LLUUID& local_id, @@ -495,28 +467,46 @@ void LLXferManager::requestVFile(const LLUUID& local_id, void** user_data, BOOL is_priority) { - LLXfer *xferp; - - for (xferp = mReceiveList; xferp ; xferp = xferp->mNext) - { - if (xferp->getXferTypeTag() == LLXfer::XFER_VFILE - && (((LLXfer_VFile*)xferp)->matchesLocalFile(local_id, type)) - && (((LLXfer_VFile*)xferp)->matchesRemoteFile(remote_id, type)) - && (remote_host == xferp->mRemoteHost) - && (callback == xferp->mCallback) - && (user_data == xferp->mCallbackDataHandle)) + LLXfer_VFile * xfer_p = NULL; + for (xfer_list_t::iterator iter = mReceiveList.begin(); + iter != mReceiveList.end(); ++iter) + { // Find any matching existing requests + if ((*iter)->getXferTypeTag() == LLXfer::XFER_VFILE) { - // cout << "requested a xfer already in progress" << endl; - return; + xfer_p = (LLXfer_VFile*) (*iter); + if (xfer_p->matchesLocalFile(local_id, type) + && xfer_p->matchesRemoteFile(remote_id, type) + && (remote_host == xfer_p->mRemoteHost) + && (callback == xfer_p->mCallback) + && (user_data == xfer_p->mCallbackDataHandle)) + + { // Have match, don't add a duplicate + #ifdef LL_XFER_DIAGNOISTIC_LOGGING + LL_INFOS("Xfer") << "Dropping duplicate xfer request for " << remote_id + << " on " << remote_host.getIPandPort() + << " local id " << local_id + << LL_ENDL; + #endif // LL_XFER_DIAGNOISTIC_LOGGING + + return; + } } } - xferp = (LLXfer *) new LLXfer_VFile(); - if (xferp) + xfer_p = new LLXfer_VFile(); + if (xfer_p) { - addToList(xferp, mReceiveList, is_priority); - ((LLXfer_VFile *)xferp)->initializeRequest(getNextID(), + #ifdef LL_XFER_DIAGNOISTIC_LOGGING + LL_INFOS("Xfer") << "Starting file xfer for " << remote_id + << " type " << LLAssetType::lookupHumanReadable(type) + << " from " << xfer_p->mRemoteHost.getIPandPort() + << ", local id " << local_id + << LL_ENDL; + #endif // LL_XFER_DIAGNOISTIC_LOGGING + + addToList(xfer_p, mReceiveList, is_priority); + ((LLXfer_VFile *)xfer_p)->initializeRequest(getNextID(), vfs, local_id, remote_id, @@ -528,78 +518,18 @@ void LLXferManager::requestVFile(const LLUUID& local_id, } else { - llerrs << "Xfer allocation error" << llendl; + LL_ERRS("Xfer") << "Xfer allocation error" << LL_ENDL; } } -/* -void LLXferManager::requestXfer( - const std::string& local_filename, - BOOL delete_remote_on_completion, - U64 xfer_id, - const LLHost &remote_host, - void (*callback)(void **,S32), - void **user_data) -{ - LLXfer *xferp; - - for (xferp = mReceiveList; xferp ; xferp = xferp->mNext) - { - if (xferp->getXferTypeTag() == LLXfer::XFER_FILE - && (((LLXfer_File*)xferp)->matchesLocalFilename(local_filename)) - && (xfer_id == xferp->mID) - && (remote_host == xferp->mRemoteHost) - && (callback == xferp->mCallback) - && (user_data == xferp->mCallbackDataHandle)) - - { - // cout << "requested a xfer already in progress" << endl; - return; - } - } - - xferp = (LLXfer *) new LLXfer_File(); - if (xferp) - { - xferp->mNext = mReceiveList; - mReceiveList = xferp; - - ((LLXfer_File *)xferp)->initializeRequest(xfer_id,local_filename,"",LL_PATH_NONE,remote_host,delete_remote_on_completion,callback,user_data); - startPendingDownloads(); - } - else - { - llerrs << "Xfer allcoation error" << llendl; - } -} - -void LLXferManager::requestXfer(U64 xfer_id, const LLHost &remote_host, BOOL delete_remote_on_completion, void (*callback)(void *,S32,void **,S32),void **user_data) -{ - LLXfer *xferp; - - xferp = (LLXfer *) new LLXfer_Mem(); - if (xferp) - { - xferp->mNext = mReceiveList; - mReceiveList = xferp; - - ((LLXfer_Mem *)xferp)->initializeRequest(xfer_id,"",LL_PATH_NONE,remote_host,delete_remote_on_completion,callback,user_data); - startPendingDownloads(); - } - else - { - llerrs << "Xfer allcoation error" << llendl; - } -} -*/ /////////////////////////////////////////////////////////// void LLXferManager::processReceiveData (LLMessageSystem *mesgsys, void ** /*user_data*/) { // there's sometimes an extra 4 bytes added to an xfer payload const S32 BUF_SIZE = LL_XFER_LARGE_PAYLOAD + 4; - char fdata_buf[LL_XFER_LARGE_PAYLOAD + 4]; /* Flawfinder : ignore */ + char fdata_buf[BUF_SIZE]; /* Flawfinder : ignore */ S32 fdata_size; U64 id; S32 packetnum; @@ -609,16 +539,24 @@ void LLXferManager::processReceiveData (LLMessageSystem *mesgsys, void ** /*user mesgsys->getS32Fast(_PREHASH_XferID, _PREHASH_Packet, packetnum); fdata_size = mesgsys->getSizeFast(_PREHASH_DataPacket,_PREHASH_Data); - mesgsys->getBinaryDataFast(_PREHASH_DataPacket, _PREHASH_Data, fdata_buf, 0, 0, BUF_SIZE); - - xferp = findXfer(id, mReceiveList); + if (fdata_size < 0 || + fdata_size > BUF_SIZE) + { + LL_WARNS("Xfer") << "Received invalid xfer data size of " << fdata_size + << " in packet number " << packetnum + << " from " << mesgsys->getSender() + << " for xfer id: " << fmt::to_string(id) + << LL_ENDL; + return; + } + mesgsys->getBinaryDataFast(_PREHASH_DataPacket, _PREHASH_Data, fdata_buf, fdata_size, 0, BUF_SIZE); - if (!xferp) + xferp = findXferByID(id, mReceiveList); + if (!xferp) { - char U64_BUF[MAX_STRING]; /* Flawfinder : ignore */ - llwarns << "received xfer data from " << mesgsys->getSender() + LL_WARNS("Xfer") << "received xfer data from " << mesgsys->getSender() << " for non-existent xfer id: " - << U64_to_str(id, U64_BUF, sizeof(U64_BUF)) << llendl; + << fmt::to_string(id) << LL_ENDL; return; } @@ -629,11 +567,11 @@ void LLXferManager::processReceiveData (LLMessageSystem *mesgsys, void ** /*user // confirm it if it was a resend of the last one, since the confirmation might have gotten dropped if (decodePacketNum(packetnum) == (xferp->mPacketNum - 1)) { - llinfos << "Reconfirming xfer " << xferp->mRemoteHost << ":" << xferp->getFileName() << " packet " << packetnum << llendl; sendConfirmPacket(mesgsys, id, decodePacketNum(packetnum), mesgsys->getSender()); + LL_INFOS("Xfer") << "Reconfirming xfer " << xferp->mRemoteHost << ":" << xferp->getFileName() << " packet " << packetnum << LL_ENDL; sendConfirmPacket(mesgsys, id, decodePacketNum(packetnum), mesgsys->getSender()); } else { - llinfos << "Ignoring xfer " << xferp->mRemoteHost << ":" << xferp->getFileName() << " recv'd packet " << packetnum << "; expecting " << xferp->mPacketNum << llendl; + LL_INFOS("Xfer") << "Ignoring xfer " << xferp->mRemoteHost << ":" << xferp->getFileName() << " recv'd packet " << packetnum << "; expecting " << xferp->mPacketNum << LL_ENDL; } return; } @@ -658,7 +596,7 @@ void LLXferManager::processReceiveData (LLMessageSystem *mesgsys, void ** /*user if (result == LL_ERR_CANNOT_OPEN_FILE) { xferp->abort(LL_ERR_CANNOT_OPEN_FILE); - removeXfer(xferp,&mReceiveList); + removeXfer(xferp,mReceiveList); startPendingDownloads(); return; } @@ -677,13 +615,13 @@ void LLXferManager::processReceiveData (LLMessageSystem *mesgsys, void ** /*user ack_info.mID = id; ack_info.mPacketNum = decodePacketNum(packetnum); ack_info.mRemoteHost = mesgsys->getSender(); - mXferAckQueue.push(ack_info); + mXferAckQueue.push_back(ack_info); } if (isLastPacket(packetnum)) { xferp->processEOF(); - removeXfer(xferp,&mReceiveList); + removeXfer(xferp,mReceiveList); startPendingDownloads(); } } @@ -692,7 +630,7 @@ void LLXferManager::processReceiveData (LLMessageSystem *mesgsys, void ** /*user void LLXferManager::sendConfirmPacket (LLMessageSystem *mesgsys, U64 id, S32 packetnum, const LLHost &remote_host) { -#if LL_XFER_PROGRESS_MESSAGES +#ifdef LL_XFER_PROGRESS_MESSAGES if (!(packetnum % 50)) { cout << "confirming xfer packet #" << packetnum << endl; @@ -703,6 +641,7 @@ void LLXferManager::sendConfirmPacket (LLMessageSystem *mesgsys, U64 id, S32 pac mesgsys->addU64Fast(_PREHASH_ID, id); mesgsys->addU32Fast(_PREHASH_Packet, packetnum); + // Ignore a circuit failure here, we'll catch it with another message mesgsys->sendMessage(remote_host); } @@ -741,6 +680,28 @@ bool LLXferManager::validateFileForTransfer(const std::string& filename) return find_and_remove(mExpectedTransfers, filename); } +/* Present in fireengine, not used by viewer +void LLXferManager::expectVFileForRequest(const std::string& filename) +{ + mExpectedVFileRequests.insert(filename); +} + +bool LLXferManager::validateVFileForRequest(const std::string& filename) +{ + return find_and_remove(mExpectedVFileRequests, filename); +} + +void LLXferManager::expectVFileForTransfer(const std::string& filename) +{ + mExpectedVFileTransfers.insert(filename); +} + +bool LLXferManager::validateVFileForTransfer(const std::string& filename) +{ + return find_and_remove(mExpectedVFileTransfers, filename); +} +*/ + static bool remove_prefix(std::string& filename, const std::string& prefix) { if (std::equal(prefix.begin(), prefix.end(), filename.begin())) @@ -801,9 +762,8 @@ void LLXferManager::processFileRequest (LLMessageSystem *mesgsys, void ** /*user mesgsys->getBOOL("XferID", "UseBigPackets", b_use_big_packets); mesgsys->getU64Fast(_PREHASH_XferID, _PREHASH_ID, id); - char U64_BUF[MAX_STRING]; /* Flawfinder : ignore */ - llinfos << "xfer request id: " << U64_to_str(id, U64_BUF, sizeof(U64_BUF)) - << " to " << mesgsys->getSender() << llendl; + LL_INFOS("Xfer") << "xfer request id: " << fmt::to_string(id) + << " to " << mesgsys->getSender() << LL_ENDL; mesgsys->getStringFast(_PREHASH_XferID, _PREHASH_Filename, local_filename); @@ -820,36 +780,45 @@ void LLXferManager::processFileRequest (LLMessageSystem *mesgsys, void ** /*user LLXfer *xferp; if (uuid != LLUUID::null) - { + { // Request for an asset - use a VFS file if(NULL == LLAssetType::lookup(type)) { - llwarns << "Invalid type for xfer request: " << uuid << ":" - << type_s16 << " to " << mesgsys->getSender() << llendl; + LL_WARNS("Xfer") << "Invalid type for xfer request: " << uuid << ":" + << type_s16 << " to " << mesgsys->getSender() << LL_ENDL; return; } - llinfos << "starting vfile transfer: " << uuid << "," << LLAssetType::lookup(type) << " to " << mesgsys->getSender() << llendl; - if (! mVFS) { - llwarns << "Attempt to send VFile w/o available VFS" << llendl; + LL_WARNS("Xfer") << "Attempt to send VFile w/o available VFS" << LL_ENDL; + return; + } + + /* Present in fireengine, not used by viewer + if (!validateVFileForTransfer(uuid.asString())) + { + // it is up to the app sending the file to mark it for expected + // transfer before the request arrives or it will be dropped + LL_WARNS("Xfer") << "SECURITY: Unapproved VFile '" << uuid << "'" << LL_ENDL; return; } + */ + + LL_INFOS("Xfer") << "starting vfile transfer: " << uuid << "," << LLAssetType::lookup(type) << " to " << mesgsys->getSender() << LL_ENDL; xferp = (LLXfer *)new LLXfer_VFile(mVFS, uuid, type); if (xferp) { - xferp->mNext = mSendList; - mSendList = xferp; + mSendList.push_front(xferp); result = xferp->startSend(id,mesgsys->getSender()); } else { - llerrs << "Xfer allcoation error" << llendl; + LL_ERRS("Xfer") << "Xfer allcoation error" << LL_ENDL; } } else if (!local_filename.empty()) - { + { // Was given a file name to send // See DEV-21775 for detailed security issues if (local_path == LL_PATH_NONE) @@ -868,7 +837,7 @@ void LLXferManager::processFileRequest (LLMessageSystem *mesgsys, void ** /*user case LL_PATH_NONE: if(!validateFileForTransfer(local_filename)) { - llwarns << "SECURITY: Unapproved filename '" << local_filename << llendl; + LL_WARNS("Xfer") << "SECURITY: Unapproved filename '" << local_filename << LL_ENDL; return; } break; @@ -876,13 +845,13 @@ void LLXferManager::processFileRequest (LLMessageSystem *mesgsys, void ** /*user case LL_PATH_CACHE: if(!verify_cache_filename(local_filename)) { - llwarns << "SECURITY: Illegal cache filename '" << local_filename << llendl; + LL_WARNS("Xfer") << "SECURITY: Illegal cache filename '" << local_filename << LL_ENDL; return; } break; default: - llwarns << "SECURITY: Restricted file dir enum: " << (U32)local_path << llendl; + LL_WARNS("Xfer") << "SECURITY: Restricted file dir enum: " << (U32)local_path << LL_ENDL; return; } @@ -897,7 +866,7 @@ void LLXferManager::processFileRequest (LLMessageSystem *mesgsys, void ** /*user { expanded_filename = local_filename; } - llinfos << "starting file transfer: " << expanded_filename << " to " << mesgsys->getSender() << llendl; + LL_INFOS("Xfer") << "starting file transfer: " << expanded_filename << " to " << mesgsys->getSender() << LL_ENDL; BOOL delete_local_on_completion = FALSE; mesgsys->getBOOL("XferID", "DeleteOnCompletion", delete_local_on_completion); @@ -907,23 +876,21 @@ void LLXferManager::processFileRequest (LLMessageSystem *mesgsys, void ** /*user if (xferp) { - xferp->mNext = mSendList; - mSendList = xferp; + mSendList.push_front(xferp); result = xferp->startSend(id,mesgsys->getSender()); } else { - llerrs << "Xfer allcoation error" << llendl; + LL_ERRS("Xfer") << "Xfer allcoation error" << LL_ENDL; } } else - { - char U64_BUF[MAX_STRING]; /* Flawfinder : ignore */ - llinfos << "starting memory transfer: " - << U64_to_str(id, U64_BUF, sizeof(U64_BUF)) << " to " - << mesgsys->getSender() << llendl; + { // no uuid or filename - use the ID sent + LL_INFOS("Xfer") << "starting memory transfer: " + << fmt::to_string(id) << " to " + << mesgsys->getSender() << LL_ENDL; - xferp = findXfer(id, mSendList); + xferp = findXferByID(id, mSendList); if (xferp) { @@ -931,7 +898,7 @@ void LLXferManager::processFileRequest (LLMessageSystem *mesgsys, void ** /*user } else { - llinfos << "Warning: " << U64_BUF << " not found." << llendl; + LL_INFOS("Xfer") << "Warning: xfer ID " << fmt::to_string(id) << " not found." << LL_ENDL; result = LL_ERR_FILE_NOT_FOUND; } } @@ -941,11 +908,11 @@ void LLXferManager::processFileRequest (LLMessageSystem *mesgsys, void ** /*user if (xferp) { xferp->abort(result); - removeXfer(xferp,&mSendList); + removeXfer(xferp, mSendList); } else // can happen with a memory transfer not found { - llinfos << "Aborting xfer to " << mesgsys->getSender() << " with error: " << result << llendl; + LL_INFOS("Xfer") << "Aborting xfer to " << mesgsys->getSender() << " with error: " << result << LL_ENDL; mesgsys->newMessageFast(_PREHASH_AbortXfer); mesgsys->nextBlockFast(_PREHASH_XferID); @@ -955,24 +922,86 @@ void LLXferManager::processFileRequest (LLMessageSystem *mesgsys, void ** /*user mesgsys->sendMessage(mesgsys->getSender()); } } - else if(xferp && (numActiveXfers(xferp->mRemoteHost) < mMaxOutgoingXfersPerCircuit)) - { - xferp->sendNextPacket(); - changeNumActiveXfers(xferp->mRemoteHost,1); -// llinfos << "***STARTING XFER IMMEDIATELY***" << llendl; - } - else + else if(xferp) { - if(xferp) + // Figure out how many transfers the host has requested + LLHostStatus *host_statusp = findHostStatus(xferp->mRemoteHost); + if (host_statusp) { - llinfos << " queueing xfer request, " << numPendingXfers(xferp->mRemoteHost) << " ahead of this one" << llendl; + if (host_statusp->mNumActive < mMaxOutgoingXfersPerCircuit) + { // Not many transfers in progress already, so start immediately + xferp->sendNextPacket(); + changeNumActiveXfers(xferp->mRemoteHost,1); + LL_DEBUGS("Xfer") << "Starting xfer ID " << fmt::to_string(id) << " immediately" << LL_ENDL; + } + else if (mHardLimitOutgoingXfersPerCircuit == 0 || + (host_statusp->mNumActive + host_statusp->mNumPending) < mHardLimitOutgoingXfersPerCircuit) + { // Must close the file handle and wait for earlier ones to complete + LL_INFOS("Xfer") << " queueing xfer request id " << fmt::to_string(id) << ", " + << host_statusp->mNumActive << " active and " + << host_statusp->mNumPending << " pending ahead of this one" + << LL_ENDL; + xferp->closeFileHandle(); // Close the file handle until we're ready to send again + } + else if (mHardLimitOutgoingXfersPerCircuit > 0) + { // Way too many requested ... it's time to stop being nice and kill the circuit + xferp->closeFileHandle(); // Close the file handle in any case + LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(xferp->mRemoteHost); + if (cdp) + { + if (cdp->getTrusted()) + { // Trusted internal circuit - don't kill it + LL_WARNS("Xfer") << "Trusted circuit to " << xferp->mRemoteHost << " has too many xfer requests in the queue " + << host_statusp->mNumActive << " active and " + << host_statusp->mNumPending << " pending ahead of this one" + << LL_ENDL; + } + else + { // Untrusted circuit - time to stop messing around and kill it + LL_WARNS("Xfer") << "Killing circuit to " << xferp->mRemoteHost << " for having too many xfer requests in the queue " + << host_statusp->mNumActive << " active and " + << host_statusp->mNumPending << " pending ahead of this one" + << LL_ENDL; + gMessageSystem->disableCircuit(xferp->mRemoteHost); + } + } + else + { // WTF? Why can't we find a circuit? Try to kill it off + LL_WARNS("Xfer") << "Backlog with circuit to " << xferp->mRemoteHost << " with too many xfer requests in the queue " + << host_statusp->mNumActive << " active and " + << host_statusp->mNumPending << " pending ahead of this one" + << " but no LLCircuitData found???" + << LL_ENDL; + gMessageSystem->disableCircuit(xferp->mRemoteHost); + } + } } else { - llwarns << "LLXferManager::processFileRequest() - no xfer found!" - << llendl; + LL_WARNS("Xfer") << "LLXferManager::processFileRequest() - no LLHostStatus found for id " << fmt::to_string(id) + << " host " << xferp->mRemoteHost << LL_ENDL; } } + else + { + LL_WARNS("Xfer") << "LLXferManager::processFileRequest() - no xfer found for id " << fmt::to_string(id) << LL_ENDL; + } +} + +/////////////////////////////////////////////////////////// + +// Return true if host is in a transfer-flood sitation. Same check for both internal and external hosts +bool LLXferManager::isHostFlooded(const LLHost & host) +{ + bool flooded = false; + LLHostStatus *host_statusp = findHostStatus(host); + if (host_statusp) + { + flooded = (mHardLimitOutgoingXfersPerCircuit > 0 && + (host_statusp->mNumActive + host_statusp->mNumPending) >= (S32)(mHardLimitOutgoingXfersPerCircuit * 0.8f)); + } + + return flooded; } @@ -986,7 +1015,7 @@ void LLXferManager::processConfirmation (LLMessageSystem *mesgsys, void ** /*use mesgsys->getU64Fast(_PREHASH_XferID, _PREHASH_ID, id); mesgsys->getS32Fast(_PREHASH_XferID, _PREHASH_Packet, packetNum); - LLXfer* xferp = findXfer(id, mSendList); + LLXfer* xferp = findXferByID(id, mSendList); if (xferp) { // cout << "confirmed packet #" << packetNum << " ping: "<< xferp->ACKTimer.getElapsedTimeF32() << endl; @@ -997,112 +1026,149 @@ void LLXferManager::processConfirmation (LLMessageSystem *mesgsys, void ** /*use } else { - removeXfer(xferp, &mSendList); + removeXfer(xferp, mSendList); } } } /////////////////////////////////////////////////////////// -void LLXferManager::retransmitUnackedPackets () +// Called from LLMessageSystem::processAcks() +void LLXferManager::retransmitUnackedPackets() { LLXfer *xferp; - LLXfer *delp; - xferp = mReceiveList; - while(xferp) + + xfer_list_t::iterator iter = mReceiveList.begin(); + while (iter != mReceiveList.end()) { + xferp = (*iter); if (xferp->mStatus == e_LL_XFER_IN_PROGRESS) { // if the circuit dies, abort if (! gMessageSystem->mCircuitInfo.isCircuitAlive( xferp->mRemoteHost )) { - llinfos << "Xfer found in progress on dead circuit, aborting" << llendl; + LL_WARNS("Xfer") << "Xfer found in progress on dead circuit, aborting transfer to " + << xferp->mRemoteHost.getIPandPort() + << LL_ENDL; xferp->mCallbackResult = LL_ERR_CIRCUIT_GONE; xferp->processEOF(); - delp = xferp; - xferp = xferp->mNext; - removeXfer(delp,&mReceiveList); + + iter = mReceiveList.erase(iter); // iter is set to next one after the deletion point + delete (xferp); continue; } } - xferp = xferp->mNext; + ++iter; } - xferp = mSendList; + // Re-build mOutgoingHosts data updateHostStatus(); + F32 et; - while (xferp) + iter = mSendList.begin(); + while (iter != mSendList.end()) { + xferp = (*iter); if (xferp->mWaitingForACK && ( (et = xferp->ACKTimer.getElapsedTimeF32()) > LL_PACKET_TIMEOUT)) { if (xferp->mRetries > LL_PACKET_RETRY_LIMIT) { - llinfos << "dropping xfer " << xferp->mRemoteHost << ":" << xferp->getFileName() << " packet retransmit limit exceeded, xfer dropped" << llendl; + LL_INFOS("Xfer") << "dropping xfer " << xferp->mRemoteHost << ":" << xferp->getFileName() << " packet retransmit limit exceeded, xfer dropped" << LL_ENDL; xferp->abort(LL_ERR_TCP_TIMEOUT); - delp = xferp; - xferp = xferp->mNext; - removeXfer(delp,&mSendList); + iter = mSendList.erase(iter); + delete xferp; + continue; } else { - llinfos << "resending xfer " << xferp->mRemoteHost << ":" << xferp->getFileName() << " packet unconfirmed after: "<< et << " sec, packet " << xferp->mPacketNum << llendl; + LL_INFOS("Xfer") << "resending xfer " << xferp->mRemoteHost << ":" << xferp->getFileName() << " packet unconfirmed after: "<< et << " sec, packet " << xferp->mPacketNum << LL_ENDL; xferp->resendLastPacket(); - xferp = xferp->mNext; } } else if ((xferp->mStatus == e_LL_XFER_REGISTERED) && ( (et = xferp->ACKTimer.getElapsedTimeF32()) > LL_XFER_REGISTRATION_TIMEOUT)) { - llinfos << "registered xfer never requested, xfer dropped" << llendl; + LL_INFOS("Xfer") << "registered xfer never requested, xfer dropped" << LL_ENDL; xferp->abort(LL_ERR_TCP_TIMEOUT); - delp = xferp; - xferp = xferp->mNext; - removeXfer(delp,&mSendList); + iter = mSendList.erase(iter); + delete xferp; + continue; } else if (xferp->mStatus == e_LL_XFER_ABORTED) { - llwarns << "Removing aborted xfer " << xferp->mRemoteHost << ":" << xferp->getFileName() << llendl; - delp = xferp; - xferp = xferp->mNext; - removeXfer(delp,&mSendList); + LL_WARNS("Xfer") << "Removing aborted xfer " << xferp->mRemoteHost << ":" << xferp->getFileName() << LL_ENDL; + iter = mSendList.erase(iter); + delete xferp; + continue; } else if (xferp->mStatus == e_LL_XFER_PENDING) { -// llinfos << "*** numActiveXfers = " << numActiveXfers(xferp->mRemoteHost) << " mMaxOutgoingXfersPerCircuit = " << mMaxOutgoingXfersPerCircuit << llendl; +// LL_INFOS("Xfer") << "*** numActiveXfers = " << numActiveXfers(xferp->mRemoteHost) << " mMaxOutgoingXfersPerCircuit = " << mMaxOutgoingXfersPerCircuit << LL_ENDL; if (numActiveXfers(xferp->mRemoteHost) < mMaxOutgoingXfersPerCircuit) { -// llinfos << "bumping pending xfer to active" << llendl; - xferp->sendNextPacket(); - changeNumActiveXfers(xferp->mRemoteHost,1); - } - xferp = xferp->mNext; - } - else - { - xferp = xferp->mNext; + if (xferp->reopenFileHandle()) + { + LL_WARNS("Xfer") << "Error re-opening file handle for xfer ID " << fmt::to_string(xferp->mID) + << " to host " << xferp->mRemoteHost << LL_ENDL; + xferp->abort(LL_ERR_CANNOT_OPEN_FILE); + iter = mSendList.erase(iter); + delete xferp; + continue; + } + else + { // No error re-opening the file, send the first packet + LL_DEBUGS("Xfer") << "Moving pending xfer ID " << fmt::to_string(xferp->mID) << " to active" << LL_ENDL; + xferp->sendNextPacket(); + changeNumActiveXfers(xferp->mRemoteHost,1); + } + } } - } + ++iter; + } // end while() loop // // HACK - if we're using xfer confirm throttling, throttle our xfer confirms here // so we don't blow through bandwidth. // - while (mXferAckQueue.getLength()) + while (!mXferAckQueue.empty()) { if (mAckThrottle.checkOverflow(1000.0f*8.0f)) { break; } - //llinfos << "Confirm packet queue length:" << mXferAckQueue.getLength() << llendl; - LLXferAckInfo ack_info; - mXferAckQueue.pop(ack_info); - //llinfos << "Sending confirm packet" << llendl; + //LL_INFOS("Xfer") << "Confirm packet queue length:" << mXferAckQueue.size() << LL_ENDL; + LLXferAckInfo ack_info = mXferAckQueue.front(); + mXferAckQueue.pop_front(); + //LL_INFOS("Xfer") << "Sending confirm packet" << LL_ENDL; sendConfirmPacket(gMessageSystem, ack_info.mID, ack_info.mPacketNum, ack_info.mRemoteHost); mAckThrottle.throttleOverflow(1000.f*8.f); // Assume 1000 bytes/packet } } +/////////////////////////////////////////////////////////// + +void LLXferManager::abortRequestById(U64 xfer_id, S32 result_code) +{ + LLXfer * xferp = findXferByID(xfer_id, mReceiveList); + if (xferp) + { + if (xferp->mStatus == e_LL_XFER_IN_PROGRESS) + { + // causes processAbort(); + xferp->abort(result_code); + } + else + { + xferp->mCallbackResult = result_code; + xferp->processEOF(); //should notify requester + removeXfer(xferp, mReceiveList); + } + // Since already removed or marked as aborted no need + // to wait for processAbort() to start new download + startPendingDownloads(); + } +} /////////////////////////////////////////////////////////// @@ -1115,12 +1181,12 @@ void LLXferManager::processAbort (LLMessageSystem *mesgsys, void ** /*user_data* mesgsys->getU64Fast(_PREHASH_XferID, _PREHASH_ID, id); mesgsys->getS32Fast(_PREHASH_XferID, _PREHASH_Result, result_code); - xferp = findXfer(id, mReceiveList); + xferp = findXferByID(id, mReceiveList); if (xferp) { xferp->mCallbackResult = result_code; xferp->processEOF(); - removeXfer(xferp, &mReceiveList); + removeXfer(xferp, mReceiveList); startPendingDownloads(); } } @@ -1136,29 +1202,31 @@ void LLXferManager::startPendingDownloads() // requests get pushed toward the back. Thus, if we didn't do a // stateful iteration, it would be possible for old requests to // never start. - LLXfer* xferp = mReceiveList; + LLXfer* xferp; std::list pending_downloads; S32 download_count = 0; S32 pending_count = 0; - while(xferp) + for (xfer_list_t::iterator iter = mReceiveList.begin(); + iter != mReceiveList.end(); + ++iter) { + xferp = (*iter); if(xferp->mStatus == e_LL_XFER_PENDING) - { + { // Count and accumulate pending downloads ++pending_count; pending_downloads.push_front(xferp); } else if(xferp->mStatus == e_LL_XFER_IN_PROGRESS) - { + { // Count downloads in progress ++download_count; } - xferp = xferp->mNext; } S32 start_count = mMaxIncomingXfers - download_count; - lldebugs << "LLXferManager::startPendingDownloads() - XFER_IN_PROGRESS: " + LL_DEBUGS("Xfer") << "LLXferManager::startPendingDownloads() - XFER_IN_PROGRESS: " << download_count << " XFER_PENDING: " << pending_count - << " startring " << llmin(start_count, pending_count) << llendl; + << " startring " << llmin(start_count, pending_count) << LL_ENDL; if((start_count > 0) && (pending_count > 0)) { @@ -1181,29 +1249,15 @@ void LLXferManager::startPendingDownloads() /////////////////////////////////////////////////////////// -void LLXferManager::addToList(LLXfer* xferp, LLXfer*& head, BOOL is_priority) +void LLXferManager::addToList(LLXfer* xferp, xfer_list_t & xfer_list, BOOL is_priority) { if(is_priority) { - xferp->mNext = NULL; - LLXfer* next = head; - if(next) - { - while(next->mNext) - { - next = next->mNext; - } - next->mNext = xferp; - } - else - { - head = xferp; - } + xfer_list.push_back(xferp); } else { - xferp->mNext = head; - head = xferp; + xfer_list.push_front(xferp); } } diff --git a/indra/llmessage/llxfermanager.h b/indra/llmessage/llxfermanager.h index b84bccb5b7..45ae2ffdd3 100644 --- a/indra/llmessage/llxfermanager.h +++ b/indra/llmessage/llxfermanager.h @@ -41,7 +41,7 @@ class LLVFS; #include "message.h" #include "llassetstorage.h" #include "lldir.h" -#include "lllinkedqueue.h" +#include #include "llthrottle.h" class LLHostStatus @@ -77,10 +77,11 @@ class LLXferManager protected: S32 mMaxOutgoingXfersPerCircuit; + S32 mHardLimitOutgoingXfersPerCircuit; // At this limit, kill off the connection S32 mMaxIncomingXfers; BOOL mUseAckThrottling; // Use ack throttling to cap file xfer bandwidth - LLLinkedQueue mXferAckQueue; + std::deque mXferAckQueue; LLThrottle mAckThrottle; public: @@ -92,19 +93,22 @@ class LLXferManager HIGH_PRIORITY = TRUE, }; - LLXfer *mSendList; - LLXfer *mReceiveList; + // Linked FIFO list, add to the front and pull from back + typedef std::deque xfer_list_t; + xfer_list_t mSendList; + xfer_list_t mReceiveList; typedef std::list status_list_t; status_list_t mOutgoingHosts; - private: protected: // implementation methods virtual void startPendingDownloads(); - virtual void addToList(LLXfer* xferp, LLXfer*& head, BOOL is_priority); + virtual void addToList(LLXfer* xferp, xfer_list_t & xfer_list, BOOL is_priority); std::multiset mExpectedTransfers; // files that are authorized to transfer out std::multiset mExpectedRequests; // files that are authorized to be downloaded on top of + std::multiset mExpectedVFileTransfers; // files that are authorized to transfer out + std::multiset mExpectedVFileRequests; // files that are authorized to be downloaded on top of public: LLXferManager(LLVFS *vfs); @@ -117,14 +121,17 @@ class LLXferManager void setAckThrottleBPS(const F32 bps); // list management routines - virtual LLXfer *findXfer(U64 id, LLXfer *list_head); - virtual void removeXfer (LLXfer *delp, LLXfer **list_head); - virtual U32 numActiveListEntries(LLXfer *list_head); + virtual LLXfer *findXferByID(U64 id, xfer_list_t & xfer_list); + virtual void removeXfer (LLXfer *delp, xfer_list_t & xfer_list); + + LLHostStatus * findHostStatus(const LLHost &host); virtual S32 numActiveXfers(const LLHost &host); virtual S32 numPendingXfers(const LLHost &host); + virtual void changeNumActiveXfers(const LLHost &host, S32 delta); virtual void setMaxOutgoingXfersPerCircuit (S32 max_num); + virtual void setHardLimitOutgoingXfersPerCircuit(S32 max_num); virtual void setMaxIncomingXfers(S32 max_num); virtual void updateHostStatus(); virtual void printHostStatus(); @@ -136,11 +143,9 @@ class LLXferManager virtual S32 decodePacketNum(S32 packet_num); virtual BOOL isLastPacket(S32 packet_num); - virtual U64 registerXfer(const void *datap, const S32 length); - // file requesting routines // .. to file - virtual void requestFile(const std::string& local_filename, + virtual U64 requestFile(const std::string& local_filename, const std::string& remote_filename, ELLPath remote_path, const LLHost& remote_host, @@ -148,7 +153,7 @@ class LLXferManager void (*callback)(void**,S32,LLExtStat), void** user_data, BOOL is_priority = FALSE, BOOL use_big_packets = FALSE); - + /* // .. to memory virtual void requestFile(const std::string& remote_filename, ELLPath remote_path, @@ -157,7 +162,7 @@ class LLXferManager void (*callback)(void*, S32, void**, S32, LLExtStat), void** user_data, BOOL is_priority = FALSE); - + */ // vfile requesting // .. to vfile virtual void requestVFile(const LLUUID &local_id, const LLUUID& remote_id, @@ -180,18 +185,15 @@ class LLXferManager virtual void expectFileForRequest(const std::string& filename); virtual bool validateFileForRequest(const std::string& filename); -/* -// xfer request (may be memory or file) -// .. to file - virtual void requestXfer(const char *local_filename, U64 xfer_id, - BOOL delete_remote_on_completion, - const LLHost &remote_host, void (*callback)(void **,S32),void **user_data); -// .. to memory - virtual void requestXfer(U64 xfer_id, - const LLHost &remote_host, - BOOL delete_remote_on_completion, - void (*callback)(void *, S32, void **, S32),void **user_data); -*/ + /** + Same idea but for VFiles, kept separate to avoid namespace overlap + */ + /* Present in fireengine, not used by viewer + virtual void expectVFileForTransfer(const std::string& filename); + virtual bool validateVFileForTransfer(const std::string& filename); + virtual void expectVFileForRequest(const std::string& filename); + virtual bool validateVFileForRequest(const std::string& filename); + */ virtual void processReceiveData (LLMessageSystem *mesgsys, void **user_data); virtual void sendConfirmPacket (LLMessageSystem *mesgsys, U64 id, S32 packetnum, const LLHost &remote_host); @@ -202,7 +204,10 @@ class LLXferManager virtual void retransmitUnackedPackets (); // error handling + void abortRequestById(U64 xfer_id, S32 result_code); virtual void processAbort (LLMessageSystem *mesgsys, void **user_data); + + virtual bool isHostFlooded(const LLHost & host); }; extern LLXferManager* gXferManager; diff --git a/indra/llmessage/machine.cpp b/indra/llmessage/machine.cpp index 8d2f512037..1e9c9c3c9a 100644 --- a/indra/llmessage/machine.cpp +++ b/indra/llmessage/machine.cpp @@ -33,7 +33,7 @@ void LLMachine::setMachinePort(S32 port) { if (port < 0) { - llinfos << "Can't assign a negative number to LLMachine::mPort" << llendl; + LL_INFOS() << "Can't assign a negative number to LLMachine::mPort" << LL_ENDL; mHost.setPort(0); } else @@ -46,7 +46,7 @@ void LLMachine::setControlPort( S32 port ) { if (port < 0) { - llinfos << "Can't assign a negative number to LLMachine::mControlPort" << llendl; + LL_INFOS() << "Can't assign a negative number to LLMachine::mControlPort" << LL_ENDL; mControlPort = 0; } else diff --git a/indra/llmessage/message.cpp b/indra/llmessage/message.cpp index 814d407d00..e042151ad5 100644 --- a/indra/llmessage/message.cpp +++ b/indra/llmessage/message.cpp @@ -47,7 +47,6 @@ // linden library headers #include "indra_constants.h" -#include "lldarray.h" #include "lldir.h" #include "llerror.h" #include "llfasttimer.h" @@ -74,7 +73,6 @@ #include "llxfermanager.h" #include "timing.h" #include "llquaternion.h" -#include "u64.h" #include "v3dmath.h" #include "v3math.h" #include "v4math.h" @@ -86,7 +84,7 @@ extern AIHTTPTimeoutPolicy fnPtrResponder_timeout; // Constants //const char* MESSAGE_LOG_FILENAME = "message.log"; -static const F32 CIRCUIT_DUMP_TIMEOUT = 30.f; +static const F32Seconds CIRCUIT_DUMP_TIMEOUT(30.f); static const S32 TRUST_TIME_WINDOW = 3; // *NOTE: This needs to be moved into a seperate file so that it never gets @@ -116,20 +114,20 @@ namespace { } - /*virtual*/ void error(U32 status, const std::string& reason) + /*virtual*/ void httpFailure(void) { // don't spam when agent communication disconnected already - if (status != 410) + if (mStatus != 410) { - LL_WARNS("Messaging") << "error status " << status + LL_WARNS("Messaging") << "error status " << mStatus << " for message " << mMessageName - << " reason " << reason << llendl; + << " reason " << mReason << LL_ENDL; } - // TODO: Map status in to useful error code. + // TODO: Map mStatus in to useful error code. if(NULL != mCallback) mCallback(mCallbackData, LL_ERR_TCP_TIMEOUT); } - /*virtual*/ void result(const LLSD& content) + /*virtual*/ void httpSuccess(void) { if(NULL != mCallback) mCallback(mCallbackData, LL_ERR_NOERR); } @@ -161,7 +159,7 @@ void LLMessageHandlerBridge::post(LLHTTPNode::ResponsePtr response, std::string name = context["request"]["wildcard"]["message-name"]; char* namePtr = LLMessageStringTable::getInstance()->getString(name.c_str()); - lldebugs << "Setting mLastSender " << input["sender"].asString() << llendl; + LL_DEBUGS() << "Setting mLastSender " << input["sender"].asString() << LL_ENDL; gMessageSystem->mLastSender = LLHost(input["sender"].asString()); gMessageSystem->mPacketsIn += 1; gMessageSystem->mLLSDMessageReader->setMessage(namePtr, input["body"]); @@ -247,7 +245,7 @@ LLMessageSystem::LLMessageSystem(const std::string& filename, U32 port, S32 version_patch, bool failure_is_fatal, const F32 circuit_heartbeat_interval, const F32 circuit_timeout) : - mCircuitInfo(circuit_heartbeat_interval, circuit_timeout), + mCircuitInfo(F32Seconds(circuit_heartbeat_interval), F32Seconds(circuit_timeout)), mLastMessageFromTrustedMessageService(false), mPacketRing(new LLPacketRing) { @@ -269,7 +267,7 @@ LLMessageSystem::LLMessageSystem(const std::string& filename, U32 port, mSendPacketFailureCount = 0; - mCircuitPrintFreq = 60.f; // seconds + mCircuitPrintFreq = F32Seconds(60.f); loadTemplateFile(filename, failure_is_fatal); @@ -291,7 +289,7 @@ LLMessageSystem::LLMessageSystem(const std::string& filename, U32 port, mbError = TRUE; mErrorCode = error; } -// LL_DEBUGS("Messaging") << << "*** port: " << mPort << llendl; +// LL_DEBUGS("Messaging") << << "*** port: " << mPort << LL_ENDL; // // Create the data structure that we can poll on @@ -308,20 +306,20 @@ LLMessageSystem::LLMessageSystem(const std::string& filename, U32 port, mPollInfop->mPollFD.desc.s = aprSocketp; mPollInfop->mPollFD.client_data = NULL; - F64 mt_sec = getMessageTimeSeconds(); + F64Seconds mt_sec = getMessageTimeSeconds(); mResendDumpTime = mt_sec; mMessageCountTime = mt_sec; mCircuitPrintTime = mt_sec; - mCurrentMessageTimeSeconds = mt_sec; + mCurrentMessageTime = F64Seconds(mt_sec); // Constants for dumping output based on message processing time/count mNumMessageCounts = 0; mMaxMessageCounts = 200; // >= 0 means dump warnings - mMaxMessageTime = 1.f; + mMaxMessageTime = F32Seconds(1.f); mTrueReceiveSize = 0; - mReceiveTime = 0.f; + mReceiveTime = F32Seconds(0.f); } @@ -331,7 +329,7 @@ void LLMessageSystem::loadTemplateFile(const std::string& filename, bool failure { if(filename.empty()) { - LL_ERRS("Messaging") << "No template filename specified" << llendl; + LL_ERRS("Messaging") << "No template filename specified" << LL_ENDL; mbError = TRUE; return; } @@ -340,9 +338,9 @@ void LLMessageSystem::loadTemplateFile(const std::string& filename, bool failure if(!_read_file_into_string(template_body, filename)) { if (failure_is_fatal) { - LL_ERRS("Messaging") << "Failed to open template: " << filename << llendl; + LL_ERRS("Messaging") << "Failed to open template: " << filename << LL_ENDL; } else { - LL_WARNS("Messaging") << "Failed to open template: " << filename << llendl; + LL_WARNS("Messaging") << "Failed to open template: " << filename << LL_ENDL; } mbError = TRUE; return; @@ -539,7 +537,7 @@ BOOL LLMessageSystem::checkMessages( S64 frame_count ) { // This is the first message being handled after a resetReceiveCounts, // we must be starting the message processing loop. Reset the timers. - mCurrentMessageTimeSeconds = totalTime() * SEC_PER_USEC; + mCurrentMessageTime = totalTime(); mMessageCountTime = getMessageTimeSeconds(); } @@ -571,7 +569,7 @@ BOOL LLMessageSystem::checkMessages( S64 frame_count ) // Ones that are non-zero but below the minimum packet size are worrisome. if (receive_size > 0) { - LL_WARNS("Messaging") << "Invalid (too short) packet discarded " << receive_size << llendl; + LL_WARNS("Messaging") << "Invalid (too short) packet discarded " << receive_size << LL_ENDL; callExceptionFunc(MX_PACKET_TOO_SHORT); } // no data in packet receive buffer @@ -597,7 +595,7 @@ BOOL LLMessageSystem::checkMessages( S64 frame_count ) // the next one LL_WARNS("Messaging") << "Malformed packet received. Packet size " << receive_size << " with invalid no. of acks " << acks - << llendl; + << LL_ENDL; valid_packet = FALSE; continue; } @@ -625,7 +623,7 @@ BOOL LLMessageSystem::checkMessages( S64 frame_count ) memcpy(&mem_id, &mTrueReceiveBuffer[true_rcv_size], /* Flawfinder: ignore*/ sizeof(TPACKETID)); packet_id = ntohl(mem_id); - //LL_INFOS("Messaging") << "got ack: " << packet_id << llendl; + //LL_INFOS("Messaging") << "got ack: " << packet_id << LL_ENDL; cdp->ackReliablePacket(packet_id); } if (!cdp->getUnackedPacketCount()) @@ -657,14 +655,14 @@ BOOL LLMessageSystem::checkMessages( S64 frame_count ) // LL_WARNS("Messaging") << "DISCARDED PACKET HOST MISMATCH! HOST: " // << host << " CIRCUIT: " // << mCircuitInfo.mCurrentCircuit->mHost - // << llendl; + // << LL_ENDL; //} // *************************************** //mCircuitInfo.mCurrentCircuit->mAcks.put(mCurrentRecvPacketID); cdp->collectRAck(mCurrentRecvPacketID); } - LL_DEBUGS("Messaging") << "Discarding duplicate resend from " << host << llendl; + LL_DEBUGS("Messaging") << "Discarding duplicate resend from " << host << LL_ENDL; if(mVerboseLog) { std::ostringstream str; @@ -676,7 +674,7 @@ BOOL LLMessageSystem::checkMessages( S64 frame_count ) << " resent " << ((acks > 0) ? "acks" : "") << " DISCARD DUPLICATE"; - LL_INFOS("Messaging") << str.str() << llendl; + LL_INFOS("Messaging") << str.str() << LL_ENDL; } mPacketsIn++; valid_packet = FALSE; @@ -755,7 +753,7 @@ BOOL LLMessageSystem::checkMessages( S64 frame_count ) { if (mbProtected && (!cdp)) { - LL_WARNS("Messaging") << "Invalid Packet from invalid circuit " << host << llendl; + LL_WARNS("Messaging") << "Invalid Packet from invalid circuit " << host << LL_ENDL; mOffCircuitPackets++; } else @@ -766,7 +764,7 @@ BOOL LLMessageSystem::checkMessages( S64 frame_count ) } } while (!valid_packet && receive_size > 0); - F64 mt_sec = getMessageTimeSeconds(); + F64Seconds mt_sec = getMessageTimeSeconds(); // Check to see if we need to print debug info if ((mt_sec - mCircuitPrintTime) > mCircuitPrintFreq) { @@ -795,9 +793,9 @@ S32 LLMessageSystem::getReceiveBytes() const } -void LLMessageSystem::processAcks() +void LLMessageSystem::processAcks(F32 collect_time) { - F64 mt_sec = getMessageTimeSeconds(); + F64Seconds mt_sec = getMessageTimeSeconds(); { gTransferManager.updateTransfers(); @@ -821,11 +819,11 @@ void LLMessageSystem::processAcks() mCircuitInfo.resendUnackedPackets(mUnackedListDepth, mUnackedListSize); //cycle through ack list for each host we need to send acks to - mCircuitInfo.sendAcks(); + mCircuitInfo.sendAcks(collect_time); if (!mDenyTrustedCircuitSet.empty()) { - LL_INFOS("Messaging") << "Sending queued DenyTrustedCircuit messages." << llendl; + LL_INFOS("Messaging") << "Sending queued DenyTrustedCircuit messages." << LL_ENDL; for (host_set_t::iterator hostit = mDenyTrustedCircuitSet.begin(); hostit != mDenyTrustedCircuitSet.end(); ++hostit) { reallySendDenyTrustedCircuit(*hostit); @@ -841,10 +839,10 @@ void LLMessageSystem::processAcks() } } - if (mMaxMessageTime >= 0.f) + if (mMaxMessageTime >= F32Seconds(0.f)) { // This is one of the only places where we're required to get REAL message system time. - mReceiveTime = (F32)(getMessageTimeSeconds(TRUE) - mMessageCountTime); + mReceiveTime = getMessageTimeSeconds(TRUE) - mMessageCountTime; if (mReceiveTime > mMaxMessageTime) { dump = TRUE; @@ -899,7 +897,7 @@ LLSD LLMessageSystem::getBuiltMessageLLSD() const else { // TODO: implement as below? - llerrs << "Message not built as LLSD." << llendl; + LL_ERRS() << "Message not built as LLSD." << LL_ENDL; } return result; } @@ -1002,14 +1000,6 @@ BOOL LLMessageSystem::isSendFullFast(const char* blockname) return mMessageBuilder->isMessageFull(blockname); } - -// blow away the last block of a message, return FALSE if that leaves no blocks or there wasn't a block to remove -// TODO: Babbage: Remove this horror. -BOOL LLMessageSystem::removeLastBlock() -{ - return mMessageBuilder->removeLastBlock(); -} - S32 LLMessageSystem::sendReliable(const LLHost &host) { return sendReliable(host, LL_DEFAULT_RELIABLE_RETRIES, TRUE, LL_PING_BASED_TIMEOUT_DUMMY, NULL, NULL); @@ -1018,13 +1008,13 @@ S32 LLMessageSystem::sendReliable(const LLHost &host) S32 LLMessageSystem::sendSemiReliable(const LLHost &host, void (*callback)(void **,S32), void ** callback_data) { - F32 timeout; + F32Seconds timeout; LLCircuitData *cdp = mCircuitInfo.findCircuit(host); if (cdp) { timeout = llmax(LL_MINIMUM_SEMIRELIABLE_TIMEOUT_SECONDS, - LL_SEMIRELIABLE_TIMEOUT_FACTOR * cdp->getPingDelayAveraged()); + F32Seconds(LL_SEMIRELIABLE_TIMEOUT_FACTOR * cdp->getPingDelayAveraged())); } else { @@ -1040,7 +1030,7 @@ S32 LLMessageSystem::sendSemiReliable(const LLHost &host, void (*callback)(void S32 LLMessageSystem::sendReliable( const LLHost &host, S32 retries, BOOL ping_based_timeout, - F32 timeout, + F32Seconds timeout, void (*callback)(void **,S32), void ** callback_data) { @@ -1049,11 +1039,11 @@ S32 LLMessageSystem::sendReliable( const LLHost &host, LLCircuitData *cdp = mCircuitInfo.findCircuit(host); if (cdp) { - timeout = llmax(LL_MINIMUM_RELIABLE_TIMEOUT_SECONDS, LL_RELIABLE_TIMEOUT_FACTOR * cdp->getPingDelayAveraged()); + timeout = llmax(LL_MINIMUM_RELIABLE_TIMEOUT_SECONDS, F32Seconds(LL_RELIABLE_TIMEOUT_FACTOR * cdp->getPingDelayAveraged())); } else { - timeout = llmax(LL_MINIMUM_RELIABLE_TIMEOUT_SECONDS, LL_RELIABLE_TIMEOUT_FACTOR * LL_AVERAGED_PING_MAX); + timeout = llmax(LL_MINIMUM_RELIABLE_TIMEOUT_SECONDS, F32Seconds(LL_RELIABLE_TIMEOUT_FACTOR * LL_AVERAGED_PING_MAX)); } } @@ -1085,7 +1075,7 @@ void LLMessageSystem::forwardReliable(const U32 circuit_code) S32 LLMessageSystem::forwardReliable( const LLHost &host, S32 retries, BOOL ping_based_timeout, - F32 timeout, + F32Seconds timeout, void (*callback)(void **,S32), void ** callback_data) { @@ -1095,13 +1085,13 @@ S32 LLMessageSystem::forwardReliable( const LLHost &host, S32 LLMessageSystem::flushSemiReliable(const LLHost &host, void (*callback)(void **,S32), void ** callback_data) { - F32 timeout; + F32Seconds timeout; LLCircuitData *cdp = mCircuitInfo.findCircuit(host); if (cdp) { timeout = llmax(LL_MINIMUM_SEMIRELIABLE_TIMEOUT_SECONDS, - LL_SEMIRELIABLE_TIMEOUT_FACTOR * cdp->getPingDelayAveraged()); + F32Seconds(LL_SEMIRELIABLE_TIMEOUT_FACTOR * cdp->getPingDelayAveraged())); } else { @@ -1152,7 +1142,7 @@ LLFnPtrResponder* LLMessageSystem::createResponder(const std::string& name) // explicitly sent as reliable, so they don't have a callback // LL_WARNS("Messaging") << "LLMessageSystem::sendMessage: Sending unreliable " // << mMessageBuilder->getMessageName() << " message via HTTP" -// << llendl; +// << LL_ENDL; return new LLFnPtrResponder( NULL, NULL, @@ -1188,11 +1178,11 @@ S32 LLMessageSystem::sendMessage(const LLHost &host) if(mVerboseLog) { LL_INFOS_ONCE("Messaging") << "MSG: -> " << host << "\tUNKNOWN CIRCUIT:\t" - << mMessageBuilder->getMessageName() << llendl; + << mMessageBuilder->getMessageName() << LL_ENDL; } LL_WARNS_ONCE("Messaging") << "sendMessage - Trying to send " << mMessageBuilder->getMessageName() << " on unknown circuit " - << host << llendl; + << host << LL_ENDL; return 0; } else @@ -1211,11 +1201,11 @@ S32 LLMessageSystem::sendMessage(const LLHost &host) if(mVerboseLog) { LL_INFOS("Messaging") << "MSG: -> " << host << "\tDEAD CIRCUIT\t\t" - << mMessageBuilder->getMessageName() << llendl; + << mMessageBuilder->getMessageName() << LL_ENDL; } LL_WARNS("Messaging") << "sendMessage - Trying to send message " << mMessageBuilder->getMessageName() << " to dead circuit " - << host << llendl; + << host << LL_ENDL; return 0; } } @@ -1260,7 +1250,7 @@ S32 LLMessageSystem::sendMessage(const LLHost &host) LL_WARNS("Messaging") << "sendMessage - Trying to send " << ((buffer_length > 4000) ? "EXTRA " : "") << "BIG message " << mMessageBuilder->getMessageName() << " - " - << buffer_length << llendl; + << buffer_length << LL_ENDL; } } if (mSendReliable) @@ -1322,7 +1312,7 @@ S32 LLMessageSystem::sendMessage(const LLHost &host) // append_acout_count is incorrect or that // MAX_BUFFER_SIZE has fallen below MTU which is bad // and probably programmer error. - LL_ERRS("Messaging") << "Buffer packing failed due to size.." << llendl; + LL_ERRS("Messaging") << "Buffer packing failed due to size.." << LL_ENDL; } } @@ -1345,7 +1335,7 @@ S32 LLMessageSystem::sendMessage(const LLHost &host) else { // mCircuitInfo already points to the correct circuit data - cdp->addBytesOut( buffer_length ); + cdp->addBytesOut( (S32Bytes)buffer_length ); } if(mVerboseLog) @@ -1363,7 +1353,7 @@ S32 LLMessageSystem::sendMessage(const LLHost &host) std::ostream_iterator append(str, " "); std::copy(acks.begin(), acks.end(), append); } - LL_INFOS("Messaging") << str.str() << llendl; + LL_INFOS("Messaging") << str.str() << LL_ENDL; } @@ -1387,7 +1377,7 @@ void LLMessageSystem::logMsgFromInvalidCircuit( const LLHost& host, BOOL recv_re << nullToEmpty(mMessageReader->getMessageName()) << (recv_reliable ? " reliable" : "") << " REJECTED"; - LL_INFOS("Messaging") << str.str() << llendl; + LL_INFOS("Messaging") << str.str() << LL_ENDL; } // nope! // cout << "Rejecting unexpected message " << mCurrentMessageTemplate->mName << " from " << hex << ip << " , " << dec << port << endl; @@ -1395,7 +1385,7 @@ void LLMessageSystem::logMsgFromInvalidCircuit( const LLHost& host, BOOL recv_re // Keep track of rejected messages as well if (mNumMessageCounts >= MAX_MESSAGE_COUNT_NUM) { - LL_WARNS("Messaging") << "Got more than " << MAX_MESSAGE_COUNT_NUM << " packets without clearing counts" << llendl; + LL_WARNS("Messaging") << "Got more than " << MAX_MESSAGE_COUNT_NUM << " packets without clearing counts" << LL_ENDL; } else { @@ -1414,7 +1404,7 @@ S32 LLMessageSystem::sendMessage( { if (!(host.isOk())) { - LL_WARNS("Messaging") << "trying to send message to invalid host" << llendl; + LL_WARNS("Messaging") << "trying to send message to invalid host" << LL_ENDL; return 0; } @@ -1432,14 +1422,14 @@ void LLMessageSystem::logTrustedMsgFromUntrustedCircuit( const LLHost& host ) LL_WARNS("Messaging") << "Received trusted message on untrusted circuit. " << "Will reply with deny. " << "Message: " << nullToEmpty(mMessageReader->getMessageName()) - << " Host: " << host << llendl; + << " Host: " << host << LL_ENDL; } if (mNumMessageCounts >= MAX_MESSAGE_COUNT_NUM) { LL_WARNS("Messaging") << "got more than " << MAX_MESSAGE_COUNT_NUM << " packets without clearing counts" - << llendl; + << LL_ENDL; } else { @@ -1457,7 +1447,7 @@ void LLMessageSystem::logValidMsg(LLCircuitData *cdp, const LLHost& host, BOOL r { if (mNumMessageCounts >= MAX_MESSAGE_COUNT_NUM) { - LL_WARNS("Messaging") << "Got more than " << MAX_MESSAGE_COUNT_NUM << " packets without clearing counts" << llendl; + LL_WARNS("Messaging") << "Got more than " << MAX_MESSAGE_COUNT_NUM << " packets without clearing counts" << LL_ENDL; } else { @@ -1472,7 +1462,7 @@ void LLMessageSystem::logValidMsg(LLCircuitData *cdp, const LLHost& host, BOOL r { // update circuit packet ID tracking (missing/out of order packets) cdp->checkPacketInID( mCurrentRecvPacketID, recv_resent ); - cdp->addBytesIn( mTrueReceiveSize ); + cdp->addBytesIn( (S32Bytes)mTrueReceiveSize ); } if(mVerboseLog) @@ -1486,7 +1476,7 @@ void LLMessageSystem::logValidMsg(LLCircuitData *cdp, const LLHost& host, BOOL r << (recv_reliable ? " reliable" : "") << (recv_resent ? " resent" : "") << (recv_acks ? " acks" : ""); - LL_INFOS("Messaging") << str.str() << llendl; + LL_INFOS("Messaging") << str.str() << LL_ENDL; } } @@ -1496,54 +1486,54 @@ void LLMessageSystem::sanityCheck() // if (!mCurrentRMessageData) // { -// LL_ERRS("Messaging") << "mCurrentRMessageData is NULL" << llendl; +// LL_ERRS("Messaging") << "mCurrentRMessageData is NULL" << LL_ENDL; // } // if (!mCurrentRMessageTemplate) // { -// LL_ERRS("Messaging") << "mCurrentRMessageTemplate is NULL" << llendl; +// LL_ERRS("Messaging") << "mCurrentRMessageTemplate is NULL" << LL_ENDL; // } // if (!mCurrentRTemplateBlock) // { -// LL_ERRS("Messaging") << "mCurrentRTemplateBlock is NULL" << llendl; +// LL_ERRS("Messaging") << "mCurrentRTemplateBlock is NULL" << LL_ENDL; // } // if (!mCurrentRDataBlock) // { -// LL_ERRS("Messaging") << "mCurrentRDataBlock is NULL" << llendl; +// LL_ERRS("Messaging") << "mCurrentRDataBlock is NULL" << LL_ENDL; // } // if (!mCurrentSMessageData) // { -// LL_ERRS("Messaging") << "mCurrentSMessageData is NULL" << llendl; +// LL_ERRS("Messaging") << "mCurrentSMessageData is NULL" << LL_ENDL; // } // if (!mCurrentSMessageTemplate) // { -// LL_ERRS("Messaging") << "mCurrentSMessageTemplate is NULL" << llendl; +// LL_ERRS("Messaging") << "mCurrentSMessageTemplate is NULL" << LL_ENDL; // } // if (!mCurrentSTemplateBlock) // { -// LL_ERRS("Messaging") << "mCurrentSTemplateBlock is NULL" << llendl; +// LL_ERRS("Messaging") << "mCurrentSTemplateBlock is NULL" << LL_ENDL; // } // if (!mCurrentSDataBlock) // { -// LL_ERRS("Messaging") << "mCurrentSDataBlock is NULL" << llendl; +// LL_ERRS("Messaging") << "mCurrentSDataBlock is NULL" << LL_ENDL; // } } void LLMessageSystem::showCircuitInfo() { - LL_INFOS("Messaging") << mCircuitInfo << llendl; + LL_INFOS("Messaging") << mCircuitInfo << LL_ENDL; } void LLMessageSystem::dumpCircuitInfo() { - lldebugst(LLERR_CIRCUIT_INFO) << mCircuitInfo << llendl; + LL_DEBUGS("Messaging") << mCircuitInfo << LL_ENDL; } /* virtual */ @@ -1587,7 +1577,7 @@ void LLMessageSystem::enableCircuit(const LLHost &host, BOOL trusted) void LLMessageSystem::disableCircuit(const LLHost &host) { - LL_INFOS("Messaging") << "LLMessageSystem::disableCircuit for " << host << llendl; + LL_INFOS("Messaging") << "LLMessageSystem::disableCircuit for " << host << LL_ENDL; U32 code = gMessageSystem->findCircuitCode( host ); // Don't need to do this, as we're removing the circuit info anyway - djs 01/28/03 @@ -1600,7 +1590,7 @@ void LLMessageSystem::disableCircuit(const LLHost &host) code_session_map_t::iterator it = mCircuitCodes.find(code); if(it != mCircuitCodes.end()) { - LL_INFOS("Messaging") << "Circuit " << code << " removed from list" << llendl; + LL_INFOS("Messaging") << "Circuit " << code << " removed from list" << LL_ENDL; //mCircuitCodes.removeData(code); mCircuitCodes.erase(it); } @@ -1616,7 +1606,7 @@ void LLMessageSystem::disableCircuit(const LLHost &host) U32 old_port = (U32)(ip_port & (U64)0xFFFFFFFF); U32 old_ip = (U32)(ip_port >> 32); - LL_INFOS("Messaging") << "Host " << LLHost(old_ip, old_port) << " circuit " << code << " removed from lookup table" << llendl; + LL_INFOS("Messaging") << "Host " << LLHost(old_ip, old_port) << " circuit " << code << " removed from lookup table" << LL_ENDL; gMessageSystem->mIPPortToCircuitCode.erase(ip_port); } mCircuitInfo.removeCircuitData(host); @@ -1626,7 +1616,7 @@ void LLMessageSystem::disableCircuit(const LLHost &host) // Sigh, since we can open circuits which don't have circuit // codes, it's possible for this to happen... - LL_WARNS("Messaging") << "Couldn't find circuit code for " << host << llendl; + LL_WARNS("Messaging") << "Couldn't find circuit code for " << host << LL_ENDL; } } @@ -1657,7 +1647,7 @@ BOOL LLMessageSystem::checkCircuitBlocked(const U32 circuit) if (!host.isOk()) { - LL_DEBUGS("Messaging") << "checkCircuitBlocked: Unknown circuit " << circuit << llendl; + LL_DEBUGS("Messaging") << "checkCircuitBlocked: Unknown circuit " << circuit << LL_ENDL; return TRUE; } @@ -1668,7 +1658,7 @@ BOOL LLMessageSystem::checkCircuitBlocked(const U32 circuit) } else { - LL_INFOS("Messaging") << "checkCircuitBlocked(circuit): Unknown host - " << host << llendl; + LL_INFOS("Messaging") << "checkCircuitBlocked(circuit): Unknown host - " << host << LL_ENDL; return FALSE; } } @@ -1679,7 +1669,7 @@ BOOL LLMessageSystem::checkCircuitAlive(const U32 circuit) if (!host.isOk()) { - LL_DEBUGS("Messaging") << "checkCircuitAlive: Unknown circuit " << circuit << llendl; + LL_DEBUGS("Messaging") << "checkCircuitAlive: Unknown circuit " << circuit << LL_ENDL; return FALSE; } @@ -1690,7 +1680,7 @@ BOOL LLMessageSystem::checkCircuitAlive(const U32 circuit) } else { - LL_INFOS("Messaging") << "checkCircuitAlive(circuit): Unknown host - " << host << llendl; + LL_INFOS("Messaging") << "checkCircuitAlive(circuit): Unknown host - " << host << LL_ENDL; return FALSE; } } @@ -1704,7 +1694,7 @@ BOOL LLMessageSystem::checkCircuitAlive(const LLHost &host) } else { - LL_DEBUGS("Messaging") << "checkCircuitAlive(host): Unknown host - " << host << llendl; + LL_DEBUGS("Messaging") << "checkCircuitAlive(host): Unknown host - " << host << LL_ENDL; return FALSE; } } @@ -1739,7 +1729,7 @@ LLHost LLMessageSystem::findHost(const U32 circuit_code) void LLMessageSystem::setMaxMessageTime(const F32 seconds) { - mMaxMessageTime = seconds; + mMaxMessageTime = F32Seconds(seconds); } void LLMessageSystem::setMaxMessageCounts(const S32 num) @@ -1861,18 +1851,18 @@ void LLMessageSystem::processAssignCircuitCode(LLMessageSystem* msg, void**) { LL_WARNS("Messaging") << "AssignCircuitCode, bad session id. Expecting " << msg->getMySessionID() << " but got " << session_id - << llendl; + << LL_ENDL; return; } U32 code; msg->getU32Fast(_PREHASH_CircuitCode, _PREHASH_Code, code); if (!code) { - LL_ERRS("Messaging") << "Assigning circuit code of zero!" << llendl; + LL_ERRS("Messaging") << "Assigning circuit code of zero!" << LL_ENDL; } msg->mOurCircuitCode = code; - LL_INFOS("Messaging") << "Circuit code " << code << " assigned." << llendl; + LL_INFOS("Messaging") << "Circuit code " << code << " assigned." << LL_ENDL; } */ @@ -1896,20 +1886,20 @@ bool LLMessageSystem::addCircuitCode(U32 code, const LLUUID& session_id) { if(!code) { - LL_WARNS("Messaging") << "addCircuitCode: zero circuit code" << llendl; + LL_WARNS("Messaging") << "addCircuitCode: zero circuit code" << LL_ENDL; return false; } code_session_map_t::iterator it = mCircuitCodes.find(code); if(it == mCircuitCodes.end()) { - LL_INFOS("Messaging") << "New circuit code " << code << " added" << llendl; + LL_INFOS("Messaging") << "New circuit code " << code << " added" << LL_ENDL; //msg->mCircuitCodes[circuit_code] = circuit_code; mCircuitCodes.insert(code_session_map_t::value_type(code, session_id)); } else { - LL_INFOS("Messaging") << "Duplicate circuit code " << code << " added" << llendl; + LL_INFOS("Messaging") << "Duplicate circuit code " << code << " added" << LL_ENDL; } return true; } @@ -1943,7 +1933,7 @@ void LLMessageSystem::processUseCircuitCode(LLMessageSystem* msg, // Whoah, abort! We don't know anything about this circuit code. LL_WARNS("Messaging") << "UseCircuitCode for " << circuit_code_in << " received without AddCircuitCode message - aborting" - << llendl; + << LL_ENDL; return; } @@ -1955,7 +1945,7 @@ void LLMessageSystem::processUseCircuitCode(LLMessageSystem* msg, { LL_WARNS("Messaging") << "UseCircuitCode unmatched session id. Got " << session_id << " but expected " << (*it).second - << llendl; + << LL_ENDL; return; } @@ -1968,7 +1958,7 @@ void LLMessageSystem::processUseCircuitCode(LLMessageSystem* msg, if ((ip_port_old == ip_port_in) && (circuit_code_old == circuit_code_in)) { // Current information is the same as incoming info, ignore - LL_INFOS("Messaging") << "Got duplicate UseCircuitCode for circuit " << circuit_code_in << " to " << msg->getSender() << llendl; + LL_INFOS("Messaging") << "Got duplicate UseCircuitCode for circuit " << circuit_code_in << " to " << msg->getSender() << LL_ENDL; return; } @@ -1978,27 +1968,27 @@ void LLMessageSystem::processUseCircuitCode(LLMessageSystem* msg, msg->mIPPortToCircuitCode.erase(ip_port_old); U32 old_port = (U32)(ip_port_old & (U64)0xFFFFFFFF); U32 old_ip = (U32)(ip_port_old >> 32); - LL_INFOS("Messaging") << "Removing derelict lookup entry for circuit " << circuit_code_old << " to " << LLHost(old_ip, old_port) << llendl; + LL_INFOS("Messaging") << "Removing derelict lookup entry for circuit " << circuit_code_old << " to " << LLHost(old_ip, old_port) << LL_ENDL; } if (circuit_code_old) { LLHost cur_host(ip, port); - LL_WARNS("Messaging") << "Disabling existing circuit for " << cur_host << llendl; + LL_WARNS("Messaging") << "Disabling existing circuit for " << cur_host << LL_ENDL; msg->disableCircuit(cur_host); if (circuit_code_old == circuit_code_in) { - LL_WARNS("Messaging") << "Asymmetrical circuit to ip/port lookup!" << llendl; - LL_WARNS("Messaging") << "Multiple circuit codes for " << cur_host << " probably!" << llendl; - LL_WARNS("Messaging") << "Permanently disabling circuit" << llendl; + LL_WARNS("Messaging") << "Asymmetrical circuit to ip/port lookup!" << LL_ENDL; + LL_WARNS("Messaging") << "Multiple circuit codes for " << cur_host << " probably!" << LL_ENDL; + LL_WARNS("Messaging") << "Permanently disabling circuit" << LL_ENDL; return; } else { LL_WARNS("Messaging") << "Circuit code changed for " << msg->getSender() << " from " << circuit_code_old << " to " - << circuit_code_in << llendl; + << circuit_code_in << LL_ENDL; } } @@ -2040,7 +2030,7 @@ void LLMessageSystem::processUseCircuitCode(LLMessageSystem* msg, LL_INFOS("Messaging") << "Circuit code " << circuit_code_in << " from " << msg->getSender() << " for agent " << id << " in session " - << session_id << llendl; + << session_id << LL_ENDL; const LLUseCircuitCodeResponder* responder = (const LLUseCircuitCodeResponder*) user; @@ -2051,7 +2041,7 @@ void LLMessageSystem::processUseCircuitCode(LLMessageSystem* msg, } else { - LL_WARNS("Messaging") << "Got zero circuit code in use_circuit_code" << llendl; + LL_WARNS("Messaging") << "Got zero circuit code in use_circuit_code" << LL_ENDL; } } @@ -2073,7 +2063,7 @@ void LLMessageSystem::processError(LLMessageSystem* msg, void**) LL_WARNS("Messaging") << "Message error from " << msg->getSender() << " - " << error_code << " " << error_token << " " << error_id << " \"" - << error_system << "\" \"" << error_message << "\"" << llendl; + << error_system << "\" \"" << error_message << "\"" << LL_ENDL; } @@ -2109,7 +2099,7 @@ void LLMessageSystem::dispatch( gMessageSystem->mMessageTemplates.end()) && !LLMessageConfig::isValidMessage(msg_name)) { - LL_WARNS("Messaging") << "Ignoring unknown message " << msg_name << llendl; + LL_WARNS("Messaging") << "Ignoring unknown message " << msg_name << LL_ENDL; responsep->notFound("Invalid message name"); return; } @@ -2120,12 +2110,12 @@ void LLMessageSystem::dispatch( if (!handler) { LL_WARNS("Messaging") << "LLMessageService::dispatch > no handler for " - << path << llendl; + << path << LL_ENDL; return; } // enable this for output of message names - //LL_INFOS("Messaging") << "< \"" << msg_name << "\"" << llendl; - //lldebugs << "data: " << LLSDNotationStreamer(message) << llendl; + //LL_INFOS("Messaging") << "< \"" << msg_name << "\"" << LL_ENDL; + //LL_DEBUGS() << "data: " << LLSDNotationStreamer(message) << LL_ENDL; handler->post(responsep, context, message); } @@ -2243,7 +2233,7 @@ S32 LLMessageSystem::sendError( else { LL_WARNS("Messaging") << "Data and message were too large -- data removed." - << llendl; + << LL_ENDL; addBinaryData("Data", NULL, 0); } return sendReliable(host); @@ -2263,7 +2253,7 @@ void process_packet_ack(LLMessageSystem *msgsystem, void** /*user_data*/) for (S32 i = 0; i < ack_count; i++) { msgsystem->getU32Fast(_PREHASH_Packets, _PREHASH_ID, packet_id, i); -// LL_DEBUGS("Messaging") << "ack recvd' from " << host << " for packet " << (TPACKETID)packet_id << llendl; +// LL_DEBUGS("Messaging") << "ack recvd' from " << host << " for packet " << (TPACKETID)packet_id << LL_ENDL; cdp->ackReliablePacket(packet_id); } if (!cdp->getUnackedPacketCount()) @@ -2284,12 +2274,12 @@ void process_log_messages(LLMessageSystem* msg, void**) if (log_message) { - LL_INFOS("Messaging") << "Starting logging via message" << llendl; + LL_INFOS("Messaging") << "Starting logging via message" << LL_ENDL; msg->startLogging(); } else { - LL_INFOS("Messaging") << "Stopping logging via message" << llendl; + LL_INFOS("Messaging") << "Stopping logging via message" << LL_ENDL; msg->stopLogging(); } }*/ @@ -2309,7 +2299,7 @@ void process_create_trusted_circuit(LLMessageSystem *msg, void **) if (!cdp) { LL_WARNS("Messaging") << "Attempt to create trusted circuit without circuit data: " - << msg->getSender() << llendl; + << msg->getSender() << LL_ENDL; return; } @@ -2328,13 +2318,13 @@ void process_create_trusted_circuit(LLMessageSystem *msg, void **) if( msg->getBlockUntrustedInterface() ) { LL_WARNS("Messaging") << "Ignoring CreateTrustedCircuit on public interface from host: " - << msg->getSender() << llendl; + << msg->getSender() << LL_ENDL; return; } else { LL_WARNS("Messaging") << "Processing CreateTrustedCircuit on public interface from host: " - << msg->getSender() << llendl; + << msg->getSender() << LL_ENDL; } } @@ -2350,7 +2340,7 @@ void process_create_trusted_circuit(LLMessageSystem *msg, void **) if(msg->isMatchingDigestForWindowAndUUIDs(their_digest, TRUST_TIME_WINDOW, local_id, remote_id)) { cdp->setTrusted(TRUE); - LL_INFOS("Messaging") << "Trusted digest from " << msg->getSender() << llendl; + LL_INFOS("Messaging") << "Trusted digest from " << msg->getSender() << LL_ENDL; return; } else if (cdp->getTrusted()) @@ -2360,13 +2350,13 @@ void process_create_trusted_circuit(LLMessageSystem *msg, void **) // the message system is being slow. Don't bother sending the deny, as it may continually // ping-pong back and forth on a very hosed circuit. LL_WARNS("Messaging") << "Ignoring bad digest from known trusted circuit: " << their_digest - << " host: " << msg->getSender() << llendl; + << " host: " << msg->getSender() << LL_ENDL; return; } else { LL_WARNS("Messaging") << "Bad digest from known circuit: " << their_digest - << " host: " << msg->getSender() << llendl; + << " host: " << msg->getSender() << LL_ENDL; msg->sendDenyTrustedCircuit(msg->getSender()); return; } @@ -2402,13 +2392,13 @@ void process_deny_trusted_circuit(LLMessageSystem *msg, void **) if( msg->getBlockUntrustedInterface() ) { LL_WARNS("Messaging") << "Ignoring DenyTrustedCircuit on public interface from host: " - << msg->getSender() << llendl; + << msg->getSender() << LL_ENDL; return; } else { LL_WARNS("Messaging") << "Processing DenyTrustedCircuit on public interface from host: " - << msg->getSender() << llendl; + << msg->getSender() << LL_ENDL; } } @@ -2421,7 +2411,7 @@ void process_deny_trusted_circuit(LLMessageSystem *msg, void **) // *TODO: probably should keep a count of number of resends // per circuit, and stop resending after a while. LL_INFOS("Messaging") << "Got DenyTrustedCircuit. Sending CreateTrustedCircuit to " - << msg->getSender() << llendl; + << msg->getSender() << LL_ENDL; msg->sendCreateTrustedCircuit(msg->getSender(), local_id, remote_id); } @@ -2537,11 +2527,11 @@ bool start_messaging_system( if (gMessageSystem->mMessageFileVersionNumber != gPrehashVersionNumber) { LL_INFOS("AppInit") << "Message template version does not match prehash version number" << LL_ENDL; - LL_INFOS("AppInit") << "Run simulator with -prehash command line option to rebuild prehash data" << llendl; + LL_INFOS("AppInit") << "Run simulator with -prehash command line option to rebuild prehash data" << LL_ENDL; } else { - LL_DEBUGS("AppInit") << "Message template version matches prehash version number" << llendl; + LL_DEBUGS("AppInit") << "Message template version matches prehash version number" << LL_ENDL; } } @@ -2587,7 +2577,7 @@ void LLMessageSystem::startLogging() str << "\t<-\tincoming message" <\toutgoing message" << std::endl; str << " <> host size zero id name"; - LL_INFOS("Messaging") << str.str() << llendl; + LL_INFOS("Messaging") << str.str() << LL_ENDL; } void LLMessageSystem::stopLogging() @@ -2595,7 +2585,7 @@ void LLMessageSystem::stopLogging() if(mVerboseLog) { mVerboseLog = FALSE; - LL_INFOS("Messaging") << "END MESSAGE LOG" << llendl; + LL_INFOS("Messaging") << "END MESSAGE LOG" << LL_ENDL; } } @@ -2609,54 +2599,54 @@ void LLMessageSystem::summarizeLogs(std::ostream& str) // Incoming str << buffer << std::endl << "Incoming:" << std::endl; - tmp_str = U64_to_str(mTotalBytesIn); + tmp_str = fmt::to_string(mTotalBytesIn); buffer = llformat( "Total bytes received: %20s (%5.2f kbits per second)", tmp_str.c_str(), ((F32)mTotalBytesIn * 0.008f) / run_time); str << buffer << std::endl; - tmp_str = U64_to_str(mPacketsIn); + tmp_str = fmt::to_string(mPacketsIn); buffer = llformat( "Total packets received: %20s (%5.2f packets per second)", tmp_str.c_str(), ((F32) mPacketsIn / run_time)); str << buffer << std::endl; buffer = llformat( "Average packet size: %20.0f bytes", (F32)mTotalBytesIn / (F32)mPacketsIn); str << buffer << std::endl; - tmp_str = U64_to_str(mReliablePacketsIn); + tmp_str = fmt::to_string(mReliablePacketsIn); buffer = llformat( "Total reliable packets: %20s (%5.2f%%)", tmp_str.c_str(), 100.f * ((F32) mReliablePacketsIn)/((F32) mPacketsIn + 1)); str << buffer << std::endl; - tmp_str = U64_to_str(mCompressedPacketsIn); + tmp_str = fmt::to_string(mCompressedPacketsIn); buffer = llformat( "Total compressed packets: %20s (%5.2f%%)", tmp_str.c_str(), 100.f * ((F32) mCompressedPacketsIn)/((F32) mPacketsIn + 1)); str << buffer << std::endl; S64 savings = mUncompressedBytesIn - mCompressedBytesIn; - tmp_str = U64_to_str(savings); + tmp_str = fmt::to_string(savings); buffer = llformat( "Total compression savings: %20s bytes", tmp_str.c_str()); str << buffer << std::endl; - tmp_str = U64_to_str(savings/(mCompressedPacketsIn +1)); + tmp_str = fmt::to_string(savings/(mCompressedPacketsIn +1)); buffer = llformat( "Avg comp packet savings: %20s (%5.2f : 1)", tmp_str.c_str(), ((F32) mUncompressedBytesIn)/((F32) mCompressedBytesIn+1)); str << buffer << std::endl; - tmp_str = U64_to_str(savings/(mPacketsIn+1)); + tmp_str = fmt::to_string(savings/(mPacketsIn+1)); buffer = llformat( "Avg overall comp savings: %20s (%5.2f : 1)", tmp_str.c_str(), ((F32) mTotalBytesIn + (F32) savings)/((F32) mTotalBytesIn + 1.f)); // Outgoing str << buffer << std::endl << std::endl << "Outgoing:" << std::endl; - tmp_str = U64_to_str(mTotalBytesOut); + tmp_str = fmt::to_string(mTotalBytesOut); buffer = llformat( "Total bytes sent: %20s (%5.2f kbits per second)", tmp_str.c_str(), ((F32)mTotalBytesOut * 0.008f) / run_time ); str << buffer << std::endl; - tmp_str = U64_to_str(mPacketsOut); + tmp_str = fmt::to_string(mPacketsOut); buffer = llformat( "Total packets sent: %20s (%5.2f packets per second)", tmp_str.c_str(), ((F32)mPacketsOut / run_time)); str << buffer << std::endl; buffer = llformat( "Average packet size: %20.0f bytes", (F32)mTotalBytesOut / (F32)mPacketsOut); str << buffer << std::endl; - tmp_str = U64_to_str(mReliablePacketsOut); + tmp_str = fmt::to_string(mReliablePacketsOut); buffer = llformat( "Total reliable packets: %20s (%5.2f%%)", tmp_str.c_str(), 100.f * ((F32) mReliablePacketsOut)/((F32) mPacketsOut + 1)); str << buffer << std::endl; - tmp_str = U64_to_str(mCompressedPacketsOut); + tmp_str = fmt::to_string(mCompressedPacketsOut); buffer = llformat( "Total compressed packets: %20s (%5.2f%%)", tmp_str.c_str(), 100.f * ((F32) mCompressedPacketsOut)/((F32) mPacketsOut + 1)); str << buffer << std::endl; savings = mUncompressedBytesOut - mCompressedBytesOut; - tmp_str = U64_to_str(savings); + tmp_str = fmt::to_string(savings); buffer = llformat( "Total compression savings: %20s bytes", tmp_str.c_str()); str << buffer << std::endl; - tmp_str = U64_to_str(savings/(mCompressedPacketsOut +1)); + tmp_str = fmt::to_string(savings/(mCompressedPacketsOut +1)); buffer = llformat( "Avg comp packet savings: %20s (%5.2f : 1)", tmp_str.c_str(), ((F32) mUncompressedBytesOut)/((F32) mCompressedBytesOut+1)); str << buffer << std::endl; - tmp_str = U64_to_str(savings/(mPacketsOut+1)); + tmp_str = fmt::to_string(savings/(mPacketsOut+1)); buffer = llformat( "Avg overall comp savings: %20s (%5.2f : 1)", tmp_str.c_str(), ((F32) mTotalBytesOut + (F32) savings)/((F32) mTotalBytesOut + 1.f)); str << buffer << std::endl << std::endl; buffer = llformat( "SendPacket failures: %20d", mSendPacketFailureCount); @@ -2703,7 +2693,7 @@ void end_messaging_system(bool print_summary) { std::ostringstream str; gMessageSystem->summarizeLogs(str); - LL_INFOS("Messaging") << str.str().c_str() << llendl; + LL_INFOS("Messaging") << str.str().c_str() << LL_ENDL; } delete gMessageSystem; @@ -2756,7 +2746,7 @@ void LLMessageSystem::dumpReceiveCounts() if(mNumMessageCounts > 0) { - LL_DEBUGS("Messaging") << "Dump: " << mNumMessageCounts << " messages processed in " << mReceiveTime << " seconds" << llendl; + LL_DEBUGS("Messaging") << "Dump: " << mNumMessageCounts << " messages processed in " << mReceiveTime << " seconds" << LL_ENDL; for (message_template_name_map_t::const_iterator iter = mMessageTemplates.begin(), end = mMessageTemplates.end(); iter != end; iter++) @@ -2765,7 +2755,7 @@ void LLMessageSystem::dumpReceiveCounts() if (mt->mReceiveCount > 0) { LL_INFOS("Messaging") << "Num: " << std::setw(3) << mt->mReceiveCount << " Bytes: " << std::setw(6) << mt->mReceiveBytes - << " Invalid: " << std::setw(3) << mt->mReceiveInvalid << " " << mt->mName << " " << llround(100 * mt->mDecodeTimeThisFrame / mReceiveTime) << "%" << llendl; + << " Invalid: " << std::setw(3) << mt->mReceiveInvalid << " " << mt->mName << " " << ll_round(100 * mt->mDecodeTimeThisFrame / mReceiveTime.value()) << "%" << LL_ENDL; } } } @@ -2882,7 +2872,7 @@ S32 LLMessageSystem::zeroCodeExpand(U8** data, S32* data_size) if ((*data_size ) < LL_MINIMUM_VALID_PACKET_SIZE) { LL_WARNS("Messaging") << "zeroCodeExpand() called with data_size of " << *data_size - << llendl; + << LL_ENDL; } mTotalBytesIn += *data_size; @@ -2921,7 +2911,7 @@ S32 LLMessageSystem::zeroCodeExpand(U8** data, S32* data_size) { if (outptr > (&mEncodedRecvBuffer[MAX_BUFFER_SIZE-1])) { - LL_WARNS("Messaging") << "attempt to write past reasonable encoded buffer size 1" << llendl; + LL_WARNS("Messaging") << "attempt to write past reasonable encoded buffer size 1" << LL_ENDL; callExceptionFunc(MX_WROTE_PAST_BUFFER_SIZE); outptr = mEncodedRecvBuffer; break; @@ -2933,7 +2923,7 @@ S32 LLMessageSystem::zeroCodeExpand(U8** data, S32* data_size) *outptr++ = *inptr++; if (outptr > (&mEncodedRecvBuffer[MAX_BUFFER_SIZE-256])) { - LL_WARNS("Messaging") << "attempt to write past reasonable encoded buffer size 2" << llendl; + LL_WARNS("Messaging") << "attempt to write past reasonable encoded buffer size 2" << LL_ENDL; callExceptionFunc(MX_WROTE_PAST_BUFFER_SIZE); outptr = mEncodedRecvBuffer; count = -1; @@ -2952,7 +2942,7 @@ S32 LLMessageSystem::zeroCodeExpand(U8** data, S32* data_size) { if (outptr > (&mEncodedRecvBuffer[MAX_BUFFER_SIZE-(*inptr)])) { - LL_WARNS("Messaging") << "attempt to write past reasonable encoded buffer size 3" << llendl; + LL_WARNS("Messaging") << "attempt to write past reasonable encoded buffer size 3" << LL_ENDL; callExceptionFunc(MX_WROTE_PAST_BUFFER_SIZE); outptr = mEncodedRecvBuffer; } @@ -2976,7 +2966,7 @@ void LLMessageSystem::addTemplate(LLMessageTemplate *templatep) if (mMessageTemplates.count(templatep->mName) > 0) { LL_ERRS("Messaging") << templatep->mName << " already used as a template name!" - << llendl; + << LL_ENDL; } mMessageTemplates[templatep->mName] = templatep; mMessageNumbers[templatep->mMessageNumber] = templatep; @@ -2992,7 +2982,7 @@ void LLMessageSystem::setHandlerFuncFast(const char *name, void (*handler_func)( } else { - LL_ERRS("Messaging") << name << " is not a known message name!" << llendl; + LL_ERRS("Messaging") << name << " is not a known message name!" << LL_ENDL; } } @@ -3005,7 +2995,7 @@ bool LLMessageSystem::callHandler(const char *name, if(iter == mMessageTemplates.end()) { LL_WARNS("Messaging") << "LLMessageSystem::callHandler: unknown message " - << name << llendl; + << name << LL_ENDL; return false; } @@ -3016,7 +3006,7 @@ bool LLMessageSystem::callHandler(const char *name, << name << " from " << (trustedSource ? "trusted " : "untrusted ") - << "source" << llendl; + << "source" << LL_ENDL; return false; } @@ -3042,12 +3032,23 @@ void LLMessageSystem::setExceptionFunc(EMessageException e, BOOL LLMessageSystem::callExceptionFunc(EMessageException exception) { callbacks_t::iterator it = mExceptionCallbacks.find(exception); - if(it != mExceptionCallbacks.end()) + if(it == mExceptionCallbacks.end()) { - ((*it).second.first)(this, (*it).second.second,exception); - return TRUE; + return FALSE; } - return FALSE; + + exception_t& ex = it->second; + msg_exception_callback ex_cb = ex.first; + + if (!ex_cb) + { + LL_WARNS("Messaging") << "LLMessageSystem::callExceptionFunc: bad message exception callback." << LL_ENDL; + return FALSE; + } + + (ex_cb)(this, ex.second, exception); + + return TRUE; } void LLMessageSystem::setTimingFunc(msg_timing_callback func, void* data) @@ -3152,7 +3153,7 @@ bool LLMessageSystem::generateDigestForWindowAndUUIDs(char* digest, const S32 wi std::string shared_secret = get_shared_secret(); if(shared_secret.empty()) { - LL_ERRS("Messaging") << "Trying to generate complex digest on a machine without a shared secret!" << llendl; + LL_ERRS("Messaging") << "Trying to generate complex digest on a machine without a shared secret!" << LL_ENDL; } U32 now = (U32)time(NULL); @@ -3171,7 +3172,7 @@ bool LLMessageSystem::isMatchingDigestForWindowAndUUIDs(const char* digest, cons std::string shared_secret = get_shared_secret(); if(shared_secret.empty()) { - LL_ERRS("Messaging") << "Trying to compare complex digests on a machine without a shared secret!" << llendl; + LL_ERRS("Messaging") << "Trying to compare complex digests on a machine without a shared secret!" << LL_ENDL; } char our_digest[MD5HEX_STR_SIZE]; /* Flawfinder: ignore */ @@ -3218,7 +3219,7 @@ bool LLMessageSystem::generateDigestForWindow(char* digest, const S32 window) co std::string shared_secret = get_shared_secret(); if(shared_secret.empty()) { - LL_ERRS("Messaging") << "Trying to generate simple digest on a machine without a shared secret!" << llendl; + LL_ERRS("Messaging") << "Trying to generate simple digest on a machine without a shared secret!" << LL_ENDL; } U32 now = (U32)time(NULL); @@ -3237,7 +3238,7 @@ bool LLMessageSystem::isMatchingDigestForWindow(const char* digest, S32 const wi std::string shared_secret = get_shared_secret(); if(shared_secret.empty()) { - LL_ERRS("Messaging") << "Trying to compare simple digests on a machine without a shared secret!" << llendl; + LL_ERRS("Messaging") << "Trying to compare simple digests on a machine without a shared secret!" << LL_ENDL; } char our_digest[MD5HEX_STR_SIZE]; /* Flawfinder: ignore */ @@ -3271,12 +3272,12 @@ void LLMessageSystem::sendCreateTrustedCircuit(const LLHost &host, const LLUUID char digest[MD5HEX_STR_SIZE]; /* Flawfinder: ignore */ if (id1.isNull()) { - LL_WARNS("Messaging") << "Can't send CreateTrustedCircuit to " << host << " because we don't have the local end point ID" << llendl; + LL_WARNS("Messaging") << "Can't send CreateTrustedCircuit to " << host << " because we don't have the local end point ID" << LL_ENDL; return; } if (id2.isNull()) { - LL_WARNS("Messaging") << "Can't send CreateTrustedCircuit to " << host << " because we don't have the remote end point ID" << llendl; + LL_WARNS("Messaging") << "Can't send CreateTrustedCircuit to " << host << " because we don't have the remote end point ID" << LL_ENDL; return; } generateDigestForWindowAndUUIDs(digest, TRUST_TIME_WINDOW, id1, id2); @@ -3284,7 +3285,7 @@ void LLMessageSystem::sendCreateTrustedCircuit(const LLHost &host, const LLUUID nextBlockFast(_PREHASH_DataBlock); addUUIDFast(_PREHASH_EndPointID, id1); addBinaryDataFast(_PREHASH_Digest, digest, MD5HEX_STR_BYTES); - LL_INFOS("Messaging") << "xmitting digest: " << digest << " Host: " << host << llendl; + LL_INFOS("Messaging") << "xmitting digest: " << digest << " Host: " << host << LL_ENDL; sendMessage(host); } @@ -3298,10 +3299,10 @@ void LLMessageSystem::reallySendDenyTrustedCircuit(const LLHost &host) LLCircuitData *cdp = mCircuitInfo.findCircuit(host); if (!cdp) { - LL_WARNS("Messaging") << "Not sending DenyTrustedCircuit to host without a circuit." << llendl; + LL_WARNS("Messaging") << "Not sending DenyTrustedCircuit to host without a circuit." << LL_ENDL; return; } - LL_INFOS("Messaging") << "Sending DenyTrustedCircuit to " << host << llendl; + LL_INFOS("Messaging") << "Sending DenyTrustedCircuit to " << host << LL_ENDL; newMessageFast(_PREHASH_DenyTrustedCircuit); nextBlockFast(_PREHASH_DataBlock); addUUIDFast(_PREHASH_EndPointID, cdp->getLocalEndPointID()); @@ -3322,7 +3323,7 @@ void LLMessageSystem::establishBidirectionalTrust(const LLHost &host, S64 frame_ std::string shared_secret = get_shared_secret(); if(shared_secret.empty()) { - LL_ERRS("Messaging") << "Trying to establish bidirectional trust on a machine without a shared secret!" << llendl; + LL_ERRS("Messaging") << "Trying to establish bidirectional trust on a machine without a shared secret!" << LL_ENDL; } LLTimer timeout; @@ -3374,8 +3375,8 @@ void LLMessageSystem::establishBidirectionalTrust(const LLHost &host, S64 frame_ void LLMessageSystem::dumpPacketToLog() { - LL_WARNS("Messaging") << "Packet Dump from:" << mPacketRing->getLastSender() << llendl; - LL_WARNS("Messaging") << "Packet Size:" << mTrueReceiveSize << llendl; + LL_WARNS("Messaging") << "Packet Dump from:" << mPacketRing->getLastSender() << LL_ENDL; + LL_WARNS("Messaging") << "Packet Size:" << mTrueReceiveSize << LL_ENDL; char line_buffer[256]; /* Flawfinder: ignore */ S32 i; S32 cur_line_pos = 0; @@ -3390,27 +3391,27 @@ void LLMessageSystem::dumpPacketToLog() if (cur_line_pos >= 16) { cur_line_pos = 0; - LL_WARNS("Messaging") << "PD:" << cur_line << "PD:" << line_buffer << llendl; + LL_WARNS("Messaging") << "PD:" << cur_line << "PD:" << line_buffer << LL_ENDL; cur_line++; } } if (cur_line_pos) { - LL_WARNS("Messaging") << "PD:" << cur_line << "PD:" << line_buffer << llendl; + LL_WARNS("Messaging") << "PD:" << cur_line << "PD:" << line_buffer << LL_ENDL; } } //static -U64 LLMessageSystem::getMessageTimeUsecs(const BOOL update) +U64Microseconds LLMessageSystem::getMessageTimeUsecs(const BOOL update) { if (gMessageSystem) { if (update) { - gMessageSystem->mCurrentMessageTimeSeconds = totalTime()*SEC_PER_USEC; + gMessageSystem->mCurrentMessageTime = totalTime(); } - return (U64)(gMessageSystem->mCurrentMessageTimeSeconds * USEC_PER_SEC); + return gMessageSystem->mCurrentMessageTime; } else { @@ -3419,19 +3420,19 @@ U64 LLMessageSystem::getMessageTimeUsecs(const BOOL update) } //static -F64 LLMessageSystem::getMessageTimeSeconds(const BOOL update) +F64Seconds LLMessageSystem::getMessageTimeSeconds(const BOOL update) { if (gMessageSystem) { if (update) { - gMessageSystem->mCurrentMessageTimeSeconds = totalTime()*SEC_PER_USEC; + gMessageSystem->mCurrentMessageTime = totalTime(); } - return gMessageSystem->mCurrentMessageTimeSeconds; + return gMessageSystem->mCurrentMessageTime; } else { - return totalTime()*SEC_PER_USEC; + return F64Seconds(totalTime()); } } @@ -3940,7 +3941,7 @@ void LLMessageSystem::getStringFast(const char *block, const char *var, { if(buffer_size <= 0) { - LL_WARNS("Messaging") << "buffer_size <= 0" << llendl; + LL_WARNS("Messaging") << "buffer_size <= 0" << LL_ENDL; } mMessageReader->getString(block, var, buffer_size, s, blocknum); } @@ -4049,7 +4050,7 @@ void LLMessageSystem::banUdpMessage(const std::string& name) } else { - llwarns << "Attempted to ban an unknown message: " << name << "." << llendl; + LL_WARNS() << "Attempted to ban an unknown message: " << name << "." << LL_ENDL; } } const LLHost& LLMessageSystem::getSender() const diff --git a/indra/llmessage/message.h b/indra/llmessage/message.h index fff0c6f85b..174a202331 100644 --- a/indra/llmessage/message.h +++ b/indra/llmessage/message.h @@ -45,7 +45,7 @@ #include "llerror.h" #include "net.h" -#include "string_table.h" +#include "llstringtable.h" #include "llcircuit.h" #include "lltimer.h" //#include "llpacketring.h" @@ -148,18 +148,15 @@ enum EPacketHeaderLayout const S32 LL_DEFAULT_RELIABLE_RETRIES = 3; -const F32 LL_MINIMUM_RELIABLE_TIMEOUT_SECONDS = 1.f; -const F32 LL_MINIMUM_SEMIRELIABLE_TIMEOUT_SECONDS = 1.f; -const F32 LL_PING_BASED_TIMEOUT_DUMMY = 0.0f; - -// *NOTE: Maybe these factors shouldn't include the msec to sec conversion -// implicitly. -// However, all units should be MKS. -const F32 LL_SEMIRELIABLE_TIMEOUT_FACTOR = 5.f / 1000.f; // factor * averaged ping -const F32 LL_RELIABLE_TIMEOUT_FACTOR = 5.f / 1000.f; // factor * averaged ping -const F32 LL_FILE_XFER_TIMEOUT_FACTOR = 5.f / 1000.f; // factor * averaged ping -const F32 LL_LOST_TIMEOUT_FACTOR = 16.f / 1000.f; // factor * averaged ping for marking packets "Lost" -const F32 LL_MAX_LOST_TIMEOUT = 5.f; // Maximum amount of time before considering something "lost" +const F32Seconds LL_MINIMUM_RELIABLE_TIMEOUT_SECONDS(1.f); +const F32Seconds LL_MINIMUM_SEMIRELIABLE_TIMEOUT_SECONDS(1.f); +const F32Seconds LL_PING_BASED_TIMEOUT_DUMMY(0.0f); + +const F32 LL_SEMIRELIABLE_TIMEOUT_FACTOR = 5.f; // averaged ping +const F32 LL_RELIABLE_TIMEOUT_FACTOR = 5.f; // averaged ping +const F32 LL_FILE_XFER_TIMEOUT_FACTOR = 5.f; //averaged ping +const F32 LL_LOST_TIMEOUT_FACTOR = 16.f; // averaged ping for marking packets "Lost" +const F32Seconds LL_MAX_LOST_TIMEOUT(5.f); // Maximum amount of time before considering something "lost" const S32 MAX_MESSAGE_COUNT_NUM = 1024; @@ -279,8 +276,8 @@ class LLMessageSystem : public LLMessageSenderInterface BOOL mSendReliable; // does the outgoing message require a pos ack? LLCircuit mCircuitInfo; - F64 mCircuitPrintTime; // used to print circuit debug info every couple minutes - F32 mCircuitPrintFreq; // seconds + F64Seconds mCircuitPrintTime; // used to print circuit debug info every couple minutes + F32Seconds mCircuitPrintFreq; std::map mIPPortToCircuitCode; std::map mCircuitCodeToIPPort; @@ -344,7 +341,7 @@ class LLMessageSystem : public LLMessageSenderInterface BOOL poll(F32 seconds); // Number of seconds that we want to block waiting for data, returns if data was received BOOL checkMessages(S64 frame_count = 0); - void processAcks(); + void processAcks(F32 collect_time = 0.f); BOOL isMessageFast(const char *msg); BOOL isMessage(const char *msg) @@ -460,8 +457,6 @@ class LLMessageSystem : public LLMessageSenderInterface BOOL isSendFull(const char* blockname = NULL); BOOL isSendFullFast(const char* blockname = NULL); - BOOL removeLastBlock(); - //void buildMessage(); S32 zeroCode(U8 **data, S32 *data_size); @@ -478,7 +473,7 @@ class LLMessageSystem : public LLMessageSenderInterface S32 sendReliable( const LLHost &host, S32 retries, BOOL ping_based_retries, - F32 timeout, + F32Seconds timeout, void (*callback)(void **,S32), void ** callback_data); @@ -498,7 +493,7 @@ class LLMessageSystem : public LLMessageSenderInterface const LLHost &host, S32 retries, BOOL ping_based_timeout, - F32 timeout, + F32Seconds timeout, void (*callback)(void **,S32), void ** callback_data); @@ -692,8 +687,8 @@ class LLMessageSystem : public LLMessageSenderInterface void setMaxMessageTime(const F32 seconds); // Max time to process messages before warning and dumping (neg to disable) void setMaxMessageCounts(const S32 num); // Max number of messages before dumping (neg to disable) - static U64 getMessageTimeUsecs(const BOOL update = FALSE); // Get the current message system time in microseconds - static F64 getMessageTimeSeconds(const BOOL update = FALSE); // Get the current message system time in seconds + static U64Microseconds getMessageTimeUsecs(const BOOL update = FALSE); // Get the current message system time in microseconds + static F64Seconds getMessageTimeSeconds(const BOOL update = FALSE); // Get the current message system time in seconds static void setTimeDecodes(BOOL b); static void setTimeDecodesSpamThreshold(F32 seconds); @@ -792,16 +787,16 @@ class LLMessageSystem : public LLMessageSenderInterface BOOL mbError; S32 mErrorCode; - F64 mResendDumpTime; // The last time we dumped resends + F64Seconds mResendDumpTime; // The last time we dumped resends LLMessageCountInfo mMessageCountList[MAX_MESSAGE_COUNT_NUM]; S32 mNumMessageCounts; - F32 mReceiveTime; - F32 mMaxMessageTime; // Max number of seconds for processing messages + F32Seconds mReceiveTime; + F32Seconds mMaxMessageTime; // Max number of seconds for processing messages S32 mMaxMessageCounts; // Max number of messages to process before dumping. - F64 mMessageCountTime; + F64Seconds mMessageCountTime; - F64 mCurrentMessageTimeSeconds; // The current "message system time" (updated the first call to checkMessages after a resetReceiveCount + F64Seconds mCurrentMessageTime; // The current "message system time" (updated the first call to checkMessages after a resetReceiveCount // message system exceptions typedef std::pair exception_t; @@ -896,7 +891,7 @@ static inline void *htonmemcpy(void *vs, const void *vct, EMsgVariableType type, case MVT_S16: if (n != 2) { - llerrs << "Size argument passed to htonmemcpy doesn't match swizzle type size" << llendl; + LL_ERRS() << "Size argument passed to htonmemcpy doesn't match swizzle type size" << LL_ENDL; } #ifdef LL_BIG_ENDIAN *(s + 1) = *(ct); @@ -911,7 +906,7 @@ static inline void *htonmemcpy(void *vs, const void *vct, EMsgVariableType type, case MVT_F32: if (n != 4) { - llerrs << "Size argument passed to htonmemcpy doesn't match swizzle type size" << llendl; + LL_ERRS() << "Size argument passed to htonmemcpy doesn't match swizzle type size" << LL_ENDL; } #ifdef LL_BIG_ENDIAN *(s + 3) = *(ct); @@ -928,7 +923,7 @@ static inline void *htonmemcpy(void *vs, const void *vct, EMsgVariableType type, case MVT_F64: if (n != 8) { - llerrs << "Size argument passed to htonmemcpy doesn't match swizzle type size" << llendl; + LL_ERRS() << "Size argument passed to htonmemcpy doesn't match swizzle type size" << LL_ENDL; } #ifdef LL_BIG_ENDIAN *(s + 7) = *(ct); @@ -948,7 +943,7 @@ static inline void *htonmemcpy(void *vs, const void *vct, EMsgVariableType type, case MVT_LLQuaternion: // We only send x, y, z and infer w (we set x, y, z to ensure that w >= 0) if (n != 12) { - llerrs << "Size argument passed to htonmemcpy doesn't match swizzle type size" << llendl; + LL_ERRS() << "Size argument passed to htonmemcpy doesn't match swizzle type size" << LL_ENDL; } #ifdef LL_BIG_ENDIAN htonmemcpy(s + 8, ct + 8, MVT_F32, 4); @@ -961,7 +956,7 @@ static inline void *htonmemcpy(void *vs, const void *vct, EMsgVariableType type, case MVT_LLVector3d: if (n != 24) { - llerrs << "Size argument passed to htonmemcpy doesn't match swizzle type size" << llendl; + LL_ERRS() << "Size argument passed to htonmemcpy doesn't match swizzle type size" << LL_ENDL; } #ifdef LL_BIG_ENDIAN htonmemcpy(s + 16, ct + 16, MVT_F64, 8); @@ -974,7 +969,7 @@ static inline void *htonmemcpy(void *vs, const void *vct, EMsgVariableType type, case MVT_LLVector4: if (n != 16) { - llerrs << "Size argument passed to htonmemcpy doesn't match swizzle type size" << llendl; + LL_ERRS() << "Size argument passed to htonmemcpy doesn't match swizzle type size" << LL_ENDL; } #ifdef LL_BIG_ENDIAN htonmemcpy(s + 12, ct + 12, MVT_F32, 4); @@ -988,7 +983,7 @@ static inline void *htonmemcpy(void *vs, const void *vct, EMsgVariableType type, case MVT_U16Vec3: if (n != 6) { - llerrs << "Size argument passed to htonmemcpy doesn't match swizzle type size" << llendl; + LL_ERRS() << "Size argument passed to htonmemcpy doesn't match swizzle type size" << LL_ENDL; } #ifdef LL_BIG_ENDIAN htonmemcpy(s + 4, ct + 4, MVT_U16, 2); @@ -1001,7 +996,7 @@ static inline void *htonmemcpy(void *vs, const void *vct, EMsgVariableType type, case MVT_U16Quat: if (n != 8) { - llerrs << "Size argument passed to htonmemcpy doesn't match swizzle type size" << llendl; + LL_ERRS() << "Size argument passed to htonmemcpy doesn't match swizzle type size" << LL_ENDL; } #ifdef LL_BIG_ENDIAN htonmemcpy(s + 6, ct + 6, MVT_U16, 2); @@ -1015,7 +1010,7 @@ static inline void *htonmemcpy(void *vs, const void *vct, EMsgVariableType type, case MVT_S16Array: if (n % 2) { - llerrs << "Size argument passed to htonmemcpy doesn't match swizzle type size" << llendl; + LL_ERRS() << "Size argument passed to htonmemcpy doesn't match swizzle type size" << LL_ENDL; } #ifdef LL_BIG_ENDIAN length = n % 2; diff --git a/indra/llmessage/message_prehash.cpp b/indra/llmessage/message_prehash.cpp index e279f781d9..a9201ef466 100644 --- a/indra/llmessage/message_prehash.cpp +++ b/indra/llmessage/message_prehash.cpp @@ -37,8 +37,6 @@ F32 const gPrehashVersionNumber = 2.000f; char const* const _PREHASH_X = LLMessageStringTable::getInstance()->getString("X"); char const* const _PREHASH_Y = LLMessageStringTable::getInstance()->getString("Y"); char const* const _PREHASH_Z = LLMessageStringTable::getInstance()->getString("Z"); -char const* const _PREHASH_SizeX = LLMessageStringTable::getInstance()->getString("SizeX"); -char const* const _PREHASH_SizeY = LLMessageStringTable::getInstance()->getString("SizeY"); char const* const _PREHASH_AddFlags = LLMessageStringTable::getInstance()->getString("AddFlags"); char const* const _PREHASH_FailureInfo = LLMessageStringTable::getInstance()->getString("FailureInfo"); char const* const _PREHASH_MapData = LLMessageStringTable::getInstance()->getString("MapData"); @@ -620,6 +618,7 @@ char const* const _PREHASH_GroupAccountSummaryRequest = LLMessageStringTable::ge char const* const _PREHASH_GroupVoteHistoryRequest = LLMessageStringTable::getInstance()->getString("GroupVoteHistoryRequest"); char const* const _PREHASH_ParamValue = LLMessageStringTable::getInstance()->getString("ParamValue"); char const* const _PREHASH_MaxAgents = LLMessageStringTable::getInstance()->getString("MaxAgents"); +char const* const _PREHASH_HardMaxAgents = LLMessageStringTable::getInstance()->getString("HardMaxAgents"); char const* const _PREHASH_CreateNewOutfitAttachments = LLMessageStringTable::getInstance()->getString("CreateNewOutfitAttachments"); char const* const _PREHASH_RegionHandle = LLMessageStringTable::getInstance()->getString("RegionHandle"); char const* const _PREHASH_TeleportProgress = LLMessageStringTable::getInstance()->getString("TeleportProgress"); @@ -819,6 +818,7 @@ char const* const _PREHASH_StateSave = LLMessageStringTable::getInstance()->getS char const* const _PREHASH_RoleData = LLMessageStringTable::getInstance()->getString("RoleData"); char const* const _PREHASH_AgentAnimation = LLMessageStringTable::getInstance()->getString("AgentAnimation"); char const* const _PREHASH_AvatarAnimation = LLMessageStringTable::getInstance()->getString("AvatarAnimation"); +char const* const _PREHASH_ObjectAnimation = LLMessageStringTable::getInstance()->getString("ObjectAnimation"); char const* const _PREHASH_LogDwellTime = LLMessageStringTable::getInstance()->getString("LogDwellTime"); char const* const _PREHASH_ParcelGodMarkAsContent = LLMessageStringTable::getInstance()->getString("ParcelGodMarkAsContent"); char const* const _PREHASH_UsePhysics = LLMessageStringTable::getInstance()->getString("UsePhysics"); @@ -1375,6 +1375,11 @@ char const* const _PREHASH_OwnerMask = LLMessageStringTable::getInstance()->getS char const* const _PREHASH_TransferInventoryAck = LLMessageStringTable::getInstance()->getString("TransferInventoryAck"); char const* const _PREHASH_RegionDenyAgeUnverified = LLMessageStringTable::getInstance()->getString("RegionDenyAgeUnverified"); char const* const _PREHASH_AgeVerificationBlock = LLMessageStringTable::getInstance()->getString("AgeVerificationBlock"); +char const* const _PREHASH_RegionAllowAccessBlock = LLMessageStringTable::getInstance()->getString("RegionAllowAccessBlock"); +char const* const _PREHASH_RegionAllowAccessOverride = LLMessageStringTable::getInstance()->getString("RegionAllowAccessOverride"); +char const* const _PREHASH_ParcelEnvironmentBlock = LLMessageStringTable::getInstance()->getString("ParcelEnvironmentBlock"); +char const* const _PREHASH_ParcelEnvironmentVersion = LLMessageStringTable::getInstance()->getString("ParcelEnvironmentVersion"); +char const* const _PREHASH_RegionAllowEnvironmentOverride = LLMessageStringTable::getInstance()->getString("RegionAllowEnvironmentOverride"); char const* const _PREHASH_UCoord = LLMessageStringTable::getInstance()->getString("UCoord"); char const* const _PREHASH_VCoord = LLMessageStringTable::getInstance()->getString("VCoord"); char const* const _PREHASH_FaceIndex = LLMessageStringTable::getInstance()->getString("FaceIndex"); @@ -1386,3 +1391,14 @@ char const* const _PREHASH_GroupAVSounds = LLMessageStringTable::getInstance()-> char const* const _PREHASH_AppearanceData = LLMessageStringTable::getInstance()->getString("AppearanceData"); char const* const _PREHASH_AppearanceVersion = LLMessageStringTable::getInstance()->getString("AppearanceVersion"); char const* const _PREHASH_CofVersion = LLMessageStringTable::getInstance()->getString("CofVersion"); +char const* const _PREHASH_AppearanceHover = LLMessageStringTable::getInstance()->getString("AppearanceHover"); +char const* const _PREHASH_HoverHeight = LLMessageStringTable::getInstance()->getString("HoverHeight"); +char const* const _PREHASH_Experience = LLMessageStringTable::getInstance()->getString("Experience"); +char const* const _PREHASH_ExperienceID = LLMessageStringTable::getInstance()->getString("ExperienceID"); + +// Aurora Sim +char const* const _PREHASH_RegionSizeX = LLMessageStringTable::getInstance()->getString("RegionSizeX"); +char const* const _PREHASH_RegionSizeY = LLMessageStringTable::getInstance()->getString("RegionSizeY"); +char const* const _PREHASH_SizeX = LLMessageStringTable::getInstance()->getString("SizeX"); +char const* const _PREHASH_SizeY = LLMessageStringTable::getInstance()->getString("SizeY"); +// Aurora Sim diff --git a/indra/llmessage/message_prehash.h b/indra/llmessage/message_prehash.h index 1c1d6e2246..390ea8ff7e 100644 --- a/indra/llmessage/message_prehash.h +++ b/indra/llmessage/message_prehash.h @@ -37,8 +37,6 @@ extern F32 const gPrehashVersionNumber; extern char const* const _PREHASH_X; extern char const* const _PREHASH_Y; extern char const* const _PREHASH_Z; -extern char const* const _PREHASH_SizeX; -extern char const* const _PREHASH_SizeY; extern char const* const _PREHASH_AddFlags; extern char const* const _PREHASH_FailureInfo; extern char const* const _PREHASH_MapData; @@ -620,6 +618,7 @@ extern char const* const _PREHASH_GroupAccountSummaryRequest; extern char const* const _PREHASH_GroupVoteHistoryRequest; extern char const* const _PREHASH_ParamValue; extern char const* const _PREHASH_MaxAgents; +extern char const* const _PREHASH_HardMaxAgents; extern char const* const _PREHASH_CreateNewOutfitAttachments; extern char const* const _PREHASH_RegionHandle; extern char const* const _PREHASH_TeleportProgress; @@ -819,6 +818,7 @@ extern char const* const _PREHASH_StateSave; extern char const* const _PREHASH_RoleData; extern char const* const _PREHASH_AgentAnimation; extern char const* const _PREHASH_AvatarAnimation; +extern char const* const _PREHASH_ObjectAnimation; extern char const* const _PREHASH_LogDwellTime; extern char const* const _PREHASH_ParcelGodMarkAsContent; extern char const* const _PREHASH_UsePhysics; @@ -1375,6 +1375,11 @@ extern char const* const _PREHASH_OwnerMask; extern char const* const _PREHASH_TransferInventoryAck; extern char const* const _PREHASH_RegionDenyAgeUnverified; extern char const* const _PREHASH_AgeVerificationBlock; +extern char const* const _PREHASH_RegionAllowAccessBlock; +extern char const* const _PREHASH_RegionAllowAccessOverride; +extern char const* const _PREHASH_ParcelEnvironmentBlock; +extern char const* const _PREHASH_ParcelEnvironmentVersion; +extern char const* const _PREHASH_RegionAllowEnvironmentOverride; extern char const* const _PREHASH_UCoord; extern char const* const _PREHASH_VCoord; extern char const* const _PREHASH_FaceIndex; @@ -1386,4 +1391,15 @@ extern char const* const _PREHASH_GroupAVSounds; extern char const* const _PREHASH_AppearanceData; extern char const* const _PREHASH_AppearanceVersion; extern char const* const _PREHASH_CofVersion; +extern char const* const _PREHASH_AppearanceHover; +extern char const* const _PREHASH_HoverHeight; +extern char const* const _PREHASH_Experience; +extern char const* const _PREHASH_ExperienceID; + +// Aurora Sim +extern char const* const _PREHASH_RegionSizeX; +extern char const* const _PREHASH_RegionSizeY; +extern char const* const _PREHASH_SizeX; +extern char const* const _PREHASH_SizeY; +// Aurora Sim #endif diff --git a/indra/llmessage/message_string_table.cpp b/indra/llmessage/message_string_table.cpp index dd063fcb83..e4f5fb3a38 100644 --- a/indra/llmessage/message_string_table.cpp +++ b/indra/llmessage/message_string_table.cpp @@ -80,10 +80,10 @@ char* LLMessageStringTable::getString(const char *str) if (mUsed >= MESSAGE_NUMBER_OF_HASH_BUCKETS - 1) { U32 i; - llinfos << "Dumping string table before crashing on HashTable full!" << llendl; + LL_INFOS() << "Dumping string table before crashing on HashTable full!" << LL_ENDL; for (i = 0; i < MESSAGE_NUMBER_OF_HASH_BUCKETS; i++) { - llinfos << "Entry #" << i << ": " << mString[i] << llendl; + LL_INFOS() << "Entry #" << i << ": " << mString[i] << LL_ENDL; } } return mString[hash_value]; diff --git a/indra/llmessage/net.cpp b/indra/llmessage/net.cpp index 6e232aa248..523bcbb60d 100644 --- a/indra/llmessage/net.cpp +++ b/indra/llmessage/net.cpp @@ -26,17 +26,14 @@ #include "linden_common.h" -#include "net.h" +//#include "net.h" // system library includes #include #if LL_WINDOWS - #define WIN32_LEAN_AND_MEAN - #include - #include +#include "llwin32headerslean.h" #else - #include #include #include #include @@ -176,7 +173,7 @@ U32 ip_string_to_u32(const char* ip_string) if (ip == INADDR_NONE && strncmp(ip_string, BROADCAST_ADDRESS_STRING, MAXADDRSTR) != 0) { - llwarns << "ip_string_to_u32() failed, Error: Invalid IP string '" << ip_string << "'" << llendl; + LL_WARNS() << "ip_string_to_u32() failed, Error: Invalid IP string '" << ip_string << "'" << LL_ENDL; return INVALID_HOST_IP_ADDRESS; } return ip; @@ -335,7 +332,7 @@ S32 receive_packet(int hSocket, char * receiveBuffer) return 0; if (WSAECONNRESET == WSAGetLastError()) return 0; - llinfos << "receivePacket() failed, Error: " << WSAGetLastError() << llendl; + LL_INFOS() << "receivePacket() failed, Error: " << WSAGetLastError() << LL_ENDL; } return nRet; @@ -369,8 +366,8 @@ BOOL send_packet(int hSocket, const char *sendBuffer, int size, U32 recipient, i { return TRUE; } - llinfos << "sendto() failed to " << u32_to_ip_string(recipient) << ":" << nPort - << ", Error " << last_error << llendl; + LL_INFOS() << "sendto() failed to " << u32_to_ip_string(recipient) << ":" << nPort + << ", Error " << last_error << LL_ENDL; } } } while ( (nRet == SOCKET_ERROR) @@ -398,7 +395,7 @@ S32 start_net(S32& socket_out, int& nPort) hSocket = socket(AF_INET, SOCK_DGRAM, 0); if (hSocket < 0) { - llwarns << "socket() failed" << llendl; + LL_WARNS() << "socket() failed" << LL_ENDL; return 1; } @@ -409,21 +406,21 @@ S32 start_net(S32& socket_out, int& nPort) stLclAddr.sin_family = AF_INET; stLclAddr.sin_addr.s_addr = htonl(INADDR_ANY); stLclAddr.sin_port = htons(0); - llinfos << "attempting to connect on OS assigned port" << llendl; + LL_INFOS() << "attempting to connect on OS assigned port" << LL_ENDL; nRet = bind(hSocket, (struct sockaddr*) &stLclAddr, sizeof(stLclAddr)); if (nRet < 0) { - llwarns << "Failed to bind on an OS assigned port error: " - << nRet << llendl; + LL_WARNS() << "Failed to bind on an OS assigned port error: " + << nRet << LL_ENDL; } else { sockaddr_in socket_info; socklen_t len = sizeof(sockaddr_in); int err = getsockname(hSocket, (sockaddr*)&socket_info, &len); - llinfos << "Get socket returned: " << err << " length " << len << llendl; + LL_INFOS() << "Get socket returned: " << err << " length " << len << LL_ENDL; nPort = ntohs(socket_info.sin_port); - llinfos << "Assigned port: " << nPort << llendl; + LL_INFOS() << "Assigned port: " << nPort << LL_ENDL; } } @@ -434,7 +431,7 @@ S32 start_net(S32& socket_out, int& nPort) stLclAddr.sin_addr.s_addr = htonl(INADDR_ANY); stLclAddr.sin_port = htons(nPort); U32 attempt_port = nPort; - llinfos << "attempting to connect on port " << attempt_port << llendl; + LL_INFOS() << "attempting to connect on port " << attempt_port << LL_ENDL; nRet = bind(hSocket, (struct sockaddr*) &stLclAddr, sizeof(stLclAddr)); if (nRet < 0) @@ -448,7 +445,7 @@ S32 start_net(S32& socket_out, int& nPort) attempt_port++) { stLclAddr.sin_port = htons(attempt_port); - llinfos << "trying port " << attempt_port << llendl; + LL_INFOS() << "trying port " << attempt_port << LL_ENDL; nRet = bind(hSocket, (struct sockaddr*) &stLclAddr, sizeof(stLclAddr)); if (!((nRet < 0) && (errno == EADDRINUSE))) { @@ -457,7 +454,7 @@ S32 start_net(S32& socket_out, int& nPort) } if (nRet < 0) { - llwarns << "startNet() : Couldn't find available network port." << llendl; + LL_WARNS() << "startNet() : Couldn't find available network port." << LL_ENDL; // Fail gracefully in release. return 3; } @@ -465,12 +462,12 @@ S32 start_net(S32& socket_out, int& nPort) // Some other socket error else { - llwarns << llformat ("bind() port: %d failed, Err: %s\n", nPort, strerror(errno)) << llendl; + LL_WARNS() << llformat ("bind() port: %d failed, Err: %s\n", nPort, strerror(errno)) << LL_ENDL; // Fail gracefully in release. return 4; } } - llinfos << "connected on port " << attempt_port << llendl; + LL_INFOS() << "connected on port " << attempt_port << LL_ENDL; nPort = attempt_port; } // Set socket to be non-blocking @@ -479,18 +476,18 @@ S32 start_net(S32& socket_out, int& nPort) nRet = setsockopt(hSocket, SOL_SOCKET, SO_RCVBUF, (char *)&rec_size, buff_size); if (nRet) { - llinfos << "Can't set receive size!" << llendl; + LL_INFOS() << "Can't set receive size!" << LL_ENDL; } nRet = setsockopt(hSocket, SOL_SOCKET, SO_SNDBUF, (char *)&snd_size, buff_size); if (nRet) { - llinfos << "Can't set send size!" << llendl; + LL_INFOS() << "Can't set send size!" << LL_ENDL; } getsockopt(hSocket, SOL_SOCKET, SO_RCVBUF, (char *)&rec_size, &buff_size); getsockopt(hSocket, SOL_SOCKET, SO_SNDBUF, (char *)&snd_size, &buff_size); - llinfos << "startNet - receive buffer size : " << rec_size << llendl; - llinfos << "startNet - send buffer size : " << snd_size << llendl; + LL_INFOS() << "startNet - receive buffer size : " << rec_size << LL_ENDL; + LL_INFOS() << "startNet - send buffer size : " << snd_size << LL_ENDL; #if LL_LINUX // Turn on recipient address tracking @@ -498,11 +495,11 @@ S32 start_net(S32& socket_out, int& nPort) int use_pktinfo = 1; if( setsockopt( hSocket, SOL_IP, IP_PKTINFO, &use_pktinfo, sizeof(use_pktinfo) ) == -1 ) { - llwarns << "No IP_PKTINFO available" << llendl; + LL_WARNS() << "No IP_PKTINFO available" << LL_ENDL; } else { - llinfos << "IP_PKKTINFO enabled" << llendl; + LL_INFOS() << "IP_PKKTINFO enabled" << LL_ENDL; } } #endif @@ -596,7 +593,7 @@ int receive_packet(int hSocket, char * receiveBuffer) } // Uncomment for testing if/when implementing for Mac or Windows: - // llinfos << "Received datagram to in addr " << u32_to_ip_string(get_receiving_interface_ip()) << llendl; + // LL_INFOS() << "Received datagram to in addr " << u32_to_ip_string(get_receiving_interface_ip()) << LL_ENDL; return nRet; } @@ -630,22 +627,22 @@ BOOL send_packet(int hSocket, const char * sendBuffer, int size, U32 recipient, if (errno == EAGAIN) { // say nothing, just repeat send - llinfos << "sendto() reported buffer full, resending (attempt " << send_attempts << ")" << llendl; - llinfos << inet_ntoa(stDstAddr.sin_addr) << ":" << nPort << llendl; + LL_INFOS() << "sendto() reported buffer full, resending (attempt " << send_attempts << ")" << LL_ENDL; + LL_INFOS() << inet_ntoa(stDstAddr.sin_addr) << ":" << nPort << LL_ENDL; resend = TRUE; } else if (errno == ECONNREFUSED) { // response to ICMP connection refused message on earlier send - llinfos << "sendto() reported connection refused, resending (attempt " << send_attempts << ")" << llendl; - llinfos << inet_ntoa(stDstAddr.sin_addr) << ":" << nPort << llendl; + LL_INFOS() << "sendto() reported connection refused, resending (attempt " << send_attempts << ")" << LL_ENDL; + LL_INFOS() << inet_ntoa(stDstAddr.sin_addr) << ":" << nPort << LL_ENDL; resend = TRUE; } else { // some other error - llinfos << "sendto() failed: " << errno << ", " << strerror(errno) << llendl; - llinfos << inet_ntoa(stDstAddr.sin_addr) << ":" << nPort << llendl; + LL_INFOS() << "sendto() failed: " << errno << ", " << strerror(errno) << LL_ENDL; + LL_INFOS() << inet_ntoa(stDstAddr.sin_addr) << ":" << nPort << LL_ENDL; resend = FALSE; } } @@ -654,7 +651,7 @@ BOOL send_packet(int hSocket, const char * sendBuffer, int size, U32 recipient, if (send_attempts >= 3) { - llinfos << "sendPacket() bailed out of send!" << llendl; + LL_INFOS() << "sendPacket() bailed out of send!" << LL_ENDL; return FALSE; } diff --git a/indra/llmessage/net.h b/indra/llmessage/net.h index 0f2437479d..beb67bae4e 100644 --- a/indra/llmessage/net.h +++ b/indra/llmessage/net.h @@ -67,5 +67,8 @@ const S32 ETHERNET_MTU_BYTES = 1500; const S32 MTUBITS = MTUBYTES*8; const S32 MTUU32S = MTUBITS/32; +// For automatic port discovery when running multiple viewers on one host +const U32 PORT_DISCOVERY_RANGE_MIN = 13000; +const U32 PORT_DISCOVERY_RANGE_MAX = PORT_DISCOVERY_RANGE_MIN + 50; #endif diff --git a/indra/llmessage/partsyspacket.cpp b/indra/llmessage/partsyspacket.cpp index ad21614258..4871e0d954 100644 --- a/indra/llmessage/partsyspacket.cpp +++ b/indra/llmessage/partsyspacket.cpp @@ -1272,7 +1272,7 @@ BOOL LLPartSysCompressedPacket::fromUnsignedBytes(U8 *in, U32 bytesUsed) } else { - llerrs << "NULL input data or number of bytes exceed mData size" << llendl; + LL_ERRS() << "NULL input data or number of bytes exceed mData size" << LL_ENDL; return FALSE; } } diff --git a/indra/llmessage/patch_code.cpp b/indra/llmessage/patch_code.cpp index e5d7f19448..5047b5e79d 100644 --- a/indra/llmessage/patch_code.cpp +++ b/indra/llmessage/patch_code.cpp @@ -88,7 +88,7 @@ void code_patch_header(LLBitPack &bitpack, LLPatchHeader *ph, S32 *patch) if ( (wbits > 17) ||(wbits < 2)) { - llerrs << "Bits needed per word in code_patch_header out of legal range. Adjust compression quatization." << llendl; + LL_ERRS() << "Bits needed per word in code_patch_header out of legal range. Adjust compression quatization." << LL_ENDL; } ph->quant_wbits |= (wbits - 2); @@ -135,7 +135,7 @@ void code_patch(LLBitPack &bitpack, S32 *patch, S32 postquant) if ( (postquant > patch_size*patch_size) ||(postquant < 0)) { - llerrs << "Bad postquant in code_patch!" << llendl; + LL_ERRS() << "Bad postquant in code_patch!" << LL_ENDL; } if (postquant) @@ -229,7 +229,10 @@ void decode_patch_group_header(LLBitPack &bitpack, LLGroupHeader *gopp) gPatchSize = gopp->patch_size; } -void decode_patch_header(LLBitPack &bitpack, LLPatchHeader *ph) +// Aurora Sim +//void decode_patch_header(LLBitPack &bitpack, LLPatchHeader *ph) +void decode_patch_header(LLBitPack &bitpack, LLPatchHeader *ph, bool b_large_patch) +// Aurora Sim { U8 retvalu8; @@ -268,15 +271,33 @@ void decode_patch_header(LLBitPack &bitpack, LLPatchHeader *ph) #endif ph->range = retvalu16; - retvalu16 = 0; +// Aurora Sim + //retvalu16 = 0; + retvalu32 = 0; #ifdef LL_BIG_ENDIAN - ret = (U8 *)&retvalu16; - bitpack.bitUnpack(&(ret[1]), 8); - bitpack.bitUnpack(&(ret[0]), 2); + //ret = (U8 *)&retvalu16; + ret = (U8*)&retvalu32; +// Aurora Sim + if (b_large_patch) + { + bitpack.bitUnpack(&(ret[3]), 8); + bitpack.bitUnpack(&(ret[2]), 8); + bitpack.bitUnpack(&(ret[1]), 8); + bitpack.bitUnpack(&(ret[0]), 8); + } + else + { + bitpack.bitUnpack(&(ret[1]), 8); + bitpack.bitUnpack(&(ret[0]), 2); + } #else - bitpack.bitUnpack((U8 *)&retvalu16, 10); +// Aurora Sim + //bitpack.bitUnpack((U8 *)&retvalu16, 10); + bitpack.bitUnpack((U8*)&retvalu32, b_large_patch ? 32 : 10); #endif - ph->patchids = retvalu16; + //ph->patchids = retvalu16; + ph->patchids = retvalu32; +// Aurora Sim gWordBits = (ph->quant_wbits & 0xf) + 2; } diff --git a/indra/llmessage/patch_code.h b/indra/llmessage/patch_code.h index 4c87c9808a..a3361daf34 100644 --- a/indra/llmessage/patch_code.h +++ b/indra/llmessage/patch_code.h @@ -40,7 +40,10 @@ void end_patch_coding(LLBitPack &bitpack); void init_patch_decoding(LLBitPack &bitpack); void decode_patch_group_header(LLBitPack &bitpack, LLGroupHeader *gopp); -void decode_patch_header(LLBitPack &bitpack, LLPatchHeader *ph); +// Aurora Sim +//void decode_patch_header(LLBitPack &bitpack, LLPatchHeader *ph); +void decode_patch_header(LLBitPack &bitpack, LLPatchHeader *ph, bool b_large_patch = false); +// Aurora Sim void decode_patch(LLBitPack &bitpack, S32 *patches); #endif diff --git a/indra/llmessage/patch_dct.h b/indra/llmessage/patch_dct.h index 101231ec84..d9c3ec7a53 100644 --- a/indra/llmessage/patch_dct.h +++ b/indra/llmessage/patch_dct.h @@ -73,7 +73,10 @@ class LLPatchHeader F32 dc_offset; // 4 bytes U16 range; // 2 = 7 ((S16) FP range (breaks if we need > 32K meters in 1 patch) U8 quant_wbits; // 1 = 8 (upper 4 bits is quant - 2, lower 4 bits is word bits - 2) - U16 patchids; // 2 = 10 (actually only uses 10 bits, 5 for each) +// Aurora Sim + //U16 patchids; // 2 = 10 (actually only uses 10 bits, 5 for each) + U32 patchids; +// Aurora Sim }; // Compression routines diff --git a/indra/llmessage/tests/llmime_test.cpp b/indra/llmessage/tests/llmime_test.cpp deleted file mode 100644 index aed5c4589c..0000000000 --- a/indra/llmessage/tests/llmime_test.cpp +++ /dev/null @@ -1,445 +0,0 @@ -/** - * @file llmime_test.cpp - * @author Phoenix - * @date 2006-12-24 - * @brief BRIEF_DESC of llmime_test.cpp - * - * $LicenseInfo:firstyear=2006&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include "llsdserialize.h" - -#include "../llmime.h" - -#include "../test/lltut.h" - -namespace tut -{ - struct mime_index - { - }; - typedef test_group mime_index_t; - typedef mime_index_t::object mime_index_object_t; - tut::mime_index_t tut_mime_index("LLMime"); - - template<> template<> - void mime_index_object_t::test<1>() - { - LLMimeIndex mime; - ensure("no headers", mime.headers().isUndefined()); - ensure_equals("invalid offset", mime.offset(), -1); - ensure_equals("invalid content length", mime.contentLength(), -1); - ensure("no content type", mime.contentType().empty()); - ensure("not multipart", !mime.isMultipart()); - ensure_equals("no attachments", mime.subPartCount(), 0); - } - - template<> template<> - void mime_index_object_t::test<2>() - { - const S32 CONTENT_LENGTH = 6000; - const S32 CONTENT_OFFSET = 100; - const std::string CONTENT_TYPE = std::string("image/j2c"); - LLSD headers; - headers["Content-Length"] = CONTENT_LENGTH; - headers["Content-Type"] = CONTENT_TYPE; - LLMimeIndex mime(headers, CONTENT_OFFSET); - ensure("headers are map", mime.headers().isMap()); - ensure_equals("offset", mime.offset(), CONTENT_OFFSET); - ensure_equals("content length", mime.contentLength(), CONTENT_LENGTH); - ensure_equals("type is image/j2c", mime.contentType(), CONTENT_TYPE); - ensure("not multipart", !mime.isMultipart()); - ensure_equals("no attachments", mime.subPartCount(), 0); - } - - template<> template<> - void mime_index_object_t::test<3>() - { - const S32 MULTI_CONTENT_LENGTH = 8000; - const S32 MULTI_CONTENT_OFFSET = 100; - const std::string MULTI_CONTENT_TYPE = std::string("multipart/mixed"); - LLSD headers; - headers["Content-Length"] = MULTI_CONTENT_LENGTH; - headers["Content-Type"] = MULTI_CONTENT_TYPE; - LLMimeIndex mime(headers, MULTI_CONTENT_OFFSET); - llinfos << "headers: " << LLSDOStreamer(headers) - << llendl; - - - const S32 META_CONTENT_LENGTH = 700; - const S32 META_CONTENT_OFFSET = 69; - const std::string META_CONTENT_TYPE = std::string( - "text/llsd+xml"); - headers = LLSD::emptyMap(); - headers["Content-Length"] = META_CONTENT_LENGTH; - headers["Content-Type"] = META_CONTENT_TYPE; - LLMimeIndex meta(headers, META_CONTENT_OFFSET); - mime.attachSubPart(meta); - - const S32 IMAGE_CONTENT_LENGTH = 6000; - const S32 IMAGE_CONTENT_OFFSET = 200; - const std::string IMAGE_CONTENT_TYPE = std::string("image/j2c"); - headers = LLSD::emptyMap(); - headers["Content-Length"] = IMAGE_CONTENT_LENGTH; - headers["Content-Type"] = IMAGE_CONTENT_TYPE; - LLMimeIndex image(headers, IMAGE_CONTENT_OFFSET); - mime.attachSubPart(image); - - // make sure we have a valid multi-part - ensure("is multipart", mime.isMultipart()); - ensure_equals("multi offset", mime.offset(), MULTI_CONTENT_OFFSET); - ensure_equals( - "multi content length", - mime.contentLength(), - MULTI_CONTENT_LENGTH); - ensure_equals("two attachments", mime.subPartCount(), 2); - - // make sure ranged gets do the right thing with out of bounds - // sub-parts. - LLMimeIndex invalid_child(mime.subPart(-1)); - ensure("no headers", invalid_child.headers().isUndefined()); - ensure_equals("invalid offset", invalid_child.offset(), -1); - ensure_equals( - "invalid content length", invalid_child.contentLength(), -1); - ensure("no content type", invalid_child.contentType().empty()); - ensure("not multipart", !invalid_child.isMultipart()); - ensure_equals("no attachments", invalid_child.subPartCount(), 0); - - invalid_child = mime.subPart(2); - ensure("no headers", invalid_child.headers().isUndefined()); - ensure_equals("invalid offset", invalid_child.offset(), -1); - ensure_equals( - "invalid content length", invalid_child.contentLength(), -1); - ensure("no content type", invalid_child.contentType().empty()); - ensure("not multipart", !invalid_child.isMultipart()); - ensure_equals("no attachments", invalid_child.subPartCount(), 0); - } - - template<> template<> - void mime_index_object_t::test<4>() - { - const S32 MULTI_CONTENT_LENGTH = 8000; - const S32 MULTI_CONTENT_OFFSET = 100; - const std::string MULTI_CONTENT_TYPE = std::string("multipart/mixed"); - LLSD headers; - headers["Content-Length"] = MULTI_CONTENT_LENGTH; - headers["Content-Type"] = MULTI_CONTENT_TYPE; - LLMimeIndex mime(headers, MULTI_CONTENT_OFFSET); - - const S32 META_CONTENT_LENGTH = 700; - const S32 META_CONTENT_OFFSET = 69; - const std::string META_CONTENT_TYPE = std::string( - "application/llsd+xml"); - headers = LLSD::emptyMap(); - headers["Content-Length"] = META_CONTENT_LENGTH; - headers["Content-Type"] = META_CONTENT_TYPE; - LLMimeIndex meta(headers, META_CONTENT_OFFSET); - mime.attachSubPart(meta); - - const S32 IMAGE_CONTENT_LENGTH = 6000; - const S32 IMAGE_CONTENT_OFFSET = 200; - const std::string IMAGE_CONTENT_TYPE = std::string("image/j2c"); - headers = LLSD::emptyMap(); - headers["Content-Length"] = IMAGE_CONTENT_LENGTH; - headers["Content-Type"] = IMAGE_CONTENT_TYPE; - LLMimeIndex image(headers, IMAGE_CONTENT_OFFSET); - mime.attachSubPart(image); - - // check what we have - ensure("is multipart", mime.isMultipart()); - ensure_equals("multi offset", mime.offset(), MULTI_CONTENT_OFFSET); - ensure_equals( - "multi content length", - mime.contentLength(), - MULTI_CONTENT_LENGTH); - ensure_equals("two attachments", mime.subPartCount(), 2); - - LLMimeIndex actual_meta = mime.subPart(0); - ensure_equals( - "meta type", actual_meta.contentType(), META_CONTENT_TYPE); - ensure_equals( - "meta offset", actual_meta.offset(), META_CONTENT_OFFSET); - ensure_equals( - "meta content length", - actual_meta.contentLength(), - META_CONTENT_LENGTH); - - LLMimeIndex actual_image = mime.subPart(1); - ensure_equals( - "image type", actual_image.contentType(), IMAGE_CONTENT_TYPE); - ensure_equals( - "image offset", actual_image.offset(), IMAGE_CONTENT_OFFSET); - ensure_equals( - "image content length", - actual_image.contentLength(), - IMAGE_CONTENT_LENGTH); - } - -/* - template<> template<> - void mime_index_object_t::test<5>() - { - } - template<> template<> - void mime_index_object_t::test<6>() - { - } - template<> template<> - void mime_index_object_t::test<7>() - { - } - template<> template<> - void mime_index_object_t::test<8>() - { - } - template<> template<> - void mime_index_object_t::test<>() - { - } -*/ -} - - -namespace tut -{ - struct mime_parse - { - }; - typedef test_group mime_parse_t; - typedef mime_parse_t::object mime_parse_object_t; - tut::mime_parse_t tut_mime_parse("LLMimeParse"); - - template<> template<> - void mime_parse_object_t::test<1>() - { - // parse one mime object - const std::string SERIALIZED_MIME("Content-Length: 200\r\nContent-Type: text/plain\r\n\r\naaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccc\r\n"); - std::stringstream istr; - istr.str(SERIALIZED_MIME); - LLMimeIndex mime; - LLMimeParser parser; - bool ok = parser.parseIndex(istr, mime); - ensure("Parse successful.", ok); - ensure_equals("content type", mime.contentType(), "text/plain"); - ensure_equals("content length", mime.contentLength(), 200); - ensure_equals("offset", mime.offset(), 49); - } - - template<> template<> - void mime_parse_object_t::test<2>() - { - // make sure we only parse one. - const std::string SERIALIZED_MIME("Content-Length: 200\r\nContent-Type: text/plain\r\n\r\naaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccc\r\n\r\nContent-Length: 200\r\nContent-Type: text/plain\r\n\r\naaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccc\r\n\r\n"); - std::stringstream istr; - istr.str(SERIALIZED_MIME); - LLMimeIndex mime; - LLMimeParser parser; - bool ok = parser.parseIndex(istr, mime); - ensure("Parse successful.", ok); - ensure("not multipart.", !mime.isMultipart()); - ensure_equals("content type", mime.contentType(), "text/plain"); - ensure_equals("content length", mime.contentLength(), 200); - ensure_equals("offset", mime.offset(), 49); - } - - template<> template<> - void mime_parse_object_t::test<3>() - { - // test multi-part and lack of content length for some of it. - /* -Content-Type: multipart/mixed; boundary="segment"rnContent-Length: 148rnrn--segmentrnContent-Type: text/plainrnrnsome datarnrn--segmentrnContent-Type: text/xml; charset=UTF-8rnContent-Length: 22rnrnrnrn - */ - const std::string SERIALIZED_MIME("Content-Type: multipart/mixed; boundary=\"segment\"\r\nContent-Length: 150\r\n\r\n--segment\r\nContent-Type: text/plain\r\n\r\nsome data\r\n\r\n--segment\r\nContent-Type: text/xml; charset=UTF-8\r\nContent-Length: 22\r\n\r\n\r\n\r\n"); - std::stringstream istr; - istr.str(SERIALIZED_MIME); - LLMimeIndex mime; - LLMimeParser parser; - bool ok = parser.parseIndex(istr, mime); - ensure("Parse successful.", ok); - ensure("is multipart.", mime.isMultipart()); - ensure_equals("sub-part count", mime.subPartCount(), 2); - ensure_equals("content length", mime.contentLength(), 150); - ensure_equals("data offset for multipart", mime.offset(), 74); - - LLMimeIndex mime_plain(mime.subPart(0)); - ensure_equals( - "first part type", - mime_plain.contentType(), - "text/plain"); - ensure_equals( - "first part content length not known.", - mime_plain.contentLength(), - -1); - ensure_equals("first part offset", mime_plain.offset(), 113); - - LLMimeIndex mime_xml(mime.subPart(1)); - ensure_equals( - "second part type", - mime_xml.contentType(), - "text/xml; charset=UTF-8"); - ensure_equals( - "second part content length", - mime_xml.contentLength(), - 22); - ensure_equals("second part offset", mime_xml.offset(), 198); - } - - template<> template<> - void mime_parse_object_t::test<4>() - { - // test multi-part, unquoted separator, and premature eof conditions - /* -Content-Type: multipart/mixed; boundary=segmentrnContent-Length: 220rnrn--segmentrnContent-Type: text/plainrnContent-Length: 55rnrnhow are you today?rnI do not know. I guess I am:n'fine'rnrn--segmentrnContent-Type: text/xml; charset=UTF-8rnContent-Length: 22rnrnrnrn */ - const std::string SERIALIZED_MIME("Content-Type: multipart/mixed; boundary=segment\r\nContent-Length: 220\r\n\r\n--segment\r\nContent-Type: text/plain\r\nContent-Length: 55\r\n\r\nhow are you today?\r\nI do not know. I guess I am:\n'fine'\r\n\r\n--segment\r\nContent-Type: text/xml; charset=UTF-8\r\nContent-Length: 22\r\n\r\n\r\n\r\n"); - std::stringstream istr; - istr.str(SERIALIZED_MIME); - LLMimeIndex mime; - LLMimeParser parser; - bool ok = parser.parseIndex(istr, mime); - ensure("Parse successful.", ok); - ensure("is multipart.", mime.isMultipart()); - ensure_equals("sub-part count", mime.subPartCount(), 2); - ensure_equals("content length", mime.contentLength(), 220); - ensure_equals("data offset for multipart", mime.offset(), 72); - - LLMimeIndex mime_plain(mime.subPart(0)); - ensure_equals( - "first part type", - mime_plain.contentType(), - "text/plain"); - ensure_equals( - "first part content length", - mime_plain.contentLength(), - 55); - ensure_equals("first part offset", mime_plain.offset(), 131); - - LLMimeIndex mime_xml(mime.subPart(1)); - ensure_equals( - "second part type", - mime_xml.contentType(), - "text/xml; charset=UTF-8"); - ensure_equals( - "second part content length", - mime_xml.contentLength(), - 22); - ensure_equals("second part offset", mime_xml.offset(), 262); - } - - template<> template<> - void mime_parse_object_t::test<5>() - { - // test multi-part with multiple params - const std::string SERIALIZED_MIME("Content-Type: multipart/mixed; boundary=segment; comment=\"testing multiple params.\"\r\nContent-Length: 220\r\n\r\n--segment\r\nContent-Type: text/plain\r\nContent-Length: 55\r\n\r\nhow are you today?\r\nI do not know. I guess I am:\n'fine'\r\n\r\n--segment\r\nContent-Type: text/xml; charset=UTF-8\r\nContent-Length: 22\r\n\r\n\r\n\r\n"); - std::stringstream istr; - istr.str(SERIALIZED_MIME); - LLMimeIndex mime; - LLMimeParser parser; - bool ok = parser.parseIndex(istr, mime); - ensure("Parse successful.", ok); - ensure("is multipart.", mime.isMultipart()); - ensure_equals("sub-part count", mime.subPartCount(), 2); - ensure_equals("content length", mime.contentLength(), 220); - - LLMimeIndex mime_plain(mime.subPart(0)); - ensure_equals( - "first part type", - mime_plain.contentType(), - "text/plain"); - ensure_equals( - "first part content length", - mime_plain.contentLength(), - 55); - - LLMimeIndex mime_xml(mime.subPart(1)); - ensure_equals( - "second part type", - mime_xml.contentType(), - "text/xml; charset=UTF-8"); - ensure_equals( - "second part content length", - mime_xml.contentLength(), - 22); - } - - template<> template<> - void mime_parse_object_t::test<6>() - { - // test multi-part with no specified boundary and eof -/* -Content-Type: multipart/relatedrnContent-Length: 220rnrn--rnContent-Type: text/plainrnContent-Length: 55rnrnhow are you today?rnI do not know. I guess I am:n'fine'rnrn--rnContent-Type: text/xml; charset=UTF-8rnContent-Length: 22rnrnrnrn -*/ - const std::string SERIALIZED_MIME("Content-Type: multipart/related\r\nContent-Length: 500\r\n\r\n--\r\nContent-Type: text/plain\r\nContent-Length: 55\r\n\r\nhow are you today?\r\nI do not know. I guess I am:\n'fine'\r\n\r\n--\r\nContent-Type: text/xml; charset=UTF-8\r\nContent-Length: 22\r\n\r\n\r\n\r\n"); - std::stringstream istr; - istr.str(SERIALIZED_MIME); - LLMimeIndex mime; - LLMimeParser parser; - bool ok = parser.parseIndex(istr, mime); - ensure("Parse successful.", ok); - ensure("is multipart.", mime.isMultipart()); - ensure_equals("sub-part count", mime.subPartCount(), 2); - ensure_equals("content length", mime.contentLength(), 500); - ensure_equals("data offset for multipart", mime.offset(), 56); - - LLMimeIndex mime_plain(mime.subPart(0)); - ensure_equals( - "first part type", - mime_plain.contentType(), - "text/plain"); - ensure_equals( - "first part content length", - mime_plain.contentLength(), - 55); - ensure_equals("first part offset", mime_plain.offset(), 108); - - LLMimeIndex mime_xml(mime.subPart(1)); - ensure_equals( - "second part type", - mime_xml.contentType(), - "text/xml; charset=UTF-8"); - ensure_equals( - "second part content length", - mime_xml.contentLength(), - 22); - ensure_equals("second part offset", mime_xml.offset(), 232); - } - -/* - template<> template<> - void mime_parse_object_t::test<>() - { - } - template<> template<> - void mime_parse_object_t::test<>() - { - } - template<> template<> - void mime_parse_object_t::test<>() - { - } - template<> template<> - void mime_parse_object_t::test<>() - { - } -*/ -} diff --git a/indra/llmessage/tests/test_llsdmessage_peer.py b/indra/llmessage/tests/test_llsdmessage_peer.py index 22edd9dad8..a81399a331 100644 --- a/indra/llmessage/tests/test_llsdmessage_peer.py +++ b/indra/llmessage/tests/test_llsdmessage_peer.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 """\ @file test_llsdmessage_peer.py @author Nat Goodspeed diff --git a/indra/llmessage/tests/testrunner.py b/indra/llmessage/tests/testrunner.py index f2c841532a..4c89b11b56 100644 --- a/indra/llmessage/tests/testrunner.py +++ b/indra/llmessage/tests/testrunner.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 """\ @file testrunner.py @author Nat Goodspeed diff --git a/indra/llplugin/CMakeLists.txt b/indra/llplugin/CMakeLists.txt index 446028b0f3..98417bbd7c 100644 --- a/indra/llplugin/CMakeLists.txt +++ b/indra/llplugin/CMakeLists.txt @@ -7,19 +7,19 @@ include(LLCommon) include(LLMath) include(LLMessage) include(LLRender) +include(Boost) include_directories( ${LLCOMMON_INCLUDE_DIRS} ${LLMATH_INCLUDE_DIRS} ${LLMESSAGE_INCLUDE_DIRS} ${LLRENDER_INCLUDE_DIRS} - ${LLQTWEBKIT_INCLUDE_DIR} ) set(llplugin_SOURCE_FILES llpluginclassbasic.cpp llpluginclassmedia.cpp - llplugincookiestore.cpp + #llplugincookiestore.cpp llplugininstance.cpp llpluginmessage.cpp llpluginmessagepipe.cpp @@ -34,7 +34,7 @@ set(llplugin_HEADER_FILES llpluginclassbasic.h llpluginclassmedia.h llpluginclassmediaowner.h - llplugincookiestore.h + #llplugincookiestore.h llplugininstance.h llpluginmessage.h llpluginmessageclasses.h @@ -47,22 +47,20 @@ set(llplugin_HEADER_FILES set_source_files_properties(${llplugin_HEADER_FILES} PROPERTIES HEADER_FILE_ONLY TRUE) -if(NOT WORD_SIZE EQUAL 32) - if(WINDOWS) - add_definitions(/FIXED:NO) - else(WINDOWS) # not windows therefore gcc LINUX and DARWIN - add_definitions(-fPIC) - endif(WINDOWS) -endif (NOT WORD_SIZE EQUAL 32) - list(APPEND llplugin_SOURCE_FILES ${llplugin_HEADER_FILES}) add_library (llplugin ${llplugin_SOURCE_FILES}) if(LINUX AND STANDALONE) - target_link_libraries (llplugin rt dl) -endif(LINUX AND STANDALONE) + target_link_libraries (llplugin llcommon rt dl) +else() + target_link_libraries( + llplugin + PUBLIC + llcommon + ) +endif() -add_dependencies(llplugin prepare) +set_target_properties(llplugin PROPERTIES POSITION_INDEPENDENT_CODE TRUE) add_subdirectory(slplugin) diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp index c5ff97ef73..daa7f4c8a8 100644 --- a/indra/llplugin/llpluginclassmedia.cpp +++ b/indra/llplugin/llpluginclassmedia.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llpluginclassmedia.cpp * @brief LLPluginClassMedia handles a plugin which knows about the "media" message class. * @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ * @endcond @@ -41,7 +41,7 @@ static int nextPowerOf2( int value ) { next_power_of_2 <<= 1; } - + return next_power_of_2; } @@ -62,6 +62,7 @@ bool LLPluginClassMedia::init_impl(void) return true; } + void LLPluginClassMedia::reset_impl(void) { mTextureParamsReceived = false; @@ -91,20 +92,26 @@ void LLPluginClassMedia::reset_impl(void) mMediaHeight = 0; mDirtyRect = LLRect::null; mAutoScaleMedia = false; - mRequestedVolume = 1.0f; + mRequestedVolume = 0.0f; + mPriority = PRIORITY_NORMAL; mLowPrioritySizeLimit = LOW_PRIORITY_TEXTURE_SIZE_DEFAULT; mAllowDownsample = false; mPadding = 0; mLastMouseX = 0; mLastMouseY = 0; mStatus = LLPluginClassMediaOwner::MEDIA_NONE; + mSleepTime = 1.0f / 100.0f; + mCanUndo = false; + mCanRedo = false; mCanCut = false; mCanCopy = false; mCanPaste = false; + mCanDoDelete = false; + mCanSelectAll = false; mMediaName.clear(); mMediaDescription.clear(); mBackgroundColor = LLColor4(1.0f, 1.0f, 1.0f, 1.0f); - + // media_browser class mNavigateURI.clear(); mNavigateResultCode = -1; @@ -112,13 +119,17 @@ void LLPluginClassMedia::reset_impl(void) mHistoryBackAvailable = false; mHistoryForwardAvailable = false; mStatusText.clear(); - mProgressPercent = 0; + mProgressPercent = 0; mClickURL.clear(); mClickNavType.clear(); mClickTarget.clear(); mClickUUID.clear(); mStatusCode = 0; - + + mClickEnforceTarget = false; + + mZoomFactor = 1.0; + // media_time class mCurrentTime = 0.0f; mDuration = 0.0f; @@ -128,7 +139,12 @@ void LLPluginClassMedia::reset_impl(void) void LLPluginClassMedia::idle_impl(void) { - if((mMediaWidth == -1) || (!mTextureParamsReceived) || (mPlugin == NULL) || (mPlugin->isBlocked()) || (mOwner == NULL)) + if(mPlugin) + { + mPlugin->idle(); + } + + if((mMediaWidth == -1) || (!mTextureParamsReceived) || (mPlugin == nullptr) || (mPlugin->isBlocked()) || (mOwner == nullptr)) { // Can't process a size change at this time } @@ -144,7 +160,7 @@ void LLPluginClassMedia::idle_impl(void) else { mRequestedTextureWidth = mRequestedMediaWidth; - + if(mPadding > 1) { // Pad up to a multiple of the specified number of bytes per row @@ -154,7 +170,7 @@ void LLPluginClassMedia::idle_impl(void) { rowbytes += mPadding - pad; } - + if(rowbytes % mRequestedTextureDepth == 0) { mRequestedTextureWidth = rowbytes / mRequestedTextureDepth; @@ -166,7 +182,7 @@ void LLPluginClassMedia::idle_impl(void) } } - + // Size change has been requested but not initiated yet. size_t newsize = mRequestedTextureWidth * mRequestedTextureHeight * mRequestedTextureDepth; @@ -181,22 +197,29 @@ void LLPluginClassMedia::idle_impl(void) mPlugin->removeSharedMemory(mTextureSharedMemoryName); mTextureSharedMemoryName.clear(); } - + mTextureSharedMemorySize = newsize; mTextureSharedMemoryName = mPlugin->addSharedMemory(mTextureSharedMemorySize); if(!mTextureSharedMemoryName.empty()) { void *addr = mPlugin->getSharedMemoryAddress(mTextureSharedMemoryName); - + // clear texture memory to avoid random screen visual fuzz from uninitialized texture data - memset( addr, 0x00, newsize ); - + if (addr) + { + memset( addr, 0x00, newsize ); + } + else + { + LL_WARNS("Plugin") << "Failed to get previously created shared memory address: " << mTextureSharedMemoryName << " size: " << mTextureSharedMemorySize << LL_ENDL; + } + // We could do this to force an update, but textureValid() will still be returning false until the first roundtrip to the plugin, // so it may not be worthwhile. // mDirtyRect.setOriginAndSize(0, 0, mRequestedMediaWidth, mRequestedMediaHeight); } } - + // This is our local indicator that a change is in progress. mTextureWidth = -1; mTextureHeight = -1; @@ -205,7 +228,7 @@ void LLPluginClassMedia::idle_impl(void) // This invalidates any existing dirty rect. resetDirty(); - + // Send a size change message to the plugin { LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change"); @@ -219,7 +242,7 @@ void LLPluginClassMedia::idle_impl(void) message.setValueReal("background_b", mBackgroundColor.mV[VZ]); message.setValueReal("background_a", mBackgroundColor.mV[VW]); mPlugin->sendMessage(message); // DO NOT just use sendMessage() here -- we want this to jump ahead of the queue. - + LL_DEBUGS("Plugin") << "Sending size_change" << LL_ENDL; } } @@ -237,8 +260,8 @@ int LLPluginClassMedia::getTextureHeight() const unsigned char* LLPluginClassMedia::getBitsData() { - unsigned char *result = NULL; - if((mPlugin != NULL) && !mTextureSharedMemoryName.empty()) + unsigned char *result = nullptr; + if((mPlugin != nullptr) && !mTextureSharedMemoryName.empty()) { result = (unsigned char*)mPlugin->getSharedMemoryAddress(mTextureSharedMemoryName); } @@ -278,11 +301,11 @@ void LLPluginClassMedia::setSizeInternal(void) mRequestedMediaWidth = mDefaultMediaWidth; mRequestedMediaHeight = mDefaultMediaHeight; } - + // Save these for size/interest calculations mFullMediaWidth = mRequestedMediaWidth; mFullMediaHeight = mRequestedMediaHeight; - + if(mAllowDownsample) { switch(mPriority) @@ -296,24 +319,24 @@ void LLPluginClassMedia::setSizeInternal(void) mRequestedMediaHeight /= 2; } break; - + default: // Don't adjust texture size break; } } - + if(mAutoScaleMedia) { mRequestedMediaWidth = nextPowerOf2(mRequestedMediaWidth); mRequestedMediaHeight = nextPowerOf2(mRequestedMediaHeight); } - - if(mRequestedMediaWidth > 2048) - mRequestedMediaWidth = 2048; - if(mRequestedMediaHeight > 2048) - mRequestedMediaHeight = 2048; + if(mRequestedMediaWidth > 6000) + mRequestedMediaWidth = 6000; + + if(mRequestedMediaHeight > 6000) + mRequestedMediaHeight = 6000; } void LLPluginClassMedia::setAutoScale(bool auto_scale) @@ -335,10 +358,10 @@ bool LLPluginClassMedia::textureValid(void) mMediaHeight <= 0 || mRequestedMediaWidth != mMediaWidth || mRequestedMediaHeight != mMediaHeight || - getBitsData() == NULL - ) + getBitsData() == nullptr + ) return false; - + return true; } @@ -346,7 +369,7 @@ bool LLPluginClassMedia::getDirty(LLRect *dirty_rect) { bool result = !mDirtyRect.isEmpty(); - if(dirty_rect != NULL) + if(dirty_rect != nullptr) { *dirty_rect = mDirtyRect; } @@ -362,8 +385,8 @@ void LLPluginClassMedia::resetDirty(void) std::string LLPluginClassMedia::translateModifiers(MASK modifiers) { std::string result; - - + + if(modifiers & MASK_CONTROL) { result += "control|"; @@ -386,7 +409,7 @@ std::string LLPluginClassMedia::translateModifiers(MASK modifiers) { result += "meta|"; } -*/ +*/ return result; } @@ -494,11 +517,11 @@ void LLPluginClassMedia::mouseEvent(EMouseEventType type, int button, int x, int // Don't spam unnecessary mouse move events. return; } - + mLastMouseX = x; mLastMouseY = y; } - + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "mouse_event"); std::string temp; switch(type) @@ -513,7 +536,7 @@ void LLPluginClassMedia::mouseEvent(EMouseEventType type, int button, int x, int message.setValueS32("button", button); message.setValueS32("x", x); - + // Incoming coordinates are OpenGL-style ((0,0) = lower left), so flip them here if the plugin has requested it. if(!mRequestedTextureCoordsOpenGL) { @@ -523,42 +546,42 @@ void LLPluginClassMedia::mouseEvent(EMouseEventType type, int button, int x, int message.setValueS32("y", y); message.setValue("modifiers", translateModifiers(modifiers)); - + sendMessage(message); } bool LLPluginClassMedia::keyEvent(EKeyEventType type, int key_code, MASK modifiers, LLSD native_key_data) { bool result = true; - + // FIXME: // HACK: we don't have an easy way to tell if the plugin is going to handle a particular keycode. // For now, return false for the ones the webkit plugin won't handle properly. - + switch(key_code) { - case KEY_BACKSPACE: - case KEY_TAB: - case KEY_RETURN: - case KEY_PAD_RETURN: - case KEY_SHIFT: - case KEY_CONTROL: - case KEY_ALT: - case KEY_CAPSLOCK: - case KEY_ESCAPE: - case KEY_PAGE_UP: - case KEY_PAGE_DOWN: - case KEY_END: - case KEY_HOME: - case KEY_LEFT: - case KEY_UP: - case KEY_RIGHT: - case KEY_DOWN: - case KEY_INSERT: + case KEY_BACKSPACE: + case KEY_TAB: + case KEY_RETURN: + case KEY_PAD_RETURN: + case KEY_SHIFT: + case KEY_CONTROL: + case KEY_ALT: + case KEY_CAPSLOCK: + case KEY_ESCAPE: + case KEY_PAGE_UP: + case KEY_PAGE_DOWN: + case KEY_END: + case KEY_HOME: + case KEY_LEFT: + case KEY_UP: + case KEY_RIGHT: + case KEY_DOWN: + case KEY_INSERT: case KEY_DELETE: - // These will be handled + // These will be handled break; - + default: // regular ASCII characters will also be handled if(key_code >= KEY_SPECIAL) @@ -569,7 +592,7 @@ bool LLPluginClassMedia::keyEvent(EKeyEventType type, int key_code, MASK modifie break; } -#if LL_DARWIN +#if LL_DARWIN if(modifiers & MASK_ALT) { // Option-key modified characters should be handled by the unicode input path instead of this one. @@ -588,29 +611,31 @@ bool LLPluginClassMedia::keyEvent(EKeyEventType type, int key_code, MASK modifie case KEY_EVENT_REPEAT: temp = "repeat"; break; } message.setValue("event", temp); - + message.setValueS32("key", key_code); message.setValue("modifiers", translateModifiers(modifiers)); message.setValueLLSD("native_key_data", native_key_data); - + sendMessage(message); } - + return result; } -void LLPluginClassMedia::scrollEvent(int x, int y, MASK modifiers) +void LLPluginClassMedia::scrollEvent(int x, int y, int clicks_x, int clicks_y, MASK modifiers) { LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "scroll_event"); message.setValueS32("x", x); message.setValueS32("y", y); + message.setValueS32("clicks_x", clicks_x); + message.setValueS32("clicks_y", clicks_y); message.setValue("modifiers", translateModifiers(modifiers)); - + sendMessage(message); } - + bool LLPluginClassMedia::textInput(const std::string &text, MASK modifiers, LLSD native_key_data) { LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "text_event"); @@ -618,18 +643,33 @@ bool LLPluginClassMedia::textInput(const std::string &text, MASK modifiers, LLSD message.setValue("text", text); message.setValue("modifiers", translateModifiers(modifiers)); message.setValueLLSD("native_key_data", native_key_data); - + sendMessage(message); - + return true; } +void LLPluginClassMedia::setCookie(std::string uri, std::string name, std::string value, std::string domain, std::string path, bool httponly, bool secure) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_cookie"); + + message.setValue("uri", uri); + message.setValue("name", name); + message.setValue("value", value); + message.setValue("domain", domain); + message.setValue("path", path); + message.setValueBoolean("httponly", httponly); + message.setValueBoolean("secure", secure); + + sendMessage(message); +} + void LLPluginClassMedia::loadURI(const std::string &uri) { LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "load_uri"); message.setValue("uri", uri); - + sendMessage(message); } @@ -645,6 +685,7 @@ void LLPluginClassMedia::setLowPrioritySizeLimit(int size) if(mLowPrioritySizeLimit != power) { mLowPrioritySizeLimit = power; + // This may affect the calculated size, so recalculate it here. setSizeInternal(); } @@ -653,24 +694,31 @@ void LLPluginClassMedia::setLowPrioritySizeLimit(int size) F64 LLPluginClassMedia::getCPUUsage() { F64 result = 0.0f; - + if(mPlugin) { result = mPlugin->getCPUUsage(); } - + return result; } -void LLPluginClassMedia::sendPickFileResponse(const std::string &file) +void LLPluginClassMedia::sendPickFileResponse(const std::vector files) { LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "pick_file_response"); - message.setValue("file", file); if(mPlugin && mPlugin->isBlocked()) { // If the plugin sent a blocking pick-file request, the response should unblock it. message.setValueBoolean("blocking_response", true); } + + LLSD file_list = LLSD::emptyArray(); + for (const auto& file : files) + { + file_list.append(LLSD::String(file)); + } + message.setValueLLSD("file_list", file_list); + sendMessage(message); } @@ -688,6 +736,18 @@ void LLPluginClassMedia::sendAuthResponse(bool ok, const std::string &username, sendMessage(message); } +void LLPluginClassMedia::undo() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_undo"); + sendMessage(message); +} + +void LLPluginClassMedia::redo() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_redo"); + sendMessage(message); +} + void LLPluginClassMedia::cut() { LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_cut"); @@ -706,10 +766,33 @@ void LLPluginClassMedia::paste() sendMessage(message); } -void LLPluginClassMedia::setUserDataPath(const std::string &user_data_path) +void LLPluginClassMedia::doDelete() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_delete"); + sendMessage(message); +} + +void LLPluginClassMedia::selectAll() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_select_all"); + sendMessage(message); +} + +void LLPluginClassMedia::showPageSource() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_show_source"); + sendMessage(message); +} + +void LLPluginClassMedia::setUserDataPath(const std::string &user_data_path_cache, + const std::string &user_data_path_cookies, + const std::string &user_data_path_cef_log) { LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_user_data_path"); - message.setValue("path", user_data_path); + message.setValue("cache_path", user_data_path_cache); + message.setValue("cookies_path", user_data_path_cookies); + message.setValue("cef_log_file", user_data_path_cef_log); + sendMessage(message); } @@ -722,14 +805,14 @@ void LLPluginClassMedia::setLanguageCode(const std::string &language_code) void LLPluginClassMedia::setPluginsEnabled(const bool enabled) { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "plugins_enabled"); + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "plugins_enabled"); message.setValueBoolean("enable", enabled); sendMessage(message); } void LLPluginClassMedia::setJavascriptEnabled(const bool enabled) { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "javascript_enabled"); + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "javascript_enabled"); message.setValueBoolean("enable", enabled); sendMessage(message); } @@ -746,7 +829,8 @@ void LLPluginClassMedia::setTarget(const std::string &target) { mTarget = target; } -/* virtual */ + +/* virtual */ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message) { std::string message_class = message.getClass(); @@ -765,21 +849,21 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message) mRequestedTextureFormat = message.getValueU32("format"); mRequestedTextureType = message.getValueU32("type"); mRequestedTextureSwapBytes = message.getValueBoolean("swap_bytes"); - mRequestedTextureCoordsOpenGL = message.getValueBoolean("coords_opengl"); - + mRequestedTextureCoordsOpenGL = message.getValueBoolean("coords_opengl"); + // These two are optional, and will default to 0 if they're not specified. mDefaultMediaWidth = message.getValueS32("default_width"); mDefaultMediaHeight = message.getValueS32("default_height"); - + mAllowDownsample = message.getValueBoolean("allow_downsample"); mPadding = message.getValueS32("padding"); setSizeInternal(); - + mTextureParamsReceived = true; } else if(message_name == "updated") - { + { if(message.hasValue("left")) { LLRect newDirtyRect; @@ -787,7 +871,7 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message) newDirtyRect.mTop = message.getValueS32("top"); newDirtyRect.mRight = message.getValueS32("right"); newDirtyRect.mBottom = message.getValueS32("bottom"); - + // The plugin is likely to have top and bottom switched, due to vertical flip and OpenGL coordinate confusion. // If they're backwards, swap them. if(newDirtyRect.mTop < newDirtyRect.mBottom) @@ -796,7 +880,7 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message) newDirtyRect.mTop = newDirtyRect.mBottom; newDirtyRect.mBottom = temp; } - + if(mDirtyRect.isEmpty()) { mDirtyRect = newDirtyRect; @@ -806,7 +890,7 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message) mDirtyRect.unionWith(newDirtyRect); } - LL_DEBUGS("PluginUpdated") << "adjusted incoming rect is: (" + LL_DEBUGS("PluginUpdated") << "adjusted incoming rect is: (" << newDirtyRect.mLeft << ", " << newDirtyRect.mTop << ", " << newDirtyRect.mRight << ", " @@ -816,10 +900,10 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message) << mDirtyRect.mRight << ", " << mDirtyRect.mBottom << ")" << LL_ENDL; - + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CONTENT_UPDATED); - } - + } + bool time_duration_updated = false; int previous_percent = mProgressPercent; @@ -839,7 +923,7 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message) { mCurrentRate = message.getValueReal("current_rate"); } - + if(message.hasValue("loaded_duration")) { mLoadedDuration = message.getValueReal("loaded_duration"); @@ -850,7 +934,7 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message) // If the message doesn't contain a loaded_duration param, assume it's equal to duration mLoadedDuration = mDuration; } - + // Calculate a percentage based on the loaded duration and total duration. if(mDuration != 0.0f) // Don't divide by zero. { @@ -861,7 +945,7 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message) { mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_TIME_DURATION_UPDATED); } - + if(previous_percent != mProgressPercent) { mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PROGRESS_UPDATED); @@ -870,9 +954,9 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message) else if(message_name == "media_status") { std::string status = message.getValue("status"); - + LL_DEBUGS("Plugin") << "Status changed to: " << status << LL_ENDL; - + if(status == "loading") { mStatus = LLPluginClassMediaOwner::MEDIA_LOADING; @@ -907,29 +991,25 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message) { S32 width = message.getValueS32("width"); S32 height = message.getValueS32("height"); - std::string name = message.getValue("name"); // TODO: check that name matches? mNaturalMediaWidth = width; mNaturalMediaHeight = height; - + setSizeInternal(); } else if(message_name == "size_change_response") { - std::string name = message.getValue("name"); - // TODO: check that name matches? - mTextureWidth = message.getValueS32("texture_width"); mTextureHeight = message.getValueS32("texture_height"); mMediaWidth = message.getValueS32("width"); mMediaHeight = message.getValueS32("height"); - + // This invalidates any existing dirty rect. resetDirty(); - - // TODO: should we verify that the plugin sent back the right values? + + // TODO: should we verify that the plugin sent back the right values? // Two size changes in a row may cause them to not match, due to queueing, etc. mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_SIZE_CHANGED); @@ -942,6 +1022,14 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message) } else if(message_name == "edit_state") { + if(message.hasValue("undo")) + { + mCanUndo = message.getValueBoolean("undo"); + } + if(message.hasValue("redo")) + { + mCanRedo = message.getValueBoolean("redo"); + } if(message.hasValue("cut")) { mCanCut = message.getValueBoolean("cut"); @@ -954,14 +1042,25 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message) { mCanPaste = message.getValueBoolean("paste"); } + if (message.hasValue("delete")) + { + mCanDoDelete = message.getValueBoolean("delete"); + } + if (message.hasValue("select_all")) + { + mCanSelectAll = message.getValueBoolean("select_all"); + } } else if(message_name == "name_text") { + mHistoryBackAvailable = message.getValueBoolean("history_back_available"); + mHistoryForwardAvailable = message.getValueBoolean("history_forward_available"); mMediaName = message.getValue("name"); mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAME_CHANGED); } else if(message_name == "pick_file") { + mIsMultipleFilePick = message.getValueBoolean("multiple_files"); mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PICK_FILE_REQUEST); } else if(message_name == "auth_request") @@ -969,7 +1068,12 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message) mAuthURL = message.getValue("url"); mAuthRealm = message.getValue("realm"); mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_AUTH_REQUEST); - } + } + else if (message_name == "file_download") + { + mFileDownloadFilename = message.getValue("filename"); + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_FILE_DOWNLOAD); + } else if(message_name == "debug_message") { mDebugMessageText = message.getValue("message_text"); @@ -996,7 +1100,7 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message) mNavigateResultString = message.getValue("result_string"); mHistoryBackAvailable = message.getValueBoolean("history_back_available"); mHistoryForwardAvailable = message.getValueBoolean("history_forward_available"); - + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_COMPLETE); } else if(message_name == "progress") @@ -1018,7 +1122,12 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message) { mClickURL = message.getValue("uri"); mClickTarget = message.getValue("target"); - mClickUUID = message.getValue("uuid"); + + // need a link to have a UUID that identifies it to a system further + // upstream - plugin could make it but we have access to LLUUID here + // so why don't we use it + mClickUUID = LLUUID::generateNewID().asString(); + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLICK_LINK_HREF); } else if(message_name == "click_nofollow") @@ -1033,13 +1142,6 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message) mStatusCode = message.getValueS32("status_code"); mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_ERROR_PAGE); } - else if(message_name == "cookie_set") - { - if(mOwner) - { - mOwner->handleCookieSet(this, message.getValue("cookie")); - } - } else if(message_name == "close_request") { mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLOSE_REQUEST); @@ -1051,7 +1153,7 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message) mGeometryY = message.getValueS32("y"); mGeometryWidth = message.getValueS32("width"); mGeometryHeight = message.getValueS32("height"); - + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_GEOMETRY_CHANGE); } else if(message_name == "link_hovered") @@ -1060,7 +1162,7 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message) mHoverLink = message.getValue("link"); mHoverText = message.getValue("title"); // message.getValue("text"); - + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_LINK_HOVERED); } else @@ -1076,20 +1178,21 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message) // if(message_name == "message_name") // { // } -// else +// else { - LL_WARNS("Plugin") << "Unknown " << message_class << " class message: " << message_name << LL_ENDL; + LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL; } } + } -/* virtual */ +/* virtual */ void LLPluginClassMedia::pluginLaunchFailed() { mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PLUGIN_FAILED_LAUNCH); } -/* virtual */ +/* virtual */ void LLPluginClassMedia::pluginDied() { mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PLUGIN_FAILED); @@ -1116,11 +1219,11 @@ void LLPluginClassMedia::focus(bool focused) LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "focus"); message.setValueBoolean("focused", focused); - + sendMessage(message); } -void LLPluginClassMedia::set_page_zoom_factor( double factor ) +void LLPluginClassMedia::set_page_zoom_factor( F64 factor ) { LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_page_zoom_factor"); @@ -1140,27 +1243,23 @@ void LLPluginClassMedia::clear_cookies() sendMessage(message); } -void LLPluginClassMedia::set_cookies(const std::string &cookies) -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_cookies"); - message.setValue("cookies", cookies); - sendMessage(message); -} - -void LLPluginClassMedia::enable_cookies(bool enable) +void LLPluginClassMedia::cookies_enabled(bool enable) { - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "enable_cookies"); + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "cookies_enabled"); message.setValueBoolean("enable", enable); sendMessage(message); } -void LLPluginClassMedia::proxy_setup(bool enable, const std::string &host, int port) +void LLPluginClassMedia::proxy_setup(bool enable, int type, const std::string &host, int port, const std::string &user, const std::string &pass) { LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "proxy_setup"); message.setValueBoolean("enable", enable); + message.setValueS32("proxy_type", type); message.setValue("host", host); message.setValueS32("port", port); + message.setValue("username", user); + message.setValue("password", pass); sendMessage(message); } @@ -1176,7 +1275,7 @@ void LLPluginClassMedia::browse_reload(bool ignore_cache) LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_reload"); message.setValueBoolean("ignore_cache", ignore_cache); - + sendMessage(message); } @@ -1192,16 +1291,6 @@ void LLPluginClassMedia::browse_back() sendMessage(message); } -void LLPluginClassMedia::set_status_redirect(int code, const std::string &url) -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_status_redirect"); - - message.setValueS32("code", code); - message.setValue("url", url); - - sendMessage(message); -} - void LLPluginClassMedia::setBrowserUserAgent(const std::string& user_agent) { LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_user_agent"); @@ -1251,6 +1340,12 @@ void LLPluginClassMedia::addCertificateFilePath(const std::string& path) sendMessage(message); } +void LLPluginClassMedia::setOverrideClickTarget(const std::string &target) +{ + mClickEnforceTarget = true; + mOverrideClickTarget = target; +} + void LLPluginClassMedia::crashPlugin() { LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "crash"); @@ -1300,7 +1395,7 @@ void LLPluginClassMedia::seek(float time) LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "seek"); message.setValueReal("time", time); - + sendMessage(message); } @@ -1318,11 +1413,11 @@ void LLPluginClassMedia::setVolume(float volume) if(volume != mRequestedVolume) { mRequestedVolume = volume; - + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "set_volume"); message.setValueReal("volume", volume); - + sendMessage(message); } } @@ -1341,4 +1436,3 @@ void LLPluginClassMedia::initializeUrlHistory(const LLSD& url_history) LL_DEBUGS("Plugin") << "Sending history" << LL_ENDL; } - diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h index 8e7a40a674..7e8c2e4eb0 100644 --- a/indra/llplugin/llpluginclassmedia.h +++ b/indra/llplugin/llpluginclassmedia.h @@ -57,6 +57,7 @@ class LLPluginClassMedia : public LLPluginClassBasic, public boost::signals2::tr int getTextureHeight() const; int getFullWidth() const { return mFullMediaWidth; }; int getFullHeight() const { return mFullMediaHeight; }; + F64 getZoomFactor() const { return mZoomFactor; }; // This may return NULL. Callers need to check for and handle this case. unsigned char* getBitsData(); @@ -72,8 +73,9 @@ class LLPluginClassMedia : public LLPluginClassBasic, public boost::signals2::tr void setSize(int width, int height); void setAutoScale(bool auto_scale); + void setZoomFactor(F64 zoom_factor) { mZoomFactor = zoom_factor; } - void setBackgroundColor(LLColor4 color) { mBackgroundColor = color; }; + void setBackgroundColor(const LLColor4& color) { mBackgroundColor = color; }; void setOwner(LLPluginClassMediaOwner *owner) { mOwner = owner; }; @@ -83,7 +85,7 @@ class LLPluginClassMedia : public LLPluginClassBasic, public boost::signals2::tr // until you call idle() again. bool textureValid(void); - bool getDirty(LLRect *dirty_rect = NULL); + bool getDirty(LLRect *dirty_rect = nullptr); void resetDirty(void); typedef enum @@ -105,7 +107,7 @@ class LLPluginClassMedia : public LLPluginClassBasic, public boost::signals2::tr bool keyEvent(EKeyEventType type, int key_code, MASK modifiers, LLSD native_key_data); - void scrollEvent(int x, int y, MASK modifiers); + void scrollEvent(int x, int y, int clicks_x, int clicks_y, MASK modifiers); // enable/disable media plugin debugging messages and info spam void enableMediaPluginDebugging( bool enable ); @@ -122,12 +124,14 @@ class LLPluginClassMedia : public LLPluginClassBasic, public boost::signals2::tr // Text may be unicode (utf8 encoded) bool textInput(const std::string &text, MASK modifiers, LLSD native_key_data); + void setCookie(std::string uri, std::string name, std::string value, std::string domain, std::string path, bool httponly, bool secure); + void loadURI(const std::string &uri); // Inherited from LLPluginProcessParentOwner - /* virtual */ void receivePluginMessage(const LLPluginMessage &message); - /* virtual */ void pluginLaunchFailed(); - /* virtual */ void pluginDied(); + /* virtual */ void receivePluginMessage(const LLPluginMessage &message) override; + /* virtual */ void pluginLaunchFailed() override; + /* virtual */ void pluginDied() override; // Inherited from LLPluginClassBasic /* virtual */ void priorityChanged(EPriority priority); @@ -135,7 +139,7 @@ class LLPluginClassMedia : public LLPluginClassBasic, public boost::signals2::tr F64 getCPUUsage(); - void sendPickFileResponse(const std::string &file); + void sendPickFileResponse(const std::vector files); void sendAuthResponse(bool ok, const std::string &username, const std::string &password); @@ -144,6 +148,12 @@ class LLPluginClassMedia : public LLPluginClassBasic, public boost::signals2::tr LLPluginClassMediaOwner::EMediaStatus getStatus() const { return mStatus; } + void undo(); + bool canUndo() const { return mCanUndo; }; + + void redo(); + bool canRedo() const { return mCanRedo; }; + void cut(); bool canCut() const { return mCanCut; }; @@ -153,8 +163,16 @@ class LLPluginClassMedia : public LLPluginClassBasic, public boost::signals2::tr void paste(); bool canPaste() const { return mCanPaste; }; + void doDelete(); + bool canDoDelete() const { return mCanDoDelete; }; + + void selectAll(); + bool canSelectAll() const { return mCanSelectAll; }; + + void showPageSource(); + // These can be called before init(), and they will be queued and sent before the media init message. - void setUserDataPath(const std::string &user_data_path); + void setUserDataPath(const std::string &user_data_path_cache, const std::string &user_data_path_cookies, const std::string &user_data_path_cef_log); void setLanguageCode(const std::string &language_code); void setPluginsEnabled(const bool enabled); void setJavascriptEnabled(const bool enabled); @@ -165,17 +183,15 @@ class LLPluginClassMedia : public LLPluginClassBasic, public boost::signals2::tr bool pluginSupportsMediaBrowser(void); void focus(bool focused); - void set_page_zoom_factor( double factor ); + void set_page_zoom_factor( F64 factor ); void clear_cache(); void clear_cookies(); - void set_cookies(const std::string &cookies); - void enable_cookies(bool enable); - void proxy_setup(bool enable, const std::string &host = LLStringUtil::null, int port = 0); + void cookies_enabled(bool enable); + void proxy_setup(bool enable, int type = 0, const std::string &host = LLStringUtil::null, int port = 0, const std::string &user = LLStringUtil::null, const std::string &pass = LLStringUtil::null); void browse_stop(); void browse_reload(bool ignore_cache = false); void browse_forward(); void browse_back(); - void set_status_redirect(int code, const std::string &url); void setBrowserUserAgent(const std::string& user_agent); void showWebInspector( bool show ); void proxyWindowOpened(const std::string &target, const std::string &uuid); @@ -213,6 +229,13 @@ class LLPluginClassMedia : public LLPluginClassBasic, public boost::signals2::tr // This is valid during MEDIA_EVENT_CLICK_LINK_HREF and MEDIA_EVENT_GEOMETRY_CHANGE std::string getClickUUID() const { return mClickUUID; }; + // mClickTarget is received from message and governs how link will be opened + // use this to enforce your own way of opening links inside plugins + void setOverrideClickTarget(const std::string &target); + void resetOverrideClickTarget() { mClickEnforceTarget = false; }; + bool isOverrideClickTarget() const { return mClickEnforceTarget; } + std::string getOverrideClickTarget() const { return mOverrideClickTarget; }; + // These are valid during MEDIA_EVENT_DEBUG_MESSAGE std::string getDebugMessageText() const { return mDebugMessageText; }; std::string getDebugMessageLevel() const { return mDebugMessageLevel; }; @@ -230,10 +253,17 @@ class LLPluginClassMedia : public LLPluginClassBasic, public boost::signals2::tr std::string getAuthURL() const { return mAuthURL; }; std::string getAuthRealm() const { return mAuthRealm; }; + // These are valid during MEDIA_EVENT_PICK_FILE_REQUEST + bool getIsMultipleFilePick() const { return mIsMultipleFilePick; } + // These are valid during MEDIA_EVENT_LINK_HOVERED std::string getHoverText() const { return mHoverText; }; std::string getHoverLink() const { return mHoverLink; }; + // these are valid during MEDIA_EVENT_LINK_HOVERED + std::string getFileDownloadFilename() const { return mFileDownloadFilename; } + + const std::string& getMediaName() const { return mMediaName; }; std::string getMediaDescription() const { return mMediaDescription; }; @@ -320,8 +350,12 @@ class LLPluginClassMedia : public LLPluginClassBasic, public boost::signals2::tr int mMediaWidth; int mMediaHeight; + F64 mZoomFactor; + float mRequestedVolume; + // Priority of this media stream + EPriority mPriority; int mLowPrioritySizeLimit; bool mAllowDownsample; @@ -337,9 +371,15 @@ class LLPluginClassMedia : public LLPluginClassBasic, public boost::signals2::tr LLPluginClassMediaOwner::EMediaStatus mStatus; + F64 mSleepTime; + + bool mCanUndo; + bool mCanRedo; bool mCanCut; bool mCanCopy; bool mCanPaste; + bool mCanDoDelete; + bool mCanSelectAll; std::string mMediaName; std::string mMediaDescription; @@ -362,6 +402,8 @@ class LLPluginClassMedia : public LLPluginClassBasic, public boost::signals2::tr std::string mClickNavType; std::string mClickTarget; std::string mClickUUID; + bool mClickEnforceTarget; + std::string mOverrideClickTarget; std::string mDebugMessageText; std::string mDebugMessageLevel; S32 mGeometryX; @@ -373,6 +415,8 @@ class LLPluginClassMedia : public LLPluginClassBasic, public boost::signals2::tr std::string mAuthRealm; std::string mHoverText; std::string mHoverLink; + std::string mFileDownloadFilename; + bool mIsMultipleFilePick; ///////////////////////////////////////// // media_time class diff --git a/indra/llplugin/llpluginclassmediaowner.h b/indra/llplugin/llpluginclassmediaowner.h index 4a739cf865..010f54c8fd 100644 --- a/indra/llplugin/llpluginclassmediaowner.h +++ b/indra/llplugin/llpluginclassmediaowner.h @@ -3,33 +3,26 @@ * @brief LLPluginClassMedia handles interaction with a plugin which knows about the "media" message class. * * @cond - * $LicenseInfo:firstyear=2008&license=viewergpl$ - * - * Copyright (c) 2008-2010, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlife.com/developers/opensource/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ * @endcond */ @@ -41,7 +34,6 @@ #include class LLPluginClassMedia; -class LLPluginCookieStore; class LLPluginClassMediaOwner { @@ -71,6 +63,8 @@ class LLPluginClassMediaOwner MEDIA_EVENT_AUTH_REQUEST, // The plugin wants to display an auth dialog + MEDIA_EVENT_FILE_DOWNLOAD, // the plugin wants to download a file + MEDIA_EVENT_DEBUG_MESSAGE, // plugin sending back debug information for host to process MEDIA_EVENT_LINK_HOVERED // Got a "link hovered" event from the plugin @@ -91,7 +85,6 @@ class LLPluginClassMediaOwner virtual ~LLPluginClassMediaOwner() {}; virtual void handleMediaEvent(LLPluginClassMedia* /*self*/, EMediaEvent /*event*/) {}; - virtual void handleCookieSet(LLPluginClassMedia* /*self*/, const std::string &/*cookie*/) {}; }; #endif // LL_LLPLUGINCLASSMEDIAOWNER_H diff --git a/indra/llplugin/llplugincookiestore.cpp b/indra/llplugin/llplugincookiestore.cpp index 283ba356f2..199769e9bc 100644 --- a/indra/llplugin/llplugincookiestore.cpp +++ b/indra/llplugin/llplugincookiestore.cpp @@ -402,7 +402,7 @@ void LLPluginCookieStore::writeChangedCookies(std::ostream& s, bool clear_change { if(mHasChangedCookies) { - lldebugs << "returning changed cookies: " << llendl; + LL_DEBUGS() << "returning changed cookies: " << LL_ENDL; cookie_map_t::iterator iter; for(iter = mCookies.begin(); iter != mCookies.end(); ) { @@ -414,7 +414,7 @@ void LLPluginCookieStore::writeChangedCookies(std::ostream& s, bool clear_change { s << iter->second->getCookie() << "\n"; - lldebugs << " " << iter->second->getCookie() << llendl; + LL_DEBUGS() << " " << iter->second->getCookie() << LL_ENDL; // If requested, clear the changed mark if(clear_changed) diff --git a/indra/llplugin/llpluginmessagepipe.cpp b/indra/llplugin/llpluginmessagepipe.cpp index a00cd63e67..655d3b35f7 100644 --- a/indra/llplugin/llpluginmessagepipe.cpp +++ b/indra/llplugin/llpluginmessagepipe.cpp @@ -120,10 +120,11 @@ LLPluginMessagePipe::~LLPluginMessagePipe() bool LLPluginMessagePipe::addMessage(const std::string &message) { // queue the message for later output - LLMutexLock lock(&mOutputMutex); + //LLMutexLock lock(&mOutputMutex); + mOutputMutex.lock(); mOutput += message; mOutput += MESSAGE_DELIMITER; // message separator - + mOutputMutex.unlock(); return true; } @@ -229,7 +230,7 @@ bool LLPluginMessagePipe::pumpOutput(bool flush) else if(APR_STATUS_IS_EOF(status)) { // This is what we normally expect when a plugin exits. - llinfos << "Got EOF from plugin socket. " << llendl; + LL_INFOS() << "Got EOF from plugin socket. " << LL_ENDL; if(mOwner) { diff --git a/indra/llplugin/llpluginprocessparent.cpp b/indra/llplugin/llpluginprocessparent.cpp index 13c1d3c4e8..dc57862d85 100644 --- a/indra/llplugin/llpluginprocessparent.cpp +++ b/indra/llplugin/llpluginprocessparent.cpp @@ -185,7 +185,7 @@ bool LLPluginProcessParent::accept() if(status == APR_SUCCESS) { -// llinfos << "SUCCESS" << llendl; +// LL_INFOS() << "SUCCESS" << LL_ENDL; // Success. Create a message pipe on the new socket new LLPluginMessagePipe(this, mSocket); diff --git a/indra/llplugin/slplugin/CMakeLists.txt b/indra/llplugin/slplugin/CMakeLists.txt index 381782ed6d..f8ab569162 100644 --- a/indra/llplugin/slplugin/CMakeLists.txt +++ b/indra/llplugin/slplugin/CMakeLists.txt @@ -6,6 +6,7 @@ include(LLPlugin) include(Linking) include(PluginAPI) include(LLMessage) +include(WinManifest) include_directories( ${LLPLUGIN_INCLUDE_DIRS} @@ -56,8 +57,9 @@ set_target_properties(SLPlugin if (WINDOWS) set_target_properties(SLPlugin PROPERTIES - LINK_FLAGS "/OPT:NOREF" + LINK_FLAGS_DEBUG "/NODEFAULTLIB:\"LIBCMTD\"" ) + EMBED_MANIFEST(SLPlugin 1) endif() target_link_libraries(SLPlugin @@ -66,12 +68,7 @@ target_link_libraries(SLPlugin ${LLCOMMON_LIBRARIES} ${APRUTIL_LIBRARIES} ${PLUGIN_API_WINDOWS_LIBRARIES} -) - -add_dependencies(SLPlugin - ${LLPLUGIN_LIBRARIES} - ${LLMESSAGE_LIBRARIES} - ${LLCOMMON_LIBRARIES} + ${PTHREAD_LIBRARY} ) if (DARWIN) diff --git a/indra/llplugin/slplugin/slplugin.cpp b/indra/llplugin/slplugin/slplugin.cpp index 7b894c4576..49c3c2ed99 100644 --- a/indra/llplugin/slplugin/slplugin.cpp +++ b/indra/llplugin/slplugin/slplugin.cpp @@ -91,45 +91,35 @@ LONG WINAPI myWin32ExceptionHandler( struct _EXCEPTION_POINTERS* exception_infop return EXCEPTION_EXECUTE_HANDLER; } -// Taken from : http://blog.kalmbachnet.de/?postid=75 -// The MSVC 2005 CRT forces the call of the default-debugger (normally Dr.Watson) +// Taken from : http://blog.kalmbach-software.de/2013/05/23/improvedpreventsetunhandledexceptionfilter/ +// The MSVC 2005 and above CRT forces the call of the default-debugger (normally Dr.Watson) // even with the other exception handling code. This (terrifying) piece of code // patches things so that doesn't happen. -LPTOP_LEVEL_EXCEPTION_FILTER WINAPI MyDummySetUnhandledExceptionFilter( - LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter ) +static BOOL PreventSetUnhandledExceptionFilter() { - return NULL; -} - -BOOL PreventSetUnhandledExceptionFilter() -{ -// WARNING: This won't work on 64-bit Windows systems so we turn it off it. -// It should work for any flavor of 32-bit Windows we care about. -// If it's off, sometimes you will see an OS message when a plugin crashes -#ifndef _WIN64 - HMODULE hKernel32 = LoadLibraryA( "kernel32.dll" ); - if ( NULL == hKernel32 ) - return FALSE; - - void *pOrgEntry = GetProcAddress( hKernel32, "SetUnhandledExceptionFilter" ); - if( NULL == pOrgEntry ) - return FALSE; - - unsigned char newJump[ 100 ]; - DWORD dwOrgEntryAddr = (DWORD)pOrgEntry; - dwOrgEntryAddr += 5; // add 5 for 5 op-codes for jmp far - void *pNewFunc = &MyDummySetUnhandledExceptionFilter; - DWORD dwNewEntryAddr = (DWORD) pNewFunc; - DWORD dwRelativeAddr = dwNewEntryAddr - dwOrgEntryAddr; - - newJump[ 0 ] = 0xE9; // JMP absolute - memcpy( &newJump[ 1 ], &dwRelativeAddr, sizeof( pNewFunc ) ); - SIZE_T bytesWritten; - BOOL bRet = WriteProcessMemory( GetCurrentProcess(), pOrgEntry, newJump, sizeof( pNewFunc ) + 1, &bytesWritten ); - return bRet; + HMODULE hKernel32 = LoadLibrary(TEXT("kernel32.dll")); + if (hKernel32 == NULL) return FALSE; + void *pOrgEntry = GetProcAddress(hKernel32, "SetUnhandledExceptionFilter"); + if (pOrgEntry == NULL) return FALSE; + +#ifdef _M_IX86 + // Code for x86: + // 33 C0 xor eax,eax + // C2 04 00 ret 4 + unsigned char szExecute[] = { 0x33, 0xC0, 0xC2, 0x04, 0x00 }; +#elif _M_X64 + // 33 C0 xor eax,eax + // C3 ret + unsigned char szExecute[] = { 0x33, 0xC0, 0xC3 }; #else - return FALSE; +#error "The following code only works for x86 and x64!" #endif + + DWORD oldProtect; + BOOL bRet = VirtualProtect(pOrgEntry, sizeof(szExecute), PAGE_EXECUTE_READWRITE, &oldProtect); + memcpy(pOrgEntry, szExecute, sizeof(szExecute)); + VirtualProtect(pOrgEntry, sizeof(szExecute), oldProtect, &oldProtect); + return bRet; } //////////////////////////////////////////////////////////////////////////////// @@ -174,6 +164,8 @@ bool checkExceptionHandler() } #endif +bool self_test = false; + // If this application on Windows platform is a console application, a console is always // created which is bad. Making it a Windows "application" via CMake settings but not // adding any code to explicitly create windows does the right thing. @@ -220,21 +212,29 @@ int main(int argc, char **argv) LL_ERRS("slplugin") << "usage: " << argv[0] << " launcher_port" << LL_ENDL; } - U32 port = 0; - if(!LLStringUtil::convertToU32(argv[1], port)) + U32 port = 61916; // Test port. + if (strcmp(argv[1], "TESTPLUGIN") == 0) + { + std::cout << "Running self test..." << std::endl; + self_test = true; + } + else if (!LLStringUtil::convertToU32(argv[1], port)) { LL_ERRS("slplugin") << "port number must be numeric" << LL_ENDL; } - // Catch signals that most kinds of crashes will generate, and exit cleanly so the system crash dialog isn't shown. - signal(SIGILL, &crash_handler); // illegal instruction + if (!self_test) + { + // Catch signals that most kinds of crashes will generate, and exit cleanly so the system crash dialog isn't shown. + signal(SIGILL, &crash_handler); // illegal instruction # if LL_DARWIN - signal(SIGEMT, &crash_handler); // emulate instruction executed + signal(SIGEMT, &crash_handler); // emulate instruction executed # endif // LL_DARWIN - signal(SIGFPE, &crash_handler); // floating-point exception - signal(SIGBUS, &crash_handler); // bus error - signal(SIGSEGV, &crash_handler); // segmentation violation - signal(SIGSYS, &crash_handler); // non-existent system call invoked + signal(SIGFPE, &crash_handler); // floating-point exception + signal(SIGBUS, &crash_handler); // bus error + signal(SIGSEGV, &crash_handler); // segmentation violation + signal(SIGSYS, &crash_handler); // non-existent system call invoked + } #endif #if LL_DARWIN @@ -247,7 +247,7 @@ int main(int argc, char **argv) plugin->init(port); #if LL_DARWIN - deleteAutoReleasePool(); + deleteAutoReleasePool(); #endif LLTimer timer; diff --git a/indra/llprimitive/CMakeLists.txt b/indra/llprimitive/CMakeLists.txt index e9478bb067..33f51a6f0c 100644 --- a/indra/llprimitive/CMakeLists.txt +++ b/indra/llprimitive/CMakeLists.txt @@ -9,22 +9,30 @@ include(LLMessage) include(LLXML) include(LLPhysicsExtensions) include(Colladadom) +include(LLCharacter) include_directories( ${LLCOMMON_INCLUDE_DIRS} ${LLMATH_INCLUDE_DIRS} ${LLMESSAGE_INCLUDE_DIRS} ${LLXML_INCLUDE_DIRS} - ${LLPHYSICSEXTENSIONS_INCLUDE_DIRS} ${COLLADADOM_INCLUDE_DIRS} + ${LLCHARACTER_INCLUDE_DIRS} + ) +include_directories(SYSTEM + ${LLCOMMON_SYSTEM_INCLUDE_DIRS} + ${LLXML_SYSTEM_INCLUDE_DIRS} + ${LLPHYSICSEXTENSIONS_INCLUDE_DIRS} ) set(llprimitive_SOURCE_FILES + lldaeloader.cpp llmaterialid.cpp llmaterial.cpp llmaterialtable.cpp llmediaentry.cpp llmodel.cpp + llmodelloader.cpp llprimitive.cpp llprimtexturelist.cpp lltextureanim.cpp @@ -37,13 +45,14 @@ set(llprimitive_SOURCE_FILES set(llprimitive_HEADER_FILES CMakeLists.txt - + lldaeloader.h legacy_object_types.h llmaterial.h llmaterialid.h llmaterialtable.h llmediaentry.h llmodel.h + llmodelloader.h llprimitive.h llprimtexturelist.h lltextureanim.h @@ -62,4 +71,9 @@ set_source_files_properties(${llprimitive_HEADER_FILES} list(APPEND llprimitive_SOURCE_FILES ${llprimitive_HEADER_FILES}) add_library (llprimitive ${llprimitive_SOURCE_FILES}) -add_dependencies(llprimitive prepare) + +target_link_libraries( + llprimitive + PUBLIC + llcommon + ) diff --git a/indra/llprimitive/lldaeloader.cpp b/indra/llprimitive/lldaeloader.cpp new file mode 100644 index 0000000000..a6a97cc1e6 --- /dev/null +++ b/indra/llprimitive/lldaeloader.cpp @@ -0,0 +1,2544 @@ +/** + * @file lldaeloader.cpp + * @brief LLDAELoader class implementation + * + * $LicenseInfo:firstyear=2013&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2013, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "lldaeloader.h" +#include "llsdserialize.h" +#include "lljoint.h" + +#include "llmatrix4a.h" + +std::string colladaVersion[VERSIONTYPE_COUNT + 1] = +{ + "1.4.0", + "1.4.1", + "Unsupported" +}; + +static const std::string lod_suffix[LLModel::NUM_LODS] = +{ + "_LOD0", + "_LOD1", + "_LOD2", + "", + "_PHYS", +}; + +const U32 LIMIT_MATERIALS_OUTPUT = 12; +bool get_dom_sources(const domInputLocalOffset_Array& inputs, U32& pos_offset, U32& tc_offset, U32& norm_offset, U32& idx_stride, + domSource*& pos_source, domSource*& tc_source, domSource*& norm_source) +{ + idx_stride = 0; + for (size_t j = 0; j < inputs.getCount(); ++j) + { + const auto& input = inputs[j]; + const auto input_semantic = input->getSemantic(); + // Offset value sanitization / fault tolerance + idx_stride = (U32)llmax((S32)input->getOffset(), (S32)idx_stride); + if (strcmp(COMMON_PROFILE_INPUT_VERTEX, input_semantic) == 0) + { + //found vertex array + const auto& uri = input->getSource(); + const auto elem = uri.getElement(); + const auto vertices = (domVertices*)elem.cast(); + if (!vertices) + { + return false; + } + + const auto& v_inp = vertices->getInput_array(); + for (size_t k = 0; k < v_inp.getCount(); ++k) + { + const auto& v_inp_k = v_inp[k]; + const auto v_inp_semantic = v_inp_k->getSemantic(); + if (strcmp(COMMON_PROFILE_INPUT_POSITION, v_inp_semantic) == 0) + { + pos_offset = input->getOffset(); + const auto& uri = v_inp_k->getSource(); + const auto elem = uri.getElement(); + pos_source = (domSource*)elem.cast(); + } + + if (strcmp(COMMON_PROFILE_INPUT_NORMAL, v_inp_semantic) == 0) + { + norm_offset = input->getOffset(); + const auto& uri = v_inp_k->getSource(); + const auto elem = uri.getElement(); + norm_source = (domSource*)elem.cast(); + } + } + } + + + if (strcmp(COMMON_PROFILE_INPUT_NORMAL, input_semantic) == 0) + { + //found normal array for this triangle list + norm_offset = input->getOffset(); + const auto& uri = input->getSource(); + const auto elem = uri.getElement(); + norm_source = (domSource*)elem.cast(); + } + else if (strcmp(COMMON_PROFILE_INPUT_TEXCOORD, input_semantic) == 0) + { + //found texCoords + tc_offset = input->getOffset(); + const auto& uri = input->getSource(); + const auto elem = uri.getElement(); + tc_source = (domSource*)elem.cast(); + } + } + + idx_stride += 1; + + return true; +} + +LLModel::EModelStatus load_face_from_dom_triangles(std::vector& face_list, std::vector& materials, domTrianglesRef& tri) +{ + LLVolumeFace face; + std::vector verts; + std::vector indices; + + const auto& inputs = tri->getInput_array(); + + U32 pos_offset, tc_offset, norm_offset, idx_stride; + domSource* pos_source = NULL, * tc_source = NULL, * norm_source = NULL; + + if (!get_dom_sources(inputs, pos_offset, tc_offset, norm_offset, idx_stride, pos_source, tc_source, norm_source) || !pos_source) + { + LL_WARNS() << "Could not find dom sources for basic geo data; invalid model." << LL_ENDL; + return LLModel::BAD_ELEMENT; + } + + if (!pos_source || !pos_source->getFloat_array()) + { + LL_WARNS() << "Unable to process mesh without position data; invalid model; invalid model." << LL_ENDL; + return LLModel::BAD_ELEMENT; + } + + const auto p = tri->getP(); + const auto& idx = p->getValue(); + + domListOfFloats dummy; + const auto& v = pos_source ? pos_source->getFloat_array()->getValue() : dummy; + const auto& tc = tc_source ? tc_source->getFloat_array()->getValue() : dummy; + const auto& n = norm_source ? norm_source->getFloat_array()->getValue() : dummy; + + const auto index_count = idx.getCount(); + const auto vertex_count = pos_source ? v.getCount() : 0; + const auto tc_count = tc_source ? tc.getCount() : 0; + const auto norm_count = norm_source ? n.getCount() : 0; + + if (pos_source) + { + if (vertex_count == 0) + { + LL_WARNS() << "Unable to process mesh with empty position array; invalid model." << LL_ENDL; + return LLModel::BAD_ELEMENT; + } + } + + face.mExtents[0].set(v[0], v[1], v[2]); + face.mExtents[1].set(v[0], v[1], v[2]); + + LLVolumeFace::VertexMapData::PointMap point_map; + + for (size_t i = 0; i < index_count; i += idx_stride) + { + LLVolumeFace::VertexData cv; + if (pos_source) + { + // guard against model data specifiying out of range indices or verts + // + const auto p_pos_index = idx[i + pos_offset] * 3; + if (((i + pos_offset) > index_count) + || ((p_pos_index + 2) > vertex_count)) + { + LL_WARNS() << "Out of range index data; invalid model." << LL_ENDL; + return LLModel::BAD_ELEMENT; + } + + const auto cv_position = LLVector4a( + v[p_pos_index], + v[p_pos_index + 1], + v[p_pos_index + 2]); + cv.setPosition(cv_position); + + if (!cv_position.isFinite3()) + { + LL_WARNS() << "Nan positional data, invalid model." << LL_ENDL; + return LLModel::BAD_ELEMENT; + } + } + + if (tc_source) + { + // guard against model data specifiying out of range indices or tcs + // + const auto p_tc_index = idx[i + tc_offset] * 2; + if (((i + tc_offset) > index_count) + || ((p_tc_index + 1) > tc_count)) + { + LL_WARNS() << "Out of range TC indices." << LL_ENDL; + return LLModel::BAD_ELEMENT; + } + + cv.mTexCoord = LLVector2( + tc[p_tc_index], + tc[p_tc_index + 1]); + + if (!cv.mTexCoord.isFinite()) + { + LL_WARNS() << "Found NaN while loading tex coords from DAE-Model, invalid model." << LL_ENDL; + return LLModel::BAD_ELEMENT; + } + } + + if (norm_source) + { + // guard against model data specifiying out of range indices or norms + // + const auto p_norm_index = idx[i + norm_offset] * 3; + if (((i + norm_offset) > index_count) + || ((p_norm_index + 2) > norm_count)) + { + LL_WARNS() << "Found out of range norm indices, invalid model." << LL_ENDL; + return LLModel::BAD_ELEMENT; + } + + const auto cv_normal = LLVector4a( + n[p_norm_index], + n[p_norm_index + 1], + n[p_norm_index + 2]); + cv.setNormal(cv_normal); + + if (!cv_normal.isFinite3()) + { + LL_WARNS() << "Found NaN while loading normals from DAE-Model, invalid model." << LL_ENDL; + return LLModel::BAD_ELEMENT; + } + } + + BOOL found = FALSE; + + const auto pos3 = LLVector3(cv.getPosition().getF32ptr()); + const auto point_iter = point_map.find(pos3); + + if (point_iter != point_map.end()) + { + const auto& vm_data = point_iter->second; + for (const auto& vm : vm_data) + { + // We have a matching loc + // + if (vm == cv) + { + // Don't share verts within the same tri, degenerate + // + const auto index_size = indices.size(); + const auto verts_new_tri = index_size % 3; + if ((verts_new_tri < 1 || indices[index_size - 1] != vm.mIndex) + && (verts_new_tri < 2 || indices[index_size - 2] != vm.mIndex)) + { + found = true; + indices.push_back(vm.mIndex); + } + break; + } + } + } + + if (!found) + { + update_min_max(face.mExtents[0], face.mExtents[1], cv.getPosition()); + verts.push_back(cv); + if (verts.size() >= 0xFFFFU) + { + //LL_ERRS() << "Attempted to write model exceeding 16-bit index buffer limitation." << LL_ENDL; + return LLModel::VERTEX_NUMBER_OVERFLOW; + } + const auto index = (U16)(verts.size() - 1); + indices.push_back(index); + + LLVolumeFace::VertexMapData d; + d.setPosition(cv.getPosition()); + d.mTexCoord = cv.mTexCoord; + d.setNormal(cv.getNormal()); + d.mIndex = index; + + if (point_iter != point_map.end()) + { + point_iter->second.push_back(d); + } + else + { + const auto point = LLVector3(d.getPosition().getF32ptr()); + point_map[point].push_back(d); + } + } + + if (indices.size() % 3 == 0 && verts.size() >= 0xFFFCU) + { + std::string material; + + if (tri->getMaterial()) + { + material = std::string(tri->getMaterial()); + } + + materials.push_back(material); + face_list.push_back(face); + face_list.rbegin()->fillFromLegacyData(verts, indices); + auto& new_face = *face_list.rbegin(); + if (!norm_source) + { + //ll_aligned_free_16(new_face.mNormals); + new_face.mNormals = NULL; + } + + if (!tc_source) + { + //ll_aligned_free_16(new_face.mTexCoords); + new_face.mTexCoords = NULL; + } + + face = LLVolumeFace(); + point_map.clear(); + } + } + + if (!verts.empty()) + { + std::string material; + + if (tri->getMaterial()) + { + material = std::string(tri->getMaterial()); + } + + materials.push_back(material); + face_list.push_back(face); + + face_list.rbegin()->fillFromLegacyData(verts, indices); + auto& new_face = *face_list.rbegin(); + if (!norm_source) + { + //ll_aligned_free_16(new_face.mNormals); + new_face.mNormals = NULL; + } + + if (!tc_source) + { + //ll_aligned_free_16(new_face.mTexCoords); + new_face.mTexCoords = NULL; + } + } + + return LLModel::NO_ERRORS; +} + +LLModel::EModelStatus load_face_from_dom_polylist(std::vector& face_list, std::vector& materials, domPolylistRef& poly) +{ + const auto p = poly->getP(); + const auto& idx = p->getValue(); + + const auto index_count = idx.getCount(); + if (index_count == 0) + { + return LLModel::NO_ERRORS; + } + + const auto& inputs = poly->getInput_array(); + const auto& vcount = poly->getVcount()->getValue(); + + auto pos_offset = 0U, tc_offset = 0U, norm_offset = 0U, idx_stride = 0U; + domSource* pos_source = NULL, * tc_source = NULL, * norm_source = NULL; + + if (!get_dom_sources(inputs, pos_offset, tc_offset, norm_offset, idx_stride, pos_source, tc_source, norm_source)) + { + LL_WARNS() << "Could not get DOM sources for basic geo data, invalid model." << LL_ENDL; + return LLModel::BAD_ELEMENT; + } + + LLVolumeFace face; + + std::vector indices; + std::vector verts; + + domListOfFloats v, tc, n; + + if (pos_source) + { + v = pos_source->getFloat_array()->getValue(); + face.mExtents[0].set(v[0], v[1], v[2]); + face.mExtents[1].set(v[0], v[1], v[2]); + } + + if (tc_source) + { + tc = tc_source->getFloat_array()->getValue(); + } + + if (norm_source) + { + n = norm_source->getFloat_array()->getValue(); + } + + LLVolumeFace::VertexMapData::PointMap point_map; + + const auto vertex_count = pos_source ? v.getCount() : 0; + const auto tc_count = tc_source ? tc.getCount() : 0; + const auto norm_count = norm_source ? n.getCount() : 0; + + size_t cur_idx = 0; + for (size_t i = 0; i < vcount.getCount(); ++i) + { + //for each polygon + auto first_index = (U16)0; + auto last_index = (U16)0; + for (size_t j = 0; j < vcount[i]; ++j) + { + //for each vertex + LLVolumeFace::VertexData cv; + + if (pos_source) + { + // guard against model data specifiying out of range indices or verts + // + const auto cur_idx_offset = cur_idx + pos_offset; + const auto p_pos_index = (size_t)idx[cur_idx_offset] * 3; + if ((cur_idx_offset > index_count) || ((p_pos_index + 2) > vertex_count)) + { + LL_WARNS() << "Out of range position indices, invalid model." << LL_ENDL; + return LLModel::BAD_ELEMENT; + } + + const auto cv_position = LLVector4a( + v[p_pos_index], + v[p_pos_index + 1], + v[p_pos_index + 2]); + cv.setPosition(cv_position); + + if (!cv_position.isFinite3()) + { + LL_WARNS() << "Found NaN while loading position data from DAE-Model, invalid model." << LL_ENDL; + return LLModel::BAD_ELEMENT; + } + + } + + if (tc_source) + { + // guard against model data specifiying out of range indices or tcs + // + const auto cur_idx_offset = cur_idx + tc_offset; + const auto p_tc_index = (size_t)idx[cur_idx_offset] * 2; + if ((cur_idx_offset > index_count) || ((p_tc_index + 1) > tc_count)) + { + LL_WARNS() << "Out of range TC indices, invalid model." << LL_ENDL; + return LLModel::BAD_ELEMENT; + } + + cv.mTexCoord = LLVector2( + tc[p_tc_index], + tc[p_tc_index + 1]); + + if (!cv.mTexCoord.isFinite()) + { + LL_WARNS() << "Found NaN while loading tex coords from DAE-Model, invalid model." << LL_ENDL; + return LLModel::BAD_ELEMENT; + } + } + + if (norm_source) + { + // guard against model data specifiying out of range indices or norms + // + const auto cur_idx_offset = cur_idx + norm_offset; + const auto p_norm_index = (size_t)idx[cur_idx_offset] * 3; + if ((cur_idx_offset > index_count) || ((p_norm_index + 2) > norm_count)) + { + LL_WARNS() << "Out of range norm indices, invalid model." << LL_ENDL; + return LLModel::BAD_ELEMENT; + } + + const auto cv_normal = LLVector4a( + n[p_norm_index], + n[p_norm_index + 1], + n[p_norm_index + 2]); + cv.setNormal(cv_normal); + + if (!cv_normal.isFinite3()) + { + LL_WARNS() << "Found NaN while loading normals from DAE-Model, invalid model." << LL_ENDL; + return LLModel::BAD_ELEMENT; + } + } + + cur_idx += idx_stride; + + BOOL found = FALSE; + + LLVector3 pos3(cv.getPosition().getF32ptr()); + const auto point_iter = point_map.find(pos3); + if (point_iter != point_map.end()) + { + const auto& vm_data = point_iter->second; + for (const auto& vm : vm_data) + { + // If vertex data matches current vertex + if (vm == cv) + { + found = TRUE; + const auto index = vm.mIndex; + if (j == 0) + { + first_index = index; + } + else if (j == 1) + { + last_index = index; + } + else + { + // if these are the same, we have a very, very skinny triangle (coincident verts on one or more edges) + // + llassert((first_index != last_index) && (last_index != index) && (first_index != index)); + indices.push_back(first_index); + indices.push_back(last_index); + indices.push_back(index); + last_index = index; + } + + break; + } + } + } + + if (!found) + { + update_min_max(face.mExtents[0], face.mExtents[1], cv.getPosition()); + verts.push_back(cv); + if (verts.size() >= 0xFFFFU) + { + //LL_ERRS() << "Attempted to write model exceeding 16-bit index buffer limitation." << LL_ENDL; + return LLModel::VERTEX_NUMBER_OVERFLOW; + } + const auto index = (U16)(verts.size() - 1); + + if (j == 0) + { + first_index = index; + } + else if (j == 1) + { + last_index = index; + } + else + { + // detect very skinny degenerate triangles with collapsed edges + // + llassert((first_index != last_index) && (last_index != index) && (first_index != index)); + indices.push_back(first_index); + indices.push_back(last_index); + indices.push_back(index); + last_index = index; + } + + LLVolumeFace::VertexMapData d; + d.setPosition(cv.getPosition()); + d.mTexCoord = cv.mTexCoord; + d.setNormal(cv.getNormal()); + d.mIndex = index; + + if (point_iter != point_map.end()) + { + point_iter->second.push_back(d); + } + else + { + point_map[pos3].push_back(d); + } + } + + if (indices.size() % 3 == 0 && indices.size() >= 0xFFFCU) + { + std::string material; + + if (poly->getMaterial()) + { + material = std::string(poly->getMaterial()); + } + + materials.push_back(material); + face_list.push_back(face); + face_list.rbegin()->fillFromLegacyData(verts, indices); + + auto& new_face = *face_list.rbegin(); + if (!norm_source) + { + //ll_aligned_free_16(new_face.mNormals); + new_face.mNormals = NULL; + } + + if (!tc_source) + { + //ll_aligned_free_16(new_face.mTexCoords); + new_face.mTexCoords = NULL; + } + + face = LLVolumeFace(); + verts.clear(); + indices.clear(); + point_map.clear(); + } + } + } + + if (!verts.empty()) + { + std::string material; + + if (poly->getMaterial()) + { + material = std::string(poly->getMaterial()); + } + + materials.push_back(material); + face_list.push_back(face); + face_list.rbegin()->fillFromLegacyData(verts, indices); + + auto& new_face = *face_list.rbegin(); + if (!norm_source) + { + //ll_aligned_free_16(new_face.mNormals); + new_face.mNormals = NULL; + } + + if (!tc_source) + { + //ll_aligned_free_16(new_face.mTexCoords); + new_face.mTexCoords = NULL; + } + } + + return LLModel::NO_ERRORS; +} + +LLModel::EModelStatus load_face_from_dom_polygons(std::vector& face_list, std::vector& materials, domPolygonsRef& poly) +{ + LLVolumeFace face; + std::vector indices; + std::vector verts; + + const auto& inputs = poly->getInput_array(); + + auto v_offset = 0U, n_offset = 0U, t_offset = 0U, stride = 0U; + domListOfFloats* v = NULL, * n = NULL, * t = NULL; + + for (size_t i = 0; i < inputs.getCount(); ++i) + { + const auto& input = inputs[i]; + const auto input_semantic = input->getSemantic(); + // Offset value sanitization / fault tolerance + stride = (U32)llmax((S32)input->getOffset() + 1, (S32)stride); + if (strcmp(COMMON_PROFILE_INPUT_VERTEX, input_semantic) == 0) + { + //found vertex array + v_offset = input->getOffset(); + + const auto& uri = input->getSource(); + const auto elem = uri.getElement(); + const auto vertices = (domVertices*)elem.cast(); + if (!vertices) + { + LL_WARNS() << "Could not find vertex source, invalid model." << LL_ENDL; + return LLModel::BAD_ELEMENT; + } + const auto& v_inp = vertices->getInput_array(); + for (size_t k = 0; k < v_inp.getCount(); ++k) + { + auto& v_inp_k = v_inp[k]; + if (strcmp(COMMON_PROFILE_INPUT_POSITION, v_inp_k->getSemantic()) == 0) + { + const auto& uri = v_inp_k->getSource(); + const auto elem = uri.getElement(); + const auto src = (domSource*)elem.cast(); + if (!src) + { + LL_WARNS() << "Could not find DOM source, invalid model." << LL_ENDL; + return LLModel::BAD_ELEMENT; + } + v = &(src->getFloat_array()->getValue()); + } + } + } + else if (strcmp(COMMON_PROFILE_INPUT_NORMAL, input_semantic) == 0) + { + //found normal array for this triangle list + n_offset = input->getOffset(); + const auto& uri = input->getSource(); + const auto elem = uri.getElement(); + const auto src = (domSource*)elem.cast(); + if (!src) + { + LL_WARNS() << "Could not find DOM source, invalid model." << LL_ENDL; + return LLModel::BAD_ELEMENT; + } + n = &(src->getFloat_array()->getValue()); + } + else if (strcmp(COMMON_PROFILE_INPUT_TEXCOORD, input_semantic) == 0 && input->getSet() == 0) + { + //found texCoords + t_offset = input->getOffset(); + const auto& uri = input->getSource(); + const auto elem = uri.getElement(); + const auto src = (domSource*)elem.cast(); + if (!src) + { + LL_WARNS() << "Could not find DOM source, invalid model." << LL_ENDL; + return LLModel::BAD_ELEMENT; + } + t = &(src->getFloat_array()->getValue()); + } + } + + const auto& ps = poly->getP_array(); + + //make a triangle list in + for (size_t i = 0; i < ps.getCount(); ++i) + { + //for each polygon + const auto& idx = ps[i]->getValue(); + const auto idx_count_by_stride = idx.getCount() / stride; + for (size_t j = 0; j < idx_count_by_stride; ++j) + { + //for each vertex + if (j > 2) + { + const auto& v0 = verts[(U32)verts.size() - 3]; + const auto& v1 = verts[(U32)verts.size() - 1]; + + verts.push_back(v0); + verts.push_back(v1); + } + + LLVolumeFace::VertexData vert; + + if (v) + { + auto v_idx = (size_t)idx[j * stride + v_offset] * 3; + v_idx = llclamp(v_idx, size_t(0), v->getCount()); + const auto v_pos = LLVector4a( + v->get(v_idx), + v->get(v_idx + 1), + v->get(v_idx + 2)); + vert.setPosition(v_pos); + if (!v_pos.isFinite3()) + { + LL_WARNS() << "Found NaN while loading position data from DAE-Model, invalid model." << LL_ENDL; + return LLModel::BAD_ELEMENT; + } + } + + //bounds check n and t lookups because some FBX to DAE converters + //use negative indices and empty arrays to indicate data does not exist + //for a particular channel + if (n && n->getCount() > 0) + { + auto n_idx = (size_t)idx[j * stride + n_offset] * 3; + n_idx = llclamp(n_idx, size_t(0), n->getCount()); + const auto v_norm = LLVector4a( + n->get(n_idx), + n->get(n_idx + 1), + n->get(n_idx + 2)); + vert.setNormal(v_norm); + if (!v_norm.isFinite3()) + { + LL_WARNS() << "Found NaN while loading normals from DAE-Model, invalid model." << LL_ENDL; + return LLModel::BAD_ELEMENT; + } + } + else + { + vert.getNormal().clear(); + } + + if (t && t->getCount() > 0) + { + auto t_idx = (size_t)idx[j * stride + t_offset] * 2; + t_idx = llclamp(t_idx, size_t(0), t->getCount()); + vert.mTexCoord = LLVector2( + t->get(t_idx), + t->get(t_idx + 1)); + if (!vert.mTexCoord.isFinite()) + { + LL_WARNS() << "Found NaN while loading tex coords from DAE-Model, invalid model." << LL_ENDL; + return LLModel::BAD_ELEMENT; + } + } + else + { + vert.mTexCoord.clear(); + } + + verts.push_back(vert); + } + } + + if (verts.empty()) + { + return LLModel::NO_ERRORS; + } + + face.mExtents[0] = verts[0].getPosition(); + face.mExtents[1] = verts[0].getPosition(); + + //create a map of unique vertices to indices + std::map vert_idx; + + auto cur_idx = 0U; + for (size_t i = 0; i < verts.size(); ++i) + { + auto iter = vert_idx.find(verts[i]); + if (iter == vert_idx.end()) + { + vert_idx[verts[i]] = cur_idx++; + } + } + + //build vertex array from map + std::vector new_verts; + new_verts.resize(vert_idx.size()); + + for (const auto& iter : vert_idx) + { + new_verts[iter.second] = iter.first; + update_min_max(face.mExtents[0], face.mExtents[1], iter.first.getPosition()); + } + + //build index array from map + indices.resize(verts.size()); + + for (size_t i = 0; i < verts.size(); ++i) + { + indices[i] = vert_idx[verts[i]]; + llassert(!i || (indices[i - 1] != indices[i])); + } + + // DEBUG just build an expanded triangle list + /*for (U32 i = 0; i < verts.size(); ++i) + { + indices.push_back((U16) i); + update_min_max(face.mExtents[0], face.mExtents[1], verts[i].getPosition()); + }*/ + + if (!new_verts.empty()) + { + std::string material; + + if (poly->getMaterial()) + { + material = std::string(poly->getMaterial()); + } + + materials.push_back(material); + face_list.push_back(face); + face_list.rbegin()->fillFromLegacyData(new_verts, indices); + + auto& new_face = *face_list.rbegin(); + if (!n) + { + //ll_aligned_free_16(new_face.mNormals); + new_face.mNormals = NULL; + } + + if (!t) + { + //ll_aligned_free_16(new_face.mTexCoords); + new_face.mTexCoords = NULL; + } + } + + return LLModel::NO_ERRORS; +} + +//----------------------------------------------------------------------------- +// LLDAELoader +//----------------------------------------------------------------------------- +LLDAELoader::LLDAELoader( + std::string filename, + S32 lod, + load_callback_t load_cb, + joint_lookup_func_t joint_lookup_func, + texture_load_func_t texture_load_func, + state_callback_t state_cb, + void* opaque_userdata, + JointTransformMap& jointTransformMap, + JointNameSet& jointsFromNodes, + std::map& jointAliasMap, + U32 maxJointsPerMesh, + U32 modelLimit, + bool preprocess) + : LLModelLoader( + filename, + lod, + load_cb, + joint_lookup_func, + texture_load_func, + state_cb, + opaque_userdata, + jointTransformMap, + jointsFromNodes, + jointAliasMap, + maxJointsPerMesh), + mGeneratedModelLimit(modelLimit), + mPreprocessDAE(preprocess) +{ +} + +LLDAELoader::~LLDAELoader() +{ +} + +struct ModelSort +{ + bool operator()(const LLPointer< LLModel >& lhs, const LLPointer< LLModel >& rhs) + { + if (lhs->mSubmodelID < rhs->mSubmodelID) + { + return true; + } + return LLStringUtil::compareInsensitive(lhs->mLabel, rhs->mLabel) < 0; + } +}; + +bool LLDAELoader::OpenFile(const std::string& filename) +{ + //no suitable slm exists, load from the .dae file + DAE dae; + domCOLLADA* dom; + if (mPreprocessDAE) + { + dom = dae.openFromMemory(filename, preprocessDAE(filename).c_str()); + } + else + { + LL_INFOS() << "Skipping dae preprocessing" << LL_ENDL; + dom = dae.open(filename); + } + + if (!dom) + { + LL_INFOS() << " Error with dae - traditionally indicates a corrupt file." << LL_ENDL; + setLoadState(ERROR_PARSING); + return false; + } + + //Dom version + const auto domVersion = dae.getDomVersion(); + std::string sldom(domVersion); + LL_INFOS() << "Collada Importer Version: " << sldom << LL_ENDL; + + //Dae version + auto docVersion = dom->getVersion(); + //0=1.4 + //1=1.4.1 + //2=Currently unsupported, however may work + if (docVersion > 1) + { + docVersion = VERSIONTYPE_COUNT; + } + LL_INFOS() << "Dae version " << colladaVersion[docVersion] << LL_ENDL; + + const auto db = dae.getDatabase(); + + const auto doc = dae.getDoc(filename); + if (!doc) + { + LL_WARNS() << "can't find internal doc" << LL_ENDL; + return false; + } + + const auto root = doc->getDomRoot(); + if (!root) + { + LL_WARNS() << "document has no root" << LL_ENDL; + return false; + } + + //Verify some basic properties of the dae + //1. Basic validity check on controller + const auto controllerCount = db->getElementCount(NULL, "controller"); + bool result = false; + for (size_t i = 0; i < controllerCount; ++i) + { + domController* pController = NULL; + db->getElement((daeElement**)&pController, i, NULL, "controller"); + result = verifyController(pController); + if (!result) + { + LL_INFOS() << "Could not verify controller" << LL_ENDL; + setLoadState(ERROR_PARSING); + return true; + } + } + + //get unit scale + mTransform.setIdentity(); + + auto unit = daeSafeCast(root->getDescendant(daeElement::matchType(domAsset::domUnit::ID()))); + + if (unit) + { + auto meter = (F32)unit->getMeter(); + mTransform.mMatrix[0][0] = meter; + mTransform.mMatrix[1][1] = meter; + mTransform.mMatrix[2][2] = meter; + } + + //get up axis rotation + LLMatrix4 rotation; + + auto up = UPAXISTYPE_Y_UP; // default is Y_UP + const auto up_axis = daeSafeCast(root->getDescendant(daeElement::matchType(domAsset::domUp_axis::ID()))); + + if (up_axis) + { + up = up_axis->getValue(); + } + + if (up == UPAXISTYPE_X_UP) + { + rotation.initRotation(0.0f, 90.0f * DEG_TO_RAD, 0.0f); + } + else if (up == UPAXISTYPE_Y_UP) + { + rotation.initRotation(90.0f * DEG_TO_RAD, 0.0f, 0.0f); + } + + rotation *= mTransform; + mTransform = rotation; + + mTransform.condition(); + + const auto mesh_count = db->getElementCount(NULL, COLLADA_TYPE_MESH); + const auto submodel_limit = mesh_count > 0 ? mGeneratedModelLimit / mesh_count : 0; + for (size_t idx = 0; idx < mesh_count; ++idx) + { + //build map of domEntities to LLModel + domMesh* mesh = NULL; + db->getElement((daeElement**)&mesh, idx, NULL, COLLADA_TYPE_MESH); + + if (mesh) + { + std::vector models; + loadModelsFromDomMesh(mesh, models, submodel_limit); + for (const auto& mdl : models) + { + if (mdl->getStatus() != LLModel::NO_ERRORS) + { + setLoadState(ERROR_MODEL + mdl->getStatus()); + return false; //abort + } + + if (mdl && validate_model(mdl)) + { + mModelList.push_back(mdl); + mModelsMap[mesh].push_back(mdl); + } + } + } + } + + std::sort(mModelList.begin(), mModelList.end(), ModelSort()); + + for (const auto mdl : mModelList) + { + const auto material_count = mdl->mMaterialList.size(); + LL_INFOS() << "Importing " << mdl->mLabel << " model with " << material_count << " material references" << LL_ENDL; + + auto mat_iter = mdl->mMaterialList.begin(); + const auto end_iter = material_count > LIMIT_MATERIALS_OUTPUT + ? mat_iter + LIMIT_MATERIALS_OUTPUT + : mdl->mMaterialList.end(); + for (; mat_iter != end_iter; ++mat_iter) + { + LL_INFOS() << mdl->mLabel << " references " << (*mat_iter) << LL_ENDL; + } + } + + const auto skin_count = db->getElementCount(NULL, COLLADA_TYPE_SKIN); + LL_INFOS() << "Collada skins to be processed: " << skin_count << LL_ENDL; + + const auto scene = root->getDescendant("visual_scene"); + + if (!scene) + { + LL_WARNS() << "document has no visual_scene" << LL_ENDL; + setLoadState(ERROR_PARSING); + return true; + } + + setLoadState(DONE); + + bool badElement = false; + + processElement(scene, badElement, &dae, root); + + if (badElement) + { + LL_INFOS() << "Scene could not be parsed" << LL_ENDL; + setLoadState(ERROR_PARSING); + } + + return true; +} + +std::string LLDAELoader::preprocessDAE(const std::string filename) +{ + // Open a DAE file for some preprocessing (like removing space characters in IDs), see MAINT-5678 + std::ifstream inFile; + inFile.open(filename.c_str(), std::ios_base::in); + std::stringstream strStream; + strStream << inFile.rdbuf(); + std::string buffer = strStream.str(); + + LL_INFOS() << "Preprocessing dae file to remove spaces from the names, ids, etc." << LL_ENDL; + + try + { + boost::regex re("\"[\\w\\.@#$-]*(\\s[\\w\\.@#$-]*)+\""); + boost::sregex_iterator next(buffer.begin(), buffer.end(), re); + boost::sregex_iterator end; + while (next != end) + { + const auto match = *next; + auto s = match.str(); + LL_INFOS() << s << " found" << LL_ENDL; + boost::replace_all(s, " ", "_"); + LL_INFOS() << "Replacing with " << s << LL_ENDL; + boost::replace_all(buffer, match.str(), s); + ++next; + } + } + catch (boost::regex_error&) + { + LL_INFOS() << "Regex error" << LL_ENDL; + } + + return buffer; +} + +void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, domMesh* mesh, domSkin* skin) +{ + llassert(model && dae && mesh && skin); + + if (model) + { + LLVector3 mesh_scale_vector; + LLVector3 mesh_translation_vector; + model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); + + LLMatrix4 normalized_transformation; + normalized_transformation.setTranslation(mesh_translation_vector); + + LLMatrix4 mesh_scale; + mesh_scale.initScale(mesh_scale_vector); + mesh_scale *= normalized_transformation; + normalized_transformation = mesh_scale; + + LLMatrix4a inv_mat; + inv_mat.loadu(normalized_transformation); + inv_mat.invert(); + + LLMatrix4 inverse_normalized_transformation(inv_mat.getF32ptr()); + + const auto bind_mat = skin->getBind_shape_matrix(); + + if (bind_mat) + { + //get bind shape matrix + const auto& dom_value = bind_mat->getValue(); + + auto& skin_info = model->mSkinInfo; + + for (size_t i = 0; i < 4; ++i) + { + for (size_t j = 0; j < 4; ++j) + { + skin_info.mBindShapeMatrix.mMatrix[i][j] = dom_value[i + j * 4]; + } + } + + auto trans = normalized_transformation; + trans *= skin_info.mBindShapeMatrix; + trans *= mBindTransform; + + skin_info.mBindShapeMatrix = trans; + } + + // Build the joint to node mapping array and update joint aliases (mJointMap) + buildJointToNodeMappingFromScene(root); + + //Some collada setup for accessing the skeleton + const auto skeleton_count = dae->getDatabase()->getElementCount(NULL, "skeleton"); + std::vector skeletons; + for (size_t i = 0; i < skeleton_count; ++i) + { + daeElement* pElement = NULL; + dae->getDatabase()->getElement(&pElement, i, 0, "skeleton"); + + //Try to get at the skeletal instance controller + const auto pSkeleton = daeSafeCast(pElement); + daeElement* pSkeletonRootNode = NULL; + if (pSkeleton) + { + pSkeletonRootNode = pSkeleton->getValue().getElement(); + } + if (pSkeleton && pSkeletonRootNode) + { + skeletons.push_back(pSkeleton); + } + } + bool missingSkeletonOrScene = false; + + //If no skeleton, do a breadth-first search to get at specific joints + if (skeletons.size() == 0) + { + const auto pScene = root->getDescendant("visual_scene"); + if (!pScene) + { + LL_WARNS() << "No visual scene - unable to parse bone offsets " << LL_ENDL; + missingSkeletonOrScene = true; + } + else + { + //Get the children at this level + const auto children = pScene->getChildren(); + + //Process any children that are joints + //Not all children are joints, some code be ambient lights, cameras, geometry etc.. + for (size_t i = 0; i < children.getCount(); ++i) + { + const auto pNode = daeSafeCast(children[i]); + if (isNodeAJoint(pNode)) + { + processJointNode(pNode, mJointList); + } + } + } + } + else + { + //Has one or more skeletons + for (const auto& pSkeleton : skeletons) + { + //Get the root node of the skeleton + if (const auto pSkeletonRootNode = pSkeleton->getValue().getElement()) + { + //Once we have the root node - start acccessing it's joint components + //Loop over all the possible joints within the .dae - using the allowed joint list in the ctor. + for (const auto& jointPair : mJointMap) + { + //Build a joint for the resolver to work with and set up the resolver + char str[64] = { 0 }; + snprintf(str, 64, "./%s", jointPair.first.c_str()); + daeSIDResolver resolver(pSkeletonRootNode, str); + + //Look for the joint + if (const auto pJoint = daeSafeCast(resolver.getElement())) + { + // FIXME this has a lot of overlap with processJointNode(), would be nice to refactor. + + //Pull out the translate id and store it in the jointTranslations map + daeSIDResolver jointResolverA(pJoint, "./translate"); + daeSIDResolver jointResolverB(pJoint, "./location"); + LLMatrix4 workingTransform; + + + if (const auto pTranslateA = daeSafeCast(jointResolverA.getElement())) + { + extractTranslation(pTranslateA, workingTransform); + } + else if (const auto pTranslateB = daeSafeCast(jointResolverB.getElement())) + { + extractTranslation(pTranslateB, workingTransform); + } + else if (const auto pTranslateElement = getChildFromElement(pJoint, "translate")) + { + if (const auto pTranslateC = daeSafeCast(pTranslateElement)) + { + //Translation via child from element + extractTranslation(pTranslateC, workingTransform); + } + else + { + LL_WARNS() << "The found element is not a translate node" << LL_ENDL; + missingSkeletonOrScene = true; + } + } + else + { + //Translation via SID + extractTranslationViaSID(pJoint, workingTransform); + } + + //Store the joint transform w/respect to it's name. + mJointList[jointPair.second.c_str()] = workingTransform; + } + } + + //If anything failed in regards to extracting the skeleton, joints or translation id, + //mention it + if (missingSkeletonOrScene) + { + LL_WARNS() << "Partial jointmap found in asset - did you mean to just have a partial map?" << LL_ENDL; + } + } //got skeleton? + } + } + + const auto joints = skin->getJoints(); + + const auto& joint_input = joints->getInput_array(); + for (size_t i = 0; i < joint_input.getCount(); ++i) + { + const auto input = joint_input.get(i); + const auto semantic = input->getSemantic(); + if (strcmp(semantic, COMMON_PROFILE_INPUT_JOINT) == 0) + { + //found joint source, fill model->mJointMap and model->mSkinInfo.mJointNames + const auto elem = input->getSource().getElement(); + if (const auto source = daeSafeCast(elem)) + { + // TODO: DRY this code + if (auto names_source = source->getName_array()) + { + const auto& names = names_source->getValue(); + for (size_t j = 0; j < names.getCount(); ++j) + { + std::string name(names.get(j)); + const auto& joint_found = mJointMap.find(name); + if (joint_found != mJointMap.end()) + { + name = joint_found->second; + } + model->mSkinInfo.mJointNames.push_back(name); + model->mSkinInfo.mJointNums.push_back(-1); + } + } + else if (auto names_source = source->getIDREF_array()) + { + const auto& names = names_source->getValue(); + for (size_t j = 0; j < names.getCount(); ++j) + { + std::string name(names.get(j).getID()); + const auto& joint_found = mJointMap.find(name); + if (joint_found != mJointMap.end()) + { + name = joint_found->second; + } + model->mSkinInfo.mJointNames.push_back(name); + model->mSkinInfo.mJointNums.push_back(-1); + } + } + } + } + else if (strcmp(semantic, COMMON_PROFILE_INPUT_INV_BIND_MATRIX) == 0) + { + //found inv_bind_matrix array, fill model->mInvBindMatrix + if (const auto source = daeSafeCast(input->getSource().getElement())) + { + if (const auto t = source->getFloat_array()) + { + const auto& transform = t->getValue(); + const auto n_transforms = transform.getCount() / 16; + + for (size_t k = 0; k < n_transforms; ++k) + { + LLMatrix4 mat; + for (size_t i = 0; i < 4; ++i) + { + for (size_t j = 0; j < 4; ++j) + { + mat.mMatrix[i][j] = transform[k * 16 + i + j * 4]; + } + } + model->mSkinInfo.mInvBindMatrix.push_back(mat); + } + } + } + } + } + + //Now that we've parsed the joint array, let's determine if we have a full rig + //(which means we have all the joint sthat are required for an avatar versus + //a skinned asset attached to a node in a file that contains an entire skeleton, + //but does not use the skeleton). + critiqueRigForUploadApplicability(model->mSkinInfo.mJointNames); + + if (!missingSkeletonOrScene) + { + // FIXME: mesh_id is used to determine which mesh gets to + // set the joint offset, in the event of a conflict. Since + // we don't know the mesh id yet, we can't guarantee that + // joint offsets will be applied with the same priority as + // in the uploaded model. If the file contains multiple + // meshes with conflicting joint offsets, preview may be + // incorrect. + LLUUID fake_mesh_id; + fake_mesh_id.generate(); + + //The joints are reset in the dtor + //if ( getRigWithSceneParity() ) + { + for (const auto& masterJointPair : mJointMap) + { + const auto lookingForJoint = masterJointPair.first; + const auto& joint_found = mJointList.find(lookingForJoint); + if (joint_found != mJointList.end()) + { + //LL_INFOS()<<"joint "<second; + const auto& joint_pos = jointTransform.getTranslation(); + if (pJoint->aboveJointPosThreshold(joint_pos)) + { + bool override_changed; // not used + pJoint->addAttachmentPosOverride(joint_pos, fake_mesh_id, "", override_changed); + if (model->mSkinInfo.mLockScaleIfJointPosition) + { + pJoint->addAttachmentScaleOverride(pJoint->getDefaultScale(), fake_mesh_id, ""); + } + } + } + else + { + //Most likely an error in the asset. + LL_WARNS() << "Tried to apply joint position from .dae, but it did not exist in the avatar rig." << LL_ENDL; + } + } + } + } + } //missingSkeletonOrScene + + //We need to construct the alternate bind matrix (which contains the new joint positions) + //in the same order as they were stored in the joint buffer. The joints associated + //with the skeleton are not stored in the same order as they are in the exported joint buffer. + //This remaps the skeletal joints to be in the same order as the joints stored in the model. + + for (auto const& joint : model->mSkinInfo.mJointNames | boost::adaptors::indexed(0)) + { + std::string lookingForJoint = joint.value().c_str(); + //Look for the joint xform that we extracted from the skeleton, using the jointIt as the key + //and store it in the alternate bind matrix + if (mJointMap.find(lookingForJoint) != mJointMap.end()) + { + auto newInverse = model->mSkinInfo.mInvBindMatrix[joint.index()]; + newInverse.setTranslation(mJointList[lookingForJoint].getTranslation()); + model->mSkinInfo.mAlternateBindMatrix.push_back(newInverse); + } + else + { + LL_DEBUGS("Mesh") << "Possibly misnamed/missing joint [" << lookingForJoint.c_str() << "] " << LL_ENDL; + } + } + + //get raw position array + if (auto verts = mesh->getVertices()) + { + const auto& inputs = verts->getInput_array(); + const auto inputs_count = inputs.getCount(); + for (size_t i = 0; i < inputs_count && model->mPosition.empty(); ++i) + { + if (strcmp(inputs[i]->getSemantic(), COMMON_PROFILE_INPUT_POSITION) == 0) + { + if (const auto* pos_source = daeSafeCast(inputs[i]->getSource().getElement())) + { + if (const auto pos_array = pos_source->getFloat_array()) + { + const auto& pos = pos_array->getValue(); + const auto pos_count = pos.getCount(); + for (size_t j = 0; j < pos_count; j += 3) + { + if (pos_count <= j + 2) + { + LL_ERRS() << "Invalid position array size." << LL_ENDL; + } + + LLVector3 v(pos[j], pos[j + 1], pos[j + 2]); + + //transform from COLLADA space to volume space + v = v * inverse_normalized_transformation; + + model->mPosition.push_back(v); + } + } + } + } + } + } + + //get skin weights array + if (auto weights = skin->getVertex_weights()) + { + const auto& inputs = weights->getInput_array(); + domFloat_array* vertex_weights = NULL; + for (size_t i = 0; i < inputs.getCount(); ++i) + { + if (strcmp(inputs[i]->getSemantic(), COMMON_PROFILE_INPUT_WEIGHT) == 0) + { + if (const auto weight_source = daeSafeCast(inputs[i]->getSource().getElement())) + { + vertex_weights = weight_source->getFloat_array(); + } + } + } + + if (vertex_weights) + { + const auto& w = vertex_weights->getValue(); + const auto& vcount = weights->getVcount()->getValue(); + const auto vcount_count = vcount.getCount(); // sure ok + const auto& v = weights->getV()->getValue(); + auto c_idx = 0; + for (auto vc_idx = 0; vc_idx < vcount_count; ++vc_idx) + { + //for each vertex + //create list of weights that influence this vertex + LLModel::weight_list weight_list; + + const auto count = vcount[vc_idx]; + for (daeUInt i = 0; i < count; ++i) + { + //for each weight + const auto joint_idx = v[c_idx++]; + const auto weight_idx = v[c_idx++]; + + if (joint_idx == -1) + { + //ignore bindings to bind_shape_matrix + continue; + } + + const auto weight_value = (F32)w[weight_idx]; + + weight_list.push_back(LLModel::JointWeight(joint_idx, weight_value)); + } + + //sort by joint weight + std::sort(weight_list.begin(), weight_list.end(), LLModel::CompareWeightGreater()); + + std::vector wght; + + auto total = 0.f; + const auto n_weights = llmin(size_t(4), weight_list.size()); + for (size_t i = 0; i < n_weights; ++i) + { + //take up to 4 most significant weights + const auto weight = weight_list[i]; + const auto weight_value = weight.mWeight; + if (weight_value > 0.f) + { + wght.push_back(weight); + total += weight_value; + } + } + + if (total != 1.f) + { + //normalize weights + const auto scale = 1.f / total; + for (size_t i = 0; i < wght.size(); ++i) + { + wght[i].mWeight *= scale; + } + } + + model->mSkinWeights[model->mPosition[vc_idx]] = wght; + } + } + + } + //add instance to scene for this model + + LLMatrix4 transformation; + transformation.initScale(mesh_scale_vector); + transformation.setTranslation(mesh_translation_vector); + transformation *= mTransform; + + material_map materials; + for (const auto& m : model->mMaterialList) + { + materials[m] = LLImportMaterial(); + } + mScene[transformation].push_back(LLModelInstance(model, model->mLabel, transformation, materials)); + stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform); + } +} + +//----------------------------------------------------------------------------- +// buildJointToNodeMappingFromScene() +//----------------------------------------------------------------------------- +void LLDAELoader::buildJointToNodeMappingFromScene(daeElement* pRoot) +{ + const auto pScene = pRoot->getDescendant("visual_scene"); + if (pScene) + { + const auto children = pScene->getChildren(); + for (size_t i = 0; i < children.getCount(); ++i) + { + const auto pNode = daeSafeCast(children[i]); + processJointToNodeMapping(pNode); + } + } +} +//----------------------------------------------------------------------------- +// processJointToNodeMapping() +//----------------------------------------------------------------------------- +void LLDAELoader::processJointToNodeMapping(domNode* pNode) +{ + if (isNodeAJoint(pNode)) + { + //1.Store the parent + const auto nodeName = std::string(pNode->getName()); + if (!nodeName.empty()) + { + mJointsFromNode.push_front(nodeName); + // Alias joint node SIDs to joint names for compatibility + const auto nodeSID = std::string(pNode->getSid()); + if (!nodeSID.empty()) + mJointMap[nodeSID] = mJointMap[nodeName]; + } + //2. Handle the kiddo's + processChildJoints(pNode); + } + else + { + //Determine if the're any children wrt to this failed node. + //This occurs when an armature is exported and ends up being what essentially amounts to + //as the root for the visual_scene + if (pNode) + { + processChildJoints(pNode); + } + else + { + LL_INFOS() << "Node is NULL" << LL_ENDL; + } + + } +} +//----------------------------------------------------------------------------- +// processChildJoint() +//----------------------------------------------------------------------------- +void LLDAELoader::processChildJoints(domNode* pParentNode) +{ + const auto childOfChild = pParentNode->getChildren(); + for (size_t i = 0; i < childOfChild.getCount(); ++i) + { + const auto pChildNode = daeSafeCast(childOfChild[i]); + if (pChildNode) + { + processJointToNodeMapping(pChildNode); + } + } +} + +//----------------------------------------------------------------------------- +// isNodeAJoint() +//----------------------------------------------------------------------------- +bool LLDAELoader::isNodeAJoint(const domNode* pNode) const +{ + if (pNode) + { + if (const auto pNodeName = pNode->getName()) + { + return LLModelLoader::isNodeAJoint(pNodeName); + } + } + LL_INFOS() << "Created node is NULL or invalid" << LL_ENDL; + return false; +} +//----------------------------------------------------------------------------- +// verifyCount +//----------------------------------------------------------------------------- +bool LLDAELoader::verifyCount(const size_t expected, const size_t result) const +{ + if (expected != result) + { + LL_INFOS() << "Error: (expected/got)" << expected << "/" << result << "verts" << LL_ENDL; + return false; + } + return true; +} +//----------------------------------------------------------------------------- +// verifyController +//----------------------------------------------------------------------------- +bool LLDAELoader::verifyController(const domController* pController) const +{ + bool result = true; + + if (const auto pSkin = pController->getSkin()) + { + const auto& uri = pSkin->getSource(); + const auto pElement = uri.getElement(); + + if (!pElement) + { + LL_INFOS() << "Can't resolve skin source" << LL_ENDL; + return false; + } + + const auto type_str = pElement->getTypeName(); + if (stricmp(type_str, "geometry") == 0) + { + //Skin is reference directly by geometry and get the vertex count from skin + const auto pVertexWeights = pSkin->getVertex_weights(); + const auto vertexWeightsCount = pVertexWeights->getCount(); + const auto pGeometry = (domGeometry*)(domElement*)uri.getElement(); + if (const auto pMesh = pGeometry->getMesh()) + { + //Get vertex count from geometry + if (const auto pVertices = pMesh->getVertices()) + { + const auto src = pVertices->getInput_array()[0]->getSource(); + const auto pSource = (domSource*)(domElement*)src.getElement(); + const auto verticesCount = pSource->getTechnique_common()->getAccessor()->getCount(); + result = verifyCount(verticesCount, vertexWeightsCount); + if (!result) + { + return false; + } + } + else + { + LL_INFOS() << "No vertices!" << LL_ENDL; + return false; + } + } + + const auto vcount_count = pVertexWeights->getVcount()->getValue().getCount(); + result = verifyCount(vcount_count, vertexWeightsCount); + if (!result) + { + return false; + } + + const auto& inputs = pVertexWeights->getInput_array(); + size_t sum = 0; + for (size_t i = 0; i < vcount_count; ++i) + { + sum += pVertexWeights->getVcount()->getValue()[i]; + } + result = verifyCount(sum * inputs.getCount(), (domInt)pVertexWeights->getV()->getValue().getCount()); + } + } + + return result; +} + +//----------------------------------------------------------------------------- +// extractTranslation() +//----------------------------------------------------------------------------- +void LLDAELoader::extractTranslation(const domTranslate* pTranslate, LLMatrix4& transform) const +{ + const auto& jointTrans = pTranslate->getValue(); + LLVector3 singleJointTranslation(jointTrans[0], jointTrans[1], jointTrans[2]); + transform.setTranslation(singleJointTranslation); +} + +//----------------------------------------------------------------------------- +// extractTranslationViaSID() +//----------------------------------------------------------------------------- +void LLDAELoader::extractTranslationViaSID(daeElement* pElement, LLMatrix4& transform) const +{ + if (pElement) + { + daeSIDResolver resolver(pElement, "./transform"); + const auto pMatrix = daeSafeCast(resolver.getElement()); + //We are only extracting out the translational component atm + LLMatrix4 workingTransform; + if (pMatrix) + { + const auto domArray = pMatrix->getValue(); + for (size_t i = 0; i < 4; ++i) + { + for (size_t j = 0; j < 4; ++j) + { + workingTransform.mMatrix[i][j] = domArray[i + j * 4]; + } + } + const auto trans = workingTransform.getTranslation(); + transform.setTranslation(trans); + } + } + else + { + LL_WARNS() << "Element is nonexistent - empty/unsupported node." << LL_ENDL; + } +} +//----------------------------------------------------------------------------- +// processJointNode() +//----------------------------------------------------------------------------- +void LLDAELoader::processJointNode(domNode* pNode, JointTransformMap& jointTransforms) +{ + if (pNode->getName() == NULL) + { + LL_WARNS() << "nameless node, can't process" << LL_ENDL; + return; + } + + //llwarns<<"ProcessJointNode# Node:" <getName()<(jointResolverA.getElement())) + { + extractTranslation(pTranslateA, workingTransform); + } + else if (const auto pTranslateB = daeSafeCast(jointResolverB.getElement())) + { + extractTranslation(pTranslateB, workingTransform); + } + else + { + const auto pTranslateElement = getChildFromElement(pNode, "translate"); + if (const auto pTranslateC = daeSafeCast(pTranslateElement)) + { + extractTranslation(pTranslateC, workingTransform); + } + else + { + daeSIDResolver jointResolver(pNode, "./matrix"); + if (const auto pMatrix = daeSafeCast(jointResolver.getElement())) + { + //LL_INFOS() <<"A matrix SID was however found!"<getValue(); + for (size_t i = 0; i < 4; ++i) + { + for (size_t j = 0; j < 4; ++j) + { + workingTransform.mMatrix[i][j] = domArray[i + j * 4]; + } + } + } + else + { + LL_WARNS() << "The found element is not translate or matrix node - most likely a corrupt export!" << LL_ENDL; + } + } + } + + //Store the working transform relative to the nodes name. + jointTransforms[pNode->getName()] = workingTransform; + + //2. handle the nodes children + + //Gather and handle the incoming nodes children + const auto childOfChild = pNode->getChildren(); + const auto childOfChildCount = childOfChild.getCount(); + + for (size_t i = 0; i < childOfChildCount; ++i) + { + if (const auto pChildNode = daeSafeCast(childOfChild[i])) + { + processJointNode(pChildNode, jointTransforms); + } + } +} + +//----------------------------------------------------------------------------- +// getChildFromElement() +//----------------------------------------------------------------------------- +daeElement* LLDAELoader::getChildFromElement(daeElement* pElement, std::string const& name) +{ + daeElement* pChildOfElement = pElement->getChild(name.c_str()); + if (pChildOfElement) + { + return pChildOfElement; + } + LL_DEBUGS("Mesh") << "Could not find a child [" << name << "] for the element: \"" << pElement->getAttribute("id") << "\"" << LL_ENDL; + return NULL; +} + +void LLDAELoader::processElement(daeElement* element, bool& badElement, DAE* dae, daeElement* domRoot) +{ + LLMatrix4 saved_transform, saved_bind_transform; + bool pushed_mat = false; + + if (const auto node = daeSafeCast(element)) + { + pushed_mat = true; + saved_transform = mTransform; + saved_bind_transform = mBindTransform; + } + + if (const auto translate = daeSafeCast(element)) + { + const auto dom_value = translate->getValue(); + + LLMatrix4 translation, translation2; + translation.setTranslation(LLVector3(dom_value[0], dom_value[1], dom_value[2])); + translation2 = translation; + + translation *= mTransform; + mTransform = translation; + mTransform.condition(); + + translation2 *= mBindTransform; + mBindTransform = translation2; + mBindTransform.condition(); + } + + if (const auto rotate = daeSafeCast(element)) + { + const auto dom_value = rotate->getValue(); + + LLMatrix4 rotation, rotation2; + rotation.initRotTrans(dom_value[3] * DEG_TO_RAD, LLVector3(dom_value[0], dom_value[1], dom_value[2]), LLVector3(0, 0, 0)); + rotation2 = rotation; + + rotation *= mTransform; + mTransform = rotation; + mTransform.condition(); + + rotation2 *= mBindTransform; + mBindTransform = rotation2; + mBindTransform.condition(); + } + + if (const auto scale = daeSafeCast(element)) + { + const auto dom_value = scale->getValue(); + + auto scale_vector = LLVector3(dom_value[0], dom_value[1], dom_value[2]); + scale_vector.abs(); // Set all values positive, since we don't currently support mirrored meshes + LLMatrix4 scaling, scaling2; + scaling.initScale(scale_vector); + scaling2 = scaling; + + scaling *= mTransform; + mTransform = scaling; + mTransform.condition(); + + scaling2 *= mBindTransform; + mBindTransform = scaling2; + mBindTransform.condition(); + } + + if (const auto matrix = daeSafeCast(element)) + { + const auto dom_value = matrix->getValue(); + + LLMatrix4 matrix_transform, matrix_transform2; + + for (size_t i = 0; i < 4; ++i) + { + for (size_t j = 0; j < 4; ++j) + { + matrix_transform.mMatrix[i][j] = dom_value[i + j * 4]; + } + } + + matrix_transform2 = matrix_transform; + + matrix_transform *= mTransform; + mTransform = matrix_transform; + mTransform.condition(); + + matrix_transform2 *= mBindTransform; + mBindTransform = matrix_transform2; + mBindTransform.condition(); + } + + // Process instance_geometry for static meshes + if (const auto instance_geo = daeSafeCast(element)) + { + if (const auto geo = daeSafeCast(instance_geo->getUrl().getElement())) + { + if (const auto mesh = daeSafeCast(geo->getDescendant(daeElement::matchType(domMesh::ID())))) + { + for (auto& model : mModelsMap[mesh]) + { + auto transformation = mTransform; + + if (mTransform.determinant() < 0) + { + //negative scales are not supported + LL_INFOS() << "Negative scale detected, unsupported transform. domInstance_geometry: " << getElementLabel(instance_geo) << LL_ENDL; + badElement = true; + } + + auto materials = getMaterials(model, instance_geo, dae); + + // adjust the transformation to compensate for mesh normalization + LLVector3 mesh_scale_vector; + LLVector3 mesh_translation_vector; + model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); + + LLMatrix4 mesh_translation; + mesh_translation.setTranslation(mesh_translation_vector); + mesh_translation *= transformation; + transformation = mesh_translation; + + LLMatrix4 mesh_scale; + mesh_scale.initScale(mesh_scale_vector); + mesh_scale *= transformation; + transformation = mesh_scale; + + if (transformation.determinant() < 0) + { + //negative scales are not supported + LL_INFOS() << "Negative scale detected, unsupported post-normalization transform. domInstance_geometry: " << getElementLabel(instance_geo) << LL_ENDL; + badElement = true; + } + + std::string label; + + if (model->mLabel.empty()) + { + label = getLodlessLabel(instance_geo); + + llassert(!label.empty()); + + if (model->mSubmodelID) + { + label += (char)((int)'a' + model->mSubmodelID); + } + + model->mLabel = label + lod_suffix[mLod]; + } + else + { + // Don't change model's name if possible, it will play havoc with scenes that already use said model. + const auto ext_pos = getSuffixPosition(model->mLabel); + if (ext_pos != -1) + { + label = model->mLabel.substr(0, ext_pos); + } + else + { + label = model->mLabel; + } + } + + mScene[transformation].push_back(LLModelInstance(model, label, transformation, materials)); + stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform); + } + } + } + else + { + LL_INFOS() << "Unable to resolve geometry URL." << LL_ENDL; + badElement = true; + } + } + + // Process instance_control elements for skinned meshes + if (const auto instance_ctl = daeSafeCast(element)) + { + if (const auto ctl = daeSafeCast(instance_ctl->getUrl().getElement())) + { + if (const auto skin = ctl->getSkin()) + { + if (const auto geom = daeSafeCast(skin->getSource().getElement())) + { + if (const auto mesh = geom->getMesh()) + { + for (const auto mdl : mModelsMap[mesh]) + { + LLDAELoader::processDomModel(mdl, dae, domRoot, mesh, skin); + } + } + } + } + } + } + + // Resolve nodes to instances + if (const auto instance_node = daeSafeCast(element)) + { + if (const auto instance = instance_node->getUrl().getElement()) + { + processElement(instance, badElement, dae, domRoot); + } + } + + //process children + const auto children = element->getChildren(); + for (size_t i = 0; i < children.getCount(); ++i) + { + processElement(children[i], badElement, dae, domRoot); + } + + if (pushed_mat) + { + //this element was a node, restore transform before processiing siblings + mTransform = saved_transform; + mBindTransform = saved_bind_transform; + } +} + +std::map LLDAELoader::getMaterials(LLModel* model, domInstance_geometry* instance_geo, DAE* dae) const +{ + std::map materials; + for (const auto& material : model->mMaterialList) + { + LLImportMaterial import_material; + domInstance_material* instance_mat = NULL; + + if (const auto technique = daeSafeCast( + instance_geo->getDescendant(daeElement::matchType(domBind_material::domTechnique_common::ID())))) + { + const auto inst_materials = technique->getChildrenByType(); + for (size_t j = 0; j < inst_materials.getCount(); ++j) + { + std::string symbol(inst_materials[j]->getSymbol()); + + if (symbol == material) // found the binding + { + instance_mat = inst_materials[j]; + break; + } + } + } + + if (instance_mat) + { + if (const auto material = daeSafeCast(instance_mat->getTarget().getElement())) + { + if (const auto instance_effect = daeSafeCast( + material->getDescendant(daeElement::matchType(domInstance_effect::ID())))) + { + if (const auto effect = daeSafeCast( + instance_effect->getUrl().getElement())) + { + if (const auto profile = daeSafeCast( + effect->getDescendant(daeElement::matchType(domProfile_COMMON::ID())))) + { + import_material = profileToMaterial(profile, dae); + } + } + } + } + } + + import_material.mBinding = material; + materials[material] = import_material; + } + + return materials; +} + +LLImportMaterial LLDAELoader::profileToMaterial(domProfile_COMMON* material, DAE* dae) const +{ + LLImportMaterial mat; + mat.mFullbright = FALSE; + + if (const auto diffuse = material->getDescendant("diffuse")) + { + if (const auto texture = daeSafeCast(diffuse->getDescendant("texture"))) + { + const auto& newparams = material->getNewparam_array(); + if (newparams.getCount()) + { + for (size_t i = 0; i < newparams.getCount(); ++i) + { + if (const auto surface = newparams[i]->getSurface()) + { + if (const auto init = surface->getFx_surface_init_common()) + { + const auto init_from = init->getInit_from_array(); + if (init_from.getCount() > i) + { + if (const auto image = daeSafeCast(init_from[i]->getValue().getElement())) + { + // we only support init_from now - embedded data will come later + if (const auto init = image->getInit_from()) + { + mat.mDiffuseMapFilename = cdom::uriToNativePath(init->getValue().str()); + mat.mDiffuseMapLabel = getElementLabel(material); + } + } + } + } + } + } + } + else if (texture->getTexture()) + { + domImage* image = NULL; + dae->getDatabase()->getElement((daeElement**)&image, 0, texture->getTexture(), COLLADA_TYPE_IMAGE); + if (image) + { + // we only support init_from now - embedded data will come later + if (const auto init = image->getInit_from()) + { + const auto image_path_value = cdom::uriToNativePath(init->getValue().str()); + +#if LL_WINDOWS + // Work-around DOM tendency to resort to UNC names which are only confusing for downstream... + // + auto i = image_path_value.cbegin(); + while (*i == '\\') + ++i; + + mat.mDiffuseMapFilename.assign(i, image_path_value.end()); +#else + mat.mDiffuseMapFilename = image_path_value; +#endif + mat.mDiffuseMapLabel = getElementLabel(material); + } + } + } + } + + if (const auto color = daeSafeCast(diffuse->getDescendant("color"))) + { + const auto domfx_color = color->getValue(); + const auto value = LLColor4(domfx_color[0], domfx_color[1], domfx_color[2], domfx_color[3]); + mat.mDiffuseColor = value; + } + } + + if (const auto emission = material->getDescendant("emission")) + { + const auto emission_color = getDaeColor(emission); + const auto color_avg = (emission_color[0] + emission_color[1] + emission_color[2]) / 3.0f; + mat.mFullbright |= color_avg > 0.25f; + } + + return mat; +} + +// try to get a decent label for this element +std::string LLDAELoader::getElementLabel(daeElement* element) +{ + // if we have a name attribute, use it + std::string name = element->getAttribute("name"); + if (name.length()) + { + return name; + } + + // if we have an ID attribute, use it + if (element->getID()) + { + return std::string(element->getID()); + } + + // if we have a parent, use it + const auto parent = element->getParent(); + std::string index_string; + if (parent) + { + // retrieve index to distinguish items inside same parent + auto ind = size_t(0); + parent->getChildren().find(element, ind); + + if (ind > 0) + { + index_string = "_" + fmt::to_string(ind); + } + + // if parent has a name or ID, use it + auto name = parent->getAttribute("name"); + if (!name.length()) + { + name = std::string(parent->getID()); + } + + if (name.length()) + { + // make sure that index won't mix up with pre-named lod extensions + const auto ext_pos = getSuffixPosition(name); + + if (ext_pos == -1) + { + return name + index_string; + } + else + { + return name.insert(ext_pos, index_string); + } + } + } + + // try to use our type + const auto element_name = element->getElementName(); + if (element_name) + { + return std::string(element_name) + index_string; + } + + // if all else fails, use "object" + return std::string("object") + index_string; +} + +// static +size_t LLDAELoader::getSuffixPosition(const std::string label) +{ + if ((label.find("_LOD") != std::string::npos) || (label.find("_PHYS") != std::string::npos)) + { + return label.rfind('_'); + } + return -1; +} + +// static +std::string LLDAELoader::getLodlessLabel(daeElement* element) +{ + std::string label = getElementLabel(element); + size_t ext_pos = getSuffixPosition(label); + if (ext_pos != -1) + { + return label.substr(0, ext_pos); + } + return label; +} + +LLColor4 LLDAELoader::getDaeColor(daeElement* element) const +{ + LLColor4 value; + if (const auto color = daeSafeCast(element->getDescendant("color"))) + { + const auto domfx_color = color->getValue(); + value = LLColor4(domfx_color[0], domfx_color[1], domfx_color[2], domfx_color[3]); + } + + return value; +} + +bool LLDAELoader::addVolumeFacesFromDomMesh(LLModel* pModel, domMesh* mesh) +{ + auto status = LLModel::NO_ERRORS; + auto& tris = mesh->getTriangles_array(); + for (size_t i = 0; i < tris.getCount(); ++i) + { + auto& tri = tris.get(i); + status = load_face_from_dom_triangles(pModel->getVolumeFaces(), pModel->getMaterialList(), tri); + pModel->mStatus = status; + if (status != LLModel::NO_ERRORS) + { + pModel->ClearFacesAndMaterials(); + return false; + } + } + + auto& polys = mesh->getPolylist_array(); + for (size_t i = 0; i < polys.getCount(); ++i) + { + auto& poly = polys.get(i); + status = load_face_from_dom_polylist(pModel->getVolumeFaces(), pModel->getMaterialList(), poly); + if (status != LLModel::NO_ERRORS) + { + pModel->ClearFacesAndMaterials(); + return false; + } + } + + auto& polygons = mesh->getPolygons_array(); + for (size_t i = 0; i < polygons.getCount(); ++i) + { + auto& poly = polygons.get(i); + status = load_face_from_dom_polygons(pModel->getVolumeFaces(), pModel->getMaterialList(), poly); + if (status != LLModel::NO_ERRORS) + { + pModel->ClearFacesAndMaterials(); + return false; + } + } + + return (status == LLModel::NO_ERRORS); +} + +//static +LLModel* LLDAELoader::loadModelFromDomMesh(domMesh* mesh) +{ + LLVolumeParams volume_params; + volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); + auto ret = new LLModel(volume_params, 0.f); + createVolumeFacesFromDomMesh(ret, mesh); + if (ret->mLabel.empty()) + { + ret->mLabel = getElementLabel(mesh); + } + return ret; +} + +//static diff version supports creating multiple models when material counts spill +// over the 8 face server-side limit +// +bool LLDAELoader::loadModelsFromDomMesh(domMesh* mesh, std::vector& models_out, U32 submodel_limit) +{ + + LLVolumeParams volume_params; + volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); + + models_out.clear(); + + auto ret = new LLModel(volume_params, 0.f); + + const auto model_name = getLodlessLabel(mesh); + ret->mLabel = model_name + lod_suffix[mLod]; + + llassert(!ret->mLabel.empty()); + + // Like a monkey, ready to be shot into space + // + ret->ClearFacesAndMaterials(); + + // Get the whole set of volume faces + // + addVolumeFacesFromDomMesh(ret, mesh); + + auto volume_faces = (U32)ret->getNumVolumeFaces(); + + // Side-steps all manner of issues when splitting models + // and matching lower LOD materials to base models + // + ret->sortVolumeFacesByMaterialName(); + + bool normalized = false; + + auto submodelID = 0; + + // remove all faces that definitely won't fit into one model and submodel limit + const auto face_limit = (submodel_limit + 1) * LL_SCULPT_MESH_MAX_FACES; + if (face_limit < volume_faces) + { + ret->setNumVolumeFaces(face_limit); + } + + LLVolume::face_list_t remainder; + do + { + // Insure we do this once with the whole gang and not per-model + // + if (!normalized && !mNoNormalize) + { + normalized = true; + ret->normalizeVolumeFaces(); + } + + ret->trimVolumeFacesToSize(LL_SCULPT_MESH_MAX_FACES, &remainder); + + if (!mNoOptimize) + { + ret->optimizeVolumeFaces(); + } + + volume_faces = remainder.size(); + + models_out.push_back(ret); + + // If we have left-over volume faces, create another model + // to absorb them... + // + if (volume_faces) + { + auto next = new LLModel(volume_params, 0.f); + next->mSubmodelID = ++submodelID; + next->mLabel = model_name + (char)((int)'a' + next->mSubmodelID) + lod_suffix[mLod]; + next->getVolumeFaces() = remainder; + next->mNormalizedScale = ret->mNormalizedScale; + next->mNormalizedTranslation = ret->mNormalizedTranslation; + if (ret->mMaterialList.size() > LL_SCULPT_MESH_MAX_FACES) + { + next->mMaterialList.assign(ret->mMaterialList.begin() + LL_SCULPT_MESH_MAX_FACES, ret->mMaterialList.end()); + } + ret = next; + } + + remainder.clear(); + + } while (volume_faces); + + return true; +} + +bool LLDAELoader::createVolumeFacesFromDomMesh(LLModel* pModel, domMesh* mesh) +{ + if (mesh) + { + pModel->ClearFacesAndMaterials(); + + addVolumeFacesFromDomMesh(pModel, mesh); + + if (pModel->getNumVolumeFaces() > 0) + { + pModel->normalizeVolumeFaces(); + pModel->optimizeVolumeFaces(); + + if (pModel->getNumVolumeFaces() > 0) + { + return true; + } + } + } + else + { + LL_WARNS() << "no mesh found" << LL_ENDL; + } + + return false; +} + diff --git a/indra/llprimitive/lldaeloader.h b/indra/llprimitive/lldaeloader.h new file mode 100644 index 0000000000..607795be84 --- /dev/null +++ b/indra/llprimitive/lldaeloader.h @@ -0,0 +1,112 @@ +/** + * @file lldaeloader.h + * @brief LLDAELoader class definition + * + * $LicenseInfo:firstyear=2013&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2013, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLDAELOADER_H +#define LL_LLDAELOADER_H + +#include "llmodelloader.h" + +class DAE; +class daeElement; +class domProfile_COMMON; +class domInstance_geometry; +class domNode; +class domTranslate; +class domController; +class domSkin; +class domMesh; + +class LLDAELoader : public LLModelLoader +{ +public: + typedef std::map material_map; + typedef std::map > > dae_model_map; + dae_model_map mModelsMap; + + LLDAELoader( + std::string filename, + S32 lod, + LLModelLoader::load_callback_t load_cb, + LLModelLoader::joint_lookup_func_t joint_lookup_func, + LLModelLoader::texture_load_func_t texture_load_func, + LLModelLoader::state_callback_t state_cb, + void* opaque_userdata, + JointTransformMap& jointTransformMap, + JointNameSet& jointsFromNodes, + std::map& jointAliasMap, + U32 maxJointsPerMesh, + U32 modelLimit, + bool preprocess); + virtual ~LLDAELoader(); + + virtual bool OpenFile(const std::string& filename); + +protected: + + void processElement(daeElement* element, bool& badElement, DAE* dae, daeElement* domRoot); + void processDomModel(LLModel* model, DAE* dae, daeElement* pRoot, domMesh* mesh, domSkin* skin); + + material_map getMaterials(LLModel* model, domInstance_geometry* instance_geo, DAE* dae) const; + LLImportMaterial profileToMaterial(domProfile_COMMON* material, DAE* dae) const; + LLColor4 getDaeColor(daeElement* element) const; + + daeElement* getChildFromElement(daeElement* pElement, std::string const& name); + + bool isNodeAJoint(const domNode* pNode) const; + void processJointNode(domNode* pNode, JointTransformMap& jointTransforms); + void extractTranslation(const domTranslate* pTranslate, LLMatrix4& transform) const; + void extractTranslationViaSID(daeElement* pElement, LLMatrix4& transform) const; + void buildJointToNodeMappingFromScene(daeElement* pRoot); + void processJointToNodeMapping(domNode* pNode); + void processChildJoints(domNode* pParentNode); + + bool verifyCount(const size_t expected, const size_t result) const; + + //Verify that a controller matches vertex counts + bool verifyController(const domController* pController) const; + + static bool addVolumeFacesFromDomMesh(LLModel* model, domMesh* mesh); + static bool createVolumeFacesFromDomMesh(LLModel* model, domMesh* mesh); + + static LLModel* loadModelFromDomMesh(domMesh* mesh); + + // Loads a mesh breaking it into one or more models as necessary + // to get around volume face limitations while retaining >8 materials + // + bool loadModelsFromDomMesh(domMesh* mesh, std::vector& models_out, U32 submodel_limit); + + static std::string getElementLabel(daeElement* element); + static size_t getSuffixPosition(const std::string label); + static std::string getLodlessLabel(daeElement* element); + + static std::string preprocessDAE(const std::string filename); + +private: + U32 mGeneratedModelLimit; // Attempt to limit amount of generated submodels + bool mPreprocessDAE; + +}; +#endif // LL_LLDAELLOADER_H diff --git a/indra/llprimitive/llmaterial.cpp b/indra/llprimitive/llmaterial.cpp index cf4c645cfd..57ceb3e11b 100644 --- a/indra/llprimitive/llmaterial.cpp +++ b/indra/llprimitive/llmaterial.cpp @@ -69,7 +69,7 @@ template T getMaterialField(const LLSD& data, const std::string& fie { return (T)data[field]; } - llerrs << "Missing or mistyped field '" << field << "' in material definition" << llendl; + LL_ERRS() << "Missing or mistyped field '" << field << "' in material definition" << LL_ENDL; return (T)LLSD(); } @@ -80,7 +80,7 @@ template<> LLUUID getMaterialField(const LLSD& data, const std::string& field, c { return data[field].asUUID(); } - llerrs << "Missing or mistyped field '" << field << "' in material definition" << llendl; + LL_ERRS() << "Missing or mistyped field '" << field << "' in material definition" << LL_ENDL; return LLUUID::null; } @@ -119,18 +119,18 @@ LLSD LLMaterial::asLLSD() const LLSD material_data; material_data[MATERIALS_CAP_NORMAL_MAP_FIELD] = mNormalID; - material_data[MATERIALS_CAP_NORMAL_MAP_OFFSET_X_FIELD] = llround(mNormalOffsetX * MATERIALS_MULTIPLIER); - material_data[MATERIALS_CAP_NORMAL_MAP_OFFSET_Y_FIELD] = llround(mNormalOffsetY * MATERIALS_MULTIPLIER); - material_data[MATERIALS_CAP_NORMAL_MAP_REPEAT_X_FIELD] = llround(mNormalRepeatX * MATERIALS_MULTIPLIER); - material_data[MATERIALS_CAP_NORMAL_MAP_REPEAT_Y_FIELD] = llround(mNormalRepeatY * MATERIALS_MULTIPLIER); - material_data[MATERIALS_CAP_NORMAL_MAP_ROTATION_FIELD] = llround(mNormalRotation * MATERIALS_MULTIPLIER); + material_data[MATERIALS_CAP_NORMAL_MAP_OFFSET_X_FIELD] = ll_round(mNormalOffsetX * MATERIALS_MULTIPLIER); + material_data[MATERIALS_CAP_NORMAL_MAP_OFFSET_Y_FIELD] = ll_round(mNormalOffsetY * MATERIALS_MULTIPLIER); + material_data[MATERIALS_CAP_NORMAL_MAP_REPEAT_X_FIELD] = ll_round(mNormalRepeatX * MATERIALS_MULTIPLIER); + material_data[MATERIALS_CAP_NORMAL_MAP_REPEAT_Y_FIELD] = ll_round(mNormalRepeatY * MATERIALS_MULTIPLIER); + material_data[MATERIALS_CAP_NORMAL_MAP_ROTATION_FIELD] = ll_round(mNormalRotation * MATERIALS_MULTIPLIER); material_data[MATERIALS_CAP_SPECULAR_MAP_FIELD] = mSpecularID; - material_data[MATERIALS_CAP_SPECULAR_MAP_OFFSET_X_FIELD] = llround(mSpecularOffsetX * MATERIALS_MULTIPLIER); - material_data[MATERIALS_CAP_SPECULAR_MAP_OFFSET_Y_FIELD] = llround(mSpecularOffsetY * MATERIALS_MULTIPLIER); - material_data[MATERIALS_CAP_SPECULAR_MAP_REPEAT_X_FIELD] = llround(mSpecularRepeatX * MATERIALS_MULTIPLIER); - material_data[MATERIALS_CAP_SPECULAR_MAP_REPEAT_Y_FIELD] = llround(mSpecularRepeatY * MATERIALS_MULTIPLIER); - material_data[MATERIALS_CAP_SPECULAR_MAP_ROTATION_FIELD] = llround(mSpecularRotation * MATERIALS_MULTIPLIER); + material_data[MATERIALS_CAP_SPECULAR_MAP_OFFSET_X_FIELD] = ll_round(mSpecularOffsetX * MATERIALS_MULTIPLIER); + material_data[MATERIALS_CAP_SPECULAR_MAP_OFFSET_Y_FIELD] = ll_round(mSpecularOffsetY * MATERIALS_MULTIPLIER); + material_data[MATERIALS_CAP_SPECULAR_MAP_REPEAT_X_FIELD] = ll_round(mSpecularRepeatX * MATERIALS_MULTIPLIER); + material_data[MATERIALS_CAP_SPECULAR_MAP_REPEAT_Y_FIELD] = ll_round(mSpecularRepeatY * MATERIALS_MULTIPLIER); + material_data[MATERIALS_CAP_SPECULAR_MAP_ROTATION_FIELD] = ll_round(mSpecularRotation * MATERIALS_MULTIPLIER); material_data[MATERIALS_CAP_SPECULAR_COLOR_FIELD] = mSpecularLightColor.getValue(); material_data[MATERIALS_CAP_SPECULAR_EXP_FIELD] = mSpecularLightExponent; diff --git a/indra/llprimitive/llmaterialid.cpp b/indra/llprimitive/llmaterialid.cpp index 820f62c43c..81b4575423 100644 --- a/indra/llprimitive/llmaterialid.cpp +++ b/indra/llprimitive/llmaterialid.cpp @@ -42,8 +42,11 @@ LLMaterialID::LLMaterialID() LLMaterialID::LLMaterialID(const LLSD& pMaterialID) { - llassert(pMaterialID.isBinary()); - parseFromBinary(pMaterialID.asBinary()); + llassert(pMaterialID.isBinary() || pMaterialID.isUUID()); + if (pMaterialID.isUUID()) + set(pMaterialID.asUUID().mData); + else + parseFromBinary(pMaterialID.asBinary()); } LLMaterialID::LLMaterialID(const LLSD::Binary& pMaterialID) @@ -56,15 +59,6 @@ LLMaterialID::LLMaterialID(const void* pMemory) set(pMemory); } -LLMaterialID::LLMaterialID(const LLMaterialID& pOtherMaterialID) -{ - copyFromOtherMaterialID(pOtherMaterialID); -} - -LLMaterialID::~LLMaterialID() -{ -} - bool LLMaterialID::operator == (const LLMaterialID& pOtherMaterialID) const { return (compareToOtherMaterialID(pOtherMaterialID) == 0); @@ -95,12 +89,6 @@ bool LLMaterialID::operator >= (const LLMaterialID& pOtherMaterialID) const return (compareToOtherMaterialID(pOtherMaterialID) >= 0); } -LLMaterialID& LLMaterialID::operator = (const LLMaterialID& pOtherMaterialID) -{ - copyFromOtherMaterialID(pOtherMaterialID); - return (*this); -} - bool LLMaterialID::isNull() const { return (compareToOtherMaterialID(LLMaterialID::null) == 0); @@ -116,12 +104,12 @@ void LLMaterialID::set(const void* pMemory) llassert(pMemory != NULL); // assumes that the required size of memory is available - memcpy(mID, pMemory, MATERIAL_ID_SIZE * sizeof(U8)); + memcpy(mID, pMemory, sizeof(mID)); } void LLMaterialID::clear() { - memset(mID, 0, MATERIAL_ID_SIZE * sizeof(U8)); + memset(mID, 0, sizeof(mID)); } LLSD LLMaterialID::asLLSD() const @@ -156,18 +144,12 @@ std::ostream& operator<<(std::ostream& s, const LLMaterialID &material_id) return s; } - void LLMaterialID::parseFromBinary (const LLSD::Binary& pMaterialID) { llassert(pMaterialID.size() == (MATERIAL_ID_SIZE * sizeof(U8))); memcpy(mID, &pMaterialID[0], MATERIAL_ID_SIZE * sizeof(U8)); } -void LLMaterialID::copyFromOtherMaterialID(const LLMaterialID& pOtherMaterialID) -{ - memcpy(mID, pOtherMaterialID.get(), MATERIAL_ID_SIZE * sizeof(U8)); -} - int LLMaterialID::compareToOtherMaterialID(const LLMaterialID& pOtherMaterialID) const { int retVal = 0; diff --git a/indra/llprimitive/llmaterialid.h b/indra/llprimitive/llmaterialid.h index 0a95204085..1a086e23b6 100644 --- a/indra/llprimitive/llmaterialid.h +++ b/indra/llprimitive/llmaterialid.h @@ -30,16 +30,18 @@ #define MATERIAL_ID_SIZE 16 #include +#include "llsd.h" class LLMaterialID { public: LLMaterialID(); + LLMaterialID(const LLUUID& id) { set(id.mData); } LLMaterialID(const LLSD& pMaterialID); LLMaterialID(const LLSD::Binary& pMaterialID); LLMaterialID(const void* pMemory); - LLMaterialID(const LLMaterialID& pOtherMaterialID); - ~LLMaterialID(); + LLMaterialID(const LLMaterialID& pOtherMaterialID) = default; + ~LLMaterialID() = default; bool operator == (const LLMaterialID& pOtherMaterialID) const; bool operator != (const LLMaterialID& pOtherMaterialID) const; @@ -49,7 +51,7 @@ class LLMaterialID bool operator > (const LLMaterialID& pOtherMaterialID) const; bool operator >= (const LLMaterialID& pOtherMaterialID) const; - LLMaterialID& operator = (const LLMaterialID& pOtherMaterialID); + LLMaterialID& operator = (const LLMaterialID& pOtherMaterialID) = default; bool isNull() const; @@ -66,11 +68,13 @@ class LLMaterialID private: void parseFromBinary(const LLSD::Binary& pMaterialID); - void copyFromOtherMaterialID(const LLMaterialID& pOtherMaterialID); int compareToOtherMaterialID(const LLMaterialID& pOtherMaterialID) const; U8 mID[MATERIAL_ID_SIZE]; } ; +static_assert(sizeof(LLMaterialID) == MATERIAL_ID_SIZE, "LLMaterialID must be sizeof(mID)"); +static_assert(std::is_trivially_copyable::value, "LLMaterialID must be a trivially copyable type"); + #endif // LL_LLMATERIALID_H diff --git a/indra/llprimitive/llmaterialtable.cpp b/indra/llprimitive/llmaterialtable.cpp index 86da1fbf4d..2e47813774 100644 --- a/indra/llprimitive/llmaterialtable.cpp +++ b/indra/llprimitive/llmaterialtable.cpp @@ -558,14 +558,14 @@ LLUUID LLMaterialTable::getCollisionSoundUUID(U8 mcode, U8 mcode2) mcode &= LL_MCODE_MASK; mcode2 &= LL_MCODE_MASK; - //llinfos << "code 1: " << ((U32) mcode) << " code 2:" << ((U32) mcode2) << llendl; + //LL_INFOS() << "code 1: " << ((U32) mcode) << " code 2:" << ((U32) mcode2) << LL_ENDL; if (mCollisionSoundMatrix && (mcode < LL_MCODE_END) && (mcode2 < LL_MCODE_END)) { return(mCollisionSoundMatrix[mcode * LL_MCODE_END + mcode2]); } else { - //llinfos << "Null Sound" << llendl; + //LL_INFOS() << "Null Sound" << LL_ENDL; return(SND_NULL); } } diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp index d93c65595b..fa39a37895 100644 --- a/indra/llprimitive/llmodel.cpp +++ b/indra/llprimitive/llmodel.cpp @@ -28,23 +28,10 @@ #include "llmodel.h" #include "llmemory.h" -#include "LLConvexDecomposition.h" +#include "llconvexdecomposition.h" #include "llsdserialize.h" #include "llvector4a.h" -#if LL_MSVC -#pragma warning (push) -#pragma warning (disable : 4068) -#pragma warning (disable : 4263) -#pragma warning (disable : 4264) -#endif -#pragma GCC diagnostic ignored "-Woverloaded-virtual" -#include "dae.h" -#include "dae/daeErrorHandler.h" -#include "dom/domConstants.h" -#include "dom/domMesh.h" -#if LL_MSVC -#pragma warning (pop) -#endif +#include "llmatrix4a.h" #ifdef LL_STANDALONE # include @@ -52,8 +39,6 @@ # include "zlib/zlib.h" #endif - - std::string model_names[] = { "lowest_lod", @@ -66,8 +51,12 @@ std::string model_names[] = const int MODEL_NAMES_LENGTH = sizeof(model_names) / sizeof(std::string); LLModel::LLModel(LLVolumeParams& params, F32 detail) - : LLVolume(params, detail), mNormalizedScale(1,1,1), mNormalizedTranslation(0,0,0) - , mPelvisOffset( 0.0f ), mStatus(NO_ERRORS) + : LLVolume(params, detail), + mNormalizedScale(1,1,1), + mNormalizedTranslation(0,0,0), + mPelvisOffset( 0.0f ), + mStatus(NO_ERRORS), + mSubmodelID(0) { mDecompID = -1; mLocalID = -1; @@ -81,671 +70,6 @@ LLModel::~LLModel() } } - -bool get_dom_sources(const domInputLocalOffset_Array& inputs, S32& pos_offset, S32& tc_offset, S32& norm_offset, S32 &idx_stride, - domSource* &pos_source, domSource* &tc_source, domSource* &norm_source) -{ - idx_stride = 0; - - for (U32 j = 0; j < inputs.getCount(); ++j) - { - idx_stride = llmax((S32) inputs[j]->getOffset(), idx_stride); - - if (strcmp(COMMON_PROFILE_INPUT_VERTEX, inputs[j]->getSemantic()) == 0) - { //found vertex array - const domURIFragmentType& uri = inputs[j]->getSource(); - daeElementRef elem = uri.getElement(); - domVertices* vertices = (domVertices*) elem.cast(); - if ( !vertices ) - { - return false; - } - - domInputLocal_Array& v_inp = vertices->getInput_array(); - - - for (U32 k = 0; k < v_inp.getCount(); ++k) - { - if (strcmp(COMMON_PROFILE_INPUT_POSITION, v_inp[k]->getSemantic()) == 0) - { - pos_offset = inputs[j]->getOffset(); - - const domURIFragmentType& uri = v_inp[k]->getSource(); - daeElementRef elem = uri.getElement(); - pos_source = (domSource*) elem.cast(); - } - - if (strcmp(COMMON_PROFILE_INPUT_NORMAL, v_inp[k]->getSemantic()) == 0) - { - norm_offset = inputs[j]->getOffset(); - - const domURIFragmentType& uri = v_inp[k]->getSource(); - daeElementRef elem = uri.getElement(); - norm_source = (domSource*) elem.cast(); - } - } - } - - if (strcmp(COMMON_PROFILE_INPUT_NORMAL, inputs[j]->getSemantic()) == 0) - { - //found normal array for this triangle list - norm_offset = inputs[j]->getOffset(); - const domURIFragmentType& uri = inputs[j]->getSource(); - daeElementRef elem = uri.getElement(); - norm_source = (domSource*) elem.cast(); - } - else if (strcmp(COMMON_PROFILE_INPUT_TEXCOORD, inputs[j]->getSemantic()) == 0) - { //found texCoords - tc_offset = inputs[j]->getOffset(); - const domURIFragmentType& uri = inputs[j]->getSource(); - daeElementRef elem = uri.getElement(); - tc_source = (domSource*) elem.cast(); - } - } - - idx_stride += 1; - - return true; -} - -LLModel::EModelStatus load_face_from_dom_triangles(std::vector& face_list, std::vector& materials, domTrianglesRef& tri) -{ - LLVolumeFace face; - std::vector verts; - std::vector indices; - - const domInputLocalOffset_Array& inputs = tri->getInput_array(); - - S32 pos_offset = -1; - S32 tc_offset = -1; - S32 norm_offset = -1; - - domSource* pos_source = NULL; - domSource* tc_source = NULL; - domSource* norm_source = NULL; - - S32 idx_stride = 0; - - if ( !get_dom_sources(inputs, pos_offset, tc_offset, norm_offset, idx_stride, pos_source, tc_source, norm_source) || !pos_source ) - { - return LLModel::BAD_ELEMENT; - } - - - domPRef p = tri->getP(); - domListOfUInts& idx = p->getValue(); - - domListOfFloats dummy ; - domListOfFloats& v = pos_source ? pos_source->getFloat_array()->getValue() : dummy ; - domListOfFloats& tc = tc_source ? tc_source->getFloat_array()->getValue() : dummy ; - domListOfFloats& n = norm_source ? norm_source->getFloat_array()->getValue() : dummy ; - - if (pos_source) - { - face.mExtents[0].set(v[0], v[1], v[2]); - face.mExtents[1].set(v[0], v[1], v[2]); - } - - LLVolumeFace::VertexMapData::PointMap point_map; - - for (U32 i = 0; i < idx.getCount(); i += idx_stride) - { - LLVolumeFace::VertexData cv; - if (pos_source) - { - cv.setPosition(LLVector4a(v[idx[i+pos_offset]*3+0], - v[idx[i+pos_offset]*3+1], - v[idx[i+pos_offset]*3+2])); - } - - if (tc_source) - { - cv.mTexCoord.setVec(tc[idx[i+tc_offset]*2+0], - tc[idx[i+tc_offset]*2+1]); - } - - if (norm_source) - { - cv.setNormal(LLVector4a(n[idx[i+norm_offset]*3+0], - n[idx[i+norm_offset]*3+1], - n[idx[i+norm_offset]*3+2])); - } - - BOOL found = FALSE; - - LLVolumeFace::VertexMapData::PointMap::iterator point_iter; - point_iter = point_map.find(LLVector3(cv.getPosition().getF32ptr())); - - if (point_iter != point_map.end()) - { - for (U32 j = 0; j < point_iter->second.size(); ++j) - { - if ((point_iter->second)[j] == cv) - { - found = TRUE; - indices.push_back((point_iter->second)[j].mIndex); - break; - } - } - } - - if (!found) - { - update_min_max(face.mExtents[0], face.mExtents[1], cv.getPosition()); - verts.push_back(cv); - if (verts.size() >= 65535) - { - //llerrs << "Attempted to write model exceeding 16-bit index buffer limitation." << llendl; - return LLModel::VERTEX_NUMBER_OVERFLOW ; - } - U16 index = (U16) (verts.size()-1); - indices.push_back(index); - - LLVolumeFace::VertexMapData d; - d.setPosition(cv.getPosition()); - d.mTexCoord = cv.mTexCoord; - d.setNormal(cv.getNormal()); - d.mIndex = index; - if (point_iter != point_map.end()) - { - point_iter->second.push_back(d); - } - else - { - point_map[LLVector3(d.getPosition().getF32ptr())].push_back(d); - } - } - - if (indices.size()%3 == 0 && verts.size() >= 65532) - { - face_list.push_back(face); - face_list.rbegin()->fillFromLegacyData(verts, indices); - LLVolumeFace& new_face = *face_list.rbegin(); - if (!norm_source) - { - ll_aligned_free_16(new_face.mNormals); - new_face.mNormals = NULL; - } - - if (!tc_source) - { - ll_aligned_free_16(new_face.mTexCoords); - new_face.mTexCoords = NULL; - } - - face = LLVolumeFace(); - point_map.clear(); - } - } - - if (!verts.empty()) - { - std::string material; - - if (tri->getMaterial()) - { - material = std::string(tri->getMaterial()); - } - - materials.push_back(material); - face_list.push_back(face); - - face_list.rbegin()->fillFromLegacyData(verts, indices); - LLVolumeFace& new_face = *face_list.rbegin(); - if (!norm_source) - { - ll_aligned_free_16(new_face.mNormals); - new_face.mNormals = NULL; - } - - if (!tc_source) - { - ll_aligned_free_16(new_face.mTexCoords); - new_face.mTexCoords = NULL; - } - } - - return LLModel::NO_ERRORS ; -} - -LLModel::EModelStatus load_face_from_dom_polylist(std::vector& face_list, std::vector& materials, domPolylistRef& poly) -{ - domPRef p = poly->getP(); - domListOfUInts& idx = p->getValue(); - - if (idx.getCount() == 0) - { - return LLModel::NO_ERRORS ; - } - - const domInputLocalOffset_Array& inputs = poly->getInput_array(); - - - domListOfUInts& vcount = poly->getVcount()->getValue(); - - S32 pos_offset = -1; - S32 tc_offset = -1; - S32 norm_offset = -1; - - domSource* pos_source = NULL; - domSource* tc_source = NULL; - domSource* norm_source = NULL; - - S32 idx_stride = 0; - - if (!get_dom_sources(inputs, pos_offset, tc_offset, norm_offset, idx_stride, pos_source, tc_source, norm_source)) - { - return LLModel::BAD_ELEMENT; - } - - LLVolumeFace face; - - std::vector indices; - std::vector verts; - - domListOfFloats v; - domListOfFloats tc; - domListOfFloats n; - - if (pos_source) - { - v = pos_source->getFloat_array()->getValue(); - face.mExtents[0].set(v[0], v[1], v[2]); - face.mExtents[1].set(v[0], v[1], v[2]); - } - - if (tc_source) - { - tc = tc_source->getFloat_array()->getValue(); - } - - if (norm_source) - { - n = norm_source->getFloat_array()->getValue(); - } - - LLVolumeFace::VertexMapData::PointMap point_map; - - U32 cur_idx = 0; - for (U32 i = 0; i < vcount.getCount(); ++i) - { //for each polygon - U32 first_index = 0; - U32 last_index = 0; - for (U32 j = 0; j < vcount[i]; ++j) - { //for each vertex - - LLVolumeFace::VertexData cv; - - if (pos_source) - { - cv.getPosition().set(v[idx[cur_idx+pos_offset]*3+0], - v[idx[cur_idx+pos_offset]*3+1], - v[idx[cur_idx+pos_offset]*3+2]); - } - - if (tc_source) - { - cv.mTexCoord.setVec(tc[idx[cur_idx+tc_offset]*2+0], - tc[idx[cur_idx+tc_offset]*2+1]); - } - - if (norm_source) - { - cv.getNormal().set(n[idx[cur_idx+norm_offset]*3+0], - n[idx[cur_idx+norm_offset]*3+1], - n[idx[cur_idx+norm_offset]*3+2]); - } - - cur_idx += idx_stride; - - BOOL found = FALSE; - - LLVolumeFace::VertexMapData::PointMap::iterator point_iter; - LLVector3 pos3(cv.getPosition().getF32ptr()); - point_iter = point_map.find(pos3); - - if (point_iter != point_map.end()) - { - for (U32 k = 0; k < point_iter->second.size(); ++k) - { - if ((point_iter->second)[k] == cv) - { - found = TRUE; - U32 index = (point_iter->second)[k].mIndex; - if (j == 0) - { - first_index = index; - } - else if (j == 1) - { - last_index = index; - } - else - { - indices.push_back(first_index); - indices.push_back(last_index); - indices.push_back(index); - last_index = index; - } - - break; - } - } - } - - if (!found) - { - update_min_max(face.mExtents[0], face.mExtents[1], cv.getPosition()); - verts.push_back(cv); - if (verts.size() >= 65535) - { - //llerrs << "Attempted to write model exceeding 16-bit index buffer limitation." << llendl; - return LLModel::VERTEX_NUMBER_OVERFLOW ; - } - U16 index = (U16) (verts.size()-1); - - if (j == 0) - { - first_index = index; - } - else if (j == 1) - { - last_index = index; - } - else - { - indices.push_back(first_index); - indices.push_back(last_index); - indices.push_back(index); - last_index = index; - } - - LLVolumeFace::VertexMapData d; - d.setPosition(cv.getPosition()); - d.mTexCoord = cv.mTexCoord; - d.setNormal(cv.getNormal()); - d.mIndex = index; - if (point_iter != point_map.end()) - { - point_iter->second.push_back(d); - } - else - { - point_map[pos3].push_back(d); - } - } - - if (indices.size()%3 == 0 && indices.size() >= 65532) - { - face_list.push_back(face); - face_list.rbegin()->fillFromLegacyData(verts, indices); - LLVolumeFace& new_face = *face_list.rbegin(); - if (!norm_source) - { - ll_aligned_free_16(new_face.mNormals); - new_face.mNormals = NULL; - } - - if (!tc_source) - { - ll_aligned_free_16(new_face.mTexCoords); - new_face.mTexCoords = NULL; - } - - face = LLVolumeFace(); - verts.clear(); - indices.clear(); - point_map.clear(); - } - } - } - - if (!verts.empty()) - { - std::string material; - - if (poly->getMaterial()) - { - material = std::string(poly->getMaterial()); - } - - materials.push_back(material); - face_list.push_back(face); - face_list.rbegin()->fillFromLegacyData(verts, indices); - - LLVolumeFace& new_face = *face_list.rbegin(); - if (!norm_source) - { - ll_aligned_free_16(new_face.mNormals); - new_face.mNormals = NULL; - } - - if (!tc_source) - { - ll_aligned_free_16(new_face.mTexCoords); - new_face.mTexCoords = NULL; - } - } - - return LLModel::NO_ERRORS ; -} - -LLModel::EModelStatus load_face_from_dom_polygons(std::vector& face_list, std::vector& materials, domPolygonsRef& poly) -{ - LLVolumeFace face; - std::vector indices; - std::vector verts; - - const domInputLocalOffset_Array& inputs = poly->getInput_array(); - - S32 v_offset = -1; - S32 n_offset = -1; - S32 t_offset = -1; - - domListOfFloats* v = NULL; - domListOfFloats* n = NULL; - domListOfFloats* t = NULL; - - U32 stride = 0; - for (U32 i = 0; i < inputs.getCount(); ++i) - { - stride = llmax((U32) inputs[i]->getOffset()+1, stride); - - if (strcmp(COMMON_PROFILE_INPUT_VERTEX, inputs[i]->getSemantic()) == 0) - { //found vertex array - v_offset = inputs[i]->getOffset(); - - const domURIFragmentType& uri = inputs[i]->getSource(); - daeElementRef elem = uri.getElement(); - domVertices* vertices = (domVertices*) elem.cast(); - if (!vertices) - { - return LLModel::BAD_ELEMENT; - } - domInputLocal_Array& v_inp = vertices->getInput_array(); - - for (U32 k = 0; k < v_inp.getCount(); ++k) - { - if (strcmp(COMMON_PROFILE_INPUT_POSITION, v_inp[k]->getSemantic()) == 0) - { - const domURIFragmentType& uri = v_inp[k]->getSource(); - daeElementRef elem = uri.getElement(); - domSource* src = (domSource*) elem.cast(); - if (!src) - { - return LLModel::BAD_ELEMENT; - } - v = &(src->getFloat_array()->getValue()); - } - } - } - else if (strcmp(COMMON_PROFILE_INPUT_NORMAL, inputs[i]->getSemantic()) == 0) - { - n_offset = inputs[i]->getOffset(); - //found normal array for this triangle list - const domURIFragmentType& uri = inputs[i]->getSource(); - daeElementRef elem = uri.getElement(); - domSource* src = (domSource*) elem.cast(); - if (!src) - { - return LLModel::BAD_ELEMENT; - } - n = &(src->getFloat_array()->getValue()); - } - else if (strcmp(COMMON_PROFILE_INPUT_TEXCOORD, inputs[i]->getSemantic()) == 0 && inputs[i]->getSet() == 0) - { //found texCoords - t_offset = inputs[i]->getOffset(); - const domURIFragmentType& uri = inputs[i]->getSource(); - daeElementRef elem = uri.getElement(); - domSource* src = (domSource*) elem.cast(); - if (!src) - { - return LLModel::BAD_ELEMENT; - } - t = &(src->getFloat_array()->getValue()); - } - } - - domP_Array& ps = poly->getP_array(); - - //make a triangle list in - for (U32 i = 0; i < ps.getCount(); ++i) - { //for each polygon - domListOfUInts& idx = ps[i]->getValue(); - for (U32 j = 0; j < idx.getCount()/stride; ++j) - { //for each vertex - if (j > 2) - { - U32 size = verts.size(); - LLVolumeFace::VertexData v0 = verts[size-3]; - LLVolumeFace::VertexData v1 = verts[size-1]; - - verts.push_back(v0); - verts.push_back(v1); - } - - LLVolumeFace::VertexData vert; - - - if (v) - { - U32 v_idx = idx[j*stride+v_offset]*3; - v_idx = llclamp(v_idx, (U32) 0, (U32) v->getCount()); - vert.getPosition().set(v->get(v_idx), - v->get(v_idx+1), - v->get(v_idx+2)); - } - - //bounds check n and t lookups because some FBX to DAE converters - //use negative indices and empty arrays to indicate data does not exist - //for a particular channel - if (n && n->getCount() > 0) - { - U32 n_idx = idx[j*stride+n_offset]*3; - n_idx = llclamp(n_idx, (U32) 0, (U32) n->getCount()); - vert.getNormal().set(n->get(n_idx), - n->get(n_idx+1), - n->get(n_idx+2)); - } - else - { - vert.getNormal().clear(); - } - - - if (t && t->getCount() > 0) - { - U32 t_idx = idx[j*stride+t_offset]*2; - t_idx = llclamp(t_idx, (U32) 0, (U32) t->getCount()); - vert.mTexCoord.setVec(t->get(t_idx), - t->get(t_idx+1)); - } - else - { - vert.mTexCoord.clear(); - } - - - verts.push_back(vert); - } - } - - if (verts.empty()) - { - return LLModel::NO_ERRORS; - } - - face.mExtents[0] = verts[0].getPosition(); - face.mExtents[1] = verts[0].getPosition(); - - //create a map of unique vertices to indices - std::map vert_idx; - - U32 cur_idx = 0; - for (U32 i = 0; i < verts.size(); ++i) - { - std::map::iterator iter = vert_idx.find(verts[i]); - if (iter == vert_idx.end()) - { - vert_idx[verts[i]] = cur_idx++; - } - } - - //build vertex array from map - std::vector new_verts; - new_verts.resize(vert_idx.size()); - - for (std::map::iterator iter = vert_idx.begin(); iter != vert_idx.end(); ++iter) - { - new_verts[iter->second] = iter->first; - update_min_max(face.mExtents[0], face.mExtents[1], iter->first.getPosition()); - } - - //build index array from map - indices.resize(verts.size()); - - for (U32 i = 0; i < verts.size(); ++i) - { - indices[i] = vert_idx[verts[i]]; - } - - // DEBUG just build an expanded triangle list - /*for (U32 i = 0; i < verts.size(); ++i) - { - indices.push_back((U16) i); - update_min_max(face.mExtents[0], face.mExtents[1], verts[i].getPosition()); - }*/ - - if (!new_verts.empty()) - { - std::string material; - - if (poly->getMaterial()) - { - material = std::string(poly->getMaterial()); - } - - materials.push_back(material); - face_list.push_back(face); - face_list.rbegin()->fillFromLegacyData(new_verts, indices); - - LLVolumeFace& new_face = *face_list.rbegin(); - if (!n) - { - ll_aligned_free_16(new_face.mNormals); - new_face.mNormals = NULL; - } - - if (!t) - { - ll_aligned_free_16(new_face.mTexCoords); - new_face.mTexCoords = NULL; - } - } - - return LLModel::NO_ERRORS ; -} - //static std::string LLModel::getStatusString(U32 status) { @@ -755,91 +79,14 @@ std::string LLModel::getStatusString(U32 status) { if(status_strings[status] == std::string()) { - llerrs << "No valid status string for this status: " << (U32)status << llendl ; - } - return status_strings[status] ; - } - - llerrs << "Invalid model status: " << (U32)status << llendl ; - - return std::string() ; -} - -void LLModel::addVolumeFacesFromDomMesh(domMesh* mesh) -{ - domTriangles_Array& tris = mesh->getTriangles_array(); - - for (U32 i = 0; i < tris.getCount(); ++i) - { - domTrianglesRef& tri = tris.get(i); - - mStatus = load_face_from_dom_triangles(mVolumeFaces, mMaterialList, tri); - - if(mStatus != NO_ERRORS) - { - mVolumeFaces.clear() ; - mMaterialList.clear() ; - return ; //abort - } - } - - domPolylist_Array& polys = mesh->getPolylist_array(); - for (U32 i = 0; i < polys.getCount(); ++i) - { - domPolylistRef& poly = polys.get(i); - mStatus = load_face_from_dom_polylist(mVolumeFaces, mMaterialList, poly); - - if(mStatus != NO_ERRORS) - { - mVolumeFaces.clear() ; - mMaterialList.clear() ; - return ; //abort - } - } - - domPolygons_Array& polygons = mesh->getPolygons_array(); - - for (U32 i = 0; i < polygons.getCount(); ++i) - { - domPolygonsRef& poly = polygons.get(i); - mStatus = load_face_from_dom_polygons(mVolumeFaces, mMaterialList, poly); - - if(mStatus != NO_ERRORS) - { - mVolumeFaces.clear() ; - mMaterialList.clear() ; - return ; //abort - } - } - -} - -BOOL LLModel::createVolumeFacesFromDomMesh(domMesh* mesh) -{ - if (mesh) - { - mVolumeFaces.clear(); - mMaterialList.clear(); - - addVolumeFacesFromDomMesh(mesh); - - if (getNumVolumeFaces() > 0) - { - normalizeVolumeFaces(); - optimizeVolumeFaces(); - - if (getNumVolumeFaces() > 0) - { - return TRUE; - } + LL_ERRS() << "No valid status string for this status: " << (U32)status << LL_ENDL ; } + return status_strings[status] ; } - else - { - llwarns << "no mesh found" << llendl; - } - - return FALSE; + + LL_ERRS() << "Invalid model status: " << (U32)status << LL_ENDL ; + + return std::string() ; } void LLModel::offsetMesh( const LLVector3& pivotPoint ) @@ -863,7 +110,73 @@ void LLModel::optimizeVolumeFaces() { for (U32 i = 0; i < (U32)getNumVolumeFaces(); ++i) { + //validate_face(mVolumeFaces[i]); mVolumeFaces[i].optimize(); + //validate_face(mVolumeFaces[i]); + } +} + +struct MaterialBinding +{ + int index; + std::string matName; +}; + +struct MaterialSort +{ + bool operator()(const MaterialBinding& lhs, const MaterialBinding& rhs) + { + return LLStringUtil::compareInsensitive(lhs.matName, rhs.matName) < 0; + } +}; + +void LLModel::sortVolumeFacesByMaterialName() +{ + std::vector bindings; + bindings.resize(mVolumeFaces.size()); + + for (U32 i = 0; i < bindings.size(); i++) + { + bindings[i].index = i; + if(i < mMaterialList.size()) + { + bindings[i].matName = mMaterialList[i]; + } + } + std::sort(bindings.begin(), bindings.end(), MaterialSort()); + std::vector< LLVolumeFace > new_faces; + + // remap the faces to be in the same order the mats now are... + // + new_faces.resize(bindings.size()); + for (U32 i = 0; i < bindings.size(); i++) + { + new_faces[i] = mVolumeFaces[bindings[i].index]; + if(i < mMaterialList.size()) + { + mMaterialList[i] = bindings[i].matName; + } + } + + mVolumeFaces = new_faces; +} + +void LLModel::trimVolumeFacesToSize(U32 new_count, LLVolume::face_list_t* remainder) +{ + llassert(new_count <= LL_SCULPT_MESH_MAX_FACES); + + if (new_count && ((U32)getNumVolumeFaces() > new_count)) + { + // Copy out remaining volume faces for alternative handling, if provided + // + if (remainder) + { + (*remainder).assign(mVolumeFaces.begin() + new_count, mVolumeFaces.end()); + } + + // Trim down to the final set of volume faces (now stuffed to the gills!) + // + mVolumeFaces.resize(new_count); } } @@ -1012,6 +325,43 @@ void LLModel::getNormalizedScaleTranslation(LLVector3& scale_out, LLVector3& tra translation_out = mNormalizedTranslation; } +LLVector3 LLModel::getTransformedCenter(const LLMatrix4& mat) +{ + LLVector3 ret; + + if (!mVolumeFaces.empty()) + { + LLMatrix4a m; + m.loadu(mat); + + LLVector4a minv,maxv; + + LLVector4a t; + m.affineTransform(mVolumeFaces[0].mPositions[0], t); + minv = maxv = t; + + for (S32 i = 0; i < (S32)mVolumeFaces.size(); ++i) + { + LLVolumeFace& face = mVolumeFaces[i]; + + for (U32 j = 0; j < (U32)face.mNumVertices; ++j) + { + m.affineTransform(face.mPositions[j],t); + update_min_max(minv, maxv, t); + } + } + + minv.add(maxv); + minv.mul(0.5f); + + ret.set(minv.getF32ptr()); + } + + return ret; +} + + + void LLModel::setNumVolumeFaces(S32 count) { mVolumeFaces.resize(count); @@ -1038,7 +388,7 @@ void LLModel::setVolumeFaceData( } else { - ll_aligned_free_16(face.mNormals); + //ll_aligned_free_16(face.mNormals); face.mNormals = NULL; } @@ -1049,7 +399,7 @@ void LLModel::setVolumeFaceData( } else { - ll_aligned_free_16(face.mTexCoords); + //ll_aligned_free_16(face.mTexCoords); face.mTexCoords = NULL; } @@ -1057,52 +407,18 @@ void LLModel::setVolumeFaceData( LLVector4a::memcpyNonAliased16((F32*) face.mIndices, (F32*) ind.get(), size); } -void LLModel::appendFaces(LLModel *model, LLMatrix4 &transform, LLMatrix4& norm_mat) -{ - if (mVolumeFaces.empty()) - { - setNumVolumeFaces(1); - } - - LLVolumeFace& face = mVolumeFaces[mVolumeFaces.size()-1]; - - - for (S32 i = 0; i < model->getNumFaces(); ++i) - { - face.appendFace(model->getVolumeFace(i), transform, norm_mat); - } - -} - -void LLModel::appendFace(const LLVolumeFace& src_face, std::string src_material, LLMatrix4& mat, LLMatrix4& norm_mat) -{ - S32 rindex = getNumVolumeFaces()-1; - if (rindex == -1 || - mVolumeFaces[rindex].mNumVertices + src_face.mNumVertices >= 65536) - { //empty or overflow will occur, append new face - LLVolumeFace cur_face; - cur_face.appendFace(src_face, mat, norm_mat); - addFace(cur_face); - mMaterialList.push_back(src_material); - } - else - { //append to existing end face - mVolumeFaces.rbegin()->appendFace(src_face, mat, norm_mat); - } -} - void LLModel::addFace(const LLVolumeFace& face) { if (face.mNumVertices == 0) { - llerrs << "Cannot add empty face." << llendl; + LL_ERRS() << "Cannot add empty face." << LL_ENDL; } mVolumeFaces.push_back(face); if (mVolumeFaces.size() > MAX_MODEL_FACES) { - llerrs << "Model prims cannot have more than " << MAX_MODEL_FACES << " faces!" << llendl; + LL_ERRS() << "Model prims cannot have more than " << MAX_MODEL_FACES << " faces!" << LL_ENDL; } } @@ -1124,7 +440,7 @@ void LLModel::generateNormals(F32 angle_cutoff) if (vol_face.mNumIndices > 65535) { - llwarns << "Too many vertices for normal generation to work." << llendl; + LL_WARNS() << "Too many vertices for normal generation to work." << LL_ENDL; continue; } @@ -1173,7 +489,9 @@ void LLModel::generateNormals(F32 angle_cutoff) } //weld vertices in temporary face, respecting angle_cutoff (step 2) + //validate_face(faceted); faceted.optimize(angle_cutoff); + //validate_face(faceted); //generate normals for welded face based on new topology (step 3) @@ -1248,7 +566,7 @@ void LLModel::generateNormals(F32 angle_cutoff) } else { - ll_aligned_free_16(new_face.mTexCoords); + //ll_aligned_free_16(new_face.mTexCoords); new_face.mTexCoords = NULL; } @@ -1305,74 +623,17 @@ void LLModel::generateNormals(F32 angle_cutoff) } //remove redundant vertices from new face (step 6) + //validate_face(new_face); new_face.optimize(); + //validate_face(new_face); mVolumeFaces[j] = new_face; } } -//static -std::string LLModel::getElementLabel(daeElement *element) -{ // try to get a decent label for this element - // if we have a name attribute, use it - std::string name = element->getAttribute("name"); - if (name.length()) - { - return name; - } - - // if we have an ID attribute, use it - if (element->getID()) - { - return std::string(element->getID()); - } - - // if we have a parent, use it - daeElement* parent = element->getParent(); - if (parent) - { - // if parent has a name, use it - std::string name = parent->getAttribute("name"); - if (name.length()) - { - return name; - } - - // if parent has an ID, use it - if (parent->getID()) - { - return std::string(parent->getID()); - } - } - - // try to use our type - daeString element_name = element->getElementName(); - if (element_name) - { - return std::string(element_name); - } - - // if all else fails, use "object" - return std::string("object"); -} - -//static -LLModel* LLModel::loadModelFromDomMesh(domMesh *mesh) -{ - LLVolumeParams volume_params; - volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); - LLModel* ret = new LLModel(volume_params, 0.f); - ret->createVolumeFacesFromDomMesh(mesh); - ret->mLabel = getElementLabel(mesh); - return ret; -} - std::string LLModel::getName() const { - if (!mRequestedLabel.empty()) - return mRequestedLabel; - else - return mLabel; + return mRequestedLabel.empty() ? mLabel : mRequestedLabel; } //static @@ -1386,8 +647,10 @@ LLSD LLModel::writeModel( const LLModel::Decomposition& decomp, BOOL upload_skin, BOOL upload_joints, + BOOL lock_scale_if_joint_position, BOOL nowrite, - BOOL as_slm) + BOOL as_slm, + int submodel_id) { LLSD mdl; @@ -1404,7 +667,7 @@ LLSD LLModel::writeModel( if (skinning) { //write skinning block - mdl["skin"] = high->mSkinInfo.asLLSD(upload_joints); + mdl["skin"] = high->mSkinInfo.asLLSD(upload_joints, lock_scale_if_joint_position); } if (!decomp.mBaseHull.empty() || @@ -1416,6 +679,14 @@ LLSD LLModel::writeModel( model[LLModel::LOD_PHYSICS] = NULL; } } + else if (submodel_id) + { + const LLModel::Decomposition fake_decomp; + mdl["secondary"] = true; + mdl["submodel_id"] = submodel_id; + mdl["physics_convex"] = fake_decomp.asLLSD(); + model[LLModel::LOD_PHYSICS] = NULL; + } if (as_slm) { //save material list names @@ -1427,7 +698,7 @@ LLSD LLModel::writeModel( for (U32 idx = 0; idx < MODEL_NAMES_LENGTH; ++idx) { - if (model[idx] && model[idx]->getNumVolumeFaces() > 0) + if (model[idx] && (model[idx]->getNumVolumeFaces() > 0) && model[idx]->getVolumeFace(0).mPositions != NULL) { LLVector3 min_pos = LLVector3(model[idx]->getVolumeFace(0).mPositions[0].getF32ptr()); LLVector3 max_pos = min_pos; @@ -1512,11 +783,11 @@ LLSD LLModel::writeModel( } } - F32* src_tc = (F32*) face.mTexCoords[j].mV; - //texcoord if (face.mTexCoords) { + F32* src_tc = (F32*) face.mTexCoords[j].mV; + for (U32 k = 0; k < 2; ++k) { //for each component //convert to 16-bit normalized @@ -1554,6 +825,7 @@ LLSD LLModel::writeModel( mdl[model_names[idx]][i]["TexCoord0Domain"]["Max"] = max_tc.getValue(); mdl[model_names[idx]][i]["TexCoord0"] = tc; } + mdl[model_names[idx]][i]["TriangleList"] = indices; if (skinning) @@ -1659,6 +931,11 @@ LLSD LLModel::writeModelToStream(std::ostream& ostr, LLSD& mdl, BOOL nowrite, BO } } + if (mdl.has("submodel_id")) + { //write out submodel id + header["submodel_id"] = (LLSD::Integer)mdl["submodel_id"]; + } + std::string out[MODEL_NAMES_LENGTH]; for (S32 i = 0; i < MODEL_NAMES_LENGTH; i++) @@ -1723,7 +1000,7 @@ LLModel::weight_list& LLModel::getJointInfluences(const LLVector3& pos) { if ((iter->first - pos).magVec() > 0.1f) { - llerrs << "Couldn't find weight list." << llendl; + LL_ERRS() << "Couldn't find weight list." << LL_ENDL; } return iter->second; @@ -1732,8 +1009,11 @@ LLModel::weight_list& LLModel::getJointInfluences(const LLVector3& pos) { //no exact match found, get closest point const F32 epsilon = 1e-5f; weight_map::iterator iter_up = mSkinWeights.lower_bound(pos); - weight_map::iterator iter_down = ++iter_up; - + weight_map::iterator iter_down = iter_up; + if (iter_up != mSkinWeights.end()) + { + iter_down = ++iter_up; + } weight_map::iterator best = iter_up; F32 min_dist = (iter->first - pos).magVec(); @@ -1828,7 +1108,7 @@ bool LLModel::loadModel(std::istream& is) { if (!LLSDSerialize::fromBinary(header, is, 1024*1024*1024)) { - llwarns << "Mesh header parse error. Not a valid mesh asset!" << llendl; + LL_WARNS() << "Mesh header parse error. Not a valid mesh asset!" << LL_ENDL; return false; } } @@ -1842,46 +1122,45 @@ bool LLModel::loadModel(std::istream& is) } } - std::string nm[] = - { + mSubmodelID = header.has("submodel_id") ? header["submodel_id"].asInteger() : false; + + static const std::array lod_name = {{ "lowest_lod", "low_lod", "medium_lod", "high_lod", "physics_mesh", - }; + }}; - const S32 MODEL_LODS = 5; + S32 lod = llclamp((S32) mDetail, 0, (S32)lod_name.size() - 1); - S32 lod = llclamp((S32) mDetail, 0, MODEL_LODS); - - if (header[nm[lod]]["offset"].asInteger() == -1 || - header[nm[lod]]["size"].asInteger() == 0 ) + if (header[lod_name[lod]]["offset"].asInteger() == -1 || + header[lod_name[lod]]["size"].asInteger() == 0 ) { //cannot load requested LOD - llwarns << "LoD data is invalid!" << llendl; + LL_WARNS() << "LoD data is invalid!" << LL_ENDL; return false; } bool has_skin = header["skin"]["offset"].asInteger() >=0 && header["skin"]["size"].asInteger() > 0; - if (lod == LLModel::LOD_HIGH) + if ((lod == LLModel::LOD_HIGH) && !mSubmodelID) { //try to load skin info and decomp info std::ios::pos_type cur_pos = is.tellg(); loadSkinInfo(header, is); is.seekg(cur_pos); } - if (lod == LLModel::LOD_HIGH || lod == LLModel::LOD_PHYSICS) + if ((lod == LLModel::LOD_HIGH || lod == LLModel::LOD_PHYSICS) && !mSubmodelID) { std::ios::pos_type cur_pos = is.tellg(); loadDecomposition(header, is); is.seekg(cur_pos); } - is.seekg(header[nm[lod]]["offset"].asInteger(), std::ios_base::cur); + is.seekg(header[lod_name[lod]]["offset"].asInteger(), std::ios_base::cur); - if (unpackVolumeFaces(is, header[nm[lod]]["size"].asInteger())) + if (unpackVolumeFaces(is, header[lod_name[lod]]["size"].asInteger())) { if (has_skin) { @@ -1921,7 +1200,7 @@ bool LLModel::loadModel(std::istream& is) } else { - llwarns << "unpackVolumeFaces failed!" << llendl; + LL_WARNS() << "unpackVolumeFaces failed!" << LL_ENDL; } return false; @@ -1939,7 +1218,7 @@ bool LLModel::isMaterialListSubset( LLModel* ref ) for (S32 dst = 0; dst < refCnt; ++dst) { - //llinfos<mMaterialList[dst]<mMaterialList[dst]<mMaterialList[dst]; if ( foundRef ) @@ -1947,8 +1226,10 @@ bool LLModel::isMaterialListSubset( LLModel* ref ) break; } } + if (!foundRef) { + LL_INFOS() << "Could not find material " << mMaterialList[src] << " in reference model " << ref->mLabel << LL_ENDL; return false; } } @@ -1984,7 +1265,7 @@ bool LLModel::matchMaterialOrder(LLModel* ref, int& refFaceCnt, int& modelFaceCn bool isASubset = isMaterialListSubset( ref ); if ( !isASubset ) { - llinfos<<"Material of model is not a subset of reference."<mMaterialList[i]] = i; - if (!reorder) - { //if any material name does not match reference, we need to reorder - reorder = ref->mMaterialList[i] != mMaterialList[i]; - } + //if any material name does not match reference, we need to reorder + reorder |= ref->mMaterialList[i] != mMaterialList[i]; base_mat.insert(ref->mMaterialList[i]); cur_mat.insert(mMaterialList[i]); } - if (reorder && - base_mat == cur_mat) //don't reorder if material name sets don't match + if (reorder && (base_mat == cur_mat)) //don't reorder if material name sets don't match { std::vector new_face_list; - new_face_list.resize(mVolumeFaces.size()); + new_face_list.resize(mMaterialList.size()); std::vector new_material_list; - new_material_list.resize(mVolumeFaces.size()); + new_material_list.resize(mMaterialList.size()); //rebuild face list so materials have the same order //as the reference model for (U32 i = 0; i < mMaterialList.size(); ++i) { U32 ref_idx = index_map[mMaterialList[i]]; - new_face_list[ref_idx] = mVolumeFaces[i]; + if (i < mVolumeFaces.size()) + { + new_face_list[ref_idx] = mVolumeFaces[i]; + } new_material_list[ref_idx] = mMaterialList[i]; } llassert(new_material_list == ref->mMaterialList); mVolumeFaces = new_face_list; - } - //override material list with reference model ordering - mMaterialList = ref->mMaterialList; + //override material list with reference model ordering + mMaterialList = ref->mMaterialList; + } + return true; } @@ -2064,7 +1346,7 @@ bool LLModel::loadDecomposition(LLSD& header, std::istream& is) S32 offset = header["physics_convex"]["offset"].asInteger(); S32 size = header["physics_convex"]["size"].asInteger(); - if (offset >= 0 && size > 0) + if (offset >= 0 && size > 0 && !mSubmodelID) { is.seekg(offset, std::ios_base::cur); @@ -2080,8 +1362,19 @@ bool LLModel::loadDecomposition(LLSD& header, std::istream& is) return true; } +LLMeshSkinInfo::LLMeshSkinInfo(): + mPelvisOffset(0.0), + mLockScaleIfJointPosition(false), + mInvalidJointsScrubbed(false), + mJointNumsInitialized(false) +{ +} -LLMeshSkinInfo::LLMeshSkinInfo(LLSD& skin) +LLMeshSkinInfo::LLMeshSkinInfo(LLSD& skin): + mPelvisOffset(0.0), + mLockScaleIfJointPosition(false), + mInvalidJointsScrubbed(false), + mJointNumsInitialized(false) { fromLLSD(skin); } @@ -2090,10 +1383,11 @@ void LLMeshSkinInfo::fromLLSD(LLSD& skin) { if (skin.has("joint_names")) { - const U32 joint_count = llmin((U32)skin["joint_names"].size(),(U32)64); + const U32 joint_count = skin["joint_names"].size(); for (U32 i = 0; i < joint_count; ++i) { mJointNames.push_back(skin["joint_names"][i]); + mJointNums.push_back(-1); } } @@ -2146,9 +1440,18 @@ void LLMeshSkinInfo::fromLLSD(LLSD& skin) { mPelvisOffset = skin["pelvis_offset"].asReal(); } + + if (skin.has("lock_scale_if_joint_position")) + { + mLockScaleIfJointPosition = skin["lock_scale_if_joint_position"].asBoolean(); + } + else + { + mLockScaleIfJointPosition = false; + } } -LLSD LLMeshSkinInfo::asLLSD(bool include_joints) const +LLSD LLMeshSkinInfo::asLLSD(bool include_joints, bool lock_scale_if_joint_position) const { LLSD ret; @@ -2186,6 +1489,11 @@ LLSD LLMeshSkinInfo::asLLSD(bool include_joints) const } } + if (lock_scale_if_joint_position) + { + ret["lock_scale_if_joint_position"] = lock_scale_if_joint_position; + } + ret["pelvis_offset"] = mPelvisOffset; } @@ -2279,7 +1587,7 @@ void LLModel::Decomposition::fromLLSD(LLSD& decomp) range = max-min; - U16 count = position.size()/6; + size_t count = position.size()/6; for (U32 j = 0; j < count; ++j) { @@ -2436,7 +1744,7 @@ LLSD LLModel::Decomposition::asLLSD() const if (vert_idx > p.size()) { - llerrs << "Index out of bounds" << llendl; + LL_ERRS() << "Index out of bounds" << LL_ENDL; } } } @@ -2456,7 +1764,7 @@ void LLModel::Decomposition::merge(const LLModel::Decomposition* rhs) if (mMeshID != rhs->mMeshID) { - llerrs << "Attempted to merge with decomposition of some other mesh." << llendl; + LL_ERRS() << "Attempted to merge with decomposition of some other mesh." << LL_ENDL; } if (mBaseHull.empty()) @@ -2473,3 +1781,228 @@ void LLModel::Decomposition::merge(const LLModel::Decomposition* rhs) } } +bool ll_is_degenerate(const LLVector4a& a, const LLVector4a& b, const LLVector4a& c, F32 tolerance) +{ + // small area check + { + LLVector4a edge1; edge1.setSub( a, b ); + LLVector4a edge2; edge2.setSub( a, c ); + ////////////////////////////////////////////////////////////////////////// + /// Linden Modified + ////////////////////////////////////////////////////////////////////////// + + // If no one edge is more than 10x longer than any other edge, we weaken + // the tolerance by a factor of 1e-4f. + + LLVector4a edge3; edge3.setSub( c, b ); + const F32 len1sq = edge1.dot3(edge1).getF32(); + const F32 len2sq = edge2.dot3(edge2).getF32(); + const F32 len3sq = edge3.dot3(edge3).getF32(); + bool abOK = (len1sq <= 100.f * len2sq) && (len1sq <= 100.f * len3sq); + bool acOK = (len2sq <= 100.f * len1sq) && (len1sq <= 100.f * len3sq); + bool cbOK = (len3sq <= 100.f * len1sq) && (len1sq <= 100.f * len2sq); + if ( abOK && acOK && cbOK ) + { + tolerance *= 1e-4f; + } + + ////////////////////////////////////////////////////////////////////////// + /// End Modified + ////////////////////////////////////////////////////////////////////////// + + LLVector4a cross; cross.setCross3( edge1, edge2 ); + + LLVector4a edge1b; edge1b.setSub( b, a ); + LLVector4a edge2b; edge2b.setSub( b, c ); + LLVector4a crossb; crossb.setCross3( edge1b, edge2b ); + + if ( ( cross.dot3(cross).getF32() < tolerance ) || ( crossb.dot3(crossb).getF32() < tolerance )) + { + return true; + } + } + + // point triangle distance check + { + LLVector4a Q; Q.setSub(a, b); + LLVector4a R; R.setSub(c, b); + + const F32 QQ = dot3fpu(Q, Q); + const F32 RR = dot3fpu(R, R); + const F32 QR = dot3fpu(R, Q); + + volatile F32 QQRR = QQ * RR; + volatile F32 QRQR = QR * QR; + F32 Det = (QQRR - QRQR); + + if( Det == 0.0f ) + { + return true; + } + } + + return false; +} + +bool validate_face(const LLVolumeFace& face) +{ + for (S32 i = 0; i < face.mNumIndices; ++i) + { + if (face.mIndices[i] >= face.mNumVertices) + { + LL_WARNS() << "Face has invalid index." << LL_ENDL; + LL_WARNS() << "face.mIndices[" << i << "]=" << face.mIndices[i] << " face.mNumVertices=" << face.mNumVertices << LL_ENDL; + return false; + } + } + + if (face.mNumIndices % 3 != 0 || face.mNumIndices == 0) + { + LL_WARNS() << "Face has invalid number of indices." << LL_ENDL; + return false; + } + + /*const LLVector4a scale(0.5f); + + for (U32 i = 0; i < face.mNumIndices; i+=3) + { + U16 idx1 = face.mIndices[i]; + U16 idx2 = face.mIndices[i+1]; + U16 idx3 = face.mIndices[i+2]; + + LLVector4a v1; v1.setMul(face.mPositions[idx1], scale); + LLVector4a v2; v2.setMul(face.mPositions[idx2], scale); + LLVector4a v3; v3.setMul(face.mPositions[idx3], scale); + + if (ll_is_degenerate(v1,v2,v3)) + { + llwarns << "Degenerate face found!" << LL_ENDL; + return false; + } + }*/ + + return true; +} + +bool validate_model(const LLModel* mdl) +{ + if (mdl->getNumVolumeFaces() == 0) + { + LL_WARNS() << "Model has no faces!" << LL_ENDL; + return false; + } + + for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) + { + if (mdl->getVolumeFace(i).mNumVertices == 0) + { + LL_WARNS() << "Face has no vertices." << LL_ENDL; + return false; + } + + if (mdl->getVolumeFace(i).mNumIndices == 0) + { + LL_WARNS() << "Face has no indices." << LL_ENDL; + return false; + } + + if (!validate_face(mdl->getVolumeFace(i))) + { + return false; + } + } + + return true; +} + +LLModelInstance::LLModelInstance(LLSD& data) + : LLModelInstanceBase() +{ + mLocalMeshID = data["mesh_id"].asInteger(); + mLabel = data["label"].asString(); + mTransform.setValue(data["transform"]); + + for (U32 i = 0; i < (U32)data["material"].size(); ++i) + { + LLImportMaterial mat(data["material"][i]); + mMaterial[mat.mBinding] = mat; + } +} + + +LLSD LLModelInstance::asLLSD() +{ + LLSD ret; + + ret["mesh_id"] = mModel->mLocalID; + ret["label"] = mLabel; + ret["transform"] = mTransform.getValue(); + + U32 i = 0; + for (std::map::iterator iter = mMaterial.begin(); iter != mMaterial.end(); ++iter) + { + ret["material"][i++] = iter->second.asLLSD(); + } + + return ret; +} + + +LLImportMaterial::~LLImportMaterial() +{ +} + +LLImportMaterial::LLImportMaterial(LLSD& data) +{ + mDiffuseMapFilename = data["diffuse"]["filename"].asString(); + mDiffuseMapLabel = data["diffuse"]["label"].asString(); + mDiffuseColor.setValue(data["diffuse"]["color"]); + mFullbright = data["fullbright"].asBoolean(); + mBinding = data["binding"].asString(); +} + + +LLSD LLImportMaterial::asLLSD() +{ + LLSD ret; + + ret["diffuse"]["filename"] = mDiffuseMapFilename; + ret["diffuse"]["label"] = mDiffuseMapLabel; + ret["diffuse"]["color"] = mDiffuseColor.getValue(); + ret["fullbright"] = mFullbright; + ret["binding"] = mBinding; + + return ret; +} + +bool LLImportMaterial::operator<(const LLImportMaterial &rhs) const +{ + + if (mDiffuseMapID != rhs.mDiffuseMapID) + { + return mDiffuseMapID < rhs.mDiffuseMapID; + } + + if (mDiffuseMapFilename != rhs.mDiffuseMapFilename) + { + return mDiffuseMapFilename < rhs.mDiffuseMapFilename; + } + + if (mDiffuseMapLabel != rhs.mDiffuseMapLabel) + { + return mDiffuseMapLabel < rhs.mDiffuseMapLabel; + } + + if (mDiffuseColor != rhs.mDiffuseColor) + { + return mDiffuseColor < rhs.mDiffuseColor; + } + + if (mBinding != rhs.mBinding) + { + return mBinding < rhs.mBinding; + } + + return mFullbright < rhs.mFullbright; +} + diff --git a/indra/llprimitive/llmodel.h b/indra/llprimitive/llmodel.h index 1cf528fd9f..9b1df2a0e1 100644 --- a/indra/llprimitive/llmodel.h +++ b/indra/llprimitive/llmodel.h @@ -31,6 +31,7 @@ #include "llvolume.h" #include "v4math.h" #include "m4math.h" +#include class daeElement; class domMesh; @@ -41,18 +42,22 @@ class domMesh; class LLMeshSkinInfo { public: + LLMeshSkinInfo(); + LLMeshSkinInfo(LLSD& data); + void fromLLSD(LLSD& data); + LLSD asLLSD(bool include_joints, bool lock_scale_if_joint_position) const; + LLUUID mMeshID; std::vector mJointNames; + mutable std::vector mJointNums; std::vector mInvBindMatrix; std::vector mAlternateBindMatrix; - std::map mJointMap; - LLMeshSkinInfo() { } - LLMeshSkinInfo(LLSD& data); - void fromLLSD(LLSD& data); - LLSD asLLSD(bool include_joints) const; LLMatrix4 mBindShapeMatrix; float mPelvisOffset; + bool mLockScaleIfJointPosition; + bool mInvalidJointsScrubbed; + bool mJointNumsInitialized; }; class LLModel : public LLVolume @@ -137,24 +142,23 @@ class LLModel : public LLVolume const LLModel::Decomposition& decomp, BOOL upload_skin, BOOL upload_joints, + BOOL lock_scale_if_joint_position, BOOL nowrite = FALSE, - BOOL as_slm = FALSE); + BOOL as_slm = FALSE, + int submodel_id = 0); static LLSD writeModelToStream( std::ostream& ostr, LLSD& mdl, BOOL nowrite = FALSE, BOOL as_slm = FALSE); + + void ClearFacesAndMaterials() { mVolumeFaces.clear(); mMaterialList.clear(); } - static LLModel* loadModelFromDomMesh(domMesh* mesh); - static std::string getElementLabel(daeElement* element); std::string getName() const; std::string getMetric() const {return mMetric;} EModelStatus getStatus() const {return mStatus;} static std::string getStatusString(U32 status) ; - void appendFaces(LLModel* model, LLMatrix4& transform, LLMatrix4& normal_transform); - void appendFace(const LLVolumeFace& src_face, std::string src_material, LLMatrix4& mat, LLMatrix4& norm_mat); - void setNumVolumeFaces(S32 count); void setVolumeFaceData( S32 f, @@ -169,18 +173,25 @@ class LLModel : public LLVolume void addFace(const LLVolumeFace& face); + void sortVolumeFacesByMaterialName(); void normalizeVolumeFaces(); + void trimVolumeFacesToSize(U32 new_count = LL_SCULPT_MESH_MAX_FACES, LLVolume::face_list_t* remainder = NULL); void optimizeVolumeFaces(); void offsetMesh( const LLVector3& pivotPoint ); void getNormalizedScaleTranslation(LLVector3& scale_out, LLVector3& translation_out); - + LLVector3 getTransformedCenter(const LLMatrix4& mat); + //reorder face list based on mMaterialList in this and reference so //order matches that of reference (material ordering touchup) bool matchMaterialOrder(LLModel* ref, int& refFaceCnt, int& modelFaceCnt ); bool isMaterialListSubset( LLModel* ref ); bool needToAddFaces( LLModel* ref, int& refFaceCnt, int& modelFaceCnt ); - std::vector mMaterialList; + typedef std::vector material_list; + + material_list mMaterialList; + + material_list& getMaterialList() { return mMaterialList; } //data used for skin weights class JointWeight @@ -273,9 +284,115 @@ class LLModel : public LLVolume Decomposition mPhysics; EModelStatus mStatus ; + + int mSubmodelID; +}; + +typedef std::vector > model_list; +typedef std::queue > model_queue; + +class LLModelMaterialBase +{ +public: + std::string mDiffuseMapFilename; + std::string mDiffuseMapLabel; + std::string mBinding; + LLColor4 mDiffuseColor; + bool mFullbright; + + LLModelMaterialBase() + : mFullbright(false) + { + mDiffuseColor.set(1,1,1,1); + } +}; + +class LLImportMaterial : public LLModelMaterialBase +{ +public: + friend class LLMeshUploadThread; + friend class LLModelPreview; + + bool operator<(const LLImportMaterial ¶ms) const; + + LLImportMaterial() : LLModelMaterialBase() + { + mDiffuseColor.set(1,1,1,1); + } + + LLImportMaterial(LLSD& data); + virtual ~LLImportMaterial(); + + LLSD asLLSD(); + + const LLUUID& getDiffuseMap() const { return mDiffuseMapID; } + void setDiffuseMap(const LLUUID& texId) { mDiffuseMapID = texId; } + protected: - void addVolumeFacesFromDomMesh(domMesh* mesh); - virtual BOOL createVolumeFacesFromDomMesh(domMesh *mesh); + + LLUUID mDiffuseMapID; + void* mOpaqueData; // allow refs to viewer/platform-specific structs for each material + // currently only stores an LLPointer< LLViewerFetchedTexture > > to + // maintain refs to textures associated with each material for free + // ref counting. +}; + +typedef std::map material_map; + +class LLModelInstanceBase +{ +public: + LLPointer mModel; + LLPointer mLOD[5]; + LLUUID mMeshID; + + LLMatrix4 mTransform; + material_map mMaterial; + + LLModelInstanceBase(LLModel* model, LLMatrix4& transform, material_map& materials) + : mModel(model), mTransform(transform), mMaterial(materials) + { + } + + LLModelInstanceBase() + : mModel(NULL) + { + } }; +typedef std::vector model_instance_list; + +class LLModelInstance : public LLModelInstanceBase +{ +public: + std::string mLabel; + LLUUID mMeshID; + S32 mLocalMeshID; + + LLModelInstance(LLModel* model, const std::string& label, LLMatrix4& transform, material_map& materials) + : LLModelInstanceBase(model, transform, materials), mLabel(label) + { + mLocalMeshID = -1; + } + + LLModelInstance(LLSD& data); + + LLSD asLLSD(); +}; + +#define LL_DEGENERACY_TOLERANCE 1e-7f + +inline F32 dot3fpu(const LLVector4a& a, const LLVector4a& b) +{ + volatile F32 p0 = a[0] * b[0]; + volatile F32 p1 = a[1] * b[1]; + volatile F32 p2 = a[2] * b[2]; + return p0 + p1 + p2; +} + +bool ll_is_degenerate(const LLVector4a& a, const LLVector4a& b, const LLVector4a& c, F32 tolerance = LL_DEGENERACY_TOLERANCE); + +bool validate_face(const LLVolumeFace& face); +bool validate_model(const LLModel* mdl); + #endif //LL_LLMODEL_H diff --git a/indra/llprimitive/llmodelloader.cpp b/indra/llprimitive/llmodelloader.cpp new file mode 100644 index 0000000000..50e36100d6 --- /dev/null +++ b/indra/llprimitive/llmodelloader.cpp @@ -0,0 +1,487 @@ +/** + * @file llmodelloader.cpp + * @brief LLModelLoader class implementation + * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llmodelloader.h" +#include "llsdserialize.h" +#include "lljoint.h" +#include "llcallbacklist.h" + +#include "llmatrix4a.h" +#include +#include "apr_time.h" + +std::list LLModelLoader::sActiveLoaderList; + +void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4a& max, BOOL& first_transform) +{ + LLVector4a box[] = + { + LLVector4a(-1, 1,-1), + LLVector4a(-1, 1, 1), + LLVector4a(-1,-1,-1), + LLVector4a(-1,-1, 1), + LLVector4a( 1, 1,-1), + LLVector4a( 1, 1, 1), + LLVector4a( 1,-1,-1), + LLVector4a( 1,-1, 1), + }; + + for (S32 j = 0; j < model->getNumVolumeFaces(); ++j) + { + const LLVolumeFace& face = model->getVolumeFace(j); + + LLVector4a center; + center.setAdd(face.mExtents[0], face.mExtents[1]); + center.mul(0.5f); + LLVector4a size; + size.setSub(face.mExtents[1],face.mExtents[0]); + size.mul(0.5f); + + for (U32 i = 0; i < 8; i++) + { + LLVector4a t; + t.setMul(size, box[i]); + t.add(center); + + LLVector4a v; + + mat.affineTransform(t, v); + + if (first_transform) + { + first_transform = FALSE; + min = max = v; + } + else + { + update_min_max(min, max, v); + } + } + } +} + +void stretch_extents(LLModel* model, LLMatrix4& mat, LLVector3& min, LLVector3& max, BOOL& first_transform) +{ + LLVector4a mina, maxa; + LLMatrix4a mata; + + mata.loadu(mat); + mina.load3(min.mV); + maxa.load3(max.mV); + + stretch_extents(model, mata, mina, maxa, first_transform); + + min.set(mina.getF32ptr()); + max.set(maxa.getF32ptr()); +} + +//----------------------------------------------------------------------------- +// LLModelLoader +//----------------------------------------------------------------------------- +LLModelLoader::LLModelLoader( + std::string filename, + S32 lod, + load_callback_t load_cb, + joint_lookup_func_t joint_lookup_func, + texture_load_func_t texture_load_func, + state_callback_t state_cb, + void* opaque_userdata, + JointTransformMap& jointTransformMap, + JointNameSet& jointsFromNodes, + JointMap& legalJointNamesMap, + U32 maxJointsPerMesh) +: mJointList( jointTransformMap ) +, mJointsFromNode( jointsFromNodes ) +, LLThread("Model Loader") +, mFilename(filename) +, mLod(lod) +, mTrySLM(false) +, mFirstTransform(TRUE) +, mNumOfFetchingTextures(0) +, mLoadCallback(load_cb) +, mJointLookupFunc(joint_lookup_func) +, mTextureLoadFunc(texture_load_func) +, mStateCallback(state_cb) +, mOpaqueData(opaque_userdata) +, mRigValidJointUpload(true) +, mLegacyRigValid(true) +, mNoNormalize(false) +, mNoOptimize(false) +, mCacheOnlyHitIfRigged(false) +, mMaxJointsPerMesh(maxJointsPerMesh) +, mJointMap(legalJointNamesMap) +{ + assert_main_thread(); + sActiveLoaderList.push_back(this) ; +} + +LLModelLoader::~LLModelLoader() +{ + assert_main_thread(); + sActiveLoaderList.remove(this); +} + +void LLModelLoader::run() +{ + doLoadModel(); + doOnIdleOneTime(boost::bind(&LLModelLoader::loadModelCallback,this)); +} + +// static +bool LLModelLoader::getSLMFilename(const std::string& model_filename, std::string& slm_filename) +{ + slm_filename = model_filename; + + std::string::size_type i = model_filename.rfind("."); + if (i != std::string::npos) + { + slm_filename.replace(i, model_filename.size()-1, ".slm"); + return true; + } + else + { + return false; + } +} + +bool LLModelLoader::doLoadModel() +{ + //first, look for a .slm file of the same name that was modified later + //than the .dae + + if (mTrySLM) + { + std::string slm_filename; + if (getSLMFilename(mFilename, slm_filename)) + { + llstat slm_status; + if (LLFile::stat(slm_filename, &slm_status) == 0) + { //slm file exists + llstat dae_status; + if (LLFile::stat(mFilename, &dae_status) != 0 || + dae_status.st_mtime < slm_status.st_mtime) + { + if (loadFromSLM(slm_filename)) + { //slm successfully loaded, if this fails, fall through and + //try loading from dae + + mLod = -1; //successfully loading from an slm implicitly sets all + //LoDs + return true; + } + } + } + } + } + + return OpenFile(mFilename); +} + +void LLModelLoader::setLoadState(U32 state) +{ + mStateCallback(state, mOpaqueData); +} + +bool LLModelLoader::loadFromSLM(const std::string& filename) +{ + //only need to populate mScene with data from slm + llstat stat; + + if (LLFile::stat(filename, &stat)) + { //file does not exist + return false; + } + + S32 file_size = (S32) stat.st_size; + + llifstream ifstream(filename.c_str(), std::ifstream::in | std::ifstream::binary); + LLSD data; + LLSDSerialize::fromBinary(data, ifstream, file_size); + ifstream.close(); + + //build model list for each LoD + model_list model[LLModel::NUM_LODS]; + + if (data["version"].asInteger() != SLM_SUPPORTED_VERSION) + { //unsupported version + return false; + } + + LLSD& mesh = data["mesh"]; + + LLVolumeParams volume_params; + volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); + + for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod) + { + for (U32 i = 0; i < (U32)mesh.size(); ++i) + { + std::stringstream str(mesh[i].asString()); + LLPointer loaded_model = new LLModel(volume_params, (F32) lod); + if (loaded_model->loadModel(str)) + { + loaded_model->mLocalID = i; + model[lod].push_back(loaded_model); + + if (lod == LLModel::LOD_HIGH) + { + if (!loaded_model->mSkinInfo.mJointNames.empty()) + { + //check to see if rig is valid + critiqueRigForUploadApplicability( loaded_model->mSkinInfo.mJointNames ); + } + else if (mCacheOnlyHitIfRigged) + { + return false; + } + } + } + } + } + + if (model[LLModel::LOD_HIGH].empty()) + { //failed to load high lod + return false; + } + + //load instance list + model_instance_list instance_list; + + LLSD& instance = data["instance"]; + + for (U32 i = 0; i < (U32)instance.size(); ++i) + { + //deserialize instance list + instance_list.push_back(LLModelInstance(instance[i])); + + //match up model instance pointers + S32 idx = instance_list[i].mLocalMeshID; + std::string instance_label = instance_list[i].mLabel; + + for (U32 lod = 0; lod < LLModel::NUM_LODS; ++lod) + { + if (!model[lod].empty()) + { + if (idx >= (S32)model[lod].size()) + { + if (model[lod].size()) + { + instance_list[i].mLOD[lod] = model[lod][0]; + } + else + { + instance_list[i].mLOD[lod] = NULL; + } + continue; + } + + if (model[lod][idx] + && model[lod][idx]->mLabel.empty() + && !instance_label.empty()) + { + // restore model names + std::string name = instance_label; + switch (lod) + { + case LLModel::LOD_IMPOSTOR: name += "_LOD0"; break; + case LLModel::LOD_LOW: name += "_LOD1"; break; + case LLModel::LOD_MEDIUM: name += "_LOD2"; break; + case LLModel::LOD_PHYSICS: name += "_PHYS"; break; + case LLModel::LOD_HIGH: break; + } + model[lod][idx]->mLabel = name; + } + + instance_list[i].mLOD[lod] = model[lod][idx]; + } + } + + if (!instance_list[i].mModel) + instance_list[i].mModel = model[LLModel::LOD_HIGH][idx]; + } + + // Set name for UI to use + std::string name = data["name"]; + if (!name.empty()) + { + model[LLModel::LOD_HIGH][0]->mRequestedLabel = name; + } + + + //convert instance_list to mScene + mFirstTransform = TRUE; + for (U32 i = 0; i < instance_list.size(); ++i) + { + LLModelInstance& cur_instance = instance_list[i]; + mScene[cur_instance.mTransform].push_back(cur_instance); + stretch_extents(cur_instance.mModel, cur_instance.mTransform, mExtents[0], mExtents[1], mFirstTransform); + } + + setLoadState( DONE ); + + return true; +} + +//static +bool LLModelLoader::isAlive(LLModelLoader* loader) +{ + if(!loader) + { + return false ; + } + + std::list::iterator iter = sActiveLoaderList.begin() ; + for(; iter != sActiveLoaderList.end() && (*iter) != loader; ++iter) ; + + return *iter == loader ; +} + +void LLModelLoader::loadModelCallback() +{ + mLoadCallback(mScene,mModelList,mLod, mOpaqueData); + + while (!isStopped()) + { //wait until this thread is stopped before deleting self + apr_sleep(100); + } + + //double check if "this" is valid before deleting it, in case it is aborted during running. + if(!isAlive(this)) + { + return ; + } + + delete this; +} + +//----------------------------------------------------------------------------- +// critiqueRigForUploadApplicability() +//----------------------------------------------------------------------------- +void LLModelLoader::critiqueRigForUploadApplicability( const std::vector &jointListFromAsset ) +{ + //Determines the following use cases for a rig: + //1. It is suitable for upload with skin weights & joint positions, or + //2. It is suitable for upload as standard av with just skin weights + + bool isJointPositionUploadOK = isRigSuitableForJointPositionUpload( jointListFromAsset ); + bool isRigLegacyOK = isRigLegacy( jointListFromAsset ); + + //It's OK that both could end up being true, both default to false + + // Both start out as true and are forced to false if any mesh in + // the model file is not vald by that criterion. Note that a file + // can contain multiple meshes. + if ( !isJointPositionUploadOK ) + { + // This starts out true, becomes false if false for any loaded + // mesh. + setRigValidForJointPositionUpload( false ); + } + + if ( !isRigLegacyOK) + { + // This starts out true, becomes false if false for any loaded + // mesh. + setLegacyRigValid( false ); + } + +} + +//----------------------------------------------------------------------------- +// isRigLegacy() +//----------------------------------------------------------------------------- +bool LLModelLoader::isRigLegacy( const std::vector &jointListFromAsset ) +{ + //No joints in asset + if ( jointListFromAsset.size() == 0 ) + { + return false; + } + + // Too many joints in asset + if (jointListFromAsset.size()>mMaxJointsPerMesh) + { + LL_WARNS() << "Rigged to " << jointListFromAsset.size() << " joints, max is " << mMaxJointsPerMesh << LL_ENDL; + LL_WARNS() << "Skinning disabled due to too many joints" << LL_ENDL; + return false; + } + + // Unknown joints in asset + S32 unknown_joint_count = 0; + for (std::vector::const_iterator it = jointListFromAsset.begin(); + it != jointListFromAsset.end(); ++it) + { + if (mJointMap.find(*it)==mJointMap.end()) + { + LL_WARNS() << "Rigged to unrecognized joint name " << *it << LL_ENDL; + unknown_joint_count++; + } + } + if (unknown_joint_count>0) + { + LL_WARNS() << "Skinning disabled due to unknown joints" << LL_ENDL; + return false; + } + + return true; +} +//----------------------------------------------------------------------------- +// isRigSuitableForJointPositionUpload() +//----------------------------------------------------------------------------- +bool LLModelLoader::isRigSuitableForJointPositionUpload( const std::vector &jointListFromAsset ) +{ + return true; +} + + +//called in the main thread +void LLModelLoader::loadTextures() +{ + BOOL is_paused = isPaused() ; + pause() ; //pause the loader + + for(scene::iterator iter = mScene.begin(); iter != mScene.end(); ++iter) + { + for(U32 i = 0 ; i < iter->second.size(); i++) + { + for(std::map::iterator j = iter->second[i].mMaterial.begin(); + j != iter->second[i].mMaterial.end(); ++j) + { + LLImportMaterial& material = j->second; + + if(!material.mDiffuseMapFilename.empty()) + { + mNumOfFetchingTextures += mTextureLoadFunc(material, mOpaqueData); + } + } + } + } + + if(!is_paused) + { + unpause() ; + } +} diff --git a/indra/llprimitive/llmodelloader.h b/indra/llprimitive/llmodelloader.h new file mode 100644 index 0000000000..033dc5fd04 --- /dev/null +++ b/indra/llprimitive/llmodelloader.h @@ -0,0 +1,211 @@ +/** + * @file llmodelloader.h + * @brief LLModelLoader class definition + * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLMODELLOADER_H +#define LL_LLMODELLOADER_H + +#include "llmodel.h" +#include "llthread.h" +#include +#include + +class LLJoint; + +typedef std::map JointTransformMap; +typedef std::map:: iterator JointTransformMapIt; +typedef std::map JointMap; +typedef std::deque JointNameSet; + +const S32 SLM_SUPPORTED_VERSION = 3; +const S32 NUM_LOD = 4; + +class LLModelLoader : public LLThread +{ +public: + + typedef std::map material_map; + typedef std::vector > model_list; + typedef std::vector model_instance_list; + typedef std::map scene; + + // Callback with loaded model data and loaded LoD + // + typedef boost::function load_callback_t; + + // Function to provide joint lookup by name + // (within preview avi skeleton, for example) + // + typedef boost::function joint_lookup_func_t; + + // Func to load and associate material with all it's textures, + // returned value is the number of textures loaded + // intentionally non-const so func can modify material to + // store platform-specific data + // + typedef boost::function texture_load_func_t; + + // Callback to inform client of state changes + // during loading process (errors will be reported + // as state changes here as well) + // + typedef boost::function state_callback_t; + + typedef enum + { + STARTING = 0, + READING_FILE, + CREATING_FACES, + GENERATING_VERTEX_BUFFERS, + GENERATING_LOD, + DONE, + WARNING_BIND_SHAPE_ORIENTATION, + ERROR_PARSING, //basically loading failed + ERROR_MATERIALS, + ERROR_PASSWORD_REQUIRED, + ERROR_NEED_MORE_MEMORY, + ERROR_INVALID_FILE, + ERROR_LOADER_SETUP, + ERROR_INVALID_PARAMETERS, + ERROR_OUT_OF_RANGE, + ERROR_FILE_VERSION_INVALID, + ERROR_MODEL // this error should always be last in this list, error code is passed as ERROR_MODEL+error_code + } eLoadState; + + U32 mState; + std::string mFilename; + + S32 mLod; + + LLMatrix4 mTransform, mBindTransform; + BOOL mFirstTransform; + LLVector3 mExtents[2]; + + bool mTrySLM; + bool mCacheOnlyHitIfRigged; // ignore cached SLM if it does not contain rig info (and we want rig info) + + model_list mModelList; + scene mScene; + + typedef std::queue > model_queue; + + //queue of models that need a physics rep + model_queue mPhysicsQ; + + //map of avatar joints as named in COLLADA assets to internal joint names + JointMap mJointMap; + JointTransformMap& mJointList; + JointNameSet& mJointsFromNode; + U32 mMaxJointsPerMesh; + + LLModelLoader( + std::string filename, + S32 lod, + LLModelLoader::load_callback_t load_cb, + LLModelLoader::joint_lookup_func_t joint_lookup_func, + LLModelLoader::texture_load_func_t texture_load_func, + LLModelLoader::state_callback_t state_cb, + void* opaque_userdata, + JointTransformMap& jointTransformMap, + JointNameSet& jointsFromNodes, + JointMap& legalJointNamesMap, + U32 maxJointsPerMesh); + virtual ~LLModelLoader() ; + + virtual void setNoNormalize() { mNoNormalize = true; } + virtual void setNoOptimize() { mNoOptimize = true; } + + virtual void run(); + + static bool getSLMFilename(const std::string& model_filename, std::string& slm_filename); + + // Will try SLM or derived class OpenFile as appropriate + // + virtual bool doLoadModel(); + + // Derived classes need to provide their parsing of files here + // + virtual bool OpenFile(const std::string& filename) = 0; + + bool loadFromSLM(const std::string& filename); + + void loadModelCallback(); + void loadTextures() ; //called in the main thread. + void setLoadState(U32 state); + + + + S32 mNumOfFetchingTextures ; //updated in the main thread + bool areTexturesReady() { return !mNumOfFetchingTextures; } //called in the main thread. + + bool verifyCount( int expected, int result ); + + //Determines the viability of an asset to be used as an avatar rig (w or w/o joint upload caps) + void critiqueRigForUploadApplicability( const std::vector &jointListFromAsset ); + + //Determines if a rig is a legacy from the joint list + bool isRigLegacy( const std::vector &jointListFromAsset ); + + //Determines if a rig is suitable for upload + bool isRigSuitableForJointPositionUpload( const std::vector &jointListFromAsset ); + + const bool isRigValidForJointPositionUpload( void ) const { return mRigValidJointUpload; } + void setRigValidForJointPositionUpload( bool rigValid ) { mRigValidJointUpload = rigValid; } + + const bool isLegacyRigValid( void ) const { return mLegacyRigValid; } + void setLegacyRigValid( bool rigValid ) { mLegacyRigValid = rigValid; } + + //----------------------------------------------------------------------------- + // isNodeAJoint() + //----------------------------------------------------------------------------- + bool isNodeAJoint(const char* name) const + { + return name != NULL && mJointMap.find(name) != mJointMap.end(); + } + +protected: + + LLModelLoader::load_callback_t mLoadCallback; + LLModelLoader::joint_lookup_func_t mJointLookupFunc; + LLModelLoader::texture_load_func_t mTextureLoadFunc; + LLModelLoader::state_callback_t mStateCallback; + void* mOpaqueData; + + bool mRigValidJointUpload; + bool mLegacyRigValid; + + bool mNoNormalize; + bool mNoOptimize; + + JointTransformMap mJointTransformMap; + + static std::list sActiveLoaderList; + static bool isAlive(LLModelLoader* loader) ; +}; +class LLMatrix4a; +void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4a& max, BOOL& first_transform); +void stretch_extents(LLModel* model, LLMatrix4& mat, LLVector3& min, LLVector3& max, BOOL& first_transform); + +#endif // LL_LLMODELLOADER_H diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp index 36969d27c4..c37cc05b4f 100644 --- a/indra/llprimitive/llprimitive.cpp +++ b/indra/llprimitive/llprimitive.cpp @@ -38,6 +38,9 @@ #include "lldatapacker.h" #include "llsdutil_math.h" #include "llprimtexturelist.h" +#include "imageids.h" +#include "llmaterialid.h" +#include "llvolume.h" /** * exported constants @@ -125,7 +128,7 @@ void LLPrimitive::setVolumeManager( LLVolumeMgr* volume_manager ) { if ( !volume_manager || sVolumeManager ) { - llerrs << "LLPrimitive::sVolumeManager attempting to be set to NULL or it already has been set." << llendl; + LL_ERRS() << "LLPrimitive::sVolumeManager attempting to be set to NULL or it already has been set." << LL_ENDL; } sVolumeManager = volume_manager; } @@ -172,7 +175,7 @@ LLPrimitive::~LLPrimitive() { clearTextureList(); // Cleanup handled by volume manager - if (mVolumep) + if (mVolumep && sVolumeManager) { sVolumeManager->unrefVolume(mVolumep); } @@ -195,7 +198,7 @@ LLPrimitive *LLPrimitive::createPrimitive(LLPCode p_code) } else { - llerrs << "primitive allocation failed" << llendl; + LL_ERRS() << "primitive allocation failed" << LL_ENDL; } return retval; @@ -319,6 +322,11 @@ S32 LLPrimitive::setTEMaterialParams(const U8 index, const LLMaterialPtr pMateri return mTextureList.setMaterialParams(index, pMaterialParams); } +LLMaterialPtr LLPrimitive::getTEMaterialParams(const U8 index) +{ + return mTextureList.getMaterialParams(index); +} + //=============================================================== S32 LLPrimitive::setTEBumpShinyFullbright(const U8 index, const U8 bump) { @@ -475,7 +483,7 @@ LLPCode LLPrimitive::legacyToPCode(const U8 legacy) pcode = LL_PCODE_TREE_NEW; break; default: - llwarns << "Unknown legacy code " << legacy << " [" << (S32)legacy << "]!" << llendl; + LL_WARNS() << "Unknown legacy code " << legacy << " [" << (S32)legacy << "]!" << LL_ENDL; } return pcode; @@ -570,7 +578,7 @@ U8 LLPrimitive::pCodeToLegacy(const LLPCode pcode) legacy = TREE_NEW; break; default: - llwarns << "Unknown pcode " << (S32)pcode << ":" << pcode << "!" << llendl; + LL_WARNS() << "Unknown pcode " << (S32)pcode << ":" << pcode << "!" << LL_ENDL; return 0; } return legacy; @@ -578,7 +586,7 @@ U8 LLPrimitive::pCodeToLegacy(const LLPCode pcode) // static -// Don't crash or llerrs here! This function is used for debug strings. +// Don't crash or LL_ERRS() here! This function is used for debug strings. std::string LLPrimitive::pCodeToString(const LLPCode pcode) { std::string pcode_string; @@ -657,7 +665,7 @@ std::string LLPrimitive::pCodeToString(const LLPCode pcode) } else { - llwarns << "Unknown base mask for pcode: " << base_code << llendl; + LL_WARNS() << "Unknown base mask for pcode: " << base_code << LL_ENDL; } U8 mask_code = pcode & (~LL_PCODE_BASE_MASK); @@ -693,7 +701,7 @@ void LLPrimitive::copyTEs(const LLPrimitive *primitivep) U32 i; if (primitivep->getExpectedNumTEs() != getExpectedNumTEs()) { - llwarns << "Primitives don't have same expected number of TE's" << llendl; + LL_WARNS() << "Primitives don't have same expected number of TE's" << LL_ENDL; } U32 num_tes = llmin(primitivep->getExpectedNumTEs(), getExpectedNumTEs()); if (mTextureList.size() < getExpectedNumTEs()) @@ -721,6 +729,16 @@ S32 face_index_from_id(LLFaceID face_ID, const std::vector& fac BOOL LLPrimitive::setVolume(const LLVolumeParams &volume_params, const S32 detail, bool unique_volume) { + if (NO_LOD == detail) + { + // build the new object + setChanged(GEOMETRY); + sVolumeManager->unrefVolume(mVolumep); + mVolumep = new LLVolume(volume_params, 1, TRUE, TRUE); + setNumTEs(mVolumep->getNumFaces()); + return FALSE; + } + LLVolume *volumep; if (unique_volume) { @@ -795,7 +813,7 @@ BOOL LLPrimitive::setVolume(const LLVolumeParams &volume_params, const S32 detai { S32 te_index = face_index_from_id(cur_mask, old_faces); old_tes.copyTexture(face_bit, *(getTE(te_index))); - //llinfos << face_bit << ":" << te_index << ":" << old_tes[face_bit].getID() << llendl; + //LL_INFOS() << face_bit << ":" << te_index << ":" << old_tes[face_bit].getID() << LL_ENDL; } } @@ -815,7 +833,7 @@ BOOL LLPrimitive::setVolume(const LLVolumeParams &volume_params, const S32 detai if (mVolumep->getNumFaces() == 0 && new_face_mask != 0) { - llwarns << "Object with 0 faces found...INCORRECT!" << llendl; + LL_WARNS() << "Object with 0 faces found...INCORRECT!" << LL_ENDL; setNumTEs(mVolumep->getNumFaces()); return TRUE; } @@ -873,7 +891,7 @@ BOOL LLPrimitive::setVolume(const LLVolumeParams &volume_params, const S32 detai } if (i == 4) { - llwarns << "No path end or outer face in volume!" << llendl; + LL_WARNS() << "No path end or outer face in volume!" << LL_ENDL; } continue; } @@ -909,7 +927,7 @@ BOOL LLPrimitive::setVolume(const LLVolumeParams &volume_params, const S32 detai } if (i == 4) { - llwarns << "No path end or outer face in volume!" << llendl; + LL_WARNS() << "No path end or outer face in volume!" << LL_ENDL; } continue; } @@ -935,8 +953,8 @@ BOOL LLPrimitive::setVolume(const LLVolumeParams &volume_params, const S32 detai } if (-1 == min_outer_bit) { - llinfos << (LLVolume *)mVolumep << llendl; - llwarns << "Bad! No outer faces, impossible!" << llendl; + LL_INFOS() << (LLVolume *)mVolumep << LL_ENDL; + LL_WARNS() << "Bad! No outer faces, impossible!" << LL_ENDL; } face_mapping[face_bit] = min_outer_bit; } @@ -955,7 +973,7 @@ BOOL LLPrimitive::setVolume(const LLVolumeParams &volume_params, const S32 detai { if (-1 == face_mapping[face_bit]) { - llwarns << "No mapping from old face to new face!" << llendl; + LL_WARNS() << "No mapping from old face to new face!" << LL_ENDL; } S32 te_num = face_index_from_id(cur_mask, mVolumep->getProfile().mFaces); @@ -985,8 +1003,6 @@ BOOL LLPrimitive::setMaterial(U8 material) } } -const F32 LL_MAX_SCALE_S = 100.0f; -const F32 LL_MAX_SCALE_T = 100.0f; S32 LLPrimitive::packTEField(U8 *cur_ptr, U8 *data_ptr, U8 data_size, U8 last_face_index, EMsgVariableType type) const { S32 face_index; @@ -1021,14 +1037,26 @@ S32 LLPrimitive::packTEField(U8 *cur_ptr, U8 *data_ptr, U8 data_size, U8 last_fa } //assign exception faces to cur_ptr - if (exception_faces >= (0x1 << 7)) + if (exception_faces >= ((U64)0x1 << 7)) { - if (exception_faces >= (0x1 << 14)) + if (exception_faces >= ((U64)0x1 << 14)) { - if (exception_faces >= (0x1 << 21)) + if (exception_faces >= ((U64)0x1 << 21)) { - if (exception_faces >= (0x1 << 28)) + if (exception_faces >= ((U64)0x1 << 28)) { + if (exception_faces >= ((U64)0x1 << 35)) + { + if (exception_faces >= ((U64)0x1 << 42)) + { + if (exception_faces >= ((U64)0x1 << 49)) + { + *cur_ptr++ = (U8)(((exception_faces >> 49) & 0x7F) | 0x80); + } + *cur_ptr++ = (U8)(((exception_faces >> 42) & 0x7F) | 0x80); + } + *cur_ptr++ = (U8)(((exception_faces >> 35) & 0x7F) | 0x80); + } *cur_ptr++ = (U8)(((exception_faces >> 28) & 0x7F) | 0x80); } *cur_ptr++ = (U8)(((exception_faces >> 21) & 0x7F) | 0x80); @@ -1037,6 +1065,7 @@ S32 LLPrimitive::packTEField(U8 *cur_ptr, U8 *data_ptr, U8 data_size, U8 last_fa } *cur_ptr++ = (U8)(((exception_faces >> 7) & 0x7F) | 0x80); } + *cur_ptr++ = (U8)(exception_faces & 0x7F); @@ -1062,7 +1091,7 @@ S32 LLPrimitive::unpackTEField(U8 *cur_ptr, U8 *buffer_end, U8 *data_ptr, U8 dat while ((cur_ptr < buffer_end) && (*cur_ptr != 0)) { -// llinfos << "TE exception" << llendl; + LL_DEBUGS("TEFieldDecode") << "TE exception" << LL_ENDL; i = 0; while (*cur_ptr & 0x80) { @@ -1077,14 +1106,16 @@ S32 LLPrimitive::unpackTEField(U8 *cur_ptr, U8 *buffer_end, U8 *data_ptr, U8 dat if (i & 0x01) { htonmemcpy(data_ptr+(j*data_size),cur_ptr,type,data_size); -// char foo[64]; -// sprintf(foo,"%x %x",*(data_ptr+(j*data_size)), *(data_ptr+(j*data_size)+1)); -// llinfos << "Assigning " << foo << " to face " << j << llendl; + LL_DEBUGS("TEFieldDecode") << "Assigning " ; + char foo[64]; + sprintf(foo,"%x %x",*(data_ptr+(j*data_size)), *(data_ptr+(j*data_size)+1)); + LL_CONT << foo << " to face " << j << LL_ENDL; } i = i >> 1; } cur_ptr += data_size; } + llassert(cur_ptr <= buffer_end); // buffer underrun return (S32)(cur_ptr - start_loc); } @@ -1094,7 +1125,7 @@ S32 LLPrimitive::unpackTEField(U8 *cur_ptr, U8 *buffer_end, U8 *data_ptr, U8 dat // Includes information about image ID, color, scale S,T, offset S,T and rotation BOOL LLPrimitive::packTEMessage(LLMessageSystem *mesgsys) const { - const U32 MAX_TES = 32; + const U32 MAX_TES = 45; U8 image_ids[MAX_TES*16]; U8 colors[MAX_TES*4]; @@ -1138,12 +1169,12 @@ BOOL LLPrimitive::packTEMessage(LLMessageSystem *mesgsys) const const LLTextureEntry* te = getTE(face_index); scale_s[face_index] = (F32) te->mScaleS; scale_t[face_index] = (F32) te->mScaleT; - offset_s[face_index] = (S16) llround((llclamp(te->mOffsetS,-1.0f,1.0f) * (F32)0x7FFF)) ; - offset_t[face_index] = (S16) llround((llclamp(te->mOffsetT,-1.0f,1.0f) * (F32)0x7FFF)) ; - image_rot[face_index] = (S16) llround(((fmod(te->mRotation, F_TWO_PI)/F_TWO_PI) * TEXTURE_ROTATION_PACK_FACTOR)); + offset_s[face_index] = (S16) ll_round((llclamp(te->mOffsetS,-1.0f,1.0f) * (F32)0x7FFF)) ; + offset_t[face_index] = (S16) ll_round((llclamp(te->mOffsetT,-1.0f,1.0f) * (F32)0x7FFF)) ; + image_rot[face_index] = (S16) ll_round(((fmod(te->mRotation, F_TWO_PI)/F_TWO_PI) * TEXTURE_ROTATION_PACK_FACTOR)); bump[face_index] = te->getBumpShinyFullbright(); media_flags[face_index] = te->getMediaTexGen(); - glow[face_index] = (U8) llround((llclamp(te->getGlow(), 0.0f, 1.0f) * (F32)0xFF)); + glow[face_index] = (U8) ll_round((llclamp(te->getGlow(), 0.0f, 1.0f) * (F32)0xFF)); // Directly sending material_ids is not safe! memcpy(&material_data[face_index*16],getTE(face_index)->getMaterialID().get(),16); /* Flawfinder: ignore */ @@ -1179,7 +1210,7 @@ BOOL LLPrimitive::packTEMessage(LLMessageSystem *mesgsys) const BOOL LLPrimitive::packTEMessage(LLDataPacker &dp) const { - const U32 MAX_TES = 32; + const U32 MAX_TES = 45; U8 image_ids[MAX_TES*16]; U8 colors[MAX_TES*4]; @@ -1223,12 +1254,12 @@ BOOL LLPrimitive::packTEMessage(LLDataPacker &dp) const const LLTextureEntry* te = getTE(face_index); scale_s[face_index] = (F32) te->mScaleS; scale_t[face_index] = (F32) te->mScaleT; - offset_s[face_index] = (S16) llround((llclamp(te->mOffsetS,-1.0f,1.0f) * (F32)0x7FFF)) ; - offset_t[face_index] = (S16) llround((llclamp(te->mOffsetT,-1.0f,1.0f) * (F32)0x7FFF)) ; - image_rot[face_index] = (S16) llround(((fmod(te->mRotation, F_TWO_PI)/F_TWO_PI) * TEXTURE_ROTATION_PACK_FACTOR)); + offset_s[face_index] = (S16) ll_round((llclamp(te->mOffsetS,-1.0f,1.0f) * (F32)0x7FFF)) ; + offset_t[face_index] = (S16) ll_round((llclamp(te->mOffsetT,-1.0f,1.0f) * (F32)0x7FFF)) ; + image_rot[face_index] = (S16) ll_round(((fmod(te->mRotation, F_TWO_PI)/F_TWO_PI) * TEXTURE_ROTATION_PACK_FACTOR)); bump[face_index] = te->getBumpShinyFullbright(); media_flags[face_index] = te->getMediaTexGen(); - glow[face_index] = (U8) llround((llclamp(te->getGlow(), 0.0f, 1.0f) * (F32)0xFF)); + glow[face_index] = (U8) ll_round((llclamp(te->getGlow(), 0.0f, 1.0f) * (F32)0xFF)); // Directly sending material_ids is not safe! memcpy(&material_data[face_index*16],getTE(face_index)->getMaterialID().get(),16); /* Flawfinder: ignore */ @@ -1383,7 +1414,7 @@ S32 LLPrimitive::unpackTEMessage(LLDataPacker &dp) { // use a negative block_num to indicate a single-block read (a non-variable block) S32 retval = 0; - const U32 MAX_TES = 32; + const U32 MAX_TES = 45; // Avoid construction of 32 UUIDs per call static LLUUID image_ids[MAX_TES]; @@ -1411,7 +1442,7 @@ S32 LLPrimitive::unpackTEMessage(LLDataPacker &dp) if (!dp.unpackBinaryData(packed_buffer, size, "TextureEntry")) { retval = TEM_INVALID; - llwarns << "Bad texture entry block! Abort!" << llendl; + LL_WARNS() << "Bad texture entry block! Abort!" << LL_ENDL; return retval; } @@ -1569,6 +1600,8 @@ BOOL LLNetworkData::isValid(U16 param_type, U32 size) return (size == 17); case PARAMS_LIGHT_IMAGE: return (size == 28); + case PARAMS_EXTENDED_MESH: + return (size == 4); } return FALSE; @@ -1839,9 +1872,12 @@ BOOL LLSculptParams::pack(LLDataPacker &dp) const BOOL LLSculptParams::unpack(LLDataPacker &dp) { - dp.unpackUUID(mSculptTexture, "texture"); - dp.unpackU8(mSculptType, "type"); - + U8 type; + LLUUID id; + dp.unpackUUID(id, "texture"); + dp.unpackU8(type, "type"); + + setSculptTexture(id, type); return TRUE; } @@ -1866,8 +1902,7 @@ bool LLSculptParams::operator==(const LLNetworkData& data) const void LLSculptParams::copy(const LLNetworkData& data) { const LLSculptParams *param = (LLSculptParams*)&data; - mSculptTexture = param->mSculptTexture; - mSculptType = param->mSculptType; + setSculptTexture(param->mSculptTexture, param->mSculptType); } @@ -1885,20 +1920,38 @@ LLSD LLSculptParams::asLLSD() const bool LLSculptParams::fromLLSD(LLSD& sd) { const char *w; - w = "texture"; + U8 type; + w = "type"; if (sd.has(w)) { - setSculptTexture( sd[w] ); - } else goto fail; - w = "type"; + type = sd[w].asInteger(); + } + else return false; + + w = "texture"; if (sd.has(w)) { - setSculptType( (U8)sd[w].asInteger() ); - } else goto fail; - + setSculptTexture(sd[w], type); + } + else return false; + return true; - fail: - return false; +} + +void LLSculptParams::setSculptTexture(const LLUUID& texture_id, U8 sculpt_type) +{ + U8 type = sculpt_type & LL_SCULPT_TYPE_MASK; + U8 flags = sculpt_type & LL_SCULPT_FLAG_MASK; + if (sculpt_type != (type | flags) || type > LL_SCULPT_TYPE_MAX) + { + mSculptTexture.set(SCULPT_DEFAULT_TEXTURE); + mSculptType = LL_SCULPT_TYPE_SPHERE; + } + else + { + mSculptTexture = texture_id; + mSculptType = sculpt_type; + } } //============================================================================ @@ -1976,3 +2029,67 @@ bool LLLightImageParams::fromLLSD(LLSD& sd) return false; } + +//============================================================================ + +LLExtendedMeshParams::LLExtendedMeshParams() +{ + mType = PARAMS_EXTENDED_MESH; + mFlags = 0; +} + +BOOL LLExtendedMeshParams::pack(LLDataPacker &dp) const +{ + dp.packU32(mFlags, "flags"); + + return TRUE; +} + +BOOL LLExtendedMeshParams::unpack(LLDataPacker &dp) +{ + dp.unpackU32(mFlags, "flags"); + + return TRUE; +} + +bool LLExtendedMeshParams::operator==(const LLNetworkData& data) const +{ + if (data.mType != PARAMS_EXTENDED_MESH) + { + return false; + } + + const LLExtendedMeshParams *param = (const LLExtendedMeshParams*)&data; + if ( (param->mFlags != mFlags) ) + { + return false; + } + + return true; +} + +void LLExtendedMeshParams::copy(const LLNetworkData& data) +{ + const LLExtendedMeshParams *param = (LLExtendedMeshParams*)&data; + mFlags = param->mFlags; +} + +LLSD LLExtendedMeshParams::asLLSD() const +{ + LLSD sd; + + sd["flags"] = LLSD::Integer(mFlags); + + return sd; +} + +bool LLExtendedMeshParams::fromLLSD(LLSD& sd) +{ + if (sd.has("flags")) + { + setFlags( sd["flags"].asInteger()); + return true; + } + + return false; +} diff --git a/indra/llprimitive/llprimitive.h b/indra/llprimitive/llprimitive.h index 1effeea737..d69c731990 100644 --- a/indra/llprimitive/llprimitive.h +++ b/indra/llprimitive/llprimitive.h @@ -106,6 +106,8 @@ class LLNetworkData PARAMS_LIGHT_IMAGE = 0x40, PARAMS_RESERVED = 0x50, // Used on server-side PARAMS_MESH = 0x60, + PARAMS_EXTENDED_MESH = 0x70, + PARAMS_MAX = PARAMS_EXTENDED_MESH }; public: @@ -259,9 +261,8 @@ class LLSculptParams : public LLNetworkData operator LLSD() const { return asLLSD(); } bool fromLLSD(LLSD& sd); - void setSculptTexture(const LLUUID& id) { mSculptTexture = id; } + void setSculptTexture(const LLUUID& texture_id, U8 sculpt_type); LLUUID getSculptTexture() const { return mSculptTexture; } - void setSculptType(U8 type) { mSculptType = type; } U8 getSculptType() const { return mSculptType; } }; @@ -289,6 +290,27 @@ class LLLightImageParams : public LLNetworkData }; +class LLExtendedMeshParams : public LLNetworkData +{ +protected: + U32 mFlags; + +public: + static const U32 ANIMATED_MESH_ENABLED_FLAG = 0x1 << 0; + + LLExtendedMeshParams(); + /*virtual*/ BOOL pack(LLDataPacker &dp) const; + /*virtual*/ BOOL unpack(LLDataPacker &dp); + /*virtual*/ bool operator==(const LLNetworkData& data) const; + /*virtual*/ void copy(const LLNetworkData& data); + LLSD asLLSD() const; + operator LLSD() const { return asLLSD(); } + bool fromLLSD(LLSD& sd); + + void setFlags(const U32& flags) { mFlags = flags; } + U32 getFlags() const { return mFlags; } + +}; // This code is not naming-standards compliant. Leaving it like this for // now to make the connection to code in @@ -298,7 +320,7 @@ class LLLightImageParams : public LLNetworkData // - Vir struct LLTEContents { - static const U32 MAX_TES = 32; + static const U32 MAX_TES = 45; U8 image_data[MAX_TES*16]; U8 colors[MAX_TES*4]; @@ -309,9 +331,9 @@ struct LLTEContents S16 image_rot[MAX_TES]; U8 bump[MAX_TES]; U8 media_flags[MAX_TES]; - U8 glow[MAX_TES]; + U8 glow[MAX_TES]; LLMaterialID material_ids[MAX_TES]; - + static const U32 MAX_TE_BUFFER = 4096; U8 packed_buffer[MAX_TE_BUFFER]; @@ -389,6 +411,8 @@ class LLPrimitive : public LLXform virtual BOOL setMaterial(const U8 material); // returns TRUE if material changed virtual void setTESelected(const U8 te, bool sel); + LLMaterialPtr getTEMaterialParams(const U8 index); + void copyTEs(const LLPrimitive *primitive); S32 packTEField(U8 *cur_ptr, U8 *data_ptr, U8 data_size, U8 last_face_index, EMsgVariableType type) const; S32 unpackTEField(U8 *cur_ptr, U8 *buffer_end, U8 *data_ptr, U8 data_size, U8 face_count, EMsgVariableType type); @@ -482,6 +506,11 @@ class LLPrimitive : public LLXform U32 mMiscFlags; // home for misc bools static LLVolumeMgr* sVolumeManager; +public: + enum + { + NO_LOD = -1 + }; }; inline BOOL LLPrimitive::isAvatar() const @@ -528,13 +557,13 @@ inline BOOL LLPrimitive::isApp(const LLPCode pcode) // Special case for setPosition. If not check-for-finite, fall through to LLXform method. void LLPrimitive::setPosition(const F32 x, const F32 y, const F32 z) { - if (llfinite(x) && llfinite(y) && llfinite(z)) + if (std::isfinite(x) && std::isfinite(y) && std::isfinite(z)) { LLXform::setPosition(x, y, z); } else { - llerrs << "Non Finite in LLPrimitive::setPosition(x,y,z) for " << pCodeToString(mPrimitiveCode) << llendl; + LL_ERRS() << "Non Finite in LLPrimitive::setPosition(x,y,z) for " << pCodeToString(mPrimitiveCode) << LL_ENDL; } } @@ -547,7 +576,7 @@ void LLPrimitive::setPosition(const LLVector3& pos) } else { - llerrs << "Non Finite in LLPrimitive::setPosition(LLVector3) for " << pCodeToString(mPrimitiveCode) << llendl; + LL_ERRS() << "Non Finite in LLPrimitive::setPosition(LLVector3) for " << pCodeToString(mPrimitiveCode) << LL_ENDL; } } @@ -559,19 +588,19 @@ void LLPrimitive::setAngularVelocity(const LLVector3& avel) } else { - llerror("Non Finite in LLPrimitive::setAngularVelocity", 0); + LL_ERRS() << "Non Finite in LLPrimitive::setAngularVelocity" << LL_ENDL; } } void LLPrimitive::setAngularVelocity(const F32 x, const F32 y, const F32 z) { - if (llfinite(x) && llfinite(y) && llfinite(z)) + if (std::isfinite(x) && std::isfinite(y) && std::isfinite(z)) { mAngularVelocity.setVec(x,y,z); } else { - llerror("Non Finite in LLPrimitive::setAngularVelocity", 0); + LL_ERRS() << "Non Finite in LLPrimitive::setAngularVelocity" << LL_ENDL; } } @@ -583,55 +612,55 @@ void LLPrimitive::setVelocity(const LLVector3& vel) } else { - llerrs << "Non Finite in LLPrimitive::setVelocity(LLVector3) for " << pCodeToString(mPrimitiveCode) << llendl; + LL_ERRS() << "Non Finite in LLPrimitive::setVelocity(LLVector3) for " << pCodeToString(mPrimitiveCode) << LL_ENDL; } } void LLPrimitive::setVelocity(const F32 x, const F32 y, const F32 z) { - if (llfinite(x) && llfinite(y) && llfinite(z)) + if (std::isfinite(x) && std::isfinite(y) && std::isfinite(z)) { mVelocity.setVec(x,y,z); } else { - llerrs << "Non Finite in LLPrimitive::setVelocity(F32,F32,F32) for " << pCodeToString(mPrimitiveCode) << llendl; + LL_ERRS() << "Non Finite in LLPrimitive::setVelocity(F32,F32,F32) for " << pCodeToString(mPrimitiveCode) << LL_ENDL; } } void LLPrimitive::setVelocityX(const F32 x) { - if (llfinite(x)) + if (std::isfinite(x)) { mVelocity.mV[VX] = x; } else { - llerror("Non Finite in LLPrimitive::setVelocityX", 0); + LL_ERRS() << "Non Finite in LLPrimitive::setVelocityX" << LL_ENDL; } } void LLPrimitive::setVelocityY(const F32 y) { - if (llfinite(y)) + if (std::isfinite(y)) { mVelocity.mV[VY] = y; } else { - llerror("Non Finite in LLPrimitive::setVelocityY", 0); + LL_ERRS() << "Non Finite in LLPrimitive::setVelocityY" << LL_ENDL; } } void LLPrimitive::setVelocityZ(const F32 z) { - if (llfinite(z)) + if (std::isfinite(z)) { mVelocity.mV[VZ] = z; } else { - llerror("Non Finite in LLPrimitive::setVelocityZ", 0); + LL_ERRS() << "Non Finite in LLPrimitive::setVelocityZ" << LL_ENDL; } } @@ -643,7 +672,7 @@ void LLPrimitive::addVelocity(const LLVector3& vel) } else { - llerror("Non Finite in LLPrimitive::addVelocity", 0); + LL_ERRS() << "Non Finite in LLPrimitive::addVelocity" << LL_ENDL; } } @@ -655,19 +684,19 @@ void LLPrimitive::setAcceleration(const LLVector3& accel) } else { - llerrs << "Non Finite in LLPrimitive::setAcceleration(LLVector3) for " << pCodeToString(mPrimitiveCode) << llendl; + LL_ERRS() << "Non Finite in LLPrimitive::setAcceleration(LLVector3) for " << pCodeToString(mPrimitiveCode) << LL_ENDL; } } void LLPrimitive::setAcceleration(const F32 x, const F32 y, const F32 z) { - if (llfinite(x) && llfinite(y) && llfinite(z)) + if (std::isfinite(x) && std::isfinite(y) && std::isfinite(z)) { mAcceleration.setVec(x,y,z); } else { - llerrs << "Non Finite in LLPrimitive::setAcceleration(F32,F32,F32) for " << pCodeToString(mPrimitiveCode) << llendl; + LL_ERRS() << "Non Finite in LLPrimitive::setAcceleration(F32,F32,F32) for " << pCodeToString(mPrimitiveCode) << LL_ENDL; } } #endif // CHECK_FOR_FINITE diff --git a/indra/llprimitive/llprimlinkinfo.h b/indra/llprimitive/llprimlinkinfo.h index 946fa75bfa..a160978f0c 100644 --- a/indra/llprimitive/llprimlinkinfo.h +++ b/indra/llprimitive/llprimlinkinfo.h @@ -280,28 +280,28 @@ S32 LLPrimLinkInfo< DATA_TYPE >::merge(LLPrimLinkInfo& other_info) // other_info.computeBoundingSphere(); // if ( other_radius != other_info.mBoundingSphere.getRadius() ) // { -// llinfos << "Other bounding sphere changed!!" << llendl; +// LL_INFOS() << "Other bounding sphere changed!!" << LL_ENDL; // } // F32 this_radius = mBoundingSphere.getRadius(); // computeBoundingSphere(); // if ( this_radius != mBoundingSphere.getRadius() ) // { -// llinfos << "This bounding sphere changed!!" << llendl; +// LL_INFOS() << "This bounding sphere changed!!" << LL_ENDL; // } F32 max_span = get_max_linkable_span(mBoundingSphere, other_info.mBoundingSphere); // F32 center_dist = (mBoundingSphere.getCenter() - other_info.mBoundingSphere.getCenter()).length(); - // llinfos << "objects are " << center_dist << "m apart" << llendl; + // LL_INFOS() << "objects are " << center_dist << "m apart" << LL_ENDL; F32 span = get_span(mBoundingSphere, other_info.mBoundingSphere); F32 span_limit = max_span + (2.f * other_info.mBoundingSphere.getRadius()); if (span > span_limit) { // there is no way any piece of other_info could link with this one - // llinfos << "span too large: " << span << " vs. " << span_limit << llendl; + // LL_INFOS() << "span too large: " << span << " vs. " << span_limit << LL_ENDL; return 0; } diff --git a/indra/llprimitive/llprimtexturelist.cpp b/indra/llprimitive/llprimtexturelist.cpp index 537e7a6695..854003d42b 100644 --- a/indra/llprimitive/llprimtexturelist.cpp +++ b/indra/llprimitive/llprimtexturelist.cpp @@ -130,14 +130,14 @@ S32 LLPrimTextureList::copyTexture(const U8 index, const LLTextureEntry& te) if (S32(index) >= mEntryList.size()) { S32 current_size = mEntryList.size(); - llwarns << "ignore copy of index = " << S32(index) << " into texture entry list of size = " << current_size << llendl; + LL_WARNS() << "ignore copy of index = " << S32(index) << " into texture entry list of size = " << current_size << LL_ENDL; return TEM_CHANGE_NONE; } // we're changing an existing entry llassert(mEntryList[index]); delete (mEntryList[index]); - if (&te) + if (te != LLTextureEntry::null) { mEntryList[index] = te.newCopy(); } @@ -377,6 +377,16 @@ S32 LLPrimTextureList::setMaterialParams(const U8 index, const LLMaterialPtr pMa return TEM_CHANGE_NONE; } +LLMaterialPtr LLPrimTextureList::getMaterialParams(const U8 index) +{ + if (index < mEntryList.size()) + { + return mEntryList[index]->getMaterialParams(); + } + + return LLMaterialPtr(); +} + S32 LLPrimTextureList::size() const { return mEntryList.size(); diff --git a/indra/llprimitive/llprimtexturelist.h b/indra/llprimitive/llprimtexturelist.h index c91764e7ad..ce5f6b72b3 100644 --- a/indra/llprimitive/llprimtexturelist.h +++ b/indra/llprimitive/llprimtexturelist.h @@ -115,6 +115,8 @@ class LLPrimTextureList S32 setMaterialID(const U8 index, const LLMaterialID& pMaterialID); S32 setMaterialParams(const U8 index, const LLMaterialPtr pMaterialParams); + LLMaterialPtr getMaterialParams(const U8 index); + S32 size() const; // void forceResize(S32 new_size); diff --git a/indra/llprimitive/lltextureanim.cpp b/indra/llprimitive/lltextureanim.cpp index 4588a19f66..41415cf52f 100644 --- a/indra/llprimitive/lltextureanim.cpp +++ b/indra/llprimitive/lltextureanim.cpp @@ -131,7 +131,7 @@ void LLTextureAnim::unpackTAMessage(LLMessageSystem *mesgsys, const S32 block_nu { if (size) { - llwarns << "Bad size " << size << " for TA block, ignoring." << llendl; + LL_WARNS() << "Bad size " << size << " for TA block, ignoring." << LL_ENDL; } mMode = 0; return; @@ -166,7 +166,7 @@ void LLTextureAnim::unpackTAMessage(LLDataPacker &dp) { if (size) { - llwarns << "Bad size " << size << " for TA block, ignoring." << llendl; + LL_WARNS() << "Bad size " << size << " for TA block, ignoring." << LL_ENDL; } mMode = 0; return; diff --git a/indra/llprimitive/lltextureentry.cpp b/indra/llprimitive/lltextureentry.cpp index 597f078490..91d5c7ca7e 100644 --- a/indra/llprimitive/lltextureentry.cpp +++ b/indra/llprimitive/lltextureentry.cpp @@ -271,8 +271,8 @@ bool LLTextureEntry::fromLLSD(const LLSD& sd) w = TEXTURE_MEDIA_DATA_KEY; if (hasMedia() != sd.has(w)) { - llwarns << "LLTextureEntry::fromLLSD: media_flags (" << hasMedia() << - ") does not match presence of media_data (" << sd.has(w) << "). Fixing." << llendl; + LL_WARNS() << "LLTextureEntry::fromLLSD: media_flags (" << hasMedia() << + ") does not match presence of media_data (" << sd.has(w) << "). Fixing." << LL_ENDL; } updateMediaData(sd[w]); @@ -417,7 +417,7 @@ S32 LLTextureEntry::setOffsetT(F32 t) S32 LLTextureEntry::setRotation(F32 theta) { - if (mRotation != theta && llfinite(theta)) + if (mRotation != theta && std::isfinite(theta)) { mRotation = theta; return TEM_CHANGE_TEXTURE; @@ -545,7 +545,7 @@ S32 LLTextureEntry::setMaterialID(const LLMaterialID& pMaterialID) { mMaterialUpdatePending = true; mMaterialID = pMaterialID; - return TEM_CHANGE_NONE; + return TEM_CHANGE_TEXTURE; } mMaterialUpdatePending = false; diff --git a/indra/llprimitive/lltextureentry.h b/indra/llprimitive/lltextureentry.h index cbd8665d3f..a40c3988f2 100644 --- a/indra/llprimitive/lltextureentry.h +++ b/indra/llprimitive/lltextureentry.h @@ -38,7 +38,7 @@ const S32 TEM_CHANGE_NONE = 0x0; const S32 TEM_CHANGE_COLOR = 0x1; const S32 TEM_CHANGE_TEXTURE = 0x2; -const S32 TEM_CHANGE_MEDIA = 0x4; //Currently doesn't do anything, (not that TEM_CHANGE_TEXTURE either) +const S32 TEM_CHANGE_MEDIA = 0x4; const S32 TEM_INVALID = 0x8; const S32 TEM_BUMPMAP_COUNT = 32; @@ -89,6 +89,10 @@ class LLTextureEntry bool operator==(const LLTextureEntry &rhs) const; bool operator!=(const LLTextureEntry &rhs) const; + + // Added to allow use with std::map + // + bool operator <(const LLTextureEntry &rhs) const; LLSD asLLSD() const; void asLLSD(LLSD& sd) const; @@ -133,7 +137,13 @@ class LLTextureEntry virtual const LLUUID &getID() const { return mID; } const LLColor4 &getColor() const { return mColor; } void getScale(F32 *s, F32 *t) const { *s = mScaleS; *t = mScaleT; } + F32 getScaleS() const { return mScaleS; } + F32 getScaleT() const { return mScaleT; } + void getOffset(F32 *s, F32 *t) const { *s = mOffsetS; *t = mOffsetT; } + F32 getOffsetS() const { return mOffsetS; } + F32 getOffsetT() const { return mOffsetT; } + F32 getRotation() const { return mRotation; } void getRotation(F32 *theta) const { *theta = mRotation; } @@ -144,7 +154,7 @@ class LLTextureEntry U8 getBumpShinyFullbright() const { return mBump; } U8 getMediaFlags() const { return mMediaFlags & TEM_MEDIA_MASK; } - U8 getTexGen() const { return mMediaFlags & TEM_TEX_GEN_MASK; } + LLTextureEntry::e_texgen getTexGen() const { return LLTextureEntry::e_texgen(mMediaFlags & TEM_TEX_GEN_MASK); } U8 getMediaTexGen() const { return mMediaFlags; } F32 getGlow() const { return mGlow; } const LLMaterialID& getMaterialID() const { return mMaterialID; }; diff --git a/indra/llprimitive/lltreeparams.cpp b/indra/llprimitive/lltreeparams.cpp index 1c82fb63f7..f07faee6a4 100644 --- a/indra/llprimitive/lltreeparams.cpp +++ b/indra/llprimitive/lltreeparams.cpp @@ -46,7 +46,7 @@ LLTreeParams::LLTreeParams() { -// llinfos << "TREE PARAMS INITIALIZED" << llendl; +// LL_INFOS() << "TREE PARAMS INITIALIZED" << LL_ENDL; // init to basic something or other... mShape = SR_TEND_FLAME; mLevels = 1; diff --git a/indra/llprimitive/llvolumemessage.cpp b/indra/llprimitive/llvolumemessage.cpp index 273ed1b7e9..3226719ba7 100644 --- a/indra/llprimitive/llvolumemessage.cpp +++ b/indra/llprimitive/llvolumemessage.cpp @@ -58,13 +58,13 @@ bool LLVolumeMessage::packProfileParams( tempU8 = params->getCurveType(); mesgsys->addU8Fast(_PREHASH_ProfileCurve, tempU8); - tempU16 = (U16) llround( params->getBegin() / CUT_QUANTA); + tempU16 = (U16) ll_round( params->getBegin() / CUT_QUANTA); mesgsys->addU16Fast(_PREHASH_ProfileBegin, tempU16); - tempU16 = 50000 - (U16) llround(params->getEnd() / CUT_QUANTA); + tempU16 = 50000 - (U16) ll_round(params->getEnd() / CUT_QUANTA); mesgsys->addU16Fast(_PREHASH_ProfileEnd, tempU16); - tempU16 = (U16) llround(params->getHollow() / HOLLOW_QUANTA); + tempU16 = (U16) ll_round(params->getHollow() / HOLLOW_QUANTA); mesgsys->addU16Fast(_PREHASH_ProfileHollow, tempU16); return true; @@ -86,13 +86,13 @@ bool LLVolumeMessage::packProfileParams( tempU8 = params->getCurveType(); dp.packU8(tempU8, "Curve"); - tempU16 = (U16) llround( params->getBegin() / CUT_QUANTA); + tempU16 = (U16) ll_round( params->getBegin() / CUT_QUANTA); dp.packU16(tempU16, "Begin"); - tempU16 = 50000 - (U16) llround(params->getEnd() / CUT_QUANTA); + tempU16 = 50000 - (U16) ll_round(params->getEnd() / CUT_QUANTA); dp.packU16(tempU16, "End"); - tempU16 = (U16) llround(params->getHollow() / HOLLOW_QUANTA); + tempU16 = (U16) ll_round(params->getHollow() / HOLLOW_QUANTA); dp.packU16(tempU16, "Hollow"); return true; } @@ -115,8 +115,8 @@ bool LLVolumeMessage::unpackProfileParams( temp_f32 = temp_u16 * CUT_QUANTA; if (temp_f32 > 1.f) { - llwarns << "Profile begin out of range: " << temp_f32 - << ". Clamping to 0.0." << llendl; + LL_WARNS() << "Profile begin out of range: " << temp_f32 + << ". Clamping to 0.0." << LL_ENDL; temp_f32 = 0.f; ok = false; } @@ -126,8 +126,8 @@ bool LLVolumeMessage::unpackProfileParams( temp_f32 = temp_u16 * CUT_QUANTA; if (temp_f32 > 1.f) { - llwarns << "Profile end out of range: " << 1.f - temp_f32 - << ". Clamping to 1.0." << llendl; + LL_WARNS() << "Profile end out of range: " << 1.f - temp_f32 + << ". Clamping to 1.0." << LL_ENDL; temp_f32 = 1.f; ok = false; } @@ -137,19 +137,19 @@ bool LLVolumeMessage::unpackProfileParams( temp_f32 = temp_u16 * HOLLOW_QUANTA; if (temp_f32 > 1.f) { - llwarns << "Profile hollow out of range: " << temp_f32 - << ". Clamping to 0.0." << llendl; + LL_WARNS() << "Profile hollow out of range: " << temp_f32 + << ". Clamping to 0.0." << LL_ENDL; temp_f32 = 0.f; ok = false; } params->setHollow(temp_f32); /* - llinfos << "Unpacking Profile Block " << block_num << llendl; - llinfos << "Curve: " << (U32)getCurve() << llendl; - llinfos << "Begin: " << getBegin() << llendl; - llinfos << "End: " << getEnd() << llendl; - llinfos << "Hollow: " << getHollow() << llendl; + LL_INFOS() << "Unpacking Profile Block " << block_num << LL_ENDL; + LL_INFOS() << "Curve: " << (U32)getCurve() << LL_ENDL; + LL_INFOS() << "Begin: " << getBegin() << LL_ENDL; + LL_INFOS() << "End: " << getEnd() << LL_ENDL; + LL_INFOS() << "Hollow: " << getHollow() << LL_ENDL; */ return ok; @@ -171,8 +171,8 @@ bool LLVolumeMessage::unpackProfileParams( temp_f32 = temp_u16 * CUT_QUANTA; if (temp_f32 > 1.f) { - llwarns << "Profile begin out of range: " << temp_f32 << llendl; - llwarns << "Clamping to 0.0" << llendl; + LL_WARNS() << "Profile begin out of range: " << temp_f32 << LL_ENDL; + LL_WARNS() << "Clamping to 0.0" << LL_ENDL; temp_f32 = 0.f; ok = false; } @@ -182,8 +182,8 @@ bool LLVolumeMessage::unpackProfileParams( temp_f32 = temp_u16 * CUT_QUANTA; if (temp_f32 > 1.f) { - llwarns << "Profile end out of range: " << 1.f - temp_f32 << llendl; - llwarns << "Clamping to 1.0" << llendl; + LL_WARNS() << "Profile end out of range: " << 1.f - temp_f32 << LL_ENDL; + LL_WARNS() << "Clamping to 1.0" << LL_ENDL; temp_f32 = 1.f; ok = false; } @@ -193,8 +193,8 @@ bool LLVolumeMessage::unpackProfileParams( temp_f32 = temp_u16 * HOLLOW_QUANTA; if (temp_f32 > 1.f) { - llwarns << "Profile hollow out of range: " << temp_f32 << llendl; - llwarns << "Clamping to 0.0" << llendl; + LL_WARNS() << "Profile hollow out of range: " << temp_f32 << LL_ENDL; + LL_WARNS() << "Clamping to 0.0" << LL_ENDL; temp_f32 = 0.f; ok = false; } @@ -223,46 +223,46 @@ bool LLVolumeMessage::packPathParams( U8 curve = params->getCurveType(); mesgsys->addU8Fast(_PREHASH_PathCurve, curve); - U16 begin = (U16) llround(params->getBegin() / CUT_QUANTA); + U16 begin = (U16) ll_round(params->getBegin() / CUT_QUANTA); mesgsys->addU16Fast(_PREHASH_PathBegin, begin); - U16 end = 50000 - (U16) llround(params->getEnd() / CUT_QUANTA); + U16 end = 50000 - (U16) ll_round(params->getEnd() / CUT_QUANTA); mesgsys->addU16Fast(_PREHASH_PathEnd, end); // Avoid truncation problem with direct F32->U8 cast. // (e.g., (U8) (0.50 / 0.01) = (U8) 49.9999999 = 49 not 50. - U8 pack_scale_x = 200 - (U8) llround(params->getScaleX() / SCALE_QUANTA); + U8 pack_scale_x = 200 - (U8) ll_round(params->getScaleX() / SCALE_QUANTA); mesgsys->addU8Fast(_PREHASH_PathScaleX, pack_scale_x ); - U8 pack_scale_y = 200 - (U8) llround(params->getScaleY() / SCALE_QUANTA); + U8 pack_scale_y = 200 - (U8) ll_round(params->getScaleY() / SCALE_QUANTA); mesgsys->addU8Fast(_PREHASH_PathScaleY, pack_scale_y ); - U8 pack_shear_x = (U8) llround(params->getShearX() / SHEAR_QUANTA); + U8 pack_shear_x = (U8) ll_round(params->getShearX() / SHEAR_QUANTA); mesgsys->addU8Fast(_PREHASH_PathShearX, pack_shear_x ); - U8 pack_shear_y = (U8) llround(params->getShearY() / SHEAR_QUANTA); + U8 pack_shear_y = (U8) ll_round(params->getShearY() / SHEAR_QUANTA); mesgsys->addU8Fast(_PREHASH_PathShearY, pack_shear_y ); - S8 twist = (S8) llround(params->getTwist() / SCALE_QUANTA); + S8 twist = (S8) ll_round(params->getTwist() / SCALE_QUANTA); mesgsys->addS8Fast(_PREHASH_PathTwist, twist); - S8 twist_begin = (S8) llround(params->getTwistBegin() / SCALE_QUANTA); + S8 twist_begin = (S8) ll_round(params->getTwistBegin() / SCALE_QUANTA); mesgsys->addS8Fast(_PREHASH_PathTwistBegin, twist_begin); - S8 radius_offset = (S8) llround(params->getRadiusOffset() / SCALE_QUANTA); + S8 radius_offset = (S8) ll_round(params->getRadiusOffset() / SCALE_QUANTA); mesgsys->addS8Fast(_PREHASH_PathRadiusOffset, radius_offset); - S8 taper_x = (S8) llround(params->getTaperX() / TAPER_QUANTA); + S8 taper_x = (S8) ll_round(params->getTaperX() / TAPER_QUANTA); mesgsys->addS8Fast(_PREHASH_PathTaperX, taper_x); - S8 taper_y = (S8) llround(params->getTaperY() / TAPER_QUANTA); + S8 taper_y = (S8) ll_round(params->getTaperY() / TAPER_QUANTA); mesgsys->addS8Fast(_PREHASH_PathTaperY, taper_y); - U8 revolutions = (U8) llround( (params->getRevolutions() - 1.0f) / REV_QUANTA); + U8 revolutions = (U8) ll_round( (params->getRevolutions() - 1.0f) / REV_QUANTA); mesgsys->addU8Fast(_PREHASH_PathRevolutions, revolutions); - S8 skew = (S8) llround(params->getSkew() / SCALE_QUANTA); + S8 skew = (S8) ll_round(params->getSkew() / SCALE_QUANTA); mesgsys->addS8Fast(_PREHASH_PathSkew, skew); return true; @@ -280,46 +280,46 @@ bool LLVolumeMessage::packPathParams( U8 curve = params->getCurveType(); dp.packU8(curve, "Curve"); - U16 begin = (U16) llround(params->getBegin() / CUT_QUANTA); + U16 begin = (U16) ll_round(params->getBegin() / CUT_QUANTA); dp.packU16(begin, "Begin"); - U16 end = 50000 - (U16) llround(params->getEnd() / CUT_QUANTA); + U16 end = 50000 - (U16) ll_round(params->getEnd() / CUT_QUANTA); dp.packU16(end, "End"); // Avoid truncation problem with direct F32->U8 cast. // (e.g., (U8) (0.50 / 0.01) = (U8) 49.9999999 = 49 not 50. - U8 pack_scale_x = 200 - (U8) llround(params->getScaleX() / SCALE_QUANTA); + U8 pack_scale_x = 200 - (U8) ll_round(params->getScaleX() / SCALE_QUANTA); dp.packU8(pack_scale_x, "ScaleX"); - U8 pack_scale_y = 200 - (U8) llround(params->getScaleY() / SCALE_QUANTA); + U8 pack_scale_y = 200 - (U8) ll_round(params->getScaleY() / SCALE_QUANTA); dp.packU8(pack_scale_y, "ScaleY"); - S8 pack_shear_x = (S8) llround(params->getShearX() / SHEAR_QUANTA); + S8 pack_shear_x = (S8) ll_round(params->getShearX() / SHEAR_QUANTA); dp.packU8(*(U8 *)&pack_shear_x, "ShearX"); - S8 pack_shear_y = (S8) llround(params->getShearY() / SHEAR_QUANTA); + S8 pack_shear_y = (S8) ll_round(params->getShearY() / SHEAR_QUANTA); dp.packU8(*(U8 *)&pack_shear_y, "ShearY"); - S8 twist = (S8) llround(params->getTwist() / SCALE_QUANTA); + S8 twist = (S8) ll_round(params->getTwist() / SCALE_QUANTA); dp.packU8(*(U8 *)&twist, "Twist"); - S8 twist_begin = (S8) llround(params->getTwistBegin() / SCALE_QUANTA); + S8 twist_begin = (S8) ll_round(params->getTwistBegin() / SCALE_QUANTA); dp.packU8(*(U8 *)&twist_begin, "TwistBegin"); - S8 radius_offset = (S8) llround(params->getRadiusOffset() / SCALE_QUANTA); + S8 radius_offset = (S8) ll_round(params->getRadiusOffset() / SCALE_QUANTA); dp.packU8(*(U8 *)&radius_offset, "RadiusOffset"); - S8 taper_x = (S8) llround(params->getTaperX() / TAPER_QUANTA); + S8 taper_x = (S8) ll_round(params->getTaperX() / TAPER_QUANTA); dp.packU8(*(U8 *)&taper_x, "TaperX"); - S8 taper_y = (S8) llround(params->getTaperY() / TAPER_QUANTA); + S8 taper_y = (S8) ll_round(params->getTaperY() / TAPER_QUANTA); dp.packU8(*(U8 *)&taper_y, "TaperY"); - U8 revolutions = (U8) llround( (params->getRevolutions() - 1.0f) / REV_QUANTA); + U8 revolutions = (U8) ll_round( (params->getRevolutions() - 1.0f) / REV_QUANTA); dp.packU8(*(U8 *)&revolutions, "Revolutions"); - S8 skew = (S8) llround(params->getSkew() / SCALE_QUANTA); + S8 skew = (S8) ll_round(params->getSkew() / SCALE_QUANTA); dp.packU8(*(U8 *)&skew, "Skew"); return true; @@ -385,12 +385,12 @@ bool LLVolumeMessage::unpackPathParams( params->setSkew((F32)(skew * SCALE_QUANTA)); /* - llinfos << "Unpacking Path Block " << block_num << llendl; - llinfos << "Curve: " << (U32)params->getCurve() << llendl; - llinfos << "Begin: " << params->getBegin() << llendl; - llinfos << "End: " << params->getEnd() << llendl; - llinfos << "Scale: " << params->getScale() << llendl; - llinfos << "Twist: " << params->getTwist() << llendl; + LL_INFOS() << "Unpacking Path Block " << block_num << LL_ENDL; + LL_INFOS() << "Curve: " << (U32)params->getCurve() << LL_ENDL; + LL_INFOS() << "Begin: " << params->getBegin() << LL_ENDL; + LL_INFOS() << "End: " << params->getEnd() << LL_ENDL; + LL_INFOS() << "Scale: " << params->getScale() << LL_ENDL; + LL_INFOS() << "Twist: " << params->getTwist() << LL_ENDL; */ return true; @@ -486,16 +486,16 @@ bool LLVolumeMessage::constrainVolumeParams(LLVolumeParams& params) bad |= params.setSkew(params.getPathParams().getSkew()) ? 0 : 0x800; if(bad) { - llwarns << "LLVolumeMessage::constrainVolumeParams() - " + LL_WARNS() << "LLVolumeMessage::constrainVolumeParams() - " << "forced to constrain incoming volume params: " - << llformat("0x%04x",bad) << llendl; + << llformat("0x%04x",bad) << LL_ENDL; } return bad ? false : true; } bool LLVolumeMessage::packVolumeParams(const LLVolumeParams* params, LLMessageSystem *mesgsys) { - // llinfos << "pack volume" << llendl; + // LL_INFOS() << "pack volume" << LL_ENDL; if (params) { packPathParams(¶ms->getPathParams(), mesgsys); @@ -511,7 +511,7 @@ bool LLVolumeMessage::packVolumeParams(const LLVolumeParams* params, LLMessageSy bool LLVolumeMessage::packVolumeParams(const LLVolumeParams* params, LLDataPacker &dp) { - // llinfos << "pack volume" << llendl; + // LL_INFOS() << "pack volume" << LL_ENDL; if (params) { packPathParams(¶ms->getPathParams(), dp); diff --git a/indra/llprimitive/object_flags.h b/indra/llprimitive/object_flags.h index f48b97d58b..e970144706 100644 --- a/indra/llprimitive/object_flags.h +++ b/indra/llprimitive/object_flags.h @@ -69,6 +69,7 @@ const U32 FLAGS_TEMPORARY = (1U << 30); //const U32 FLAGS_UNUSED_007 = (1U << 31); // was FLAGS_ZLIB_COMPRESSED const U32 FLAGS_LOCAL = FLAGS_ANIM_SOURCE | FLAGS_CAMERA_SOURCE; +const U32 FLAGS_WORLD = FLAGS_USE_PHYSICS | FLAGS_PHANTOM | FLAGS_TEMPORARY_ON_REZ; typedef enum e_havok_joint_type { diff --git a/indra/llqtwebkit/CMakeLists.txt b/indra/llqtwebkit/CMakeLists.txt deleted file mode 100644 index 6fbf5e9606..0000000000 --- a/indra/llqtwebkit/CMakeLists.txt +++ /dev/null @@ -1,70 +0,0 @@ -# -*- cmake -*- - -project(llqtwebkit) - -include(00-Common) -include(Qt4) - -if(NOT WORD_SIZE EQUAL 32) - if(WINDOWS) - add_definitions(/FIXED:NO) - else(WINDOWS) - add_definitions(-fPIC) - endif(WINDOWS) -endif(NOT WORD_SIZE EQUAL 32) - -include_directories(${QT_INCLUDES}) - -add_subdirectory(qtwebkit_cookiejar) -include_directories(qtwebkit_cookiejar/src/) - -set(llqtwebkit_SOURCE_FILES - llembeddedbrowser.cpp - llembeddedbrowserwindow.cpp - lljsobject.cpp - llnetworkaccessmanager.cpp - llqtwebkit.cpp - llstyle.cpp - llwebpage.cpp - llwebpageopenshim.cpp - ) - -set(llqtwebkit_HEADER_FILES - llembeddedbrowser.h - llembeddedbrowser_p.h - llembeddedbrowserwindow.h - llembeddedbrowserwindow_p.h - lljsobject.h - llnetworkaccessmanager.h - llqtwebkit.h - llstyle.h - llwebpage.h - llwebpageopenshim.h - pstdint.h - ) - -set(llqtwebkit_UI_FILES - passworddialog.ui - ) - -set(llqtwebkit_LINK_LIBRARIES - networkcookiejar -) - -QT4_WRAP_UI(llqtwebkit_UI_MOC ${llqtwebkit_UI_FILES}) -QT4_WRAP_CPP(llqtwebkit_HEADERS_MOC ${llqtwebkit_HEADER_FILES}) -include_directories(${CMAKE_CURRENT_BINARY_DIR}) - -add_library(llqtwebkit - ${llqtwebkit_SOURCE_FILES} - ${llqtwebkit_HEADERS_MOC} - ${llqtwebkit_UI_MOC} -) - -add_dependencies(llqtwebkit prepare) - -target_link_libraries(llqtwebkit ${llqtwebkit_LINK_LIBRARIES}) - -add_dependencies(llqtwebkit - networkcookiejar -) diff --git a/indra/llqtwebkit/autotests/llembeddedbrowser/llembeddedbrowser.pro b/indra/llqtwebkit/autotests/llembeddedbrowser/llembeddedbrowser.pro deleted file mode 100644 index 02ecce5a2b..0000000000 --- a/indra/llqtwebkit/autotests/llembeddedbrowser/llembeddedbrowser.pro +++ /dev/null @@ -1,14 +0,0 @@ -TEMPLATE = app -TARGET = -DEPENDPATH += . -INCLUDEPATH += . - -CONFIG += qtestlib -QT += webkit opengl network - -include(../../llmozlib2.pri) -DEFINES += AUTOTEST - -# Input -SOURCES += tst_llembeddedbrowser.cpp - diff --git a/indra/llqtwebkit/autotests/llembeddedbrowser/tst_llembeddedbrowser.cpp b/indra/llqtwebkit/autotests/llembeddedbrowser/tst_llembeddedbrowser.cpp deleted file mode 100644 index a59cc9e196..0000000000 --- a/indra/llqtwebkit/autotests/llembeddedbrowser/tst_llembeddedbrowser.cpp +++ /dev/null @@ -1,400 +0,0 @@ -/* Copyright (c) 2006-2010, Linden Research, Inc. - * - * LLQtWebKit Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in GPL-license.txt in this distribution, or online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - */ - -#include -#include -#include - -class tst_LLEmbeddedBrowser : public QObject -{ - Q_OBJECT - -public slots: - void initTestCase(); - void cleanupTestCase(); - void init(); - void cleanup(); - -private slots: - void llembeddedbrowser_data(); - void llembeddedbrowser(); - - void clearAllCookies(); - void clearCache_data(); - void clearCache(); - void clearLastError_data(); - void clearLastError(); - void createBrowserWindow_data(); - void createBrowserWindow(); - void destroyBrowserWindow(); - void enableCookies_data(); - void enableCookies(); - void enablePlugins_data(); - void enablePlugins(); - void enableProxy_data(); - void enableProxy(); - void getGREVersion_data(); - void getGREVersion(); - void getInstance(); - void getLastError_data(); - void getLastError(); - void initBrowser_data(); - void initBrowser(); //change function init as initbrowser - void reset(); - void setBrowserAgentId_data(); - void setBrowserAgentId(); - void setLastError_data(); - void setLastError(); -}; - -// Subclass that exposes the protected functions. -class SubLLEmbeddedBrowser : public LLEmbeddedBrowser -{ -public: - -}; - -// This will be called before the first test function is executed. -// It is only called once. -void tst_LLEmbeddedBrowser::initTestCase() -{ -} - -// This will be called after the last test function is executed. -// It is only called once. -void tst_LLEmbeddedBrowser::cleanupTestCase() -{ -} - -// This will be called before each test function is executed. -void tst_LLEmbeddedBrowser::init() -{ -} - -// This will be called after every test function. -void tst_LLEmbeddedBrowser::cleanup() -{ -} - -void tst_LLEmbeddedBrowser::llembeddedbrowser_data() -{ -} - -void tst_LLEmbeddedBrowser::llembeddedbrowser() -{ - SubLLEmbeddedBrowser browser; - QCOMPARE(browser.clearAllCookies(), false); - QCOMPARE(browser.clearCache(), false); - browser.clearLastError(); - QCOMPARE(browser.enableCookies(false), false); - QCOMPARE(browser.enablePlugins(false), true); - QCOMPARE(browser.enableProxy(false, std::string(""), -1), true); - QCOMPARE(browser.getGREVersion(), std::string(QT_VERSION_STR)); - QVERIFY(browser.getInstance() != NULL); - QCOMPARE(browser.getLastError(), 0); - browser.setBrowserAgentId("uBrowser"); - browser.setLastError(-1); - QCOMPARE(browser.reset(), true); - browser.destroyBrowserWindow(0); - browser.destroyBrowserWindow((LLEmbeddedBrowserWindow*)6); - QCOMPARE(browser.getWindowCount(), 0); - QCOMPARE(browser.init(std::string(""),std::string(""),std::string(""),0), true); -} - -// public bool clearAllCookies() -void tst_LLEmbeddedBrowser::clearAllCookies() -{ - SubLLEmbeddedBrowser browser; - - QCOMPARE(browser.clearAllCookies(), false); - browser.reset(); - QCOMPARE(browser.clearAllCookies(), true); -} - -void tst_LLEmbeddedBrowser::clearCache_data() -{ - QTest::addColumn("clearCache"); -#if QT_VERSION < 0x040500 - QTest::newRow("QTVersion < 4.5") << false; -#else - QTest::newRow("QTVersion > 4.5") << true; -#endif -} - -// public bool clearCache() -void tst_LLEmbeddedBrowser::clearCache() -{ - QFETCH(bool, clearCache); - - SubLLEmbeddedBrowser browser; - browser.reset(); - QCOMPARE(browser.clearCache(), clearCache); -} - -void tst_LLEmbeddedBrowser::clearLastError_data() -{ - QTest::addColumn("lastError"); - QTest::newRow("1") << 1; -} - -// public void clearLastError() -void tst_LLEmbeddedBrowser::clearLastError() -{ - SubLLEmbeddedBrowser browser; - QFETCH(int, lastError); - - browser.setLastError(lastError); - browser.clearLastError(); - QCOMPARE(browser.getLastError(), 0); -} - -void tst_LLEmbeddedBrowser::createBrowserWindow_data() -{ - QTest::addColumn("width"); - QTest::addColumn("height"); - QTest::newRow("0,0") << 0 << 0; - QTest::newRow("800,600") << 800 << 600; -} - -// public LLEmbeddedBrowserWindow* createBrowserWindow(int width, int height) -void tst_LLEmbeddedBrowser::createBrowserWindow() -{ - QFETCH(int, width); - QFETCH(int, height); - SubLLEmbeddedBrowser browser; - - LLEmbeddedBrowserWindow *window = browser.createBrowserWindow(width, height); - QVERIFY(window); - QCOMPARE(browser.getLastError(), 0); - QCOMPARE(browser.getWindowCount(), 1); - QCOMPARE(window->getBrowserWidth(), (int16_t)width); - QCOMPARE(window->getBrowserHeight(), (int16_t)height); -} - -// public bool destroyBrowserWindow(LLEmbeddedBrowserWindow* browser_window) -void tst_LLEmbeddedBrowser::destroyBrowserWindow() -{ - SubLLEmbeddedBrowser browser; - browser.reset(); - LLEmbeddedBrowserWindow* browser_window = browser.createBrowserWindow(200, 100); - if (browser_window) - { - QCOMPARE(browser.getWindowCount(), 1); - browser.destroyBrowserWindow(browser_window); - QCOMPARE(browser.getLastError(), 0); - QCOMPARE(browser.getWindowCount(), 0); - } - - browser_window = browser.createBrowserWindow(800, 600); - if (browser_window) - { - QCOMPARE(browser.getWindowCount(), 1); - browser.destroyBrowserWindow(browser_window); - QCOMPARE(browser.getLastError(), 0); - QCOMPARE(browser.getWindowCount(), 0); - } -} - -void tst_LLEmbeddedBrowser::enableCookies_data() -{ - QTest::addColumn("enabled"); - QTest::addColumn("enableCookies"); - QTest::newRow("disable") << false << false; - QTest::newRow("enable") << true << false; -} - -// public bool enableCookies(bool enabled) -void tst_LLEmbeddedBrowser::enableCookies() -{ - QFETCH(bool, enabled); - QFETCH(bool, enableCookies); - - SubLLEmbeddedBrowser browser; - browser.reset(); - QCOMPARE(browser.enableCookies(enabled), enableCookies); - // TODO check that cookies are not saved -} - -void tst_LLEmbeddedBrowser::enablePlugins_data() -{ - QTest::addColumn("enabled"); - QTest::addColumn("enablePlugins"); - QTest::newRow("disable") << false << true; - QTest::newRow("enable") << true << true; -} - -// public bool enablePlugins(bool enabled) -void tst_LLEmbeddedBrowser::enablePlugins() -{ - QFETCH(bool, enabled); - QFETCH(bool, enablePlugins); - - SubLLEmbeddedBrowser browser; - browser.reset(); - QCOMPARE(browser.enablePlugins(enabled), enablePlugins); - // TODO check that plugins work/do not work -} - -Q_DECLARE_METATYPE(std::string) -void tst_LLEmbeddedBrowser::enableProxy_data() -{ - QTest::addColumn("enabled"); - QTest::addColumn("host_name"); - QTest::addColumn("port"); - QTest::addColumn("enableProxy"); - QTest::newRow("null") << false << std::string() << 0 << true; - QTest::newRow("valid") << true << std::string("wtfsurf.com") << 80 << true; -} - -// public bool enableProxy(bool enabled, std::string host_name, int port) -void tst_LLEmbeddedBrowser::enableProxy() -{ - QFETCH(bool, enabled); - QFETCH(std::string, host_name); - QFETCH(int, port); - QFETCH(bool, enableProxy); - - SubLLEmbeddedBrowser browser; - browser.reset(); - QCOMPARE(browser.enableProxy(enabled, host_name, port), enableProxy); - // TODO need some proxy servers to test this -} - -void tst_LLEmbeddedBrowser::getGREVersion_data() -{ - QTest::addColumn("getGREVersion"); - QTest::newRow("valid") << std::string(QT_VERSION_STR); -} - -// public std::string getGREVersion() -void tst_LLEmbeddedBrowser::getGREVersion() -{ - QFETCH(std::string, getGREVersion); - - SubLLEmbeddedBrowser browser; - browser.reset(); - QCOMPARE(browser.getGREVersion(), getGREVersion); -} - -// public static LLEmbeddedBrowser* getInstance() -void tst_LLEmbeddedBrowser::getInstance() -{ - SubLLEmbeddedBrowser browser; - QVERIFY(browser.getInstance() != NULL); -} - -void tst_LLEmbeddedBrowser::getLastError_data() -{ - QTest::addColumn("error"); - QTest::newRow("0") << 0; - QTest::newRow("-1") << -1; - QTest::newRow("100") << 100; -} - -// public int getLastError() -void tst_LLEmbeddedBrowser::getLastError() -{ - QFETCH(int, error); - SubLLEmbeddedBrowser browser; - browser.setLastError(error); - QCOMPARE(browser.getLastError(), error); -} - -void tst_LLEmbeddedBrowser::initBrowser_data() -{ - QTest::addColumn("application_directory"); - QTest::addColumn("component_directory"); - QTest::addColumn("profile_directory"); - QTest::addColumn("native_window_handleCount"); - QTest::addColumn("init"); - QTest::newRow("null") << std::string() << std::string() << std::string() << (void *)0 << true; - QTest::newRow("valid") << std::string("/home/crystal/Settings/") << std::string() << std::string() << (void *)0 << true; -} -void tst_LLEmbeddedBrowser::initBrowser() -{ - QFETCH(std::string, application_directory); - QFETCH(std::string, component_directory); - QFETCH(std::string, profile_directory); - QFETCH(void *, native_window_handleCount); - SubLLEmbeddedBrowser browser; - browser.init(application_directory,component_directory,profile_directory,native_window_handleCount); - QCOMPARE(browser.getLastError(), 0); -} - -// public bool reset() -void tst_LLEmbeddedBrowser::reset() -{ - SubLLEmbeddedBrowser browser; - - browser.setLastError(100); - QCOMPARE(browser.getLastError(), 100); - QVERIFY(browser.reset()); - QCOMPARE(browser.getLastError(), 0); - // TODO what should reset really do? -} - -void tst_LLEmbeddedBrowser::setBrowserAgentId_data() -{ - QTest::addColumn("id"); - QTest::newRow("null") << std::string(); - QTest::newRow("valid") << std::string("uBrowser"); - -} - -// public void setBrowserAgentId(std::string id) -void tst_LLEmbeddedBrowser::setBrowserAgentId() -{ - QFETCH(std::string, id); - - SubLLEmbeddedBrowser browser; - browser.reset(); - browser.setBrowserAgentId(id); - LLEmbeddedBrowserWindow *window = browser.createBrowserWindow(0, 0); - Q_UNUSED(window); - // TODO confirm that the page is actually sending the agent ID -} - -void tst_LLEmbeddedBrowser::setLastError_data() -{ - QTest::addColumn("error_number"); - QTest::newRow("0") << 0; - QTest::newRow("-1") << -1; - QTest::newRow("100") << 100; -} - -// public void setLastError(int error_number) -void tst_LLEmbeddedBrowser::setLastError() -{ - QFETCH(int, error_number); - - SubLLEmbeddedBrowser browser; - - browser.setLastError(error_number); - QCOMPARE(browser.getLastError(), error_number); -} - -QTEST_MAIN(tst_LLEmbeddedBrowser) -#include "tst_llembeddedbrowser.moc" - diff --git a/indra/llqtwebkit/autotests/llembeddedbrowserwindow/llembeddedbrowserwindow.pro b/indra/llqtwebkit/autotests/llembeddedbrowserwindow/llembeddedbrowserwindow.pro deleted file mode 100644 index a89f500652..0000000000 --- a/indra/llqtwebkit/autotests/llembeddedbrowserwindow/llembeddedbrowserwindow.pro +++ /dev/null @@ -1,14 +0,0 @@ -TEMPLATE = app -TARGET = -DEPENDPATH += . -INCLUDEPATH += . - -CONFIG += qtestlib -QT += webkit opengl network - -include(../../llmozlib2.pri) -DEFINES += AUTOTEST - -# Input -SOURCES += tst_llembeddedbrowserwindow.cpp - diff --git a/indra/llqtwebkit/autotests/llembeddedbrowserwindow/tst_llembeddedbrowserwindow.cpp b/indra/llqtwebkit/autotests/llembeddedbrowserwindow/tst_llembeddedbrowserwindow.cpp deleted file mode 100644 index 4c365d3713..0000000000 --- a/indra/llqtwebkit/autotests/llembeddedbrowserwindow/tst_llembeddedbrowserwindow.cpp +++ /dev/null @@ -1,1027 +0,0 @@ -/* Copyright (c) 2006-2010, Linden Research, Inc. - * - * LLQtWebKit Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in GPL-license.txt in this distribution, or online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - */ - -#include - -#include "llembeddedbrowserwindow.h" -#include "llembeddedbrowser.h" - -#ifndef QTRY_COMPARE - -#define __TRY_TIMEOUT__ 10000 -#define __TRY_STEP__ 50 - -#define __QTRY(__expression__, __functionToCall__) \ - do { \ - int __i = 0; \ - while (!(__expression__) && __i < __TRY_TIMEOUT__) { \ - QTest::qWait(__TRY_STEP__); \ - __i += __TRY_STEP__; \ - } \ - __functionToCall__; \ - } while(0) - -#define QTRY_COMPARE(__expression__, __expected__) \ - __QTRY((__expression__ == __expected__), QCOMPARE(__expression__, __expected__)); - -#define QTRY_VERIFY(__expression__) \ - __QTRY(__expression__, QVERIFY(__expression__)); - -#endif // QTRY_COMPARE - -class tst_LLEmbeddedBrowserWindow : public QObject -{ - Q_OBJECT - -public slots: - void initTestCase(); - void cleanupTestCase(); - void init(); - void cleanup(); - -private slots: - void llembeddedbrowserwindow_data(); - void llembeddedbrowserwindow(); - - void addObserver_data(); - void addObserver(); - void canNavigateBack_data(); - void canNavigateBack(); - void canNavigateForward_data(); - void canNavigateForward(); - void evaluateJavascript_data(); - void evaluateJavascript(); - void flipWindow_data(); - void flipWindow(); - void focusBrowser_data(); - void focusBrowser(); - void getBrowserDepth_data(); - void getBrowserDepth(); - void getBrowserHeight_data(); - void getBrowserHeight(); - void getBrowserRowSpan_data(); - void getBrowserRowSpan(); - void getBrowserWidth_data(); - void getBrowserWidth(); - void getClickLinkHref_data(); - void getClickLinkHref(); - void getClickLinkTarget_data(); - void getClickLinkTarget(); - void getCurrentUri_data(); - void getCurrentUri(); - void getNoFollowScheme_data(); - void getNoFollowScheme(); - void getPageBuffer_data(); - void getPageBuffer(); - void getPercentComplete_data(); - void getPercentComplete(); - void getStatusMsg_data(); - void getStatusMsg(); - void getWindowId_data(); - void getWindowId(); - void grabWindow_data(); - void grabWindow(); - void keyPress_data(); - void keyPress(); - void mouseDown_data(); - void mouseDown(); - void mouseLeftDoubleClick_data(); - void mouseLeftDoubleClick(); - void mouseMove_data(); - void mouseMove(); - void mouseUp_data(); - void mouseUp(); - void navigateBack_data(); - void navigateBack(); - void navigateForward_data(); - void navigateForward(); - void navigateReload_data(); - void navigateReload(); - void navigateStop_data(); - void navigateStop(); - void navigateTo_data(); - void navigateTo(); - void remObserver_data(); - void remObserver(); - void scrollByLines_data(); - void scrollByLines(); - void setBackgroundColor_data(); - void setBackgroundColor(); - void setCaretColor_data(); - void setCaretColor(); - void setEnabled_data(); - void setEnabled(); - void setNoFollowScheme_data(); - void setNoFollowScheme(); - void setParent_data(); - void setParent(); - void setSize_data(); - void setSize(); - void setWindowId_data(); - void setWindowId(); - void unicodeInput_data(); - void unicodeInput(); -}; - -// Subclass that exposes the protected functions. -class SubLLEmbeddedBrowserWindow : public LLEmbeddedBrowserWindow -{ -public: - -}; - -// This will be called before the first test function is executed. -// It is only called once. -void tst_LLEmbeddedBrowserWindow::initTestCase() -{ -} - -// This will be called after the last test function is executed. -// It is only called once. -void tst_LLEmbeddedBrowserWindow::cleanupTestCase() -{ -} - -// This will be called before each test function is executed. -void tst_LLEmbeddedBrowserWindow::init() -{ -} - -// This will be called after every test function. -void tst_LLEmbeddedBrowserWindow::cleanup() -{ -} - -void tst_LLEmbeddedBrowserWindow::llembeddedbrowserwindow_data() -{ -} - -void tst_LLEmbeddedBrowserWindow::llembeddedbrowserwindow() -{ - SubLLEmbeddedBrowserWindow window; - QCOMPARE(window.addObserver((LLEmbeddedBrowserWindowObserver*)0), false); - QCOMPARE(window.canNavigateBack(), false); - QCOMPARE(window.canNavigateForward(), false); - QCOMPARE(window.evaluateJavascript(std::string()), std::string()); - QCOMPARE(window.flipWindow(false), true); - window.focusBrowser(false); - QCOMPARE(window.getBrowserDepth(), (int16_t)4); - QCOMPARE(window.getBrowserHeight(), (int16_t)0); - QCOMPARE(window.getBrowserRowSpan(), (int32_t)0); - QCOMPARE(window.getBrowserWidth(), (int16_t)0); - QCOMPARE(window.getClickLinkHref(), std::string()); - QCOMPARE(window.getClickLinkTarget(), std::string()); - QCOMPARE(window.getCurrentUri(), std::string()); - QCOMPARE(window.getNoFollowScheme(), std::string("secondlife")); - QCOMPARE(window.getPageBuffer(), (unsigned char*)0); - QCOMPARE(window.getPercentComplete(), (int16_t)0); - QCOMPARE(window.getStatusMsg(), std::string()); - QCOMPARE(window.getWindowId(), -1); - QCOMPARE(window.grabWindow(-1, -1, -1, -1), (unsigned char*)0); - window.keyPress(0); - window.mouseDown(0, 0); - window.mouseLeftDoubleClick(0, 0); - window.mouseMove(0, 0); - window.mouseUp(0, 0); - window.navigateBack(); - window.navigateForward(); - window.navigateReload(); - window.navigateStop(); - QCOMPARE(window.navigateTo(std::string()), true); - QCOMPARE(window.remObserver((LLEmbeddedBrowserWindowObserver*)0), false); - window.scrollByLines(0); - window.setBackgroundColor(0, 0, 0); - window.setCaretColor(0, 0, 0); - window.setEnabled(false); - window.setNoFollowScheme(std::string()); - window.setParent((LLEmbeddedBrowser*)0); - QCOMPARE(window.setSize(0, 0), true); - window.setWindowId(-1); - window.unicodeInput((uint32_t)0); -} - -void tst_LLEmbeddedBrowserWindow::addObserver_data() -{ -#if 0 - QTest::addColumn("observerCount"); - QTest::addColumn("addObserver"); - QTest::newRow("null") << 0 << false; -#endif -} - -// public bool addObserver(LLEmbeddedBrowserWindowObserver* observer) -void tst_LLEmbeddedBrowserWindow::addObserver() -{ -#if 0 - QFETCH(int, observerCount); - QFETCH(bool, addObserver); - - SubLLEmbeddedBrowserWindow window; - - QCOMPARE(window.addObserver(observer), addObserver); -#endif - QSKIP("Test is same with remObserver.", SkipAll); -} - -void tst_LLEmbeddedBrowserWindow::canNavigateBack_data() -{ -#if 0 - QTest::addColumn("canNavigateBack"); - QTest::newRow("true") << true; - QTest::newRow("false") << false; -#endif -} - -// public bool canNavigateBack() -void tst_LLEmbeddedBrowserWindow::canNavigateBack() -{ - //QFETCH(bool, canNavigateForward); - - SubLLEmbeddedBrowserWindow window; - window.setSize(800,600); - window.setParent(new LLEmbeddedBrowser()); - QCOMPARE(window.canNavigateForward(), false); - window.navigateTo(std::string("http://www.google.com")); - QTest::qWait(__TRY_TIMEOUT__); - QCOMPARE(window.canNavigateBack(), false); - window.navigateTo(std::string("http://www.cnn.com")); - QTest::qWait(__TRY_TIMEOUT__); - QCOMPARE(window.canNavigateBack(), true); - window.navigateBack(); - QTRY_COMPARE(window.canNavigateForward(), true); - window.navigateForward(); - QTRY_COMPARE(window.canNavigateBack(), true); -} - -void tst_LLEmbeddedBrowserWindow::canNavigateForward_data() -{ -#if 0 - QTest::addColumn("canNavigateForward"); - QTest::newRow("true") << true; - QTest::newRow("false") << false; -#endif -} - -// public bool canNavigateForward() -void tst_LLEmbeddedBrowserWindow::canNavigateForward() -{ - QSKIP("Test is same with canNavigateBack().", SkipAll); -} - -Q_DECLARE_METATYPE(std::string) -void tst_LLEmbeddedBrowserWindow::evaluateJavascript_data() -{ - QTest::addColumn("script"); - QTest::addColumn("evaluateJavascript"); - QTest::newRow("null") << std::string() << std::string(); - //QTest::newRow("valid") << std::string("alert(\"hey!\")") << std::string("alert(\"hey!\")"); -} - -// public std::string evaluateJavascript(std::string script) -void tst_LLEmbeddedBrowserWindow::evaluateJavascript() -{ - QFETCH(std::string, script); - QFETCH(std::string, evaluateJavascript); - - SubLLEmbeddedBrowserWindow window; - - window.evaluateJavascript(script); -} - -void tst_LLEmbeddedBrowserWindow::flipWindow_data() -{ - QTest::addColumn("flip"); - QTest::addColumn("flipWindow"); - QTest::newRow("false") << false << true; - QTest::newRow("true") << true << true; -} - -// public bool flipWindow(bool flip) -void tst_LLEmbeddedBrowserWindow::flipWindow() -{ - QFETCH(bool, flip); - QFETCH(bool, flipWindow); - - SubLLEmbeddedBrowserWindow window; - - QCOMPARE(window.flipWindow(flip), flipWindow); -} - -void tst_LLEmbeddedBrowserWindow::focusBrowser_data() -{ - QTest::addColumn("focus_browser"); - QTest::newRow("true") << true; - QTest::newRow("false") << false; -} - -// public void focusBrowser(bool focus_browser) -void tst_LLEmbeddedBrowserWindow::focusBrowser() -{ - QFETCH(bool, focus_browser); - - SubLLEmbeddedBrowserWindow window; - window.focusBrowser(focus_browser); -} - -Q_DECLARE_METATYPE(int16_t) -void tst_LLEmbeddedBrowserWindow::getBrowserDepth_data() -{ -#if 0 - QTest::addColumn("getBrowserDepth"); - QTest::newRow("null") << int16_t(); -#endif -} - -// public int16_t getBrowserDepth() -void tst_LLEmbeddedBrowserWindow::getBrowserDepth() -{ - //QFETCH(int16_t, getBrowserDepth); - - SubLLEmbeddedBrowserWindow window; - - QCOMPARE(window.getBrowserDepth(), int16_t(4)); -} - -void tst_LLEmbeddedBrowserWindow::getBrowserHeight_data() -{ -#if 0 - QTest::addColumn("getBrowserHeight"); - QTest::newRow("null") << int16_t(); -#endif -} - -// public int16_t getBrowserHeight() -void tst_LLEmbeddedBrowserWindow::getBrowserHeight() -{ -#if 0 - QFETCH(int16_t, getBrowserHeight); - - SubLLEmbeddedBrowserWindow window; - - QCOMPARE(window.getBrowserHeight(), getBrowserHeight); -#endif - QSKIP("Test is same with setSize().", SkipAll); -} - -Q_DECLARE_METATYPE(int32_t) -void tst_LLEmbeddedBrowserWindow::getBrowserRowSpan_data() -{ -#if 0 - QTest::addColumn("getBrowserRowSpan"); - QTest::newRow("null") << int32_t(); -#endif -} - -// public int32_t getBrowserRowSpan() -void tst_LLEmbeddedBrowserWindow::getBrowserRowSpan() -{ -#if 0 - SubLLEmbeddedBrowserWindow window; - window.setSize(0, 0); - - QCOMPARE(window.getBrowserWidth(), int16_t(0)); - QCOMPARE(window.getBrowserRowSpan(), int32_t(0)); - window.setSize(100, 100); - - QCOMPARE(window.getBrowserWidth(), int16_t(100)); - QCOMPARE(window.getBrowserRowSpan(), int32_t(400)); -#endif - QSKIP("Test is same with setSize().", SkipAll); -} - -void tst_LLEmbeddedBrowserWindow::getBrowserWidth_data() -{ -#if 0 - QTest::addColumn("getBrowserWidth"); - QTest::newRow("null") << int16_t(); -#endif -} - -// public int16_t getBrowserWidth() -void tst_LLEmbeddedBrowserWindow::getBrowserWidth() -{ -#if 0 - //QFETCH(int16_t, getBrowserWidth); - - SubLLEmbeddedBrowserWindow window; - window.setSize(0, 0); - - QCOMPARE(window.getBrowserWidth(), int16_t(0)); - QCOMPARE(window.getBrowserHeight(), int16_t(0)); - window.setSize(100, 100); - - QCOMPARE(window.getBrowserWidth(), int16_t(100)); - QCOMPARE(window.getBrowserHeight(), int16_t(100)); -#endif - QSKIP("Test is same with setSize().", SkipAll); -} - -//Q_DECLARE_METATYPE(std::string const) -void tst_LLEmbeddedBrowserWindow::getClickLinkHref_data() -{ -#if 0 - QTest::addColumn("getClickLinkHref"); - QTest::newRow("null") << std::string const(); -#endif -} - -// public std::string const getClickLinkHref() -void tst_LLEmbeddedBrowserWindow::getClickLinkHref() -{ - //QFETCH(std::string const, getClickLinkHref); - - SubLLEmbeddedBrowserWindow window; - - window.getClickLinkHref(); -} - -void tst_LLEmbeddedBrowserWindow::getClickLinkTarget_data() -{ -#if 0 - QTest::addColumn("getClickLinkTarget"); - QTest::newRow("null") << std::string const(); -#endif -} - -// public std::string const getClickLinkTarget() -void tst_LLEmbeddedBrowserWindow::getClickLinkTarget() -{ - //QFETCH(std::string const, getClickLinkTarget); - - SubLLEmbeddedBrowserWindow window; - - window.getClickLinkTarget(); -} - -void tst_LLEmbeddedBrowserWindow::getCurrentUri_data() -{ -#if 0 - QTest::addColumn("getCurrentUri"); - QTest::newRow("null") << std::string const(); -#endif -} - -// public std::string const getCurrentUri() -void tst_LLEmbeddedBrowserWindow::getCurrentUri() -{ - //QFETCH(std::string const, getCurrentUri); - - SubLLEmbeddedBrowserWindow window; - window.navigateTo(std::string("http://www.google.ca/")); - QTRY_COMPARE(QString::fromStdString(window.getCurrentUri()), QString::fromStdString(std::string("http://www.google.ca/"))); -} - -void tst_LLEmbeddedBrowserWindow::getNoFollowScheme_data() -{ -#if 0 - QTest::addColumn("getNoFollowScheme"); - QTest::newRow("FTP") << std::string("FTP"); -#endif -} - -// public std::string getNoFollowScheme() -void tst_LLEmbeddedBrowserWindow::getNoFollowScheme() -{ - //QFETCH(std::string, getNoFollowScheme); - - SubLLEmbeddedBrowserWindow window; - window.setNoFollowScheme("FTP://www.google.com"); - - QCOMPARE(window.getNoFollowScheme(), std::string("FTP")); -} - -//Q_DECLARE_METATYPE(unsigned char*) -void tst_LLEmbeddedBrowserWindow::getPageBuffer_data() -{ -#if 0 - QTest::addColumn("getPageBuffer"); - QTest::newRow("null") << unsigned char*(); -#endif -} - -// public unsigned char* getPageBuffer() -void tst_LLEmbeddedBrowserWindow::getPageBuffer() -{ - //QFETCH(unsigned char*, getPageBuffer); - - SubLLEmbeddedBrowserWindow window; - window.setSize(100,100); - window.grabWindow(0, 0, 100, 100); - - QVERIFY(window.getPageBuffer() != NULL); -} - -//Q_DECLARE_METATYPE(int16_t const) -void tst_LLEmbeddedBrowserWindow::getPercentComplete_data() -{ -#if 0 - QTest::addColumn("getPercentComplete"); - QTest::newRow("null") << int16_t const(); -#endif -} - -// public int16_t const getPercentComplete() -void tst_LLEmbeddedBrowserWindow::getPercentComplete() -{ - //QFETCH(int16_t const, getPercentComplete); - SubLLEmbeddedBrowserWindow window; - window.navigateTo(std::string("http://www.google.com")); - QTest::qWait(1000); - QVERIFY(window.getPercentComplete() > 0); -} - -void tst_LLEmbeddedBrowserWindow::getStatusMsg_data() -{ -#if 0 - QTest::addColumn("getStatusMsg"); - QTest::newRow("null") << std::string const(); -#endif -} - -// public std::string const getStatusMsg() -void tst_LLEmbeddedBrowserWindow::getStatusMsg() -{ - //QFETCH(std::string const, getStatusMsg); - - SubLLEmbeddedBrowserWindow window; - window.navigateTo(std::string("http://www.google.com")); - QTest::qWait(1000); - window.navigateStop(); - window.navigateTo(std::string("http://www.yahoo.com")); - // Seems status msg will always be null during navigating. - //QTRY_VERIFY(QString::fromStdString(window.getStatusMsg())!= NULL); - QSKIP("Status msg will always be null during navigating", SkipAll); -} - -void tst_LLEmbeddedBrowserWindow::getWindowId_data() -{ -#if 0 - QTest::addColumn("getWindowId"); - QTest::newRow("0") << 0; - QTest::newRow("-1") << -1; -#endif -} - -// public int getWindowId() -void tst_LLEmbeddedBrowserWindow::getWindowId() -{ - //QFETCH(int, getWindowId); - - SubLLEmbeddedBrowserWindow window; - window.setWindowId(0); - QCOMPARE(window.getWindowId(), 0); - window.setWindowId(100); - QCOMPARE(window.getWindowId(), 100); -} - -void tst_LLEmbeddedBrowserWindow::grabWindow_data() -{ -#if 0 - QTest::addColumn("x"); - QTest::addColumn("y"); - QTest::addColumn("width"); - QTest::addColumn("height"); - QTest::addColumn("grabWindow"); - QTest::newRow("null") << 0 << 0 << 0 << 0 << 0; -#endif -} - -// public unsigned char* grabWindow(int x, int y, int width, int height) -void tst_LLEmbeddedBrowserWindow::grabWindow() -{ - QSKIP("Test is same with getPageBuffer().", SkipAll); -} - -void tst_LLEmbeddedBrowserWindow::keyPress_data() -{ - QTest::addColumn("key_code"); - QTest::newRow("null") << int16_t(0); - QTest::newRow("valid") << int16_t(0x0E); -} - -// public void keyPress(int16_t key_code) -void tst_LLEmbeddedBrowserWindow::keyPress() -{ - QFETCH(int16_t, key_code); - - SubLLEmbeddedBrowserWindow window; - window.keyPress(key_code); -} - -void tst_LLEmbeddedBrowserWindow::mouseDown_data() -{ - QTest::addColumn("x"); - QTest::addColumn("y"); - QTest::newRow("0") << int16_t(0) << int16_t(0); - QTest::newRow("bignumber") << int16_t(100000) << int16_t(100000); - QTest::newRow("valid") << int16_t(100) << int16_t(100); -} - -// public void mouseDown(int16_t x, int16_t y) -void tst_LLEmbeddedBrowserWindow::mouseDown() -{ - QFETCH(int16_t, x); - QFETCH(int16_t, y); - - SubLLEmbeddedBrowserWindow window; - window.mouseDown(x, y); -} - -void tst_LLEmbeddedBrowserWindow::mouseLeftDoubleClick_data() -{ - QTest::addColumn("x"); - QTest::addColumn("y"); - QTest::newRow("0") << int16_t(0) << int16_t(0); - QTest::newRow("bignumber") << int16_t(100000) << int16_t(100000); - QTest::newRow("valid") << int16_t(100) << int16_t(100); -} - -// public void mouseLeftDoubleClick(int16_t x, int16_t y) -void tst_LLEmbeddedBrowserWindow::mouseLeftDoubleClick() -{ - QFETCH(int16_t, x); - QFETCH(int16_t, y); - - SubLLEmbeddedBrowserWindow window; - window.mouseLeftDoubleClick(x, y); -} - -void tst_LLEmbeddedBrowserWindow::mouseMove_data() -{ - QTest::addColumn("x"); - QTest::addColumn("y"); - QTest::newRow("0") << int16_t(0) << int16_t(0); - QTest::newRow("bignumber") << int16_t(100000) << int16_t(100000); - QTest::newRow("valid") << int16_t(100) << int16_t(100); -} - -// public void mouseMove(int16_t x, int16_t y) -void tst_LLEmbeddedBrowserWindow::mouseMove() -{ - QFETCH(int16_t, x); - QFETCH(int16_t, y); - - SubLLEmbeddedBrowserWindow window; - window.mouseMove(x, y); -} - -void tst_LLEmbeddedBrowserWindow::mouseUp_data() -{ - QTest::addColumn("x"); - QTest::addColumn("y"); - QTest::newRow("0") << int16_t(0) << int16_t(0); - QTest::newRow("bignumber") << int16_t(100000) << int16_t(100000); - QTest::newRow("valid") << int16_t(100) << int16_t(100); -} - -// public void mouseUp(int16_t x, int16_t y) -void tst_LLEmbeddedBrowserWindow::mouseUp() -{ - QFETCH(int16_t, x); - QFETCH(int16_t, y); - - SubLLEmbeddedBrowserWindow window; - window.mouseUp(x, y); -} - -void tst_LLEmbeddedBrowserWindow::navigateBack_data() -{ -#if 0 - QTest::addColumn("foo"); - QTest::newRow("0") << 0; - QTest::newRow("-1") << -1; -#endif -} - -// public void navigateBack() -void tst_LLEmbeddedBrowserWindow::navigateBack() -{ - //QFETCH(int, foo); - - SubLLEmbeddedBrowserWindow window; - window.navigateTo(std::string("http://www.google.ca/")); - QTest::qWait(__TRY_TIMEOUT__); - QCOMPARE(window.canNavigateForward(), false); - window.navigateTo(std::string("http://www.yahoo.com/")); - QTest::qWait(__TRY_TIMEOUT__); - QCOMPARE(window.canNavigateBack(), true); - window.navigateBack(); - QTRY_COMPARE(QString::fromStdString((window.getCurrentUri())), QString("http://www.google.ca/")); - window.navigateBack(); - QTRY_COMPARE(QString::fromStdString((window.getCurrentUri())), QString("http://www.google.ca/")); -} - -void tst_LLEmbeddedBrowserWindow::navigateForward_data() -{ -#if 0 - QTest::addColumn("foo"); - QTest::newRow("0") << 0; - QTest::newRow("-1") << -1; -#endif -} - -// public void navigateForward() -void tst_LLEmbeddedBrowserWindow::navigateForward() -{ - // QFETCH(int, foo); - SubLLEmbeddedBrowserWindow window; - window.navigateTo(std::string("http://www.google.ca/")); - QTest::qWait(__TRY_TIMEOUT__); - QCOMPARE(window.canNavigateForward(), false); - window.navigateTo(std::string("http://www.yahoo.ca/")); - QTest::qWait(__TRY_TIMEOUT__); - QCOMPARE(window.canNavigateBack(), true); - window.navigateBack(); - QTRY_COMPARE(QString::fromStdString((window.getCurrentUri())), QString("http://www.google.ca/")); - window.navigateForward(); - QTRY_COMPARE(QString::fromStdString((window.getCurrentUri())), QString("http://ca.yahoo.com/")); - window.navigateForward(); - QTRY_COMPARE(QString::fromStdString((window.getCurrentUri())), QString("http://ca.yahoo.com/")); -} - -void tst_LLEmbeddedBrowserWindow::navigateReload_data() -{ -#if 0 - QTest::addColumn("foo"); - QTest::newRow("0") << 0; - QTest::newRow("-1") << -1; -#endif -} - -// public void navigateReload() -void tst_LLEmbeddedBrowserWindow::navigateReload() -{ - SubLLEmbeddedBrowserWindow window; - - window.navigateTo(std::string("http://www.google.ca/")); - QTest::qWait(__TRY_TIMEOUT__); - window.navigateReload(); - QTRY_COMPARE(QString::fromStdString((window.getCurrentUri())), QString("http://www.google.ca/")); -} - -void tst_LLEmbeddedBrowserWindow::navigateStop_data() -{ -#if 0 - QTest::addColumn("foo"); - QTest::newRow("0") << 0; - QTest::newRow("-1") << -1; -#endif -} - -// public void navigateStop() -void tst_LLEmbeddedBrowserWindow::navigateStop() -{ - SubLLEmbeddedBrowserWindow window; - window.navigateTo("www.google.com"); - window.navigateStop(); -} - -void tst_LLEmbeddedBrowserWindow::navigateTo_data() -{ - QTest::addColumn("uri"); - QTest::addColumn("navigateTo"); - QTest::newRow("null") << std::string() << std::string(); - QTest::newRow("valid") << std::string("http://www.google.ca/") << std::string("http://www.google.ca/"); -} - -// public bool navigateTo(std::string const uri) -void tst_LLEmbeddedBrowserWindow::navigateTo() -{ - QSKIP("Test is same with navigateBack(), navigateForward().", SkipAll); -} - -void tst_LLEmbeddedBrowserWindow::remObserver_data() -{ -#if 0 - QTest::addColumn("observerCount"); - QTest::addColumn("remObserver"); - QTest::newRow("null") << 0 << false; -#endif -} - -// public bool remObserver(LLEmbeddedBrowserWindowObserver* observer) -void tst_LLEmbeddedBrowserWindow::remObserver() -{ -// QFETCH(int, observerCount); -// QFETCH(bool, remObserver); - - SubLLEmbeddedBrowserWindow window; - LLEmbeddedBrowserWindowObserver* observer = new LLEmbeddedBrowserWindowObserver(); - window.addObserver(observer); - QCOMPARE(window.getObserverNumber(), 1); - window.remObserver(observer); - QCOMPARE(window.getObserverNumber(), 0); -} - -void tst_LLEmbeddedBrowserWindow::scrollByLines_data() -{ - QTest::addColumn("lines"); - QTest::newRow("null") << int16_t(0); - QTest::addColumn("lines"); - QTest::newRow("100") << int16_t(100); -} - -// public void scrollByLines(int16_t lines) -void tst_LLEmbeddedBrowserWindow::scrollByLines() -{ - QFETCH(int16_t, lines); - - SubLLEmbeddedBrowserWindow window; - - window.scrollByLines(lines); -} - -Q_DECLARE_METATYPE(uint8_t) -void tst_LLEmbeddedBrowserWindow::setBackgroundColor_data() -{ - QTest::addColumn("red"); - QTest::addColumn("green"); - QTest::addColumn("blue"); - QTest::newRow("black") << uint8_t(0) << uint8_t(0) << uint8_t(0); - QTest::newRow("red") << uint8_t(255) << uint8_t(0) << uint8_t(0); - QTest::newRow("green") << uint8_t(0) << uint8_t(255) << uint8_t(0); - QTest::newRow("blue") << uint8_t(0) << uint8_t(0) << uint8_t(255); -} - -// public void setBackgroundColor(uint8_t const red, uint8_t const green, uint8_t const blue) -void tst_LLEmbeddedBrowserWindow::setBackgroundColor() -{ - QFETCH(uint8_t, red); - QFETCH(uint8_t, green); - QFETCH(uint8_t, blue); - - SubLLEmbeddedBrowserWindow window; - - window.setBackgroundColor(red, green, blue); -} - -void tst_LLEmbeddedBrowserWindow::setCaretColor_data() -{ - QTest::addColumn("red"); - QTest::addColumn("green"); - QTest::addColumn("blue"); - QTest::newRow("black") << uint8_t(0) << uint8_t(0) << uint8_t(0); - QTest::newRow("red") << uint8_t(255) << uint8_t(0) << uint8_t(0); - QTest::newRow("green") << uint8_t(0) << uint8_t(255) << uint8_t(0); - QTest::newRow("blue") << uint8_t(0) << uint8_t(0) << uint8_t(255); -} - -// public void setCaretColor(uint8_t const red, uint8_t const green, uint8_t const blue) -void tst_LLEmbeddedBrowserWindow::setCaretColor() -{ - QFETCH(uint8_t, red); - QFETCH(uint8_t, green); - QFETCH(uint8_t, blue); - - SubLLEmbeddedBrowserWindow window; - - window.setCaretColor(red, green, blue); -} - -void tst_LLEmbeddedBrowserWindow::setEnabled_data() -{ - QTest::addColumn("enabledIn"); - QTest::newRow("true") << true; - QTest::newRow("false") << false; -} - -// public void setEnabled(bool enabledIn) -void tst_LLEmbeddedBrowserWindow::setEnabled() -{ - QFETCH(bool, enabledIn); - - SubLLEmbeddedBrowserWindow window; - - window.setEnabled(enabledIn); -} - -void tst_LLEmbeddedBrowserWindow::setNoFollowScheme_data() -{ - QTest::addColumn("scheme"); - QTest::addColumn("result"); - QTest::newRow("null") << std::string() << std::string(); - QTest::newRow("valid") << std::string("ftp://www.google.com") << std::string("ftp");; -} - -// public void setNoFollowScheme(std::string scheme) -void tst_LLEmbeddedBrowserWindow::setNoFollowScheme() -{ - QFETCH(std::string, scheme); - QFETCH(std::string, result); - - SubLLEmbeddedBrowserWindow window; - - window.setNoFollowScheme(scheme); - QCOMPARE(window.getNoFollowScheme(), result); -} - -void tst_LLEmbeddedBrowserWindow::setParent_data() -{ -#if 0 - QTest::addColumn("parentCount"); - QTest::newRow("0") << 0; - QTest::newRow("-1") << -1; -#endif -} - -// public void setParent(LLEmbeddedBrowser* parent) -void tst_LLEmbeddedBrowserWindow::setParent() -{ -#if 0 - QFETCH(int, parentCount); - - SubLLEmbeddedBrowserWindow window; - LLEmbeddedBrowser* parent = new LLEmbeddedBrowser(); - - window.setParent(parent); -#endif - QSKIP("Has been tested before.", SkipAll); -} - -void tst_LLEmbeddedBrowserWindow::setSize_data() -{ - QTest::addColumn("width"); - QTest::addColumn("height"); - QTest::addColumn("setSize"); - QTest::newRow("null") << int16_t(0) << int16_t(0) << true; - QTest::newRow("valid") << int16_t(100) << int16_t(200) << true; -} - -// public bool setSize(int16_t width, int16_t height) -void tst_LLEmbeddedBrowserWindow::setSize() -{ - QFETCH(int16_t, width); - QFETCH(int16_t, height); - QFETCH(bool, setSize); - - SubLLEmbeddedBrowserWindow window; - QCOMPARE(window.setSize(width, height), setSize); - window.grabWindow(0, 0, 800, 600); - - QCOMPARE(window.getBrowserWidth(), width); - QCOMPARE(window.getBrowserHeight(), height); - QCOMPARE(window.getBrowserRowSpan(), (int32_t)width * 4); -} - -void tst_LLEmbeddedBrowserWindow::setWindowId_data() -{ - QTest::addColumn("window_id"); - QTest::newRow("0") << 0; - QTest::newRow("-1") << -1; - QTest::newRow("100") << 100; -} - -// public void setWindowId(int window_id) -void tst_LLEmbeddedBrowserWindow::setWindowId() -{ - QFETCH(int, window_id); - - SubLLEmbeddedBrowserWindow window; - - window.setWindowId(window_id); - QCOMPARE(window.getWindowId(), window_id); -} - -Q_DECLARE_METATYPE(uint32_t) -void tst_LLEmbeddedBrowserWindow::unicodeInput_data() -{ - QTest::addColumn("unicode_char"); - QTest::newRow("null") << uint32_t(); - QTest::newRow("valid") << uint32_t(54); -} - -// public void unicodeInput(uint32_t unicode_char) -void tst_LLEmbeddedBrowserWindow::unicodeInput() -{ - QFETCH(uint32_t, unicode_char); - - SubLLEmbeddedBrowserWindow window; - - window.unicodeInput(unicode_char); -} - -QTEST_MAIN(tst_LLEmbeddedBrowserWindow) -#include "tst_llembeddedbrowserwindow.moc" - diff --git a/indra/llqtwebkit/llembeddedbrowser.cpp b/indra/llqtwebkit/llembeddedbrowser.cpp deleted file mode 100644 index f38019b9b6..0000000000 --- a/indra/llqtwebkit/llembeddedbrowser.cpp +++ /dev/null @@ -1,759 +0,0 @@ -/* Copyright (c) 2006-2010, Linden Research, Inc. - * - * LLQtWebKit Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in GPL-license.txt in this distribution, or online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - */ - -#include "llembeddedbrowser.h" - -#include "llembeddedbrowser_p.h" -#include "llembeddedbrowserwindow.h" -#include "llnetworkaccessmanager.h" -#include "llstyle.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// singleton pattern - initialization -LLEmbeddedBrowser* LLEmbeddedBrowser::sInstance = 0; - -LLEmbeddedBrowserPrivate::LLEmbeddedBrowserPrivate() - : mErrorNum(0) - , mNativeWindowHandle(0) - , mNetworkAccessManager(0) - , mApplication(0) -#if QT_VERSION >= 0x040500 - , mDiskCache(0) -#endif - , mNetworkCookieJar(0) - , mHostLanguage( "en" ) - , mIgnoreSSLCertErrors(false) -{ - if (!qApp) - { - static int argc = 0; - static const char* argv[] = {""}; - QApplication::setAttribute(Qt::AA_MacPluginApplication); - QApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings); - - mApplication = new QApplication(argc, (char **)argv); - mApplication->addLibraryPath(qApp->applicationDirPath()); - } - qApp->setStyle(new LLStyle()); - mNetworkAccessManager = new LLNetworkAccessManager(this); -#if LL_DARWIN - // HACK: Qt installs CarbonEvent handlers that steal events from our main event loop. - // This uninstalls them. - // It's not clear whether calling this internal function is really a good idea. It's probably not. - // It does, however, seem to fix at least one problem ( https://jira.secondlife.com/browse/MOZ-12 ). - extern void qt_release_app_proc_handler(); - qt_release_app_proc_handler(); - - // This is defined and exported from qwidget_mac.mm. - // Calling it with false should prevent qwidget from bringing its process to the foreground, such as when bringing up a popup menu. - extern void qt_mac_set_raise_process(bool b); - qt_mac_set_raise_process(false); -#endif -} - -LLEmbeddedBrowserPrivate::~LLEmbeddedBrowserPrivate() -{ - delete mApplication; - delete mNetworkAccessManager; - delete mNetworkCookieJar; -} - - - -LLEmbeddedBrowser::LLEmbeddedBrowser() - : d(new LLEmbeddedBrowserPrivate) - , mPluginsEnabled( false ) - , mJavaScriptEnabled( false ) - , mCookiesEnabled( false ) -{ -} - -LLEmbeddedBrowser::~LLEmbeddedBrowser() -{ - if(d->mNetworkCookieJar) - { - d->mNetworkCookieJar->mBrowser = NULL; - } - - delete d; -} - -LLEmbeddedBrowser* LLEmbeddedBrowser::getInstance() -{ - if (!sInstance) - sInstance = new LLEmbeddedBrowser; - return sInstance; -} - -void LLEmbeddedBrowser::setLastError(int error_number) -{ - d->mErrorNum = error_number; -} - -void LLEmbeddedBrowser::clearLastError() -{ - d->mErrorNum = 0x0000; -} - -int LLEmbeddedBrowser::getLastError() -{ - return d->mErrorNum; -} - -std::string LLEmbeddedBrowser::getGREVersion() -{ - // take the string directly from Qt - return std::string(QT_VERSION_STR); -} - -bool LLEmbeddedBrowser::init(std::string application_directory, - std::string component_directory, - std::string profile_directory, - void* native_window_handle) -{ - Q_UNUSED(application_directory); - Q_UNUSED(component_directory); - Q_UNUSED(native_window_handle); - d->mStorageDirectory = QString::fromStdString(profile_directory); - QWebSettings::setIconDatabasePath(d->mStorageDirectory); - // The gif and jpeg libraries should be installed in component_directory/imageformats/ - QCoreApplication::addLibraryPath(QString::fromStdString(component_directory)); - - // turn on plugins by default - enablePlugins( true ); - - // Until QtWebkit defaults to 16 - QWebSettings::globalSettings()->setFontSize(QWebSettings::DefaultFontSize, 16); - QWebSettings::globalSettings()->setFontSize(QWebSettings::DefaultFixedFontSize, 16); - - - QWebSettings::globalSettings()->setAttribute(QWebSettings::OfflineStorageDatabaseEnabled, true); - QWebSettings::globalSettings()->setOfflineStoragePath(QDesktopServices::storageLocation(QDesktopServices::DataLocation)); - - // use default text encoding - not sure how this helps right now so commenting out until we - // understand how to use it a little better. - //QWebSettings::globalSettings()->setDefaultTextEncoding ( "" ); - - return reset(); -} - -bool LLEmbeddedBrowser::reset() -{ - foreach(LLEmbeddedBrowserWindow *window, d->windows) - delete window; - d->windows.clear(); - delete d->mNetworkAccessManager; - d->mNetworkAccessManager = new LLNetworkAccessManager(d); -#if QT_VERSION >= 0x040500 - d->mDiskCache = new QNetworkDiskCache(d->mNetworkAccessManager); - d->mDiskCache->setCacheDirectory(d->mStorageDirectory + "/cache"); - if (QLatin1String(qVersion()) != QLatin1String("4.5.1")) - d->mNetworkAccessManager->setCache(d->mDiskCache); -#endif - d->mNetworkCookieJar = new LLNetworkCookieJar(d->mNetworkAccessManager, this); - d->mNetworkAccessManager->setCookieJar(d->mNetworkCookieJar); - clearLastError(); - return true; -} - -bool LLEmbeddedBrowser::clearCache() -{ -#if QT_VERSION >= 0x040500 - if (d->mDiskCache) - { - d->mDiskCache->clear(); - return true; - } -#endif - return false; -} - -bool LLEmbeddedBrowser::enableProxy(bool enabled, std::string host_name, int port) -{ - QNetworkProxy proxy; - if (enabled) - { - proxy.setType(QNetworkProxy::HttpProxy); - QString q_host_name = QString::fromStdString(host_name); - proxy.setHostName(q_host_name); - proxy.setPort(port); - } - d->mNetworkAccessManager->setProxy(proxy); - return true; -} - -bool LLEmbeddedBrowser::clearAllCookies() -{ - if (!d->mNetworkCookieJar) - return false; - d->mNetworkCookieJar->clear(); - return true; -} - -void LLEmbeddedBrowser::setCookies(const std::string &cookies) -{ - if (d->mNetworkCookieJar) - { - d->mNetworkCookieJar->setCookiesFromRawForm(cookies); - } -} - -std::string LLEmbeddedBrowser::getAllCookies() -{ - std::string result; - - if (d->mNetworkCookieJar) - { - result = d->mNetworkCookieJar->getAllCookiesInRawForm(); - } - - return result; -} - -void LLEmbeddedBrowser::enableCookies( bool enabled ) -{ - mCookiesEnabled = enabled; - enableCookiesTransient( mCookiesEnabled ); -} - -void LLEmbeddedBrowser::enableCookiesTransient( bool enabled ) -{ - if ( d->mNetworkCookieJar ) - { - d->mNetworkCookieJar->mAllowCookies = enabled; - } -} - -bool LLEmbeddedBrowser::areCookiesEnabled() -{ - return mCookiesEnabled; -} - -void LLEmbeddedBrowser::enablePlugins( bool enabled ) -{ - mPluginsEnabled = enabled; // record state - enablePluginsTransient( mPluginsEnabled ); -} - -void LLEmbeddedBrowser::enablePluginsTransient( bool enabled ) -{ - QWebSettings* default_settings = QWebSettings::globalSettings(); - default_settings->setAttribute( QWebSettings::PluginsEnabled, enabled ); -} - -bool LLEmbeddedBrowser::arePluginsEnabled() -{ - return mPluginsEnabled; -} - -void LLEmbeddedBrowser::enableJavaScript( bool enabled ) -{ - mJavaScriptEnabled = enabled; // record state - enableJavaScriptTransient( mJavaScriptEnabled ); -} - -void LLEmbeddedBrowser::enableJavaScriptTransient( bool enabled ) -{ - QWebSettings* default_settings = QWebSettings::globalSettings(); - default_settings->setAttribute( QWebSettings::JavascriptEnabled, enabled ); - default_settings->setAttribute( QWebSettings::JavascriptCanOpenWindows, enabled ); -} - -bool LLEmbeddedBrowser::isJavaScriptEnabled() -{ - return mJavaScriptEnabled; -} - -bool LLEmbeddedBrowser::showWebInspector(bool show) -{ - QWebSettings::globalSettings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, show); - foreach (LLEmbeddedBrowserWindow* window, d->windows) - { - window->showWebInspector(show); - } - return true; -} - -/* - Sets a string that should be addded to the user agent to identify the application -*/ -void LLEmbeddedBrowser::setBrowserAgentId(std::string id) -{ - QCoreApplication::setApplicationName(QString::fromStdString(id)); -} - -// updates value of 'hostLanguage' in JavaScript 'Navigator' obect that -// embedded pages can query to see what language the host app is set to -// IMPORTANT: call this before any windows are created - only gets passed -// to LLWebPage when new window is created -void LLEmbeddedBrowser::setHostLanguage( const std::string& host_language ) -{ - d->mHostLanguage = host_language; -} - -LLEmbeddedBrowserWindow* LLEmbeddedBrowser::createBrowserWindow(int width, int height, const std::string target) -{ - LLEmbeddedBrowserWindow *newWin = new LLEmbeddedBrowserWindow(); - if (newWin) - { - newWin->setSize(width, height); - newWin->setParent(this); - newWin->setHostLanguage(d->mHostLanguage); - clearLastError(); - d->windows.append(newWin); - - if(!target.empty() && (target != "_blank")) - { - newWin->setTarget(target); - } - - return newWin; - } - return 0; -} - -bool LLEmbeddedBrowser::destroyBrowserWindow(LLEmbeddedBrowserWindow* browser_window) -{ - // check if exists in windows list - if (d->windows.removeOne(browser_window)) - { - delete browser_window; - clearLastError(); - return true; - } - return false; -} - -int LLEmbeddedBrowser::getWindowCount() const -{ - return d->windows.size(); -} - -void LLEmbeddedBrowser::pump(int max_milliseconds) -{ -#if 0 - // This USED to be necessary on the mac, but with Qt 4.6 it seems to cause trouble loading some pages, - // and using processEvents() seems to work properly now. - // Leaving this here in case these issues ever come back. - - // On the Mac, calling processEvents hangs the viewer. - // I'm not entirely sure this does everything we need, but it seems to work better, and allows things like animated gifs to work. - qApp->sendPostedEvents(); - qApp->sendPostedEvents(0, QEvent::DeferredDelete); -#else - qApp->processEvents(QEventLoop::AllEvents, max_milliseconds); -#endif -} - -void LLEmbeddedBrowser::cookieChanged(const std::string &cookie, const std::string &url, bool dead) -{ - foreach (LLEmbeddedBrowserWindow* window, d->windows) - { - window->cookieChanged(cookie, url, dead); - } -} - -//////////////////////////////////////////////////////////////////////////////// -// -bool LLEmbeddedBrowser::setCAFile(const std::string &ca_file) -{ - bool result = false; - //qDebug() << "LLEmbeddedBrowser::" << __FUNCTION__ << "attempting to read certs from file: " << QString::fromStdString(ca_file); - - // Extract the list of certificates from the specified file - QList certs = QSslCertificate::fromPath(QString::fromStdString(ca_file)); - - if(!certs.isEmpty()) - { - //qDebug() << "LLEmbeddedBrowser::" << __FUNCTION__ << "certs read: " << certs; - - // Set the default CA cert for Qt's SSL implementation. - QSslConfiguration config = QSslConfiguration::defaultConfiguration(); - config.setCaCertificates(certs); - QSslConfiguration::setDefaultConfiguration(config); - result = true; - } - - return result; -} - -//////////////////////////////////////////////////////////////////////////////// -// -bool LLEmbeddedBrowser::addCAFile(const std::string &ca_file) -{ - // Enabling this can help diagnose certificate verification issues. - const bool cert_debugging_on = false; - - if ( cert_debugging_on ) - { - //qDebug() << "\n\nLLEmbeddedBrowser::" << __FUNCTION__ << " ------------------- (Before add)"; - QSslCertificate cert; - foreach(cert, QSslSocket::defaultCaCertificates()) - { - //qDebug() << cert.issuerInfo(QSslCertificate::CommonName) << " --- " << cert.subjectInfo(QSslCertificate::CommonName); - } - } - - bool result = false; - //qDebug() << "LLEmbeddedBrowser::" << __FUNCTION__ << "attempting to read certs from file: " << QString::fromStdString(ca_file); - - if ( cert_debugging_on ) - { - //qDebug() << "\n\nLLEmbeddedBrowser::" << __FUNCTION__ << " ------------------- (From CA.pem)"; - QList certs = QSslCertificate::fromPath(QString::fromStdString(ca_file)); - QSslCertificate cert; - foreach(cert, certs) - { - //qDebug() << cert.issuerInfo(QSslCertificate::CommonName) << " --- " << cert.subjectInfo(QSslCertificate::CommonName); - } - } - - result = QSslSocket::addDefaultCaCertificates(QString::fromStdString(ca_file)); - - if ( cert_debugging_on ) - { - //qDebug() << "\n\nLLEmbeddedBrowser::" << __FUNCTION__ << " ------------------- (After add)"; - QSslCertificate cert; - foreach(cert, QSslSocket::defaultCaCertificates()) - { - //qDebug() << cert.issuerInfo(QSslCertificate::CommonName) << " --- " << cert.subjectInfo(QSslCertificate::CommonName); - } - } - - return result; -} - -void LLEmbeddedBrowser::setIgnoreSSLCertErrors(bool ignore) -{ - d->mIgnoreSSLCertErrors = ignore; -} - -bool LLEmbeddedBrowser::getIgnoreSSLCertErrors() -{ - return d->mIgnoreSSLCertErrors; -} - -const std::vector< std::string > LLEmbeddedBrowser::getInstalledCertsList() -{ - std::vector< std::string > cert_list; - - QSslCertificate cert; - foreach(cert, QSslSocket::defaultCaCertificates()) - { - QString cert_info=""; - - QString issuer_info=""; - issuer_info+="C="; - issuer_info+=cert.issuerInfo(QSslCertificate::CountryName); - issuer_info+=", ST="; - issuer_info+=cert.issuerInfo(QSslCertificate::StateOrProvinceName); - issuer_info+=", L="; - issuer_info+=cert.issuerInfo(QSslCertificate::LocalityName); - issuer_info+=", O="; - issuer_info+=cert.issuerInfo(QSslCertificate::Organization); - issuer_info+=", OU="; - issuer_info+=cert.issuerInfo(QSslCertificate::OrganizationalUnitName); - issuer_info+=", CN="; - issuer_info+=cert.issuerInfo(QSslCertificate::CommonName); - cert_info+=issuer_info; - cert_info+="\n"; - - QString subject_info=""; - subject_info+="C="; - subject_info+=cert.subjectInfo(QSslCertificate::CountryName); - subject_info+=", ST="; - subject_info+=cert.subjectInfo(QSslCertificate::StateOrProvinceName); - subject_info+=", L="; - subject_info+=cert.subjectInfo(QSslCertificate::LocalityName); - subject_info+=", O="; - subject_info+=cert.subjectInfo(QSslCertificate::Organization); - subject_info+=", OU="; - subject_info+=cert.subjectInfo(QSslCertificate::OrganizationalUnitName); - subject_info+=", CN="; - subject_info+=cert.subjectInfo(QSslCertificate::CommonName); - cert_info+=subject_info; - cert_info+="\n"; - - cert_info+="Not valid before: "; - cert_info+=cert.effectiveDate().toString(); - cert_info+="\n"; - cert_info+="Not valid after: "; - cert_info+=cert.expiryDate().toString(); - cert_info+="\n"; - - cert_list.push_back( llToStdString(cert_info) ); - } - return cert_list; -} - -// Second Life viewer specific functions -void LLEmbeddedBrowser::setSLObjectEnabled( bool enabled ) -{ - foreach ( LLEmbeddedBrowserWindow* window, d->windows ) - { - window->setSLObjectEnabled( enabled ); - } -} - -void LLEmbeddedBrowser::setAgentLanguage( const std::string& agent_language ) -{ - foreach ( LLEmbeddedBrowserWindow* window, d->windows ) - { - window->setAgentLanguage( agent_language ); - } -} - -void LLEmbeddedBrowser::setAgentRegion( const std::string& agent_region ) -{ - foreach ( LLEmbeddedBrowserWindow* window, d->windows ) - { - window->setAgentRegion( agent_region ); - } -} - -void LLEmbeddedBrowser::setAgentLocation( double x, double y, double z ) -{ - foreach ( LLEmbeddedBrowserWindow* window, d->windows ) - { - window->setAgentLocation( x, y, z ); - } -} - -void LLEmbeddedBrowser::setAgentGlobalLocation( double x, double y, double z ) -{ - foreach ( LLEmbeddedBrowserWindow* window, d->windows ) - { - window->setAgentGlobalLocation( x, y, z ); - } -} - -void LLEmbeddedBrowser::setAgentOrientation( double angle ) -{ - foreach ( LLEmbeddedBrowserWindow* window, d->windows ) - { - window->setAgentOrientation( angle ); - } -} - -void LLEmbeddedBrowser::setAgentMaturity( const std::string& agent_maturity ) -{ - foreach ( LLEmbeddedBrowserWindow* window, d->windows ) - { - window->setAgentMaturity( agent_maturity ); - } -} - -void LLEmbeddedBrowser::emitLocation() -{ - foreach ( LLEmbeddedBrowserWindow* window, d->windows ) - { - window->emitLocation(); - } -} - -void LLEmbeddedBrowser::emitMaturity() -{ - foreach ( LLEmbeddedBrowserWindow* window, d->windows ) - { - window->emitMaturity(); - } -} - -void LLEmbeddedBrowser::emitLanguage() -{ - foreach ( LLEmbeddedBrowserWindow* window, d->windows ) - { - window->emitLanguage(); - } -} - -void LLEmbeddedBrowser::setPageZoomFactor( double factor ) -{ - foreach ( LLEmbeddedBrowserWindow* window, d->windows ) - { - window->setPageZoomFactor( factor ); - } -} - -void LLEmbeddedBrowser::qtMessageHandler(QtMsgType type, const char *msg) -{ - std::string msg_type(""); - switch (type) - { - case QtDebugMsg: - msg_type="Debug"; - break; - case QtWarningMsg: - msg_type="Warning"; - break; - case QtCriticalMsg: - msg_type="Critical"; - break; - case QtFatalMsg: - msg_type="Fatal"; - break; - }; - - foreach ( LLEmbeddedBrowserWindow* window, sInstance->d->windows ) - { - - window->onQtDebugMessage( std::string( msg ), msg_type); - } -} - -void LLEmbeddedBrowser::enableQtMessageHandler( bool enable ) -{ - if ( enable ) - { - qInstallMsgHandler( qtMessageHandler ); - } - else - { - // remove handler - qInstallMsgHandler(0); - }; -} - -LLNetworkCookieJar::LLNetworkCookieJar(QObject* parent, LLEmbeddedBrowser *browser) - : NetworkCookieJar(parent) - , mAllowCookies(true) - , mBrowser(browser) -{ -} - -LLNetworkCookieJar::~LLNetworkCookieJar() -{ -} - -QList LLNetworkCookieJar::cookiesForUrl(const QUrl& url) const -{ - if (!mAllowCookies) - return QList(); - return NetworkCookieJar::cookiesForUrl(url); -} - -bool LLNetworkCookieJar::setCookiesFromUrl(const QList &cookie_list, const QUrl& url) -{ - if (!mAllowCookies) - return false; - return NetworkCookieJar::setCookiesFromUrl(cookie_list, url); -} - -void LLNetworkCookieJar::onCookieSetFromURL(const QNetworkCookie &cookie, const QUrl &url, bool already_dead) -{ -// qDebug() << "LLNetworkCookieJar::" << __FUNCTION__ << (already_dead?"set dead cookie":"set cookie ") << cookie; - - if(mBrowser) - { - QByteArray cookie_bytes = cookie.toRawForm(QNetworkCookie::Full); - std::string cookie_string(cookie_bytes.data(), cookie_bytes.size()); - std::string url_string = llToStdString(url); - mBrowser->cookieChanged(cookie_string, url_string, already_dead); - } -} - -void LLNetworkCookieJar::clear() -{ - clearCookies(); -} - -void LLNetworkCookieJar::setCookiesFromRawForm(const std::string &cookie_string) -{ - QByteArray cookie_bytearray(cookie_string.data(), cookie_string.size()); - QList cookie_list = QNetworkCookie::parseCookies(cookie_bytearray); - setCookies(cookie_list); -} - -std::string LLNetworkCookieJar::getAllCookiesInRawForm() -{ - std::string result; - - QList cookie_list = allCookies(); - - foreach (const QNetworkCookie &cookie, cookie_list) - { - QByteArray raw_form = cookie.toRawForm(QNetworkCookie::Full); - result.append(raw_form.data(), raw_form.size()); - result.append("\n"); - } - - return result; -} - -#include "llembeddedbrowserwindow_p.h" -#include - -QGraphicsWebView *LLEmbeddedBrowserPrivate::findView(QNetworkReply *reply) -{ - for (int i = 0; i < windows.count(); ++i) - if (windows[i]->d->mView->url() == reply->url()) - return windows[i]->d->mView; - return windows[0]->d->mView; -} - -bool LLEmbeddedBrowserPrivate::authRequest(const std::string &in_url, const std::string &in_realm, std::string &out_username, std::string &out_password) -{ - bool result = false; - -// qDebug() << "LLEmbeddedBrowser::" << __FUNCTION__ << "requesting auth for url " << QString::fromStdString(in_url) << ", realm " << QString::fromStdString(in_realm); -// -// qDebug() << "LLEmbeddedBrowser::" << __FUNCTION__ << "window count is " << windows.count(); - - if(windows.count() > 1) - { - qDebug() << "LLEmbeddedBrowser::" << __FUNCTION__ << "WARNING: authRequest called with more than one window, using the first one"; - } - - LLEmbeddedBrowserWindow* window = windows.first(); - - if(window) - { - result = window->authRequest(in_url, in_realm, out_username, out_password); - } - - return result; -} - -bool LLEmbeddedBrowserPrivate::certError(const std::string &in_url, const std::string &in_msg) -{ - bool result = false; - - LLEmbeddedBrowserWindow* window = windows.first(); - if(window) - { - result = window->certError(in_url, in_msg); - } - - return result; -} diff --git a/indra/llqtwebkit/llembeddedbrowser.h b/indra/llqtwebkit/llembeddedbrowser.h deleted file mode 100644 index c21a6b063d..0000000000 --- a/indra/llqtwebkit/llembeddedbrowser.h +++ /dev/null @@ -1,115 +0,0 @@ -/* Copyright (c) 2006-2010, Linden Research, Inc. - * - * LLQtWebKit Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in GPL-license.txt in this distribution, or online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - */ - -#ifndef LLEMBEDDEDBROWSER_H -#define LLEMBEDDEDBROWSER_H - -#include -#include -#include -#include - -class LLEmbeddedBrowserWindow; -class LLEmbeddedBrowserWindowObserver; - -class LLEmbeddedBrowserPrivate; -class LLEmbeddedBrowser -{ - public: - LLEmbeddedBrowser(); - virtual ~LLEmbeddedBrowser(); - - static LLEmbeddedBrowser* getInstance(); - - bool init(std::string application_directory, - std::string component_directory, - std::string profile_directory, - void* native_window_handle); - bool reset(); - bool clearCache(); - bool enableProxy(bool enabled, std::string host_name, int port); - bool clearAllCookies(); - void setCookies(const std::string &cookies); - std::string getAllCookies(); - - void enableCookies( bool enabled ); - void enableCookiesTransient( bool enabled ); - bool areCookiesEnabled(); - void enablePlugins( bool enabled ); - void enablePluginsTransient( bool enabled ); - bool arePluginsEnabled(); - void enableJavaScript( bool enabled ); - void enableJavaScriptTransient( bool enabled ); - bool isJavaScriptEnabled(); - - bool showWebInspector(bool show); - std::string getGREVersion(); - void setBrowserAgentId(std::string id); - void setHostLanguage( const std::string& host_language ); - LLEmbeddedBrowserWindow* createBrowserWindow(int width, int height, const std::string target); - bool destroyBrowserWindow(LLEmbeddedBrowserWindow* browser_window); - void setLastError(int error_number); - void clearLastError(); - int getLastError(); - int getWindowCount() const; - void pump(int max_milliseconds); - void cookieChanged(const std::string &cookie, const std::string &url, bool dead); - bool setCAFile(const std::string &ca_file); - bool addCAFile(const std::string &ca_file); - void setIgnoreSSLCertErrors(bool ignore); - bool getIgnoreSSLCertErrors(); - const std::vector< std::string > getInstalledCertsList(); - - void enableQtMessageHandler( bool enable ); - - void setPageZoomFactor( double factor ); - - // Second Life specific functions - void setSLObjectEnabled( bool enabled ); - void setAgentLanguage( const std::string& agent_language ); - void setAgentRegion( const std::string& agent_region ); - void setAgentLocation( double x, double y, double z ); - void setAgentGlobalLocation( double x, double y, double z ); - void setAgentOrientation( double angle ); - void setAgentMaturity( const std::string& agent_maturity ); - void emitLocation(); - void emitMaturity(); - void emitLanguage(); - - private: - friend class LLEmbeddedBrowserWindow; - friend class LLEmbeddedBrowserWindowPrivate; - LLEmbeddedBrowserPrivate *d; - bool mPluginsEnabled; - bool mJavaScriptEnabled; - bool mCookiesEnabled; - - static void qtMessageHandler(QtMsgType type, const char *msg); - - static LLEmbeddedBrowser* sInstance; -}; - -#endif // LLEMBEDDEDBROWSER_H - diff --git a/indra/llqtwebkit/llembeddedbrowser_p.h b/indra/llqtwebkit/llembeddedbrowser_p.h deleted file mode 100644 index 9f9f9cd027..0000000000 --- a/indra/llqtwebkit/llembeddedbrowser_p.h +++ /dev/null @@ -1,90 +0,0 @@ -/* Copyright (c) 2006-2010, Linden Research, Inc. - * - * LLQtWebKit Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in GPL-license.txt in this distribution, or online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - */ - -#ifndef LLEMBEDDEDBROWSER_P_H -#define LLEMBEDDEDBROWSER_P_H - -#include -#include -#if QT_VERSION >= 0x040500 -#include -#endif - -#include "networkcookiejar.h" -#include "llembeddedbrowser.h" - -#include - -class LLEmbeddedBrowser; -class LLNetworkCookieJar : public NetworkCookieJar -{ -public: - LLNetworkCookieJar(QObject *parent, LLEmbeddedBrowser *browser); - ~LLNetworkCookieJar(); - - QList cookiesForUrl(const QUrl& url) const; - bool setCookiesFromUrl(const QList &cookie_list, const QUrl& url); - - /*virtual*/ void onCookieSetFromURL(const QNetworkCookie &cookie, const QUrl &url, bool already_dead); - - void clear(); - - void setCookiesFromRawForm(const std::string &cookie_string); - std::string getAllCookiesInRawForm(); - - bool mAllowCookies; - LLEmbeddedBrowser *mBrowser; -}; - -class LLNetworkAccessManager; -class LLEmbeddedBrowserPrivate -{ -public: - LLEmbeddedBrowserPrivate(); - ~LLEmbeddedBrowserPrivate(); - - bool authRequest(const std::string &in_url, const std::string &in_realm, std::string &out_username, std::string &out_password); - bool certError(const std::string &in_url, const std::string &in_msg); - - int mErrorNum; - void* mNativeWindowHandle; - LLNetworkAccessManager *mNetworkAccessManager; - QApplication *mApplication; -#if QT_VERSION >= 0x040500 - QNetworkDiskCache *mDiskCache; -#endif - LLNetworkCookieJar *mNetworkCookieJar; - - QGraphicsWebView *findView(QNetworkReply *); - - QString mStorageDirectory; - QList windows; - - std::string mHostLanguage; - bool mIgnoreSSLCertErrors; -}; - -#endif - diff --git a/indra/llqtwebkit/llembeddedbrowserwindow.cpp b/indra/llqtwebkit/llembeddedbrowserwindow.cpp deleted file mode 100644 index c990d5567c..0000000000 --- a/indra/llqtwebkit/llembeddedbrowserwindow.cpp +++ /dev/null @@ -1,1136 +0,0 @@ -/* Copyright (c) 2006-2010, Linden Research, Inc. - * - * LLQtWebKit Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in GPL-license.txt in this distribution, or online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - */ - -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "llembeddedbrowserwindow.h" -#include "llembeddedbrowserwindow_p.h" - -#include "llembeddedbrowser.h" -#include "llembeddedbrowser_p.h" -#include "llnetworkaccessmanager.h" - -#ifdef STATIC_QT - #include - // Enable gif and jpeg plugins, since web pages look pretty bleak without gifs or jpegs. - // Qt 4.7 uses the system gif and jpeg libraries by default, so this is no longer necessary. -// Q_IMPORT_PLUGIN(qgif) -// Q_IMPORT_PLUGIN(qjpeg) -#ifndef LL_LINUX - // Qt also has its own translators for CJK text encodings we need to pull in. - Q_IMPORT_PLUGIN(qcncodecs) - Q_IMPORT_PLUGIN(qjpcodecs) - Q_IMPORT_PLUGIN(qkrcodecs) - Q_IMPORT_PLUGIN(qtwcodecs) -#endif -#endif - -//#define LLEMBEDDEDBROWSER_DEBUG 1 - -#ifdef LLEMBEDDEDBROWSER_DEBUG -#include -#endif - -#if LL_DARWIN || defined(STATIC_QT) - // Don't define qt_sendSpontaneousEvent on the mac -- it causes a multiply-defined symbol. - extern bool qt_sendSpontaneousEvent(QObject *receiver, QEvent *event); -#else - #include - bool qt_sendSpontaneousEvent(QObject *receiver, QEvent *event) - { - return QCoreApplication::sendSpontaneousEvent(receiver, event); - } -#endif - -LLEmbeddedBrowserWindow::LLEmbeddedBrowserWindow() -{ - d = new LLEmbeddedBrowserWindowPrivate(); - - d->mPage = new LLWebPage; - d->mInspector = new QWebInspector; - d->mInspector->setPage(d->mPage); - d->mPage->window = this; - d->mView = new LLWebView; - d->mPage->webView = d->mView; - d->mView->window = this; - d->mView->setPage(d->mPage); - d->mGraphicsScene = new LLGraphicsScene; - d->mGraphicsScene->window = this; - d->mGraphicsView = new QGraphicsView; - d->mGraphicsScene->addItem(d->mView); - d->mGraphicsView->setScene(d->mGraphicsScene); - d->mGraphicsScene->setStickyFocus(true); - d->mGraphicsView->viewport()->setParent(0); - - mEnableLoadingOverlay = false; -} - -LLEmbeddedBrowserWindow::~LLEmbeddedBrowserWindow() -{ - delete d; -} - -void LLEmbeddedBrowserWindow::setParent(LLEmbeddedBrowser* parent) -{ -#ifdef LLEMBEDDEDBROWSER_DEBUG - qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << parent; -#endif - d->mParent = parent; - if (parent) - { - d->mPage->setNetworkAccessManager(parent->d->mNetworkAccessManager); - } else - { - d->mPage->setNetworkAccessManager(0); - } -} - -void LLEmbeddedBrowserWindow::showWebInspector(bool show) -{ - if ( d ) - { - if ( d->mInspector ) - { - d->mInspector->setVisible( show ); - } - } -} - -void LLEmbeddedBrowserWindow::enableLoadingOverlay(bool enable) -{ - mEnableLoadingOverlay = enable; -} - -// change the background color that gets used between pages (usually white) -void LLEmbeddedBrowserWindow::setBackgroundColor(const uint8_t red, const uint8_t green, const uint8_t blue) -{ -#ifdef LLEMBEDDEDBROWSER_DEBUG - qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << red << green << blue; -#endif - d->backgroundColor = QColor(red, green, blue); -} - -// -void LLEmbeddedBrowserWindow::setEnabled(bool enabled) -{ -#ifdef LLEMBEDDEDBROWSER_DEBUG - qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << enabled; -#endif - d->mEnabled = enabled; -} - -// allow consumers of this class to observe events - add themselves as an observer -bool LLEmbeddedBrowserWindow::addObserver(LLEmbeddedBrowserWindowObserver* observer) -{ -#ifdef LLEMBEDDEDBROWSER_DEBUG - qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << observer; -#endif - return d->mEventEmitter.addObserver(observer); -} - -// allow consumers of this class to observe events - remove themselves as an observer -bool LLEmbeddedBrowserWindow::remObserver(LLEmbeddedBrowserWindowObserver* observer) -{ -#ifdef LLEMBEDDEDBROWSER_DEBUG - qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << observer; -#endif - return d->mEventEmitter.remObserver(observer); -} - -int LLEmbeddedBrowserWindow::getObserverNumber() -{ - return d->mEventEmitter.getObserverNumber(); -} - -// used by observers of this class to get the current URI -std::string& LLEmbeddedBrowserWindow::getCurrentUri() -{ - d->mCurrentUri = llToStdString(d->mPage->mainFrame()->url()); - return d->mCurrentUri; -} - -// utility method that is used by observers to retrieve data after an event -int16_t LLEmbeddedBrowserWindow::getPercentComplete() -{ -#ifdef LLEMBEDDEDBROWSER_DEBUG - qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__; -#endif - return d->mPercentComplete; -} - -// utility method that is used by observers to retrieve data after an event -std::string& LLEmbeddedBrowserWindow::getStatusMsg() -{ -#ifdef LLEMBEDDEDBROWSER_DEBUG - qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__; -#endif - return d->mStatusText; -} - -// render a page into memory and grab the window -unsigned char* LLEmbeddedBrowserWindow::grabWindow(int x, int y, int width, int height) -{ -#if LLEMBEDDEDBROWSER_DEBUG > 10 - qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << x << y << width << height; -#endif - // only grab the window if it's enabled - if (!d->mEnabled) - return 0; - - if (!d->mDirty) - return d->mPageBuffer; - - Q_ASSERT(d->mImage.size() == d->mView->size()); - if (!d->mPage->mainFrame()->url().isValid()) - { - d->mImage.fill(d->backgroundColor.value()); - } else - { - QPainter painter(&d->mImage); - - QRectF r(x, y, width, height); - QRect g(0, 0, d->mView->width(), d->mView->height()); - d->mGraphicsView->render(&painter, r, g); - - d->mDirty = false; - - const bool spinner_enabled = false; - if ( spinner_enabled ) - { - const time_t seconds_before_show_overlay = 1; - - if ( mEnableLoadingOverlay && - d->mShowLoadingOverlay && - time(NULL) - d->mTimeLoadStarted >= seconds_before_show_overlay ) - { - painter.setRenderHint(QPainter::Antialiasing);; - - QBrush brush; - QPen pen; - - int size = width; - if ( height < width ) - size = height; - - const int symbol_translucency = 64; // 0=fully trans, 255=opaque - const int symbol_proportion_of_sceen = 8; // (1/8) - const int symbol_diameter = size/(symbol_proportion_of_sceen); - const int symbol_start_line = symbol_diameter*2/3; - const int symbol_end_line = symbol_diameter; - const int symbol_num_segments = 20; - const int symbol_line_width = size/60; - if ( size < 4 ) size = 4; - - QColor background_color(QColor(128,128,128,symbol_translucency)); - brush.setColor(background_color); - brush.setStyle(Qt::SolidPattern); - pen.setColor(background_color); - painter.setPen(pen); - painter.setBrush(brush); - painter.drawRect(0,0,width, height); - - painter.translate(QPoint(width/2, height/2)); - - static int offset=0; - painter.rotate(((qreal)(offset++%(symbol_num_segments))/(qreal)symbol_num_segments)*360.0f); - - for ( int count=0; countmDirty = true; // force dirty so updates happen frequently during load - } - } - - painter.end(); - if (d->mFlipBitmap) - { - d->mImage = d->mImage.mirrored(); - } - d->mImage = d->mImage.rgbSwapped(); - } - - d->mPageBuffer = d->mImage.bits(); - - return d->mPageBuffer; -} - -// return the buffer that contains the rendered page -unsigned char* LLEmbeddedBrowserWindow::getPageBuffer() -{ -#ifdef LLEMBEDDEDBROWSER_DEBUG - qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__; -#endif - return d->mPageBuffer; -} - -int16_t LLEmbeddedBrowserWindow::getBrowserWidth() -{ -#if LLEMBEDDEDBROWSER_DEBUG > 10 - qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__; -#endif - return d->mImage.width(); -} - -int16_t LLEmbeddedBrowserWindow::getBrowserHeight() -{ -#if LLEMBEDDEDBROWSER_DEBUG > 10 - qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__; -#endif - return d->mImage.height(); -} - -int16_t LLEmbeddedBrowserWindow::getBrowserDepth() -{ -#if LLEMBEDDEDBROWSER_DEBUG > 10 - qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__; -#endif - return 4; -} - -int32_t LLEmbeddedBrowserWindow::getBrowserRowSpan() -{ -#if LLEMBEDDEDBROWSER_DEBUG > 10 - qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__; -#endif - return 4 * getBrowserWidth(); -} - -bool LLEmbeddedBrowserWindow::navigateTo(const std::string uri) -{ -#ifdef LLEMBEDDEDBROWSER_DEBUG - qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << QString::fromStdString(uri); -#endif - QUrl url = QUrl::fromUserInput(QString::fromStdString(uri)); - - d->mPage->triggerAction(QWebPage::Stop); - d->mPage->mainFrame()->setUrl(url); - d->mPage->mainFrame()->load(url); - return true; -} - -bool LLEmbeddedBrowserWindow::userAction(LLQtWebKit::EUserAction action) -{ -#ifdef LLEMBEDDEDBROWSER_DEBUG - qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << action; -#endif - bool result = true; - - switch(action) - { - case LLQtWebKit::UA_EDIT_CUT: - d->mPage->triggerAction(QWebPage::Cut); - break; - case LLQtWebKit::UA_EDIT_COPY: - d->mPage->triggerAction(QWebPage::Copy); - break; - case LLQtWebKit::UA_EDIT_PASTE: - d->mPage->triggerAction(QWebPage::Paste); - break; - case LLQtWebKit::UA_NAVIGATE_STOP: - d->mPage->triggerAction(QWebPage::Stop); - break; - case LLQtWebKit::UA_NAVIGATE_BACK: - d->mPage->triggerAction(QWebPage::Back); - break; - case LLQtWebKit::UA_NAVIGATE_FORWARD: - d->mPage->triggerAction(QWebPage::Forward); - break; - case LLQtWebKit::UA_NAVIGATE_RELOAD: - d->mPage->triggerAction(QWebPage::ReloadAndBypassCache); - break; - default: - result = false; - break; - } - - return result; -} - -bool LLEmbeddedBrowserWindow::userActionIsEnabled(LLQtWebKit::EUserAction action) -{ -#if LLEMBEDDEDBROWSER_DEBUG > 10 - qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << action; -#endif - - bool result; - - switch(action) - { - case LLQtWebKit::UA_EDIT_CUT: - result = d->mPage->action(QWebPage::Cut)->isEnabled(); - break; - case LLQtWebKit::UA_EDIT_COPY: - result = d->mPage->action(QWebPage::Copy)->isEnabled(); - break; - case LLQtWebKit::UA_EDIT_PASTE: - result = d->mPage->action(QWebPage::Paste)->isEnabled(); - break; - case LLQtWebKit::UA_NAVIGATE_STOP: - result = true; - break; - case LLQtWebKit::UA_NAVIGATE_BACK: - result = d->mPage->history()->canGoBack(); - break; - case LLQtWebKit::UA_NAVIGATE_FORWARD: - result = d->mPage->history()->canGoForward(); - break; - case LLQtWebKit::UA_NAVIGATE_RELOAD: - result = true; - break; - default: - result = false; - break; - } - return result; -} - -// set the size of the browser window -bool LLEmbeddedBrowserWindow::setSize(int16_t width, int16_t height) -{ -#ifdef LLEMBEDDEDBROWSER_DEBUG - qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << width << height; -#endif - d->mPageBuffer = NULL; - d->mImage = QImage(QSize(width, height), QImage::Format_RGB32); - d->mGraphicsView->resize(width, height); - d->mView->resize(width, height); - d->mImage.fill(d->backgroundColor.rgb()); - return true; -} - -bool LLEmbeddedBrowserWindow::flipWindow(bool flip) -{ -#ifdef LLEMBEDDEDBROWSER_DEBUG - qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << flip; -#endif - d->mFlipBitmap = flip; - return true; -} - -static Qt::KeyboardModifiers convert_modifiers(LLQtWebKit::EKeyboardModifier modifiers) -{ - Qt::KeyboardModifiers result = Qt::NoModifier; - - if(modifiers & LLQtWebKit::KM_MODIFIER_SHIFT) - result |= Qt::ShiftModifier; - - if(modifiers & LLQtWebKit::KM_MODIFIER_CONTROL) - result |= Qt::ControlModifier; - - if(modifiers & LLQtWebKit::KM_MODIFIER_ALT) - result |= Qt::AltModifier; - - if(modifiers & LLQtWebKit::KM_MODIFIER_META) - result |= Qt::MetaModifier; - - return result; -} - -static Qt::MouseButton qt_button_from_button_number(int button) -{ - Qt::MouseButton result; - - switch(button) - { - default: result = Qt::NoButton; break; - case 0: result = Qt::LeftButton; break; - case 1: result = Qt::RightButton; break; - case 2: result = Qt::MidButton; break; - case 3: result = Qt::XButton1; break; - case 4: result = Qt::XButton2; break; - } - - return result; -} - -static QEvent::Type event_from_mouse_event(LLQtWebKit::EMouseEvent mouse_event) -{ - QEvent::Type result; - - switch(mouse_event) - { - default: - result = QEvent::None; - break; - - case LLQtWebKit::ME_MOUSE_MOVE: - result = QEvent::MouseMove; - break; - - case LLQtWebKit::ME_MOUSE_DOWN: - result = QEvent::MouseButtonPress; - break; - - case LLQtWebKit::ME_MOUSE_UP: - result = QEvent::MouseButtonRelease; - break; - - case LLQtWebKit::ME_MOUSE_DOUBLE_CLICK: - result = QEvent::MouseButtonDblClick; - break; - } - - return result; -} - -static QEvent::Type event_from_keyboard_event(LLQtWebKit::EKeyEvent keyboard_event) -{ - QEvent::Type result; - - switch(keyboard_event) - { - default: - result = QEvent::None; - break; - - case LLQtWebKit::KE_KEY_DOWN: - case LLQtWebKit::KE_KEY_REPEAT: - result = QEvent::KeyPress; - break; - - case LLQtWebKit::KE_KEY_UP: - result = QEvent::KeyRelease; - break; - } - - return result; -} - -void LLEmbeddedBrowserWindow::mouseEvent(LLQtWebKit::EMouseEvent mouse_event, int16_t button, int16_t x, int16_t y, LLQtWebKit::EKeyboardModifier modifiers) -{ -#if LLEMBEDDEDBROWSER_DEBUG > 10 - qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << x << y; -#endif - - QEvent::Type type = event_from_mouse_event(mouse_event); - Qt::MouseButton qt_button = qt_button_from_button_number(button); - Qt::KeyboardModifiers qt_modifiers = convert_modifiers(modifiers); - - if(type == QEvent::MouseMove) - { - // Mouse move events should always use "no button". - qt_button = Qt::NoButton; - } - - // FIXME: should the current button state be updated before or after constructing the event? - switch(type) - { - case QEvent::MouseButtonPress: - case QEvent::MouseButtonDblClick: - d->mCurrentMouseButtonState |= qt_button; - break; - - case QEvent::MouseButtonRelease: - d->mCurrentMouseButtonState &= ~qt_button; - break; - - default: - break; - } - - QMouseEvent event(type, QPoint(x, y), qt_button, d->mCurrentMouseButtonState, qt_modifiers); - - qt_sendSpontaneousEvent(d->mGraphicsView->viewport(), &event); -} - -void LLEmbeddedBrowserWindow::scrollWheelEvent(int16_t x, int16_t y, int16_t scroll_x, int16_t scroll_y, LLQtWebKit::EKeyboardModifier modifiers) -{ -#ifdef LLEMBEDDEDBROWSER_DEBUG - qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << x << y; -#endif - - Qt::KeyboardModifiers qt_modifiers = convert_modifiers(modifiers); - - if(scroll_y != 0) - { - QWheelEvent event(QPoint(x, y), scroll_y, d->mCurrentMouseButtonState, qt_modifiers, Qt::Vertical); - qApp->sendEvent(d->mGraphicsView->viewport(), &event); - } - - if(scroll_x != 0) - { - QWheelEvent event(QPoint(x, y), scroll_x, d->mCurrentMouseButtonState, qt_modifiers, Qt::Horizontal); - qApp->sendEvent(d->mGraphicsView->viewport(), &event); - } -} - - -// utility methods to set an error message so something else can look at it -void LLEmbeddedBrowserWindow::scrollByLines(int16_t lines) -{ -#ifdef LLEMBEDDEDBROWSER_DEBUG - qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << lines; -#endif - int currentScrollValue = d->mPage->mainFrame()->scrollBarValue(Qt::Vertical); - d->mPage->mainFrame()->setScrollBarValue(Qt::Vertical, currentScrollValue + lines); -} - -// Send a keyboard event with native event data. -void LLEmbeddedBrowserWindow::keyboardEvent( - LLQtWebKit::EKeyEvent key_event, - uint32_t key_code, - const char *utf8_text, - LLQtWebKit::EKeyboardModifier modifiers, - uint32_t native_scan_code, - uint32_t native_virtual_key, - uint32_t native_modifiers) -{ - QEvent::Type type = event_from_keyboard_event(key_event); - Qt::KeyboardModifiers qt_modifiers = convert_modifiers(modifiers); - bool auto_repeat = (key_event == LLQtWebKit::KE_KEY_REPEAT); - QString text = QString::fromUtf8(utf8_text); - - Qt::Key key = Qt::Key_unknown; - - switch (key_code) - { - case LLQtWebKit::KEY_RETURN: key = Qt::Key_Return; break; - case LLQtWebKit::KEY_LEFT: key = Qt::Key_Left; break; - case LLQtWebKit::KEY_RIGHT: key = Qt::Key_Right; break; - case LLQtWebKit::KEY_UP: key = Qt::Key_Up; break; - case LLQtWebKit::KEY_DOWN: key = Qt::Key_Down; break; - case LLQtWebKit::KEY_ESCAPE: key = Qt::Key_Escape; break; - case LLQtWebKit::KEY_BACKSPACE: key = Qt::Key_Backspace; break; - case LLQtWebKit::KEY_DELETE: key = Qt::Key_Delete; break; - case LLQtWebKit::KEY_SHIFT: key = Qt::Key_Shift; break; - case LLQtWebKit::KEY_CONTROL: key = Qt::Key_Control; break; - case LLQtWebKit::KEY_ALT: key = Qt::Key_Alt; break; - case LLQtWebKit::KEY_HOME: key = Qt::Key_Home; break; - case LLQtWebKit::KEY_END: key = Qt::Key_End; break; - case LLQtWebKit::KEY_PAGE_UP: key = Qt::Key_PageUp; break; - case LLQtWebKit::KEY_PAGE_DOWN: key = Qt::Key_PageDown; break; - case LLQtWebKit::KEY_HYPHEN: key = Qt::Key_hyphen; break; - case LLQtWebKit::KEY_EQUALS: key = Qt::Key_Equal; break; - case LLQtWebKit::KEY_INSERT: key = Qt::Key_Insert; break; - case LLQtWebKit::KEY_CAPSLOCK: key = Qt::Key_CapsLock; break; - case LLQtWebKit::KEY_TAB: key = Qt::Key_Tab; break; - case LLQtWebKit::KEY_ADD: key = Qt::Key_Plus; break; - case LLQtWebKit::KEY_SUBTRACT: key = Qt::Key_Minus; break; - case LLQtWebKit::KEY_MULTIPLY: key = Qt::Key_Asterisk; break; - case LLQtWebKit::KEY_DIVIDE: key = Qt::Key_Slash; break; - case LLQtWebKit::KEY_F1: key = Qt::Key_F1; break; - case LLQtWebKit::KEY_F2: key = Qt::Key_F2; break; - case LLQtWebKit::KEY_F3: key = Qt::Key_F3; break; - case LLQtWebKit::KEY_F4: key = Qt::Key_F4; break; - case LLQtWebKit::KEY_F5: key = Qt::Key_F5; break; - case LLQtWebKit::KEY_F6: key = Qt::Key_F6; break; - case LLQtWebKit::KEY_F7: key = Qt::Key_F7; break; - case LLQtWebKit::KEY_F8: key = Qt::Key_F8; break; - case LLQtWebKit::KEY_F9: key = Qt::Key_F9; break; - case LLQtWebKit::KEY_F10: key = Qt::Key_F10; break; - case LLQtWebKit::KEY_F11: key = Qt::Key_F11; break; - case LLQtWebKit::KEY_F12: key = Qt::Key_F12; break; - - case LLQtWebKit::KEY_PAD_UP: key = Qt::Key_Up; qt_modifiers |= Qt::KeypadModifier; break; - case LLQtWebKit::KEY_PAD_DOWN: key = Qt::Key_Down; qt_modifiers |= Qt::KeypadModifier; break; - case LLQtWebKit::KEY_PAD_LEFT: key = Qt::Key_Left; qt_modifiers |= Qt::KeypadModifier; break; - case LLQtWebKit::KEY_PAD_RIGHT: key = Qt::Key_Right; qt_modifiers |= Qt::KeypadModifier; break; - case LLQtWebKit::KEY_PAD_HOME: key = Qt::Key_Home; qt_modifiers |= Qt::KeypadModifier; break; - case LLQtWebKit::KEY_PAD_END: key = Qt::Key_End; qt_modifiers |= Qt::KeypadModifier; break; - case LLQtWebKit::KEY_PAD_PGUP: key = Qt::Key_PageUp; qt_modifiers |= Qt::KeypadModifier; break; - case LLQtWebKit::KEY_PAD_PGDN: key = Qt::Key_PageDown; qt_modifiers |= Qt::KeypadModifier; break; - case LLQtWebKit::KEY_PAD_CENTER: key = Qt::Key_5; qt_modifiers |= Qt::KeypadModifier; break; - case LLQtWebKit::KEY_PAD_INS: key = Qt::Key_Insert; qt_modifiers |= Qt::KeypadModifier; break; - case LLQtWebKit::KEY_PAD_DEL: key = Qt::Key_Delete; qt_modifiers |= Qt::KeypadModifier; break; - case LLQtWebKit::KEY_PAD_RETURN: key = Qt::Key_Enter; qt_modifiers |= Qt::KeypadModifier; break; - case LLQtWebKit::KEY_PAD_ADD: key = Qt::Key_Plus; qt_modifiers |= Qt::KeypadModifier; break; - case LLQtWebKit::KEY_PAD_SUBTRACT: key = Qt::Key_Minus; qt_modifiers |= Qt::KeypadModifier; break; - case LLQtWebKit::KEY_PAD_MULTIPLY: key = Qt::Key_Asterisk; qt_modifiers |= Qt::KeypadModifier; break; - case LLQtWebKit::KEY_PAD_DIVIDE: key = Qt::Key_Slash; qt_modifiers |= Qt::KeypadModifier; break; - - case LLQtWebKit::KEY_NONE: key = Qt::Key_unknown; break; - - default: - key = (Qt::Key)toupper(key_code); - break; - } - - - QKeyEvent *event = - QKeyEvent::createExtendedKeyEvent( - type, - key, - qt_modifiers, - native_scan_code, - native_virtual_key, - native_modifiers, - text, - auto_repeat, - text.count()); - - qApp->sendEvent(d->mGraphicsScene, event); - - delete event; -} - - -// give focus to the browser so that input keyboard events work -void LLEmbeddedBrowserWindow::focusBrowser(bool focus_browser) -{ -#ifdef LLEMBEDDEDBROWSER_DEBUG - qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << focus_browser; -#endif - QEvent ev(QEvent::WindowActivate); - qApp->sendEvent(d->mGraphicsScene, &ev); - - QEvent ev2(QEvent::ActivationChange); - qApp->sendEvent(d->mGraphicsScene, &ev2); - - QFocusEvent event(focus_browser ? QEvent::FocusIn : QEvent::FocusOut, Qt::ActiveWindowFocusReason); - qApp->sendEvent(d->mPage, &event); -} - -void LLEmbeddedBrowserWindow::setWindowId(int window_id) -{ -#ifdef LLEMBEDDEDBROWSER_DEBUG - qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << window_id; -#endif - d->mWindowId = window_id; -} - -int LLEmbeddedBrowserWindow::getWindowId() -{ - return d->mWindowId; -} - -void LLEmbeddedBrowserWindow::proxyWindowOpened(const std::string target, const std::string uuid) -{ - LLWebPageOpenShim *shim = findShim(uuid); - if(!shim) - { - // We don't already have a shim with this uuid -- create one. - shim = new LLWebPageOpenShim(this, d->mPage); - d->mProxyPages.push_back(shim); - -#ifdef LLEMBEDDEDBROWSER_DEBUG - qDebug() << "LLEmbeddedBrowserWindow::proxyWindowOpened: page list size is " << d->mProxyPages.size(); -#endif - } - - shim->setProxy(target, uuid); -} - -void LLEmbeddedBrowserWindow::proxyWindowClosed(const std::string uuid) -{ - LLWebPageOpenShim *shim = findShim(uuid); - if(shim) - { - deleteShim(shim); - } -} - -std::string LLEmbeddedBrowserWindow::evaluateJavaScript(std::string script) -{ -#ifdef LLEMBEDDEDBROWSER_DEBUG - qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << QString::fromStdString(script); -#endif - QString q_script = QString::fromStdString(script); - QString result = d->mPage->mainFrame()->evaluateJavaScript(q_script).toString(); - return llToStdString(result); -} - -void LLEmbeddedBrowserWindow::setHostLanguage(const std::string host_language) -{ -#ifdef LLEMBEDDEDBROWSER_DEBUG - qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << QString::fromStdString(host_language); -#endif - if ( d ) - if ( d->mPage ) - d->mPage->setHostLanguage( host_language ); -} - -void LLEmbeddedBrowserWindow::navigateErrorPage( int http_status_code ) -{ - LLEmbeddedBrowserWindowEvent event(getWindowId()); - event.setIntValue( http_status_code ); - - d->mEventEmitter.update(&LLEmbeddedBrowserWindowObserver::onNavigateErrorPage, event); -} - -void LLEmbeddedBrowserWindow::setNoFollowScheme(std::string scheme) -{ -#ifdef LLEMBEDDEDBROWSER_DEBUG - qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__ << QString::fromStdString(scheme); -#endif - d->mNoFollowScheme = QString::fromStdString(scheme); - // The scheme part of the url is what is before '://' - d->mNoFollowScheme = d->mNoFollowScheme.mid(0, d->mNoFollowScheme.indexOf("://")); -} - -std::string LLEmbeddedBrowserWindow::getNoFollowScheme() -{ -#ifdef LLEMBEDDEDBROWSER_DEBUG - qDebug() << "LLEmbeddedBrowserWindow" << __FUNCTION__; -#endif - return llToStdString(d->mNoFollowScheme); -} - -void LLEmbeddedBrowserWindow::prependHistoryUrl(std::string url) -{ -#ifdef WEBHISTORYPATCH - // *HACK: we only have a URL here, we set a "" title and "current time" as - // last visited time. - d->mPage->history()->prependItem(QString::fromStdString(url), - QString::fromAscii(""), - QDateTime::currentDateTime()); -#else - Q_UNUSED(url); -#endif -} - -void LLEmbeddedBrowserWindow::clearHistory() -{ - d->mPage->history()->clear(); -} - -std::string LLEmbeddedBrowserWindow::dumpHistory() -{ - std::ostringstream oss; - const QList &items = d->mPage->history()->backItems(9999); - oss << "cur: " << d->mPage->history()->currentItemIndex() << ":" - << d->mPage->history()->currentItem().url().toString().toAscii().data() << "\n"; - for (int i=0; i< items.count(); i++) { - oss << items[i].url().toString().toAscii().data() << "\n"; - } - return oss.str(); -} - -void LLEmbeddedBrowserWindow::cookieChanged(const std::string &cookie, const std::string &url, bool dead) -{ - LLEmbeddedBrowserWindowEvent event(getWindowId()); - event.setEventUri(url); - event.setStringValue(cookie); - event.setIntValue((int)dead); - - d->mEventEmitter.update(&LLEmbeddedBrowserWindowObserver::onCookieChanged, event); -} - -QWebPage *LLEmbeddedBrowserWindow::createWindow() -{ - QWebPage *result = NULL; - if(d->mOpeningSelf) - { - // Special case: opening self to set target, etc. -#ifdef LLEMBEDDEDBROWSER_DEBUG - qDebug() << "LLEmbeddedBrowserWindow::createWindow: opening self to set target name. "; -#endif - result = d->mPage; - d->mOpeningSelf = false; - } - else - { - LLWebPageOpenShim *shim = new LLWebPageOpenShim(this, d->mPage); - d->mProxyPages.push_back(shim); - result = shim; - -#ifdef LLEMBEDDEDBROWSER_DEBUG - qDebug() << "LLEmbeddedBrowserWindow::createWindow: page list size is " << d->mProxyPages.size(); -#endif - } - - return result; -} - -LLWebPageOpenShim *LLEmbeddedBrowserWindow::findShim(const std::string &uuid) -{ - LLEmbeddedBrowserWindowPrivate::ProxyList::iterator iter; - for(iter = d->mProxyPages.begin(); iter != d->mProxyPages.end(); iter++) - { - if((*iter)->matchesUUID(uuid)) - return *iter; - } - - return NULL; -} - -void LLEmbeddedBrowserWindow::deleteShim(LLWebPageOpenShim *shim) -{ - shim->window = 0; - shim->deleteLater(); - d->mProxyPages.remove(shim); - -#ifdef LLEMBEDDEDBROWSER_DEBUG - qDebug() << "LLEmbeddedBrowserWindow::deleteShim: page list size is " << d->mProxyPages.size(); -#endif -} - -void LLEmbeddedBrowserWindow::setTarget(const std::string &target) -{ -#ifdef LLEMBEDDEDBROWSER_DEBUG - qDebug() << "LLEmbeddedBrowserWindow::setTarget: setting target to " << QString::fromStdString(target); -#endif - - d->mOpeningSelf = true; - - std::stringstream s; - s << "window.open(\"\",\"" << target << "\");"; - - evaluateJavaScript(s.str()); -} - -std::string LLEmbeddedBrowserWindow::requestFilePicker() -{ - std::string filename_chosen; - - LLEmbeddedBrowserWindowEvent event(getWindowId()); - event.setEventUri(getCurrentUri()); - event.setStringValue("*.png;*.jpg"); - - // If there's at least one observer registered, call it with the event. - LLEmbeddedBrowserWindowPrivate::Emitter::iterator i = d->mEventEmitter.begin(); - if(i != d->mEventEmitter.end()) - { - filename_chosen = (*i)->onRequestFilePicker(event); - } - - return filename_chosen; -} - -bool LLEmbeddedBrowserWindow::authRequest(const std::string &in_url, const std::string &in_realm, std::string &out_username, std::string &out_password) -{ - bool result = false; - -#ifdef LLEMBEDDEDBROWSER_DEBUG - qDebug() << "LLEmbeddedBrowserWindow::authRequest: requesting auth for url " << QString::fromStdString(in_url) << ", realm " << QString::fromStdString(in_realm); -#endif - - // If there's at least one observer registered, send it the auth request. - LLEmbeddedBrowserWindowPrivate::Emitter::iterator i = d->mEventEmitter.begin(); - if(i != d->mEventEmitter.end()) - { - result = (*i)->onAuthRequest(in_url, in_realm, out_username, out_password); - } - - return result; -} - -bool LLEmbeddedBrowserWindow::certError(const std::string &in_url, const std::string &in_msg) -{ - bool result = false; - - // If there's at least one observer registered, send it the auth request. - LLEmbeddedBrowserWindowPrivate::Emitter::iterator i = d->mEventEmitter.begin(); - if(i != d->mEventEmitter.end()) - { - result = (*i)->onCertError(in_url, in_msg); - } - - return result; -} - -void LLEmbeddedBrowserWindow::onQtDebugMessage( const std::string& msg, const std::string& msg_type) -{ - // If there's at least one observer registered, send it the auth request. - LLEmbeddedBrowserWindowPrivate::Emitter::iterator i = d->mEventEmitter.begin(); - if(i != d->mEventEmitter.end()) - { - (*i)->onQtDebugMessage(msg, msg_type); - } -} - -void LLEmbeddedBrowserWindow::setWhiteListRegex( const std::string& regex ) -{ - if ( d ) - if ( d->mPage ) - d->mPage->setWhiteListRegex( regex ); -} - -// Second Life viewer specific functions -void LLEmbeddedBrowserWindow::setSLObjectEnabled( bool enabled ) -{ - if ( d ) - if ( d->mPage ) - d->mPage->setSLObjectEnabled( enabled ); -} - -void LLEmbeddedBrowserWindow::setAgentLanguage( const std::string& agent_language ) -{ - if ( d ) - if ( d->mPage ) - d->mPage->setAgentLanguage( agent_language ); -} - -void LLEmbeddedBrowserWindow::setAgentRegion( const std::string& agent_region ) -{ - if ( d ) - if ( d->mPage ) - d->mPage->setAgentRegion( agent_region ); -} - -void LLEmbeddedBrowserWindow::setAgentLocation( double x, double y, double z ) -{ - if ( d ) - if ( d->mPage ) - d->mPage->setAgentLocation( x, y, z ); -} - -void LLEmbeddedBrowserWindow::setAgentGlobalLocation( double x, double y, double z ) -{ - if ( d ) - if ( d->mPage ) - d->mPage->setAgentGlobalLocation( x, y, z ); -} - -void LLEmbeddedBrowserWindow::setAgentOrientation( double angle ) -{ - if ( d ) - if ( d->mPage ) - d->mPage->setAgentOrientation( angle ); -} - -void LLEmbeddedBrowserWindow::setAgentMaturity( const std::string& agent_maturity ) -{ - if ( d ) - if ( d->mPage ) - d->mPage->setAgentMaturity( agent_maturity ); -} - -void LLEmbeddedBrowserWindow::emitLocation() -{ - if ( d ) - if ( d->mPage ) - d->mPage->emitLocation(); -} - -void LLEmbeddedBrowserWindow::emitMaturity() -{ - if ( d ) - if ( d->mPage ) - d->mPage->emitMaturity(); -} - -void LLEmbeddedBrowserWindow::emitLanguage() -{ - if ( d ) - if ( d->mPage ) - d->mPage->emitLanguage(); -} - -void LLEmbeddedBrowserWindow::setPageZoomFactor( double factor ) -{ - if ( d ) - if ( d->mPage ) - d->mPage->setPageZoomFactor( factor ); -} - -LLGraphicsScene::LLGraphicsScene() - : QGraphicsScene() - , window(0) -{ - connect(this, SIGNAL(changed(const QList &)), - this, SLOT(repaintRequestedSlot(const QList &))); -} - -void LLGraphicsScene::repaintRequestedSlot(const QList ®ions) -{ - if (!window) - return; - window->d->mDirty = true; - for (int i = 0; i < regions.count(); ++i) - { - LLEmbeddedBrowserWindowEvent event(window->getWindowId()); - event.setEventUri(window->getCurrentUri()); - event.setRectValue(regions[i].x(), regions[i].y(), regions[i].width(), regions[i].height()); - - window->d->mEventEmitter.update(&LLEmbeddedBrowserWindowObserver::onPageChanged, event); - } -} - -#include -#include -LLWebView::LLWebView(QGraphicsItem *parent) - : QGraphicsWebView(parent) - , window(0) -{ -} - -bool LLWebView::event(QEvent* event) -{ - if (window && event->type() == QEvent::CursorChange) { - QCursor cursor = this->cursor(); - if (currentShape != cursor.shape()) { - currentShape = cursor.shape(); - LLQtWebKit::ECursor llcursor; - switch(currentShape) - { - case Qt::ArrowCursor: - llcursor = LLQtWebKit::C_ARROW; - break; - case Qt::PointingHandCursor: - llcursor = LLQtWebKit::C_POINTINGHAND; - break; - case Qt::IBeamCursor: - llcursor = LLQtWebKit::C_IBEAM; - break; - case Qt::SplitVCursor: - llcursor = LLQtWebKit::C_SPLITV; - break; - case Qt::SplitHCursor: - llcursor = LLQtWebKit::C_SPLITH; - break; - default: - qWarning() << "Unhandled cursor shape:" << currentShape; - llcursor = LLQtWebKit::C_ARROW; - } - - LLEmbeddedBrowserWindowEvent event(window->getWindowId()); - event.setEventUri(window->getCurrentUri()); - event.setIntValue((int)llcursor); - window->d->mEventEmitter.update(&LLEmbeddedBrowserWindowObserver::onCursorChanged, event); - } - - return true; - } - return QGraphicsWebView::event(event); -} - - -std::string llToStdString(const QString &s) -{ - return llToStdString(s.toUtf8()); -} - -std::string llToStdString(const QByteArray &bytes) -{ - return std::string(bytes.constData(), bytes.size()); -} - -std::string llToStdString(const QUrl &url) -{ - return llToStdString(url.toEncoded()); -} diff --git a/indra/llqtwebkit/llembeddedbrowserwindow.h b/indra/llqtwebkit/llembeddedbrowserwindow.h deleted file mode 100644 index 0c8080c15d..0000000000 --- a/indra/llqtwebkit/llembeddedbrowserwindow.h +++ /dev/null @@ -1,185 +0,0 @@ -/* Copyright (c) 2006-2010, Linden Research, Inc. - * - * LLQtWebKit Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in GPL-license.txt in this distribution, or online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - */ - -#ifndef LLEMBEDDEDBROWSERWINDOW_H -#define LLEMBEDDEDBROWSERWINDOW_H - -#include -#include -#include -#if defined _MSC_VER && _MSC_VER < 1600 -#include "pstdint.h" -#else -#include // Use the C99 official header -#endif - -#include "llqtwebkit.h" - -class LLEmbeddedBrowser; -class LLWebPageOpenShim; -class QWebPage; - -//////////////////////////////////////////////////////////////////////////////// -// class for a "window" that holds a browser - there can be lots of these -class LLEmbeddedBrowserWindowPrivate; -class LLEmbeddedBrowserWindow -{ -public: - LLEmbeddedBrowserWindow(); - virtual ~LLEmbeddedBrowserWindow(); - - // housekeeping - void setParent(LLEmbeddedBrowser* parent); - bool setSize(int16_t width, int16_t height); - void focusBrowser(bool focus_browser); - void scrollByLines(int16_t lines); - void setWindowId(int window_id); - int getWindowId(); - void proxyWindowOpened(const std::string target, const std::string uuid); - void proxyWindowClosed(const std::string uuid); - - // random accessors - int16_t getPercentComplete(); - std::string& getStatusMsg(); - std::string& getCurrentUri(); - - // memory buffer management - unsigned char* grabWindow(int x, int y, int width, int height); - bool flipWindow(bool flip); - unsigned char* getPageBuffer(); - int16_t getBrowserWidth(); - int16_t getBrowserHeight(); - int16_t getBrowserDepth(); - int32_t getBrowserRowSpan(); - - // set background color that you see in between pages - default is white but sometimes useful to change - void setBackgroundColor(const uint8_t red, const uint8_t green, const uint8_t blue); - - // can turn off updates to a page - e.g. when it's hidden by your windowing system - void setEnabled(bool enabledIn); - - // navigation - bool userAction(LLQtWebKit::EUserAction action); - bool userActionIsEnabled(LLQtWebKit::EUserAction action); - bool navigateTo(const std::string uri); - - // javascript access/control - std::string evaluateJavaScript(std::string script); - - // redirection when you hit an error page - void navigateErrorPage( int http_status_code ); - - // host language setting - void setHostLanguage(const std::string host_language); - - // mouse & keyboard events - void mouseEvent(LLQtWebKit::EMouseEvent mouse_event, int16_t button, int16_t x, int16_t y, LLQtWebKit::EKeyboardModifier modifiers); - void scrollWheelEvent(int16_t x, int16_t y, int16_t scroll_x, int16_t scroll_y, LLQtWebKit::EKeyboardModifier modifiers); - void keyboardEvent( - LLQtWebKit::EKeyEvent key_event, - uint32_t key_code, - const char *utf8_text, - LLQtWebKit::EKeyboardModifier modifiers, - uint32_t native_scan_code, - uint32_t native_virtual_key, - uint32_t native_modifiers); - - // allow consumers of this class and to observe browser events - bool addObserver(LLEmbeddedBrowserWindowObserver* observer); - bool remObserver(LLEmbeddedBrowserWindowObserver* observer); - int getObserverNumber(); - - // accessor/mutator for scheme that browser doesn't follow - e.g. secondlife.com:// - void setNoFollowScheme(std::string scheme); - std::string getNoFollowScheme(); - - // prepend the current history with the given url - void prependHistoryUrl(std::string url); - // clear the URL history - void clearHistory(); - std::string dumpHistory(); - - void cookieChanged(const std::string &cookie, const std::string &url, bool dead); - - QWebPage *createWindow(); - - LLWebPageOpenShim *findShim(const std::string &uuid); - void deleteShim(LLWebPageOpenShim *shim); - void setTarget(const std::string &target); - - std::string requestFilePicker(); - - void showWebInspector(bool enabled); - - bool authRequest(const std::string &in_url, const std::string &in_realm, std::string &out_username, std::string &out_password); - bool certError(const std::string &in_url, const std::string &in_msg); - - void onQtDebugMessage( const std::string& msg, const std::string& msg_type); - - void enableLoadingOverlay(bool enable); - - void setWhiteListRegex( const std::string& regex ); - - void setPageZoomFactor( double factor ); - - // Second Life specific functions - void setSLObjectEnabled( bool enabled ); - void setAgentLanguage( const std::string& agent_language ); - void setAgentRegion( const std::string& agent_region ); - void setAgentLocation( double x, double y, double z ); - void setAgentGlobalLocation( double x, double y, double z ); - void setAgentOrientation( double angle ); - void setAgentMaturity( const std::string& agent_maturity ); - void emitLocation(); - void emitMaturity(); - void emitLanguage(); - -private: - friend class LLWebPage; - friend class LLWebPageOpenShim; - friend class LLGraphicsScene; - friend class LLWebView; - friend class LLEmbeddedBrowserPrivate; - LLEmbeddedBrowserWindowPrivate *d; - bool mEnableLoadingOverlay; - -}; - - -// QString::toStdString converts to ascii, not utf8. Define our own versions that do utf8. - -#ifdef QSTRING_H -std::string llToStdString(const QString &s); -#endif - -#ifdef QBYTEARRAY_H -std::string llToStdString(const QByteArray &bytes); -#endif - -#ifdef QURL_H -std::string llToStdString(const QUrl &url); -#endif - -#endif // LLEMBEDEDDBROWSERWINDOW_H diff --git a/indra/llqtwebkit/llembeddedbrowserwindow_p.h b/indra/llqtwebkit/llembeddedbrowserwindow_p.h deleted file mode 100644 index 27b36d9478..0000000000 --- a/indra/llqtwebkit/llembeddedbrowserwindow_p.h +++ /dev/null @@ -1,251 +0,0 @@ -/* Copyright (c) 2006-2010, Linden Research, Inc. - * - * LLQtWebKit Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in GPL-license.txt in this distribution, or online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - */ - -#ifndef LLEMBEDDEDBROWSERWINDOW_P_H -#define LLEMBEDDEDBROWSERWINDOW_P_H - -#include "llwebpage.h" -#include "llwebpageopenshim.h" - -#include -#include -#include -#include -#include - -/////////////////////////////////////////////////////////////////////////////// -// manages the process of storing and emitting events that the consumer -// of the embedding class can observe -template< class T > -class LLEmbeddedBrowserWindowEmitter -{ - public: - LLEmbeddedBrowserWindowEmitter() { }; - ~LLEmbeddedBrowserWindowEmitter() { }; - - typedef typename T::EventType EventType; - typedef std::list< T* > ObserverContainer; - typedef typename ObserverContainer::iterator iterator; - typedef void(T::*observerMethod)(const EventType&); - - /////////////////////////////////////////////////////////////////////////////// - // - bool addObserver(T* observer) - { - if (! observer) - return false; - - if (std::find(observers.begin(), observers.end(), observer) != observers.end()) - return false; - - observers.push_back(observer); - - return true; - } - - /////////////////////////////////////////////////////////////////////////////// - // - bool remObserver(T* observer) - { - if (! observer) - return false; - - observers.remove(observer); - - return true; - } - - /////////////////////////////////////////////////////////////////////////////// - // - void update(observerMethod method, const EventType& msg) - { - typename std::list< T* >::iterator iter = observers.begin(); - - while(iter != observers.end()) - { - ((*iter)->*method)(msg); - ++iter; - } - } - - int getObserverNumber() - { - return observers.size(); - } - - iterator begin() - { - return observers.begin(); - } - - iterator end() - { - return observers.end(); - } - - protected: - ObserverContainer observers; -}; - -#include "llqtwebkit.h" -#include "llembeddedbrowserwindow.h" -#include -#include - -class LLGraphicsScene : public QGraphicsScene -{ - Q_OBJECT - -public: - LLGraphicsScene(); - LLEmbeddedBrowserWindow *window; - - void mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent) { - QGraphicsScene::mouseMoveEvent(mouseEvent); - mouseEvent->setAccepted(true); - mouseEvent->setButtons(Qt::LeftButton); - } - -private slots: - void repaintRequestedSlot(const QList &); - friend class LLEmbeddedBrowserWindow; -}; - - -class LLWebView : public QGraphicsWebView -{ - Q_OBJECT - -public: - LLWebView(QGraphicsItem *parent = 0); - LLEmbeddedBrowserWindow *window; - - static QUrl guessUrlFromString(const QString &string); - - int width() const { return boundingRect().width(); } - int height() const { return boundingRect().height(); } - -protected: - bool event(QEvent *event); - - Qt::CursorShape currentShape; -}; - -class LLEmbeddedBrowserWindowPrivate -{ - public: - LLEmbeddedBrowserWindowPrivate() - : mParent(0) - , mPage(0) - , mView(0) - , mGraphicsScene(0) - , mGraphicsView(0) - , mInspector(0) - , mCurrentMouseButtonState(Qt::NoButton) - , mPercentComplete(0) - , mShowLoadingOverlay(false) - , mTimeLoadStarted(0) - , mStatusText("") - , mTitle("") - , mCurrentUri("") - , mNoFollowScheme("secondlife") - , mWindowId(-1) - , mEnabled(true) - , mFlipBitmap(false) - , mPageBuffer(NULL) - , mDirty(false) - , mOpeningSelf(false) - { - } - - ~LLEmbeddedBrowserWindowPrivate() - { - while(!mProxyPages.empty()) - { - ProxyList::iterator iter = mProxyPages.begin(); - (*iter)->window = 0; - (*iter)->deleteLater(); - } - - if(mGraphicsScene) - { - mGraphicsScene->window = 0; - } - if(mPage) - { - mPage->window = 0; - } - if(mView) - { - mView->deleteLater(); - } - if(mGraphicsScene) - { - mGraphicsScene->deleteLater(); - } - if(mGraphicsView) - { - mGraphicsView->viewport()->setParent(mGraphicsView); - mGraphicsView->deleteLater(); - } - if(mInspector) - { - mInspector->deleteLater(); - } - } - - typedef LLEmbeddedBrowserWindowEmitter< LLEmbeddedBrowserWindowObserver> Emitter; - Emitter mEventEmitter; - QImage mImage; - LLEmbeddedBrowser *mParent; - LLWebPage *mPage; - typedef std::list ProxyList; - ProxyList mProxyPages; - - LLWebView *mView; - QWebInspector* mInspector; - LLGraphicsScene *mGraphicsScene; - QGraphicsView *mGraphicsView; - Qt::MouseButtons mCurrentMouseButtonState; - - int16_t mPercentComplete; - bool mShowLoadingOverlay; - time_t mTimeLoadStarted; - std::string mStatusText; - std::string mTitle; - std::string mCurrentUri; - QString mNoFollowScheme; - int mWindowId; - bool mEnabled; - bool mFlipBitmap; - unsigned char* mPageBuffer; - QColor backgroundColor; - bool mDirty; - bool mOpeningSelf; -}; - - -#endif - diff --git a/indra/llqtwebkit/lljsobject.cpp b/indra/llqtwebkit/lljsobject.cpp deleted file mode 100644 index f5abfa7023..0000000000 --- a/indra/llqtwebkit/lljsobject.cpp +++ /dev/null @@ -1,153 +0,0 @@ -/* Copyright (c) 2006-2010, Linden Research, Inc. - * - * LLQtWebKit Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in GPL-license.txt in this distribution, or online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - */ - -#include -#include "lljsobject.h" - -LLJsObject::LLJsObject( QObject* parent ) : - QObject( parent ) -{ - mEnabled = false; - - mAgentLanguage = QString(); - mAgentMaturity = QString(); - mAgentRegion = QString(); - - mAgentLocation[ "x" ] = 0.0; - mAgentLocation[ "y" ] = 0.0; - mAgentLocation[ "z" ] = 0.0; - - mAgentGlobalLocation[ "x" ] = 0.0; - mAgentGlobalLocation[ "y" ] = 0.0; - mAgentGlobalLocation[ "z" ] = 0.0; -} - -void LLJsObject::setSLObjectEnabled( bool enabled ) -{ - mEnabled = enabled; -} - -bool LLJsObject::getSLObjectEnabled() -{ - return mEnabled; -} - -void LLJsObject::setAgentLanguage( const QString& agent_language ) -{ - if ( mEnabled ) - { - mAgentLanguage = agent_language; - } - else - { - mAgentLanguage = QString(); - } -} - -void LLJsObject::setAgentRegion( const QString& agent_region ) -{ - if ( mEnabled ) - { - mAgentRegion = agent_region; - } - else - { - mAgentRegion = QString(); - } -} - -void LLJsObject::setAgentMaturity( const QString& agent_maturity ) -{ - if ( mEnabled ) - { - mAgentMaturity = agent_maturity; - } - else - { - mAgentMaturity = QString(); - } -} - -void LLJsObject::setAgentLocation( const QVariantMap agent_location ) -{ - if ( mEnabled ) - { - mAgentLocation = agent_location; - } - else - { - mAgentLocation[ "x" ] = 0.0; - mAgentLocation[ "y" ] = 0.0; - mAgentLocation[ "z" ] = 0.0; - } -} - -void LLJsObject::setAgentGlobalLocation( const QVariantMap agent_global_location ) -{ - if ( mEnabled ) - { - mAgentGlobalLocation = agent_global_location; - } - else - { - mAgentGlobalLocation[ "x" ] = 0.0; - mAgentGlobalLocation[ "y" ] = 0.0; - mAgentGlobalLocation[ "z" ] = 0.0; - } -} - -void LLJsObject::setAgentOrientation( const double angle ) -{ - if ( mEnabled ) - { - mAgentOrientation = angle; - } - else - { - mAgentOrientation = 0.0; - } -} - -void LLJsObject::emitLocation() -{ - QVariantMap agent_location; - - agent_location[ "region" ] = mAgentRegion; - agent_location[ "location" ] = mAgentLocation; - agent_location[ "orientation" ] = mAgentOrientation; - agent_location[ "globalLocation" ] = mAgentGlobalLocation; - - emit getLocation( agent_location ); -} - -void LLJsObject::emitMaturity() -{ - emit getMaturity( mAgentMaturity ); -} - -void LLJsObject::emitLanguage() -{ - emit getLanguage( mAgentLanguage ); -} diff --git a/indra/llqtwebkit/lljsobject.h b/indra/llqtwebkit/lljsobject.h deleted file mode 100644 index 806a8a8a1b..0000000000 --- a/indra/llqtwebkit/lljsobject.h +++ /dev/null @@ -1,71 +0,0 @@ -/* Copyright (c) 2006-2010, Linden Research, Inc. - * - * LLQtWebKit Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in GPL-license.txt in this distribution, or online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - */ - -#ifndef LLJSOBJECT_H -#define LLJSOBJECT_H - -#include -#include -#include - -class LLJsObject : - public QObject -{ - Q_OBJECT - - public: - LLJsObject( QObject* parent = 0 ); - - void setSLObjectEnabled( bool enabled ); - bool getSLObjectEnabled(); - - void setAgentLanguage( const QString& agent_language ); - void setAgentRegion( const QString& agent_region ); - void setAgentMaturity( const QString& agent_maturity ); - void setAgentLocation( const QVariantMap agent_location ); - void setAgentGlobalLocation( const QVariantMap agent_global_location ); - void setAgentOrientation( const double angle ); - - void emitLocation(); - void emitMaturity(); - void emitLanguage(); - - signals: - void getLocation( const QVariantMap agent_location ); - void getMaturity( const QString agent_maturity ); - void getLanguage( const QString agent_language ); - - private: - bool mEnabled; - - QString mAgentLanguage; - QString mAgentMaturity; - QString mAgentRegion; - QVariantMap mAgentLocation; - QVariantMap mAgentGlobalLocation; - double mAgentOrientation; -}; - -#endif // LLJSOBJECT_H diff --git a/indra/llqtwebkit/llnetworkaccessmanager.cpp b/indra/llqtwebkit/llnetworkaccessmanager.cpp deleted file mode 100644 index 2a51f13400..0000000000 --- a/indra/llqtwebkit/llnetworkaccessmanager.cpp +++ /dev/null @@ -1,247 +0,0 @@ -/* Copyright (c) 2006-2010, Linden Research, Inc. - * - * LLQtWebKit Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in GPL-license.txt in this distribution, or online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - */ - -#include -#include "llnetworkaccessmanager.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "llembeddedbrowserwindow.h" -#include "llembeddedbrowser_p.h" - -#include "ui_passworddialog.h" - - -LLNetworkAccessManager::LLNetworkAccessManager(LLEmbeddedBrowserPrivate* browser,QObject* parent) - : QNetworkAccessManager(parent) - , mBrowser(browser) -{ - connect(this, SIGNAL(finished(QNetworkReply*)), - this, SLOT(finishLoading(QNetworkReply*))); - connect(this, SIGNAL(authenticationRequired(QNetworkReply*, QAuthenticator*)), - this, SLOT(authenticationRequiredSlot(QNetworkReply*, QAuthenticator*))); - connect(this, SIGNAL(sslErrors( QNetworkReply *, const QList &)), - this, SLOT(sslErrorsSlot( QNetworkReply *, const QList & ))); -} - -QNetworkReply *LLNetworkAccessManager::createRequest(Operation op, const QNetworkRequest &request, - QIODevice *outgoingData) -{ - - // Create a local copy of the request we can modify. - QNetworkRequest mutable_request(request); - - // Set an Accept-Language header in the request, based on what the host has set through setHostLanguage. - mutable_request.setRawHeader(QByteArray("Accept-Language"), QByteArray(mBrowser->mHostLanguage.c_str())); - - // this is undefine'd in 4.7.1 and leads to caching issues - setting it here explicitly - mutable_request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferNetwork); - - if(op == GetOperation) - { - // GET requests should not have a Content-Type header, but it seems somebody somewhere is adding one. - // This removes it. - mutable_request.setRawHeader("Content-Type", QByteArray()); - } - -// qDebug() << "headers for request:" << mutable_request.rawHeaderList(); - - // and pass this through to the parent implementation - return QNetworkAccessManager::createRequest(op, mutable_request, outgoingData); -} - -void LLNetworkAccessManager::sslErrorsSlot(QNetworkReply* reply, const QList& errors) -{ - // Enabling this can help diagnose certificate verification issues. - const bool ssl_debugging_on = false; - - // flag that indicates if the error that brought us here is one we care about or not - bool valid_ssl_error = false; - - foreach( const QSslError &error, errors ) - { - if ( ssl_debugging_on ) - { - qDebug() << "SSL error details are (" << (int)(error.error()) << ") - " << error.error(); - } - - // SSL "error" codes we don't care about - if we get one of these, we want to continue - if ( error.error() != QSslError::NoError - // many more in src/network/ssl/qsslerror.h - ) - { - if ( ssl_debugging_on ) - { - qDebug() << "Found valid SSL error - will not ignore"; - } - - valid_ssl_error = true; - } - else - { - if ( ssl_debugging_on ) - { - qDebug() << "Found invalid SSL error - will ignore and continue"; - } - } - } - - if ( ssl_debugging_on ) - { - qDebug() << "LLNetworkAccessManager" << __FUNCTION__ << "errors: " << errors - << ", peer certificate chain: "; - - QSslCertificate cert; - foreach(cert, reply->sslConfiguration().peerCertificateChain()) - { - qDebug() << " cert: " << cert - << ", issuer = " << cert.issuerInfo(QSslCertificate::CommonName) - << ", subject = " << cert.subjectInfo(QSslCertificate::CommonName); - } - } - - if ( valid_ssl_error ) - { - std::string url = llToStdString(reply->url()); - QString err_msg=""; - foreach( const QSslError &error, errors ) - { - err_msg+=error.errorString(); - err_msg+="\n"; - - QSslCertificate cert = error.certificate(); - - QString issuer_info=""; - issuer_info+="C="; - issuer_info+=cert.issuerInfo(QSslCertificate::CountryName); - issuer_info+=", ST="; - issuer_info+=cert.issuerInfo(QSslCertificate::StateOrProvinceName); - issuer_info+=", L="; - issuer_info+=cert.issuerInfo(QSslCertificate::LocalityName); - issuer_info+=", O="; - issuer_info+=cert.issuerInfo(QSslCertificate::Organization); - issuer_info+=", OU="; - issuer_info+=cert.issuerInfo(QSslCertificate::OrganizationalUnitName); - issuer_info+=", CN="; - issuer_info+=cert.issuerInfo(QSslCertificate::CommonName); - err_msg+=issuer_info; - err_msg+="\n"; - - QString subject_info=""; - subject_info+="C="; - subject_info+=cert.subjectInfo(QSslCertificate::CountryName); - subject_info+=", ST="; - subject_info+=cert.subjectInfo(QSslCertificate::StateOrProvinceName); - subject_info+=", L="; - subject_info+=cert.subjectInfo(QSslCertificate::LocalityName); - subject_info+=", O="; - subject_info+=cert.subjectInfo(QSslCertificate::Organization); - subject_info+=", OU="; - subject_info+=cert.subjectInfo(QSslCertificate::OrganizationalUnitName); - subject_info+=", CN="; - subject_info+=cert.subjectInfo(QSslCertificate::CommonName); - err_msg+=subject_info; - err_msg+="\n"; - - err_msg+="Not valid before: "; - err_msg+=cert.effectiveDate().toString(); - err_msg+="\n"; - err_msg+="Not valid after: "; - err_msg+=cert.expiryDate().toString(); - err_msg+="\n"; - err_msg+="----------\n"; - } - - if(mBrowser->certError(url, llToStdString(err_msg))) - { - // signal we should ignore and continue processing - reply->ignoreSslErrors(); - } - else - { - // The user canceled, don't return yet so we can test ignore variable - } - } - - // we the SSL error is invalid (in our opinion) or we explicitly ignore all SSL errors - if ( valid_ssl_error == false || ( mBrowser && mBrowser->mIgnoreSSLCertErrors ) ) - { - // signal we should ignore and continue processing - reply->ignoreSslErrors(); - }; -} - -void LLNetworkAccessManager::finishLoading(QNetworkReply* reply) -{ - QVariant val = reply->attribute( QNetworkRequest::HttpStatusCodeAttribute ); - int http_status_code = val.toInt(); - if ( http_status_code >=400 && http_status_code <=499 ) - { - if (mBrowser) - { - std::string current_url = llToStdString(reply->url()); - foreach (LLEmbeddedBrowserWindow *window, mBrowser->windows) - { - if (window->getCurrentUri() == current_url) - { - window->navigateErrorPage( http_status_code ); - } - } - } - } - - // tests if navigation request resulted in a cache hit - useful for testing so leaving here for the moment. - //QVariant from_cache = reply->attribute( QNetworkRequest::SourceIsFromCacheAttribute ); - //QString url = QString(reply->url().toEncoded()); - //qDebug() << url << " --- from cache?" << fromCache.toBool() << "\n"; -} - -void LLNetworkAccessManager:: authenticationRequiredSlot(QNetworkReply *reply, QAuthenticator *authenticator) -{ - std::string username; - std::string password; - std::string url = llToStdString(reply->url()); - std::string realm = llToStdString(authenticator->realm()); - - if(mBrowser->authRequest(url, realm, username, password)) - { - // Got credentials to try, attempt auth with them. - authenticator->setUser(QString::fromStdString(username)); - authenticator->setPassword(QString::fromStdString(password)); - } - else - { - // The user cancelled, don't attempt auth. - } -} - diff --git a/indra/llqtwebkit/llnetworkaccessmanager.h b/indra/llqtwebkit/llnetworkaccessmanager.h deleted file mode 100644 index 478b679aa2..0000000000 --- a/indra/llqtwebkit/llnetworkaccessmanager.h +++ /dev/null @@ -1,57 +0,0 @@ -/* Copyright (c) 2006-2010, Linden Research, Inc. - * - * LLQtWebKit Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in GPL-license.txt in this distribution, or online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - */ - -#ifndef LLNETWORKACCESSMANAGER_H -#define LLNETWORKACCESSMANAGER_H - -#include -#include - -#include "ui_passworddialog.h" - -class QGraphicsProxyWidget; - -class LLEmbeddedBrowserPrivate; -class LLNetworkAccessManager: public QNetworkAccessManager -{ - Q_OBJECT -public: - LLNetworkAccessManager(LLEmbeddedBrowserPrivate* browser, QObject* parent = 0); - -protected: - virtual QNetworkReply *createRequest(Operation op, const QNetworkRequest &request, - QIODevice *outgoingData = 0); -private slots: - void finishLoading(QNetworkReply* reply); - void authenticationRequiredSlot(QNetworkReply *reply, QAuthenticator *authenticator); - void sslErrorsSlot(QNetworkReply* reply, const QList& errors); - -private: - LLEmbeddedBrowserPrivate* mBrowser; - -}; - -#endif // LLNETWORKACCESSMANAGER_H - diff --git a/indra/llqtwebkit/llqtwebkit.cpp b/indra/llqtwebkit/llqtwebkit.cpp deleted file mode 100644 index 2be066d11a..0000000000 --- a/indra/llqtwebkit/llqtwebkit.cpp +++ /dev/null @@ -1,820 +0,0 @@ -/* Copyright (c) 2006-2010, Linden Research, Inc. - * - * LLQtWebKit Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in GPL-license.txt in this distribution, or online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - */ - -#include -#include -#include -#include - -#include "llqtwebkit.h" - -#include "llembeddedbrowser.h" -#include "llembeddedbrowserwindow.h" - -LLQtWebKit* LLQtWebKit::sInstance = 0; - -//////////////////////////////////////////////////////////////////////////////// -// -LLQtWebKit::LLQtWebKit() : - mMaxBrowserWindows(16) -{ -} - -//////////////////////////////////////////////////////////////////////////////// -// -LLQtWebKit* LLQtWebKit::getInstance() -{ - if (! sInstance) - { - sInstance = new LLQtWebKit; - } - - return sInstance; -} - -//////////////////////////////////////////////////////////////////////////////// -// -LLQtWebKit::~LLQtWebKit() -{ -} - -//////////////////////////////////////////////////////////////////////////////// -// -bool LLQtWebKit::init(std::string application_directory, - std::string component_directory, - std::string profile_directory, - void* native_window_handle) -{ - return LLEmbeddedBrowser::getInstance()->init(application_directory, - component_directory, - profile_directory, - native_window_handle); -} - -//////////////////////////////////////////////////////////////////////////////// -// -int LLQtWebKit::getLastError() -{ - return LLEmbeddedBrowser::getInstance()->getLastError(); -} - -//////////////////////////////////////////////////////////////////////////////// -// -bool LLQtWebKit::reset() -{ - mBrowserWindowMap.clear(); - return LLEmbeddedBrowser::getInstance()->reset(); -} - -//////////////////////////////////////////////////////////////////////////////// -// -bool LLQtWebKit::clearCache() -{ - return LLEmbeddedBrowser::getInstance()->clearCache(); -} - -//////////////////////////////////////////////////////////////////////////////// -// -std::string LLQtWebKit::getVersion() -{ - const int majorVersion = 2; - const int minorVersion = 2; - - // number of hours since "time began" for this library - used to identify builds of same version - const int magicNumber = static_cast< int >((time(NULL) / 3600L) - (321190L)); - - // return as a string for now - don't think we need to expose actual version numbers - std::ostringstream codec; - codec << std::setw(1) << std::setfill('0'); - codec << majorVersion << "."; - codec << std::setw(2) << std::setfill('0'); - codec << minorVersion << "."; - codec << std::setw(5) << std::setfill('0'); - codec << magicNumber; - codec << " (QtWebKit version "; - codec << LLEmbeddedBrowser::getInstance()->getGREVersion(); - codec << ")"; - - return codec.str(); -} - -//////////////////////////////////////////////////////////////////////////////// -// -void LLQtWebKit::setBrowserAgentId(std::string id) -{ - LLEmbeddedBrowser::getInstance()->setBrowserAgentId(id); -} - -//////////////////////////////////////////////////////////////////////////////// -// -bool LLQtWebKit::enableProxy(bool enabled, std::string host_name, int port) -{ - return LLEmbeddedBrowser::getInstance()->enableProxy(enabled, host_name, port); -} - -//////////////////////////////////////////////////////////////////////////////// -// -void LLQtWebKit::setHostLanguage(const std::string& host_language ) -{ - LLEmbeddedBrowser::getInstance()->setHostLanguage(host_language); -} - -//////////////////////////////////////////////////////////////////////////////// -// -int LLQtWebKit::createBrowserWindow(int width, int height, const std::string target) -{ - LLEmbeddedBrowserWindow* browser_window = LLEmbeddedBrowser::getInstance()->createBrowserWindow(width, height, target); - - if (browser_window) - { - // arbitrary limit so we don't exhaust system resources - int id(0); - while (++id < mMaxBrowserWindows) - { - std::pair< BrowserWindowMapIter, bool > result = mBrowserWindowMap.insert(std::make_pair(id, browser_window)); - - // find first place the insert succeeds and use that index as the id - if (result.second) - { - browser_window->setWindowId(id); - return id; - } - } - } - - return 0; -} - -//////////////////////////////////////////////////////////////////////////////// -// -void LLQtWebKit::proxyWindowOpened(int browser_window_id, const std::string target, const std::string uuid) -{ - LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); - if (browser_window) - { - browser_window->proxyWindowOpened(target, uuid); - } -} -//////////////////////////////////////////////////////////////////////////////// -// -void LLQtWebKit::proxyWindowClosed(int browser_window_id, const std::string uuid) -{ - LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); - if (browser_window) - { - browser_window->proxyWindowClosed(uuid); - } -} - -//////////////////////////////////////////////////////////////////////////////// -// -bool LLQtWebKit::destroyBrowserWindow(int browser_window_id) -{ - // don't use the utility method here since we need the iteratorator to remove the entry from the map - BrowserWindowMapIter iterator = mBrowserWindowMap.find(browser_window_id); - LLEmbeddedBrowserWindow* browser_window = (*iterator).second; - - if (browser_window) - { - LLEmbeddedBrowser::getInstance()->destroyBrowserWindow(browser_window); - } - - mBrowserWindowMap.erase(iterator); - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// -bool LLQtWebKit::setBackgroundColor(int browser_window_id, const int red, const int green, const int blue) -{ - LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); - if (browser_window) - { - browser_window->setBackgroundColor(red, green, blue); - return true; - } - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// -bool LLQtWebKit::setEnabled(int browser_window_id, bool enabled) -{ - LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); - if (browser_window) - { - browser_window->setEnabled(enabled); - return true; - } - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// -bool LLQtWebKit::setSize(int browser_window_id, int width, int height) -{ - LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); - if (browser_window) - { - browser_window->setSize(width, height); - return true; - } - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// -bool LLQtWebKit::scrollByLines(int browser_window_id, int lines) -{ - LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); - if (browser_window) - { - browser_window->scrollByLines(lines); - return true; - } - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// -bool LLQtWebKit::addObserver(int browser_window_id, LLEmbeddedBrowserWindowObserver* subject) -{ - LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); - if (browser_window) - { - browser_window->addObserver(subject); - } - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// -bool LLQtWebKit::remObserver(int browser_window_id, LLEmbeddedBrowserWindowObserver* subject) -{ - LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); - if (browser_window) - { - browser_window->remObserver(subject); - } - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// -bool LLQtWebKit::navigateTo(int browser_window_id, const std::string uri) -{ - LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); - if (browser_window) - { - return browser_window->navigateTo(uri) ? true : false; - } - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// -bool LLQtWebKit::userAction(int browser_window_id, EUserAction action) -{ - LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); - if (browser_window) - { - return browser_window->userAction(action); - } - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// -bool LLQtWebKit::userActionIsEnabled(int browser_window_id, EUserAction action) -{ - LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); - if (browser_window) - { - return browser_window->userActionIsEnabled(action); - } - return false; -} - -/////////////////////////////////////////////////////////////////////////////// -// -const unsigned char* LLQtWebKit::grabBrowserWindow(int browser_window_id) -{ - LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); - if (browser_window) - { - return browser_window->grabWindow(0, 0, browser_window->getBrowserWidth(), browser_window->getBrowserHeight()); - } - - return 0; -} - -//////////////////////////////////////////////////////////////////////////////// -// -const unsigned char* LLQtWebKit::getBrowserWindowPixels(int browser_window_id) -{ - LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); - if (browser_window) - { - return browser_window->getPageBuffer(); - } - - return 0; -} - -//////////////////////////////////////////////////////////////////////////////// -// -bool LLQtWebKit::flipWindow(int browser_window_id, bool flip) -{ - LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); - if (browser_window) - { - browser_window->flipWindow(flip); - return true; - } - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// -int LLQtWebKit::getBrowserWidth(int browser_window_id) -{ - LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); - if (browser_window) - { - return browser_window->getBrowserWidth(); - } - - return 0; -} - -//////////////////////////////////////////////////////////////////////////////// -// -int LLQtWebKit::getBrowserHeight(int browser_window_id) -{ - LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); - if (browser_window) - { - return browser_window->getBrowserHeight(); - } - - return 0; -} - -//////////////////////////////////////////////////////////////////////////////// -// -int LLQtWebKit::getBrowserDepth(int browser_window_id) -{ - LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); - if (browser_window) - { - return browser_window->getBrowserDepth(); - } - - return 0; -} - -//////////////////////////////////////////////////////////////////////////////// -// -int LLQtWebKit::getBrowserRowSpan(int browser_window_id) -{ - LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); - if (browser_window) - { - return browser_window->getBrowserRowSpan(); - } - - return 0; -} - -//////////////////////////////////////////////////////////////////////////////// -// -bool LLQtWebKit::mouseEvent(int browser_window_id, EMouseEvent mouse_event, int button, int x, int y, EKeyboardModifier modifiers) -{ - LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); - if (browser_window) - { - browser_window->mouseEvent(mouse_event, button, x, y, modifiers); - return true; - } - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// -bool LLQtWebKit::scrollWheelEvent(int browser_window_id, int x, int y, int scroll_x, int scroll_y, EKeyboardModifier modifiers) -{ - LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); - if (browser_window) - { - browser_window->scrollWheelEvent(x, y, scroll_x, scroll_y, modifiers); - return true; - } - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// -bool LLQtWebKit::keyboardEvent( - int browser_window_id, - EKeyEvent key_event, - uint32_t key_code, - const char *utf8_text, - EKeyboardModifier modifiers, - uint32_t native_scan_code, - uint32_t native_virtual_key, - uint32_t native_modifiers) -{ - LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); - if (browser_window) - { - browser_window->keyboardEvent(key_event, key_code, utf8_text, modifiers, native_scan_code, native_virtual_key, native_modifiers); - return true; - } - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// -bool LLQtWebKit::focusBrowser(int browser_window_id, bool focus_browser) -{ - LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); - if (browser_window) - { - browser_window->focusBrowser(focus_browser); - return true; - } - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// -void LLQtWebKit::setNoFollowScheme(int browser_window_id, std::string scheme) -{ - LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); - if (browser_window) - { - browser_window->setNoFollowScheme(scheme); - } -} - -//////////////////////////////////////////////////////////////////////////////// -// -std::string LLQtWebKit::getNoFollowScheme(int browser_window_id) -{ - LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); - if (browser_window) - { - return browser_window->getNoFollowScheme(); - } - - return (""); -} - -//////////////////////////////////////////////////////////////////////////////// -// -void LLQtWebKit::pump(int max_milliseconds) -{ - LLEmbeddedBrowser::getInstance()->pump(max_milliseconds); -} - -//////////////////////////////////////////////////////////////////////////////// -// -void LLQtWebKit::enableCookies(bool enabled) -{ - LLEmbeddedBrowser::getInstance()->enableCookies( enabled ); -} - -//////////////////////////////////////////////////////////////////////////////// -// -bool LLQtWebKit::clearAllCookies() -{ - return LLEmbeddedBrowser::getInstance()->clearAllCookies(); -} - -//////////////////////////////////////////////////////////////////////////////// -// -void LLQtWebKit::setCookies(const std::string &cookies) -{ - return LLEmbeddedBrowser::getInstance()->setCookies(cookies); -} - -//////////////////////////////////////////////////////////////////////////////// -// -std::string LLQtWebKit::getAllCookies() -{ - return LLEmbeddedBrowser::getInstance()->getAllCookies(); -} - - -//////////////////////////////////////////////////////////////////////////////// -// -void LLQtWebKit::enablePlugins(bool enabled) -{ - LLEmbeddedBrowser::getInstance()->enablePlugins(enabled); -} - -//////////////////////////////////////////////////////////////////////////////// -// -void LLQtWebKit::enableJavaScript(bool enabled) -{ - LLEmbeddedBrowser::getInstance()->enableJavaScript(enabled); -} - -//////////////////////////////////////////////////////////////////////////////// -// -bool LLQtWebKit::showWebInspector(bool show) -{ - return LLEmbeddedBrowser::getInstance()->showWebInspector(show); -} - -//////////////////////////////////////////////////////////////////////////////// -// -std::string LLQtWebKit::evaluateJavaScript(int browser_window_id, const std::string script) -{ - LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); - if (browser_window) - { - return browser_window->evaluateJavaScript(script); - } - - return ""; -} - -//////////////////////////////////////////////////////////////////////////////// -// -void LLQtWebKit::prependHistoryUrl(int browser_window_id, std::string url) -{ - LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); - if (browser_window) - { - browser_window->prependHistoryUrl(url); - } -} - -//////////////////////////////////////////////////////////////////////////////// -// -void LLQtWebKit::clearHistory(int browser_window_id) -{ - LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); - if (browser_window) - { - browser_window->clearHistory(); - } -} - -std::string LLQtWebKit::dumpHistory(int browser_window_id) -{ - LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); - if (browser_window) - { - return browser_window->dumpHistory(); - } - - return NULL; -} - -//////////////////////////////////////////////////////////////////////////////// -// -bool LLQtWebKit::setCAFile(const std::string &ca_file) -{ - return LLEmbeddedBrowser::getInstance()->setCAFile(ca_file); -} - -//////////////////////////////////////////////////////////////////////////////// -// -bool LLQtWebKit::addCAFile(const std::string &ca_file) -{ - return LLEmbeddedBrowser::getInstance()->addCAFile(ca_file); -} - -//////////////////////////////////////////////////////////////////////////////// -// -void LLQtWebKit::setIgnoreSSLCertErrors(bool ignore) -{ - LLEmbeddedBrowser::getInstance()->setIgnoreSSLCertErrors(ignore); -} - -//////////////////////////////////////////////////////////////////////////////// -// -bool LLQtWebKit::getIgnoreSSLCertErrors() -{ - return LLEmbeddedBrowser::getInstance()-> getIgnoreSSLCertErrors(); -} - -//////////////////////////////////////////////////////////////////////////////// -// -const std::vector< std::string > LLQtWebKit::getInstalledCertsList() -{ - return LLEmbeddedBrowser::getInstance()->getInstalledCertsList(); -} - -//////////////////////////////////////////////////////////////////////////////// -// utility method to get an LLEmbeddedBrowserWindow* from a window id (int) -LLEmbeddedBrowserWindow* LLQtWebKit::getBrowserWindowFromWindowId(int browser_window_id) -{ - BrowserWindowMapIter iterator = mBrowserWindowMap.find(browser_window_id); - - if (iterator != mBrowserWindowMap.end()) - return (*iterator).second; - else - return 0; -} - -LLEmbeddedBrowserWindowObserver::~LLEmbeddedBrowserWindowObserver() -{ -} - -void LLEmbeddedBrowserWindowObserver::onCursorChanged(const EventType&) -{ -} - -void LLEmbeddedBrowserWindowObserver::onPageChanged(const EventType&) -{ -} - -void LLEmbeddedBrowserWindowObserver::onNavigateBegin(const EventType&) -{ -} - -void LLEmbeddedBrowserWindowObserver::onNavigateComplete(const EventType&) -{ -} - -void LLEmbeddedBrowserWindowObserver::onUpdateProgress(const EventType&) -{ -} - -void LLEmbeddedBrowserWindowObserver::onStatusTextChange(const EventType&) -{ -} - -void LLEmbeddedBrowserWindowObserver::onTitleChange(const EventType&) -{ -} - -void LLEmbeddedBrowserWindowObserver::onLocationChange(const EventType&) -{ -} - -void LLEmbeddedBrowserWindowObserver::onNavigateErrorPage(const EventType&) -{ -} - -void LLEmbeddedBrowserWindowObserver::onClickLinkHref(const EventType&) -{ -} - -void LLEmbeddedBrowserWindowObserver::onClickLinkNoFollow(const EventType&) -{ -} - -void LLEmbeddedBrowserWindowObserver::onCookieChanged(const EventType&) -{ -} - -std::string LLEmbeddedBrowserWindowObserver::onRequestFilePicker(const EventType&) -{ - return std::string(); -} - -void LLEmbeddedBrowserWindowObserver::onWindowCloseRequested(const EventType&) -{ -} - -void LLEmbeddedBrowserWindowObserver::onWindowGeometryChangeRequested(const EventType&) -{ -} - -bool LLEmbeddedBrowserWindowObserver::onAuthRequest(const std::string &, const std::string &, std::string &, std::string &) -{ - return false; -} - -bool LLEmbeddedBrowserWindowObserver::onCertError(const std::string &, const std::string &) -{ - return false; // cancel and abort after cert error -} - -void LLEmbeddedBrowserWindowObserver::onQtDebugMessage( const std::string &, const std::string &) -{ -} - -void LLEmbeddedBrowserWindowObserver::onLinkHovered(const EventType&) -{ -} - -// set the regex used to determine if a page is trusted or not -void LLQtWebKit::setWhiteListRegex( int browser_window_id, const std::string& regex ) -{ - LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); - if (browser_window) - { - browser_window->setWhiteListRegex(regex); - } -} - -// Second Life viewer specific functions -void LLQtWebKit::setSLObjectEnabled( bool enabled ) -{ - LLEmbeddedBrowser::getInstance()->setSLObjectEnabled( enabled ); -} - -void LLQtWebKit::setAgentLanguage( const std::string& agent_language ) -{ - LLEmbeddedBrowser::getInstance()->setAgentLanguage( agent_language ); -} - -void LLQtWebKit::setAgentRegion( const std::string& agent_region ) -{ - LLEmbeddedBrowser::getInstance()->setAgentRegion( agent_region ); -} - -void LLQtWebKit::setAgentLocation( double x, double y, double z ) -{ - LLEmbeddedBrowser::getInstance()->setAgentLocation( x, y, z ); -} - -void LLQtWebKit::setAgentGlobalLocation( double x, double y, double z ) -{ - LLEmbeddedBrowser::getInstance()->setAgentGlobalLocation( x, y, z ); -} - -void LLQtWebKit::setAgentOrientation( double angle ) -{ - LLEmbeddedBrowser::getInstance()->setAgentOrientation( angle ); -} - - -void LLQtWebKit::setAgentMaturity( const std::string& agent_maturity ) -{ - LLEmbeddedBrowser::getInstance()->setAgentMaturity( agent_maturity ); -} - -void LLQtWebKit::emitLocation() -{ - LLEmbeddedBrowser::getInstance()->emitLocation(); -} - -void LLQtWebKit::emitMaturity() -{ - LLEmbeddedBrowser::getInstance()->emitMaturity(); -} - -void LLQtWebKit::emitLanguage() -{ - LLEmbeddedBrowser::getInstance()->emitLanguage(); -} - -void LLQtWebKit::enableQtMessageHandler( bool enable ) -{ - LLEmbeddedBrowser::getInstance()->enableQtMessageHandler( enable ); -} - -void LLQtWebKit::enableLoadingOverlay( int browser_window_id, bool enable) -{ - LLEmbeddedBrowserWindow* browser_window = getBrowserWindowFromWindowId(browser_window_id); - if (browser_window) - { - browser_window->enableLoadingOverlay( enable ); - } -} - -void LLQtWebKit::setPageZoomFactor( double factor ) -{ - LLEmbeddedBrowser::getInstance()->setPageZoomFactor( factor ); -} diff --git a/indra/llqtwebkit/llqtwebkit.h b/indra/llqtwebkit/llqtwebkit.h deleted file mode 100644 index 8e7ebd3906..0000000000 --- a/indra/llqtwebkit/llqtwebkit.h +++ /dev/null @@ -1,470 +0,0 @@ -/* Copyright (c) 2006-2010, Linden Research, Inc. - * - * LLQtWebKit Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in GPL-license.txt in this distribution, or online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - */ - -#ifndef LLQTWEBKIT_H -#define LLQTWEBKIT_H - -#if defined _MSC_VER && _MSC_VER < 1600 -// no pstdint.h in the client where this header is used -typedef unsigned long uint32_t; -#else -#include // Use the C99 official header -#endif - -#include -#include -#include - -class LLEmbeddedBrowser; -class LLEmbeddedBrowserWindow; - -// Use this to conditionalize code that depends on particular changes to the llqtwebkit API. -// This can be useful for times when we're waiting for a rebuild on one platform or another. -// When you bump this number, please note what the changes were in a comment below the #define, -// and keep the existing comments as history. -#define LLQTWEBKIT_API_VERSION 16 -// version 16: - // Added LLQtWebKit::enableLoadingOverlay() -// version 15: - // Added LLQtWebKit::setPageZoomFactor() -// version 14: - // Added LLEmbeddedBrowserWindowObserver::onQtDebugMessage -// version 13: - // Added LLEmbeddedBrowserWindowObserver::onCertError -// version 12: - // Pass over value to indicate if host for current URL is trusted as per whitelist regex or not -// version 11: - // Added initial support for url/host whitelist via a regex -// version 10: - // Added initial support for creating and displaying the Qt Web Inspector -// version 9: - // Added initial support for exposing certain Second Life viewer/agent variables to JavaScript -// version 8: - // Removed calls to set/clear 404 redirects and made the API now emit an event that the - // consumer can catch and decide what to do when an HTTP status code after navigate is 400-499 -// version 7: - // Added LLEmbeddedBrowserWindowEvent::setNavigationType() && LLEmbeddedBrowserWindowEvent::getNavigationType() - // Used to pass (and retrieve) the type of navigation event that caused a link to be activated. -// version 6: - // Added LLQtWebKit::addCAFile() -// version 5: - // Added LLEmbeddedBrowserWindowObserver::onLinkHovered -// version 4: - // Added LLEmbeddedBrowserWindowObserver::onAuthRequest -// version 3: - // Added setIgnoreSSLCertErrors and getIgnoreSSLCertErrors -// version 2: - // Changed the usage of the event parameters in onClickLinkHref and onClickLinkNoFollow events slightly. - // The clicked URI for both should now be retrieved with getEventUri() instead of getStringValue(). - // The "target" string in onClickLinkHref is now retrieved with getStringValue() instead of getStringValue2(). - // The contents of getStringValue2() in the onClickLinkHref event is now a unique ID for the window proxy the click targets. - // Removed the "link target type" concept, since it doesn't really belong here. - // Removed most of the construtor variants in LLEmbeddedBrowserWindowEvent and added setters in their place. - // Removed setCaretColor, since it's done nothing for some time now. - // Added LLEmbeddedBrowserWindowObserver::onWindowGeometryChangeRequested - // Added -// version 1: - // Added the LLQTWEBKIT_API_VERSION define. - // Added LLEmbeddedBrowserWindowObserver::onWindowCloseRequested - -//////////////////////////////////////////////////////////////////////////////// -// data class that is passed with an event -class LLEmbeddedBrowserWindowEvent -{ - public: - LLEmbeddedBrowserWindowEvent(int window_id) : - mEventWindowId(window_id) - { - }; - - virtual ~LLEmbeddedBrowserWindowEvent() {} - - void setEventUri(const std::string &uri) { mEventUri = uri; } - void setNavigationType(const std::string &type) { mNavigationType = type; } - void setTrustedHost(const bool trusted) { mTrustedHost = trusted; } - void setIntValue(int val) { mIntVal = val; } - void setStringValue(const std::string &val) { mStringVal = val; } - void setStringValue2(const std::string &val) { mStringVal2 = val; } - void setRectValue(int x, int y, int width, int height) - { - mXVal = x; - mYVal = y; - mWidthVal = width; - mHeightVal = height; - } - - int getEventWindowId() const { return mEventWindowId; } - std::string getEventUri() const { return mEventUri; } - std::string getNavigationType() const { return mNavigationType; } - bool getTrustedHost() const { return mTrustedHost; } - int getIntValue() const { return mIntVal; }; - std::string getStringValue() const { return mStringVal; } - std::string getStringValue2() const { return mStringVal2; } - void getRectValue(int& x, int& y, int& width, int& height) const - { - x = mXVal; - y = mYVal; - width = mWidthVal; - height = mHeightVal; - }; - - private: - int mEventWindowId; - std::string mEventUri; - std::string mNavigationType; - bool mTrustedHost; - int mIntVal; - std::string mStringVal; - std::string mStringVal2; - int mXVal; - int mYVal; - int mWidthVal; - int mHeightVal; -}; - -//////////////////////////////////////////////////////////////////////////////// -// derrive from this class and override these methods to observe these events -#ifdef __GNUC__ -#pragma GCC visibility push(default) -#endif -class LLEmbeddedBrowserWindowObserver -{ - public: - virtual ~LLEmbeddedBrowserWindowObserver(); - typedef LLEmbeddedBrowserWindowEvent EventType; - - virtual void onCursorChanged(const EventType& event); - virtual void onPageChanged(const EventType& event); - virtual void onNavigateBegin(const EventType& event); - virtual void onNavigateComplete(const EventType& event); - virtual void onNavigateErrorPage(const EventType& event); - virtual void onUpdateProgress(const EventType& event); - virtual void onStatusTextChange(const EventType& event); - virtual void onTitleChange(const EventType& event); - virtual void onLocationChange(const EventType& event); - virtual void onClickLinkHref(const EventType& event); - virtual void onClickLinkNoFollow(const EventType& event); - virtual void onCookieChanged(const EventType& event); - // mStringVal will be the cookie in RFC 2109 string format - // mEventUri will be the url that caused the cookie change - // mIntVal will be true if the cookie is dead (i.e. being deleted), false otherwise - virtual std::string onRequestFilePicker(const EventType& event); - virtual void onWindowCloseRequested(const EventType& event); - virtual void onWindowGeometryChangeRequested(const EventType& event); - - // This should return true to attempt auth, or false to cancel. - virtual bool onAuthRequest(const std::string &in_url, const std::string &in_realm, std::string &out_username, std::string &out_password); - - // This should return true to continue after cert error, or false to cancel and abort. - virtual bool onCertError(const std::string &in_url, const std::string &in_msg); - - virtual void onLinkHovered(const EventType& event); - // mEventURI will be the link - // mStringVal will be the title - // mStringVal2 will be the text - - // catch qDebug() messages from Qt and pipe them back to host application - virtual void onQtDebugMessage( const std::string& msg, const std::string& msg_type); -}; -#ifdef __GNUC__ -#pragma GCC visibility pop -#endif - -//////////////////////////////////////////////////////////////////////////////// -// main library class - -#ifdef __GNUC__ -#pragma GCC visibility push(default) -#endif -class LLQtWebKit -{ - public: - typedef enum e_cursor - { - C_ARROW, - C_IBEAM, - C_SPLITV, - C_SPLITH, - C_POINTINGHAND - } ECursor; - - typedef enum e_user_action - { - UA_EDIT_CUT, - UA_EDIT_COPY, - UA_EDIT_PASTE, - UA_NAVIGATE_STOP, - UA_NAVIGATE_BACK, - UA_NAVIGATE_FORWARD, - UA_NAVIGATE_RELOAD - } EUserAction; - - typedef enum e_key_event - { - KE_KEY_DOWN, - KE_KEY_REPEAT, - KE_KEY_UP - }EKeyEvent; - - typedef enum e_mouse_event - { - ME_MOUSE_MOVE, - ME_MOUSE_DOWN, - ME_MOUSE_UP, - ME_MOUSE_DOUBLE_CLICK - }EMouseEvent; - - typedef enum e_mouse_button - { - MB_MOUSE_BUTTON_LEFT, - MB_MOUSE_BUTTON_RIGHT, - MB_MOUSE_BUTTON_MIDDLE, - MB_MOUSE_BUTTON_EXTRA_1, - MB_MOUSE_BUTTON_EXTRA_2, - }EMouseButton; - - typedef enum e_keyboard_modifier - { - KM_MODIFIER_NONE = 0x00, - KM_MODIFIER_SHIFT = 0x01, - KM_MODIFIER_CONTROL = 0x02, - KM_MODIFIER_ALT = 0x04, - KM_MODIFIER_META = 0x08 - }EKeyboardModifier; - - virtual ~LLQtWebKit(); - - // singleton access - static LLQtWebKit* getInstance(); - - // housekeeping - bool init(std::string application_directory, - std::string component_directory, - std::string profile_directory, - void* native_window_handle); - bool reset(); - bool clearCache(); - int getLastError(); - std::string getVersion(); - void setBrowserAgentId(std::string id); - bool enableProxy(bool enabled, std::string host_name, int port); - - void enableCookies(bool enabled); - bool clearAllCookies(); - - // The following two functions accept and return cookies in the same format that's used for the Set-Cookie: HTTP header - // as defined in RFC 2109 ( http://www.ietf.org/rfc/rfc2109.txt ). The string should not contain the literal "Set-Cookie:", - // just the cookie itself. - // Multiple cookies within the string are separated by a newline character ('\n') - void setCookies(const std::string &cookies); - std::string getAllCookies(); - - void enablePlugins(bool enabled); - void enableJavaScript(bool enabled); - - // Web inspector - Firebug-esque debugger - bool showWebInspector(bool show); - - // updates value of 'hostLanguage' in JavaScript 'Navigator' obect that - // embedded pages can query to see what language the host app is set to - void setHostLanguage(const std::string& host_language); - - // browser window - creation/deletion, mutation etc. - int createBrowserWindow(int width, int height, const std::string target = std::string("")); - void proxyWindowOpened(int browser_window_id, const std::string target, const std::string uuid); - void proxyWindowClosed(int browser_window_id, const std::string uuid); - bool destroyBrowserWindow(int browser_window_id); - bool setSize(int browser_window_id, int width, int height); - bool scrollByLines(int browser_window_id, int lines); - bool setBackgroundColor(int browser_window_id, const int red, const int green, const int blue); - bool setEnabled(int browser_window_id, bool enabled); - - // add/remove yourself as an observer on browser events - see LLEmbeddedBrowserWindowObserver declaration - bool addObserver(int browser_window_id, LLEmbeddedBrowserWindowObserver* subject); - bool remObserver(int browser_window_id, LLEmbeddedBrowserWindowObserver* subject); - - // navigation - self explanatory - bool navigateTo(int browser_window_id, const std::string uri); - bool userAction(int browser_window_id, EUserAction action); - bool userActionIsEnabled(int browser_window_id, EUserAction action); - - // javascript access/control - std::string evaluateJavaScript(int browser_window_id, const std::string script); - - // set/clear URL to redirect to when a 404 page is reached - bool set404RedirectUrl(int browser_window_in, std::string redirect_url); - bool clr404RedirectUrl(int browser_window_in); - - // access to rendered bitmap data - const unsigned char* grabBrowserWindow(int browser_window_id); // renders page to memory and returns pixels - const unsigned char* getBrowserWindowPixels(int browser_window_id); // just returns pixels - no render - bool flipWindow(int browser_window_id, bool flip); // optionally flip window (pixels) you get back - int getBrowserWidth(int browser_window_id); // current browser width (can vary slightly after page is rendered) - int getBrowserHeight(int browser_window_id); // current height - int getBrowserDepth(int browser_window_id); // depth in bytes - int getBrowserRowSpan(int browser_window_id); // width in pixels * depth in bytes - - // mouse/keyboard interaction - bool mouseEvent(int browser_window_id, EMouseEvent mouse_event, int button, int x, int y, EKeyboardModifier modifiers); // send a mouse event to a browser window at given XY in browser space - bool scrollWheelEvent(int browser_window_id, int x, int y, int scroll_x, int scroll_y, EKeyboardModifier modifiers); - bool keyboardEvent( - int browser_window_id, - EKeyEvent key_event, - uint32_t key_code, - const char *utf8_text, - EKeyboardModifier modifiers, - uint32_t native_scan_code = 0, - uint32_t native_virtual_key = 0, - uint32_t native_modifiers = 0); - - bool focusBrowser(int browser_window_id, bool focus_browser); // set/remove focus to given browser window - - // accessor/mutator for scheme that browser doesn't follow - e.g. secondlife.com:// - void setNoFollowScheme(int browser_window_id, std::string scheme); - std::string getNoFollowScheme(int browser_window_id); - - void pump(int max_milliseconds); - - void prependHistoryUrl(int browser_window_id, std::string url); - void clearHistory(int browser_window_id); - std::string dumpHistory(int browser_window_id); - - // Specify a path to a .pem file containing a list of CA certificates the browser should trust. - // NOTE that this will replace the default list of root certs (not add to it). - // If the file isn't found or doesn't contain any certs in the correct format, this call will have no effect and will return false. - // NOTE: Using this function causes strange cert verification issues on the Mac. - // Using addCAFile() instead seems to work better. - bool setCAFile(const std::string &ca_file); - - // This behaves similarly, but instead of replacing the entire list it appends additional trusted root certs to the current list. - bool addCAFile(const std::string &ca_file); - - // Set a flag causing all SSL cert errors to be ignored. - // NOTE: this should only be used for testing, as it negates the security model of https. - void setIgnoreSSLCertErrors(bool ignore); - bool getIgnoreSSLCertErrors(); - - const std::vector< std::string > getInstalledCertsList(); - - void enableQtMessageHandler( bool enable ); - - void enableLoadingOverlay( int browser_window_id, bool enable); - - // Copied from indra_constants.h. - // The key_code argument to keyboardEvent should either be one of these or a 7-bit ascii character. - enum keyCodes - { - // Leading zeroes ensure that these won't sign-extend when assigned to a larger type. - KEY_RETURN = 0x0081, - KEY_LEFT = 0x0082, - KEY_RIGHT = 0x0083, - KEY_UP = 0x0084, - KEY_DOWN = 0x0085, - KEY_ESCAPE = 0x0086, - KEY_BACKSPACE = 0x0087, - KEY_DELETE = 0x0088, - KEY_SHIFT = 0x0089, - KEY_CONTROL = 0x008A, - KEY_ALT = 0x008B, - KEY_HOME = 0x008C, - KEY_END = 0x008D, - KEY_PAGE_UP = 0x008E, - KEY_PAGE_DOWN = 0x008F, - KEY_HYPHEN = 0x0090, - KEY_EQUALS = 0x0091, - KEY_INSERT = 0x0092, - KEY_CAPSLOCK = 0x0093, - KEY_TAB = 0x0094, - KEY_ADD = 0x0095, - KEY_SUBTRACT = 0x0096, - KEY_MULTIPLY = 0x0097, - KEY_DIVIDE = 0x0098, - KEY_F1 = 0x00A1, - KEY_F2 = 0x00A2, - KEY_F3 = 0x00A3, - KEY_F4 = 0x00A4, - KEY_F5 = 0x00A5, - KEY_F6 = 0x00A6, - KEY_F7 = 0x00A7, - KEY_F8 = 0x00A8, - KEY_F9 = 0x00A9, - KEY_F10 = 0x00AA, - KEY_F11 = 0x00AB, - KEY_F12 = 0x00AC, - - KEY_PAD_UP = 0x00C0, - KEY_PAD_DOWN = 0x00C1, - KEY_PAD_LEFT = 0x00C2, - KEY_PAD_RIGHT = 0x00C3, - KEY_PAD_HOME = 0x00C4, - KEY_PAD_END = 0x00C5, - KEY_PAD_PGUP = 0x00C6, - KEY_PAD_PGDN = 0x00C7, - KEY_PAD_CENTER = 0x00C8, // the 5 in the middle - KEY_PAD_INS = 0x00C9, - KEY_PAD_DEL = 0x00CA, - KEY_PAD_RETURN = 0x00CB, - KEY_PAD_ADD = 0x00CC, - KEY_PAD_SUBTRACT = 0x00CD, - KEY_PAD_MULTIPLY = 0x00CE, - KEY_PAD_DIVIDE = 0x00CF, - - KEY_NONE = 0x00FF // not sent from keyboard. For internal use only. - }; - - // set the regex used to determine if a page is trusted or not - void setWhiteListRegex( int browser_window_id, const std::string& regex ); - - // Second Life specific functions - // (Note, this is a departure from the generic nature of this library) - void setSLObjectEnabled( bool enabled ); // enable or disaable feature - void setAgentLanguage( const std::string& agent_language ); // viewer language selected by agent - void setAgentRegion( const std::string& agent_region ); // name of region where agent is located - void setAgentLocation( double x, double y, double z ); // agent's x,y,z location within a region - void setAgentGlobalLocation( double x, double y, double z ); // agent's x,y,z location within the current grid - void setAgentOrientation( double angle ); // direction (0..359) agent is facing - void setAgentMaturity( const std::string& agent_maturity ); // selected maturity level of agent - void emitLocation(); - void emitMaturity(); - void emitLanguage(); - - // set the zoom factor for web pages ( can be less than 0.0) - void setPageZoomFactor( double factor ); - - private: - LLQtWebKit(); - LLEmbeddedBrowserWindow* getBrowserWindowFromWindowId(int browser_window_id); - static LLQtWebKit* sInstance; - const int mMaxBrowserWindows; - typedef std::map< int, LLEmbeddedBrowserWindow* > BrowserWindowMap; - typedef std::map< int, LLEmbeddedBrowserWindow* >::iterator BrowserWindowMapIter; - BrowserWindowMap mBrowserWindowMap; -}; - -#ifdef __GNUC__ -#pragma GCC visibility pop -#endif - -#endif // LLQTWEBKIT_H diff --git a/indra/llqtwebkit/llqtwebkit.pri b/indra/llqtwebkit/llqtwebkit.pri deleted file mode 100644 index 4f85aa423d..0000000000 --- a/indra/llqtwebkit/llqtwebkit.pri +++ /dev/null @@ -1,47 +0,0 @@ -DEPENDPATH += $$PWD -INCLUDEPATH += $$PWD - -!mac { -unix { - DEFINES += LL_LINUX -} -} - -mac { - DEFINES += LL_OSX -} - -win32{ - DEFINES += _WINDOWS -} - -# Input -HEADERS += llembeddedbrowser.h \ - llembeddedbrowser_p.h \ - llembeddedbrowserwindow.h \ - llembeddedbrowserwindow_p.h \ - llnetworkaccessmanager.h \ - llqtwebkit.h \ - llwebpage.h \ - llwebpageopenshim.h \ - llstyle.h \ - lljsobject.h - -SOURCES += llembeddedbrowser.cpp \ - llembeddedbrowserwindow.cpp \ - llnetworkaccessmanager.cpp \ - llqtwebkit.cpp \ - llwebpage.cpp \ - llwebpageopenshim.cpp \ - llstyle.cpp \ - lljsobject.cpp - -FORMS += passworddialog.ui - -RCC_DIR = .rcc -UI_DIR = .ui -MOC_DIR = .moc -OBJECTS_DIR = .obj - -include(static.pri) -include(qtwebkit_cookiejar/src/src.pri) diff --git a/indra/llqtwebkit/llqtwebkit.pro b/indra/llqtwebkit/llqtwebkit.pro deleted file mode 100644 index b6ff077bd1..0000000000 --- a/indra/llqtwebkit/llqtwebkit.pro +++ /dev/null @@ -1,18 +0,0 @@ -TEMPLATE = lib -CONFIG += static staticlib # we always build as static lib whether Qt is static or not -TARGET = -DEPENDPATH += . -INCLUDEPATH += . - -include(llqtwebkit.pri) - -QT += webkit opengl network gui - -win32:CONFIG(debug,debug|release) { - TARGET = llqtwebkitd -} - -RCC_DIR = $$PWD/.rcc -UI_DIR = $$PWD/.ui -MOC_DIR = $$PWD/.moc -OBJECTS_DIR = $$PWD/.obj diff --git a/indra/llqtwebkit/llstyle.cpp b/indra/llqtwebkit/llstyle.cpp deleted file mode 100644 index 8822d481a2..0000000000 --- a/indra/llqtwebkit/llstyle.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/* Copyright (c) 2006-2010, Linden Research, Inc. - * - * LLQtWebKit Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in GPL-license.txt in this distribution, or online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - */ - -#include "llstyle.h" - -#include "llembeddedbrowserwindow_p.h" -#include -#include -#include - -LLStyle::LLStyle() - : QPlastiqueStyle() -{ -} - -void LLStyle::drawComplexControl(ComplexControl control, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const -{ -#ifdef Q_WS_MAC - if (control == QStyle::CC_ScrollBar) { - QStyleOptionSlider* opt = (QStyleOptionSlider*)option; - const QPoint topLeft = opt->rect.topLeft(); - painter->translate(topLeft); - opt->rect.moveTo(QPoint(0, 0)); - painter->fillRect(opt->rect, opt->palette.background()); - } -#endif - QPlastiqueStyle::drawComplexControl(control, option, painter, widget); -} - -void LLStyle::drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const -{ - switch(element) - { - case CE_ScrollBarAddLine: - case CE_ScrollBarSubLine: - // This fixes the "scrollbar arrows pointing the wrong way" bug. - if (const QStyleOptionSlider *scrollBar = qstyleoption_cast(option)) - { - // Make the State_Horizontal bit in the option's state field match its orientation field. - QStyleOptionSlider localOption(*scrollBar); - if(localOption.orientation == Qt::Horizontal) - { - localOption.state |= State_Horizontal; - } - else - { - localOption.state &= ~State_Horizontal; - } - QPlastiqueStyle::drawControl(element, &localOption, painter, widget); - return; - } - default: - break; - } - - QPlastiqueStyle::drawControl(element, option, painter, widget); -} diff --git a/indra/llqtwebkit/llstyle.h b/indra/llqtwebkit/llstyle.h deleted file mode 100644 index 77c09b3bb6..0000000000 --- a/indra/llqtwebkit/llstyle.h +++ /dev/null @@ -1,42 +0,0 @@ -/* Copyright (c) 2006-2010, Linden Research, Inc. - * - * LLQtWebKit Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in GPL-license.txt in this distribution, or online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - */ - -#ifndef LLSTYLE_H -#define LLSTYLE_H - -#include - -class LLStyle : public QPlastiqueStyle -{ - -public: - explicit LLStyle(); - void drawComplexControl(ComplexControl control, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget = 0) const; - void drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const; - -}; - -#endif - diff --git a/indra/llqtwebkit/llwebpage.cpp b/indra/llqtwebkit/llwebpage.cpp deleted file mode 100644 index 113c0c186a..0000000000 --- a/indra/llqtwebkit/llwebpage.cpp +++ /dev/null @@ -1,536 +0,0 @@ -/* Copyright (c) 2006-2010, Linden Research, Inc. - * - * LLQtWebKit Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in GPL-license.txt in this distribution, or online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - */ - -#include "llwebpage.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "llqtwebkit.h" -#include "llembeddedbrowser.h" -#include "llembeddedbrowserwindow.h" -#include "llembeddedbrowserwindow_p.h" -#include "lljsobject.h" - -LLWebPage::LLWebPage(QObject *parent) - : QWebPage(parent) - , window(0) - , mHostLanguage( "en" ) - , mWhiteListRegex( "" ) -{ - mJsObject = new LLJsObject( parent ); - - connect(this, SIGNAL(loadProgress(int)), - this, SLOT(loadProgressSlot(int))); - connect(this, SIGNAL(linkHovered(const QString &, const QString &, const QString &)), - this, SLOT(linkHoveredSlot(const QString &, const QString &, const QString &))); - connect(this, SIGNAL(statusBarMessage(const QString &)), - this, SLOT(statusBarMessageSlot(const QString &))); - connect(mainFrame(), SIGNAL(urlChanged(const QUrl&)), - this, SLOT(urlChangedSlot(const QUrl&))); - connect(this, SIGNAL(loadStarted()), - this, SLOT(loadStarted())); - connect(this, SIGNAL(loadFinished(bool)), - this, SLOT(loadFinished(bool))); - connect(this, SIGNAL(windowCloseRequested()), - this, SLOT(windowCloseRequested())); - connect(this, SIGNAL(geometryChangeRequested(const QRect&)), - this, SLOT(geometryChangeRequested(const QRect&))); - connect(mainFrame(), SIGNAL(titleChanged(const QString&)), - this, SLOT(titleChangedSlot(const QString&))); - connect(mainFrame(), SIGNAL(javaScriptWindowObjectCleared()), - this, SLOT(extendNavigatorObject())); -} - -LLWebPage::~LLWebPage() -{ - delete mJsObject; -} - -void LLWebPage::loadProgressSlot(int progress) -{ - if (!window) - return; - window->d->mPercentComplete = progress; - LLEmbeddedBrowserWindowEvent event(window->getWindowId()); - event.setEventUri(window->getCurrentUri()); - event.setIntValue(progress); - window->d->mEventEmitter.update(&LLEmbeddedBrowserWindowObserver::onUpdateProgress, event); - - if ( progress >= 100 ) - window->d->mShowLoadingOverlay = false; - - window->d->mDirty = true; - window->grabWindow(0,0,webView->boundingRect().width(),webView->boundingRect().height()); - - window->d->mEventEmitter.update(&LLEmbeddedBrowserWindowObserver::onPageChanged, event); -} - -void LLWebPage::linkHoveredSlot(const QString &link, const QString &title, const QString &textContent) -{ - if (!window) - return; - LLEmbeddedBrowserWindowEvent event(window->getWindowId()); - event.setEventUri(llToStdString(link)); - event.setStringValue(llToStdString(title)); - event.setStringValue2(llToStdString(textContent)); - window->d->mEventEmitter.update(&LLEmbeddedBrowserWindowObserver::onLinkHovered, event); -} - -void LLWebPage::statusBarMessageSlot(const QString& text) -{ - if (!window) - return; - window->d->mStatusText = llToStdString(text); - LLEmbeddedBrowserWindowEvent event(window->getWindowId()); - event.setEventUri(window->getCurrentUri()); - event.setStringValue(window->d->mStatusText); - window->d->mEventEmitter.update(&LLEmbeddedBrowserWindowObserver::onStatusTextChange, event); -} - -void LLWebPage::titleChangedSlot(const QString& text) -{ - if (!window) - return; - window->d->mTitle = llToStdString(text); - LLEmbeddedBrowserWindowEvent event(window->getWindowId()); - event.setEventUri(window->getCurrentUri()); - event.setStringValue(window->d->mTitle); - window->d->mEventEmitter.update(&LLEmbeddedBrowserWindowObserver::onTitleChange, event); -} - -// set the regex used to determine if a page is trusted or not -void LLWebPage::setWhiteListRegex( const std::string& regex ) -{ - mWhiteListRegex = regex; -} - -void LLWebPage::configureTrustedPage( bool is_trusted ) -{ - // action happens in browser window parent - LLEmbeddedBrowser* parent_browser = 0; - if ( window && window->d && window->d->mParent ) - { - parent_browser = window->d->mParent; - if ( parent_browser ) - { - if ( is_trusted ) - { - //qDebug() << "Whitelist passed - turning on"; - - // trusted so turn everything on - parent_browser->enableJavaScriptTransient( true ); - parent_browser->enableCookiesTransient( true ); - parent_browser->enablePluginsTransient( true ); - } - else - { - //qDebug() << "Whitelist failed - reverting to default state"; - - // restore default state set by client - parent_browser->enableJavaScript( parent_browser->isJavaScriptEnabled() ); - parent_browser->enableCookies( parent_browser->areCookiesEnabled() ); - parent_browser->enablePlugins( parent_browser->arePluginsEnabled() ); - } - } - } -} - -bool LLWebPage::checkRegex( const QUrl& url ) -{ - QRegExp reg_exp( QString::fromStdString( mWhiteListRegex ) ); - reg_exp.setCaseSensitivity( Qt::CaseInsensitive ); - reg_exp.setMinimal( true ); - - if ( reg_exp.exactMatch( url.host() ) ) - { - return true; - } - else - { - return false; - } -} - -void LLWebPage::checkWhiteList( const QUrl& url ) -{ - if ( mWhiteListRegex.length() ) - { - if ( checkRegex( url ) ) - { - configureTrustedPage( true ); // page is "trusted" - go ahead and configure it as such - } - else - { - configureTrustedPage( false ); // page is "NOT trusted" - go ahead and configure it as such - } - } - else - // no regex specified, don't do anything (i.e. don't change trust state) - { - } -} - -void LLWebPage::urlChangedSlot(const QUrl& url) -{ - if (!window) - return; - - checkWhiteList( url ); - - LLEmbeddedBrowserWindowEvent event(window->getWindowId()); - event.setEventUri(window->getCurrentUri()); - window->d->mEventEmitter.update(&LLEmbeddedBrowserWindowObserver::onLocationChange, event); -} - -bool LLWebPage::event(QEvent *event) -{ - bool result = QWebPage::event(event); - - if (event->type() == QEvent::GraphicsSceneMousePress) - currentPoint = ((QGraphicsSceneMouseEvent*)event)->pos().toPoint(); - else if(event->type() == QEvent::GraphicsSceneMouseRelease) - currentPoint = QPoint(); - - return result; -} - -bool LLWebPage::acceptNavigationRequest(QWebFrame* frame, const QNetworkRequest& request, NavigationType type) -{ - Q_UNUSED( frame ); - - if (!window) - return false; - - if (request.url().scheme() == window->d->mNoFollowScheme) - { - QString encodedUrl = request.url().toEncoded(); - // QUrl is turning foo:///home/bar into foo:/home/bar for some reason while Firefox does not - // http://bugs.webkit.org/show_bug.cgi?id=24695 - if (!encodedUrl.startsWith(window->d->mNoFollowScheme + "://")) { - encodedUrl = encodedUrl.mid(window->d->mNoFollowScheme.length() + 1); - encodedUrl = window->d->mNoFollowScheme + "://" + encodedUrl; - } - std::string rawUri = llToStdString(encodedUrl); - LLEmbeddedBrowserWindowEvent event(window->getWindowId()); - event.setEventUri(rawUri); - - // pass over the navigation type as per this page: http://apidocs.meego.com/1.1/core/html/qt4/qwebpage.html#NavigationType-enum - // pass as strings because telling everyone who needs to know about enums is too invasive. - std::string nav_type("unknown"); - if (type == QWebPage::NavigationTypeLinkClicked) nav_type="clicked"; - else - if (type == QWebPage::NavigationTypeFormSubmitted) nav_type="form_submited"; - else - if (type == QWebPage::NavigationTypeBackOrForward) nav_type="back_forward"; - else - if (type == QWebPage::NavigationTypeReload) nav_type="reloaded"; - else - if (type == QWebPage::NavigationTypeFormResubmitted) nav_type="form_resubmited"; - event.setNavigationType(nav_type); - - if ( mWhiteListRegex.length() ) - { - if ( frame ) - { - if ( checkRegex( frame->url() ) ) - { - event.setTrustedHost( true ); - } - else - { - event.setTrustedHost( false ); - } - } - else - // no frame - no trust (TODO: when can this happen?) - { - event.setTrustedHost( false ); - } - } - else - // no regex is like switching it off and indicating everything is trusted - { - event.setTrustedHost( true ); - } - - window->d->mEventEmitter.update(&LLEmbeddedBrowserWindowObserver::onClickLinkNoFollow, event); - - //qDebug() << "LLWebPage::acceptNavigationRequest: sending onClickLinkNoFollow, NavigationType is " << type << ", url is " << QString::fromStdString(rawUri) ; - return false; - } - - - return true; -} - - -void LLWebPage::loadStarted() -{ - if (!window) - return; - - QUrl url( QString::fromStdString( window->getCurrentUri() ) ); - checkWhiteList( url ); - - window->d->mShowLoadingOverlay = true; - - window->d->mTimeLoadStarted=time(NULL); - - window->d->mDirty = true; - window->grabWindow(0,0,webView->boundingRect().width(),webView->boundingRect().height()); - - LLEmbeddedBrowserWindowEvent event(window->getWindowId()); - event.setEventUri(window->getCurrentUri()); - window->d->mEventEmitter.update(&LLEmbeddedBrowserWindowObserver::onNavigateBegin, event); -} - -void LLWebPage::loadFinished(bool) -{ - if (!window) - return; - - window->d->mShowLoadingOverlay = false; - - window->d->mDirty = true; - window->grabWindow(0,0,webView->boundingRect().width(),webView->boundingRect().height()); - - LLEmbeddedBrowserWindowEvent event(window->getWindowId()); - event.setEventUri(window->getCurrentUri()); - window->d->mEventEmitter.update(&LLEmbeddedBrowserWindowObserver::onPageChanged, event); - - window->d->mEventEmitter.update(&LLEmbeddedBrowserWindowObserver::onNavigateComplete, event); -} - -void LLWebPage::windowCloseRequested() -{ - if (!window) - return; - LLEmbeddedBrowserWindowEvent event(window->getWindowId()); - window->d->mEventEmitter.update(&LLEmbeddedBrowserWindowObserver::onWindowCloseRequested, event); -} - -void LLWebPage::geometryChangeRequested(const QRect& geom) -{ - if (!window) - return; - - LLEmbeddedBrowserWindowEvent event(window->getWindowId()); - // empty UUID indicates this is targeting the main window -// event.setStringValue(window->getUUID()); - event.setRectValue(geom.x(), geom.y(), geom.width(), geom.height()); - window->d->mEventEmitter.update(&LLEmbeddedBrowserWindowObserver::onWindowGeometryChangeRequested, event); -} - -QString LLWebPage::chooseFile(QWebFrame* parentFrame, const QString& suggestedFile) -{ - Q_UNUSED(parentFrame); - Q_UNUSED(suggestedFile); - - return QString::fromStdString( window->requestFilePicker() ); -} - -void LLWebPage::javaScriptAlert(QWebFrame* frame, const QString& msg) -{ - Q_UNUSED(frame); - QMessageBox *msgBox = new QMessageBox; - msgBox->setWindowTitle(tr("JavaScript Alert - %1").arg(mainFrame()->url().host())); - msgBox->setText(msg); - msgBox->addButton(QMessageBox::Ok); - - QGraphicsProxyWidget *proxy = webView->scene()->addWidget(msgBox); - proxy->setWindowFlags(Qt::Window); // this makes the item a panel (and will make it get a window 'frame') - proxy->setPanelModality(QGraphicsItem::SceneModal); - proxy->setPos((webView->boundingRect().width() - msgBox->sizeHint().width())/2, - (webView->boundingRect().height() - msgBox->sizeHint().height())/2); - proxy->setActive(true); // make it the active item - - connect(msgBox, SIGNAL(finished(int)), proxy, SLOT(deleteLater())); - msgBox->show(); - - webView->scene()->setFocusItem(proxy); -} - -bool LLWebPage::javaScriptConfirm(QWebFrame* frame, const QString& msg) -{ - Q_UNUSED(frame); - Q_UNUSED(msg); - qWarning() << "LLWebPage::" << __FUNCTION__ << "not implemented" << msg << "returning true"; - return true; -} - -bool LLWebPage::javaScriptPrompt(QWebFrame* frame, const QString& msg, const QString& defaultValue, QString* result) -{ - Q_UNUSED(frame); - Q_UNUSED(msg); - Q_UNUSED(defaultValue); - Q_UNUSED(result); - qWarning() << "LLWebPage::" << __FUNCTION__ << "not implemented" << msg << defaultValue << "returning false"; - return false; -} - -void LLWebPage::extendNavigatorObject() -{ - // legacy - will go away in the future - QString q_host_language = QString::fromStdString( mHostLanguage ); - mainFrame()->evaluateJavaScript(QString("navigator.hostLanguage=\"%1\"").arg( q_host_language )); - - // the new way - if ( mJsObject ) - { - bool enabled = mJsObject->getSLObjectEnabled(); - if ( enabled ) - { - mainFrame()->addToJavaScriptWindowObject("slviewer", mJsObject ); - }; - }; -} - -QWebPage *LLWebPage::createWindow(WebWindowType type) -{ - Q_UNUSED(type); - QWebPage *result = NULL; - - if(window) - { - result = window->createWindow(); - } - - return result; -} - -void LLWebPage::setHostLanguage(const std::string& host_language) -{ - mHostLanguage = host_language; -} - -bool LLWebPage::supportsExtension(QWebPage::Extension extension) const -{ - if (extension == QWebPage::ErrorPageExtension) - return true; - return false; -} - -bool LLWebPage::extension(Extension, const ExtensionOption* option, ExtensionReturn* output) -{ - const QWebPage::ErrorPageExtensionOption* info = static_cast(option); - QWebPage::ErrorPageExtensionReturn* errorPage = static_cast(output); - - errorPage->content = QString("Failed loading page

    %1

    ") - .arg(info->errorString).toUtf8(); - - return true; -} - -// Second Life viewer specific functions -void LLWebPage::setSLObjectEnabled( bool enabled ) -{ - if ( mJsObject ) - mJsObject->setSLObjectEnabled( enabled ); -} - -void LLWebPage::setAgentLanguage( const std::string& agent_language ) -{ - if ( mJsObject ) - mJsObject->setAgentLanguage( QString::fromStdString( agent_language ) ); -} - -void LLWebPage::setAgentRegion( const std::string& agent_region ) -{ - if ( mJsObject ) - mJsObject->setAgentRegion( QString::fromStdString( agent_region ) ); -} - -void LLWebPage::setAgentLocation( double x, double y, double z ) -{ - if ( mJsObject ) - { - QVariantMap location; - location["x"] = x; - location["y"] = y; - location["z"] = z; - mJsObject->setAgentLocation( location ); - } -} - -void LLWebPage::setAgentGlobalLocation( double x, double y, double z ) -{ - if ( mJsObject ) - { - QVariantMap global_location; - global_location["x"] = x; - global_location["y"] = y; - global_location["z"] = z; - mJsObject->setAgentGlobalLocation( global_location ); - } -} - -void LLWebPage::setAgentOrientation( double angle ) -{ - if ( mJsObject ) - { - mJsObject->setAgentOrientation( angle ); - } -} - -void LLWebPage::setAgentMaturity( const std::string& agent_maturity ) -{ - if ( mJsObject ) - mJsObject->setAgentMaturity( QString::fromStdString( agent_maturity ) ); -} - -void LLWebPage::emitLocation() -{ - if ( mJsObject ) - mJsObject->emitLocation(); -} - -void LLWebPage::emitMaturity() -{ - if ( mJsObject ) - mJsObject->emitMaturity(); -} - -void LLWebPage::emitLanguage() -{ - if ( mJsObject ) - mJsObject->emitLanguage(); -} - -void LLWebPage::setPageZoomFactor( double factor ) -{ - if ( webView ) - { - webView->setZoomFactor( factor ); - } -} \ No newline at end of file diff --git a/indra/llqtwebkit/llwebpage.h b/indra/llqtwebkit/llwebpage.h deleted file mode 100644 index 1a882254f1..0000000000 --- a/indra/llqtwebkit/llwebpage.h +++ /dev/null @@ -1,108 +0,0 @@ -/* Copyright (c) 2006-2010, Linden Research, Inc. - * - * LLQtWebKit Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in GPL-license.txt in this distribution, or online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - */ - -#ifndef LLWEBPAGE_H -#define LLWEBPAGE_H - -class QGraphicsWebView; -#include -#include "llqtwebkit.h" - -class LLEmbeddedBrowserWindow; -class LLJsObject; - -class LLWebPage : public QWebPage -{ - Q_OBJECT - - public: - LLWebPage(QObject *parent = 0); - ~LLWebPage(); - - LLEmbeddedBrowserWindow *window; - bool event(QEvent *event); - - QGraphicsWebView *webView; - - void setHostLanguage(const std::string& host_language); - virtual bool supportsExtension(QWebPage::Extension extension) const; - virtual bool extension(Extension extension, const ExtensionOption* option, ExtensionReturn* output); - - // set the regex used to determine if a page is trusted or not - void setWhiteListRegex( const std::string& regex ); - - // check the whitelist and update browser config as appropriate - void checkWhiteList( const QUrl& url ); - - // code to change settings if page is known to be trusted goes here - void configureTrustedPage( bool is_trusted ); - - // Second Life specific functions - void setAgentRegion( const std::string& agent_region ); - void setAgentLocation( double x, double y, double z ); - void setAgentGlobalLocation( double x, double y, double z ); - void setAgentOrientation( double angle ); - void setSLObjectEnabled( bool enabled ); - void setAgentLanguage( const std::string& agent_language ); - void setAgentMaturity( const std::string& agent_maturity ); - void emitLocation(); - void emitMaturity(); - void emitLanguage(); - - void setPageZoomFactor( double factor ); - - protected: - bool acceptNavigationRequest(QWebFrame* frame, const QNetworkRequest& request, NavigationType type); - - public slots: - void loadProgressSlot(int progress); - void linkHoveredSlot(const QString &link, const QString &title, const QString &textContent); - void statusBarMessageSlot(const QString &); - void titleChangedSlot(const QString &); - void urlChangedSlot(const QUrl& url); - void loadStarted(); - void loadFinished(bool ok); - void windowCloseRequested(); - void geometryChangeRequested(const QRect& geom); - - private slots: - void extendNavigatorObject(); - - protected: - QString chooseFile(QWebFrame* parentFrame, const QString& suggestedFile); - void javaScriptAlert(QWebFrame* frame, const QString& msg); - bool javaScriptConfirm(QWebFrame* frame, const QString& msg); - bool javaScriptPrompt(QWebFrame* frame, const QString& msg, const QString& defaultValue, QString* result); - QWebPage *createWindow(WebWindowType type); - - private: - bool checkRegex( const QUrl& url ); - QPoint currentPoint; - std::string mHostLanguage; - std::string mWhiteListRegex; - LLJsObject* mJsObject; -}; - -#endif diff --git a/indra/llqtwebkit/llwebpageopenshim.cpp b/indra/llqtwebkit/llwebpageopenshim.cpp deleted file mode 100644 index af9627907f..0000000000 --- a/indra/llqtwebkit/llwebpageopenshim.cpp +++ /dev/null @@ -1,176 +0,0 @@ -/* Copyright (c) 2006-2010, Linden Research, Inc. - * - * LLQtWebKit Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in GPL-license.txt in this distribution, or online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - */ - -#include "llwebpageopenshim.h" - -#include -#include -#include -#include - -#include "llqtwebkit.h" -#include "llembeddedbrowserwindow.h" -#include "llembeddedbrowserwindow_p.h" - -LLWebPageOpenShim::LLWebPageOpenShim(LLEmbeddedBrowserWindow *in_window, QObject *parent) - : QWebPage(parent) - , window(in_window) - , mOpeningSelf(false) - , mGeometryChangeRequested(false) - , mHasSentUUID(false) -{ -// qDebug() << "LLWebPageOpenShim created"; - - connect(this, SIGNAL(windowCloseRequested()), - this, SLOT(windowCloseRequested())); - connect(this, SIGNAL(geometryChangeRequested(const QRect&)), - this, SLOT(geometryChangeRequested(const QRect&))); - - // Create a unique UUID for this proxy - mUUID = llToStdString(QUuid::createUuid().toString()); - - // mTarget starts out as the empty string, which is what we want. -} - -LLWebPageOpenShim::~LLWebPageOpenShim() -{ -// qDebug() << "LLWebPageOpenShim destroyed"; -} - -void LLWebPageOpenShim::windowCloseRequested() -{ -// qDebug() << "LLWebPageOpenShim::windowCloseRequested"; - if(window) - { - LLEmbeddedBrowserWindowEvent event(window->getWindowId()); - event.setStringValue(mUUID); - window->d->mEventEmitter.update(&LLEmbeddedBrowserWindowObserver::onWindowCloseRequested, event); - } -} - -void LLWebPageOpenShim::geometryChangeRequested(const QRect& geom) -{ -// qDebug() << "LLWebPageOpenShim::geometryChangeRequested: " << geom ; - - // This seems to happen before acceptNavigationRequest is called. If this is the case, delay sending the message until afterwards. - - if(window && mHasSentUUID) - { - LLEmbeddedBrowserWindowEvent event(window->getWindowId()); - event.setStringValue(mUUID); - event.setRectValue(geom.x(), geom.y(), geom.width(), geom.height()); - window->d->mEventEmitter.update(&LLEmbeddedBrowserWindowObserver::onWindowGeometryChangeRequested, event); - } - else - { - mGeometry = geom; - mGeometryChangeRequested = true; - } - -} - -bool LLWebPageOpenShim::matchesTarget(const std::string target) -{ - return (target == mTarget); -} - -bool LLWebPageOpenShim::matchesUUID(const std::string uuid) -{ - return (uuid == mUUID); -} - -void LLWebPageOpenShim::setProxy(const std::string &target, const std::string &uuid) -{ - mTarget = target; - mUUID = uuid; - - mHasSentUUID = false; - - mOpeningSelf = true; - - mainFrame()->evaluateJavaScript(QString("window.open("", \"%1\");").arg( QString::fromStdString(target) )); -} - -bool LLWebPageOpenShim::acceptNavigationRequest(QWebFrame* frame, const QNetworkRequest& request, NavigationType type) -{ - Q_UNUSED(type); - if (!window) - { - return false; - } - - if(mOpeningSelf) - { - qDebug() << "LLWebPageOpenShim::acceptNavigationRequest: reopening self to set target name."; - return true; - } - -#if 0 - qDebug() << "LLWebPageOpenShim::acceptNavigationRequest called, NavigationType is " << type - << ", web frame is " << frame - << ", frame->page is " << frame->page() - << ", url is " << request.url() - << ", frame name is " << frame->frameName() - ; -#endif - - if (request.url().scheme() == QString("file")) - { - // For some reason, I'm seeing a spurious call to this function with a file:/// URL that points to the current working directory. - // Ignoring file:/// URLs here isn't a perfect solution (since it could potentially break content in local HTML files), - // but it's the best I could come up with for now. - - return false; - } - - // The name of the incoming frame has been set to the link target that was used when opening this window. - std::string click_href = llToStdString(request.url()); - mTarget = llToStdString(frame->frameName()); - - // build event based on the data we have and emit it - LLEmbeddedBrowserWindowEvent event( window->getWindowId()); - event.setEventUri(click_href); - event.setStringValue(mTarget); - event.setStringValue2(mUUID); - - window->d->mEventEmitter.update( &LLEmbeddedBrowserWindowObserver::onClickLinkHref, event ); - - mHasSentUUID = true; - - if(mGeometryChangeRequested) - { - geometryChangeRequested(mGeometry); - mGeometryChangeRequested = false; - } - - return false; -} - -QWebPage *LLWebPageOpenShim::createWindow(WebWindowType type) -{ - Q_UNUSED(type); - - return this; -} diff --git a/indra/llqtwebkit/llwebpageopenshim.h b/indra/llqtwebkit/llwebpageopenshim.h deleted file mode 100644 index 322f832ce0..0000000000 --- a/indra/llqtwebkit/llwebpageopenshim.h +++ /dev/null @@ -1,63 +0,0 @@ -/* Copyright (c) 2006-2010, Linden Research, Inc. - * - * LLQtWebKit Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in GPL-license.txt in this distribution, or online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - */ - -#ifndef LLWEBPAGEOPENSHIM_H -#define LLWEBPAGEOPENSHIM_H - -#include - -class LLEmbeddedBrowserWindow; -class LLWebPageOpenShim : public QWebPage -{ - Q_OBJECT - - public: - LLWebPageOpenShim(LLEmbeddedBrowserWindow *in_window, QObject *parent = 0); - ~LLWebPageOpenShim(); - LLEmbeddedBrowserWindow *window; - bool matchesTarget(const std::string target); - bool matchesUUID(const std::string uuid); - void setProxy(const std::string &target, const std::string &uuid); - - public slots: - void windowCloseRequested(); - void geometryChangeRequested(const QRect& geom); - - protected: - bool acceptNavigationRequest(QWebFrame* frame, const QNetworkRequest& request, NavigationType type); - QWebPage *createWindow(WebWindowType type); - - private: - std::string mUUID; - std::string mTarget; - bool mOpeningSelf; - bool mGeometryChangeRequested; - bool mHasSentUUID; - QRect mGeometry; - -}; - -#endif - diff --git a/indra/llqtwebkit/passworddialog.ui b/indra/llqtwebkit/passworddialog.ui deleted file mode 100644 index 033514eff8..0000000000 --- a/indra/llqtwebkit/passworddialog.ui +++ /dev/null @@ -1,137 +0,0 @@ - - - PasswordDialog - - - - 0 - 0 - 394 - 183 - - - - Dialog - - - - - - Qt::Vertical - - - - 20 - 12 - - - - - - - - - - - true - - - - - - - - 32 - 32 - - - - icon - - - - - - - Qt::Vertical - - - - 20 - 13 - - - - - - - - User name: - - - - - - - - - - Password: - - - - - - - QLineEdit::Password - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - - - buttonBox - accepted() - PasswordDialog - accept() - - - 248 - 254 - - - 157 - 274 - - - - - buttonBox - rejected() - PasswordDialog - reject() - - - 316 - 260 - - - 286 - 274 - - - - - diff --git a/indra/llqtwebkit/pstdint.h b/indra/llqtwebkit/pstdint.h deleted file mode 100644 index b36f63db3a..0000000000 --- a/indra/llqtwebkit/pstdint.h +++ /dev/null @@ -1,728 +0,0 @@ -/* A portable stdint.h - **************************************************************************** - * BSD License: - **************************************************************************** - * - * Copyright (c) 2005-2007 Paul Hsieh - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - **************************************************************************** - * - * Version 0.1.10 - * - * The ANSI C standard committee, for the C99 standard, specified the - * inclusion of a new standard include file called stdint.h. This is - * a very useful and long desired include file which contains several - * very precise definitions for integer scalar types that is - * critically important for making portable several classes of - * applications including cryptography, hashing, variable length - * integer libraries and so on. But for most developers its likely - * useful just for programming sanity. - * - * The problem is that most compiler vendors have decided not to - * implement the C99 standard, and the next C++ language standard - * (which has a lot more mindshare these days) will be a long time in - * coming and its unknown whether or not it will include stdint.h or - * how much adoption it will have. Either way, it will be a long time - * before all compilers come with a stdint.h and it also does nothing - * for the extremely large number of compilers available today which - * do not include this file, or anything comparable to it. - * - * So that's what this file is all about. Its an attempt to build a - * single universal include file that works on as many platforms as - * possible to deliver what stdint.h is supposed to. A few things - * that should be noted about this file: - * - * 1) It is not guaranteed to be portable and/or present an identical - * interface on all platforms. The extreme variability of the - * ANSI C standard makes this an impossibility right from the - * very get go. Its really only meant to be useful for the vast - * majority of platforms that possess the capability of - * implementing usefully and precisely defined, standard sized - * integer scalars. Systems which are not intrinsically 2s - * complement may produce invalid constants. - * - * 2) There is an unavoidable use of non-reserved symbols. - * - * 3) Other standard include files are invoked. - * - * 4) This file may come in conflict with future platforms that do - * include stdint.h. The hope is that one or the other can be - * used with no real difference. - * - * 5) In the current verison, if your platform can't represent - * int32_t, int16_t and int8_t, it just dumps out with a compiler - * error. - * - * 6) 64 bit integers may or may not be defined. Test for their - * presence with the test: #ifdef INT64_MAX or #ifdef UINT64_MAX. - * Note that this is different from the C99 specification which - * requires the existence of 64 bit support in the compiler. If - * this is not defined for your platform, yet it is capable of - * dealing with 64 bits then it is because this file has not yet - * been extended to cover all of your system's capabilities. - * - * 7) (u)intptr_t may or may not be defined. Test for its presence - * with the test: #ifdef PTRDIFF_MAX. If this is not defined - * for your platform, then it is because this file has not yet - * been extended to cover all of your system's capabilities, not - * because its optional. - * - * 8) The following might not been defined even if your platform is - * capable of defining it: - * - * WCHAR_MIN - * WCHAR_MAX - * (u)int64_t - * PTRDIFF_MIN - * PTRDIFF_MAX - * (u)intptr_t - * - * 9) The following have not been defined: - * - * WINT_MIN - * WINT_MAX - * - * 10) The criteria for defining (u)int_least(*)_t isn't clear, - * except for systems which don't have a type that precisely - * defined 8, 16, or 32 bit types (which this include file does - * not support anyways). Default definitions have been given. - * - * 11) The criteria for defining (u)int_fast(*)_t isn't something I - * would trust to any particular compiler vendor or the ANSI C - * committee. It is well known that "compatible systems" are - * commonly created that have very different performance - * characteristics from the systems they are compatible with, - * especially those whose vendors make both the compiler and the - * system. Default definitions have been given, but its strongly - * recommended that users never use these definitions for any - * reason (they do *NOT* deliver any serious guarantee of - * improved performance -- not in this file, nor any vendor's - * stdint.h). - * - * 12) The following macros: - * - * PRINTF_INTMAX_MODIFIER - * PRINTF_INT64_MODIFIER - * PRINTF_INT32_MODIFIER - * PRINTF_INT16_MODIFIER - * PRINTF_LEAST64_MODIFIER - * PRINTF_LEAST32_MODIFIER - * PRINTF_LEAST16_MODIFIER - * PRINTF_INTPTR_MODIFIER - * - * are strings which have been defined as the modifiers required - * for the "d", "u" and "x" printf formats to correctly output - * (u)intmax_t, (u)int64_t, (u)int32_t, (u)int16_t, (u)least64_t, - * (u)least32_t, (u)least16_t and (u)intptr_t types respectively. - * PRINTF_INTPTR_MODIFIER is not defined for some systems which - * provide their own stdint.h. PRINTF_INT64_MODIFIER is not - * defined if INT64_MAX is not defined. These are an extension - * beyond what C99 specifies must be in stdint.h. - * - * In addition, the following macros are defined: - * - * PRINTF_INTMAX_HEX_WIDTH - * PRINTF_INT64_HEX_WIDTH - * PRINTF_INT32_HEX_WIDTH - * PRINTF_INT16_HEX_WIDTH - * PRINTF_INT8_HEX_WIDTH - * PRINTF_INTMAX_DEC_WIDTH - * PRINTF_INT64_DEC_WIDTH - * PRINTF_INT32_DEC_WIDTH - * PRINTF_INT16_DEC_WIDTH - * PRINTF_INT8_DEC_WIDTH - * - * Which specifies the maximum number of characters required to - * print the number of that type in either hexadecimal or decimal. - * These are an extension beyond what C99 specifies must be in - * stdint.h. - * - * Compilers tested (all with 0 warnings at their highest respective - * settings): Borland Turbo C 2.0, WATCOM C/C++ 11.0 (16 bits and 32 - * bits), Microsoft Visual C++ 6.0 (32 bit), Microsoft Visual Studio - * .net (VC7), Intel C++ 4.0, GNU gcc v3.3.3 - * - * This file should be considered a work in progress. Suggestions for - * improvements, especially those which increase coverage are strongly - * encouraged. - * - * Acknowledgements - * - * The following people have made significant contributions to the - * development and testing of this file: - * - * Chris Howie - * John Steele Scott - * Dave Thorup - * - */ - -#include -#include -#include - -/* - * For gcc with _STDINT_H, fill in the PRINTF_INT*_MODIFIER macros, and - * do nothing else. On the Mac OS X version of gcc this is _STDINT_H_. - */ - -#if ((defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L) || (defined (__WATCOMC__) && (defined (_STDINT_H_INCLUDED) || __WATCOMC__ >= 1250)) || (defined(__GNUC__) && (defined(_STDINT_H) || defined(_STDINT_H_)) )) && !defined (_PSTDINT_H_INCLUDED) -#include -#define _PSTDINT_H_INCLUDED -# ifndef PRINTF_INT64_MODIFIER -# define PRINTF_INT64_MODIFIER "ll" -# endif -# ifndef PRINTF_INT32_MODIFIER -# define PRINTF_INT32_MODIFIER "l" -# endif -# ifndef PRINTF_INT16_MODIFIER -# define PRINTF_INT16_MODIFIER "h" -# endif -# ifndef PRINTF_INTMAX_MODIFIER -# define PRINTF_INTMAX_MODIFIER PRINTF_INT64_MODIFIER -# endif -# ifndef PRINTF_INT64_HEX_WIDTH -# define PRINTF_INT64_HEX_WIDTH "16" -# endif -# ifndef PRINTF_INT32_HEX_WIDTH -# define PRINTF_INT32_HEX_WIDTH "8" -# endif -# ifndef PRINTF_INT16_HEX_WIDTH -# define PRINTF_INT16_HEX_WIDTH "4" -# endif -# ifndef PRINTF_INT8_HEX_WIDTH -# define PRINTF_INT8_HEX_WIDTH "2" -# endif -# ifndef PRINTF_INT64_DEC_WIDTH -# define PRINTF_INT64_DEC_WIDTH "20" -# endif -# ifndef PRINTF_INT32_DEC_WIDTH -# define PRINTF_INT32_DEC_WIDTH "10" -# endif -# ifndef PRINTF_INT16_DEC_WIDTH -# define PRINTF_INT16_DEC_WIDTH "5" -# endif -# ifndef PRINTF_INT8_DEC_WIDTH -# define PRINTF_INT8_DEC_WIDTH "3" -# endif -# ifndef PRINTF_INTMAX_HEX_WIDTH -# define PRINTF_INTMAX_HEX_WIDTH PRINTF_INT64_HEX_WIDTH -# endif -# ifndef PRINTF_INTMAX_DEC_WIDTH -# define PRINTF_INTMAX_DEC_WIDTH PRINTF_INT64_DEC_WIDTH -# endif - -/* - * Something really weird is going on with Open Watcom. Just pull some of - * these duplicated definitions from Open Watcom's stdint.h file for now. - */ - -# if defined (__WATCOMC__) && __WATCOMC__ >= 1250 -# if !defined (INT64_C) -# define INT64_C(x) (x + (INT64_MAX - INT64_MAX)) -# endif -# if !defined (UINT64_C) -# define UINT64_C(x) (x + (UINT64_MAX - UINT64_MAX)) -# endif -# if !defined (INT32_C) -# define INT32_C(x) (x + (INT32_MAX - INT32_MAX)) -# endif -# if !defined (UINT32_C) -# define UINT32_C(x) (x + (UINT32_MAX - UINT32_MAX)) -# endif -# if !defined (INT16_C) -# define INT16_C(x) (x) -# endif -# if !defined (UINT16_C) -# define UINT16_C(x) (x) -# endif -# if !defined (INT8_C) -# define INT8_C(x) (x) -# endif -# if !defined (UINT8_C) -# define UINT8_C(x) (x) -# endif -# if !defined (UINT64_MAX) -# define UINT64_MAX 18446744073709551615ULL -# endif -# if !defined (INT64_MAX) -# define INT64_MAX 9223372036854775807LL -# endif -# if !defined (UINT32_MAX) -# define UINT32_MAX 4294967295UL -# endif -# if !defined (INT32_MAX) -# define INT32_MAX 2147483647L -# endif -# if !defined (INTMAX_MAX) -# define INTMAX_MAX INT64_MAX -# endif -# if !defined (INTMAX_MIN) -# define INTMAX_MIN INT64_MIN -# endif -# endif -#endif - -#ifndef _PSTDINT_H_INCLUDED -#define _PSTDINT_H_INCLUDED - -#ifndef SIZE_MAX -# define SIZE_MAX (~(size_t)0) -#endif - -/* - * Deduce the type assignments from limits.h under the assumption that - * integer sizes in bits are powers of 2, and follow the ANSI - * definitions. - */ - -#ifndef UINT8_MAX -# define UINT8_MAX 0xff -#endif -#ifndef uint8_t -# if (UCHAR_MAX == UINT8_MAX) || defined (S_SPLINT_S) - typedef unsigned char uint8_t; -# define UINT8_C(v) ((uint8_t) v) -# else -# error "Platform not supported" -# endif -#endif - -#ifndef INT8_MAX -# define INT8_MAX 0x7f -#endif -#ifndef INT8_MIN -# define INT8_MIN INT8_C(0x80) -#endif -#ifndef int8_t -# if (SCHAR_MAX == INT8_MAX) || defined (S_SPLINT_S) - typedef signed char int8_t; -# define INT8_C(v) ((int8_t) v) -# else -# error "Platform not supported" -# endif -#endif - -#ifndef UINT16_MAX -# define UINT16_MAX 0xffff -#endif -#ifndef uint16_t -#if (UINT_MAX == UINT16_MAX) || defined (S_SPLINT_S) - typedef unsigned int uint16_t; -# ifndef PRINTF_INT16_MODIFIER -# define PRINTF_INT16_MODIFIER "" -# endif -# define UINT16_C(v) ((uint16_t) (v)) -#elif (USHRT_MAX == UINT16_MAX) - typedef unsigned short uint16_t; -# define UINT16_C(v) ((uint16_t) (v)) -# ifndef PRINTF_INT16_MODIFIER -# define PRINTF_INT16_MODIFIER "h" -# endif -#else -#error "Platform not supported" -#endif -#endif - -#ifndef INT16_MAX -# define INT16_MAX 0x7fff -#endif -#ifndef INT16_MIN -# define INT16_MIN INT16_C(0x8000) -#endif -#ifndef int16_t -#if (INT_MAX == INT16_MAX) || defined (S_SPLINT_S) - typedef signed int int16_t; -# define INT16_C(v) ((int16_t) (v)) -# ifndef PRINTF_INT16_MODIFIER -# define PRINTF_INT16_MODIFIER "" -# endif -#elif (SHRT_MAX == INT16_MAX) - typedef signed short int16_t; -# define INT16_C(v) ((int16_t) (v)) -# ifndef PRINTF_INT16_MODIFIER -# define PRINTF_INT16_MODIFIER "h" -# endif -#else -#error "Platform not supported" -#endif -#endif - -#ifndef UINT32_MAX -# define UINT32_MAX (0xffffffffUL) -#endif -#ifndef uint32_t -#if (ULONG_MAX == UINT32_MAX) || defined (S_SPLINT_S) - typedef unsigned long uint32_t; -# define UINT32_C(v) v ## UL -# ifndef PRINTF_INT32_MODIFIER -# define PRINTF_INT32_MODIFIER "l" -# endif -#elif (UINT_MAX == UINT32_MAX) - typedef unsigned int uint32_t; -# ifndef PRINTF_INT32_MODIFIER -# define PRINTF_INT32_MODIFIER "" -# endif -# define UINT32_C(v) v ## U -#elif (USHRT_MAX == UINT32_MAX) - typedef unsigned short uint32_t; -# define UINT32_C(v) ((unsigned short) (v)) -# ifndef PRINTF_INT32_MODIFIER -# define PRINTF_INT32_MODIFIER "" -# endif -#else -#error "Platform not supported" -#endif -#endif - -#ifndef INT32_MAX -# define INT32_MAX (0x7fffffffL) -#endif -#ifndef INT32_MIN -# define INT32_MIN INT32_C(0x80000000) -#endif -#ifndef int32_t -#if (LONG_MAX == INT32_MAX) || defined (S_SPLINT_S) - typedef signed long int32_t; -# define INT32_C(v) v ## L -# ifndef PRINTF_INT32_MODIFIER -# define PRINTF_INT32_MODIFIER "l" -# endif -#elif (INT_MAX == INT32_MAX) - typedef signed int int32_t; -# define INT32_C(v) v -# ifndef PRINTF_INT32_MODIFIER -# define PRINTF_INT32_MODIFIER "" -# endif -#elif (SHRT_MAX == INT32_MAX) - typedef signed short int32_t; -# define INT32_C(v) ((short) (v)) -# ifndef PRINTF_INT32_MODIFIER -# define PRINTF_INT32_MODIFIER "" -# endif -#else -#error "Platform not supported" -#endif -#endif - -/* - * The macro stdint_int64_defined is temporarily used to record - * whether or not 64 integer support is available. It must be - * defined for any 64 integer extensions for new platforms that are - * added. - */ - -#undef stdint_int64_defined -#if (defined(__STDC__) && defined(__STDC_VERSION__)) || defined (S_SPLINT_S) -# if (__STDC__ && __STDC_VERSION >= 199901L) || defined (S_SPLINT_S) -# define stdint_int64_defined - typedef long long int64_t; - typedef unsigned long long uint64_t; -# define UINT64_C(v) v ## ULL -# define INT64_C(v) v ## LL -# ifndef PRINTF_INT64_MODIFIER -# define PRINTF_INT64_MODIFIER "ll" -# endif -# endif -#endif - -#if !defined (stdint_int64_defined) -# if defined(__GNUC__) -# define stdint_int64_defined - __extension__ typedef long long int64_t; - __extension__ typedef unsigned long long uint64_t; -# define UINT64_C(v) v ## ULL -# define INT64_C(v) v ## LL -# ifndef PRINTF_INT64_MODIFIER -# define PRINTF_INT64_MODIFIER "ll" -# endif -# elif defined(__MWERKS__) || defined (__SUNPRO_C) || defined (__SUNPRO_CC) || defined (__APPLE_CC__) || defined (_LONG_LONG) || defined (_CRAYC) || defined (S_SPLINT_S) -# define stdint_int64_defined - typedef long long int64_t; - typedef unsigned long long uint64_t; -# define UINT64_C(v) v ## ULL -# define INT64_C(v) v ## LL -# ifndef PRINTF_INT64_MODIFIER -# define PRINTF_INT64_MODIFIER "ll" -# endif -# elif (defined(__WATCOMC__) && defined(__WATCOM_INT64__)) || (defined(_MSC_VER) && _INTEGRAL_MAX_BITS >= 64) || (defined (__BORLANDC__) && __BORLANDC__ > 0x460) || defined (__alpha) || defined (__DECC) -# define stdint_int64_defined - typedef __int64 int64_t; - typedef unsigned __int64 uint64_t; -# define UINT64_C(v) v ## UI64 -# define INT64_C(v) v ## I64 -# ifndef PRINTF_INT64_MODIFIER -# define PRINTF_INT64_MODIFIER "I64" -# endif -# endif -#endif - -#if !defined (LONG_LONG_MAX) && defined (INT64_C) -# define LONG_LONG_MAX INT64_C (9223372036854775807) -#endif -#ifndef ULONG_LONG_MAX -# define ULONG_LONG_MAX UINT64_C (18446744073709551615) -#endif - -#if !defined (INT64_MAX) && defined (INT64_C) -# define INT64_MAX INT64_C (9223372036854775807) -#endif -#if !defined (INT64_MIN) && defined (INT64_C) -# define INT64_MIN INT64_C (-9223372036854775808) -#endif -#if !defined (UINT64_MAX) && defined (INT64_C) -# define UINT64_MAX UINT64_C (18446744073709551615) -#endif - -/* - * Width of hexadecimal for number field. - */ - -#ifndef PRINTF_INT64_HEX_WIDTH -# define PRINTF_INT64_HEX_WIDTH "16" -#endif -#ifndef PRINTF_INT32_HEX_WIDTH -# define PRINTF_INT32_HEX_WIDTH "8" -#endif -#ifndef PRINTF_INT16_HEX_WIDTH -# define PRINTF_INT16_HEX_WIDTH "4" -#endif -#ifndef PRINTF_INT8_HEX_WIDTH -# define PRINTF_INT8_HEX_WIDTH "2" -#endif - -#ifndef PRINTF_INT64_DEC_WIDTH -# define PRINTF_INT64_DEC_WIDTH "20" -#endif -#ifndef PRINTF_INT32_DEC_WIDTH -# define PRINTF_INT32_DEC_WIDTH "10" -#endif -#ifndef PRINTF_INT16_DEC_WIDTH -# define PRINTF_INT16_DEC_WIDTH "5" -#endif -#ifndef PRINTF_INT8_DEC_WIDTH -# define PRINTF_INT8_DEC_WIDTH "3" -#endif - -/* - * Ok, lets not worry about 128 bit integers for now. Moore's law says - * we don't need to worry about that until about 2040 at which point - * we'll have bigger things to worry about. - */ - -#ifdef stdint_int64_defined - typedef int64_t intmax_t; - typedef uint64_t uintmax_t; -# define INTMAX_MAX INT64_MAX -# define INTMAX_MIN INT64_MIN -# define UINTMAX_MAX UINT64_MAX -# define UINTMAX_C(v) UINT64_C(v) -# define INTMAX_C(v) INT64_C(v) -# ifndef PRINTF_INTMAX_MODIFIER -# define PRINTF_INTMAX_MODIFIER PRINTF_INT64_MODIFIER -# endif -# ifndef PRINTF_INTMAX_HEX_WIDTH -# define PRINTF_INTMAX_HEX_WIDTH PRINTF_INT64_HEX_WIDTH -# endif -# ifndef PRINTF_INTMAX_DEC_WIDTH -# define PRINTF_INTMAX_DEC_WIDTH PRINTF_INT64_DEC_WIDTH -# endif -#else - typedef int32_t intmax_t; - typedef uint32_t uintmax_t; -# define INTMAX_MAX INT32_MAX -# define UINTMAX_MAX UINT32_MAX -# define UINTMAX_C(v) UINT32_C(v) -# define INTMAX_C(v) INT32_C(v) -# ifndef PRINTF_INTMAX_MODIFIER -# define PRINTF_INTMAX_MODIFIER PRINTF_INT32_MODIFIER -# endif -# ifndef PRINTF_INTMAX_HEX_WIDTH -# define PRINTF_INTMAX_HEX_WIDTH PRINTF_INT32_HEX_WIDTH -# endif -# ifndef PRINTF_INTMAX_DEC_WIDTH -# define PRINTF_INTMAX_DEC_WIDTH PRINTF_INT32_DEC_WIDTH -# endif -#endif - -/* - * Because this file currently only supports platforms which have - * precise powers of 2 as bit sizes for the default integers, the - * least definitions are all trivial. Its possible that a future - * version of this file could have different definitions. - */ - -#ifndef stdint_least_defined - typedef int8_t int_least8_t; - typedef uint8_t uint_least8_t; - typedef int16_t int_least16_t; - typedef uint16_t uint_least16_t; - typedef int32_t int_least32_t; - typedef uint32_t uint_least32_t; -# define PRINTF_LEAST32_MODIFIER PRINTF_INT32_MODIFIER -# define PRINTF_LEAST16_MODIFIER PRINTF_INT16_MODIFIER -# define UINT_LEAST8_MAX UINT8_MAX -# define INT_LEAST8_MAX INT8_MAX -# define UINT_LEAST16_MAX UINT16_MAX -# define INT_LEAST16_MAX INT16_MAX -# define UINT_LEAST32_MAX UINT32_MAX -# define INT_LEAST32_MAX INT32_MAX -# define INT_LEAST8_MIN INT8_MIN -# define INT_LEAST16_MIN INT16_MIN -# define INT_LEAST32_MIN INT32_MIN -# ifdef stdint_int64_defined - typedef int64_t int_least64_t; - typedef uint64_t uint_least64_t; -# define PRINTF_LEAST64_MODIFIER PRINTF_INT64_MODIFIER -# define UINT_LEAST64_MAX UINT64_MAX -# define INT_LEAST64_MAX INT64_MAX -# define INT_LEAST64_MIN INT64_MIN -# endif -#endif -#undef stdint_least_defined - -/* - * The ANSI C committee pretending to know or specify anything about - * performance is the epitome of misguided arrogance. The mandate of - * this file is to *ONLY* ever support that absolute minimum - * definition of the fast integer types, for compatibility purposes. - * No extensions, and no attempt to suggest what may or may not be a - * faster integer type will ever be made in this file. Developers are - * warned to stay away from these types when using this or any other - * stdint.h. - */ - -typedef int_least8_t int_fast8_t; -typedef uint_least8_t uint_fast8_t; -typedef int_least16_t int_fast16_t; -typedef uint_least16_t uint_fast16_t; -typedef int_least32_t int_fast32_t; -typedef uint_least32_t uint_fast32_t; -#define UINT_FAST8_MAX UINT_LEAST8_MAX -#define INT_FAST8_MAX INT_LEAST8_MAX -#define UINT_FAST16_MAX UINT_LEAST16_MAX -#define INT_FAST16_MAX INT_LEAST16_MAX -#define UINT_FAST32_MAX UINT_LEAST32_MAX -#define INT_FAST32_MAX INT_LEAST32_MAX -#define INT_FAST8_MIN INT_LEAST8_MIN -#define INT_FAST16_MIN INT_LEAST16_MIN -#define INT_FAST32_MIN INT_LEAST32_MIN -#ifdef stdint_int64_defined - typedef int_least64_t int_fast64_t; - typedef uint_least64_t uint_fast64_t; -# define UINT_FAST64_MAX UINT_LEAST64_MAX -# define INT_FAST64_MAX INT_LEAST64_MAX -# define INT_FAST64_MIN INT_LEAST64_MIN -#endif - -#undef stdint_int64_defined - -/* - * Whatever piecemeal, per compiler thing we can do about the wchar_t - * type limits. - */ - -#if defined(__WATCOMC__) || defined(_MSC_VER) || defined (__GNUC__) -# include -# ifndef WCHAR_MIN -# define WCHAR_MIN 0 -# endif -# ifndef WCHAR_MAX -# define WCHAR_MAX ((wchar_t)-1) -# endif -#endif - -/* - * Whatever piecemeal, per compiler/platform thing we can do about the - * (u)intptr_t types and limits. - */ - -#if defined (_MSC_VER) && defined (_UINTPTR_T_DEFINED) -# define STDINT_H_UINTPTR_T_DEFINED -#endif - -#ifndef STDINT_H_UINTPTR_T_DEFINED -# if defined (__alpha__) || defined (__ia64__) || defined (__x86_64__) || defined (_WIN64) -# define stdint_intptr_bits 64 -# elif defined (__WATCOMC__) || defined (__TURBOC__) -# if defined(__TINY__) || defined(__SMALL__) || defined(__MEDIUM__) -# define stdint_intptr_bits 16 -# else -# define stdint_intptr_bits 32 -# endif -# elif defined (__i386__) || defined (_WIN32) || defined (WIN32) -# define stdint_intptr_bits 32 -# elif defined (__INTEL_COMPILER) -/* TODO -- what will Intel do about x86-64? */ -# endif - -# ifdef stdint_intptr_bits -# define stdint_intptr_glue3_i(a,b,c) a##b##c -# define stdint_intptr_glue3(a,b,c) stdint_intptr_glue3_i(a,b,c) -# ifndef PRINTF_INTPTR_MODIFIER -# define PRINTF_INTPTR_MODIFIER stdint_intptr_glue3(PRINTF_INT,stdint_intptr_bits,_MODIFIER) -# endif -# ifndef PTRDIFF_MAX -# define PTRDIFF_MAX stdint_intptr_glue3(INT,stdint_intptr_bits,_MAX) -# endif -# ifndef PTRDIFF_MIN -# define PTRDIFF_MIN stdint_intptr_glue3(INT,stdint_intptr_bits,_MIN) -# endif -# ifndef UINTPTR_MAX -# define UINTPTR_MAX stdint_intptr_glue3(UINT,stdint_intptr_bits,_MAX) -# endif -# ifndef INTPTR_MAX -# define INTPTR_MAX stdint_intptr_glue3(INT,stdint_intptr_bits,_MAX) -# endif -# ifndef INTPTR_MIN -# define INTPTR_MIN stdint_intptr_glue3(INT,stdint_intptr_bits,_MIN) -# endif -# ifndef INTPTR_C -# define INTPTR_C(x) stdint_intptr_glue3(INT,stdint_intptr_bits,_C)(x) -# endif -# ifndef UINTPTR_C -# define UINTPTR_C(x) stdint_intptr_glue3(UINT,stdint_intptr_bits,_C)(x) -# endif - typedef stdint_intptr_glue3(uint,stdint_intptr_bits,_t) uintptr_t; - typedef stdint_intptr_glue3( int,stdint_intptr_bits,_t) intptr_t; -# else -/* TODO -- This following is likely wrong for some platforms, and does - nothing for the definition of uintptr_t. */ - typedef ptrdiff_t intptr_t; -# endif -# define STDINT_H_UINTPTR_T_DEFINED -#endif - -/* - * Assumes sig_atomic_t is signed and we have a 2s complement machine. - */ - -#ifndef SIG_ATOMIC_MAX -# define SIG_ATOMIC_MAX ((((sig_atomic_t) 1) << (sizeof (sig_atomic_t)*CHAR_BIT-1)) - 1) -#endif - -#endif diff --git a/indra/llqtwebkit/qtwebkit_cookiejar/CMakeLists.txt b/indra/llqtwebkit/qtwebkit_cookiejar/CMakeLists.txt deleted file mode 100644 index 635765c83c..0000000000 --- a/indra/llqtwebkit/qtwebkit_cookiejar/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -# -*- cmake -*- - -add_subdirectory(src) diff --git a/indra/llqtwebkit/qtwebkit_cookiejar/autotest/trie/trie.pro b/indra/llqtwebkit/qtwebkit_cookiejar/autotest/trie/trie.pro deleted file mode 100644 index c031e19718..0000000000 --- a/indra/llqtwebkit/qtwebkit_cookiejar/autotest/trie/trie.pro +++ /dev/null @@ -1,15 +0,0 @@ -TEMPLATE = app -TARGET = -DEPENDPATH += . -INCLUDEPATH += . - -win32: CONFIG += console -mac:CONFIG -= app_bundle - -CONFIG += qtestlib - -include(../../src/src.pri) - -# Input -SOURCES += tst_trie.cpp -HEADERS += diff --git a/indra/llqtwebkit/qtwebkit_cookiejar/autotest/trie/tst_trie.cpp b/indra/llqtwebkit/qtwebkit_cookiejar/autotest/trie/tst_trie.cpp deleted file mode 100644 index e4bdc6d4ed..0000000000 --- a/indra/llqtwebkit/qtwebkit_cookiejar/autotest/trie/tst_trie.cpp +++ /dev/null @@ -1,270 +0,0 @@ -/* Copyright (c) 2006-2010, Linden Research, Inc. - * - * LLQtWebKit Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in GPL-license.txt in this distribution, or online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - */ - -#include -#include - -class tst_Trie : public QObject -{ - Q_OBJECT - -public slots: - void initTestCase(); - void cleanupTestCase(); - void init(); - void cleanup(); - -private slots: - void trie_data(); - void trie(); - - void insert_data(); - void insert(); - void clear(); - void find_data(); - void find(); - void remove_data(); - void remove(); - void all(); -}; - -// Subclass that exposes the protected functions. -class SubTrie : public Trie -{ -public: - -}; - -// This will be called before the first test function is executed. -// It is only called once. -void tst_Trie::initTestCase() -{ -} - -// This will be called after the last test function is executed. -// It is only called once. -void tst_Trie::cleanupTestCase() -{ -} - -// This will be called before each test function is executed. -void tst_Trie::init() -{ -} - -// This will be called after every test function. -void tst_Trie::cleanup() -{ -} - -void tst_Trie::trie_data() -{ -} - -void tst_Trie::trie() -{ - SubTrie t; - t.clear(); - QCOMPARE(t.find(QStringList()), QList()); - QCOMPARE(t.remove(QStringList(), -1), false); - QCOMPARE(t.all(), QList()); - t.insert(QStringList(), -1); -} - -void tst_Trie::insert_data() -{ -#if 0 - QTest::addColumn("key"); - QTest::addColumn("value"); - QTest::newRow("null") << QStringList() << T(); -#endif -} - -// public void insert(QStringList const& key, T value) -void tst_Trie::insert() -{ -#if 0 - QFETCH(QStringList, key); - QFETCH(T, value); - - SubTrie t>; - - t>.insert(key, value); -#endif - QSKIP("Test is not implemented.", SkipAll); -} - -// public void clear() -void tst_Trie::clear() -{ - SubTrie t; - t.insert(QStringList(), 0); - t.clear(); - QCOMPARE(t.find(QStringList()), QList()); - QCOMPARE(t.all(), QList()); -} - -Q_DECLARE_METATYPE(QStringList) -typedef QList IntList; -Q_DECLARE_METATYPE(IntList) -void tst_Trie::find_data() -{ - QTest::addColumn("keys"); - QTest::addColumn("values"); - QTest::addColumn("find"); - QTest::addColumn("found"); - - QTest::newRow("null") << QStringList() << IntList() << QStringList() << IntList(); - - QStringList wiki = (QStringList() << "t,e,a" << "i" << "t,e,n" << "i,n" << "i,n,n" << "t,o"); - IntList wikiNum = (IntList() << 3 << 11 << 12 << 5 << 9 << 7); - - QTest::newRow("wikipedia-0") - << wiki - << wikiNum - << (QStringList() << "t") - << (IntList()); - - QTest::newRow("wikipedia-1") - << wiki - << wikiNum - << (QStringList() << "t" << "o") - << (IntList() << 7); - - QTest::newRow("wikipedia-2") - << (wiki << "t,o") - << (wikiNum << 4) - << (QStringList() << "t" << "o") - << (IntList() << 7 << 4); - - QTest::newRow("wikipedia-3") - << wiki - << wikiNum - << (QStringList() << "i" << "n" << "n") - << (IntList() << 9); - -} - -// public QList const find(QStringList const& key) -void tst_Trie::find() -{ - QFETCH(QStringList, keys); - QFETCH(IntList, values); - QFETCH(QStringList, find); - QFETCH(IntList, found); - - SubTrie t; - for (int i = 0; i < keys.count(); ++i) - t.insert(keys[i].split(","), values[i]); - QCOMPARE(t.all(), values); - QCOMPARE(t.find(find), found); -} - -void tst_Trie::remove_data() -{ - QTest::addColumn("keys"); - QTest::addColumn("values"); - QTest::addColumn("removeKey"); - QTest::addColumn("removeValue"); - QTest::addColumn("removed"); - - QTest::newRow("null") << QStringList() << IntList() << QStringList() << -1 << false; - - QStringList wiki = (QStringList() << "t,e,a" << "i" << "t,e,n" << "i,n" << "i,n,n" << "t,o"); - IntList wikiNum = (IntList() << 3 << 11 << 12 << 5 << 9 << 7); - - QTest::newRow("valid key-0") - << wiki - << wikiNum - << (QStringList() << "t") - << -1 - << false; - - QTest::newRow("valid key-1") - << wiki - << wikiNum - << (QStringList() << "t" << "o") - << -1 - << false; - - QTest::newRow("valid key-2") - << wiki - << wikiNum - << (QStringList() << "t" << "o" << "w") - << 2 - << false; - - QTest::newRow("valid key-3") - << wiki - << wikiNum - << (QStringList() << "t" << "o") - << 7 - << true; - - QTest::newRow("valid key-4") - << wiki - << wikiNum - << (QStringList() << "i" << "n") - << 3 - << false; - - QTest::newRow("valid key-5") - << wiki - << wikiNum - << (QStringList() << "i" << "n") - << 5 - << true; - -} - -// public bool remove(QStringList const& key, T value) -void tst_Trie::remove() -{ - QFETCH(QStringList, keys); - QFETCH(IntList, values); - QFETCH(QStringList, removeKey); - QFETCH(int, removeValue); - QFETCH(bool, removed); - - SubTrie t; - for (int i = 0; i < keys.count(); ++i) - t.insert(keys[i].split(","), values[i]); - QCOMPARE(t.all(), values); - QCOMPARE(t.remove(removeKey, removeValue), removed); - if (removed) - values.removeOne(removeValue); - QCOMPARE(t.all(), values); -} - -void tst_Trie::all() -{ - SubTrie t; - // hmm everyone else tests this it seems - QSKIP("Test is not implemented.", SkipAll); -} - -QTEST_MAIN(tst_Trie) -#include "tst_trie.moc" - diff --git a/indra/llqtwebkit/qtwebkit_cookiejar/benchmark/networkcookiejar/cookiejar.pro b/indra/llqtwebkit/qtwebkit_cookiejar/benchmark/networkcookiejar/cookiejar.pro deleted file mode 100644 index 350fbc0f6e..0000000000 --- a/indra/llqtwebkit/qtwebkit_cookiejar/benchmark/networkcookiejar/cookiejar.pro +++ /dev/null @@ -1,17 +0,0 @@ -TEMPLATE = app -TARGET = -DEPENDPATH += . -INCLUDEPATH += . - -win32: CONFIG += console -mac:CONFIG -= app_bundle - -CONFIG += qtestlib - -include(../../src/src.pri) -#include(../../../dev/code/webweaver/src/iris.pri) -#include(../../../dev/arora/src/src.pri) - -# Input -SOURCES += main.cpp -HEADERS += diff --git a/indra/llqtwebkit/qtwebkit_cookiejar/benchmark/networkcookiejar/main.cpp b/indra/llqtwebkit/qtwebkit_cookiejar/benchmark/networkcookiejar/main.cpp deleted file mode 100644 index 863d6b0bec..0000000000 --- a/indra/llqtwebkit/qtwebkit_cookiejar/benchmark/networkcookiejar/main.cpp +++ /dev/null @@ -1,159 +0,0 @@ -/* Copyright (c) 2006-2010, Linden Research, Inc. - * - * LLQtWebKit Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in GPL-license.txt in this distribution, or online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - */ - -#include -#include -#include - -class CookieJarBenchmark: public QObject { - Q_OBJECT - -private slots: - void setCookiesFromUrl(); - void cookiesForUrl(); - void player(); - -private: - QNetworkCookieJar *getJar(bool populate = true); - QList generateCookies(int size); -}; - -QNetworkCookieJar *CookieJarBenchmark::getJar(bool populate) -{ - QNetworkCookieJar *jar; - if (qgetenv("JAR") == "CookieJar") { - jar = new NetworkCookieJar(this); - } else { - jar = new QNetworkCookieJar(this); - } - if (!populate) - return jar; - - // pre populate - for (int i = 0; i < 500; ++i) { - QList cookies = generateCookies(1); - QUrl url = QUrl(QString("http://%1").arg(cookies[0].domain())); - jar->setCookiesFromUrl(cookies, url); - } - - return jar; -} - -QList CookieJarBenchmark::generateCookies(int size) -{ - QList cookies; - for (int i = 0; i < size; ++i) { - QNetworkCookie cookie; - - QString tld; - int c = qrand() % 3; - if (c == 0) tld = "com"; - if (c == 1) tld = "net"; - if (c == 2) tld = "org"; - - QString mid; - int size = qrand() % 6 + 3; - while (mid.count() < size) - mid += QString(QChar::fromAscii(qrand() % 26 + 65)); - - QString sub; - c = qrand() % 3; - if (c == 0) sub = "."; - if (c == 1) sub = ".www."; - if (c == 2) sub = ".foo"; - - cookie.setDomain(QString("%1%2.%3").arg(sub).arg(mid).arg(tld)); - cookie.setName("a"); - cookie.setValue("b"); - cookie.setPath("/"); - cookies.append(cookie); - } - return cookies; -} - -void CookieJarBenchmark::setCookiesFromUrl() -{ - QNetworkCookieJar *jar = getJar(); - QList cookies = generateCookies(1); - QUrl url = QUrl(QString("http://%1").arg(cookies[0].domain())); - QBENCHMARK { - jar->setCookiesFromUrl(cookies, url); - } - delete jar; -} - -void CookieJarBenchmark::cookiesForUrl() -{ - QNetworkCookieJar *jar = getJar(); - QList cookies = generateCookies(1); - cookies[0].setDomain("www.foo.tld"); - QUrl url = QUrl("http://www.foo.tld"); - //QUrl url = QUrl(QString("http://foo%1/").arg(cookies[0].domain())); - jar->setCookiesFromUrl(cookies, url); - //qDebug() << cookies << url; - int c = 0; - QBENCHMARK { - c += jar->cookiesForUrl(url).count(); - } - delete jar; -} - -// Grab the cookie.log file from the manualtest/browser directory -void CookieJarBenchmark::player() -{ - QBENCHMARK { - QFile file("cookie.log"); - file.open(QFile::ReadOnly); - QDataStream stream(&file); - QNetworkCookieJar *jar = getJar(false); - while (!stream.atEnd()) { - QString command; - QUrl url; - stream >> command; - stream >> url; - //qDebug() << command << url; - if (command == "cookiesForUrl") { - jar->cookiesForUrl(url); - } - if (command == "setCookiesFromUrl") { - QByteArray data; - stream >> data; - QDataStream dstream(&data, QIODevice::ReadWrite); - qint32 c; - dstream >> c; - QList cookies; - for (int i = 0; i < c; ++i) { - QByteArray text; - dstream >> text; - cookies += QNetworkCookie::parseCookies(text); - } - jar->setCookiesFromUrl(cookies, url); - } - } - } -} - -QTEST_MAIN(CookieJarBenchmark) -#include "main.moc" diff --git a/indra/llqtwebkit/qtwebkit_cookiejar/manualtest/browser/browser.pro b/indra/llqtwebkit/qtwebkit_cookiejar/manualtest/browser/browser.pro deleted file mode 100644 index a363bbefce..0000000000 --- a/indra/llqtwebkit/qtwebkit_cookiejar/manualtest/browser/browser.pro +++ /dev/null @@ -1,11 +0,0 @@ -###################################################################### -# Automatically generated by qmake (2.01a) Wed Jan 7 13:19:00 2009 -###################################################################### - -TEMPLATE = app -TARGET = -DEPENDPATH += . -INCLUDEPATH += . -include(../../src/src.pri) -# Input -SOURCES += main.cpp diff --git a/indra/llqtwebkit/qtwebkit_cookiejar/manualtest/browser/main.cpp b/indra/llqtwebkit/qtwebkit_cookiejar/manualtest/browser/main.cpp deleted file mode 100644 index 6d21759fc4..0000000000 --- a/indra/llqtwebkit/qtwebkit_cookiejar/manualtest/browser/main.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/* Copyright (c) 2006-2010, Linden Research, Inc. - * - * LLQtWebKit Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in GPL-license.txt in this distribution, or online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - */ - -#include -#include -#include -#include - -QFile file; -QDataStream stream; - -class CookieLog : public NetworkCookieJar { - - Q_OBJECT - -public: - CookieLog(QObject *parent = 0) : NetworkCookieJar(parent) - { - file.setFileName("cookie.log"); - file.open(QFile::WriteOnly); - stream.setDevice(&file); - }; - - virtual QList cookiesForUrl(const QUrl & url) const - { - stream << QString("cookiesForUrl") << url; - QList cookies = NetworkCookieJar::cookiesForUrl(url); - //stream << "#" << cookies; - file.flush(); - return cookies; - } - - virtual bool setCookiesFromUrl(const QList &cookieList, const QUrl &url) - { - QByteArray data; - QDataStream dstream(&data, QIODevice::ReadWrite); - qint32 c = cookieList.count(); - dstream << c; - qDebug() << cookieList.count(); - for (int i = 0; i < c; ++i) - dstream << cookieList[i].toRawForm(); - dstream.device()->close(); - stream << QString("setCookiesFromUrl") << url << data;// << cookieList; - bool set = NetworkCookieJar::setCookiesFromUrl(cookieList, url); - file.flush(); - return set; - } - -}; - -int main(int argc, char**argv) { - QApplication application(argc, argv); - QWebView view; - QString url = "http://www.google.com"; - if (argc > 1) - url = argv[1]; - view.load(QUrl(url)); - view.page()->networkAccessManager()->setCookieJar(new CookieLog()); - view.show(); - return application.exec(); -} - -#include "main.moc" diff --git a/indra/llqtwebkit/qtwebkit_cookiejar/manualtest/fuzz/fuzz.pro b/indra/llqtwebkit/qtwebkit_cookiejar/manualtest/fuzz/fuzz.pro deleted file mode 100644 index 0ad65f1bff..0000000000 --- a/indra/llqtwebkit/qtwebkit_cookiejar/manualtest/fuzz/fuzz.pro +++ /dev/null @@ -1,12 +0,0 @@ -###################################################################### -# Automatically generated by qmake (2.01a) Wed Jan 7 13:19:00 2009 -###################################################################### - -TEMPLATE = app -TARGET = -DEPENDPATH += . -INCLUDEPATH += . -include(../../src/src.pri) -DEFINES += QT_NO_CAST_FROM_ASCII QT_STRICT_ITERATOR -# Input -SOURCES += main.cpp diff --git a/indra/llqtwebkit/qtwebkit_cookiejar/manualtest/fuzz/main.cpp b/indra/llqtwebkit/qtwebkit_cookiejar/manualtest/fuzz/main.cpp deleted file mode 100644 index 28c79a1c2b..0000000000 --- a/indra/llqtwebkit/qtwebkit_cookiejar/manualtest/fuzz/main.cpp +++ /dev/null @@ -1,100 +0,0 @@ -/* Copyright (c) 2006-2010, Linden Research, Inc. - * - * LLQtWebKit Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in GPL-license.txt in this distribution, or online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - */ - -#include -#include - -QStringList generateKey() { - QStringList key; - int size = qrand() % 20 + 3; - while (key.count() < size) - key += QString(QChar::fromAscii(qrand() % 26 + 64)); - return key; -} - -void basicCheck() { - QStringList list; - list << QLatin1String("to") << QLatin1String("tea") << QLatin1String("ten") << QLatin1String("i") << QLatin1String("in") << QLatin1String("inn"); - Trie trie; - for (int i = 0; i < list.count(); ++i) { - QString key = list[i]; - QStringList keyList; - for (int j = 0; j < key.count(); ++j) - keyList.append(QString(key[j])); - trie.insert(keyList, i); - } - QByteArray data; - { - QDataStream stream(&data, QIODevice::ReadWrite); - stream << trie; - } - Trie trie2; - { - QDataStream stream(&data, QIODevice::ReadOnly); - stream >> trie2; - } - for (int i = 0; i < list.count(); ++i) { - QString key = list[i]; - QStringList keyList; - for (int j = 0; j < key.count(); ++j) - keyList.append(QString(key[j])); - QList x = trie2.find(keyList); - qDebug() << x.count() << i << x[0] << i; - qDebug() << trie2.remove(keyList, i); - qDebug() << trie2.find(keyList).count(); - } -} - -int main(int argc, char **argv) { - Q_UNUSED(argc); - Q_UNUSED(argv); - - basicCheck(); - - QHash hash; - Trie t; - while (hash.count() < 500) { - qDebug() << hash.count(); - QStringList key = generateKey(); - int value = qrand() % 50000; - hash[key.join(QLatin1String(","))] = value; - t.insert(key, value); - - QHashIterator i(hash); - while (i.hasNext()) { - i.next(); - if (t.find(i.key().split(QLatin1Char(','))).count() == 0) - qDebug() << i.key(); - Q_ASSERT(t.find(i.key().split(QLatin1Char(','))).count() > 0); - if (qrand() % 500 == 0) { - t.remove(i.key().split(QLatin1Char(',')), i.value()); - hash.remove(i.key()); - } - //cout << i.key() << ": " << i.value() << endl; - } - } - return 0; -} - diff --git a/indra/llqtwebkit/qtwebkit_cookiejar/src/CMakeLists.txt b/indra/llqtwebkit/qtwebkit_cookiejar/src/CMakeLists.txt deleted file mode 100644 index 20bacf3ebe..0000000000 --- a/indra/llqtwebkit/qtwebkit_cookiejar/src/CMakeLists.txt +++ /dev/null @@ -1,27 +0,0 @@ -# -*- cmake -*- - -project(networkcookiejar) - -set(networkcookiejar_SOURCE_FILES - networkcookiejar.cpp - ) - -set(networkcookiejar_HEADER_FILES - networkcookiejar.h - networkcookiejar_p.h - trie_p.h - twoleveldomains_p.h - - ) - -QT4_WRAP_CPP(networkcookiejar_HEADERS_MOC ${networkcookiejar_HEADER_FILES}) - -add_library(networkcookiejar - ${networkcookiejar_SOURCE_FILES} - ${networkcookiejar_HEADERS_MOC} - ${networkcookiejar_UI_MOC} -) - -add_dependencies(networkcookiejar prepare) - -target_link_libraries(networkcookiejar) \ No newline at end of file diff --git a/indra/llqtwebkit/qtwebkit_cookiejar/src/networkcookiejar.cpp b/indra/llqtwebkit/qtwebkit_cookiejar/src/networkcookiejar.cpp deleted file mode 100644 index 274d9e1c1c..0000000000 --- a/indra/llqtwebkit/qtwebkit_cookiejar/src/networkcookiejar.cpp +++ /dev/null @@ -1,444 +0,0 @@ -/* Copyright (c) 2006-2010, Linden Research, Inc. - * - * LLQtWebKit Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in GPL-license.txt in this distribution, or online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - */ - -#include "networkcookiejar.h" -#include "networkcookiejar_p.h" -#include "twoleveldomains_p.h" - -//#define NETWORKCOOKIEJAR_DEBUG - -#ifndef QT_NO_DEBUG -// ^ Prevent being left on in a released product by accident -// qDebug any cookies that are rejected for further inspection -#define NETWORKCOOKIEJAR_LOGREJECTEDCOOKIES -#include -#endif - -#include -#include - -#if defined(NETWORKCOOKIEJAR_DEBUG) -#include -#endif - - -NetworkCookieJar::NetworkCookieJar(QObject *parent) - : QNetworkCookieJar(parent) -{ - d = new NetworkCookieJarPrivate; -} - -NetworkCookieJar::~NetworkCookieJar() -{ - delete d; -} - -static QStringList splitHost(const QString &host) { - QStringList parts = host.split(QLatin1Char('.'), QString::KeepEmptyParts); - // Remove empty components that are on the start and end - while (!parts.isEmpty() && parts.last().isEmpty()) - parts.removeLast(); - while (!parts.isEmpty() && parts.first().isEmpty()) - parts.removeFirst(); - return parts; -} - -inline static bool shorterPaths(const QNetworkCookie &c1, const QNetworkCookie &c2) -{ - return c2.path().length() < c1.path().length(); -} - -QList NetworkCookieJar::cookiesForUrl(const QUrl &url) const -{ -#if defined(NETWORKCOOKIEJAR_DEBUG) - qDebug() << "NetworkCookieJar::" << __FUNCTION__ << url; -#endif - // Generate split host - QString host = url.host(); - if (url.scheme().toLower() == QLatin1String("file")) - host = QLatin1String("localhost"); - QStringList urlHost = splitHost(host); - - // Get all the cookies for url - QList cookies = d->tree.find(urlHost); - if (urlHost.count() > 2) { - int top = 2; - if (d->matchesBlacklist(urlHost.last())) - top = 3; - - urlHost.removeFirst(); - while (urlHost.count() >= top) { - cookies += d->tree.find(urlHost); - urlHost.removeFirst(); - } - } - - // Prevent doing anything expensive in the common case where - // there are no cookies to check - if (cookies.isEmpty()) - return cookies; - - QDateTime now = QDateTime::currentDateTime().toTimeSpec(Qt::UTC); - const QString urlPath = d->urlPath(url); - const bool isSecure = url.scheme().toLower() == QLatin1String("https"); - QList::iterator i = cookies.begin(); - for (; i != cookies.end();) { - if (!d->matchingPath(*i, urlPath)) { -#if defined(NETWORKCOOKIEJAR_DEBUG) - qDebug() << __FUNCTION__ << "Ignoring cookie, path does not match" << *i << urlPath; -#endif - i = cookies.erase(i); - continue; - } - if (!isSecure && i->isSecure()) { - i = cookies.erase(i); -#if defined(NETWORKCOOKIEJAR_DEBUG) - qDebug() << __FUNCTION__ << "Ignoring cookie, security mismatch" - << *i << !isSecure; -#endif - continue; - } - if (!i->isSessionCookie() && now > i->expirationDate()) { - // remove now (expensive short term) because there will - // probably be many more cookiesForUrl calls for this host - d->tree.remove(splitHost(i->domain()), *i); -#if defined(NETWORKCOOKIEJAR_DEBUG) - qDebug() << __FUNCTION__ << "Ignoring cookie, expiration issue" - << *i << now; -#endif - i = cookies.erase(i); - continue; - } - ++i; - } - - // shorter paths should go first - qSort(cookies.begin(), cookies.end(), shorterPaths); -#if defined(NETWORKCOOKIEJAR_DEBUG) - qDebug() << "NetworkCookieJar::" << __FUNCTION__ << "returning" << cookies.count(); - qDebug() << cookies; -#endif - return cookies; -} - -static const qint32 NetworkCookieJarMagic = 0xae; - -QByteArray NetworkCookieJar::saveState () const -{ - int version = 1; - QByteArray data; - QDataStream stream(&data, QIODevice::WriteOnly); - - stream << qint32(NetworkCookieJarMagic); - stream << qint32(version); - stream << d->tree; - return data; -} - -bool NetworkCookieJar::restoreState(const QByteArray &state) -{ - int version = 1; - QByteArray sd = state; - QDataStream stream(&sd, QIODevice::ReadOnly); - if (stream.atEnd()) - return false; - qint32 marker; - qint32 v; - stream >> marker; - stream >> v; - if (marker != NetworkCookieJarMagic || v != version) - return false; - stream >> d->tree; - if (stream.status() != QDataStream::Ok) { - d->tree.clear(); - return false; - } - return true; -} - -/*! - Remove any session cookies or cookies that have expired. - */ -void NetworkCookieJar::endSession() -{ - const QList cookies = d->tree.all(); - QDateTime now = QDateTime::currentDateTime().toTimeSpec(Qt::UTC); - QList::const_iterator i = cookies.constBegin(); - for (; i != cookies.constEnd();) { - if (i->isSessionCookie() - || (!i->isSessionCookie() && now > i->expirationDate())) { - d->tree.remove(splitHost(i->domain()), *i); - } - ++i; - } -} - -static const int maxCookiePathLength = 1024; - -bool NetworkCookieJar::setCookiesFromUrl(const QList &cookieList, const QUrl &url) -{ -#if defined(NETWORKCOOKIEJAR_DEBUG) - qDebug() << "NetworkCookieJar::" << __FUNCTION__ << url; - qDebug() << cookieList; -#endif - QDateTime now = QDateTime::currentDateTime().toTimeSpec(Qt::UTC); - bool changed = false; - QString fullUrlPath = url.path(); - QString defaultPath = fullUrlPath.mid(0, fullUrlPath.lastIndexOf(QLatin1Char('/')) + 1); - if (defaultPath.isEmpty()) - defaultPath = QLatin1Char('/'); - - QString urlPath = d->urlPath(url); - foreach (QNetworkCookie cookie, cookieList) { - if (cookie.path().length() > maxCookiePathLength) - continue; - - bool alreadyDead = !cookie.isSessionCookie() && cookie.expirationDate() < now; - - if (cookie.path().isEmpty()) { - cookie.setPath(defaultPath); - } - // Matching the behavior of Firefox, no path checking is done when setting cookies - // Safari does something even odder, when that paths don't match it keeps - // the cookie, but changes the paths to the default path -#if 0 - else if (!d->matchingPath(cookie, urlPath)) { -#ifdef NETWORKCOOKIEJAR_LOGREJECTEDCOOKIES - qDebug() << "NetworkCookieJar::" << __FUNCTION__ - << "Blocked cookie because: path doesn't match: " << cookie << url; -#endif - continue; - } -#endif - - if (cookie.domain().isEmpty()) { - QString host = url.host().toLower(); - if (host.isEmpty()) - continue; - cookie.setDomain(host); - } else if (!d->matchingDomain(cookie, url)) { -#ifdef NETWORKCOOKIEJAR_LOGREJECTEDCOOKIES - qDebug() << "NetworkCookieJar::" << __FUNCTION__ - << "Blocked cookie because: domain doesn't match: " << cookie << url; -#endif - continue; - } - - // replace/remove existing cookies - removeCookie(cookie); - - // Notify derived class - onCookieSetFromURL(cookie, url, alreadyDead); - - if (alreadyDead) - continue; - - changed = true; - d->tree.insert(splitHost(cookie.domain()), cookie); - } - - return changed; -} - -QList NetworkCookieJar::allCookies() const -{ -#if defined(NETWORKCOOKIEJAR_DEBUG) - qDebug() << "NetworkCookieJar::" << __FUNCTION__; -#endif - return d->tree.all(); -} - -void NetworkCookieJar::clearCookies() -{ -#if defined(NETWORKCOOKIEJAR_DEBUG) - qDebug() << "NetworkCookieJar::" << __FUNCTION__; -#endif - d->tree.clear(); -} - -void NetworkCookieJar::setCookies(const QList &cookieList) -{ -#if defined(NETWORKCOOKIEJAR_DEBUG) - qDebug() << "NetworkCookieJar::" << __FUNCTION__ << cookieList.count(); -#endif - - QDateTime now = QDateTime::currentDateTime().toTimeSpec(Qt::UTC); - - foreach (const QNetworkCookie &cookie, cookieList) - { - // If a matching cookie is already in the list, remove it. - removeCookie(cookie); - - if(!cookie.isSessionCookie() && cookie.expirationDate() < now) - { -#if defined(NETWORKCOOKIEJAR_DEBUG) - qDebug() << "NetworkCookieJar::" << __FUNCTION__ << "removing cookie: " << cookie; -#endif - // This cookie has expired -- don't re-add it - } - else - { -#if defined(NETWORKCOOKIEJAR_DEBUG) - qDebug() << "NetworkCookieJar::" << __FUNCTION__ << "adding cookie: " << cookie; -#endif - // this cookie has not expired -- save it - d->tree.insert(splitHost(cookie.domain()), cookie); - } - - } -} - -void NetworkCookieJar::setAllCookies(const QList &cookieList) -{ -#if defined(NETWORKCOOKIEJAR_DEBUG) - qDebug() << "NetworkCookieJar::" << __FUNCTION__ << cookieList.count(); -#endif - clearCookies(); - setCookies(cookieList); -} - -void NetworkCookieJar::removeCookie(const QNetworkCookie &cookie) -{ -#if defined(NETWORKCOOKIEJAR_DEBUG) - qDebug() << "NetworkCookieJar::" << __FUNCTION__ << "removing cookie: " << cookie; -#endif - - // If a cookie with the matching domain, path, and name exists in the cookiejar, remove it. - QString domain = cookie.domain(); - Q_ASSERT(!domain.isEmpty()); - QStringList urlHost = splitHost(domain); - - QList cookies = d->tree.find(urlHost); - QList::const_iterator it = cookies.constBegin(); - for (; it != cookies.constEnd(); ++it) - { - if (cookie.name() == it->name() && - domain == it->domain() && - cookie.path() == it->path()) - { -#if defined(NETWORKCOOKIEJAR_DEBUG) - qDebug() << "NetworkCookieJar::" << __FUNCTION__ << "found matching cookie: " << *it; -#endif - d->tree.remove(urlHost, *it); - break; - } - } -} - -void NetworkCookieJar::dump() -{ -#if defined(NETWORKCOOKIEJAR_DEBUG) - qDebug() << "NetworkCookieJar::" << __FUNCTION__ << "dumping all cookies: "; - QList cookies = allCookies(); - foreach (const QNetworkCookie &cookie, cookies) - { - qDebug() << " " << cookie; - } -#endif -} - -QString NetworkCookieJarPrivate::urlPath(const QUrl &url) const -{ - QString urlPath = url.path(); - if (!urlPath.endsWith(QLatin1Char('/'))) - urlPath += QLatin1Char('/'); - return urlPath; -} - -bool NetworkCookieJarPrivate::matchingPath(const QNetworkCookie &cookie, const QString &urlPath) const -{ - QString cookiePath = cookie.path(); - if (!cookiePath.endsWith(QLatin1Char('/'))) - cookiePath += QLatin1Char('/'); - - return urlPath.startsWith(cookiePath); -} - -bool NetworkCookieJarPrivate::matchesBlacklist(const QString &string) const -{ - if (!setSecondLevelDomain) { - // Alternatively to save a little bit of ram we could just - // use bsearch on twoLevelDomains in place - for (int j = 0; twoLevelDomains[j]; ++j) - secondLevelDomains += QLatin1String(twoLevelDomains[j]); - setSecondLevelDomain = true; - } - QStringList::const_iterator i = - qBinaryFind(secondLevelDomains.constBegin(), secondLevelDomains.constEnd(), string); - return (i != secondLevelDomains.constEnd()); -} - -bool NetworkCookieJarPrivate::matchingDomain(const QNetworkCookie &cookie, const QUrl &url) const -{ - QString domain = cookie.domain().simplified().toLower(); - domain.remove(QLatin1Char(' ')); - QStringList parts = splitHost(domain); - if (parts.isEmpty()) - return false; - - // When there is only one part only file://localhost/ is accepted - if (parts.count() == 1) { - QString s = parts.first(); - if (parts.first() != QLatin1String("localhost")) - return false; - if (url.scheme().toLower() == QLatin1String("file")) - return true; - } - - // Check for blacklist - if (parts.count() == 2 && matchesBlacklist(parts.last())) - return false; - - QStringList urlParts = url.host().toLower().split(QLatin1Char('.'), QString::SkipEmptyParts); - if (urlParts.isEmpty()) - return false; - while (urlParts.count() > parts.count()) - urlParts.removeFirst(); - - for (int j = 0; j < urlParts.count(); ++j) { - if (urlParts.at(j) != parts.at(j)) { - return false; - } - } - - return true; -} - -void NetworkCookieJar::setSecondLevelDomains(const QStringList &secondLevelDomains) -{ - d->setSecondLevelDomain = true; - d->secondLevelDomains = secondLevelDomains; - qSort(d->secondLevelDomains); -} - - -void NetworkCookieJar::onCookieSetFromURL(const QNetworkCookie &cookie, const QUrl &url, bool already_dead) -{ - Q_UNUSED(cookie); - Q_UNUSED(url); - Q_UNUSED(already_dead); - - // Derived classes can use this to track cookie changes. -} diff --git a/indra/llqtwebkit/qtwebkit_cookiejar/src/networkcookiejar.h b/indra/llqtwebkit/qtwebkit_cookiejar/src/networkcookiejar.h deleted file mode 100644 index 86b14fa16e..0000000000 --- a/indra/llqtwebkit/qtwebkit_cookiejar/src/networkcookiejar.h +++ /dev/null @@ -1,61 +0,0 @@ -/* Copyright (c) 2006-2010, Linden Research, Inc. - * - * LLQtWebKit Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in GPL-license.txt in this distribution, or online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - */ - -#ifndef NETWORKCOOKIEJAR_H -#define NETWORKCOOKIEJAR_H - -#include - -class NetworkCookieJarPrivate; -class NetworkCookieJar : public QNetworkCookieJar { - Q_OBJECT -public: - NetworkCookieJar(QObject *parent = 0); - ~NetworkCookieJar(); - - virtual QList cookiesForUrl(const QUrl & url) const; - virtual bool setCookiesFromUrl(const QList &cookieList, const QUrl &url); - -protected: - QByteArray saveState() const; - bool restoreState(const QByteArray &state); - void endSession(); - - QList allCookies() const; - void clearCookies(); - void setCookies(const QList &cookieList); - void setAllCookies(const QList &cookieList); - void removeCookie(const QNetworkCookie &cookie); - void dump(); - void setSecondLevelDomains(const QStringList &secondLevelDomains); - - virtual void onCookieSetFromURL(const QNetworkCookie &cookie, const QUrl &url, bool already_dead); - -private: - NetworkCookieJarPrivate *d; -}; - -#endif - diff --git a/indra/llqtwebkit/qtwebkit_cookiejar/src/networkcookiejar_p.h b/indra/llqtwebkit/qtwebkit_cookiejar/src/networkcookiejar_p.h deleted file mode 100644 index d8f22cfce0..0000000000 --- a/indra/llqtwebkit/qtwebkit_cookiejar/src/networkcookiejar_p.h +++ /dev/null @@ -1,66 +0,0 @@ -/* Copyright (c) 2006-2010, Linden Research, Inc. - * - * LLQtWebKit Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in GPL-license.txt in this distribution, or online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - */ - -#ifndef NETWORKCOOKIEJARPRIVATE_H -#define NETWORKCOOKIEJARPRIVATE_H - -#include "trie_p.h" - -QT_BEGIN_NAMESPACE -QDataStream &operator<<(QDataStream &stream, const QNetworkCookie &cookie) -{ - stream << cookie.toRawForm(); - return stream; -} - -QDataStream &operator>>(QDataStream &stream, QNetworkCookie &cookie) -{ - QByteArray value; - stream >> value; - QList newCookies = QNetworkCookie::parseCookies(value); - if (!newCookies.isEmpty()) - cookie = newCookies.first(); - return stream; -} -QT_END_NAMESPACE - -class NetworkCookieJarPrivate { -public: - NetworkCookieJarPrivate() - : setSecondLevelDomain(false) - {} - - Trie tree; - mutable bool setSecondLevelDomain; - mutable QStringList secondLevelDomains; - - bool matchesBlacklist(const QString &string) const; - bool matchingDomain(const QNetworkCookie &cookie, const QUrl &url) const; - QString urlPath(const QUrl &url) const; - bool matchingPath(const QNetworkCookie &cookie, const QString &urlPath) const; -}; - -#endif - diff --git a/indra/llqtwebkit/qtwebkit_cookiejar/src/src.pri b/indra/llqtwebkit/qtwebkit_cookiejar/src/src.pri deleted file mode 100644 index 78ac273a15..0000000000 --- a/indra/llqtwebkit/qtwebkit_cookiejar/src/src.pri +++ /dev/null @@ -1,5 +0,0 @@ -INCLUDEPATH += $$PWD -DEPENDPATH += $$PWD - -HEADERS += trie_p.h networkcookiejar.h twoleveldomains_p.h networkcookiejar_p.h -SOURCES += networkcookiejar.cpp diff --git a/indra/llqtwebkit/qtwebkit_cookiejar/src/trie_p.h b/indra/llqtwebkit/qtwebkit_cookiejar/src/trie_p.h deleted file mode 100644 index a4959a198c..0000000000 --- a/indra/llqtwebkit/qtwebkit_cookiejar/src/trie_p.h +++ /dev/null @@ -1,247 +0,0 @@ -/* Copyright (c) 2006-2010, Linden Research, Inc. - * - * LLQtWebKit Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in GPL-license.txt in this distribution, or online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - */ - -#ifndef TRIE_H -#define TRIE_H - -//#define TRIE_DEBUG - -#include - -#if defined(TRIE_DEBUG) -#include -#endif - -/* - A Trie tree (prefix tree) where the lookup takes m in the worst case. - - The key is stored in *reverse* order - - Example: - Keys: x,a y,a - - Trie: - a - | \ - x y -*/ - -template -class Trie { -public: - Trie(); - ~Trie(); - - void clear(); - void insert(const QStringList &key, const T &value); - bool remove(const QStringList &key, const T &value); - QList find(const QStringList &key) const; - QList all() const; - - inline bool contains(const QStringList &key) const; - inline bool isEmpty() const { return children.isEmpty() && values.isEmpty(); } - -private: - const Trie* walkTo(const QStringList &key) const; - Trie* walkTo(const QStringList &key, bool create = false); - - template friend QDataStream &operator<<(QDataStream &, const Trie&); - template friend QDataStream &operator>>(QDataStream &, Trie&); - - QList values; - QStringList childrenKeys; - QList > children; -}; - -template -Trie::Trie() { -} - -template -Trie::~Trie() { -} - -template -void Trie::clear() { -#if defined(TRIE_DEBUG) - qDebug() << "Trie::" << __FUNCTION__; -#endif - values.clear(); - childrenKeys.clear(); - children.clear(); -} - -template -bool Trie::contains(const QStringList &key) const { - return walkTo(key); -} - -template -void Trie::insert(const QStringList &key, const T &value) { -#if defined(TRIE_DEBUG) - qDebug() << "Trie::" << __FUNCTION__ << key << value; -#endif - Trie *node = walkTo(key, true); - if (node) - node->values.append(value); -} - -template -bool Trie::remove(const QStringList &key, const T &value) { -#if defined(TRIE_DEBUG) - qDebug() << "Trie::" << __FUNCTION__ << key << value; -#endif - Trie *node = walkTo(key, true); - if (node) { - bool removed = node->values.removeOne(value); - if (!removed) - return false; - - // A faster implementation of removing nodes up the tree - // can be created if profile shows this to be slow - QStringList subKey = key; - while (node->values.isEmpty() - && node->children.isEmpty() - && !subKey.isEmpty()) { - QString currentLevelKey = subKey.first(); - QStringList parentKey = subKey.mid(1); - Trie *parent = walkTo(parentKey, false); - Q_ASSERT(parent); - QStringList::iterator iterator; - iterator = qBinaryFind(parent->childrenKeys.begin(), - parent->childrenKeys.end(), - currentLevelKey); - Q_ASSERT(iterator != parent->childrenKeys.end()); - int index = iterator - parent->childrenKeys.begin(); - parent->children.removeAt(index); - parent->childrenKeys.removeAt(index); - - node = parent; - subKey = parentKey; - } - return removed; - } - return false; -} - -template -QList Trie::find(const QStringList &key) const { -#if defined(TRIE_DEBUG) - qDebug() << "Trie::" << __FUNCTION__ << key; -#endif - const Trie *node = walkTo(key); - if (node) - return node->values; - return QList(); -} - -template -QList Trie::all() const { -#if defined(TRIE_DEBUG) - qDebug() << "Trie::" << __FUNCTION__; -#endif - QList all = values; - for (int i = 0; i < children.count(); ++i) - all += children[i].all(); - return all; -} - -template -QDataStream &operator<<(QDataStream &out, const Trie&trie) { - out << trie.values; - out << trie.childrenKeys; - out << trie.children; - Q_ASSERT(trie.childrenKeys.count() == trie.children.count()); - return out; -} - -template -QDataStream &operator>>(QDataStream &in, Trie &trie) { - trie.clear(); - if (in.status() != QDataStream::Ok) - return in; - in >> trie.values; - in >> trie.childrenKeys; - in >> trie.children; - //Q_ASSERT(trie.childrenKeys.count() == trie.children.count()); - if (trie.childrenKeys.count() != trie.children.count()) - in.setStatus(QDataStream::ReadCorruptData); - return in; -} - -// Very fast const walk -template -const Trie* Trie::walkTo(const QStringList &key) const { - const Trie *node = this; - QStringList::const_iterator childIterator; - QStringList::const_iterator begin, end; - - int depth = key.count() - 1; - while (depth >= 0) { - const QString currentLevelKey = key.at(depth--); - begin = node->childrenKeys.constBegin(); - end = node->childrenKeys.constEnd(); - childIterator = qBinaryFind(begin, end, currentLevelKey); - if (childIterator == end) - return 0; - node = &node->children.at(childIterator - begin); - } - return node; -} - -template -Trie* Trie::walkTo(const QStringList &key, bool create) { - QStringList::iterator iterator; - Trie *node = this; - QStringList::iterator begin, end; - int depth = key.count() - 1; - while (depth >= 0) { - const QString currentLevelKey = key.at(depth--); - begin = node->childrenKeys.begin(); - end = node->childrenKeys.end(); - iterator = qBinaryFind(begin, end, currentLevelKey); -#if defined(TRIE_DEBUG) - qDebug() << "\t" << node << key << currentLevelKey << node->childrenKeys; -#endif - int index = -1; - if (iterator == end) { - if (!create) - return 0; - iterator = qLowerBound(begin, - end, - currentLevelKey); - index = iterator - begin; - node->childrenKeys.insert(iterator, currentLevelKey); - node->children.insert(index, Trie()); - } else { - index = iterator - begin; - } - Q_ASSERT(index >= 0 && index < node->children.count()); - node = &node->children[index]; - } - return node; -} - -#endif diff --git a/indra/llqtwebkit/qtwebkit_cookiejar/src/twoleveldomains_p.h b/indra/llqtwebkit/qtwebkit_cookiejar/src/twoleveldomains_p.h deleted file mode 100644 index e4c046cb68..0000000000 --- a/indra/llqtwebkit/qtwebkit_cookiejar/src/twoleveldomains_p.h +++ /dev/null @@ -1,92 +0,0 @@ -/* Copyright (c) 2006-2010, Linden Research, Inc. - * - * LLQtWebKit Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in GPL-license.txt in this distribution, or online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - */ - -// Updated from https://wiki.mozilla.org/TLD_List#External_Links -// To set a custom list use NetworkCookieJar::setSecondLevelDomains() -static const char *const twoLevelDomains[] = { - "ao", - "ar", - "arpa", - "bd", - "bn", - "br", - "co", - "cr", - "cy", - "do", - "eg", - "et", - "fj", - "fk", - "gh", - "gn", - "gu", - "id", - "il", - "jm", - "ke", - "kh", - "ki", - "kw", - "kz", - "lb", - "lc", - "lr", - "ls", - "ml", - "mm", - "mv", - "mw", - "mx", - "my", - "ng", - "ni", - "np", - "nz", - "om", - "pa", - "pe", - "pg", - "pw", - "py", - "qa", - "sa", - "sb", - "sv", - "sy", - "th", - "tn", - "tz", - "uk", - "uy", - "va", - "ve", - "ye", - "yu", - "za", - "zm", - "zw", - 0 -}; diff --git a/indra/llqtwebkit/static.pri b/indra/llqtwebkit/static.pri deleted file mode 100644 index 8c282347d1..0000000000 --- a/indra/llqtwebkit/static.pri +++ /dev/null @@ -1,18 +0,0 @@ -# Detect if Qt is static or shared -CONFIG(debug, debug|release) { - win32:PRL = $$[QT_INSTALL_LIBS] QtGui.prl -} else { - win32:PRL = $$[QT_INSTALL_LIBS] QtGuid.prl -} - -unix:!mac: PRL = $$[QT_INSTALL_LIBS] libQtGui.prl -mac: PRL = $$[QT_INSTALL_LIBS] QtGui.framework/QtGui.prl -include($$join(PRL, "/")) - -contains(QMAKE_PRL_CONFIG, static) { - DEFINES += STATIC_QT - QTPLUGIN += qgif -} else { - DEFINES += SHARED_QT -} - diff --git a/indra/llqtwebkit/tests/3dgl/3dgl.cpp b/indra/llqtwebkit/tests/3dgl/3dgl.cpp deleted file mode 100644 index c07c5d89c8..0000000000 --- a/indra/llqtwebkit/tests/3dgl/3dgl.cpp +++ /dev/null @@ -1,269 +0,0 @@ -/* Copyright (c) 2006-2010, Linden Research, Inc. - * - * LLQtWebKit Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in GPL-license.txt in this distribution, or online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - */ -#define FREEGLUT_STATIC - -#include "zpr.h" -#include "llqtwebkit.h" - -#include -#include -#include -#include - -bool gDebugMode = false; -int gBrowserWindowId=-1; -GLuint gBrowserTexture=-1; -GLuint gCheckerTexture=-1; - -// manually make part of the browser texture transparent - for testing - LLQtWebKit will handle this eventually -void alphaize_browser_texture(unsigned char* texture_pixels) -{ - const int texture_depth=4; - - int texture_width = LLQtWebKit::getInstance()->getBrowserWidth(gBrowserWindowId); - int texture_height = LLQtWebKit::getInstance()->getBrowserHeight(gBrowserWindowId); - - const int num_squares=16; - int sqr1_alpha=0xff; - int sqr2_alpha=0x00; - - for(int y1=0;y1pump(200); - LLQtWebKit::getInstance()->grabBrowserWindow( gBrowserWindowId ); - glutPostRedisplay(); - }; -} - -void display(void) -{ - glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); - - glPushMatrix(); - - glBindTexture(GL_TEXTURE_2D, gCheckerTexture); - glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - glBegin(GL_QUADS); - glTexCoord2f(1.0f, 0.0f); glVertex3f(-0.8f, -0.8f, -0.8f); - glTexCoord2f(1.0f, 1.0f); glVertex3f(-0.8f, 0.8f, -0.8f); - glTexCoord2f(0.0f, 1.0f); glVertex3f( 0.8f, 0.8f, -0.8f); - glTexCoord2f(0.0f, 0.0f); glVertex3f( 0.8f, -0.8f, -0.8f); - glEnd(); - - glBindTexture(GL_TEXTURE_2D, gBrowserTexture); - if(!gDebugMode) - { - const unsigned char* browser_pixels=LLQtWebKit::getInstance()->getBrowserWindowPixels(gBrowserWindowId); - if(browser_pixels) - { - int texture_width = LLQtWebKit::getInstance()->getBrowserWidth(gBrowserWindowId); - int texture_height = LLQtWebKit::getInstance()->getBrowserHeight(gBrowserWindowId); - int texture_depth = 4; - - unsigned char* texture_pixels = new unsigned char[texture_width*texture_height*texture_depth]; - memcpy(texture_pixels, browser_pixels, texture_width*texture_height*texture_depth); - alphaize_browser_texture(texture_pixels); - - glTexSubImage2D(GL_TEXTURE_2D, 0, - 0, 0, - texture_width, texture_height, - GL_RGBA, - GL_UNSIGNED_BYTE, - texture_pixels); - - delete [] texture_pixels; - }; - }; - glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - glBegin(GL_QUADS); - glTexCoord2f(0.0f, 0.0f); glVertex3f(-0.8f, -0.8f, 0.8f); - glTexCoord2f(1.0f, 0.0f); glVertex3f( 0.8f, -0.8f, 0.8f); - glTexCoord2f(1.0f, 1.0f); glVertex3f( 0.8f, 0.8f, 0.8f); - glTexCoord2f(0.0f, 1.0f); glVertex3f(-0.8f, 0.8f, 0.8f); - glEnd(); - - glPopMatrix(); - - glutSwapBuffers(); -} - -GLuint make_rgba_texture(int texture_width, int texture_height) -{ - const int texture_depth=4; - - unsigned char* texture_pixels = new unsigned char[texture_width*texture_height*texture_depth]; - - const int num_squares=rand()%10+10; - int sqr1_r=rand()%0xa0+0x20; - int sqr1_g=rand()%0xa0+0x20; - int sqr1_b=rand()%0xa0+0x20; - int sqr1_alpha=0xff; - - int sqr2_r=rand()%0xa0+0x20; - int sqr2_g=rand()%0xa0+0x20; - int sqr2_b=rand()%0xa0+0x20; - int sqr2_alpha=0x00; - - for(int y1=0;y1init(std::string(), app_dir, profile_dir, GetDesktopWindow()); - - LLQtWebKit::getInstance()->enableJavaScript(true); - LLQtWebKit::getInstance()->enableCookies(true); - LLQtWebKit::getInstance()->enablePlugins(true); - - const std::string start_url("http://news.google.com"); - //const std::string start_url("http://www.youtube.com/watch?v=4Z3r9X8OahA&feature=rbl_entertainment"); - gBrowserWindowId=LLQtWebKit::getInstance()->createBrowserWindow(browser_width, browser_height); - LLQtWebKit::getInstance()->setSize(gBrowserWindowId, browser_width, browser_height); - LLQtWebKit::getInstance()->flipWindow(gBrowserWindowId, true); - LLQtWebKit::getInstance()->navigateTo(gBrowserWindowId, start_url); - } - - gCheckerTexture = make_rgba_texture( browser_width, browser_height); - - glutMainLoop(); - - return 0; -} diff --git a/indra/llqtwebkit/tests/3dgl/3dgl.pro b/indra/llqtwebkit/tests/3dgl/3dgl.pro deleted file mode 100644 index 6285128ef7..0000000000 --- a/indra/llqtwebkit/tests/3dgl/3dgl.pro +++ /dev/null @@ -1,38 +0,0 @@ -TEMPLATE = app -TARGET = -DEPENDPATH += . -INCLUDEPATH += . -INCLUDEPATH += ../../ -CONFIG -= app_bundle - -QT += webkit opengl network - -!mac { -unix { - DEFINES += LL_LINUX - LIBS += -lglui -lglut - LIBS += $$PWD/../../libllqtwebkit.a -} -} - -mac { - DEFINES += LL_OSX - LIBS += -framework GLUT -framework OpenGL - LIBS += $$PWD/libllqtwebkit.dylib -} - -win32 { - DEFINES += _WINDOWS - INCLUDEPATH += ../ - INCLUDEPATH += $$PWD/../../stage/packages/include - DESTDIR=../build - release { - LIBS += $$PWD/../../Release/llqtwebkit.lib - LIBS += $$PWD/../build/freeglut_static.lib - LIBS += comdlg32.lib - } -} - -include(../../static.pri) - -SOURCES += 3dgl.cpp zpr.c diff --git a/indra/llqtwebkit/tests/3dgl/zpr.c b/indra/llqtwebkit/tests/3dgl/zpr.c deleted file mode 100644 index 65373efc56..0000000000 --- a/indra/llqtwebkit/tests/3dgl/zpr.c +++ /dev/null @@ -1,429 +0,0 @@ -#include -#include -#include -#include - -#include "zpr.h" - -/* This code was originally C++ :-) */ - -#define bool int -#define true 1 -#define false 0 - -static double _left = 0.0; -static double _right = 0.0; -static double _bottom = 0.0; -static double _top = 0.0; -static double _zNear = -10.0; -static double _zFar = 10.0; - -static int _mouseX = 0; -static int _mouseY = 0; -static bool _mouseLeft = false; -static bool _mouseMiddle = false; -static bool _mouseRight = false; - -static double _dragPosX = 0.0; -static double _dragPosY = 0.0; -static double _dragPosZ = 0.0; - -static double _matrix[16]; -static double _matrixInverse[16]; - -static double vlen(double x,double y,double z); -static void pos(double *px,double *py,double *pz,const int x,const int y,const int *viewport); -static void getMatrix(); -static void invertMatrix(const GLdouble *m, GLdouble *out ); - -static void zprReshape(int w,int h); -static void zprMouse(int button, int state, int x, int y); -static void zprMotion(int x, int y); - -static void zprPick(GLdouble x, GLdouble y,GLdouble delX, GLdouble delY); - -/* Configurable center point for zooming and rotation */ - -GLfloat zprReferencePoint[4] = { 0,0,0,0 }; - -void -zprInit() -{ - getMatrix(); - - glutReshapeFunc(zprReshape); - glutMouseFunc(zprMouse); - glutMotionFunc(zprMotion); -} - -static void -zprReshape(int w,int h) -{ - glViewport(0,0,w,h); - - _top = 1.0; - _bottom = -1.0; - _left = -(double)w/(double)h; - _right = -_left; - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(_left,_right,_bottom,_top,_zNear,_zFar); - - glMatrixMode(GL_MODELVIEW); -} - -static void -zprMouse(int button, int state, int x, int y) -{ - GLint viewport[4]; - - /* Do picking */ - if (state==GLUT_DOWN) - zprPick(x,glutGet(GLUT_WINDOW_HEIGHT)-1-y,3,3); - - _mouseX = x; - _mouseY = y; - - if (state==GLUT_UP) - switch (button) - { - case GLUT_LEFT_BUTTON: _mouseLeft = false; break; - case GLUT_MIDDLE_BUTTON: _mouseMiddle = false; break; - case GLUT_RIGHT_BUTTON: _mouseRight = false; break; - } - else - switch (button) - { - case GLUT_LEFT_BUTTON: _mouseLeft = true; break; - case GLUT_MIDDLE_BUTTON: _mouseMiddle = true; break; - case GLUT_RIGHT_BUTTON: _mouseRight = true; break; - } - - glGetIntegerv(GL_VIEWPORT,viewport); - pos(&_dragPosX,&_dragPosY,&_dragPosZ,x,y,viewport); - glutPostRedisplay(); -} - -static void -zprMotion(int x, int y) -{ - bool changed = false; - - const int dx = x - _mouseX; - const int dy = y - _mouseY; - - GLint viewport[4]; - glGetIntegerv(GL_VIEWPORT,viewport); - - if (dx==0 && dy==0) - return; - - if (_mouseMiddle || (_mouseLeft && _mouseRight)) - { - double s = exp((double)dy*0.01); - - glTranslatef( zprReferencePoint[0], zprReferencePoint[1], zprReferencePoint[2]); - glScalef(s,s,s); - glTranslatef(-zprReferencePoint[0],-zprReferencePoint[1],-zprReferencePoint[2]); - - changed = true; - } - else - if (_mouseLeft) - { - double ax,ay,az; - double bx,by,bz; - double angle; - - ax = dy; - ay = dx; - az = 0.0; - angle = vlen(ax,ay,az)/(double)(viewport[2]+1)*180.0; - - /* Use inverse matrix to determine local axis of rotation */ - - bx = _matrixInverse[0]*ax + _matrixInverse[4]*ay + _matrixInverse[8] *az; - by = _matrixInverse[1]*ax + _matrixInverse[5]*ay + _matrixInverse[9] *az; - bz = _matrixInverse[2]*ax + _matrixInverse[6]*ay + _matrixInverse[10]*az; - - glTranslatef( zprReferencePoint[0], zprReferencePoint[1], zprReferencePoint[2]); - glRotatef(angle,bx,by,bz); - glTranslatef(-zprReferencePoint[0],-zprReferencePoint[1],-zprReferencePoint[2]); - - changed = true; - } - else - if (_mouseRight) - { - double px,py,pz; - - pos(&px,&py,&pz,x,y,viewport); - - glLoadIdentity(); - glTranslatef(px-_dragPosX,py-_dragPosY,pz-_dragPosZ); - glMultMatrixd(_matrix); - - _dragPosX = px; - _dragPosY = py; - _dragPosZ = pz; - - changed = true; - } - - _mouseX = x; - _mouseY = y; - - if (changed) - { - getMatrix(); - glutPostRedisplay(); - } -} - -/***************************************************************** - * Utility functions - *****************************************************************/ - -static double -vlen(double x,double y,double z) -{ - return sqrt(x*x+y*y+z*z); -} - -static void -pos(double *px,double *py,double *pz,const int x,const int y,const int *viewport) -{ - /* - Use the ortho projection and viewport information - to map from mouse co-ordinates back into world - co-ordinates - */ - - *px = (double)(x-viewport[0])/(double)(viewport[2]); - *py = (double)(y-viewport[1])/(double)(viewport[3]); - - *px = _left + (*px)*(_right-_left); - *py = _top + (*py)*(_bottom-_top); - *pz = _zNear; -} - -static void -getMatrix() -{ - glGetDoublev(GL_MODELVIEW_MATRIX,_matrix); - invertMatrix(_matrix,_matrixInverse); -} - -/* - * From Mesa-2.2\src\glu\project.c - * - * Compute the inverse of a 4x4 matrix. Contributed by scotter@lafn.org - */ - -static void -invertMatrix(const GLdouble *m, GLdouble *out ) -{ - -/* NB. OpenGL Matrices are COLUMN major. */ -#define MAT(m,r,c) (m)[(c)*4+(r)] - -/* Here's some shorthand converting standard (row,column) to index. */ -#define m11 MAT(m,0,0) -#define m12 MAT(m,0,1) -#define m13 MAT(m,0,2) -#define m14 MAT(m,0,3) -#define m21 MAT(m,1,0) -#define m22 MAT(m,1,1) -#define m23 MAT(m,1,2) -#define m24 MAT(m,1,3) -#define m31 MAT(m,2,0) -#define m32 MAT(m,2,1) -#define m33 MAT(m,2,2) -#define m34 MAT(m,2,3) -#define m41 MAT(m,3,0) -#define m42 MAT(m,3,1) -#define m43 MAT(m,3,2) -#define m44 MAT(m,3,3) - - GLdouble det; - GLdouble d12, d13, d23, d24, d34, d41; - GLdouble tmp[16]; /* Allow out == in. */ - - /* Inverse = adjoint / det. (See linear algebra texts.)*/ - - /* pre-compute 2x2 dets for last two rows when computing */ - /* cofactors of first two rows. */ - d12 = (m31*m42-m41*m32); - d13 = (m31*m43-m41*m33); - d23 = (m32*m43-m42*m33); - d24 = (m32*m44-m42*m34); - d34 = (m33*m44-m43*m34); - d41 = (m34*m41-m44*m31); - - tmp[0] = (m22 * d34 - m23 * d24 + m24 * d23); - tmp[1] = -(m21 * d34 + m23 * d41 + m24 * d13); - tmp[2] = (m21 * d24 + m22 * d41 + m24 * d12); - tmp[3] = -(m21 * d23 - m22 * d13 + m23 * d12); - - /* Compute determinant as early as possible using these cofactors. */ - det = m11 * tmp[0] + m12 * tmp[1] + m13 * tmp[2] + m14 * tmp[3]; - - /* Run singularity test. */ - if (det == 0.0) { - /* printf("invert_matrix: Warning: Singular matrix.\n"); */ -/* memcpy(out,_identity,16*sizeof(double)); */ - } - else { - GLdouble invDet = 1.0 / det; - /* Compute rest of inverse. */ - tmp[0] *= invDet; - tmp[1] *= invDet; - tmp[2] *= invDet; - tmp[3] *= invDet; - - tmp[4] = -(m12 * d34 - m13 * d24 + m14 * d23) * invDet; - tmp[5] = (m11 * d34 + m13 * d41 + m14 * d13) * invDet; - tmp[6] = -(m11 * d24 + m12 * d41 + m14 * d12) * invDet; - tmp[7] = (m11 * d23 - m12 * d13 + m13 * d12) * invDet; - - /* Pre-compute 2x2 dets for first two rows when computing */ - /* cofactors of last two rows. */ - d12 = m11*m22-m21*m12; - d13 = m11*m23-m21*m13; - d23 = m12*m23-m22*m13; - d24 = m12*m24-m22*m14; - d34 = m13*m24-m23*m14; - d41 = m14*m21-m24*m11; - - tmp[8] = (m42 * d34 - m43 * d24 + m44 * d23) * invDet; - tmp[9] = -(m41 * d34 + m43 * d41 + m44 * d13) * invDet; - tmp[10] = (m41 * d24 + m42 * d41 + m44 * d12) * invDet; - tmp[11] = -(m41 * d23 - m42 * d13 + m43 * d12) * invDet; - tmp[12] = -(m32 * d34 - m33 * d24 + m34 * d23) * invDet; - tmp[13] = (m31 * d34 + m33 * d41 + m34 * d13) * invDet; - tmp[14] = -(m31 * d24 + m32 * d41 + m34 * d12) * invDet; - tmp[15] = (m31 * d23 - m32 * d13 + m33 * d12) * invDet; - - memcpy(out, tmp, 16*sizeof(GLdouble)); - } - -#undef m11 -#undef m12 -#undef m13 -#undef m14 -#undef m21 -#undef m22 -#undef m23 -#undef m24 -#undef m31 -#undef m32 -#undef m33 -#undef m34 -#undef m41 -#undef m42 -#undef m43 -#undef m44 -#undef MAT -} - -/***************************************** Picking ****************************************************/ - -static void (*selection)(void) = NULL; -static void (*pick)(GLint name) = NULL; - -void zprSelectionFunc(void (*f)(void)) -{ - selection = f; -} - -void zprPickFunc(void (*f)(GLint name)) -{ - pick = f; -} - -/* Draw in selection mode */ - -static void -zprPick(GLdouble x, GLdouble y,GLdouble delX, GLdouble delY) -{ - GLuint buffer[1024]; - const int bufferSize = sizeof(buffer)/sizeof(GLuint); - - GLint viewport[4]; - GLdouble projection[16]; - - GLint hits; - GLint i,j,k; - - GLint min = -1; - GLuint minZ = -1; - - glSelectBuffer(bufferSize,buffer); /* Selection buffer for hit records */ - glRenderMode(GL_SELECT); /* OpenGL selection mode */ - glInitNames(); /* Clear OpenGL name stack */ - - glMatrixMode(GL_PROJECTION); - glPushMatrix(); /* Push current projection matrix */ - glGetIntegerv(GL_VIEWPORT,viewport); /* Get the current viewport size */ - glGetDoublev(GL_PROJECTION_MATRIX,projection); /* Get the projection matrix */ - glLoadIdentity(); /* Reset the projection matrix */ - gluPickMatrix(x,y,delX,delY,viewport); /* Set the picking matrix */ - glMultMatrixd(projection); /* Apply projection matrix */ - - glMatrixMode(GL_MODELVIEW); - - if (selection) - selection(); /* Draw the scene in selection mode */ - - hits = glRenderMode(GL_RENDER); /* Return to normal rendering mode */ - - /* Diagnostic output to stdout */ - - #ifndef NDEBUG - if (hits!=0) - { - printf("hits = %d\n",hits); - - for (i=0,j=0; i rotate - * Middle button -> zoom - * Right button -> pan - * - * Picking is also provided via two configurable callbacks: - * - * void zprSelectionFunc(void (*f)(void)) - * - * The draw function to be called in OpenGL selection - * mode in response to a mouse-down button event. - * - * void zprPickFunc(void (*f)(GLint name)) - * - * The callback function which will receive the - * top-most item of the name stack of the closest selection - * hit. If there is no selection hit, -1 - * - * Limitations - * ----------- - * - * Works best with zprReferencePoint appropriately configured. - * Works best with ortho projection. - * You may need to use glEnable(GL_NORMALIZATION) for correct lighting. - * Near and far clip planes are hard-coded. - * Zooming and rotation is centered on the origin. - * Only one window can use the callbacks at one time. - * - */ - -#ifdef WIN32 -#include -#endif - -#define FREEGLUT_STATIC - -#include - -#ifdef __cplusplus -extern "C" -{ -#endif - -/* - * - */ - -/* Mouse Manipulation API */ - -void zprInit(); - -extern GLfloat zprReferencePoint[4]; - -/* Picking API (Optional) */ - -extern void zprSelectionFunc(void (*f)(void)); /* Selection-mode draw function */ -extern void zprPickFunc(void (*f)(GLint name)); /* Pick event handling function */ - -/* - * - */ - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/indra/llqtwebkit/tests/qttestapp/main.cpp b/indra/llqtwebkit/tests/qttestapp/main.cpp deleted file mode 100644 index 3ab3a9c179..0000000000 --- a/indra/llqtwebkit/tests/qttestapp/main.cpp +++ /dev/null @@ -1,341 +0,0 @@ -/* Copyright (c) 2006-2010, Linden Research, Inc. - * - * LLQtWebKit Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in GPL-license.txt in this distribution, or online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - */ - -#include -#include - -class WebPage : public QWidget, LLEmbeddedBrowserWindowObserver -{ - Q_OBJECT - -signals: - void locationChanged(const QString &); - void canGoBack(bool); - void canGoForward(bool); - -public: - WebPage(QWidget *parent = 0); - ~WebPage(); - - void onCursorChanged(const EventType& event); - void onPageChanged(const EventType& event); - void onNavigateBegin(const EventType& event); - void onNavigateComplete(const EventType& event); - void onUpdateProgress(const EventType& event); - void onStatusTextChange(const EventType& event); - void onLocationChange(const EventType& event); - void onClickLinkHref(const EventType& event); - void onClickLinkNoFollow(const EventType& event); - -public slots: - void goBack(); - void goForward(); - void reload(); - void loadUrl(const QString &); - -protected: - void resizeEvent(QResizeEvent *event); - void paintEvent(QPaintEvent *event); - void mouseDoubleClickEvent(QMouseEvent *event); - void mouseMoveEvent(QMouseEvent *event); - void mousePressEvent(QMouseEvent *event); - void mouseReleaseEvent(QMouseEvent *event); - void keyPressEvent(QKeyEvent *event); - void keyReleaseEvent(QKeyEvent *event); -private: - void updateSLvariables(); - int mBrowserWindowId; -}; - -WebPage::WebPage(QWidget *parent) - : QWidget(parent) -{ - setMouseTracking(true); - std::string applicationDir = std::string(); - std::string componentDir = applicationDir; - std::string profileDir = applicationDir + "\\" + "testGL_profile"; - LLQtWebKit::getInstance()->init(applicationDir, componentDir, profileDir, 0); - - mBrowserWindowId = LLQtWebKit::getInstance()->createBrowserWindow(width(), height()); - - // observer events that LLQtWebKit emits - LLQtWebKit::getInstance()->addObserver( mBrowserWindowId, this ); - - // append details to agent string - LLQtWebKit::getInstance()->setBrowserAgentId("testqtapp"); - - // don't flip bitmap - LLQtWebKit::getInstance()->flipWindow(mBrowserWindowId, false); - - // test Second Life viewer specific functions - LLQtWebKit::getInstance()->setSLObjectEnabled( true ); // true means feature is turned on - LLQtWebKit::getInstance()->setAgentLanguage( "tst-en" ); // viewer language selected by agent - LLQtWebKit::getInstance()->setAgentRegion( "QtTestAppRegion" ); // name of region where agent is located - LLQtWebKit::getInstance()->setAgentLocation( 9.8, 7.6, 5.4 ); // agent's x,y,z location within a region - LLQtWebKit::getInstance()->setAgentGlobalLocation( 119.8, 227.6, 335.4 ); // agent's x,y,z location within the grid - LLQtWebKit::getInstance()->setAgentMaturity( "Very immature" ); // selected maturity level of agent - LLQtWebKit::getInstance()->setAgentOrientation( (rand()%36000)/100.0f ); // direction avatar is facing - LLQtWebKit::getInstance()->emitLocation(); - LLQtWebKit::getInstance()->emitLanguage(); - LLQtWebKit::getInstance()->emitMaturity(); - - // go to the "home page" - LLQtWebKit::getInstance()->navigateTo(mBrowserWindowId, "http://callum-linden.s3.amazonaws.com/browsertest.html"); -} - -WebPage::~WebPage() -{ - // unhook observer - LLQtWebKit::getInstance()->remObserver( mBrowserWindowId, this ); - - // clean up - LLQtWebKit::getInstance()->reset(); -} - -void WebPage::updateSLvariables() -{ - // randomly update SL values to test - LLQtWebKit::getInstance()->setAgentOrientation( (rand()%36000)/100.0f ); - LLQtWebKit::getInstance()->setAgentLocation( (rand()%25600)/100.0f, (rand()%25600)/100.0f, (rand()%25600)/100.0f ); - LLQtWebKit::getInstance()->setAgentGlobalLocation( (rand()%25600)/100.0f, (rand()%25600)/100.0f, (rand()%25600)/100.0f ); - - if ( rand() % 2 ) - LLQtWebKit::getInstance()->setAgentLanguage( "One language" ); - else - LLQtWebKit::getInstance()->setAgentLanguage( "Another language" ); - - if ( rand() % 2 ) - LLQtWebKit::getInstance()->setAgentRegion( "Region Wibble" ); - else - LLQtWebKit::getInstance()->setAgentRegion( "Region Flasm" ); - - if ( rand() % 2 ) - LLQtWebKit::getInstance()->setAgentMaturity( "Adults only" ); - else - LLQtWebKit::getInstance()->setAgentMaturity( "Children only" ); - - LLQtWebKit::getInstance()->emitLocation(); - LLQtWebKit::getInstance()->emitLanguage(); - LLQtWebKit::getInstance()->emitMaturity(); -} - -void WebPage::onCursorChanged(const EventType& event) -{ - //qDebug() << __FUNCTION__ << QString::fromStdString(event.getEventUri()); - switch (event.getIntValue()) { - case LLQtWebKit::C_ARROW: setCursor(QCursor(Qt::ArrowCursor)); break; - case LLQtWebKit::C_IBEAM: setCursor(QCursor(Qt::IBeamCursor)); break; - case LLQtWebKit::C_SPLITV: setCursor(QCursor(Qt::SplitHCursor)); break; - case LLQtWebKit::C_SPLITH: setCursor(QCursor(Qt::SplitVCursor)); break; - case LLQtWebKit::C_POINTINGHAND: setCursor(QCursor(Qt::PointingHandCursor)); break; - default: break; - } -} - -void WebPage::onPageChanged(const EventType& event) -{ - Q_UNUSED(event); - LLQtWebKit::getInstance()->grabBrowserWindow( mBrowserWindowId ); - //qDebug() << __FUNCTION__ << QString::fromStdString(event.getEventUri()); - update(); -} - -void WebPage::onNavigateBegin(const EventType& event) -{ - Q_UNUSED(event); - //qDebug() << __FUNCTION__ << QString::fromStdString(event.getEventUri()); -} - -void WebPage::onNavigateComplete(const EventType& event) -{ - Q_UNUSED(event); - //qDebug() << __FUNCTION__ << QString::fromStdString(event.getEventUri()); -} - -void WebPage::onUpdateProgress(const EventType& event) -{ - Q_UNUSED(event); -} - -void WebPage::onStatusTextChange(const EventType& event) -{ - Q_UNUSED(event); -} - -void WebPage::onLocationChange(const EventType& event) -{ - //qDebug() << __FUNCTION__; - emit locationChanged(QString::fromStdString(event.getEventUri())); - //void canGoBack(bool); - //void canGoForward(bool); -} - -void WebPage::onClickLinkHref(const EventType& event) -{ - Q_UNUSED(event); -} - -void WebPage::onClickLinkNoFollow(const EventType& event) -{ - Q_UNUSED(event); -} - -void WebPage::resizeEvent(QResizeEvent *event) -{ - LLQtWebKit::getInstance()->setSize(mBrowserWindowId, event->size().width(), event->size().height()); - QWidget::resizeEvent(event); -} - -void WebPage::paintEvent(QPaintEvent *event) -{ - Q_UNUSED(event); - - int width = LLQtWebKit::getInstance()->getBrowserWidth(mBrowserWindowId); - int height = LLQtWebKit::getInstance()->getBrowserHeight(mBrowserWindowId); - const unsigned char* pixels = LLQtWebKit::getInstance()->getBrowserWindowPixels(mBrowserWindowId); - QImage image(pixels, width, height, QImage::Format_RGB32); - image = image.rgbSwapped(); - QPainter painter(this); - painter.drawImage(QPoint(0, 0), image); -} - -void WebPage::mouseDoubleClickEvent(QMouseEvent *event) -{ - LLQtWebKit::getInstance()->mouseEvent( mBrowserWindowId, - LLQtWebKit::ME_MOUSE_DOUBLE_CLICK, - LLQtWebKit::MB_MOUSE_BUTTON_LEFT, - event->x(), event->y(), - LLQtWebKit::KM_MODIFIER_NONE ); -} - -void WebPage::mouseMoveEvent(QMouseEvent *event) -{ - updateSLvariables(); - - LLQtWebKit::getInstance()->mouseEvent( mBrowserWindowId, - LLQtWebKit::ME_MOUSE_MOVE, - LLQtWebKit::MB_MOUSE_BUTTON_LEFT, - event->x(), event->y(), - LLQtWebKit::KM_MODIFIER_NONE ); -} - -void WebPage::mousePressEvent(QMouseEvent *event) -{ - LLQtWebKit::getInstance()->mouseEvent( mBrowserWindowId, - LLQtWebKit::ME_MOUSE_DOWN, - LLQtWebKit::MB_MOUSE_BUTTON_LEFT, - event->x(), event->y(), - LLQtWebKit::KM_MODIFIER_NONE ); -} - -void WebPage::mouseReleaseEvent(QMouseEvent *event) -{ - LLQtWebKit::getInstance()->mouseEvent( mBrowserWindowId, - LLQtWebKit::ME_MOUSE_UP, - LLQtWebKit::MB_MOUSE_BUTTON_LEFT, - event->x(), event->y(), - LLQtWebKit::KM_MODIFIER_NONE ); - - LLQtWebKit::getInstance()->focusBrowser(mBrowserWindowId, true); -} - -void WebPage::keyPressEvent(QKeyEvent *event) -{ - Q_UNUSED(event); -} - -void WebPage::keyReleaseEvent(QKeyEvent *event) -{ - Q_UNUSED(event); - //LLQtWebKit::getInstance()->unicodeInput(mBrowserWindowId, event->text().at(0).unicode(),LLQtWebKit::KM_MODIFIER_NONE); -} - -void WebPage::goBack() -{ - LLQtWebKit::getInstance()->userAction(mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_BACK); -} - -void WebPage::goForward() -{ - LLQtWebKit::getInstance()->userAction(mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_FORWARD); -} - -void WebPage::reload() -{ - LLQtWebKit::getInstance()->userAction(mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_RELOAD); -} - -void WebPage::loadUrl(const QString &url) -{ - LLQtWebKit::getInstance()->navigateTo(mBrowserWindowId, url.toStdString()); -} - -#include "ui_window.h" - -class Window : public QDialog, public Ui_Dialog -{ - Q_OBJECT -public: - Window(QWidget *parent = 0); - -public slots: - void loadUrl(); -}; - -Window::Window(QWidget *parent) - : QDialog(parent) -{ - setupUi(this); - connect(webpage, SIGNAL(locationChanged(const QString &)), - location, SLOT(setText(const QString &))); - connect(webpage, SIGNAL(canGoBack(bool)), - backButton, SLOT(setEnabled(bool))); - connect(webpage, SIGNAL(canGoForward(bool)), - forwardButton, SLOT(setEnabled(bool))); - connect(backButton, SIGNAL(clicked()), - webpage, SLOT(goBack())); - connect(forwardButton, SIGNAL(clicked()), - webpage, SLOT(goForward())); - connect(reloadButton, SIGNAL(clicked()), - webpage, SLOT(reload())); - connect(location, SIGNAL(returnPressed()), - this, SLOT(loadUrl())); -} - -void Window::loadUrl() -{ - webpage->loadUrl(location->text()); -} - - -int main(int argc, char **argv) -{ - QApplication application(argc, argv); - Window window; - window.show(); - return application.exec(); -} - -#include "main.moc" diff --git a/indra/llqtwebkit/tests/qttestapp/qttestapp.pro b/indra/llqtwebkit/tests/qttestapp/qttestapp.pro deleted file mode 100644 index 5a0ca33cf0..0000000000 --- a/indra/llqtwebkit/tests/qttestapp/qttestapp.pro +++ /dev/null @@ -1,38 +0,0 @@ -TEMPLATE = app -TARGET = -DEPENDPATH += . -INCLUDEPATH += . -INCLUDEPATH += ../../ -CONFIG -= app_bundle - -include(../../static.pri) - -QT += webkit opengl network - -unix { - LIBS += $$PWD/../../libllqtwebkit.a -} - -!mac { -unix { - DEFINES += LL_LINUX -} -} - -mac { - DEFINES += LL_OSX -} - - -win32{ - DEFINES += _WINDOWS - INCLUDEPATH += ../ - DESTDIR=../build - release { - LIBS += $$PWD/../../Release/llqtwebkit.lib - } -} - -# Input -SOURCES += main.cpp -FORMS += window.ui diff --git a/indra/llqtwebkit/tests/qttestapp/webpage.h b/indra/llqtwebkit/tests/qttestapp/webpage.h deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/indra/llqtwebkit/tests/qttestapp/window.ui b/indra/llqtwebkit/tests/qttestapp/window.ui deleted file mode 100644 index 6125821cc3..0000000000 --- a/indra/llqtwebkit/tests/qttestapp/window.ui +++ /dev/null @@ -1,79 +0,0 @@ - - - Dialog - - - - 0 - 0 - 766 - 613 - - - - Dialog - - - - 0 - - - - - 6 - - - 6 - - - 6 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0 - 0 - - - - - - - - - WebPage - QWidget -
    webpage.h
    - 1 -
    -
    - - -
    diff --git a/indra/llqtwebkit/tests/ssltest/ssltest.cpp b/indra/llqtwebkit/tests/ssltest/ssltest.cpp deleted file mode 100644 index fcbf80314d..0000000000 --- a/indra/llqtwebkit/tests/ssltest/ssltest.cpp +++ /dev/null @@ -1,229 +0,0 @@ -/* Copyright (c) 2006-2010, Linden Research, Inc. - * - * LLQtWebKit Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in GPL-license.txt in this distribution, or online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - */ - -#ifndef _WINDOWS -extern "C" { -#include -} -#endif - -#ifdef _WINDOWS -#include -#include -#endif - -#include -#include -#include - -#ifdef LL_OSX -// I'm not sure why STATIC_QT is getting defined, but the Q_IMPORT_PLUGIN thing doesn't seem to be necessary on the mac. -#undef STATIC_QT -#endif - -#ifdef STATIC_QT -#include -Q_IMPORT_PLUGIN(qgif) -#endif - -#include "llqtwebkit.h" - -class sslTest : - public LLEmbeddedBrowserWindowObserver -{ - public: - sslTest( std::string url, bool ignore_ca_file, bool ignore_ssl_errors ) : - mBrowserWindowWidth( 512 ), - mBrowserWindowHeight( 512 ), - mBrowserWindowHandle( 0 ), - mNavigateInProgress( true ) - { -#ifdef _WINDOWS - std::string cwd = std::string( _getcwd( NULL, 1024) ); - std::string profile_dir = cwd + "\\" + "ssltest_profile"; - void* native_window_handle = (void*)GetDesktopWindow(); - std::string ca_file_loc = cwd + "\\" + "CA.pem"; -#else - std::string cwd = std::string( getcwd( NULL, 1024) ); - std::string profile_dir = cwd + "/" + "ssltest_profile"; - void* native_window_handle = 0; - std::string ca_file_loc = cwd + "/" + "CA.pem"; -#endif - std::cout << "ssltest> === begin ===" << std::endl; - std::cout << "ssltest> current working dir is " << cwd << std::endl; - std::cout << "ssltest> profiles dir location is " << profile_dir << std::endl; - - LLQtWebKit::getInstance()->init( cwd, cwd, profile_dir, native_window_handle ); - - LLQtWebKit::getInstance()->enableJavaScript( true ); - LLQtWebKit::getInstance()->enablePlugins( true ); - - mBrowserWindowHandle = LLQtWebKit::getInstance()->createBrowserWindow( mBrowserWindowWidth, mBrowserWindowHeight ); - LLQtWebKit::getInstance()->setSize( mBrowserWindowHandle, mBrowserWindowWidth, mBrowserWindowHeight ); - - LLQtWebKit::getInstance()->addObserver( mBrowserWindowHandle, this ); - - if ( ! ignore_ca_file ) - { - std::cout << "ssltest> Expected certificate authority file location is " << ca_file_loc << std::endl; - LLQtWebKit::getInstance()->setCAFile( ca_file_loc.c_str() ); - } - else - { - std::cout << "ssltest> Not loading certificate authority file" << std::endl; - }; - - if ( ignore_ssl_errors ) - { - LLQtWebKit::getInstance()->setIgnoreSSLCertErrors( true ); - std::cout << "ssltest> Ignoring SSL errors " << std::endl; - } - else - { - std::cout << "ssltest> Not ignoring SSL errors " << std::endl; - }; - - LLQtWebKit::getInstance()->navigateTo( mBrowserWindowHandle, url ); - - std::cout << "ssltest> navigating to " << url << std::endl; - }; - - bool idle( void ) - { - LLQtWebKit::getInstance()->pump( 100 ); - -#if _WINDOWS - MSG msg; - while ( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) ) - { - GetMessage( &msg, NULL, 0, 0 ); - TranslateMessage( &msg ); - DispatchMessage( &msg ); - }; -#endif - return mNavigateInProgress; - }; - - ~sslTest() - { - LLQtWebKit::getInstance()->remObserver( mBrowserWindowHandle, this ); - LLQtWebKit::getInstance()->reset(); - std::cout << "ssltest> === end ===" << std::endl; - }; - - void onNavigateBegin( const EventType& eventIn ) - { - mNavigateInProgress = true; - std::cout << "ssltest> Event: begin navigation to " << eventIn.getEventUri() << std::endl; - }; - - void onNavigateComplete( const EventType& eventIn ) - { - std::cout << "ssltest> Event: end navigation to " << eventIn.getEventUri() << std::endl; - mNavigateInProgress = false; - }; - - void onUpdateProgress( const EventType& eventIn ) - { - std::cout << "ssltest> Event: progress value updated to " << eventIn.getIntValue() << std::endl; - }; - - void onStatusTextChange( const EventType& eventIn ) - { - std::cout << "ssltest> Event: status updated to " << eventIn.getStringValue() << std::endl; - }; - - void onTitleChange( const EventType& eventIn ) - { - std::cout << "ssltest> Event: title changed to " << eventIn.getStringValue() << std::endl; - }; - - void onLocationChange( const EventType& eventIn ) - { - std::cout << "ssltest> Event: location changed to " << eventIn.getStringValue() << std::endl; - }; - - bool onCertError(const std::string &in_url, const std::string &in_msg) - { - std::cout << "ssltest> Cert error triggered\n" << in_url << "\n" << in_msg << std::endl; - return true; - } - - private: - int mBrowserWindowWidth; - int mBrowserWindowHeight; - int mBrowserWindowHandle; - bool mNavigateInProgress; -}; - -int main( int argc, char* argv[] ) -{ - bool ingore_ssl_errors = false; - bool ignore_ca_file = false; - - for( int i = 1; i < argc; ++i ) - { - if ( std::string( argv[ i ] ) == "--help" ) - { - std::cout << std::endl << "ssltest [--ignoresslerrors] [--ignorecafile]" << std::endl; - std::cout << "Looks for cert file CA.pem in the current working directory"; - - exit( 0 ); - }; - - if ( std::string( argv[ i ] ) == "--ignoresslerrors" ) - ingore_ssl_errors = true; - - if ( std::string( argv[ i ] ) == "--ignorecafile" ) - ignore_ca_file = true; - }; - - std::string url ( "https://my.secondlife.com/callum.linden" ); - for( int i = 1; i < argc; ++i ) - { - if ( std::string( argv[ i ] ).substr( 0, 2 ) != "--" ) - { - url = std::string( argv[ i ] ); - break; - }; - }; - - std::cout << std::endl << " --------- sslTest application starting --------- " << std::endl; - std::cout << "ssltest> URL specified is " << url << std::endl; - - sslTest* app = new sslTest( url, ignore_ca_file, ingore_ssl_errors ); - - bool result = app->idle(); - while( result ) - { - result = app->idle(); - }; - - delete app; - - std::cout << " --------- sslTest application ending --------- " << std::endl; - - return 0; -} diff --git a/indra/llqtwebkit/tests/ssltest/ssltest.pro b/indra/llqtwebkit/tests/ssltest/ssltest.pro deleted file mode 100644 index 981e352113..0000000000 --- a/indra/llqtwebkit/tests/ssltest/ssltest.pro +++ /dev/null @@ -1,28 +0,0 @@ -TEMPLATE = app -TARGET = -DEPENDPATH += . -INCLUDEPATH += . -INCLUDEPATH += ../../ -CONFIG -= app_bundle -CONFIG += console - -QT += webkit network - -mac { - DEFINES += LL_OSX - LIBS += $$PWD/libllqtwebkit.dylib -} - -win32 { - DEFINES += _WINDOWS - INCLUDEPATH += ../ - DESTDIR=../build - LIBS += user32.lib - release { - LIBS += $$PWD/../../Release/llqtwebkit.lib - } -} - -include(../../static.pri) - -SOURCES += ssltest.cpp diff --git a/indra/llqtwebkit/tests/testgl/testgl.cpp b/indra/llqtwebkit/tests/testgl/testgl.cpp deleted file mode 100644 index 6dfb11a725..0000000000 --- a/indra/llqtwebkit/tests/testgl/testgl.cpp +++ /dev/null @@ -1,1002 +0,0 @@ -/* Copyright (c) 2006-2010, Linden Research, Inc. - * - * LLQtWebKit Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in GPL-license.txt in this distribution, or online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - */ - -#ifndef _WINDOWS -extern "C" { -#include -} -#endif - -#ifdef _WINDOWS -#include -#include // file choser dialog -#include // for local file access -#endif - -#include -#include -#include -#include -#include - -#ifdef LL_OSX -// I'm not sure why STATIC_QT is getting defined, but the Q_IMPORT_PLUGIN thing doesn't seem to be necessary on the mac. -#undef STATIC_QT -#endif - -#ifdef STATIC_QT -#include -Q_IMPORT_PLUGIN(qgif) -#endif - -#ifdef LL_OSX -#include -#include -#else -#define FREEGLUT_STATIC -#include "GL/glut.h" -#endif -#include "llqtwebkit.h" - -#ifdef _WINDOWS - #define PATH_SEPARATOR "\\" -#else - #define PATH_SEPARATOR "/" -#endif - - -//////////////////////////////////////////////////////////////////////////////// -// -std::string chooseFileName() -{ -#ifdef _WINDOWS - OPENFILENAMEA ofn ; - static char szFile[_MAX_PATH] ; - - ZeroMemory( &ofn , sizeof( ofn) ); - ofn.lStructSize = sizeof ( ofn ); - ofn.hwndOwner = NULL ; - ofn.lpstrFile = szFile ; - ofn.lpstrFile[0] = '\0'; - ofn.nMaxFile = sizeof( szFile ); - ofn.lpstrFilter = "All\0*.*\0Images\0*.jpg;*.png\0"; - ofn.nFilterIndex =1; - ofn.lpstrFileTitle = NULL ; - ofn.nMaxFileTitle = 0 ; - ofn.lpstrInitialDir=NULL ; - ofn.Flags = OFN_PATHMUSTEXIST|OFN_FILEMUSTEXIST ; - - GetOpenFileNameA( &ofn ); - - return ofn.lpstrFile; -#else - return ""; -#endif -} - -//////////////////////////////////////////////////////////////////////////////// -// Implementation of the test app - implemented as a class and derrives from -// the observer so we can catch events emitted by LLQtWebKit -// -class testGL : - public LLEmbeddedBrowserWindowObserver -{ - public: - testGL() : - mAppWindowWidth( 800 ), // dimensions of the app window - can be anything - mAppWindowHeight( 900 ), - mBrowserWindowWidth( mAppWindowWidth ), // dimensions of the embedded browser - can be anything - mBrowserWindowHeight( mAppWindowHeight ), // but looks best when it's the same as the app window - mAppTextureWidth( -1 ), // dimensions of the texture that the browser is rendered into - mAppTextureHeight( -1 ), // calculated at initialization - mAppTexture( 0 ), - mBrowserWindowId( 0 ), - mAppWindowName( "testGL" ), - mCwd(), - mHomeUrl(), - mNeedsUpdate( true ) // flag to indicate if browser texture needs an update - { -#ifdef _WINDOWS // to remove warning on Windows - mCwd = _getcwd(NULL, 1024); -#else - mCwd = getcwd(NULL, 1024); -#endif - mHomeUrl = "http://callum-linden.s3.amazonaws.com/browsertest.html"; - std::cout << "LLQtWebKit version: " << LLQtWebKit::getInstance()->getVersion() << std::endl; - - std::cout << "Current working directory is " << mCwd << std::endl; - }; - - //////////////////////////////////////////////////////////////////////////////// - // - void init( const std::string argv0, const std::string argv1 ) - { - // OpenGL initialization - glClearColor( 0.0f, 0.0f, 0.0f, 0.5f); - glEnable( GL_COLOR_MATERIAL ); - glColorMaterial( GL_FRONT, GL_AMBIENT_AND_DIFFUSE ); - glEnable( GL_TEXTURE_2D ); - glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); - glEnable( GL_CULL_FACE ); - - // calculate texture size required (next power of two above browser window size - for ( mAppTextureWidth = 1; mAppTextureWidth < mBrowserWindowWidth; mAppTextureWidth <<= 1 ) - { - }; - - for ( mAppTextureHeight = 1; mAppTextureHeight < mBrowserWindowHeight; mAppTextureHeight <<= 1 ) - { - }; - - // create the texture used to display the browser data - glGenTextures( 1, &mAppTexture ); - glBindTexture( GL_TEXTURE_2D, mAppTexture ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - glTexImage2D( GL_TEXTURE_2D, 0, - GL_RGB, - mAppTextureWidth, mAppTextureHeight, - 0, GL_RGB, GL_UNSIGNED_BYTE, 0 ); - - // create a single browser window and set things up. - mProfileDir = mCwd + PATH_SEPARATOR + "testGL_profile"; - std::cout << "Profiles dir location is " << mProfileDir << std::endl; - - mCookiePath = mProfileDir + PATH_SEPARATOR + "cookies.txt"; - std::cout << "Cookies.txt file location is " << mCookiePath << std::endl; - - LLQtWebKit::getInstance()->init( mApplicationDir, mApplicationDir, mProfileDir, getNativeWindowHandle() ); - - LLQtWebKit::getInstance()->enableQtMessageHandler( false ); - - // set host language test (in reality, string will be language code passed into client) - // IMPORTANT: must be called before createBrowserWindow(...) - LLQtWebKit::getInstance()->setHostLanguage( "EN-AB-CD-EF" ); - - // set up features - LLQtWebKit::getInstance()->enableJavaScript( true ); - LLQtWebKit::getInstance()->enableCookies( true ); - LLQtWebKit::getInstance()->enablePlugins( true ); - - // make a browser window - mBrowserWindowId = LLQtWebKit::getInstance()->createBrowserWindow( mBrowserWindowWidth, mBrowserWindowHeight ); - - // tell LLQtWebKit about the size of the browser window - LLQtWebKit::getInstance()->setSize( mBrowserWindowId, mBrowserWindowWidth, mBrowserWindowHeight ); - - // observer events that LLQtWebKit emits - LLQtWebKit::getInstance()->addObserver( mBrowserWindowId, this ); - - // append details to agent string - LLQtWebKit::getInstance()->setBrowserAgentId( mAppWindowName ); - - // don't flip bitmap - LLQtWebKit::getInstance()->flipWindow( mBrowserWindowId, false ); - - // only "trust" pages whose host match this regex - LLQtWebKit::getInstance()->setWhiteListRegex( mBrowserWindowId, "^([^.]+\\.)*amazonaws\\.com$" ); - - LLQtWebKit::getInstance()->enableLoadingOverlay( mBrowserWindowId, true ); - - // Attempt to read cookies from the cookie file and send them to llqtwebkit. - { - std::ifstream cookie_file(mCookiePath.c_str(), std::ios_base::in); - std::string cookies; - - while(cookie_file.good() && !cookie_file.eof()) - { - std::string tmp; - std::getline(cookie_file, tmp); - cookies += tmp; - cookies += "\n"; - } - - if(!cookies.empty()) - { - LLQtWebKit::getInstance()->setCookies(cookies); - } - } - - #if 0 - const std::vector before=LLQtWebKit::getInstance()->getInstalledCertsList(); - std::cout << "Certs before CA.pem load: " << before.size() << " items" << std::endl; - for(int i=0;isetCAFile( ca_pem_file_loc.c_str() ); - std::cout << "Expected CA.pem file location is " << ca_pem_file_loc << std::endl; - - #if 0 - const std::vector after=LLQtWebKit::getInstance()->getInstalledCertsList(); - std::cout << "Certs after CA.pem load: " << after.size() << " items" << std::endl; - for(int i=0;isetSLObjectEnabled( true ); // true means the feature is turned on - LLQtWebKit::getInstance()->setAgentLanguage( "tst-en" ); // viewer language selected by agent - LLQtWebKit::getInstance()->setAgentRegion( "TestGL region" ); // name of region where agent is located - LLQtWebKit::getInstance()->setAgentLocation( 9.8, 7.6, 5.4 ); // agent's x,y,z location within a region - LLQtWebKit::getInstance()->setAgentGlobalLocation( 1234.5, 6789.0, 3456.7 ); // agent's x,y,z location within a region - LLQtWebKit::getInstance()->setAgentOrientation( 175.69 ); // direction (0..359) agent is facing - LLQtWebKit::getInstance()->setAgentMaturity( "Very immature" ); // selected maturity level of agent - - // go to the "home page" or URL passed in via command line - if ( ! argv1.empty() ) - LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, argv1 ); - else - LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, mHomeUrl ); - }; - - //////////////////////////////////////////////////////////////////////////////// - // - void reset( void ) - { - // Get cookies from this instance - std::string cookies = LLQtWebKit::getInstance()->getAllCookies(); - - // Dump cookies to stdout -// std::cout << "Cookies:" << std::endl; -// std::cout << cookies; - - // and save them to cookies.txt in the profile directory - { - std::ofstream cookie_file(mCookiePath.c_str(), std::ios_base::out|std::ios_base::trunc); - - if(cookie_file.good()) - { - cookie_file << cookies; - } - - cookie_file.close(); - } - - // unhook observer - LLQtWebKit::getInstance()->remObserver( mBrowserWindowId, this ); - - // clean up - LLQtWebKit::getInstance()->reset(); - }; - - //////////////////////////////////////////////////////////////////////////////// - // - void reshape( int widthIn, int heightIn ) - { - if ( heightIn == 0 ) - heightIn = 1; - - LLQtWebKit::getInstance()->setSize(mBrowserWindowId, widthIn, heightIn ); - mNeedsUpdate = true; - - glMatrixMode( GL_PROJECTION ); - glLoadIdentity(); - - glViewport( 0, 0, widthIn, heightIn ); - glOrtho( 0.0f, widthIn, heightIn, 0.0f, -1.0f, 1.0f ); - - // we use these elsewhere so save - mAppWindowWidth = widthIn; - mAppWindowHeight = heightIn; - mBrowserWindowWidth = widthIn; - mBrowserWindowHeight = heightIn; - - glMatrixMode( GL_MODELVIEW ); - glLoadIdentity(); - - mNeedsUpdate = true; - idle(); - - glutPostRedisplay(); - }; - - void updateSLvariables() - { - if ( rand() % 2 ) - LLQtWebKit::getInstance()->setAgentRegion( "Region Wibble" ); - else - LLQtWebKit::getInstance()->setAgentRegion( "Region Flasm" ); - LLQtWebKit::getInstance()->setAgentLocation( (rand()%25600)/100.0f, (rand()%25600)/100.0f, (rand()%25600)/100.0f ); - LLQtWebKit::getInstance()->setAgentGlobalLocation( (rand()%25600)/10.0f, (rand()%25600)/10.0f, (rand()%25600)/10.0f ); - LLQtWebKit::getInstance()->setAgentOrientation( (rand()%3600)/10.0f ); - LLQtWebKit::getInstance()->emitLocation(); - - if ( rand() % 2 ) - LLQtWebKit::getInstance()->setAgentLanguage( "One language" ); - else - LLQtWebKit::getInstance()->setAgentLanguage( "Another language" ); - LLQtWebKit::getInstance()->emitLanguage(); - - if ( rand() % 2 ) - LLQtWebKit::getInstance()->setAgentMaturity( "Adults only" ); - else - LLQtWebKit::getInstance()->setAgentMaturity( "Children only" ); - LLQtWebKit::getInstance()->emitMaturity(); - } - - //////////////////////////////////////////////////////////////////////////////// - // - void idle() - { - static time_t starttime = time( NULL ); - if ( time( NULL ) - starttime ) - { - updateSLvariables(); - time( &starttime ); - }; - - LLQtWebKit::getInstance()->pump(100); - - // onPageChanged event sets this - if ( mNeedsUpdate ) - // grab a page but don't reset 'needs update' flag until we've written it to the texture in display() - LLQtWebKit::getInstance()->grabBrowserWindow( mBrowserWindowId ); - - // lots of updates for smooth motion - glutPostRedisplay(); - }; - - //////////////////////////////////////////////////////////////////////////////// - // - void display() - { - // clear screen - glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); - - glLoadIdentity(); - - // use the browser texture - glBindTexture( GL_TEXTURE_2D, mAppTexture ); - - // valid window ? - if ( mBrowserWindowId ) - { - // needs to be updated? - if ( mNeedsUpdate ) - { - // grab the page - const unsigned char* pixels = LLQtWebKit::getInstance()->getBrowserWindowPixels( mBrowserWindowId ); - if ( pixels ) - { - // write them into the texture - glTexSubImage2D( GL_TEXTURE_2D, 0, - 0, 0, - // because sometimes the rowspan != width * bytes per pixel (mBrowserWindowWidth) - LLQtWebKit::getInstance()->getBrowserRowSpan( mBrowserWindowId ) / LLQtWebKit::getInstance()->getBrowserDepth( mBrowserWindowId ), - mBrowserWindowHeight, -#ifdef _WINDOWS - LLQtWebKit::getInstance()->getBrowserDepth(mBrowserWindowId ) == 3 ? GL_RGBA : GL_RGBA, -#elif defined(__APPLE__) - GL_RGBA, -#elif defined(LL_LINUX) - GL_RGBA, -#endif - GL_UNSIGNED_BYTE, - pixels ); - }; - - // flag as already updated - mNeedsUpdate = false; - }; - }; - - // scale the texture so that it fits the screen - GLfloat textureScaleX = ( GLfloat )mBrowserWindowWidth / ( GLfloat )mAppTextureWidth; - GLfloat textureScaleY = ( GLfloat )mBrowserWindowHeight / ( GLfloat )mAppTextureHeight; - - // draw the single quad full screen (orthographic) - glMatrixMode( GL_TEXTURE ); - glPushMatrix(); - glScalef( textureScaleX, textureScaleY, 1.0f ); - - glEnable( GL_TEXTURE_2D ); - glColor3f( 1.0f, 1.0f, 1.0f ); - glBegin( GL_QUADS ); - glTexCoord2f( 1.0f, 0.0f ); - glVertex2d( mAppWindowWidth, 0 ); - - glTexCoord2f( 0.0f, 0.0f ); - glVertex2d( 0, 0 ); - - glTexCoord2f( 0.0f, 1.0f ); - glVertex2d( 0, mAppWindowHeight ); - - glTexCoord2f( 1.0f, 1.0f ); - glVertex2d( mAppWindowWidth, mAppWindowHeight ); - glEnd(); - - glMatrixMode( GL_TEXTURE ); - glPopMatrix(); - - glutSwapBuffers(); - }; - - //////////////////////////////////////////////////////////////////////////////// - // convert a GLUT keyboard modifier to an LLQtWebKit one - // (only valid in mouse and keyboard callbacks - LLQtWebKit::EKeyboardModifier getLLQtWebKitKeyboardModifierCode() - { - int result = LLQtWebKit::KM_MODIFIER_NONE; - - int modifiers = glutGetModifiers(); - - if ( GLUT_ACTIVE_SHIFT & modifiers ) - { - result |= LLQtWebKit::KM_MODIFIER_SHIFT; - } - - if ( GLUT_ACTIVE_CTRL & modifiers ) - result |= LLQtWebKit::KM_MODIFIER_CONTROL; - - if ( GLUT_ACTIVE_ALT & modifiers ) - result |= LLQtWebKit::KM_MODIFIER_ALT; - - return (LLQtWebKit::EKeyboardModifier)result; - }; - - //////////////////////////////////////////////////////////////////////////////// - // - void mouseButton( int button, int state, int xIn, int yIn ) - { - // texture is scaled to fit the screen so we scale mouse coords in the same way - xIn = ( xIn * mBrowserWindowWidth ) / mAppWindowWidth; - yIn = ( yIn * mBrowserWindowHeight ) / mAppWindowHeight; - - if ( button == GLUT_LEFT_BUTTON ) - { - if ( state == GLUT_DOWN ) - { - // send event to LLQtWebKit - LLQtWebKit::getInstance()->mouseEvent( mBrowserWindowId, - LLQtWebKit::ME_MOUSE_DOWN, - LLQtWebKit::MB_MOUSE_BUTTON_LEFT, - xIn, yIn, - getLLQtWebKitKeyboardModifierCode() ); - } - else - if ( state == GLUT_UP ) - { - // send event to LLQtWebKit - LLQtWebKit::getInstance()->mouseEvent( mBrowserWindowId, - LLQtWebKit::ME_MOUSE_UP, - LLQtWebKit::MB_MOUSE_BUTTON_LEFT, - xIn, yIn, - getLLQtWebKitKeyboardModifierCode() ); - - - // this seems better than sending focus on mouse down (still need to improve this) - LLQtWebKit::getInstance()->focusBrowser( mBrowserWindowId, true ); - }; - }; - - // force a GLUT update - glutPostRedisplay(); - } - - //////////////////////////////////////////////////////////////////////////////// - // - void mouseMove( int xIn , int yIn ) - { - // texture is scaled to fit the screen so we scale mouse coords in the same way - xIn = ( xIn * mBrowserWindowWidth ) / mAppWindowWidth; - yIn = ( yIn * mBrowserWindowHeight ) / mAppWindowHeight; - - // send event to LLQtWebKit - LLQtWebKit::getInstance()->mouseEvent( mBrowserWindowId, - LLQtWebKit::ME_MOUSE_MOVE, - LLQtWebKit::MB_MOUSE_BUTTON_LEFT, - xIn, yIn, - LLQtWebKit::KM_MODIFIER_NONE ); - - - // force a GLUT update - glutPostRedisplay(); - }; - - //////////////////////////////////////////////////////////////////////////////// - // - void keyboard( unsigned char keyIn, bool isDown) - { - // ESC key exits - if ( keyIn == 27 ) - { - reset(); - - exit( 0 ); - }; - - // Translate some keys - switch(keyIn) - { - case 127: - // Turn delete char into backspace - keyIn = LLQtWebKit::KEY_BACKSPACE; - break; - case '\r': - case '\n': - // Turn CR and NL into enter key - keyIn = LLQtWebKit::KEY_RETURN; - break; - - case '\t': - keyIn = LLQtWebKit::KEY_TAB; - break; - - default: - break; - } - - // control-H goes home - if ( keyIn == 8 ) - { - LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, mHomeUrl ); - } - // control-B navigates back - else if ( keyIn == 2 ) - { - LLQtWebKit::getInstance()->userAction(mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_BACK); - } - // control-F navigates forward - else if ( keyIn == 6 ) - { - LLQtWebKit::getInstance()->userAction(mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_FORWARD); - } - // control-R reloads - else if ( keyIn == 18 ) - { - LLQtWebKit::getInstance()->userAction(mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_RELOAD ); - } - // control-I toggles inspector - else if ( keyIn == 23 ) - { - LLQtWebKit::getInstance()->showWebInspector( true ); - } - else if ( keyIn == '1' ) - { - if ( getLLQtWebKitKeyboardModifierCode() == LLQtWebKit::KM_MODIFIER_CONTROL ) - { - LLQtWebKit::getInstance()->setPageZoomFactor( 1.0 ); - } - } - else if ( keyIn == '2' ) - { - if ( getLLQtWebKitKeyboardModifierCode() == LLQtWebKit::KM_MODIFIER_CONTROL ) - { - LLQtWebKit::getInstance()->setPageZoomFactor( 2.0 ); - } - } - - char text[2]; - if(keyIn < 0x80) - { - text[0] = (char)keyIn; - } - else - { - text[0] = 0; - } - - text[1] = 0; - - std::cerr << "key " << (isDown?"down ":"up ") << (int)keyIn << ", modifiers = " << (int)getLLQtWebKitKeyboardModifierCode() << std::endl; - - // send event to LLQtWebKit - LLQtWebKit::getInstance()->keyboardEvent(mBrowserWindowId, isDown?LLQtWebKit::KE_KEY_DOWN:LLQtWebKit::KE_KEY_UP, keyIn, text, getLLQtWebKitKeyboardModifierCode() ); - }; - - //////////////////////////////////////////////////////////////////////////////// - // - void keyboardSpecial( int specialIn, bool isDown) - { - uint32_t key = LLQtWebKit::KEY_NONE; - - switch(specialIn) - { - case GLUT_KEY_F1: key = LLQtWebKit::KEY_F1; break; - case GLUT_KEY_F2: key = LLQtWebKit::KEY_F2; break; - case GLUT_KEY_F3: key = LLQtWebKit::KEY_F3; break; - case GLUT_KEY_F4: key = LLQtWebKit::KEY_F4; break; - case GLUT_KEY_F5: key = LLQtWebKit::KEY_F5; break; - case GLUT_KEY_F6: key = LLQtWebKit::KEY_F6; break; - case GLUT_KEY_F7: key = LLQtWebKit::KEY_F7; break; - case GLUT_KEY_F8: key = LLQtWebKit::KEY_F8; break; - case GLUT_KEY_F9: key = LLQtWebKit::KEY_F9; break; - case GLUT_KEY_F10: key = LLQtWebKit::KEY_F10; break; - case GLUT_KEY_F11: key = LLQtWebKit::KEY_F11; break; - case GLUT_KEY_F12: key = LLQtWebKit::KEY_F12; break; - case GLUT_KEY_LEFT: key = LLQtWebKit::KEY_LEFT; break; - case GLUT_KEY_UP: key = LLQtWebKit::KEY_UP; break; - case GLUT_KEY_RIGHT: key = LLQtWebKit::KEY_RIGHT; break; - case GLUT_KEY_DOWN: key = LLQtWebKit::KEY_DOWN; break; - case GLUT_KEY_PAGE_UP: key = LLQtWebKit::KEY_PAGE_UP; break; - case GLUT_KEY_PAGE_DOWN: key = LLQtWebKit::KEY_PAGE_DOWN;break; - case GLUT_KEY_HOME: key = LLQtWebKit::KEY_HOME; break; - case GLUT_KEY_END: key = LLQtWebKit::KEY_END; break; - case GLUT_KEY_INSERT: key = LLQtWebKit::KEY_INSERT; break; - - default: - break; - } - - if(key != LLQtWebKit::KEY_NONE) - { - keyboard(key, isDown); - } - }; - - //////////////////////////////////////////////////////////////////////////////// - // virtual - void onPageChanged( const EventType& /*eventIn*/ ) - { - // flag that an update is required - page grab happens in idle() so we don't stall - mNeedsUpdate = true; - }; - - //////////////////////////////////////////////////////////////////////////////// - // virtual - void onNavigateBegin( const EventType& eventIn ) - { - std::cout << "Event: begin navigation to " << eventIn.getEventUri() << std::endl; - }; - - //////////////////////////////////////////////////////////////////////////////// - // virtual - void onNavigateComplete( const EventType& eventIn ) - { - std::cout << "Event: end navigation to " << eventIn.getEventUri() << std::endl; - }; - - //////////////////////////////////////////////////////////////////////////////// - // virtual - void onUpdateProgress( const EventType& eventIn ) - { - std::cout << "Event: progress value updated to " << eventIn.getIntValue() << std::endl; - }; - - //////////////////////////////////////////////////////////////////////////////// - // virtual - void onStatusTextChange( const EventType& eventIn ) - { - std::cout << "Event: status updated to " << eventIn.getStringValue() << std::endl; - }; - - //////////////////////////////////////////////////////////////////////////////// - // virtual - void onTitleChange( const EventType& eventIn ) - { - std::cout << "Event: title changed to " << eventIn.getStringValue() << std::endl; - glutSetWindowTitle( eventIn.getStringValue().c_str() ); - }; - - //////////////////////////////////////////////////////////////////////////////// - // virtual - void onLocationChange( const EventType& eventIn ) - { - std::cout << "Event: location changed to " << eventIn.getStringValue() << std::endl; - }; - - //////////////////////////////////////////////////////////////////////////////// - // virtual - void onClickLinkHref( const EventType& eventIn ) - { - std::string uuid = eventIn.getStringValue2(); - - std::cout << "Event: clicked on link:" << std::endl; - std::cout << " URL:" << eventIn.getEventUri() << std::endl; - std::cout << " target:" << eventIn.getStringValue() << std::endl; - std::cout << " UUID:" << uuid << std::endl; - std::cout << std::endl; - - // Since we never actually open the window, send a "proxy window closed" back to webkit to keep it from leaking. - LLQtWebKit::getInstance()->proxyWindowClosed(mBrowserWindowId, uuid); - }; - - // virtual - void onClickLinkNoFollow(const EventType& eventIn) - { - std::cout << "Clink link no-follow --" << std::endl; - std::cout << " URL:" << eventIn.getEventUri() << std::endl; - std::cout << " type:" << eventIn.getNavigationType() << std::endl; - std::cout << " trusted:" << eventIn.getTrustedHost() << std::endl; - } - - - //////////////////////////////////////////////////////////////////////////////// - // virtual - void onCookieChanged( const EventType& eventIn ) - { - int dead = eventIn.getIntValue(); - std::cout << (dead?"deleting cookie: ":"setting cookie: ") << eventIn.getStringValue() << std::endl; - } - - //////////////////////////////////////////////////////////////////////////////// - // virtual - std::string onRequestFilePicker( const EventType& ) - { - std::string fn = chooseFileName(); - return fn; - } - - //////////////////////////////////////////////////////////////////////////////// - // virtual - bool onAuthRequest(const std::string &in_url, const std::string &in_realm, std::string &out_username, std::string &out_password) - { - std::cout << "Auth request, url = " << in_url << ", realm = " << in_realm << std::endl; - out_username = ""; // replace these temporarily with site username/password as required. - out_password = ""; - return false; - } - - //////////////////////////////////////////////////////////////////////////////// - // virtual - bool onCertError(const std::string &in_url, const std::string &in_msg) - { - std::cout << "Cert error, url = " << in_url << ", message = " << in_msg << std::endl; - return false; // cancel (return true to ignore errors and continue) - } - - virtual void onQtDebugMessage( const std::string& msg, const std::string& msg_type) - { - std::cout << "QtDebugMsg [" << msg_type << "]> " << msg << std::endl; - } - - //////////////////////////////////////////////////////////////////////////////// - // virtual - void onLinkHovered( const EventType& eventIn ) - { - std::cout - << "Link hovered, link = " << eventIn.getEventUri() - << ", title = " << eventIn.getStringValue() - << ", text = " << eventIn.getStringValue2() - << std::endl; - }; - - //////////////////////////////////////////////////////////////////////////////// - // virtual - void onWindowCloseRequested( const EventType& ) - { - std::cout << "Event: window close requested" << std::endl; - }; - - //////////////////////////////////////////////////////////////////////////////// - // virtual - void onNavigateErrorPage( const EventType& event ) - { - std::cout << "Error page hit with code of " << event.getIntValue() << " - navigating to another URL" << std::endl; - LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, "http://bestbuy.com" ); - }; - - //////////////////////////////////////////////////////////////////////////////// - // virtual - void onWindowGeometryChangeRequested( const EventType& eventIn) - { - int x, y, width, height; - eventIn.getRectValue(x, y, width, height); - - std::cout << "Event: window geometry change requested" << std::endl; - std::cout << " uuid: " << eventIn.getStringValue() << std::endl; - std::cout << " location: (" << x << ", " << y << ")" << std::endl; - std::cout << " size: (" << width << ", " << height << ")" << std::endl; - }; - - //////////////////////////////////////////////////////////////////////////////// - // - int getAppWindowWidth() - { - return mAppWindowWidth; - }; - - //////////////////////////////////////////////////////////////////////////////// - // - int getAppWindowHeight() - { - return mAppWindowHeight; - }; - - //////////////////////////////////////////////////////////////////////////////// - // - std::string getAppWindowName() - { - return mAppWindowName; - }; - - //////////////////////////////////////////////////////////////////////////////// - // - void* getNativeWindowHandle() - { - // My implementation of the embedded browser needs a native window handle - // Can't get this via GLUT so had to use this hack - #ifdef _WINDOWS - return FindWindow( NULL, (LPCWSTR)mAppWindowName.c_str() ); - #else - #ifdef LL_OSX - // not needed on osx - return 0; - #else - //#error "You will need an implementation of this method" - return 0; - #endif - #endif - }; - - private: - int mAppWindowWidth; - int mAppWindowHeight; - int mBrowserWindowWidth; - int mBrowserWindowHeight; - int mAppTextureWidth; - int mAppTextureHeight; - GLuint mAppTexture; - int mBrowserWindowId; - std::string mAppWindowName; - std::string mHomeUrl; - std::string mCwd; - bool mNeedsUpdate; - std::string mApplicationDir; - std::string mProfileDir; - std::string mCookiePath; -}; - -testGL* theApp; - -//////////////////////////////////////////////////////////////////////////////// -// -void glutReshape( int widthIn, int heightIn ) -{ - if ( theApp ) - theApp->reshape( widthIn, heightIn ); -}; - -//////////////////////////////////////////////////////////////////////////////// -// -void glutDisplay() -{ - if ( theApp ) - theApp->display(); -}; - -//////////////////////////////////////////////////////////////////////////////// -// -void glutIdle() -{ - if ( theApp ) - theApp->idle(); -}; - -//////////////////////////////////////////////////////////////////////////////// -// -void glutKeyboard( unsigned char keyIn, int /*xIn*/, int /*yIn*/ ) -{ - if ( theApp ) - { - theApp->keyboard( keyIn, true ); - } -}; - -//////////////////////////////////////////////////////////////////////////////// -// -void glutKeyboardUp( unsigned char keyIn, int /*xIn*/, int /*yIn*/ ) -{ - if ( theApp ) - { - theApp->keyboard( keyIn, false ); - } -}; - -//////////////////////////////////////////////////////////////////////////////// -// -void glutSpecial( int specialIn, int /*xIn*/, int /*yIn*/ ) -{ - if ( theApp ) - { - theApp->keyboardSpecial( specialIn, true ); - } -}; - -//////////////////////////////////////////////////////////////////////////////// -// -void glutSpecialUp( int specialIn, int /*xIn*/, int /*yIn*/ ) -{ - if ( theApp ) - { - theApp->keyboardSpecial( specialIn, false ); - } -}; - -//////////////////////////////////////////////////////////////////////////////// -// -void glutMouseMove( int xIn , int yIn ) -{ - if ( theApp ) - theApp->mouseMove( xIn, yIn ); -} - -//////////////////////////////////////////////////////////////////////////////// -// -void glutMouseButton( int buttonIn, int stateIn, int xIn, int yIn ) -{ - if ( theApp ) - theApp->mouseButton( buttonIn, stateIn, xIn, yIn ); -} - -//////////////////////////////////////////////////////////////////////////////// -// -int main( int argc, char* argv[] ) -{ - glutInit( &argc, argv ); - glutInitDisplayMode( GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGB ); - - // implementation in a class so we can observer events - // means we need this painful GLUT <--> class shim... - theApp = new testGL; - - if ( theApp ) - { - glutInitWindowPosition( 80, 0 ); - glutInitWindowSize( theApp->getAppWindowWidth(), theApp->getAppWindowHeight() ); - - glutCreateWindow( theApp->getAppWindowName().c_str() ); - - std::string url = ""; - if ( 2 == argc ) - url = std::string( argv[ 1 ] ); - - theApp->init( std::string( argv[ 0 ] ), url ); - - glutKeyboardFunc( glutKeyboard ); - glutKeyboardUpFunc( glutKeyboardUp ); - glutSpecialFunc( glutSpecial ); - glutSpecialUpFunc( glutSpecialUp ); - - glutMouseFunc( glutMouseButton ); - glutPassiveMotionFunc( glutMouseMove ); - glutMotionFunc( glutMouseMove ); - - glutDisplayFunc( glutDisplay ); - glutReshapeFunc( glutReshape ); - - glutIdleFunc( glutIdle ); - - glutMainLoop(); - - std::cout << "glutMainLoop returned" << std::endl; - - delete theApp; - }; - - return 0; -} diff --git a/indra/llqtwebkit/tests/testgl/testgl.pro b/indra/llqtwebkit/tests/testgl/testgl.pro deleted file mode 100644 index 42692d68d6..0000000000 --- a/indra/llqtwebkit/tests/testgl/testgl.pro +++ /dev/null @@ -1,38 +0,0 @@ -TEMPLATE = app -TARGET = -DEPENDPATH += . -INCLUDEPATH += . -INCLUDEPATH += ../../ -CONFIG -= app_bundle - -QT += webkit opengl network - -!mac { -unix { - DEFINES += LL_LINUX - LIBS += -lglui -lglut - LIBS += $$PWD/../../libllqtwebkit.a -} -} - -mac { - DEFINES += LL_OSX - LIBS += -framework GLUT -framework OpenGL - LIBS += $$PWD/libllqtwebkit.dylib -} - -win32 { - DEFINES += _WINDOWS - INCLUDEPATH += ../ - INCLUDEPATH += $$PWD/../../stage/packages/include - DESTDIR=../build - release { - LIBS += $$PWD/../../Release/llqtwebkit.lib - LIBS += $$PWD/../build/freeglut_static.lib - LIBS += comdlg32.lib - } -} - -include(../../static.pri) - -SOURCES += testgl.cpp diff --git a/indra/llqtwebkit/tests/textmode/textmode.cpp b/indra/llqtwebkit/tests/textmode/textmode.cpp deleted file mode 100644 index 019fba902d..0000000000 --- a/indra/llqtwebkit/tests/textmode/textmode.cpp +++ /dev/null @@ -1,292 +0,0 @@ -/* Copyright (c) 2006-2010, Linden Research, Inc. - * - * LLQtWebKit Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in GPL-license.txt in this distribution, or online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/technology-programs/license-virtual-world/viewerlicensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - */ - -#ifndef _WINDOWS -extern "C" { -#include -} -#endif - -#ifdef _WINDOWS -#include -#include -#endif - -#include -#include -#include -#include -#include -#include - -#ifdef LL_OSX -// I'm not sure why STATIC_QT is getting defined, but the Q_IMPORT_PLUGIN thing doesn't seem to be necessary on the mac. -#undef STATIC_QT -#endif - -#ifdef STATIC_QT -#include -Q_IMPORT_PLUGIN(qgif) -#endif - -#include "llqtwebkit.h" - -class textMode : - public LLEmbeddedBrowserWindowObserver -{ - public: - textMode( std::string url, bool ignore_ca_file, bool ignore_ssl_errors ) : - mBrowserWindowWidth( 512 ), - mBrowserWindowHeight( 512 ), - mBrowserWindowHandle( 0 ), - mNavigateInProgress( true ), - mLogLine( "" ) - { - -#ifdef _WINDOWS - std::string cwd = std::string( _getcwd( NULL, 1024) ); - std::string profile_dir = cwd + "\\" + "textmode_profile"; - void* native_window_handle = (void*)GetDesktopWindow(); - std::string ca_file_loc = cwd + "\\" + "CA.pem"; -#else - std::string cwd = std::string( getcwd( NULL, 1024) ); - std::string profile_dir = cwd + "/" + "textmode_profile"; - void* native_window_handle = 0; - std::string ca_file_loc = cwd + "/" + "CA.pem"; -#endif - mLogLine << "Current working dir is " << cwd << std::endl; - mLogLine << "Profiles dir is " << profile_dir; - writeLine( mLogLine.str() ); - - LLQtWebKit::getInstance()->init( cwd, cwd, profile_dir, native_window_handle ); - - LLQtWebKit::getInstance()->enableQtMessageHandler( true ); - - LLQtWebKit::getInstance()->enableJavaScript( true ); - LLQtWebKit::getInstance()->enablePlugins( true ); - - mBrowserWindowHandle = LLQtWebKit::getInstance()->createBrowserWindow( mBrowserWindowWidth, mBrowserWindowHeight ); - LLQtWebKit::getInstance()->setSize( mBrowserWindowHandle, mBrowserWindowWidth, mBrowserWindowHeight ); - - LLQtWebKit::getInstance()->addObserver( mBrowserWindowHandle, this ); - - if ( ! ignore_ca_file ) - { - mLogLine.str(""); - mLogLine << "Expected certificate authority file location is " << ca_file_loc; - writeLine( mLogLine.str() ); - LLQtWebKit::getInstance()->setCAFile( ca_file_loc.c_str() ); - } - else - { - mLogLine.str(""); - mLogLine << "Not loading certificate authority file"; - writeLine( mLogLine.str() ); - }; - - if ( ignore_ssl_errors ) - { - LLQtWebKit::getInstance()->setIgnoreSSLCertErrors( true ); - mLogLine.str(""); - mLogLine << "Ignoring SSL errors"; - writeLine( mLogLine.str() ); - } - else - { - mLogLine.str(""); - mLogLine << "Not ignoring SSL errors"; - writeLine( mLogLine.str() ); - }; - - mLogLine.str(""); - mLogLine << "Navigating to " << url; - writeLine( mLogLine.str() ); - - LLQtWebKit::getInstance()->navigateTo( mBrowserWindowHandle, url ); - }; - - bool idle( void ) - { - LLQtWebKit::getInstance()->pump( 100 ); - -#if _WINDOWS - MSG msg; - while ( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) ) - { - GetMessage( &msg, NULL, 0, 0 ); - TranslateMessage( &msg ); - DispatchMessage( &msg ); - }; -#endif - return mNavigateInProgress; - }; - - ~textMode() - { - LLQtWebKit::getInstance()->remObserver( mBrowserWindowHandle, this ); - LLQtWebKit::getInstance()->reset(); - }; - - void onNavigateBegin( const EventType& eventIn ) - { - mNavigateInProgress = true; - mLogLine.str(""); - mLogLine << "Event: Begin navigation to " << eventIn.getEventUri(); - writeLine( mLogLine.str() ); - }; - - void onNavigateComplete( const EventType& eventIn ) - { - mLogLine.str(""); - mLogLine << "Event: End navigation to " << eventIn.getEventUri(); - writeLine( mLogLine.str() ); - mNavigateInProgress = false; - }; - - void onUpdateProgress( const EventType& eventIn ) - { - mLogLine.str(""); - mLogLine << "Event: progress value updated to " << eventIn.getIntValue(); - writeLine( mLogLine.str() ); - }; - - void onStatusTextChange( const EventType& eventIn ) - { - mLogLine.str(""); - mLogLine << "Event: status updated to " << eventIn.getStringValue(); - writeLine( mLogLine.str() ); - }; - - void onTitleChange( const EventType& eventIn ) - { - mLogLine.str(""); - mLogLine << "Event: title change to " << eventIn.getStringValue(); - writeLine( mLogLine.str() ); - }; - - void onLocationChange( const EventType& eventIn ) - { - mLogLine.str(""); - mLogLine << "Event: location changed to " << eventIn.getStringValue(); - writeLine( mLogLine.str() ); - }; - - bool onCertError(const std::string &in_url, const std::string &in_msg) - { - mLogLine.str(""); - mLogLine << "Cert error triggered: " << std::endl << in_url << "\n" << in_msg; - writeLine( mLogLine.str() ); - return true; - } - - void onCookieChanged(const EventType& event) - { - std::string url = event.getEventUri(); - std::string cookie = event.getStringValue(); - int dead = event.getIntValue(); - mLogLine.str(""); - if ( ! dead ) - mLogLine << "Cookie added:" << cookie; - else - mLogLine << "Cookie deleted:" << cookie; - writeLine( mLogLine.str() ); - } - - virtual void onQtDebugMessage( const std::string& msg, const std::string& msg_type) - { - mLogLine.str(""); - mLogLine << "QtDebugMsg (" << msg_type << "): " << msg.substr(msg.length() - 1); - writeLine( mLogLine.str() ); - } - - void writeLine( std::string line ) - { - double elapsed_seconds = (double)clock() / (double)CLOCKS_PER_SEC; - - std::cout << "[" << std::setprecision(7) << std::setw(3) << std::setfill('0') << elapsed_seconds << "] "; - const int max_len = 140; - if ( line.length() > max_len ) - { - std::cout << line.substr(0, max_len); - std::cout << "...."; - } - else - { - std::cout << line; - } - std::cout << std::endl; - //std::cout << std::endl; - } - - private: - int mBrowserWindowWidth; - int mBrowserWindowHeight; - int mBrowserWindowHandle; - bool mNavigateInProgress; - std::ostringstream mLogLine; -}; - -int main( int argc, char* argv[] ) -{ - bool ingore_ssl_errors = false; - bool ignore_ca_file = false; - - for( int i = 1; i < argc; ++i ) - { - if ( std::string( argv[ i ] ) == "--help" ) - { - std::cout << std::endl << "textmode " << std::endl; - exit( 0 ); - }; - - if ( std::string( argv[ i ] ) == "--ignoresslerrors" ) - ingore_ssl_errors = true; - - if ( std::string( argv[ i ] ) == "--ignorecafile" ) - ignore_ca_file = true; - }; - - std::string url ( "https://my.secondlife.com/callum.linden" ); - for( int i = 1; i < argc; ++i ) - { - if ( std::string( argv[ i ] ).substr( 0, 2 ) != "--" ) - { - url = std::string( argv[ i ] ); - break; - }; - }; - - textMode* app = new textMode( url, ignore_ca_file, ingore_ssl_errors ); - - bool result = app->idle(); - while( result ) - { - result = app->idle(); - }; - - delete app; - - return 0; -} diff --git a/indra/llqtwebkit/tests/textmode/textmode.pro b/indra/llqtwebkit/tests/textmode/textmode.pro deleted file mode 100644 index d41e1ea689..0000000000 --- a/indra/llqtwebkit/tests/textmode/textmode.pro +++ /dev/null @@ -1,28 +0,0 @@ -TEMPLATE = app -TARGET = -DEPENDPATH += . -INCLUDEPATH += . -INCLUDEPATH += ../../ -CONFIG -= app_bundle -CONFIG += console - -QT += webkit network - -mac { - DEFINES += LL_OSX - LIBS += $$PWD/libllqtwebkit.dylib -} - -win32 { - DEFINES += _WINDOWS - INCLUDEPATH += ../ - DESTDIR=../build - LIBS += user32.lib - release { - LIBS += $$PWD/../../Release/llqtwebkit.lib - } -} - -include(../../static.pri) - -SOURCES += textmode.cpp diff --git a/indra/llqtwebkit/win32/3p-qt-vars.bat b/indra/llqtwebkit/win32/3p-qt-vars.bat deleted file mode 100644 index 5ea118848d..0000000000 --- a/indra/llqtwebkit/win32/3p-qt-vars.bat +++ /dev/null @@ -1,6 +0,0 @@ -@echo off -echo Setting up a Qt environment using 3p-qt HG repository -set QTDIR=C:\Work\3p-llqtwebkit\stage -set PATH=C:\Work\3p-llqtwebkit\stage\bin;%PATH% -set QMAKESPEC=win32-msvc2010 -call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\Tools\vsvars32.bat" diff --git a/indra/llqtwebkit/win32/Qt Command Prompt (3p-qt).lnk b/indra/llqtwebkit/win32/Qt Command Prompt (3p-qt).lnk deleted file mode 100644 index 460a9e9cf1..0000000000 Binary files a/indra/llqtwebkit/win32/Qt Command Prompt (3p-qt).lnk and /dev/null differ diff --git a/indra/llrender/CMakeLists.txt b/indra/llrender/CMakeLists.txt index 38adb7dd00..029afac306 100644 --- a/indra/llrender/CMakeLists.txt +++ b/indra/llrender/CMakeLists.txt @@ -8,6 +8,7 @@ include(LLCommon) include(LLImage) include(LLMath) include(LLRender) +include(LLVFS) include(LLWindow) include(LLXML) include(LLVFS) @@ -18,6 +19,7 @@ include_directories( ${LLIMAGE_INCLUDE_DIRS} ${LLMATH_INCLUDE_DIRS} ${LLRENDER_INCLUDE_DIRS} + ${LLVFS_INCLUDE_DIRS} ${LLWINDOW_INCLUDE_DIRS} ${LLXML_INCLUDE_DIRS} ${LLVFS_INCLUDE_DIRS} @@ -74,7 +76,17 @@ set(llrender_HEADER_FILES set_source_files_properties(${llrender_HEADER_FILES} PROPERTIES HEADER_FILE_ONLY TRUE) +# Workaround hack for clang bugs +if (DARWIN) + set_property(SOURCE llgl.cpp PROPERTY COMPILE_FLAGS -O1) +endif (DARWIN) + list(APPEND llrender_SOURCE_FILES ${llrender_HEADER_FILES}) add_library (llrender ${llrender_SOURCE_FILES}) -add_dependencies(llrender prepare) + +target_link_libraries( + llrender + PUBLIC + llcommon + ) diff --git a/indra/llrender/llcubemap.cpp b/indra/llrender/llcubemap.cpp index 362452d837..09c76461da 100644 --- a/indra/llrender/llcubemap.cpp +++ b/indra/llrender/llcubemap.cpp @@ -34,6 +34,7 @@ #include "v3dmath.h" #include "m3math.h" #include "m4math.h" +#include "llmatrix4a.h" #include "llrender.h" #include "llglslshader.h" @@ -79,18 +80,16 @@ void LLCubeMap::initGL() // Not initialized, do stuff. if (mImages[0].isNull()) { - U32 texname = 0; - - LLImageGL::generateTextures(LLTexUnit::TT_CUBE_MAP, GL_RGB8, 1, &texname); + LLImageGL::GLTextureName texname = LLImageGL::createTextureName(); for (int i = 0; i < 6; i++) { mImages[i] = new LLImageGL(64, 64, 4, (use_cube_mipmaps? TRUE : FALSE)); mImages[i]->setTarget(mTargets[i], LLTexUnit::TT_CUBE_MAP); mRawImages[i] = new LLImageRaw(64, 64, 4); - mImages[i]->createGLTexture(0, mRawImages[i], texname); + mImages[i]->createGLTexture(0, mRawImages[i], &texname); - gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_CUBE_MAP, texname); + gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_CUBE_MAP, texname->getTexName()); mImages[i]->setAddressMode(LLTexUnit::TAM_CLAMP); stop_glerror(); } @@ -100,7 +99,7 @@ void LLCubeMap::initGL() } else { - llwarns << "Using cube map without extension!" << llendl; + LL_WARNS() << "Using cube map without extension!" << LL_ENDL; } } @@ -168,7 +167,7 @@ void LLCubeMap::init(const std::vector >& rawimages) } } -GLuint LLCubeMap::getGLName() +GLuint LLCubeMap::getTexName() { return mImages[0]->getTexName(); } @@ -265,18 +264,13 @@ void LLCubeMap::setMatrix(S32 stage) gGL.getTexUnit(stage)->activate(); } - LLVector3 x(gGLModelView+0); - LLVector3 y(gGLModelView+4); - LLVector3 z(gGLModelView+8); - - LLMatrix3 mat3; - mat3.setRows(x,y,z); - LLMatrix4 trans(mat3); + LLMatrix4a trans(gGLModelView); + trans.setRow<3>(LLVector4a::getZero()); trans.transpose(); gGL.matrixMode(LLRender::MM_TEXTURE); gGL.pushMatrix(); - gGL.loadMatrix((F32 *)trans.mMatrix); + gGL.loadMatrix(trans); gGL.matrixMode(LLRender::MM_MODELVIEW); /*if (stage > 0) @@ -305,7 +299,7 @@ void LLCubeMap::restoreMatrix() void LLCubeMap::setReflection (void) { - gGL.getTexUnit(mTextureStage)->bindManual(LLTexUnit::TT_CUBE_MAP, getGLName()); + gGL.getTexUnit(mTextureStage)->bindManual(LLTexUnit::TT_CUBE_MAP, getTexName()); mImages[0]->setFilteringOption(LLTexUnit::TFO_ANISOTROPIC); mImages[0]->setAddressMode(LLTexUnit::TAM_CLAMP); } diff --git a/indra/llrender/llcubemap.h b/indra/llrender/llcubemap.h index ee2c41e026..78975f2164 100644 --- a/indra/llrender/llcubemap.h +++ b/indra/llrender/llcubemap.h @@ -59,7 +59,7 @@ class LLCubeMap : public LLRefCount void finishPaint(); - GLuint getGLName(); + GLuint getTexName(); LLVector3 map(U8 side, U16 v_val, U16 h_val) const; BOOL project(F32& v_val, F32& h_val, BOOL& outside, diff --git a/indra/llrender/llfontfreetype.cpp b/indra/llrender/llfontfreetype.cpp index 36515c48ad..f954d2cc8b 100644 --- a/indra/llrender/llfontfreetype.cpp +++ b/indra/llrender/llfontfreetype.cpp @@ -2,45 +2,37 @@ * @file llfontfreetype.cpp * @brief Freetype font library wrapper * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #include "linden_common.h" #include "llfontfreetype.h" +#include "llfontgl.h" // Freetype stuff #include - -// For some reason, this won't work if it's not wrapped in the ifdef -#ifdef FT_FREETYPE_H #include FT_FREETYPE_H -#endif + #include "llerror.h" #include "llimage.h" @@ -82,7 +74,7 @@ LLFontManager::LLFontManager() if (error) { // Clean up freetype libs. - llerrs << "Freetype initialization failure!" << llendl; + LL_ERRS() << "Freetype initialization failure!" << LL_ENDL; FT_Done_FreeType(gFTLibrary); } } @@ -103,40 +95,20 @@ LLFontGlyphInfo::LLFontGlyphInfo(U32 index) mYBitmapOffset(0), // Offset to the origin in the bitmap mXBearing(0), // Distance from baseline to left in pixels mYBearing(0), // Distance from baseline to top in pixels - mIsRendered(FALSE), - mMetricsValid(FALSE) -{} - -LLFontList::LLFontList() + mBitmapNum(0) // Which bitmap in the bitmap cache contains this glyph { } -LLFontList::~LLFontList() -{ - LLFontList::iterator iter; - for(iter = this->begin(); iter != this->end(); iter++) - { - delete *iter; - // The (now dangling) pointers in the vector will be cleaned up when the vector is deleted by the superclass destructor. - } -} -void LLFontList::addAtEnd(LLFontFreetype *font) -{ - // Purely a convenience function - this->push_back(font); -} - LLFontFreetype::LLFontFreetype() : mFontBitmapCachep(new LLFontBitmapCache), - mValid(FALSE), mAscender(0.f), mDescender(0.f), mLineHeight(0.f), - mFallbackFontp(NULL), mIsFallback(FALSE), mFTFace(NULL), mRenderGlyphCount(0), mAddGlyphCount(0), + mStyle(0), mPointSize(0) { } @@ -165,7 +137,7 @@ BOOL LLFontFreetype::loadFace(const std::string& filename, const F32 point_size, mFTFace = NULL; } - llinfos << "Loading font file: " << filename << llendl; + LL_INFOS() << "Loading font file: " << filename << LL_ENDL; int error; @@ -209,42 +181,62 @@ BOOL LLFontFreetype::loadFace(const std::string& filename, const F32 point_size, mDescender = -mFTFace->descender * pixels_per_unit; mLineHeight = mFTFace->height * pixels_per_unit; - S32 max_char_width = llround(0.5f + (x_max - x_min)); - S32 max_char_height = llround(0.5f + (y_max - y_min)); + S32 max_char_width = ll_pos_round(0.5f + (x_max - x_min)); + S32 max_char_height = ll_pos_round(0.5f + (y_max - y_min)); mFontBitmapCachep->init(components, max_char_width, max_char_height); if (!mFTFace->charmap) { - //llinfos << " no unicode encoding, set whatever encoding there is..." << llendl; + //LL_INFOS() << " no unicode encoding, set whatever encoding there is..." << LL_ENDL; FT_Set_Charmap(mFTFace, mFTFace->charmaps[0]); } if (!mIsFallback || !sOpenGLcrashOnRestart) // because this often crashes under Linux... { - // Add the empty glyph`5 - addGlyph(0, 0); + // Add the default glyph + addGlyphFromFont(this, 0, 0); } mName = filename; mPointSize = point_size; + mStyle = LLFontGL::NORMAL; + if(mFTFace->style_flags & FT_STYLE_FLAG_BOLD) + { + mStyle |= LLFontGL::BOLD; + mStyle &= ~LLFontGL::NORMAL; + } + + if(mFTFace->style_flags & FT_STYLE_FLAG_ITALIC) + { + mStyle |= LLFontGL::ITALIC; + mStyle &= ~LLFontGL::NORMAL; + } + return TRUE; } -//virtual +void LLFontFreetype::setFallbackFonts(const font_vector_t &font) +{ + mFallbackFonts = font; +} + +const LLFontFreetype::font_vector_t &LLFontFreetype::getFallbackFonts() const +{ + return mFallbackFonts; +} + F32 LLFontFreetype::getLineHeight() const { return mLineHeight; } -//virtual F32 LLFontFreetype::getAscenderHeight() const { return mAscender; } -//virtual F32 LLFontFreetype::getDescenderHeight() const { return mDescender; @@ -255,65 +247,18 @@ F32 LLFontFreetype::getXAdvance(const llwchar wch) const if (mFTFace == NULL) return 0.0; - llassert(!mIsFallback); - U32 glyph_index; - // Return existing info only if it is current LLFontGlyphInfo* gi = getGlyphInfo(wch); - if (gi && gi->mMetricsValid) - { - return gi->mXAdvance; - } - - const LLFontFreetype* fontp = this; - - // Initialize char to glyph map - glyph_index = FT_Get_Char_Index(mFTFace, wch); - if (glyph_index == 0 && mFallbackFontp) + if (gi) { - LLFontList::iterator iter; - for(iter = mFallbackFontp->begin(); (iter != mFallbackFontp->end()) && (glyph_index == 0); iter++) - { - glyph_index = FT_Get_Char_Index((*iter)->mFTFace, wch); - if(glyph_index) - { - fontp = *iter; - } - } - } - - if (glyph_index) - { - // This font has this glyph - fontp->renderGlyph(glyph_index); - - // Create the entry if it's not there - char_glyph_info_map_t::iterator iter2 = mCharGlyphInfoMap.find(wch); - if (iter2 == mCharGlyphInfoMap.end()) - { - gi = new LLFontGlyphInfo(glyph_index); - insertGlyphInfo(wch, gi); - } - else - { - gi = iter2->second; - } - - gi->mWidth = fontp->mFTFace->glyph->bitmap.width; - gi->mHeight = fontp->mFTFace->glyph->bitmap.rows; - - // Convert these from 26.6 units to float pixels. - gi->mXAdvance = fontp->mFTFace->glyph->advance.x / 64.f; - gi->mYAdvance = fontp->mFTFace->glyph->advance.y / 64.f; - gi->mMetricsValid = TRUE; return gi->mXAdvance; } else { - gi = get_if_there(mCharGlyphInfoMap, (llwchar)0, (LLFontGlyphInfo*)NULL); - if (gi) + char_glyph_info_map_t::iterator found_it = mCharGlyphInfoMap.find((llwchar)0); + if (found_it != mCharGlyphInfoMap.end()) { - return gi->mXAdvance; + return found_it->second->mXAdvance; } } @@ -321,16 +266,24 @@ F32 LLFontFreetype::getXAdvance(const llwchar wch) const return (F32)mFontBitmapCachep->getMaxCharWidth(); } -F32 LLFontFreetype::getXKerning(const llwchar char_left, const llwchar char_right) const +F32 LLFontFreetype::getXAdvance(const LLFontGlyphInfo* glyph) const { if (mFTFace == NULL) return 0.0; - llassert(!mIsFallback); - LLFontGlyphInfo* left_glyph_info = get_if_there(mCharGlyphInfoMap, char_left, (LLFontGlyphInfo*)NULL); + return glyph->mXAdvance; +} + +F32 LLFontFreetype::getXKerning(llwchar char_left, llwchar char_right) const +{ + if (mFTFace == nullptr) + return 0.0; + + //llassert(!mIsFallback); + LLFontGlyphInfo* left_glyph_info = getGlyphInfo(char_left);; U32 left_glyph = left_glyph_info ? left_glyph_info->mGlyphIndex : 0; // Kern this puppy. - LLFontGlyphInfo* right_glyph_info = get_if_there(mCharGlyphInfoMap, char_right, (LLFontGlyphInfo*)NULL); + LLFontGlyphInfo* right_glyph_info = getGlyphInfo(char_right); U32 right_glyph = right_glyph_info ? right_glyph_info->mGlyphIndex : 0; FT_Vector delta; @@ -340,27 +293,34 @@ F32 LLFontFreetype::getXKerning(const llwchar char_left, const llwchar char_righ return delta.x*(1.f/64.f); } -BOOL LLFontFreetype::hasGlyph(const llwchar wch) const +F32 LLFontFreetype::getXKerning(const LLFontGlyphInfo* left_glyph_info, const LLFontGlyphInfo* right_glyph_info) const +{ + if (mFTFace == nullptr) + return 0.0; + + U32 left_glyph = left_glyph_info ? left_glyph_info->mGlyphIndex : 0; + U32 right_glyph = right_glyph_info ? right_glyph_info->mGlyphIndex : 0; + + FT_Vector delta; + + llverify(!FT_Get_Kerning(mFTFace, left_glyph, right_glyph, ft_kerning_unfitted, &delta)); + + return delta.x*(1.f/64.f); +} + +BOOL LLFontFreetype::hasGlyph(llwchar wch) const { llassert(!mIsFallback); - const LLFontGlyphInfo* gi = getGlyphInfo(wch); - if (gi && gi->mIsRendered) - { - return TRUE; - } - else - { - return FALSE; - } + return(mCharGlyphInfoMap.find(wch) != mCharGlyphInfoMap.end()); } -BOOL LLFontFreetype::addChar(const llwchar wch) const +LLFontGlyphInfo* LLFontFreetype::addGlyph(llwchar wch) const { if (mFTFace == NULL) return FALSE; llassert(!mIsFallback); - //lldebugs << "Adding new glyph for " << wch << " to font" << llendl; + //LL_DEBUGS() << "Adding new glyph for " << wch << " to font" << LL_ENDL; FT_UInt glyph_index; @@ -368,36 +328,30 @@ BOOL LLFontFreetype::addChar(const llwchar wch) const glyph_index = FT_Get_Char_Index(mFTFace, wch); if (glyph_index == 0) { - // Try looking it up in the backup Unicode font - if (mFallbackFontp) + //LL_INFOS() << "Trying to add glyph from fallback font!" << LL_ENDL; + font_vector_t::const_iterator iter; + for(iter = mFallbackFonts.begin(); iter != mFallbackFonts.end(); iter++) { - //llinfos << "Trying to add glyph from fallback font!" << llendl; - LLFontList::iterator iter; - for(iter = mFallbackFontp->begin(); iter != mFallbackFontp->end(); iter++) + glyph_index = FT_Get_Char_Index((*iter)->mFTFace, wch); + if (glyph_index) { - glyph_index = FT_Get_Char_Index((*iter)->mFTFace, wch); - if (glyph_index) - { - addGlyphFromFont(*iter, wch, glyph_index); - return TRUE; - } + return addGlyphFromFont(*iter, wch, glyph_index); } } } char_glyph_info_map_t::iterator iter = mCharGlyphInfoMap.find(wch); - if (iter == mCharGlyphInfoMap.end() || !(iter->second->mIsRendered)) + if (iter == mCharGlyphInfoMap.end()) { - BOOL result = addGlyph(wch, glyph_index); - return result; + return addGlyphFromFont(this, wch, glyph_index); } - return FALSE; + return NULL; } -BOOL LLFontFreetype::addGlyphFromFont(const LLFontFreetype *fontp, const llwchar wch, const U32 glyph_index) const +LLFontGlyphInfo* LLFontFreetype::addGlyphFromFont(const LLFontFreetype *fontp, llwchar wch, U32 glyph_index) const { if (mFTFace == NULL) - return FALSE; + return NULL; //llassert(!mIsFallback); fontp->renderGlyph(glyph_index); @@ -420,8 +374,6 @@ BOOL LLFontFreetype::addGlyphFromFont(const LLFontFreetype *fontp, const llwchar // Convert these from 26.6 units to float pixels. gi->mXAdvance = fontp->mFTFace->glyph->advance.x / 64.f; gi->mYAdvance = fontp->mFTFace->glyph->advance.y / 64.f; - gi->mIsRendered = TRUE; - gi->mMetricsValid = TRUE; insertGlyphInfo(wch, gi); @@ -492,17 +444,25 @@ BOOL LLFontFreetype::addGlyphFromFont(const LLFontFreetype *fontp, const llwchar // omit it from the font-image. } - return TRUE; + LLImageGL *image_gl = mFontBitmapCachep->getImageGL(bitmap_num); + LLImageRaw *image_raw = mFontBitmapCachep->getImageRaw(bitmap_num); + image_gl->setSubImage(image_raw, 0, 0, image_gl->getWidth(), image_gl->getHeight()); + + return gi; } -LLFontGlyphInfo* LLFontFreetype::getGlyphInfo(const llwchar wch) const +LLFontGlyphInfo* LLFontFreetype::getGlyphInfo(llwchar wch) const { char_glyph_info_map_t::iterator iter = mCharGlyphInfoMap.find(wch); if (iter != mCharGlyphInfoMap.end()) { return iter->second; } - return NULL; + else + { + // this glyph doesn't yet exist, so render it and return the result + return addGlyph(wch); + } } void LLFontFreetype::insertGlyphInfo(llwchar wch, LLFontGlyphInfo* gi) const @@ -519,51 +479,86 @@ void LLFontFreetype::insertGlyphInfo(llwchar wch, LLFontGlyphInfo* gi) const } } -BOOL LLFontFreetype::addGlyph(const llwchar wch, const U32 glyph_index) const -{ - return addGlyphFromFont(this, wch, glyph_index); -} - void LLFontFreetype::renderGlyph(const U32 glyph_index) const { if (mFTFace == NULL) return; - llassert_always(! FT_Load_Glyph(mFTFace, glyph_index, FT_LOAD_DEFAULT)); - - llassert_always(! FT_Render_Glyph(mFTFace->glyph, gFontRenderMode) ); + if (FT_Load_Glyph(mFTFace, glyph_index, FT_LOAD_RENDER | FT_LOAD_TARGET_LIGHT) != 0) + { + // If glyph fails to load and/or render, render a fallback character + llassert_always(!FT_Load_Char(mFTFace, L'?', FT_LOAD_RENDER | FT_LOAD_TARGET_LIGHT)); + } mRenderGlyphCount++; } -void LLFontFreetype::resetBitmapCache() +void LLFontFreetype::reset(F32 vert_dpi, F32 horz_dpi) { - // Iterate through glyphs and clear the mIsRendered flag - for (char_glyph_info_map_t::iterator iter = mCharGlyphInfoMap.begin(); - iter != mCharGlyphInfoMap.end(); ++iter) + resetBitmapCache(); + loadFace(mName,mPointSize,vert_dpi,horz_dpi,mFontBitmapCachep->getNumComponents(),mIsFallback); + if (!mIsFallback) { - iter->second->mIsRendered = FALSE; - //FIXME: this is only strictly necessary when resetting the entire font, - //not just flushing the bitmap - iter->second->mMetricsValid = FALSE; + // This is the head of the list - need to rebuild ourself and all fallbacks. + //loadFace(mName,mPointSize,vert_dpi,horz_dpi,mFontBitmapCachep->getNumComponents(),mIsFallback); + if (mFallbackFonts.empty()) + { + LL_WARNS() << "LLFontGL::reset(), no fallback fonts present" << LL_ENDL; + } + else + { + for(font_vector_t::iterator it = mFallbackFonts.begin(); + it != mFallbackFonts.end(); + ++it) + { + (*it)->reset(vert_dpi, horz_dpi); + } + } } +} + +void LLFontFreetype::resetBitmapCache() +{ + for_each(mCharGlyphInfoMap.begin(), mCharGlyphInfoMap.end(), DeletePairedPointer()); + mCharGlyphInfoMap.clear(); + mFontBitmapCachep->reset(); + // Adding default glyph is skipped for fallback fonts here as well as in loadFace(). + // This if was added as fix for EXT-4971. if (!mIsFallback || !sOpenGLcrashOnRestart) // because this often crashes under Linux... { - // Add the empty glyph`5 - addGlyph(0, 0); + // Add the empty glyph + addGlyphFromFont(this, 0, 0); } } +void LLFontFreetype::destroyGL() +{ + mFontBitmapCachep->destroyGL(); +} + +const std::string &LLFontFreetype::getName() const +{ + return mName; +} + +const LLPointer LLFontFreetype::getFontBitmapCache() const +{ + return mFontBitmapCachep; +} + +void LLFontFreetype::setStyle(U8 style) +{ + mStyle = style; +} + +U8 LLFontFreetype::getStyle() const +{ + return mStyle; +} -void LLFontFreetype::setSubImageLuminanceAlpha(const U32 x, - const U32 y, - const U32 bitmap_num, - const U32 width, - const U32 height, - const U8 *data, - S32 stride) const +void LLFontFreetype::setSubImageLuminanceAlpha(const U32 x, const U32 y, const U32 bitmap_num, const U32 width, const U32 height, const U8 *data, S32 stride) const { LLImageRaw *image_raw = mFontBitmapCachep->getImageRaw(bitmap_num); diff --git a/indra/llrender/llfontfreetype.h b/indra/llrender/llfontfreetype.h index 1a7dfb9ade..649fb254ba 100644 --- a/indra/llrender/llfontfreetype.h +++ b/indra/llrender/llfontfreetype.h @@ -1,40 +1,34 @@ /** - * @file llfont.h + * @file llfontfreetype.h * @brief Font library wrapper * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #ifndef LL_LLFONTFREETYPE_H #define LL_LLFONTFREETYPE_H -#include -#include "llmemory.h" +#include +#include "llpointer.h" #include "llstl.h" #include "llimagegl.h" @@ -51,34 +45,30 @@ class LLFontFreetype; struct FT_FaceRec_; typedef struct FT_FaceRec_* LLFT_Face; -extern LLFontManager *gFontManagerp; - class LLFontManager { public: static void initClass(); static void cleanupClass(); -public: +private: LLFontManager(); - virtual ~LLFontManager(); + ~LLFontManager(); }; -class LLFontGlyphInfo +struct LLFontGlyphInfo { -public: LLFontGlyphInfo(U32 index); -public: + U32 mGlyphIndex; + // Metrics S32 mWidth; // In pixels S32 mHeight; // In pixels F32 mXAdvance; // In pixels F32 mYAdvance; // In pixels - BOOL mMetricsValid; // We have up-to-date metrics for this glyph // Information for actually rendering - BOOL mIsRendered; // We actually have rendered this glyph S32 mXBitmapOffset; // Offset to the origin in the bitmap S32 mYBitmapOffset; // Offset to the origin in the bitmap S32 mXBearing; // Distance from baseline to left in pixels @@ -86,37 +76,27 @@ class LLFontGlyphInfo S32 mBitmapNum; // Which bitmap in the bitmap cache contains this glyph }; -// Used for lists of fallback fonts -class LLFontList : public std::vector -{ -public: - LLFontList(); - ~LLFontList(); - void addAtEnd(LLFontFreetype *font); -}; +extern LLFontManager *gFontManagerp; -class LLFontFreetype +class LLFontFreetype : public LLRefCount { public: LLFontFreetype(); - virtual ~LLFontFreetype(); + ~LLFontFreetype(); // is_fallback should be true for fallback fonts that aren't used // to render directly (Unicode backup, primarily) - virtual BOOL loadFace(const std::string& filename, - const F32 point_size, - const F32 vert_dpi, - const F32 horz_dpi, - const S32 components, - BOOL is_fallback); - void setFallbackFont(LLFontList *fontp) { mFallbackFontp = fontp; } + BOOL loadFace(const std::string& filename, const F32 point_size, const F32 vert_dpi, const F32 horz_dpi, const S32 components, BOOL is_fallback); + + typedef std::vector > font_vector_t; - void setCharToGlyphMap(llwchar wch, U32 glyph_index) const; + void setFallbackFonts(const font_vector_t &font); + const font_vector_t &getFallbackFonts() const; // Global font metrics - in units of pixels - virtual F32 getLineHeight() const; - virtual F32 getAscenderHeight() const; - virtual F32 getDescenderHeight() const; + F32 getLineHeight() const; + F32 getAscenderHeight() const; + F32 getDescenderHeight() const; // For a lowercase "g": @@ -145,51 +125,53 @@ class LLFontFreetype LAST_CHAR_FULL = 255 }; - const LLFontGlyphInfo &getMetrics(const llwchar wc) const; - F32 getXAdvance(const llwchar wc) const; - F32 getXKerning(const llwchar char_left, const llwchar char_right) const; // Get the kerning between the two characters - virtual void reset() = 0; + F32 getXAdvance(llwchar wc) const; + F32 getXAdvance(const LLFontGlyphInfo* glyph) const; + F32 getXKerning(llwchar char_left, llwchar char_right) const; // Get the kerning between the two characters + F32 getXKerning(const LLFontGlyphInfo* left_glyph_info, const LLFontGlyphInfo* right_glyph_info) const; // Get the kerning between the two characters + LLFontGlyphInfo* getGlyphInfo(const llwchar wch) const; - static bool sOpenGLcrashOnRestart; + void reset(F32 vert_dpi, F32 horz_dpi); -protected: - virtual BOOL hasGlyph(const llwchar wch) const; // Has a glyph for this character - virtual BOOL addChar(const llwchar wch) const; // Add a new character to the font if necessary - virtual BOOL addGlyph(const llwchar wch, const U32 glyph_index) const; // Add a new glyph to the existing font - virtual BOOL addGlyphFromFont(const LLFontFreetype *fontp, const llwchar wch, const U32 glyph_index) const; // Add a glyph from this font to the other (returns the glyph_index, 0 if not found) + void destroyGL(); - virtual LLFontGlyphInfo* getGlyphInfo(const llwchar wch) const; + const std::string& getName() const; - void insertGlyphInfo(llwchar wch, LLFontGlyphInfo* gi) const; - void renderGlyph(const U32 glyph_index) const; + const LLPointer getFontBitmapCache() const; + + void setStyle(U8 style); + U8 getStyle() const; + static bool sOpenGLcrashOnRestart; + +private: void resetBitmapCache(); + void setSubImageLuminanceAlpha(const U32 x, const U32 y, const U32 bitmap_num, const U32 width, const U32 height, const U8 *data, S32 stride = 0) const; + BOOL hasGlyph(llwchar wch) const; // Has a glyph for this character + LLFontGlyphInfo* addGlyph(llwchar wch) const; // Add a new character to the font if necessary + LLFontGlyphInfo* addGlyphFromFont(const LLFontFreetype *fontp, llwchar wch, U32 glyph_index) const; // Add a glyph from this font to the other (returns the glyph_index, 0 if not found) + void renderGlyph(U32 glyph_index) const; + void insertGlyphInfo(llwchar wch, LLFontGlyphInfo* gi) const; -protected: std::string mName; + + U8 mStyle; + F32 mPointSize; F32 mAscender; F32 mDescender; F32 mLineHeight; - mutable LLPointer mFontBitmapCachep; - LLFT_Face mFTFace; BOOL mIsFallback; - LLFontList *mFallbackFontp; // A list of fallback fonts to look for glyphs in (for Unicode chars) + font_vector_t mFallbackFonts; // A list of fallback fonts to look for glyphs in (for Unicode chars) - typedef std::map char_glyph_info_map_t; + typedef boost::unordered_map char_glyph_info_map_t; mutable char_glyph_info_map_t mCharGlyphInfoMap; // Information about glyph location in bitmap - BOOL mValid; - void setSubImageLuminanceAlpha(const U32 x, - const U32 y, - const U32 bitmap_num, - const U32 width, - const U32 height, - const U8 *data, - S32 stride = 0) const; + mutable LLPointer mFontBitmapCachep; + mutable S32 mRenderGlyphCount; mutable S32 mAddGlyphCount; }; diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp index 010dcf9407..1dea74985b 100644 --- a/indra/llrender/llfontgl.cpp +++ b/indra/llrender/llfontgl.cpp @@ -26,23 +26,28 @@ #include "linden_common.h" - - #include "llfontgl.h" // Linden library includes +#include "llfasttimer.h" #include "llfontfreetype.h" #include "llfontbitmapcache.h" #include "llfontregistry.h" #include "llgl.h" #include "llrender.h" -#include "v4color.h" #include "llstl.h" -#include "llfasttimer.h" +#include "v4color.h" +#include "lltexture.h" +#include "lldir.h" // Third party library includes #include +#if LL_WINDOWS +#include "llwin32headerslean.h" +#include +#endif + const S32 BOLD_OFFSET = 1; // static class members @@ -51,9 +56,9 @@ F32 LLFontGL::sHorizDPI = 96.f; F32 LLFontGL::sScaleX = 1.f; F32 LLFontGL::sScaleY = 1.f; BOOL LLFontGL::sDisplayFont = TRUE ; -std::string LLFontGL::sAppDir; +std::string LLFontGL::sFontDir; -LLColor4 LLFontGL::sShadowColor(0.f, 0.f, 0.f, 1.f); +LLColor4U LLFontGL::sShadowColor(0, 0, 0, 255); LLFontRegistry* LLFontGL::sFontRegistry = NULL; LLCoordGL LLFontGL::sCurOrigin; @@ -69,22 +74,9 @@ const F32 PIXEL_CORRECTION_DISTANCE = 0.01f; const F32 PAD_UVY = 0.5f; // half of vertical padding between glyphs in the glyph texture const F32 DROP_SHADOW_SOFT_STRENGTH = 0.3f; -F32 llfont_round_x(F32 x) -{ - //return llfloor((x-LLFontGL::sCurOrigin.mX)/LLFontGL::sScaleX+0.5f)*LLFontGL::sScaleX+LLFontGL::sCurOrigin.mX; - //return llfloor(x/LLFontGL::sScaleX+0.5f)*LLFontGL::sScaleY; - return x; -} - -F32 llfont_round_y(F32 y) -{ - //return llfloor((y-LLFontGL::sCurOrigin.mY)/LLFontGL::sScaleY+0.5f)*LLFontGL::sScaleY+LLFontGL::sCurOrigin.mY; - //return llfloor(y+0.5f); - return y; -} +const U32 GLYPH_VERTICES = 6; LLFontGL::LLFontGL() - : LLFontFreetype() { clearEmbeddedChars(); } @@ -96,69 +88,25 @@ LLFontGL::~LLFontGL() void LLFontGL::reset() { - if (!mIsFallback) - { - // This is the head of the list - need to rebuild ourself and all fallbacks. - loadFace(mName,mPointSize,sVertDPI,sHorizDPI,mFontBitmapCachep->getNumComponents(),mIsFallback); - if (mFallbackFontp==NULL) - { - llwarns << "LLFontGL::reset(), no fallback fonts present" << llendl; - } - else - { - for (LLFontList::iterator it = mFallbackFontp->begin(); - it != mFallbackFontp->end(); - ++it) - { - (*it)->reset(); - } - } - } - resetBitmapCache(); -} - -bool findOrCreateFont(LLFontGL*& fontp, const LLFontDescriptor& desc) -{ - // Don't delete existing fonts, if any, here, because they've - // already been deleted by LLFontRegistry::clear() - fontp = LLFontGL::getFont(desc); - return (fontp != NULL); + mFontFreetype->reset(sVertDPI, sHorizDPI); } - void LLFontGL::destroyGL() { - mFontBitmapCachep->destroyGL(); + mFontFreetype->destroyGL(); } BOOL LLFontGL::loadFace(const std::string& filename, const F32 point_size, const F32 vert_dpi, const F32 horz_dpi, const S32 components, BOOL is_fallback) { - if (!LLFontFreetype::loadFace(filename, point_size, vert_dpi, horz_dpi, components, is_fallback)) - { - return FALSE; - } - return TRUE; -} - - -BOOL LLFontGL::addChar(const llwchar wch) const -{ - if (!LLFontFreetype::addChar(wch)) + if(mFontFreetype == reinterpret_cast(NULL)) { - return FALSE; + mFontFreetype = new LLFontFreetype; } - stop_glerror(); - - LLFontGlyphInfo *glyph_info = getGlyphInfo(wch); - U32 bitmap_num = glyph_info->mBitmapNum; - LLImageGL *image_gl = mFontBitmapCachep->getImageGL(bitmap_num); - LLImageRaw *image_raw = mFontBitmapCachep->getImageRaw(bitmap_num); - image_gl->setSubImage(image_raw, 0, 0, image_gl->getWidth(), image_gl->getHeight()); - return TRUE; + return mFontFreetype->loadFace(filename, point_size, vert_dpi, horz_dpi, components, is_fallback); } -static LLFastTimer::DeclareTimer FTM_RENDER_FONTS("Fonts"); +static LLTrace::BlockTimerStatHandle FTM_RENDER_FONTS("Fonts"); S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, const LLRect& rect, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, ShadowType shadow, S32 max_chars, F32* right_x, BOOL use_embedded, BOOL use_ellipses) const @@ -188,24 +136,32 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, const LLRect& rect S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, ShadowType shadow, S32 max_chars, S32 max_pixels, F32* right_x, BOOL use_embedded, BOOL use_ellipses) const { - LLFastTimer _(FTM_RENDER_FONTS); + LL_RECORD_BLOCK_TIME(FTM_RENDER_FONTS); if(!sDisplayFont) //do not display texts { return wstr.length() ; } - if (wstr.empty()) + if (wstr.empty() || !max_pixels) { return 0; } + if (max_chars == -1) + max_chars = S32_MAX; + + const S32 max_index = llmin(llmax(max_chars, begin_offset + max_chars), S32(wstr.length())); + if (max_index <= 0 || begin_offset >= max_index || max_pixels <= 0) + return 0; + gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE); S32 scaled_max_pixels = max_pixels == S32_MAX ? S32_MAX : llceil((F32)max_pixels * sScaleX); - // Strip off any style bits that are already accounted for by the font. - style = style & (~getFontDesc().getStyle()); + // determine which style flags need to be added programmatically by stripping off the + // style bits that are drawn by the underlying Freetype font + U8 style_to_add = (style | mFontDescriptor.getStyle()) & ~mFontFreetype->getStyle(); F32 drop_shadow_strength = 0.f; if (shadow != NO_SHADOW) @@ -231,16 +187,7 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons S32 chars_drawn = 0; S32 i; - S32 length; - - if (-1 == max_chars) - { - length = (S32)wstr.length() - begin_offset; - } - else - { - length = llmin((S32)wstr.length() - begin_offset, max_chars ); - } + S32 length = max_index - begin_offset; F32 cur_x, cur_y, cur_render_x, cur_render_y; @@ -255,13 +202,13 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons switch (valign) { case TOP: - cur_y -= llceil(mAscender); + cur_y -= llceil(mFontFreetype->getAscenderHeight()); break; case BOTTOM: - cur_y += llceil(mDescender); + cur_y += llceil(mFontFreetype->getDescenderHeight()); break; case VCENTER: - cur_y -= llceil((llceil(mAscender) - llceil(mDescender))/2.f); + cur_y -= llceil((llceil(mFontFreetype->getAscenderHeight()) - llceil(mFontFreetype->getDescenderHeight())) / 2.f); break; case BASELINE: // Baseline, do nothing. @@ -275,10 +222,10 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons case LEFT: break; case RIGHT: - cur_x -= llmin(scaled_max_pixels, llround(getWidthF32(wstr.c_str(), begin_offset, length) * sScaleX)); + cur_x -= llmin(scaled_max_pixels, ll_pos_round(getWidthF32(wstr.c_str(), begin_offset, length) * sScaleX)); break; case HCENTER: - cur_x -= llmin(scaled_max_pixels, llround(getWidthF32(wstr.c_str(), begin_offset, length) * sScaleX)) / 2; + cur_x -= llmin(scaled_max_pixels, ll_pos_round(getWidthF32(wstr.c_str(), begin_offset, length) * sScaleX)) / 2; break; default: break; @@ -287,9 +234,9 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons cur_render_y = cur_y; cur_render_x = cur_x; - F32 start_x = (F32)llround(cur_x); + F32 start_x = (F32)ll_round(cur_x); - const LLFontBitmapCache* font_bitmap_cache = mFontBitmapCachep; + const LLFontBitmapCache* font_bitmap_cache = mFontFreetype->getFontBitmapCache(); F32 inv_width = 1.f / font_bitmap_cache->getBitmapWidth(); F32 inv_height = 1.f / font_bitmap_cache->getBitmapHeight(); @@ -301,20 +248,27 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons if (use_ellipses && halign == LEFT) { // check for too long of a string - S32 string_width = llround(getWidthF32(wstr.c_str(), begin_offset, max_chars) * sScaleX); + S32 string_width = ll_pos_round(getWidthF32(wstr, begin_offset, max_chars) * sScaleX); if (string_width > scaled_max_pixels) { // use four dots for ellipsis width to generate padding const LLWString dots(utf8str_to_wstring(std::string("...."))); - scaled_max_pixels = llmax(0, scaled_max_pixels - llround(getWidthF32(dots.c_str()))); + scaled_max_pixels = llmax(0, scaled_max_pixels - ll_pos_round(getWidthF32(dots.c_str()))); draw_ellipses = TRUE; } } + const LLFontGlyphInfo* next_glyph = NULL; - // Remember last-used texture to avoid unnecesssary bind calls. - LLImageGL *last_bound_texture = NULL; + const S32 GLYPH_BATCH_SIZE = 30; + static LL_ALIGN_16(LLVector4a vertices[GLYPH_BATCH_SIZE * GLYPH_VERTICES]); + static LLVector2 uvs[GLYPH_BATCH_SIZE * GLYPH_VERTICES]; + static LLColor4U colors[GLYPH_BATCH_SIZE * GLYPH_VERTICES]; + LLColor4U text_color(color); + + S32 bitmap_num = -1; + S32 glyph_count = 0; for (i = begin_offset; i < begin_offset + length; i++) { llwchar wch = wstr[i]; @@ -343,19 +297,31 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons break; } - if (last_bound_texture != ext_image) - { - gGL.getTexUnit(0)->bind(ext_image); - last_bound_texture = ext_image; - } + gGL.getTexUnit(0)->bind(ext_image); // snap origin to whole screen pixel - const F32 ext_x = (F32)llround(cur_render_x + (EXT_X_BEARING * sScaleX)); - const F32 ext_y = (F32)llround(cur_render_y + (EXT_Y_BEARING * sScaleY + mAscender - mLineHeight)); + const F32 ext_x = (F32)ll_round(cur_render_x + (EXT_X_BEARING * sScaleX)); + const F32 ext_y = (F32)ll_round(cur_render_y + (EXT_Y_BEARING * sScaleY + mFontFreetype->getAscenderHeight() - mFontFreetype->getLineHeight())); LLRectf uv_rect(0.f, 1.f, 1.f, 0.f); LLRectf screen_rect(ext_x, ext_y + ext_height, ext_x + ext_width, ext_y); - drawGlyph(screen_rect, uv_rect, LLColor4::white, style, shadow, drop_shadow_strength); + + if (glyph_count > 0) + { + gGL.begin(LLRender::TRIANGLES); + { + gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * GLYPH_VERTICES); + } + gGL.end(); + glyph_count = 0; + } + renderQuad(vertices, uvs, colors, screen_rect, uv_rect, LLColor4U::white, 0); + //No batching here. It will never happen. + gGL.begin(LLRender::TRIANGLES); + { + gGL.vertexBatchPreTransformed(vertices, uvs, colors, GLYPH_VERTICES); + } + gGL.end(); if (!label.empty()) { @@ -364,13 +330,11 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons /*llfloor*/(ext_x / sScaleX) + ext_image->getWidth() + EXT_X_BEARING - sCurOrigin.mX, /*llfloor*/(cur_render_y / sScaleY) - sCurOrigin.mY, color, - halign, BASELINE, NORMAL, NO_SHADOW, S32_MAX, S32_MAX, NULL, + halign, BASELINE, UNDERLINE, NO_SHADOW, S32_MAX, S32_MAX, NULL, TRUE ); gGL.popMatrix(); } - gGL.color4fv(color.mV); - chars_drawn++; cur_x += ext_advance; if (((i + 1) < length) && wstr[i+1]) @@ -381,23 +345,36 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons } else { - if (!hasGlyph(wch)) + const LLFontGlyphInfo* fgi = next_glyph; + next_glyph = NULL; + if(!fgi) { - addChar(wch); + fgi = mFontFreetype->getGlyphInfo(wch); } - - const LLFontGlyphInfo* fgi= getGlyphInfo(wch); if (!fgi) { - llerrs << "Missing Glyph Info" << llendl; + LL_ERRS() << "Missing Glyph Info" << LL_ENDL; break; } // Per-glyph bitmap texture. - LLImageGL *image_gl = mFontBitmapCachep->getImageGL(fgi->mBitmapNum); - if (last_bound_texture != image_gl) + S32 next_bitmap_num = fgi->mBitmapNum; + if (next_bitmap_num != bitmap_num) { - gGL.getTexUnit(0)->bind(image_gl); - last_bound_texture = image_gl; + // Actually draw the queued glyphs before switching their texture; + // otherwise the queued glyphs will be taken from wrong textures. + if (glyph_count > 0) + { + gGL.begin(LLRender::TRIANGLES); + { + gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * GLYPH_VERTICES); + } + gGL.end(); + glyph_count = 0; + } + + bitmap_num = next_bitmap_num; + LLImageGL *font_image = font_bitmap_cache->getImageGL(bitmap_num); + gGL.getTexUnit(0)->bind(font_image); } if ((start_x + scaled_max_pixels) < (cur_x + fgi->mXBearing + fgi->mWidth)) @@ -412,13 +389,24 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons (fgi->mYBitmapOffset + fgi->mHeight + PAD_UVY) * inv_height, (fgi->mXBitmapOffset + fgi->mWidth) * inv_width, (fgi->mYBitmapOffset - PAD_UVY) * inv_height); - // snap glyph origin to whole screen pixel - LLRectf screen_rect((F32)llround(cur_render_x + (F32)fgi->mXBearing), - (F32)llround(cur_render_y + (F32)fgi->mYBearing), - (F32)llround(cur_render_x + (F32)fgi->mXBearing) + (F32)fgi->mWidth, - (F32)llround(cur_render_y + (F32)fgi->mYBearing) - (F32)fgi->mHeight); + // snap glyph origin to whole screen pixel + LLRectf screen_rect((F32)ll_round(cur_render_x + (F32)fgi->mXBearing), + (F32)ll_round(cur_render_y + (F32)fgi->mYBearing), + (F32)ll_round(cur_render_x + (F32)fgi->mXBearing) + (F32)fgi->mWidth, + (F32)ll_round(cur_render_y + (F32)fgi->mYBearing) - (F32)fgi->mHeight); - drawGlyph(screen_rect, uv_rect, color, style, shadow, drop_shadow_strength); + if (glyph_count >= GLYPH_BATCH_SIZE) + { + gGL.begin(LLRender::TRIANGLES); + { + gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * GLYPH_VERTICES); + } + gGL.end(); + + glyph_count = 0; + } + + drawGlyph(glyph_count, vertices, uvs, colors, screen_rect, uv_rect, text_color, style_to_add, shadow, drop_shadow_strength); chars_drawn++; cur_x += fgi->mXAdvance; @@ -428,33 +416,41 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons if (next_char && (next_char < LAST_CHARACTER)) { // Kern this puppy. - if (!hasGlyph(next_char)) - { - addChar(next_char); - } - cur_x += getXKerning(wch, next_char); + next_glyph = mFontFreetype->getGlyphInfo(next_char); + cur_x += mFontFreetype->getXKerning(fgi, next_glyph); } // Round after kerning. // Must do this to cur_x, not just to cur_render_x, otherwise you // will squish sub-pixel kerned characters too close together. // For example, "CCCCC" looks bad. - cur_x = (F32)llround(cur_x); - //cur_y = (F32)llround(cur_y); + cur_x = (F32)ll_round(cur_x); + //cur_y = (F32)ll_round(cur_y); cur_render_x = cur_x; cur_render_y = cur_y; } } + if(glyph_count) + { + gGL.begin(LLRender::TRIANGLES); + { + gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * GLYPH_VERTICES); + } + gGL.end(); + } + + if (right_x) { *right_x = (cur_x - origin.mV[VX]) / sScaleX; } - if (style & UNDERLINE) + //FIXME: add underline as glyph? + if (style_to_add & UNDERLINE) { - F32 descender = (F32)llfloor(mDescender); + F32 descender = (F32)llfloor(mFontFreetype->getDescenderHeight()); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); gGL.begin(LLRender::LINES); @@ -474,7 +470,7 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons (cur_x - origin.mV[VX]) / sScaleX, (F32)y, color, LEFT, valign, - style, + style_to_add, shadow, S32_MAX, max_pixels, right_x, @@ -487,127 +483,120 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons return chars_drawn; } -S32 LLFontGL::render(const LLWString &text, S32 begin_offset, F32 x, F32 y, const LLColor4 &color) const -{ - return render(text, begin_offset, x, y, color, LEFT, BASELINE, NORMAL, NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE); -} - S32 LLFontGL::renderUTF8(const std::string &text, S32 begin_offset, F32 x, F32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, ShadowType shadow, S32 max_chars, S32 max_pixels, F32* right_x, BOOL use_ellipses) const { return render(utf8str_to_wstring(text), begin_offset, x, y, color, halign, valign, style, shadow, max_chars, max_pixels, right_x, use_ellipses); } -S32 LLFontGL::renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y, const LLColor4 &color) const -{ - return renderUTF8(text, begin_offset, (F32)x, (F32)y, color, LEFT, BASELINE, NORMAL, NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE); +// font metrics - override for LLFontFreetype that returns units of virtual pixels +F32 LLFontGL::getAscenderHeight() const +{ + return mFontFreetype->getAscenderHeight() / sScaleY; } -S32 LLFontGL::renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, ShadowType shadow) const -{ - return renderUTF8(text, begin_offset, (F32)x, (F32)y, color, halign, valign, style, shadow, S32_MAX, S32_MAX, NULL, FALSE); +F32 LLFontGL::getDescenderHeight() const +{ + return mFontFreetype->getDescenderHeight() / sScaleY; } -S32 LLFontGL::getWidth(const std::string& utf8text) const -{ - LLWString wtext = utf8str_to_wstring(utf8text); - return getWidth(wtext.c_str(), 0, S32_MAX); +F32 LLFontGL::getLineHeight() const +{ + return (F32)ll_pos_round(mFontFreetype->getLineHeight() / sScaleY); } -S32 LLFontGL::getWidth(const llwchar* wchars) const +S32 LLFontGL::getWidth(const std::string& utf8text, const S32 begin_offset, const S32 max_chars, BOOL use_embedded) const { - return getWidth(wchars, 0, S32_MAX); + return getWidth(utf8str_to_wstring(utf8text), begin_offset, max_chars, use_embedded); } -S32 LLFontGL::getWidth(const std::string& utf8text, const S32 begin_offset, const S32 max_chars) const +S32 LLFontGL::getWidth(const LLWString& utf32text, const S32 begin_offset, const S32 max_chars, BOOL use_embedded) const { - LLWString wtext = utf8str_to_wstring(utf8text); - return getWidth(wtext.c_str(), begin_offset, max_chars); + F32 width = getWidthF32(utf32text, begin_offset, max_chars, use_embedded); + return ll_pos_round(width); } -S32 LLFontGL::getWidth(const llwchar* wchars, const S32 begin_offset, const S32 max_chars, BOOL use_embedded) const +F32 LLFontGL::getWidthF32(const std::string& utf8text, const S32 begin_offset, const S32 max_chars, BOOL use_embedded) const { - F32 width = getWidthF32(wchars, begin_offset, max_chars, use_embedded); - return llround(width); + return getWidthF32(utf8str_to_wstring(utf8text), begin_offset, max_chars, use_embedded); } -F32 LLFontGL::getWidthF32(const std::string& utf8text) const +F32 LLFontGL::getWidthF32(const LLWString& utf32text, const S32 begin_offset, const S32 max_chars, BOOL use_embedded) const { - LLWString wtext = utf8str_to_wstring(utf8text); - return getWidthF32(wtext.c_str(), 0, S32_MAX); -} + const S32 LAST_CHARACTER = LLFontFreetype::LAST_CHAR_FULL; -F32 LLFontGL::getWidthF32(const llwchar* wchars) const -{ - return getWidthF32(wchars, 0, S32_MAX); -} + const S32 max_index = llmin(llmax(max_chars, begin_offset + max_chars), S32(utf32text.length())); + if (max_index <= 0 || begin_offset >= max_index) + return 0; -F32 LLFontGL::getWidthF32(const std::string& utf8text, const S32 begin_offset, const S32 max_chars ) const -{ - LLWString wtext = utf8str_to_wstring(utf8text); - return getWidthF32(wtext.c_str(), begin_offset, max_chars); -} + F32 cur_x = 0; -F32 LLFontGL::getWidthF32(const llwchar* wchars, const S32 begin_offset, const S32 max_chars, BOOL use_embedded) const -{ - const S32 LAST_CHARACTER = LLFontFreetype::LAST_CHAR_FULL; + const LLFontGlyphInfo* next_glyph = NULL; - F32 cur_x = 0; - const S32 max_index = begin_offset + max_chars; + F32 width_padding = 0.f; for (S32 i = begin_offset; i < max_index; i++) { - const llwchar wch = wchars[i]; - if (wch == 0) - { - break; // done - } + const llwchar wch = utf32text[i]; const embedded_data_t* ext_data = use_embedded ? getEmbeddedCharData(wch) : NULL; if (ext_data) { // Handle crappy embedded hack cur_x += getEmbeddedCharAdvance(ext_data); - if( ((i+1) < max_chars) && (i+1 < max_index)) + if(i+1 < max_index) { cur_x += EXT_KERNING * sScaleX; } } else { - cur_x += getXAdvance(wch); - llwchar next_char = wchars[i+1]; + const LLFontGlyphInfo* fgi = next_glyph; + next_glyph = NULL; + if(!fgi) + { + fgi = mFontFreetype->getGlyphInfo(wch); + } + + F32 advance = mFontFreetype->getXAdvance(fgi); - if (((i + 1) < begin_offset + max_chars) - && next_char - && (next_char < LAST_CHARACTER)) + // for the last character we want to measure the greater of its width and xadvance values + // so keep track of the difference between these values for the each character we measure + // so we can fix things up at the end + width_padding = llmax( 0.f, // always use positive padding amount + width_padding - advance, // previous padding left over after advance of current character + (F32)(fgi->mWidth + fgi->mXBearing) - advance); // difference between width of this character and advance to next character + + cur_x += advance; + if ((i + 1) < max_index) { - // Kern this puppy. - cur_x += getXKerning(wch, next_char); + llwchar next_char = utf32text[i+1]; + if (next_char < LAST_CHARACTER) + { + // Kern this puppy. + next_glyph = mFontFreetype->getGlyphInfo(next_char); + cur_x += mFontFreetype->getXKerning(fgi, next_glyph); + } } + // Round after kerning. + cur_x = (F32)ll_pos_round(cur_x); } - // Round after kerning. - cur_x = (F32)llround(cur_x); } + // add in extra pixels for last character's width past its xadvance + cur_x += width_padding; + return cur_x / sScaleX; } // Returns the max number of complete characters from text (up to max_chars) that can be drawn in max_pixels -S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_chars, +S32 LLFontGL::maxDrawableChars(const LLWString& utf32text, F32 max_pixels, S32 max_chars, EWordWrapStyle end_on_word_boundary, const BOOL use_embedded, F32* drawn_pixels) const { - if (!wchars || !wchars[0] || max_chars == 0) - { + const S32 max_index = llmin(max_chars, S32(utf32text.length())); + if (max_index <= 0 || max_pixels <= 0.f) return 0; - } - - //llassert(max_pixels >= 0.f); - //llassert(max_chars >= 0); - if(max_pixels < 0.f || max_chars < 0) { - return 0; - } BOOL clip = FALSE; F32 cur_x = 0; @@ -616,18 +605,16 @@ S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_ch S32 start_of_last_word = 0; BOOL in_word = FALSE; - F32 scaled_max_pixels = (F32)llceil(max_pixels * sScaleX); + // avoid S32 overflow when max_pixels == S32_MAX by staying in floating point + F32 scaled_max_pixels = max_pixels * sScaleX; + F32 width_padding = 0.f; + + LLFontGlyphInfo* next_glyph = NULL; S32 i; - for (i=0; (i < max_chars); i++) + for (i=0; (i < max_index); i++) { - llwchar wch = wchars[i]; - - if(wch == 0) - { - // Null terminator. We're done. - break; - } + llwchar wch = utf32text[i]; const embedded_data_t* ext_data = use_embedded ? getEmbeddedCharData(wch) : NULL; if (ext_data) @@ -648,7 +635,7 @@ S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_ch break; } - if (((i+1) < max_chars) && wchars[i+1]) + if ((i+1) < max_index) { cur_x += EXT_KERNING * sScaleX; } @@ -677,22 +664,36 @@ S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_ch } } - cur_x += getXAdvance(wch); - - if (scaled_max_pixels < cur_x) + LLFontGlyphInfo* fgi = next_glyph; + next_glyph = NULL; + if(!fgi) + { + fgi = mFontFreetype->getGlyphInfo(wch); + } + + // account for glyphs that run beyond the starting point for the next glyphs + width_padding = llmax( 0.f, // always use positive padding amount + width_padding - fgi->mXAdvance, // previous padding left over after advance of current character + (F32)(fgi->mWidth + fgi->mXBearing) - fgi->mXAdvance); // difference between width of this character and advance to next character + + cur_x += fgi->mXAdvance; + + // clip if current character runs past scaled_max_pixels (using width_padding) + if (scaled_max_pixels < cur_x + width_padding) { clip = TRUE; break; } - if (((i+1) < max_chars) && wchars[i+1]) + if ((i+1) < max_index) { // Kern this puppy. - cur_x += getXKerning(wch, wchars[i+1]); + next_glyph = mFontFreetype->getGlyphInfo(utf32text[i + 1]); + cur_x += mFontFreetype->getXKerning(fgi, next_glyph); } } // Round after kerning. - cur_x = (F32)llround(cur_x); + cur_x = (F32)ll_pos_round(cur_x); drawn_x = cur_x; } @@ -725,35 +726,49 @@ S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_ch } -S32 LLFontGL::firstDrawableChar(const llwchar* wchars, F32 max_pixels, S32 text_len, S32 start_pos, S32 max_chars) const +S32 LLFontGL::firstDrawableChar(const LLWString& utf32text, F32 max_pixels, S32 start_pos, S32 max_chars) const { - if (!wchars || !wchars[0] || max_chars == 0) - { + const S32 max_index = llmin(llmax(max_chars, start_pos + max_chars), S32(utf32text.length())); + if (max_index <= 0 || start_pos >= max_index || max_pixels <= 0.f || start_pos < 0) return 0; - } F32 total_width = 0.0; S32 drawable_chars = 0; F32 scaled_max_pixels = max_pixels * sScaleX; - S32 start = llmin(start_pos, text_len - 1); + S32 start = llmin(start_pos, max_index - 1); for (S32 i = start; i >= 0; i--) { - llwchar wch = wchars[i]; + llwchar wch = utf32text[i]; const embedded_data_t* ext_data = getEmbeddedCharData(wch); - F32 char_width = ext_data ? getEmbeddedCharAdvance(ext_data) : getXAdvance(wch); + F32 width = 0; + + if(ext_data) + { + width = getEmbeddedCharAdvance(ext_data); + } + else + { + const LLFontGlyphInfo* fgi= mFontFreetype->getGlyphInfo(wch); - if( scaled_max_pixels < (total_width + char_width) ) + // last character uses character width, since the whole character needs to be visible + // other characters just use advance + width = (i == start) + ? (F32)(fgi->mWidth + fgi->mXBearing) // use actual width for last character + : fgi->mXAdvance; // use advance for all other characters + } + + if( scaled_max_pixels < (total_width + width) ) { break; } - total_width += char_width; + total_width += width; drawable_chars++; - if( max_chars >= 0 && drawable_chars >= max_chars ) + if( max_index >= 0 && drawable_chars >= max_index ) { break; } @@ -761,121 +776,108 @@ S32 LLFontGL::firstDrawableChar(const llwchar* wchars, F32 max_pixels, S32 text_ if ( i > 0 ) { // kerning - total_width += ext_data ? (EXT_KERNING * sScaleX) : getXKerning(wchars[i-1], wch); + total_width += ext_data ? (EXT_KERNING * sScaleX) : mFontFreetype->getXKerning(utf32text[i - 1], wch); } // Round after kerning. - total_width = llround(total_width); + total_width = (F32)ll_pos_round(total_width); } - return start_pos - drawable_chars; + if (drawable_chars == 0) + { + return start_pos; // just draw last character + } + else + { + // if only 1 character is drawable, we want to return start_pos as the first character to draw + // if 2 are drawable, return start_pos and character before start_pos, etc. + return start_pos + 1 - drawable_chars; + } + } -S32 LLFontGL::charFromPixelOffset(const llwchar* wchars, const S32 begin_offset, F32 target_x, F32 max_pixels, S32 max_chars, BOOL round, BOOL use_embedded) const +S32 LLFontGL::charFromPixelOffset(const LLWString& utf32text, const S32 begin_offset, F32 target_x, F32 max_pixels, S32 max_chars, BOOL round, BOOL use_embedded) const { - if (!wchars || !wchars[0] || max_chars == 0) - { + const S32 max_index = llmin(llmax(max_chars,begin_offset + max_chars), S32(utf32text.length())); + if (max_index <= 0 || begin_offset >= max_index || max_pixels <= 0.f) return 0; - } F32 cur_x = 0; - S32 pos = 0; target_x *= sScaleX; - // max_chars is S32_MAX by default, so make sure we don't get overflow - const S32 max_index = begin_offset + llmin(S32_MAX - begin_offset, max_chars); - F32 scaled_max_pixels = max_pixels * sScaleX; + + const LLFontGlyphInfo* next_glyph = NULL; - for (S32 i = begin_offset; (i < max_index); i++) + S32 pos; + for (pos = begin_offset; pos < max_index; pos++) { - llwchar wch = wchars[i]; + llwchar wch = utf32text[pos]; if (!wch) { break; // done } + const embedded_data_t* ext_data = use_embedded ? getEmbeddedCharData(wch) : NULL; - if (ext_data) + const LLFontGlyphInfo* glyph = next_glyph; + next_glyph = NULL; + if(!glyph && !ext_data) { - F32 ext_advance = getEmbeddedCharAdvance(ext_data); - - if (round) - { - // Note: if the mouse is on the left half of the character, the pick is to the character's left - // If it's on the right half, the pick is to the right. - if (target_x < cur_x + ext_advance/2) - { - break; - } - } - else - { - if (target_x < cur_x + ext_advance) - { - break; - } - } + glyph = mFontFreetype->getGlyphInfo(wch); + } + + F32 char_width = ext_data ? getEmbeddedCharAdvance(ext_data) : mFontFreetype->getXAdvance(glyph); - if (scaled_max_pixels < cur_x + ext_advance) + if (round) + { + // Note: if the mouse is on the left half of the character, the pick is to the character's left + // If it's on the right half, the pick is to the right. + if (target_x < cur_x + char_width*0.5f) { break; } - - pos++; - cur_x += ext_advance; - - if (((i + 1) < max_index) - && (wchars[(i + 1)])) - { - cur_x += EXT_KERNING * sScaleX; - } - // Round after kerning. - cur_x = (F32)llfloor(cur_x + 0.5f); } - else + else if (target_x < cur_x + char_width) { - F32 char_width = getXAdvance(wch); + break; + } - if (round) - { - // Note: if the mouse is on the left half of the character, the pick is to the character's left - // If it's on the right half, the pick is to the right. - if (target_x < cur_x + char_width*0.5f) - { - break; - } - } - else if (target_x < cur_x + char_width) - { - break; - } + if (scaled_max_pixels < cur_x + char_width) + { + break; + } + + cur_x += char_width; - if (scaled_max_pixels < cur_x + char_width) + if ((pos + 1) < max_index) + { + + if(ext_data) { - break; + cur_x += EXT_KERNING * sScaleX; } - - pos++; - cur_x += char_width; - - if (((i + 1) < max_index) - && (wchars[(i + 1)])) + else { - llwchar next_char = wchars[i + 1]; - // Kern this puppy. - cur_x += getXKerning(wch, next_char); + next_glyph = mFontFreetype->getGlyphInfo(utf32text[pos + 1]); + cur_x += mFontFreetype->getXKerning(glyph, next_glyph); } - - // Round after kerning. - cur_x = (F32)llround(cur_x); } + + + // Round after kerning. + cur_x = (F32)ll_pos_round(cur_x); + } - return pos; + return pos - begin_offset; } +const LLFontDescriptor& LLFontGL::getFontDesc() const +{ + return mFontDescriptor; +} const LLFontGL::embedded_data_t* LLFontGL::getEmbeddedCharData(const llwchar wch) const { @@ -933,18 +935,18 @@ void LLFontGL::removeEmbeddedChar( llwchar wc ) const } // static -void LLFontGL::initClass(F32 screen_dpi, F32 x_scale, F32 y_scale, const std::string& app_dir, const std::vector& xui_paths, bool create_gl_textures) +void LLFontGL::initClass(F32 screen_dpi, F32 x_scale, F32 y_scale, const std::string& app_dir, bool create_gl_textures) { sVertDPI = (F32)llfloor(screen_dpi * y_scale); sHorizDPI = (F32)llfloor(screen_dpi * x_scale); sScaleX = x_scale; sScaleY = y_scale; - sAppDir = app_dir; + sFontDir = app_dir; // Font registry init if (!sFontRegistry) { - sFontRegistry = new LLFontRegistry(xui_paths,create_gl_textures); + sFontRegistry = new LLFontRegistry(create_gl_textures); sFontRegistry->parseFontInfo("fonts.xml"); } else @@ -999,7 +1001,7 @@ void LLFontGL::destroyAllGL() // static U8 LLFontGL::getStyleFromString(const std::string &style) { - S32 ret = 0; + U8 ret = 0; if (style.find("NORMAL") != style.npos) { ret |= NORMAL; @@ -1041,9 +1043,18 @@ std::string LLFontGL::getStringFromStyle(U8 style) } return style_string; } + +// static std::string LLFontGL::nameFromFont(const LLFontGL* fontp) { - return fontp->getFontDesc().getName(); + return fontp->mFontDescriptor.getName(); +} + + +// static +std::string LLFontGL::sizeFromFont(const LLFontGL* fontp) +{ + return fontp->getFontDesc().getSize(); } // static @@ -1108,6 +1119,7 @@ LLFontGL::VAlign LLFontGL::vAlignFromName(const std::string& name) //else leave baseline return gl_vfont_align; } + //static LLFontGL* LLFontGL::getFontMonospace() { @@ -1162,160 +1174,219 @@ LLFontGL* LLFontGL::getFont(const LLFontDescriptor& desc) return sFontRegistry->getFont(desc); } +// static +LLFontGL* LLFontGL::getFontByName(const std::string& name) +{ + // check for most common fonts first + if (name == "SANSSERIF") + { + return getFontSansSerif(); + } + else if (name == "SANSSERIF_SMALL") + { + return getFontSansSerifSmall(); + } + else if (name == "SANSSERIF_BIG") + { + return getFontSansSerifBig(); + } + else if (name == "SMALL" || name == "OCRA") + { + // *BUG: Should this be "MONOSPACE"? Do we use "OCRA" anymore? + // Does "SMALL" mean "SERIF"? + return getFontMonospace(); + } + else + { + return NULL; + } +} + +//static +LLFontGL* LLFontGL::getFontDefault() +{ + return getFontSansSerif(); // Fallback to sans serif as default font +} + +static std::string sSystemFontPath; + // static std::string LLFontGL::getFontPathSystem() { - std::string system_path; + if (!sSystemFontPath.empty()) return sSystemFontPath; - // Try to figure out where the system's font files are stored. - char *system_root = NULL; #if LL_WINDOWS - system_root = getenv("SystemRoot"); /* Flawfinder: ignore */ - if (!system_root) - { - llwarns << "SystemRoot not found, attempting to load fonts from default path." << llendl; - } -#endif - - if (system_root) + wchar_t* pPath = nullptr; + if (SHGetKnownFolderPath(FOLDERID_Fonts, 0, nullptr, &pPath) == S_OK) { - system_path = llformat("%s/fonts/", system_root); + sSystemFontPath = ll_convert_wide_to_string(pPath, CP_UTF8) + gDirUtilp->getDirDelimiter(); + LL_INFOS() << "from SHGetKnownFolderPath(): " << sSystemFontPath << LL_ENDL; + CoTaskMemFree(pPath); + pPath = nullptr; } else { -#if LL_WINDOWS - // HACK for windows 98/Me - system_path = "/WINDOWS/FONTS/"; + // Try to figure out where the system's font files are stored. + auto system_root = LLStringUtil::getenv("SystemRoot"); + if (! system_root.empty()) + { + sSystemFontPath = gDirUtilp->add(system_root, "fonts") + gDirUtilp->getDirDelimiter(); + LL_INFOS() << "from SystemRoot: " << sSystemFontPath << LL_ENDL; + } + else + { + LL_WARNS() << "SystemRoot not found, attempting to load fonts from default path." << LL_ENDL; + // HACK for windows 98/Me + sSystemFontPath = "/WINDOWS/FONTS/"; + } + } + #elif LL_DARWIN // HACK for Mac OS X - system_path = "/System/Library/Fonts/"; + sSystemFontPath = "/System/Library/Fonts/"; #endif - } - return system_path; + return sSystemFontPath; } +static std::string sLocalFontPath; // static std::string LLFontGL::getFontPathLocal() { - std::string local_path; + if (!sLocalFontPath.empty()) return sLocalFontPath; // Backup files if we can't load from system fonts directory. // We could store this in an end-user writable directory to allow // end users to switch fonts. - if (LLFontGL::sAppDir.length()) + if (!LLFontGL::sFontDir.empty()) { // use specified application dir to look for fonts - local_path = LLFontGL::sAppDir + "/fonts/"; + sLocalFontPath = gDirUtilp->add(LLFontGL::sFontDir, "fonts") + gDirUtilp->getDirDelimiter(); } else { // assume working directory is executable directory - local_path = "./fonts/"; + sLocalFontPath = "./fonts/"; } - return local_path; + return sLocalFontPath; } LLFontGL::LLFontGL(const LLFontGL &source) { - llerrs << "Not implemented!" << llendl; + LL_ERRS() << "Not implemented!" << LL_ENDL; } LLFontGL &LLFontGL::operator=(const LLFontGL &source) { - llerrs << "Not implemented" << llendl; + LL_ERRS() << "Not implemented" << LL_ENDL; return *this; } -void LLFontGL::renderQuad(const LLRectf& screen_rect, const LLRectf& uv_rect, F32 slant_amt) const +void LLFontGL::renderQuad(LLVector4a* vertex_out, LLVector2* uv_out, LLColor4U* colors_out, const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4U& color, F32 slant_amt) const { - gGL.texCoord2f(uv_rect.mRight, uv_rect.mTop); - gGL.vertex2f(llfont_round_x(screen_rect.mRight), - llfont_round_y(screen_rect.mTop)); - - gGL.texCoord2f(uv_rect.mLeft, uv_rect.mTop); - gGL.vertex2f(llfont_round_x(screen_rect.mLeft), - llfont_round_y(screen_rect.mTop)); - - gGL.texCoord2f(uv_rect.mLeft, uv_rect.mBottom); - gGL.vertex2f(llfont_round_x(screen_rect.mLeft + slant_amt), - llfont_round_y(screen_rect.mBottom)); - - gGL.texCoord2f(uv_rect.mRight, uv_rect.mBottom); - gGL.vertex2f(llfont_round_x(screen_rect.mRight + slant_amt), - llfont_round_y(screen_rect.mBottom)); + S32 index = 0; + + vertex_out[index].set(screen_rect.mLeft, screen_rect.mTop, 0.f); + uv_out[index] = LLVector2(uv_rect.mLeft, uv_rect.mTop); + colors_out[index] = color; + index++; + + vertex_out[index].set(screen_rect.mLeft + slant_amt, screen_rect.mBottom, 0.f); + uv_out[index] = LLVector2(uv_rect.mLeft, uv_rect.mBottom); + colors_out[index] = color; + index++; + + vertex_out[index].set(screen_rect.mRight, screen_rect.mTop, 0.f); + uv_out[index] = LLVector2(uv_rect.mRight, uv_rect.mTop); + colors_out[index] = color; + index++; + + vertex_out[index].set(screen_rect.mRight, screen_rect.mTop, 0.f); + uv_out[index] = LLVector2(uv_rect.mRight, uv_rect.mTop); + colors_out[index] = color; + index++; + + vertex_out[index].set(screen_rect.mLeft + slant_amt, screen_rect.mBottom, 0.f); + uv_out[index] = LLVector2(uv_rect.mLeft, uv_rect.mBottom); + colors_out[index] = color; + index++; + + vertex_out[index].set(screen_rect.mRight + slant_amt, screen_rect.mBottom, 0.f); + uv_out[index] = LLVector2(uv_rect.mRight, uv_rect.mBottom); + colors_out[index] = color; } -void LLFontGL::drawGlyph(const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4& color, U8 style, ShadowType shadow, F32 drop_shadow_strength) const +void LLFontGL::drawGlyph(S32& glyph_count, LLVector4a* vertex_out, LLVector2* uv_out, LLColor4U* colors_out, const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4U& color, U8 style, ShadowType shadow, F32 drop_shadow_strength) const { F32 slant_offset; - slant_offset = ((style & ITALIC) ? ( -mAscender * 0.2f) : 0.f); + slant_offset = ((style & ITALIC) ? ( -mFontFreetype->getAscenderHeight() * 0.2f) : 0.f); - gGL.begin(LLRender::QUADS); + //FIXME: bold and drop shadow are mutually exclusive only for convenience + //Allow both when we need them. + if (style & BOLD) { - //FIXME: bold and drop shadow are mutually exclusive only for convenience - //Allow both when we need them. - if (style & BOLD) + for (S32 pass = 0; pass < 2; pass++) { - gGL.color4fv(color.mV); - for (S32 pass = 0; pass < 2; pass++) - { - LLRectf screen_rect_offset = screen_rect; + LLRectf screen_rect_offset = screen_rect; - screen_rect_offset.translate((F32)(pass * BOLD_OFFSET), 0.f); - renderQuad(screen_rect_offset, uv_rect, slant_offset); - } + screen_rect_offset.translate((F32)(pass * BOLD_OFFSET), 0.f); + const U32 idx = glyph_count * GLYPH_VERTICES; + renderQuad(&vertex_out[idx], &uv_out[idx], &colors_out[idx], screen_rect_offset, uv_rect, color, slant_offset); + glyph_count++; } - else if (shadow == DROP_SHADOW_SOFT) + } + else if (shadow == DROP_SHADOW_SOFT) + { + LLColor4U& shadow_color = LLFontGL::sShadowColor; + shadow_color.mV[VALPHA] = U8(color.mV[VALPHA] * drop_shadow_strength * DROP_SHADOW_SOFT_STRENGTH); + for (S32 pass = 0; pass < 5; pass++) { - LLColor4 shadow_color = LLFontGL::sShadowColor; - shadow_color.mV[VALPHA] = color.mV[VALPHA] * drop_shadow_strength * DROP_SHADOW_SOFT_STRENGTH; - gGL.color4fv(shadow_color.mV); - for (S32 pass = 0; pass < 5; pass++) - { - LLRectf screen_rect_offset = screen_rect; + LLRectf screen_rect_offset = screen_rect; - switch(pass) - { - case 0: - screen_rect_offset.translate(-1.f, -1.f); - break; - case 1: - screen_rect_offset.translate(1.f, -1.f); - break; - case 2: - screen_rect_offset.translate(1.f, 1.f); - break; - case 3: - screen_rect_offset.translate(-1.f, 1.f); - break; - case 4: - screen_rect_offset.translate(0, -2.f); - break; - } - - renderQuad(screen_rect_offset, uv_rect, slant_offset); + switch(pass) + { + case 0: + screen_rect_offset.translate(-1.f, -1.f); + break; + case 1: + screen_rect_offset.translate(1.f, -1.f); + break; + case 2: + screen_rect_offset.translate(1.f, 1.f); + break; + case 3: + screen_rect_offset.translate(-1.f, 1.f); + break; + case 4: + screen_rect_offset.translate(0, -2.f); + break; } - gGL.color4fv(color.mV); - renderQuad(screen_rect, uv_rect, slant_offset); - } - else if (shadow == DROP_SHADOW) - { - LLColor4 shadow_color = LLFontGL::sShadowColor; - shadow_color.mV[VALPHA] = color.mV[VALPHA] * drop_shadow_strength; - gGL.color4fv(shadow_color.mV); - LLRectf screen_rect_shadow = screen_rect; - screen_rect_shadow.translate(1.f, -1.f); - renderQuad(screen_rect_shadow, uv_rect, slant_offset); - gGL.color4fv(color.mV); - renderQuad(screen_rect, uv_rect, slant_offset); - } - else // normal rendering - { - gGL.color4fv(color.mV); - renderQuad(screen_rect, uv_rect, slant_offset); + + const U32 idx = glyph_count * GLYPH_VERTICES; + renderQuad(&vertex_out[idx], &uv_out[idx], &colors_out[idx], screen_rect_offset, uv_rect, shadow_color, slant_offset); + glyph_count++; } - + const U32 idx = glyph_count * GLYPH_VERTICES; + renderQuad(&vertex_out[idx], &uv_out[idx], &colors_out[idx], screen_rect, uv_rect, color, slant_offset); + glyph_count++; + } + else if (shadow == DROP_SHADOW) + { + LLColor4U& shadow_color = LLFontGL::sShadowColor; + shadow_color.mV[VALPHA] = U8(color.mV[VALPHA] * drop_shadow_strength); + LLRectf screen_rect_shadow = screen_rect; + screen_rect_shadow.translate(1.f, -1.f); + U32 idx = glyph_count * GLYPH_VERTICES; + renderQuad(&vertex_out[idx], &uv_out[idx], &colors_out[idx], screen_rect_shadow, uv_rect, shadow_color, slant_offset); + glyph_count++; + idx = glyph_count * GLYPH_VERTICES; + renderQuad(&vertex_out[idx], &uv_out[idx], &colors_out[idx], screen_rect, uv_rect, color, slant_offset); + glyph_count++; + } + else // normal rendering + { + const U32 idx = glyph_count * GLYPH_VERTICES; + renderQuad(&vertex_out[idx], &uv_out[idx], &colors_out[idx], screen_rect, uv_rect, color, slant_offset); + glyph_count++; } - gGL.end(); } diff --git a/indra/llrender/llfontgl.h b/indra/llrender/llfontgl.h index 9476382eb5..4c1d409be6 100644 --- a/indra/llrender/llfontgl.h +++ b/indra/llrender/llfontgl.h @@ -28,23 +28,24 @@ #ifndef LL_LLFONTGL_H #define LL_LLFONTGL_H -#include "llfontfreetype.h" -#include "lltexture.h" -#include "v2math.h" #include "llcoord.h" +#include "llfontregistry.h" +#include "llimagegl.h" +#include "llpointer.h" #include "llrect.h" +#include "v2math.h" -#include "llfontregistry.h" +class LLImageGL; class LLColor4; - // Key used to request a font. class LLFontDescriptor; +class LLFontFreetype; // Structure used to store previously requested fonts. class LLFontRegistry; -class LLFontGL : public LLFontFreetype +class LLFontGL { public: enum HAlign @@ -88,7 +89,7 @@ class LLFontGL : public LLFontFreetype void destroyGL(); - /* virtual*/ BOOL loadFace(const std::string& filename, const F32 point_size, const F32 vert_dpi, const F32 horz_dpi, const S32 components, BOOL is_fallback); + BOOL loadFace(const std::string& filename, const F32 point_size, const F32 vert_dpi, const F32 horz_dpi, const S32 components, BOOL is_fallback); S32 render(const LLWString &text, S32 begin_offset, const LLRect& rect, @@ -110,27 +111,19 @@ class LLFontGL : public LLFontFreetype BOOL use_embedded = FALSE, BOOL use_ellipses = FALSE) const; - S32 render(const LLWString &text, S32 begin_offset, F32 x, F32 y, const LLColor4 &color) const; - // renderUTF8 does a conversion, so is slower! - S32 renderUTF8(const std::string &text, S32 begin_offset, F32 x, F32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, ShadowType shadow, S32 max_chars, S32 max_pixels, F32* right_x, BOOL use_ellipses) const; - S32 renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y, const LLColor4 &color) const; - S32 renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style = NORMAL, ShadowType shadow = NO_SHADOW) const; + S32 renderUTF8(const std::string &text, S32 begin_offset, F32 x, F32 y, const LLColor4 &color, HAlign halign = LEFT, VAlign valign = BASELINE, U8 style = NORMAL, ShadowType shadow = NO_SHADOW, S32 max_chars = S32_MAX, S32 max_pixels = S32_MAX, F32* right_x = NULL, BOOL use_ellipses = FALSE) const; // font metrics - override for LLFont that returns units of virtual pixels - /*virtual*/ F32 getLineHeight() const { return (F32)llround(mLineHeight / sScaleY); } - /*virtual*/ F32 getAscenderHeight() const { return (F32)llround(mAscender / sScaleY); } - /*virtual*/ F32 getDescenderHeight() const { return (F32)llround(mDescender / sScaleY); } + F32 getAscenderHeight() const; + F32 getDescenderHeight() const; + F32 getLineHeight() const; - S32 getWidth(const std::string& utf8text) const; - S32 getWidth(const llwchar* wchars) const; - S32 getWidth(const std::string& utf8text, const S32 offset, const S32 max_chars ) const; - S32 getWidth(const llwchar* wchars, const S32 offset, const S32 max_chars, BOOL use_embedded = FALSE) const; + S32 getWidth(const std::string& utf8str, const S32 offset = 0, const S32 max_chars = S32_MAX, BOOL use_embedded = FALSE) const; + S32 getWidth(const LLWString& utf32str, const S32 offset = 0, const S32 max_chars = S32_MAX, BOOL use_embedded = FALSE) const; - F32 getWidthF32(const std::string& utf8text) const; - F32 getWidthF32(const llwchar* wchars) const; - F32 getWidthF32(const std::string& text, const S32 offset, const S32 max_chars ) const; - F32 getWidthF32(const llwchar* wchars, const S32 offset, const S32 max_chars, BOOL use_embedded = FALSE ) const; + F32 getWidthF32(const std::string& utf8str, const S32 offset = 0, const S32 max_chars = S32_MAX, BOOL use_embedded = FALSE) const; + F32 getWidthF32(const LLWString& utf32str, const S32 offset = 0, const S32 max_chars = S32_MAX, BOOL use_embedded = FALSE) const; // The following are called often, frequently with large buffers, so do not use a string interface @@ -141,18 +134,17 @@ class LLFontGL : public LLFontFreetype WORD_BOUNDARY_IF_POSSIBLE, ANYWHERE } EWordWrapStyle ; - S32 maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_chars = S32_MAX, EWordWrapStyle end_on_word_boundary = ANYWHERE, + S32 maxDrawableChars(const LLWString& utf32str, F32 max_pixels = F32_MAX, S32 max_chars = S32_MAX, EWordWrapStyle end_on_word_boundary = ANYWHERE, const BOOL use_embedded = FALSE, F32* drawn_pixels = NULL) const; // Returns the index of the first complete characters from text that can be drawn in max_pixels // given that the character at start_pos should be the last character (or as close to last as possible). - S32 firstDrawableChar(const llwchar* wchars, F32 max_pixels, S32 text_len, S32 start_pos=S32_MAX, S32 max_chars = S32_MAX) const; + S32 firstDrawableChar(const LLWString& utf32str, F32 max_pixels = F32_MAX, S32 start_pos = S32_MAX, S32 max_chars = S32_MAX) const; // Returns the index of the character closest to pixel position x (ignoring text to the right of max_pixels and max_chars) - S32 charFromPixelOffset(const llwchar* wchars, const S32 char_offset, F32 x, F32 max_pixels=F32_MAX, S32 max_chars = S32_MAX, BOOL round = TRUE, BOOL use_embedded = FALSE) const; + S32 charFromPixelOffset(const LLWString& utf32str, const S32 char_offset, F32 x, F32 max_pixels = F32_MAX, S32 max_chars = S32_MAX, BOOL round = TRUE, BOOL use_embedded = FALSE) const; - const LLFontDescriptor &getFontDesc() const { return mFontDesc; } - void setFontDesc(const LLFontDescriptor& font_desc) { mFontDesc = font_desc; } + const LLFontDescriptor& getFontDesc() const; LLTexture *getTexture() const; @@ -160,7 +152,7 @@ class LLFontGL : public LLFontFreetype void addEmbeddedChar( llwchar wc, LLTexture* image, const LLWString& label) const; void removeEmbeddedChar( llwchar wc ) const; - static void initClass(F32 screen_dpi, F32 x_scale, F32 y_scale, const std::string& app_dir, const std::vector& xui_paths, bool create_gl_textures = true); + static void initClass(F32 screen_dpi, F32 x_scale, F32 y_scale, const std::string& app_dir, bool create_gl_textures = true); // Load sans-serif, sans-serif-small, etc. // Slow, requires multiple seconds to load fonts. @@ -171,7 +163,9 @@ class LLFontGL : public LLFontFreetype // Takes a string with potentially several flags, i.e. "NORMAL|BOLD|ITALIC" static U8 getStyleFromString(const std::string &style); static std::string getStringFromStyle(U8 style); + static std::string nameFromFont(const LLFontGL* fontp); + static std::string sizeFromFont(const LLFontGL* fontp); static std::string nameFromHAlign(LLFontGL::HAlign align); static LLFontGL::HAlign hAlignFromName(const std::string& name); @@ -201,6 +195,9 @@ class LLFontGL : public LLFontFreetype static LLFontGL* getFontSansSerifBold(); static LLFontGL* getFontExtChar(); static LLFontGL* getFont(const LLFontDescriptor& desc); + // Use with legacy names like "SANSSERIF_SMALL" or "OCRA" + static LLFontGL* getFontByName(const std::string& name); + static LLFontGL* getFontDefault(); // default fallback font static std::string getFontPathLocal(); static std::string getFontPathSystem(); @@ -209,34 +206,36 @@ class LLFontGL : public LLFontFreetype static F32 sCurDepth; static std::vector > sOriginStack; - static LLColor4 sShadowColor; + // Singu Note: LLColor4U to avoid converting from LLColor4 to LLColor4U for every glyph(batch). + static LLColor4U sShadowColor; static F32 sVertDPI; static F32 sHorizDPI; static F32 sScaleX; static F32 sScaleY; static BOOL sDisplayFont ; - static std::string sAppDir; // For loading fonts + static std::string sFontDir; // For loading fonts + +private: + friend class LLFontRegistry; friend class LLTextBillboard; friend class LLHUDText; LLFontGL(const LLFontGL &source); LLFontGL &operator=(const LLFontGL &source); -protected: - /*virtual*/ BOOL addChar(const llwchar wch) const; protected: typedef std::map embedded_map_t; mutable embedded_map_t mEmbeddedChars; - LLFontDescriptor mFontDesc; + LLFontDescriptor mFontDescriptor; + LLPointer mFontFreetype; - void renderQuad(const LLRectf& screen_rect, const LLRectf& uv_rect, F32 slant_amt) const; - void drawGlyph(const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4& color, U8 style, ShadowType shadow, F32 drop_shadow_fade) const; + void renderQuad(LLVector4a* vertex_out, LLVector2* uv_out, LLColor4U* colors_out, const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4U& color, F32 slant_amt) const; + void drawGlyph(S32& glyph_count, LLVector4a* vertex_out, LLVector2* uv_out, LLColor4U* colors_out, const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4U& color, U8 style, ShadowType shadow, F32 drop_shadow_fade) const; // Registry holds all instantiated fonts. static LLFontRegistry* sFontRegistry; - }; #endif diff --git a/indra/llrender/llfontregistry.cpp b/indra/llrender/llfontregistry.cpp index fcfbc4c849..7e11477e8d 100644 --- a/indra/llrender/llfontregistry.cpp +++ b/indra/llrender/llfontregistry.cpp @@ -34,13 +34,15 @@ #include "llcontrol.h" #include "lldir.h" #include "llwindow.h" +#include "llxmlnode.h" extern LLControlGroup gSavedSettings; using std::string; using std::map; -bool fontDescInitFromXML(LLXMLNodePtr node, LLFontDescriptor& desc); +bool font_desc_init_from_xml(LLXMLNodePtr node, LLFontDescriptor& desc); +bool init_from_xml(LLFontRegistry* registry, LLXMLNodePtr node); LLFontDescriptor::LLFontDescriptor(): mStyle(0) @@ -163,14 +165,9 @@ LLFontDescriptor LLFontDescriptor::normalize() const return LLFontDescriptor(new_name,new_size,new_style,getFileNames()); } -LLFontRegistry::LLFontRegistry(const string_vec_t& xui_paths, - bool create_gl_textures) +LLFontRegistry::LLFontRegistry(bool create_gl_textures) : mCreateGLTextures(create_gl_textures) { - // Propagate this down from LLUICtrlFactory so LLRender doesn't - // need an upstream dependency on LLUI. - mXUIPaths = xui_paths; - // This is potentially a slow directory traversal, so we want to // cache the result. mUltimateFallbackList = LLWindow::getDynamicFallbackFontList(); @@ -183,23 +180,27 @@ LLFontRegistry::~LLFontRegistry() bool LLFontRegistry::parseFontInfo(const std::string& xml_filename) { - bool success = false; // Succeed if we find at least one XUI file - const string_vec_t& xml_paths = mXUIPaths; + bool success = false; // Succeed if we find and read at least one XUI file + const string_vec_t xml_paths = gDirUtilp->findSkinnedFilenames(LLDir::XUI, xml_filename); + if (xml_paths.empty()) + { + // We didn't even find one single XUI file + return false; + } + for (string_vec_t::const_iterator path_it = xml_paths.begin(); path_it != xml_paths.end(); ++path_it) { LLXMLNodePtr root; - std::string full_filename = gDirUtilp->findSkinnedFilename(*path_it, xml_filename); - bool parsed_file = LLXMLNode::parseFile(full_filename, root, NULL); + bool parsed_file = LLXMLNode::parseFile(*path_it, root, NULL); if (!parsed_file) continue; if ( root.isNull() || ! root->hasName( "fonts" ) ) { - llwarns << "Bad font info file: " - << full_filename << llendl; + LL_WARNS() << "Bad font info file: " << *path_it << LL_ENDL; continue; } @@ -208,12 +209,12 @@ bool LLFontRegistry::parseFontInfo(const std::string& xml_filename) if (root->hasName("fonts")) { // Expect a collection of children consisting of "font" or "font_size" entries - bool init_succ = initFromXML(root); + bool init_succ = init_from_xml(this, root); success = success || init_succ; } } - if (success) - dump(); + //if (success) + // dump(); return success; } @@ -224,14 +225,14 @@ std::string currentOsName() return "Windows"; #elif LL_DARWIN return "Mac"; -#elif LL_SDL +#elif LL_SDL || LL_MESA_HEADLESS return "Linux"; #else return ""; #endif } -bool fontDescInitFromXML(LLXMLNodePtr node, LLFontDescriptor& desc) +bool font_desc_init_from_xml(LLXMLNodePtr node, LLFontDescriptor& desc) { if (node->hasName("font")) { @@ -264,14 +265,14 @@ bool fontDescInitFromXML(LLXMLNodePtr node, LLFontDescriptor& desc) { if (child_name == currentOsName()) { - fontDescInitFromXML(child, desc); + font_desc_init_from_xml(child, desc); } } } return true; } -bool LLFontRegistry::initFromXML(LLXMLNodePtr node) +bool init_from_xml(LLFontRegistry* registry, LLXMLNodePtr node) { LLXMLNodePtr child; @@ -282,17 +283,17 @@ bool LLFontRegistry::initFromXML(LLXMLNodePtr node) if (child->hasName("font")) { LLFontDescriptor desc; - bool font_succ = fontDescInitFromXML(child, desc); + bool font_succ = font_desc_init_from_xml(child, desc); LLFontDescriptor norm_desc = desc.normalize(); if (font_succ) { // if this is the first time we've seen this font name, // create a new template map entry for it. - const LLFontDescriptor *match_desc = getMatchingFontDesc(desc); + const LLFontDescriptor *match_desc = registry->getMatchingFontDesc(desc); if (match_desc == NULL) { // Create a new entry (with no corresponding font). - mFontMap[norm_desc] = NULL; + registry->mFontMap[norm_desc] = NULL; } // otherwise, find the existing entry and combine data. else @@ -307,8 +308,8 @@ bool LLFontRegistry::initFromXML(LLXMLNodePtr node) desc.getFileNames().end()); LLFontDescriptor new_desc = *match_desc; new_desc.getFileNames() = match_file_names; - mFontMap.erase(*match_desc); - mFontMap[new_desc] = NULL; + registry->mFontMap.erase(*match_desc); + registry->mFontMap[new_desc] = NULL; } } } @@ -319,7 +320,7 @@ bool LLFontRegistry::initFromXML(LLXMLNodePtr node) if (child->getAttributeString("name",size_name) && child->getAttributeF32("size",size_value)) { - mFontSizes[size_name] = size_value; + registry->mFontSizes[size_name] = size_value; } } @@ -352,10 +353,10 @@ LLFontGL *LLFontRegistry::createFont(const LLFontDescriptor& desc) bool found_size = nameToSize(norm_desc.getSize(),point_size); if (!found_size) { - llwarns << "createFont unrecognized size " << norm_desc.getSize() << llendl; + LL_WARNS() << "createFont unrecognized size " << norm_desc.getSize() << LL_ENDL; return NULL; } - llinfos << "createFont " << norm_desc.getName() << " size " << norm_desc.getSize() << " style " << ((S32) norm_desc.getStyle()) << llendl; + LL_INFOS() << "createFont " << norm_desc.getName() << " size " << norm_desc.getSize() << " style " << ((S32) norm_desc.getStyle()) << LL_ENDL; F32 fallback_scale = 1.0; // Find corresponding font template (based on same descriptor with no size specified) @@ -364,8 +365,8 @@ LLFontGL *LLFontRegistry::createFont(const LLFontDescriptor& desc) const LLFontDescriptor *match_desc = getClosestFontTemplate(template_desc); if (!match_desc) { - llwarns << "createFont failed, no template found for " - << norm_desc.getName() << " style [" << ((S32)norm_desc.getStyle()) << "]" << llendl; + LL_WARNS() << "createFont failed, no template found for " + << norm_desc.getName() << " style [" << ((S32)norm_desc.getStyle()) << "]" << LL_ENDL; return NULL; } @@ -379,11 +380,11 @@ LLFontGL *LLFontRegistry::createFont(const LLFontDescriptor& desc) if (it != mFontMap.end() && it->second != NULL) { if (it->second != NULL) { - llinfos << "-- matching font exists: " << nearest_exact_desc.getName() << " size " << nearest_exact_desc.getSize() << " style " << ((S32) nearest_exact_desc.getStyle()) << llendl; + LL_INFOS() << "-- matching font exists: " << nearest_exact_desc.getName() << " size " << nearest_exact_desc.getSize() << " style " << ((S32) nearest_exact_desc.getStyle()) << LL_ENDL; return it->second; } else { - llwarns << "Failed to find font" << llendl; + LL_WARNS() << "Failed to find font" << LL_ENDL; } //Haven't plugged free-type in yet. // copying underlying Freetype font, and storing in LLFontGL with requested font descriptor @@ -406,7 +407,7 @@ LLFontGL *LLFontRegistry::createFont(const LLFontDescriptor& desc) file_names.insert(file_names.end(), match_default_desc->getFileNames().begin(), match_default_desc->getFileNames().end()); - llinfos << "Found matching fallback fonts: " << match_default_desc->getFileNames().size() << llendl; + LL_INFOS() << "Found matching fallback fonts: " << match_default_desc->getFileNames().size() << LL_ENDL; } // Add ultimate fallback list - generated dynamically on linux, @@ -418,13 +419,14 @@ LLFontGL *LLFontRegistry::createFont(const LLFontDescriptor& desc) // Load fonts based on names. if (file_names.empty()) { - llwarns << "createFont failed, no file names specified" << llendl; + LL_WARNS() << "createFont failed, no file names specified" << LL_ENDL; return NULL; } - LLFontList *fontlistp = new LLFontList; + + LLFontFreetype::font_vector_t fontlist; LLFontGL *result = NULL; - // Snarf all fonts we can into fontlistp. First will get pulled + // Snarf all fonts we can into fontlist. First will get pulled // off the list and become the "head" font, set to non-fallback. // Rest will consitute the fallback list. BOOL is_first_found = TRUE; @@ -439,7 +441,7 @@ LLFontGL *LLFontRegistry::createFont(const LLFontDescriptor& desc) ++file_name_it) { LLFontGL *fontp = new LLFontGL; - std::string font_path = local_path + *file_name_it; + std::string font_path = gDirUtilp->add(local_path, *file_name_it); // *HACK: Fallback fonts don't render, so we can use that to suppress // creation of OpenGL textures for test apps. JC BOOL is_fallback = !is_first_found || !mCreateGLTextures; @@ -447,12 +449,12 @@ LLFontGL *LLFontRegistry::createFont(const LLFontDescriptor& desc) if (!fontp->loadFace(font_path, extra_scale * point_size, LLFontGL::sVertDPI, LLFontGL::sHorizDPI, 2, is_fallback)) { - font_path = sys_path + *file_name_it; + font_path = gDirUtilp->add(sys_path, *file_name_it); if (!fontp->loadFace(font_path, extra_scale * point_size, LLFontGL::sVertDPI, LLFontGL::sHorizDPI, 2, is_fallback)) { - LL_INFOS_ONCE("LLFontRegistry") << "Couldn't load font " << *file_name_it << LL_ENDL; + LL_INFOS_ONCE("LLFontRegistry") << "Couldn't load font " << *file_name_it << " from path " << font_path << LL_ENDL; delete fontp; fontp = NULL; } @@ -466,22 +468,30 @@ LLFontGL *LLFontRegistry::createFont(const LLFontDescriptor& desc) is_first_found = false; } else - fontlistp->addAtEnd(fontp); + { + fontlist.push_back(fontp->mFontFreetype); + delete fontp; + fontp = NULL; + } } } - if (result && !fontlistp->empty()) + + if (result && !fontlist.empty()) { - result->setFallbackFont(fontlistp); + result->mFontFreetype->setFallbackFonts(fontlist); } norm_desc.setStyle(match_desc->getStyle()); - if (result) - result->setFontDesc(norm_desc); - if (!result) + if (result) { - llwarns << "createFont failed in some way" << llendl; + result->mFontDescriptor = desc; } + else + { + LL_WARNS() << "createFont failed in some way" << LL_ENDL; + } + mFontMap[norm_desc] = result; return result; } @@ -524,19 +534,19 @@ void LLFontRegistry::destroyGL() LLFontGL *LLFontRegistry::getFont(const LLFontDescriptor& orig_desc) { - LLFontDescriptor norm_desc = orig_desc.normalize(); + LLFontDescriptor desc = orig_desc.normalize(); - font_reg_map_t::iterator it = mFontMap.find(norm_desc); + font_reg_map_t::iterator it = mFontMap.find(desc); if (it != mFontMap.end()) return it->second; else { - LLFontGL *fontp = createFont(orig_desc); + LLFontGL *fontp = createFont(desc); if (!fontp) { - llwarns << "getFont failed, name " << orig_desc.getName() - <<" style=[" << ((S32) orig_desc.getStyle()) << "]" - << " size=[" << orig_desc.getSize() << "]" << llendl; + LL_WARNS() << "getFont failed, name " << desc.getName() + <<" style=[" << ((S32) desc.getStyle()) << "]" + << " size=[" << desc.getSize() << "]" << LL_ENDL; } return fontp; } @@ -639,28 +649,28 @@ const LLFontDescriptor *LLFontRegistry::getClosestFontTemplate(const LLFontDescr void LLFontRegistry::dump() { - llinfos << "LLFontRegistry dump: " << llendl; + LL_INFOS() << "LLFontRegistry dump: " << LL_ENDL; for (font_size_map_t::iterator size_it = mFontSizes.begin(); size_it != mFontSizes.end(); ++size_it) { - llinfos << "Size: " << size_it->first << " => " << size_it->second << llendl; + LL_INFOS() << "Size: " << size_it->first << " => " << size_it->second << LL_ENDL; } for (font_reg_map_t::iterator font_it = mFontMap.begin(); font_it != mFontMap.end(); ++font_it) { const LLFontDescriptor& desc = font_it->first; - llinfos << "Font: name=" << desc.getName() + LL_INFOS() << "Font: name=" << desc.getName() << " style=[" << ((S32)desc.getStyle()) << "]" << " size=[" << desc.getSize() << "]" << " fileNames=" - << llendl; + << LL_ENDL; for (string_vec_t::const_iterator file_it=desc.getFileNames().begin(); file_it != desc.getFileNames().end(); ++file_it) { - llinfos << " file: " << *file_it <); // create_gl_textures - set to false for test apps with no OpenGL window, // such as llui_libtest - LLFontRegistry(const string_vec_t& xui_paths, - bool create_gl_textures); + LLFontRegistry(bool create_gl_textures); ~LLFontRegistry(); // Load standard font info from XML file(s). bool parseFontInfo(const std::string& xml_filename); - bool initFromXML(LLXMLNodePtr node); // Clear cached glyphs for all fonts. void reset(); @@ -95,6 +94,7 @@ class LLFontRegistry const string_vec_t& getUltimateFallbackList() const; private: + LLFontRegistry(const LLFontRegistry& other); // no-copy LLFontGL *createFont(const LLFontDescriptor& desc); typedef std::map font_reg_map_t; typedef std::map font_size_map_t; @@ -105,7 +105,6 @@ class LLFontRegistry font_size_map_t mFontSizes; string_vec_t mUltimateFallbackList; - string_vec_t mXUIPaths; bool mCreateGLTextures; }; diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp index dcde319d23..c6b99ba673 100644 --- a/indra/llrender/llgl.cpp +++ b/indra/llrender/llgl.cpp @@ -67,11 +67,17 @@ void* gl_get_proc_address(const char *pStr) { void* pPtr = (void*)GLH_EXT_GET_PROC_ADDRESS(pStr); if(!pPtr) - llinfos << "Failed to find symbol '" << pStr << "'" << llendl; + LL_INFOS() << "Failed to find symbol '" << pStr << "'" << LL_ENDL; return pPtr; } #undef GLH_EXT_GET_PROC_ADDRESS #define GLH_EXT_GET_PROC_ADDRESS(p) gl_get_proc_address(p) +#undef GLH_EXT_GET_PROC_ADDRESS_CORE +#define GLH_EXT_GET_PROC_ADDRESS_CORE(ver, p) gl_get_proc_address((mGLVersion >= ver) ? p : p"ARB") +#undef GLH_EXT_GET_PROC_ADDRESS_CORE_EXT +#define GLH_EXT_GET_PROC_ADDRESS_CORE_EXT(ver, p) gl_get_proc_address((mGLVersion >= ver) ? p : p"EXT") +#undef GLH_EXT_GET_PROC_ADDRESS_CORE_OR_ARB +#define GLH_EXT_GET_PROC_ADDRESS_CORE_OR_ARB(ver, p, arb) gl_get_proc_address((mGLVersion >= ver) ? p : arb) #endif //!LL_DARWIN #if GL_ARB_debug_output @@ -90,20 +96,95 @@ void APIENTRY gl_debug_callback(GLenum source, { if (severity == GL_DEBUG_SEVERITY_HIGH_ARB) { - llwarns << "----- GL ERROR --------" << llendl; + LL_WARNS() << "----- GL ERROR --------" << LL_ENDL; } else { - llwarns << "----- GL WARNING -------" << llendl; + if (severity == GL_DEBUG_SEVERITY_MEDIUM_ARB) + { + LL_WARNS() << "----- GL WARNING MEDIUM --------" << LL_ENDL; + } + else if (severity == GL_DEBUG_SEVERITY_LOW_ARB) + { + if (type == GL_DEBUG_TYPE_OTHER_ARB) + { + if (id == 0x20004 || // Silence nvidia glClear noop messages + id == 0x20043 || // Silence nvidia CSAA messages. + id == 0x20084 // Silence nvidia texture mapping with no base level messages. + ) + { + return; + } + } + + LL_WARNS() << "----- GL WARNING LOW --------" << LL_ENDL; + } + else if (severity == 0x826b && id == 0x20071 && type == GL_DEBUG_TYPE_OTHER_ARB && source == GL_DEBUG_SOURCE_API_ARB) + { + // Silence nvidia buffer detail info. + return; + } } - llwarns << "Type: " << std::hex << type << std::dec << llendl; - llwarns << "ID: " << std::hex << id << std::dec<< llendl; - llwarns << "Severity: " << std::hex << severity << std::dec << llendl; - llwarns << "Message: " << message << llendl; - llwarns << "-----------------------" << llendl; + + std::string sourcestr = "Unknown"; + switch (source) + { + case GL_DEBUG_SOURCE_API_ARB: + sourcestr = "OpenGL"; + break; + case GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB: + sourcestr = "Window manager"; + break; + case GL_DEBUG_SOURCE_SHADER_COMPILER_ARB: + sourcestr = "Shader compiler"; + break; + case GL_DEBUG_SOURCE_THIRD_PARTY_ARB: + sourcestr = "3rd party"; + break; + case GL_DEBUG_SOURCE_APPLICATION_ARB: + sourcestr = "Application"; + break; + case GL_DEBUG_SOURCE_OTHER_ARB: + sourcestr = "Other"; + break; + default: + break; + } + + std::string typestr = "Unknown"; + switch (type) + { + case GL_DEBUG_TYPE_ERROR_ARB: + typestr = "Error"; + break; + case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB: + typestr = "Deprecated behavior"; + break; + case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB: + typestr = "Undefined behavior"; + break; + case GL_DEBUG_TYPE_PORTABILITY_ARB: + typestr = "Portability"; + break; + case GL_DEBUG_TYPE_PERFORMANCE_ARB: + typestr = "Performance"; + break; + case GL_DEBUG_TYPE_OTHER_ARB: + typestr = "Other"; + break; + default: + break; + } + + LL_WARNS() << "Source: " << sourcestr << " (" << std::hex << source << std::dec << ")" << LL_ENDL; + LL_WARNS() << "Type: " << typestr << " (" << std::hex << type << std::dec << ")" << LL_ENDL; + LL_WARNS() << "ID: " << std::hex << id << std::dec<< LL_ENDL; + LL_WARNS() << "Severity: " << std::hex << severity << std::dec << LL_ENDL; + LL_WARNS() << "Message: " << message << LL_ENDL; + LL_WARNS() << "-----------------------" << LL_ENDL; if (severity == GL_DEBUG_SEVERITY_HIGH_ARB) { - llerrs << "Halting on GL Error" << llendl; + LL_ERRS() << "Halting on GL Error" << LL_ENDL; } } #endif @@ -151,13 +232,59 @@ LLMatrix4 gGLObliqueProjectionInverse; std::list LLGLUpdate::sGLQ; -#if (LL_WINDOWS || LL_LINUX || LL_SOLARIS) && !LL_MESA_HEADLESS -// ATI prototypes +#if (LL_WINDOWS || LL_LINUX) && !LL_MESA_HEADLESS #if LL_WINDOWS -PFNGLGETSTRINGIPROC glGetStringi = NULL; +PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = NULL; +PFNWGLGETPIXELFORMATATTRIBIVARBPROC wglGetPixelFormatAttribivARB = NULL; +PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = NULL; +PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL; +PFNGLDRAWRANGEELEMENTSPROC glDrawRangeElements = NULL; + +// GL_ARB_multitexture +PFNGLMULTITEXCOORD1DARBPROC glMultiTexCoord1dARB = NULL; +PFNGLMULTITEXCOORD1DVARBPROC glMultiTexCoord1dvARB = NULL; +PFNGLMULTITEXCOORD1FARBPROC glMultiTexCoord1fARB = NULL; +PFNGLMULTITEXCOORD1FVARBPROC glMultiTexCoord1fvARB = NULL; +PFNGLMULTITEXCOORD1IARBPROC glMultiTexCoord1iARB = NULL; +PFNGLMULTITEXCOORD1IVARBPROC glMultiTexCoord1ivARB = NULL; +PFNGLMULTITEXCOORD1SARBPROC glMultiTexCoord1sARB = NULL; +PFNGLMULTITEXCOORD1SVARBPROC glMultiTexCoord1svARB = NULL; +PFNGLMULTITEXCOORD2DARBPROC glMultiTexCoord2dARB = NULL; +PFNGLMULTITEXCOORD2DVARBPROC glMultiTexCoord2dvARB = NULL; +PFNGLMULTITEXCOORD2FARBPROC glMultiTexCoord2fARB = NULL; +PFNGLMULTITEXCOORD2FVARBPROC glMultiTexCoord2fvARB = NULL; +PFNGLMULTITEXCOORD2IARBPROC glMultiTexCoord2iARB = NULL; +PFNGLMULTITEXCOORD2IVARBPROC glMultiTexCoord2ivARB = NULL; +PFNGLMULTITEXCOORD2SARBPROC glMultiTexCoord2sARB = NULL; +PFNGLMULTITEXCOORD2SVARBPROC glMultiTexCoord2svARB = NULL; +PFNGLMULTITEXCOORD3DARBPROC glMultiTexCoord3dARB = NULL; +PFNGLMULTITEXCOORD3DVARBPROC glMultiTexCoord3dvARB = NULL; +PFNGLMULTITEXCOORD3FARBPROC glMultiTexCoord3fARB = NULL; +PFNGLMULTITEXCOORD3FVARBPROC glMultiTexCoord3fvARB = NULL; +PFNGLMULTITEXCOORD3IARBPROC glMultiTexCoord3iARB = NULL; +PFNGLMULTITEXCOORD3IVARBPROC glMultiTexCoord3ivARB = NULL; +PFNGLMULTITEXCOORD3SARBPROC glMultiTexCoord3sARB = NULL; +PFNGLMULTITEXCOORD3SVARBPROC glMultiTexCoord3svARB = NULL; +PFNGLMULTITEXCOORD4DARBPROC glMultiTexCoord4dARB = NULL; +PFNGLMULTITEXCOORD4DVARBPROC glMultiTexCoord4dvARB = NULL; +PFNGLMULTITEXCOORD4FARBPROC glMultiTexCoord4fARB = NULL; +PFNGLMULTITEXCOORD4FVARBPROC glMultiTexCoord4fvARB = NULL; +PFNGLMULTITEXCOORD4IARBPROC glMultiTexCoord4iARB = NULL; +PFNGLMULTITEXCOORD4IVARBPROC glMultiTexCoord4ivARB = NULL; +PFNGLMULTITEXCOORD4SARBPROC glMultiTexCoord4sARB = NULL; +PFNGLMULTITEXCOORD4SVARBPROC glMultiTexCoord4svARB = NULL; +PFNGLACTIVETEXTUREARBPROC glActiveTextureARB = NULL; +PFNGLCLIENTACTIVETEXTUREARBPROC glClientActiveTextureARB = NULL; #endif +#if LL_LINUX_NV_GL_HEADERS +// linux nvidia headers. these define these differently to mesa's. ugh. +PFNGLACTIVETEXTUREARBPROC glActiveTextureARB = NULL; +PFNGLCLIENTACTIVETEXTUREARBPROC glClientActiveTextureARB = NULL; +PFNGLDRAWRANGEELEMENTSPROC glDrawRangeElements = NULL; +#endif // LL_LINUX_NV_GL_HEADERS + // vertex blending prototypes PFNGLWEIGHTPOINTERARBPROC glWeightPointerARB = NULL; PFNGLVERTEXBLENDARBPROC glVertexBlendARB = NULL; @@ -186,6 +313,15 @@ PFNGLISVERTEXARRAYPROC glIsVertexArray = NULL; PFNGLMAPBUFFERRANGEPROC glMapBufferRange = NULL; PFNGLFLUSHMAPPEDBUFFERRANGEPROC glFlushMappedBufferRange = NULL; +// GL_ARB_texture_compression +PFNGLCOMPRESSEDTEXIMAGE3DARBPROC glCompressedTexImage3DARB = NULL; +PFNGLCOMPRESSEDTEXIMAGE2DARBPROC glCompressedTexImage2DARB = NULL; +PFNGLCOMPRESSEDTEXIMAGE1DARBPROC glCompressedTexImage1DARB = NULL; +PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC glCompressedTexSubImage3DARB = NULL; +PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC glCompressedTexSubImage2DARB = NULL; +PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC glCompressedTexSubImage1DARB = NULL; +PFNGLGETCOMPRESSEDTEXIMAGEARBPROC glGetCompressedTexImageARB = NULL; + // GL_ARB_sync PFNGLFENCESYNCPROC glFenceSync = NULL; PFNGLISSYNCPROC glIsSync = NULL; @@ -199,21 +335,6 @@ PFNGLGETSYNCIVPROC glGetSynciv = NULL; PFNGLBUFFERPARAMETERIAPPLEPROC glBufferParameteriAPPLE = NULL; PFNGLFLUSHMAPPEDBUFFERRANGEAPPLEPROC glFlushMappedBufferRangeAPPLE = NULL; -// vertex object prototypes -PFNGLNEWOBJECTBUFFERATIPROC glNewObjectBufferATI = NULL; -PFNGLISOBJECTBUFFERATIPROC glIsObjectBufferATI = NULL; -PFNGLUPDATEOBJECTBUFFERATIPROC glUpdateObjectBufferATI = NULL; -PFNGLGETOBJECTBUFFERFVATIPROC glGetObjectBufferfvATI = NULL; -PFNGLGETOBJECTBUFFERIVATIPROC glGetObjectBufferivATI = NULL; -PFNGLFREEOBJECTBUFFERATIPROC glFreeObjectBufferATI = NULL; -PFNGLARRAYOBJECTATIPROC glArrayObjectATI = NULL; -PFNGLVERTEXATTRIBARRAYOBJECTATIPROC glVertexAttribArrayObjectATI = NULL; -PFNGLGETARRAYOBJECTFVATIPROC glGetArrayObjectfvATI = NULL; -PFNGLGETARRAYOBJECTIVATIPROC glGetArrayObjectivATI = NULL; -PFNGLVARIANTARRAYOBJECTATIPROC glVariantObjectArrayATI = NULL; -PFNGLGETVARIANTARRAYOBJECTFVATIPROC glGetVariantArrayObjectfvATI = NULL; -PFNGLGETVARIANTARRAYOBJECTIVATIPROC glGetVariantArrayObjectivATI = NULL; - // GL_ARB_occlusion_query PFNGLGENQUERIESARBPROC glGenQueriesARB = NULL; PFNGLDELETEQUERIESARBPROC glDeleteQueriesARB = NULL; @@ -223,6 +344,7 @@ PFNGLENDQUERYARBPROC glEndQueryARB = NULL; PFNGLGETQUERYIVARBPROC glGetQueryivARB = NULL; PFNGLGETQUERYOBJECTIVARBPROC glGetQueryObjectivARB = NULL; PFNGLGETQUERYOBJECTUIVARBPROC glGetQueryObjectuivARB = NULL; +PFNGLGETQUERYOBJECTUI64VEXTPROC glGetQueryObjectui64vEXT = NULL; // GL_ARB_point_parameters PFNGLPOINTPARAMETERFARBPROC glPointParameterfARB = NULL; @@ -275,8 +397,8 @@ PFNGLBLENDFUNCSEPARATEEXTPROC glBlendFuncSeparateEXT = NULL; PFNGLDRAWBUFFERSARBPROC glDrawBuffersARB = NULL; //shader object prototypes -PFNGLDELETEOBJECTARBPROC glDeleteObjectARB = NULL; -PFNGLGETHANDLEARBPROC glGetHandleARB = NULL; +PFNGLDELETEOBJECTARBPROC glDeleteShader = NULL; +PFNGLDELETEOBJECTARBPROC glDeleteProgram = NULL; PFNGLDETACHOBJECTARBPROC glDetachObjectARB = NULL; PFNGLCREATESHADEROBJECTARBPROC glCreateShaderObjectARB = NULL; PFNGLSHADERSOURCEARBPROC glShaderSourceARB = NULL; @@ -304,10 +426,12 @@ PFNGLUNIFORM3IVARBPROC glUniform3ivARB = NULL; PFNGLUNIFORM4IVARBPROC glUniform4ivARB = NULL; PFNGLUNIFORMMATRIX2FVARBPROC glUniformMatrix2fvARB = NULL; PFNGLUNIFORMMATRIX3FVARBPROC glUniformMatrix3fvARB = NULL; +PFNGLUNIFORMMATRIX3X4FVPROC glUniformMatrix3x4fv = NULL; PFNGLUNIFORMMATRIX4FVARBPROC glUniformMatrix4fvARB = NULL; -PFNGLGETOBJECTPARAMETERFVARBPROC glGetObjectParameterfvARB = NULL; -PFNGLGETOBJECTPARAMETERIVARBPROC glGetObjectParameterivARB = NULL; -PFNGLGETINFOLOGARBPROC glGetInfoLogARB = NULL; +PFNGLGETOBJECTPARAMETERIVARBPROC glGetShaderiv = NULL; +PFNGLGETOBJECTPARAMETERIVARBPROC glGetProgramiv = NULL; +PFNGLGETINFOLOGARBPROC glGetShaderInfoLog = NULL; +PFNGLGETINFOLOGARBPROC glGetProgramInfoLog = NULL; PFNGLGETATTACHEDOBJECTSARBPROC glGetAttachedObjectsARB = NULL; PFNGLGETUNIFORMLOCATIONARBPROC glGetUniformLocationARB = NULL; PFNGLGETACTIVEUNIFORMARBPROC glGetActiveUniformARB = NULL; @@ -316,12 +440,7 @@ PFNGLGETUNIFORMIVARBPROC glGetUniformivARB = NULL; PFNGLGETSHADERSOURCEARBPROC glGetShaderSourceARB = NULL; PFNGLVERTEXATTRIBIPOINTERPROC glVertexAttribIPointer = NULL; -#if LL_WINDOWS -PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = NULL; -#endif - // vertex shader prototypes -#if LL_LINUX || LL_SOLARIS PFNGLVERTEXATTRIB1DARBPROC glVertexAttrib1dARB = NULL; PFNGLVERTEXATTRIB1DVARBPROC glVertexAttrib1dvARB = NULL; PFNGLVERTEXATTRIB1FARBPROC glVertexAttrib1fARB = NULL; @@ -340,15 +459,13 @@ PFNGLVERTEXATTRIB3FARBPROC glVertexAttrib3fARB = NULL; PFNGLVERTEXATTRIB3FVARBPROC glVertexAttrib3fvARB = NULL; PFNGLVERTEXATTRIB3SARBPROC glVertexAttrib3sARB = NULL; PFNGLVERTEXATTRIB3SVARBPROC glVertexAttrib3svARB = NULL; -#endif // LL_LINUX || LL_SOLARIS -PFNGLVERTEXATTRIB4NBVARBPROC glVertexAttrib4nbvARB = NULL; -PFNGLVERTEXATTRIB4NIVARBPROC glVertexAttrib4nivARB = NULL; -PFNGLVERTEXATTRIB4NSVARBPROC glVertexAttrib4nsvARB = NULL; -PFNGLVERTEXATTRIB4NUBARBPROC glVertexAttrib4nubARB = NULL; -PFNGLVERTEXATTRIB4NUBVARBPROC glVertexAttrib4nubvARB = NULL; -PFNGLVERTEXATTRIB4NUIVARBPROC glVertexAttrib4nuivARB = NULL; -PFNGLVERTEXATTRIB4NUSVARBPROC glVertexAttrib4nusvARB = NULL; -#if LL_LINUX || LL_SOLARIS +PFNGLVERTEXATTRIB4NBVARBPROC glVertexAttrib4NbvARB = NULL; +PFNGLVERTEXATTRIB4NIVARBPROC glVertexAttrib4NivARB = NULL; +PFNGLVERTEXATTRIB4NSVARBPROC glVertexAttrib4NsvARB = NULL; +PFNGLVERTEXATTRIB4NUBARBPROC glVertexAttrib4NubARB = NULL; +PFNGLVERTEXATTRIB4NUBVARBPROC glVertexAttrib4NubvARB = NULL; +PFNGLVERTEXATTRIB4NUIVARBPROC glVertexAttrib4NuivARB = NULL; +PFNGLVERTEXATTRIB4NUSVARBPROC glVertexAttrib4NusvARB = NULL; PFNGLVERTEXATTRIB4BVARBPROC glVertexAttrib4bvARB = NULL; PFNGLVERTEXATTRIB4DARBPROC glVertexAttrib4dARB = NULL; PFNGLVERTEXATTRIB4DVARBPROC glVertexAttrib4dvARB = NULL; @@ -386,21 +503,9 @@ PFNGLGETVERTEXATTRIBFVARBPROC glGetVertexAttribfvARB = NULL; PFNGLGETVERTEXATTRIBIVARBPROC glGetVertexAttribivARB = NULL; PFNGLGETVERTEXATTRIBPOINTERVARBPROC glGetVertexAttribPointervARB = NULL; PFNGLISPROGRAMARBPROC glIsProgramARB = NULL; -#endif // LL_LINUX || LL_SOLARIS PFNGLBINDATTRIBLOCATIONARBPROC glBindAttribLocationARB = NULL; PFNGLGETACTIVEATTRIBARBPROC glGetActiveAttribARB = NULL; PFNGLGETATTRIBLOCATIONARBPROC glGetAttribLocationARB = NULL; - -#if LL_WINDOWS -PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL; -#endif - -#if LL_LINUX_NV_GL_HEADERS -// linux nvidia headers. these define these differently to mesa's. ugh. -PFNGLACTIVETEXTUREARBPROC glActiveTextureARB = NULL; -PFNGLCLIENTACTIVETEXTUREARBPROC glClientActiveTextureARB = NULL; -PFNGLDRAWRANGEELEMENTSPROC glDrawRangeElements = NULL; -#endif // LL_LINUX_NV_GL_HEADERS #endif // (LL_WINDOWS || LL_LINUX || LL_SOLARIS) && !LL_MESA_HEADLESS LLGLManager gGLManager; @@ -424,7 +529,6 @@ LLGLManager::LLGLManager() : mHasVertexArrayObject(FALSE), mHasMapBufferRange(FALSE), mHasFlushBufferRange(FALSE), - mHasPBuffer(FALSE), mHasShaderObjects(FALSE), mHasVertexShader(FALSE), mHasFragmentShader(FALSE), @@ -433,7 +537,6 @@ LLGLManager::LLGLManager() : mHasOcclusionQuery2(FALSE), mHasPointParameters(FALSE), mHasDrawBuffers(FALSE), - mHasTextureRectangle(FALSE), mHasTransformFeedback(FALSE), mMaxIntegerSamples(0), @@ -442,19 +545,24 @@ LLGLManager::LLGLManager() : mHasCubeMap(FALSE), mHasDebugOutput(FALSE), + mHasGpuShader5(FALSE), + mHasAdaptiveVsync(FALSE), + mHasTextureSwizzle(FALSE), + mIsATI(FALSE), mIsNVIDIA(FALSE), mIsIntel(FALSE), + mIsHD3K(FALSE), mIsGF2or4MX(FALSE), mIsGF3(FALSE), mIsGFFX(FALSE), mATIOffsetVerticalLines(FALSE), mATIOldDriver(FALSE), - +#if LL_DARWIN + mIsMobileGF(FALSE), +#endif mHasRequirements(TRUE), - mHasSeparateSpecularColor(FALSE), - mDebugGPU(FALSE), mDriverVersionMajor(1), @@ -465,8 +573,83 @@ LLGLManager::LLGLManager() : mGLSLVersionMinor(0), mVRAM(0), mGLMaxVertexRange(0), - mGLMaxIndexRange(0) + mGLMaxIndexRange(0), + mGLMaxVertexUniformComponents(0) +{ +} + +std::set sGLExtensions; // Not techincally safe to issue this before context is created. +#if LL_WINDOWS +std::set sWGLExtensions; // Fine (probably) without context. +#endif +void registerExtension(std::string ext, std::set& extensions) +{ + extensions.emplace(ext); + LL_INFOS("GLExtensions") << ext << LL_ENDL; +} +void loadExtensionStrings() +{ + sGLExtensions.clear(); + U32 gl_version = atoi((const char*)glGetString(GL_VERSION)); + if (gl_version >= 3) + { +#ifndef LL_DARWIN + PFNGLGETSTRINGIPROC glGetStringi = (PFNGLGETSTRINGIPROC)GLH_EXT_GET_PROC_ADDRESS("glGetStringi"); +#endif + GLint count = 0; + glGetIntegerv(GL_NUM_EXTENSIONS, &count); + for (GLint i = 0; i < count; ++i) + { + registerExtension((char const*)glGetStringi(GL_EXTENSIONS, i), sGLExtensions); + } + } + else // Deprecated. + { + typedef boost::tokenizer > tokenizer; + boost::char_separator sep(" "); + std::string extensions((const char*)glGetString(GL_EXTENSIONS)); + for (auto& extension : tokenizer(extensions, sep)) + { + registerExtension(extension, sGLExtensions); + } + } +} +#if LL_WINDOWS +void loadWGLExtensionStrings() +{ + sWGLExtensions.clear(); + PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB"); + if (wglGetExtensionsStringARB) + { + typedef boost::tokenizer > tokenizer; + boost::char_separator sep(" "); + std::string extensions = std::string(wglGetExtensionsStringARB(wglGetCurrentDC())); + for (auto& extension : tokenizer(extensions, sep)) + { + registerExtension(extension, sWGLExtensions); + } + } +} +#endif + +bool ExtensionExists(std::string ext) { + auto* extensions = &sGLExtensions; +#if LL_WINDOWS + if (ext.rfind("WGL_", 0) == 0) + { + extensions = &sWGLExtensions; + if (extensions->empty()) + loadWGLExtensionStrings(); + } + else +#endif + if (extensions->empty()) + loadExtensionStrings(); + bool found = extensions->find(ext) != extensions->end(); + if (!found) + LL_INFOS("GLExtensions") << ext << " MISSING" << LL_ENDL; + return found; } //--------------------------------------------------------------------- @@ -474,40 +657,35 @@ LLGLManager::LLGLManager() : //--------------------------------------------------------------------- void LLGLManager::initWGL() { - mHasPBuffer = FALSE; #if LL_WINDOWS && !LL_MESA_HEADLESS - if (!glh_init_extensions("WGL_ARB_pixel_format")) + loadWGLExtensionStrings(); + if (ExtensionExists("WGL_ARB_pixel_format")) + { + wglGetPixelFormatAttribivARB = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC)wglGetProcAddress("wglGetPixelFormatAttribivARB"); + wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB"); + } + else { LL_WARNS("RenderInit") << "No ARB pixel format extensions" << LL_ENDL; } - - if (ExtensionExists("WGL_ARB_create_context",gGLHExts.mSysExts)) + + if (ExtensionExists("WGL_ARB_create_context")) { - GLH_EXT_NAME(wglCreateContextAttribsARB) = (PFNWGLCREATECONTEXTATTRIBSARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglCreateContextAttribsARB"); + wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB"); } else { LL_WARNS("RenderInit") << "No ARB create context extensions" << LL_ENDL; } - if (ExtensionExists("WGL_EXT_swap_control", gGLHExts.mSysExts)) + if (ExtensionExists("WGL_EXT_swap_control")) { - GLH_EXT_NAME(wglSwapIntervalEXT) = (PFNWGLSWAPINTERVALEXTPROC)GLH_EXT_GET_PROC_ADDRESS("wglSwapIntervalEXT"); + wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT"); } - - if( !glh_init_extensions("WGL_ARB_pbuffer") ) - { - LL_WARNS("RenderInit") << "No ARB WGL PBuffer extensions" << LL_ENDL; - } - - if( !glh_init_extensions("WGL_ARB_render_texture") ) + else { - LL_WARNS("RenderInit") << "No ARB WGL render texture extensions" << LL_ENDL; + LL_WARNS("RenderInit") << "No ARB swap control extensions" << LL_ENDL; } - - mHasPBuffer = ExtensionExists("WGL_ARB_pbuffer", gGLHExts.mSysExts) && - ExtensionExists("WGL_ARB_render_texture", gGLHExts.mSysExts) && - ExtensionExists("WGL_ARB_pixel_format", gGLHExts.mSysExts); #endif } @@ -521,40 +699,7 @@ bool LLGLManager::initGL() stop_glerror(); -#if LL_WINDOWS - if (!glGetStringi) - { - glGetStringi = (PFNGLGETSTRINGIPROC) GLH_EXT_GET_PROC_ADDRESS("glGetStringi"); - } - - //reload extensions string (may have changed after using wglCreateContextAttrib) - if (glGetStringi) - { - std::stringstream str; - - GLint count = 0; - glGetIntegerv(GL_NUM_EXTENSIONS, &count); - for (GLint i = 0; i < count; ++i) - { - std::string ext((const char*) glGetStringi(GL_EXTENSIONS, i)); - str << ext << " "; - LL_DEBUGS("GLExtensions") << ext << llendl; - } - - { - PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = 0; - wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB"); - if(wglGetExtensionsStringARB) - { - str << (const char*) wglGetExtensionsStringARB(wglGetCurrentDC()); - } - } - - free(gGLHExts.mSysExts); - std::string extensions = str.str(); - gGLHExts.mSysExts = strdup(extensions.c_str()); - } -#endif + loadExtensionStrings(); stop_glerror(); @@ -587,27 +732,19 @@ bool LLGLManager::initGL() } #endif } - - if (mGLVersion >= 2.1f && LLImageGL::sCompressTextures) - { //use texture compression - glHint(GL_TEXTURE_COMPRESSION_HINT, GL_NICEST); - } - else - { //GL version is < 3.0, always disable texture compression - LLImageGL::sCompressTextures = false; - } // Trailing space necessary to keep "nVidia Corpor_ati_on" cards // from being recognized as ATI. - if (mGLVendor.substr(0,4) == "ATI ") + if (mGLVendor.substr(0,4) == "ATI " +//#if LL_LINUX +// // The Mesa-based drivers put this in the Renderer string, +// // not the Vendor string. +// || mGLRenderer.find("AMD") != std::string::npos +//#endif //LL_LINUX + ) { mGLVendorShort = "ATI"; - // "mobile" appears to be unused, and this code was causing warnings. - //BOOL mobile = FALSE; - //if (mGLRenderer.find("MOBILITY") != std::string::npos) - //{ - // mobile = TRUE; - //} + // *TODO: Fix this? mIsATI = TRUE; #if LL_WINDOWS && !LL_MESA_HEADLESS @@ -648,6 +785,14 @@ bool LLGLManager::initGL() { mIsGF3 = TRUE; } +#if LL_DARWIN + else if ((mGLRenderer.find("9400M") != std::string::npos) + || (mGLRenderer.find("9600M") != std::string::npos) + || (mGLRenderer.find("9800M") != std::string::npos)) + { + mIsMobileGF = TRUE; + } +#endif } else if (mGLVendor.find("INTEL") != std::string::npos @@ -660,6 +805,14 @@ bool LLGLManager::initGL() { mGLVendorShort = "INTEL"; mIsIntel = TRUE; +#if LL_WINDOWS + if (mGLRenderer.find("HD") != std::string::npos + && ((mGLRenderer.find("2000") != std::string::npos || mGLRenderer.find("3000") != std::string::npos) + || (mGLVersion == 3.1f && mGLRenderer.find("INTEL(R) HD GRAPHICS") != std::string::npos))) + { + mIsHD3K = TRUE; + } +#endif } else { @@ -667,10 +820,18 @@ bool LLGLManager::initGL() } stop_glerror(); - // This is called here because it depends on the setting of mIsGF2or4MX, and sets up mHasMultitexture. initExtensions(); stop_glerror(); + if (mGLVersion >= 2.1f && mHasCompressedTextures && LLImageGL::sCompressTextures) + { //use texture compression + glHint(GL_TEXTURE_COMPRESSION_HINT, GL_NICEST); + } + else + { //GL version is < 3.0, always disable texture compression + LLImageGL::sCompressTextures = false; + } + S32 old_vram = mVRAM; if (mHasATIMemInfo) @@ -703,8 +864,19 @@ bool LLGLManager::initGL() mNumTextureImageUnits = llmin(num_tex_image_units, 32); } + if (mHasVertexShader) + { + //According to the spec, the resulting value should never be less than 512. We need at least 1024 to use skinned shaders. + glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB, &mGLMaxVertexUniformComponents); + if (mIsHD3K) + { + mGLMaxVertexUniformComponents = llmax(mGLMaxVertexUniformComponents, 4096); + } + } + if (LLRender::sGLCoreProfile) { + // If core is true, then mNumTextureUnits is pretty much unused. mNumTextureUnits = llmin(mNumTextureImageUnits, MAX_GL_TEXTURE_UNITS); } else if (mHasMultitexture) @@ -727,7 +899,8 @@ bool LLGLManager::initGL() } stop_glerror(); - + + //Singu Note: Multisampled texture stuff in v3 is dead, however we DO use multisampled FBOs. if (mHasFramebufferMultisample) { glGetIntegerv(GL_MAX_INTEGER_SAMPLES, &mMaxIntegerSamples); @@ -738,16 +911,20 @@ bool LLGLManager::initGL() #if LL_WINDOWS if (mHasDebugOutput && gDebugGL) { //setup debug output callback + glEnable(GL_DEBUG_OUTPUT); glDebugMessageCallbackARB((GLDEBUGPROCARB) gl_debug_callback, NULL); glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB); + glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, true); } #endif stop_glerror(); +#if LL_WINDOWS if (mIsIntel && mGLVersion <= 3.f) { //never try to use framebuffer objects on older intel drivers (crashy) mHasFramebufferObject = FALSE; } +#endif stop_glerror(); @@ -780,12 +957,9 @@ void LLGLManager::getGLInfo(LLSD& info) info["GLInfo"]["GLVersion"] = std::string((const char *)glGetString(GL_VERSION)); #if !LL_MESA_HEADLESS - std::string all_exts = ll_safe_string((const char *)gGLHExts.mSysExts); - boost::char_separator sep(" "); - boost::tokenizer > tok(all_exts, sep); - for(boost::tokenizer >::iterator i = tok.begin(); i != tok.end(); ++i) + for (auto& extension : sGLExtensions) { - info["GLInfo"]["GLExtensions"].append(*i); + info["GLInfo"]["GLExtensions"].append(extension); } #endif } @@ -799,9 +973,11 @@ std::string LLGLManager::getGLInfoString() info_str += std::string("GL_VERSION ") + ll_safe_string((const char *)glGetString(GL_VERSION)) + std::string("\n"); #if !LL_MESA_HEADLESS - std::string all_exts= ll_safe_string(((const char *)gGLHExts.mSysExts)); - LLStringUtil::replaceChar(all_exts, ' ', '\n'); - info_str += std::string("GL_EXTENSIONS:\n") + all_exts + std::string("\n"); + info_str += std::string("GL_EXTENSIONS:\n"); + for (auto& extension : sGLExtensions) + { + info_str += extension + "\n"; + } #endif return info_str; @@ -813,10 +989,13 @@ void LLGLManager::printGLInfoString() LL_INFOS("RenderInit") << "GL_RENDERER: " << ((const char *)glGetString(GL_RENDERER)) << LL_ENDL; LL_INFOS("RenderInit") << "GL_VERSION: " << ((const char *)glGetString(GL_VERSION)) << LL_ENDL; -#if !LL_MESA_HEADLESS - std::string all_exts= ll_safe_string(((const char *)gGLHExts.mSysExts)); - LLStringUtil::replaceChar(all_exts, ' ', '\n'); - LL_DEBUGS("RenderInit") << "GL_EXTENSIONS:\n" << all_exts << LL_ENDL; +#if !LL_MESA_HEADLESS + LL_DEBUGS("RenderInit") << "GL_EXTENSIONS:" << "\n"; + for (auto& extension : sGLExtensions) + { + LL_CONT << extension << "\n"; + } + LL_CONT << LL_ENDL; #endif } @@ -889,7 +1068,6 @@ void LLGLManager::initExtensions() mHasBlendFuncSeparate = FALSE; # endif // GL_EXT_blend_func_separate mHasMipMapGeneration = FALSE; - mHasSeparateSpecularColor = FALSE; mHasAnisotropic = FALSE; mHasCubeMap = FALSE; mHasOcclusionQuery = FALSE; @@ -897,54 +1075,65 @@ void LLGLManager::initExtensions() mHasShaderObjects = FALSE; mHasVertexShader = FALSE; mHasFragmentShader = FALSE; - mHasTextureRectangle = FALSE; -#else // LL_MESA_HEADLESS //important, gGLHExts.mSysExts is uninitialized until after glh_init_extensions is called - mHasMultitexture = glh_init_extensions("GL_ARB_multitexture"); - mHasATIMemInfo = ExtensionExists("GL_ATI_meminfo", gGLHExts.mSysExts); - mHasNVXMemInfo = ExtensionExists("GL_NVX_gpu_memory_info", gGLHExts.mSysExts); - mHasSeparateSpecularColor = glh_init_extensions("GL_EXT_separate_specular_color"); - mHasAnisotropic = glh_init_extensions("GL_EXT_texture_filter_anisotropic"); - glh_init_extensions("GL_ARB_texture_cube_map"); - mHasCubeMap = ExtensionExists("GL_ARB_texture_cube_map", gGLHExts.mSysExts); - mHasARBEnvCombine = ExtensionExists("GL_ARB_texture_env_combine", gGLHExts.mSysExts); - mHasCompressedTextures = glh_init_extensions("GL_ARB_texture_compression"); - mHasOcclusionQuery = ExtensionExists("GL_ARB_occlusion_query", gGLHExts.mSysExts); - mHasOcclusionQuery2 = ExtensionExists("GL_ARB_occlusion_query2", gGLHExts.mSysExts); - mHasVertexBufferObject = ExtensionExists("GL_ARB_vertex_buffer_object", gGLHExts.mSysExts); - mHasVertexArrayObject = ExtensionExists("GL_ARB_vertex_array_object", gGLHExts.mSysExts); - mHasSync = ExtensionExists("GL_ARB_sync", gGLHExts.mSysExts); - mHasMapBufferRange = ExtensionExists("GL_ARB_map_buffer_range", gGLHExts.mSysExts); - mHasFlushBufferRange = ExtensionExists("GL_APPLE_flush_buffer_range", gGLHExts.mSysExts); - mHasDepthClamp = ExtensionExists("GL_ARB_depth_clamp", gGLHExts.mSysExts) || ExtensionExists("GL_NV_depth_clamp", gGLHExts.mSysExts); +#ifdef GL_ARB_gpu_shader5 + mHasGpuShader5 = FALSE; +#endif +#else // LL_MESA_HEADLESS + mHasMultitexture = mGLVersion >= 1.3f || ExtensionExists("GL_ARB_multitexture"); + mHasATIMemInfo = ExtensionExists("GL_ATI_meminfo"); + mHasNVXMemInfo = ExtensionExists("GL_NVX_gpu_memory_info"); + mHasCompressedTextures = mGLVersion >= 1.3 || ExtensionExists("GL_ARB_texture_compression"); + mHasAnisotropic = mGLVersion >= 4.6f || ExtensionExists("GL_EXT_texture_filter_anisotropic"); + mHasCubeMap = mGLVersion >= 1.3f || ExtensionExists("GL_ARB_texture_cube_map"); + mHasARBEnvCombine = mGLVersion >= 2.1f || ExtensionExists("GL_ARB_texture_env_combine"); + mHasOcclusionQuery = mGLVersion >= 1.5f || ExtensionExists("GL_ARB_occlusion_query"); + mHasOcclusionQuery2 = mGLVersion >= 3.3f || ExtensionExists("GL_ARB_occlusion_query2"); + mHasVertexBufferObject = mGLVersion >= 1.5f || ExtensionExists("GL_ARB_vertex_buffer_object"); + mHasVertexArrayObject = mGLVersion >= 3.f || ExtensionExists("GL_ARB_vertex_array_object"); + mHasSync = mGLVersion >= 3.2f || ExtensionExists("GL_ARB_sync"); + mHasMapBufferRange = mGLVersion >= 3.f || ExtensionExists("GL_ARB_map_buffer_range"); + mHasFlushBufferRange = ExtensionExists("GL_APPLE_flush_buffer_range"); + mHasDepthClamp = mGLVersion >= 3.2f || ExtensionExists("GL_ARB_depth_clamp") || ExtensionExists("GL_NV_depth_clamp"); // mask out FBO support when packed_depth_stencil isn't there 'cause we need it for LLRenderTarget -Brad #ifdef GL_ARB_framebuffer_object - mHasFramebufferObject = ExtensionExists("GL_ARB_framebuffer_object", gGLHExts.mSysExts); + mHasFramebufferObject = mGLVersion >= 3.f || ExtensionExists("GL_ARB_framebuffer_object"); #else - mHasFramebufferObject = ExtensionExists("GL_EXT_framebuffer_object", gGLHExts.mSysExts) && - ExtensionExists("GL_EXT_framebuffer_blit", gGLHExts.mSysExts) && - ExtensionExists("GL_EXT_framebuffer_multisample", gGLHExts.mSysExts) && - ExtensionExists("GL_EXT_packed_depth_stencil", gGLHExts.mSysExts); + mHasFramebufferObject = mGLVersion >= 3.f || (ExtensionExists("GL_EXT_framebuffer_object") && + ExtensionExists("GL_EXT_framebuffer_blit") && + ExtensionExists("GL_EXT_framebuffer_multisample") && + ExtensionExists("GL_EXT_packed_depth_stencil")); #endif - mHasFramebufferMultisample = mHasFramebufferObject && ExtensionExists("GL_EXT_framebuffer_multisample", gGLHExts.mSysExts); + mHasFramebufferMultisample = mGLVersion >= 3.f || (mHasFramebufferObject && ExtensionExists("GL_EXT_framebuffer_multisample")); mHasMipMapGeneration = mHasFramebufferObject || mGLVersion >= 1.4f; - mHasDrawBuffers = ExtensionExists("GL_ARB_draw_buffers", gGLHExts.mSysExts); - mHasBlendFuncSeparate = ExtensionExists("GL_EXT_blend_func_separate", gGLHExts.mSysExts); - mHasTextureRectangle = ExtensionExists("GL_ARB_texture_rectangle", gGLHExts.mSysExts); - mHasDebugOutput = ExtensionExists("GL_ARB_debug_output", gGLHExts.mSysExts); - mHasTransformFeedback = mGLVersion >= 4.f || ExtensionExists("GL_EXT_transform_feedback", gGLHExts.mSysExts); + mHasDrawBuffers = mGLVersion >= 2.f || ExtensionExists("GL_ARB_draw_buffers"); + mHasBlendFuncSeparate = mGLVersion >= 1.4f || ExtensionExists("GL_EXT_blend_func_separate"); + mHasDebugOutput = mGLVersion >= 4.3f || ExtensionExists("GL_ARB_debug_output"); + mHasTransformFeedback = mGLVersion >= 4.f || ExtensionExists("GL_EXT_transform_feedback"); #if !LL_DARWIN - mHasPointParameters = !mIsATI && ExtensionExists("GL_ARB_point_parameters", gGLHExts.mSysExts); + mHasPointParameters = mGLVersion >= 2.f || (!mIsATI && ExtensionExists("GL_ARB_point_parameters")); +#endif + mHasShaderObjects = mGLVersion >= 2.f || ExtensionExists("GL_ARB_shader_objects") && (LLRender::sGLCoreProfile || ExtensionExists("GL_ARB_shading_language_100")); + mHasVertexShader = mGLVersion >= 2.f || (ExtensionExists("GL_ARB_vertex_program") && ExtensionExists("GL_ARB_vertex_shader") + && (LLRender::sGLCoreProfile || ExtensionExists("GL_ARB_shading_language_100"))); + mHasFragmentShader = mGLVersion >= 2.f || ExtensionExists("GL_ARB_fragment_shader") && (LLRender::sGLCoreProfile || ExtensionExists("GL_ARB_shading_language_100")); #endif - mHasShaderObjects = ExtensionExists("GL_ARB_shader_objects", gGLHExts.mSysExts) && (LLRender::sGLCoreProfile || ExtensionExists("GL_ARB_shading_language_100", gGLHExts.mSysExts)); - mHasVertexShader = ExtensionExists("GL_ARB_vertex_program", gGLHExts.mSysExts) && ExtensionExists("GL_ARB_vertex_shader", gGLHExts.mSysExts) - && (LLRender::sGLCoreProfile || ExtensionExists("GL_ARB_shading_language_100", gGLHExts.mSysExts)); - mHasFragmentShader = ExtensionExists("GL_ARB_fragment_shader", gGLHExts.mSysExts) && (LLRender::sGLCoreProfile || ExtensionExists("GL_ARB_shading_language_100", gGLHExts.mSysExts)); +#ifdef GL_ARB_gpu_shader5 + mHasGpuShader5 = mGLVersion >= 4.f || ExtensionExists("GL_ARB_gpu_shader5");; +#endif +#if LL_WINDOWS + mHasAdaptiveVsync = ExtensionExists("WGL_EXT_swap_control_tear"); +#elif LL_LINUX + mHasAdaptiveVsync = ExtensionExists("GLX_EXT_swap_control_tear"); +#endif + +#ifdef GL_ARB_texture_swizzle + mHasTextureSwizzle = mGLVersion >= 3.3f || ExtensionExists("GL_ARB_texture_swizzle"); #endif #if LL_LINUX || LL_SOLARIS - llinfos << "initExtensions() checking shell variables to adjust features..." << llendl; + LL_INFOS() << "initExtensions() checking shell variables to adjust features..." << LL_ENDL; // Our extension support for the Linux Client is very young with some // potential driver gotchas, so offer a semi-secret way to turn it off. if (getenv("LL_GL_NOEXT")) /* Flawfinder: ignore */ @@ -959,7 +1148,6 @@ void LLGLManager::initExtensions() mHasDrawBuffers = FALSE; mHasBlendFuncSeparate = FALSE; mHasMipMapGeneration = FALSE; - mHasSeparateSpecularColor = FALSE; mHasAnisotropic = FALSE; mHasCubeMap = FALSE; mHasOcclusionQuery = FALSE; @@ -967,6 +1155,8 @@ void LLGLManager::initExtensions() mHasShaderObjects = FALSE; mHasVertexShader = FALSE; mHasFragmentShader = FALSE; + mHasAdaptiveVsync = FALSE; + mHasTextureSwizzle = FALSE; LL_WARNS("RenderInit") << "GL extension support DISABLED via LL_GL_NOEXT" << LL_ENDL; } else if (getenv("LL_GL_BASICEXT")) /* Flawfinder: ignore */ @@ -998,7 +1188,6 @@ void LLGLManager::initExtensions() if (strchr(blacklist,'d')) mHasMipMapGeneration = FALSE;//S // if (strchr(blacklist,'f')) mHasNVVertexArrayRange = FALSE;//S // if (strchr(blacklist,'g')) mHasNVFence = FALSE;//S - if (strchr(blacklist,'h')) mHasSeparateSpecularColor = FALSE; if (strchr(blacklist,'i')) mHasAnisotropic = FALSE;//S if (strchr(blacklist,'j')) mHasCubeMap = FALSE;//S // if (strchr(blacklist,'k')) mHasATIVAO = FALSE;//S @@ -1010,7 +1199,6 @@ void LLGLManager::initExtensions() if (strchr(blacklist,'q')) mHasFramebufferObject = FALSE;//S if (strchr(blacklist,'r')) mHasDrawBuffers = FALSE;//S if (strchr(blacklist,'s')) mHasFramebufferMultisample = FALSE; - if (strchr(blacklist,'t')) mHasTextureRectangle = FALSE; if (strchr(blacklist,'u')) mHasBlendFuncSeparate = FALSE;//S if (strchr(blacklist,'v')) mHasDepthClamp = FALSE; @@ -1029,10 +1217,6 @@ void LLGLManager::initExtensions() { LL_INFOS("RenderInit") << "Couldn't initialize GL_ARB_texture_env_combine" << LL_ENDL; } - if (!mHasSeparateSpecularColor) - { - LL_INFOS("RenderInit") << "Couldn't initialize separate specular color" << LL_ENDL; - } if (!mHasAnisotropic) { LL_INFOS("RenderInit") << "Couldn't initialize anisotropic filtering" << LL_ENDL; @@ -1092,23 +1276,72 @@ void LLGLManager::initExtensions() glGetIntegerv(GL_MAX_ELEMENTS_VERTICES, (GLint*) &mGLMaxVertexRange); glGetIntegerv(GL_MAX_ELEMENTS_INDICES, (GLint*) &mGLMaxIndexRange); -#if (LL_WINDOWS || LL_LINUX || LL_SOLARIS) && !LL_MESA_HEADLESS +#if (LL_WINDOWS || LL_LINUX) && !LL_MESA_HEADLESS LL_DEBUGS("RenderInit") << "GL Probe: Getting symbols" << LL_ENDL; +#if LL_WINDOWS + if (mHasMultitexture) + { + glMultiTexCoord1dARB = (PFNGLMULTITEXCOORD1DARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.3, "glMultiTexCoord1d"); + glMultiTexCoord1dvARB = (PFNGLMULTITEXCOORD1DVARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.3, "glMultiTexCoord1dv"); + glMultiTexCoord1fARB = (PFNGLMULTITEXCOORD1FARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.3, "glMultiTexCoord1f"); + glMultiTexCoord1fvARB = (PFNGLMULTITEXCOORD1FVARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.3, "glMultiTexCoord1fv"); + glMultiTexCoord1iARB = (PFNGLMULTITEXCOORD1IARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.3, "glMultiTexCoord1i"); + glMultiTexCoord1ivARB = (PFNGLMULTITEXCOORD1IVARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.3, "glMultiTexCoord1iv"); + glMultiTexCoord1sARB = (PFNGLMULTITEXCOORD1SARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.3, "glMultiTexCoord1s"); + glMultiTexCoord1svARB = (PFNGLMULTITEXCOORD1SVARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.3, "glMultiTexCoord1sv"); + glMultiTexCoord2dARB = (PFNGLMULTITEXCOORD2DARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.3, "glMultiTexCoord2d"); + glMultiTexCoord2dvARB = (PFNGLMULTITEXCOORD2DVARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.3, "glMultiTexCoord2dv"); + glMultiTexCoord2fARB = (PFNGLMULTITEXCOORD2FARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.3, "glMultiTexCoord2f"); + glMultiTexCoord2fvARB = (PFNGLMULTITEXCOORD2FVARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.3, "glMultiTexCoord2fv"); + glMultiTexCoord2iARB = (PFNGLMULTITEXCOORD2IARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.3, "glMultiTexCoord2i"); + glMultiTexCoord2ivARB = (PFNGLMULTITEXCOORD2IVARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.3, "glMultiTexCoord2iv"); + glMultiTexCoord2sARB = (PFNGLMULTITEXCOORD2SARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.3, "glMultiTexCoord2s"); + glMultiTexCoord2svARB = (PFNGLMULTITEXCOORD2SVARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.3, "glMultiTexCoord2sv"); + glMultiTexCoord3dARB = (PFNGLMULTITEXCOORD3DARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.3, "glMultiTexCoord3d"); + glMultiTexCoord3dvARB = (PFNGLMULTITEXCOORD3DVARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.3, "glMultiTexCoord3dv"); + glMultiTexCoord3fARB = (PFNGLMULTITEXCOORD3FARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.3, "glMultiTexCoord3f"); + glMultiTexCoord3fvARB = (PFNGLMULTITEXCOORD3FVARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.3, "glMultiTexCoord3fv"); + glMultiTexCoord3iARB = (PFNGLMULTITEXCOORD3IARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.3, "glMultiTexCoord3i"); + glMultiTexCoord3ivARB = (PFNGLMULTITEXCOORD3IVARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.3, "glMultiTexCoord3iv"); + glMultiTexCoord3sARB = (PFNGLMULTITEXCOORD3SARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.3, "glMultiTexCoord3s"); + glMultiTexCoord3svARB = (PFNGLMULTITEXCOORD3SVARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.3, "glMultiTexCoord3sv"); + glMultiTexCoord4dARB = (PFNGLMULTITEXCOORD4DARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.3, "glMultiTexCoord4d"); + glMultiTexCoord4dvARB = (PFNGLMULTITEXCOORD4DVARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.3, "glMultiTexCoord4dv"); + glMultiTexCoord4fARB = (PFNGLMULTITEXCOORD4FARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.3, "glMultiTexCoord4f"); + glMultiTexCoord4fvARB = (PFNGLMULTITEXCOORD4FVARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.3, "glMultiTexCoord4fv"); + glMultiTexCoord4iARB = (PFNGLMULTITEXCOORD4IARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.3, "glMultiTexCoord4i"); + glMultiTexCoord4ivARB = (PFNGLMULTITEXCOORD4IVARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.3, "glMultiTexCoord4iv"); + glMultiTexCoord4sARB = (PFNGLMULTITEXCOORD4SARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.3, "glMultiTexCoord4s"); + glMultiTexCoord4svARB = (PFNGLMULTITEXCOORD4SVARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.3, "glMultiTexCoord4sv"); + glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.3, "glActiveTexture"); + glClientActiveTextureARB = (PFNGLCLIENTACTIVETEXTUREARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.3, "glClientActiveTexture"); + } +#endif + if (mHasCompressedTextures) + { + glCompressedTexImage3DARB = (PFNGLCOMPRESSEDTEXIMAGE3DARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.3, "glCompressedTexImage3D"); + glCompressedTexImage2DARB = (PFNGLCOMPRESSEDTEXIMAGE2DARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.3, "glCompressedTexImage2D"); + glCompressedTexImage1DARB = (PFNGLCOMPRESSEDTEXIMAGE1DARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.3, "glCompressedTexImage1D"); + glCompressedTexSubImage3DARB = (PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.3, "glCompressedTexSubImage3D"); + glCompressedTexSubImage2DARB = (PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.3, "glCompressedTexSubImage2D"); + glCompressedTexSubImage1DARB = (PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.3, "glCompressedTexSubImage1D"); + glGetCompressedTexImageARB = (PFNGLGETCOMPRESSEDTEXIMAGEARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.3, "glGetCompressedTexImage"); + } if (mHasVertexBufferObject) { - glBindBufferARB = (PFNGLBINDBUFFERARBPROC)GLH_EXT_GET_PROC_ADDRESS("glBindBufferARB"); + glBindBufferARB = (PFNGLBINDBUFFERARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.5, "glBindBuffer"); if (glBindBufferARB) { - glDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC)GLH_EXT_GET_PROC_ADDRESS("glDeleteBuffersARB"); - glGenBuffersARB = (PFNGLGENBUFFERSARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGenBuffersARB"); - glIsBufferARB = (PFNGLISBUFFERARBPROC)GLH_EXT_GET_PROC_ADDRESS("glIsBufferARB"); - glBufferDataARB = (PFNGLBUFFERDATAARBPROC)GLH_EXT_GET_PROC_ADDRESS("glBufferDataARB"); - glBufferSubDataARB = (PFNGLBUFFERSUBDATAARBPROC)GLH_EXT_GET_PROC_ADDRESS("glBufferSubDataARB"); - glGetBufferSubDataARB = (PFNGLGETBUFFERSUBDATAARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetBufferSubDataARB"); - glMapBufferARB = (PFNGLMAPBUFFERARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMapBufferARB"); - glUnmapBufferARB = (PFNGLUNMAPBUFFERARBPROC)GLH_EXT_GET_PROC_ADDRESS("glUnmapBufferARB"); - glGetBufferParameterivARB = (PFNGLGETBUFFERPARAMETERIVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetBufferParameterivARB"); - glGetBufferPointervARB = (PFNGLGETBUFFERPOINTERVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetBufferPointervARB"); + glDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.5, "glDeleteBuffers"); + glGenBuffersARB = (PFNGLGENBUFFERSARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.5, "glGenBuffers"); + glIsBufferARB = (PFNGLISBUFFERARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.5, "glIsBuffer"); + glBufferDataARB = (PFNGLBUFFERDATAARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.5, "glBufferData"); + glBufferSubDataARB = (PFNGLBUFFERSUBDATAARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.5, "glBufferSubData"); + glGetBufferSubDataARB = (PFNGLGETBUFFERSUBDATAARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.5, "glGetBufferSubData"); + glMapBufferARB = (PFNGLMAPBUFFERARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.5, "glMapBuffer"); + glUnmapBufferARB = (PFNGLUNMAPBUFFERARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.5, "glUnmapBuffer"); + glGetBufferParameterivARB = (PFNGLGETBUFFERPARAMETERIVARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.5, "glGetBufferParameteriv"); + glGetBufferPointervARB = (PFNGLGETBUFFERPOINTERVARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.5, "glGetBufferPointerv"); } else { @@ -1139,7 +1372,7 @@ void LLGLManager::initExtensions() } if (mHasFramebufferObject) { - llinfos << "initExtensions() FramebufferObject-related procs..." << llendl; + LL_INFOS() << "initExtensions() FramebufferObject-related procs..." << LL_ENDL; glIsRenderbuffer = (PFNGLISRENDERBUFFERPROC) GLH_EXT_GET_PROC_ADDRESS("glIsRenderbuffer"); glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC) GLH_EXT_GET_PROC_ADDRESS("glBindRenderbuffer"); glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC) GLH_EXT_GET_PROC_ADDRESS("glDeleteRenderbuffers"); @@ -1163,27 +1396,27 @@ void LLGLManager::initExtensions() } if (mHasDrawBuffers) { - glDrawBuffersARB = (PFNGLDRAWBUFFERSARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDrawBuffersARB"); + glDrawBuffersARB = (PFNGLDRAWBUFFERSARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glDrawBuffers"); } if (mHasBlendFuncSeparate) { - glBlendFuncSeparateEXT = (PFNGLBLENDFUNCSEPARATEEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glBlendFuncSeparateEXT"); + glBlendFuncSeparateEXT = (PFNGLBLENDFUNCSEPARATEEXTPROC)GLH_EXT_GET_PROC_ADDRESS_CORE_EXT(1.4, "glBlendFuncSeparate"); } if (mHasTransformFeedback) { - glBeginTransformFeedback = (PFNGLBEGINTRANSFORMFEEDBACKPROC) GLH_EXT_GET_PROC_ADDRESS("glBeginTransformFeedback"); - glEndTransformFeedback = (PFNGLENDTRANSFORMFEEDBACKPROC) GLH_EXT_GET_PROC_ADDRESS("glEndTransformFeedback"); - glTransformFeedbackVaryings = (PFNGLTRANSFORMFEEDBACKVARYINGSPROC) GLH_EXT_GET_PROC_ADDRESS("glTransformFeedbackVaryings"); - glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC) GLH_EXT_GET_PROC_ADDRESS("glBindBufferRange"); + glBeginTransformFeedback = (PFNGLBEGINTRANSFORMFEEDBACKPROC)GLH_EXT_GET_PROC_ADDRESS_CORE_EXT(4.0, "glBeginTransformFeedback"); + glEndTransformFeedback = (PFNGLENDTRANSFORMFEEDBACKPROC)GLH_EXT_GET_PROC_ADDRESS_CORE_EXT(4.0, "glEndTransformFeedback"); + glTransformFeedbackVaryings = (PFNGLTRANSFORMFEEDBACKVARYINGSPROC)GLH_EXT_GET_PROC_ADDRESS_CORE_EXT(4.0, "glTransformFeedbackVaryings"); + glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC)GLH_EXT_GET_PROC_ADDRESS_CORE_EXT(3.0, "glBindBufferRange"); } if (mHasDebugOutput) { - glDebugMessageControlARB = (PFNGLDEBUGMESSAGECONTROLARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDebugMessageControlARB"); - glDebugMessageInsertARB = (PFNGLDEBUGMESSAGEINSERTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDebugMessageInsertARB"); - glDebugMessageCallbackARB = (PFNGLDEBUGMESSAGECALLBACKARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDebugMessageCallbackARB"); - glGetDebugMessageLogARB = (PFNGLGETDEBUGMESSAGELOGARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetDebugMessageLogARB"); + glDebugMessageControlARB = (PFNGLDEBUGMESSAGECONTROLARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(4.3, "glDebugMessageControl"); + glDebugMessageInsertARB = (PFNGLDEBUGMESSAGEINSERTARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(4.3, "glDebugMessageInsert"); + glDebugMessageCallbackARB = (PFNGLDEBUGMESSAGECALLBACKARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(4.3, "glDebugMessageCallback"); + glGetDebugMessageLogARB = (PFNGLGETDEBUGMESSAGELOGARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(4.3, "glGetDebugMessageLog"); } -#if (!LL_LINUX && !LL_SOLARIS) || LL_LINUX_NV_GL_HEADERS +#if !LL_LINUX || LL_LINUX_NV_GL_HEADERS // This is expected to be a static symbol on Linux GL implementations, except if we use the nvidia headers - bah glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC)GLH_EXT_GET_PROC_ADDRESS("glDrawRangeElements"); if (!glDrawRangeElements) @@ -1194,139 +1427,125 @@ void LLGLManager::initExtensions() #endif // !LL_LINUX || LL_LINUX_NV_GL_HEADERS #if LL_LINUX_NV_GL_HEADERS // nvidia headers are critically different from mesa-esque - glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC)GLH_EXT_GET_PROC_ADDRESS("glActiveTextureARB"); - glClientActiveTextureARB = (PFNGLCLIENTACTIVETEXTUREARBPROC)GLH_EXT_GET_PROC_ADDRESS("glClientActiveTextureARB"); + glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC)GLH_EXT_GET_PROC_ADDRESS("glActiveTexture"); + glClientActiveTextureARB = (PFNGLCLIENTACTIVETEXTUREARBPROC)GLH_EXT_GET_PROC_ADDRESS("glClientActiveTexture"); #endif // LL_LINUX_NV_GL_HEADERS if (mHasOcclusionQuery) { - llinfos << "initExtensions() OcclusionQuery-related procs..." << llendl; - glGenQueriesARB = (PFNGLGENQUERIESARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGenQueriesARB"); - glDeleteQueriesARB = (PFNGLDELETEQUERIESARBPROC)GLH_EXT_GET_PROC_ADDRESS("glDeleteQueriesARB"); - glIsQueryARB = (PFNGLISQUERYARBPROC)GLH_EXT_GET_PROC_ADDRESS("glIsQueryARB"); - glBeginQueryARB = (PFNGLBEGINQUERYARBPROC)GLH_EXT_GET_PROC_ADDRESS("glBeginQueryARB"); - glEndQueryARB = (PFNGLENDQUERYARBPROC)GLH_EXT_GET_PROC_ADDRESS("glEndQueryARB"); - glGetQueryivARB = (PFNGLGETQUERYIVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetQueryivARB"); - glGetQueryObjectivARB = (PFNGLGETQUERYOBJECTIVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetQueryObjectivARB"); - glGetQueryObjectuivARB = (PFNGLGETQUERYOBJECTUIVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetQueryObjectuivARB"); + LL_INFOS() << "initExtensions() OcclusionQuery-related procs..." << LL_ENDL; + glGenQueriesARB = (PFNGLGENQUERIESARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.4, "glGenQueries"); + glDeleteQueriesARB = (PFNGLDELETEQUERIESARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.4, "glDeleteQueries"); + glIsQueryARB = (PFNGLISQUERYARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.4, "glIsQuery"); + glBeginQueryARB = (PFNGLBEGINQUERYARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.4, "glBeginQuery"); + glEndQueryARB = (PFNGLENDQUERYARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.4, "glEndQuery"); + glGetQueryivARB = (PFNGLGETQUERYIVARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.4, "glGetQueryiv"); + glGetQueryObjectivARB = (PFNGLGETQUERYOBJECTIVARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.4, "glGetQueryObjectiv"); + glGetQueryObjectuivARB = (PFNGLGETQUERYOBJECTUIVARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(1.4, "glGetQueryObjectuiv"); } +#if !LL_DARWIN + glGetQueryObjectui64vEXT = (PFNGLGETQUERYOBJECTUI64VEXTPROC)GLH_EXT_GET_PROC_ADDRESS_CORE_EXT(3.2, "glGetQueryObjectui64v"); +#endif if (mHasPointParameters) { - llinfos << "initExtensions() PointParameters-related procs..." << llendl; - glPointParameterfARB = (PFNGLPOINTPARAMETERFARBPROC)GLH_EXT_GET_PROC_ADDRESS("glPointParameterfARB"); - glPointParameterfvARB = (PFNGLPOINTPARAMETERFVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glPointParameterfvARB"); + LL_INFOS() << "initExtensions() PointParameters-related procs..." << LL_ENDL; + glPointParameterfARB = (PFNGLPOINTPARAMETERFARBPROC) GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glPointParameterf"); + glPointParameterfvARB = (PFNGLPOINTPARAMETERFVARBPROC) GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glPointParameterfv"); } if (mHasShaderObjects) { - glDeleteObjectARB = (PFNGLDELETEOBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDeleteObjectARB"); - glGetHandleARB = (PFNGLGETHANDLEARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetHandleARB"); - glDetachObjectARB = (PFNGLDETACHOBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDetachObjectARB"); - glCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glCreateShaderObjectARB"); - glShaderSourceARB = (PFNGLSHADERSOURCEARBPROC) GLH_EXT_GET_PROC_ADDRESS("glShaderSourceARB"); - glCompileShaderARB = (PFNGLCOMPILESHADERARBPROC) GLH_EXT_GET_PROC_ADDRESS("glCompileShaderARB"); - glCreateProgramObjectARB = (PFNGLCREATEPROGRAMOBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glCreateProgramObjectARB"); - glAttachObjectARB = (PFNGLATTACHOBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glAttachObjectARB"); - glLinkProgramARB = (PFNGLLINKPROGRAMARBPROC) GLH_EXT_GET_PROC_ADDRESS("glLinkProgramARB"); - glUseProgramObjectARB = (PFNGLUSEPROGRAMOBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUseProgramObjectARB"); - glValidateProgramARB = (PFNGLVALIDATEPROGRAMARBPROC) GLH_EXT_GET_PROC_ADDRESS("glValidateProgramARB"); - glUniform1fARB = (PFNGLUNIFORM1FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform1fARB"); - glUniform2fARB = (PFNGLUNIFORM2FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform2fARB"); - glUniform3fARB = (PFNGLUNIFORM3FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform3fARB"); - glUniform4fARB = (PFNGLUNIFORM4FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform4fARB"); - glUniform1iARB = (PFNGLUNIFORM1IARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform1iARB"); - glUniform2iARB = (PFNGLUNIFORM2IARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform2iARB"); - glUniform3iARB = (PFNGLUNIFORM3IARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform3iARB"); - glUniform4iARB = (PFNGLUNIFORM4IARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform4iARB"); - glUniform1fvARB = (PFNGLUNIFORM1FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform1fvARB"); - glUniform2fvARB = (PFNGLUNIFORM2FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform2fvARB"); - glUniform3fvARB = (PFNGLUNIFORM3FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform3fvARB"); - glUniform4fvARB = (PFNGLUNIFORM4FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform4fvARB"); - glUniform1ivARB = (PFNGLUNIFORM1IVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform1ivARB"); - glUniform2ivARB = (PFNGLUNIFORM2IVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform2ivARB"); - glUniform3ivARB = (PFNGLUNIFORM3IVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform3ivARB"); - glUniform4ivARB = (PFNGLUNIFORM4IVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform4ivARB"); - glUniformMatrix2fvARB = (PFNGLUNIFORMMATRIX2FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniformMatrix2fvARB"); - glUniformMatrix3fvARB = (PFNGLUNIFORMMATRIX3FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniformMatrix3fvARB"); - glUniformMatrix4fvARB = (PFNGLUNIFORMMATRIX4FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniformMatrix4fvARB"); - glGetObjectParameterfvARB = (PFNGLGETOBJECTPARAMETERFVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetObjectParameterfvARB"); - glGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetObjectParameterivARB"); - glGetInfoLogARB = (PFNGLGETINFOLOGARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetInfoLogARB"); - glGetAttachedObjectsARB = (PFNGLGETATTACHEDOBJECTSARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetAttachedObjectsARB"); - glGetUniformLocationARB = (PFNGLGETUNIFORMLOCATIONARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetUniformLocationARB"); - glGetActiveUniformARB = (PFNGLGETACTIVEUNIFORMARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetActiveUniformARB"); - glGetUniformfvARB = (PFNGLGETUNIFORMFVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetUniformfvARB"); - glGetUniformivARB = (PFNGLGETUNIFORMIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetUniformivARB"); - glGetShaderSourceARB = (PFNGLGETSHADERSOURCEARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetShaderSourceARB"); + glDeleteShader = (PFNGLDELETEOBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS_CORE_OR_ARB(2.0, "glDeleteShader", "glDeleteObjectARB"); + glDeleteProgram = (PFNGLDELETEOBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS_CORE_OR_ARB(2.0, "glDeleteProgram", "glDeleteObjectARB"); + glDetachObjectARB = (PFNGLDETACHOBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS_CORE_OR_ARB(2.0, "glDetachShader", "glDetachObjectARB"); + glCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS_CORE_OR_ARB(2.0, "glCreateShader", "glCreateShaderObjectARB"); + glShaderSourceARB = (PFNGLSHADERSOURCEARBPROC) GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glShaderSource"); + glCompileShaderARB = (PFNGLCOMPILESHADERARBPROC) GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glCompileShader"); + glCreateProgramObjectARB = (PFNGLCREATEPROGRAMOBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS_CORE_OR_ARB(2.0, "glCreateProgram", "glCreateProgramObjectARB"); + glAttachObjectARB = (PFNGLATTACHOBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS_CORE_OR_ARB(2.0, "glAttachShader", "glAttachObjectARB"); + glLinkProgramARB = (PFNGLLINKPROGRAMARBPROC) GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glLinkProgram"); + glUseProgramObjectARB = (PFNGLUSEPROGRAMOBJECTARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE_OR_ARB(2.0, "glUseProgram", "glUseProgramObjectARB"); + glValidateProgramARB = (PFNGLVALIDATEPROGRAMARBPROC) GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glValidateProgram"); + glUniform1fARB = (PFNGLUNIFORM1FARBPROC) GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glUniform1f"); + glUniform2fARB = (PFNGLUNIFORM2FARBPROC) GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glUniform2f"); + glUniform3fARB = (PFNGLUNIFORM3FARBPROC) GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glUniform3f"); + glUniform4fARB = (PFNGLUNIFORM4FARBPROC) GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glUniform4f"); + glUniform1iARB = (PFNGLUNIFORM1IARBPROC) GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glUniform1i"); + glUniform2iARB = (PFNGLUNIFORM2IARBPROC) GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glUniform2i"); + glUniform3iARB = (PFNGLUNIFORM3IARBPROC) GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glUniform3i"); + glUniform4iARB = (PFNGLUNIFORM4IARBPROC) GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glUniform4i"); + glUniform1fvARB = (PFNGLUNIFORM1FVARBPROC) GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glUniform1fv"); + glUniform2fvARB = (PFNGLUNIFORM2FVARBPROC) GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glUniform2fv"); + glUniform3fvARB = (PFNGLUNIFORM3FVARBPROC) GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glUniform3fv"); + glUniform4fvARB = (PFNGLUNIFORM4FVARBPROC) GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glUniform4fv"); + glUniform1ivARB = (PFNGLUNIFORM1IVARBPROC) GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glUniform1iv"); + glUniform2ivARB = (PFNGLUNIFORM2IVARBPROC) GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glUniform2iv"); + glUniform3ivARB = (PFNGLUNIFORM3IVARBPROC) GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glUniform3iv"); + glUniform4ivARB = (PFNGLUNIFORM4IVARBPROC) GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glUniform4iv"); + glUniformMatrix2fvARB = (PFNGLUNIFORMMATRIX2FVARBPROC) GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glUniformMatrix2fv"); + glUniformMatrix3fvARB = (PFNGLUNIFORMMATRIX3FVARBPROC) GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glUniformMatrix3fv"); + glUniformMatrix3x4fv = (PFNGLUNIFORMMATRIX3X4FVPROC) GLH_EXT_GET_PROC_ADDRESS_CORE(2.1, "glUniformMatrix3x4fv"); + glUniformMatrix4fvARB = (PFNGLUNIFORMMATRIX4FVARBPROC) GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glUniformMatrix4fv"); + glGetShaderiv = (PFNGLGETOBJECTPARAMETERIVARBPROC) GLH_EXT_GET_PROC_ADDRESS_CORE_OR_ARB(2.0, "glGetShaderiv", "glGetObjectParameteriv"); + glGetProgramiv = (PFNGLGETOBJECTPARAMETERIVARBPROC) GLH_EXT_GET_PROC_ADDRESS_CORE_OR_ARB(2.0, "glGetProgramiv", "glGetObjectParameteriv"); + glGetShaderInfoLog = (PFNGLGETINFOLOGARBPROC) GLH_EXT_GET_PROC_ADDRESS_CORE_OR_ARB(2.0, "glGetShaderInfoLog", "glGetInfoLog"); + glGetProgramInfoLog = (PFNGLGETINFOLOGARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE_OR_ARB(2.0, "glGetProgramInfoLog", "glGetInfoLog"); + glGetAttachedObjectsARB = (PFNGLGETATTACHEDOBJECTSARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE_OR_ARB(2.0, "glGetAttachedShaders", "glGetAttachedObjects"); + glGetUniformLocationARB = (PFNGLGETUNIFORMLOCATIONARBPROC) GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glGetUniformLocation"); + glGetActiveUniformARB = (PFNGLGETACTIVEUNIFORMARBPROC) GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glGetActiveUniform"); + glGetUniformfvARB = (PFNGLGETUNIFORMFVARBPROC) GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glGetUniformfv"); + glGetUniformivARB = (PFNGLGETUNIFORMIVARBPROC) GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glGetUniformiv"); + glGetShaderSourceARB = (PFNGLGETSHADERSOURCEARBPROC) GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glGetShaderSource"); } if (mHasVertexShader) { - llinfos << "initExtensions() VertexShader-related procs..." << llendl; - glGetAttribLocationARB = (PFNGLGETATTRIBLOCATIONARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetAttribLocationARB"); - glBindAttribLocationARB = (PFNGLBINDATTRIBLOCATIONARBPROC) GLH_EXT_GET_PROC_ADDRESS("glBindAttribLocationARB"); - glGetActiveAttribARB = (PFNGLGETACTIVEATTRIBARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetActiveAttribARB"); - glVertexAttrib1dARB = (PFNGLVERTEXATTRIB1DARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1dARB"); - glVertexAttrib1dvARB = (PFNGLVERTEXATTRIB1DVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1dvARB"); - glVertexAttrib1fARB = (PFNGLVERTEXATTRIB1FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1fARB"); - glVertexAttrib1fvARB = (PFNGLVERTEXATTRIB1FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1fvARB"); - glVertexAttrib1sARB = (PFNGLVERTEXATTRIB1SARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1sARB"); - glVertexAttrib1svARB = (PFNGLVERTEXATTRIB1SVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1svARB"); - glVertexAttrib2dARB = (PFNGLVERTEXATTRIB2DARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2dARB"); - glVertexAttrib2dvARB = (PFNGLVERTEXATTRIB2DVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2dvARB"); - glVertexAttrib2fARB = (PFNGLVERTEXATTRIB2FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2fARB"); - glVertexAttrib2fvARB = (PFNGLVERTEXATTRIB2FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2fvARB"); - glVertexAttrib2sARB = (PFNGLVERTEXATTRIB2SARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2sARB"); - glVertexAttrib2svARB = (PFNGLVERTEXATTRIB2SVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2svARB"); - glVertexAttrib3dARB = (PFNGLVERTEXATTRIB3DARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3dARB"); - glVertexAttrib3dvARB = (PFNGLVERTEXATTRIB3DVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3dvARB"); - glVertexAttrib3fARB = (PFNGLVERTEXATTRIB3FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3fARB"); - glVertexAttrib3fvARB = (PFNGLVERTEXATTRIB3FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3fvARB"); - glVertexAttrib3sARB = (PFNGLVERTEXATTRIB3SARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3sARB"); - glVertexAttrib3svARB = (PFNGLVERTEXATTRIB3SVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3svARB"); - glVertexAttrib4nbvARB = (PFNGLVERTEXATTRIB4NBVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nbvARB"); - glVertexAttrib4nivARB = (PFNGLVERTEXATTRIB4NIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nivARB"); - glVertexAttrib4nsvARB = (PFNGLVERTEXATTRIB4NSVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nsvARB"); - glVertexAttrib4nubARB = (PFNGLVERTEXATTRIB4NUBARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nubARB"); - glVertexAttrib4nubvARB = (PFNGLVERTEXATTRIB4NUBVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nubvARB"); - glVertexAttrib4nuivARB = (PFNGLVERTEXATTRIB4NUIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nuivARB"); - glVertexAttrib4nusvARB = (PFNGLVERTEXATTRIB4NUSVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nusvARB"); - glVertexAttrib4bvARB = (PFNGLVERTEXATTRIB4BVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4bvARB"); - glVertexAttrib4dARB = (PFNGLVERTEXATTRIB4DARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4dARB"); - glVertexAttrib4dvARB = (PFNGLVERTEXATTRIB4DVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4dvARB"); - glVertexAttrib4fARB = (PFNGLVERTEXATTRIB4FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4fARB"); - glVertexAttrib4fvARB = (PFNGLVERTEXATTRIB4FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4fvARB"); - glVertexAttrib4ivARB = (PFNGLVERTEXATTRIB4IVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4ivARB"); - glVertexAttrib4sARB = (PFNGLVERTEXATTRIB4SARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4sARB"); - glVertexAttrib4svARB = (PFNGLVERTEXATTRIB4SVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4svARB"); - glVertexAttrib4ubvARB = (PFNGLVERTEXATTRIB4UBVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4ubvARB"); - glVertexAttrib4uivARB = (PFNGLVERTEXATTRIB4UIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4uivARB"); - glVertexAttrib4usvARB = (PFNGLVERTEXATTRIB4USVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4usvARB"); - glVertexAttribPointerARB = (PFNGLVERTEXATTRIBPOINTERARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttribPointerARB"); - glVertexAttribIPointer = (PFNGLVERTEXATTRIBIPOINTERPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttribIPointer"); - glEnableVertexAttribArrayARB = (PFNGLENABLEVERTEXATTRIBARRAYARBPROC) GLH_EXT_GET_PROC_ADDRESS("glEnableVertexAttribArrayARB"); - glDisableVertexAttribArrayARB = (PFNGLDISABLEVERTEXATTRIBARRAYARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDisableVertexAttribArrayARB"); - glProgramStringARB = (PFNGLPROGRAMSTRINGARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramStringARB"); - glBindProgramARB = (PFNGLBINDPROGRAMARBPROC) GLH_EXT_GET_PROC_ADDRESS("glBindProgramARB"); - glDeleteProgramsARB = (PFNGLDELETEPROGRAMSARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDeleteProgramsARB"); - glGenProgramsARB = (PFNGLGENPROGRAMSARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGenProgramsARB"); - glProgramEnvParameter4dARB = (PFNGLPROGRAMENVPARAMETER4DARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramEnvParameter4dARB"); - glProgramEnvParameter4dvARB = (PFNGLPROGRAMENVPARAMETER4DVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramEnvParameter4dvARB"); - glProgramEnvParameter4fARB = (PFNGLPROGRAMENVPARAMETER4FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramEnvParameter4fARB"); - glProgramEnvParameter4fvARB = (PFNGLPROGRAMENVPARAMETER4FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramEnvParameter4fvARB"); - glProgramLocalParameter4dARB = (PFNGLPROGRAMLOCALPARAMETER4DARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramLocalParameter4dARB"); - glProgramLocalParameter4dvARB = (PFNGLPROGRAMLOCALPARAMETER4DVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramLocalParameter4dvARB"); - glProgramLocalParameter4fARB = (PFNGLPROGRAMLOCALPARAMETER4FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramLocalParameter4fARB"); - glProgramLocalParameter4fvARB = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramLocalParameter4fvARB"); - glGetProgramEnvParameterdvARB = (PFNGLGETPROGRAMENVPARAMETERDVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetProgramEnvParameterdvARB"); - glGetProgramEnvParameterfvARB = (PFNGLGETPROGRAMENVPARAMETERFVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetProgramEnvParameterfvARB"); - glGetProgramLocalParameterdvARB = (PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetProgramLocalParameterdvARB"); - glGetProgramLocalParameterfvARB = (PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetProgramLocalParameterfvARB"); - glGetProgramivARB = (PFNGLGETPROGRAMIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetProgramivARB"); - glGetProgramStringARB = (PFNGLGETPROGRAMSTRINGARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetProgramStringARB"); - glGetVertexAttribdvARB = (PFNGLGETVERTEXATTRIBDVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribdvARB"); - glGetVertexAttribfvARB = (PFNGLGETVERTEXATTRIBFVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribfvARB"); - glGetVertexAttribivARB = (PFNGLGETVERTEXATTRIBIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribivARB"); - glGetVertexAttribPointervARB = (PFNGLGETVERTEXATTRIBPOINTERVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glgetVertexAttribPointervARB"); - glIsProgramARB = (PFNGLISPROGRAMARBPROC) GLH_EXT_GET_PROC_ADDRESS("glIsProgramARB"); + LL_INFOS() << "initExtensions() VertexShader-related procs..." << LL_ENDL; + glGetAttribLocationARB = (PFNGLGETATTRIBLOCATIONARBPROC) GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glGetAttribLocation"); + glBindAttribLocationARB = (PFNGLBINDATTRIBLOCATIONARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glBindAttribLocation"); + glGetActiveAttribARB = (PFNGLGETACTIVEATTRIBARBPROC) GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glGetActiveAttrib"); + glVertexAttrib1dARB = (PFNGLVERTEXATTRIB1DARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glVertexAttrib1d"); + glVertexAttrib1dvARB = (PFNGLVERTEXATTRIB1DVARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glVertexAttrib1dv"); + glVertexAttrib1fARB = (PFNGLVERTEXATTRIB1FARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glVertexAttrib1f"); + glVertexAttrib1fvARB = (PFNGLVERTEXATTRIB1FVARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glVertexAttrib1fv"); + glVertexAttrib1sARB = (PFNGLVERTEXATTRIB1SARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glVertexAttrib1s"); + glVertexAttrib1svARB = (PFNGLVERTEXATTRIB1SVARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glVertexAttrib1sv"); + glVertexAttrib2dARB = (PFNGLVERTEXATTRIB2DARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glVertexAttrib2d"); + glVertexAttrib2dvARB = (PFNGLVERTEXATTRIB2DVARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glVertexAttrib2dv"); + glVertexAttrib2fARB = (PFNGLVERTEXATTRIB2FARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glVertexAttrib2f"); + glVertexAttrib2fvARB = (PFNGLVERTEXATTRIB2FVARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glVertexAttrib2fv"); + glVertexAttrib2sARB = (PFNGLVERTEXATTRIB2SARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glVertexAttrib2s"); + glVertexAttrib2svARB = (PFNGLVERTEXATTRIB2SVARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glVertexAttrib2sv"); + glVertexAttrib3dARB = (PFNGLVERTEXATTRIB3DARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glVertexAttrib3d"); + glVertexAttrib3dvARB = (PFNGLVERTEXATTRIB3DVARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glVertexAttrib3dv"); + glVertexAttrib3fARB = (PFNGLVERTEXATTRIB3FARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glVertexAttrib3f"); + glVertexAttrib3fvARB = (PFNGLVERTEXATTRIB3FVARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glVertexAttrib3fv"); + glVertexAttrib3sARB = (PFNGLVERTEXATTRIB3SARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glVertexAttrib3s"); + glVertexAttrib3svARB = (PFNGLVERTEXATTRIB3SVARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glVertexAttrib3sv"); + glVertexAttrib4NbvARB = (PFNGLVERTEXATTRIB4NBVARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glVertexAttrib4Nbv"); + glVertexAttrib4NivARB = (PFNGLVERTEXATTRIB4NIVARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glVertexAttrib4Niv"); + glVertexAttrib4NsvARB = (PFNGLVERTEXATTRIB4NSVARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glVertexAttrib4Nsv"); + glVertexAttrib4NubARB = (PFNGLVERTEXATTRIB4NUBARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glVertexAttrib4Nub"); + glVertexAttrib4NubvARB = (PFNGLVERTEXATTRIB4NUBVARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glVertexAttrib4Nubv"); + glVertexAttrib4NuivARB = (PFNGLVERTEXATTRIB4NUIVARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glVertexAttrib4Nuiv"); + glVertexAttrib4NusvARB = (PFNGLVERTEXATTRIB4NUSVARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glVertexAttrib4Nusv"); + glVertexAttrib4bvARB = (PFNGLVERTEXATTRIB4BVARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glVertexAttrib4bv"); + glVertexAttrib4dARB = (PFNGLVERTEXATTRIB4DARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glVertexAttrib4d"); + glVertexAttrib4dvARB = (PFNGLVERTEXATTRIB4DVARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glVertexAttrib4dv"); + glVertexAttrib4fARB = (PFNGLVERTEXATTRIB4FARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glVertexAttrib4f"); + glVertexAttrib4fvARB = (PFNGLVERTEXATTRIB4FVARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glVertexAttrib4fv"); + glVertexAttrib4ivARB = (PFNGLVERTEXATTRIB4IVARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glVertexAttrib4iv"); + glVertexAttrib4sARB = (PFNGLVERTEXATTRIB4SARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glVertexAttrib4s"); + glVertexAttrib4svARB = (PFNGLVERTEXATTRIB4SVARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glVertexAttrib4sv"); + glVertexAttrib4ubvARB = (PFNGLVERTEXATTRIB4UBVARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glVertexAttrib4ubv"); + glVertexAttrib4uivARB = (PFNGLVERTEXATTRIB4UIVARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glVertexAttrib4uiv"); + glVertexAttrib4usvARB = (PFNGLVERTEXATTRIB4USVARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glVertexAttrib4usv"); + glVertexAttribPointerARB = (PFNGLVERTEXATTRIBPOINTERARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glVertexAttribPointer"); + glVertexAttribIPointer = (PFNGLVERTEXATTRIBIPOINTERPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(3.0, "glVertexAttribIPointer"); + glEnableVertexAttribArrayARB = (PFNGLENABLEVERTEXATTRIBARRAYARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glEnableVertexAttribArray"); + glDisableVertexAttribArrayARB = (PFNGLDISABLEVERTEXATTRIBARRAYARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glDisableVertexAttribArray"); + glGetVertexAttribdvARB = (PFNGLGETVERTEXATTRIBDVARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glGetVertexAttribdv"); + glGetVertexAttribfvARB = (PFNGLGETVERTEXATTRIBFVARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glGetVertexAttribfv"); + glGetVertexAttribivARB = (PFNGLGETVERTEXATTRIBIVARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glGetVertexAttribiv"); + glGetVertexAttribPointervARB = (PFNGLGETVERTEXATTRIBPOINTERVARBPROC)GLH_EXT_GET_PROC_ADDRESS_CORE(2.0, "glGetVertexAttribPointerv"); } LL_DEBUGS("RenderInit") << "GL Probe: Got symbols" << LL_ENDL; #endif @@ -1346,6 +1565,35 @@ void flush_glerror() glGetError(); } +const std::string getGLErrorString(GLenum error) +{ + switch(error) + { + case GL_NO_ERROR: + return "No Error"; + case GL_INVALID_ENUM: + return "Invalid Enum"; + case GL_INVALID_VALUE: + return "Invalid Value"; + case GL_INVALID_OPERATION: + return "Invalid Operation"; + case GL_INVALID_FRAMEBUFFER_OPERATION: + return "Invalid Framebuffer Operation"; + case GL_OUT_OF_MEMORY: + return "Out of Memory"; + case GL_STACK_UNDERFLOW: + return "Stack Underflow"; + case GL_STACK_OVERFLOW: + return "Stack Overflow"; +#ifdef GL_TABLE_TOO_LARGE + case GL_TABLE_TOO_LARGE: + return "Table too large"; +#endif + default: + return "UNKNOWN ERROR"; + } +} + //this function outputs gl error to the log file, does not crash the code. void log_glerror() { @@ -1358,17 +1606,8 @@ void log_glerror() error = glGetError(); while (LL_UNLIKELY(error)) { - GLubyte const * gl_error_msg = gluErrorString(error); - if (NULL != gl_error_msg) - { - llwarns << "GL Error: " << error << " GL Error String: " << gl_error_msg << llendl ; - } - else - { - // gluErrorString returns NULL for some extensions' error codes. - // you'll probably have to grep for the number in glext.h. - llwarns << "GL Error: UNKNOWN 0x" << std::hex << error << std::dec << llendl; - } + std::string gl_error_msg = getGLErrorString(error); + LL_WARNS() << "GL Error: 0x" << std::hex << error << std::dec << " GL Error String: " << gl_error_msg << LL_ENDL; error = glGetError(); } } @@ -1382,27 +1621,13 @@ void do_assert_glerror() while (LL_UNLIKELY(error)) { quit = TRUE; - GLubyte const * gl_error_msg = gluErrorString(error); - if (NULL != gl_error_msg) - { - LL_WARNS("RenderState") << "GL Error:" << error<< LL_ENDL; - LL_WARNS("RenderState") << "GL Error String:" << gl_error_msg << LL_ENDL; - - if (gDebugSession) - { - gFailLog << "GL Error:" << gl_error_msg << std::endl; - } - } - else + + std::string gl_error_msg = getGLErrorString(error); + LL_WARNS("RenderState") << "GL Error: 0x" << std::hex << error << std::dec << LL_ENDL; + LL_WARNS("RenderState") << "GL Error String: " << gl_error_msg << LL_ENDL; + if (gDebugSession) { - // gluErrorString returns NULL for some extensions' error codes. - // you'll probably have to grep for the number in glext.h. - LL_WARNS("RenderState") << "GL Error: UNKNOWN 0x" << std::hex << error << std::dec << LL_ENDL; - - if (gDebugSession) - { - gFailLog << "GL Error: UNKNOWN 0x" << std::hex << error << std::dec << std::endl; - } + gFailLog << "GL Error: 0x" << std::hex << error << std::dec << " GL Error String: " << gl_error_msg << std::endl; } error = glGetError(); } @@ -1415,26 +1640,36 @@ void do_assert_glerror() } else { - llerrs << "One or more unhandled GL errors." << llendl; + LL_ERRS() << "One or more unhandled GL errors." << LL_ENDL; } } } void assert_glerror() { - if (gNoRender) + if(!gNoRender) + {} + else + { return; + } if (!gGLActive) { - //llwarns << "GL used while not active!" << llendl; - - if (gDebugSession) + //LL_WARNS() << "GL used while not active!" << LL_ENDL; + + if (!gDebugSession) + {} + else { //ll_fail("GL used while not active"); } } - if (gDebugGL) + if (!gDebugGL) + { + //funny looking if for branch prediction -- gDebugGL is almost always false and assert_glerror is called often + } + else { do_assert_glerror(); } @@ -1453,33 +1688,49 @@ void clear_glerror() // // Static members -boost::unordered_map LLGLState::sStateMap; +std::vector LLGLStateValidator::sStateDataVec; GLboolean LLGLDepthTest::sDepthEnabled = GL_FALSE; // OpenGL default GLenum LLGLDepthTest::sDepthFunc = GL_LESS; // OpenGL default GLboolean LLGLDepthTest::sWriteEnabled = GL_TRUE; // OpenGL default //static -void LLGLState::initClass() +void LLGLStateValidator::initClass() { - sStateMap[GL_DITHER] = GL_TRUE; - // sStateMap[GL_TEXTURE_2D] = GL_TRUE; - + stop_glerror(); + + gGL.setSceneBlendType(LLRender::BT_ALPHA); //make sure multisample defaults to disabled - sStateMap[GL_MULTISAMPLE_ARB] = GL_FALSE; glDisable(GL_MULTISAMPLE_ARB); + stop_glerror(); + for (auto data : sStateDataVec) + { + llassert_always(data->depth == 0); + llassert_always(data->activeInstance == nullptr); + if (data->disabler && *data->disabler) + { + continue; + } + const char* stateStr = data->stateStr; + LLGLenum state = data->state; + LLGLboolean cur_state = data->currentState; + llassert_always_msg(cur_state == glIsEnabled(state), llformat("%s expected %s", stateStr, cur_state ? "TRUE" : "FALSE")); + } + const bool old = gDebugGL; + gDebugGL = true; + checkStates(); + gDebugGL = old; } //static -void LLGLState::restoreGL() +void LLGLStateValidator::restoreGL() { - sStateMap.clear(); initClass(); } //static // Really shouldn't be needed, but seems we sometimes do. -void LLGLState::resetTextureStates() +void LLGLStateValidator::resetTextureStates() { gGL.flush(); GLint maxTextureUnits; @@ -1493,35 +1744,60 @@ void LLGLState::resetTextureStates() } } -void LLGLState::dumpStates() +void LLGLStateValidator::dumpStates() { LL_INFOS("RenderState") << "GL States:" << LL_ENDL; - for (boost::unordered_map::iterator iter = sStateMap.begin(); - iter != sStateMap.end(); ++iter) + for (auto data : sStateDataVec) { - LL_INFOS("RenderState") << llformat(" 0x%04x : %s",(S32)iter->first,iter->second?"TRUE":"FALSE") << LL_ENDL; + LL_INFOS("RenderState") << llformat("%s : %s", data->stateStr, data->currentState ? "TRUE" : "FALSE") << LL_ENDL; } } -void LLGLState::checkStates(const std::string& msg) +void LLGLStateValidator::checkState(LLGLStateStaticData& data) { - if (!gDebugGL) + if (gDebugGL) + { + if (data.disabler && *data.disabler) + { + return; + } + if (!gDebugSession) + { + llassert_always(data.currentState == (bool)glIsEnabled(data.state)); + } + else + { + if (data.currentState != (bool)glIsEnabled(data.state)) + { + ll_fail(llformat("GL enabled state for %s does not match expected state of %s.", data.stateStr, data.currentState ? "TRUE" : "FALSE")); + } + } + } +} + +bool LLGLStateValidator::registerStateData(LLGLStateStaticData& data) +{ + sStateDataVec.emplace_back(&data); + return true; +} + +void LLGLStateValidator::checkStates(const std::string& msg) +{ + if (!gDebugGL || gGLManager.mIsDisabled) { return; } stop_glerror(); - GLint src; - GLint dst; - glGetIntegerv(GL_BLEND_SRC, &src); - glGetIntegerv(GL_BLEND_DST, &dst); + GLint src = gGL.getContextSnapshot().blendColorSFactor; + GLint dst = gGL.getContextSnapshot().blendColorDFactor; stop_glerror(); BOOL error = FALSE; - if (src != GL_SRC_ALPHA || dst != GL_ONE_MINUS_SRC_ALPHA) + if (src != LLRender::BF_SOURCE_ALPHA || dst != LLRender::BF_ONE_MINUS_SOURCE_ALPHA) { if (gDebugSession) { @@ -1534,11 +1810,15 @@ void LLGLState::checkStates(const std::string& msg) } } - for (boost::unordered_map::iterator iter = sStateMap.begin(); - iter != sStateMap.end(); ++iter) + for (auto data : sStateDataVec) { - LLGLenum state = iter->first; - LLGLboolean cur_state = iter->second; + if (data->disabler && *data->disabler) + { + continue; + } + const char* stateStr = data->stateStr; + LLGLenum state = data->state; + LLGLboolean cur_state = data->currentState; stop_glerror(); LLGLboolean gl_state = glIsEnabled(state); stop_glerror(); @@ -1547,24 +1827,24 @@ void LLGLState::checkStates(const std::string& msg) dumpStates(); if (gDebugSession) { - gFailLog << llformat("LLGLState error. State: 0x%04x",state) << std::endl; + gFailLog << llformat("LLGLState error. State: %s 0x%04x. Expected %s", stateStr, state, cur_state ? "TRUE" : "FALSE") << std::endl; error = TRUE; } else { - LL_GL_ERRS << llformat("LLGLState error. State: 0x%04x",state) << LL_ENDL; + LL_GL_ERRS << llformat("LLGLState error. State: %s 0x%04x. Expected %s", stateStr, state, cur_state ? "TRUE" : "FALSE") << LL_ENDL; } } } if (error) { - ll_fail("LLGLState::checkStates failed."); + ll_fail("LLGLStateValidator::checkStates failed."); } stop_glerror(); } -void LLGLState::checkTextureChannels(const std::string& msg) +void LLGLStateValidator::checkTextureChannels(const std::string& msg) { #if 0 if (!gDebugGL) @@ -1626,10 +1906,6 @@ void LLGLState::checkTextureChannels(const std::string& msg) GLint stackDepth = 0; - glh::matrix4f mat; - glh::matrix4f identity; - identity.identity(); - for (GLint i = 1; i < gGLManager.mNumTextureUnits; i++) { gGL.getTexUnit(i)->activate(); @@ -1649,10 +1925,11 @@ void LLGLState::checkTextureChannels(const std::string& msg) } } - glGetFloatv(GL_TEXTURE_MATRIX, (GLfloat*) mat.m); + LLMatrix4a mat; + glGetFloatv(GL_TEXTURE_MATRIX, (GLfloat*) mat.mMatrix); stop_glerror(); - if (mat != identity) + if (!mat.isIdentity()) { error = TRUE; LL_WARNS("RenderState") << "Texture matrix in channel " << i << " corrupt." << LL_ENDL; @@ -1664,7 +1941,7 @@ void LLGLState::checkTextureChannels(const std::string& msg) for (S32 j = (i == 0 ? 1 : 0); - j < (gGLManager.mHasTextureRectangle ? 9 : 8); j++) + j < 8; j++) { if (glIsEnabled(value[j])) { @@ -1700,7 +1977,7 @@ void LLGLState::checkTextureChannels(const std::string& msg) if (tex != 0) { error = TRUE; - LL_WARNS("RenderState") << "Texture channel " << i << " still has texture " << tex << " bound." << llendl; + LL_WARNS("RenderState") << "Texture channel " << i << " still has texture " << tex << " bound." << LL_ENDL; if (gDebugSession) { @@ -1719,7 +1996,7 @@ void LLGLState::checkTextureChannels(const std::string& msg) { if (gDebugSession) { - ll_fail("LLGLState::checkTextureChannels failed."); + ll_fail("LLGLStateValidator::checkTextureChannels failed."); } else { @@ -1729,7 +2006,7 @@ void LLGLState::checkTextureChannels(const std::string& msg) #endif } -void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask) +void LLGLStateValidator::checkClientArrays(const std::string& msg, U32 data_mask) { if (!gDebugGL || LLGLSLShader::sNoFixedFunction) { @@ -1744,7 +2021,7 @@ void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask) if (active_texture != GL_TEXTURE0_ARB) { - llwarns << "Client active texture corrupted: " << active_texture << llendl; + LL_WARNS() << "Client active texture corrupted: " << active_texture << LL_ENDL; if (gDebugSession) { gFailLog << "Client active texture corrupted: " << active_texture << std::endl; @@ -1755,7 +2032,7 @@ void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask) /*glGetIntegerv(GL_ACTIVE_TEXTURE_ARB, &active_texture); if (active_texture != GL_TEXTURE0_ARB) { - llwarns << "Active texture corrupted: " << active_texture << llendl; + LL_WARNS() << "Active texture corrupted: " << active_texture << LL_ENDL; if (gDebugSession) { gFailLog << "Active texture corrupted: " << active_texture << std::endl; @@ -1895,7 +2172,7 @@ void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask) { if (gDebugSession) { - ll_fail("LLGLState::checkClientArrays failed."); + ll_fail("LLGLStateValidator::checkClientArrays failed."); } else { @@ -1906,108 +2183,36 @@ void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask) /////////////////////////////////////////////////////////////////////// -LLGLState::LLGLState(LLGLenum state, S32 enabled) : - mState(state), mWasEnabled(FALSE), mIsEnabled(FALSE) -{ - if (LLGLSLShader::sNoFixedFunction) - { //always ignore state that's deprecated post GL 3.0 - switch (state) - { - case GL_ALPHA_TEST: - case GL_NORMALIZE: - case GL_TEXTURE_GEN_R: - case GL_TEXTURE_GEN_S: - case GL_TEXTURE_GEN_T: - case GL_TEXTURE_GEN_Q: - case GL_LIGHTING: - case GL_COLOR_MATERIAL: - case GL_FOG: - case GL_LINE_STIPPLE: - case GL_POLYGON_STIPPLE: - mState = 0; - break; - } - } - - stop_glerror(); - if (mState) - { - mWasEnabled = sStateMap[state]; - llassert(mWasEnabled == glIsEnabled(state)); - setEnabled(enabled); - stop_glerror(); - } -} - -void LLGLState::setEnabled(S32 enabled) -{ - if (!mState) - { - return; - } - if (enabled == CURRENT_STATE) - { - enabled = sStateMap[mState] == GL_TRUE ? TRUE : FALSE; - } - else if (enabled == TRUE && sStateMap[mState] != GL_TRUE) - { - gGL.flush(); - glEnable(mState); - sStateMap[mState] = GL_TRUE; - } - else if (enabled == FALSE && sStateMap[mState] != GL_FALSE) - { - gGL.flush(); - glDisable(mState); - sStateMap[mState] = GL_FALSE; - } - mIsEnabled = enabled; -} - -LLGLState::~LLGLState() -{ - stop_glerror(); - if (mState) - { - if (gDebugGL) - { - if (!gDebugSession) - { - llassert_always(sStateMap[mState] == glIsEnabled(mState)); - } - else - { - if (sStateMap[mState] != glIsEnabled(mState)) - { - ll_fail("GL enabled state does not match expected"); - } - } - } - - if (mIsEnabled != mWasEnabled) - { - gGL.flush(); - if (mWasEnabled) - { - glEnable(mState); - sStateMap[mState] = GL_TRUE; - } - else - { - glDisable(mState); - sStateMap[mState] = GL_FALSE; - } - } - } - stop_glerror(); -} - //////////////////////////////////////////////////////////////////////////////// +initLLGLState(GL_BLEND, false, nullptr); +initLLGLState(GL_CLIP_PLANE0, false, nullptr); +initLLGLState(GL_CULL_FACE, false, nullptr); +initLLGLState(GL_DEPTH_CLAMP, false, nullptr); +initLLGLState(GL_DITHER, true, nullptr); +initLLGLState(GL_LINE_SMOOTH, false, nullptr); +initLLGLState(GL_MULTISAMPLE_ARB, false, nullptr); +initLLGLState(GL_POLYGON_OFFSET_FILL, false, nullptr); +initLLGLState(GL_POLYGON_OFFSET_LINE, false, nullptr); +initLLGLState(GL_POLYGON_SMOOTH, false, nullptr); +initLLGLState(GL_SCISSOR_TEST, false, nullptr); +initLLGLState(GL_STENCIL_TEST, false, nullptr); +initLLGLState(GL_ALPHA_TEST, false, &LLGLSLShader::sNoFixedFunction); +initLLGLState(GL_COLOR_MATERIAL, false, &LLGLSLShader::sNoFixedFunction); +initLLGLState(GL_FOG, false, &LLGLSLShader::sNoFixedFunction); +initLLGLState(GL_LINE_STIPPLE, false, &LLGLSLShader::sNoFixedFunction); +initLLGLState(GL_LIGHTING, false, &LLGLSLShader::sNoFixedFunction); +initLLGLState(GL_NORMALIZE, false, &LLGLSLShader::sNoFixedFunction); +initLLGLState(GL_POLYGON_STIPPLE, false, &LLGLSLShader::sNoFixedFunction); +initLLGLState(GL_TEXTURE_GEN_Q, false, &LLGLSLShader::sNoFixedFunction); +initLLGLState(GL_TEXTURE_GEN_R, false, &LLGLSLShader::sNoFixedFunction); +initLLGLState(GL_TEXTURE_GEN_S, false, &LLGLSLShader::sNoFixedFunction); +initLLGLState(GL_TEXTURE_GEN_T, false, &LLGLSLShader::sNoFixedFunction); + void LLGLManager::initGLStates() { //gl states moved to classes in llglstates.h - LLGLState::initClass(); + LLGLStateValidator::initClass(); } //////////////////////////////////////////////////////////////////////////////// @@ -2143,7 +2348,7 @@ void parse_glsl_version(S32& major, S32& minor) LLStringUtil::convertToS32(minor_str, minor); } -LLGLUserClipPlane::LLGLUserClipPlane(const LLPlane& p, const glh::matrix4f& modelview, const glh::matrix4f& projection, bool apply) +LLGLUserClipPlane::LLGLUserClipPlane(const LLPlane& p, const LLMatrix4a& modelview, const LLMatrix4a& projection, bool apply) { mApply = apply; @@ -2158,27 +2363,42 @@ LLGLUserClipPlane::LLGLUserClipPlane(const LLPlane& p, const glh::matrix4f& mode void LLGLUserClipPlane::setPlane(F32 a, F32 b, F32 c, F32 d) { - glh::matrix4f& P = mProjection; - glh::matrix4f& M = mModelview; - - glh::matrix4f invtrans_MVP = (P * M).inverse().transpose(); - glh::vec4f oplane(a,b,c,d); - glh::vec4f cplane; - invtrans_MVP.mult_matrix_vec(oplane, cplane); - - cplane /= fabs(cplane[2]); // normalize such that depth is not scaled - cplane[3] -= 1; - - if(cplane[2] < 0) - cplane *= -1; - - glh::matrix4f suffix; - suffix.set_row(2, cplane); - glh::matrix4f newP = suffix * P; + LLMatrix4a& P = mProjection; + LLMatrix4a& M = mModelview; + + LLMatrix4a invtrans_MVP; + invtrans_MVP.setMul(P,M); + invtrans_MVP.invert(); + invtrans_MVP.transpose(); + + LLVector4a oplane(a,b,c,d); + LLVector4a cplane; + LLVector4a cplane_splat; + LLVector4a cplane_neg; + + invtrans_MVP.rotate4(oplane,cplane); + + cplane_splat.splat<2>(cplane); + cplane_splat.setAbs(cplane_splat); + cplane.div(cplane_splat); + cplane.sub(LLVector4a(0.f,0.f,0.f,1.f)); + + cplane_splat.splat<2>(cplane); + cplane_neg = cplane; + cplane_neg.negate(); + + cplane.setSelectWithMask( cplane_splat.lessThan( _mm_setzero_ps() ), cplane_neg, cplane ); + + LLMatrix4a suffix; + suffix.setIdentity(); + suffix.setColumn<2>(cplane); + LLMatrix4a newP; + newP.setMul(suffix,P); + gGL.matrixMode(LLRender::MM_PROJECTION); gGL.pushMatrix(); - gGL.loadMatrix(newP.m); - gGLObliqueProjectionInverse = LLMatrix4(newP.inverse().transpose().m); + gGL.loadMatrix(newP); + //gGLObliqueProjectionInverse = LLMatrix4(newP.inverse().transpose().m); gGL.matrixMode(LLRender::MM_MODELVIEW); } @@ -2252,11 +2472,11 @@ void LLGLNamePool::release(GLuint name) } else { - llerrs << "Attempted to release a pooled name that is not in use!" << llendl; + LL_ERRS() << "Attempted to release a pooled name that is not in use!" << LL_ENDL; } } } - llerrs << "Attempted to release a non pooled name!" << llendl; + LL_ERRS() << "Attempted to release a non pooled name!" << LL_ENDL; #else releaseName(name); #endif @@ -2265,7 +2485,7 @@ void LLGLNamePool::release(GLuint name) //static void LLGLNamePool::upkeepPools() { - for (tracker_t::instance_iter iter = beginInstances(); iter != endInstances(); ++iter) + for (tracker_t::instance_iter iter = beginInstances(), iter_end = endInstances(); iter != iter_end; ++iter) { LLGLNamePool & pool = *iter; pool.upkeep(); @@ -2275,7 +2495,7 @@ void LLGLNamePool::upkeepPools() //static void LLGLNamePool::cleanupPools() { - for (tracker_t::instance_iter iter = beginInstances(); iter != endInstances(); ++iter) + for (tracker_t::instance_iter iter = beginInstances(), iter_end = endInstances(); iter != iter_end; ++iter) { LLGLNamePool & pool = *iter; pool.cleanup(); @@ -2367,19 +2587,18 @@ void LLGLDepthTest::checkState() } } -LLGLSquashToFarClip::LLGLSquashToFarClip(glh::matrix4f P, U32 layer) +LLGLSquashToFarClip::LLGLSquashToFarClip(const LLMatrix4a& P_in, U32 layer) { - + LLMatrix4a P = P_in; F32 depth = 0.99999f - 0.0001f * layer; - for (U32 i = 0; i < 4; i++) - { - P.element(2, i) = P.element(3, i) * depth; - } + LLVector4a col = P.getColumn<3>(); + col.mul(depth); + P.setColumn<2>(col); gGL.matrixMode(LLRender::MM_PROJECTION); gGL.pushMatrix(); - gGL.loadMatrix(P.m); + gGL.loadMatrix(P); gGL.matrixMode(LLRender::MM_MODELVIEW); } diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h index de4a81bb5b..39b7a70ebe 100644 --- a/indra/llrender/llgl.h +++ b/indra/llrender/llgl.h @@ -30,7 +30,7 @@ // This file contains various stuff for handling gl extensions and other gl related stuff. #include -#include +#include #include #include "llerror.h" @@ -38,12 +38,13 @@ #include "llstring.h" #include "stdtypes.h" #include "v4math.h" +#include "llmatrix4a.h" #include "llplane.h" #include "llgltypes.h" +#include "llrender.h" #include "llinstancetracker.h" #include "llglheaders.h" -#include "glh/glh_linear.h" extern BOOL gDebugGL; extern BOOL gDebugSession; @@ -93,7 +94,6 @@ class LLGLManager BOOL mHasSync; BOOL mHasMapBufferRange; BOOL mHasFlushBufferRange; - BOOL mHasPBuffer; BOOL mHasShaderObjects; BOOL mHasVertexShader; BOOL mHasFragmentShader; @@ -103,7 +103,6 @@ class LLGLManager BOOL mHasPointParameters; BOOL mHasDrawBuffers; BOOL mHasDepthClamp; - BOOL mHasTextureRectangle; BOOL mHasTransformFeedback; S32 mMaxIntegerSamples; @@ -112,22 +111,32 @@ class LLGLManager BOOL mHasARBEnvCombine; BOOL mHasCubeMap; BOOL mHasDebugOutput; + BOOL mHasGpuShader5; + BOOL mHasAdaptiveVsync; + BOOL mHasTextureSwizzle; + + bool mHasTextureCompression; // Vendor-specific extensions BOOL mIsATI; BOOL mIsNVIDIA; BOOL mIsIntel; + BOOL mIsHD3K; BOOL mIsGF2or4MX; BOOL mIsGF3; BOOL mIsGFFX; BOOL mATIOffsetVerticalLines; BOOL mATIOldDriver; +#if LL_DARWIN + // Needed to distinguish problem cards on older Macs that break with Materials + BOOL mIsMobileGF; +#endif + // Whether this version of GL is good enough for SL to use BOOL mHasRequirements; // Misc extensions - BOOL mHasSeparateSpecularColor; //whether this GPU is in the debug list. BOOL mDebugGPU; @@ -144,6 +153,8 @@ class LLGLManager S32 mVRAM; // VRAM in MB S32 mGLMaxVertexRange; S32 mGLMaxIndexRange; + + S32 mGLMaxVertexUniformComponents; void getPixelFormat(); // Get the best pixel format @@ -216,13 +227,13 @@ void clear_glerror(); //disable lighting for rendering hud objects //INCORRECT USAGE - LLGLEnable lighting(GL_LIGHTING); + LLGLEnable lighting; renderHUD(); - LLGLDisable lighting(GL_LIGHTING); + LLGLDisable lighting; //CORRECT USAGE { - LLGLEnable lighting(GL_LIGHTING); + LLGLEnable lighting; renderHUD(); } @@ -230,12 +241,10 @@ void clear_glerror(); is useful: { - LLGLEnable lighting(light_hud ? GL_LIGHTING : 0); + LLGLEnable lighting(light_hud); renderHUD(); } - A LLGLState initialized with a parameter of 0 does nothing. - LLGLState works by maintaining a map of the current GL states, and ignoring redundant enables/disables. If a redundant call is attempted, it becomes a noop, otherwise, it is set in the constructor and reset in the destructor. @@ -244,59 +253,131 @@ void clear_glerror(); if the existing GL state does not match the expected GL state. */ -class LLGLState + +struct LLGLStateStaticData { -public: - static void initClass(); - static void restoreGL(); + const char* stateStr; + LLGLenum state; + bool currentState; + U32 depth; + char* activeInstance; + bool* disabler; +}; +class LLGLStateValidator { +public: static void resetTextureStates(); static void dumpStates(); static void checkStates(const std::string& msg = ""); static void checkTextureChannels(const std::string& msg = ""); static void checkClientArrays(const std::string& msg = "", U32 data_mask = 0); - -protected: - static boost::unordered_map sStateMap; - + static void checkState(LLGLStateStaticData& data); + static void initClass(); + static void restoreGL(); + static bool registerStateData(LLGLStateStaticData& data); +private: + static std::vector sStateDataVec; +}; + +class LLGLStateIface { public: enum { CURRENT_STATE = -2 }; - LLGLState(LLGLenum state, S32 enabled = CURRENT_STATE); - ~LLGLState(); - void setEnabled(S32 enabled); - void enable() { setEnabled(TRUE); } - void disable() { setEnabled(FALSE); } -protected: - LLGLenum mState; - BOOL mWasEnabled; - BOOL mIsEnabled; + virtual ~LLGLStateIface() {} + virtual void enable() = 0; + virtual void disable() = 0; }; -// New LLGLState class wrappers that don't depend on actual GL flags. -class LLGLEnableBlending : public LLGLState +template +class LLGLState : public LLGLStateIface { public: - LLGLEnableBlending(bool enable); + + LLGLState(S8 newState = CURRENT_STATE) + { + ++staticData.depth; + mPriorInstance = staticData.activeInstance; + staticData.activeInstance = (char*)this; + mPriorState = staticData.currentState; + setEnabled(newState); + } + virtual ~LLGLState() + { + llassert_always(staticData.activeInstance == (char*)this); + if (staticData.depth != 0) + { + staticData.activeInstance = mPriorInstance; + --staticData.depth; + if (gDebugGL) { + LLGLStateValidator::checkState(staticData); + } + setState(mPriorState); + } + else + { + llassert_always(mPriorInstance == nullptr); + } + } + + virtual void enable() { setEnabled(true); } + virtual void disable() { setEnabled(false); } + + static LLGLStateStaticData staticData; + // Getter + static bool isEnabled() { return staticData.currentState && (!staticData.disabler || !*staticData.disabler); } + // For assertions. If feature is on or unsupported, return true. + static bool checkEnabled() { return (!staticData.disabler || !*staticData.disabler) ? staticData.currentState : true; } + // For assertions. If feature is off or unsupported, return true. + static bool checkDisabled() { return (!staticData.disabler || !*staticData.disabler) ? !staticData.currentState : true; } +private: + char *mPriorInstance; + bool mPriorState; + + void setEnabled(S32 newState) + { + llassert_always(staticData.activeInstance == (char*)this); + bool enabled = newState == CURRENT_STATE ? staticData.currentState : !!newState; + setState(enabled); + } + + static void setState(bool enabled) + { + if (staticData.currentState != enabled && (!staticData.disabler || !*staticData.disabler)) + { + gGL.flush(); + staticData.currentState = enabled; + staticData.currentState ? glEnable(state) : glDisable(state); + } + } }; +#define initLLGLState(state, value, disabler_ptr) \ + template <> \ + LLGLStateStaticData LLGLState::staticData = {#state, state, value, 0, nullptr, disabler_ptr}; \ + bool registered_##state = LLGLStateValidator::registerStateData(LLGLState::staticData); -class LLGLEnableAlphaReject : public LLGLState +template <> +class LLGLState<0> : public LLGLStateIface { -public: - LLGLEnableAlphaReject(bool enable); + LLGLState(S8 newState = CURRENT_STATE) { } + virtual ~LLGLState() { } + virtual void enable() { } + virtual void disable() { } + static bool isEnabled() { return false; } + // For assertions. If feature is on or unsupported, return true. + static bool checkEnabled() { return true; } + // For assertions. If feature is off or unsupported, return true. + static bool checkDisabled() { return true; } }; -/// TODO: Being deprecated. -class LLGLEnable : public LLGLState +template +struct LLGLEnable : public LLGLState { -public: - LLGLEnable(LLGLenum state) : LLGLState(state, TRUE) {} + LLGLEnable(bool noskip = true) : LLGLState(noskip ? TRUE : LLGLState::CURRENT_STATE) {} }; -/// TODO: Being deprecated. -class LLGLDisable : public LLGLState +template +struct LLGLDisable : public LLGLState { -public: - LLGLDisable(LLGLenum state) : LLGLState(state, FALSE) {} + LLGLDisable(bool noskip = true) : LLGLState(noskip ? FALSE : LLGLState::CURRENT_STATE) {} }; /* @@ -311,21 +392,23 @@ class LLGLDisable : public LLGLState Does not stack. Caches inverse of projection matrix used in gGLObliqueProjectionInverse */ +LL_ALIGN_PREFIX(16) class LLGLUserClipPlane { public: - LLGLUserClipPlane(const LLPlane& plane, const glh::matrix4f& modelview, const glh::matrix4f& projection, bool apply = true); + LLGLUserClipPlane(const LLPlane& plane, const LLMatrix4a& modelview, const LLMatrix4a& projection, bool apply = true); ~LLGLUserClipPlane(); void setPlane(F32 a, F32 b, F32 c, F32 d); private: - bool mApply; - glh::matrix4f mProjection; - glh::matrix4f mModelview; -}; + LL_ALIGN_16(LLMatrix4a mProjection); + LL_ALIGN_16(LLMatrix4a mModelview); + + bool mApply; +} LL_ALIGN_POSTFIX(16); /* Modify and load projection matrix to push depth values to far clip plane. @@ -338,7 +421,7 @@ class LLGLUserClipPlane class LLGLSquashToFarClip { public: - LLGLSquashToFarClip(glh::matrix4f projection, U32 layer = 0); + LLGLSquashToFarClip(const LLMatrix4a& projection, U32 layer = 0); ~LLGLSquashToFarClip(); }; @@ -445,12 +528,8 @@ class LLGLSyncFence : public LLGLFence void wait(); }; -extern LLMatrix4 gGLObliqueProjectionInverse; - #include "llglstates.h" -void init_glstates(); - void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor_specific, std::string* version_string ); extern BOOL gClothRipple; diff --git a/indra/llrender/llgldbg.cpp b/indra/llrender/llgldbg.cpp index c54ab18f9b..30101d8a55 100644 --- a/indra/llrender/llgldbg.cpp +++ b/indra/llrender/llgldbg.cpp @@ -118,112 +118,112 @@ void llgl_dump() F32 fv[16]; GLboolean b; - llinfos << "==========================" << llendl; - llinfos << "OpenGL State" << llendl; - llinfos << "==========================" << llendl; + LL_INFOS() << "==========================" << LL_ENDL; + LL_INFOS() << "OpenGL State" << LL_ENDL; + LL_INFOS() << "==========================" << LL_ENDL; - llinfos << "-----------------------------------" << llendl; - llinfos << "Current Values" << llendl; - llinfos << "-----------------------------------" << llendl; + LL_INFOS() << "-----------------------------------" << LL_ENDL; + LL_INFOS() << "Current Values" << LL_ENDL; + LL_INFOS() << "-----------------------------------" << LL_ENDL; glGetFloatv(GL_CURRENT_COLOR, fv); - llinfos << "GL_CURRENT_COLOR : " << fv4(fv) << llendl; + LL_INFOS() << "GL_CURRENT_COLOR : " << fv4(fv) << LL_ENDL; glGetFloatv(GL_CURRENT_NORMAL, fv); - llinfos << "GL_CURRENT_NORMAL : " << fv3(fv) << llendl; + LL_INFOS() << "GL_CURRENT_NORMAL : " << fv3(fv) << LL_ENDL; - llinfos << "-----------------------------------" << llendl; - llinfos << "Lighting" << llendl; - llinfos << "-----------------------------------" << llendl; + LL_INFOS() << "-----------------------------------" << LL_ENDL; + LL_INFOS() << "Lighting" << LL_ENDL; + LL_INFOS() << "-----------------------------------" << LL_ENDL; - llinfos << "GL_LIGHTING : " << boolstr(glIsEnabled(GL_LIGHTING)) << llendl; + LL_INFOS() << "GL_LIGHTING : " << boolstr(glIsEnabled(GL_LIGHTING)) << LL_ENDL; - llinfos << "GL_COLOR_MATERIAL : " << boolstr(glIsEnabled(GL_COLOR_MATERIAL)) << llendl; + LL_INFOS() << "GL_COLOR_MATERIAL : " << boolstr(glIsEnabled(GL_COLOR_MATERIAL)) << LL_ENDL; glGetIntegerv(GL_COLOR_MATERIAL_PARAMETER, (GLint*)&i); - llinfos << "GL_COLOR_MATERIAL_PARAMETER: " << cmstr(i) << llendl; + LL_INFOS() << "GL_COLOR_MATERIAL_PARAMETER: " << cmstr(i) << LL_ENDL; glGetIntegerv(GL_COLOR_MATERIAL_FACE, (GLint*)&i); - llinfos << "GL_COLOR_MATERIAL_FACE : " << facestr(i) << llendl; + LL_INFOS() << "GL_COLOR_MATERIAL_FACE : " << facestr(i) << LL_ENDL; fv[0] = fv[1] = fv[2] = fv[3] = 12345.6789f; glGetMaterialfv(GL_FRONT, GL_AMBIENT, fv); - llinfos << "GL_AMBIENT material : " << fv4(fv) << llendl; + LL_INFOS() << "GL_AMBIENT material : " << fv4(fv) << LL_ENDL; fv[0] = fv[1] = fv[2] = fv[3] = 12345.6789f; glGetMaterialfv(GL_FRONT, GL_DIFFUSE, fv); - llinfos << "GL_DIFFUSE material : " << fv4(fv) << llendl; + LL_INFOS() << "GL_DIFFUSE material : " << fv4(fv) << LL_ENDL; fv[0] = fv[1] = fv[2] = fv[3] = 12345.6789f; glGetMaterialfv(GL_FRONT, GL_SPECULAR, fv); - llinfos << "GL_SPECULAR material : " << fv4(fv) << llendl; + LL_INFOS() << "GL_SPECULAR material : " << fv4(fv) << LL_ENDL; fv[0] = fv[1] = fv[2] = fv[3] = 12345.6789f; glGetMaterialfv(GL_FRONT, GL_EMISSION, fv); - llinfos << "GL_EMISSION material : " << fv4(fv) << llendl; + LL_INFOS() << "GL_EMISSION material : " << fv4(fv) << LL_ENDL; fv[0] = fv[1] = fv[2] = fv[3] = 12345.6789f; glGetMaterialfv(GL_FRONT, GL_SHININESS, fv); - llinfos << "GL_SHININESS material : " << fv1(fv) << llendl; + LL_INFOS() << "GL_SHININESS material : " << fv1(fv) << LL_ENDL; fv[0] = fv[1] = fv[2] = fv[3] = 12345.6789f; glGetFloatv(GL_LIGHT_MODEL_AMBIENT, fv); - llinfos << "GL_LIGHT_MODEL_AMBIENT : " << fv4(fv) << llendl; + LL_INFOS() << "GL_LIGHT_MODEL_AMBIENT : " << fv4(fv) << LL_ENDL; glGetBooleanv(GL_LIGHT_MODEL_LOCAL_VIEWER, &b); - llinfos << "GL_LIGHT_MODEL_LOCAL_VIEWER: " << boolstr(b) << llendl; + LL_INFOS() << "GL_LIGHT_MODEL_LOCAL_VIEWER: " << boolstr(b) << LL_ENDL; glGetBooleanv(GL_LIGHT_MODEL_TWO_SIDE, &b); - llinfos << "GL_LIGHT_MODEL_TWO_SIDE : " << boolstr(b) << llendl; + LL_INFOS() << "GL_LIGHT_MODEL_TWO_SIDE : " << boolstr(b) << LL_ENDL; for (int l=0; l<8; l++) { b = glIsEnabled(GL_LIGHT0+l); - llinfos << "GL_LIGHT" << l << " : " << boolstr(b) << llendl; + LL_INFOS() << "GL_LIGHT" << l << " : " << boolstr(b) << LL_ENDL; if (!b) continue; glGetLightfv(GL_LIGHT0+l, GL_AMBIENT, fv); - llinfos << " GL_AMBIENT light : " << fv4(fv) << llendl; + LL_INFOS() << " GL_AMBIENT light : " << fv4(fv) << LL_ENDL; glGetLightfv(GL_LIGHT0+l, GL_DIFFUSE, fv); - llinfos << " GL_DIFFUSE light : " << fv4(fv) << llendl; + LL_INFOS() << " GL_DIFFUSE light : " << fv4(fv) << LL_ENDL; glGetLightfv(GL_LIGHT0+l, GL_SPECULAR, fv); - llinfos << " GL_SPECULAR light : " << fv4(fv) << llendl; + LL_INFOS() << " GL_SPECULAR light : " << fv4(fv) << LL_ENDL; glGetLightfv(GL_LIGHT0+l, GL_POSITION, fv); - llinfos << " GL_POSITION light : " << fv4(fv) << llendl; + LL_INFOS() << " GL_POSITION light : " << fv4(fv) << LL_ENDL; glGetLightfv(GL_LIGHT0+l, GL_CONSTANT_ATTENUATION, fv); - llinfos << " GL_CONSTANT_ATTENUATION : " << fv1(fv) << llendl; + LL_INFOS() << " GL_CONSTANT_ATTENUATION : " << fv1(fv) << LL_ENDL; glGetLightfv(GL_LIGHT0+l, GL_QUADRATIC_ATTENUATION, fv); - llinfos << " GL_QUADRATIC_ATTENUATION : " << fv1(fv) << llendl; + LL_INFOS() << " GL_QUADRATIC_ATTENUATION : " << fv1(fv) << LL_ENDL; glGetLightfv(GL_LIGHT0+l, GL_SPOT_DIRECTION, fv); - llinfos << " GL_SPOT_DIRECTION : " << fv4(fv) << llendl; + LL_INFOS() << " GL_SPOT_DIRECTION : " << fv4(fv) << LL_ENDL; glGetLightfv(GL_LIGHT0+l, GL_SPOT_EXPONENT, fv); - llinfos << " GL_SPOT_EXPONENT : " << fv1(fv) << llendl; + LL_INFOS() << " GL_SPOT_EXPONENT : " << fv1(fv) << LL_ENDL; glGetLightfv(GL_LIGHT0+l, GL_SPOT_CUTOFF, fv); - llinfos << " GL_SPOT_CUTOFF : " << fv1(fv) << llendl; + LL_INFOS() << " GL_SPOT_CUTOFF : " << fv1(fv) << LL_ENDL; } - llinfos << "-----------------------------------" << llendl; - llinfos << "Pixel Operations" << llendl; - llinfos << "-----------------------------------" << llendl; + LL_INFOS() << "-----------------------------------" << LL_ENDL; + LL_INFOS() << "Pixel Operations" << LL_ENDL; + LL_INFOS() << "-----------------------------------" << LL_ENDL; - llinfos << "GL_ALPHA_TEST : " << boolstr(glIsEnabled(GL_ALPHA_TEST)) << llendl; - llinfos << "GL_DEPTH_TEST : " << boolstr(glIsEnabled(GL_DEPTH_TEST)) << llendl; + LL_INFOS() << "GL_ALPHA_TEST : " << boolstr(glIsEnabled(GL_ALPHA_TEST)) << LL_ENDL; + LL_INFOS() << "GL_DEPTH_TEST : " << boolstr(glIsEnabled(GL_DEPTH_TEST)) << LL_ENDL; glGetBooleanv(GL_DEPTH_WRITEMASK, &b); - llinfos << "GL_DEPTH_WRITEMASK : " << boolstr(b) << llendl; + LL_INFOS() << "GL_DEPTH_WRITEMASK : " << boolstr(b) << LL_ENDL; - llinfos << "GL_BLEND : " << boolstr(glIsEnabled(GL_BLEND)) << llendl; - llinfos << "GL_DITHER : " << boolstr(glIsEnabled(GL_DITHER)) << llendl; + LL_INFOS() << "GL_BLEND : " << boolstr(glIsEnabled(GL_BLEND)) << LL_ENDL; + LL_INFOS() << "GL_DITHER : " << boolstr(glIsEnabled(GL_DITHER)) << LL_ENDL; } // End diff --git a/indra/llrender/llglheaders.h b/indra/llrender/llglheaders.h index 11074a7fd0..542ed4458e 100644 --- a/indra/llrender/llglheaders.h +++ b/indra/llrender/llglheaders.h @@ -27,250 +27,13 @@ #ifndef LL_LLGLHEADERS_H #define LL_LLGLHEADERS_H -#if LL_SOLARIS -# if defined(__sparc) -# define I_NEED_OS2_H // avoiding BOOL conflicts -# endif -# include "GL/gl.h" -# if defined(__sparc) -# undef I_NEED_OS2_H -# ifdef BOOL -# undef BOOL // now get rid of Xmd.h crap -# endif -# endif -# include "GL/glx.h" -# define GL_GLEXT_PROTOTYPES 1 -# include "GL/glext.h" -# include "GL/glu.h" -# include "GL/glx.h" -# define GLX_GLXEXT_PROTOTYPES 1 -# include "GL/glxext.h" -//# define GLH_EXT_GET_PROC_ADDRESS(p) glXGetProcAddressARB((const GLubyte*)(p)) -# define GLH_EXT_GET_PROC_ADDRESS(p) glXGetProcAddress((const GLubyte*)(p)) -// the X headers define 'Status'. Undefine to avoid confusion. -#undef Status - -// The __APPLE__ kludge is to make glh_extensions.h not symbol-clash horribly -// This header is distributed with SL. You'll find it in linden/libraries/include/GL/ -# define __APPLE__ -# include "GL/glh_extensions.h" -# undef __APPLE__ - - -// GL_ARB_vertex_buffer_object -extern PFNGLBINDBUFFERARBPROC glBindBufferARB; -extern PFNGLDELETEBUFFERSARBPROC glDeleteBuffersARB; -extern PFNGLGENBUFFERSARBPROC glGenBuffersARB; -extern PFNGLISBUFFERARBPROC glIsBufferARB; -extern PFNGLBUFFERDATAARBPROC glBufferDataARB; -extern PFNGLBUFFERSUBDATAARBPROC glBufferSubDataARB; -extern PFNGLGETBUFFERSUBDATAARBPROC glGetBufferSubDataARB; -extern PFNGLMAPBUFFERARBPROC glMapBufferARB; -extern PFNGLUNMAPBUFFERARBPROC glUnmapBufferARB; -extern PFNGLGETBUFFERPARAMETERIVARBPROC glGetBufferParameterivARB; -extern PFNGLGETBUFFERPOINTERVARBPROC glGetBufferPointervARB; - -// GL_ARB_vertex_array_object -extern PFNGLBINDVERTEXARRAYPROC glBindVertexArray; -extern PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays; -extern PFNGLGENVERTEXARRAYSPROC glGenVertexArrays; -extern PFNGLISVERTEXARRAYPROC glIsVertexArray; - -// GL_ARB_sync -extern PFNGLFENCESYNCPROC glFenceSync; -extern PFNGLISSYNCPROC glIsSync; -extern PFNGLDELETESYNCPROC glDeleteSync; -extern PFNGLCLIENTWAITSYNCPROC glClientWaitSync; -extern PFNGLWAITSYNCPROC glWaitSync; -extern PFNGLGETINTEGER64VPROC glGetInteger64v; -extern PFNGLGETSYNCIVPROC glGetSynciv; - -// GL_APPLE_flush_buffer_range -extern PFNGLBUFFERPARAMETERIAPPLEPROC glBufferParameteriAPPLE; -extern PFNGLFLUSHMAPPEDBUFFERRANGEAPPLEPROC glFlushMappedBufferRangeAPPLE; - -// GL_ARB_map_buffer_range -extern PFNGLMAPBUFFERRANGEPROC glMapBufferRange; -extern PFNGLFLUSHMAPPEDBUFFERRANGEPROC glFlushMappedBufferRange; - -// GL_ATI_vertex_array_object -extern PFNGLNEWOBJECTBUFFERATIPROC glNewObjectBufferATI; -extern PFNGLISOBJECTBUFFERATIPROC glIsObjectBufferATI; -extern PFNGLUPDATEOBJECTBUFFERATIPROC glUpdateObjectBufferATI; -extern PFNGLGETOBJECTBUFFERFVATIPROC glGetObjectBufferfvATI; -extern PFNGLGETOBJECTBUFFERIVATIPROC glGetObjectBufferivATI; -extern PFNGLFREEOBJECTBUFFERATIPROC glFreeObjectBufferATI; -extern PFNGLARRAYOBJECTATIPROC glArrayObjectATI; -extern PFNGLVERTEXATTRIBARRAYOBJECTATIPROC glVertexAttribArrayObjectATI; -extern PFNGLGETARRAYOBJECTFVATIPROC glGetArrayObjectfvATI; -extern PFNGLGETARRAYOBJECTIVATIPROC glGetArrayObjectivATI; -extern PFNGLVARIANTARRAYOBJECTATIPROC glVariantObjectArrayATI; -extern PFNGLGETVARIANTARRAYOBJECTFVATIPROC glGetVariantArrayObjectfvATI; -extern PFNGLGETVARIANTARRAYOBJECTIVATIPROC glGetVariantArrayObjectivATI; - -// GL_ARB_occlusion_query -extern PFNGLGENQUERIESARBPROC glGenQueriesARB; -extern PFNGLDELETEQUERIESARBPROC glDeleteQueriesARB; -extern PFNGLISQUERYARBPROC glIsQueryARB; -extern PFNGLBEGINQUERYARBPROC glBeginQueryARB; -extern PFNGLENDQUERYARBPROC glEndQueryARB; -extern PFNGLGETQUERYIVARBPROC glGetQueryivARB; -extern PFNGLGETQUERYOBJECTIVARBPROC glGetQueryObjectivARB; -extern PFNGLGETQUERYOBJECTUIVARBPROC glGetQueryObjectuivARB; - -// GL_ARB_point_parameters -extern PFNGLPOINTPARAMETERFARBPROC glPointParameterfARB; -extern PFNGLPOINTPARAMETERFVARBPROC glPointParameterfvARB; - -// GL_ARB_shader_objects -extern PFNGLDELETEOBJECTARBPROC glDeleteObjectARB; -extern PFNGLGETHANDLEARBPROC glGetHandleARB; -extern PFNGLDETACHOBJECTARBPROC glDetachObjectARB; -extern PFNGLCREATESHADEROBJECTARBPROC glCreateShaderObjectARB; -extern PFNGLSHADERSOURCEARBPROC glShaderSourceARB; -extern PFNGLCOMPILESHADERARBPROC glCompileShaderARB; -extern PFNGLCREATEPROGRAMOBJECTARBPROC glCreateProgramObjectARB; -extern PFNGLATTACHOBJECTARBPROC glAttachObjectARB; -extern PFNGLLINKPROGRAMARBPROC glLinkProgramARB; -extern PFNGLUSEPROGRAMOBJECTARBPROC glUseProgramObjectARB; -extern PFNGLVALIDATEPROGRAMARBPROC glValidateProgramARB; -extern PFNGLUNIFORM1FARBPROC glUniform1fARB; -extern PFNGLUNIFORM2FARBPROC glUniform2fARB; -extern PFNGLUNIFORM3FARBPROC glUniform3fARB; -extern PFNGLUNIFORM4FARBPROC glUniform4fARB; -extern PFNGLUNIFORM1IARBPROC glUniform1iARB; -extern PFNGLUNIFORM2IARBPROC glUniform2iARB; -extern PFNGLUNIFORM3IARBPROC glUniform3iARB; -extern PFNGLUNIFORM4IARBPROC glUniform4iARB; -extern PFNGLUNIFORM1FVARBPROC glUniform1fvARB; -extern PFNGLUNIFORM2FVARBPROC glUniform2fvARB; -extern PFNGLUNIFORM3FVARBPROC glUniform3fvARB; -extern PFNGLUNIFORM4FVARBPROC glUniform4fvARB; -extern PFNGLUNIFORM1IVARBPROC glUniform1ivARB; -extern PFNGLUNIFORM2IVARBPROC glUniform2ivARB; -extern PFNGLUNIFORM3IVARBPROC glUniform3ivARB; -extern PFNGLUNIFORM4IVARBPROC glUniform4ivARB; -extern PFNGLUNIFORMMATRIX2FVARBPROC glUniformMatrix2fvARB; -extern PFNGLUNIFORMMATRIX3FVARBPROC glUniformMatrix3fvARB; -extern PFNGLUNIFORMMATRIX4FVARBPROC glUniformMatrix4fvARB; -extern PFNGLGETOBJECTPARAMETERFVARBPROC glGetObjectParameterfvARB; -extern PFNGLGETOBJECTPARAMETERIVARBPROC glGetObjectParameterivARB; -extern PFNGLGETINFOLOGARBPROC glGetInfoLogARB; -extern PFNGLGETATTACHEDOBJECTSARBPROC glGetAttachedObjectsARB; -extern PFNGLGETUNIFORMLOCATIONARBPROC glGetUniformLocationARB; -extern PFNGLGETACTIVEUNIFORMARBPROC glGetActiveUniformARB; -extern PFNGLGETUNIFORMFVARBPROC glGetUniformfvARB; -extern PFNGLGETUNIFORMIVARBPROC glGetUniformivARB; -extern PFNGLGETSHADERSOURCEARBPROC glGetShaderSourceARB; - -// GL_ARB_vertex_shader -extern PFNGLVERTEXATTRIB1DARBPROC glVertexAttrib1dARB; -extern PFNGLVERTEXATTRIB1DVARBPROC glVertexAttrib1dvARB; -extern PFNGLVERTEXATTRIB1FARBPROC glVertexAttrib1fARB; -extern PFNGLVERTEXATTRIB1FVARBPROC glVertexAttrib1fvARB; -extern PFNGLVERTEXATTRIB1SARBPROC glVertexAttrib1sARB; -extern PFNGLVERTEXATTRIB1SVARBPROC glVertexAttrib1svARB; -extern PFNGLVERTEXATTRIB2DARBPROC glVertexAttrib2dARB; -extern PFNGLVERTEXATTRIB2DVARBPROC glVertexAttrib2dvARB; -extern PFNGLVERTEXATTRIB2FARBPROC glVertexAttrib2fARB; -extern PFNGLVERTEXATTRIB2FVARBPROC glVertexAttrib2fvARB; -extern PFNGLVERTEXATTRIB2SARBPROC glVertexAttrib2sARB; -extern PFNGLVERTEXATTRIB2SVARBPROC glVertexAttrib2svARB; -extern PFNGLVERTEXATTRIB3DARBPROC glVertexAttrib3dARB; -extern PFNGLVERTEXATTRIB3DVARBPROC glVertexAttrib3dvARB; -extern PFNGLVERTEXATTRIB3FARBPROC glVertexAttrib3fARB; -extern PFNGLVERTEXATTRIB3FVARBPROC glVertexAttrib3fvARB; -extern PFNGLVERTEXATTRIB3SARBPROC glVertexAttrib3sARB; -extern PFNGLVERTEXATTRIB3SVARBPROC glVertexAttrib3svARB; -extern PFNGLVERTEXATTRIB4NBVARBPROC glVertexAttrib4nbvARB; -extern PFNGLVERTEXATTRIB4NIVARBPROC glVertexAttrib4nivARB; -extern PFNGLVERTEXATTRIB4NSVARBPROC glVertexAttrib4nsvARB; -extern PFNGLVERTEXATTRIB4NUBARBPROC glVertexAttrib4nubARB; -extern PFNGLVERTEXATTRIB4NUBVARBPROC glVertexAttrib4nubvARB; -extern PFNGLVERTEXATTRIB4NUIVARBPROC glVertexAttrib4nuivARB; -extern PFNGLVERTEXATTRIB4NUSVARBPROC glVertexAttrib4nusvARB; -extern PFNGLVERTEXATTRIB4BVARBPROC glVertexAttrib4bvARB; -extern PFNGLVERTEXATTRIB4DARBPROC glVertexAttrib4dARB; -extern PFNGLVERTEXATTRIB4DVARBPROC glVertexAttrib4dvARB; -extern PFNGLVERTEXATTRIB4FARBPROC glVertexAttrib4fARB; -extern PFNGLVERTEXATTRIB4FVARBPROC glVertexAttrib4fvARB; -extern PFNGLVERTEXATTRIB4IVARBPROC glVertexAttrib4ivARB; -extern PFNGLVERTEXATTRIB4SARBPROC glVertexAttrib4sARB; -extern PFNGLVERTEXATTRIB4SVARBPROC glVertexAttrib4svARB; -extern PFNGLVERTEXATTRIB4UBVARBPROC glVertexAttrib4ubvARB; -extern PFNGLVERTEXATTRIB4UIVARBPROC glVertexAttrib4uivARB; -extern PFNGLVERTEXATTRIB4USVARBPROC glVertexAttrib4usvARB; -extern PFNGLVERTEXATTRIBPOINTERARBPROC glVertexAttribPointerARB; -extern PFNGLVERTEXATTRIBIPOINTERPROC glVertexAttribIPointer; -extern PFNGLENABLEVERTEXATTRIBARRAYARBPROC glEnableVertexAttribArrayARB; -extern PFNGLDISABLEVERTEXATTRIBARRAYARBPROC glDisableVertexAttribArrayARB; -extern PFNGLPROGRAMSTRINGARBPROC glProgramStringARB; -extern PFNGLBINDPROGRAMARBPROC glBindProgramARB; -extern PFNGLDELETEPROGRAMSARBPROC glDeleteProgramsARB; -extern PFNGLGENPROGRAMSARBPROC glGenProgramsARB; -extern PFNGLPROGRAMENVPARAMETER4DARBPROC glProgramEnvParameter4dARB; -extern PFNGLPROGRAMENVPARAMETER4DVARBPROC glProgramEnvParameter4dvARB; -extern PFNGLPROGRAMENVPARAMETER4FARBPROC glProgramEnvParameter4fARB; -extern PFNGLPROGRAMENVPARAMETER4FVARBPROC glProgramEnvParameter4fvARB; -extern PFNGLPROGRAMLOCALPARAMETER4DARBPROC glProgramLocalParameter4dARB; -extern PFNGLPROGRAMLOCALPARAMETER4DVARBPROC glProgramLocalParameter4dvARB; -extern PFNGLPROGRAMLOCALPARAMETER4FARBPROC glProgramLocalParameter4fARB; -extern PFNGLPROGRAMLOCALPARAMETER4FVARBPROC glProgramLocalParameter4fvARB; -extern PFNGLGETPROGRAMENVPARAMETERDVARBPROC glGetProgramEnvParameterdvARB; -extern PFNGLGETPROGRAMENVPARAMETERFVARBPROC glGetProgramEnvParameterfvARB; -extern PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC glGetProgramLocalParameterdvARB; -extern PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC glGetProgramLocalParameterfvARB; -extern PFNGLGETPROGRAMIVARBPROC glGetProgramivARB; -extern PFNGLGETPROGRAMSTRINGARBPROC glGetProgramStringARB; -extern PFNGLGETVERTEXATTRIBDVARBPROC glGetVertexAttribdvARB; -extern PFNGLGETVERTEXATTRIBFVARBPROC glGetVertexAttribfvARB; -extern PFNGLGETVERTEXATTRIBIVARBPROC glGetVertexAttribivARB; -extern PFNGLGETVERTEXATTRIBPOINTERVARBPROC glGetVertexAttribPointervARB; -extern PFNGLISPROGRAMARBPROC glIsProgramARB; -extern PFNGLBINDATTRIBLOCATIONARBPROC glBindAttribLocationARB; -extern PFNGLGETACTIVEATTRIBARBPROC glGetActiveAttribARB; -extern PFNGLGETATTRIBLOCATIONARBPROC glGetAttribLocationARB; - -extern PFNGLCOMPRESSEDTEXIMAGE2DARBPROC glCompressedTexImage2DARB; -extern PFNGLGETCOMPRESSEDTEXIMAGEARBPROC glGetCompressedTexImageARB; - -extern PFNGLCOLORTABLEEXTPROC glColorTableEXT; - -//GL_EXT_blend_func_separate -extern PFNGLBLENDFUNCSEPARATEEXTPROC glBlendFuncSeparateEXT; - -//GL_EXT_framebuffer_object -extern PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT; -extern PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT; -extern PFNGLDELETERENDERBUFFERSEXTPROC glDeleteRenderbuffersEXT; -extern PFNGLGENRENDERBUFFERSEXTPROC glGenRenderbuffersEXT; -extern PFNGLRENDERBUFFERSTORAGEEXTPROC glRenderbufferStorageEXT; -extern PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC glGetRenderbufferParameterivEXT; -extern PFNGLISFRAMEBUFFEREXTPROC glIsFramebufferEXT; -extern PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT; -extern PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffersEXT; -extern PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT; -extern PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT; -extern PFNGLFRAMEBUFFERTEXTURE1DEXTPROC glFramebufferTexture1DEXT; -extern PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT; -extern PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glFramebufferTexture3DEXT; -extern PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbufferEXT; -extern PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glGetFramebufferAttachmentParameterivEXT; -extern PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT; - -#elif LL_MESA +#if LL_MESA //---------------------------------------------------------------------------- // MESA headers // quotes so we get libraries/.../GL/ version #define GL_GLEXT_PROTOTYPES 1 #include "GL/gl.h" #include "GL/glext.h" -#include "GL/glu.h" - -// The __APPLE__ kludge is to make glh_extensions.h not symbol-clash horribly -# define __APPLE__ -# include "GL/glh_extensions.h" -# undef __APPLE__ #elif LL_LINUX //---------------------------------------------------------------------------- @@ -281,14 +44,8 @@ extern PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT; // quotes so we get libraries/.../GL/ version #include "GL/gl.h" #include "GL/glext.h" -#include "GL/glu.h" - #if LL_LINUX && !LL_MESA_HEADLESS -// The __APPLE__ kludge is to make glh_extensions.h not symbol-clash horribly -# define __APPLE__ -# include "GL/glh_extensions.h" -# undef __APPLE__ /* Although SDL very likely ends up calling glXGetProcAddress() itself, if we use SDL_GL_GetProcAddress() then we get bogus addresses back on @@ -320,244 +77,87 @@ extern PFNGLCLIENTACTIVETEXTUREARBPROC glClientActiveTextureARB; extern PFNGLDRAWRANGEELEMENTSPROC glDrawRangeElements; #endif // LL_LINUX_NV_GL_HEADERS -// GL_ARB_vertex_array_object -extern PFNGLBINDVERTEXARRAYPROC glBindVertexArray; -extern PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays; -extern PFNGLGENVERTEXARRAYSPROC glGenVertexArrays; -extern PFNGLISVERTEXARRAYPROC glIsVertexArray; - -// GL_ARB_vertex_buffer_object -extern PFNGLBINDBUFFERARBPROC glBindBufferARB; -extern PFNGLDELETEBUFFERSARBPROC glDeleteBuffersARB; -extern PFNGLGENBUFFERSARBPROC glGenBuffersARB; -extern PFNGLISBUFFERARBPROC glIsBufferARB; -extern PFNGLBUFFERDATAARBPROC glBufferDataARB; -extern PFNGLBUFFERSUBDATAARBPROC glBufferSubDataARB; -extern PFNGLGETBUFFERSUBDATAARBPROC glGetBufferSubDataARB; -extern PFNGLMAPBUFFERARBPROC glMapBufferARB; -extern PFNGLUNMAPBUFFERARBPROC glUnmapBufferARB; -extern PFNGLGETBUFFERPARAMETERIVARBPROC glGetBufferParameterivARB; -extern PFNGLGETBUFFERPOINTERVARBPROC glGetBufferPointervARB; - -// GL_ARB_sync -extern PFNGLFENCESYNCPROC glFenceSync; -extern PFNGLISSYNCPROC glIsSync; -extern PFNGLDELETESYNCPROC glDeleteSync; -extern PFNGLCLIENTWAITSYNCPROC glClientWaitSync; -extern PFNGLWAITSYNCPROC glWaitSync; -extern PFNGLGETINTEGER64VPROC glGetInteger64v; -extern PFNGLGETSYNCIVPROC glGetSynciv; - -// GL_APPLE_flush_buffer_range -extern PFNGLBUFFERPARAMETERIAPPLEPROC glBufferParameteriAPPLE; -extern PFNGLFLUSHMAPPEDBUFFERRANGEAPPLEPROC glFlushMappedBufferRangeAPPLE; - -// GL_ARB_map_buffer_range -extern PFNGLMAPBUFFERRANGEPROC glMapBufferRange; -extern PFNGLFLUSHMAPPEDBUFFERRANGEPROC glFlushMappedBufferRange; - -// GL_ATI_vertex_array_object -extern PFNGLNEWOBJECTBUFFERATIPROC glNewObjectBufferATI; -extern PFNGLISOBJECTBUFFERATIPROC glIsObjectBufferATI; -extern PFNGLUPDATEOBJECTBUFFERATIPROC glUpdateObjectBufferATI; -extern PFNGLGETOBJECTBUFFERFVATIPROC glGetObjectBufferfvATI; -extern PFNGLGETOBJECTBUFFERIVATIPROC glGetObjectBufferivATI; -extern PFNGLFREEOBJECTBUFFERATIPROC glFreeObjectBufferATI; -extern PFNGLARRAYOBJECTATIPROC glArrayObjectATI; -extern PFNGLVERTEXATTRIBARRAYOBJECTATIPROC glVertexAttribArrayObjectATI; -extern PFNGLGETARRAYOBJECTFVATIPROC glGetArrayObjectfvATI; -extern PFNGLGETARRAYOBJECTIVATIPROC glGetArrayObjectivATI; -extern PFNGLVARIANTARRAYOBJECTATIPROC glVariantObjectArrayATI; -extern PFNGLGETVARIANTARRAYOBJECTFVATIPROC glGetVariantArrayObjectfvATI; -extern PFNGLGETVARIANTARRAYOBJECTIVATIPROC glGetVariantArrayObjectivATI; - -// GL_ARB_occlusion_query -extern PFNGLGENQUERIESARBPROC glGenQueriesARB; -extern PFNGLDELETEQUERIESARBPROC glDeleteQueriesARB; -extern PFNGLISQUERYARBPROC glIsQueryARB; -extern PFNGLBEGINQUERYARBPROC glBeginQueryARB; -extern PFNGLENDQUERYARBPROC glEndQueryARB; -extern PFNGLGETQUERYIVARBPROC glGetQueryivARB; -extern PFNGLGETQUERYOBJECTIVARBPROC glGetQueryObjectivARB; -extern PFNGLGETQUERYOBJECTUIVARBPROC glGetQueryObjectuivARB; - -// GL_ARB_point_parameters -extern PFNGLPOINTPARAMETERFARBPROC glPointParameterfARB; -extern PFNGLPOINTPARAMETERFVARBPROC glPointParameterfvARB; - -// GL_ARB_shader_objects -extern PFNGLDELETEOBJECTARBPROC glDeleteObjectARB; -extern PFNGLGETHANDLEARBPROC glGetHandleARB; -extern PFNGLDETACHOBJECTARBPROC glDetachObjectARB; -extern PFNGLCREATESHADEROBJECTARBPROC glCreateShaderObjectARB; -extern PFNGLSHADERSOURCEARBPROC glShaderSourceARB; -extern PFNGLCOMPILESHADERARBPROC glCompileShaderARB; -extern PFNGLCREATEPROGRAMOBJECTARBPROC glCreateProgramObjectARB; -extern PFNGLATTACHOBJECTARBPROC glAttachObjectARB; -extern PFNGLLINKPROGRAMARBPROC glLinkProgramARB; -extern PFNGLUSEPROGRAMOBJECTARBPROC glUseProgramObjectARB; -extern PFNGLVALIDATEPROGRAMARBPROC glValidateProgramARB; -extern PFNGLUNIFORM1FARBPROC glUniform1fARB; -extern PFNGLUNIFORM2FARBPROC glUniform2fARB; -extern PFNGLUNIFORM3FARBPROC glUniform3fARB; -extern PFNGLUNIFORM4FARBPROC glUniform4fARB; -extern PFNGLUNIFORM1IARBPROC glUniform1iARB; -extern PFNGLUNIFORM2IARBPROC glUniform2iARB; -extern PFNGLUNIFORM3IARBPROC glUniform3iARB; -extern PFNGLUNIFORM4IARBPROC glUniform4iARB; -extern PFNGLUNIFORM1FVARBPROC glUniform1fvARB; -extern PFNGLUNIFORM2FVARBPROC glUniform2fvARB; -extern PFNGLUNIFORM3FVARBPROC glUniform3fvARB; -extern PFNGLUNIFORM4FVARBPROC glUniform4fvARB; -extern PFNGLUNIFORM1IVARBPROC glUniform1ivARB; -extern PFNGLUNIFORM2IVARBPROC glUniform2ivARB; -extern PFNGLUNIFORM3IVARBPROC glUniform3ivARB; -extern PFNGLUNIFORM4IVARBPROC glUniform4ivARB; -extern PFNGLUNIFORMMATRIX2FVARBPROC glUniformMatrix2fvARB; -extern PFNGLUNIFORMMATRIX3FVARBPROC glUniformMatrix3fvARB; -extern PFNGLUNIFORMMATRIX4FVARBPROC glUniformMatrix4fvARB; -extern PFNGLGETOBJECTPARAMETERFVARBPROC glGetObjectParameterfvARB; -extern PFNGLGETOBJECTPARAMETERIVARBPROC glGetObjectParameterivARB; -extern PFNGLGETINFOLOGARBPROC glGetInfoLogARB; -extern PFNGLGETATTACHEDOBJECTSARBPROC glGetAttachedObjectsARB; -extern PFNGLGETUNIFORMLOCATIONARBPROC glGetUniformLocationARB; -extern PFNGLGETACTIVEUNIFORMARBPROC glGetActiveUniformARB; -extern PFNGLGETUNIFORMFVARBPROC glGetUniformfvARB; -extern PFNGLGETUNIFORMIVARBPROC glGetUniformivARB; -extern PFNGLGETSHADERSOURCEARBPROC glGetShaderSourceARB; - -// GL_ARB_vertex_shader -extern PFNGLVERTEXATTRIB1DARBPROC glVertexAttrib1dARB; -extern PFNGLVERTEXATTRIB1DVARBPROC glVertexAttrib1dvARB; -extern PFNGLVERTEXATTRIB1FARBPROC glVertexAttrib1fARB; -extern PFNGLVERTEXATTRIB1FVARBPROC glVertexAttrib1fvARB; -extern PFNGLVERTEXATTRIB1SARBPROC glVertexAttrib1sARB; -extern PFNGLVERTEXATTRIB1SVARBPROC glVertexAttrib1svARB; -extern PFNGLVERTEXATTRIB2DARBPROC glVertexAttrib2dARB; -extern PFNGLVERTEXATTRIB2DVARBPROC glVertexAttrib2dvARB; -extern PFNGLVERTEXATTRIB2FARBPROC glVertexAttrib2fARB; -extern PFNGLVERTEXATTRIB2FVARBPROC glVertexAttrib2fvARB; -extern PFNGLVERTEXATTRIB2SARBPROC glVertexAttrib2sARB; -extern PFNGLVERTEXATTRIB2SVARBPROC glVertexAttrib2svARB; -extern PFNGLVERTEXATTRIB3DARBPROC glVertexAttrib3dARB; -extern PFNGLVERTEXATTRIB3DVARBPROC glVertexAttrib3dvARB; -extern PFNGLVERTEXATTRIB3FARBPROC glVertexAttrib3fARB; -extern PFNGLVERTEXATTRIB3FVARBPROC glVertexAttrib3fvARB; -extern PFNGLVERTEXATTRIB3SARBPROC glVertexAttrib3sARB; -extern PFNGLVERTEXATTRIB3SVARBPROC glVertexAttrib3svARB; -extern PFNGLVERTEXATTRIB4NBVARBPROC glVertexAttrib4nbvARB; -extern PFNGLVERTEXATTRIB4NIVARBPROC glVertexAttrib4nivARB; -extern PFNGLVERTEXATTRIB4NSVARBPROC glVertexAttrib4nsvARB; -extern PFNGLVERTEXATTRIB4NUBARBPROC glVertexAttrib4nubARB; -extern PFNGLVERTEXATTRIB4NUBVARBPROC glVertexAttrib4nubvARB; -extern PFNGLVERTEXATTRIB4NUIVARBPROC glVertexAttrib4nuivARB; -extern PFNGLVERTEXATTRIB4NUSVARBPROC glVertexAttrib4nusvARB; -extern PFNGLVERTEXATTRIB4BVARBPROC glVertexAttrib4bvARB; -extern PFNGLVERTEXATTRIB4DARBPROC glVertexAttrib4dARB; -extern PFNGLVERTEXATTRIB4DVARBPROC glVertexAttrib4dvARB; -extern PFNGLVERTEXATTRIB4FARBPROC glVertexAttrib4fARB; -extern PFNGLVERTEXATTRIB4FVARBPROC glVertexAttrib4fvARB; -extern PFNGLVERTEXATTRIB4IVARBPROC glVertexAttrib4ivARB; -extern PFNGLVERTEXATTRIB4SARBPROC glVertexAttrib4sARB; -extern PFNGLVERTEXATTRIB4SVARBPROC glVertexAttrib4svARB; -extern PFNGLVERTEXATTRIB4UBVARBPROC glVertexAttrib4ubvARB; -extern PFNGLVERTEXATTRIB4UIVARBPROC glVertexAttrib4uivARB; -extern PFNGLVERTEXATTRIB4USVARBPROC glVertexAttrib4usvARB; -extern PFNGLVERTEXATTRIBPOINTERARBPROC glVertexAttribPointerARB; -extern PFNGLVERTEXATTRIBIPOINTERPROC glVertexAttribIPointer; -extern PFNGLENABLEVERTEXATTRIBARRAYARBPROC glEnableVertexAttribArrayARB; -extern PFNGLDISABLEVERTEXATTRIBARRAYARBPROC glDisableVertexAttribArrayARB; -extern PFNGLPROGRAMSTRINGARBPROC glProgramStringARB; -extern PFNGLBINDPROGRAMARBPROC glBindProgramARB; -extern PFNGLDELETEPROGRAMSARBPROC glDeleteProgramsARB; -extern PFNGLGENPROGRAMSARBPROC glGenProgramsARB; -extern PFNGLPROGRAMENVPARAMETER4DARBPROC glProgramEnvParameter4dARB; -extern PFNGLPROGRAMENVPARAMETER4DVARBPROC glProgramEnvParameter4dvARB; -extern PFNGLPROGRAMENVPARAMETER4FARBPROC glProgramEnvParameter4fARB; -extern PFNGLPROGRAMENVPARAMETER4FVARBPROC glProgramEnvParameter4fvARB; -extern PFNGLPROGRAMLOCALPARAMETER4DARBPROC glProgramLocalParameter4dARB; -extern PFNGLPROGRAMLOCALPARAMETER4DVARBPROC glProgramLocalParameter4dvARB; -extern PFNGLPROGRAMLOCALPARAMETER4FARBPROC glProgramLocalParameter4fARB; -extern PFNGLPROGRAMLOCALPARAMETER4FVARBPROC glProgramLocalParameter4fvARB; -extern PFNGLGETPROGRAMENVPARAMETERDVARBPROC glGetProgramEnvParameterdvARB; -extern PFNGLGETPROGRAMENVPARAMETERFVARBPROC glGetProgramEnvParameterfvARB; -extern PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC glGetProgramLocalParameterdvARB; -extern PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC glGetProgramLocalParameterfvARB; -extern PFNGLGETPROGRAMIVARBPROC glGetProgramivARB; -extern PFNGLGETPROGRAMSTRINGARBPROC glGetProgramStringARB; -extern PFNGLGETVERTEXATTRIBDVARBPROC glGetVertexAttribdvARB; -extern PFNGLGETVERTEXATTRIBFVARBPROC glGetVertexAttribfvARB; -extern PFNGLGETVERTEXATTRIBIVARBPROC glGetVertexAttribivARB; -extern PFNGLGETVERTEXATTRIBPOINTERVARBPROC glGetVertexAttribPointervARB; -extern PFNGLISPROGRAMARBPROC glIsProgramARB; -extern PFNGLBINDATTRIBLOCATIONARBPROC glBindAttribLocationARB; -extern PFNGLGETACTIVEATTRIBARBPROC glGetActiveAttribARB; -extern PFNGLGETATTRIBLOCATIONARBPROC glGetAttribLocationARB; - -extern PFNGLCOMPRESSEDTEXIMAGE2DARBPROC glCompressedTexImage2DARB; -extern PFNGLGETCOMPRESSEDTEXIMAGEARBPROC glGetCompressedTexImageARB; - -//GL_EXT_blend_func_separate -extern PFNGLBLENDFUNCSEPARATEEXTPROC glBlendFuncSeparateEXT; - -//GL_ARB_framebuffer_object -extern PFNGLISRENDERBUFFERPROC glIsRenderbuffer; -extern PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer; -extern PFNGLDELETERENDERBUFFERSPROC glDeleteRenderbuffers; -extern PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers; -extern PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage; -extern PFNGLGETRENDERBUFFERPARAMETERIVPROC glGetRenderbufferParameteriv; -extern PFNGLISFRAMEBUFFERPROC glIsFramebuffer; -extern PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer; -extern PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers; -extern PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers; -extern PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus; -extern PFNGLFRAMEBUFFERTEXTURE1DPROC glFramebufferTexture1D; -extern PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D; -extern PFNGLFRAMEBUFFERTEXTURE3DPROC glFramebufferTexture3D; -extern PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer; -extern PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glGetFramebufferAttachmentParameteriv; -extern PFNGLGENERATEMIPMAPPROC glGenerateMipmap; -extern PFNGLBLITFRAMEBUFFERPROC glBlitFramebuffer; -extern PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glRenderbufferStorageMultisample; -extern PFNGLFRAMEBUFFERTEXTURELAYERPROC glFramebufferTextureLayer; - -//GL_ARB_draw_buffers -extern PFNGLDRAWBUFFERSARBPROC glDrawBuffersARB; - -//GL_ARB_texture_multisample -extern PFNGLTEXIMAGE2DMULTISAMPLEPROC glTexImage2DMultisample; -extern PFNGLTEXIMAGE3DMULTISAMPLEPROC glTexImage3DMultisample; -extern PFNGLGETMULTISAMPLEFVPROC glGetMultisamplefv; -extern PFNGLSAMPLEMASKIPROC glSampleMaski; - -//transform feedback (4.0 core) -extern PFNGLBEGINTRANSFORMFEEDBACKPROC glBeginTransformFeedback; -extern PFNGLENDTRANSFORMFEEDBACKPROC glEndTransformFeedback; -extern PFNGLTRANSFORMFEEDBACKVARYINGSPROC glTransformFeedbackVaryings; -extern PFNGLBINDBUFFERRANGEPROC glBindBufferRange; - - #elif LL_WINDOWS //---------------------------------------------------------------------------- // LL_WINDOWS -// windows gl headers depend on things like APIENTRY, so include windows. -#define WIN32_LEAN_AND_MEAN -#include -#include +#include "llwin32headerslean.h" //---------------------------------------------------------------------------- #include -#include // quotes so we get libraries/.../GL/ version #include "GL/glext.h" -#include "GL/glh_extensions.h" +#include +#define GLH_EXT_GET_PROC_ADDRESS(p) wglGetProcAddress(p) // WGL_ARB_create_context -extern PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB; -extern PFNGLGETSTRINGIPROC glGetStringi; +extern PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB; +// WGL_ARB_swap_control +extern PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT; +// WGL_ARB_pixel_format +extern PFNWGLGETPIXELFORMATATTRIBIVARBPROC wglGetPixelFormatAttribivARB; +extern PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB; + +// Mesa goes up to Opengl 1.3. Windows api only includes 1.1. Include 1.2 and 1.3 features here +// Opengl 1.2 +extern PFNGLDRAWRANGEELEMENTSPROC glDrawRangeElements; + +// GL_ARB_multitexture +extern PFNGLMULTITEXCOORD1DARBPROC glMultiTexCoord1dARB; +extern PFNGLMULTITEXCOORD1DVARBPROC glMultiTexCoord1dvARB; +extern PFNGLMULTITEXCOORD1FARBPROC glMultiTexCoord1fARB; +extern PFNGLMULTITEXCOORD1FVARBPROC glMultiTexCoord1fvARB; +extern PFNGLMULTITEXCOORD1IARBPROC glMultiTexCoord1iARB; +extern PFNGLMULTITEXCOORD1IVARBPROC glMultiTexCoord1ivARB; +extern PFNGLMULTITEXCOORD1SARBPROC glMultiTexCoord1sARB; +extern PFNGLMULTITEXCOORD1SVARBPROC glMultiTexCoord1svARB; +extern PFNGLMULTITEXCOORD2DARBPROC glMultiTexCoord2dARB; +extern PFNGLMULTITEXCOORD2DVARBPROC glMultiTexCoord2dvARB; +extern PFNGLMULTITEXCOORD2FARBPROC glMultiTexCoord2fARB; +extern PFNGLMULTITEXCOORD2FVARBPROC glMultiTexCoord2fvARB; +extern PFNGLMULTITEXCOORD2IARBPROC glMultiTexCoord2iARB; +extern PFNGLMULTITEXCOORD2IVARBPROC glMultiTexCoord2ivARB; +extern PFNGLMULTITEXCOORD2SARBPROC glMultiTexCoord2sARB; +extern PFNGLMULTITEXCOORD2SVARBPROC glMultiTexCoord2svARB; +extern PFNGLMULTITEXCOORD3DARBPROC glMultiTexCoord3dARB; +extern PFNGLMULTITEXCOORD3DVARBPROC glMultiTexCoord3dvARB; +extern PFNGLMULTITEXCOORD3FARBPROC glMultiTexCoord3fARB; +extern PFNGLMULTITEXCOORD3FVARBPROC glMultiTexCoord3fvARB; +extern PFNGLMULTITEXCOORD3IARBPROC glMultiTexCoord3iARB; +extern PFNGLMULTITEXCOORD3IVARBPROC glMultiTexCoord3ivARB; +extern PFNGLMULTITEXCOORD3SARBPROC glMultiTexCoord3sARB; +extern PFNGLMULTITEXCOORD3SVARBPROC glMultiTexCoord3svARB; +extern PFNGLMULTITEXCOORD4DARBPROC glMultiTexCoord4dARB; +extern PFNGLMULTITEXCOORD4DVARBPROC glMultiTexCoord4dvARB; +extern PFNGLMULTITEXCOORD4FARBPROC glMultiTexCoord4fARB; +extern PFNGLMULTITEXCOORD4FVARBPROC glMultiTexCoord4fvARB; +extern PFNGLMULTITEXCOORD4IARBPROC glMultiTexCoord4iARB; +extern PFNGLMULTITEXCOORD4IVARBPROC glMultiTexCoord4ivARB; +extern PFNGLMULTITEXCOORD4SARBPROC glMultiTexCoord4sARB; +extern PFNGLMULTITEXCOORD4SVARBPROC glMultiTexCoord4svARB; +extern PFNGLACTIVETEXTUREARBPROC glActiveTextureARB; +extern PFNGLCLIENTACTIVETEXTUREARBPROC glClientActiveTextureARB; + +#endif + +#if LL_WINDOWS || (LL_LINUX && !LL_MESA_HEADLESS && !LL_MESA) + +//GL_ARB_texture_compression +// ARB variants of these are missing from mesa gl.h for some odd reason. +extern PFNGLCOMPRESSEDTEXIMAGE3DARBPROC glCompressedTexImage3DARB; +extern PFNGLCOMPRESSEDTEXIMAGE2DARBPROC glCompressedTexImage2DARB; +extern PFNGLCOMPRESSEDTEXIMAGE1DARBPROC glCompressedTexImage1DARB; +extern PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC glCompressedTexSubImage3DARB; +extern PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC glCompressedTexSubImage2DARB; +extern PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC glCompressedTexSubImage1DARB; +extern PFNGLGETCOMPRESSEDTEXIMAGEARBPROC glGetCompressedTexImageARB; + +// GL_ARB_vertex_array_object +extern PFNGLBINDVERTEXARRAYPROC glBindVertexArray; +extern PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays; +extern PFNGLGENVERTEXARRAYSPROC glGenVertexArrays; +extern PFNGLISVERTEXARRAYPROC glIsVertexArray; // GL_ARB_vertex_buffer_object extern PFNGLBINDBUFFERARBPROC glBindBufferARB; @@ -572,12 +172,6 @@ extern PFNGLUNMAPBUFFERARBPROC glUnmapBufferARB; extern PFNGLGETBUFFERPARAMETERIVARBPROC glGetBufferParameterivARB; extern PFNGLGETBUFFERPOINTERVARBPROC glGetBufferPointervARB; -// GL_ARB_vertex_array_object -extern PFNGLBINDVERTEXARRAYPROC glBindVertexArray; -extern PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays; -extern PFNGLGENVERTEXARRAYSPROC glGenVertexArrays; -extern PFNGLISVERTEXARRAYPROC glIsVertexArray; - // GL_ARB_sync extern PFNGLFENCESYNCPROC glFenceSync; extern PFNGLISSYNCPROC glIsSync; @@ -595,23 +189,6 @@ extern PFNGLFLUSHMAPPEDBUFFERRANGEAPPLEPROC glFlushMappedBufferRangeAPPLE; extern PFNGLMAPBUFFERRANGEPROC glMapBufferRange; extern PFNGLFLUSHMAPPEDBUFFERRANGEPROC glFlushMappedBufferRange; -// GL_ATI_vertex_array_object -extern PFNGLNEWOBJECTBUFFERATIPROC glNewObjectBufferATI; -extern PFNGLISOBJECTBUFFERATIPROC glIsObjectBufferATI; -extern PFNGLUPDATEOBJECTBUFFERATIPROC glUpdateObjectBufferATI; -extern PFNGLGETOBJECTBUFFERFVATIPROC glGetObjectBufferfvATI; -extern PFNGLGETOBJECTBUFFERIVATIPROC glGetObjectBufferivATI; -extern PFNGLFREEOBJECTBUFFERATIPROC glFreeObjectBufferATI; -extern PFNGLARRAYOBJECTATIPROC glArrayObjectATI; -extern PFNGLVERTEXATTRIBARRAYOBJECTATIPROC glVertexAttribArrayObjectATI; -extern PFNGLGETARRAYOBJECTFVATIPROC glGetArrayObjectfvATI; -extern PFNGLGETARRAYOBJECTIVATIPROC glGetArrayObjectivATI; -extern PFNGLVARIANTARRAYOBJECTATIPROC glVariantObjectArrayATI; -extern PFNGLGETVARIANTARRAYOBJECTFVATIPROC glGetVariantArrayObjectfvATI; -extern PFNGLGETVARIANTARRAYOBJECTIVATIPROC glGetVariantArrayObjectivATI; - -extern PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT; - // GL_ARB_occlusion_query extern PFNGLGENQUERIESARBPROC glGenQueriesARB; extern PFNGLDELETEQUERIESARBPROC glDeleteQueriesARB; @@ -622,13 +199,15 @@ extern PFNGLGETQUERYIVARBPROC glGetQueryivARB; extern PFNGLGETQUERYOBJECTIVARBPROC glGetQueryObjectivARB; extern PFNGLGETQUERYOBJECTUIVARBPROC glGetQueryObjectuivARB; +extern PFNGLGETQUERYOBJECTUI64VEXTPROC glGetQueryObjectui64vEXT; + // GL_ARB_point_parameters extern PFNGLPOINTPARAMETERFARBPROC glPointParameterfARB; extern PFNGLPOINTPARAMETERFVARBPROC glPointParameterfvARB; // GL_ARB_shader_objects -extern PFNGLDELETEOBJECTARBPROC glDeleteObjectARB; -extern PFNGLGETHANDLEARBPROC glGetHandleARB; +extern PFNGLDELETEOBJECTARBPROC glDeleteShader; +extern PFNGLDELETEOBJECTARBPROC glDeleteProgram; extern PFNGLDETACHOBJECTARBPROC glDetachObjectARB; extern PFNGLCREATESHADEROBJECTARBPROC glCreateShaderObjectARB; extern PFNGLSHADERSOURCEARBPROC glShaderSourceARB; @@ -656,10 +235,12 @@ extern PFNGLUNIFORM3IVARBPROC glUniform3ivARB; extern PFNGLUNIFORM4IVARBPROC glUniform4ivARB; extern PFNGLUNIFORMMATRIX2FVARBPROC glUniformMatrix2fvARB; extern PFNGLUNIFORMMATRIX3FVARBPROC glUniformMatrix3fvARB; +extern PFNGLUNIFORMMATRIX3X4FVPROC glUniformMatrix3x4fv; extern PFNGLUNIFORMMATRIX4FVARBPROC glUniformMatrix4fvARB; -extern PFNGLGETOBJECTPARAMETERFVARBPROC glGetObjectParameterfvARB; -extern PFNGLGETOBJECTPARAMETERIVARBPROC glGetObjectParameterivARB; -extern PFNGLGETINFOLOGARBPROC glGetInfoLogARB; +extern PFNGLGETOBJECTPARAMETERIVARBPROC glGetShaderiv; +extern PFNGLGETOBJECTPARAMETERIVARBPROC glGetProgramiv; +extern PFNGLGETINFOLOGARBPROC glGetShaderInfoLog; +extern PFNGLGETINFOLOGARBPROC glGetProgramInfoLog; extern PFNGLGETATTACHEDOBJECTSARBPROC glGetAttachedObjectsARB; extern PFNGLGETUNIFORMLOCATIONARBPROC glGetUniformLocationARB; extern PFNGLGETACTIVEUNIFORMARBPROC glGetActiveUniformARB; @@ -686,13 +267,13 @@ extern PFNGLVERTEXATTRIB3FARBPROC glVertexAttrib3fARB; extern PFNGLVERTEXATTRIB3FVARBPROC glVertexAttrib3fvARB; extern PFNGLVERTEXATTRIB3SARBPROC glVertexAttrib3sARB; extern PFNGLVERTEXATTRIB3SVARBPROC glVertexAttrib3svARB; -extern PFNGLVERTEXATTRIB4NBVARBPROC glVertexAttrib4nbvARB; -extern PFNGLVERTEXATTRIB4NIVARBPROC glVertexAttrib4nivARB; -extern PFNGLVERTEXATTRIB4NSVARBPROC glVertexAttrib4nsvARB; -extern PFNGLVERTEXATTRIB4NUBARBPROC glVertexAttrib4nubARB; -extern PFNGLVERTEXATTRIB4NUBVARBPROC glVertexAttrib4nubvARB; -extern PFNGLVERTEXATTRIB4NUIVARBPROC glVertexAttrib4nuivARB; -extern PFNGLVERTEXATTRIB4NUSVARBPROC glVertexAttrib4nusvARB; +extern PFNGLVERTEXATTRIB4NBVARBPROC glVertexAttrib4NbvARB; +extern PFNGLVERTEXATTRIB4NIVARBPROC glVertexAttrib4NivARB; +extern PFNGLVERTEXATTRIB4NSVARBPROC glVertexAttrib4NsvARB; +extern PFNGLVERTEXATTRIB4NUBARBPROC glVertexAttrib4NubARB; +extern PFNGLVERTEXATTRIB4NUBVARBPROC glVertexAttrib4NubvARB; +extern PFNGLVERTEXATTRIB4NUIVARBPROC glVertexAttrib4NuivARB; +extern PFNGLVERTEXATTRIB4NUSVARBPROC glVertexAttrib4NusvARB; extern PFNGLVERTEXATTRIB4BVARBPROC glVertexAttrib4bvARB; extern PFNGLVERTEXATTRIB4DARBPROC glVertexAttrib4dARB; extern PFNGLVERTEXATTRIB4DVARBPROC glVertexAttrib4dvARB; @@ -775,6 +356,7 @@ extern PFNGLENDTRANSFORMFEEDBACKPROC glEndTransformFeedback; extern PFNGLTRANSFORMFEEDBACKVARYINGSPROC glTransformFeedbackVaryings; extern PFNGLBINDBUFFERRANGEPROC glBindBufferRange; + //GL_ARB_debug_output extern PFNGLDEBUGMESSAGECONTROLARBPROC glDebugMessageControlARB; extern PFNGLDEBUGMESSAGEINSERTARBPROC glDebugMessageInsertARB; @@ -786,13 +368,10 @@ extern PFNGLGETDEBUGMESSAGELOGARBPROC glGetDebugMessageLogARB; // LL_DARWIN #include -#include #define GL_EXT_separate_specular_color 1 #include -#include "GL/glh_extensions.h" - // These symbols don't exist on 10.3.9, so they have to be declared weak. Redeclaring them here fixes the problem. // Note that they also must not be called on 10.3.9. This should be taken care of by a runtime check for the existence of the GL extension. #include diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp index b8827db9e8..0066dbc851 100644 --- a/indra/llrender/llglslshader.cpp +++ b/indra/llrender/llglslshader.cpp @@ -43,7 +43,6 @@ #else #define UNIFORM_ERRS LL_ERRS("Shader") #endif - // Lots of STL stuff in here, using namespace std to keep things more readable using std::vector; using std::pair; @@ -54,6 +53,12 @@ GLhandleARB LLGLSLShader::sCurBoundShader = 0; LLGLSLShader* LLGLSLShader::sCurBoundShaderPtr = NULL; S32 LLGLSLShader::sIndexedTextureChannels = 0; bool LLGLSLShader::sNoFixedFunction = false; +bool LLGLSLShader::sProfileEnabled = false; +std::set LLGLSLShader::sInstances; +U64 LLGLSLShader::sTotalTimeElapsed = 0; +U32 LLGLSLShader::sTotalTrianglesDrawn = 0; +U64 LLGLSLShader::sTotalSamplesDrawn = 0; +U32 LLGLSLShader::sTotalDrawCalls = 0; //UI shader -- declared here so llui_libtest will link properly //Singu note: Not using llui_libtest... and LLViewerShaderMgr is a part of newview. So, @@ -83,26 +88,252 @@ LLShaderFeatures::LLShaderFeatures() , hasGamma(false) , mIndexedTextureChannels(0) , disableTextureIndex(false) - , hasAlphaMask(false) + , hasAlphaMask(false) + , attachNothing(false) { } //=============================== // LLGLSL Shader implementation //=============================== + +//static +void LLGLSLShader::initProfile() +{ + sProfileEnabled = true; + sTotalTimeElapsed = 0; + sTotalTrianglesDrawn = 0; + sTotalSamplesDrawn = 0; + sTotalDrawCalls = 0; + + for (std::set::iterator iter = sInstances.begin(); iter != sInstances.end(); ++iter) + { + (*iter)->clearStats(); + } +} + + +struct LLGLSLShaderCompareTimeElapsed +{ + bool operator()(const LLGLSLShader* const& lhs, const LLGLSLShader* const& rhs) + { + return lhs->mTimeElapsed < rhs->mTimeElapsed; + } +}; + +//static +void LLGLSLShader::finishProfile(bool emit_report) +{ + sProfileEnabled = false; + + if (emit_report) + { + std::vector sorted; + + for (std::set::iterator iter = sInstances.begin(); iter != sInstances.end(); ++iter) + { + sorted.push_back(*iter); + } + + std::sort(sorted.begin(), sorted.end(), LLGLSLShaderCompareTimeElapsed()); + + for (std::vector::iterator iter = sorted.begin(); iter != sorted.end(); ++iter) + { + (*iter)->dumpStats(); + } + + LL_INFOS() << "-----------------------------------" << LL_ENDL; + LL_INFOS() << "Total rendering time: " << llformat("%.4f ms", sTotalTimeElapsed/1000000.f) << LL_ENDL; + LL_INFOS() << "Total samples drawn: " << llformat("%.4f million", sTotalSamplesDrawn/1000000.f) << LL_ENDL; + LL_INFOS() << "Total triangles drawn: " << llformat("%.3f million", sTotalTrianglesDrawn/1000000.f) << LL_ENDL; + } +} + +void LLGLSLShader::clearStats() +{ + mTrianglesDrawn = 0; + mTimeElapsed = 0; + mSamplesDrawn = 0; + mDrawCalls = 0; + mTextureStateFetched = false; + mTextureMagFilter.clear(); + mTextureMinFilter.clear(); +} + +void LLGLSLShader::dumpStats() +{ + if (mDrawCalls > 0) + { + LL_INFOS() << "=============================================" << LL_ENDL; + LL_INFOS() << mName << LL_ENDL; + for (U32 i = 0; i < mShaderFiles.size(); ++i) + { + LL_INFOS() << mShaderFiles[i].first << LL_ENDL; + } + for (U32 i = 0; i < mTexture.size(); ++i) + { + GLint idx = mTexture[i]; + + if (idx >= 0) + { + GLint uniform_idx = getUniformLocation(i); + LL_INFOS() << mUniformNameMap[uniform_idx] << " - " << std::hex << mTextureMagFilter[i] << "/" << mTextureMinFilter[i] << std::dec << LL_ENDL; + } + } + LL_INFOS() << "=============================================" << LL_ENDL; + + F32 ms = mTimeElapsed/1000000.f; + F32 seconds = ms/1000.f; + + F32 pct_tris = (F32) mTrianglesDrawn/(F32)sTotalTrianglesDrawn*100.f; + F32 tris_sec = (F32) (mTrianglesDrawn/1000000.0); + tris_sec /= seconds; + + F32 pct_samples = (F32) ((F64)mSamplesDrawn/(F64)sTotalSamplesDrawn)*100.f; + F32 samples_sec = (F32) mSamplesDrawn/1000000000.0; + samples_sec /= seconds; + + F32 pct_calls = (F32) mDrawCalls/(F32)sTotalDrawCalls*100.f; + U32 avg_batch = mTrianglesDrawn/mDrawCalls; + + LL_INFOS() << "Triangles Drawn: " << mTrianglesDrawn << " " << llformat("(%.2f pct of total, %.3f million/sec)", pct_tris, tris_sec ) << LL_ENDL; + LL_INFOS() << "Draw Calls: " << mDrawCalls << " " << llformat("(%.2f pct of total, avg %d tris/call)", pct_calls, avg_batch) << LL_ENDL; + LL_INFOS() << "SamplesDrawn: " << mSamplesDrawn << " " << llformat("(%.2f pct of total, %.3f billion/sec)", pct_samples, samples_sec) << LL_ENDL; + LL_INFOS() << "Time Elapsed: " << mTimeElapsed << " " << llformat("(%.2f pct of total, %.5f ms)\n", (F32) ((F64)mTimeElapsed/(F64)sTotalTimeElapsed)*100.f, ms) << LL_ENDL; + } +} + +//static +void LLGLSLShader::startProfile() +{ + if (sProfileEnabled && sCurBoundShaderPtr) + { + sCurBoundShaderPtr->placeProfileQuery(); + } + +} + +//static +void LLGLSLShader::stopProfile(U32 count, U32 mode) +{ + if (sProfileEnabled && sCurBoundShaderPtr) + { + sCurBoundShaderPtr->readProfileQuery(count, mode); + } +} + +void LLGLSLShader::placeProfileQuery() +{ +#if !LL_DARWIN + if (mTimerQuery == 0) + { + glGenQueriesARB(1, &mSamplesQuery); + glGenQueriesARB(1, &mTimerQuery); + } + + if (!mTextureStateFetched) + { + mTextureStateFetched = true; + mTextureMagFilter.resize(mTexture.size()); + mTextureMinFilter.resize(mTexture.size()); + + U32 cur_active = gGL.getCurrentTexUnitIndex(); + + for (U32 i = 0; i < mTexture.size(); ++i) + { + GLint idx = mTexture[i]; + + if (idx >= 0) + { + gGL.getTexUnit(idx)->activate(); + + U32 mag = 0xFFFFFFFF; + U32 min = 0xFFFFFFFF; + + U32 type = LLTexUnit::getInternalType(gGL.getTexUnit(idx)->getCurrType()); + + glGetTexParameteriv(type, GL_TEXTURE_MAG_FILTER, (GLint*) &mag); + glGetTexParameteriv(type, GL_TEXTURE_MIN_FILTER, (GLint*) &min); + + mTextureMagFilter[i] = mag; + mTextureMinFilter[i] = min; + } + } + + gGL.getTexUnit(cur_active)->activate(); + } + + + glBeginQueryARB(GL_SAMPLES_PASSED, mSamplesQuery); + glBeginQueryARB(GL_TIME_ELAPSED, mTimerQuery); +#endif +} + +void LLGLSLShader::readProfileQuery(U32 count, U32 mode) +{ +#if !LL_DARWIN + glEndQueryARB(GL_TIME_ELAPSED); + glEndQueryARB(GL_SAMPLES_PASSED); + + GLuint64 time_elapsed = 0; + glGetQueryObjectui64vEXT(mTimerQuery, GL_QUERY_RESULT, &time_elapsed); + + GLuint64 samples_passed = 0; + glGetQueryObjectui64vEXT(mSamplesQuery, GL_QUERY_RESULT, &samples_passed); + + sTotalTimeElapsed += time_elapsed; + mTimeElapsed += time_elapsed; + + sTotalSamplesDrawn += samples_passed; + mSamplesDrawn += samples_passed; + + U32 tri_count = 0; + switch (mode) + { + case LLRender::TRIANGLES: tri_count = count/3; break; + case LLRender::TRIANGLE_FAN: tri_count = count-2; break; + case LLRender::TRIANGLE_STRIP: tri_count = count-2; break; + default: tri_count = count; break; //points lines etc just use primitive count + } + + mTrianglesDrawn += tri_count; + sTotalTrianglesDrawn += tri_count; + + sTotalDrawCalls++; + mDrawCalls++; +#endif +} LLGLSLShader::LLGLSLShader(S32 shader_class) -: mProgramObject(0), mShaderClass(shader_class), mActiveTextureChannels(0), mShaderLevel(0), mShaderGroup(SG_DEFAULT), mUniformsDirty(FALSE) + : mProgramObject(0), + mShaderClass(shader_class), + mAttributeMask(0), + mTotalUniformSize(0), + mActiveTextureChannels(0), + mShaderLevel(0), + mShaderGroup(SG_DEFAULT), + mUniformsDirty(FALSE), + mTimerQuery(0), + mLightHash(0), + mSamplesQuery(0) + { LLShaderMgr::getGlobalShaderList().push_back(this); } +LLGLSLShader::~LLGLSLShader() +{ +} + void LLGLSLShader::unload() { - stop_glerror(); - mAttribute.clear(); + sInstances.erase(this); + + stop_glerror(); + mAttribute.clear(); mTexture.clear(); mUniform.clear(); mShaderFiles.clear(); + mDefines.clear(); if (mProgramObject) { @@ -117,24 +348,38 @@ void LLGLSLShader::unload() glDeleteObjectARB(obj[i]); }*/ if(mProgramObject) - glDeleteObjectARB(mProgramObject); + glDeleteProgram(mProgramObject); mProgramObject = 0; } - - //hack to make apple not complain - glGetError(); - + + if (mTimerQuery) + { + glDeleteQueriesARB(1, &mTimerQuery); + mTimerQuery = 0; + } + + if (mSamplesQuery) + { + glDeleteQueriesARB(1, &mSamplesQuery); + mSamplesQuery = 0; + } + + //hack to make apple not complain + glGetError(); + stop_glerror(); } -BOOL LLGLSLShader::createShader(vector * attributes, - vector * uniforms, +BOOL LLGLSLShader::createShader(std::vector * attributes, + std::vector * uniforms, U32 varying_count, const char** varyings) { - //reloading, reset matrix hash values - for (U32 i = 0; i < LLRender::NUM_MATRIX_MODES; ++i) - { + sInstances.insert(this); + + //reloading, reset matrix hash values + for (U32 i = 0; i < LLRender::NUM_MATRIX_MODES; ++i) + { mMatHash[i] = 0xFFFFFFFF; } mLightHash = 0xFFFFFFFF; @@ -143,15 +388,20 @@ BOOL LLGLSLShader::createShader(vector * attributes, BOOL success = TRUE; if(mProgramObject) //purge the old program - glDeleteObjectARB(mProgramObject); + glDeleteProgram(mProgramObject); // Create program mProgramObject = glCreateProgramObjectARB(); +#if LL_DARWIN + // work-around missing mix(vec3,vec3,bvec3) + mDefines["OLD_SELECT"] = "1"; +#endif + //compile new source vector< pair >::iterator fileIter = mShaderFiles.begin(); for ( ; fileIter != mShaderFiles.end(); fileIter++ ) { - GLhandleARB shaderhandle = LLShaderMgr::instance()->loadShaderFile((*fileIter).first, mShaderLevel, (*fileIter).second, mFeatures.mIndexedTextureChannels); + GLhandleARB shaderhandle = LLShaderMgr::instance()->loadShaderFile((*fileIter).first, mShaderLevel, (*fileIter).second, &mDefines, mFeatures.mIndexedTextureChannels); LL_DEBUGS("ShaderLoading") << "SHADER FILE: " << (*fileIter).first << " mShaderLevel=" << mShaderLevel << LL_ENDL; if (shaderhandle > 0) { @@ -164,10 +414,10 @@ BOOL LLGLSLShader::createShader(vector * attributes, } // Attach existing objects - if (!LLShaderMgr::instance()->attachShaderFeatures(this)) + if (!LLShaderMgr::instance()->attachClassSharedShaders(*this, mShaderClass) || !LLShaderMgr::instance()->attachShaderFeatures(this)) { if(mProgramObject) - glDeleteObjectARB(mProgramObject); + glDeleteProgram(mProgramObject); mProgramObject = 0; return FALSE; } @@ -197,7 +447,7 @@ BOOL LLGLSLShader::createShader(vector * attributes, if( !success ) { if(mProgramObject) - glDeleteObjectARB(mProgramObject); + glDeleteProgram(mProgramObject); mProgramObject = 0; LL_WARNS("ShaderLoading") << "Failed to link shader: " << mName << LL_ENDL; @@ -210,30 +460,17 @@ BOOL LLGLSLShader::createShader(vector * attributes, return createShader(attributes,uniforms); } } - else if (mFeatures.mIndexedTextureChannels > 0) - { //override texture channels for indexed texture rendering - bind(); - S32 channel_count = mFeatures.mIndexedTextureChannels; - - for (S32 i = 0; i < channel_count; i++) - { - uniform1i(llformat("tex%d", i), i); - } - S32 cur_tex = channel_count; //adjust any texture channels that might have been overwritten - for (U32 i = 0; i < mTexture.size(); i++) - { - if (mTexture[i] > -1 && mTexture[i] < channel_count) - { - llassert(cur_tex < gGLManager.mNumTextureImageUnits); - uniform1i(i, cur_tex); - mTexture[i] = cur_tex++; - } - } - unbind(); - } + if (LLShaderMgr::instance()->mProgramObjects.find(mName) == LLShaderMgr::instance()->mProgramObjects.end()) + { + LLShaderMgr::instance()->mProgramObjects.emplace(mName, mProgramObject); + } + else + { + LL_WARNS("ShaderLoading") << "Attempting to create shader program with duplicate name: " << mName << LL_ENDL; + } - return success; + return success; } BOOL LLGLSLShader::attachObject(std::string object) @@ -263,13 +500,13 @@ void LLGLSLShader::attachObject(GLhandleARB object) { if((*it).second.mHandle == object) { - LL_DEBUGS("ShaderLoading") << "Attached: " << (*it).first << llendl; + LL_INFOS("ShaderLoading") << "Attached: " << (*it).first << LL_ENDL; break; } } if(it == LLShaderMgr::instance()->mShaderObjects.end()) { - LL_WARNS("ShaderLoading") << "Attached unknown shader!" << llendl; + LL_WARNS("ShaderLoading") << "Attached unknown shader!" << LL_ENDL; } stop_glerror(); @@ -290,7 +527,7 @@ void LLGLSLShader::attachObjects(GLhandleARB* objects, S32 count) } } -BOOL LLGLSLShader::mapAttributes(const vector * attributes) +BOOL LLGLSLShader::mapAttributes(const std::vector * attributes) { //before linking, make sure reserved attributes always have consistent locations for (U32 i = 0; i < LLShaderMgr::instance()->mReservedAttribs.size(); i++) @@ -309,6 +546,8 @@ BOOL LLGLSLShader::mapAttributes(const vector * attributes) if (res) { //read back channel locations + mAttributeMask = 0; + //read back reserved channels first for (U32 i = 0; i < (S32) LLShaderMgr::instance()->mReservedAttribs.size(); i++) { @@ -317,6 +556,7 @@ BOOL LLGLSLShader::mapAttributes(const vector * attributes) if (index != -1) { mAttribute[i] = index; + mAttributeMask |= 1 << i; LL_DEBUGS("ShaderLoading") << "Attribute " << name << " assigned to channel " << index << LL_ENDL; } } @@ -324,7 +564,7 @@ BOOL LLGLSLShader::mapAttributes(const vector * attributes) { for (U32 i = 0; i < numAttributes; i++) { - const char* name = (*attributes)[i].c_str(); + const char* name = (*attributes)[i].String().c_str(); S32 index = glGetAttribLocationARB(mProgramObject, name); if (index != -1) { @@ -340,20 +580,54 @@ BOOL LLGLSLShader::mapAttributes(const vector * attributes) return FALSE; } -void LLGLSLShader::mapUniform(GLint index, const vector * uniforms) -{ - if (index == -1) - { - return; +void LLGLSLShader::mapUniform(const gl_uniform_data_t& gl_uniform, const vector * uniforms) +{ + GLint size = gl_uniform.size; + char* name = (char*)gl_uniform.name.c_str(); //blegh +#if !LL_DARWIN + if (size > 0) + { + switch(gl_uniform.type) + { + case GL_FLOAT_VEC2: size *= 2; break; + case GL_FLOAT_VEC3: size *= 3; break; + case GL_FLOAT_VEC4: size *= 4; break; + case GL_DOUBLE: size *= 2; break; + case GL_DOUBLE_VEC2: size *= 2; break; + case GL_DOUBLE_VEC3: size *= 6; break; + case GL_DOUBLE_VEC4: size *= 8; break; + case GL_INT_VEC2: size *= 2; break; + case GL_INT_VEC3: size *= 3; break; + case GL_INT_VEC4: size *= 4; break; + case GL_UNSIGNED_INT_VEC2: size *= 2; break; + case GL_UNSIGNED_INT_VEC3: size *= 3; break; + case GL_UNSIGNED_INT_VEC4: size *= 4; break; + case GL_BOOL_VEC2: size *= 2; break; + case GL_BOOL_VEC3: size *= 3; break; + case GL_BOOL_VEC4: size *= 4; break; + case GL_FLOAT_MAT2: size *= 4; break; + case GL_FLOAT_MAT3: size *= 9; break; + case GL_FLOAT_MAT4: size *= 16; break; + case GL_FLOAT_MAT2x3: size *= 6; break; + case GL_FLOAT_MAT2x4: size *= 8; break; + case GL_FLOAT_MAT3x2: size *= 6; break; + case GL_FLOAT_MAT3x4: size *= 12; break; + case GL_FLOAT_MAT4x2: size *= 8; break; + case GL_FLOAT_MAT4x3: size *= 12; break; + case GL_DOUBLE_MAT2: size *= 8; break; + case GL_DOUBLE_MAT3: size *= 18; break; + case GL_DOUBLE_MAT4: size *= 32; break; + case GL_DOUBLE_MAT2x3: size *= 12; break; + case GL_DOUBLE_MAT2x4: size *= 16; break; + case GL_DOUBLE_MAT3x2: size *= 12; break; + case GL_DOUBLE_MAT3x4: size *= 24; break; + case GL_DOUBLE_MAT4x2: size *= 16; break; + case GL_DOUBLE_MAT4x3: size *= 24; break; + } + mTotalUniformSize += size; } +#endif - GLenum type; - GLsizei length; - GLint size; - char name[1024]; /* Flawfinder: ignore */ - name[0] = 0; - - glGetActiveUniformARB(mProgramObject, index, 1024, &length, &size, &type, (GLcharARB *)name); S32 location = glGetUniformLocationARB(mProgramObject, name); if (location != -1) { @@ -365,44 +639,68 @@ void LLGLSLShader::mapUniform(GLint index, const vector * uniforms) is_array[0] = 0; } - mUniformMap[name] = location; + LLStaticHashedString hashedName(name); + mUniformNameMap[location] = name; + mUniformMap[hashedName] = location; + LL_DEBUGS("ShaderLoading") << "Uniform " << name << " is at location " << location << LL_ENDL; + + // Indexed textures are referenced by hardcoded tex unit index. This is where that mapping happens. + if (gl_uniform.texunit_priority < (U32)mFeatures.mIndexedTextureChannels) + { + // mUniform and mTexture are irrelivant for indexed textures, since there's no enum to look them up through. + // Thus, only call mapUniformTextureChannel to create the texunit => uniform location mapping in opengl. + mapUniformTextureChannel(location, gl_uniform.type); + return; + } //find the index of this uniform - for (S32 i = 0; i < (S32) LLShaderMgr::instance()->mReservedUniforms.size(); i++) + for (U32 i = 0; i < LLShaderMgr::instance()->mReservedUniforms.size(); i++) { if ( (mUniform[i] == -1) && (LLShaderMgr::instance()->mReservedUniforms[i] == name)) { //found it mUniform[i] = location; - mTexture[i] = mapUniformTextureChannel(location, type); + mTexture[i] = mapUniformTextureChannel(location, gl_uniform.type); return; } } if (uniforms != NULL) { - for (U32 i = 0; i < uniforms->size(); i++) + U32 j = LLShaderMgr::instance()->mReservedUniforms.size(); + for (U32 i = 0; i < uniforms->size(); i++, j++) { - if ( (mUniform[i+LLShaderMgr::instance()->mReservedUniforms.size()] == -1) - && ((*uniforms)[i] == name)) + if ( (mUniform[j] == -1) + && ((*uniforms)[i].String() == name)) { //found it - mUniform[i+LLShaderMgr::instance()->mReservedUniforms.size()] = location; - mTexture[i+LLShaderMgr::instance()->mReservedUniforms.size()] = mapUniformTextureChannel(location, type); + mUniform[j] = location; + mTexture[j] = mapUniformTextureChannel(location, gl_uniform.type);; return; } } } } - } +} + +void LLGLSLShader::addPermutation(std::string name, std::string value) +{ + mDefines[name] = value; +} + +void LLGLSLShader::removePermutation(std::string name) +{ + mDefines[name].erase(); +} GLint LLGLSLShader::mapUniformTextureChannel(GLint location, GLenum type) { if (type >= GL_SAMPLER_1D_ARB && type <= GL_SAMPLER_2D_RECT_SHADOW_ARB /*|| type == GL_SAMPLER_2D_MULTISAMPLE*/) { //this here is a texture + gGL.syncShaders(); glUniform1iARB(location, mActiveTextureChannels); LL_DEBUGS("ShaderLoading") << "Assigned to texture channel " << mActiveTextureChannels << LL_ENDL; return mActiveTextureChannels++; @@ -410,33 +708,93 @@ GLint LLGLSLShader::mapUniformTextureChannel(GLint location, GLenum type) return -1; } -BOOL LLGLSLShader::mapUniforms(const vector * uniforms) +BOOL LLGLSLShader::mapUniforms(const vector * uniforms) { BOOL res = TRUE; + + auto& reservedUniforms = LLShaderMgr::instance()->mReservedUniforms; + mTotalUniformSize = 0; mActiveTextureChannels = 0; mUniform.clear(); mUniformMap.clear(); + mUniformNameMap.clear(); mTexture.clear(); - mValue.clear(); + mValueVec4.clear(); + mValueMat3.clear(); + mValueMat4.clear(); //initialize arrays U32 numUniforms = (uniforms == NULL) ? 0 : uniforms->size(); - mUniform.resize(numUniforms + LLShaderMgr::instance()->mReservedUniforms.size(), -1); - mTexture.resize(numUniforms + LLShaderMgr::instance()->mReservedUniforms.size(), -1); + mUniform.resize(numUniforms + reservedUniforms.size(), -1); + mTexture.resize(numUniforms + reservedUniforms.size(), -1); bind(); //get the number of active uniforms GLint activeCount; - glGetObjectParameterivARB(mProgramObject, GL_OBJECT_ACTIVE_UNIFORMS_ARB, &activeCount); + glGetProgramiv(mProgramObject, GL_OBJECT_ACTIVE_UNIFORMS_ARB, &activeCount); + std::vector< gl_uniform_data_t > gl_uniforms; + + bool has_diffuse = false; + U32 max_index = mFeatures.mIndexedTextureChannels; + // Gather active uniforms. for (S32 i = 0; i < activeCount; i++) { - mapUniform(i, uniforms); + // Fetch name and size from opengl + char name[1024]; + gl_uniform_data_t gl_uniform; + GLsizei length; + glGetActiveUniformARB(mProgramObject, i, 1024, &length, &gl_uniform.size, &gl_uniform.type, (GLcharARB *)name); + if (length && name[length - 1] == '\0') + { + --length; // Some drivers can't be trusted... + } + if (gl_uniform.size < 0 || length <= 0) + continue; + gl_uniform.name = std::string(name, length); + + // Track if diffuseMap uniform was detected. If so, flag as such to assert indexed textures aren't also used in this shader. + has_diffuse |= gl_uniform.name == "diffuseMap"; + + // Use mReservedUniforms to calculate texunit ordering. Reserve priority [0,max_index) for indexed textures if applicable. + auto it = std::find(reservedUniforms.begin(), reservedUniforms.end(), gl_uniform.name); + gl_uniform.texunit_priority = it != reservedUniforms.end() ? max_index + std::distance(reservedUniforms.begin(), it) : UINT_MAX; + + // Indexed texture uniforms must ALWAYS have highest texunit priority. Ensures [texunit[0],texunit[max_index]) map to [tex[0],tex[max_index]) uniforms. + // Note that this logic will break if a tex# index is skipped over in the shader. + if (gl_uniform.texunit_priority == UINT_MAX) + { + S32 idx; + if (sscanf(gl_uniform.name.c_str(), "tex%d", &idx)) + { + gl_uniform.texunit_priority = idx; + } + } + + gl_uniforms.push_back(gl_uniform); + } + + // Sort uniforms by texunit_priority + std::sort(gl_uniforms.begin(), gl_uniforms.end(), [](gl_uniform_data_t& lhs, gl_uniform_data_t& rhs) + { + return lhs.texunit_priority < rhs.texunit_priority; + }); + + // Sanity check + if (gl_uniforms.size() && gl_uniforms[0].name == "tex0") + { + llassert_always_msg(!has_diffuse, "Indexed textures and diffuseMap are incompatible!"); + } + + for (auto& gl_uniform : gl_uniforms) + { + mapUniform(gl_uniform, uniforms); } unbind(); + LL_DEBUGS("ShaderLoading") << "Total Uniform Size: " << mTotalUniformSize << LL_ENDL; return res; } @@ -451,7 +809,7 @@ void LLGLSLShader::bind() if (gGLManager.mHasShaderObjects) { LLVertexBuffer::unbind(); - glUseProgramObjectARB(mProgramObject); + gGL.setShader(mProgramObject); sCurBoundShader = mProgramObject; sCurBoundShaderPtr = this; if (mUniformsDirty) @@ -477,7 +835,7 @@ void LLGLSLShader::unbind() } } LLVertexBuffer::unbind(); - glUseProgramObjectARB(0); + gGL.setShader(0); sCurBoundShader = 0; sCurBoundShaderPtr = NULL; stop_glerror(); @@ -489,12 +847,64 @@ void LLGLSLShader::bindNoShader(void) LLVertexBuffer::unbind(); if (gGLManager.mHasShaderObjects) { - glUseProgramObjectARB(0); + gGL.setShader(0); sCurBoundShader = 0; sCurBoundShaderPtr = NULL; } } +S32 LLGLSLShader::bindTexture(const std::string &uniform, LLTexture *texture, LLTexUnit::eTextureType mode) +{ + S32 channel = 0; + channel = getUniformLocation(uniform); + + return bindTexture(channel, texture, mode); +} + +S32 LLGLSLShader::bindTexture(S32 uniform, LLTexture *texture, LLTexUnit::eTextureType mode) +{ + if (uniform < 0 || uniform >= (S32)mTexture.size()) + { + UNIFORM_ERRS << "Uniform out of range: " << uniform << LL_ENDL; + return -1; + } + + uniform = mTexture[uniform]; + + if (uniform > -1) + { + gGL.getTexUnit(uniform)->bind(texture, mode); + } + + return uniform; +} + +S32 LLGLSLShader::unbindTexture(const std::string &uniform, LLTexUnit::eTextureType mode) +{ + S32 channel = 0; + channel = getUniformLocation(uniform); + + return unbindTexture(channel); +} + +S32 LLGLSLShader::unbindTexture(S32 uniform, LLTexUnit::eTextureType mode) +{ + if (uniform < 0 || uniform >= (S32)mTexture.size()) + { + UNIFORM_ERRS << "Uniform out of range: " << uniform << LL_ENDL; + return -1; + } + + uniform = mTexture[uniform]; + + if (uniform > -1) + { + gGL.getTexUnit(uniform)->unbind(mode); + } + + return uniform; +} + S32 LLGLSLShader::enableTexture(S32 uniform, LLTexUnit::eTextureType mode) { if (uniform < 0 || uniform >= (S32)mTexture.size()) @@ -530,7 +940,7 @@ S32 LLGLSLShader::disableTexture(S32 uniform, LLTexUnit::eTextureType mode) } else { - llerrs << "Texture channel " << index << " texture type corrupted." << llendl; + LL_ERRS() << "Texture channel " << index << " texture type corrupted." << LL_ENDL; } } gGL.getTexUnit(index)->disable(); @@ -538,309 +948,6 @@ S32 LLGLSLShader::disableTexture(S32 uniform, LLTexUnit::eTextureType mode) return index; } -void LLGLSLShader::uniform1i(U32 index, GLint x) -{ - if (mProgramObject > 0) - { - if (mUniform.size() <= index) - { - UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL; - return; - } - - if (mUniform[index] >= 0) - { - std::map::iterator iter = mValue.find(mUniform[index]); - if (iter == mValue.end() || iter->second.mV[0] != x) - { - glUniform1iARB(mUniform[index], x); - mValue[mUniform[index]] = LLVector4(x,0.f,0.f,0.f); - } - } - } -} - -void LLGLSLShader::uniform1f(U32 index, GLfloat x) -{ - if (mProgramObject > 0) - { - if (mUniform.size() <= index) - { - UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL; - return; - } - - if (mUniform[index] >= 0) - { - std::map::iterator iter = mValue.find(mUniform[index]); - if (iter == mValue.end() || iter->second.mV[0] != x) - { - glUniform1fARB(mUniform[index], x); - mValue[mUniform[index]] = LLVector4(x,0.f,0.f,0.f); - } - } - } -} - -void LLGLSLShader::uniform2f(U32 index, GLfloat x, GLfloat y) -{ - if (mProgramObject > 0) - { - if (mUniform.size() <= index) - { - UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL; - return; - } - - if (mUniform[index] >= 0) - { - std::map::iterator iter = mValue.find(mUniform[index]); - LLVector4 vec(x,y,0.f,0.f); - if (iter == mValue.end() || shouldChange(iter->second,vec)) - { - glUniform2fARB(mUniform[index], x, y); - mValue[mUniform[index]] = vec; - } - } - } -} - -void LLGLSLShader::uniform3f(U32 index, GLfloat x, GLfloat y, GLfloat z) -{ - if (mProgramObject > 0) - { - if (mUniform.size() <= index) - { - UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL; - return; - } - - if (mUniform[index] >= 0) - { - std::map::iterator iter = mValue.find(mUniform[index]); - LLVector4 vec(x,y,z,0.f); - if (iter == mValue.end() || shouldChange(iter->second,vec)) - { - glUniform3fARB(mUniform[index], x, y, z); - mValue[mUniform[index]] = vec; - } - } - } -} - -void LLGLSLShader::uniform4f(U32 index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) -{ - if (mProgramObject > 0) - { - if (mUniform.size() <= index) - { - UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL; - return; - } - - if (mUniform[index] >= 0) - { - std::map::iterator iter = mValue.find(mUniform[index]); - LLVector4 vec(x,y,z,w); - if (iter == mValue.end() || shouldChange(iter->second,vec)) - { - glUniform4fARB(mUniform[index], x, y, z, w); - mValue[mUniform[index]] = vec; - } - } - } -} - -void LLGLSLShader::uniform1iv(U32 index, U32 count, const GLint* v) -{ - if (mProgramObject > 0) - { - if (mUniform.size() <= index) - { - UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL; - return; - } - - if (mUniform[index] >= 0) - { - std::map::iterator iter = mValue.find(mUniform[index]); - LLVector4 vec(v[0],0.f,0.f,0.f); - if (iter == mValue.end() || shouldChange(iter->second,vec) || count != 1) - { - glUniform1ivARB(mUniform[index], count, v); - mValue[mUniform[index]] = vec; - } - } - } -} - -void LLGLSLShader::uniform1fv(U32 index, U32 count, const GLfloat* v) -{ - if (mProgramObject > 0) - { - if (mUniform.size() <= index) - { - UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL; - return; - } - - if (mUniform[index] >= 0) - { - std::map::iterator iter = mValue.find(mUniform[index]); - LLVector4 vec(v[0],0.f,0.f,0.f); - if (iter == mValue.end() || shouldChange(iter->second,vec) || count != 1) - { - glUniform1fvARB(mUniform[index], count, v); - mValue[mUniform[index]] = vec; - } - } - } -} - -void LLGLSLShader::uniform2fv(U32 index, U32 count, const GLfloat* v) -{ - if (mProgramObject > 0) - { - if (mUniform.size() <= index) - { - UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL; - return; - } - - if (mUniform[index] >= 0) - { - std::map::iterator iter = mValue.find(mUniform[index]); - LLVector4 vec(v[0],v[1],0.f,0.f); - if (iter == mValue.end() || shouldChange(iter->second,vec) || count != 1) - { - glUniform2fvARB(mUniform[index], count, v); - mValue[mUniform[index]] = vec; - } - } - } -} - -void LLGLSLShader::uniform3fv(U32 index, U32 count, const GLfloat* v) -{ - if (mProgramObject > 0) - { - if (mUniform.size() <= index) - { - UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL; - return; - } - - if (mUniform[index] >= 0) - { - std::map::iterator iter = mValue.find(mUniform[index]); - LLVector4 vec(v[0],v[1],v[2],0.f); - if (iter == mValue.end() || shouldChange(iter->second,vec) || count != 1) - { - glUniform3fvARB(mUniform[index], count, v); - mValue[mUniform[index]] = vec; - } - } - } -} - -void LLGLSLShader::uniform4fv(U32 index, U32 count, const GLfloat* v) -{ - if (mProgramObject > 0) - { - if (mUniform.size() <= index) - { - UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL; - return; - } - - if (mUniform[index] >= 0) - { - std::map::iterator iter = mValue.find(mUniform[index]); - LLVector4 vec(v[0],v[1],v[2],v[3]); - if (iter == mValue.end() || shouldChange(iter->second,vec) || count != 1) - { - glUniform4fvARB(mUniform[index], count, v); - mValue[mUniform[index]] = vec; - } - } - } -} - -void LLGLSLShader::uniformMatrix2fv(U32 index, U32 count, GLboolean transpose, const GLfloat *v) -{ - if (mProgramObject > 0) - { - if (mUniform.size() <= index) - { - UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL; - return; - } - - if (mUniform[index] >= 0) - { - glUniformMatrix2fvARB(mUniform[index], count, transpose, v); - } - } -} - -void LLGLSLShader::uniformMatrix3fv(U32 index, U32 count, GLboolean transpose, const GLfloat *v) -{ - if (mProgramObject > 0) - { - if (mUniform.size() <= index) - { - UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL; - return; - } - - if (mUniform[index] >= 0) - { - glUniformMatrix3fvARB(mUniform[index], count, transpose, v); - } - } -} - -void LLGLSLShader::uniformMatrix4fv(U32 index, U32 count, GLboolean transpose, const GLfloat *v) -{ - if (mProgramObject > 0) - { - if (mUniform.size() <= index) - { - UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL; - return; - } - - if (mUniform[index] >= 0) - { - glUniformMatrix4fvARB(mUniform[index], count, transpose, v); - } - } -} - -GLint LLGLSLShader::getUniformLocation(const string& uniform) -{ - GLint ret = -1; - if (mProgramObject > 0) - { - std::map::iterator iter = mUniformMap.find(uniform); - if (iter != mUniformMap.end()) - { - if (gDebugGL) - { - stop_glerror(); - if (iter->second != glGetUniformLocationARB(mProgramObject, uniform.c_str())) - { - llerrs << "Uniform does not match." << llendl; - } - stop_glerror(); - } - ret = iter->second; - } - } - - return ret; -} - GLint LLGLSLShader::getUniformLocation(U32 index) { GLint ret = -1; @@ -865,186 +972,6 @@ GLint LLGLSLShader::getAttribLocation(U32 attrib) } } -void LLGLSLShader::uniform1i(const string& uniform, GLint v) -{ - GLint location = getUniformLocation(uniform); - - if (location >= 0) - { - std::map::iterator iter = mValue.find(location); - LLVector4 vec(v,0.f,0.f,0.f); - if (iter == mValue.end() || shouldChange(iter->second,vec)) - { - glUniform1iARB(location, v); - mValue[location] = vec; - } - } -} - -void LLGLSLShader::uniform1f(const string& uniform, GLfloat v) -{ - GLint location = getUniformLocation(uniform); - - if (location >= 0) - { - std::map::iterator iter = mValue.find(location); - LLVector4 vec(v,0.f,0.f,0.f); - if (iter == mValue.end() || shouldChange(iter->second,vec)) - { - glUniform1fARB(location, v); - mValue[location] = vec; - } - } -} - -void LLGLSLShader::uniform2f(const string& uniform, GLfloat x, GLfloat y) -{ - GLint location = getUniformLocation(uniform); - - if (location >= 0) - { - std::map::iterator iter = mValue.find(location); - LLVector4 vec(x,y,0.f,0.f); - if (iter == mValue.end() || shouldChange(iter->second,vec)) - { - glUniform2fARB(location, x,y); - mValue[location] = vec; - } - } - -} - -void LLGLSLShader::uniform3f(const string& uniform, GLfloat x, GLfloat y, GLfloat z) -{ - GLint location = getUniformLocation(uniform); - - if (location >= 0) - { - std::map::iterator iter = mValue.find(location); - LLVector4 vec(x,y,z,0.f); - if (iter == mValue.end() || shouldChange(iter->second,vec)) - { - glUniform3fARB(location, x,y,z); - mValue[location] = vec; - } - } -} - -void LLGLSLShader::uniform4f(const string& uniform, GLfloat x, GLfloat y, GLfloat z, GLfloat w) -{ - GLint location = getUniformLocation(uniform); - - if (location >= 0) - { - std::map::iterator iter = mValue.find(location); - LLVector4 vec(x,y,z,w); - if (iter == mValue.end() || shouldChange(iter->second,vec)) - { - glUniform4fARB(location, x,y,z,w); - mValue[location] = vec; - } - } -} - -void LLGLSLShader::uniform1fv(const string& uniform, U32 count, const GLfloat* v) -{ - GLint location = getUniformLocation(uniform); - - if (location >= 0) - { - std::map::iterator iter = mValue.find(location); - LLVector4 vec(v[0],0.f,0.f,0.f); - if (iter == mValue.end() || shouldChange(iter->second,vec) || count != 1) - { - glUniform1fvARB(location, count, v); - mValue[location] = vec; - } - } -} - -void LLGLSLShader::uniform2fv(const string& uniform, U32 count, const GLfloat* v) -{ - GLint location = getUniformLocation(uniform); - - if (location >= 0) - { - std::map::iterator iter = mValue.find(location); - LLVector4 vec(v[0],v[1],0.f,0.f); - if (iter == mValue.end() || shouldChange(iter->second,vec) || count != 1) - { - glUniform2fvARB(location, count, v); - mValue[location] = vec; - } - } -} - -void LLGLSLShader::uniform3fv(const string& uniform, U32 count, const GLfloat* v) -{ - GLint location = getUniformLocation(uniform); - - if (location >= 0) - { - std::map::iterator iter = mValue.find(location); - LLVector4 vec(v[0],v[1],v[2],0.f); - if (iter == mValue.end() || shouldChange(iter->second,vec) || count != 1) - { - glUniform3fvARB(location, count, v); - mValue[location] = vec; - } - } -} - -void LLGLSLShader::uniform4fv(const string& uniform, U32 count, const GLfloat* v) -{ - GLint location = getUniformLocation(uniform); - - if (location >= 0) - { - LLVector4 vec(v); - std::map::iterator iter = mValue.find(location); - if (iter == mValue.end() || shouldChange(iter->second,vec) || count != 1) - { - stop_glerror(); - glUniform4fvARB(location, count, v); - stop_glerror(); - mValue[location] = vec; - } - } -} - -void LLGLSLShader::uniformMatrix2fv(const string& uniform, U32 count, GLboolean transpose, const GLfloat* v) -{ - GLint location = getUniformLocation(uniform); - - if (location >= 0) - { - glUniformMatrix2fvARB(location, count, transpose, v); - } -} - -void LLGLSLShader::uniformMatrix3fv(const string& uniform, U32 count, GLboolean transpose, const GLfloat* v) -{ - GLint location = getUniformLocation(uniform); - - if (location >= 0) - { - glUniformMatrix3fvARB(location, count, transpose, v); - } -} - -void LLGLSLShader::uniformMatrix4fv(const string& uniform, U32 count, GLboolean transpose, const GLfloat* v) -{ - GLint location = getUniformLocation(uniform); - - if (location >= 0) - { - stop_glerror(); - glUniformMatrix4fvARB(location, count, transpose, v); - stop_glerror(); - } -} - - void LLGLSLShader::vertexAttrib4f(U32 index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) { if (mAttribute[index] > 0) @@ -1053,16 +980,7 @@ void LLGLSLShader::vertexAttrib4f(U32 index, GLfloat x, GLfloat y, GLfloat z, GL } } -void LLGLSLShader::vertexAttrib4fv(U32 index, GLfloat* v) -{ - if (mAttribute[index] > 0) - { - glVertexAttrib4fvARB(mAttribute[index], v); - } -} - void LLGLSLShader::setMinimumAlpha(F32 minimum) { - gGL.flush(); uniform1f(LLShaderMgr::MINIMUM_ALPHA, minimum); } diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h index a5817ce289..d1d9fde09e 100644 --- a/indra/llrender/llglslshader.h +++ b/indra/llrender/llglslshader.h @@ -29,6 +29,12 @@ #include "llgl.h" #include "llrender.h" +#include "llstaticstringtable.h" +#ifdef LL_RELEASE_FOR_DOWNLOAD +#define UNIFORM_ERRS LL_WARNS_ONCE("Shader") +#else +#define UNIFORM_ERRS LL_ERRS("Shader") +#endif class LLShaderFeatures { @@ -50,6 +56,7 @@ class LLShaderFeatures S32 mIndexedTextureChannels; bool disableTextureIndex; bool hasAlphaMask; + bool attachNothing; // char numLights; @@ -66,63 +73,329 @@ class LLGLSLShader SG_SKY, SG_WATER }; + + struct gl_uniform_data_t { + std::string name; + GLenum type = -1; + GLint size = -1; + U32 texunit_priority = UINT_MAX; // Lower gets earlier texunits indices. + }; + static std::set sInstances; + static bool sProfileEnabled; + LLGLSLShader(S32 shader_class); + ~LLGLSLShader(); static GLhandleARB sCurBoundShader; static LLGLSLShader* sCurBoundShaderPtr; + static S32 sIndexedTextureChannels; static bool sNoFixedFunction; + static void initProfile(); + static void finishProfile(bool emit_report = true); + + static void startProfile(); + static void stopProfile(U32 count, U32 mode); + void unload(); - BOOL createShader(std::vector * attributes, - std::vector * uniforms, + void clearStats(); + void dumpStats(); + void placeProfileQuery(); + void readProfileQuery(U32 count, U32 mode); + + BOOL createShader(std::vector * attributes, + std::vector * uniforms, U32 varying_count = 0, const char** varyings = NULL); BOOL attachObject(std::string object); void attachObject(GLhandleARB object); void attachObjects(GLhandleARB* objects = NULL, S32 count = 0); - BOOL mapAttributes(const std::vector * attributes); - BOOL mapUniforms(const std::vector * uniforms); - void mapUniform(GLint index, const std::vector * uniforms); - void uniform1i(U32 index, GLint i); - void uniform1f(U32 index, GLfloat v); - void uniform2f(U32 index, GLfloat x, GLfloat y); - void uniform3f(U32 index, GLfloat x, GLfloat y, GLfloat z); - void uniform4f(U32 index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); - void uniform1iv(U32 index, U32 count, const GLint* i); - void uniform1fv(U32 index, U32 count, const GLfloat* v); - void uniform2fv(U32 index, U32 count, const GLfloat* v); - void uniform3fv(U32 index, U32 count, const GLfloat* v); - void uniform4fv(U32 index, U32 count, const GLfloat* v); - void uniform1i(const std::string& uniform, GLint i); - void uniform1f(const std::string& uniform, GLfloat v); - void uniform2f(const std::string& uniform, GLfloat x, GLfloat y); - void uniform3f(const std::string& uniform, GLfloat x, GLfloat y, GLfloat z); - void uniform4f(const std::string& uniform, GLfloat x, GLfloat y, GLfloat z, GLfloat w); - void uniform1iv(const std::string& uniform, U32 count, const GLint* i); - void uniform1fv(const std::string& uniform, U32 count, const GLfloat* v); - void uniform2fv(const std::string& uniform, U32 count, const GLfloat* v); - void uniform3fv(const std::string& uniform, U32 count, const GLfloat* v); - void uniform4fv(const std::string& uniform, U32 count, const GLfloat* v); - void uniformMatrix2fv(U32 index, U32 count, GLboolean transpose, const GLfloat *v); - void uniformMatrix3fv(U32 index, U32 count, GLboolean transpose, const GLfloat *v); - void uniformMatrix4fv(U32 index, U32 count, GLboolean transpose, const GLfloat *v); - void uniformMatrix2fv(const std::string& uniform, U32 count, GLboolean transpose, const GLfloat *v); - void uniformMatrix3fv(const std::string& uniform, U32 count, GLboolean transpose, const GLfloat *v); - void uniformMatrix4fv(const std::string& uniform, U32 count, GLboolean transpose, const GLfloat *v); + BOOL mapAttributes(const std::vector * attributes); + BOOL mapUniforms(const std::vector *); + void mapUniform(const gl_uniform_data_t& gl_uniform, const std::vector *); + S32 getUniformFromIndex(const U32 index) + { + if (mUniform.size() <= index) + { + UNIFORM_ERRS << "Uniform index out of bounds." << LL_ENDL; + return -1; + } + return mUniform[index]; + } + template + S32 updateUniform(std::vector >& cache, S32 uniform, const F32* val) + { + if (mProgramObject > 0) + { + if (uniform >= 0) + { + typename std::vector >::iterator iter = std::find_if(cache.begin(), cache.end(), boost::bind(&std::pair::first, _1) == uniform); + if (iter == cache.end()) + { + T tmp; + memcpy(&tmp, val, sizeof(F32)*N); + cache.push_back(std::make_pair(uniform, tmp)); + return true; + } + else if (memcmp(&iter->second, val, sizeof(F32)*N)) + { + memcpy(&iter->second, val, sizeof(F32)*N); + return true; + } + } + } + return false; + } + void uniform1i(U32 index, GLint x) + { + F32 val = x; + if (updateUniform(mValueVec4, getUniformFromIndex(index), &val)) + { + gGL.syncShaders(); + glUniform1iARB(mUniform[index], x); + } + } + void uniform1f(U32 index, GLfloat x) + { + if (updateUniform(mValueVec4, getUniformFromIndex(index), &x)) + { + gGL.syncShaders(); + glUniform1fARB(mUniform[index], x); + } + } + void uniform2f(U32 index, GLfloat x, GLfloat y) + { + F32 val[] = { x, y }; + if (updateUniform(mValueVec4, getUniformFromIndex(index), val)) + { + gGL.syncShaders(); + glUniform2fARB(mUniform[index], x, y); + } + } + void uniform3f(U32 index, GLfloat x, GLfloat y, GLfloat z) + { + F32 val[] = { x, y, z }; + if (updateUniform(mValueVec4, getUniformFromIndex(index), val)) + { + gGL.syncShaders(); + glUniform3fARB(mUniform[index], x, y, z); + } + } + void uniform4f(U32 index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) + { + F32 val[] = { x, y, z, w }; + if (updateUniform(mValueVec4, getUniformFromIndex(index), val)) + { + gGL.syncShaders(); + glUniform4fARB(mUniform[index], x, y, z, w); + } + } + void uniform1iv(U32 index, U32 count, const GLint* v) + { + F32 val[] = { static_cast(v[0]) }; + if (updateUniform(mValueVec4, getUniformFromIndex(index), val) || count > 1) + { + gGL.syncShaders(); + glUniform1ivARB(mUniform[index], count, v); + } + } + void uniform1fv(U32 index, U32 count, const GLfloat* v) + { + if (updateUniform(mValueVec4, getUniformFromIndex(index), v) || count > 1) + { + gGL.syncShaders(); + glUniform1fvARB(mUniform[index], count, v); + } + } + void uniform2fv(U32 index, U32 count, const GLfloat* v) + { + if (updateUniform(mValueVec4, getUniformFromIndex(index), v) || count > 1) + { + gGL.syncShaders(); + glUniform2fvARB(mUniform[index], count, v); + } + } + void uniform3fv(U32 index, U32 count, const GLfloat* v) + { + if (updateUniform(mValueVec4, getUniformFromIndex(index), v) || count > 1) + { + gGL.syncShaders(); + glUniform3fvARB(mUniform[index], count, v); + } + } + void uniform4fv(U32 index, U32 count, const GLfloat* v) + { + if (updateUniform(mValueVec4, getUniformFromIndex(index), v) || count > 1) + { + gGL.syncShaders(); + glUniform4fvARB(mUniform[index], count, v); + } + } + void uniformMatrix3fv(U32 index, U32 count, GLboolean transpose, const GLfloat *v) + { + if (updateUniform(mValueMat3, getUniformFromIndex(index), v) || count > 1) + { + gGL.syncShaders(); + glUniformMatrix3fvARB(mUniform[index], count, transpose, v); + } + } + void uniformMatrix3x4fv(U32 index, U32 count, GLboolean transpose, const GLfloat *v) + { + if (updateUniform(mValueMat4, getUniformFromIndex(index), v) || count > 1) + { + gGL.syncShaders(); + glUniformMatrix3x4fv(mUniform[index], count, transpose, v); + } + } + void uniformMatrix4fv(U32 index, U32 count, GLboolean transpose, const GLfloat *v) + { + if (updateUniform(mValueMat4, getUniformFromIndex(index), v) || count > 1) + { + gGL.syncShaders(); + glUniformMatrix4fvARB(mUniform[index], count, transpose, v); + } + } + void uniform1i(const LLStaticHashedString& uniform, GLint i) + { + GLint location = getUniformLocation(uniform); + if (location < 0) + return; + F32 val = i; + if (updateUniform(mValueVec4, getUniformLocation(uniform), &val)) + { + gGL.syncShaders(); + glUniform1iARB(location, i); + } + } + void uniform1f(const LLStaticHashedString& uniform, GLfloat v) + { + GLint location = getUniformLocation(uniform); + if (location < 0) + return; + if (updateUniform(mValueVec4, location, &v)) + { + gGL.syncShaders(); + glUniform1fARB(location, v); + } + } + void uniform2f(const LLStaticHashedString& uniform, GLfloat x, GLfloat y) + { + GLint location = getUniformLocation(uniform); + if (location < 0) + return; + F32 val[] = { x, y }; + if (updateUniform(mValueVec4, location, val)) + { + gGL.syncShaders(); + glUniform2fARB(location, x, y); + } + } + void uniform3f(const LLStaticHashedString& uniform, GLfloat x, GLfloat y, GLfloat z) + { + GLint location = getUniformLocation(uniform); + if (location < 0) + return; + F32 val[] = { x, y, z }; + if (updateUniform(mValueVec4, location, val)) + { + gGL.syncShaders(); + glUniform3fARB(location, x, y, z); + } + } + void uniform1fv(const LLStaticHashedString& uniform, U32 count, const GLfloat* v) + { + GLint location = getUniformLocation(uniform); + if (location < 0) + return; + if (updateUniform(mValueVec4, location, v)) + { + gGL.syncShaders(); + glUniform1fvARB(location, count, v); + } + } + void uniform2fv(const LLStaticHashedString& uniform, U32 count, const GLfloat* v) + { + GLint location = getUniformLocation(uniform); + if (location < 0) + return; + if (updateUniform(mValueVec4, location, v)) + { + gGL.syncShaders(); + glUniform2fvARB(location, count, v); + } + } + void uniform3fv(const LLStaticHashedString& uniform, U32 count, const GLfloat* v) + { + GLint location = getUniformLocation(uniform); + if (location < 0) + return; + if (updateUniform(mValueVec4, location, v)) + { + gGL.syncShaders(); + glUniform3fvARB(location, count, v); + } + } + void uniform4fv(const LLStaticHashedString& uniform, U32 count, const GLfloat* v) + { + GLint location = getUniformLocation(uniform); + if (location < 0) + return; + if (updateUniform(mValueVec4, location, v)) + { + gGL.syncShaders(); + glUniform4fvARB(location, count, v); + } + } + void uniformMatrix4fv(const LLStaticHashedString& uniform, U32 count, GLboolean transpose, const GLfloat *v) + { + GLint location = getUniformLocation(uniform); + if (location < 0) + return; + if (updateUniform(mValueMat4, location, v)) + { + gGL.syncShaders(); + glUniformMatrix4fvARB(location, count, transpose, v); + } + } void setMinimumAlpha(F32 minimum); void vertexAttrib4f(U32 index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); - void vertexAttrib4fv(U32 index, GLfloat* v); - GLint getUniformLocation(const std::string& uniform); + GLint getUniformLocation(const LLStaticHashedString& uniform) + { + GLint ret = -1; + if (mProgramObject > 0) + { + LLStaticStringTable::iterator iter = mUniformMap.find(uniform); + if (iter != mUniformMap.end()) + { + if (gDebugGL) + { + gGL.syncShaders(); + stop_glerror(); + if (iter->second != glGetUniformLocationARB(mProgramObject, uniform.String().c_str())) + { + LL_ERRS() << "Uniform does not match." << LL_ENDL; + } + stop_glerror(); + } + ret = iter->second; + } + } + + return ret; + } GLint getUniformLocation(U32 index); GLint getAttribLocation(U32 attrib); GLint mapUniformTextureChannel(GLint location, GLenum type); + void addPermutation(std::string name, std::string value); + void removePermutation(std::string name); + //enable/disable texture channel for specified uniform //if given texture uniform is active in the shader, //the corresponding channel will be active upon return @@ -130,6 +403,13 @@ class LLGLSLShader S32 enableTexture(S32 uniform, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE); S32 disableTexture(S32 uniform, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE); + // bindTexture returns the texture unit we've bound the texture to. + // You can reuse the return value to unbind a texture when required. + S32 bindTexture(const std::string& uniform, LLTexture *texture, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE); + S32 bindTexture(S32 uniform, LLTexture *texture, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE); + S32 unbindTexture(const std::string& uniform, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE); + S32 unbindTexture(S32 uniform, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE); + BOOL link(BOOL suppress_errors = FALSE); void bind(); void unbind(); @@ -142,10 +422,17 @@ class LLGLSLShader GLhandleARB mProgramObject; std::vector mAttribute; //lookup table of attribute enum to attribute channel + U32 mAttributeMask; //mask of which reserved attributes are set (lines up with LLVertexBuffer::getTypeMask()) std::vector mUniform; //lookup table of uniform enum to uniform location - std::map mUniformMap; //lookup map of uniform name to uniform location - std::map mValue; //lookup map of uniform location to last known value - std::vector mTexture; + LLStaticStringTable mUniformMap; //lookup map of uniform name to uniform location + std::map mUniformNameMap; //lookup map of uniform location to uniform name + //There are less naive ways to do this than just having several vectors for the differing types, but this method is of least complexity and has some inherent type-safety. + std::vector > mValueVec4; //lookup map of uniform location to last known value + std::vector > mValueMat3; //lookup map of uniform location to last known value + std::vector > mValueMat4; //lookup map of uniform location to last known value + + std::vector mTexture; //lookup table of texture uniform enum to texture channel + S32 mTotalUniformSize; S32 mActiveTextureChannels; S32 mShaderClass; S32 mShaderLevel; @@ -154,6 +441,24 @@ class LLGLSLShader LLShaderFeatures mFeatures; std::vector< std::pair< std::string, GLenum > > mShaderFiles; std::string mName; + std::map mDefines; + + //statistcis for profiling shader performance + U32 mTimerQuery; + U32 mSamplesQuery; + U64 mTimeElapsed; + static U64 sTotalTimeElapsed; + U32 mTrianglesDrawn; + static U32 sTotalTrianglesDrawn; + U64 mSamplesDrawn; + static U64 sTotalSamplesDrawn; + U32 mDrawCalls; + static U32 sTotalDrawCalls; + + bool mTextureStateFetched; + std::vector mTextureMagFilter; + std::vector mTextureMinFilter; + }; //UI shader (declared here so llui_libtest will link properly) diff --git a/indra/llrender/llglstates.h b/indra/llrender/llglstates.h index 266f266a6a..3a81eac94f 100644 --- a/indra/llrender/llglstates.h +++ b/indra/llrender/llglstates.h @@ -53,181 +53,128 @@ class LLGLDepthTest //---------------------------------------------------------------------------- -class LLGLSDefault +struct LLGLSDefault { -protected: - LLGLEnable mColorMaterial; - LLGLDisable mAlphaTest, mBlend, mCullFace, mDither, mFog, - mLineSmooth, mLineStipple, mNormalize, mPolygonSmooth, - mGLMultisample; -public: - LLGLSDefault() - : - // Enable - mColorMaterial(GL_COLOR_MATERIAL), - // Disable - mAlphaTest(GL_ALPHA_TEST), - mBlend(GL_BLEND), - mCullFace(GL_CULL_FACE), - mDither(GL_DITHER), - mFog(GL_FOG), - mLineSmooth(GL_LINE_SMOOTH), - mLineStipple(GL_LINE_STIPPLE), - mNormalize(GL_NORMALIZE), - mPolygonSmooth(GL_POLYGON_SMOOTH), - mGLMultisample(GL_MULTISAMPLE_ARB) - { } -}; - -class LLGLSObjectSelect -{ -protected: - LLGLDisable mBlend, mFog, mAlphaTest; - LLGLEnable mCullFace; -public: - LLGLSObjectSelect() - : mBlend(GL_BLEND), mFog(GL_FOG), - mAlphaTest(GL_ALPHA_TEST), - mCullFace(GL_CULL_FACE) - { } +private: + LLGLEnable mColorMaterial; + LLGLDisable mAlphaTest; + LLGLDisable mBlend; + LLGLDisable mCullFace; + LLGLDisable mDither; + LLGLDisable mFog; + LLGLDisable mLineSmooth; + LLGLDisable mLineStipple; + LLGLDisable mNormalize; + LLGLDisable mPolygonSmooth; + LLGLDisable mGLMultisample; + LLGLDisable lighting; +}; + +struct LLGLSObjectSelect +{ +private: + LLGLDisable mBlend; + LLGLDisable mAlphaTest; + LLGLDisable mFog; + LLGLEnable mCullFace; }; -class LLGLSObjectSelectAlpha +struct LLGLSObjectSelectAlpha { -protected: - LLGLEnable mAlphaTest; -public: - LLGLSObjectSelectAlpha() - : mAlphaTest(GL_ALPHA_TEST) - {} +private: + LLGLEnable mAlphaTest; }; //---------------------------------------------------------------------------- -class LLGLSUIDefault +struct LLGLSUIDefault { -protected: - LLGLEnable mBlend, mAlphaTest; - LLGLDisable mCullFace; +private: + LLGLEnable mBlend; + LLGLEnable mAlphaTest; + LLGLDisable mCullFace; + LLGLDisable mMSAA; + //LLGLEnable mScissor; LLGLDepthTest mDepthTest; - LLGLDisable mMSAA; public: - LLGLSUIDefault() - : mBlend(GL_BLEND), mAlphaTest(GL_ALPHA_TEST), - mCullFace(GL_CULL_FACE), - mDepthTest(GL_FALSE, GL_TRUE, GL_LEQUAL), - mMSAA(GL_MULTISAMPLE_ARB) + LLGLSUIDefault() + : mDepthTest(GL_FALSE, GL_TRUE, GL_LEQUAL) {} }; -class LLGLSNoAlphaTest // : public LLGLSUIDefault +struct LLGLSNoAlphaTest // : public LLGLSUIDefault { -protected: - LLGLDisable mAlphaTest; -public: - LLGLSNoAlphaTest() - : mAlphaTest(GL_ALPHA_TEST) - {} +private: + LLGLDisable mAlphaTest; }; //---------------------------------------------------------------------------- -class LLGLSFog +struct LLGLSFog { -protected: - LLGLEnable mFog; -public: - LLGLSFog() - : mFog(GL_FOG) - {} +private: + LLGLEnable mFog; }; -class LLGLSNoFog +struct LLGLSNoFog { -protected: - LLGLDisable mFog; -public: - LLGLSNoFog() - : mFog(GL_FOG) - {} +private: + LLGLDisable mFog; }; //---------------------------------------------------------------------------- -class LLGLSPipeline +struct LLGLSPipeline { -protected: - LLGLEnable mCullFace; +private: + LLGLEnable mCullFace; LLGLDepthTest mDepthTest; public: LLGLSPipeline() - : mCullFace(GL_CULL_FACE), - mDepthTest(GL_TRUE, GL_TRUE, GL_LEQUAL) - { } + : mDepthTest(GL_TRUE, GL_TRUE, GL_LEQUAL) + {} }; -class LLGLSPipelineAlpha // : public LLGLSPipeline +struct LLGLSPipelineAlpha // : public LLGLSPipeline { -protected: - LLGLEnable mBlend, mAlphaTest; -public: - LLGLSPipelineAlpha() - : mBlend(GL_BLEND), - mAlphaTest(GL_ALPHA_TEST) - { } +private: + LLGLEnable mAlphaTest; + LLGLEnable mBlend; }; -class LLGLSPipelineEmbossBump +struct LLGLSPipelineEmbossBump { -protected: - LLGLDisable mFog; -public: - LLGLSPipelineEmbossBump() - : mFog(GL_FOG) - { } +private: + LLGLDisable mFog; }; -class LLGLSPipelineSelection +struct LLGLSPipelineSelection { -protected: - LLGLDisable mCullFace; -public: - LLGLSPipelineSelection() - : mCullFace(GL_CULL_FACE) - {} +private: + LLGLDisable mCullFace; }; -class LLGLSPipelineAvatar +struct LLGLSPipelineAvatar { -protected: - LLGLEnable mNormalize; -public: - LLGLSPipelineAvatar() - : mNormalize(GL_NORMALIZE) - {} +private: + LLGLEnable mNormalize; }; -class LLGLSPipelineSkyBox +struct LLGLSPipelineSkyBox { -protected: - LLGLDisable mAlphaTest, mCullFace, mFog; -public: - LLGLSPipelineSkyBox() - : mAlphaTest(GL_ALPHA_TEST), mCullFace(GL_CULL_FACE), mFog(GL_FOG) - { } +private: + LLGLDisable mAlphaTest; + LLGLDisable mCullFace; + LLGLDisable mFog; + LLGLDisable mLighting; }; -class LLGLSTracker +struct LLGLSTracker { -protected: - LLGLEnable mCullFace, mBlend, mAlphaTest; -public: - LLGLSTracker() : - mCullFace(GL_CULL_FACE), - mBlend(GL_BLEND), - mAlphaTest(GL_ALPHA_TEST) - - { } +private: + LLGLEnable mAlphaTest; + LLGLEnable mBlend; + LLGLEnable mCullFace; }; //---------------------------------------------------------------------------- diff --git a/indra/llrender/llgltexture.cpp b/indra/llrender/llgltexture.cpp index 5154a854fe..3e86385954 100644 --- a/indra/llrender/llgltexture.cpp +++ b/indra/llrender/llgltexture.cpp @@ -46,28 +46,25 @@ S32 LLGLTexture::getCategoryFromIndex(S32 index) return (index < BOOST_HIGH) ? index : index + (BOOST_HIGH - BOOST_SCULPTED) - 1 ; } -LLGLTexture::LLGLTexture(BOOL usemipmaps) +LLGLTexture::LLGLTexture(BOOL usemipmaps, bool allow_compresssion) { - init(); - mUseMipMaps = usemipmaps; + init(usemipmaps, allow_compresssion); } -LLGLTexture::LLGLTexture(const U32 width, const U32 height, const U8 components, BOOL usemipmaps) +LLGLTexture::LLGLTexture(const U32 width, const U32 height, const U8 components, BOOL usemipmaps, bool allow_compresssion) { - init(); + init(usemipmaps, allow_compresssion); mFullWidth = width ; mFullHeight = height ; - mUseMipMaps = usemipmaps ; mComponents = components ; setTexelsPerImage(); } -LLGLTexture::LLGLTexture(const LLImageRaw* raw, BOOL usemipmaps) +LLGLTexture::LLGLTexture(const LLImageRaw* raw, BOOL usemipmaps, bool allow_compresssion) { - init(); - mUseMipMaps = usemipmaps ; + init(usemipmaps, allow_compresssion); // Create an empty image of the specified size and width - mGLTexturep = new LLImageGL(raw, usemipmaps) ; + mGLTexturep = new LLImageGL(raw, usemipmaps, mAllowCompression) ; } LLGLTexture::~LLGLTexture() @@ -75,14 +72,15 @@ LLGLTexture::~LLGLTexture() cleanup(); } -void LLGLTexture::init() +void LLGLTexture::init(bool use_mipmaps, bool allow_compression) { mBoostLevel = LLGLTexture::BOOST_NONE; + mUseMipMaps = use_mipmaps; + mAllowCompression = allow_compression; mFullWidth = 0; mFullHeight = 0; mTexelsPerImage = 0 ; - mUseMipMaps = FALSE ; mComponents = 0 ; mTextureState = NO_DELETE ; @@ -146,7 +144,7 @@ void LLGLTexture::generateGLTexture() { if(mGLTexturep.isNull()) { - mGLTexturep = new LLImageGL(mFullWidth, mFullHeight, mComponents, mUseMipMaps) ; + mGLTexturep = new LLImageGL(mFullWidth, mFullHeight, mComponents, mUseMipMaps, mAllowCompression) ; } } @@ -167,7 +165,7 @@ BOOL LLGLTexture::createGLTexture() return mGLTexturep->createGLTexture() ; } -BOOL LLGLTexture::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename, BOOL to_create, S32 category) +BOOL LLGLTexture::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, LLImageGL::GLTextureName* usename, BOOL to_create, S32 category) { llassert(mGLTexturep.notNull()) ; @@ -298,7 +296,7 @@ LLTexUnit::eTextureAddressMode LLGLTexture::getAddressMode(void) const return mGLTexturep->getAddressMode() ; } -S32 LLGLTexture::getTextureMemory() const +S32Bytes LLGLTexture::getTextureMemory() const { llassert(mGLTexturep.notNull()) ; @@ -312,11 +310,11 @@ LLGLenum LLGLTexture::getPrimaryFormat() const return mGLTexturep->getPrimaryFormat() ; } -BOOL LLGLTexture::getIsAlphaMask(const F32 max_rmse) const +BOOL LLGLTexture::getIsAlphaMask(const F32 max_rmse, const F32 max_mid) const { llassert(mGLTexturep.notNull()) ; - return mGLTexturep->getIsAlphaMask(max_rmse) ; + return mGLTexturep->getIsAlphaMask(max_rmse, max_mid) ; } BOOL LLGLTexture::getMask(const LLVector2 &tc) @@ -395,4 +393,4 @@ void LLGLTexture::setTexelsPerImage() S32 fullwidth = llmin(mFullWidth,(S32)MAX_IMAGE_SIZE_DEFAULT); S32 fullheight = llmin(mFullHeight,(S32)MAX_IMAGE_SIZE_DEFAULT); mTexelsPerImage = (F32)fullwidth * fullheight; -} \ No newline at end of file +} diff --git a/indra/llrender/llgltexture.h b/indra/llrender/llgltexture.h index 1b61078583..122ae77723 100644 --- a/indra/llrender/llgltexture.h +++ b/indra/llrender/llgltexture.h @@ -49,6 +49,7 @@ class LLGLTexture : public LLTexture enum EBoostLevel { BOOST_NONE = 0, + BOOST_ALM , //acts like NONE when ALM is on, max discard when ALM is off BOOST_AVATAR_BAKED , BOOST_AVATAR , BOOST_CLOUDS , @@ -97,9 +98,9 @@ class LLGLTexture : public LLTexture LOG_CLASS(LLGLTexture); public: - LLGLTexture(BOOL usemipmaps = TRUE); - LLGLTexture(const LLImageRaw* raw, BOOL usemipmaps) ; - LLGLTexture(const U32 width, const U32 height, const U8 components, BOOL usemipmaps) ; + LLGLTexture(BOOL usemipmaps = TRUE, bool allow_compresssion=false); + LLGLTexture(const LLImageRaw* raw, BOOL usemipmaps, bool allow_compresssion=false) ; + LLGLTexture(const U32 width, const U32 height, const U8 components, BOOL usemipmaps, bool allow_compresssion=false) ; virtual void dump(); // debug info to llinfos @@ -123,8 +124,7 @@ class LLGLTexture : public LLTexture BOOL hasGLTexture() const ; LLGLuint getTexName() const ; BOOL createGLTexture() ; - BOOL createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename = 0, BOOL to_create = TRUE, S32 category = LLGLTexture::OTHER); - + BOOL createGLTexture(S32 discard_level, const LLImageRaw* imageraw, LLImageGL::GLTextureName* usename = nullptr, BOOL to_create = TRUE, S32 category = LLGLTexture::OTHER); void setFilteringOption(LLTexUnit::eTextureFilterOptions option); void setExplicitFormat(LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format = 0, BOOL swap_bytes = FALSE); void setAddressMode(LLTexUnit::eTextureAddressMode mode); @@ -138,9 +138,9 @@ class LLGLTexture : public LLTexture S32 getDiscardLevel() const; S8 getComponents() const; BOOL getBoundRecently() const; - S32 getTextureMemory() const ; + S32Bytes getTextureMemory() const ; LLGLenum getPrimaryFormat() const; - BOOL getIsAlphaMask(const F32 max_rmse) const ; + BOOL getIsAlphaMask(const F32 max_rmse, const F32 max_mid) const ; LLTexUnit::eTextureType getTarget(void) const ; BOOL getMask(const LLVector2 &tc); F32 getTimePassedSinceLastBound(); @@ -168,7 +168,7 @@ class LLGLTexture : public LLTexture private: void cleanup(); - void init(); + void init(bool use_mipmaps, bool allow_compression); protected: void setTexelsPerImage(); @@ -187,7 +187,8 @@ class LLGLTexture : public LLTexture //GL texture LLPointer mGLTexturep ; - S8 mDontDiscard; // Keep full res version of this image (for UI, etc) + bool mDontDiscard; // Keep full res version of this image (for UI, etc) + bool mAllowCompression; protected: LLGLTextureState mTextureState ; diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index 3bccad5e3f..c1a9c51e92 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -50,12 +50,10 @@ U32 wpo2(U32 i); U32 LLImageGL::sUniqueCount = 0; U32 LLImageGL::sBindCount = 0; -S32 LLImageGL::sGlobalTextureMemoryInBytes = 0; -S32 LLImageGL::sBoundTextureMemoryInBytes = 0; -S32 LLImageGL::sCurBoundTextureMemory = 0; +S64Bytes LLImageGL::sGlobalTextureMemory(0); +S64Bytes LLImageGL::sBoundTextureMemory(0); +S64Bytes LLImageGL::sCurBoundTextureMemory(0); S32 LLImageGL::sCount = 0; -LLImageGL::dead_texturelist_t LLImageGL::sDeadTextureList[LLTexUnit::TT_NONE]; -U32 LLImageGL::sCurTexName = 1; BOOL LLImageGL::sGlobalUseAnisotropic = FALSE; F32 LLImageGL::sLastFrameTime = 0.f; @@ -80,14 +78,17 @@ S32 LLImageGL::sCurTexPickSize = -1 ; LLPointer LLImageGL::sHighlightTexturep = NULL; S32 LLImageGL::sMaxCategories = 1 ; -std::vector LLImageGL::sTextureMemByCategory; -std::vector LLImageGL::sTextureMemByCategoryBound ; -std::vector LLImageGL::sTextureCurMemByCategoryBound ; +std::vector LLImageGL::sTextureMemByCategory; +std::vector LLImageGL::sTextureMemByCategoryBound ; +std::vector LLImageGL::sTextureCurMemByCategoryBound ; //------------------------ // **************************************************************************************************** //End for texture auditing use only // **************************************************************************************************** +//static std::vector sActiveTextureNames; +//static std::vector sDeletedTextureNames; + // ************************************************************************************** //below are functions for debug use //do not delete them even though they are not currently being used. @@ -120,9 +121,9 @@ void LLImageGL::checkTexSize(bool forced) const GLint texname; glGetIntegerv(GL_TEXTURE_BINDING_2D, &texname); BOOL error = FALSE; - if (texname != mTexName) + if (texname != getTexName()) { - llinfos << "Bound: " << texname << " Should bind: " << mTexName << " Default: " << LLImageGL::sDefaultGLTexture->getTexName() << llendl; + LL_INFOS() << "Bound: " << texname << " Should bind: " << getTexName() << " Default: " << (LLImageGL::sDefaultGLTexture ? LLImageGL::sDefaultGLTexture->getTexName() : 0) << LL_ENDL; error = TRUE; if (gDebugSession) @@ -131,7 +132,7 @@ void LLImageGL::checkTexSize(bool forced) const } else { - llerrs << "Invalid texture bound!" << llendl; + LL_ERRS() << "Invalid texture bound!" << LL_ENDL; } } stop_glerror() ; @@ -155,8 +156,8 @@ void LLImageGL::checkTexSize(bool forced) const } else { - llerrs << "wrong texture size and discard level: width: " << - mWidth << " Height: " << mHeight << " Current Level: " << (S32)mCurrentDiscardLevel << llendl ; + LL_ERRS() << "wrong texture size and discard level: width: " << + mWidth << " Height: " << mHeight << " Current Level: " << (S32)mCurrentDiscardLevel << LL_ENDL ; } } @@ -221,7 +222,7 @@ void LLImageGL::setHighlightTexture(S32 category) } } } - sHighlightTexturep->createGLTexture(0, image_raw, 0, TRUE, category); + sHighlightTexturep->createGLTexture(0, image_raw, nullptr, TRUE, category); image_raw = NULL; } @@ -237,12 +238,14 @@ S32 LLImageGL::dataFormatBits(S32 dataformat) case GL_ALPHA: return 8; case GL_COLOR_INDEX: return 8; case GL_LUMINANCE_ALPHA: return 16; + case GL_RED: return 8; + case GL_RG: return 16; case GL_RGB: return 24; case GL_RGB8: return 24; case GL_RGBA: return 32; case GL_BGRA: return 32; // Used for QuickTime media textures on the Mac default: - llerrs << "LLImageGL::Unknown format: " << dataformat << llendl; + LL_ERRS() << "LLImageGL::Unknown format: " << dataformat << LL_ENDL; return 0; } } @@ -273,25 +276,27 @@ S32 LLImageGL::dataFormatComponents(S32 dataformat) case GL_ALPHA: return 1; case GL_COLOR_INDEX: return 1; case GL_LUMINANCE_ALPHA: return 2; + case GL_RED: return 1; + case GL_RG: return 2; case GL_RGB: return 3; case GL_RGBA: return 4; case GL_BGRA: return 4; // Used for QuickTime media textures on the Mac default: - llerrs << "LLImageGL::Unknown format: " << dataformat << llendl; + LL_ERRS() << "LLImageGL::Unknown format: " << dataformat << LL_ENDL; return 0; } } //---------------------------------------------------------------------------- -static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE_STATS("Image Stats"); +static LLTrace::BlockTimerStatHandle FTM_IMAGE_UPDATE_STATS("Image Stats"); // static void LLImageGL::updateStats(F32 current_time) { - LLFastTimer t(FTM_IMAGE_UPDATE_STATS); + LL_RECORD_BLOCK_TIME(FTM_IMAGE_UPDATE_STATS); sLastFrameTime = current_time; - sBoundTextureMemoryInBytes = sCurBoundTextureMemory; - sCurBoundTextureMemory = 0; + sBoundTextureMemory = sCurBoundTextureMemory; + sCurBoundTextureMemory = S64Bytes(0); if(gAuditTexture) { @@ -303,22 +308,22 @@ void LLImageGL::updateStats(F32 current_time) for(U32 i = 0 ; i < sTextureCurMemByCategoryBound.size() ; i++) { sTextureMemByCategoryBound[i] = sTextureCurMemByCategoryBound[i] ; - sTextureCurMemByCategoryBound[i] = 0 ; + sTextureCurMemByCategoryBound[i] = (S64Bytes)0 ; } } } //static -S32 LLImageGL::updateBoundTexMem(const S32 mem, const S32 ncomponents, S32 category) +S32 LLImageGL::updateBoundTexMem(const S32Bytes mem, const S32 ncomponents, S32 category) { if(gAuditTexture && ncomponents > 0 && category > -1) { - sTextureCurBoundCounter[getTextureCounterIndex(mem / ncomponents)]++ ; + sTextureCurBoundCounter[getTextureCounterIndex(mem.value() / ncomponents)]++ ; sTextureCurMemByCategoryBound[category] += mem ; } LLImageGL::sCurBoundTextureMemory += mem ; - return LLImageGL::sCurBoundTextureMemory; + return LLImageGL::sCurBoundTextureMemory.value(); } //---------------------------------------------------------------------------- @@ -326,67 +331,82 @@ S32 LLImageGL::updateBoundTexMem(const S32 mem, const S32 ncomponents, S32 categ //static void LLImageGL::destroyGL(BOOL save_state) { - for (S32 stage = 0; stage < gGLManager.mNumTextureUnits; stage++) - { - gGL.getTexUnit(stage)->unbind(LLTexUnit::TT_TEXTURE); - } - - int stored_count = 0; - sAllowReadBackRaw = true ; - for (std::set::iterator iter = sImageList.begin(); - iter != sImageList.end(); iter++) + LLTexUnit::sWhiteTexture = 0; + if (save_state) { - LLImageGL* glimage = *iter; - if (glimage->mTexName) + U32 count = 0; + sAllowReadBackRaw = true; + for (std::set::iterator iter = sImageList.begin(); + iter != sImageList.end(); iter++) { - if (save_state && glimage->isGLTextureCreated() && glimage->mComponents) + LLImageGL* glimage = *iter; + GLuint tex = glimage->getTexName(); + if (tex) { - glimage->mSaveData = new LLImageRaw; - if(!glimage->readBackRaw(glimage->mCurrentDiscardLevel, glimage->mSaveData, false)) //necessary, keep it. + if (glimage->isGLTextureCreated()) { - glimage->mSaveData = NULL ; - } - else - { - glimage->mSaveDiscardLevel = glimage->mCurrentDiscardLevel; - stored_count++; + glimage->mSaveData = new LLImageRaw; + if (glimage->mComponents && glimage->readBackRaw(-1, glimage->mSaveData, false))//necessary, keep it. + { + ++count; + glimage->mSaveDiscardLevel = glimage->mCurrentDiscardLevel; + glimage->destroyGLTexture(); + continue; + } } } - - glimage->destroyGLTexture(); + glimage->mSaveData = nullptr; + glimage->forceToInvalidateGLTexture(); stop_glerror(); } + LL_INFOS() << "Storing " << count << " images..." << LL_ENDL; + sAllowReadBackRaw = false; } - llinfos << "Storing " << stored_count << " images..." << llendl; - sAllowReadBackRaw = false ; + for (S32 stage = 0; stage < gGLManager.mNumTextureUnits; stage++) + { + gGL.getTexUnit(stage)->unbind(LLTexUnit::TT_TEXTURE); + } + //clean_validate_buffers(); } //static void LLImageGL::restoreGL() { - - int recovered_count = 0; + U32 count = 0; for (std::set::iterator iter = sImageList.begin(); iter != sImageList.end(); iter++) { LLImageGL* glimage = *iter; if(glimage->getTexName()) { - llerrs << "tex name is not 0." << llendl ; + LL_ERRS() << "tex name is not 0." << LL_ENDL ; } - if (glimage->mSaveData.notNull()) + LLPointer data = glimage->mSaveData; + glimage->mSaveData = nullptr; + if (data.notNull() && glimage->getComponents() && + data->getComponents() && + glimage->mSaveDiscardLevel >= 0 && + glimage->createGLTexture(glimage->mSaveDiscardLevel, data, nullptr, TRUE, glimage->getCategory())) { - if (glimage->getComponents() && glimage->mSaveData->getComponents() && glimage->mSaveDiscardLevel >= 0) - { - glimage->createGLTexture(glimage->mSaveDiscardLevel, glimage->mSaveData, 0, TRUE, glimage->getCategory()); stop_glerror(); - recovered_count++; - } - glimage->mSaveData = NULL; // deletes data - glimage->mSaveDiscardLevel = -1; + /*if (glimage->getHasGLTexture()) + { + LL_INFOS() << "Restored " << glimage << " texid:" << glimage->getTexName() << LL_ENDL; + } + else + { + LL_INFOS() << "Restored " << glimage << " texid: (null)" << LL_ENDL; + }*/ + ++count; + } + else + { + //LL_INFOS() << "Skipped " << glimage << LL_ENDL; + glimage->forceToInvalidateGLTexture(); } } - llinfos << "Restored " << recovered_count << " images" << llendl; + + LL_INFOS() << "Restored " << count << " images" << LL_ENDL; } //static @@ -427,29 +447,29 @@ BOOL LLImageGL::create(LLPointer& dest, const LLImageRaw* imageraw, B //---------------------------------------------------------------------------- -LLImageGL::LLImageGL(BOOL usemipmaps) - : mSaveData(0), mSaveDiscardLevel(-1) +LLImageGL::LLImageGL(BOOL usemipmaps, bool allow_compression) + : mSaveData(0), mSaveDiscardLevel(-1), mIsCompressed(false) { - init(usemipmaps); + init(usemipmaps, allow_compression); setSize(0, 0, 0); sImageList.insert(this); sCount++; } -LLImageGL::LLImageGL(U32 width, U32 height, U8 components, BOOL usemipmaps) +LLImageGL::LLImageGL(U32 width, U32 height, U8 components, BOOL usemipmaps, bool allow_compression) : mSaveData(0), mSaveDiscardLevel(-1) { llassert( components <= 4 ); - init(usemipmaps); + init(usemipmaps, allow_compression); setSize(width, height, components); sImageList.insert(this); sCount++; } -LLImageGL::LLImageGL(const LLImageRaw* imageraw, BOOL usemipmaps) +LLImageGL::LLImageGL(const LLImageRaw* imageraw, BOOL usemipmaps, bool allow_compression) : mSaveData(0), mSaveDiscardLevel(-1) { - init(usemipmaps); + init(usemipmaps, allow_compression); setSize(0, 0, 0); sImageList.insert(this); sCount++; @@ -466,39 +486,38 @@ LLImageGL::~LLImageGL() sCount--; } -void LLImageGL::init(BOOL usemipmaps) +const S8 INVALID_OFFSET = -99 ; + +void LLImageGL::init(BOOL usemipmaps, bool allow_compression) { // keep these members in the same order as declared in llimagehl.h // so that it is obvious by visual inspection if we forgot to // init a field. - mTextureMemory = 0; + mTextureMemory = (S32Bytes)0; mLastBindTime = 0.f; mPickMask = NULL; mPickMaskWidth = 0; mPickMaskHeight = 0; mUseMipMaps = usemipmaps; + mAllowCompression = allow_compression; mHasExplicitFormat = FALSE; mAutoGenMips = FALSE; - mCanMask = TRUE; mIsMask = FALSE; mMaskRMSE = 1.f ; + mMaskMidPercentile = 1.f; - - mNeedsAlphaAndPickMask = TRUE ; + mNeedsAlphaAndPickMask = FALSE ; mAlphaStride = 0 ; - mAlphaOffset = 0 ; + mAlphaOffset = INVALID_OFFSET ; mGLTextureCreated = FALSE ; - mTexName = 0; + mTexName.reset(); mWidth = 0; mHeight = 0; mCurrentDiscardLevel = -1; - - - mAllowCompression = true; mTarget = GL_TEXTURE_2D; mBindTarget = LLTexUnit::TT_TEXTURE; @@ -565,12 +584,12 @@ void LLImageGL::setSize(S32 width, S32 height, S32 ncomponents, S32 discard_leve // Check if dimensions are a power of two! if (!checkSize(width,height)) { - llerrs << llformat("Texture has non power of two dimension: %dx%d",width,height) << llendl; + LL_WARNS() << llformat("Texture has non power of two dimension: %dx%d",width,height) << " Unless on WhiteCore, beware." << LL_ENDL; } if (mTexName) { -// llwarns << "Setting Size of LLImageGL with existing mTexName = " << mTexName << llendl; +// LL_WARNS() << "Setting Size of LLImageGL with existing mTexName = " << getTexName() << LL_ENDL; destroyGLTexture(); } @@ -609,7 +628,7 @@ void LLImageGL::setSize(S32 width, S32 height, S32 ncomponents, S32 discard_leve // virtual void LLImageGL::dump() { - llinfos << "mMaxDiscardLevel " << S32(mMaxDiscardLevel) + LL_INFOS() << "mMaxDiscardLevel " << S32(mMaxDiscardLevel) << " mLastBindTime " << mLastBindTime << " mTarget " << S32(mTarget) << " mBindTarget " << S32(mBindTarget) @@ -624,12 +643,12 @@ void LLImageGL::dump() #if DEBUG_MISS << " mMissed " << mMissed #endif - << llendl; + << LL_ENDL; - llinfos << " mTextureMemory " << mTextureMemory - << " mTexNames " << mTexName + LL_INFOS() << " mTextureMemory " << mTextureMemory + << " mTexNames " << getTexName() << " mIsResident " << S32(mIsResident) - << llendl; + << LL_ENDL; } //---------------------------------------------------------------------------- @@ -638,9 +657,9 @@ void LLImageGL::forceUpdateBindStats(void) const mLastBindTime = sLastFrameTime; } -BOOL LLImageGL::updateBindStats(S32 tex_mem) const +BOOL LLImageGL::updateBindStats(S32Bytes tex_mem) const { - if (mTexName != 0) + if (getTexName()) { #ifdef DEBUG_MISS mMissed = ! getIsResident(TRUE); @@ -691,10 +710,10 @@ void LLImageGL::setImage(const LLImageRaw* imageraw) setImage(rawdata, FALSE); } -static LLFastTimer::DeclareTimer FTM_SET_IMAGE("setImage"); +static LLTrace::BlockTimerStatHandle FTM_SET_IMAGE("setImage"); void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) { - LLFastTimer t(FTM_SET_IMAGE); + LL_RECORD_BLOCK_TIME(FTM_SET_IMAGE); bool is_compressed = false; if (mFormatPrimary >= GL_COMPRESSED_RGBA_S3TC_DXT1_EXT && mFormatPrimary <= GL_COMPRESSED_RGBA_S3TC_DXT5_EXT) { @@ -718,7 +737,7 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) llverify(gGL.getTexUnit(0)->bind(this)); - + mIsCompressed = false; if (mUseMipMaps) { if (data_hasmips) @@ -743,10 +762,11 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) S32 tex_size = dataFormatBytes(mFormatPrimary, w, h); glCompressedTexImage2DARB(mTarget, gl_level, mFormatPrimary, w, h, 0, tex_size, (GLvoid *)data_in); stop_glerror(); + mIsCompressed = true; } else { -// LLFastTimer t2(FTM_TEMP4); +// LL_RECORD_BLOCK_TIME(FTM_TEMP4); if(mFormatSwapBytes) { @@ -754,7 +774,7 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) stop_glerror(); } - LLImageGL::setManualImage(mTarget, gl_level, mFormatInternal, w, h, mFormatPrimary, GL_UNSIGNED_BYTE, (GLvoid*)data_in, mAllowCompression); + mIsCompressed = LLImageGL::setManualImage(mTarget, gl_level, mFormatInternal, w, h, mFormatPrimary, GL_UNSIGNED_BYTE, (GLvoid*)data_in, mAllowCompression); if (gl_level == 0) { analyzeAlpha(data_in, w, h); @@ -778,7 +798,7 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) { stop_glerror(); { -// LLFastTimer t2(FTM_TEMP4); +// LL_RECORD_BLOCK_TIME(FTM_TEMP4); if(mFormatSwapBytes) { @@ -791,10 +811,15 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) mMipLevels = wpo2(llmax(w, h)); - //use legacy mipmap generation mode - glTexParameteri(mTarget, GL_GENERATE_MIPMAP, GL_TRUE); + //use legacy mipmap generation mode (note: making this condional can cause rendering issues) + // -- but making it not conditional triggers deprecation warnings when core profile is enabled + // (some rendering issues while core profile is enabled are acceptable at this point in time) + if (!LLRender::sGLCoreProfile) + { + glTexParameteri(mTarget, GL_GENERATE_MIPMAP, GL_TRUE); + } - LLImageGL::setManualImage(mTarget, 0, mFormatInternal, + mIsCompressed = LLImageGL::setManualImage(mTarget, 0, mFormatInternal, w, h, mFormatPrimary, mFormatType, data_in, mAllowCompression); @@ -808,6 +833,12 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) glPixelStorei(GL_UNPACK_SWAP_BYTES, 0); stop_glerror(); } + + if (LLRender::sGLCoreProfile) + { + glGenerateMipmap(mTarget); + } + stop_glerror(); } } else @@ -852,14 +883,14 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) } llassert(w > 0 && h > 0 && cur_mip_data); { -// LLFastTimer t1(FTM_TEMP4); +// LL_RECORD_BLOCK_TIME(FTM_TEMP4); if(mFormatSwapBytes) { glPixelStorei(GL_UNPACK_SWAP_BYTES, 1); stop_glerror(); } - LLImageGL::setManualImage(mTarget, m, mFormatInternal, w, h, mFormatPrimary, mFormatType, cur_mip_data, mAllowCompression); + mIsCompressed = LLImageGL::setManualImage(mTarget, m, mFormatInternal, w, h, mFormatPrimary, mFormatType, cur_mip_data, mAllowCompression); if (m == 0) { analyzeAlpha(data_in, w, h); @@ -893,7 +924,7 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) } else { - llerrs << "Compressed Image has mipmaps but data does not (can not auto generate compressed mips)" << llendl; + LL_ERRS() << "Compressed Image has mipmaps but data does not (can not auto generate compressed mips)" << LL_ENDL; } } else @@ -906,6 +937,7 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) S32 tex_size = dataFormatBytes(mFormatPrimary, w, h); glCompressedTexImage2DARB(mTarget, 0, mFormatPrimary, w, h, 0, tex_size, (GLvoid *)data_in); stop_glerror(); + mIsCompressed = true; } else { @@ -915,7 +947,7 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) stop_glerror(); } - LLImageGL::setManualImage(mTarget, 0, mFormatInternal, w, h, + mIsCompressed = LLImageGL::setManualImage(mTarget, 0, mFormatInternal, w, h, mFormatPrimary, mFormatType, (GLvoid *)data_in, mAllowCompression); analyzeAlpha(data_in, w, h); @@ -941,16 +973,16 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3 { return TRUE; } - if (mTexName == 0) + if (!getTexName()) { // *TODO: Re-enable warning? Ran into thread locking issues? DK 2011-02-18 - //llwarns << "Setting subimage on image without GL texture" << llendl; + //LL_WARNS() << "Setting subimage on image without GL texture" << LL_ENDL; return FALSE; } if (datap == NULL) { // *TODO: Re-enable warning? Ran into thread locking issues? DK 2011-02-18 - //llwarns << "Setting subimage on image with NULL datap" << llendl; + //LL_WARNS() << "Setting subimage on image with NULL datap" << LL_ENDL; return FALSE; } @@ -964,7 +996,7 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3 if (mUseMipMaps) { dump(); - llerrs << "setSubImage called with mipmapped image (not supported)" << llendl; + LL_ERRS() << "setSubImage called with mipmapped image (not supported)" << LL_ENDL; } llassert_always(mCurrentDiscardLevel == 0); llassert_always(x_pos >= 0 && y_pos >= 0); @@ -973,28 +1005,28 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3 (y_pos + height) > getHeight()) { dump(); - llerrs << "Subimage not wholly in target image!" + LL_ERRS() << "Subimage not wholly in target image!" << " x_pos " << x_pos << " y_pos " << y_pos << " width " << width << " height " << height << " getWidth() " << getWidth() << " getHeight() " << getHeight() - << llendl; + << LL_ENDL; } if ((x_pos + width) > data_width || (y_pos + height) > data_height) { dump(); - llerrs << "Subimage not wholly in source image!" + LL_ERRS() << "Subimage not wholly in source image!" << " x_pos " << x_pos << " y_pos " << y_pos << " width " << width << " height " << height << " source_width " << data_width << " source_height " << data_height - << llendl; + << LL_ENDL; } @@ -1009,8 +1041,8 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3 datap += (y_pos * data_width + x_pos) * getComponents(); // Update the GL texture - BOOL res = gGL.getTexUnit(0)->bindManual(mBindTarget, mTexName); - if (!res) llerrs << "LLImageGL::setSubImage(): bindTexture failed" << llendl; + BOOL res = gGL.getTexUnit(0)->bindManual(mBindTarget, getTexName()); + if (!res) LL_ERRS() << "LLImageGL::setSubImage(): bindTexture failed" << LL_ENDL; stop_glerror(); glTexSubImage2D(mTarget, 0, x_pos, y_pos, @@ -1053,140 +1085,229 @@ BOOL LLImageGL::setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_ } } -// static -static LLFastTimer::DeclareTimer FTM_GENERATE_TEXTURES("generate textures"); -void LLImageGL::generateTextures(LLTexUnit::eTextureType type, U32 format, S32 numTextures, U32 *textures) +/*void validate_add_texture(U32 name) { - LLFastTimer t(FTM_GENERATE_TEXTURES); - bool empty = true; - - dead_texturelist_t::iterator iter = sDeadTextureList[type].find(format); - - if (iter != sDeadTextureList[type].end()) + auto found = std::find(sActiveTextureNames.begin(), sActiveTextureNames.end(), name); + if (found != sActiveTextureNames.end()) { - empty = iter->second.empty(); + LL_ERRS() << "Allocating allocated texture name " << name << LL_ENDL; } - - for (S32 i = 0; i < numTextures; ++i) + else { - if (!empty) + //LL_INFOS() << "Allocated buffer name " << name << LL_ENDL; + sActiveTextureNames.push_back(name); + } +} + +void validate_del_texture(U32 name) +{ + auto found = std::find(sActiveTextureNames.begin(), sActiveTextureNames.end(), name); + if (found == sActiveTextureNames.end()) + { + if (std::find(sDeletedTextureNames.begin(), sDeletedTextureNames.end(), name) == sDeletedTextureNames.end()) { - textures[i] = iter->second.front(); - iter->second.pop_front(); - empty = iter->second.empty(); + LL_ERRS() << "Deleting unknown texture name " << name << LL_ENDL; } else { - textures[i] = sCurTexName++; + LL_ERRS() << "Deleting deleted texture name " << name << LL_ENDL; } } + else + { + //LL_INFOS() << "Deleted buffer name " << name << LL_ENDL; + sActiveTextureNames.erase(found); + sDeletedTextureNames.push_back(name); + } + } -// static -void LLImageGL::deleteTextures(LLTexUnit::eTextureType type, U32 format, S32 mip_levels, S32 numTextures, U32 *textures, bool immediate) +void validate_bind_texture(U32 name) { - if (gGLManager.mInited) + auto found = std::find(sActiveTextureNames.begin(), sActiveTextureNames.end(), name); + if (found == sActiveTextureNames.end()) { - if (format == 0 || type == LLTexUnit::TT_CUBE_MAP || mip_levels == -1) - { //unknown internal format or unknown number of mip levels, not safe to reuse - glDeleteTextures(numTextures, textures); + if (std::find(sDeletedTextureNames.begin(), sDeletedTextureNames.end(), name) == sDeletedTextureNames.end()) + { + LL_ERRS() << "Binding unknown texture name " << name << LL_ENDL; } else { - for (S32 i = 0; i < numTextures; ++i) - { //remove texture from VRAM by setting its size to zero - for (S32 j = 0; j <= mip_levels; j++) - { - gGL.getTexUnit(0)->bindManual(type, textures[i]); + LL_ERRS() << "Binding deleted texture name " << name << LL_ENDL; + } + } +} - glTexImage2D(LLTexUnit::getInternalType(type), j, format, 0, 0, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - } +void clean_validate_buffers() +{ + LL_INFOS() << "Clearing active buffer names. Count " << sActiveBufferNames.size() << LL_ENDL; + sActiveTextureNames.clear(); + LL_INFOS() << "Clearing deleted buffer names. Count " << sDeletedBufferNames.size() << LL_ENDL; + sDeletedTextureNames.clear(); +}*/ - llassert(std::find(sDeadTextureList[type][format].begin(), - sDeadTextureList[type][format].end(), textures[i]) == - sDeadTextureList[type][format].end()); +// static +static LLTrace::BlockTimerStatHandle FTM_GENERATE_TEXTURES("generate textures"); +void LLImageGL::generateTextures(S32 numTextures, U32 *textures) +{ + LL_RECORD_BLOCK_TIME(FTM_GENERATE_TEXTURES); + glGenTextures(numTextures, textures); + /*for (S32 i = 0; i < numTextures; ++i) + { + validate_add_texture(textures[i]); + }*/ +} - sDeadTextureList[type][format].push_back(textures[i]); - } +// static +void LLImageGL::deleteTextures(S32 numTextures, U32 *textures, const std::vector& allocationData) +{ + if (gGLManager.mInited) + { + for (auto& entry : allocationData) + { + texMemoryDeallocated(entry); } + + glDeleteTextures(numTextures, textures); + /*for (S32 i = 0; i < numTextures; ++i) + { + validate_del_texture(textures[i]); + }*/ } - - /*if (immediate) +} + +// static +void LLImageGL::texMemoryAllocated(const AllocationInfo& entry) +{ + sGlobalTextureMemory += (S64Bytes)entry.size; + if (gAuditTexture) { - LLImageGL::deleteDeadTextures(); - }*/ + incTextureCounter((S64Bytes)entry.size, entry.components, entry.category); + } } // static -static LLFastTimer::DeclareTimer FTM_SET_MANUAL_IMAGE("setManualImage"); -void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void *pixels, bool allow_compression) +void LLImageGL::texMemoryDeallocated(const AllocationInfo& entry) { - LLFastTimer t(FTM_SET_MANUAL_IMAGE); - bool use_scratch = false; - U32* scratch = NULL; + sGlobalTextureMemory -= (S64Bytes)entry.size; + if (gAuditTexture) + { + decTextureCounter((S64Bytes)entry.size, entry.components, entry.category); + } +} + +// static +static LLTrace::BlockTimerStatHandle FTM_SET_MANUAL_IMAGE("setManualImage"); +bool LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void *pixels, bool allow_compression) +{ + LL_RECORD_BLOCK_TIME(FTM_SET_MANUAL_IMAGE); + bool compressed = false; + std::vector scratch; if (LLRender::sGLCoreProfile) { - if (pixformat == GL_ALPHA && pixtype == GL_UNSIGNED_BYTE) - { //GL_ALPHA is deprecated, convert to RGBA - use_scratch = true; - scratch = new U32[width*height]; +#ifdef GL_ARB_texture_swizzle + if(gGLManager.mHasTextureSwizzle) + { + if (pixformat == GL_ALPHA) + { //GL_ALPHA is deprecated, convert to RGBA + const GLint mask[] = {GL_ZERO, GL_ZERO, GL_ZERO, GL_RED}; + glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, mask); + pixformat = GL_RED; + intformat = GL_R8; + } - U32 pixel_count = (U32) (width*height); - for (U32 i = 0; i < pixel_count; i++) - { - U8* pix = (U8*) &scratch[i]; - pix[0] = pix[1] = pix[2] = 0; - pix[3] = ((U8*) pixels)[i]; - } - - pixformat = GL_RGBA; - intformat = GL_RGBA8; + if (pixformat == GL_LUMINANCE) + { //GL_LUMINANCE is deprecated, convert to GL_RGBA + const GLint mask[] = {GL_RED, GL_RED, GL_RED, GL_ONE}; + glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, mask); + pixformat = GL_RED; + intformat = GL_R8; + } + + if (pixformat == GL_LUMINANCE_ALPHA) + { //GL_LUMINANCE_ALPHA is deprecated, convert to RGBA + const GLint mask[] = {GL_RED, GL_RED, GL_RED, GL_GREEN}; + glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, mask); + pixformat = GL_RG; + intformat = GL_RG8; + } } + else +#endif + { + if (pixformat == GL_ALPHA && pixtype == GL_UNSIGNED_BYTE) + { //GL_ALPHA is deprecated, convert to RGBA + scratch.resize(width*height); - if (pixformat == GL_LUMINANCE_ALPHA && pixtype == GL_UNSIGNED_BYTE) - { //GL_LUMINANCE_ALPHA is deprecated, convert to RGBA - use_scratch = true; - scratch = new U32[width*height]; + U32 pixel_count = (U32) (width*height); + for (U32 i = 0; i < pixel_count; i++) + { + U8* pix = (U8*) &scratch[i]; + pix[0] = pix[1] = pix[2] = 0; + pix[3] = ((U8*) pixels)[i]; + } - U32 pixel_count = (U32) (width*height); - for (U32 i = 0; i < pixel_count; i++) - { - U8 lum = ((U8*) pixels)[i*2+0]; - U8 alpha = ((U8*) pixels)[i*2+1]; + pixels = &scratch[0]; - U8* pix = (U8*) &scratch[i]; - pix[0] = pix[1] = pix[2] = lum; - pix[3] = alpha; - } - - pixformat = GL_RGBA; - intformat = GL_RGBA8; - } + pixformat = GL_RGBA; + intformat = GL_RGBA8; + } - if (pixformat == GL_LUMINANCE && pixtype == GL_UNSIGNED_BYTE) - { //GL_LUMINANCE_ALPHA is deprecated, convert to RGB - use_scratch = true; - scratch = new U32[width*height]; + if (pixformat == GL_LUMINANCE_ALPHA && pixtype == GL_UNSIGNED_BYTE) + { //GL_LUMINANCE_ALPHA is deprecated, convert to RGBA + scratch.resize(width*height); - U32 pixel_count = (U32) (width*height); - for (U32 i = 0; i < pixel_count; i++) - { - U8 lum = ((U8*) pixels)[i]; - - U8* pix = (U8*) &scratch[i]; - pix[0] = pix[1] = pix[2] = lum; - pix[3] = 255; - } - - pixformat = GL_RGBA; - intformat = GL_RGB8; + U32 pixel_count = (U32) (width*height); + for (U32 i = 0; i < pixel_count; i++) + { + U8 lum = ((U8*) pixels)[i*2+0]; + U8 alpha = ((U8*) pixels)[i*2+1]; + + U8* pix = (U8*) &scratch[i]; + pix[0] = pix[1] = pix[2] = lum; + pix[3] = alpha; + } + + pixels = &scratch[0]; + + pixformat = GL_RGBA; + intformat = GL_RGBA8; + } + + if (pixformat == GL_LUMINANCE && pixtype == GL_UNSIGNED_BYTE) + { //GL_LUMINANCE_ALPHA is deprecated, convert to RGB + scratch.resize(width*height); + + U32 pixel_count = (U32) (width*height); + for (U32 i = 0; i < pixel_count; i++) + { + U8 lum = ((U8*) pixels)[i]; + + U8* pix = (U8*) &scratch[i]; + pix[0] = pix[1] = pix[2] = lum; + pix[3] = 255; + } + + pixels = &scratch[0]; + + pixformat = GL_RGBA; + intformat = GL_RGB8; + } } } - if (LLImageGL::sCompressTextures && allow_compression) { + compressed = true; switch (intformat) { + case GL_RED: + case GL_R8: + intformat = GL_COMPRESSED_RED; + break; + case GL_RG: + case GL_RG8: + intformat = GL_COMPRESSED_RG; + break; case GL_RGB: case GL_RGB8: intformat = GL_COMPRESSED_RGB; @@ -1208,30 +1329,27 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt intformat = GL_COMPRESSED_ALPHA; break; default: - llwarns << "Could not compress format: " << std::hex << intformat << std::dec << llendl; + compressed = false; + LL_WARNS() << "Could not compress format: " << std::hex << intformat << std::dec << LL_ENDL; break; } } stop_glerror(); - glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, use_scratch ? scratch : pixels); + glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, pixels); stop_glerror(); - - if (use_scratch) - { - delete [] scratch; - } + return compressed; } //create an empty GL texture: just create a texture name //the texture is assiciate with some image by calling glTexImage outside LLImageGL -static LLFastTimer::DeclareTimer FTM_CREATE_GL_TEXTURE1("createGLTexture()"); +static LLTrace::BlockTimerStatHandle FTM_CREATE_GL_TEXTURE1("createGLTexture()"); BOOL LLImageGL::createGLTexture() { - LLFastTimer t(FTM_CREATE_GL_TEXTURE1); + LL_RECORD_BLOCK_TIME(FTM_CREATE_GL_TEXTURE1); if (gGLManager.mIsDisabled) { - llwarns << "Trying to create a texture while GL is disabled!" << llendl; + LL_WARNS() << "Trying to create a texture while GL is disabled!" << LL_ENDL; return FALSE; } @@ -1240,29 +1358,24 @@ BOOL LLImageGL::createGLTexture() llassert(gGLManager.mInited); stop_glerror(); - if(mTexName) - { - LLImageGL::deleteTextures(mBindTarget, mFormatInternal, mMipLevels, 1, (reinterpret_cast(&mTexName))) ; - } - + mTexName = createTextureName(); - LLImageGL::generateTextures(mBindTarget, mFormatInternal, 1, &mTexName); stop_glerror(); - if (!mTexName) + if (!getTexName()) { - llerrs << "LLImageGL::createGLTexture failed to make an empty texture" << llendl; + LL_ERRS() << "LLImageGL::createGLTexture failed to make an empty texture" << LL_ENDL; } return TRUE ; } -static LLFastTimer::DeclareTimer FTM_CREATE_GL_TEXTURE2("createGLTexture(raw)"); -BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename/*=0*/, BOOL to_create, S32 category) +static LLTrace::BlockTimerStatHandle FTM_CREATE_GL_TEXTURE2("createGLTexture(raw)"); +BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, GLTextureName* usename, BOOL to_create, S32 category) { - LLFastTimer t(FTM_CREATE_GL_TEXTURE2); + LL_RECORD_BLOCK_TIME(FTM_CREATE_GL_TEXTURE2); if (gGLManager.mIsDisabled) { - llwarns << "Trying to create a texture while GL is disabled!" << llendl; + LL_WARNS() << "Trying to create a texture while GL is disabled!" << LL_ENDL; return FALSE; } @@ -1276,6 +1389,8 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S discard_level = mCurrentDiscardLevel; } + discard_level = llclamp(discard_level, 0, (S32)mMaxDiscardLevel); + // Actual image width/height = raw image width/height * 2^discard_level S32 raw_w = imageraw->getWidth() ; S32 raw_h = imageraw->getHeight() ; @@ -1333,10 +1448,10 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S return createGLTexture(discard_level, rawdata, FALSE, usename); } -static LLFastTimer::DeclareTimer FTM_CREATE_GL_TEXTURE3("createGLTexture3(data)"); -BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_hasmips, S32 usename) +static LLTrace::BlockTimerStatHandle FTM_CREATE_GL_TEXTURE3("createGLTexture3(data)"); +BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_hasmips, GLTextureName* usename) { - LLFastTimer t(FTM_CREATE_GL_TEXTURE3); + LL_RECORD_BLOCK_TIME(FTM_CREATE_GL_TEXTURE3); llassert(data_in); stop_glerror(); @@ -1347,23 +1462,23 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_ } discard_level = llclamp(discard_level, 0, (S32)mMaxDiscardLevel); - if (mTexName != 0 && discard_level == mCurrentDiscardLevel) + if (getTexName() != 0 && discard_level == mCurrentDiscardLevel) { // This will only be true if the size has not changed setImage(data_in, data_hasmips); + //checkTexSize(); return TRUE; } - U32 old_name = mTexName; // S32 old_discard = mCurrentDiscardLevel; - if (usename != 0) + if (usename && *usename) { - mTexName = usename; + mTexName = *usename; } else { - LLImageGL::generateTextures(mBindTarget, mFormatInternal, 1, &mTexName); + mTexName = createTextureName(); stop_glerror(); { llverify(gGL.getTexUnit(0)->bind(this)); @@ -1374,9 +1489,9 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_ stop_glerror(); } } - if (!mTexName) + if (!getTexName()) { - llerrs << "LLImageGL::createGLTexture failed to make texture" << llendl; + LL_ERRS() << "LLImageGL::createGLTexture failed to make texture" << LL_ENDL; } if (mUseMipMaps) @@ -1394,37 +1509,25 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_ mCurrentDiscardLevel = discard_level; setImage(data_in, data_hasmips); + glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_MAX_LEVEL, mMaxDiscardLevel - discard_level); // Set texture options to our defaults. gGL.getTexUnit(0)->setHasMipMaps(mHasMipMaps); gGL.getTexUnit(0)->setTextureAddressMode(mAddressMode); gGL.getTexUnit(0)->setTextureFilteringOption(mFilterOption); + //gGL.getTexUnit(0)->unbind(mBindTarget); + //llverify(gGL.getTexUnit(0)->bindManual(mBindTarget, getTexName())); + //checkTexSize(); + // things will break if we don't unbind after creation gGL.getTexUnit(0)->unbind(mBindTarget); stop_glerror(); - if (old_name != 0) - { - sGlobalTextureMemoryInBytes -= mTextureMemory; - - if(gAuditTexture) - { - decTextureCounter(mTextureMemory, mComponents, mCategory) ; - } - - LLImageGL::deleteTextures(mBindTarget, mFormatInternal, mMipLevels, 1, &old_name); - - stop_glerror(); - } + mTextureMemory = (S32Bytes)getMipBytes(discard_level); - mTextureMemory = getMipBytes(discard_level); - sGlobalTextureMemoryInBytes += mTextureMemory; + mTexName->addAllocatedMemory(mTextureMemory, mComponents, mCategory); - if(gAuditTexture) - { - incTextureCounter(mTextureMemory, mComponents, mCategory) ; - } // mark this as bound at this point, so we don't throw it out immediately mLastBindTime = sLastFrameTime; return TRUE; @@ -1434,7 +1537,7 @@ BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compre { // VWR-13505 : Merov : Allow gl texture read back so save texture works again (temporary) //llassert_always(sAllowReadBackRaw) ; - //llerrs << "should not call this function!" << llendl ; + //LL_ERRS() << "should not call this function!" << LL_ENDL ; if (discard_level < 0) { @@ -1443,7 +1546,7 @@ BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compre return FALSE; } - if (mTexName == 0 || discard_level < mCurrentDiscardLevel || discard_level > mMaxDiscardLevel ) + if (getTexName() == 0 || discard_level < mCurrentDiscardLevel || discard_level > mMaxDiscardLevel ) { return FALSE; } @@ -1452,7 +1555,7 @@ BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compre //explicitly unbind texture gGL.getTexUnit(0)->unbind(mBindTarget); - llverify(gGL.getTexUnit(0)->bindManual(mBindTarget, mTexName)); + llverify(gGL.getTexUnit(0)->bindManual(mBindTarget, getTexName())); //debug code, leave it there commented. checkTexSize() ; @@ -1474,39 +1577,38 @@ BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compre } if(width < glwidth) { - llwarns << "texture size is smaller than it should be." << llendl ; - llwarns << "width: " << width << " glwidth: " << glwidth << " mWidth: " << mWidth << - " mCurrentDiscardLevel: " << (S32)mCurrentDiscardLevel << " discard_level: " << (S32)discard_level << llendl ; + LL_WARNS() << "texture size is smaller than it should be." << LL_ENDL ; + LL_WARNS() << "width: " << width << " glwidth: " << glwidth << " mWidth: " << mWidth << + " mCurrentDiscardLevel: " << (S32)mCurrentDiscardLevel << " discard_level: " << (S32)discard_level << LL_ENDL ; return FALSE ; } if (width <= 0 || width > 2048 || height <= 0 || height > 2048 || ncomponents < 1 || ncomponents > 4) { - llerrs << llformat("LLImageGL::readBackRaw: bogus params: %d x %d x %d",width,height,ncomponents) << llendl; - } - - LLGLint is_compressed = 0; - if (compressed_ok) - { - glGetTexLevelParameteriv(mTarget, is_compressed, GL_TEXTURE_COMPRESSED, (GLint*)&is_compressed); + LL_ERRS() << llformat("LLImageGL::readBackRaw: bogus params: %d x %d x %d",width,height,ncomponents) << LL_ENDL; } //----------------------------------------------------------------------------------------------- GLenum error ; while((error = glGetError()) != GL_NO_ERROR) { - llwarns << "GL Error happens before reading back texture. Error code: " << error << llendl ; + LL_WARNS() << "GL Error happens before reading back texture. Error code: " << error << LL_ENDL ; } //----------------------------------------------------------------------------------------------- - if (is_compressed) + if (mIsCompressed) { + if (!compressed_ok) + { + return false; + } + LLGLint glbytes; glGetTexLevelParameteriv(mTarget, gl_discard, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, (GLint*)&glbytes); if(!imageraw->allocateDataSize(width, height, ncomponents, glbytes)) { - llwarns << "Memory allocation failed for reading back texture. Size is: " << glbytes << llendl ; - llwarns << "width: " << width << "height: " << height << "components: " << ncomponents << llendl ; + LL_WARNS() << "Memory allocation failed for reading back texture. Size is: " << glbytes << LL_ENDL ; + LL_WARNS() << "width: " << width << "height: " << height << "components: " << ncomponents << LL_ENDL ; return FALSE ; } @@ -1517,8 +1619,8 @@ BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compre { if(!imageraw->allocateDataSize(width, height, ncomponents)) { - llwarns << "Memory allocation failed for reading back texture." << llendl ; - llwarns << "width: " << width << "height: " << height << "components: " << ncomponents << llendl ; + LL_WARNS() << "Memory allocation failed for reading back texture." << LL_ENDL ; + LL_WARNS() << "width: " << width << "height: " << height << "components: " << ncomponents << LL_ENDL ; return FALSE ; } @@ -1529,12 +1631,12 @@ BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compre //----------------------------------------------------------------------------------------------- if((error = glGetError()) != GL_NO_ERROR) { - llwarns << "GL Error happens after reading back texture. Error code: " << error << llendl ; + LL_WARNS() << "GL Error happens after reading back texture. Error code: " << error << LL_ENDL ; imageraw->deleteData() ; while((error = glGetError()) != GL_NO_ERROR) { - llwarns << "GL Error happens after reading back texture. Error code: " << error << llendl ; + LL_WARNS() << "GL Error happens after reading back texture. Error code: " << error << LL_ENDL ; } return FALSE ; @@ -1548,34 +1650,6 @@ void LLImageGL::deleteDeadTextures() { bool reset = false; - /*for(U32 i=0;isecond.empty()) - { - GLuint tex = it->second.front(); - it->second.pop_front(); - for (int j = 0; j < gGLManager.mNumTextureImageUnits; j++) - { - LLTexUnit* tex_unit = gGL.getTexUnit(j); - if (tex_unit && tex_unit->getCurrTexture() == tex) - { - tex_unit->unbind(tex_unit->getCurrType()); - stop_glerror(); - - if (i > 0) - { - reset = true; - } - } - } - glDeleteTextures(1, &tex); - stop_glerror(); - } - } - }*/ - if (reset) { gGL.getTexUnit(0)->activate(); @@ -1584,21 +1658,10 @@ void LLImageGL::deleteDeadTextures() void LLImageGL::destroyGLTexture() { - if (mTexName != 0) + if (getTexName()) { - if(mTextureMemory) - { - if(gAuditTexture) - { - decTextureCounter(mTextureMemory, mComponents, mCategory) ; - } - sGlobalTextureMemoryInBytes -= mTextureMemory; - mTextureMemory = 0; - } - - LLImageGL::deleteTextures(mBindTarget, mFormatInternal, mMipLevels, 1, &mTexName); - mCurrentDiscardLevel = -1 ; //invalidate mCurrentDiscardLevel. - mTexName = 0; + mTexName.reset(); + mCurrentDiscardLevel = -1 ; //invalidate mCurrentDiscardLevel. mGLTextureCreated = FALSE ; } } @@ -1606,7 +1669,7 @@ void LLImageGL::destroyGLTexture() //force to invalidate the gl texture, most likely a sculpty texture void LLImageGL::forceToInvalidateGLTexture() { - if (mTexName != 0) + if (getTexName() != 0) { destroyGLTexture(); } @@ -1626,7 +1689,8 @@ void LLImageGL::setAddressMode(LLTexUnit::eTextureAddressMode mode) mAddressMode = mode; } - if (gGL.getTexUnit(gGL.getCurrentTexUnitIndex())->getCurrTexture() == mTexName) + GLuint tex = getTexName(); + if (tex && gGL.getTexUnit(gGL.getCurrentTexUnitIndex())->getCurrTexture() == tex) { gGL.getTexUnit(gGL.getCurrentTexUnitIndex())->setTextureAddressMode(mode); mTexOptionsDirty = false; @@ -1641,7 +1705,8 @@ void LLImageGL::setFilteringOption(LLTexUnit::eTextureFilterOptions option) mFilterOption = option; } - if (mTexName != 0 && gGL.getTexUnit(gGL.getCurrentTexUnitIndex())->getCurrTexture() == mTexName) + GLuint tex = getTexName(); + if (tex && gGL.getTexUnit(gGL.getCurrentTexUnitIndex())->getCurrTexture() == tex) { gGL.getTexUnit(gGL.getCurrentTexUnitIndex())->setTextureFilteringOption(option); mTexOptionsDirty = false; @@ -1653,9 +1718,10 @@ BOOL LLImageGL::getIsResident(BOOL test_now) { if (test_now) { - if (mTexName != 0) + GLuint tex = getTexName(); + if (tex) { - glAreTexturesResident(1, (GLuint*)&mTexName, &mIsResident); + glAreTexturesResident(1, (GLuint*)&tex, &mIsResident); } else { @@ -1739,7 +1805,6 @@ void LLImageGL::setTarget(const LLGLenum target, const LLTexUnit::eTextureType b } //Used by media in V2 -const S8 INVALID_OFFSET = -99 ; void LLImageGL::setNeedsAlphaAndPickMask(BOOL need_mask) { if(mNeedsAlphaAndPickMask != need_mask) @@ -1753,7 +1818,6 @@ void LLImageGL::setNeedsAlphaAndPickMask(BOOL need_mask) else //do not need alpha mask { mAlphaOffset = INVALID_OFFSET ; - mCanMask = FALSE; } } } @@ -1776,8 +1840,7 @@ void LLImageGL::calcAlphaChannelOffsetAndStride() mAlphaStride = 2; break; case GL_RGB: - mNeedsAlphaAndPickMask = FALSE ; - mCanMask = FALSE; + setNeedsAlphaAndPickMask(FALSE); return ; //no alpha channel. case GL_RGBA: mAlphaStride = 4; @@ -1821,17 +1884,16 @@ void LLImageGL::calcAlphaChannelOffsetAndStride() mAlphaOffset < 0 || //unsupported type (mFormatPrimary == GL_BGRA_EXT && mFormatType != GL_UNSIGNED_BYTE)) //unknown situation { - llwarns << "Cannot analyze alpha for image with format type " << std::hex << mFormatType << std::dec << llendl; + LL_WARNS() << "Cannot analyze alpha for image with format type " << std::hex << mFormatType << std::dec << LL_ENDL; - mNeedsAlphaAndPickMask = FALSE ; - mCanMask = FALSE; + setNeedsAlphaAndPickMask(FALSE); } } -std::map > > sTextureMaskMap; +//std::map > > sTextureMaskMap; void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h) { - if(!mNeedsAlphaAndPickMask || !mCanMask) + if(!mNeedsAlphaAndPickMask) { return ; } @@ -1844,6 +1906,9 @@ void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h) U32 sample[16]; memset(sample, 0, sizeof(U32)*16); + U32 min = 0, max = 0; + U32 mids = 0; + // generate histogram of quantized alpha. // also add-in the histogram of a 2x2 box-sampled version. The idea is // this will mid-skew the data (and thus increase the chances of not @@ -1875,6 +1940,10 @@ void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h) ++sample[s3/16]; ++sample[s4/16]; + min = std::min(std::min(std::min(std::min(min, s1), s2), s3), s4); + max = std::max(std::max(std::max(std::max(max, s1), s2), s3), s4); + mids += (s1 > 2 && s1 < 253) + (s2 > 2 && s2 < 253) + (s3 > 2 && s3 < 253) + (s4 > 2 && s4 < 253); + const U32 asum = (s1+s2+s3+s4); alphatotal += asum; sample[asum/(16*4)] += 4; @@ -1903,9 +1972,18 @@ void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h) ++sample[s1/16]; current += mAlphaStride; + min = std::min(min, s1); + max = std::max(max, s1); + mids += (s1 > 2 && s1 < 253); + if(i%2==0) { - S32 avg = (s1+current[mAlphaStride])/2; + const U32 s2 = *current; + min = std::min(min, s2); + max = std::max(max, s2); + mids += (s2 > 2 && s2 < 253); + + S32 avg = (s1+s2)/2; if(avg >=128) avg-=255; sum+=F64(avg*avg*2)/F64(length); @@ -1947,9 +2025,10 @@ void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h) mIsMask = TRUE; } - mMaskRMSE = sqrt(sum)/255.0; + mMaskMidPercentile = (F32)mids / (F32)(w * h); + mMaskRMSE = ((max-min)%255)==0 ? sqrt(sum)/255.0 : FLT_MAX; - std::list > &data = sTextureMaskMap[getTexName()]; + /*std::list > &data = sTextureMaskMap[getTexName()]; data.clear(); data.push_back(std::make_pair("RMSE", llformat("%f",mMaskRMSE))); data.push_back(std::make_pair(" sum", llformat("%lf",sum))); @@ -1960,10 +2039,39 @@ void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h) data.push_back(std::make_pair(" stride", llformat("%i",S32(mAlphaOffset)))); data.push_back(std::make_pair(" split", llformat("%u|%u|%u",lowerhalftotal,midrangetotal,upperhalftotal))); data.push_back(std::make_pair(" alphatotal", llformat("%u",alphatotal))); - data.push_back(std::make_pair(" alphatotal/48", llformat("%u",length/48))); + data.push_back(std::make_pair(" alphatotal/48", llformat("%u",length/48)));*/ } +//---------------------------------------------------------------------------- +U32 LLImageGL::createPickMask(S32 pWidth, S32 pHeight) +{ + U32 pick_width = pWidth/2 + 1; + U32 pick_height = pHeight/2 + 1; + + U32 size = pick_width * pick_height; + size = (size + 7) / 8; // pixelcount-to-bits + mPickMask = new U8[size]; + mPickMaskWidth = pick_width - 1; + mPickMaskHeight = pick_height - 1; + + memset(mPickMask, 0, sizeof(U8) * size); + + return size; +} + +//---------------------------------------------------------------------------- +void LLImageGL::freePickMask() +{ + // pickmask validity depends on old image size, delete it + if (mPickMask != NULL) + { + delete [] mPickMask; + } + mPickMask = NULL; + mPickMaskWidth = mPickMaskHeight = 0; +} + //---------------------------------------------------------------------------- void LLImageGL::updatePickMask(S32 width, S32 height, const U8* data_in) { @@ -1972,9 +2080,7 @@ void LLImageGL::updatePickMask(S32 width, S32 height, const U8* data_in) return ; } - delete [] mPickMask; - mPickMask = NULL; - mPickMaskWidth = mPickMaskHeight = 0; + freePickMask(); if (mFormatType != GL_UNSIGNED_BYTE || mFormatPrimary != GL_RGBA) @@ -1983,16 +2089,11 @@ void LLImageGL::updatePickMask(S32 width, S32 height, const U8* data_in) return; } - U32 pick_width = width/2 + 1; - U32 pick_height = height/2 + 1; - - U32 size = pick_width * pick_height; - size = (size + 7) / 8; // pixelcount-to-bits - mPickMask = new U8[size]; - mPickMaskWidth = pick_width - 1; - mPickMaskHeight = pick_height - 1; - - memset(mPickMask, 0, sizeof(U8) * size); +#ifdef SHOW_ASSERT + const U32 pickSize = createPickMask(width, height); +#else // SHOW_ASSERT + createPickMask(width, height); +#endif // SHOW_ASSERT U32 pick_bit = 0; @@ -2006,7 +2107,7 @@ void LLImageGL::updatePickMask(S32 width, S32 height, const U8* data_in) { U32 pick_idx = pick_bit/8; U32 pick_offset = pick_bit%8; - llassert(pick_idx < size); + llassert(pick_idx < pickSize); mPickMask[pick_idx] |= 1 << pick_offset; } @@ -2117,19 +2218,19 @@ S32 LLImageGL::getTextureCounterIndex(U32 val) } //static -void LLImageGL::incTextureCounter(U32 val, S32 ncomponents, S32 category) +void LLImageGL::incTextureCounter(S32Bytes val, S32 ncomponents, S32 category) { - sTextureLoadedCounter[getTextureCounterIndex(val)]++ ; + sTextureLoadedCounter[getTextureCounterIndex(val.value())]++ ; if(category > -1) - sTextureMemByCategory[category] += (S32)val * ncomponents ; + sTextureMemByCategory[category] += (S32Bytes)val * ncomponents ; } //static -void LLImageGL::decTextureCounter(U32 val, S32 ncomponents, S32 category) +void LLImageGL::decTextureCounter(S32Bytes val, S32 ncomponents, S32 category) { - sTextureLoadedCounter[getTextureCounterIndex(val)]-- ; + sTextureLoadedCounter[getTextureCounterIndex(val.value())]-- ; if(category > -1) - sTextureMemByCategory[category] -= (S32)val * ncomponents ; + sTextureMemByCategory[category] -= (S32Bytes)val * ncomponents ; } void LLImageGL::setCurTexSizebar(S32 index, BOOL set_pick_size) diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h index 4cbbcfc63f..c35a8a24ae 100644 --- a/indra/llrender/llimagegl.h +++ b/indra/llrender/llimagegl.h @@ -34,6 +34,7 @@ #include "llpointer.h" #include "llrefcount.h" #include "v2math.h" +#include "llunits.h" #include "llrender.h" @@ -44,25 +45,72 @@ class LLImageGL : public LLRefCount { friend class LLTexUnit; + friend class GLTextureName; public: - static U32 sCurTexName; - - //previously used but now available texture names - // sDeadTextureList[][] - typedef std::map > dead_texturelist_t; - static dead_texturelist_t sDeadTextureList[LLTexUnit::TT_NONE]; - + struct AllocationInfo; +private: // These 2 functions replace glGenTextures() and glDeleteTextures() - static void generateTextures(LLTexUnit::eTextureType type, U32 format, S32 numTextures, U32 *textures); - static void deleteTextures(LLTexUnit::eTextureType type, U32 format, S32 mip_levels, S32 numTextures, U32 *textures, bool immediate = false); + static void generateTextures(S32 numTextures, U32 *textures); + static void deleteTextures(S32 numTextures, U32 *textures, const std::vector& allocationData); + static void texMemoryAllocated(const AllocationInfo& entry); + static void texMemoryDeallocated(const AllocationInfo& entry); +public: static void deleteDeadTextures(); + struct AllocationInfo + { + AllocationInfo(S32Bytes& _size, U8 _components, U32 _category) : + size(_size), components(_components), category(_category) + {} + S32Bytes size; + U8 components; + U32 category; + }; + // Singu Note: + // The topology of GLImageGL is wrong. As a result, tex names are shared across multiple LLImageGL + // instances. To avoid redundant glDelete calls gl tex names have been wrapped in GLTextureName, + // which is refcounted via std::shared_ptr. + class GLTextureNameInstance { + public: + GLTextureNameInstance(U32 size = 1) : mTexCount(size) + { + mTexNames.resize(mTexCount, 0); + LLImageGL::generateTextures(1, mTexNames.data()); + } + ~GLTextureNameInstance() + { + LLImageGL::deleteTextures(1, mTexNames.data(), mAllocationData); + } + GLuint getTexName(U32 idx = 0) const + { + return mTexNames[idx]; + } + void addAllocatedMemory(S32Bytes size, U8 components, U32 category) + { + mAllocationData.emplace_back(size, components, category); + LLImageGL::texMemoryAllocated(mAllocationData.back()); + } + const std::vector& getAllocatedMemoryInfo() const + { + return mAllocationData; + } + private: + const size_t mTexCount; + std::vector mTexNames; + std::vector mAllocationData; + }; + typedef std::shared_ptr GLTextureName; + + static GLTextureName createTextureName(U32 size = 0) { + return std::make_shared(); + } + // Size calculation static S32 dataFormatBits(S32 dataformat); static S32 dataFormatBytes(S32 dataformat, S32 width, S32 height); static S32 dataFormatComponents(S32 dataformat); - BOOL updateBindStats(S32 tex_mem) const ; + BOOL updateBindStats(S32Bytes tex_mem) const ; F32 getTimePassedSinceLastBound(); void forceUpdateBindStats(void) const; @@ -75,7 +123,7 @@ class LLImageGL : public LLRefCount static void dirtyTexOptions(); // Sometimes called externally for textures not using LLImageGL (should go away...) - static S32 updateBoundTexMem(const S32 mem, const S32 ncomponents, S32 category) ; + static S32 updateBoundTexMem(const S32Bytes mem, const S32 ncomponents, S32 category) ; static bool checkSize(S32 width, S32 height); @@ -87,9 +135,9 @@ class LLImageGL : public LLRefCount static BOOL create(LLPointer& dest, const LLImageRaw* imageraw, BOOL usemipmaps = TRUE); public: - LLImageGL(BOOL usemipmaps = TRUE); - LLImageGL(U32 width, U32 height, U8 components, BOOL usemipmaps = TRUE); - LLImageGL(const LLImageRaw* imageraw, BOOL usemipmaps = TRUE); + LLImageGL(BOOL usemipmaps = TRUE, bool allow_compression = false); + LLImageGL(U32 width, U32 height, U8 components, BOOL usemipmaps = TRUE, bool allow_compression = false); + LLImageGL(const LLImageRaw* imageraw, BOOL usemipmaps = TRUE, bool allow_compression = false); protected: virtual ~LLImageGL(); @@ -104,12 +152,12 @@ class LLImageGL : public LLRefCount void setComponents(S32 ncomponents) { mComponents = (S8)ncomponents ;} void setAllowCompression(bool allow) { mAllowCompression = allow; } - static void setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void *pixels, bool allow_compression = true); + static bool setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void *pixels = nullptr, bool allow_compression = false); BOOL createGLTexture() ; - BOOL createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename = 0, BOOL to_create = TRUE, + BOOL createGLTexture(S32 discard_level, const LLImageRaw* imageraw, GLTextureName* usename = nullptr, BOOL to_create = TRUE, S32 category = sMaxCategories-1); - BOOL createGLTexture(S32 discard_level, const U8* data, BOOL data_hasmips = FALSE, S32 usename = 0); + BOOL createGLTexture(S32 discard_level, const U8* data, BOOL data_hasmips = FALSE, GLTextureName* usename = nullptr); void setImage(const LLImageRaw* imageraw); void setImage(const U8* data_in, BOOL data_hasmips = FALSE); BOOL setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update = FALSE); @@ -139,10 +187,10 @@ class LLImageGL : public LLRefCount LLGLenum getPrimaryFormat() const { return mFormatPrimary; } LLGLenum getFormatType() const { return mFormatType; } - BOOL getHasGLTexture() const { return mTexName != 0; } - LLGLuint getTexName() const { return mTexName; } + BOOL getHasGLTexture() const { return mTexName != nullptr; } + LLGLuint getTexName() const { return mTexName ? mTexName->getTexName() : 0; } - BOOL getIsAlphaMask(const F32 max_rmse) const { return mCanMask && (max_rmse < 0.f ? (bool)mIsMask : (mMaskRMSE <= max_rmse)); } + BOOL getIsAlphaMask(const F32 max_rmse, const F32 max_mid) const { return mNeedsAlphaAndPickMask && (max_rmse < 0.f ? (bool)mIsMask : (mMaskRMSE <= max_rmse && mMaskMidPercentile <= max_mid)); } BOOL getIsResident(BOOL test_now = FALSE); // not const @@ -173,16 +221,19 @@ class LLImageGL : public LLRefCount LLTexUnit::eTextureFilterOptions getFilteringOption(void) const { return mFilterOption; } LLGLenum getTexTarget()const { return mTarget ;} - void init(BOOL usemipmaps); + void init(BOOL usemipmaps, bool allow_compression); virtual void cleanup(); // Clean up the LLImageGL so it can be reinitialized. Be careful when using this in derived class destructors void setNeedsAlphaAndPickMask(BOOL need_mask); public: // Various GL/Rendering options - S32 mTextureMemory; + S32Bytes mTextureMemory; mutable F32 mLastBindTime; // last time this was bound, by discard level private: + U32 createPickMask(S32 pWidth, S32 pHeight); + void freePickMask(); + LLPointer mSaveData; // used for destroyGL/restoreGL S32 mSaveDiscardLevel; U8* mPickMask; //downsampled bitmap approximation of alpha channel. NULL if no alpha channel @@ -192,20 +243,21 @@ class LLImageGL : public LLRefCount S8 mHasExplicitFormat; // If false (default), GL format is f(mComponents) S8 mAutoGenMips; - BOOL mCanMask; BOOL mIsMask; F32 mMaskRMSE; + F32 mMaskMidPercentile; BOOL mNeedsAlphaAndPickMask; S8 mAlphaStride ; S8 mAlphaOffset ; bool mGLTextureCreated ; - LLGLuint mTexName; + GLTextureName mTexName; U16 mWidth; U16 mHeight; S8 mCurrentDiscardLevel; bool mAllowCompression; + bool mIsCompressed = false; protected: LLGLenum mTarget; // Normally GL_TEXTURE2D, sometimes something else (ex. cube maps) @@ -236,9 +288,9 @@ class LLImageGL : public LLRefCount static F32 sLastFrameTime; // Global memory statistics - static S32 sGlobalTextureMemoryInBytes; // Tracks main memory texmem - static S32 sBoundTextureMemoryInBytes; // Tracks bound texmem for last completed frame - static S32 sCurBoundTextureMemory; // Tracks bound texmem for current frame + static S64Bytes sGlobalTextureMemory; // Tracks main memory texmem + static S64Bytes sBoundTextureMemory; // Tracks bound texmem for last completed frame + static S64Bytes sCurBoundTextureMemory; // Tracks bound texmem for current frame static U32 sBindCount; // Tracks number of texture binds for current frame static U32 sUniqueCount; // Tracks number of unique texture binds for current frame static BOOL sGlobalUseAnisotropic; @@ -282,8 +334,8 @@ class LLImageGL : public LLRefCount static void setHighlightTexture(S32 category) ; static S32 getTextureCounterIndex(U32 val) ; - static void incTextureCounter(U32 val, S32 ncomponents, S32 category) ; - static void decTextureCounter(U32 val, S32 ncomponents, S32 category) ; + static void incTextureCounter(S32Bytes val, S32 ncomponents, S32 category) ; + static void decTextureCounter(S32Bytes val, S32 ncomponents, S32 category) ; static void setCurTexSizebar(S32 index, BOOL set_pick_size = TRUE) ; static void resetCurTexSizebar(); //---------------------------------------- @@ -291,9 +343,9 @@ class LLImageGL : public LLRefCount //for debug use: show texture category distribution //---------------------------------------- - static std::vector sTextureMemByCategory; - static std::vector sTextureMemByCategoryBound ; - static std::vector sTextureCurMemByCategoryBound ; + static std::vector sTextureMemByCategory; + static std::vector sTextureMemByCategoryBound ; + static std::vector sTextureCurMemByCategoryBound ; //---------------------------------------- // **************************************************************************************************** //End of definitions for texture auditing use only diff --git a/indra/llrender/llpostprocess.cpp b/indra/llrender/llpostprocess.cpp index 1ea12e351e..0096525f08 100644 --- a/indra/llrender/llpostprocess.cpp +++ b/indra/llrender/llpostprocess.cpp @@ -35,14 +35,17 @@ #include "llpostprocess.h" #include "lldir.h" +#include "llcontrol.h" +#include "llfasttimer.h" #include "llgl.h" #include "llglslshader.h" +#include "llmatrix4a.h" +#include "llperlin.h" #include "llrender.h" #include "llsdserialize.h" #include "llsdutil.h" #include "llsdutil_math.h" #include "llvertexbuffer.h" -#include "llfasttimer.h" extern LLGLSLShader gPostColorFilterProgram; extern LLGLSLShader gPostNightVisionProgram; @@ -51,6 +54,28 @@ extern LLGLSLShader gPostPosterizeProgram; extern LLGLSLShader gPostMotionBlurProgram; extern LLGLSLShader gPostVignetteProgram; +static LLStaticHashedString sGamma("gamma"); +static LLStaticHashedString sBrightness("brightness"); +static LLStaticHashedString sContrast("contrast"); +static LLStaticHashedString sContrastBase("contrastBase"); +static LLStaticHashedString sSaturation("saturation"); +static LLStaticHashedString sBrightMult("brightMult"); +static LLStaticHashedString sNoiseStrength("noiseStrength"); +static LLStaticHashedString sLayerCount("layerCount"); + +static LLStaticHashedString sVignetteStrength("vignette_strength"); +static LLStaticHashedString sVignettRadius("vignette_radius"); +static LLStaticHashedString sVignetteDarkness("vignette_darkness"); +static LLStaticHashedString sVignetteDesaturation("vignette_desaturation"); +static LLStaticHashedString sVignetteChromaticAberration("vignette_chromatic_aberration"); + +static LLStaticHashedString sHorizontalPass("horizontalPass"); +static LLStaticHashedString sKern("kern"); + +static LLStaticHashedString sPrevProj("prev_proj"); +static LLStaticHashedString sInvProj("inv_proj"); +static LLStaticHashedString sBlurStrength("blur_strength"); + static const unsigned int NOISE_SIZE = 512; static const char * const XML_FILENAME = "postprocesseffects.xml"; @@ -155,16 +180,16 @@ class LLColorFilterShader : public LLPostProcessSinglePassColorShader /*virtual*/ QuadType preDraw() { - getShader().uniform1f("gamma", mGamma); - getShader().uniform1f("brightness", mBrightness); - getShader().uniform1f("contrast", mContrast); + getShader().uniform1f(sGamma, mGamma); + getShader().uniform1f(sBrightness, mBrightness); + getShader().uniform1f(sContrast, mContrast); float baseI = (mContrastBase.get()[VX] + mContrastBase.get()[VY] + mContrastBase.get()[VZ]) / 3.0f; baseI = mContrastBase.get()[VW] / llmax(baseI,0.001f); float baseR = mContrastBase.get()[VX] * baseI; float baseG = mContrastBase.get()[VY] * baseI; float baseB = mContrastBase.get()[VZ] * baseI; - getShader().uniform3fv("contrastBase", 1, LLVector3(baseR, baseG, baseB).mV); - getShader().uniform1f("saturation", mSaturation); + getShader().uniform3fv(sContrastBase, 1, LLVector3(baseR, baseG, baseB).mV); + getShader().uniform1f(sSaturation, mSaturation); return QUAD_NORMAL; } @@ -187,8 +212,8 @@ class LLNightVisionShader : public LLPostProcessSinglePassColorShader { LLPostProcess::getInstance()->bindNoise(1); - getShader().uniform1f("brightMult", mBrightnessMult); - getShader().uniform1f("noiseStrength", mNoiseStrength); + getShader().uniform1f(sBrightMult, mBrightnessMult); + getShader().uniform1f(sNoiseStrength, mNoiseStrength); return QUAD_NOISE; } @@ -206,7 +231,7 @@ class LLPosterizeShader : public LLPostProcessSinglePassColorShader } /*virtual*/ QuadType preDraw() { - getShader().uniform1i("layerCount", mNumLayers); + getShader().uniform1i(sLayerCount, mNumLayers); return QUAD_NORMAL; } }; @@ -232,12 +257,12 @@ class LLVignetteShader : public LLPostProcessSinglePassColorShader /*virtual*/ QuadType preDraw() { LLVector2 screen_rect = LLPostProcess::getInstance()->getDimensions(); - getShader().uniform1f("vignette_strength", mStrength); - getShader().uniform1f("vignette_radius", mRadius); - getShader().uniform1f("vignette_darkness", mDarkness); - getShader().uniform1f("vignette_desaturation", mDesaturation); - getShader().uniform1f("vignette_chromatic_aberration", mChromaticAberration); - getShader().uniform2fv("screen_res", 1, screen_rect.mV); + + getShader().uniform1f(sVignetteStrength, mStrength); + getShader().uniform1f(sVignettRadius, mRadius); + getShader().uniform1f(sVignetteDarkness, mDarkness); + getShader().uniform1f(sVignetteDesaturation, mDesaturation); + getShader().uniform1f(sVignetteChromaticAberration, mChromaticAberration); return QUAD_NORMAL; } }; @@ -259,13 +284,18 @@ class LLGaussBlurShader : public LLPostProcessShader /*virtual*/ S32 getDepthChannel() const { return -1; } /*virtual*/ QuadType preDraw() { - mPassLoc = getShader().getUniformLocation("horizontalPass"); + LLVector2 screen_rect = LLPostProcess::getInstance()->getDimensions(); + + mPassLoc = getShader().getUniformLocation(sHorizontalPass); + LLVector4 vec[] = { LLVector4(1.3846153846f, 3.2307692308f, 0.f, 0.f) / screen_rect.mV[VX], LLVector4( 0.f,0.f, 1.3846153846f, 3.2307692308f ) / screen_rect.mV[VY] }; + getShader().uniform4fv(sKern, LL_ARRAY_SIZE(vec), (GLfloat*)vec); return QUAD_NORMAL; } /*virtual*/ bool draw(U32 pass) { if((S32)pass > mNumPasses*2) return false; + gGL.syncShaders(); glUniform1iARB(mPassLoc, (pass-1) % 2); return true; } @@ -282,23 +312,22 @@ class LLMotionShader : public LLPostProcessShader { addSetting(mStrength); } - /*virtual*/ bool isEnabled() const { return LLPostProcessShader::isEnabled() && llabs(gGLModelView[0] - gGLPreviousModelView[0]) > .0000001; } + /*virtual*/ bool isEnabled() const { return LLPostProcessShader::isEnabled() && llabs(gGLModelView.getF32ptr()[0] - gGLPreviousModelView.getF32ptr()[0]) > .0000001; } /*virtual*/ S32 getColorChannel() const { return 0; } /*virtual*/ S32 getDepthChannel() const { return 1; } /*virtual*/ QuadType preDraw() { - glh::matrix4f inv_proj(gGLModelView); - inv_proj.mult_left(gGLProjection); - inv_proj = inv_proj.inverse(); - glh::matrix4f prev_proj(gGLPreviousModelView); - prev_proj.mult_left(gGLProjection); + LLMatrix4a inv_proj; + inv_proj.setMul(gGLProjection,gGLModelView); + inv_proj.invert(); + LLMatrix4a prev_proj; + prev_proj.setMul(gGLProjection,gGLPreviousModelView); LLVector2 screen_rect = LLPostProcess::getInstance()->getDimensions(); - getShader().uniformMatrix4fv("prev_proj", 1, GL_FALSE, prev_proj.m); - getShader().uniformMatrix4fv("inv_proj", 1, GL_FALSE, inv_proj.m); - getShader().uniform2fv("screen_res", 1, screen_rect.mV); - getShader().uniform1i("blur_strength", mStrength); + getShader().uniformMatrix4fv(sPrevProj, 1, GL_FALSE, prev_proj.getF32ptr()); + getShader().uniformMatrix4fv(sInvProj, 1, GL_FALSE, inv_proj.getF32ptr()); + getShader().uniform1i(sBlurStrength, mStrength); return QUAD_NORMAL; } @@ -312,7 +341,7 @@ class LLMotionShader : public LLPostProcessShader LLPostProcess::LLPostProcess(void) : mVBO(NULL), mDepthTexture(0), - mNoiseTexture(NULL), + mNoiseTexture(0), mScreenWidth(0), mScreenHeight(0), mNoiseTextureScale(0.f), @@ -327,41 +356,44 @@ LLPostProcess::LLPostProcess(void) : mShaders.push_back(new LLPosterizeShader()); /* Do nothing. Needs to be updated to use our current shader system, and to work with the move into llrender.*/ - std::string pathName(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight", XML_FILENAME)); - LL_DEBUGS2("AppInit", "Shaders") << "Loading PostProcess Effects settings from " << pathName << LL_ENDL; - - llifstream effectsXML(pathName); - - if (effectsXML) + auto load_effects = [&](const std::string& pathName) { - LLPointer parser = new LLSDXMLParser(); + LL_DEBUGS("AppInit", "Shaders") << "Loading PostProcess Effects settings from " << pathName << LL_ENDL; + llifstream effectsXML(pathName); - parser->parse(effectsXML, mAllEffectInfo, LLSDSerialize::SIZE_UNLIMITED); - } + if (effectsXML) + { + LLPointer parser = new LLSDXMLParser(); + parser->parse(effectsXML, mAllEffectInfo, LLSDSerialize::SIZE_UNLIMITED); + } + }; + load_effects(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight", XML_FILENAME)); + load_effects(gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "windlight", XML_FILENAME)); - if (!mAllEffectInfo.has("default")) - mAllEffectInfo["default"] = LLSD::emptyMap(); + auto setting = gSavedSettings.getControl("SinguPostProcessDefault"); + setting->getSignal()->connect(std::bind(&LLPostProcess::setSelectedEffect, this, std::bind(&LLSD::asStringRef, std::placeholders::_2))); + const auto& str = setting->get().asStringRef(); + if (!mAllEffectInfo.has(str)) + mAllEffectInfo[str] = LLSD::emptyMap(); - LLSD& defaults = mAllEffectInfo["default"]; + LLSD& defaults = mAllEffectInfo[str]; - for(std::list >::iterator it=mShaders.begin();it!=mShaders.end();++it) + // Add defaults for all missing effects + for(auto& shader : mShaders) { - LLSD shader_defaults = (*it)->getDefaults(); + const LLSD shader_defaults = shader->getDefaults(); for (LLSD::map_const_iterator it2 = defaults.beginMap();it2 != defaults.endMap();++it2) { if(!defaults.has(it2->first)) defaults[it2->first]=it2->second; } } - for(std::list >::iterator it=mShaders.begin();it!=mShaders.end();++it) - { - (*it)->loadSettings(defaults); - } - setSelectedEffect("default"); + setSelectedEffect(str); } LLPostProcess::~LLPostProcess(void) { + gSavedSettings.setString("SinguPostProcessDefault", mSelectedEffectName); destroyGL() ; } @@ -376,7 +408,7 @@ void LLPostProcess::initialize(unsigned int width, unsigned int height) //Setup our VBO. { - mVBO = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TEXCOORD1,3); + mVBO = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TEXCOORD1,GL_STREAM_DRAW_ARB); mVBO->allocateBuffer(4,0,TRUE); LLStrider v; @@ -386,11 +418,22 @@ void LLPostProcess::initialize(unsigned int width, unsigned int height) mVBO->getVertexStrider(v); mVBO->getTexCoord0Strider(uv1); mVBO->getTexCoord1Strider(uv2); - - v[0] = LLVector3( uv2[0] = uv1[0] = LLVector2(0, 0) ); - v[1] = LLVector3( uv2[1] = uv1[1] = LLVector2(0, mScreenHeight) ); - v[2] = LLVector3( uv2[2] = uv1[2] = LLVector2(mScreenWidth, 0) ); - v[3] = LLVector3( uv2[3] = uv1[3] = LLVector2(mScreenWidth, mScreenHeight) ); + + uv2[0] = uv1[0] = LLVector2(0, 0); + uv2[1] = uv1[1] = LLVector2(0, 1); + uv2[2] = uv1[2] = LLVector2(1, 0); + uv2[3] = uv1[3] = LLVector2(1, 1); + + LLVector3 vec1[4] = { + LLVector3(0, 0, 0), + LLVector3(0, mScreenHeight, 0), + LLVector3(mScreenWidth, 0, 0), + LLVector3(mScreenWidth, mScreenHeight, 0) }; + + v[0] = vec1[0]; + v[1] = vec1[1]; + v[2] = vec1[2]; + v[3] = vec1[3]; mVBO->flush(); } @@ -399,23 +442,22 @@ void LLPostProcess::initialize(unsigned int width, unsigned int height) void LLPostProcess::createScreenTextures() { - const LLTexUnit::eTextureType type = LLTexUnit::TT_RECT_TEXTURE; + const LLTexUnit::eTextureType type = LLTexUnit::TT_TEXTURE; mRenderTarget[0].allocate(mScreenWidth,mScreenHeight,GL_RGBA,FALSE,FALSE,type,FALSE); if(mRenderTarget[0].getFBO())//Only need pingpong between two rendertargets if FBOs are supported. mRenderTarget[1].allocate(mScreenWidth,mScreenHeight,GL_RGBA,FALSE,FALSE,type,FALSE); stop_glerror(); - if(mDepthTexture) - LLImageGL::deleteTextures(type, 0, 0, 1, &mDepthTexture, true); + mDepthTexture.reset(); for(std::list >::iterator it=mShaders.begin();it!=mShaders.end();++it) { if((*it)->getDepthChannel()>=0) { - LLImageGL::generateTextures(type, GL_DEPTH_COMPONENT24, 1, &mDepthTexture); - gGL.getTexUnit(0)->bindManual(type, mDepthTexture); - LLImageGL::setManualImage(LLTexUnit::getInternalType(type), 0, GL_DEPTH_COMPONENT24, mScreenWidth, mScreenHeight, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL, false); + mDepthTexture = LLImageGL::createTextureName(); + gGL.getTexUnit(0)->bindManual(type, mDepthTexture->getTexName()); + LLImageGL::setManualImage(LLTexUnit::getInternalType(type), 0, GL_DEPTH_COMPONENT24, mScreenWidth, mScreenHeight, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT); stop_glerror(); gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); @@ -430,43 +472,45 @@ void LLPostProcess::createNoiseTexture() std::vector buffer(NOISE_SIZE * NOISE_SIZE); for (unsigned int i = 0; i < NOISE_SIZE; i++){ for (unsigned int k = 0; k < NOISE_SIZE; k++){ - buffer[(i * NOISE_SIZE) + k] = (GLubyte)((double) rand() / ((double) RAND_MAX + 1.f) * 255.f); + F32 pnoise = LLPerlinNoise::noise(LLVector2(i, k) * .5f) * (1.f/.7f); + buffer[i * NOISE_SIZE + k] = (GLubyte)(llclamp(.5f + pnoise * .5f, 0.f, 1.f) * 255.f); } } - mNoiseTexture = new LLImageGL(FALSE) ; - if(mNoiseTexture->createGLTexture()) - { - gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mNoiseTexture->getTexName()); - LLImageGL::setManualImage(GL_TEXTURE_2D, 0, GL_LUMINANCE, NOISE_SIZE, NOISE_SIZE, GL_LUMINANCE, GL_UNSIGNED_BYTE, &buffer[0]); - stop_glerror(); - gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); - gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_WRAP); - stop_glerror(); - } + mNoiseTexture = LLImageGL::createTextureName(); + stop_glerror(); + gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mNoiseTexture->getTexName()); + stop_glerror(); + + LLImageGL::setManualImage(GL_TEXTURE_2D, 0, GL_LUMINANCE8, NOISE_SIZE, NOISE_SIZE, GL_LUMINANCE, GL_UNSIGNED_BYTE, &buffer[0]); + + stop_glerror(); + gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); + gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_WRAP); + stop_glerror(); } void LLPostProcess::destroyGL() { mRenderTarget[0].release(); mRenderTarget[1].release(); - if(mDepthTexture) - LLImageGL::deleteTextures(LLTexUnit::TT_RECT_TEXTURE, 0, 0, 1, &mDepthTexture, true); - mDepthTexture=0; - mNoiseTexture = NULL ; + mDepthTexture.reset(); + mNoiseTexture.reset(); + mNoiseTexture=0 ; mVBO = NULL ; } /*static*/void LLPostProcess::cleanupClass() { - if(instanceExists()) - getInstance()->destroyGL() ; + if (instanceExists()) + deleteSingleton(); } void LLPostProcess::copyFrameBuffer() { mRenderTarget[!!mRenderTarget[0].getFBO()].bindTexture(0,0); - glCopyTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB,0,0,0,0,0,mScreenWidth, mScreenHeight); + glCopyTexSubImage2D(GL_TEXTURE_2D,0,0,0,0,0,mScreenWidth, mScreenHeight); + stop_glerror(); if(mDepthTexture) { @@ -474,8 +518,9 @@ void LLPostProcess::copyFrameBuffer() { if((*it)->isEnabled() && (*it)->getDepthChannel()>=0) { - gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_RECT_TEXTURE, mDepthTexture); - glCopyTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB,0,0,0,0,0,mScreenWidth, mScreenHeight); + gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mDepthTexture->getTexName()); + glCopyTexSubImage2D(GL_TEXTURE_2D,0,0,0,0,0,mScreenWidth, mScreenHeight); + stop_glerror(); break; } } @@ -485,7 +530,7 @@ void LLPostProcess::copyFrameBuffer() void LLPostProcess::bindNoise(U32 channel) { - gGL.getTexUnit(channel)->bind(mNoiseTexture); + gGL.getTexUnit(channel)->bindManual(LLTexUnit::TT_TEXTURE,mNoiseTexture->getTexName()); } void LLPostProcess::renderEffects(unsigned int width, unsigned int height) @@ -508,8 +553,7 @@ void LLPostProcess::doEffects(void) { LLVertexBuffer::unbind(); - mNoiseTextureScale = 0.001f + ((100.f - mSelectedEffectInfo["noise_size"].asFloat()) / 100.f); - mNoiseTextureScale *= (mScreenHeight / NOISE_SIZE); + mNoiseTextureScale = (1.f - (mSelectedEffectInfo["noise_size"].asFloat() - 1.f) *(9.f/990.f)) / (float)NOISE_SIZE; /// Copy the screen buffer to the render texture copyFrameBuffer(); @@ -517,7 +561,7 @@ void LLPostProcess::doEffects(void) //Disable depth. Set blendmode to replace. LLGLDepthTest depth(GL_FALSE,GL_FALSE); - LLGLEnable blend(GL_BLEND); + LLGLEnable blend; gGL.setSceneBlendType(LLRender::BT_REPLACE); /// Change to an orthogonal view @@ -555,20 +599,26 @@ void LLPostProcess::applyShaders(void) S32 color_channel = (*it)->getColorChannel(); S32 depth_channel = (*it)->getDepthChannel(); if(depth_channel >= 0) - gGL.getTexUnit(depth_channel)->bindManual(LLTexUnit::TT_RECT_TEXTURE, mDepthTexture); + gGL.getTexUnit(depth_channel)->bindManual(LLTexUnit::TT_TEXTURE, mDepthTexture->getTexName()); U32 pass = 1; (*it)->bindShader(); QuadType quad = (*it)->preDraw(); while((*it)->draw(pass++)) { - mRenderTarget[!primary_rendertarget].bindTarget(); + LLRenderTarget& write_target = mRenderTarget[!primary_rendertarget]; + LLRenderTarget& read_target = mRenderTarget[mRenderTarget[0].getFBO() ? primary_rendertarget : !primary_rendertarget]; + write_target.bindTarget(); if(color_channel >= 0) - mRenderTarget[mRenderTarget[0].getFBO() ? primary_rendertarget : !primary_rendertarget].bindTexture(0,color_channel); + read_target.bindTexture(0,color_channel); drawOrthoQuad(quad); - mRenderTarget[!primary_rendertarget].flush(); + + if(color_channel >= 0 && !mRenderTarget[0].getFBO()) + gGL.getTexUnit(color_channel)->unbind(read_target.getUsage()); + + write_target.flush(); if(mRenderTarget[0].getFBO()) primary_rendertarget = !primary_rendertarget; } @@ -593,8 +643,13 @@ void LLPostProcess::drawOrthoQuad(QuadType type) LLStrider uv2; mVBO->getTexCoord1Strider(uv2); - float offs[2] = {(float) rand() / (float) RAND_MAX, (float) rand() / (float) RAND_MAX}; - float scale[2] = {mScreenWidth * mNoiseTextureScale / mScreenHeight, mNoiseTextureScale}; + float offs[2] = { + /*ll_round*/((float) rand() / (float) RAND_MAX), + /*ll_round*/((float) rand() / (float) RAND_MAX) }; + float scale[2] = { + ((float)mScreenWidth * mNoiseTextureScale), + ((float)mScreenHeight * mNoiseTextureScale) }; + uv2[0] = LLVector2(offs[0],offs[1]); uv2[1] = LLVector2(offs[0],offs[1]+scale[1]); uv2[2] = LLVector2(offs[0]+scale[0],offs[1]); @@ -611,10 +666,11 @@ void LLPostProcess::setSelectedEffect(std::string const & effectName) { mSelectedEffectName = effectName; mSelectedEffectInfo = mAllEffectInfo[effectName]; - for(std::list >::iterator it=mShaders.begin();it!=mShaders.end();++it) + for(auto shader : mShaders) { - (*it)->loadSettings(mSelectedEffectInfo); + shader->loadSettings(mSelectedEffectInfo); } + mSelectedEffectChanged(mSelectedEffectName); } void LLPostProcess::setSelectedEffectValue(std::string const & setting, LLSD value) @@ -650,9 +706,10 @@ void LLPostProcess::resetSelectedEffect() void LLPostProcess::saveEffectAs(std::string const & effectName) { mAllEffectInfo[effectName] = mSelectedEffectInfo; + mSelectedEffectChanged(mSelectedEffectName); // Might've changed, either way update the lists - std::string pathName(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight", XML_FILENAME)); - //llinfos << "Saving PostProcess Effects settings to " << pathName << llendl; + std::string pathName(gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "windlight", XML_FILENAME)); + //LL_INFOS() << "Saving PostProcess Effects settings to " << pathName << LL_ENDL; llofstream effectsXML(pathName); diff --git a/indra/llrender/llpostprocess.h b/indra/llrender/llpostprocess.h index 6c3da675ea..b130cf2af1 100644 --- a/indra/llrender/llpostprocess.h +++ b/indra/llrender/llpostprocess.h @@ -34,6 +34,7 @@ #define LL_POSTPROCESS_H #include +#include #include "llsd.h" #include "llrendertarget.h" @@ -89,8 +90,8 @@ class LLPostProcess : public LLSingleton U32 mNextDrawTarget; //Need to pingpong between two rendertargets. Cannot sample target texture of currently bound FBO. // However this is ONLY the case if fbos are actually supported, else swapping isn't needed. LLRenderTarget mRenderTarget[2]; - U32 mDepthTexture; - LLPointer mNoiseTexture ; + LLImageGL::GLTextureName mDepthTexture; + LLImageGL::GLTextureName mNoiseTexture ; U32 mScreenWidth; U32 mScreenHeight; @@ -103,6 +104,9 @@ class LLPostProcess : public LLSingleton // The map of all availible effects LLSD mAllEffectInfo; + typedef boost::signals2::signal selected_effect_changed_signal; + selected_effect_changed_signal mSelectedEffectChanged; + public: LLPostProcess(void); ~LLPostProcess(void); @@ -144,6 +148,7 @@ class LLPostProcess : public LLSingleton // Setters void setSelectedEffect(std::string const & effectName); void setSelectedEffectValue(std::string const & setting, LLSD value); + auto setSelectedEffectChangeCallback(const selected_effect_changed_signal::slot_type& func) { return mSelectedEffectChanged.connect(func); } void resetSelectedEffect(); void saveEffectAs(std::string const & effectName); }; diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp index bbf70b9ded..a40a0f1acb 100644 --- a/indra/llrender/llrender.cpp +++ b/indra/llrender/llrender.cpp @@ -35,17 +35,18 @@ #include "llrendertarget.h" #include "lltexture.h" #include "llshadermgr.h" +#include "llmatrix4a.h" LLRender gGL; // Handy copies of last good GL matrices //Would be best to migrate these to LLMatrix4a and LLVector4a, but that's too divergent right now. -LL_ALIGN_16(F32 gGLModelView[16]); -LL_ALIGN_16(F32 gGLLastModelView[16]); -LL_ALIGN_16(F32 gGLPreviousModelView[16]); -LL_ALIGN_16(F32 gGLLastProjection[16]); -LL_ALIGN_16(F32 gGLProjection[16]); -LL_ALIGN_16(S32 gGLViewport[4]); +LLMatrix4a gGLModelView; +LLMatrix4a gGLLastModelView; +LLMatrix4a gGLPreviousModelView; +LLMatrix4a gGLLastProjection; +LLMatrix4a gGLProjection; +LLRect gGLViewport; U32 LLRender::sUICalls = 0; U32 LLRender::sUIVerts = 0; @@ -53,24 +54,21 @@ U32 LLTexUnit::sWhiteTexture = 0; bool LLRender::sGLCoreProfile = false; static const U32 LL_NUM_TEXTURE_LAYERS = 32; -static const U32 LL_NUM_LIGHT_UNITS = 8; -static GLenum sGLTextureType[] = +static const GLenum sGLTextureType[] = { GL_TEXTURE_2D, - GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_CUBE_MAP_ARB - //,GL_TEXTURE_2D_MULTISAMPLE Don't use. }; -static GLint sGLAddressMode[] = +static const GLint sGLAddressMode[] = { GL_REPEAT, GL_MIRRORED_REPEAT, GL_CLAMP_TO_EDGE }; -static GLenum sGLCompareFunc[] = +static const GLenum sGLCompareFunc[] = { GL_NEVER, GL_ALWAYS, @@ -84,7 +82,7 @@ static GLenum sGLCompareFunc[] = const U32 immediate_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_TEXCOORD0; -static GLenum sGLBlendFactor[] = +static const GLenum sGLBlendFactor[] = { GL_ONE, GL_ZERO, @@ -100,16 +98,30 @@ static GLenum sGLBlendFactor[] = GL_ZERO // 'BF_UNDEF' }; +static const GLenum sGLPolygonFaceType[] = +{ + GL_FRONT, + GL_BACK, + GL_FRONT_AND_BACK +}; + +static const GLenum sGLPolygonMode[] = +{ + GL_POINT, + GL_LINE, + GL_FILL +}; + LLTexUnit::LLTexUnit(S32 index) -: mCurrTexType(TT_NONE), mCurrBlendType(TB_MULT), -mCurrColorOp(TBO_MULT), mCurrAlphaOp(TBO_MULT), -mCurrColorSrc1(TBS_TEX_COLOR), mCurrColorSrc2(TBS_PREV_COLOR), -mCurrAlphaSrc1(TBS_TEX_ALPHA), mCurrAlphaSrc2(TBS_PREV_ALPHA), -mCurrColorScale(1), mCurrAlphaScale(1), mCurrTexture(0), -mHasMipMaps(false) + : mCurrTexType(TT_NONE), mCurrBlendType(TB_MULT), + mCurrColorOp(TBO_MULT), mCurrAlphaOp(TBO_MULT), + mCurrColorSrc1(TBS_TEX_COLOR), mCurrColorSrc2(TBS_PREV_COLOR), + mCurrAlphaSrc1(TBS_TEX_ALPHA), mCurrAlphaSrc2(TBS_PREV_ALPHA), + mCurrColorScale(1), mCurrAlphaScale(1), mCurrTexture(0), + mHasMipMaps(false), + mIndex(index) { llassert_always(index < (S32)LL_NUM_TEXTURE_LAYERS); - mIndex = index; } //static @@ -118,6 +130,8 @@ U32 LLTexUnit::getInternalType(eTextureType type) return sGLTextureType[type]; } +//void validate_bind_texture(U32 name); + void LLTexUnit::refreshState(void) { // We set dirty to true so that the tex unit knows to ignore caching @@ -141,6 +155,7 @@ void LLTexUnit::refreshState(void) glEnable(sGLTextureType[mCurrTexType]); } + //if (mCurrTexture) validate_bind_texture(mCurrTexture); glBindTexture(sGLTextureType[mCurrTexType], mCurrTexture); } else @@ -168,11 +183,12 @@ void LLTexUnit::activate(void) { if (mIndex < 0) return; - if ((S32)gGL.mCurrTextureUnitIndex != mIndex || gGL.mDirty) + if ((S32)gGL.getCurrentTexUnitIndex() != mIndex || gGL.mDirty) { - gGL.flush(); + //gGL.flush(); + // Apply immediately. glActiveTextureARB(GL_TEXTURE0_ARB + mIndex); - gGL.mCurrTextureUnitIndex = mIndex; + gGL.mContext.texUnit = gGL.mNewContext.texUnit = mIndex; } } @@ -193,7 +209,7 @@ void LLTexUnit::enable(eTextureType type) mCurrTexType = type; gGL.flush(); - if (!LLGLSLShader::sNoFixedFunction && + if (!LLGLSLShader::sNoFixedFunction && //type != LLTexUnit::TT_MULTISAMPLE_TEXTURE && mIndex < gGLManager.mNumTextureUnits) { @@ -227,64 +243,77 @@ void LLTexUnit::disable(void) bool LLTexUnit::bind(LLTexture* texture, bool for_rendering, bool forceBind) { stop_glerror(); - if (mIndex < 0) return false; - - LLImageGL* gl_tex = NULL ; - if (texture == NULL || !(gl_tex = texture->getGLTexture())) - { - llwarns << "NULL LLTexUnit::bind texture" << llendl; - return false; - } - - if (!gl_tex->getTexName()) //if texture does not exist + if (mIndex >= 0) { - //if deleted, will re-generate it immediately - texture->forceImmediateUpdate() ; + //gGL.flush(); - gl_tex->forceUpdateBindStats() ; - return texture->bindDefaultImage(mIndex); - } + LLImageGL* gl_tex = NULL ; - //in audit, replace the selected texture by the default one. - if(gAuditTexture && for_rendering && LLImageGL::sCurTexPickSize > 0) - { - if(texture->getWidth() * texture->getHeight() == LLImageGL::sCurTexPickSize) - { - gl_tex->updateBindStats(gl_tex->mTextureMemory); - return bind(LLImageGL::sHighlightTexturep.get()); - } - } - if ((mCurrTexture != gl_tex->getTexName()) || forceBind) - { - gGL.flush(); - activate(); - enable(gl_tex->getTarget()); - mCurrTexture = gl_tex->getTexName(); - glBindTexture(sGLTextureType[gl_tex->getTarget()], mCurrTexture); - if(gl_tex->updateBindStats(gl_tex->mTextureMemory)) + if (texture != NULL && (gl_tex = texture->getGLTexture())) { - texture->setActive() ; - texture->updateBindStatsForTester() ; + if (gl_tex->getTexName()) //if texture exists + { + //in audit, replace the selected texture by the default one. + if(gAuditTexture && for_rendering && LLImageGL::sCurTexPickSize > 0) + { + if(texture->getWidth() * texture->getHeight() == LLImageGL::sCurTexPickSize) + { + gl_tex->updateBindStats(gl_tex->mTextureMemory); + return bind(LLImageGL::sHighlightTexturep.get()); + } + } + if ((mCurrTexture != gl_tex->getTexName()) || forceBind) + { + gGL.flush(); + activate(); + enable(gl_tex->getTarget()); + mCurrTexture = gl_tex->getTexName(); + //validate_bind_texture(mCurrTexture); + glBindTexture(sGLTextureType[gl_tex->getTarget()], mCurrTexture); + if(gl_tex->updateBindStats(gl_tex->mTextureMemory)) + { + texture->setActive() ; + texture->updateBindStatsForTester() ; + } + mHasMipMaps = gl_tex->mHasMipMaps; + if (gl_tex->mTexOptionsDirty) + { + gl_tex->mTexOptionsDirty = false; + setTextureAddressMode(gl_tex->mAddressMode); + setTextureFilteringOption(gl_tex->mFilterOption); + } + } + } + else + { + //if deleted, will re-generate it immediately + texture->forceImmediateUpdate() ; + + gl_tex->forceUpdateBindStats() ; + return texture->bindDefaultImage(mIndex); + } } - mHasMipMaps = gl_tex->mHasMipMaps; - if (gl_tex->mTexOptionsDirty) + else { - gl_tex->mTexOptionsDirty = false; - setTextureAddressMode(gl_tex->mAddressMode); - setTextureFilteringOption(gl_tex->mFilterOption); + LL_WARNS() << "NULL LLTexUnit::bind texture" << LL_ENDL; + return false; } } + else + { // mIndex < 0 + return false; + } + return true; } bool LLTexUnit::bind(LLImageGL* texture, bool for_rendering, bool forceBind) { - stop_glerror(); if (mIndex < 0) return false; if(!texture) { - llwarns << "NULL LLTexUnit::bind texture" << llendl; + LL_WARNS() << "NULL LLTexUnit::bind texture" << LL_ENDL; return false; } @@ -294,35 +323,27 @@ bool LLTexUnit::bind(LLImageGL* texture, bool for_rendering, bool forceBind) { return bind(LLImageGL::sDefaultGLTexture) ; } - stop_glerror(); return false ; } if ((mCurrTexture != texture->getTexName()) || forceBind) { gGL.flush(); - stop_glerror(); activate(); - stop_glerror(); enable(texture->getTarget()); - stop_glerror(); mCurrTexture = texture->getTexName(); + //validate_bind_texture(mCurrTexture); glBindTexture(sGLTextureType[texture->getTarget()], mCurrTexture); - stop_glerror(); texture->updateBindStats(texture->mTextureMemory); mHasMipMaps = texture->mHasMipMaps; if (texture->mTexOptionsDirty) { - stop_glerror(); texture->mTexOptionsDirty = false; setTextureAddressMode(texture->mAddressMode); setTextureFilteringOption(texture->mFilterOption); - stop_glerror(); } } - stop_glerror(); - return true; } @@ -330,26 +351,26 @@ bool LLTexUnit::bind(LLCubeMap* cubeMap) { if (mIndex < 0) return false; - gGL.flush(); - if (cubeMap == NULL) { - llwarns << "NULL LLTexUnit::bind cubemap" << llendl; + LL_WARNS() << "NULL LLTexUnit::bind cubemap" << LL_ENDL; return false; } if (cubeMap->mImages[0].isNull()) { - llwarns << "NULL LLTexUnit::bind cubeMap->mImages[0]" << llendl; + LL_WARNS() << "NULL LLTexUnit::bind cubeMap->mImages[0]" << LL_ENDL; return false; } if (mCurrTexture != cubeMap->mImages[0]->getTexName()) { if (gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps) { + gGL.flush(); activate(); enable(LLTexUnit::TT_CUBE_MAP); mCurrTexture = cubeMap->mImages[0]->getTexName(); + //validate_bind_texture(mCurrTexture); glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, mCurrTexture); mHasMipMaps = cubeMap->mImages[0]->mHasMipMaps; cubeMap->mImages[0]->updateBindStats(cubeMap->mImages[0]->mTextureMemory); @@ -363,7 +384,7 @@ bool LLTexUnit::bind(LLCubeMap* cubeMap) } else { - llwarns << "Using cube map without extension!" << llendl; + LL_WARNS() << "Using cube map without extension!" << LL_ENDL; return false; } } @@ -376,13 +397,13 @@ bool LLTexUnit::bind(LLRenderTarget* renderTarget, bool bindDepth) { if (mIndex < 0) return false; - gGL.flush(); + //gGL.flush(); if (bindDepth) { if (renderTarget->hasStencil()) { - llerrs << "Cannot bind a render buffer for sampling. Allocate render target without a stencil buffer if sampling of depth buffer is required." << llendl; + LL_ERRS() << "Cannot bind a render buffer for sampling. Allocate render target without a stencil buffer if sampling of depth buffer is required." << LL_ENDL; } bindManual(renderTarget->getUsage(), renderTarget->getDepth()); @@ -410,6 +431,7 @@ bool LLTexUnit::bindManual(eTextureType type, U32 texture, bool hasMips) activate(); enable(type); mCurrTexture = texture; + //validate_bind_texture(texture); glBindTexture(sGLTextureType[type], texture); mHasMipMaps = hasMips; } @@ -418,28 +440,31 @@ bool LLTexUnit::bindManual(eTextureType type, U32 texture, bool hasMips) void LLTexUnit::unbind(eTextureType type) { - stop_glerror(); - if (mIndex < 0) return; //always flush and activate for consistency // some code paths assume unbind always flushes and sets the active texture - gGL.flush(); - activate(); + if (gGL.getCurrentTexUnitIndex() != mIndex || gGL.mDirty) + { + gGL.flush(); + activate(); + } // Disabled caching of binding state. - if (mCurrTexType == type) + if (mCurrTexType == type && mCurrTexture != 0) { + gGL.flush(); mCurrTexture = 0; - if (LLGLSLShader::sNoFixedFunction && type == LLTexUnit::TT_TEXTURE) + if (/*LLGLSLShader::sNoFixedFunction && */type == LLTexUnit::TT_TEXTURE) { + //if (sWhiteTexture) + // validate_bind_texture(sWhiteTexture); glBindTexture(sGLTextureType[type], sWhiteTexture); } else { glBindTexture(sGLTextureType[type], 0); } - stop_glerror(); } } @@ -509,7 +534,7 @@ void LLTexUnit::setTextureFilteringOption(LLTexUnit::eTextureFilterOptions optio { glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &gGL.mMaxAnisotropy); - llinfos << "gGL.mMaxAnisotropy: " << gGL.mMaxAnisotropy << llendl ; + LL_INFOS() << "gGL.mMaxAnisotropy: " << gGL.mMaxAnisotropy << LL_ENDL ; gGL.mMaxAnisotropy = llmax(1.f, gGL.mMaxAnisotropy) ; } glTexParameterf(sGLTextureType[mCurrTexType], GL_TEXTURE_MAX_ANISOTROPY_EXT, gGL.mMaxAnisotropy); @@ -528,7 +553,7 @@ void LLTexUnit::setTextureBlendType(eTextureBlendType type) return; } - if (mIndex < 0) return; + if (mIndex < 0 || mIndex >= gGLManager.mNumTextureUnits) return; // Do nothing if it's already correctly set. if (mCurrBlendType == type && !gGL.mDirty) @@ -563,7 +588,7 @@ void LLTexUnit::setTextureBlendType(eTextureBlendType type) glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); break; default: - llerrs << "Unknown Texture Blend Type: " << type << llendl; + LL_ERRS() << "Unknown Texture Blend Type: " << type << LL_ENDL; break; } setColorScale(scale_amount); @@ -603,7 +628,7 @@ GLint LLTexUnit::getTextureSource(eTextureBlendSrc src) return GL_CONSTANT_ARB; default: - llwarns << "Unknown eTextureBlendSrc: " << src << ". Using Vertex Color instead." << llendl; + LL_WARNS() << "Unknown eTextureBlendSrc: " << src << ". Using Vertex Color instead." << LL_ENDL; return GL_PRIMARY_COLOR_ARB; } } @@ -641,7 +666,7 @@ GLint LLTexUnit::getTextureSourceType(eTextureBlendSrc src, bool isAlpha) return GL_ONE_MINUS_SRC_ALPHA; default: - llwarns << "Unknown eTextureBlendSrc: " << src << ". Using Source Color or Alpha instead." << llendl; + LL_WARNS() << "Unknown eTextureBlendSrc: " << src << ". Using Source Color or Alpha instead." << LL_ENDL; return (isAlpha) ? GL_SRC_ALPHA: GL_SRC_COLOR; } } @@ -653,7 +678,7 @@ void LLTexUnit::setTextureCombiner(eTextureBlendOp op, eTextureBlendSrc src1, eT return; } - if (mIndex < 0) return; + if (mIndex < 0 || mIndex >= gGLManager.mNumTextureUnits) return; activate(); if (mCurrBlendType != TB_COMBINE || gGL.mDirty) @@ -782,7 +807,7 @@ void LLTexUnit::setTextureCombiner(eTextureBlendOp op, eTextureBlendSrc src1, eT break; default: - llwarns << "Unknown eTextureBlendOp: " << op << ". Setting op to replace." << llendl; + LL_WARNS() << "Unknown eTextureBlendOp: " << op << ". Setting op to replace." << LL_ENDL; // Slightly special syntax (no second sources), just set all and return. glTexEnvi(GL_TEXTURE_ENV, comb_enum, GL_REPLACE); glTexEnvi(GL_TEXTURE_ENV, src0_enum, source1); @@ -803,8 +828,8 @@ void LLTexUnit::setColorScale(S32 scale) { if (mCurrColorScale != scale || gGL.mDirty) { - mCurrColorScale = scale; gGL.flush(); + mCurrColorScale = scale; glTexEnvi( GL_TEXTURE_ENV, GL_RGB_SCALE, scale ); } } @@ -813,8 +838,8 @@ void LLTexUnit::setAlphaScale(S32 scale) { if (mCurrAlphaScale != scale || gGL.mDirty) { - mCurrAlphaScale = scale; gGL.flush(); + mCurrAlphaScale = scale; glTexEnvi( GL_TEXTURE_ENV, GL_ALPHA_SCALE, scale ); } } @@ -830,207 +855,95 @@ void LLTexUnit::debugTextureUnit(void) if ((GL_TEXTURE0_ARB + mIndex) != activeTexture) { U32 set_unit = (activeTexture - GL_TEXTURE0_ARB); - llwarns << "Incorrect Texture Unit! Expected: " << set_unit << " Actual: " << mIndex << llendl; + LL_WARNS() << "Incorrect Texture Unit! Expected: " << set_unit << " Actual: " << mIndex << LL_ENDL; } } -LLLightState::LLLightState(S32 index) -: mIndex(index), - mEnabled(false), - mConstantAtten(1.f), - mLinearAtten(0.f), - mQuadraticAtten(0.f), - mSpotExponent(0.f), - mSpotCutoff(180.f) +LLLightState::LLLightState(S32 index) : + mState(index), + mIndex(index) { - if (mIndex == 0) - { - mDiffuse.set(1,1,1,1); - mSpecular.set(1,1,1,1); - } - - mAmbient.set(0,0,0,1); - mPosition.set(0,0,1,0); - mSpotDirection.set(0,0,-1); + mPosMatrix.setIdentity(); + mSpotMatrix.setIdentity(); } -void LLLightState::enable() -{ - if (!mEnabled) - { - if (!LLGLSLShader::sNoFixedFunction) - { - glEnable(GL_LIGHT0+mIndex); - } - mEnabled = true; +#define UPDATE_LIGHTSTATE(state, value) \ + if (mState.state != value) { \ + mState.state = value; \ + ++gGL.mLightHash; \ } -} -void LLLightState::disable() -{ - if (mEnabled) - { - if (!LLGLSLShader::sNoFixedFunction) - { - glDisable(GL_LIGHT0+mIndex); - } - mEnabled = false; +#define UPDATE_LIGHTSTATE_AND_TRANSFORM(state, value, matrix, transformhash) \ + if (mState.state != value || memcmp(matrix.getF32ptr(), gGL.getModelviewMatrix().getF32ptr(), sizeof(LLMatrix4a))) { \ + mState.state = value; \ + ++gGL.mLightHash; \ + ++gGL.transformhash[mIndex]; \ + matrix = gGL.getModelviewMatrix(); \ } -} void LLLightState::setDiffuse(const LLColor4& diffuse) { - if (mDiffuse != diffuse) - { - ++gGL.mLightHash; - mDiffuse = diffuse; - if (!LLGLSLShader::sNoFixedFunction) - { - glLightfv(GL_LIGHT0+mIndex, GL_DIFFUSE, mDiffuse.mV); - } - } -} - -void LLLightState::setAmbient(const LLColor4& ambient) -{ - if (mAmbient != ambient) - { - ++gGL.mLightHash; - mAmbient = ambient; - if (!LLGLSLShader::sNoFixedFunction) - { - glLightfv(GL_LIGHT0+mIndex, GL_AMBIENT, mAmbient.mV); - } - } + UPDATE_LIGHTSTATE(mDiffuse, diffuse); } void LLLightState::setSpecular(const LLColor4& specular) { - if (mSpecular != specular) - { - ++gGL.mLightHash; - mSpecular = specular; - if (!LLGLSLShader::sNoFixedFunction) - { - glLightfv(GL_LIGHT0+mIndex, GL_SPECULAR, mSpecular.mV); - } - } + UPDATE_LIGHTSTATE(mSpecular, specular); } void LLLightState::setPosition(const LLVector4& position) { - //always set position because modelview matrix may have changed - ++gGL.mLightHash; - mPosition = position; - if (!LLGLSLShader::sNoFixedFunction) - { - glLightfv(GL_LIGHT0+mIndex, GL_POSITION, mPosition.mV); - } - else - { //transform position by current modelview matrix - glh::vec4f pos(position.mV); - - const glh::matrix4f& mat = gGL.getModelviewMatrix(); - mat.mult_matrix_vec(pos); - - mPosition.set(pos.v); - } - + UPDATE_LIGHTSTATE_AND_TRANSFORM(mPosition, position, mPosMatrix, mLightPositionTransformHash); } void LLLightState::setConstantAttenuation(const F32& atten) { - if (mConstantAtten != atten) - { - mConstantAtten = atten; - ++gGL.mLightHash; - if (!LLGLSLShader::sNoFixedFunction) - { - glLightf(GL_LIGHT0+mIndex, GL_CONSTANT_ATTENUATION, atten); - } - } + UPDATE_LIGHTSTATE(mConstantAtten, atten); } void LLLightState::setLinearAttenuation(const F32& atten) { - if (mLinearAtten != atten) - { - ++gGL.mLightHash; - mLinearAtten = atten; - if (!LLGLSLShader::sNoFixedFunction) - { - glLightf(GL_LIGHT0+mIndex, GL_LINEAR_ATTENUATION, atten); - } - } + UPDATE_LIGHTSTATE(mLinearAtten, atten); } void LLLightState::setQuadraticAttenuation(const F32& atten) { - if (mQuadraticAtten != atten) - { - ++gGL.mLightHash; - mQuadraticAtten = atten; - if (!LLGLSLShader::sNoFixedFunction) - { - glLightf(GL_LIGHT0+mIndex, GL_QUADRATIC_ATTENUATION, atten); - } - } + UPDATE_LIGHTSTATE(mQuadraticAtten, atten); } void LLLightState::setSpotExponent(const F32& exponent) { - if (mSpotExponent != exponent) - { - ++gGL.mLightHash; - mSpotExponent = exponent; - if (!LLGLSLShader::sNoFixedFunction) - { - glLightf(GL_LIGHT0+mIndex, GL_SPOT_EXPONENT, exponent); - } - } + UPDATE_LIGHTSTATE(mSpotExponent, exponent); } void LLLightState::setSpotCutoff(const F32& cutoff) { - if (mSpotCutoff != cutoff) - { - ++gGL.mLightHash; - mSpotCutoff = cutoff; - if (!LLGLSLShader::sNoFixedFunction) - { - glLightf(GL_LIGHT0+mIndex, GL_SPOT_CUTOFF, cutoff); - } - } + UPDATE_LIGHTSTATE(mSpotCutoff, cutoff); } void LLLightState::setSpotDirection(const LLVector3& direction) { - //always set direction because modelview matrix may have changed - ++gGL.mLightHash; - mSpotDirection = direction; - if (!LLGLSLShader::sNoFixedFunction) - { - glLightfv(GL_LIGHT0+mIndex, GL_SPOT_DIRECTION, direction.mV); - } - else - { //transform direction by current modelview matrix - glh::vec3f dir(direction.mV); - - const glh::matrix4f& mat = gGL.getModelviewMatrix(); - mat.mult_matrix_dir(dir); + UPDATE_LIGHTSTATE_AND_TRANSFORM(mSpotDirection, direction, mSpotMatrix, mLightSpotTransformHash); +} - mSpotDirection.set(dir.v); +void LLLightState::setEnabled(const bool enabled) +{ + if (mEnabled != enabled) + { + mEnabled = enabled; + ++gGL.mLightHash; } } -LLRender::eBlendFactor blendfunc_debug[4]={LLRender::BF_UNDEF}; + LLRender::LLRender() : mDirty(false), mCount(0), - mQuadCycle(0), mMode(LLRender::TRIANGLES), - mCurrTextureUnitIndex(0), - mMaxAnisotropy(0.f) + mMatrixMode(LLRender::MM_MODELVIEW), + mMatIdx{ 0 }, + mMaxAnisotropy(0.f), + mPrimitiveReset(false) { mTexUnits.reserve(LL_NUM_TEXTURE_LAYERS); for (U32 i = 0; i < LL_NUM_TEXTURE_LAYERS; i++) @@ -1039,33 +952,24 @@ LLRender::LLRender() } mDummyTexUnit = new LLTexUnit(-1); - for (U32 i = 0; i < LL_NUM_LIGHT_UNITS; ++i) + for (U32 i = 0; i < NUM_LIGHTS; ++i) { mLightState.push_back(new LLLightState(i)); } - - for (U32 i = 0; i < 4; i++) - { - mCurrColorMask[i] = true; - } - - mCurrAlphaFunc = CF_DEFAULT; - mCurrAlphaFuncVal = 0.01f; - mCurrBlendColorSFactor = BF_UNDEF; - mCurrBlendAlphaSFactor = BF_UNDEF; - mCurrBlendColorDFactor = BF_UNDEF; - mCurrBlendAlphaDFactor = BF_UNDEF; - - mMatrixMode = LLRender::MM_MODELVIEW; - for (U32 i = 0; i < NUM_MATRIX_MODES; ++i) + resetSyncHashes(); + + //Init base matrix for each mode + for(S32 i = 0; i < NUM_MATRIX_MODES; ++i) { - mMatIdx[i] = 0; - mMatHash[i] = 0; - mCurMatHash[i] = 0xFFFFFFFF; + mMatrix[i][0].setIdentity(); } - mLightHash = 0; + gGLModelView.setIdentity(); + gGLLastModelView.setIdentity(); + gGLPreviousModelView.setIdentity(); + gGLLastProjection.setIdentity(); + gGLProjection.setIdentity(); } LLRender::~LLRender() @@ -1075,14 +979,16 @@ LLRender::~LLRender() void LLRender::init() { - llassert_always(mBuffer.isNull()) ; - stop_glerror(); - mBuffer = new LLVertexBuffer(immediate_mask, 0); - mBuffer->allocateBuffer(4096, 0, TRUE); - mBuffer->getVertexStrider(mVerticesp); - mBuffer->getTexCoord0Strider(mTexcoordsp); - mBuffer->getColorStrider(mColorsp); + if (sGLCoreProfile && !LLVertexBuffer::sUseVAO) + { //bind a dummy vertex array object so we're core profile compliant +#ifdef GL_ARB_vertex_array_object + U32 ret; + glGenVertexArrays(1, &ret); + glBindVertexArray(ret); +#endif + } stop_glerror(); + restoreVertexBuffers(); } void LLRender::shutdown() @@ -1103,88 +1009,314 @@ void LLRender::shutdown() mBuffer = NULL ; } +void LLRender::destroyGL() +{ + // Reset gl state cache + mCurShader = 0; + mContext = Context(); + resetSyncHashes(); + LLTexUnit::sWhiteTexture = 0; // Also done in LLImageGL::destroyGL. + for (auto unit : mTexUnits) + { + if (unit->getCurrTexture() > 0) + { + unit->unbind(unit->getCurrType()); + } + } + + resetVertexBuffers(); +} + void LLRender::refreshState(void) { mDirty = true; - U32 active_unit = mCurrTextureUnitIndex; + U32 active_unit = getCurrentTexUnitIndex(); for (U32 i = 0; i < mTexUnits.size(); i++) { mTexUnits[i]->refreshState(); + stop_glerror(); } mTexUnits[active_unit]->activate(); + stop_glerror(); - setColorMask(mCurrColorMask[0], mCurrColorMask[1], mCurrColorMask[2], mCurrColorMask[3]); + /*setColorMask(mCurrColorMask[0], mCurrColorMask[1], mCurrColorMask[2], mCurrColorMask[3]); + stop_glerror(); setAlphaRejectSettings(mCurrAlphaFunc, mCurrAlphaFuncVal); + stop_glerror(); //Singu note: Also reset glBlendFunc blendFunc(mCurrBlendColorSFactor,mCurrBlendColorDFactor,mCurrBlendAlphaSFactor,mCurrBlendAlphaDFactor); + stop_glerror();*/ mDirty = false; } -void LLRender::syncLightState() +void LLRender::resetVertexBuffers() { - LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; + mBuffer = NULL; +} - if (!shader) - { +void LLRender::restoreVertexBuffers() +{ + if (!mBuffer.isNull()) return; - } + stop_glerror(); + mBuffer = new LLVertexBuffer(immediate_mask, 0); + stop_glerror(); + mBuffer->allocateBuffer(4096, 0, TRUE); + stop_glerror(); + mBuffer->getVertexStrider(mVerticesp); + stop_glerror(); + mBuffer->getTexCoord0Strider(mTexcoordsp); + stop_glerror(); + mBuffer->getColorStrider(mColorsp); + stop_glerror(); +} - if (shader->mLightHash != mLightHash) +void LLRender::syncShaders() +{ + if (mCurShader != mNextShader) { - shader->mLightHash = mLightHash; - - LLVector4 position[8]; - LLVector3 direction[8]; - LLVector3 attenuation[8]; - LLVector3 diffuse[8]; + glUseProgramObjectARB(mNextShader); + mCurShader = mNextShader; + } +} - for (U32 i = 0; i < 8; i++) +void LLRender::syncContextState() +{ + if (mContext.color != mNewContext.color) + { + mContext.color = mNewContext.color; + glColor4fv(mContext.color.mV); + } + if (mContext.colorMask != mNewContext.colorMask) + { + mContext.colorMask = mNewContext.colorMask; + glColorMask( + mContext.colorMask & (1 << 0), + mContext.colorMask & (1 << 1), + mContext.colorMask & (1 << 2), + mContext.colorMask & (1 << 3)); + } + if (mContext.alphaFunc != mNewContext.alphaFunc || + mContext.alphaVal != mNewContext.alphaVal) + { + mContext.alphaFunc = mNewContext.alphaFunc; + mContext.alphaVal = mNewContext.alphaVal; + if (mContext.alphaFunc == CF_DEFAULT) { - LLLightState* light = mLightState[i]; - - position[i] = light->mPosition; - direction[i] = light->mSpotDirection; - attenuation[i].set(light->mLinearAtten, light->mQuadraticAtten, light->mSpecular.mV[3]); - diffuse[i].set(light->mDiffuse.mV); + glAlphaFunc(GL_GREATER, 0.01f); + } + else + { + glAlphaFunc(sGLCompareFunc[mContext.alphaFunc], mContext.alphaVal); + } + } + if (LLGLState::isEnabled() && ( + mContext.blendColorSFactor != mNewContext.blendColorSFactor || + mContext.blendAlphaSFactor != mNewContext.blendAlphaSFactor || + mContext.blendColorDFactor != mNewContext.blendColorDFactor || + mContext.blendAlphaDFactor != mNewContext.blendAlphaDFactor)) + { + mContext.blendColorSFactor = mNewContext.blendColorSFactor; + mContext.blendAlphaSFactor = mNewContext.blendAlphaSFactor; + mContext.blendColorDFactor = mNewContext.blendColorDFactor; + mContext.blendAlphaDFactor = mNewContext.blendAlphaDFactor; + if (mContext.blendColorSFactor == mContext.blendAlphaSFactor && + mContext.blendColorDFactor == mContext.blendAlphaDFactor) + { + glBlendFunc(sGLBlendFactor[mContext.blendColorSFactor], sGLBlendFactor[mContext.blendColorDFactor]); + } + else + { + glBlendFuncSeparateEXT(sGLBlendFactor[mContext.blendColorSFactor], sGLBlendFactor[mContext.blendColorDFactor], + sGLBlendFactor[mContext.blendAlphaSFactor], sGLBlendFactor[mContext.blendAlphaDFactor]); + } + } + if (mContext.lineWidth != mNewContext.lineWidth) + { + mContext.lineWidth = mNewContext.lineWidth; + glLineWidth(mContext.lineWidth); + } + if (mContext.pointSize != mNewContext.pointSize) + { + mContext.pointSize = mNewContext.pointSize; + glPointSize(mContext.pointSize); + } + if (mContext.polygonMode[0] != mNewContext.polygonMode[0] || mContext.polygonMode[1] != mNewContext.polygonMode[1]) + { + if (mNewContext.polygonMode[0] == mNewContext.polygonMode[1]) + { + glPolygonMode(GL_FRONT_AND_BACK, sGLPolygonMode[mNewContext.polygonMode[0]]); + } + else + { + if (mContext.polygonMode[0] != mNewContext.polygonMode[0]) + { + glPolygonMode(GL_FRONT, sGLPolygonMode[mNewContext.polygonMode[0]]); + } + if (mContext.polygonMode[1] != mNewContext.polygonMode[1]) + { + glPolygonMode(GL_BACK, sGLPolygonMode[mNewContext.polygonMode[1]]); + } } - shader->uniform4fv(LLShaderMgr::LIGHT_POSITION, 8, position[0].mV); - shader->uniform3fv(LLShaderMgr::LIGHT_DIRECTION, 8, direction[0].mV); - shader->uniform3fv(LLShaderMgr::LIGHT_ATTENUATION, 8, attenuation[0].mV); - shader->uniform3fv(LLShaderMgr::LIGHT_DIFFUSE, 8, diffuse[0].mV); - shader->uniform4fv(LLShaderMgr::LIGHT_AMBIENT, 1, mAmbientLightColor.mV); - //HACK -- duplicate sunlight color for compatibility with drivers that can't deal with multiple shader objects referencing the same uniform - shader->uniform4fv(LLShaderMgr::SUNLIGHT_COLOR, 1, diffuse[0].mV); + mContext.polygonMode[0] = mNewContext.polygonMode[0]; + mContext.polygonMode[1] = mNewContext.polygonMode[1]; + } + if (mContext.polygonOffset[0] != mNewContext.polygonOffset[0] || mContext.polygonOffset[1] != mNewContext.polygonOffset[1]) + { + mContext.polygonOffset[0] = mNewContext.polygonOffset[0]; + mContext.polygonOffset[1] = mNewContext.polygonOffset[1]; + glPolygonOffset(mContext.polygonOffset[0], mContext.polygonOffset[1]); + } + if (mContext.viewPort != mNewContext.viewPort) + { + mContext.viewPort = mNewContext.viewPort; + glViewport(mContext.viewPort.mLeft, mContext.viewPort.mBottom, mContext.viewPort.getWidth(), mContext.viewPort.getHeight()); + } + if (LLGLState::isEnabled() && mContext.scissor != mNewContext.scissor) + { + mContext.scissor = mNewContext.scissor; + glScissor(mContext.scissor.mLeft, mContext.scissor.mBottom, mContext.scissor.getWidth(), mContext.scissor.getHeight()); } } -void LLRender::syncMatrices() +U32 sLightMask = 0xFFFFFFFF; +void LLRender::syncLightState() { - stop_glerror(); - - U32 name[] = + if (!LLGLSLShader::sNoFixedFunction) { - LLShaderMgr::MODELVIEW_MATRIX, - LLShaderMgr::PROJECTION_MATRIX, - LLShaderMgr::TEXTURE_MATRIX0, - LLShaderMgr::TEXTURE_MATRIX1, - LLShaderMgr::TEXTURE_MATRIX2, - LLShaderMgr::TEXTURE_MATRIX3, - }; + // Legacy + if (mCurLegacyLightHash != mLightHash) + { + mCurLegacyLightHash = mLightHash; + for (U32 i = 0; i < NUM_LIGHTS; i++) + { + const LLLightState* light = mLightState[i]; + const U32 idx = GL_LIGHT0 + i; + const LLLightStateData& state = light->mState; + + if (light->mEnabled && (1 << i) & sLightMask) { + glEnable(idx); + if (mLightSpotTransformHash[i] != mCurLightSpotTransformHash[i] || + mLightPositionTransformHash[i] != mCurLightPositionTransformHash[i]) + { - LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; + glPushAttrib(GL_TRANSFORM_BIT); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + if (mLightPositionTransformHash[i] != mCurLightPositionTransformHash[i]) + { + glLoadMatrixf(light->mPosMatrix.getF32ptr()); + glLightfv(idx, GL_POSITION, state.mPosition.mV); + } + if (mLightSpotTransformHash[i] != mCurLightSpotTransformHash[i]) + { + glLoadMatrixf(light->mSpotMatrix.getF32ptr()); + glLightfv(idx, GL_SPOT_DIRECTION, state.mSpotDirection.mV); + } + mCurLightPositionTransformHash[i] = mLightPositionTransformHash[i]; + mCurLightSpotTransformHash[i] = mLightSpotTransformHash[i]; + + glPopMatrix(); + glPopAttrib(); + } + glLightfv(idx, GL_DIFFUSE, state.mDiffuse.mV); + glLightfv(idx, GL_SPECULAR, state.mSpecular.mV); + glLightf(idx, GL_CONSTANT_ATTENUATION, state.mConstantAtten); + glLightf(idx, GL_LINEAR_ATTENUATION, state.mLinearAtten); + glLightf(idx, GL_QUADRATIC_ATTENUATION, state.mQuadraticAtten); + glLightf(idx, GL_SPOT_EXPONENT, state.mSpotExponent); + glLightf(idx, GL_SPOT_CUTOFF, state.mSpotCutoff); + } + else + { + glDisable(idx); + } + } + + glLightModelfv(GL_LIGHT_MODEL_AMBIENT, mAmbientLightColor.mV); + } + return; + } + + LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; + if (!shader || (!shader->mFeatures.hasLighting && !shader->mFeatures.calculatesLighting)) + { + return; + } + if (shader->mLightHash != mLightHash) + { + shader->mLightHash = mLightHash; + + LLVector3 attenuation[8]; + LLVector3 diffuse[8]; + + for (U32 i = 0; i < NUM_LIGHTS; i++) + { + const LLLightState* light = mLightState[i]; + const LLLightStateData& state = light->mState; + + attenuation[i].set(state.mLinearAtten, state.mQuadraticAtten, state.mSpecular.mV[3]); + diffuse[i].set((light->mEnabled && (1 << i) & sLightMask) ? state.mDiffuse.mV : LLVector3::zero.mV); + + if (mLightPositionTransformHash[i] != mCurLightPositionTransformHash[i]) + { + LLVector4a pos; + pos.loadua(state.mPosition.mV); + light->mPosMatrix.rotate4(pos, pos); + mCurLightPosition[i].set(pos.getF32ptr()); + mCurLightPositionTransformHash[i] = mLightPositionTransformHash[i]; + } + // If state.mSpecular.mV[3] == 0.f then this light is a spotlight, thus update the direction... + // Otherwise don't bother and leave the hash stale in case it turns into a spotlight later. + if (state.mSpecular.mV[3] == 0.f && mLightSpotTransformHash[i] != mCurLightSpotTransformHash[i]) + { + LLVector4a dir; + dir.load3(state.mSpotDirection.mV); + light->mSpotMatrix.rotate(dir, dir); + mCurSpotDirection[i].set(dir.getF32ptr()); + mCurLightSpotTransformHash[i] = mLightSpotTransformHash[i]; + } + } + + shader->uniform4fv(LLShaderMgr::LIGHT_POSITION, NUM_LIGHTS, mCurLightPosition[0].mV); + shader->uniform3fv(LLShaderMgr::LIGHT_DIRECTION, NUM_LIGHTS, mCurSpotDirection[0].mV); + shader->uniform3fv(LLShaderMgr::LIGHT_ATTENUATION, NUM_LIGHTS, attenuation[0].mV); + shader->uniform3fv(LLShaderMgr::LIGHT_DIFFUSE, NUM_LIGHTS, diffuse[0].mV); + shader->uniform4fv(LLShaderMgr::LIGHT_AMBIENT, 1, mAmbientLightColor.mV); + //HACK -- duplicate sunlight color for compatibility with drivers that can't deal with multiple shader objects referencing the same uniform + shader->uniform3fv(LLShaderMgr::SUNLIGHT_COLOR, 1, diffuse[0].mV); + } +} + +void LLRender::syncMatrices() +{ + stop_glerror(); + + syncShaders(); + + static const U32 name[] = + { + LLShaderMgr::MODELVIEW_MATRIX, + LLShaderMgr::PROJECTION_MATRIX, + LLShaderMgr::TEXTURE_MATRIX0, + LLShaderMgr::TEXTURE_MATRIX1, + LLShaderMgr::TEXTURE_MATRIX2, + LLShaderMgr::TEXTURE_MATRIX3, + }; - static glh::matrix4f cached_mvp; + LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; + static LLMatrix4a cached_mvp; static U32 cached_mvp_mdv_hash = 0xFFFFFFFF; static U32 cached_mvp_proj_hash = 0xFFFFFFFF; - static glh::matrix4f cached_normal; + static LLMatrix4a cached_normal; static U32 cached_normal_hash = 0xFFFFFFFF; if (shader) @@ -1196,9 +1328,9 @@ void LLRender::syncMatrices() U32 i = MM_MODELVIEW; if (mMatHash[i] != shader->mMatHash[i]) { //update modelview, normal, and MVP - glh::matrix4f& mat = mMatrix[i][mMatIdx[i]]; - - shader->uniformMatrix4fv(name[i], 1, GL_FALSE, mat.m); + const LLMatrix4a& mat = mMatrix[i][mMatIdx[i]]; + + shader->uniformMatrix4fv(name[i], 1, GL_FALSE, mat.getF32ptr()); shader->mMatHash[i] = mMatHash[i]; //update normal matrix @@ -1207,20 +1339,20 @@ void LLRender::syncMatrices() { if (cached_normal_hash != mMatHash[i]) { - cached_normal = mat.inverse().transpose(); + cached_normal = mat; + cached_normal.invert(); + cached_normal.transpose(); cached_normal_hash = mMatHash[i]; } + + const LLMatrix4a& norm = cached_normal; - glh::matrix4f& norm = cached_normal; - - F32 norm_mat[] = - { - norm.m[0], norm.m[1], norm.m[2], - norm.m[4], norm.m[5], norm.m[6], - norm.m[8], norm.m[9], norm.m[10] - }; + LLVector3 norms[3]; + norms[0].set(norm.getRow<0>().getF32ptr()); + norms[1].set(norm.getRow<1>().getF32ptr()); + norms[2].set(norm.getRow<2>().getF32ptr()); - shader->uniformMatrix3fv(LLShaderMgr::NORMAL_MATRIX, 1, GL_FALSE, norm_mat); + shader->uniformMatrix3fv(LLShaderMgr::NORMAL_MATRIX, 1, GL_FALSE, norms[0].mV); } //update MVP matrix @@ -1232,13 +1364,12 @@ void LLRender::syncMatrices() if (cached_mvp_mdv_hash != mMatHash[i] || cached_mvp_proj_hash != mMatHash[MM_PROJECTION]) { - cached_mvp = mat; - cached_mvp.mult_left(mMatrix[proj][mMatIdx[proj]]); + cached_mvp.setMul(mMatrix[proj][mMatIdx[proj]], mat); cached_mvp_mdv_hash = mMatHash[i]; cached_mvp_proj_hash = mMatHash[MM_PROJECTION]; } - shader->uniformMatrix4fv(LLShaderMgr::MODELVIEW_PROJECTION_MATRIX, 1, GL_FALSE, cached_mvp.m); + shader->uniformMatrix4fv(LLShaderMgr::MODELVIEW_PROJECTION_MATRIX, 1, GL_FALSE, cached_mvp.getF32ptr()); } } @@ -1246,9 +1377,9 @@ void LLRender::syncMatrices() i = MM_PROJECTION; if (mMatHash[i] != shader->mMatHash[i]) { //update projection matrix, normal, and MVP - glh::matrix4f& mat = mMatrix[i][mMatIdx[i]]; - - shader->uniformMatrix4fv(name[i], 1, GL_FALSE, mat.m); + const LLMatrix4a& mat = mMatrix[i][mMatIdx[i]]; + + shader->uniformMatrix4fv(name[i], 1, GL_FALSE, mat.getF32ptr()); shader->mMatHash[i] = mMatHash[i]; if (!mvp_done) @@ -1260,13 +1391,12 @@ void LLRender::syncMatrices() if (cached_mvp_mdv_hash != mMatHash[i] || cached_mvp_proj_hash != mMatHash[MM_PROJECTION]) { U32 mdv = MM_MODELVIEW; - cached_mvp = mat; - cached_mvp.mult_right(mMatrix[mdv][mMatIdx[mdv]]); + cached_mvp.setMul(mat,mMatrix[mdv][mMatIdx[mdv]]); cached_mvp_mdv_hash = mMatHash[MM_MODELVIEW]; cached_mvp_proj_hash = mMatHash[MM_PROJECTION]; } - - shader->uniformMatrix4fv(LLShaderMgr::MODELVIEW_PROJECTION_MATRIX, 1, GL_FALSE, cached_mvp.m); + + shader->uniformMatrix4fv(LLShaderMgr::MODELVIEW_PROJECTION_MATRIX, 1, GL_FALSE, cached_mvp.getF32ptr()); } } } @@ -1275,16 +1405,10 @@ void LLRender::syncMatrices() { if (mMatHash[i] != shader->mMatHash[i]) { - shader->uniformMatrix4fv(name[i], 1, GL_FALSE, mMatrix[i][mMatIdx[i]].m); + shader->uniformMatrix4fv(name[i], 1, GL_FALSE, mMatrix[i][mMatIdx[i]].getF32ptr()); shader->mMatHash[i] = mMatHash[i]; } } - - - if (shader->mFeatures.hasLighting || shader->mFeatures.calculatesLighting) - { //also sync light state - syncLightState(); - } } else if (!LLGLSLShader::sNoFixedFunction) { @@ -1300,55 +1424,171 @@ void LLRender::syncMatrices() for (U32 i = 0; i < 2; ++i) { - if (mMatHash[i] != mCurMatHash[i]) + if (mMatHash[i] != mCurLegacyMatHash[i]) { glMatrixMode(mode[i]); - glLoadMatrixf(mMatrix[i][mMatIdx[i]].m); - mCurMatHash[i] = mMatHash[i]; + glLoadMatrixf(mMatrix[i][mMatIdx[i]].getF32ptr()); + mCurLegacyMatHash[i] = mMatHash[i]; } } for (U32 i = 2; i < NUM_MATRIX_MODES; ++i) { - if (mMatHash[i] != mCurMatHash[i]) + if (mMatHash[i] != mCurLegacyMatHash[i]) { gGL.getTexUnit(i-2)->activate(); glMatrixMode(mode[i]); - glLoadMatrixf(mMatrix[i][mMatIdx[i]].m); - mCurMatHash[i] = mMatHash[i]; + glLoadMatrixf(mMatrix[i][mMatIdx[i]].getF32ptr()); + mCurLegacyMatHash[i] = mMatHash[i]; } } } + //also sync light state + syncLightState(); + //sync context. + syncContextState(); + stop_glerror(); } -void LLRender::translatef(const GLfloat& x, const GLfloat& y, const GLfloat& z) +LLMatrix4a LLRender::genRot(const GLfloat& a, const LLVector4a& axis) const { - flush(); + F32 r = a * DEG_TO_RAD; - { - glh::matrix4f trans_mat(1,0,0,x, - 0,1,0,y, - 0,0,1,z, - 0,0,0,1); + F32 c = cosf(r); + F32 s = sinf(r); + + F32 ic = 1.f-c; + + const LLVector4a add1(c,axis[VZ]*s,-axis[VY]*s); //1,z,-y + const LLVector4a add2(-axis[VZ]*s,c,axis[VX]*s); //-z,1,x + const LLVector4a add3(axis[VY]*s,-axis[VX]*s,c); //y,-x,1 + + LLVector4a axis_x; + axis_x.splat<0>(axis); + LLVector4a axis_y; + axis_y.splat<1>(axis); + LLVector4a axis_z; + axis_z.splat<2>(axis); + + LLVector4a c_axis; + c_axis.setMul(axis,ic); + + LLMatrix4a rot_mat; + rot_mat.getRow<0>().setMul(c_axis,axis_x); + rot_mat.getRow<0>().add(add1); + rot_mat.getRow<1>().setMul(c_axis,axis_y); + rot_mat.getRow<1>().add(add2); + rot_mat.getRow<2>().setMul(c_axis,axis_z); + rot_mat.getRow<2>().add(add3); + rot_mat.setRow<3>(LLVector4a(0,0,0,1)); + + return rot_mat; +} +LLMatrix4a LLRender::genOrtho(const GLfloat& left, const GLfloat& right, const GLfloat& bottom, const GLfloat& top, const GLfloat& zNear, const GLfloat& zFar) const +{ + LLMatrix4a ortho_mat; + ortho_mat.setRow<0>(LLVector4a(2.f/(right-left),0,0)); + ortho_mat.setRow<1>(LLVector4a(0,2.f/(top-bottom),0)); + ortho_mat.setRow<2>(LLVector4a(0,0,-2.f/(zFar-zNear))); + ortho_mat.setRow<3>(LLVector4a(-(right+left)/(right-left),-(top+bottom)/(top-bottom),-(zFar+zNear)/(zFar-zNear),1)); + + return ortho_mat; +} + +LLMatrix4a LLRender::genPersp(const GLfloat& fovy, const GLfloat& aspect, const GLfloat& zNear, const GLfloat& zFar) const +{ + GLfloat f = 1.f/tanf(DEG_TO_RAD*fovy/2.f); + + LLMatrix4a persp_mat; + persp_mat.setRow<0>(LLVector4a(f/aspect,0,0)); + persp_mat.setRow<1>(LLVector4a(0,f,0)); + persp_mat.setRow<2>(LLVector4a(0,0,(zFar+zNear)/(zNear-zFar),-1.f)); + persp_mat.setRow<3>(LLVector4a(0,0,(2.f*zFar*zNear)/(zNear-zFar),0)); + + return persp_mat; +} + +LLMatrix4a LLRender::genLook(const LLVector3& pos_in, const LLVector3& dir_in, const LLVector3& up_in) const +{ + const LLVector4a pos(pos_in.mV[VX],pos_in.mV[VY],pos_in.mV[VZ],1.f); + LLVector4a dir(dir_in.mV[VX],dir_in.mV[VY],dir_in.mV[VZ]); + const LLVector4a up(up_in.mV[VX],up_in.mV[VY],up_in.mV[VZ]); + + LLVector4a left_norm; + left_norm.setCross3(dir,up); + left_norm.normalize3fast(); + LLVector4a up_norm; + up_norm.setCross3(left_norm,dir); + up_norm.normalize3fast(); + LLVector4a& dir_norm = dir; + dir.normalize3fast(); - mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].mult_right(trans_mat); - mMatHash[mMatrixMode]++; + LLVector4a left_dot; + left_dot.setAllDot3(left_norm,pos); + left_dot.negate(); + LLVector4a up_dot; + up_dot.setAllDot3(up_norm,pos); + up_dot.negate(); + LLVector4a dir_dot; + dir_dot.setAllDot3(dir_norm,pos); + + dir_norm.negate(); + + LLMatrix4a lookat_mat; + lookat_mat.setRow<0>(left_norm); + lookat_mat.setRow<1>(up_norm); + lookat_mat.setRow<2>(dir_norm); + lookat_mat.setRow<3>(LLVector4a(0,0,0,1)); + + lookat_mat.getRow<0>().copyComponent<3>(left_dot); + lookat_mat.getRow<1>().copyComponent<3>(up_dot); + lookat_mat.getRow<2>().copyComponent<3>(dir_dot); + + lookat_mat.transpose(); + + return lookat_mat; +} + +const LLMatrix4a& LLRender::genNDCtoWC() const +{ + static LLMatrix4a mat( + LLVector4a(.5f,0,0,0), + LLVector4a(0,.5f,0,0), + LLVector4a(0,0,.5f,0), + LLVector4a(.5f,.5f,.5f,1.f)); + return mat; +} + +void LLRender::translatef(const GLfloat& x, const GLfloat& y, const GLfloat& z) +{ + if( llabs(x) < F_APPROXIMATELY_ZERO && + llabs(y) < F_APPROXIMATELY_ZERO && + llabs(z) < F_APPROXIMATELY_ZERO) + { + return; } + + flush(); + + mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].applyTranslation_affine(x,y,z); + mMatHash[mMatrixMode]++; + } void LLRender::scalef(const GLfloat& x, const GLfloat& y, const GLfloat& z) { + if( (llabs(x-1.f)) < F_APPROXIMATELY_ZERO && + (llabs(y-1.f)) < F_APPROXIMATELY_ZERO && + (llabs(z-1.f)) < F_APPROXIMATELY_ZERO) + { + return; + } flush(); { - glh::matrix4f scale_mat(x,0,0,0, - 0,y,0,0, - 0,0,z,0, - 0,0,0,1); - - mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].mult_right(scale_mat); + mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].applyScale_affine(x,y,z); mMatHash[mMatrixMode]++; } } @@ -1357,44 +1597,160 @@ void LLRender::ortho(F32 left, F32 right, F32 bottom, F32 top, F32 zNear, F32 zF { flush(); - { + LLMatrix4a ortho_mat; + ortho_mat.setRow<0>(LLVector4a(2.f/(right-left),0,0)); + ortho_mat.setRow<1>(LLVector4a(0,2.f/(top-bottom),0)); + ortho_mat.setRow<2>(LLVector4a(0,0,-2.f/(zFar-zNear))); + ortho_mat.setRow<3>(LLVector4a(-(right+left)/(right-left),-(top+bottom)/(top-bottom),-(zFar+zNear)/(zFar-zNear),1)); - glh::matrix4f ortho_mat(2.f/(right-left),0,0, -(right+left)/(right-left), - 0,2.f/(top-bottom),0, -(top+bottom)/(top-bottom), - 0,0,-2.f/(zFar-zNear), -(zFar+zNear)/(zFar-zNear), - 0,0,0,1); - - mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].mult_right(ortho_mat); - mMatHash[mMatrixMode]++; - } + mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].mul_affine(ortho_mat); + mMatHash[mMatrixMode]++; } -void LLRender::rotatef(const GLfloat& a, const GLfloat& x, const GLfloat& y, const GLfloat& z) +void LLRender::rotatef(const LLMatrix4a& rot) { flush(); + mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].mul_affine(rot); + mMatHash[mMatrixMode]++; +} + +void LLRender::rotatef(const GLfloat& a, const GLfloat& x, const GLfloat& y, const GLfloat& z) +{ + if( llabs(a) < F_APPROXIMATELY_ZERO || + llabs(a-360.f) < F_APPROXIMATELY_ZERO) { - F32 r = a * DEG_TO_RAD; + return; + } + + flush(); - F32 c = cosf(r); - F32 s = sinf(r); + rotatef(genRot(a,x,y,z)); +} + +//LLRender::projectf & LLRender::unprojectf adapted from gluProject & gluUnproject in Mesa's GLU 9.0 library. +// License/Copyright Statement: +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Except as contained in this notice, the name of Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ - F32 ic = 1.f-c; +bool LLRender::projectf(const LLVector3& object, const LLMatrix4a& modelview, const LLMatrix4a& projection, const LLRect& viewport, LLVector3& windowCoordinate) +{ + //Begin SSE intrinsics - glh::matrix4f rot_mat(x*x*ic+c, x*y*ic-z*s, x*z*ic+y*s, 0, - x*y*ic+z*s, y*y*ic+c, y*z*ic-x*s, 0, - x*z*ic-y*s, y*z*ic+x*s, z*z*ic+c, 0, - 0,0,0,1); + // Declare locals + const LLVector4a obj_vector(object.mV[VX],object.mV[VY],object.mV[VZ]); + const LLVector4a one(1.f); + LLVector4a temp_vec; //Scratch vector + LLVector4a w; //Splatted W-component. - mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].mult_right(rot_mat); - mMatHash[mMatrixMode]++; - } + modelview.affineTransform(obj_vector, temp_vec); //temp_vec = modelview * obj_vector; + + //Passing temp_matrix as v and res is safe. res not altered until after all other calculations + projection.rotate4(temp_vec, temp_vec); //temp_vec = projection * temp_vec + + w.splat<3>(temp_vec); //w = temp_vec.wwww + + //If w == 0.f, use 1.f instead. + LLVector4a div; + div.setSelectWithMask( w.equal( _mm_setzero_ps() ), one, w ); //float div = (w[N] == 0.f ? 1.f : w[N]); + temp_vec.div(div); //temp_vec /= div; + + //Map x, y to range 0-1 + temp_vec.mul(.5f); + temp_vec.add(.5f); + + LLVector4Logical mask = temp_vec.equal(_mm_setzero_ps()); + if(mask.areAllSet(LLVector4Logical::MASK_W)) + return false; + + //End SSE intrinsics + + //Window coordinates + windowCoordinate[0]=temp_vec[VX]*viewport.getWidth()+viewport.mLeft; + windowCoordinate[1]=temp_vec[VY]*viewport.getHeight()+viewport.mBottom; + //This is only correct when glDepthRange(0.0, 1.0) + windowCoordinate[2]=temp_vec[VZ]; + + return true; } -void LLRender::pushMatrix() +bool LLRender::unprojectf(const LLVector3& windowCoordinate, const LLMatrix4a& modelview, const LLMatrix4a& projection, const LLRect& viewport, LLVector3& object) { - flush(); + //Begin SSE intrinsics + + // Declare locals + static const LLVector4a one(1.f); + static const LLVector4a two(2.f); + LLVector4a norm_view( + ((windowCoordinate.mV[VX] - (F32)viewport.mLeft) / (F32)viewport.getWidth()), + ((windowCoordinate.mV[VY] - (F32)viewport.mBottom) / (F32)viewport.getHeight()), + windowCoordinate.mV[VZ], + 1.f); + LLMatrix4a inv_mat; //Inverse transformation matrix + LLVector4a temp_vec; //Scratch vector + LLVector4a w; //Splatted W-component. + + inv_mat.setMul(projection,modelview); //inv_mat = projection*modelview + + float det = inv_mat.invert(); + + //Normalize. -1.0 : +1.0 + norm_view.mul(two); // norm_view *= vec4(.2f) + norm_view.sub(one); // norm_view -= vec4(1.f) + + inv_mat.rotate4(norm_view,temp_vec); //inv_mat * norm_view + + w.splat<3>(temp_vec); //w = temp_vec.wwww + + //If w == 0.f, use 1.f instead. Defer return if temp_vec.w == 0.f until after all SSE intrinsics. + LLVector4a div; + div.setSelectWithMask( w.equal( _mm_setzero_ps() ), one, w ); //float div = (w[N] == 0.f ? 1.f : w[N]); + temp_vec.div(div); //temp_vec /= div; + + LLVector4Logical mask = temp_vec.equal(_mm_setzero_ps()); + if(mask.areAllSet(LLVector4Logical::MASK_W)) + return false; + + //End SSE intrinsics + + if(det == 0.f) + return false; + + object.set(temp_vec.getF32ptr()); + + return true; +} + +void LLRender::pushMatrix() +{ { if (mMatIdx[mMatrixMode] < LL_MATRIX_STACK_DEPTH-1) { @@ -1403,45 +1759,46 @@ void LLRender::pushMatrix() } else { - llwarns << "Matrix stack overflow." << llendl; + LL_WARNS() << "Matrix stack overflow." << LL_ENDL; } } } void LLRender::popMatrix() { - flush(); { if (mMatIdx[mMatrixMode] > 0) { + if ( memcmp(mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].getF32ptr(), mMatrix[mMatrixMode][mMatIdx[mMatrixMode] - 1].getF32ptr(), sizeof(LLMatrix4a)) ) + { + flush(); + } --mMatIdx[mMatrixMode]; mMatHash[mMatrixMode]++; } else { - llwarns << "Matrix stack underflow." << llendl; + flush(); + LL_WARNS() << "Matrix stack underflow." << LL_ENDL; } } } -void LLRender::loadMatrix(const GLfloat* m) +void LLRender::loadMatrix(const LLMatrix4a& mat) { flush(); - { - mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].set_value((GLfloat*) m); - mMatHash[mMatrixMode]++; - } + + mMatrix[mMatrixMode][mMatIdx[mMatrixMode]] = mat; + mMatHash[mMatrixMode]++; } -void LLRender::multMatrix(const GLfloat* m) +void LLRender::multMatrix(const LLMatrix4a& mat) { flush(); - { - glh::matrix4f mat((GLfloat*) m); + + mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].mul_affine(mat); + mMatHash[mMatrixMode]++; - mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].mult_right(mat); - mMatHash[mMatrixMode]++; - } } void LLRender::matrixMode(U32 mode) @@ -1470,20 +1827,16 @@ void LLRender::loadIdentity() { flush(); - { - llassert_always(mMatrixMode < NUM_MATRIX_MODES) ; - - mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].make_identity(); - mMatHash[mMatrixMode]++; - } + mMatrix[mMatrixMode][mMatIdx[mMatrixMode]].setIdentity(); + mMatHash[mMatrixMode]++; } -const glh::matrix4f& LLRender::getModelviewMatrix() +const LLMatrix4a& LLRender::getModelviewMatrix() { return mMatrix[MM_MODELVIEW][mMatIdx[MM_MODELVIEW]]; } -const glh::matrix4f& LLRender::getProjectionMatrix() +const LLMatrix4a& LLRender::getProjectionMatrix() { return mMatrix[MM_PROJECTION][mMatIdx[MM_PROJECTION]]; } @@ -1492,61 +1845,73 @@ void LLRender::translateUI(F32 x, F32 y, F32 z) { if (mUIOffset.empty()) { - llerrs << "Need to push a UI translation frame before offsetting" << llendl; + LL_ERRS() << "Need to push a UI translation frame before offsetting" << LL_ENDL; } LLVector4a add(x,y,z); - mUIOffset.back()->add(add); + mUIOffset.back().add(add); } void LLRender::scaleUI(F32 x, F32 y, F32 z) { if (mUIScale.empty()) { - llerrs << "Need to push a UI transformation frame before scaling." << llendl; + LL_ERRS() << "Need to push a UI transformation frame before scaling." << LL_ENDL; } LLVector4a scale(x,y,z); - mUIScale.back()->mul(scale); + mUIScale.back().mul(scale); +} + +void LLRender::rotateUI(LLQuaternion& rot) +{ + if (mUIRotation.empty()) + { + mUIRotation.push_back(rot); + } + else + { + mUIRotation.push_back(mUIRotation.back()*rot); + } } void LLRender::pushUIMatrix() { if (mUIOffset.empty()) { - mUIOffset.push_back(static_cast(ll_aligned_malloc_16(sizeof(LLVector4a)))); - mUIOffset.back()->splat(0.f); + mUIOffset.emplace_back(LLVector4a(0.f)); } else { - const LLVector4a* last_entry = mUIOffset.back(); - mUIOffset.push_back(static_cast(ll_aligned_malloc_16(sizeof(LLVector4a)))); - *mUIOffset.back() = *last_entry; + mUIOffset.push_back(mUIOffset.back()); } if (mUIScale.empty()) { - mUIScale.push_back(static_cast(ll_aligned_malloc_16(sizeof(LLVector4a)))); - mUIScale.back()->splat(1.f); + mUIScale.emplace_back(LLVector4a(1.f)); } else { - const LLVector4a* last_entry = mUIScale.back(); - mUIScale.push_back(static_cast(ll_aligned_malloc_16(sizeof(LLVector4a)))); - *mUIScale.back() = *last_entry; + mUIScale.push_back(mUIScale.back()); + } + if (!mUIRotation.empty()) + { + mUIRotation.push_back(mUIRotation.back()); } } void LLRender::popUIMatrix() { - if (mUIOffset.empty()) + if (mUIOffset.empty() || mUIScale.empty()) { - llerrs << "UI offset stack blown." << llendl; + LL_ERRS() << "UI offset or scale stack blown." << LL_ENDL; } - ll_aligned_free_16(mUIOffset.back()); mUIOffset.pop_back(); - ll_aligned_free_16(mUIScale.back()); mUIScale.pop_back(); + if (!mUIRotation.empty()) + { + mUIRotation.pop_back(); + } } LLVector3 LLRender::getUITranslation() @@ -1555,7 +1920,7 @@ LLVector3 LLRender::getUITranslation() { return LLVector3(0,0,0); } - return LLVector3(mUIOffset.back()->getF32ptr()); + return LLVector3(mUIOffset.back().getF32ptr()); } LLVector3 LLRender::getUIScale() @@ -1564,7 +1929,7 @@ LLVector3 LLRender::getUIScale() { return LLVector3(1,1,1); } - return LLVector3(mUIScale.back()->getF32ptr()); + return LLVector3(mUIScale.back().getF32ptr()); } @@ -1572,10 +1937,12 @@ void LLRender::loadUIIdentity() { if (mUIOffset.empty() || mUIScale.empty()) { - llerrs << "Need to push UI translation frame before clearing offset." << llendl; + LL_ERRS() << "Need to push UI translation frame before clearing offset." << LL_ENDL; } - mUIOffset.back()->splat(0.f); - mUIScale.back()->splat(1.f); + mUIOffset.back().splat(0.f); + mUIScale.back().splat(1.f); + if (!mUIRotation.empty()) + mUIRotation.push_back(LLQuaternion()); } void LLRender::setColorMask(bool writeColor, bool writeAlpha) @@ -1585,22 +1952,11 @@ void LLRender::setColorMask(bool writeColor, bool writeAlpha) void LLRender::setColorMask(bool writeColorR, bool writeColorG, bool writeColorB, bool writeAlpha) { - flush(); - - if (mCurrColorMask[0] != writeColorR || - mCurrColorMask[1] != writeColorG || - mCurrColorMask[2] != writeColorB || - mCurrColorMask[3] != writeAlpha || mDirty) + const U8 mask = (U8)writeColorR | ((U8)writeColorG << 1) | ((U8)writeColorB << 2) | ((U8)writeAlpha << 3); + if (mNewContext.colorMask != mask || mDirty) { - mCurrColorMask[0] = writeColorR; - mCurrColorMask[1] = writeColorG; - mCurrColorMask[2] = writeColorB; - mCurrColorMask[3] = writeAlpha; - - glColorMask(writeColorR ? GL_TRUE : GL_FALSE, - writeColorG ? GL_TRUE : GL_FALSE, - writeColorB ? GL_TRUE : GL_FALSE, - writeAlpha ? GL_TRUE : GL_FALSE); + flush(); + mNewContext.colorMask = mask; } } @@ -1630,36 +1986,27 @@ void LLRender::setSceneBlendType(eBlendType type) blendFunc(BF_ONE, BF_ZERO); break; default: - llerrs << "Unknown Scene Blend Type: " << type << llendl; + LL_ERRS() << "Unknown Scene Blend Type: " << type << LL_ENDL; break; } } void LLRender::setAlphaRejectSettings(eCompareFunc func, F32 value) { - flush(); - if (LLGLSLShader::sNoFixedFunction) { //glAlphaFunc is deprecated in OpenGL 3.3 return; } - if (mCurrAlphaFunc != func || - mCurrAlphaFuncVal != value || mDirty) + if (mNewContext.alphaFunc != func || + mNewContext.alphaVal != value || mDirty) { - mCurrAlphaFunc = func; - mCurrAlphaFuncVal = value; - if (func == CF_DEFAULT) - { - glAlphaFunc(GL_GREATER, 0.01f); - } - else - { - glAlphaFunc(sGLCompareFunc[func], value); - } + flush(); + mNewContext.alphaFunc = func; + mNewContext.alphaVal = value; } - if (gDebugGL) + /*if (gDebugGL) { //make sure cached state is correct GLint cur_func = 0; glGetIntegerv(GL_ALPHA_TEST_FUNC, &cur_func); @@ -1671,7 +2018,7 @@ void LLRender::setAlphaRejectSettings(eCompareFunc func, F32 value) if (cur_func != sGLCompareFunc[func]) { - llerrs << "Alpha test function corrupted!" << llendl; + LL_ERRS() << "Alpha test function corrupted!" << LL_ENDL; } F32 ref = 0.f; @@ -1679,34 +2026,55 @@ void LLRender::setAlphaRejectSettings(eCompareFunc func, F32 value) if (ref != value) { - llerrs << "Alpha test value corrupted!" << llendl; + LL_ERRS() << "Alpha test value corrupted!" << LL_ENDL; } + }*/ +} + +void LLRender::setViewport(const LLRect& rect) +{ + if (mNewContext.viewPort != rect || mDirty) + { + flush(); + mNewContext.viewPort = rect; + } +} + +void LLRender::setScissor(const LLRect& rect) +{ + if (mNewContext.scissor != rect || mDirty) + { + if (LLGLState::isEnabled()) + { + flush(); + } + mNewContext.scissor = rect; } } void check_blend_funcs() { - llassert_always(blendfunc_debug[0] == LLRender::BF_SOURCE_ALPHA ); - llassert_always(blendfunc_debug[1] == LLRender::BF_SOURCE_ALPHA ); - llassert_always(blendfunc_debug[2] == LLRender::BF_ONE_MINUS_SOURCE_ALPHA ); - llassert_always(blendfunc_debug[3] == LLRender::BF_ONE_MINUS_SOURCE_ALPHA ); + llassert_always(gGL.mNewContext.blendColorSFactor == LLRender::BF_SOURCE_ALPHA ); + llassert_always(gGL.mNewContext.blendAlphaSFactor == LLRender::BF_SOURCE_ALPHA ); + llassert_always(gGL.mNewContext.blendColorDFactor == LLRender::BF_ONE_MINUS_SOURCE_ALPHA); + llassert_always(gGL.mNewContext.blendAlphaDFactor == LLRender::BF_ONE_MINUS_SOURCE_ALPHA ); } void LLRender::blendFunc(eBlendFactor sfactor, eBlendFactor dfactor) { llassert(sfactor < BF_UNDEF); llassert(dfactor < BF_UNDEF); - if (mCurrBlendColorSFactor != sfactor || mCurrBlendColorDFactor != dfactor || - mCurrBlendAlphaSFactor != sfactor || mCurrBlendAlphaDFactor != dfactor || mDirty) - { - mCurrBlendColorSFactor = sfactor; - mCurrBlendAlphaSFactor = sfactor; - mCurrBlendColorDFactor = dfactor; - mCurrBlendAlphaDFactor = dfactor; - blendfunc_debug[0]=blendfunc_debug[1]=sfactor; - blendfunc_debug[2]=blendfunc_debug[3]=dfactor; - flush(); - glBlendFunc(sGLBlendFactor[sfactor], sGLBlendFactor[dfactor]); + if (mNewContext.blendColorSFactor != sfactor || mNewContext.blendColorDFactor != dfactor || + mNewContext.blendAlphaSFactor != sfactor || mNewContext.blendAlphaDFactor != dfactor || mDirty) + { + if (LLGLState::isEnabled()) + { + flush(); + } + mNewContext.blendColorSFactor = sfactor; + mNewContext.blendAlphaSFactor = sfactor; + mNewContext.blendColorDFactor = dfactor; + mNewContext.blendAlphaDFactor = dfactor; } } @@ -1719,24 +2087,21 @@ void LLRender::blendFunc(eBlendFactor color_sfactor, eBlendFactor color_dfactor, llassert(alpha_dfactor < BF_UNDEF); if (!gGLManager.mHasBlendFuncSeparate) { - LL_WARNS_ONCE("render") << "no glBlendFuncSeparateEXT(), using color-only blend func" << llendl; + LL_WARNS_ONCE("render") << "no glBlendFuncSeparateEXT(), using color-only blend func" << LL_ENDL; blendFunc(color_sfactor, color_dfactor); return; } - if (mCurrBlendColorSFactor != color_sfactor || mCurrBlendColorDFactor != color_dfactor || - mCurrBlendAlphaSFactor != alpha_sfactor || mCurrBlendAlphaDFactor != alpha_dfactor || mDirty) - { - mCurrBlendColorSFactor = color_sfactor; - mCurrBlendAlphaSFactor = alpha_sfactor; - mCurrBlendColorDFactor = color_dfactor; - mCurrBlendAlphaDFactor = alpha_dfactor; - blendfunc_debug[0]=color_sfactor; - blendfunc_debug[1]=alpha_sfactor; - blendfunc_debug[2]=color_dfactor; - blendfunc_debug[3]=alpha_dfactor; - flush(); - glBlendFuncSeparateEXT(sGLBlendFactor[color_sfactor], sGLBlendFactor[color_dfactor], - sGLBlendFactor[alpha_sfactor], sGLBlendFactor[alpha_dfactor]); + if (mNewContext.blendColorSFactor != color_sfactor || mNewContext.blendColorDFactor != color_dfactor || + mNewContext.blendAlphaSFactor != alpha_sfactor || mNewContext.blendAlphaDFactor != alpha_dfactor || mDirty) + { + if (LLGLState::isEnabled()) + { + flush(); + } + mNewContext.blendColorSFactor = color_sfactor; + mNewContext.blendAlphaSFactor = alpha_sfactor; + mNewContext.blendColorDFactor = color_dfactor; + mNewContext.blendAlphaDFactor = alpha_dfactor; } } @@ -1748,7 +2113,7 @@ LLTexUnit* LLRender::getTexUnit(U32 index) } else { - lldebugs << "Non-existing texture unit layer requested: " << index << llendl; + LL_DEBUGS() << "Non-existing texture unit layer requested: " << index << LL_ENDL; return mDummyTexUnit; } } @@ -1765,26 +2130,82 @@ LLLightState* LLRender::getLight(U32 index) void LLRender::setAmbientLightColor(const LLColor4& color) { - if (color != mAmbientLightColor) + if (color != mAmbientLightColor || mDirty) { ++mLightHash; mAmbientLightColor = color; - if (!LLGLSLShader::sNoFixedFunction) + } +} + +void LLRender::setLineWidth(F32 line_width) +{ + if (LLRender::sGLCoreProfile) + { + mNewContext.lineWidth = 1.f; + return; + } + if (mNewContext.lineWidth != line_width || mDirty) + { + if (mMode == LLRender::LINES || mMode == LLRender::LINE_STRIP) + { + flush(); + } + mNewContext.lineWidth = line_width; + } +} + +void LLRender::setPointSize(F32 point_size) +{ + if (mNewContext.pointSize != point_size || mDirty) + { + if (mMode == LLRender::POINTS) + { + flush(); + } + mNewContext.pointSize = point_size; + } +} + +void LLRender::setPolygonMode(ePolygonFaceType type, ePolygonMode mode) +{ + ePolygonMode newMode[] = { + (type == PF_FRONT_AND_BACK || type == PF_FRONT) ? mode : mNewContext.polygonMode[0], + (type == PF_FRONT_AND_BACK || type == PF_BACK) ? mode : mNewContext.polygonMode[1] + }; + + if (newMode[0] != mNewContext.polygonMode[0] || newMode[1] != mNewContext.polygonMode[1] || mDirty) + { + flush(); + mNewContext.polygonMode[0] = newMode[0]; + mNewContext.polygonMode[1] = newMode[1]; + } +} + +void LLRender::setPolygonOffset(F32 factor, F32 bias) +{ + if (factor != mNewContext.polygonOffset[0] || + bias != mNewContext.polygonOffset[1] || mDirty) + { + if (LLGLState::isEnabled() || + LLGLState::isEnabled() /*|| + Unused: LLGLState::isEnabled()*/ ) { - glLightModelfv(GL_LIGHT_MODEL_AMBIENT, color.mV); + flush(); } + mNewContext.polygonOffset[0] = factor; + mNewContext.polygonOffset[1] = bias; } } bool LLRender::verifyTexUnitActive(U32 unitToVerify) { - if (mCurrTextureUnitIndex == unitToVerify) + if (getCurrentTexUnitIndex() == unitToVerify) { return true; } else { - llwarns << "TexUnit currently active: " << mCurrTextureUnitIndex << " (expecting " << unitToVerify << ")" << llendl; + LL_WARNS() << "TexUnit currently active: " << getCurrentTexUnitIndex() << " (expecting " << unitToVerify << ")" << LL_ENDL; return false; } } @@ -1797,25 +2218,31 @@ void LLRender::clearErrors() } } +void LLRender::resetSyncHashes() { + memset(&mLightHash, 0, sizeof(mLightHash)); + memset(&mCurLegacyLightHash, 0xFF, sizeof(mCurLegacyLightHash)); + memset(mMatHash, 0, sizeof(mMatHash)); + memset(mCurLegacyMatHash, 0xFF, sizeof(mCurLegacyMatHash)); + memset(mLightPositionTransformHash, 0, sizeof(mLightPositionTransformHash)); + memset(mCurLightPositionTransformHash, 0xFF, sizeof(mCurLightPositionTransformHash)); + memset(mLightSpotTransformHash, 0, sizeof(mLightSpotTransformHash)); + memset(mCurLightSpotTransformHash, 0xFF, sizeof(mLightSpotTransformHash)); +} + void LLRender::begin(const GLuint& mode) { if (mode != mMode) { - if (mode == LLRender::QUADS) - { - mQuadCycle = 1; - } - - if (mMode == LLRender::QUADS || - mMode == LLRender::LINES || + if (mMode == LLRender::LINES || mMode == LLRender::TRIANGLES || - mMode == LLRender::POINTS) + mMode == LLRender::POINTS || + mMode == LLRender::TRIANGLE_STRIP ) { flush(); } else if (mCount != 0) { - llerrs << "gGL.begin() called redundantly." << llendl; + LL_ERRS() << "gGL.begin() called redundantly." << LL_ENDL; } mMode = mode; @@ -1827,18 +2254,23 @@ void LLRender::end() if (mCount == 0) { return; - //IMM_ERRS << "GL begin and end called with no vertices specified." << llendl; + //IMM_ERRS << "GL begin and end called with no vertices specified." << LL_ENDL; } - if ((mMode != LLRender::QUADS && - mMode != LLRender::LINES && + if ((mMode != LLRender::LINES && mMode != LLRender::TRIANGLES && - mMode != LLRender::POINTS) || + mMode != LLRender::POINTS && + mMode != LLRender::TRIANGLE_STRIP) || mCount > 2048) { flush(); } + else if (mMode == LLRender::TRIANGLE_STRIP) + { + mPrimitiveReset = true; + } } + void LLRender::flush() { if (mCount > 0) @@ -1846,22 +2278,22 @@ void LLRender::flush() #if 0 if (!glIsEnabled(GL_VERTEX_ARRAY)) { - llerrs << "foo 1" << llendl; + LL_ERRS() << "foo 1" << LL_ENDL; } if (!glIsEnabled(GL_COLOR_ARRAY)) { - llerrs << "foo 2" << llendl; + LL_ERRS() << "foo 2" << LL_ENDL; } if (!glIsEnabled(GL_TEXTURE_COORD_ARRAY)) { - llerrs << "foo 3" << llendl; + LL_ERRS() << "foo 3" << LL_ENDL; } if (glIsEnabled(GL_NORMAL_ARRAY)) { - llerrs << "foo 7" << llendl; + LL_ERRS() << "foo 7" << LL_ENDL; } GLvoid* pointer; @@ -1869,19 +2301,19 @@ void LLRender::flush() glGetPointerv(GL_VERTEX_ARRAY_POINTER, &pointer); if (pointer != &(mBuffer[0].v)) { - llerrs << "foo 4" << llendl; + LL_ERRS() << "foo 4" << LL_ENDL; } glGetPointerv(GL_COLOR_ARRAY_POINTER, &pointer); if (pointer != &(mBuffer[0].c)) { - llerrs << "foo 5" << llendl; + LL_ERRS() << "foo 5" << LL_ENDL; } glGetPointerv(GL_TEXTURE_COORD_ARRAY_POINTER, &pointer); if (pointer != &(mBuffer[0].uv)) { - llerrs << "foo 6" << llendl; + LL_ERRS() << "foo 6" << LL_ENDL; } #endif @@ -1893,19 +2325,11 @@ void LLRender::flush() if (gDebugGL) { - if (mMode == LLRender::QUADS && !sGLCoreProfile) - { - if (mCount%4 != 0) - { - llerrs << "Incomplete quad rendered." << llendl; - } - } - if (mMode == LLRender::TRIANGLES) { if (mCount%3 != 0) { - llerrs << "Incomplete triangle rendered." << llendl; + LL_ERRS() << "Incomplete triangle rendered." << LL_ENDL; } } @@ -1913,7 +2337,7 @@ void LLRender::flush() { if (mCount%2 != 0) { - llerrs << "Incomplete line rendered." << llendl; + LL_ERRS() << "Incomplete line rendered." << LL_ENDL; } } } @@ -1932,21 +2356,14 @@ void LLRender::flush() mBuffer->flush(); mBuffer->setBuffer(immediate_mask); - if (mMode == LLRender::QUADS && sGLCoreProfile) - { - mBuffer->drawArrays(LLRender::TRIANGLES, 0, count); - mQuadCycle = 1; - } - else - { - mBuffer->drawArrays(mMode, 0, count); - } + mBuffer->drawArrays(mMode, 0, count); mVerticesp[0] = mVerticesp[count]; mTexcoordsp[0] = mTexcoordsp[count]; mColorsp[0] = mColorsp[count]; mCount = 0; + mPrimitiveReset = false; } } @@ -1959,226 +2376,206 @@ void LLRender::vertex4a(const LLVector4a& vertex) { case LLRender::POINTS: flush(); break; case LLRender::TRIANGLES: if (mCount%3==0) flush(); break; - case LLRender::QUADS: if(mCount%4 == 0) flush(); break; case LLRender::LINES: if (mCount%2 == 0) flush(); break; + case LLRender::TRIANGLE_STRIP: + { + LLVector4a vert[] = { mVerticesp[mCount - 2], mVerticesp[mCount - 1], mVerticesp[mCount] }; + LLColor4U col[] = { mColorsp[mCount - 2], mColorsp[mCount - 1], mColorsp[mCount] }; + LLVector2 tc[] = { mTexcoordsp[mCount - 2], mTexcoordsp[mCount - 1], mTexcoordsp[mCount] }; + flush(); + for (int i = 0; i < LL_ARRAY_SIZE(vert); ++i) + { + mVerticesp[i] = vert[i]; + mColorsp[i] = col[i]; + mTexcoordsp[i] = tc[i]; + } + mCount = 2; + break; + } } } if (mCount > 4094) { - // llwarns << "GL immediate mode overflow. Some geometry not drawn." << llendl; + // LL_WARNS() << "GL immediate mode overflow. Some geometry not drawn." << LL_ENDL; return; } - if (mUIOffset.empty()) + if (mPrimitiveReset && mCount) { - mVerticesp[mCount]=vertex; + // Insert degenerate + ++mCount; + mVerticesp[mCount] = mVerticesp[mCount - 1]; + mColorsp[mCount] = mColorsp[mCount - 1]; + mTexcoordsp[mCount] = mTexcoordsp[mCount - 1]; + mVerticesp[mCount - 1] = mVerticesp[mCount - 2]; + mColorsp[mCount - 1] = mColorsp[mCount - 2]; + mTexcoordsp[mCount - 1] = mTexcoordsp[mCount - 2]; } - else + + if (mUIOffset.empty()) { - //LLVector3 vert = (LLVector3(x,y,z)+mUIOffset.back()).scaledVec(mUIScale.back()); - mVerticesp[mCount].setAdd(vertex,*mUIOffset.back()); - mVerticesp[mCount].mul(*mUIScale.back()); + if (!mUIRotation.empty() && mUIRotation.back().isNotIdentity()) + { + LLVector4 vert(vertex.getF32ptr()); + mVerticesp[mCount].loadua((vert*mUIRotation.back()).mV); + } + else + { + mVerticesp[mCount] = vertex; + } } - - if (mMode == LLRender::QUADS && LLRender::sGLCoreProfile) + else { - mQuadCycle++; - if (mQuadCycle == 4) - { //copy two vertices so fourth quad element will add a triangle - mQuadCycle = 0; - - mCount++; - mVerticesp[mCount] = mVerticesp[mCount-3]; - mColorsp[mCount] = mColorsp[mCount-3]; - mTexcoordsp[mCount] = mTexcoordsp[mCount-3]; - - mCount++; - mVerticesp[mCount] = mVerticesp[mCount-2]; - mColorsp[mCount] = mColorsp[mCount-2]; - mTexcoordsp[mCount] = mTexcoordsp[mCount-2]; + if (!mUIRotation.empty() && mUIRotation.back().isNotIdentity()) + { + LLVector4 vert(vertex.getF32ptr()); + vert = vert * mUIRotation.back(); + LLVector4a postrot_vert; + postrot_vert.loadua(vert.mV); + mVerticesp[mCount].setAdd(postrot_vert, mUIOffset.back()); + mVerticesp[mCount].mul(mUIScale.back()); + } + else + { + //LLVector3 vert = (LLVector3(x,y,z)+mUIOffset.back()).scaledVec(mUIScale.back()); + mVerticesp[mCount].setAdd(vertex, mUIOffset.back()); + mVerticesp[mCount].mul(mUIScale.back()); } } mCount++; mVerticesp[mCount] = mVerticesp[mCount-1]; mColorsp[mCount] = mColorsp[mCount-1]; - mTexcoordsp[mCount] = mTexcoordsp[mCount-1]; + mTexcoordsp[mCount] = mTexcoordsp[mCount-1]; + + if (mPrimitiveReset && mCount) + { + mCount++; + mVerticesp[mCount] = mVerticesp[mCount - 1]; + mColorsp[mCount] = mColorsp[mCount - 1]; + mTexcoordsp[mCount] = mTexcoordsp[mCount - 1]; + } + + mPrimitiveReset = false; } void LLRender::vertexBatchPreTransformed(LLVector4a* verts, S32 vert_count) { if (mCount + vert_count > 4094) { - // llwarns << "GL immediate mode overflow. Some geometry not drawn." << llendl; + // LL_WARNS() << "GL immediate mode overflow. Some geometry not drawn." << LL_ENDL; return; } - if (sGLCoreProfile && mMode == LLRender::QUADS) - { //quads are deprecated, convert to triangle list - S32 i = 0; - - while (i < vert_count) - { - //read first three - mVerticesp[mCount++] = verts[i++]; - mTexcoordsp[mCount] = mTexcoordsp[mCount-1]; - mColorsp[mCount] = mColorsp[mCount-1]; - - mVerticesp[mCount++] = verts[i++]; - mTexcoordsp[mCount] = mTexcoordsp[mCount-1]; - mColorsp[mCount] = mColorsp[mCount-1]; - - mVerticesp[mCount++] = verts[i++]; - mTexcoordsp[mCount] = mTexcoordsp[mCount-1]; - mColorsp[mCount] = mColorsp[mCount-1]; - - //copy two - mVerticesp[mCount++] = verts[i-3]; - mTexcoordsp[mCount] = mTexcoordsp[mCount-1]; - mColorsp[mCount] = mColorsp[mCount-1]; - - mVerticesp[mCount++] = verts[i-1]; - mTexcoordsp[mCount] = mTexcoordsp[mCount-1]; - mColorsp[mCount] = mColorsp[mCount-1]; - - //copy last one - mVerticesp[mCount++] = verts[i++]; - mTexcoordsp[mCount] = mTexcoordsp[mCount-1]; - mColorsp[mCount] = mColorsp[mCount-1]; - } - } - else + if (mPrimitiveReset && mCount) { - for (S32 i = 0; i < vert_count; i++) - { - mVerticesp[mCount] = verts[i]; + // Insert degenerate + ++mCount; + mVerticesp[mCount] = verts[0]; + mColorsp[mCount] = mColorsp[mCount - 1]; + mTexcoordsp[mCount] = mTexcoordsp[mCount - 1]; + mVerticesp[mCount - 1] = mVerticesp[mCount - 2]; + mColorsp[mCount - 1] = mColorsp[mCount - 2]; + mTexcoordsp[mCount - 1] = mTexcoordsp[mCount - 2]; + ++mCount; + mColorsp[mCount] = mColorsp[mCount - 1]; + mTexcoordsp[mCount] = mTexcoordsp[mCount - 1]; + } - mCount++; - mTexcoordsp[mCount] = mTexcoordsp[mCount-1]; - mColorsp[mCount] = mColorsp[mCount-1]; - } + mVerticesp.copyArray(mCount, verts, vert_count); + + for (S32 i = 0; i < vert_count; i++) + { + mCount++; + mTexcoordsp[mCount] = mTexcoordsp[mCount-1]; + mColorsp[mCount] = mColorsp[mCount-1]; } - mVerticesp[mCount] = mVerticesp[mCount-1]; + if (mCount > 0) // ND: Guard against crashes if mCount is zero, yes it can happen + mVerticesp[mCount] = mVerticesp[mCount-1]; + + mPrimitiveReset = false; } void LLRender::vertexBatchPreTransformed(LLVector4a* verts, LLVector2* uvs, S32 vert_count) { if (mCount + vert_count > 4094) { - // llwarns << "GL immediate mode overflow. Some geometry not drawn." << llendl; + // LL_WARNS() << "GL immediate mode overflow. Some geometry not drawn." << LL_ENDL; return; } - if (sGLCoreProfile && mMode == LLRender::QUADS) - { //quads are deprecated, convert to triangle list - S32 i = 0; - - while (i < vert_count) - { - //read first three - mVerticesp[mCount] = verts[i]; - mTexcoordsp[mCount++] = uvs[i++]; - mColorsp[mCount] = mColorsp[mCount-1]; - - mVerticesp[mCount] = verts[i]; - mTexcoordsp[mCount++] = uvs[i++]; - mColorsp[mCount] = mColorsp[mCount-1]; - - mVerticesp[mCount] = verts[i]; - mTexcoordsp[mCount++] = uvs[i++]; - mColorsp[mCount] = mColorsp[mCount-1]; - - //copy last two - mVerticesp[mCount] = verts[i-3]; - mTexcoordsp[mCount++] = uvs[i-3]; - mColorsp[mCount] = mColorsp[mCount-1]; + if (mPrimitiveReset && mCount) + { + // Insert degenerate + ++mCount; + mVerticesp[mCount] = verts[0]; + mColorsp[mCount] = mColorsp[mCount - 1]; + mTexcoordsp[mCount] = uvs[0]; + mVerticesp[mCount - 1] = mVerticesp[mCount - 2]; + mColorsp[mCount - 1] = mColorsp[mCount - 2]; + mTexcoordsp[mCount - 1] = mTexcoordsp[mCount - 2]; + ++mCount; + mColorsp[mCount] = mColorsp[mCount - 1]; + mTexcoordsp[mCount] = mTexcoordsp[mCount - 1]; + } - mVerticesp[mCount] = verts[i-1]; - mTexcoordsp[mCount++] = uvs[i-1]; - mColorsp[mCount] = mColorsp[mCount-1]; + mVerticesp.copyArray(mCount, verts, vert_count); + mTexcoordsp.copyArray(mCount, uvs, vert_count); - //copy last one - mVerticesp[mCount] = verts[i]; - mTexcoordsp[mCount++] = uvs[i++]; - mColorsp[mCount] = mColorsp[mCount-1]; - } - } - else + for (S32 i = 0; i < vert_count; i++) { - for (S32 i = 0; i < vert_count; i++) - { - mVerticesp[mCount] = verts[i]; - mTexcoordsp[mCount] = uvs[i]; + mCount++; + mColorsp[mCount] = mColorsp[mCount-1]; + } - mCount++; - mColorsp[mCount] = mColorsp[mCount-1]; - } + if (mCount > 0) + { + mVerticesp[mCount] = mVerticesp[mCount - 1]; + mTexcoordsp[mCount] = mTexcoordsp[mCount - 1]; } - mVerticesp[mCount] = mVerticesp[mCount-1]; - mTexcoordsp[mCount] = mTexcoordsp[mCount-1]; + mPrimitiveReset = false; } void LLRender::vertexBatchPreTransformed(LLVector4a* verts, LLVector2* uvs, LLColor4U* colors, S32 vert_count) { if (mCount + vert_count > 4094) { - // llwarns << "GL immediate mode overflow. Some geometry not drawn." << llendl; + // LL_WARNS() << "GL immediate mode overflow. Some geometry not drawn." << LL_ENDL; return; } - - if (sGLCoreProfile && mMode == LLRender::QUADS) - { //quads are deprecated, convert to triangle list - S32 i = 0; - - while (i < vert_count) - { - //read first three - mVerticesp[mCount] = verts[i]; - mTexcoordsp[mCount] = uvs[i]; - mColorsp[mCount++] = colors[i++]; - - mVerticesp[mCount] = verts[i]; - mTexcoordsp[mCount] = uvs[i]; - mColorsp[mCount++] = colors[i++]; - - mVerticesp[mCount] = verts[i]; - mTexcoordsp[mCount] = uvs[i]; - mColorsp[mCount++] = colors[i++]; - - //copy last two - mVerticesp[mCount] = verts[i-3]; - mTexcoordsp[mCount] = uvs[i-3]; - mColorsp[mCount++] = colors[i-3]; + if (mPrimitiveReset && mCount) + { + // Insert degenerate + ++mCount; + mVerticesp[mCount] = verts[0]; + mColorsp[mCount] = colors[mCount - 1]; + mTexcoordsp[mCount] = uvs[0]; + mVerticesp[mCount - 1] = mVerticesp[mCount - 2]; + mColorsp[mCount - 1] = mColorsp[mCount - 2]; + mTexcoordsp[mCount - 1] = mTexcoordsp[mCount - 2]; + ++mCount; + mColorsp[mCount] = mColorsp[mCount - 1]; + mTexcoordsp[mCount] = mTexcoordsp[mCount - 1]; + } - mVerticesp[mCount] = verts[i-1]; - mTexcoordsp[mCount] = uvs[i-1]; - mColorsp[mCount++] = colors[i-1]; + // Singu Note: Batch copies instead of iterating. + mVerticesp.copyArray(mCount, verts, vert_count); + mTexcoordsp.copyArray(mCount, uvs, vert_count); + mColorsp.copyArray(mCount, colors, vert_count); + mCount += vert_count; - //copy last one - mVerticesp[mCount] = verts[i]; - mTexcoordsp[mCount] = uvs[i]; - mColorsp[mCount++] = colors[i++]; - } - } - else + if (mCount > 0) { - for (S32 i = 0; i < vert_count; i++) - { - mVerticesp[mCount] = verts[i]; - mTexcoordsp[mCount] = uvs[i]; - mColorsp[mCount] = colors[i]; - - mCount++; - } + mVerticesp[mCount] = mVerticesp[mCount - 1]; + mTexcoordsp[mCount] = mTexcoordsp[mCount - 1]; + mColorsp[mCount] = mColorsp[mCount - 1]; } - mVerticesp[mCount] = mVerticesp[mCount-1]; - mTexcoordsp[mCount] = mTexcoordsp[mCount-1]; - mColorsp[mCount] = mColorsp[mCount-1]; + mPrimitiveReset = false; } void LLRender::texCoord2f(const GLfloat& x, const GLfloat& y) @@ -2198,7 +2595,15 @@ void LLRender::texCoord2fv(const GLfloat* tc) void LLRender::color4ub(const GLubyte& r, const GLubyte& g, const GLubyte& b, const GLubyte& a) { - mColorsp[mCount] = LLColor4U(r,g,b,a); + if (!LLGLSLShader::sCurBoundShaderPtr || + LLGLSLShader::sCurBoundShaderPtr->mAttributeMask & LLVertexBuffer::MAP_COLOR) + { + mColorsp[mCount] = LLColor4U(r,g,b,a); + } + else + { //not using shaders or shader reads color from a uniform + diffuseColor4ub(r,g,b,a); + } } void LLRender::color4ubv(const GLubyte* c) { @@ -2237,9 +2642,10 @@ void LLRender::diffuseColor3f(F32 r, F32 g, F32 b) { shader->uniform4f(LLShaderMgr::DIFFUSE_COLOR, r,g,b,1.f); } - else + else if (r != mNewContext.color.mV[0] || g != mNewContext.color.mV[1] || b != mNewContext.color.mV[2] || mNewContext.color.mV[3] != 1.f || mDirty) { - glColor3f(r,g,b); + flush(); + mNewContext.color.set(r, g, b, 1.f); } } @@ -2252,9 +2658,10 @@ void LLRender::diffuseColor3fv(const F32* c) { shader->uniform4f(LLShaderMgr::DIFFUSE_COLOR, c[0], c[1], c[2], 1.f); } - else + else if (c[0] != mNewContext.color.mV[0] || c[1] != mNewContext.color.mV[1] || c[2] != mNewContext.color.mV[2] || mNewContext.color.mV[3] != 1.f || mDirty) { - glColor3fv(c); + flush(); + mNewContext.color.set(c[0], c[1], c[2], 1.f); } } @@ -2267,9 +2674,10 @@ void LLRender::diffuseColor4f(F32 r, F32 g, F32 b, F32 a) { shader->uniform4f(LLShaderMgr::DIFFUSE_COLOR, r,g,b,a); } - else + else if (r != mNewContext.color.mV[0] || g != mNewContext.color.mV[1] || b != mNewContext.color.mV[2] || a != mNewContext.color.mV[3] || mDirty) { - glColor4f(r,g,b,a); + flush(); + mNewContext.color = { r, g, b, a }; } } @@ -2282,9 +2690,10 @@ void LLRender::diffuseColor4fv(const F32* c) { shader->uniform4fv(LLShaderMgr::DIFFUSE_COLOR, 1, c); } - else + else if (c[0] != mNewContext.color.mV[0] || c[1] != mNewContext.color.mV[1] || c[2] != mNewContext.color.mV[2] || c[3] != mNewContext.color.mV[3] || mDirty) { - glColor4fv(c); + flush(); + mNewContext.color.set(c); } } @@ -2297,21 +2706,44 @@ void LLRender::diffuseColor4ubv(const U8* c) { shader->uniform4f(LLShaderMgr::DIFFUSE_COLOR, c[0]/255.f, c[1]/255.f, c[2]/255.f, c[3]/255.f); } - else + else if (c[0] / 255.f != mNewContext.color.mV[0] || c[1] / 255.f != mNewContext.color.mV[1] || c[2] / 255.f != mNewContext.color.mV[2] || c[3] / 255.f != mNewContext.color.mV[3] || mDirty) { - glColor4ubv(c); + flush(); + mNewContext.color.mV[0] = c[0] / 255.f; + mNewContext.color.mV[1] = c[1] / 255.f; + mNewContext.color.mV[2] = c[2] / 255.f; + mNewContext.color.mV[3] = c[3] / 255.f; + } +} + +void LLRender::diffuseColor4ub(U8 r, U8 g, U8 b, U8 a) +{ + LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; + llassert(!LLGLSLShader::sNoFixedFunction || shader != NULL); + + if (shader) + { + shader->uniform4f(LLShaderMgr::DIFFUSE_COLOR, r/255.f, g/255.f, b/255.f, a/255.f); + } + else if (r / 255.f != mNewContext.color.mV[0] || g / 255.f != mNewContext.color.mV[1] || b / 255.f != mNewContext.color.mV[2] || a / 255.f != mNewContext.color.mV[3] || mDirty) + { + flush(); + mNewContext.color.mV[0] = r / 255.f; + mNewContext.color.mV[1] = g / 255.f; + mNewContext.color.mV[2] = b / 255.f; + mNewContext.color.mV[3] = a / 255.f; } } void LLRender::debugTexUnits(void) { - LL_INFOS("TextureUnit") << "Active TexUnit: " << mCurrTextureUnitIndex << LL_ENDL; + LL_INFOS("TextureUnit") << "Active TexUnit: " << getCurrentTexUnitIndex() << LL_ENDL; std::string active_enabled = "false"; for (U32 i = 0; i < mTexUnits.size(); i++) { if (getTexUnit(i)->mCurrTexType != LLTexUnit::TT_NONE) { - if (i == mCurrTextureUnitIndex) active_enabled = "true"; + if (i == getCurrentTexUnitIndex()) active_enabled = "true"; LL_INFOS("TextureUnit") << "TexUnit: " << i << " Enabled" << LL_ENDL; LL_INFOS("TextureUnit") << "Enabled As: " ; switch (getTexUnit(i)->mCurrTexType) @@ -2319,9 +2751,6 @@ void LLRender::debugTexUnits(void) case LLTexUnit::TT_TEXTURE: LL_CONT << "Texture 2D"; break; - case LLTexUnit::TT_RECT_TEXTURE: - LL_CONT << "Texture Rectangle"; - break; case LLTexUnit::TT_CUBE_MAP: LL_CONT << "Cube Map"; break; diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h index d8f01a75ab..381e7592b8 100644 --- a/indra/llrender/llrender.h +++ b/indra/llrender/llrender.h @@ -42,13 +42,16 @@ #include "llpointer.h" #include "llglheaders.h" #include "llmatrix4a.h" -#include "glh/glh_linear.h" +#include "llrect.h" +#include "llvector4a.h" +#include class LLVertexBuffer; class LLCubeMap; class LLImageGL; class LLRenderTarget; class LLTexture ; +class LLMatrix4a; #define LL_MATRIX_STACK_DEPTH 32 @@ -61,9 +64,7 @@ class LLTexUnit typedef enum { TT_TEXTURE = 0, // Standard 2D Texture - TT_RECT_TEXTURE, // Non power of 2 texture TT_CUBE_MAP, // 6-sided cube map texture - //TT_MULTISAMPLE_TEXTURE, // see GL_ARB_texture_multisample Do not use TT_NONE // No texture type is currently enabled } eTextureType; @@ -198,7 +199,7 @@ class LLTexUnit void setHasMipMaps(bool hasMips) { mHasMipMaps = hasMips; } protected: - S32 mIndex; + const S32 mIndex; U32 mCurrTexture; eTextureType mCurrTexType; eTextureBlendType mCurrBlendType; @@ -220,15 +221,57 @@ class LLTexUnit void setTextureCombiner(eTextureBlendOp op, eTextureBlendSrc src1, eTextureBlendSrc src2, bool isAlpha = false); }; +struct LLLightStateData +{ + LLLightStateData(bool notSun=true) : + mConstantAtten(1.f), + mLinearAtten(0.f), + mQuadraticAtten(0.f), + mSpotExponent(0.f), + mSpotCutoff(180.f) + { + if (!notSun) + { + mDiffuse.set(1, 1, 1, 1); + mSpecular.set(1, 1, 1, 1); + } + mPosition.set(0, 0, 1, 0); + mSpotDirection.set(0, 0, -1); + } + + LLColor4 mDiffuse; + LLColor4 mSpecular; + LLVector4 mPosition; + LLVector3 mSpotDirection; + + F32 mConstantAtten; + F32 mLinearAtten; + F32 mQuadraticAtten; + + F32 mSpotExponent; + F32 mSpotCutoff; +}; + class LLLightState { public: LLLightState(S32 index); - void enable(); - void disable(); + void enable() { setEnabled(true); } + void disable() { setEnabled(false); } + void setState(LLLightStateData& state) { + setDiffuse(state.mDiffuse); + setSpecular(state.mSpecular); + setPosition(state.mPosition); + setConstantAttenuation(state.mConstantAtten); + setLinearAttenuation(state.mLinearAtten); + setQuadraticAttenuation(state.mQuadraticAtten); + setSpotExponent(state.mSpotExponent); + setSpotCutoff(state.mSpotCutoff); + setSpotDirection(state.mSpotDirection); + } + const LLColor4& getDiffuse() const { return mState.mDiffuse; } void setDiffuse(const LLColor4& diffuse); - void setAmbient(const LLColor4& ambient); void setSpecular(const LLColor4& specular); void setPosition(const LLVector4& position); void setConstantAttenuation(const F32& atten); @@ -237,30 +280,40 @@ class LLLightState void setSpotExponent(const F32& exponent); void setSpotCutoff(const F32& cutoff); void setSpotDirection(const LLVector3& direction); + void setEnabled(const bool enabled); protected: friend class LLRender; S32 mIndex; + LLLightStateData mState; bool mEnabled; - LLColor4 mDiffuse; - LLColor4 mAmbient; - LLColor4 mSpecular; - LLVector4 mPosition; - LLVector3 mSpotDirection; - - F32 mConstantAtten; - F32 mLinearAtten; - F32 mQuadraticAtten; - - F32 mSpotExponent; - F32 mSpotCutoff; + LLMatrix4a mPosMatrix; + LLMatrix4a mSpotMatrix; }; + +LL_ALIGN_PREFIX(16) class LLRender { friend class LLTexUnit; + friend void check_blend_funcs(); public: + enum eTexIndex + { + DIFFUSE_MAP = 0, + NORMAL_MAP, + SPECULAR_MAP, + NUM_TEXTURE_CHANNELS, + }; + + enum eVolumeTexIndex + { + LIGHT_TEX = 0, + SCULPT_TEX, + NUM_VOLUME_TEXTURE_CHANNELS, + }; + typedef enum { TRIANGLES = 0, TRIANGLE_STRIP, @@ -268,7 +321,6 @@ class LLRender POINTS, LINES, LINE_STRIP, - QUADS, LINE_LOOP, NUM_MODES } eGeomModes; @@ -325,36 +377,145 @@ class LLRender MM_TEXTURE } eMatrixMode; + typedef enum + { + PF_FRONT, + PF_BACK, + PF_FRONT_AND_BACK + } ePolygonFaceType; + + typedef enum + { + PM_POINT, + PM_LINE, + PM_FILL + } ePolygonMode; + + static const U8 NUM_LIGHTS = 8; + + // Cache of global gl state. (excludes nested texunit/light states) + struct Context { + Context() : + texUnit(0), + color{ 1.f,1.f,1.f,1.f }, + colorMask{ 0xf }, + alphaFunc(CF_ALWAYS), + alphaVal(0.f), + blendColorSFactor(BF_ONE), + blendAlphaDFactor(BF_ZERO), + blendAlphaSFactor(BF_ONE), + blendColorDFactor(BF_ZERO), + lineWidth(1.f), + pointSize(1.f), + polygonMode{ PM_FILL, PM_FILL }, + polygonOffset{ 0.f, 0.f }, + viewPort(), + scissor() + { + } + U32 texUnit; + LLColor4 color; + U8 colorMask : 4; + eCompareFunc alphaFunc; + F32 alphaVal; + eBlendFactor blendColorSFactor; + eBlendFactor blendColorDFactor; + eBlendFactor blendAlphaSFactor; + eBlendFactor blendAlphaDFactor; + F32 lineWidth; + F32 pointSize; + ePolygonMode polygonMode[2]; + F32 polygonOffset[2]; + LLRect viewPort; + LLRect scissor; + void printDiff(const Context& other) const + { + if (memcmp(this, &other, sizeof(other)) == 0) + { + return; + } +#define PRINT_DIFF(prop) \ + LL_INFOS() << #prop << ": " << other.prop; \ + if (prop != other.prop) { LL_CONT << " -> " << prop; } \ + LL_CONT << LL_ENDL; +#define PRINT_DIFF_BIT(prop, bit) \ + LL_INFOS() << #prop << "(1<<" << #bit << "): " << (other.prop&(1< " << (prop&(1< mBuffer; LLStrider mVerticesp; @@ -459,24 +649,22 @@ class LLRender LLTexUnit* mDummyTexUnit; std::vector mLightState; - eBlendFactor mCurrBlendColorSFactor; - eBlendFactor mCurrBlendColorDFactor; - eBlendFactor mCurrBlendAlphaSFactor; - eBlendFactor mCurrBlendAlphaDFactor; - F32 mMaxAnisotropy; - std::vector mUIOffset; - std::vector mUIScale; + std::vector > mUIOffset; + std::vector > mUIScale; + std::vector mUIRotation; + + bool mPrimitiveReset; +} LL_ALIGN_POSTFIX(16); -}; -extern F32 gGLModelView[16]; -extern F32 gGLLastModelView[16]; -extern F32 gGLLastProjection[16]; -extern F32 gGLPreviousModelView[16]; -extern F32 gGLProjection[16]; -extern S32 gGLViewport[4]; +extern LLMatrix4a gGLModelView; +extern LLMatrix4a gGLLastModelView; +extern LLMatrix4a gGLLastProjection; +extern LLMatrix4a gGLPreviousModelView; +extern LLMatrix4a gGLProjection; +extern LLRect gGLViewport; extern LLRender gGL; diff --git a/indra/llrender/llrender2dutils.cpp b/indra/llrender/llrender2dutils.cpp index 7ab223f4d0..c869381868 100644 --- a/indra/llrender/llrender2dutils.cpp +++ b/indra/llrender/llrender2dutils.cpp @@ -123,11 +123,13 @@ void gl_rect_2d(S32 left, S32 top, S32 right, S32 bottom, BOOL filled ) // Counterclockwise quad will face the viewer if( filled ) { - gGL.begin( LLRender::QUADS ); + gGL.begin( LLRender::TRIANGLES ); gGL.vertex2i(left, top); gGL.vertex2i(left, bottom); - gGL.vertex2i(right, bottom); gGL.vertex2i(right, top); + gGL.vertex2i(right, top); + gGL.vertex2i(left, bottom); + gGL.vertex2i(right, bottom); gGL.end(); } else @@ -195,50 +197,61 @@ void gl_drop_shadow(S32 left, S32 top, S32 right, S32 bottom, const LLColor4 &st LLColor4 end_color = start_color; end_color.mV[VALPHA] = 0.f; - gGL.begin(LLRender::QUADS); + gGL.begin(LLRender::TRIANGLES); // Right edge, CCW faces screen gGL.color4fv(start_color.mV); - gGL.vertex2i(right, top-lines); - gGL.vertex2i(right, bottom); + gGL.vertex2i(right, top - lines); + gGL.vertex2i(right, bottom); gGL.color4fv(end_color.mV); - gGL.vertex2i(right+lines, bottom); - gGL.vertex2i(right+lines, top-lines); + gGL.vertex2i(right + lines, bottom); + gGL.vertex2i(right + lines, bottom); + gGL.vertex2i(right + lines, top - lines); + gGL.color4fv(start_color.mV); + gGL.vertex2i(right, top - lines); // Bottom edge, CCW faces screen - gGL.color4fv(start_color.mV); - gGL.vertex2i(right, bottom); - gGL.vertex2i(left+lines, bottom); + gGL.vertex2i(left + lines, bottom); gGL.color4fv(end_color.mV); - gGL.vertex2i(left+lines, bottom-lines); - gGL.vertex2i(right, bottom-lines); + gGL.vertex2i(left + lines, bottom - lines); + gGL.vertex2i(right, bottom - lines); + gGL.vertex2i(right, bottom - lines); + gGL.color4fv(start_color.mV); + gGL.vertex2i(right, bottom); + gGL.vertex2i(left + lines, bottom); // bottom left Corner gGL.color4fv(start_color.mV); - gGL.vertex2i(left+lines, bottom); + gGL.vertex2i(left + lines, bottom); gGL.color4fv(end_color.mV); - gGL.vertex2i(left, bottom); + gGL.vertex2i(left, bottom); + gGL.vertex2i(left + lines, bottom - lines); + gGL.vertex2i(left + lines, bottom - lines); + gGL.vertex2i(left, bottom); // make the bottom left corner not sharp - gGL.vertex2i(left+1, bottom-lines+1); - gGL.vertex2i(left+lines, bottom-lines); + gGL.vertex2i(left + 1, bottom - lines + 1); // bottom right corner gGL.color4fv(start_color.mV); - gGL.vertex2i(right, bottom); + gGL.vertex2i(right, bottom); gGL.color4fv(end_color.mV); - gGL.vertex2i(right, bottom-lines); + gGL.vertex2i(right, bottom - lines); + gGL.vertex2i(right + lines, bottom); + gGL.vertex2i(right + lines, bottom); + gGL.vertex2i(right, bottom - lines); // make the rightmost corner not sharp - gGL.vertex2i(right+lines-1, bottom-lines+1); - gGL.vertex2i(right+lines, bottom); + gGL.vertex2i(right + lines - 1, bottom - lines + 1); // top right corner gGL.color4fv(start_color.mV); - gGL.vertex2i( right, top-lines ); + gGL.vertex2i(right, top - lines); gGL.color4fv(end_color.mV); - gGL.vertex2i( right+lines, top-lines ); + gGL.vertex2i(right + lines, top - lines); + gGL.vertex2i(right, top); + gGL.vertex2i(right, top); + gGL.vertex2i(right + lines, top - lines); // make the corner not sharp - gGL.vertex2i( right+lines-1, top-1 ); - gGL.vertex2i( right, top ); + gGL.vertex2i(right + lines - 1, top - 1 ); gGL.end(); stop_glerror(); @@ -342,27 +355,32 @@ void gl_draw_image( S32 x, S32 y, LLTexture* image, const LLColor4& color, const { if (NULL == image) { - llwarns << "image == NULL; aborting function" << llendl; + LL_WARNS() << "image == NULL; aborting function" << LL_ENDL; return; } gl_draw_scaled_rotated_image( x, y, image->getWidth(0), image->getHeight(0), 0.f, image, color, uv_rect ); } +void gl_draw_scaled_target(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* target, const LLColor4& color, const LLRectf& uv_rect) +{ + gl_draw_scaled_rotated_image(x, y, width, height, 0.f, NULL, color, uv_rect, target); +} + void gl_draw_scaled_image(S32 x, S32 y, S32 width, S32 height, LLTexture* image, const LLColor4& color, const LLRectf& uv_rect) { if (NULL == image) { - llwarns << "image == NULL; aborting function" << llendl; + LL_WARNS() << "image == NULL; aborting function" << LL_ENDL; return; } gl_draw_scaled_rotated_image( x, y, width, height, 0.f, image, color, uv_rect ); } -void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 border_width, S32 border_height, S32 width, S32 height, LLTexture* image, const LLColor4& color, BOOL solid_color, const LLRectf& uv_rect) +void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 border_width, S32 border_height, S32 width, S32 height, LLTexture* image, const LLColor4& color, BOOL solid_color, const LLRectf& uv_rect, bool scale_inner) { if (NULL == image) { - llwarns << "image == NULL; aborting function" << llendl; + LL_WARNS() << "image == NULL; aborting function" << LL_ENDL; return; } @@ -371,251 +389,243 @@ void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 border_width, S32 border F32 border_height_fraction = (F32)border_height / (F32)image->getHeight(0); LLRectf scale_rect(border_width_fraction, 1.f - border_height_fraction, 1.f - border_width_fraction, border_height_fraction); - gl_draw_scaled_image_with_border(x, y, width, height, image, color, solid_color, uv_rect, scale_rect); + gl_draw_scaled_image_with_border(x, y, width, height, image, color, solid_color, uv_rect, scale_rect, scale_inner); } -void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 width, S32 height, LLTexture* image, const LLColor4& color, BOOL solid_color, const LLRectf& uv_outer_rect, const LLRectf& center_rect) +void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 width, S32 height, LLTexture* image, const LLColor4& color, BOOL solid_color, const LLRectf& uv_outer_rect, const LLRectf& center_rect, bool scale_inner) { stop_glerror(); if (NULL == image) { - llwarns << "image == NULL; aborting function" << llendl; + LL_WARNS() << "image == NULL; aborting function" << LL_ENDL; return; } - // add in offset of current image to current UI translation - const LLVector3 ui_scale = gGL.getUIScale(); - const LLVector3 ui_translation = (gGL.getUITranslation() + LLVector3(x, y, 0.f)).scaledVec(ui_scale); - - F32 uv_width = uv_outer_rect.getWidth(); - F32 uv_height = uv_outer_rect.getHeight(); - - // shrink scaling region to be proportional to clipped image region - LLRectf uv_center_rect( - uv_outer_rect.mLeft + (center_rect.mLeft * uv_width), - uv_outer_rect.mBottom + (center_rect.mTop * uv_height), - uv_outer_rect.mLeft + (center_rect.mRight * uv_width), - uv_outer_rect.mBottom + (center_rect.mBottom * uv_height)); - - F32 image_width = image->getWidth(0); - F32 image_height = image->getHeight(0); + if (solid_color) + { + if (LLGLSLShader::sNoFixedFunction) + { + gSolidColorProgram.bind(); + } + else + { + gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_COLOR); + gGL.getTexUnit(0)->setTextureAlphaBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_TEX_ALPHA, LLTexUnit::TBS_VERT_ALPHA); + } + } - S32 image_natural_width = llround(image_width * uv_width); - S32 image_natural_height = llround(image_height * uv_height); + if (center_rect.mLeft == 0.f + && center_rect.mRight == 1.f + && center_rect.mBottom == 0.f + && center_rect.mTop == 1.f) + { + gl_draw_scaled_image(x, y, width, height, image, color, uv_outer_rect); + } + else + { + // add in offset of current image to current UI translation + const LLVector3 ui_scale = gGL.getUIScale(); + const LLVector3 ui_translation = (gGL.getUITranslation() + LLVector3(x, y, 0.f)).scaledVec(ui_scale); - LLRectf draw_center_rect( uv_center_rect.mLeft * image_width, - uv_center_rect.mTop * image_height, - uv_center_rect.mRight * image_width, - uv_center_rect.mBottom * image_height); + F32 uv_width = uv_outer_rect.getWidth(); + F32 uv_height = uv_outer_rect.getHeight(); - { // scale fixed region of image to drawn region - draw_center_rect.mRight += width - image_natural_width; - draw_center_rect.mTop += height - image_natural_height; + // shrink scaling region to be proportional to clipped image region + LLRectf uv_center_rect( uv_outer_rect.mLeft + (center_rect.mLeft * uv_width), + uv_outer_rect.mBottom + (center_rect.mTop * uv_height), + uv_outer_rect.mLeft + (center_rect.mRight * uv_width), + uv_outer_rect.mBottom + (center_rect.mBottom * uv_height)); - F32 border_shrink_width = llmax(0.f, draw_center_rect.mLeft - draw_center_rect.mRight); - F32 border_shrink_height = llmax(0.f, draw_center_rect.mBottom - draw_center_rect.mTop); + F32 image_width = image->getWidth(0); + F32 image_height = image->getHeight(0); - F32 shrink_width_ratio = center_rect.getWidth() == 1.f ? 0.f : border_shrink_width / ((F32)image_natural_width * (1.f - center_rect.getWidth())); - F32 shrink_height_ratio = center_rect.getHeight() == 1.f ? 0.f : border_shrink_height / ((F32)image_natural_height * (1.f - center_rect.getHeight())); + S32 image_natural_width = ll_pos_round(image_width * uv_width); + S32 image_natural_height = ll_pos_round(image_height * uv_height); - F32 shrink_scale = 1.f - llmax(shrink_width_ratio, shrink_height_ratio); + LLRectf draw_center_rect( uv_center_rect.mLeft * image_width, + uv_center_rect.mTop * image_height, + uv_center_rect.mRight * image_width, + uv_center_rect.mBottom * image_height); + + if (scale_inner) + { + // scale center region of image to drawn region + draw_center_rect.mRight += width - image_natural_width; + draw_center_rect.mTop += height - image_natural_height; - draw_center_rect.mLeft = llround(ui_translation.mV[VX] + (F32)draw_center_rect.mLeft * shrink_scale * ui_scale.mV[VX]); - draw_center_rect.mTop = llround(ui_translation.mV[VY] + lerp((F32)height, (F32)draw_center_rect.mTop, shrink_scale) * ui_scale.mV[VY]); - draw_center_rect.mRight = llround(ui_translation.mV[VX] + lerp((F32)width, (F32)draw_center_rect.mRight, shrink_scale) * ui_scale.mV[VX]); - draw_center_rect.mBottom = llround(ui_translation.mV[VY] + (F32)draw_center_rect.mBottom * shrink_scale * ui_scale.mV[VY]); - } + const F32 border_shrink_width = llmax(0.f, draw_center_rect.mLeft - draw_center_rect.mRight); + const F32 border_shrink_height = llmax(0.f, draw_center_rect.mBottom - draw_center_rect.mTop); - LLRectf draw_outer_rect(ui_translation.mV[VX], - ui_translation.mV[VY] + height * ui_scale.mV[VY], - ui_translation.mV[VX] + width * ui_scale.mV[VX], - ui_translation.mV[VY]); + const F32 shrink_width_ratio = center_rect.getWidth() == 1.f ? 0.f : border_shrink_width / ((F32)image_natural_width * (1.f - center_rect.getWidth())); + const F32 shrink_height_ratio = center_rect.getHeight() == 1.f ? 0.f : border_shrink_height / ((F32)image_natural_height * (1.f - center_rect.getHeight())); - LLGLSUIDefault gls_ui; - - if (solid_color) - { - if (LLGLSLShader::sNoFixedFunction) - { - gSolidColorProgram.bind(); + const F32 border_shrink_scale = 1.f - llmax(shrink_width_ratio, shrink_height_ratio); + draw_center_rect.mLeft *= border_shrink_scale; + draw_center_rect.mTop = lerp((F32)height, (F32)draw_center_rect.mTop, border_shrink_scale); + draw_center_rect.mRight = lerp((F32)width, (F32)draw_center_rect.mRight, border_shrink_scale); + draw_center_rect.mBottom *= border_shrink_scale; } else { - gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_COLOR); - gGL.getTexUnit(0)->setTextureAlphaBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_TEX_ALPHA, LLTexUnit::TBS_VERT_ALPHA); + // keep center region of image at fixed scale, but in same relative position + F32 scale_factor = llmin((F32)width / draw_center_rect.getWidth(), (F32)height / draw_center_rect.getHeight(), 1.f); + F32 scaled_width = draw_center_rect.getWidth() * scale_factor; + F32 scaled_height = draw_center_rect.getHeight() * scale_factor; + draw_center_rect.setCenterAndSize(uv_center_rect.getCenterX() * width, uv_center_rect.getCenterY() * height, scaled_width, scaled_height); } - } - gGL.getTexUnit(0)->bind(image, true); + draw_center_rect.mLeft = ll_round(ui_translation.mV[VX] + (F32)draw_center_rect.mLeft * ui_scale.mV[VX]); + draw_center_rect.mTop = ll_round(ui_translation.mV[VY] + (F32)draw_center_rect.mTop * ui_scale.mV[VY]); + draw_center_rect.mRight = ll_round(ui_translation.mV[VX] + (F32)draw_center_rect.mRight * ui_scale.mV[VX]); + draw_center_rect.mBottom = ll_round(ui_translation.mV[VY] + (F32)draw_center_rect.mBottom * ui_scale.mV[VY]); + + LLRectf draw_outer_rect(ui_translation.mV[VX], + ui_translation.mV[VY] + height * ui_scale.mV[VY], + ui_translation.mV[VX] + width * ui_scale.mV[VX], + ui_translation.mV[VY]); + + LLGLSUIDefault gls_ui; + + gGL.getTexUnit(0)->bind(image, true); gGL.color4fv(color.mV); - gGL.diffuseColor4fv(color.mV); //workaround: Intel HD 4000 - const S32 NUM_VERTICES = 9 * 4; // 9 quads + const S32 NUM_VERTICES = (2 + 2 * 3) * 3 + 4; LLVector2 uv[NUM_VERTICES]; LLVector4a pos[NUM_VERTICES]; S32 index = 0; - gGL.begin(LLRender::QUADS); + gGL.begin(LLRender::TRIANGLE_STRIP); { - // draw bottom left - uv[index] = LLVector2(uv_outer_rect.mLeft, uv_outer_rect.mBottom); - pos[index].set(draw_outer_rect.mLeft, draw_outer_rect.mBottom, 0.f); - index++; - - uv[index] = LLVector2(uv_center_rect.mLeft, uv_outer_rect.mBottom); - pos[index].set(draw_center_rect.mLeft, draw_outer_rect.mBottom, 0.f); + // draw top left + uv[index] = LLVector2(uv_outer_rect.mLeft, uv_outer_rect.mTop); + pos[index].set(draw_outer_rect.mLeft, draw_outer_rect.mTop, 0.f); index++; - uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mBottom); - pos[index].set(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f); + uv[index] = LLVector2(uv_outer_rect.mLeft, uv_center_rect.mTop); + pos[index].set(draw_outer_rect.mLeft, draw_center_rect.mTop, 0.f); index++; - uv[index] = LLVector2(uv_outer_rect.mLeft, uv_center_rect.mBottom); - pos[index].set(draw_outer_rect.mLeft, draw_center_rect.mBottom, 0.f); + uv[index] = LLVector2(uv_center_rect.mLeft, uv_outer_rect.mTop); + pos[index].set(draw_center_rect.mLeft, draw_outer_rect.mTop, 0.f); index++; - // draw bottom middle - uv[index] = LLVector2(uv_center_rect.mLeft, uv_outer_rect.mBottom); - pos[index].set(draw_center_rect.mLeft, draw_outer_rect.mBottom, 0.f); + uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mTop); + pos[index].set(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f); index++; - uv[index] = LLVector2(uv_center_rect.mRight, uv_outer_rect.mBottom); - pos[index].set(draw_center_rect.mRight, draw_outer_rect.mBottom, 0.f); + // draw top middle + uv[index] = LLVector2(uv_center_rect.mRight, uv_outer_rect.mTop); + pos[index].set(draw_center_rect.mRight, draw_outer_rect.mTop, 0.f); index++; - uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mBottom); - pos[index].set(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f); + uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mTop); + pos[index].set(draw_center_rect.mRight, draw_center_rect.mTop, 0.f); index++; - uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mBottom); - pos[index].set(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f); + // draw top right + uv[index] = LLVector2(uv_outer_rect.mRight, uv_outer_rect.mTop); + pos[index].set(draw_outer_rect.mRight, draw_outer_rect.mTop, 0.f); index++; - // draw bottom right - uv[index] = LLVector2(uv_center_rect.mRight, uv_outer_rect.mBottom); - pos[index].set(draw_center_rect.mRight, draw_outer_rect.mBottom, 0.f); + uv[index] = LLVector2(uv_outer_rect.mRight, uv_center_rect.mTop); + pos[index].set(draw_outer_rect.mRight, draw_center_rect.mTop, 0.f); index++; - uv[index] = LLVector2(uv_outer_rect.mRight, uv_outer_rect.mBottom); - pos[index].set(draw_outer_rect.mRight, draw_outer_rect.mBottom, 0.f); + // draw degenerate + uv[index] = LLVector2(uv_outer_rect.mRight, uv_center_rect.mTop); + pos[index].set(draw_outer_rect.mRight, draw_center_rect.mTop, 0.f); index++; - uv[index] = LLVector2(uv_outer_rect.mRight, uv_center_rect.mBottom); - pos[index].set(draw_outer_rect.mRight, draw_center_rect.mBottom, 0.f); + uv[index] = LLVector2(uv_outer_rect.mLeft, uv_center_rect.mTop); + pos[index].set(draw_outer_rect.mLeft, draw_center_rect.mTop, 0.f); index++; - uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mBottom); - pos[index].set(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f); + // draw left + uv[index] = LLVector2(uv_outer_rect.mLeft, uv_center_rect.mTop); + pos[index].set(draw_outer_rect.mLeft, draw_center_rect.mTop, 0.f); index++; - // draw left uv[index] = LLVector2(uv_outer_rect.mLeft, uv_center_rect.mBottom); pos[index].set(draw_outer_rect.mLeft, draw_center_rect.mBottom, 0.f); index++; - uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mBottom); - pos[index].set(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f); - index++; - uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mTop); pos[index].set(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f); index++; - uv[index] = LLVector2(uv_outer_rect.mLeft, uv_center_rect.mTop); - pos[index].set(draw_outer_rect.mLeft, draw_center_rect.mTop, 0.f); - index++; - - // draw middle uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mBottom); pos[index].set(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f); index++; - uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mBottom); - pos[index].set(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f); - index++; - + // draw middle uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mTop); pos[index].set(draw_center_rect.mRight, draw_center_rect.mTop, 0.f); index++; - uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mTop); - pos[index].set(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f); - index++; - - // draw right uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mBottom); pos[index].set(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f); index++; - uv[index] = LLVector2(uv_outer_rect.mRight, uv_center_rect.mBottom); - pos[index].set(draw_outer_rect.mRight, draw_center_rect.mBottom, 0.f); - index++; - + // draw right uv[index] = LLVector2(uv_outer_rect.mRight, uv_center_rect.mTop); pos[index].set(draw_outer_rect.mRight, draw_center_rect.mTop, 0.f); index++; - uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mTop); - pos[index].set(draw_center_rect.mRight, draw_center_rect.mTop, 0.f); - index++; - - // draw top left - uv[index] = LLVector2(uv_outer_rect.mLeft, uv_center_rect.mTop); - pos[index].set(draw_outer_rect.mLeft, draw_center_rect.mTop, 0.f); - index++; - - uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mTop); - pos[index].set(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f); + uv[index] = LLVector2(uv_outer_rect.mRight, uv_center_rect.mBottom); + pos[index].set(draw_outer_rect.mRight, draw_center_rect.mBottom, 0.f); index++; - uv[index] = LLVector2(uv_center_rect.mLeft, uv_outer_rect.mTop); - pos[index].set(draw_center_rect.mLeft, draw_outer_rect.mTop, 0.f); + // draw degenerate + uv[index] = LLVector2(uv_outer_rect.mRight, uv_center_rect.mBottom); + pos[index].set(draw_outer_rect.mRight, draw_center_rect.mBottom, 0.f); index++; - uv[index] = LLVector2(uv_outer_rect.mLeft, uv_outer_rect.mTop); - pos[index].set(draw_outer_rect.mLeft, draw_outer_rect.mTop, 0.f); + uv[index] = LLVector2(uv_outer_rect.mLeft, uv_center_rect.mBottom); + pos[index].set(draw_outer_rect.mLeft, draw_center_rect.mBottom, 0.f); index++; - // draw top middle - uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mTop); - pos[index].set(draw_center_rect.mLeft, draw_center_rect.mTop, 0.f); + // draw bottom left + uv[index] = LLVector2(uv_outer_rect.mLeft, uv_center_rect.mBottom); + pos[index].set(draw_outer_rect.mLeft, draw_center_rect.mBottom, 0.f); index++; - uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mTop); - pos[index].set(draw_center_rect.mRight, draw_center_rect.mTop, 0.f); + uv[index] = LLVector2(uv_outer_rect.mLeft, uv_outer_rect.mBottom); + pos[index].set(draw_outer_rect.mLeft, draw_outer_rect.mBottom, 0.f); index++; - uv[index] = LLVector2(uv_center_rect.mRight, uv_outer_rect.mTop); - pos[index].set(draw_center_rect.mRight, draw_outer_rect.mTop, 0.f); + uv[index] = LLVector2(uv_center_rect.mLeft, uv_center_rect.mBottom); + pos[index].set(draw_center_rect.mLeft, draw_center_rect.mBottom, 0.f); index++; - uv[index] = LLVector2(uv_center_rect.mLeft, uv_outer_rect.mTop); - pos[index].set(draw_center_rect.mLeft, draw_outer_rect.mTop, 0.f); + uv[index] = LLVector2(uv_center_rect.mLeft, uv_outer_rect.mBottom); + pos[index].set(draw_center_rect.mLeft, draw_outer_rect.mBottom, 0.f); index++; - // draw top right - uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mTop); - pos[index].set(draw_center_rect.mRight, draw_center_rect.mTop, 0.f); + // draw bottom middle + uv[index] = LLVector2(uv_center_rect.mRight, uv_center_rect.mBottom); + pos[index].set(draw_center_rect.mRight, draw_center_rect.mBottom, 0.f); index++; - uv[index] = LLVector2(uv_outer_rect.mRight, uv_center_rect.mTop); - pos[index].set(draw_outer_rect.mRight, draw_center_rect.mTop, 0.f); + uv[index] = LLVector2(uv_center_rect.mRight, uv_outer_rect.mBottom); + pos[index].set(draw_center_rect.mRight, draw_outer_rect.mBottom, 0.f); index++; - uv[index] = LLVector2(uv_outer_rect.mRight, uv_outer_rect.mTop); - pos[index].set(draw_outer_rect.mRight, draw_outer_rect.mTop, 0.f); + // draw bottom right + uv[index] = LLVector2(uv_outer_rect.mRight, uv_center_rect.mBottom); + pos[index].set(draw_outer_rect.mRight, draw_center_rect.mBottom, 0.f); index++; - uv[index] = LLVector2(uv_center_rect.mRight, uv_outer_rect.mTop); - pos[index].set(draw_center_rect.mRight, draw_outer_rect.mTop, 0.f); + uv[index] = LLVector2(uv_outer_rect.mRight, uv_outer_rect.mBottom); + pos[index].set(draw_outer_rect.mRight, draw_outer_rect.mBottom, 0.f); index++; gGL.vertexBatchPreTransformed(pos, uv, NUM_VERTICES); + } + gGL.end(); } - gGL.end(); if (solid_color) { @@ -635,28 +645,34 @@ void gl_draw_rotated_image(S32 x, S32 y, F32 degrees, LLTexture* image, const LL gl_draw_scaled_rotated_image( x, y, image->getWidth(0), image->getHeight(0), degrees, image, color, uv_rect ); } -void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degrees, LLTexture* image, const LLColor4& color, const LLRectf& uv_rect) +void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degrees, LLTexture* image, const LLColor4& color, const LLRectf& uv_rect, LLRenderTarget* target) { - if (NULL == image) + if (!image && !target) { - llwarns << "image == NULL; aborting function" << llendl; + LL_WARNS() << "image == NULL; aborting function" << LL_ENDL; return; } LLGLSUIDefault gls_ui; - - gGL.getTexUnit(0)->bind(image, true); + if(image != NULL) + { + gGL.getTexUnit(0)->bind(image, true); + } + else + { + gGL.getTexUnit(0)->bind(target); + } gGL.color4fv(color.mV); if (degrees == 0.f) { - const S32 NUM_VERTICES = 4; // 9 quads + const S32 NUM_VERTICES = 4; LLVector2 uv[NUM_VERTICES]; LLVector4a pos[NUM_VERTICES]; - gGL.begin(LLRender::QUADS); + gGL.begin(LLRender::TRIANGLE_STRIP); { LLVector3 ui_scale = gGL.getUIScale(); LLVector3 ui_translation = gGL.getUITranslation(); @@ -664,12 +680,8 @@ void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degre ui_translation.mV[VY] += y; ui_translation.scaleVec(ui_scale); S32 index = 0; - S32 scaled_width = llround(width * ui_scale.mV[VX]); - S32 scaled_height = llround(height * ui_scale.mV[VY]); - - uv[index] = LLVector2(uv_rect.mRight, uv_rect.mTop); - pos[index].set(ui_translation.mV[VX] + scaled_width, ui_translation.mV[VY] + scaled_height, 0.f); - index++; + S32 scaled_width = ll_pos_round(width * ui_scale.mV[VX]); + S32 scaled_height = ll_pos_round(height * ui_scale.mV[VY]); uv[index] = LLVector2(uv_rect.mLeft, uv_rect.mTop); pos[index].set(ui_translation.mV[VX], ui_translation.mV[VY] + scaled_height, 0.f); @@ -679,6 +691,10 @@ void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degre pos[index].set(ui_translation.mV[VX], ui_translation.mV[VY], 0.f); index++; + uv[index] = LLVector2(uv_rect.mRight, uv_rect.mTop); + pos[index].set(ui_translation.mV[VX] + scaled_width, ui_translation.mV[VY] + scaled_height, 0.f); + index++; + uv[index] = LLVector2(uv_rect.mRight, uv_rect.mBottom); pos[index].set(ui_translation.mV[VX] + scaled_width, ui_translation.mV[VY], 0.f); index++; @@ -698,19 +714,22 @@ void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degre gGL.translateUI(offset_x, offset_y, 0.f); LLMatrix3 quat(0.f, 0.f, degrees*DEG_TO_RAD); - - gGL.getTexUnit(0)->bind(image, true); + + if(image != NULL) + { + gGL.getTexUnit(0)->bind(image, true); + } + else + { + gGL.getTexUnit(0)->bind(target); + } gGL.color4fv(color.mV); - - gGL.begin(LLRender::QUADS); + + gGL.begin(LLRender::TRIANGLE_STRIP); { LLVector3 v; - v = LLVector3(offset_x, offset_y, 0.f) * quat; - gGL.texCoord2f(uv_rect.mRight, uv_rect.mTop); - gGL.vertex2f(v.mV[0], v.mV[1] ); - v = LLVector3(-offset_x, offset_y, 0.f) * quat; gGL.texCoord2f(uv_rect.mLeft, uv_rect.mTop); gGL.vertex2f(v.mV[0], v.mV[1] ); @@ -719,6 +738,10 @@ void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degre gGL.texCoord2f(uv_rect.mLeft, uv_rect.mBottom); gGL.vertex2f(v.mV[0], v.mV[1] ); + v = LLVector3(offset_x, offset_y, 0.f) * quat; + gGL.texCoord2f(uv_rect.mRight, uv_rect.mTop); + gGL.vertex2f(v.mV[0], v.mV[1]); + v = LLVector3(offset_x, -offset_y, 0.f) * quat; gGL.texCoord2f(uv_rect.mRight, uv_rect.mBottom); gGL.vertex2f(v.mV[0], v.mV[1] ); @@ -736,12 +759,12 @@ void gl_stippled_line_3d( const LLVector3& start, const LLVector3& end, const LL S32 shift = S32(phase * 4.f) % 4; // Stippled line - LLGLEnable stipple(GL_LINE_STIPPLE); + LLGLEnable stipple; gGL.color4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], color.mV[VALPHA]); gGL.flush(); - glLineWidth(2.5f); + gGL.setLineWidth(2.5f); if (!LLGLSLShader::sNoFixedFunction) { @@ -870,15 +893,14 @@ void gl_ring( F32 radius, F32 width, const LLColor4& center_color, const LLColor if( render_center ) { gGL.color4fv(center_color.mV); - gGL.diffuseColor4fv(center_color.mV); gl_deep_circle( radius, width, steps ); } else { - gGL.diffuseColor4fv(side_color.mV); - gl_washer_2d(radius, radius - width, steps, side_color, side_color); - gGL.translateUI(0.f, 0.f, width); + gGL.color4fv(side_color.mV); gl_washer_2d(radius - width, radius, steps, side_color, side_color); + gGL.translateUI(0.f, 0.f, width); + gl_washer_2d(radius, radius - width, steps, side_color, side_color); } } gGL.popUIMatrix(); @@ -921,15 +943,15 @@ void gl_washer_2d(F32 outer_radius, F32 inner_radius, S32 steps, const LLColor4& gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gGL.begin( LLRender::TRIANGLE_STRIP ); + gGL.begin( LLRender::TRIANGLE_STRIP ); { steps += 1; // An extra step to close the circle. while( steps-- ) { + gGL.color4fv(inner_color.mV); + gGL.vertex2f(x2, y2); gGL.color4fv(outer_color.mV); gGL.vertex2f( x1, y1 ); - gGL.color4fv(inner_color.mV); - gGL.vertex2f( x2, y2 ); F32 x1_new = x1 * COS_DELTA - y1 * SIN_DELTA; y1 = x1 * SIN_DELTA + y1 * COS_DELTA; @@ -962,10 +984,10 @@ void gl_washer_segment_2d(F32 outer_radius, F32 inner_radius, F32 start_radians, steps += 1; // An extra step to close the circle. while( steps-- ) { + gGL.color4fv(inner_color.mV); + gGL.vertex2f(x2, y2); gGL.color4fv(outer_color.mV); gGL.vertex2f( x1, y1 ); - gGL.color4fv(inner_color.mV); - gGL.vertex2f( x2, y2 ); F32 x1_new = x1 * COS_DELTA - y1 * SIN_DELTA; y1 = x1 * SIN_DELTA + y1 * COS_DELTA; @@ -1017,41 +1039,45 @@ void gl_washer_spokes_2d(F32 outer_radius, F32 inner_radius, S32 count, const LL void gl_rect_2d_simple_tex( S32 width, S32 height ) { - gGL.begin( LLRender::QUADS ); - - gGL.texCoord2f(1.f, 1.f); - gGL.vertex2i(width, height); - + gGL.begin( LLRender::TRIANGLE_STRIP ); + { gGL.texCoord2f(0.f, 1.f); gGL.vertex2i(0, height); gGL.texCoord2f(0.f, 0.f); gGL.vertex2i(0, 0); + gGL.texCoord2f(1.f, 1.f); + gGL.vertex2i(width, height); + gGL.texCoord2f(1.f, 0.f); gGL.vertex2i(width, 0); - + } gGL.end(); } -void gl_rect_2d_simple( S32 width, S32 height ) +void gl_rect_2d_simple(S32 width, S32 height) { - gGL.begin( LLRender::QUADS ); - gGL.vertex2i(width, height); + gGL.begin(LLRender::TRIANGLES); + { gGL.vertex2i(0, height); gGL.vertex2i(0, 0); + gGL.vertex2i(width, height); + gGL.vertex2i(width, height); + gGL.vertex2i(0, 0); gGL.vertex2i(width, 0); + } gGL.end(); } -void gl_segmented_rect_2d_tex(const S32 left, - const S32 top, - const S32 right, - const S32 bottom, - const S32 texture_width, - const S32 texture_height, - const S32 border_size, - const U32 edges) +void gl_segmented_rect_2d_tex(const S32 left, + const S32 top, + const S32 right, + const S32 bottom, + const S32 texture_width, + const S32 texture_height, + const S32 border_size, + const U32 edges) { S32 width = llabs(right - left); S32 height = llabs(top - bottom); @@ -1078,142 +1104,113 @@ void gl_segmented_rect_2d_tex(const S32 left, LLVector2 width_vec((F32)width, 0.f); LLVector2 height_vec(0.f, (F32)height); - gGL.begin(LLRender::QUADS); + gGL.begin(LLRender::TRIANGLE_STRIP); { - // draw bottom left - gGL.texCoord2f(0.f, 0.f); - gGL.vertex2f(0.f, 0.f); - - gGL.texCoord2f(border_uv_scale.mV[VX], 0.f); - gGL.vertex2fv(border_width_left.mV); - - gGL.texCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]); - gGL.vertex2fv((border_width_left + border_height_bottom).mV); - - gGL.texCoord2f(0.f, border_uv_scale.mV[VY]); - gGL.vertex2fv(border_height_bottom.mV); - - // draw bottom middle - gGL.texCoord2f(border_uv_scale.mV[VX], 0.f); - gGL.vertex2fv(border_width_left.mV); - - gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 0.f); - gGL.vertex2fv((width_vec - border_width_right).mV); + // draw top left + gGL.texCoord2f(0.f, 1.f); + gGL.vertex2fv((height_vec).mV); - gGL.texCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]); - gGL.vertex2fv((width_vec - border_width_right + border_height_bottom).mV); + gGL.texCoord2f(0.f, 1.f - border_uv_scale.mV[VY]); + gGL.vertex2fv((height_vec - border_height_top).mV); - gGL.texCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]); - gGL.vertex2fv((border_width_left + border_height_bottom).mV); + gGL.texCoord2f(border_uv_scale.mV[VX], 1.f); + gGL.vertex2fv((border_width_left + height_vec).mV); - // draw bottom right - gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 0.f); - gGL.vertex2fv((width_vec - border_width_right).mV); + gGL.texCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]); + gGL.vertex2fv((border_width_left + height_vec - border_height_top).mV); - gGL.texCoord2f(1.f, 0.f); - gGL.vertex2fv(width_vec.mV); + // draw top middle + gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f); + gGL.vertex2fv((width_vec - border_width_right + height_vec).mV); - gGL.texCoord2f(1.f, border_uv_scale.mV[VY]); - gGL.vertex2fv((width_vec + border_height_bottom).mV); + gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]); + gGL.vertex2fv((width_vec - border_width_right + height_vec - border_height_top).mV); - gGL.texCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]); - gGL.vertex2fv((width_vec - border_width_right + border_height_bottom).mV); + // draw top right + gGL.texCoord2f(1.f, 1.f); + gGL.vertex2fv((width_vec + height_vec).mV); + gGL.texCoord2f(1.f, 1.f - border_uv_scale.mV[VY]); + gGL.vertex2fv((width_vec + height_vec - border_height_top).mV); + } + gGL.end(); + gGL.begin(LLRender::TRIANGLE_STRIP); + { // draw left + gGL.texCoord2f(0.f, 1.f - border_uv_scale.mV[VY]); + gGL.vertex2fv((height_vec - border_height_top).mV); + gGL.texCoord2f(0.f, border_uv_scale.mV[VY]); gGL.vertex2fv(border_height_bottom.mV); - gGL.texCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]); - gGL.vertex2fv((border_width_left + border_height_bottom).mV); - gGL.texCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]); gGL.vertex2fv((border_width_left + height_vec - border_height_top).mV); - gGL.texCoord2f(0.f, 1.f - border_uv_scale.mV[VY]); - gGL.vertex2fv((height_vec - border_height_top).mV); - - // draw middle gGL.texCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]); gGL.vertex2fv((border_width_left + border_height_bottom).mV); - gGL.texCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]); - gGL.vertex2fv((width_vec - border_width_right + border_height_bottom).mV); - + // draw middle gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]); gGL.vertex2fv((width_vec - border_width_right + height_vec - border_height_top).mV); - gGL.texCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]); - gGL.vertex2fv((border_width_left + height_vec - border_height_top).mV); - - // draw right gGL.texCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]); gGL.vertex2fv((width_vec - border_width_right + border_height_bottom).mV); - gGL.texCoord2f(1.f, border_uv_scale.mV[VY]); - gGL.vertex2fv((width_vec + border_height_bottom).mV); - + // draw right gGL.texCoord2f(1.f, 1.f - border_uv_scale.mV[VY]); gGL.vertex2fv((width_vec + height_vec - border_height_top).mV); - gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]); - gGL.vertex2fv((width_vec - border_width_right + height_vec - border_height_top).mV); - - // draw top left - gGL.texCoord2f(0.f, 1.f - border_uv_scale.mV[VY]); - gGL.vertex2fv((height_vec - border_height_top).mV); - - gGL.texCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]); - gGL.vertex2fv((border_width_left + height_vec - border_height_top).mV); - - gGL.texCoord2f(border_uv_scale.mV[VX], 1.f); - gGL.vertex2fv((border_width_left + height_vec).mV); - - gGL.texCoord2f(0.f, 1.f); - gGL.vertex2fv((height_vec).mV); + gGL.texCoord2f(1.f, border_uv_scale.mV[VY]); + gGL.vertex2fv((width_vec + border_height_bottom).mV); - // draw top middle - gGL.texCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]); - gGL.vertex2fv((border_width_left + height_vec - border_height_top).mV); + } + gGL.end(); + gGL.begin(LLRender::TRIANGLE_STRIP); + { + // draw bottom left + gGL.texCoord2f(0.f, border_uv_scale.mV[VY]); + gGL.vertex2fv(border_height_bottom.mV); - gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]); - gGL.vertex2fv((width_vec - border_width_right + height_vec - border_height_top).mV); + gGL.texCoord2f(0.f, 0.f); + gGL.vertex2f(0.f, 0.f); - gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f); - gGL.vertex2fv((width_vec - border_width_right + height_vec).mV); + gGL.texCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]); + gGL.vertex2fv((border_width_left + border_height_bottom).mV); - gGL.texCoord2f(border_uv_scale.mV[VX], 1.f); - gGL.vertex2fv((border_width_left + height_vec).mV); + gGL.texCoord2f(border_uv_scale.mV[VX], 0.f); + gGL.vertex2fv(border_width_left.mV); - // draw top right - gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]); - gGL.vertex2fv((width_vec - border_width_right + height_vec - border_height_top).mV); + // draw bottom middle + gGL.texCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]); + gGL.vertex2fv((width_vec - border_width_right + border_height_bottom).mV); - gGL.texCoord2f(1.f, 1.f - border_uv_scale.mV[VY]); - gGL.vertex2fv((width_vec + height_vec - border_height_top).mV); + gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 0.f); + gGL.vertex2fv((width_vec - border_width_right).mV); - gGL.texCoord2f(1.f, 1.f); - gGL.vertex2fv((width_vec + height_vec).mV); + // draw bottom right + gGL.texCoord2f(1.f, border_uv_scale.mV[VY]); + gGL.vertex2fv((width_vec + border_height_bottom).mV); - gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f); - gGL.vertex2fv((width_vec - border_width_right + height_vec).mV); + gGL.texCoord2f(1.f , 0.f); + gGL.vertex2fv(width_vec.mV); } gGL.end(); gGL.popUIMatrix(); } -//FIXME: rewrite to use scissor? -void gl_segmented_rect_2d_fragment_tex(const S32 left, - const S32 top, - const S32 right, - const S32 bottom, - const S32 texture_width, - const S32 texture_height, - const S32 border_size, - const F32 start_fragment, - const F32 end_fragment, - const U32 edges) +void gl_segmented_rect_2d_fragment_tex(const LLRect& rect, + const S32 texture_width, + const S32 texture_height, + const S32 border_size, + const F32 start_fragment, + const F32 end_fragment, + const U32 edges) { + const S32 left = rect.mLeft; + const S32 right = rect.mRight; + const S32 top = rect.mTop; + const S32 bottom = rect.mBottom; S32 width = llabs(right - left); S32 height = llabs(top - bottom); @@ -1247,10 +1244,10 @@ void gl_segmented_rect_2d_fragment_tex(const S32 left, LLVector2 x_min; LLVector2 x_max; - gGL.begin(LLRender::QUADS); { if (start_fragment < middle_start) { + gGL.begin(LLRender::TRIANGLE_STRIP); u_min = (start_fragment / middle_start) * border_uv_scale.mV[VX]; u_max = llmin(end_fragment / middle_start, 1.f) * border_uv_scale.mV[VX]; x_min = (start_fragment / middle_start) * border_width_left; @@ -1263,41 +1260,31 @@ void gl_segmented_rect_2d_fragment_tex(const S32 left, gGL.texCoord2f(border_uv_scale.mV[VX], 0.f); gGL.vertex2fv(x_max.mV); - gGL.texCoord2f(u_max, border_uv_scale.mV[VY]); - gGL.vertex2fv((x_max + border_height_bottom).mV); - - gGL.texCoord2f(u_min, border_uv_scale.mV[VY]); - gGL.vertex2fv((x_min + border_height_bottom).mV); - - // draw left gGL.texCoord2f(u_min, border_uv_scale.mV[VY]); gGL.vertex2fv((x_min + border_height_bottom).mV); gGL.texCoord2f(u_max, border_uv_scale.mV[VY]); gGL.vertex2fv((x_max + border_height_bottom).mV); - gGL.texCoord2f(u_max, 1.f - border_uv_scale.mV[VY]); - gGL.vertex2fv((x_max + height_vec - border_height_top).mV); - - gGL.texCoord2f(u_min, 1.f - border_uv_scale.mV[VY]); - gGL.vertex2fv((x_min + height_vec - border_height_top).mV); - - // draw top left + // draw left gGL.texCoord2f(u_min, 1.f - border_uv_scale.mV[VY]); gGL.vertex2fv((x_min + height_vec - border_height_top).mV); gGL.texCoord2f(u_max, 1.f - border_uv_scale.mV[VY]); gGL.vertex2fv((x_max + height_vec - border_height_top).mV); - gGL.texCoord2f(u_max, 1.f); - gGL.vertex2fv((x_max + height_vec).mV); - + // draw top left gGL.texCoord2f(u_min, 1.f); gGL.vertex2fv((x_min + height_vec).mV); + + gGL.texCoord2f(u_max, 1.f); + gGL.vertex2fv((x_max + height_vec).mV); + gGL.end(); } if (end_fragment > middle_start || start_fragment < middle_end) { + gGL.begin(LLRender::TRIANGLE_STRIP); x_min = border_width_left + ((llclamp(start_fragment, middle_start, middle_end) - middle_start)) * width_vec; x_max = border_width_left + ((llclamp(end_fragment, middle_start, middle_end) - middle_start)) * width_vec; @@ -1306,47 +1293,39 @@ void gl_segmented_rect_2d_fragment_tex(const S32 left, gGL.vertex2fv(x_min.mV); gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 0.f); - gGL.vertex2fv((x_max).mV); - - gGL.texCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]); - gGL.vertex2fv((x_max + border_height_bottom).mV); - - gGL.texCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]); - gGL.vertex2fv((x_min + border_height_bottom).mV); + gGL.vertex2fv(x_max.mV); - // draw middle gGL.texCoord2f(border_uv_scale.mV[VX], border_uv_scale.mV[VY]); gGL.vertex2fv((x_min + border_height_bottom).mV); gGL.texCoord2f(1.f - border_uv_scale.mV[VX], border_uv_scale.mV[VY]); gGL.vertex2fv((x_max + border_height_bottom).mV); - gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]); - gGL.vertex2fv((x_max + height_vec - border_height_top).mV); - - gGL.texCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]); - gGL.vertex2fv((x_min + height_vec - border_height_top).mV); - - // draw top middle + // draw middle gGL.texCoord2f(border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]); gGL.vertex2fv((x_min + height_vec - border_height_top).mV); gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f - border_uv_scale.mV[VY]); gGL.vertex2fv((x_max + height_vec - border_height_top).mV); + // draw top middle + gGL.texCoord2f(border_uv_scale.mV[VX], 1.f); + gGL.vertex2fv((x_min + height_vec).mV); + gGL.texCoord2f(1.f - border_uv_scale.mV[VX], 1.f); gGL.vertex2fv((x_max + height_vec).mV); - gGL.texCoord2f(border_uv_scale.mV[VX], 1.f); - gGL.vertex2fv((x_min + height_vec).mV); + gGL.end(); + } if (end_fragment > middle_end) { - u_min = (1.f - llmax(0.f, ((start_fragment - middle_end) / middle_start))) * border_uv_scale.mV[VX]; - u_max = (1.f - ((end_fragment - middle_end) / middle_start)) * border_uv_scale.mV[VX]; - x_min = width_vec - ((1.f - llmax(0.f, ((start_fragment - middle_end) / middle_start))) * border_width_right); - x_max = width_vec - ((1.f - ((end_fragment - middle_end) / middle_start)) * border_width_right); + gGL.begin(LLRender::TRIANGLE_STRIP); + u_min = 1.f - ((1.f - llmax(0.f, (start_fragment - middle_end) / middle_start)) * border_uv_scale.mV[VX]); + u_max = 1.f - ((1.f - ((end_fragment - middle_end) / middle_start)) * border_uv_scale.mV[VX]); + x_min = width_vec - ((1.f - llmax(0.f, (start_fragment - middle_end) / middle_start)) * border_width_right); + x_max = width_vec - ((1.f - ((end_fragment - middle_end) / middle_start)) * border_width_right); // draw bottom right gGL.texCoord2f(u_min, 0.f); @@ -1355,183 +1334,129 @@ void gl_segmented_rect_2d_fragment_tex(const S32 left, gGL.texCoord2f(u_max, 0.f); gGL.vertex2fv(x_max.mV); - gGL.texCoord2f(u_max, border_uv_scale.mV[VY]); - gGL.vertex2fv((x_max + border_height_bottom).mV); - - gGL.texCoord2f(u_min, border_uv_scale.mV[VY]); - gGL.vertex2fv((x_min + border_height_bottom).mV); - - // draw right gGL.texCoord2f(u_min, border_uv_scale.mV[VY]); gGL.vertex2fv((x_min + border_height_bottom).mV); gGL.texCoord2f(u_max, border_uv_scale.mV[VY]); gGL.vertex2fv((x_max + border_height_bottom).mV); - gGL.texCoord2f(u_max, 1.f - border_uv_scale.mV[VY]); - gGL.vertex2fv((x_max + height_vec - border_height_top).mV); - - gGL.texCoord2f(u_min, 1.f - border_uv_scale.mV[VY]); - gGL.vertex2fv((x_min + height_vec - border_height_top).mV); - - // draw top right + // draw right gGL.texCoord2f(u_min, 1.f - border_uv_scale.mV[VY]); gGL.vertex2fv((x_min + height_vec - border_height_top).mV); gGL.texCoord2f(u_max, 1.f - border_uv_scale.mV[VY]); gGL.vertex2fv((x_max + height_vec - border_height_top).mV); - gGL.texCoord2f(u_max, 1.f); - gGL.vertex2fv((x_max + height_vec).mV); - + // draw top right gGL.texCoord2f(u_min, 1.f); gGL.vertex2fv((x_min + height_vec).mV); + + gGL.texCoord2f(u_max, 1.f); + gGL.vertex2fv((x_max + height_vec).mV); + gGL.end(); } } - gGL.end(); gGL.popUIMatrix(); } -void gl_segmented_rect_3d_tex(const LLVector2& border_scale, const LLVector3& border_width, - const LLVector3& border_height, const LLVector3& width_vec, const LLVector3& height_vec, - const U32 edges) +void gl_segmented_rect_3d_tex(const LLRectf& clip_rect, const LLRectf& center_uv_rect, const LLRectf& center_draw_rect, + const LLVector3& width_vec, const LLVector3& height_vec) { - LLVector3 left_border_width = ((edges & (~(U32)ROUNDED_RECT_RIGHT)) != 0) ? border_width : LLVector3::zero; - LLVector3 right_border_width = ((edges & (~(U32)ROUNDED_RECT_LEFT)) != 0) ? border_width : LLVector3::zero; - - LLVector3 top_border_height = ((edges & (~(U32)ROUNDED_RECT_BOTTOM)) != 0) ? border_height : LLVector3::zero; - LLVector3 bottom_border_height = ((edges & (~(U32)ROUNDED_RECT_TOP)) != 0) ? border_height : LLVector3::zero; - - - gGL.begin(LLRender::QUADS); + gGL.begin(LLRender::TRIANGLE_STRIP); { - // draw bottom left - gGL.texCoord2f(0.f, 0.f); - gGL.vertex3f(0.f, 0.f, 0.f); - - gGL.texCoord2f(border_scale.mV[VX], 0.f); - gGL.vertex3fv(left_border_width.mV); - - gGL.texCoord2f(border_scale.mV[VX], border_scale.mV[VY]); - gGL.vertex3fv((left_border_width + bottom_border_height).mV); - - gGL.texCoord2f(0.f, border_scale.mV[VY]); - gGL.vertex3fv(bottom_border_height.mV); - - // draw bottom middle - gGL.texCoord2f(border_scale.mV[VX], 0.f); - gGL.vertex3fv(left_border_width.mV); - - gGL.texCoord2f(1.f - border_scale.mV[VX], 0.f); - gGL.vertex3fv((width_vec - right_border_width).mV); + // draw top left + gGL.texCoord2f(clip_rect.mLeft, clip_rect.mTop); + gGL.vertex3fv((height_vec).mV); - gGL.texCoord2f(1.f - border_scale.mV[VX], border_scale.mV[VY]); - gGL.vertex3fv((width_vec - right_border_width + bottom_border_height).mV); + gGL.texCoord2f(clip_rect.mLeft, center_uv_rect.mTop); + gGL.vertex3fv((center_draw_rect.mTop * height_vec).mV); - gGL.texCoord2f(border_scale.mV[VX], border_scale.mV[VY]); - gGL.vertex3fv((left_border_width + bottom_border_height).mV); + gGL.texCoord2f(center_uv_rect.mLeft, clip_rect.mTop); + gGL.vertex3fv((center_draw_rect.mLeft * width_vec + height_vec).mV); - // draw bottom right - gGL.texCoord2f(1.f - border_scale.mV[VX], 0.f); - gGL.vertex3fv((width_vec - right_border_width).mV); + gGL.texCoord2f(center_uv_rect.mLeft, center_uv_rect.mTop); + gGL.vertex3fv((center_draw_rect.mLeft * width_vec + center_draw_rect.mTop * height_vec).mV); - gGL.texCoord2f(1.f, 0.f); - gGL.vertex3fv(width_vec.mV); + // draw top middle + gGL.texCoord2f(center_uv_rect.mRight, clip_rect.mTop); + gGL.vertex3fv((center_draw_rect.mRight * width_vec + height_vec).mV); - gGL.texCoord2f(1.f, border_scale.mV[VY]); - gGL.vertex3fv((width_vec + bottom_border_height).mV); + gGL.texCoord2f(center_uv_rect.mRight, center_uv_rect.mTop); + gGL.vertex3fv((center_draw_rect.mRight * width_vec + center_draw_rect.mTop * height_vec).mV); - gGL.texCoord2f(1.f - border_scale.mV[VX], border_scale.mV[VY]); - gGL.vertex3fv((width_vec - right_border_width + bottom_border_height).mV); + // draw top right + gGL.texCoord2f(clip_rect.mRight, clip_rect.mTop); + gGL.vertex3fv((width_vec + height_vec).mV); + gGL.texCoord2f(clip_rect.mRight, center_uv_rect.mTop); + gGL.vertex3fv((width_vec + center_draw_rect.mTop * height_vec).mV); + } + gGL.end(); + gGL.begin(LLRender::TRIANGLE_STRIP); + { // draw left - gGL.texCoord2f(0.f, border_scale.mV[VY]); - gGL.vertex3fv(bottom_border_height.mV); + gGL.texCoord2f(clip_rect.mLeft, center_uv_rect.mTop); + gGL.vertex3fv((center_draw_rect.mTop * height_vec).mV); - gGL.texCoord2f(border_scale.mV[VX], border_scale.mV[VY]); - gGL.vertex3fv((left_border_width + bottom_border_height).mV); + gGL.texCoord2f(clip_rect.mLeft, center_uv_rect.mBottom); + gGL.vertex3fv((center_draw_rect.mBottom * height_vec).mV); - gGL.texCoord2f(border_scale.mV[VX], 1.f - border_scale.mV[VY]); - gGL.vertex3fv((left_border_width + height_vec - top_border_height).mV); + gGL.texCoord2f(center_uv_rect.mLeft, center_uv_rect.mTop); + gGL.vertex3fv((center_draw_rect.mLeft * width_vec + center_draw_rect.mTop * height_vec).mV); - gGL.texCoord2f(0.f, 1.f - border_scale.mV[VY]); - gGL.vertex3fv((height_vec - top_border_height).mV); + gGL.texCoord2f(center_uv_rect.mLeft, center_uv_rect.mBottom); + gGL.vertex3fv((center_draw_rect.mLeft * width_vec + center_draw_rect.mBottom * height_vec).mV); // draw middle - gGL.texCoord2f(border_scale.mV[VX], border_scale.mV[VY]); - gGL.vertex3fv((left_border_width + bottom_border_height).mV); - - gGL.texCoord2f(1.f - border_scale.mV[VX], border_scale.mV[VY]); - gGL.vertex3fv((width_vec - right_border_width + bottom_border_height).mV); + gGL.texCoord2f(center_uv_rect.mRight, center_uv_rect.mTop); + gGL.vertex3fv((center_draw_rect.mRight * width_vec + center_draw_rect.mTop * height_vec).mV); - gGL.texCoord2f(1.f - border_scale.mV[VX], 1.f - border_scale.mV[VY]); - gGL.vertex3fv((width_vec - right_border_width + height_vec - top_border_height).mV); - - gGL.texCoord2f(border_scale.mV[VX], 1.f - border_scale.mV[VY]); - gGL.vertex3fv((left_border_width + height_vec - top_border_height).mV); + gGL.texCoord2f(center_uv_rect.mRight, center_uv_rect.mBottom); + gGL.vertex3fv((center_draw_rect.mRight * width_vec + center_draw_rect.mBottom * height_vec).mV); // draw right - gGL.texCoord2f(1.f - border_scale.mV[VX], border_scale.mV[VY]); - gGL.vertex3fv((width_vec - right_border_width + bottom_border_height).mV); - - gGL.texCoord2f(1.f, border_scale.mV[VY]); - gGL.vertex3fv((width_vec + bottom_border_height).mV); - - gGL.texCoord2f(1.f, 1.f - border_scale.mV[VY]); - gGL.vertex3fv((width_vec + height_vec - top_border_height).mV); - - gGL.texCoord2f(1.f - border_scale.mV[VX], 1.f - border_scale.mV[VY]); - gGL.vertex3fv((width_vec - right_border_width + height_vec - top_border_height).mV); + gGL.texCoord2f(clip_rect.mRight, center_uv_rect.mTop); + gGL.vertex3fv((width_vec + center_draw_rect.mTop * height_vec).mV); - // draw top left - gGL.texCoord2f(0.f, 1.f - border_scale.mV[VY]); - gGL.vertex3fv((height_vec - top_border_height).mV); - - gGL.texCoord2f(border_scale.mV[VX], 1.f - border_scale.mV[VY]); - gGL.vertex3fv((left_border_width + height_vec - top_border_height).mV); - - gGL.texCoord2f(border_scale.mV[VX], 1.f); - gGL.vertex3fv((left_border_width + height_vec).mV); - - gGL.texCoord2f(0.f, 1.f); - gGL.vertex3fv((height_vec).mV); + gGL.texCoord2f(clip_rect.mRight, center_uv_rect.mBottom); + gGL.vertex3fv((width_vec + center_draw_rect.mBottom * height_vec).mV); - // draw top middle - gGL.texCoord2f(border_scale.mV[VX], 1.f - border_scale.mV[VY]); - gGL.vertex3fv((left_border_width + height_vec - top_border_height).mV); + } + gGL.end(); + gGL.begin(LLRender::TRIANGLE_STRIP); + { + // draw bottom left + gGL.texCoord2f(clip_rect.mLeft, center_uv_rect.mBottom); + gGL.vertex3fv((center_draw_rect.mBottom * height_vec).mV); - gGL.texCoord2f(1.f - border_scale.mV[VX], 1.f - border_scale.mV[VY]); - gGL.vertex3fv((width_vec - right_border_width + height_vec - top_border_height).mV); + gGL.texCoord2f(clip_rect.mLeft, clip_rect.mBottom); + gGL.vertex3f(0.f, 0.f, 0.f); - gGL.texCoord2f(1.f - border_scale.mV[VX], 1.f); - gGL.vertex3fv((width_vec - right_border_width + height_vec).mV); + gGL.texCoord2f(center_uv_rect.mLeft, center_uv_rect.mBottom); + gGL.vertex3fv((center_draw_rect.mLeft * width_vec + center_draw_rect.mBottom * height_vec).mV); - gGL.texCoord2f(border_scale.mV[VX], 1.f); - gGL.vertex3fv((left_border_width + height_vec).mV); + gGL.texCoord2f(center_uv_rect.mLeft, clip_rect.mBottom); + gGL.vertex3fv((center_draw_rect.mLeft * width_vec).mV); - // draw top right - gGL.texCoord2f(1.f - border_scale.mV[VX], 1.f - border_scale.mV[VY]); - gGL.vertex3fv((width_vec - right_border_width + height_vec - top_border_height).mV); + // draw bottom middle + gGL.texCoord2f(center_uv_rect.mRight, center_uv_rect.mBottom); + gGL.vertex3fv((center_draw_rect.mRight * width_vec + center_draw_rect.mBottom * height_vec).mV); - gGL.texCoord2f(1.f, 1.f - border_scale.mV[VY]); - gGL.vertex3fv((width_vec + height_vec - top_border_height).mV); + gGL.texCoord2f(center_uv_rect.mRight, clip_rect.mBottom); + gGL.vertex3fv((center_draw_rect.mRight * width_vec).mV); - gGL.texCoord2f(1.f, 1.f); - gGL.vertex3fv((width_vec + height_vec).mV); + // draw bottom right + gGL.texCoord2f(clip_rect.mRight, center_uv_rect.mBottom); + gGL.vertex3fv((width_vec + center_draw_rect.mBottom * height_vec).mV); - gGL.texCoord2f(1.f - border_scale.mV[VX], 1.f); - gGL.vertex3fv((width_vec - right_border_width + height_vec).mV); + gGL.texCoord2f(clip_rect.mRight, clip_rect.mBottom); + gGL.vertex3fv(width_vec.mV); } gGL.end(); } -void gl_segmented_rect_3d_tex_top(const LLVector2& border_scale, const LLVector3& border_width, const LLVector3& border_height, const LLVector3& width_vec, const LLVector3& height_vec) -{ - gl_segmented_rect_3d_tex(border_scale, border_width, border_height, width_vec, height_vec, ROUNDED_RECT_TOP); -} - // static void LLRender2D::initClass(LLImageProviderInterface* image_provider, const LLVector2* scale_factor) @@ -1593,8 +1518,7 @@ void LLRender2D::setScaleFactor(const LLVector2 &scale_factor) //static void LLRender2D::setLineWidth(F32 width) { - gGL.flush(); - glLineWidth(width * lerp(sGLScaleFactor.mV[VX], sGLScaleFactor.mV[VY], 0.5f)); + gGL.setLineWidth(width * lerp(sGLScaleFactor.mV[VX], sGLScaleFactor.mV[VY], 0.5f)); } //static @@ -1617,4 +1541,4 @@ LLPointer LLRender2D::getUIImage(const std::string& name, S32 priorit return sImageProvider->getUIImage(name, priority); else return NULL; -} \ No newline at end of file +} diff --git a/indra/llrender/llrender2dutils.h b/indra/llrender/llrender2dutils.h index 0323af6a26..1a2fbdbf43 100644 --- a/indra/llrender/llrender2dutils.h +++ b/indra/llrender/llrender2dutils.h @@ -71,11 +71,12 @@ void gl_washer_2d(F32 outer_radius, F32 inner_radius, S32 steps, const LLColor4& void gl_washer_segment_2d(F32 outer_radius, F32 inner_radius, F32 start_radians, F32 end_radians, S32 steps, const LLColor4& inner_color, const LLColor4& outer_color); void gl_washer_spokes_2d(F32 outer_radius, F32 inner_radius, S32 count, const LLColor4& inner_color, const LLColor4& outer_color); void gl_draw_image(S32 x, S32 y, LLTexture* image, const LLColor4& color = UI_VERTEX_COLOR, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f)); +void gl_draw_scaled_target(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* target, const LLColor4& color = UI_VERTEX_COLOR, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f)); void gl_draw_scaled_image(S32 x, S32 y, S32 width, S32 height, LLTexture* image, const LLColor4& color = UI_VERTEX_COLOR, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f)); void gl_draw_rotated_image(S32 x, S32 y, F32 degrees, LLTexture* image, const LLColor4& color = UI_VERTEX_COLOR, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f)); -void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degrees,LLTexture* image, const LLColor4& color = UI_VERTEX_COLOR, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f)); -void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 border_width, S32 border_height, S32 width, S32 height, LLTexture* image, const LLColor4 &color, BOOL solid_color = FALSE, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f)); -void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 width, S32 height, LLTexture* image, const LLColor4 &color, BOOL solid_color = FALSE, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f), const LLRectf& scale_rect = LLRectf(0.f, 1.f, 1.f, 0.f)); +void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degrees, LLTexture* image, const LLColor4& color = UI_VERTEX_COLOR, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f), LLRenderTarget* target = NULL); +void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 border_width, S32 border_height, S32 width, S32 height, LLTexture* image, const LLColor4 &color, BOOL solid_color = FALSE, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f), bool scale_inner = true); +void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 width, S32 height, LLTexture* image, const LLColor4 &color, BOOL solid_color = FALSE, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f), const LLRectf& scale_rect = LLRectf(0.f, 1.f, 1.f, 0.f), bool scale_inner = true); void gl_stippled_line_3d( const LLVector3& start, const LLVector3& end, const LLColor4& color, F32 phase = 0.f ); @@ -105,9 +106,8 @@ typedef enum e_rounded_edge void gl_segmented_rect_2d_tex(const S32 left, const S32 top, const S32 right, const S32 bottom, const S32 texture_width, const S32 texture_height, const S32 border_size, const U32 edges = ROUNDED_RECT_ALL); -void gl_segmented_rect_2d_fragment_tex(const S32 left, const S32 top, const S32 right, const S32 bottom, const S32 texture_width, const S32 texture_height, const S32 border_size, const F32 start_fragment, const F32 end_fragment, const U32 edges = ROUNDED_RECT_ALL); -void gl_segmented_rect_3d_tex(const LLVector2& border_scale, const LLVector3& border_width, const LLVector3& border_height, const LLVector3& width_vec, const LLVector3& height_vec, U32 edges = ROUNDED_RECT_ALL); -void gl_segmented_rect_3d_tex_top(const LLVector2& border_scale, const LLVector3& border_width, const LLVector3& border_height, const LLVector3& width_vec, const LLVector3& height_vec); +void gl_segmented_rect_2d_fragment_tex(const LLRect& rect, const S32 texture_width, const S32 texture_height, const S32 border_size, const F32 start_fragment, const F32 end_fragment, const U32 edges = ROUNDED_RECT_ALL); +void gl_segmented_rect_3d_tex(const LLRectf& clip_rect, const LLRectf& center_uv_rect, const LLRectf& center_draw_rect, const LLVector3& width_vec, const LLVector3& height_vec); inline void gl_rect_2d( const LLRect& rect, BOOL filled ) { diff --git a/indra/llrender/llrendertarget.cpp b/indra/llrender/llrendertarget.cpp index 977245b6e0..af5ad22e2f 100644 --- a/indra/llrender/llrendertarget.cpp +++ b/indra/llrender/llrendertarget.cpp @@ -43,7 +43,7 @@ void check_framebuffer_status() case GL_FRAMEBUFFER_COMPLETE: break; default: - llwarns << "check_framebuffer_status failed -- " << std::hex << status << std::dec << llendl; + LL_WARNS() << "check_framebuffer_status failed -- " << std::hex << status << std::dec << LL_ENDL; ll_fail("check_framebuffer_status failed"); break; } @@ -51,7 +51,7 @@ void check_framebuffer_status() } bool LLRenderTarget::sUseFBO = false; -U32 LLRenderTarget::sCurFBO = 0; +LLRenderTarget* LLRenderTarget::sCurFBO = 0; LLRenderTarget::LLRenderTarget() : mResX(0), @@ -72,7 +72,7 @@ LLRenderTarget::~LLRenderTarget() release(); } -void LLRenderTarget::resize(U32 resx, U32 resy, U32 color_fmt) +void LLRenderTarget::resize(U32 resx, U32 resy) { //for accounting, get the number of pixels added/subtracted S32 pix_diff = (resx*resy)-(mResX*mResY); @@ -80,10 +80,12 @@ void LLRenderTarget::resize(U32 resx, U32 resy, U32 color_fmt) mResX = resx; mResY = resy; + llassert(mInternalFormat.size() == mTex.size()); + for (U32 i = 0; i < mTex.size(); ++i) { //resize color attachments gGL.getTexUnit(0)->bindManual(mUsage, mTex[i]); - LLImageGL::setManualImage(LLTexUnit::getInternalType(mUsage), 0, color_fmt, mResX, mResY, GL_RGBA, GL_UNSIGNED_BYTE, NULL, false); + LLImageGL::setManualImage(LLTexUnit::getInternalType(mUsage), 0, mInternalFormat[i], mResX, mResY, GL_RGBA, GL_UNSIGNED_BYTE); sBytesAllocated += pix_diff*4; } @@ -101,9 +103,9 @@ void LLRenderTarget::resize(U32 resx, U32 resy, U32 color_fmt) gGL.getTexUnit(0)->bindManual(mUsage, mDepth); U32 internal_type = LLTexUnit::getInternalType(mUsage); if(!mStencil) - LLImageGL::setManualImage(internal_type, 0, GL_DEPTH_COMPONENT24, mResX, mResY, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL, false); + LLImageGL::setManualImage(internal_type, 0, GL_DEPTH_COMPONENT24, mResX, mResY, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT); else - LLImageGL::setManualImage(internal_type, 0, GL_DEPTH24_STENCIL8, mResX, mResY, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL, false); + LLImageGL::setManualImage(internal_type, 0, GL_DEPTH24_STENCIL8, mResX, mResY, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8); } sBytesAllocated += pix_diff*4; @@ -141,7 +143,7 @@ bool LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, boo { if (!allocateDepth()) { - llwarns << "Failed to allocate depth buffer for render target." << llendl; + LL_WARNS() << "Failed to allocate depth buffer for render target." << LL_ENDL; return false; } } @@ -161,7 +163,7 @@ bool LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, boo glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, LLTexUnit::getInternalType(mUsage), mDepth, 0); stop_glerror(); } - glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO); + glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO ? sCurFBO->getFBO() : 0); } stop_glerror(); @@ -181,20 +183,20 @@ bool LLRenderTarget::addColorAttachment(U32 color_fmt) if( offset >= 4 ) { - llwarns << "Too many color attachments" << llendl; + LL_WARNS() << "Too many color attachments" << LL_ENDL; llassert( offset < 4 ); return false; } if( offset > 0 && (mFBO == 0 || !gGLManager.mHasDrawBuffers) ) { - llwarns << "FBO not used or no drawbuffers available; mFBO=" << (U32)mFBO << " gGLManager.mHasDrawBuffers=" << (U32)gGLManager.mHasDrawBuffers << llendl; + LL_WARNS() << "FBO not used or no drawbuffers available; mFBO=" << (U32)mFBO << " gGLManager.mHasDrawBuffers=" << (U32)gGLManager.mHasDrawBuffers << LL_ENDL; llassert( mFBO != 0 ); llassert( gGLManager.mHasDrawBuffers ); return false; } - U32 tex; - LLImageGL::generateTextures(mUsage, color_fmt, 1, &tex); + auto texName = LLImageGL::createTextureName(); + U32 tex = texName->getTexName(); gGL.getTexUnit(0)->bindManual(mUsage, tex); stop_glerror(); @@ -202,10 +204,10 @@ bool LLRenderTarget::addColorAttachment(U32 color_fmt) { clear_glerror(); - LLImageGL::setManualImage(LLTexUnit::getInternalType(mUsage), 0, color_fmt, mResX, mResY, GL_RGBA, GL_UNSIGNED_BYTE, NULL, false); + LLImageGL::setManualImage(LLTexUnit::getInternalType(mUsage), 0, color_fmt, mResX, mResY, GL_RGBA, GL_UNSIGNED_BYTE); if (glGetError() != GL_NO_ERROR) { - llwarns << "Could not allocate color buffer for render target." << llendl; + LL_WARNS() << "Could not allocate color buffer for render target." << LL_ENDL; return false; } } @@ -226,17 +228,8 @@ bool LLRenderTarget::addColorAttachment(U32 color_fmt) stop_glerror(); } - if (mUsage != LLTexUnit::TT_RECT_TEXTURE) - { - gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_MIRROR); - stop_glerror(); - } - else - { - // ATI doesn't support mirrored repeat for rectangular textures. - gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); - stop_glerror(); - } + gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_MIRROR); + stop_glerror(); if (mFBO) { @@ -248,10 +241,11 @@ bool LLRenderTarget::addColorAttachment(U32 color_fmt) check_framebuffer_status(); - glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO); + glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO ? sCurFBO->getFBO() : 0); } mTex.push_back(tex); + mTexName.push_back(texName); mInternalFormat.push_back(color_fmt); if (gDebugGL) @@ -265,6 +259,7 @@ bool LLRenderTarget::addColorAttachment(U32 color_fmt) bool LLRenderTarget::allocateDepth() { + mDepthName.reset(); if (mStencil && mFBO) { //use render buffers where stencil buffers are in play @@ -277,25 +272,24 @@ bool LLRenderTarget::allocateDepth() } else { - if(!mStencil) - LLImageGL::generateTextures(mUsage, GL_DEPTH_COMPONENT24, 1, &mDepth); - else - LLImageGL::generateTextures(mUsage, GL_DEPTH24_STENCIL8, 1, &mDepth); + mDepthName = LLImageGL::createTextureName(); + mDepth = mDepthName->getTexName(); + gGL.getTexUnit(0)->bindManual(mUsage, mDepth); U32 internal_type = LLTexUnit::getInternalType(mUsage); stop_glerror(); clear_glerror(); if(!mStencil) - LLImageGL::setManualImage(internal_type, 0, GL_DEPTH_COMPONENT24, mResX, mResY, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL, false); + LLImageGL::setManualImage(internal_type, 0, GL_DEPTH_COMPONENT24, mResX, mResY, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT); else - LLImageGL::setManualImage(internal_type, 0, GL_DEPTH24_STENCIL8, mResX, mResY, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL, false); + LLImageGL::setManualImage(internal_type, 0, GL_DEPTH24_STENCIL8, mResX, mResY, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8); gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); } if (glGetError() != GL_NO_ERROR) { - llwarns << "Unable to allocate depth buffer for render target." << llendl; + LL_WARNS() << "Unable to allocate depth buffer for render target." << LL_ENDL; return false; } @@ -308,17 +302,17 @@ void LLRenderTarget::shareDepthBuffer(LLRenderTarget& target) { if (!mFBO || !target.mFBO) { - llerrs << "Cannot share depth buffer between non FBO render targets." << llendl; + LL_ERRS() << "Cannot share depth buffer between non FBO render targets." << LL_ENDL; } if (target.mDepth) { - llerrs << "Attempting to override existing depth buffer. Detach existing buffer first." << llendl; + LL_ERRS() << "Attempting to override existing depth buffer. Detach existing buffer first." << LL_ENDL; } if (target.mUseDepth) { - llerrs << "Attempting to override existing shared depth buffer. Detach existing buffer first." << llendl; + LL_ERRS() << "Attempting to override existing shared depth buffer. Detach existing buffer first." << LL_ENDL; } if (mDepth) @@ -343,7 +337,7 @@ void LLRenderTarget::shareDepthBuffer(LLRenderTarget& target) check_framebuffer_status(); - glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO); + glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO ? sCurFBO->getFBO() : 0); target.mUseDepth = true; } @@ -365,8 +359,8 @@ void LLRenderTarget::release() { glBindFramebuffer(GL_FRAMEBUFFER, mFBO); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, LLTexUnit::getInternalType(mUsage), 0, 0); + glBindFramebuffer(GL_FRAMEBUFFER,0); } - LLImageGL::deleteTextures(mUsage, 0, 0, 1, &mDepth, true); stop_glerror(); } mDepth = 0; @@ -386,6 +380,7 @@ void LLRenderTarget::release() { //attached as a texture glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, LLTexUnit::getInternalType(mUsage), 0, 0); } + glBindFramebuffer(GL_FRAMEBUFFER,0); mUseDepth = false; } @@ -395,13 +390,11 @@ void LLRenderTarget::release() mFBO = 0; } - if (mTex.size() > 0) - { - sBytesAllocated -= mResX*mResY*4*mTex.size(); - LLImageGL::deleteTextures(mUsage, mInternalFormat[0], 0, mTex.size(), &mTex[0], true); - mTex.clear(); - mInternalFormat.clear(); - } + sBytesAllocated -= mResX * mResY * 4 * mTex.size(); + mTex.clear(); + mInternalFormat.clear(); + mDepthName.reset(); + mTexName.clear(); // Were textures not being released at all..? mResX = mResY = 0; @@ -414,17 +407,18 @@ void LLRenderTarget::bindTarget() if (mFBO) { stop_glerror(); + mPreviousFBO = sCurFBO; if (mSampleBuffer) { mSampleBuffer->bindTarget(this); - sCurFBO = mSampleBuffer->mFBO; + sCurFBO = mSampleBuffer; stop_glerror(); } else { glBindFramebuffer(GL_FRAMEBUFFER, mFBO); - sCurFBO = mFBO; + sCurFBO = this; stop_glerror(); if (gGLManager.mHasDrawBuffers) @@ -447,8 +441,7 @@ void LLRenderTarget::bindTarget() stop_glerror(); } } - - glViewport(0, 0, mResX, mResY); + gGL.setViewport(0, 0, mResX, mResY); sBoundTarget = this; } @@ -459,18 +452,22 @@ void LLRenderTarget::clear(U32 mask_in) { mask |= GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT; } + if (mFBO) { check_framebuffer_status(); stop_glerror(); + LLGLDisable scissor; + gGL.syncContextState(); glClear(mask & mask_in); stop_glerror(); } else { - LLGLEnable scissor(GL_SCISSOR_TEST); - glScissor(0, 0, mResX, mResY); + LLGLEnable scissor; + gGL.setScissor(0, 0, mResX, mResY); stop_glerror(); + gGL.syncContextState(); glClear(mask & mask_in); } } @@ -479,7 +476,7 @@ U32 LLRenderTarget::getTexture(U32 attachment) const { if (attachment > mTex.size()-1) { - llerrs << "Invalid attachment index." << llendl; + LL_ERRS() << "Invalid attachment index." << LL_ENDL; } if (mTex.empty()) { @@ -522,7 +519,7 @@ void LLRenderTarget::flush(bool fetch_depth) stop_glerror(); if(mSampleBuffer) { - LLGLEnable multisample(GL_MULTISAMPLE); + LLGLEnable multisample; stop_glerror(); glBindFramebuffer(GL_FRAMEBUFFER, mFBO); stop_glerror(); @@ -577,8 +574,18 @@ void LLRenderTarget::flush(bool fetch_depth) } glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); } - glBindFramebuffer(GL_FRAMEBUFFER, mPreviousFBO); + glBindFramebuffer(GL_FRAMEBUFFER, mPreviousFBO ? mPreviousFBO->getFBO() : 0); sCurFBO = mPreviousFBO; + + if(mPreviousFBO) + { + gGL.setViewport(0, 0, mPreviousFBO->mResX, mPreviousFBO->mResY); + mPreviousFBO = NULL; + } + else + { + gGL.setViewport(gGLViewport); + } stop_glerror(); } } @@ -593,7 +600,7 @@ void LLRenderTarget::copyContents(LLRenderTarget& source, S32 srcX0, S32 srcY0, gGL.flush(); if (!source.mFBO || !mFBO) { - llwarns << "Cannot copy framebuffer contents for non FBO render targets." << llendl; + LL_WARNS() << "Cannot copy framebuffer contents for non FBO render targets." << LL_ENDL; return; } @@ -613,7 +620,7 @@ void LLRenderTarget::copyContents(LLRenderTarget& source, S32 srcX0, S32 srcY0, stop_glerror(); glCopyTexSubImage2D(LLTexUnit::getInternalType(mUsage), 0, srcX0, srcY0, dstX0, dstY0, dstX1, dstY1); stop_glerror(); - glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO); + glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO ? sCurFBO->getFBO() : 0); stop_glerror(); } else @@ -636,7 +643,7 @@ void LLRenderTarget::copyContents(LLRenderTarget& source, S32 srcX0, S32 srcY0, stop_glerror(); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); stop_glerror(); - glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO); + glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO ? sCurFBO->getFBO() : 0); stop_glerror(); } } @@ -648,7 +655,7 @@ void LLRenderTarget::copyContentsToFramebuffer(LLRenderTarget& source, S32 srcX0 { if (!source.mFBO) { - llwarns << "Cannot copy framebuffer contents for non FBO render targets." << llendl; + LL_WARNS() << "Cannot copy framebuffer contents for non FBO render targets." << LL_ENDL; return; } { @@ -670,7 +677,7 @@ void LLRenderTarget::copyContentsToFramebuffer(LLRenderTarget& source, S32 srcX0 if(mask) glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); stop_glerror(); - glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO); + glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO ? sCurFBO->getFBO() : 0); stop_glerror(); } } @@ -680,12 +687,9 @@ bool LLRenderTarget::isComplete() const return (!mTex.empty() || mDepth) ? true : false; } -void LLRenderTarget::getViewport(S32* viewport) +void LLRenderTarget::getViewport(LLRect& viewport) { - viewport[0] = 0; - viewport[1] = 0; - viewport[2] = mResX; - viewport[3] = mResY; + viewport = LLRect(0, mResY, mResX, 0); } //================================================== @@ -751,7 +755,7 @@ void LLMultisampleBuffer::bindTarget(LLRenderTarget* ref) check_framebuffer_status(); - glViewport(0, 0, mResX, mResY); + gGL.setViewport(0, 0, mResX, mResY); sBoundTarget = this; } @@ -771,7 +775,7 @@ bool LLMultisampleBuffer::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth if(color_fmt != GL_RGBA) { - llwarns << "Unsupported color format: " << color_fmt << llendl; + LL_WARNS() << "Unsupported color format: " << color_fmt << LL_ENDL; return false; } @@ -819,7 +823,7 @@ bool LLMultisampleBuffer::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth } stop_glerror(); - glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO); + glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO ? sCurFBO->getFBO() : 0); stop_glerror(); @@ -875,7 +879,7 @@ bool LLMultisampleBuffer::addColorAttachment(U32 color_fmt) if (offset >= 4 || (offset > 0 && (mFBO == 0 || !gGLManager.mHasDrawBuffers))) { - llerrs << "Too many color attachments!" << llendl; + LL_ERRS() << "Too many color attachments!" << LL_ENDL; } U32 tex; @@ -886,7 +890,7 @@ bool LLMultisampleBuffer::addColorAttachment(U32 color_fmt) glRenderbufferStorageMultisample(GL_RENDERBUFFER, mSamples, color_fmt, mResX, mResY); if (glGetError() != GL_NO_ERROR) { - llwarns << "Unable to allocate color buffer for multisample render target." << llendl; + LL_WARNS() << "Unable to allocate color buffer for multisample render target." << LL_ENDL; release(); return false; } @@ -898,7 +902,7 @@ bool LLMultisampleBuffer::addColorAttachment(U32 color_fmt) glBindFramebuffer(GL_FRAMEBUFFER, mFBO); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+offset, GL_RENDERBUFFER, tex); check_framebuffer_status(); - glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO); + glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO ? sCurFBO->getFBO() : 0); } mTex.push_back(tex); @@ -922,7 +926,7 @@ bool LLMultisampleBuffer::allocateDepth() if (glGetError() != GL_NO_ERROR) { - llwarns << "Unable to allocate depth buffer for multisample render target." << llendl; + LL_WARNS() << "Unable to allocate depth buffer for multisample render target." << LL_ENDL; return false; } diff --git a/indra/llrender/llrendertarget.h b/indra/llrender/llrendertarget.h index c2696aae6d..bf37cba2bd 100644 --- a/indra/llrender/llrendertarget.h +++ b/indra/llrender/llrendertarget.h @@ -65,7 +65,7 @@ class LLRenderTarget //whether or not to use FBO implementation static bool sUseFBO; static U32 sBytesAllocated; - static U32 sCurFBO; + static LLRenderTarget* sCurFBO; LLRenderTarget(); virtual ~LLRenderTarget(); @@ -79,7 +79,7 @@ class LLRenderTarget // CAUTION: if the GL runs out of memory attempting to resize, this render target will be undefined // DO NOT use for screen space buffers or for scratch space for an image that might be uploaded // DO use for render targets that resize often and aren't likely to ruin someone's day if they break - void resize(U32 resx, U32 resy, U32 color_fmt); + void resize(U32 resx, U32 resy); //provide this render target with a multisample resource. void setSampleBuffer(LLMultisampleBuffer* buffer); @@ -107,7 +107,7 @@ class LLRenderTarget void clear(U32 mask = 0xFFFFFFFF); //get applied viewport - void getViewport(S32* viewport); + void getViewport(LLRect& viewport); //get X resolution U32 getWidth() const { return mResX; } @@ -152,9 +152,11 @@ class LLRenderTarget U32 mResX; U32 mResY; std::vector mTex; + std::vector mTexName; std::vector mInternalFormat; U32 mFBO; - U32 mPreviousFBO; + LLRenderTarget* mPreviousFBO; + LLImageGL::GLTextureName mDepthName; U32 mDepth; bool mStencil; bool mUseDepth; diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp index 7b890c57aa..568ec8c14f 100644 --- a/indra/llrender/llshadermgr.cpp +++ b/indra/llrender/llshadermgr.cpp @@ -56,14 +56,7 @@ LLShaderMgr::LLShaderMgr() { { const std::string dumpdir = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"shader_dump")+gDirUtilp->getDirDelimiter(); - try - { - boost::filesystem::remove_all(dumpdir); - } - catch(const boost::filesystem::filesystem_error& e) - { - llinfos << "boost::filesystem::remove_all(\""+dumpdir+"\") failed: '" + e.code().message() + "'" << llendl; - } + gDirUtilp->deleteDirAndContents(dumpdir); } } @@ -87,7 +80,11 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) { llassert_always(shader != NULL); LLShaderFeatures *features = & shader->mFeatures; - + + if (features->attachNothing) + { + return TRUE; + } ////////////////////////////////////// // Attach Vertex Shader Features First ////////////////////////////////////// @@ -501,27 +498,28 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) //============================================================================ // Load Shader -static std::string get_object_log(GLhandleARB ret) +static std::string get_object_log(GLhandleARB ret, bool isProgram) { std::string res; //get log length GLint length; - glGetObjectParameterivARB(ret, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length); + (isProgram ? glGetProgramiv : glGetShaderiv)(ret, GL_INFO_LOG_LENGTH, &length); + if (length > 0) { //the log could be any size, so allocate appropriately GLcharARB* log = new GLcharARB[length]; - glGetInfoLogARB(ret, length, &length, log); + (isProgram ? glGetProgramInfoLog : glGetShaderInfoLog)(ret, length, &length, log); res = std::string((char *)log); delete[] log; } return res; } -void LLShaderMgr::dumpObjectLog(GLhandleARB ret, BOOL warns) +void LLShaderMgr::dumpObjectLog(GLhandleARB ret, bool isProgram, bool warns) { - std::string log = get_object_log(ret); + std::string log = get_object_log(ret, isProgram); if ( log.length() > 0 ) { if (warns) @@ -535,14 +533,17 @@ void LLShaderMgr::dumpObjectLog(GLhandleARB ret, BOOL warns) } } -GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_level, GLenum type, S32 texture_index_channels) +GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_level, GLenum type, std::map* defines, S32 texture_index_channels) { std::pair::iterator, std::multimap::iterator> range; range = mShaderObjects.equal_range(filename); for (std::multimap::iterator it = range.first; it != range.second;++it) { - if((*it).second.mLevel == shader_level && (*it).second.mType == type) + if((*it).second.mLevel == shader_level && (*it).second.mType == type && (*it).second.mIndexChannels == texture_index_channels && (*it).second.mDefinitions == (defines ? *defines : std::map())) + { + //LL_INFOS("ShaderLoading") << "Loading cached shader for " << filename << LL_ENDL; return (*it).second.mHandle; + } } GLenum error = GL_NO_ERROR; @@ -554,8 +555,8 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade LL_WARNS("ShaderLoading") << "GL ERROR entering loadShaderFile(): " << error << LL_ENDL; } } - - LL_DEBUGS("ShaderLoading") << "Loading shader file: " << filename << " class " << shader_level << LL_ENDL; + + LL_INFOS("ShaderLoading") << "Loading shader file: " << filename << " class " << shader_level << LL_ENDL; if (filename.empty()) { @@ -579,7 +580,7 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade file = LLFile::fopen(fname.str(), "r"); /* Flawfinder: ignore */ if (file) { - LL_INFOS("ShaderLoading") << "Loading file: shaders/class" << gpu_class << "/" << filename << " (Want class " << gpu_class << ")" << LL_ENDL; + //LL_INFOS("ShaderLoading") << "Loading file: shaders/class" << gpu_class << "/" << filename << " (Want class " << gpu_class << ")" << LL_ENDL; break; // done } } @@ -605,82 +606,96 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade { //should NEVER get here -- if major version is 1 and minor version is less than 10, // viewer should never attempt to use shaders, continuing will result in undefined behavior - llerrs << "Unsupported GLSL Version." << llendl; + LL_ERRS() << "Unsupported GLSL Version." << LL_ENDL; } if (minor_version <= 19) { text[count++] = strdup("#version 110\n"); - text[count++] = strdup("#define ATTRIBUTE attribute\n"); - text[count++] = strdup("#define VARYING varying\n"); - text[count++] = strdup("#define VARYING_FLAT varying\n"); } else if (minor_version <= 29) { //set version to 1.20 text[count++] = strdup("#version 120\n"); - text[count++] = strdup("#define FXAA_GLSL_120 1\n"); - text[count++] = strdup("#define FXAA_FAST_PIXEL_OFFSET 0\n"); - text[count++] = strdup("#define ATTRIBUTE attribute\n"); - text[count++] = strdup("#define VARYING varying\n"); - text[count++] = strdup("#define VARYING_FLAT varying\n"); + if (type == GL_FRAGMENT_SHADER_ARB) + { + // Need to enable extensions here instead of in the shader files, + // before any non-preprocessor directives (per spec) + text[count++] = strdup("#extension GL_ARB_shader_texture_lod : enable\n"); + text[count++] = strdup("#define FXAA_GLSL_120 1\n"); + text[count++] = strdup("#define FXAA_FAST_PIXEL_OFFSET 0\n"); + } } + + text[count++] = strdup("#define ATTRIBUTE attribute\n"); + text[count++] = strdup("#define VARYING varying\n"); + text[count++] = strdup("#define VARYING_FLAT varying\n"); } else { if (major_version < 4) { - //set version to 1.30 - text[count++] = strdup("#version 130\n"); - + if (major_version > 1 || minor_version >= 40) + { + //set version to 1.40 + text[count++] = strdup("#version 140\n"); + } + else + { + //set version to 1.30 + text[count++] = strdup("#version 130\n"); + } + if (minor_version == 50 && gGLManager.mHasGpuShader5) + { + // Need to enable extensions here instead of in the shader files, + // before any non-preprocessor directives (per spec) + text[count++] = strdup("#extension GL_ARB_gpu_shader5 : enable\n"); + } //some implementations of GLSL 1.30 require integer precision be explicitly declared text[count++] = strdup("precision mediump int;\n"); text[count++] = strdup("precision highp float;\n"); + if (type == GL_FRAGMENT_SHADER_ARB) + { + text[count++] = strdup("#define FXAA_GLSL_130 1\n"); + } } else { //set version to 400 text[count++] = strdup("#version 400\n"); + if (type == GL_FRAGMENT_SHADER_ARB) + { + text[count++] = strdup("#define FXAA_GLSL_400 1\n"); + } } - text[count++] = strdup("#define DEFINE_GL_FRAGCOLOR 1\n"); - text[count++] = strdup("#define FXAA_GLSL_130 1\n"); - - text[count++] = strdup("#define ATTRIBUTE in\n"); - if (type == GL_VERTEX_SHADER_ARB) { //"varying" state is "out" in a vertex program, "in" in a fragment program // ("varying" is deprecated after version 1.20) + text[count++] = strdup("#define ATTRIBUTE in\n"); text[count++] = strdup("#define VARYING out\n"); text[count++] = strdup("#define VARYING_FLAT flat out\n"); } else { + text[count++] = strdup("#define DEFINE_GL_FRAGCOLOR 1\n"); text[count++] = strdup("#define VARYING in\n"); text[count++] = strdup("#define VARYING_FLAT flat in\n"); - } - - //backwards compatibility with legacy texture lookup syntax - text[count++] = strdup("#define texture2D texture\n"); - text[count++] = strdup("#define textureCube texture\n"); - text[count++] = strdup("#define texture2DLod textureLod\n"); - text[count++] = strdup("#define shadow2D(a,b) vec2(texture(a,b))\n"); - if (major_version > 1 || minor_version >= 40) - { //GLSL 1.40 replaces texture2DRect et al with texture - text[count++] = strdup("#define texture2DRect texture\n"); - text[count++] = strdup("#define shadow2DRect(a,b) vec2(texture(a,b))\n"); + //backwards compatibility with legacy texture lookup syntax + text[count++] = strdup("#define texture2D texture\n"); + text[count++] = strdup("#define textureCube texture\n"); + text[count++] = strdup("#define texture2DLod textureLod\n"); + text[count++] = strdup("#define shadow2D(a,b) vec2(texture(a,b))\n"); } } - static const LLCachedControl SHPackDeferredNormals("SHPackDeferredNormals",false); - if(SHPackDeferredNormals) - text[count++] = strdup("#define PACK_NORMALS\n"); - - //copy preprocessor definitions into buffer - for (std::map::iterator iter = mDefinitions.begin(); iter != mDefinitions.end(); ++iter) + if(defines) { - std::string define = "#define " + iter->first + " " + iter->second + "\n"; - text[count++] = (GLcharARB *) strdup(define.c_str()); + for (std::map::iterator iter = defines->begin(); iter != defines->end(); ++iter) + { + std::string define = "#define " + iter->first + " " + iter->second + "\n"; + text[count++] = (GLcharARB *) strdup(define.c_str()); + } } if (texture_index_channels > 0 && type == GL_FRAGMENT_SHADER_ARB) @@ -718,6 +733,8 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade } */ + text[count++] = strdup("#define HAS_DIFFUSE_LOOKUP 1\n"); + //uniform declartion for (S32 i = 0; i < texture_index_channels; ++i) { @@ -772,9 +789,13 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade else { //should never get here. Indexed texture rendering requires GLSL 1.30 or later // (for passing integers between vertex and fragment shaders) - llerrs << "Indexed texture rendering requires GLSL 1.30 or later." << llendl; + LL_ERRS() << "Indexed texture rendering requires GLSL 1.30 or later." << LL_ENDL; } } + else if( type == GL_FRAGMENT_SHADER_ARB ) + { + text[count++] = strdup("#define HAS_DIFFUSE_LOOKUP 0\n"); + } //copy file into memory while( fgets((char *)buff, 1024, file) != NULL && count < LL_ARRAY_SIZE(text) ) @@ -791,7 +812,7 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade if (error != GL_NO_ERROR) { LL_WARNS("ShaderLoading") << "GL ERROR in glCreateShaderObjectARB: " << error << LL_ENDL; - glDeleteObjectARB(ret); //no longer need handle + glDeleteShader(ret); //no longer need handle ret=0; } } @@ -807,7 +828,7 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade if (error != GL_NO_ERROR) { LL_WARNS("ShaderLoading") << "GL ERROR in glShaderSourceARB: " << error << LL_ENDL; - glDeleteObjectARB(ret); //no longer need handle + glDeleteShader(ret); //no longer need handle ret=0; } } @@ -824,7 +845,7 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade if (error != GL_NO_ERROR) { LL_WARNS("ShaderLoading") << "GL ERROR in glCompileShaderARB: " << error << LL_ENDL; - glDeleteObjectARB(ret); //no longer need handle + glDeleteShader(ret); //no longer need handle ret=0; } } @@ -836,7 +857,7 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade { //check for errors GLint success = GL_TRUE; - glGetObjectParameterivARB(ret, GL_OBJECT_COMPILE_STATUS_ARB, &success); + glGetShaderiv(ret, GL_COMPILE_STATUS, &success); if (gDebugGL || success == GL_FALSE) { error = glGetError(); @@ -844,10 +865,9 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade { //an error occured, print log LL_WARNS("ShaderLoading") << "GLSL Compilation Error: (" << error << ") in " << filename << LL_ENDL; - dumpObjectLog(ret); - error_str = get_object_log(ret); + dumpObjectLog(ret, false); + error_str = get_object_log(ret, false); -#if LL_WINDOWS std::stringstream ostr; //dump shader source for debugging for (GLuint i = 0; i < count; i++) @@ -857,32 +877,20 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade if (i % 128 == 0) { //dump every 128 lines - LL_WARNS("ShaderLoading") << "\n" << ostr.str() << llendl; - ostr = std::stringstream(); + LL_WARNS("ShaderLoading") << "\n" << ostr.str() << LL_ENDL; + ostr.clear(); + ostr.str(LLStringUtil::null); } } - LL_WARNS("ShaderLoading") << "\n" << ostr.str() << llendl; -#else - std::string str; - - for (GLuint i = 0; i < count; i++) { - str.append(text[i]); - - if (i % 128 == 0) - { - LL_WARNS("ShaderLoading") << str << llendl; - str = ""; - } - } -#endif - glDeleteObjectARB(ret); //no longer need handle + LL_WARNS("ShaderLoading") << "\n" << ostr.str() << LL_ENDL; + glDeleteShader(ret); //no longer need handle ret = 0; } } if(ret) - dumpObjectLog(ret,false); + dumpObjectLog(ret, false, false); } static const LLCachedControl dump_raw_shaders("ShyotlDumpRawShaders",false); @@ -923,7 +931,7 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade if (ret) { // Add shader file to map - mShaderObjects.insert(make_pair(filename,CachedObjectInfo(ret,try_gpu_class,type))); + mShaderObjects.insert(make_pair(filename,CachedObjectInfo(ret,try_gpu_class,type, texture_index_channels,defines))); shader_level = try_gpu_class; } else @@ -931,19 +939,76 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade if (shader_level > 1) { shader_level--; - return loadShaderFile(filename,shader_level,type,texture_index_channels); + return loadShaderFile(filename,shader_level,type, defines, texture_index_channels); } LL_WARNS("ShaderLoading") << "Failed to load " << filename << LL_ENDL; } return ret; } +void LLShaderMgr::unloadShaders() +{ + //Instead of manually unloading, shaders are now automatically accumulated in a list. + //Simply iterate and unload. + std::vector &shader_list = LLShaderMgr::getGlobalShaderList(); + for (std::vector::iterator it = shader_list.begin(); it != shader_list.end(); ++it) + (*it)->unload(); + mShaderObjects.clear(); + mProgramObjects.clear(); +} + +void LLShaderMgr::unloadShaderObjects() +{ + std::multimap::iterator it = mShaderObjects.begin(); + for (; it != mShaderObjects.end(); ++it) + if (it->second.mHandle) + glDeleteShader(it->second.mHandle); + mShaderObjects.clear(); + cleanupShaderSources(); +} + +void LLShaderMgr::cleanupShaderSources() +{ + if (!mProgramObjects.empty()) + { + for (auto iter = mProgramObjects.cbegin(), + iter_end = mProgramObjects.cend(); iter != iter_end; ++iter) + { + GLuint program = iter->second; + if (program > 0) + { + GLhandleARB shaders[1024] = {}; + GLsizei count = -1; + glGetAttachedObjectsARB(program, 1024, &count, shaders); + if (count > 0) + { + for (GLsizei i = 0; i < count; ++i) + { + std::multimap::iterator it = mShaderObjects.begin(); + for (; it != mShaderObjects.end(); it++) + { + if ((*it).second.mHandle == shaders[i]) + { + glDetachObjectARB(program, shaders[i]); + break; + } + } + } + } + } + } + + // Clear the linked program list as its no longer needed + mProgramObjects.clear(); + } +} + BOOL LLShaderMgr::linkProgramObject(GLhandleARB obj, BOOL suppress_errors) { //check for errors glLinkProgramARB(obj); GLint success = GL_TRUE; - glGetObjectParameterivARB(obj, GL_OBJECT_LINK_STATUS_ARB, &success); + glGetProgramiv(obj, GL_LINK_STATUS, &success); if (!suppress_errors && success == GL_FALSE) { //an error occured, print log @@ -987,7 +1052,7 @@ BOOL LLShaderMgr::linkProgramObject(GLhandleARB obj, BOOL suppress_errors) } #else - std::string log = get_object_log(obj); + std::string log = get_object_log(obj, true); LLStringUtil::toLower(log); if (log.find("software") != std::string::npos) { @@ -998,7 +1063,7 @@ BOOL LLShaderMgr::linkProgramObject(GLhandleARB obj, BOOL suppress_errors) #endif if (!suppress_errors) { - dumpObjectLog(obj, !success); + dumpObjectLog(obj, true, !success); } return success; @@ -1009,15 +1074,15 @@ BOOL LLShaderMgr::validateProgramObject(GLhandleARB obj) //check program validity against current GL glValidateProgramARB(obj); GLint success = GL_TRUE; - glGetObjectParameterivARB(obj, GL_OBJECT_VALIDATE_STATUS_ARB, &success); + glGetProgramiv(obj, GL_VALIDATE_STATUS, &success); if (success == GL_FALSE) { LL_WARNS("ShaderLoading") << "GLSL program not valid: " << LL_ENDL; - dumpObjectLog(obj); + dumpObjectLog(obj, true); } else { - dumpObjectLog(obj, FALSE); + dumpObjectLog(obj, true, false); } return success; @@ -1035,7 +1100,7 @@ void LLShaderMgr::initAttribsAndUniforms() mReservedAttribs.push_back("texcoord3"); mReservedAttribs.push_back("diffuse_color"); mReservedAttribs.push_back("emissive"); - mReservedAttribs.push_back("binormal"); + mReservedAttribs.push_back("tangent"); mReservedAttribs.push_back("weight"); mReservedAttribs.push_back("weight4"); mReservedAttribs.push_back("clothing"); @@ -1051,9 +1116,9 @@ void LLShaderMgr::initAttribsAndUniforms() mReservedUniforms.push_back("texture_matrix1"); mReservedUniforms.push_back("texture_matrix2"); mReservedUniforms.push_back("texture_matrix3"); - llassert(mReservedUniforms.size() == LLShaderMgr::TEXTURE_MATRIX3+1); - - mReservedUniforms.push_back("viewport"); + mReservedUniforms.push_back("object_plane_s"); + mReservedUniforms.push_back("object_plane_t"); + llassert(mReservedUniforms.size() == LLShaderMgr::OBJECT_PLANE_T+1); mReservedUniforms.push_back("light_position"); mReservedUniforms.push_back("light_direction"); @@ -1089,7 +1154,7 @@ void LLShaderMgr::initAttribsAndUniforms() mReservedUniforms.push_back("specularMap"); mReservedUniforms.push_back("bumpMap"); mReservedUniforms.push_back("environmentMap"); - mReservedUniforms.push_back("cloude_noise_texture"); + mReservedUniforms.push_back("cloud_noise_texture"); mReservedUniforms.push_back("fullbright"); mReservedUniforms.push_back("lightnorm"); mReservedUniforms.push_back("sunlight_color_copy"); @@ -1132,6 +1197,7 @@ void LLShaderMgr::initAttribsAndUniforms() mReservedUniforms.push_back("minimum_alpha"); + mReservedUniforms.push_back("emissive_brightness"); mReservedUniforms.push_back("shadow_matrix"); mReservedUniforms.push_back("env_mat"); @@ -1144,7 +1210,9 @@ void LLShaderMgr::initAttribsAndUniforms() mReservedUniforms.push_back("ssao_factor"); mReservedUniforms.push_back("ssao_factor_inv"); mReservedUniforms.push_back("ssao_effect"); - mReservedUniforms.push_back("screen_res"); + mReservedUniforms.push_back("ssao_scale"); + mReservedUniforms.push_back("kern_scale"); + mReservedUniforms.push_back("noise_scale"); mReservedUniforms.push_back("near_clip"); mReservedUniforms.push_back("shadow_offset"); mReservedUniforms.push_back("shadow_bias"); @@ -1156,10 +1224,10 @@ void LLShaderMgr::initAttribsAndUniforms() mReservedUniforms.push_back("depth_cutoff"); mReservedUniforms.push_back("norm_cutoff"); mReservedUniforms.push_back("shadow_target_width"); + mReservedUniforms.push_back("downsampled_depth_scale"); - llassert(mReservedUniforms.size() == LLShaderMgr::DEFERRED_SHADOW_TARGET_WIDTH+1); + llassert(mReservedUniforms.size() == LLShaderMgr::DEFERRED_DOWNSAMPLED_DEPTH_SCALE+1); - mReservedUniforms.push_back("tc_scale"); mReservedUniforms.push_back("rcp_screen_res"); mReservedUniforms.push_back("rcp_frame_opt"); mReservedUniforms.push_back("rcp_frame_opt2"); @@ -1174,6 +1242,7 @@ void LLShaderMgr::initAttribsAndUniforms() mReservedUniforms.push_back("dof_height"); mReservedUniforms.push_back("depthMap"); + mReservedUniforms.push_back("depthMapDownsampled"); mReservedUniforms.push_back("shadowMap0"); mReservedUniforms.push_back("shadowMap1"); mReservedUniforms.push_back("shadowMap2"); @@ -1192,7 +1261,56 @@ void LLShaderMgr::initAttribsAndUniforms() mReservedUniforms.push_back("lightMap"); mReservedUniforms.push_back("bloomMap"); mReservedUniforms.push_back("projectionMap"); + mReservedUniforms.push_back("norm_mat"); + + mReservedUniforms.push_back("global_gamma"); + mReservedUniforms.push_back("texture_gamma"); + + mReservedUniforms.push_back("specular_color"); + mReservedUniforms.push_back("env_intensity"); + mReservedUniforms.push_back("matrixPalette"); + mReservedUniforms.push_back("translationPalette"); + mReservedUniforms.push_back("maxWeight"); + + mReservedUniforms.push_back("screenTex"); + mReservedUniforms.push_back("screenDepth"); + mReservedUniforms.push_back("refTex"); + mReservedUniforms.push_back("eyeVec"); + mReservedUniforms.push_back("time"); + mReservedUniforms.push_back("d1"); + mReservedUniforms.push_back("d2"); + mReservedUniforms.push_back("lightDir"); + mReservedUniforms.push_back("specular"); + mReservedUniforms.push_back("lightExp"); + mReservedUniforms.push_back("waterFogColor"); + mReservedUniforms.push_back("waterFogDensity"); + mReservedUniforms.push_back("waterFogKS"); + mReservedUniforms.push_back("refScale"); + mReservedUniforms.push_back("waterHeight"); + mReservedUniforms.push_back("waterPlane"); + mReservedUniforms.push_back("normScale"); + mReservedUniforms.push_back("fresnelScale"); + mReservedUniforms.push_back("fresnelOffset"); + mReservedUniforms.push_back("blurMultiplier"); + mReservedUniforms.push_back("sunAngle"); + mReservedUniforms.push_back("scaledAngle"); + mReservedUniforms.push_back("sunAngle2"); + + mReservedUniforms.push_back("camPosLocal"); + + mReservedUniforms.push_back("gWindDir"); + mReservedUniforms.push_back("gSinWaveParams"); + mReservedUniforms.push_back("gGravity"); + + mReservedUniforms.push_back("detail_0"); + mReservedUniforms.push_back("detail_1"); + mReservedUniforms.push_back("detail_2"); + mReservedUniforms.push_back("detail_3"); + mReservedUniforms.push_back("alpha_ramp"); + + mReservedUniforms.push_back("origin"); + mReservedUniforms.push_back("display_gamma"); llassert(mReservedUniforms.size() == END_RESERVED_UNIFORMS); std::set dupe_check; @@ -1201,7 +1319,7 @@ void LLShaderMgr::initAttribsAndUniforms() { if (dupe_check.find(mReservedUniforms[i]) != dupe_check.end()) { - llerrs << "Duplicate reserved uniform name found: " << mReservedUniforms[i] << llendl; + LL_ERRS() << "Duplicate reserved uniform name found: " << mReservedUniforms[i] << LL_ENDL; } dupe_check.insert(mReservedUniforms[i]); } diff --git a/indra/llrender/llshadermgr.h b/indra/llrender/llshadermgr.h index 7e30e75f08..61c949c540 100644 --- a/indra/llrender/llshadermgr.h +++ b/indra/llrender/llshadermgr.h @@ -47,7 +47,8 @@ class LLShaderMgr TEXTURE_MATRIX1, TEXTURE_MATRIX2, TEXTURE_MATRIX3, - VIEWPORT, + OBJECT_PLANE_S, + OBJECT_PLANE_T, LIGHT_POSITION, LIGHT_DIRECTION, LIGHT_ATTENUATION, @@ -109,6 +110,7 @@ class LLShaderMgr GLOW_DELTA, MINIMUM_ALPHA, + EMISSIVE_BRIGHTNESS, DEFERRED_SHADOW_MATRIX, DEFERRED_ENV_MAT, @@ -121,7 +123,9 @@ class LLShaderMgr DEFERRED_SSAO_FACTOR, DEFERRED_SSAO_FACTOR_INV, DEFERRED_SSAO_EFFECT, - DEFERRED_SCREEN_RES, + DEFERRED_SSAO_SCALE, + DEFERRED_KERN_SCALE, + DEFERRED_NOISE_SCALE, DEFERRED_NEAR_CLIP, DEFERRED_SHADOW_OFFSET, DEFERRED_SHADOW_BIAS, @@ -133,8 +137,8 @@ class LLShaderMgr DEFERRED_DEPTH_CUTOFF, DEFERRED_NORM_CUTOFF, DEFERRED_SHADOW_TARGET_WIDTH, + DEFERRED_DOWNSAMPLED_DEPTH_SCALE, - FXAA_TC_SCALE, FXAA_RCP_SCREEN_RES, FXAA_RCP_FRAME_OPT, FXAA_RCP_FRAME_OPT2, @@ -149,6 +153,7 @@ class LLShaderMgr DOF_HEIGHT, DEFERRED_DEPTH, + DEFERRED_DOWNSAMPLED_DEPTH, DEFERRED_SHADOW0, DEFERRED_SHADOW1, DEFERRED_SHADOW2, @@ -164,6 +169,56 @@ class LLShaderMgr DEFERRED_LIGHT, DEFERRED_BLOOM, DEFERRED_PROJECTION, + DEFERRED_NORM_MATRIX, + + GLOBAL_GAMMA, + TEXTURE_GAMMA, + + SPECULAR_COLOR, + ENVIRONMENT_INTENSITY, + + AVATAR_MATRIX, + AVATAR_TRANSLATION, + AVATAR_MAX_WEIGHT, + + WATER_SCREENTEX, + WATER_SCREENDEPTH, + WATER_REFTEX, + WATER_EYEVEC, + WATER_TIME, + WATER_WAVE_DIR1, + WATER_WAVE_DIR2, + WATER_LIGHT_DIR, + WATER_SPECULAR, + WATER_SPECULAR_EXP, + WATER_FOGCOLOR, + WATER_FOGDENSITY, + WATER_FOGKS, + WATER_REFSCALE, + WATER_WATERHEIGHT, + WATER_WATERPLANE, + WATER_NORM_SCALE, + WATER_FRESNEL_SCALE, + WATER_FRESNEL_OFFSET, + WATER_BLUR_MULTIPLIER, + WATER_SUN_ANGLE, + WATER_SCALED_ANGLE, + WATER_SUN_ANGLE2, + + WL_CAMPOSLOCAL, + + AVATAR_WIND, + AVATAR_SINWAVE, + AVATAR_GRAVITY, + + TERRAIN_DETAIL0, + TERRAIN_DETAIL1, + TERRAIN_DETAIL2, + TERRAIN_DETAIL3, + TERRAIN_ALPHARAMP, + + SHINY_ORIGIN, +DISPLAY_GAMMA, END_RESERVED_UNIFORMS } eGLSLReservedUniforms; @@ -173,29 +228,37 @@ class LLShaderMgr virtual void initAttribsAndUniforms(void); BOOL attachShaderFeatures(LLGLSLShader * shader); - void dumpObjectLog(GLhandleARB ret, BOOL warns = TRUE); + void dumpObjectLog(GLhandleARB ret, bool isProgram, bool warns = TRUE); BOOL linkProgramObject(GLhandleARB obj, BOOL suppress_errors = FALSE); BOOL validateProgramObject(GLhandleARB obj); - GLhandleARB loadShaderFile(const std::string& filename, S32 & shader_level, GLenum type, S32 texture_index_channels = -1); + GLhandleARB loadShaderFile(const std::string& filename, S32 & shader_level, GLenum type, std::map* defines = NULL, S32 texture_index_channels = -1); + void unloadShaders(); + void unloadShaderObjects(); // Implemented in the application to actually point to the shader directory. virtual std::string getShaderDirPrefix(void) = 0; // Pure Virtual // Implemented in the application to actually update out of date uniforms for a particular shader virtual void updateShaderUniforms(LLGLSLShader * shader) = 0; // Pure Virtual + virtual bool attachClassSharedShaders(LLGLSLShader& shader, S32 shader_class) = 0; // Pure Virtual public: struct CachedObjectInfo { - CachedObjectInfo(GLhandleARB handle, U32 level, GLenum type) : - mHandle(handle), mLevel(level), mType(type) {} + CachedObjectInfo(GLhandleARB handle, U32 level, GLenum type, U32 texture_index_channels, std::map *definitions) : + mHandle(handle), mLevel(level), mType(type), mIndexChannels(texture_index_channels), mDefinitions(definitions ? *definitions : std::map()){} GLhandleARB mHandle; //Actual handle of the opengl shader object. U32 mLevel; //Level /might/ not be needed, but it's stored to ensure there's no change in behavior. GLenum mType; //GL_VERTEX_SHADER_ARB or GL_FRAGMENT_SHADER_ARB. Tracked because some utility shaders can be loaded as both types (carefully). + U32 mIndexChannels; //LLShaderFeatures::mIndexedTextureChannels + std::map mDefinitions; }; // Map of shader names to compiled std::multimap mShaderObjects; //Singu Note: Packing more info here. Doing such provides capability to skip unneeded duplicate loading.. + // Map of program names linked + std::map mProgramObjects; + //global (reserved slot) shader parameters std::vector mReservedAttribs; @@ -205,6 +268,7 @@ class LLShaderMgr std::map mDefinitions; protected: + void cleanupShaderSources(); // our parameter manager singleton instance static LLShaderMgr * sInstance; diff --git a/indra/llrender/lluiimage.cpp b/indra/llrender/lluiimage.cpp index da122425c5..58478ac520 100644 --- a/indra/llrender/lluiimage.cpp +++ b/indra/llrender/lluiimage.cpp @@ -38,11 +38,9 @@ LLUIImage::LLUIImage(const std::string& name, LLPointer image) mImage(image), mScaleRegion(0.f, 1.f, 1.f, 0.f), mClipRegion(0.f, 1.f, 1.f, 0.f), - mUniformScaling(TRUE), - mNoClip(TRUE), - mImageLoaded(NULL) -{ -} + mImageLoaded(NULL), + mScaleStyle(SCALE_INNER) +{} LLUIImage::~LLUIImage() { @@ -52,44 +50,35 @@ LLUIImage::~LLUIImage() void LLUIImage::setClipRegion(const LLRectf& region) { mClipRegion = region; - mNoClip = mClipRegion.mLeft == 0.f - && mClipRegion.mRight == 1.f - && mClipRegion.mBottom == 0.f - && mClipRegion.mTop == 1.f; } void LLUIImage::setScaleRegion(const LLRectf& region) { mScaleRegion = region; - mUniformScaling = mScaleRegion.mLeft == 0.f - && mScaleRegion.mRight == 1.f - && mScaleRegion.mBottom == 0.f - && mScaleRegion.mTop == 1.f; +} + +void LLUIImage::setScaleStyle(LLUIImage::EScaleStyle style) +{ + mScaleStyle = style; } //TODO: move drawing implementation inside class void LLUIImage::draw(S32 x, S32 y, const LLColor4& color) const { - gl_draw_scaled_image(x, y, getWidth(), getHeight(), mImage, color, mClipRegion); + draw(x, y, getWidth(), getHeight(), color); } void LLUIImage::draw(S32 x, S32 y, S32 width, S32 height, const LLColor4& color) const { - if (mUniformScaling) - { - gl_draw_scaled_image(x, y, width, height, mImage, color, mClipRegion); - } - else - { - gl_draw_scaled_image_with_border( - x, y, - width, height, - mImage, - color, - FALSE, - mClipRegion, - mScaleRegion); - } + gl_draw_scaled_image_with_border( + x, y, + width, height, + mImage, + color, + FALSE, + mClipRegion, + mScaleRegion, + mScaleStyle == SCALE_INNER); } void LLUIImage::drawSolid(S32 x, S32 y, S32 width, S32 height, const LLColor4& color) const @@ -101,7 +90,8 @@ void LLUIImage::drawSolid(S32 x, S32 y, S32 width, S32 height, const LLColor4& c color, TRUE, mClipRegion, - mScaleRegion); + mScaleRegion, + mScaleStyle == SCALE_INNER); } void LLUIImage::drawBorder(S32 x, S32 y, S32 width, S32 height, const LLColor4& color, S32 border_width) const @@ -112,16 +102,60 @@ void LLUIImage::drawBorder(S32 x, S32 y, S32 width, S32 height, const LLColor4& drawSolid(border_rect, color); } +void LLUIImage::draw3D(const LLVector3& origin_agent, const LLVector3& x_axis, const LLVector3& y_axis, + const LLRect& rect, const LLColor4& color) +{ + F32 border_scale = 1.f; + F32 border_height = (1.f - mScaleRegion.getHeight()) * getHeight(); + F32 border_width = (1.f - mScaleRegion.getWidth()) * getWidth(); + if (rect.getHeight() < border_height || rect.getWidth() < border_width) + { + if(border_height - rect.getHeight() > border_width - rect.getWidth()) + { + border_scale = (F32)rect.getHeight() / border_height; + } + else + { + border_scale = (F32)rect.getWidth() / border_width; + } + } + + LLRender2D::pushMatrix(); + { + LLVector3 rect_origin = origin_agent + (rect.mLeft * x_axis) + (rect.mBottom * y_axis); + LLRender2D::translate(rect_origin.mV[VX], + rect_origin.mV[VY], + rect_origin.mV[VZ]); + gGL.getTexUnit(0)->bind(getImage()); + gGL.color4fv(color.mV); + + LLRectf center_uv_rect(mClipRegion.mLeft + mScaleRegion.mLeft * mClipRegion.getWidth(), + mClipRegion.mBottom + mScaleRegion.mTop * mClipRegion.getHeight(), + mClipRegion.mLeft + mScaleRegion.mRight * mClipRegion.getWidth(), + mClipRegion.mBottom + mScaleRegion.mBottom * mClipRegion.getHeight()); + gl_segmented_rect_3d_tex(mClipRegion, + center_uv_rect, + LLRectf(border_width * border_scale * 0.5f / (F32)rect.getWidth(), + (rect.getHeight() - (border_height * border_scale * 0.5f)) / (F32)rect.getHeight(), + (rect.getWidth() - (border_width * border_scale * 0.5f)) / (F32)rect.getWidth(), + (border_height * border_scale * 0.5f) / (F32)rect.getHeight()), + rect.getWidth() * x_axis, + rect.getHeight() * y_axis); + + } LLRender2D::popMatrix(); +} + + S32 LLUIImage::getWidth() const { // return clipped dimensions of actual image area - return llround((F32)mImage->getWidth(0) * mClipRegion.getWidth()); + return ll_pos_round((F32)mImage->getWidth(0) * mClipRegion.getWidth()); } S32 LLUIImage::getHeight() const { // return clipped dimensions of actual image area - return llround((F32)mImage->getHeight(0) * mClipRegion.getHeight()); + return ll_pos_round((F32)mImage->getHeight(0) * mClipRegion.getHeight()); } S32 LLUIImage::getTextureWidth() const @@ -152,3 +186,48 @@ void LLUIImage::onImageLoaded() } } + +namespace LLInitParam +{ + void ParamValue::updateValueFromBlock() + { + // The keyword "none" is specifically requesting a null image + // do not default to current value. Used to overwrite template images. + if (name() == "none") + { + updateValue(NULL); + return; + } + + LLUIImage* imagep = LLRender2D::getUIImage(name()); + if (imagep) + { + updateValue(imagep); + } + } + + void ParamValue::updateBlockFromValue(bool make_block_authoritative) + { + if (getValue() == NULL) + { + name.set("none", make_block_authoritative); + } + else + { + name.set(getValue()->getName(), make_block_authoritative); + } + } + + + bool ParamCompare::equals( + LLUIImage* const &a, + LLUIImage* const &b) + { + // force all LLUIImages for XML UI export to be "non-default" + if (!a && !b) + return false; + else + return (a == b); + } +} + diff --git a/indra/llrender/lluiimage.h b/indra/llrender/lluiimage.h index 45af03272a..939f78d65d 100644 --- a/indra/llrender/lluiimage.h +++ b/indra/llrender/lluiimage.h @@ -32,8 +32,12 @@ #include "llrefcount.h" #include "llrefcount.h" #include "llrect.h" +#ifndef BOOST_FUNCTION_HPP_INCLUDED #include +#define BOOST_FUNCTION_HPP_INCLUDED +#endif #include +#include "llinitparam.h" #include "lltexture.h" extern const LLColor4 UI_VERTEX_COLOR; @@ -41,6 +45,12 @@ extern const LLColor4 UI_VERTEX_COLOR; class LLUIImage : public LLRefCount { public: + enum EScaleStyle + { + SCALE_INNER, + SCALE_OUTER + }; + typedef boost::signals2::signal image_loaded_signal_t; LLUIImage(const std::string& name, LLPointer image); @@ -48,6 +58,7 @@ class LLUIImage : public LLRefCount void setClipRegion(const LLRectf& region); void setScaleRegion(const LLRectf& region); + void setScaleStyle(EScaleStyle style); LLPointer getImage() { return mImage; } const LLPointer& getImage() const { return mImage; } @@ -63,7 +74,9 @@ class LLUIImage : public LLRefCount void drawBorder(S32 x, S32 y, S32 width, S32 height, const LLColor4& color, S32 border_width) const; void drawBorder(const LLRect& rect, const LLColor4& color, S32 border_width) const { drawBorder(rect.mLeft, rect.mBottom, rect.getWidth(), rect.getHeight(), color, border_width); } void drawBorder(S32 x, S32 y, const LLColor4& color, S32 border_width) const { drawBorder(x, y, getWidth(), getHeight(), color, border_width); } - + + void draw3D(const LLVector3& origin_agent, const LLVector3& x_axis, const LLVector3& y_axis, const LLRect& rect, const LLColor4& color); + const std::string& getName() const { return mName; } virtual S32 getWidth() const; @@ -80,14 +93,43 @@ class LLUIImage : public LLRefCount protected: image_loaded_signal_t* mImageLoaded; - std::string mName; - LLRectf mScaleRegion; - LLRectf mClipRegion; - LLPointer mImage; - BOOL mUniformScaling; - BOOL mNoClip; + std::string mName; + LLRectf mScaleRegion; + LLRectf mClipRegion; + LLPointer mImage; + EScaleStyle mScaleStyle; }; +namespace LLInitParam +{ + template<> + class ParamValue + : public CustomParamValue + { + typedef boost::add_reference::type>::type T_const_ref; + typedef CustomParamValue super_t; + public: + Optional name; + + ParamValue(LLUIImage* const& image = NULL) + : super_t(image) + { + updateBlockFromValue(false); + addSynonym(name, "name"); + } + + void updateValueFromBlock(); + void updateBlockFromValue(bool make_block_authoritative); + }; + + // Need custom comparison function for our test app, which only loads + // LLUIImage* as NULL. + template<> + struct ParamCompare + { + static bool equals(LLUIImage* const &a, LLUIImage* const &b); + }; +} typedef LLPointer LLUIImagePtr; #endif diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index 67c271a0e5..f766af31b8 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -74,10 +74,10 @@ U32 vbo_block_size(U32 size) U32 vbo_block_index(U32 size) { - return vbo_block_size(size)/LL_VBO_BLOCK_SIZE; + return ((vbo_block_size(size)-1)/LL_VBO_BLOCK_SIZE); } -const U32 LL_VBO_POOL_SEED_COUNT = vbo_block_index(LL_VBO_POOL_MAX_SEED_SIZE); +const U32 LL_VBO_POOL_SEED_COUNT = vbo_block_index(LL_VBO_POOL_MAX_SEED_SIZE)+1; //============================================================================ @@ -88,17 +88,16 @@ LLVBOPool LLVertexBuffer::sDynamicVBOPool(GL_DYNAMIC_DRAW_ARB, GL_ARRAY_BUFFER_A LLVBOPool LLVertexBuffer::sStreamIBOPool(GL_STREAM_DRAW_ARB, GL_ELEMENT_ARRAY_BUFFER_ARB); LLVBOPool LLVertexBuffer::sDynamicIBOPool(GL_DYNAMIC_DRAW_ARB, GL_ELEMENT_ARRAY_BUFFER_ARB); -U32 LLVBOPool::sBytesPooled = 0; -U32 LLVBOPool::sIndexBytesPooled = 0; -U32 LLVBOPool::sCurGLName = 1; +U64 LLVBOPool::sBytesPooled = 0; +U64 LLVBOPool::sIndexBytesPooled = 0; +std::vector LLVBOPool::sPendingDeletions; -std::list LLVertexBuffer::sAvailableVAOName; +std::vector LLVertexBuffer::sAvailableVAOName; U32 LLVertexBuffer::sCurVAOName = 1; -U32 LLVertexBuffer::sAllocatedIndexBytes = 0; +U64 LLVertexBuffer::sAllocatedIndexBytes = 0; U32 LLVertexBuffer::sIndexCount = 0; -LLPrivateMemoryPool* LLVertexBuffer::sPrivatePoolp = NULL; U32 LLVertexBuffer::sBindCount = 0; U32 LLVertexBuffer::sSetCount = 0; S32 LLVertexBuffer::sCount = 0; @@ -112,28 +111,84 @@ U32 LLVertexBuffer::sGLRenderIndices = 0; U32 LLVertexBuffer::sLastMask = 0; bool LLVertexBuffer::sVBOActive = false; bool LLVertexBuffer::sIBOActive = false; -U32 LLVertexBuffer::sAllocatedBytes = 0; +U64 LLVertexBuffer::sAllocatedBytes = 0; U32 LLVertexBuffer::sVertexCount = 0; bool LLVertexBuffer::sMapped = false; bool LLVertexBuffer::sUseStreamDraw = true; bool LLVertexBuffer::sUseVAO = false; bool LLVertexBuffer::sPreferStreamDraw = false; +LLVertexBuffer* LLVertexBuffer::sUtilityBuffer = nullptr; +static std::vector sActiveBufferNames; +static std::vector sDeletedBufferNames; -U32 LLVBOPool::genBuffer() +/*void validate_add_buffer(U32 name) { - U32 ret = 0; + auto found = std::find(sActiveBufferNames.begin(), sActiveBufferNames.end(), name); + if (found != sActiveBufferNames.end()) + { + LL_ERRS() << "Allocating allocated buffer name " << name << LL_ENDL; + } + else + { + //LL_INFOS() << "Allocated buffer name " << name << LL_ENDL; + sActiveBufferNames.push_back(name); + } +} - if (mGLNamePool.empty()) +void validate_del_buffer(U32 name) +{ + auto found = std::find(sActiveBufferNames.begin(), sActiveBufferNames.end(), name); + if (found == sActiveBufferNames.end()) { - ret = sCurGLName++; + if (std::find(sDeletedBufferNames.begin(), sDeletedBufferNames.end(), name) == sDeletedBufferNames.end()) + { + LL_ERRS() << "Deleting unknown buffer name " << name << LL_ENDL; + } + else + { + LL_ERRS() << "Deleting deleted buffer name " << name << LL_ENDL; + } } else { - ret = mGLNamePool.front(); - mGLNamePool.pop_front(); + //LL_INFOS() << "Deleted buffer name " << name << LL_ENDL; + sActiveBufferNames.erase(found); + sDeletedBufferNames.push_back(name); + } +} + +void validate_bind_buffer(U32 name) +{ + auto found = std::find(sActiveBufferNames.begin(), sActiveBufferNames.end(), name); + if (found == sActiveBufferNames.end()) + { + if (std::find(sDeletedBufferNames.begin(), sDeletedBufferNames.end(), name) == sDeletedBufferNames.end()) + { + LL_ERRS() << "Binding unknown buffer name " << name << LL_ENDL; + } + else + { + LL_ERRS() << "Binding deleted buffer name " << name << LL_ENDL; + } } +} +void clean_validate_buffers() +{ + LL_INFOS() << "Clearing active buffer names. Count " << sActiveBufferNames.size() << LL_ENDL; + sActiveBufferNames.clear(); + LL_INFOS() << "Clearing deleted buffer names. Count " << sDeletedBufferNames.size() << LL_ENDL; + sDeletedBufferNames.clear(); +}*/ + +U32 LLVBOPool::genBuffer() +{ + U32 ret = 0; + + glGenBuffersARB(1, &ret); + //validate_add_buffer(ret); + return ret; } @@ -141,16 +196,20 @@ void LLVBOPool::deleteBuffer(U32 name) { if (gGLManager.mInited) { - LLVertexBuffer::unbind(); - - glBindBufferARB(mType, name); - glBufferDataARB(mType, 0, NULL, mUsage); + //LLVertexBuffer::unbind(); - llassert(std::find(mGLNamePool.begin(), mGLNamePool.end(), name) == mGLNamePool.end()); + //validate_bind_buffer(name); + //glBindBufferARB(mType, name); + //glBufferDataARB(mType, 0, nullptr, mUsage); + //glBindBufferARB(mType, 0); - mGLNamePool.push_back(name); - - glBindBufferARB(mType, 0); + //validate_del_buffer(name); + if (LLVertexBuffer::sGLRenderBuffer == name) { + //LLVertexBuffer::sGLRenderBuffer = 0; + LLVertexBuffer::unbind(); + } + sPendingDeletions.emplace_back(name); + //glDeleteBuffersARB(1, &name); } } @@ -162,11 +221,11 @@ LLVBOPool::LLVBOPool(U32 vboUsage, U32 vboType) std::fill(mMissCount.begin(), mMissCount.end(), 0); } -volatile U8* LLVBOPool::allocate(U32& name, U32 size, bool for_seed) +volatile U8* LLVBOPool::allocate(U32& name, U32 size, U32 seed) { llassert(vbo_block_size(size) == size); - volatile U8* ret = NULL; + volatile U8* ret = nullptr; U32 i = vbo_block_index(size); @@ -175,16 +234,17 @@ volatile U8* LLVBOPool::allocate(U32& name, U32 size, bool for_seed) mFreeList.resize(i+1); } - if (mFreeList[i].empty() || for_seed) + if (mFreeList[i].empty() || seed) { //make a new buffer - name = genBuffer(); - + name = seed > 0 ? seed : genBuffer(); + + //validate_bind_buffer(name); glBindBufferARB(mType, name); - if (!for_seed && i < LL_VBO_POOL_SEED_COUNT) + if (!seed && i < LL_VBO_POOL_SEED_COUNT) { //record this miss - mMissCount[i]++; + mMissCount[i]++; } if (mType == GL_ARRAY_BUFFER_ARB) @@ -198,17 +258,20 @@ volatile U8* LLVBOPool::allocate(U32& name, U32 size, bool for_seed) if (LLVertexBuffer::sDisableVBOMapping || mUsage != GL_DYNAMIC_DRAW_ARB) { - glBufferDataARB(mType, size, 0, mUsage); - ret = (U8*) ll_aligned_malloc_16(size); + glBufferDataARB(mType, size, nullptr, mUsage); + ret = (U8*)ll_aligned_malloc<64>(size); } else { //always use a true hint of static draw when allocating non-client-backed buffers - glBufferDataARB(mType, size, 0, GL_STATIC_DRAW_ARB); + glBufferDataARB(mType, size, nullptr, GL_STATIC_DRAW_ARB); } - glBindBufferARB(mType, 0); + if (!seed) + { + glBindBufferARB(mType, 0); + } - if (for_seed) + if (seed) { //put into pool for future use llassert(mFreeList.size() > i); @@ -218,11 +281,11 @@ volatile U8* LLVBOPool::allocate(U32& name, U32 size, bool for_seed) if (mType == GL_ARRAY_BUFFER_ARB) { - sBytesPooled += size; - } - else - { - sIndexBytesPooled += size; + sBytesPooled += size; + } + else + { + sIndexBytesPooled += size; } mFreeList[i].push_back(rec); } @@ -252,7 +315,7 @@ void LLVBOPool::release(U32 name, volatile U8* buffer, U32 size) llassert(vbo_block_size(size) == size); deleteBuffer(name); - ll_aligned_free_16((U8*) buffer); + ll_aligned_free<64>((U8*) buffer); if (mType == GL_ARRAY_BUFFER_ARB) { @@ -273,22 +336,45 @@ void LLVBOPool::seedPool() mFreeList.resize(LL_VBO_POOL_SEED_COUNT); } + static std::vector< U32 > sizes; for (U32 i = 0; i < LL_VBO_POOL_SEED_COUNT; i++) { if (mMissCount[i] > mFreeList[i].size()) - { - U32 size = i*LL_VBO_BLOCK_SIZE; - + { + U32 size = i * LL_VBO_BLOCK_SIZE + LL_VBO_BLOCK_SIZE; + S32 count = mMissCount[i] - mFreeList[i].size(); for (S32 j = 0; j < count; ++j) { - allocate(dummy_name, size, true); + sizes.push_back(size); } } } -} + if (!sizes.empty()) + { + const U32 len = sizes.size(); + U32* names = new U32[len]; + glGenBuffersARB(len, names); + for (U32 i = 0; i < len; ++i) + { + allocate(dummy_name, sizes[i], names[i]); + } + delete[] names; + glBindBufferARB(mType, 0); + } + sizes.clear(); +} + +void LLVBOPool::deleteReleasedBuffers() +{ + if (!sPendingDeletions.empty()) + { + glDeleteBuffersARB(sPendingDeletions.size(), sPendingDeletions.data()); + sPendingDeletions.clear(); + } +} void LLVBOPool::cleanup() { @@ -306,7 +392,7 @@ void LLVBOPool::cleanup() if (r.mClientData) { - ll_aligned_free_16((void*) r.mClientData); + ll_aligned_free<64>((void*) r.mClientData); } l.pop_front(); @@ -328,6 +414,7 @@ void LLVBOPool::cleanup() //reset miss counts std::fill(mMissCount.begin(), mMissCount.end(), 0); + deleteReleasedBuffers(); } @@ -342,13 +429,39 @@ S32 LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_MAX] = sizeof(LLVector2), // TYPE_TEXCOORD3, sizeof(LLColor4U), // TYPE_COLOR, sizeof(LLColor4U), // TYPE_EMISSIVE, only alpha is used currently - sizeof(LLVector4), // TYPE_BINORMAL, + sizeof(LLVector4), // TYPE_TANGENT, sizeof(F32), // TYPE_WEIGHT, sizeof(LLVector4), // TYPE_WEIGHT4, sizeof(LLVector4), // TYPE_CLOTHWEIGHT, sizeof(LLVector4), // TYPE_TEXTURE_INDEX (actually exists as position.w), no extra data, but stride is 16 bytes }; +static std::string vb_type_name[] = +{ + "TYPE_VERTEX", + "TYPE_NORMAL", + "TYPE_TEXCOORD0", + "TYPE_TEXCOORD1", + "TYPE_TEXCOORD2", + "TYPE_TEXCOORD3", + "TYPE_COLOR", + "TYPE_EMISSIVE", + "TYPE_TANGENT", + "TYPE_WEIGHT", + "TYPE_WEIGHT4", + "TYPE_CLOTHWEIGHT", + "TYPE_TEXTURE_INDEX", + "TYPE_MAX", + "TYPE_INDEX", +}; + +// static +const std::string& LLVertexBuffer::getTypeName(U8 i) +{ + llassert_always(i < (U8)(sizeof(vb_type_name) / sizeof(std::string))); + return vb_type_name[i]; +} + U32 LLVertexBuffer::sGLMode[LLRender::NUM_MODES] = { GL_TRIANGLES, @@ -357,7 +470,6 @@ U32 LLVertexBuffer::sGLMode[LLRender::NUM_MODES] = GL_POINTS, GL_LINES, GL_LINE_STRIP, - GL_QUADS, GL_LINE_LOOP, }; @@ -368,8 +480,8 @@ U32 LLVertexBuffer::getVAOName() if (!sAvailableVAOName.empty()) { - ret = sAvailableVAOName.front(); - sAvailableVAOName.pop_front(); + ret = sAvailableVAOName.back(); + sAvailableVAOName.pop_back(); } else { @@ -436,7 +548,7 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask) else { - GLenum array[] = + static const GLenum array[] = { GL_VERTEX_ARRAY, GL_NORMAL_ARRAY, @@ -444,7 +556,7 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask) GL_COLOR_ARRAY, }; - GLenum mask[] = + static const GLenum mask[] = { MAP_VERTEX, MAP_NORMAL, @@ -472,7 +584,7 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask) } else { - llerrs << "Bad client state! " << array[i] << " disabled." << llendl; + LL_ERRS() << "Bad client state! " << array[i] << " disabled." << LL_ENDL; } } } @@ -491,7 +603,7 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask) } else { - llerrs << "Bad client state! " << array[i] << " enabled." << llendl; + LL_ERRS() << "Bad client state! " << array[i] << " enabled." << LL_ENDL; } } } @@ -523,16 +635,16 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask) } } - if (sLastMask & MAP_BINORMAL) + if (sLastMask & MAP_TANGENT) { - if (!(data_mask & MAP_BINORMAL)) + if (!(data_mask & MAP_TANGENT)) { glClientActiveTextureARB(GL_TEXTURE2_ARB); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glClientActiveTextureARB(GL_TEXTURE0_ARB); } } - else if (data_mask & MAP_BINORMAL) + else if (data_mask & MAP_TANGENT) { glClientActiveTextureARB(GL_TEXTURE2_ARB); glEnableClientState(GL_TEXTURE_COORD_ARRAY); @@ -551,85 +663,96 @@ void LLVertexBuffer::drawArrays(U32 mode, const std::vector& pos, con gGL.syncMatrices(); U32 count = pos.size(); - + llassert(norm.size() >= pos.size()); llassert(count > 0); - if( count == 0 ) + if (count == 0) { - llwarns << "Called drawArrays with 0 vertices" << llendl; + LL_WARNS() << "Called drawArrays with 0 vertices" << LL_ENDL; return; } - if( norm.size() < pos.size() ) + if (norm.size() < pos.size()) { - llwarns << "Called drawArrays with #" << norm.size() << " normals and #" << pos.size() << " vertices" << llendl; + LL_WARNS() << "Called drawArrays with #" << norm.size() << " normals and #" << pos.size() << " vertices" << LL_ENDL; return; } - unbind(); - - setupClientArrays(MAP_VERTEX | MAP_NORMAL); - - LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; - - if (shader) + if (!sUtilityBuffer) { - S32 loc = LLVertexBuffer::TYPE_VERTEX; - if (loc > -1) - { - glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, 0, pos[0].mV); - } - loc = LLVertexBuffer::TYPE_NORMAL; - if (loc > -1) - { - glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, 0, norm[0].mV); - } + sUtilityBuffer = new LLVertexBuffer(MAP_VERTEX | MAP_NORMAL | MAP_TEXCOORD0, GL_STREAM_DRAW); + sUtilityBuffer->allocateBuffer(count, count, true); } - else + if (sUtilityBuffer->getNumVerts() < (S32)count) { - glVertexPointer(3, GL_FLOAT, 0, pos[0].mV); - glNormalPointer(GL_FLOAT, 0, norm[0].mV); + sUtilityBuffer->resizeBuffer(count, count); } - glDrawArrays(sGLMode[mode], 0, count); + LLStrider vertex_strider; + LLStrider normal_strider; + sUtilityBuffer->getVertexStrider(vertex_strider); + sUtilityBuffer->getNormalStrider(normal_strider); + for (U32 i = 0; i < count; ++i) + { + *(vertex_strider++) = pos[i]; + *(normal_strider++) = norm[i]; + } + + sUtilityBuffer->setBuffer(MAP_VERTEX | MAP_NORMAL); + sUtilityBuffer->drawArrays(mode, 0, pos.size()); } //static -void LLVertexBuffer::drawElements(U32 mode, const LLVector4a* pos, const LLVector2* tc, S32 num_indices, const U16* indicesp) +void LLVertexBuffer::drawElements(U32 mode, const S32 num_vertices, const LLVector4a* pos, const LLVector2* tc, S32 num_indices, const U16* indicesp) { llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL); - gGL.syncMatrices(); + if (num_vertices <= 0) + { + LL_WARNS() << "Called drawElements with 0 vertices" << LL_ENDL; + return; + } - U32 mask = LLVertexBuffer::MAP_VERTEX; - if (tc) + if (num_indices <= 0) { - mask = mask | LLVertexBuffer::MAP_TEXCOORD0; + LL_WARNS() << "Called drawElements with 0 indices" << LL_ENDL; + return; } - unbind(); - - setupClientArrays(mask); + gGL.syncMatrices(); - if (LLGLSLShader::sNoFixedFunction) + if (!sUtilityBuffer) { - S32 loc = LLVertexBuffer::TYPE_VERTEX; - glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, 16, pos); - - if (tc) - { - loc = LLVertexBuffer::TYPE_TEXCOORD0; - glVertexAttribPointerARB(loc, 2, GL_FLOAT, GL_FALSE, 0, tc); - } + sUtilityBuffer = new LLVertexBuffer(MAP_VERTEX | MAP_NORMAL | MAP_TEXCOORD0, GL_STREAM_DRAW); + sUtilityBuffer->allocateBuffer(num_vertices, num_indices, true); } - else + if (sUtilityBuffer->getNumVerts() < num_vertices || sUtilityBuffer->getNumIndices() < num_indices) { - glTexCoordPointer(2, GL_FLOAT, 0, tc); - glVertexPointer(3, GL_FLOAT, 16, pos); + sUtilityBuffer->resizeBuffer(llmax(sUtilityBuffer->getNumVerts(), num_vertices), llmax(sUtilityBuffer->getNumIndices(), num_indices)); } - glDrawElements(sGLMode[mode], num_indices, GL_UNSIGNED_SHORT, indicesp); + U32 mask = LLVertexBuffer::MAP_VERTEX; + + LLStrider index_strider; + LLStrider vertex_strider; + sUtilityBuffer->getIndexStrider(index_strider); + sUtilityBuffer->getVertexStrider(vertex_strider); + const S32 index_size = ((num_indices * sizeof(U16)) + 0xF) & ~0xF; + const S32 vertex_size = ((num_vertices * 4 * sizeof(F32)) + 0xF) & ~0xF; + LLVector4a::memcpyNonAliased16((F32*)index_strider.get(), (F32*)indicesp, index_size); + LLVector4a::memcpyNonAliased16((F32*)vertex_strider.get(), (F32*)pos, vertex_size); + if (tc) + { + mask = mask | LLVertexBuffer::MAP_TEXCOORD0; + LLStrider tc_strider; + sUtilityBuffer->getTexCoord0Strider(tc_strider); + const S32 tc_size = ((num_vertices * 2 * sizeof(F32)) + 0xF) & ~0xF; + LLVector4a::memcpyNonAliased16((F32*)tc_strider.get(), (F32*)tc, tc_size); + } + + sUtilityBuffer->setBuffer(mask); + sUtilityBuffer->draw(mode, num_indices, 0); } void LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_offset) const @@ -637,7 +760,7 @@ void LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_of if (start >= (U32) mNumVerts || end >= (U32) mNumVerts) { - llerrs << "Bad vertex buffer draw range: [" << start << ", " << end << "] vs " << mNumVerts << llendl; + LL_ERRS() << "Bad vertex buffer draw range: [" << start << ", " << end << "] vs " << mNumVerts << LL_ENDL; } llassert(mNumIndices >= 0); @@ -645,7 +768,7 @@ void LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_of if (indices_offset >= (U32) mNumIndices || indices_offset + count > (U32) mNumIndices) { - llerrs << "Bad index buffer draw range: [" << indices_offset << ", " << indices_offset+count << "]" << llendl; + LL_ERRS() << "Bad index buffer draw range: [" << indices_offset << ", " << indices_offset + count << "]" << LL_ENDL; } if (gDebugGL && !useVBOs()) @@ -655,7 +778,7 @@ void LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_of { if (idx[i] < start || idx[i] > end) { - llerrs << "Index out of range: " << idx[i] << " not in [" << start << ", " << end << "]" << llendl; + LL_ERRS() << "Index out of range: " << idx[i] << " not in [" << start << ", " << end << "]" << LL_ENDL; } } @@ -673,7 +796,7 @@ void LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_of S32 idx = (S32) (v[i][3]+0.25f); if (idx < 0 || idx >= shader->mFeatures.mIndexedTextureChannels) { - llerrs << "Bad texture index found in vertex data stream." << llendl; + LL_ERRS() << "Bad texture index found in vertex data stream." << LL_ENDL; } } } @@ -693,19 +816,19 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi { if (mGLArray != sGLRenderArray) { - llerrs << "Wrong vertex array bound." << llendl; + LL_ERRS() << "Wrong vertex array bound." << LL_ENDL; } } else { if (mGLIndices != sGLRenderIndices) { - llerrs << "Wrong index buffer bound." << llendl; + LL_ERRS() << "Wrong index buffer bound." << LL_ENDL; } if (mGLBuffer != sGLRenderBuffer) { - llerrs << "Wrong vertex buffer bound." << llendl; + LL_ERRS() << "Wrong vertex buffer bound." << LL_ENDL; } } @@ -716,13 +839,13 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi if (elem != mGLIndices) { - llerrs << "Wrong index buffer bound!" << llendl; + LL_ERRS() << "Wrong index buffer bound!" << LL_ENDL; } } if (mode >= LLRender::NUM_MODES) { - llerrs << "Invalid draw mode: " << mode << llendl; + LL_ERRS() << "Invalid draw mode: " << mode << LL_ENDL; return; } @@ -745,32 +868,32 @@ void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const if (indices_offset >= (U32) mNumIndices || indices_offset + count > (U32) mNumIndices) { - llerrs << "Bad index buffer draw range: [" << indices_offset << ", " << indices_offset+count << "]" << llendl; + LL_ERRS() << "Bad index buffer draw range: [" << indices_offset << ", " << indices_offset + count << "]" << LL_ENDL; } if (mGLArray) { if (mGLArray != sGLRenderArray) { - llerrs << "Wrong vertex array bound." << llendl; + LL_ERRS() << "Wrong vertex array bound." << LL_ENDL; } } else { if (mGLIndices != sGLRenderIndices) { - llerrs << "Wrong index buffer bound." << llendl; + LL_ERRS() << "Wrong index buffer bound." << LL_ENDL; } if (mGLBuffer != sGLRenderBuffer) { - llerrs << "Wrong vertex buffer bound." << llendl; + LL_ERRS() << "Wrong vertex buffer bound." << LL_ENDL; } } if (mode >= LLRender::NUM_MODES) { - llerrs << "Invalid draw mode: " << mode << llendl; + LL_ERRS() << "Invalid draw mode: " << mode << LL_ENDL; return; } @@ -781,7 +904,7 @@ void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const placeFence(); } -static LLFastTimer::DeclareTimer FTM_GL_DRAW_ARRAYS("GL draw arrays"); +static LLTrace::BlockTimerStatHandle FTM_GL_DRAW_ARRAYS("GL draw arrays"); void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const { llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL); @@ -792,32 +915,32 @@ void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const if (first >= (U32) mNumVerts || first + count > (U32) mNumVerts) { - llerrs << "Bad vertex buffer draw range: [" << first << ", " << first+count << "]" << llendl; + LL_ERRS() << "Bad vertex buffer draw range: [" << first << ", " << first+count << "]" << LL_ENDL; } if (mGLArray) { if (mGLArray != sGLRenderArray) { - llerrs << "Wrong vertex array bound." << llendl; + LL_ERRS() << "Wrong vertex array bound." << LL_ENDL; } } else { if (mGLBuffer != sGLRenderBuffer || useVBOs() != sVBOActive) { - llerrs << "Wrong vertex buffer bound." << llendl; + LL_ERRS() << "Wrong vertex buffer bound." << LL_ENDL; } } if (mode >= LLRender::NUM_MODES) { - llerrs << "Invalid draw mode: " << mode << llendl; + LL_ERRS() << "Invalid draw mode: " << mode << LL_ENDL; return; } { - LLFastTimer t2(FTM_GL_DRAW_ARRAYS); + //LL_RECORD_BLOCK_TIME(FTM_GL_DRAW_ARRAYS); stop_glerror(); glDrawArrays(sGLMode[mode], first, count); } @@ -829,12 +952,7 @@ void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const void LLVertexBuffer::initClass(bool use_vbo, bool no_vbo_mapping) { sEnableVBOs = use_vbo && gGLManager.mHasVertexBufferObject; - sDisableVBOMapping = sEnableVBOs;// && no_vbo_mapping; //Temporary workaround for vbo mapping being straight up broken - - if (!sPrivatePoolp) - { - sPrivatePoolp = LLPrivateMemoryPoolManager::getInstance()->newPool(LLPrivateMemoryPool::STATIC); - } + sDisableVBOMapping = sEnableVBOs;// && no_vbo_mapping; } //static @@ -876,12 +994,17 @@ void LLVertexBuffer::cleanupClass() sDynamicIBOPool.cleanup(); sStreamVBOPool.cleanup(); sDynamicVBOPool.cleanup(); + //clean_validate_buffers(); - if(sPrivatePoolp) + if (!sAvailableVAOName.empty()) { - LLPrivateMemoryPoolManager::getInstance()->deletePool(sPrivatePoolp); - sPrivatePoolp = NULL; + glDeleteVertexArrays(sAvailableVAOName.size(), sAvailableVAOName.data()); + sAvailableVAOName.clear(); } + sLastMask = 0; + + delete sUtilityBuffer; + sUtilityBuffer = nullptr; } //---------------------------------------------------------------------------- @@ -933,14 +1056,16 @@ LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) : mAlignedOffset(0), mAlignedIndexOffset(0), mSize(0), + mResidentSize(0), mIndicesSize(0), + mResidentIndicesSize(0), mTypeMask(typemask), mUsage(LLVertexBuffer::determineUsage(usage)), mGLBuffer(0), mGLIndices(0), mGLArray(0), - mMappedData(NULL), - mMappedIndexData(NULL), + mMappedData(nullptr), + mMappedIndexData(nullptr), mMappedDataUsingVBOs(false), mMappedIndexDataUsingVBOs(false), mVertexLocked(false), @@ -948,7 +1073,7 @@ LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) : mFinal(false), mEmpty(true), mMappable(false), - mFence(NULL) + mFence(nullptr) { mMappable = (mUsage == GL_DYNAMIC_DRAW_ARB && !sDisableVBOMapping); @@ -981,7 +1106,7 @@ S32 LLVertexBuffer::calcOffsets(const U32& typemask, S32* offsets, S32 num_verti offsets[TYPE_TEXTURE_INDEX] = offsets[TYPE_VERTEX] + 12; - return offset+16; + return offset; } //static @@ -1026,7 +1151,7 @@ LLVertexBuffer::~LLVertexBuffer() delete mFence; } - mFence = NULL; + mFence = nullptr; sVertexCount -= mNumVerts; sIndexCount -= mNumIndices; @@ -1072,6 +1197,10 @@ void LLVertexBuffer::genBuffer(U32 size) { mMappedData = sDynamicVBOPool.allocate(mGLBuffer, mSize); } + if ((sDisableVBOMapping || mUsage != GL_DYNAMIC_DRAW_ARB) && !mMappedData) + { + LL_ERRS() << "mMappedData allocation failedd" << LL_ENDL; + } sGLCount++; } @@ -1088,6 +1217,10 @@ void LLVertexBuffer::genIndices(U32 size) { mMappedIndexData = sDynamicIBOPool.allocate(mGLIndices, mIndicesSize); } + if ((sDisableVBOMapping || mUsage != GL_DYNAMIC_DRAW_ARB) && !mMappedIndexData) + { + LL_ERRS() << "mMappedIndexData allocation failedd" << LL_ENDL; + } sGLCount++; } @@ -1104,7 +1237,7 @@ void LLVertexBuffer::releaseBuffer() } mGLBuffer = 0; - mMappedData = NULL; + mMappedData = nullptr; sGLCount--; } @@ -1121,7 +1254,7 @@ void LLVertexBuffer::releaseIndices() } mGLIndices = 0; - mMappedIndexData = NULL; + mMappedIndexData = nullptr; sGLCount--; } @@ -1139,6 +1272,7 @@ void LLVertexBuffer::createGLBuffer(U32 size) } mEmpty = true; + mResidentSize = size; mMappedDataUsingVBOs = useVBOs(); @@ -1150,7 +1284,7 @@ void LLVertexBuffer::createGLBuffer(U32 size) { static int gl_buffer_idx = 0; mGLBuffer = ++gl_buffer_idx; - mMappedData = (U8*)ALLOCATE_MEM(sPrivatePoolp, size); + mMappedData = (U8*)ll_aligned_malloc_16(size); mSize = size; } } @@ -1168,6 +1302,7 @@ void LLVertexBuffer::createGLIndices(U32 size) } mEmpty = true; + mResidentIndicesSize = size; //pad by 16 bytes for aligned copies size += 16; @@ -1182,7 +1317,7 @@ void LLVertexBuffer::createGLIndices(U32 size) } else { - mMappedIndexData = (U8*)ALLOCATE_MEM(sPrivatePoolp, size); + mMappedIndexData = (U8*)ll_aligned_malloc_16(size); static int gl_buffer_idx = 0; mGLIndices = ++gl_buffer_idx; mIndicesSize = size; @@ -1199,8 +1334,8 @@ void LLVertexBuffer::destroyGLBuffer() } else { - FREE_MEM(sPrivatePoolp, (void*) mMappedData); - mMappedData = NULL; + ll_aligned_free_16((void*) mMappedData); + mMappedData = nullptr; mEmpty = true; } } @@ -1219,8 +1354,8 @@ void LLVertexBuffer::destroyGLIndices() } else { - FREE_MEM(sPrivatePoolp, (void*) mMappedIndexData); - mMappedIndexData = NULL; + ll_aligned_free_16((void*) mMappedIndexData); + mMappedIndexData = nullptr; mEmpty = true; } } @@ -1235,7 +1370,7 @@ void LLVertexBuffer::updateNumVerts(S32 nverts) if (nverts > 65536) { - llwarns << "Vertex buffer overflow!" << llendl; + LL_WARNS() << "Vertex buffer overflow!" << LL_ENDL; nverts = 65536; } @@ -1274,7 +1409,7 @@ void LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create) if (nverts < 0 || nindices < 0 || nverts > 65536) { - llwarns << "Bad vertex buffer allocation: " << nverts << " : " << nindices << llendl; + LL_WARNS() << "Bad vertex buffer allocation: " << nverts << " : " << nindices << LL_ENDL; } updateNumVerts(nverts); @@ -1285,7 +1420,7 @@ void LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create) //actually allocate space for the vertex buffer if using VBO mapping flush(); - if (gGLManager.mHasVertexArrayObject && useVBOs() && (LLRender::sGLCoreProfile || sUseVAO)) + if (gGLManager.mHasVertexArrayObject && useVBOs() && sUseVAO) { #if GL_ARB_vertex_array_object mGLArray = getVAOName(); @@ -1295,7 +1430,7 @@ void LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create) } } -static LLFastTimer::DeclareTimer FTM_SETUP_VERTEX_ARRAY("Setup VAO"); +static LLTrace::BlockTimerStatHandle FTM_SETUP_VERTEX_ARRAY("Setup VAO"); void LLVertexBuffer::setupVertexArray() { @@ -1304,7 +1439,7 @@ void LLVertexBuffer::setupVertexArray() return; } - LLFastTimer t(FTM_SETUP_VERTEX_ARRAY); + //LL_RECORD_BLOCK_TIME(FTM_SETUP_VERTEX_ARRAY); #if GL_ARB_vertex_array_object glBindVertexArray(mGLArray); #endif @@ -1320,7 +1455,7 @@ void LLVertexBuffer::setupVertexArray() 2, //TYPE_TEXCOORD3, 4, //TYPE_COLOR, 4, //TYPE_EMISSIVE, - 3, //TYPE_BINORMAL, + 4, //TYPE_TANGENT, 1, //TYPE_WEIGHT, 4, //TYPE_WEIGHT4, 4, //TYPE_CLOTHWEIGHT, @@ -1337,7 +1472,7 @@ void LLVertexBuffer::setupVertexArray() GL_FLOAT, //TYPE_TEXCOORD3, GL_UNSIGNED_BYTE, //TYPE_COLOR, GL_UNSIGNED_BYTE, //TYPE_EMISSIVE, - GL_FLOAT, //TYPE_BINORMAL, + GL_FLOAT, //TYPE_TANGENT, GL_FLOAT, //TYPE_WEIGHT, GL_FLOAT, //TYPE_WEIGHT4, GL_FLOAT, //TYPE_CLOTHWEIGHT, @@ -1354,7 +1489,7 @@ void LLVertexBuffer::setupVertexArray() false, //TYPE_TEXCOORD3, false, //TYPE_COLOR, false, //TYPE_EMISSIVE, - false, //TYPE_BINORMAL, + false, //TYPE_TANGENT, false, //TYPE_WEIGHT, false, //TYPE_WEIGHT4, false, //TYPE_CLOTHWEIGHT, @@ -1371,15 +1506,15 @@ void LLVertexBuffer::setupVertexArray() GL_FALSE, //TYPE_TEXCOORD3, GL_TRUE, //TYPE_COLOR, GL_TRUE, //TYPE_EMISSIVE, - GL_FALSE, //TYPE_BINORMAL, + GL_FALSE, //TYPE_TANGENT, GL_FALSE, //TYPE_WEIGHT, GL_FALSE, //TYPE_WEIGHT4, GL_FALSE, //TYPE_CLOTHWEIGHT, GL_FALSE, //TYPE_TEXTURE_INDEX }; - bindGLBuffer(true); - bindGLIndices(true); + bindGLBuffer(); + bindGLIndices(); for (U32 i = 0; i < TYPE_MAX; ++i) { @@ -1393,13 +1528,13 @@ void LLVertexBuffer::setupVertexArray() //glVertexattribIPointer requires GLSL 1.30 or later if (gGLManager.mGLSLVersionMajor > 1 || gGLManager.mGLSLVersionMinor >= 30) { - glVertexAttribIPointer(i, attrib_size[i], attrib_type[i], sTypeSize[i], reinterpret_cast(mOffsets[i])); + glVertexAttribIPointer(i, attrib_size[i], attrib_type[i], sTypeSize[i], reinterpret_cast(static_cast(mOffsets[i]))); } #endif } else { - glVertexAttribPointerARB(i, attrib_size[i], attrib_type[i], attrib_normalized[i], sTypeSize[i], reinterpret_cast(mOffsets[i])); + glVertexAttribPointerARB(i, attrib_size[i], attrib_type[i], attrib_normalized[i], sTypeSize[i], reinterpret_cast(static_cast(mOffsets[i]))); } } else @@ -1441,38 +1576,38 @@ bool LLVertexBuffer::useVBOs() const //---------------------------------------------------------------------------- -bool expand_region(LLVertexBuffer::MappedRegion& region, S32 index, S32 count) +bool expand_region(LLVertexBuffer::MappedRegion& region, U32 offset, U32 length) { - S32 end = index+count; - S32 region_end = region.mIndex+region.mCount; + U32 end = offset + length; + U32 region_end = region.mOffset + region.mLength; - if (end < region.mIndex || - index > region_end) + if (end < region.mOffset || + offset > region_end) { //gap exists, do not merge return false; } - S32 new_end = llmax(end, region_end); - S32 new_index = llmin(index, region.mIndex); - region.mIndex = new_index; - region.mCount = new_end-new_index; + U32 new_end = llmax(end, region_end); + U32 new_offset = llmin(offset, region.mOffset); + region.mOffset = new_offset; + region.mLength = new_end-new_offset; return true; } -static LLFastTimer::DeclareTimer FTM_VBO_MAP_BUFFER_RANGE("VBO Map Range"); -static LLFastTimer::DeclareTimer FTM_VBO_MAP_BUFFER("VBO Map"); +static LLTrace::BlockTimerStatHandle FTM_VBO_MAP_BUFFER_RANGE("VBO Map Range"); +static LLTrace::BlockTimerStatHandle FTM_VBO_MAP_BUFFER("VBO Map"); // Map for data access volatile U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range) { - bindGLBuffer(true); + bindGLBuffer(); if (mFinal) { - llerrs << "LLVertexBuffer::mapVeretxBuffer() called on a finalized buffer." << llendl; + LL_ERRS() << "LLVertexBuffer::mapVeretxBuffer() called on a finalized buffer." << LL_ENDL; } if (!useVBOs() && !mMappedData && !mMappedIndexData) { - llerrs << "LLVertexBuffer::mapVertexBuffer() called on unallocated buffer." << llendl; + LL_ERRS() << "LLVertexBuffer::mapVertexBuffer() called on unallocated buffer." << LL_ENDL; } if (useVBOs()) @@ -1484,32 +1619,47 @@ volatile U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, boo count = mNumVerts-index; } - bool mapped = false; - //see if range is already mapped - for (U32 i = 0; i < mMappedVertexRegions.size(); ++i) + if (getSize() > LL_VBO_BLOCK_SIZE) { - MappedRegion& region = mMappedVertexRegions[i]; - if (region.mType == type) + U32 offset = mOffsets[type] + sTypeSize[type] * index; + U32 length = sTypeSize[type] * count; + + bool mapped = false; + //see if range is already mapped + for (U32 i = 0; i < mMappedVertexRegions.size(); ++i) { - if (expand_region(region, index, count)) + MappedRegion& region = mMappedVertexRegions[i]; + if (expand_region(region, offset, length)) { + ++i; + while (MappedRegion* pNext = i < mMappedVertexRegions.size() ? &mMappedVertexRegions[i] : nullptr) + { + if (expand_region(region, pNext->mOffset, pNext->mLength)) + { + mMappedVertexRegions.erase(mMappedVertexRegions.begin() + i); + } + else + { + ++i; + } + } mapped = true; break; } } - } - if (!mapped) - { - //not already mapped, map new region - MappedRegion region(type, mMappable && map_range ? -1 : index, count); - mMappedVertexRegions.push_back(region); + if (!mapped) + { + //not already mapped, map new region + MappedRegion region(type, mMappable && map_range ? -1 : offset, length); + mMappedVertexRegions.push_back(region); + } } } if (mVertexLocked && map_range) { - llerrs << "Attempted to map a specific range of a buffer that was already mapped." << llendl; + LL_ERRS() << "Attempted to map a specific range of a buffer that was already mapped." << LL_ENDL; } if (!mVertexLocked) @@ -1524,14 +1674,14 @@ volatile U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, boo } else { - volatile U8* src = NULL; + volatile U8* src = nullptr; waitFence(); if (gGLManager.mHasMapBufferRange) { if (map_range) { #ifdef GL_ARB_map_buffer_range - LLFastTimer t(FTM_VBO_MAP_BUFFER_RANGE); + //LL_RECORD_BLOCK_TIME(FTM_VBO_MAP_BUFFER_RANGE); S32 offset = mOffsets[type] + sTypeSize[type]*index; S32 length = (sTypeSize[type]*count+0xF) & ~0xF; src = (U8*) glMapBufferRange(GL_ARRAY_BUFFER_ARB, offset, length, @@ -1551,11 +1701,11 @@ volatile U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, boo if (size < mSize) { - llerrs << "Invalid buffer size." << llendl; + LL_ERRS() << "Invalid buffer size." << LL_ENDL; } } - LLFastTimer t(FTM_VBO_MAP_BUFFER); + //LL_RECORD_BLOCK_TIME(FTM_VBO_MAP_BUFFER); src = (U8*) glMapBufferRange(GL_ARRAY_BUFFER_ARB, 0, mSize, GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT); @@ -1600,25 +1750,25 @@ volatile U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, boo { //-------------------- //print out more debug info before crash - llinfos << "vertex buffer size: (num verts : num indices) = " << getNumVerts() << " : " << getNumIndices() << llendl; + LL_INFOS() << "vertex buffer size: (num verts : num indices) = " << getNumVerts() << " : " << getNumIndices() << LL_ENDL; GLint size; glGetBufferParameterivARB(GL_ARRAY_BUFFER_ARB, GL_BUFFER_SIZE_ARB, &size); - llinfos << "GL_ARRAY_BUFFER_ARB size is " << size << llendl; + LL_INFOS() << "GL_ARRAY_BUFFER_ARB size is " << size << LL_ENDL; //-------------------- GLint buff; glGetIntegerv(GL_ARRAY_BUFFER_BINDING_ARB, &buff); if ((GLuint)buff != mGLBuffer) { - llerrs << "Invalid GL vertex buffer bound: " << buff << llendl; + LL_ERRS() << "Invalid GL vertex buffer bound: " << buff << LL_ENDL; } - llerrs << "glMapBuffer returned NULL (no vertex data)" << llendl; + LL_ERRS() << "glMapBuffer returned NULL (no vertex data)" << LL_ENDL; } else { - llerrs << "memory allocation for vertex data failed." << llendl; + LL_ERRS() << "memory allocation for vertex data failed." << LL_ENDL; } } } @@ -1639,19 +1789,19 @@ volatile U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, boo } -static LLFastTimer::DeclareTimer FTM_VBO_MAP_INDEX_RANGE("IBO Map Range"); -static LLFastTimer::DeclareTimer FTM_VBO_MAP_INDEX("IBO Map"); +static LLTrace::BlockTimerStatHandle FTM_VBO_MAP_INDEX_RANGE("IBO Map Range"); +static LLTrace::BlockTimerStatHandle FTM_VBO_MAP_INDEX("IBO Map"); volatile U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range) { - bindGLIndices(true); + bindGLIndices(); if (mFinal) { - llerrs << "LLVertexBuffer::mapIndexBuffer() called on a finalized buffer." << llendl; + LL_ERRS() << "LLVertexBuffer::mapIndexBuffer() called on a finalized buffer." << LL_ENDL; } if (!useVBOs() && !mMappedData && !mMappedIndexData) { - llerrs << "LLVertexBuffer::mapIndexBuffer() called on unallocated buffer." << llendl; + LL_ERRS() << "LLVertexBuffer::mapIndexBuffer() called on unallocated buffer." << LL_ENDL; } if (useVBOs()) @@ -1663,31 +1813,50 @@ volatile U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range count = mNumIndices-index; } - bool mapped = false; - //see if range is already mapped - for (U32 i = 0; i < mMappedIndexRegions.size(); ++i) + if (getIndicesSize() > LL_VBO_BLOCK_SIZE) { - MappedRegion& region = mMappedIndexRegions[i]; - if (expand_region(region, index, count)) + U32 offset = sizeof(U16) * index; + U32 length = sizeof(U16) * count; + + bool mapped = false; + //see if range is already mapped + for (U32 i = 0; i < mMappedIndexRegions.size(); ++i) { - mapped = true; - break; + MappedRegion& region = mMappedIndexRegions[i]; + if (expand_region(region, offset, length)) + { + ++i; + while (MappedRegion* pNext = i < mMappedIndexRegions.size() ? &mMappedIndexRegions[i] : nullptr) + { + if (expand_region(region, pNext->mOffset, pNext->mLength)) + { + mMappedIndexRegions.erase(mMappedIndexRegions.begin() + i); + } + else + { + ++i; + } + } + mapped = true; + break; + } } - } - if (!mapped) - { - //not already mapped, map new region - MappedRegion region(TYPE_INDEX, mMappable && map_range ? -1 : index, count); - mMappedIndexRegions.push_back(region); + if (!mapped) + { + //not already mapped, map new region + MappedRegion region(TYPE_INDEX, mMappable && map_range ? -1 : offset, length); + mMappedIndexRegions.push_back(region); + } } } if (mIndexLocked && map_range) { - llerrs << "Attempted to map a specific range of a buffer that was already mapped." << llendl; + LL_ERRS() << "Attempted to map a specific range of a buffer that was already mapped." << LL_ENDL; } + bool was_locked = mIndexLocked; if (!mIndexLocked) { mIndexLocked = true; @@ -1701,7 +1870,7 @@ volatile U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range if (elem != mGLIndices) { - llerrs << "Wrong index buffer bound!" << llendl; + LL_ERRS() << "Wrong index buffer bound!" << LL_ENDL; } } @@ -1711,14 +1880,14 @@ volatile U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range } else { - volatile U8* src = NULL; + volatile U8* src = nullptr; waitFence(); if (gGLManager.mHasMapBufferRange) { if (map_range) { #ifdef GL_ARB_map_buffer_range - LLFastTimer t(FTM_VBO_MAP_INDEX_RANGE); + //LL_RECORD_BLOCK_TIME(FTM_VBO_MAP_INDEX_RANGE); S32 offset = sizeof(U16)*index; S32 length = sizeof(U16)*count; src = (U8*) glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length, @@ -1730,7 +1899,7 @@ volatile U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range else { #ifdef GL_ARB_map_buffer_range - LLFastTimer t(FTM_VBO_MAP_INDEX); + //LL_RECORD_BLOCK_TIME(FTM_VBO_MAP_INDEX); src = (U8*) glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, sizeof(U16)*mNumIndices, GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT); @@ -1752,7 +1921,7 @@ volatile U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range } else { - LLFastTimer t(FTM_VBO_MAP_INDEX); + //LL_RECORD_BLOCK_TIME(FTM_VBO_MAP_INDEX); map_range = false; src = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); } @@ -1777,14 +1946,18 @@ volatile U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &buff); if ((GLuint)buff != mGLIndices) { - llerrs << "Invalid GL index buffer bound: " << buff << llendl; + LL_ERRS() << "Invalid GL index buffer bound: " << buff << LL_ENDL; } - llerrs << "glMapBuffer returned NULL (no index data)" << llendl; + LL_ERRS() << "glMapBuffer returned NULL (no index data)" << LL_ENDL; + } + else if (was_locked) + { + LL_ERRS() << "mIndexLocked was true but no Index data allocated" << LL_ENDL; } else { - llerrs << "memory allocation for Index data failed. " << llendl; + LL_ERRS() << "memory allocation for Index data failed. " << LL_ENDL; } } } @@ -1803,12 +1976,12 @@ volatile U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range } } -static LLFastTimer::DeclareTimer FTM_VBO_UNMAP("VBO Unmap"); -static LLFastTimer::DeclareTimer FTM_VBO_FLUSH_RANGE("Flush VBO Range"); +static LLTrace::BlockTimerStatHandle FTM_VBO_UNMAP("VBO Unmap"); +static LLTrace::BlockTimerStatHandle FTM_VBO_FLUSH_RANGE("Flush VBO Range"); -static LLFastTimer::DeclareTimer FTM_IBO_UNMAP("IBO Unmap"); -static LLFastTimer::DeclareTimer FTM_IBO_FLUSH_RANGE("Flush IBO Range"); +static LLTrace::BlockTimerStatHandle FTM_IBO_UNMAP("IBO Unmap"); +static LLTrace::BlockTimerStatHandle FTM_IBO_FLUSH_RANGE("Flush IBO Range"); void LLVertexBuffer::unmapBuffer() { @@ -1821,8 +1994,8 @@ void LLVertexBuffer::unmapBuffer() if (mMappedData && mVertexLocked) { - LLFastTimer t(FTM_VBO_UNMAP); - bindGLBuffer(true); + //LL_RECORD_BLOCK_TIME(FTM_VBO_UNMAP); + bindGLBuffer(); updated_all = mIndexLocked; //both vertex and index buffers done updating if(!mMappable) @@ -1833,9 +2006,18 @@ void LLVertexBuffer::unmapBuffer() for (U32 i = 0; i < mMappedVertexRegions.size(); ++i) { const MappedRegion& region = mMappedVertexRegions[i]; - S32 offset = region.mIndex >= 0 ? mOffsets[region.mType]+sTypeSize[region.mType]*region.mIndex : 0; - S32 length = sTypeSize[region.mType]*region.mCount; - glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, offset, length, (U8*) mMappedData+offset); + U32 offset = region.mOffset; + U32 length = region.mLength; + if ((mResidentSize - length) <= LL_VBO_BLOCK_SIZE * 2 || (offset == 0 && length >= mResidentSize)) + { + glBufferDataARB(GL_ARRAY_BUFFER_ARB, getSize(), nullptr, mUsage); + glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, getSize(), (U8*)mMappedData); + break; + } + else + { + glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, offset, length, (U8*)mMappedData + offset); + } stop_glerror(); } @@ -1844,6 +2026,7 @@ void LLVertexBuffer::unmapBuffer() else { stop_glerror(); + glBufferDataARB(GL_ARRAY_BUFFER_ARB, getSize(), nullptr, mUsage); // glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, getSize(), (U8*) mMappedData); stop_glerror(); } @@ -1858,11 +2041,11 @@ void LLVertexBuffer::unmapBuffer() for (U32 i = 0; i < mMappedVertexRegions.size(); ++i) { const MappedRegion& region = mMappedVertexRegions[i]; - S32 offset = region.mIndex >= 0 ? mOffsets[region.mType]+sTypeSize[region.mType]*region.mIndex : 0; - S32 length = sTypeSize[region.mType]*region.mCount; + U32 offset = region.mOffset; + U32 length = region.mLength; if (gGLManager.mHasMapBufferRange) { - LLFastTimer t(FTM_VBO_FLUSH_RANGE); + //LL_RECORD_BLOCK_TIME(FTM_VBO_FLUSH_RANGE); #ifdef GL_ARB_map_buffer_range glFlushMappedBufferRange(GL_ARRAY_BUFFER_ARB, offset, length); #endif @@ -1881,7 +2064,7 @@ void LLVertexBuffer::unmapBuffer() glUnmapBufferARB(GL_ARRAY_BUFFER_ARB); stop_glerror(); - mMappedData = NULL; + mMappedData = nullptr; } mVertexLocked = false; @@ -1890,7 +2073,7 @@ void LLVertexBuffer::unmapBuffer() if (mMappedIndexData && mIndexLocked) { - LLFastTimer t(FTM_IBO_UNMAP); + //LL_RECORD_BLOCK_TIME(FTM_IBO_UNMAP); bindGLIndices(); if(!mMappable) { @@ -1899,9 +2082,18 @@ void LLVertexBuffer::unmapBuffer() for (U32 i = 0; i < mMappedIndexRegions.size(); ++i) { const MappedRegion& region = mMappedIndexRegions[i]; - S32 offset = region.mIndex >= 0 ? sizeof(U16)*region.mIndex : 0; - S32 length = sizeof(U16)*region.mCount; - glBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length, (U8*) mMappedIndexData+offset); + U32 offset = region.mOffset; + U32 length = region.mLength; + if ((mResidentIndicesSize - length) <= LL_VBO_BLOCK_SIZE * 2 || (offset == 0 && length >= mResidentIndicesSize)) + { + glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, getIndicesSize(), nullptr, mUsage); // + glBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, getIndicesSize(), (U8*)mMappedIndexData); + break; + } + else + { + glBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length, (U8*)mMappedIndexData + offset); + } stop_glerror(); } @@ -1910,6 +2102,7 @@ void LLVertexBuffer::unmapBuffer() else { stop_glerror(); + glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, getIndicesSize(), nullptr, mUsage); // glBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, getIndicesSize(), (U8*) mMappedIndexData); stop_glerror(); } @@ -1923,11 +2116,11 @@ void LLVertexBuffer::unmapBuffer() for (U32 i = 0; i < mMappedIndexRegions.size(); ++i) { const MappedRegion& region = mMappedIndexRegions[i]; - S32 offset = region.mIndex >= 0 ? sizeof(U16)*region.mIndex : 0; - S32 length = sizeof(U16)*region.mCount; + U32 offset = region.mOffset; + U32 length = region.mLength; if (gGLManager.mHasMapBufferRange) { - LLFastTimer t(FTM_IBO_FLUSH_RANGE); + //LL_RECORD_BLOCK_TIME(FTM_IBO_FLUSH_RANGE); #ifdef GL_ARB_map_buffer_range glFlushMappedBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length); #endif @@ -1948,7 +2141,7 @@ void LLVertexBuffer::unmapBuffer() glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB); stop_glerror(); - mMappedIndexData = NULL; + mMappedIndexData = nullptr; } mIndexLocked = false; @@ -1963,36 +2156,23 @@ void LLVertexBuffer::unmapBuffer() //---------------------------------------------------------------------------- -template struct VertexBufferStrider +template +struct VertexBufferStrider { typedef LLStrider strider_t; static bool get(LLVertexBuffer& vbo, strider_t& strider, S32 index, S32 count, bool map_range) { - if (type == LLVertexBuffer::TYPE_INDEX) - { - volatile U8* ptr = vbo.mapIndexBuffer(index, count, map_range); - - if (ptr == NULL) - { - llwarns << "mapIndexBuffer failed!" << llendl; - return false; - } - - strider = (T*)ptr; - strider.setStride(0); - return true; - } - else if (vbo.hasDataType(type)) + if (vbo.hasDataType(type)) { S32 stride = LLVertexBuffer::sTypeSize[type]; volatile U8* ptr = vbo.mapVertexBuffer(type, index, count, map_range); - if (ptr == NULL) + if (ptr == nullptr) { - llwarns << "mapVertexBuffer failed!" << llendl; + LL_WARNS() << "mapVertexBuffer failed!" << LL_ENDL; return false; } @@ -2002,12 +2182,34 @@ template struct VertexBufferStrider } else { - llwarns << "VertexBufferStrider could not find valid vertex data." << llendl; + LL_WARNS() << "VertexBufferStrider could not find valid vertex data." << LL_ENDL; } return false; } }; +template +struct VertexBufferStrider +{ + typedef LLStrider strider_t; + static bool get(LLVertexBuffer& vbo, + strider_t& strider, + S32 index, S32 count, bool map_range) + { + volatile U8* ptr = vbo.mapIndexBuffer(index, count, map_range); + + if (ptr == nullptr) + { + LL_WARNS() << "mapIndexBuffer failed!" << LL_ENDL; + return false; + } + + strider = (T*) ptr; + strider.setStride(0); + return true; + } +}; + bool LLVertexBuffer::getVertexStrider(LLStrider& strider, S32 index, S32 count, bool map_range) { return VertexBufferStrider::get(*this, strider, index, count, map_range); @@ -2028,14 +2230,25 @@ bool LLVertexBuffer::getTexCoord1Strider(LLStrider& strider, S32 inde { return VertexBufferStrider::get(*this, strider, index, count, map_range); } - +bool LLVertexBuffer::getTexCoord2Strider(LLStrider& strider, S32 index, S32 count, bool map_range) +{ + return VertexBufferStrider::get(*this, strider, index, count, map_range); +} bool LLVertexBuffer::getNormalStrider(LLStrider& strider, S32 index, S32 count, bool map_range) { return VertexBufferStrider::get(*this, strider, index, count, map_range); } -bool LLVertexBuffer::getBinormalStrider(LLStrider& strider, S32 index, S32 count, bool map_range) +bool LLVertexBuffer::getNormalStrider(LLStrider& strider, S32 index, S32 count, bool map_range) +{ + return VertexBufferStrider::get(*this, strider, index, count, map_range); +} +bool LLVertexBuffer::getTangentStrider(LLStrider& strider, S32 index, S32 count, bool map_range) { - return VertexBufferStrider::get(*this, strider, index, count, map_range); + return VertexBufferStrider::get(*this, strider, index, count, map_range); +} +bool LLVertexBuffer::getTangentStrider(LLStrider& strider, S32 index, S32 count, bool map_range) +{ + return VertexBufferStrider::get(*this, strider, index, count, map_range); } bool LLVertexBuffer::getColorStrider(LLStrider& strider, S32 index, S32 count, bool map_range) { @@ -2050,25 +2263,25 @@ bool LLVertexBuffer::getWeightStrider(LLStrider& strider, S32 index, S32 co return VertexBufferStrider::get(*this, strider, index, count, map_range); } -bool LLVertexBuffer::getWeight4Strider(LLStrider& strider, S32 index, S32 count, bool map_range) +bool LLVertexBuffer::getWeight4Strider(LLStrider& strider, S32 index, S32 count, bool map_range) { - return VertexBufferStrider::get(*this, strider, index, count, map_range); + return VertexBufferStrider::get(*this, strider, index, count, map_range); } -bool LLVertexBuffer::getClothWeightStrider(LLStrider& strider, S32 index, S32 count, bool map_range) +bool LLVertexBuffer::getClothWeightStrider(LLStrider& strider, S32 index, S32 count, bool map_range) { - return VertexBufferStrider::get(*this, strider, index, count, map_range); + return VertexBufferStrider::get(*this, strider, index, count, map_range); } //---------------------------------------------------------------------------- -static LLFastTimer::DeclareTimer FTM_BIND_GL_ARRAY("Bind Array"); +static LLTrace::BlockTimerStatHandle FTM_BIND_GL_ARRAY("Bind Array"); bool LLVertexBuffer::bindGLArray() { if (mGLArray && sGLRenderArray != mGLArray) { { - LLFastTimer t(FTM_BIND_GL_ARRAY); + //LL_RECORD_BLOCK_TIME(FTM_BIND_GL_ARRAY); #if GL_ARB_vertex_array_object glBindVertexArray(mGLArray); #endif @@ -2085,22 +2298,28 @@ bool LLVertexBuffer::bindGLArray() return false; } -static LLFastTimer::DeclareTimer FTM_BIND_GL_BUFFER("Bind Buffer"); +static LLTrace::BlockTimerStatHandle FTM_BIND_GL_BUFFER("Bind Buffer"); bool LLVertexBuffer::bindGLBuffer(bool force_bind) { + //stop_glerror(); bindGLArray(); + //stop_glerror(); bool ret = false; if (useVBOs() && (force_bind || (mGLBuffer && (mGLBuffer != sGLRenderBuffer || !sVBOActive)))) { - LLFastTimer t(FTM_BIND_GL_BUFFER); + //LL_RECORD_BLOCK_TIME(FTM_BIND_GL_BUFFER); /*if (sMapped) { - llerrs << "VBO bound while another VBO mapped!" << llendl; + LL_ERRS() << "VBO bound while another VBO mapped!" << LL_ENDL; }*/ + //stop_glerror(); + + //validate_bind_buffer(mGLBuffer); glBindBufferARB(GL_ARRAY_BUFFER_ARB, mGLBuffer); + //stop_glerror(); sGLRenderBuffer = mGLBuffer; sBindCount++; sVBOActive = true; @@ -2117,7 +2336,7 @@ bool LLVertexBuffer::bindGLBuffer(bool force_bind) return ret; } -static LLFastTimer::DeclareTimer FTM_BIND_GL_INDICES("Bind Indices"); +static LLTrace::BlockTimerStatHandle FTM_BIND_GL_INDICES("Bind Indices"); bool LLVertexBuffer::bindGLIndices(bool force_bind) { @@ -2126,11 +2345,12 @@ bool LLVertexBuffer::bindGLIndices(bool force_bind) bool ret = false; if (useVBOs() && (force_bind || (mGLIndices && (mGLIndices != sGLRenderIndices || !sIBOActive)))) { - LLFastTimer t(FTM_BIND_GL_INDICES); + //LL_RECORD_BLOCK_TIME(FTM_BIND_GL_INDICES); /*if (sMapped) { - llerrs << "VBO bound while another VBO mapped!" << llendl; + LL_ERRS() << "VBO bound while another VBO mapped!" << LL_ENDL; }*/ + //validate_bind_buffer(mGLIndices); glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, mGLIndices); sGLRenderIndices = mGLIndices; stop_glerror(); @@ -2150,16 +2370,6 @@ void LLVertexBuffer::flush() } } -// bind for transform feedback (quick 'n dirty) -void LLVertexBuffer::bindForFeedback(U32 channel, U32 type, U32 index, U32 count) -{ -#ifdef GL_TRANSFORM_FEEDBACK_BUFFER - U32 offset = mOffsets[type] + sTypeSize[type]*index; - U32 size= (sTypeSize[type]*count); - glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, channel, mGLBuffer, offset, size); -#endif -} - // Set for rendering void LLVertexBuffer::setBuffer(U32 data_mask) { @@ -2181,7 +2391,7 @@ void LLVertexBuffer::setBuffer(U32 data_mask) U32 required = 1 << i; if ((data_mask & required) == 0) { - llwarns << "Missing attribute: " << LLShaderMgr::instance()->mReservedAttribs[i] << llendl; + LL_WARNS() << "Missing attribute: " << LLShaderMgr::instance()->mReservedAttribs[i] << LL_ENDL; } required_mask |= required; @@ -2190,7 +2400,7 @@ void LLVertexBuffer::setBuffer(U32 data_mask) if ((data_mask & required_mask) != required_mask) { - llerrs << "Shader consumption mismatches data provision." << llendl; + LL_ERRS() << "Shader consumption mismatches data provision." << LL_ENDL; } } } @@ -2222,7 +2432,7 @@ void LLVertexBuffer::setBuffer(U32 data_mask) } else { - llerrs << "Invalid GL vertex buffer bound: " << buff << llendl; + LL_ERRS() << "Invalid GL vertex buffer bound: " << buff << LL_ENDL; } } @@ -2237,7 +2447,7 @@ void LLVertexBuffer::setBuffer(U32 data_mask) } else { - llerrs << "Invalid GL index buffer bound: " << buff << llendl; + LL_ERRS() << "Invalid GL index buffer bound: " << buff << LL_ENDL; } } } @@ -2308,7 +2518,15 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask) if (gDebugGL && ((data_mask & mTypeMask) != data_mask)) { - llerrs << "LLVertexBuffer::setupVertexBuffer missing required components for supplied data mask." << llendl; + for (U32 i = 0; i < LLVertexBuffer::TYPE_MAX; ++i) + { + U32 mask = 1 << i; + if (mask & data_mask && !(mask & mTypeMask)) + { //bit set in data_mask, but not set in mTypeMask + LL_WARNS() << "Missing required component " << vb_type_name[i] << LL_ENDL; + } + } + LL_ERRS() << "LLVertexBuffer::setupVertexBuffer missing required components for supplied data mask." << LL_ENDL; } if (LLGLSLShader::sNoFixedFunction) @@ -2337,11 +2555,11 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask) void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD1]); glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], ptr); } - if (data_mask & MAP_BINORMAL) + if (data_mask & MAP_TANGENT) { - S32 loc = TYPE_BINORMAL; - void* ptr = (void*)(base + mOffsets[TYPE_BINORMAL]); - glVertexAttribPointerARB(loc, 3,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_BINORMAL], ptr); + S32 loc = TYPE_TANGENT; + void* ptr = (void*)(base + mOffsets[TYPE_TANGENT]); + glVertexAttribPointerARB(loc, 4,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TANGENT], ptr); } if (data_mask & MAP_TEXCOORD0) { @@ -2352,7 +2570,8 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask) if (data_mask & MAP_COLOR) { S32 loc = TYPE_COLOR; - void* ptr = (void*)(base + mOffsets[TYPE_COLOR]); + //bind emissive instead of color pointer if emissive is present + void* ptr = (data_mask & MAP_EMISSIVE) ? (void*)(base + mOffsets[TYPE_EMISSIVE]) : (void*)(base + mOffsets[TYPE_COLOR]); glVertexAttribPointerARB(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_COLOR], ptr); } if (data_mask & MAP_EMISSIVE) @@ -2360,6 +2579,12 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask) S32 loc = TYPE_EMISSIVE; void* ptr = (void*)(base + mOffsets[TYPE_EMISSIVE]); glVertexAttribPointerARB(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_EMISSIVE], ptr); + + if (!(data_mask & MAP_COLOR)) + { //map emissive to color channel when color is not also being bound to avoid unnecessary shader swaps + loc = TYPE_COLOR; + glVertexAttribPointerARB(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_EMISSIVE], ptr); + } } if (data_mask & MAP_WEIGHT) { @@ -2419,10 +2644,10 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask) glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], (void*)(base + mOffsets[TYPE_TEXCOORD1])); glClientActiveTextureARB(GL_TEXTURE0_ARB); } - if (data_mask & MAP_BINORMAL) + if (data_mask & MAP_TANGENT) { glClientActiveTextureARB(GL_TEXTURE2_ARB); - glTexCoordPointer(3,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_BINORMAL], (void*)(base + mOffsets[TYPE_BINORMAL])); + glTexCoordPointer(4,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TANGENT], (void*)(base + mOffsets[TYPE_TANGENT])); glClientActiveTextureARB(GL_TEXTURE0_ARB); } if (data_mask & MAP_TEXCOORD0) @@ -2442,8 +2667,8 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask) llglassertok(); } -LLVertexBuffer::MappedRegion::MappedRegion(S32 type, S32 index, S32 count) -: mType(type), mIndex(index), mCount(count) +LLVertexBuffer::MappedRegion::MappedRegion(S32 type, U32 offset, U32 length) +: mType(type), mOffset(offset), mLength(length) { llassert(mType == LLVertexBuffer::TYPE_INDEX || mType < LLVertexBuffer::TYPE_TEXTURE_INDEX); diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h index 4801117a52..906e62dbb1 100644 --- a/indra/llrender/llvertexbuffer.h +++ b/indra/llrender/llvertexbuffer.h @@ -54,10 +54,12 @@ class LLVBOPool { public: - static U32 sBytesPooled; - static U32 sIndexBytesPooled; - - static U32 sCurGLName; + static U64 sBytesPooled; + static U64 sIndexBytesPooled; + static std::vector sPendingDeletions; + + // Periodically call from render loop. Batches VBO deletions together in a single call. + static void deleteReleasedBuffers(); LLVBOPool(U32 vboUsage, U32 vboType); @@ -65,7 +67,7 @@ class LLVBOPool const U32 mType; //size MUST be a power of 2 - volatile U8* allocate(U32& name, U32 size, bool for_seed = false); + volatile U8* allocate(U32& name, U32 size, U32 seed = 0); //size MUST be the size provided to allocate that returned the given name void release(U32 name, volatile U8* buffer, U32 size); @@ -86,8 +88,6 @@ class LLVBOPool volatile U8* mClientData; }; - std::list mGLNamePool; - typedef std::list record_list_t; std::vector mFreeList; std::vector mMissCount; @@ -97,7 +97,6 @@ class LLVBOPool //============================================================================ // base class -class LLPrivateMemoryPool; class LLVertexBuffer : public LLRefCount { public: @@ -105,10 +104,10 @@ class LLVertexBuffer : public LLRefCount { public: S32 mType; - S32 mIndex; - S32 mCount; + U32 mOffset; + U32 mLength; - MappedRegion(S32 type, S32 index, S32 count); + MappedRegion(S32 type, U32 offset, U32 length); }; LLVertexBuffer(const LLVertexBuffer& rhs) @@ -119,16 +118,18 @@ class LLVertexBuffer : public LLRefCount const LLVertexBuffer& operator=(const LLVertexBuffer& rhs) { - llerrs << "Illegal operation!" << llendl; + LL_ERRS() << "Illegal operation!" << LL_ENDL; return *this; } + static const std::string& getTypeName(U8 i); + static LLVBOPool sStreamVBOPool; static LLVBOPool sDynamicVBOPool; static LLVBOPool sStreamIBOPool; static LLVBOPool sDynamicIBOPool; - static std::list sAvailableVAOName; + static std::vector sAvailableVAOName; static U32 sCurVAOName; static bool sUseStreamDraw; @@ -144,7 +145,7 @@ class LLVertexBuffer : public LLRefCount static void cleanupClass(); static void setupClientArrays(U32 data_mask); static void drawArrays(U32 mode, const std::vector& pos, const std::vector& norm); - static void drawElements(U32 mode, const LLVector4a* pos, const LLVector2* tc, S32 num_indices, const U16* indicesp); + static void drawElements(U32 mode, const S32 num_vertices, const LLVector4a* pos, const LLVector2* tc, S32 num_indices, const U16* indicesp); static void unbind(); //unbind any bound vertex buffer @@ -173,7 +174,7 @@ class LLVertexBuffer : public LLRefCount TYPE_TEXCOORD3, TYPE_COLOR, TYPE_EMISSIVE, - TYPE_BINORMAL, + TYPE_TANGENT, TYPE_WEIGHT, TYPE_WEIGHT4, TYPE_CLOTHWEIGHT, @@ -191,7 +192,7 @@ class LLVertexBuffer : public LLRefCount MAP_COLOR = (1<& strider, S32 index=0, S32 count = -1, bool map_range = false); bool getTexCoord0Strider(LLStrider& strider, S32 index=0, S32 count = -1, bool map_range = false); bool getTexCoord1Strider(LLStrider& strider, S32 index=0, S32 count = -1, bool map_range = false); + bool getTexCoord2Strider(LLStrider& strider, S32 index=0, S32 count = -1, bool map_range = false); bool getNormalStrider(LLStrider& strider, S32 index=0, S32 count = -1, bool map_range = false); - bool getBinormalStrider(LLStrider& strider, S32 index=0, S32 count = -1, bool map_range = false); + bool getNormalStrider(LLStrider& strider, S32 index=0, S32 count = -1, bool map_range = false); + bool getTangentStrider(LLStrider& strider, S32 index=0, S32 count = -1, bool map_range = false); + bool getTangentStrider(LLStrider& strider, S32 index=0, S32 count = -1, bool map_range = false); bool getColorStrider(LLStrider& strider, S32 index=0, S32 count = -1, bool map_range = false); bool getEmissiveStrider(LLStrider& strider, S32 index=0, S32 count = -1, bool map_range = false); bool getWeightStrider(LLStrider& strider, S32 index=0, S32 count = -1, bool map_range = false); - bool getWeight4Strider(LLStrider& strider, S32 index=0, S32 count = -1, bool map_range = false); - bool getClothWeightStrider(LLStrider& strider, S32 index=0, S32 count = -1, bool map_range = false); + bool getWeight4Strider(LLStrider& strider, S32 index=0, S32 count = -1, bool map_range = false); + bool getClothWeightStrider(LLStrider& strider, S32 index=0, S32 count = -1, bool map_range = false); bool useVBOs() const; @@ -293,7 +295,9 @@ class LLVertexBuffer : public LLRefCount ptrdiff_t mAlignedOffset; ptrdiff_t mAlignedIndexOffset; S32 mSize; + U32 mResidentSize; S32 mIndicesSize; + U32 mResidentIndicesSize; U32 mTypeMask; const S32 mUsage; // GL usage @@ -326,9 +330,6 @@ class LLVertexBuffer : public LLRefCount static S32 determineUsage(S32 usage); -private: - static LLPrivateMemoryPool* sPrivatePoolp; - public: static S32 sCount; static S32 sGLCount; @@ -346,12 +347,15 @@ class LLVertexBuffer : public LLRefCount static bool sVBOActive; static bool sIBOActive; static U32 sLastMask; - static U32 sAllocatedBytes; - static U32 sAllocatedIndexBytes; + static U64 sAllocatedBytes; + static U64 sAllocatedIndexBytes; static U32 sVertexCount; static U32 sIndexCount; static U32 sBindCount; static U32 sSetCount; + +private: + static LLVertexBuffer* sUtilityBuffer; }; diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index 057e7d0ca0..3caf919eb6 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -24,6 +24,9 @@ include_directories( ) set(llui_SOURCE_FILES + lfidbearer.cpp + llaccordionctrl.cpp + llaccordionctrltab.cpp llalertdialog.cpp llbutton.cpp llcheckboxctrl.cpp @@ -34,6 +37,7 @@ set(llui_SOURCE_FILES lldraghandle.cpp lleditmenuhandler.cpp llfiltereditor.cpp + llflatlistview.cpp llfloater.cpp llflyoutbutton.cpp llfocusmgr.cpp @@ -42,6 +46,7 @@ set(llui_SOURCE_FILES llkeywords.cpp lllayoutstack.cpp lllineeditor.cpp + llloadingindicator.cpp lllocalcliprect.cpp llmenugl.cpp llmodaldialog.cpp @@ -91,12 +96,16 @@ set(llui_SOURCE_FILES llviewborder.cpp llviewmodel.cpp llviewquery.cpp + llxuiparser.cpp ) set(llui_HEADER_FILES CMakeLists.txt ailist.h + lfidbearer.h + llaccordionctrl.h + llaccordionctrltab.h llalertdialog.h llbutton.h llcallbackmap.h @@ -108,6 +117,7 @@ set(llui_HEADER_FILES lldraghandle.h lleditmenuhandler.h llfiltereditor.h + llflatlistview.h llfloater.h llflyoutbutton.h llfocusmgr.h @@ -117,6 +127,7 @@ set(llui_HEADER_FILES llkeywords.h lllayoutstack.h lllineeditor.h + llloadingindicator.h lllocalcliprect.h llmemberlistener.h llmenugl.h @@ -172,6 +183,7 @@ set(llui_HEADER_FILES llviewborder.h llviewmodel.h llviewquery.h + llxuiparser.h ) set_source_files_properties(${llui_HEADER_FILES} diff --git a/indra/llui/ailist.h b/indra/llui/ailist.h index 14ef05f0c6..1511fef2e0 100644 --- a/indra/llui/ailist.h +++ b/indra/llui/ailist.h @@ -253,11 +253,15 @@ class AIConstListIterator { typedef AIConstListIterator _Self; typedef std::list > _Container; typedef typename _Container::iterator _Iterator; +#if LL_LINUX && GCC_VERSION <= 40899 + typedef _Iterator _ConstIterator; +#else typedef typename _Container::const_iterator _ConstIterator; +#endif typedef AIListIterator iterator; _Container const* mContainer; - _Iterator mConstIterator; // This has to be an _Iterator instead of _ConstIterator, because the compiler doesn't accept a const_iterator for erase yet (C++11 does). + _ConstIterator mConstIterator; void ref(void) { @@ -289,7 +293,7 @@ class AIConstListIterator { typedef T const& reference; AIConstListIterator(void) : mContainer(NULL) { } - AIConstListIterator(_Container const* __c, _Iterator const& __i) : mContainer(__c), mConstIterator(__i) + AIConstListIterator(_Container const* __c, _ConstIterator const& __i) : mContainer(__c), mConstIterator(__i) { llassert(mContainer); ref(); @@ -343,7 +347,7 @@ class AIConstListIterator { _Self& operator++() { - _Iterator cur = mConstIterator; + _ConstIterator cur = mConstIterator; ++cur; unref(); while(cur != mContainer->end() && cur->dead) @@ -364,7 +368,7 @@ class AIConstListIterator { _Self& operator--() { - _Iterator cur = mConstIterator; + _ConstIterator cur = mConstIterator; --cur; unref(); while(cur->dead) diff --git a/indra/llui/lfidbearer.cpp b/indra/llui/lfidbearer.cpp new file mode 100644 index 0000000000..6ac6714d56 --- /dev/null +++ b/indra/llui/lfidbearer.cpp @@ -0,0 +1,59 @@ +/* Copyright (C) 2019 Liru Færs + * + * LFIDBearer is a class that holds an ID or IDs that menus can use + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 */ + +#include "linden_common.h" +#include "lfidbearer.h" +#include "llmenugl.h" +#include "lluictrlfactory.h" + +const std::array LFIDBearer::sMenuStrings +{ + "menu_avs_list.xml" // 0 +, "menu_groups_list.xml" // 1 +, "menu_objects_list.xml" // 2 +, "menu_experiences.xml" // 3 +}; +std::array LFIDBearer::sMenus {}; + +const LFIDBearer* LFIDBearer::sActive = nullptr; +LFIDBearer::Type LFIDBearer::sActiveType = LFIDBearer::AVATAR; +uuid_vec_t LFIDBearer::sActiveIDs {}; + +void LFIDBearer::buildMenus() +{ + auto& factory = LLUICtrlFactory::instance(); + for (auto i = 0; i < COUNT; ++i) + sMenus[i] = factory.buildMenu(sMenuStrings[i], LLMenuGL::sMenuContainer); +} + +LLMenuGL* LFIDBearer::showMenu(LLView* self, const std::string& menu_name, S32 x, S32 y, std::function on_menu_built) +{ + auto menu = LLUICtrlFactory::instance().buildMenu(menu_name, LLMenuGL::sMenuContainer); + if (on_menu_built) on_menu_built(menu); + showMenu(self, menu, x, y); + return menu; +} + +void LFIDBearer::showMenu(LLView* self, LLMenuGL* menu, S32 x, S32 y) +{ + setActive(); // Menu listeners rely on this + menu->buildDrawLabels(); + menu->updateParent(LLMenuGL::sMenuContainer); + LLMenuGL::showPopup(self, menu, x, y); +} diff --git a/indra/llui/lfidbearer.h b/indra/llui/lfidbearer.h new file mode 100644 index 0000000000..3f434a5a7e --- /dev/null +++ b/indra/llui/lfidbearer.h @@ -0,0 +1,73 @@ +/* Copyright (C) 2019 Liru Færs + * + * LFIDBearer is a class that holds an ID or IDs that menus can use + * This class also bears the type of ID/IDs that it is holding + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 */ + +#pragma once + +#include "lluuid.h" + +class LLMenuGL; +class LLView; + +struct LFIDBearer +{ + enum Type : S8 + { + MULTIPLE = -2, + NONE = -1, + AVATAR = 0, + GROUP, + OBJECT, + EXPERIENCE, + COUNT + }; + + virtual ~LFIDBearer() { if (sActive == this) sActive = nullptr; } + virtual LLUUID getStringUUIDSelectedItem() const = 0; + virtual uuid_vec_t getSelectedIDs() const { return { getStringUUIDSelectedItem() }; } + virtual Type getSelectedType() const { return AVATAR; } + + template static const T* getActive() { return static_cast(sActive); } + static const LLUUID& getActiveSelectedID() { return sActiveIDs.empty() ? LLUUID::null : sActiveIDs[0]; } + static const uuid_vec_t& getActiveSelectedIDs() { return sActiveIDs; } + static size_t getActiveNumSelected() { return sActiveIDs.size(); } + static const Type& getActiveType() { return sActiveType; } + + void setActive() const + { + sActive = this; + sActiveType = getSelectedType(); + sActiveIDs = getSelectedIDs(); + //sActiveIDs or even some kinda hybrid map, if Type is MULTIPLE fill the vals? and remove a buncha virtual functions? + } + + static void buildMenus(); + LLMenuGL* showMenu(LLView* self, const std::string& menu_name, S32 x, S32 y, std::function on_menu_built = nullptr); + void showMenu(LLView* self, LLMenuGL* menu, S32 x, S32 y); + +protected: + // Menus that recur, such as general avatars or groups menus + static const std::array sMenuStrings; + static std::array sMenus; + +private: + static const LFIDBearer* sActive; + static Type sActiveType; + static uuid_vec_t sActiveIDs; +}; diff --git a/indra/llui/llaccordionctrl.cpp b/indra/llui/llaccordionctrl.cpp new file mode 100644 index 0000000000..be26d58a72 --- /dev/null +++ b/indra/llui/llaccordionctrl.cpp @@ -0,0 +1,925 @@ +/** + * @file llaccordionctrl.cpp + * @brief Accordion panel implementation + * + * $LicenseInfo:firstyear=2009&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ +#include "linden_common.h" + +#include "llaccordionctrl.h" +#include "llaccordionctrltab.h" + +#include "lluictrlfactory.h" // builds floaters from XML + +#include "llwindow.h" +#include "llfocusmgr.h" +#include "lllocalcliprect.h" + +#include "boost/bind.hpp" + +static const S32 BORDER_MARGIN = 2; +static const S32 PARENT_BORDER_MARGIN = 5; +static const S32 VERTICAL_MULTIPLE = 16; +static const F32 MIN_AUTO_SCROLL_RATE = 120.f; +static const F32 MAX_AUTO_SCROLL_RATE = 500.f; +static const F32 AUTO_SCROLL_RATE_ACCEL = 120.f; + +// LLAccordionCtrl =================================================================| + +//static LLDefaultChildRegistry::Register t2("accordion"); +static LLRegisterWidget t2("accordion"); + +/*LLAccordionCtrl::LLAccordionCtrl(const Params& params):LLPanel(params) + , mFitParent(params.fit_parent) + , mAutoScrolling( false ) + , mAutoScrollRate( 0.f ) + , mSelectedTab( NULL ) + , mTabComparator( NULL ) + , mNoVisibleTabsHelpText(NULL) + , mNoVisibleTabsOrigString(params.no_visible_tabs_text.initial_value().asString()) +{ + initNoTabsWidget(params.no_matched_tabs_text); + + mSingleExpansion = params.single_expansion; + if(mFitParent && !mSingleExpansion) + { + LL_INFOS() << "fit_parent works best when combined with single_expansion" << LL_ENDL; + } +}*/ + +LLAccordionCtrl::LLAccordionCtrl() : LLPanel() + , mAutoScrolling( false ) + , mAutoScrollRate( 0.f ) + , mSelectedTab( NULL ) + , mNoVisibleTabsHelpText(NULL) +{ + initNoTabsWidget(""/*LLTextBox::Params()*/); + + mSingleExpansion = false; + mFitParent = false; + LLUICtrlFactory::getInstance()->buildPanel(this, "accordion_parent.xml"); +} + +//--------------------------------------------------------------------------------- +void LLAccordionCtrl::draw() +{ + if (mAutoScrolling) + { + // add acceleration to autoscroll + mAutoScrollRate = llmin(mAutoScrollRate + (LLFrameTimer::getFrameDeltaTimeF32() * AUTO_SCROLL_RATE_ACCEL), MAX_AUTO_SCROLL_RATE); + } + else + { + // reset to minimum for next time + mAutoScrollRate = MIN_AUTO_SCROLL_RATE; + } + // clear this flag to be set on next call to autoScroll + mAutoScrolling = false; + + LLRect local_rect(0, getRect().getHeight(), getRect().getWidth(), 0); + + LLLocalClipRect clip(local_rect); + + LLPanel::draw(); +} + + +//--------------------------------------------------------------------------------- +BOOL LLAccordionCtrl::postBuild() +{ + static LLUICachedControl scrollbar_size ("UIScrollbarSize", 0); + + LLRect scroll_rect; + scroll_rect.setOriginAndSize( + getRect().getWidth() - scrollbar_size, + 1, + scrollbar_size, + getRect().getHeight() - 1); + + mScrollbar = new LLScrollbar("scrollable vertical", scroll_rect, LLScrollbar::VERTICAL, mInnerRect.getHeight(), 0, mInnerRect.getHeight(), boost::bind(&LLAccordionCtrl::onScrollPosChangeCallback, this, _1, _2), VERTICAL_MULTIPLE); + mScrollbar->setFollows(FOLLOWS_RIGHT | FOLLOWS_TOP | FOLLOWS_BOTTOM); + LLView::addChild( mScrollbar ); + mScrollbar->setVisible( false ); + mScrollbar->setFollows(FOLLOWS_RIGHT|FOLLOWS_TOP|FOLLOWS_BOTTOM); + + //if it was created from xml... + std::vector accordion_tabs; + for(child_list_const_iter_t it = getChildList()->begin(); + getChildList()->end() != it; ++it) + { + LLAccordionCtrlTab* accordion_tab = dynamic_cast(*it); + if(accordion_tab == NULL) + continue; + if(std::find(mAccordionTabs.begin(),mAccordionTabs.end(),accordion_tab) == mAccordionTabs.end()) + { + accordion_tabs.push_back(accordion_tab); + } + } + + for(std::vector::reverse_iterator it = accordion_tabs.rbegin();it!=accordion_tabs.rend();++it) + addCollapsibleCtrl(*it); + + arrange (); + + if(mSingleExpansion) + { + if(!mAccordionTabs[0]->getDisplayChildren()) + mAccordionTabs[0]->setDisplayChildren(true); + for(size_t i=1;igetDisplayChildren()) + mAccordionTabs[i]->setDisplayChildren(false); + } + } + + updateNoTabsHelpTextVisibility(); + + return TRUE; +} + + +//--------------------------------------------------------------------------------- +LLAccordionCtrl::~LLAccordionCtrl() +{ + mAccordionTabs.clear(); +} + +//--------------------------------------------------------------------------------- + +void LLAccordionCtrl::reshape(S32 width, S32 height, BOOL called_from_parent) +{ + // adjust our rectangle + LLRect rcLocal = getRect(); + rcLocal.mRight = rcLocal.mLeft + width; + rcLocal.mTop = rcLocal.mBottom + height; + + // get textbox a chance to reshape its content + mNoVisibleTabsHelpText->reshape(width, height, called_from_parent); + + setRect(rcLocal); + + // assume that help text is always fit accordion. + // necessary text paddings can be set via h_pad and v_pad + mNoVisibleTabsHelpText->setRect(getLocalRect()); + + arrange(); +} + +//--------------------------------------------------------------------------------- +BOOL LLAccordionCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask) +{ + return LLPanel::handleRightMouseDown(x, y, mask); +} + +//--------------------------------------------------------------------------------- +void LLAccordionCtrl::shiftAccordionTabs(S16 panel_num, S32 delta) +{ + for(size_t i = panel_num; i < mAccordionTabs.size(); i++ ) + { + ctrlShiftVertical(mAccordionTabs[i],delta); + } +} + + +//--------------------------------------------------------------------------------- +void LLAccordionCtrl::onCollapseCtrlCloseOpen(S16 panel_num) +{ + if(mSingleExpansion) + { + for(size_t i=0;igetDisplayChildren()) + mAccordionTabs[i]->setDisplayChildren(false); + } + + } + arrange(); +} + +void LLAccordionCtrl::show_hide_scrollbar(S32 width, S32 height) +{ + calcRecuiredHeight(); + if(getRecuiredHeight() > height ) + showScrollbar(width,height); + else + hideScrollbar(width,height); +} + +void LLAccordionCtrl::showScrollbar(S32 width, S32 height) +{ + bool was_visible = mScrollbar->getVisible(); + + mScrollbar->setVisible(true); + + static LLUICachedControl scrollbar_size ("UIScrollbarSize", 0); + + ctrlSetLeftTopAndSize(mScrollbar + ,width-scrollbar_size - PARENT_BORDER_MARGIN/2 + ,height-PARENT_BORDER_MARGIN + ,scrollbar_size + ,height-2*PARENT_BORDER_MARGIN); + + mScrollbar->setPageSize(height); + mScrollbar->setDocParams(mInnerRect.getHeight(),mScrollbar->getDocPos()); + + if(was_visible) + { + S32 scroll_pos = llmin(mScrollbar->getDocPos(), getRecuiredHeight() - height - 1); + mScrollbar->setDocPos(scroll_pos); + } +} + +void LLAccordionCtrl::hideScrollbar( S32 width, S32 height ) +{ + if(mScrollbar->getVisible() == false) + return; + mScrollbar->setVisible(false); + + static LLUICachedControl scrollbar_size ("UIScrollbarSize", 0); + + S32 panel_width = width - 2*BORDER_MARGIN; + + //reshape all accordeons and shift all draggers + for(size_t i=0;igetRect(); + ctrlSetLeftTopAndSize(mAccordionTabs[i],panel_rect.mLeft,panel_rect.mTop,panel_width,panel_rect.getHeight()); + } + + mScrollbar->setDocPos(0); + + if(mAccordionTabs.size()>0) + { + S32 panel_top = height - BORDER_MARGIN; // Top coordinate of the first panel + S32 diff = panel_top - mAccordionTabs[0]->getRect().mTop; + shiftAccordionTabs(0,diff); + } +} + + +//--------------------------------------------------------------------------------- +S32 LLAccordionCtrl::calcRecuiredHeight() +{ + S32 rec_height = 0; + + std::vector::iterator panel; + for(panel=mAccordionTabs.begin(); panel!=mAccordionTabs.end(); ++panel) + { + LLAccordionCtrlTab* accordion_tab = dynamic_cast(*panel); + if(accordion_tab && accordion_tab->getVisible()) + { + rec_height += accordion_tab->getRect().getHeight(); + } + } + + mInnerRect.setLeftTopAndSize(0,rec_height + BORDER_MARGIN*2,getRect().getWidth(),rec_height + BORDER_MARGIN); + + return mInnerRect.getHeight(); +} + +//--------------------------------------------------------------------------------- +void LLAccordionCtrl::ctrlSetLeftTopAndSize(LLView* panel, S32 left, S32 top, S32 width, S32 height) +{ + if(!panel) + return; + LLRect panel_rect = panel->getRect(); + panel_rect.setLeftTopAndSize( left, top, width, height); + panel->reshape( width, height, 1); + panel->setRect(panel_rect); +} + +void LLAccordionCtrl::ctrlShiftVertical(LLView* panel,S32 delta) +{ + if(!panel) + return; + panel->translate(0,delta); +} + +//--------------------------------------------------------------------------------- + +void LLAccordionCtrl::addCollapsibleCtrl(LLView* view) +{ + LLAccordionCtrlTab* accordion_tab = dynamic_cast(view); + if(!accordion_tab) + return; + if(std::find(beginChild(), endChild(), accordion_tab) == endChild()) + addChild(accordion_tab); + mAccordionTabs.push_back(accordion_tab); + + accordion_tab->setDropDownStateChangedCallback( boost::bind(&LLAccordionCtrl::onCollapseCtrlCloseOpen, this, S16(mAccordionTabs.size() - 1)) ); + arrange(); +} + +void LLAccordionCtrl::removeCollapsibleCtrl(LLView* view) +{ + LLAccordionCtrlTab* accordion_tab = dynamic_cast(view); + if(!accordion_tab) + return; + + if(std::find(beginChild(), endChild(), accordion_tab) != endChild()) + removeChild(accordion_tab); + + for (std::vector::iterator iter = mAccordionTabs.begin(); + iter != mAccordionTabs.end(); ++iter) + { + if (accordion_tab == (*iter)) + { + mAccordionTabs.erase(iter); + break; + } + } + + // if removed is selected - reset selection + if (mSelectedTab == view) + { + mSelectedTab = NULL; + } +} + +void LLAccordionCtrl::initNoTabsWidget(const std::string/*LLTextBox::Params*/& tb_params) +{ + //LLTextBox::Params tp = tb_params; + //tp.rect(getLocalRect()); + mNoMatchedTabsOrigString = tb_params; //tp.initial_value().asString(); + mNoVisibleTabsHelpText = new LLTextBox(tb_params, getLocalRect()); //LLUICtrlFactory::create(tp, this); +} + +void LLAccordionCtrl::updateNoTabsHelpTextVisibility() +{ + bool visible_exists = false; + std::vector::const_iterator it = mAccordionTabs.begin(); + const std::vector::const_iterator it_end = mAccordionTabs.end(); + for (; it != it_end; ++it) + { + if ((*it)->getVisible()) + { + visible_exists = true; + break; + } + } + + mNoVisibleTabsHelpText->setVisible(!visible_exists); +} + +void LLAccordionCtrl::arrangeSinge() +{ + S32 panel_left = BORDER_MARGIN; // Margin from left side of Splitter + S32 panel_top = getRect().getHeight() - BORDER_MARGIN; // Top coordinate of the first panel + S32 panel_width = getRect().getWidth() - 4; // Top coordinate of the first panel + S32 panel_height; + + S32 collapsed_height = 0; + + for(size_t i=0;i(mAccordionTabs[i]); + + if(accordion_tab->getVisible() == false) //skip hidden accordion tabs + continue; + if(!accordion_tab->isExpanded() ) + { + collapsed_height+=mAccordionTabs[i]->getRect().getHeight(); + } + } + + S32 expanded_height = getRect().getHeight() - BORDER_MARGIN - collapsed_height; + + for(size_t i=0;i(mAccordionTabs[i]); + + if(accordion_tab->getVisible() == false) //skip hidden accordion tabs + continue; + if(!accordion_tab->isExpanded() ) + { + panel_height = accordion_tab->getRect().getHeight(); + } + else + { + if(mFitParent) + { + panel_height = expanded_height; + } + else + { + if(accordion_tab->getAccordionView()) + { + panel_height = accordion_tab->getAccordionView()->getRect().getHeight() + + accordion_tab->getHeaderHeight() + 2*BORDER_MARGIN; + } + else + { + panel_height = accordion_tab->getRect().getHeight(); + } + } + } + + // make sure at least header is shown + panel_height = llmax(panel_height, accordion_tab->getHeaderHeight()); + + ctrlSetLeftTopAndSize(mAccordionTabs[i], panel_left, panel_top, panel_width, panel_height); + panel_top-=mAccordionTabs[i]->getRect().getHeight(); + } + + show_hide_scrollbar(getRect().getWidth(), getRect().getHeight()); + updateLayout(getRect().getWidth(), getRect().getHeight()); +} + +void LLAccordionCtrl::arrangeMultiple() +{ + S32 panel_left = BORDER_MARGIN; // Margin from left side of Splitter + S32 panel_top = getRect().getHeight() - BORDER_MARGIN; // Top coordinate of the first panel + S32 panel_width = getRect().getWidth() - 4; // Top coordinate of the first panel + + //Calculate params + for(size_t i = 0; i < mAccordionTabs.size(); i++ ) + { + LLAccordionCtrlTab* accordion_tab = dynamic_cast(mAccordionTabs[i]); + + if(accordion_tab->getVisible() == false) //skip hidden accordion tabs + continue; + + if(!accordion_tab->isExpanded() ) + { + ctrlSetLeftTopAndSize(mAccordionTabs[i], panel_left, panel_top, panel_width, accordion_tab->getRect().getHeight()); + panel_top-=mAccordionTabs[i]->getRect().getHeight(); + } + else + { + S32 panel_height = accordion_tab->getRect().getHeight(); + + if(mFitParent) + { + // all expanded tabs will have equal height + panel_height = calcExpandedTabHeight(i, panel_top); + ctrlSetLeftTopAndSize(accordion_tab, panel_left, panel_top, panel_width, panel_height); + + // try to make accordion tab fit accordion view height. + // Accordion View should implement getRequiredRect() and provide valid height + S32 optimal_height = accordion_tab->getAccordionView()->getRequiredRect().getHeight(); + optimal_height += accordion_tab->getHeaderHeight() + 2 * BORDER_MARGIN; + if(optimal_height < panel_height) + { + panel_height = optimal_height; + } + + // minimum tab height is equal to header height + if(mAccordionTabs[i]->getHeaderHeight() > panel_height) + { + panel_height = mAccordionTabs[i]->getHeaderHeight(); + } + } + + ctrlSetLeftTopAndSize(mAccordionTabs[i], panel_left, panel_top, panel_width, panel_height); + panel_top-=panel_height; + + } + } + + show_hide_scrollbar(getRect().getWidth(),getRect().getHeight()); + + updateLayout(getRect().getWidth(),getRect().getHeight()); +} + + +void LLAccordionCtrl::arrange() +{ + updateNoTabsHelpTextVisibility(); + + if( mAccordionTabs.size() == 0) + { + //We do not arrange if we do not have what should be arranged + return; + } + + + if(mAccordionTabs.size() == 1) + { + S32 panel_top = getRect().getHeight() - BORDER_MARGIN; // Top coordinate of the first panel + S32 panel_width = getRect().getWidth() - 4; // Top coordinate of the first panel + + LLAccordionCtrlTab* accordion_tab = dynamic_cast(mAccordionTabs[0]); + + LLRect panel_rect = accordion_tab->getRect(); + + S32 panel_height = getRect().getHeight() - 2*BORDER_MARGIN; + + if (accordion_tab->getFitParent()) + panel_height = accordion_tab->getRect().getHeight(); + ctrlSetLeftTopAndSize(accordion_tab,panel_rect.mLeft,panel_top,panel_width,panel_height); + + show_hide_scrollbar(getRect().getWidth(),getRect().getHeight()); + return; + + } + + if(mSingleExpansion) + arrangeSinge (); + else + arrangeMultiple (); +} + +//--------------------------------------------------------------------------------- + +BOOL LLAccordionCtrl::handleScrollWheel ( S32 x, S32 y, S32 clicks ) +{ + if(LLPanel::handleScrollWheel(x,y,clicks)) + return TRUE; + if( mScrollbar->getVisible() && mScrollbar->handleScrollWheel( 0, 0, clicks ) ) + return TRUE; + return false; + +} + +BOOL LLAccordionCtrl::handleKeyHere (KEY key, MASK mask) +{ + if( mScrollbar->getVisible() && mScrollbar->handleKeyHere( key,mask ) ) + return TRUE; + return LLPanel::handleKeyHere(key,mask); +} + +BOOL LLAccordionCtrl::handleDragAndDrop (S32 x, S32 y, MASK mask, + BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg) +{ + // Scroll folder view if needed. Never accepts a drag or drop. + *accept = ACCEPT_NO; + BOOL handled = autoScroll(x, y); + + if( !handled ) + { + handled = childrenHandleDragAndDrop(x, y, mask, drop, cargo_type, + cargo_data, accept, tooltip_msg) != NULL; + } + return TRUE; +} + +BOOL LLAccordionCtrl::autoScroll (S32 x, S32 y) +{ + static LLUICachedControl scrollbar_size ("UIScrollbarSize", 0); + + bool scrolling = false; + if( mScrollbar->getVisible() ) + { + LLRect rect_local( 0, getRect().getHeight(), getRect().getWidth() - scrollbar_size, 0 ); + LLRect screen_local_extents; + + // clip rect against root view + screenRectToLocal(getRootView()->getLocalRect(), &screen_local_extents); + rect_local.intersectWith(screen_local_extents); + + // autoscroll region should take up no more than one third of visible scroller area + S32 auto_scroll_region_height = llmin(rect_local.getHeight() / 3, 10); + S32 auto_scroll_speed = ll_pos_round(mAutoScrollRate * LLFrameTimer::getFrameDeltaTimeF32()); + + LLRect bottom_scroll_rect = screen_local_extents; + bottom_scroll_rect.mTop = rect_local.mBottom + auto_scroll_region_height; + if( bottom_scroll_rect.pointInRect( x, y ) && (mScrollbar->getDocPos() < mScrollbar->getDocPosMax()) ) + { + mScrollbar->setDocPos( mScrollbar->getDocPos() + auto_scroll_speed ); + mAutoScrolling = true; + scrolling = true; + } + + LLRect top_scroll_rect = screen_local_extents; + top_scroll_rect.mBottom = rect_local.mTop - auto_scroll_region_height; + if( top_scroll_rect.pointInRect( x, y ) && (mScrollbar->getDocPos() > 0) ) + { + mScrollbar->setDocPos( mScrollbar->getDocPos() - auto_scroll_speed ); + mAutoScrolling = true; + scrolling = true; + } + } + return scrolling; +} + +void LLAccordionCtrl::updateLayout (S32 width, S32 height) +{ + S32 panel_top = height - BORDER_MARGIN ; + if(mScrollbar->getVisible()) + panel_top+=mScrollbar->getDocPos(); + + S32 panel_width = width - 2*BORDER_MARGIN; + + static LLUICachedControl scrollbar_size ("UIScrollbarSize", 0); + if(mScrollbar->getVisible()) + panel_width-=scrollbar_size; + + //set sizes for first panels and dragbars + for(size_t i=0;igetVisible()) + continue; + LLRect panel_rect = mAccordionTabs[i]->getRect(); + ctrlSetLeftTopAndSize(mAccordionTabs[i],panel_rect.mLeft,panel_top,panel_width,panel_rect.getHeight()); + panel_top-=panel_rect.getHeight(); + } +} + +void LLAccordionCtrl::onScrollPosChangeCallback(S32, LLScrollbar*) +{ + updateLayout(getRect().getWidth(),getRect().getHeight()); +} +/*void LLAccordionCtrl::onOpen (const LLSD& key) +{ + for(size_t i=0;i(mAccordionTabs[i]); + LLPanel* panel = dynamic_cast(accordion_tab->getAccordionView()); + if(panel!=NULL) + { + panel->onOpen(key); + } + } +}*/ +S32 LLAccordionCtrl::notifyParent(const LLSD& info) +{ + if(info.has("action")) + { + std::string str_action = info["action"]; + if(str_action == "size_changes") + { + // + arrange(); + return 1; + } + else if(str_action == "select_next") + { + for(size_t i=0;i(mAccordionTabs[i]); + if(accordion_tab->hasFocus()) + { + while(++igetVisible()) + break; + } + if(i(mAccordionTabs[i]); + accordion_tab->notify(LLSD().with("action","select_first")); + return 1; + } + break; + } + } + return 0; + } + else if(str_action == "select_prev") + { + for(size_t i=0;i(mAccordionTabs[i]); + if(accordion_tab->hasFocus() && i>0) + { + bool prev_visible_tab_found = false; + while(i>0) + { + if(mAccordionTabs[--i]->getVisible()) + { + prev_visible_tab_found = true; + break; + } + } + + if (prev_visible_tab_found) + { + accordion_tab = dynamic_cast(mAccordionTabs[i]); + accordion_tab->notify(LLSD().with("action","select_last")); + return 1; + } + break; + } + } + return 0; + } + else if(str_action == "select_current") + { + for(size_t i=0;ihasFocus()) + { + if (mAccordionTabs[i] != mSelectedTab) + { + if (mSelectedTab) + { + mSelectedTab->setSelected(false); + } + mSelectedTab = mAccordionTabs[i]; + mSelectedTab->setSelected(true); + } + + return 1; + } + } + return 0; + } + else if(str_action == "deselect_current") + { + // Reset selection to the currently selected tab. + if (mSelectedTab) + { + mSelectedTab->setSelected(false); + mSelectedTab = NULL; + return 1; + } + return 0; + } + } + else if (info.has("scrollToShowRect")) + { + LLRect screen_rc, local_rc; + screen_rc.setValue(info["scrollToShowRect"]); + screenRectToLocal(screen_rc, &local_rc); + + // Translate to parent coordinatess to check if we are in visible rectangle + local_rc.translate( getRect().mLeft, getRect().mBottom ); + + if ( !getRect().contains (local_rc) ) + { + // Back to local coords and calculate position for scroller + S32 bottom = mScrollbar->getDocPos() - local_rc.mBottom + getRect().mBottom; + S32 top = mScrollbar->getDocPos() - local_rc.mTop + getRect().mTop; + + S32 scroll_pos = llclamp(mScrollbar->getDocPos(), + bottom, // min vertical scroll + top); // max vertical scroll + + mScrollbar->setDocPos( scroll_pos ); + } + return 1; + } + else if (info.has("child_visibility_change")) + { + BOOL new_visibility = info["child_visibility_change"]; + if (new_visibility) + { + // there is at least one visible tab + mNoVisibleTabsHelpText->setVisible(FALSE); + } + else + { + // it could be the latest visible tab, check all of them + updateNoTabsHelpTextVisibility(); + } + } + return LLPanel::notifyParent(info); +} +void LLAccordionCtrl::reset () +{ + if(mScrollbar) + mScrollbar->setDocPos(0); +} + +void LLAccordionCtrl::expandDefaultTab() +{ + if (mAccordionTabs.size() > 0) + { + LLAccordionCtrlTab* tab = mAccordionTabs.front(); + + if (!tab->getDisplayChildren()) + { + tab->setDisplayChildren(true); + } + + for (size_t i = 1; i < mAccordionTabs.size(); ++i) + { + tab = mAccordionTabs[i]; + + if (tab->getDisplayChildren()) + { + tab->setDisplayChildren(false); + } + } + + arrange(); + } +} + +void LLAccordionCtrl::sort() +{ + if (!mTabComparator) + { + LL_WARNS() << "No comparator specified for sorting accordion tabs." << LL_ENDL; + return; + } + + std::sort(mAccordionTabs.begin(), mAccordionTabs.end(), LLComparatorAdaptor(*mTabComparator)); + arrange(); +} + +void LLAccordionCtrl::setFilterSubString(const std::string& filter_string) +{ + LLStringUtil::format_map_t args; + args["[SEARCH_TERM]"] = LLURI::escape(filter_string); + std::string text = filter_string.empty() ? mNoVisibleTabsOrigString : mNoMatchedTabsOrigString; + LLStringUtil::format(text, args); + + mNoVisibleTabsHelpText->setValue(text); +} + +const LLAccordionCtrlTab* LLAccordionCtrl::getExpandedTab() const +{ + typedef std::vector::const_iterator tabs_const_iterator; + + const LLAccordionCtrlTab* result = 0; + + for (tabs_const_iterator i = mAccordionTabs.begin(); i != mAccordionTabs.end(); ++i) + { + if ((*i)->isExpanded()) + { + result = *i; + break; + } + } + + return result; +} + +S32 LLAccordionCtrl::calcExpandedTabHeight(S32 tab_index /* = 0 */, S32 available_height /* = 0 */) +{ + if(tab_index < 0) + { + return available_height; + } + + S32 collapsed_tabs_height = 0; + S32 num_expanded = 0; + + for(size_t n = tab_index; n < mAccordionTabs.size(); ++n) + { + if(!mAccordionTabs[n]->isExpanded()) + { + collapsed_tabs_height += mAccordionTabs[n]->getHeaderHeight(); + } + else + { + ++num_expanded; + } + } + + if(0 == num_expanded) + { + return available_height; + } + + S32 expanded_tab_height = available_height - collapsed_tabs_height - BORDER_MARGIN; // top BORDER_MARGIN is added in arrange(), here we add bottom BORDER_MARGIN + expanded_tab_height /= num_expanded; + return expanded_tab_height; +} + + +//static +LLView* LLAccordionCtrl::fromXML(LLXMLNodePtr node, LLView* parent, LLUICtrlFactory* factory) +{ + LLAccordionCtrl* ctrl = new LLAccordionCtrl(); + ctrl->mCommitCallbackRegistrar.pushScope(); + ctrl->mEnableCallbackRegistrar.pushScope(); + ctrl->initPanelXML(node, parent, factory); + ctrl->mCommitCallbackRegistrar.popScope(); + ctrl->mEnableCallbackRegistrar.popScope(); + return ctrl; +} + +void LLAccordionCtrl::initFromXML(LLXMLNodePtr node, LLView* parent) +{ + if (node->hasAttribute("single_expansion")) + node->getAttribute_bool("single_expansion", mSingleExpansion); + if (node->hasAttribute("fit_parent")) + node->getAttribute_bool("fit_parent", mFitParent); + if (node->hasAttribute("no_matched_tabs_text")) + { + node->getAttributeString("no_matched_tabs_text", mNoMatchedTabsOrigString); + mNoVisibleTabsHelpText->setValue(mNoMatchedTabsOrigString); + } + if (node->hasAttribute("no_visible_tabs_text")) + node->getAttributeString("no_visible_tabs_text", mNoVisibleTabsOrigString); + + LLPanel::initFromXML(node, parent); +} diff --git a/indra/llui/llaccordionctrl.h b/indra/llui/llaccordionctrl.h new file mode 100644 index 0000000000..95e321df35 --- /dev/null +++ b/indra/llui/llaccordionctrl.h @@ -0,0 +1,197 @@ +/** + * @file LLAccordionCtrl.h + * @brief Accordion Panel implementation + * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_ACCORDIONCTRL_H +#define LL_ACCORDIONCTRL_H + +#include "llpanel.h" +#include "lltextbox.h" +#include "llscrollbar.h" + +#include +#include +#include + +class LLAccordionCtrlTab; + +class LLAccordionCtrl: public LLPanel +{ +private: + + std::vector mAccordionTabs; + + void ctrlSetLeftTopAndSize(LLView* panel, S32 left, S32 top, S32 width, S32 height); + void ctrlShiftVertical(LLView* panel,S32 delta); + + void onCollapseCtrlCloseOpen(S16 panel_num); + void shiftAccordionTabs(S16 panel_num, S32 delta); + + +public: + /** + * Abstract comparator for accordion tabs. + */ + class LLTabComparator + { + public: + LLTabComparator() {}; + virtual ~LLTabComparator() {}; + + /** Returns true if tab1 < tab2, false otherwise */ + virtual bool compare(const LLAccordionCtrlTab* tab1, const LLAccordionCtrlTab* tab2) const = 0; + }; + + #if 0 // Singu TODO: LLPanel::Params, LLTextBox::Params + struct Params + : public LLInitParam::Block + { + Optional single_expansion, + fit_parent; /* Accordion will fit its parent size, controls that are placed into + accordion tabs are responsible for scrolling their content. + *NOTE fit_parent works best when combined with single_expansion. + Accordion view should implement getRequiredRect() and provide valid height*/ + Optional no_matched_tabs_text; + Optional no_visible_tabs_text; + + Params() + : single_expansion("single_expansion",false) + , fit_parent("fit_parent", false) + , no_matched_tabs_text("no_matched_tabs_text") + , no_visible_tabs_text("no_visible_tabs_text") + {}; + }; + + LLAccordionCtrl(const Params& params); + #endif + + LLAccordionCtrl(); + virtual ~LLAccordionCtrl(); + + virtual BOOL postBuild(); + static LLView* fromXML(LLXMLNodePtr node, LLView* parent, class LLUICtrlFactory* factory); + virtual void initFromXML(LLXMLNodePtr node, LLView* parent); + + virtual BOOL handleRightMouseDown ( S32 x, S32 y, MASK mask); + virtual BOOL handleScrollWheel ( S32 x, S32 y, S32 clicks ); + virtual BOOL handleKeyHere (KEY key, MASK mask); + virtual BOOL handleDragAndDrop (S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg); + // + + // Call reshape after changing splitter's size + virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + + void addCollapsibleCtrl(LLView* view); + void removeCollapsibleCtrl(LLView* view); + void arrange(); + + + void draw(); + + void onScrollPosChangeCallback(S32, LLScrollbar*); + + //void onOpen (const LLSD& key); + S32 notifyParent(const LLSD& info); + + void reset (); + void expandDefaultTab(); + + void setComparator(const LLTabComparator* comp) { mTabComparator = comp; } + void sort(); + + /** + * Sets filter substring as a search_term for help text when there are no any visible tabs. + */ + void setFilterSubString(const std::string& filter_string); + + /** + * This method returns the first expanded accordion tab. + * It is expected to be called for accordion which doesn't allow multiple + * tabs to be expanded. Use with care. + */ + const LLAccordionCtrlTab* getExpandedTab() const; + + LLAccordionCtrlTab* getSelectedTab() const { return mSelectedTab; } + + bool getFitParent() const {return mFitParent;} + +private: + void initNoTabsWidget(const std::string/*LLTextBox::Params*/& tb_params); + void updateNoTabsHelpTextVisibility(); + + void arrangeSinge(); + void arrangeMultiple(); + + // Calc Splitter's height that is necessary to display all child content + S32 calcRecuiredHeight(); + S32 getRecuiredHeight() const { return mInnerRect.getHeight(); } + S32 calcExpandedTabHeight(S32 tab_index = 0, S32 available_height = 0); + + void updateLayout (S32 width, S32 height); + + void show_hide_scrollbar (S32 width, S32 height); + + void showScrollbar (S32 width, S32 height); + void hideScrollbar (S32 width, S32 height); + + BOOL autoScroll (S32 x, S32 y); + + /** + * An adaptor for LLTabComparator + */ + struct LLComparatorAdaptor + { + LLComparatorAdaptor(const LLTabComparator& comparator) : mComparator(comparator) {}; + + bool operator()(const LLAccordionCtrlTab* tab1, const LLAccordionCtrlTab* tab2) + { + return mComparator.compare(tab1, tab2); + } + + const LLTabComparator& mComparator; + }; + +private: + LLRect mInnerRect; + LLScrollbar* mScrollbar; + bool mSingleExpansion; + bool mFitParent; + bool mAutoScrolling; + F32 mAutoScrollRate; + LLTextBox* mNoVisibleTabsHelpText; + + std::string mNoMatchedTabsOrigString; + std::string mNoVisibleTabsOrigString; + + LLAccordionCtrlTab* mSelectedTab; + const LLTabComparator* mTabComparator; +}; + + +#endif // LL_LLSPLITTER_H diff --git a/indra/llui/llaccordionctrltab.cpp b/indra/llui/llaccordionctrltab.cpp new file mode 100644 index 0000000000..79ebd97057 --- /dev/null +++ b/indra/llui/llaccordionctrltab.cpp @@ -0,0 +1,1278 @@ +/** + * @file LLAccordionCtrlTab.cpp + * @brief Collapsible control implementation + * + * $LicenseInfo:firstyear=2009&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llaccordionctrltab.h" +#include "llaccordionctrl.h" + +#include "lllocalcliprect.h" +#include "llscrollbar.h" +#include "lltextbox.h" +//#include "lltextutil.h" +#include "lluictrl.h" +#include "lluictrlfactory.h" + +static const std::string DD_BUTTON_NAME = "dd_button"; +static const std::string DD_TEXTBOX_NAME = "dd_textbox"; +static const std::string DD_HEADER_NAME = "dd_header"; + +static const S32 HEADER_HEIGHT = 23; +static const S32 HEADER_IMAGE_LEFT_OFFSET = 5; +static const S32 HEADER_TEXT_LEFT_OFFSET = 30; +static const F32 AUTO_OPEN_TIME = 1.f; +static const S32 VERTICAL_MULTIPLE = 16; +static const S32 PARENT_BORDER_MARGIN = 5; + +//static LLDefaultChildRegistry::Register t1("accordion_tab"); +static LLRegisterWidget t1("accordion_tab"); + +class LLAccordionCtrlTab::LLAccordionCtrlTabHeader : public LLUICtrl +{ +public: + friend class LLUICtrlFactory; + + struct Params : public LLAccordionCtrlTab::Params //LLInitParam::Block + { + Params(); + Params(const LLAccordionCtrlTab::Params& p) : LLAccordionCtrlTab::Params(p) {} + }; + + LLAccordionCtrlTabHeader(const LLAccordionCtrlTabHeader::Params& p); + + virtual ~LLAccordionCtrlTabHeader(); + + virtual void draw(); + + virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + + virtual BOOL postBuild(); + + std::string getTitle(); + void setTitle(const std::string& title, const std::string& hl); + + void setTitleFontStyle(std::string style); + + void setTitleColor(LLUIColor); + + void setSelected(bool is_selected) { mIsSelected = is_selected; } + + virtual void onMouseEnter(S32 x, S32 y, MASK mask); + virtual void onMouseLeave(S32 x, S32 y, MASK mask); + virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); + virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg); +private: + + LLTextBox* mHeaderTextbox; + + // Overlay images (arrows) + LLPointer mImageCollapsed; + LLPointer mImageExpanded; + LLPointer mImageCollapsedPressed; + LLPointer mImageExpandedPressed; + + // Background images + LLPointer mImageHeader; + LLPointer mImageHeaderOver; + LLPointer mImageHeaderPressed; + LLPointer mImageHeaderFocused; + + // style saved when applying it in setTitleFontStyle + //U8/*LLStyle::Params*/ mStyleParams; + + LLUIColor mHeaderBGColor; + + bool mNeedsHighlight; + bool mIsSelected; + + LLFrameTimer mAutoOpenTimer; +}; + +LLAccordionCtrlTab::LLAccordionCtrlTabHeader::Params::Params() +{ +} + +LLAccordionCtrlTab::LLAccordionCtrlTabHeader::LLAccordionCtrlTabHeader( + const LLAccordionCtrlTabHeader::Params& p) +: LLUICtrl(p) +, mHeaderBGColor(p.header_bg_color()) +, mNeedsHighlight(false) +, mIsSelected(false), + mImageCollapsed(p.header_collapse_img), + mImageCollapsedPressed(p.header_collapse_img_pressed), + mImageExpanded(p.header_expand_img), + mImageExpandedPressed(p.header_expand_img_pressed), + mImageHeader(p.header_image), + mImageHeaderOver(p.header_image_over), + mImageHeaderPressed(p.header_image_pressed), + mImageHeaderFocused(p.header_image_focused) +{ + mHeaderTextbox = new LLTextBox(DD_TEXTBOX_NAME, p.title(), 200, p.font(), false); + mHeaderTextbox->setColor(p.header_text_color()); + mHeaderTextbox->setFollows(FOLLOWS_NONE); + mHeaderTextbox->setFontShadow(LLFontGL::NO_SHADOW); + mHeaderTextbox->setUseEllipses(true); + mHeaderTextbox->setBackgroundVisible(false); + addChild(mHeaderTextbox); +} + +LLAccordionCtrlTab::LLAccordionCtrlTabHeader::~LLAccordionCtrlTabHeader() +{ +} + +BOOL LLAccordionCtrlTab::LLAccordionCtrlTabHeader::postBuild() +{ + return TRUE; +} + +std::string LLAccordionCtrlTab::LLAccordionCtrlTabHeader::getTitle() +{ + if(mHeaderTextbox) + { + return mHeaderTextbox->getText(); + } + else + { + return LLStringUtil::null; + } +} + +void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::setTitle(const std::string& title, const std::string& hl) +{ + if(mHeaderTextbox) + { + mHeaderTextbox->setText(title); + /*LLTextUtil::textboxSetHighlightedVal( + mHeaderTextbox, + mStyleParams, + title, + hl);*/ + } +} + +void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::setTitleFontStyle(std::string style) +{ + if (mHeaderTextbox) + { + mHeaderTextbox->setFontStyle(/*mStyleParams =*/ LLFontGL::getStyleFromString(style)); + } +} + +void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::setTitleColor(LLUIColor color) +{ + if(mHeaderTextbox) + { + mHeaderTextbox->setColor(color); + } +} + +void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::draw() +{ + S32 width = getRect().getWidth(); + S32 height = getRect().getHeight(); + + //F32 alpha = getCurrentTransparency(); // Singu TODO + gl_rect_2d(0,0,width - 1 ,height - 1,mHeaderBGColor.get() /*% alpha*/,true); + + LLAccordionCtrlTab* parent = dynamic_cast(getParent()); + bool collapsible = (parent && parent->getCollapsible()); + bool expanded = (parent && parent->getDisplayChildren()); + + // Handle overlay images, if needed + // Only show green "focus" background image if the accordion is open, + // because the user's mental model of focus is that it goes away after + // the accordion is closed. + if (getParent()->hasFocus() || mIsSelected + /*&& !(collapsible && !expanded)*/ // WHY?? + ) + { + mImageHeaderFocused->draw(0,0,width,height); + } + else + { + mImageHeader->draw(0,0,width,height); + } + + if(mNeedsHighlight) + { + mImageHeaderOver->draw(0,0,width,height); + } + + + if(collapsible) + { + LLPointer overlay_image; + if(expanded) + { + overlay_image = mImageExpanded; + } + else + { + overlay_image = mImageCollapsed; + } + overlay_image->draw(HEADER_IMAGE_LEFT_OFFSET, + (height - overlay_image->getHeight()) / 2); + } + + LLUICtrl::draw(); +} + +void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::reshape(S32 width, S32 height, BOOL called_from_parent /* = TRUE */) +{ + S32 header_height = mHeaderTextbox->getTextPixelHeight(); + + LLRect textboxRect(HEADER_TEXT_LEFT_OFFSET,(height+header_height)/2 ,width,(height-header_height)/2); + mHeaderTextbox->reshape(textboxRect.getWidth(), textboxRect.getHeight()); + mHeaderTextbox->setRect(textboxRect); + + if (mHeaderTextbox->getTextPixelWidth() > mHeaderTextbox->getRect().getWidth()) + { + setToolTip(mHeaderTextbox->getText()); + } + else + { + setToolTip(LLStringUtil::null); + } +} + +void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::onMouseEnter(S32 x, S32 y, MASK mask) +{ + LLUICtrl::onMouseEnter(x, y, mask); + mNeedsHighlight = true; +} +void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::onMouseLeave(S32 x, S32 y, MASK mask) +{ + LLUICtrl::onMouseLeave(x, y, mask); + mNeedsHighlight = false; + mAutoOpenTimer.stop(); +} +BOOL LLAccordionCtrlTab::LLAccordionCtrlTabHeader::handleKey(KEY key, MASK mask, BOOL called_from_parent) +{ + if ( ( key == KEY_LEFT || key == KEY_RIGHT) && mask == MASK_NONE) + { + return getParent()->handleKey(key, mask, called_from_parent); + } + return LLUICtrl::handleKey(key, mask, called_from_parent); +} +BOOL LLAccordionCtrlTab::LLAccordionCtrlTabHeader::handleDragAndDrop(S32 x, S32 y, MASK mask, + BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg) +{ + LLAccordionCtrlTab* parent = dynamic_cast(getParent()); + + if ( parent && !parent->getDisplayChildren() && parent->getCollapsible() && parent->canOpenClose() ) + { + if (mAutoOpenTimer.getStarted()) + { + if (mAutoOpenTimer.getElapsedTimeF32() > AUTO_OPEN_TIME) + { + parent->changeOpenClose(false); + mAutoOpenTimer.stop(); + return TRUE; + } + } + else + mAutoOpenTimer.start(); + } + + return LLUICtrl::handleDragAndDrop(x, y, mask, drop, cargo_type, + cargo_data, accept, tooltip_msg); +} +LLAccordionCtrlTab::Params::Params() + : title("title") + ,display_children("expanded", true) + ,header_height("header_height", HEADER_HEIGHT), + min_width("min_width", 0), + min_height("min_height", 0) + ,collapsible("collapsible", true) + ,header_bg_color("header_bg_color") + ,dropdown_bg_color("dropdown_bg_color") + ,header_visible("header_visible",true) + ,padding_left("padding_left",2) + ,padding_right("padding_right",2) + ,padding_top("padding_top",2) + ,padding_bottom("padding_bottom",2) + ,header_expand_img("header_expand_img") + ,header_expand_img_pressed("header_expand_img_pressed") + ,header_collapse_img("header_collapse_img") + ,header_collapse_img_pressed("header_collapse_img_pressed") + ,header_image("header_image") + ,header_image_over("header_image_over") + ,header_image_pressed("header_image_pressed") + ,header_image_focused("header_image_focused") + ,header_text_color("header_text_color") + ,fit_panel("fit_panel",true) + ,selection_enabled("selection_enabled", false) +{ + changeDefault(mouse_opaque, false); +} + +LLAccordionCtrlTab::LLAccordionCtrlTab(const LLAccordionCtrlTab::Params&p) + : LLUICtrl(p) + ,mDisplayChildren(p.display_children) + ,mCollapsible(p.collapsible) + ,mExpandedHeight(0) + ,mDropdownBGColor(p.dropdown_bg_color()) + ,mHeaderVisible(p.header_visible) + ,mPaddingLeft(p.padding_left) + ,mPaddingRight(p.padding_right) + ,mPaddingTop(p.padding_top) + ,mPaddingBottom(p.padding_bottom) + ,mCanOpenClose(true) + ,mFitPanel(p.fit_panel) + ,mSelectionEnabled(p.selection_enabled) + ,mContainerPanel(NULL) + ,mScrollbar(NULL) +{ + mStoredOpenCloseState = false; + mWasStateStored = false; + + mDropdownBGColor = LLColor4::white; + LLAccordionCtrlTabHeader::Params headerParams(p); + headerParams.name(DD_HEADER_NAME); + headerParams.title(p.title); + mHeader = LLUICtrlFactory::create(headerParams); + addChild(mHeader, 1); + + LLFocusableElement::setFocusReceivedCallback(boost::bind(&LLAccordionCtrlTab::selectOnFocusReceived, this)); + + if (!p.selection_enabled) + { + LLFocusableElement::setFocusLostCallback(boost::bind(&LLAccordionCtrlTab::deselectOnFocusLost, this)); + } + + reshape(100, 200,FALSE); +} + +LLAccordionCtrlTab::~LLAccordionCtrlTab() +{ +} + + +void LLAccordionCtrlTab::setDisplayChildren(bool display) +{ + mDisplayChildren = display; + LLRect rect = getRect(); + + rect.mBottom = rect.mTop - (getDisplayChildren() ? + mExpandedHeight : HEADER_HEIGHT); + setRect(rect); + + if(mContainerPanel) + mContainerPanel->setVisible(getDisplayChildren()); + + if(mDisplayChildren) + { + adjustContainerPanel(); + } + else + { + if(mScrollbar) + mScrollbar->setVisible(false); + } + +} + +void LLAccordionCtrlTab::reshape(S32 width, S32 height, BOOL called_from_parent /* = TRUE */) +{ + LLRect headerRect; + + headerRect.setLeftTopAndSize( + 0,height,width,HEADER_HEIGHT); + mHeader->setRect(headerRect); + mHeader->reshape(headerRect.getWidth(), headerRect.getHeight()); + + if(!mDisplayChildren) + return; + + LLRect childRect; + + childRect.setLeftTopAndSize( + getPaddingLeft(), + height - getHeaderHeight() - getPaddingTop(), + width - getPaddingLeft() - getPaddingRight(), + height - getHeaderHeight() - getPaddingTop() - getPaddingBottom() ); + + adjustContainerPanel(childRect); +} + +void LLAccordionCtrlTab::changeOpenClose(bool is_open) +{ + if(is_open) + mExpandedHeight = getRect().getHeight(); + + setDisplayChildren(!is_open); + reshape(getRect().getWidth(), getRect().getHeight(), FALSE); + if (mCommitSignal) + { + (*mCommitSignal)(this, getDisplayChildren()); + } +} + +/*void LLAccordionCtrlTab::onVisibilityChange(BOOL new_visibility) +{ + LLUICtrl::onVisibilityChange(new_visibility); + + notifyParent(LLSD().with("child_visibility_change", new_visibility)); +}*/ + +BOOL LLAccordionCtrlTab::handleMouseDown(S32 x, S32 y, MASK mask) +{ + if(mCollapsible && mHeaderVisible && mCanOpenClose) + { + if(y >= (getRect().getHeight() - HEADER_HEIGHT) ) + { + mHeader->setFocus(true); + changeOpenClose(getDisplayChildren()); + + //reset stored state + mWasStateStored = false; + return TRUE; + } + } + return LLUICtrl::handleMouseDown(x,y,mask); +} + +BOOL LLAccordionCtrlTab::handleMouseUp(S32 x, S32 y, MASK mask) +{ + return LLUICtrl::handleMouseUp(x,y,mask); +} + +boost::signals2::connection LLAccordionCtrlTab::setDropDownStateChangedCallback(commit_callback_t cb) +{ + return setCommitCallback(cb); +} + +bool LLAccordionCtrlTab::addChild(LLView* child, S32 tab_group) +{ + if(DD_HEADER_NAME != child->getName()) + { + reshape(child->getRect().getWidth() , child->getRect().getHeight() + HEADER_HEIGHT ); + mExpandedHeight = getRect().getHeight(); + } + + bool res = LLUICtrl::addChild(child, tab_group); + + if(DD_HEADER_NAME != child->getName()) + { + if(!mCollapsible) + setDisplayChildren(true); + else + setDisplayChildren(getDisplayChildren()); + } + + if (!mContainerPanel) + mContainerPanel = findContainerView(); + + return res; +} + +void LLAccordionCtrlTab::setAccordionView(LLView* panel) +{ + addChild(panel,0); +} + +std::string LLAccordionCtrlTab::getTitle() const +{ + if (mHeader) + { + return mHeader->getTitle(); + } + else + { + return LLStringUtil::null; + } +} + +void LLAccordionCtrlTab::setTitle(const std::string& title, const std::string& hl) +{ + if (mHeader) + { + mHeader->setTitle(title, hl); + } +} + +void LLAccordionCtrlTab::setTitleFontStyle(std::string style) +{ + if (mHeader) + { + mHeader->setTitleFontStyle(style); + } +} + +void LLAccordionCtrlTab::setTitleColor(LLUIColor color) +{ + if (mHeader) + { + mHeader->setTitleColor(color); + } +} + +boost::signals2::connection LLAccordionCtrlTab::setFocusReceivedCallback(const focus_signal_t::slot_type& cb) +{ + if (mHeader) + { + return mHeader->setFocusReceivedCallback(cb); + } + return boost::signals2::connection(); +} + +boost::signals2::connection LLAccordionCtrlTab::setFocusLostCallback(const focus_signal_t::slot_type& cb) +{ + if (mHeader) + { + return mHeader->setFocusLostCallback(cb); + } + return boost::signals2::connection(); +} + +void LLAccordionCtrlTab::setSelected(bool is_selected) +{ + if (mHeader) + { + mHeader->setSelected(is_selected); + } +} + +LLView* LLAccordionCtrlTab::findContainerView() +{ + for(child_list_const_iter_t it = getChildList()->begin(); + getChildList()->end() != it; ++it) + { + LLView* child = *it; + if(DD_HEADER_NAME == child->getName()) + continue; + if(!child->getVisible()) + continue; + return child; + } + return NULL; +} + +void LLAccordionCtrlTab::selectOnFocusReceived() +{ + if (getParent()) // A parent may not be set if tabs are added dynamically. + getParent()->notifyParent(LLSD().with("action", "select_current")); +} + +void LLAccordionCtrlTab::deselectOnFocusLost() +{ + if(getParent()) // A parent may not be set if tabs are added dynamically. + { + getParent()->notifyParent(LLSD().with("action", "deselect_current")); + } + +} + +S32 LLAccordionCtrlTab::getHeaderHeight() +{ + return mHeaderVisible?HEADER_HEIGHT:0; +} + +void LLAccordionCtrlTab::setHeaderVisible(bool value) +{ + if(mHeaderVisible == value) + return; + mHeaderVisible = value; + if(mHeader) + mHeader->setVisible(value); + reshape(getRect().getWidth(), getRect().getHeight(), FALSE); +}; + +//virtual +BOOL LLAccordionCtrlTab::postBuild() +{ + if(mHeader) + mHeader->setVisible(mHeaderVisible); + + static LLUICachedControl scrollbar_size ("UIScrollbarSize", 0); + + LLRect scroll_rect; + scroll_rect.setOriginAndSize( + getRect().getWidth() - scrollbar_size, + 1, + scrollbar_size, + getRect().getHeight() - 1); + + mContainerPanel = findContainerView(); + + if(!mFitPanel) + { + mScrollbar = new LLScrollbar("scrollable vertical", scroll_rect, LLScrollbar::VERTICAL, getRect().getHeight(), 0, getRect().getHeight(), boost::bind(&LLAccordionCtrlTab::onScrollPosChangeCallback, this, _1, _2), VERTICAL_MULTIPLE); + mScrollbar->setFollows(FOLLOWS_RIGHT | FOLLOWS_TOP | FOLLOWS_BOTTOM); + LLView::addChild( mScrollbar ); + mScrollbar->setFollows(FOLLOWS_RIGHT|FOLLOWS_TOP|FOLLOWS_BOTTOM); + + mScrollbar->setVisible(false); + } + + if(mContainerPanel) + mContainerPanel->setVisible(mDisplayChildren); + + return LLUICtrl::postBuild(); +} +bool LLAccordionCtrlTab::notifyChildren (const LLSD& info) +{ + if(info.has("action")) + { + std::string str_action = info["action"]; + if(str_action == "store_state") + { + storeOpenCloseState(); + return true; + } + if(str_action == "restore_state") + { + restoreOpenCloseState(); + return true; + } + } + return LLUICtrl::notifyChildren(info); +} + +S32 LLAccordionCtrlTab::notifyParent(const LLSD& info) +{ + if(info.has("action")) + { + std::string str_action = info["action"]; + if(str_action == "size_changes") + { + // + S32 height = info["height"]; + height = llmax(height,10) + HEADER_HEIGHT + getPaddingTop() + getPaddingBottom(); + + mExpandedHeight = height; + + if(isExpanded()) + { + LLRect panel_rect = getRect(); + panel_rect.setLeftTopAndSize( panel_rect.mLeft, panel_rect.mTop, panel_rect.getWidth(), height); + reshape(getRect().getWidth(),height); + setRect(panel_rect); + } + + //LLAccordionCtrl should rearrange accordion tab if one of accordion change its size + if (getParent()) // A parent may not be set if tabs are added dynamically. + getParent()->notifyParent(info); + return 1; + } + else if(str_action == "select_prev") + { + showAndFocusHeader(); + return 1; + } + } + else if (info.has("scrollToShowRect")) + { + LLAccordionCtrl* parent = dynamic_cast(getParent()); + if (parent && parent->getFitParent()) + { + // EXT-8285 ('No attachments worn' text appears at the bottom of blank 'Attachments' accordion) + // The problem was in passing message "scrollToShowRect" IN LLAccordionCtrlTab::notifyParent + // FROM child LLScrollContainer TO parent LLAccordionCtrl with "it_parent" set to true. + + // It is wrong notification for parent accordion which leads to recursive call of adjustContainerPanel + // As the result of recursive call of adjustContainerPanel we got LLAccordionCtrlTab + // that reshaped and re-sized with different rectangles. + + // LLAccordionCtrl has own scrollContainer and LLAccordionCtrlTab has own scrollContainer + // both should handle own scroll container's event. + // So, if parent accordion "fit_parent" accordion tab should handle its scroll container events itself. + + return 1; + } + + if (!getDisplayChildren()) + { + // Don't pass scrolling event further if our contents are invisible (STORM-298). + return 1; + } + } + + return LLUICtrl::notifyParent(info); +} + +S32 LLAccordionCtrlTab::notify(const LLSD& info) +{ + if(info.has("action")) + { + std::string str_action = info["action"]; + if(str_action == "select_first") + { + showAndFocusHeader(); + return 1; + } + else if( str_action == "select_last" ) + { + if(getDisplayChildren() == false) + { + showAndFocusHeader(); + } + else + { + LLView* view = getAccordionView(); + if(view) + view->notify(LLSD().with("action","select_last")); + } + } + } + return 0; +} + +BOOL LLAccordionCtrlTab::handleKey(KEY key, MASK mask, BOOL called_from_parent) +{ + if( !mHeader->hasFocus() ) + return LLUICtrl::handleKey(key, mask, called_from_parent); + + if ( (key == KEY_RETURN )&& mask == MASK_NONE) + { + changeOpenClose(getDisplayChildren()); + return TRUE; + } + + if ( (key == KEY_ADD || key == KEY_RIGHT)&& mask == MASK_NONE) + { + if(getDisplayChildren() == false) + { + changeOpenClose(getDisplayChildren()); + return TRUE; + } + } + if ( (key == KEY_SUBTRACT || key == KEY_LEFT)&& mask == MASK_NONE) + { + if(getDisplayChildren() == true) + { + changeOpenClose(getDisplayChildren()); + return TRUE; + } + } + + if ( key == KEY_DOWN && mask == MASK_NONE) + { + //if collapsed go to the next accordion + if(getDisplayChildren() == false) + //we processing notifyParent so let call parent directly + getParent()->notifyParent(LLSD().with("action","select_next")); + else + { + getAccordionView()->notify(LLSD().with("action","select_first")); + } + return TRUE; + } + + if ( key == KEY_UP && mask == MASK_NONE) + { + //go to the previous accordion + + //we processing notifyParent so let call parent directly + getParent()->notifyParent(LLSD().with("action","select_prev")); + return TRUE; + } + + return LLUICtrl::handleKey(key, mask, called_from_parent); +} + +void LLAccordionCtrlTab::showAndFocusHeader() +{ + mHeader->setFocus(true); + mHeader->setSelected(mSelectionEnabled); + + LLRect screen_rc; + LLRect selected_rc = mHeader->getRect(); + localRectToScreen(selected_rc, &screen_rc); + + // This call to notifyParent() is intended to deliver "scrollToShowRect" command + // to the parent LLAccordionCtrl so by calling it from the direct parent of this + // accordion tab (assuming that the parent is an LLAccordionCtrl) the calls chain + // is shortened and messages from inside the collapsed tabs are avoided. + // See STORM-536. + getParent()->notifyParent(LLSD().with("scrollToShowRect",screen_rc.getValue())); +} +void LLAccordionCtrlTab::storeOpenCloseState() +{ + if(mWasStateStored) + return; + mStoredOpenCloseState = getDisplayChildren(); + mWasStateStored = true; +} + +void LLAccordionCtrlTab::restoreOpenCloseState() +{ + if(!mWasStateStored) + return; + if(getDisplayChildren() != mStoredOpenCloseState) + { + changeOpenClose(getDisplayChildren()); + } + mWasStateStored = false; +} + +void LLAccordionCtrlTab::adjustContainerPanel () +{ + S32 width = getRect().getWidth(); + S32 height = getRect().getHeight(); + + LLRect child_rect; + child_rect.setLeftTopAndSize( + getPaddingLeft(), + height - getHeaderHeight() - getPaddingTop(), + width - getPaddingLeft() - getPaddingRight(), + height - getHeaderHeight() - getPaddingTop() - getPaddingBottom() ); + + adjustContainerPanel(child_rect); +} + +void LLAccordionCtrlTab::adjustContainerPanel(const LLRect& child_rect) +{ + if(!mContainerPanel) + return; + + if(!mFitPanel) + { + show_hide_scrollbar(child_rect); + updateLayout(child_rect); + } + else + { + mContainerPanel->reshape(child_rect.getWidth(),child_rect.getHeight()); + mContainerPanel->setRect(child_rect); + } +} + +S32 LLAccordionCtrlTab::getChildViewHeight() +{ + if(!mContainerPanel) + return 0; + return mContainerPanel->getRect().getHeight(); +} + +void LLAccordionCtrlTab::show_hide_scrollbar(const LLRect& child_rect) +{ + if(getChildViewHeight() > child_rect.getHeight() ) + showScrollbar(child_rect); + else + hideScrollbar(child_rect); +} +void LLAccordionCtrlTab::showScrollbar(const LLRect& child_rect) +{ + if(!mContainerPanel || !mScrollbar) + return; + bool was_visible = mScrollbar->getVisible(); + mScrollbar->setVisible(true); + + static LLUICachedControl scrollbar_size ("UIScrollbarSize", 0); + + { + ctrlSetLeftTopAndSize(mScrollbar,child_rect.getWidth()-scrollbar_size, + child_rect.getHeight()-PARENT_BORDER_MARGIN, + scrollbar_size, + child_rect.getHeight()-2*PARENT_BORDER_MARGIN); + } + + LLRect orig_rect = mContainerPanel->getRect(); + + mScrollbar->setPageSize(child_rect.getHeight()); + mScrollbar->setDocParams(orig_rect.getHeight(),mScrollbar->getDocPos()); + + if(was_visible) + { + S32 scroll_pos = llmin(mScrollbar->getDocPos(), orig_rect.getHeight() - child_rect.getHeight() - 1); + mScrollbar->setDocPos(scroll_pos); + } + else//shrink child panel + { + updateLayout(child_rect); + } + +} + +void LLAccordionCtrlTab::hideScrollbar( const LLRect& child_rect ) +{ + if(!mContainerPanel || !mScrollbar) + return; + + if(mScrollbar->getVisible() == false) + return; + mScrollbar->setVisible(false); + mScrollbar->setDocPos(0); + + //shrink child panel + updateLayout(child_rect); +} + +void LLAccordionCtrlTab::onScrollPosChangeCallback(S32, LLScrollbar*) +{ + LLRect child_rect; + + S32 width = getRect().getWidth(); + S32 height = getRect().getHeight(); + + child_rect.setLeftTopAndSize( + getPaddingLeft(), + height - getHeaderHeight() - getPaddingTop(), + width - getPaddingLeft() - getPaddingRight(), + height - getHeaderHeight() - getPaddingTop() - getPaddingBottom() ); + + updateLayout(child_rect); +} + +void LLAccordionCtrlTab::drawChild(const LLRect& root_rect,LLView* child) +{ + if (child && child->getVisible() && child->getRect().isValid()) + { + LLRect screen_rect; + localRectToScreen(child->getRect(),&screen_rect); + + if ( root_rect.overlaps(screen_rect) /*&& LLUI::sDirtyRect.overlaps(screen_rect)*/)// Singu TODO: LLUI::sDirtyRect + { + gGL.matrixMode(LLRender::MM_MODELVIEW); + LLUI::pushMatrix(); + { + LLUI::translate((F32)child->getRect().mLeft, (F32)child->getRect().mBottom); + child->draw(); + + } + LLUI::popMatrix(); + } + } +} + +void LLAccordionCtrlTab::draw() +{ + if(mFitPanel) + LLUICtrl::draw(); + else + { + LLRect root_rect = getRootView()->getRect(); + drawChild(root_rect,mHeader); + drawChild(root_rect,mScrollbar ); + { + LLRect child_rect; + + S32 width = getRect().getWidth(); + S32 height = getRect().getHeight(); + + child_rect.setLeftTopAndSize( + getPaddingLeft(), + height - getHeaderHeight() - getPaddingTop(), + width - getPaddingLeft() - getPaddingRight(), + height - getHeaderHeight() - getPaddingTop() - getPaddingBottom() ); + + LLLocalClipRect clip(child_rect); + drawChild(root_rect,mContainerPanel); + } + } +} + +void LLAccordionCtrlTab::updateLayout ( const LLRect& child_rect ) +{ + LLView* child = getAccordionView(); + if(!mContainerPanel) + return; + + S32 panel_top = child_rect.getHeight(); + S32 panel_width = child_rect.getWidth(); + + static LLUICachedControl scrollbar_size ("UIScrollbarSize", 0); + if(mScrollbar && mScrollbar->getVisible() != false) + { + panel_top+=mScrollbar->getDocPos(); + panel_width-=scrollbar_size; + } + + //set sizes for first panels and dragbars + LLRect panel_rect = child->getRect(); + ctrlSetLeftTopAndSize(mContainerPanel,child_rect.mLeft,panel_top,panel_width,panel_rect.getHeight()); +} +void LLAccordionCtrlTab::ctrlSetLeftTopAndSize(LLView* panel, S32 left, S32 top, S32 width, S32 height) +{ + if(!panel) + return; + LLRect panel_rect = panel->getRect(); + panel_rect.setLeftTopAndSize( left, top, width, height); + panel->reshape( width, height, 1); + panel->setRect(panel_rect); +} +BOOL LLAccordionCtrlTab::handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_rect) +{ + //header may be not the first child but we need to process it first + if(y >= (getRect().getHeight() - HEADER_HEIGHT - HEADER_HEIGHT/2) ) + { + //inside tab header + //fix for EXT-6619 + mHeader->handleToolTip(x, y, msg, sticky_rect); + return TRUE; + } + return LLUICtrl::handleToolTip(x, y, msg, sticky_rect); +} +BOOL LLAccordionCtrlTab::handleScrollWheel ( S32 x, S32 y, S32 clicks ) +{ + if( LLUICtrl::handleScrollWheel(x,y,clicks)) + { + return TRUE; + } + if( mScrollbar && mScrollbar->getVisible() && mScrollbar->handleScrollWheel( 0, 0, clicks ) ) + { + return TRUE; + } + return FALSE; +} + +//static +LLView* LLAccordionCtrlTab::fromXML(LLXMLNodePtr node, LLView* parent, LLUICtrlFactory* factory) +{ + Params p; + // Singu TODO: Widgets folder for defaults instead of shoving into params here where noted + if (node->hasAttribute("title")) + { + std::string title; + node->getAttributeString("title", title); + p.title(title); + } + + if (node->hasAttribute("expanded")) + { + bool display_children; + node->getAttribute_bool("expanded", display_children); + p.display_children(display_children); + } + + if (node->hasAttribute("header_height")) + { + S32 header_height; + node->getAttributeS32("header_height", header_height); + p.header_height(header_height); + } + + if (node->hasAttribute("min_width")) + { + S32 min_width; + node->getAttributeS32("min_width", min_width); + p.min_width(min_width); + } + + if (node->hasAttribute("min_width")) + { + S32 min_height; + node->getAttributeS32("min_height", min_height); + p.min_height(min_height); + } + + if (node->hasAttribute("collapsible")) + { + bool collapsible; + node->getAttribute_bool("collapsible", collapsible); + p.collapsible(collapsible); + } + + if (node->hasAttribute("header_bg_color")) + { + LLColor4 color; + node->getAttributeColor("header_bg_color", color); + p.header_bg_color(color); + } + else // widget + { + p.header_bg_color(LLUI::sColorsGroup->getColor("ButtonUnselectedBgColor")); // was DkGray2 + } + + if (node->hasAttribute("dropdown_bg_color")) + { + LLColor4 color; + node->getAttributeColor("dropdown_bg_color", color); + p.dropdown_bg_color(color); + } + + if (node->hasAttribute("header_visible")) + { + bool header_visible; + node->getAttribute_bool("header_visible", header_visible); + p.header_visible(header_visible); + } + + if (node->hasAttribute("padding_left")) + { + S32 padding_left; + node->getAttributeS32("padding_left", padding_left); + p.padding_left(padding_left); + } + + if (node->hasAttribute("padding_right")) + { + S32 padding_right; + node->getAttributeS32("padding_right", padding_right); + p.padding_right(padding_right); + } + + if (node->hasAttribute("padding_top")) + { + S32 padding_top; + node->getAttributeS32("padding_top", padding_top); + p.padding_top(padding_top); + } + + if (node->hasAttribute("padding_bottom")) + { + S32 padding_bottom; + node->getAttributeS32("padding_bottom", padding_bottom); + p.padding_bottom(padding_bottom); + } + + if (node->hasAttribute("header_expand_img")) + { + std::string image; + node->getAttributeString("header_expand_img", image); + p.header_expand_img.name(image); + } + else // widget + { + p.header_expand_img.name("Accordion_ArrowOpened_Off"); + } + + if (node->hasAttribute("header_expand_img_pressed")) + { + std::string image; + node->getAttributeString("header_expand_img_pressed", image); + p.header_expand_img_pressed.name(image); + } + else // widget + { + p.header_expand_img_pressed.name("Accordion_ArrowOpened_Press"); + } + + if (node->hasAttribute("header_collapse_img")) + { + std::string image; + node->getAttributeString("header_collapse_img", image); + p.header_collapse_img.name(image); + } + else // widget + { + p.header_collapse_img.name("Accordion_ArrowClosed_Off"); + } + + if (node->hasAttribute("header_collapse_img_pressed")) + { + std::string image; + node->getAttributeString("header_collapse_img_pressed", image); + p.header_collapse_img_pressed.name(image); + } + else // widget + { + p.header_collapse_img_pressed.name("Accordion_ArrowClosed_Press"); + } + + if (node->hasAttribute("header_image")) + { + std::string image; + node->getAttributeString("header_image", image); + p.header_image.name(image); + } + else // widget + { + p.header_image.name("Accordion_Off"); + } + + if (node->hasAttribute("header_image_over")) + { + std::string image; + node->getAttributeString("header_image_over", image); + p.header_image_over.name(image); + } + else // widget + { + p.header_image_over.name("Accordion_Over"); + } + + if (node->hasAttribute("header_image_pressed")) + { + std::string image; + node->getAttributeString("header_image_pressed", image); + p.header_image_pressed.name(image); + } + else // widget + { + p.header_image_pressed.name("Accordion_Press"); + } + + if (node->hasAttribute("header_image_focused")) + { + std::string image; + node->getAttributeString("header_image_focused", image); + p.header_image_focused.name(image); + } + else // widget + { + p.header_image_focused.name("Accordion_Selected"); + } + + if (node->hasAttribute("header_text_color")) + { + LLColor4 color; + node->getAttributeColor("header_text_color", color); + p.header_text_color(color); + } + else // widget + { + p.header_text_color(LLUI::sColorsGroup->getColor("ButtonLabelColor")); // AccordionHeaderTextColor + } + + if (node->hasAttribute("fit_panel")) + { + bool fit_panel; + node->getAttribute_bool("fit_panel", fit_panel); + p.fit_panel(fit_panel); + } + + if (node->hasAttribute("selection_enabled")) + { + bool selection_enabled; + node->getAttribute_bool("selection_enabled", selection_enabled); + p.selection_enabled(selection_enabled); + } + + if (node->hasAttribute("font")) + { + std::string font; + node->getAttributeString("font", font); + p.font.name(font); + } + else // widget + { + p.font.name("SansSerif"); + } + + LLAccordionCtrlTab* ctrl = new LLAccordionCtrlTab(p); + ctrl->initFromXML(node, parent); + return ctrl; +} diff --git a/indra/llui/llaccordionctrltab.h b/indra/llui/llaccordionctrltab.h new file mode 100644 index 0000000000..45321c85c5 --- /dev/null +++ b/indra/llui/llaccordionctrltab.h @@ -0,0 +1,248 @@ +/** + * @file LLAccordionCtrlTab.h + * @brief Collapsible box control implementation + * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_ACCORDIONCTRLTAB_H_ +#define LL_ACCORDIONCTRLTAB_H_ + +#include +#include "llrect.h" +#include "lluictrl.h" +#include "lluicolor.h" +#include "llstyle.h" + +class LLUICtrlFactory; +class LLUIImage; +class LLButton; +class LLTextBox; +class LLScrollbar; + + + +// LLAccordionCtrlTab is a container for other controls. +// It has a Header, by clicking on which hosted controls are shown or hidden. +// When hosted controls are show - LLAccordionCtrlTab is expanded. +// When hosted controls are hidden - LLAccordionCtrlTab is collapsed. + +class LLAccordionCtrlTab : public LLUICtrl +{ +// Interface +public: + + struct Params + : public LLInitParam::Block + { + Optional display_children, //expanded or collapsed after initialization + collapsible; + + Optional title; + + Optional header_height, + min_width, + min_height; + + // Overlay images (arrows on the left) + Mandatory header_expand_img, + header_expand_img_pressed, + header_collapse_img, + header_collapse_img_pressed; + + // Background images for the accordion tabs + Mandatory header_image, + header_image_over, + header_image_pressed, + header_image_focused; + + Optional header_bg_color, + header_text_color, + dropdown_bg_color; + + Optional header_visible; + + Optional fit_panel; + + Optional selection_enabled; + + Optional padding_left, + padding_right, + padding_top, + padding_bottom; + + Params(); + }; + +// typedef LLDefaultChildRegistry child_registry_t; // Singu TODO: NOTE: This comes in with the VMM merge. + + virtual ~LLAccordionCtrlTab(); + + // Registers callback for expand/collapse events. + boost::signals2::connection setDropDownStateChangedCallback(commit_callback_t cb); + + // Changes expand/collapse state + virtual void setDisplayChildren(bool display); + + // Returns expand/collapse state + virtual bool getDisplayChildren() const {return mDisplayChildren;}; + + //set LLAccordionCtrlTab panel + void setAccordionView(LLView* panel); + LLView* getAccordionView() { return mContainerPanel; }; + + std::string getTitle() const; + + // Set text and highlight substring in LLAccordionCtrlTabHeader + void setTitle(const std::string& title, const std::string& hl = LLStringUtil::null); + + // Set text font style in LLAccordionCtrlTabHeader + void setTitleFontStyle(std::string style); + + // Set text color in LLAccordionCtrlTabHeader + void setTitleColor(LLUIColor color); + + boost::signals2::connection setFocusReceivedCallback(const focus_signal_t::slot_type& cb); + boost::signals2::connection setFocusLostCallback(const focus_signal_t::slot_type& cb); + + void setSelected(bool is_selected); + + bool getCollapsible() {return mCollapsible;}; + + void setCollapsible(bool collapsible) {mCollapsible = collapsible;}; + void changeOpenClose(bool is_open); + + void canOpenClose(bool can_open_close) { mCanOpenClose = can_open_close;}; + bool canOpenClose() const { return mCanOpenClose; }; + + virtual BOOL postBuild(); + static LLView* fromXML(LLXMLNodePtr node, LLView* parent, class LLUICtrlFactory* factory); + + S32 notifyParent(const LLSD& info); + S32 notify(const LLSD& info); + bool notifyChildren(const LLSD& info); + + void draw(); + + void storeOpenCloseState (); + void restoreOpenCloseState (); + +protected: + LLAccordionCtrlTab(const LLAccordionCtrlTab::Params&); + friend class LLUICtrlFactory; + +// Overrides +public: + + // Call reshape after changing size + virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + + /** + * Raises notifyParent event with "child_visibility_change" = new_visibility + */ + //void onVisibilityChange(BOOL new_visibility); + + // Changes expand/collapse state and triggers expand/collapse callbacks + virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); + + virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); + virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); + + virtual BOOL handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_rect); + virtual BOOL handleScrollWheel( S32 x, S32 y, S32 clicks ); + + + virtual bool addChild(LLView* child, S32 tab_group = 0 ); + + bool isExpanded() const { return mDisplayChildren; } + + S32 getHeaderHeight(); + + // Min size functions + + void setHeaderVisible(bool value); + + bool getHeaderVisible() { return mHeaderVisible;} + + S32 mExpandedHeight; // Height of expanded ctrl. + // Used to restore height after expand. + + S32 getPaddingLeft() const { return mPaddingLeft;} + S32 getPaddingRight() const { return mPaddingRight;} + S32 getPaddingTop() const { return mPaddingTop;} + S32 getPaddingBottom() const { return mPaddingBottom;} + + void showAndFocusHeader(); + + void setFitPanel( bool fit ) { mFitPanel = true; } + bool getFitParent() const { return mFitPanel; } + +protected: + void adjustContainerPanel (const LLRect& child_rect); + void adjustContainerPanel (); + S32 getChildViewHeight (); + + void onScrollPosChangeCallback(S32, LLScrollbar*); + + void show_hide_scrollbar (const LLRect& child_rect); + void showScrollbar (const LLRect& child_rect); + void hideScrollbar (const LLRect& child_rect); + + void updateLayout ( const LLRect& child_rect ); + void ctrlSetLeftTopAndSize (LLView* panel, S32 left, S32 top, S32 width, S32 height); + + void drawChild(const LLRect& root_rect,LLView* child); + + LLView* findContainerView (); + + void selectOnFocusReceived(); + void deselectOnFocusLost(); + +private: + + class LLAccordionCtrlTabHeader; + LLAccordionCtrlTabHeader* mHeader; //Header + + bool mDisplayChildren; //Expanded/collapsed + bool mCollapsible; + bool mHeaderVisible; + + bool mCanOpenClose; + bool mFitPanel; + + S32 mPaddingLeft; + S32 mPaddingRight; + S32 mPaddingTop; + S32 mPaddingBottom; + + bool mStoredOpenCloseState; + bool mWasStateStored; + + bool mSelectionEnabled; + + LLScrollbar* mScrollbar; + LLView* mContainerPanel; + + LLUIColor mDropdownBGColor; +}; + +#endif diff --git a/indra/llui/llalertdialog.cpp b/indra/llui/llalertdialog.cpp index 739eb61d4d..b7cef0a2ec 100644 --- a/indra/llui/llalertdialog.cpp +++ b/indra/llui/llalertdialog.cpp @@ -48,6 +48,7 @@ #include "lluictrlfactory.h" #include "llnotifications.h" #include "llfunctorregistry.h" +#include "lldraghandle.h" const S32 MAX_ALLOWED_MSG_WIDTH = 400; const F32 DEFAULT_BUTTON_DELAY = 0.5f; @@ -186,7 +187,7 @@ LLAlertDialog::LLAlertDialog( LLNotificationPtr notification, bool modal) // Message: create text box using raw string, as text has been structure deliberately // Use size of created text box to generate dialog box size std::string msg = mNote->getMessage(); - llwarns << "Alert: " << msg << llendl; + LL_WARNS() << "Alert: " << msg << LL_ENDL; LLTextBox* msg_box = new LLTextBox( std::string("Alert message"), msg, (F32)MAX_ALLOWED_MSG_WIDTH, font ); const LLRect& text_rect = msg_box->getRect(); @@ -233,6 +234,12 @@ LLAlertDialog::LLAlertDialog( LLNotificationPtr notification, bool modal) msg_box->setColor( LLUI::sColorsGroup->getColor( "AlertTextColor" ) ); } + LLDragHandle* handle = getDragHandle(); + if (handle) + { + getDragHandle()->setTextColor(LLUI::sColorsGroup->getColor(mCaution ? "AlertCautionTextColor" : "AlertTextColor")); + } + LLRect rect; rect.setLeftTopAndSize( msg_x, msg_y, text_rect.getWidth(), text_rect.getHeight() ); msg_box->setRect( rect ); @@ -257,6 +264,10 @@ LLAlertDialog::LLAlertDialog( LLNotificationPtr notification, bool modal) button_data.mText); btn->setClickedCallback(boost::bind(&LLAlertDialog::onButtonPressed, this, _1, button_data.mUrl)); + if (mCaution) + { + btn->setColor(LLUI::sColorsGroup->getColor("ButtonCautionImageColor")); + } addChild(btn); @@ -370,6 +381,11 @@ bool LLAlertDialog::setCheckBox( const std::string& check_title, const std::stri max_msg_width, LINE_HEIGHT); mCheck = new LLCheckboxCtrl(std::string("check"), check_rect, check_title, font, boost::bind(&LLAlertDialog::onClickIgnore, this, _1)); + mCheck->setEnabledColor(LLUI::sColorsGroup->getColor( mCaution ? "AlertCautionTextColor" : "AlertTextColor")); + if (mCaution) + { + mCheck->setButtonColor(LLUI::sColorsGroup->getColor("ButtonCautionImageColor")); + } addChild(mCheck); return true; @@ -504,7 +520,7 @@ void LLAlertDialog::setEditTextArgs(const LLSD& edit_args) } else { - llwarns << "LLAlertDialog::setEditTextArgs called on dialog with no line editor" << llendl; + LL_WARNS() << "LLAlertDialog::setEditTextArgs called on dialog with no line editor" << LL_ENDL; } } diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp index daa7de213e..120c378dfa 100644 --- a/indra/llui/llbutton.cpp +++ b/indra/llui/llbutton.cpp @@ -61,66 +61,92 @@ S32 BTN_HEIGHT = 0; S32 BTN_GRID = 12; S32 BORDER_SIZE = 1; + +LLButton::Params::Params() + : label_selected("label_selected"), // requires is_toggle true + label_shadow("label_shadow", true), + auto_resize("auto_resize", false), + use_ellipses("use_ellipses", false), + image_unselected("image_unselected", LLUI::getUIImage("button_enabled_32x128.tga")), + image_selected("image_selected", LLUI::getUIImage("button_enabled_selected_32x128.tga")), + image_hover_selected("image_hover_selected"), + image_hover_unselected("image_hover_unselected"), + image_disabled_selected("image_disabled_selected", LLUI::getUIImage("button_disabled_32x128.tga")), + image_disabled("image_disabled", LLUI::getUIImage("button_disabled_32x128.tga")), + image_pressed("image_pressed", LLUI::getUIImage("button_enabled_selected_32x128.tga")), + image_pressed_selected("image_pressed_selected", LLUI::getUIImage("button_enabled_32x128.tga")), + image_overlay("image_overlay"), + image_overlay_selected("image_overlay_selected"), + image_overlay_alignment("image_overlay_alignment", std::string("center")), + image_overlay_enable("image_overlay_enable", true), + label_color("label_color", LLUI::sColorsGroup->getColor("ButtonLabelColor")), + label_color_selected("label_color_selected", LLUI::sColorsGroup->getColor("ButtonLabelSelectedColor")), + label_color_disabled("label_color_disabled", LLUI::sColorsGroup->getColor("ButtonLabelDisabledColor")), + label_color_disabled_selected("label_color_disabled_selected", LLUI::sColorsGroup->getColor("ButtonLabelSelectedDisabledColor")), + image_color("image_color", LLUI::sColorsGroup->getColor("ButtonImageColor")), // requires is_toggle true + image_color_disabled("image_color_disabled", LLUI::sColorsGroup->getColor("ButtonImageColor")), + image_overlay_color("image_overlay_color", LLColor4::white), + image_overlay_selected_color("image_overlay_selected_color", LLColor4::white), + image_overlay_disabled_color("image_overlay_disabled_color", LLColor4(1.f, 1.f, 1.f, .5f)), + flash_color("flash_color", LLUI::sColorsGroup->getColor("ButtonFlashBgColor")), + pad_right("pad_right", LLUI::sConfigGroup->getS32("ButtonHPad")), + pad_left("pad_left", LLUI::sConfigGroup->getS32("ButtonHPad")), + pad_bottom("pad_bottom", LLUI::sConfigGroup->getS32("ButtonVPad")), + image_top_pad("image_top_pad"), + image_bottom_pad("image_bottom_pad"), + imgoverlay_label_space("imgoverlay_label_space", 1), + click_callback("click_callback"), + mouse_down_callback("mouse_down_callback"), + mouse_up_callback("mouse_up_callback"), + mouse_held_callback("mouse_held_callback"), + is_toggle("is_toggle", false), + scale_image("scale_image", true), + commit_on_return("commit_on_return", true), + display_pressed_state("display_pressed_state", true), + hover_glow_amount("hover_glow_amount", 0.25f), + //held_down_delay("held_down_delay"), + use_draw_context_alpha("use_draw_context_alpha", true), + //badge("badge"), + handle_right_mouse("handle_right_mouse", false), + button_flash_enable("button_flash_enable", false), + button_flash_count("button_flash_count", LLUI::sConfigGroup->getS32("ButtonFlashCount")), + button_flash_rate("button_flash_rate", LLUI::sConfigGroup->getF32("ButtonFlashRate")), + fade_when_disabled("fade_when_disabled", false), + help_url("help_url") +{ + addSynonym(is_toggle, "toggle"); + changeDefault(initial_value, LLSD(false)); + changeDefault(font_halign, LLFontGL::HCENTER); +} + LLButton::LLButton( const std::string& name, const LLRect& rect, const std::string& control_name, commit_callback_t commit_callback) : LLUICtrl(name, rect, TRUE, commit_callback), - - mMouseDownFrame( 0 ), + mMouseDownFrame(0), mMouseHeldDownCount(0), - mBorderEnabled( FALSE ), - mFlashing( FALSE ), + mBorderEnabled(FALSE), + mFlashing(FALSE), mCurGlowStrength(0.f), mNeedsHighlight(FALSE), - mUnselectedLabel(name), - mSelectedLabel(name), - mGLFont( LLFontGL::getFontSansSerif() ), - mHeldDownDelay( 0.5f ), // seconds until held-down callback is called - mHeldDownFrameDelay( 0 ), - mImageUnselected(LLUI::getUIImage("button_enabled_32x128.tga")), - mImageSelected(LLUI::getUIImage("button_enabled_selected_32x128.tga")), - mImageDisabled(LLUI::getUIImage("button_disabled_32x128.tga")), - mImageDisabledSelected(LLUI::getUIImage("button_disabled_32x128.tga")), - mImagePressed(LLUI::getUIImage("button_enabled_selected_32x128.tga")), - mImagePressedSelected(LLUI::getUIImage("button_enabled_32x128.tga")), + mHeldDownDelay(0.5f), // seconds until held-down callback is called + mHeldDownFrameDelay(0), mImageFlash(NULL), - mImageHoverSelected( NULL ), - mImageHoverUnselected( NULL ), - mUnselectedLabelColor(LLUI::sColorsGroup->getColor("ButtonLabelColor" )), - mSelectedLabelColor(LLUI::sColorsGroup->getColor("ButtonLabelSelectedColor")), - mDisabledLabelColor(LLUI::sColorsGroup->getColor("ButtonLabelDisabledColor")), - mDisabledSelectedLabelColor(LLUI::sColorsGroup->getColor("ButtonLabelSelectedDisabledColor")), - mImageColor(LLUI::sColorsGroup->getColor("ButtonImageColor")), - mFlashBgColor(LLUI::sColorsGroup->getColor("ButtonFlashBgColor")), - mDisabledImageColor(LLUI::sColorsGroup->getColor("ButtonImageColor")), - mImageOverlay(NULL), - mImageOverlayColor(LLColor4::white), - mImageOverlayDisabledColor(LLColor4(1.f,1.f,1.f,.5f)), - mImageOverlaySelectedColor(LLColor4::white), - mImageOverlayAlignment(LLFontGL::HCENTER), mImageOverlayTopPad(0), mImageOverlayBottomPad(0), mImgOverlayLabelSpace(1), - mIsToggle( FALSE ), - mScaleImage( TRUE ), - mDropShadowedText( TRUE ), - mAutoResize( FALSE ), - mHAlign( LLFontGL::HCENTER ), - mLeftHPad( LLBUTTON_H_PAD ), - mRightHPad( LLBUTTON_H_PAD ), - mBottomVPad( LLBUTTON_V_PAD ), - mHoverGlowStrength(0.25f), - mCommitOnReturn(TRUE), - mFadeWhenDisabled(FALSE), + mDropShadowedText(TRUE), mForcePressedState(false), - mDisplayPressedState(TRUE), - mMouseDownSignal(NULL), - mMouseUpSignal(NULL), - mHeldDownSignal(NULL), - mHandleRightMouse(false), - mButtonFlashCount(LLUI::sConfigGroup->getS32("ButtonFlashCount")), - mButtonFlashRate(LLUI::sConfigGroup->getF32("ButtonFlashRate")), - mAlpha(1.f) + mAlpha(1.f), + mMouseDownSignal(nullptr), + mMouseUpSignal(nullptr), + mHeldDownSignal(nullptr) { - init(control_name); + Params params; + params.label_selected(name) + .label(name) + .control_name(control_name) + .name(name) + .rect(rect); + initFromParams(params); } @@ -133,92 +159,133 @@ LLButton::LLButton(const std::string& name, const LLRect& rect, const std::string& unselected_label, const std::string& selected_label ) : LLUICtrl(name, rect, TRUE, commit_callback), - mMouseDownFrame( 0 ), + mMouseDownFrame(0), mMouseHeldDownCount(0), - mBorderEnabled( FALSE ), - mFlashing( FALSE ), + mBorderEnabled(FALSE), + mFlashing(FALSE), mCurGlowStrength(0.f), mNeedsHighlight(FALSE), - mUnselectedLabel(unselected_label), - mSelectedLabel(selected_label), - mGLFont( font ? font : LLFontGL::getFontSansSerif() ), - mHeldDownDelay( 0.5f ), // seconds until held-down callback is called - mHeldDownFrameDelay( 0 ), - mImageUnselected(LLUI::getUIImage("button_enabled_32x128.tga")), - mImageSelected(LLUI::getUIImage("button_enabled_selected_32x128.tga")), - mImageDisabled(LLUI::getUIImage("button_disabled_32x128.tga")), - mImageDisabledSelected(LLUI::getUIImage("button_disabled_32x128.tga")), - mImagePressed(LLUI::getUIImage("button_enabled_selected_32x128.tga")), - mImagePressedSelected(LLUI::getUIImage("button_enabled_32x128.tga")), + mHeldDownDelay(0.5f), // seconds until held-down callback is called + mHeldDownFrameDelay(0), mImageFlash(NULL), - mImageHoverSelected( NULL ), - mImageHoverUnselected( NULL ), - mUnselectedLabelColor(LLUI::sColorsGroup->getColor("ButtonLabelColor" )), - mSelectedLabelColor(LLUI::sColorsGroup->getColor("ButtonLabelSelectedColor")), - mDisabledLabelColor(LLUI::sColorsGroup->getColor("ButtonLabelDisabledColor")), - mDisabledSelectedLabelColor(LLUI::sColorsGroup->getColor("ButtonLabelSelectedDisabledColor")), - mImageColor(LLUI::sColorsGroup->getColor("ButtonImageColor")), - mFlashBgColor(LLUI::sColorsGroup->getColor("ButtonFlashBgColor")), - mDisabledImageColor(LLUI::sColorsGroup->getColor("ButtonImageColor")), - mImageOverlay(NULL), - mImageOverlayColor(LLColor4::white), - mImageOverlayDisabledColor(LLColor4(1.f,1.f,1.f,.5f)), - mImageOverlaySelectedColor(LLColor4::white), - mImageOverlayAlignment(LLFontGL::HCENTER), mImageOverlayTopPad(0), mImageOverlayBottomPad(0), mImgOverlayLabelSpace(1), - mIsToggle( FALSE ), - mScaleImage( TRUE ), - mDropShadowedText( TRUE ), - mAutoResize( FALSE ), - mHAlign( LLFontGL::HCENTER ), - mLeftHPad( LLBUTTON_H_PAD ), - mRightHPad( LLBUTTON_H_PAD ), - mBottomVPad( LLBUTTON_V_PAD ), - mHoverGlowStrength(0.25f), - mCommitOnReturn(TRUE), - mFadeWhenDisabled(FALSE), + mDropShadowedText(TRUE), mForcePressedState(false), - mDisplayPressedState(TRUE), - mMouseDownSignal(NULL), - mMouseUpSignal(NULL), - mHeldDownSignal(NULL), - mHandleRightMouse(false), - mButtonFlashCount(LLUI::sConfigGroup->getS32("ButtonFlashCount")), - mButtonFlashRate(LLUI::sConfigGroup->getF32("ButtonFlashRate")), - mAlpha(1.f) + mAlpha(1.f), + mMouseDownSignal(nullptr), + mMouseUpSignal(nullptr), + mHeldDownSignal(nullptr) { - - if( unselected_image_name != "" ) + Params params; + params.label_selected(selected_label) + .label(unselected_label) + .font(font) + .control_name(control_name) + .name(name) + .rect(rect); + + if (!unselected_image_name.empty()) { // user-specified image - don't use fixed borders unless requested - mImageUnselected = LLUI::getUIImage(unselected_image_name); - mImageDisabled = mImageUnselected; + auto image = LLUI::getUIImage(unselected_image_name); + params.image_unselected(image) + .image_disabled(image) + .image_pressed_selected(image) - mFadeWhenDisabled = TRUE; - //mScaleImage = FALSE; - - mImagePressedSelected = mImageUnselected; + .fade_when_disabled(true); + //params.scale_image(false); } - if( selected_image_name != "" ) + if (!selected_image_name.empty()) { // user-specified image - don't use fixed borders unless requested - mImageSelected = LLUI::getUIImage(selected_image_name); - mImageDisabledSelected = mImageSelected; + auto image = LLUI::getUIImage(selected_image_name); + params.image_selected(image) + .image_disabled_selected(image) + .image_pressed(image) - mFadeWhenDisabled = TRUE; - //mScaleImage = FALSE; - - mImagePressed = mImageSelected; + .fade_when_disabled(true); + //params.scale_image(false); } - init(control_name); + initFromParams(params); +} + +LLButton::LLButton(const Params& params) +: LLUICtrl(params), + mMouseDownFrame(0), + mMouseHeldDownCount(0), + mBorderEnabled(FALSE), + mFlashing(FALSE), + mCurGlowStrength(0.f), + mNeedsHighlight(FALSE), + mHeldDownDelay(0.5f), // seconds until held-down callback is called + mHeldDownFrameDelay(0), + mImageFlash(NULL), + mImageOverlayTopPad(0), + mImageOverlayBottomPad(0), + mImgOverlayLabelSpace(1), + mDropShadowedText(TRUE), + mForcePressedState(false), + mAlpha(1.f), + mMouseDownSignal(nullptr), + mMouseUpSignal(nullptr), + mHeldDownSignal(nullptr) +{ + initFromParams(params); } -void LLButton::init(const std::string& control_name) +void LLButton::initFromParams(const Params& params) { + LLUICtrl::initFromParams(params); + mUnselectedLabel = params.label; + mSelectedLabel = params.label_selected; + auto font = params.font(); + mGLFont = font ? font : LLFontGL::getFontSansSerif(); + mHAlign = params.font_halign; + mImageUnselected = params.image_unselected; + mImageSelected = params.image_selected; + mImageDisabled = params.image_disabled; + mImageDisabledSelected = params.image_disabled_selected; + mImagePressed = params.image_pressed; + mImagePressedSelected = params.image_pressed_selected; + mImageHoverSelected = params.image_hover_selected; + mImageHoverUnselected = params.image_hover_unselected; + mUnselectedLabelColor = params.label_color; + mSelectedLabelColor = params.label_color_selected; + mDisabledLabelColor = params.label_color_disabled; + mDisabledSelectedLabelColor = params.label_color_disabled_selected; + mImageColor = params.image_color; + mFlashBgColor = params.flash_color; + mDisabledImageColor = params.image_color_disabled; + mImageOverlay = params.image_overlay; + mImageOverlaySelected = params.image_overlay_selected; + mImageOverlayColor = params.image_overlay_color; + mImageOverlayDisabledColor = params.image_overlay_disabled_color; + mImageOverlaySelectedColor = params.image_overlay_selected_color; + mImageOverlayAlignment = LLFontGL::hAlignFromName(params.image_overlay_alignment); + mIsToggle = params.is_toggle; + mScaleImage = params.scale_image; + mAutoResize = params.auto_resize; + mLeftHPad = params.pad_left; + mRightHPad = params.pad_right; + mBottomVPad = params.pad_bottom; + mHoverGlowStrength = params.hover_glow_amount; + mCommitOnReturn = params.commit_on_return; + mFadeWhenDisabled = params.fade_when_disabled; + mDisplayPressedState = params.display_pressed_state; + if (params.mouse_down_callback.isProvided()) + setMouseDownCallback(params.mouse_down_callback); + if (params.mouse_up_callback.isProvided()) + setMouseUpCallback(params.mouse_up_callback); + if (params.mouse_held_callback.isProvided()) + setHeldDownCallback(params.mouse_held_callback); + mHandleRightMouse = params.handle_right_mouse; + mButtonFlashCount = params.button_flash_count; + mButtonFlashRate = params.button_flash_rate; + // Hack to make sure there is space for at least one character if (getRect().getWidth() - (mRightHPad + mLeftHPad) < mGLFont->getWidth(std::string(" "))) { @@ -229,9 +296,16 @@ void LLButton::init(const std::string& control_name) mMouseDownTimer.stop(); - setControlName(control_name, NULL); + setControlName(params.control_name, NULL); } +//static +const LLButton::Params& LLButton::getDefaultParams() +{ + // Singu Note: We diverge here, not using LLUICtrlFactory::getDefaultParams + static const Params p; + return p; +} // virtual LLButton::~LLButton() @@ -272,7 +346,7 @@ void LLButton::onCommit() LLUICtrl::onCommit(); } -/*boost::signals2::connection LLButton::setClickedCallback(const CommitCallbackParam& cb) +boost::signals2::connection LLButton::setClickedCallback(const CommitCallbackParam& cb) { return setClickedCallback(initCommitCallback(cb)); } @@ -287,7 +361,7 @@ boost::signals2::connection LLButton::setMouseUpCallback(const CommitCallbackPar boost::signals2::connection LLButton::setHeldDownCallback(const CommitCallbackParam& cb) { return setHeldDownCallback(initCommitCallback(cb)); -}*/ +} boost::signals2::connection LLButton::setClickedCallback( const commit_signal_t::slot_type& cb ) @@ -387,7 +461,7 @@ BOOL LLButton::handleMouseDown(S32 x, S32 y, MASK mask) if(mMouseDownSignal) (*mMouseDownSignal)(this, LLSD()); mMouseDownTimer.start(); - mMouseDownFrame = (S32) LLFrameTimer::getFrameCount(); + mMouseDownFrame = LLFrameTimer::getFrameCount(); mMouseHeldDownCount = 0; @@ -515,7 +589,7 @@ BOOL LLButton::handleHover(S32 x, S32 y, MASK mask) if (mMouseDownTimer.getStarted()) { F32 elapsed = getHeldDownTime(); - if( mHeldDownDelay <= elapsed && mHeldDownFrameDelay <= (S32)LLFrameTimer::getFrameCount() - mMouseDownFrame) + if( mHeldDownDelay <= elapsed && mHeldDownFrameDelay <= LLFrameTimer::getFrameCount() - mMouseDownFrame) { LLSD param; param["count"] = mMouseHeldDownCount++; @@ -525,7 +599,7 @@ BOOL LLButton::handleHover(S32 x, S32 y, MASK mask) // We only handle the click if the click both started and ended within us getWindow()->setCursor(UI_CURSOR_ARROW); - lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << llendl; + LL_DEBUGS("UserInput") << "hover handled by " << getName() << LL_ENDL; } return TRUE; } @@ -536,8 +610,8 @@ void LLButton::getOverlayImageSize(S32& overlay_width, S32& overlay_height) overlay_height = mImageOverlay->getHeight(); F32 scale_factor = llmin((F32)getRect().getWidth() / (F32)overlay_width, (F32)getRect().getHeight() / (F32)overlay_height, 1.f); - overlay_width = llround((F32)overlay_width * scale_factor); - overlay_height = llround((F32)overlay_height * scale_factor); + overlay_width = ll_round((F32)overlay_width * scale_factor); + overlay_height = ll_round((F32)overlay_height * scale_factor); } @@ -696,7 +770,7 @@ void LLButton::draw() if (hasFocus()) { F32 lerp_amt = gFocusMgr.getFocusFlashAmt(); - drawBorder(imagep, gFocusMgr.getFocusColor() % alpha, llround(lerp(1.f, 3.f, lerp_amt))); + drawBorder(imagep, gFocusMgr.getFocusColor() % alpha, ll_round(lerp(1.f, 3.f, lerp_amt))); } if (use_glow_effect) @@ -704,11 +778,11 @@ void LLButton::draw() mCurGlowStrength = lerp(mCurGlowStrength, mFlashing ? (flash? 1.0 : 0.0) : mHoverGlowStrength, - LLCriticalDamp::getInterpolant(0.05f)); + LLSmoothInterpolation::getInterpolant(0.05f)); } else { - mCurGlowStrength = lerp(mCurGlowStrength, 0.f, LLCriticalDamp::getInterpolant(0.05f)); + mCurGlowStrength = lerp(mCurGlowStrength, 0.f, LLSmoothInterpolation::getInterpolant(0.05f)); } // Draw button image, if available. @@ -741,7 +815,7 @@ void LLButton::draw() else { // no image - lldebugs << "No image for button " << getName() << llendl; + LL_DEBUGS() << "No image for button " << getName() << LL_ENDL; // draw it in pink so we can find it gl_rect_2d(0, getRect().getHeight(), getRect().getWidth(), 0, LLColor4::pink1 % alpha, FALSE); } @@ -783,12 +857,13 @@ void LLButton::draw() } overlay_color.mV[VALPHA] *= alpha; + auto& overlay = (mIsToggle && mImageOverlaySelected && getToggleState()) ? mImageOverlaySelected : mImageOverlay; switch(mImageOverlayAlignment) { case LLFontGL::LEFT: text_left += overlay_width + mImgOverlayLabelSpace; text_width -= overlay_width + mImgOverlayLabelSpace; - mImageOverlay->draw( + overlay->draw( mLeftHPad, center_y - (overlay_height / 2), overlay_width, @@ -796,7 +871,7 @@ void LLButton::draw() overlay_color); break; case LLFontGL::HCENTER: - mImageOverlay->draw( + overlay->draw( center_x - (overlay_width / 2), center_y - (overlay_height / 2), overlay_width, @@ -806,7 +881,7 @@ void LLButton::draw() case LLFontGL::RIGHT: text_right -= overlay_width + mImgOverlayLabelSpace; text_width -= overlay_width + mImgOverlayLabelSpace; - mImageOverlay->draw( + overlay->draw( getRect().getWidth() - mRightHPad - overlay_width, center_y - (overlay_height / 2), overlay_width, @@ -958,7 +1033,7 @@ void LLButton::setImageUnselected(LLPointer image) mImageUnselected = image; if (mImageUnselected.isNull()) { - llwarns << "Setting default button image for: " << getName() << " to NULL" << llendl; + LL_WARNS() << "Setting default button image for: " << getName() << " to NULL" << LL_ENDL; } } @@ -981,7 +1056,7 @@ void LLButton::resize(LLUIString label) { S32 overlay_width = mImageOverlay->getWidth(); F32 scale_factor = (getRect().getHeight() - (mImageOverlayBottomPad + mImageOverlayTopPad)) / (F32)mImageOverlay->getHeight(); - overlay_width = llround((F32)overlay_width * scale_factor); + overlay_width = ll_round((F32)overlay_width * scale_factor); switch(mImageOverlayAlignment) { @@ -1199,6 +1274,9 @@ LLView* LLButton::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *fa std::string image_overlay; node->getAttributeString("image_overlay", image_overlay); + std::string image_overlay_selected; + node->getAttributeString("image_overlay_selected", image_overlay_selected); + LLFontGL::HAlign image_overlay_alignment = LLFontGL::HCENTER; std::string image_overlay_alignment_string; if (node->hasAttribute("image_overlay_alignment")) @@ -1234,6 +1312,7 @@ LLView* LLButton::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *fa if(image_disabled != LLStringUtil::null) button->setImageDisabled(LLUI::getUIImage(image_disabled)); if(image_overlay != LLStringUtil::null) button->setImageOverlay(image_overlay, image_overlay_alignment); + if (!image_overlay_selected.empty()) button->mImageOverlaySelected = LLUI::getUIImage(image_overlay_selected); if (node->hasAttribute("halign")) { diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h index 5710585fd2..dfa405f63a 100644 --- a/indra/llui/llbutton.h +++ b/indra/llui/llbutton.h @@ -74,6 +74,87 @@ class LLButton : public LLUICtrl { public: + struct Params + : public LLInitParam::Block + { + // text label + Optional label_selected; + Optional label_shadow; + Optional auto_resize; + Optional use_ellipses; + + // images + Optional image_unselected, + image_selected, + image_hover_selected, + image_hover_unselected, + image_disabled_selected, + image_disabled, + image_flash, + image_pressed, + image_pressed_selected, + image_overlay, + image_overlay_selected; + + Optional image_overlay_alignment; + Optional image_overlay_enable; + + // colors + Optional label_color, + label_color_selected, + label_color_disabled, + label_color_disabled_selected, + image_color, + image_color_disabled, + image_overlay_color, + image_overlay_selected_color, + image_overlay_disabled_color, + flash_color; + + // layout + Optional pad_right; + Optional pad_left; + Optional pad_bottom; // under text label + + //image overlay paddings + Optional image_top_pad; + Optional image_bottom_pad; + + /** + * Space between image_overlay and label + */ + Optional imgoverlay_label_space; + + // callbacks + Optional click_callback, // alias -> commit_callback + mouse_down_callback, + mouse_up_callback, + mouse_held_callback; + + // misc + Optional is_toggle, + scale_image, + commit_on_return, + display_pressed_state; + + Optional hover_glow_amount; + //Optional held_down_delay; + + Optional use_draw_context_alpha; + + //Optional badge; + + Optional handle_right_mouse; + + Optional button_flash_enable; + Optional button_flash_count; + Optional button_flash_rate; + Optional fade_when_disabled; + Optional help_url; + + Params(); + }; + // simple button with text label LLButton(const std::string& name, const LLRect &rect = LLRect(), const std::string& control_name = std::string(), commit_callback_t commit_callback = NULL); @@ -86,6 +167,11 @@ class LLButton const LLFontGL* mGLFont = NULL, const std::string& unselected_label = LLStringUtil::null, const std::string& selected_label = LLStringUtil::null ); + + void initFromParams(const Params& p); + static const LLButton::Params& getDefaultParams(); + LLButton(const Params& p = getDefaultParams()); + public: ~LLButton(); @@ -93,7 +179,6 @@ class LLButton typedef boost::function button_callback_t; void addImageAttributeToXML(LLXMLNodePtr node, const LLPointer, const std::string& xmlTagName) const; - void init(const std::string& control_name); virtual LLXMLNodePtr getXML(bool save_children = true) const; static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); @@ -116,10 +201,10 @@ class LLButton void setSelectedLabelColor( const LLColor4& c ) { mSelectedLabelColor = c; } - /*boost::signals2::connection setClickedCallback(const CommitCallbackParam& cb); + boost::signals2::connection setClickedCallback(const CommitCallbackParam& cb); boost::signals2::connection setMouseDownCallback(const CommitCallbackParam& cb); boost::signals2::connection setMouseUpCallback(const CommitCallbackParam& cb); - boost::signals2::connection setHeldDownCallback(const CommitCallbackParam& cb);*/ + boost::signals2::connection setHeldDownCallback(const CommitCallbackParam& cb); boost::signals2::connection setClickedCallback( const commit_signal_t::slot_type& cb ); // mouse down and up within button boost::signals2::connection setMouseDownCallback( const commit_signal_t::slot_type& cb ); @@ -161,7 +246,6 @@ class LLButton const std::string getLabelUnselected() const { return wstring_to_utf8str(mUnselectedLabel); } const std::string getLabelSelected() const { return wstring_to_utf8str(mSelectedLabel); } - void setImageColor(const std::string& color_control); void setImageColor(const LLColor4& c); /*virtual*/ void setColor(const LLColor4& c); @@ -205,12 +289,7 @@ class LLButton void setImageDisabled(LLPointer image); void setImageDisabledSelected(LLPointer image); void setImageFlash(LLPointer image); - void setImagePressed(LLPointer image); - - void setCommitOnReturn(BOOL commit) { mCommitOnReturn = commit; } - BOOL getCommitOnReturn() const { return mCommitOnReturn; } - static void onHeldDown(void *userdata); // to be called by gIdleCallbacks void setHelpURLCallback(const std::string &help_url); const std::string& getHelpURL() const { return mHelpURL; } @@ -240,12 +319,13 @@ class LLButton const LLFontGL *mGLFont; - S32 mMouseDownFrame; + U64 mMouseDownFrame; S32 mMouseHeldDownCount; // Counter for parameter passed to held-down callback F32 mHeldDownDelay; // seconds, after which held-down callbacks get called S32 mHeldDownFrameDelay; // frames, after which held-down callbacks get called LLPointer mImageOverlay; + LLPointer mImageOverlaySelected; LLFontGL::HAlign mImageOverlayAlignment; LLUIColor mImageOverlayColor; LLUIColor mImageOverlaySelectedColor; diff --git a/indra/llui/llcallbackmap.h b/indra/llui/llcallbackmap.h index 2ad6d54c50..b92febdb20 100644 --- a/indra/llui/llcallbackmap.h +++ b/indra/llui/llcallbackmap.h @@ -35,7 +35,10 @@ #include #include +#ifndef BOOST_FUNCTION_HPP_INCLUDED #include +#define BOOST_FUNCTION_HPP_INCLUDED +#endif class LLCallbackMap { diff --git a/indra/llui/llcheckboxctrl.cpp b/indra/llui/llcheckboxctrl.cpp index ada81b6397..ad0166f4e9 100644 --- a/indra/llui/llcheckboxctrl.cpp +++ b/indra/llui/llcheckboxctrl.cpp @@ -83,7 +83,7 @@ LLCheckBoxCtrl::LLCheckBoxCtrl(const std::string& name, const LLRect& rect, // Label (add a little space to make sure text actually renders) const S32 FUDGE = 10; S32 text_width = mFont->getWidth( label ) + FUDGE; - S32 text_height = llround(mFont->getLineHeight()); + S32 text_height = ll_round(mFont->getLineHeight()); LLRect label_rect; label_rect.setOriginAndSize( LLCHECKBOXCTRL_HPAD + LLCHECKBOXCTRL_BTN_SIZE + LLCHECKBOXCTRL_SPACING, @@ -93,13 +93,14 @@ LLCheckBoxCtrl::LLCheckBoxCtrl(const std::string& name, const LLRect& rect, // *HACK Get rid of this with SL-55508... // this allows blank check boxes and radio boxes for now - std::string local_label = label; + // Singu Note: Don't do this. Slows rendering down dramatically, and also seems to not fix anything? + /*std::string local_label = label; if(local_label.empty()) { local_label = " "; - } + }*/ - mLabel = new LLTextBox( std::string("CheckboxCtrl Label"), label_rect, local_label, mFont ); + mLabel = new LLTextBox( std::string("CheckboxCtrl Label"), label_rect, label, mFont ); mLabel->setFollowsLeft(); mLabel->setFollowsBottom(); addChild(mLabel); @@ -187,7 +188,7 @@ void LLCheckBoxCtrl::reshape(S32 width, S32 height, BOOL called_from_parent) //stretch or shrink bounding rectangle of label when rebuilding UI at new scale const S32 FUDGE = 10; S32 text_width = mFont->getWidth( mLabel->getText() ) + FUDGE; - S32 text_height = llround(mFont->getLineHeight()); + S32 text_height = ll_round(mFont->getLineHeight()); LLRect label_rect; label_rect.setOriginAndSize( LLCHECKBOXCTRL_HPAD + LLCHECKBOXCTRL_BTN_SIZE + LLCHECKBOXCTRL_SPACING, diff --git a/indra/llui/llcheckboxctrl.h b/indra/llui/llcheckboxctrl.h index 47eb46670a..c0fdf842dc 100644 --- a/indra/llui/llcheckboxctrl.h +++ b/indra/llui/llcheckboxctrl.h @@ -100,8 +100,10 @@ class LLCheckBoxCtrl // LLCheckBoxCtrl interface virtual BOOL toggle() { return mButton->toggleState(); } // returns new state - void setEnabledColor( const LLColor4 &color ) { mTextEnabledColor = color; } - void setDisabledColor( const LLColor4 &color ) { mTextDisabledColor = color; } + void setEnabledColor(const LLColor4 &color) { mTextEnabledColor = color; setEnabled(getEnabled()); } + void setDisabledColor( const LLColor4 &color ) { mTextDisabledColor = color; setEnabled(getEnabled()); } + + void setButtonColor(const LLColor4 &color) { if (mButton) mButton->setColor(color); } void setLabel( const LLStringExplicit& label ); std::string getLabel() const; diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp index 64d003f0be..284aa77506 100644 --- a/indra/llui/llcombobox.cpp +++ b/indra/llui/llcombobox.cpp @@ -160,20 +160,24 @@ LLView* LLComboBox::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory * LLComboBox* combo_box = new LLComboBox("combo_box", rect, label); combo_box->setAllowTextEntry(allow_text_entry, max_chars); + if (LLFontGL* font = selectFont(node)) + combo_box->mButton->setFont(font); + const std::string& contents = node->getValue(); if (contents.find_first_not_of(" \n\t") != contents.npos) { - llerrs << "Legacy combo box item format used! Please convert to tags!" << llendl; + LL_ERRS() << "Legacy combo box item format used! Please convert to tags!" << LL_ENDL; } else { LLXMLNodePtr child; for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling()) { - if (child->hasName("combo_item")) + if (child->hasName("combo_item") || child->hasName("combo_box.item")) { std::string label = child->getTextContents(); + child->getAttributeString("label", label); std::string value = label; child->getAttributeString("value", value); @@ -193,11 +197,17 @@ LLView* LLComboBox::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory * //Do this AFTER combo_items are set up so setValue is actually able to select the correct initial entry. combo_box->initFromXML(node, parent); + // if we haven't already gotten a value from our control_name and // if providing user text entry or descriptive label // don't select an item under the hood - if (!combo_box->acceptsTextInput() && combo_box->mLabel.empty()) + if (combo_box->getControlName().empty()) { - combo_box->selectFirstItem(); + const auto text = combo_box->acceptsTextInput(); + std::string label; + if (node->getAttributeString("label", label)) + text ? combo_box->setLabel(label) : (void)combo_box->mList->selectItemByLabel(label, FALSE); + else if (!text && combo_box->mLabel.empty()) + combo_box->selectFirstItem(); } return combo_box; @@ -431,12 +441,12 @@ void LLComboBox::setLabel(const LLStringExplicit& name) { if (!mSuppressTentative) mTextEntry->setTentative(mTextEntryTentative); } + mTextEntry->setCursor(0); // Be scrolled to the beginning! } if (!mAllowTextEntry) { - mButton->setLabelUnselected(name); - mButton->setLabelSelected(name); + mButton->setLabel(name); } } @@ -454,9 +464,7 @@ void LLComboBox::updateLabel() // the combo button label. if (!mAllowTextEntry) { - std::string label = getSelectedItemLabel(); - mButton->setLabelUnselected(label); - mButton->setLabelSelected(label); + mButton->setLabel(getSelectedItemLabel()); } } @@ -502,13 +510,16 @@ void LLComboBox::onFocusLost() void LLComboBox::setButtonVisible(BOOL visible) { + static LLUICachedControl drop_shadow_button ("DropShadowButton", 0); + mButton->setVisible(visible); if (mTextEntry) { LLRect text_entry_rect(0, getRect().getHeight(), getRect().getWidth(), 0); if (visible) { - text_entry_rect.mRight -= llmax(8,mArrowImage->getWidth()) + 2 * LLUI::sConfigGroup->getS32("DropShadowButton"); + S32 arrow_width = mArrowImage ? mArrowImage->getWidth() : 0; + text_entry_rect.mRight -= llmax(8,arrow_width) + 2 * drop_shadow_button; } //mTextEntry->setRect(text_entry_rect); mTextEntry->reshape(text_entry_rect.getWidth(), text_entry_rect.getHeight(), TRUE); @@ -547,18 +558,21 @@ S32 LLComboBox::getCurrentIndex() const void LLComboBox::updateLayout() { + static LLUICachedControl drop_shadow_button ("DropShadowButton", 0); LLRect rect = getLocalRect(); if (mAllowTextEntry) { - S32 shadow_size = LLUI::sConfigGroup->getS32("DropShadowButton"); - mButton->setRect(LLRect( getRect().getWidth() - llmax(8,mArrowImage->getWidth()) - 2 * shadow_size, + S32 arrow_width = mArrowImage ? mArrowImage->getWidth() : 0; + S32 shadow_size = drop_shadow_button; + mButton->setRect(LLRect( getRect().getWidth() - llmax(8,arrow_width) - 2 * shadow_size, rect.mTop, rect.mRight, rect.mBottom)); mButton->setTabStop(FALSE); + mButton->setHAlign(LLFontGL::HCENTER); if (!mTextEntry) { LLRect text_entry_rect(0, getRect().getHeight(), getRect().getWidth(), 0); - text_entry_rect.mRight -= llmax(8,mArrowImage->getWidth()) + 2 * shadow_size; + text_entry_rect.mRight -= llmax(8,arrow_width) + 2 * drop_shadow_button; // clear label on button std::string cur_label = mButton->getLabelSelected(); mTextEntry = new LLLineEditor(std::string("combo_text_entry"), @@ -707,6 +721,7 @@ void LLComboBox::showList() mList->setVisible(TRUE); setUseBoundingRect(TRUE); +// updateBoundingRect(); } void LLComboBox::hideList() @@ -733,6 +748,7 @@ void LLComboBox::hideList() { gFocusMgr.setTopCtrl(NULL); } +// updateBoundingRect(); } } @@ -908,6 +924,19 @@ BOOL LLComboBox::handleUnicodeCharHere(llwchar uni_char) return result; } +BOOL LLComboBox::handleScrollWheel(S32 x, S32 y, S32 clicks) +{ + if (mList->getVisible()) return mList->handleScrollWheel(x, y, clicks); + if (mAllowTextEntry) // We might be editable + if (!mList->getFirstSelected()) // We aren't in the list, don't kill their text + return false; + + setCurrentByIndex(llclamp(getCurrentIndex() + clicks, 0, getItemCount() - 1)); + prearrangeList(); + onCommit(); + return true; +} + void LLComboBox::setAllowTextEntry(BOOL allow, S32 max_chars, BOOL set_tentative) { mAllowTextEntry = allow; @@ -923,6 +952,7 @@ void LLComboBox::setTextEntry(const LLStringExplicit& text) if (mTextEntry) { mTextEntry->setText(text); + mTextEntry->setCursor(0); // Singu Note: Move the cursor over to the beginning mHasAutocompletedText = FALSE; updateSelection(); } @@ -1004,9 +1034,7 @@ void LLComboBox::onTextEntry(LLLineEditor* line_editor) void LLComboBox::updateSelection() { - if(mSuppressAutoComplete) { - return; - } + if(mSuppressAutoComplete) return; LLWString left_wstring = mTextEntry->getWText().substr(0, mTextEntry->getCursor()); // user-entered portion of string, based on assumption that any selected @@ -1217,3 +1245,25 @@ BOOL LLComboBox::selectItemRange( S32 first, S32 last ) return mList->selectItemRange(first, last); } + +/* Singu Note: This isn't very necessary for now, let's not bother. +static LLRegisterWidget register_icons_combo_box("icons_combo_box"); + +LLIconsComboBox::Params::Params() +: icon_column("icon_column", ICON_COLUMN), + label_column("label_column", LABEL_COLUMN) +{} + +LLIconsComboBox::LLIconsComboBox(const LLIconsComboBox::Params& p) +: LLComboBox(p), + mIconColumnIndex(p.icon_column), + mLabelColumnIndex(p.label_column) +{} + +const std::string LLIconsComboBox::getSelectedItemLabel(S32 column) const +{ + mButton->setImageOverlay(LLComboBox::getSelectedItemLabel(mIconColumnIndex), mButton->getImageOverlayHAlign()); + + return LLComboBox::getSelectedItemLabel(mLabelColumnIndex); +} +*/ diff --git a/indra/llui/llcombobox.h b/indra/llui/llcombobox.h index 2131ba06c1..4e180924ef 100644 --- a/indra/llui/llcombobox.h +++ b/indra/llui/llcombobox.h @@ -76,6 +76,7 @@ class LLComboBox virtual BOOL handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_rect); virtual BOOL handleKeyHere(KEY key, MASK mask); virtual BOOL handleUnicodeCharHere(llwchar uni_char); + virtual BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); // LLUICtrl interface virtual void clear(); // select nothing diff --git a/indra/llui/llcontainerview.cpp b/indra/llui/llcontainerview.cpp index f9ee54e9f7..ef4325f5be 100644 --- a/indra/llui/llcontainerview.cpp +++ b/indra/llui/llcontainerview.cpp @@ -178,7 +178,7 @@ void LLContainerView::arrange(S32 width, S32 height, BOOL called_from_parent) LLView *childp = *child_iter; if (!childp->getVisible()) { - llwarns << "Incorrect visibility!" << llendl; + LL_WARNS() << "Incorrect visibility!" << LL_ENDL; } LLRect child_rect = childp->getRequiredRect(); child_height += child_rect.getHeight(); diff --git a/indra/llui/lldraghandle.cpp b/indra/llui/lldraghandle.cpp index 33f1a1a1c7..741f1c6943 100644 --- a/indra/llui/lldraghandle.cpp +++ b/indra/llui/lldraghandle.cpp @@ -247,7 +247,7 @@ void LLDragHandleTop::reshapeTitleBox() S32 title_width = font->getWidth( getTitleBox()->getText() ) + TITLE_PAD; if (getMaxTitleWidth() > 0) title_width = llmin(title_width, getMaxTitleWidth()); - S32 title_height = llround(font->getLineHeight()); + S32 title_height = ll_round(font->getLineHeight()); LLRect title_rect; title_rect.setLeftTopAndSize( LEFT_PAD, @@ -301,6 +301,13 @@ BOOL LLDragHandle::handleMouseUp(S32 x, S32 y, MASK mask) return TRUE; } +void LLDragHandle::setTextColor(const LLColor4& color) +{ + if (mTitleBox) + { + mTitleBox->setColor(color); + } +} BOOL LLDragHandle::handleHover(S32 x, S32 y, MASK mask) { @@ -351,13 +358,13 @@ BOOL LLDragHandle::handleHover(S32 x, S32 y, MASK mask) mDragLastScreenY += delta_y; getWindow()->setCursor(UI_CURSOR_ARROW); - lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (active)" <setCursor(UI_CURSOR_ARROW); - lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (inactive)" << llendl; + LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (inactive)" << LL_ENDL; handled = TRUE; } diff --git a/indra/llui/lldraghandle.h b/indra/llui/lldraghandle.h index 9eb3e55a6c..a573d458d5 100644 --- a/indra/llui/lldraghandle.h +++ b/indra/llui/lldraghandle.h @@ -63,6 +63,8 @@ class LLDragHandle : public LLView virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); + virtual void setTextColor(const LLColor4& color); + protected: LLTextBox* getTitleBox() const { return mTitleBox; } void setTitleBox(LLTextBox*); diff --git a/indra/llui/lleditmenuhandler.h b/indra/llui/lleditmenuhandler.h index d72283cd99..966ab352e5 100644 --- a/indra/llui/lleditmenuhandler.h +++ b/indra/llui/lleditmenuhandler.h @@ -49,7 +49,7 @@ class LLEditMenuHandler virtual void cut() {}; virtual BOOL canCut() const { return FALSE; } - virtual void copy() {}; + virtual void copy() const {}; virtual BOOL canCopy() const { return FALSE; } virtual void paste() {}; diff --git a/indra/llui/llflatlistview.cpp b/indra/llui/llflatlistview.cpp new file mode 100644 index 0000000000..205bea49d3 --- /dev/null +++ b/indra/llui/llflatlistview.cpp @@ -0,0 +1,1464 @@ +/** + * @file llflatlistview.cpp + * @brief LLFlatListView base class and extension to support messages for several cases of an empty list. + * + * $LicenseInfo:firstyear=2009&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llpanel.h" +#include "lltextbox.h" +#include "lluictrlfactory.h" + +#include "llflatlistview.h" + +static const LLRegisterWidget flat_list_view("flat_list_view"); + +const LLSD SELECTED_EVENT = LLSD().with("selected", true); +const LLSD UNSELECTED_EVENT = LLSD().with("selected", false); + +//forward declaration +bool llsds_are_equal(const LLSD& llsd_1, const LLSD& llsd_2); + +LLFlatListView::Params::Params() +: allow_select("allow_select"), + multi_select("multi_select"), + keep_one_selected("keep_one_selected"), + keep_selection_visible_on_reshape("keep_selection_visible_on_reshape",false), + item_pad("item_pad"), + no_items_text("no_items_text") +{}; + +void LLFlatListView::reshape(S32 width, S32 height, BOOL called_from_parent /* = TRUE */) +{ + S32 delta = height - getRect().getHeight(); + LLScrollContainer::reshape(width, height, called_from_parent); + setItemsNoScrollWidth(width); + rearrangeItems(); + + if (delta!= 0 && mKeepSelectionVisibleOnReshape) + { + ensureSelectedVisible(); + } +} + +const LLRect& LLFlatListView::getItemsRect() const +{ + return mItemsPanel->getRect(); +} + +bool LLFlatListView::addItem(LLPanel * item, const LLSD& value /*= LLUUID::null*/, EAddPosition pos /*= ADD_BOTTOM*/,bool rearrange /*= true*/) +{ + if (!item) return false; + if (value.isUndefined()) return false; + + //force uniqueness of items, easiest check but unreliable + if (item->getParent() == mItemsPanel) return false; + + item_pair_t* new_pair = new item_pair_t(item, value); + switch (pos) + { + case ADD_TOP: + mItemPairs.push_front(new_pair); + //in LLView::draw() children are iterated in backorder + mItemsPanel->addChildInBack(item); + break; + case ADD_BOTTOM: + mItemPairs.push_back(new_pair); + mItemsPanel->addChild(item); + break; + default: + break; + } + + //_4 is for MASK + item->setMouseDownCallback(boost::bind(&LLFlatListView::onItemMouseClick, this, new_pair, _4)); + item->setRightMouseDownCallback(boost::bind(&LLFlatListView::onItemRightMouseClick, this, new_pair, _4)); + + // Children don't accept the focus + item->setTabStop(false); + + if (rearrange) + { + rearrangeItems(); + notifyParentItemsRectChanged(); + } + return true; +} + +bool LLFlatListView::addItemPairs(pairs_list_t panel_list, bool rearrange /*= true*/) +{ + if (!mItemComparator) + { + LL_WARNS_ONCE() << "No comparator specified for inserting FlatListView items." << LL_ENDL; + return false; + } + if (panel_list.size() == 0) + { + return false; + } + + // presort list so that it will be easier to sort elements into mItemPairs + panel_list.sort(ComparatorAdaptor(*mItemComparator)); + + pairs_const_iterator_t new_pair_it = panel_list.begin(); + item_pair_t* new_pair = *new_pair_it; + pairs_iterator_t pair_it = mItemPairs.begin(); + item_pair_t* item_pair = *pair_it; + + // sort panel_list into mItemPars + while (new_pair_it != panel_list.end() && pair_it != mItemPairs.end()) + { + if (!new_pair->first || new_pair->first->getParent() == mItemsPanel) + { + // iterator already used or we are reusing existing panel + new_pair_it++; + new_pair = *new_pair_it; + } + else if (mItemComparator->compare(new_pair->first, item_pair->first)) + { + LLPanel* panel = new_pair->first; + + mItemPairs.insert(pair_it, new_pair); + mItemsPanel->addChild(panel); + + //_4 is for MASK + panel->setMouseDownCallback(boost::bind(&LLFlatListView::onItemMouseClick, this, new_pair, _4)); + panel->setRightMouseDownCallback(boost::bind(&LLFlatListView::onItemRightMouseClick, this, new_pair, _4)); + // Children don't accept the focus + panel->setTabStop(false); + } + else + { + pair_it++; + item_pair = *pair_it; + } + } + + // Add what is left of panel_list into the end of mItemPairs. + for (; new_pair_it != panel_list.end(); ++new_pair_it) + { + item_pair_t* item_pair = *new_pair_it; + LLPanel *panel = item_pair->first; + if (panel && panel->getParent() != mItemsPanel) + { + mItemPairs.push_back(item_pair); + mItemsPanel->addChild(panel); + + //_4 is for MASK + panel->setMouseDownCallback(boost::bind(&LLFlatListView::onItemMouseClick, this, item_pair, _4)); + panel->setRightMouseDownCallback(boost::bind(&LLFlatListView::onItemRightMouseClick, this, item_pair, _4)); + // Children don't accept the focus + panel->setTabStop(false); + } + } + + if (rearrange) + { + rearrangeItems(); + notifyParentItemsRectChanged(); + } + return true; +} + + +bool LLFlatListView::insertItemAfter(LLPanel* after_item, LLPanel* item_to_add, const LLSD& value /*= LLUUID::null*/) +{ + if (!after_item) return false; + if (!item_to_add) return false; + if (value.isUndefined()) return false; + + if (mItemPairs.empty()) return false; + + //force uniqueness of items, easiest check but unreliable + if (item_to_add->getParent() == mItemsPanel) return false; + + item_pair_t* after_pair = getItemPair(after_item); + if (!after_pair) return false; + + item_pair_t* new_pair = new item_pair_t(item_to_add, value); + if (after_pair == mItemPairs.back()) + { + mItemPairs.push_back(new_pair); + mItemsPanel->addChild(item_to_add); + } + else + { + pairs_iterator_t it = mItemPairs.begin(); + for (; it != mItemPairs.end(); ++it) + { + if (*it == after_pair) + { + // insert new elements before the element at position of passed iterator. + mItemPairs.insert(++it, new_pair); + mItemsPanel->addChild(item_to_add); + break; + } + } + } + + //_4 is for MASK + item_to_add->setMouseDownCallback(boost::bind(&LLFlatListView::onItemMouseClick, this, new_pair, _4)); + item_to_add->setRightMouseDownCallback(boost::bind(&LLFlatListView::onItemRightMouseClick, this, new_pair, _4)); + + rearrangeItems(); + notifyParentItemsRectChanged(); + return true; +} + + +bool LLFlatListView::removeItem(LLPanel* item, bool rearrange) +{ + if (!item) return false; + if (item->getParent() != mItemsPanel) return false; + + item_pair_t* item_pair = getItemPair(item); + if (!item_pair) return false; + + return removeItemPair(item_pair, rearrange); +} + +bool LLFlatListView::removeItemByValue(const LLSD& value, bool rearrange) +{ + if (value.isUndefined()) return false; + + item_pair_t* item_pair = getItemPair(value); + if (!item_pair) return false; + + return removeItemPair(item_pair, rearrange); +} + +bool LLFlatListView::removeItemByUUID(const LLUUID& uuid, bool rearrange) +{ + return removeItemByValue(LLSD(uuid), rearrange); +} + +LLPanel* LLFlatListView::getItemByValue(const LLSD& value) const +{ + if (value.isUndefined()) return nullptr; + + item_pair_t* pair = getItemPair(value); + if (pair) return pair->first; + return nullptr; +} + +bool LLFlatListView::valueExists(const LLSD& value) const +{ + if (value.isUndefined()) return false; + item_pair_t* pair = getItemPair(value); + return pair != nullptr; +} + +bool LLFlatListView::selectItem(LLPanel* item, bool select /*= true*/) +{ + if (!item) return false; + if (item->getParent() != mItemsPanel) return false; + + item_pair_t* item_pair = getItemPair(item); + if (!item_pair) return false; + + return selectItemPair(item_pair, select); +} + +bool LLFlatListView::selectItemByValue(const LLSD& value, bool select /*= true*/) +{ + if (value.isUndefined()) return false; + + item_pair_t* item_pair = getItemPair(value); + if (!item_pair) return false; + + return selectItemPair(item_pair, select); +} + +bool LLFlatListView::selectItemByUUID(const LLUUID& uuid, bool select /* = true*/) +{ + return selectItemByValue(LLSD(uuid), select); +} + + +LLSD LLFlatListView::getSelectedValue() const +{ + if (mSelectedItemPairs.empty()) return LLSD(); + + item_pair_t* first_selected_pair = mSelectedItemPairs.front(); + return first_selected_pair->second; +} + +void LLFlatListView::getSelectedValues(std::vector& selected_values) const +{ + if (mSelectedItemPairs.empty()) return; + + for (pairs_const_iterator_t it = mSelectedItemPairs.begin(); it != mSelectedItemPairs.end(); ++it) + { + selected_values.push_back((*it)->second); + } +} + +LLUUID LLFlatListView::getSelectedUUID() const +{ + const LLSD& value = getSelectedValue(); + if (value.isDefined() && value.isUUID()) + { + return value.asUUID(); + } + else + { + return LLUUID::null; + } +} + +void LLFlatListView::getSelectedUUIDs(uuid_vec_t& selected_uuids) const +{ + if (mSelectedItemPairs.empty()) return; + + for (pairs_const_iterator_t it = mSelectedItemPairs.begin(); it != mSelectedItemPairs.end(); ++it) + { + selected_uuids.push_back((*it)->second.asUUID()); + } +} + +LLPanel* LLFlatListView::getSelectedItem() const +{ + if (mSelectedItemPairs.empty()) return nullptr; + + return mSelectedItemPairs.front()->first; +} + +void LLFlatListView::getSelectedItems(std::vector& selected_items) const +{ + if (mSelectedItemPairs.empty()) return; + + for (pairs_const_iterator_t it = mSelectedItemPairs.begin(); it != mSelectedItemPairs.end(); ++it) + { + selected_items.push_back((*it)->first); + } +} + +void LLFlatListView::resetSelection(bool no_commit_on_deselection /*= false*/) +{ + if (mSelectedItemPairs.empty()) return; + + for (pairs_iterator_t it= mSelectedItemPairs.begin(); it != mSelectedItemPairs.end(); ++it) + { + item_pair_t* pair_to_deselect = *it; + LLPanel* item = pair_to_deselect->first; + item->setValue(UNSELECTED_EVENT); + } + + mSelectedItemPairs.clear(); + + if (mCommitOnSelectionChange && !no_commit_on_deselection) + { + onCommit(); + } + + // Stretch selected item rect to ensure it won't be clipped + mSelectedItemsBorder->setRect(getLastSelectedItemRect().stretch(-1)); +} + +void LLFlatListView::setNoItemsCommentText(const std::string& comment_text) +{ + mNoItemsCommentTextbox->setValue(comment_text); +} + +U32 LLFlatListView::size(const bool only_visible_items) const +{ + if (only_visible_items) + { + U32 size = 0; + for (pairs_const_iterator_t + iter = mItemPairs.begin(), + iter_end = mItemPairs.end(); + iter != iter_end; ++iter) + { + if ((*iter)->first->getVisible()) + ++size; + } + return size; + } + else + { + return mItemPairs.size(); + } +} + +void LLFlatListView::clear() +{ + // This will clear mSelectedItemPairs, calling all appropriate callbacks. + resetSelection(); + + // do not use LLView::deleteAllChildren to avoid removing nonvisible items. drag-n-drop for ex. + for (pairs_iterator_t it = mItemPairs.begin(); it != mItemPairs.end(); ++it) + { + mItemsPanel->removeChild((*it)->first); + (*it)->first->die(); + delete *it; + } + mItemPairs.clear(); + + // also set items panel height to zero. Reshape it to allow reshaping of non-item children + LLRect rc = mItemsPanel->getRect(); + rc.mBottom = rc.mTop; + mItemsPanel->reshape(rc.getWidth(), rc.getHeight()); + mItemsPanel->setRect(rc); + + setNoItemsCommentVisible(true); + notifyParentItemsRectChanged(); +} + +void LLFlatListView::sort() +{ + if (!mItemComparator) + { + LL_WARNS() << "No comparator specified for sorting FlatListView items." << LL_ENDL; + return; + } + + mItemPairs.sort(ComparatorAdaptor(*mItemComparator)); + rearrangeItems(); +} + +bool LLFlatListView::updateValue(const LLSD& old_value, const LLSD& new_value) +{ + if (old_value.isUndefined() || new_value.isUndefined()) return false; + if (llsds_are_equal(old_value, new_value)) return false; + + item_pair_t* item_pair = getItemPair(old_value); + if (!item_pair) return false; + + item_pair->second = new_value; + return true; +} + +////////////////////////////////////////////////////////////////////////// +// PROTECTED STUFF +////////////////////////////////////////////////////////////////////////// + +LLFlatListView::LLFlatListView(const std::string& name, const LLRect& rect, bool opaque, const LLColor4& color, const S32& item_pad, bool allow_select, bool multi_select, bool keep_one_selected, bool keep_selection_visible_on_reshape, const std::string& no_items_text) +: LLScrollContainer(name, rect, nullptr, opaque, color) + , mItemComparator(nullptr) + , mItemsPanel(nullptr) + , mItemPad(item_pad) + , mAllowSelection(allow_select) + , mMultipleSelection(multi_select) + , mCommitOnSelectionChange(false) + , mKeepOneItemSelected(keep_one_selected) + , mIsConsecutiveSelection(false) + , mKeepSelectionVisibleOnReshape(keep_selection_visible_on_reshape) + , mPrevNotifyParentRect(LLRect()) + , mNoItemsCommentTextbox(nullptr) +{ + mBorderThickness = getBorderWidth(); + + LLRect scroll_rect = getRect(); + LLRect items_rect; + + setItemsNoScrollWidth(scroll_rect.getWidth()); + items_rect.setLeftTopAndSize(mBorderThickness, scroll_rect.getHeight() - mBorderThickness, mItemsNoScrollWidth, 0); + + mItemsPanel = new LLPanel("items panel", items_rect); + addChild(mItemsPanel); + + //we don't need to stretch in vertical direction on reshaping by a parent + //no bottom following! + mItemsPanel->setFollows(FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_TOP); + + mSelectedItemsBorder = new LLViewBorder( + "scroll border", + getLastSelectedItemRect(), + LLViewBorder::BEVEL_IN); + mSelectedItemsBorder->setVisible(false); + mItemsPanel->addChild(mSelectedItemsBorder); + + { + // create textbox for "No Items" comment text + { + LLRect comment_rect = getRect(); + comment_rect.setOriginAndSize(0, 0, comment_rect.getWidth(), comment_rect.getHeight()); + comment_rect.stretch(-getBorderWidth()); + mNoItemsCommentTextbox = new LLTextBox(no_items_text, comment_rect, no_items_text); + } + mNoItemsCommentTextbox->setBorderVisible(false); + + { + mNoItemsCommentTextbox->setFollows(FOLLOWS_ALL); + } + } +}; + +LLFlatListView::~LLFlatListView() +{ + delete_and_clear(mItemPairs); +} + +// virtual +void LLFlatListView::draw() +{ + // Highlight border if a child of this container has keyboard focus + if ( mSelectedItemsBorder->getVisible() ) + { + mSelectedItemsBorder->setKeyboardFocusHighlight( hasFocus() ); + } + LLScrollContainer::draw(); +} + +// virtual +BOOL LLFlatListView::postBuild() +{ + setTabStop(true); + return LLScrollContainer::postBuild(); +} + +void LLFlatListView::rearrangeItems() +{ + static LLUICachedControl scrollbar_size ("UIScrollbarSize", 0); + + setNoItemsCommentVisible(0==size()); + + if (mItemPairs.empty()) return; + + //calculating required height - assuming items can be of different height + //list should accommodate all its items + S32 height = 0; + + S32 invisible_children_count = 0; + pairs_iterator_t it = mItemPairs.begin(); + for (; it != mItemPairs.end(); ++it) + { + LLPanel* item = (*it)->first; + + // skip invisible child + if (!item->getVisible()) + { + ++invisible_children_count; + continue; + } + + height += item->getRect().getHeight(); + } + + // add paddings between items, excluding invisible ones + height += mItemPad * (mItemPairs.size() - invisible_children_count - 1); + + LLRect rc = mItemsPanel->getRect(); + S32 width = mItemsNoScrollWidth; + + // update width to avoid horizontal scrollbar + if (height > getRect().getHeight() - 2 * mBorderThickness) + width -= scrollbar_size; + + //changes the bottom, end of the list goes down in the scroll container + rc.setLeftTopAndSize(rc.mLeft, rc.mTop, width, height); + mItemsPanel->setRect(rc); + + //reshaping items + S32 item_new_top = height; + pairs_iterator_t it2, first_it = mItemPairs.begin(); + for (it2 = first_it; it2 != mItemPairs.end(); ++it2) + { + LLPanel* item = (*it2)->first; + + // skip invisible child + if (!item->getVisible()) + continue; + + LLRect rc = item->getRect(); + rc.setLeftTopAndSize(rc.mLeft, item_new_top, width, rc.getHeight()); + item->reshape(rc.getWidth(), rc.getHeight()); + item->setRect(rc); + + // move top for next item in list + item_new_top -= (rc.getHeight() + mItemPad); + } + + // Stretch selected item rect to ensure it won't be clipped + mSelectedItemsBorder->setRect(getLastSelectedItemRect().stretch(-1)); +} + +void LLFlatListView::onItemMouseClick(item_pair_t* item_pair, MASK mask) +{ + if (!item_pair) return; + + if (!item_pair->first) + { + LL_WARNS() << "Attempt to selet an item pair containing null panel item" << LL_ENDL; + return; + } + + setFocus(TRUE); + + bool select_item = !isSelected(item_pair); + + //*TODO find a better place for that enforcing stuff + if (mKeepOneItemSelected && numSelected() == 1 && !select_item) return; + + if ( (mask & MASK_SHIFT) && !(mask & MASK_CONTROL) + && mMultipleSelection && !mSelectedItemPairs.empty() ) + { + item_pair_t* last_selected_pair = mSelectedItemPairs.back(); + + // If item_pair is already selected - do nothing + if (last_selected_pair == item_pair) + return; + + bool grab_items = false; + bool reverse = false; + pairs_list_t pairs_to_select; + + // Pick out items from list between last selected and current clicked item_pair. + for (pairs_iterator_t + iter = mItemPairs.begin(), + iter_end = mItemPairs.end(); + iter != iter_end; ++iter) + { + item_pair_t* cur = *iter; + if (cur == last_selected_pair || cur == item_pair) + { + // We've got reverse selection if last grabed item isn't a new selection. + reverse = grab_items && (cur != item_pair); + grab_items = !grab_items; + // Skip last selected and current clicked item pairs. + continue; + } + if (!cur->first->getVisible()) + { + // Skip invisible item pairs. + continue; + } + if (grab_items) + { + pairs_to_select.push_back(cur); + } + } + + if (reverse) + { + pairs_to_select.reverse(); + } + + pairs_to_select.push_back(item_pair); + + for (pairs_iterator_t + iter = pairs_to_select.begin(), + iter_end = pairs_to_select.end(); + iter != iter_end; ++iter) + { + item_pair_t* pair_to_select = *iter; + if (isSelected(pair_to_select)) + { + // Item was already selected but there is a need to keep order from last selected pair to new selection. + // Do it here to prevent extra mCommitOnSelectionChange in selectItemPair(). + mSelectedItemPairs.remove(pair_to_select); + mSelectedItemPairs.push_back(pair_to_select); + } + else + { + selectItemPair(pair_to_select, true); + } + } + + if (!select_item) + { + // Update last selected item border. + mSelectedItemsBorder->setRect(getLastSelectedItemRect().stretch(-1)); + } + return; + } + + //no need to do additional commit on selection reset + if (!(mask & MASK_CONTROL) || !mMultipleSelection) resetSelection(true); + + //only CTRL usage allows to deselect an item, usual clicking on an item cannot deselect it + if (mask & MASK_CONTROL) + selectItemPair(item_pair, select_item); + else + selectItemPair(item_pair, true); +} + +void LLFlatListView::onItemRightMouseClick(item_pair_t* item_pair, MASK mask) +{ + if (!item_pair) + return; + + // Forbid deselecting of items on right mouse button click if mMultipleSelection flag is set on, + // because some of derived classes may have context menu and selected items must be kept. + if ( !(mask & MASK_CONTROL) && mMultipleSelection && isSelected(item_pair) ) + return; + + // else got same behavior as at onItemMouseClick + onItemMouseClick(item_pair, mask); +} + +BOOL LLFlatListView::handleKeyHere(KEY key, MASK mask) +{ + BOOL reset_selection = (mask != MASK_SHIFT); + BOOL handled = FALSE; + switch (key) + { + case KEY_RETURN: + { + if (mSelectedItemPairs.size() && mask == MASK_NONE) + { + mOnReturnSignal(this, getValue()); + handled = TRUE; + } + break; + } + case KEY_UP: + { + if ( !selectNextItemPair(true, reset_selection) && reset_selection) + { + // If case we are in accordion tab notify parent to go to the previous accordion + if (notifyParent(LLSD().with("action","select_prev")) > 0 )//message was processed + resetSelection(); + } + break; + } + case KEY_DOWN: + { + if ( !selectNextItemPair(false, reset_selection) && reset_selection) + { + // If case we are in accordion tab notify parent to go to the next accordion + if ( notifyParent(LLSD().with("action","select_next")) > 0 ) //message was processed + resetSelection(); + } + break; + } + case KEY_ESCAPE: + { + if (mask == MASK_NONE) + { + setFocus(FALSE); // pass focus to the game area (EXT-8357) + } + break; + } + default: + break; + } + + if ( ( key == KEY_UP || key == KEY_DOWN ) && mSelectedItemPairs.size() ) + { + ensureSelectedVisible(); + /* + LLRect visible_rc = getVisibleContentRect(); + LLRect selected_rc = getLastSelectedItemRect(); + + if ( !visible_rc.contains (selected_rc) ) + { + // But scroll in Items panel coordinates + scrollToShowRect(selected_rc); + } + + // In case we are in accordion tab notify parent to show selected rectangle + LLRect screen_rc; + localRectToScreen(selected_rc, &screen_rc); + notifyParent(LLSD().with("scrollToShowRect",screen_rc.getValue()));*/ + + handled = TRUE; + } + + return handled ? handled : LLScrollContainer::handleKeyHere(key, mask); +} + +LLFlatListView::item_pair_t* LLFlatListView::getItemPair(LLPanel* item) const +{ + llassert(item); + + for (pairs_const_iterator_t it= mItemPairs.begin(); it != mItemPairs.end(); ++it) + { + item_pair_t* item_pair = *it; + if (item_pair->first == item) return item_pair; + } + return nullptr; +} + +//compares two LLSD's +bool llsds_are_equal(const LLSD& llsd_1, const LLSD& llsd_2) +{ + llassert(llsd_1.isDefined()); + llassert(llsd_2.isDefined()); + + if (llsd_1.type() != llsd_2.type()) return false; + + if (!llsd_1.isMap()) + { + if (llsd_1.isUUID()) return llsd_1.asUUID() == llsd_2.asUUID(); + + //assumptions that string representaion is enough for other types + return llsd_1.asString() == llsd_2.asString(); + } + + if (llsd_1.size() != llsd_2.size()) return false; + + LLSD::map_const_iterator llsd_1_it = llsd_1.beginMap(); + LLSD::map_const_iterator llsd_2_it = llsd_2.beginMap(); + for (S32 i = 0; i < llsd_1.size(); ++i) + { + if ((*llsd_1_it).first != (*llsd_2_it).first) return false; + if (!llsds_are_equal((*llsd_1_it).second, (*llsd_2_it).second)) return false; + ++llsd_1_it; + ++llsd_2_it; + } + return true; +} + +LLFlatListView::item_pair_t* LLFlatListView::getItemPair(const LLSD& value) const +{ + llassert(value.isDefined()); + + for (pairs_const_iterator_t it= mItemPairs.begin(); it != mItemPairs.end(); ++it) + { + item_pair_t* item_pair = *it; + if (llsds_are_equal(item_pair->second, value)) return item_pair; + } + return nullptr; +} + +bool LLFlatListView::selectItemPair(item_pair_t* item_pair, bool select) +{ + llassert(item_pair); + + if (!mAllowSelection && select) return false; + + if (isSelected(item_pair) == select) return true; //already in specified selection state + if (select) + { + mSelectedItemPairs.push_back(item_pair); + } + else + { + mSelectedItemPairs.remove(item_pair); + } + + //a way of notifying panel of selection state changes + LLPanel* item = item_pair->first; + item->setValue(select ? SELECTED_EVENT : UNSELECTED_EVENT); + + if (mCommitOnSelectionChange) + { + onCommit(); + } + + // Stretch selected item rect to ensure it won't be clipped + mSelectedItemsBorder->setRect(getLastSelectedItemRect().stretch(-1)); + // By default mark it as not consecutive selection + mIsConsecutiveSelection = false; + + return true; +} + +void LLFlatListView::scrollToShowFirstSelectedItem() +{ + if (!mSelectedItemPairs.size()) return; + + LLRect selected_rc = mSelectedItemPairs.front()->first->getRect(); + + if (selected_rc.isValid()) + { + scrollToShowRect(selected_rc); + } +} + +LLRect LLFlatListView::getLastSelectedItemRect() +{ + if (!mSelectedItemPairs.size()) + { + return LLRect::null; + } + + return mSelectedItemPairs.back()->first->getRect(); +} + +void LLFlatListView::selectFirstItem () +{ + // No items - no actions! + if (0 == size()) return; + + // Select first visible item + for (pairs_iterator_t + iter = mItemPairs.begin(), + iter_end = mItemPairs.end(); + iter != iter_end; ++iter) + { + // skip invisible items + if ( (*iter)->first->getVisible() ) + { + selectItemPair(*iter, true); + ensureSelectedVisible(); + break; + } + } +} + +void LLFlatListView::selectLastItem () +{ + // No items - no actions! + if (0 == size()) return; + + // Select last visible item + for (pairs_list_t::reverse_iterator + r_iter = mItemPairs.rbegin(), + r_iter_end = mItemPairs.rend(); + r_iter != r_iter_end; ++r_iter) + { + // skip invisible items + if ( (*r_iter)->first->getVisible() ) + { + selectItemPair(*r_iter, true); + ensureSelectedVisible(); + break; + } + } +} + +void LLFlatListView::ensureSelectedVisible() +{ + LLRect selected_rc = getLastSelectedItemRect(); + + if (selected_rc.isValid()) + { + scrollToShowRect(selected_rc); + } +} + + +// virtual +bool LLFlatListView::selectNextItemPair(bool is_up_direction, bool reset_selection) +{ + // No items - no actions! + if (0 == size()) + return false; + + if (!mIsConsecutiveSelection) + { + // Leave only one item selected if list has not consecutive selection + if (mSelectedItemPairs.size() && !reset_selection) + { + item_pair_t* cur_sel_pair = mSelectedItemPairs.back(); + resetSelection(); + selectItemPair (cur_sel_pair, true); + } + } + + if (mSelectedItemPairs.size()) + { + item_pair_t* to_sel_pair = nullptr; + item_pair_t* cur_sel_pair = nullptr; + + // Take the last selected pair + cur_sel_pair = mSelectedItemPairs.back(); + // Bases on given direction choose next item to select + if (is_up_direction) + { + // Find current selected item position in mItemPairs list + pairs_list_t::reverse_iterator sel_it = std::find(mItemPairs.rbegin(), mItemPairs.rend(), cur_sel_pair); + + for (;++sel_it != mItemPairs.rend();) + { + // skip invisible items + if ( (*sel_it)->first->getVisible() ) + { + to_sel_pair = *sel_it; + break; + } + } + } + else + { + // Find current selected item position in mItemPairs list + pairs_list_t::iterator sel_it = std::find(mItemPairs.begin(), mItemPairs.end(), cur_sel_pair); + + for (;++sel_it != mItemPairs.end();) + { + // skip invisible items + if ( (*sel_it)->first->getVisible() ) + { + to_sel_pair = *sel_it; + break; + } + } + } + + if (to_sel_pair) + { + bool select = true; + if (reset_selection) + { + // Reset current selection if we were asked about it + resetSelection(); + } + else + { + // If item already selected and no reset request than we should deselect last selected item. + select = (mSelectedItemPairs.end() == std::find(mSelectedItemPairs.begin(), mSelectedItemPairs.end(), to_sel_pair)); + } + // Select/Deselect next item + selectItemPair(select ? to_sel_pair : cur_sel_pair, select); + // Mark it as consecutive selection + mIsConsecutiveSelection = true; + return true; + } + } + else + { + // If there weren't selected items then choose the first one bases on given direction + // Force selection to first item + if (is_up_direction) + selectLastItem(); + else + selectFirstItem(); + // Mark it as consecutive selection + mIsConsecutiveSelection = true; + return true; + } + + return false; +} + +BOOL LLFlatListView::canSelectAll() const +{ + return 0 != size() && mAllowSelection && mMultipleSelection; +} + +void LLFlatListView::selectAll() +{ + if (!mAllowSelection || !mMultipleSelection) + return; + + mSelectedItemPairs.clear(); + + for (pairs_const_iterator_t it= mItemPairs.begin(); it != mItemPairs.end(); ++it) + { + item_pair_t* item_pair = *it; + mSelectedItemPairs.push_back(item_pair); + //a way of notifying panel of selection state changes + LLPanel* item = item_pair->first; + item->setValue(SELECTED_EVENT); + } + + if (mCommitOnSelectionChange) + { + onCommit(); + } + + // Stretch selected item rect to ensure it won't be clipped + mSelectedItemsBorder->setRect(getLastSelectedItemRect().stretch(-1)); +} + +bool LLFlatListView::isSelected(item_pair_t* item_pair) const +{ + llassert(item_pair); + + pairs_const_iterator_t it_end = mSelectedItemPairs.end(); + return std::find(mSelectedItemPairs.begin(), it_end, item_pair) != it_end; +} + +bool LLFlatListView::removeItemPair(item_pair_t* item_pair, bool rearrange) +{ + llassert(item_pair); + + bool deleted = false; + bool selection_changed = false; + for (pairs_iterator_t it = mItemPairs.begin(); it != mItemPairs.end(); ++it) + { + item_pair_t* _item_pair = *it; + if (_item_pair == item_pair) + { + mItemPairs.erase(it); + deleted = true; + break; + } + } + + if (!deleted) return false; + + for (pairs_iterator_t it = mSelectedItemPairs.begin(); it != mSelectedItemPairs.end(); ++it) + { + item_pair_t* selected_item_pair = *it; + if (selected_item_pair == item_pair) + { + it = mSelectedItemPairs.erase(it); + selection_changed = true; + break; + } + } + + mItemsPanel->removeChild(item_pair->first); + item_pair->first->die(); + delete item_pair; + + if (rearrange) + { + rearrangeItems(); + notifyParentItemsRectChanged(); + } + + if (selection_changed && mCommitOnSelectionChange) + { + onCommit(); + } + + return true; +} + +void LLFlatListView::notifyParentItemsRectChanged() +{ + S32 comment_height = 0; + + // take into account comment text height if exists + if (mNoItemsCommentTextbox && mNoItemsCommentTextbox->getVisible()) + { + // top text padding inside the textbox is included into the height + comment_height = mNoItemsCommentTextbox->getTextPixelHeight(); + + // take into account a distance from parent's top border to textbox's top + comment_height += getRect().getHeight() - mNoItemsCommentTextbox->getRect().mTop; + } + + LLRect req_rect = getItemsRect(); + + // get maximum of items total height and comment text height + req_rect.setOriginAndSize(req_rect.mLeft, req_rect.mBottom, req_rect.getWidth(), llmax(req_rect.getHeight(), comment_height)); + + // take into account border size. + req_rect.stretch(getBorderWidth()); + + if (req_rect == mPrevNotifyParentRect) + return; + + mPrevNotifyParentRect = req_rect; + + LLSD params; + params["action"] = "size_changes"; + params["width"] = req_rect.getWidth(); + params["height"] = req_rect.getHeight(); + + if (getParent()) // dummy widgets don't have a parent + getParent()->notifyParent(params); +} + +void LLFlatListView::setNoItemsCommentVisible(bool visible) const +{ + if (mNoItemsCommentTextbox) + { + mSelectedItemsBorder->setVisible(!visible); + mNoItemsCommentTextbox->setVisible(visible); + } +} + +void LLFlatListView::getItems(std::vector& items) const +{ + if (mItemPairs.empty()) return; + + items.clear(); + for (pairs_const_iterator_t it = mItemPairs.begin(); it != mItemPairs.end(); ++it) + { + items.push_back((*it)->first); + } +} + +void LLFlatListView::getValues(std::vector& values) const +{ + if (mItemPairs.empty()) return; + + values.clear(); + for (pairs_const_iterator_t it = mItemPairs.begin(); it != mItemPairs.end(); ++it) + { + values.push_back((*it)->second); + } +} + +// virtual +void LLFlatListView::onFocusReceived() +{ + if (size()) + { + mSelectedItemsBorder->setVisible(TRUE); + } + gEditMenuHandler = this; +} +// virtual +void LLFlatListView::onFocusLost() +{ + mSelectedItemsBorder->setVisible(FALSE); + // Route menu back to the default + if (gEditMenuHandler == this) + { + gEditMenuHandler = nullptr; + } +} + +//virtual +S32 LLFlatListView::notify(const LLSD& info) +{ + if (info.has("action")) + { + std::string str_action = info["action"]; + if (str_action == "select_first") + { + setFocus(true); + selectFirstItem(); + return 1; + } + else if (str_action == "select_last") + { + setFocus(true); + selectLastItem(); + return 1; + } + } + else if (info.has("rearrange")) + { + rearrangeItems(); + notifyParentItemsRectChanged(); + return 1; + } + return 0; +} + +void LLFlatListView::detachItems(std::vector& detached_items) +{ + LLSD action; + action.with("detach", LLSD()); + // Clear detached_items list + detached_items.clear(); + // Go through items and detach valid items, remove them from items panel + // and add to detached_items. + for (pairs_iterator_t + iter = mItemPairs.begin(), + iter_end = mItemPairs.end(); + iter != iter_end; ++iter) + { + LLPanel* pItem = (*iter)->first; + if (1 == pItem->notify(action)) + { + selectItemPair((*iter), false); + mItemsPanel->removeChild(pItem); + detached_items.push_back(pItem); + } + } + if (!detached_items.empty()) + { + // Some items were detached, clean ourself from unusable memory + if (detached_items.size() == mItemPairs.size()) + { + // This way will be faster if all items were disconnected + for (pairs_iterator_t + iter = mItemPairs.begin(), + iter_end = mItemPairs.end(); + iter != iter_end; ++iter) + { + (*iter)->first = nullptr; + delete *iter; + } + mItemPairs.clear(); + // Also set items panel height to zero. + // Reshape it to allow reshaping of non-item children. + LLRect rc = mItemsPanel->getRect(); + rc.mBottom = rc.mTop; + mItemsPanel->reshape(rc.getWidth(), rc.getHeight()); + mItemsPanel->setRect(rc); + setNoItemsCommentVisible(true); + } + else + { + for (std::vector::const_iterator + detached_iter = detached_items.begin(), + detached_iter_end = detached_items.end(); + detached_iter != detached_iter_end; ++detached_iter) + { + LLPanel* pDetachedItem = *detached_iter; + for (pairs_iterator_t + iter = mItemPairs.begin(), + iter_end = mItemPairs.end(); + iter != iter_end; ++iter) + { + item_pair_t* item_pair = *iter; + if (item_pair->first == pDetachedItem) + { + mItemPairs.erase(iter); + item_pair->first = nullptr; + delete item_pair; + break; + } + } + } + rearrangeItems(); + } + notifyParentItemsRectChanged(); + } +} + + +/************************************************************************/ +/* LLFlatListViewEx implementation */ +/************************************************************************/ +/* Singu Note: Let's not use this for now... +LLFlatListViewEx::Params::Params() +: no_items_msg("no_items_msg") +, no_filtered_items_msg("no_filtered_items_msg") +{ + +} + +LLFlatListViewEx::LLFlatListViewEx(const Params& p) +: LLFlatListView(p) +, mNoFilteredItemsMsg(p.no_filtered_items_msg) +, mNoItemsMsg(p.no_items_msg) +, mForceShowingUnmatchedItems(false) +, mHasMatchedItems(false) +{ + +} + +void LLFlatListViewEx::updateNoItemsMessage(const std::string& filter_string) +{ + bool items_filtered = !filter_string.empty(); + if (items_filtered) + { + // items were filtered + LLStringUtil::format_map_t args; + args["[SEARCH_TERM]"] = LLURI::escape(filter_string); + std::string text = mNoFilteredItemsMsg; + LLStringUtil::format(text, args); + setNoItemsCommentText(text); + } + else + { + // list does not contain any items at all + setNoItemsCommentText(mNoItemsMsg); + } + +} + +bool LLFlatListViewEx::getForceShowingUnmatchedItems() +{ + return mForceShowingUnmatchedItems; +} + +void LLFlatListViewEx::setForceShowingUnmatchedItems(bool show) +{ + mForceShowingUnmatchedItems = show; +} + +void LLFlatListViewEx::setFilterSubString(const std::string& filter_str) +{ + if (0 != LLStringUtil::compareInsensitive(filter_str, mFilterSubString)) + { + mFilterSubString = filter_str; + updateNoItemsMessage(mFilterSubString); + filterItems(); + } +} + +void LLFlatListViewEx::updateItemVisibility(LLPanel* item, const LLSD &action) +{ + if (!item) return; + + // 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 + { + // TODO: implement (re)storing of current selection. + if (!mForceShowingUnmatchedItems) + { + selectItem(item, false); + } + item->setVisible(mForceShowingUnmatchedItems); + } +} + +void LLFlatListViewEx::filterItems() +{ + 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; + for (item_panel_list_t::iterator + iter = items.begin(), + iter_end = items.end(); + iter != iter_end; ++iter) + { + LLPanel* pItem = (*iter); + updateItemVisibility(pItem, action); + } + + sort(); + notifyParentItemsRectChanged(); +} + +bool LLFlatListViewEx::hasMatchedItems() +{ + return mHasMatchedItems; +} +*/ + +// Old-style fromXML stuffs +// static +LLView* LLFlatListView::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) +{ + // Stuff from scroll container + std::string name("flat_list_view"); + node->getAttributeString("name", name); + + LLRect rect; + createRect(node, rect, parent, LLRect()); + + BOOL opaque = FALSE; + node->getAttributeBOOL("opaque", opaque); + + LLColor4 color(0,0,0,0); + LLUICtrlFactory::getAttributeColor(node, "color", color); + + // Stuff from flat list + bool allow_select = false; + node->getAttribute_bool("allow_select", allow_select); + bool multi_select = false; + node->getAttribute_bool("multi_select", multi_select); + bool keep_one_selected = false; + node->getAttribute_bool("keep_one_selected", keep_one_selected); + bool keep_selection_visible_on_reshape = false; + node->getAttribute_bool("keep_selection_visible_on_reshape", keep_selection_visible_on_reshape); + U32 item_pad; + node->getAttributeU32("item_pad", item_pad); + std::string no_items_text; + node->getAttributeString("no_items_text", no_items_text); + + return new LLFlatListView(name, rect, opaque, color, item_pad, allow_select, multi_select, keep_one_selected, keep_selection_visible_on_reshape, no_items_text); +} +// + +//EOF diff --git a/indra/llui/llflatlistview.h b/indra/llui/llflatlistview.h new file mode 100644 index 0000000000..ade20412af --- /dev/null +++ b/indra/llui/llflatlistview.h @@ -0,0 +1,540 @@ +/** + * @file llflatlistview.h + * @brief LLFlatListView base class and extension to support messages for several cases of an empty list. + * + * $LicenseInfo:firstyear=2009&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLFLATLISTVIEW_H +#define LL_LLFLATLISTVIEW_H + +#include "llpanel.h" +#include "llscrollcontainer.h" +#include "lltextbox.h" + + +/** + * LLFlatListView represents a flat list ui control that operates on items in a form of LLPanel's. + * LLSD can be associated with each added item, it can keep data from an item in digested form. + * Associated LLSD's can be of any type (singular, a map etc.). + * Items (LLPanel's subclasses) can be of different height. + * The list is LLPanel created in itself and grows in height while new items are added. + * + * The control can manage selection of its items when the flag "allow_select" is set. Also ability to select + * multiple items (by using CTRL) is enabled through setting the flag "multi_select" - if selection is not allowed that flag + * is ignored. The option "keep_one_selected" forces at least one item to be selected at any time (only for mouse events on items) + * since any item of the list was selected. + * + * Examples of using this control are presented in Picks panel (My Profile and Profile View), where this control is used to + * manage the list of pick items. + * + * ASSUMPTIONS AND STUFF + * - NULL pointers and undefined LLSD's are not accepted by any method of this class unless specified otherwise + * - Order of returned selected items are not guaranteed + * - The control assumes that all items being added are unique. + */ +class LLFlatListView : public LLScrollContainer, public LLEditMenuHandler +{ + LOG_CLASS(LLFlatListView); +public: + + /** + * Abstract comparator for comparing flat list items in a form of LLPanel + */ + class ItemComparator + { + public: + ItemComparator() {}; + virtual ~ItemComparator() {}; + + /** Returns true if item1 < item2, false otherwise */ + virtual bool compare(const LLPanel* item1, const LLPanel* item2) const = 0; + }; + + /** + * Represents reverse comparator which acts as a decorator for a comparator that need to be reversed + */ + class ItemReverseComparator : public ItemComparator + { + public: + ItemReverseComparator(const ItemComparator& comparator) : mComparator(comparator) {}; + virtual ~ItemReverseComparator() {}; + + bool compare(const LLPanel* item1, const LLPanel* item2) const override + { + return mComparator.compare(item2, item1); + } + + private: + const ItemComparator& mComparator; + }; + + + struct Params : public LLInitParam::Block + { + /** turning on/off selection support */ + Optional allow_select; + + /** turning on/off multiple selection (works while clicking and holding CTRL)*/ + Optional multi_select; + + /** don't allow to deselect all selected items (for mouse events on items only) */ + Optional keep_one_selected; + + /** try to keep selection visible after reshape */ + Optional keep_selection_visible_on_reshape; + + /** padding between items */ + Optional item_pad; + + /** textbox with info message when list is empty*/ + Optional no_items_text; + + Params(); + }; + + // disable traversal when finding widget to hand focus off to + /*virtual*/ BOOL canFocusChildren() const override { return FALSE; } + + /** + * Connects callback to signal called when Return key is pressed. + */ + boost::signals2::connection setReturnCallback( const commit_signal_t::slot_type& cb ) { return mOnReturnSignal.connect(cb); } + + /** Overridden LLPanel's reshape, height is ignored, the list sets its height to accommodate all items */ + void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE) override; + + /** Returns full rect of child panel */ + const LLRect& getItemsRect() const; + + LLRect getRequiredRect() override { return getItemsRect(); } + + /** Returns distance between items */ + const S32 getItemsPad() const { return mItemPad; } + + /** + * Adds and item and LLSD value associated with it to the list at specified position + * @return true if the item was added, false otherwise + */ + virtual bool addItem(LLPanel * item, const LLSD& value = LLUUID::null, EAddPosition pos = ADD_BOTTOM, bool rearrange = true); + + /** + * Insert item_to_add along with associated value to the list right after the after_item. + * @return true if the item was successfully added, false otherwise + */ + virtual bool insertItemAfter(LLPanel* after_item, LLPanel* item_to_add, const LLSD& value = LLUUID::null); + + /** + * Remove specified item + * @return true if the item was removed, false otherwise + */ + virtual bool removeItem(LLPanel* item, bool rearrange = true); + + /** + * Remove an item specified by value + * @return true if the item was removed, false otherwise + */ + virtual bool removeItemByValue(const LLSD& value, bool rearrange = true); + + /** + * Remove an item specified by uuid + * @return true if the item was removed, false otherwise + */ + virtual bool removeItemByUUID(const LLUUID& uuid, bool rearrange = true); + + /** + * Get an item by value + * @return the item as LLPanel if associated with value, NULL otherwise + */ + virtual LLPanel* getItemByValue(const LLSD& value) const; + + /** + * Check for item by value in list + * @return bool whether item exists by value or not + */ + virtual bool valueExists(const LLSD& value) const; + + template + T* getTypedItemByValue(const LLSD& value) const + { + return dynamic_cast(getItemByValue(value)); + } + + /** + * Select or deselect specified item based on select + * @return true if succeed, false otherwise + */ + virtual bool selectItem(LLPanel* item, bool select = true); + + /** + * Select or deselect an item by associated value based on select + * @return true if succeed, false otherwise + */ + virtual bool selectItemByValue(const LLSD& value, bool select = true); + + /** + * Select or deselect an item by associated uuid based on select + * @return true if succeed, false otherwise + */ + virtual bool selectItemByUUID(const LLUUID& uuid, bool select = true); + + /** + * Get all panels stored in the list. + */ + virtual void getItems(std::vector& items) const; + + /** + * Get all items values. + */ + virtual void getValues(std::vector& values) const; + + /** + * Get LLSD associated with the first selected item + */ + virtual LLSD getSelectedValue() const; + + /** + * Get LLSD's associated with selected items. + * @param selected_values std::vector being populated with LLSD associated with selected items + */ + virtual void getSelectedValues(std::vector& selected_values) const; + + + /** + * Get LLUUID associated with selected item + * @return LLUUID if such was associated with selected item + */ + virtual LLUUID getSelectedUUID() const; + + /** + * Get LLUUIDs associated with selected items + * @param selected_uuids An std::vector being populated with LLUUIDs associated with selected items + */ + virtual void getSelectedUUIDs(uuid_vec_t& selected_uuids) const; + + /** Get the top selected item */ + virtual LLPanel* getSelectedItem() const; + + /** + * Get selected items + * @param selected_items An std::vector being populated with pointers to selected items + */ + virtual void getSelectedItems(std::vector& selected_items) const; + + + /** + * Resets selection of items. + * + * It calls onCommit callback if setCommitOnSelectionChange(bool b) was called with "true" + * argument for current Flat List. + * @param no_commit_on_deselection - if true onCommit callback will not be called + */ + virtual void resetSelection(bool no_commit_on_deselection = false); + + /** + * Sets comment text which will be shown in the list is it is empty. + * + * Textbox to hold passed text is created while this method is called at the first time. + * + * @param comment_text - string to be shown as a comment. + */ + void setNoItemsCommentText( const std::string& comment_text); + + /** Turn on/off multiple selection support */ + void setAllowMultipleSelection(bool allow) { mMultipleSelection = allow; } + + /** Turn on/off selection support */ + void setAllowSelection(bool can_select) { mAllowSelection = can_select; } + + /** Sets flag whether onCommit should be fired if selection was changed */ + // FIXME: this should really be a separate signal, since "Commit" implies explicit user action, and selection changes can happen more indirectly. + void setCommitOnSelectionChange(bool b) { mCommitOnSelectionChange = b; } + + /** Get number of selected items in the list */ + U32 numSelected() const {return mSelectedItemPairs.size(); } + + /** Get number of (visible) items in the list */ + U32 size(const bool only_visible_items = true) const; + + /** Removes all items from the list */ + void clear() override; + + /** + * Removes all items that can be detached from the list but doesn't destroy + * them, caller responsible to manage items after they are detached. + * Detachable item should accept "detach" action via notify() method, + * where it disconnect all callbacks, does other valuable routines and + * return 1. + */ + void detachItems(std::vector& detached_items); + + /** + * Set comparator to use for future sorts. + * + * This class does NOT manage lifetime of the comparator + * but assumes that the comparator is always alive. + */ + void setComparator(const ItemComparator* comp) { mItemComparator = comp; } + void sort(); + + bool updateValue(const LLSD& old_value, const LLSD& new_value); + + void scrollToShowFirstSelectedItem(); + + void selectFirstItem (); + void selectLastItem (); + + S32 notify(const LLSD& info) override; + + static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); // Old-style + + virtual ~LLFlatListView(); +protected: + + /** Pairs LLpanel representing a single item LLPanel and LLSD associated with it */ + typedef std::pair item_pair_t; + + typedef std::list pairs_list_t; + typedef pairs_list_t::iterator pairs_iterator_t; + typedef pairs_list_t::const_iterator pairs_const_iterator_t; + + /** An adapter for a ItemComparator */ + struct ComparatorAdaptor + { + ComparatorAdaptor(const ItemComparator& comparator) : mComparator(comparator) {}; + + bool operator()(const item_pair_t* item_pair1, const item_pair_t* item_pair2) const + { + return mComparator.compare(item_pair1->first, item_pair2->first); + } + + const ItemComparator& mComparator; + }; + + + friend class LLUICtrlFactory; + LLFlatListView(const std::string& name, const LLRect& rect, bool opaque, const LLColor4& color, const S32& item_pad, bool allow_select, bool multi_select, bool keep_one_selected, bool keep_selection_visible_on_reshape, const std::string& no_items_text); + + /** Manage selection on mouse events */ + void onItemMouseClick(item_pair_t* item_pair, MASK mask); + + void onItemRightMouseClick(item_pair_t* item_pair, MASK mask); + + /** + * Updates position of items. + * It does not take into account invisible items. + */ + virtual void rearrangeItems(); + + virtual item_pair_t* getItemPair(LLPanel* item) const; + + virtual item_pair_t* getItemPair(const LLSD& value) const; + + virtual bool selectItemPair(item_pair_t* item_pair, bool select); + + virtual bool selectNextItemPair(bool is_up_direction, bool reset_selection); + + BOOL canSelectAll() const override; + void selectAll() override; + + virtual bool isSelected(item_pair_t* item_pair) const; + + virtual bool removeItemPair(item_pair_t* item_pair, bool rearrange); + + bool addItemPairs(pairs_list_t panel_list, bool rearrange = true); + + /** + * Notify parent about changed size of internal controls with "size_changes" action + * + * Size includes Items Rect width and either Items Rect height or comment text height. + * Comment text height is included if comment text is set and visible. + * List border size is also included into notified size. + */ + void notifyParentItemsRectChanged(); + + BOOL handleKeyHere(KEY key, MASK mask) override; + + BOOL postBuild() override; + + void onFocusReceived() override; + + void onFocusLost() override; + + void draw() override; + + LLRect getLastSelectedItemRect(); + + void ensureSelectedVisible(); + +private: + + void setItemsNoScrollWidth(S32 new_width) {mItemsNoScrollWidth = new_width - 2 * mBorderThickness;} + + void setNoItemsCommentVisible(bool visible) const; + +protected: + + /** Comparator to use when sorting the list. */ + const ItemComparator* mItemComparator; + + +private: + + LLPanel* mItemsPanel; + + S32 mItemsNoScrollWidth; + + S32 mBorderThickness; + + /** Items padding */ + S32 mItemPad; + + /** Selection support flag */ + bool mAllowSelection; + + /** Multiselection support flag, ignored if selection is not supported */ + bool mMultipleSelection; + + /** + * Flag specified whether onCommit be called if selection is changed in the list. + * + * Can be ignored in the resetSelection() method. + * @see resetSelection() + */ + bool mCommitOnSelectionChange; + + bool mKeepOneItemSelected; + + bool mIsConsecutiveSelection; + + bool mKeepSelectionVisibleOnReshape; + + /** All pairs of the list */ + pairs_list_t mItemPairs; + + /** Selected pairs for faster access */ + pairs_list_t mSelectedItemPairs; + + /** + * Rectangle contained previous size of items parent notified last time. + * Is used to reduce amount of parentNotify() calls if size was not changed. + */ + LLRect mPrevNotifyParentRect; + + LLTextBox* mNoItemsCommentTextbox; + + LLViewBorder* mSelectedItemsBorder; + + commit_signal_t mOnReturnSignal; +}; + +/** + * Extends LLFlatListView functionality to show different messages when there are no items in the + * list depend on whether they are filtered or not. + * + * Class provides one message per case of empty list. + * It also provides protected updateNoItemsMessage() method to be called each time when derived list + * is changed to update base mNoItemsCommentTextbox value. + * + * It is implemented to avoid duplication of this functionality in concrete implementations of the + * lists. It is intended to be used as a base class for lists which should support two different + * messages for empty state. Can be improved to support more than two messages via state-to-message map. + */ +class LLFlatListViewEx : public LLFlatListView +{ +public: + LOG_CLASS(LLFlatListViewEx); + + struct Params : public LLInitParam::Block + { + /** + * Contains a message for empty list when it does not contain any items at all. + */ + Optional no_items_msg; + + /** + * Contains a message for empty list when its items are removed by filtering. + */ + Optional no_filtered_items_msg; + Params(); + }; + + // *WORKAROUND: two methods to overload appropriate Params due to localization issue: + // no_items_msg & no_filtered_items_msg attributes are not defined as translatable in VLT. See EXT-5931 + void setNoItemsMsg(const std::string& msg) { mNoItemsMsg = msg; } + void setNoFilteredItemsMsg(const std::string& msg) { mNoFilteredItemsMsg = msg; } + + bool getForceShowingUnmatchedItems(); + + void setForceShowingUnmatchedItems(bool show); + + /** + * Sets up new filter string and filters the list. + */ + void setFilterSubString(const std::string& filter_str); + std::string getFilterSubString() const { 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(); + + /** + * Returns true if last call of filterItems() found at least one matching item + */ + bool hasMatchedItems(); + +protected: + LLFlatListViewEx(const Params& p); + + /** + * Applies a message for empty list depend on passed argument. + * + * @param filter_string - if is not empty, message for filtered items will be set, otherwise for + * completely empty list. Value of filter string will be passed as search_term in SLURL. + */ + void updateNoItemsMessage(const std::string& filter_string); + + /** + * Applies visibility acording to action and LLFlatListView settings. + * + * @param item - item we are changing + * @param item - action - parameters to determin visibility from + */ + void updateItemVisibility(LLPanel* item, const LLSD &action); + +private: + std::string mNoFilteredItemsMsg; + std::string mNoItemsMsg; + std::string mFilterSubString; + /** + * Show list items that don't match current filter + */ + bool mForceShowingUnmatchedItems; + /** + * True if last call of filterItems() found at least one matching item + */ + bool mHasMatchedItems; +}; + +#endif diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index 16fb57c255..c86e4ae507 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -35,8 +35,6 @@ #include "linden_common.h" -#include "llmultifloater.h" - #include "llfocusmgr.h" #include "lluictrlfactory.h" @@ -56,10 +54,13 @@ #include "llcontrol.h" #include "lltabcontainer.h" #include "v2math.h" +#include "lltrans.h" +#include "llmultifloater.h" #include "llfasttimer.h" #include "airecursive.h" #include "llnotifications.h" + const S32 MINIMIZED_WIDTH = 160; const S32 CLOSE_BOX_FROM_TOP = 1; // use this to control "jumping" behavior when Ctrl-Tabbing @@ -104,14 +105,14 @@ std::string LLFloater::sButtonNames[BUTTON_COUNT] = std::string LLFloater::sButtonToolTips[BUTTON_COUNT] = { #ifdef LL_DARWIN - "Close (Cmd-W)", //BUTTON_CLOSE + "BUTTON_CLOSE_DARWIN", //"Close (Cmd-W)", //BUTTON_CLOSE #else - "Close (Ctrl-W)", //BUTTON_CLOSE + "BUTTON_CLOSE_WIN", //"Close (Ctrl-W)", //BUTTON_CLOSE #endif - "Restore", //BUTTON_RESTORE - "Minimize", //BUTTON_MINIMIZE - "Tear Off", //BUTTON_TEAR_OFF - "Edit", //BUTTON_EDIT + "BUTTON_RESTORE", //"Restore", //BUTTON_RESTORE + "BUTTON_MINIMIZE", //"Minimize", //BUTTON_MINIMIZE + "BUTTON_TEAR_OFF", //"Tear Off", //BUTTON_TEAR_OFF + "BUTTON_EDIT", //"Edit", //BUTTON_EDIT }; @@ -130,6 +131,31 @@ LLFloater::handle_map_t LLFloater::sFloaterMap; LLFloaterView* gFloaterView = NULL; +//static +void LLFloater::initClass() +{ + // translate tooltips for floater buttons + for (S32 i = 0; i < BUTTON_COUNT; i++) + { + sButtonToolTips[i] = LLTrans::getString( sButtonToolTips[i] ); + } + + LLControlVariable* ctrl = LLUI::sConfigGroup->getControl("ActiveFloaterTransparency"); + if (ctrl) + { + ctrl->getSignal()->connect(boost::bind(&LLFloater::updateActiveFloaterTransparency)); + updateActiveFloaterTransparency(); + } + + ctrl = LLUI::sConfigGroup->getControl("InactiveFloaterTransparency"); + if (ctrl) + { + ctrl->getSignal()->connect(boost::bind(&LLFloater::updateInactiveFloaterTransparency)); + updateInactiveFloaterTransparency(); + } + +} + LLFloater::LLFloater() : //FIXME: we should initialize *all* member variables here LLPanel(), mAutoFocus(TRUE), @@ -355,6 +381,18 @@ void LLFloater::initFloater(const std::string& title, } } +// static +void LLFloater::updateActiveFloaterTransparency() +{ + sActiveControlTransparency = LLUI::sConfigGroup->getF32("ActiveFloaterTransparency"); +} + +// static +void LLFloater::updateInactiveFloaterTransparency() +{ + sInactiveControlTransparency = LLUI::sConfigGroup->getF32("InactiveFloaterTransparency"); +} + void LLFloater::addResizeCtrls() { // Resize bars (sides) @@ -571,6 +609,9 @@ void LLFloater::open() /* Flawfinder: ignore */ setVisibleAndFrontmost(mAutoFocus); } + if (!getControlName().empty()) + setControlValue(true); + onOpen(); } @@ -633,6 +674,34 @@ void LLFloater::close(bool app_quitting) } } + //If floater is a dependent, remove it from parent (dependee) + LLFloater* dependee = mDependeeHandle.get(); + if (dependee) + { + dependee->removeDependentFloater(this); + } + + // now close dependent floater + for (handle_set_iter_t dependent_it = mDependents.begin(); + dependent_it != mDependents.end(); ) + { + LLFloater* floaterp = dependent_it->get(); + if (floaterp) + { + ++dependent_it; + floaterp->close(app_quitting); + } + else + { + mDependents.erase(dependent_it++); + } + } + + cleanupHandles(); + + if (!app_quitting && !getControlName().empty()) + setControlValue(false); + // Let floater do cleanup. onClose(app_quitting); } @@ -714,11 +783,6 @@ void LLFloater::applyRectControl() void LLFloater::applyTitle() { - if (gNoRender) - { - return; - } - if (!mDragHandle) { return; @@ -747,7 +811,7 @@ void LLFloater::setTitle( const std::string& title ) applyTitle(); } -std::string LLFloater::getTitle() +std::string LLFloater::getTitle() const { if (mTitle.empty()) { @@ -765,7 +829,7 @@ void LLFloater::setShortTitle( const std::string& short_title ) applyTitle(); } -std::string LLFloater::getShortTitle() +std::string LLFloater::getShortTitle() const { if (mShortTitle.empty()) { @@ -777,13 +841,11 @@ std::string LLFloater::getShortTitle() } } - - BOOL LLFloater::canSnapTo(const LLView* other_view) { if (NULL == other_view) { - llwarns << "other_view is NULL" << llendl; + LL_WARNS() << "other_view is NULL" << LL_ENDL; return FALSE; } @@ -1017,7 +1079,8 @@ void LLFloater::setFocus( BOOL b ) if (b) { // only push focused floaters to front of stack if not in midst of ctrl-tab cycle - if (!getHost() && !((LLFloaterView*)getParent())->getCycleMode()) + LLFloaterView * parent = dynamic_cast(getParent()); + if (!getHost() && parent && !parent->getCycleMode()) { if (!isFrontmost()) { @@ -1034,6 +1097,7 @@ void LLFloater::setFocus( BOOL b ) last_focus->setFocus(TRUE); } } + updateTransparency(b ? TT_ACTIVE : TT_INACTIVE); } // virtual @@ -1075,8 +1139,9 @@ void LLFloater::setForeground(BOOL front) releaseFocus(); } - if (front || !LLUI::sConfigGroup->getBOOL("FloaterUnfocusedBackgroundOpaque")) // Singu Note: This can be removed when InactiveFloaterTransparency is added - setBackgroundOpaque( front ); + setBackgroundOpaque( front ); + // Singu Note: Upstream isn't doing this, I can't see where they were actually going inactive. Maybe setFocus(false) isn't being called, but we have parity there.. + updateTransparency(front || getIsChrome() ? TT_ACTIVE : TT_INACTIVE); } } @@ -1185,7 +1250,7 @@ void LLFloater::removeDependentFloater(LLFloater* floaterp) floaterp->mDependeeHandle = LLHandle(); } -BOOL LLFloater::offerClickToButton(S32 x, S32 y, MASK mask, EFloaterButtons index) +BOOL LLFloater::offerClickToButton(S32 x, S32 y, MASK mask, EFloaterButton index) { if( mButtonsEnabled[index] ) { @@ -1291,7 +1356,14 @@ void LLFloater::setFrontmost(BOOL take_focus) { // there are more than one floater view // so we need to query our parent directly - ((LLFloaterView*)getParent())->bringToFront(this, take_focus); + LLFloaterView * parent = dynamic_cast( getParent() ); + if (parent) + { + parent->bringToFront(this, take_focus); + } + + // Make sure to set the appropriate transparency type (STORM-732). + updateTransparency(hasFocus() || getIsChrome() ? TT_ACTIVE : TT_INACTIVE); } } @@ -1426,42 +1498,45 @@ void LLFloater::onClickClose() // virtual void LLFloater::draw() { + const F32 alpha = getCurrentTransparency(); + // draw background if( isBackgroundVisible() ) { + drawShadow(this); + S32 left = LLPANEL_BORDER_WIDTH; S32 top = getRect().getHeight() - LLPANEL_BORDER_WIDTH; S32 right = getRect().getWidth() - LLPANEL_BORDER_WIDTH; S32 bottom = LLPANEL_BORDER_WIDTH; - static LLColor4 shadow_color = LLUI::sColorsGroup->getColor("ColorDropShadow"); - static F32 shadow_offset = (F32)LLUI::sConfigGroup->getS32("DropShadowFloater"); - if (!isBackgroundOpaque()) - { - shadow_offset *= 0.2f; - shadow_color.mV[VALPHA] *= 0.5f; - } - gl_drop_shadow(left, top, right, bottom, - shadow_color, - llround(shadow_offset)); - // No transparent windows in simple UI + LLColor4 color; if (isBackgroundOpaque()) { - gl_rect_2d( left, top, right, bottom, getBackgroundColor() ); + color = getBackgroundColor(); } else { - gl_rect_2d( left, top, right, bottom, getTransparentColor() ); + color = getTransparentColor(); } - if(gFocusMgr.childHasKeyboardFocus(this) && !getIsChrome() && !getCurrentTitle().empty()) { + // We're not using images, use old-school flat colors + gl_rect_2d( left, top, right, bottom, color % alpha ); + // draw highlight on title bar to indicate focus. RDW - const LLFontGL* font = LLResMgr::getInstance()->getRes( LLFONT_SANSSERIF ); - LLRect r = getRect(); - gl_rect_2d_offset_local(0, r.getHeight(), r.getWidth(), r.getHeight() - (S32)font->getLineHeight() - 1, - LLUI::sColorsGroup->getColor("TitleBarFocusColor"), 0, TRUE); + if(gFocusMgr.childHasKeyboardFocus(this) + && !getIsChrome() + && !getCurrentTitle().empty()) + { + static auto titlebar_focus_color = LLUI::sColorsGroup->getColor("TitleBarFocusColor"); + + const LLFontGL* font = LLFontGL::getFontSansSerif(); + LLRect r = getRect(); + gl_rect_2d_offset_local(0, r.getHeight(), r.getWidth(), r.getHeight() - (S32)font->getLineHeight() - 1, + titlebar_focus_color % alpha, 0, TRUE); + } } } @@ -1492,23 +1567,8 @@ void LLFloater::draw() } else { - // draw children - LLView* focused_child = dynamic_cast(gFocusMgr.getKeyboardFocus()); - BOOL focused_child_visible = FALSE; - if (focused_child && focused_child->getParent() == this) - { - focused_child_visible = focused_child->getVisible(); - focused_child->setVisible(FALSE); - } - // don't call LLPanel::draw() since we've implemented custom background rendering LLView::draw(); - - if (focused_child_visible) - { - focused_child->setVisible(TRUE); - } - drawChild(focused_child); } if( isBackgroundVisible() ) @@ -1533,6 +1593,49 @@ void LLFloater::draw() } } +void LLFloater::drawShadow(LLPanel* panel) +{ + S32 left = LLPANEL_BORDER_WIDTH; + S32 top = panel->getRect().getHeight() - LLPANEL_BORDER_WIDTH; + S32 right = panel->getRect().getWidth() - LLPANEL_BORDER_WIDTH; + S32 bottom = LLPANEL_BORDER_WIDTH; + + static LLUICachedControl shadow_offset_S32 ("DropShadowFloater", 0); + static LLColor4 shadow_color = LLUI::sColorsGroup->getColor("ColorDropShadow"); + F32 shadow_offset = (F32)shadow_offset_S32; + + if (!panel->isBackgroundOpaque()) + { + shadow_offset *= 0.2f; + shadow_color.mV[VALPHA] *= 0.5f; + } + gl_drop_shadow(left, top, right, bottom, + shadow_color % getCurrentTransparency(), + ll_round(shadow_offset)); +} + +void LLFloater::updateTransparency(LLView* view, ETypeTransparency transparency_type) +{ + if (view) + { + if (view->isCtrl()) + { + static_cast(view)->setTransparencyType(transparency_type); + } + + for (LLView* pChild : *view->getChildList()) + { + if ((pChild->getChildCount()) || (pChild->isCtrl())) + updateTransparency(pChild, transparency_type); + } + } +} + +void LLFloater::updateTransparency(ETypeTransparency transparency_type) +{ + updateTransparency(this, transparency_type); +} + void LLFloater::setCanMinimize(BOOL can_minimize) { // if removing minimize/restore button programmatically, @@ -1623,16 +1726,16 @@ void LLFloater::updateButtons() btn_rect.setLeftTopAndSize( LLPANEL_BORDER_WIDTH, getRect().getHeight() - CLOSE_BOX_FROM_TOP - (LLFLOATER_CLOSE_BOX_SIZE + 1) * button_count, - llround((F32)LLFLOATER_CLOSE_BOX_SIZE * mButtonScale), - llround((F32)LLFLOATER_CLOSE_BOX_SIZE * mButtonScale)); + ll_round((F32)LLFLOATER_CLOSE_BOX_SIZE * mButtonScale), + ll_round((F32)LLFLOATER_CLOSE_BOX_SIZE * mButtonScale)); } else { btn_rect.setLeftTopAndSize( getRect().getWidth() - LLPANEL_BORDER_WIDTH - (LLFLOATER_CLOSE_BOX_SIZE + 1) * button_count, getRect().getHeight() - CLOSE_BOX_FROM_TOP, - llround((F32)LLFLOATER_CLOSE_BOX_SIZE * mButtonScale), - llround((F32)LLFLOATER_CLOSE_BOX_SIZE * mButtonScale)); + ll_round((F32)LLFLOATER_CLOSE_BOX_SIZE * mButtonScale), + ll_round((F32)LLFLOATER_CLOSE_BOX_SIZE * mButtonScale)); } mButtons[i]->setRect(btn_rect); @@ -1659,16 +1762,16 @@ void LLFloater::buildButtons() btn_rect.setLeftTopAndSize( LLPANEL_BORDER_WIDTH, getRect().getHeight() - CLOSE_BOX_FROM_TOP - (LLFLOATER_CLOSE_BOX_SIZE + 1) * (i + 1), - llround(LLFLOATER_CLOSE_BOX_SIZE * mButtonScale), - llround(LLFLOATER_CLOSE_BOX_SIZE * mButtonScale)); + ll_round(LLFLOATER_CLOSE_BOX_SIZE * mButtonScale), + ll_round(LLFLOATER_CLOSE_BOX_SIZE * mButtonScale)); } else { btn_rect.setLeftTopAndSize( getRect().getWidth() - LLPANEL_BORDER_WIDTH - (LLFLOATER_CLOSE_BOX_SIZE + 1) * (i + 1), getRect().getHeight() - CLOSE_BOX_FROM_TOP, - llround(LLFLOATER_CLOSE_BOX_SIZE * mButtonScale), - llround(LLFLOATER_CLOSE_BOX_SIZE * mButtonScale)); + ll_round(LLFLOATER_CLOSE_BOX_SIZE * mButtonScale), + ll_round(LLFLOATER_CLOSE_BOX_SIZE * mButtonScale)); } LLButton* buttonp = new LLButton( @@ -2328,7 +2431,7 @@ LLRect LLFloaterView::getSnapRect() const return snap_rect; } -LLFloater *LLFloaterView::getFocusedFloater() +LLFloater *LLFloaterView::getFocusedFloater() const { for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) { @@ -2341,7 +2444,7 @@ LLFloater *LLFloaterView::getFocusedFloater() return NULL; } -LLFloater *LLFloaterView::getFrontmost() +LLFloater *LLFloaterView::getFrontmost() const { for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) { @@ -2354,7 +2457,7 @@ LLFloater *LLFloaterView::getFrontmost() return NULL; } -LLFloater *LLFloaterView::getBackmost() +LLFloater *LLFloaterView::getBackmost() const { LLFloater* back_most = NULL; for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) @@ -2389,7 +2492,7 @@ void LLFloaterView::syncFloaterTabOrder() } } -LLFloater* LLFloaterView::getParentFloater(LLView* viewp) +LLFloater* LLFloaterView::getParentFloater(LLView* viewp) const { LLView* parentp = viewp->getParent(); @@ -2510,7 +2613,7 @@ LLView* LLFloater::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *f return floaterp; } -LLFastTimer::DeclareTimer POST_BUILD("Floater Post Build"); +LLTrace::BlockTimerStatHandle POST_BUILD("Floater Post Build"); void LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory, BOOL open) /* Flawfinder: ignore */ { std::string name(getName()); @@ -2582,14 +2685,14 @@ void LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactor BOOL result; { - LLFastTimer ft(POST_BUILD); + LL_RECORD_BLOCK_TIME(POST_BUILD); result = postBuild(); } if (!result) { - llerrs << "Failed to construct floater " << name << llendl; + LL_ERRS() << "Failed to construct floater " << name << LL_ENDL; } applyRectControl(); diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h index bd826a9366..f53e2714f5 100644 --- a/indra/llui/llfloater.h +++ b/indra/llui/llfloater.h @@ -94,16 +94,19 @@ class LLFloater : public LLPanel friend class LLFloaterView; friend class LLMultiFloater; public: - enum EFloaterButtons + enum EFloaterButton { - BUTTON_CLOSE, + BUTTON_CLOSE = 0, BUTTON_RESTORE, BUTTON_MINIMIZE, BUTTON_TEAR_OFF, BUTTON_EDIT, BUTTON_COUNT }; - + + // Load translations for tooltips for standard buttons + static void initClass(); + LLFloater(); LLFloater(const std::string& name); //simple constructor for data-driven initialization LLFloater( const std::string& name, const LLRect& rect, const std::string& title, @@ -164,9 +167,9 @@ class LLFloater : public LLPanel void applyTitle(); const std::string& getCurrentTitle() const; void setTitle( const std::string& title); - std::string getTitle(); + std::string getTitle() const; void setShortTitle( const std::string& short_title ); - std::string getShortTitle(); + std::string getShortTitle() const; void setTitleVisible(bool visible); virtual void setMinimized(BOOL b); void moveResizeHandlesToFront(); @@ -174,8 +177,8 @@ class LLFloater : public LLPanel void addDependentFloater(LLHandle dependent_handle, BOOL reposition = TRUE); LLFloater* getDependee() { return (LLFloater*)mDependeeHandle.get(); } void removeDependentFloater(LLFloater* dependent); - BOOL isMinimized() { return mMinimized; } - BOOL isFrontmost(); + BOOL isMinimized() const { return mMinimized; } + virtual BOOL isFrontmost(); BOOL isDependent() { return !mDependeeHandle.isDead(); } void setCanMinimize(BOOL can_minimize); void setCanClose(BOOL can_close); @@ -199,6 +202,7 @@ class LLFloater : public LLPanel virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask); virtual BOOL handleMiddleMouseDown(S32 x, S32 y, MASK mask); virtual void draw(); + virtual void drawShadow(LLPanel* panel); virtual void onOpen() {} @@ -218,7 +222,6 @@ class LLFloater : public LLPanel virtual BOOL canSaveAs() const { return FALSE; } virtual void saveAs() {} - virtual void saveAsType(BOOL type=false) {} void setSnapTarget(LLHandle handle) { mSnappedTo = handle; } void clearSnapTarget() { mSnappedTo.markDead(); } @@ -245,6 +248,8 @@ class LLFloater : public LLPanel static BOOL getEditModeEnabled() { return sEditModeEnabled; } static LLMultiFloater* getFloaterHost() {return sHostp; } + void updateTransparency(ETypeTransparency transparency_type); + void enableResizeCtrls(bool enable, bool width = true, bool height = true); protected: @@ -260,21 +265,29 @@ class LLFloater : public LLPanel void destroy() { die(); } // Don't call this directly. You probably want to call close(). JC private: - void setForeground(BOOL b); // called only by floaterview void cleanupHandles(); // remove handles to dead floaters void createMinimizeButton(); void updateButtons(); void buildButtons(); - BOOL offerClickToButton(S32 x, S32 y, MASK mask, EFloaterButtons index); + BOOL offerClickToButton(S32 x, S32 y, MASK mask, EFloaterButton index); void addResizeCtrls(); void layoutResizeCtrls(); + static void updateActiveFloaterTransparency(); + static void updateInactiveFloaterTransparency(); + void updateTransparency(LLView* view, ETypeTransparency transparency_type); + LLRect mExpandedRect; + +protected: LLDragHandle* mDragHandle; LLResizeBar* mResizeBar[4]; LLResizeHandle* mResizeHandle[4]; LLButton *mMinimizeButton; + + LLButton* mButtons[BUTTON_COUNT]; +private: BOOL mCanTearOff; BOOL mMinimized; BOOL mForeground; @@ -295,10 +308,7 @@ class LLFloater : public LLPanel handle_set_t mDependents; bool mDragOnLeft; - BOOL mButtonsEnabled[BUTTON_COUNT]; -protected: - LLButton* mButtons[BUTTON_COUNT]; -private: + bool mButtonsEnabled[BUTTON_COUNT]; F32 mButtonScale; BOOL mAutoFocus; LLHandle mSnappedTo; @@ -345,7 +355,7 @@ class LLFloaterView : public LLUICtrl /*virtual*/ void draw(); /*virtual*/ LLRect getSnapRect() const; - void refresh(); + /*virtual*/ void refresh(); void getNewFloaterPosition( S32* left, S32* top ); void resetStartingFloaterPosition(); @@ -374,10 +384,10 @@ class LLFloaterView : public LLUICtrl void minimizeAllChildren(); //
    - LLFloater* getFrontmost(); - LLFloater* getBackmost(); - LLFloater* getParentFloater(LLView* viewp); - LLFloater* getFocusedFloater(); + LLFloater* getFrontmost() const; + LLFloater* getBackmost() const; + LLFloater* getParentFloater(LLView* viewp) const; + LLFloater* getFocusedFloater() const; void syncFloaterTabOrder(); // Returns z order of child provided. 0 is closest, larger numbers diff --git a/indra/llui/llflyoutbutton.cpp b/indra/llui/llflyoutbutton.cpp index b45cdda3b2..52f443d91a 100644 --- a/indra/llui/llflyoutbutton.cpp +++ b/indra/llui/llflyoutbutton.cpp @@ -107,6 +107,9 @@ LLView* LLFlyoutButton::fromXML(LLXMLNodePtr node, LLView* parent, LLUICtrlFacto flyout_button->mListPosition = ABOVE; } + if (LLFontGL* font = selectFont(node)) + flyout_button->mActionButton->setFont(font); + flyout_button->initFromXML(node, parent); for (LLXMLNodePtr child = node->getFirstChild(); child.notNull(); child = child->getNextSibling()) @@ -170,4 +173,8 @@ void LLFlyoutButton::setToggleState(BOOL state) mToggleState = state; } +void LLFlyoutButton::setLabel(const std::string& label) +{ + mActionButton->setLabel(label); +} diff --git a/indra/llui/llflyoutbutton.h b/indra/llui/llflyoutbutton.h index 0d9ce80bfe..d74a7eb3a0 100644 --- a/indra/llui/llflyoutbutton.h +++ b/indra/llui/llflyoutbutton.h @@ -45,6 +45,7 @@ class LLFlyoutButton : public LLComboBox virtual void setEnabled(BOOL enabled); void setToggleState(BOOL state); + void setLabel(const std::string& label); // Not to be confused with LLComboBox::setLabel virtual LLXMLNodePtr getXML(bool save_children = true) const; static LLView* fromXML(LLXMLNodePtr node, LLView* parent, LLUICtrlFactory* factory); diff --git a/indra/llui/llfocusmgr.cpp b/indra/llui/llfocusmgr.cpp index 7817fd0d57..60983c9d4e 100644 --- a/indra/llui/llfocusmgr.cpp +++ b/indra/llui/llfocusmgr.cpp @@ -33,10 +33,10 @@ const F32 FOCUS_FADE_TIME = 0.3f; LLFocusableElement::LLFocusableElement() -: mFocusLostCallback(NULL), - mFocusReceivedCallback(NULL), - mFocusChangedCallback(NULL), - mTopLostCallback(NULL) +: mFocusLostCallback(nullptr), + mFocusReceivedCallback(nullptr), + mFocusChangedCallback(nullptr), + mTopLostCallback(nullptr) { } @@ -46,12 +46,30 @@ BOOL LLFocusableElement::handleKey(KEY key, MASK mask, BOOL called_from_parent) return FALSE; } +// virtual +BOOL LLFocusableElement::handleKeyUp(KEY key, MASK mask, BOOL called_from_parent) +{ + return FALSE; +} + // virtual BOOL LLFocusableElement::handleUnicodeChar(llwchar uni_char, BOOL called_from_parent) { return FALSE; } +// virtual +bool LLFocusableElement::wantsKeyUpKeyDown() const +{ + return false; +} + +//virtual +bool LLFocusableElement::wantsReturnKey() const +{ + return false; +} + // virtual LLFocusableElement::~LLFocusableElement() { @@ -128,14 +146,14 @@ struct LLFocusMgr::Impl LLFocusMgr gFocusMgr; LLFocusMgr::LLFocusMgr() -: mLockedView( NULL ), - mMouseCaptor( NULL ), - mKeyboardFocus( NULL ), - mLastKeyboardFocus( NULL ), - mDefaultKeyboardFocus( NULL ), - mLastDefaultKeyboardFocus( NULL ), +: mLockedView(nullptr ), + mMouseCaptor(nullptr ), + mKeyboardFocus(nullptr ), + mLastKeyboardFocus(nullptr ), + mDefaultKeyboardFocus(nullptr ), + mLastDefaultKeyboardFocus(nullptr ), mKeystrokesOnly(FALSE), - mTopCtrl( NULL ), + mTopCtrl(nullptr ), mAppHasFocus(TRUE), // Macs don't seem to notify us that we've gotten focus, so default to true mImpl(new LLFocusMgr::Impl) { @@ -145,22 +163,22 @@ LLFocusMgr::~LLFocusMgr() { mImpl->mFocusHistory.clear(); delete mImpl; - mImpl = NULL; + mImpl = nullptr; } void LLFocusMgr::releaseFocusIfNeeded( const LLView* view ) { if( childHasMouseCapture( view ) ) { - setMouseCapture( NULL ); + setMouseCapture(nullptr ); } if( childHasKeyboardFocus( view )) { if (view == mLockedView) { - mLockedView = NULL; - setKeyboardFocus( NULL ); + mLockedView = nullptr; + setKeyboardFocus(nullptr ); } else { @@ -170,7 +188,7 @@ void LLFocusMgr::releaseFocusIfNeeded( const LLView* view ) if( childIsTopCtrl( view ) ) { - setTopCtrl( NULL ); + setTopCtrl(nullptr); } } @@ -179,7 +197,7 @@ void LLFocusMgr::restoreDefaultKeyboardFocus(LLFocusableElement* current_default if (current_default_focus && mDefaultKeyboardFocus == current_default_focus) { setDefaultKeyboardFocus(mLastDefaultKeyboardFocus); - mLastDefaultKeyboardFocus = NULL; + mLastDefaultKeyboardFocus = nullptr; } } @@ -188,7 +206,7 @@ void LLFocusMgr::restoreKeyboardFocus(LLFocusableElement* current_focus) if (current_focus && mKeyboardFocus == current_focus) { setKeyboardFocus(mLastKeyboardFocus); - mLastKeyboardFocus = NULL; + mLastKeyboardFocus = nullptr; } } @@ -201,7 +219,7 @@ void LLFocusMgr::setKeyboardFocus(LLFocusableElement* new_focus, BOOL lock, BOOL focus_dirty = false; if (mLockedView && - (new_focus == NULL || + (new_focus == nullptr || (new_focus != mLockedView && dynamic_cast(new_focus) && !dynamic_cast(new_focus)->hasAncestor(mLockedView)))) @@ -273,7 +291,7 @@ void LLFocusMgr::setKeyboardFocus(LLFocusableElement* new_focus, BOOL lock, BOOL // If we've got a default keyboard focus, and the caller is // releasing keyboard focus, move to the default. - if (mDefaultKeyboardFocus != NULL && mKeyboardFocus == NULL) + if (mDefaultKeyboardFocus != nullptr && mKeyboardFocus == nullptr) { mDefaultKeyboardFocus->setFocus(TRUE); } @@ -325,7 +343,7 @@ BOOL LLFocusMgr::childHasKeyboardFocus(const LLView* parent ) const // Returns TRUE is parent or any descedent of parent is the mouse captor. BOOL LLFocusMgr::childHasMouseCapture( const LLView* parent ) const { - if( mMouseCaptor && dynamic_cast(mMouseCaptor) != NULL ) + if( mMouseCaptor && dynamic_cast(mMouseCaptor) != nullptr ) { LLView* captor_view = (LLView*)mMouseCaptor; while( captor_view ) @@ -346,26 +364,41 @@ void LLFocusMgr::removeKeyboardFocusWithoutCallback( const LLFocusableElement* f // in order to unlock it if (focus == mLockedView) { - mLockedView = NULL; + mLockedView = nullptr; } + if (mKeyboardFocus == focus) { - mKeyboardFocus = NULL; + mKeyboardFocus = nullptr; } if (mLastKeyboardFocus == focus) { - mLastKeyboardFocus = NULL; + mLastKeyboardFocus = nullptr; } if (mDefaultKeyboardFocus == focus) { - mDefaultKeyboardFocus = NULL; + mDefaultKeyboardFocus = nullptr; } if (mLastDefaultKeyboardFocus == focus) { - mLastDefaultKeyboardFocus = NULL; + mLastDefaultKeyboardFocus = nullptr; } } +bool LLFocusMgr::keyboardFocusHasAccelerators() const +{ + LLView* focus_view = dynamic_cast(mKeyboardFocus); + while(focus_view) + { + if (focus_view->hasAccelerators()) + { + return true; + } + + focus_view = focus_view->getParent(); + } + return false; +} void LLFocusMgr::setMouseCapture( LLMouseHandler* new_captor ) { @@ -378,11 +411,11 @@ void LLFocusMgr::setMouseCapture( LLMouseHandler* new_captor ) { if (new_captor) { - llinfos << "New mouse captor: " << new_captor->getName() << llendl; + LL_INFOS() << "New mouse captor: " << new_captor->getName() << LL_ENDL; } else { - llinfos << "New mouse captor: NULL" << llendl; + LL_INFOS() << "New mouse captor: NULL" << LL_ENDL; } } @@ -398,7 +431,7 @@ void LLFocusMgr::removeMouseCaptureWithoutCallback( const LLMouseHandler* captor { if( mMouseCaptor == captor ) { - mMouseCaptor = NULL; + mMouseCaptor = nullptr; } } @@ -438,7 +471,7 @@ void LLFocusMgr::removeTopCtrlWithoutCallback( const LLUICtrl* top_view ) { if( mTopCtrl == top_view ) { - mTopCtrl = NULL; + mTopCtrl = nullptr; } } @@ -449,7 +482,7 @@ void LLFocusMgr::lockFocus() void LLFocusMgr::unlockFocus() { - mLockedView = NULL; + mLockedView = nullptr; } F32 LLFocusMgr::getFocusFlashAmt() const @@ -484,7 +517,7 @@ void LLFocusMgr::setAppHasFocus(BOOL focus) // release focus from "top ctrl"s, which generally hides them if (!focus && mTopCtrl) { - setTopCtrl(NULL); + setTopCtrl(nullptr); } mAppHasFocus = focus; } @@ -500,7 +533,7 @@ LLUICtrl* LLFocusMgr::getLastFocusForGroup(LLView* subtree_root) const return static_cast(found_it->second.get()); } } - return NULL; + return nullptr; } void LLFocusMgr::clearLastFocusForGroup(LLView* subtree_root) diff --git a/indra/llui/llfocusmgr.h b/indra/llui/llfocusmgr.h index 5f1466f5df..04c32e11f7 100644 --- a/indra/llui/llfocusmgr.h +++ b/indra/llui/llfocusmgr.h @@ -57,8 +57,17 @@ class LLFocusableElement // These were brought up the hierarchy from LLView so that we don't have to use dynamic_cast when dealing with keyboard focus. virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); + virtual BOOL handleKeyUp(KEY key, MASK mask, BOOL called_from_parent); virtual BOOL handleUnicodeChar(llwchar uni_char, BOOL called_from_parent); + /** + * If true this LLFocusableElement wants to receive KEYUP and KEYDOWN messages + * even for normal character strokes. + * Default implementation returns false. + */ + virtual bool wantsKeyUpKeyDown() const; + virtual bool wantsReturnKey() const; + virtual void onTopLost(); // called when registered as top ctrl and user clicks elsewhere protected: virtual void onFocusReceived(); @@ -94,7 +103,7 @@ class LLFocusMgr F32 getFocusTime() const { return mFocusFlashTimer.getElapsedTimeF32(); } F32 getFocusFlashAmt() const; - S32 getFocusFlashWidth() const { return llround(lerp(1.f, 3.f, getFocusFlashAmt())); } + S32 getFocusFlashWidth() const { return ll_round(lerp(1.f, 3.f, getFocusFlashAmt())); } LLColor4 getFocusColor() const; void triggerFocusFlash(); BOOL getAppHasFocus() const { return mAppHasFocus; } @@ -121,6 +130,7 @@ class LLFocusMgr void unlockFocus(); BOOL focusLocked() const { return mLockedView != NULL; } + bool keyboardFocusHasAccelerators() const; struct Impl; diff --git a/indra/llui/llfunctorregistry.h b/indra/llui/llfunctorregistry.h index 31d48084b1..43c8b47c80 100644 --- a/indra/llui/llfunctorregistry.h +++ b/indra/llui/llfunctorregistry.h @@ -37,8 +37,6 @@ #include #include -#include - #include "llsd.h" #include "llsingleton.h" @@ -81,7 +79,7 @@ class LLFunctorRegistry : public LLSingleton > } else { - llerrs << "attempt to store duplicate name '" << name << "' in LLFunctorRegistry. NOT ADDED." << llendl; + LL_ERRS() << "attempt to store duplicate name '" << name << "' in LLFunctorRegistry. NOT ADDED." << LL_ENDL; retval = false; } @@ -92,7 +90,7 @@ class LLFunctorRegistry : public LLSingleton > { if (mMap.count(name) == 0) { - llwarns << "trying to remove '" << name << "' from LLFunctorRegistry but it's not there." << llendl; + LL_WARNS() << "trying to remove '" << name << "' from LLFunctorRegistry but it's not there." << LL_ENDL; return false; } mMap.erase(name); @@ -107,7 +105,7 @@ class LLFunctorRegistry : public LLSingleton > } else { - llwarns << "tried to find '" << name << "' in LLFunctorRegistry, but it wasn't there." << llendl; + LL_WARNS() << "tried to find '" << name << "' in LLFunctorRegistry, but it wasn't there." << LL_ENDL; return mMap[LOGFUNCTOR]; } } @@ -119,7 +117,7 @@ class LLFunctorRegistry : public LLSingleton > static void log_functor(const LLSD& notification, const LLSD& payload) { - llwarns << "log_functor called with payload: " << payload << llendl; + LL_WARNS() << "log_functor called with payload: " << payload << LL_ENDL; } static void do_nothing(const LLSD& notification, const LLSD& payload) @@ -140,5 +138,6 @@ class LLFunctorRegistration } }; + #endif//LL_LLFUNCTORREGISTRY_H diff --git a/indra/llui/lliconctrl.cpp b/indra/llui/lliconctrl.cpp index 90b313d45c..fecdce4329 100644 --- a/indra/llui/lliconctrl.cpp +++ b/indra/llui/lliconctrl.cpp @@ -40,68 +40,56 @@ #include "llcontrol.h" #include "llui.h" #include "lluictrlfactory.h" - -const F32 RESOLUTION_BUMP = 1.f; +#include "lluiimage.h" static LLRegisterWidget r("icon"); -LLIconCtrl::LLIconCtrl(const std::string& name, const LLRect &rect, const LLUUID &image_id) -: LLUICtrl(name, - rect, - FALSE, // mouse opaque - NULL, - FOLLOWS_LEFT | FOLLOWS_TOP), - mColor( LLColor4::white ) +LLIconCtrl::Params::Params() +: image("image_name"), + color("color"), +// use_draw_context_alpha("use_draw_context_alpha", true), + scale_image("scale_image"), + min_width("min_width", 0), + min_height("min_height", 0) +{} + +LLIconCtrl::LLIconCtrl(const LLIconCtrl::Params& p) +: LLUICtrl(p), + mColor(p.color()), + mImagep(p.image), +// mUseDrawContextAlpha(p.use_draw_context_alpha), + mPriority(0), + mMinWidth(p.min_width), + mMinHeight(p.min_height) { - setImage( image_id ); - setTabStop(FALSE); + if (mImagep.notNull()) + { + LLUICtrl::setValue(mImagep->getName()); + } + setTabStop(false); } -LLIconCtrl::LLIconCtrl(const std::string& name, const LLRect &rect, const std::string &image_name) +LLIconCtrl::LLIconCtrl(const std::string& name, const LLRect &rect, const std::string &image_name, const S32& min_width, const S32& min_height) : LLUICtrl(name, rect, FALSE, // mouse opaque NULL, FOLLOWS_LEFT | FOLLOWS_TOP), mColor( LLColor4::white ), - mImageName(image_name) + mPriority(0), + mMinWidth(min_width), + mMinHeight(min_height) { - setImage( image_name ); + setValue( image_name ); setTabStop(FALSE); } - LLIconCtrl::~LLIconCtrl() { mImagep = NULL; } -void LLIconCtrl::setImage(const std::string& image_name) -{ - //RN: support UUIDs masquerading as strings - if (LLUUID::validate(image_name)) - { - mImageID = LLUUID(image_name); - - setImage(mImageID); - } - else - { - mImageName = image_name; - mImagep = LLUI::getUIImage(image_name); - mImageID.setNull(); - } -} - -void LLIconCtrl::setImage(const LLUUID& image_id) -{ - mImageName.clear(); - mImagep = LLUI::getUIImageByID(image_id); - mImageID = image_id; -} - - void LLIconCtrl::draw() { if( mImagep.notNull() ) @@ -120,23 +108,40 @@ void LLIconCtrl::setAlpha(F32 alpha) } // virtual +// value might be a string or a UUID void LLIconCtrl::setValue(const LLSD& value ) { - if (value.isUUID()) + LLSD tvalue(value); + if (value.isString() && LLUUID::validate(value.asString())) { - setImage(value.asUUID()); + //RN: support UUIDs masquerading as strings + tvalue = LLSD(LLUUID(value.asString())); + } + LLUICtrl::setValue(tvalue); + if (tvalue.isUUID()) + { + mImagep = LLUI::getUIImageByID(tvalue.asUUID(), mPriority); } else { - setImage(value.asString()); + mImagep = LLUI::getUIImage(tvalue.asString(), mPriority); + } + + if (mImagep.notNull() + && mImagep->getImage().notNull() + && mMinWidth + && mMinHeight) + { + mImagep->getImage()->setKnownDrawSize(llmax(mMinWidth, mImagep->getWidth()), llmax(mMinHeight, mImagep->getHeight())); } } -// virtual -LLSD LLIconCtrl::getValue() const +std::string LLIconCtrl::getImageName() const { - LLSD ret = getImage(); - return ret; + if (getValue().isString()) + return getValue().asString(); + else + return std::string(); } // virtual @@ -146,11 +151,14 @@ LLXMLNodePtr LLIconCtrl::getXML(bool save_children) const node->setName(LL_ICON_CTRL_TAG); - if (mImageName != "") + if (!getImageName().empty()) { - node->createChild("image_name", TRUE)->setStringValue(mImageName); + node->createChild("image_name", TRUE)->setStringValue(getImageName()); } + if (mMinWidth) node->createChild("min_width", true)->setIntValue(mMinWidth); + if (mMinHeight) node->createChild("min_height", true)->setIntValue(mMinHeight); + node->createChild("color", TRUE)->setFloatValue(4, mColor.mV); return node; @@ -170,7 +178,18 @@ LLView* LLIconCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory * LLColor4 color(LLColor4::white); LLUICtrlFactory::getAttributeColor(node,"color", color); - LLIconCtrl* icon = new LLIconCtrl("icon", rect, image_name); + S32 min_width = 0, min_height = 0; + if (node->hasAttribute("min_width")) + { + node->getAttributeS32("min_width", min_width); + } + + if (node->hasAttribute("min_height")) + { + node->getAttributeS32("min_height", min_height); + } + + LLIconCtrl* icon = new LLIconCtrl("icon", rect, image_name, min_width, min_height); icon->setColor(color); diff --git a/indra/llui/lliconctrl.h b/indra/llui/lliconctrl.h index 2506fb209d..16f4c42383 100644 --- a/indra/llui/lliconctrl.h +++ b/indra/llui/lliconctrl.h @@ -49,33 +49,55 @@ class LLIconCtrl : public LLUICtrl { public: - LLIconCtrl(const std::string& name, const LLRect &rect, const LLUUID &image_id); - LLIconCtrl(const std::string& name, const LLRect &rect, const std::string &image_name); + struct Params : public LLInitParam::Block + { + Optional image; + Optional color; +// Optional use_draw_context_alpha; + Optional min_width, + min_height; + Ignored scale_image; + + Params(); + }; +protected: + LLIconCtrl(const Params&); + friend class LLUICtrlFactory; + +public: + LLIconCtrl(const std::string& name, const LLRect &rect, const std::string &image_name, const S32& min_width = 0, const S32& min_height = 0); virtual ~LLIconCtrl(); // llview overrides virtual void draw(); - void setImage(const std::string& image_name); - void setImage(const LLUUID& image_name); - const LLUUID &getImage() const { return mImageID; } - std::string getImageName() const { return mImageName; } - - // Takes a UUID, wraps get/setImage + // lluictrl overrides virtual void setValue(const LLSD& value ); - virtual LLSD getValue() const; /*virtual*/ void setAlpha(F32 alpha); + std::string getImageName() const; + void setColor(const LLColor4& color) { mColor = color; } + void setImage(LLPointer image) { mImagep = image; } + const LLPointer getImage() { return mImagep; } virtual LLXMLNodePtr getXML(bool save_children = true) const; static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); +protected: + S32 mPriority; + + //the output size of the icon image if set. + S32 mMinWidth, + mMinHeight; + + // If set to true (default), use the draw context transparency. + // If false, will use transparency returned by getCurrentTransparency(). See STORM-698. + //bool mUseDrawContextAlpha; + private: LLColor4 mColor; - std::string mImageName; - LLUUID mImageID; LLPointer mImagep; }; diff --git a/indra/llui/llkeywords.cpp b/indra/llui/llkeywords.cpp index e3a2795fbd..148aedda4c 100644 --- a/indra/llui/llkeywords.cpp +++ b/indra/llui/llkeywords.cpp @@ -100,7 +100,7 @@ BOOL LLKeywords::loadFromFile( const std::string& filename ) file.open(filename); /* Flawfinder: ignore */ if( file.fail() ) { - llinfos << "LLKeywords::loadFromFile() Unable to open file: " << filename << llendl; + LL_INFOS() << "LLKeywords::loadFromFile() Unable to open file: " << filename << LL_ENDL; return mLoaded; } @@ -108,7 +108,7 @@ BOOL LLKeywords::loadFromFile( const std::string& filename ) file >> buffer; if( strcmp( buffer, "llkeywords" ) ) { - llinfos << filename << " does not appear to be a keyword file" << llendl; + LL_INFOS() << filename << " does not appear to be a keyword file" << LL_ENDL; return mLoaded; } @@ -118,7 +118,7 @@ BOOL LLKeywords::loadFromFile( const std::string& filename ) file >> version_num; if( strcmp(buffer, "version") || version_num != (U32)KEYWORD_FILE_CURRENT_VERSION ) { - llinfos << filename << " does not appear to be a version " << KEYWORD_FILE_CURRENT_VERSION << " keyword file" << llendl; + LL_INFOS() << filename << " does not appear to be a version " << KEYWORD_FILE_CURRENT_VERSION << " keyword file" << LL_ENDL; return mLoaded; } @@ -348,18 +348,18 @@ LLColor3 LLKeywords::readColor( const std::string& s ) S32 values_read = sscanf(s.c_str(), "%f, %f, %f]", &r, &g, &b ); if( values_read != 3 ) { - llinfos << " poorly formed color in keyword file" << llendl; + LL_INFOS() << " poorly formed color in keyword file" << LL_ENDL; } return LLColor3( r, g, b ); } -LLFastTimer::DeclareTimer FTM_SYNTAX_COLORING("Syntax Coloring"); +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) { - LLFastTimer ft(FTM_SYNTAX_COLORING); + LL_RECORD_BLOCK_TIME(FTM_SYNTAX_COLORING); seg_list->clear(); if( wtext.empty() ) @@ -560,7 +560,7 @@ void LLKeywords::findSegments(std::vector* seg_list, const LLW S32 seg_start = cur - base; S32 seg_end = seg_start + seg_len; - // llinfos << "Seg: [" << word.c_str() << "]" << llendl; + // LL_INFOS() << "Seg: [" << word.c_str() << "]" << LL_ENDL; LLTextSegmentPtr text_segment = new LLTextSegment( cur_token->getColor(), seg_start, seg_end ); @@ -605,10 +605,10 @@ void LLKeywords::insertSegment(std::vector& seg_list, LLTextSe #ifdef _DEBUG void LLKeywords::dump() { - llinfos << "LLKeywords" << llendl; + LL_INFOS() << "LLKeywords" << LL_ENDL; - llinfos << "LLKeywords::sWordTokenMap" << llendl; + LL_INFOS() << "LLKeywords::sWordTokenMap" << LL_ENDL; word_token_map_t::iterator word_token_iter = mWordTokenMap.begin(); while( word_token_iter != mWordTokenMap.end() ) { @@ -617,7 +617,7 @@ void LLKeywords::dump() ++word_token_iter; } - llinfos << "LLKeywords::sLineTokenList" << llendl; + LL_INFOS() << "LLKeywords::sLineTokenList" << LL_ENDL; for (token_list_t::iterator iter = mLineTokenList.begin(); iter != mLineTokenList.end(); ++iter) { @@ -626,7 +626,7 @@ void LLKeywords::dump() } - llinfos << "LLKeywords::sDelimiterTokenList" << llendl; + LL_INFOS() << "LLKeywords::sDelimiterTokenList" << LL_ENDL; for (token_list_t::iterator iter = mDelimiterTokenList.begin(); iter != mDelimiterTokenList.end(); ++iter) { @@ -637,12 +637,12 @@ void LLKeywords::dump() void LLKeywordToken::dump() { - llinfos << "[" << + LL_INFOS() << "[" << mColor.mV[VX] << ", " << mColor.mV[VY] << ", " << mColor.mV[VZ] << "] [" << wstring_to_utf8str(mToken) << "]" << - llendl; + LL_ENDL; } #endif // DEBUG diff --git a/indra/llui/lllayoutstack.cpp b/indra/llui/lllayoutstack.cpp index 83e532a65c..f704035544 100644 --- a/indra/llui/lllayoutstack.cpp +++ b/indra/llui/lllayoutstack.cpp @@ -34,7 +34,8 @@ #include "llpanel.h" #include "lluictrlfactory.h" #include "llcriticaldamp.h" -#include "boost/foreach.hpp" + +#include static const F32 MIN_FRACTIONAL_SIZE = 0.00001f; static const F32 MAX_FRACTIONAL_SIZE = 1.f; @@ -122,7 +123,7 @@ F32 LLLayoutPanel::getVisibleAmount() const S32 LLLayoutPanel::getLayoutDim() const { - return llround((F32)((mOrientation == LLLayoutStack::HORIZONTAL) + return ll_round((F32)((mOrientation == LLLayoutStack::HORIZONTAL) ? getRect().getWidth() : getRect().getHeight())); } @@ -149,7 +150,7 @@ void LLLayoutPanel::setTargetDim(S32 value) S32 LLLayoutPanel::getVisibleDim() const { F32 min_dim = getRelevantMinDim(); - return llround(mVisibleAmt + return ll_round(mVisibleAmt * (min_dim + (((F32)mTargetDim - min_dim) * (1.f - mCollapseAmt)))); } @@ -157,7 +158,7 @@ S32 LLLayoutPanel::getVisibleDim() const void LLLayoutPanel::setOrientation( LLLayoutStack::ELayoutOrientation orientation ) { mOrientation = orientation; - S32 layout_dim = llround((F32)((mOrientation == LLLayoutStack::HORIZONTAL) + S32 layout_dim = ll_round((F32)((mOrientation == LLLayoutStack::HORIZONTAL) ? getRect().getWidth() : getRect().getHeight())); @@ -245,7 +246,7 @@ void LLLayoutStack::draw() // always clip to stack itself LLLocalClipRect clip(getLocalRect()); - BOOST_FOREACH(LLLayoutPanel* panelp, mPanels) + for (LLLayoutPanel* panelp : mPanels) { // clip to layout rectangle, not bounding rectangle LLRect clip_rect = panelp->getRect(); @@ -276,7 +277,7 @@ void LLLayoutStack::draw() // Check for bogus rectangle if (!panelp->getRect().isValid()) { - llwarns << "Bogus rectangle for " << panelp->getName() << " with " << panelp->getRect() << llendl; + LL_WARNS() << "Bogus rectangle for " << panelp->getName() << " with " << panelp->getRect() << LL_ENDL; } } LLUI::popMatrix(); @@ -290,7 +291,7 @@ void LLLayoutStack::draw() // Check for bogus rectangle if (!getRect().isValid()) { - llwarns << "Bogus rectangle for " << getName() << " with " << getRect() << llendl; + LL_WARNS() << "Bogus rectangle for " << getName() << " with " << getRect() << LL_ENDL; } } } @@ -352,11 +353,11 @@ void LLLayoutStack::collapsePanel(LLPanel* panel, BOOL collapsed) mNeedsLayout = true; } -static LLFastTimer::DeclareTimer FTM_UPDATE_LAYOUT("Update LayoutStacks"); +static LLTrace::BlockTimerStatHandle FTM_UPDATE_LAYOUT("Update LayoutStacks"); void LLLayoutStack::updateLayout() { - LLFastTimer ft(FTM_UPDATE_LAYOUT); + LL_RECORD_BLOCK_TIME(FTM_UPDATE_LAYOUT); if (!mNeedsLayout) return; @@ -367,32 +368,32 @@ void LLLayoutStack::updateLayout() : getRect().getHeight(); // first, assign minimum dimensions - LLLayoutPanel* panelp = NULL; - BOOST_FOREACH(panelp, mPanels) + LLLayoutPanel* panelp = mPanels.size() ? *mPanels.rbegin() : nullptr; + for (auto* panelp : mPanels) { if (panelp->mAutoResize) { panelp->mTargetDim = panelp->getRelevantMinDim(); } - space_to_distribute -= panelp->getVisibleDim() + llround((F32)mPanelSpacing * panelp->getVisibleAmount()); + space_to_distribute -= panelp->getVisibleDim() + ll_round((F32)mPanelSpacing * panelp->getVisibleAmount()); total_visible_fraction += panelp->mFractionalSize * panelp->getAutoResizeFactor(); } llassert(total_visible_fraction < 1.05f); // don't need spacing after last panel - space_to_distribute += panelp ? llround((F32)mPanelSpacing * panelp->getVisibleAmount()) : 0; + space_to_distribute += panelp ? ll_round((F32)mPanelSpacing * panelp->getVisibleAmount()) : 0; S32 remaining_space = space_to_distribute; F32 fraction_distributed = 0.f; if (space_to_distribute > 0 && total_visible_fraction > 0.f) { // give space proportionally to visible auto resize panels - BOOST_FOREACH(LLLayoutPanel* panelp, mPanels) + for (LLLayoutPanel* panelp : mPanels) { if (panelp->mAutoResize) { F32 fraction_to_distribute = (panelp->mFractionalSize * panelp->getAutoResizeFactor()) / (total_visible_fraction); - S32 delta = llround((F32)space_to_distribute * fraction_to_distribute); + S32 delta = ll_round((F32)space_to_distribute * fraction_to_distribute); fraction_distributed += fraction_to_distribute; panelp->mTargetDim += delta; remaining_space -= delta; @@ -401,7 +402,7 @@ void LLLayoutStack::updateLayout() } // distribute any left over pixels to non-collapsed, visible panels - BOOST_FOREACH(LLLayoutPanel* panelp, mPanels) + for (LLLayoutPanel* panelp : mPanels) { if (remaining_space == 0) break; @@ -417,7 +418,7 @@ void LLLayoutStack::updateLayout() F32 cur_pos = (mOrientation == HORIZONTAL) ? 0.f : (F32)getRect().getHeight(); - BOOST_FOREACH(LLLayoutPanel* panelp, mPanels) + for (LLLayoutPanel* panelp : mPanels) { F32 panel_dim = llmax(panelp->getExpandedMinDim(), panelp->mTargetDim); F32 panel_visible_dim = panelp->getVisibleDim(); @@ -425,17 +426,17 @@ void LLLayoutStack::updateLayout() LLRect panel_rect; if (mOrientation == HORIZONTAL) { - panel_rect.setLeftTopAndSize(llround(cur_pos), + panel_rect.setLeftTopAndSize(ll_round(cur_pos), getRect().getHeight(), - llround(panel_dim), + ll_round(panel_dim), getRect().getHeight()); } else { panel_rect.setLeftTopAndSize(0, - llround(cur_pos), + ll_round(cur_pos), getRect().getWidth(), - llround(panel_dim)); + ll_round(panel_dim)); } panelp->setIgnoreReshape(true); panelp->setShape(panel_rect); @@ -447,14 +448,14 @@ void LLLayoutStack::updateLayout() if (mOrientation == HORIZONTAL) { resize_bar_rect.mLeft = panel_rect.mRight - mResizeBarOverlap; - resize_bar_rect.mRight = panel_rect.mRight + (S32)(llround(panel_spacing)) + mResizeBarOverlap; + resize_bar_rect.mRight = panel_rect.mRight + (S32)(ll_round(panel_spacing)) + mResizeBarOverlap; cur_pos += panel_visible_dim + panel_spacing; } else //VERTICAL { resize_bar_rect.mTop = panel_rect.mBottom + mResizeBarOverlap; - resize_bar_rect.mBottom = panel_rect.mBottom - (S32)(llround(panel_spacing)) - mResizeBarOverlap; + resize_bar_rect.mBottom = panel_rect.mBottom - (S32)(ll_round(panel_spacing)) - mResizeBarOverlap; cur_pos -= panel_visible_dim + panel_spacing; } @@ -473,7 +474,7 @@ LLLayoutPanel* LLLayoutStack::findEmbeddedPanel(LLPanel* panelp) const if (!panelp) return NULL; e_panel_list_t::const_iterator panel_it; - BOOST_FOREACH(LLLayoutPanel* p, mPanels) + for (LLLayoutPanel* p : mPanels) { if (p == panelp) { @@ -487,7 +488,7 @@ LLLayoutPanel* LLLayoutStack::findEmbeddedPanelByName(const std::string& name) c { LLLayoutPanel* result = NULL; - BOOST_FOREACH(LLLayoutPanel* p, mPanels) + for (LLLayoutPanel* p : mPanels) { if (p->getName() == name) { @@ -501,7 +502,7 @@ LLLayoutPanel* LLLayoutStack::findEmbeddedPanelByName(const std::string& name) c void LLLayoutStack::createResizeBar(LLLayoutPanel* panelp) { - BOOST_FOREACH(LLLayoutPanel* lp, mPanels) + for (LLLayoutPanel* lp : mPanels) { if (lp->mResizeBar == NULL) { @@ -534,7 +535,7 @@ void LLLayoutStack::createResizeBar(LLLayoutPanel* panelp) //static void LLLayoutStack::updateClass() { - for (instance_iter it = beginInstances(); it != endInstances(); ++it) + for (instance_iter it = beginInstances(), it_end(endInstances()); it != it_end; ++it) { it->updateLayout(); it->mAnimatedThisFrame = false; @@ -545,7 +546,7 @@ void LLLayoutStack::updateFractionalSizes() { F32 total_resizable_dim = 0.f; - BOOST_FOREACH(LLLayoutPanel* panelp, mPanels) + for (LLLayoutPanel* panelp : mPanels) { if (panelp->mAutoResize) { @@ -553,7 +554,7 @@ void LLLayoutStack::updateFractionalSizes() } } - BOOST_FOREACH(LLLayoutPanel* panelp, mPanels) + for (LLLayoutPanel* panelp : mPanels) { if (panelp->mAutoResize) { @@ -561,7 +562,7 @@ void LLLayoutStack::updateFractionalSizes() panelp->mFractionalSize = panel_resizable_dim > 0.f ? llclamp(panel_resizable_dim / total_resizable_dim, MIN_FRACTIONAL_SIZE, MAX_FRACTIONAL_SIZE) : MIN_FRACTIONAL_SIZE; - llassert(!llisnan(panelp->mFractionalSize)); + llassert(!std::isnan(panelp->mFractionalSize)); } } @@ -574,7 +575,7 @@ void LLLayoutStack::normalizeFractionalSizes() S32 num_auto_resize_panels = 0; F32 total_fractional_size = 0.f; - BOOST_FOREACH(LLLayoutPanel* panelp, mPanels) + for (LLLayoutPanel* panelp : mPanels) { if (panelp->mAutoResize) { @@ -585,7 +586,7 @@ void LLLayoutStack::normalizeFractionalSizes() if (total_fractional_size == 0.f) { // equal distribution - BOOST_FOREACH(LLLayoutPanel* panelp, mPanels) + for (LLLayoutPanel* panelp : mPanels) { if (panelp->mAutoResize) { @@ -595,7 +596,7 @@ void LLLayoutStack::normalizeFractionalSizes() } else { // renormalize - BOOST_FOREACH(LLLayoutPanel* panelp, mPanels) + for (LLLayoutPanel* panelp : mPanels) { if (panelp->mAutoResize) { @@ -612,7 +613,7 @@ bool LLLayoutStack::animatePanels() // // animate visibility // - BOOST_FOREACH(LLLayoutPanel* panelp, mPanels) + for (LLLayoutPanel* panelp : mPanels) { if (panelp->getVisible()) { @@ -620,7 +621,7 @@ bool LLLayoutStack::animatePanels() { if (!mAnimatedThisFrame) { - panelp->mVisibleAmt = lerp(panelp->mVisibleAmt, 1.f, LLCriticalDamp::getInterpolant(mOpenTimeConstant)); + panelp->mVisibleAmt = lerp(panelp->mVisibleAmt, 1.f, LLSmoothInterpolation::getInterpolant(mOpenTimeConstant)); if (panelp->mVisibleAmt > 0.99f) { panelp->mVisibleAmt = 1.f; @@ -645,7 +646,7 @@ bool LLLayoutStack::animatePanels() { if (!mAnimatedThisFrame) { - panelp->mVisibleAmt = lerp(panelp->mVisibleAmt, 0.f, LLCriticalDamp::getInterpolant(mCloseTimeConstant)); + panelp->mVisibleAmt = lerp(panelp->mVisibleAmt, 0.f, LLSmoothInterpolation::getInterpolant(mCloseTimeConstant)); if (panelp->mVisibleAmt < 0.001f) { panelp->mVisibleAmt = 0.f; @@ -672,7 +673,7 @@ bool LLLayoutStack::animatePanels() { if (!mAnimatedThisFrame) { - panelp->mCollapseAmt = lerp(panelp->mCollapseAmt, collapse_state, LLCriticalDamp::getInterpolant(mCloseTimeConstant)); + panelp->mCollapseAmt = lerp(panelp->mCollapseAmt, collapse_state, LLSmoothInterpolation::getInterpolant(mCloseTimeConstant)); } if (llabs(panelp->mCollapseAmt - collapse_state) < 0.001f) @@ -710,7 +711,7 @@ void LLLayoutStack::updatePanelRect( LLLayoutPanel* resized_panel, const LLRect& LLLayoutPanel* other_resize_panel = NULL; LLLayoutPanel* following_panel = NULL; - BOOST_REVERSE_FOREACH(LLLayoutPanel* panelp, mPanels) + for(LLLayoutPanel* panelp : boost::adaptors::reverse(mPanels)) { if (panelp->mAutoResize) { @@ -759,7 +760,7 @@ void LLLayoutStack::updatePanelRect( LLLayoutPanel* resized_panel, const LLRect& AFTER_RESIZED_PANEL } which_panel = BEFORE_RESIZED_PANEL; - BOOST_FOREACH(LLLayoutPanel* panelp, mPanels) + for (LLLayoutPanel* panelp : mPanels) { if (!panelp->getVisible() || panelp->mCollapsed) { @@ -789,7 +790,7 @@ void LLLayoutStack::updatePanelRect( LLLayoutPanel* resized_panel, const LLRect& fraction_given_up -= new_fractional_size - panelp->mFractionalSize; fraction_remaining -= panelp->mFractionalSize; panelp->mFractionalSize = new_fractional_size; - llassert(!llisnan(panelp->mFractionalSize)); + llassert(!std::isnan(panelp->mFractionalSize)); } else { @@ -805,7 +806,7 @@ void LLLayoutStack::updatePanelRect( LLLayoutPanel* resized_panel, const LLRect& fraction_given_up -= new_fractional_size - panelp->mFractionalSize; fraction_remaining -= panelp->mFractionalSize; panelp->mFractionalSize = new_fractional_size; - llassert(!llisnan(panelp->mFractionalSize)); + llassert(!std::isnan(panelp->mFractionalSize)); } else { // freeze new size as original size @@ -867,7 +868,7 @@ void LLLayoutStack::reshape(S32 width, S32 height, BOOL called_from_parent) void LLLayoutStack::updateResizeBarLimits() { LLLayoutPanel* previous_visible_panelp = NULL; - BOOST_REVERSE_FOREACH(LLLayoutPanel* visible_panelp, mPanels) + for(LLLayoutPanel* visible_panelp : boost::adaptors::reverse(mPanels)) { if (!visible_panelp->getVisible() || visible_panelp->mCollapsed) { @@ -951,7 +952,7 @@ LLView* LLLayoutStack::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactor } else { - llwarns << "Unknown orientation " << orientation_string << ", using vertical" << llendl; + LL_WARNS() << "Unknown orientation " << orientation_string << ", using vertical" << LL_ENDL; } BOOL clip = false; @@ -1035,4 +1036,4 @@ LLView* LLLayoutPanel::fromXML(LLXMLNodePtr node, LLView* parent, LLUICtrlFactor panelp->setOrigin(0, 0); return panelp; -} \ No newline at end of file +} diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index 15b387cbca..87ee96dfe1 100644 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -43,18 +43,18 @@ #include "lltimer.h" #include "llcalc.h" -//#include "llclipboard.h" +#include "llclipboard.h" #include "llcontrol.h" #include "llbutton.h" #include "llfocusmgr.h" #include "llkeyboard.h" +#include "llmenugl.h" #include "llrect.h" #include "llresmgr.h" #include "llstring.h" #include "llwindow.h" #include "llui.h" #include "lluictrlfactory.h" -#include "llclipboard.h" #include "../newview/lgghunspell_wrapper.h" // @@ -178,19 +178,9 @@ LLLineEditor::LLLineEditor(const std::string& name, const LLRect& rect, sImage = LLUI::getUIImage("sm_rounded_corners_simple.tga"); } mImage = sImage; + // make the popup menu available - //LLMenuGL* menu = LLUICtrlFactory::getInstance()->buildMenu("menu_texteditor.xml", parent_view); - LLMenuGL* menu = new LLMenuGL("wot"); - /*if (!menu) - { - menu = new LLMenuGL(LLStringUtil::null); - }*/ - menu->addChild(new LLMenuItemCallGL("Cut", context_cut, NULL, this)); - menu->addChild(new LLMenuItemCallGL("Copy", context_copy, NULL, this)); - menu->addChild(new LLMenuItemCallGL("Paste", context_paste, NULL, this)); - menu->addChild(new LLMenuItemCallGL("Delete", context_delete, NULL, this)); - menu->addChild(new LLMenuItemCallGL("Select All", context_selectall, NULL, this)); - menu->addSeparator(); + LLMenuGL* menu = LLUICtrlFactory::getInstance()->buildMenu("menu_texteditor.xml", LLMenuGL::sMenuContainer); //menu->setBackgroundColor(gColors.getColor("MenuPopupBgColor")); menu->setCanTearOff(FALSE); menu->setVisible(FALSE); @@ -396,12 +386,16 @@ void LLLineEditor::setCursor( S32 pos ) S32 pixels_after_scroll = findPixelNearestPos(); if( pixels_after_scroll > mMaxHPixels ) { - S32 width_chars_to_left = mGLFont->getWidth(mText.getWString().c_str(), 0, mScrollHPos); - S32 last_visible_char = mGLFont->maxDrawableChars(mText.getWString().c_str(), llmax(0.f, (F32)(mMaxHPixels - mMinHPixels + width_chars_to_left))); - S32 min_scroll = mGLFont->firstDrawableChar(mText.getWString().c_str(), (F32)(mMaxHPixels - mMinHPixels - UI_LINEEDITOR_CURSOR_THICKNESS - UI_LINEEDITOR_H_PAD), mText.length(), getCursor()); + const LLWString& utf32text = mText.getWString(); + S32 width_chars_to_left = mGLFont->getWidth(utf32text, 0, mScrollHPos); + S32 last_visible_char = mGLFont->maxDrawableChars(utf32text, llmax(0.f, (F32)(mMaxHPixels - mMinHPixels + width_chars_to_left))); + // character immediately to left of cursor should be last one visible (SCROLL_INCREMENT_ADD will scroll in more characters) + // or first character if cursor is at beginning + S32 new_last_visible_char = llmax(0, getCursor() - 1); + S32 min_scroll = mGLFont->firstDrawableChar(utf32text, (F32)(mMaxHPixels - mMinHPixels - UI_LINEEDITOR_CURSOR_THICKNESS - UI_LINEEDITOR_H_PAD), new_last_visible_char); if (old_cursor_pos == last_visible_char) { - mScrollHPos = llmin(mText.length(), llmax(min_scroll, mScrollHPos + SCROLL_INCREMENT_ADD)); + mScrollHPos = llmin(utf32text.length(), LLWString::size_type(llmax(min_scroll, mScrollHPos + SCROLL_INCREMENT_ADD))); } else { @@ -428,6 +422,13 @@ void LLLineEditor::setCursorToEnd() deselect(); } +void LLLineEditor::resetScrollPosition() +{ + mScrollHPos = 0; + // make sure cursor stays in visible range + setCursor(getCursor()); +} + BOOL LLLineEditor::canDeselect() const { return hasSelection(); @@ -441,40 +442,9 @@ void LLLineEditor::deselect() } -void LLLineEditor::context_cut(void* data) -{ - LLLineEditor* line = (LLLineEditor*)data; - if(line)line->cut(); -} -void LLLineEditor::context_copy(void* data) -{ - LLLineEditor* line = (LLLineEditor*)data; - if(line)line->copy(); -} - - -void LLLineEditor::spell_correct(void* data) +void LLLineEditor::spell_show(void* show) { - SpellMenuBind* tempBind = (SpellMenuBind*)data; - LLLineEditor* line = tempBind->origin; - if(tempBind && line) - { - llinfos << ((LLMenuItemCallGL *)(tempBind->menuItem))->getName() << " : " << tempBind->origin->getName() << " : " << tempBind->word << llendl; - if(line)line->spellReplace(tempBind); - } -} - - -void LLLineEditor::spell_show(void * data) -{ - SpellMenuBind* tempBind = (SpellMenuBind*)data; - LLLineEditor* line = tempBind->origin; - - if (tempBind && line) - { - BOOL show = (tempBind->word == "Show Misspellings"); - glggHunSpell->setSpellCheckHighlight(show); - } + glggHunSpell->setSpellCheckHighlight(!!show); } std::vector LLLineEditor::getMisspelledWordsPositions() @@ -482,7 +452,7 @@ std::vector LLLineEditor::getMisspelledWordsPositions() std::vector thePosesOfBadWords; const LLWString& text = mText.getWString(); - //llinfos << "end of box is at " << cursorloc << " and end of text is at " << text.length() << llendl; + //LL_INFOS() << "end of box is at " << cursorloc << " and end of text is at " << text.length() << LL_ENDL; S32 wordStart=0; S32 wordEnd=mStartSpellHere; while(wordEnd < mEndSpellHere) @@ -509,7 +479,7 @@ std::vector LLLineEditor::getMisspelledWordsPositions() { //misspelled word here, and you have just right clicked on it! //get the center of this word.. - //S32 center = llround( (wordEnd-wordStart)/2 ) + wordStart; + //S32 center = ll_round( (wordEnd-wordStart)/2 ) + wordStart; //turn this cursor position into a pixel pos //center = findPixelNearestPos(center-getCursor()); @@ -526,33 +496,15 @@ std::vector LLLineEditor::getMisspelledWordsPositions() void LLLineEditor::spell_add(void* data) { - SpellMenuBind* tempBind = (SpellMenuBind*)data; - if(tempBind) + auto self = static_cast(data); + S32 wordStart = 0, wordLen = 0; + if (self->getWordBoundriesAt(self->calculateCursorFromMouse(self->mLastContextMenuX), &wordStart, &wordLen)) { - glggHunSpell->addWordToCustomDictionary(tempBind->word); - tempBind->origin->mPrevSpelledText="";//make it update + glggHunSpell->addWordToCustomDictionary(wstring_to_utf8str(self->getWText().substr(wordStart, wordLen))); + self->mPrevSpelledText.clear(); //make it update } } - -void LLLineEditor::context_paste(void* data) -{ - LLLineEditor* line = (LLLineEditor*)data; - if(line)line->paste(); -} - -void LLLineEditor::context_delete(void* data) -{ - LLLineEditor* line = (LLLineEditor*)data; - if(line)line->doDelete(); -} - -void LLLineEditor::context_selectall(void* data) -{ - LLLineEditor* line = (LLLineEditor*)data; - if(line)line->selectAll(); -} - void LLLineEditor::startSelection() { mIsSelecting = TRUE; @@ -724,7 +676,7 @@ BOOL LLLineEditor::handleMouseDown(S32 x, S32 y, MASK mask) BOOL LLLineEditor::handleMiddleMouseDown(S32 x, S32 y, MASK mask) { - // llinfos << "MiddleMouseDown" << llendl; + // llinfo << "MiddleMouseDown" << LL_ENDL; setFocus( TRUE ); if( canPastePrimary() ) { @@ -766,7 +718,7 @@ BOOL LLLineEditor::handleHover(S32 x, S32 y, MASK mask) // Scroll if mouse cursor outside of bounds if (mScrollTimer.hasExpired()) { - S32 increment = llround(mScrollTimer.getElapsedTimeF32() / AUTO_SCROLL_TIME); + S32 increment = ll_round(mScrollTimer.getElapsedTimeF32() / AUTO_SCROLL_TIME); mScrollTimer.reset(AUTO_SCROLL_TIME); if( (x < mMinHPixels) && (mScrollHPos > 0 ) ) { @@ -793,14 +745,14 @@ BOOL LLLineEditor::handleHover(S32 x, S32 y, MASK mask) mKeystrokeTimer.reset(); getWindow()->setCursor(UI_CURSOR_IBEAM); - lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (active)" << llendl; + LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (active)" << LL_ENDL; handled = TRUE; } if( !handled ) { getWindow()->setCursor(UI_CURSOR_IBEAM); - lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (inactive)" << llendl; + LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (inactive)" << LL_ENDL; handled = TRUE; } @@ -860,6 +812,32 @@ void LLLineEditor::removeChar() } } +// Remove a word (set of characters up to next space/punctuation) from the text +void LLLineEditor::removeWord(bool prev) +{ + const S32& pos(mCursorPos); + if (prev ? pos > 0 : pos < getLength()) + { + S32 new_pos(prev ? prevWordPos(pos) : nextWordPos(pos)); + if (new_pos == pos) // Other character we don't jump over + new_pos = prev ? prevWordPos(new_pos-1) : nextWordPos(new_pos+1); + + const U32 diff(labs(pos - new_pos)); + if (prev) + { + mText.erase(new_pos, diff); + setCursor(new_pos); + } + else + { + mText.erase(pos, diff); + } + } + else + { + reportBadKeystroke(); + } +} void LLLineEditor::addChar(const llwchar uni_char) { @@ -892,6 +870,23 @@ void LLLineEditor::addChar(const llwchar uni_char) mText.insert(getCursor(), w_buf); setCursor(getCursor() + 1); + + if (!mReadOnly && mAutoreplaceCallback != NULL) + { + // autoreplace the text, if necessary + S32 replacement_start; + S32 replacement_length; + LLWString replacement_string; + S32 new_cursor_pos = getCursor(); + mAutoreplaceCallback(replacement_start, replacement_length, replacement_string, new_cursor_pos, mText); + + if (replacement_length > 0 || !replacement_string.empty()) + { + mText.erase(replacement_start, replacement_length); + mText.insert(replacement_start, replacement_string); + setCursor(new_cursor_pos); + } + } } else { @@ -1124,7 +1119,7 @@ BOOL LLLineEditor::canCopy() const // copy selection to clipboard -void LLLineEditor::copy() +void LLLineEditor::copy() const { if( canCopy() ) { @@ -1135,12 +1130,19 @@ void LLLineEditor::copy() } -void LLLineEditor::spellReplace(SpellMenuBind* spellData) +void LLLineEditor::spell_correct(void* data) { - mText.erase(spellData->wordPositionStart, - spellData->wordPositionEnd - spellData->wordPositionStart); - insert(spellData->word,spellData->wordPositionStart); - mCursorPos+=spellData->word.length() - (spellData->wordPositionEnd-spellData->wordPositionStart); + auto self = static_cast(data); + S32 wordStart = 0, wordLen = 0; + if (self->getWordBoundriesAt(self->calculateCursorFromMouse(self->mLastContextMenuX), &wordStart, &wordLen)) + { + auto word = utf8str_to_wstring(LLMenuGL::sMenuContainer->getActivatedItem()->getLabel()); + LLWStringUtil::replaceTabsWithSpaces(word, 4); + + self->mText.erase(wordStart, wordLen); + self->mText.insert(wordStart, word); + self->mCursorPos += word.length() - wordLen; + } } @@ -1310,7 +1312,7 @@ BOOL LLLineEditor::handleSpecialKey(KEY key, MASK mask) case KEY_BACKSPACE: if (!mReadOnly) { - //llinfos << "Handling backspace" << llendl; + //LL_INFOS() << "Handling backspace" << LL_ENDL; if( hasSelection() ) { deleteSelection(); @@ -1318,7 +1320,10 @@ BOOL LLLineEditor::handleSpecialKey(KEY key, MASK mask) else if( 0 < getCursor() ) { - removeChar(); + if (mask == MASK_CONTROL) + removeWord(true); + else + removeChar(); } else { @@ -1328,6 +1333,14 @@ BOOL LLLineEditor::handleSpecialKey(KEY key, MASK mask) handled = TRUE; break; + case KEY_DELETE: + if (!mReadOnly && mask == MASK_CONTROL) + { + removeWord(false); + handled = true; + } + break; + case KEY_PAGE_UP: case KEY_HOME: if (!mIgnoreArrowKeys) @@ -1439,8 +1452,9 @@ BOOL LLLineEditor::handleSpecialKey(KEY key, MASK mask) break; case KEY_RETURN: + if (getCommitOnReturn()) onCommit(); // store sent line in history - updateHistory(); + else updateHistory(); break; case KEY_ESCAPE: @@ -1850,14 +1864,14 @@ void LLLineEditor::draw() { S32 select_left; S32 select_right; - if( mSelectionStart < getCursor() ) + if (mSelectionStart < mSelectionEnd) { select_left = mSelectionStart; - select_right = getCursor(); + select_right = mSelectionEnd; } else { - select_left = getCursor(); + select_left = mSelectionEnd; select_right = mSelectionStart; } @@ -1872,7 +1886,7 @@ void LLLineEditor::draw() LLFontGL::NORMAL, LLFontGL::NO_SHADOW, select_left - mScrollHPos, - mMaxHPixels - llround(rendered_pixels_right), + mMaxHPixels - ll_round(rendered_pixels_right), &rendered_pixels_right); } @@ -1881,25 +1895,26 @@ void LLLineEditor::draw() LLColor4 color(1.f - bg_color.mV[0], 1.f - bg_color.mV[1], 1.f - bg_color.mV[2], alpha ); // selected middle S32 width = mGLFont->getWidth(mText.getWString().c_str(), mScrollHPos + rendered_text, select_right - mScrollHPos - rendered_text); - width = llmin(width, mMaxHPixels - llround(rendered_pixels_right)); - gl_rect_2d(llround(rendered_pixels_right), cursor_top, llround(rendered_pixels_right)+width, cursor_bottom, color); + width = llmin(width, mMaxHPixels - ll_round(rendered_pixels_right)); + gl_rect_2d(ll_round(rendered_pixels_right), cursor_top, ll_round(rendered_pixels_right)+width, cursor_bottom, color); + LLColor4 tmp_color( 1.f - text_color.mV[0], 1.f - text_color.mV[1], 1.f - text_color.mV[2], alpha ); rendered_text += mGLFont->render( mText, mScrollHPos + rendered_text, rendered_pixels_right, text_bottom, - LLColor4( 1.f - text_color.mV[0], 1.f - text_color.mV[1], 1.f - text_color.mV[2], alpha ), + tmp_color, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, select_right - mScrollHPos - rendered_text, - mMaxHPixels - llround(rendered_pixels_right), + mMaxHPixels - ll_round(rendered_pixels_right), &rendered_pixels_right); } if( (rendered_pixels_right < (F32)mMaxHPixels) && (rendered_text < text_len) ) { // unselected, right side - mGLFont->render( + rendered_text += mGLFont->render( mText, mScrollHPos + rendered_text, rendered_pixels_right, text_bottom, text_color, @@ -1907,13 +1922,13 @@ void LLLineEditor::draw() LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, - mMaxHPixels - llround(rendered_pixels_right), + mMaxHPixels - ll_round(rendered_pixels_right), &rendered_pixels_right); } } else { - mGLFont->render( + rendered_text = mGLFont->render( mText, mScrollHPos, rendered_pixels_right, text_bottom, text_color, @@ -1921,7 +1936,7 @@ void LLLineEditor::draw() LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, - mMaxHPixels - llround(rendered_pixels_right), + mMaxHPixels - ll_round(rendered_pixels_right), &rendered_pixels_right); } #if 0 // for when we're ready for image art. @@ -1956,8 +1971,9 @@ void LLLineEditor::draw() cursor_right, cursor_bottom, text_color); if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode() && !hasSelection()) { + LLColor4 tmp_color( 1.f - text_color.mV[0], 1.f - text_color.mV[1], 1.f - text_color.mV[2], alpha ); mGLFont->render(mText, getCursor(), (F32)(cursor_left + UI_LINEEDITOR_CURSOR_THICKNESS / 2), text_bottom, - LLColor4( 1.f - text_color.mV[0], 1.f - text_color.mV[1], 1.f - text_color.mV[2], alpha ), + tmp_color, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, @@ -1988,7 +2004,7 @@ void LLLineEditor::draw() LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, - mMaxHPixels - llround(rendered_pixels_right), + mMaxHPixels - ll_round(rendered_pixels_right), &rendered_pixels_right, FALSE); } @@ -2013,7 +2029,7 @@ void LLLineEditor::draw() LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, - mMaxHPixels - llround(rendered_pixels_right), + mMaxHPixels - ll_round(rendered_pixels_right), &rendered_pixels_right, FALSE); } // Draw children (border) @@ -2459,7 +2475,7 @@ BOOL LLLineEditor::evaluateFloat() else { // Replace the expression with the result - std::string result_str = llformat("%f", result); + std::string result_str = fmt::to_string(result); setText(result_str); selectAll(); } @@ -2750,13 +2766,19 @@ void LLLineEditor::updateAllowingLanguageInput() // fine on 1.15.0.2, since all prevalidate func reject any // non-ASCII characters. I'm not sure on future versions, // however... + LLWindow* window = getWindow(); + if (!window) + { + // test app, no window available + return; + } if (hasFocus() && !mReadOnly && !mDrawAsterixes && mPrevalidateFunc == NULL) { - getWindow()->allowLanguageTextInput(this, TRUE); + window->allowLanguageTextInput(this, TRUE); } else { - getWindow()->allowLanguageTextInput(this, FALSE); + window->allowLanguageTextInput(this, FALSE); } } @@ -2771,7 +2793,7 @@ void LLLineEditor::resetPreedit() { if (hasSelection()) { - llwarns << "Preedit and selection!" << llendl; + LL_WARNS() << "Preedit and selection!" << LL_ENDL; deselect(); } @@ -2928,7 +2950,7 @@ void LLLineEditor::markAsPreedit(S32 position, S32 length) setCursor(position); if (hasPreeditString()) { - llwarns << "markAsPreedit invoked when hasPreeditString is true." << llendl; + LL_WARNS() << "markAsPreedit invoked when hasPreeditString is true." << LL_ENDL; } mPreeditWString.assign( LLWString( mText.getWString(), position, length ) ); if (length > 0) @@ -2956,7 +2978,7 @@ void LLLineEditor::markAsPreedit(S32 position, S32 length) S32 LLLineEditor::getPreeditFontSize() const { - return llround(mGLFont->getLineHeight() * LLUI::getScaleFactor().mV[VY]); + return ll_round(mGLFont->getLineHeight() * LLUI::getScaleFactor().mV[VY]); } void LLLineEditor::setReplaceNewlinesWithSpaces(BOOL replace) @@ -2983,102 +3005,47 @@ void LLLineEditor::showContextMenu(S32 x, S32 y) { gEditMenuHandler = this; - /*S32 screen_x, screen_y; - localPointToScreen(x, y, &screen_x, &screen_y); - menu->show(screen_x, screen_y);*/ - - - //setCursorAtLocalPos( x); - S32 wordStart = 0; - S32 wordLen = 0; - S32 pos = calculateCursorFromMouse(x); + if(menu->isOpen()) + { + menu->setVisible(FALSE); + } - LLMenuGL* menu = (LLMenuGL*)mContextMenuHandle.get(); - if (menu) + // spell_check="true" in xui + if (!mReadOnly && mSpellCheckable) { - if(menu->isOpen()) - { - menu->setVisible(FALSE); - } - for (int i = 0;i<(int)suggestionMenuItems.size();i++) - { - SpellMenuBind * tempBind = suggestionMenuItems[i]; - if(tempBind) - { - menu->removeChild((LLMenuItemCallGL *)tempBind->menuItem); - ((LLMenuItemCallGL *)tempBind->menuItem)->die(); - //delete tempBind->menuItem; - //tempBind->menuItem = NULL; - delete tempBind; - } - } - suggestionMenuItems.clear(); + constexpr auto spell_sep = "Spell Check Sep"; + // Remove everything after the separator if we added it, because menus don't autodie yet. + menu->erase(menu->find(menu->findChild(spell_sep)), menu->end()); + menu->addSeparator(spell_sep); - // spell_check="true" in xui - menu->setItemVisible("Spelsep", !mReadOnly && mSpellCheckable); - if (!mReadOnly && mSpellCheckable) + // search for word matches + S32 wordStart = 0; + S32 wordLen = 0; + S32 pos = calculateCursorFromMouse(x); + if (getWordBoundriesAt(pos, &wordStart, &wordLen)) { - // search for word matches - bool is_word_part = getWordBoundriesAt(pos, &wordStart, &wordLen); - if (is_word_part) - { - const LLWString& text = mText.getWString(); - std::string selectedWord(std::string(text.begin(), text.end()).substr(wordStart,wordLen)); - - if (!glggHunSpell->isSpelledRight(selectedWord)) - { - //misspelled word here, and you have just right clicked on it! - std::vector suggs = glggHunSpell->getSuggestionList(selectedWord); - - for (int i = 0; i<(int)suggs.size() ;i++) - { - SpellMenuBind * tempStruct = new SpellMenuBind; - tempStruct->origin = this; - tempStruct->word = suggs[i]; - tempStruct->wordPositionEnd = wordStart + wordLen; - tempStruct->wordPositionStart=wordStart; - LLMenuItemCallGL * suggMenuItem = new LLMenuItemCallGL( - tempStruct->word, spell_correct, NULL, tempStruct); - //new LLMenuItemCallGL("Select All", context_selectall, NULL, this)); - tempStruct->menuItem = suggMenuItem; - suggestionMenuItems.push_back(tempStruct); - menu->addChild(suggMenuItem); - } - SpellMenuBind * tempStruct = new SpellMenuBind; - tempStruct->origin = this; - tempStruct->word = selectedWord; - tempStruct->wordPositionEnd = wordStart + wordLen; - tempStruct->wordPositionStart=wordStart; - LLMenuItemCallGL * suggMenuItem = new LLMenuItemCallGL( - "Add Word", spell_add, NULL, tempStruct); - tempStruct->menuItem = suggMenuItem; - suggestionMenuItems.push_back(tempStruct); - menu->addChild(suggMenuItem); - } - } + const auto selectedWord = wstring_to_utf8str(getWText().substr(wordStart, wordLen)); - SpellMenuBind * tempStruct = new SpellMenuBind; - tempStruct->origin = this; - if (glggHunSpell->getSpellCheckHighlight()) - { - tempStruct->word = "Hide Misspellings"; - } - else + if (!glggHunSpell->isSpelledRight(selectedWord)) { - tempStruct->word = "Show Misspellings"; + //misspelled word here, and you have just right clicked on it! + + for (const auto& word : glggHunSpell->getSuggestionList(selectedWord)) + { + menu->addChild(new LLMenuItemCallGL(word, spell_correct, nullptr, this)); + } + menu->addChild(new LLMenuItemCallGL("Add Word", spell_add, nullptr, this)); } - LLMenuItemCallGL * suggMenuItem = new LLMenuItemCallGL( - tempStruct->word, spell_show, NULL, tempStruct); - tempStruct->menuItem = suggMenuItem; - suggestionMenuItems.push_back(tempStruct); - menu->addChild(suggMenuItem); } - mLastContextMenuX = x; - menu->buildDrawLabels(); - menu->updateParent(LLMenuGL::sMenuContainer); - LLMenuGL::showPopup(this, menu, x, y); + bool show = !glggHunSpell->getSpellCheckHighlight(); + menu->addChild(new LLMenuItemCallGL(show ? "Show Misspellings" : "Hide Misspellings", spell_show, nullptr, show ? menu : nullptr)); } + + mLastContextMenuX = x; + menu->buildDrawLabels(); + menu->updateParent(LLMenuGL::sMenuContainer); + LLMenuGL::showPopup(this, menu, x, y); } } diff --git a/indra/llui/lllineeditor.h b/indra/llui/lllineeditor.h index c665ad96c0..ec002a452a 100644 --- a/indra/llui/lllineeditor.h +++ b/indra/llui/lllineeditor.h @@ -101,23 +101,13 @@ class LLLineEditor /*virtual*/ BOOL handleUnicodeCharHere(llwchar uni_char); /*virtual*/ void onMouseCaptureLost(); - struct SpellMenuBind - { - LLLineEditor* origin; - void * menuItem; - std::string word; - S32 wordPositionStart; - S32 wordPositionEnd; - }; - - virtual void spellReplace(SpellMenuBind* spellData); virtual void insert(std::string what,S32 wher); // LLEditMenuHandler overrides virtual void cut(); virtual BOOL canCut() const; - virtual void copy(); + void copy() const override final; virtual BOOL canCopy() const; virtual void paste(); @@ -137,11 +127,6 @@ class LLLineEditor virtual void deselect(); virtual BOOL canDeselect() const; - static void context_cut(void* data); - static void context_copy(void* data); - static void context_paste(void* data); - static void context_delete(void* data); - static void context_selectall(void* data); static void spell_correct(void* data); static void spell_show(void* data); static void spell_add(void* data); @@ -167,6 +152,10 @@ class LLLineEditor virtual BOOL isSpellDirty() const { return mText.getString() != mPrevSpelledText; } // Returns TRUE if user changed value at all virtual void resetSpellDirty() { mPrevSpelledText = mText.getString(); } // Clear dirty state + typedef boost::function autoreplace_callback_t; + autoreplace_callback_t mAutoreplaceCallback; + void setAutoreplaceCallback(autoreplace_callback_t cb) { mAutoreplaceCallback = cb; } + // assumes UTF8 text virtual void setValue(const LLSD& value ) { setText(value.asString()); } virtual LLSD getValue() const { return LLSD(getText()); } @@ -186,6 +175,9 @@ class LLLineEditor void setCursor( S32 pos ); void setCursorToEnd(); + // set scroll to earliest position it can reasonably be set + void resetScrollPosition(); + // Selects characters 'start' to 'end'. void setSelection(S32 start, S32 end); @@ -266,6 +258,7 @@ class LLLineEditor void pasteHelper(bool is_primary); void removeChar(); + void removeWord(bool prev); void addChar(const llwchar c); void setCursorAtLocalPos(S32 local_mouse_x); S32 calculateCursorFromMouse(S32 local_mouse_x); @@ -301,7 +294,6 @@ class LLLineEditor S32 mEndSpellHere; // the location of the last char on the screen BOOL mSpellCheckable; // set in xui as "spell_check". Default value for a field LLFrameTimer mSpellTimer; - std::vector suggestionMenuItems; S32 mLastContextMenuX; // line history support: diff --git a/indra/llui/llloadingindicator.cpp b/indra/llui/llloadingindicator.cpp new file mode 100644 index 0000000000..915571874f --- /dev/null +++ b/indra/llui/llloadingindicator.cpp @@ -0,0 +1,104 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +/** + * @file llloadingindicator.cpp + * @brief Perpetual loading indicator + * + * $LicenseInfo:firstyear=2010&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llloadingindicator.h" + +// Linden library includes +#include "llsingleton.h" + +// Project includes +#include "lluictrlfactory.h" +#include "lluiimage.h" + +static LLRegisterWidget r("loading_indicator"); + +/////////////////////////////////////////////////////////////////////////////// +// LLLoadingIndicator class +/////////////////////////////////////////////////////////////////////////////// + +LLLoadingIndicator::LLLoadingIndicator(const Params& p) +: LLUICtrl(p), + mImagesPerSec(p.images_per_sec > 0 ? p.images_per_sec : 1.0f), + mCurImageIdx(0) +{ +} + +void LLLoadingIndicator::initFromParams(const Params& p) +{ + for (LLUIImage* image : p.images().image) + { + mImages.push_back(image); + } + + if (mImages.empty()) // Singu Note: We don't have default widgets yet, so let's just handle this here + for (int i = 1; i <= 12; ++i) + mImages.push_back(LLUI::getUIImage(llformat("Progress_%d", i))); + + // Start timer for switching images. + start(); +} + +void LLLoadingIndicator::draw() +{ + // Time to switch to the next image? + if (mImageSwitchTimer.getStarted() && mImageSwitchTimer.hasExpired()) + { + // Switch to the next image. + if (!mImages.empty()) + { + mCurImageIdx = (mCurImageIdx + 1) % mImages.size(); + } + + // Restart timer. + start(); + } + + LLUIImagePtr cur_image = mImages.empty() ? LLUIImagePtr(NULL) : mImages[mCurImageIdx]; + + // Draw current image. + if( cur_image.notNull() ) + { + cur_image->draw(getLocalRect(), LLColor4::white % getDrawContext().mAlpha); + } + + LLUICtrl::draw(); +} + +void LLLoadingIndicator::stop() +{ + mImageSwitchTimer.stop(); +} + +void LLLoadingIndicator::start() +{ + mImageSwitchTimer.start(); + F32 period = 1.0f / (mImages.size() * mImagesPerSec); + mImageSwitchTimer.setTimerExpirySec(period); +} diff --git a/indra/llui/llloadingindicator.h b/indra/llui/llloadingindicator.h new file mode 100644 index 0000000000..b5e86c0ac1 --- /dev/null +++ b/indra/llui/llloadingindicator.h @@ -0,0 +1,104 @@ +/** + * @file llloadingindicator.h + * @brief Perpetual loading indicator + * + * $LicenseInfo:firstyear=2010&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLLOADINGINDICATOR_H +#define LL_LLLOADINGINDICATOR_H + +#include "lluictrl.h" +#include "lluiimage.h" + +/////////////////////////////////////////////////////////////////////////////// +// class LLLoadingIndicator +/////////////////////////////////////////////////////////////////////////////// + +/** + * Perpetual loading indicator (a la MacOSX or YouTube) + * + * Number of rotations per second can be overridden + * with the "images_per_sec" parameter. + * + * Can start/stop spinning. + * + * @see start() + * @see stop() + */ +class LLLoadingIndicator +: public LLUICtrl +{ + LOG_CLASS(LLLoadingIndicator); +public: + + struct Images : public LLInitParam::Block + { + Multiple image; + + Images() + : image("image") + {} + }; + + struct Params : public LLInitParam::Block + { + Optional images_per_sec; + Optional > images; + + Params() + : images_per_sec("images_per_sec", 1.0f), + images("images") + {} + }; + + virtual ~LLLoadingIndicator() {} + + // llview overrides + void draw() override; + + /** + * Stop spinning. + */ + void stop(); + + /** + * Start spinning. + */ + void start(); + + void reset() { mCurImageIdx = 0; } + +private: + LLLoadingIndicator(const Params&); + void initFromParams(const Params&); + + friend class LLUICtrlFactory; + + F32 mImagesPerSec; + S8 mCurImageIdx; + LLFrameTimer mImageSwitchTimer; + + std::vector mImages; +}; + +#endif // LL_LLLOADINGINDICATOR_H diff --git a/indra/llui/lllocalcliprect.cpp b/indra/llui/lllocalcliprect.cpp index f3a526faeb..cacc9e0224 100644 --- a/indra/llui/lllocalcliprect.cpp +++ b/indra/llui/lllocalcliprect.cpp @@ -33,14 +33,13 @@ LLScreenClipRect::LLScreenClipRect(const LLRect& rect, BOOL enabled) -: mScissorState(GL_SCISSOR_TEST), - mEnabled(enabled) +: mScissorState(enabled), + mEnabled(enabled), + mRootScissorRect(gGL.getScissor()) { if (mEnabled) { pushClipRect(rect); - mScissorState.setEnabled(!sClipRectStack.empty()); - updateScissorRegion(); } } @@ -49,11 +48,9 @@ LLScreenClipRect::~LLScreenClipRect() if (mEnabled) { popClipRect(); - updateScissorRegion(); } } -//static void LLScreenClipRect::pushClipRect(const LLRect& rect) { LLRect combined_clip_rect = rect; @@ -68,23 +65,27 @@ void LLScreenClipRect::pushClipRect(const LLRect& rect) combined_clip_rect = LLRect::null; } } + sClipRectStack.push(combined_clip_rect); + updateScissorRegion(); } -//static void LLScreenClipRect::popClipRect() { sClipRectStack.pop(); + if (!sClipRectStack.empty()) + { + updateScissorRegion(); + } + else + { + gGL.setScissor(mRootScissorRect); + } } -//static +// static void LLScreenClipRect::updateScissorRegion() { - if (sClipRectStack.empty()) return; - - // finish any deferred calls in the old clipping region - gGL.flush(); - LLRect rect = sClipRectStack.top(); stop_glerror(); S32 x,y,w,h; @@ -92,7 +93,7 @@ void LLScreenClipRect::updateScissorRegion() y = llfloor(rect.mBottom * LLUI::getScaleFactor().mV[VY]); w = llmax(0, llceil(rect.getWidth() * LLUI::getScaleFactor().mV[VX])) + 1; h = llmax(0, llceil(rect.getHeight() * LLUI::getScaleFactor().mV[VY])) + 1; - glScissor( x,y,w,h ); + gGL.setScissor( x,y,w,h ); stop_glerror(); } diff --git a/indra/llui/lllocalcliprect.h b/indra/llui/lllocalcliprect.h index eeeaf2adb6..18b0eccade 100644 --- a/indra/llui/lllocalcliprect.h +++ b/indra/llui/lllocalcliprect.h @@ -42,13 +42,14 @@ class LLScreenClipRect virtual ~LLScreenClipRect(); private: - static void pushClipRect(const LLRect& rect); - static void popClipRect(); + void pushClipRect(const LLRect& rect); + void popClipRect(); static void updateScissorRegion(); private: - LLGLState mScissorState; - BOOL mEnabled; + LLGLState mScissorState; + const BOOL mEnabled; + const LLRect mRootScissorRect; static std::stack sClipRectStack; }; diff --git a/indra/llui/llmemberlistener.h b/indra/llui/llmemberlistener.h index 0760213c78..9b90c757bf 100644 --- a/indra/llui/llmemberlistener.h +++ b/indra/llui/llmemberlistener.h @@ -8,7 +8,7 @@ * (in header) * * class T { - * class LLDoTest : public LLMemberListener + * class LLDoTest : public LLMemberListener * { * bool handleEvent(LLPointer event, const LLSD& userdata); * }; @@ -82,5 +82,24 @@ class LLMemberListener : public LLOldEvents::LLSimpleListener std::string mRegisteredName; }; +class LLBindMemberListener : public LLOldEvents::LLSimpleListener +{ +public: + typedef boost::function event, const LLSD& userdata)> event_callback_t; + template + LLBindMemberListener(T *pointer, const std::string& register_name, event_callback_t cb) + { + pointer->registerEventListener(register_name, this); + mCallback = cb; + } + + // This is what you have to override to handle this event + virtual bool handleEvent(LLPointer event, const LLSD& userdata) + { + mCallback(event, userdata); + return true; + } + event_callback_t mCallback; +}; #endif // LL_LLMEMBERLISTENER_H diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp index c501d865ca..d7175b9aa2 100644 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -70,10 +70,9 @@ using namespace LLOldEvents; // static -LLMenuHolderGL *LLMenuGL::sMenuContainer = NULL; +LLMenuHolderGL *LLMenuGL::sMenuContainer = nullptr; S32 MENU_BAR_HEIGHT = 0; -S32 MENU_BAR_WIDTH = 0; ///============================================================================ /// Local function declarations, constants, enums, and typedefs @@ -158,7 +157,7 @@ LLMenuItemGL::LLMenuItemGL( const std::string& name, const std::string& label, K LLMenuItemGL::~LLMenuItemGL() { - lldebugs << "Menu destroyed:" << this->getName() << llendl; + LL_DEBUGS() << "Menu destroyed:" << this->getName() << LL_ENDL; }; // virtual @@ -221,7 +220,7 @@ BOOL LLMenuItemGL::handleAcceleratorKey(KEY key, MASK mask) { if( getEnabled() && (!gKeyboard->getKeyRepeated(key) || mAllowKeyRepeat) && (key == mAcceleratorKey) && (mask == (mAcceleratorMask & MASK_NORMALKEYS)) ) { - doIt(); + onCommit(); return TRUE; } return FALSE; @@ -258,7 +257,7 @@ BOOL LLMenuItemGL::handleRightMouseUp(S32 x, S32 y, MASK mask) // if not, it will be added to the list BOOL LLMenuItemGL::addToAcceleratorList(std::list *listp) { - LLKeyBinding *accelerator = NULL; + LLKeyBinding *accelerator = nullptr; if (mAcceleratorKey != KEY_NONE) { @@ -268,19 +267,37 @@ BOOL LLMenuItemGL::addToAcceleratorList(std::list *listp) accelerator = *list_it; if ((accelerator->mKey == mAcceleratorKey) && (accelerator->mMask == (mAcceleratorMask & MASK_NORMALKEYS))) { + + // *NOTE: get calling code to throw up warning or route + // warning messages back to app-provided output + // std::string warning; + // warning.append("Duplicate key binding <"); + // appendAcceleratorString( warning ); + // warning.append("> for menu items:\n "); + // warning.append(accelerator->mName); + // warning.append("\n "); + // warning.append(mLabel); + + // LL_WARNS() << warning << LL_ENDL; + // LLAlertDialog::modalAlert(warning); return FALSE; } } if (!accelerator) { - accelerator = new LLKeyBinding; - if (accelerator) + try { + accelerator = new LLKeyBinding; accelerator->mKey = mAcceleratorKey; accelerator->mMask = (mAcceleratorMask & MASK_NORMALKEYS); // accelerator->mName = mLabel; + listp->push_back(accelerator);//addData(accelerator); + } + catch (const std::bad_alloc& e) + { + LL_WARNS() << "Failed to allocate memory for keybinding with exception: " << e.what() << LL_ENDL; + return FALSE; } - listp->push_back(accelerator);//addData(accelerator); } } return TRUE; @@ -342,7 +359,7 @@ void LLMenuItemGL::setJumpKey(KEY key) // virtual U32 LLMenuItemGL::getNominalHeight( void ) const { - return llround(mFont->getLineHeight()) + MENU_ITEM_PADDING; + return ll_round(mFont->getLineHeight()) + MENU_ITEM_PADDING; } //virtual @@ -400,7 +417,7 @@ void LLMenuItemGL::buildDrawLabel( void ) mDrawAccelLabel = st; } -void LLMenuItemGL::doIt( void ) +void LLMenuItemGL::onCommit( void ) { // Check torn-off status to allow left-arrow keyboard navigation back // to parent menu. @@ -411,6 +428,8 @@ void LLMenuItemGL::doIt( void ) { LLMenuGL::sMenuContainer->hideMenus(); } + + LLUICtrl::onCommit(); } // set the hover status (called by it's menu) @@ -456,7 +475,7 @@ BOOL LLMenuItemGL::handleKeyHere( KEY key, MASK mask ) // switch to keyboard navigation mode LLMenuGL::setKeyboardMode(TRUE); - doIt(); + onCommit(); return TRUE; } } @@ -469,7 +488,7 @@ BOOL LLMenuItemGL::handleMouseUp( S32 x, S32 y, MASK mask) // switch to mouse navigation mode LLMenuGL::setKeyboardMode(FALSE); - doIt(); + onCommit(); make_ui_sound("UISndClickRelease"); return LLView::handleMouseUp(x, y, mask); } @@ -486,7 +505,7 @@ BOOL LLMenuItemGL::handleMouseDown( S32 x, S32 y, MASK mask) BOOL LLMenuItemGL::handleScrollWheel( S32 x, S32 y, S32 clicks ) { // If the menu is scrollable let it handle the wheel event. - return FALSE;//!getMenu()->isScrollable(); + return !getMenu()->isScrollable(); } void LLMenuItemGL::draw( void ) @@ -562,8 +581,9 @@ void LLMenuItemGL::draw( void ) std::string::size_type offset = upper_case_label.find(mJumpKey); if (offset != std::string::npos) { - S32 x_begin = LEFT_PLAIN_PIXELS + mFont->getWidth(mLabel, 0, offset); - S32 x_end = LEFT_PLAIN_PIXELS + mFont->getWidth(mLabel, 0, offset + 1); + const LLWString& utf32text = mLabel.getWString(); + S32 x_begin = LEFT_PLAIN_PIXELS + mFont->getWidth(utf32text, 0, offset); + S32 x_end = LEFT_PLAIN_PIXELS + mFont->getWidth(utf32text, 0, offset + 1); gl_line_2d(x_begin, (MENU_ITEM_PADDING / 2) + 1, x_end, (MENU_ITEM_PADDING / 2) + 1); } } @@ -586,6 +606,7 @@ void LLMenuItemGL::handleVisibilityChange(BOOL new_visibility) } LLView::handleVisibilityChange(new_visibility); } + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLMenuItemSeparatorGL // @@ -626,12 +647,12 @@ BOOL LLMenuItemSeparatorGL::handleMouseDown(S32 x, S32 y, MASK mask) { // the menu items are in the child list in bottom up order LLView* prev_menu_item = parent_menu->findNextSibling(this); - return prev_menu_item ? prev_menu_item->handleMouseDown(x, prev_menu_item->getRect().getHeight(), mask) : FALSE; + return (prev_menu_item && prev_menu_item->getVisible() && prev_menu_item->getEnabled()) ? prev_menu_item->handleMouseDown(x, prev_menu_item->getRect().getHeight(), mask) : FALSE; } else { LLView* next_menu_item = parent_menu->findPrevSibling(this); - return next_menu_item ? next_menu_item->handleMouseDown(x, 0, mask) : FALSE; + return (next_menu_item && next_menu_item->getVisible() && next_menu_item->getEnabled()) ? next_menu_item->handleMouseDown(x, 0, mask) : FALSE; } } @@ -641,12 +662,12 @@ BOOL LLMenuItemSeparatorGL::handleMouseUp(S32 x, S32 y, MASK mask) if (y > getRect().getHeight() / 2) { LLView* prev_menu_item = parent_menu->findNextSibling(this); - return prev_menu_item ? prev_menu_item->handleMouseUp(x, prev_menu_item->getRect().getHeight(), mask) : FALSE; + return (prev_menu_item && prev_menu_item->getVisible() && prev_menu_item->getEnabled()) ? prev_menu_item->handleMouseUp(x, prev_menu_item->getRect().getHeight(), mask) : FALSE; } else { LLView* next_menu_item = parent_menu->findPrevSibling(this); - return next_menu_item ? next_menu_item->handleMouseUp(x, 0, mask) : FALSE; + return (next_menu_item && next_menu_item->getVisible() && next_menu_item->getEnabled()) ? next_menu_item->handleMouseUp(x, 0, mask) : FALSE; } } @@ -671,16 +692,17 @@ BOOL LLMenuItemSeparatorGL::handleHover(S32 x, S32 y, MASK mask) // This class represents a vertical separator. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLMenuItemVerticalSeparatorGL +class LLMenuItemVerticalSeparatorGL final : public LLMenuItemSeparatorGL { public: - LLMenuItemVerticalSeparatorGL( void ); + LLMenuItemVerticalSeparatorGL(const std::string& name = LLStringUtil::null); - virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask) { return FALSE; } + BOOL handleMouseDown(S32 x, S32 y, MASK mask) override { return FALSE; } }; -LLMenuItemVerticalSeparatorGL::LLMenuItemVerticalSeparatorGL( void ) +LLMenuItemVerticalSeparatorGL::LLMenuItemVerticalSeparatorGL(const std::string& name) +: LLMenuItemSeparatorGL(name) { setLabel( VERTICAL_SEPARATOR_LABEL ); } @@ -729,15 +751,18 @@ LLFloater* LLMenuItemTearOffGL::getParentFloater() } } - return NULL; + return nullptr; } -void LLMenuItemTearOffGL::doIt() +void LLMenuItemTearOffGL::onCommit() { if (getMenu()->getTornOff()) { - LLTearOffMenu* torn_off_menu = (LLTearOffMenu*)(getMenu()->getParent()); - torn_off_menu->close(); + LLTearOffMenu* torn_off_menu = dynamic_cast(getMenu()->getParent()); + if (torn_off_menu) + { + torn_off_menu->close(); + } } else { @@ -802,15 +827,15 @@ U32 LLMenuItemTearOffGL::getNominalHeight( void ) const // This class represents a blank, non-functioning item. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLMenuItemBlankGL : public LLMenuItemGL +class LLMenuItemBlankGL final : public LLMenuItemGL { public: - LLMenuItemBlankGL( void ) : LLMenuItemGL( LLStringUtil::null, LLStringUtil::null ) + LLMenuItemBlankGL(const std::string& name = LLStringUtil::null) : LLMenuItemGL(name, LLStringUtil::null) { setEnabled(FALSE); } - virtual void doIt( void ) {} - virtual void draw( void ) {} + void onCommit() override {} + void draw() override {} }; @@ -953,8 +978,7 @@ LLXMLNodePtr LLMenuItemCallGL::getXML(bool save_children) const return node; } -// doIt() - Call the callback provided -void LLMenuItemCallGL::doIt( void ) +void LLMenuItemCallGL::onCommit( void ) { // RN: menu item can be deleted in callback, so beware getMenu()->setItemLastSelected( this ); @@ -965,7 +989,7 @@ void LLMenuItemCallGL::doIt( void ) } LLPointer fired_event = new LLEvent(this); fireEvent(fired_event, "on_click"); - LLMenuItemGL::doIt(); + LLMenuItemGL::onCommit(); } void LLMenuItemCallGL::updateEnabled( void ) @@ -1150,14 +1174,14 @@ void LLMenuItemToggleGL::buildDrawLabel( void ) mDrawAccelLabel = st; } -// doIt() - do the primary funcationality of the menu item. -void LLMenuItemToggleGL::doIt( void ) +// onCommit() - do the primary funcationality of the menu item. +void LLMenuItemToggleGL::onCommit( void ) { getMenu()->setItemLastSelected( this ); - //llinfos << "LLMenuItemToggleGL::doIt " << mLabel.c_str() << llendl; + //LL_INFOS() << "LLMenuItemToggleGL::onCommit " << mLabel.c_str() << LL_ENDL; *mToggle = !(*mToggle); buildDrawLabel(); - LLMenuItemGL::doIt(); + LLMenuItemGL::onCommit(); } @@ -1168,7 +1192,7 @@ LLMenuItemBranchGL::LLMenuItemBranchGL( const std::string& name, const std::stri LLMenuGL* branch = dynamic_cast(branch_handle.get()); if(!branch) { - llerrs << "Non-menu handle passed as branch reference." << llendl; + LL_ERRS() << "Non-menu handle passed as branch reference." << LL_ENDL; } if (branch) @@ -1187,6 +1211,8 @@ LLMenuItemBranchGL::~LLMenuItemBranchGL() } } + + // virtual LLView* LLMenuItemBranchGL::getChildView(const std::string& name, BOOL recurse, BOOL create_if_missing) const { @@ -1214,7 +1240,7 @@ BOOL LLMenuItemBranchGL::handleMouseUp(S32 x, S32 y, MASK mask) // switch to mouse navigation mode LLMenuGL::setKeyboardMode(FALSE); - doIt(); + onCommit(); make_ui_sound("UISndClickRelease"); return TRUE; } @@ -1269,8 +1295,7 @@ void LLMenuItemBranchGL::buildDrawLabel( void ) mDrawBranchLabel = LLMenuGL::BRANCH_SUFFIX; } -// doIt() - do the primary functionality of the menu item. -void LLMenuItemBranchGL::doIt( void ) +void LLMenuItemBranchGL::onCommit( void ) { openMenu(); @@ -1280,6 +1305,8 @@ void LLMenuItemBranchGL::doIt( void ) { getBranch()->highlightNextItem(NULL); } + + LLUICtrl::onCommit(); } BOOL LLMenuItemBranchGL::handleKey(KEY key, MASK mask, BOOL called_from_parent) @@ -1326,7 +1353,8 @@ void LLMenuItemBranchGL::setHighlight( BOOL highlight ) BOOL auto_open = getEnabled() && (!branch->getVisible() || branch->getTornOff()); // torn off menus don't open sub menus on hover unless they have focus - if (getMenu()->getTornOff() && !((LLFloater*)getMenu()->getParent())->hasFocus()) + LLFloater * menu_parent = dynamic_cast(getMenu()->getParent()); + if (getMenu()->getTornOff() && menu_parent && !menu_parent->hasFocus()) { auto_open = FALSE; } @@ -1347,7 +1375,11 @@ void LLMenuItemBranchGL::setHighlight( BOOL highlight ) { if (branch->getTornOff()) { - ((LLFloater*)branch->getParent())->setFocus(FALSE); + LLFloater * branch_parent = dynamic_cast(branch->getParent()); + if (branch_parent) + { + branch_parent->setFocus(FALSE); + } branch->clearHoverItem(); } else @@ -1379,7 +1411,7 @@ void LLMenuItemBranchGL::handleVisibilityChange( BOOL new_visibility ) { if (new_visibility == FALSE && getBranch() && !getBranch()->getTornOff()) { - lldebugs << "Forcing branch to visible. Menu: " << getName() << " Branch: " << getBranch()->getName() << llendl; + LL_DEBUGS() << "Forcing branch to visible. Menu: " << getName() << " Branch: " << getBranch()->getName() << LL_ENDL; getBranch()->setVisible(FALSE); } LLMenuItemGL::handleVisibilityChange(new_visibility); @@ -1405,11 +1437,19 @@ BOOL LLMenuItemBranchGL::handleKeyHere( KEY key, MASK mask ) BOOL handled = branch->clearHoverItem(); if (branch->getTornOff()) { - ((LLFloater*)branch->getParent())->setFocus(FALSE); + LLFloater * branch_parent = dynamic_cast(branch->getParent()); + if (branch_parent) + { + branch_parent->setFocus(FALSE); + } } if (handled && getMenu()->getTornOff()) { - ((LLFloater*)getMenu()->getParent())->setFocus(TRUE); + LLFloater * menu_parent = dynamic_cast(getMenu()->getParent()); + if (menu_parent) + { + menu_parent->setFocus(TRUE); + } } return handled; } @@ -1449,9 +1489,13 @@ void LLMenuItemBranchGL::openMenu() if (branch->getTornOff()) { - gFloaterView->bringToFront((LLFloater*)branch->getParent()); - // this might not be necessary, as torn off branches don't get focus and hence no highligth - branch->highlightNextItem(NULL); + LLFloater * branch_parent = dynamic_cast(branch->getParent()); + if (branch_parent) + { + gFloaterView->bringToFront(branch_parent); + // this might not be necessary, as torn off branches don't get focus and hence no highligth + branch->highlightNextItem(NULL); + } } else if( !branch->getVisible() ) { @@ -1483,11 +1527,18 @@ void LLMenuItemBranchGL::openMenu() branch->localPointToOtherView( 0, 0, &x, &y, branch->getParent() ); F32 center_y = top - (getRect().getHeight() / 2.f); + if( y < menu_region_rect.mBottom && center_y <= menu_region_rect.getCenterY()) { // open upwards if menu extends past bottom // adjust by the height of the menu item branch since it is a submenu - delta_y = branch_rect.getHeight() - getRect().getHeight(); + delta_y = branch_rect.getHeight() - getRect().getHeight(); + // Singu: Handle menu clipping off the top of the screen too. + if ( branch_rect.mTop + delta_y > menu_region_rect.mTop ) + { + delta_y -= branch_rect.mTop + delta_y - menu_region_rect.mTop; + delta_y -= delta_y % getRect().getHeight(); + } } if( x + branch_rect.getWidth() > menu_region_rect.mRight ) @@ -1584,7 +1635,11 @@ void LLMenuItemBranchDownGL::openMenu( void ) { if (branch->getTornOff()) { - gFloaterView->bringToFront((LLFloater*)branch->getParent()); + LLFloater * branch_parent = dynamic_cast(branch->getParent()); + if (branch_parent) + { + gFloaterView->bringToFront(branch_parent); + } } else { @@ -1639,7 +1694,11 @@ void LLMenuItemBranchDownGL::setHighlight( BOOL highlight ) { if (branch->getTornOff()) { - ((LLFloater*)branch->getParent())->setFocus(FALSE); + LLFloater * branch_parent = dynamic_cast(branch->getParent()); + if (branch_parent) + { + branch_parent->setFocus(FALSE); + } branch->clearHoverItem(); } else @@ -1661,7 +1720,7 @@ BOOL LLMenuItemBranchDownGL::handleMouseDown( S32 x, S32 y, MASK mask ) { // switch to mouse control mode LLMenuGL::setKeyboardMode(FALSE); - doIt(); + onCommit(); make_ui_sound("UISndClick"); setVisible(TRUE); return TRUE; @@ -1701,7 +1760,7 @@ BOOL LLMenuItemBranchDownGL::handleKeyHere(KEY key, MASK mask) // open new menu only if previous menu was open if (itemp && itemp->getEnabled() && menu_open) { - itemp->doIt(); + itemp->onCommit(); } return TRUE; @@ -1715,7 +1774,7 @@ BOOL LLMenuItemBranchDownGL::handleKeyHere(KEY key, MASK mask) // open new menu only if previous menu was open if (itemp && itemp->getEnabled() && menu_open) { - itemp->doIt(); + itemp->onCommit(); } return TRUE; @@ -1727,7 +1786,7 @@ BOOL LLMenuItemBranchDownGL::handleKeyHere(KEY key, MASK mask) if (!isActive()) { - doIt(); + onCommit(); } getBranch()->highlightNextItem(NULL); return TRUE; @@ -1739,7 +1798,7 @@ BOOL LLMenuItemBranchDownGL::handleKeyHere(KEY key, MASK mask) if (!isActive()) { - doIt(); + onCommit(); } getBranch()->highlightPrevItem(NULL); return TRUE; @@ -1793,9 +1852,10 @@ void LLMenuItemBranchDownGL::draw( void ) std::string::size_type offset = upper_case_label.find(getJumpKey()); if (offset != std::string::npos) { - S32 x_offset = llround((F32)getRect().getWidth() / 2.f - getFont()->getWidthF32(mLabel.getString(), 0, S32_MAX) / 2.f); - S32 x_begin = x_offset + getFont()->getWidth(mLabel, 0, offset); - S32 x_end = x_offset + getFont()->getWidth(mLabel, 0, offset + 1); + const LLWString& utf32text = mLabel.getWString(); + S32 x_offset = ll_round((F32)getRect().getWidth() / 2.f - getFont()->getWidthF32(utf32text, 0, S32_MAX) / 2.f); + S32 x_begin = x_offset + getFont()->getWidth(utf32text, 0, offset); + S32 x_end = x_offset + getFont()->getWidth(utf32text, 0, offset + 1); gl_line_2d(x_begin, LABEL_BOTTOM_PAD_PIXELS, x_end, LABEL_BOTTOM_PAD_PIXELS); } } @@ -1805,6 +1865,117 @@ void LLMenuItemBranchDownGL::draw( void ) setHover(FALSE); } + +class LLMenuScrollItem : public LLMenuItemCallGL +{ +public: + enum EArrowType + { + ARROW_DOWN, + ARROW_UP + }; + struct ArrowTypes : public LLInitParam::TypeValuesHelper + { + static void declareValues() + { + declare("up", ARROW_UP); + declare("down", ARROW_DOWN); + } + }; + + struct Params : public LLInitParam::Block + { + Optional arrow_type; + Optional scroll_callback; + }; + +protected: + LLMenuScrollItem(const Params&); + friend class LLUICtrlFactory; + +public: + /*virtual*/ void draw(); + /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent); + /*virtual*/ void setEnabled(BOOL enabled); + virtual void onCommit( void ); + +private: + LLButton* mArrowBtn; +}; + +LLMenuScrollItem::LLMenuScrollItem(const Params& p) +: LLMenuItemCallGL(p.name, NULL/*p*/) +{ + std::string icon; + if (p.arrow_type.isProvided() && p.arrow_type == ARROW_UP) + { + icon = "arrow_up.tga"; + } + else + { + icon = "arrow_down.tga"; + } + + /* Singu TODO: LLButton::Params + LLButton::Params bparams; + + // Disabled the Return key handling by LLMenuScrollItem instead of + // passing the key press to the currently selected menu item. See STORM-385. + bparams.commit_on_return(false); + bparams.mouse_opaque(true); + bparams.scale_image(false); + bparams.click_callback(p.scroll_callback); + bparams.mouse_held_callback(p.scroll_callback); + bparams.follows.flags(FOLLOWS_ALL); + std::string background = "transparent.j2c"; + bparams.image_unselected.name(background); + bparams.image_disabled.name(background); + bparams.image_selected.name(background); + bparams.image_hover_selected.name(background); + bparams.image_disabled_selected.name(background); + bparams.image_hover_unselected.name(background); + bparams.image_overlay.name(icon); + + mArrowBtn = LLUICtrlFactory::create(bparams); + */ + const LLRect rect = getRect(); + const std::string background = "transparent.j2c"; + mArrowBtn = new LLButton("", LLRect(0, 0, rect.getWidth(), rect.getHeight()), background, background, "", NULL); + mArrowBtn->setCommitOnReturn(false); + mArrowBtn->setMouseOpaque(true); + mArrowBtn->setScaleImage(false); + mArrowBtn->setClickedCallback(p.scroll_callback); + mArrowBtn->setHeldDownCallback(p.scroll_callback); + mArrowBtn->setFollows(FOLLOWS_ALL); + mArrowBtn->setImageOverlay(icon); + addChild(mArrowBtn); +} + +/*virtual*/ +void LLMenuScrollItem::draw() +{ + LLUICtrl::draw(); +} + +/*virtual*/ +void LLMenuScrollItem::reshape(S32 width, S32 height, BOOL called_from_parent) +{ + mArrowBtn->reshape(width, height, called_from_parent); + LLView::reshape(width, height, called_from_parent); +} + +/*virtual*/ +void LLMenuScrollItem::setEnabled(BOOL enabled) +{ + mArrowBtn->setEnabled(enabled); + LLView::setEnabled(enabled); +} + +void LLMenuScrollItem::onCommit( void ) +{ + LLUICtrl::onCommit(); +} + ///============================================================================ /// Class LLMenuGL ///============================================================================ @@ -1816,10 +1987,12 @@ LLMenuGL::LLMenuGL( const std::string& name, const std::string& label ) : LLUICtrl( name, LLRect(), FALSE), mBackgroundColor( sDefaultBackgroundColor ), mBgVisible( TRUE ), - mHasSelection( FALSE ), + mHasSelection(false), + mHorizontalLayout(false), + mScrollable(mHorizontalLayout ? FALSE : /*p.scrollable*/false), // Scrolling is supported only for vertical layout + mMaxScrollableItems(/*p.max_scrollable_items*/ U32_MAX), mLabel( label ), mDropShadowed( TRUE ), - mHorizontalLayout( FALSE ), mKeepFixedSize( FALSE ), mLastMouseX(0), mLastMouseY(0), @@ -1829,9 +2002,13 @@ LLMenuGL::LLMenuGL( const std::string& name, const std::string& label ) mTearOffItem(NULL), mSpilloverBranch(NULL), mFirstVisibleItem(NULL), + mArrowUpItem(NULL), + mArrowDownItem(NULL), mSpilloverMenu(NULL), mJumpKey(KEY_NONE), + mCreateJumpKeys(true/*p.create_jump_keys*/), mNeedsArrange(FALSE), + mResetScrollPositionOnShow(true), mShortcutPad(ACCEL_PAD_PIXELS) { mFadeTimer.stop(); @@ -1842,10 +2019,12 @@ LLMenuGL::LLMenuGL( const std::string& label) : LLUICtrl( label, LLRect(), FALSE), mBackgroundColor( sDefaultBackgroundColor ), mBgVisible( TRUE ), - mHasSelection( FALSE ), + mHasSelection(false), + mHorizontalLayout(false), + mScrollable(mHorizontalLayout ? FALSE : /*p.scrollable*/false), // Scrolling is supported only for vertical layout + mMaxScrollableItems(/*p.max_scrollable_items*/ U32_MAX), mLabel( label ), mDropShadowed( TRUE ), - mHorizontalLayout( FALSE ), mKeepFixedSize( FALSE ), mLastMouseX(0), mLastMouseY(0), @@ -1856,8 +2035,12 @@ LLMenuGL::LLMenuGL( const std::string& label) mSpilloverBranch(NULL), mSpilloverMenu(NULL), mFirstVisibleItem(NULL), + mArrowUpItem(NULL), + mArrowDownItem(NULL), mJumpKey(KEY_NONE), + mCreateJumpKeys(true/*p.create_jump_keys*/), mNeedsArrange(FALSE), + mResetScrollPositionOnShow(true), mShortcutPad(ACCEL_PAD_PIXELS) { mFadeTimer.stop(); @@ -1926,14 +2109,14 @@ LLXMLNodePtr LLMenuGL::getXML(bool save_children) const return node; } -void LLMenuGL::parseChildXML(LLXMLNodePtr child, LLView *parent, LLUICtrlFactory *factory) +void LLMenuGL::parseChildXML(LLXMLNodePtr child, LLView *parent) { std::string name(child->getName()->mString); if (child->hasName(LL_MENU_GL_TAG)) { // SUBMENU - LLMenuGL *submenu = (LLMenuGL*)LLMenuGL::fromXML(child, parent, factory); - appendMenu(submenu, 0); + LLMenuGL *submenu = (LLMenuGL*)LLMenuGL::fromXML(child, parent, LLUICtrlFactory::getInstance()); + appendMenu(submenu); if (LLMenuGL::sMenuContainer != NULL) { submenu->updateParent(LLMenuGL::sMenuContainer); @@ -1963,6 +2146,8 @@ void LLMenuGL::parseChildXML(LLXMLNodePtr child, LLView *parent, LLUICtrlFactory child->getAttributeString("type", type); child->getAttributeString("name", item_name); child->getAttributeString("label", source_label); + + LLStringUtil::format(source_label, LLTrans::getDefaultArgs()); // parse jump key out of label typedef boost::tokenizer > tokenizer; @@ -2008,7 +2193,7 @@ void LLMenuGL::parseChildXML(LLXMLNodePtr child, LLView *parent, LLUICtrlFactory { mask |= MASK_SHIFT; } - S32 pipe_pos = shortcut.rfind("|"); + S32 pipe_pos = shortcut.rfind('|'); std::string key_str = shortcut.substr(pipe_pos+1); KEY key = KEY_NONE; @@ -2054,7 +2239,7 @@ void LLMenuGL::parseChildXML(LLXMLNodePtr child, LLView *parent, LLUICtrlFactory if (!callback) { - lldebugs << "Ignoring \"on_check\" \"" << item_name << "\" because \"" << callback_name << "\" is not registered" << llendl; + LL_DEBUGS() << "Ignoring \"on_check\" \"" << item_name << "\" because \"" << callback_name << "\" is not registered" << LL_ENDL; continue; } @@ -2099,7 +2284,7 @@ void LLMenuGL::parseChildXML(LLXMLNodePtr child, LLView *parent, LLUICtrlFactory if (!callback) { - lldebugs << "Ignoring \"on_click\" \"" << item_name << "\" because \"" << callback_name << "\" is not registered" << llendl; + LL_DEBUGS() << "Ignoring \"on_click\" \"" << item_name << "\" because \"" << callback_name << "\" is not registered" << LL_ENDL; continue; } @@ -2133,7 +2318,7 @@ void LLMenuGL::parseChildXML(LLXMLNodePtr child, LLView *parent, LLUICtrlFactory if (!callback) { - lldebugs << "Ignoring \"on_enable\" \"" << item_name << "\" because \"" << callback_name << "\" is not registered" << llendl; + LL_DEBUGS() << "Ignoring \"on_enable\" \"" << item_name << "\" because \"" << callback_name << "\" is not registered" << LL_ENDL; continue; } @@ -2177,7 +2362,7 @@ void LLMenuGL::parseChildXML(LLXMLNodePtr child, LLView *parent, LLUICtrlFactory if (!callback) { - lldebugs << "Ignoring \"on_visible\" \"" << item_name << "\" because \"" << callback_name << "\" is not registered" << llendl; + LL_DEBUGS() << "Ignoring \"on_visible\" \"" << item_name << "\" because \"" << callback_name << "\" is not registered" << LL_ENDL; continue; } @@ -2202,30 +2387,21 @@ void LLMenuGL::parseChildXML(LLXMLNodePtr child, LLView *parent, LLUICtrlFactory } } -// This wrapper is needed because the virtual linkage causes errors if default parameters are used bool LLMenuGL::addChild(LLView* view, S32 tab_group) -{ - return addChild(view, 0, tab_group); -} - -bool LLMenuGL::addChild(LLView* view, LLView* insert_before, S32 tab_group) { if (LLMenuGL* menup = dynamic_cast(view)) { - lldebugs << "Adding menu " << menup->getName() << " to " << getName() << llendl; - if (!insert_before) - appendMenu(menup); - else - appendMenu(menup, insert_before); + LL_DEBUGS() << "Adding menu " << menup->getName() << " to " << getName() << LL_ENDL; + appendMenu(menup); return true; } else if (LLMenuItemGL* itemp = dynamic_cast(view)) { - lldebugs << "Adding " << itemp->getName() << " to " << getName() << llendl; - append(itemp, insert_before); + LL_DEBUGS() << "Adding " << itemp->getName() << " to " << getName() << LL_ENDL; + append(itemp); return true; } - lldebugs << "Error adding unknown child '"<<(view ? view->getName() : std::string("NULL")) << "' to " << getName() << llendl; + LL_DEBUGS() << "Error adding unknown child '"<<(view ? view->getName() : std::string("NULL")) << "' to " << getName() << LL_ENDL; return false; } @@ -2295,57 +2471,80 @@ BOOL LLMenuGL::isOpen() } } // static -LLView* LLMenuGL::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) +LLView* LLMenuGL::fromXML(LLXMLNodePtr node, LLView* parent, LLUICtrlFactory* factory) { std::string name("menu"); node->getAttributeString("name", name); - std::string label = name; - node->getAttributeString("label", label); + LLMenuGL* menu = new LLMenuGL(name); - // parse jump key out of label - std::string new_menu_label; + // Menus can be extended using filename + if (node->hasAttribute("filename")) + { + std::string filename; + node->getAttributeString("filename", filename); + LLXMLNodePtr root; + LLUICtrlFactory::getLayeredXMLNode(filename, root); + menu->initMenuXML(root, parent); + } + menu->initMenuXML(node, parent); - typedef boost::tokenizer > tokenizer; - boost::char_separator sep("_"); - tokenizer tokens(label, sep); - tokenizer::iterator token_iter; + return menu; +} - KEY jump_key = KEY_NONE; - S32 token_count = 0; - for( token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter) +void LLMenuGL::initMenuXML(LLXMLNodePtr node, LLView* parent) +{ + std::string label; + if (node->getAttributeString("label", label)) { - new_menu_label += (*token_iter); - if (token_count > 0) + LLStringUtil::format(label, LLTrans::getDefaultArgs()); + + // parse jump key out of label + std::string new_menu_label; + + typedef boost::tokenizer> tokenizer; + boost::char_separator sep("_"); + + KEY jump_key = KEY_NONE; + S32 token_count = 0; + for (auto token : tokenizer(label, sep)) { - jump_key = (*token_iter).c_str()[0]; + new_menu_label += token; + if (token_count > 0) + { + jump_key = token.front(); + } + ++token_count; } - ++token_count; + + setLabel(new_menu_label); + setJumpKey(jump_key); } BOOL opaque = TRUE; node->getAttributeBOOL("opaque", opaque); - LLMenuGL *menu = new LLMenuGL(name, new_menu_label); + bool b(false); + node->getAttribute_bool("scrollable", b); + setScrollable(b); - menu->setJumpKey(jump_key); BOOL tear_off = FALSE; node->getAttributeBOOL("tear_off", tear_off); - menu->setCanTearOff(tear_off); + setCanTearOff(tear_off); if (node->hasAttribute("drop_shadow")) { BOOL drop_shadow = FALSE; node->getAttributeBOOL("drop_shadow", drop_shadow); - menu->setDropShadowed(drop_shadow); + setDropShadowed(drop_shadow); } - menu->setBackgroundVisible(opaque); + setBackgroundVisible(opaque); LLColor4 color(0,0,0,1); if (opaque && LLUICtrlFactory::getAttributeColor(node,"color", color)) { - menu->setBackgroundColor(color); + setBackgroundColor(color); } BOOL create_jump_keys = FALSE; @@ -2354,17 +2553,127 @@ LLView* LLMenuGL::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *fa LLXMLNodePtr child; for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling()) { - menu->parseChildXML(child, parent, factory); + parseChildXML(child, parent); } if (create_jump_keys) { - menu->createJumpKeys(); + createJumpKeys(); } - return menu; } + +bool LLMenuGL::scrollItems(EScrollingDirection direction) +{ + // Slowing down items scrolling when arrow button is held + if (mScrollItemsTimer.hasExpired() && NULL != mFirstVisibleItem) + { + mScrollItemsTimer.setTimerExpirySec(.033f); + } + else + { + return false; + } + + switch (direction) + { + case SD_UP: + { + item_list_t::iterator cur_item_iter; + item_list_t::iterator prev_item_iter; + for (cur_item_iter = mItems.begin(), prev_item_iter = mItems.begin(); cur_item_iter != mItems.end(); cur_item_iter++) + { + if( (*cur_item_iter) == mFirstVisibleItem) + { + break; + } + if ((*cur_item_iter)->getVisible()) + { + prev_item_iter = cur_item_iter; + } + } + + if ((*prev_item_iter)->getVisible()) + { + mFirstVisibleItem = *prev_item_iter; + } + break; + } + case SD_DOWN: + { + if (NULL == mFirstVisibleItem) + { + mFirstVisibleItem = *mItems.begin(); + } + + item_list_t::iterator cur_item_iter; + + for (cur_item_iter = mItems.begin(); cur_item_iter != mItems.end(); cur_item_iter++) + { + if( (*cur_item_iter) == mFirstVisibleItem) + { + break; + } + } + + item_list_t::iterator next_item_iter; + + if (cur_item_iter != mItems.end()) + { + for (next_item_iter = ++cur_item_iter; next_item_iter != mItems.end(); next_item_iter++) + { + if( (*next_item_iter)->getVisible()) + { + break; + } + } + + if (next_item_iter != mItems.end() && + (*next_item_iter)->getVisible()) + { + mFirstVisibleItem = *next_item_iter; + } + } + break; + } + case SD_BEGIN: + { + mFirstVisibleItem = *mItems.begin(); + break; + } + case SD_END: + { + item_list_t::reverse_iterator first_visible_item_iter = mItems.rend(); + + // Need to scroll through number of actual existing items in menu. + // Otherwise viewer will hang for a time needed to scroll U32_MAX + // times in std::advance(). STORM-659. + size_t nitems = mItems.size(); + U32 scrollable_items = nitems < mMaxScrollableItems ? nitems : mMaxScrollableItems; + + // Advance by mMaxScrollableItems back from the end of the list + // to make the last item visible. + std::advance(first_visible_item_iter, scrollable_items); + mFirstVisibleItem = *first_visible_item_iter; + break; + } + default: + //LL_WARNS() << "Unknown scrolling direction: " << direction << LL_ENDL; + LL_WARNS() << "Unknown scrolling direction: " << direction << LL_ENDL; + } + + mNeedsArrange = TRUE; + arrangeAndClear(); + + return true; +} + +void LLMenuGL::setScrollable(bool b) +{ + mScrollable = b; +} + // rearrange the child rects so they fit the shape of the menu. void LLMenuGL::arrange( void ) { @@ -2394,13 +2703,14 @@ void LLMenuGL::arrange( void ) // *FIX: create the item first and then ask for its dimensions? S32 spillover_item_width = PLAIN_PAD_PIXELS + LLFontGL::getFontSansSerif()->getWidth( std::string("More") ); // *TODO: Translate - S32 spillover_item_height = llround(LLFontGL::getFontSansSerif()->getLineHeight()) + MENU_ITEM_PADDING; + S32 spillover_item_height = ll_round(LLFontGL::getFontSansSerif()->getLineHeight()) + MENU_ITEM_PADDING; // Scrolling support item_list_t::iterator first_visible_item_iter; - //S32 height_before_first_visible_item = -1; - //S32 visible_items_height = 0; - //U32 scrollable_items_cnt = 0; + item_list_t::iterator first_hidden_item_iter = mItems.end(); + S32 height_before_first_visible_item = -1; + S32 visible_items_height = 0; + U32 scrollable_items_cnt = 0; if (mHorizontalLayout) { @@ -2448,15 +2758,16 @@ void LLMenuGL::arrange( void ) else { item_list_t::iterator item_iter; + for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter) { - llassert_always((*item_iter)!=NULL); // do first so LLMenuGLItemCall can call on_visible to determine if visible (*item_iter)->buildDrawLabel(); if ((*item_iter)->getVisible()) { if (!getTornOff() + && !mScrollable && *item_iter != mSpilloverBranch && height + (*item_iter)->getNominalHeight() > max_height - spillover_item_height) { @@ -2472,6 +2783,8 @@ void LLMenuGL::arrange( void ) removeChild(itemp); mSpilloverMenu->addChild(itemp); } + + addChild(mSpilloverBranch); height += mSpilloverBranch->getNominalHeight(); @@ -2485,20 +2798,170 @@ void LLMenuGL::arrange( void ) height += (*item_iter)->getNominalHeight(); width = llmax( width, (*item_iter)->getNominalWidth() ); } + + if (mScrollable) + { + // Determining visible items boundaries + if (NULL == mFirstVisibleItem) + { + mFirstVisibleItem = *item_iter; + } + + if (*item_iter == mFirstVisibleItem) + { + height_before_first_visible_item = height - (*item_iter)->getNominalHeight(); + first_visible_item_iter = item_iter; + scrollable_items_cnt = 0; + } + + if (-1 != height_before_first_visible_item && 0 == visible_items_height && + (++scrollable_items_cnt > mMaxScrollableItems || + height - height_before_first_visible_item > max_height - spillover_item_height * 2 )) + { + first_hidden_item_iter = item_iter; + visible_items_height = height - height_before_first_visible_item - (*item_iter)->getNominalHeight(); + scrollable_items_cnt--; + } + } + } + } + + if (mScrollable) + { + S32 max_items_height = max_height - spillover_item_height * 2; + + if (visible_items_height == 0) + visible_items_height = height - height_before_first_visible_item; + + // Fix mFirstVisibleItem value, if it doesn't allow to display all items, that can fit + if (visible_items_height < max_items_height && scrollable_items_cnt < mMaxScrollableItems) + { + item_list_t::iterator tmp_iter(first_visible_item_iter); + while (visible_items_height < max_items_height && + scrollable_items_cnt < mMaxScrollableItems && + first_visible_item_iter != mItems.begin()) + { + if ((*first_visible_item_iter)->getVisible()) + { + // It keeps visible item, after first_visible_item_iter + tmp_iter = first_visible_item_iter; + } + + first_visible_item_iter--; + + if ((*first_visible_item_iter)->getVisible()) + { + visible_items_height += (*first_visible_item_iter)->getNominalHeight(); + height_before_first_visible_item -= (*first_visible_item_iter)->getNominalHeight(); + scrollable_items_cnt++; + } + } + + // Roll back one item, that doesn't fit + if (visible_items_height > max_items_height) + { + visible_items_height -= (*first_visible_item_iter)->getNominalHeight(); + height_before_first_visible_item += (*first_visible_item_iter)->getNominalHeight(); + scrollable_items_cnt--; + first_visible_item_iter = tmp_iter; + } + if (!(*first_visible_item_iter)->getVisible()) + { + first_visible_item_iter = tmp_iter; + } + + mFirstVisibleItem = *first_visible_item_iter; } } } S32 cur_height = (S32)llmin(max_height, height); + + if (mScrollable && + (height_before_first_visible_item > MENU_ITEM_PADDING || + height_before_first_visible_item + visible_items_height < (S32)height)) + { + // Reserving 2 extra slots for arrow items + cur_height = visible_items_height + spillover_item_height * 2; + } + setRect(LLRect(getRect().mLeft, getRect().mTop, getRect().mLeft + width, getRect().mTop - cur_height)); S32 cur_width = 0; S32 offset = 0; + if (mScrollable) + { + // No space for all items, creating arrow items + if (height_before_first_visible_item > MENU_ITEM_PADDING || + height_before_first_visible_item + visible_items_height < (S32)height) + { + if (NULL == mArrowUpItem) + { + LLMenuScrollItem::Params item_params; + item_params.name(ARROW_UP); + item_params.arrow_type(LLMenuScrollItem::ARROW_UP); + item_params.scroll_callback.function(boost::bind(&LLMenuGL::scrollItems, this, SD_UP)); + + mArrowUpItem = LLUICtrlFactory::create(item_params); + LLUICtrl::addChild(mArrowUpItem); + + } + if (NULL == mArrowDownItem) + { + LLMenuScrollItem::Params item_params; + item_params.name(ARROW_DOWN); + item_params.arrow_type(LLMenuScrollItem::ARROW_DOWN); + item_params.scroll_callback.function(boost::bind(&LLMenuGL::scrollItems, this, SD_DOWN)); + + mArrowDownItem = LLUICtrlFactory::create(item_params); + LLUICtrl::addChild(mArrowDownItem); + } + + LLRect rect; + mArrowUpItem->setRect(rect.setLeftTopAndSize( 0, cur_height, width, mArrowUpItem->getNominalHeight())); + mArrowUpItem->setVisible(TRUE); + mArrowUpItem->setEnabled(height_before_first_visible_item > MENU_ITEM_PADDING); + mArrowUpItem->reshape(width, mArrowUpItem->getNominalHeight()); + mArrowDownItem->setRect(rect.setLeftTopAndSize( 0, mArrowDownItem->getNominalHeight(), width, mArrowDownItem->getNominalHeight())); + mArrowDownItem->setVisible(TRUE); + mArrowDownItem->setEnabled(height_before_first_visible_item + visible_items_height < (S32)height); + mArrowDownItem->reshape(width, mArrowDownItem->getNominalHeight()); + + cur_height -= mArrowUpItem->getNominalHeight(); + + offset = menu_region_rect.mRight; // This moves items behind visible area + } + else + { + if (NULL != mArrowUpItem) + { + mArrowUpItem->setVisible(FALSE); + } + if (NULL != mArrowDownItem) + { + mArrowDownItem->setVisible(FALSE); + } + } + + } + item_list_t::iterator item_iter; for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter) { if ((*item_iter)->getVisible()) { + if (mScrollable) + { + if (item_iter == first_visible_item_iter) + { + offset = 0; + } + else if (item_iter == first_hidden_item_iter) + { + offset = menu_region_rect.mRight; // This moves items behind visible area + } + } + // setup item rect to hold label LLRect rect; if (mHorizontalLayout) @@ -2578,6 +3041,9 @@ void LLMenuGL::cleanupSpilloverBranch() void LLMenuGL::createJumpKeys() { + if (!mCreateJumpKeys) return; + mCreateJumpKeys = FALSE; + mJumpKeys.clear(); std::set unique_words; @@ -2679,9 +3145,59 @@ void LLMenuGL::empty( void ) mItems.clear(); mFirstVisibleItem = NULL; + mArrowUpItem = NULL; + mArrowDownItem = NULL; deleteAllChildren(); - +} + +// erase group of items from menu +void LLMenuGL::erase( S32 begin, S32 end, bool arrange/* = true*/) +{ + S32 items = mItems.size(); + + if ( items == 0 || begin >= end || begin < 0 || end > items ) + { + return; + } + + item_list_t::iterator start_position = mItems.begin(); + std::advance(start_position, begin); + + item_list_t::iterator end_position = mItems.begin(); + std::advance(end_position, end); + + erase(start_position, end_position); + + if (arrange) + { + needsArrange(); + } +} + +// add new item at position +void LLMenuGL::insert(S32 position, LLView* ctrl, bool arrange /*= true*/) +{ + LLMenuItemGL* item = dynamic_cast(ctrl); + + if (NULL == item || position < 0 || (U32)position >= mItems.size()) + { + return; + } + + item_list_t::iterator position_iter = mItems.begin(); + std::advance(position_iter, position); + insert(position_iter, item, arrange); +} +void LLMenuGL::insert(item_list_t::const_iterator position_iter, LLMenuItemGL* item, bool arrange /*= true*/) +{ + mItems.insert(position_iter, item); + LLUICtrl::addChild(item); + + if (arrange) + { + needsArrange(); + } } // Adjust rectangle of the menu @@ -2703,7 +3219,7 @@ BOOL LLMenuGL::handleJumpKey(KEY key) // force highlight to close old menus and open and sub-menus found_it->second->setHighlight(TRUE); - found_it->second->doIt(); + found_it->second->onCommit(); } // if we are navigating the menus, we need to eat the keystroke @@ -2713,61 +3229,36 @@ BOOL LLMenuGL::handleJumpKey(KEY key) // Add the menu item to this menu. -// This wrapper is needed because the virtual linkage causes errors if default parameters are used BOOL LLMenuGL::append( LLMenuItemGL* item ) -{ - return append(item, 0); -} - -BOOL LLMenuGL::append(LLMenuItemGL* item, LLView* insert_before) { if (!item) return FALSE; - if (!insert_before) - { mItems.push_back( item ); - } - else - { - item_list_t::iterator i; - - for (i = mItems.begin(); i != mItems.end(); ++i) - if (*i == insert_before) - break; - mItems.insert(i, item); - } - LLUICtrl::addChild(item); needsArrange(); return TRUE; } // add a separator to this menu -BOOL LLMenuGL::addSeparator() +BOOL LLMenuGL::addSeparator(const std::string& name) { - LLMenuItemGL* separator = new LLMenuItemSeparatorGL(); + LLMenuItemGL* separator = new LLMenuItemSeparatorGL(name); return addChild(separator); } // add a menu - this will create a cascading menu -// This wrapper is needed because the virtual linkage causes errors if default parameters are used BOOL LLMenuGL::appendMenu( LLMenuGL* menu ) -{ - return appendMenu(menu, 0); -} - -BOOL LLMenuGL::appendMenu(LLMenuGL* menu, LLView* insert_before) { if( menu == this ) { - llerrs << "** Attempt to attach menu to itself. This is certainly " - << "a logic error." << llendl; + LL_ERRS() << "** Attempt to attach menu to itself. This is certainly " + << "a logic error." << LL_ENDL; } BOOL success = TRUE; LLMenuItemBranchGL* branch = NULL; branch = new LLMenuItemBranchGL( menu->getName(), menu->getLabel(), menu->getHandle() ); branch->setJumpKey(menu->getJumpKey()); - success &= append( branch, insert_before ); + success &= append( branch ); // Inherit colors menu->setBackgroundColor( mBackgroundColor ); @@ -2822,7 +3313,7 @@ void LLMenuGL::setItemLastSelected(LLMenuItemGL* item) LLMenuHolderGL::setActivatedItem(item); } - // fix the checkmarks + // update enabled and checkmark status item->buildDrawLabel(); } @@ -2837,11 +3328,6 @@ void LLMenuGL::setTornOff(BOOL torn_off) mTornOff = torn_off; } -U32 LLMenuGL::getItemCount() -{ - return mItems.size(); -} - LLMenuItemGL* LLMenuGL::getItem(S32 number) { if (number >= 0 && number < (S32)mItems.size()) @@ -2879,7 +3365,11 @@ LLMenuItemGL* LLMenuGL::highlightNextItem(LLMenuItemGL* cur_item, BOOL skip_disa // same as giving focus to it if (!cur_item && getTornOff()) { - ((LLFloater*)getParent())->setFocus(TRUE); + LLFloater * parent = dynamic_cast(getParent()); + if (parent) + { + parent->setFocus(TRUE); + } } // Current item position in the items list @@ -2895,9 +3385,36 @@ LLMenuItemGL* LLMenuGL::highlightNextItem(LLMenuItemGL* cur_item, BOOL skip_disa next_item_iter = cur_item_iter; next_item_iter++; + // First visible item position in the items list + item_list_t::iterator first_visible_item_iter = std::find(mItems.begin(), mItems.end(), mFirstVisibleItem); + if (next_item_iter == mItems.end()) { next_item_iter = mItems.begin(); + + // If current item is the last in the list, the menu is scrolled to the beginning + // and the first item is highlighted. + if (mScrollable && !scrollItems(SD_BEGIN)) + { + return NULL; + } + } + // If current item is the last visible, the menu is scrolled one item down + // and the next item is highlighted. + else if (mScrollable && + (U32)std::abs(std::distance(first_visible_item_iter, next_item_iter)) >= mMaxScrollableItems) + { + // Call highlightNextItem() recursively only if the menu was successfully scrolled down. + // If scroll timer hasn't expired yet the menu won't be scrolled and calling + // highlightNextItem() will result in an endless recursion. + if (scrollItems(SD_DOWN)) + { + return highlightNextItem(cur_item, skip_disabled); + } + else + { + return NULL; + } } } @@ -2954,7 +3471,11 @@ LLMenuItemGL* LLMenuGL::highlightPrevItem(LLMenuItemGL* cur_item, BOOL skip_disa // same as giving focus to it if (!cur_item && getTornOff()) { - ((LLFloater*)getParent())->setFocus(TRUE); + LLFloater * parent = dynamic_cast(getParent()); + if (parent) + { + parent->setFocus(TRUE); + } } // Current item reverse position from the end of the list @@ -2970,9 +3491,36 @@ LLMenuItemGL* LLMenuGL::highlightPrevItem(LLMenuItemGL* cur_item, BOOL skip_disa prev_item_iter = cur_item_iter; prev_item_iter++; + // First visible item reverse position in the items list + item_list_t::reverse_iterator first_visible_item_iter = std::find(mItems.rbegin(), mItems.rend(), mFirstVisibleItem); + if (prev_item_iter == mItems.rend()) { prev_item_iter = mItems.rbegin(); + + // If current item is the first in the list, the menu is scrolled to the end + // and the last item is highlighted. + if (mScrollable && !scrollItems(SD_END)) + { + return NULL; + } + } + // If current item is the first visible, the menu is scrolled one item up + // and the previous item is highlighted. + else if (mScrollable && + std::distance(first_visible_item_iter, cur_item_iter) <= 0) + { + // Call highlightNextItem() only if the menu was successfully scrolled up. + // If scroll timer hasn't expired yet the menu won't be scrolled and calling + // highlightNextItem() will result in an endless recursion. + if (scrollItems(SD_UP)) + { + return highlightPrevItem(cur_item, skip_disabled); + } + else + { + return NULL; + } } } @@ -3073,8 +3621,8 @@ BOOL LLMenuGL::handleHover( S32 x, S32 y, MASK mask ) LLVector2 mouse_avg_dir((F32)mMouseVelX, (F32)mMouseVelY); mouse_avg_dir.normVec(); F32 interp = 0.5f * (llclamp(mouse_dir * mouse_avg_dir, 0.f, 1.f)); - mMouseVelX = llround(lerp((F32)mouse_delta_x, (F32)mMouseVelX, interp)); - mMouseVelY = llround(lerp((F32)mouse_delta_y, (F32)mMouseVelY, interp)); + mMouseVelX = ll_round(lerp((F32)mouse_delta_x, (F32)mMouseVelX, interp)); + mMouseVelY = ll_round(lerp((F32)mouse_delta_y, (F32)mMouseVelY, interp)); mLastMouseX = x; mLastMouseY = y; @@ -3082,7 +3630,7 @@ BOOL LLMenuGL::handleHover( S32 x, S32 y, MASK mask ) if ((llabs(mMouseVelX) > 0 || llabs(mMouseVelY) > 0) /*&& (!mHasSelection || - (mouse_delta_x == 0 && mouse_delta_y == 0) || + // (mouse_delta_x == 0 && mouse_delta_y == 0) || (mMouseVelX < 0) || llabs((F32)mMouseVelY) / llabs((F32)mMouseVelX) > MAX_MOUSE_SLOPE_SUB_MENU)*/) { @@ -3137,9 +3685,24 @@ BOOL LLMenuGL::handleHover( S32 x, S32 y, MASK mask ) BOOL LLMenuGL::handleScrollWheel( S32 x, S32 y, S32 clicks ) { - return blockMouseEvent(x, y); + if (!mScrollable) + return blockMouseEvent(x, y); + + if( clicks > 0 ) + { + while( clicks-- ) + scrollItems(SD_DOWN); + } + else + { + while( clicks++ ) + scrollItems(SD_UP); + } + + return TRUE; } + void LLMenuGL::draw( void ) { if (mNeedsArrange) @@ -3149,9 +3712,8 @@ void LLMenuGL::draw( void ) } if (mDropShadowed && !mTornOff) { - static S32 drop_shadow_floater = LLUI::sConfigGroup->getS32("DropShadowFloater"); - static LLColor4 color_drop_shadow = LLUI::sColorsGroup->getColor("ColorDropShadow"); - + static LLUICachedControl drop_shadow_floater("DropShadowFloater", 0); + static const LLColor4 color_drop_shadow(LLUI::sColorsGroup->getColor4("ColorDropShadow")); gl_drop_shadow(0, getRect().getHeight(), getRect().getWidth(), 0, color_drop_shadow, drop_shadow_floater ); } @@ -3160,20 +3722,6 @@ void LLMenuGL::draw( void ) { gl_rect_2d( 0, getRect().getHeight(), getRect().getWidth(), 0, mBackgroundColor ); } - - - /*LLRect rootRect = getRootView()->getRect(); - for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) - { - LLMenuItemGL* itemp = static_cast(*child_it); - if(itemp) - { - LLRect screenRect; - localRectToScreen(itemp->getRect(),&screenRect); - lldebugs << itemp->getName() << "Visible:" << itemp->getVisible() << " ValidRect: " << itemp->getRect().isValid() << " Overlaps: " << rootRect.overlaps(screenRect) << llendl; - } - }*/ - LLView::draw(); } @@ -3188,10 +3736,9 @@ void LLMenuGL::setVisible(BOOL visible) { if (visible != getVisible()) { - LLView::setVisible(visible); if (!visible) { - lldebugs << "Hiding " << getName() << llendl; + LL_DEBUGS() << "Hiding " << getName() << LL_ENDL; mFadeTimer.start(); clearHoverItem(); // reset last known mouse coordinates so @@ -3201,10 +3748,12 @@ void LLMenuGL::setVisible(BOOL visible) } else { - lldebugs << "Showing " << getName() << llendl; + LL_DEBUGS() << "Showing " << getName() << LL_ENDL; mHasSelection = true; mFadeTimer.stop(); } + + LLView::setVisible(visible); } } @@ -3225,7 +3774,7 @@ LLMenuGL* LLMenuGL::getChildMenuByName(const std::string& name, BOOL recurse) co return menup; } } - llwarns << "Child Menu " << name << " not found in menu " << getName() << llendl; + LL_WARNS() << "Child Menu " << name << " not found in menu " << getName() << LL_ENDL; return NULL; } @@ -3262,6 +3811,24 @@ void LLMenuGL::showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y) return; } + menu->setVisible( TRUE ); + + //Do not show menu if all menu items are disabled + BOOL item_enabled = false; + for (LLView::child_list_t::const_iterator itor = menu->getChildList()->begin(); + itor != menu->getChildList()->end(); + ++itor) + { + LLView *menu_item = (*itor); + item_enabled = item_enabled || menu_item->getEnabled(); + } + + if(!item_enabled) + { + menu->setVisible( FALSE ); + return; + } + // Save click point for detecting cursor moves before mouse-up. // Must be in local coords to compare with mouseUp events. // If the mouse doesn't move, the menu will stay open ala the Mac. @@ -3274,8 +3841,6 @@ void LLMenuGL::showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y) menu->mFirstVisibleItem = NULL; } - menu->setVisible( TRUE ); - // Fix menu rect if needed. menu->needsArrange(); menu->arrangeAndClear(); @@ -3306,1546 +3871,1634 @@ void LLMenuGL::showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y) menu->getParent()->sendChildToFront(menu); } -//----------------------------------------------------------------------------- -// class LLPieMenuBranch -// A branch to another pie menu -//----------------------------------------------------------------------------- -class LLPieMenuBranch : public LLMenuItemGL -{ -public: - LLPieMenuBranch(const std::string& name, const std::string& label, LLPieMenu* branch); - - virtual LLXMLNodePtr getXML(bool save_children = true) const; - - // called to rebuild the draw label - virtual void buildDrawLabel( void ); - - virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask) - { - LLMenuItemGL::handleMouseUp(x,y,mask); - return TRUE; - } - - // doIt() - do the primary funcationality of the menu item. - virtual void doIt( void ); - - LLPieMenu* getBranch() { return mBranch; } +///============================================================================ +/// Class LLMenuBarGL +///============================================================================ -protected: - LLPieMenu* mBranch; -}; +static LLRegisterWidget r2("menu_bar"); -const F32 PIE_MENU_WIDTH = 190; -const F32 PIE_MENU_HEIGHT = 190; +// Default constructor +LLMenuBarGL::LLMenuBarGL( const std::string& name ) +: LLMenuGL ( name, name ) +{ + mHorizontalLayout = TRUE; + mKeepFixedSize = TRUE; + mAltKeyTrigger = FALSE; +} -LLPieMenuBranch::LLPieMenuBranch(const std::string& name, - const std::string& label, - LLPieMenu* branch) -: LLMenuItemGL( name, label, KEY_NONE, MASK_NONE ), - mBranch( branch ) +// Default destructor +LLMenuBarGL::~LLMenuBarGL() { - mBranch->hide(FALSE); - mBranch->setParentMenuItem(this); + std::for_each(mAccelerators.begin(), mAccelerators.end(), DeletePointer()); + mAccelerators.clear(); } // virtual -LLXMLNodePtr LLPieMenuBranch::getXML(bool save_children) const +LLXMLNodePtr LLMenuBarGL::getXML(bool save_children) const { - if (mBranch) + // Sorty of hacky: reparent items to this and then back at the end of the export + LLView *orig_parent = NULL; + item_list_t::const_iterator item_iter; + for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter) { - return mBranch->getXML(); + LLMenuItemGL* child = *item_iter; + LLMenuItemBranchGL* branch = (LLMenuItemBranchGL*)child; + LLMenuGL *menu = branch->getBranch(); + orig_parent = menu->getParent(); + menu->updateParent((LLView *)this); } - return LLMenuItemGL::getXML(); -} + LLXMLNodePtr node = LLMenuGL::getXML(); -// called to rebuild the draw label -void LLPieMenuBranch::buildDrawLabel( void ) -{ + node->setName(LL_MENU_BAR_GL_TAG); + + for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter) { - // default enablement is this -- if any of the subitems are - // enabled, this item is enabled. JC - U32 sub_count = mBranch->getItemCount(); - U32 i; - BOOL any_enabled = FALSE; - for (i = 0; i < sub_count; i++) - { - LLMenuItemGL* item = mBranch->getItem(i); - item->buildDrawLabel(); - if (item->getEnabled() && !item->getDrawTextDisabled() ) - { - any_enabled = TRUE; - break; - } - } - setDrawTextDisabled(!any_enabled); - setEnabled(TRUE); + LLMenuItemGL* child = *item_iter; + LLMenuItemBranchGL* branch = (LLMenuItemBranchGL*)child; + LLMenuGL *menu = branch->getBranch(); + menu->updateParent(orig_parent); } - mDrawAccelLabel.clear(); - std::string st = mDrawAccelLabel; - appendAcceleratorString( st ); - mDrawAccelLabel = st; - - // No special branch suffix - mDrawBranchLabel.clear(); + return node; } -// doIt() - do the primary funcationality of the menu item. -void LLPieMenuBranch::doIt( void ) +LLView* LLMenuBarGL::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) { - LLPieMenu *parent = (LLPieMenu *)getParent(); - - LLRect rect = parent->getRect(); - S32 center_x; - S32 center_y; - parent->localPointToScreen(rect.getWidth() / 2, rect.getHeight() / 2, ¢er_x, ¢er_y); - - parent->hide(FALSE); - mBranch->show( center_x, center_y, FALSE ); -} - -//----------------------------------------------------------------------------- -// class LLPieMenu -// A circular menu of items, icons, etc. -//----------------------------------------------------------------------------- -LLPieMenu::LLPieMenu(const std::string& name, const std::string& label) -: LLMenuGL(name, label), - mFirstMouseDown(FALSE), - mUseInfiniteRadius(FALSE), - mHoverItem(NULL), - mHoverThisFrame(FALSE), - mHoveredAnyItem(FALSE), - mOuterRingAlpha(1.f), - mCurRadius(0.f), - mRightMouseDown(FALSE) -{ - setRect(LLRect(0,PIE_MENU_HEIGHT,PIE_MENU_WIDTH,0)); - LLMenuGL::setVisible(FALSE); -} + BOOL opaque = FALSE; + node->getAttributeBOOL("opaque", opaque); -LLPieMenu::LLPieMenu(const std::string& name) -: LLMenuGL(name, name), - mFirstMouseDown(FALSE), - mUseInfiniteRadius(FALSE), - mHoverItem(NULL), - mHoverThisFrame(FALSE), - mHoveredAnyItem(FALSE), - mOuterRingAlpha(1.f), - mCurRadius(0.f), - mRightMouseDown(FALSE) -{ - setRect(LLRect(0,PIE_MENU_HEIGHT,PIE_MENU_WIDTH,0)); - LLMenuGL::setVisible(FALSE); -} + LLMenuBarGL *menubar = new LLMenuBarGL("menu"); + LLHandle parent_handle; + LLFloater* parent_floater = dynamic_cast(parent); + if (parent_floater) + { + parent_handle = parent_floater->getHandle(); + } -// virtual -LLXMLNodePtr LLPieMenu::getXML(bool save_children) const -{ - LLXMLNodePtr node = LLMenuGL::getXML(); + // We need to have the rect early so that it's around when building + // the menu items + LLRect view_rect; + createRect(node, view_rect, parent, menubar->getRequiredRect()); + menubar->setRect(view_rect); - node->setName(LL_PIE_MENU_TAG); + if (node->hasAttribute("drop_shadow")) + { + BOOL drop_shadow = FALSE; + node->getAttributeBOOL("drop_shadow", drop_shadow); + menubar->setDropShadowed(drop_shadow); + } - return node; -} + menubar->setBackgroundVisible(opaque); + LLColor4 color(0,0,0,0); + if (opaque && LLUICtrlFactory::getAttributeColor(node,"color", color)) + { + menubar->setBackgroundColor(color); + } -void LLPieMenu::initXML(LLXMLNodePtr node, LLView *context, LLUICtrlFactory *factory) -{ LLXMLNodePtr child; for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling()) { - if (child->hasName(LL_PIE_MENU_TAG)) - { - // SUBMENU - std::string name("menu"); - child->getAttributeString("name", name); - std::string label(name); - child->getAttributeString("label", label); - - LLPieMenu *submenu = new LLPieMenu(name, label); - appendPieMenu(submenu); - submenu->initXML(child, context, factory); - } - else + if (child->hasName("menu")) { - parseChildXML(child, context, factory); + LLMenuGL *menu = (LLMenuGL*)LLMenuGL::fromXML(child, parent, factory); + menubar->appendMenu(menu); + if (LLMenuGL::sMenuContainer != NULL) + { + menu->updateParent(LLMenuGL::sMenuContainer); + } + else + { + menu->updateParent(parent); + } } } -} -bool LLPieMenu::addChild(LLView* view, S32 tab_group) -{ - if(LLMenuGL::addChild(view, tab_group)) - { - LLMenuItemSeparatorGL* sep = dynamic_cast(view); - if(sep) - sep->setVisible(false); - return true; - } - return false; -} + menubar->initFromXML(node, parent); -// virtual -void LLPieMenu::setVisible(BOOL visible) -{ - if (!visible) + BOOL create_jump_keys = FALSE; + node->getAttributeBOOL("create_jump_keys", create_jump_keys); + if (create_jump_keys) { - hide(FALSE); + menubar->createJumpKeys(); } + + return menubar; } -BOOL LLPieMenu::handleHover( S32 x, S32 y, MASK mask ) +BOOL LLMenuBarGL::handleAcceleratorKey(KEY key, MASK mask) { - // This is mostly copied from the llview class, but it continues - // the hover handle code after a hover handler has been found. - BOOL handled = FALSE; - - // If we got a hover event, we've already moved the cursor - // for any menu shifts, so subsequent mouseup messages will be in the - // correct position. No need to correct them. - //mShiftHoriz = 0; - //mShiftVert = 0; - - // release mouse capture after short period of visibility if we're using a finite boundary - // so that right click outside of boundary will trigger new pie menu - if (hasMouseCapture() && - !mRightMouseDown && - mShrinkBorderTimer.getStarted() && - mShrinkBorderTimer.getElapsedTimeF32() >= PIE_SHRINK_TIME) + if (getHighlightedItem() && mask == MASK_NONE) { - gFocusMgr.setMouseCapture(NULL); - mUseInfiniteRadius = FALSE; + // unmodified key accelerators are ignored when navigating menu + // (but are used as jump keys so will still work when appropriate menu is up) + return FALSE; } - - LLMenuItemGL *item = pieItemFromXY( x, y ); - - if (item && item->getEnabled()) + BOOL result = LLMenuGL::handleAcceleratorKey(key, mask); + if (result && mask & MASK_ALT) { - getWindow()->setCursor(UI_CURSOR_ARROW); - lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << llendl; - handled = TRUE; + // ALT key used to trigger hotkey, don't use as shortcut to open menu + mAltKeyTrigger = FALSE; + } - if (item != mHoverItem) + if(!result + && (key == KEY_F10 && mask == MASK_CONTROL) + && !gKeyboard->getKeyRepeated(key) + && isInVisibleChain()) + { + if (getHighlightedItem()) { - if (mHoverItem) - { - mHoverItem->setHighlight( FALSE ); - } - mHoverItem = item; - mHoverItem->setHighlight( TRUE ); - - switch(pieItemIndexFromXY(x, y)) - { - case 0: - make_ui_sound("UISndPieMenuSliceHighlight0"); - break; - case 1: - make_ui_sound("UISndPieMenuSliceHighlight1"); - break; - case 2: - make_ui_sound("UISndPieMenuSliceHighlight2"); - break; - case 3: - make_ui_sound("UISndPieMenuSliceHighlight3"); - break; - case 4: - make_ui_sound("UISndPieMenuSliceHighlight4"); - break; - case 5: - make_ui_sound("UISndPieMenuSliceHighlight5"); - break; - case 6: - make_ui_sound("UISndPieMenuSliceHighlight6"); - break; - case 7: - make_ui_sound("UISndPieMenuSliceHighlight7"); - break; - default: - make_ui_sound("UISndPieMenuSliceHighlight0"); - break; - } + clearHoverItem(); } - mHoveredAnyItem = TRUE; - } - else - { - // clear out our selection - if (mHoverItem) + else { - mHoverItem->setHighlight(FALSE); - mHoverItem = NULL; + // close menus originating from other menu bars when first opening menu via keyboard + LLMenuGL::sMenuContainer->hideMenus(); + highlightNextItem(NULL); + LLMenuGL::setKeyboardMode(TRUE); } + return TRUE; } - if( !handled && pointInView( x, y ) ) - { - getWindow()->setCursor(UI_CURSOR_ARROW); - lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << llendl; - handled = TRUE; - } - - mHoverThisFrame = TRUE; - - return handled; + return result; } -BOOL LLPieMenu::handleMouseDown( S32 x, S32 y, MASK mask ) +BOOL LLMenuBarGL::handleKeyHere(KEY key, MASK mask) { - BOOL handled = FALSE; - // The click was somewhere within our rectangle - LLMenuItemGL *item = pieItemFromXY( x, y ); - - if (item) + static LLUICachedControl use_altkey_for_menus ("UseAltKeyForMenus", 0); + if(key == KEY_ALT && !gKeyboard->getKeyRepeated(key) && use_altkey_for_menus) { - // lie to the item about where the click happened - // to make sure it's within the item's rectangle - handled = item->handleMouseDown( 0, 0, mask ); + mAltKeyTrigger = TRUE; } - else if (!mRightMouseDown) + else // if any key other than ALT hit, clear out waiting for Alt key mode { - // call hidemenus to make sure transient selections get cleared - ((LLMenuHolderGL*)getParent())->hideMenus(); + mAltKeyTrigger = FALSE; } - // always handle mouse down as mouse up will close open menus - return TRUE; + if (key == KEY_ESCAPE && mask == MASK_NONE) + { + LLMenuGL::setKeyboardMode(FALSE); + // if any menus are visible, this will return TRUE, stopping further processing of ESCAPE key + return LLMenuGL::sMenuContainer->hideMenus(); + } + + // before processing any other key, check to see if ALT key has triggered menu access + checkMenuTrigger(); + + return LLMenuGL::handleKeyHere(key, mask); } -BOOL LLPieMenu::handleRightMouseDown(S32 x, S32 y, MASK mask) +BOOL LLMenuBarGL::handleJumpKey(KEY key) { - BOOL handled = FALSE; - - mRightMouseDown = TRUE; + // perform case-insensitive comparison + key = toupper(key); + navigation_key_map_t::iterator found_it = mJumpKeys.find(key); + if(found_it != mJumpKeys.end() && found_it->second->getEnabled()) + { + // switch to keyboard navigation mode + LLMenuGL::setKeyboardMode(TRUE); - // The click was somewhere within our rectangle - LLMenuItemGL *item = pieItemFromXY( x, y ); - S32 delta_x = x /*+ mShiftHoriz*/ - getLocalRect().getCenterX(); - S32 delta_y = y /*+ mShiftVert*/ - getLocalRect().getCenterY(); - BOOL clicked_in_pie = ((delta_x * delta_x) + (delta_y * delta_y) < mCurRadius*mCurRadius) || mUseInfiniteRadius; + found_it->second->setHighlight(TRUE); + found_it->second->onCommit(); + } + return TRUE; +} - // grab mouse if right clicking anywhere within pie (even deadzone in middle), to detect drag outside of pie - if (clicked_in_pie) +BOOL LLMenuBarGL::handleMouseDown(S32 x, S32 y, MASK mask) +{ + // clicks on menu bar closes existing menus from other contexts but leave + // own menu open so that we get toggle behavior + if (!getHighlightedItem() || !getHighlightedItem()->isActive()) { - // capture mouse cursor as if on initial menu show - gFocusMgr.setMouseCapture(this); - mShrinkBorderTimer.stop(); - mUseInfiniteRadius = TRUE; - handled = TRUE; + LLMenuGL::sMenuContainer->hideMenus(); } - - if (item) + + return LLMenuGL::handleMouseDown(x, y, mask); +} + +void LLMenuBarGL::setVisible(BOOL visible) +{ + if(visible != getVisible()) { - // lie to the item about where the click happened - // to make sure it's within the item's rectangle - if (item->handleMouseDown( 0, 0, mask )) + if(!visible) { - handled = TRUE; + LL_DEBUGS() << "Hiding " << getName() << LL_ENDL; + } + else + { + LL_DEBUGS() << "Showing " << getName() << LL_ENDL; } } - - return handled; + LLUICtrl::setVisible(visible); } -BOOL LLPieMenu::handleRightMouseUp( S32 x, S32 y, MASK mask ) +void LLMenuBarGL::draw() { - // release mouse capture when right mouse button released, and we're past the shrink time - if (mShrinkBorderTimer.getStarted() && - mShrinkBorderTimer.getElapsedTimeF32() > PIE_SHRINK_TIME) + LLMenuItemGL* itemp = getHighlightedItem(); + // If we are in mouse-control mode and the mouse cursor is not hovering over + // the current highlighted menu item and it isn't open, then remove the + // highlight. This is done via a polling mechanism here, as we don't receive + // notifications when the mouse cursor moves off of us + if (itemp && !itemp->isOpen() && !itemp->getHover() && !LLMenuGL::getKeyboardMode()) { - mUseInfiniteRadius = FALSE; - gFocusMgr.setMouseCapture(NULL); + clearHoverItem(); } - S32 delta_x = x /*+ mShiftHoriz*/ - getLocalRect().getCenterX(); - S32 delta_y = y /*+ mShiftVert*/ - getLocalRect().getCenterY(); - if (!mHoveredAnyItem && !mFirstMouseDown && (delta_x * delta_x) + (delta_y * delta_y) < PIE_CENTER_SIZE * PIE_CENTER_SIZE) - { - // user released right mouse button in middle of pie, interpret this as closing the menu - sMenuContainer->hideMenus(); - return TRUE; - } + checkMenuTrigger(); + LLMenuGL::draw(); +} - BOOL result = handleMouseUp( x, y, mask ); - mRightMouseDown = FALSE; - mHoveredAnyItem = FALSE; - return result; +void LLMenuBarGL::checkMenuTrigger() +{ + // has the ALT key been pressed and subsequently released? + if (mAltKeyTrigger && !gKeyboard->getKeyDown(KEY_ALT)) + { + // if alt key was released quickly, treat it as a menu access key + // otherwise it was probably an Alt-zoom or similar action + static LLUICachedControl menu_access_key_time ("MenuAccessKeyTime", 0); + if (gKeyboard->getKeyElapsedTime(KEY_ALT) <= menu_access_key_time || + gKeyboard->getKeyElapsedFrameCount(KEY_ALT) < 2) + { + if (getHighlightedItem()) + { + clearHoverItem(); + } + else + { + // close menus originating from other menu bars + LLMenuGL::sMenuContainer->hideMenus(); + + highlightNextItem(NULL); + LLMenuGL::setKeyboardMode(TRUE); + } + } + mAltKeyTrigger = FALSE; + } } -BOOL LLPieMenu::handleMouseUp( S32 x, S32 y, MASK mask ) +BOOL LLMenuBarGL::jumpKeysActive() { - BOOL handled = FALSE; - - // The click was somewhere within our rectangle - LLMenuItemGL *item = pieItemFromXY( x, y ); + // require user to be in keyboard navigation mode to activate key triggers + // as menu bars are always visible and it is easy to leave the mouse cursor over them + return LLMenuGL::getKeyboardMode() && getHighlightedItem() && LLMenuGL::jumpKeysActive(); +} - if (item) +// rearrange the child rects so they fit the shape of the menu bar. +void LLMenuBarGL::arrange( void ) +{ + U32 pos = 0; + LLRect rect( 0, getRect().getHeight(), 0, 0 ); + item_list_t::const_iterator item_iter; + for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter) { - // lie to the item about where the click happened - // to make sure it's within the item's rectangle - if (item->getEnabled()) + LLMenuItemGL* item = *item_iter; + if (item->getVisible()) { - handled = item->handleMouseUp( 0, 0, mask ); - hide(TRUE); + rect.mLeft = pos; + pos += item->getNominalWidth(); + rect.mRight = pos; + item->setRect( rect ); + item->buildDrawLabel(); } } - else if (!mRightMouseDown) + reshape(rect.mRight, rect.getHeight()); +} + + +S32 LLMenuBarGL::getRightmostMenuEdge() +{ + // Find the last visible menu + item_list_t::reverse_iterator item_iter; + for (item_iter = mItems.rbegin(); item_iter != mItems.rend(); ++item_iter) { - // call hidemenus to make sure transient selections get cleared - ((LLMenuHolderGL*)getParent())->hideMenus(); + if ((*item_iter)->getVisible()) + { + break; + } } - if (handled) + if (item_iter == mItems.rend()) { - make_ui_sound("UISndClickRelease"); + return 0; } + return (*item_iter)->getRect().mRight; +} - if (!handled && !mUseInfiniteRadius) +// add a vertical separator to this menu +BOOL LLMenuBarGL::addSeparator(const std::string& name) +{ + LLMenuItemGL* separator = new LLMenuItemVerticalSeparatorGL(name); + return append(separator); +} + +// add a menu - this will create a drop down menu. +BOOL LLMenuBarGL::appendMenu( LLMenuGL* menu ) +{ + if( menu == this ) { - // call hidemenus to make sure transient selections get cleared - sMenuContainer->hideMenus(); + LL_ERRS() << "** Attempt to attach menu to itself. This is certainly " + << "a logic error." << LL_ENDL; } - if (mFirstMouseDown) - { - make_ui_sound("UISndPieMenuAppear"); - mFirstMouseDown = FALSE; - } - - // *FIX: is this necessary? - if (!mShrinkBorderTimer.getStarted()) + BOOL success = TRUE; + + LLMenuItemBranchGL* branch = NULL; + branch = new LLMenuItemBranchDownGL( menu->getName(), menu->getLabel(), menu->getHandle()); + success &= branch->addToAcceleratorList(&mAccelerators); + success &= append( branch ); + branch->setJumpKey(branch->getJumpKey()); + menu->updateParent(LLMenuGL::sMenuContainer); + + return success; +} + +BOOL LLMenuBarGL::handleHover( S32 x, S32 y, MASK mask ) +{ + BOOL handled = FALSE; + LLView* active_menu = NULL; + + BOOL no_mouse_data = mLastMouseX == 0 && mLastMouseY == 0; + S32 mouse_delta_x = no_mouse_data ? 0 : x - mLastMouseX; + S32 mouse_delta_y = no_mouse_data ? 0 : y - mLastMouseY; + mMouseVelX = (mMouseVelX / 2) + (mouse_delta_x / 2); + mMouseVelY = (mMouseVelY / 2) + (mouse_delta_y / 2); + mLastMouseX = x; + mLastMouseY = y; + + // if nothing currently selected or mouse has moved since last call, pick menu item via mouse + // otherwise let keyboard control it + if (!getHighlightedItem() || !LLMenuGL::getKeyboardMode() || llabs(mMouseVelX) > 0 || llabs(mMouseVelY) > 0) { - mShrinkBorderTimer.start(); + // find current active menu + for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) + { + LLView* viewp = *child_it; + if (((LLMenuItemGL*)viewp)->isOpen()) + { + active_menu = viewp; + } + } + + // check for new active menu + for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) + { + LLView* viewp = *child_it; + S32 local_x = x - viewp->getRect().mLeft; + S32 local_y = y - viewp->getRect().mBottom; + if( viewp->getVisible() && + viewp->getEnabled() && + viewp->pointInView(local_x, local_y) && + viewp->handleHover(local_x, local_y, mask)) + { + ((LLMenuItemGL*)viewp)->setHighlight(TRUE); + handled = TRUE; + if (active_menu && active_menu != viewp) + { + ((LLMenuItemGL*)viewp)->onCommit(); + LLMenuGL::setKeyboardMode(FALSE); + } + LLMenuGL::setKeyboardMode(FALSE); + } + } + + if (handled) + { + // set hover false on inactive menus + for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) + { + LLView* viewp = *child_it; + S32 local_x = x - viewp->getRect().mLeft; + S32 local_y = y - viewp->getRect().mBottom; + if (!viewp->pointInView(local_x, local_y) && ((LLMenuItemGL*)viewp)->getHighlight()) + { + ((LLMenuItemGL*)viewp)->setHighlight(FALSE); + } + } + } } - return handled; + getWindow()->setCursor(UI_CURSOR_ARROW); + + return TRUE; +} + +///============================================================================ +/// Class LLMenuHolderGL +///============================================================================ +LLCoordGL LLMenuHolderGL::sContextMenuSpawnPos(S32_MAX, S32_MAX); +LLMenuHolderGL::LLMenuHolderGL() + : LLPanel(std::string("Menu Holder")) +{ + setMouseOpaque(FALSE); + sItemActivationTimer.stop(); + mCanHide = TRUE; } +LLMenuHolderGL::LLMenuHolderGL(const std::string& name, const LLRect& rect, BOOL mouse_opaque, U32 follows) +: LLPanel(name, rect, FALSE) +{ + setMouseOpaque(mouse_opaque); + sItemActivationTimer.stop(); + mCanHide = TRUE; +} -// virtual -void LLPieMenu::draw() +void LLMenuHolderGL::draw() { - // clear hover if mouse moved away - if (!mHoverThisFrame && mHoverItem) + LLView::draw(); + // now draw last selected item as overlay + LLMenuItemGL* selecteditem = (LLMenuItemGL*)sItemLastSelectedHandle.get(); + if (selecteditem && selecteditem->getVisible() && sItemActivationTimer.getStarted() && sItemActivationTimer.getElapsedTimeF32() < ACTIVATE_HIGHLIGHT_TIME) { - mHoverItem->setHighlight(FALSE); - mHoverItem = NULL; + // make sure toggle items, for example, show the proper state when fading out + selecteditem->buildDrawLabel(); + + LLRect item_rect; + selecteditem->localRectToOtherView(selecteditem->getLocalRect(), &item_rect, this); + + F32 interpolant = sItemActivationTimer.getElapsedTimeF32() / ACTIVATE_HIGHLIGHT_TIME; + + LLUI::pushMatrix(); + { + LLUI::translate((F32)item_rect.mLeft, (F32)item_rect.mBottom, 0.f); + LLColor4 bg_color(LLMenuItemGL::sHighlightBackground.mV[VRED], + LLMenuItemGL::sHighlightBackground.mV[VGREEN], + LLMenuItemGL::sHighlightBackground.mV[VBLUE], + lerp(LLMenuItemGL::sHighlightBackground.mV[VALPHA], 0.f, interpolant)); + selecteditem->getMenu()->drawBackground(selecteditem, bg_color); + selecteditem->draw(); + } + LLUI::popMatrix(); } +} - F32 width = (F32) getRect().getWidth(); - F32 height = (F32) getRect().getHeight(); - mCurRadius = PIE_SCALE_FACTOR * llmax( width/2, height/2 ); +BOOL LLMenuHolderGL::handleMouseDown( S32 x, S32 y, MASK mask ) +{ + BOOL handled = LLView::childrenHandleMouseDown(x, y, mask) != NULL; + if (!handled) + { + // clicked off of menu, hide them all + hideMenus(); + } + return handled; +} - mOuterRingAlpha = mUseInfiniteRadius ? 0.f : 1.f; - if (mShrinkBorderTimer.getStarted()) +BOOL LLMenuHolderGL::handleRightMouseDown( S32 x, S32 y, MASK mask ) +{ + BOOL handled = LLView::childrenHandleRightMouseDown(x, y, mask) != NULL; + if (!handled) { - mOuterRingAlpha = clamp_rescale(mShrinkBorderTimer.getElapsedTimeF32(), 0.f, PIE_SHRINK_TIME, 0.f, 1.f); - mCurRadius *= clamp_rescale(mShrinkBorderTimer.getElapsedTimeF32(), 0.f, PIE_SHRINK_TIME, 1.f, 1.f / PIE_SCALE_FACTOR); + // clicked off of menu, hide them all + hideMenus(); } + return handled; +} - // correct for non-square pixels - F32 center_x = width/2; - F32 center_y = height/2; - S32 steps = 100; +// This occurs when you mouse-down to spawn a context menu, hold the button +// down, move off the menu, then mouse-up. We want this to close the menu. +BOOL LLMenuHolderGL::handleRightMouseUp( S32 x, S32 y, MASK mask ) +{ + const S32 SLOP = 2; + S32 spawn_dx = (x - sContextMenuSpawnPos.mX); + S32 spawn_dy = (y - sContextMenuSpawnPos.mY); + if (-SLOP <= spawn_dx && spawn_dx <= SLOP + && -SLOP <= spawn_dy && spawn_dy <= SLOP) + { + // we're still inside the slop region from spawning this menu + // so interpret the mouse-up as a single-click to show and leave on + // screen + sContextMenuSpawnPos.set(S32_MAX, S32_MAX); + return TRUE; + } - gGL.pushUIMatrix(); + BOOL handled = LLView::childrenHandleRightMouseUp(x, y, mask) != NULL; + if (!handled) { - gGL.translateUI(center_x, center_y, 0.f); + // clicked off of menu, hide them all + hideMenus(); + } + return handled; +} - F32 line_width = LLUI::sConfigGroup->getF32("PieMenuLineWidth"); - LLColor4 line_color = LLUI::sColorsGroup->getColor("PieMenuLineColor"); - LLColor4 bg_color = LLUI::sColorsGroup->getColor("PieMenuBgColor"); - LLColor4 selected_color = LLUI::sColorsGroup->getColor("PieMenuSelectedColor"); +BOOL LLMenuHolderGL::handleKey(KEY key, MASK mask, BOOL called_from_parent) +{ + BOOL handled = false; + LLMenuGL* const pMenu = dynamic_cast(getVisibleMenu()); - // main body - LLColor4 outer_color = bg_color; - outer_color.mV[VALPHA] *= mOuterRingAlpha; - gl_washer_2d( mCurRadius, (F32) PIE_CENTER_SIZE, steps, bg_color, outer_color ); + if (pMenu) + { + //eat TAB key - EXT-7000 + if (key == KEY_TAB && mask == MASK_NONE) + { + return TRUE; + } - // selected wedge - item_list_t::iterator item_iter; - S32 i = 0; - for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter) + //handle ESCAPE and RETURN key + handled = LLPanel::handleKey(key, mask, called_from_parent); + if (!handled) { - if ((*item_iter)->getHighlight()) + if (pMenu->getHighlightedItem()) { - F32 arc_size = F_PI * 0.25f; - - F32 start_radians = (i * arc_size) - (arc_size * 0.5f); - F32 end_radians = start_radians + arc_size; - - LLColor4 outer_color = selected_color; - outer_color.mV[VALPHA] *= mOuterRingAlpha; - gl_washer_segment_2d( mCurRadius, (F32)PIE_CENTER_SIZE, start_radians, end_radians, steps / 8, selected_color, outer_color ); + handled = pMenu->handleKey(key, mask, TRUE); + } + else + { + if (key == KEY_UP || key == KEY_DOWN) // Singu Note: Only highlight if the user actually meant to navigate through the menu + { + //highlight first enabled one + if (pMenu->highlightNextItem(NULL)) + { + handled = true; + } + } } - i++; } + } - LLUI::setLineWidth( line_width ); - - // inner lines - outer_color = line_color; - outer_color.mV[VALPHA] *= mOuterRingAlpha; - gl_washer_spokes_2d( mCurRadius, (F32)PIE_CENTER_SIZE, 8, line_color, outer_color ); - - // inner circle - gGL.color4fv( line_color.mV ); - gl_circle_2d( 0, 0, (F32)PIE_CENTER_SIZE, steps, FALSE ); + return handled; - // outer circle - gGL.color4fv( outer_color.mV ); - gl_circle_2d( 0, 0, mCurRadius, steps, FALSE ); +} - LLUI::setLineWidth(1.0f); +void LLMenuHolderGL::reshape(S32 width, S32 height, BOOL called_from_parent) +{ + if (width != getRect().getWidth() || height != getRect().getHeight()) + { + hideMenus(); } - gGL.popUIMatrix(); - - mHoverThisFrame = FALSE; - - LLView::draw(); + LLView::reshape(width, height, called_from_parent); } -void LLPieMenu::drawBackground(LLMenuItemGL* itemp, LLColor4& color) +LLView* const LLMenuHolderGL::getVisibleMenu() const { - F32 width = (F32) getRect().getWidth(); - F32 height = (F32) getRect().getHeight(); - F32 center_x = width/2; - F32 center_y = height/2; - S32 steps = 100; + for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) + { + LLView* viewp = *child_it; + if (viewp->getVisible() && dynamic_cast(viewp) != NULL && !dynamic_cast(viewp)) + { + return viewp; + } + } + return NULL; +} - gGL.color4fv( color.mV ); - gGL.pushUIMatrix(); + +BOOL LLMenuHolderGL::hideMenus() +{ + if (!mCanHide) { - gGL.translateUI(center_x - itemp->getRect().mLeft, center_y - itemp->getRect().mBottom, 0.f); + return FALSE; + } - item_list_t::iterator item_iter; - S32 i = 0; - for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter) + sItemActivationTimer.stop(); + + BOOL menu_visible = hasVisibleMenu(); + if (menu_visible) + { + LLMenuGL::setKeyboardMode(FALSE); + // clicked off of menu, hide them all + for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) { - if ((*item_iter) == itemp) + LLView* viewp = *child_it; + if (dynamic_cast(viewp) != NULL && viewp->getVisible() && !dynamic_cast(viewp)) { - F32 arc_size = F_PI * 0.25f; - - F32 start_radians = (i * arc_size) - (arc_size * 0.5f); - F32 end_radians = start_radians + arc_size; - - LLColor4 outer_color = color; - outer_color.mV[VALPHA] *= mOuterRingAlpha; - gl_washer_segment_2d( mCurRadius, (F32)PIE_CENTER_SIZE, start_radians, end_radians, steps / 8, color, outer_color ); + viewp->setVisible(FALSE); } - i++; } } - gGL.popUIMatrix(); + //if (gFocusMgr.childHasKeyboardFocus(this)) + //{ + // gFocusMgr.setKeyboardFocus(NULL); + //} + + return menu_visible; } -// virtual -BOOL LLPieMenu::append(LLMenuItemGL *item) +void LLMenuHolderGL::setActivatedItem(LLMenuItemGL* item) { - item->setBriefItem(TRUE); - item->setFont( LLFontGL::getFontSansSerifSmall() ); - return LLMenuGL::append(item); + sItemLastSelectedHandle = item->getHandle(); + sItemActivationTimer.start(); } -// virtual -BOOL LLPieMenu::addSeparator() +///============================================================================ +/// Class LLTearOffMenu +///============================================================================ +LLTearOffMenu::LLTearOffMenu(LLMenuGL* menup) : + LLFloater(menup->getName(), LLRect(0, 100, 100, 0), menup->getLabel(), FALSE, DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT, FALSE, FALSE) { - LLMenuItemGL* separator = new LLMenuItemBlankGL(); - separator->setFont( LLFontGL::getFontSansSerifSmall() ); - return append( separator ); + S32 floater_header_size = LLFLOATER_HEADER_SIZE; + + setName(menup->getName()); + setTitle(menup->getLabel()); + setCanMinimize(FALSE); + // flag menu as being torn off + menup->setTornOff(TRUE); + // update menu layout as torn off menu (no spillover menus) + menup->needsArrange(); + + LLRect rect; + menup->localRectToOtherView(LLRect(-1, menup->getRect().getHeight(), menup->getRect().getWidth() + 3, 0), &rect, gFloaterView); + // make sure this floater is big enough for menu + mTargetHeight = (F32)(rect.getHeight() + floater_header_size); + reshape(rect.getWidth(), rect.getHeight()); + setRect(rect); + + // attach menu to floater + menup->setFollows(FOLLOWS_LEFT | FOLLOWS_BOTTOM); + mOldParent = menup->getParent(); + addChild(menup); + menup->setVisible(TRUE); + LLRect menu_rect = menup->getRect(); + menu_rect.setOriginAndSize( 1, 1, + menu_rect.getWidth(), menu_rect.getHeight()); + menup->setRect(menu_rect); + menup->setDropShadowed(FALSE); + + mMenu = menup; + + // highlight first item (tear off item will be disabled) + mMenu->highlightNextItem(NULL); } +LLTearOffMenu::~LLTearOffMenu() +{ +} -BOOL LLPieMenu::appendPieMenu(LLPieMenu *menu) +void LLTearOffMenu::draw() { - if (menu == this) + mMenu->setBackgroundVisible(isBackgroundOpaque()); + mMenu->needsArrange(); + + if (getRect().getHeight() != mTargetHeight) { - llerrs << "Can't attach a pie menu to itself" << llendl; + // animate towards target height + reshape(getRect().getWidth(), llceil(lerp((F32)getRect().getHeight(), mTargetHeight, LLSmoothInterpolation::getInterpolant(0.05f)))); } - LLPieMenuBranch *item; - item = new LLPieMenuBranch(menu->getName(), menu->getLabel(), menu); - getParent()->addChild(item->getBranch()); - item->setFont( LLFontGL::getFontSansSerifSmall() ); - return append( item ); + LLFloater::draw(); } -// virtual -void LLPieMenu::arrange() +void LLTearOffMenu::onFocusReceived() { - // all divide by 6 - const S32 CARD_X = 60; - const S32 DIAG_X = 48; - const S32 CARD_Y = 76; - const S32 DIAG_Y = 42; + // if nothing is highlighted, just highlight first item + if (!mMenu->getHighlightedItem()) + { + mMenu->highlightNextItem(NULL); + } - const S32 ITEM_CENTER_X[] = { CARD_X, DIAG_X, 0, -DIAG_X, -CARD_X, -DIAG_X, 0, DIAG_X }; - const S32 ITEM_CENTER_Y[] = { 0, DIAG_Y, CARD_Y, DIAG_Y, 0, -DIAG_Y, -CARD_Y, -DIAG_Y }; + // parent menu items get highlights so navigation logic keeps working + LLMenuItemGL* parent_menu_item = mMenu->getParentMenuItem(); + while(parent_menu_item) + { + if (parent_menu_item->getMenu()->getVisible()) + { + parent_menu_item->setHighlight(TRUE); + parent_menu_item = parent_menu_item->getMenu()->getParentMenuItem(); + } + else + { + break; + } + } + LLFloater::onFocusReceived(); +} - S32 font_height = 0; - if( mItems.size() ) +void LLTearOffMenu::onFocusLost() +{ + // remove highlight from parent item and our own menu + mMenu->clearHoverItem(); + LLFloater::onFocusLost(); +} + +BOOL LLTearOffMenu::handleUnicodeChar(llwchar uni_char, BOOL called_from_parent) +{ + // pass keystrokes down to menu + return mMenu->handleUnicodeChar(uni_char, TRUE); +} + +BOOL LLTearOffMenu::handleKeyHere(KEY key, MASK mask) +{ + if (!mMenu->getHighlightedItem()) { - font_height = (*mItems.begin())->getNominalHeight(); + if (key == KEY_UP) + { + mMenu->highlightPrevItem(NULL); + return TRUE; + } + else if (key == KEY_DOWN) + { + mMenu->highlightNextItem(NULL); + return TRUE; + } } - S32 item_width = 0; + // pass keystrokes down to menu + return mMenu->handleKey(key, mask, TRUE); +} -// F32 sin_delta = OO_SQRT2; // sin(45 deg) -// F32 cos_delta = OO_SQRT2; // cos(45 deg) +void LLTearOffMenu::translate(S32 x, S32 y) +{ + if (x != 0 && y != 0) + { + // hide open sub-menus by clearing current hover item + mMenu->clearHoverItem(); + } + LLFloater::translate(x, y); +} - // TODO: Compute actual bounding rect for menu +//static +LLTearOffMenu* LLTearOffMenu::create(LLMenuGL* menup) +{ + LLTearOffMenu* tearoffp = new LLTearOffMenu(menup); + // keep onscreen + gFloaterView->adjustToFitScreen(tearoffp, FALSE); + tearoffp->open(); /* Flawfinder: ignore */ - LLRect rect = getRect(); + return tearoffp; +} - // place items around a circle, with item 0 at positive X, - // rotating counter-clockwise - item_list_t::iterator item_iter; - S32 i = 0; - for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter) +void LLTearOffMenu::onClose(bool app_quitting) +{ + removeChild(mMenu); + mOldParent->addChild(mMenu); + mMenu->clearHoverItem(); + mMenu->setFollowsNone(); + mMenu->setBackgroundVisible(TRUE); + mMenu->setVisible(FALSE); + mMenu->setTornOff(FALSE); + mMenu->setDropShadowed(TRUE); + destroy(); +} + + +LLContextMenuBranch::LLContextMenuBranch(const std::string& name, const std::string& label, LLContextMenu* branch) +: LLMenuItemGL( name, label, KEY_NONE, MASK_NONE ), + mBranch( branch ) +{ + mBranch->hide(); + mBranch->setParentMenuItem(this); +} + +// virtual +LLXMLNodePtr LLContextMenuBranch::getXML(bool save_children) const +{ + if (mBranch) { - LLMenuItemGL *item = *item_iter; + return mBranch->getXML(); + } - item_width = item->getNominalWidth(); + return LLMenuItemGL::getXML(); +} - // Put in the right place around a circle centered at 0,0 - rect.setCenterAndSize(ITEM_CENTER_X[i], - ITEM_CENTER_Y[i], - item_width, font_height ); +// called to rebuild the draw label +void LLContextMenuBranch::buildDrawLabel( void ) +{ + { + // default enablement is this -- if any of the subitems are + // enabled, this item is enabled. JC + U32 sub_count = mBranch->getItemCount(); + U32 i; + BOOL any_enabled = FALSE; + for (i = 0; i < sub_count; i++) + { + LLMenuItemGL* item = mBranch->getItem(i); + item->buildDrawLabel(); + if (item->getEnabled() && !item->getDrawTextDisabled() ) + { + any_enabled = TRUE; + break; + } + } + setDrawTextDisabled(!any_enabled); + setEnabled(TRUE); + } - // Correct for the actual rectangle size - rect.translate( getRect().getWidth()/2, getRect().getHeight()/2 ); + mDrawAccelLabel.clear(); + std::string st = mDrawAccelLabel; + appendAcceleratorString( st ); + mDrawAccelLabel = st; - item->setRect( rect ); + // Singu Note: This is meaningless to pies + mDrawBranchLabel = LLMenuGL::BRANCH_SUFFIX; +} - // Make sure enablement is correct - item->buildDrawLabel(); - i++; +void LLContextMenuBranch::showSubMenu() +{ + if (getDrawTextDisabled()) return; // Singu Note: Don't open disabled submenus! + S32 center_x; + S32 center_y; + static LLUICachedControl context("LiruUseContextMenus", false); + if (context) // Use the edge of this item + { + localPointToScreen(getRect().getWidth(), getRect().getHeight(), ¢er_x, ¢er_y); + } + else // Use the center of the parent pie menu, and hide it + { + LLContextMenu* parent = static_cast(getParent()); + const LLRect& rect = parent->getRect(); + parent->localPointToScreen(rect.getWidth() / 2, rect.getHeight() / 2, ¢er_x, ¢er_y); + parent->hide(); } + mBranch->show(center_x, center_y, context); } -LLMenuItemGL *LLPieMenu::pieItemFromXY(S32 x, S32 y) +// onCommit() - do the primary funcationality of the menu item. +void LLContextMenuBranch::onCommit( void ) { - // We might have shifted this menu on draw. If so, we need - // to shift over mouseup events until we get a hover event. - //x += mShiftHoriz; - //y += mShiftVert; + showSubMenu(); +} - // An arc of the pie menu is 45 degrees - const F32 ARC_DEG = 45.f; - S32 delta_x = x - getRect().getWidth() / 2; - S32 delta_y = y - getRect().getHeight() / 2; +void LLContextMenuBranch::setHighlight( BOOL highlight ) +{ + if (highlight == getHighlight()) return; + LLMenuItemGL::setHighlight(highlight); - // circle safe zone in the center - S32 dist_squared = delta_x*delta_x + delta_y*delta_y; - if (dist_squared < PIE_CENTER_SIZE*PIE_CENTER_SIZE) + // Singu Note: Pie menus show subs only on click + static LLUICachedControl context("LiruUseContextMenus", false); + if (!context) return; + + if (highlight) { - return NULL; + showSubMenu(); } - - // infinite radius is only used with right clicks - S32 radius = llmax( getRect().getWidth()/2, getRect().getHeight()/2 ); - if (!(mUseInfiniteRadius && mRightMouseDown) && dist_squared > radius * radius) + else { - return NULL; + mBranch->hide(); } +} - F32 angle = RAD_TO_DEG * (F32) atan2((F32)delta_y, (F32)delta_x); - - // rotate marks CCW so that east = [0, ARC_DEG) instead of - // [-ARC_DEG/2, ARC_DEG/2) - angle += ARC_DEG / 2.f; - // make sure we're only using positive angles - if (angle < 0.f) angle += 360.f; +/////////////////////////////////////////////////////////////////////////////////////////////////////////// +//----------------------------------------------------------------------------- +// class LLContextMenu +// A context menu +//----------------------------------------------------------------------------- +LLContextMenu::LLContextMenu(const std::string& name, const std::string& label) +: LLMenuGL(name, label.empty() ? name : label), + mHoveredAnyItem(FALSE), + mHoverItem(NULL) +{ + //setBackgroundVisible(TRUE); + LLMenuGL::setVisible(FALSE); +} + +// virtual +LLXMLNodePtr LLContextMenu::getXML(bool save_children) const +{ + LLXMLNodePtr node = LLMenuGL::getXML(); - S32 which = S32( angle / ARC_DEG ); + node->setName(LL_PIE_MENU_TAG); - if (0 <= which && which < (S32)mItems.size() ) + return node; +} + +void LLContextMenu::initXML(LLXMLNodePtr node, LLView *context, LLUICtrlFactory *factory, bool is_context) +{ + LLXMLNodePtr child; + for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling()) { - item_list_t::iterator item_iter; - for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter) + if (child->hasName(LL_PIE_MENU_TAG)) { - if (which == 0) + // In context menus, more submenu is just an extension of the parent + bool more(false); + if (is_context && child->getAttribute_bool("more", more) && more) { - if((*item_iter)->getVisible()) - return (*item_iter); - else - return NULL; + //addSeparator(); // Singu Note: perhaps a separator (above) is in order, too? + initXML(child, context, factory, true); + //addSeparator(); // Singu Note: perhaps a separator (below) is in order, too? + } + else + { + // SUBMENU + std::string name("menu"); + child->getAttributeString("name", name); + std::string label(name); + child->getAttributeString("label", label); + + // Singu Note: Pie Submenus are denoted with >, while context submenus have an obvious arrow at the end + LLContextMenu* submenu = is_context ? new LLContextMenu(name, label) : new LLPieMenu(name, label + " >"); + appendContextSubMenu(submenu); + submenu->initXML(child, context, factory, is_context); } - which--; + } + else + { + parseChildXML(child, context); } } - - return NULL; } -S32 LLPieMenu::pieItemIndexFromXY(S32 x, S32 y) +// virtual +void LLContextMenu::setVisible(BOOL visible) { - // An arc of the pie menu is 45 degrees - const F32 ARC_DEG = 45.f; - // correct for non-square pixels - S32 delta_x = x - getRect().getWidth() / 2; - S32 delta_y = y - getRect().getHeight() / 2; + if (!visible) + hide(); +} - // circle safe zone in the center - if (delta_x*delta_x + delta_y*delta_y < PIE_CENTER_SIZE*PIE_CENTER_SIZE) +// Takes cursor position in screen space? +void LLContextMenu::show(S32 x, S32 y, bool context) +{ + if (getChildList()->empty()) { - return -1; + // nothing to show, so abort + return; } + // Save click point for detecting cursor moves before mouse-up. + // Must be in local coords to compare with mouseUp events. + // If the mouse doesn't move, the menu will stay open ala the Mac. + // See also LLMenuGL::showPopup() + LLMenuHolderGL::sContextMenuSpawnPos.set(x,y); - F32 angle = RAD_TO_DEG * (F32) atan2((F32)delta_y, (F32)delta_x); - - // rotate marks CCW so that east = [0, ARC_DEG) instead of - // [-ARC_DEG/2, ARC_DEG/2) - angle += ARC_DEG / 2.f; - - // make sure we're only using positive angles - if (angle < 0.f) angle += 360.f; - - S32 which = S32( angle / ARC_DEG ); - return which; -} + arrangeAndClear(); -void LLPieMenu::show(S32 x, S32 y, BOOL mouse_down) -{ S32 width = getRect().getWidth(); S32 height = getRect().getHeight(); - const LLRect menu_region_rect = LLMenuGL::sMenuContainer->getMenuRect(); - LLView* parent_view = getParent(); - S32 local_x, local_y; - parent_view->screenPointToLocal(x, y, &local_x, &local_y); - - LLRect rect; - rect.setCenterAndSize(local_x, local_y, width, height); - setRect(rect); - - arrange(); - - // Adjust the pie rectangle to keep it on screen - if(!menu_region_rect.contains(rect)) + // Singu TODO: These could probably be combined a bit more. + if (context) // Singu Note: Determine menu repositioning behavior based on menu type { - S32 trans[2]={0,0}; - if (rect.mLeft < menu_region_rect.mLeft) - { - trans[0] = menu_region_rect.mLeft - rect.mLeft; - } - else if (rect.mRight > menu_region_rect.mRight) - { - trans[0] = menu_region_rect.mRight - rect.mRight; - } - if (rect.mBottom < menu_region_rect.mBottom) + // Open upwards if menu extends past bottom + if (y - height < menu_region_rect.mBottom) { - trans[1] = menu_region_rect.mBottom - rect.mBottom; + if (getParentMenuItem()) // Adjust if this is a submenu + { + y += height - getParentMenuItem()->getNominalHeight(); + } + else + { + y += height; + } } - else if (rect.mTop > menu_region_rect.mTop) + + // Open out to the left if menu extends past right edge + if (x + width > menu_region_rect.mRight) { - trans[1] = menu_region_rect.mTop - rect.mTop; + if (getParentMenuItem()) + { + x -= getParentMenuItem()->getRect().getWidth() + width; + } + else + { + x -= width; + } } - setRect(rect.translate(trans[0],trans[1])); - LLUI::setMousePositionLocal(getParent(),rect.getCenterX(), rect.getCenterY()); - } - // *FIX: what happens when mouse buttons reversed? - mRightMouseDown = mouse_down; - mFirstMouseDown = mouse_down; - mUseInfiniteRadius = TRUE; - mHoveredAnyItem = FALSE; + S32 local_x, local_y; + parent_view->screenPointToLocal(x, y, &local_x, &local_y); - if (!mFirstMouseDown) + LLRect rect; + rect.setLeftTopAndSize(local_x, local_y, width, height); + setRect(rect); + } + else { - make_ui_sound("UISndPieMenuAppear"); + S32 local_x, local_y; + parent_view->screenPointToLocal(x, y, &local_x, &local_y); + + LLRect rect; + rect.setCenterAndSize(local_x, local_y, width, height); + setRect(rect); + if (!menu_region_rect.contains(rect)) // Adjust the pie rectangle to keep it on screen + { + S32 trans[2]={0,0}; + if (rect.mLeft < menu_region_rect.mLeft) + { + trans[0] = menu_region_rect.mLeft - rect.mLeft; + } + else if (rect.mRight > menu_region_rect.mRight) + { + trans[0] = menu_region_rect.mRight - rect.mRight; + } + if (rect.mBottom < menu_region_rect.mBottom) + { + trans[1] = menu_region_rect.mBottom - rect.mBottom; + } + else if (rect.mTop > menu_region_rect.mTop) + { + trans[1] = menu_region_rect.mTop - rect.mTop; + } + setRect(rect.translate(trans[0],trans[1])); + LLUI::setMousePositionLocal(getParent(),rect.getCenterX(), rect.getCenterY()); + } } + arrange(); LLView::setVisible(TRUE); - - // we want all mouse events in case user does quick right click again off of pie menu - // rectangle, to support gestural menu traversal - gFocusMgr.setMouseCapture(this); - - if (mouse_down) - { - mShrinkBorderTimer.stop(); - } - else - { - mShrinkBorderTimer.start(); - } } -void LLPieMenu::hide(BOOL item_selected) +void LLContextMenu::hide() { if (!getVisible()) return; + LLView::setVisible(FALSE); + if (mHoverItem) { mHoverItem->setHighlight( FALSE ); - mHoverItem = NULL; } - - make_ui_sound("UISndPieMenuHide"); - - mFirstMouseDown = FALSE; - mRightMouseDown = FALSE; - mUseInfiniteRadius = FALSE; - mHoveredAnyItem = FALSE; - - LLView::setVisible(FALSE); - - gFocusMgr.setMouseCapture(NULL); -} - -///============================================================================ -/// Class LLMenuBarGL -///============================================================================ - -static LLRegisterWidget r2("menu_bar"); - -// Default constructor -LLMenuBarGL::LLMenuBarGL( const std::string& name ) -: LLMenuGL ( name, name ) -{ - mHorizontalLayout = TRUE; - mKeepFixedSize = TRUE; - mAltKeyTrigger = FALSE; + mHoverItem = nullptr; } -// Default destructor -LLMenuBarGL::~LLMenuBarGL() -{ - std::for_each(mAccelerators.begin(), mAccelerators.end(), DeletePointer()); - mAccelerators.clear(); -} -// virtual -LLXMLNodePtr LLMenuBarGL::getXML(bool save_children) const +BOOL LLContextMenu::handleHover( S32 x, S32 y, MASK mask ) { - // Sorty of hacky: reparent items to this and then back at the end of the export - LLView *orig_parent = NULL; - item_list_t::const_iterator item_iter; - for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter) - { - LLMenuItemGL* child = *item_iter; - LLMenuItemBranchGL* branch = (LLMenuItemBranchGL*)child; - LLMenuGL *menu = branch->getBranch(); - orig_parent = menu->getParent(); - menu->updateParent((LLView *)this); - } - - LLXMLNodePtr node = LLMenuGL::getXML(); - - node->setName(LL_MENU_BAR_GL_TAG); + LLMenuGL::handleHover(x, y, mask); - for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter) - { - LLMenuItemGL* child = *item_iter; - LLMenuItemBranchGL* branch = (LLMenuItemBranchGL*)child; - LLMenuGL *menu = branch->getBranch(); - menu->updateParent(orig_parent); - } + LLMenuItemGL* item = getHighlightedItem(); - return node; + return handleHoverOver(item, x, y); } -LLView* LLMenuBarGL::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) +BOOL LLContextMenu::handleHoverOver(LLMenuItemGL* item, S32 x, S32 y) { - BOOL opaque = FALSE; - node->getAttributeBOOL("opaque", opaque); - - LLMenuBarGL *menubar = new LLMenuBarGL("menu"); - - LLHandle parent_handle; - LLFloater* parent_floater = dynamic_cast(parent); - if (parent_floater) - { - parent_handle = parent_floater->getHandle(); - } - - // We need to have the rect early so that it's around when building - // the menu items - LLRect view_rect; - createRect(node, view_rect, parent, menubar->getRequiredRect()); - menubar->setRect(view_rect); - - if (node->hasAttribute("drop_shadow")) - { - BOOL drop_shadow = FALSE; - node->getAttributeBOOL("drop_shadow", drop_shadow); - menubar->setDropShadowed(drop_shadow); - } + BOOL handled = FALSE; - menubar->setBackgroundVisible(opaque); - LLColor4 color(0,0,0,0); - if (opaque && LLUICtrlFactory::getAttributeColor(node,"color", color)) + if (item && item->getEnabled()) { - menubar->setBackgroundColor(color); - } + getWindow()->setCursor(UI_CURSOR_ARROW); + handled = TRUE; - LLXMLNodePtr child; - for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling()) - { - if (child->hasName("menu")) + if (item != mHoverItem) { - LLMenuGL *menu = (LLMenuGL*)LLMenuGL::fromXML(child, parent, factory); - menubar->appendMenu(menu); - if (LLMenuGL::sMenuContainer != NULL) - { - menu->updateParent(LLMenuGL::sMenuContainer); - } - else + if (mHoverItem) { - menu->updateParent(parent); + mHoverItem->setHighlight( FALSE ); } + mHoverItem = item; + mHoverItem->setHighlight( TRUE ); + } + mHoveredAnyItem = TRUE; + } + else + { + // clear out our selection + if (mHoverItem) + { + mHoverItem->setHighlight(FALSE); + mHoverItem = NULL; } } - menubar->initFromXML(node, parent); - - BOOL create_jump_keys = FALSE; - node->getAttributeBOOL("create_jump_keys", create_jump_keys); - if (create_jump_keys) + if( !handled && pointInView( x, y ) ) { - menubar->createJumpKeys(); + getWindow()->setCursor(UI_CURSOR_ARROW); + handled = TRUE; } - return menubar; + return handled; } -BOOL LLMenuBarGL::handleAcceleratorKey(KEY key, MASK mask) +// handleMouseDown and handleMouseUp are handled by LLMenuGL + + +BOOL LLContextMenu::handleRightMouseDown(S32 x, S32 y, MASK mask) { - if (getHighlightedItem() && mask == MASK_NONE) - { - // unmodified key accelerators are ignored when navigating menu - // (but are used as jump keys so will still work when appropriate menu is up) - return FALSE; - } - BOOL result = LLMenuGL::handleAcceleratorKey(key, mask); - if (result && mask & MASK_ALT) + BOOL handled = FALSE; + + // The click was somewhere within our rectangle + LLMenuItemGL* item = getHighlightedItem(); + + S32 local_x = x - getRect().mLeft; + S32 local_y = y - getRect().mBottom; + + BOOL clicked_in_menu = pointInView(local_x, local_y); + + // grab mouse if right clicking anywhere within pie (even deadzone in middle), to detect drag outside of pie + if (clicked_in_menu) { - // ALT key used to trigger hotkey, don't use as shortcut to open menu - mAltKeyTrigger = FALSE; + // capture mouse cursor as if on initial menu show + handled = TRUE; } - if(!result - && (key == KEY_F10 && mask == MASK_CONTROL) - && !gKeyboard->getKeyRepeated(key) - && isInVisibleChain()) + if (item) { - if (getHighlightedItem()) - { - clearHoverItem(); - } - else + // lie to the item about where the click happened + // to make sure it's within the item's rectangle + if (item->handleMouseDown( 0, 0, mask )) { - // close menus originating from other menu bars when first opening menu via keyboard - LLMenuGL::sMenuContainer->hideMenus(); - highlightNextItem(NULL); - LLMenuGL::setKeyboardMode(TRUE); + handled = TRUE; } - return TRUE; } - return result; + return handled; } -BOOL LLMenuBarGL::handleKeyHere(KEY key, MASK mask) +BOOL LLContextMenu::handleRightMouseUp( S32 x, S32 y, MASK mask ) { - if(key == KEY_ALT && !gKeyboard->getKeyRepeated(key) && LLUI::sConfigGroup->getBOOL("UseAltKeyForMenus")) - { - mAltKeyTrigger = TRUE; - } - else // if any key other than ALT hit, clear out waiting for Alt key mode - { - mAltKeyTrigger = FALSE; - } - - if (key == KEY_ESCAPE && mask == MASK_NONE) + S32 local_x = x - getRect().mLeft; + S32 local_y = y - getRect().mBottom; + + if (!mHoveredAnyItem && !pointInView(local_x, local_y)) { - LLMenuGL::setKeyboardMode(FALSE); - // if any menus are visible, this will return TRUE, stopping further processing of ESCAPE key - return LLMenuGL::sMenuContainer->hideMenus(); + sMenuContainer->hideMenus(); + return TRUE; } - // before processing any other key, check to see if ALT key has triggered menu access - checkMenuTrigger(); - return LLMenuGL::handleKeyHere(key, mask); + BOOL result = handleMouseUp( x, y, mask ); + mHoveredAnyItem = FALSE; + + return result; } -BOOL LLMenuBarGL::handleJumpKey(KEY key) +bool LLContextMenu::addChild(LLView* view, S32 tab_group) { - // perform case-insensitive comparison - key = toupper(key); - navigation_key_map_t::iterator found_it = mJumpKeys.find(key); - if(found_it != mJumpKeys.end() && found_it->second->getEnabled()) + if (LLContextMenu* context = dynamic_cast(view)) + return appendContextSubMenu(context); + if (LLMenuItemGL* item = dynamic_cast(view)) { - // switch to keyboard navigation mode - LLMenuGL::setKeyboardMode(TRUE); - - found_it->second->setHighlight(TRUE); - found_it->second->doIt(); + if (!mItems.empty() && mItems.back()->getType() == "separator" && item->getType() == "separator") // Singu TODO: Profile this? Does it matter? + item->setVisible(false); + return append(item); } - return TRUE; + if (LLMenuGL* menu = dynamic_cast(view)) + return appendMenu(menu); + return false; } -BOOL LLMenuBarGL::handleMouseDown(S32 x, S32 y, MASK mask) + +BOOL LLContextMenu::appendContextSubMenu(LLContextMenu* menu) { - // clicks on menu bar closes existing menus from other contexts but leave - // own menu open so that we get toggle behavior - if (!getHighlightedItem() || !getHighlightedItem()->isActive()) + if (menu == this) { - LLMenuGL::sMenuContainer->hideMenus(); + LL_ERRS() << "Can't attach a context menu to itself" << LL_ENDL; } + LLContextMenuBranch* item = new LLContextMenuBranch(menu->getName(), menu->getLabel(), menu); + getParent()->addChild(item->getBranch()); + return append(item); +} - return LLMenuGL::handleMouseDown(x, y, mask); +const S32 PIE_MENU_HEIGHT = 190; +const S32 PIE_MENU_WIDTH = 190; + +//----------------------------------------------------------------------------- +// class LLPieMenu +// A circular menu of items, icons, etc. +//----------------------------------------------------------------------------- +LLPieMenu::LLPieMenu(const std::string& name, const std::string& label) +: LLContextMenu(name, label), + mFirstMouseDown(FALSE), + mUseInfiniteRadius(FALSE), + mHoverIndex(-1), + mHoverThisFrame(FALSE), + mOuterRingAlpha(1.f), + mCurRadius(0.f), + mRightMouseDown(FALSE) +{ + setRect(LLRect(0,PIE_MENU_HEIGHT,PIE_MENU_WIDTH,0)); } -void LLMenuBarGL::setVisible(BOOL visible) +// Separators on pie menus are invisible +bool LLPieMenu::addChild(LLView* view, S32 tab_group) { - if(visible != getVisible()) + if (LLContextMenu::addChild(view, tab_group) && view->getVisible()) { - if(!visible) - { - lldebugs << "Hiding " << getName() << llendl; - } - else - { - lldebugs << "Showing " << getName() << llendl; - } + LLMenuItemSeparatorGL* sep = dynamic_cast(view); + if(sep) + sep->setVisible(false); + return true; } - LLUICtrl::setVisible(visible); + return false; } -void LLMenuBarGL::draw() +BOOL LLPieMenu::handleHover( S32 x, S32 y, MASK mask ) { - LLMenuItemGL* itemp = getHighlightedItem(); - // If we are in mouse-control mode and the mouse cursor is not hovering over - // the current highlighted menu item and it isn't open, then remove the - // highlight. This is done via a polling mechanism here, as we don't receive - // notifications when the mouse cursor moves off of us - if (itemp && !itemp->isOpen() && !itemp->getHover() && !LLMenuGL::getKeyboardMode()) + // release mouse capture after short period of visibility if we're using a finite boundary + // so that right click outside of boundary will trigger new pie menu + if (hasMouseCapture() && + !mRightMouseDown && + mShrinkBorderTimer.getStarted() && + mShrinkBorderTimer.getElapsedTimeF32() >= PIE_SHRINK_TIME) { - clearHoverItem(); + gFocusMgr.setMouseCapture(NULL); + mUseInfiniteRadius = FALSE; } - checkMenuTrigger(); + mHoverThisFrame = TRUE; - LLMenuGL::draw(); -} + S32 index = mHoverIndex; + mHoverIndex = pieItemIndexFromXY(x, y); + BOOL handled = handleHoverOver(pieItemFromIndex(mHoverIndex), x, y); -void LLMenuBarGL::checkMenuTrigger() -{ - // has the ALT key been pressed and subsequently released? - if (mAltKeyTrigger && !gKeyboard->getKeyDown(KEY_ALT)) + if (mHoverItem && mHoverIndex != index) { - // if alt key was released quickly, treat it as a menu access key - // otherwise it was probably an Alt-zoom or similar action - if (gKeyboard->getKeyElapsedTime(KEY_ALT) <= LLUI::sConfigGroup->getF32("MenuAccessKeyTime") || - gKeyboard->getKeyElapsedFrameCount(KEY_ALT) < 2) + switch(mHoverIndex) { - if (getHighlightedItem()) - { - clearHoverItem(); - } - else - { - // close menus originating from other menu bars - LLMenuGL::sMenuContainer->hideMenus(); - - highlightNextItem(NULL); - LLMenuGL::setKeyboardMode(TRUE); - } + case 0: + make_ui_sound("UISndPieMenuSliceHighlight0"); + break; + case 1: + make_ui_sound("UISndPieMenuSliceHighlight1"); + break; + case 2: + make_ui_sound("UISndPieMenuSliceHighlight2"); + break; + case 3: + make_ui_sound("UISndPieMenuSliceHighlight3"); + break; + case 4: + make_ui_sound("UISndPieMenuSliceHighlight4"); + break; + case 5: + make_ui_sound("UISndPieMenuSliceHighlight5"); + break; + case 6: + make_ui_sound("UISndPieMenuSliceHighlight6"); + break; + case 7: + make_ui_sound("UISndPieMenuSliceHighlight7"); + break; + default: + make_ui_sound("UISndPieMenuSliceHighlight0"); + break; } - mAltKeyTrigger = FALSE; } + return handled; } -BOOL LLMenuBarGL::jumpKeysActive() +BOOL LLPieMenu::handleMouseDown( S32 x, S32 y, MASK mask ) { - // require user to be in keyboard navigation mode to activate key triggers - // as menu bars are always visible and it is easy to leave the mouse cursor over them - return LLMenuGL::getKeyboardMode() && getHighlightedItem() && LLMenuGL::jumpKeysActive(); -} + BOOL handled = FALSE; + // The click was somewhere within our rectangle + LLMenuItemGL *item = pieItemFromXY( x, y ); -// rearrange the child rects so they fit the shape of the menu bar. -void LLMenuBarGL::arrange( void ) -{ - U32 pos = 0; - LLRect rect( 0, getRect().getHeight(), 0, 0 ); - item_list_t::const_iterator item_iter; - for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter) + if (item) { - LLMenuItemGL* item = *item_iter; - if (item->getVisible()) - { - rect.mLeft = pos; - pos += item->getNominalWidth(); - rect.mRight = pos; - item->setRect( rect ); - item->buildDrawLabel(); - } + // lie to the item about where the click happened + // to make sure it's within the item's rectangle + handled = item->handleMouseDown( 0, 0, mask ); } - reshape(rect.mRight, rect.getHeight()); -} + // always handle mouse down as mouse up will close open menus + return TRUE; +} -S32 LLMenuBarGL::getRightmostMenuEdge() +BOOL LLPieMenu::handleRightMouseDown(S32 x, S32 y, MASK mask) { - // Find the last visible menu - item_list_t::reverse_iterator item_iter; - for (item_iter = mItems.rbegin(); item_iter != mItems.rend(); ++item_iter) + BOOL handled = FALSE; + + mRightMouseDown = TRUE; + + // The click was somewhere within our rectangle + LLMenuItemGL *item = pieItemFromXY( x, y ); + S32 delta_x = x /*+ mShiftHoriz*/ - getLocalRect().getCenterX(); + S32 delta_y = y /*+ mShiftVert*/ - getLocalRect().getCenterY(); + BOOL clicked_in_pie = ((delta_x * delta_x) + (delta_y * delta_y) < mCurRadius*mCurRadius) || mUseInfiniteRadius; + + // grab mouse if right clicking anywhere within pie (even deadzone in middle), to detect drag outside of pie + if (clicked_in_pie) { - if ((*item_iter)->getVisible()) - { - break; - } + // capture mouse cursor as if on initial menu show + gFocusMgr.setMouseCapture(this); + mShrinkBorderTimer.stop(); + mUseInfiniteRadius = TRUE; + handled = TRUE; } - if (item_iter == mItems.rend()) + if (item) { - return 0; + // lie to the item about where the click happened + // to make sure it's within the item's rectangle + if (item->handleMouseDown( 0, 0, mask )) + { + handled = TRUE; + } } - return (*item_iter)->getRect().mRight; -} -// add a vertical separator to this menu -BOOL LLMenuBarGL::addSeparator() -{ - LLMenuItemGL* separator = new LLMenuItemVerticalSeparatorGL(); - return append( separator ); + return handled; } -// add a menu - this will create a drop down menu. -BOOL LLMenuBarGL::appendMenu( LLMenuGL* menu ) +BOOL LLPieMenu::handleRightMouseUp( S32 x, S32 y, MASK mask ) { - if( menu == this ) + // release mouse capture when right mouse button released, and we're past the shrink time + if (mShrinkBorderTimer.getStarted() && + mShrinkBorderTimer.getElapsedTimeF32() > PIE_SHRINK_TIME) { - llerrs << "** Attempt to attach menu to itself. This is certainly " - << "a logic error." << llendl; + mUseInfiniteRadius = FALSE; + gFocusMgr.setMouseCapture(NULL); } - BOOL success = TRUE; + S32 delta_x = x /*+ mShiftHoriz*/ - getLocalRect().getCenterX(); + S32 delta_y = y /*+ mShiftVert*/ - getLocalRect().getCenterY(); + if (!mHoveredAnyItem && !mFirstMouseDown && (delta_x * delta_x) + (delta_y * delta_y) < PIE_CENTER_SIZE * PIE_CENTER_SIZE) + { + // user released right mouse button in middle of pie, interpret this as closing the menu + sMenuContainer->hideMenus(); + return TRUE; + } - LLMenuItemBranchGL* branch = NULL; - branch = new LLMenuItemBranchDownGL( menu->getName(), menu->getLabel(), menu->getHandle()); - success &= branch->addToAcceleratorList(&mAccelerators); - success &= append( branch ); - branch->setJumpKey(branch->getJumpKey()); - menu->updateParent(LLMenuGL::sMenuContainer); - - return success; + + BOOL result = handleMouseUp( x, y, mask ); + mRightMouseDown = FALSE; + mHoveredAnyItem = FALSE; + + return result; } -BOOL LLMenuBarGL::handleHover( S32 x, S32 y, MASK mask ) +BOOL LLPieMenu::handleMouseUp( S32 x, S32 y, MASK mask ) { BOOL handled = FALSE; - LLView* active_menu = NULL; - BOOL no_mouse_data = mLastMouseX == 0 && mLastMouseY == 0; - S32 mouse_delta_x = no_mouse_data ? 0 : x - mLastMouseX; - S32 mouse_delta_y = no_mouse_data ? 0 : y - mLastMouseY; - mMouseVelX = (mMouseVelX / 2) + (mouse_delta_x / 2); - mMouseVelY = (mMouseVelY / 2) + (mouse_delta_y / 2); - mLastMouseX = x; - mLastMouseY = y; + // The click was somewhere within our rectangle + LLMenuItemGL *item = pieItemFromXY( x, y ); - // if nothing currently selected or mouse has moved since last call, pick menu item via mouse - // otherwise let keyboard control it - if (!getHighlightedItem() || !LLMenuGL::getKeyboardMode() || llabs(mMouseVelX) > 0 || llabs(mMouseVelY) > 0) + if (item) { - // find current active menu - for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) - { - LLView* viewp = *child_it; - if (((LLMenuItemGL*)viewp)->isOpen()) - { - active_menu = viewp; - } - } - - // check for new active menu - for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) + // lie to the item about where the click happened + // to make sure it's within the item's rectangle + if (item->getEnabled()) { - LLView* viewp = *child_it; - S32 local_x = x - viewp->getRect().mLeft; - S32 local_y = y - viewp->getRect().mBottom; - if( viewp->getVisible() && - viewp->getEnabled() && - viewp->pointInView(local_x, local_y) && - viewp->handleHover(local_x, local_y, mask)) - { - ((LLMenuItemGL*)viewp)->setHighlight(TRUE); - handled = TRUE; - if (active_menu && active_menu != viewp) - { - ((LLMenuItemGL*)viewp)->doIt(); - LLMenuGL::setKeyboardMode(FALSE); - } - LLMenuGL::setKeyboardMode(FALSE); - } + handled = item->handleMouseUp( 0, 0, mask ); + hide(); } - - if (handled) + } + else if (!mRightMouseDown) + { + // if shift is held, click is in the view, and a parent menu exists, go back up + if (mask & MASK_SHIFT && pointInView(x, y)) { - // set hover false on inactive menus - for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) + if (LLMenuItemGL* branch = getParentMenuItem()) { - LLView* viewp = *child_it; - S32 local_x = x - viewp->getRect().mLeft; - S32 local_y = y - viewp->getRect().mBottom; - if (!viewp->pointInView(local_x, local_y) && ((LLMenuItemGL*)viewp)->getHighlight()) + if (LLContextMenu* parent = dynamic_cast(branch->getParent())) { - ((LLMenuItemGL*)viewp)->setHighlight(FALSE); + hide(); + parent->show(LLMenuHolderGL::sContextMenuSpawnPos.mX, LLMenuHolderGL::sContextMenuSpawnPos.mY, false); + return true; } } } + // call hidemenus to make sure transient selections get cleared + sMenuContainer->hideMenus(); } - getWindow()->setCursor(UI_CURSOR_ARROW); - - return TRUE; -} - -///============================================================================ -/// Class LLMenuHolderGL -///============================================================================ -LLCoordGL LLMenuHolderGL::sContextMenuSpawnPos(S32_MAX, S32_MAX); -LLMenuHolderGL::LLMenuHolderGL() - : LLPanel(std::string("Menu Holder")) -{ - setMouseOpaque(FALSE); - sItemActivationTimer.stop(); - mCanHide = TRUE; -} - -LLMenuHolderGL::LLMenuHolderGL(const std::string& name, const LLRect& rect, BOOL mouse_opaque, U32 follows) -: LLPanel(name, rect, FALSE) -{ - setMouseOpaque(mouse_opaque); - sItemActivationTimer.stop(); - mCanHide = TRUE; -} - - -void LLMenuHolderGL::draw() -{ - LLView::draw(); - // now draw last selected item as overlay - LLMenuItemGL* selecteditem = (LLMenuItemGL*)sItemLastSelectedHandle.get(); - if (selecteditem && selecteditem->getVisible() && sItemActivationTimer.getStarted() && sItemActivationTimer.getElapsedTimeF32() < ACTIVATE_HIGHLIGHT_TIME) + if (handled) { - // make sure toggle items, for example, show the proper state when fading out - selecteditem->buildDrawLabel(); - - LLRect item_rect; - selecteditem->localRectToOtherView(selecteditem->getLocalRect(), &item_rect, this); - - F32 interpolant = sItemActivationTimer.getElapsedTimeF32() / ACTIVATE_HIGHLIGHT_TIME; - F32 alpha = lerp(LLMenuItemGL::sHighlightBackground.mV[VALPHA], 0.f, interpolant); - LLColor4 bg_color(LLMenuItemGL::sHighlightBackground.mV[VRED], - LLMenuItemGL::sHighlightBackground.mV[VGREEN], - LLMenuItemGL::sHighlightBackground.mV[VBLUE], - alpha); - - LLUI::pushMatrix(); - { - LLUI::translate((F32)item_rect.mLeft, (F32)item_rect.mBottom, 0.f); - selecteditem->getMenu()->drawBackground(selecteditem, bg_color); - selecteditem->draw(); - } - LLUI::popMatrix(); + make_ui_sound("UISndClickRelease"); } -} -BOOL LLMenuHolderGL::handleMouseDown( S32 x, S32 y, MASK mask ) -{ - BOOL handled = LLView::childrenHandleMouseDown(x, y, mask) != NULL; - if (!handled) + if (!handled && !mUseInfiniteRadius) { - // clicked off of menu, hide them all - hideMenus(); + // call hidemenus to make sure transient selections get cleared + sMenuContainer->hideMenus(); } - return handled; -} -BOOL LLMenuHolderGL::handleRightMouseDown( S32 x, S32 y, MASK mask ) -{ - BOOL handled = LLView::childrenHandleRightMouseDown(x, y, mask) != NULL; - if (!handled) + if (mFirstMouseDown) { - // clicked off of menu, hide them all - hideMenus(); + make_ui_sound("UISndPieMenuAppear"); + mFirstMouseDown = FALSE; + } + + // *FIX: is this necessary? + if (!mShrinkBorderTimer.getStarted()) + { + mShrinkBorderTimer.start(); } + return handled; } -// This occurs when you mouse-down to spawn a context menu, hold the button -// down, move off the menu, then mouse-up. We want this to close the menu. -BOOL LLMenuHolderGL::handleRightMouseUp( S32 x, S32 y, MASK mask ) + +// virtual +void LLPieMenu::draw() { - const S32 SLOP = 2; - S32 spawn_dx = (x - sContextMenuSpawnPos.mX); - S32 spawn_dy = (y - sContextMenuSpawnPos.mY); - if (-SLOP <= spawn_dx && spawn_dx <= SLOP - && -SLOP <= spawn_dy && spawn_dy <= SLOP) + // clear hover if mouse moved away + if (!mHoverThisFrame && mHoverItem) { - // we're still inside the slop region from spawning this menu - // so interpret the mouse-up as a single-click to show and leave on - // screen - sContextMenuSpawnPos.set(S32_MAX, S32_MAX); - return TRUE; + mHoverItem->setHighlight(FALSE); + mHoverItem = NULL; + mHoverIndex = -1; } - BOOL handled = LLView::childrenHandleRightMouseUp(x, y, mask) != NULL; - if (!handled) + const auto& rect = getRect(); + // correct for non-square pixels + F32 center_x = ((F32) rect.getWidth())/2; + F32 center_y = ((F32) rect.getHeight())/2; + constexpr S32 steps = 100; + mCurRadius = PIE_SCALE_FACTOR * llmax(center_x, center_y); + + mOuterRingAlpha = mUseInfiniteRadius ? 0.f : 1.f; + if (mShrinkBorderTimer.getStarted()) { - // clicked off of menu, hide them all - hideMenus(); + const auto& elapsed = mShrinkBorderTimer.getElapsedTimeF32(); + mOuterRingAlpha = clamp_rescale(elapsed, 0.f, PIE_SHRINK_TIME, 0.f, 1.f); + mCurRadius *= clamp_rescale(elapsed, 0.f, PIE_SHRINK_TIME, 1.f, 1.f / PIE_SCALE_FACTOR); } - return handled; -} -BOOL LLMenuHolderGL::handleKey(KEY key, MASK mask, BOOL called_from_parent) -{ - BOOL handled = false; - LLMenuGL* const pMenu = dynamic_cast(getVisibleMenu()); - - if (pMenu) + + gGL.pushUIMatrix(); { - //eat TAB key - EXT-7000 - if (key == KEY_TAB && mask == MASK_NONE) - { - return TRUE; - } + gGL.translateUI(center_x, center_y, 0.f); - //handle ESCAPE and RETURN key - handled = LLPanel::handleKey(key, mask, called_from_parent); - if (!handled) + static const LLUICachedControl line_width("PieMenuLineWidth"); + static const LLCachedControl line_color(*LLUI::sColorsGroup, "PieMenuLineColor"); + static const LLCachedControl bg_color(*LLUI::sColorsGroup, "PieMenuBgColor"); + static const LLCachedControl selected_color(*LLUI::sColorsGroup, "PieMenuSelectedColor"); + + // main body + LLColor4 outer_color = bg_color; + outer_color.mV[VALPHA] *= mOuterRingAlpha; + gl_washer_2d( mCurRadius, (F32) PIE_CENTER_SIZE, steps, bg_color, outer_color ); + + // selected wedge + if (mHoverItem) { - if (pMenu->getHighlightedItem()) - { - handled = pMenu->handleKey(key, mask, TRUE); - } - else - { - //highlight first enabled one - if(pMenu->highlightNextItem(NULL)) - { - handled = true; - } - } + constexpr F32 arc_size = F_PI * 0.25f; + + F32 start_radians = (mHoverIndex * arc_size) - (arc_size * 0.5f); + F32 end_radians = start_radians + arc_size; + + LLColor4 outer_color = selected_color; + outer_color.mV[VALPHA] *= mOuterRingAlpha; + gl_washer_segment_2d( mCurRadius, (F32)PIE_CENTER_SIZE, start_radians, end_radians, steps / 8, selected_color, outer_color ); } + + LLUI::setLineWidth( line_width ); + + // inner lines + outer_color = line_color; + outer_color.mV[VALPHA] *= mOuterRingAlpha; + gl_washer_spokes_2d( mCurRadius, (F32)PIE_CENTER_SIZE, 8, line_color, outer_color ); + + // inner circle + gGL.color4fv( line_color().mV ); + gl_circle_2d( 0, 0, (F32)PIE_CENTER_SIZE, steps, FALSE ); + + // outer circle + gGL.color4fv( outer_color.mV ); + gl_circle_2d( 0, 0, mCurRadius, steps, FALSE ); + + LLUI::setLineWidth(1.0f); } - - return handled; - + gGL.popUIMatrix(); + + mHoverThisFrame = FALSE; + + LLView::draw(); } -void LLMenuHolderGL::reshape(S32 width, S32 height, BOOL called_from_parent) +// virtual +void LLPieMenu::drawBackground(LLMenuItemGL*, LLColor4&) { - if (width != getRect().getWidth() || height != getRect().getHeight()) - { - hideMenus(); - } - LLView::reshape(width, height, called_from_parent); + // Selection is drawn in our draw call, do nothing here and override base drawing rectangles. } -LLView* const LLMenuHolderGL::getVisibleMenu() const +// virtual +BOOL LLPieMenu::append(LLMenuItemGL *item) { - for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) - { - LLView* viewp = *child_it; - if (viewp->getVisible() && dynamic_cast(viewp) != NULL && !dynamic_cast(viewp)) - { - return viewp; - } - } - return NULL; + item->setBriefItem(TRUE); + item->setFont( LLFontGL::getFontSansSerifSmall() ); + return LLMenuGL::append(item); } +// virtual +BOOL LLPieMenu::addSeparator(const std::string& name) +{ + return append(new LLMenuItemBlankGL(name)); +} -BOOL LLMenuHolderGL::hideMenus() +// virtual +void LLPieMenu::arrange() { - if (!mCanHide) - { - return FALSE; - } + // all divide by 6 + const S32 CARD_X = 60; + const S32 DIAG_X = 48; + const S32 CARD_Y = 76; + const S32 DIAG_Y = 42; - sItemActivationTimer.stop(); + const S32 ITEM_CENTER_X[] = { CARD_X, DIAG_X, 0, -DIAG_X, -CARD_X, -DIAG_X, 0, DIAG_X }; + const S32 ITEM_CENTER_Y[] = { 0, DIAG_Y, CARD_Y, DIAG_Y, 0, -DIAG_Y, -CARD_Y, -DIAG_Y }; - BOOL menu_visible = hasVisibleMenu(); - if (menu_visible) + S32 font_height = 0; + if( mItems.size() ) { - LLMenuGL::setKeyboardMode(FALSE); - // clicked off of menu, hide them all - for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) - { - LLView* viewp = *child_it; - if (dynamic_cast(viewp) != NULL && viewp->getVisible() && !dynamic_cast(viewp)) - { - viewp->setVisible(FALSE); - } - } + font_height = (*mItems.begin())->getNominalHeight(); } - //if (gFocusMgr.childHasKeyboardFocus(this)) - //{ - // gFocusMgr.setKeyboardFocus(NULL); - //} + S32 item_width = 0; - return menu_visible; -} +// F32 sin_delta = OO_SQRT2; // sin(45 deg) +// F32 cos_delta = OO_SQRT2; // cos(45 deg) -void LLMenuHolderGL::setActivatedItem(LLMenuItemGL* item) -{ - sItemLastSelectedHandle = item->getHandle(); - sItemActivationTimer.start(); -} + // TODO: Compute actual bounding rect for menu -///============================================================================ -/// Class LLTearOffMenu -///============================================================================ -LLTearOffMenu::LLTearOffMenu(LLMenuGL* menup) : - LLFloater(menup->getName(), LLRect(0, 100, 100, 0), menup->getLabel(), FALSE, DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT, FALSE, FALSE) -{ - S32 floater_header_size = LLFLOATER_HEADER_SIZE; + LLRect rect = getRect(); - setName(menup->getName()); - setTitle(menup->getLabel()); - setCanMinimize(FALSE); - // flag menu as being torn off - menup->setTornOff(TRUE); - // update menu layout as torn off menu (no spillover menus) - menup->needsArrange(); + // place items around a circle, with item 0 at positive X, + // rotating counter-clockwise + item_list_t::iterator item_iter; + S32 i = 0; + for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter) + { + LLMenuItemGL *item = *item_iter; - LLRect rect; - menup->localRectToOtherView(LLRect(-1, menup->getRect().getHeight(), menup->getRect().getWidth() + 3, 0), &rect, gFloaterView); - // make sure this floater is big enough for menu - mTargetHeight = (F32)(rect.getHeight() + floater_header_size); - reshape(rect.getWidth(), rect.getHeight()); - setRect(rect); + item_width = item->getNominalWidth(); - // attach menu to floater - menup->setFollows(FOLLOWS_BOTTOM|FOLLOWS_LEFT); - mOldParent = menup->getParent(); - addChild(menup); - menup->setVisible(TRUE); - - LLRect menu_rect = menup->getRect(); - menu_rect.setOriginAndSize( 1, 1, - menu_rect.getWidth(), menu_rect.getHeight()); - menup->setRect(menu_rect); - menup->setDropShadowed(FALSE); + // Put in the right place around a circle centered at 0,0 + rect.setCenterAndSize(ITEM_CENTER_X[i], + ITEM_CENTER_Y[i], + item_width, font_height ); - mMenu = menup; + // Correct for the actual rectangle size + rect.translate( getRect().getWidth()/2, getRect().getHeight()/2 ); - // highlight first item (tear off item will be disabled) - mMenu->highlightNextItem(NULL); -} + item->setRect( rect ); + // Make sure enablement is correct + item->buildDrawLabel(); + i++; + } +} -void LLTearOffMenu::draw() +LLMenuItemGL *LLPieMenu::pieItemFromXY(S32 x, S32 y) { - mMenu->setBackgroundVisible(isBackgroundOpaque()); - mMenu->needsArrange(); - - if (getRect().getHeight() != mTargetHeight) - { - // animate towards target height - reshape(getRect().getWidth(), llceil(lerp((F32)getRect().getHeight(), mTargetHeight, LLCriticalDamp::getInterpolant(0.05f)))); - } - LLFloater::draw(); + return pieItemFromIndex(pieItemIndexFromXY(x, y)); } -void LLTearOffMenu::onFocusReceived() +S32 LLPieMenu::pieItemIndexFromXY(S32 x, S32 y) { - // if nothing is highlighted, just highlight first item - if (!mMenu->getHighlightedItem()) + // An arc of the pie menu is 45 degrees + const F32 ARC_DEG = 45.f; + + // correct for non-square pixels + S32 delta_x = x - getRect().getWidth() / 2; + S32 delta_y = y - getRect().getHeight() / 2; + + // circle safe zone in the center + S32 dist_squared = delta_x*delta_x + delta_y*delta_y; + if (dist_squared < PIE_CENTER_SIZE*PIE_CENTER_SIZE) { - mMenu->highlightNextItem(NULL); + return -1; } - // parent menu items get highlights so navigation logic keeps working - LLMenuItemGL* parent_menu_item = mMenu->getParentMenuItem(); - while(parent_menu_item) + // infinite radius is only used with right clicks + S32 radius = llmax( getRect().getWidth()/2, getRect().getHeight()/2 ); + if (!(mUseInfiniteRadius && mRightMouseDown) && dist_squared > radius * radius) { - if (parent_menu_item->getMenu()->getVisible()) - { - parent_menu_item->setHighlight(TRUE); - parent_menu_item = parent_menu_item->getMenu()->getParentMenuItem(); - } - else - { - break; - } + return -1; } - LLFloater::onFocusReceived(); -} -void LLTearOffMenu::onFocusLost() -{ - // remove highlight from parent item and our own menu - mMenu->clearHoverItem(); - LLFloater::onFocusLost(); -} + F32 angle = RAD_TO_DEG * (F32) atan2((F32)delta_y, (F32)delta_x); -BOOL LLTearOffMenu::handleUnicodeChar(llwchar uni_char, BOOL called_from_parent) -{ - // pass keystrokes down to menu - return mMenu->handleUnicodeChar(uni_char, TRUE); + // rotate marks CCW so that east = [0, ARC_DEG) instead of + // [-ARC_DEG/2, ARC_DEG/2) + angle += ARC_DEG / 2.f; + + // make sure we're only using positive angles + if (angle < 0.f) angle += 360.f; + + return S32( angle / ARC_DEG ); } -BOOL LLTearOffMenu::handleKeyHere(KEY key, MASK mask) +LLMenuItemGL* LLPieMenu::pieItemFromIndex(S32 which) { - if (!mMenu->getHighlightedItem()) + if (0 <= which && which < (S32)mItems.size() ) { - if (key == KEY_UP) - { - mMenu->highlightPrevItem(NULL); - return TRUE; - } - else if (key == KEY_DOWN) + item_list_t::iterator item_iter; + for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter) { - mMenu->highlightNextItem(NULL); - return TRUE; + if (which == 0) + { + return (*item_iter)->getVisible() ? (*item_iter) : NULL; + } + --which; } } - // pass keystrokes down to menu - return mMenu->handleKey(key, mask, TRUE); -} -void LLTearOffMenu::translate(S32 x, S32 y) -{ - if (x != 0 && y != 0) - { - // hide open sub-menus by clearing current hover item - mMenu->clearHoverItem(); - } - LLFloater::translate(x, y); + return NULL; } -//static -LLTearOffMenu* LLTearOffMenu::create(LLMenuGL* menup) + +// virtual +void LLPieMenu::show(S32 x, S32 y, bool mouse_down) { - LLTearOffMenu* tearoffp = new LLTearOffMenu(menup); - // keep onscreen - gFloaterView->adjustToFitScreen(tearoffp, FALSE); - tearoffp->open(); /* Flawfinder: ignore */ + LLContextMenu::show(x, y, false); - return tearoffp; + // *FIX: what happens when mouse buttons reversed? + mRightMouseDown = mouse_down; + mFirstMouseDown = mouse_down; + mUseInfiniteRadius = TRUE; + mHoveredAnyItem = FALSE; + + if (!mFirstMouseDown) make_ui_sound("UISndPieMenuAppear"); + + // we want all mouse events in case user does quick right click again off of pie menu + // rectangle, to support gestural menu traversal + gFocusMgr.setMouseCapture(this); + + mouse_down ? mShrinkBorderTimer.stop() : mShrinkBorderTimer.start(); } -void LLTearOffMenu::onClose(bool app_quitting) +// virtual +void LLPieMenu::hide() { - removeChild(mMenu); - mOldParent->addChild(mMenu); - mMenu->clearHoverItem(); - mMenu->setFollowsNone(); - mMenu->setBackgroundVisible(TRUE); - mMenu->setVisible(FALSE); - mMenu->setTornOff(FALSE); - mMenu->setDropShadowed(TRUE); - destroy(); + LLContextMenu::hide(); + make_ui_sound("UISndPieMenuHide"); + + mFirstMouseDown = FALSE; + mRightMouseDown = FALSE; + mUseInfiniteRadius = FALSE; + mHoveredAnyItem = FALSE; + + gFocusMgr.setMouseCapture(NULL); } diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h index 07effab8dc..d63b294d80 100644 --- a/indra/llui/llmenugl.h +++ b/indra/llui/llmenugl.h @@ -47,7 +47,6 @@ extern S32 MENU_BAR_HEIGHT; -extern S32 MENU_BAR_WIDTH; // These callbacks are used by the LLMenuItemCallGL and LLMenuItemCheckGL // classes during their work. @@ -79,16 +78,6 @@ typedef void (*label_callback)(std::string&,void*); class LLMenuItemGL : public LLUICtrl { public: - // static functions to control the global color scheme. - /*static void setEnabledColor( const LLColor4& color ) { sEnabledColor = color; } - static const LLColor4& getEnabledColor() { return sEnabledColor; } - static void setDisabledColor( const LLColor4& color ) { sDisabledColor = color; } - static const LLColor4& getDisabledColor() { return sDisabledColor; } - static void setHighlightBGColor( const LLColor4& color ) { sHighlightBackground = color; } - static const LLColor4& getHighlightBGColor() { return sHighlightBackground; } - static void setHighlightFGColor( const LLColor4& color ) { sHighlightForeground = color; } - static const LLColor4& getHighlightFGColor() { return sHighlightForeground; }*/ - LLMenuItemGL( const std::string& name, const std::string& label, KEY key = KEY_NONE, MASK = MASK_NONE ); virtual ~LLMenuItemGL(); @@ -148,7 +137,7 @@ class LLMenuItemGL : public LLUICtrl // lead to visual errors if the state of the object changes // without the knowledge of the menu item. For example, if a // boolean being watched is changed outside of the menu item's - // doIt() function, the draw buffer will not be updated and will + // onCommit() function, the draw buffer will not be updated and will // reflect the wrong value. If this ever becomes an issue, there // are ways to fix this. // Returns the enabled state of the item. @@ -157,8 +146,7 @@ class LLMenuItemGL : public LLUICtrl // for branching menu items, bring sub menus up to root level of menu hierarchy virtual void updateBranchParent( LLView* parentp ){}; - // doIt() - do the primary funcationality of the menu item. - virtual void doIt( void ); + virtual void onCommit( void ); virtual void setHighlight( BOOL highlight ); virtual BOOL getHighlight() const { return mHighlight; } @@ -190,6 +178,7 @@ class LLMenuItemGL : public LLUICtrl // the current accelerator key and mask to the provided string. void appendAcceleratorString( std::string& st ) const; +protected: KEY mAcceleratorKey; MASK mAcceleratorMask; // mLabel contains the actual label specified by the user. @@ -245,15 +234,14 @@ class LLMenuItemSeparatorGL : public LLMenuItemGL virtual std::string getType() const { return "separator"; } - // doIt() - do the primary funcationality of the menu item. - virtual void doIt( void ) {} + virtual void onCommit( void ) {} - virtual void draw( void ); - virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); - virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); - virtual BOOL handleHover(S32 x, S32 y, MASK mask); + /*virtual*/ void draw( void ); + /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); - virtual U32 getNominalHeight( void ) const; + /*virtual*/ U32 getNominalHeight( void ) const; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -323,8 +311,7 @@ class LLMenuItemCallGL : public LLMenuItemGL, public LLOldEvents::LLObservable // called to rebuild the draw label virtual void buildDrawLabel( void ); - // doIt() - do the primary funcationality of the menu item. - virtual void doIt( void ); + virtual void onCommit( void ); virtual BOOL handleAcceleratorKey(KEY key, MASK mask); virtual BOOL handleKeyHere(KEY key, MASK mask); @@ -419,8 +406,8 @@ class LLMenuItemToggleGL : public LLMenuItemGL // called to rebuild the draw label virtual void buildDrawLabel( void ); - // doIt() - do the primary funcationality of the menu item. - virtual void doIt( void ); + // onCommit() - do the primary funcationality of the menu item. + virtual void onCommit( void ); // LLView Functionality //virtual void draw( void ); @@ -429,7 +416,6 @@ class LLMenuItemToggleGL : public LLMenuItemGL BOOL* mToggle; }; - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLMenuGL // @@ -453,6 +439,15 @@ class LLMenuGL static const std::string ARROW_UP; static const std::string ARROW_DOWN; + // for scrollable menus + typedef enum e_scrolling_direction + { + SD_UP = 0, + SD_DOWN = 1, + SD_BEGIN = 2, + SD_END = 3 + } EScrollingDirection; + protected: // let branching menu items use my protected traversal methods friend class LLMenuItemBranchGL; @@ -462,22 +457,21 @@ class LLMenuGL virtual ~LLMenuGL( void ); virtual LLXMLNodePtr getXML(bool save_children = true) const; static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); + void initMenuXML(LLXMLNodePtr node, LLView* parent); - void parseChildXML(LLXMLNodePtr child, LLView *parent, LLUICtrlFactory *factory); + void parseChildXML(LLXMLNodePtr child, LLView *parent); // LLView Functionality /*virtual*/ BOOL handleUnicodeCharHere( llwchar uni_char ); /*virtual*/ BOOL handleHover( S32 x, S32 y, MASK mask ); /*virtual*/ BOOL handleScrollWheel( S32 x, S32 y, S32 clicks ); /*virtual*/ void draw( void ); - virtual void drawBackground(LLMenuItemGL* itemp, LLColor4& color); + /*virtual*/ void drawBackground(LLMenuItemGL* itemp, LLColor4& color); /*virtual*/ void setVisible(BOOL visible); /*virtual*/ bool addChild(LLView* view, S32 tab_group = 0); /*virtual*/ void removeChild( LLView* ctrl); /*virtual*/ BOOL postBuild(); - bool addChild(LLView* view, LLView* insert_before, S32 tab_group = 0); - virtual BOOL handleAcceleratorKey(KEY key, MASK mask); LLMenuGL* getChildMenuByName(const std::string& name, BOOL recurse) const; @@ -496,7 +490,7 @@ class LLMenuGL void setCanTearOff(BOOL tear_off); // add a separator to this menu - virtual BOOL addSeparator(); + virtual BOOL addSeparator(const std::string& name = LLStringUtil::null); // for branching menu items, bring sub menus up to root level of menu hierarchy virtual void updateParent( LLView* parentp ); @@ -531,8 +525,33 @@ class LLMenuGL // remove all items on the menu void empty( void ); + // erase group of items from menu + void erase(S32 begin, S32 end, bool arrange = true); + typedef std::list item_list_t; + inline item_list_t::iterator erase(item_list_t::const_iterator first, item_list_t::const_iterator last) + { + for (auto it = first; it != last; ++it) + LLUICtrl::removeChild(*it); + return mItems.erase(first, last); + } + + // add new item at position + void insert(S32 begin, LLView* ctrl, bool arrange = true); + void insert(item_list_t::const_iterator position_iter, LLMenuItemGL* item, bool arrange = true); + + // find an item's position + item_list_t::const_iterator find(LLMenuItemGL* item) const { return std::find(mItems.begin(), mItems.end(), item); } + + // end of items, for use with other members that return an iterator + item_list_t::const_iterator end() const { return mItems.cend(); } + + // get list of items + const item_list_t& getItems() const { return mItems; } + + // number of menu items + item_list_t::size_type getItemCount() const { return mItems.size(); } + void setItemLastSelected(LLMenuItemGL* item); // must be in menu - U32 getItemCount(); // number of menu items LLMenuItemGL* getItem(S32 number); // 0 = first item LLMenuItemGL* getHighlightedItem(); @@ -545,7 +564,7 @@ class LLMenuGL // Show popup in global screen space based on last mouse location. static void showPopup(LLMenuGL* menu); - // Show popup at a specific location. + // Show popup at a specific location, in the spawn_view's coordinate frame static void showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y); // Whether to drop shadow menu bar @@ -566,27 +585,31 @@ class LLMenuGL static BOOL getKeyboardMode() { return sKeyboardMode; } S32 getShortcutPad() { return mShortcutPad; } - BOOL isScrollable() const { return FALSE; } + + bool scrollItems(EScrollingDirection direction); + BOOL isScrollable() const { return mScrollable; } + void setScrollable(bool b); static class LLMenuHolderGL* sMenuContainer; - bool isScrollPositionOnShowReset() { return false; } + void resetScrollPositionOnShow(bool reset_scroll_pos) { mResetScrollPositionOnShow = reset_scroll_pos; } + bool isScrollPositionOnShowReset() { return mResetScrollPositionOnShow; } protected: void createSpilloverBranch(); void cleanupSpilloverBranch(); +public: // Add the menu item to this menu. virtual BOOL append( LLMenuItemGL* item ); - BOOL append(LLMenuItemGL* item, LLView* insert_before); // add a menu - this will create a cascading menu virtual BOOL appendMenu( LLMenuGL* menu ); - BOOL appendMenu(LLMenuGL* menu, LLView* insert_before); - // TODO: create accessor methods for these? - typedef std::list< LLMenuItemGL* > item_list_t; +protected: item_list_t mItems; + // TODO: create accessor methods for these? LLMenuItemGL*mFirstVisibleItem; + LLMenuItemGL *mArrowUpItem, *mArrowDownItem; typedef std::map navigation_key_map_t; navigation_key_map_t mJumpKeys; @@ -594,11 +617,15 @@ class LLMenuGL S32 mLastMouseY; S32 mMouseVelX; S32 mMouseVelY; + U32 mMaxScrollableItems; BOOL mHorizontalLayout; + BOOL mScrollable; BOOL mKeepFixedSize; BOOL mNeedsArrange; private: + + static LLColor4 sDefaultBackgroundColor; static BOOL sKeyboardMode; @@ -609,12 +636,15 @@ class LLMenuGL BOOL mDropShadowed; // Whether to drop shadow bool mHasSelection; LLFrameTimer mFadeTimer; + LLTimer mScrollItemsTimer; BOOL mTornOff; class LLMenuItemTearOffGL* mTearOffItem; class LLMenuItemBranchGL* mSpilloverBranch; LLMenuGL* mSpilloverMenu; KEY mJumpKey; + BOOL mCreateJumpKeys; S32 mShortcutPad; + bool mResetScrollPositionOnShow; }; // end class LLMenuGL @@ -648,8 +678,7 @@ class LLMenuItemBranchGL : public LLMenuItemGL // called to rebuild the draw label virtual void buildDrawLabel( void ); - // doIt() - do the primary funcationality of the menu item. - virtual void doIt( void ); + virtual void onCommit( void ); virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); virtual BOOL handleUnicodeChar(llwchar uni_char, BOOL called_from_parent); @@ -684,6 +713,43 @@ class LLMenuItemBranchGL : public LLMenuItemGL }; // end class LLMenuItemBranchGL +//----------------------------------------------------------------------------- +// class LLContextMenu +// A context menu +//----------------------------------------------------------------------------- + +class LLContextMenu +: public LLMenuGL +{ +public: + LLContextMenu(const std::string& name, const std::string& label = ""); + + virtual LLXMLNodePtr getXML(bool save_children = true) const; + void initXML(LLXMLNodePtr node, LLView* context, LLUICtrlFactory* factory, bool is_context); + +public: + virtual ~LLContextMenu() {} + + // LLView Functionality + // can't set visibility directly, must call show or hide + virtual void setVisible(BOOL visible); + + virtual void show(S32 x, S32 y, bool context = true); + virtual void hide(); + + virtual BOOL handleHover( S32 x, S32 y, MASK mask ); + BOOL handleHoverOver(LLMenuItemGL* item, S32 x, S32 y); // Singu Note: Unify common functionality between Pie and Context hover behaviors + virtual BOOL handleRightMouseDown( S32 x, S32 y, MASK mask ); + virtual BOOL handleRightMouseUp( S32 x, S32 y, MASK mask ); + + virtual bool addChild(LLView* view, S32 tab_group = 0); + + BOOL appendContextSubMenu(LLContextMenu* menu); + +protected: + BOOL mHoveredAnyItem; + LLMenuItemGL* mHoverItem; +}; //----------------------------------------------------------------------------- // class LLPieMenu @@ -691,23 +757,16 @@ class LLMenuItemBranchGL : public LLMenuItemGL //----------------------------------------------------------------------------- class LLPieMenu -: public LLMenuGL +: public LLContextMenu { public: - LLPieMenu(const std::string& name, const std::string& label); - LLPieMenu(const std::string& name); + LLPieMenu(const std::string& name, const std::string& label = ""); virtual ~LLPieMenu() {} - virtual LLXMLNodePtr getXML(bool save_children = true) const; - void initXML(LLXMLNodePtr node, LLView *context, LLUICtrlFactory *factory); - // LLView Functionality // hide separators. they are added to 'pad' in empty cells. virtual bool addChild(LLView* view, S32 tab_group = 0); - // can't set visibility directly, must call show or hide - virtual void setVisible(BOOL visible); - virtual BOOL handleHover( S32 x, S32 y, MASK mask ); virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask ); virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); @@ -719,36 +778,61 @@ class LLPieMenu private: virtual BOOL append(LLMenuItemGL* item); public: - virtual BOOL addSeparator(); - - BOOL appendPieMenu(LLPieMenu *menu); + virtual BOOL addSeparator(const std::string& name = LLStringUtil::null) override final; virtual void arrange( void ); // Display the menu centered on this point on the screen. - void show(S32 x, S32 y, BOOL mouse_down); - void hide(BOOL item_selected); + /*virtual*/ void show(S32 x, S32 y, bool mouse_down = true); + /*virtual*/ void hide(); private: LLMenuItemGL *pieItemFromXY(S32 x, S32 y); + LLMenuItemGL* pieItemFromIndex(S32 which); S32 pieItemIndexFromXY(S32 x, S32 y); - // These cause menu items to be spuriously selected by right-clicks - // near the window edge at low frame rates. I don't think they are - // needed unless you shift the menu position in the draw() function. JC - //S32 mShiftHoriz; // non-zero if menu had to shift this frame - //S32 mShiftVert; // non-zero if menu had to shift this frame BOOL mFirstMouseDown; // true from show until mouse up BOOL mUseInfiniteRadius; // allow picking pie menu items anywhere outside of center circle - LLMenuItemGL* mHoverItem; + S32 mHoverIndex; BOOL mHoverThisFrame; - BOOL mHoveredAnyItem; LLFrameTimer mShrinkBorderTimer; F32 mOuterRingAlpha; // for rendering pie menus as both bounded and unbounded F32 mCurRadius; BOOL mRightMouseDown; }; +//----------------------------------------------------------------------------- +// class LLContextMenuBranch +// A branch to another context menu +//----------------------------------------------------------------------------- +class LLContextMenuBranch : public LLMenuItemGL +{ +public: + LLContextMenuBranch(const std::string& name, const std::string& label, LLContextMenu* branch); + + virtual LLXMLNodePtr getXML(bool save_children = true) const; + + // called to rebuild the draw label + virtual void buildDrawLabel( void ); + + virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask) + { + LLMenuItemGL::handleMouseUp(x,y,mask); + return TRUE; + } + + // onCommit() - do the primary funcationality of the menu item. + virtual void onCommit( void ); + + LLContextMenu* getBranch() { return mBranch; } + void setHighlight( BOOL highlight ); + +protected: + void showSubMenu(); + + LLContextMenu* mBranch; +}; + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLMenuBarGL @@ -774,7 +858,7 @@ class LLMenuBarGL : public LLMenuGL /*virtual*/ BOOL jumpKeysActive(); // add a vertical separator to this menu - virtual BOOL addSeparator(); + virtual BOOL addSeparator(const std::string& name = LLStringUtil::null) override final; // LLView Functionality virtual BOOL handleHover( S32 x, S32 y, MASK mask ); @@ -826,6 +910,7 @@ class LLMenuHolderGL : public LLPanel LLView*const getVisibleMenu() const; virtual BOOL hasVisibleMenu() const {return getVisibleMenu() != NULL;} + static LLMenuItemGL* getActivatedItem() { return static_cast(sItemLastSelectedHandle.get()); } static void setActivatedItem(LLMenuItemGL* item); // Need to detect if mouse-up after context menu spawn has moved. @@ -849,7 +934,8 @@ class LLTearOffMenu : public LLFloater { public: static LLTearOffMenu* create(LLMenuGL* menup); - virtual ~LLTearOffMenu() {} + virtual ~LLTearOffMenu(); + virtual void onClose(bool app_quitting); virtual void draw(void); virtual void onFocusReceived(); @@ -880,7 +966,7 @@ class LLMenuItemTearOffGL : public LLMenuItemGL virtual LLXMLNodePtr getXML(bool save_children = true) const; virtual std::string getType() const { return "tearoff_menu"; } - virtual void doIt(void); + virtual void onCommit(void); virtual void draw(void); virtual U32 getNominalHeight() const; diff --git a/indra/llui/llmodaldialog.cpp b/indra/llui/llmodaldialog.cpp index 8c8f94113a..8d7b0fdbf4 100644 --- a/indra/llui/llmodaldialog.cpp +++ b/indra/llui/llmodaldialog.cpp @@ -73,7 +73,7 @@ LLModalDialog::~LLModalDialog() std::list::iterator iter = std::find(sModalStack.begin(), sModalStack.end(), this); if (iter != sModalStack.end()) { - llerrs << "Attempt to delete dialog while still in sModalStack!" << llendl; + LL_ERRS() << "Attempt to delete dialog while still in sModalStack!" << LL_ENDL; } } @@ -115,7 +115,7 @@ void LLModalDialog::startModal() if (iter != sModalStack.end()) { sModalStack.erase(iter); - llwarns << "Dialog already on modal stack" << llendl; + LL_WARNS() << "Dialog already on modal stack" << LL_ENDL; //TODO: incvestigate in which specific cases it happens, cause that's not good! -SG } @@ -139,7 +139,7 @@ void LLModalDialog::stopModal() } else { - llwarns << "LLModalDialog::stopModal not in list!" << llendl; + LL_WARNS() << "LLModalDialog::stopModal not in list!" << LL_ENDL; } } if (!sModalStack.empty()) @@ -194,7 +194,7 @@ BOOL LLModalDialog::handleHover(S32 x, S32 y, MASK mask) if( childrenHandleHover(x, y, mask) == NULL ) { getWindow()->setCursor(UI_CURSOR_ARROW); - lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << llendl; + LL_DEBUGS("UserInput") << "hover handled by " << getName() << LL_ENDL; } return TRUE; } @@ -292,7 +292,7 @@ void LLModalDialog::draw() void LLModalDialog::centerOnScreen() { LLVector2 window_size = LLUI::getWindowSize(); - centerWithin(LLRect(0, 0, llround(window_size.mV[VX]), llround(window_size.mV[VY]))); + centerWithin(LLRect(0, 0, ll_round(window_size.mV[VX]), ll_round(window_size.mV[VY]))); } diff --git a/indra/llui/llmultifloater.cpp b/indra/llui/llmultifloater.cpp index 07b811f71a..a15a1ec5f1 100644 --- a/indra/llui/llmultifloater.cpp +++ b/indra/llui/llmultifloater.cpp @@ -187,7 +187,8 @@ BOOL LLMultiFloater::closeAllFloaters() //Tab did not actually close, possibly due to a pending Save Confirmation dialog.. //so try and close the next one in the list... tabToClose++; - }else + } + else { //Tab closed ok. lastTabCount = mTabContainer->getTabCount(); @@ -238,7 +239,7 @@ void LLMultiFloater::addFloater(LLFloater* floaterp, BOOL select_added_floater, if (!mTabContainer) { - llerrs << "Tab Container used without having been initialized." << llendl; + LL_ERRS() << "Tab Container used without having been initialized." << LL_ENDL; return; } @@ -252,7 +253,7 @@ void LLMultiFloater::addFloater(LLFloater* floaterp, BOOL select_added_floater, else if (floaterp->getHost()) { // floaterp is hosted by somebody else and - // this is adding it, so remove it from it's old host + // this is adding it, so remove it from its old host floaterp->getHost()->removeFloater(floaterp); } else if (floaterp->getParent() == gFloaterView) @@ -302,8 +303,21 @@ void LLMultiFloater::addFloater(LLFloater* floaterp, BOOL select_added_floater, { floaterp->setVisible(FALSE); } + + // Tabs sometimes overlap resize handle + moveResizeHandlesToFront(); +} + +void LLMultiFloater::updateFloaterTitle(LLFloater* floaterp) +{ + S32 index = mTabContainer->getIndexForPanel(floaterp); + if (index != -1) + { + mTabContainer->setPanelTitle(index, floaterp->getShortTitle()); + } } + /** BOOL selectFloater(LLFloater* floaterp) @@ -329,8 +343,9 @@ void LLMultiFloater::selectPrevFloater() mTabContainer->selectPrevTab(); } -void LLMultiFloater::showFloater(LLFloater* floaterp) +void LLMultiFloater::showFloater(LLFloater* floaterp, LLTabContainer::eInsertionPoint insertion_point) { + if(!floaterp) return; // we won't select a panel that already is selected // it is hard to do this internally to tab container // as tab selection is handled via index and the tab at a given @@ -338,7 +353,7 @@ void LLMultiFloater::showFloater(LLFloater* floaterp) if (floaterp != mTabContainer->getCurrentPanel() && !mTabContainer->selectTabPanel(floaterp)) { - addFloater(floaterp, TRUE); + addFloater(floaterp, TRUE, insertion_point); } } @@ -417,6 +432,13 @@ BOOL LLMultiFloater::handleKeyHere(KEY key, MASK mask) if (floater && floater->canClose() && floater->isCloseable()) { floater->close(); + + // EXT-5695 (Tabbed IM window loses focus if close any tabs by Ctrl+W) + // bring back focus on tab container if there are any tab left + if(mTabContainer->getTabCount() > 0) + { + mTabContainer->setFocus(TRUE); + } } return TRUE; } @@ -468,12 +490,17 @@ void LLMultiFloater::setFloaterFlashing(LLFloater* floaterp, BOOL flashing) void LLMultiFloater::onTabSelected() { - tabOpen((LLFloater*)mTabContainer->getCurrentPanel()); + LLFloater* floaterp = dynamic_cast(mTabContainer->getCurrentPanel()); + if (floaterp) + { + tabOpen(floaterp); + } } void LLMultiFloater::setCanResize(BOOL can_resize) { LLFloater::setCanResize(can_resize); + if (!mTabContainer) return; if (isResizable() && mTabContainer->getTabPosition() == LLTabContainer::BOTTOM) { mTabContainer->setRightTabBtnOffset(RESIZE_HANDLE_WIDTH); @@ -510,16 +537,9 @@ void LLMultiFloater::updateResizeLimits() // initialize minimum size constraint to the original xml values. S32 new_min_width = mOrigMinWidth; S32 new_min_height = mOrigMinHeight; - // possibly increase minimum size constraint due to children's minimums. - for (S32 tab_idx = 0; tab_idx < mTabContainer->getTabCount(); ++tab_idx) - { - LLFloater* floaterp = (LLFloater*)mTabContainer->getPanelByIndex(tab_idx); - if (floaterp) - { - new_min_width = llmax(new_min_width, floaterp->getMinWidth() + LLPANEL_BORDER_WIDTH * 2); - new_min_height = llmax(new_min_height, floaterp->getMinHeight() + LLFLOATER_HEADER_SIZE + TABCNTR_HEADER_HEIGHT); - } - } + + computeResizeLimits(new_min_width, new_min_height); + setResizeLimits(new_min_width, new_min_height); S32 cur_height = getRect().getHeight(); @@ -545,3 +565,17 @@ void LLMultiFloater::updateResizeLimits() gFloaterView->adjustToFitScreen(this, TRUE); } } + +void LLMultiFloater::computeResizeLimits(S32& new_min_width, S32& new_min_height) +{ + // possibly increase minimum size constraint due to children's minimums. + for (S32 tab_idx = 0; tab_idx < mTabContainer->getTabCount(); ++tab_idx) + { + LLFloater* floaterp = (LLFloater*)mTabContainer->getPanelByIndex(tab_idx); + if (floaterp) + { + new_min_width = llmax(new_min_width, floaterp->getMinWidth() + LLPANEL_BORDER_WIDTH * 2); + new_min_height = llmax(new_min_height, floaterp->getMinHeight() + LLFLOATER_HEADER_SIZE + TABCNTR_HEADER_HEIGHT); + } + } +} diff --git a/indra/llui/llmultifloater.h b/indra/llui/llmultifloater.h index e56b387bc4..b18ff292ae 100644 --- a/indra/llui/llmultifloater.h +++ b/indra/llui/llmultifloater.h @@ -56,7 +56,7 @@ class LLMultiFloater : public LLFloater virtual void growToFit(S32 content_width, S32 content_height); virtual void addFloater(LLFloater* floaterp, BOOL select_added_floater, LLTabContainer::eInsertionPoint insertion_point = LLTabContainer::END); - virtual void showFloater(LLFloater* floaterp); + virtual void showFloater(LLFloater* floaterp, LLTabContainer::eInsertionPoint insertion_point = LLTabContainer::END); virtual void removeFloater(LLFloater* floaterp); virtual void tabOpen(LLFloater* opened_floater); @@ -76,6 +76,7 @@ class LLMultiFloater : public LLFloater void onTabSelected(); virtual void updateResizeLimits(); + virtual void updateFloaterTitle(LLFloater* floaterp); protected: struct LLFloaterData @@ -94,6 +95,9 @@ class LLMultiFloater : public LLFloater LLTabContainer::TabPosition mTabPos; BOOL mAutoResize; S32 mOrigMinWidth, mOrigMinHeight; // logically const but initialized late + +private: + virtual void computeResizeLimits(S32& new_min_width, S32& new_min_height); }; #endif // LL_MULTI_FLOATER_H diff --git a/indra/llui/llmultislider.cpp b/indra/llui/llmultislider.cpp index 183a1245fd..fa431d6766 100644 --- a/indra/llui/llmultislider.cpp +++ b/indra/llui/llmultislider.cpp @@ -288,7 +288,7 @@ bool LLMultiSlider::findUnusedValue(F32& initVal) // stop if it's filled if(initVal == mInitialValue && !firstTry) { - llwarns << "Whoa! Too many multi slider elements to add one to" << llendl; + LL_WARNS() << "Whoa! Too many multi slider elements to add one to" << LL_ENDL; return false; } @@ -343,12 +343,12 @@ BOOL LLMultiSlider::handleHover(S32 x, S32 y, MASK mask) onCommit(); getWindow()->setCursor(UI_CURSOR_ARROW); - lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (active)" << llendl; + LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (active)" << LL_ENDL; } else { getWindow()->setCursor(UI_CURSOR_ARROW); - lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (inactive)" << llendl; + LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (inactive)" << LL_ENDL; } return TRUE; } @@ -466,7 +466,7 @@ void LLMultiSlider::draw() F32 opacity = getEnabled() ? 1.f : 0.3f; // Track - LLUIImagePtr thumb_imagep = LLUI::getUIImage("rounded_square.tga"); + LLUIImagePtr thumb_imagep = LLUI::getUIImage("Rounded_Square"); S32 height_offset = (getRect().getHeight() - MULTI_TRACK_HEIGHT) / 2; LLRect track_rect(0, getRect().getHeight() - height_offset, getRect().getWidth(), height_offset ); diff --git a/indra/llui/llmultisliderctrl.cpp b/indra/llui/llmultisliderctrl.cpp index 50da077877..7ef6084705 100644 --- a/indra/llui/llmultisliderctrl.cpp +++ b/indra/llui/llmultisliderctrl.cpp @@ -391,7 +391,7 @@ void LLMultiSliderCtrl::setPrecision(S32 precision) { if (precision < 0 || precision > 10) { - llerrs << "LLMultiSliderCtrl::setPrecision - precision out of range" << llendl; + LL_ERRS() << "LLMultiSliderCtrl::setPrecision - precision out of range" << LL_ENDL; return; } diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp index 41254b0bbd..e2cdfa8ed3 100644 --- a/indra/llui/llnotifications.cpp +++ b/indra/llui/llnotifications.cpp @@ -40,6 +40,8 @@ #include "lltrans.h" #include "llnotifications.h" +#include "aialert.h" +#include "aistatemachine.h" #include "../newview/hippogridmanager.h" @@ -49,6 +51,9 @@ #endif #include +// Two macros, used to make access to mItems thread-safe, to keep the diff to a minimum. +#define AILOCK_mItems mItems_wat mItems_w(mItems_sf); LLNotificationSet& mItems(*mItems_w) +#define AILOCK_const_mItems mItems_crat mItems_r(mItems_sf); LLNotificationSet const& mItems(*mItems_r) const std::string NOTIFICATION_PERSIST_VERSION = "0.93"; @@ -69,8 +74,9 @@ class LLNotificationHistoryChannel : public LLNotificationChannel bool historyHandler(const LLSD& payload) { // we ignore "load" messages, but rewrite the persistence file on any other + // onDelete handes "delete" message, so skip that too. std::string sigtype = payload["sigtype"]; - if (sigtype != "load") + if (sigtype != "load" && sigtype != "delete") { savePersistentNotifications(); } @@ -80,17 +86,21 @@ class LLNotificationHistoryChannel : public LLNotificationChannel // The history channel gets all notifications except those that have been cancelled static bool historyFilter(LLNotificationPtr pNotification) { - return !pNotification->isCancelled(); + return pNotification->isPersistent() && !pNotification->isCancelled() && !pNotification->isRespondedTo() && !pNotification->isExpired(); } void savePersistentNotifications() { - llinfos << "Saving open notifications to " << mFileName << llendl; + if (mLoading) + { + return; + } + LL_INFOS() << "Saving open notifications to " << mFileName << LL_ENDL; llofstream notify_file(mFileName.c_str()); if (!notify_file.is_open()) { - llwarns << "Failed to open " << mFileName << llendl; + LL_WARNS() << "Failed to open " << mFileName << LL_ENDL; return; } @@ -98,6 +108,10 @@ class LLNotificationHistoryChannel : public LLNotificationChannel output["version"] = NOTIFICATION_PERSIST_VERSION; LLSD& data = output["data"]; + AILOCK_mItems; + + static LLCachedControl maxPersistentNotificaitons("MaxPersistentNotifications"); + for (LLNotificationSet::iterator it = mItems.begin(); it != mItems.end(); ++it) { if (!LLNotificationTemplates::instance().templateExists((*it)->getName())) continue; @@ -105,7 +119,15 @@ class LLNotificationHistoryChannel : public LLNotificationChannel // only store notifications flagged as persisting LLNotificationTemplatePtr templatep = LLNotificationTemplates::instance().getTemplate((*it)->getName()); if (!templatep->mPersist) continue; + if ((*it)->isCancelled() || (*it)->isExpired() || (*it)->isRespondedTo()) continue; + if (data.size() >= maxPersistentNotificaitons) + { + LL_WARNS() << "Too many persistent notifications." + << " Saved " << maxPersistentNotificaitons << " of " << mItems.size() + << " persistent notifications." << LL_ENDL; + break; + } data.append((*it)->asLLSD()); } @@ -115,52 +137,75 @@ class LLNotificationHistoryChannel : public LLNotificationChannel void loadPersistentNotifications() { - llinfos << "Loading open notifications from " << mFileName << llendl; - - llifstream notify_file(mFileName.c_str()); - if (!notify_file.is_open()) + if (mLoading) { - llwarns << "Failed to open " << mFileName << llendl; return; } + mLoading = true; + LL_INFOS() << "Loading open notifications from " << mFileName << LL_ENDL; - LLSD input; - LLPointer parser = new LLSDXMLParser(); - if (parser->parse(notify_file, input, LLSDSerialize::SIZE_UNLIMITED) < 0) + while (true) { - llwarns << "Failed to parse open notifications" << llendl; - return; - } + llifstream notify_file(mFileName.c_str()); + if (!notify_file.is_open()) + { + LL_WARNS() << "Failed to open " << mFileName << LL_ENDL; + break; + } - if (input.isUndefined()) return; - std::string version = input["version"]; - if (version != NOTIFICATION_PERSIST_VERSION) - { - llwarns << "Bad open notifications version: " << version << llendl; - return; - } - LLSD& data = input["data"]; - if (data.isUndefined()) return; + LLSD input; + LLPointer parser = new LLSDXMLParser(); + if (parser->parse(notify_file, input, LLSDSerialize::SIZE_UNLIMITED) < 0) + { + LL_WARNS() << "Failed to parse open notifications" << LL_ENDL; + break; + } - LLNotifications& instance = LLNotifications::instance(); - for (LLSD::array_const_iterator notification_it = data.beginArray(); - notification_it != data.endArray(); - ++notification_it) - { - instance.add(LLNotificationPtr(new LLNotification(*notification_it))); + if (input.isUndefined()) return; + std::string version = input["version"]; + if (version != NOTIFICATION_PERSIST_VERSION) + { + LL_WARNS() << "Bad open notifications version: " << version << LL_ENDL; + break; + } + LLSD& data = input["data"]; + if (data.isUndefined()) break; + + S32 processed_notifications = 0; + static LLCachedControl maxPersistentNotificaitons("MaxPersistentNotifications"); + + LLNotifications& instance = LLNotifications::instance(); + for (LLSD::array_const_iterator notification_it = data.beginArray(); + notification_it != data.endArray(); + ++notification_it) + { + if (processed_notifications++ >= maxPersistentNotificaitons) + { + LL_WARNS() << "Too many persistent notifications." + << " Processed " << maxPersistentNotificaitons << " of " << data.size() << " persistent notifications." << LL_ENDL; + break; + } + instance.add(LLNotificationPtr(new LLNotification(*notification_it))); + + } + break; } + mLoading = false; + savePersistentNotifications(); } //virtual void onDelete(LLNotificationPtr pNotification) { - // we want to keep deleted notifications in our log - mItems.insert(pNotification); - - return; + { + AILOCK_mItems; + mItems.erase(pNotification); // Delete immediately. + } + savePersistentNotifications(); } private: + bool mLoading = false; std::string mFileName; }; @@ -223,7 +268,7 @@ LLNotificationForm::LLNotificationForm(const std::string& name, const LLXMLNodeP { if (!xml_node->hasName("form")) { - llwarns << "Bad xml node for form: " << xml_node->getName() << llendl; + LL_WARNS() << "Bad xml node for form: " << xml_node->getName() << LL_ENDL; } LLXMLNodePtr child = xml_node->getFirstChild(); while(child) @@ -270,6 +315,7 @@ LLNotificationForm::LLNotificationForm(const std::string& name, const LLXMLNodeP } LLNotificationForm::LLNotificationForm(const LLSD& sd) + : mIgnore(IGNORE_NO) { if (sd.isArray()) { @@ -277,7 +323,8 @@ LLNotificationForm::LLNotificationForm(const LLSD& sd) } else { - llwarns << "Invalid form data " << sd << llendl; + if (!sd.isUndefined()) + LL_WARNS() << "Invalid form data " << sd << LL_ENDL; mFormData = LLSD::emptyArray(); } } @@ -408,7 +455,7 @@ LLNotification::LLNotification(const LLNotification::Params& p) : mTimestamp(p.timestamp), mSubstitutions(p.substitutions), mPayload(p.payload), - mExpiresAt(0), + mExpiresAt(F64SecondsImplicit()), mResponseFunctorName(p.functor_name), mTemporaryResponder(p.mTemporaryResponder), mRespondedTo(false), @@ -756,6 +803,7 @@ void LLNotificationChannelBase::connectChanged(const LLStandardSignal::slot_type // all of the notifications that are already in the channel // we use a special signal called "load" in case the channel wants to care // only about new notifications + AILOCK_mItems; for (LLNotificationSet::iterator it = mItems.begin(); it != mItems.end(); ++it) { slot(LLSD().with("sigtype", "load").with("id", (*it)->id())); @@ -794,8 +842,11 @@ bool LLNotificationChannelBase::updateItem(const LLSD& payload) // internal call, for use in avoiding lookup bool LLNotificationChannelBase::updateItem(const LLSD& payload, LLNotificationPtr pNotification) -{ +{ + llassert(AIThreadID::in_main_thread()); + std::string cmd = payload["sigtype"]; + AILOCK_mItems; LLNotificationSet::iterator foundItem = mItems.find(pNotification); bool wasFound = (foundItem != mItems.end()); bool passesFilter = mFilter(pNotification); @@ -880,7 +931,7 @@ bool LLNotificationChannelBase::updateItem(const LLSD& payload, LLNotificationPt assert(!wasFound); if (passesFilter) { - llinfos << "Inserting " << pNotification->getName() << llendl; + //LL_INFOS() << "Inserting " << pNotification->getName() << LL_ENDL; // not in our list, add it and say so mItems.insert(pNotification); abortProcessing = mChanged(payload); @@ -892,9 +943,9 @@ bool LLNotificationChannelBase::updateItem(const LLSD& payload, LLNotificationPt // if we have it in our list, pass on the delete, then delete it, else do nothing if (wasFound) { + onDelete(pNotification); abortProcessing = mChanged(payload); mItems.erase(pNotification); - onDelete(pNotification); } } return abortProcessing; @@ -942,6 +993,7 @@ void LLNotificationChannel::setComparator(LLNotificationComparator comparator) { mComparator = comparator; LLNotificationSet s2(mComparator); + AILOCK_mItems; s2.insert(mItems.begin(), mItems.end()); mItems.swap(s2); @@ -951,16 +1003,19 @@ void LLNotificationChannel::setComparator(LLNotificationComparator comparator) bool LLNotificationChannel::isEmpty() const { + AILOCK_const_mItems; return mItems.empty(); } LLNotificationChannel::Iterator LLNotificationChannel::begin() { + AILOCK_const_mItems; return mItems.begin(); } LLNotificationChannel::Iterator LLNotificationChannel::end() { + AILOCK_const_mItems; return mItems.end(); } @@ -1094,7 +1149,7 @@ LLNotificationChannelPtr LLNotifications::getChannel(const std::string& channelN ChannelMap::iterator p = mChannels.find(channelName); if(p == mChannels.end()) { - llerrs << "Did not find channel named " << channelName << llendl; + LL_ERRS() << "Did not find channel named " << channelName << LL_ENDL; return LLNotificationChannelPtr(); } return p->second; @@ -1130,13 +1185,6 @@ void LLNotifications::createDefaultChannels() LLNotificationChannel::buildChannel("Visible", "Ignore", &LLNotificationFilters::includeEverything); - // create special history channel - //std::string notifications_log_file = gDirUtilp->getExpandedFilename ( LL_PATH_PER_SL_ACCOUNT, "open_notifications.xml" ); - // use ^^^ when done debugging notifications serialization - std::string notifications_log_file = gDirUtilp->getExpandedFilename ( LL_PATH_USER_SETTINGS, "open_notifications.xml" ); - // this isn't a leak, don't worry about the empty "new" - new LLNotificationHistoryChannel(notifications_log_file); - // connect action methods to these channels LLNotifications::instance().getChannel("Expiration")-> connectChanged(boost::bind(&LLNotifications::expirationHandler, this, _1)); @@ -1148,6 +1196,14 @@ void LLNotifications::createDefaultChannels() connectFailedFilter(&handleIgnoredNotification); } +void LLNotifications::onLoginCompleted() +{ + // create special history channel + std::string notifications_log_file = gDirUtilp->getExpandedFilename ( LL_PATH_PER_SL_ACCOUNT, "singu_open_notifications_" + gHippoGridManager->getCurrentGrid()->getGridName() + ".xml"); + // this isn't a leak, don't worry about the empty "new" + new LLNotificationHistoryChannel(notifications_log_file ); +} + static std::string sStringSkipNextTime("Skip this dialog next time"); static std::string sStringAlwaysChoose("Always choose this option"); @@ -1156,7 +1212,7 @@ bool LLNotificationTemplates::addTemplate(const std::string &name, { if (mTemplates.count(name)) { - llwarns << "LLNotifications -- attempted to add template '" << name << "' twice." << llendl; + LL_WARNS() << "LLNotifications -- attempted to add template '" << name << "' twice." << LL_ENDL; return false; } mTemplates[name] = theTemplate; @@ -1193,7 +1249,7 @@ void LLNotifications::forceResponse(const LLNotification::Params& params, S32 op if (selected_item.isUndefined()) { - llwarns << "Invalid option" << option << " for notification " << (std::string)params.name << llendl; + LL_WARNS() << "Invalid option" << option << " for notification " << (std::string)params.name << LL_ENDL; return; } response[selected_item["name"].asString()] = true; @@ -1214,7 +1270,7 @@ LLNotificationTemplates::TemplateNames LLNotificationTemplates::getTemplateNames typedef std::map StringMap; void replaceSubstitutionStrings(LLXMLNodePtr node, StringMap& replacements) { - //llwarns << "replaceSubstitutionStrings" << llendl; + //LL_WARNS() << "replaceSubstitutionStrings" << LL_ENDL; // walk the list of attributes looking for replacements for (LLXMLAttribList::iterator it=node->mAttributes.begin(); it != node->mAttributes.end(); ++it) @@ -1228,13 +1284,13 @@ void replaceSubstitutionStrings(LLXMLNodePtr node, StringMap& replacements) if (found != replacements.end()) { replacement = found->second; - //llinfos << "replaceSubstitutionStrings: value: \"" << value << "\" repl: \"" << replacement << "\"." << llendl; + //LL_INFOS() << "replaceSubstitutionStrings: value: \"" << value << "\" repl: \"" << replacement << "\"." << LL_ENDL; it->second->setValue(replacement); } else { - llwarns << "replaceSubstitutionStrings FAILURE: could not find replacement \"" << value << "\"." << llendl; + LL_WARNS() << "replaceSubstitutionStrings FAILURE: could not find replacement \"" << value << "\"." << LL_ENDL; } } } @@ -1273,7 +1329,7 @@ LLXMLNodePtr LLNotificationTemplates::checkForXMLTemplate(LLXMLNodePtr item) } else { - llwarns << "XML template lookup failure on '" << replacementName << "' " << llendl; + LL_WARNS() << "XML template lookup failure on '" << replacementName << "' " << LL_ENDL; } } } @@ -1282,14 +1338,20 @@ LLXMLNodePtr LLNotificationTemplates::checkForXMLTemplate(LLXMLNodePtr item) bool LLNotificationTemplates::loadTemplates() { - const std::string xml_filename = "notifications.xml"; + LL_INFOS() << "Reading notifications template" << LL_ENDL; + // Passing findSkinnedFilenames(constraint=LLDir::ALL_SKINS) makes it + // output all relevant pathnames instead of just the ones from the most + // specific skin. + std::vector search_paths = + gDirUtilp->findSkinnedFilenames(LLDir::XUI, "notifications.xml", LLDir::ALL_SKINS); + + std::string base_filename = search_paths.front(); LLXMLNodePtr root; - - BOOL success = LLUICtrlFactory::getLayeredXMLNode(xml_filename, root); + BOOL success = LLXMLNode::getLayeredXMLNode(root, search_paths); if (!success || root.isNull() || !root->hasName( "notifications" )) { - llerrs << "Problem reading UI Notifications file: " << xml_filename << llendl; + LL_ERRS() << "Problem reading XML from UI Notifications file: " << base_filename << LL_ENDL; return false; } @@ -1321,8 +1383,8 @@ bool LLNotificationTemplates::loadTemplates() if (!item->hasName("notification")) { - llwarns << "Unexpected entity " << item->getName()->mString << - " found in " << xml_filename << llendl; + LL_WARNS() << "Unexpected entity " << item->getName()->mString << + " found in notifications.xml [language=]" << LLUI::getLanguage() << LL_ENDL; continue; } } @@ -1332,14 +1394,20 @@ bool LLNotificationTemplates::loadTemplates() bool LLNotifications::loadNotifications() { - const std::string xml_filename = "notifications.xml"; + LL_INFOS() << "Reading notifications template" << LL_ENDL; + // Passing findSkinnedFilenames(constraint=LLDir::ALL_SKINS) makes it + // output all relevant pathnames instead of just the ones from the most + // specific skin. + std::vector search_paths = + gDirUtilp->findSkinnedFilenames(LLDir::XUI, "notifications.xml", LLDir::ALL_SKINS); + + std::string base_filename = search_paths.front(); LLXMLNodePtr root; - - BOOL success = LLUICtrlFactory::getLayeredXMLNode(xml_filename, root); + BOOL success = LLXMLNode::getLayeredXMLNode(root, search_paths); if (!success || root.isNull() || !root->hasName( "notifications" )) { - llerrs << "Problem reading UI Notifications file: " << xml_filename << llendl; + LL_ERRS() << "Problem reading XML from UI Notifications file: " << base_filename << LL_ENDL; return false; } @@ -1359,11 +1427,11 @@ bool LLNotifications::loadNotifications() if (!item->getAttributeString("name", pTemplate->mName)) { - llwarns << "Unable to parse notification with no name" << llendl; + LL_WARNS() << "Unable to parse notification with no name" << LL_ENDL; continue; } - //llinfos << "Parsing " << pTemplate->mName << llendl; + //LL_INFOS() << "Parsing " << pTemplate->mName << LL_ENDL; pTemplate->mMessage = item->getTextContents(); pTemplate->mDefaultFunctor = pTemplate->mName; @@ -1421,12 +1489,12 @@ bool LLNotifications::loadNotifications() std::string key; formitem->getAttributeString("key", key); pTemplate->mUniqueContext.push_back(key); - //llwarns << "adding " << key << " to unique context" << llendl; + //LL_WARNS() << "adding " << key << " to unique context" << LL_ENDL; } else { - llwarns << "'unique' has unrecognized subelement " - << formitem->getName()->mString << llendl; + LL_WARNS() << "'unique' has unrecognized subelement " + << formitem->getName()->mString << LL_ENDL; } } } @@ -1442,7 +1510,7 @@ bool LLNotifications::loadNotifications() //std::ostringstream ostream; //root->writeToOstream(ostream, "\n "); - //llwarns << ostream.str() << llendl; + //LL_WARNS() << ostream.str() << LL_ENDL; return true; } @@ -1479,40 +1547,168 @@ LLNotificationPtr LLNotifications::add(const LLNotification::Params& p) return pNotif; } +namespace AIAlert { std::string text(Error const& error, int suppress_mask = 0); } +LLNotificationPtr LLNotifications::add(AIAlert::Error const& error, int type, unsigned int suppress_mask) +{ + LLSD substitutions = LLSD::emptyMap(); + substitutions["[PAYLOAD]"] = AIAlert::text(error, suppress_mask); + return add(LLNotification::Params((type == AIAlert::modal || error.is_modal()) ? "AIAlertModal" : "AIAlert").substitutions(substitutions)); +} + +//-------------------------------------------------------------------------------- +// struct UpdateItem +// +// Allow LLNotifications::add, LLNotifications::cancel and LLNotifications::update +// to be called from any thread. + +struct UpdateItem +{ + char const* sigtype; + LLNotificationPtr pNotif; + UpdateItem(char const* st, LLNotificationPtr const& np) : sigtype(st), pNotif(np) { } + void doit(void) const; +}; + +void UpdateItem::doit(void) const +{ + LLNotifications::getInstance()->updateItem(LLSD().with("sigtype", sigtype).with("id", pNotif->id()), pNotif); + if (!strcmp(sigtype, "delete")) + { + pNotif->cancel(); + } +} + +class UpdateItemSM : public AIStateMachine +{ + protected: + typedef AIStateMachine direct_base_type; + + enum update_item_state_type { + UpdateItem_idle = direct_base_type::max_state, + UpdateItem_doit + }; + + public: + static state_type const max_state = UpdateItem_doit + 1; + + public: + UpdateItemSM(void) : AIStateMachine(CWD_ONLY(true)) { } + + static void add(UpdateItem const& ui); + + /*virtual*/ const char* getName() const { return "UpdateItemSM"; } + + private: + static UpdateItemSM* sSelf; + typedef std::deque updateQueue_type; + AIThreadSafeSimpleDC mUpdateQueue; + typedef AIAccess mUpdateQueue_wat; + typedef AIAccess mUpdateQueue_rat; + typedef AIAccessConst mUpdateQueue_crat; + + protected: + /*virtual*/ ~UpdateItemSM() { } + + protected: + /*virtual*/ void initialize_impl(void) { set_state(UpdateItem_idle); } + /*virtual*/ void multiplex_impl(state_type run_state); + /*virtual*/ void abort_impl(void) { } + /*virtual*/ void finish_impl(void) { } + /*virtual*/ char const* state_str_impl(state_type run_state) const; +}; + +//static +UpdateItemSM* UpdateItemSM::sSelf; + +void UpdateItemSM::add(UpdateItem const& ui) +{ + if (!sSelf) + { + sSelf = new UpdateItemSM; + sSelf->run(NULL, 0, false, true, &gMainThreadEngine); + } + if (AIThreadID::in_main_thread()) + { + ui.doit(); + return; + } + mUpdateQueue_wat mUpdateQueue_w(sSelf->mUpdateQueue); + mUpdateQueue_w->push_back(ui); + sSelf->advance_state(UpdateItem_doit); +} + +char const* UpdateItemSM::state_str_impl(state_type run_state) const +{ + switch(run_state) + { + // A complete listing of hello_world_state_type. + AI_CASE_RETURN(UpdateItem_idle); + AI_CASE_RETURN(UpdateItem_doit); + } + llassert(false); + return "UNKNOWN STATE"; +} + +void UpdateItemSM::multiplex_impl(state_type run_state) +{ + switch(run_state) + { + case UpdateItem_idle: + idle(); + break; + case UpdateItem_doit: + { + mUpdateQueue_wat mUpdateQueue_w(sSelf->mUpdateQueue); + while (!mUpdateQueue_w->empty()) + { + UpdateItem const& ui(mUpdateQueue_w->front()); + ui.doit(); + mUpdateQueue_w->pop_front(); + } + set_state(UpdateItem_idle); + break; + } + } +} + +// end of UpdateItemSM +//-------------------------------------------------------------------------------- void LLNotifications::add(const LLNotificationPtr pNotif) { if (pNotif == NULL) return; // first see if we already have it -- if so, that's a problem + AILOCK_mItems; LLNotificationSet::iterator it=mItems.find(pNotif); if (it != mItems.end()) { - llerrs << "Notification added a second time to the master notification channel." << llendl; + LL_ERRS() << "Notification added a second time to the master notification channel." << LL_ENDL; } - updateItem(LLSD().with("sigtype", "add").with("id", pNotif->id()), pNotif); + UpdateItemSM::add(UpdateItem("add", pNotif)); } void LLNotifications::cancel(LLNotificationPtr pNotif) { if (pNotif == NULL || pNotif->isCancelled()) return; + AILOCK_mItems; LLNotificationSet::iterator it=mItems.find(pNotif); if (it == mItems.end()) { - llerrs << "Attempted to delete nonexistent notification " << pNotif->getName() << llendl; + LL_ERRS() << "Attempted to delete nonexistent notification " << pNotif->getName() << LL_ENDL; } - updateItem(LLSD().with("sigtype", "delete").with("id", pNotif->id()), pNotif); - pNotif->cancel(); + UpdateItemSM::add(UpdateItem("delete", pNotif)); } void LLNotifications::update(const LLNotificationPtr pNotif) { + AILOCK_mItems; LLNotificationSet::iterator it=mItems.find(pNotif); if (it != mItems.end()) { - updateItem(LLSD().with("sigtype", "change").with("id", pNotif->id()), pNotif); + UpdateItemSM::add(UpdateItem("change", pNotif)); } } @@ -1520,10 +1716,11 @@ void LLNotifications::update(const LLNotificationPtr pNotif) LLNotificationPtr LLNotifications::find(LLUUID const& uuid) { LLNotificationPtr target = LLNotificationPtr(new LLNotification(uuid)); + AILOCK_mItems; LLNotificationSet::iterator it=mItems.find(target); if (it == mItems.end()) { - llwarns << "Tried to dereference uuid '" << uuid << "' as a notification key but didn't find it." << llendl; + LL_WARNS() << "Tried to dereference uuid '" << uuid << "' as a notification key but didn't find it." << LL_ENDL; return LLNotificationPtr((LLNotification*)NULL); } else @@ -1534,6 +1731,7 @@ LLNotificationPtr LLNotifications::find(LLUUID const& uuid) void LLNotifications::forEachNotification(NotificationProcess process) { + AILOCK_mItems; std::for_each(mItems.begin(), mItems.end(), process); } diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h index fe9049ee29..ea308ebb42 100644 --- a/indra/llui/llnotifications.h +++ b/indra/llui/llnotifications.h @@ -94,7 +94,7 @@ #include #include #include - +#include // we want to minimize external dependencies, but this one is important #include "llsd.h" #include "llinstancetracker.h" @@ -103,10 +103,14 @@ #include "llavatarname.h" #include "llevents.h" #include "llfunctorregistry.h" +#include "llinitparam.h" #include "llui.h" #include "llxmlnode.h" #include "llnotificationptr.h" #include "llnotificationcontext.h" +#include "aithreadsafe.h" + +namespace AIAlert { class Error; } typedef enum e_notification_priority { @@ -129,6 +133,70 @@ class LLNotificationForm LOG_CLASS(LLNotificationForm); public: + struct FormElementBase : public LLInitParam::Block + { + Optional name; + Optional enabled; + + FormElementBase(); + }; + + struct FormIgnore : public LLInitParam::Block + { + Optional text; + Optional save_option; + Optional control; + Optional invert_control; + + FormIgnore(); + }; + + struct FormButton : public LLInitParam::Block + { + Mandatory index; + Mandatory text; + Optional ignore; + Optional is_default; + + Mandatory type; + + FormButton(); + }; + + struct FormInput : public LLInitParam::Block + { + Mandatory type; + Optional width; + Optional max_length_chars; + Optional text; + + Optional value; + FormInput(); + }; + + struct FormElement : public LLInitParam::ChoiceBlock + { + Alternative button; + Alternative input; + + FormElement(); + }; + + struct FormElements : public LLInitParam::Block + { + Multiple elements; + FormElements(); + }; + + struct Params : public LLInitParam::Block + { + Optional name; + Optional ignore; + Optional form_elements; + + Params(); + }; + typedef enum e_ignore_type { IGNORE_NO, @@ -194,6 +262,7 @@ class LLNotification : { LOG_CLASS(LLNotification); friend class LLNotifications; +friend struct UpdateItem; public: // parameter object used to instantiate a new notification @@ -303,7 +372,7 @@ friend class LLNotifications; // after someone responds to a notification (usually by clicking a button, // but sometimes by filling out a little form and THEN clicking a button), - // the result of the response (the name and value of the button clicked, + // the result of the response (the name and value of the button clicked, // plus any other data) should be packaged up as LLSD, then passed as a // parameter to the notification's respond() method here. This will look up // and call the appropriate responder. @@ -316,7 +385,7 @@ friend class LLNotifications; // ["payload"] = transaction specific data, such as ["source_id"] (originator of notification), // ["item_id"] (attached inventory item), etc. // ["substitutions"] = string substitutions used to generate notification message - // from the template + // from the template // ["time"] = time at which notification was generated; // ["expiry"] = time at which notification expires; // ["responseFunctor"] = name of registered functor that handles responses to notification; @@ -510,7 +579,7 @@ namespace LLNotificationComparators struct orderBy { typedef boost::function field_t; - orderBy(field_t field, EDirection direction = ORDER_INCREASING) : mField(field), mDirection(direction) {} + orderBy(field_t field, EDirection direction = ORDER_INCREASING) : mField(field), mDirection(direction) {} bool operator()(LLNotificationPtr lhs, LLNotificationPtr rhs) { if (mDirection == ORDER_DECREASING) @@ -564,9 +633,10 @@ class LLNotificationChannelBase : public boost::signals2::trackable { LOG_CLASS(LLNotificationChannelBase); + friend struct UpdateItem; public: LLNotificationChannelBase(LLNotificationFilter filter, LLNotificationComparator comp) : - mFilter(filter), mItems(comp) + mFilter(filter), mItems_sf(comp) {} virtual ~LLNotificationChannelBase() {} // you can also connect to a Channel, so you can be notified of @@ -580,7 +650,9 @@ class LLNotificationChannelBase : const LLNotificationFilter& getFilter() { return mFilter; } protected: - LLNotificationSet mItems; + AIThreadSafeSimpleDC mItems_sf; + typedef AIAccess mItems_wat; + typedef AIAccessConst mItems_crat; LLStandardSignal mChanged; LLStandardSignal mPassedFilter; LLStandardSignal mFailedFilter; @@ -625,18 +697,18 @@ class LLNotificationChannel : public: virtual ~LLNotificationChannel() {} typedef LLNotificationSet::iterator Iterator; - + std::string getName() const { return mName; } std::string getParentChannelName() { return mParent; } - - bool isEmpty() const; - - Iterator begin(); - Iterator end(); + + bool isEmpty() const; + + Iterator begin(); + Iterator end(); - // Channels have a comparator to control sort order; + // Channels have a comparator to control sort order; // the default sorts by arrival date - void setComparator(LLNotificationComparator comparator); + void setComparator(LLNotificationComparator comparator); std::string summarize(); @@ -647,7 +719,7 @@ class LLNotificationChannel : LLNotificationComparator comparator=LLNotificationComparators::orderByUUID()); protected: - // Notification Channels have a filter, which determines which notifications + // Notification Channels have a filter, which determines which notifications // will be added to this channel. // Channel filters cannot change. // Channels have a protected constructor so you can't make smart pointers that don't @@ -724,6 +796,7 @@ class LLNotifications : // OK to call more than once because it will reload bool loadNotifications(); void createDefaultChannels(); + void onLoginCompleted(); // we provide a collection of simple add notification functions so that it's reasonable to create notifications in one line LLNotificationPtr add(const std::string& name, @@ -737,6 +810,7 @@ class LLNotifications : const LLSD& substitutions, const LLSD& payload, LLNotificationFunctorRegistry::ResponseFunctor functor); + LLNotificationPtr add(AIAlert::Error const& error, int type, unsigned int suppress_mask); LLNotificationPtr add(const LLNotification::Params& p); void forceResponse(const LLNotification::Params& params, S32 option); diff --git a/indra/llui/llnotificationsutil.cpp b/indra/llui/llnotificationsutil.cpp index 4abc9ca69e..4c24b511e3 100644 --- a/indra/llui/llnotificationsutil.cpp +++ b/indra/llui/llnotificationsutil.cpp @@ -25,11 +25,76 @@ #include "linden_common.h" #include "llnotificationsutil.h" +#include "lltrans.h" #include "llnotifications.h" #include "llsd.h" #include "llxmlnode.h" // apparently needed to call LLNotifications::instance() +namespace AIAlert +{ + +LLNotificationPtr add(Error const& error, unsigned int suppress_mask, modal_nt type) +{ + return LLNotifications::instance().add(error, type, suppress_mask); +} + +LLNotificationPtr add(std::string const& xml_desc, modal_nt type) +{ + return LLNotifications::instance().add(Error(Prefix(), type, xml_desc, AIArgs()), type, 0); +} + +LLNotificationPtr add(std::string const& xml_desc, AIArgs const& args, modal_nt type) +{ + return LLNotifications::instance().add(Error(Prefix(), type, xml_desc, args), type, 0); +} + +LLNotificationPtr add(Error const& error, std::string const& xml_desc, unsigned int suppress_mask, modal_nt type) +{ + return LLNotifications::instance().add(Error(Prefix(), type, error, xml_desc, AIArgs()), type, suppress_mask); +} + +LLNotificationPtr add(Error const& error, std::string const& xml_desc, AIArgs const& args, unsigned int suppress_mask, modal_nt type) +{ + return LLNotifications::instance().add(Error(Prefix(), type, error, xml_desc, args), type, suppress_mask); +} + +LLNotificationPtr add(std::string const& xml_desc, Error const& error, unsigned int suppress_mask, modal_nt type) +{ + return LLNotifications::instance().add(Error(Prefix(), type, xml_desc, AIArgs(), error), type, suppress_mask); +} + +LLNotificationPtr add(std::string const& xml_desc, AIArgs const& args, Error const& error, unsigned int suppress_mask, modal_nt type) +{ + return LLNotifications::instance().add(Error(Prefix(), type, xml_desc, args, error), type, suppress_mask); +} + +std::string text(Error const& error, int suppress_mask) +{ + std::string alert_text; + bool suppress_newlines = false; + bool last_was_prefix = false; + for (Error::lines_type::const_iterator line = error.lines().begin(); line != error.lines().end(); ++line) + { + // Even if a line is suppressed, we print its leading newline if requested, but never more than one. + if (!suppress_newlines && line->prepend_newline()) + { + alert_text += '\n'; + suppress_newlines = true; + } + if (!line->suppressed(suppress_mask)) + { + if (last_was_prefix) alert_text += ' '; // The translation system strips off spaces... add them back. + alert_text += LLTrans::getString(line->getXmlDesc(), line->args()); + suppress_newlines = false; + last_was_prefix = line->is_prefix(); + } + } + return alert_text; +} + +} // namespace AIAlert + LLNotificationPtr LLNotificationsUtil::add(const std::string& name) { return LLNotifications::instance().add( diff --git a/indra/llui/llnotificationsutil.h b/indra/llui/llnotificationsutil.h index 4093324d0c..018db39c56 100644 --- a/indra/llui/llnotificationsutil.h +++ b/indra/llui/llnotificationsutil.h @@ -30,11 +30,59 @@ // to avoid including the heavyweight llnotifications.h #include "llnotificationptr.h" +#include "lluuid.h" +#include "aialert.h" +#ifndef BOOST_FUNCTION_HPP_INCLUDED #include +#define BOOST_FUNCTION_HPP_INCLUDED +#endif class LLSD; +namespace AIAlert +{ + // Add an alert directly to LLNotifications. + + // Look up xml_desc in strings.xml. + LLNotificationPtr add(std::string const& xml_desc, + modal_nt type = not_modal); + // ... with replacement args. + LLNotificationPtr add(std::string const& xml_desc, AIArgs const& args, + modal_nt type = not_modal); + + // Append it to an existing alert error. + LLNotificationPtr add(Error const& error, + std::string const& xml_desc, + unsigned int suppress_mask = 0, modal_nt type = not_modal); + LLNotificationPtr add(Error const& error, + std::string const& xml_desc, AIArgs const& args, + unsigned int suppress_mask = 0, modal_nt type = not_modal); + // Prepend it to an existing alert error. + LLNotificationPtr add(std::string const& xml_desc, + Error const& error, + unsigned int suppress_mask = 0, modal_nt type = not_modal); + LLNotificationPtr add(std::string const& xml_desc, AIArgs const& args, + Error const& error, + unsigned int suppress_mask = 0, modal_nt type = not_modal); + + // Just show the caught alert error. + LLNotificationPtr add(Error const& error, + unsigned int suppress_mask = 0, modal_nt type = not_modal); + + // Short cuts for enforcing modal alerts. + inline LLNotificationPtr add_modal(std::string const& xml_desc) { return add(xml_desc, modal); } + inline LLNotificationPtr add_modal(std::string const& xml_desc, AIArgs const& args) { return add(xml_desc, args, modal); } + inline LLNotificationPtr add_modal(Error const& error, std::string const& xml_desc, unsigned int suppress_mask = 0) { return add(error, xml_desc, suppress_mask, modal); } + inline LLNotificationPtr add_modal(Error const& error, std::string const& xml_desc, AIArgs const& args, unsigned int suppress_mask = 0) { return add(error, xml_desc, args, suppress_mask, modal); } + inline LLNotificationPtr add_modal(std::string const& xml_desc, Error const& error, unsigned int suppress_mask = 0) { return add(xml_desc, error, suppress_mask, modal); } + inline LLNotificationPtr add_modal(std::string const& xml_desc, AIArgs const& args, Error const& error, unsigned int suppress_mask = 0) { return add(xml_desc, args, error, suppress_mask, modal); } + inline LLNotificationPtr add_modal(Error const& error, unsigned int suppress_mask = 0) { return add(error, suppress_mask, modal); } + + // Return the full, translated, texted of the alert (possibly suppressing certain output). + std::string text(Error const& error, int suppress_mask = 0); +} + namespace LLNotificationsUtil { LLNotificationPtr add(const std::string& name); diff --git a/indra/llui/llpanel.cpp b/indra/llui/llpanel.cpp index d9e1c7e94e..e311daa1c5 100644 --- a/indra/llui/llpanel.cpp +++ b/indra/llui/llpanel.cpp @@ -159,8 +159,12 @@ void LLPanel::addBorder(LLViewBorder::EBevel border_bevel, void LLPanel::removeBorder() { - delete mBorder; - mBorder = NULL; + if (mBorder) + { + removeChild(mBorder); + delete mBorder; + mBorder = NULL; + } } @@ -192,14 +196,16 @@ void LLPanel::draw() // draw background if( mBgVisible ) { - LLRect local_rect = getLocalRect(); + F32 alpha = getCurrentTransparency(); + + LLRect&& local_rect = getLocalRect(); if (mBgOpaque ) { - gl_rect_2d( local_rect, mBgColorOpaque ); + gl_rect_2d( local_rect, mBgColorOpaque % alpha); } else { - gl_rect_2d( local_rect, mBgColorAlpha ); + gl_rect_2d( local_rect, mBgColorAlpha % alpha); } } @@ -277,7 +283,7 @@ BOOL LLPanel::handleKeyHere( KEY key, MASK mask ) // handle user hitting ESC to defocus if (key == KEY_ESCAPE && mask == MASK_NONE) { - gFocusMgr.setKeyboardFocus(NULL); + setFocus(FALSE); return TRUE; } else if( (mask == MASK_SHIFT) && (KEY_TAB == key)) @@ -304,29 +310,25 @@ BOOL LLPanel::handleKeyHere( KEY key, MASK mask ) } } } - - // If we have a default button, click it when - // return is pressed, unless current focus is a return-capturing button - // in which case *that* button will handle the return key - LLButton* focused_button = dynamic_cast(cur_focus); - if (cur_focus && !(focused_button && focused_button->getCommitOnReturn())) + + // If RETURN was pressed and something has focus, call onCommit() + if (!handled && cur_focus && key == KEY_RETURN && mask == MASK_NONE) { - // RETURN key means hit default button in this case - if (key == KEY_RETURN && mask == MASK_NONE - && mDefaultBtn != NULL - && mDefaultBtn->getVisible() - && mDefaultBtn->getEnabled()) + if (cur_focus->getCommitOnReturn()) + { + // current focus is a return-capturing element, + // let *that* element handle the return key + handled = FALSE; + } + else if (mDefaultBtn && mDefaultBtn->getVisible() && mDefaultBtn->getEnabled()) { + // If we have a default button, click it when return is pressed mDefaultBtn->onCommit(); handled = TRUE; } - } - - if (key == KEY_RETURN && mask == MASK_NONE) - { - // set keyboard focus to self to trigger commitOnFocusLost behavior on current ctrl - if (cur_focus && cur_focus->acceptsTextInput()) + else if (cur_focus->acceptsTextInput()) { + // call onCommit for text input handling control cur_focus->onCommit(); handled = TRUE; } @@ -343,8 +345,8 @@ BOOL LLPanel::checkRequirements() args["COMPONENTS"] = mRequirementsError; args["FLOATER"] = getName(); - llwarns << getName() << " failed requirements check on: \n" - << mRequirementsError << llendl; + LL_WARNS() << getName() << " failed requirements check on: \n" + << mRequirementsError << LL_ENDL; LLNotifications::instance().add(LLNotification::Params("FailedRequirementsCheck").payload(args)); mRequirementsError.clear(); @@ -363,34 +365,16 @@ void LLPanel::handleVisibilityChange ( BOOL new_visibility ) void LLPanel::setFocus(BOOL b) { - if( b ) + if( b && !hasFocus()) { - if (!gFocusMgr.childHasKeyboardFocus(this)) - { - //refresh(); - if (!focusFirstItem()) - { - LLUICtrl::setFocus(TRUE); - } - onFocusReceived(); - } + // give ourselves focus preemptively, to avoid infinite loop + LLUICtrl::setFocus(TRUE); + // then try to pass to first valid child + focusFirstItem(); } else { - if( this == gFocusMgr.getKeyboardFocus() ) - { - gFocusMgr.setKeyboardFocus( NULL ); - } - else - { - //RN: why is this here? - LLView::ctrl_list_t ctrls = getCtrlList(); - for (LLView::ctrl_list_t::iterator ctrl_it = ctrls.begin(); ctrl_it != ctrls.end(); ++ctrl_it) - { - LLUICtrl* ctrl = *ctrl_it; - ctrl->setFocus( FALSE ); - } - } + LLUICtrl::setFocus(b); } } @@ -402,7 +386,7 @@ void LLPanel::setBorderVisible(BOOL b) } } -LLFastTimer::DeclareTimer FTM_PANEL_CONSTRUCTION("Panel Construction"); +LLTrace::BlockTimerStatHandle FTM_PANEL_CONSTRUCTION("Panel Construction"); // virtual LLXMLNodePtr LLPanel::getXML(bool save_children) const { @@ -457,8 +441,31 @@ LLView* LLPanel::fromXML(LLXMLNodePtr node, LLView* parent, LLUICtrlFactory *fac std::string name("panel"); node->getAttributeString("name", name); - LLPanel* panelp = factory->createFactoryPanel(name); - LLFastTimer _(FTM_PANEL_CONSTRUCTION); + std::string class_attr; + node->getAttributeString("class", class_attr); + + LLPanel* panelp = NULL; + + { + if(!class_attr.empty()) + { + panelp = LLRegisterPanelClass::instance().createPanelClass(class_attr); + } + + if (!panelp) + { + panelp = factory->createFactoryPanel(name); + /* Singu TODO: Future? + llassert(panelp); + + if (!panelp) + { + return NULL; // :( + }*/ + } + } + LL_RECORD_BLOCK_TIME(FTM_PANEL_CONSTRUCTION); + // Fall back on a default panel, if there was no special factory. if (!panelp) { @@ -548,11 +555,13 @@ BOOL LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *f void LLPanel::initChildrenXML(LLXMLNodePtr node, LLUICtrlFactory* factory) { + std::string kidstring(node->getName()->mString); + kidstring += ".string"; LLXMLNodePtr child; for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling()) { // look for string declarations for programmatic text - if (child->hasName("string")) + if (child->hasName("string") || child->hasName(kidstring)) { std::string string_name; child->getAttributeString("name", string_name); @@ -646,11 +655,11 @@ std::string LLPanel::getString(const std::string& name, const LLStringUtil::form //if(LLUI::sConfigGroup->getBOOL("QAMode")) if(LLUI::sQAMode) { - llerrs << err_str << llendl; + LL_ERRS() << err_str << LL_ENDL; } else { - llwarns << err_str << llendl; + LL_WARNS() << err_str << LL_ENDL; } return LLStringUtil::null; } @@ -665,11 +674,11 @@ std::string LLPanel::getString(const std::string& name) const std::string err_str("Failed to find string " + name + " in panel " + getName()); // *TODO: Translate if(LLUI::sQAMode) { - llerrs << err_str << llendl; + LL_ERRS() << err_str << LL_ENDL; } else { - llwarns << err_str << llendl; + LL_WARNS() << err_str << LL_ENDL; } return LLStringUtil::null; } diff --git a/indra/llui/llpanel.h b/indra/llui/llpanel.h index d2ca151e5a..f379cd2a62 100644 --- a/indra/llui/llpanel.h +++ b/indra/llui/llpanel.h @@ -39,8 +39,8 @@ #include "lluictrl.h" #include "llbutton.h" #include "lllineeditor.h" -#include "lluiimage.h" #include "llviewborder.h" +#include "lluiimage.h" #include "lluistring.h" #include "v4color.h" #include @@ -142,6 +142,7 @@ class LLPanel : public LLUICtrl CommitCallbackRegistry::ScopedRegistrar& getCommitCallbackRegistrar() { return mCommitCallbackRegistrar; } EnableCallbackRegistry::ScopedRegistrar& getEnableCallbackRegistrar() { return mEnableCallbackRegistrar; } + virtual BOOL initPanelXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); void initChildrenXML(LLXMLNodePtr node, LLUICtrlFactory* factory); void setPanelParameters(LLXMLNodePtr node, LLView *parentp); @@ -151,6 +152,7 @@ class LLPanel : public LLUICtrl std::string getString(const std::string& name) const; // ** Wrappers for setting child properties by name ** -TomY + // WARNING: These are deprecated, please use getChild("name")->doStuff() idiom instead // LLView void childSetVisible(const std::string& name, bool visible); @@ -196,7 +198,7 @@ class LLPanel : public LLUICtrl BOOL childSetTextArg(const std::string& id, const std::string& key, const LLStringExplicit& text); BOOL childSetLabelArg(const std::string& id, const std::string& key, const LLStringExplicit& text); BOOL childSetToolTipArg(const std::string& id, const std::string& key, const LLStringExplicit& text); - + // LLSlider / LLMultiSlider / LLSpinCtrl void childSetMinValue(const std::string& id, LLSD min_value); void childSetMaxValue(const std::string& id, LLSD max_value); @@ -228,6 +230,7 @@ class LLPanel : public LLUICtrl static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); boost::signals2::connection setVisibleCallback( const commit_signal_t::slot_type& cb ); + protected: // Override to set not found list LLButton* getDefaultButton() { return mDefaultBtn; } @@ -262,4 +265,56 @@ class LLPanel : public LLUICtrl }; // end class LLPanel +typedef boost::function LLPanelClassCreatorFunc; + +// local static instance for registering a particular panel class + +class LLRegisterPanelClass +: public LLSingleton< LLRegisterPanelClass > +{ +public: + // reigister with either the provided builder, or the generic templated builder + void addPanelClass(const std::string& tag,LLPanelClassCreatorFunc func) + { + mPanelClassesNames[tag] = func; + } + + LLPanel* createPanelClass(const std::string& tag) + { + param_name_map_t::iterator iT = mPanelClassesNames.find(tag); + if(iT == mPanelClassesNames.end()) + return 0; + return iT->second(); + } + template + static T* defaultPanelClassBuilder() + { + T* pT = new T(); + return pT; + } + +private: + typedef std::map< std::string, LLPanelClassCreatorFunc> param_name_map_t; + + param_name_map_t mPanelClassesNames; +}; + + +// local static instance for registering a particular panel class +template + class LLPanelInjector +{ +public: + // register with either the provided builder, or the generic templated builder + LLPanelInjector(const std::string& tag); +}; + + +template + LLPanelInjector::LLPanelInjector(const std::string& tag) +{ + LLRegisterPanelClass::instance().addPanelClass(tag,&LLRegisterPanelClass::defaultPanelClassBuilder); +} + + #endif diff --git a/indra/llui/llprogressbar.cpp b/indra/llui/llprogressbar.cpp index 0443c480ae..9ba58039ed 100644 --- a/indra/llui/llprogressbar.cpp +++ b/indra/llui/llprogressbar.cpp @@ -48,16 +48,16 @@ static LLRegisterWidget r("progress_bar"); LLProgressBar::LLProgressBar(const std::string& name, const LLRect &rect) - : LLView(name, rect, FALSE), - mImageBar( NULL ), - mImageShadow( NULL ) + : LLView(name, rect, FALSE) + //mImageBar( NULL ), + // mImageShadow( NULL ) { mPercentDone = 0.f; // Defaults: - setImageBar("rounded_square.tga"); - setImageShadow("rounded_square_soft.tga"); + setImageBar("Rounded_Square"); + setImageShadow("Rounded_Square_Soft"); mColorBackground = LLColor4(0.3254f, 0.4000f, 0.5058f, 1.0f); mColorBar = LLColor4(0.5764f, 0.6627f, 0.8352f, 1.0f); @@ -75,16 +75,14 @@ void LLProgressBar::draw() static LLTimer timer; F32 alpha = getDrawContext().mAlpha; - //LLUIImagePtr shadow_imagep = LLUI::getUIImage("rounded_square_soft.tga"); - LLUIImagePtr bar_fg_imagep = LLUI::getUIImage("progressbar_fill.tga"); - LLUIImagePtr bar_bg_imagep = LLUI::getUIImage("progressbar_track.tga"); - //LLUIImagePtr bar_imagep = LLUI::getUIImage("rounded_square.tga"); + LLUIImagePtr bar_fg_imagep = LLUI::getUIImage("ProgressBar"); + LLUIImagePtr bar_bg_imagep = LLUI::getUIImage("ProgressTrack"); LLColor4 background_color = LLUI::sColorsGroup->getColor("LoginProgressBarBgColor"); bar_bg_imagep->draw(getLocalRect(), background_color % alpha); LLRect progress_rect = getLocalRect(); - progress_rect.mRight = llround(getRect().getWidth() * (mPercentDone / 100.f)); + progress_rect.mRight = ll_round(getRect().getWidth() * (mPercentDone / 100.f)); bar_fg_imagep->draw(progress_rect, LLColor4::white % alpha); } @@ -95,12 +93,12 @@ void LLProgressBar::setPercent(const F32 percent) void LLProgressBar::setImageBar( const std::string &bar_name ) { - mImageBar = LLUI::getUIImage(bar_name)->getImage(); + //mImageBar = LLUI::getUIImage(bar_name)->getImage(); } void LLProgressBar::setImageShadow(const std::string &shadow_name) { - mImageShadow = LLUI::getUIImage(shadow_name)->getImage(); + //mImageShadow = LLUI::getUIImage(shadow_name)->getImage(); } void LLProgressBar::setColorBar(const LLColor4 &c) @@ -140,14 +138,14 @@ LLView* LLProgressBar::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactor LLProgressBar *progress = new LLProgressBar(name, LLRect()); - std::string image_bar; + /*std::string image_bar; if (node->hasAttribute("image_bar")) node->getAttributeString("image_bar",image_bar); if (image_bar != LLStringUtil::null) progress->setImageBar(image_bar); std::string image_shadow; if (node->hasAttribute("image_shadow")) node->getAttributeString("image_shadow",image_shadow); - if (image_shadow != LLStringUtil::null) progress->setImageShadow(image_shadow); + if (image_shadow != LLStringUtil::null) progress->setImageShadow(image_shadow);*/ LLColor4 color_bar; diff --git a/indra/llui/llprogressbar.h b/indra/llui/llprogressbar.h index 8f548da660..d7af5360c6 100644 --- a/indra/llui/llprogressbar.h +++ b/indra/llui/llprogressbar.h @@ -62,13 +62,13 @@ class LLProgressBar protected: F32 mPercentDone; - LLPointer mImageBar; + // mImageBar; //LLUUID mImageBarID; //LLString mImageBarName; LLColor4 mColorBar; LLColor4 mColorBar2; - LLPointer mImageShadow; + //LLPointer mImageShadow; //LLUUID mImageShadowID; //LLString mImageShadowName; LLColor4 mColorShadow; diff --git a/indra/llui/llradiogroup.cpp b/indra/llui/llradiogroup.cpp index c592fccfb2..0cdaffff67 100644 --- a/indra/llui/llradiogroup.cpp +++ b/indra/llui/llradiogroup.cpp @@ -46,16 +46,36 @@ static LLRegisterWidget r("radio_group"); +/* + * A checkbox control with use_radio_style == true. + */ +class LLRadioCtrl : public LLCheckBoxCtrl +{ +public: + LLRadioCtrl(const std::string& name, const LLRect& rect, const std::string& label, const std::string& value = "", const LLFontGL* font = NULL, commit_callback_t commit_callback = NULL); + /*virtual*/ ~LLRadioCtrl(); + + virtual LLXMLNodePtr getXML(bool save_children = true) const; + /*virtual*/ void setValue(const LLSD& value); + + LLSD getPayload() { return mPayload; } +protected: + friend class LLUICtrlFactory; + + LLSD mPayload; // stores data that this item represents in the radio group +}; + LLRadioGroup::LLRadioGroup(const std::string& name, const LLRect& rect, S32 initial_index, commit_callback_t commit_callback, - BOOL border) : + bool border, bool allow_deselect) : LLUICtrl(name, rect, TRUE, commit_callback, FOLLOWS_LEFT | FOLLOWS_TOP), - mSelectedIndex(initial_index) + mSelectedIndex(initial_index), + mAllowDeselect(allow_deselect) { init(border); } -void LLRadioGroup::init(BOOL border) +void LLRadioGroup::init(bool border) { if (border) { @@ -67,12 +87,19 @@ void LLRadioGroup::init(BOOL border) } - - LLRadioGroup::~LLRadioGroup() { } +// virtual +BOOL LLRadioGroup::postBuild() +{ + if (!mRadioButtons.empty()) + { + mRadioButtons[0]->setTabStop(true); + } + return TRUE; +} // virtual void LLRadioGroup::setEnabled(BOOL enabled) @@ -133,16 +160,39 @@ void LLRadioGroup::setIndexEnabled(S32 index, BOOL enabled) BOOL LLRadioGroup::setSelectedIndex(S32 index, BOOL from_event) { - if (index < 0 || index >= (S32)mRadioButtons.size()) + if ((S32)mRadioButtons.size() <= index ) { return FALSE; } + if (mSelectedIndex >= 0) + { + LLRadioCtrl* old_radio_item = mRadioButtons[mSelectedIndex]; + old_radio_item->setTabStop(false); + old_radio_item->setValue( FALSE ); + } + else + { + mRadioButtons[0]->setTabStop(false); + } + mSelectedIndex = index; + if (mSelectedIndex >= 0) + { + LLRadioCtrl* radio_item = mRadioButtons[mSelectedIndex]; + radio_item->setTabStop(true); + radio_item->setValue( TRUE ); + + if (hasFocus()) + { + radio_item->focusFirstItem(FALSE, FALSE); + } + } + if (!from_event) { - setControlValue(getSelectedIndex()); + setControlValue(getValue()); } return TRUE; @@ -207,41 +257,23 @@ BOOL LLRadioGroup::handleKeyHere(KEY key, MASK mask) return handled; } -void LLRadioGroup::draw() +BOOL LLRadioGroup::handleMouseDown(S32 x, S32 y, MASK mask) { - S32 current_button = 0; - - BOOL take_focus = FALSE; - if (gFocusMgr.childHasKeyboardFocus(this)) - { - take_focus = TRUE; - } - - for (button_list_t::iterator iter = mRadioButtons.begin(); - iter != mRadioButtons.end(); ++iter) + // grab focus preemptively, before child button takes mousecapture + // + if (hasTabStop()) { - LLRadioCtrl* radio = *iter; - BOOL selected = (current_button == mSelectedIndex); - radio->setValue( selected ); - if (take_focus && selected && !gFocusMgr.childHasKeyboardFocus(radio)) - { - // don't flash keyboard focus when navigating via keyboard - BOOL DONT_FLASH = FALSE; - radio->focusFirstItem(FALSE, DONT_FLASH); - } - current_button++; + focusFirstItem(FALSE, FALSE); } - LLView::draw(); + return LLUICtrl::handleMouseDown(x, y, mask); } - // When adding a button, we need to ensure that the radio // group gets a message when the button is clicked. -LLRadioCtrl* LLRadioGroup::addRadioButton(const std::string& name, const std::string& label, const LLRect& rect, const LLFontGL* font ) +LLRadioCtrl* LLRadioGroup::addRadioButton(const std::string& name, const std::string& label, const LLRect& rect, const LLFontGL* font, const std::string& payload) { - // Highlight will get fixed in draw method above - LLRadioCtrl* radio = new LLRadioCtrl(name, rect, label, font, boost::bind(&LLRadioGroup::onClickButton, this, _1)); + LLRadioCtrl* radio = new LLRadioCtrl(name, rect, label, payload, font, boost::bind(&LLRadioGroup::onClickButton, this, _1)); addChild(radio); mRadioButtons.push_back(radio); return radio; @@ -252,7 +284,7 @@ LLRadioCtrl* LLRadioGroup::addRadioButton(const std::string& name, const std::st void LLRadioGroup::onClickButton(LLUICtrl* ctrl) { - // llinfos << "LLRadioGroup::onClickButton" << llendl; + // LL_INFOS() << "LLRadioGroup::onClickButton" << LL_ENDL; LLRadioCtrl* clicked_radio = dynamic_cast(ctrl); if (!clicked_radio) return; @@ -263,9 +295,15 @@ void LLRadioGroup::onClickButton(LLUICtrl* ctrl) LLRadioCtrl* radio = *iter; if (radio == clicked_radio) { - // llinfos << "clicked button " << counter << llendl; - setSelectedIndex(index); - setControlValue(index); + if (index == mSelectedIndex && mAllowDeselect) + { + // don't select anything + setSelectedIndex(-1); + } + else + { + setSelectedIndex(index); + } // BUG: Calls click callback even if button didn't actually change onCommit(); @@ -276,18 +314,17 @@ void LLRadioGroup::onClickButton(LLUICtrl* ctrl) index++; } - llwarns << "LLRadioGroup::onClickButton - clicked button that isn't a child" << llendl; + LL_WARNS() << "LLRadioGroup::onClickButton - clicked button that isn't a child" << LL_ENDL; } void LLRadioGroup::setValue( const LLSD& value ) { - std::string value_name = value.asString(); int idx = 0; for (button_list_t::const_iterator iter = mRadioButtons.begin(); iter != mRadioButtons.end(); ++iter) { LLRadioCtrl* radio = *iter; - if (radio->getName() == value_name) + if (radio->getPayload().asString() == value.asString()) { setSelectedIndex(idx); idx = -1; @@ -304,8 +341,7 @@ void LLRadioGroup::setValue( const LLSD& value ) } else { - llwarns << "LLRadioGroup::setValue: radio_item with name=\"" << value_name << "\" not found, radio_group values are set by radio_item name not value. Falling back on LLUICtrl::setValue." << llendl; - LLUICtrl::setValue(value); + setSelectedIndex(-1, TRUE); } } } @@ -317,7 +353,7 @@ LLSD LLRadioGroup::getValue() const for (button_list_t::const_iterator iter = mRadioButtons.begin(); iter != mRadioButtons.end(); ++iter) { - if (idx == index) return LLSD((*iter)->getName()); + if (idx == index) return LLSD((*iter)->getPayload()); ++idx; } return LLSD(); @@ -333,6 +369,7 @@ LLXMLNodePtr LLRadioGroup::getXML(bool save_children) const // Attributes node->createChild("draw_border", TRUE)->setBoolValue(mHasBorder); + node->createChild("allow_deselect", TRUE)->setBoolValue(mAllowDeselect); // Contents @@ -355,17 +392,21 @@ LLView* LLRadioGroup::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory U32 initial_value = 0; node->getAttributeU32("initial_value", initial_value); - BOOL draw_border = TRUE; - node->getAttributeBOOL("draw_border", draw_border); + bool draw_border = true; + node->getAttribute_bool("draw_border", draw_border); + + bool allow_deselect = false; + node->getAttribute_bool("allow_deselect", allow_deselect); LLRect rect; createRect(node, rect, parent, LLRect()); - LLRadioGroup* radio_group = new LLRadioGroup("radio_group", + LLRadioGroup* radio_group = new LLRadioGroup("radio_group", rect, initial_value, NULL, - draw_border); + draw_border, + allow_deselect); const std::string& contents = node->getValue(); @@ -392,7 +433,7 @@ LLView* LLRadioGroup::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory radio_group->addRadioButton(std::string("radio"), line, rect, font); ++token_iter; } - llwarns << "Legacy radio group format used! Please convert to use tags!" << llendl; + LL_WARNS() << "Legacy radio group format used! Please convert to use tags!" << LL_ENDL; } else { @@ -406,7 +447,13 @@ LLView* LLRadioGroup::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory createRect(child, item_rect, radio_group, rect); std::string item_label = child->getTextContents(); - LLRadioCtrl* radio = radio_group->addRadioButton("radio", item_label, item_rect, font); + child->getAttributeString("label", item_label); + std::string item_name("radio"); + child->getAttributeString("name", item_name); + std::string payload(item_name); // Support old-style name as payload + child->getAttributeString("value", payload); + child->getAttributeString("initial_value", payload); // Synonym + LLRadioCtrl* radio = radio_group->addRadioButton(item_name, item_label, item_rect, font, payload); radio->initFromXML(child, radio_group); } @@ -432,11 +479,10 @@ LLUUID LLRadioGroup::getCurrentID() const BOOL LLRadioGroup::setSelectedByValue(const LLSD& value, BOOL selected) { S32 idx = 0; - std::string value_string = value.asString(); for (button_list_t::const_iterator iter = mRadioButtons.begin(); iter != mRadioButtons.end(); ++iter) { - if((*iter)->getName() == value_string) + if((*iter)->getPayload().asString() == value.asString()) { setSelectedIndex(idx); return TRUE; @@ -455,11 +501,10 @@ LLSD LLRadioGroup::getSelectedValue() BOOL LLRadioGroup::isSelected(const LLSD& value) const { S32 idx = 0; - std::string value_string = value.asString(); for (button_list_t::const_iterator iter = mRadioButtons.begin(); iter != mRadioButtons.end(); ++iter) { - if((*iter)->getName() == value_string) + if((*iter)->getPayload().asString() == value.asString()) { if (idx == mSelectedIndex) { @@ -481,6 +526,17 @@ BOOL LLRadioGroup::operateOnAll(EOperation op) return FALSE; } +LLRadioCtrl::LLRadioCtrl(const std::string& name, const LLRect& rect, const std::string& label, const std::string& value, const LLFontGL* font, commit_callback_t commit_callback) +: LLCheckBoxCtrl(name, rect, label, font, commit_callback, FALSE, RADIO_STYLE), + mPayload(value) +{ + setTabStop(FALSE); + // use name as default "Value" for backwards compatibility + if (value.empty()) + { + mPayload = name; + } +} LLRadioCtrl::~LLRadioCtrl() { @@ -499,7 +555,7 @@ LLXMLNodePtr LLRadioCtrl::getXML(bool save_children) const node->setName(LL_RADIO_ITEM_TAG); - node->setStringValue(getLabel()); + node->createChild("value", TRUE)->setStringValue(mPayload); return node; } diff --git a/indra/llui/llradiogroup.h b/indra/llui/llradiogroup.h index 3cc0422178..e21c7bc1fc 100644 --- a/indra/llui/llradiogroup.h +++ b/indra/llui/llradiogroup.h @@ -37,26 +37,6 @@ #include "llcheckboxctrl.h" #include "llctrlselectioninterface.h" - -/* - * A checkbox control with use_radio_style == true. - */ -class LLRadioCtrl : public LLCheckBoxCtrl -{ -public: - LLRadioCtrl(const std::string& name, const LLRect& rect, const std::string& label, const LLFontGL* font = NULL, - commit_callback_t commit_callback = NULL) : - LLCheckBoxCtrl(name, rect, label, font, commit_callback, FALSE, RADIO_STYLE) - { - setTabStop(FALSE); - } - /*virtual*/ ~LLRadioCtrl(); - - virtual LLXMLNodePtr getXML(bool save_children = true) const; - /*virtual*/ void setValue(const LLSD& value); -}; - - /* * An invisible view containing multiple mutually exclusive toggling * buttons (usually radio buttons). Automatically handles the mutex @@ -66,25 +46,32 @@ class LLRadioGroup : public LLUICtrl, public LLCtrlSelectionInterface { public: - // Radio group constructor. Doesn't rely on - // needing a control + + // Radio group constructor. Doesn't rely on needing a control LLRadioGroup(const std::string& name, const LLRect& rect, S32 initial_index, commit_callback_t commit_callback, - BOOL border = TRUE); + bool border = true, bool allow_deselect = false); + +protected: + friend class LLUICtrlFactory; + +public: virtual ~LLRadioGroup(); + virtual BOOL postBuild(); + + virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); + virtual BOOL handleKeyHere(KEY key, MASK mask); virtual void setEnabled(BOOL enabled); virtual LLXMLNodePtr getXML(bool save_children = true) const; static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); void setIndexEnabled(S32 index, BOOL enabled); - // return the index value of the selected item S32 getSelectedIndex() const { return mSelectedIndex; } - // set the index value programatically BOOL setSelectedIndex(S32 index, BOOL from_event = FALSE); @@ -92,14 +79,10 @@ class LLRadioGroup virtual void setValue(const LLSD& value ); virtual LLSD getValue() const; - // Draw the group, but also fix the highlighting based on the control. - void draw(); - // You must use this method to add buttons to a radio group. // Don't use addChild -- it won't set the callback function // correctly. - LLRadioCtrl* addRadioButton(const std::string& name, const std::string& label, const LLRect& rect, const LLFontGL* font); - LLRadioCtrl* getRadioButton(const S32& index) { return mRadioButtons[index]; } + class LLRadioCtrl* addRadioButton(const std::string& name, const std::string& label, const LLRect& rect, const LLFontGL* font, const std::string& payload = ""); // Update the control as needed. Userdata must be a pointer to the button. void onClickButton(LLUICtrl* clicked_radio); @@ -123,14 +106,15 @@ class LLRadioGroup private: // protected function shared by the two constructors. - void init(BOOL border); + void init(bool border); S32 mSelectedIndex; - typedef std::vector button_list_t; + + typedef std::vector button_list_t; button_list_t mRadioButtons; - BOOL mHasBorder; + bool mHasBorder; + bool mAllowDeselect; // user can click on an already selected option to deselect it }; - #endif diff --git a/indra/llui/llresmgr.cpp b/indra/llui/llresmgr.cpp index 334ead62aa..fc810d567f 100644 --- a/indra/llui/llresmgr.cpp +++ b/indra/llui/llresmgr.cpp @@ -36,6 +36,7 @@ #include "linden_common.h" #include "llresmgr.h" +#include "llimagegl.h" #include "llfontgl.h" #include "llerror.h" #include "llstring.h" @@ -156,10 +157,10 @@ void LLResMgr::setLocale( LLLOCALE_ID locale_id ) case LLLOCALE_USA: //#if LL_WINDOWS // // Windows doesn't use ISO country codes. -// llinfos << "Setting locale to " << setlocale( LC_ALL, "english-usa" ) << llendl; +// LL_INFOS() << "Setting locale to " << setlocale( LC_ALL, "english-usa" ) << LL_ENDL; //#else // // posix version should work everywhere else. -// llinfos << "Setting locale to " << setlocale( LC_ALL, "en_US" ) << llendl; +// LL_INFOS() << "Setting locale to " << setlocale( LC_ALL, "en_US" ) << LL_ENDL; //#endif // mStrings = mUSAStrings; @@ -168,10 +169,10 @@ void LLResMgr::setLocale( LLLOCALE_ID locale_id ) case LLLOCALE_UK: //#if LL_WINDOWS // // Windows doesn't use ISO country codes. -// llinfos << "Setting locale to " << setlocale( LC_ALL, "english-uk" ) << llendl; +// LL_INFOS() << "Setting locale to " << setlocale( LC_ALL, "english-uk" ) << LL_ENDL; //#else // // posix version should work everywhere else. -// llinfos << "Setting locale to " << setlocale( LC_ALL, "en_GB" ) << llendl; +// LL_INFOS() << "Setting locale to " << setlocale( LC_ALL, "en_GB" ) << LL_ENDL; //#endif // mStrings = mUKStrings; @@ -413,7 +414,7 @@ void LLResMgr::getIntegerString( std::string& output, S32 input ) const { if (fraction == remaining_count) { - fraction_string = llformat("%d", fraction); + fraction_string = fmt::to_string(fraction); } else { @@ -468,13 +469,13 @@ LLLocale::LLLocale(const std::string& locale_string) char* new_locale_string = setlocale( LC_ALL, locale_string.c_str()); if ( new_locale_string == NULL && PrevFailedLocaleString != locale_string ) { - llwarns << "Failed to set locale " << locale_string.c_str() << llendl; + LL_WARNS() << "Failed to set locale " << locale_string.c_str() << LL_ENDL; setlocale(LC_ALL, SYSTEM_LOCALE.c_str()); PrevFailedLocaleString = locale_string; } //else //{ - // llinfos << "Set locale to " << new_locale_string << llendl; + // LL_INFOS() << "Set locale to " << new_locale_string << LL_ENDL; //} } diff --git a/indra/llui/llscrollbar.cpp b/indra/llui/llscrollbar.cpp index ca898a4d0f..96912a0f5a 100644 --- a/indra/llui/llscrollbar.cpp +++ b/indra/llui/llscrollbar.cpp @@ -2,31 +2,25 @@ * @file llscrollbar.cpp * @brief Scrollbar UI widget * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -46,6 +40,7 @@ #include "llwindow.h" #include "llcontrol.h" #include "llrender.h" +#include "lluictrlfactory.h" LLScrollbar::LLScrollbar( const std::string& name, LLRect rect, @@ -402,7 +397,7 @@ BOOL LLScrollbar::handleHover(S32 x, S32 y, MASK mask) } getWindow()->setCursor(UI_CURSOR_ARROW); - lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (active)" << llendl; + LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (active)" << LL_ENDL; handled = TRUE; } else @@ -414,7 +409,7 @@ BOOL LLScrollbar::handleHover(S32 x, S32 y, MASK mask) if( !handled ) { getWindow()->setCursor(UI_CURSOR_ARROW); - lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (inactive)" << llendl; + LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (inactive)" << LL_ENDL; handled = TRUE; } @@ -468,6 +463,13 @@ BOOL LLScrollbar::handleMouseUp(S32 x, S32 y, MASK mask) return handled; } +BOOL LLScrollbar::handleDoubleClick(S32 x, S32 y, MASK mask) +{ + // just treat a double click as a second click + return handleMouseDown(x, y, mask); +} + + void LLScrollbar::reshape(S32 width, S32 height, BOOL called_from_parent) { if (width == getRect().getWidth() && height == getRect().getHeight()) return; @@ -502,16 +504,15 @@ void LLScrollbar::draw() BOOL hovered = getEnabled() && !other_captor && (hasMouseCapture() || mThumbRect.pointInRect(local_mouse_x, local_mouse_y)); if (hovered) { - mCurGlowStrength = lerp(mCurGlowStrength, mHoverGlowStrength, LLCriticalDamp::getInterpolant(0.05f)); + mCurGlowStrength = lerp(mCurGlowStrength, mHoverGlowStrength, LLSmoothInterpolation::getInterpolant(0.05f)); } else { - mCurGlowStrength = lerp(mCurGlowStrength, 0.f, LLCriticalDamp::getInterpolant(0.05f)); + mCurGlowStrength = lerp(mCurGlowStrength, 0.f, LLSmoothInterpolation::getInterpolant(0.05f)); } - // Draw background and thumb. - LLUIImage* rounded_rect_imagep = LLUI::getUIImage("rounded_square.tga"); + LLUIImage* rounded_rect_imagep = LLUI::getUIImage("Rounded_Square"); if (!rounded_rect_imagep) { @@ -525,6 +526,9 @@ void LLScrollbar::draw() } else { + // Thumb + LLRect outline_rect = mThumbRect; + outline_rect.stretch(2); // Background rounded_rect_imagep->drawSolid(mOrientation == HORIZONTAL ? SCROLLBAR_SIZE : 0, mOrientation == VERTICAL ? SCROLLBAR_SIZE : 0, @@ -532,9 +536,6 @@ void LLScrollbar::draw() mOrientation == VERTICAL ? getRect().getHeight() - 2 * SCROLLBAR_SIZE : getRect().getHeight(), mTrackColor); - // Thumb - LLRect outline_rect = mThumbRect; - outline_rect.stretch(2); if (gFocusMgr.getKeyboardFocus() == this) { @@ -636,3 +637,8 @@ void LLScrollbar::onLineDownBtnPressed( const LLSD& data ) { changeLine( mStepSize, TRUE ); } + +void LLScrollbar::setThickness(S32 thickness) +{ + mThickness = thickness < 0 ? SCROLLBAR_SIZE : thickness; +} diff --git a/indra/llui/llscrollbar.h b/indra/llui/llscrollbar.h index fab34326cb..2482cce2f0 100644 --- a/indra/llui/llscrollbar.h +++ b/indra/llui/llscrollbar.h @@ -2,31 +2,25 @@ * @file llscrollbar.h * @brief Scrollbar UI widget * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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$ */ @@ -36,6 +30,7 @@ #include "stdtypes.h" #include "lluictrl.h" #include "v4color.h" +#include "llbutton.h" // // Constants @@ -59,6 +54,7 @@ class LLScrollbar callback_t change_callback, S32 step_size = 1); +public: virtual ~LLScrollbar(); virtual void setValue(const LLSD& value); @@ -67,6 +63,7 @@ class LLScrollbar virtual BOOL handleKeyHere(KEY key, MASK mask); virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); + virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask); virtual BOOL handleHover(S32 x, S32 y, MASK mask); virtual BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, @@ -104,6 +101,9 @@ class LLScrollbar void onLineUpBtnPressed(const LLSD& data); void onLineDownBtnPressed(const LLSD& data); + S32 getThickness() const { return mThickness; } + void setThickness(S32 thickness); + void setTrackColor( const LLColor4& color ) { mTrackColor = color; } void setThumbColor( const LLColor4& color ) { mThumbColor = color; } void setHighlightColor( const LLColor4& color ) { mHighlightColor = color; } @@ -145,5 +145,4 @@ class LLScrollbar }; - #endif // LL_SCROLLBAR_H diff --git a/indra/llui/llscrollcontainer.cpp b/indra/llui/llscrollcontainer.cpp index f8998e40a3..778329d1da 100644 --- a/indra/llui/llscrollcontainer.cpp +++ b/indra/llui/llscrollcontainer.cpp @@ -146,7 +146,7 @@ LLScrollContainer::~LLScrollContainer( void ) // virtual void LLScrollContainer::scrollHorizontal( S32 new_pos ) { - //llinfos << "LLScrollContainer::scrollHorizontal()" << llendl; + //LL_INFOS() << "LLScrollContainer::scrollHorizontal()" << LL_ENDL; if( mScrolledView ) { LLRect doc_rect = mScrolledView->getRect(); @@ -158,7 +158,7 @@ void LLScrollContainer::scrollHorizontal( S32 new_pos ) // virtual void LLScrollContainer::scrollVertical( S32 new_pos ) { - // llinfos << "LLScrollContainer::scrollVertical() " << new_pos << llendl; + // LL_INFOS() << "LLScrollContainer::scrollVertical() " << new_pos << LL_ENDL; if( mScrolledView ) { LLRect doc_rect = mScrolledView->getRect(); @@ -218,6 +218,15 @@ BOOL LLScrollContainer::handleKeyHere(KEY key, MASK mask) return FALSE; } +BOOL LLScrollContainer::handleUnicodeCharHere(llwchar uni_char) +{ + if (mScrolledView && mScrolledView->handleUnicodeCharHere(uni_char)) + { + return TRUE; + } + return FALSE; +} + BOOL LLScrollContainer::handleScrollWheel( S32 x, S32 y, S32 clicks ) { // Give event to my child views - they may have scroll bars @@ -262,7 +271,6 @@ BOOL LLScrollContainer::handleDragAndDrop(S32 x, S32 y, MASK mask, EAcceptance* accept, std::string& tooltip_msg) { - //S32 scrollbar_size = SCROLLBAR_SIZE; // Scroll folder view if needed. Never accepts a drag or drop. *accept = ACCEPT_NO; BOOL handled = autoScroll(x, y); @@ -299,7 +307,7 @@ bool LLScrollContainer::autoScroll(S32 x, S32 y) // clip rect against root view inner_rect_local.intersectWith(screen_local_extents); - S32 auto_scroll_speed = llround(mAutoScrollRate * LLFrameTimer::getFrameDeltaTimeF32()); + S32 auto_scroll_speed = ll_round(mAutoScrollRate * LLFrameTimer::getFrameDeltaTimeF32()); // autoscroll region should take up no more than one third of visible scroller area S32 auto_scroll_region_width = llmin(inner_rect_local.getWidth() / 3, 10); S32 auto_scroll_region_height = llmin(inner_rect_local.getHeight() / 3, 10); @@ -413,6 +421,7 @@ void LLScrollContainer::calcVisibleSize( S32 *visible_width, S32 *visible_height } } + void LLScrollContainer::draw() { S32 scrollbar_size = SCROLLBAR_SIZE; @@ -525,7 +534,7 @@ bool LLScrollContainer::addChild(LLView* view, S32 tab_group) void LLScrollContainer::updateScroll() { - if (!mScrolledView) + if (!getVisible() || !mScrolledView) { return; } @@ -626,6 +635,7 @@ LLRect LLScrollContainer::getVisibleContentRect() visible_rect.translate(-contents_rect.mLeft, -contents_rect.mBottom); return visible_rect; } + LLRect LLScrollContainer::getContentWindowRect() { updateScroll(); @@ -648,7 +658,7 @@ void LLScrollContainer::scrollToShowRect(const LLRect& rect, const LLRect& const { if (!mScrolledView) { - llwarns << "LLScrollContainer::scrollToShowRect with no view!" << llendl; + LL_WARNS() << "LLScrollContainer::scrollToShowRect with no view!" << LL_ENDL; return; } @@ -729,6 +739,13 @@ S32 LLScrollContainer::getBorderWidth() const return 0; } +void LLScrollContainer::setSize(S32 size) +{ + mSize = size; + mScrollbar[VERTICAL]->setThickness(size); + mScrollbar[HORIZONTAL]->setThickness(size); +} + // virtual LLXMLNodePtr LLScrollContainer::getXML(bool save_children) const { @@ -760,7 +777,7 @@ LLView* LLScrollContainer::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFa node->getAttributeString("name", name); LLRect rect; - createRect(node, rect, parent, LLRect()); + U32 follows_flags = createRect(node, rect, parent, LLRect()); BOOL opaque = FALSE; node->getAttributeBOOL("opaque", opaque); @@ -771,6 +788,10 @@ LLView* LLScrollContainer::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFa // Create the scroll view LLScrollContainer *ret = new LLScrollContainer(name, rect, (LLPanel*)NULL, opaque, color); + // Obey xml follows + ret->setFollows(follows_flags); + ret->parseFollowsFlags(node); + LLPanel* panelp = NULL; // Find a child panel to add @@ -782,7 +803,7 @@ LLView* LLScrollContainer::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFa { if (panelp) { - llinfos << "Warning! Attempting to put multiple panels into a scrollable container view!" << llendl; + LL_INFOS() << "Warning! Attempting to put multiple panels into a scrollable container view!" << LL_ENDL; delete control; } else @@ -797,7 +818,7 @@ LLView* LLScrollContainer::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFa panelp = new LLPanel(std::string("dummy"), LLRect::null, FALSE); } - ret->mScrolledView = panelp; + ret->addChild(panelp); return ret; } diff --git a/indra/llui/llscrollcontainer.h b/indra/llui/llscrollcontainer.h index 8239789b36..c40b95cbe3 100644 --- a/indra/llui/llscrollcontainer.h +++ b/indra/llui/llscrollcontainer.h @@ -2,31 +2,25 @@ * @file llscrollcontainer.h * @brief LLScrollContainer class header file. * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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$ */ @@ -78,7 +72,7 @@ class LLScrollContainer : public LLUICtrl void setReserveScrollCorner( BOOL b ) { mReserveScrollCorner = b; } LLRect getVisibleContentRect(); LLRect getContentWindowRect(); - const LLRect& getScrolledViewRect() const { return mScrolledView ? mScrolledView->getRect() : LLRect::null; } + virtual const LLRect& getScrolledViewRect() const { return mScrolledView ? mScrolledView->getRect() : LLRect::null; } void pageUp(S32 overlap = 0); void pageDown(S32 overlap = 0); void goToTop(); @@ -90,6 +84,7 @@ class LLScrollContainer : public LLUICtrl // LLView functionality virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); virtual BOOL handleKeyHere(KEY key, MASK mask); + virtual BOOL handleUnicodeCharHere(llwchar uni_char); virtual BOOL handleScrollWheel( S32 x, S32 y, S32 clicks ); virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, @@ -105,9 +100,14 @@ class LLScrollContainer : public LLUICtrl virtual LLXMLNodePtr getXML(bool save_children) const; static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); + S32 getSize() const { return mSize; } + void setSize(S32 thickness); + +protected: + LLView* mScrolledView; + private: void init(); - // internal scrollbar handlers virtual void scrollHorizontal( S32 new_pos ); virtual void scrollVertical( S32 new_pos ); @@ -117,7 +117,6 @@ class LLScrollContainer : public LLUICtrl private: LLScrollbar* mScrollbar[SCROLLBAR_COUNT]; - LLView* mScrolledView; S32 mSize; BOOL mIsOpaque; LLColor4 mBackgroundColor; diff --git a/indra/llui/llscrolllistcell.cpp b/indra/llui/llscrolllistcell.cpp index 8ebf6bc04b..24a81cf941 100644 --- a/indra/llui/llscrolllistcell.cpp +++ b/indra/llui/llscrolllistcell.cpp @@ -203,7 +203,7 @@ LLScrollListText::LLScrollListText(const LLScrollListCell::Params& p) // initialize rounded rect image if (!mRoundedRectImage) { - mRoundedRectImage = LLUI::getUIImage("rounded_square.tga"); + mRoundedRectImage = LLUI::getUIImage("Rounded_Square"); } } @@ -254,7 +254,7 @@ BOOL LLScrollListText::getVisible() const //virtual S32 LLScrollListText::getHeight() const { - return llround(mFont->getLineHeight()); + return ll_round(mFont->getLineHeight()); } @@ -326,7 +326,7 @@ void LLScrollListText::draw(const LLColor4& color, const LLColor4& highlight_col break; } LLRect highlight_rect(left - 2, - llround(mFont->getLineHeight()) + 1, + ll_round(mFont->getLineHeight()) + 1, left + mFont->getWidth(mText.getString(), mHighlightOffset, mHighlightCount) + 1, 1); mRoundedRectImage->draw(highlight_rect, highlight_color); @@ -438,13 +438,14 @@ void LLScrollListCheck::setEnabled(BOOL enable) LLScrollListDate::LLScrollListDate( const LLScrollListCell::Params& p) : LLScrollListText(p), + mFormat(p.format), mDate(p.value().asDate()) {} void LLScrollListDate::setValue(const LLSD& value) { mDate = value.asDate(); - LLScrollListText::setValue(mDate.asRFC1123()); + LLScrollListText::setValue(mFormat.empty() ? mDate.asRFC1123() : mDate.toHTTPDateString(mFormat)); } const LLSD LLScrollListDate::getValue() const diff --git a/indra/llui/llscrolllistcell.h b/indra/llui/llscrolllistcell.h index 3e4a9cd061..3cbdc6d3ee 100644 --- a/indra/llui/llscrolllistcell.h +++ b/indra/llui/llscrolllistcell.h @@ -61,6 +61,7 @@ class LLScrollListCell Optional userdata; Optional value; Optional tool_tip; + Optional format; Optional font; Optional font_color; @@ -77,6 +78,7 @@ class LLScrollListCell visible("visible", true), value("value"), tool_tip("tool_tip", ""), + format("format", "%D %T"), font("font"/*, LLFontGL::getFontSansSerifSmall()*/), font_color("font_color", LLColor4::black), font_style("font-style"), @@ -230,6 +232,7 @@ class LLScrollListDate : public LLScrollListText virtual const LLSD getValue() const; private: + std::string mFormat; LLDate mDate; }; diff --git a/indra/llui/llscrolllistcolumn.cpp b/indra/llui/llscrolllistcolumn.cpp index 6353528c4f..72d4b3d01a 100644 --- a/indra/llui/llscrolllistcolumn.cpp +++ b/indra/llui/llscrolllistcolumn.cpp @@ -40,9 +40,10 @@ const S32 MIN_COLUMN_WIDTH = 20; //--------------------------------------------------------------------------- // LLScrollColumnHeader //--------------------------------------------------------------------------- -LLScrollColumnHeader::LLScrollColumnHeader(const std::string& name, const LLRect& rect, LLScrollListColumn* column) -: LLButton(name, rect, "square_btn_32x128.tga", "square_btn_selected_32x128.tga", LLStringUtil::null, NULL, LLFontGL::getFontSansSerifSmall()), +LLScrollColumnHeader::LLScrollColumnHeader(const std::string& name, const LLRect& rect, LLScrollListColumn* column, const std::string& unselected_image_name, const std::string& selected_image_name) +: LLButton(name, rect, unselected_image_name, selected_image_name, LLStringUtil::null, NULL, LLFontGL::getFontSansSerifSmall()), mColumn(column), + mDrawArrow(true), mHasResizableElement(FALSE) { setClickedCallback(boost::bind(&LLScrollColumnHeader::onClick, this, _2)); @@ -65,20 +66,23 @@ LLScrollColumnHeader::~LLScrollColumnHeader() void LLScrollColumnHeader::draw() { - std::string sort_column = mColumn->mParentCtrl->getSortColumnName(); - BOOL draw_arrow = !mColumn->mLabel.empty() - && mColumn->mParentCtrl->isSorted() - // check for indirect sorting column as well as column's sorting name - && (sort_column == mColumn->mSortingColumn || sort_column == mColumn->mName); - - BOOL is_ascending = mColumn->mParentCtrl->getSortAscending(); - if (draw_arrow) + if (mDrawArrow) { - setImageOverlay(is_ascending ? "up_arrow.tga" : "down_arrow.tga", LLFontGL::RIGHT, LLColor4::white); - } - else - { - setImageOverlay(LLUUID::null); + std::string sort_column = mColumn->mParentCtrl->getSortColumnName(); + BOOL draw_arrow = !mColumn->mLabel.empty() + && mColumn->mParentCtrl->isSorted() + // check for indirect sorting column as well as column's sorting name + && (sort_column == mColumn->mSortingColumn || sort_column == mColumn->mName); + + BOOL is_ascending = mColumn->mParentCtrl->getSortAscending(); + if (draw_arrow) + { + setImageOverlay(is_ascending ? "up_arrow.tga" : "down_arrow.tga", LLFontGL::RIGHT, LLColor4::white); + } + else + { + setImageOverlay(LLUUID::null); + } } // Draw children @@ -245,8 +249,8 @@ void LLScrollColumnHeader::handleReshape(const LLRect& new_rect, bool by_user) // tell scroll list to layout columns again // do immediate update to get proper feedback to resize handle // which needs to know how far the resize actually went - mColumn->mParentCtrl->dirtyColumns(); //Must flag as dirty, else updateColumns will probably be a noop. - mColumn->mParentCtrl->updateColumns(); + const bool force_update = true; + mColumn->mParentCtrl->updateColumns(force_update); } } diff --git a/indra/llui/llscrolllistcolumn.h b/indra/llui/llscrolllistcolumn.h index 2026e075c5..c7cea5976a 100644 --- a/indra/llui/llscrolllistcolumn.h +++ b/indra/llui/llscrolllistcolumn.h @@ -40,7 +40,7 @@ class LLScrollListCtrl; class LLScrollColumnHeader : public LLButton { public: - LLScrollColumnHeader(const std::string& name, const LLRect& rect, LLScrollListColumn* column); + LLScrollColumnHeader(const std::string& name, const LLRect& rect, LLScrollListColumn* column, const std::string& unselected_image_name = "square_btn_32x128.tga", const std::string& selected_image_name = "square_btn_selected_32x128.tga"); ~LLScrollColumnHeader(); /*virtual*/ void draw(); @@ -51,6 +51,8 @@ class LLScrollColumnHeader : public LLButton /*virtual*/ void handleReshape(const LLRect& new_rect, bool by_user = false); LLScrollListColumn* getColumn() { return mColumn; } + // Singu Note: Toggles drawing the sort arrow altogether + void setDrawArrow(bool draw_arrow) { mDrawArrow = draw_arrow; } void setHasResizableElement(BOOL resizable); void updateResizeBars(); BOOL canResize(); @@ -60,6 +62,7 @@ class LLScrollColumnHeader : public LLButton private: LLScrollListColumn* mColumn; + bool mDrawArrow; LLResizeBar* mResizeBar; BOOL mHasResizableElement; }; diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index f76b21762d..4b8844d33e 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -54,13 +54,15 @@ #include "llsdparam.h" #include "llmenugl.h" +#include + static LLRegisterWidget r("scroll_list"); // local structures & classes. struct SortScrollListItem { - SortScrollListItem(const std::vector >& sort_orders,const LLScrollListCtrl::sort_signal_t* sort_signal) + SortScrollListItem(const std::vector& sort_orders,const LLScrollListCtrl::sort_signal_t* sort_signal) : mSortOrders(sort_orders) , mSortSignal(sort_signal) {} @@ -100,7 +102,7 @@ struct SortScrollListItem } - typedef std::vector > sort_order_t; + typedef std::vector sort_order_t; const LLScrollListCtrl::sort_signal_t* mSortSignal; const sort_order_t& mSortOrders; }; @@ -123,6 +125,7 @@ LLScrollListCtrl::LLScrollListCtrl(const std::string& name, const LLRect& rect, mNeedsScroll(false), mCanSelect(true), mColumnsDirty(false), + mSortEnabled(true), mMaxItemCount(INT_MAX), mMaxContentWidth(0), mBorderThickness( 2 ), @@ -154,6 +157,7 @@ LLScrollListCtrl::LLScrollListCtrl(const std::string& name, const LLRect& rect, mFgUnselectedColor(LLUI::sColorsGroup->getColor("ScrollUnselectedColor")), mFgDisabledColor(LLUI::sColorsGroup->getColor("ScrollDisabledColor")), mHighlightedColor(LLUI::sColorsGroup->getColor("ScrollHighlightedColor")), + mFilter(), mSearchColumn(0), mColumnPadding(5) { @@ -192,7 +196,8 @@ LLScrollListCtrl::LLScrollListCtrl(const std::string& name, const LLRect& rect, addChild(mBorder); } - LLTextBox* textBox = new LLTextBox("comment_text",mItemListRect,std::string()); + LLTextBox* textBox = new LLTextBox("comment_text",mItemListRect, LLStringUtil::null); + mCommentTextView = textBox; textBox->setBorderVisible(false); textBox->setFollows(FOLLOWS_ALL); textBox->setFontShadow(LLFontGL::NO_SHADOW); @@ -307,14 +312,14 @@ std::vector LLScrollListCtrl::getAllSelected() const return ret; } -uuid_vec_t LLScrollListCtrl::getSelectedIDs() +uuid_vec_t LLScrollListCtrl::getSelectedIDs() const { - LLUUID selected_id; uuid_vec_t ids; - std::vector selected = this->getAllSelected(); - for(std::vector::iterator itr = selected.begin(); itr != selected.end(); ++itr) + if (!getCanSelect()) return ids; + + for(const auto& item : mItemList) { - ids.push_back((*itr)->getUUID()); + if (item->getSelected()) ids.push_back(item->getUUID()); } return ids; } @@ -397,6 +402,17 @@ std::vector LLScrollListCtrl::getAllData() const return ret; } +uuid_vec_t LLScrollListCtrl::getAllIDs() const +{ + uuid_vec_t ret; + ret.reserve(mItemList.size()); //Optimization + for(const auto& item : mItemList) + { + ret.push_back(item->getUUID()); + } + return ret; +} + // returns first matching item LLScrollListItem* LLScrollListCtrl::getItem(const LLSD& sd) const { @@ -440,23 +456,27 @@ void LLScrollListCtrl::updateLayout() mCommentTextView->setShape(mItemListRect); + adjustScrollbar(mFilter.empty() ? getItemCount() : mScrollbar->getDocSize()); // Doc size is the item count without a filter, otherwise it's calculated whenever filter is updated + dirtyColumns(); +} + +void LLScrollListCtrl::adjustScrollbar(S32 doc_size) +{ // how many lines of content in a single "page" - S32 page_lines = getLinesPerPage(); + S32 page_lines = getLinesPerPage(); - BOOL scrollbar_visible = mLineHeight * getItemCount() > mItemListRect.getHeight(); + bool scrollbar_visible = mLineHeight * doc_size > mItemListRect.getHeight(); if (scrollbar_visible) { // provide space on the right for scrollbar mItemListRect.mRight = getRect().getWidth() - mBorderThickness - SCROLLBAR_SIZE; + mScrollbar->setOrigin(mItemListRect.mRight, mItemListRect.mBottom); + mScrollbar->reshape(SCROLLBAR_SIZE, mItemListRect.getHeight() + (mDisplayColumnHeaders ? mHeadingHeight : 0)); } - mScrollbar->setOrigin(getRect().getWidth() - mBorderThickness - SCROLLBAR_SIZE, mItemListRect.mBottom); - mScrollbar->reshape(SCROLLBAR_SIZE, mItemListRect.getHeight() + (mDisplayColumnHeaders ? mHeadingHeight : 0)); mScrollbar->setPageSize(page_lines); - mScrollbar->setDocSize( getItemCount() ); + mScrollbar->setDocSize(doc_size); mScrollbar->setVisible(scrollbar_visible); - - dirtyColumns(); } // Attempt to size the control to show all items. @@ -490,6 +510,9 @@ BOOL LLScrollListCtrl::addItem( LLScrollListItem* item, EAddPosition pos, BOOL r BOOL not_too_big = getItemCount() < mMaxItemCount; if (not_too_big) { + if (!mFilter.empty() && !filterItem(item)) // If we're filtering, filter this item if needed, if not, bump the document size. + mScrollbar->setDocSize(mScrollbar->getDocSize()+1); + switch( pos ) { case ADD_TOP: @@ -499,12 +522,14 @@ BOOL LLScrollListCtrl::addItem( LLScrollListItem* item, EAddPosition pos, BOOL r case ADD_SORTED: { - // sort by column 0, in ascending order - std::vector single_sort_column; - single_sort_column.push_back(std::make_pair(0, TRUE)); - mItemList.push_back(item); - std::stable_sort(mItemList.begin(), mItemList.end(), SortScrollListItem(single_sort_column,mSortCallback)); + // std::stable_sort is expensive. Only do this if the user sort criteria is not column 0, otherwise + // setNeedsSort does what we want. + if (mSortColumns.empty() || mSortColumns[0].first != 0) + { + // sort by column 0, in ascending order + std::stable_sort(mItemList.begin(), mItemList.end(), SortScrollListItem({ {0,true} }, mSortCallback)); + } // ADD_SORTED just sorts by first column... // this might not match user sort criteria, so flag list as being in unsorted state @@ -568,13 +593,13 @@ S32 LLScrollListCtrl::calcMaxContentWidth() if (mColumnWidthsDirty) { - mColumnWidthsDirty = false; // update max content width for this column, by looking at all items - column->mMaxContentWidth = column->mHeader ? LLFontGL::getFontSansSerifSmall()->getWidth(column->mLabel) + mColumnPadding + HEADING_TEXT_PADDING : 0; - item_list::iterator iter; - for (iter = mItemList.begin(); iter != mItemList.end(); iter++) + column->mMaxContentWidth = column->mHeader ? LLFontGL::getFontSansSerifSmall()->getWidth(column->mLabel.getWString()) + mColumnPadding + HEADING_TEXT_PADDING : 0; + for (auto& item : mItemList) { - LLScrollListCell* cellp = (*iter)->getColumn(column->mIndex); + if (item->getFiltered()) continue; + + LLScrollListCell* cellp = item->getColumn(column->mIndex); if (!cellp) continue; column->mMaxContentWidth = llmax(LLFontGL::getFontSansSerifSmall()->getWidth(cellp->getValue().asString()) + mColumnPadding + COLUMN_TEXT_PADDING, column->mMaxContentWidth); @@ -582,6 +607,7 @@ S32 LLScrollListCtrl::calcMaxContentWidth() } max_item_width += column->mMaxContentWidth; } + mColumnWidthsDirty = false; mMaxContentWidth = max_item_width; return max_item_width; @@ -597,15 +623,19 @@ bool LLScrollListCtrl::updateColumnWidths() if (!column) continue; // update column width - S32 new_width = column->getWidth(); + S32 new_width = 0; if (column->mRelWidth >= 0) { - new_width = (S32)llround(column->mRelWidth*mItemListRect.getWidth()); + new_width = (S32)ll_round(column->mRelWidth*mItemListRect.getWidth()); } else if (column->mDynamicWidth) { new_width = (mItemListRect.getWidth() - mTotalStaticColumnWidth - mTotalColumnPadding) / mNumDynamicWidthColumns; } + else + { + new_width = column->getWidth(); + } if (column->getWidth() != new_width) { @@ -623,10 +653,8 @@ const S32 SCROLL_LIST_ROW_PAD = 2; void LLScrollListCtrl::updateLineHeight() { mLineHeight = 0; - item_list::iterator iter; - for (iter = mItemList.begin(); iter != mItemList.end(); iter++) + for (auto& itemp : mItemList) { - LLScrollListItem *itemp = *iter; S32 num_cols = itemp->getNumColumns(); S32 i = 0; for (const LLScrollListCell* cell = itemp->getColumn(i); i < num_cols; cell = itemp->getColumn(++i)) @@ -648,9 +676,9 @@ void LLScrollListCtrl::updateLineHeightInsert(LLScrollListItem* itemp) } -void LLScrollListCtrl::updateColumns() +void LLScrollListCtrl::updateColumns(bool force_update) { - if (!mColumnsDirty) + if (!mColumnsDirty && !force_update) return; mColumnsDirty = false; @@ -704,7 +732,7 @@ void LLScrollListCtrl::updateColumns() } // propagate column widths to individual cells - if (columns_changed_width) + if (columns_changed_width || force_update) { item_list::iterator iter; for (iter = mItemList.begin(); iter != mItemList.end(); iter++) @@ -747,6 +775,7 @@ BOOL LLScrollListCtrl::selectFirstItem() for (iter = mItemList.begin(); iter != mItemList.end(); iter++) { LLScrollListItem *itemp = *iter; + if (itemp->getFiltered()) continue; if( first_item && itemp->getEnabled() ) { if (!itemp->getSelected()) @@ -805,13 +834,13 @@ BOOL LLScrollListCtrl::selectItemRange( S32 first_index, S32 last_index ) iter = mItemList.erase(iter); continue ; } - - if( index >= first_index && index <= last_index ) + + if (index >= first_index && index <= last_index) { - if( itemp->getEnabled() ) + if (itemp->getEnabled()) { selectItem(itemp, FALSE); - success = TRUE; + success = TRUE; } } else @@ -954,6 +983,8 @@ S32 LLScrollListCtrl::selectMultiple( uuid_vec_t ids ) for (iter = mItemList.begin(); iter != mItemList.end(); iter++) { LLScrollListItem* item = *iter; + if (item->getFiltered()) continue; + uuid_vec_t::iterator iditr; for(iditr = ids.begin(); iditr != ids.end(); ++iditr) { @@ -979,15 +1010,14 @@ S32 LLScrollListCtrl::getItemIndex( LLScrollListItem* target_item ) const updateSort(); S32 index = 0; - item_list::const_iterator iter; - for (iter = mItemList.begin(); iter != mItemList.end(); iter++) + for (LLScrollListItem* itemp : mItemList) { - LLScrollListItem *itemp = *iter; + if (itemp->getFiltered()) continue; if (target_item == itemp) { return index; } - index++; + ++index; } return -1; } @@ -997,15 +1027,14 @@ S32 LLScrollListCtrl::getItemIndex( const LLUUID& target_id ) const updateSort(); S32 index = 0; - item_list::const_iterator iter; - for (iter = mItemList.begin(); iter != mItemList.end(); iter++) + for (LLScrollListItem* itemp : mItemList) { - LLScrollListItem *itemp = *iter; + if (itemp->getFiltered()) continue; if (target_id == itemp->getUUID()) { return index; } - index++; + ++index; } return -1; } @@ -1027,6 +1056,7 @@ void LLScrollListCtrl::selectPrevItem( BOOL extend_selection) for (iter = mItemList.begin(); iter != mItemList.end(); iter++) { LLScrollListItem* cur_item = *iter; + if (cur_item->getFiltered()) continue; if (cur_item->getSelected()) { @@ -1071,6 +1101,7 @@ void LLScrollListCtrl::selectNextItem( BOOL extend_selection) for (iter = mItemList.rbegin(); iter != mItemList.rend(); iter++) { LLScrollListItem* cur_item = *iter; + if (cur_item->getFiltered()) continue; if (cur_item->getSelected()) { @@ -1120,7 +1151,7 @@ void LLScrollListCtrl::deselectAllItems(BOOL no_commit_on_change) void LLScrollListCtrl::setCommentText(const std::string& comment_text) { - getChild("comment_text")->setWrappedText(comment_text); + static_cast(mCommentTextView)->setWrappedText(comment_text); } LLScrollListItem* LLScrollListCtrl::addSeparator(EAddPosition pos) @@ -1175,6 +1206,7 @@ LLScrollListItem* LLScrollListCtrl::getItemByLabel(const std::string& label, BOO for (iter = mItemList.begin(); iter != mItemList.end(); iter++) { LLScrollListItem* item = *iter; + std::string item_text = item->getColumn(column)->getValue().asString(); // Only select enabled items with matching names if (!case_sensitive) { @@ -1210,6 +1242,8 @@ BOOL LLScrollListCtrl::selectItemByPrefix(const LLWString& target, BOOL case_sen for (iter = mItemList.begin(); iter != mItemList.end(); iter++) { LLScrollListItem* item = *iter; + if (item->getFiltered()) continue; + // Only select enabled items with matching names LLScrollListCell* cellp = item->getColumn(getSearchColumn()); BOOL select = cellp ? item->getEnabled() && ('\0' == cellp->getValue().asString()[0]) : FALSE; @@ -1233,6 +1267,9 @@ BOOL LLScrollListCtrl::selectItemByPrefix(const LLWString& target, BOOL case_sen { LLScrollListItem* item = *iter; + // Don't select filtered items + if (item->getFiltered()) continue; + // Only select enabled items with matching names LLScrollListCell* cellp = item->getColumn(getSearchColumn()); if (!cellp) @@ -1317,6 +1354,8 @@ BOOL LLScrollListCtrl::setSelectedByValue(const LLSD& value, BOOL selected) for (iter = mItemList.begin(); iter != mItemList.end(); iter++) { LLScrollListItem* item = *iter; + if (item->getFiltered()) continue; + if (item->getEnabled() && (item->getValue().asString() == value.asString())) { if (selected) @@ -1346,7 +1385,7 @@ BOOL LLScrollListCtrl::isSelected(const LLSD& value) const for (iter = mItemList.begin(); iter != mItemList.end(); iter++) { LLScrollListItem* item = *iter; - if (item->getValue().asString() == value.asString()) + if (!item->getFiltered() && item->getValue().asString() == value.asString()) { return item->getSelected(); } @@ -1385,9 +1424,6 @@ void LLScrollListCtrl::drawItems() S32 x = mItemListRect.mLeft; S32 y = mItemListRect.mTop - mLineHeight; - // allow for partial line at bottom - S32 num_page_lines = getLinesPerPage(); - LLRect item_rect; LLGLSUIDefault gls_ui; @@ -1395,70 +1431,102 @@ void LLScrollListCtrl::drawItems() { LLLocalClipRect clip(mItemListRect); - S32 cur_y = y; - - S32 max_columns = 0; - - LLColor4 highlight_color = LLColor4::white; - F32 type_ahead_timeout = LLUI::sConfigGroup->getF32("TypeAheadTimeout"); - highlight_color.mV[VALPHA] = clamp_rescale(mSearchTimer.getElapsedTimeF32(), type_ahead_timeout * 0.7f, type_ahead_timeout, 0.4f, 0.f); + LLRect clip_rect = LLUI::getRootView()->getRect(); + if (LLGLState::isEnabled()) + { + LLRect scissor = gGL.getScissor(); + scissor.mLeft /= LLUI::getScaleFactor().mV[VX]; + scissor.mTop /= LLUI::getScaleFactor().mV[VY]; + scissor.mRight /= LLUI::getScaleFactor().mV[VX]; + scissor.mBottom /= LLUI::getScaleFactor().mV[VY]; + clip_rect.intersectWith(scissor); + } S32 first_line = mScrollLines; - S32 last_line = llmin((S32)mItemList.size() - 1, mScrollLines + getLinesPerPage()); - if ((item_list::size_type)first_line >= mItemList.size()) { return; } - item_list::iterator iter; - for (S32 line = first_line; line <= last_line; line++) - { - LLScrollListItem* item = mItemList[line]; - - item_rect.setOriginAndSize( - x, - cur_y, - mItemListRect.getWidth(), - mLineHeight ); - item->setRect(item_rect); + S32 list_size = mItemList.size() - 1; - //llinfos << item_rect.getWidth() << llendl; + // allow for partial line at bottom + S32 num_page_lines = mFilter.empty() ? getLinesPerPage() : mScrollbar->getDocSize() + 1; + S32 last_line = llmin(list_size, mScrollLines + num_page_lines); - max_columns = llmax(max_columns, item->getNumColumns()); + S32 max_columns = 0; - LLColor4 fg_color; - LLColor4 bg_color(LLColor4::transparent); + LLColor4 highlight_color = LLColor4::white; + static const LLUICachedControl type_ahead_timeout("TypeAheadTimeout"); + highlight_color.mV[VALPHA] = clamp_rescale(mSearchTimer.getElapsedTimeF32(), type_ahead_timeout * 0.7f, type_ahead_timeout, 0.4f, 0.f); - if( mScrollLines <= line && line < mScrollLines + num_page_lines ) + bool done = false; + for (S32 pass = 0; !done; ++pass) + { + bool should_continue = false; // False until all passes are done for all row cells. + S32 cur_y = y; + for (S32 index = first_line, line = first_line; index <= list_size; ++index) { - fg_color = (item->getEnabled() ? mFgUnselectedColor : mFgDisabledColor); - if( item->getSelected() && mCanSelect) - { - bg_color = mBgSelectedColor; - fg_color = (item->getEnabled() ? mFgSelectedColor : mFgDisabledColor); - } - else if (mHighlightedItem == line && mCanSelect) - { - bg_color = mHighlightedColor; - } - else + LLScrollListItem* item = mItemList[index]; + if (item->getFiltered()) continue; // Skip filtered + + item_rect.setOriginAndSize( + x, + cur_y, + mItemListRect.getWidth(), + mLineHeight); + item->setRect(item_rect); + + //LL_INFOS() << item_rect.getWidth() << LL_ENDL; + + max_columns = llmax(max_columns, item->getNumColumns()); + + LLColor4 fg_color; + LLColor4 bg_color(LLColor4::transparent); + { - if (mDrawStripes && (line % 2 == 0) && (max_columns > 1)) + cur_y -= mLineHeight; + + // Do not draw if not on screen. + LLRect screen_rect = item_rect; + screen_rect.translate(LLFontGL::sCurOrigin.mX, LLFontGL::sCurOrigin.mY); + if (!clip_rect.overlaps(screen_rect)) { - bg_color = mBgStripeColor; + continue; } - } - if (!item->getEnabled()) - { - bg_color = mBgReadOnlyColor; - } + fg_color = (item->getEnabled() ? mFgUnselectedColor : mFgDisabledColor); + if (item->getSelected() && mCanSelect) + { + bg_color = mBgSelectedColor; + fg_color = (item->getEnabled() ? mFgSelectedColor : mFgDisabledColor); + } + else if (mHighlightedItem == line && mCanSelect) + { + bg_color = mHighlightedColor; + } + else + { + if (mDrawStripes && (line % 2 == 0) && (max_columns > 1)) + { + bg_color = mBgStripeColor; + } + } - item->draw(item_rect, fg_color, bg_color, highlight_color, mColumnPadding); + if (!item->getEnabled()) + { + bg_color = mBgReadOnlyColor; + } - cur_y -= mLineHeight; + should_continue |= item->draw(pass, item_rect, fg_color, bg_color, highlight_color, mColumnPadding); + if (++line > last_line) + { + break; // Don't draw any more than needed. + } + } } + done = !should_continue; } + } } @@ -1486,7 +1554,7 @@ void LLScrollListCtrl::draw() updateColumns(); - getChildView("comment_text")->setVisible(mItemList.empty()); + mCommentTextView->setVisible(mItemList.empty()); drawItems(); @@ -1604,9 +1672,10 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask) // meaning that we never stop selecting until hitting max or // the end of the list. LLScrollListItem* lastSelected = mLastSelected; + auto selected_count = getAllSelected().size(); for (itor = mItemList.begin(); itor != mItemList.end(); ++itor) { - if(mMaxSelectable > 0 && getAllSelected().size() >= mMaxSelectable) + if(mMaxSelectable > 0 && selected_count >= mMaxSelectable) { if(mOnMaximumSelectCallback) { @@ -1615,6 +1684,7 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask) break; } LLScrollListItem *item = *itor; + if (item->getFiltered()) continue; if (item == hit_item || item == lastSelected) { selectItem(item, FALSE); @@ -1629,6 +1699,7 @@ BOOL LLScrollListCtrl::selectItemAt(S32 x, S32 y, MASK mask) { selectItem(item, FALSE); } + ++selected_count; } } } @@ -1740,10 +1811,7 @@ BOOL LLScrollListCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask) if (col->mHeader && col->mHeader->getRect().pointInRect(x,y)) // Right clicking a column header shouldn't bring up a menu return FALSE; } - gFocusMgr.setKeyboardFocus(this); // Menu listeners rely on this - mPopupMenu->buildDrawLabels(); - mPopupMenu->updateParent(LLMenuGL::sMenuContainer); - LLMenuGL::showPopup(this, mPopupMenu, x, y); + showMenu(this, mPopupMenu, x, y); return TRUE; } @@ -1756,17 +1824,19 @@ BOOL LLScrollListCtrl::handleDoubleClick(S32 x, S32 y, MASK mask) { // Offer the click to the children, even if we aren't enabled // so the scroll bars will work. - if (NULL == LLView::childrenHandleDoubleClick(x, y, mask)) + handled = LLView::childrenHandleDoubleClick(x, y, mask) != nullptr; + if (!handled) { // Run the callback only if an item is being double-clicked. - if( mCanSelect && hitItem(x, y) && mOnDoubleClickCallback ) + if (mCanSelect && mOnDoubleClickCallback && hitItem(x, y)) { mOnDoubleClickCallback(); + handled = true; } } } - return TRUE; + return handled; } BOOL LLScrollListCtrl::handleClick(S32 x, S32 y, MASK mask) @@ -1839,15 +1909,16 @@ LLScrollListItem* LLScrollListCtrl::hitItem( S32 x, S32 y ) // allow for partial line at bottom S32 num_page_lines = getLinesPerPage(); + S32 list_size = mItemList.size() - 1; + S32 last_line = llmin(list_size, mScrollLines + num_page_lines); - S32 line = 0; - item_list::iterator iter; - for(iter = mItemList.begin(); iter != mItemList.end(); iter++) + for (S32 index = mScrollLines, line = mScrollLines; index <= list_size; ++index) { - LLScrollListItem* item = *iter; - if( mScrollLines <= line && line < mScrollLines + num_page_lines ) + LLScrollListItem* item = mItemList[index]; + if (item->getFiltered()) continue; + { - if( item->getEnabled() && item_rect.pointInRect( x, y ) ) + if (item->getEnabled() && item_rect.pointInRect( x, y )) { hit_item = item; break; @@ -1855,7 +1926,7 @@ LLScrollListItem* LLScrollListCtrl::hitItem( S32 x, S32 y ) item_rect.translate(0, -mLineHeight); } - line++; + if (++line > last_line) break; // Don't try to hit any undrawn items } return hit_item; @@ -1913,6 +1984,63 @@ S32 LLScrollListCtrl::getRowOffsetFromIndex(S32 index) return row_bottom; } +bool LLScrollListCtrl::filterItem(LLScrollListItem* item) +{ + for (const auto& column : item->mColumns) + { + // Only filter text, search tooltip because it'll usually be the text anyway. + if (column->isText() && boost::icontains(column->getToolTip(), mFilter)) + { + item->setFiltered(false); + return false; + } + } + item->setFiltered(true); + return true; +} + +void LLScrollListCtrl::setFilter(const std::string& filter) +{ + if (filter == mFilter) return; + + bool no_filter = filter.empty(); + // If our filter string has been expanded, we can skip already filtered items + bool expanded = !no_filter && !mFilter.empty() && boost::icontains(filter, mFilter); + // If our filter string has been contracted, we can skip already unfiltered items + bool contracted = !no_filter && !mFilter.empty() && !expanded && boost::icontains(mFilter, filter); + bool unique = !expanded && !contracted; + + mFilter = filter; + S32 unfiltered_count = no_filter ? mItemList.size() // No filter, doc size is all items + : !unique ? mScrollbar->getDocSize() // Expanded/contracted filter, start with the current doc size and remove/add respectively + : 0; // Different filter, count up from 0; + for (auto& item : mItemList) + { + if (no_filter) item->setFiltered(false); + else if (expanded && !item->getFiltered()) // Filter has been expanded and we are not yet filtered + { + if (filterItem(item)) --unfiltered_count; // We are now filtered, lower the count + } + else if (unique || // Filter isn't expanded, find out if we should be filtered or + (contracted && item->getFiltered())) // Filter has contracted and we were filtered before, should we still be? + { + if (!filterItem(item)) ++unfiltered_count; // Wasn't filltered, bump count + } + } + + if (mLastSelected && mLastSelected->getFiltered()) // Remove selection if filtered. + mLastSelected = nullptr; + + // Scrollbar needs adjusted + setScrollPos(0); // Changing the filter resets scroll position + adjustScrollbar(unfiltered_count); +} + +void LLScrollListCtrl::setContextMenu(const std::string& menu) +{ + setContextMenu(LLUICtrlFactory::instance().buildMenu(menu, LLMenuGL::sMenuContainer)); +} + BOOL LLScrollListCtrl::handleHover(S32 x,S32 y,MASK mask) { @@ -2142,26 +2270,28 @@ BOOL LLScrollListCtrl::handleUnicodeCharHere(llwchar uni_char) while(iter != start_iter) { LLScrollListItem* item = *iter; - - LLScrollListCell* cellp = item->getColumn(getSearchColumn()); - if (cellp) + if (!item->getFiltered()) { - // Only select enabled items with matching first characters - LLWString item_label = utf8str_to_wstring(cellp->getValue().asString()); - if (item->getEnabled() && LLStringOps::toLower(item_label[0]) == uni_char) + LLScrollListCell* cellp = item->getColumn(getSearchColumn()); + if (cellp) { - selectItem(item); - mNeedsScroll = true; - cellp->highlightText(0, 1); - mSearchTimer.reset(); - - if (mCommitOnKeyboardMovement - && !mCommitOnSelectionChange) + // Only select enabled items with matching first characters + LLWString item_label = utf8str_to_wstring(cellp->getValue().asString()); + if (item->getEnabled() && LLStringOps::toLower(item_label[0]) == uni_char) { - onCommit(); - } + selectItem(item); + mNeedsScroll = true; + cellp->highlightText(0, 1); + mSearchTimer.reset(); - break; + if (mCommitOnKeyboardMovement + && !mCommitOnSelectionChange) + { + onCommit(); + } + + break; + } } } @@ -2262,7 +2392,7 @@ struct SameSortColumn SameSortColumn(S32 column) : mColumn(column) {} S32 mColumn; - bool operator()(std::pair sort_column) { return sort_column.first == mColumn; } + bool operator()(LLScrollListCtrl::sort_column_t sort_column) { return sort_column.first == mColumn; } }; BOOL LLScrollListCtrl::setSort(S32 column_idx, BOOL ascending) @@ -2296,6 +2426,16 @@ BOOL LLScrollListCtrl::setSort(S32 column_idx, BOOL ascending) } } +void LLScrollListCtrl::setSortEnabled(bool sort) +{ + bool update = sort && !mSortEnabled; + mSortEnabled = sort; + if (update) + { + updateSort(); + } +} + S32 LLScrollListCtrl::getLinesPerPage() { //if mPageLines is NOT provided display all item @@ -2317,6 +2457,12 @@ void LLScrollListCtrl::onScrollChange( S32 new_pos, LLScrollbar* scrollbar ) } +void LLScrollListCtrl::setSortOrder(const sort_order_t& order) +{ + mSortColumns = order; + updateSort(); +} + void LLScrollListCtrl::sortByColumn(const std::string& name, BOOL ascending) { column_map_t::iterator itor = mColumns.find(name); @@ -2350,7 +2496,7 @@ void LLScrollListCtrl::updateSort() const // for one-shot sorts, does not save sort column/order void LLScrollListCtrl::sortOnce(S32 column, BOOL ascending) { - std::vector > sort_column; + std::vector sort_column; sort_column.push_back(std::make_pair(column, ascending)); // do stable sort to preserve any previous sorts @@ -2552,53 +2698,45 @@ void LLScrollListCtrl::setScrollListParameters(LLXMLNodePtr node) node->getAttribute_bool("mouse_wheel_opaque", mMouseWheelOpaque); } - if (node->hasAttribute("menu_file")) + if (node->hasAttribute("menu_num")) { - std::string menu_file; - node->getAttributeString("menu_file", menu_file); - mPopupMenu = LLUICtrlFactory::getInstance()->buildMenu(menu_file, LLMenuGL::sMenuContainer); + // Some UI uses common menus identified by number + // 0 is avatars, 1 will be for groups, others could be for lists of objects or locations or experiences + S32 menu_num; + node->getAttributeS32("menu_num", menu_num); + mPopupMenu = sMenus[menu_num]; + } + else if (node->hasAttribute("menu_file")) + { + std::string menu; + node->getAttributeString("menu_file", menu); + if (!menu.empty()) setContextMenu(menu); } -} - -// static -LLView* LLScrollListCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) -{ - LLRect rect; - createRect(node, rect, parent, LLRect()); - - BOOL multi_select = false; - node->getAttributeBOOL("multi_select", multi_select); - BOOL draw_border = true; - node->getAttributeBOOL("draw_border", draw_border); - BOOL draw_heading = false; - node->getAttributeBOOL("draw_heading", draw_heading); - S32 search_column = 0; - node->getAttributeS32("search_column", search_column); - S32 sort_column = -1; - node->getAttributeS32("sort_column", sort_column); - BOOL sort_ascending = true; - node->getAttributeBOOL("sort_ascending", sort_ascending); - - LLScrollListCtrl* scroll_list = new LLScrollListCtrl("scroll_list", rect, NULL, multi_select, draw_border, draw_heading); if (node->hasAttribute("heading_height")) { S32 heading_height; node->getAttributeS32("heading_height", heading_height); - scroll_list->setHeadingHeight(heading_height); + setHeadingHeight(heading_height); } - scroll_list->setScrollListParameters(node); - scroll_list->initFromXML(node, parent); - scroll_list->setSearchColumn(search_column); + S32 search_column = 0; + node->getAttributeS32("search_column", search_column); + BOOL sort_ascending = true; + node->getAttributeBOOL("sort_ascending", sort_ascending); + + setSearchColumn(search_column); LLSD columns; S32 index = 0; + const std::string nodename(std::string(node->getName()->mString) + '.'); + const std::string kidcolumns(nodename + "columns"); + const std::string kidcolumn(nodename + "column"); for (LLXMLNodePtr child = node->getFirstChild(); child.notNull(); child = child->getNextSibling()) { - if (child->hasName("column")) + if (child->hasName("column") || child->hasName("columns") || child->hasName(kidcolumn) || child->hasName(kidcolumns)) { - std::string labelname(""); + std::string labelname; if (child->getAttributeString("label", labelname)) columns[index]["label"] = labelname; else if (child->getAttributeString("image", labelname)) @@ -2621,9 +2759,9 @@ LLView* LLScrollListCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFac } else // Singu Note: if a scroll list does not provide sort_direction, provide sort_ascending to sort as expected { - bool sort_ascending = true; - child->getAttribute_bool("sort_ascending", sort_ascending); - columns[index]["sort_ascending"] = sort_ascending; + bool col_sort_ascending = sort_ascending; + child->getAttribute_bool("sort_ascending", col_sort_ascending); + columns[index]["sort_ascending"] = col_sort_ascending; } S32 columnwidth = -1; @@ -2649,16 +2787,13 @@ LLView* LLScrollListCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFac ++index; } } - scroll_list->setColumnHeadings(columns); - - if (sort_column >= 0) - { - scroll_list->sortByColumnIndex(sort_column, sort_ascending); - } + setColumnHeadings(columns); + const std::string kidrow(nodename + "row"); + const std::string kidrows(nodename + "rows"); for (LLXMLNodePtr child = node->getFirstChild(); child.notNull(); child = child->getNextSibling()) { - if (child->hasName("row") || child->hasName("rows")) + if (child->hasName("row") || child->hasName(kidrow) || child->hasName("rows") || child->hasName(kidrows)) { LLUUID id; LLSD row; @@ -2674,20 +2809,21 @@ LLView* LLScrollListCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFac bool explicit_column = false; for (LLXMLNodePtr row_child = child->getFirstChild(); row_child.notNull(); row_child = row_child->getNextSibling()) { - if (row_child->hasName("column")) + if (row_child->hasName("column") || row_child->hasName("columns")) { std::string value = row_child->getTextContents(); + row_child->getAttributeString("value", value); row["columns"][column_idx]["value"] = value; - std::string columnname(""); + std::string columnname; if (row_child->getAttributeString("name", columnname)) row["columns"][column_idx]["column"] = columnname; - std::string font(""); + std::string font; if (row_child->getAttributeString("font", font)) row["columns"][column_idx]["font"] = font; - std::string font_style(""); + std::string font_style; if (row_child->getAttributeString("font-style", font_style)) row["columns"][column_idx]["font-style"] = font_style; @@ -2696,33 +2832,58 @@ LLView* LLScrollListCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFac } } if(explicit_column) - scroll_list->addElement(row); + addElement(row); else { LLSD entry_id; if(id_found) entry_id = id; - scroll_list->addSimpleElement(value,ADD_BOTTOM,entry_id); + addSimpleElement(value,ADD_BOTTOM,entry_id); } } } - scroll_list->setCommentText(node->getTextContents()); + S32 sort_column = -1; + node->getAttributeS32("sort_column", sort_column); + if (sort_column >= 0) + { + sortByColumnIndex(sort_column, sort_ascending); + } + + setCommentText(node->getTextContents()); +} + +// static +LLView* LLScrollListCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) +{ + LLRect rect; + createRect(node, rect, parent, LLRect()); + + BOOL multi_select = false; + node->getAttributeBOOL("multi_select", multi_select); + + BOOL draw_border = true; + node->getAttributeBOOL("draw_border", draw_border); + + BOOL draw_heading = false; + node->getAttributeBOOL("draw_heading", draw_heading); + + LLScrollListCtrl* scroll_list = new LLScrollListCtrl("scroll_list", rect, NULL, multi_select, draw_border, draw_heading); + + scroll_list->setScrollListParameters(node); + scroll_list->initFromXML(node, parent); return scroll_list; } // LLEditMenuHandler functions // virtual -void LLScrollListCtrl::copy() +void LLScrollListCtrl::copy() const { std::string buffer; - - std::vector items = getAllSelected(); - std::vector::iterator itor; - for (itor = items.begin(); itor != items.end(); ++itor) + for (auto item : getAllSelected()) { - buffer += (*itor)->getContentsCSV() + "\n"; + buffer += item->getContentsCSV() + '\n'; } gClipboard.copyFromSubstring(utf8str_to_wstring(buffer), 0, buffer.length()); } @@ -2754,7 +2915,7 @@ void LLScrollListCtrl::selectAll() for (iter = mItemList.begin(); iter != mItemList.end(); iter++) { LLScrollListItem *itemp = *iter; - if( itemp->getEnabled() ) + if (itemp->getEnabled() && !itemp->getFiltered()) { selectItem(itemp, FALSE); } @@ -2819,7 +2980,7 @@ void LLScrollListCtrl::addColumn(const LLScrollListColumn::Params& column_params } if (new_column->mRelWidth >= 0) { - new_column->setWidth((S32)llround(new_column->mRelWidth*mItemListRect.getWidth())); + new_column->setWidth((S32)ll_round(new_column->mRelWidth*mItemListRect.getWidth())); } else if(new_column->mDynamicWidth) { @@ -2848,24 +3009,29 @@ void LLScrollListCtrl::addColumn(const LLScrollListColumn::Params& column_params LLRect temp_rect = LLRect(left,top+mHeadingHeight,right,top); - new_column->mHeader = new LLScrollColumnHeader("btn_" + name, temp_rect, new_column); - new_column->mHeader->setToolTip(column_params.tool_tip()); - new_column->mHeader->setTabStop(false); - new_column->mHeader->setVisible(mDisplayColumnHeaders); - - if(column_params.header.image.isProvided()) + if (column_params.header.image.isProvided()) { - new_column->mHeader->setImages(column_params.header.image, column_params.header.image); - } - else if(column_params.header.image_overlay.isProvided()) - { - new_column->mHeader->setImageOverlay(column_params.header.image_overlay); + new_column->mHeader = new LLScrollColumnHeader("btn_" + name, temp_rect, new_column, column_params.header.image, column_params.header.image); + new_column->mHeader->setDrawArrow(false); } else { - new_column->mHeader->setLabel(column_params.header.label()); + new_column->mHeader = new LLScrollColumnHeader("btn_" + name, temp_rect, new_column); + if (column_params.header.image_overlay.isProvided()) + { + new_column->mHeader->setImageOverlay(column_params.header.image_overlay); + new_column->mHeader->setDrawArrow(false); + } + else + { + new_column->mHeader->setLabel(column_params.header.label()); + } } + new_column->mHeader->setToolTip(column_params.tool_tip()); + new_column->mHeader->setTabStop(false); + new_column->mHeader->setVisible(mDisplayColumnHeaders); + addChild(new_column->mHeader); sendChildToFront(mScrollbar); @@ -2920,7 +3086,7 @@ std::string LLScrollListCtrl::getSortColumnName() BOOL LLScrollListCtrl::hasSortOrder() const { - return !mSortColumns.empty(); + return mSortEnabled && !mSortColumns.empty(); } void LLScrollListCtrl::clearSortOrder() @@ -2998,10 +3164,10 @@ void LLScrollListCtrl::setColumnHeadings(const LLSD& headings) "width" "dynamic_width" */ -LLFastTimer::DeclareTimer FTM_ADD_SCROLLLIST_ELEMENT("Add Scroll List Item"); +LLTrace::BlockTimerStatHandle FTM_ADD_SCROLLLIST_ELEMENT("Add Scroll List Item"); LLScrollListItem* LLScrollListCtrl::addElement(const LLSD& element, EAddPosition pos, void* userdata) { - LLFastTimer _(FTM_ADD_SCROLLLIST_ELEMENT); + LL_RECORD_BLOCK_TIME(FTM_ADD_SCROLLLIST_ELEMENT); LLScrollListItem::Params item_params; LLParamSDParser parser; parser.readSD(element, item_params); @@ -3011,14 +3177,14 @@ LLScrollListItem* LLScrollListCtrl::addElement(const LLSD& element, EAddPosition LLScrollListItem* LLScrollListCtrl::addRow(const LLScrollListItem::Params& item_p, EAddPosition pos) { - LLFastTimer _(FTM_ADD_SCROLLLIST_ELEMENT); + LL_RECORD_BLOCK_TIME(FTM_ADD_SCROLLLIST_ELEMENT); LLScrollListItem *new_item = new LLScrollListItem(item_p); return addRow(new_item, item_p, pos); } LLScrollListItem* LLScrollListCtrl::addRow(LLScrollListItem *new_item, const LLScrollListItem::Params& item_p, EAddPosition pos) { - LLFastTimer _(FTM_ADD_SCROLLLIST_ELEMENT); + LL_RECORD_BLOCK_TIME(FTM_ADD_SCROLLLIST_ELEMENT); if (!item_p.validateBlock() || !new_item) return NULL; new_item->setNumColumns(mColumns.size()); @@ -3035,7 +3201,7 @@ LLScrollListItem* LLScrollListCtrl::addRow(LLScrollListItem *new_item, const LLS // empty columns strings index by ordinal if (column.empty()) { - column = llformat("%d", col_index); + column = fmt::to_string(col_index); } LLScrollListColumn* columnp = getColumn(column); @@ -3199,6 +3365,11 @@ void LLScrollListCtrl::setFocus(BOOL b) selectFirstItem(); //onCommit(); // SJB: selectFirstItem() will call onCommit() if appropriate } + + // Singu Note: Edit menu handler, y'know for Ctrl-A and such! + if (b) gEditMenuHandler = this; + else if (gEditMenuHandler == this) gEditMenuHandler = NULL; + LLUICtrl::setFocus(b); } diff --git a/indra/llui/llscrolllistctrl.h b/indra/llui/llscrolllistctrl.h index 9babab0093..c1dcf8eed6 100644 --- a/indra/llui/llscrolllistctrl.h +++ b/indra/llui/llscrolllistctrl.h @@ -32,9 +32,9 @@ #include #include +#include "lfidbearer.h" #include "lluictrl.h" #include "llctrlselectioninterface.h" -//#include "lldarray.h" #include "llfontgl.h" #include "llui.h" #include "llstring.h" // LLWString @@ -49,6 +49,7 @@ class LLMenuGL; class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler, public LLCtrlListInterface, public LLCtrlScrollInterface +, public LFIDBearer { public: typedef boost::function callback_t; @@ -195,12 +196,12 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler, // "StringUUID" interface: use this when you're creating a list that contains non-unique strings each of which // has an associated, unique UUID, and only one of which can be selected at a time. LLScrollListItem* addStringUUIDItem(const std::string& item_text, const LLUUID& id, EAddPosition pos = ADD_BOTTOM, BOOL enabled = TRUE); - LLUUID getStringUUIDSelectedItem() const; + LLUUID getStringUUIDSelectedItem() const override final; LLScrollListItem* getFirstSelected() const; virtual S32 getFirstSelectedIndex() const; std::vector getAllSelected() const; - uuid_vec_t getSelectedIDs(); //Helper. Much like getAllSelected, but just provides a LLUUID vec + uuid_vec_t getSelectedIDs() const override final; //Helper. Much like getAllSelected, but just provides a LLUUID vec S32 getNumSelected() const; LLScrollListItem* getLastSelectedItem() const { return mLastSelected; } @@ -208,6 +209,7 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler, LLScrollListItem* getFirstData() const; LLScrollListItem* getLastData() const; std::vector getAllData() const; + uuid_vec_t getAllIDs() const; //Helper. Much like getAllData, but just provides a LLUUID vec LLScrollListItem* getItem(const LLSD& sd) const; @@ -249,8 +251,21 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler, void clearSearchString() { mSearchString.clear(); } - // support right-click context menus for avatar/group lists + bool filterItem(LLScrollListItem* item); + void setFilter(const std::string& filter); + + // Context Menus void setContextMenu(LLMenuGL* menu) { mPopupMenu = menu; } + void setContextMenu(U8 index) { mPopupMenu = sMenus[index]; } + void setContextMenu(const std::string& menu); + + Type getSelectedType() const override + { + for (auto i = 0; mPopupMenu && i < COUNT; ++i) + if (sMenus[i] == mPopupMenu) + return (Type)i; + return LFIDBearer::getSelectedType(); + } // Overridden from LLView /*virtual*/ void draw(); @@ -274,6 +289,7 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler, virtual void resetDirty(); // Clear dirty state virtual void updateLayout(); + void adjustScrollbar(S32 doc_size); virtual void fitContents(S32 max_width, S32 max_height); virtual LLRect getRequiredRect(); @@ -289,7 +305,7 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler, static void onClickColumn(void *userdata); - virtual void updateColumns(); + virtual void updateColumns(bool force_update = false); S32 calcMaxContentWidth(); bool updateColumnWidths(); S32 getMaxContentWidth() { return mMaxContentWidth; } @@ -306,7 +322,7 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler, virtual void scrollToShowSelected(); // LLEditMenuHandler functions - virtual void copy(); + void copy() const override final; virtual BOOL canCopy() const; virtual void cut(); virtual BOOL canCut() const; @@ -319,11 +335,33 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler, void updateStaticColumnWidth(LLScrollListColumn* col, S32 new_width); S32 getTotalStaticColumnWidth() { return mTotalStaticColumnWidth; } + typedef std::pair sort_column_t; + typedef std::vector sort_order_t; + const sort_order_t& getSortOrder() const { return mSortColumns; } std::string getSortColumnName(); BOOL getSortAscending() { return mSortColumns.empty() ? TRUE : mSortColumns.back().second; } BOOL hasSortOrder() const; + void setSortOrder(const sort_order_t& order); void clearSortOrder(); + void setSortEnabled(bool sort); + template S32 selectMultiple(const std::vector& vec) + { + size_t count = 0; + for (item_list::iterator iter = mItemList.begin(); iter != mItemList.end(); ++iter) + { + LLScrollListItem* item = *iter; + for (typename std::vector::const_iterator titr = vec.begin(); titr != vec.end(); ++titr) + if (item->getEnabled() && static_cast(item->getValue()) == (*titr)) + { + selectItem(item, false); + ++count; + break; + } + } + if (mCommitOnSelectionChange) commitIfChanged(); + return count; + } S32 selectMultiple( uuid_vec_t ids ); // conceptually const, but mutates mItemList void updateSort() const; @@ -335,7 +373,7 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler, void setNeedsSortColumn(S32 col) { if(!isSorted())return; - for(std::vector >::iterator it=mSortColumns.begin();it!=mSortColumns.end();++it) + for(auto it=mSortColumns.begin();it!=mSortColumns.end();++it) { if((*it).first == col) { @@ -352,6 +390,7 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler, return mSortCallback->connect(cb); } + S32 getLinesPerPage(); protected: // "Full" interface: use this when you're creating a list that has one or more of the following: @@ -388,7 +427,6 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler, void deselectItem(LLScrollListItem* itemp); void commitIfChanged(); BOOL setSort(S32 column, BOOL ascending); - S32 getLinesPerPage(); S32 mLineHeight; // the max height of a single line S32 mScrollLines; // how many lines we've scrolled down @@ -407,6 +445,7 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler, bool mDisplayColumnHeaders; bool mColumnsDirty; bool mColumnWidthsDirty; + bool mSortEnabled; mutable item_list mItemList; @@ -438,11 +477,13 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler, S32 mHighlightedItem; class LLViewBorder* mBorder; LLMenuGL *mPopupMenu; - + LLView *mCommentTextView; LLWString mSearchString; LLFrameTimer mSearchTimer; + + std::string mFilter; S32 mSearchColumn; S32 mNumDynamicWidthColumns; @@ -460,8 +501,7 @@ class LLScrollListCtrl : public LLUICtrl, public LLEditMenuHandler, typedef std::vector ordered_columns_t; ordered_columns_t mColumnsIndexed; - typedef std::pair sort_column_t; - std::vector mSortColumns; + sort_order_t mSortColumns; sort_signal_t* mSortCallback; }; // end class LLScrollListCtrl diff --git a/indra/llui/llscrolllistitem.cpp b/indra/llui/llscrolllistitem.cpp index fc48e2578d..d6d3cf2aa3 100644 --- a/indra/llui/llscrolllistitem.cpp +++ b/indra/llui/llscrolllistitem.cpp @@ -28,6 +28,7 @@ #include "linden_common.h" #include "llscrolllistitem.h" +#include "llview.h" //--------------------------------------------------------------------------- @@ -37,6 +38,7 @@ LLScrollListItem::LLScrollListItem( const Params& p ) : mSelected(FALSE), mEnabled(p.enabled), + mFiltered(false), mUserdata(p.userdata), mItemValue(p.value), mColumns() @@ -79,7 +81,7 @@ void LLScrollListItem::setColumn( S32 column, LLScrollListCell *cell ) } else { - llerrs << "LLScrollListItem::setColumn: bad column: " << column << llendl; + LL_ERRS() << "LLScrollListItem::setColumn: bad column: " << column << LL_ENDL; } } @@ -116,32 +118,73 @@ std::string LLScrollListItem::getContentsCSV() const } -void LLScrollListItem::draw(const LLRect& rect, const LLColor4& fg_color, const LLColor4& bg_color, const LLColor4& highlight_color, S32 column_padding) +bool LLScrollListItem::draw(const U32 pass, const LLRect& rect, const LLColor4& fg_color, const LLColor4& bg_color, const LLColor4& highlight_color, S32 column_padding) { - // draw background rect - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - LLRect bg_rect = rect; - gl_rect_2d( bg_rect, bg_color ); - - S32 cur_x = rect.mLeft; - S32 num_cols = getNumColumns(); - S32 cur_col = 0; + const U32 num_cols = (U32)getNumColumns(); - for (LLScrollListCell* cell = getColumn(0); cur_col < num_cols; cell = getColumn(++cur_col)) + // draw background rect + if (pass == 0) + { + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + gl_rect_2d(rect, bg_color); + return true; + } + // Draw column (pass - 1) + else if (pass <= num_cols) { + LLScrollListCell* cur_cell = getColumn(pass - 1); + if (!cur_cell) + { + return false; + } // Two ways a cell could be hidden - if (cell->getWidth() < 0 - || !cell->getVisible()) continue; - - LLUI::pushMatrix(); + else if (cur_cell->getWidth() && cur_cell->getVisible()) { - LLUI::translate((F32) cur_x, (F32) rect.mBottom); - - cell->draw( fg_color, highlight_color ); + // Iterate over cells to the left and calculate offset. + S32 offset = rect.mLeft; + for (U32 i = 0; i < (pass - 1); ++i) + { + LLScrollListCell* cell = getColumn(i); + if (!cell) + { + return false; // Shouldn't happen. + } + if (cell->getVisible() && cell->getWidth()) + { + // Only apply padding if cell is visible and has width. + offset += cell->getWidth() + column_padding; + } + } + // Do not draw if not on screen. + // Only care about horizontal bounds. This draw call wont even occur if this row is entirely off screen. + LLRect clip_rect = LLUI::getRootView()->getRect(); + if (LLGLState::isEnabled()) + { + LLRect scissor = gGL.getScissor(); + scissor.mLeft /= LLUI::getScaleFactor().mV[VX]; + scissor.mTop /= LLUI::getScaleFactor().mV[VY]; + scissor.mRight /= LLUI::getScaleFactor().mV[VX]; + scissor.mBottom /= LLUI::getScaleFactor().mV[VY]; + clip_rect.intersectWith(scissor); + } + if (offset + LLFontGL::sCurOrigin.mX >= clip_rect.mRight) + { + // Went off the right edge of the screen. Don't bother with any more columns. + return false; + } + // Draw if not off the left edge of screen. If it is off the left edge, still return true if other colums remain. + if (offset + LLFontGL::sCurOrigin.mX + cur_cell->getWidth() > clip_rect.mLeft) + { + LLUI::pushMatrix(); + { + LLUI::translate((F32)offset, (F32)rect.mBottom); + cur_cell->draw(fg_color, highlight_color); + } + LLUI::popMatrix(); + } } - LLUI::popMatrix(); - - cur_x += cell->getWidth() + column_padding; + return pass != getNumColumns(); } + return false; } diff --git a/indra/llui/llscrolllistitem.h b/indra/llui/llscrolllistitem.h index 0d87a0fbf5..f291b7cf25 100644 --- a/indra/llui/llscrolllistitem.h +++ b/indra/llui/llscrolllistitem.h @@ -71,6 +71,9 @@ class LLScrollListItem void setEnabled( BOOL b ) { mEnabled = b; } BOOL getEnabled() const { return mEnabled; } + void setFiltered(bool b) { if (mFiltered = b) mSelected = false; } + bool getFiltered() const { return mFiltered; } + void setUserdata( void* userdata ) { mUserdata = userdata; } void* getUserdata() const { return mUserdata; } @@ -92,7 +95,7 @@ class LLScrollListItem std::string getContentsCSV() const; - virtual void draw(const LLRect& rect, const LLColor4& fg_color, const LLColor4& bg_color, const LLColor4& highlight_color, S32 column_padding); + virtual bool draw(const U32 pass, const LLRect& rect, const LLColor4& fg_color, const LLColor4& bg_color, const LLColor4& highlight_color, S32 column_padding); protected: LLScrollListItem( const Params& ); @@ -100,6 +103,7 @@ class LLScrollListItem private: BOOL mSelected; BOOL mEnabled; + bool mFiltered; void* mUserdata; LLSD mItemValue; std::vector mColumns; diff --git a/indra/llui/llslider.cpp b/indra/llui/llslider.cpp index 8933542525..10beb24773 100644 --- a/indra/llui/llslider.cpp +++ b/indra/llui/llslider.cpp @@ -54,7 +54,6 @@ LLSlider::LLSlider( F32 min_value, F32 max_value, F32 increment, - BOOL volume, const std::string& control_name) : LLUICtrl( name, rect, TRUE, commit_callback, @@ -64,7 +63,6 @@ LLSlider::LLSlider( mMinValue( min_value ), mMaxValue( max_value ), mIncrement( increment ), - mVolumeSlider( volume ), mMouseOffset( 0 ), mTrackColor( LLUI::sColorsGroup->getColor( "SliderTrackColor" ) ), mThumbOutlineColor( LLUI::sColorsGroup->getColor( "SliderThumbOutlineColor" ) ), @@ -72,9 +70,9 @@ LLSlider::LLSlider( mMouseDownSignal( NULL ), mMouseUpSignal( NULL ) { - mThumbImage = LLUI::getUIImage("icn_slide-thumb_dark.tga"); - mTrackImage = LLUI::getUIImage("icn_slide-groove_dark.tga"); - mTrackHighlightImage = LLUI::getUIImage("icn_slide-highlight.tga"); + mThumbImage = LLUI::getUIImage("SliderThumb_Off"); + mTrackImage = LLUI::getUIImage("SliderTrack_Horiz"); + mTrackHighlightImage = LLUI::getUIImage("SliderTrack_Horiz_Highlight"); // properly handle setting the starting thumb rect // do it this way to handle both the operating-on-settings @@ -156,12 +154,12 @@ BOOL LLSlider::handleHover(S32 x, S32 y, MASK mask) setValueAndCommit(t * (mMaxValue - mMinValue) + mMinValue ); getWindow()->setCursor(UI_CURSOR_ARROW); - lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (active)" << llendl; + LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (active)" << LL_ENDL; } else { getWindow()->setCursor(UI_CURSOR_ARROW); - lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (inactive)" << llendl; + LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (inactive)" << LL_ENDL; } return TRUE; } @@ -172,7 +170,7 @@ BOOL LLSlider::handleMouseUp(S32 x, S32 y, MASK mask) if( hasMouseCapture() ) { - gFocusMgr.setMouseCapture( NULL ); + gFocusMgr.setMouseCapture(nullptr ); if (mMouseUpSignal) (*mMouseUpSignal)( this, getValueF32() ); @@ -229,15 +227,12 @@ BOOL LLSlider::handleKeyHere(KEY key, MASK mask) BOOL handled = FALSE; switch(key) { - case KEY_UP: case KEY_DOWN: - // eat up and down keys to be consistent - handled = TRUE; - break; case KEY_LEFT: setValueAndCommit(getValueF32() - getIncrement()); handled = TRUE; break; + case KEY_UP: case KEY_RIGHT: setValueAndCommit(getValueF32() + getIncrement()); handled = TRUE; @@ -248,6 +243,16 @@ BOOL LLSlider::handleKeyHere(KEY key, MASK mask) return handled; } +BOOL LLSlider::handleScrollWheel(S32 x, S32 y, S32 clicks) +{ + F32 old_val = getValueF32(); + F32 new_val = old_val - clicks * getIncrement(); + setValueAndCommit(new_val); + // Singu Note: We have to tell the viewer we're done dragging if it cares + if (mMouseUpSignal && old_val != new_val) (*mMouseUpSignal)(this, new_val); + return TRUE; +} + void LLSlider::draw() { F32 alpha = getDrawContext().mAlpha; @@ -276,7 +281,7 @@ void LLSlider::draw() mThumbImage->drawBorder(mThumbRect, gFocusMgr.getFocusColor() % alpha, gFocusMgr.getFocusFlashWidth()); } - if( hasMouseCapture() ) + if( hasMouseCapture() ) // currently clicking on slider { // Show ghost where thumb was before dragging began. if (mThumbImage.notNull()) @@ -310,20 +315,11 @@ LLXMLNodePtr LLSlider::getXML(bool save_children) const { LLXMLNodePtr node = LLUICtrl::getXML(); - if (mVolumeSlider) - { - node->setName(LL_VOLUME_SLIDER_CTRL_TAG); - } - else - { - node->setName(LL_SLIDER_TAG); - } - + node->setName(LL_SLIDER_TAG); node->createChild("initial_val", TRUE)->setFloatValue(getInitialValue()); node->createChild("min_val", TRUE)->setFloatValue(getMinValue()); node->createChild("max_val", TRUE)->setFloatValue(getMaxValue()); node->createChild("increment", TRUE)->setFloatValue(getIncrement()); - node->createChild("volume", TRUE)->setBoolValue(mVolumeSlider); return node; } @@ -358,17 +354,13 @@ LLView* LLSlider::fromXML(LLXMLNodePtr node, LLView *parent, class LLUICtrlFacto F32 increment = 0.1f; node->getAttributeF32("increment", increment); - BOOL volume = node->hasName("volume_slider") ? TRUE : FALSE; - node->getAttributeBOOL("volume", volume); - LLSlider* slider = new LLSlider("slider_bar", rect, NULL, initial_value, min_value, max_value, - increment, - volume); + increment); slider->initFromXML(node, parent); diff --git a/indra/llui/llslider.h b/indra/llui/llslider.h index 59bda673fa..4fe90193ee 100644 --- a/indra/llui/llslider.h +++ b/indra/llui/llslider.h @@ -48,7 +48,6 @@ class LLSlider : public LLUICtrl F32 min_value, F32 max_value, F32 increment, - BOOL volume, //TODO: create a "volume" slider sub-class or just use image art, no? -MG const std::string& control_name = LLStringUtil::null ); virtual LLXMLNodePtr getXML(bool save_children = true) const; @@ -75,12 +74,12 @@ class LLSlider : public LLUICtrl boost::signals2::connection setMouseDownCallback( const commit_signal_t::slot_type& cb ); boost::signals2::connection setMouseUpCallback( const commit_signal_t::slot_type& cb ); - - virtual BOOL handleHover(S32 x, S32 y, MASK mask); - virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); - virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); - virtual BOOL handleKeyHere(KEY key, MASK mask); - virtual void draw(); + BOOL handleHover(S32 x, S32 y, MASK mask) override; + BOOL handleMouseUp(S32 x, S32 y, MASK mask) override; + BOOL handleMouseDown(S32 x, S32 y, MASK mask) override; + BOOL handleKeyHere(KEY key, MASK mask) override; + BOOL handleScrollWheel(S32 x, S32 y, S32 clicks) override; + void draw() override; private: void setValueAndCommit(F32 value); @@ -92,7 +91,6 @@ class LLSlider : public LLUICtrl F32 mMaxValue; F32 mIncrement; - BOOL mVolumeSlider; S32 mMouseOffset; LLRect mDragStartThumbRect; diff --git a/indra/llui/llsliderctrl.cpp b/indra/llui/llsliderctrl.cpp index 594a2d890a..0f164711ee 100644 --- a/indra/llui/llsliderctrl.cpp +++ b/indra/llui/llsliderctrl.cpp @@ -59,7 +59,6 @@ LLSliderCtrl::LLSliderCtrl(const std::string& name, const LLRect& rect, S32 text_left, BOOL show_text, BOOL can_edit_text, - BOOL volume, commit_callback_t commit_callback, F32 initial_value, F32 min_value, F32 max_value, F32 increment, const std::string& control_which) @@ -67,7 +66,6 @@ LLSliderCtrl::LLSliderCtrl(const std::string& name, const LLRect& rect, mFont(font), mShowText( show_text ), mCanEditText( can_edit_text ), - mVolumeSlider( volume ), mPrecision( 3 ), mLabelBox( NULL ), mLabelWidth( label_width ), @@ -75,7 +73,8 @@ LLSliderCtrl::LLSliderCtrl(const std::string& name, const LLRect& rect, mEditor( NULL ), mTextBox( NULL ), mTextEnabledColor( LLUI::sColorsGroup->getColor( "LabelTextColor" ) ), - mTextDisabledColor( LLUI::sColorsGroup->getColor( "LabelDisabledColor" ) ) + mTextDisabledColor(LLUI::sColorsGroup->getColor("LabelDisabledColor")), + mEditorCommitSignal(NULL) { S32 top = getRect().getHeight(); S32 bottom = 0; @@ -104,7 +103,7 @@ LLSliderCtrl::LLSliderCtrl(const std::string& name, const LLRect& rect, mSlider = new LLSlider(std::string("slider"), slider_rect, boost::bind(&LLSliderCtrl::onSliderCommit,_1,_2), - initial_value, min_value, max_value, increment, volume, + initial_value, min_value, max_value, increment, control_which ); addChild( mSlider ); @@ -141,6 +140,11 @@ LLSliderCtrl::LLSliderCtrl(const std::string& name, const LLRect& rect, updateText(); } +LLSliderCtrl::~LLSliderCtrl() +{ + delete mEditorCommitSignal; +} + void LLSliderCtrl::setValue(F32 v, BOOL from_event) { mSlider->setValue( v, from_event ); @@ -238,6 +242,8 @@ void LLSliderCtrl::onEditorCommit( LLUICtrl* ctrl, const LLSD& userdata ) if( success ) { self->onCommit(); + if (self->mEditorCommitSignal) + (*(self->mEditorCommitSignal))(self, self->getValueF32()); } else { @@ -332,7 +338,7 @@ void LLSliderCtrl::setPrecision(S32 precision) { if (precision < 0 || precision > 10) { - llerrs << "LLSliderCtrl::setPrecision - precision out of range" << llendl; + LL_ERRS() << "LLSliderCtrl::setPrecision - precision out of range" << LL_ENDL; return; } @@ -350,6 +356,12 @@ boost::signals2::connection LLSliderCtrl::setSliderMouseUpCallback( const commit return mSlider->setMouseUpCallback( cb ); } +boost::signals2::connection LLSliderCtrl::setSliderEditorCommitCallback(const commit_signal_t::slot_type& cb) +{ + if (!mEditorCommitSignal) mEditorCommitSignal = new commit_signal_t(); + return mEditorCommitSignal->connect(cb); +} + void LLSliderCtrl::onTabInto() { if( mEditor ) @@ -373,8 +385,6 @@ LLXMLNodePtr LLSliderCtrl::getXML(bool save_children) const node->createChild("show_text", TRUE)->setBoolValue(mShowText); node->createChild("can_edit_text", TRUE)->setBoolValue(mCanEditText); - - node->createChild("volume", TRUE)->setBoolValue(mVolumeSlider); node->createChild("decimal_digits", TRUE)->setIntValue(mPrecision); @@ -424,9 +434,6 @@ LLView* LLSliderCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory BOOL can_edit_text = FALSE; node->getAttributeBOOL("can_edit_text", can_edit_text); - BOOL volume = FALSE; - node->getAttributeBOOL("volume", volume); - F32 initial_value = 0.f; node->getAttributeF32("initial_val", initial_value); @@ -483,7 +490,6 @@ LLView* LLSliderCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory rect.getWidth() - text_left, show_text, can_edit_text, - volume, NULL, initial_value, min_value, diff --git a/indra/llui/llsliderctrl.h b/indra/llui/llsliderctrl.h index bf1b8366ed..0b173a5319 100644 --- a/indra/llui/llsliderctrl.h +++ b/indra/llui/llsliderctrl.h @@ -57,12 +57,11 @@ class LLSliderCtrl : public LLUICtrl S32 text_left, BOOL show_text, BOOL can_edit_text, - BOOL volume, //TODO: create a "volume" slider sub-class or just use image art, no? -MG commit_callback_t commit_callback, F32 initial_value, F32 min_value, F32 max_value, F32 increment, const std::string& control_which = LLStringUtil::null ); - virtual ~LLSliderCtrl() {} // Children all cleaned up by default view destructor. + virtual ~LLSliderCtrl(); virtual LLXMLNodePtr getXML(bool save_children = true) const; static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); @@ -99,6 +98,7 @@ class LLSliderCtrl : public LLUICtrl boost::signals2::connection setSliderMouseDownCallback( const commit_signal_t::slot_type& cb ); boost::signals2::connection setSliderMouseUpCallback( const commit_signal_t::slot_type& cb ); + boost::signals2::connection setSliderEditorCommitCallback(const commit_signal_t::slot_type& cb); virtual void onTabInto(); @@ -124,8 +124,7 @@ class LLSliderCtrl : public LLUICtrl const LLFontGL* mFont; BOOL mShowText; BOOL mCanEditText; - BOOL mVolumeSlider; - + S32 mPrecision; LLTextBox* mLabelBox; S32 mLabelWidth; @@ -137,6 +136,8 @@ class LLSliderCtrl : public LLUICtrl LLColor4 mTextEnabledColor; LLColor4 mTextDisabledColor; + + commit_signal_t* mEditorCommitSignal; }; #endif // LL_LLSLIDERCTRL_H diff --git a/indra/llui/llspinctrl.cpp b/indra/llui/llspinctrl.cpp index 489f712820..57c9f3aa6b 100644 --- a/indra/llui/llspinctrl.cpp +++ b/indra/llui/llspinctrl.cpp @@ -147,7 +147,7 @@ F32 clamp_precision(F32 value, S32 decimal_precision) for (S32 i = 0; i < decimal_precision; i++) clamped_value *= 10.0; - clamped_value = llround((F32)clamped_value); + clamped_value = ll_round((F32)clamped_value); for (S32 i = 0; i < decimal_precision; i++) clamped_value /= 10.0; @@ -161,13 +161,13 @@ F32 get_increment(F32 inc, S32 decimal_precision) //CF: finetune increments if(gKeyboard->getKeyDown(KEY_ALT)) inc = inc * 10.f; else if(gKeyboard->getKeyDown(KEY_CONTROL)) { - if (llround(inc * 1000.f) == 25) // 0.025 gets 0.05 here + if (ll_round(inc * 1000.f) == 25) // 0.025 gets 0.05 here inc = inc * 0.2f; else inc = inc * 0.1f; } else if(gKeyboard->getKeyDown(KEY_SHIFT)) { - if (decimal_precision == 2 && llround(inc) == 1) // for rotations, finest step is 0.05 + if (decimal_precision == 2 && ll_round(inc) == 1) // for rotations, finest step is 0.05 inc = inc * 0.05f; else inc = inc * 0.01f; @@ -264,6 +264,7 @@ void LLSpinCtrl::forceSetValue(const LLSD& value ) mValue = v; updateEditor(); + mEditor->resetScrollPosition(); } } @@ -329,7 +330,9 @@ void LLSpinCtrl::onEditorCommit( const LLSD& data ) if( success ) { - updateEditor(); + // We committed and clamped value + // try to display as much as possible + mEditor->resetScrollPosition(); } else { @@ -384,7 +387,7 @@ void LLSpinCtrl::setPrecision(S32 precision) { if (precision < 0 || precision > 10) { - llerrs << "LLSpinCtrl::setPrecision - precision out of range" << llendl; + LL_ERRS() << "LLSpinCtrl::setPrecision - precision out of range" << LL_ENDL; return; } @@ -400,7 +403,7 @@ void LLSpinCtrl::setLabel(const LLStringExplicit& label) } else { - llwarns << "Attempting to set label on LLSpinCtrl constructed without one " << getName() << llendl; + LL_WARNS() << "Attempting to set label on LLSpinCtrl constructed without one " << getName() << LL_ENDL; } updateLabelColor(); } @@ -461,6 +464,7 @@ BOOL LLSpinCtrl::handleKeyHere(KEY key, MASK mask) // text editors don't support revert normally (due to user confusion) // but not allowing revert on a spinner seems dangerous updateEditor(); + mEditor->resetScrollPosition(); mEditor->setFocus(FALSE); return TRUE; } diff --git a/indra/llui/llstatbar.cpp b/indra/llui/llstatbar.cpp index bed37f2c04..b13dbd907d 100644 --- a/indra/llui/llstatbar.cpp +++ b/indra/llui/llstatbar.cpp @@ -45,23 +45,17 @@ /////////////////////////////////////////////////////////////////////////////////// -LLStatBar::LLStatBar(const std::string& name, const LLRect& rect, const std::string& setting, +LLStatBar::LLStatBar(const std::string& name, const LLRect& rect, LLStat* stat, const Parameters& parameters, const std::string& setting, BOOL default_bar, BOOL default_history) : LLView(name, rect, TRUE), mSetting(setting), mLabel(name), - mMinBar(0.f), - mMaxBar(50.f), - mStatp(NULL), - mTickSpacing(10.f), - mLabelSpacing(10.f), - mPrecision(0), - mUpdatesPerSec(5), - mPerSec(true), - mDisplayMean(true) + mParameters(parameters), + mStatp(stat), + mValue(0.f), + mMinShift(0), + mMaxShift(0) { - mValue = 0.f; - S32 mode = -1; if (mSetting.length() > 0) { @@ -127,13 +121,13 @@ void LLStatBar::draw() { if (!mStatp) { -// llinfos << "No stats for statistics bar!" << llendl; +// LL_INFOS() << "No stats for statistics bar!" << LL_ENDL; return; } // Get the values. F32 current, min, max, mean; - if (mPerSec) + if (mParameters.mPerSec) { current = mStatp->getCurrentPerSec(); min = mStatp->getMinPerSec(); @@ -149,9 +143,9 @@ void LLStatBar::draw() } - if ((mUpdatesPerSec == 0.f) || (mUpdateTimer.getElapsedTimeF32() > 1.f/mUpdatesPerSec) || (mValue == 0.f)) + if ((mParameters.mUpdatesPerSec == 0.f) || (mUpdateTimer.getElapsedTimeF32() > 1.f/mParameters.mUpdatesPerSec) || (mValue == 0.f)) { - if (mDisplayMean) + if (mParameters.mDisplayMean) { mValue = mean; } @@ -170,22 +164,20 @@ void LLStatBar::draw() S32 tick_width = 1; S32 left, top, right, bottom; - F32 value_scale = max_width/(mMaxBar - mMinBar); + F32 value_scale = max_width/((mParameters.mMaxBar + mMaxShift) - (mParameters.mMinBar + mMinShift)); LLFontGL::getFontMonospace()->renderUTF8(mLabel, 0, 0, getRect().getHeight(), LLColor4(1.f, 1.f, 1.f, 1.f), LLFontGL::LEFT, LLFontGL::TOP); - std::string value_format; + std::string value_str; - if (!mUnitLabel.empty()) + if (!mParameters.mUnitLabel.empty()) { - value_format = llformat( "%%.%df%%s", mPrecision); - value_str = llformat( value_format.c_str(), mValue, mUnitLabel.c_str()); + value_str = llformat( "%.*f%s", mParameters.mPrecision, mValue, mParameters.mUnitLabel.c_str()); } else { - value_format = llformat( "%%.%df", mPrecision); - value_str = llformat( value_format.c_str(), mValue); + value_str = llformat("%.*f", mParameters.mPrecision, mValue); } // Draw the value. @@ -193,11 +185,8 @@ void LLStatBar::draw() LLColor4(1.f, 1.f, 1.f, 0.5f), LLFontGL::RIGHT, LLFontGL::TOP); - value_format = llformat( "%%.%df", mPrecision); if (mDisplayBar) { - std::string tick_label; - // Draw the tick marks. F32 tick_value; top = bar_top; @@ -205,24 +194,23 @@ void LLStatBar::draw() LLGLSUIDefault gls_ui; gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - for (tick_value = mMinBar; tick_value <= mMaxBar; tick_value += mTickSpacing) + for (tick_value = mParameters.mMinBar + mMinShift; tick_value <= (mParameters.mMaxBar + mMaxShift); tick_value += mParameters.mTickSpacing) { - left = llfloor((tick_value - mMinBar)*value_scale); + left = llfloor((tick_value - (mParameters.mMinBar + mMinShift))*value_scale); right = left + tick_width; gl_rect_2d(left, top, right, bottom, LLColor4(1.f, 1.f, 1.f, 0.1f)); } // Draw the tick labels (and big ticks). bottom = bar_top - bar_height - tick_height; - for (tick_value = mMinBar; tick_value <= mMaxBar; tick_value += mLabelSpacing) + for (tick_value = mParameters.mMinBar + mMinShift; tick_value <= (mParameters.mMaxBar + mMaxShift); tick_value += mParameters.mLabelSpacing) { - left = llfloor((tick_value - mMinBar)*value_scale); + left = llfloor((tick_value - (mParameters.mMinBar + mMinShift))*value_scale); right = left + tick_width; gl_rect_2d(left, top, right, bottom, LLColor4(1.f, 1.f, 1.f, 0.25f)); - tick_label = llformat( value_format.c_str(), tick_value); // draw labels for the tick marks - LLFontGL::getFontMonospace()->renderUTF8(tick_label, 0, left - 1, bar_top - bar_height - tick_height, + LLFontGL::getFontMonospace()->renderUTF8(llformat("%.*f", mParameters.mPrecision, tick_value), 0, left - 1, bar_top - bar_height - tick_height, LLColor4(1.f, 1.f, 1.f, 0.5f), LLFontGL::LEFT, LLFontGL::TOP); } @@ -242,15 +230,15 @@ void LLStatBar::draw() return; } // draw min and max - left = (S32) ((min - mMinBar) * value_scale); + left = (S32) ((min - (mParameters.mMinBar + mMinShift)) * value_scale); if (left < 0) { left = 0; - llwarns << "Min:" << min << llendl; + LL_WARNS() << "Min:" << min << LL_ENDL; } - right = (S32) ((max - mMinBar) * value_scale); + right = (S32) ((max - (mParameters.mMinBar + mMinShift)) * value_scale); gl_rect_2d(left, top, right, bottom, LLColor4(1.f, 0.f, 0.f, 0.25f)); S32 num_values = mStatp->getNumValues() - 1; @@ -263,44 +251,35 @@ void LLStatBar::draw() { continue; } - if (mPerSec) + if (mParameters.mPerSec) { - left = (S32)((mStatp->getPrevPerSec(i) - mMinBar) * value_scale); - right = (S32)((mStatp->getPrevPerSec(i) - mMinBar) * value_scale) + 1; - gl_rect_2d(left, bottom+i+1, right, bottom+i, LLColor4(1.f, 0.f, 0.f, 1.f)); + left = (S32)((mStatp->getPrevPerSec(i) - (mParameters.mMinBar + mMinShift)) * value_scale); + gl_rect_2d(left, bottom+i+1, left+1, bottom+i, LLColor4(1.f, 0.f, 0.f, 1.f)); } else { - left = (S32)((mStatp->getPrev(i) - mMinBar) * value_scale); - right = (S32)((mStatp->getPrev(i) - mMinBar) * value_scale) + 1; - gl_rect_2d(left, bottom+i+1, right, bottom+i, LLColor4(1.f, 0.f, 0.f, 1.f)); + left = (S32)((mStatp->getPrev(i) - (mParameters.mMinBar + mMinShift)) * value_scale); + gl_rect_2d(left, bottom+i+1, left + 1, bottom+i, LLColor4(1.f, 0.f, 0.f, 1.f)); } } } else { // draw current - left = (S32) ((current - mMinBar) * value_scale) - 1; - right = (S32) ((current - mMinBar) * value_scale) + 1; - gl_rect_2d(left, top, right, bottom, LLColor4(1.f, 0.f, 0.f, 1.f)); + left = (S32) ((current - (mParameters.mMinBar + mMinShift)) * value_scale) - 1; + gl_rect_2d(left, top, left + 2, bottom, LLColor4(1.f, 0.f, 0.f, 1.f)); } // draw mean bar top = bar_top + 2; bottom = bar_top - bar_height - 2; - left = (S32) ((mean - mMinBar) * value_scale) - 1; - right = (S32) ((mean - mMinBar) * value_scale) + 1; - gl_rect_2d(left, top, right, bottom, LLColor4(0.f, 1.f, 0.f, 1.f)); + left = (S32)((mean - (mParameters.mMinBar + mMinShift)) * value_scale) - 1; + gl_rect_2d(left, top, left + 2, bottom, LLColor4(0.f, 1.f, 0.f, 1.f)); } LLView::draw(); } -void LLStatBar::setUnitLabel(const std::string& unit_label) -{ - mUnitLabel = unit_label; -} - LLRect LLStatBar::getRequiredRect() { LLRect rect; diff --git a/indra/llui/llstatbar.h b/indra/llui/llstatbar.h index 8c1ef3ecd6..8d04c79526 100644 --- a/indra/llui/llstatbar.h +++ b/indra/llui/llstatbar.h @@ -47,33 +47,60 @@ class LLStatBar : public LLView }; public: - LLStatBar(const std::string& name, const LLRect& rect, const std::string& setting = std::string(), + struct Parameters { + Parameters() : + mMinBar(0.f), + mMaxBar(50.f), + mTickSpacing(10.f), + mLabelSpacing(10.f), + mPrecision(0), + mUpdatesPerSec(5), + mPerSec(true), + mDisplayMean(true), + mUnitLabel("") + {} + F32 mMinBar; + F32 mMaxBar; + F32 mTickSpacing; + F32 mLabelSpacing; + U32 mPrecision; + F32 mUpdatesPerSec; + BOOL mPerSec; // Use the per sec stats. + BOOL mDisplayMean; // If true, display mean, if false, display current value + std::string mUnitLabel; + }; + + LLStatBar(const std::string& name, const LLRect& rect, LLStat* stat, const LLStatBar::Parameters& parameters, const std::string& setting = std::string(), BOOL default_bar = FALSE, BOOL default_history = FALSE); virtual void draw(); virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); + void fit(F32 value) { + if (mParameters.mMinBar + mMinShift > value) + { + mMinShift = value - mParameters.mMinBar; + } + if (mParameters.mMaxBar + mMaxShift < value) + { + mMaxShift = value - mParameters.mMaxBar; + } + } - void setUnitLabel(const std::string& unit_label); /*virtual*/ LLRect getRequiredRect(); // Return the height of this object, given the set options. - F32 mMinBar; - F32 mMaxBar; - F32 mTickSpacing; - F32 mLabelSpacing; - U32 mPrecision; - F32 mUpdatesPerSec; - BOOL mPerSec; // Use the per sec stats. +private: + const Parameters mParameters; BOOL mDisplayBar; // Display the bar graph. BOOL mDisplayHistory; - BOOL mDisplayMean; // If true, display mean, if false, display current value - LLStat *mStatp; -private: + const LLStat* mStatp; + const LLUIString mLabel; + const std::string mSetting; + LLFrameTimer mUpdateTimer; - LLUIString mLabel; - std::string mUnitLabel; F32 mValue; - std::string mSetting; + F32 mMinShift; + F32 mMaxShift; }; #endif diff --git a/indra/llui/llstatgraph.cpp b/indra/llui/llstatgraph.cpp index 2e3be18031..dd74e58829 100644 --- a/indra/llui/llstatgraph.cpp +++ b/indra/llui/llstatgraph.cpp @@ -120,7 +120,7 @@ void LLStatGraph::draw() color = mThresholdColors[i]; gGL.color4fv(color.mV); - gl_rect_2d(1, llround(frac*getRect().getHeight()), getRect().getWidth() - 1, 0, TRUE); + gl_rect_2d(1, ll_round(frac*getRect().getHeight()), getRect().getWidth() - 1, 0, TRUE); } void LLStatGraph::setValue(const LLSD& value) diff --git a/indra/llui/llstatview.cpp b/indra/llui/llstatview.cpp index 9cd5ceb7eb..178c830de3 100644 --- a/indra/llui/llstatview.cpp +++ b/indra/llui/llstatview.cpp @@ -66,7 +66,7 @@ LLStatView::~LLStatView() } } -LLStatBar *LLStatView::addStat(const std::string& name, LLStat *statp, +LLStatBar *LLStatView::addStat(const std::string& name, LLStat *statp, const LLStatBar::Parameters& parameters, const std::string& setting, BOOL default_bar, BOOL default_history) { LLStatBar *stat_barp; @@ -74,8 +74,7 @@ LLStatBar *LLStatView::addStat(const std::string& name, LLStat *statp, mNumStatBars++; - stat_barp = new LLStatBar(name, r, setting, default_bar, default_history); - stat_barp->mStatp = statp; + stat_barp = new LLStatBar(name, r, statp, parameters, setting, default_bar, default_history); stat_barp->setVisible(mDisplayChildren); addChildInBack(stat_barp); diff --git a/indra/llui/llstatview.h b/indra/llui/llstatview.h index 397c73ba56..cfd4c6576c 100644 --- a/indra/llui/llstatview.h +++ b/indra/llui/llstatview.h @@ -58,9 +58,10 @@ class LLStatView : public LLContainerView friend class LLUICtrlFactory; public: - LLStatBar *addStat(const std::string& name, LLStat *statp, + LLStatBar *addStat(const std::string& name, LLStat *statp, const LLStatBar::Parameters& parameters, const std::string& setting = std::string(), BOOL default_bar = FALSE, BOOL default_history = FALSE); LLStatView *addStatView(LLStatView::Params& p); + protected: typedef std::vector sb_vector_t; sb_vector_t mStatBars; diff --git a/indra/llui/llstyle.cpp b/indra/llui/llstyle.cpp index 90e5388073..9551c98b83 100644 --- a/indra/llui/llstyle.cpp +++ b/indra/llui/llstyle.cpp @@ -33,6 +33,8 @@ #include "linden_common.h" #include "llstyle.h" + +#include "llfontgl.h" #include "llstring.h" #include "llui.h" diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp index c0e5b80520..6de7511979 100644 --- a/indra/llui/lltabcontainer.cpp +++ b/indra/llui/lltabcontainer.cpp @@ -1,11 +1,11 @@ -/** +/** * @file lltabcontainer.cpp * @brief LLTabContainer class * * $LicenseInfo:firstyear=2001&license=viewergpl$ - * + * * Copyright (c) 2001-2009, Linden Research, Inc. - * + * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab * to you under the terms of the GNU General Public License, version 2.0 @@ -13,17 +13,17 @@ * ("Other License"), formally executed by you and Linden Lab. Terms of * the GPL can be found in doc/GPL-license.txt in this distribution, or * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * + * * There are special exceptions to the terms and conditions of the GPL as * it is applied to this Source Code. View the full text of the exception * in the file doc/FLOSS-exception.txt in this software distribution, or * online at * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * + * * By copying, modifying or distributing this software, you acknowledge * that you have read and understood your obligations described above, * and agree to abide by those obligations. - * + * * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, * COMPLETENESS OR PERFORMANCE. @@ -40,6 +40,7 @@ #include "llresmgr.h" #include "llresizehandle.h" #include "lltextbox.h" +#include "lltrans.h" #include "llcriticaldamp.h" #include "lluictrlfactory.h" #include "llrender.h" @@ -92,7 +93,7 @@ class LLTabTuple LLTabContainer::LLTabContainer(const std::string& name, const LLRect& rect, TabPosition pos, BOOL bordered, BOOL is_vertical ) - : + : LLPanel(name, rect, bordered), mCurrentTabIdx(-1), mTabsHidden(FALSE), @@ -114,7 +115,7 @@ LLTabContainer::LLTabContainer(const std::string& name, const LLRect& rect, TabP mJumpNextArrowBtn(NULL), mRightTabBtnOffset(0), mTotalTabWidth(0) -{ +{ //RN: HACK to support default min width for legacy vertical tab containers if (mIsVertical) { @@ -214,7 +215,7 @@ void LLTabContainer::draw() } } - setScrollPosPixels(mIsVertical ? target_pixel_scroll : lerp((F32)getScrollPosPixels(), (F32)target_pixel_scroll, LLCriticalDamp::getInterpolant(0.08f))); + setScrollPosPixels(mIsVertical ? target_pixel_scroll : lerp((F32)getScrollPosPixels(), (F32)target_pixel_scroll, LLSmoothInterpolation::getInterpolant(0.08f))); BOOL has_scroll_arrows = !getTabsHidden() && ((mMaxScrollPos > 0) || (mScrollPosPixels > 0)); if (!mIsVertical) @@ -237,7 +238,7 @@ void LLTabContainer::draw() left = LLPANEL_BORDER_WIDTH + (has_scroll_arrows ? (TABCNTR_ARROW_BTN_SIZE * 2) : TABCNTR_TAB_H_PAD); left -= getScrollPosPixels(); } - + // Hide all the buttons if (getTabsHidden() || mIsVertical) { @@ -507,7 +508,7 @@ BOOL LLTabContainer::handleMouseUp( S32 x, S32 y, MASK mask ) BOOL LLTabContainer::handleToolTip( S32 x, S32 y, std::string& msg, LLRect* sticky_rect ) { BOOL handled = LLPanel::handleToolTip( x, y, msg, sticky_rect ); - if (!handled && getTabCount() > 0 && !getTabsHidden()) + if (!handled && getTabCount() > 0 && !getTabsHidden()) { LLTabTuple* firsttuple = getTab(0); @@ -700,7 +701,7 @@ BOOL LLTabContainer::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDrag mDragAndDropDelayTimer.stop(); } } - else + else { // Start a timer so we don't open tabs as soon as we hover on them mDragAndDropDelayTimer.start(); @@ -710,9 +711,9 @@ BOOL LLTabContainer::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDrag return LLView::handleDragAndDrop(x, y, mask, drop, type, cargo_data, accept, tooltip); } -void LLTabContainer::addTabPanel(LLPanel* child, - const std::string& label, - BOOL select, +void LLTabContainer::addTabPanel(LLPanel* child, + const std::string& label, + BOOL select, S32 indent, BOOL placeholder, eInsertionPoint insertion_point) @@ -735,16 +736,16 @@ void LLTabContainer::addTabPanel(LLPanel* child, { button_width = llclamp(font->getWidth(trimmed_label) + TAB_PADDING, mMinTabWidth, mMaxTabWidth); } - + // Tab panel S32 tab_panel_top; S32 tab_panel_bottom; - if (!getTabsHidden()) + if (!getTabsHidden()) { if( getTabPosition() == LLTabContainer::TOP ) { S32 tab_height = mIsVertical ? BTN_HEIGHT : TABCNTR_TAB_HEIGHT; - tab_panel_top = getRect().getHeight() - getTopBorderHeight() - (tab_height - TABCNTR_BUTTON_PANEL_OVERLAP); + tab_panel_top = getRect().getHeight() - getTopBorderHeight() - (tab_height - TABCNTR_BUTTON_PANEL_OVERLAP); tab_panel_bottom = LLPANEL_BORDER_WIDTH; } else @@ -769,7 +770,7 @@ void LLTabContainer::addTabPanel(LLPanel* child, } else { - tab_panel_rect = LLRect(LLPANEL_BORDER_WIDTH, + tab_panel_rect = LLRect(LLPANEL_BORDER_WIDTH, tab_panel_top, getRect().getWidth()-LLPANEL_BORDER_WIDTH, tab_panel_bottom ); @@ -811,12 +812,12 @@ void LLTabContainer::addTabPanel(LLPanel* child, LLTextBox* textbox = NULL; LLButton* btn = NULL; - + if (placeholder) { btn_rect.translate(0, -LLBUTTON_V_PAD-2); textbox = new LLTextBox(trimmed_label, btn_rect, trimmed_label, font); - + btn = new LLButton(LLStringUtil::null); } else @@ -826,8 +827,8 @@ void LLTabContainer::addTabPanel(LLPanel* child, btn = new LLButton(std::string("vert tab button"), btn_rect, LLStringUtil::null, - LLStringUtil::null, - LLStringUtil::null, + LLStringUtil::null, + LLStringUtil::null, NULL, font, trimmed_label, trimmed_label); @@ -843,18 +844,13 @@ void LLTabContainer::addTabPanel(LLPanel* child, } else { - std::string tooltip = trimmed_label; - tooltip += "\nAlt-Left arrow for previous tab"; - tooltip += "\nAlt-Right arrow for next tab"; - btn = new LLButton(std::string(child->getName()) + " tab", - btn_rect, + btn_rect, LLStringUtil::null, LLStringUtil::null, LLStringUtil::null, NULL, // set userdata below font, trimmed_label, trimmed_label ); btn->setVisible( FALSE ); - btn->setToolTip( tooltip ); btn->setScaleImage(TRUE); btn->setImages(tab_img, tab_selected_img); @@ -877,8 +873,20 @@ void LLTabContainer::addTabPanel(LLPanel* child, btn->setFollowsBottom(); } } + std::string tooltip = trimmed_label; + LLStringUtil::format_map_t args; + args["[ALT]"] = LLTrans::getString( +#ifdef LL_DARWIN + "accel-mac-option" +#else + "accel-win-alt" +#endif + ); + tooltip += '\n' + LLTrans::getString("tab_tooltip_prev", args); + tooltip += '\n' + LLTrans::getString("tab_tooltip_next", args); + btn->setToolTip( tooltip ); } - + LLTabTuple* tuple = new LLTabTuple( this, child, btn, textbox ); insertTuple( tuple, insertion_point ); @@ -906,7 +914,7 @@ void LLTabContainer::addTabPanel(LLPanel* child, sendChildToFront(mNextArrowBtn); sendChildToFront(mJumpPrevArrowBtn); sendChildToFront(mJumpNextArrowBtn); - + if( select ) { selectLastTab(); @@ -958,7 +966,7 @@ void LLTabContainer::removeTabPanel(LLPanel* child) } } } - + BOOL has_focus = gFocusMgr.childHasKeyboardFocus(this); // If the tab being deleted is the selected one, select a different tab. @@ -972,7 +980,7 @@ void LLTabContainer::removeTabPanel(LLPanel* child) removeChild( tuple->mTabPanel ); // delete tuple->mTabPanel; - + mTabList.erase( iter ); delete tuple; @@ -1041,7 +1049,7 @@ void LLTabContainer::deleteAllTabs() // Actually delete the tuples themselves std::for_each(mTabList.begin(), mTabList.end(), DeletePointer()); mTabList.clear(); - + // And there isn't a current tab any more mCurrentTabIdx = -1; } @@ -1173,7 +1181,7 @@ void LLTabContainer::selectPrevTab() { mTabList[idx]->mButton->setFocus(TRUE); } -} +} BOOL LLTabContainer::selectTabPanel(LLPanel* child) { @@ -1205,7 +1213,7 @@ BOOL LLTabContainer::selectTab(S32 which) { return FALSE; } - + LLSD cbdata; if (selected_tuple->mTabPanel) cbdata = selected_tuple->mTabPanel->getName(); @@ -1219,7 +1227,7 @@ BOOL LLTabContainer::selectTab(S32 which) (*mCommitSignal)(this, cbdata); } } - + return res; } @@ -1247,7 +1255,7 @@ BOOL LLTabContainer::setTab(S32 which) tuple->mButton->setToggleState( is_selected ); // RN: this limits tab-stops to active button only, which would require arrow keys to switch tabs tuple->mButton->setTabStop( is_selected ); - + if (is_selected) { // Make sure selected tab is within scroll region @@ -1336,8 +1344,8 @@ BOOL LLTabContainer::selectTabByName(const std::string& name) LLPanel* panel = getPanelByName(name); if (!panel) { - llwarns << "LLTabContainer::selectTabByName(" - << name << ") failed" << llendl; + LL_WARNS() << "LLTabContainer::selectTabByName(" + << name << ") failed" << LL_ENDL; return FALSE; } @@ -1391,7 +1399,7 @@ void LLTabContainer::reshapeTuple(LLTabTuple* tuple) { const LLFontGL* fontp = LLResMgr::getInstance()->getRes( LLFONT_SANSSERIF_SMALL ); S32 image_overlay_width = 0; - image_overlay_width = tuple->mButton->getImageOverlay().notNull() ? + image_overlay_width = tuple->mButton->getImageOverlay().notNull() ? tuple->mButton->getImageOverlay()->getImage()->getWidth(0) : 0; // remove current width from total tab strip width mTotalTabWidth -= tuple->mButton->getRect().getWidth(); @@ -1401,7 +1409,7 @@ void LLTabContainer::reshapeTuple(LLTabTuple* tuple) tuple->mPadding = image_overlay_width; tuple->mButton->setRightHPad(6); - tuple->mButton->reshape(llclamp(fontp->getWidth(tuple->mButton->getLabelSelected()) + TAB_PADDING + tuple->mPadding, mMinTabWidth, mMaxTabWidth), + tuple->mButton->reshape(llclamp(fontp->getWidth(tuple->mButton->getLabelSelected()) + TAB_PADDING + tuple->mPadding, mMinTabWidth, mMaxTabWidth), tuple->mButton->getRect().getHeight()); // add back in button width to total tab strip width mTotalTabWidth += tuple->mButton->getRect().getWidth(); @@ -1412,7 +1420,7 @@ void LLTabContainer::reshapeTuple(LLTabTuple* tuple) } void LLTabContainer::setTitle(const std::string& title) -{ +{ if (mTitleBox) { mTitleBox->setText( title ); @@ -1452,10 +1460,18 @@ void LLTabContainer::setPanelTitle(S32 index, const std::string& title) { LLTabTuple* tuple = getTab(index); LLButton* tab_button = tuple->mButton; - const LLFontGL* fontp = LLFontGL::getFontSansSerifSmall(); - mTotalTabWidth -= tab_button->getRect().getWidth(); - tab_button->reshape(llclamp(fontp->getWidth(title) + TAB_PADDING + tuple->mPadding, mMinTabWidth, mMaxTabWidth), tab_button->getRect().getHeight()); - mTotalTabWidth += tab_button->getRect().getWidth(); + if (!mIsVertical) + { + const LLFontGL* fontp = LLFontGL::getFontSansSerifSmall(); + mTotalTabWidth -= tab_button->getRect().getWidth(); + tab_button->reshape(llclamp(fontp->getWidth(title) + + TAB_PADDING + + tuple->mPadding, + mMinTabWidth, + mMaxTabWidth), + tab_button->getRect().getHeight()); + mTotalTabWidth += tab_button->getRect().getWidth(); + } tab_button->setLabelSelected(title); tab_button->setLabelUnselected(title); } @@ -1556,7 +1572,7 @@ LLView* LLTabContainer::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFacto node->getAttributeBOOL("border", border); LLTabContainer* tab_container = new LLTabContainer(name, LLRect::null, tab_position, border, is_vertical); - + S32 tab_min_width = tab_container->mMinTabWidth; if (node->hasAttribute("tab_width")) { @@ -1573,9 +1589,9 @@ LLView* LLTabContainer::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFacto node->getAttributeS32("tab_max_width", tab_max_width); } - tab_container->setMinTabWidth(tab_min_width); - tab_container->setMaxTabWidth(tab_max_width); - + tab_container->setMinTabWidth(tab_min_width); + tab_container->setMaxTabWidth(tab_max_width); + BOOL hidden(tab_container->getTabsHidden()); node->getAttributeBOOL("hide_tabs", hidden); tab_container->setTabsHidden(hidden); @@ -1614,7 +1630,7 @@ LLView* LLTabContainer::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFacto tab_container->postBuild(); tab_container->initButtons(); // now that we have the correct rect - + return tab_container; } @@ -1627,7 +1643,7 @@ void LLTabContainer::initButtons() { return; // Don't have a rect yet or already got called } - + std::string out_id; std::string in_id; @@ -1650,7 +1666,7 @@ void LLTabContainer::initButtons() mPrevArrowBtn->setFollowsTop(); mPrevArrowBtn->setFollowsLeft(); mPrevArrowBtn->setHeldDownCallback(boost::bind(&LLTabContainer::onPrevBtnHeld, this, _2)); - + out_id = "UIImgBtnScrollDownOutUUID"; in_id = "UIImgBtnScrollDownInUUID"; mNextArrowBtn = new LLButton(std::string("Down Arrow"), down_arrow_btn_rect, @@ -1661,7 +1677,7 @@ void LLTabContainer::initButtons() } else // Horizontal { - S32 arrow_fudge = 1; // match new art better + S32 arrow_fudge = 1; // match new art better // tabs on bottom reserve room for resize handle (just in case) if (getTabPosition() == BOTTOM) @@ -1705,7 +1721,7 @@ void LLTabContainer::initButtons() boost::bind(&LLTabContainer::onPrevBtn, this, _2), LLFontGL::getFontSansSerif() ); mPrevArrowBtn->setHeldDownCallback(boost::bind(&LLTabContainer::onPrevBtnHeld, this, _2)); mPrevArrowBtn->setFollowsLeft(); - + out_id = "UIImgBtnJumpRightOutUUID"; in_id = "UIImgBtnJumpRightInUUID"; mJumpNextArrowBtn = new LLButton(std::string("Jump Right Arrow"), jump_right_arrow_btn_rect, @@ -1740,7 +1756,7 @@ void LLTabContainer::initButtons() mPrevArrowBtn->setSaveToXML(false); mPrevArrowBtn->setTabStop(FALSE); addChild(mPrevArrowBtn); - + mNextArrowBtn->setSaveToXML(false); mNextArrowBtn->setTabStop(FALSE); addChild(mNextArrowBtn); @@ -1758,7 +1774,7 @@ void LLTabContainer::initButtons() mJumpNextArrowBtn->setTabStop(FALSE); addChild(mJumpNextArrowBtn); } - + // set default tab group to be panel contents setDefaultTabGroup(1); } @@ -1880,3 +1896,8 @@ void LLTabContainer::commitHoveredButton(S32 x, S32 y) } } +S32 LLTabContainer::getTotalTabWidth() const +{ + return mTotalTabWidth; +} + diff --git a/indra/llui/lltabcontainer.h b/indra/llui/lltabcontainer.h index de5a51639e..311e14b305 100644 --- a/indra/llui/lltabcontainer.h +++ b/indra/llui/lltabcontainer.h @@ -98,6 +98,7 @@ class LLTabContainer : public LLPanel S32 getIndexForPanel(LLPanel* panel); S32 getPanelIndexByTitle(const std::string& title); LLPanel* getPanelByName(const std::string& name); + S32 getTotalTabWidth() const; void setCurrentTabName(const std::string& name); void selectFirstTab(); diff --git a/indra/llui/lltextbox.cpp b/indra/llui/lltextbox.cpp index 239ac5b749..4a64b00447 100644 --- a/indra/llui/lltextbox.cpp +++ b/indra/llui/lltextbox.cpp @@ -395,8 +395,14 @@ void LLTextBox::initFromXML(LLXMLNodePtr node, LLView* parent) LLFontGL* font = LLView::selectFont(node); if(font) mFontGL = font; - - setText(node->getTextContents()); + + if (node->hasAttribute("value")) + { + std::string text; + node->getAttributeString("value", text); + setText(text); + } + else setText(node->getTextContents()); LLFontGL::HAlign halign = LLView::selectFontHAlign(node); setHAlign(halign); diff --git a/indra/llui/lltextbox.h b/indra/llui/lltextbox.h index 738ec3b066..27215a20cf 100644 --- a/indra/llui/lltextbox.h +++ b/indra/llui/lltextbox.h @@ -113,6 +113,7 @@ class LLTextBox void setLineLengths(); void drawText(S32 x, S32 y, const LLColor4& color ); +protected: LLUIString mText; const LLFontGL* mFontGL; LLColor4 mTextColor; diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index e6049f8437..d3eea88621 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -43,6 +43,7 @@ #include "lluictrlfactory.h" #include "lluiimage.h" #include "llurlaction.h" +#include "llurlregistry.h" #include "llrect.h" #include "llfocusmgr.h" #include "lltimer.h" @@ -64,6 +65,7 @@ #include "lltextparser.h" #include "lldir.h" #include +#include "llmemberlistener.h" #include "llmenugl.h" #include "../newview/lgghunspell_wrapper.h" @@ -95,9 +97,6 @@ const S32 PREEDIT_STANDOUT_GAP = 1; const S32 PREEDIT_STANDOUT_POSITION = 2; const S32 PREEDIT_STANDOUT_THICKNESS = 2; - -LLColor4 LLTextEditor::mLinkColor = LLColor4::blue; - /////////////////////////////////////////////////////////////////// class LLTextEditor::LLTextCmdInsert : public LLTextEditor::LLTextCmd @@ -246,50 +245,54 @@ class LLTextEditor::LLTextCmdRemove : public LLTextEditor::LLTextCmd /////////////////////////////////////////////////////////////////// -LLTextEditor::LLTextEditor( - const std::string& name, - const LLRect& rect, +LLTextEditor::LLTextEditor( + const std::string& name, + const LLRect& rect, S32 max_length, // In bytes - const std::string &default_text, + const std::string &default_text, const LLFontGL* font, - BOOL allow_embedded_items) - : - LLUICtrl( name, rect, TRUE, NULL, FOLLOWS_TOP | FOLLOWS_LEFT ), + BOOL allow_embedded_items, + bool parse_html) + : + LLUICtrl(name, rect, TRUE, NULL, FOLLOWS_TOP | FOLLOWS_LEFT), mTextIsUpToDate(TRUE), - mMaxTextByteLength( max_length ), + mMaxTextByteLength(max_length), mPopupMenuHandle(), mBaseDocIsPristine(TRUE), - mPristineCmd( NULL ), - mLastCmd( NULL ), - mCursorPos( 0 ), - mIsSelecting( FALSE ), - mSelectionStart( 0 ), - mSelectionEnd( 0 ), - mScrolledToBottom( TRUE ), - mOnScrollEndCallback( NULL ), - mOnScrollEndData( NULL ), - mCursorColor( LLUI::sColorsGroup->getColor( "TextCursorColor" ) ), - mFgColor( LLUI::sColorsGroup->getColor( "TextFgColor" ) ), - mDefaultColor( LLUI::sColorsGroup->getColor( "TextDefaultColor" ) ), - mReadOnlyFgColor( LLUI::sColorsGroup->getColor( "TextFgReadOnlyColor" ) ), - mWriteableBgColor( LLUI::sColorsGroup->getColor( "TextBgWriteableColor" ) ), - mReadOnlyBgColor( LLUI::sColorsGroup->getColor( "TextBgReadOnlyColor" ) ), - mFocusBgColor( LLUI::sColorsGroup->getColor( "TextBgFocusColor" ) ), - mReadOnly(FALSE), - mWordWrap( FALSE ), - mShowLineNumbers ( FALSE ), - mTabsToNextField( TRUE ), - mCommitOnFocusLost( FALSE ), - mHideScrollbarForShortDocs( FALSE ), - mTakesNonScrollClicks( TRUE ), - mTrackBottom( FALSE ), - mAllowEmbeddedItems( allow_embedded_items ), + mPristineCmd(NULL), + mLastCmd(NULL), + mCursorPos(0), + mIsSelecting(FALSE), + mSelectionStart(0), + mSelectionEnd(0), + mScrolledToBottom(TRUE), + mOnScrollEndCallback(NULL), + mOnScrollEndData(NULL), + mCursorColor(LLUI::sColorsGroup->getColor("TextCursorColor")), + mFgColor(LLUI::sColorsGroup->getColor("TextFgColor")), + mDefaultColor(LLUI::sColorsGroup->getColor("TextDefaultColor")), + mReadOnlyFgColor(LLUI::sColorsGroup->getColor("TextFgReadOnlyColor")), + mWriteableBgColor(LLUI::sColorsGroup->getColor("TextBgWriteableColor")), + mReadOnlyBgColor(LLUI::sColorsGroup->getColor("TextBgReadOnlyColor")), + mFocusBgColor(LLUI::sColorsGroup->getColor("TextBgFocusColor")), + mLinkColor(nullptr), + mReadOnly(parse_html), + mWordWrap(FALSE), + mShowLineNumbers(FALSE), + mTabsToNextField(TRUE), + mCommitOnFocusLost(FALSE), + mHideScrollbarForShortDocs(FALSE), + mTakesNonScrollClicks(TRUE), + mTrackBottom(FALSE), + mAllowEmbeddedItems(allow_embedded_items), mAcceptCallingCardNames(FALSE), - mHandleEditKeysDirectly( FALSE ), + mHandleEditKeysDirectly(FALSE), mMouseDownX(0), mMouseDownY(0), mLastSelectionX(-1), mLastSelectionY(-1), + mParseHTML(parse_html), + mParseHighlights(false), mLastContextMenuX(-1), mLastContextMenuY(-1), mReflowNeeded(FALSE), @@ -312,105 +315,166 @@ LLTextEditor::LLTextEditor( updateTextRect(); - S32 line_height = llround( mGLFont->getLineHeight() ); + S32 line_height = ll_round(mGLFont->getLineHeight()); S32 page_size = mTextRect.getHeight() / line_height; // Init the scrollbar LLRect scroll_rect; - scroll_rect.setOriginAndSize( + scroll_rect.setOriginAndSize( getRect().getWidth() - SCROLLBAR_SIZE, 1, SCROLLBAR_SIZE, getRect().getHeight() - 1); S32 lines_in_doc = getLineCount(); - mScrollbar = new LLScrollbar( std::string("Scrollbar"), scroll_rect, + mScrollbar = new LLScrollbar(std::string("Scrollbar"), scroll_rect, LLScrollbar::VERTICAL, - lines_in_doc, - 0, + lines_in_doc, + 0, page_size, NULL); mScrollbar->setFollowsRight(); mScrollbar->setFollowsTop(); mScrollbar->setFollowsBottom(); - mScrollbar->setEnabled( TRUE ); - mScrollbar->setVisible( TRUE ); + mScrollbar->setEnabled(TRUE); + mScrollbar->setVisible(TRUE); mScrollbar->setOnScrollEndCallback(mOnScrollEndCallback, mOnScrollEndData); addChild(mScrollbar); - mBorder = new LLViewBorder( std::string("text ed border"), LLRect(0, getRect().getHeight(), getRect().getWidth(), 0), LLViewBorder::BEVEL_IN, LLViewBorder::STYLE_LINE, UI_TEXTEDITOR_BORDER ); - addChild( mBorder ); + mBorder = new LLViewBorder(std::string("text ed border"), LLRect(0, getRect().getHeight(), getRect().getWidth(), 0), LLViewBorder::BEVEL_IN, LLViewBorder::STYLE_LINE, UI_TEXTEDITOR_BORDER); + addChild(mBorder); appendText(default_text, FALSE, FALSE); - + resetDirty(); // Update saved text state - mParseHTML=FALSE; - mHTML.clear(); - // make the popup menu available - //LLMenuGL* menu = LLUICtrlFactory::getInstance()->buildMenu("menu_texteditor.xml", parent_view); - LLMenuGL* menu = new LLMenuGL("rclickmenu"); - /*if (!menu) - { - menu = new LLMenuGL(LLStringUtil::null); - }*/ - menu->addChild(new LLMenuItemCallGL("Cut", context_cut, NULL, this)); - menu->addChild(new LLMenuItemCallGL("Copy", context_copy, NULL, this)); - menu->addChild(new LLMenuItemCallGL("Paste", context_paste, NULL, this)); - menu->addChild(new LLMenuItemCallGL("Delete", context_delete, NULL, this)); - menu->addChild(new LLMenuItemCallGL("Select All", context_selectall, NULL, this)); - menu->addSeparator(); - menu->setCanTearOff(FALSE); - menu->setVisible(FALSE); - mPopupMenuHandle = menu->getHandle(); + setCommitCallback(boost::bind(&LLTextEditor::setControlValue, this, _2)); } LLTextEditor::~LLTextEditor() { gFocusMgr.releaseFocusIfNeeded( this ); // calls onCommit() + if (mLinkColor) + { + delete mLinkColor; + mLinkColor = nullptr; + } // Scrollbar is deleted by LLView std::for_each(mUndoStack.begin(), mUndoStack.end(), DeletePointer()); - //LLView::deleteViewByHandle(mPopupMenuHandle); + mSegments.clear(); + auto menu = mPopupMenuHandle.get(); + if (menu) + { + menu->die(); + mPopupMenuHandle.markDead(); + } +} + +const std::string& LLTextEditor::getMenuSegmentUrl() const +{ + auto segment = getSegmentAtLocalPos(mLastContextMenuX, mLastContextMenuY); + auto style = segment ? segment->getStyle() : nullptr; + return style ? style->getLinkHREF() : LLStringUtil::null; } -void LLTextEditor::context_cut(void* data) + +static LFIDBearer::Type get_type_from_url(const std::string& url) { - LLTextEditor* line = (LLTextEditor*)data; - if(line)line->cut(); + auto pos = url.find("/app/"); + if (pos != std::string::npos && pos + 10 <= url.size()) + { + auto type = url.substr(pos + 5, 5); + return type == "agent" ? LFIDBearer::AVATAR + : type == "group" ? LFIDBearer::GROUP + : type == "experience" ? LFIDBearer::EXPERIENCE + : LFIDBearer::OBJECT; + } + return LFIDBearer::NONE; } -void LLTextEditor::context_copy(void* data) + +LLUUID LLTextEditor::getStringUUIDSelectedItem() const { - LLTextEditor* line = (LLTextEditor*)data; - if(line)line->copy(); + const auto& url = getMenuSegmentUrl(); + const auto& type = get_type_from_url(url); + return type == LFIDBearer::NONE ? LLUUID::null : LLUUID(type == OBJECT ? LLUrlAction::getObjectId(url) : LLUrlAction::getUserID(url)); } +LFIDBearer::Type LLTextEditor::getSelectedType() const +{ + return get_type_from_url(getMenuSegmentUrl()); +} -void LLTextEditor::spell_correct(void* data) +class CopyRawText : public LLMemberListener { - SpellMenuBind* tempBind = (SpellMenuBind*)data; - LLTextEditor* line = tempBind->origin; - if(tempBind && line) + bool handleEvent(LLPointer, const LLSD& userdata) override { - llinfos << tempBind->menuItem->getName() << " : " << tempBind->origin->getName() << " : " << tempBind->word << llendl; - if(line)line->spellReplace(tempBind); + LFIDBearer::getActive()->copyRaw(); + return true; } -} +}; + +class TextEditorVisible : public LLMemberListener +{ + bool handleEvent(LLPointer, const LLSD& userdata) override + { + LLMenuGL::sMenuContainer->findControl(userdata["control"].asString())->setValue(!!dynamic_cast(gFocusMgr.getKeyboardFocus())); + return true; + } +}; +class ContextUrl : public LLMemberListener +{ + bool handleEvent(LLPointer, const LLSD& userdata) override + { + const auto& url = LFIDBearer::getActive()->getMenuSegmentUrl(); + const auto& op = userdata.asStringRef(); + if (op == "Open") LLUrlAction::openURL(url); + else if (op == "OpenInternal") LLUrlAction::openURLInternal(url); + else if (op == "OpenExternal") LLUrlAction::openURLExternal(url); + else if (op == "Execute") LLUrlAction::executeSLURL(url, true); + else if (op == "Block") LLUrlAction::blockObject(url); + else if (op == "Unblock") LLUrlAction::unblockObject(url); + else if (op == "Teleport") LLUrlAction::teleportToLocation(url); + else if (op == "ShowOnMap") LLUrlAction::showLocationOnMap(url); + else if (op == "CopyLabel") LLUrlAction::copyLabelToClipboard(url); + else if (op == "CopyUrl") LLUrlAction::copyURLToClipboard(url); + return true; + } +}; -void LLTextEditor::spell_show(void * data) +class ContextUrlCopy : public LLMemberListener { - SpellMenuBind* tempBind = (SpellMenuBind*)data; - LLTextEditor* line = tempBind->origin; + bool handleEvent(LLPointer, const LLSD& userdata) override + { + LLView::getWindow()->copyTextToClipboard(utf8str_to_wstring(LFIDBearer::getActiveSelectedID().asString())); + return true; + } +}; + - if(tempBind && line) +void LLTextEditor::spell_correct(void* data) +{ + auto self = static_cast(data); + S32 wordStart = 0, wordLen = 0; + if (self->getWordBoundriesAt(self->getCursorPosFromLocalCoord(self->mLastContextMenuX, self->mLastContextMenuY, TRUE), &wordStart, &wordLen)) { - BOOL show = (tempBind->word == "Show Misspellings"); - glggHunSpell->setSpellCheckHighlight(show); + const auto& word = utf8str_to_wstring(LLMenuGL::sMenuContainer->getActivatedItem()->getLabel()); + + self->remove(wordStart, wordLen, TRUE); + self->insert(wordStart, word, FALSE); + self->mCursorPos += word.length() - wordLen; + self->needsReflow(); } } +void LLTextEditor::spell_show(void* show) +{ + glggHunSpell->setSpellCheckHighlight(!!show); +} + + std::vector LLTextEditor::getMisspelledWordsPositions() { resetSpellDirty(); @@ -454,29 +518,22 @@ std::vector LLTextEditor::getMisspelledWordsPositions() void LLTextEditor::spell_add(void* data) { - SpellMenuBind* tempBind = (SpellMenuBind*)data; - if(tempBind) + auto self = static_cast(data); + S32 wordStart = 0, wordLen = 0; + if (self->getWordBoundriesAt(self->getCursorPosFromLocalCoord(self->mLastContextMenuX, self->mLastContextMenuY, TRUE), &wordStart, &wordLen)) { - glggHunSpell->addWordToCustomDictionary(tempBind->word); - tempBind->origin->mPrevSpelledText.erase();//make it update + glggHunSpell->addWordToCustomDictionary(wstring_to_utf8str(self->getWText().substr(wordStart, wordLen))); + self->mPrevSpelledText.erase(); //make it update } } - -void LLTextEditor::context_paste(void* data) -{ - LLTextEditor* line = (LLTextEditor*)data; - if(line)line->paste(); -} -void LLTextEditor::context_delete(void* data) -{ - LLTextEditor* line = (LLTextEditor*)data; - if(line)line->doDelete(); -} -void LLTextEditor::context_selectall(void* data) +//static +void LLTextEditor::addMenuListeners() { - LLTextEditor* line = (LLTextEditor*)data; - if(line)line->selectAll(); + (new CopyRawText)->registerListener(LLMenuGL::sMenuContainer, "CopyRawText"); + (new TextEditorVisible)->registerListener(LLMenuGL::sMenuContainer, "TextEditorVisible"); + (new ContextUrl)->registerListener(LLMenuGL::sMenuContainer, "Text.Url"); + (new ContextUrlCopy)->registerListener(LLMenuGL::sMenuContainer, "Text.Url.CopyUUID"); } void LLTextEditor::setTrackColor( const LLColor4& color ) @@ -551,8 +608,17 @@ void LLTextEditor::updateLineStartList(S32 startpos) } } else - { - const llwchar* str = mWText.c_str() + start_idx; + { + //Scratch buffer. Avoid needless realloc. + static LLWString buf; + + if(start_idx) + { + buf.resize(end_idx - start_idx); + std::copy(mWText.begin() + start_idx, mWText.begin() + end_idx, buf.begin()); + } + const LLWString& str = start_idx ? buf : mWText; + S32 drawn = mGLFont->maxDrawableChars(str, (F32)abs(mTextRect.getWidth()) - line_width, end_idx - start_idx, mWordWrap ? LLFontGL::WORD_BOUNDARY_IF_POSSIBLE : LLFontGL::ANYWHERE, mAllowEmbeddedItems ); if( 0 == drawn && line_width == start_x) @@ -627,40 +693,56 @@ BOOL LLTextEditor::truncate() return did_truncate; } -void LLTextEditor::setText(const LLStringExplicit &utf8str) +LLMenuGL* LLTextEditor::createUrlContextMenu(S32 x, S32 y, const std::string &in_url) { - // LLStringUtil::removeCRLF(utf8str); - mUTF8Text = utf8str_removeCRLF(utf8str); - // mUTF8Text = utf8str; - mWText = utf8str_to_wstring(mUTF8Text); - mTextIsUpToDate = TRUE; - - truncate(); - blockUndo(); - - setCursorPos(0); - deselect(); + // work out the XUI menu file to use for this url + LLUrlMatch match; + std::string url = in_url; + if (!LLUrlRegistry::instance().findUrl(url, match)) + { + return nullptr; + } - needsReflow(); + std::string xui_file = match.getMenuName(); + if (xui_file.empty()) + { + return nullptr; + } - resetDirty(); + // create and return the context menu from the XUI file + llassert(LLMenuGL::sMenuContainer != NULL); + auto menu = LLUICtrlFactory::instance().buildMenu(xui_file, LLMenuGL::sMenuContainer); + return menu; } -void LLTextEditor::setWText(const LLWString &wtext) +void LLTextEditor::setText(const LLStringExplicit &utf8str, bool force_replace_links) { - mWText = wtext; - mUTF8Text.clear(); - mTextIsUpToDate = FALSE; + // clear out the existing text and segments + mWText.clear(); - truncate(); - blockUndo(); + clearSegments(); +// createDefaultSegment(); - setCursorPos(0); deselect(); - needsReflow(); + // append the new text (supports Url linking) + std::string text(utf8str); + //LLStringUtil::removeCRLF(text); + + // appendText modifies mCursorPos... + appendText(utf8str, false, false, nullptr, force_replace_links); + // ...so move cursor to top after appending text + setCursorPos(0); resetDirty(); + + mUTF8Text = text; + mTextIsUpToDate = true; +} + +void LLTextEditor::setWText(const LLWString& text, bool force_replace_links) +{ + setText(wstring_to_utf8str(text), force_replace_links); } // virtual @@ -675,7 +757,7 @@ const std::string& LLTextEditor::getText() const { if (mAllowEmbeddedItems) { - llwarns << "getText() called on text with embedded items (not supported)" << llendl; + LL_WARNS() << "getText() called on text with embedded items (not supported)" << LL_ENDL; } mUTF8Text = wstring_to_utf8str(mWText); mTextIsUpToDate = TRUE; @@ -756,7 +838,7 @@ void LLTextEditor::selectNext(const std::string& search_text_in, BOOL case_insen } // If still -1, then search_text just isn't found. - if (-1 == loc) + if (-1 == loc) { mIsSelecting = FALSE; mSelectionEnd = 0; @@ -879,9 +961,9 @@ S32 LLTextEditor::getLineStart( S32 line ) const { S32 num_lines = getLineCount(); if (num_lines == 0) - { + { return 0; - } + } line = llclamp(line, 0, num_lines-1); S32 segidx = mLineStartList[line].mSegment; @@ -890,10 +972,10 @@ S32 LLTextEditor::getLineStart( S32 line ) const S32 res = seg->getStart() + segoffset; if (res > seg->getEnd()) { - //llerrs << "wtf" << llendl; + //LL_ERRS() << "wtf" << LL_ENDL; // This happens when creating a new notecard using the AO on certain opensims. // Play it safe instead of bringing down the viewer - MC - llwarns << "BAD JOOJOO! Text length (" << res << ") greater than text end (" << seg->getEnd() << "). Setting line start to " << seg->getEnd() << llendl; + LL_WARNS() << "BAD JOOJOO! Text length (" << res << ") greater than text end (" << seg->getEnd() << "). Setting line start to " << seg->getEnd() << LL_ENDL; res = seg->getEnd(); } return res; @@ -970,7 +1052,7 @@ S32 LLTextEditor::getCursorPosFromLocalCoord( S32 local_x, S32 local_y, BOOL rou // Figure out which line we're nearest to. S32 total_lines = getLineCount(); - S32 line_height = llround( mGLFont->getLineHeight() ); + S32 line_height = ll_round( mGLFont->getLineHeight() ); S32 max_visible_lines = mTextRect.getHeight() / line_height; S32 scroll_lines = mScrollbar->getDocPos(); S32 visible_lines = llmin( total_lines - scroll_lines, max_visible_lines ); // Lines currently visible @@ -1366,93 +1448,51 @@ BOOL LLTextEditor::handleRightMouseDown( S32 x, S32 y, MASK mask ) { setFocus(TRUE); - //setCursorAtLocalPos( x, y, TRUE ); - S32 wordStart = 0; - S32 wordLen = 0; - S32 pos = getCursorPosFromLocalCoord(x,y,TRUE); - - LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get(); + auto segment = getSegmentAtLocalPos(x, y); + const LLStyleSP style = segment ? segment->getStyle() : nullptr; + auto submenu = (style && style->isLink()) ? createUrlContextMenu(x, y, style->getLinkHREF()) : nullptr; + // Add url menu to base menu if we have a selection, otherwise make it the menu. + auto menu = (submenu && !hasSelection()) ? submenu : LLUICtrlFactory::instance().buildMenu("menu_texteditor.xml", LLMenuGL::sMenuContainer); + mPopupMenuHandle = menu->getHandle(); if (menu) { - for(int i = 0;i<(int)suggestionMenuItems.size();i++) + if (submenu && submenu != menu) { - SpellMenuBind * tempBind = suggestionMenuItems[i]; - if(tempBind) - { - menu->removeChild(tempBind->menuItem); - tempBind->menuItem->die(); - //delete tempBind->menuItem; - //tempBind->menuItem = NULL; - delete tempBind; - } + submenu->removeChild(submenu->getChild("Select All")); // There can be only one! + menu->appendMenu(submenu); } - suggestionMenuItems.clear(); // spell_check="true" in xui - menu->setItemVisible("Spelsep", !mReadOnly && mSpellCheckable); if (!mReadOnly && mSpellCheckable) { - bool is_word_part = getWordBoundriesAt(pos, &wordStart, &wordLen); - if (is_word_part) + S32 wordStart = 0; + S32 wordLen = 0; + S32 pos = getCursorPosFromLocalCoord(x, y, TRUE); + if (getWordBoundriesAt(pos, &wordStart, &wordLen)) { - const LLWString &text = mWText; - std::string selectedWord(std::string(text.begin(), text.end()).substr(wordStart,wordLen)); + const auto selectedWord = wstring_to_utf8str(getWText().substr(wordStart, wordLen)); if (!glggHunSpell->isSpelledRight(selectedWord)) { //misspelled word here, and you have just right clicked on it! - std::vector suggs = glggHunSpell->getSuggestionList(selectedWord); - for (int i = 0; i<(int)suggs.size(); i++) + menu->addSeparator(); + for (const auto& word : glggHunSpell->getSuggestionList(selectedWord)) { - SpellMenuBind * tempStruct = new SpellMenuBind; - tempStruct->origin = this; - tempStruct->word = suggs[i]; - tempStruct->wordPositionEnd = wordStart + wordLen; - tempStruct->wordPositionStart=wordStart; - tempStruct->wordY=y; - LLMenuItemCallGL * suggMenuItem = new LLMenuItemCallGL( - tempStruct->word, spell_correct, NULL, tempStruct); - tempStruct->menuItem = suggMenuItem; - suggestionMenuItems.push_back(tempStruct); - menu->addChild(suggMenuItem); + menu->addChild(new LLMenuItemCallGL(word, spell_correct, nullptr, this)); } - SpellMenuBind * tempStruct = new SpellMenuBind; - tempStruct->origin = this; - tempStruct->word = selectedWord; - tempStruct->wordPositionEnd = wordStart + wordLen; - tempStruct->wordPositionStart=wordStart; - tempStruct->wordY=y; - LLMenuItemCallGL * suggMenuItem = new LLMenuItemCallGL( - "Add Word", spell_add, NULL, tempStruct); - tempStruct->menuItem = suggMenuItem; - suggestionMenuItems.push_back(tempStruct); - menu->addChild(suggMenuItem); + menu->addChild(new LLMenuItemCallGL("Add Word", spell_add, nullptr, this)); } } - SpellMenuBind * tempStruct = new SpellMenuBind; - tempStruct->origin = this; - if (glggHunSpell->getSpellCheckHighlight()) - { - tempStruct->word = "Hide Misspellings"; - } - else - { - tempStruct->word = "Show Misspellings"; - } - - LLMenuItemCallGL * suggMenuItem = new LLMenuItemCallGL( - tempStruct->word, spell_show, NULL, tempStruct); - tempStruct->menuItem = suggMenuItem; - suggestionMenuItems.push_back(tempStruct); - menu->addChild(suggMenuItem); + bool show = !glggHunSpell->getSpellCheckHighlight(); + auto word = show ? "Show Misspellings" : "Hide Misspellings"; + menu->addChild(new LLMenuItemCallGL(word, spell_show, nullptr, show ? &show : nullptr)); } + mLastContextMenuX = x; mLastContextMenuY = y; - menu->buildDrawLabels(); - menu->updateParent(LLMenuGL::sMenuContainer); - LLMenuGL::showPopup(this, menu, x, y); + showMenu(this, menu, x, y); } return TRUE; } @@ -1469,11 +1509,17 @@ BOOL LLTextEditor::handleMiddleMouseDown(S32 x, S32 y, MASK mask) return TRUE; } +bool always_underline_links() +{ + static const LLUICachedControl always_underline("SinguAlwaysUnderlineLinks"); + return always_underline; +} BOOL LLTextEditor::handleHover(S32 x, S32 y, MASK mask) { BOOL handled = FALSE; + auto old_hover = mHoverSegment; mHoverSegment = NULL; if(hasMouseCapture() ) { @@ -1499,7 +1545,7 @@ BOOL LLTextEditor::handleHover(S32 x, S32 y, MASK mask) mSelectionEnd = mCursorPos; } - lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (active)" << llendl; + LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (active)" << LL_ENDL; getWindow()->setCursor(UI_CURSOR_IBEAM); handled = TRUE; } @@ -1527,14 +1573,14 @@ BOOL LLTextEditor::handleHover(S32 x, S32 y, MASK mask) { if(cur_segment->getStyle()->isLink()) { - lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (over link, inactive)" << llendl; + LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (over link, inactive)" << LL_ENDL; getWindow()->setCursor(UI_CURSOR_HAND); handled = TRUE; } else if(cur_segment->getStyle()->getIsEmbeddedItem()) { - lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (over embedded item, inactive)" << llendl; + LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (over embedded item, inactive)" << LL_ENDL; getWindow()->setCursor(UI_CURSOR_HAND); //getWindow()->setCursor(UI_CURSOR_ARROW); handled = TRUE; @@ -1545,7 +1591,7 @@ BOOL LLTextEditor::handleHover(S32 x, S32 y, MASK mask) if( !handled ) { - lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (inactive)" << llendl; + LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (inactive)" << LL_ENDL; if (!mScrollbar->getVisible() || x < getRect().getWidth() - SCROLLBAR_SIZE) { getWindow()->setCursor(UI_CURSOR_IBEAM); @@ -1558,6 +1604,14 @@ BOOL LLTextEditor::handleHover(S32 x, S32 y, MASK mask) } } + if (old_hover != mHoverSegment) + { + if (old_hover && !always_underline_links()) + old_hover->underlineOnHover(false); + if (mHoverSegment) + mHoverSegment->underlineOnHover(true); + } + if (mOnScrollEndCallback && mOnScrollEndData && (mScrollbar->getDocPos() == mScrollbar->getDocPosMax())) { mOnScrollEndCallback(mOnScrollEndData); @@ -1565,6 +1619,14 @@ BOOL LLTextEditor::handleHover(S32 x, S32 y, MASK mask) return handled; } +void LLTextEditor::onMouseLeave(S32 x, S32 y, MASK mask) +{ + if (mHoverSegment && !always_underline_links()) + { + mHoverSegment->underlineOnHover(false); + mHoverSegment = nullptr; + } +} BOOL LLTextEditor::handleMouseUp(S32 x, S32 y, MASK mask) { @@ -1723,11 +1785,6 @@ S32 LLTextEditor::remove(const S32 pos, const S32 length, const BOOL group_with_ return execute( new LLTextCmdRemove( pos, group_with_next_op, length ) ); } -S32 LLTextEditor::append(const LLWString &wstr, const BOOL group_with_next_op) -{ - return insert(mWText.length(), wstr, group_with_next_op); -} - S32 LLTextEditor::overwriteChar(S32 pos, llwchar wc) { if ((S32)mWText.length() == pos) @@ -1814,6 +1871,33 @@ void LLTextEditor::removeChar() } } +// Remove a word (set of characters up to next space/punctuation) from the text +void LLTextEditor::removeWord(bool prev) +{ + const S32& pos(mCursorPos); + if (prev ? pos > 0 : pos < getLength()) + { + S32 new_pos(prev ? prevWordPos(pos) : nextWordPos(pos)); + if (new_pos == pos) // Other character we don't jump over + new_pos = prev ? prevWordPos(new_pos-1) : nextWordPos(new_pos+1); + + const U32 diff(labs(pos - new_pos)); + if (prev) + { + remove(new_pos, diff, false); + setCursorPos(new_pos); + } + else + { + remove(pos, diff, false); + } + } + else + { + reportBadKeystroke(); + } +} + // Add a single character to the text S32 LLTextEditor::addChar(S32 pos, llwchar wc) { @@ -2133,7 +2217,7 @@ BOOL LLTextEditor::canCopy() const } // copy selection to clipboard -void LLTextEditor::copy() +void LLTextEditor::copy(bool raw) const { if( !canCopy() ) { @@ -2141,7 +2225,54 @@ void LLTextEditor::copy() } S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); S32 length = llabs( mSelectionStart - mSelectionEnd ); - gClipboard.copyFromSubstring(mWText, left_pos, length, mSourceID); + // Does our selection include any Segments with links? + if (mParseHTML && raw) + { + auto begin = std::find_if(mSegments.begin(), mSegments.end(), [left_pos](const LLTextSegmentPtr& ptr) { + return ptr->getEnd() > left_pos; + }); + auto last = mSegments.end(); + if (begin == last || begin->isNull()) + { + gClipboard.copyFromSubstring(mWText, left_pos, length, mSourceID); + return; + } + S32 right_pos = left_pos + length, offset = 0; + { + // If our selection starts in the middle of a link, set our left_pos to the beginning of its segment. + auto segment = **begin; + if (auto style = segment.getStyle()) + if (style->isLink()) + left_pos = llmin(segment.getStart(), left_pos); + } + auto text = mWText.substr(left_pos, length); + for (; begin->notNull() && begin != last && (*begin)->getStart() <= right_pos; ++begin) + { + auto segment = **begin; + //llassert(segment->getStyle()); // If someone is stores the result of the S32 constructor, they're in so much trouble!! + const auto& link = segment.getStyle()->getLinkHREF(); + if (!link.empty()) + { + const S32 label_length = (segment.getEnd() - segment.getStart()); + const S32 start = (segment.getStart()+offset)-left_pos; + const auto label = text.substr(start, label_length); + const auto wlink = utf8str_to_wstring(link); + const auto pos = wlink.find(label); + // Do not replace if normal link, or contains normal link (but may omit protocol) but ends the same way + // (i.e. [http://foo.bar/baz foo.bar] should still be restored here but not foo.bar/baz or foo.bar + if (pos == std::string::npos // Label is not (part of) the url + || (pos != 0 && wlink[pos-1] != '/') || pos+label.size() != wlink.size()) // Label is part of the url but there's more on either side of the url after the protocol + { + constexpr llwchar startchar = '[', space = ' ', endchar = ']'; + const auto raw_html = startchar + wlink + space + label + endchar; + text.replace(start, label_length, raw_html); + offset += raw_html.size() - label_length; // Track how much we've offset the string by replacing labels with their raw html and thus adding characters + } + } + } + gClipboard.copyFromSubstring(text, 0, text.length(), mSourceID); + } + else gClipboard.copyFromSubstring(mWText, left_pos, length, mSourceID); } BOOL LLTextEditor::canPaste() const @@ -2150,17 +2281,6 @@ BOOL LLTextEditor::canPaste() const } -void LLTextEditor::spellReplace(SpellMenuBind* spellData) -{ - remove( spellData->wordPositionStart, - spellData->wordPositionEnd - spellData->wordPositionStart, TRUE ); - LLWString clean_string = utf8str_to_wstring(spellData->word); - insert(spellData->wordPositionStart, clean_string, FALSE); - mCursorPos+=clean_string.length() - (spellData->wordPositionEnd-spellData->wordPositionStart); - needsReflow(); -} - - // paste from clipboard void LLTextEditor::paste() { @@ -2341,6 +2461,13 @@ BOOL LLTextEditor::handleControlKey(const KEY key, const MASK mask) } break; + case KEY_DELETE: + if (getEnabled()) + removeWord(false); + else + handled = false; + break; + default: handled = FALSE; break; @@ -2372,6 +2499,17 @@ BOOL LLTextEditor::handleEditKey(const KEY key, const MASK mask) } handled = TRUE; } + else if ((mask & (MASK_CONTROL|MASK_SHIFT)) == (MASK_CONTROL|MASK_SHIFT)) + { + if (key == 'C') + { + if (canCopy()) + copy(true); + else + reportBadKeystroke(); + handled = TRUE; + } + } else if( MASK_CONTROL & mask ) { @@ -2447,7 +2585,10 @@ BOOL LLTextEditor::handleSpecialKey(const KEY key, const MASK mask, BOOL* return else if( 0 < mCursorPos ) { - removeCharOrTab(); + if (mask == MASK_CONTROL) + removeWord(true); + else + removeCharOrTab(); } else { @@ -2455,7 +2596,6 @@ BOOL LLTextEditor::handleSpecialKey(const KEY key, const MASK mask, BOOL* return } break; - case KEY_RETURN: if (mask == MASK_NONE) { @@ -2887,7 +3027,7 @@ void LLTextEditor::drawSelectionBackground() const S32 text_len = getLength(); std::queue line_endings; - S32 line_height = llround( mGLFont->getLineHeight() ); + S32 line_height = ll_round( mGLFont->getLineHeight() ); S32 selection_left = llmin( mSelectionStart, mSelectionEnd ); S32 selection_right = llmax( mSelectionStart, mSelectionEnd ); @@ -2983,7 +3123,7 @@ void LLTextEditor::drawSelectionBackground() { gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); const LLColor4& color = mReadOnly ? mReadOnlyBgColor : mWriteableBgColor; - F32 alpha = hasFocus() ? 1.f : 0.5f; + F32 alpha = hasFocus() ? 1.f : 0.8f; gGL.color4f( 1.f - color.mV[0], 1.f - color.mV[1], 1.f - color.mV[2], alpha ); S32 margin_offset = mShowLineNumbers ? UI_TEXTEDITOR_LINE_NUMBER_MARGIN : 0; @@ -3082,7 +3222,7 @@ void LLTextEditor::drawMisspelled() S32 line_end = 0; // Determine if the cursor is visible and if so what its coordinates are. - while( (mTextRect.mBottom <= llround(text_y)) && (search_pos < num_lines)) + while( (mTextRect.mBottom <= ll_round(text_y)) && (search_pos < num_lines)) { line_end = text_len + 1; S32 next_line = -1; @@ -3157,7 +3297,7 @@ void LLTextEditor::drawCursor() S32 line_end = 0; // Determine if the cursor is visible and if so what its coordinates are. - while( (mTextRect.mBottom <= llround(text_y)) && (cur_pos < num_lines)) + while( (mTextRect.mBottom <= ll_round(text_y)) && (cur_pos < num_lines)) { line_end = text_len + 1; S32 next_line = -1; @@ -3276,7 +3416,7 @@ void LLTextEditor::drawPreeditMarker() return; } - const S32 line_height = llround( mGLFont->getLineHeight() ); + const S32 line_height = ll_round( mGLFont->getLineHeight() ); S32 line_start = getLineStart(cur_line); S32 line_y = mTextRect.mTop - line_height; @@ -3396,16 +3536,18 @@ void LLTextEditor::drawText() if (seg_iter == mSegments.end() || (*seg_iter)->getStart() > line_start) --seg_iter; LLTextSegment* cur_segment = *seg_iter; - S32 line_height = llround( mGLFont->getLineHeight() ); + S32 line_height = ll_round( mGLFont->getLineHeight() ); F32 text_y = (F32)(mTextRect.mTop - line_height); while((mTextRect.mBottom <= text_y) && (cur_line < num_lines)) { + S32 next_line = cur_line + 1; + S32 next_start = -1; S32 line_end = text_len; - if ((cur_line + 1) < num_lines) + if (next_line < num_lines) { - next_start = getLineStart(cur_line + 1); + next_start = getLineStart(next_line); line_end = next_start; } line_wraps = text[line_end-1] != '\n'; @@ -3421,13 +3563,13 @@ void LLTextEditor::drawText() if( mShowLineNumbers && !cur_line_is_continuation) { const LLFontGL *num_font = LLFontGL::getFontMonospace(); - F32 y_top = text_y + ((F32)llround(num_font->getLineHeight()) / 2); - const LLWString ltext = utf8str_to_wstring(llformat("%*d", UI_TEXTEDITOR_LINE_NUMBER_DIGITS, cur_line_num )); + F32 y_top = text_y + ((F32)ll_round(num_font->getLineHeight()) / 2); BOOL is_cur_line = getCurrentLine() == cur_line_num; const U8 style = is_cur_line ? LLFontGL::BOLD : LLFontGL::NORMAL; const LLColor4 fg_color = is_cur_line ? mCursorColor : mReadOnlyFgColor; - num_font->render( - ltext, // string to draw + + num_font->renderUTF8( + llformat("%*d", UI_TEXTEDITOR_LINE_NUMBER_DIGITS, cur_line_num), // string to draw 0, // begin offset 3., // x y_top, // y @@ -3437,9 +3579,11 @@ void LLTextEditor::drawText() style, LLFontGL::NO_SHADOW, S32_MAX, // max chars - UI_TEXTEDITOR_LINE_NUMBER_MARGIN); // max pixels + UI_TEXTEDITOR_LINE_NUMBER_MARGIN, + NULL); // max pixels } + // draw a single line of text S32 seg_start = line_start; while( seg_start < line_end ) { @@ -3448,7 +3592,7 @@ void LLTextEditor::drawText() seg_iter++; if (seg_iter == mSegments.end()) { - llwarns << "Ran off the segmentation end!" << llendl; + LL_WARNS() << "Ran off the segmentation end!" << LL_ENDL; return; } cur_segment = *seg_iter; @@ -3465,7 +3609,7 @@ void LLTextEditor::drawText() S32 style_image_height = style->mImageHeight; S32 style_image_width = style->mImageWidth; LLUIImagePtr image = style->getImage(); - image->draw(llround(text_x), llround(text_y)+line_height-style_image_height, + image->draw(ll_round(text_x), ll_round(text_y)+line_height-style_image_height, style_image_width, style_image_height); } @@ -3474,13 +3618,6 @@ void LLTextEditor::drawText() style->mUnderline = TRUE; } - S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); - - if ( (mParseHTML) && (left_pos > seg_start) && (left_pos < clipped_end) && mIsSelecting && (mSelectionStart == mSelectionEnd) ) - { - mHTML = style->getLinkHREF(); - } - drawClippedSegment( text, seg_start, clipped_end, text_x, text_y, selection_left, selection_right, style, &text_x ); if( text_x == text_start && mShowLineNumbers ) @@ -3552,7 +3689,7 @@ void LLTextEditor::drawClippedSegment(const LLWString &text, S32 seg_start, S32 } } - F32 y_top = y + (F32)llround(font->getLineHeight()); + F32 y_top = y + (F32)ll_round(font->getLineHeight()); if( selection_left > seg_start ) { @@ -3955,7 +4092,7 @@ void LLTextEditor::reshape(S32 width, S32 height, BOOL called_from_parent) // propagate shape information to scrollbar mScrollbar->setDocSize( getLineCount() ); - S32 line_height = llround( mGLFont->getLineHeight() ); + S32 line_height = ll_round( mGLFont->getLineHeight() ); S32 page_lines = mTextRect.getHeight() / line_height; mScrollbar->setPageSize( page_lines ); } @@ -4030,31 +4167,76 @@ void LLTextEditor::appendColoredText(const std::string &new_text, style->setVisible(true); style->setColor(lcolor); style->setFontName(font_name); - appendStyledText(new_text, allow_undo, prepend_newline, style); + appendText(new_text, allow_undo, prepend_newline, style); } -void LLTextEditor::appendStyledText(const std::string &new_text, - bool allow_undo, - bool prepend_newline, - LLStyleSP stylep) +static LLTrace::BlockTimerStatHandle FTM_APPEND_TEXT("Append Text"); + +void LLTextEditor::appendText(const std::string &new_text, bool allow_undo, bool prepend_newline, + const LLStyleSP style, bool force_replace_links) { - S32 part = (S32)LLTextParser::WHOLE; - if(mParseHTML) + LL_RECORD_BLOCK_TIME(FTM_APPEND_TEXT); + if (new_text.empty()) + return; + + std::string text = prepend_newline && !mWText.empty() ? ('\n' + new_text) : new_text; + appendTextImpl(text, style, force_replace_links); + + if (!allow_undo) { + blockUndo(); + } +} + +static LLTrace::BlockTimerStatHandle FTM_PARSE_HTML("Parse HTML"); + +// Appends new text to end of document +void LLTextEditor::appendTextImpl(const std::string &new_text, const LLStyleSP style, bool force_replace_links) +{ + std::string text = new_text; + static const LLUICachedControl replace_links("SinguReplaceLinks"); + force_replace_links = force_replace_links || replace_links; + bool is_link = style && style->isLink(); // Don't search for URLs inside a link segment (STORM-358). - S32 start=0,end=0; - std::string text = new_text; - while ( findHTML(text, &start, &end) ) + S32 part = (S32)LLTextParser::WHOLE; + if (mReadOnly && mParseHTML && !is_link) // Singu Note: Do not replace html if the user is going to edit it. (Like in profiles) + { + LL_RECORD_BLOCK_TIME(FTM_PARSE_HTML); + size_t start=0, end=0; + LLUrlMatch match; + auto append_substr = [&](const size_t& pos, const size_t& count) { - LLStyleSP html(new LLStyle); - html->setVisible(true); - html->setColor(mLinkColor); - if (stylep) + appendAndHighlightText(text.substr(pos, count), part, style); + }; + auto append_link = [&](const std::string& link, LLStyleSP link_style) + { + if (!link_style->isLink()) { - html->setFontName(stylep->getFontString()); + appendAndHighlightText(link, part, style); + return; } - html->mUnderline = TRUE; + if (style) // Respect styling + { + const auto& text_style = *style; + link_style->mItalic = text_style.mItalic; + link_style->mBold = text_style.mBold; + link_style->mUnderline = text_style.mUnderline; + } + // Hack around colors looking bad on some backgrounds by allowing setting link color for this editor + if (mLinkColor) link_style->setColor(*mLinkColor); + const auto always_underline(always_underline_links()); + if (always_underline) link_style->mUnderline = true; + appendAndHighlightText(link, part, link_style, !always_underline/*match.underlineOnHoverOnly()*/); + }; + const auto&& cb = force_replace_links ? boost::bind(&LLTextEditor::replaceUrl, this, _1, _2, _3) : static_cast(LLUrlRegistryNullCallback); + auto& urlr = LLUrlRegistry::instance(); + while (!text.empty() && urlr.findUrl(text, match, cb)) + { + start = match.getStart(); + end = match.getEnd()+1; + + // output the text before the Url if (start > 0) { if (part == (S32)LLTextParser::WHOLE || @@ -4066,15 +4248,69 @@ void LLTextEditor::appendStyledText(const std::string &new_text, { part = (S32)LLTextParser::MIDDLE; } - std::string subtext=text.substr(0,start); - appendHighlightedText(subtext,allow_undo, prepend_newline, part, stylep); + append_substr(0, start); } - - html->setLinkHREF(text.substr(start,end-start)); - appendText(text.substr(start, end-start),allow_undo, prepend_newline, html); - if (end < (S32)text.length()) + + auto url = match.getUrl(); + const auto& label = match.getLabel(); + if (force_replace_links || url == label) { - text = text.substr(end,text.length() - end); + // add icon before url if need + /* Singu TODO: Icons next to links? + LLTextUtil::processUrlMatch(&match, this, isContentTrusted() || match.isTrusted()); + if ((isContentTrusted() || match.isTrusted()) && !match.getIcon().empty() ) + { + link_style->setImage(match.getIcon()); + setLastSegmentToolTip(LLTrans::getString("TooltipSLIcon")); + }*/ + + // output the styled url + append_link(label + match.getQuery(), match.getStyle()); + bool tooltip_required = !match.getTooltip().empty(); + + // set the tooltip for the Url label + if (tooltip_required) + { + setLastSegmentToolTip(match.getTooltip()); + } + + /* Singu Note: Upstream uses hardcoded Grey here, they have no care for skins, this could be awful! + Also it splits up the link! For now just make it append it to the same segment with its label above. + // show query part of url with gray color only for LLUrlEntryHTTP and LLUrlEntryHTTPNoProtocol url entries + std::string label = match.getQuery(); + if (!label.empty()) + { + link_params.color = LLColor4::grey; + link_params.readonly_color = LLColor4::grey; + appendAndHighlightTextImpl(label, part, link_params, match.underlineOnHoverOnly()); + append_link(label); + + // set the tooltip for the query part of url + if (tooltip_required) + { + setLastSegmentToolTip(match.getTooltip()); + } + }*/ + } + else // Still link the link itself + { + const auto pos = text.find(url); + bool fallback(pos == std::string::npos); // In special cases like no protocol and brackets + bool brackets(fallback && text.find('[') == start); // Brackets + if (fallback == brackets && start < pos) // Leading text, only in special case if brackets present + append_substr(start, brackets ? 1 : pos-start); + // In the special cases, only link exactly the url, this might not have a protocol so calculate the exact string + if (fallback) url = brackets ? text.substr(start+1, text.find(' ', start+2)-start) : text.substr(start, end-start); + append_link(url, match.getStyle()); // Append the link + const auto url_end = pos + url.size(); + if (fallback == brackets && end > url_end) // Ending text, only in special case if brackets present + append_substr(url_end, end-url_end); + } + + // move on to the rest of the text after the Url + if (end < (S32)text.length()) + { + text = text.substr(end, text.length() - end); end=0; part=(S32)LLTextParser::END; } @@ -4083,51 +4319,135 @@ void LLTextEditor::appendStyledText(const std::string &new_text, break; } } - if (part != (S32)LLTextParser::WHOLE) part=(S32)LLTextParser::END; - if (end < (S32)text.length()) appendHighlightedText(text,allow_undo, prepend_newline, part, stylep); + if (part != (S32)LLTextParser::WHOLE) + part=(S32)LLTextParser::END; + if (end < (S32)text.length()) + appendAndHighlightText(text, part, style); } else { - appendHighlightedText(new_text, allow_undo, prepend_newline, part, stylep); + appendAndHighlightText(text, part, style); } } -void LLTextEditor::appendHighlightedText(const std::string &new_text, - bool allow_undo, - bool prepend_newline, - S32 highlight_part, - LLStyleSP stylep) +void LLTextEditor::setLastSegmentToolTip(const std::string &tooltip) { - // If LindenUserDir is empty then we didn't login yet. - // In that case we can't instantiate LLTextParser, which - // is initialized per user. - if (mParseHighlights && !gDirUtilp->getLindenUserDir(true).empty()) + LLTextSegmentPtr segment = mSegments.back(); + segment->setToolTip(tooltip); +} + +void LLTextEditor::appendLineBreakSegment(/*const LLStyle::Params& style_params*/) +{ + /* + segment_vec_t segments; + LLStyleSP sp(new LLStyle(style_params)); + const auto& length = getLength(); + segments.push_back(new LLTextSegment(sp, length, length + 1));*/ + + insertStringNoUndo(getLength(), LLWString(1, '\n')); +} + +void LLTextEditor::appendAndHighlightText(const std::string& new_text, S32 highlight_part, const LLStyleSP stylep, bool underline_on_hover) +{ + if (new_text.empty()) return; + + std::string::size_type start = 0; + /*std::string::size_type pos = new_text.find('\n',start); + + while(pos != std::string::npos) { - LLTextParser* highlight = LLTextParser::getInstance(); - - if (highlight && stylep) + if(pos!=start) { - LLSD pieces = highlight->parsePartialLineHighlights(new_text, stylep->getColor(), (LLTextParser::EHighlightPosition)highlight_part); - bool lprepend=prepend_newline; - for (S32 i=0;igetStyle(); + + // update segment start/end length in case we replaced text earlier + S32 seg_length = seg->getEnd() - seg->getStart(); + seg->setStart(seg_start); + seg->setEnd(seg_start + seg_length); + + // if we find a link with our Url, then replace the label + if (style->getLinkHREF() == url) + { + S32 start = seg->getStart(); + S32 end = seg->getEnd(); + const auto& old_label = text.substr(start, end - start); + if (wlabel != old_label) { - LLSD color_llsd = pieces[i]["color"]; - LLColor4 lcolor; - lcolor.setValue(color_llsd); - LLStyleSP lstylep(new LLStyle(*stylep)); - lstylep->setColor(lcolor); - if (i != 0 && (pieces.size() > 1) ) lprepend=FALSE; - appendText((std::string)pieces[i]["text"], allow_undo, lprepend, lstylep); + const auto difference = std::abs((S32)wlabel.length() - (S32)old_label.length()); + if (mSelectionEnd >= end) // Selection stays at/after end + { + mSelectionEnd += difference; + if (mSelectionStart >= end) + mSelectionStart += difference; + } + if (mCursorPos >= end) // Cursor stays at/after end + mCursorPos += difference; + text.replace(start, end - start, wlabel); + seg->setEnd(start + wlabel.size()); + modified = true; } - return; } + + /* Singu TODO: Icons with Urls? + // Icon might be updated when more avatar or group info + // becomes available + if (style->isImage() && style->getLinkHREF() == url) + { + LLUIImagePtr image = image_from_icon_name( icon ); + if (image) + { + LLStyle::Params icon_params; + icon_params.image = image; + LLStyleConstSP new_style(new LLStyle(icon_params)); + seg->setStyle(new_style); + modified = true; + } + } + */ + + // work out the character offset for the next segment + seg_start = seg->getEnd(); + } + + // update the editor with the new (wide) text string + if (modified) + { + mWText = text; + mTextIsUpToDate = FALSE; + setCursorPos(mCursorPos); + needsReflow(); } - appendText(new_text, allow_undo, prepend_newline, stylep); } -// Appends new text to end of document -void LLTextEditor::appendText(const std::string &new_text, bool allow_undo, bool prepend_newline, - const LLStyleSP stylep) + +void LLTextEditor::appendAndHighlightTextImpl(const std::string& new_text, S32 highlight_part, const LLStyleSP stylep, bool underline_on_hover) { // Save old state BOOL was_scrolled_to_bottom = (mScrollbar->getDocPos() == mScrollbar->getDocPosMax()); @@ -4142,29 +4462,61 @@ void LLTextEditor::appendText(const std::string &new_text, bool allow_undo, bool setCursorPos(old_length); - // Add carriage return if not first line - if (getLength() != 0 - && prepend_newline) + // This is where we appendHighlightedText + // If LindenUserDir is empty then we didn't login yet. + // In that case we can't instantiate LLTextParser, which is initialized per user. + LLTextParser* highlight = mParseHighlights && stylep && !gDirUtilp->getLindenUserDir(true).empty() ? LLTextParser::getInstance() : nullptr; + if (highlight) { - std::string final_text = "\n"; - final_text += new_text; - append(utf8str_to_wstring(final_text), TRUE); + const LLSD pieces = highlight->parsePartialLineHighlights(new_text, stylep->getColor(), (LLTextParser::EHighlightPosition)highlight_part); + auto cur_length = getLength(); + for (auto i = pieces.beginArray(), end = pieces.endArray(); i < end; ++i) + { + const auto& piece = *i; + LLWString wide_text = utf8str_to_wstring(piece["text"].asString()); + + insertStringNoUndo(cur_length, wide_text); + LLStyleSP sp(new LLStyle(*stylep)); + sp->setColor(piece["color"]); + auto wide_size = wide_text.size(); + LLTextSegmentPtr segmentp = new LLTextSegment(sp, cur_length, cur_length + wide_size); + cur_length += wide_size; + if (underline_on_hover) segmentp->setUnderlineOnHover(true); + mSegments.push_back(segmentp); + } } else { - append(utf8str_to_wstring(new_text), TRUE ); - } + LLWString wide_text = utf8str_to_wstring(new_text); - if (stylep) - { - S32 segment_start = old_length; - S32 segment_end = getLength(); - LLTextSegmentPtr segment = new LLTextSegment(stylep, segment_start, segment_end ); - mSegments.push_back(segment); + auto length = getLength(); + auto insert_len = length + insertStringNoUndo(length, utf8str_to_wstring(new_text)); + + if (stylep) + { + S32 segment_start = old_length; + S32 segment_end = old_length + wide_text.size(); + LLTextSegmentPtr segment = new LLTextSegment(stylep, segment_start, segment_end); + if (underline_on_hover) segment->setUnderlineOnHover(true); + mSegments.push_back(segment); + } + else // If no style, still make a segment, + { + auto segment = mSegments.empty() ? nullptr : mSegments.back(); + if (!segment || !segment->getIsDefault()) + { + LLColor4& text_color = (mReadOnly ? mReadOnlyFgColor : mFgColor); + LLTextSegmentPtr segment = new LLTextSegment(text_color, length, insert_len); + segment->setIsDefault(true); // call it a default segment so we can consolidate later. + mSegments.push_back(segment); + } + else // It's later! + { + segment->setEnd(insert_len); + } + } } - - needsReflow(); - + // Set the cursor and scroll position // Maintain the scroll position unless the scroll was at the end of the doc (in which // case, move it to the new end of the doc) or unless the user was doing actively selecting @@ -4178,14 +4530,11 @@ void LLTextEditor::appendText(const std::string &new_text, bool allow_undo, bool } endOfDoc(); } - else if( selection_start != selection_end ) + else if (was_selecting || selection_start != selection_end) { mSelectionStart = selection_start; mSelectionEnd = selection_end; - - - mIsSelecting = was_selecting; setCursorPos(cursor_pos); } @@ -4197,11 +4546,6 @@ void LLTextEditor::appendText(const std::string &new_text, bool allow_undo, bool { setCursorPos(cursor_pos); } - - if( !allow_undo ) - { - blockUndo(); - } } void LLTextEditor::removeTextFromEnd(S32 num_chars) @@ -4234,20 +4578,76 @@ S32 LLTextEditor::insertStringNoUndo(const S32 pos, const LLWString &wstr) mWText.insert(pos, wstr); mTextIsUpToDate = FALSE; - if ( truncate() ) + //HACK: If we are readonly we shouldn't need to truncate + if (!mReadOnly && truncate()) { // The user's not getting everything he's hoping for make_ui_sound("UISndBadKeystroke"); insert_len = mWText.length() - old_len; } + needsReflow(/*pos*/); + return insert_len; } S32 LLTextEditor::removeStringNoUndo(S32 pos, S32 length) { + auto seg_iter = getSegIterContaining(pos); + S32 end = pos + length; + while(seg_iter != mSegments.end()) + { + LLTextSegmentPtr segmentp = *seg_iter; + if (segmentp->getStart() < pos) + { + // deleting from middle of segment + if (segmentp->getEnd() > end) + { + segmentp->setEnd(segmentp->getEnd() - length); + } + // truncating segment + else + { + segmentp->setEnd(pos); + } + } + else if (segmentp->getStart() < end) + { + // deleting entire segment + if (segmentp->getEnd() <= end) + { + // remove segment + seg_iter = mSegments.erase(seg_iter); + continue; + } + // deleting head of segment + else + { + segmentp->setStart(pos); + segmentp->setEnd(segmentp->getEnd() - length); + } + } + else + { + // shifting segments backward to fill deleted portion + segmentp->setStart(segmentp->getStart() - length); + segmentp->setEnd(segmentp->getEnd() - length); + } + ++seg_iter; + } + mWText.erase(pos, length); + + // recreate default segment in case we erased everything + createDefaultSegment(); + mTextIsUpToDate = FALSE; + + /*needsReflow(pos);*/ + // Singu Note: This kinda sucks for performance of delete, fix this later (with LLTextBase merge?) + updateLineStartList(); + mReflowNeeded = false; + return -length; // This will be wrong if someone calls removeStringNoUndo with an excessive length } @@ -4359,13 +4759,32 @@ void LLTextEditor::loadKeywords(const std::string& filename, } } -static LLFastTimer::DeclareTimer FTM_SYNTAX_HIGHLIGHTING("Syntax Highlighting"); -static LLFastTimer::DeclareTimer FTM_UPDATE_TEXT_SEGMENTS("Update Text Segments"); +static LLTrace::BlockTimerStatHandle FTM_SYNTAX_HIGHLIGHTING("Syntax Highlighting"); +static LLTrace::BlockTimerStatHandle FTM_UPDATE_TEXT_SEGMENTS("Update Text Segments"); + + +void LLTextEditor::createDefaultSegment() +{ + if (mSegments.empty()) + { + LLColor4& text_color = (mReadOnly ? mReadOnlyFgColor : mFgColor); + LLTextSegmentPtr default_segment = new LLTextSegment(text_color, 0, mWText.length()); + default_segment->setIsDefault(TRUE); + mSegments.push_back(default_segment); + } +} + +void LLTextEditor::clearSegments() +{ + mLineStartList.clear(); + mSegments.clear(); + createDefaultSegment(); +} void LLTextEditor::updateSegments() { { - LLFastTimer ft(FTM_SYNTAX_HIGHLIGHTING); + LL_RECORD_BLOCK_TIME(FTM_SYNTAX_HIGHLIGHTING); if (mKeywords.isLoaded()) { // HACK: No non-ascii keywords for now @@ -4377,19 +4796,13 @@ void LLTextEditor::updateSegments() } } - LLFastTimer ft(FTM_UPDATE_TEXT_SEGMENTS); + LL_RECORD_BLOCK_TIME(FTM_UPDATE_TEXT_SEGMENTS); // Make sure we have at least one segment if (mSegments.size() == 1 && mSegments[0]->getIsDefault()) { - mSegments.clear(); // create default segment - } - if (mSegments.empty()) - { - LLColor4& text_color = ( mReadOnly ? mReadOnlyFgColor : mFgColor ); - LLTextSegmentPtr default_segment = new LLTextSegment( text_color, 0, mWText.length() ); - default_segment->setIsDefault(TRUE); - mSegments.push_back(default_segment); + clearSegments(); // create default segment } + else createDefaultSegment(); } // Only effective if text was removed from the end of the editor @@ -4421,7 +4834,7 @@ void LLTextEditor::pruneSegments() } else { - llwarns << "Tried to erase end of empty LLTextEditor" << llendl; + LL_WARNS() << "Tried to erase end of empty LLTextEditor" << LL_ENDL; } } @@ -4492,10 +4905,16 @@ BOOL LLTextEditor::handleMouseUpOverSegment(S32 x, S32 y, MASK mask) // This mouse up was part of a click. // Regardless of where the cursor is, see if we recently touched a link // and launch it if we did. - if (mParseHTML && mHTML.length() > 0) + if (mParseHTML) { - LLUrlAction::clickAction(mHTML); - mHTML.clear(); + if (auto segment = getSegmentAtLocalPos(x, y)) + { + if (auto style = segment->getStyle()) + { + if (style->isLink()) + LLUrlAction::clickAction(style->getLinkHREF(), true); + } + } } } @@ -4503,6 +4922,34 @@ BOOL LLTextEditor::handleMouseUpOverSegment(S32 x, S32 y, MASK mask) } +LLTextEditor::segment_list_t::iterator LLTextEditor::getSegIterContaining(S32 index) +{ + S32 text_len = getLength(); + + if (index > text_len) { return mSegments.end(); } + + // when there are no segments, we return the end iterator, which must be checked by caller + if (mSegments.size() <= 1) { return mSegments.begin(); } + + LLPointer index_segment = new LLTextSegment(index); + auto it = std::lower_bound(mSegments.begin(), mSegments.end(), index_segment, LLTextSegment::compare()); + return it; +} + +LLTextEditor::segment_list_t::const_iterator LLTextEditor::getSegIterContaining(S32 index) const +{ + S32 text_len = getLength(); + + if (index > text_len) { return mSegments.end(); } + + // when there are no segments, we return the end iterator, which must be checked by caller + if (mSegments.size() <= 1) { return mSegments.begin(); } + + LLPointer index_segment = new LLTextSegment(index); + auto it = std::lower_bound(mSegments.begin(), mSegments.end(), index_segment, LLTextSegment::compare()); + return it; +} + // Finds the text segment (if any) at the give local screen position LLTextSegment* LLTextEditor::getSegmentAtLocalPos( S32 x, S32 y ) const { @@ -4544,110 +4991,6 @@ void LLTextEditor::setOnScrollEndCallback(void (*callback)(void*), void* userdat mScrollbar->setOnScrollEndCallback(callback, userdata); } -/////////////////////////////////////////////////////////////////// -// Hack for Notecards - -BOOL LLTextEditor::importBuffer(const char* buffer, S32 length ) -{ - std::istringstream instream(buffer); - - // Version 1 format: - // Linden text version 1\n - // {\n - // - // Text length \n - // (text may contain ext_char_values) - // }\n - - char tbuf[MAX_STRING]; /* Flawfinder: ignore */ - - S32 version = 0; - instream.getline(tbuf, MAX_STRING); - if( 1 != sscanf(tbuf, "Linden text version %d", &version) ) - { - llwarns << "Invalid Linden text file header " << llendl; - return FALSE; - } - - if( 1 != version ) - { - llwarns << "Invalid Linden text file version: " << version << llendl; - return FALSE; - } - - instream.getline(tbuf, MAX_STRING); - if( 0 != sscanf(tbuf, "{") ) - { - llwarns << "Invalid Linden text file format" << llendl; - return FALSE; - } - - S32 text_len = 0; - instream.getline(tbuf, MAX_STRING); - if( 1 != sscanf(tbuf, "Text length %d", &text_len) ) - { - llwarns << "Invalid Linden text length field" << llendl; - return FALSE; - } - - if( text_len > mMaxTextByteLength ) - { - llwarns << "Invalid Linden text length: " << text_len << llendl; - return FALSE; - } - - BOOL success = TRUE; - - char* text = new char[ text_len + 1]; - if (text == NULL) - { - llerrs << "Memory allocation failure." << llendl; - return FALSE; - } - instream.get(text, text_len + 1, '\0'); - text[text_len] = '\0'; - if( text_len != (S32)strlen(text) )/* Flawfinder: ignore */ - { - llwarns << llformat("Invalid text length: %d != %d ",strlen(text),text_len) << llendl;/* Flawfinder: ignore */ - success = FALSE; - } - - instream.getline(tbuf, MAX_STRING); - if( success && (0 != sscanf(tbuf, "}")) ) - { - llwarns << "Invalid Linden text file format: missing terminal }" << llendl; - success = FALSE; - } - - if( success ) - { - // Actually set the text - setText( LLStringExplicit(text) ); - } - - delete[] text; - - setCursorPos(0); - deselect(); - - needsReflow(); - return success; -} - -BOOL LLTextEditor::exportBuffer(std::string &buffer ) -{ - std::ostringstream outstream(buffer); - - outstream << "Linden text version 1\n"; - outstream << "{\n"; - - outstream << llformat("Text length %d\n", mWText.length() ); - outstream << getText(); - outstream << "}\n"; - - return TRUE; -} - ////////////////////////////////////////////////////////////////////////// // LLTextSegment @@ -4693,26 +5036,45 @@ LLTextSegment::LLTextSegment( const LLColor3& color, S32 start, S32 end ) : BOOL LLTextSegment::getToolTip(std::string& msg) const { + // do we have a tooltip for a loaded keyword (for script editor)? if (mToken && !mToken->getToolTip().empty()) { const LLWString& wmsg = mToken->getToolTip(); msg = wstring_to_utf8str(wmsg); return TRUE; } + // or do we have an explicitly set tooltip (e.g., for Urls) + if (!mTooltip.empty()) + { + msg = mTooltip; + return TRUE; + } + return FALSE; } +void LLTextSegment::setToolTip(const std::string& tooltip) +{ + // we cannot replace a keyword tooltip that's loaded from a file + if (mToken) + { + LL_WARNS() << "LLTextSegment::setToolTip: cannot replace keyword tooltip." << LL_ENDL; + return; + } + mTooltip = tooltip; +} + void LLTextSegment::dump() const { - llinfos << "Segment [" << + LL_INFOS() << "Segment [" << // mColor.mV[VX] << ", " << // mColor.mV[VY] << ", " << // mColor.mV[VZ] << "]\t[" << mStart << ", " << getEnd() << "]" << - llendl; + LL_ENDL; } @@ -4730,6 +5092,7 @@ LLXMLNodePtr LLTextEditor::getXML(bool save_children) const node->createChild("font", TRUE)->setStringValue(LLFontGL::nameFromFont(mGLFont)); node->createChild("word_wrap", TRUE)->setBoolValue(mWordWrap); node->createChild("hide_scrollbar", TRUE)->setBoolValue(mHideScrollbarForShortDocs); + node->createChild("hide_border", TRUE)->setBoolValue(!mBorder->getVisible()); addColorXML(node, mCursorColor, "cursor_color", "TextCursorColor"); addColorXML(node, mFgColor, "text_color", "TextFgColor"); @@ -4745,40 +5108,6 @@ LLXMLNodePtr LLTextEditor::getXML(bool save_children) const return node; } -// static -LLView* LLTextEditor::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) -{ - LLRect rect; - createRect(node, rect, parent, LLRect()); - - U32 max_text_length = 255; - node->getAttributeU32("max_length", max_text_length); - - BOOL allow_embedded_items; - node->getAttributeBOOL("embedded_items", allow_embedded_items); - - LLFontGL* font = LLView::selectFont(node); - - std::string text = node->getTextContents().substr(0, max_text_length - 1); - - LLTextEditor* text_editor = new LLTextEditor("text_editor", - rect, - max_text_length, - text, - font, - allow_embedded_items); - - text_editor->setTextEditorParameters(node); - - BOOL hide_scrollbar = FALSE; - node->getAttributeBOOL("hide_scrollbar",hide_scrollbar); - text_editor->setHideScrollbarForShortDocs(hide_scrollbar); - - text_editor->initFromXML(node, parent); - - return text_editor; -} - void LLTextEditor::setTextEditorParameters(LLXMLNodePtr node) { BOOL word_wrap = FALSE; @@ -4814,173 +5143,6 @@ void LLTextEditor::setTextEditorParameters(LLXMLNodePtr node) } } -/////////////////////////////////////////////////////////////////// -// Refactoring note: We may eventually want to replace this with boost::regex or -// boost::tokenizer capabilities since we've already fixed at least two JIRAs -// concerning logic issues associated with this function. -S32 LLTextEditor::findHTMLToken(const std::string &line, S32 pos, BOOL reverse) const -{ - std::string openers=" \t\n('\"[{<>"; - std::string closers=" \t\n)'\"]}><;"; - - if (reverse) - { - for (int index=pos; index >= 0; index--) - { - char c = line[index]; - S32 m2 = openers.find(c); - if (m2 >= 0) - { - return index+1; - } - } - return 0; // index is -1, don't want to return that. - } - else - { - // adjust the search slightly, to allow matching parenthesis inside the URL - S32 paren_count = 0; - for (int index=pos; index<(S32)line.length(); index++) - { - char c = line[index]; - - if (c == '(') - { - paren_count++; - } - else if (c == ')') - { - if (paren_count <= 0) - { - return index; - } - else - { - paren_count--; - } - } - else - { - S32 m2 = closers.find(c); - if (m2 >= 0) - { - return index; - } - } - } - return line.length(); - } -} - -BOOL LLTextEditor::findHTML(const std::string &line, S32 *begin, S32 *end) const -{ - - S32 m1,m2,m3; - BOOL matched = FALSE; - - m1=line.find("://",*end); - - if (m1 >= 0) //Easy match. - { - *begin = findHTMLToken(line, m1, TRUE); - *end = findHTMLToken(line, m1, FALSE); - - //Load_url only handles http and https so don't hilite ftp, smb, etc. - m2 = line.substr(*begin,(m1 - *begin)).find("http"); - m3 = line.substr(*begin,(m1 - *begin)).find("secondlife"); - - std::string badneighbors=".,<>?';\"][}{=-+_)(*&^%$#@!~`\t\r\n\\"; - - if (m2 >= 0 || m3>=0) - { - S32 bn = badneighbors.find(line.substr(m1+3,1)); - - if (bn < 0) - { - matched = TRUE; - } - } - } -/* matches things like secondlife.com (no http://) needs a whitelist to really be effective. - else //Harder match. - { - m1 = line.find(".",*end); - - if (m1 >= 0) - { - *end = findHTMLToken(line, m1, FALSE); - *begin = findHTMLToken(line, m1, TRUE); - - m1 = line.rfind(".",*end); - - if ( ( *end - m1 ) > 2 && m1 > *begin) - { - std::string badneighbors=".,<>/?';\"][}{=-+_)(*&^%$#@!~`"; - m2 = badneighbors.find(line.substr(m1+1,1)); - m3 = badneighbors.find(line.substr(m1-1,1)); - if (m3<0 && m2<0) - { - matched = TRUE; - } - } - } - } - */ - - if (matched) - { - S32 strpos, strpos2; - - std::string url = line.substr(*begin,*end - *begin); - std::string slurlID = "slurl.com/secondlife/"; - strpos = url.find(slurlID); - - if (strpos < 0) - { - slurlID="maps.secondlife.com/secondlife/"; - strpos = url.find(slurlID); - } - - if (strpos < 0) - { - slurlID="secondlife://"; - strpos = url.find(slurlID); - } - - if (strpos < 0) - { - slurlID="sl://"; - strpos = url.find(slurlID); - } - - if (strpos >= 0) - { - strpos+=slurlID.length(); - - while ( ( strpos2=url.find("/",strpos) ) == -1 ) - { - if ((*end+2) >= (S32)line.length() || line.substr(*end,1) != " " ) - { - matched=FALSE; - break; - } - - strpos = (*end + 1) - *begin; - - *end = findHTMLToken(line,(*begin + strpos),FALSE); - url = line.substr(*begin,*end - *begin); - } - } - - } - - if (!matched) - { - *begin=*end=0; - } - return matched; -} - void LLTextEditor::updateAllowingLanguageInput() @@ -5008,7 +5170,7 @@ void LLTextEditor::resetPreedit() { if (hasSelection()) { - llwarns << "Preedit and selection!" << llendl; + LL_WARNS() << "Preedit and selection!" << LL_ENDL; deselect(); } @@ -5122,7 +5284,7 @@ BOOL LLTextEditor::getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect } const llwchar * const text = mWText.c_str(); - const S32 line_height = llround(mGLFont->getLineHeight()); + const S32 line_height = ll_round(mGLFont->getLineHeight()); if (coord) { @@ -5197,7 +5359,7 @@ void LLTextEditor::markAsPreedit(S32 position, S32 length) setCursorPos(position); if (hasPreeditString()) { - llwarns << "markAsPreedit invoked when hasPreeditString is true." << llendl; + LL_WARNS() << "markAsPreedit invoked when hasPreeditString is true." << LL_ENDL; } mPreeditWString = LLWString( mWText, position, length ); if (length > 0) @@ -5225,7 +5387,7 @@ void LLTextEditor::markAsPreedit(S32 position, S32 length) S32 LLTextEditor::getPreeditFontSize() const { - return llround(mGLFont->getLineHeight() * LLUI::getScaleFactor().mV[VY]); + return ll_round(mGLFont->getLineHeight() * LLUI::getScaleFactor().mV[VY]); } void LLTextEditor::setKeystrokeCallback(const keystroke_signal_t::slot_type& callback) diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h index 51300450db..09defc0495 100644 --- a/indra/llui/lltexteditor.h +++ b/indra/llui/lltexteditor.h @@ -39,22 +39,19 @@ #include "llkeywords.h" #include "lluictrl.h" #include "llframetimer.h" -#include "lldarray.h" #include "llstyle.h" #include "lleditmenuhandler.h" -#include "lldarray.h" #include "llpreeditor.h" -#include "llmenugl.h" +#include "lfidbearer.h" class LLFontGL; -class LLScrollbar; -class LLViewBorder; class LLKeywordToken; +class LLMenuGL; class LLTextCmd; -class LLUICtrlFactory; class LLTextEditor : public LLUICtrl, LLEditMenuHandler, protected LLPreeditor +, public LFIDBearer { public: // @@ -67,18 +64,25 @@ class LLTextEditor : public LLUICtrl, LLEditMenuHandler, protected LLPreeditor LLTextEditor(const std::string& name, const LLRect& rect, S32 max_length, - const std::string &default_text, + const std::string &default_text, const LLFontGL* glfont = NULL, - BOOL allow_embedded_items = FALSE); + BOOL allow_embedded_items = FALSE, + bool parse_html = false); virtual ~LLTextEditor(); + const std::string& getMenuSegmentUrl() const; + + LLUUID getStringUUIDSelectedItem() const override final; + Type getSelectedType() const override final; + typedef boost::signals2::signal keystroke_signal_t; + static void addMenuListeners(); + void setKeystrokeCallback(const keystroke_signal_t::slot_type& callback); virtual LLXMLNodePtr getXML(bool save_children = true) const; - static LLView* fromXML(LLXMLNodePtr node, LLView *parent, class LLUICtrlFactory *factory); void setTextEditorParameters(LLXMLNodePtr node); void setParseHTML(BOOL parsing) {mParseHTML=parsing;} void setParseHighlights(BOOL parsing) {mParseHighlights=parsing;} @@ -87,6 +91,7 @@ class LLTextEditor : public LLUICtrl, LLEditMenuHandler, protected LLPreeditor virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); virtual BOOL handleHover(S32 x, S32 y, MASK mask); + virtual void onMouseLeave(S32 x, S32 y, MASK mask) override; virtual BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask ); virtual BOOL handleRightMouseDown( S32 x, S32 y, MASK mask ); @@ -116,16 +121,6 @@ class LLTextEditor : public LLUICtrl, LLEditMenuHandler, protected LLPreeditor virtual BOOL isDirty() const { return( mLastCmd != NULL || (mPristineCmd && (mPristineCmd != mLastCmd)) ); } BOOL isSpellDirty() const { return mWText != mPrevSpelledText; } // Returns TRUE if user changed value at all void resetSpellDirty() { mPrevSpelledText = mWText; } // Clear dirty state - - struct SpellMenuBind - { - LLTextEditor* origin; - LLMenuItemCallGL * menuItem; - std::string word; - S32 wordPositionStart; - S32 wordPositionEnd; - S32 wordY; - }; // LLEditMenuHandler interface virtual void undo(); @@ -134,13 +129,13 @@ class LLTextEditor : public LLUICtrl, LLEditMenuHandler, protected LLPreeditor virtual BOOL canRedo() const; virtual void cut(); virtual BOOL canCut() const; - virtual void copy(); + void copy(bool raw) const; + void copyRaw() const { copy(true); } + void copy() const override final { copy(false); } virtual BOOL canCopy() const; virtual void paste(); virtual BOOL canPaste() const; - virtual void spellReplace(SpellMenuBind* spellData); - virtual void updatePrimary(); virtual void copyPrimary(); virtual void pastePrimary(); @@ -152,12 +147,6 @@ class LLTextEditor : public LLUICtrl, LLEditMenuHandler, protected LLPreeditor virtual BOOL canSelectAll() const; virtual void deselect(); virtual BOOL canDeselect() const; - static void context_cut(void* data); - - static void context_copy(void* data); - static void context_paste(void* data); - static void context_delete(void* data); - static void context_selectall(void* data); static void spell_correct(void* data); static void spell_add(void* data); static void spell_show(void* data); @@ -179,20 +168,24 @@ class LLTextEditor : public LLUICtrl, LLEditMenuHandler, protected LLPreeditor void insertText(const std::string &text, BOOL deleteSelection = TRUE); // appends text at end void appendText(const std::string &wtext, bool allow_undo, bool prepend_newline, - const LLStyleSP stylep = NULL); + const LLStyleSP stylep = NULL, bool force_replace_links = true); + void appendTextImpl(const std::string& new_text, const LLStyleSP style, bool force_replace_links = true); + + void setLastSegmentToolTip(const std::string& tooltip); + + void appendLineBreakSegment(); + + void appendAndHighlightText(const std::string& new_text, S32 highlight_part, const LLStyleSP stylep, bool underline_on_hover = false); + + void replaceUrl(const std::string& url, const std::string& label, const std::string& icon); void appendColoredText(const std::string &wtext, bool allow_undo, bool prepend_newline, const LLColor4 &color, const std::string& font_name = LLStringUtil::null); - // if styled text starts a line, you need to prepend a newline. - void appendStyledText(const std::string &new_text, bool allow_undo, - bool prepend_newline, - LLStyleSP stylep = NULL); - void appendHighlightedText(const std::string &new_text, bool allow_undo, - bool prepend_newline, S32 highlight_part, - LLStyleSP stylep); + void appendAndHighlightTextImpl(const std::string& new_text, S32 highlight_part, const LLStyleSP stylep, bool underline_on_hover = false); + // Removes text from the end of document // Does not change highlight or cursor position. void removeTextFromEnd(S32 num_chars); @@ -243,8 +236,8 @@ class LLTextEditor : public LLUICtrl, LLEditMenuHandler, protected LLPreeditor void setCommitOnFocusLost(BOOL b) { mCommitOnFocusLost = b; } // Hack to handle Notecards - virtual BOOL importBuffer(const char* buffer, S32 length ); - virtual BOOL exportBuffer(std::string& buffer ); + virtual BOOL importBuffer(const char* buffer, S32 length) { return false; } + virtual BOOL exportBuffer(std::string& buffer) { return false; } // If takes focus, will take keyboard focus on click. void setTakesFocus(BOOL b) { mTakesFocus = b; } @@ -256,8 +249,8 @@ class LLTextEditor : public LLUICtrl, LLEditMenuHandler, protected LLPreeditor void setHandleEditKeysDirectly( BOOL b ) { mHandleEditKeysDirectly = b; } - // Callbacks - static void setLinkColor(LLColor4 color) { mLinkColor = color; } + // Use for when the link color needs to be changed to avoid looking awful + void setLinkColor(LLColor4* color) { if (mLinkColor) delete mLinkColor; mLinkColor = color; } void setOnScrollEndCallback(void (*callback)(void*), void* userdata); @@ -266,10 +259,12 @@ class LLTextEditor : public LLUICtrl, LLEditMenuHandler, protected LLPreeditor LLSD getValue() const; const std::string& getText() const; - + + LLMenuGL* createUrlContextMenu(S32 x, S32 y, const std::string &url); // create a popup context menu for the given Url + // Non-undoable - void setText(const LLStringExplicit &utf8str); - void setWText(const LLWString &wtext); + void setText(const LLStringExplicit &utf8str, bool force_replace_links = true); + void setWText(const LLWString &wtext, bool force_replace_links = true); // Returns byte length limit S32 getMaxLength() const { return mMaxTextByteLength; } @@ -287,6 +282,7 @@ class LLTextEditor : public LLUICtrl, LLEditMenuHandler, protected LLPreeditor llwchar getWChar(S32 pos) const { return mWText[pos]; } LLWString getWSubString(S32 pos, S32 len) const { return mWText.substr(pos, len); } + const LLTextSegment* getLastSegment() const { return mSegments.empty() ? nullptr : mSegments.back(); } const LLTextSegment* getCurrentSegment() const { return getSegmentAtOffset(mCursorPos); } const LLTextSegment* getPreviousSegment() const; void getSelectedSegments(std::vector& segments) const; @@ -301,17 +297,16 @@ class LLTextEditor : public LLUICtrl, LLEditMenuHandler, protected LLPreeditor LLHandle mPopupMenuHandle; - S32 getLength() const { return mWText.length(); } void getSegmentAndOffset( S32 startpos, S32* segidxp, S32* offsetp ) const; void drawPreeditMarker(); public: + S32 getLength() const { return mWText.length(); } void updateLineStartList(S32 startpos = 0); protected: void updateScrollFromCursor(); void updateTextRect(); const LLRect& getTextRect() const { return mTextRect; } - void assignEmbedded(const std::string &s); BOOL truncate(); // Returns true if truncation occurs void removeCharOrTab(); @@ -367,9 +362,6 @@ class LLTextEditor : public LLUICtrl, LLEditMenuHandler, protected LLPreeditor virtual llwchar pasteEmbeddedItem(llwchar ext_char) { return ext_char; } virtual void bindEmbeddedChars(const LLFontGL* font) const {} virtual void unbindEmbeddedChars(const LLFontGL* font) const {} - - S32 findHTMLToken(const std::string &line, S32 pos, BOOL reverse) const; - BOOL findHTML(const std::string &line, S32 *begin, S32 *end) const; // Abstract inner base class representing an undoable editor command. // Concrete sub-classes can be defined for operations such as insert, remove, etc. @@ -408,10 +400,12 @@ class LLTextEditor : public LLUICtrl, LLEditMenuHandler, protected LLPreeditor S32 overwriteChar(S32 pos, llwchar wc); void removeChar(); S32 removeChar(S32 pos); + void removeWord(bool prev); S32 insert(const S32 pos, const LLWString &wstr, const BOOL group_with_next_op); +public: S32 remove(const S32 pos, const S32 length, const BOOL group_with_next_op); - S32 append(const LLWString &wstr, const BOOL group_with_next_op); - +protected: + // Direct operations S32 insertStringNoUndo(S32 pos, const LLWString &wstr); // returns num of chars actually inserted S32 removeStringNoUndo(S32 pos, S32 length); @@ -456,9 +450,12 @@ class LLTextEditor : public LLUICtrl, LLEditMenuHandler, protected LLPreeditor BOOL mParseHTML; BOOL mParseHighlights; - std::string mHTML; typedef std::vector segment_list_t; + + segment_list_t::iterator getSegIterContaining(S32 index); + segment_list_t::const_iterator getSegIterContaining(S32 index) const; + segment_list_t mSegments; LLTextSegmentPtr mHoverSegment; @@ -482,6 +479,8 @@ class LLTextEditor : public LLUICtrl, LLEditMenuHandler, protected LLPreeditor void pasteHelper(bool is_primary); void onKeyStroke(); + void createDefaultSegment(); + void clearSegments(); void updateSegments(); void pruneSegments(); @@ -504,7 +503,7 @@ class LLTextEditor : public LLUICtrl, LLEditMenuHandler, protected LLPreeditor // Data // LLKeywords mKeywords; - static LLColor4 mLinkColor; + LLColor4* mLinkColor; // Concrete LLTextCmd sub-classes used by the LLTextEditor base class class LLTextCmdInsert; @@ -560,7 +559,6 @@ class LLTextEditor : public LLUICtrl, LLEditMenuHandler, protected LLPreeditor typedef std::vector line_list_t; //to keep track of what we have to remove before showing menu - std::vector suggestionMenuItems; S32 mLastContextMenuX; S32 mLastContextMenuY; @@ -617,6 +615,7 @@ class LLTextSegment : public LLRefCount LLTextSegment( const LLColor3& color, S32 start, S32 end ); S32 getStart() const { return mStart; } + void setStart(S32 start) { mStart = start; } S32 getEnd() const { return mEnd; } void setEnd( S32 end ) { mEnd = end; } const LLColor4& getColor() const { return mStyle->getColor(); } @@ -625,9 +624,12 @@ class LLTextSegment : public LLRefCount void setStyle(const LLStyleSP &style) { mStyle = style; } void setIsDefault(BOOL b) { mIsDefault = b; } BOOL getIsDefault() const { return mIsDefault; } + void setUnderlineOnHover(bool b) { mUnderlineOnHover = b; } + void underlineOnHover(bool hover) { if (mUnderlineOnHover) mStyle->mUnderline = hover; } void setToken( LLKeywordToken* token ) { mToken = token; } LLKeywordToken* getToken() const { return mToken; } BOOL getToolTip( std::string& msg ) const; + void setToolTip(const std::string& tooltip); void dump() const; @@ -645,6 +647,8 @@ class LLTextSegment : public LLRefCount S32 mEnd; LLKeywordToken* mToken; BOOL mIsDefault; + bool mUnderlineOnHover = false; + std::string mTooltip; }; diff --git a/indra/llui/lltrans.cpp b/indra/llui/lltrans.cpp index fa95500550..df6cd77a83 100644 --- a/indra/llui/lltrans.cpp +++ b/indra/llui/lltrans.cpp @@ -50,7 +50,7 @@ bool LLTrans::parseStrings(const std::string& xml_filename, const std::sethasName( "strings" )) { - llerrs << "Problem reading strings: " << xml_filename << llendl; + LL_ERRS() << "Problem reading strings: " << xml_filename << LL_ENDL; return false; } @@ -67,7 +67,7 @@ bool LLTrans::parseStrings(const std::string& xml_filename, const std::setgetAttributeString("name", string_name)) { - llwarns << "Unable to parse string with no name" << llendl; + LL_WARNS() << "Unable to parse string with no name" << LL_ENDL; continue; } @@ -91,15 +91,20 @@ bool LLTrans::parseStrings(const std::string& xml_filename, const std::set +#include /** * @brief String template loaded from strings.xml diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp index 5a68c9efe9..f29dc3dcb1 100644 --- a/indra/llui/llui.cpp +++ b/indra/llui/llui.cpp @@ -79,7 +79,7 @@ void make_ui_sound(const char* namep) std::string name = ll_safe_string(namep); if (!LLUI::sConfigGroup->controlExists(name)) { - llwarns << "tried to make ui sound for unknown sound name: " << name << llendl; + LL_WARNS() << "tried to make ui sound for unknown sound name: " << name << LL_ENDL; } else { @@ -90,12 +90,12 @@ void make_ui_sound(const char* namep) { if (LLUI::sConfigGroup->getBOOL("UISndDebugSpamToggle")) { - llinfos << "ui sound name: " << name << " triggered but silent (null uuid)" << llendl; + LL_INFOS() << "ui sound name: " << name << " triggered but silent (null uuid)" << LL_ENDL; } } else { - llwarns << "ui sound named: " << name << " does not translate to a valid uuid" << llendl; + LL_WARNS() << "ui sound named: " << name << " does not translate to a valid uuid" << LL_ENDL; } } @@ -103,7 +103,7 @@ void make_ui_sound(const char* namep) { if (LLUI::sConfigGroup->getBOOL("UISndDebugSpamToggle")) { - llinfos << "ui sound name: " << name << llendl; + LL_INFOS() << "ui sound name: " << name << LL_ENDL; } LLUI::sAudioCallback(uuid); } @@ -137,7 +137,7 @@ void LLUI::initClass(LLControlGroup* config, || sIgnoresGroup == NULL || sColorsGroup == NULL) { - llerrs << "Failure to initialize configuration groups" << llendl; + LL_ERRS() << "Failure to initialize configuration groups" << LL_ENDL; } sAudioCallback = audio_callback; @@ -158,8 +158,8 @@ void LLUI::cleanupClass() void LLUI::setMousePositionScreen(S32 x, S32 y) { S32 screen_x, screen_y; - screen_x = llround((F32)x * getScaleFactor().mV[VX]); - screen_y = llround((F32)y * getScaleFactor().mV[VY]); + screen_x = ll_pos_round((F32)x * getScaleFactor().mV[VX]); + screen_y = ll_pos_round((F32)y * getScaleFactor().mV[VY]); LLView::getWindow()->setCursorPosition(LLCoordGL(screen_x, screen_y).convert()); } @@ -170,8 +170,8 @@ void LLUI::getMousePositionScreen(S32 *x, S32 *y) LLCoordWindow cursor_pos_window; getWindow()->getCursorPosition(&cursor_pos_window); LLCoordGL cursor_pos_gl(cursor_pos_window.convert()); - *x = llround((F32)cursor_pos_gl.mX / getScaleFactor().mV[VX]); - *y = llround((F32)cursor_pos_gl.mY / getScaleFactor().mV[VX]); + *x = ll_pos_round((F32)cursor_pos_gl.mX / getScaleFactor().mV[VX]); + *y = ll_pos_round((F32)cursor_pos_gl.mY / getScaleFactor().mV[VX]); } //static @@ -223,32 +223,33 @@ std::string LLUI::getLanguage() //static std::string LLUI::locateSkin(const std::string& filename) { - std::string slash = gDirUtilp->getDirDelimiter(); std::string found_file = filename; - if (!gDirUtilp->fileExists(found_file)) + if (gDirUtilp->fileExists(found_file)) { - found_file = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename); // Should be CUSTOM_SKINS? + return found_file; } - if (sConfigGroup && sConfigGroup->controlExists("Language")) + + found_file = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename); // Should be CUSTOM_SKINS? + if (gDirUtilp->fileExists(found_file)) { - if (!gDirUtilp->fileExists(found_file)) - { - std::string localization = getLanguage(); - std::string local_skin = "xui" + slash + localization + slash + filename; - found_file = gDirUtilp->findSkinnedFilename(local_skin); - } + return found_file; } - if (!gDirUtilp->fileExists(found_file)) + + found_file = gDirUtilp->findSkinnedFilename(LLDir::XUI, filename); + if (! found_file.empty()) { - std::string local_skin = "xui" + slash + "en-us" + slash + filename; - found_file = gDirUtilp->findSkinnedFilename(local_skin); + return found_file; } - if (!gDirUtilp->fileExists(found_file)) + + found_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, filename); + if (gDirUtilp->fileExists(found_file)) { - found_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, filename); + return found_file; } - return found_file; -} + LL_WARNS("LLUI") << "Can't find '" << filename + << "' in user settings, any skin directory or app_settings" << LL_ENDL; + return ""; +} //static LLVector2 LLUI::getWindowSize() @@ -262,15 +263,15 @@ LLVector2 LLUI::getWindowSize() //static void LLUI::screenPointToGL(S32 screen_x, S32 screen_y, S32 *gl_x, S32 *gl_y) { - *gl_x = llround((F32)screen_x * getScaleFactor().mV[VX]); - *gl_y = llround((F32)screen_y * getScaleFactor().mV[VY]); + *gl_x = ll_round((F32)screen_x * getScaleFactor().mV[VX]); + *gl_y = ll_round((F32)screen_y * getScaleFactor().mV[VY]); } //static void LLUI::glPointToScreen(S32 gl_x, S32 gl_y, S32 *screen_x, S32 *screen_y) { - *screen_x = llround((F32)gl_x / getScaleFactor().mV[VX]); - *screen_y = llround((F32)gl_y / getScaleFactor().mV[VY]); + *screen_x = ll_round((F32)gl_x / getScaleFactor().mV[VX]); + *screen_y = ll_round((F32)gl_y / getScaleFactor().mV[VY]); } //static @@ -313,3 +314,227 @@ void LLUI::setQAMode(BOOL b) LLUI::sQAMode = b; } +namespace LLInitParam +{ + ParamValue::ParamValue(const LLUIColor& color) + : super_t(color), + red("red"), + green("green"), + blue("blue"), + alpha("alpha"), + control("") + { + updateBlockFromValue(false); + } + + void ParamValue::updateValueFromBlock() + { + if (control.isProvided() && !control().empty()) + { + updateValue(LLUI::sColorsGroup->controlExists(control) ? LLUI::sColorsGroup->getColor(control) : LLUI::sConfigGroup->getColor(control)); // Singu Note: Most of our colors will be in sColorsGroup (skin), but some may be moved to settings for users. + } + else + { + updateValue(LLColor4(red, green, blue, alpha)); + } + } + + void ParamValue::updateBlockFromValue(bool make_block_authoritative) + { + LLColor4 color = getValue(); + red.set(color.mV[VRED], make_block_authoritative); + green.set(color.mV[VGREEN], make_block_authoritative); + blue.set(color.mV[VBLUE], make_block_authoritative); + alpha.set(color.mV[VALPHA], make_block_authoritative); + control.set("", make_block_authoritative); + } + + bool ParamCompare::equals(const LLFontGL* a, const LLFontGL* b) + { + return !(a->getFontDesc() < b->getFontDesc()) + && !(b->getFontDesc() < a->getFontDesc()); + } + + ParamValue::ParamValue(const LLFontGL* fontp) + : super_t(fontp), + name("name"), + size("size"), + style("style") + { + if (!fontp) + { + updateValue(LLFontGL::getFontDefault()); + } + addSynonym(name, ""); + updateBlockFromValue(false); + } + + void ParamValue::updateValueFromBlock() + { + const LLFontGL* res_fontp = LLFontGL::getFontByName(name); + if (res_fontp) + { + updateValue(res_fontp); + return; + } + + U8 fontstyle = 0; + fontstyle = LLFontGL::getStyleFromString(style()); + LLFontDescriptor desc(name(), size(), fontstyle); + const LLFontGL* fontp = LLFontGL::getFont(desc); + if (fontp) + { + updateValue(fontp); + } + else + { + updateValue(LLFontGL::getFontDefault()); + } + } + + void ParamValue::updateBlockFromValue(bool make_block_authoritative) + { + if (getValue()) + { + name.set(LLFontGL::nameFromFont(getValue()), make_block_authoritative); + size.set(LLFontGL::sizeFromFont(getValue()), make_block_authoritative); + style.set(LLFontGL::getStringFromStyle(getValue()->getFontDesc().getStyle()), make_block_authoritative); + } + } + + ParamValue::ParamValue(const LLRect& rect) + : super_t(rect), + left("left"), + top("top"), + right("right"), + bottom("bottom"), + width("width"), + height("height") + { + updateBlockFromValue(false); + } + + void ParamValue::updateValueFromBlock() + { + LLRect rect; + + //calculate from params + // prefer explicit left and right + if (left.isProvided() && right.isProvided()) + { + rect.mLeft = left; + rect.mRight = right; + } + // otherwise use width along with specified side, if any + else if (width.isProvided()) + { + // only right + width provided + if (right.isProvided()) + { + rect.mRight = right; + rect.mLeft = right - width; + } + else // left + width, or just width + { + rect.mLeft = left; + rect.mRight = left + width; + } + } + // just left, just right, or none + else + { + rect.mLeft = left; + rect.mRight = right; + } + + // prefer explicit bottom and top + if (bottom.isProvided() && top.isProvided()) + { + rect.mBottom = bottom; + rect.mTop = top; + } + // otherwise height along with specified side, if any + else if (height.isProvided()) + { + // top + height provided + if (top.isProvided()) + { + rect.mTop = top; + rect.mBottom = top - height; + } + // bottom + height or just height + else + { + rect.mBottom = bottom; + rect.mTop = bottom + height; + } + } + // just bottom, just top, or none + else + { + rect.mBottom = bottom; + rect.mTop = top; + } + updateValue(rect); + } + + void ParamValue::updateBlockFromValue(bool make_block_authoritative) + { + // because of the ambiguity in specifying a rect by position and/or dimensions + // we use the lowest priority pairing so that any valid pairing in xui + // will override those calculated from the rect object + // in this case, that is left+width and bottom+height + LLRect& value = getValue(); + + right.set(value.mRight, false); + left.set(value.mLeft, make_block_authoritative); + width.set(value.getWidth(), make_block_authoritative); + + top.set(value.mTop, false); + bottom.set(value.mBottom, make_block_authoritative); + height.set(value.getHeight(), make_block_authoritative); + } + + ParamValue::ParamValue(const LLCoordGL& coord) + : super_t(coord), + x("x"), + y("y") + { + updateBlockFromValue(false); + } + + void ParamValue::updateValueFromBlock() + { + updateValue(LLCoordGL(x, y)); + } + + void ParamValue::updateBlockFromValue(bool make_block_authoritative) + { + x.set(getValue().mX, make_block_authoritative); + y.set(getValue().mY, make_block_authoritative); + } + + + void TypeValues::declareValues() + { + declare("left", LLFontGL::LEFT); + declare("right", LLFontGL::RIGHT); + declare("center", LLFontGL::HCENTER); + } + + void TypeValues::declareValues() + { + declare("top", LLFontGL::TOP); + declare("center", LLFontGL::VCENTER); + declare("baseline", LLFontGL::BASELINE); + declare("bottom", LLFontGL::BOTTOM); + } + + void TypeValues::declareValues() + { + declare("none", LLFontGL::NO_SHADOW); + declare("hard", LLFontGL::DROP_SHADOW); + declare("soft", LLFontGL::DROP_SHADOW_SOFT); + } +} + diff --git a/indra/llui/llui.h b/indra/llui/llui.h index aede0f859f..2389ee34c9 100644 --- a/indra/llui/llui.h +++ b/indra/llui/llui.h @@ -32,12 +32,17 @@ #include "llcontrol.h" #include "llcoord.h" #include "v2math.h" -#include "llregistry.h" +#include "llinitparam.h" #include "llrender2dutils.h" #include "llpointer.h" +#include "lluicolor.h" #include "lluiimage.h" #include +// for initparam specialization +#include "llfontgl.h" + + // LLUIFactory #include "llsd.h" @@ -200,7 +205,7 @@ class LLUIFactory { } - virtual ~LLUIFactory() + virtual ~LLUIFactory() { } @@ -375,7 +380,7 @@ class LLInitClass static void initClass() { - llerrs << "No static initClass() method defined for " << typeid(T).name() << llendl; + LL_ERRS() << "No static initClass() method defined for " << typeid(T).name() << LL_ENDL; } }; @@ -390,7 +395,7 @@ class LLDestroyClass static void destroyClass() { - llerrs << "No static destroyClass() method defined for " << typeid(T).name() << llendl; + LL_ERRS() << "No static destroyClass() method defined for " << typeid(T).name() << LL_ENDL; } }; @@ -504,4 +509,99 @@ class LLParamBlock template T* LLParamBlock::sBlock = NULL; + +namespace LLInitParam +{ + template<> + class ParamValue + : public CustomParamValue + { + typedef CustomParamValue super_t; + public: + Optional left, + top, + right, + bottom, + width, + height; + + ParamValue(const LLRect& value); + + void updateValueFromBlock(); + void updateBlockFromValue(bool make_block_authoritative); + }; + + template<> + class ParamValue + : public CustomParamValue + { + typedef CustomParamValue super_t; + + public: + Optional red, + green, + blue, + alpha; + Optional control; + + ParamValue(const LLUIColor& color); + void updateValueFromBlock(); + void updateBlockFromValue(bool make_block_authoritative); + }; + + template<> + class ParamValue + : public CustomParamValue + { + typedef CustomParamValue super_t; + public: + Optional name, + size, + style; + + ParamValue(const LLFontGL* value); + void updateValueFromBlock(); + void updateBlockFromValue(bool make_block_authoritative); + }; + + template<> + struct TypeValues : public TypeValuesHelper + { + static void declareValues(); + }; + + template<> + struct TypeValues : public TypeValuesHelper + { + static void declareValues(); + }; + + template<> + struct TypeValues : public TypeValuesHelper + { + static void declareValues(); + }; + + template<> + struct ParamCompare + { + static bool equals(const LLFontGL* a, const LLFontGL* b); + }; + + + template<> + class ParamValue + : public CustomParamValue + { + typedef CustomParamValue super_t; + public: + Optional x, + y; + + ParamValue(const LLCoordGL& val); + void updateValueFromBlock(); + void updateBlockFromValue(bool make_block_authoritative); + }; +} + #endif diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp index b70737c27c..26acc25da7 100644 --- a/indra/llui/lluictrl.cpp +++ b/indra/llui/lluictrl.cpp @@ -31,7 +31,6 @@ * $/LicenseInfo$ */ -//#include "llviewerprecompiledheaders.h" #include "linden_common.h" #include "lluictrl.h" #include "llfocusmgr.h" @@ -39,46 +38,197 @@ static LLRegisterWidget r("ui_ctrl"); -// NOTE: the LLFocusableElement implementation has been moved to llfocusmgr.cpp, to mirror the header where the class is defined. +F32 LLUICtrl::sActiveControlTransparency = 1.0f; +F32 LLUICtrl::sInactiveControlTransparency = 1.0f; -LLUICtrl::LLUICtrl() : - mViewModel(LLViewModelPtr(new LLViewModel)), - mMakeVisibleControlVariable(NULL), - mMakeInvisibleControlVariable(NULL), - mCommitSignal(NULL), - mValidateSignal(NULL), - mMouseEnterSignal(NULL), - mMouseLeaveSignal(NULL), - mMouseDownSignal(NULL), - mMouseUpSignal(NULL), - mRightMouseDownSignal(NULL), - mRightMouseUpSignal(NULL), - mDoubleClickSignal(NULL), - mTentative(FALSE), +LLUICtrl::CallbackParam::CallbackParam() +: name("name"), + function_name("function"), + parameter("parameter"), + control_name("control") // Shortcut to control -> "control_name" for backwards compatability +{ + addSynonym(parameter, "userdata"); +} + +LLUICtrl::EnableControls::EnableControls() +: enabled("enabled_control"), + disabled("disabled_control") +{} + +LLUICtrl::ControlVisibility::ControlVisibility() +: visible("visibility_control"), + invisible("invisibility_control") +{ + addSynonym(visible, "visiblity_control"); + addSynonym(invisible, "invisiblity_control"); +} + +LLUICtrl::Params::Params() +: tab_stop("tab_stop", true), + chrome("chrome", false), + requests_front("requests_front", false), + label("label"), + initial_value("value"), + init_callback("init_callback"), + commit_callback("commit_callback"), + validate_callback("validate_callback"), + mouseenter_callback("mouseenter_callback"), + mouseleave_callback("mouseleave_callback"), + control_name("control_name"), + font("font", LLFontGL::getFontSansSerif()), + font_halign("halign"), + font_valign("valign"), + length("length"), // ignore LLXMLNode cruft + type("type") // ignore LLXMLNode cruft +{ + addSynonym(initial_value, "initial_value"); +} + +// NOTE: the LLFocusableElement implementation has been moved from here to llfocusmgr.cpp. + +//static +const LLUICtrl::Params& LLUICtrl::getDefaultParams() +{ + // Singu Note: We diverge here, not using LLUICtrlFactory::getDefaultParams + static const Params p; + return p; +} + + +LLUICtrl::LLUICtrl(const LLUICtrl::Params& p, const LLViewModelPtr& viewmodel) +: LLView(p), + mCommitSignal(nullptr), + mValidateSignal(nullptr), + mMouseEnterSignal(nullptr), + mMouseLeaveSignal(nullptr), + mMouseDownSignal(nullptr), + mMouseUpSignal(nullptr), + mRightMouseDownSignal(nullptr), + mRightMouseUpSignal(nullptr), + mDoubleClickSignal(nullptr), + mViewModel(viewmodel), + mEnabledControlVariable(nullptr), + mDisabledControlVariable(nullptr), + mMakeVisibleControlVariable(nullptr), + mMakeInvisibleControlVariable(nullptr), + mIsChrome(FALSE), + mRequestsFront(p.requests_front), mTabStop(TRUE), - mIsChrome(FALSE) + mTentative(FALSE), + mCommitOnReturn(FALSE), + mTransparencyType(TT_DEFAULT) { } +void LLUICtrl::initFromParams(const Params& p) +{ + LLView::initFromParams(p); + + mRequestsFront = p.requests_front; + + setIsChrome(p.chrome); + if(p.enabled_controls.isProvided()) + { + if (p.enabled_controls.enabled.isChosen()) + { + LLControlVariable* control = findControl(p.enabled_controls.enabled); + if (control) + setEnabledControlVariable(control); + } + else if(p.enabled_controls.disabled.isChosen()) + { + LLControlVariable* control = findControl(p.enabled_controls.disabled); + if (control) + setDisabledControlVariable(control); + } + } + if(p.controls_visibility.isProvided()) + { + if (p.controls_visibility.visible.isChosen()) + { + LLControlVariable* control = findControl(p.controls_visibility.visible); + if (control) + setMakeVisibleControlVariable(control); + } + else if (p.controls_visibility.invisible.isChosen()) + { + LLControlVariable* control = findControl(p.controls_visibility.invisible); + if (control) + setMakeInvisibleControlVariable(control); + } + } + + setTabStop(p.tab_stop); + + if (p.initial_value.isProvided() + && !p.control_name.isProvided()) + { + setValue(p.initial_value); + } + + if (p.commit_callback.isProvided()) + { + setCommitCallback(initCommitCallback(p.commit_callback)); + } + + if (p.validate_callback.isProvided()) + { + setValidateCallback(initEnableCallback(p.validate_callback)); + } + + if (p.init_callback.isProvided()) + { + if (p.init_callback.function.isProvided()) + { + p.init_callback.function()(this, p.init_callback.parameter); + } + else + { + commit_callback_t* initfunc = (CommitCallbackRegistry::getValue(p.init_callback.function_name)); + if (initfunc) + { + (*initfunc)(this, p.init_callback.parameter); + } + } + } + + if(p.mouseenter_callback.isProvided()) + { + setMouseEnterCallback(initCommitCallback(p.mouseenter_callback)); + } + + if(p.mouseleave_callback.isProvided()) + { + setMouseLeaveCallback(initCommitCallback(p.mouseleave_callback)); + } +} + LLUICtrl::LLUICtrl(const std::string& name, const LLRect rect, BOOL mouse_opaque, commit_callback_t commit_callback, U32 reshape) : // can't make this automatically follow top and left, breaks lots // of buttons in the UI. JC 7/20/2002 LLView( name, rect, mouse_opaque, reshape ), - mCommitSignal(NULL), - mValidateSignal(NULL), - mViewModel(LLViewModelPtr(new LLViewModel)), - mMouseEnterSignal(NULL), - mMouseLeaveSignal(NULL), - mMouseDownSignal(NULL), - mMouseUpSignal(NULL), - mRightMouseDownSignal(NULL), - mRightMouseUpSignal(NULL), - mDoubleClickSignal(NULL), - mTentative( FALSE ), + mIsChrome(FALSE), + mRequestsFront(false), mTabStop( TRUE ), - mIsChrome(FALSE) + mTentative( FALSE ), + mViewModel(LLViewModelPtr(new LLViewModel)), + mEnabledControlVariable(nullptr), + mDisabledControlVariable(nullptr), + mMakeVisibleControlVariable(nullptr), + mMakeInvisibleControlVariable(nullptr), + mCommitSignal(nullptr), + mValidateSignal(nullptr), + mMouseEnterSignal(nullptr), + mMouseLeaveSignal(nullptr), + mMouseDownSignal(nullptr), + mMouseUpSignal(nullptr), + mRightMouseDownSignal(nullptr), + mRightMouseUpSignal(nullptr), + mDoubleClickSignal(nullptr), + mCommitOnReturn(FALSE), + mTransparencyType(TT_DEFAULT) { if(commit_callback) setCommitCallback(commit_callback); @@ -90,7 +240,7 @@ LLUICtrl::~LLUICtrl() if( gFocusMgr.getTopCtrl() == this ) { - llwarns << "UI Control holding top ctrl deleted: " << getName() << ". Top view removed." << llendl; + LL_WARNS() << "UI Control holding top ctrl deleted: " << getName() << ". Top view removed." << LL_ENDL; gFocusMgr.removeTopCtrlWithoutCallback( this ); } @@ -105,6 +255,66 @@ LLUICtrl::~LLUICtrl() delete mDoubleClickSignal; } +void default_commit_handler(LLUICtrl* ctrl, const LLSD& param) +{} + +bool default_enable_handler(LLUICtrl* ctrl, const LLSD& param) +{ + return true; +} + + +LLUICtrl::commit_signal_t::slot_type LLUICtrl::initCommitCallback(const CommitCallbackParam& cb) +{ + if (cb.function.isProvided()) + { + if (cb.parameter.isProvided()) + return boost::bind(cb.function(), _1, cb.parameter); + else + return cb.function(); + } + else + { + std::string function_name = cb.function_name; + commit_callback_t* func = (CommitCallbackRegistry::getValue(function_name)); + if (func) + { + if (cb.parameter.isProvided()) + return boost::bind((*func), _1, cb.parameter); + else + return commit_signal_t::slot_type(*func); + } + else if (!function_name.empty()) + { + LL_WARNS() << "No callback found for: '" << function_name << "' in control: " << getName() << LL_ENDL; + } + } + return default_commit_handler; +} + +LLUICtrl::enable_signal_t::slot_type LLUICtrl::initEnableCallback(const EnableCallbackParam& cb) +{ + // Set the callback function + if (cb.function.isProvided()) + { + if (cb.parameter.isProvided()) + return boost::bind(cb.function(), this, cb.parameter); + else + return cb.function(); + } + else + { + enable_callback_t* func = (EnableCallbackRegistry::getValue(cb.function_name)); + if (func) + { + if (cb.parameter.isProvided()) + return boost::bind((*func), this, cb.parameter); + else + return enable_signal_t::slot_type(*func); + } + } + return default_enable_handler; +} // virtual void LLUICtrl::onMouseEnter(S32 x, S32 y, MASK mask) @@ -128,10 +338,13 @@ void LLUICtrl::onMouseLeave(S32 x, S32 y, MASK mask) BOOL LLUICtrl::handleMouseDown(S32 x, S32 y, MASK mask) { BOOL handled = LLView::handleMouseDown(x,y,mask); + if (mMouseDownSignal) { (*mMouseDownSignal)(this,x,y,mask); } + LL_DEBUGS() << "LLUICtrl::handleMousedown - handled is returning as: " << handled << " " << LL_ENDL; + return handled; } @@ -143,6 +356,7 @@ BOOL LLUICtrl::handleMouseUp(S32 x, S32 y, MASK mask) { (*mMouseUpSignal)(this,x,y,mask); } + return handled; } @@ -178,6 +392,13 @@ BOOL LLUICtrl::handleDoubleClick(S32 x, S32 y, MASK mask) return handled; } +// can't tab to children of a non-tab-stop widget +BOOL LLUICtrl::canFocusChildren() const +{ + return TRUE;//hasTabStop(); +} + + void LLUICtrl::onCommit() { if (mCommitSignal) @@ -193,7 +414,7 @@ BOOL LLUICtrl::isCtrl() const //virtual void LLUICtrl::setValue(const LLSD& value) { - mViewModel->setValue(value); + mViewModel->setValue(value); } //virtual @@ -206,10 +427,10 @@ LLSD LLUICtrl::getValue() const /// change), share their ViewModel. void LLUICtrl::shareViewModelFrom(const LLUICtrl& other) { - // Because mViewModel is an LLViewModelPtr, this assignment will quietly - // dispose of the previous LLViewModel -- unless it's already shared by - // somebody else. - mViewModel = other.mViewModel; + // Because mViewModel is an LLViewModelPtr, this assignment will quietly + // dispose of the previous LLViewModel -- unless it's already shared by + // somebody else. + mViewModel = other.mViewModel; } //virtual @@ -218,12 +439,72 @@ LLViewModel* LLUICtrl::getViewModel() const return mViewModel; } +//virtual +BOOL LLUICtrl::postBuild() +{ + // + // Find all of the children that want to be in front and move them to the front + // + + if (getChildCount() > 0) + { + std::vector childrenToMoveToFront; + + for (LLView::child_list_const_iter_t child_it = beginChild(); child_it != endChild(); ++child_it) + { + LLUICtrl* uictrl = dynamic_cast(*child_it); + + if (uictrl && uictrl->mRequestsFront) + { + childrenToMoveToFront.push_back(uictrl); + } + } + + for (std::vector::iterator it = childrenToMoveToFront.begin(); it != childrenToMoveToFront.end(); ++it) + { + sendChildToFront(*it); + } + } + + return LLView::postBuild(); +} + +void LLUICtrl::setEnabledControlVariable(LLControlVariable* control) +{ + if (mEnabledControlVariable) + { + mEnabledControlConnection.disconnect(); // disconnect current signal + mEnabledControlVariable = nullptr; + } + if (control) + { + mEnabledControlVariable = control; + mEnabledControlConnection = mEnabledControlVariable->getSignal()->connect(boost::bind(&controlListener, _2, getHandle(), std::string("enabled"))); + setEnabled(mEnabledControlVariable->getValue().asBoolean()); + } +} + +void LLUICtrl::setDisabledControlVariable(LLControlVariable* control) +{ + if (mDisabledControlVariable) + { + mDisabledControlConnection.disconnect(); // disconnect current signal + mDisabledControlVariable = nullptr; + } + if (control) + { + mDisabledControlVariable = control; + mDisabledControlConnection = mDisabledControlVariable->getSignal()->connect(boost::bind(&controlListener, _2, getHandle(), std::string("disabled"))); + setEnabled(!(mDisabledControlVariable->getValue().asBoolean())); + } +} + void LLUICtrl::setMakeVisibleControlVariable(LLControlVariable* control) { if (mMakeVisibleControlVariable) { mMakeVisibleControlConnection.disconnect(); // disconnect current signal - mMakeVisibleControlVariable = NULL; + mMakeVisibleControlVariable = nullptr; } if (control) { @@ -238,7 +519,7 @@ void LLUICtrl::setMakeInvisibleControlVariable(LLControlVariable* control) if (mMakeInvisibleControlVariable) { mMakeInvisibleControlConnection.disconnect(); // disconnect current signal - mMakeInvisibleControlVariable = NULL; + mMakeInvisibleControlVariable = nullptr; } if (control) { @@ -253,7 +534,22 @@ bool LLUICtrl::controlListener(const LLSD& newvalue, LLHandle handle, LLUICtrl* ctrl = handle.get(); if (ctrl) { - if (type == "visible") + if (type == "value") + { + ctrl->setValue(newvalue); + return true; + } + else if (type == "enabled") + { + ctrl->setEnabled(newvalue.asBoolean()); + return true; + } + else if(type =="disabled") + { + ctrl->setEnabled(!newvalue.asBoolean()); + return true; + } + else if (type == "visible") { ctrl->setVisible(newvalue.asBoolean()); return true; @@ -282,19 +578,19 @@ BOOL LLUICtrl::setLabelArg( const std::string& key, const LLStringExplicit& text // virtual LLCtrlSelectionInterface* LLUICtrl::getSelectionInterface() { - return NULL; + return nullptr; } // virtual LLCtrlListInterface* LLUICtrl::getListInterface() { - return NULL; + return nullptr; } // virtual LLCtrlScrollInterface* LLUICtrl::getScrollInterface() { - return NULL; + return nullptr; } BOOL LLUICtrl::hasFocus() const @@ -320,7 +616,7 @@ void LLUICtrl::setFocus(BOOL b) { if( gFocusMgr.childHasKeyboardFocus(this)) { - gFocusMgr.setKeyboardFocus( NULL ); + gFocusMgr.setKeyboardFocus(nullptr ); } } } @@ -352,7 +648,7 @@ BOOL LLUICtrl::isDirty() const //virtual void LLUICtrl::resetDirty() { - mViewModel->resetDirty(); + mViewModel->resetDirty(); } // virtual @@ -374,7 +670,6 @@ void LLUICtrl::setIsChrome(BOOL is_chrome) // virtual BOOL LLUICtrl::getIsChrome() const { - LLView* parent_ctrl = getParent(); while(parent_ctrl) { @@ -430,11 +725,11 @@ class LLUICtrl::DefaultTabGroupFirstSorter : public LLQuerySorter, public LLSing } }; -LLFastTimer::DeclareTimer FTM_FOCUS_FIRST_ITEM("Focus First Item"); +LLTrace::BlockTimerStatHandle FTM_FOCUS_FIRST_ITEM("Focus First Item"); BOOL LLUICtrl::focusFirstItem(BOOL prefer_text_fields, BOOL focus_flash) { - LLFastTimer _(FTM_FOCUS_FIRST_ITEM); + LL_RECORD_BLOCK_TIME(FTM_FOCUS_FIRST_ITEM); // try to select default tab group child LLCtrlQuery query = getTabOrderQuery(); // sort things such that the default tab group is at the front @@ -524,11 +819,13 @@ BOOL LLUICtrl::focusLastItem(BOOL prefer_text_fields) return FALSE; } + BOOL LLUICtrl::focusNextItem(BOOL text_fields_only) { // this assumes that this method is called on the focus root. LLCtrlQuery query = getTabOrderQuery(); - if(text_fields_only || LLUI::sConfigGroup->getBOOL("TabToTextFieldsOnly")) + static LLUICachedControl tab_to_text_fields_only ("TabToTextFieldsOnly", false); + if(text_fields_only || tab_to_text_fields_only) { query.addPreFilter(LLUICtrl::LLTextInputFilter::getInstance()); } @@ -540,7 +837,8 @@ BOOL LLUICtrl::focusPrevItem(BOOL text_fields_only) { // this assumes that this method is called on the focus root. LLCtrlQuery query = getTabOrderQuery(); - if(text_fields_only || LLUI::sConfigGroup->getBOOL("TabToTextFieldsOnly")) + static LLUICachedControl tab_to_text_fields_only ("TabToTextFieldsOnly", false); + if(text_fields_only || tab_to_text_fields_only) { query.addPreFilter(LLUICtrl::LLTextInputFilter::getInstance()); } @@ -552,7 +850,7 @@ LLUICtrl* LLUICtrl::findRootMostFocusRoot() { LLUICtrl* focus_root = NULL; LLUICtrl* next_view = this; - while(next_view) + while(next_view/* && next_view->hasTabStop()*/) { if (next_view->isFocusRoot()) { @@ -607,6 +905,8 @@ void LLUICtrl::initFromXML(LLXMLNodePtr node, LLView* parent) setTabStop(has_tab_stop); + node->getAttributeBOOL("requests_front", mRequestsFront); + std::string str = node->getName()->mString; std::string attrib_str; LLXMLNodePtr child_node; @@ -656,6 +956,20 @@ void LLUICtrl::initFromXML(LLXMLNodePtr node, LLView* parent) } LLView::initFromXML(node, parent); + if (node->getAttributeString("enabled_control", attrib_str)) + { + LLControlVariable* control = findControl(attrib_str); + if (control) + setEnabledControlVariable(control); + } + + if (node->getAttributeString("disabled_control", attrib_str)) + { + LLControlVariable* control = findControl(attrib_str); + if (control) + setDisabledControlVariable(control); + } + if(node->getAttributeString("visibility_control",attrib_str) || node->getAttributeString("visiblity_control",attrib_str)) { LLControlVariable* control = findControl(attrib_str); @@ -707,15 +1021,16 @@ LLUICtrl* LLUICtrl::getParentUICtrl() const } // *TODO: Deprecate; for backwards compatability only: -boost::signals2::connection LLUICtrl::setCommitCallback( boost::function cb, void* data) +boost::signals2::connection LLUICtrl::setCommitCallback( std::function cb, void* data) { return setCommitCallback( boost::bind(cb, _1, data)); } -boost::signals2::connection LLUICtrl::setValidateBeforeCommit( boost::function cb ) +boost::signals2::connection LLUICtrl::setValidateBeforeCommit( std::function cb ) { if (!mValidateSignal) mValidateSignal = new enable_signal_t(); return mValidateSignal->connect(boost::bind(cb, _2)); } + // virtual void LLUICtrl::setTentative(BOOL b) { @@ -728,7 +1043,6 @@ BOOL LLUICtrl::getTentative() const return mTentative; } - // virtual void LLUICtrl::setColor(const LLColor4& color) { } @@ -745,6 +1059,47 @@ void LLUICtrl::setMinValue(LLSD min_value) void LLUICtrl::setMaxValue(LLSD max_value) { } +F32 LLUICtrl::getCurrentTransparency() +{ + F32 alpha = 0; + + switch(mTransparencyType) + { + case TT_DEFAULT: + alpha = getDrawContext().mAlpha; + break; + + case TT_ACTIVE: + alpha = sActiveControlTransparency; + break; + + case TT_INACTIVE: + alpha = sInactiveControlTransparency; + break; + + case TT_FADING: + alpha = sInactiveControlTransparency / 2.f; + break; + } + + return alpha; +} + +void LLUICtrl::setTransparencyType(ETypeTransparency type) +{ + mTransparencyType = type; +} + +boost::signals2::connection LLUICtrl::setCommitCallback(const CommitCallbackParam& cb) +{ + return setCommitCallback(initCommitCallback(cb)); +} + +boost::signals2::connection LLUICtrl::setValidateCallback(const EnableCallbackParam& cb) +{ + return setValidateCallback(initEnableCallback(cb)); +} + boost::signals2::connection LLUICtrl::setCommitCallback( const commit_signal_t::slot_type& cb ) { if (!mCommitSignal) mCommitSignal = new commit_signal_t(); diff --git a/indra/llui/lluictrl.h b/indra/llui/lluictrl.h index b7ebc5bccf..ff28f25195 100644 --- a/indra/llui/lluictrl.h +++ b/indra/llui/lluictrl.h @@ -34,13 +34,13 @@ #ifndef LL_LLUICTRL_H #define LL_LLUICTRL_H -#include "llview.h" +//#include "llboost.h" #include "llrect.h" #include "llsd.h" -#include -#include +#include "llregistry.h" #include "llinitparam.h" +#include "llview.h" #include "llviewmodel.h" // *TODO move dependency to .cpp file class LLUICtrl @@ -49,36 +49,126 @@ class LLUICtrl public: typedef boost::function commit_callback_t; typedef boost::signals2::signal commit_signal_t; + // *TODO: add xml support for this type of signal in the future typedef boost::signals2::signal mouse_signal_t; + typedef boost::function enable_callback_t; typedef boost::signals2::signal enable_signal_t; - LLUICtrl(); + struct CallbackParam : public LLInitParam::Block + { + Ignored name; + + Optional function_name; + Optional parameter; + + Optional control_name; + + CallbackParam(); + }; + + struct CommitCallbackParam : public LLInitParam::Block + { + Optional function; + }; + + // also used for visible callbacks + struct EnableCallbackParam : public LLInitParam::Block + { + Optional function; + }; + + struct EnableControls : public LLInitParam::ChoiceBlock + { + Alternative enabled; + Alternative disabled; + + EnableControls(); + }; + struct ControlVisibility : public LLInitParam::ChoiceBlock + { + Alternative visible; + Alternative invisible; + + ControlVisibility(); + }; + struct Params : public LLInitParam::Block + { + Optional label; + Optional tab_stop, + chrome, + requests_front; + Optional initial_value; + + Optional init_callback, + commit_callback; + Optional validate_callback; + + Optional mouseenter_callback, + mouseleave_callback; + + Optional control_name; + Optional enabled_controls; + Optional controls_visibility; + + // font params + Optional font; + Optional font_halign; + Optional font_valign; + + // cruft from LLXMLNode implementation + Ignored type, + length; + + Params(); + }; + + enum ETypeTransparency + { + TT_DEFAULT, + TT_ACTIVE, // focused floater + TT_INACTIVE, // other floaters + TT_FADING, // fading toast + }; + /*virtual*/ ~LLUICtrl(); + + void initFromParams(const Params& p); + static const Params& getDefaultParams(); + LLUICtrl(const Params& p = getDefaultParams(), + const LLViewModelPtr& viewmodel=LLViewModelPtr(new LLViewModel)); + // Singu Note: This constructor is deprecated: LLUICtrl( const std::string& name, const LLRect rect = LLRect(), BOOL mouse_opaque = TRUE, commit_callback_t commit_callback = NULL, U32 reshape=FOLLOWS_NONE); - /*virtual*/ ~LLUICtrl(); + + commit_signal_t::slot_type initCommitCallback(const CommitCallbackParam& cb); + enable_signal_t::slot_type initEnableCallback(const EnableCallbackParam& cb); // We need this virtual so we can override it with derived versions virtual LLViewModel* getViewModel() const; - // We shouldn't ever need to set this directly - //virtual void setViewModel(const LLViewModelPtr&); + // We shouldn't ever need to set this directly + //virtual void setViewModel(const LLViewModelPtr&); + + BOOL postBuild() override; + +public: // LLView interface /*virtual*/ void initFromXML(LLXMLNodePtr node, LLView* parent); /*virtual*/ LLXMLNodePtr getXML(bool save_children = true) const; - /*virtual*/ BOOL setLabelArg( const std::string& key, const LLStringExplicit& text ); - /*virtual*/ BOOL isCtrl() const; - /*virtual*/ void onMouseEnter(S32 x, S32 y, MASK mask); - /*virtual*/ void onMouseLeave(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleRightMouseUp(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL setLabelArg( const std::string& key, const LLStringExplicit& text ) override; + /*virtual*/ BOOL isCtrl() const override; + /*virtual*/ void onMouseEnter(S32 x, S32 y, MASK mask) override; + /*virtual*/ void onMouseLeave(S32 x, S32 y, MASK mask) override; + /*virtual*/ BOOL canFocusChildren() const override; + /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask) override; + /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask) override; + /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask) override; + /*virtual*/ BOOL handleRightMouseUp(S32 x, S32 y, MASK mask) override; + /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask) override; // From LLFocusableElement - /*virtual*/ void setFocus( BOOL b ); - /*virtual*/ BOOL hasFocus() const; + /*virtual*/ void setFocus( BOOL b ) override; + /*virtual*/ BOOL hasFocus() const override; // New virtuals @@ -86,6 +176,9 @@ class LLUICtrl virtual class LLCtrlSelectionInterface* getSelectionInterface(); virtual class LLCtrlListInterface* getListInterface(); virtual class LLCtrlScrollInterface* getScrollInterface(); + + void setEnabledControlVariable(LLControlVariable* control); + void setDisabledControlVariable(LLControlVariable* control); void setMakeVisibleControlVariable(LLControlVariable* control); void setMakeInvisibleControlVariable(LLControlVariable* control); @@ -93,9 +186,9 @@ class LLUICtrl virtual BOOL getTentative() const; virtual void setValue(const LLSD& value); virtual LLSD getValue() const; - /// When two widgets are displaying the same data (e.g. during a skin - /// change), share their ViewModel. - virtual void shareViewModelFrom(const LLUICtrl& other); + /// When two widgets are displaying the same data (e.g. during a skin + /// change), share their ViewModel. + virtual void shareViewModelFrom(const LLUICtrl& other); virtual BOOL setTextArg( const std::string& key, const LLStringExplicit& text ); virtual void setIsChrome(BOOL is_chrome); @@ -112,15 +205,25 @@ class LLUICtrl // Default to no-op: virtual void onTabInto(); + + // Clear any user-provided input (text in a text editor, checked checkbox, + // selected radio button, etc.). Defaults to no-op. virtual void clear(); + virtual void setColor(const LLColor4& color); virtual void setAlpha(F32 alpha); virtual void setMinValue(LLSD min_value); virtual void setMaxValue(LLSD max_value); + F32 getCurrentTransparency(); + + void setTransparencyType(ETypeTransparency type); + ETypeTransparency getTransparencyType() const {return mTransparencyType;} + BOOL focusNextItem(BOOL text_entry_only); BOOL focusPrevItem(BOOL text_entry_only); - virtual BOOL focusFirstItem(BOOL prefer_text_fields = FALSE, BOOL focus_flash = TRUE ); + virtual // Singu Note: focusFirstItem is overridden for our old chat ui to prevent focusing on topmost uictrls. + BOOL focusFirstItem(BOOL prefer_text_fields = FALSE, BOOL focus_flash = TRUE ); BOOL focusLastItem(BOOL prefer_text_fields = FALSE); // Non Virtuals @@ -132,10 +235,16 @@ class LLUICtrl LLUICtrl* getParentUICtrl() const; + void setCommitOnReturn(BOOL commit) { mCommitOnReturn = commit; } + BOOL getCommitOnReturn() const { return mCommitOnReturn; } + + boost::signals2::connection setCommitCallback(const CommitCallbackParam& cb); + boost::signals2::connection setValidateCallback(const EnableCallbackParam& cb); + //Start using these! boost::signals2::connection setCommitCallback( const commit_signal_t::slot_type& cb ); boost::signals2::connection setValidateCallback( const enable_signal_t::slot_type& cb ); - + boost::signals2::connection setMouseEnterCallback( const commit_signal_t::slot_type& cb ); boost::signals2::connection setMouseLeaveCallback( const commit_signal_t::slot_type& cb ); @@ -147,8 +256,8 @@ class LLUICtrl boost::signals2::connection setDoubleClickCallback( const mouse_signal_t::slot_type& cb ); // *TODO: Deprecate; for backwards compatability only: - boost::signals2::connection setCommitCallback( boost::function cb, void* data); - boost::signals2::connection setValidateBeforeCommit( boost::function cb ); + boost::signals2::connection setCommitCallback( std::function cb, void* data); + boost::signals2::connection setValidateBeforeCommit( std::function cb ); static LLView* fromXML(LLXMLNodePtr node, LLView* parent, class LLUICtrlFactory* factory); @@ -163,12 +272,16 @@ class LLUICtrl }; template class CallbackRegistry : public LLRegistrySingleton - {}; + {}; - class CommitCallbackRegistry : public CallbackRegistry{}; + class CommitCallbackRegistry : public CallbackRegistry + { + }; // the enable callback registry is also used for visiblity callbacks - class EnableCallbackRegistry : public CallbackRegistry{}; - + class EnableCallbackRegistry : public CallbackRegistry + { + }; + protected: static bool controlListener(const LLSD& newvalue, LLHandle handle, std::string type); @@ -186,18 +299,31 @@ class LLUICtrl mouse_signal_t* mDoubleClickSignal; - LLViewModelPtr mViewModel; + LLViewModelPtr mViewModel; + LLControlVariable* mEnabledControlVariable; + boost::signals2::connection mEnabledControlConnection; + LLControlVariable* mDisabledControlVariable; + boost::signals2::connection mDisabledControlConnection; LLControlVariable* mMakeVisibleControlVariable; boost::signals2::connection mMakeVisibleControlConnection; LLControlVariable* mMakeInvisibleControlVariable; boost::signals2::connection mMakeInvisibleControlConnection; + + static F32 sActiveControlTransparency; + static F32 sInactiveControlTransparency; + private: - BOOL mTabStop; BOOL mIsChrome; + BOOL mRequestsFront; + BOOL mTabStop; BOOL mTentative; + ETypeTransparency mTransparencyType; + + bool mCommitOnReturn; + class DefaultTabGroupFirstSorter; }; diff --git a/indra/llui/lluictrlfactory.cpp b/indra/llui/lluictrlfactory.cpp index d5bb963d4d..d753b40e1a 100644 --- a/indra/llui/lluictrlfactory.cpp +++ b/indra/llui/lluictrlfactory.cpp @@ -71,9 +71,9 @@ #include "lluiimage.h" #include "llviewborder.h" -LLFastTimer::DeclareTimer FTM_WIDGET_CONSTRUCTION("Widget Construction"); -LLFastTimer::DeclareTimer FTM_INIT_FROM_PARAMS("Widget InitFromParams"); -LLFastTimer::DeclareTimer FTM_WIDGET_SETUP("Widget Setup"); +LLTrace::BlockTimerStatHandle FTM_WIDGET_CONSTRUCTION("Widget Construction"); +LLTrace::BlockTimerStatHandle FTM_INIT_FROM_PARAMS("Widget InitFromParams"); +LLTrace::BlockTimerStatHandle FTM_WIDGET_SETUP("Widget Setup"); const char XML_HEADER[] = "\n"; @@ -158,7 +158,7 @@ void LLUICtrlFactory::setupPaths() { std::string slash = gDirUtilp->getDirDelimiter(); std::string dir = "xui" + slash + "en-us"; - llwarns << "XUI::config file unable to open: " << filename << llendl; + LL_WARNS() << "XUI::config file unable to open: " << filename << LL_ENDL; sXUIPaths.push_back(dir); } } @@ -174,7 +174,7 @@ const std::vector& LLUICtrlFactory::getXUIPaths() //----------------------------------------------------------------------------- bool LLUICtrlFactory::getLayeredXMLNode(const std::string &xui_filename, LLXMLNodePtr& root) { - std::string full_filename = gDirUtilp->findSkinnedFilename(sXUIPaths.front(), xui_filename); + std::string full_filename = gDirUtilp->findSkinnedFilenameBaseLang(LLDir::XUI, xui_filename); if (full_filename.empty()) { // try filename as passed in since sometimes we load an xml file from a user-supplied path @@ -184,39 +184,31 @@ bool LLUICtrlFactory::getLayeredXMLNode(const std::string &xui_filename, LLXMLNo } else { - llwarns << "Couldn't find UI description file: " << sXUIPaths.front() + gDirUtilp->getDirDelimiter() + xui_filename << llendl; + LL_WARNS() << "Couldn't find UI description file: " << sXUIPaths.front() + gDirUtilp->getDirDelimiter() + xui_filename << LL_ENDL; return false; } } if (!LLXMLNode::parseFile(full_filename, root, NULL)) { - llwarns << "Problem reading UI description file: " << full_filename << llendl; + LL_WARNS() << "Problem reading UI description file: " << full_filename << LL_ENDL; return false; } + + std::vector paths = + gDirUtilp->findSkinnedFilenames(LLDir::XUI, xui_filename); - LLXMLNodePtr updateRoot; - - std::vector::const_iterator itor; - - for (itor = sXUIPaths.begin(), ++itor; itor != sXUIPaths.end(); ++itor) + for ( auto& layer_filename : paths ) { - std::string nodeName; - std::string updateName; - - std::string layer_filename = gDirUtilp->findSkinnedFilename((*itor), xui_filename); - if(layer_filename.empty()) - { - // no localized version of this file, that's ok, keep looking - continue; - } - + LLXMLNodePtr updateRoot; if (!LLXMLNode::parseFile(layer_filename, updateRoot, NULL)) { - llwarns << "Problem reading localized UI description file: " << (*itor) + gDirUtilp->getDirDelimiter() + xui_filename << llendl; + LL_WARNS() << "Problem reading localized UI description file: " << layer_filename << LL_ENDL; return false; } + std::string updateName; + std::string nodeName; updateRoot->getAttributeString("name", updateName); root->getAttributeString("name", nodeName); @@ -233,7 +225,7 @@ bool LLUICtrlFactory::getLayeredXMLNode(const std::string &xui_filename, LLXMLNo bool LLUICtrlFactory::getLayeredXMLNodeFromBuffer(const std::string &buffer, LLXMLNodePtr& root) { if (!LLXMLNode::parseBuffer((U8*)buffer.data(), buffer.size(), root, 0)) { - llwarns << "Error reading UI description from buffer." << llendl; + LL_WARNS() << "Error reading UI description from buffer." << LL_ENDL; return false; } return true; @@ -273,7 +265,7 @@ void LLUICtrlFactory::buildFloaterInternal(LLFloater *floaterp, LLXMLNodePtr &ro // root must be called floater if( !(root->hasName("floater") || root->hasName("multi_floater") ) ) { - llwarns << "Root node should be named floater in: " << filename << llendl; + LL_WARNS() << "Root node should be named floater in: " << filename << LL_ENDL; return; } @@ -324,7 +316,7 @@ S32 LLUICtrlFactory::saveToXML(LLView* viewp, const std::string& filename) llofstream out(filename); if (!out.good()) { - llwarns << "Unable to open " << filename << " for output." << llendl; + LL_WARNS() << "Unable to open " << filename << " for output." << LL_ENDL; return 1; } @@ -373,7 +365,7 @@ BOOL LLUICtrlFactory::buildPanelInternal(LLPanel* panelp, LLXMLNodePtr &root, co // root must be called panel if( !root->hasName("panel" ) ) { - llwarns << "Root node should be named panel in : " << filename << llendl; + LL_WARNS() << "Root node should be named panel in : " << filename << LL_ENDL; return didPost; } @@ -414,19 +406,19 @@ LLMenuGL *LLUICtrlFactory::buildMenu(const std::string &filename, LLView* parent LLXMLNodePtr root; LLMenuGL* menu; - if (!LLUICtrlFactory::getLayeredXMLNode(filename, root)) + if (!getLayeredXMLNode(filename, root)) { - return NULL; + return nullptr; } // root must be called panel - if( !root->hasName( "menu_bar" ) && !root->hasName( "menu" )) + if (!root->hasName("menu_bar") && !root->hasName("menu") && !root->hasName("context_menu")) { - llwarns << "Root node should be named menu bar or menu in : " << filename << llendl; - return NULL; + LL_WARNS() << "Root node should be named menu bar or menu in: " << filename << LL_ENDL; + return nullptr; } - if (root->hasName("menu")) + if (root->hasName("menu") || root->hasName("context_menu")) { menu = (LLMenuGL*)LLMenuGL::fromXML(root, parentp, this); } @@ -446,7 +438,7 @@ LLMenuGL *LLUICtrlFactory::buildMenu(const std::string &filename, LLView* parent //----------------------------------------------------------------------------- // buildMenu() //----------------------------------------------------------------------------- -LLPieMenu *LLUICtrlFactory::buildPieMenu(const std::string &filename, LLView* parentp) +LLContextMenu* LLUICtrlFactory::buildContextMenu(const std::string& filename, LLView* parentp) { LLXMLNodePtr root; @@ -458,16 +450,17 @@ LLPieMenu *LLUICtrlFactory::buildPieMenu(const std::string &filename, LLView* pa // root must be called panel if( !root->hasName( LL_PIE_MENU_TAG )) { - llwarns << "Root node should be named " << LL_PIE_MENU_TAG << " in : " << filename << llendl; + LL_WARNS() << "Root node should be named " << LL_PIE_MENU_TAG << " in : " << filename << LL_ENDL; return NULL; } std::string name("menu"); root->getAttributeString("name", name); - LLPieMenu *menu = new LLPieMenu(name); + static LLUICachedControl context("LiruUseContextMenus", false); + LLContextMenu* menu = context ? new LLContextMenu(name) : new LLPieMenu(name); parentp->addChild(menu); - menu->initXML(root, parentp, this); + menu->initXML(root, parentp, this, context); if (LLUI::sShowXUINames) { @@ -495,15 +488,15 @@ void LLUICtrlFactory::rebuild() { continue; } - llinfos << "Rebuilding UI panel " << panelp->getName() + LL_INFOS() << "Rebuilding UI panel " << panelp->getName() << " from " << filename - << llendl; + << LL_ENDL; BOOL visible = panelp->getVisible(); panelp->setVisible(FALSE); panelp->setFocus(FALSE); panelp->deleteAllChildren(); - buildPanel(panelp, filename.c_str(), &panelp->getFactoryMap()); + buildPanel(panelp, filename, &panelp->getFactoryMap()); panelp->setVisible(visible); } @@ -518,9 +511,9 @@ void LLUICtrlFactory::rebuild() continue; } std::string filename = built_floater_it->second; - llinfos << "Rebuilding UI floater " << floaterp->getName() + LL_INFOS() << "Rebuilding UI floater " << floaterp->getName() << " from " << filename - << llendl; + << LL_ENDL; BOOL visible = floaterp->getVisible(); floaterp->setVisible(FALSE); floaterp->setFocus(FALSE); @@ -544,7 +537,7 @@ LLView *LLUICtrlFactory::createCtrlWidget(LLPanel *parent, LLXMLNodePtr node) if (func == NULL) { - llwarns << "Unknown control type " << ctrl_type << llendl; + LL_WARNS() << "Unknown control type " << ctrl_type << LL_ENDL; return NULL; } diff --git a/indra/llui/lluictrlfactory.h b/indra/llui/lluictrlfactory.h index 3fac2bdb50..ee6abb8267 100644 --- a/indra/llui/lluictrlfactory.h +++ b/indra/llui/lluictrlfactory.h @@ -43,9 +43,9 @@ class LLView; -extern LLFastTimer::DeclareTimer FTM_WIDGET_SETUP; -extern LLFastTimer::DeclareTimer FTM_WIDGET_CONSTRUCTION; -extern LLFastTimer::DeclareTimer FTM_INIT_FROM_PARAMS; +extern LLTrace::BlockTimerStatHandle FTM_WIDGET_SETUP; +extern LLTrace::BlockTimerStatHandle FTM_WIDGET_CONSTRUCTION; +extern LLTrace::BlockTimerStatHandle FTM_INIT_FROM_PARAMS; // Build time optimization, generate this once in .cpp file #ifndef LLUICTRLFACTORY_CPP @@ -106,7 +106,7 @@ class LLUICtrlFactory : public LLSingleton bool builtPanel(LLPanel* panelp) {return mBuiltPanels.find(panelp->getHandle()) != mBuiltPanels.end();} class LLMenuGL *buildMenu(const std::string &filename, LLView* parentp); - class LLPieMenu *buildPieMenu(const std::string &filename, LLView* parentp); + class LLContextMenu* buildContextMenu(const std::string& filename, LLView* parentp); // Does what you want for LLFloaters and LLPanels // Returns 0 on success @@ -157,14 +157,14 @@ class LLUICtrlFactory : public LLSingleton if (!params.validateBlock()) { - llwarns << /*getInstance()->getCurFileName() <<*/ ": Invalid parameter block for " << typeid(T).name() << llendl; + LL_WARNS() << /*getInstance()->getCurFileName() <<*/ ": Invalid parameter block for " << typeid(T).name() << LL_ENDL; //return NULL; } - { LLFastTimer _(FTM_WIDGET_CONSTRUCTION); + { LL_RECORD_BLOCK_TIME(FTM_WIDGET_CONSTRUCTION); widget = new T(params); } - { LLFastTimer _(FTM_INIT_FROM_PARAMS); + { LL_RECORD_BLOCK_TIME(FTM_INIT_FROM_PARAMS); widget->initFromParams(params); } diff --git a/indra/llui/lluistring.cpp b/indra/llui/lluistring.cpp index 0332765f1d..74b1da1b5c 100644 --- a/indra/llui/lluistring.cpp +++ b/indra/llui/lluistring.cpp @@ -32,10 +32,11 @@ #include "linden_common.h" #include "lluistring.h" +#include "llfasttimer.h" #include "llsd.h" #include "lltrans.h" -LLFastTimer::DeclareTimer FTM_UI_STRING("UI String"); +LLTrace::BlockTimerStatHandle FTM_UI_STRING("UI String"); LLUIString::LLUIString(const std::string& instring, const LLStringUtil::format_map_t& args) @@ -60,7 +61,7 @@ void LLUIString::setArgList(const LLStringUtil::format_map_t& args) void LLUIString::setArgs(const LLSD& sd) { - LLFastTimer timer(FTM_UI_STRING); + LL_RECORD_BLOCK_TIME(FTM_UI_STRING); if (!sd.isMap()) return; for(LLSD::map_const_iterator sd_it = sd.beginMap(); @@ -123,7 +124,7 @@ void LLUIString::updateResult() const { mNeedsResult = false; - LLFastTimer timer(FTM_UI_STRING); + LL_RECORD_BLOCK_TIME(FTM_UI_STRING); // optimize for empty strings (don't attempt string replacement) if (mOrig.empty()) diff --git a/indra/llui/lluistring.h b/indra/llui/lluistring.h index d88c3cd666..0ca830f7dd 100644 --- a/indra/llui/lluistring.h +++ b/indra/llui/lluistring.h @@ -48,12 +48,12 @@ // LLUIString mMessage("Welcome [USERNAME] to [SECONDLIFE]!"); // mMessage.setArg("[USERNAME]", "Steve"); // mMessage.setArg("[SECONDLIFE]", "Second Life"); -// llinfos << mMessage.getString() << llendl; // outputs "Welcome Steve to Second Life" +// LL_INFOS() << mMessage.getString() << LL_ENDL; // outputs "Welcome Steve to Second Life" // mMessage.setArg("[USERNAME]", "Joe"); -// llinfos << mMessage.getString() << llendl; // outputs "Welcome Joe to Second Life" +// LL_INFOS() << mMessage.getString() << LL_ENDL; // outputs "Welcome Joe to Second Life" // mMessage = "Bienvenido a la [SECONDLIFE] [USERNAME]" // mMessage.setArg("[SECONDLIFE]", "Segunda Vida"); -// llinfos << mMessage.getString() << llendl; // outputs "Bienvenido a la Segunda Vida Joe" +// LL_INFOS() << mMessage.getString() << LL_ENDL; // outputs "Bienvenido a la Segunda Vida Joe" // Implementation Notes: // Attempting to have operator[](const std::string& s) return mArgs[s] fails because we have diff --git a/indra/llui/llundo.cpp b/indra/llui/llundo.cpp index 8f57636a52..d1e36586c8 100644 --- a/indra/llui/llundo.cpp +++ b/indra/llui/llundo.cpp @@ -57,7 +57,7 @@ LLUndoBuffer::LLUndoBuffer( LLUndoAction (*create_func()), S32 initial_count ) mActions[i] = create_func(); if (!mActions[i]) { - llerrs << "Unable to create action for undo buffer" << llendl; + LL_ERRS() << "Unable to create action for undo buffer" << LL_ENDL; } } } diff --git a/indra/llui/llurlaction.cpp b/indra/llui/llurlaction.cpp index fd9b3d9a6d..74ce67e88c 100644 --- a/indra/llui/llurlaction.cpp +++ b/indra/llui/llurlaction.cpp @@ -1,3 +1,5 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com /** * @file llurlaction.cpp * @author Martin Reddy @@ -24,7 +26,6 @@ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ - #include "linden_common.h" #include "llurlaction.h" @@ -32,6 +33,7 @@ #include "llwindow.h" #include "llurlregistry.h" + // global state for the callback functions LLUrlAction::url_callback_t LLUrlAction::sOpenURLCallback; LLUrlAction::url_callback_t LLUrlAction::sOpenURLInternalCallback; @@ -83,18 +85,19 @@ void LLUrlAction::openURLExternal(std::string url) } } -void LLUrlAction::executeSLURL(std::string url) +bool LLUrlAction::executeSLURL(std::string url, bool trusted_content) { if (sExecuteSLURLCallback) { - sExecuteSLURLCallback(url); + return sExecuteSLURLCallback(url, trusted_content); } + return false; } -void LLUrlAction::clickAction(std::string url) +void LLUrlAction::clickAction(std::string url, bool trusted_content) { // Try to handle as SLURL first, then http Url - if ( (sExecuteSLURLCallback) && !sExecuteSLURLCallback(url) ) + if ( (sExecuteSLURLCallback) && !sExecuteSLURLCallback(url, trusted_content) ) { if (sOpenURLCallback) { @@ -157,3 +160,86 @@ void LLUrlAction::showProfile(std::string url) } } } + +std::string LLUrlAction::getUserID(std::string url) +{ + LLURI uri(url); + LLSD path_array = uri.pathArray(); + std::string id_str; + if (path_array.size() == 4) + { + id_str = path_array.get(2).asString(); + } + return id_str; +} + +std::string LLUrlAction::getObjectId(std::string url) +{ + LLURI uri(url); + LLSD path_array = uri.pathArray(); + std::string id_str; + if (path_array.size() >= 3) + { + id_str = path_array.get(2).asString(); + } + return id_str; +} + +std::string LLUrlAction::getObjectName(std::string url) +{ + LLURI uri(url); + LLSD query_map = uri.queryMap(); + std::string name; + if (query_map.has("name")) + { + name = query_map["name"].asString(); + } + return name; +} + +void LLUrlAction::sendIM(std::string url) +{ + std::string id_str = getUserID(url); + if (LLUUID::validate(id_str)) + { + executeSLURL("secondlife:///app/agent/" + id_str + "/im"); + } +} + +void LLUrlAction::addFriend(std::string url) +{ + std::string id_str = getUserID(url); + if (LLUUID::validate(id_str)) + { + executeSLURL("secondlife:///app/agent/" + id_str + "/requestfriend"); + } +} + +void LLUrlAction::removeFriend(std::string url) +{ + std::string id_str = getUserID(url); + if (LLUUID::validate(id_str)) + { + executeSLURL("secondlife:///app/agent/" + id_str + "/removefriend"); + } +} + +void LLUrlAction::blockObject(std::string url) +{ + std::string object_id = getObjectId(url); + std::string object_name = getObjectName(url); + if (LLUUID::validate(object_id)) + { + executeSLURL("secondlife:///app/agent/" + object_id + "/block/" + LLURI::escape(object_name)); + } +} + +void LLUrlAction::unblockObject(std::string url) +{ + std::string object_id = getObjectId(url); + std::string object_name = getObjectName(url); + if (LLUUID::validate(object_id)) + { + executeSLURL("secondlife:///app/agent/" + object_id + "/unblock/" + object_name); + } +} diff --git a/indra/llui/llurlaction.h b/indra/llui/llurlaction.h index c34960b826..51ab8261b8 100644 --- a/indra/llui/llurlaction.h +++ b/indra/llui/llurlaction.h @@ -28,8 +28,7 @@ #ifndef LL_LLURLACTION_H #define LL_LLURLACTION_H -#include -#include +#include /// /// The LLUrlAction class provides a number of static functions that @@ -57,7 +56,7 @@ class LLUrlAction static void openURLExternal(std::string url); /// execute the given secondlife: SLURL - static void executeSLURL(std::string url); + static bool executeSLURL(std::string url, bool trusted_content = true); /// if the Url specifies an SL location, teleport there static void teleportToLocation(std::string url); @@ -66,7 +65,7 @@ class LLUrlAction static void showLocationOnMap(std::string url); /// perform the appropriate action for left-clicking on a Url - static void clickAction(std::string url); + static void clickAction(std::string url, bool trusted_content); /// copy the label for a Url to the clipboard static void copyLabelToClipboard(std::string url); @@ -76,10 +75,18 @@ class LLUrlAction /// if the Url specifies an SL command in the form like 'app/{cmd}/{id}/*', show its profile static void showProfile(std::string url); + static std::string getUserID(std::string url); + static std::string getObjectName(std::string url); + static std::string getObjectId(std::string url); + static void sendIM(std::string url); + static void addFriend(std::string url); + static void removeFriend(std::string url); + static void blockObject(std::string url); + static void unblockObject(std::string url); /// specify the callbacks to enable this class's functionality - typedef boost::function url_callback_t; - typedef boost::function execute_url_callback_t; + typedef std::function url_callback_t; + typedef std::function execute_url_callback_t; static void setOpenURLCallback(url_callback_t cb); static void setOpenURLInternalCallback(url_callback_t cb); diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp index d4c83d6742..a68f4df9f3 100644 --- a/indra/llui/llurlentry.cpp +++ b/indra/llui/llurlentry.cpp @@ -31,21 +31,28 @@ #include "lluri.h" #include "llurlmatch.h" #include "llurlregistry.h" +#include "lluriparser.h" #include "llavatarnamecache.h" #include "llcachename.h" #include "lltrans.h" //#include "lluicolortable.h" #include "message.h" +#include "llexperiencecache.h" -#define APP_HEADER_REGEX "((x-grid-location-info://[-\\w\\.]+/app)|(secondlife:///app))" +#include +#include // + +#define APP_HEADER_REGEX "((((x-grid-info://)|(x-grid-location-info://))[-\\w\\.]+(:\\d+)?/app)|(secondlife:///app))" +#define X_GRID_OR_SECONDLIFE_HEADER_REGEX "((((x-grid-info://)|(x-grid-location-info://))[-\\w\\.]+(:\\d+)?/)|(secondlife://))" // Utility functions std::string localize_slapp_label(const std::string& url, const std::string& full_name); LLUrlEntryBase::LLUrlEntryBase() -{} +{ +} LLUrlEntryBase::~LLUrlEntryBase() { @@ -62,14 +69,13 @@ std::string LLUrlEntryBase::getIcon(const std::string &url) return mIcon; } -/*LLStyle::Params LLUrlEntryBase::getStyle() const +LLStyleSP LLUrlEntryBase::getStyle() const { - LLStyle::Params style_params; - style_params.color = LLUIColorTable::instance().getColor("HTMLLinkColor"); - style_params.readonly_color = LLUIColorTable::instance().getColor("HTMLLinkColor"); - style_params.font.style = "UNDERLINE"; + static const LLUICachedControl color("HTMLLinkColor"); + LLStyleSP style_params(new LLStyle(true, color, LLStringUtil::null)); + //style_params->mUnderline = true; // Singu Note: We're not gonna bother here, underlining on hover return style_params; -}*/ +} std::string LLUrlEntryBase::getIDStringFromUrl(const std::string &url) const @@ -111,14 +117,14 @@ std::string LLUrlEntryBase::getLabelFromWikiLink(const std::string &url) const { // return the label part from [http://www.example.org Label] const char *text = url.c_str(); - S32 start = 0; + size_t start = 0; while (! isspace(text[start])) { - start++; + ++start; } while (text[start] == ' ' || text[start] == '\t') { - start++; + ++start; } return unescapeUrl(url.substr(start, url.size()-start-1)); } @@ -127,10 +133,10 @@ std::string LLUrlEntryBase::getUrlFromWikiLink(const std::string &string) const { // return the url part from [http://www.example.org Label] const char *text = string.c_str(); - S32 end = 0; + size_t end = 0; while (! isspace(text[end])) { - end++; + ++end; } return escapeUrl(string.substr(1, end-1)); } @@ -142,11 +148,14 @@ void LLUrlEntryBase::addObserver(const std::string &id, // add a callback to be notified when we have a label for the uuid LLUrlEntryObserver observer; observer.url = url; - observer.signal = new LLUrlLabelSignal(); - if (observer.signal) + try { + observer.signal = new LLUrlLabelSignal(); observer.signal->connect(cb); - mObservers.insert(std::pair(id, observer)); + mObservers.emplace(id, observer); + } + catch (...) + { } } @@ -178,13 +187,50 @@ bool LLUrlEntryBase::isLinkDisabled() const return globally_disabled; } -static std::string getStringAfterToken(const std::string str, const std::string token) +bool LLUrlEntryBase::isWikiLinkCorrect(const std::string& url) { - size_t pos = str.find(token); + LLWString label = utf8str_to_wstring(getLabelFromWikiLink(url)); + label.erase(std::remove(label.begin(), label.end(), L'\u200B'), label.end()); + return (LLUrlRegistry::instance().hasUrl(wstring_to_utf8str(label))) ? false : true; +} + +std::string LLUrlEntryBase::urlToLabelWithGreyQuery(const std::string &url) const +{ + LLUriParser up(unescapeUrl(url)); + up.normalize(); + + std::string label; + up.extractParts(); + up.glueFirst(label); + + return label; +} + +std::string LLUrlEntryBase::urlToGreyQuery(const std::string &url) const +{ + LLUriParser up(unescapeUrl(url)); + + std::string label; + up.extractParts(); + up.glueFirst(label, false); + + size_t pos = url.find(label); if (pos == std::string::npos) { return ""; } + pos += label.size(); + return url.substr(pos); +} + + +static std::string getStringAfterToken(const std::string& str, const std::string& token) +{ + size_t pos = str.find(token); + if (pos == std::string::npos) + { + return LLStringUtil::null; + } pos += token.size(); return str.substr(pos, str.size() - pos); @@ -194,8 +240,9 @@ static std::string getStringAfterToken(const std::string str, const std::string // LLUrlEntryHTTP Describes generic http: and https: Urls // LLUrlEntryHTTP::LLUrlEntryHTTP() + : LLUrlEntryBase() { - mPattern = boost::regex("https?://([-\\w\\.]+)+(:\\d+)?(:\\w+)?(@\\d+)?(@\\w+)?/?\\S*", + mPattern = boost::regex("https?://([^\\s/?\\.#]+\\.?)+\\.\\w+(:\\d+)?(/\\S*)?", boost::regex::perl|boost::regex::icase); mMenuName = "menu_url_http.xml"; mTooltip = LLTrans::getString("TooltipHttpUrl"); @@ -206,13 +253,27 @@ std::string LLUrlEntryHTTP::getLabel(const std::string &url, const LLUrlLabelCal return unescapeUrl(url); } +std::string LLUrlEntryHTTP::getUrl(const std::string &string) const +{ + if (string.find("://") == std::string::npos) + { + return "http://" + escapeUrl(string); + } + return escapeUrl(string); +} + +std::string LLUrlEntryHTTP::getTooltip(const std::string &url) const +{ + return mTooltip;; +} + // // LLUrlEntryHTTP Describes generic http: and https: Urls with custom label // We use the wikipedia syntax of [http://www.example.org Text] // LLUrlEntryHTTPLabel::LLUrlEntryHTTPLabel() { - mPattern = boost::regex("\\[https?://\\S+[ \t]+[^\\]]+\\]", + mPattern = boost::regex("\\[(https?://\\S+|\\S+\\.([^\\s<]*)?)[ \t]+[^\\]]+\\]", boost::regex::perl|boost::regex::icase); mMenuName = "menu_url_http.xml"; mTooltip = LLTrans::getString("TooltipHttpUrl"); @@ -231,27 +292,32 @@ std::string LLUrlEntryHTTPLabel::getTooltip(const std::string &string) const std::string LLUrlEntryHTTPLabel::getUrl(const std::string &string) const { - return getUrlFromWikiLink(string); + auto url = getUrlFromWikiLink(string); + if (!boost::istarts_with(url, "http")) + return "http://" + url; + return url; } // // LLUrlEntryHTTPNoProtocol Describes generic Urls like www.google.com // LLUrlEntryHTTPNoProtocol::LLUrlEntryHTTPNoProtocol() + : LLUrlEntryBase() { - mPattern = boost::regex("(" - "\\bwww\\.\\S+\\.\\S+" // i.e. www.FOO.BAR - "|" // or - "(?]+\\.(?:com|net|edu|org)([/:][^[:space:]<]*)?\\b" // i.e. FOO.net - ")", - boost::regex::perl|boost::regex::icase); + mPattern = boost::regex("\\bwww\\.\\S+\\.([^\\s<]*)?\\b", // i.e. www.FOO.BAR + boost::regex::perl | boost::regex::icase); mMenuName = "menu_url_http.xml"; mTooltip = LLTrans::getString("TooltipHttpUrl"); } std::string LLUrlEntryHTTPNoProtocol::getLabel(const std::string &url, const LLUrlLabelCallback &cb) { - return unescapeUrl(url); + return urlToLabelWithGreyQuery(url); +} + +std::string LLUrlEntryHTTPNoProtocol::getQuery(const std::string &url) const +{ + return urlToGreyQuery(url); } std::string LLUrlEntryHTTPNoProtocol::getUrl(const std::string &string) const @@ -263,14 +329,104 @@ std::string LLUrlEntryHTTPNoProtocol::getUrl(const std::string &string) const return escapeUrl(string); } +std::string LLUrlEntryHTTPNoProtocol::getTooltip(const std::string &url) const +{ + return unescapeUrl(url); +} + +LLUrlEntryInvalidSLURL::LLUrlEntryInvalidSLURL() + : LLUrlEntryBase() +{ + mPattern = boost::regex("(https?://(maps.secondlife.com|slurl.com)/secondlife/|secondlife://(/app/(worldmap|teleport)/)?)[^ /]+(/-?[0-9]+){1,3}(/?(\\?\\S*)?)?", + boost::regex::perl|boost::regex::icase); + mMenuName = "menu_url_http.xml"; + mTooltip = LLTrans::getString("TooltipHttpUrl"); +} + +std::string LLUrlEntryInvalidSLURL::getLabel(const std::string &url, const LLUrlLabelCallback &cb) +{ + + return escapeUrl(url); +} + +std::string LLUrlEntryInvalidSLURL::getUrl(const std::string &string) const +{ + return escapeUrl(string); +} + +std::string LLUrlEntryInvalidSLURL::getTooltip(const std::string &url) const +{ + return unescapeUrl(url); +} + +bool LLUrlEntryInvalidSLURL::isSLURLvalid(const std::string &url) const +{ + S32 actual_parts; + + if(url.find(".com/secondlife/") != std::string::npos) + { + actual_parts = 5; + } + else if(url.find("/app/") != std::string::npos) + { + actual_parts = 6; + } + else + { + actual_parts = 3; + } + + LLURI uri(url); + LLSD path_array = uri.pathArray(); + S32 path_parts = path_array.size(); + S32 x,y,z; + + if (path_parts == actual_parts) + { + // handle slurl with (X,Y,Z) coordinates + LLStringUtil::convertToS32(path_array[path_parts-3].asString(),x); + LLStringUtil::convertToS32(path_array[path_parts-2].asString(),y); + LLStringUtil::convertToS32(path_array[path_parts-1].asString(),z); + + if((x>= 0 && x<= 256) && (y>= 0 && y<= 256) && (z>= 0)) + { + return TRUE; + } + } + else if (path_parts == (actual_parts-1)) + { + // handle slurl with (X,Y) coordinates + + LLStringUtil::convertToS32(path_array[path_parts-2].asString(),x); + LLStringUtil::convertToS32(path_array[path_parts-1].asString(),y); + ; + if((x>= 0 && x<= 256) && (y>= 0 && y<= 256)) + { + return TRUE; + } + } + else if (path_parts == (actual_parts-2)) + { + // handle slurl with (X) coordinate + LLStringUtil::convertToS32(path_array[path_parts-1].asString(),x); + if(x>= 0 && x<= 256) + { + return TRUE; + } + } + + return FALSE; +} + // // LLUrlEntrySLURL Describes generic http: and https: Urls // LLUrlEntrySLURL::LLUrlEntrySLURL() { // see http://slurl.com/about.php for details on the SLURL format - mPattern = boost::regex("http://(maps.secondlife.com|slurl.com)/secondlife/[^ /]+(/\\d+){0,3}(/?(\\?title|\\?img|\\?msg)=\\S*)?/?", + mPattern = boost::regex("https?://(maps.secondlife.com|slurl.com)/secondlife/[^ /]+(/\\d+){0,3}(/?(\\?\\S*)?)?", boost::regex::perl|boost::regex::icase); + mIcon = "Hand"; mMenuName = "menu_url_slurl.xml"; mTooltip = LLTrans::getString("TooltipSLURL"); } @@ -284,6 +440,7 @@ std::string LLUrlEntrySLURL::getLabel(const std::string &url, const LLUrlLabelCa // - http://slurl.com/secondlife/Place/X // - http://slurl.com/secondlife/Place // + LLURI uri(url); LLSD path_array = uri.pathArray(); S32 path_parts = path_array.size(); @@ -335,10 +492,60 @@ std::string LLUrlEntrySLURL::getLocation(const std::string &url) const return url.substr(pos, url.size() - pos); } +// +// LLUrlEntrySeconlifeURL Describes *secondlife.com/ and *lindenlab.com/ urls to substitute icon 'hand.png' before link +// +LLUrlEntrySecondlifeURL::LLUrlEntrySecondlifeURL() +{ + mPattern = boost::regex("\\b(https?://)?([-\\w\\.]*\\.)?(secondlife|lindenlab)\\.com(:\\d{1,5})?(/\\S*)?", + boost::regex::perl|boost::regex::icase); + + mIcon = "Hand"; + mMenuName = "menu_url_http.xml"; + mTooltip = LLTrans::getString("TooltipHttpUrl"); +} + +/// Return the url from a string that matched the regex +std::string LLUrlEntrySecondlifeURL::getUrl(const std::string &string) const +{ + if (string.find("://") == std::string::npos) + { + return "https://" + escapeUrl(string); + } + return escapeUrl(string); +} + +std::string LLUrlEntrySecondlifeURL::getLabel(const std::string &url, const LLUrlLabelCallback &cb) +{ + return urlToLabelWithGreyQuery(url); +} + +std::string LLUrlEntrySecondlifeURL::getQuery(const std::string &url) const +{ + return urlToGreyQuery(url); +} + +std::string LLUrlEntrySecondlifeURL::getTooltip(const std::string &url) const +{ + return url; +} + +// +// LLUrlEntrySimpleSecondlifeURL Describes *secondlife.com and *lindenlab.com urls to substitute icon 'hand.png' before link +// +LLUrlEntrySimpleSecondlifeURL::LLUrlEntrySimpleSecondlifeURL() + { + mPattern = boost::regex("(https?://)?([-\\w\\.]*\\.)?(secondlife|lindenlab)\\.com(?!\\S)", + boost::regex::perl|boost::regex::icase); + + mIcon = "Hand"; + mMenuName = "menu_url_http.xml"; +} + // // LLUrlEntryAgent Describes a Second Life agent Url, e.g., // secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about -// x-grid-location-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about +// x-grid-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about // LLUrlEntryAgent::LLUrlEntryAgent() { @@ -371,7 +578,17 @@ void LLUrlEntryAgent::callObservers(const std::string &id, void LLUrlEntryAgent::onAvatarNameCache(const LLUUID& id, const LLAvatarName& av_name) { - std::string label = av_name.getCompleteName(); + auto range = mAvatarNameCacheConnections.equal_range(id); + for (auto it = range.first; it != range.second; ++it) + { + if (it->second.connected()) + { + it->second.disconnect(); + } + } + mAvatarNameCacheConnections.erase(range.first, range.second); + + std::string label = av_name.getNSName(); // received the agent name from the server - tell our observers callObservers(id.asString(), label, mIcon); @@ -426,10 +643,11 @@ bool LLUrlEntryAgent::underlineOnHoverOnly(const std::string &string) const std::string LLUrlEntryAgent::getLabel(const std::string &url, const LLUrlLabelCallback &cb) { + static std::string name_wait_str = LLTrans::getString("LoadingData"); if (!gCacheName) { // probably at the login screen, use short string for layout - return LLTrans::getString("LoadingData"); + return name_wait_str; } std::string agent_id_string = getIDStringFromUrl(url); @@ -448,7 +666,7 @@ std::string LLUrlEntryAgent::getLabel(const std::string &url, const LLUrlLabelCa LLAvatarName av_name; if (LLAvatarNameCache::get(agent_id, &av_name)) { - std::string label = av_name.getCompleteName(); + std::string label = av_name.getNSName(); // handle suffixes like /mute or /offerteleport label = localize_slapp_label(url, label); @@ -456,21 +674,19 @@ std::string LLUrlEntryAgent::getLabel(const std::string &url, const LLUrlLabelCa } else { - LLAvatarNameCache::get(agent_id, - boost::bind(&LLUrlEntryAgent::onAvatarNameCache, - this, _1, _2)); + auto connection = LLAvatarNameCache::get(agent_id, boost::bind(&LLUrlEntryAgent::onAvatarNameCache, this, _1, _2)); + mAvatarNameCacheConnections.emplace(agent_id, connection); addObserver(agent_id_string, url, cb); - return LLTrans::getString("LoadingData"); + return name_wait_str; } } -/*LLStyle::Params LLUrlEntryAgent::getStyle() const +LLStyleSP LLUrlEntryAgent::getStyle() const { - LLStyle::Params style_params = LLUrlEntryBase::getStyle(); - style_params.color = LLUIColorTable::instance().getColor("HTMLLinkColor"); - style_params.readonly_color = LLUIColorTable::instance().getColor("HTMLLinkColor"); + static const LLUICachedControl color("HTMLAgentColor"); + LLStyleSP style_params(new LLStyle(true, color, LLStringUtil::null)); return style_params; -}*/ +} std::string localize_slapp_label(const std::string& url, const std::string& full_name) { @@ -499,6 +715,10 @@ std::string localize_slapp_label(const std::string& url, const std::string& full { return LLTrans::getString("SLappAgentRequestFriend") + " " + full_name; } + if (LLStringUtil::endsWith(url, "/removefriend")) + { + return LLTrans::getString("SLappAgentRemoveFriend") + " " + full_name; + } return full_name; } @@ -513,14 +733,26 @@ std::string LLUrlEntryAgent::getIcon(const std::string &url) // // LLUrlEntryAgentName describes a Second Life agent name Url, e.g., // secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/(completename|displayname|username) -// x-grid-location-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/(completename|displayname|username) +// x-grid-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/(completename|displayname|username) // LLUrlEntryAgentName::LLUrlEntryAgentName() -{} +{ + mMenuName = "menu_url_agent.xml"; +} void LLUrlEntryAgentName::onAvatarNameCache(const LLUUID& id, const LLAvatarName& av_name) { + auto range = mAvatarNameCacheConnections.equal_range(id); + for (auto it = range.first; it != range.second; ++it) + { + if (it->second.connected()) + { + it->second.disconnect(); + } + } + mAvatarNameCacheConnections.erase(range.first, range.second); + std::string label = getName(av_name); // received the agent name from the server - tell our observers callObservers(id.asString(), label, mIcon); @@ -528,10 +760,11 @@ void LLUrlEntryAgentName::onAvatarNameCache(const LLUUID& id, std::string LLUrlEntryAgentName::getLabel(const std::string &url, const LLUrlLabelCallback &cb) { + static std::string name_wait_str = LLTrans::getString("LoadingData"); if (!gCacheName) { // probably at the login screen, use short string for layout - return LLTrans::getString("LoadingData"); + return name_wait_str; } std::string agent_id_string = getIDStringFromUrl(url); @@ -554,24 +787,24 @@ std::string LLUrlEntryAgentName::getLabel(const std::string &url, const LLUrlLab } else { - LLAvatarNameCache::get(agent_id, - boost::bind(&LLUrlEntryAgentCompleteName::onAvatarNameCache, - this, _1, _2)); + auto connection = LLAvatarNameCache::get(agent_id, boost::bind(&LLUrlEntryAgentName::onAvatarNameCache, this, _1, _2)); + mAvatarNameCacheConnections.emplace(agent_id, connection); addObserver(agent_id_string, url, cb); - return LLTrans::getString("LoadingData"); + return name_wait_str; } } -/*LLStyle::Params LLUrlEntryAgentName::getStyle() const +LLStyleSP LLUrlEntryAgentName::getStyle() const { - // don't override default colors - return LLStyle::Params().is_link(false); -}*/ + static const LLUICachedControl color("HTMLAgentColor"); + LLStyleSP style_params(new LLStyle(true, color, LLStringUtil::null)); + return style_params; +} // // LLUrlEntryAgentCompleteName describes a Second Life agent complete name Url, e.g., // secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/completename -// x-grid-location-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/completename +// x-grid-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/completename // LLUrlEntryAgentCompleteName::LLUrlEntryAgentCompleteName() { @@ -584,10 +817,26 @@ std::string LLUrlEntryAgentCompleteName::getName(const LLAvatarName& avatar_name return avatar_name.getCompleteName(); } +// +// LLUrlEntryAgentLegacyName describes a Second Life agent legacy name Url, e.g., +// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/legacyname +// x-grid-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/legacyname +// +LLUrlEntryAgentLegacyName::LLUrlEntryAgentLegacyName() +{ + mPattern = boost::regex(APP_HEADER_REGEX "/agent/[\\da-f-]+/legacyname", + boost::regex::perl|boost::regex::icase); +} + +std::string LLUrlEntryAgentLegacyName::getName(const LLAvatarName& avatar_name) +{ + return avatar_name.getLegacyName(); +} + // // LLUrlEntryAgentDisplayName describes a Second Life agent display name Url, e.g., // secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/displayname -// x-grid-location-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/displayname +// x-grid-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/displayname // LLUrlEntryAgentDisplayName::LLUrlEntryAgentDisplayName() { @@ -597,13 +846,13 @@ LLUrlEntryAgentDisplayName::LLUrlEntryAgentDisplayName() std::string LLUrlEntryAgentDisplayName::getName(const LLAvatarName& avatar_name) { - return avatar_name.mDisplayName; + return avatar_name.getDisplayName(); } // // LLUrlEntryAgentUserName describes a Second Life agent user name Url, e.g., // secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/username -// x-grid-location-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/username +// x-grid-info://lincoln.lindenlab.com/app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/username // LLUrlEntryAgentUserName::LLUrlEntryAgentUserName() { @@ -613,14 +862,14 @@ LLUrlEntryAgentUserName::LLUrlEntryAgentUserName() std::string LLUrlEntryAgentUserName::getName(const LLAvatarName& avatar_name) { - return avatar_name.mUsername.empty() ? avatar_name.getLegacyName() : avatar_name.mUsername; + return avatar_name.getAccountName(); } // // LLUrlEntryGroup Describes a Second Life group Url, e.g., // secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/about // secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/inspect -// x-grid-location-info://lincoln.lindenlab.com/app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/inspect +// x-grid-info://lincoln.lindenlab.com/app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/inspect // LLUrlEntryGroup::LLUrlEntryGroup() { @@ -682,13 +931,12 @@ std::string LLUrlEntryGroup::getLabel(const std::string &url, const LLUrlLabelCa } } -/*LLStyle::Params LLUrlEntryGroup::getStyle() const +LLStyleSP LLUrlEntryGroup::getStyle() const { - LLStyle::Params style_params = LLUrlEntryBase::getStyle(); - style_params.color = LLUIColorTable::instance().getColor("HTMLLinkColor"); - style_params.readonly_color = LLUIColorTable::instance().getColor("HTMLLinkColor"); + LLStyleSP style_params = LLUrlEntryBase::getStyle(); + //style_params->mUnderline = false; // Singu Note: We're not gonna bother here, underlining on hover return style_params; -}*/ +} // @@ -700,7 +948,7 @@ LLUrlEntryInventory::LLUrlEntryInventory() //*TODO: add supporting of inventory item names with whitespaces //this pattern cann't parse for example //secondlife:///app/inventory/0e346d8b-4433-4d66-a6b0-fd37083abc4c/select?name=name with spaces¶m2=value - //x-grid-location-info://lincoln.lindenlab.com/app/inventory/0e346d8b-4433-4d66-a6b0-fd37083abc4c/select?name=name with spaces¶m2=value + //x-grid-info://lincoln.lindenlab.com/app/inventory/0e346d8b-4433-4d66-a6b0-fd37083abc4c/select?name=name with spaces¶m2=value mPattern = boost::regex(APP_HEADER_REGEX "/inventory/[\\da-f-]+/\\w+\\S*", boost::regex::perl|boost::regex::icase); mMenuName = "menu_url_inventory.xml"; @@ -718,7 +966,7 @@ std::string LLUrlEntryInventory::getLabel(const std::string &url, const LLUrlLab // LLUrlEntryObjectIM::LLUrlEntryObjectIM() { - mPattern = boost::regex("secondlife:///app/objectim/[\\da-f-]+\?.*", + mPattern = boost::regex(APP_HEADER_REGEX "/objectim/[\\da-f-]+\?\\S*\\w", boost::regex::perl|boost::regex::icase); mMenuName = "menu_url_objectim.xml"; } @@ -751,7 +999,7 @@ std::set LLUrlEntryParcel::sParcelInfoObservers; /// /// LLUrlEntryParcel Describes a Second Life parcel Url, e.g., /// secondlife:///app/parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/about -/// x-grid-location-info://lincoln.lindenlab.com/app/parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/about +/// x-grid-info://lincoln.lindenlab.com/app/parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/about /// LLUrlEntryParcel::LLUrlEntryParcel() { @@ -775,7 +1023,7 @@ std::string LLUrlEntryParcel::getLabel(const std::string &url, const LLUrlLabelC if (path_parts < 3) // no parcel id { - llwarns << "Failed to parse url [" << url << "]" << llendl; + LL_WARNS() << "Failed to parse url [" << url << "]" << LL_ENDL; return url; } @@ -821,19 +1069,16 @@ void LLUrlEntryParcel::processParcelInfo(const LLParcelData& parcel_data) // If parcel name is empty use Sim_name (x, y, z) for parcel label. else if (!parcel_data.sim_name.empty()) { - S32 region_x = llround(parcel_data.global_x) % REGION_WIDTH_UNITS; - S32 region_y = llround(parcel_data.global_y) % REGION_WIDTH_UNITS; - S32 region_z = llround(parcel_data.global_z); + S32 region_x = ll_round(parcel_data.global_x) % REGION_WIDTH_UNITS; + S32 region_y = ll_round(parcel_data.global_y) % REGION_WIDTH_UNITS; + S32 region_z = ll_round(parcel_data.global_z); label = llformat("%s (%d, %d, %d)", parcel_data.sim_name.c_str(), region_x, region_y, region_z); } - for (std::set::iterator iter = sParcelInfoObservers.begin(); - iter != sParcelInfoObservers.end(); - ++iter) + for (auto url_entry : sParcelInfoObservers) { - LLUrlEntryParcel* url_entry = *iter; if (url_entry) { url_entry->onParcelInfoReceived(parcel_data.parcel_id.asString(), label); @@ -846,7 +1091,7 @@ void LLUrlEntryParcel::processParcelInfo(const LLParcelData& parcel_data) // LLUrlEntryPlace::LLUrlEntryPlace() { - mPattern = boost::regex("((x-grid-location-info://[-\\w\\.]+/region/)|(secondlife://))\\S+/?(\\d+/\\d+/\\d+|\\d+/\\d+)/?", + mPattern = boost::regex("((((x-grid-info://)|(x-grid-location-info://))[-\\w\\.]+(:\\d+)?/region/)|(secondlife://))\\S+/?(\\d+/\\d+/\\d+|\\d+/\\d+)/?", boost::regex::perl|boost::regex::icase); mMenuName = "menu_url_slurl.xml"; mTooltip = LLTrans::getString("TooltipSLURL"); @@ -878,6 +1123,15 @@ std::string LLUrlEntryPlace::getLabel(const std::string &url, const LLUrlLabelCa std::string y = path_array[1]; return location + " (" + x + "," + y + ")"; } + else if (path_parts > 3) // xgrid, show as grid: place(x, y, z) + { + auto place = unescapeUrl(path_array[1].asStringRef()); + const auto& x = path_array[2].asStringRef(); + const auto& y = path_array[3].asStringRef(); + location += ": " + place + " (" + x + ',' + y; + if (path_parts == 5) location += ',' + path_array[4].asStringRef(); + return location + ')'; + } return url; } @@ -885,6 +1139,12 @@ std::string LLUrlEntryPlace::getLabel(const std::string &url, const LLUrlLabelCa std::string LLUrlEntryPlace::getLocation(const std::string &url) const { // return the part of the Url after secondlife:// part + const auto uri = LLURI(url); + bool xgrid = boost::algorithm::starts_with(uri.scheme(), "x-grid"); + if (xgrid) + { + return ::getStringAfterToken(url, "region/"); + } return ::getStringAfterToken(url, "://"); } @@ -894,7 +1154,7 @@ std::string LLUrlEntryPlace::getLocation(const std::string &url) const // LLUrlEntryRegion::LLUrlEntryRegion() { - mPattern = boost::regex("secondlife:///app/region/[^/\\s]+(/\\d+)?(/\\d+)?(/\\d+)?/?", + mPattern = boost::regex(X_GRID_OR_SECONDLIFE_HEADER_REGEX"//app/region/[^/\\s]+(/\\d+)?(/\\d+)?(/\\d+)?/?", boost::regex::perl|boost::regex::icase); mMenuName = "menu_url_slurl.xml"; mTooltip = LLTrans::getString("TooltipSLURL"); @@ -910,30 +1170,37 @@ std::string LLUrlEntryRegion::getLabel(const std::string &url, const LLUrlLabelC // - secondlife:///app/region/Place // - LLSD path_array = LLURI(url).pathArray(); + const auto uri = LLURI(url); + LLSD path_array = uri.pathArray(); S32 path_parts = path_array.size(); - if (path_parts < 3) // no region name + bool xgrid = boost::algorithm::starts_with(uri.scheme(), "x-grid"); + auto i = xgrid ? 3 : 2; + + if (path_parts < i+1) // no region name { - llwarns << "Failed to parse url [" << url << "]" << llendl; + LL_WARNS() << "Failed to parse url [" << url << "]" << LL_ENDL; return url; } - std::string label = unescapeUrl(path_array[2]); // region name + std::string label = + xgrid ? unescapeUrl(path_array[0].asStringRef()) + ": " + unescapeUrl(path_array[i].asStringRef()) : // grid and region name + unescapeUrl(path_array[i].asStringRef()); // region name - if (path_parts > 3) // secondlife:///app/region/Place/X + ++i; + if (path_parts > i+1) // secondlife:///app/region/Place/X { - std::string x = path_array[3]; + std::string x = path_array[i++]; label += " (" + x; - if (path_parts > 4) // secondlife:///app/region/Place/X/Y + if (path_parts > i+1) // secondlife:///app/region/Place/X/Y { - std::string y = path_array[4]; + std::string y = path_array[i++]; label += "," + y; - if (path_parts > 5) // secondlife:///app/region/Place/X/Y/Z + if (path_parts > i+1) // secondlife:///app/region/Place/X/Y/Z { - std::string z = path_array[5]; + std::string z = path_array[i]; label = label + "," + z; } } @@ -946,15 +1213,17 @@ std::string LLUrlEntryRegion::getLabel(const std::string &url, const LLUrlLabelC std::string LLUrlEntryRegion::getLocation(const std::string &url) const { - LLSD path_array = LLURI(url).pathArray(); - std::string region_name = unescapeUrl(path_array[2]); + const auto uri = LLURI(url); + LLSD path_array = uri.pathArray(); + bool xgrid = boost::algorithm::starts_with(uri.scheme(), "x-grid"); + std::string region_name = unescapeUrl(path_array[xgrid ? 3 : 2]); return region_name; } // // LLUrlEntryTeleport Describes a Second Life teleport Url, e.g., // secondlife:///app/teleport/Ahern/50/50/50/ -// x-grid-location-info://lincoln.lindenlab.com/app/teleport/Ahern/50/50/50/ +// x-grid-info://lincoln.lindenlab.com/app/teleport/Ahern/50/50/50/ // LLUrlEntryTeleport::LLUrlEntryTeleport() { @@ -1028,7 +1297,7 @@ std::string LLUrlEntryTeleport::getLocation(const std::string &url) const // LLUrlEntrySL::LLUrlEntrySL() { - mPattern = boost::regex("secondlife://(\\w+)?(:\\d+)?/\\S+", + mPattern = boost::regex(X_GRID_OR_SECONDLIFE_HEADER_REGEX "(\\w+)?(:\\d+)?/\\S+", boost::regex::perl|boost::regex::icase); mMenuName = "menu_url_slapp.xml"; mTooltip = LLTrans::getString("TooltipSLAPP"); @@ -1045,7 +1314,7 @@ std::string LLUrlEntrySL::getLabel(const std::string &url, const LLUrlLabelCallb // LLUrlEntrySLLabel::LLUrlEntrySLLabel() { - mPattern = boost::regex("\\[secondlife://\\S+[ \t]+[^\\]]+\\]", + mPattern = boost::regex("\\[" X_GRID_OR_SECONDLIFE_HEADER_REGEX "\\S+[ \t]+[^\\]]+\\]", boost::regex::perl|boost::regex::icase); mMenuName = "menu_url_slapp.xml"; mTooltip = LLTrans::getString("TooltipSLAPP"); @@ -1053,7 +1322,8 @@ LLUrlEntrySLLabel::LLUrlEntrySLLabel() std::string LLUrlEntrySLLabel::getLabel(const std::string &url, const LLUrlLabelCallback &cb) { - return getLabelFromWikiLink(url); + std::string label = getLabelFromWikiLink(url); + return (!LLUrlRegistry::instance().hasUrl(label)) ? label : getUrl(url); } std::string LLUrlEntrySLLabel::getUrl(const std::string &string) const @@ -1149,11 +1419,13 @@ std::string LLUrlEntryNoLink::getLabel(const std::string &url, const LLUrlLabelC return getUrl(url); } -/*LLStyle::Params LLUrlEntryNoLink::getStyle() const +LLStyleSP LLUrlEntryNoLink::getStyle() const { // Don't render as URL (i.e. no context menu or hand cursor). - return LLStyle::Params().is_link(false); -}*/ + LLStyleSP style(new LLStyle()); + style->setLinkHREF(" "); + return style; +} // @@ -1186,3 +1458,126 @@ std::string LLUrlEntryIcon::getIcon(const std::string &url) LLStringUtil::trim(mIcon); return mIcon; } + +// +// LLUrlEntryEmail Describes a generic mailto: Urls +// +LLUrlEntryEmail::LLUrlEntryEmail() + : LLUrlEntryBase() +{ + mPattern = boost::regex("(mailto:)?[\\w\\.\\-]+@[\\w\\.\\-]+\\.[a-z]{2,63}", + boost::regex::perl | boost::regex::icase); + mMenuName = "menu_url_email.xml"; + mTooltip = LLTrans::getString("TooltipEmail"); +} + +std::string LLUrlEntryEmail::getLabel(const std::string &url, const LLUrlLabelCallback &cb) +{ + size_t pos = url.find("mailto:"); + + if (pos == std::string::npos) + { + return escapeUrl(url); + } + + std::string ret = escapeUrl(url.substr(pos + 7, url.length() - pos + 8)); + return ret; +} + +std::string LLUrlEntryEmail::getUrl(const std::string &string) const +{ + if (string.find("mailto:") == std::string::npos) + { + return "mailto:" + escapeUrl(string); + } + return escapeUrl(string); +} + +LLUrlEntryExperienceProfile::LLUrlEntryExperienceProfile() +{ + mPattern = boost::regex(APP_HEADER_REGEX "/experience/[\\da-f-]+/\\w+\\S*", + boost::regex::perl|boost::regex::icase); + mIcon = "Generic_Experience"; + mMenuName = "menu_url_experience.xml"; +} + +std::string LLUrlEntryExperienceProfile::getLabel(const std::string& url, const LLUrlLabelCallback& cb) +{ + if (!gCacheName) + { + // probably at the login screen, use short string for layout + return LLTrans::getString("LoadingData"); + } + + std::string experience_id_string = getIDStringFromUrl(url); + if (experience_id_string.empty()) + { + // something went wrong, just give raw url + return unescapeUrl(url); + } + + LLUUID experience_id(experience_id_string); + if (experience_id.isNull()) + { + return LLTrans::getString("ExperienceNameNull"); + } + + const LLSD& experience_details = LLExperienceCache::instance().get(experience_id); + if (!experience_details.isUndefined()) + { + std::string experience_name_string = experience_details[LLExperienceCache::NAME].asString(); + return experience_name_string.empty() ? LLTrans::getString("ExperienceNameUntitled") : experience_name_string; + } + + addObserver(experience_id_string, url, cb); + LLExperienceCache::instance().get(experience_id, boost::bind(&LLUrlEntryExperienceProfile::onExperienceDetails, this, _1)); + return LLTrans::getString("LoadingData"); + +} + +void LLUrlEntryExperienceProfile::onExperienceDetails(const LLSD& experience_details) +{ + std::string name = experience_details[LLExperienceCache::NAME].asString(); + if(name.empty()) + { + name = LLTrans::getString("ExperienceNameUntitled"); + } + callObservers(experience_details[LLExperienceCache::EXPERIENCE_ID].asString(), name, LLStringUtil::null); +} + +// +// +// LLUrlEntryJIRA describes a Jira Issue Tracker entry +// +LLUrlEntryJira::LLUrlEntryJira() +{ + mPattern = boost::regex("(\\b(?:ALCH|SV|BUG|CHOP|FIRE|MAINT|OPEN|SCR|STORM|SVC|VWR|WEB)-\\d+)", + boost::regex::perl); + mMenuName = "menu_url_http.xml"; + mTooltip = LLTrans::getString("TooltipHttpUrl"); +} + +std::string LLUrlEntryJira::getLabel(const std::string &url, const LLUrlLabelCallback &cb) +{ + return unescapeUrl(url); +} + +std::string LLUrlEntryJira::getTooltip(const std::string &string) const +{ + return getUrl(string); +} + +std::string LLUrlEntryJira::getUrl(const std::string &url) const +{ + return (boost::format( + (url.find("ALCH") != std::string::npos) ? + "http://alchemy.atlassian.net/browse/%1%" : + (url.find("SV") != std::string::npos) ? + "https://singularityviewer.atlassian.net/browse/%1%" : + (url.find("FIRE") != std::string::npos) ? + "https://jira.firestormviewer.com/browse/%1%" : + "http://jira.secondlife.com/browse/%1%" + ) % url).str(); +} +// + diff --git a/indra/llui/llurlentry.h b/indra/llui/llurlentry.h index 0e2f4038fb..6c382aa26d 100644 --- a/indra/llui/llurlentry.h +++ b/indra/llui/llurlentry.h @@ -32,12 +32,10 @@ #include "lluicolor.h" #include "llstyle.h" +#include "llavatarname.h" #include "llhost.h" // for resolving parcel name by parcel id -#include #include -#include -#include class LLAvatarName; @@ -77,11 +75,14 @@ class LLUrlEntryBase /// Given a matched Url, return a label for the Url virtual std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) { return url; } + /// Return port, query and fragment parts for the Url + virtual std::string getQuery(const std::string &url) const { return ""; } + /// Return an icon that can be displayed next to Urls of this type virtual std::string getIcon(const std::string &url); /// Return the style to render the displayed text - //virtual LLStyle::Params getStyle() const; + virtual LLStyleSP getStyle() const; /// Given a matched Url, return a tooltip string for the hyperlink virtual std::string getTooltip(const std::string &string) const { return mTooltip; } @@ -93,12 +94,18 @@ class LLUrlEntryBase virtual std::string getLocation(const std::string &url) const { return ""; } /// Should this link text be underlined only when mouse is hovered over it? - virtual bool underlineOnHoverOnly(const std::string &string) const { return false; } + virtual bool underlineOnHoverOnly(const std::string &string) const { return true; } // + + virtual bool isTrusted() const { return false; } virtual LLUUID getID(const std::string &string) const { return LLUUID::null; } bool isLinkDisabled() const; + bool isWikiLinkCorrect(const std::string& url); + + virtual bool isSLURLvalid(const std::string &url) const { return TRUE; }; + protected: std::string getIDStringFromUrl(const std::string &url) const; std::string escapeUrl(const std::string &url) const; @@ -106,6 +113,8 @@ class LLUrlEntryBase std::string getLabelFromWikiLink(const std::string &url) const; std::string getUrlFromWikiLink(const std::string &string) const; void addObserver(const std::string &id, const std::string &url, const LLUrlLabelCallback &cb); + std::string urlToLabelWithGreyQuery(const std::string &url) const; + std::string urlToGreyQuery(const std::string &url) const; virtual void callObservers(const std::string &id, const std::string &label, const std::string& icon); typedef struct { @@ -123,45 +132,83 @@ class LLUrlEntryBase /// /// LLUrlEntryHTTP Describes generic http: and https: Urls /// -class LLUrlEntryHTTP : public LLUrlEntryBase +class LLUrlEntryHTTP final : public LLUrlEntryBase { public: LLUrlEntryHTTP(); - /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) override; + /*virtual*/ std::string getUrl(const std::string &string) const override; + /*virtual*/ std::string getTooltip(const std::string &url) const override; }; /// /// LLUrlEntryHTTPLabel Describes generic http: and https: Urls with custom labels /// -class LLUrlEntryHTTPLabel : public LLUrlEntryBase +class LLUrlEntryHTTPLabel final : public LLUrlEntryBase { public: LLUrlEntryHTTPLabel(); - /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); - /*virtual*/ std::string getTooltip(const std::string &string) const; - /*virtual*/ std::string getUrl(const std::string &string) const; + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) override; + /*virtual*/ std::string getTooltip(const std::string &string) const override; + /*virtual*/ std::string getUrl(const std::string &string) const override; }; /// /// LLUrlEntryHTTPNoProtocol Describes generic Urls like www.google.com /// -class LLUrlEntryHTTPNoProtocol : public LLUrlEntryBase +class LLUrlEntryHTTPNoProtocol final : public LLUrlEntryBase { public: LLUrlEntryHTTPNoProtocol(); - /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); - /*virtual*/ std::string getUrl(const std::string &string) const; + std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) override; + std::string getQuery(const std::string &url) const override; + std::string getUrl(const std::string &string) const override; + std::string getTooltip(const std::string &url) const override; +}; + +class LLUrlEntryInvalidSLURL final : public LLUrlEntryBase +{ +public: + LLUrlEntryInvalidSLURL(); + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) override; + /*virtual*/ std::string getUrl(const std::string &string) const override; + /*virtual*/ std::string getTooltip(const std::string &url) const override; + + bool isSLURLvalid(const std::string &url) const override; }; /// /// LLUrlEntrySLURL Describes http://slurl.com/... Urls /// -class LLUrlEntrySLURL : public LLUrlEntryBase +class LLUrlEntrySLURL final : public LLUrlEntryBase { public: LLUrlEntrySLURL(); - /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); - /*virtual*/ std::string getLocation(const std::string &url) const; + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) override; + /*virtual*/ std::string getLocation(const std::string &url) const override; +}; + +/// +/// LLUrlEntrySeconlifeURLs Describes *secondlife.com and *lindenlab.com Urls +/// +class LLUrlEntrySecondlifeURL : public LLUrlEntryBase +{ +public: + LLUrlEntrySecondlifeURL(); + /*virtual*/ bool isTrusted() const override { return true; } + /*virtual*/ std::string getUrl(const std::string &string) const override; + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) override; + /*virtual*/ std::string getQuery(const std::string &url) const override; + /*virtual*/ std::string getTooltip(const std::string &url) const override; +}; + +/// +/// LLUrlEntrySeconlifeURLs Describes *secondlife.com and *lindenlab.com Urls +/// +class LLUrlEntrySimpleSecondlifeURL final : public LLUrlEntrySecondlifeURL +{ +public: + LLUrlEntrySimpleSecondlifeURL(); }; /// @@ -171,16 +218,29 @@ class LLUrlEntryAgent : public LLUrlEntryBase { public: LLUrlEntryAgent(); - /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); - /*virtual*/ std::string getIcon(const std::string &url); - /*virtual*/ std::string getTooltip(const std::string &string) const; - //*virtual*/ LLStyle::Params getStyle() const; - /*virtual*/ LLUUID getID(const std::string &string) const; - /*virtual*/ bool underlineOnHoverOnly(const std::string &string) const; + ~LLUrlEntryAgent() + { + for(const auto& conn_pair : mAvatarNameCacheConnections) + { + if (conn_pair.second.connected()) + { + conn_pair.second.disconnect(); + } + } + mAvatarNameCacheConnections.clear(); + } + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) override; + /*virtual*/ std::string getIcon(const std::string &url) override; + /*virtual*/ std::string getTooltip(const std::string &string) const override; + /*virtual*/ LLStyleSP getStyle() const override; + /*virtual*/ LLUUID getID(const std::string &string) const override; + /*virtual*/ bool underlineOnHoverOnly(const std::string &string) const override; protected: - /*virtual*/ void callObservers(const std::string &id, const std::string &label, const std::string& icon); + /*virtual*/ void callObservers(const std::string &id, const std::string &label, const std::string& icon) override; private: void onAvatarNameCache(const LLUUID& id, const LLAvatarName& av_name); + using avatar_name_cache_connection_map_t = std::multimap; + avatar_name_cache_connection_map_t mAvatarNameCacheConnections; }; /// @@ -192,13 +252,27 @@ class LLUrlEntryAgentName : public LLUrlEntryBase, public boost::signals2::track { public: LLUrlEntryAgentName(); - /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); - //*virtual*/ LLStyle::Params getStyle() const; + ~LLUrlEntryAgentName() + { + for (const auto& conn_pair : mAvatarNameCacheConnections) + { + if (conn_pair.second.connected()) + { + conn_pair.second.disconnect(); + } + } + mAvatarNameCacheConnections.clear(); + + } + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) override; + /*virtual*/ LLStyleSP getStyle() const override; protected: // override this to pull out relevant name fields virtual std::string getName(const LLAvatarName& avatar_name) = 0; private: void onAvatarNameCache(const LLUUID& id, const LLAvatarName& av_name); + using avatar_name_cache_connection_map_t = std::multimap; + avatar_name_cache_connection_map_t mAvatarNameCacheConnections; }; @@ -207,12 +281,20 @@ class LLUrlEntryAgentName : public LLUrlEntryBase, public boost::signals2::track /// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/completename /// that displays the full display name + user name for an avatar /// such as "James Linden (james.linden)" -class LLUrlEntryAgentCompleteName : public LLUrlEntryAgentName +class LLUrlEntryAgentCompleteName final : public LLUrlEntryAgentName { public: LLUrlEntryAgentCompleteName(); private: - /*virtual*/ std::string getName(const LLAvatarName& avatar_name); + /*virtual*/ std::string getName(const LLAvatarName& avatar_name) override; +}; + +class LLUrlEntryAgentLegacyName final : public LLUrlEntryAgentName +{ +public: + LLUrlEntryAgentLegacyName(); +private: + /*virtual*/ std::string getName(const LLAvatarName& avatar_name) override; }; /// @@ -220,12 +302,12 @@ class LLUrlEntryAgentCompleteName : public LLUrlEntryAgentName /// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/displayname /// that displays the just the display name for an avatar /// such as "James Linden" -class LLUrlEntryAgentDisplayName : public LLUrlEntryAgentName +class LLUrlEntryAgentDisplayName final : public LLUrlEntryAgentName { public: LLUrlEntryAgentDisplayName(); private: - /*virtual*/ std::string getName(const LLAvatarName& avatar_name); + /*virtual*/ std::string getName(const LLAvatarName& avatar_name) override; }; /// @@ -233,25 +315,39 @@ class LLUrlEntryAgentDisplayName : public LLUrlEntryAgentName /// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/username /// that displays the just the display name for an avatar /// such as "james.linden" -class LLUrlEntryAgentUserName : public LLUrlEntryAgentName +class LLUrlEntryAgentUserName final : public LLUrlEntryAgentName { public: LLUrlEntryAgentUserName(); private: - /*virtual*/ std::string getName(const LLAvatarName& avatar_name); + /*virtual*/ std::string getName(const LLAvatarName& avatar_name) override; +}; + +/// +/// LLUrlEntryExperienceProfile Describes a Second Life experience profile Url, e.g., +/// secondlife:///app/experience/0e346d8b-4433-4d66-a6b0-fd37083abc4c/profile +/// that displays the experience name +class LLUrlEntryExperienceProfile final : public LLUrlEntryBase +{ +public: + LLUrlEntryExperienceProfile(); + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) override; +private: + void onExperienceDetails(const LLSD& experience_details); }; + /// /// LLUrlEntryGroup Describes a Second Life group Url, e.g., /// secondlife:///app/group/00005ff3-4044-c79f-9de8-fb28ae0df991/about /// -class LLUrlEntryGroup : public LLUrlEntryBase +class LLUrlEntryGroup final : public LLUrlEntryBase { public: LLUrlEntryGroup(); - /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); - //*virtual*/ LLStyle::Params getStyle() const; - /*virtual*/ LLUUID getID(const std::string &string) const; + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) override; + /*virtual*/ LLStyleSP getStyle() const override; + /*virtual*/ LLUUID getID(const std::string &string) const override; private: void onGroupNameReceived(const LLUUID& id, const std::string& name, bool is_group); }; @@ -260,11 +356,11 @@ class LLUrlEntryGroup : public LLUrlEntryBase /// LLUrlEntryInventory Describes a Second Life inventory Url, e.g., /// secondlife:///app/inventory/0e346d8b-4433-4d66-a6b0-fd37083abc4c/select /// -class LLUrlEntryInventory : public LLUrlEntryBase +class LLUrlEntryInventory final : public LLUrlEntryBase { public: LLUrlEntryInventory(); - /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) override; private: }; @@ -272,12 +368,12 @@ class LLUrlEntryInventory : public LLUrlEntryBase /// LLUrlEntryObjectIM Describes a Second Life inspector for the object Url, e.g., /// secondlife:///app/objectim/7bcd7864-da6b-e43f-4486-91d28a28d95b?name=Object&owner=3de548e1-57be-cfea-2b78-83ae3ad95998&slurl=Danger!%20Danger!/200/200/30/&groupowned=1 /// -class LLUrlEntryObjectIM : public LLUrlEntryBase +class LLUrlEntryObjectIM final : public LLUrlEntryBase { public: LLUrlEntryObjectIM(); - /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); - /*virtual*/ std::string getLocation(const std::string &url) const; + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) override; + /*virtual*/ std::string getLocation(const std::string &url) const override; private: }; @@ -285,7 +381,7 @@ class LLUrlEntryObjectIM : public LLUrlEntryBase /// LLUrlEntryParcel Describes a Second Life parcel Url, e.g., /// secondlife:///app/parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/about /// -class LLUrlEntryParcel : public LLUrlEntryBase +class LLUrlEntryParcel final : public LLUrlEntryBase { public: struct LLParcelData @@ -300,7 +396,7 @@ class LLUrlEntryParcel : public LLUrlEntryBase LLUrlEntryParcel(); ~LLUrlEntryParcel(); - /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) override; // Sends a parcel info request to sim. void sendParcelInfoRequest(const LLUUID& parcel_id); @@ -332,98 +428,123 @@ class LLUrlEntryParcel : public LLUrlEntryBase /// LLUrlEntryPlace Describes a Second Life location Url, e.g., /// secondlife://Ahern/50/50/50 /// -class LLUrlEntryPlace : public LLUrlEntryBase +class LLUrlEntryPlace final : public LLUrlEntryBase { public: LLUrlEntryPlace(); - /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); - /*virtual*/ std::string getLocation(const std::string &url) const; + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) override; + /*virtual*/ std::string getLocation(const std::string &url) const override; }; /// /// LLUrlEntryRegion Describes a Second Life location Url, e.g., /// secondlife:///app/region/Ahern/128/128/0 /// -class LLUrlEntryRegion : public LLUrlEntryBase +class LLUrlEntryRegion final : public LLUrlEntryBase { public: LLUrlEntryRegion(); - /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); - /*virtual*/ std::string getLocation(const std::string &url) const; + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) override; + /*virtual*/ std::string getLocation(const std::string &url) const override; }; /// /// LLUrlEntryTeleport Describes a Second Life teleport Url, e.g., /// secondlife:///app/teleport/Ahern/50/50/50/ /// -class LLUrlEntryTeleport : public LLUrlEntryBase +class LLUrlEntryTeleport final : public LLUrlEntryBase { public: LLUrlEntryTeleport(); - /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); - /*virtual*/ std::string getLocation(const std::string &url) const; + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) override; + /*virtual*/ std::string getLocation(const std::string &url) const override; }; /// /// LLUrlEntrySL Describes a generic SLURL, e.g., a Url that starts /// with secondlife:// (used as a catch-all for cases not matched above) /// -class LLUrlEntrySL : public LLUrlEntryBase +class LLUrlEntrySL final : public LLUrlEntryBase { public: LLUrlEntrySL(); - /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) override; }; /// /// LLUrlEntrySLLabel Describes a generic SLURL, e.g., a Url that starts /// with secondlife:// with the ability to specify a custom label. /// -class LLUrlEntrySLLabel : public LLUrlEntryBase +class LLUrlEntrySLLabel final : public LLUrlEntryBase { public: LLUrlEntrySLLabel(); - /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); - /*virtual*/ std::string getUrl(const std::string &string) const; - /*virtual*/ std::string getTooltip(const std::string &string) const; - /*virtual*/ bool underlineOnHoverOnly(const std::string &string) const; + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) override; + /*virtual*/ std::string getUrl(const std::string &string) const override; + /*virtual*/ std::string getTooltip(const std::string &string) const override; + /*virtual*/ bool underlineOnHoverOnly(const std::string &string) const override; }; /// /// LLUrlEntryWorldMap Describes a Second Life worldmap Url, e.g., /// secondlife:///app/worldmap/Ahern/50/50/50 /// -class LLUrlEntryWorldMap : public LLUrlEntryBase +class LLUrlEntryWorldMap final : public LLUrlEntryBase { public: LLUrlEntryWorldMap(); - /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); - /*virtual*/ std::string getLocation(const std::string &url) const; + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) override; + /*virtual*/ std::string getLocation(const std::string &url) const override; }; /// /// LLUrlEntryNoLink lets us turn of URL detection with ... tags /// -class LLUrlEntryNoLink : public LLUrlEntryBase +class LLUrlEntryNoLink final : public LLUrlEntryBase { public: LLUrlEntryNoLink(); - /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); - /*virtual*/ std::string getUrl(const std::string &string) const; - //*virtual*/ LLStyle::Params getStyle() const; + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) override; + /*virtual*/ std::string getUrl(const std::string &string) const override; + /*virtual*/ LLStyleSP getStyle() const override; }; /// /// LLUrlEntryIcon describes an icon with ... tags /// -class LLUrlEntryIcon : public LLUrlEntryBase +class LLUrlEntryIcon final : public LLUrlEntryBase { public: LLUrlEntryIcon(); - /*virtual*/ std::string getUrl(const std::string &string) const; - /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb); - /*virtual*/ std::string getIcon(const std::string &url); + /*virtual*/ std::string getUrl(const std::string &string) const override; + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) override; + /*virtual*/ std::string getIcon(const std::string &url) override; }; +/// +/// LLUrlEntryEmail Describes a generic mailto: Urls +/// +class LLUrlEntryEmail final : public LLUrlEntryBase +{ +public: + LLUrlEntryEmail(); + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) override; + /*virtual*/ std::string getUrl(const std::string &string) const override; +}; + +// +/// +/// LLUrlEntryJira describes a Jira Issue +/// +class LLUrlEntryJira final : public LLUrlEntryBase +{ +public: + LLUrlEntryJira(); + /*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb) override; + /*virtual*/ std::string getTooltip(const std::string &string) const override; + /*virtual*/ std::string getUrl(const std::string &string) const override; + +}; +// #endif diff --git a/indra/llui/llurlmatch.cpp b/indra/llui/llurlmatch.cpp index af4955ac4e..240e04ef0a 100644 --- a/indra/llui/llurlmatch.cpp +++ b/indra/llui/llurlmatch.cpp @@ -1,3 +1,5 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com /** * @file llurlmatch.cpp * @author Martin Reddy @@ -37,26 +39,29 @@ LLUrlMatch::LLUrlMatch() : mIcon(""), mMenuName(""), mLocation(""), - mUnderlineOnHoverOnly(false) + mUnderlineOnHoverOnly(false), + mTrusted(false) { } -void LLUrlMatch::setValues(U32 start, U32 end, const std::string &url, - const std::string &label, const std::string &tooltip, - const std::string &icon, /*const LLStyle::Params& style,*/ +void LLUrlMatch::setValues(U32 start, U32 end, const std::string &url, const std::string &label, + const std::string& query, const std::string &tooltip, + const std::string &icon, const LLStyleSP& style, const std::string &menu, const std::string &location, - const LLUUID& id, bool underline_on_hover_only) + const LLUUID& id, bool underline_on_hover_only, bool trusted) { mStart = start; mEnd = end; mUrl = url; mLabel = label; + mQuery = query; mTooltip = tooltip; mIcon = icon; - //mStyle = style; - //mStyle.link_href = url; + mStyle = style; + mStyle->setLinkHREF(mStyle->isLink() ? LLStringUtil::null : url); // Singu Note: This hack exists in lieu of no link flag mMenuName = menu; mLocation = location; mID = id; mUnderlineOnHoverOnly = underline_on_hover_only; + mTrusted = trusted; } diff --git a/indra/llui/llurlmatch.h b/indra/llui/llurlmatch.h index af36e69255..fc0b505ecb 100644 --- a/indra/llui/llurlmatch.h +++ b/indra/llui/llurlmatch.h @@ -30,8 +30,6 @@ //#include "linden_common.h" -#include -#include #include "llstyle.h" /// @@ -62,6 +60,9 @@ class LLUrlMatch /// return a label that can be used for the display of this Url std::string getLabel() const { return mLabel; } + /// return a right part of url which should be drawn in grey + std::string getQuery() const { return mQuery; } + /// return a message that could be displayed in a tooltip or status bar std::string getTooltip() const { return mTooltip; } @@ -69,7 +70,7 @@ class LLUrlMatch std::string getIcon() const { return mIcon; } /// Return the color to render the displayed text - //LLStyle::Params getStyle() const { return mStyle; } + LLStyleSP getStyle() const { return mStyle; } /// Return the name of a XUI file containing the context menu items std::string getMenuName() const { return mMenuName; } @@ -80,12 +81,15 @@ class LLUrlMatch /// Should this link text be underlined only when mouse is hovered over it? bool underlineOnHoverOnly() const { return mUnderlineOnHoverOnly; } + /// Return true if Url is trusted. + bool isTrusted() const { return mTrusted; } + /// Change the contents of this match object (used by LLUrlRegistry) void setValues(U32 start, U32 end, const std::string &url, const std::string &label, - const std::string &tooltip, const std::string &icon, - /*const LLStyle::Params& style, */const std::string &menu, + const std::string& query, const std::string &tooltip, const std::string &icon, + const LLStyleSP& style, const std::string &menu, const std::string &location, const LLUUID& id, - bool underline_on_hover_only = false ); + bool underline_on_hover_only = false, bool trusted = false); const LLUUID& getID() const { return mID; } private: @@ -93,13 +97,15 @@ class LLUrlMatch U32 mEnd; std::string mUrl; std::string mLabel; + std::string mQuery; std::string mTooltip; std::string mIcon; std::string mMenuName; std::string mLocation; LLUUID mID; - //LLStyle::Params mStyle; + LLStyleSP mStyle; bool mUnderlineOnHoverOnly; + bool mTrusted; }; #endif diff --git a/indra/llui/llurlregistry.cpp b/indra/llui/llurlregistry.cpp index 235b002d0d..c7dba05e4b 100644 --- a/indra/llui/llurlregistry.cpp +++ b/indra/llui/llurlregistry.cpp @@ -1,3 +1,5 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com /** * @file llurlregistry.cpp * @author Martin Reddy @@ -27,6 +29,7 @@ #include "linden_common.h" #include "llurlregistry.h" +#include "lluriparser.h" #include @@ -37,15 +40,26 @@ void LLUrlRegistryNullCallback(const std::string &url, const std::string &label, LLUrlRegistry::LLUrlRegistry() { - mUrlEntry.reserve(20); + mUrlEntry.reserve(23); // // Urls are matched in the order that they were registered registerUrl(new LLUrlEntryNoLink()); - registerUrl(new LLUrlEntryIcon()); + mUrlEntryIcon = new LLUrlEntryIcon(); + registerUrl(mUrlEntryIcon); + mLLUrlEntryInvalidSLURL = new LLUrlEntryInvalidSLURL(); + registerUrl(mLLUrlEntryInvalidSLURL); registerUrl(new LLUrlEntrySLURL()); + + // decorated links for host names like: secondlife.com and lindenlab.com + mUrlEntryTrusted = new LLUrlEntrySecondlifeURL(); + registerUrl(mUrlEntryTrusted); + registerUrl(new LLUrlEntrySimpleSecondlifeURL()); + registerUrl(new LLUrlEntryHTTP()); - registerUrl(new LLUrlEntryHTTPLabel()); + mUrlEntryHTTPLabel = new LLUrlEntryHTTPLabel(); + registerUrl(mUrlEntryHTTPLabel); registerUrl(new LLUrlEntryAgentCompleteName()); + registerUrl(new LLUrlEntryAgentLegacyName()); registerUrl(new LLUrlEntryAgentDisplayName()); registerUrl(new LLUrlEntryAgentUserName()); // LLUrlEntryAgent*Name must appear before LLUrlEntryAgent since @@ -59,14 +73,18 @@ LLUrlRegistry::LLUrlRegistry() registerUrl(new LLUrlEntryObjectIM()); registerUrl(new LLUrlEntryPlace()); registerUrl(new LLUrlEntryInventory()); - registerUrl(new LLUrlEntryObjectIM()); + registerUrl(new LLUrlEntryExperienceProfile()); //LLUrlEntrySL and LLUrlEntrySLLabel have more common pattern, //so it should be registered in the end of list registerUrl(new LLUrlEntrySL()); - registerUrl(new LLUrlEntrySLLabel()); - // most common pattern is a URL without any protocol, - // e.g., "secondlife.com" - registerUrl(new LLUrlEntryHTTPNoProtocol()); + mUrlEntrySLLabel = new LLUrlEntrySLLabel(); + registerUrl(mUrlEntrySLLabel); + registerUrl(new LLUrlEntryEmail()); + // Parse teh jiras! + registerUrl(new LLUrlEntryJira()); // + // most common pattern is a URL without any protocol starting with "www", + // e.g., "www.secondlife.com" + registerUrl(new LLUrlEntryHTTPNoProtocol()); } LLUrlRegistry::~LLUrlRegistry() @@ -90,7 +108,7 @@ void LLUrlRegistry::registerUrl(LLUrlEntryBase *url, bool force_front) } } -static bool matchRegex(const char *text, boost::regex regex, U32 &start, U32 &end) +static bool matchRegex(const char *text, const boost::regex& regex, U32 &start, U32 &end) { boost::cmatch result; bool found; @@ -100,7 +118,7 @@ static bool matchRegex(const char *text, boost::regex regex, U32 &start, U32 &en { found = boost::regex_search(text, result, regex); } - catch (std::runtime_error &) + catch (const std::runtime_error &) { return false; } @@ -127,6 +145,11 @@ static bool matchRegex(const char *text, boost::regex regex, U32 &start, U32 &en end--; } + else if (text[end] == ']' && std::string(text+start, end-start).find('[') == std::string::npos) + { + end--; + } + return true; } @@ -142,32 +165,77 @@ static bool stringHasUrl(const std::string &text) text.find(".edu") != std::string::npos || text.find(".org") != std::string::npos || text.find("") != std::string::npos || - text.find(" +static bool stringHasJira(const std::string &text) +{ + // fast heuristic test for a URL in a string. This is used + // to avoid lots of costly regex calls, BUT it needs to be + // kept in sync with the LLUrlEntry regexes we support. + return (text.find("ALCH") != std::string::npos || + text.find("SV") != std::string::npos || + text.find("BUG") != std::string::npos || + text.find("CHOP") != std::string::npos || + text.find("FIRE") != std::string::npos || + text.find("MAINT") != std::string::npos || + text.find("OPEN") != std::string::npos || + text.find("SCR") != std::string::npos || + text.find("STORM") != std::string::npos || + text.find("SVC") != std::string::npos || + text.find("VWR") != std::string::npos || + text.find("WEB") != std::string::npos); } +// -bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LLUrlLabelCallback &cb) +bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LLUrlLabelCallback &cb, bool is_content_trusted) { // avoid costly regexes if there is clearly no URL in the text - if (! stringHasUrl(text)) + if (!(stringHasUrl(text) || stringHasJira(text))) // { return false; } // find the first matching regex from all url entries in the registry U32 match_start = 0, match_end = 0; - LLUrlEntryBase *match_entry = NULL; + LLUrlEntryBase *match_entry = nullptr; std::vector::iterator it; for (it = mUrlEntry.begin(); it != mUrlEntry.end(); ++it) { + //Skip for url entry icon if content is not trusted + if(!is_content_trusted && (mUrlEntryIcon == *it)) + { + continue; + } + LLUrlEntryBase *url_entry = *it; U32 start = 0, end = 0; if (matchRegex(text.c_str(), url_entry->getPattern(), start, end)) { // does this match occur in the string before any other match - if (start < match_start || match_entry == NULL) + if (start < match_start || match_entry == nullptr) { + + if (mLLUrlEntryInvalidSLURL == *it) + { + if(url_entry && url_entry->isSLURLvalid(text.substr(start, end - start + 1))) + { + continue; + } + } + + if((mUrlEntryHTTPLabel == *it) || (mUrlEntrySLLabel == *it)) + { + if(url_entry && !url_entry->isWikiLinkCorrect(text.substr(start, end - start + 1))) + { + continue; + } + } + match_start = start; match_end = end; match_entry = url_entry; @@ -178,18 +246,32 @@ bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LL // did we find a match? if so, return its details in the match object if (match_entry) { + // Skip if link is an email with an empty username (starting with @). See MAINT-5371. + if (match_start > 0 && text.substr(match_start - 1, 1) == "@") + return false; + // fill in the LLUrlMatch object and return it std::string url = text.substr(match_start, match_end - match_start + 1); + + if (match_entry == mUrlEntryTrusted) + { + LLUriParser up(url); + up.normalize(); + url = up.normalizedUri(); + } + match.setValues(match_start, match_end, match_entry->getUrl(url), match_entry->getLabel(url, cb), + match_entry->getQuery(url), match_entry->getTooltip(url), match_entry->getIcon(url), - //match_entry->getStyle(), + match_entry->getStyle(), match_entry->getMenuName(), match_entry->getLocation(url), match_entry->getID(url), - match_entry->underlineOnHoverOnly(url)); + match_entry->underlineOnHoverOnly(url), + match_entry->isTrusted()); return true; } @@ -209,7 +291,7 @@ bool LLUrlRegistry::findUrl(const LLWString &text, LLUrlMatch &match, const LLUr // character encoding, so we need to update the start // and end values to be correct for the wide string. LLWString wurl = utf8str_to_wstring(match.getUrl()); - S32 start = text.find(wurl); + size_t start = text.find(wurl); if (start == std::string::npos) { return false; @@ -218,9 +300,10 @@ bool LLUrlRegistry::findUrl(const LLWString &text, LLUrlMatch &match, const LLUr match.setValues(start, end, match.getUrl(), match.getLabel(), + match.getQuery(), match.getTooltip(), match.getIcon(), - //match.getStyle(), + match.getStyle(), match.getMenuName(), match.getLocation(), match.getID(), diff --git a/indra/llui/llurlregistry.h b/indra/llui/llurlregistry.h index da16171a97..90099c6d1a 100644 --- a/indra/llui/llurlregistry.h +++ b/indra/llui/llurlregistry.h @@ -33,9 +33,6 @@ #include "llsingleton.h" #include "llstring.h" -#include -#include - /// This default callback for findUrl() simply ignores any label updates void LLUrlRegistryNullCallback(const std::string &url, const std::string &label, @@ -73,7 +70,8 @@ class LLUrlRegistry : public LLSingleton /// get the next Url in an input string, starting at a given character offset /// your callback is invoked if the matched Url's label changes in the future bool findUrl(const std::string &text, LLUrlMatch &match, - const LLUrlLabelCallback &cb = &LLUrlRegistryNullCallback); + const LLUrlLabelCallback &cb = &LLUrlRegistryNullCallback, + bool is_content_trusted = false); /// a slightly less efficient version of findUrl for wide strings bool findUrl(const LLWString &text, LLUrlMatch &match, @@ -92,6 +90,11 @@ class LLUrlRegistry : public LLSingleton friend class LLSingleton; std::vector mUrlEntry; + LLUrlEntryBase* mUrlEntryTrusted; + LLUrlEntryBase* mUrlEntryIcon; + LLUrlEntryBase* mLLUrlEntryInvalidSLURL; + LLUrlEntryBase* mUrlEntryHTTPLabel; + LLUrlEntryBase* mUrlEntrySLLabel; }; #endif diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index 6d2ae643aa..78602df941 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -38,7 +38,6 @@ #include #include -#include #include "llrender.h" #include "llevent.h" @@ -176,12 +175,12 @@ LLView::LLView( const std::string& name, const LLRect& rect, BOOL mouse_opaque, LLView::~LLView() { - //llinfos << "Deleting view " << mName << ":" << (void*) this << llendl; + //LL_INFOS() << "Deleting view " << mName << ":" << (void*) this << LL_ENDL; // llassert(LLView::sIsDrawing == FALSE); if( hasMouseCapture() ) { - //llwarns << "View holding mouse capture deleted: " << getName() << ". Mouse capture removed." << llendl; + //LL_WARNS() << "View holding mouse capture deleted: " << getName() << ". Mouse capture removed." << LL_ENDL; gFocusMgr.removeMouseCaptureWithoutCallback( this ); } @@ -322,7 +321,7 @@ bool LLView::addChild(LLView* child, S32 tab_group) } if (mParentView == child) { - llerrs << "Adding view " << child->getName() << " as child of itself" << llendl; + LL_ERRS() << "Adding view " << child->getName() << " as child of itself" << LL_ENDL; } // remove from current parent @@ -372,7 +371,7 @@ void LLView::removeChild(LLView* child) // if we are removing an item we are currently iterating over, that would be bad llassert(child->mInDraw == false); mChildList.remove( child ); - for(boost::unordered_map::iterator it=mChildHashMap.begin(); it != mChildHashMap.end(); ++it) + for(boost::container::flat_map::iterator it=mChildHashMap.begin(); it != mChildHashMap.end(); ++it) { if(it->second == child) { @@ -392,7 +391,7 @@ void LLView::removeChild(LLView* child) } else { - llwarns << child->getName() << "is not a child of " << getName() << llendl; + LL_WARNS() << child->getName() << "is not a child of " << getName() << LL_ENDL; } updateBoundingRect(); } @@ -400,7 +399,7 @@ void LLView::removeChild(LLView* child) LLView::ctrl_list_t LLView::getCtrlList() const { ctrl_list_t controls; - BOOST_FOREACH(LLView* viewp, mChildList) + for (LLView* viewp : mChildList) { if(viewp->isCtrl()) { @@ -613,12 +612,12 @@ void LLView::deleteAllChildren() LLView* viewp = mChildList.front(); delete viewp; // will remove the child from mChildList } - mChildHashMap.clear(); + mChildHashMap.clear(); // } void LLView::setAllChildrenEnabled(BOOL b) { - BOOST_FOREACH(LLView* viewp, mChildList) + for (LLView* viewp : mChildList) { viewp->setEnabled(b); } @@ -644,7 +643,7 @@ void LLView::setVisible(BOOL visible) // virtual void LLView::handleVisibilityChange ( BOOL new_visibility ) { - BOOST_FOREACH(LLView* viewp, mChildList) + for (LLView* viewp : mChildList) { // only views that are themselves visible will have their overall visibility affected by their ancestors if (viewp->getVisible()) @@ -680,12 +679,12 @@ BOOL LLView::handleHover(S32 x, S32 y, MASK mask) void LLView::onMouseEnter(S32 x, S32 y, MASK mask) { - //llinfos << "Mouse entered " << getName() << llendl; + //LL_INFOS() << "Mouse entered " << getName() << LL_ENDL; } void LLView::onMouseLeave(S32 x, S32 y, MASK mask) { - //llinfos << "Mouse left " << getName() << llendl; + //LL_INFOS() << "Mouse left " << getName() << LL_ENDL; } std::string LLView::getShowNamesToolTip() @@ -722,7 +721,7 @@ BOOL LLView::handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_rect_s std::string tool_tip; - BOOST_FOREACH(LLView* viewp, mChildList) + for(LLView* viewp : mChildList) { S32 local_x = x - viewp->mRect.mLeft; S32 local_y = y - viewp->mRect.mBottom; @@ -804,13 +803,13 @@ LLView* LLView::childrenHandleCharEvent(const std::string& desc, const METHOD& m { if ( getVisible() && getEnabled() ) { - BOOST_FOREACH(LLView* viewp, mChildList) + for (LLView* viewp : mChildList) { if ((viewp->*method)(c, mask, TRUE)) { if (LLView::sDebugKeys) { - llinfos << desc << " handled by " << viewp->getName() << llendl; + LL_INFOS() << desc << " handled by " << viewp->getName() << LL_ENDL; } return viewp; } @@ -823,7 +822,7 @@ LLView* LLView::childrenHandleCharEvent(const std::string& desc, const METHOD& m template LLView* LLView::childrenHandleMouseEvent(const METHOD& method, S32 x, S32 y, XDATA extra, bool allow_mouse_block) { - BOOST_FOREACH(LLView* viewp, mChildList) + for (LLView* viewp : mChildList) { S32 local_x = x - viewp->getRect().mLeft; S32 local_y = y - viewp->getRect().mBottom; @@ -853,7 +852,7 @@ LLView* LLView::childrenHandleDragAndDrop(S32 x, S32 y, MASK mask, // default to not accepting drag and drop, will be overridden by handler *accept = ACCEPT_NO; - BOOST_FOREACH(LLView* viewp, mChildList) + for (LLView* viewp : mChildList) { S32 local_x = x - viewp->getRect().mLeft; S32 local_y = y - viewp->getRect().mBottom; @@ -879,7 +878,7 @@ LLView* LLView::childrenHandleDragAndDrop(S32 x, S32 y, MASK mask, LLView* LLView::childrenHandleHover(S32 x, S32 y, MASK mask) { - BOOST_FOREACH(LLView* viewp, mChildList) + for (LLView* viewp : mChildList) { S32 local_x = x - viewp->getRect().mLeft; S32 local_y = y - viewp->getRect().mBottom; @@ -904,9 +903,9 @@ LLView* LLView::childrenHandleHover(S32 x, S32 y, MASK mask) LLView* LLView::childFromPoint(S32 x, S32 y, bool recur) { if (!getVisible()) - return NULL; + return NULL; // - BOOST_FOREACH(LLView* viewp, mChildList) + for (LLView* viewp : mChildList) { S32 local_x = x - viewp->getRect().mLeft; S32 local_y = y - viewp->getRect().mBottom; @@ -930,7 +929,7 @@ LLView* LLView::childFromPoint(S32 x, S32 y, bool recur) return viewp; } - return 0; + return NULL; // } BOOL LLView::handleKey(KEY key, MASK mask, BOOL called_from_parent) @@ -947,10 +946,12 @@ BOOL LLView::handleKey(KEY key, MASK mask, BOOL called_from_parent) if (!handled) { + // For event logging we don't care which widget handles it + // So we capture the key at the end of this function once we know if it was handled handled = handleKeyHere( key, mask ); - if (handled && LLView::sDebugKeys) + if (handled && LLView::sDebugKeys) // - AHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH { - llinfos << "Key handled by " << getName() << llendl; + LL_INFOS() << "Key handled by " << getName() << LL_ENDL; } } } @@ -963,6 +964,38 @@ BOOL LLView::handleKey(KEY key, MASK mask, BOOL called_from_parent) return handled; } +BOOL LLView::handleKeyUp(KEY key, MASK mask, BOOL called_from_parent) +{ + BOOL handled = FALSE; + + if (getVisible() && getEnabled()) + { + if (called_from_parent) + { + // Downward traversal + handled = childrenHandleKeyUp(key, mask) != NULL; + } + + if (!handled) + { + // For event logging we don't care which widget handles it + // So we capture the key at the end of this function once we know if it was handled + handled = handleKeyUpHere(key, mask); + if (handled) + { + LL_DEBUGS() << "Key handled by " << getName() << LL_ENDL; + } + } + } + + if (!handled && !called_from_parent && mParentView) + { + // Upward traversal + handled = mParentView->handleKeyUp(key, mask, FALSE); + } + return handled; +} + // Called from handleKey() // Handles key in this object. Checking parents and children happens in handleKey() BOOL LLView::handleKeyHere(KEY key, MASK mask) @@ -970,6 +1003,13 @@ BOOL LLView::handleKeyHere(KEY key, MASK mask) return FALSE; } +// Called from handleKey() +// Handles key in this object. Checking parents and children happens in handleKey() +BOOL LLView::handleKeyUpHere(KEY key, MASK mask) +{ + return FALSE; +} + BOOL LLView::handleUnicodeChar(llwchar uni_char, BOOL called_from_parent) { BOOL handled = FALSE; @@ -987,7 +1027,7 @@ BOOL LLView::handleUnicodeChar(llwchar uni_char, BOOL called_from_parent) handled = handleUnicodeCharHere(uni_char); if (handled && LLView::sDebugKeys) { - llinfos << "Unicode key handled by " << getName() << llendl; + LL_INFOS() << "Unicode key handled by " << getName() << LL_ENDL; } } } @@ -1095,6 +1135,12 @@ LLView* LLView::childrenHandleKey(KEY key, MASK mask) return childrenHandleCharEvent("Key", &LLView::handleKey, key, mask); } +// Called during downward traversal +LLView* LLView::childrenHandleKeyUp(KEY key, MASK mask) +{ + return childrenHandleCharEvent("Key Up", &LLView::handleKeyUp, key, mask); +} + // Called during downward traversal LLView* LLView::childrenHandleUnicodeChar(llwchar uni_char) { @@ -1137,7 +1183,7 @@ LLView* LLView::childrenHandleMiddleMouseUp(S32 x, S32 y, MASK mask) LLView* handled_view = NULL; if( getVisible() && getEnabled() ) { - BOOST_FOREACH(LLView* viewp, mChildList) + for (LLView* viewp : mChildList) { S32 local_x = x - viewp->getRect().mLeft; S32 local_y = y - viewp->getRect().mBottom; @@ -1175,7 +1221,16 @@ void LLView::drawChildren() }*/ if (!mChildList.empty()) { - LLView* rootp = LLUI::getRootView(); + LLRect clip_rect = LLUI::getRootView()->getRect(); + if (LLGLState::isEnabled()) + { + LLRect scissor = gGL.getScissor(); + scissor.mLeft /= LLUI::getScaleFactor().mV[VX]; + scissor.mTop /= LLUI::getScaleFactor().mV[VY]; + scissor.mRight /= LLUI::getScaleFactor().mV[VX]; + scissor.mBottom /= LLUI::getScaleFactor().mV[VY]; + clip_rect.intersectWith(scissor); + } ++sDepth; for (child_list_const_reverse_iter_t child_iter = mChildList.rbegin(); child_iter != mChildList.rend(); ++child_iter) @@ -1189,10 +1244,13 @@ void LLView::drawChildren() if (viewp->getVisible() && /*viewp != focus_view && */viewp->getRect().isValid()) { // Only draw views that are within the root view - LLRect screen_rect = viewp->calcScreenRect(); - if ( rootp->getRect().overlaps(screen_rect) ) + // LLView::calcScreenRect not used due to scrolllist cells containing views that aren't inserted into the view heirarchy. + // Render-time offset is stored in LLFontGL::sCurOrigin, which is valid during the draw call chain (which this method is part of) + // Bonus: Reading LLFontGL::sCurOrigin is way (way way way) faster than calling LLView::calcScreenRect. + LLRect screen_rect = viewp->getRect(); + screen_rect.translate(LLFontGL::sCurOrigin.mX, LLFontGL::sCurOrigin.mY); + if ( clip_rect.overlaps(screen_rect) ) { - //gGL.matrixMode(LLRender::MM_MODELVIEW); LLUI::pushMatrix(); { LLUI::translate((F32)viewp->getRect().mLeft, (F32)viewp->getRect().mBottom, 0.f); @@ -1210,14 +1268,13 @@ void LLView::drawChildren() // Check for bogus rectangle if (!getRect().isValid()) { - llwarns << "Bogus rectangle for " << getName() << " with " << mRect << llendl; + LL_WARNS() << "Bogus rectangle for " << getName() << " with " << mRect << LL_ENDL; } } } LLUI::popMatrix(); } } - } --sDepth; } @@ -1332,8 +1389,10 @@ void LLView::reshape(S32 width, S32 height, BOOL called_from_parent) mRect.mTop = getRect().mBottom + height; // move child views according to reshape flags - BOOST_FOREACH(LLView* viewp, mChildList) + for (LLView* viewp : mChildList) { + if (viewp != NULL) + { LLRect child_rect( viewp->mRect ); if (viewp->followsRight() && viewp->followsLeft()) @@ -1377,9 +1436,13 @@ void LLView::reshape(S32 width, S32 height, BOOL called_from_parent) S32 delta_x = child_rect.mLeft - viewp->getRect().mLeft; S32 delta_y = child_rect.mBottom - viewp->getRect().mBottom; viewp->translate( delta_x, delta_y ); - viewp->reshape(child_rect.getWidth(), child_rect.getHeight()); + if (child_rect.getWidth() != viewp->getRect().getWidth() || child_rect.getHeight() != viewp->getRect().getHeight()) + { + viewp->reshape(child_rect.getWidth(), child_rect.getHeight()); + } } } + } if (!called_from_parent) { @@ -1396,7 +1459,7 @@ LLRect LLView::calcBoundingRect() { LLRect local_bounding_rect = LLRect::null; - BOOST_FOREACH(LLView* childp, mChildList) + for (LLView* childp : mChildList) { // ignore invisible and "top" children when calculating bounding rect // such as combobox popups @@ -1549,16 +1612,16 @@ BOOL LLView::hasChild(const std::string& childname, BOOL recurse) const //----------------------------------------------------------------------------- // getChildView() //----------------------------------------------------------------------------- -static LLFastTimer::DeclareTimer FTM_FIND_VIEWS("Find Widgets"); +static LLTrace::BlockTimerStatHandle FTM_FIND_VIEWS("Find Widgets"); LLView* LLView::getChildView(const std::string& name, BOOL recurse, BOOL create_if_missing) const { - LLFastTimer ft(FTM_FIND_VIEWS); + LL_RECORD_BLOCK_TIME(FTM_FIND_VIEWS); //richard: should we allow empty names? //if(name.empty()) // return NULL; // Look for direct children *first* - /*BOOST_FOREACH(LLView* childp, mChildList) + /*for (LLView* childp : mChildList) { llassert(childp); if (childp->getName() == name) @@ -1566,7 +1629,7 @@ LLView* LLView::getChildView(const std::string& name, BOOL recurse, BOOL create_ return childp; } }*/ - boost::unordered_map::const_iterator it = mChildHashMap.find(name); + boost::container::flat_map::const_iterator it = mChildHashMap.find(name); if(it != mChildHashMap.end()) { return it->second; @@ -1574,7 +1637,7 @@ LLView* LLView::getChildView(const std::string& name, BOOL recurse, BOOL create_ if (recurse) { // Look inside each child as well. - BOOST_FOREACH(LLView* childp, mChildList) + for (LLView* childp : mChildList) { llassert(childp); LLView* viewp = childp->getChildView(name, recurse, FALSE); @@ -2220,7 +2283,7 @@ LLView* LLView::findSnapEdge(S32& new_edge_val, const LLCoordGL& mouse_dir, ESna } break; default: - llerrs << "Invalid snap edge" << llendl; + LL_ERRS() << "Invalid snap edge" << LL_ENDL; } } @@ -2322,7 +2385,7 @@ LLView* LLView::findSnapEdge(S32& new_edge_val, const LLCoordGL& mouse_dir, ESna } break; default: - llerrs << "Invalid snap edge" << llendl; + LL_ERRS() << "Invalid snap edge" << LL_ENDL; } } } @@ -2338,7 +2401,7 @@ LLView* LLView::findSnapEdge(S32& new_edge_val, const LLCoordGL& mouse_dir, ESna void LLView::registerEventListener(std::string name, LLSimpleListener* function) { mDispatchList.insert(std::pair(name, function)); - lldebugs << getName() << " registered " << name << llendl; + LL_DEBUGS() << getName() << " registered " << name << LL_ENDL; } @@ -2413,7 +2476,9 @@ LLControlVariable *LLView::findControl(const std::string& name) { return mParentView->findControl(name); } - return LLUI::sConfigGroup->getControl(name); + if (LLControlVariable* control = LLUI::sConfigGroup->getControl(name)) + return control; + return LLUI::sAccountGroup->getControl(name); } const S32 FLOATER_H_MARGIN = 15; @@ -2766,6 +2831,10 @@ void LLView::initFromXML(LLXMLNodePtr node, LLView* parent) node->getAttributeBOOL("mouse_opaque", mMouseOpaque); node->getAttributeS32("default_tab_group", mDefaultTabGroup); + if (node->hasAttribute("sound_flags")) + { + node->getAttributeU8("sound_flags", mSoundFlags); + } reshape(view_rect.getWidth(), view_rect.getHeight()); } @@ -2913,7 +2982,7 @@ bool LLView::setControlValue(const LLSD& value) std::string ctrlname = getControlName(); if (!ctrlname.empty()) { - LLUI::sConfigGroup->setUntypedValue(ctrlname, value); + LLUI::getControlControlGroup(ctrlname).setUntypedValue(ctrlname, value); return true; } return false; @@ -2929,7 +2998,7 @@ void LLView::setControlName(const std::string& control_name, LLView *context) if (!mControlName.empty()) { - llwarns << "setControlName called twice on same control!" << llendl; + LL_WARNS() << "setControlName called twice on same control!" << LL_ENDL; mControlConnection.disconnect(); // disconnect current signal mControlName.clear(); } @@ -3008,7 +3077,7 @@ S32 LLView::notifyParent(const LLSD& info) bool LLView::notifyChildren(const LLSD& info) { bool ret = false; - BOOST_FOREACH(LLView* childp, mChildList) + for (LLView* childp : mChildList) { ret = ret || childp->notifyChildren(info); } diff --git a/indra/llui/llview.h b/indra/llui/llview.h index b009bab41d..7cfce62c4e 100644 --- a/indra/llui/llview.h +++ b/indra/llui/llview.h @@ -57,7 +57,7 @@ #include "llinitparam.h" #include "lltreeiterators.h" #include "llfocusmgr.h" -#include +#include // #include "ailist.h" const U32 FOLLOWS_NONE = 0x00; @@ -122,7 +122,7 @@ class LLRegisterWidget if (registry->isTagRegistered(tag)) { //error! - llerrs << "Widget named " << tag << " already registered!" << llendl; + LL_ERRS() << "Widget named " << tag << " already registered!" << LL_ENDL; } else { @@ -235,7 +235,7 @@ class LLView private: // widgets in general are not copyable - LLView(const LLView& other) {}; + LLView(const LLView& other) = delete; public: #if LL_DEBUG static BOOL sIsDrawing; @@ -357,6 +357,11 @@ class LLView BOOL focusNextRoot(); BOOL focusPrevRoot(); + // Normally we want the app menus to get priority on accelerated keys + // However, sometimes we want to give specific views a first chance + // at handling them. (eg. the script editor) + virtual bool hasAccelerators() const { return false; } + virtual void deleteAllChildren(); virtual void setTentative(BOOL b); @@ -447,6 +452,7 @@ class LLView // inherited from LLFocusableElement /* virtual */ BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); + /* virtual */ BOOL handleKeyUp(KEY key, MASK mask, BOOL called_from_parent); /* virtual */ BOOL handleUnicodeChar(llwchar uni_char, BOOL called_from_parent); virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, @@ -512,7 +518,7 @@ class LLView const child_list_t* getChildList() const { return &mChildList; } child_list_const_iter_t beginChild() const { return mChildList.begin(); } child_list_const_iter_t endChild() const { return mChildList.end(); } - boost::unordered_map mChildHashMap; + boost::container::flat_map mChildHashMap; // // LLMouseHandler functions // Default behavior is to pass events to children @@ -552,7 +558,7 @@ class LLView // did we find *something* with that name? if (child) { - llwarns << "Found child named " << name << " but of wrong type " << typeid(child).name() << ", expecting " << typeid(T).name() << llendl; + LL_WARNS() << "Found child named " << name << " but of wrong type " << typeid(child).name() << ", expecting " << typeid(T).name() << LL_ENDL; } if (create_if_missing) { @@ -579,7 +585,7 @@ class LLView std::string xml_tag = LLWidgetClassRegistry::getInstance()->getTag(); if (xml_tag.empty()) { - llwarns << "No xml tag registered for this class " << llendl; + LL_WARNS() << "No xml tag registered for this class " << LL_ENDL; return NULL; } // create dummy xml node (" + // which equates to the following nesting: + // button + // param + // nested_param1 + // nested_param2 + // nested_param3 + mCurReadDepth++; + for(LLXMLNodePtr childp = nodep->getFirstChild(); childp.notNull();) + { + std::string child_name(childp->getName()->mString); + S32 num_tokens_pushed = 0; + + // for non "dotted" child nodes check to see if child node maps to another widget type + // and if not, treat as a child element of the current node + // e.g. will interpret as "button.rect" + // since there is no widget named "rect" + if (child_name.find('.') == std::string::npos) + { + mNameStack.push_back(std::make_pair(child_name, true)); + num_tokens_pushed++; + } + else + { + // parse out "dotted" name into individual tokens + tokenizer name_tokens(child_name, sep); + + tokenizer::iterator name_token_it = name_tokens.begin(); + if(name_token_it == name_tokens.end()) + { + childp = childp->getNextSibling(); + continue; + } + + // check for proper nesting + if (mNameStack.empty()) + { + if (*name_token_it != mRootNodeName) + { + childp = childp->getNextSibling(); + continue; + } + } + else if(mNameStack.back().first != *name_token_it) + { + childp = childp->getNextSibling(); + continue; + } + + // now ignore first token + ++name_token_it; + + // copy remaining tokens on to our running token list + for(tokenizer::iterator token_to_push = name_token_it; token_to_push != name_tokens.end(); ++token_to_push) + { + mNameStack.push_back(std::make_pair(*token_to_push, true)); + num_tokens_pushed++; + } + } + + // recurse and visit children XML nodes + if(readXUIImpl(childp, block)) + { + // child node successfully parsed, remove from DOM + + values_parsed = true; + LLXMLNodePtr node_to_remove = childp; + childp = childp->getNextSibling(); + + nodep->deleteChild(node_to_remove); + } + else + { + childp = childp->getNextSibling(); + } + + while(num_tokens_pushed-- > 0) + { + mNameStack.pop_back(); + } + } + mCurReadDepth--; + return values_parsed; +} + +bool LLXUIParser::readAttributes(LLXMLNodePtr nodep, LLInitParam::BaseBlock& block) +{ + typedef boost::tokenizer > tokenizer; + boost::char_separator sep("."); + + bool any_parsed = false; + bool silent = mCurReadDepth > 0; + + for(LLXMLAttribList::const_iterator attribute_it = nodep->mAttributes.begin(); + attribute_it != nodep->mAttributes.end(); + ++attribute_it) + { + S32 num_tokens_pushed = 0; + std::string attribute_name(attribute_it->first->mString); + mCurReadNode = attribute_it->second; + + tokenizer name_tokens(attribute_name, sep); + // copy remaining tokens on to our running token list + for(tokenizer::iterator token_to_push = name_tokens.begin(); token_to_push != name_tokens.end(); ++token_to_push) + { + mNameStack.push_back(std::make_pair(*token_to_push, true)); + num_tokens_pushed++; + } + + // child nodes are not necessarily valid attributes, so don't complain once we've recursed + any_parsed |= block.submitValue(mNameStack, *this, silent); + + while(num_tokens_pushed-- > 0) + { + mNameStack.pop_back(); + } + } + + return any_parsed; +} + +void LLXUIParser::writeXUIImpl(LLXMLNodePtr node, const LLInitParam::BaseBlock &block, const LLInitParam::predicate_rule_t rules, const LLInitParam::BaseBlock* diff_block) +{ + mWriteRootNode = node; + name_stack_t name_stack = Parser::name_stack_t(); + block.serializeBlock(*this, name_stack, rules, diff_block); + mOutNodes.clear(); +} + +// go from a stack of names to a specific XML node +LLXMLNodePtr LLXUIParser::getNode(name_stack_t& stack) +{ + LLXMLNodePtr out_node = mWriteRootNode; + + name_stack_t::iterator next_it = stack.begin(); + for (name_stack_t::iterator it = stack.begin(); + it != stack.end(); + it = next_it) + { + ++next_it; + bool force_new_node = false; + + if (it->first.empty()) + { + it->second = false; + continue; + } + + if (next_it != stack.end() && next_it->first.empty() && next_it->second) + { + force_new_node = true; + } + + + out_nodes_t::iterator found_it = mOutNodes.find(it->first); + + // node with this name not yet written + if (found_it == mOutNodes.end() || it->second || force_new_node) + { + // make an attribute if we are the last element on the name stack + bool is_attribute = next_it == stack.end(); + LLXMLNodePtr new_node = new LLXMLNode(it->first.c_str(), is_attribute); + out_node->addChild(new_node); + mOutNodes[it->first] = new_node; + out_node = new_node; + it->second = false; + } + else + { + out_node = found_it->second; + } + } + + return (out_node == mWriteRootNode ? LLXMLNodePtr(NULL) : out_node); +} + +bool LLXUIParser::readFlag(Parser& parser, void* val_ptr) +{ + LLXUIParser& self = static_cast(parser); + return self.mCurReadNode == DUMMY_NODE; +} + +bool LLXUIParser::writeFlag(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ + // just create node + LLXUIParser& self = static_cast(parser); + LLXMLNodePtr node = self.getNode(stack); + return node.notNull(); +} + +bool LLXUIParser::readBoolValue(Parser& parser, void* val_ptr) +{ + S32 value; + LLXUIParser& self = static_cast(parser); + bool success = self.mCurReadNode->getBoolValue(1, &value); + *((bool*)val_ptr) = (value != FALSE); + return success; +} + +bool LLXUIParser::writeBoolValue(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ + LLXUIParser& self = static_cast(parser); + LLXMLNodePtr node = self.getNode(stack); + if (node.notNull()) + { + node->setBoolValue(*((bool*)val_ptr)); + return true; + } + return false; +} + +bool LLXUIParser::readStringValue(Parser& parser, void* val_ptr) +{ + LLXUIParser& self = static_cast(parser); + *((std::string*)val_ptr) = self.mCurReadNode->getSanitizedValue(); + return true; +} + +bool LLXUIParser::writeStringValue(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ + LLXUIParser& self = static_cast(parser); + LLXMLNodePtr node = self.getNode(stack); + if (node.notNull()) + { + const std::string* string_val = reinterpret_cast(val_ptr); + if (string_val->find('\n') != std::string::npos + || string_val->size() > MAX_STRING_ATTRIBUTE_SIZE) + { + // don't write strings with newlines into attributes + std::string attribute_name = node->getName()->mString; + LLXMLNodePtr parent_node = node->mParent; + parent_node->deleteChild(node); + // write results in text contents of node + if (attribute_name == "value") + { + // "value" is implicit, just write to parent + node = parent_node; + } + else + { + // create a child that is not an attribute, but with same name + node = parent_node->createChild(attribute_name.c_str(), false); + } + } + node->setStringValue(*string_val); + return true; + } + return false; +} + +bool LLXUIParser::readU8Value(Parser& parser, void* val_ptr) +{ + LLXUIParser& self = static_cast(parser); + return self.mCurReadNode->getByteValue(1, (U8*)val_ptr); +} + +bool LLXUIParser::writeU8Value(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ + LLXUIParser& self = static_cast(parser); + LLXMLNodePtr node = self.getNode(stack); + if (node.notNull()) + { + node->setUnsignedValue(*((U8*)val_ptr)); + return true; + } + return false; +} + +bool LLXUIParser::readS8Value(Parser& parser, void* val_ptr) +{ + LLXUIParser& self = static_cast(parser); + S32 value; + if(self.mCurReadNode->getIntValue(1, &value)) + { + *((S8*)val_ptr) = value; + return true; + } + return false; +} + +bool LLXUIParser::writeS8Value(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ + LLXUIParser& self = static_cast(parser); + LLXMLNodePtr node = self.getNode(stack); + if (node.notNull()) + { + node->setIntValue(*((S8*)val_ptr)); + return true; + } + return false; +} + +bool LLXUIParser::readU16Value(Parser& parser, void* val_ptr) +{ + LLXUIParser& self = static_cast(parser); + U32 value; + if(self.mCurReadNode->getUnsignedValue(1, &value)) + { + *((U16*)val_ptr) = value; + return true; + } + return false; +} + +bool LLXUIParser::writeU16Value(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ + LLXUIParser& self = static_cast(parser); + LLXMLNodePtr node = self.getNode(stack); + if (node.notNull()) + { + node->setUnsignedValue(*((U16*)val_ptr)); + return true; + } + return false; +} + +bool LLXUIParser::readS16Value(Parser& parser, void* val_ptr) +{ + LLXUIParser& self = static_cast(parser); + S32 value; + if(self.mCurReadNode->getIntValue(1, &value)) + { + *((S16*)val_ptr) = value; + return true; + } + return false; +} + +bool LLXUIParser::writeS16Value(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ + LLXUIParser& self = static_cast(parser); + LLXMLNodePtr node = self.getNode(stack); + if (node.notNull()) + { + node->setIntValue(*((S16*)val_ptr)); + return true; + } + return false; +} + +bool LLXUIParser::readU32Value(Parser& parser, void* val_ptr) +{ + LLXUIParser& self = static_cast(parser); + return self.mCurReadNode->getUnsignedValue(1, (U32*)val_ptr); +} + +bool LLXUIParser::writeU32Value(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ + LLXUIParser& self = static_cast(parser); + LLXMLNodePtr node = self.getNode(stack); + if (node.notNull()) + { + node->setUnsignedValue(*((U32*)val_ptr)); + return true; + } + return false; +} + +bool LLXUIParser::readS32Value(Parser& parser, void* val_ptr) +{ + LLXUIParser& self = static_cast(parser); + return self.mCurReadNode->getIntValue(1, (S32*)val_ptr); +} + +bool LLXUIParser::writeS32Value(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ + LLXUIParser& self = static_cast(parser); + LLXMLNodePtr node = self.getNode(stack); + if (node.notNull()) + { + node->setIntValue(*((S32*)val_ptr)); + return true; + } + return false; +} + +bool LLXUIParser::readF32Value(Parser& parser, void* val_ptr) +{ + LLXUIParser& self = static_cast(parser); + return self.mCurReadNode->getFloatValue(1, (F32*)val_ptr); +} + +bool LLXUIParser::writeF32Value(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ + LLXUIParser& self = static_cast(parser); + LLXMLNodePtr node = self.getNode(stack); + if (node.notNull()) + { + node->setFloatValue(*((F32*)val_ptr)); + return true; + } + return false; +} + +bool LLXUIParser::readF64Value(Parser& parser, void* val_ptr) +{ + LLXUIParser& self = static_cast(parser); + return self.mCurReadNode->getDoubleValue(1, (F64*)val_ptr); +} + +bool LLXUIParser::writeF64Value(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ + LLXUIParser& self = static_cast(parser); + LLXMLNodePtr node = self.getNode(stack); + if (node.notNull()) + { + node->setDoubleValue(*((F64*)val_ptr)); + return true; + } + return false; +} + +bool LLXUIParser::readVector3Value(Parser& parser, void* val_ptr) +{ + LLXUIParser& self = static_cast(parser); + LLVector3* vecp = (LLVector3*)val_ptr; + if(self.mCurReadNode->getFloatValue(3, vecp->mV) >= 3) + { + return true; + } + + return false; +} + +bool LLXUIParser::writeVector3Value(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ + LLXUIParser& self = static_cast(parser); + LLXMLNodePtr node = self.getNode(stack); + if (node.notNull()) + { + LLVector3 vector = *((LLVector3*)val_ptr); + node->setFloatValue(3, vector.mV); + return true; + } + return false; +} + +bool LLXUIParser::readColor4Value(Parser& parser, void* val_ptr) +{ + LLXUIParser& self = static_cast(parser); + LLColor4* colorp = (LLColor4*)val_ptr; + if(self.mCurReadNode->getFloatValue(4, colorp->mV) >= 3) + { + return true; + } + + return false; +} + +bool LLXUIParser::writeColor4Value(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ + LLXUIParser& self = static_cast(parser); + LLXMLNodePtr node = self.getNode(stack); + if (node.notNull()) + { + LLColor4 color = *((LLColor4*)val_ptr); + node->setFloatValue(4, color.mV); + return true; + } + return false; +} + +bool LLXUIParser::readUIColorValue(Parser& parser, void* val_ptr) +{ + LLXUIParser& self = static_cast(parser); + LLUIColor* param = (LLUIColor*)val_ptr; + LLColor4 color; + bool success = self.mCurReadNode->getFloatValue(4, color.mV) >= 3; + if (success) + { + param->set(color); + return true; + } + return false; +} + +bool LLXUIParser::writeUIColorValue(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ + LLXUIParser& self = static_cast(parser); + LLXMLNodePtr node = self.getNode(stack); + if (node.notNull()) + { + LLUIColor color = *((LLUIColor*)val_ptr); + //RN: don't write out the color that is represented by a function + // rely on param block exporting to get the reference to the color settings + if (color.isReference()) return false; + node->setFloatValue(4, color.get().mV); + return true; + } + return false; +} + +bool LLXUIParser::readUUIDValue(Parser& parser, void* val_ptr) +{ + LLXUIParser& self = static_cast(parser); + LLUUID temp_id; + // LLUUID::set is destructive, so use temporary value + if (temp_id.set(self.mCurReadNode->getSanitizedValue())) + { + *(LLUUID*)(val_ptr) = temp_id; + return true; + } + return false; +} + +bool LLXUIParser::writeUUIDValue(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ + LLXUIParser& self = static_cast(parser); + LLXMLNodePtr node = self.getNode(stack); + if (node.notNull()) + { + node->setStringValue(((LLUUID*)val_ptr)->asString()); + return true; + } + return false; +} + +bool LLXUIParser::readSDValue(Parser& parser, void* val_ptr) +{ + LLXUIParser& self = static_cast(parser); + *((LLSD*)val_ptr) = LLSD(self.mCurReadNode->getSanitizedValue()); + return true; +} + +bool LLXUIParser::writeSDValue(Parser& parser, const void* val_ptr, name_stack_t& stack) +{ + LLXUIParser& self = static_cast(parser); + + LLXMLNodePtr node = self.getNode(stack); + if (node.notNull()) + { + std::string string_val = ((LLSD*)val_ptr)->asString(); + if (string_val.find('\n') != std::string::npos || string_val.size() > MAX_STRING_ATTRIBUTE_SIZE) + { + // don't write strings with newlines into attributes + std::string attribute_name = node->getName()->mString; + LLXMLNodePtr parent_node = node->mParent; + parent_node->deleteChild(node); + // write results in text contents of node + if (attribute_name == "value") + { + // "value" is implicit, just write to parent + node = parent_node; + } + else + { + node = parent_node->createChild(attribute_name.c_str(), false); + } + } + + node->setStringValue(string_val); + return true; + } + return false; +} + +/*virtual*/ std::string LLXUIParser::getCurrentElementName() +{ + std::string full_name; + for (name_stack_t::iterator it = mNameStack.begin(); + it != mNameStack.end(); + ++it) + { + full_name += it->first + "."; // build up dotted names: "button.param.nestedparam." + } + + return full_name; +} + +void LLXUIParser::parserWarning(const std::string& message) +{ +#ifdef LL_WINDOWS + // use Visual Studio friendly formatting of output message for easy access to originating xml + LL_INFOS() << llformat("%s(%d):\t%s", mCurFileName.c_str(), mCurReadNode->getLineNumber(), message.c_str()) << LL_ENDL; +#else + Parser::parserWarning(message); +#endif +} + +void LLXUIParser::parserError(const std::string& message) +{ +#ifdef LL_WINDOWS + // use Visual Studio friendly formatting of output message for easy access to originating xml + LL_INFOS() << llformat("%s(%d):\t%s", mCurFileName.c_str(), mCurReadNode->getLineNumber(), message.c_str()) << LL_ENDL; +#else + Parser::parserError(message); +#endif +} + + +// +// LLSimpleXUIParser +// + +struct ScopedFile +{ + ScopedFile( const std::string& filename, const char* accessmode ) + { + mFile = LLFile::fopen(filename, accessmode); + } + + ~ScopedFile() + { + fclose(mFile); + mFile = NULL; + } + + S32 getRemainingBytes() + { + if (!isOpen()) return 0; + + size_t cur_pos = ftell(mFile); + fseek(mFile, 0L, SEEK_END); + size_t file_size = ftell(mFile); + fseek(mFile, cur_pos, SEEK_SET); + return file_size - cur_pos; + } + + bool isOpen() { return mFile != NULL; } + + LLFILE* mFile; +}; +LLSimpleXUIParser::LLSimpleXUIParser(LLSimpleXUIParser::element_start_callback_t element_cb) +: Parser(sSimpleXUIReadFuncs, sSimpleXUIWriteFuncs, sSimpleXUIInspectFuncs), + mParser(nullptr), + mCurReadDepth(0), + mCurAttributeValueBegin(nullptr), + mElementCB(element_cb) +{ + if (sSimpleXUIReadFuncs.empty()) + { + registerParserFuncs(readFlag); + registerParserFuncs(readBoolValue); + registerParserFuncs(readStringValue); + registerParserFuncs(readU8Value); + registerParserFuncs(readS8Value); + registerParserFuncs(readU16Value); + registerParserFuncs(readS16Value); + registerParserFuncs(readU32Value); + registerParserFuncs(readS32Value); + registerParserFuncs(readF32Value); + registerParserFuncs(readF64Value); + registerParserFuncs(readColor4Value); + registerParserFuncs(readUIColorValue); + registerParserFuncs(readUUIDValue); + registerParserFuncs(readSDValue); + } +} + +LLSimpleXUIParser::~LLSimpleXUIParser() +{ +} + + +bool LLSimpleXUIParser::readXUI(const std::string& filename, LLInitParam::BaseBlock& block, bool silent) +{ + LL_RECORD_BLOCK_TIME(FTM_PARSE_XUI); + + mParser = XML_ParserCreate(NULL); + XML_SetUserData(mParser, this); + XML_SetElementHandler( mParser, startElementHandler, endElementHandler); + XML_SetCharacterDataHandler( mParser, characterDataHandler); + + mOutputStack.push_back(std::make_pair(&block, 0)); + mNameStack.clear(); + mCurFileName = filename; + mCurReadDepth = 0; + setParseSilently(silent); + + ScopedFile file(filename, "rb"); + if( !file.isOpen() ) + { + LL_WARNS("ReadXUI") << "Unable to open file " << filename << LL_ENDL; + XML_ParserFree( mParser ); + return false; + } + + S32 bytes_read = 0; + + S32 buffer_size = file.getRemainingBytes(); + void* buffer = XML_GetBuffer(mParser, buffer_size); + if( !buffer ) + { + LL_WARNS("ReadXUI") << "Unable to allocate XML buffer while reading file " << filename << LL_ENDL; + XML_ParserFree( mParser ); + return false; + } + + bytes_read = (S32)fread(buffer, 1, buffer_size, file.mFile); + if( bytes_read <= 0 ) + { + LL_WARNS("ReadXUI") << "Error while reading file " << filename << LL_ENDL; + XML_ParserFree( mParser ); + return false; + } + + mEmptyLeafNode.push_back(false); + + if( !XML_ParseBuffer(mParser, bytes_read, TRUE ) ) + { + LL_WARNS("ReadXUI") << "Error while parsing file " << filename << LL_ENDL; + XML_ParserFree( mParser ); + return false; + } + + mEmptyLeafNode.pop_back(); + + XML_ParserFree( mParser ); + return true; +} + +void LLSimpleXUIParser::startElementHandler(void *userData, const char *name, const char **atts) +{ + LLSimpleXUIParser* self = reinterpret_cast(userData); + self->startElement(name, atts); +} + +void LLSimpleXUIParser::endElementHandler(void *userData, const char *name) +{ + LLSimpleXUIParser* self = reinterpret_cast(userData); + self->endElement(name); +} + +void LLSimpleXUIParser::characterDataHandler(void *userData, const char *s, int len) +{ + LLSimpleXUIParser* self = reinterpret_cast(userData); + self->characterData(s, len); +} + +void LLSimpleXUIParser::characterData(const char *s, int len) +{ + mTextContents += std::string(s, len); +} + +void LLSimpleXUIParser::startElement(const char *name, const char **atts) +{ + processText(); + + typedef boost::tokenizer > tokenizer; + boost::char_separator sep("."); + + if (mElementCB) + { + LLInitParam::BaseBlock* blockp = mElementCB(*this, name); + if (blockp) + { + mOutputStack.push_back(std::make_pair(blockp, 0)); + } + } + + mOutputStack.back().second++; + S32 num_tokens_pushed = 0; + std::string child_name(name); + + if (mOutputStack.back().second == 1) + { // root node for this block + mScope.push_back(child_name); + } + else + { // compound attribute + if (child_name.find('.') == std::string::npos) + { + mNameStack.push_back(std::make_pair(child_name, true)); + num_tokens_pushed++; + mScope.push_back(child_name); + } + else + { + // parse out "dotted" name into individual tokens + tokenizer name_tokens(child_name, sep); + + tokenizer::iterator name_token_it = name_tokens.begin(); + if(name_token_it == name_tokens.end()) + { + return; + } + + // check for proper nesting + if(!mScope.empty() && *name_token_it != mScope.back()) + { + return; + } + + // now ignore first token + ++name_token_it; + + // copy remaining tokens on to our running token list + for(tokenizer::iterator token_to_push = name_token_it; token_to_push != name_tokens.end(); ++token_to_push) + { + mNameStack.push_back(std::make_pair(*token_to_push, true)); + num_tokens_pushed++; + } + mScope.push_back(mNameStack.back().first); + } + } + + // parent node is not empty + mEmptyLeafNode.back() = false; + // we are empty if we have no attributes + mEmptyLeafNode.push_back(atts[0] == NULL); + + mTokenSizeStack.push_back(num_tokens_pushed); + readAttributes(atts); + +} + +void LLSimpleXUIParser::endElement(const char *name) +{ + bool has_text = processText(); + + // no text, attributes, or children + if (!has_text && mEmptyLeafNode.back()) + { + // submit this as a valueless name (even though there might be text contents we haven't seen yet) + mCurAttributeValueBegin = NO_VALUE_MARKER; + mOutputStack.back().first->submitValue(mNameStack, *this, mParseSilently); + } + + if (--mOutputStack.back().second == 0) + { + if (mOutputStack.empty()) + { + LL_ERRS("ReadXUI") << "Parameter block output stack popped while empty." << LL_ENDL; + } + mOutputStack.pop_back(); + } + + S32 num_tokens_to_pop = mTokenSizeStack.back(); + mTokenSizeStack.pop_back(); + while(num_tokens_to_pop-- > 0) + { + mNameStack.pop_back(); + } + mScope.pop_back(); + mEmptyLeafNode.pop_back(); +} + +bool LLSimpleXUIParser::readAttributes(const char **atts) +{ + typedef boost::tokenizer > tokenizer; + boost::char_separator sep("."); + + bool any_parsed = false; + for(S32 i = 0; atts[i] && atts[i+1]; i += 2 ) + { + std::string attribute_name(atts[i]); + mCurAttributeValueBegin = atts[i+1]; + + S32 num_tokens_pushed = 0; + tokenizer name_tokens(attribute_name, sep); + // copy remaining tokens on to our running token list + for(tokenizer::iterator token_to_push = name_tokens.begin(); token_to_push != name_tokens.end(); ++token_to_push) + { + mNameStack.push_back(std::make_pair(*token_to_push, true)); + num_tokens_pushed++; + } + + // child nodes are not necessarily valid attributes, so don't complain once we've recursed + any_parsed |= mOutputStack.back().first->submitValue(mNameStack, *this, mParseSilently); + + while(num_tokens_pushed-- > 0) + { + mNameStack.pop_back(); + } + } + return any_parsed; +} + +bool LLSimpleXUIParser::processText() +{ + if (!mTextContents.empty()) + { + LLStringUtil::trim(mTextContents); + if (!mTextContents.empty()) + { + mNameStack.push_back(std::make_pair(std::string("value"), true)); + mCurAttributeValueBegin = mTextContents.c_str(); + mOutputStack.back().first->submitValue(mNameStack, *this, mParseSilently); + mNameStack.pop_back(); + } + mTextContents.clear(); + return true; + } + return false; +} + +/*virtual*/ std::string LLSimpleXUIParser::getCurrentElementName() +{ + std::string full_name; + for (name_stack_t::iterator it = mNameStack.begin(); + it != mNameStack.end(); + ++it) + { + full_name += it->first + "."; // build up dotted names: "button.param.nestedparam." + } + + return full_name; +} + +void LLSimpleXUIParser::parserWarning(const std::string& message) +{ +#ifdef LL_WINDOWS + // use Visual Studio friendly formatting of output message for easy access to originating xml + LL_INFOS() << llformat("%s(%d):\t%s", mCurFileName.c_str(), LINE_NUMBER_HERE, message.c_str()) << LL_ENDL; +#else + Parser::parserWarning(message); +#endif +} + +void LLSimpleXUIParser::parserError(const std::string& message) +{ +#ifdef LL_WINDOWS + // use Visual Studio friendly formatting of output message for easy access to originating xml + LL_INFOS() << llformat("%s(%d):\t%s", mCurFileName.c_str(), LINE_NUMBER_HERE, message.c_str()) << LL_ENDL; +#else + Parser::parserError(message); +#endif +} + +bool LLSimpleXUIParser::readFlag(Parser& parser, void* val_ptr) +{ + LLSimpleXUIParser& self = static_cast(parser); + return self.mCurAttributeValueBegin == NO_VALUE_MARKER; +} + +bool LLSimpleXUIParser::readBoolValue(Parser& parser, void* val_ptr) +{ + LLSimpleXUIParser& self = static_cast(parser); + if (!strcmp(self.mCurAttributeValueBegin, "true")) + { + *((bool*)val_ptr) = true; + return true; + } + else if (!strcmp(self.mCurAttributeValueBegin, "false")) + { + *((bool*)val_ptr) = false; + return true; + } + + return false; +} + +bool LLSimpleXUIParser::readStringValue(Parser& parser, void* val_ptr) +{ + LLSimpleXUIParser& self = static_cast(parser); + *((std::string*)val_ptr) = self.mCurAttributeValueBegin; + return true; +} + +bool LLSimpleXUIParser::readU8Value(Parser& parser, void* val_ptr) +{ + LLSimpleXUIParser& self = static_cast(parser); + return parse(self.mCurAttributeValueBegin, uint_p[assign_a(*(U8*)val_ptr)]).full; +} + +bool LLSimpleXUIParser::readS8Value(Parser& parser, void* val_ptr) +{ + LLSimpleXUIParser& self = static_cast(parser); + return parse(self.mCurAttributeValueBegin, int_p[assign_a(*(S8*)val_ptr)]).full; +} + +bool LLSimpleXUIParser::readU16Value(Parser& parser, void* val_ptr) +{ + LLSimpleXUIParser& self = static_cast(parser); + return parse(self.mCurAttributeValueBegin, uint_p[assign_a(*(U16*)val_ptr)]).full; +} + +bool LLSimpleXUIParser::readS16Value(Parser& parser, void* val_ptr) +{ + LLSimpleXUIParser& self = static_cast(parser); + return parse(self.mCurAttributeValueBegin, int_p[assign_a(*(S16*)val_ptr)]).full; +} + +bool LLSimpleXUIParser::readU32Value(Parser& parser, void* val_ptr) +{ + LLSimpleXUIParser& self = static_cast(parser); + return parse(self.mCurAttributeValueBegin, uint_p[assign_a(*(U32*)val_ptr)]).full; +} + +bool LLSimpleXUIParser::readS32Value(Parser& parser, void* val_ptr) +{ + LLSimpleXUIParser& self = static_cast(parser); + return parse(self.mCurAttributeValueBegin, int_p[assign_a(*(S32*)val_ptr)]).full; +} + +bool LLSimpleXUIParser::readF32Value(Parser& parser, void* val_ptr) +{ + LLSimpleXUIParser& self = static_cast(parser); + return parse(self.mCurAttributeValueBegin, real_p[assign_a(*(F32*)val_ptr)]).full; +} + +bool LLSimpleXUIParser::readF64Value(Parser& parser, void* val_ptr) +{ + LLSimpleXUIParser& self = static_cast(parser); + return parse(self.mCurAttributeValueBegin, real_p[assign_a(*(F64*)val_ptr)]).full; +} + +bool LLSimpleXUIParser::readColor4Value(Parser& parser, void* val_ptr) +{ + LLSimpleXUIParser& self = static_cast(parser); + LLColor4 value; + + if (parse(self.mCurAttributeValueBegin, real_p[assign_a(value.mV[0])] >> real_p[assign_a(value.mV[1])] >> real_p[assign_a(value.mV[2])] >> real_p[assign_a(value.mV[3])], space_p).full) + { + *(LLColor4*)(val_ptr) = value; + return true; + } + return false; +} + +bool LLSimpleXUIParser::readUIColorValue(Parser& parser, void* val_ptr) +{ + LLSimpleXUIParser& self = static_cast(parser); + LLColor4 value; + LLUIColor* colorp = (LLUIColor*)val_ptr; + + if (parse(self.mCurAttributeValueBegin, real_p[assign_a(value.mV[0])] >> real_p[assign_a(value.mV[1])] >> real_p[assign_a(value.mV[2])] >> real_p[assign_a(value.mV[3])], space_p).full) + { + colorp->set(value); + return true; + } + return false; +} + +bool LLSimpleXUIParser::readUUIDValue(Parser& parser, void* val_ptr) +{ + LLSimpleXUIParser& self = static_cast(parser); + LLUUID temp_id; + // LLUUID::set is destructive, so use temporary value + if (temp_id.set(std::string(self.mCurAttributeValueBegin))) + { + *(LLUUID*)(val_ptr) = temp_id; + return true; + } + return false; +} + +bool LLSimpleXUIParser::readSDValue(Parser& parser, void* val_ptr) +{ + LLSimpleXUIParser& self = static_cast(parser); + *((LLSD*)val_ptr) = LLSD(self.mCurAttributeValueBegin); + return true; +} diff --git a/indra/llui/llxuiparser.h b/indra/llui/llxuiparser.h new file mode 100644 index 0000000000..b24e07cc35 --- /dev/null +++ b/indra/llui/llxuiparser.h @@ -0,0 +1,255 @@ +/** + * @file llxuiparser.h + * @brief Utility functions for handling XUI structures in XML + * + * $LicenseInfo:firstyear=2003&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LLXUIPARSER_H +#define LLXUIPARSER_H + +#include "llinitparam.h" +#include "llregistry.h" +#include "llxmlnode.h" + +#include +#include +#include + +class LLView; + +// lookup widget type by name +class LLWidgetTypeRegistry +: public LLRegistrySingleton +{}; + + +// global static instance for registering all widget types +typedef boost::function LLWidgetCreatorFunc; + +typedef LLRegistry widget_registry_t; + +class LLChildRegistryRegistry +: public LLRegistrySingleton +{}; + +class LLXSDWriter : public LLInitParam::Parser +{ + LOG_CLASS(LLXSDWriter); +public: + void writeXSD(const std::string& name, LLXMLNodePtr node, const LLInitParam::BaseBlock& block, const std::string& xml_namespace); + + /*virtual*/ std::string getCurrentElementName() { return LLStringUtil::null; } + /*virtual*/ std::string getCurrentFileName() { return LLStringUtil::null; } + LLXSDWriter(); + ~LLXSDWriter(); + +protected: + void writeAttribute(const std::string& type, const Parser::name_stack_t&, S32 min_count, S32 max_count, const std::vector* possible_values); + void addAttributeToSchema(LLXMLNodePtr nodep, const std::string& attribute_name, const std::string& type, bool mandatory, const std::vector* possible_values); + LLXMLNodePtr mAttributeNode; + LLXMLNodePtr mElementNode; + LLXMLNodePtr mSchemaNode; + + typedef std::set string_set_t; + typedef std::map attributes_map_t; + attributes_map_t mAttributesWritten; +}; + + + +// NOTE: DOES NOT WORK YET +// should support child widgets for XUI +class LLXUIXSDWriter : public LLXSDWriter +{ +public: + void writeXSD(const std::string& name, const std::string& path, const LLInitParam::BaseBlock& block); +}; + + +class LLXUIParserImpl; + +class LLXUIParser : public LLInitParam::Parser +{ +LOG_CLASS(LLXUIParser); + +public: + LLXUIParser(); + typedef LLInitParam::Parser::name_stack_t name_stack_t; + + /*virtual*/ std::string getCurrentElementName(); + /*virtual*/ std::string getCurrentFileName() { return mCurFileName; } + /*virtual*/ void parserWarning(const std::string& message); + /*virtual*/ void parserError(const std::string& message); + + void readXUI(LLXMLNodePtr node, LLInitParam::BaseBlock& block, const std::string& filename = LLStringUtil::null, bool silent=false); + template + void writeXUI(LLXMLNodePtr node, + const BLOCK& block, + const LLInitParam::predicate_rule_t rules = LLInitParam::default_parse_rules(), + const LLInitParam::BaseBlock* diff_block = NULL) + { + if (!diff_block + && !rules.isAmbivalent(LLInitParam::HAS_DEFAULT_VALUE)) + { + diff_block = &LLInitParam::defaultValue(); + } + writeXUIImpl(node, block, rules, diff_block); + } + +private: + LLXUIParser(const LLXUIParser& other); // no-copy + void writeXUIImpl(LLXMLNodePtr node, + const LLInitParam::BaseBlock& block, + const LLInitParam::predicate_rule_t rules, + const LLInitParam::BaseBlock* diff_block); + bool readXUIImpl(LLXMLNodePtr node, LLInitParam::BaseBlock& block); + bool readAttributes(LLXMLNodePtr nodep, LLInitParam::BaseBlock& block); + + //reader helper functions + static bool readFlag(Parser& parser, void* val_ptr); + static bool readBoolValue(Parser& parser, void* val_ptr); + static bool readStringValue(Parser& parser, void* val_ptr); + static bool readU8Value(Parser& parser, void* val_ptr); + static bool readS8Value(Parser& parser, void* val_ptr); + static bool readU16Value(Parser& parser, void* val_ptr); + static bool readS16Value(Parser& parser, void* val_ptr); + static bool readU32Value(Parser& parser, void* val_ptr); + static bool readS32Value(Parser& parser, void* val_ptr); + static bool readF32Value(Parser& parser, void* val_ptr); + static bool readF64Value(Parser& parser, void* val_ptr); + static bool readVector3Value(Parser& parser, void* val_ptr); + static bool readColor4Value(Parser& parser, void* val_ptr); + static bool readUIColorValue(Parser& parser, void* val_ptr); + static bool readUUIDValue(Parser& parser, void* val_ptr); + static bool readSDValue(Parser& parser, void* val_ptr); + + //writer helper functions + static bool writeFlag(Parser& parser, const void* val_ptr, name_stack_t&); + static bool writeBoolValue(Parser& parser, const void* val_ptr, name_stack_t&); + static bool writeStringValue(Parser& parser, const void* val_ptr, name_stack_t&); + static bool writeU8Value(Parser& parser, const void* val_ptr, name_stack_t&); + static bool writeS8Value(Parser& parser, const void* val_ptr, name_stack_t&); + static bool writeU16Value(Parser& parser, const void* val_ptr, name_stack_t&); + static bool writeS16Value(Parser& parser, const void* val_ptr, name_stack_t&); + static bool writeU32Value(Parser& parser, const void* val_ptr, name_stack_t&); + static bool writeS32Value(Parser& parser, const void* val_ptr, name_stack_t&); + static bool writeF32Value(Parser& parser, const void* val_ptr, name_stack_t&); + static bool writeF64Value(Parser& parser, const void* val_ptr, name_stack_t&); + static bool writeVector3Value(Parser& parser, const void* val_ptr, name_stack_t&); + static bool writeColor4Value(Parser& parser, const void* val_ptr, name_stack_t&); + static bool writeUIColorValue(Parser& parser, const void* val_ptr, name_stack_t&); + static bool writeUUIDValue(Parser& parser, const void* val_ptr, name_stack_t&); + static bool writeSDValue(Parser& parser, const void* val_ptr, name_stack_t&); + + LLXMLNodePtr getNode(name_stack_t& stack); + +private: + Parser::name_stack_t mNameStack; + LLXMLNodePtr mCurReadNode; + // Root of the widget XML sub-tree, for example, "line_editor" + LLXMLNodePtr mWriteRootNode; + + typedef std::map out_nodes_t; + out_nodes_t mOutNodes; + LLXMLNodePtr mLastWrittenChild; + S32 mCurReadDepth; + std::string mCurFileName; + std::string mRootNodeName; +}; + +// LLSimpleXUIParser is a streamlined SAX-based XUI parser that does not support localization +// or parsing of a tree of independent param blocks, such as child widgets. +// Use this for reading non-localized files that only need a single param block as a result. +// +// NOTE: In order to support nested block parsing, we need callbacks for start element that +// push new blocks contexts on the mScope stack. +// NOTE: To support localization without building a DOM, we need to enforce consistent +// ordering of child elements from base file to localized diff file. Then we can use a pair +// of coroutines to perform matching of xml nodes during parsing. Not sure if the overhead +// of coroutines would offset the gain from SAX parsing +class LLSimpleXUIParserImpl; + +class LLSimpleXUIParser : public LLInitParam::Parser +{ +LOG_CLASS(LLSimpleXUIParser); +public: + typedef LLInitParam::Parser::name_stack_t name_stack_t; + typedef LLInitParam::BaseBlock* (*element_start_callback_t)(LLSimpleXUIParser&, const char* block_name); + + LLSimpleXUIParser(element_start_callback_t element_cb = nullptr); + virtual ~LLSimpleXUIParser(); + + /*virtual*/ std::string getCurrentElementName(); + /*virtual*/ std::string getCurrentFileName() { return mCurFileName; } + /*virtual*/ void parserWarning(const std::string& message); + /*virtual*/ void parserError(const std::string& message); + + bool readXUI(const std::string& filename, LLInitParam::BaseBlock& block, bool silent=false); + + +private: + //reader helper functions + static bool readFlag(Parser&, void* val_ptr); + static bool readBoolValue(Parser&, void* val_ptr); + static bool readStringValue(Parser&, void* val_ptr); + static bool readU8Value(Parser&, void* val_ptr); + static bool readS8Value(Parser&, void* val_ptr); + static bool readU16Value(Parser&, void* val_ptr); + static bool readS16Value(Parser&, void* val_ptr); + static bool readU32Value(Parser&, void* val_ptr); + static bool readS32Value(Parser&, void* val_ptr); + static bool readF32Value(Parser&, void* val_ptr); + static bool readF64Value(Parser&, void* val_ptr); + static bool readColor4Value(Parser&, void* val_ptr); + static bool readUIColorValue(Parser&, void* val_ptr); + static bool readUUIDValue(Parser&, void* val_ptr); + static bool readSDValue(Parser&, void* val_ptr); + +private: + static void startElementHandler(void *userData, const char *name, const char **atts); + static void endElementHandler(void *userData, const char *name); + static void characterDataHandler(void *userData, const char *s, int len); + + void startElement(const char *name, const char **atts); + void endElement(const char *name); + void characterData(const char *s, int len); + bool readAttributes(const char **atts); + bool processText(); + + Parser::name_stack_t mNameStack; + struct XML_ParserStruct* mParser; + LLXMLNodePtr mLastWrittenChild; + S32 mCurReadDepth; + std::string mCurFileName; + std::string mTextContents; + const char* mCurAttributeValueBegin; + std::vector mTokenSizeStack; + std::vector mScope; + std::vector mEmptyLeafNode; + element_start_callback_t mElementCB; + + std::vector > mOutputStack; +}; + + +#endif //LLXUIPARSER_H diff --git a/indra/llvfs/CMakeLists.txt b/indra/llvfs/CMakeLists.txt index ca491529b1..aa60e08ddd 100644 --- a/indra/llvfs/CMakeLists.txt +++ b/indra/llvfs/CMakeLists.txt @@ -60,9 +60,10 @@ set_source_files_properties(${llvfs_HEADER_FILES} list(APPEND llvfs_SOURCE_FILES ${llvfs_HEADER_FILES}) add_library (llvfs ${llvfs_SOURCE_FILES}) -add_dependencies(llvfs prepare) target_link_libraries(llvfs + PUBLIC + llcommon ${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY} ) diff --git a/indra/llvfs/lldir.cpp b/indra/llvfs/lldir.cpp index d2d5fa5857..84b173c3f1 100644 --- a/indra/llvfs/lldir.cpp +++ b/indra/llvfs/lldir.cpp @@ -1,3 +1,4 @@ + /** * @file lldir.cpp * @brief implementation of directory utilities base class @@ -42,6 +43,7 @@ #include "lldiriterator.h" #include "stringize.h" +#include #include #include #include @@ -69,6 +71,15 @@ LLDir_Linux gDirUtil; LLDir *gDirUtilp = (LLDir *)&gDirUtil; +/// Values for findSkinnedFilenames(subdir) parameter +const char + *LLDir::XUI = "xui", + *LLDir::TEXTURES = "textures", + *LLDir::SKINBASE = ""; + +static const char* const empty = ""; +std::string LLDir::sDumpDir = ""; + LLDir::LLDir() : mAppName(""), mExecutablePathAndName(""), @@ -81,7 +92,9 @@ LLDir::LLDir() mOSCacheDir(""), mCAFile(""), mTempDir(""), - mDirDelimiter("/") // fallback to forward slash if not overridden + mDirDelimiter("/"), // fallback to forward slash if not overridden + mLanguage("en"), + mUserName("undefined") { } @@ -89,7 +102,36 @@ LLDir::~LLDir() { } - +std::vector LLDir::getFilesInDir(const std::string &dirname) +{ + //Returns a vector of fullpath filenames. + +#if LL_WINDOWS + boost::filesystem::path p (utf8str_to_utf16str(dirname).c_str()); +#else + boost::filesystem::path p (dirname); +#endif + std::vector v; + + if (exists(p)) + { + if (is_directory(p)) + { + boost::filesystem::directory_iterator end_iter; + for (boost::filesystem::directory_iterator dir_itr(p); + dir_itr != end_iter; + ++dir_itr) + { + if (boost::filesystem::is_regular_file(dir_itr->status())) + { + v.push_back(dir_itr->path().filename().string()); + } + } + } + } + return v; +} + S32 LLDir::deleteFilesInDir(const std::string &dirname, const std::string &mask) { S32 count = 0; @@ -100,54 +142,94 @@ S32 LLDir::deleteFilesInDir(const std::string &dirname, const std::string &mask) // File masks starting with "/" will match nothing, so we consider them invalid. if (LLStringUtil::startsWith(mask, getDirDelimiter())) { - llwarns << "Invalid file mask: " << mask << llendl; + LL_WARNS() << "Invalid file mask: " << mask << LL_ENDL; llassert(!"Invalid file mask"); } - LLDirIterator iter(dirname, mask); - while (iter.next(filename)) + try { - fullpath = add(dirname, filename); - - if(LLFile::isdir(fullpath)) + LLDirIterator iter(dirname, mask); + while (iter.next(filename)) { - // skipping directory traversal filenames - count++; - continue; - } + fullpath = add(dirname, filename); - S32 retry_count = 0; - while (retry_count < 5) - { - if (0 != LLFile::remove(fullpath)) + if(LLFile::isdir(fullpath)) { - retry_count++; - result = errno; - llwarns << "Problem removing " << fullpath << " - errorcode: " - << result << " attempt " << retry_count << llendl; - - if(retry_count >= 5) - { - llwarns << "Failed to remove " << fullpath << llendl ; - return count ; - } - - ms_sleep(100); + // skipping directory traversal filenames + count++; + continue; } - else + + S32 retry_count = 0; + while (retry_count < 5) { - if (retry_count) + if (0 != LLFile::remove(fullpath)) { - llwarns << "Successfully removed " << fullpath << llendl; + retry_count++; + result = errno; + LL_WARNS() << "Problem removing " << fullpath << " - errorcode: " + << result << " attempt " << retry_count << LL_ENDL; + + if(retry_count >= 5) + { + LL_WARNS() << "Failed to remove " << fullpath << LL_ENDL ; + return count ; + } + + ms_sleep(100); } - break; - } + else + { + if (retry_count) + { + LL_WARNS() << "Successfully removed " << fullpath << LL_ENDL; + } + break; + } + } + count++; } - count++; } + catch(...) + { + LL_WARNS() << "Unable to remove some files from " + dirname << LL_ENDL; + } + return count; } +U32 LLDir::deleteDirAndContents(const std::string& dir_name) +{ + //Removes the directory and its contents. Returns number of files removed. + + U32 num_deleted = 0; + + try + { +#if LL_WINDOWS + boost::filesystem::path dir_path(utf8str_to_utf16str(dir_name).c_str()); +#else + boost::filesystem::path dir_path(dir_name); +#endif + if (boost::filesystem::exists (dir_path)) + { + if (!boost::filesystem::is_empty (dir_path)) + { // Directory has content + num_deleted = boost::filesystem::remove_all (dir_path); + } + else + { // Directory is empty + boost::filesystem::remove (dir_path); + } + } + } + catch (boost::filesystem::filesystem_error &er) + { + LL_WARNS() << "Failed to delete " << dir_name << " with error " << er.code().message() << LL_ENDL; + } + return num_deleted; +} + const std::string LLDir::findFile(const std::string &filename, const std::string& searchPath1, const std::string& searchPath2, @@ -235,6 +317,34 @@ const std::string &LLDir::getChatLogsDir() const return mChatLogsDir; } +void LLDir::setDumpDir( const std::string& path ) +{ + LLDir::sDumpDir = path; + if (! sDumpDir.empty() && sDumpDir.rbegin() == mDirDelimiter.rbegin() ) + { + sDumpDir.erase(sDumpDir.size() -1); + } +} + +const std::string &LLDir::getDumpDir() const +{ + if (sDumpDir.empty() ) + { + /* Singu Note: don't generate a different dump dir each time + LLUUID uid; + uid.generate(); + + sDumpDir = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "") + + "dump-" + uid.asString(); + */ + + sDumpDir = getExpandedFilename(LL_PATH_LOGS, "") + "singularity-debug"; + dir_exists_or_crash(sDumpDir); + } + + return LLDir::sDumpDir; +} + const std::string &LLDir::getPerAccountChatLogsDir() const { return mPerAccountChatLogsDir; @@ -263,6 +373,12 @@ const std::string LLDir::getCacheDir(bool get_default) const } } +#if (defined(_WIN64) || defined(__amd64__) || defined(__x86_64__)) +#define OS_CACHE_DIR "SingularityViewer64" +#else +#define OS_CACHE_DIR "SingularityViewer" +#endif + // Return the default cache directory std::string LLDir::buildSLOSCacheDir() const { @@ -280,7 +396,7 @@ std::string LLDir::buildSLOSCacheDir() const } else { - res = add(getOSCacheDir(), "SingularityViewer"); + res = add(getOSCacheDir(), OS_CACHE_DIR); } return res; } @@ -303,21 +419,27 @@ const std::string &LLDir::getDirDelimiter() const return mDirDelimiter; } +const std::string& LLDir::getDefaultSkinDir() const +{ + return mDefaultSkinDir; +} + const std::string &LLDir::getSkinDir() const { return mSkinDir; } -const std::string &LLDir::getUserSkinDir() const +const std::string& LLDir::getUserDefaultSkinDir() const { - return mUserSkinDir; + return mUserDefaultSkinDir; } -const std::string& LLDir::getDefaultSkinDir() const +const std::string &LLDir::getUserSkinDir() const { - return mDefaultSkinDir; + return mUserSkinDir; } + const std::string LLDir::getSkinBaseDir() const { return mSkinBaseDir; @@ -328,6 +450,11 @@ const std::string &LLDir::getLLPluginDir() const return mLLPluginDir; } +const std::string &LLDir::getUserName() const +{ + return mUserName; +} + static std::string ELLPathToString(ELLPath location) { typedef std::map ELLPathMap; @@ -396,12 +523,29 @@ std::string LLDir::getExpandedFilename(ELLPath location, const std::string& subd prefix = getCacheDir(); break; + case LL_PATH_DUMP: + prefix=getDumpDir(); + break; + case LL_PATH_USER_SETTINGS: prefix = add(getOSUserAppDir(), "user_settings"); break; case LL_PATH_PER_SL_ACCOUNT: prefix = getLindenUserDir(); + if (prefix.empty()) + { + // if we're asking for the per-SL-account directory but we haven't + // logged in yet (or otherwise don't know the account name from + // which to build this string), then intentionally return a blank + // string to the caller and skip the below warning about a blank + // prefix. + LL_DEBUGS("LLDir") << "getLindenUserDir() not yet set: " + << ELLPathToString(location) + << ", '" << subdir1 << "', '" << subdir2 << "', '" << in_filename + << "' => ''" << LL_ENDL; + return std::string(); + } break; case LL_PATH_CHAT_LOGS: @@ -454,9 +598,9 @@ std::string LLDir::getExpandedFilename(ELLPath location, const std::string& subd if (prefix.empty()) { - llwarns << ELLPathToString(location) + LL_WARNS() << ELLPathToString(location) << ", '" << subdir1 << "', '" << subdir2 << "', '" << in_filename - << "': prefix is empty, possible bad filename" << llendl; + << "': prefix is empty, possible bad filename" << LL_ENDL; } std::string expanded_filename = add(add(prefix, subdir1), subdir2); @@ -498,7 +642,7 @@ std::string LLDir::getBaseFileName(const std::string& filepath, bool strip_exten std::string LLDir::getDirName(const std::string& filepath) const { std::size_t offset = filepath.find_last_of(getDirDelimiter()); - S32 len = (offset == std::string::npos) ? 0 : offset; + size_t len = (offset == std::string::npos) ? 0 : offset; std::string dirname = filepath.substr(0, len); return dirname; } @@ -514,31 +658,214 @@ std::string LLDir::getExtension(const std::string& filepath) const return exten; } -std::string LLDir::findSkinnedFilename(const std::string &filename) const +std::string LLDir::findSkinnedFilenameBaseLang(const std::string &subdir, + const std::string &filename, + ESkinConstraint constraint) const { - return findSkinnedFilename("", "", filename); + // This implementation is basically just as described in the declaration comments. + std::vector found(findSkinnedFilenames(subdir, filename, constraint)); + if (found.empty()) + { + return ""; + } + return found.front(); } -std::string LLDir::findSkinnedFilename(const std::string &subdir, const std::string &filename) const +std::string LLDir::findSkinnedFilename(const std::string &subdir, + const std::string &filename, + ESkinConstraint constraint) const { - return findSkinnedFilename("", subdir, filename); + // This implementation is basically just as described in the declaration comments. + std::vector found(findSkinnedFilenames(subdir, filename, constraint)); + if (found.empty()) + { + return ""; + } + return found.back(); } -std::string LLDir::findSkinnedFilename(const std::string &subdir1, const std::string &subdir2, const std::string &filename) const +// This method exists because the two code paths for +// findSkinnedFilenames(ALL_SKINS) and findSkinnedFilenames(CURRENT_SKIN) must +// generate the list of candidate pathnames in identical ways. The only +// difference is in the body of the inner loop. +template +void LLDir::walkSearchSkinDirs(const std::string& subdir, + const std::vector& subsubdirs, + const std::string& filename, + const FUNCTION& function) const { - // generate subdirectory path fragment, e.g. "/foo/bar", "/foo", "" - std::string subdirs = ((subdir1.empty() ? "" : mDirDelimiter) + subdir1) - + ((subdir2.empty() ? "" : mDirDelimiter) + subdir2); + BOOST_FOREACH(std::string skindir, mSearchSkinDirs) + { + std::string subdir_path(add(skindir, subdir)); + BOOST_FOREACH(std::string subsubdir, subsubdirs) + { + std::string full_path(add(add(subdir_path, subsubdir), filename)); + if (fileExists(full_path)) + { + function(subsubdir, full_path); + } + } + } +} - std::vector search_paths; - - search_paths.push_back(getUserSkinDir() + subdirs); // first look in user skin override - search_paths.push_back(getSkinDir() + subdirs); // then in current skin - search_paths.push_back(getDefaultSkinDir() + subdirs); // then default skin - search_paths.push_back(getCacheDir() + subdirs); // and last in preload directory +// ridiculous little helper function that should go away when we can use lambda +inline void push_back(std::vector& vector, const std::string& value) +{ + vector.push_back(value); +} + +typedef std::map StringMap; +// ridiculous little helper function that should go away when we can use lambda +inline void store_in_map(StringMap& map, const std::string& key, const std::string& value) +{ + map[key] = value; +} + +std::vector LLDir::findSkinnedFilenames(const std::string& subdir, + const std::string& filename, + ESkinConstraint constraint) const +{ + // Recognize subdirs that have no localization. + static const std::set sUnlocalized = list_of + ("") // top-level directory not localized + ("textures") // textures not localized + ; + + LL_DEBUGS("LLDir") << "subdir '" << subdir << "', filename '" << filename + << "', constraint " + << ((constraint == CURRENT_SKIN)? "CURRENT_SKIN" : "ALL_SKINS") + << LL_ENDL; + + // Build results vector. + std::vector results; + // Disallow filenames that may escape subdir + if (filename.find("..") != std::string::npos) + { + LL_WARNS("LLDir") << "Ignoring potentially relative filename '" << filename << "'" << LL_ENDL; + return results; + } + + // Cache the default language directory for each subdir we've encountered. + // A cache entry whose value is the empty string means "not localized, + // don't bother checking again." + static StringMap sLocalized; + + // Check whether we've already discovered if this subdir is localized. + StringMap::const_iterator found = sLocalized.find(subdir); + if (found == sLocalized.end()) + { + // We have not yet determined that. Is it one of the subdirs "known" + // to be unlocalized? + if (sUnlocalized.find(subdir) != sUnlocalized.end()) + { + // This subdir is known to be unlocalized. Remember that. + found = sLocalized.insert(StringMap::value_type(subdir, "")).first; + } + else + { + // We do not recognize this subdir. Investigate. + std::string subdir_path(add(getDefaultSkinDir(), subdir)); + if (fileExists(add(subdir_path, "en"))) + { + // defaultSkinDir/subdir contains subdir "en". That's our + // default language; this subdir is localized. + found = sLocalized.insert(StringMap::value_type(subdir, "en")).first; + } + else if (fileExists(add(subdir_path, "en-us"))) + { + // defaultSkinDir/subdir contains subdir "en-us" but not "en". + // Set as default language; this subdir is localized. + found = sLocalized.insert(StringMap::value_type(subdir, "en-us")).first; + } + else + { + // defaultSkinDir/subdir contains neither "en" nor "en-us". + // Assume it's not localized. Remember that assumption. + found = sLocalized.insert(StringMap::value_type(subdir, "")).first; + } + } + } + // Every code path above should have resulted in 'found' becoming a valid + // iterator to an entry in sLocalized. + llassert(found != sLocalized.end()); + + // Now -- is this subdir localized, or not? The answer determines what + // subdirectories we check (under subdir) for the requested filename. + std::vector subsubdirs; + if (found->second.empty()) + { + // subdir is not localized. filename should be located directly within it. + subsubdirs.push_back(""); + } + else + { + // subdir is localized, and found->second is the default language + // directory within it. Check both the default language and the + // current language -- if it differs from the default, of course. + subsubdirs.push_back(found->second); + if (mLanguage != found->second) + { + subsubdirs.push_back(mLanguage); + } + } + + // The process we use depends on 'constraint'. + if (constraint != CURRENT_SKIN) // meaning ALL_SKINS + { + // ALL_SKINS is simpler: just return every pathname generated by + // walkSearchSkinDirs(). Tricky bit: walkSearchSkinDirs() passes its + // FUNCTION the subsubdir as well as the full pathname. We just want + // the full pathname. + walkSearchSkinDirs(subdir, subsubdirs, filename, + boost::bind(push_back, boost::ref(results), _2)); + } + else // CURRENT_SKIN + { + // CURRENT_SKIN turns out to be a bit of a misnomer because we might + // still return files from two different skins. In any case, this + // value of 'constraint' means we will return at most two paths: one + // for the default language, one for the current language (supposing + // those differ). + // It is important to allow a user to override only the localization + // for a particular file, for all viewer installs, without also + // overriding the default-language file. + // It is important to allow a user to override only the default- + // language file, for all viewer installs, without also overriding the + // applicable localization of that file. + // Therefore, treat the default language and the current language as + // two separate cases. For each, capture the most-specialized file + // that exists. + // Use a map keyed by subsubdir (i.e. language code). This allows us + // to handle the case of a single subsubdirs entry with the same logic + // that handles two. For every real file path generated by + // walkSearchSkinDirs(), update the map entry for its subsubdir. + StringMap path_for; + walkSearchSkinDirs(subdir, subsubdirs, filename, + boost::bind(store_in_map, boost::ref(path_for), _1, _2)); + // Now that we have a path for each of the default language and the + // current language, copy them -- in proper order -- into results. + // Don't drive this by walking the map itself: it matters that we + // generate results in the same order as subsubdirs. + BOOST_FOREACH(std::string subsubdir, subsubdirs) + { + StringMap::const_iterator found(path_for.find(subsubdir)); + if (found != path_for.end()) + { + results.push_back(found->second); + } + } + } - std::string found_file = findFile(filename, search_paths); - return found_file; + LL_DEBUGS("LLDir") << empty; + const char* comma = ""; + BOOST_FOREACH(std::string path, results) + { + LL_CONT << comma << "'" << path << "'"; + comma = ", "; + } + LL_CONT << LL_ENDL; + + return results; } std::string LLDir::getTempFilename() const @@ -553,7 +880,7 @@ std::string LLDir::getTempFilename() const } // static -std::string LLDir::getScrubbedFileName(const std::string uncleanFileName) +std::string LLDir::getScrubbedFileName(const std::string& uncleanFileName) { std::string name(uncleanFileName); std::string illegalChars(getForbiddenFileChars()); @@ -564,8 +891,8 @@ std::string LLDir::getScrubbedFileName(const std::string uncleanFileName) // replace any illegal file chars with and underscore '_' for( unsigned int i = 0; i < illegalChars.length(); i++ ) { - int j = -1; - while((j = name.find(illegalChars[i])) > -1) + size_t j = std::string::npos; + while ((j = name.find(illegalChars[i])) != std::string::npos) { name[j] = '_'; } @@ -579,6 +906,19 @@ std::string LLDir::getForbiddenFileChars() return "\\/:*?\"<>|"; } +// static +std::string LLDir::getGridSpecificDir( const std::string& in, const std::string& grid ) +{ + std::string ret = in; + if (!grid.empty()) + { + std::string gridlower(grid); + LLStringUtil::toLower(gridlower); + ret += '@' + gridlower; + } + return ret; +} + void LLDir::setLindenUserDir(const std::string &grid, const std::string &first, const std::string &last) { // if both first and last aren't set, assume we're grabbing the cached dir @@ -588,25 +928,44 @@ void LLDir::setLindenUserDir(const std::string &grid, const std::string &first, // utterly consistent with our firstname/lastname case. std::string userlower(first+"_"+last); LLStringUtil::toLower(userlower); - mLindenUserDir = add(getOSUserAppDir(), userlower); - - if (!grid.empty()) - { - std::string gridlower(grid); - LLStringUtil::toLower(gridlower); - mLindenUserDir += "@"; - mLindenUserDir += gridlower; - } + mLindenUserDir = getGridSpecificDir(add(getOSUserAppDir(), userlower), grid); } else { - llerrs << "Invalid name for LLDir::setLindenUserDir" << llendl; + LL_ERRS() << "Invalid name for LLDir::setLindenUserDir" << LL_ENDL; } dumpCurrentDirectories(); } -void LLDir::setChatLogsDir(const std::string &path) +void LLDir::makePortable() +{ + std::string dir = mExecutableDir; + dir.erase(dir.rfind(mDirDelimiter)); // Go one level up + dir += mDirDelimiter + "portable_viewer"; + if (LLFile::mkdir(dir) == -1) + { + if (errno != EEXIST) + { + LL_WARNS() << "Couldn't create portable_viewer directory." << LL_ENDL; + return; // Failed, don't mess anything up. + } + } + mOSUserDir = dir + mDirDelimiter + "settings"; + mOSCacheDir = dir + mDirDelimiter + "cache"; + if (LLFile::mkdir(mOSUserDir) == -1 || LLFile::mkdir(mOSCacheDir) == -1) + { + if (errno != EEXIST) + { + LL_WARNS() << "Couldn't create portable_viewer cache and settings directories." << LL_ENDL; + return; // Failed, don't mess up the existing initialization. + } + } + mDefaultCacheDir = buildSLOSCacheDir(); + initAppDirs(mAppName); // This is kinda lazy, but it's probably the quickest, most uniform way. +} + +void LLDir::setChatLogsDir( const std::string& path) { if (!path.empty() ) { @@ -614,10 +973,15 @@ void LLDir::setChatLogsDir(const std::string &path) } else { - llwarns << "Invalid name for LLDir::setChatLogsDir" << llendl; + LL_WARNS() << "Invalid name for LLDir::setChatLogsDir" << LL_ENDL; } } +void LLDir::updatePerAccountChatLogsDir(const std::string &grid) +{ + mPerAccountChatLogsDir = getGridSpecificDir(add(getChatLogsDir(), mUserName), grid); +} + void LLDir::setPerAccountChatLogsDir(const std::string &grid, const std::string &first, const std::string &last) { // if both first and last aren't set, assume we're grabbing the cached dir @@ -627,36 +991,69 @@ void LLDir::setPerAccountChatLogsDir(const std::string &grid, const std::string // utterly consistent with our firstname/lastname case. std::string userlower(first+"_"+last); LLStringUtil::toLower(userlower); - mPerAccountChatLogsDir = add(getChatLogsDir(), userlower); - if (!grid.empty()) - { - std::string gridlower(grid); - LLStringUtil::toLower(gridlower); - mPerAccountChatLogsDir += "@"; - mPerAccountChatLogsDir += gridlower; - } + + mUserName = userlower; + updatePerAccountChatLogsDir(grid); } else { - llwarns << "Invalid name for LLDir::setPerAccountChatLogsDir" << llendl; + LL_WARNS() << "Invalid name for LLDir::setPerAccountChatLogsDir" << LL_ENDL; } } -void LLDir::setSkinFolder(const std::string &skin_folder) +void LLDir::setSkinFolder(const std::string &skin_folder, const std::string& language) { + LL_DEBUGS("LLDir") << "Setting skin '" << skin_folder << "', language '" << language << "'" + << LL_ENDL; + mSkinName = skin_folder; + mLanguage = language; + + // This method is called multiple times during viewer initialization. Each + // time it's called, reset mSearchSkinDirs. + mSearchSkinDirs.clear(); + + // base skin which is used as fallback for all skinned files + // e.g. c:\program files\secondlife\skins\default + mDefaultSkinDir = getSkinBaseDir(); + append(mDefaultSkinDir, "default"); + // This is always the most general of the search skin directories. + addSearchSkinDir(mDefaultSkinDir); + mSkinDir = getSkinBaseDir(); append(mSkinDir, skin_folder); + // Next level of generality is a skin installed with the viewer. + addSearchSkinDir(mSkinDir); - // user modifications to current skin + // user modifications to skins, current and default // e.g. c:\documents and settings\users\username\application data\second life\skins\dazzle mUserSkinDir = getOSUserAppDir(); append(mUserSkinDir, "skins_sg1"); + mUserDefaultSkinDir = mUserSkinDir; + append(mUserDefaultSkinDir, "default"); append(mUserSkinDir, skin_folder); + // Next level of generality is user modifications to default skin... + addSearchSkinDir(mUserDefaultSkinDir); + // then user-defined skins. + addSearchSkinDir(mUserSkinDir); +} - // base skin which is used as fallback for all skinned files - // e.g. c:\program files\secondlife\skins\default - mDefaultSkinDir = getSkinBaseDir(); - append(mDefaultSkinDir, "default"); +void LLDir::addSearchSkinDir(const std::string& skindir) +{ + if (std::find(mSearchSkinDirs.begin(), mSearchSkinDirs.end(), skindir) == mSearchSkinDirs.end()) + { + LL_DEBUGS("LLDir") << "search skin: '" << skindir << "'" << LL_ENDL; + mSearchSkinDirs.push_back(skindir); + } +} + +std::string LLDir::getSkinFolder() const +{ + return mSkinName; +} + +std::string LLDir::getLanguage() const +{ + return mLanguage; } bool LLDir::setCacheDir(const std::string &path) @@ -685,22 +1082,22 @@ bool LLDir::setCacheDir(const std::string &path) void LLDir::dumpCurrentDirectories() { - LL_DEBUGS2("AppInit","Directories") << "Current Directories:" << LL_ENDL; - - LL_DEBUGS2("AppInit","Directories") << " CurPath: " << getCurPath() << LL_ENDL; - LL_DEBUGS2("AppInit","Directories") << " AppName: " << getAppName() << LL_ENDL; - LL_DEBUGS2("AppInit","Directories") << " ExecutableFilename: " << getExecutableFilename() << LL_ENDL; - LL_DEBUGS2("AppInit","Directories") << " ExecutableDir: " << getExecutableDir() << LL_ENDL; - LL_DEBUGS2("AppInit","Directories") << " ExecutablePathAndName: " << getExecutablePathAndName() << LL_ENDL; - LL_DEBUGS2("AppInit","Directories") << " WorkingDir: " << getWorkingDir() << LL_ENDL; - LL_DEBUGS2("AppInit","Directories") << " AppRODataDir: " << getAppRODataDir() << LL_ENDL; - LL_DEBUGS2("AppInit","Directories") << " OSUserDir: " << getOSUserDir() << LL_ENDL; - LL_DEBUGS2("AppInit","Directories") << " OSUserAppDir: " << getOSUserAppDir() << LL_ENDL; - LL_DEBUGS2("AppInit","Directories") << " LindenUserDir: " << getLindenUserDir() << LL_ENDL; - LL_DEBUGS2("AppInit","Directories") << " TempDir: " << getTempDir() << LL_ENDL; - LL_DEBUGS2("AppInit","Directories") << " CAFile: " << getCAFile() << LL_ENDL; - LL_DEBUGS2("AppInit","Directories") << " SkinBaseDir: " << getSkinBaseDir() << LL_ENDL; - LL_DEBUGS2("AppInit","Directories") << " SkinDir: " << getSkinDir() << LL_ENDL; + LL_DEBUGS("AppInit","Directories") << "Current Directories:" << LL_ENDL; + + LL_DEBUGS("AppInit","Directories") << " CurPath: " << getCurPath() << LL_ENDL; + LL_DEBUGS("AppInit","Directories") << " AppName: " << getAppName() << LL_ENDL; + LL_DEBUGS("AppInit","Directories") << " ExecutableFilename: " << getExecutableFilename() << LL_ENDL; + LL_DEBUGS("AppInit","Directories") << " ExecutableDir: " << getExecutableDir() << LL_ENDL; + LL_DEBUGS("AppInit","Directories") << " ExecutablePathAndName: " << getExecutablePathAndName() << LL_ENDL; + LL_DEBUGS("AppInit","Directories") << " WorkingDir: " << getWorkingDir() << LL_ENDL; + LL_DEBUGS("AppInit","Directories") << " AppRODataDir: " << getAppRODataDir() << LL_ENDL; + LL_DEBUGS("AppInit","Directories") << " OSUserDir: " << getOSUserDir() << LL_ENDL; + LL_DEBUGS("AppInit","Directories") << " OSUserAppDir: " << getOSUserAppDir() << LL_ENDL; + LL_DEBUGS("AppInit","Directories") << " LindenUserDir: " << getLindenUserDir() << LL_ENDL; + LL_DEBUGS("AppInit","Directories") << " TempDir: " << getTempDir() << LL_ENDL; + LL_DEBUGS("AppInit","Directories") << " CAFile: " << getCAFile() << LL_ENDL; + LL_DEBUGS("AppInit","Directories") << " SkinBaseDir: " << getSkinBaseDir() << LL_ENDL; + LL_DEBUGS("AppInit","Directories") << " SkinDir: " << getSkinDir() << LL_ENDL; } std::string LLDir::add(const std::string& path, const std::string& name) const @@ -747,7 +1144,7 @@ LLDir::SepOff LLDir::needSep(const std::string& path, const std::string& name) c { // But if BOTH path and name bring a separator, we need not add one. // Moreover, we should actually skip the leading separator of 'name'. - return SepOff(false, seplen); + return SepOff(false, static_cast(seplen)); } // Here we know that either path_ends_sep or name_starts_sep is true -- // but not both. So don't add a separator, and don't skip any characters: @@ -770,13 +1167,13 @@ void dir_exists_or_crash(const std::string &dir_name) { if(0 != LLFile::mkdir(dir_name, 0700)) // octal { - llerrs << "Unable to create directory: " << dir_name << llendl; + LL_ERRS() << "Unable to create directory: " << dir_name << LL_ENDL; } } else { - llerrs << "Unable to stat: " << dir_name << " errno = " << stat_rv - << llendl; + LL_ERRS() << "Unable to stat: " << dir_name << " errno = " << stat_rv + << LL_ENDL; } } else @@ -784,7 +1181,7 @@ void dir_exists_or_crash(const std::string &dir_name) // data_dir exists, make sure it's a directory. if(!S_ISDIR(dir_stat.st_mode)) { - llerrs << "Data directory collision: " << dir_name << llendl; + LL_ERRS() << "Data directory collision: " << dir_name << LL_ENDL; } } #endif diff --git a/indra/llvfs/lldir.h b/indra/llvfs/lldir.h index 23f84bb41b..34b5ebf559 100644 --- a/indra/llvfs/lldir.h +++ b/indra/llvfs/lldir.h @@ -53,6 +53,7 @@ typedef enum ELLPath LL_PATH_EXECUTABLE = 16, LL_PATH_DEFAULT_SKIN = 17, LL_PATH_FONTS = 18, + LL_PATH_DUMP = 19, LL_PATH_LAST } ELLPath; @@ -71,12 +72,13 @@ class LLDir const std::string& app_read_only_data_dir = "") = 0; virtual S32 deleteFilesInDir(const std::string &dirname, const std::string &mask); - + U32 deleteDirAndContents(const std::string& dir_name); + std::vector getFilesInDir(const std::string &dirname); // pure virtual functions virtual U32 countFilesInDir(const std::string &dirname, const std::string &mask) = 0; virtual std::string getCurPath() = 0; - virtual BOOL fileExists(const std::string &filename) const = 0; + virtual bool fileExists(const std::string &filename) const = 0; const std::string findFile(const std::string& filename, const std::vector filenames) const; const std::string findFile(const std::string& filename, const std::string& searchPath1 = "", const std::string& searchPath2 = "", const std::string& searchPath3 = "") const; @@ -94,17 +96,20 @@ class LLDir const std::string &getOSUserAppDir() const; // Location of the os-specific user app dir const std::string &getLindenUserDir(bool empty_ok = false) const; // Location of the Linden user dir. const std::string &getChatLogsDir() const; // Location of the chat logs dir. + const std::string &getDumpDir() const; // Location of the per-run dump dir. const std::string &getPerAccountChatLogsDir() const; // Location of the per account chat logs dir. const std::string &getTempDir() const; // Common temporary directory const std::string getCacheDir(bool get_default = false) const; // Location of the cache. const std::string &getOSCacheDir() const; // location of OS-specific cache folder (may be empty string) const std::string &getCAFile() const; // File containing TLS certificate authorities const std::string &getDirDelimiter() const; // directory separator for platform (ie. '\' or '/' or ':') + const std::string &getDefaultSkinDir() const; // folder for default skin. e.g. c:\program files\second life\skins\default const std::string &getSkinDir() const; // User-specified skin folder. + const std::string &getUserDefaultSkinDir() const; // dir with user modifications to default skin const std::string &getUserSkinDir() const; // User-specified skin folder with user modifications. e.g. c:\documents and settings\username\application data\second life\skins\curskin - const std::string &getDefaultSkinDir() const; // folder for default skin. e.g. c:\program files\second life\skins\default const std::string getSkinBaseDir() const; // folder that contains all installed skins (not user modifications). e.g. c:\program files\second life\skins const std::string &getLLPluginDir() const; // Directory containing plugins and plugin shell + const std::string &getUserName() const; // Expanded filename std::string getExpandedFilename(ELLPath location, const std::string &filename) const; @@ -117,23 +122,80 @@ class LLDir std::string getExtension(const std::string& filepath) const; // Excludes '.', e.g getExtension("foo.wav") == "wav" // these methods search the various skin paths for the specified file in the following order: - // getUserSkinDir(), getSkinDir(), getDefaultSkinDir() - std::string findSkinnedFilename(const std::string &filename) const; - std::string findSkinnedFilename(const std::string &subdir, const std::string &filename) const; - std::string findSkinnedFilename(const std::string &subdir1, const std::string &subdir2, const std::string &filename) const; + // getUserSkinDir(), getUserDefaultSkinDir(), getSkinDir(), getDefaultSkinDir() + /// param value for findSkinnedFilenames(), explained below + enum ESkinConstraint { CURRENT_SKIN, ALL_SKINS }; + /** + * Given a filename within skin, return an ordered sequence of paths to + * search. Nonexistent files will be filtered out -- which means that the + * vector might be empty. + * + * @param subdir Identify top-level skin subdirectory by passing one of + * LLDir::XUI (file lives under "xui" subtree), LLDir::TEXTURES (file + * lives under "textures" subtree), LLDir::SKINBASE (file lives at top + * level of skin subdirectory). + * @param filename Desired filename within subdir within skin, e.g. + * "panel_login.xml". DO NOT prepend (e.g.) "xui" or the desired language. + * @param constraint Callers perform two different kinds of processing. + * When fetching a XUI file, for instance, the existence of @a filename in + * the specified skin completely supercedes any @a filename in the default + * skin. For that case, leave the default @a constraint=CURRENT_SKIN. The + * returned vector will contain only + * ".../current_skin/xui/en/filename", + * ".../current_skin/xui/current_language/filename". + * But for (e.g.) "strings.xml", we want a given skin to be able to + * override only specific entries from the default skin. Any string not + * defined in the specified skin will be sought in the default skin. For + * that case, pass @a constraint=ALL_SKINS. The returned vector will + * contain at least ".../default/xui/en/strings.xml", + * ".../default/xui/current_language/strings.xml", + * ".../current_skin/xui/en/strings.xml", + * ".../current_skin/xui/current_language/strings.xml". + */ + std::vector findSkinnedFilenames(const std::string& subdir, + const std::string& filename, + ESkinConstraint constraint=CURRENT_SKIN) const; + /// Values for findSkinnedFilenames(subdir) parameter + static const char *XUI, *TEXTURES, *SKINBASE; + /** + * Return the base-language pathname from findSkinnedFilenames(), or + * the empty string if no such file exists. Parameters are identical to + * findSkinnedFilenames(). This is shorthand for capturing the vector + * returned by findSkinnedFilenames(), checking for empty() and then + * returning front(). + */ + std::string findSkinnedFilenameBaseLang(const std::string &subdir, + const std::string &filename, + ESkinConstraint constraint=CURRENT_SKIN) const; + /** + * Return the "most localized" pathname from findSkinnedFilenames(), or + * the empty string if no such file exists. Parameters are identical to + * findSkinnedFilenames(). This is shorthand for capturing the vector + * returned by findSkinnedFilenames(), checking for empty() and then + * returning back(). + */ + std::string findSkinnedFilename(const std::string &subdir, + const std::string &filename, + ESkinConstraint constraint=CURRENT_SKIN) const; // random filename in common temporary directory std::string getTempFilename() const; // For producing safe download file names from potentially unsafe ones - static std::string getScrubbedFileName(const std::string uncleanFileName); + static std::string getScrubbedFileName(const std::string& uncleanFileName); static std::string getForbiddenFileChars(); + static std::string getGridSpecificDir( const std::string& in, const std::string& grid ); + void setDumpDir( const std::string& path ); + void makePortable(); virtual void setChatLogsDir(const std::string &path); // Set the chat logs dir to this user's dir - virtual void setPerAccountChatLogsDir(const std::string &grid, const std::string &first, const std::string &last); // Set the per user chat log directory. + virtual void setPerAccountChatLogsDir(const std::string &grid, const std::string &first, const std::string& last); // Set the per user chat log directory. virtual void setLindenUserDir(const std::string& grid, const std::string& first, const std::string& last); // Set the linden user dir to this user's dir - virtual void setSkinFolder(const std::string &skin_folder); + virtual void setSkinFolder(const std::string &skin_folder, const std::string& language); + virtual std::string getSkinFolder() const; + virtual std::string getLanguage() const; virtual bool setCacheDir(const std::string &path); + virtual void updatePerAccountChatLogsDir(const std::string &grid); virtual void dumpCurrentDirectories(); @@ -151,6 +213,16 @@ class LLDir // Does an add() or append() call need a directory delimiter? typedef std::pair SepOff; SepOff needSep(const std::string& path, const std::string& name) const; + // build mSearchSkinDirs without adding duplicates + void addSearchSkinDir(const std::string& skindir); + + // Internal to findSkinnedFilenames() + template + void walkSearchSkinDirs(const std::string& subdir, + const std::vector& subsubdirs, + const std::string& filename, + const FUNCTION& function) const; + std::string mAppName; // install directory under progams/ ie "SecondLife" std::string mExecutablePathAndName; // full path + Filename of .exe std::string mExecutableFilename; // Filename of .exe @@ -168,11 +240,21 @@ class LLDir std::string mDefaultCacheDir; // default cache diretory std::string mOSCacheDir; // operating system cache dir std::string mDirDelimiter; + std::string mSkinName; // caller-specified skin name std::string mSkinBaseDir; // Base for skins paths. - std::string mSkinDir; // Location for current skin info. std::string mDefaultSkinDir; // Location for default skin info. + std::string mSkinDir; // Location for current skin info. + std::string mUserDefaultSkinDir; // Location for default skin info. std::string mUserSkinDir; // Location for user-modified skin info. + // Skin directories to search, most general to most specific. This order + // works well for composing fine-grained files, in which an individual item + // in a specific file overrides the corresponding item in more general + // files. Of course, for a file-level search, iterate backwards. + std::vector mSearchSkinDirs; + std::string mLanguage; // Current viewer language std::string mLLPluginDir; // Location for plugins and plugin shell + static std::string sDumpDir; // Per-run crash report subdir of log directory. + std::string mUserName; // Current user name }; void dir_exists_or_crash(const std::string &dir_name); diff --git a/indra/llvfs/lldir_linux.cpp b/indra/llvfs/lldir_linux.cpp index e3090d8c5c..6e70c2235e 100644 --- a/indra/llvfs/lldir_linux.cpp +++ b/indra/llvfs/lldir_linux.cpp @@ -49,7 +49,7 @@ static std::string getCurrentUserHome(char* fallback) } else { - llinfos << "Couldn't detect home directory from passwd - trying $HOME" << llendl; + LL_INFOS() << "Couldn't detect home directory from passwd - trying $HOME" << LL_ENDL; const char *const home_env = getenv("HOME"); /* Flawfinder: ignore */ if (home_env) { @@ -57,7 +57,7 @@ static std::string getCurrentUserHome(char* fallback) } else { - llwarns << "Couldn't detect home directory! Falling back to " << fallback << llendl; + LL_WARNS() << "Couldn't detect home directory! Falling back to " << fallback << LL_ENDL; } } @@ -76,11 +76,11 @@ LLDir_Linux::LLDir_Linux() if (getcwd(tmp_str, LL_MAX_PATH) == NULL) { strcpy(tmp_str, "/tmp"); - llwarns << "Could not get current directory; changing to " - << tmp_str << llendl; + LL_WARNS() << "Could not get current directory; changing to " + << tmp_str << LL_ENDL; if (chdir(tmp_str) == -1) { - llerrs << "Could not change directory to " << tmp_str << llendl; + LL_ERRS() << "Could not change directory to " << tmp_str << LL_ENDL; } } @@ -93,19 +93,7 @@ LLDir_Linux::LLDir_Linux() #else mAppRODataDir = tmp_str; #endif - std::string::size_type build_dir_pos = mExecutableDir.rfind("/indra/viewer-linux-"); - if (build_dir_pos != std::string::npos) - { - // ...we're in a dev checkout - mSkinBaseDir = mExecutableDir.substr(0, build_dir_pos) + "/indra/newview/skins"; - llinfos << "Running in dev checkout with mSkinBaseDir " - << mSkinBaseDir << llendl; - } - else - { - // ...normal installation running - mSkinBaseDir = mAppRODataDir + mDirDelimiter + "skins"; - } + mSkinBaseDir = mAppRODataDir + mDirDelimiter + "skins"; mOSUserDir = getCurrentUserHome(tmp_str); mOSUserAppDir = ""; @@ -187,8 +175,8 @@ void LLDir_Linux::initAppDirs(const std::string &app_name, { if (errno != EEXIST) { - llwarns << "Couldn't create app user dir " << mOSUserAppDir << llendl; - llwarns << "Default to base dir" << mOSUserDir << llendl; + LL_WARNS() << "Couldn't create app user dir " << mOSUserAppDir << LL_ENDL; + LL_WARNS() << "Default to base dir" << mOSUserDir << LL_ENDL; mOSUserAppDir = mOSUserDir; } } @@ -198,7 +186,7 @@ void LLDir_Linux::initAppDirs(const std::string &app_name, { if (errno != EEXIST) { - llwarns << "Couldn't create LL_PATH_LOGS dir " << getExpandedFilename(LL_PATH_LOGS,"") << llendl; + LL_WARNS() << "Couldn't create LL_PATH_LOGS dir " << getExpandedFilename(LL_PATH_LOGS,"") << LL_ENDL; } } @@ -207,7 +195,7 @@ void LLDir_Linux::initAppDirs(const std::string &app_name, { if (errno != EEXIST) { - llwarns << "Couldn't create LL_PATH_USER_SETTINGS dir " << getExpandedFilename(LL_PATH_USER_SETTINGS,"") << llendl; + LL_WARNS() << "Couldn't create LL_PATH_USER_SETTINGS dir " << getExpandedFilename(LL_PATH_USER_SETTINGS,"") << LL_ENDL; } } @@ -216,11 +204,11 @@ void LLDir_Linux::initAppDirs(const std::string &app_name, { if (errno != EEXIST) { - llwarns << "Couldn't create LL_PATH_CACHE dir " << getExpandedFilename(LL_PATH_CACHE,"") << llendl; + LL_WARNS() << "Couldn't create LL_PATH_CACHE dir " << getExpandedFilename(LL_PATH_CACHE,"") << LL_ENDL; } } - mCAFile = getExpandedFilename(LL_PATH_APP_SETTINGS, "CA.pem"); + mCAFile = getExpandedFilename(LL_PATH_APP_SETTINGS, "ca-bundle.crt"); } U32 LLDir_Linux::countFilesInDir(const std::string &dirname, const std::string &mask) @@ -247,14 +235,14 @@ std::string LLDir_Linux::getCurPath() char tmp_str[LL_MAX_PATH]; /* Flawfinder: ignore */ if (getcwd(tmp_str, LL_MAX_PATH) == NULL) { - llwarns << "Could not get current directory" << llendl; + LL_WARNS() << "Could not get current directory" << LL_ENDL; tmp_str[0] = '\0'; } return tmp_str; } -BOOL LLDir_Linux::fileExists(const std::string &filename) const +bool LLDir_Linux::fileExists(const std::string &filename) const { struct stat stat_data; // Check the age of the file @@ -274,7 +262,7 @@ BOOL LLDir_Linux::fileExists(const std::string &filename) const /*virtual*/ std::string LLDir_Linux::getLLPluginLauncher() { return gDirUtilp->getExecutableDir() + gDirUtilp->getDirDelimiter() + - "SLPlugin"; + "llplugin/SLPlugin"; } /*virtual*/ std::string LLDir_Linux::getLLPluginFilename(std::string base_name) diff --git a/indra/llvfs/lldir_linux.h b/indra/llvfs/lldir_linux.h index 46bf91c69d..58f488da68 100644 --- a/indra/llvfs/lldir_linux.h +++ b/indra/llvfs/lldir_linux.h @@ -53,7 +53,7 @@ class LLDir_Linux : public LLDir virtual std::string getCurPath(); virtual U32 countFilesInDir(const std::string &dirname, const std::string &mask); - /*virtual*/ BOOL fileExists(const std::string &filename) const; + /*virtual*/ bool fileExists(const std::string &filename) const; /*virtual*/ std::string getLLPluginLauncher(); /*virtual*/ std::string getLLPluginFilename(std::string base_name); diff --git a/indra/llvfs/lldir_mac.cpp b/indra/llvfs/lldir_mac.cpp index 114dc0c47b..1127614aa5 100644 --- a/indra/llvfs/lldir_mac.cpp +++ b/indra/llvfs/lldir_mac.cpp @@ -149,21 +149,8 @@ LLDir_Mac::LLDir_Mac() CFURLRef resourcesURLRef = CFBundleCopyResourcesDirectoryURL(mainBundleRef); CFURLRefToLLString(resourcesURLRef, mAppRODataDir, true); - - U32 build_dir_pos = mExecutableDir.rfind("/indra/build-darwin-"); - if (build_dir_pos != std::string::npos) - { - // ...we're in a dev checkout - mSkinBaseDir = mExecutableDir.substr(0, build_dir_pos) - + "/indra/newview/skins"; - llinfos << "Running in dev checkout with mSkinBaseDir " - << mSkinBaseDir << llendl; - } - else - { - // ...normal installation running - mSkinBaseDir = mAppRODataDir + mDirDelimiter + "skins"; - } + + mSkinBaseDir = mAppRODataDir + mDirDelimiter + "skins"; // mOSUserDir error = FSFindFolder(kUserDomain, kApplicationSupportFolderType, true, &fileRef); @@ -267,7 +254,7 @@ std::string LLDir_Mac::getCurPath() -BOOL LLDir_Mac::fileExists(const std::string &filename) const +bool LLDir_Mac::fileExists(const std::string &filename) const { struct stat stat_data; // Check the age of the file diff --git a/indra/llvfs/lldir_mac.h b/indra/llvfs/lldir_mac.h index d99f9e39e0..5e3fab3fa0 100644 --- a/indra/llvfs/lldir_mac.h +++ b/indra/llvfs/lldir_mac.h @@ -52,7 +52,7 @@ class LLDir_Mac : public LLDir virtual std::string getCurPath(); virtual U32 countFilesInDir(const std::string &dirname, const std::string &mask); - virtual BOOL fileExists(const std::string &filename) const; + virtual bool fileExists(const std::string &filename) const; /*virtual*/ std::string getLLPluginLauncher(); /*virtual*/ std::string getLLPluginFilename(std::string base_name); diff --git a/indra/llvfs/lldir_solaris.cpp b/indra/llvfs/lldir_solaris.cpp index 22df6a9a30..a6e1289a09 100644 --- a/indra/llvfs/lldir_solaris.cpp +++ b/indra/llvfs/lldir_solaris.cpp @@ -58,7 +58,7 @@ static std::string getCurrentUserHome(char* fallback) } else { - llinfos << "Couldn't detect home directory from passwd - trying $HOME" << llendl; + LL_INFOS() << "Couldn't detect home directory from passwd - trying $HOME" << LL_ENDL; const char *const home_env = getenv("HOME"); /* Flawfinder: ignore */ if (home_env) { @@ -66,7 +66,7 @@ static std::string getCurrentUserHome(char* fallback) } else { - llwarns << "Couldn't detect home directory! Falling back to " << fallback << llendl; + LL_WARNS() << "Couldn't detect home directory! Falling back to " << fallback << LL_ENDL; } } @@ -85,11 +85,11 @@ LLDir_Solaris::LLDir_Solaris() if (getcwd(tmp_str, LL_MAX_PATH) == NULL) { strcpy(tmp_str, "/tmp"); - llwarns << "Could not get current directory; changing to " - << tmp_str << llendl; + LL_WARNS() << "Could not get current directory; changing to " + << tmp_str << LL_ENDL; if (chdir(tmp_str) == -1) { - llerrs << "Could not change directory to " << tmp_str << llendl; + LL_ERRS() << "Could not change directory to " << tmp_str << LL_ENDL; } } @@ -107,12 +107,12 @@ LLDir_Solaris::LLDir_Solaris() sprintf(path, "/proc/%d/psinfo", (int)getpid()); int proc_fd = -1; if((proc_fd = open(path, O_RDONLY)) == -1){ - llwarns << "unable to open " << path << llendl; + LL_WARNS() << "unable to open " << path << LL_ENDL; return; } psinfo_t proc_psinfo; if(read(proc_fd, &proc_psinfo, sizeof(psinfo_t)) != sizeof(psinfo_t)){ - llwarns << "Unable to read " << path << llendl; + LL_WARNS() << "Unable to read " << path << LL_ENDL; close(proc_fd); return; } @@ -120,13 +120,13 @@ LLDir_Solaris::LLDir_Solaris() close(proc_fd); mExecutableFilename = strdup(proc_psinfo.pr_fname); - llinfos << "mExecutableFilename = [" << mExecutableFilename << "]" << llendl; + LL_INFOS() << "mExecutableFilename = [" << mExecutableFilename << "]" << LL_ENDL; sprintf(path, "/proc/%d/path/a.out", (int)getpid()); char execpath[LL_MAX_PATH]; if(readlink(path, execpath, LL_MAX_PATH) == -1){ - llwarns << "Unable to read link from " << path << llendl; + LL_WARNS() << "Unable to read link from " << path << LL_ENDL; return; } @@ -136,7 +136,7 @@ LLDir_Solaris::LLDir_Solaris() *p = NULL; mExecutablePathAndName = strdup(execpath); - llinfos << "mExecutablePathAndName = [" << mExecutablePathAndName << "]" << llendl; + LL_INFOS() << "mExecutablePathAndName = [" << mExecutablePathAndName << "]" << LL_ENDL; //NOTE: Why force people to cd into the package directory? // Look for SECONDLIFE env variable and use it, if set. @@ -157,7 +157,7 @@ LLDir_Solaris::LLDir_Solaris() *s = (char)NULL; mExecutableDir = strdup(execpath); - llinfos << "mExecutableDir = [" << mExecutableDir << "]" << llendl; + LL_INFOS() << "mExecutableDir = [" << mExecutableDir << "]" << LL_ENDL; } } @@ -211,8 +211,8 @@ void LLDir_Solaris::initAppDirs(const std::string &app_name, { if (errno != EEXIST) { - llwarns << "Couldn't create app user dir " << mOSUserAppDir << llendl; - llwarns << "Default to base dir" << mOSUserDir << llendl; + LL_WARNS() << "Couldn't create app user dir " << mOSUserAppDir << LL_ENDL; + LL_WARNS() << "Default to base dir" << mOSUserDir << LL_ENDL; mOSUserAppDir = mOSUserDir; } } @@ -222,7 +222,7 @@ void LLDir_Solaris::initAppDirs(const std::string &app_name, { if (errno != EEXIST) { - llwarns << "Couldn't create LL_PATH_LOGS dir " << getExpandedFilename(LL_PATH_LOGS,"") << llendl; + LL_WARNS() << "Couldn't create LL_PATH_LOGS dir " << getExpandedFilename(LL_PATH_LOGS,"") << LL_ENDL; } } @@ -231,7 +231,7 @@ void LLDir_Solaris::initAppDirs(const std::string &app_name, { if (errno != EEXIST) { - llwarns << "Couldn't create LL_PATH_USER_SETTINGS dir " << getExpandedFilename(LL_PATH_USER_SETTINGS,"") << llendl; + LL_WARNS() << "Couldn't create LL_PATH_USER_SETTINGS dir " << getExpandedFilename(LL_PATH_USER_SETTINGS,"") << LL_ENDL; } } @@ -240,7 +240,7 @@ void LLDir_Solaris::initAppDirs(const std::string &app_name, { if (errno != EEXIST) { - llwarns << "Couldn't create LL_PATH_CACHE dir " << getExpandedFilename(LL_PATH_CACHE,"") << llendl; + LL_WARNS() << "Couldn't create LL_PATH_CACHE dir " << getExpandedFilename(LL_PATH_CACHE,"") << LL_ENDL; } } @@ -271,14 +271,14 @@ std::string LLDir_Solaris::getCurPath() char tmp_str[LL_MAX_PATH]; /* Flawfinder: ignore */ if (getcwd(tmp_str, LL_MAX_PATH) == NULL) { - llwarns << "Could not get current directory" << llendl; + LL_WARNS() << "Could not get current directory" << LL_ENDL; tmp_str[0] = '\0'; } return tmp_str; } -BOOL LLDir_Solaris::fileExists(const std::string &filename) const +bool LLDir_Solaris::fileExists(const std::string &filename) const { struct stat stat_data; // Check the age of the file diff --git a/indra/llvfs/lldir_solaris.h b/indra/llvfs/lldir_solaris.h index 88da8500d8..c2d660554c 100644 --- a/indra/llvfs/lldir_solaris.h +++ b/indra/llvfs/lldir_solaris.h @@ -53,7 +53,7 @@ class LLDir_Solaris : public LLDir virtual std::string getCurPath(); virtual U32 countFilesInDir(const std::string &dirname, const std::string &mask); - /*virtual*/ BOOL fileExists(const std::string &filename) const; + /*virtual*/ bool fileExists(const std::string &filename) const; private: DIR *mDirp; diff --git a/indra/llvfs/lldir_win32.cpp b/indra/llvfs/lldir_win32.cpp index 271afa5e94..8547f14080 100644 --- a/indra/llvfs/lldir_win32.cpp +++ b/indra/llvfs/lldir_win32.cpp @@ -48,40 +48,29 @@ LLDir_Win32::LLDir_Win32() WCHAR w_str[MAX_PATH]; - // Application Data is where user settings go - SHGetSpecialFolderPath(NULL, w_str, CSIDL_APPDATA, TRUE); + WCHAR* pPath = NULL; + if(SHGetKnownFolderPath(FOLDERID_RoamingAppData, 0, NULL, &pPath) == S_OK) + wcscpy_s(w_str, pPath); + + CoTaskMemFree(pPath); + pPath = NULL; mOSUserDir = utf16str_to_utf8str(llutf16string(w_str)); // We want cache files to go on the local disk, even if the // user is on a network with a "roaming profile". // - // On XP this is: - // C:\Docments and Settings\James\Local Settings\Application Data - // On Vista this is: - // C:\Users\James\AppData\Local + // On Vista and above this is: + // C:\Users\\AppData\Local // // We used to store the cache in AppData\Roaming, and the installer // cleans up that version on upgrade. JC + if(SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, NULL, &pPath) == S_OK) + wcscpy_s(w_str, pPath); - if(HMODULE shell = LoadLibrary(L"shell32")) //SHGetSpecialFolderPath is deprecated from Vista an onwards. Try to use SHGetSpecialFolderPath if it's available - { - HRESULT (WINAPI* pSHGetKnownFolderPath)(REFKNOWNFOLDERID rfid, DWORD dwFlags, HANDLE hToken, PWSTR *ppszPath); - pSHGetKnownFolderPath = (HRESULT (WINAPI *)(REFKNOWNFOLDERID, DWORD, HANDLE, PWSTR *))GetProcAddress(shell, "SHGetKnownFolderPath"); - WCHAR* pPath = NULL; - if(pSHGetKnownFolderPath && (*pSHGetKnownFolderPath)(FOLDERID_LocalAppData, 0, NULL, &pPath) == S_OK) - wcscpy_s(w_str,pPath); - else - SHGetSpecialFolderPath(NULL, w_str, CSIDL_LOCAL_APPDATA, TRUE); + CoTaskMemFree(pPath); + pPath = NULL; - FreeLibrary(shell); - if(pPath) - CoTaskMemFree(pPath); - } - else //XP doesn't support SHGetKnownFolderPath - { - SHGetSpecialFolderPath(NULL, w_str, CSIDL_LOCAL_APPDATA, TRUE); - } mOSCacheDir = utf16str_to_utf8str(llutf16string(w_str)); if (GetTempPath(MAX_PATH, w_str)) @@ -109,7 +98,7 @@ LLDir_Win32::LLDir_Win32() { w_str[size] = '\0'; mExecutablePathAndName = utf16str_to_utf8str(llutf16string(w_str)); - S32 path_end = mExecutablePathAndName.find_last_of('\\'); + size_t path_end = mExecutablePathAndName.find_last_of('\\'); if (path_end != std::string::npos) { mExecutableDir = mExecutablePathAndName.substr(0, path_end); @@ -136,7 +125,7 @@ LLDir_Win32::LLDir_Win32() // if (mExecutableDir.find("indra") == std::string::npos) - + // *NOTE:Mani - It is a mistake to put viewer specific code in // the LLDir implementation. The references to 'skins' and // 'llplugin' need to go somewhere else. @@ -149,7 +138,7 @@ LLDir_Win32::LLDir_Win32() mAppRODataDir = mExecutableDir; } - llinfos << "mAppRODataDir = " << mAppRODataDir << llendl; +// LL_INFOS() << "mAppRODataDir = " << mAppRODataDir << LL_ENDL; mSkinBaseDir = mAppRODataDir + mDirDelimiter + "skins"; @@ -162,7 +151,7 @@ LLDir_Win32::LLDir_Win32() { if (errno != EEXIST) { - llwarns << "Couldn't create LL_PATH_CACHE dir " << mDefaultCacheDir << llendl; + LL_WARNS() << "Couldn't create LL_PATH_CACHE dir " << mDefaultCacheDir << LL_ENDL; } } @@ -194,8 +183,8 @@ void LLDir_Win32::initAppDirs(const std::string &app_name, { if (errno != EEXIST) { - llwarns << "Couldn't create app user dir " << mOSUserAppDir << llendl; - llwarns << "Default to base dir" << mOSUserDir << llendl; + LL_WARNS() << "Couldn't create app user dir " << mOSUserAppDir << LL_ENDL; + LL_WARNS() << "Default to base dir" << mOSUserDir << LL_ENDL; mOSUserAppDir = mOSUserDir; } } @@ -206,7 +195,7 @@ void LLDir_Win32::initAppDirs(const std::string &app_name, { if (errno != EEXIST) { - llwarns << "Couldn't create LL_PATH_LOGS dir " << getExpandedFilename(LL_PATH_LOGS,"") << llendl; + LL_WARNS() << "Couldn't create LL_PATH_LOGS dir " << getExpandedFilename(LL_PATH_LOGS,"") << LL_ENDL; } } @@ -215,7 +204,7 @@ void LLDir_Win32::initAppDirs(const std::string &app_name, { if (errno != EEXIST) { - llwarns << "Couldn't create LL_PATH_USER_SETTINGS dir " << getExpandedFilename(LL_PATH_USER_SETTINGS,"") << llendl; + LL_WARNS() << "Couldn't create LL_PATH_USER_SETTINGS dir " << getExpandedFilename(LL_PATH_USER_SETTINGS,"") << LL_ENDL; } } @@ -224,11 +213,11 @@ void LLDir_Win32::initAppDirs(const std::string &app_name, { if (errno != EEXIST) { - llwarns << "Couldn't create LL_PATH_CACHE dir " << getExpandedFilename(LL_PATH_CACHE,"") << llendl; + LL_WARNS() << "Couldn't create LL_PATH_CACHE dir " << getExpandedFilename(LL_PATH_CACHE,"") << LL_ENDL; } } - mCAFile = getExpandedFilename(LL_PATH_APP_SETTINGS, "CA.pem"); + mCAFile = getExpandedFilename(LL_PATH_APP_SETTINGS, "ca-bundle.crt"); } U32 LLDir_Win32::countFilesInDir(const std::string &dirname, const std::string &mask) @@ -267,7 +256,7 @@ std::string LLDir_Win32::getCurPath() } -BOOL LLDir_Win32::fileExists(const std::string &filename) const +bool LLDir_Win32::fileExists(const std::string &filename) const { llstat stat_data; // Check the age of the file diff --git a/indra/llvfs/lldir_win32.h b/indra/llvfs/lldir_win32.h index 4421b87f06..ed2f916d43 100644 --- a/indra/llvfs/lldir_win32.h +++ b/indra/llvfs/lldir_win32.h @@ -50,7 +50,7 @@ class LLDir_Win32 : public LLDir /*virtual*/ std::string getCurPath(); /*virtual*/ U32 countFilesInDir(const std::string &dirname, const std::string &mask); - /*virtual*/ BOOL fileExists(const std::string &filename) const; + /*virtual*/ bool fileExists(const std::string &filename) const; /*virtual*/ std::string getLLPluginLauncher(); /*virtual*/ std::string getLLPluginFilename(std::string base_name); diff --git a/indra/llvfs/lldiriterator.cpp b/indra/llvfs/lldiriterator.cpp index 0d1c4b37f0..0cdf456234 100644 --- a/indra/llvfs/lldiriterator.cpp +++ b/indra/llvfs/lldiriterator.cpp @@ -49,7 +49,11 @@ class LLDirIterator::Impl LLDirIterator::Impl::Impl(const std::string &dirname, const std::string &mask) : mIsValid(false) { +#if LL_WINDOWS + fs::path dir_path(utf8str_to_utf16str(dirname).c_str()); +#else fs::path dir_path(dirname); +#endif bool is_dir = false; @@ -58,19 +62,15 @@ LLDirIterator::Impl::Impl(const std::string &dirname, const std::string &mask) { is_dir = fs::is_directory(dir_path); } -#if BOOST_FILESYSTEM_VERSION >= 3 - catch (fs::filesystem_error& e) -#else - catch (fs::basic_filesystem_error& e) -#endif + catch (const fs::filesystem_error& e) { - llwarns << e.what() << llendl; + LL_WARNS() << e.what() << LL_ENDL; return; } if (!is_dir) { - llwarns << "Invalid path: \"" << dir_path.string() << "\"" << llendl; + LL_WARNS() << "Invalid path: \"" << dir_path.string() << "\"" << LL_ENDL; return; } @@ -79,13 +79,9 @@ LLDirIterator::Impl::Impl(const std::string &dirname, const std::string &mask) { mIter = fs::directory_iterator(dir_path); } -#if BOOST_FILESYSTEM_VERSION >= 3 - catch (fs::filesystem_error& e) -#else - catch (fs::basic_filesystem_error& e) -#endif + catch (const fs::filesystem_error& e) { - llerrs << e.what() << llendl; + LL_WARNS() << e.what() << LL_ENDL; return; } @@ -101,8 +97,8 @@ LLDirIterator::Impl::Impl(const std::string &dirname, const std::string &mask) } catch (boost::regex_error& e) { - llerrs << "\"" << exp << "\" is not a valid regular expression: " - << e.what() << llendl; + LL_WARNS() << "\"" << exp << "\" is not a valid regular expression: " + << e.what() << LL_ENDL; return; } @@ -119,26 +115,32 @@ bool LLDirIterator::Impl::next(std::string &fname) if (!mIsValid) { - llwarns << "The iterator is not correctly initialized." << llendl; + LL_WARNS() << "The iterator is not correctly initialized." << LL_ENDL; return false; } fs::directory_iterator end_itr; // default construction yields past-the-end bool found = false; - while (mIter != end_itr && !found) + + // Check if path is a directory. + try { - boost::smatch match; -#if BOOST_FILESYSTEM_VERSION >= 3 - std::string name = mIter->path().filename().string(); -#else - std::string name = mIter->path().filename(); -#endif - if ((found = boost::regex_match(name, match, mFilterExp))) + while (mIter != end_itr && !found) { - fname = name; + boost::smatch match; + std::string name = mIter->path().filename().string(); + found = boost::regex_match(name, match, mFilterExp); + if (found) + { + fname = name; + } + + ++mIter; } - - ++mIter; + } + catch (const fs::filesystem_error& e) + { + LL_WARNS() << e.what() << LL_ENDL; } return found; @@ -186,7 +188,7 @@ std::string glob_to_regex(const std::string& glob) case '}': if (!braces) { - llerrs << "glob_to_regex: Closing brace without an equivalent opening brace: " << glob << llendl; + LL_ERRS() << "glob_to_regex: Closing brace without an equivalent opening brace: " << glob << LL_ENDL; } regex+=')'; @@ -217,7 +219,7 @@ std::string glob_to_regex(const std::string& glob) if (braces) { - llerrs << "glob_to_regex: Unterminated brace expression: " << glob << llendl; + LL_ERRS() << "glob_to_regex: Unterminated brace expression: " << glob << LL_ENDL; } return regex; diff --git a/indra/llvfs/lllfsthread.cpp b/indra/llvfs/lllfsthread.cpp index 249e6a172d..4022a86b4f 100644 --- a/indra/llvfs/lllfsthread.cpp +++ b/indra/llvfs/lllfsthread.cpp @@ -93,7 +93,7 @@ LLLFSThread::handle_t LLLFSThread::read(const std::string& filename, /* Flawfind bool res = addRequest(req); if (!res) { - llerrs << "LLLFSThread::read called after LLLFSThread::cleanupClass()" << llendl; + LL_ERRS() << "LLLFSThread::read called after LLLFSThread::cleanupClass()" << LL_ENDL; } return handle; @@ -115,7 +115,7 @@ LLLFSThread::handle_t LLLFSThread::write(const std::string& filename, bool res = addRequest(req); if (!res) { - llerrs << "LLLFSThread::read called after LLLFSThread::cleanupClass()" << llendl; + LL_ERRS() << "LLLFSThread::read called after LLLFSThread::cleanupClass()" << LL_ENDL; } return handle; @@ -140,7 +140,7 @@ LLLFSThread::Request::Request(LLLFSThread* thread, { if (numbytes <= 0) { - llwarns << "LLLFSThread: Request with numbytes = " << numbytes << llendl; + LL_WARNS() << "LLLFSThread: Request with numbytes = " << numbytes << LL_ENDL; } } @@ -162,7 +162,7 @@ void LLLFSThread::Request::deleteRequest() { if (getStatus() == STATUS_QUEUED) { - llerrs << "Attempt to delete a queued LLLFSThread::Request!" << llendl; + LL_ERRS() << "Attempt to delete a queued LLLFSThread::Request!" << LL_ENDL; } if (mResponder.notNull()) { @@ -181,7 +181,7 @@ bool LLLFSThread::Request::processRequest() LLAPRFile infile(mFileName, LL_APR_RB); if (!infile.getFileHandle()) { - llwarns << "LLLFS: Unable to read file: " << mFileName << llendl; + LL_WARNS() << "LLLFS: Unable to read file: " << mFileName << LL_ENDL; mBytesRead = 0; // fail return true; } @@ -193,7 +193,7 @@ bool LLLFSThread::Request::processRequest() llassert_always(off >= 0); mBytesRead = infile.read(mBuffer, mBytes ); complete = true; -// llinfos << "LLLFSThread::READ:" << mFileName << " Bytes: " << mBytesRead << llendl; +// LL_INFOS() << "LLLFSThread::READ:" << mFileName << " Bytes: " << mBytesRead << LL_ENDL; } else if (mOperation == FILE_WRITE) { @@ -203,7 +203,7 @@ bool LLLFSThread::Request::processRequest() LLAPRFile outfile(mFileName, flags); if (!outfile.getFileHandle()) { - llwarns << "LLLFS: Unable to write file: " << mFileName << llendl; + LL_WARNS() << "LLLFS: Unable to write file: " << mFileName << LL_ENDL; mBytesRead = 0; // fail return true; } @@ -212,18 +212,18 @@ bool LLLFSThread::Request::processRequest() S32 seek = outfile.seek(APR_SET, mOffset); if (seek < 0) { - llwarns << "LLLFS: Unable to write file (seek failed): " << mFileName << llendl; + LL_WARNS() << "LLLFS: Unable to write file (seek failed): " << mFileName << LL_ENDL; mBytesRead = 0; // fail return true; } } mBytesRead = outfile.write(mBuffer, mBytes ); complete = true; -// llinfos << "LLLFSThread::WRITE:" << mFileName << " Bytes: " << mBytesRead << "/" << mBytes << " Offset:" << mOffset << llendl; +// LL_INFOS() << "LLLFSThread::WRITE:" << mFileName << " Bytes: " << mBytesRead << "/" << mBytes << " Offset:" << mOffset << LL_ENDL; } else { - llerrs << "LLLFSThread::unknown operation: " << (S32)mOperation << llendl; + LL_ERRS() << "LLLFSThread::unknown operation: " << (S32)mOperation << LL_ENDL; } return complete; } diff --git a/indra/llvfs/llpidlock.cpp b/indra/llvfs/llpidlock.cpp index f45b88b1ba..6fd7381a6c 100644 --- a/indra/llvfs/llpidlock.cpp +++ b/indra/llvfs/llpidlock.cpp @@ -109,7 +109,7 @@ void LLPidLockFile::writeLockFile(LLSD pids) if (!LLSDSerialize::toXML(pids,ofile)) { - llwarns << "Unable to write concurrent save lock file." << llendl; + LL_WARNS() << "Unable to write concurrent save lock file." << LL_ENDL; } ofile.close(); } diff --git a/indra/llvfs/llvfile.cpp b/indra/llvfs/llvfile.cpp index 7825c35fe0..af6d7da2df 100644 --- a/indra/llvfs/llvfile.cpp +++ b/indra/llvfs/llvfile.cpp @@ -39,7 +39,7 @@ const S32 LLVFile::WRITE = 0x00000002; const S32 LLVFile::READ_WRITE = 0x00000003; // LLVFile::READ & LLVFile::WRITE const S32 LLVFile::APPEND = 0x00000006; // 0x00000004 & LLVFile::WRITE -static LLFastTimer::DeclareTimer FTM_VFILE_WAIT("VFile Wait"); +static LLTrace::BlockTimerStatHandle FTM_VFILE_WAIT("VFile Wait"); //---------------------------------------------------------------------------- LLVFSThread* LLVFile::sVFSThread = NULL; @@ -72,7 +72,7 @@ LLVFile::~LLVFile() { if (!(mMode & LLVFile::WRITE)) { - //llwarns << "Destroying LLVFile with pending async read/write, aborting..." << llendl; + //LL_WARNS() << "Destroying LLVFile with pending async read/write, aborting..." << LL_ENDL; sVFSThread->setFlags(mHandle, LLVFSThread::FLAG_AUTO_COMPLETE | LLVFSThread::FLAG_ABORT); } else // WRITE @@ -88,13 +88,13 @@ BOOL LLVFile::read(U8 *buffer, S32 bytes, BOOL async, F32 priority) { if (! (mMode & READ)) { - llwarns << "Attempt to read from file " << mFileID << " opened with mode " << std::hex << mMode << std::dec << llendl; + LL_WARNS() << "Attempt to read from file " << mFileID << " opened with mode " << std::hex << mMode << std::dec << LL_ENDL; return FALSE; } if (mHandle != LLVFSThread::nullHandle()) { - llwarns << "Attempt to read from vfile object " << mFileID << " with pending async operation" << llendl; + LL_WARNS() << "Attempt to read from vfile object " << mFileID << " with pending async operation" << LL_ENDL; return FALSE; } mPriority = priority; @@ -198,11 +198,11 @@ BOOL LLVFile::write(const U8 *buffer, S32 bytes) { if (! (mMode & WRITE)) { - llwarns << "Attempt to write to file " << mFileID << " opened with mode " << std::hex << mMode << std::dec << llendl; + LL_WARNS() << "Attempt to write to file " << mFileID << " opened with mode " << std::hex << mMode << std::dec << LL_ENDL; } if (mHandle != LLVFSThread::nullHandle()) { - llerrs << "Attempt to write to vfile object " << mFileID << " with pending async operation" << llendl; + LL_ERRS() << "Attempt to write to vfile object " << mFileID << " with pending async operation" << LL_ENDL; return FALSE; } BOOL success = TRUE; @@ -232,7 +232,7 @@ BOOL LLVFile::write(const U8 *buffer, S32 bytes) if (wrote < bytes) { - llwarns << "Tried to write " << bytes << " bytes, actually wrote " << wrote << llendl; + LL_WARNS() << "Tried to write " << bytes << " bytes, actually wrote " << wrote << LL_ENDL; success = FALSE; } @@ -252,7 +252,7 @@ BOOL LLVFile::seek(S32 offset, S32 origin) { if (mMode == APPEND) { - llwarns << "Attempt to seek on append-only file" << llendl; + LL_WARNS() << "Attempt to seek on append-only file" << LL_ENDL; return FALSE; } @@ -267,14 +267,14 @@ BOOL LLVFile::seek(S32 offset, S32 origin) if (new_pos > size) { - llwarns << "Attempt to seek past end of file" << llendl; + LL_WARNS() << "Attempt to seek past end of file" << LL_ENDL; mPosition = size; return FALSE; } else if (new_pos < 0) { - llwarns << "Attempt to seek past beginning of file" << llendl; + LL_WARNS() << "Attempt to seek past beginning of file" << LL_ENDL; mPosition = 0; return FALSE; @@ -308,20 +308,20 @@ BOOL LLVFile::setMaxSize(S32 size) { if (! (mMode & WRITE)) { - llwarns << "Attempt to change size of file " << mFileID << " opened with mode " << std::hex << mMode << std::dec << llendl; + LL_WARNS() << "Attempt to change size of file " << mFileID << " opened with mode " << std::hex << mMode << std::dec << LL_ENDL; return FALSE; } if (!mVFS->checkAvailable(size)) { - //LLFastTimer t(FTM_VFILE_WAIT); + //LL_RECORD_BLOCK_TIME(FTM_VFILE_WAIT); S32 count = 0; while (sVFSThread->getPending() > 1000) { if (count % 100 == 0) { - llinfos << "VFS catching up... Pending: " << sVFSThread->getPending() << llendl; + LL_INFOS() << "VFS catching up... Pending: " << sVFSThread->getPending() << LL_ENDL; } if (sVFSThread->isPaused()) { @@ -337,14 +337,14 @@ BOOL LLVFile::rename(const LLUUID &new_id, const LLAssetType::EType new_type) { if (! (mMode & WRITE)) { - llwarns << "Attempt to rename file " << mFileID << " opened with mode " << std::hex << mMode << std::dec << llendl; + LL_WARNS() << "Attempt to rename file " << mFileID << " opened with mode " << std::hex << mMode << std::dec << LL_ENDL; return FALSE; } if (mHandle != LLVFSThread::nullHandle()) { - llwarns << "Renaming file with pending async read" << llendl; + LL_WARNS() << "Renaming file with pending async read" << LL_ENDL; } waitForLock(VFSLOCK_READ); @@ -364,18 +364,18 @@ BOOL LLVFile::rename(const LLUUID &new_id, const LLAssetType::EType new_type) BOOL LLVFile::remove() { -// llinfos << "Removing file " << mFileID << llendl; +// LL_INFOS() << "Removing file " << mFileID << LL_ENDL; if (! (mMode & WRITE)) { // Leaving paranoia warning just because this should be a very infrequent // operation. - llwarns << "Remove file " << mFileID << " opened with mode " << std::hex << mMode << std::dec << llendl; + LL_WARNS() << "Remove file " << mFileID << " opened with mode " << std::hex << mMode << std::dec << LL_ENDL; } if (mHandle != LLVFSThread::nullHandle()) { - llwarns << "Removing file with pending async read" << llendl; + LL_WARNS() << "Removing file with pending async read" << LL_ENDL; } // why not seek back to the beginning of the file too? @@ -423,7 +423,7 @@ bool LLVFile::isLocked(EVFSLock lock) void LLVFile::waitForLock(EVFSLock lock) { - //LLFastTimer t(FTM_VFILE_WAIT); + //LL_RECORD_BLOCK_TIME(FTM_VFILE_WAIT); // spin until the lock clears while (isLocked(lock)) { diff --git a/indra/llvfs/llvfs.cpp b/indra/llvfs/llvfs.cpp index 1f87c14402..8d21a65dc2 100644 --- a/indra/llvfs/llvfs.cpp +++ b/indra/llvfs/llvfs.cpp @@ -619,7 +619,7 @@ void LLVFS::presizeDataFile(const U32 size) { if (!mDataFP) { - llerrs << "LLVFS::presizeDataFile() with no data file open" << llendl; + LL_ERRS() << "LLVFS::presizeDataFile() with no data file open" << LL_ENDL; return; } @@ -634,11 +634,11 @@ void LLVFS::presizeDataFile(const U32 size) if (tmp) { - llinfos << "Pre-sized VFS data file to " << ftell(mDataFP) << " bytes" << llendl; + LL_INFOS() << "Pre-sized VFS data file to " << ftell(mDataFP) << " bytes" << LL_ENDL; } else { - llwarns << "Failed to pre-size VFS data file" << llendl; + LL_WARNS() << "Failed to pre-size VFS data file" << LL_ENDL; } } @@ -648,7 +648,7 @@ BOOL LLVFS::getExists(const LLUUID &file_id, const LLAssetType::EType file_type) if (!isValid()) { - llerrs << "Attempting to use invalid VFS!" << llendl; + LL_ERRS() << "Attempting to use invalid VFS!" << LL_ENDL; } lockData(); @@ -674,7 +674,7 @@ S32 LLVFS::getSize(const LLUUID &file_id, const LLAssetType::EType file_type) if (!isValid()) { - llerrs << "Attempting to use invalid VFS!" << llendl; + LL_ERRS() << "Attempting to use invalid VFS!" << LL_ENDL; } @@ -701,7 +701,7 @@ S32 LLVFS::getMaxSize(const LLUUID &file_id, const LLAssetType::EType file_type if (!isValid()) { - llerrs << "Attempting to use invalid VFS!" << llendl; + LL_ERRS() << "Attempting to use invalid VFS!" << LL_ENDL; } lockData(); @@ -737,15 +737,15 @@ BOOL LLVFS::setMaxSize(const LLUUID &file_id, const LLAssetType::EType file_type { if (!isValid()) { - llerrs << "Attempting to use invalid VFS!" << llendl; + LL_ERRS() << "Attempting to use invalid VFS!" << LL_ENDL; } if (mReadOnly) { - llerrs << "Attempt to write to read-only VFS" << llendl; + LL_ERRS() << "Attempt to write to read-only VFS" << LL_ENDL; } if (max_size <= 0) { - llwarns << "VFS: Attempt to assign size " << max_size << " to vfile " << file_id << llendl; + LL_WARNS() << "VFS: Attempt to assign size " << max_size << " to vfile " << file_id << LL_ENDL; return FALSE; } @@ -792,7 +792,7 @@ BOOL LLVFS::setMaxSize(const LLUUID &file_id, const LLAssetType::EType file_type if (block->mLength < block->mSize) { // JC: Was a warning, but Ian says it's bad. - llerrs << "Truncating virtual file " << file_id << " to " << block->mLength << " bytes" << llendl; + LL_ERRS() << "Truncating virtual file " << file_id << " to " << block->mLength << " bytes" << LL_ENDL; block->mSize = block->mLength; } @@ -860,10 +860,10 @@ BOOL LLVFS::setMaxSize(const LLUUID &file_id, const LLAssetType::EType file_type fseek(mDataFP, new_data_location, SEEK_SET); if (fwrite(&buffer[0], block->mSize, 1, mDataFP) != 1) { - llwarns << "Short write" << llendl; + LL_WARNS() << "Short write" << LL_ENDL; } } else { - llwarns << "Short read" << llendl; + LL_WARNS() << "Short read" << LL_ENDL; } } } @@ -880,7 +880,7 @@ BOOL LLVFS::setMaxSize(const LLUUID &file_id, const LLAssetType::EType file_type } else { - llwarns << "VFS: No space (" << max_size << ") to resize existing vfile " << file_id << llendl; + LL_WARNS() << "VFS: No space (" << max_size << ") to resize existing vfile " << file_id << LL_ENDL; //dumpMap(); unlockData(); dumpStatistics(); @@ -916,7 +916,7 @@ BOOL LLVFS::setMaxSize(const LLUUID &file_id, const LLAssetType::EType file_type } else { - llwarns << "VFS: No space (" << max_size << ") for new virtual file " << file_id << llendl; + LL_WARNS() << "VFS: No space (" << max_size << ") for new virtual file " << file_id << LL_ENDL; //dumpMap(); unlockData(); dumpStatistics(); @@ -935,11 +935,11 @@ void LLVFS::renameFile(const LLUUID &file_id, const LLAssetType::EType file_type { if (!isValid()) { - llerrs << "Attempting to use invalid VFS!" << llendl; + LL_ERRS() << "Attempting to use invalid VFS!" << LL_ENDL; } if (mReadOnly) { - llerrs << "Attempt to write to read-only VFS" << llendl; + LL_ERRS() << "Attempt to write to read-only VFS" << LL_ENDL; } lockData(); @@ -971,7 +971,7 @@ void LLVFS::renameFile(const LLUUID &file_id, const LLAssetType::EType file_type { if(dest_block->mLocks[i]) { - llerrs << "Renaming VFS block to a locked file." << llendl; + LL_ERRS() << "Renaming VFS block to a locked file." << LL_ENDL; } dest_block->mLocks[i] = src_block->mLocks[i]; } @@ -991,7 +991,7 @@ void LLVFS::renameFile(const LLUUID &file_id, const LLAssetType::EType file_type } else { - llwarns << "VFS: Attempt to rename nonexistent vfile " << file_id << ":" << file_type << llendl; + LL_WARNS() << "VFS: Attempt to rename nonexistent vfile " << file_id << ":" << file_type << LL_ENDL; } unlockData(); } @@ -1023,11 +1023,11 @@ void LLVFS::removeFile(const LLUUID &file_id, const LLAssetType::EType file_type { if (!isValid()) { - llerrs << "Attempting to use invalid VFS!" << llendl; + LL_ERRS() << "Attempting to use invalid VFS!" << LL_ENDL; } if (mReadOnly) { - llerrs << "Attempt to write to read-only VFS" << llendl; + LL_ERRS() << "Attempt to write to read-only VFS" << LL_ENDL; } lockData(); @@ -1041,7 +1041,7 @@ void LLVFS::removeFile(const LLUUID &file_id, const LLAssetType::EType file_type } else { - llwarns << "VFS: attempting to remove nonexistent file " << file_id << " type " << file_type << llendl; + LL_WARNS() << "VFS: attempting to remove nonexistent file " << file_id << " type " << file_type << LL_ENDL; } unlockData(); @@ -1054,7 +1054,7 @@ S32 LLVFS::getData(const LLUUID &file_id, const LLAssetType::EType file_type, U8 if (!isValid()) { - llerrs << "Attempting to use invalid VFS!" << llendl; + LL_ERRS() << "Attempting to use invalid VFS!" << LL_ENDL; } llassert(location >= 0); llassert(length >= 0); @@ -1073,7 +1073,7 @@ S32 LLVFS::getData(const LLUUID &file_id, const LLAssetType::EType file_type, U8 if (location > block->mSize) { - llwarns << "VFS: Attempt to read location " << location << " in file " << file_id << " of length " << block->mSize << llendl; + LL_WARNS() << "VFS: Attempt to read location " << location << " in file " << file_id << " of length " << block->mSize << LL_ENDL; } else { @@ -1101,11 +1101,11 @@ S32 LLVFS::storeData(const LLUUID &file_id, const LLAssetType::EType file_type, { if (!isValid()) { - llerrs << "Attempting to use invalid VFS!" << llendl; + LL_ERRS() << "Attempting to use invalid VFS!" << LL_ENDL; } if (mReadOnly) { - llerrs << "Attempt to write to read-only VFS" << llendl; + LL_ERRS() << "Attempt to write to read-only VFS" << LL_ENDL; } llassert(length > 0); @@ -1130,22 +1130,22 @@ S32 LLVFS::storeData(const LLUUID &file_id, const LLAssetType::EType file_type, if (block->mLength == BLOCK_LENGTH_INVALID) { // Block was removed, ignore write - llwarns << "VFS: Attempt to write to invalid block" + LL_WARNS() << "VFS: Attempt to write to invalid block" << " in file " << file_id << " location: " << in_loc << " bytes: " << length - << llendl; + << LL_ENDL; unlockData(); return length; } else if (location > block->mLength) { - llwarns << "VFS: Attempt to write to location " << location + LL_WARNS() << "VFS: Attempt to write to location " << location << " in file " << file_id << " type " << S32(file_type) << " of size " << block->mSize << " block length " << block->mLength - << llendl; + << LL_ENDL; unlockData(); return length; } @@ -1153,7 +1153,7 @@ S32 LLVFS::storeData(const LLUUID &file_id, const LLAssetType::EType file_type, { if (length > block->mLength - location ) { - llwarns << "VFS: Truncating write to virtual file " << file_id << " type " << S32(file_type) << llendl; + LL_WARNS() << "VFS: Truncating write to virtual file " << file_id << " type " << S32(file_type) << LL_ENDL; length = block->mLength - location; } U32 file_location = location + block->mLocation; @@ -1162,7 +1162,7 @@ S32 LLVFS::storeData(const LLUUID &file_id, const LLAssetType::EType file_type, S32 write_len = (S32)fwrite(buffer, 1, length, mDataFP); if (write_len != length) { - llwarns << llformat("VFS Write Error: %d != %d",write_len,length) << llendl; + LL_WARNS() << llformat("VFS Write Error: %d != %d",write_len,length) << LL_ENDL; } // fflush(mDataFP); @@ -1225,7 +1225,7 @@ void LLVFS::decLock(const LLUUID &file_id, const LLAssetType::EType file_type, E } else { - llwarns << "VFS: Decrementing zero-value lock " << lock << llendl; + LL_WARNS() << "VFS: Decrementing zero-value lock " << lock << LL_ENDL; } mLockCounts[lock]--; } @@ -1277,7 +1277,7 @@ void LLVFS::eraseBlockLength(LLVFSBlock *block) } if(!found_block) { - llerrs << "eraseBlock could not find block" << llendl; + LL_ERRS() << "eraseBlock could not find block" << LL_ENDL; } } @@ -1300,7 +1300,7 @@ void LLVFS::addFreeBlock(LLVFSBlock *block) size_t dbgcount = mFreeBlocksByLocation.count(block->mLocation); if(dbgcount > 0) { - llerrs << "addFreeBlock called with block already in list" << llendl; + LL_ERRS() << "addFreeBlock called with block already in list" << LL_ENDL; } #endif @@ -1329,7 +1329,7 @@ void LLVFS::addFreeBlock(LLVFSBlock *block) if (merge_prev && merge_next) { - // llinfos << "VFS merge BOTH" << llendl; + // LL_INFOS() << "VFS merge BOTH" << LL_ENDL; // Previous block is changing length (a lot), so only need to update length map. // Next block is going away completely. JC eraseBlockLength(prev_block); @@ -1343,7 +1343,7 @@ void LLVFS::addFreeBlock(LLVFSBlock *block) } else if (merge_prev) { - // llinfos << "VFS merge previous" << llendl; + // LL_INFOS() << "VFS merge previous" << LL_ENDL; // Previous block is maintaining location, only changing length, // therefore only need to update the length map. JC eraseBlockLength(prev_block); @@ -1354,7 +1354,7 @@ void LLVFS::addFreeBlock(LLVFSBlock *block) } else if (merge_next) { - // llinfos << "VFS merge next" << llendl; + // LL_INFOS() << "VFS merge next" << LL_ENDL; // Next block is changing both location and length, // so both free lists must update. JC eraseBlock(next_block); @@ -1381,7 +1381,7 @@ void LLVFS::addFreeBlock(LLVFSBlock *block) //{ // if (!isValid()) // { -// llerrs << "Attempting to use invalid VFS!" << llendl; +// LL_ERRS() << "Attempting to use invalid VFS!" << LL_ENDL; // } // // TODO: could we optimize this with hints from the calling code? // blocks_location_map_t::iterator iter = mFreeBlocksByLocation.begin(); @@ -1440,11 +1440,11 @@ void LLVFS::sync(LLVFSFileBlock *block, BOOL remove) { if (!isValid()) { - llerrs << "Attempting to use invalid VFS!" << llendl; + LL_ERRS() << "Attempting to use invalid VFS!" << LL_ENDL; } if (mReadOnly) { - llwarns << "Attempt to sync read-only VFS" << llendl; + LL_WARNS() << "Attempt to sync read-only VFS" << LL_ENDL; return; } if (block->mLength == BLOCK_LENGTH_INVALID) @@ -1454,7 +1454,7 @@ void LLVFS::sync(LLVFSFileBlock *block, BOOL remove) } if (block->mLength == 0) { - llerrs << "VFS syncing zero-length block" << llendl; + LL_ERRS() << "VFS syncing zero-length block" << LL_ENDL; } BOOL set_index_to_end = FALSE; @@ -1506,7 +1506,7 @@ void LLVFS::sync(LLVFSFileBlock *block, BOOL remove) if (fwrite(buffer, LLVFSFileBlock::SERIAL_SIZE, 1, mIndexFP) != 1) { - llwarns << "Short write" << llendl; + LL_WARNS() << "Short write" << LL_ENDL; } // *NOTE: Why was this commented out? @@ -1522,7 +1522,7 @@ LLVFSBlock *LLVFS::findFreeBlock(S32 size, LLVFSFileBlock *immune) { if (!isValid()) { - llerrs << "Attempting to use invalid VFS!" << llendl; + LL_ERRS() << "Attempting to use invalid VFS!" << LL_ENDL; } LLVFSBlock *block = NULL; @@ -1567,7 +1567,7 @@ LLVFSBlock *LLVFS::findFreeBlock(S32 size, LLVFSFileBlock *immune) if (lru_list.size() == 0) { // No more files to delete, and still not enough room! - llwarns << "VFS: Can't make " << size << " bytes of free space in VFS, giving up" << llendl; + LL_WARNS() << "VFS: Can't make " << size << " bytes of free space in VFS, giving up" << LL_ENDL; break; } @@ -1578,7 +1578,7 @@ LLVFSBlock *LLVFS::findFreeBlock(S32 size, LLVFSFileBlock *immune) { // ditch this file and look again for a free block - should find it // TODO: it'll be faster just to assign the free block and break - llinfos << "LRU: Removing " << file_block->mFileID << ":" << file_block->mFileType << llendl; + LL_INFOS() << "LRU: Removing " << file_block->mFileID << ":" << file_block->mFileType << LL_ENDL; lru_list.erase(it); removeFileBlock(file_block); file_block = NULL; @@ -1586,8 +1586,8 @@ LLVFSBlock *LLVFS::findFreeBlock(S32 size, LLVFSFileBlock *immune) } - llinfos << "VFS: LRU: Aggressive: " << (S32)lru_list.size() << " files remain" << llendl; - dumpLockCounts(); + //LL_INFOS() << "VFS: LRU: Aggressive: " << (S32)lru_list.size() << " files remain" << LL_ENDL; + //dumpLockCounts(); // Now it's time to aggressively make more space // Delete the oldest 5MB of the vfs or enough to hold the file, which ever is larger @@ -1601,7 +1601,7 @@ LLVFSBlock *LLVFS::findFreeBlock(S32 size, LLVFSFileBlock *immune) file_block = *it; // TODO: it would be great to be able to batch all these sync() calls - // llinfos << "LRU2: Removing " << file_block->mFileID << ":" << file_block->mFileType << " last accessed" << file_block->mAccessTime << llendl; + // LL_INFOS() << "LRU2: Removing " << file_block->mFileID << ":" << file_block->mFileType << " last accessed" << file_block->mAccessTime << LL_ENDL; cleaned_up += file_block->mLength; lru_list.erase(it++); @@ -1615,7 +1615,7 @@ LLVFSBlock *LLVFS::findFreeBlock(S32 size, LLVFSFileBlock *immune) F32 time = timer.getElapsedTimeF32(); if (time > 0.5f) { - llwarns << "VFS: Spent " << time << " seconds in findFreeBlock!" << llendl; + LL_WARNS() << "VFS: Spent " << time << " seconds in findFreeBlock!" << LL_ENDL; } return block; @@ -1629,7 +1629,7 @@ void LLVFS::pokeFiles() { if (!isValid()) { - llerrs << "Attempting to use invalid VFS!" << llendl; + LL_ERRS() << "Attempting to use invalid VFS!" << LL_ENDL; } U32 word; @@ -1641,7 +1641,7 @@ void LLVFS::pokeFiles() fseek(mDataFP, 0, SEEK_SET); if (fwrite(&word, sizeof(word), 1, mDataFP) != 1) { - llwarns << "Could not write to data file" << llendl; + LL_WARNS() << "Could not write to data file" << LL_ENDL; } fflush(mDataFP); } @@ -1652,7 +1652,7 @@ void LLVFS::pokeFiles() fseek(mIndexFP, 0, SEEK_SET); if (fwrite(&word, sizeof(word), 1, mIndexFP) != 1) { - llwarns << "Could not write to index file" << llendl; + LL_WARNS() << "Could not write to index file" << LL_ENDL; } fflush(mIndexFP); } @@ -1661,20 +1661,20 @@ void LLVFS::pokeFiles() void LLVFS::dumpMap() { - llinfos << "Files:" << llendl; + LL_INFOS() << "Files:" << LL_ENDL; for (fileblock_map::iterator it = mFileBlocks.begin(); it != mFileBlocks.end(); ++it) { LLVFSFileBlock *file_block = (*it).second; - llinfos << "Location: " << file_block->mLocation << "\tLength: " << file_block->mLength << "\t" << file_block->mFileID << "\t" << file_block->mFileType << llendl; + LL_INFOS() << "Location: " << file_block->mLocation << "\tLength: " << file_block->mLength << "\t" << file_block->mFileID << "\t" << file_block->mFileType << LL_ENDL; } - llinfos << "Free Blocks:" << llendl; + LL_INFOS() << "Free Blocks:" << LL_ENDL; for (blocks_location_map_t::iterator iter = mFreeBlocksByLocation.begin(), end = mFreeBlocksByLocation.end(); iter != end; iter++) { LLVFSBlock *free_block = iter->second; - llinfos << "Location: " << free_block->mLocation << "\tLength: " << free_block->mLength << llendl; + LL_INFOS() << "Location: " << free_block->mLocation << "\tLength: " << free_block->mLength << LL_ENDL; } } @@ -1698,7 +1698,7 @@ void LLVFS::audit() if (fread(&buffer[0], 1, index_size, mIndexFP) != index_size) { - llwarns << "Index truncated" << llendl; + LL_WARNS() << "Index truncated" << LL_ENDL; vfs_corrupt = TRUE; } @@ -1727,7 +1727,7 @@ void LLVFS::audit() { if (mFileBlocks.find(*block) == mFileBlocks.end()) { - llwarns << "VFile " << block->mFileID << ":" << block->mFileType << " on disk, not in memory, loc " << block->mIndexLocation << llendl; + LL_WARNS() << "VFile " << block->mFileID << ":" << block->mFileType << " on disk, not in memory, loc " << block->mIndexLocation << LL_ENDL; } else if (found_files.find(*block) != found_files.end()) { @@ -1739,22 +1739,22 @@ void LLVFS::audit() mIndexFP = NULL; unlockAndClose(mDataFP); mDataFP = NULL; - llwarns << "VFS: Original block index " << block->mIndexLocation + LL_WARNS() << "VFS: Original block index " << block->mIndexLocation << " location " << block->mLocation << " length " << block->mLength << " size " << block->mSize << " id " << block->mFileID << " type " << block->mFileType - << llendl; - llwarns << "VFS: Duplicate block index " << dupe->mIndexLocation + << LL_ENDL; + LL_WARNS() << "VFS: Duplicate block index " << dupe->mIndexLocation << " location " << dupe->mLocation << " length " << dupe->mLength << " size " << dupe->mSize << " id " << dupe->mFileID << " type " << dupe->mFileType - << llendl; - llwarns << "VFS: Index size " << index_size << llendl; - llwarns << "VFS: INDEX CORRUPT" << llendl; + << LL_ENDL; + LL_WARNS() << "VFS: Index size " << index_size << LL_ENDL; + LL_WARNS() << "VFS: INDEX CORRUPT" << LL_ENDL; vfs_corrupt = TRUE; break; } @@ -1767,7 +1767,7 @@ void LLVFS::audit() { if (block->mLength) { - llwarns << "VFile " << block->mFileID << ":" << block->mFileType << " corrupt on disk" << llendl; + LL_WARNS() << "VFile " << block->mFileID << ":" << block->mFileType << " corrupt on disk" << LL_ENDL; } // else this is just a hole } @@ -1783,19 +1783,19 @@ void LLVFS::audit() { if (! found_files.count(*block)) { - llwarns << "VFile " << block->mFileID << ":" << block->mFileType << " in memory, not on disk, loc " << block->mIndexLocation<< llendl; + LL_WARNS() << "VFile " << block->mFileID << ":" << block->mFileType << " in memory, not on disk, loc " << block->mIndexLocation<< LL_ENDL; fseek(mIndexFP, block->mIndexLocation, SEEK_SET); U8 buf[LLVFSFileBlock::SERIAL_SIZE]; if (fread(buf, LLVFSFileBlock::SERIAL_SIZE, 1, mIndexFP) != 1) { - llwarns << "VFile " << block->mFileID - << " gave short read" << llendl; + LL_WARNS() << "VFile " << block->mFileID + << " gave short read" << LL_ENDL; } LLVFSFileBlock disk_block; disk_block.deserialize(buf, block->mIndexLocation); - llwarns << "Instead found " << disk_block.mFileID << ":" << block->mFileType << llendl; + LL_WARNS() << "Instead found " << disk_block.mFileID << ":" << block->mFileType << LL_ENDL; } else { @@ -1809,10 +1809,10 @@ void LLVFS::audit() iter != found_files.end(); iter++) { LLVFSFileBlock* block = iter->second; - llwarns << "VFile " << block->mFileID << ":" << block->mFileType << " szie:" << block->mSize << " leftover" << llendl; + LL_WARNS() << "VFile " << block->mFileID << ":" << block->mFileType << " szie:" << block->mSize << " leftover" << LL_ENDL; } - llinfos << "VFS: audit OK" << llendl; + LL_INFOS() << "VFS: audit OK" << LL_ENDL; // mutex released by LLMutexLock() destructor. } @@ -1839,12 +1839,12 @@ void LLVFS::checkMem() S32 index_loc = *iter; if (index_loc == block->mIndexLocation) { - llwarns << "VFile block " << block->mFileID << ":" << block->mFileType << " is marked as a hole" << llendl; + LL_WARNS() << "VFile block " << block->mFileID << ":" << block->mFileType << " is marked as a hole" << LL_ENDL; } } } - llinfos << "VFS: mem check OK" << llendl; + LL_INFOS() << "VFS: mem check OK" << LL_ENDL; unlockData(); } @@ -1854,7 +1854,7 @@ void LLVFS::dumpLockCounts() S32 i; for (i = 0; i < VFSLOCK_COUNT; i++) { - llinfos << "LockType: " << i << ": " << mLockCounts[i] << llendl; + LL_INFOS() << "LockType: " << i << ": " << mLockCounts[i] << LL_ENDL; } } @@ -1879,7 +1879,7 @@ void LLVFS::dumpStatistics() } else if (file_block->mLength <= 0) { - llinfos << "Bad file block at: " << file_block->mLocation << "\tLength: " << file_block->mLength << "\t" << file_block->mFileID << "\t" << file_block->mFileType << llendl; + LL_INFOS() << "Bad file block at: " << file_block->mLocation << "\tLength: " << file_block->mLength << "\t" << file_block->mFileID << "\t" << file_block->mFileType << LL_ENDL; size_counts[file_block->mLength]++; location_counts[file_block->mLocation]++; } @@ -1901,13 +1901,13 @@ void LLVFS::dumpStatistics() { S32 size = it->first; S32 size_count = it->second; - llinfos << "Bad files size " << size << " count " << size_count << llendl; + LL_INFOS() << "Bad files size " << size << " count " << size_count << LL_ENDL; } for (std::map::iterator it = location_counts.begin(); it != location_counts.end(); ++it) { U32 location = it->first; S32 location_count = it->second; - llinfos << "Bad files location " << location << " count " << location_count << llendl; + LL_INFOS() << "Bad files location " << location << " count " << location_count << LL_ENDL; } // Investigate free list. @@ -1921,14 +1921,14 @@ void LLVFS::dumpStatistics() LLVFSBlock *free_block = iter->second; if (free_block->mLength <= 0) { - llinfos << "Bad free block at: " << free_block->mLocation << "\tLength: " << free_block->mLength << llendl; + LL_INFOS() << "Bad free block at: " << free_block->mLocation << "\tLength: " << free_block->mLength << LL_ENDL; } else { - llinfos << "Block: " << free_block->mLocation + LL_INFOS() << "Block: " << free_block->mLocation << "\tLength: " << free_block->mLength << "\tEnd: " << free_block->mLocation + free_block->mLength - << llendl; + << LL_ENDL; total_free_size += free_block->mLength; } @@ -1943,38 +1943,38 @@ void LLVFS::dumpStatistics() // Dump histogram of free block sizes for (std::map::iterator it = free_length_counts.begin(); it != free_length_counts.end(); ++it) { - llinfos << "Free length " << it->first << " count " << it->second << llendl; + LL_INFOS() << "Free length " << it->first << " count " << it->second << LL_ENDL; } - llinfos << "Invalid blocks: " << invalid_file_count << llendl; - llinfos << "File blocks: " << mFileBlocks.size() << llendl; + LL_INFOS() << "Invalid blocks: " << invalid_file_count << LL_ENDL; + LL_INFOS() << "File blocks: " << mFileBlocks.size() << LL_ENDL; S32 length_list_count = (S32)mFreeBlocksByLength.size(); S32 location_list_count = (S32)mFreeBlocksByLocation.size(); if (length_list_count == location_list_count) { - llinfos << "Free list lengths match, free blocks: " << location_list_count << llendl; + LL_INFOS() << "Free list lengths match, free blocks: " << location_list_count << LL_ENDL; } else { - llwarns << "Free list lengths do not match!" << llendl; - llwarns << "By length: " << length_list_count << llendl; - llwarns << "By location: " << location_list_count << llendl; + LL_WARNS() << "Free list lengths do not match!" << LL_ENDL; + LL_WARNS() << "By length: " << length_list_count << LL_ENDL; + LL_WARNS() << "By location: " << location_list_count << LL_ENDL; } - llinfos << "Max file: " << max_file_size/1024 << "K" << llendl; - llinfos << "Max free: " << max_free_size/1024 << "K" << llendl; - llinfos << "Total file size: " << total_file_size/1024 << "K" << llendl; - llinfos << "Total free size: " << total_free_size/1024 << "K" << llendl; - llinfos << "Sum: " << (total_file_size + total_free_size) << " bytes" << llendl; - llinfos << llformat("%.0f%% full",((F32)(total_file_size)/(F32)(total_file_size+total_free_size))*100.f) << llendl; + LL_INFOS() << "Max file: " << max_file_size/1024 << "K" << LL_ENDL; + LL_INFOS() << "Max free: " << max_free_size/1024 << "K" << LL_ENDL; + LL_INFOS() << "Total file size: " << total_file_size/1024 << "K" << LL_ENDL; + LL_INFOS() << "Total free size: " << total_free_size/1024 << "K" << LL_ENDL; + LL_INFOS() << "Sum: " << (total_file_size + total_free_size) << " bytes" << LL_ENDL; + LL_INFOS() << llformat("%.0f%% full",((F32)(total_file_size)/(F32)(total_file_size+total_free_size))*100.f) << LL_ENDL; - llinfos << " " << llendl; + LL_INFOS() << " " << LL_ENDL; for (std::map >::iterator iter = filetype_counts.begin(); iter != filetype_counts.end(); ++iter) { - llinfos << "Type: " << LLAssetType::getDesc(iter->first) + LL_INFOS() << "Type: " << LLAssetType::getDesc(iter->first) << " Count: " << iter->second.first - << " Bytes: " << (iter->second.second>>20) << " MB" << llendl; + << " Bytes: " << (iter->second.second>>20) << " MB" << LL_ENDL; } // Look for potential merges @@ -1989,7 +1989,7 @@ void LLVFS::dumpStatistics() LLVFSBlock *second_block = iter->second; if (first_block->mLocation + first_block->mLength == second_block->mLocation) { - llinfos << "Potential merge at " << first_block->mLocation << llendl; + LL_INFOS() << "Potential merge at " << first_block->mLocation << LL_ENDL; } first_block = second_block; } @@ -2046,10 +2046,10 @@ void LLVFS::listFiles() { LLUUID id = file_spec.mFileID; std::string extension = get_extension(file_spec.mFileType); - llinfos << " File: " << id + LL_INFOS() << " File: " << id << " Type: " << LLAssetType::getDesc(file_spec.mFileType) << " Size: " << size - << llendl; + << LL_ENDL; } } @@ -2090,7 +2090,7 @@ void LLVFS::dumpFiles() std::string extension = get_extension(type); std::string filename = id.asString() + extension; - llinfos << " Writing " << filename << llendl; + LL_INFOS() << " Writing " << filename << LL_ENDL; LLAPRFile outfile(filename, LL_APR_WB); outfile.write(&buffer[0], size); @@ -2102,7 +2102,7 @@ void LLVFS::dumpFiles() unlockData(); - llinfos << "Extracted " << files_extracted << " files out of " << mFileBlocks.size() << llendl; + LL_INFOS() << "Extracted " << files_extracted << " files out of " << mFileBlocks.size() << LL_ENDL; } //============================================================================ diff --git a/indra/llvfs/llvfs.h b/indra/llvfs/llvfs.h index 87a83c1924..696773db67 100644 --- a/indra/llvfs/llvfs.h +++ b/indra/llvfs/llvfs.h @@ -29,7 +29,6 @@ #include #include "lluuid.h" -#include "linked_lists.h" #include "llassettype.h" #include "llthread.h" diff --git a/indra/llvfs/llvfsthread.cpp b/indra/llvfs/llvfsthread.cpp index a57e2b15ab..8cd85929e2 100644 --- a/indra/llvfs/llvfsthread.cpp +++ b/indra/llvfs/llvfsthread.cpp @@ -88,7 +88,7 @@ LLVFSThread::handle_t LLVFSThread::read(LLVFS* vfs, const LLUUID &file_id, const bool res = addRequest(req); if (!res) { - llerrs << "LLVFSThread::read called after LLVFSThread::cleanupClass()" << llendl; + LL_ERRS() << "LLVFSThread::read called after LLVFSThread::cleanupClass()" << LL_ENDL; req->deleteRequest(); handle = nullHandle(); } @@ -107,7 +107,7 @@ S32 LLVFSThread::readImmediate(LLVFS* vfs, const LLUUID &file_id, const LLAssetT S32 res = addRequest(req) ? 1 : 0; if (res == 0) { - llerrs << "LLVFSThread::read called after LLVFSThread::cleanupClass()" << llendl; + LL_ERRS() << "LLVFSThread::read called after LLVFSThread::cleanupClass()" << LL_ENDL; req->deleteRequest(); } else @@ -130,7 +130,7 @@ LLVFSThread::handle_t LLVFSThread::write(LLVFS* vfs, const LLUUID &file_id, cons bool res = addRequest(req); if (!res) { - llerrs << "LLVFSThread::read called after LLVFSThread::cleanupClass()" << llendl; + LL_ERRS() << "LLVFSThread::read called after LLVFSThread::cleanupClass()" << LL_ENDL; req->deleteRequest(); handle = nullHandle(); } @@ -149,7 +149,7 @@ S32 LLVFSThread::writeImmediate(LLVFS* vfs, const LLUUID &file_id, const LLAsset S32 res = addRequest(req) ? 1 : 0; if (res == 0) { - llerrs << "LLVFSThread::read called after LLVFSThread::cleanupClass()" << llendl; + LL_ERRS() << "LLVFSThread::read called after LLVFSThread::cleanupClass()" << LL_ENDL; req->deleteRequest(); } else @@ -175,7 +175,7 @@ S32 LLVFSThread::writeImmediate(LLVFS* vfs, const LLUUID &file_id, const LLAsset // bool res = addRequest(req); // if (!res) // { -// llerrs << "LLVFSThread::read called after LLVFSThread::cleanupClass()" << llendl; +// LL_ERRS() << "LLVFSThread::read called after LLVFSThread::cleanupClass()" << LL_ENDL; // req->deleteRequest(); // handle = nullHandle(); // } @@ -203,17 +203,17 @@ LLVFSThread::Request::Request(handle_t handle, U32 priority, U32 flags, if (numbytes <= 0 && mOperation != FILE_RENAME) { - llwarns << "LLVFSThread: Request with numbytes = " << numbytes + LL_WARNS() << "LLVFSThread: Request with numbytes = " << numbytes << " operation = " << op << " offset " << offset - << " file_type " << file_type << llendl; + << " file_type " << file_type << LL_ENDL; } if (mOperation == FILE_WRITE) { S32 blocksize = mVFS->getMaxSize(mFileID, mFileType); if (blocksize < 0) { - llwarns << "VFS write to temporary block (shouldn't happen)" << llendl; + LL_WARNS() << "VFS write to temporary block (shouldn't happen)" << LL_ENDL; } mVFS->incLock(mFileID, mFileType, VFSLOCK_APPEND); } @@ -248,7 +248,7 @@ void LLVFSThread::Request::deleteRequest() { if (getStatus() == STATUS_QUEUED) { - llerrs << "Attempt to delete a queued LLVFSThread::Request!" << llendl; + LL_ERRS() << "Attempt to delete a queued LLVFSThread::Request!" << LL_ENDL; } if (mOperation == FILE_WRITE) { @@ -273,13 +273,13 @@ bool LLVFSThread::Request::processRequest() llassert(mOffset >= 0); mBytesRead = mVFS->getData(mFileID, mFileType, mBuffer, mOffset, mBytes); complete = true; - //llinfos << llformat("LLVFSThread::READ '%s': %d bytes arg:%d",getFilename(),mBytesRead) << llendl; + //LL_INFOS() << llformat("LLVFSThread::READ '%s': %d bytes arg:%d",getFilename(),mBytesRead) << LL_ENDL; } else if (mOperation == FILE_WRITE) { mBytesRead = mVFS->storeData(mFileID, mFileType, mBuffer, mOffset, mBytes); complete = true; - //llinfos << llformat("LLVFSThread::WRITE '%s': %d bytes arg:%d",getFilename(),mBytesRead) << llendl; + //LL_INFOS() << llformat("LLVFSThread::WRITE '%s': %d bytes arg:%d",getFilename(),mBytesRead) << LL_ENDL; } else if (mOperation == FILE_RENAME) { @@ -288,11 +288,11 @@ bool LLVFSThread::Request::processRequest() mVFS->renameFile(mFileID, mFileType, *new_idp, new_type); mFileID = *new_idp; complete = true; - //llinfos << llformat("LLVFSThread::RENAME '%s': %d bytes arg:%d",getFilename(),mBytesRead) << llendl; + //LL_INFOS() << llformat("LLVFSThread::RENAME '%s': %d bytes arg:%d",getFilename(),mBytesRead) << LL_ENDL; } else { - llerrs << llformat("LLVFSThread::unknown operation: %d", mOperation) << llendl; + LL_ERRS() << llformat("LLVFSThread::unknown operation: %d", mOperation) << LL_ENDL; } return complete; } diff --git a/indra/llwindow/CMakeLists.txt b/indra/llwindow/CMakeLists.txt index c7d9509e17..73a7aa59b4 100644 --- a/indra/llwindow/CMakeLists.txt +++ b/indra/llwindow/CMakeLists.txt @@ -11,7 +11,6 @@ project(llwindow) include(00-Common) -include(DirectX) include(LLCommon) include(LLImage) include(LLMath) @@ -68,7 +67,6 @@ if (LINUX) ${LLMATH_LIBRARIES} ${LLRENDER_LIBRARIES} ${LLVFS_LIBRARIES} - ${LLWINDOW_LIBRARIES} ${LLXML_LIBRARIES} ${UI_LIBRARIES} # for GTK ${SDL_LIBRARY} @@ -145,11 +143,9 @@ if (llwindow_HEADER_FILES) endif (llwindow_HEADER_FILES) list(APPEND viewer_SOURCE_FILES ${viewer_HEADER_FILES}) -add_library (llwindow + add_library (llwindow ${llwindow_SOURCE_FILES} ${viewer_SOURCE_FILES} ) -add_dependencies(llwindow prepare) -target_link_libraries (llwindow ${llwindow_LINK_LIBRARIES}) - +target_link_libraries (llwindow PUBLIC llcommon ${llwindow_LINK_LIBRARIES}) diff --git a/indra/llwindow/GL/glh_extensions.h b/indra/llwindow/GL/glh_extensions.h deleted file mode 100644 index 554cb1731f..0000000000 --- a/indra/llwindow/GL/glh_extensions.h +++ /dev/null @@ -1,211 +0,0 @@ -/* - * glh_extensions.h - * $LicenseInfo:firstyear=2006&license=mit$ (mit used here to satisfy validity checker) - * Copyright (C) 2006, NVIDIA - * From nVidia Corporation, downloaded 2006-12-18 from: - * http://developer.nvidia.com/attach/8196 - * ("NVParse Library with Source (.zip) (2390 KB)") - * - * License (quoted from license_info.txt in aforementioned file): - * "The files bison.exe, bison.simple, and flex.exe are covered by - * the GPL. All other files in this distribution can be used however - * you want." - * $/LicenseInfo$ - - */ - -#ifndef GLH_EXTENSIONS -#define GLH_EXTENSIONS - -#include -#include - -#ifdef _WIN32 -# include -#endif - -#ifndef __APPLE__ -#include -#endif - -#ifdef _WIN32 -# include "GL/wglext.h" -#endif - -#define CHECK_MEMORY(ptr) \ - if (NULL == ptr) { \ - printf("Error allocating memory in file %s, line %d\n", __FILE__, __LINE__); \ - exit(-1); \ - } - -#ifdef GLH_EXT_SINGLE_FILE -# define GLH_EXTENSIONS_SINGLE_FILE // have to do this because glh_genext.h unsets GLH_EXT_SINGLE_FILE -#endif - -#include "glh_genext.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef GLH_EXTENSIONS_SINGLE_FILE - -class GLHExts -{ -public: - GLHExts() - { - mSysExts = NULL; -// mUnsupportedExts = NULL; - } - ~GLHExts() - { - if (mSysExts) - { - free(mSysExts); - } -// if (mUnsupportedExts) -// { -// free(mUnsupportedExts); -// } - } - char *mSysExts; -// char *mUnsupportedExts; -}; - -GLHExts gGLHExts; - -static int ExtensionExists(const char* extName, const char* sysExts) -{ - char *padExtName = (char*)malloc(strlen(extName) + 2); - strcat(strcpy(padExtName, extName), " "); - - if (0 == strcmp(extName, "GL_VERSION_1_2")) { - const char *version = (const char*)glGetString(GL_VERSION); - if (strstr(version, "1.0") == version || strstr(version, "1.1") == version) { - return FALSE; - } else { - return TRUE; - } - } - if (strstr(sysExts, padExtName)) { - free(padExtName); - return TRUE; - } else { - free(padExtName); - return FALSE; - } -} - -static const char* EatWhiteSpace(const char *str) -{ - for (; *str && (' ' == *str || '\t' == *str || '\n' == *str); str++); - return str; -} - -static const char* EatNonWhiteSpace(const char *str) -{ - for (; *str && (' ' != *str && '\t' != *str && '\n' != *str); str++); - return str; -} - - -int glh_init_extensions(const char *origReqExts) -{ - // Length of requested extensions string - //unsigned reqExtsLen; - char *reqExts; - // Ptr for individual extensions within reqExts - char *reqExt; - int success = TRUE; - - // build space-padded extension string - if (NULL == gGLHExts.mSysExts) { - const char *extensions = (const char*)glGetString(GL_EXTENSIONS); - int sysExtsLen = (int)strlen(extensions); - const char *winsys_extensions = 0; - int winsysExtsLen = 0; -#ifdef _WIN32 - { - PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = 0; - wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB"); - if(wglGetExtensionsStringARB) - { - winsys_extensions = wglGetExtensionsStringARB(wglGetCurrentDC()); - winsysExtsLen = (S32)strlen(winsys_extensions); - } - } -#endif - // Add 2 bytes, one for padding space, one for terminating NULL - gGLHExts.mSysExts = (char*)malloc(sysExtsLen + winsysExtsLen + 3); - CHECK_MEMORY(gGLHExts.mSysExts); - strcpy(gGLHExts.mSysExts, extensions); - gGLHExts.mSysExts[sysExtsLen] = ' '; - gGLHExts.mSysExts[sysExtsLen + 1] = 0; - if (winsysExtsLen) - { - strcat(gGLHExts.mSysExts, winsys_extensions); - } - gGLHExts.mSysExts[sysExtsLen + 1 + winsysExtsLen] = ' '; - gGLHExts.mSysExts[sysExtsLen + 1 + winsysExtsLen + 1] = 0; - } - - if (NULL == origReqExts) - { - return TRUE; - } - reqExts = strdup(origReqExts); - /* - reqExtsLen = (S32)strlen(reqExts); - if (NULL == gGLHExts.mUnsupportedExts) - { - gGLHExts.mUnsupportedExts = (char*)malloc(reqExtsLen + 1); - } - else if (reqExtsLen > strlen(gGLHExts.mUnsupportedExts)) - { - gGLHExts.mUnsupportedExts = (char*)realloc(gGLHExts.mUnsupportedExts, reqExtsLen + 1); - } - CHECK_MEMORY(gGLHExts.mUnsupportedExts); - *gGLHExts.mUnsupportedExts = 0; - */ - - // Parse requested extension list - for (reqExt = reqExts; - (reqExt = (char*)EatWhiteSpace(reqExt)) && *reqExt; - reqExt = (char*)EatNonWhiteSpace(reqExt)) - { - char *extEnd = (char*)EatNonWhiteSpace(reqExt); - char saveChar = *extEnd; - *extEnd = (char)0; - - if (!ExtensionExists(reqExt, gGLHExts.mSysExts) || - !glh_init_extension(reqExt)) { - /* - // add reqExt to end of unsupportedExts - strcat(gGLHExts.mUnsupportedExts, reqExt); - strcat(gGLHExts.mUnsupportedExts, " "); - */ - success = FALSE; - } - *extEnd = saveChar; - } - free(reqExts); - return success; -} - -const char* glh_get_unsupported_extensions() -{ - return ""; -// return (const char*)gGLHExts.mUnsupportedExts; -} - -#else -int glh_init_extensions(const char *origReqExts); -const char* glh_get_unsupported_extensions(); -#endif /* GLH_EXT_SINGLE_FILE */ - -#ifdef __cplusplus -} -#endif - -#endif /* GLH_EXTENSIONS */ diff --git a/indra/llwindow/GL/glh_genext.h b/indra/llwindow/GL/glh_genext.h deleted file mode 100644 index 8d42025198..0000000000 --- a/indra/llwindow/GL/glh_genext.h +++ /dev/null @@ -1,1671 +0,0 @@ -/* - * glh_genext.h - * From nVidia Corporation, downloaded 2006-12-18 from: - * http://developer.nvidia.com/attach/8196 - * ("NVParse Library with Source (.zip) (2390 KB)") - * - * License (quoted from license_info.txt in aforementioned file): - * "The files bison.exe, bison.simple, and flex.exe are covered by - * the GPL. All other files in this distribution can be used however - * you want." - */ - -/* File generated by extgen.cpp -- do not modify */ -#ifndef GLH_GENEXT_H -#define GLH_GENEXT_H - -// MBW -- None of this is necessary on Mac OS. -#ifndef __APPLE__ - -#include -#include - -#ifdef _WIN32 /* supports windows, x -- need to generalize */ -# include -# define GLH_EXT_GET_PROC_ADDRESS(p) wglGetProcAddress(p) -#else if GLX_VERSION_1_3 -# include -# define GLH_EXT_GET_PROC_ADDRESS(p) glXGetProcAddressARB(p) -#endif - -#ifdef GLH_EXT_SINGLE_FILE - #define GLH_EXTERN - #define GLH_INITIALIZER = 0 -#else - #define GLH_EXTERN extern - #define GLH_INITIALIZER -#endif - -#define GLH__PREPROCESSOR_GYMNASTICS2(a,b) a##b -#define GLH__PREPROCESSOR_GYMNASTICS(a,b) GLH__PREPROCESSOR_GYMNASTICS2(a,b) - -#ifndef GLH_EXT_PREFIX -# define GLH_EXT_NAME(a) a -#else -# define GLH_EXT_NAME(a) GLH__PREPROCESSOR_GYMNASTICS(GLH_EXT_PREFIX,a) -#endif - -#ifndef _WIN32 -# ifndef GLH_CORE_1_2_PREFIX -# define GLH_CORE_1_2_PREFIX _ -# endif -#endif - -#ifndef GLH_CORE_1_2_PREFIX -# define GLH_CORE_1_2_NAME(a) a -#else -# define GLH_CORE_1_2_NAME(a) GLH__PREPROCESSOR_GYMNASTICS(GLH_CORE_1_2_PREFIX,a) -#endif - -#ifdef GL_ARB_multitexture - GLH_EXTERN PFNGLMULTITEXCOORD1DARBPROC GLH_EXT_NAME(glMultiTexCoord1dARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD1DVARBPROC GLH_EXT_NAME(glMultiTexCoord1dvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD1FARBPROC GLH_EXT_NAME(glMultiTexCoord1fARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD1FVARBPROC GLH_EXT_NAME(glMultiTexCoord1fvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD1IARBPROC GLH_EXT_NAME(glMultiTexCoord1iARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD1IVARBPROC GLH_EXT_NAME(glMultiTexCoord1ivARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD1SARBPROC GLH_EXT_NAME(glMultiTexCoord1sARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD1SVARBPROC GLH_EXT_NAME(glMultiTexCoord1svARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD2DARBPROC GLH_EXT_NAME(glMultiTexCoord2dARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD2DVARBPROC GLH_EXT_NAME(glMultiTexCoord2dvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD2FARBPROC GLH_EXT_NAME(glMultiTexCoord2fARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD2FVARBPROC GLH_EXT_NAME(glMultiTexCoord2fvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD2IARBPROC GLH_EXT_NAME(glMultiTexCoord2iARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD2IVARBPROC GLH_EXT_NAME(glMultiTexCoord2ivARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD2SARBPROC GLH_EXT_NAME(glMultiTexCoord2sARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD2SVARBPROC GLH_EXT_NAME(glMultiTexCoord2svARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD3DARBPROC GLH_EXT_NAME(glMultiTexCoord3dARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD3DVARBPROC GLH_EXT_NAME(glMultiTexCoord3dvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD3FARBPROC GLH_EXT_NAME(glMultiTexCoord3fARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD3FVARBPROC GLH_EXT_NAME(glMultiTexCoord3fvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD3IARBPROC GLH_EXT_NAME(glMultiTexCoord3iARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD3IVARBPROC GLH_EXT_NAME(glMultiTexCoord3ivARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD3SARBPROC GLH_EXT_NAME(glMultiTexCoord3sARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD3SVARBPROC GLH_EXT_NAME(glMultiTexCoord3svARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD4DARBPROC GLH_EXT_NAME(glMultiTexCoord4dARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD4DVARBPROC GLH_EXT_NAME(glMultiTexCoord4dvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD4FARBPROC GLH_EXT_NAME(glMultiTexCoord4fARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD4FVARBPROC GLH_EXT_NAME(glMultiTexCoord4fvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD4IARBPROC GLH_EXT_NAME(glMultiTexCoord4iARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD4IVARBPROC GLH_EXT_NAME(glMultiTexCoord4ivARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD4SARBPROC GLH_EXT_NAME(glMultiTexCoord4sARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD4SVARBPROC GLH_EXT_NAME(glMultiTexCoord4svARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLACTIVETEXTUREARBPROC GLH_EXT_NAME(glActiveTextureARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLCLIENTACTIVETEXTUREARBPROC GLH_EXT_NAME(glClientActiveTextureARB) GLH_INITIALIZER; -#endif - -#ifdef GL_ARB_texture_border_clamp -#endif - -#ifdef GL_ARB_texture_compression - GLH_EXTERN PFNGLCOMPRESSEDTEXIMAGE3DARBPROC GLH_EXT_NAME(glCompressedTexImage3DARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLCOMPRESSEDTEXIMAGE2DARBPROC GLH_EXT_NAME(glCompressedTexImage2DARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLCOMPRESSEDTEXIMAGE1DARBPROC GLH_EXT_NAME(glCompressedTexImage1DARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC GLH_EXT_NAME(glCompressedTexSubImage3DARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC GLH_EXT_NAME(glCompressedTexSubImage2DARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC GLH_EXT_NAME(glCompressedTexSubImage1DARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETCOMPRESSEDTEXIMAGEARBPROC GLH_EXT_NAME(glGetCompressedTexImageARB) GLH_INITIALIZER; -#endif - -#ifdef GL_ARB_texture_cube_map -#endif - -#ifdef GL_ARB_transpose_matrix - GLH_EXTERN PFNGLLOADTRANSPOSEMATRIXFARBPROC GLH_EXT_NAME(glLoadTransposeMatrixfARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLLOADTRANSPOSEMATRIXDARBPROC GLH_EXT_NAME(glLoadTransposeMatrixdARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTTRANSPOSEMATRIXFARBPROC GLH_EXT_NAME(glMultTransposeMatrixfARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTTRANSPOSEMATRIXDARBPROC GLH_EXT_NAME(glMultTransposeMatrixdARB) GLH_INITIALIZER; -#endif - -#ifdef GL_ARB_vertex_program - GLH_EXTERN PFNGLVERTEXATTRIB1SARBPROC GLH_EXT_NAME(glVertexAttrib1sARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB1FARBPROC GLH_EXT_NAME(glVertexAttrib1fARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB1DARBPROC GLH_EXT_NAME(glVertexAttrib1dARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB2SARBPROC GLH_EXT_NAME(glVertexAttrib2sARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB2FARBPROC GLH_EXT_NAME(glVertexAttrib2fARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB2DARBPROC GLH_EXT_NAME(glVertexAttrib2dARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB3SARBPROC GLH_EXT_NAME(glVertexAttrib3sARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB3FARBPROC GLH_EXT_NAME(glVertexAttrib3fARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB3DARBPROC GLH_EXT_NAME(glVertexAttrib3dARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB4SARBPROC GLH_EXT_NAME(glVertexAttrib4sARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB4FARBPROC GLH_EXT_NAME(glVertexAttrib4fARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB4DARBPROC GLH_EXT_NAME(glVertexAttrib4dARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB4NUBARBPROC GLH_EXT_NAME(glVertexAttrib4NubARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB1SVARBPROC GLH_EXT_NAME(glVertexAttrib1svARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB1FVARBPROC GLH_EXT_NAME(glVertexAttrib1fvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB1DVARBPROC GLH_EXT_NAME(glVertexAttrib1dvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB2SVARBPROC GLH_EXT_NAME(glVertexAttrib2svARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB2FVARBPROC GLH_EXT_NAME(glVertexAttrib2fvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB2DVARBPROC GLH_EXT_NAME(glVertexAttrib2dvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB3SVARBPROC GLH_EXT_NAME(glVertexAttrib3svARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB3FVARBPROC GLH_EXT_NAME(glVertexAttrib3fvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB3DVARBPROC GLH_EXT_NAME(glVertexAttrib3dvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB4BVARBPROC GLH_EXT_NAME(glVertexAttrib4bvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB4SVARBPROC GLH_EXT_NAME(glVertexAttrib4svARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB4IVARBPROC GLH_EXT_NAME(glVertexAttrib4ivARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB4UBVARBPROC GLH_EXT_NAME(glVertexAttrib4ubvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB4USVARBPROC GLH_EXT_NAME(glVertexAttrib4usvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB4UIVARBPROC GLH_EXT_NAME(glVertexAttrib4uivARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB4FVARBPROC GLH_EXT_NAME(glVertexAttrib4fvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB4DVARBPROC GLH_EXT_NAME(glVertexAttrib4dvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB4NBVARBPROC GLH_EXT_NAME(glVertexAttrib4NbvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB4NSVARBPROC GLH_EXT_NAME(glVertexAttrib4NsvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB4NIVARBPROC GLH_EXT_NAME(glVertexAttrib4NivARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB4NUBVARBPROC GLH_EXT_NAME(glVertexAttrib4NubvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB4NUSVARBPROC GLH_EXT_NAME(glVertexAttrib4NusvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB4NUIVARBPROC GLH_EXT_NAME(glVertexAttrib4NuivARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIBPOINTERARBPROC GLH_EXT_NAME(glVertexAttribPointerARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLENABLEVERTEXATTRIBARRAYARBPROC GLH_EXT_NAME(glEnableVertexAttribArrayARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLDISABLEVERTEXATTRIBARRAYARBPROC GLH_EXT_NAME(glDisableVertexAttribArrayARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLPROGRAMSTRINGARBPROC GLH_EXT_NAME(glProgramStringARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLBINDPROGRAMARBPROC GLH_EXT_NAME(glBindProgramARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLDELETEPROGRAMSARBPROC GLH_EXT_NAME(glDeleteProgramsARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLGENPROGRAMSARBPROC GLH_EXT_NAME(glGenProgramsARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLPROGRAMENVPARAMETER4DARBPROC GLH_EXT_NAME(glProgramEnvParameter4dARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLPROGRAMENVPARAMETER4DVARBPROC GLH_EXT_NAME(glProgramEnvParameter4dvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLPROGRAMENVPARAMETER4FARBPROC GLH_EXT_NAME(glProgramEnvParameter4fARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLPROGRAMENVPARAMETER4FVARBPROC GLH_EXT_NAME(glProgramEnvParameter4fvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLPROGRAMLOCALPARAMETER4DARBPROC GLH_EXT_NAME(glProgramLocalParameter4dARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLPROGRAMLOCALPARAMETER4DVARBPROC GLH_EXT_NAME(glProgramLocalParameter4dvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLPROGRAMLOCALPARAMETER4FARBPROC GLH_EXT_NAME(glProgramLocalParameter4fARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLPROGRAMLOCALPARAMETER4FVARBPROC GLH_EXT_NAME(glProgramLocalParameter4fvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETPROGRAMENVPARAMETERDVARBPROC GLH_EXT_NAME(glGetProgramEnvParameterdvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETPROGRAMENVPARAMETERFVARBPROC GLH_EXT_NAME(glGetProgramEnvParameterfvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC GLH_EXT_NAME(glGetProgramLocalParameterdvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC GLH_EXT_NAME(glGetProgramLocalParameterfvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETPROGRAMIVARBPROC GLH_EXT_NAME(glGetProgramivARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETPROGRAMSTRINGARBPROC GLH_EXT_NAME(glGetProgramStringARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETVERTEXATTRIBDVARBPROC GLH_EXT_NAME(glGetVertexAttribdvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETVERTEXATTRIBFVARBPROC GLH_EXT_NAME(glGetVertexAttribfvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETVERTEXATTRIBIVARBPROC GLH_EXT_NAME(glGetVertexAttribivARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETVERTEXATTRIBPOINTERVARBPROC GLH_EXT_NAME(glGetVertexAttribPointervARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLISPROGRAMARBPROC GLH_EXT_NAME(glIsProgramARB) GLH_INITIALIZER; -#endif - -#ifdef GL_EXT_abgr -#endif - -#ifdef GL_EXT_bgra -#endif - -#ifdef GL_EXT_blend_color - GLH_EXTERN PFNGLBLENDCOLOREXTPROC GLH_EXT_NAME(glBlendColorEXT) GLH_INITIALIZER; -#endif - -#ifdef GL_EXT_blend_minmax - GLH_EXTERN PFNGLBLENDEQUATIONEXTPROC GLH_EXT_NAME(glBlendEquationEXT) GLH_INITIALIZER; -#endif - -#ifdef GL_EXT_blend_subtract -#endif - -#ifdef GL_EXT_compiled_vertex_array - GLH_EXTERN PFNGLLOCKARRAYSEXTPROC GLH_EXT_NAME(glLockArraysEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLUNLOCKARRAYSEXTPROC GLH_EXT_NAME(glUnlockArraysEXT) GLH_INITIALIZER; -#endif - -#ifdef GL_EXT_fog_coord - GLH_EXTERN PFNGLFOGCOORDDEXTPROC GLH_EXT_NAME(glFogCoorddEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLFOGCOORDDVEXTPROC GLH_EXT_NAME(glFogCoorddvEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLFOGCOORDFEXTPROC GLH_EXT_NAME(glFogCoordfEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLFOGCOORDFVEXTPROC GLH_EXT_NAME(glFogCoordfvEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLFOGCOORDPOINTEREXTPROC GLH_EXT_NAME(glFogCoordPointerEXT) GLH_INITIALIZER; -#endif - -#ifdef GL_EXT_light_max_exponent -#endif - -#ifdef GL_EXT_packed_pixels -#endif - -#ifdef GL_EXT_paletted_texture - GLH_EXTERN PFNGLCOLORSUBTABLEEXTPROC GLH_EXT_NAME(glColorSubTableEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLCOLORTABLEEXTPROC GLH_EXT_NAME(glColorTableEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETCOLORTABLEEXTPROC GLH_EXT_NAME(glGetColorTableEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETCOLORTABLEPARAMETERFVEXTPROC GLH_EXT_NAME(glGetColorTableParameterfvEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETCOLORTABLEPARAMETERIVEXTPROC GLH_EXT_NAME(glGetColorTableParameterivEXT) GLH_INITIALIZER; -#endif - -#ifdef GL_EXT_point_parameters - GLH_EXTERN PFNGLPOINTPARAMETERFEXTPROC GLH_EXT_NAME(glPointParameterfEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLPOINTPARAMETERFVEXTPROC GLH_EXT_NAME(glPointParameterfvEXT) GLH_INITIALIZER; -#endif - -#ifdef GL_EXT_rescale_normal -#endif - -#ifdef GL_EXT_secondary_color - GLH_EXTERN PFNGLSECONDARYCOLOR3BEXTPROC GLH_EXT_NAME(glSecondaryColor3bEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLSECONDARYCOLOR3BVEXTPROC GLH_EXT_NAME(glSecondaryColor3bvEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLSECONDARYCOLOR3DEXTPROC GLH_EXT_NAME(glSecondaryColor3dEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLSECONDARYCOLOR3DVEXTPROC GLH_EXT_NAME(glSecondaryColor3dvEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLSECONDARYCOLOR3FEXTPROC GLH_EXT_NAME(glSecondaryColor3fEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLSECONDARYCOLOR3FVEXTPROC GLH_EXT_NAME(glSecondaryColor3fvEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLSECONDARYCOLOR3IEXTPROC GLH_EXT_NAME(glSecondaryColor3iEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLSECONDARYCOLOR3IVEXTPROC GLH_EXT_NAME(glSecondaryColor3ivEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLSECONDARYCOLOR3SEXTPROC GLH_EXT_NAME(glSecondaryColor3sEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLSECONDARYCOLOR3SVEXTPROC GLH_EXT_NAME(glSecondaryColor3svEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLSECONDARYCOLOR3UBEXTPROC GLH_EXT_NAME(glSecondaryColor3ubEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLSECONDARYCOLOR3UBVEXTPROC GLH_EXT_NAME(glSecondaryColor3ubvEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLSECONDARYCOLOR3UIEXTPROC GLH_EXT_NAME(glSecondaryColor3uiEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLSECONDARYCOLOR3UIVEXTPROC GLH_EXT_NAME(glSecondaryColor3uivEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLSECONDARYCOLOR3USEXTPROC GLH_EXT_NAME(glSecondaryColor3usEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLSECONDARYCOLOR3USVEXTPROC GLH_EXT_NAME(glSecondaryColor3usvEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLSECONDARYCOLORPOINTEREXTPROC GLH_EXT_NAME(glSecondaryColorPointerEXT) GLH_INITIALIZER; -#endif - -#ifdef GL_EXT_separate_specular_color -#endif - -#ifdef GL_EXT_shared_texture_palette -#endif - -#ifdef GL_EXT_stencil_wrap -#endif - -#ifdef GL_EXT_texture_compression_s3tc -#endif - -#ifdef GL_EXT_texture_cube_map -#endif - -#ifdef GL_EXT_texture_edge_clamp -#endif - -#ifdef GL_EXT_texture_env_add -#endif - -#ifdef GL_EXT_texture_env_combine -#endif - -#ifdef GL_EXT_texture_filter_anisotropic -#endif - -#ifdef GL_EXT_texture_lod_bias -#endif - -#ifdef GL_EXT_texture_object - GLH_EXTERN PFNGLARETEXTURESRESIDENTEXTPROC GLH_EXT_NAME(glAreTexturesResidentEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLBINDTEXTUREEXTPROC GLH_EXT_NAME(glBindTextureEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLDELETETEXTURESEXTPROC GLH_EXT_NAME(glDeleteTexturesEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLGENTEXTURESEXTPROC GLH_EXT_NAME(glGenTexturesEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLISTEXTUREEXTPROC GLH_EXT_NAME(glIsTextureEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLPRIORITIZETEXTURESEXTPROC GLH_EXT_NAME(glPrioritizeTexturesEXT) GLH_INITIALIZER; -#endif - -#ifdef GL_EXT_texture3D - GLH_EXTERN PFNGLTEXIMAGE3DEXTPROC GLH_EXT_NAME(glTexImage3DEXT) GLH_INITIALIZER; -#endif - -#ifdef GL_EXT_vertex_array - GLH_EXTERN PFNGLARRAYELEMENTEXTPROC GLH_EXT_NAME(glArrayElementEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLCOLORPOINTEREXTPROC GLH_EXT_NAME(glColorPointerEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLEDGEFLAGPOINTEREXTPROC GLH_EXT_NAME(glEdgeFlagPointerEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETPOINTERVEXTPROC GLH_EXT_NAME(glGetPointervEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLINDEXPOINTEREXTPROC GLH_EXT_NAME(glIndexPointerEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLNORMALPOINTEREXTPROC GLH_EXT_NAME(glNormalPointerEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLTEXCOORDPOINTEREXTPROC GLH_EXT_NAME(glTexCoordPointerEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXPOINTEREXTPROC GLH_EXT_NAME(glVertexPointerEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLDRAWARRAYSEXTPROC GLH_EXT_NAME(glDrawArraysEXT) GLH_INITIALIZER; -#endif - -#ifdef GL_EXT_vertex_weighting - GLH_EXTERN PFNGLVERTEXWEIGHTFEXTPROC GLH_EXT_NAME(glVertexWeightfEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXWEIGHTFVEXTPROC GLH_EXT_NAME(glVertexWeightfvEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXWEIGHTPOINTEREXTPROC GLH_EXT_NAME(glVertexWeightPointerEXT) GLH_INITIALIZER; -#endif - -#ifdef GL_NV_blend_square -#endif - -#ifdef GL_NV_evaluators - GLH_EXTERN PFNGLMAPCONTROLPOINTSNVPROC GLH_EXT_NAME(glMapControlPointsNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLMAPPARAMETERIVNVPROC GLH_EXT_NAME(glMapParameterivNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLMAPPARAMETERFVNVPROC GLH_EXT_NAME(glMapParameterfvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETMAPCONTROLPOINTSNVPROC GLH_EXT_NAME(glGetMapControlPointsNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETMAPPARAMETERIVNVPROC GLH_EXT_NAME(glGetMapParameterivNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETMAPPARAMETERFVNVPROC GLH_EXT_NAME(glGetMapParameterfvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETMAPATTRIBPARAMETERIVNVPROC GLH_EXT_NAME(glGetMapAttribParameterivNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETMAPATTRIBPARAMETERFVNVPROC GLH_EXT_NAME(glGetMapAttribParameterfvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLEVALMAPSNVPROC GLH_EXT_NAME(glEvalMapsNV) GLH_INITIALIZER; -#endif - -#ifdef GL_NV_fence - GLH_EXTERN PFNGLGENFENCESNVPROC GLH_EXT_NAME(glGenFencesNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLDELETEFENCESNVPROC GLH_EXT_NAME(glDeleteFencesNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLSETFENCENVPROC GLH_EXT_NAME(glSetFenceNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLTESTFENCENVPROC GLH_EXT_NAME(glTestFenceNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLFINISHFENCENVPROC GLH_EXT_NAME(glFinishFenceNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLISFENCENVPROC GLH_EXT_NAME(glIsFenceNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETFENCEIVNVPROC GLH_EXT_NAME(glGetFenceivNV) GLH_INITIALIZER; -#endif - -#ifdef GL_NV_fog_distance -#endif - -#ifdef GL_NV_packed_depth_stencil -#endif - -#ifdef GL_NV_register_combiners - GLH_EXTERN PFNGLCOMBINERPARAMETERFVNVPROC GLH_EXT_NAME(glCombinerParameterfvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLCOMBINERPARAMETERFNVPROC GLH_EXT_NAME(glCombinerParameterfNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLCOMBINERPARAMETERIVNVPROC GLH_EXT_NAME(glCombinerParameterivNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLCOMBINERPARAMETERINVPROC GLH_EXT_NAME(glCombinerParameteriNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLCOMBINERINPUTNVPROC GLH_EXT_NAME(glCombinerInputNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLCOMBINEROUTPUTNVPROC GLH_EXT_NAME(glCombinerOutputNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLFINALCOMBINERINPUTNVPROC GLH_EXT_NAME(glFinalCombinerInputNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETCOMBINERINPUTPARAMETERFVNVPROC GLH_EXT_NAME(glGetCombinerInputParameterfvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETCOMBINERINPUTPARAMETERIVNVPROC GLH_EXT_NAME(glGetCombinerInputParameterivNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETCOMBINEROUTPUTPARAMETERFVNVPROC GLH_EXT_NAME(glGetCombinerOutputParameterfvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETCOMBINEROUTPUTPARAMETERIVNVPROC GLH_EXT_NAME(glGetCombinerOutputParameterivNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETFINALCOMBINERINPUTPARAMETERFVNVPROC GLH_EXT_NAME(glGetFinalCombinerInputParameterfvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETFINALCOMBINERINPUTPARAMETERIVNVPROC GLH_EXT_NAME(glGetFinalCombinerInputParameterivNV) GLH_INITIALIZER; -#endif - -#ifdef GL_NV_register_combiners2 - GLH_EXTERN PFNGLCOMBINERSTAGEPARAMETERFVNVPROC GLH_EXT_NAME(glCombinerStageParameterfvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETCOMBINERSTAGEPARAMETERFVNVPROC GLH_EXT_NAME(glGetCombinerStageParameterfvNV) GLH_INITIALIZER; -#endif - -#ifdef GL_NV_texgen_reflection -#endif - -#ifdef GL_NV_texture_env_combine4 -#endif - -#ifdef GL_NV_texture_rectangle -#endif - -#ifdef GL_NV_texture_shader -#endif - -#ifdef GL_NV_vertex_array_range - GLH_EXTERN PFNGLFLUSHVERTEXARRAYRANGENVPROC GLH_EXT_NAME(glFlushVertexArrayRangeNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXARRAYRANGENVPROC GLH_EXT_NAME(glVertexArrayRangeNV) GLH_INITIALIZER; -# ifdef _WIN32 - GLH_EXTERN PFNWGLALLOCATEMEMORYNVPROC GLH_EXT_NAME(wglAllocateMemoryNV) GLH_INITIALIZER; -# endif -# ifdef GLX_VERSION_1_3 - GLH_EXTERN PFNGLXALLOCATEMEMORYNVPROC GLH_EXT_NAME(glXAllocateMemoryNV) GLH_INITIALIZER; -# endif -# ifdef _WIN32 - GLH_EXTERN PFNWGLFREEMEMORYNVPROC GLH_EXT_NAME(wglFreeMemoryNV) GLH_INITIALIZER; -# endif -# ifdef GLX_VERSION_1_3 - GLH_EXTERN PFNGLXFREEMEMORYNVPROC GLH_EXT_NAME(glXFreeMemoryNV) GLH_INITIALIZER; -# endif -#endif - -#ifdef GL_NV_vertex_program - GLH_EXTERN PFNGLAREPROGRAMSRESIDENTNVPROC GLH_EXT_NAME(glAreProgramsResidentNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLBINDPROGRAMNVPROC GLH_EXT_NAME(glBindProgramNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLDELETEPROGRAMSNVPROC GLH_EXT_NAME(glDeleteProgramsNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLEXECUTEPROGRAMNVPROC GLH_EXT_NAME(glExecuteProgramNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLGENPROGRAMSNVPROC GLH_EXT_NAME(glGenProgramsNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETPROGRAMPARAMETERDVNVPROC GLH_EXT_NAME(glGetProgramParameterdvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETPROGRAMPARAMETERFVNVPROC GLH_EXT_NAME(glGetProgramParameterfvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETPROGRAMIVNVPROC GLH_EXT_NAME(glGetProgramivNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETPROGRAMSTRINGNVPROC GLH_EXT_NAME(glGetProgramStringNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETTRACKMATRIXIVNVPROC GLH_EXT_NAME(glGetTrackMatrixivNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETVERTEXATTRIBDVNVPROC GLH_EXT_NAME(glGetVertexAttribdvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETVERTEXATTRIBFVNVPROC GLH_EXT_NAME(glGetVertexAttribfvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETVERTEXATTRIBIVNVPROC GLH_EXT_NAME(glGetVertexAttribivNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETVERTEXATTRIBPOINTERVNVPROC GLH_EXT_NAME(glGetVertexAttribPointervNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLISPROGRAMNVPROC GLH_EXT_NAME(glIsProgramNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLLOADPROGRAMNVPROC GLH_EXT_NAME(glLoadProgramNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLPROGRAMPARAMETER4DNVPROC GLH_EXT_NAME(glProgramParameter4dNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLPROGRAMPARAMETER4DVNVPROC GLH_EXT_NAME(glProgramParameter4dvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLPROGRAMPARAMETER4FNVPROC GLH_EXT_NAME(glProgramParameter4fNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLPROGRAMPARAMETER4FVNVPROC GLH_EXT_NAME(glProgramParameter4fvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLPROGRAMPARAMETERS4DVNVPROC GLH_EXT_NAME(glProgramParameters4dvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLPROGRAMPARAMETERS4FVNVPROC GLH_EXT_NAME(glProgramParameters4fvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLREQUESTRESIDENTPROGRAMSNVPROC GLH_EXT_NAME(glRequestResidentProgramsNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLTRACKMATRIXNVPROC GLH_EXT_NAME(glTrackMatrixNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIBPOINTERNVPROC GLH_EXT_NAME(glVertexAttribPointerNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB1DNVPROC GLH_EXT_NAME(glVertexAttrib1dNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB1DVNVPROC GLH_EXT_NAME(glVertexAttrib1dvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB1FNVPROC GLH_EXT_NAME(glVertexAttrib1fNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB1FVNVPROC GLH_EXT_NAME(glVertexAttrib1fvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB1SNVPROC GLH_EXT_NAME(glVertexAttrib1sNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB1SVNVPROC GLH_EXT_NAME(glVertexAttrib1svNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB2DNVPROC GLH_EXT_NAME(glVertexAttrib2dNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB2DVNVPROC GLH_EXT_NAME(glVertexAttrib2dvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB2FNVPROC GLH_EXT_NAME(glVertexAttrib2fNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB2FVNVPROC GLH_EXT_NAME(glVertexAttrib2fvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB2SNVPROC GLH_EXT_NAME(glVertexAttrib2sNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB2SVNVPROC GLH_EXT_NAME(glVertexAttrib2svNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB3DNVPROC GLH_EXT_NAME(glVertexAttrib3dNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB3DVNVPROC GLH_EXT_NAME(glVertexAttrib3dvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB3FNVPROC GLH_EXT_NAME(glVertexAttrib3fNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB3FVNVPROC GLH_EXT_NAME(glVertexAttrib3fvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB3SNVPROC GLH_EXT_NAME(glVertexAttrib3sNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB3SVNVPROC GLH_EXT_NAME(glVertexAttrib3svNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB4DNVPROC GLH_EXT_NAME(glVertexAttrib4dNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB4DVNVPROC GLH_EXT_NAME(glVertexAttrib4dvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB4FNVPROC GLH_EXT_NAME(glVertexAttrib4fNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB4FVNVPROC GLH_EXT_NAME(glVertexAttrib4fvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB4SNVPROC GLH_EXT_NAME(glVertexAttrib4sNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB4SVNVPROC GLH_EXT_NAME(glVertexAttrib4svNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB4UBVNVPROC GLH_EXT_NAME(glVertexAttrib4ubvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIBS1DVNVPROC GLH_EXT_NAME(glVertexAttribs1dvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIBS1FVNVPROC GLH_EXT_NAME(glVertexAttribs1fvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIBS1SVNVPROC GLH_EXT_NAME(glVertexAttribs1svNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIBS2DVNVPROC GLH_EXT_NAME(glVertexAttribs2dvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIBS2FVNVPROC GLH_EXT_NAME(glVertexAttribs2fvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIBS2SVNVPROC GLH_EXT_NAME(glVertexAttribs2svNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIBS3DVNVPROC GLH_EXT_NAME(glVertexAttribs3dvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIBS3FVNVPROC GLH_EXT_NAME(glVertexAttribs3fvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIBS3SVNVPROC GLH_EXT_NAME(glVertexAttribs3svNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIBS4DVNVPROC GLH_EXT_NAME(glVertexAttribs4dvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIBS4FVNVPROC GLH_EXT_NAME(glVertexAttribs4fvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIBS4SVNVPROC GLH_EXT_NAME(glVertexAttribs4svNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIBS4UBVNVPROC GLH_EXT_NAME(glVertexAttribs4ubvNV) GLH_INITIALIZER; -#endif - -#ifdef GL_SGIS_generate_mipmap -#endif - -#ifdef GL_SGIS_texture_lod -#endif - -#ifdef GL_SGIX_depth_texture -#endif - -#ifdef GL_SGIX_shadow -#endif - -#ifdef GL_VERSION_1_2 - /* These routines are prefixed by the preprocessor constant - GLH_CORE_1_2_PREFIX to avoid colliding with the OpenGL 1.2 namespace. */ - GLH_EXTERN PFNGLBLENDCOLORPROC GLH_CORE_1_2_NAME(glBlendColor) GLH_INITIALIZER; - GLH_EXTERN PFNGLBLENDEQUATIONPROC GLH_CORE_1_2_NAME(glBlendEquation) GLH_INITIALIZER; - GLH_EXTERN PFNGLDRAWRANGEELEMENTSPROC GLH_CORE_1_2_NAME(glDrawRangeElements) GLH_INITIALIZER; - GLH_EXTERN PFNGLCOLORTABLEPROC GLH_CORE_1_2_NAME(glColorTable) GLH_INITIALIZER; - GLH_EXTERN PFNGLCOLORTABLEPARAMETERFVPROC GLH_CORE_1_2_NAME(glColorTableParameterfv) GLH_INITIALIZER; - GLH_EXTERN PFNGLCOLORTABLEPARAMETERIVPROC GLH_CORE_1_2_NAME(glColorTableParameteriv) GLH_INITIALIZER; - GLH_EXTERN PFNGLCOPYCOLORTABLEPROC GLH_CORE_1_2_NAME(glCopyColorTable) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETCOLORTABLEPROC GLH_CORE_1_2_NAME(glGetColorTable) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETCOLORTABLEPARAMETERFVPROC GLH_CORE_1_2_NAME(glGetColorTableParameterfv) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETCOLORTABLEPARAMETERIVPROC GLH_CORE_1_2_NAME(glGetColorTableParameteriv) GLH_INITIALIZER; - GLH_EXTERN PFNGLTEXIMAGE3DPROC GLH_CORE_1_2_NAME(glTexImage3D) GLH_INITIALIZER; - GLH_EXTERN PFNGLTEXSUBIMAGE3DPROC GLH_CORE_1_2_NAME(glTexSubImage3D) GLH_INITIALIZER; - GLH_EXTERN PFNGLCOPYTEXSUBIMAGE3DPROC GLH_CORE_1_2_NAME(glCopyTexSubImage3D) GLH_INITIALIZER; -#endif - -#ifdef GL_WIN_swap_hint - GLH_EXTERN PFNGLADDSWAPHINTRECTWINPROC GLH_EXT_NAME(glAddSwapHintRectWIN) GLH_INITIALIZER; -#endif - -#ifdef WGL_ARB_pbuffer -# ifdef _WIN32 - GLH_EXTERN PFNWGLCREATEPBUFFERARBPROC GLH_EXT_NAME(wglCreatePbufferARB) GLH_INITIALIZER; -# endif -# ifdef _WIN32 - GLH_EXTERN PFNWGLGETPBUFFERDCARBPROC GLH_EXT_NAME(wglGetPbufferDCARB) GLH_INITIALIZER; -# endif -# ifdef _WIN32 - GLH_EXTERN PFNWGLRELEASEPBUFFERDCARBPROC GLH_EXT_NAME(wglReleasePbufferDCARB) GLH_INITIALIZER; -# endif -# ifdef _WIN32 - GLH_EXTERN PFNWGLDESTROYPBUFFERARBPROC GLH_EXT_NAME(wglDestroyPbufferARB) GLH_INITIALIZER; -# endif -# ifdef _WIN32 - GLH_EXTERN PFNWGLQUERYPBUFFERARBPROC GLH_EXT_NAME(wglQueryPbufferARB) GLH_INITIALIZER; -# endif -#endif - -#ifdef WGL_ARB_render_texture -# ifdef _WIN32 - GLH_EXTERN PFNWGLBINDTEXIMAGEARBPROC GLH_EXT_NAME(wglBindTexImageARB) GLH_INITIALIZER; -# endif -# ifdef _WIN32 - GLH_EXTERN PFNWGLRELEASETEXIMAGEARBPROC GLH_EXT_NAME(wglReleaseTexImageARB) GLH_INITIALIZER; -# endif -# ifdef _WIN32 - GLH_EXTERN PFNWGLSETPBUFFERATTRIBARBPROC GLH_EXT_NAME(wglSetPbufferAttribARB) GLH_INITIALIZER; -# endif -#endif - -#ifdef WGL_ARB_pixel_format -# ifdef _WIN32 - GLH_EXTERN PFNWGLGETPIXELFORMATATTRIBIVARBPROC GLH_EXT_NAME(wglGetPixelFormatAttribivARB) GLH_INITIALIZER; -# endif -# ifdef _WIN32 - GLH_EXTERN PFNWGLGETPIXELFORMATATTRIBFVARBPROC GLH_EXT_NAME(wglGetPixelFormatAttribfvARB) GLH_INITIALIZER; -# endif -# ifdef _WIN32 - GLH_EXTERN PFNWGLCHOOSEPIXELFORMATARBPROC GLH_EXT_NAME(wglChoosePixelFormatARB) GLH_INITIALIZER; -# endif -#endif - - -#ifdef GLH_EXT_SINGLE_FILE - -int glh_init_extension(const char* extension) -{ - if (NULL == extension) { - return FALSE; -#ifdef GL_ARB_multitexture - } else if (0 == strcmp(extension, "GL_ARB_multitexture")) { - GLH_EXT_NAME(glMultiTexCoord1dARB) = (PFNGLMULTITEXCOORD1DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord1dARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord1dARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord1dvARB) = (PFNGLMULTITEXCOORD1DVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord1dvARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord1dvARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord1fARB) = (PFNGLMULTITEXCOORD1FARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord1fARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord1fARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord1fvARB) = (PFNGLMULTITEXCOORD1FVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord1fvARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord1fvARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord1iARB) = (PFNGLMULTITEXCOORD1IARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord1iARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord1iARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord1ivARB) = (PFNGLMULTITEXCOORD1IVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord1ivARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord1ivARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord1sARB) = (PFNGLMULTITEXCOORD1SARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord1sARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord1sARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord1svARB) = (PFNGLMULTITEXCOORD1SVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord1svARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord1svARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord2dARB) = (PFNGLMULTITEXCOORD2DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord2dARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord2dARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord2dvARB) = (PFNGLMULTITEXCOORD2DVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord2dvARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord2dvARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord2fARB) = (PFNGLMULTITEXCOORD2FARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord2fARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord2fARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord2fvARB) = (PFNGLMULTITEXCOORD2FVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord2fvARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord2fvARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord2iARB) = (PFNGLMULTITEXCOORD2IARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord2iARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord2iARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord2ivARB) = (PFNGLMULTITEXCOORD2IVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord2ivARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord2ivARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord2sARB) = (PFNGLMULTITEXCOORD2SARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord2sARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord2sARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord2svARB) = (PFNGLMULTITEXCOORD2SVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord2svARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord2svARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord3dARB) = (PFNGLMULTITEXCOORD3DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord3dARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord3dARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord3dvARB) = (PFNGLMULTITEXCOORD3DVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord3dvARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord3dvARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord3fARB) = (PFNGLMULTITEXCOORD3FARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord3fARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord3fARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord3fvARB) = (PFNGLMULTITEXCOORD3FVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord3fvARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord3fvARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord3iARB) = (PFNGLMULTITEXCOORD3IARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord3iARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord3iARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord3ivARB) = (PFNGLMULTITEXCOORD3IVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord3ivARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord3ivARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord3sARB) = (PFNGLMULTITEXCOORD3SARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord3sARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord3sARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord3svARB) = (PFNGLMULTITEXCOORD3SVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord3svARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord3svARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord4dARB) = (PFNGLMULTITEXCOORD4DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord4dARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord4dARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord4dvARB) = (PFNGLMULTITEXCOORD4DVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord4dvARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord4dvARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord4fARB) = (PFNGLMULTITEXCOORD4FARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord4fARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord4fARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord4fvARB) = (PFNGLMULTITEXCOORD4FVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord4fvARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord4fvARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord4iARB) = (PFNGLMULTITEXCOORD4IARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord4iARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord4iARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord4ivARB) = (PFNGLMULTITEXCOORD4IVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord4ivARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord4ivARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord4sARB) = (PFNGLMULTITEXCOORD4SARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord4sARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord4sARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord4svARB) = (PFNGLMULTITEXCOORD4SVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord4svARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord4svARB)) - return FALSE; - GLH_EXT_NAME(glActiveTextureARB) = (PFNGLACTIVETEXTUREARBPROC)GLH_EXT_GET_PROC_ADDRESS("glActiveTextureARB"); - if (NULL == GLH_EXT_NAME(glActiveTextureARB)) - return FALSE; - GLH_EXT_NAME(glClientActiveTextureARB) = (PFNGLCLIENTACTIVETEXTUREARBPROC)GLH_EXT_GET_PROC_ADDRESS("glClientActiveTextureARB"); - if (NULL == GLH_EXT_NAME(glClientActiveTextureARB)) - return FALSE; -#endif - -#ifdef GL_ARB_texture_border_clamp - } else if (0 == strcmp(extension, "GL_ARB_texture_border_clamp")) { -#endif - -#ifdef GL_ARB_texture_compression - } else if (0 == strcmp(extension, "GL_ARB_texture_compression")) { - GLH_EXT_NAME(glCompressedTexImage3DARB) = (PFNGLCOMPRESSEDTEXIMAGE3DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glCompressedTexImage3DARB"); - if (NULL == GLH_EXT_NAME(glCompressedTexImage3DARB)) - return FALSE; - GLH_EXT_NAME(glCompressedTexImage2DARB) = (PFNGLCOMPRESSEDTEXIMAGE2DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glCompressedTexImage2DARB"); - if (NULL == GLH_EXT_NAME(glCompressedTexImage2DARB)) - return FALSE; - GLH_EXT_NAME(glCompressedTexImage1DARB) = (PFNGLCOMPRESSEDTEXIMAGE1DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glCompressedTexImage1DARB"); - if (NULL == GLH_EXT_NAME(glCompressedTexImage1DARB)) - return FALSE; - GLH_EXT_NAME(glCompressedTexSubImage3DARB) = (PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glCompressedTexSubImage3DARB"); - if (NULL == GLH_EXT_NAME(glCompressedTexSubImage3DARB)) - return FALSE; - GLH_EXT_NAME(glCompressedTexSubImage2DARB) = (PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glCompressedTexSubImage2DARB"); - if (NULL == GLH_EXT_NAME(glCompressedTexSubImage2DARB)) - return FALSE; - GLH_EXT_NAME(glCompressedTexSubImage1DARB) = (PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glCompressedTexSubImage1DARB"); - if (NULL == GLH_EXT_NAME(glCompressedTexSubImage1DARB)) - return FALSE; - GLH_EXT_NAME(glGetCompressedTexImageARB) = (PFNGLGETCOMPRESSEDTEXIMAGEARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetCompressedTexImageARB"); - if (NULL == GLH_EXT_NAME(glGetCompressedTexImageARB)) - return FALSE; -#endif - -#ifdef GL_ARB_texture_cube_map - } else if (0 == strcmp(extension, "GL_ARB_texture_cube_map")) { -#endif - -#ifdef GL_ARB_transpose_matrix - } else if (0 == strcmp(extension, "GL_ARB_transpose_matrix")) { - GLH_EXT_NAME(glLoadTransposeMatrixfARB) = (PFNGLLOADTRANSPOSEMATRIXFARBPROC)GLH_EXT_GET_PROC_ADDRESS("glLoadTransposeMatrixfARB"); - if (NULL == GLH_EXT_NAME(glLoadTransposeMatrixfARB)) - return FALSE; - GLH_EXT_NAME(glLoadTransposeMatrixdARB) = (PFNGLLOADTRANSPOSEMATRIXDARBPROC)GLH_EXT_GET_PROC_ADDRESS("glLoadTransposeMatrixdARB"); - if (NULL == GLH_EXT_NAME(glLoadTransposeMatrixdARB)) - return FALSE; - GLH_EXT_NAME(glMultTransposeMatrixfARB) = (PFNGLMULTTRANSPOSEMATRIXFARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultTransposeMatrixfARB"); - if (NULL == GLH_EXT_NAME(glMultTransposeMatrixfARB)) - return FALSE; - GLH_EXT_NAME(glMultTransposeMatrixdARB) = (PFNGLMULTTRANSPOSEMATRIXDARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultTransposeMatrixdARB"); - if (NULL == GLH_EXT_NAME(glMultTransposeMatrixdARB)) - return FALSE; -#endif - -#ifdef GL_ARB_vertex_program - } else if (0 == strcmp(extension, "GL_ARB_vertex_program")) { - GLH_EXT_NAME(glVertexAttrib1sARB) = (PFNGLVERTEXATTRIB1SARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1sARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib1sARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib1fARB) = (PFNGLVERTEXATTRIB1FARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1fARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib1fARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib1dARB) = (PFNGLVERTEXATTRIB1DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1dARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib1dARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib2sARB) = (PFNGLVERTEXATTRIB2SARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2sARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib2sARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib2fARB) = (PFNGLVERTEXATTRIB2FARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2fARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib2fARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib2dARB) = (PFNGLVERTEXATTRIB2DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2dARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib2dARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib3sARB) = (PFNGLVERTEXATTRIB3SARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3sARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib3sARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib3fARB) = (PFNGLVERTEXATTRIB3FARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3fARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib3fARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib3dARB) = (PFNGLVERTEXATTRIB3DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3dARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib3dARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib4sARB) = (PFNGLVERTEXATTRIB4SARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4sARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib4sARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib4fARB) = (PFNGLVERTEXATTRIB4FARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4fARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib4fARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib4dARB) = (PFNGLVERTEXATTRIB4DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4dARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib4dARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib4NubARB) = (PFNGLVERTEXATTRIB4NUBARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4NubARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib4NubARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib1svARB) = (PFNGLVERTEXATTRIB1SVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1svARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib1svARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib1fvARB) = (PFNGLVERTEXATTRIB1FVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1fvARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib1fvARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib1dvARB) = (PFNGLVERTEXATTRIB1DVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1dvARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib1dvARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib2svARB) = (PFNGLVERTEXATTRIB2SVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2svARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib2svARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib2fvARB) = (PFNGLVERTEXATTRIB2FVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2fvARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib2fvARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib2dvARB) = (PFNGLVERTEXATTRIB2DVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2dvARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib2dvARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib3svARB) = (PFNGLVERTEXATTRIB3SVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3svARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib3svARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib3fvARB) = (PFNGLVERTEXATTRIB3FVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3fvARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib3fvARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib3dvARB) = (PFNGLVERTEXATTRIB3DVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3dvARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib3dvARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib4bvARB) = (PFNGLVERTEXATTRIB4BVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4bvARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib4bvARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib4svARB) = (PFNGLVERTEXATTRIB4SVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4svARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib4svARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib4ivARB) = (PFNGLVERTEXATTRIB4IVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4ivARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib4ivARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib4ubvARB) = (PFNGLVERTEXATTRIB4UBVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4ubvARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib4ubvARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib4usvARB) = (PFNGLVERTEXATTRIB4USVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4usvARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib4usvARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib4uivARB) = (PFNGLVERTEXATTRIB4UIVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4uivARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib4uivARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib4fvARB) = (PFNGLVERTEXATTRIB4FVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4fvARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib4fvARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib4dvARB) = (PFNGLVERTEXATTRIB4DVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4dvARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib4dvARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib4NbvARB) = (PFNGLVERTEXATTRIB4NBVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4NbvARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib4NbvARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib4NsvARB) = (PFNGLVERTEXATTRIB4NSVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4NsvARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib4NsvARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib4NivARB) = (PFNGLVERTEXATTRIB4NIVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4NivARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib4NivARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib4NubvARB) = (PFNGLVERTEXATTRIB4NUBVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4NubvARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib4NubvARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib4NusvARB) = (PFNGLVERTEXATTRIB4NUSVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4NusvARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib4NusvARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib4NuivARB) = (PFNGLVERTEXATTRIB4NUIVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4NuivARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib4NuivARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttribPointerARB) = (PFNGLVERTEXATTRIBPOINTERARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribPointerARB"); - if (NULL == GLH_EXT_NAME(glVertexAttribPointerARB)) - return GL_FALSE; - GLH_EXT_NAME(glEnableVertexAttribArrayARB) = (PFNGLENABLEVERTEXATTRIBARRAYARBPROC)GLH_EXT_GET_PROC_ADDRESS("glEnableVertexAttribArrayARB"); - if (NULL == GLH_EXT_NAME(glEnableVertexAttribArrayARB)) - return GL_FALSE; - GLH_EXT_NAME(glDisableVertexAttribArrayARB) = (PFNGLDISABLEVERTEXATTRIBARRAYARBPROC)GLH_EXT_GET_PROC_ADDRESS("glDisableVertexAttribArrayARB"); - if (NULL == GLH_EXT_NAME(glDisableVertexAttribArrayARB)) - return GL_FALSE; - GLH_EXT_NAME(glProgramStringARB) = (PFNGLPROGRAMSTRINGARBPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramStringARB"); - if (NULL == GLH_EXT_NAME(glProgramStringARB)) - return GL_FALSE; - GLH_EXT_NAME(glBindProgramARB) = (PFNGLBINDPROGRAMARBPROC)GLH_EXT_GET_PROC_ADDRESS("glBindProgramARB"); - if (NULL == GLH_EXT_NAME(glBindProgramARB)) - return GL_FALSE; - GLH_EXT_NAME(glDeleteProgramsARB) = (PFNGLDELETEPROGRAMSARBPROC)GLH_EXT_GET_PROC_ADDRESS("glDeleteProgramsARB"); - if (NULL == GLH_EXT_NAME(glDeleteProgramsARB)) - return GL_FALSE; - GLH_EXT_NAME(glGenProgramsARB) = (PFNGLGENPROGRAMSARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGenProgramsARB"); - if (NULL == GLH_EXT_NAME(glGenProgramsARB)) - return GL_FALSE; - GLH_EXT_NAME(glProgramEnvParameter4dARB) = (PFNGLPROGRAMENVPARAMETER4DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramEnvParameter4dARB"); - if (NULL == GLH_EXT_NAME(glProgramEnvParameter4dARB)) - return GL_FALSE; - GLH_EXT_NAME(glProgramEnvParameter4dvARB) = (PFNGLPROGRAMENVPARAMETER4DVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramEnvParameter4dvARB"); - if (NULL == GLH_EXT_NAME(glProgramEnvParameter4dvARB)) - return GL_FALSE; - GLH_EXT_NAME(glProgramEnvParameter4fARB) = (PFNGLPROGRAMENVPARAMETER4FARBPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramEnvParameter4fARB"); - if (NULL == GLH_EXT_NAME(glProgramEnvParameter4fARB)) - return GL_FALSE; - GLH_EXT_NAME(glProgramEnvParameter4fvARB) = (PFNGLPROGRAMENVPARAMETER4FVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramEnvParameter4fvARB"); - if (NULL == GLH_EXT_NAME(glProgramEnvParameter4fvARB)) - return GL_FALSE; - GLH_EXT_NAME(glProgramLocalParameter4dARB) = (PFNGLPROGRAMLOCALPARAMETER4DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramLocalParameter4dARB"); - if (NULL == GLH_EXT_NAME(glProgramLocalParameter4dARB)) - return GL_FALSE; - GLH_EXT_NAME(glProgramLocalParameter4dvARB) = (PFNGLPROGRAMLOCALPARAMETER4DVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramLocalParameter4dvARB"); - if (NULL == GLH_EXT_NAME(glProgramLocalParameter4dvARB)) - return GL_FALSE; - GLH_EXT_NAME(glProgramLocalParameter4fARB) = (PFNGLPROGRAMLOCALPARAMETER4FARBPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramLocalParameter4fARB"); - if (NULL == GLH_EXT_NAME(glProgramLocalParameter4fARB)) - return GL_FALSE; - GLH_EXT_NAME(glProgramLocalParameter4fvARB) = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramLocalParameter4fvARB"); - if (NULL == GLH_EXT_NAME(glProgramLocalParameter4fvARB)) - return GL_FALSE; - GLH_EXT_NAME(glGetProgramEnvParameterdvARB) = (PFNGLGETPROGRAMENVPARAMETERDVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetProgramEnvParameterdvARB"); - if (NULL == GLH_EXT_NAME(glGetProgramEnvParameterdvARB)) - return GL_FALSE; - GLH_EXT_NAME(glGetProgramEnvParameterfvARB) = (PFNGLGETPROGRAMENVPARAMETERFVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetProgramEnvParameterfvARB"); - if (NULL == GLH_EXT_NAME(glGetProgramEnvParameterfvARB)) - return GL_FALSE; - GLH_EXT_NAME(glGetProgramLocalParameterdvARB) = (PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetProgramLocalParameterdvARB"); - if (NULL == GLH_EXT_NAME(glGetProgramLocalParameterdvARB)) - return GL_FALSE; - GLH_EXT_NAME(glGetProgramLocalParameterfvARB) = (PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetProgramLocalParameterfvARB"); - if (NULL == GLH_EXT_NAME(glGetProgramLocalParameterfvARB)) - return GL_FALSE; - GLH_EXT_NAME(glGetProgramivARB) = (PFNGLGETPROGRAMIVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetProgramivARB"); - if (NULL == GLH_EXT_NAME(glGetProgramivARB)) - return GL_FALSE; - GLH_EXT_NAME(glGetProgramStringARB) = (PFNGLGETPROGRAMSTRINGARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetProgramStringARB"); - if (NULL == GLH_EXT_NAME(glGetProgramStringARB)) - return GL_FALSE; - GLH_EXT_NAME(glGetVertexAttribdvARB) = (PFNGLGETVERTEXATTRIBDVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribdvARB"); - if (NULL == GLH_EXT_NAME(glGetVertexAttribdvARB)) - return GL_FALSE; - GLH_EXT_NAME(glGetVertexAttribfvARB) = (PFNGLGETVERTEXATTRIBFVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribfvARB"); - if (NULL == GLH_EXT_NAME(glGetVertexAttribfvARB)) - return GL_FALSE; - GLH_EXT_NAME(glGetVertexAttribivARB) = (PFNGLGETVERTEXATTRIBIVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribivARB"); - if (NULL == GLH_EXT_NAME(glGetVertexAttribivARB)) - return GL_FALSE; - GLH_EXT_NAME(glGetVertexAttribPointervARB) = (PFNGLGETVERTEXATTRIBPOINTERVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribPointervARB"); - if (NULL == GLH_EXT_NAME(glGetVertexAttribPointervARB)) - return GL_FALSE; - GLH_EXT_NAME(glIsProgramARB) = (PFNGLISPROGRAMARBPROC)GLH_EXT_GET_PROC_ADDRESS("glIsProgramARB"); - if (NULL == GLH_EXT_NAME(glIsProgramARB)) - return GL_FALSE; -#endif - -#ifdef GL_EXT_abgr - } else if (0 == strcmp(extension, "GL_EXT_abgr")) { -#endif - -#ifdef GL_EXT_bgra - } else if (0 == strcmp(extension, "GL_EXT_bgra")) { -#endif - -#ifdef GL_EXT_blend_color - } else if (0 == strcmp(extension, "GL_EXT_blend_color")) { - GLH_EXT_NAME(glBlendColorEXT) = (PFNGLBLENDCOLOREXTPROC)GLH_EXT_GET_PROC_ADDRESS("glBlendColorEXT"); - if (NULL == GLH_EXT_NAME(glBlendColorEXT)) - return FALSE; -#endif - -#ifdef GL_EXT_blend_minmax - } else if (0 == strcmp(extension, "GL_EXT_blend_minmax")) { - GLH_EXT_NAME(glBlendEquationEXT) = (PFNGLBLENDEQUATIONEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glBlendEquationEXT"); - if (NULL == GLH_EXT_NAME(glBlendEquationEXT)) - return FALSE; -#endif - -#ifdef GL_EXT_blend_subtract - } else if (0 == strcmp(extension, "GL_EXT_blend_subtract")) { -#endif - -#ifdef GL_EXT_compiled_vertex_array - } else if (0 == strcmp(extension, "GL_EXT_compiled_vertex_array")) { - GLH_EXT_NAME(glLockArraysEXT) = (PFNGLLOCKARRAYSEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glLockArraysEXT"); - if (NULL == GLH_EXT_NAME(glLockArraysEXT)) - return FALSE; - GLH_EXT_NAME(glUnlockArraysEXT) = (PFNGLUNLOCKARRAYSEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glUnlockArraysEXT"); - if (NULL == GLH_EXT_NAME(glUnlockArraysEXT)) - return FALSE; -#endif - -#ifdef GL_EXT_fog_coord - } else if (0 == strcmp(extension, "GL_EXT_fog_coord")) { - GLH_EXT_NAME(glFogCoorddEXT) = (PFNGLFOGCOORDDEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glFogCoorddEXT"); - if (NULL == GLH_EXT_NAME(glFogCoorddEXT)) - return FALSE; - GLH_EXT_NAME(glFogCoorddvEXT) = (PFNGLFOGCOORDDVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glFogCoorddvEXT"); - if (NULL == GLH_EXT_NAME(glFogCoorddvEXT)) - return FALSE; - GLH_EXT_NAME(glFogCoordfEXT) = (PFNGLFOGCOORDFEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glFogCoordfEXT"); - if (NULL == GLH_EXT_NAME(glFogCoordfEXT)) - return FALSE; - GLH_EXT_NAME(glFogCoordfvEXT) = (PFNGLFOGCOORDFVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glFogCoordfvEXT"); - if (NULL == GLH_EXT_NAME(glFogCoordfvEXT)) - return FALSE; - GLH_EXT_NAME(glFogCoordPointerEXT) = (PFNGLFOGCOORDPOINTEREXTPROC)GLH_EXT_GET_PROC_ADDRESS("glFogCoordPointerEXT"); - if (NULL == GLH_EXT_NAME(glFogCoordPointerEXT)) - return FALSE; -#endif - -#ifdef GL_EXT_light_max_exponent - } else if (0 == strcmp(extension, "GL_EXT_light_max_exponent")) { -#endif - -#ifdef GL_EXT_packed_pixels - } else if (0 == strcmp(extension, "GL_EXT_packed_pixels")) { -#endif - -#ifdef GL_EXT_paletted_texture - } else if (0 == strcmp(extension, "GL_EXT_paletted_texture")) { - GLH_EXT_NAME(glColorSubTableEXT) = (PFNGLCOLORSUBTABLEEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glColorSubTableEXT"); - if (NULL == GLH_EXT_NAME(glColorSubTableEXT)) - return FALSE; - GLH_EXT_NAME(glColorTableEXT) = (PFNGLCOLORTABLEEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glColorTableEXT"); - if (NULL == GLH_EXT_NAME(glColorTableEXT)) - return FALSE; - GLH_EXT_NAME(glGetColorTableEXT) = (PFNGLGETCOLORTABLEEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glGetColorTableEXT"); - if (NULL == GLH_EXT_NAME(glGetColorTableEXT)) - return FALSE; - GLH_EXT_NAME(glGetColorTableParameterfvEXT) = (PFNGLGETCOLORTABLEPARAMETERFVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glGetColorTableParameterfvEXT"); - if (NULL == GLH_EXT_NAME(glGetColorTableParameterfvEXT)) - return FALSE; - GLH_EXT_NAME(glGetColorTableParameterivEXT) = (PFNGLGETCOLORTABLEPARAMETERIVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glGetColorTableParameterivEXT"); - if (NULL == GLH_EXT_NAME(glGetColorTableParameterivEXT)) - return FALSE; -#endif - -#ifdef GL_EXT_point_parameters - } else if (0 == strcmp(extension, "GL_EXT_point_parameters")) { - GLH_EXT_NAME(glPointParameterfEXT) = (PFNGLPOINTPARAMETERFEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glPointParameterfEXT"); - if (NULL == GLH_EXT_NAME(glPointParameterfEXT)) - return FALSE; - GLH_EXT_NAME(glPointParameterfvEXT) = (PFNGLPOINTPARAMETERFVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glPointParameterfvEXT"); - if (NULL == GLH_EXT_NAME(glPointParameterfvEXT)) - return FALSE; -#endif - -#ifdef GL_EXT_rescale_normal - } else if (0 == strcmp(extension, "GL_EXT_rescale_normal")) { -#endif - -#ifdef GL_EXT_secondary_color - } else if (0 == strcmp(extension, "GL_EXT_secondary_color")) { - GLH_EXT_NAME(glSecondaryColor3bEXT) = (PFNGLSECONDARYCOLOR3BEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3bEXT"); - if (NULL == GLH_EXT_NAME(glSecondaryColor3bEXT)) - return FALSE; - GLH_EXT_NAME(glSecondaryColor3bvEXT) = (PFNGLSECONDARYCOLOR3BVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3bvEXT"); - if (NULL == GLH_EXT_NAME(glSecondaryColor3bvEXT)) - return FALSE; - GLH_EXT_NAME(glSecondaryColor3dEXT) = (PFNGLSECONDARYCOLOR3DEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3dEXT"); - if (NULL == GLH_EXT_NAME(glSecondaryColor3dEXT)) - return FALSE; - GLH_EXT_NAME(glSecondaryColor3dvEXT) = (PFNGLSECONDARYCOLOR3DVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3dvEXT"); - if (NULL == GLH_EXT_NAME(glSecondaryColor3dvEXT)) - return FALSE; - GLH_EXT_NAME(glSecondaryColor3fEXT) = (PFNGLSECONDARYCOLOR3FEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3fEXT"); - if (NULL == GLH_EXT_NAME(glSecondaryColor3fEXT)) - return FALSE; - GLH_EXT_NAME(glSecondaryColor3fvEXT) = (PFNGLSECONDARYCOLOR3FVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3fvEXT"); - if (NULL == GLH_EXT_NAME(glSecondaryColor3fvEXT)) - return FALSE; - GLH_EXT_NAME(glSecondaryColor3iEXT) = (PFNGLSECONDARYCOLOR3IEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3iEXT"); - if (NULL == GLH_EXT_NAME(glSecondaryColor3iEXT)) - return FALSE; - GLH_EXT_NAME(glSecondaryColor3ivEXT) = (PFNGLSECONDARYCOLOR3IVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3ivEXT"); - if (NULL == GLH_EXT_NAME(glSecondaryColor3ivEXT)) - return FALSE; - GLH_EXT_NAME(glSecondaryColor3sEXT) = (PFNGLSECONDARYCOLOR3SEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3sEXT"); - if (NULL == GLH_EXT_NAME(glSecondaryColor3sEXT)) - return FALSE; - GLH_EXT_NAME(glSecondaryColor3svEXT) = (PFNGLSECONDARYCOLOR3SVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3svEXT"); - if (NULL == GLH_EXT_NAME(glSecondaryColor3svEXT)) - return FALSE; - GLH_EXT_NAME(glSecondaryColor3ubEXT) = (PFNGLSECONDARYCOLOR3UBEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3ubEXT"); - if (NULL == GLH_EXT_NAME(glSecondaryColor3ubEXT)) - return FALSE; - GLH_EXT_NAME(glSecondaryColor3ubvEXT) = (PFNGLSECONDARYCOLOR3UBVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3ubvEXT"); - if (NULL == GLH_EXT_NAME(glSecondaryColor3ubvEXT)) - return FALSE; - GLH_EXT_NAME(glSecondaryColor3uiEXT) = (PFNGLSECONDARYCOLOR3UIEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3uiEXT"); - if (NULL == GLH_EXT_NAME(glSecondaryColor3uiEXT)) - return FALSE; - GLH_EXT_NAME(glSecondaryColor3uivEXT) = (PFNGLSECONDARYCOLOR3UIVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3uivEXT"); - if (NULL == GLH_EXT_NAME(glSecondaryColor3uivEXT)) - return FALSE; - GLH_EXT_NAME(glSecondaryColor3usEXT) = (PFNGLSECONDARYCOLOR3USEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3usEXT"); - if (NULL == GLH_EXT_NAME(glSecondaryColor3usEXT)) - return FALSE; - GLH_EXT_NAME(glSecondaryColor3usvEXT) = (PFNGLSECONDARYCOLOR3USVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3usvEXT"); - if (NULL == GLH_EXT_NAME(glSecondaryColor3usvEXT)) - return FALSE; - GLH_EXT_NAME(glSecondaryColorPointerEXT) = (PFNGLSECONDARYCOLORPOINTEREXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColorPointerEXT"); - if (NULL == GLH_EXT_NAME(glSecondaryColorPointerEXT)) - return FALSE; -#endif - -#ifdef GL_EXT_separate_specular_color - } else if (0 == strcmp(extension, "GL_EXT_separate_specular_color")) { -#endif - -#ifdef GL_EXT_shared_texture_palette - } else if (0 == strcmp(extension, "GL_EXT_shared_texture_palette")) { -#endif - -#ifdef GL_EXT_stencil_wrap - } else if (0 == strcmp(extension, "GL_EXT_stencil_wrap")) { -#endif - -#ifdef GL_EXT_texture_compression_s3tc - } else if (0 == strcmp(extension, "GL_EXT_texture_compression_s3tc")) { -#endif - -#ifdef GL_EXT_texture_cube_map - } else if (0 == strcmp(extension, "GL_EXT_texture_cube_map")) { -#endif - -#ifdef GL_EXT_texture_edge_clamp - } else if (0 == strcmp(extension, "GL_EXT_texture_edge_clamp")) { -#endif - -#ifdef GL_EXT_texture_env_add - } else if (0 == strcmp(extension, "GL_EXT_texture_env_add")) { -#endif - -#ifdef GL_EXT_texture_env_combine - } else if (0 == strcmp(extension, "GL_EXT_texture_env_combine")) { -#endif - -#ifdef GL_EXT_texture_filter_anisotropic - } else if (0 == strcmp(extension, "GL_EXT_texture_filter_anisotropic")) { -#endif - -#ifdef GL_EXT_texture_lod_bias - } else if (0 == strcmp(extension, "GL_EXT_texture_lod_bias")) { -#endif - -#ifdef GL_EXT_texture_object - } else if (0 == strcmp(extension, "GL_EXT_texture_object")) { - GLH_EXT_NAME(glAreTexturesResidentEXT) = (PFNGLARETEXTURESRESIDENTEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glAreTexturesResidentEXT"); - if (NULL == GLH_EXT_NAME(glAreTexturesResidentEXT)) - return FALSE; - GLH_EXT_NAME(glBindTextureEXT) = (PFNGLBINDTEXTUREEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glBindTextureEXT"); - if (NULL == GLH_EXT_NAME(glBindTextureEXT)) - return FALSE; - GLH_EXT_NAME(glDeleteTexturesEXT) = (PFNGLDELETETEXTURESEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glDeleteTexturesEXT"); - if (NULL == GLH_EXT_NAME(glDeleteTexturesEXT)) - return FALSE; - GLH_EXT_NAME(glGenTexturesEXT) = (PFNGLGENTEXTURESEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glGenTexturesEXT"); - if (NULL == GLH_EXT_NAME(glGenTexturesEXT)) - return FALSE; - GLH_EXT_NAME(glIsTextureEXT) = (PFNGLISTEXTUREEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glIsTextureEXT"); - if (NULL == GLH_EXT_NAME(glIsTextureEXT)) - return FALSE; - GLH_EXT_NAME(glPrioritizeTexturesEXT) = (PFNGLPRIORITIZETEXTURESEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glPrioritizeTexturesEXT"); - if (NULL == GLH_EXT_NAME(glPrioritizeTexturesEXT)) - return FALSE; -#endif - -#ifdef GL_EXT_texture3D - } else if (0 == strcmp(extension, "GL_EXT_texture3D")) { - GLH_EXT_NAME(glTexImage3DEXT) = (PFNGLTEXIMAGE3DEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glTexImage3DEXT"); - if (NULL == GLH_EXT_NAME(glTexImage3DEXT)) - return FALSE; -#endif - -#ifdef GL_EXT_vertex_array - } else if (0 == strcmp(extension, "GL_EXT_vertex_array")) { - GLH_EXT_NAME(glArrayElementEXT) = (PFNGLARRAYELEMENTEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glArrayElementEXT"); - if (NULL == GLH_EXT_NAME(glArrayElementEXT)) - return FALSE; - GLH_EXT_NAME(glColorPointerEXT) = (PFNGLCOLORPOINTEREXTPROC)GLH_EXT_GET_PROC_ADDRESS("glColorPointerEXT"); - if (NULL == GLH_EXT_NAME(glColorPointerEXT)) - return FALSE; - GLH_EXT_NAME(glEdgeFlagPointerEXT) = (PFNGLEDGEFLAGPOINTEREXTPROC)GLH_EXT_GET_PROC_ADDRESS("glEdgeFlagPointerEXT"); - if (NULL == GLH_EXT_NAME(glEdgeFlagPointerEXT)) - return FALSE; - GLH_EXT_NAME(glGetPointervEXT) = (PFNGLGETPOINTERVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glGetPointervEXT"); - if (NULL == GLH_EXT_NAME(glGetPointervEXT)) - return FALSE; - GLH_EXT_NAME(glIndexPointerEXT) = (PFNGLINDEXPOINTEREXTPROC)GLH_EXT_GET_PROC_ADDRESS("glIndexPointerEXT"); - if (NULL == GLH_EXT_NAME(glIndexPointerEXT)) - return FALSE; - GLH_EXT_NAME(glNormalPointerEXT) = (PFNGLNORMALPOINTEREXTPROC)GLH_EXT_GET_PROC_ADDRESS("glNormalPointerEXT"); - if (NULL == GLH_EXT_NAME(glNormalPointerEXT)) - return FALSE; - GLH_EXT_NAME(glTexCoordPointerEXT) = (PFNGLTEXCOORDPOINTEREXTPROC)GLH_EXT_GET_PROC_ADDRESS("glTexCoordPointerEXT"); - if (NULL == GLH_EXT_NAME(glTexCoordPointerEXT)) - return FALSE; - GLH_EXT_NAME(glVertexPointerEXT) = (PFNGLVERTEXPOINTEREXTPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexPointerEXT"); - if (NULL == GLH_EXT_NAME(glVertexPointerEXT)) - return FALSE; - GLH_EXT_NAME(glDrawArraysEXT) = (PFNGLDRAWARRAYSEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glDrawArraysEXT"); - if (NULL == GLH_EXT_NAME(glDrawArraysEXT)) - return FALSE; -#endif - -#ifdef GL_EXT_vertex_weighting - } else if (0 == strcmp(extension, "GL_EXT_vertex_weighting")) { - GLH_EXT_NAME(glVertexWeightfEXT) = (PFNGLVERTEXWEIGHTFEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexWeightfEXT"); - if (NULL == GLH_EXT_NAME(glVertexWeightfEXT)) - return FALSE; - GLH_EXT_NAME(glVertexWeightfvEXT) = (PFNGLVERTEXWEIGHTFVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexWeightfvEXT"); - if (NULL == GLH_EXT_NAME(glVertexWeightfvEXT)) - return FALSE; - GLH_EXT_NAME(glVertexWeightPointerEXT) = (PFNGLVERTEXWEIGHTPOINTEREXTPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexWeightPointerEXT"); - if (NULL == GLH_EXT_NAME(glVertexWeightPointerEXT)) - return FALSE; -#endif - -#ifdef GL_NV_blend_square - } else if (0 == strcmp(extension, "GL_NV_blend_square")) { -#endif - -#ifdef GL_NV_evaluators - } else if (0 == strcmp(extension, "GL_NV_evaluators")) { - GLH_EXT_NAME(glMapControlPointsNV) = (PFNGLMAPCONTROLPOINTSNVPROC)GLH_EXT_GET_PROC_ADDRESS("glMapControlPointsNV"); - if (NULL == GLH_EXT_NAME(glMapControlPointsNV)) - return FALSE; - GLH_EXT_NAME(glMapParameterivNV) = (PFNGLMAPPARAMETERIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glMapParameterivNV"); - if (NULL == GLH_EXT_NAME(glMapParameterivNV)) - return FALSE; - GLH_EXT_NAME(glMapParameterfvNV) = (PFNGLMAPPARAMETERFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glMapParameterfvNV"); - if (NULL == GLH_EXT_NAME(glMapParameterfvNV)) - return FALSE; - GLH_EXT_NAME(glGetMapControlPointsNV) = (PFNGLGETMAPCONTROLPOINTSNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetMapControlPointsNV"); - if (NULL == GLH_EXT_NAME(glGetMapControlPointsNV)) - return FALSE; - GLH_EXT_NAME(glGetMapParameterivNV) = (PFNGLGETMAPPARAMETERIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetMapParameterivNV"); - if (NULL == GLH_EXT_NAME(glGetMapParameterivNV)) - return FALSE; - GLH_EXT_NAME(glGetMapParameterfvNV) = (PFNGLGETMAPPARAMETERFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetMapParameterfvNV"); - if (NULL == GLH_EXT_NAME(glGetMapParameterfvNV)) - return FALSE; - GLH_EXT_NAME(glGetMapAttribParameterivNV) = (PFNGLGETMAPATTRIBPARAMETERIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetMapAttribParameterivNV"); - if (NULL == GLH_EXT_NAME(glGetMapAttribParameterivNV)) - return FALSE; - GLH_EXT_NAME(glGetMapAttribParameterfvNV) = (PFNGLGETMAPATTRIBPARAMETERFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetMapAttribParameterfvNV"); - if (NULL == GLH_EXT_NAME(glGetMapAttribParameterfvNV)) - return FALSE; - GLH_EXT_NAME(glEvalMapsNV) = (PFNGLEVALMAPSNVPROC)GLH_EXT_GET_PROC_ADDRESS("glEvalMapsNV"); - if (NULL == GLH_EXT_NAME(glEvalMapsNV)) - return FALSE; -#endif - -#ifdef GL_NV_fence - } else if (0 == strcmp(extension, "GL_NV_fence")) { - GLH_EXT_NAME(glGenFencesNV) = (PFNGLGENFENCESNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGenFencesNV"); - if (NULL == GLH_EXT_NAME(glGenFencesNV)) - return FALSE; - GLH_EXT_NAME(glDeleteFencesNV) = (PFNGLDELETEFENCESNVPROC)GLH_EXT_GET_PROC_ADDRESS("glDeleteFencesNV"); - if (NULL == GLH_EXT_NAME(glDeleteFencesNV)) - return FALSE; - GLH_EXT_NAME(glSetFenceNV) = (PFNGLSETFENCENVPROC)GLH_EXT_GET_PROC_ADDRESS("glSetFenceNV"); - if (NULL == GLH_EXT_NAME(glSetFenceNV)) - return FALSE; - GLH_EXT_NAME(glTestFenceNV) = (PFNGLTESTFENCENVPROC)GLH_EXT_GET_PROC_ADDRESS("glTestFenceNV"); - if (NULL == GLH_EXT_NAME(glTestFenceNV)) - return FALSE; - GLH_EXT_NAME(glFinishFenceNV) = (PFNGLFINISHFENCENVPROC)GLH_EXT_GET_PROC_ADDRESS("glFinishFenceNV"); - if (NULL == GLH_EXT_NAME(glFinishFenceNV)) - return FALSE; - GLH_EXT_NAME(glIsFenceNV) = (PFNGLISFENCENVPROC)GLH_EXT_GET_PROC_ADDRESS("glIsFenceNV"); - if (NULL == GLH_EXT_NAME(glIsFenceNV)) - return FALSE; - GLH_EXT_NAME(glGetFenceivNV) = (PFNGLGETFENCEIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetFenceivNV"); - if (NULL == GLH_EXT_NAME(glGetFenceivNV)) - return FALSE; -#endif - -#ifdef GL_NV_fog_distance - } else if (0 == strcmp(extension, "GL_NV_fog_distance")) { -#endif - -#ifdef GL_NV_packed_depth_stencil - } else if (0 == strcmp(extension, "GL_NV_packed_depth_stencil")) { -#endif - -#ifdef GL_NV_register_combiners - } else if (0 == strcmp(extension, "GL_NV_register_combiners")) { - GLH_EXT_NAME(glCombinerParameterfvNV) = (PFNGLCOMBINERPARAMETERFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glCombinerParameterfvNV"); - if (NULL == GLH_EXT_NAME(glCombinerParameterfvNV)) - return FALSE; - GLH_EXT_NAME(glCombinerParameterfNV) = (PFNGLCOMBINERPARAMETERFNVPROC)GLH_EXT_GET_PROC_ADDRESS("glCombinerParameterfNV"); - if (NULL == GLH_EXT_NAME(glCombinerParameterfNV)) - return FALSE; - GLH_EXT_NAME(glCombinerParameterivNV) = (PFNGLCOMBINERPARAMETERIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glCombinerParameterivNV"); - if (NULL == GLH_EXT_NAME(glCombinerParameterivNV)) - return FALSE; - GLH_EXT_NAME(glCombinerParameteriNV) = (PFNGLCOMBINERPARAMETERINVPROC)GLH_EXT_GET_PROC_ADDRESS("glCombinerParameteriNV"); - if (NULL == GLH_EXT_NAME(glCombinerParameteriNV)) - return FALSE; - GLH_EXT_NAME(glCombinerInputNV) = (PFNGLCOMBINERINPUTNVPROC)GLH_EXT_GET_PROC_ADDRESS("glCombinerInputNV"); - if (NULL == GLH_EXT_NAME(glCombinerInputNV)) - return FALSE; - GLH_EXT_NAME(glCombinerOutputNV) = (PFNGLCOMBINEROUTPUTNVPROC)GLH_EXT_GET_PROC_ADDRESS("glCombinerOutputNV"); - if (NULL == GLH_EXT_NAME(glCombinerOutputNV)) - return FALSE; - GLH_EXT_NAME(glFinalCombinerInputNV) = (PFNGLFINALCOMBINERINPUTNVPROC)GLH_EXT_GET_PROC_ADDRESS("glFinalCombinerInputNV"); - if (NULL == GLH_EXT_NAME(glFinalCombinerInputNV)) - return FALSE; - GLH_EXT_NAME(glGetCombinerInputParameterfvNV) = (PFNGLGETCOMBINERINPUTPARAMETERFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetCombinerInputParameterfvNV"); - if (NULL == GLH_EXT_NAME(glGetCombinerInputParameterfvNV)) - return FALSE; - GLH_EXT_NAME(glGetCombinerInputParameterivNV) = (PFNGLGETCOMBINERINPUTPARAMETERIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetCombinerInputParameterivNV"); - if (NULL == GLH_EXT_NAME(glGetCombinerInputParameterivNV)) - return FALSE; - GLH_EXT_NAME(glGetCombinerOutputParameterfvNV) = (PFNGLGETCOMBINEROUTPUTPARAMETERFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetCombinerOutputParameterfvNV"); - if (NULL == GLH_EXT_NAME(glGetCombinerOutputParameterfvNV)) - return FALSE; - GLH_EXT_NAME(glGetCombinerOutputParameterivNV) = (PFNGLGETCOMBINEROUTPUTPARAMETERIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetCombinerOutputParameterivNV"); - if (NULL == GLH_EXT_NAME(glGetCombinerOutputParameterivNV)) - return FALSE; - GLH_EXT_NAME(glGetFinalCombinerInputParameterfvNV) = (PFNGLGETFINALCOMBINERINPUTPARAMETERFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetFinalCombinerInputParameterfvNV"); - if (NULL == GLH_EXT_NAME(glGetFinalCombinerInputParameterfvNV)) - return FALSE; - GLH_EXT_NAME(glGetFinalCombinerInputParameterivNV) = (PFNGLGETFINALCOMBINERINPUTPARAMETERIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetFinalCombinerInputParameterivNV"); - if (NULL == GLH_EXT_NAME(glGetFinalCombinerInputParameterivNV)) - return FALSE; -#endif - -#ifdef GL_NV_register_combiners2 - } else if (0 == strcmp(extension, "GL_NV_register_combiners2")) { - GLH_EXT_NAME(glCombinerStageParameterfvNV) = (PFNGLCOMBINERSTAGEPARAMETERFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glCombinerStageParameterfvNV"); - if (NULL == GLH_EXT_NAME(glCombinerStageParameterfvNV)) - return FALSE; - GLH_EXT_NAME(glGetCombinerStageParameterfvNV) = (PFNGLGETCOMBINERSTAGEPARAMETERFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetCombinerStageParameterfvNV"); - if (NULL == GLH_EXT_NAME(glGetCombinerStageParameterfvNV)) - return FALSE; -#endif - -#ifdef GL_NV_texgen_reflection - } else if (0 == strcmp(extension, "GL_NV_texgen_reflection")) { -#endif - -#ifdef GL_NV_texture_env_combine4 - } else if (0 == strcmp(extension, "GL_NV_texture_env_combine4")) { -#endif - -#ifdef GL_NV_texture_rectangle - } else if (0 == strcmp(extension, "GL_NV_texture_rectangle")) { -#endif - -#ifdef GL_NV_texture_shader - } else if (0 == strcmp(extension, "GL_NV_texture_shader")) { -#endif - -#ifdef GL_NV_vertex_array_range - } else if (0 == strcmp(extension, "GL_NV_vertex_array_range")) { - GLH_EXT_NAME(glFlushVertexArrayRangeNV) = (PFNGLFLUSHVERTEXARRAYRANGENVPROC)GLH_EXT_GET_PROC_ADDRESS("glFlushVertexArrayRangeNV"); - if (NULL == GLH_EXT_NAME(glFlushVertexArrayRangeNV)) - return FALSE; - GLH_EXT_NAME(glVertexArrayRangeNV) = (PFNGLVERTEXARRAYRANGENVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexArrayRangeNV"); - if (NULL == GLH_EXT_NAME(glVertexArrayRangeNV)) - return FALSE; -# ifdef _WIN32 - GLH_EXT_NAME(wglAllocateMemoryNV) = (PFNWGLALLOCATEMEMORYNVPROC)GLH_EXT_GET_PROC_ADDRESS("wglAllocateMemoryNV"); - if (NULL == GLH_EXT_NAME(wglAllocateMemoryNV)) - return FALSE; -# endif -# ifdef GLX_VERSION_1_3 - GLH_EXT_NAME(glXAllocateMemoryNV) = (PFNGLXALLOCATEMEMORYNVPROC)GLH_EXT_GET_PROC_ADDRESS("glXAllocateMemoryNV"); - if (NULL == GLH_EXT_NAME(glXAllocateMemoryNV)) - return FALSE; -# endif -# ifdef _WIN32 - GLH_EXT_NAME(wglFreeMemoryNV) = (PFNWGLFREEMEMORYNVPROC)GLH_EXT_GET_PROC_ADDRESS("wglFreeMemoryNV"); - if (NULL == GLH_EXT_NAME(wglFreeMemoryNV)) - return FALSE; -# endif -# ifdef GLX_VERSION_1_3 - GLH_EXT_NAME(glXFreeMemoryNV) = (PFNGLXFREEMEMORYNVPROC)GLH_EXT_GET_PROC_ADDRESS("glXFreeMemoryNV"); - if (NULL == GLH_EXT_NAME(glXFreeMemoryNV)) - return FALSE; -# endif -#endif - -#ifdef GL_NV_vertex_program - } else if (0 == strcmp(extension, "GL_NV_vertex_program")) { - GLH_EXT_NAME(glAreProgramsResidentNV) = (PFNGLAREPROGRAMSRESIDENTNVPROC)GLH_EXT_GET_PROC_ADDRESS("glAreProgramsResidentNV"); - if (NULL == GLH_EXT_NAME(glAreProgramsResidentNV)) - return FALSE; - GLH_EXT_NAME(glBindProgramNV) = (PFNGLBINDPROGRAMNVPROC)GLH_EXT_GET_PROC_ADDRESS("glBindProgramNV"); - if (NULL == GLH_EXT_NAME(glBindProgramNV)) - return FALSE; - GLH_EXT_NAME(glDeleteProgramsNV) = (PFNGLDELETEPROGRAMSNVPROC)GLH_EXT_GET_PROC_ADDRESS("glDeleteProgramsNV"); - if (NULL == GLH_EXT_NAME(glDeleteProgramsNV)) - return FALSE; - GLH_EXT_NAME(glExecuteProgramNV) = (PFNGLEXECUTEPROGRAMNVPROC)GLH_EXT_GET_PROC_ADDRESS("glExecuteProgramNV"); - if (NULL == GLH_EXT_NAME(glExecuteProgramNV)) - return FALSE; - GLH_EXT_NAME(glGenProgramsNV) = (PFNGLGENPROGRAMSNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGenProgramsNV"); - if (NULL == GLH_EXT_NAME(glGenProgramsNV)) - return FALSE; - GLH_EXT_NAME(glGetProgramParameterdvNV) = (PFNGLGETPROGRAMPARAMETERDVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetProgramParameterdvNV"); - if (NULL == GLH_EXT_NAME(glGetProgramParameterdvNV)) - return FALSE; - GLH_EXT_NAME(glGetProgramParameterfvNV) = (PFNGLGETPROGRAMPARAMETERFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetProgramParameterfvNV"); - if (NULL == GLH_EXT_NAME(glGetProgramParameterfvNV)) - return FALSE; - GLH_EXT_NAME(glGetProgramivNV) = (PFNGLGETPROGRAMIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetProgramivNV"); - if (NULL == GLH_EXT_NAME(glGetProgramivNV)) - return FALSE; - GLH_EXT_NAME(glGetProgramStringNV) = (PFNGLGETPROGRAMSTRINGNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetProgramStringNV"); - if (NULL == GLH_EXT_NAME(glGetProgramStringNV)) - return FALSE; - GLH_EXT_NAME(glGetTrackMatrixivNV) = (PFNGLGETTRACKMATRIXIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetTrackMatrixivNV"); - if (NULL == GLH_EXT_NAME(glGetTrackMatrixivNV)) - return FALSE; - GLH_EXT_NAME(glGetVertexAttribdvNV) = (PFNGLGETVERTEXATTRIBDVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribdvNV"); - if (NULL == GLH_EXT_NAME(glGetVertexAttribdvNV)) - return FALSE; - GLH_EXT_NAME(glGetVertexAttribfvNV) = (PFNGLGETVERTEXATTRIBFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribfvNV"); - if (NULL == GLH_EXT_NAME(glGetVertexAttribfvNV)) - return FALSE; - GLH_EXT_NAME(glGetVertexAttribivNV) = (PFNGLGETVERTEXATTRIBIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribivNV"); - if (NULL == GLH_EXT_NAME(glGetVertexAttribivNV)) - return FALSE; - GLH_EXT_NAME(glGetVertexAttribPointervNV) = (PFNGLGETVERTEXATTRIBPOINTERVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribPointervNV"); - if (NULL == GLH_EXT_NAME(glGetVertexAttribPointervNV)) - return FALSE; - GLH_EXT_NAME(glIsProgramNV) = (PFNGLISPROGRAMNVPROC)GLH_EXT_GET_PROC_ADDRESS("glIsProgramNV"); - if (NULL == GLH_EXT_NAME(glIsProgramNV)) - return FALSE; - GLH_EXT_NAME(glLoadProgramNV) = (PFNGLLOADPROGRAMNVPROC)GLH_EXT_GET_PROC_ADDRESS("glLoadProgramNV"); - if (NULL == GLH_EXT_NAME(glLoadProgramNV)) - return FALSE; - GLH_EXT_NAME(glProgramParameter4dNV) = (PFNGLPROGRAMPARAMETER4DNVPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramParameter4dNV"); - if (NULL == GLH_EXT_NAME(glProgramParameter4dNV)) - return FALSE; - GLH_EXT_NAME(glProgramParameter4dvNV) = (PFNGLPROGRAMPARAMETER4DVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramParameter4dvNV"); - if (NULL == GLH_EXT_NAME(glProgramParameter4dvNV)) - return FALSE; - GLH_EXT_NAME(glProgramParameter4fNV) = (PFNGLPROGRAMPARAMETER4FNVPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramParameter4fNV"); - if (NULL == GLH_EXT_NAME(glProgramParameter4fNV)) - return FALSE; - GLH_EXT_NAME(glProgramParameter4fvNV) = (PFNGLPROGRAMPARAMETER4FVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramParameter4fvNV"); - if (NULL == GLH_EXT_NAME(glProgramParameter4fvNV)) - return FALSE; - GLH_EXT_NAME(glProgramParameters4dvNV) = (PFNGLPROGRAMPARAMETERS4DVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramParameters4dvNV"); - if (NULL == GLH_EXT_NAME(glProgramParameters4dvNV)) - return FALSE; - GLH_EXT_NAME(glProgramParameters4fvNV) = (PFNGLPROGRAMPARAMETERS4FVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramParameters4fvNV"); - if (NULL == GLH_EXT_NAME(glProgramParameters4fvNV)) - return FALSE; - GLH_EXT_NAME(glRequestResidentProgramsNV) = (PFNGLREQUESTRESIDENTPROGRAMSNVPROC)GLH_EXT_GET_PROC_ADDRESS("glRequestResidentProgramsNV"); - if (NULL == GLH_EXT_NAME(glRequestResidentProgramsNV)) - return FALSE; - GLH_EXT_NAME(glTrackMatrixNV) = (PFNGLTRACKMATRIXNVPROC)GLH_EXT_GET_PROC_ADDRESS("glTrackMatrixNV"); - if (NULL == GLH_EXT_NAME(glTrackMatrixNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttribPointerNV) = (PFNGLVERTEXATTRIBPOINTERNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribPointerNV"); - if (NULL == GLH_EXT_NAME(glVertexAttribPointerNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttrib1dNV) = (PFNGLVERTEXATTRIB1DNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1dNV"); - if (NULL == GLH_EXT_NAME(glVertexAttrib1dNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttrib1dvNV) = (PFNGLVERTEXATTRIB1DVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1dvNV"); - if (NULL == GLH_EXT_NAME(glVertexAttrib1dvNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttrib1fNV) = (PFNGLVERTEXATTRIB1FNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1fNV"); - if (NULL == GLH_EXT_NAME(glVertexAttrib1fNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttrib1fvNV) = (PFNGLVERTEXATTRIB1FVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1fvNV"); - if (NULL == GLH_EXT_NAME(glVertexAttrib1fvNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttrib1sNV) = (PFNGLVERTEXATTRIB1SNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1sNV"); - if (NULL == GLH_EXT_NAME(glVertexAttrib1sNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttrib1svNV) = (PFNGLVERTEXATTRIB1SVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1svNV"); - if (NULL == GLH_EXT_NAME(glVertexAttrib1svNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttrib2dNV) = (PFNGLVERTEXATTRIB2DNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2dNV"); - if (NULL == GLH_EXT_NAME(glVertexAttrib2dNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttrib2dvNV) = (PFNGLVERTEXATTRIB2DVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2dvNV"); - if (NULL == GLH_EXT_NAME(glVertexAttrib2dvNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttrib2fNV) = (PFNGLVERTEXATTRIB2FNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2fNV"); - if (NULL == GLH_EXT_NAME(glVertexAttrib2fNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttrib2fvNV) = (PFNGLVERTEXATTRIB2FVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2fvNV"); - if (NULL == GLH_EXT_NAME(glVertexAttrib2fvNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttrib2sNV) = (PFNGLVERTEXATTRIB2SNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2sNV"); - if (NULL == GLH_EXT_NAME(glVertexAttrib2sNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttrib2svNV) = (PFNGLVERTEXATTRIB2SVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2svNV"); - if (NULL == GLH_EXT_NAME(glVertexAttrib2svNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttrib3dNV) = (PFNGLVERTEXATTRIB3DNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3dNV"); - if (NULL == GLH_EXT_NAME(glVertexAttrib3dNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttrib3dvNV) = (PFNGLVERTEXATTRIB3DVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3dvNV"); - if (NULL == GLH_EXT_NAME(glVertexAttrib3dvNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttrib3fNV) = (PFNGLVERTEXATTRIB3FNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3fNV"); - if (NULL == GLH_EXT_NAME(glVertexAttrib3fNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttrib3fvNV) = (PFNGLVERTEXATTRIB3FVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3fvNV"); - if (NULL == GLH_EXT_NAME(glVertexAttrib3fvNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttrib3sNV) = (PFNGLVERTEXATTRIB3SNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3sNV"); - if (NULL == GLH_EXT_NAME(glVertexAttrib3sNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttrib3svNV) = (PFNGLVERTEXATTRIB3SVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3svNV"); - if (NULL == GLH_EXT_NAME(glVertexAttrib3svNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttrib4dNV) = (PFNGLVERTEXATTRIB4DNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4dNV"); - if (NULL == GLH_EXT_NAME(glVertexAttrib4dNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttrib4dvNV) = (PFNGLVERTEXATTRIB4DVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4dvNV"); - if (NULL == GLH_EXT_NAME(glVertexAttrib4dvNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttrib4fNV) = (PFNGLVERTEXATTRIB4FNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4fNV"); - if (NULL == GLH_EXT_NAME(glVertexAttrib4fNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttrib4fvNV) = (PFNGLVERTEXATTRIB4FVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4fvNV"); - if (NULL == GLH_EXT_NAME(glVertexAttrib4fvNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttrib4sNV) = (PFNGLVERTEXATTRIB4SNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4sNV"); - if (NULL == GLH_EXT_NAME(glVertexAttrib4sNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttrib4svNV) = (PFNGLVERTEXATTRIB4SVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4svNV"); - if (NULL == GLH_EXT_NAME(glVertexAttrib4svNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttrib4ubvNV) = (PFNGLVERTEXATTRIB4UBVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4ubvNV"); - if (NULL == GLH_EXT_NAME(glVertexAttrib4ubvNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttribs1dvNV) = (PFNGLVERTEXATTRIBS1DVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs1dvNV"); - if (NULL == GLH_EXT_NAME(glVertexAttribs1dvNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttribs1fvNV) = (PFNGLVERTEXATTRIBS1FVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs1fvNV"); - if (NULL == GLH_EXT_NAME(glVertexAttribs1fvNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttribs1svNV) = (PFNGLVERTEXATTRIBS1SVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs1svNV"); - if (NULL == GLH_EXT_NAME(glVertexAttribs1svNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttribs2dvNV) = (PFNGLVERTEXATTRIBS2DVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs2dvNV"); - if (NULL == GLH_EXT_NAME(glVertexAttribs2dvNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttribs2fvNV) = (PFNGLVERTEXATTRIBS2FVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs2fvNV"); - if (NULL == GLH_EXT_NAME(glVertexAttribs2fvNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttribs2svNV) = (PFNGLVERTEXATTRIBS2SVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs2svNV"); - if (NULL == GLH_EXT_NAME(glVertexAttribs2svNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttribs3dvNV) = (PFNGLVERTEXATTRIBS3DVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs3dvNV"); - if (NULL == GLH_EXT_NAME(glVertexAttribs3dvNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttribs3fvNV) = (PFNGLVERTEXATTRIBS3FVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs3fvNV"); - if (NULL == GLH_EXT_NAME(glVertexAttribs3fvNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttribs3svNV) = (PFNGLVERTEXATTRIBS3SVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs3svNV"); - if (NULL == GLH_EXT_NAME(glVertexAttribs3svNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttribs4dvNV) = (PFNGLVERTEXATTRIBS4DVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs4dvNV"); - if (NULL == GLH_EXT_NAME(glVertexAttribs4dvNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttribs4fvNV) = (PFNGLVERTEXATTRIBS4FVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs4fvNV"); - if (NULL == GLH_EXT_NAME(glVertexAttribs4fvNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttribs4svNV) = (PFNGLVERTEXATTRIBS4SVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs4svNV"); - if (NULL == GLH_EXT_NAME(glVertexAttribs4svNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttribs4ubvNV) = (PFNGLVERTEXATTRIBS4UBVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs4ubvNV"); - if (NULL == GLH_EXT_NAME(glVertexAttribs4ubvNV)) - return FALSE; -#endif - -#ifdef GL_SGIS_generate_mipmap - } else if (0 == strcmp(extension, "GL_SGIS_generate_mipmap")) { -#endif - -#ifdef GL_SGIS_texture_lod - } else if (0 == strcmp(extension, "GL_SGIS_texture_lod")) { -#endif - -#ifdef GL_SGIX_depth_texture - } else if (0 == strcmp(extension, "GL_SGIX_depth_texture")) { -#endif - -#ifdef GL_SGIX_shadow - } else if (0 == strcmp(extension, "GL_SGIX_shadow")) { -#endif - -#ifdef GL_VERSION_1_2 - } else if (0 == strcmp(extension, "GL_VERSION_1_2")) { - GLH_CORE_1_2_NAME(glBlendColor) = (PFNGLBLENDCOLORPROC)GLH_EXT_GET_PROC_ADDRESS("glBlendColor"); - if (NULL == GLH_CORE_1_2_NAME(glBlendColor)) - return FALSE; - GLH_CORE_1_2_NAME(glBlendEquation) = (PFNGLBLENDEQUATIONPROC)GLH_EXT_GET_PROC_ADDRESS("glBlendEquation"); - if (NULL == GLH_CORE_1_2_NAME(glBlendEquation)) - return FALSE; - GLH_CORE_1_2_NAME(glDrawRangeElements) = (PFNGLDRAWRANGEELEMENTSPROC)GLH_EXT_GET_PROC_ADDRESS("glDrawRangeElements"); - if (NULL == GLH_CORE_1_2_NAME(glDrawRangeElements)) - return FALSE; - GLH_CORE_1_2_NAME(glColorTable) = (PFNGLCOLORTABLEPROC)GLH_EXT_GET_PROC_ADDRESS("glColorTable"); - if (NULL == GLH_CORE_1_2_NAME(glColorTable)) - return FALSE; - GLH_CORE_1_2_NAME(glColorTableParameterfv) = (PFNGLCOLORTABLEPARAMETERFVPROC)GLH_EXT_GET_PROC_ADDRESS("glColorTableParameterfv"); - if (NULL == GLH_CORE_1_2_NAME(glColorTableParameterfv)) - return FALSE; - GLH_CORE_1_2_NAME(glColorTableParameteriv) = (PFNGLCOLORTABLEPARAMETERIVPROC)GLH_EXT_GET_PROC_ADDRESS("glColorTableParameteriv"); - if (NULL == GLH_CORE_1_2_NAME(glColorTableParameteriv)) - return FALSE; - GLH_CORE_1_2_NAME(glCopyColorTable) = (PFNGLCOPYCOLORTABLEPROC)GLH_EXT_GET_PROC_ADDRESS("glCopyColorTable"); - if (NULL == GLH_CORE_1_2_NAME(glCopyColorTable)) - return FALSE; - GLH_CORE_1_2_NAME(glGetColorTable) = (PFNGLGETCOLORTABLEPROC)GLH_EXT_GET_PROC_ADDRESS("glGetColorTable"); - if (NULL == GLH_CORE_1_2_NAME(glGetColorTable)) - return FALSE; - GLH_CORE_1_2_NAME(glGetColorTableParameterfv) = (PFNGLGETCOLORTABLEPARAMETERFVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetColorTableParameterfv"); - if (NULL == GLH_CORE_1_2_NAME(glGetColorTableParameterfv)) - return FALSE; - GLH_CORE_1_2_NAME(glGetColorTableParameteriv) = (PFNGLGETCOLORTABLEPARAMETERIVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetColorTableParameteriv"); - if (NULL == GLH_CORE_1_2_NAME(glGetColorTableParameteriv)) - return FALSE; - GLH_CORE_1_2_NAME(glTexImage3D) = (PFNGLTEXIMAGE3DPROC)GLH_EXT_GET_PROC_ADDRESS("glTexImage3D"); - if (NULL == GLH_CORE_1_2_NAME(glTexImage3D)) - return FALSE; - GLH_CORE_1_2_NAME(glTexSubImage3D) = (PFNGLTEXSUBIMAGE3DPROC)GLH_EXT_GET_PROC_ADDRESS("glTexSubImage3D"); - if (NULL == GLH_CORE_1_2_NAME(glTexSubImage3D)) - return FALSE; - GLH_CORE_1_2_NAME(glCopyTexSubImage3D) = (PFNGLCOPYTEXSUBIMAGE3DPROC)GLH_EXT_GET_PROC_ADDRESS("glCopyTexSubImage3D"); - if (NULL == GLH_CORE_1_2_NAME(glCopyTexSubImage3D)) - return FALSE; -#endif - -#ifdef GL_WIN_swap_hint - } else if (0 == strcmp(extension, "GL_WIN_swap_hint")) { - GLH_EXT_NAME(glAddSwapHintRectWIN) = (PFNGLADDSWAPHINTRECTWINPROC)GLH_EXT_GET_PROC_ADDRESS("glAddSwapHintRectWIN"); - if (NULL == GLH_EXT_NAME(glAddSwapHintRectWIN)) - return FALSE; -#endif - -#ifdef WGL_ARB_pbuffer - } else if (0 == strcmp(extension, "WGL_ARB_pbuffer")) { -# ifdef _WIN32 - GLH_EXT_NAME(wglCreatePbufferARB) = (PFNWGLCREATEPBUFFERARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglCreatePbufferARB"); - if (NULL == GLH_EXT_NAME(wglCreatePbufferARB)) - return FALSE; -# endif -# ifdef _WIN32 - GLH_EXT_NAME(wglGetPbufferDCARB) = (PFNWGLGETPBUFFERDCARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglGetPbufferDCARB"); - if (NULL == GLH_EXT_NAME(wglGetPbufferDCARB)) - return FALSE; -# endif -# ifdef _WIN32 - GLH_EXT_NAME(wglReleasePbufferDCARB) = (PFNWGLRELEASEPBUFFERDCARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglReleasePbufferDCARB"); - if (NULL == GLH_EXT_NAME(wglReleasePbufferDCARB)) - return FALSE; -# endif -# ifdef _WIN32 - GLH_EXT_NAME(wglDestroyPbufferARB) = (PFNWGLDESTROYPBUFFERARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglDestroyPbufferARB"); - if (NULL == GLH_EXT_NAME(wglDestroyPbufferARB)) - return FALSE; -# endif -# ifdef _WIN32 - GLH_EXT_NAME(wglQueryPbufferARB) = (PFNWGLQUERYPBUFFERARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglQueryPbufferARB"); - if (NULL == GLH_EXT_NAME(wglQueryPbufferARB)) - return FALSE; -# endif -#endif - -#ifdef WGL_ARB_render_texture -# ifdef _WIN32 - GLH_EXT_NAME(wglBindTexImageARB) = (PFNWGLBINDTEXIMAGEARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglBindTexImageARB"); - if (NULL == GLH_EXT_NAME(wglBindTexImageARB)) - return FALSE; -# endif -# ifdef _WIN32 - GLH_EXT_NAME(wglReleaseTexImageARB) = (PFNWGLRELEASETEXIMAGEARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglReleaseTexImageARB"); - if (NULL == GLH_EXT_NAME(wglReleaseTexImageARB)) - return FALSE; -# endif -# ifdef _WIN32 - GLH_EXT_NAME(wglSetPbufferAttribARB) = (PFNWGLSETPBUFFERATTRIBARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglSetPbufferAttribARB"); - if (NULL == GLH_EXT_NAME(wglSetPbufferAttribARB)) - return FALSE; -# endif -#endif - -#ifdef WGL_ARB_pixel_format - } else if (0 == strcmp(extension, "WGL_ARB_pixel_format")) { -# ifdef _WIN32 - GLH_EXT_NAME(wglGetPixelFormatAttribivARB) = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglGetPixelFormatAttribivARB"); - if (NULL == GLH_EXT_NAME(wglGetPixelFormatAttribivARB)) - return FALSE; -# endif -# ifdef _WIN32 - GLH_EXT_NAME(wglGetPixelFormatAttribfvARB) = (PFNWGLGETPIXELFORMATATTRIBFVARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglGetPixelFormatAttribfvARB"); - if (NULL == GLH_EXT_NAME(wglGetPixelFormatAttribfvARB)) - return FALSE; -# endif -# ifdef _WIN32 - GLH_EXT_NAME(wglChoosePixelFormatARB) = (PFNWGLCHOOSEPIXELFORMATARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglChoosePixelFormatARB"); - if (NULL == GLH_EXT_NAME(wglChoosePixelFormatARB)) - return FALSE; -# endif -#endif - - } else { - return FALSE; - } - return TRUE; -} -#endif - -#else // defined(__APPLE__) - -#ifdef GLH_EXT_SINGLE_FILE - -int glh_init_extension(const char* extension) -{ - // MBW -- XXX -- Should this check for extension availability? - return TRUE; -} -#endif // GLH_EXT_SINGLE_FILE - -#endif // defined(__APPLE__) - -#undef GLH_EXT_SINGLE_FILE - -#endif /* GLH_GENEXT_H */ diff --git a/indra/llwindow/glh/glh_linear.h b/indra/llwindow/glh/glh_linear.h deleted file mode 100644 index 04ae1bd066..0000000000 --- a/indra/llwindow/glh/glh_linear.h +++ /dev/null @@ -1,1621 +0,0 @@ -/* - glh - is a platform-indepenedent C++ OpenGL helper library - - - Copyright (c) 2000 Cass Everitt - Copyright (c) 2000 NVIDIA Corporation - All rights reserved. - - Redistribution and use in source and binary forms, with or - without modification, are permitted provided that the following - conditions are met: - - * Redistributions of source code must retain the above - copyright notice, this list of conditions and the following - disclaimer. - - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials - provided with the distribution. - - * The names of contributors to this software may not be used - to endorse or promote products derived from this software - without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. - - - Cass Everitt - cass@r3.nu -*/ - -/* -glh_linear.h -*/ - -// Author: Cass W. Everitt - -#ifndef GLH_LINEAR_H -#define GLH_LINEAR_H - -#include -#include -#include - -// only supports float for now... -#define GLH_REAL_IS_FLOAT - -#ifdef GLH_REAL_IS_FLOAT -# define GLH_REAL float -# define GLH_REAL_NAMESPACE ns_float -#endif - -#define GLH_QUATERNION_NORMALIZATION_THRESHOLD 64 - -#define GLH_RAD_TO_DEG GLH_REAL(57.2957795130823208767981548141052) -#define GLH_DEG_TO_RAD GLH_REAL(0.0174532925199432957692369076848861) -#define GLH_ZERO GLH_REAL(0.0) -#define GLH_ONE GLH_REAL(1.0) -#define GLH_TWO GLH_REAL(2.0) -#define GLH_EPSILON GLH_REAL(10e-6) -#define GLH_PI GLH_REAL(3.1415926535897932384626433832795) - -#define equivalent(a,b) (((a < b + GLH_EPSILON) && (a > b - GLH_EPSILON)) ? true : false) - -namespace glh -{ - - inline GLH_REAL to_degrees(GLH_REAL radians) { return radians*GLH_RAD_TO_DEG; } - inline GLH_REAL to_radians(GLH_REAL degrees) { return degrees*GLH_DEG_TO_RAD; } - - // forward declarations for friend template functions. - template class vec; - - // forward declarations for friend template functions. - template - bool operator == ( const vec & v1, const vec & v2 ); - - // forward declarations for friend template functions. - template - bool operator != ( const vec & v1, const vec & v2 ); - - template - class vec - { - public: - int size() const { return N; } - - vec(const T & t = T()) - { for(int i = 0; i < N; i++) v[i] = t; } - vec(const T * tp) - { for(int i = 0; i < N; i++) v[i] = tp[i]; } - - const T * get_value() const - { return v; } - - - T dot( const vec & rhs ) const - { - T r = 0; - for(int i = 0; i < N; i++) r += v[i]*rhs.v[i]; - return r; - } - - T length() const - { - T r = 0; - for(int i = 0; i < N; i++) r += v[i]*v[i]; - return T(sqrt(r)); - } - - T square_norm() const - { - T r = 0; - for(int i = 0; i < N; i++) r += v[i]*v[i]; - return r; - } - - void negate() - { for(int i = 0; i < N; i++) v[i] = -v[i]; } - - - T normalize() - { - T sum(0); - for(int i = 0; i < N; i++) - sum += v[i]*v[i]; - sum = T(sqrt(sum)); - if (sum > GLH_EPSILON) - for(int i = 0; i < N; i++) - v[i] /= sum; - return sum; - } - - - vec & set_value( const T * rhs ) - { for(int i = 0; i < N; i++) v[i] = rhs[i]; return *this; } - - T & operator [] ( int i ) - { return v[i]; } - - const T & operator [] ( int i ) const - { return v[i]; } - - vec & operator *= ( T d ) - { for(int i = 0; i < N; i++) v[i] *= d; return *this;} - - vec & operator *= ( const vec & u ) - { for(int i = 0; i < N; i++) v[i] *= u[i]; return *this;} - - vec & operator /= ( T d ) - { if(d == 0) return *this; for(int i = 0; i < N; i++) v[i] /= d; return *this;} - - vec & operator += ( const vec & u ) - { for(int i = 0; i < N; i++) v[i] += u.v[i]; return *this;} - - vec & operator -= ( const vec & u ) - { for(int i = 0; i < N; i++) v[i] -= u.v[i]; return *this;} - - - vec operator - () const - { vec rv = v; rv.negate(); return rv; } - - vec operator + ( const vec &v) const - { vec rt(*this); return rt += v; } - - vec operator - ( const vec &v) const - { vec rt(*this); return rt -= v; } - - vec operator * ( T d) const - { vec rt(*this); return rt *= d; } - - friend bool operator == <> ( const vec &v1, const vec &v2 ); - friend bool operator != <> ( const vec &v1, const vec &v2 ); - - - //protected: - T v[N]; - }; - - - - // vector friend operators - - template inline - vec operator * ( const vec & b, T d ) - { - vec rt(b); - return rt *= d; - } - - template inline - vec operator * ( T d, const vec & b ) - { return b*d; } - - template inline - vec operator * ( const vec & b, const vec & d ) - { - vec rt(b); - return rt *= d; - } - - template inline - vec operator / ( const vec & b, T d ) - { vec rt(b); return rt /= d; } - - template inline - vec operator + ( const vec & v1, const vec & v2 ) - { vec rt(v1); return rt += v2; } - - template inline - vec operator - ( const vec & v1, const vec & v2 ) - { vec rt(v1); return rt -= v2; } - - - template inline - bool operator == ( const vec & v1, const vec & v2 ) - { - for(int i = 0; i < N; i++) - if(v1.v[i] != v2.v[i]) - return false; - return true; - } - - template inline - bool operator != ( const vec & v1, const vec & v2 ) - { return !(v1 == v2); } - - - typedef vec<3,unsigned char> vec3ub; - typedef vec<4,unsigned char> vec4ub; - - - - - - namespace GLH_REAL_NAMESPACE - { - typedef GLH_REAL real; - - class line; - class plane; - class matrix4; - class quaternion; - typedef quaternion rotation; - - class vec2 : public vec<2,real> - { - public: - vec2(const real & t = real()) : vec<2,real>(t) - {} - vec2(const vec<2,real> & t) : vec<2,real>(t) - {} - vec2(const real * tp) : vec<2,real>(tp) - {} - - vec2(real x, real y ) - { v[0] = x; v[1] = y; } - - void get_value(real & x, real & y) const - { x = v[0]; y = v[1]; } - - vec2 & set_value( const real & x, const real & y) - { v[0] = x; v[1] = y; return *this; } - - }; - - - class vec3 : public vec<3,real> - { - public: - vec3(const real & t = real()) : vec<3,real>(t) - {} - vec3(const vec<3,real> & t) : vec<3,real>(t) - {} - vec3(const real * tp) : vec<3,real>(tp) - {} - - vec3(real x, real y, real z) - { v[0] = x; v[1] = y; v[2] = z; } - - void get_value(real & x, real & y, real & z) const - { x = v[0]; y = v[1]; z = v[2]; } - - vec3 cross( const vec3 &rhs ) const - { - vec3 rt; - rt.v[0] = v[1]*rhs.v[2]-v[2]*rhs.v[1]; - rt.v[1] = v[2]*rhs.v[0]-v[0]*rhs.v[2]; - rt.v[2] = v[0]*rhs.v[1]-v[1]*rhs.v[0]; - return rt; - } - - vec3 & set_value( const real & x, const real & y, const real & z) - { v[0] = x; v[1] = y; v[2] = z; return *this; } - - }; - - - class vec4 : public vec<4,real> - { - public: - vec4(const real & t = real()) : vec<4,real>(t) - {} - vec4(const vec<4,real> & t) : vec<4,real>(t) - {} - - vec4(const vec<3,real> & t, real fourth) - - { v[0] = t.v[0]; v[1] = t.v[1]; v[2] = t.v[2]; v[3] = fourth; } - vec4(const real * tp) : vec<4,real>(tp) - {} - vec4(real x, real y, real z, real w) - { v[0] = x; v[1] = y; v[2] = z; v[3] = w; } - - void get_value(real & x, real & y, real & z, real & w) const - { x = v[0]; y = v[1]; z = v[2]; w = v[3]; } - - vec4 & set_value( const real & x, const real & y, const real & z, const real & w) - { v[0] = x; v[1] = y; v[2] = z; v[3] = w; return *this; } - }; - - inline - vec3 homogenize(const vec4 & v) - { - vec3 rt; - assert(v.v[3] != GLH_ZERO); - rt.v[0] = v.v[0]/v.v[3]; - rt.v[1] = v.v[1]/v.v[3]; - rt.v[2] = v.v[2]/v.v[3]; - return rt; - } - - - - class line - { - public: - - line() - { set_value(vec3(0,0,0),vec3(0,0,1)); } - - line( const vec3 & p0, const vec3 &p1) - { set_value(p0,p1); } - - void set_value( const vec3 &p0, const vec3 &p1) - { - position = p0; - direction = p1-p0; - direction.normalize(); - } - - bool get_closest_points(const line &line2, - vec3 &pointOnThis, - vec3 &pointOnThat) - { - - // quick check to see if parallel -- if so, quit. - if(fabs(direction.dot(line2.direction)) == 1.0) - return 0; - line l2 = line2; - - // Algorithm: Brian Jean - // - register real u; - register real v; - vec3 Vr = direction; - vec3 Vs = l2.direction; - register real Vr_Dot_Vs = Vr.dot(Vs); - register real detA = real(1.0 - (Vr_Dot_Vs * Vr_Dot_Vs)); - vec3 C = l2.position - position; - register real C_Dot_Vr = C.dot(Vr); - register real C_Dot_Vs = C.dot(Vs); - - u = (C_Dot_Vr - Vr_Dot_Vs * C_Dot_Vs)/detA; - v = (C_Dot_Vr * Vr_Dot_Vs - C_Dot_Vs)/detA; - - pointOnThis = position; - pointOnThis += direction * u; - pointOnThat = l2.position; - pointOnThat += l2.direction * v; - - return 1; - } - - vec3 get_closest_point(const vec3 &point) - { - vec3 np = point - position; - vec3 rp = direction*direction.dot(np)+position; - return rp; - } - - const vec3 & get_position() const {return position;} - - const vec3 & get_direction() const {return direction;} - - //protected: - vec3 position; - vec3 direction; - }; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // matrix - - - class matrix4 - { - - public: - - matrix4() { make_identity(); } - - matrix4( real r ) - { set_value(r); } - - matrix4( real * m ) - { set_value(m); } - - matrix4( real a00, real a01, real a02, real a03, - real a10, real a11, real a12, real a13, - real a20, real a21, real a22, real a23, - real a30, real a31, real a32, real a33 ) - { - element(0,0) = a00; - element(0,1) = a01; - element(0,2) = a02; - element(0,3) = a03; - - element(1,0) = a10; - element(1,1) = a11; - element(1,2) = a12; - element(1,3) = a13; - - element(2,0) = a20; - element(2,1) = a21; - element(2,2) = a22; - element(2,3) = a23; - - element(3,0) = a30; - element(3,1) = a31; - element(3,2) = a32; - element(3,3) = a33; - } - - - void get_value( real * mp ) const - { - int c = 0; - for(int j=0; j < 4; j++) - for(int i=0; i < 4; i++) - mp[c++] = element(i,j); - } - - - const real * get_value() const - { return m; } - - void set_value( real * mp) - { - int c = 0; - for(int j=0; j < 4; j++) - for(int i=0; i < 4; i++) - element(i,j) = mp[c++]; - } - - void set_value( real r ) - { - for(int i=0; i < 4; i++) - for(int j=0; j < 4; j++) - element(i,j) = r; - } - - void make_identity() - { - element(0,0) = 1.0; - element(0,1) = 0.0; - element(0,2) = 0.0; - element(0,3) = 0.0; - - element(1,0) = 0.0; - element(1,1) = 1.0; - element(1,2) = 0.0; - element(1,3) = 0.0; - - element(2,0) = 0.0; - element(2,1) = 0.0; - element(2,2) = 1.0; - element(2,3) = 0.0; - - element(3,0) = 0.0; - element(3,1) = 0.0; - element(3,2) = 0.0; - element(3,3) = 1.0; - } - - - static matrix4 identity() - { - static matrix4 mident ( - 1.0, 0.0, 0.0, 0.0, - 0.0, 1.0, 0.0, 0.0, - 0.0, 0.0, 1.0, 0.0, - 0.0, 0.0, 0.0, 1.0 ); - return mident; - } - - - void set_scale( real s ) - { - element(0,0) = s; - element(1,1) = s; - element(2,2) = s; - } - - void set_scale( const vec3 & s ) - { - element(0,0) = s.v[0]; - element(1,1) = s.v[1]; - element(2,2) = s.v[2]; - } - - - void set_translate( const vec3 & t ) - { - element(0,3) = t.v[0]; - element(1,3) = t.v[1]; - element(2,3) = t.v[2]; - } - - void set_row(int r, const vec4 & t) - { - element(r,0) = t.v[0]; - element(r,1) = t.v[1]; - element(r,2) = t.v[2]; - element(r,3) = t.v[3]; - } - - void set_column(int c, const vec4 & t) - { - element(0,c) = t.v[0]; - element(1,c) = t.v[1]; - element(2,c) = t.v[2]; - element(3,c) = t.v[3]; - } - - - void get_row(int r, vec4 & t) const - { - t.v[0] = element(r,0); - t.v[1] = element(r,1); - t.v[2] = element(r,2); - t.v[3] = element(r,3); - } - - vec4 get_row(int r) const - { - vec4 v; get_row(r, v); - return v; - } - - void get_column(int c, vec4 & t) const - { - t.v[0] = element(0,c); - t.v[1] = element(1,c); - t.v[2] = element(2,c); - t.v[3] = element(3,c); - } - - vec4 get_column(int c) const - { - vec4 v; get_column(c, v); - return v; - } - - matrix4 inverse() const - { - matrix4 minv; - - real r1[8], r2[8], r3[8], r4[8]; - real *s[4], *tmprow; - - s[0] = &r1[0]; - s[1] = &r2[0]; - s[2] = &r3[0]; - s[3] = &r4[0]; - - register int i,j,p,jj; - for(i=0;i<4;i++) - { - for(j=0;j<4;j++) - { - s[i][j] = element(i,j); - if(i==j) s[i][j+4] = 1.0; - else s[i][j+4] = 0.0; - } - } - real scp[4]; - for(i=0;i<4;i++) - { - scp[i] = real(fabs(s[i][0])); - for(j=1;j<4;j++) - if(real(fabs(s[i][j])) > scp[i]) scp[i] = real(fabs(s[i][j])); - if(scp[i] == 0.0) return minv; // singular matrix! - } - - int pivot_to; - real scp_max; - for(i=0;i<4;i++) - { - // select pivot row - pivot_to = i; - scp_max = real(fabs(s[i][i]/scp[i])); - // find out which row should be on top - for(p=i+1;p<4;p++) - if(real(fabs(s[p][i]/scp[p])) > scp_max) - { scp_max = real(fabs(s[p][i]/scp[p])); pivot_to = p; } - // Pivot if necessary - if(pivot_to != i) - { - tmprow = s[i]; - s[i] = s[pivot_to]; - s[pivot_to] = tmprow; - real tmpscp; - tmpscp = scp[i]; - scp[i] = scp[pivot_to]; - scp[pivot_to] = tmpscp; - } - - real mji; - // perform gaussian elimination - for(j=i+1;j<4;j++) - { - mji = s[j][i]/s[i][i]; - s[j][i] = 0.0; - for(jj=i+1;jj<8;jj++) - s[j][jj] -= mji*s[i][jj]; - } - } - if(s[3][3] == 0.0) return minv; // singular matrix! - - // - // Now we have an upper triangular matrix. - // - // x x x x | y y y y - // 0 x x x | y y y y - // 0 0 x x | y y y y - // 0 0 0 x | y y y y - // - // we'll back substitute to get the inverse - // - // 1 0 0 0 | z z z z - // 0 1 0 0 | z z z z - // 0 0 1 0 | z z z z - // 0 0 0 1 | z z z z - // - - real mij; - for(i=3;i>0;i--) - { - for(j=i-1;j > -1; j--) - { - mij = s[j][i]/s[i][i]; - for(jj=j+1;jj<8;jj++) - s[j][jj] -= mij*s[i][jj]; - } - } - - for(i=0;i<4;i++) - for(j=0;j<4;j++) - minv(i,j) = s[i][j+4] / s[i][i]; - - return minv; - } - - - matrix4 transpose() const - { - matrix4 mtrans; - - for(int i=0;i<4;i++) - for(int j=0;j<4;j++) - mtrans(i,j) = element(j,i); - return mtrans; - } - - matrix4 & mult_right( const matrix4 & b ) - { - matrix4 mt(*this); - set_value(real(0)); - - for(int i=0; i < 4; i++) - for(int j=0; j < 4; j++) - for(int c=0; c < 4; c++) - element(i,j) += mt(i,c) * b(c,j); - return *this; - } - - matrix4 & mult_left( const matrix4 & b ) - { - matrix4 mt(*this); - set_value(real(0)); - - for(int i=0; i < 4; i++) - for(int j=0; j < 4; j++) - for(int c=0; c < 4; c++) - element(i,j) += b(i,c) * mt(c,j); - return *this; - } - - // dst = M * src - void mult_matrix_vec( const vec3 &src, vec3 &dst ) const - { - real w = ( - src.v[0] * element(3,0) + - src.v[1] * element(3,1) + - src.v[2] * element(3,2) + - element(3,3) ); - - assert(w != GLH_ZERO); - - dst.v[0] = ( - src.v[0] * element(0,0) + - src.v[1] * element(0,1) + - src.v[2] * element(0,2) + - element(0,3) ) / w; - dst.v[1] = ( - src.v[0] * element(1,0) + - src.v[1] * element(1,1) + - src.v[2] * element(1,2) + - element(1,3) ) / w; - dst.v[2] = ( - src.v[0] * element(2,0) + - src.v[1] * element(2,1) + - src.v[2] * element(2,2) + - element(2,3) ) / w; - } - - void mult_matrix_vec( vec3 & src_and_dst) const - { mult_matrix_vec(vec3(src_and_dst), src_and_dst); } - - - // dst = src * M - void mult_vec_matrix( const vec3 &src, vec3 &dst ) const - { - real w = ( - src.v[0] * element(0,3) + - src.v[1] * element(1,3) + - src.v[2] * element(2,3) + - element(3,3) ); - - assert(w != GLH_ZERO); - - dst.v[0] = ( - src.v[0] * element(0,0) + - src.v[1] * element(1,0) + - src.v[2] * element(2,0) + - element(3,0) ) / w; - dst.v[1] = ( - src.v[0] * element(0,1) + - src.v[1] * element(1,1) + - src.v[2] * element(2,1) + - element(3,1) ) / w; - dst.v[2] = ( - src.v[0] * element(0,2) + - src.v[1] * element(1,2) + - src.v[2] * element(2,2) + - element(3,2) ) / w; - } - - - void mult_vec_matrix( vec3 & src_and_dst) const - { mult_vec_matrix(vec3(src_and_dst), src_and_dst); } - - // dst = M * src - void mult_matrix_vec( const vec4 &src, vec4 &dst ) const - { - dst.v[0] = ( - src.v[0] * element(0,0) + - src.v[1] * element(0,1) + - src.v[2] * element(0,2) + - src.v[3] * element(0,3)); - dst.v[1] = ( - src.v[0] * element(1,0) + - src.v[1] * element(1,1) + - src.v[2] * element(1,2) + - src.v[3] * element(1,3)); - dst.v[2] = ( - src.v[0] * element(2,0) + - src.v[1] * element(2,1) + - src.v[2] * element(2,2) + - src.v[3] * element(2,3)); - dst.v[3] = ( - src.v[0] * element(3,0) + - src.v[1] * element(3,1) + - src.v[2] * element(3,2) + - src.v[3] * element(3,3)); - } - - void mult_matrix_vec( vec4 & src_and_dst) const - { mult_matrix_vec(vec4(src_and_dst), src_and_dst); } - - - // dst = src * M - void mult_vec_matrix( const vec4 &src, vec4 &dst ) const - { - dst.v[0] = ( - src.v[0] * element(0,0) + - src.v[1] * element(1,0) + - src.v[2] * element(2,0) + - src.v[3] * element(3,0)); - dst.v[1] = ( - src.v[0] * element(0,1) + - src.v[1] * element(1,1) + - src.v[2] * element(2,1) + - src.v[3] * element(3,1)); - dst.v[2] = ( - src.v[0] * element(0,2) + - src.v[1] * element(1,2) + - src.v[2] * element(2,2) + - src.v[3] * element(3,2)); - dst.v[3] = ( - src.v[0] * element(0,3) + - src.v[1] * element(1,3) + - src.v[2] * element(2,3) + - src.v[3] * element(3,3)); - } - - - void mult_vec_matrix( vec4 & src_and_dst) const - { mult_vec_matrix(vec4(src_and_dst), src_and_dst); } - - - // dst = M * src - void mult_matrix_dir( const vec3 &src, vec3 &dst ) const - { - dst.v[0] = ( - src.v[0] * element(0,0) + - src.v[1] * element(0,1) + - src.v[2] * element(0,2) ) ; - dst.v[1] = ( - src.v[0] * element(1,0) + - src.v[1] * element(1,1) + - src.v[2] * element(1,2) ) ; - dst.v[2] = ( - src.v[0] * element(2,0) + - src.v[1] * element(2,1) + - src.v[2] * element(2,2) ) ; - } - - - void mult_matrix_dir( vec3 & src_and_dst) const - { mult_matrix_dir(vec3(src_and_dst), src_and_dst); } - - - // dst = src * M - void mult_dir_matrix( const vec3 &src, vec3 &dst ) const - { - dst.v[0] = ( - src.v[0] * element(0,0) + - src.v[1] * element(1,0) + - src.v[2] * element(2,0) ) ; - dst.v[1] = ( - src.v[0] * element(0,1) + - src.v[1] * element(1,1) + - src.v[2] * element(2,1) ) ; - dst.v[2] = ( - src.v[0] * element(0,2) + - src.v[1] * element(1,2) + - src.v[2] * element(2,2) ) ; - } - - - void mult_dir_matrix( vec3 & src_and_dst) const - { mult_dir_matrix(vec3(src_and_dst), src_and_dst); } - - - real & operator () (int row, int col) - { return element(row,col); } - - const real & operator () (int row, int col) const - { return element(row,col); } - - real & element (int row, int col) - { return m[row | (col<<2)]; } - - const real & element (int row, int col) const - { return m[row | (col<<2)]; } - - matrix4 & operator *= ( const matrix4 & mat ) - { - mult_right( mat ); - return *this; - } - - matrix4 & operator *= ( const real & r ) - { - for (int i = 0; i < 4; ++i) - { - element(0,i) *= r; - element(1,i) *= r; - element(2,i) *= r; - element(3,i) *= r; - } - return *this; - } - - matrix4 & operator += ( const matrix4 & mat ) - { - for (int i = 0; i < 4; ++i) - { - element(0,i) += mat.element(0,i); - element(1,i) += mat.element(1,i); - element(2,i) += mat.element(2,i); - element(3,i) += mat.element(3,i); - } - return *this; - } - - friend matrix4 operator * ( const matrix4 & m1, const matrix4 & m2 ); - friend bool operator == ( const matrix4 & m1, const matrix4 & m2 ); - friend bool operator != ( const matrix4 & m1, const matrix4 & m2 ); - - //protected: - real m[16]; - }; - - inline - matrix4 operator * ( const matrix4 & m1, const matrix4 & m2 ) - { - matrix4 product; - - product = m1; - product.mult_right(m2); - - return product; - } - - inline - bool operator ==( const matrix4 &m1, const matrix4 &m2 ) - { - return ( - m1(0,0) == m2(0,0) && - m1(0,1) == m2(0,1) && - m1(0,2) == m2(0,2) && - m1(0,3) == m2(0,3) && - m1(1,0) == m2(1,0) && - m1(1,1) == m2(1,1) && - m1(1,2) == m2(1,2) && - m1(1,3) == m2(1,3) && - m1(2,0) == m2(2,0) && - m1(2,1) == m2(2,1) && - m1(2,2) == m2(2,2) && - m1(2,3) == m2(2,3) && - m1(3,0) == m2(3,0) && - m1(3,1) == m2(3,1) && - m1(3,2) == m2(3,2) && - m1(3,3) == m2(3,3) ); - } - - inline - bool operator != ( const matrix4 & m1, const matrix4 & m2 ) - { return !( m1 == m2 ); } - - - - - - - - - - - - - - class quaternion - { - public: - - quaternion() - { - *this = identity(); - } - - quaternion( const real v[4] ) - { - set_value( v ); - } - - - quaternion( real q0, real q1, real q2, real q3 ) - { - set_value( q0, q1, q2, q3 ); - } - - - quaternion( const matrix4 & m ) - { - set_value( m ); - } - - - quaternion( const vec3 &axis, real radians ) - { - set_value( axis, radians ); - } - - - quaternion( const vec3 &rotateFrom, const vec3 &rotateTo ) - { - set_value( rotateFrom, rotateTo ); - } - - quaternion( const vec3 & from_look, const vec3 & from_up, - const vec3 & to_look, const vec3& to_up) - { - set_value(from_look, from_up, to_look, to_up); - } - - const real * get_value() const - { - return &q[0]; - } - - void get_value( real &q0, real &q1, real &q2, real &q3 ) const - { - q0 = q[0]; - q1 = q[1]; - q2 = q[2]; - q3 = q[3]; - } - - quaternion & set_value( real q0, real q1, real q2, real q3 ) - { - q[0] = q0; - q[1] = q1; - q[2] = q2; - q[3] = q3; - counter = 0; - return *this; - } - - void get_value( vec3 &axis, real &radians ) const - { - radians = real(acos( q[3] ) * GLH_TWO); - if ( radians == GLH_ZERO ) - axis = vec3( 0.0, 0.0, 1.0 ); - else - { - axis.v[0] = q[0]; - axis.v[1] = q[1]; - axis.v[2] = q[2]; - axis.normalize(); - } - } - - void get_value( matrix4 & m ) const - { - real s, xs, ys, zs, wx, wy, wz, xx, xy, xz, yy, yz, zz; - - real norm = q[0] * q[0] + q[1] * q[1] + q[2] * q[2] + q[3] * q[3]; - - s = (equivalent(norm,GLH_ZERO)) ? GLH_ZERO : ( GLH_TWO / norm ); - - xs = q[0] * s; - ys = q[1] * s; - zs = q[2] * s; - - wx = q[3] * xs; - wy = q[3] * ys; - wz = q[3] * zs; - - xx = q[0] * xs; - xy = q[0] * ys; - xz = q[0] * zs; - - yy = q[1] * ys; - yz = q[1] * zs; - zz = q[2] * zs; - - m(0,0) = real( GLH_ONE - ( yy + zz )); - m(1,0) = real ( xy + wz ); - m(2,0) = real ( xz - wy ); - - m(0,1) = real ( xy - wz ); - m(1,1) = real ( GLH_ONE - ( xx + zz )); - m(2,1) = real ( yz + wx ); - - m(0,2) = real ( xz + wy ); - m(1,2) = real ( yz - wx ); - m(2,2) = real ( GLH_ONE - ( xx + yy )); - - m(3,0) = m(3,1) = m(3,2) = m(0,3) = m(1,3) = m(2,3) = GLH_ZERO; - m(3,3) = GLH_ONE; - } - - quaternion & set_value( const real * qp ) - { - memcpy(q,qp,sizeof(real) * 4); - - counter = 0; - return *this; - } - - quaternion & set_value( const matrix4 & m ) - { - real tr, s; - int i, j, k; - const int nxt[3] = { 1, 2, 0 }; - - tr = m(0,0) + m(1,1) + m(2,2); - - if ( tr > GLH_ZERO ) - { - s = real(sqrt( tr + m(3,3) )); - q[3] = real ( s * 0.5 ); - s = real(0.5) / s; - - q[0] = real ( ( m(1,2) - m(2,1) ) * s ); - q[1] = real ( ( m(2,0) - m(0,2) ) * s ); - q[2] = real ( ( m(0,1) - m(1,0) ) * s ); - } - else - { - i = 0; - if ( m(1,1) > m(0,0) ) - i = 1; - - if ( m(2,2) > m(i,i) ) - i = 2; - - j = nxt[i]; - k = nxt[j]; - - s = real(sqrt( ( m(i,j) - ( m(j,j) + m(k,k) )) + GLH_ONE )); - - q[i] = real ( s * 0.5 ); - s = real(0.5 / s); - - q[3] = real ( ( m(j,k) - m(k,j) ) * s ); - q[j] = real ( ( m(i,j) + m(j,i) ) * s ); - q[k] = real ( ( m(i,k) + m(k,i) ) * s ); - } - - counter = 0; - return *this; - } - - quaternion & set_value( const vec3 &axis, real theta ) - { - real sqnorm = axis.square_norm(); - - if (sqnorm <= GLH_EPSILON) - { - // axis too small. - x = y = z = 0.0; - w = 1.0; - } - else - { - theta *= real(0.5); - real sin_theta = real(sin(theta)); - - if (!equivalent(sqnorm,GLH_ONE)) - sin_theta /= real(sqrt(sqnorm)); - x = sin_theta * axis.v[0]; - y = sin_theta * axis.v[1]; - z = sin_theta * axis.v[2]; - w = real(cos(theta)); - } - return *this; - } - - quaternion & set_value( const vec3 & rotateFrom, const vec3 & rotateTo ) - { - vec3 p1, p2; - real alpha; - - p1 = rotateFrom; - p1.normalize(); - p2 = rotateTo; - p2.normalize(); - - alpha = p1.dot(p2); - - if(equivalent(alpha,GLH_ONE)) - { - *this = identity(); - return *this; - } - - // ensures that the anti-parallel case leads to a positive dot - if(equivalent(alpha,-GLH_ONE)) - { - vec3 v; - - if(p1.v[0] != p1.v[1] || p1.v[0] != p1.v[2]) - v = vec3(p1.v[1], p1.v[2], p1.v[0]); - else - v = vec3(-p1.v[0], p1.v[1], p1.v[2]); - - v -= p1 * p1.dot(v); - v.normalize(); - - set_value(v, GLH_PI); - return *this; - } - - p1 = p1.cross(p2); - p1.normalize(); - set_value(p1,real(acos(alpha))); - - counter = 0; - return *this; - } - - quaternion & set_value( const vec3 & from_look, const vec3 & from_up, - const vec3 & to_look, const vec3 & to_up) - { - quaternion r_look = quaternion(from_look, to_look); - - vec3 rotated_from_up(from_up); - r_look.mult_vec(rotated_from_up); - - quaternion r_twist = quaternion(rotated_from_up, to_up); - - *this = r_twist; - *this *= r_look; - return *this; - } - - quaternion & operator *= ( const quaternion & qr ) - { - quaternion ql(*this); - - w = ql.w * qr.w - ql.x * qr.x - ql.y * qr.y - ql.z * qr.z; - x = ql.w * qr.x + ql.x * qr.w + ql.y * qr.z - ql.z * qr.y; - y = ql.w * qr.y + ql.y * qr.w + ql.z * qr.x - ql.x * qr.z; - z = ql.w * qr.z + ql.z * qr.w + ql.x * qr.y - ql.y * qr.x; - - counter += qr.counter; - counter++; - counter_normalize(); - return *this; - } - - void normalize() - { - real rnorm = GLH_ONE / real(sqrt(w * w + x * x + y * y + z * z)); - if (equivalent(rnorm, GLH_ZERO)) - return; - x *= rnorm; - y *= rnorm; - z *= rnorm; - w *= rnorm; - counter = 0; - } - - friend bool operator == ( const quaternion & q1, const quaternion & q2 ); - - friend bool operator != ( const quaternion & q1, const quaternion & q2 ); - - friend quaternion operator * ( const quaternion & q1, const quaternion & q2 ); - - bool equals( const quaternion & r, real tolerance ) const - { - real t; - - t = ( - (q[0]-r.q[0])*(q[0]-r.q[0]) + - (q[1]-r.q[1])*(q[1]-r.q[1]) + - (q[2]-r.q[2])*(q[2]-r.q[2]) + - (q[3]-r.q[3])*(q[3]-r.q[3]) ); - if(t > GLH_EPSILON) - return false; - return 1; - } - - quaternion & conjugate() - { - q[0] *= -GLH_ONE; - q[1] *= -GLH_ONE; - q[2] *= -GLH_ONE; - return *this; - } - - quaternion & invert() - { - return conjugate(); - } - - quaternion inverse() const - { - quaternion r = *this; - return r.invert(); - } - - // - // Quaternion multiplication with cartesian vector - // v' = q*v*q(star) - // - void mult_vec( const vec3 &src, vec3 &dst ) const - { - real v_coef = w * w - x * x - y * y - z * z; - real u_coef = GLH_TWO * (src.v[0] * x + src.v[1] * y + src.v[2] * z); - real c_coef = GLH_TWO * w; - - dst.v[0] = v_coef * src.v[0] + u_coef * x + c_coef * (y * src.v[2] - z * src.v[1]); - dst.v[1] = v_coef * src.v[1] + u_coef * y + c_coef * (z * src.v[0] - x * src.v[2]); - dst.v[2] = v_coef * src.v[2] + u_coef * z + c_coef * (x * src.v[1] - y * src.v[0]); - } - - void mult_vec( vec3 & src_and_dst) const - { - mult_vec(vec3(src_and_dst), src_and_dst); - } - - void scale_angle( real scaleFactor ) - { - vec3 axis; - real radians; - - get_value(axis, radians); - radians *= scaleFactor; - set_value(axis, radians); - } - - static quaternion slerp( const quaternion & p, const quaternion & q, real alpha ) - { - quaternion r; - - real cos_omega = p.x * q.x + p.y * q.y + p.z * q.z + p.w * q.w; - // if B is on opposite hemisphere from A, use -B instead - - int bflip; - if ( ( bflip = (cos_omega < GLH_ZERO)) ) - cos_omega = -cos_omega; - - // complementary interpolation parameter - real beta = GLH_ONE - alpha; - - if(cos_omega <= GLH_ONE - GLH_EPSILON) - return p; - - real omega = real(acos(cos_omega)); - real one_over_sin_omega = GLH_ONE / real(sin(omega)); - - beta = real(sin(omega*beta) * one_over_sin_omega); - alpha = real(sin(omega*alpha) * one_over_sin_omega); - - if (bflip) - alpha = -alpha; - - r.x = beta * p.q[0]+ alpha * q.q[0]; - r.y = beta * p.q[1]+ alpha * q.q[1]; - r.z = beta * p.q[2]+ alpha * q.q[2]; - r.w = beta * p.q[3]+ alpha * q.q[3]; - return r; - } - - static quaternion identity() - { - static quaternion ident( vec3( 0.0, 0.0, 0.0 ), GLH_ONE ); - return ident; - } - - real & operator []( int i ) - { - assert(i < 4); - return q[i]; - } - - const real & operator []( int i ) const - { - assert(i < 4); - return q[i]; - } - - protected: - - void counter_normalize() - { - if (counter > GLH_QUATERNION_NORMALIZATION_THRESHOLD) - normalize(); - } - - union - { - struct - { - real q[4]; - }; - struct - { - real x; - real y; - real z; - real w; - }; - }; - - // renormalization counter - unsigned char counter; - }; - - inline - bool operator == ( const quaternion & q1, const quaternion & q2 ) - { - return (equivalent(q1.x, q2.x) && - equivalent(q1.y, q2.y) && - equivalent(q1.z, q2.z) && - equivalent(q1.w, q2.w) ); - } - - inline - bool operator != ( const quaternion & q1, const quaternion & q2 ) - { - return ! ( q1 == q2 ); - } - - inline - quaternion operator * ( const quaternion & q1, const quaternion & q2 ) - { - quaternion r(q1); - r *= q2; - return r; - } - - - - - - - - - - - class plane - { - public: - - plane() - { - planedistance = 0.0; - planenormal.set_value( 0.0, 0.0, 1.0 ); - } - - - plane( const vec3 &p0, const vec3 &p1, const vec3 &p2 ) - { - vec3 v0 = p1 - p0; - vec3 v1 = p2 - p0; - planenormal = v0.cross(v1); - planenormal.normalize(); - planedistance = p0.dot(planenormal); - } - - plane( const vec3 &normal, real distance ) - { - planedistance = distance; - planenormal = normal; - planenormal.normalize(); - } - - plane( const vec3 &normal, const vec3 &point ) - { - planenormal = normal; - planenormal.normalize(); - planedistance = point.dot(planenormal); - } - - void offset( real d ) - { - planedistance += d; - } - - bool intersect( const line &l, vec3 &intersection ) const - { - vec3 pos, dir; - vec3 pn = planenormal; - real pd = planedistance; - - pos = l.get_position(); - dir = l.get_direction(); - - if(dir.dot(pn) == 0.0) return 0; - pos -= pn*pd; - // now we're talking about a plane passing through the origin - if(pos.dot(pn) < 0.0) pn.negate(); - if(dir.dot(pn) > 0.0) dir.negate(); - vec3 ppos = pn * pos.dot(pn); - pos = (ppos.length()/dir.dot(-pn))*dir; - intersection = l.get_position(); - intersection += pos; - return 1; - } - void transform( const matrix4 &matrix ) - { - matrix4 invtr = matrix.inverse(); - invtr = invtr.transpose(); - - vec3 pntOnplane = planenormal * planedistance; - vec3 newPntOnplane; - vec3 newnormal; - - invtr.mult_dir_matrix(planenormal, newnormal); - matrix.mult_vec_matrix(pntOnplane, newPntOnplane); - - newnormal.normalize(); - planenormal = newnormal; - planedistance = newPntOnplane.dot(planenormal); - } - - bool is_in_half_space( const vec3 &point ) const - { - - if(( point.dot(planenormal) - planedistance) < 0.0) - return 0; - return 1; - } - - - real distance( const vec3 & point ) const - { - return planenormal.dot(point - planenormal*planedistance); - } - - const vec3 &get_normal() const - { - return planenormal; - } - - - real get_distance_from_origin() const - { - return planedistance; - } - - - friend bool operator == ( const plane & p1, const plane & p2 ); - - - friend bool operator != ( const plane & p1, const plane & p2 ); - - //protected: - vec3 planenormal; - real planedistance; - }; - - inline - bool operator == (const plane & p1, const plane & p2 ) - { - return ( p1.planedistance == p2.planedistance && p1.planenormal == p2.planenormal); - } - - inline - bool operator != ( const plane & p1, const plane & p2 ) - { return ! (p1 == p2); } - - - - } // "ns_##GLH_REAL" - - // make common typedefs... -#ifdef GLH_REAL_IS_FLOAT - typedef GLH_REAL_NAMESPACE::vec2 vec2f; - typedef GLH_REAL_NAMESPACE::vec3 vec3f; - typedef GLH_REAL_NAMESPACE::vec4 vec4f; - typedef GLH_REAL_NAMESPACE::quaternion quaternionf; - typedef GLH_REAL_NAMESPACE::quaternion rotationf; - typedef GLH_REAL_NAMESPACE::line linef; - typedef GLH_REAL_NAMESPACE::plane planef; - typedef GLH_REAL_NAMESPACE::matrix4 matrix4f; -#endif - - - - -} // namespace glh - - - -#endif - diff --git a/indra/llwindow/lldragdropwin32.cpp b/indra/llwindow/lldragdropwin32.cpp index 15acddd987..d00d9ab47e 100644 --- a/indra/llwindow/lldragdropwin32.cpp +++ b/indra/llwindow/lldragdropwin32.cpp @@ -242,11 +242,11 @@ class LLDragDropWin32Target: LLCoordWindow cursor_coord_window( pt_client.x, pt_client.y ); LLCoordGL gl_coord(cursor_coord_window.convert()); - llinfos << "### (Drop) URL is: " << mDropUrl << llendl; - llinfos << "### raw coords are: " << pt.x << " x " << pt.y << llendl; - llinfos << "### client coords are: " << pt_client.x << " x " << pt_client.y << llendl; - llinfos << "### GL coords are: " << gl_coord.mX << " x " << gl_coord.mY << llendl; - llinfos << llendl; + LL_INFOS() << "### (Drop) URL is: " << mDropUrl << LL_ENDL; + LL_INFOS() << "### raw coords are: " << pt.x << " x " << pt.y << LL_ENDL; + LL_INFOS() << "### client coords are: " << pt_client.x << " x " << pt_client.y << LL_ENDL; + LL_INFOS() << "### GL coords are: " << gl_coord.mX << " x " << gl_coord.mY << LL_ENDL; + LL_INFOS() << LL_ENDL; // no keyboard modifier option yet but we could one day MASK mask = gKeyboard->currentMask( TRUE ); diff --git a/indra/llwindow/lldxhardware.cpp b/indra/llwindow/lldxhardware.cpp index d8058baf53..f9ec9c21b1 100644 --- a/indra/llwindow/lldxhardware.cpp +++ b/indra/llwindow/lldxhardware.cpp @@ -2,31 +2,25 @@ * @file lldxhardware.cpp * @brief LLDXHardware implementation * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -40,9 +34,12 @@ #include #undef INITGUID +#include + #include #include "lldxhardware.h" + #include "llerror.h" #include "llstring.h" @@ -59,11 +56,160 @@ LLDXHardware gDXHardware; #define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p); (p)=NULL; } } #define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } } -std::string get_string(IDxDiagContainer *containerp, WCHAR *wszPropName) +typedef BOOL ( WINAPI* PfnCoSetProxyBlanket )( IUnknown* pProxy, DWORD dwAuthnSvc, DWORD dwAuthzSvc, + OLECHAR* pServerPrincName, DWORD dwAuthnLevel, DWORD dwImpLevel, + RPC_AUTH_IDENTITY_HANDLE pAuthInfo, DWORD dwCapabilities ); + +HRESULT GetVideoMemoryViaWMI( WCHAR* strInputDeviceID, DWORD* pdwAdapterRam ) +{ + HRESULT hr; + bool bGotMemory = false; + HRESULT hrCoInitialize = S_OK; + IWbemLocator* pIWbemLocator = nullptr; + IWbemServices* pIWbemServices = nullptr; + BSTR pNamespace = nullptr; + + *pdwAdapterRam = 0; + hrCoInitialize = CoInitialize( 0 ); + + hr = CoCreateInstance( CLSID_WbemLocator, + nullptr, + CLSCTX_INPROC_SERVER, + IID_IWbemLocator, + ( LPVOID* )&pIWbemLocator ); +#ifdef PRINTF_DEBUGGING + if( FAILED( hr ) ) wprintf( L"WMI: CoCreateInstance failed: 0x%0.8x\n", hr ); +#endif + + if( SUCCEEDED( hr ) && pIWbemLocator ) + { + // Using the locator, connect to WMI in the given namespace. + pNamespace = SysAllocString( L"\\\\.\\root\\cimv2" ); + + hr = pIWbemLocator->ConnectServer( pNamespace, nullptr, nullptr, 0L, + 0L, nullptr, nullptr, &pIWbemServices ); +#ifdef PRINTF_DEBUGGING + if( FAILED( hr ) ) wprintf( L"WMI: pIWbemLocator->ConnectServer failed: 0x%0.8x\n", hr ); +#endif + if( SUCCEEDED( hr ) && pIWbemServices != 0 ) + { + HINSTANCE hinstOle32 = nullptr; + + hinstOle32 = LoadLibraryW( L"ole32.dll" ); + if( hinstOle32 ) + { + PfnCoSetProxyBlanket pfnCoSetProxyBlanket = nullptr; + + pfnCoSetProxyBlanket = ( PfnCoSetProxyBlanket )GetProcAddress( hinstOle32, "CoSetProxyBlanket" ); + if( pfnCoSetProxyBlanket != 0 ) + { + // Switch security level to IMPERSONATE. + pfnCoSetProxyBlanket( pIWbemServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, nullptr, + RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, nullptr, 0 ); + } + + FreeLibrary( hinstOle32 ); + } + + IEnumWbemClassObject* pEnumVideoControllers = nullptr; + BSTR pClassName = nullptr; + + pClassName = SysAllocString( L"Win32_VideoController" ); + + hr = pIWbemServices->CreateInstanceEnum( pClassName, 0, + nullptr, &pEnumVideoControllers ); +#ifdef PRINTF_DEBUGGING + if( FAILED( hr ) ) wprintf( L"WMI: pIWbemServices->CreateInstanceEnum failed: 0x%0.8x\n", hr ); +#endif + + if( SUCCEEDED( hr ) && pEnumVideoControllers ) + { + IWbemClassObject* pVideoControllers[10] = {0}; + DWORD uReturned = 0; + BSTR pPropName = nullptr; + + // Get the first one in the list + pEnumVideoControllers->Reset(); + hr = pEnumVideoControllers->Next( 5000, // timeout in 5 seconds + 10, // return the first 10 + pVideoControllers, + &uReturned ); +#ifdef PRINTF_DEBUGGING + if( FAILED( hr ) ) wprintf( L"WMI: pEnumVideoControllers->Next failed: 0x%0.8x\n", hr ); + if( uReturned == 0 ) wprintf( L"WMI: pEnumVideoControllers uReturned == 0\n" ); +#endif + + VARIANT var; + if( SUCCEEDED( hr ) ) + { + bool bFound = false; + for( UINT iController = 0; iController < uReturned; iController++ ) + { + if ( !pVideoControllers[iController] ) + continue; + + pPropName = SysAllocString( L"PNPDeviceID" ); + hr = pVideoControllers[iController]->Get( pPropName, 0L, &var, nullptr, nullptr ); +#ifdef PRINTF_DEBUGGING + if( FAILED( hr ) ) + wprintf( L"WMI: pVideoControllers[iController]->Get PNPDeviceID failed: 0x%0.8x\n", hr ); +#endif + if( SUCCEEDED( hr ) ) + { + if( wcsstr( var.bstrVal, strInputDeviceID ) != 0 ) + bFound = true; + } + VariantClear( &var ); + if( pPropName ) SysFreeString( pPropName ); + + if( bFound ) + { + pPropName = SysAllocString( L"AdapterRAM" ); + hr = pVideoControllers[iController]->Get( pPropName, 0L, &var, nullptr, nullptr ); +#ifdef PRINTF_DEBUGGING + if( FAILED( hr ) ) + wprintf( L"WMI: pVideoControllers[iController]->Get AdapterRAM failed: 0x%0.8x\n", + hr ); +#endif + if( SUCCEEDED( hr ) ) + { + bGotMemory = true; + *pdwAdapterRam = var.ulVal; + } + VariantClear( &var ); + if( pPropName ) SysFreeString( pPropName ); + break; + } + SAFE_RELEASE( pVideoControllers[iController] ); + } + } + } + + if( pClassName ) + SysFreeString( pClassName ); + SAFE_RELEASE( pEnumVideoControllers ); + } + + if( pNamespace ) + SysFreeString( pNamespace ); + SAFE_RELEASE( pIWbemServices ); + } + + SAFE_RELEASE( pIWbemLocator ); + + if( SUCCEEDED( hrCoInitialize ) ) + CoUninitialize(); + + if( bGotMemory ) + return S_OK; + else + return E_FAIL; +} + +void get_wstring(IDxDiagContainer* containerp, const WCHAR* wszPropName, WCHAR* wszPropValue, int outputSize) { - HRESULT hr; + HRESULT hr; VARIANT var; - WCHAR wszPropValue[256]; VariantInit( &var ); hr = containerp->GetProp(wszPropName, &var ); @@ -73,22 +219,28 @@ std::string get_string(IDxDiagContainer *containerp, WCHAR *wszPropName) switch( var.vt ) { case VT_UI4: - swprintf( wszPropValue, L"%d", var.ulVal ); /* Flawfinder: ignore */ + swprintf(wszPropValue, outputSize, L"%d", var.ulVal); /* Flawfinder: ignore */ break; case VT_I4: - swprintf( wszPropValue, L"%d", var.lVal ); /* Flawfinder: ignore */ + swprintf(wszPropValue, outputSize, L"%d", var.lVal); /* Flawfinder: ignore */ break; case VT_BOOL: wcscpy( wszPropValue, (var.boolVal) ? L"true" : L"false" ); /* Flawfinder: ignore */ break; case VT_BSTR: - wcsncpy( wszPropValue, var.bstrVal, 255 ); /* Flawfinder: ignore */ - wszPropValue[255] = 0; + wcsncpy( wszPropValue, var.bstrVal, outputSize-1 ); /* Flawfinder: ignore */ + wszPropValue[outputSize-1] = 0; break; } } // Clear the variant (this is needed to free BSTR memory) VariantClear( &var ); +} + +std::string get_string(IDxDiagContainer *containerp, const WCHAR *wszPropName) +{ + WCHAR wszPropValue[256]; + get_wstring(containerp, wszPropName, wszPropValue, 256); return utf16str_to_utf8str(wszPropValue); } @@ -126,7 +278,7 @@ BOOL LLVersion::set(const std::string &version_string) } if (count < 4) { - //llwarns << "Potentially bogus version string!" << version_string << llendl; + //LL_WARNS() << "Potentially bogus version string!" << version_string << LL_ENDL; for (i = 0; i < 4; i++) { mFields[i] = 0; @@ -166,10 +318,10 @@ std::string LLDXDriverFile::dump() gWriteDebug(mDateString.c_str()); gWriteDebug("\n"); } - llinfos << mFilepath << llendl; - llinfos << mName << llendl; - llinfos << mVersionString << llendl; - llinfos << mDateString << llendl; + LL_INFOS() << mFilepath << LL_ENDL; + LL_INFOS() << mName << LL_ENDL; + LL_INFOS() << mVersionString << LL_ENDL; + LL_INFOS() << mDateString << LL_ENDL; return ""; } @@ -177,6 +329,7 @@ std::string LLDXDriverFile::dump() LLDXDevice::~LLDXDevice() { for_each(mDriverFiles.begin(), mDriverFiles.end(), DeletePairedPointer()); + mDriverFiles.clear(); } std::string LLDXDevice::dump() @@ -191,11 +344,11 @@ std::string LLDXDevice::dump() gWriteDebug(mPCIString.c_str()); gWriteDebug("\n"); } - llinfos << llendl; - llinfos << "DeviceName:" << mName << llendl; - llinfos << "PCIString:" << mPCIString << llendl; - llinfos << "Drivers" << llendl; - llinfos << "-------" << llendl; + LL_INFOS() << LL_ENDL; + LL_INFOS() << "DeviceName:" << mName << LL_ENDL; + LL_INFOS() << "PCIString:" << mPCIString << LL_ENDL; + LL_INFOS() << "Drivers" << LL_ENDL; + LL_INFOS() << "-------" << LL_ENDL; for (driver_file_map_t::iterator iter = mDriverFiles.begin(), end = mDriverFiles.end(); iter != end; iter++) @@ -236,6 +389,7 @@ LLDXHardware::LLDXHardware() void LLDXHardware::cleanup() { // for_each(mDevices.begin(), mDevices.end(), DeletePairedPointer()); + // mDevices.clear(); } /* @@ -289,13 +443,19 @@ LLDXDevice *LLDXHardware::findDevice(const std::string &vendor, const std::strin } */ -BOOL LLDXHardware::getInfo(BOOL vram_only) +BOOL LLDXHardware::getInfo(BOOL vram_only, S32Megabytes system_ram) { LLTimer hw_timer; BOOL ok = FALSE; HRESULT hr; - CoInitialize(NULL); + hr = CoInitialize(NULL); + if (FAILED(hr)) + { + LL_WARNS() << "COM initialization failure!" << LL_ENDL; + gWriteDebug("COM initialization failure!\n"); + return ok; + } IDxDiagProvider *dx_diag_providerp = NULL; IDxDiagContainer *dx_diag_rootp = NULL; @@ -319,65 +479,113 @@ BOOL LLDXHardware::getInfo(BOOL vram_only) gWriteDebug("No DXDiag provider found! DirectX 9 not installed!\n"); goto LCleanup; } - if (SUCCEEDED(hr)) // if FAILED(hr) then dx9 is not installed - { - // Fill out a DXDIAG_INIT_PARAMS struct and pass it to IDxDiagContainer::Initialize - // Passing in TRUE for bAllowWHQLChecks, allows dxdiag to check if drivers are - // digital signed as logo'd by WHQL which may connect via internet to update - // WHQL certificates. - DXDIAG_INIT_PARAMS dx_diag_init_params; - ZeroMemory(&dx_diag_init_params, sizeof(DXDIAG_INIT_PARAMS)); - - dx_diag_init_params.dwSize = sizeof(DXDIAG_INIT_PARAMS); - dx_diag_init_params.dwDxDiagHeaderVersion = DXDIAG_DX9_SDK_VERSION; - dx_diag_init_params.bAllowWHQLChecks = TRUE; - dx_diag_init_params.pReserved = NULL; + if (SUCCEEDED(hr)) // if FAILED(hr) then dx9 is not installed + { + // Fill out a DXDIAG_INIT_PARAMS struct and pass it to IDxDiagContainer::Initialize + // Passing in TRUE for bAllowWHQLChecks, allows dxdiag to check if drivers are + // digital signed as logo'd by WHQL which may connect via internet to update + // WHQL certificates. + DXDIAG_INIT_PARAMS dx_diag_init_params; + ZeroMemory(&dx_diag_init_params, sizeof(DXDIAG_INIT_PARAMS)); + + dx_diag_init_params.dwSize = sizeof(DXDIAG_INIT_PARAMS); + dx_diag_init_params.dwDxDiagHeaderVersion = DXDIAG_DX9_SDK_VERSION; + dx_diag_init_params.bAllowWHQLChecks = TRUE; + dx_diag_init_params.pReserved = NULL; LL_DEBUGS("AppInit") << "dx_diag_providerp->Initialize" << LL_ENDL; - hr = dx_diag_providerp->Initialize(&dx_diag_init_params); - if(FAILED(hr)) + hr = dx_diag_providerp->Initialize(&dx_diag_init_params); + if (FAILED(hr)) { - goto LCleanup; + goto LCleanup; } LL_DEBUGS("AppInit") << "dx_diag_providerp->GetRootContainer" << LL_ENDL; - hr = dx_diag_providerp->GetRootContainer( &dx_diag_rootp ); - if(FAILED(hr) || !dx_diag_rootp) + hr = dx_diag_providerp->GetRootContainer(&dx_diag_rootp); + if (FAILED(hr) || !dx_diag_rootp) { - goto LCleanup; + goto LCleanup; } - HRESULT hr; - // Get display driver information LL_DEBUGS("AppInit") << "dx_diag_rootp->GetChildContainer" << LL_ENDL; hr = dx_diag_rootp->GetChildContainer(L"DxDiag_DisplayDevices", &devices_containerp); - if(FAILED(hr) || !devices_containerp) + if (FAILED(hr) || !devices_containerp) { - goto LCleanup; + goto LCleanup; } - // Get device 0 + DWORD device_count; + devices_containerp->GetNumberOfChildContainers(&device_count); + + // Get devices LL_DEBUGS("AppInit") << "devices_containerp->GetChildContainer" << LL_ENDL; - hr = devices_containerp->GetChildContainer(L"0", &device_containerp); - if(FAILED(hr) || !device_containerp) + + S32 vram_max = -1; + std::string gpu_string_max; + for (DWORD i = 0; i < device_count; ++i) { - goto LCleanup; + std::wstring str = L""; + str += std::to_wstring(i); + hr = devices_containerp->GetChildContainer(str.data(), &device_containerp); + if (FAILED(hr) || !device_containerp) + { + continue; + } + + DWORD vram = 0; + S32 detected_ram; + std::string ram_str; + + WCHAR deviceID[512]; + + get_wstring(device_containerp, L"szDeviceID", deviceID, 512); + + if (SUCCEEDED(GetVideoMemoryViaWMI(deviceID, &vram))) + { + detected_ram = vram / (1024 * 1024); + LL_INFOS("AppInit") << "VRAM for device[" << i << "]: " << detected_ram << " WMI" << LL_ENDL; + } + else + { + // Get the English VRAM string + ram_str = get_string(device_containerp, L"szDisplayMemoryEnglish"); + + // We don't need the device any more + SAFE_RELEASE(device_containerp); + + // Dump the string as an int into the structure + char* stopstring; + detected_ram = strtol(ram_str.c_str(), &stopstring, 10); + detected_ram = llmax(0, detected_ram - ((S32)(system_ram / (2 * device_count)) + 1)); // Ignore shared memory pool. + + LL_INFOS("AppInit") << "VRAM for device[" << i << "]: " << detected_ram << " DX9 string: " << ram_str << LL_ENDL; + } + + if (detected_ram > vram_max) + { + gpu_string_max = ram_str; + vram_max = detected_ram; + } } - - // Get the English VRAM string + + if (vram_max <= 0) { - std::string ram_str = get_string(device_containerp, L"szDisplayMemoryEnglish"); + gpu_string_max = ""; + LL_INFOS("AppInit") << "No dedicated VRAM. Using system memory instead." << LL_ENDL; + vram_max = (S32)system_ram / 2; // Integrated graphics perhaps? Use half system ram. + } - // We don't need the device any more - SAFE_RELEASE(device_containerp); + LL_INFOS("AppInit") << "VRAM Detected: " << vram_max << " DX9 string: " << gpu_string_max << LL_ENDL; - // Dump the string as an int into the structure - char *stopstring; - mVRAM = strtol(ram_str.c_str(), &stopstring, 10); - LL_INFOS("AppInit") << "VRAM Detected: " << mVRAM << " DX9 string: " << ram_str << LL_ENDL; + if (vram_max == -1) + { + goto LCleanup; } + + mVRAM = vram_max; + if (vram_only) { ok = TRUE; @@ -385,15 +593,17 @@ BOOL LLDXHardware::getInfo(BOOL vram_only) } + + /* for now, we ONLY do vram_only the rest of this is commented out, to ensure no-one is tempted to use it - + // Now let's get device and driver information // Get the IDxDiagContainer object called "DxDiag_SystemDevices". // This call may take some time while dxdiag gathers the info. DWORD num_devices = 0; - WCHAR wszContainer[256]; + WCHAR wszContainer[256]; LL_DEBUGS("AppInit") << "dx_diag_rootp->GetChildContainer DxDiag_SystemDevices" << LL_ENDL; hr = dx_diag_rootp->GetChildContainer(L"DxDiag_SystemDevices", &system_device_containerp); if (FAILED(hr)) @@ -516,7 +726,7 @@ BOOL LLDXHardware::getInfo(BOOL vram_only) SAFE_RELEASE(device_containerp); } */ - } + } // dumpDevices(); ok = TRUE; @@ -545,7 +755,13 @@ LLSD LLDXHardware::getDisplayInfo() LLTimer hw_timer; HRESULT hr; LLSD ret; - CoInitialize(NULL); + hr = CoInitialize(NULL); + if (FAILED(hr)) + { + LL_WARNS() << "COM initialization failure!" << LL_ENDL; + gWriteDebug("COM initialization failure!\n"); + return ret; + } IDxDiagProvider *dx_diag_providerp = NULL; IDxDiagContainer *dx_diag_rootp = NULL; @@ -555,7 +771,7 @@ LLSD LLDXHardware::getDisplayInfo() IDxDiagContainer *driver_containerp = NULL; // CoCreate a IDxDiagProvider* - llinfos << "CoCreateInstance IID_IDxDiagProvider" << llendl; + LL_INFOS() << "CoCreateInstance IID_IDxDiagProvider" << LL_ENDL; hr = CoCreateInstance(CLSID_DxDiagProvider, NULL, CLSCTX_INPROC_SERVER, @@ -564,7 +780,7 @@ LLSD LLDXHardware::getDisplayInfo() if (FAILED(hr)) { - llwarns << "No DXDiag provider found! DirectX 9 not installed!" << llendl; + LL_WARNS() << "No DXDiag provider found! DirectX 9 not installed!" << LL_ENDL; gWriteDebug("No DXDiag provider found! DirectX 9 not installed!\n"); goto LCleanup; } @@ -582,24 +798,22 @@ LLSD LLDXHardware::getDisplayInfo() dx_diag_init_params.bAllowWHQLChecks = TRUE; dx_diag_init_params.pReserved = NULL; - llinfos << "dx_diag_providerp->Initialize" << llendl; + LL_INFOS() << "dx_diag_providerp->Initialize" << LL_ENDL; hr = dx_diag_providerp->Initialize(&dx_diag_init_params); if(FAILED(hr)) { goto LCleanup; } - llinfos << "dx_diag_providerp->GetRootContainer" << llendl; + LL_INFOS() << "dx_diag_providerp->GetRootContainer" << LL_ENDL; hr = dx_diag_providerp->GetRootContainer( &dx_diag_rootp ); if(FAILED(hr) || !dx_diag_rootp) { goto LCleanup; } - HRESULT hr; - // Get display driver information - llinfos << "dx_diag_rootp->GetChildContainer" << llendl; + LL_INFOS() << "dx_diag_rootp->GetChildContainer" << LL_ENDL; hr = dx_diag_rootp->GetChildContainer(L"DxDiag_DisplayDevices", &devices_containerp); if(FAILED(hr) || !devices_containerp) { @@ -607,7 +821,7 @@ LLSD LLDXHardware::getDisplayInfo() } // Get device 0 - llinfos << "devices_containerp->GetChildContainer" << llendl; + LL_INFOS() << "devices_containerp->GetChildContainer" << LL_ENDL; hr = devices_containerp->GetChildContainer(L"0", &device_containerp); if(FAILED(hr) || !device_containerp) { diff --git a/indra/llwindow/lldxhardware.h b/indra/llwindow/lldxhardware.h index 0ce218b080..4e92d7a2f4 100644 --- a/indra/llwindow/lldxhardware.h +++ b/indra/llwindow/lldxhardware.h @@ -92,7 +92,7 @@ class LLDXHardware // Returns TRUE on success. // vram_only TRUE does a "light" probe. - BOOL getInfo(BOOL vram_only); + BOOL getInfo(BOOL vram_only, S32Megabytes sytem_ram); S32 getVRAM() const { return mVRAM; } diff --git a/indra/llwindow/llkeyboard.cpp b/indra/llwindow/llkeyboard.cpp index 09502ebac6..3b0360a1a3 100644 --- a/indra/llwindow/llkeyboard.cpp +++ b/indra/llwindow/llkeyboard.cpp @@ -57,6 +57,7 @@ LLKeyboard::LLKeyboard() : mCallbacks(NULL), mNumpadDistinct(ND_NUMLOCK_OFF) mKeyUp[i] = FALSE; mKeyDown[i] = FALSE; mKeyRepeated[i] = FALSE; + mControllerKeys[i] = FALSE; } mInsertMode = LL_KIM_INSERT; @@ -185,7 +186,7 @@ BOOL LLKeyboard::translateKey(const U16 os_key, KEY *out_key) iter = mTranslateKeyMap.find(os_key); if (iter == mTranslateKeyMap.end()) { - //llwarns << "Unknown virtual key " << os_key << llendl; + //LL_WARNS() << "Unknown virtual key " << os_key << LL_ENDL; *out_key = 0; return FALSE; } @@ -256,7 +257,7 @@ BOOL LLKeyboard::handleTranslatedKeyUp(KEY translated_key, U32 translated_mask) handled = mCallbacks->handleTranslatedKeyUp(translated_key, translated_mask); } - lldebugst(LLERR_USER_INPUT) << "keyup -" << translated_key << "-" << llendl; + LL_DEBUGS("LLERR_USER_INPUT") << "keyup -" << translated_key << "-" << LL_ENDL; return handled; } @@ -319,7 +320,7 @@ BOOL LLKeyboard::keyFromString(const std::string& str, KEY *key) *key = res; return TRUE; } - llwarns << "keyFromString failed: " << str << llendl; + LL_WARNS() << "keyFromString failed: " << str << LL_ENDL; return FALSE; } diff --git a/indra/llwindow/llkeyboard.h b/indra/llwindow/llkeyboard.h index f8b155bf14..a52e7b5220 100644 --- a/indra/llwindow/llkeyboard.h +++ b/indra/llwindow/llkeyboard.h @@ -28,8 +28,12 @@ #define LL_LLKEYBOARD_H #include +#ifndef BOOST_FUNCTION_HPP_INCLUDED +#include +#define BOOST_FUNCTION_HPP_INCLUDED +#endif -#include "string_table.h" +#include "llstringtable.h" #include "lltimer.h" #include "indra_constants.h" @@ -40,7 +44,7 @@ enum EKeystate KEYSTATE_UP }; -typedef void (*LLKeyFunc)(EKeystate keystate); +typedef boost::function LLKeyFunc; enum EKeyboardInsertMode { @@ -113,6 +117,12 @@ class LLKeyboard F32 getKeyElapsedTime( KEY key ); // Returns time in seconds since key was pressed. S32 getKeyElapsedFrameCount( KEY key ); // Returns time in frames since key was pressed. + void setControllerKey(KEY key, bool level) + { + mControllerKeys[key] = mKeyLevel[key] = level; + (level ? mKeyDown[key] : mKeyUp[key]) = true; + } + protected: void addKeyName(KEY key, const std::string& name); @@ -127,6 +137,7 @@ class LLKeyboard BOOL mKeyRepeated[KEY_COUNT]; // Key was repeated BOOL mKeyUp[KEY_COUNT]; // Up edge BOOL mKeyDown[KEY_COUNT]; // Down edge + BOOL mControllerKeys[KEY_COUNT]; // Keys held in controller KEY mCurTranslatedKey; KEY mCurScanKey; // Used during the scanKeyboard() diff --git a/indra/llwindow/llkeyboardwin32.cpp b/indra/llwindow/llkeyboardwin32.cpp index df78816bd6..47992c0e71 100644 --- a/indra/llwindow/llkeyboardwin32.cpp +++ b/indra/llwindow/llkeyboardwin32.cpp @@ -28,9 +28,7 @@ #include "linden_common.h" -#define WIN32_LEAN_AND_MEAN -#include -#include +#include "llwin32headerslean.h" #include "llkeyboardwin32.h" @@ -261,15 +259,15 @@ void LLKeyboardWin32::scanKeyboard() // *TODO: I KNOW there must be a better way of // interrogating the key state than this, using async key // state can cause ALL kinds of bugs - Doug - if (key < KEY_BUTTON0) + if ((key < KEY_BUTTON0) && ((key < '0') || (key > '9'))) { // ...under windows make sure the key actually still is down. // ...translate back to windows key U16 virtual_key = inverseTranslateExtendedKey(key); // keydown in highest bit - if (!pending_key_events && !(GetAsyncKeyState(virtual_key) & 0x8000)) + if (!mControllerKeys[key] && !pending_key_events && !(GetAsyncKeyState(virtual_key) & 0x8000)) { - //llinfos << "Key up event missed, resetting" << llendl; + //LL_INFOS() << "Key up event missed, resetting" << LL_ENDL; mKeyLevel[key] = FALSE; } } diff --git a/indra/llwindow/llkeyboardwin32.h b/indra/llwindow/llkeyboardwin32.h index a2138759f9..bffccc7f5f 100644 --- a/indra/llwindow/llkeyboardwin32.h +++ b/indra/llwindow/llkeyboardwin32.h @@ -2,31 +2,25 @@ * @file llkeyboardwin32.h * @brief Handler for assignable key bindings * - * $LicenseInfo:firstyear=2004&license=viewergpl$ - * - * Copyright (c) 2004-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * Copyright (C) 2010, Linden Research, Inc. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llwindow/llmousehandler.cpp b/indra/llwindow/llmousehandler.cpp index 8695e92f77..bea66e763c 100644 --- a/indra/llwindow/llmousehandler.cpp +++ b/indra/llwindow/llmousehandler.cpp @@ -39,7 +39,7 @@ BOOL LLMouseHandler::handleAnyMouseClick(S32 x, S32 y, MASK mask, EClickType cli case CLICK_MIDDLE: handled = handleMiddleMouseDown(x, y, mask); break; case CLICK_DOUBLELEFT: handled = handleDoubleClick(x, y, mask); break; default: - llwarns << "Unhandled enum." << llendl; + LL_WARNS() << "Unhandled enum." << LL_ENDL; } } else @@ -51,7 +51,7 @@ BOOL LLMouseHandler::handleAnyMouseClick(S32 x, S32 y, MASK mask, EClickType cli case CLICK_MIDDLE: handled = handleMiddleMouseUp(x, y, mask); break; case CLICK_DOUBLELEFT: handled = handleDoubleClick(x, y, mask); break; default: - llwarns << "Unhandled enum." << llendl; + LL_WARNS() << "Unhandled enum." << LL_ENDL; } } return handled; diff --git a/indra/llwindow/llwindow.cpp b/indra/llwindow/llwindow.cpp index 8df242331b..756660716f 100644 --- a/indra/llwindow/llwindow.cpp +++ b/indra/llwindow/llwindow.cpp @@ -39,7 +39,6 @@ #include "llerror.h" #include "llkeyboard.h" -#include "linked_lists.h" #include "llwindowcallbacks.h" @@ -50,15 +49,18 @@ LLSplashScreen *gSplashScreenp = NULL; BOOL gDebugClicks = FALSE; BOOL gDebugWindowProc = FALSE; -const S32 gURLProtocolWhitelistCount = 4; -const std::string gURLProtocolWhitelist[] = { "secondlife:", "http:", "https:", "data:"/*, "file:"*/ }; - +bool isWhitelistedProtocol(const std::string& escaped_url) { // CP: added a handler list - this is what's used to open the protocol and is based on registry entry // only meaningful difference currently is that file: protocols are opened using http: // since no protocol handler exists in registry for file: // Important - these lists should match - protocol to handler // Maestro: This list isn't referenced anywhere that I could find //const std::string gURLProtocolWhitelistHandler[] = { "http", "http", "https" }; + for (const auto& protocol : { "secondlife:", "http:", "https:", "data:", "mailto:" }) + if (escaped_url.find(protocol) != std::string::npos) + return true; + return false; +} S32 OSMessageBox(const std::string& text, const std::string& caption, U32 type) @@ -73,8 +75,8 @@ S32 OSMessageBox(const std::string& text, const std::string& caption, U32 type) S32 result = 0; #if LL_MESA_HEADLESS // !!! *FIX: (???) - llwarns << "OSMessageBox: " << text << llendl; - return OSBTN_OK; + LL_WARNS() << "OSMessageBox: " << text << LL_ENDL; + result = OSBTN_OK; #elif LL_WINDOWS result = OSMessageBoxWin32(text, caption, type); #elif LL_DARWIN @@ -250,6 +252,48 @@ BOOL LLWindow::copyTextToPrimary(const LLWString &src) return FALSE; // fail } +#if LL_WINDOWS +#include +#endif + +int LLWindow::ShellEx(const std::string& command) +{ +#if LL_WINDOWS + llutf16string url_utf16 = L'"' + utf8str_to_utf16str(command) + L'"'; + SHELLEXECUTEINFO sei = { sizeof( sei ) }; + sei.fMask = SEE_MASK_NOASYNC; + sei.nShow = SW_SHOWNORMAL; + sei.lpVerb = L"open"; + sei.lpFile = url_utf16.c_str(); + const auto& code = ShellExecuteEx(&sei) ? 0 : GetLastError(); +#elif LL_DARWIN + CFURLRef urlRef; + CFStringRef stringRef = CFStringCreateWithCString(NULL, command.c_str(), kCFStringEncodingUTF8); + if (stringRef) + { + // This will succeed if the string is a full URL, including the http:// + // Note that URLs specified this way need to be properly percent-escaped. + urlRef = CFURLCreateWithString(NULL, stringRef, NULL); + + // Don't use CRURLCreateWithFileSystemPath -- only want valid URLs + CFRelease(stringRef); + } + + OSStatus code; + if (urlRef) + { + code = LSOpenCFURLRef(urlRef, NULL); + CFRelease(urlRef); + } + else code = -1; +#else // LL_LINUX or other modern unix, pray it has xdg-open + const auto& code = std::system(("xdg-open \"" + command + '"').c_str()); +#endif + + if (code) LL_WARNS() << "Failed to open \"" << command << "\" return code: " << code << LL_ENDL; + return code; +} + // static std::vector LLWindow::getDynamicFallbackFontList() { @@ -388,7 +432,7 @@ LLWindow* LLWindowManager::createWindow( const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height, U32 flags, BOOL fullscreen, BOOL clearBg, - BOOL disable_vsync, + const S32 vsync_mode, BOOL use_gl, BOOL ignore_pixel_depth, U32 fsaa_samples) @@ -400,32 +444,32 @@ LLWindow* LLWindowManager::createWindow( #if LL_MESA_HEADLESS new_window = new LLWindowMesaHeadless(callbacks, title, name, x, y, width, height, flags, - fullscreen, clearBg, disable_vsync, ignore_pixel_depth); + fullscreen, clearBg, vsync_mode, ignore_pixel_depth); #elif LL_SDL new_window = new LLWindowSDL(callbacks, title, x, y, width, height, flags, - fullscreen, clearBg, disable_vsync, ignore_pixel_depth, fsaa_samples); + fullscreen, clearBg, vsync_mode, ignore_pixel_depth, fsaa_samples); #elif LL_WINDOWS new_window = new LLWindowWin32(callbacks, title, name, x, y, width, height, flags, - fullscreen, clearBg, disable_vsync, ignore_pixel_depth, fsaa_samples); + fullscreen, clearBg, vsync_mode, ignore_pixel_depth, fsaa_samples); #elif LL_DARWIN new_window = new LLWindowMacOSX(callbacks, title, name, x, y, width, height, flags, - fullscreen, clearBg, disable_vsync, ignore_pixel_depth, fsaa_samples); + fullscreen, clearBg, vsync_mode, ignore_pixel_depth, fsaa_samples); #endif } else { new_window = new LLWindowHeadless(callbacks, title, name, x, y, width, height, flags, - fullscreen, clearBg, disable_vsync, ignore_pixel_depth); + fullscreen, clearBg, vsync_mode, ignore_pixel_depth); } if (FALSE == new_window->isValid()) { delete new_window; - llwarns << "LLWindowManager::create() : Error creating window." << llendl; + LL_WARNS() << "LLWindowManager::create() : Error creating window." << LL_ENDL; return NULL; } sWindowList.insert(new_window); @@ -436,8 +480,8 @@ BOOL LLWindowManager::destroyWindow(LLWindow* window) { if (sWindowList.find(window) == sWindowList.end()) { - llerrs << "LLWindowManager::destroyWindow() : Window pointer not valid, this window doesn't exist!" - << llendl; + LL_ERRS() << "LLWindowManager::destroyWindow() : Window pointer not valid, this window doesn't exist!" + << LL_ENDL; return FALSE; } diff --git a/indra/llwindow/llwindow.h b/indra/llwindow/llwindow.h index 575c578160..2305b69e12 100644 --- a/indra/llwindow/llwindow.h +++ b/indra/llwindow/llwindow.h @@ -32,6 +32,7 @@ #include "llstring.h" #include "llcursortypes.h" #include "llsd.h" +#include "llinstancetracker.h" class LLSplashScreen; @@ -65,7 +66,8 @@ class LLWindow : public LLInstanceTracker // currently unused }; public: - virtual void show() = 0; + virtual void postInitialized() {} + virtual void show(bool focus = true) = 0; virtual void hide() = 0; virtual void close() = 0; virtual BOOL getVisible() = 0; @@ -82,7 +84,7 @@ class LLWindow : public LLInstanceTracker BOOL setSize(LLCoordScreen size); BOOL setSize(LLCoordWindow size); virtual void setMinSize(U32 min_width, U32 min_height, bool enforce_immediately = true); - virtual BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp = NULL) = 0; + virtual BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, const S32 vsync_mode, std::function stopFn, std::function restoreFn, const LLCoordScreen * const posp = NULL) = 0; virtual BOOL setCursorPosition(LLCoordWindow position) = 0; virtual BOOL getCursorPosition(LLCoordWindow *position) = 0; virtual void showCursor() = 0; @@ -121,6 +123,8 @@ class LLWindow : public LLInstanceTracker virtual BOOL setGamma(const F32 gamma) = 0; // Set the gamma virtual void setFSAASamples(const U32 fsaa_samples) = 0; //set number of FSAA samples virtual U32 getFSAASamples() = 0; + virtual void setVsyncMode(const S32 vsync_mode) = 0; + virtual S32 getVsyncMode() = 0; virtual BOOL restoreGamma() = 0; // Restore original gamma table (before updating gamma) virtual ESwapMethod getSwapMethod() { return mSwapMethod; } virtual void processMiscNativeEvents(); @@ -165,7 +169,7 @@ class LLWindow : public LLInstanceTracker virtual void updateLanguageTextInputArea() {} virtual void interruptLanguageTextInput() {} virtual void spawnWebBrowser(const std::string& escaped_url, bool async) {}; - virtual void ShellEx(const std::string& command) {}; + static int ShellEx(const std::string& command); static std::vector getDynamicFallbackFontList(); @@ -274,7 +278,7 @@ class LLWindowManager U32 flags = 0, BOOL fullscreen = FALSE, BOOL clearBg = FALSE, - BOOL disable_vsync = TRUE, + const S32 vsync_mode = 0, BOOL use_gl = TRUE, BOOL ignore_pixel_depth = FALSE, U32 fsaa_samples = 0); @@ -287,11 +291,7 @@ class LLWindowManager // extern BOOL gDebugWindowProc; -// Protocols, like "http" and "https" we support in URLs -extern const S32 gURLProtocolWhitelistCount; -extern const std::string gURLProtocolWhitelist[]; -//extern const std::string gURLProtocolWhitelistHandler[]; - +bool isWhitelistedProtocol(const std::string& escaped_url); void simpleEscapeString ( std::string& stringIn ); #endif // _LL_window_h_ diff --git a/indra/llwindow/llwindowcallbacks.cpp b/indra/llwindow/llwindowcallbacks.cpp index 9712ae1d91..5b2e2f7952 100644 --- a/indra/llwindow/llwindowcallbacks.cpp +++ b/indra/llwindow/llwindowcallbacks.cpp @@ -185,6 +185,11 @@ void LLWindowCallbacks::handleResumeWatchdog(LLWindow *window) } +bool LLWindowCallbacks::handleDPIScaleChange(LLWindow *window, float xDPIScale, float yDPIScale, U32 width, U32 height) +{ + return false; +} + std::string LLWindowCallbacks::translateString(const char* tag) { return std::string(); diff --git a/indra/llwindow/llwindowcallbacks.h b/indra/llwindow/llwindowcallbacks.h index 7da5959700..aa349d29f3 100644 --- a/indra/llwindow/llwindowcallbacks.h +++ b/indra/llwindow/llwindowcallbacks.h @@ -79,7 +79,8 @@ class LLWindowCallbacks DND_LINK // Drop accepted would result in a "link" operation }; virtual DragNDropResult handleDragNDrop(LLWindow *window, LLCoordGL pos, MASK mask, DragNDropAction action, std::string data); - + virtual bool handleDPIScaleChange(LLWindow *window, float xDPIScale, float yDPIScale, U32 width = 0, U32 height = 0); + virtual void handlePingWatchdog(LLWindow *window, const char * msg); virtual void handlePauseWatchdog(LLWindow *window); virtual void handleResumeWatchdog(LLWindow *window); diff --git a/indra/llwindow/llwindowheadless.cpp b/indra/llwindow/llwindowheadless.cpp index dbdb40f5b9..d07521cf2e 100644 --- a/indra/llwindow/llwindowheadless.cpp +++ b/indra/llwindow/llwindowheadless.cpp @@ -35,7 +35,7 @@ // LLWindowHeadless::LLWindowHeadless(LLWindowCallbacks* callbacks, const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height, U32 flags, BOOL fullscreen, BOOL clear_background, - BOOL disable_vsync, BOOL ignore_pixel_depth) + const S32 vsync_mode, BOOL ignore_pixel_depth) : LLWindow(callbacks, fullscreen, flags) { // Initialize a headless keyboard. diff --git a/indra/llwindow/llwindowheadless.h b/indra/llwindow/llwindowheadless.h index 72f9684ca3..0364c5340d 100644 --- a/indra/llwindow/llwindowheadless.h +++ b/indra/llwindow/llwindowheadless.h @@ -32,7 +32,7 @@ class LLWindowHeadless : public LLWindow { public: - /*virtual*/ void show() {}; + /*virtual*/ void show(bool) {}; /*virtual*/ void hide() {}; /*virtual*/ void close() {}; /*virtual*/ BOOL getVisible() {return FALSE;}; @@ -48,7 +48,7 @@ class LLWindowHeadless : public LLWindow /*virtual*/ BOOL setPosition(LLCoordScreen position) {return FALSE;}; /*virtual*/ BOOL setSizeImpl(LLCoordScreen size) {return FALSE;}; /*virtual*/ BOOL setSizeImpl(LLCoordWindow size) {return FALSE;}; - /*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp = NULL) {return FALSE;}; + /*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, const S32 vsync_mode, std::function stopFn, std::function restoreFn, const LLCoordScreen * const posp = NULL) {return FALSE;}; /*virtual*/ BOOL setCursorPosition(LLCoordWindow position) {return FALSE;}; /*virtual*/ BOOL getCursorPosition(LLCoordWindow *position) {return FALSE;}; /*virtual*/ void showCursor() {}; @@ -69,6 +69,8 @@ class LLWindowHeadless : public LLWindow /*virtual*/ BOOL setGamma(const F32 gamma) {return FALSE; }; // Set the gamma /*virtual*/ void setFSAASamples(const U32 fsaa_samples) { } /*virtual*/ U32 getFSAASamples() { return 0; } + /*virtual*/ void setVsyncMode(const S32 vsync_mode) {} + /*virtual*/ S32 getVsyncMode() { return 0; } /*virtual*/ BOOL restoreGamma() {return FALSE; }; // Restore original gamma table (before updating gamma) //virtual ESwapMethod getSwapMethod() { return mSwapMethod; } /*virtual*/ void gatherInput() {}; @@ -96,7 +98,7 @@ class LLWindowHeadless : public LLWindow S32 x, S32 y, S32 width, S32 height, U32 flags, BOOL fullscreen, BOOL clear_background, - BOOL disable_vsync, BOOL ignore_pixel_depth); + const S32 vsync_mode, BOOL ignore_pixel_depth); virtual ~LLWindowHeadless(); private: diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp index 303a23959e..9be125958d 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -1,3 +1,5 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com /** * @file llwindowmacosx.cpp * @brief Platform-dependent implementation of llwindow @@ -30,7 +32,6 @@ #include "llkeyboardmacosx.h" #include "llwindowcallbacks.h" -#include "llwindowmacosx-objc.h" #include "llpreeditor.h" #include "llerror.h" @@ -39,27 +40,28 @@ #include "lldir.h" #include "indra_constants.h" -#include #include +#include +#include extern BOOL gDebugWindowProc; +extern BOOL gUseMultGL; // culled from winuser.h //const S32 WHEEL_DELTA = 120; /* Value for rolling one detent */ // On the Mac, the scroll wheel reports a delta of 1 for each detent. // There's also acceleration for faster scrolling, based on a slider in the system preferences. -const S32 WHEEL_DELTA = 1; /* Value for rolling one detent */ const S32 BITS_PER_PIXEL = 32; const S32 MAX_NUM_RESOLUTIONS = 32; - +namespace +{ + NSKeyEventRef mRawKeyEvent = NULL; +} // // LLWindowMacOSX // -BOOL LLWindowMacOSX::sUseMultGL = FALSE; -WindowRef LLWindowMacOSX::sMediaWindow = NULL; - // Cross-platform bits: BOOL check_for_card(const char* RENDERER, const char* bad_card) @@ -67,17 +69,17 @@ BOOL check_for_card(const char* RENDERER, const char* bad_card) if (!strnicmp(RENDERER, bad_card, strlen(bad_card))) { std::string buffer = llformat( - "Your video card appears to be a %s, which Second Life does not support.\n" + "Your video card appears to be a %s, which Singularity does not support.\n" "\n" - "Second Life requires a video card with 32 Mb of memory or more, as well as\n" + "Singularity requires a video card with 32 Mb of memory or more, as well as\n" "multitexture support. We explicitly support nVidia GeForce 2 or better, \n" - "and ATI Radeon 8500 or better.\n" + "and ATI Radeon 8500 or better... A LOT better. lol\n" "\n" "If you own a supported card and continue to receive this message, try \n" "updating to the latest video card drivers. Otherwise look in the\n" "secondlife.com support section or e-mail technical support\n" "\n" - "You can try to run Second Life, but it will probably crash or run\n" + "You can try to run Singularity, but it will probably crash or run\n" "very slowly. Try anyway?", bad_card); S32 button = OSMessageBox(buffer.c_str(), "Unsupported video card", OSMB_YESNO); @@ -98,105 +100,9 @@ BOOL check_for_card(const char* RENDERER, const char* bad_card) // We may want to base this on the setting of _DEBUG... #define CAPTURE_ALL_DISPLAYS 0 -static double getDictDouble (CFDictionaryRef refDict, CFStringRef key); +//static double getDictDouble (CFDictionaryRef refDict, CFStringRef key); static long getDictLong (CFDictionaryRef refDict, CFStringRef key); - - - -// CarbonEvents we're interested in. -static EventTypeSpec WindowHandlerEventList[] = -{ - // Window-related events - { kEventClassWindow, kEventWindowActivated }, - { kEventClassWindow, kEventWindowDeactivated }, - { kEventClassWindow, kEventWindowShown }, - { kEventClassWindow, kEventWindowHidden }, - { kEventClassWindow, kEventWindowCollapsed }, - { kEventClassWindow, kEventWindowExpanded }, - { kEventClassWindow, kEventWindowGetClickActivation }, - { kEventClassWindow, kEventWindowClose }, - { kEventClassWindow, kEventWindowBoundsChanging }, - { kEventClassWindow, kEventWindowBoundsChanged }, - { kEventClassWindow, kEventWindowGetIdealSize }, - - // Mouse events - { kEventClassMouse, kEventMouseDown }, - { kEventClassMouse, kEventMouseUp }, - { kEventClassMouse, kEventMouseDragged }, - { kEventClassMouse, kEventMouseWheelMoved }, - { kEventClassMouse, kEventMouseMoved }, - - // Keyboard events - // No longer handle raw key down events directly. - // When text input events come in, extract the raw key events from them and process at that point. - // This allows input methods to eat keystrokes the way they're supposed to. -// { kEventClassKeyboard, kEventRawKeyDown }, -// { kEventClassKeyboard, kEventRawKeyRepeat }, - { kEventClassKeyboard, kEventRawKeyUp }, - { kEventClassKeyboard, kEventRawKeyModifiersChanged }, - - // Text input events - { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent }, - { kEventClassTextInput, kEventTextInputUpdateActiveInputArea }, - { kEventClassTextInput, kEventTextInputOffsetToPos }, - { kEventClassTextInput, kEventTextInputPosToOffset }, - { kEventClassTextInput, kEventTextInputShowHideBottomWindow }, - { kEventClassTextInput, kEventTextInputGetSelectedText }, - { kEventClassTextInput, kEventTextInputFilterText }, - - // TSM Document Access events (advanced input method support) - { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetLength }, - { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetSelectedRange }, - { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetCharacters }, - { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetFont }, - { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetGlyphInfo }, - { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessLockDocument }, - { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessUnlockDocument } -}; - -static EventTypeSpec GlobalHandlerEventList[] = -{ - // Mouse events - { kEventClassMouse, kEventMouseDown }, - { kEventClassMouse, kEventMouseUp }, - { kEventClassMouse, kEventMouseDragged }, - { kEventClassMouse, kEventMouseWheelMoved }, - { kEventClassMouse, kEventMouseMoved }, - - // Keyboard events - // No longer handle raw key down events directly. - // When text input events come in, extract the raw key events from them and process at that point. - // This allows input methods to eat keystrokes the way they're supposed to. -// { kEventClassKeyboard, kEventRawKeyDown }, -// { kEventClassKeyboard, kEventRawKeyRepeat }, - { kEventClassKeyboard, kEventRawKeyUp }, - { kEventClassKeyboard, kEventRawKeyModifiersChanged }, - - // Text input events - { kEventClassTextInput, kEventTextInputUpdateActiveInputArea }, - { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent }, - { kEventClassTextInput, kEventTextInputOffsetToPos }, - { kEventClassTextInput, kEventTextInputPosToOffset }, - { kEventClassTextInput, kEventTextInputShowHideBottomWindow }, - { kEventClassTextInput, kEventTextInputGetSelectedText }, - { kEventClassTextInput, kEventTextInputFilterText }, - - // TSM Document Access events (advanced input method support) - { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetLength }, - { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetSelectedRange }, - { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetCharacters }, - { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetFont }, - { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetGlyphInfo }, - { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessLockDocument }, - { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessUnlockDocument } -}; - -static EventTypeSpec CommandHandlerEventList[] = -{ - { kEventClassCommand, kEventCommandProcess } -}; - // MBW -- HACK ALERT // On the Mac, to put up an OS dialog in full screen mode, we must first switch OUT of full screen mode. // The proper way to do this is to bracket the dialog with calls to beforeDialog() and afterDialog(), but these @@ -204,13 +110,11 @@ static EventTypeSpec CommandHandlerEventList[] = // This assumes that there will be only one object of this class at any time. Hopefully this is true. static LLWindowMacOSX *gWindowImplementation = NULL; - - LLWindowMacOSX::LLWindowMacOSX(LLWindowCallbacks* callbacks, const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height, U32 flags, BOOL fullscreen, BOOL clearBg, - BOOL disable_vsync, + S32 vsync_setting, BOOL ignore_pixel_depth, U32 fsaa_samples) : LLWindow(NULL, fullscreen, flags) @@ -233,8 +137,6 @@ LLWindowMacOSX::LLWindowMacOSX(LLWindowCallbacks* callbacks, mContext = NULL; mPixelFormat = NULL; mDisplay = CGMainDisplayID(); - mOldDisplayMode = NULL; - mTimer = NULL; mSimulatedRightClick = FALSE; mLastModifiers = 0; mHandsOffEvents = FALSE; @@ -246,69 +148,40 @@ LLWindowMacOSX::LLWindowMacOSX(LLWindowCallbacks* callbacks, mOverrideAspectRatio = 0.f; mMaximized = FALSE; mMinimized = FALSE; - mTSMDocument = NULL; // Just in case. mLanguageTextInputAllowed = FALSE; - mTSMScriptCode = 0; - mTSMLangCode = 0; mPreeditor = NULL; - mRawKeyEvent = NULL; mFSAASamples = fsaa_samples; mForceRebuild = FALSE; - // For reasons that aren't clear to me, LLTimers seem to be created in the "started" state. - // Since the started state of this one is used to track whether the NMRec has been installed, it wants to start out in the "stopped" state. - mBounceTimer.stop(); - // Get the original aspect ratio of the main device. mOriginalAspectRatio = (double)CGDisplayPixelsWide(mDisplay) / (double)CGDisplayPixelsHigh(mDisplay); // Stash the window title - strcpy((char*)mWindowTitle + 1, title.c_str()); /* Flawfinder: ignore */ - mWindowTitle[0] = title.length(); - - mEventHandlerUPP = NewEventHandlerUPP(staticEventHandler); - mMoveEventCampartorUPP = NewEventComparatorUPP(staticMoveEventComparator); - mGlobalHandlerRef = NULL; - mWindowHandlerRef = NULL; + mWindowTitle = title; + //mWindowTitle[0] = title.length(); mDragOverrideCursor = -1; - // We're not clipping yet - SetRect( &mOldMouseClip, 0, 0, 0, 0 ); - // Set up global event handlers (the fullscreen case needs this) - InstallStandardEventHandler(GetApplicationEventTarget()); + //InstallStandardEventHandler(GetApplicationEventTarget()); // Stash an object pointer for OSMessageBox() gWindowImplementation = this; - // Create the GL context and set it up for windowed or fullscreen, as appropriate. - if(createContext(x, y, width, height, 32, fullscreen, disable_vsync)) + if(createContext(x, y, width, height, 32, fullscreen, vsync_setting)) { if(mWindow != NULL) { - // MBW -- XXX -- I think we can now do this here? - // Constrain the window to the screen it's mostly on, resizing if necessary. - ConstrainWindowToScreen( - mWindow, - kWindowStructureRgn, - kWindowConstrainMayResize | - // kWindowConstrainStandardOptions | - 0, - NULL, - NULL); - - MacShowWindow(mWindow); - BringToFront(mWindow); + makeWindowOrderFront(mWindow); } if (!gGLManager.initGL()) { setupFailure( - "Second Life is unable to run because your video card drivers\n" + "Singularity is unable to run because your video card drivers\n" "are out of date or unsupported. Please make sure you have\n" "the latest video card drivers installed.\n" - "If you continue to receive this message, contact customer service.", + "If you continue to receive this message, contact support.", "Error", OSMB_OK); return; @@ -317,483 +190,452 @@ LLWindowMacOSX::LLWindowMacOSX(LLWindowCallbacks* callbacks, //start with arrow cursor initCursors(); setCursor( UI_CURSOR_ARROW ); + + allowLanguageTextInput(NULL, FALSE); } mCallbacks = callbacks; stop_glerror(); + + } -BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, BOOL disable_vsync) -{ - OSStatus err; - BOOL glNeedsInit = FALSE; - - if(mGlobalHandlerRef == NULL) - { - InstallApplicationEventHandler(mEventHandlerUPP, GetEventTypeCount (CommandHandlerEventList), CommandHandlerEventList, (void*)this, &mGlobalHandlerRef); - } - - mFullscreen = fullscreen; - - if (mFullscreen && (mOldDisplayMode == NULL)) - { - LL_INFOS("Window") << "createContext: setting up fullscreen " << width << "x" << height << LL_ENDL; - - // NOTE: The refresh rate will be REPORTED AS 0 for many DVI and notebook displays. Plan accordingly. - double refresh = getDictDouble (CGDisplayCurrentMode (mDisplay), kCGDisplayRefreshRate); +// These functions are used as wrappers for our internal event handling callbacks. +// It's a good idea to wrap these to avoid reworking more code than we need to within LLWindow. - // If the requested width or height is 0, find the best default for the monitor. - if((width == 0) || (height == 0)) - { - // Scan through the list of modes, looking for one which has: - // height between 700 and 800 - // aspect ratio closest to the user's original mode - S32 resolutionCount = 0; - LLWindowResolution *resolutionList = getSupportedResolutions(resolutionCount); +bool callKeyUp(NSKeyEventRef event, unsigned short key, unsigned int mask) +{ + mRawKeyEvent = event; + bool retVal = gKeyboard->handleKeyUp(key, mask); + mRawKeyEvent = NULL; + return retVal; +} - if(resolutionList != NULL) - { - F32 closestAspect = 0; - U32 closestHeight = 0; - U32 closestWidth = 0; - int i; +bool callKeyDown(NSKeyEventRef event, unsigned short key, unsigned int mask) +{ + mRawKeyEvent = event; + bool retVal = gKeyboard->handleKeyDown(key, mask); + mRawKeyEvent = NULL; + return retVal; +} - LL_DEBUGS("Window") << "createContext: searching for a display mode, original aspect is " << mOriginalAspectRatio << LL_ENDL; +void callResetKeys() +{ + gKeyboard->resetKeys(); +} - for(i=0; i < resolutionCount; i++) - { - F32 aspect = (F32)resolutionList[i].mWidth / (F32)resolutionList[i].mHeight; +bool callUnicodeCallback(wchar_t character, unsigned int mask) +{ + NativeKeyEventData eventData; + + memset(&eventData, 0, sizeof(NativeKeyEventData)); + + eventData.mKeyEvent = NativeKeyEventData::KEYCHAR; + eventData.mEventType = 0; + eventData.mEventModifiers = mask; + eventData.mEventKeyCode = 0; + eventData.mEventChars = character; + eventData.mEventUnmodChars = character; + eventData.mEventRepeat = false; + + mRawKeyEvent = &eventData; + + bool result = gWindowImplementation->getCallbacks()->handleUnicodeChar(character, mask); + mRawKeyEvent = NULL; + return result; +} - LL_DEBUGS("Window") << "createContext: width " << resolutionList[i].mWidth << " height " << resolutionList[i].mHeight << " aspect " << aspect << LL_ENDL; +void callFocus() +{ + if (gWindowImplementation) + { + gWindowImplementation->getCallbacks()->handleFocus(gWindowImplementation); + } +} - if( (resolutionList[i].mHeight >= 700) && (resolutionList[i].mHeight <= 800) && - (fabs(aspect - mOriginalAspectRatio) < fabs(closestAspect - mOriginalAspectRatio))) - { - LL_DEBUGS("Window") << " (new closest mode) " << LL_ENDL; +void callFocusLost() +{ + if (gWindowImplementation) + { + gWindowImplementation->getCallbacks()->handleFocusLost(gWindowImplementation); + } +} - // This is the closest mode we've seen yet. - closestWidth = resolutionList[i].mWidth; - closestHeight = resolutionList[i].mHeight; - closestAspect = aspect; - } - } +void callRightMouseDown(float *pos, MASK mask) +{ + if (gWindowImplementation->allowsLanguageInput()) + { + gWindowImplementation->interruptLanguageTextInput(); + } + + LLCoordGL outCoords; + outCoords.mX = ll_round(pos[0]); + outCoords.mY = ll_round(pos[1]); + gWindowImplementation->getCallbacks()->handleRightMouseDown(gWindowImplementation, outCoords, gKeyboard->currentMask(TRUE)); +} - width = closestWidth; - height = closestHeight; - } - } +void callRightMouseUp(float *pos, MASK mask) +{ + if (gWindowImplementation->allowsLanguageInput()) + { + gWindowImplementation->interruptLanguageTextInput(); + } + + LLCoordGL outCoords; + outCoords.mX = ll_round(pos[0]); + outCoords.mY = ll_round(pos[1]); + gWindowImplementation->getCallbacks()->handleRightMouseUp(gWindowImplementation, outCoords, gKeyboard->currentMask(TRUE)); +} - if((width == 0) || (height == 0)) - { - // Mode search failed for some reason. Use the old-school default. - width = 1024; - height = 768; - } +void callLeftMouseDown(float *pos, MASK mask) +{ + if (gWindowImplementation->allowsLanguageInput()) + { + gWindowImplementation->interruptLanguageTextInput(); + } + + LLCoordGL outCoords; + outCoords.mX = ll_round(pos[0]); + outCoords.mY = ll_round(pos[1]); + gWindowImplementation->getCallbacks()->handleMouseDown(gWindowImplementation, outCoords, gKeyboard->currentMask(TRUE)); +} - if (true) - { - // Fullscreen support - CFDictionaryRef refDisplayMode = 0; - boolean_t exactMatch = false; - -#if CAPTURE_ALL_DISPLAYS - // Capture all displays (may want to do this for final build) - CGCaptureAllDisplays (); -#else - // Capture only the main display (useful for debugging) - CGDisplayCapture (mDisplay); -#endif +void callLeftMouseUp(float *pos, MASK mask) +{ + if (gWindowImplementation->allowsLanguageInput()) + { + gWindowImplementation->interruptLanguageTextInput(); + } + + LLCoordGL outCoords; + outCoords.mX = ll_round(pos[0]); + outCoords.mY = ll_round(pos[1]); + gWindowImplementation->getCallbacks()->handleMouseUp(gWindowImplementation, outCoords, gKeyboard->currentMask(TRUE)); + +} - // Switch the display to the desired resolution and refresh - refDisplayMode = CGDisplayBestModeForParametersAndRefreshRate( - mDisplay, - BITS_PER_PIXEL, - width, - height, - refresh, - &exactMatch); +void callDoubleClick(float *pos, MASK mask) +{ + if (gWindowImplementation->allowsLanguageInput()) + { + gWindowImplementation->interruptLanguageTextInput(); + } + + LLCoordGL outCoords; + outCoords.mX = ll_round(pos[0]); + outCoords.mY = ll_round(pos[1]); + gWindowImplementation->getCallbacks()->handleDoubleClick(gWindowImplementation, outCoords, gKeyboard->currentMask(TRUE)); +} - if (refDisplayMode) - { - LL_DEBUGS("Window") << "createContext: switching display resolution" << LL_ENDL; - mOldDisplayMode = CGDisplayCurrentMode (mDisplay); - CGDisplaySwitchToMode (mDisplay, refDisplayMode); - // CFRelease(refDisplayMode); +void callResize(unsigned int width, unsigned int height) +{ + if (gWindowImplementation != NULL) + { + gWindowImplementation->getCallbacks()->handleResize(gWindowImplementation, width, height); + } +} - AddEventTypesToHandler(mGlobalHandlerRef, GetEventTypeCount (GlobalHandlerEventList), GlobalHandlerEventList); - } +void callMouseMoved(float *pos, MASK mask) +{ + LLCoordGL outCoords; + outCoords.mX = ll_round(pos[0]); + outCoords.mY = ll_round(pos[1]); + S32 deltas[2]; + gWindowImplementation->getMouseDeltas(deltas); + outCoords.mX += deltas[0]; + outCoords.mY += deltas[1]; + gWindowImplementation->getCallbacks()->handleMouseMove(gWindowImplementation, outCoords, gKeyboard->currentMask(TRUE)); +} +void callScrollMoved(float delta) +{ + gWindowImplementation->getCallbacks()->handleScrollWheel(gWindowImplementation, delta); +} - mFullscreen = TRUE; - mFullscreenWidth = CGDisplayPixelsWide(mDisplay); - mFullscreenHeight = CGDisplayPixelsHigh(mDisplay); - mFullscreenBits = CGDisplayBitsPerPixel(mDisplay); - mFullscreenRefresh = llround(getDictDouble (CGDisplayCurrentMode (mDisplay), kCGDisplayRefreshRate)); +void callMouseExit() +{ + gWindowImplementation->getCallbacks()->handleMouseLeave(gWindowImplementation); +} - LL_INFOS("Window") << "Running at " << mFullscreenWidth - << "x" << mFullscreenHeight - << "x" << mFullscreenBits - << " @ " << mFullscreenRefresh - << LL_ENDL; - } - else - { - // No fullscreen support - mFullscreen = FALSE; - mFullscreenWidth = -1; - mFullscreenHeight = -1; - mFullscreenBits = -1; - mFullscreenRefresh = -1; - - std::string error= llformat("Unable to run fullscreen at %d x %d.\nRunning in window.", width, height); - OSMessageBox(error, "Error", OSMB_OK); - } +void callWindowFocus() +{ + if ( gWindowImplementation && gWindowImplementation->getCallbacks() ) + { + gWindowImplementation->getCallbacks()->handleFocus(gWindowImplementation); + // Reset badge count + updateBadge(0); } - - if(!mFullscreen && (mWindow == NULL)) + else { - //int displayWidth = CGDisplayPixelsWide(mDisplay); - //int displayHeight = CGDisplayPixelsHigh(mDisplay); - //const int menuBarPlusTitleBar = 44; // Ugly magic number. - - LL_DEBUGS("Window") << "createContext: creating window" << LL_ENDL; - - mPreviousWindowRect.left = (long) x; - mPreviousWindowRect.right = (long) x + width; - mPreviousWindowRect.top = (long) y; - mPreviousWindowRect.bottom = (long) y + height; - - //----------------------------------------------------------------------- - // Create the window - //----------------------------------------------------------------------- - mWindow = NewCWindow( - NULL, - &mPreviousWindowRect, - mWindowTitle, - false, // Create the window invisible. Whoever calls createContext() should show it after any moving/resizing. - // noGrowDocProc, // Window with no grow box and no zoom box - zoomDocProc, // Window with a grow box and a zoom box - // zoomNoGrow, // Window with a zoom box but no grow box - kFirstWindowOfClass, - true, - (long)this); + LL_WARNS("COCOA") << "Window Implementation or callbacks not yet initialized." << LL_ENDL; + } - if (!mWindow) - { - setupFailure("Window creation error", "Error", OSMB_OK); - return FALSE; - } - // Turn on live resize. - // For this to work correctly, we need to be able to call LLViewerWindow::draw from - // the event handler for kEventWindowBoundsChanged. It's not clear that we have access from here. - // err = ChangeWindowAttributes(mWindow, kWindowLiveResizeAttribute, 0); +} - // Set up window event handlers (some window-related events ONLY go to window handlers.) - InstallStandardEventHandler(GetWindowEventTarget(mWindow)); - InstallWindowEventHandler(mWindow, mEventHandlerUPP, GetEventTypeCount (WindowHandlerEventList), WindowHandlerEventList, (void*)this, &mWindowHandlerRef); // add event handler -#if LL_OS_DRAGDROP_ENABLED - InstallTrackingHandler( dragTrackingHandler, mWindow, (void*)this ); - InstallReceiveHandler( dragReceiveHandler, mWindow, (void*)this ); -#endif // LL_OS_DRAGDROP_ENABLED - } +void callWindowUnfocus() +{ + gWindowImplementation->getCallbacks()->handleFocusLost(gWindowImplementation); +} +void callWindowHide() +{ + if ( gWindowImplementation && gWindowImplementation->getCallbacks() ) { - // Create and initialize our TSM document for language text input. - // If an error occured, we can do nothing better than simply ignore it. - // mTSMDocument will be kept NULL in case. - if (mTSMDocument) - { - DeactivateTSMDocument(mTSMDocument); - DeleteTSMDocument(mTSMDocument); - mTSMDocument = NULL; - } - static InterfaceTypeList types = { kUnicodeDocument }; - err = NewTSMDocument(1, types, &mTSMDocument, 0); - if (err != noErr) - { - LL_WARNS("Window") << "createContext: couldn't create a TSMDocument (" << err << ")" << LL_ENDL; - } - if (mTSMDocument) - { - ActivateTSMDocument(mTSMDocument); - allowLanguageTextInput(NULL, FALSE); - } + gWindowImplementation->getCallbacks()->handleActivate(gWindowImplementation, false); } +} - if(mContext == NULL) +void callWindowUnhide() +{ + if ( gWindowImplementation && gWindowImplementation->getCallbacks() ) { - AGLRendererInfo rendererInfo = NULL; + gWindowImplementation->getCallbacks()->handleActivate(gWindowImplementation, true); + } +} - //----------------------------------------------------------------------- - // Create GL drawing context - //----------------------------------------------------------------------- +void callDeltaUpdate(double *delta, MASK mask) +{ + gWindowImplementation->updateMouseDeltas(delta); +} - if(mPixelFormat == NULL) - { - if(mFullscreen) - { - GLint fullscreenAttrib[] = - { - AGL_RGBA, - AGL_FULLSCREEN, - AGL_NO_RECOVERY, - AGL_SAMPLE_BUFFERS_ARB, mFSAASamples > 0 ? 1 : 0, - AGL_SAMPLES_ARB, mFSAASamples, - AGL_DOUBLEBUFFER, - AGL_CLOSEST_POLICY, - AGL_ACCELERATED, - AGL_RED_SIZE, 8, - AGL_GREEN_SIZE, 8, - AGL_BLUE_SIZE, 8, - AGL_ALPHA_SIZE, 8, - AGL_DEPTH_SIZE, 24, - AGL_STENCIL_SIZE, 8, - AGL_NONE - }; - - LL_DEBUGS("Window") << "createContext: creating fullscreen pixelformat" << LL_ENDL; - - GDHandle gdhDisplay = NULL; - err = DMGetGDeviceByDisplayID ((DisplayIDType)mDisplay, &gdhDisplay, false); - - mPixelFormat = aglChoosePixelFormat(&gdhDisplay, 1, fullscreenAttrib); - rendererInfo = aglQueryRendererInfo(&gdhDisplay, 1); - } - else - { - // NOTE from Leslie: - // - // AGL_NO_RECOVERY, when combined with AGL_ACCELERATED prevents software rendering - // fallback which means we won't hvae shaders that compile and link but then don't - // work. The drawback is that our shader compilation will be a bit more finicky though. +void callMiddleMouseDown(float *pos, MASK mask) +{ + LLCoordGL outCoords; + outCoords.mX = ll_round(pos[0]); + outCoords.mY = ll_round(pos[1]); + S32 deltas[2]; + gWindowImplementation->getMouseDeltas(deltas); + outCoords.mX += deltas[0]; + outCoords.mY += deltas[1]; + gWindowImplementation->getCallbacks()->handleMiddleMouseDown(gWindowImplementation, outCoords, mask); +} - GLint windowedAttrib[] = - { - AGL_RGBA, - AGL_NO_RECOVERY, - AGL_DOUBLEBUFFER, - AGL_CLOSEST_POLICY, - AGL_ACCELERATED, - AGL_SAMPLE_BUFFERS_ARB, mFSAASamples > 0 ? 1 : 0, - AGL_SAMPLES_ARB, mFSAASamples, - AGL_RED_SIZE, 8, - AGL_GREEN_SIZE, 8, - AGL_BLUE_SIZE, 8, - AGL_ALPHA_SIZE, 8, - AGL_DEPTH_SIZE, 24, - AGL_STENCIL_SIZE, 8, - AGL_NONE - }; - - LL_DEBUGS("Window") << "createContext: creating windowed pixelformat" << LL_ENDL; - - mPixelFormat = aglChoosePixelFormat(NULL, 0, windowedAttrib); - - GDHandle gdhDisplay = GetMainDevice(); - rendererInfo = aglQueryRendererInfo(&gdhDisplay, 1); - } +void callMiddleMouseUp(float *pos, MASK mask) +{ + LLCoordGL outCoords; + outCoords.mX = ll_round(pos[0]); + outCoords.mY = ll_round(pos[1]); + S32 deltas[2]; + gWindowImplementation->getMouseDeltas(deltas); + outCoords.mX += deltas[0]; + outCoords.mY += deltas[1]; + gWindowImplementation->getCallbacks()->handleMiddleMouseUp(gWindowImplementation, outCoords, mask); +} - // May want to get the real error text like this: - // (char *) aglErrorString(aglGetError()); +void callModifier(MASK mask) +{ + gKeyboard->handleModifier(mask); +} - if(aglGetError() != AGL_NO_ERROR) - { - setupFailure("Can't find suitable pixel format", "Error", OSMB_OK); - return FALSE; - } - } +void callHandleDragEntered(std::string url) +{ + gWindowImplementation->handleDragNDrop(url, LLWindowCallbacks::DNDA_START_TRACKING); +} - if(mPixelFormat) - { - LL_DEBUGS("Window") << "createContext: creating GL context" << LL_ENDL; - mContext = aglCreateContext(mPixelFormat, NULL); - } +void callHandleDragExited(std::string url) +{ + gWindowImplementation->handleDragNDrop(url, LLWindowCallbacks::DNDA_STOP_TRACKING); +} - if(mContext == NULL) - { - setupFailure("Can't make GL context", "Error", OSMB_OK); - return FALSE; - } +void callHandleDragUpdated(std::string url) +{ + gWindowImplementation->handleDragNDrop(url, LLWindowCallbacks::DNDA_TRACK); +} - gGLManager.mVRAM = 0; +void callHandleDragDropped(std::string url) +{ + gWindowImplementation->handleDragNDrop(url, LLWindowCallbacks::DNDA_DROPPED); +} - if(rendererInfo != NULL) +void callQuitHandler() +{ + if (gWindowImplementation) + { + if(gWindowImplementation->getCallbacks()->handleCloseRequest(gWindowImplementation)) { - GLint result; - - if(aglDescribeRenderer(rendererInfo, AGL_VIDEO_MEMORY, &result)) - { - // llinfos << "createContext: aglDescribeRenderer(AGL_VIDEO_MEMORY) returned " << result << llendl; - gGLManager.mVRAM = result / (1024 * 1024); - } - else - { - // llinfos << "createContext: aglDescribeRenderer(AGL_VIDEO_MEMORY) failed." << llendl; - } - - // This could be useful at some point, if it takes into account the memory already used by screen buffers, etc... - if(aglDescribeRenderer(rendererInfo, AGL_TEXTURE_MEMORY, &result)) - { - // llinfos << "createContext: aglDescribeRenderer(AGL_TEXTURE_MEMORY) returned " << result << llendl; - } - else - { - // llinfos << "createContext: aglDescribeRenderer(AGL_TEXTURE_MEMORY) failed." << llendl; - } - - aglDestroyRendererInfo(rendererInfo); + gWindowImplementation->getCallbacks()->handleQuit(gWindowImplementation); } - - // Since we just created the context, it needs to be set up. - glNeedsInit = TRUE; } +} - // Hook up the context to a drawable - if (mFullscreen && (mOldDisplayMode != NULL)) +void getPreeditSelectionRange(int *position, int *length) +{ + if (gWindowImplementation->getPreeditor()) { - // We successfully captured the display. Use a fullscreen drawable - - LL_DEBUGS("Window") << "createContext: attaching fullscreen drawable" << LL_ENDL; - -#if CAPTURE_ALL_DISPLAYS - // Capture all displays (may want to do this for final build) - aglDisable (mContext, AGL_FS_CAPTURE_SINGLE); -#else - // Capture only the main display (useful for debugging) - aglEnable (mContext, AGL_FS_CAPTURE_SINGLE); -#endif - - if (!aglSetFullScreen (mContext, 0, 0, 0, 0)) - { - setupFailure("Can't set GL fullscreen", "Error", OSMB_OK); - return FALSE; - } + gWindowImplementation->getPreeditor()->getSelectionRange(position, length); } - else if(!mFullscreen && (mWindow != NULL)) +} + +void getPreeditMarkedRange(int *position, int *length) +{ + if (gWindowImplementation->getPreeditor()) { - LL_DEBUGS("Window") << "createContext: attaching windowed drawable" << LL_ENDL; + gWindowImplementation->getPreeditor()->getPreeditRange(position, length); + } +} - // We created a window. Use it as the drawable. - if(!aglSetDrawable(mContext, GetWindowPort (mWindow))) - { - setupFailure("Can't set GL drawable", "Error", OSMB_OK); - return FALSE; - } +void setPreeditMarkedRange(int position, int length) +{ + if (gWindowImplementation->getPreeditor()) + { + gWindowImplementation->getPreeditor()->markAsPreedit(position, length); } - else +} + +bool handleUnicodeCharacter(wchar_t c) +{ + bool success = false; + if (gWindowImplementation->getPreeditor()) { - setupFailure("Can't get fullscreen or windowed drawable.", "Error", OSMB_OK); - return FALSE; + success = gWindowImplementation->getPreeditor()->handleUnicodeCharHere(c); } + + return success; +} - if(mContext != NULL) +void resetPreedit() +{ + if (gWindowImplementation->getPreeditor()) { - LL_DEBUGS("Window") << "createContext: setting current context" << LL_ENDL; + gWindowImplementation->getPreeditor()->resetPreedit(); + } +} - if (!aglSetCurrentContext(mContext)) +// For reasons of convenience, handle IME updates here. +// This largely mirrors the old implementation, only sans the carbon parameters. +void setMarkedText(unsigned short *unitext, unsigned int *replacementRange, long text_len, attributedStringInfo segments) +{ + if (gWindowImplementation->getPreeditor()) + { + LLPreeditor *preeditor = gWindowImplementation->getPreeditor(); + preeditor->resetPreedit(); + // This should be a viable replacement for the kEventParamTextInputSendReplaceRange parameter. + if (replacementRange[0] < replacementRange[1]) { - setupFailure("Can't activate GL rendering context", "Error", OSMB_OK); - return FALSE; + const LLWString& text = preeditor->getPreeditString(); + const S32 location = wstring_wstring_length_from_utf16_length(text, 0, replacementRange[0]); + const S32 length = wstring_wstring_length_from_utf16_length(text, location, replacementRange[1]); + preeditor->markAsPreedit(location, length); } + + LLWString fix_str = utf16str_to_wstring(llutf16string(unitext, text_len)); + + S32 caret_position = fix_str.length(); + + preeditor->updatePreedit(fix_str, segments.seg_lengths, segments.seg_standouts, caret_position); } +} - if(glNeedsInit) +void getPreeditLocation(float *location, unsigned int length) +{ + if (gWindowImplementation->getPreeditor()) { - // Check for some explicitly unsupported cards. - const char* RENDERER = (const char*) glGetString(GL_RENDERER); - - const char* CARD_LIST[] = - { "RAGE 128", - "RIVA TNT2", - "Intel 810", - "3Dfx/Voodoo3", - "Radeon 7000", - "Radeon 7200", - "Radeon 7500", - "Radeon DDR", - "Radeon VE", - "GDI Generic" }; - const S32 CARD_COUNT = LL_ARRAY_SIZE(CARD_LIST); - - // Future candidates: - // ProSavage/Twister - // SuperSavage + LLPreeditor *preeditor = gWindowImplementation->getPreeditor(); + LLCoordGL coord; + LLCoordScreen screen; + LLRect rect; + + preeditor->getPreeditLocation(length, &coord, &rect, NULL); + + float c[4] = {static_cast(coord.mX), + static_cast(coord.mY), 0, 0}; + + convertRectToScreen(gWindowImplementation->getWindow(), c); + + location[0] = c[0]; + location[1] = c[1]; + } +} - S32 i; - for (i = 0; i < CARD_COUNT; i++) +void LLWindowMacOSX::updateMouseDeltas(double* deltas) +{ + if (mCursorDecoupled) + { + mCursorLastEventDeltaX = ll_round(deltas[0]); + mCursorLastEventDeltaY = ll_round(-deltas[1]); + + if (mCursorIgnoreNextDelta) { - if (check_for_card(RENDERER, CARD_LIST[i])) - { - close(); - return FALSE; - } + mCursorLastEventDeltaX = 0; + mCursorLastEventDeltaY = 0; + mCursorIgnoreNextDelta = FALSE; } + } else { + mCursorLastEventDeltaX = 0; + mCursorLastEventDeltaY = 0; } +} - GLint colorBits, alphaBits, depthBits, stencilBits; +void LLWindowMacOSX::getMouseDeltas(S32* delta) +{ + delta[0] = mCursorLastEventDeltaX; + delta[1] = mCursorLastEventDeltaY; +} - if( !aglDescribePixelFormat(mPixelFormat, AGL_BUFFER_SIZE, &colorBits) || - !aglDescribePixelFormat(mPixelFormat, AGL_ALPHA_SIZE, &alphaBits) || - !aglDescribePixelFormat(mPixelFormat, AGL_DEPTH_SIZE, &depthBits) || - !aglDescribePixelFormat(mPixelFormat, AGL_STENCIL_SIZE, &stencilBits)) +BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, S32 vsync_setting) +{ + mFullscreen = fullscreen; + + if (mWindow == NULL) { - close(); - setupFailure("Can't get pixel format description", "Error", OSMB_OK); - return FALSE; + mWindow = getMainAppWindow(); } - LL_INFOS("GLInit") << "GL buffer: Color Bits " << S32(colorBits) - << " Alpha Bits " << S32(alphaBits) - << " Depth Bits " << S32(depthBits) - << " Stencil Bits" << S32(stencilBits) - << LL_ENDL; - - if (colorBits < 32) + // Disable vertical sync for swap + bool vsync_enabled; + GLint frames_per_swap; + switch (vsync_setting) { - close(); - setupFailure( - "Second Life requires True Color (32-bit) to run in a window.\n" - "Please go to Control Panels -> Display -> Settings and\n" - "set the screen to 32-bit color.\n" - "Alternately, if you choose to run fullscreen, Second Life\n" - "will automatically adjust the screen each time it runs.", - "Error", - OSMB_OK); - return FALSE; + //default: + case 0: //E_VSYNC_DISABLED: + { + LL_INFOS("Window") << "Disabling vertical sync" << LL_ENDL; + vsync_enabled = false; + frames_per_swap = 0; + break; } - - if (alphaBits < 8) + case -1: //E_VSYNC_ADAPTIVE: + default: //case E_VSYNC_NORMAL: { - close(); - setupFailure( - "Second Life is unable to run because it can't get an 8 bit alpha\n" - "channel. Usually this is due to video card driver issues.\n" - "Please make sure you have the latest video card drivers installed.\n" - "Also be sure your monitor is set to True Color (32-bit) in\n" - "Control Panels -> Display -> Settings.\n" - "If you continue to receive this message, contact customer service.", - "Error", - OSMB_OK); - return FALSE; + LL_INFOS("Window") << "Enabling vertical sync" << LL_ENDL; + vsync_enabled = true; + frames_per_swap = 1; + break; + } } - // Disable vertical sync for swap - GLint frames_per_swap = 0; - if (disable_vsync) + if(mContext == NULL) { - LL_DEBUGS("GLInit") << "Disabling vertical sync" << LL_ENDL; - frames_per_swap = 0; + // Our OpenGL view is already defined within SecondLife.xib. + // Get the view instead. + mGLView = createOpenGLView(mWindow, mFSAASamples, vsync_enabled); + mContext = getCGLContextObj(mGLView); + + gGLManager.mVRAM = getVramSize(mGLView); } - else + + // This sets up our view to recieve text from our non-inline text input window. + setupInputWindow(mWindow, mGLView); + + // Hook up the context to a drawable + + if(mContext != NULL) { - LL_DEBUGS("GLinit") << "Keeping vertical sync" << LL_ENDL; - frames_per_swap = 1; + + + CGLError err = CGLSetCurrentContext(mContext); + if (err != kCGLNoError) + { + setupFailure("Can't activate GL rendering context", "Error", OSMB_OK); + return FALSE; + } } - aglSetInteger(mContext, AGL_SWAP_INTERVAL, &frames_per_swap); + + CGLSetParameter(mContext, kCGLCPSwapInterval, &frames_per_swap); //enable multi-threaded OpenGL - if (sUseMultGL) + if (gUseMultGL) { CGLError cgl_err; CGLContextObj ctx = CGLGetCurrentContext(); @@ -809,114 +651,22 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits LL_DEBUGS("GLInit") << "Multi-threaded OpenGL enabled." << LL_ENDL; } } - - // Don't need to get the current gamma, since there's a call that restores it to the system defaults. + makeFirstResponder(mWindow, mGLView); + return TRUE; } -// changing fullscreen resolution, or switching between windowed and fullscreen mode. -BOOL LLWindowMacOSX::switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp) +// We only support OS X 10.7's fullscreen app mode which is literally a full screen window that fills a virtual desktop. +// This makes this method obsolete. +BOOL LLWindowMacOSX::switchContext(BOOL fullscreen, const LLCoordScreen &size, const S32 vsync_mode, std::function stopFn, std::function restoreFn, const LLCoordScreen * const posp) { - BOOL needsRebuild = FALSE; - BOOL result = true; + return FALSE; +} - if(fullscreen) - { - if(mFullscreen) - { - // Switching resolutions in fullscreen mode. Don't need to rebuild for this. - // Fullscreen support - CFDictionaryRef refDisplayMode = 0; - boolean_t exactMatch = false; - - // Switch the display to the desired resolution and refresh - refDisplayMode = CGDisplayBestModeForParametersAndRefreshRate( - mDisplay, - BITS_PER_PIXEL, - size.mX, - size.mY, - getDictDouble (CGDisplayCurrentMode (mDisplay), kCGDisplayRefreshRate), - &exactMatch); - - if (refDisplayMode) - { - CGDisplaySwitchToMode (mDisplay, refDisplayMode); - // CFRelease(refDisplayMode); - } - - mFullscreenWidth = CGDisplayPixelsWide(mDisplay); - mFullscreenHeight = CGDisplayPixelsHigh(mDisplay); - mFullscreenBits = CGDisplayBitsPerPixel(mDisplay); - mFullscreenRefresh = llround(getDictDouble (CGDisplayCurrentMode (mDisplay), kCGDisplayRefreshRate)); - - LL_INFOS("Window") << "Switched resolution to " << mFullscreenWidth - << "x" << mFullscreenHeight - << "x" << mFullscreenBits - << " @ " << mFullscreenRefresh - << LL_ENDL; - - // Update the GL context to the new screen size - if (!aglUpdateContext(mContext)) - { - setupFailure("Can't set GL fullscreen", "Error", OSMB_OK); - result = FALSE; - } - } - else - { - // Switching from windowed to fullscreen - needsRebuild = TRUE; - } - } - else - { - if(mFullscreen) - { - // Switching from fullscreen to windowed - needsRebuild = TRUE; - } - else - { - // Windowed to windowed -- not sure why we would be called like this. Just change the window size. - // The bounds changed event handler will do the rest. - if(mWindow != NULL) - { - ::SizeWindow(mWindow, size.mX, size.mY, true); - } - } - } - - stop_glerror(); - if(needsRebuild || mForceRebuild) - { - mForceRebuild = FALSE; - destroyContext(); - result = createContext(0, 0, size.mX, size.mY, 0, fullscreen, disable_vsync); - if (result) - { - if(mWindow != NULL) - { - MacShowWindow(mWindow); - BringToFront(mWindow); - } - - llverify(gGLManager.initGL()); - - //start with arrow cursor - initCursors(); - setCursor( UI_CURSOR_ARROW ); - } - } - - stop_glerror(); - - return result; -} - -void LLWindowMacOSX::destroyContext() -{ - if (!mContext) +void LLWindowMacOSX::destroyContext() +{ + if (!mContext) { // We don't have a context return; @@ -925,32 +675,7 @@ void LLWindowMacOSX::destroyContext() if(mContext != NULL) { LL_DEBUGS("Window") << "destroyContext: unhooking drawable " << LL_ENDL; - - aglSetCurrentContext (NULL); - aglSetDrawable(mContext, NULL); - } - - // Make sure the display resolution gets restored - if(mOldDisplayMode != NULL) - { - LL_DEBUGS("Window") << "destroyContext: restoring display resolution " << LL_ENDL; - - CGDisplaySwitchToMode (mDisplay, mOldDisplayMode); - -#if CAPTURE_ALL_DISPLAYS - // Uncapture all displays (may want to do this for final build) - CGReleaseAllDisplays (); -#else - // Uncapture only the main display (useful for debugging) - CGDisplayRelease (mDisplay); -#endif - - // CFRelease(mOldDisplayMode); - - mOldDisplayMode = NULL; - - // Remove the global event handlers the fullscreen case needed - RemoveEventTypesFromHandler(mGlobalHandlerRef, GetEventTypeCount (GlobalHandlerEventList), GlobalHandlerEventList); + CGLSetCurrentContext(NULL); } // Clean up remaining GL state before blowing away window @@ -959,49 +684,29 @@ void LLWindowMacOSX::destroyContext() // Clean up the pixel format if(mPixelFormat != NULL) { - LL_DEBUGS("Window") << "destroyContext: destroying pixel format " << LL_ENDL; - aglDestroyPixelFormat(mPixelFormat); + CGLDestroyPixelFormat(mPixelFormat); mPixelFormat = NULL; } - // Remove any Carbon Event handlers we installed - if(mGlobalHandlerRef != NULL) - { - LL_DEBUGS("Window") << "destroyContext: removing global event handler" << LL_ENDL; - RemoveEventHandler(mGlobalHandlerRef); - mGlobalHandlerRef = NULL; - } - - if(mWindowHandlerRef != NULL) + // Destroy our LLOpenGLView + if(mGLView != NULL) { - LL_DEBUGS("Window") << "destroyContext: removing window event handler" << LL_ENDL; - RemoveEventHandler(mWindowHandlerRef); - mWindowHandlerRef = NULL; + removeGLView(mGLView); + mGLView = NULL; } - - // Cleanup any TSM document we created. - if(mTSMDocument != NULL) + + // Clean up the GL context + if(mContext != NULL) { - LL_DEBUGS("Window") << "destroyContext: deleting TSM document" << LL_ENDL; - DeactivateTSMDocument(mTSMDocument); - DeleteTSMDocument(mTSMDocument); - mTSMDocument = NULL; + CGLDestroyContext(mContext); } - + // Close the window if(mWindow != NULL) { - LL_DEBUGS("Window") << "destroyContext: disposing window" << LL_ENDL; - DisposeWindow(mWindow); - mWindow = NULL; - } - - // Clean up the GL context - if(mContext != NULL) - { - LL_DEBUGS("Window") << "destroyContext: destroying GL context" << LL_ENDL; - aglDestroyContext(mContext); - mContext = NULL; + NSWindowRef dead_window = mWindow; + mWindow = NULL; + closeWindow(dead_window); } } @@ -1020,19 +725,13 @@ LLWindowMacOSX::~LLWindowMacOSX() } -void LLWindowMacOSX::show() +void LLWindowMacOSX::show(bool) { - if(IsWindowCollapsed(mWindow)) - CollapseWindow(mWindow, false); - - MacShowWindow(mWindow); - BringToFront(mWindow); } void LLWindowMacOSX::hide() { setMouseClipping(FALSE); - HideWindow(mWindow); } //virtual @@ -1040,7 +739,6 @@ void LLWindowMacOSX::minimize() { setMouseClipping(FALSE); showCursor(); - CollapseWindow(mWindow, true); } //virtual @@ -1069,7 +767,7 @@ void LLWindowMacOSX::close() BOOL LLWindowMacOSX::isValid() { - if(mFullscreen) + if (mFullscreen) { return(TRUE); } @@ -1081,12 +779,12 @@ BOOL LLWindowMacOSX::getVisible() { BOOL result = FALSE; - if(mFullscreen) + if (mFullscreen) { result = TRUE; - }if (mWindow) + } + if (mWindow) { - if(MacIsWindowVisible(mWindow)) result = TRUE; } @@ -1107,7 +805,6 @@ BOOL LLWindowMacOSX::maximize() { if (mWindow && !mMaximized) { - ZoomWindow(mWindow, inContent, true); } return mMaximized; @@ -1120,60 +817,15 @@ BOOL LLWindowMacOSX::getFullscreen() void LLWindowMacOSX::gatherInput() { - // stop bouncing icon after fixed period of time - if (mBounceTimer.getStarted() && mBounceTimer.getElapsedTimeF32() > mBounceTime) - { - stopDockTileBounce(); - } - - // Use the old-school version so we get AppleEvent handler dispatch and menuselect handling. - // Anything that has an event handler will get processed inside WaitNextEvent, so we only need to handle - // the odd stuff here. - EventRecord evt; - while(WaitNextEvent(everyEvent, &evt, 0, NULL)) - { - // printf("WaitNextEvent returned true, event is %d.\n", evt.what); - switch(evt.what) - { - case mouseDown: - { - short part; - WindowRef window; - long selectResult; - part = FindWindow(evt.where, &window); - switch ( part ) - { - case inMenuBar: - selectResult = MenuSelect(evt.where); - - HiliteMenu(0); - break; - } - } - break; - - case kHighLevelEvent: - AEProcessAppleEvent (&evt); - break; - - case updateEvt: - // We shouldn't be getting these regularly (since our window will be buffered), but we need to handle them correctly... - BeginUpdate((WindowRef)evt.message); - EndUpdate((WindowRef)evt.message); - break; - - } - } - updateCursor(); } BOOL LLWindowMacOSX::getPosition(LLCoordScreen *position) { - Rect window_rect; - OSStatus err = -1; + float rect[4]; + S32 err = -1; - if(mFullscreen) + if (mFullscreen) { position->mX = 0; position->mY = 0; @@ -1181,14 +833,14 @@ BOOL LLWindowMacOSX::getPosition(LLCoordScreen *position) } else if(mWindow) { - err = GetWindowBounds(mWindow, kWindowContentRgn, &window_rect); + getContentViewBounds(mWindow, rect); - position->mX = window_rect.left; - position->mY = window_rect.top; + position->mX = rect[0]; + position->mY = rect[1]; } else { - llerrs << "LLWindowMacOSX::getPosition(): no window and not fullscreen!" << llendl; + LL_ERRS() << "LLWindowMacOSX::getPosition(): no window and not fullscreen!" << LL_ENDL; } return (err == noErr); @@ -1196,10 +848,10 @@ BOOL LLWindowMacOSX::getPosition(LLCoordScreen *position) BOOL LLWindowMacOSX::getSize(LLCoordScreen *size) { - Rect window_rect; - OSStatus err = -1; + float rect[4]; + S32 err = -1; - if(mFullscreen) + if (mFullscreen) { size->mX = mFullscreenWidth; size->mY = mFullscreenHeight; @@ -1207,14 +859,14 @@ BOOL LLWindowMacOSX::getSize(LLCoordScreen *size) } else if(mWindow) { - err = GetWindowBounds(mWindow, kWindowContentRgn, &window_rect); + getScaledContentViewBounds(mWindow, mGLView, rect); - size->mX = window_rect.right - window_rect.left; - size->mY = window_rect.bottom - window_rect.top; + size->mX = rect[2]; + size->mY = rect[3]; } else { - llerrs << "LLWindowMacOSX::getPosition(): no window and not fullscreen!" << llendl; + LL_ERRS() << "LLWindowMacOSX::getPosition(): no window and not fullscreen!" << LL_ENDL; } return (err == noErr); @@ -1222,10 +874,10 @@ BOOL LLWindowMacOSX::getSize(LLCoordScreen *size) BOOL LLWindowMacOSX::getSize(LLCoordWindow *size) { - Rect window_rect; - OSStatus err = -1; - - if(mFullscreen) + float rect[4]; + S32 err = -1; + + if (mFullscreen) { size->mX = mFullscreenWidth; size->mY = mFullscreenHeight; @@ -1233,72 +885,69 @@ BOOL LLWindowMacOSX::getSize(LLCoordWindow *size) } else if(mWindow) { - err = GetWindowBounds(mWindow, kWindowContentRgn, &window_rect); - - size->mX = window_rect.right - window_rect.left; - size->mY = window_rect.bottom - window_rect.top; + getScaledContentViewBounds(mWindow, mGLView, rect); + + size->mX = rect[2]; + size->mY = rect[3]; } else { - llerrs << "LLWindowMacOSX::getPosition(): no window and not fullscreen!" << llendl; + LL_ERRS() << "LLWindowMacOSX::getPosition(): no window and not fullscreen!" << LL_ENDL; } - + return (err == noErr); } -BOOL LLWindowMacOSX::setPosition(const LLCoordScreen position) +BOOL LLWindowMacOSX::setPosition(LLCoordScreen position) { if(mWindow) { - MacMoveWindow(mWindow, position.mX, position.mY, false); + float pos[2] = {static_cast(position.mX), + static_cast(position.mY)}; + setWindowPos(mWindow, pos); } return TRUE; } -BOOL LLWindowMacOSX::setSizeImpl(const LLCoordScreen size) +BOOL LLWindowMacOSX::setSizeImpl(LLCoordScreen size) { if(mWindow) { - SizeWindow(mWindow, size.mX, size.mY, true); + LLCoordWindow to; + convertCoords(size, &to); + setWindowSize(mWindow, to.mX, to.mY); + return TRUE; } - return TRUE; + return FALSE; } -BOOL LLWindowMacOSX::setSizeImpl(const LLCoordWindow size) +BOOL LLWindowMacOSX::setSizeImpl(LLCoordWindow size) { - Rect client_rect; if (mWindow) { - OSStatus err = GetWindowBounds(mWindow, kWindowContentRgn, &client_rect); - if (err == noErr) - { - client_rect.right = client_rect.left + size.mX; - client_rect.bottom = client_rect.top + size.mY; - err = SetWindowBounds(mWindow, kWindowContentRgn, &client_rect); - } - if (err == noErr) - { - return TRUE; - } - else - { - llinfos << "Error setting size" << err << llendl; - return FALSE; - } + const int titlePadding = 22; + setWindowSize(mWindow, size.mX, size.mY + titlePadding); + return TRUE; } + return FALSE; } void LLWindowMacOSX::swapBuffers() { - aglSwapBuffers(mContext); + CGLFlushDrawable(mContext); +} + +void LLWindowMacOSX::restoreGLContext() +{ + CGLSetCurrentContext(mContext); } F32 LLWindowMacOSX::getGamma() { - F32 result = 1.8; // Default to something sane + F32 result = 2.2; // Default to something sane CGGammaValue redMin; CGGammaValue redMax; @@ -1410,17 +1059,17 @@ void LLWindowMacOSX::setMouseClipping( BOOL b ) if(b) { - // llinfos << "setMouseClipping(TRUE)" << llendl; + // LL_INFOS() << "setMouseClipping(TRUE)" << LL_ENDL; } else { - // llinfos << "setMouseClipping(FALSE)" << llendl; + // LL_INFOS() << "setMouseClipping(FALSE)" << LL_ENDL; } adjustCursorDecouple(); } -BOOL LLWindowMacOSX::setCursorPosition(const LLCoordWindow position) +BOOL LLWindowMacOSX::setCursorPosition(LLCoordWindow position) { BOOL result = FALSE; LLCoordScreen screen_pos; @@ -1432,16 +1081,18 @@ BOOL LLWindowMacOSX::setCursorPosition(const LLCoordWindow position) CGPoint newPosition; - // llinfos << "setCursorPosition(" << screen_pos.mX << ", " << screen_pos.mY << ")" << llendl; + // LL_INFOS() << "setCursorPosition(" << screen_pos.mX << ", " << screen_pos.mY << ")" << LL_ENDL; newPosition.x = screen_pos.mX; newPosition.y = screen_pos.mY; - CGSetLocalEventsSuppressionInterval(0.0); + CGEventSourceRef src = CGEventSourceCreate(kCGEventSourceStateHIDSystemState); + CGEventSourceSetLocalEventsSuppressionInterval(src, 0.0); if(CGWarpMouseCursorPosition(newPosition) == noErr) { result = TRUE; } + CFRelease(src); // Under certain circumstances, this will trigger us to decouple the cursor. adjustCursorDecouple(true); @@ -1454,39 +1105,15 @@ BOOL LLWindowMacOSX::setCursorPosition(const LLCoordWindow position) return result; } -static void fixOrigin(void) -{ - GrafPtr port; - Rect portrect; - - ::GetPort(&port); - ::GetPortBounds(port, &portrect); - if((portrect.left != 0) || (portrect.top != 0)) - { - // Mozilla sometimes changes our port origin. - ::SetOrigin(0,0); - } -} - BOOL LLWindowMacOSX::getCursorPosition(LLCoordWindow *position) { - Point cursor_point; + float cursor_point[2]; LLCoordScreen screen_pos; - GrafPtr save; if(mWindow == NULL) return FALSE; - - ::GetPort(&save); - ::SetPort(GetWindowPort(mWindow)); - fixOrigin(); - - // gets the mouse location in local coordinates - ::GetMouse(&cursor_point); - -// lldebugs << "getCursorPosition(): cursor is at " << cursor_point.h << ", " << cursor_point.v << " port origin: " << portrect.left << ", " << portrect.top << llendl; - - ::SetPort(save); + + getCursorPos(mWindow, cursor_point); if(mCursorDecoupled) { @@ -1499,12 +1126,12 @@ BOOL LLWindowMacOSX::getCursorPosition(LLCoordWindow *position) // CGGetLastMouseDelta may behave strangely when the cursor's first captured. // Stash in the event handler instead. - cursor_point.h += mCursorLastEventDeltaX; - cursor_point.v += mCursorLastEventDeltaY; + cursor_point[0] += mCursorLastEventDeltaX; + cursor_point[1] += mCursorLastEventDeltaY; } - - position->mX = cursor_point.h; - position->mY = cursor_point.v; + float scale = getScaleFactor(); + position->mX = cursor_point[0] * scale; + position->mY = cursor_point[1] * scale; return TRUE; } @@ -1518,10 +1145,9 @@ void LLWindowMacOSX::adjustCursorDecouple(bool warpingMouse) // The cursor should be decoupled. Make sure it is. if(!mCursorDecoupled) { - // llinfos << "adjustCursorDecouple: decoupling cursor" << llendl; + // LL_INFOS() << "adjustCursorDecouple: decoupling cursor" << LL_ENDL; CGAssociateMouseAndMouseCursorPosition(false); mCursorDecoupled = true; - FlushSpecificEventsFromQueue(GetCurrentEventQueue(), mMoveEventCampartorUPP, NULL); mCursorIgnoreNextDelta = TRUE; } } @@ -1531,7 +1157,7 @@ void LLWindowMacOSX::adjustCursorDecouple(bool warpingMouse) // The cursor should not be decoupled. Make sure it isn't. if(mCursorDecoupled) { - // llinfos << "adjustCursorDecouple: recoupling cursor" << llendl; + // LL_INFOS() << "adjustCursorDecouple: recoupling cursor" << LL_ENDL; CGAssociateMouseAndMouseCursorPosition(true); mCursorDecoupled = false; } @@ -1568,183 +1194,56 @@ F32 LLWindowMacOSX::getPixelAspectRatio() // MBW -- XXX -- There's got to be a better way than this. Find it, please... +// Since we're no longer supporting the "typical" fullscreen mode with CGL or NSOpenGL anymore, these are unnecessary. -Geenz void LLWindowMacOSX::beforeDialog() { - if(mFullscreen) - { - -#if CAPTURE_ALL_DISPLAYS - // Uncapture all displays (may want to do this for final build) - CGReleaseAllDisplays (); -#else - // Uncapture only the main display (useful for debugging) - CGDisplayRelease (mDisplay); -#endif - // kDocumentWindowClass - // kMovableModalWindowClass - // kAllWindowClasses - - // GLint order = 0; - // aglSetInteger(mContext, AGL_ORDER_CONTEXT_TO_FRONT, &order); - aglSetDrawable(mContext, NULL); - // GetWindowGroupLevel(GetWindowGroupOfClass(kAllWindowClasses), &oldWindowLevel); - // SetWindowGroupLevel(GetWindowGroupOfClass(kAllWindowClasses), CGShieldingWindowLevel()); - - mHandsOffEvents = TRUE; - - } } void LLWindowMacOSX::afterDialog() { - if(mFullscreen) - { - mHandsOffEvents = FALSE; - - // SetWindowGroupLevel(GetWindowGroupOfClass(kAllWindowClasses), oldWindowLevel); - aglSetFullScreen(mContext, 0, 0, 0, 0); - // GLint order = 1; - // aglSetInteger(mContext, AGL_ORDER_CONTEXT_TO_FRONT, &order); - -#if CAPTURE_ALL_DISPLAYS - // Capture all displays (may want to do this for final build) - CGCaptureAllDisplays (); -#else - // Capture only the main display (useful for debugging) - CGDisplayCapture (mDisplay); -#endif - } + //For fix problem with Core Flow view on OSX + restoreGLContext(); } void LLWindowMacOSX::flashIcon(F32 seconds) { - // Don't do this if we're already started, since this would try to install the NMRec twice. - if(!mBounceTimer.getStarted()) - { - OSErr err; - - mBounceTime = seconds; - memset(&mBounceRec, 0, sizeof(mBounceRec)); - mBounceRec.qType = nmType; - mBounceRec.nmMark = 1; - err = NMInstall(&mBounceRec); - if(err == noErr) - { - mBounceTimer.start(); - } - else - { - // This is very not-fatal (only problem is the icon will not bounce), but we'd like to find out about it somehow... - llinfos << "NMInstall failed with error code " << err << llendl; - } - } + // For consistency with OS X conventions, the number of seconds given is ignored and + // left up to the OS (which will actually bounce it for one second). + requestUserAttention(); } BOOL LLWindowMacOSX::isClipboardTextAvailable() { - OSStatus err; - ScrapRef scrap; - ScrapFlavorFlags flags; - BOOL result = false; - - err = GetCurrentScrap(&scrap); - - if(err == noErr) - { - err = GetScrapFlavorFlags(scrap, kScrapFlavorTypeUnicode, &flags); - } - - if(err == noErr) - result = true; - - return result; + return pasteBoardAvailable(); } BOOL LLWindowMacOSX::pasteTextFromClipboard(LLWString &dst) -{ - OSStatus err; - ScrapRef scrap; - Size len; - BOOL result = false; - - err = GetCurrentScrap(&scrap); - - if(err == noErr) - { - err = GetScrapFlavorSize(scrap, kScrapFlavorTypeUnicode, &len); - } - - if((err == noErr) && (len > 0)) +{ + llutf16string str(copyFromPBoard()); + dst = utf16str_to_wstring(str); + if (dst != L"") { - int u16len = len / sizeof(U16); - U16 *temp = new U16[u16len + 1]; - if (temp) - { - memset(temp, 0, (u16len + 1) * sizeof(temp[0])); - err = GetScrapFlavorData(scrap, kScrapFlavorTypeUnicode, &len, temp); - if (err == noErr) - { - // convert \r\n to \n and \r to \n in the incoming text. - U16 *s, *d; - for(s = d = temp; s[0] != '\0'; s++, d++) - { - if(s[0] == '\r') - { - if(s[1] == '\n') - { - // CRLF, a.k.a. DOS newline. Collapse to a single '\n'. - s++; - } - - d[0] = '\n'; - } - else - { - d[0] = s[0]; - } - } - - d[0] = '\0'; - - dst = utf16str_to_wstring(temp); - - result = true; - } - delete[] temp; - } + return true; + } else { + return false; } - - return result; } BOOL LLWindowMacOSX::copyTextToClipboard(const LLWString &s) { - OSStatus err; - ScrapRef scrap; - //Size len; - //char *temp; BOOL result = false; - - if (!s.empty()) - { - err = GetCurrentScrap(&scrap); - if (err == noErr) - err = ClearScrap(&scrap); - - if (err == noErr) - { - llutf16string utf16str = wstring_to_utf16str(s); - size_t u16len = utf16str.length() * sizeof(U16); - err = PutScrapFlavor(scrap, kScrapFlavorTypeUnicode, kScrapFlavorMaskNone, u16len, utf16str.data()); - if (err == noErr) - result = true; - } - } + llutf16string utf16str = wstring_to_utf16str(s); + + result = copyToPBoard(utf16str.data(), utf16str.length()); return result; } +void LLWindowMacOSX::setWindowTitle(const std::string& title) +{ + setTitle(title); +} // protected BOOL LLWindowMacOSX::resetDisplayResolution() @@ -1758,7 +1257,7 @@ LLWindow::LLWindowResolution* LLWindowMacOSX::getSupportedResolutions(S32 &num_r { if (!mSupportedResolutions) { - CFArrayRef modes = CGDisplayAvailableModes(mDisplay); + CFArrayRef modes = CGDisplayCopyAllDisplayModes(mDisplay, NULL); if(modes != NULL) { @@ -1781,1030 +1280,107 @@ LLWindow::LLWindowResolution* LLWindowMacOSX::getSupportedResolutions(S32 &num_r if(bits == BITS_PER_PIXEL && width >= 800 && height >= 600) { BOOL resolution_exists = FALSE; - for(S32 i = 0; i < mNumSupportedResolutions; i++) - { - if (mSupportedResolutions[i].mWidth == width && - mSupportedResolutions[i].mHeight == height) - { - resolution_exists = TRUE; - } - } - if (!resolution_exists) - { - mSupportedResolutions[mNumSupportedResolutions].mWidth = width; - mSupportedResolutions[mNumSupportedResolutions].mHeight = height; - mNumSupportedResolutions++; - } - } - } - } - } - - num_resolutions = mNumSupportedResolutions; - return mSupportedResolutions; -} - -BOOL LLWindowMacOSX::convertCoords(LLCoordGL from, LLCoordWindow *to) -{ - S32 client_height; - Rect client_rect; - - if(mFullscreen) - { - // In the fullscreen case, the "window" is the entire screen. - client_rect.left = 0; - client_rect.top = 0; - client_rect.right = mFullscreenWidth; - client_rect.bottom = mFullscreenHeight; - } - else if (!mWindow || - (GetWindowBounds(mWindow, kWindowContentRgn, &client_rect) != noErr) || - NULL == to) - { - return FALSE; - } - - to->mX = from.mX; - client_height = client_rect.bottom - client_rect.top; - to->mY = client_height - from.mY - 1; - - return TRUE; -} - -BOOL LLWindowMacOSX::convertCoords(LLCoordWindow from, LLCoordGL* to) -{ - S32 client_height; - Rect client_rect; - - if(mFullscreen) - { - // In the fullscreen case, the "window" is the entire screen. - client_rect.left = 0; - client_rect.top = 0; - client_rect.right = mFullscreenWidth; - client_rect.bottom = mFullscreenHeight; - } - else if (!mWindow || - (GetWindowBounds(mWindow, kWindowContentRgn, &client_rect) != noErr) || - NULL == to) - { - return FALSE; - } - - to->mX = from.mX; - client_height = client_rect.bottom - client_rect.top; - to->mY = client_height - from.mY - 1; - - return TRUE; -} - -BOOL LLWindowMacOSX::convertCoords(LLCoordScreen from, LLCoordWindow* to) -{ - if(mFullscreen) - { - // In the fullscreen case, window and screen coordinates are the same. - to->mX = from.mX; - to->mY = from.mY; - return TRUE; - } - else if(mWindow) - { - GrafPtr save; - Point mouse_point; - - mouse_point.h = from.mX; - mouse_point.v = from.mY; - - ::GetPort(&save); - ::SetPort(GetWindowPort(mWindow)); - fixOrigin(); - - ::GlobalToLocal(&mouse_point); - - to->mX = mouse_point.h; - to->mY = mouse_point.v; - - ::SetPort(save); - - return TRUE; - } - - return FALSE; -} - -BOOL LLWindowMacOSX::convertCoords(LLCoordWindow from, LLCoordScreen *to) -{ - if(mFullscreen) - { - // In the fullscreen case, window and screen coordinates are the same. - to->mX = from.mX; - to->mY = from.mY; - return TRUE; - } - else if(mWindow) - { - GrafPtr save; - Point mouse_point; - - mouse_point.h = from.mX; - mouse_point.v = from.mY; - ::GetPort(&save); - ::SetPort(GetWindowPort(mWindow)); - fixOrigin(); - - LocalToGlobal(&mouse_point); - - to->mX = mouse_point.h; - to->mY = mouse_point.v; - - ::SetPort(save); - - return TRUE; - } - - return FALSE; -} - -BOOL LLWindowMacOSX::convertCoords(LLCoordScreen from, LLCoordGL *to) -{ - LLCoordWindow window_coord; - - return(convertCoords(from, &window_coord) && convertCoords(window_coord, to)); -} - -BOOL LLWindowMacOSX::convertCoords(LLCoordGL from, LLCoordScreen *to) -{ - LLCoordWindow window_coord; - - return(convertCoords(from, &window_coord) && convertCoords(window_coord, to)); -} - - - - -void LLWindowMacOSX::setupFailure(const std::string& text, const std::string& caption, U32 type) -{ - destroyContext(); - - OSMessageBox(text, caption, type); -} - -pascal Boolean LLWindowMacOSX::staticMoveEventComparator( EventRef event, void* data) -{ - UInt32 evtClass = GetEventClass (event); - UInt32 evtKind = GetEventKind (event); - - if ((evtClass == kEventClassMouse) && ((evtKind == kEventMouseDragged) || (evtKind == kEventMouseMoved))) - { - return true; - } - - else - { - return false; - } -} - - -pascal OSStatus LLWindowMacOSX::staticEventHandler(EventHandlerCallRef myHandler, EventRef event, void* userData) -{ - LLWindowMacOSX *self = (LLWindowMacOSX*)userData; - - return(self->eventHandler(myHandler, event)); -} - -OSStatus LLWindowMacOSX::eventHandler (EventHandlerCallRef myHandler, EventRef event) -{ - OSStatus result = eventNotHandledErr; - UInt32 evtClass = GetEventClass (event); - UInt32 evtKind = GetEventKind (event); - - // Always handle command events, even in hands-off mode. - if((evtClass == kEventClassCommand) && (evtKind == kEventCommandProcess)) - { - HICommand command; - GetEventParameter (event, kEventParamDirectObject, typeHICommand, NULL, sizeof(command), NULL, &command); - - switch(command.commandID) - { - case kHICommandQuit: - if(mCallbacks->handleCloseRequest(this)) - { - // Get the app to initiate cleanup. - mCallbacks->handleQuit(this); - // The app is responsible for calling destroyWindow when done with GL - } - result = noErr; - break; - - default: - // MBW -- XXX -- Should we handle other events here? - break; - } - } - - if(mHandsOffEvents) - { - return(result); - } - - switch (evtClass) - { - case kEventClassTextInput: - { - switch (evtKind) - { - case kEventTextInputUpdateActiveInputArea: - { - EventParamType param_type; - - long fix_len; - UInt32 text_len; - if (mPreeditor - && (result = GetEventParameter(event, kEventParamTextInputSendFixLen, - typeLongInteger, ¶m_type, sizeof(fix_len), NULL, &fix_len)) == noErr - && typeLongInteger == param_type - && (result = GetEventParameter(event, kEventParamTextInputSendText, - typeUnicodeText, ¶m_type, 0, &text_len, NULL)) == noErr - && typeUnicodeText == param_type) - { - // Handle an optional (but essential to facilitate TSMDA) ReplaceRange param. - CFRange range; - if (GetEventParameter(event, kEventParamTextInputSendReplaceRange, - typeCFRange, ¶m_type, sizeof(range), NULL, &range) == noErr - && typeCFRange == param_type) - { - // Although the spec. is unclear, replace range should - // not present when there is an active preedit. We just - // ignore the case. markAsPreedit will detect the case and warn it. - const LLWString & text = mPreeditor->getPreeditString(); - const S32 location = wstring_wstring_length_from_utf16_length(text, 0, range.location); - const S32 length = wstring_wstring_length_from_utf16_length(text, location, range.length); - mPreeditor->markAsPreedit(location, length); - } - mPreeditor->resetPreedit(); - - // Receive the text from input method. - U16 *const text = new U16[text_len / sizeof(U16)]; - GetEventParameter(event, kEventParamTextInputSendText, typeUnicodeText, NULL, text_len, NULL, text); - if (fix_len < 0) - { - // Do we still need this? Seems obsolete... - fix_len = text_len; - } - const LLWString fix_string - = utf16str_to_wstring(llutf16string(text, fix_len / sizeof(U16))); - const LLWString preedit_string - = utf16str_to_wstring(llutf16string(text + fix_len / sizeof(U16), (text_len - fix_len) / sizeof(U16))); - delete[] text; - - // Handle fixed (comitted) string. - if (fix_string.length() > 0) - { - for (LLWString::const_iterator i = fix_string.begin(); i != fix_string.end(); i++) - { - mPreeditor->handleUnicodeCharHere(*i); - } - } - - // Receive the segment info and caret position. - LLPreeditor::segment_lengths_t preedit_segment_lengths; - LLPreeditor::standouts_t preedit_standouts; - S32 caret_position = preedit_string.length(); - UInt32 text_range_array_size; - if (GetEventParameter(event, kEventParamTextInputSendHiliteRng, typeTextRangeArray, - ¶m_type, 0, &text_range_array_size, NULL) == noErr - && typeTextRangeArray == param_type - && text_range_array_size > sizeof(TextRangeArray)) - { - // TextRangeArray is a variable-length struct. - TextRangeArray * const text_range_array = (TextRangeArray *) new char[text_range_array_size]; - GetEventParameter(event, kEventParamTextInputSendHiliteRng, typeTextRangeArray, - NULL, text_range_array_size, NULL, text_range_array); - - // WARNING: We assume ranges are in ascending order, - // although the condition is undocumented. It seems - // OK to assume this. I also assumed - // the ranges are contiguous in previous versions, but I - // have heard a rumore that older versions os ATOK may - // return ranges with some _gap_. I don't know whether - // it is true, but I'm preparing my code for the case. - - const S32 ranges = text_range_array->fNumOfRanges; - preedit_segment_lengths.reserve(ranges); - preedit_standouts.reserve(ranges); - - S32 last_bytes = 0; - S32 last_utf32 = 0; - for (S32 i = 0; i < ranges; i++) - { - const TextRange &range = text_range_array->fRange[i]; - if (range.fStart > last_bytes) - { - const S32 length_utf16 = (range.fStart - last_bytes) / sizeof(U16); - const S32 length_utf32 = wstring_wstring_length_from_utf16_length(preedit_string, last_utf32, length_utf16); - preedit_segment_lengths.push_back(length_utf32); - preedit_standouts.push_back(FALSE); - last_utf32 += length_utf32; - } - if (range.fEnd > range.fStart) - { - const S32 length_utf16 = (range.fEnd - range.fStart) / sizeof(U16); - const S32 length_utf32 = wstring_wstring_length_from_utf16_length(preedit_string, last_utf32, length_utf16); - preedit_segment_lengths.push_back(length_utf32); - preedit_standouts.push_back( - kTSMHiliteSelectedRawText == range.fHiliteStyle - || kTSMHiliteSelectedConvertedText == range.fHiliteStyle - || kTSMHiliteSelectedText == range.fHiliteStyle); - last_utf32 += length_utf32; - } - if (kTSMHiliteCaretPosition == range.fHiliteStyle) - { - caret_position = last_utf32; - } - last_bytes = range.fEnd; - } - if (preedit_string.length() > last_utf32) - { - preedit_segment_lengths.push_back(preedit_string.length() - last_utf32); - preedit_standouts.push_back(FALSE); - } - - delete[] (char *) text_range_array; - } - - // Handle preedit string. - if (preedit_string.length() == 0) - { - preedit_segment_lengths.clear(); - preedit_standouts.clear(); - } - else if (preedit_segment_lengths.size() == 0) - { - preedit_segment_lengths.push_back(preedit_string.length()); - preedit_standouts.push_back(FALSE); - } - mPreeditor->updatePreedit(preedit_string, preedit_segment_lengths, preedit_standouts, caret_position); - - result = noErr; - } - } - break; - - case kEventTextInputUnicodeForKeyEvent: - { - UInt32 modifiers = 0; - - - // First, process the raw event. - { - EventRef rawEvent = NULL; - - // Get the original event and extract the modifier keys, so we can ignore command-key events. - if (GetEventParameter(event, kEventParamTextInputSendKeyboardEvent, typeEventRef, NULL, sizeof(rawEvent), NULL, &rawEvent) == noErr) - { - // Grab the modifiers for later use in this function... - GetEventParameter (rawEvent, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers); - - // and call this function recursively to handle the raw key event. - eventHandler (myHandler, rawEvent); - - // save the raw event until we're done processing the unicode input as well. - mRawKeyEvent = rawEvent; - } - } - - OSStatus err = noErr; - EventParamType actualType = typeUnicodeText; - UInt32 actualSize = 0; - size_t actualCount = 0; - U16 *buffer = NULL; - - // Get the size of the unicode data - err = GetEventParameter (event, kEventParamTextInputSendText, typeUnicodeText, &actualType, 0, &actualSize, NULL); - if(err == noErr) - { - // allocate a buffer and get the actual data. - actualCount = actualSize / sizeof(U16); - buffer = new U16[actualCount]; - err = GetEventParameter (event, kEventParamTextInputSendText, typeUnicodeText, &actualType, actualSize, &actualSize, buffer); - } - - if(err == noErr) - { - if(modifiers & (cmdKey | controlKey)) - { - // This was a menu key equivalent. Ignore it. - } - else - { - MASK mask = LLWindowMacOSX::modifiersToMask(modifiers); - - llassert( actualType == typeUnicodeText ); - - // The result is a UTF16 buffer. Pass the characters in turn to handleUnicodeChar. - - // Convert to UTF32 and go character-by-character. - llutf16string utf16(buffer, actualCount); - LLWString utf32 = utf16str_to_wstring(utf16); - LLWString::iterator iter; - - for(iter = utf32.begin(); iter != utf32.end(); iter++) - { - mCallbacks->handleUnicodeChar(*iter, mask); - } - } - } - - if(buffer != NULL) - { - delete[] buffer; - } - - mRawKeyEvent = NULL; - result = err; - } - break; - - case kEventTextInputOffsetToPos: - { - EventParamType param_type; - long offset; - if (mPreeditor - && GetEventParameter(event, kEventParamTextInputSendTextOffset, typeLongInteger, - ¶m_type, sizeof(offset), NULL, &offset) == noErr - && typeLongInteger == param_type) - { - S32 preedit, preedit_length; - mPreeditor->getPreeditRange(&preedit, &preedit_length); - const LLWString & text = mPreeditor->getPreeditString(); - - LLCoordGL caret_coord; - LLRect preedit_bounds; - if (0 <= offset - && mPreeditor->getPreeditLocation(wstring_wstring_length_from_utf16_length(text, preedit, offset / sizeof(U16)), - &caret_coord, &preedit_bounds, NULL)) - { - LLCoordGL caret_base_coord(caret_coord.mX, preedit_bounds.mBottom); - LLCoordScreen caret_base_coord_screen; - convertCoords(caret_base_coord, &caret_base_coord_screen); - Point qd_point; - qd_point.h = caret_base_coord_screen.mX; - qd_point.v = caret_base_coord_screen.mY; - SetEventParameter(event, kEventParamTextInputReplyPoint, typeQDPoint, sizeof(qd_point), &qd_point); - - short line_height = (short) preedit_bounds.getHeight(); - SetEventParameter(event, kEventParamTextInputReplyLineHeight, typeShortInteger, sizeof(line_height), &line_height); - - result = noErr; - } - else - { - result = errOffsetInvalid; - } - } - } - break; - - case kEventTextInputGetSelectedText: - { - if (mPreeditor) - { - S32 selection, selection_length; - mPreeditor->getSelectionRange(&selection, &selection_length); - if (selection_length) - { - const LLWString text = mPreeditor->getPreeditString().substr(selection, selection_length); - const llutf16string text_utf16 = wstring_to_utf16str(text); - result = SetEventParameter(event, kEventParamTextInputReplyText, typeUnicodeText, - text_utf16.length() * sizeof(U16), text_utf16.c_str()); - } - } - } - break; - } - } - break; - - case kEventClassKeyboard: - { - UInt32 keyCode = 0; - char charCode = 0; - UInt32 modifiers = 0; - - // Some of these may fail for some event types. That's fine. - GetEventParameter (event, kEventParamKeyCode, typeUInt32, NULL, sizeof(UInt32), NULL, &keyCode); - GetEventParameter (event, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers); - - // save the raw event so getNativeKeyData can use it. - mRawKeyEvent = event; - - // printf("key event, key code = 0x%08x, char code = 0x%02x (%c), modifiers = 0x%08x\n", keyCode, charCode, (char)charCode, modifiers); - // fflush(stdout); - - switch (evtKind) - { - case kEventRawKeyDown: - case kEventRawKeyRepeat: - if (gDebugWindowProc) - { - printf("key down, key code = 0x%08x, char code = 0x%02x (%c), modifiers = 0x%08x\n", - (unsigned int)keyCode, charCode, (char)charCode, (unsigned int)modifiers); - fflush(stdout); - } - gKeyboard->handleKeyDown(keyCode, modifiers); - result = eventNotHandledErr; - break; - - case kEventRawKeyUp: - if (gDebugWindowProc) - { - printf("key up, key code = 0x%08x, char code = 0x%02x (%c), modifiers = 0x%08x\n", - (unsigned int)keyCode, charCode, (char)charCode, (unsigned int)modifiers); - fflush(stdout); - } - gKeyboard->handleKeyUp(keyCode, modifiers); - result = eventNotHandledErr; - break; - - case kEventRawKeyModifiersChanged: - // The keyboard input system wants key up/down events for modifier keys. - // Mac OS doesn't supply these directly, but can supply events when the collective modifier state changes. - // Use these events to generate up/down events for the modifiers. - - if((modifiers & shiftKey) && !(mLastModifiers & shiftKey)) - { - if (gDebugWindowProc) printf("Shift key down event\n"); - gKeyboard->handleKeyDown(0x38, (modifiers & 0x00FFFFFF) | ((0x38 << 24) & 0xFF000000)); - } - else if(!(modifiers & shiftKey) && (mLastModifiers & shiftKey)) - { - if (gDebugWindowProc) printf("Shift key up event\n"); - gKeyboard->handleKeyUp(0x38, (modifiers & 0x00FFFFFF) | ((0x38 << 24) & 0xFF000000)); - } - - if((modifiers & alphaLock) && !(mLastModifiers & alphaLock)) - { - if (gDebugWindowProc) printf("Caps lock down event\n"); - gKeyboard->handleKeyDown(0x39, (modifiers & 0x00FFFFFF) | ((0x39 << 24) & 0xFF000000)); - } - else if(!(modifiers & alphaLock) && (mLastModifiers & alphaLock)) - { - if (gDebugWindowProc) printf("Caps lock up event\n"); - gKeyboard->handleKeyUp(0x39, (modifiers & 0x00FFFFFF) | ((0x39 << 24) & 0xFF000000)); - } - - if((modifiers & controlKey) && !(mLastModifiers & controlKey)) - { - if (gDebugWindowProc) printf("Control key down event\n"); - gKeyboard->handleKeyDown(0x3b, (modifiers & 0x00FFFFFF) | ((0x3b << 24) & 0xFF000000)); - } - else if(!(modifiers & controlKey) && (mLastModifiers & controlKey)) - { - if (gDebugWindowProc) printf("Control key up event\n"); - gKeyboard->handleKeyUp(0x3b, (modifiers & 0x00FFFFFF) | ((0x3b << 24) & 0xFF000000)); - } - - if((modifiers & optionKey) && !(mLastModifiers & optionKey)) - { - if (gDebugWindowProc) printf("Option key down event\n"); - gKeyboard->handleKeyDown(0x3a, (modifiers & 0x00FFFFFF) | ((0x3a << 24) & 0xFF000000)); - } - else if(!(modifiers & optionKey) && (mLastModifiers & optionKey)) - { - if (gDebugWindowProc) printf("Option key up event\n"); - gKeyboard->handleKeyUp(0x3a, (modifiers & 0x00FFFFFF) | ((0x3a << 24) & 0xFF000000)); - } - - // When the state of the 'Fn' key (the one that changes some of the mappings on a powerbook/macbook keyboard - // to an embedded keypad) changes, it may subsequently cause a key up event to be lost, which may lead to - // a movement key getting "stuck" down. This is bad. - // This is an OS bug -- even the GetKeys() API doesn't tell you the key has been released. - // This workaround causes all held-down keys to be reset whenever the state of the Fn key changes. This isn't - // exactly what we want, but it does avoid the case where you get stuck running forward. - if((modifiers & kEventKeyModifierFnMask) != (mLastModifiers & kEventKeyModifierFnMask)) - { - if (gDebugWindowProc) printf("Fn key state change event\n"); - gKeyboard->resetKeys(); - } - - if (gDebugWindowProc) fflush(stdout); - - mLastModifiers = modifiers; - result = eventNotHandledErr; - break; - } - - mRawKeyEvent = NULL; - } - break; - - case kEventClassMouse: - { - result = CallNextEventHandler(myHandler, event); - if (eventNotHandledErr == result) - { // only handle events not already handled (prevents wierd resize interaction) - EventMouseButton button = kEventMouseButtonPrimary; - HIPoint location = {0.0f, 0.0f}; - UInt32 modifiers = 0; - UInt32 clickCount = 1; - long wheelDelta = 0; - LLCoordScreen inCoords; - LLCoordGL outCoords; - MASK mask = 0; - - GetEventParameter(event, kEventParamMouseButton, typeMouseButton, NULL, sizeof(button), NULL, &button); - GetEventParameter(event, kEventParamMouseLocation, typeHIPoint, NULL, sizeof(location), NULL, &location); - GetEventParameter(event, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(modifiers), NULL, &modifiers); - GetEventParameter(event, kEventParamMouseWheelDelta, typeLongInteger, NULL, sizeof(wheelDelta), NULL, &wheelDelta); - GetEventParameter(event, kEventParamClickCount, typeUInt32, NULL, sizeof(clickCount), NULL, &clickCount); - - inCoords.mX = llround(location.x); - inCoords.mY = llround(location.y); - - if(modifiers & shiftKey) { mask |= MASK_SHIFT; } - if(modifiers & controlKey) { mask |= MASK_CONTROL; } - if(modifiers & optionKey) { mask |= MASK_ALT; } - - if(mCursorDecoupled) - { - CGMouseDelta x, y; - - // If the cursor's decoupled, we need to read the latest movement delta as well. - CGGetLastMouseDelta( &x, &y ); - mCursorLastEventDeltaX = x; - mCursorLastEventDeltaY = y; - - if(mCursorIgnoreNextDelta) - { - mCursorLastEventDeltaX = 0; - mCursorLastEventDeltaY = 0; - mCursorIgnoreNextDelta = FALSE; - } - } - else - { - mCursorLastEventDeltaX = 0; - mCursorLastEventDeltaY = 0; - } - - inCoords.mX += mCursorLastEventDeltaX; - inCoords.mY += mCursorLastEventDeltaY; - - convertCoords(inCoords, &outCoords); - - // printf("coords in: %d, %d; coords out: %d, %d\n", inCoords.mX, inCoords.mY, outCoords.mX, outCoords.mY); - // fflush(stdout); - - - switch (evtKind) - { - case kEventMouseDown: - if (mLanguageTextInputAllowed) - { - // We need to interrupt before handling mouse events, - // so that the fixed string from IM are delivered to - // the currently focused UI component. - interruptLanguageTextInput(); - } - switch(button) - { - case kEventMouseButtonPrimary: - if(modifiers & cmdKey) - { - // Simulate a right click - mSimulatedRightClick = true; - mCallbacks->handleRightMouseDown(this, outCoords, mask); - } - else if(clickCount == 2) - { - // Windows double-click events replace the second mousedown event in a double-click. - mCallbacks->handleDoubleClick(this, outCoords, mask); - } - else - { - mCallbacks->handleMouseDown(this, outCoords, mask); - } - break; - case kEventMouseButtonSecondary: - mCallbacks->handleRightMouseDown(this, outCoords, mask); - break; - - case kEventMouseButtonTertiary: - mCallbacks->handleMiddleMouseDown(this, outCoords, mask); - break; - } - result = noErr; - break; - case kEventMouseUp: - - switch(button) - { - case kEventMouseButtonPrimary: - if(mSimulatedRightClick) - { - // End of simulated right click - mSimulatedRightClick = false; - mCallbacks->handleRightMouseUp(this, outCoords, mask); - } - else - { - mCallbacks->handleMouseUp(this, outCoords, mask); - } - break; - case kEventMouseButtonSecondary: - mCallbacks->handleRightMouseUp(this, outCoords, mask); - break; - - case kEventMouseButtonTertiary: - mCallbacks->handleMiddleMouseUp(this, outCoords, mask); - break; - } - result = noErr; - break; - - case kEventMouseWheelMoved: - { - static S32 z_delta = 0; - - z_delta += wheelDelta; - - if (z_delta <= -WHEEL_DELTA || WHEEL_DELTA <= z_delta) - { - mCallbacks->handleScrollWheel(this, -z_delta / WHEEL_DELTA); - z_delta = 0; - } - } - result = noErr; - break; - - case kEventMouseDragged: - case kEventMouseMoved: - mCallbacks->handleMouseMove(this, outCoords, mask); - result = noErr; - break; - - } - } - } - break; - - case kEventClassWindow: - switch(evtKind) - { - case kEventWindowActivated: - if (mTSMDocument) - { - ActivateTSMDocument(mTSMDocument); - } - mCallbacks->handleFocus(this); - break; - case kEventWindowDeactivated: - if (mTSMDocument) - { - DeactivateTSMDocument(mTSMDocument); - } - mCallbacks->handleFocusLost(this); - break; - - case kEventWindowBoundsChanging: - { - // This is where we would constrain move/resize to a particular screen - - const S32 MIN_WIDTH = mMinWindowWidth; - const S32 MIN_HEIGHT = mMinWindowHeight; - - Rect currentBounds; - Rect previousBounds; - - GetEventParameter(event, kEventParamCurrentBounds, typeQDRectangle, NULL, sizeof(Rect), NULL, ¤tBounds); - GetEventParameter(event, kEventParamPreviousBounds, typeQDRectangle, NULL, sizeof(Rect), NULL, &previousBounds); - - // Put an offset into window un-maximize operation since the kEventWindowGetIdealSize - // event only allows the specification of size and not position. - if (mMaximized) - { - short leftOffset = mPreviousWindowRect.left - currentBounds.left; - currentBounds.left += leftOffset; - currentBounds.right += leftOffset; - - short topOffset = mPreviousWindowRect.top - currentBounds.top; - currentBounds.top += topOffset; - currentBounds.bottom += topOffset; - } - else - { - // Store off the size for future un-maximize operations - mPreviousWindowRect = previousBounds; - } - - if ((currentBounds.right - currentBounds.left) < MIN_WIDTH) - { - currentBounds.right = currentBounds.left + MIN_WIDTH; - } - - if ((currentBounds.bottom - currentBounds.top) < MIN_HEIGHT) - { - currentBounds.bottom = currentBounds.top + MIN_HEIGHT; + for(S32 i = 0; i < mNumSupportedResolutions; i++) + { + if (mSupportedResolutions[i].mWidth == width && + mSupportedResolutions[i].mHeight == height) + { + resolution_exists = TRUE; + } + } + if (!resolution_exists) + { + mSupportedResolutions[mNumSupportedResolutions].mWidth = width; + mSupportedResolutions[mNumSupportedResolutions].mHeight = height; + mNumSupportedResolutions++; + } } - - SetEventParameter(event, kEventParamCurrentBounds, typeQDRectangle, sizeof(Rect), ¤tBounds); - result = noErr; } - break; + CFRelease(modes); + } + } - case kEventWindowBoundsChanged: - { - // Get new window bounds - Rect newBounds; - GetEventParameter(event, kEventParamCurrentBounds, typeQDRectangle, NULL, sizeof(Rect), NULL, &newBounds); + num_resolutions = mNumSupportedResolutions; + return mSupportedResolutions; +} - // Get previous window bounds - Rect oldBounds; - GetEventParameter(event, kEventParamPreviousBounds, typeQDRectangle, NULL, sizeof(Rect), NULL, &oldBounds); +BOOL LLWindowMacOSX::convertCoords(LLCoordGL from, LLCoordWindow *to) +{ + to->mX = from.mX; + to->mY = from.mY; + return TRUE; +} - // Determine if the new size is larger than the old - bool newBoundsLarger = ((newBounds.right - newBounds.left) >= (oldBounds.right - oldBounds.left)); - newBoundsLarger &= ((newBounds.bottom - newBounds.top) >= (oldBounds.bottom - oldBounds.top)); +BOOL LLWindowMacOSX::convertCoords(LLCoordWindow from, LLCoordGL* to) +{ + to->mX = from.mX; + to->mY = from.mY; + return TRUE; +} - // Check to see if this is a zoom event (+ button on window pane) - unsigned int eventParams; - GetEventParameter(event, kEventParamAttributes, typeUInt32, NULL, sizeof(int), NULL, &eventParams); - bool isZoomEvent = ((eventParams & kWindowBoundsChangeZoom) != 0); +BOOL LLWindowMacOSX::convertCoords(LLCoordScreen from, LLCoordWindow* to) +{ + if(mWindow) + { + float mouse_point[2]; + float scale_factor = getScaleFactor(); + mouse_point[0] = from.mX; + mouse_point[1] = from.mY; + + convertScreenToWindow(mWindow, mouse_point); - // Maximized flag is if zoom event and increasing window size - mMaximized = (isZoomEvent && newBoundsLarger); + to->mX = mouse_point[0] * scale_factor; + to->mY = mouse_point[1] * scale_factor; - aglUpdateContext(mContext); + return TRUE; + } + return FALSE; +} - mCallbacks->handleResize(this, newBounds.right - newBounds.left, newBounds.bottom - newBounds.top); - } - break; +BOOL LLWindowMacOSX::convertCoords(LLCoordWindow from, LLCoordScreen *to) +{ + if(mWindow) + { + float mouse_point[2]; + float scale_factor = getScaleFactor(); + mouse_point[0] = from.mX / scale_factor; + mouse_point[1] = from.mY / scale_factor; + convertWindowToScreen(mWindow, mouse_point); - case kEventWindowGetIdealSize: - // Only recommend a new ideal size when un-maximizing - if (mMaximized == TRUE) - { - Point nonMaximizedSize; + to->mX = mouse_point[0]; + to->mY = mouse_point[1]; - nonMaximizedSize.v = mPreviousWindowRect.bottom - mPreviousWindowRect.top; - nonMaximizedSize.h = mPreviousWindowRect.right - mPreviousWindowRect.left; + return TRUE; + } + return FALSE; +} - SetEventParameter(event, kEventParamDimensions, typeQDPoint, sizeof(Point), &nonMaximizedSize); - result = noErr; - } - break; +BOOL LLWindowMacOSX::convertCoords(LLCoordScreen from, LLCoordGL *to) +{ + LLCoordWindow window_coord; - case kEventWindowClose: - if(mCallbacks->handleCloseRequest(this)) - { - // Get the app to initiate cleanup. - mCallbacks->handleQuit(this); - // The app is responsible for calling destroyWindow when done with GL - } - result = noErr; - break; - - case kEventWindowHidden: - // llinfos << "LLWindowMacOSX: Deactivating on hide" << llendl; - mMinimized = TRUE; - mCallbacks->handleActivate(this, false); - // result = noErr; - break; - - case kEventWindowShown: - // llinfos << "LLWindowMacOSX: Activating on show" << llendl; - mMinimized = FALSE; - mCallbacks->handleActivate(this, true); - // result = noErr; - break; - - case kEventWindowCollapsed: - // llinfos << "LLWindowMacOSX: Deactivating on collapse" << llendl; - mMinimized = TRUE; - mCallbacks->handleActivate(this, false); - // result = noErr; - break; - - case kEventWindowExpanded: - // llinfos << "LLWindowMacOSX: Activating on expand" << llendl; - mMinimized = FALSE; - mCallbacks->handleActivate(this, true); - // result = noErr; - break; - - case kEventWindowGetClickActivation: - // BringToFront(mWindow); - // result = noErr; - break; - } - break; + return(convertCoords(from, &window_coord) && convertCoords(window_coord, to)); +} - case kEventClassTSMDocumentAccess: - if (mPreeditor) - { - switch(evtKind) - { +BOOL LLWindowMacOSX::convertCoords(LLCoordGL from, LLCoordScreen *to) +{ + LLCoordWindow window_coord; - case kEventTSMDocumentAccessGetLength: - { - // Return the number of UTF-16 units in the text, excluding those for preedit. - - S32 preedit, preedit_length; - mPreeditor->getPreeditRange(&preedit, &preedit_length); - const LLWString & text = mPreeditor->getPreeditString(); - const CFIndex length = wstring_utf16_length(text, 0, preedit) - + wstring_utf16_length(text, preedit + preedit_length, text.length()); - result = SetEventParameter(event, kEventParamTSMDocAccessCharacterCount, typeCFIndex, sizeof(length), &length); - } - break; + return(convertCoords(from, &window_coord) && convertCoords(window_coord, to)); +} - case kEventTSMDocumentAccessGetSelectedRange: - { - // Return the selected range, excluding preedit. - // In our preeditor, preedit and selection are exclusive, so, - // when it has a preedit, there is no selection and the - // insertion point is on the preedit that corrupses into the - // beginning of the preedit when the preedit was removed. - - S32 preedit, preedit_length; - mPreeditor->getPreeditRange(&preedit, &preedit_length); - const LLWString & text = mPreeditor->getPreeditString(); - - CFRange range; - if (preedit_length) - { - range.location = wstring_utf16_length(text, 0, preedit); - range.length = 0; - } - else - { - S32 selection, selection_length; - mPreeditor->getSelectionRange(&selection, &selection_length); - range.location = wstring_utf16_length(text, 0, selection); - range.length = wstring_utf16_length(text, selection, selection_length); - } - result = SetEventParameter(event, kEventParamTSMDocAccessReplyCharacterRange, typeCFRange, sizeof(range), &range); - } - break; - case kEventTSMDocumentAccessGetCharacters: - { - UniChar *target_pointer; - CFRange range; - EventParamType param_type; - if ((result = GetEventParameter(event, kEventParamTSMDocAccessSendCharacterRange, - typeCFRange, ¶m_type, sizeof(range), NULL, &range)) == noErr - && typeCFRange == param_type - && (result = GetEventParameter(event, kEventParamTSMDocAccessSendCharactersPtr, - typePtr, ¶m_type, sizeof(target_pointer), NULL, &target_pointer)) == noErr - && typePtr == param_type) - { - S32 preedit, preedit_length; - mPreeditor->getPreeditRange(&preedit, &preedit_length); - const LLWString & text = mPreeditor->getPreeditString(); - - // The GetCharacters event of TSMDA has a fundamental flaw; - // An input method need to decide the starting offset and length - // *before* it actually see the contents, so it is impossible - // to guarantee the character-aligned access. The event reply - // has no way to indicate a condition something like "Request - // was not fulfilled due to unaligned access. Please retry." - // Any error sent back to the input method stops use of TSMDA - // entirely during the session... - // We need to simulate very strictly the behaviour as if the - // underlying *text engine* holds the contents in UTF-16. - // I guess this is the reason why Apple repeats saying "all - // text handling application should use UTF-16." They are - // trying to _fix_ the flaw by changing the appliations... - // ... or, domination of UTF-16 in the industry may be a part - // of the company vision, and Apple is trying to force third - // party developers to obey their vision. Remember that use - // of 16 bits per _a_character_ was one of the very fundamental - // Unicode design policy on its early days (during late 80s) - // and the original Unicode design was by two Apple employees... - - const llutf16string text_utf16 - = wstring_to_utf16str(text, preedit) - + wstring_to_utf16str(text.substr(preedit + preedit_length)); - - llassert_always(sizeof(U16) == sizeof(UniChar)); - llassert(0 <= range.location && 0 <= range.length && range.location + range.length <= text_utf16.length()); - memcpy(target_pointer, text_utf16.c_str() + range.location, range.length * sizeof(UniChar)); - - // Note that result has already been set above. - } - } - break; - } - } - break; - } - return result; +void LLWindowMacOSX::setupFailure(const std::string& text, const std::string& caption, U32 type) +{ + destroyContext(); + + OSMessageBox(text, caption, type); } + // Note on event recording - QUIT is a known special case and we are choosing NOT to record it for the record and playback feature + // it is handled at a very low-level const char* cursorIDToName(int id) { switch (id) @@ -2844,11 +1420,17 @@ const char* cursorIDToName(int id) case UI_CURSOR_PIPETTE: return "UI_CURSOR_PIPETTE"; case UI_CURSOR_TOOLSIT: return "UI_CURSOR_TOOLSIT"; case UI_CURSOR_TOOLBUY: return "UI_CURSOR_TOOLBUY"; - case UI_CURSOR_TOOLOPEN: return "UI_CURSOR_TOOLOPEN"; case UI_CURSOR_TOOLPAY: return "UI_CURSOR_TOOLPAY"; + case UI_CURSOR_TOOLOPEN: return "UI_CURSOR_TOOLOPEN"; + /*case UI_CURSOR_TOOLPATHFINDING: return "UI_CURSOR_PATHFINDING"; + case UI_CURSOR_TOOLPATHFINDING_PATH_START: return "UI_CURSOR_PATHFINDING_START"; + case UI_CURSOR_TOOLPATHFINDING_PATH_START_ADD: return "UI_CURSOR_PATHFINDING_START_ADD"; + case UI_CURSOR_TOOLPATHFINDING_PATH_END: return "UI_CURSOR_PATHFINDING_END"; + case UI_CURSOR_TOOLPATHFINDING_PATH_END_ADD: return "UI_CURSOR_PATHFINDING_END_ADD"; + case UI_CURSOR_TOOLNO: return "UI_CURSOR_NO";*/ } - llerrs << "cursorIDToName: unknown cursor id" << id << llendl; + LL_ERRS() << "cursorIDToName: unknown cursor id" << id << LL_ENDL; return "UI_CURSOR_ARROW"; } @@ -2871,7 +1453,7 @@ static void initPixmapCursor(int cursorid, int hotspotX, int hotspotY) void LLWindowMacOSX::updateCursor() { - OSStatus result = noErr; + S32 result = 0; if (mDragOverrideCursor != -1) { @@ -2887,8 +1469,10 @@ void LLWindowMacOSX::updateCursor() mNextCursor = UI_CURSOR_WORKING; } - if(mCurrentCursor == mNextCursor) - return; + if(mCurrentCursor == mNextCursor) + { + return; + } // RN: replace multi-drag cursors with single versions if (mNextCursor == UI_CURSOR_ARROWDRAGMULTI) @@ -2904,11 +1488,11 @@ void LLWindowMacOSX::updateCursor() { default: case UI_CURSOR_ARROW: - InitCursor(); + setArrowCursor(); if(mCursorHidden) { // Since InitCursor resets the hide level, correct for it here. - ::HideCursor(); + hideNSCursor(); } break; @@ -2916,12 +1500,12 @@ void LLWindowMacOSX::updateCursor() // Find out what they look like and replicate them. // These are essentially correct - case UI_CURSOR_WAIT: SetThemeCursor(kThemeWatchCursor); break; - case UI_CURSOR_IBEAM: SetThemeCursor(kThemeIBeamCursor); break; - case UI_CURSOR_CROSS: SetThemeCursor(kThemeCrossCursor); break; - case UI_CURSOR_HAND: SetThemeCursor(kThemePointingHandCursor); break; + case UI_CURSOR_WAIT: /* Apple purposely doesn't allow us to set the beachball cursor manually. Let NSApp figure out when to do this. */ break; + case UI_CURSOR_IBEAM: setIBeamCursor(); break; + case UI_CURSOR_CROSS: setCrossCursor(); break; + case UI_CURSOR_HAND: setPointingHandCursor(); break; // case UI_CURSOR_NO: SetThemeCursor(kThemeNotAllowedCursor); break; - case UI_CURSOR_ARROWCOPY: SetThemeCursor(kThemeCopyArrowCursor); break; + case UI_CURSOR_ARROWCOPY: setCopyCursor(); break; // Double-check these case UI_CURSOR_NO: @@ -2938,6 +1522,7 @@ void LLWindowMacOSX::updateCursor() case UI_CURSOR_NOLOCKED: case UI_CURSOR_ARROWLOCKED: case UI_CURSOR_GRABLOCKED: + case UI_CURSOR_PIPETTE: case UI_CURSOR_TOOLTRANSLATE: case UI_CURSOR_TOOLROTATE: case UI_CURSOR_TOOLSCALE: @@ -2950,8 +1535,14 @@ void LLWindowMacOSX::updateCursor() case UI_CURSOR_TOOLMEDIAOPEN: case UI_CURSOR_TOOLSIT: case UI_CURSOR_TOOLBUY: - case UI_CURSOR_TOOLOPEN: case UI_CURSOR_TOOLPAY: + case UI_CURSOR_TOOLOPEN: + /*case UI_CURSOR_TOOLPATHFINDING: + case UI_CURSOR_TOOLPATHFINDING_PATH_START: + case UI_CURSOR_TOOLPATHFINDING_PATH_START_ADD: + case UI_CURSOR_TOOLPATHFINDING_PATH_END: + case UI_CURSOR_TOOLPATHFINDING_PATH_END_ADD: + case UI_CURSOR_TOOLNO:*/ result = setImageCursor(gCursors[mNextCursor]); break; @@ -2959,7 +1550,7 @@ void LLWindowMacOSX::updateCursor() if(result != noErr) { - InitCursor(); + setArrowCursor(); } mCurrentCursor = mNextCursor; @@ -2983,6 +1574,7 @@ void LLWindowMacOSX::initCursors() initPixmapCursor(UI_CURSOR_NOLOCKED, 8, 8); initPixmapCursor(UI_CURSOR_ARROWLOCKED, 1, 1); initPixmapCursor(UI_CURSOR_GRABLOCKED, 2, 14); + initPixmapCursor(UI_CURSOR_PIPETTE, 3, 29); initPixmapCursor(UI_CURSOR_TOOLTRANSLATE, 1, 1); initPixmapCursor(UI_CURSOR_TOOLROTATE, 1, 1); initPixmapCursor(UI_CURSOR_TOOLSCALE, 1, 1); @@ -2995,8 +1587,14 @@ void LLWindowMacOSX::initCursors() initPixmapCursor(UI_CURSOR_TOOLMEDIAOPEN, 1, 1); initPixmapCursor(UI_CURSOR_TOOLSIT, 20, 15); initPixmapCursor(UI_CURSOR_TOOLBUY, 20, 15); + initPixmapCursor(UI_CURSOR_TOOLPAY, 20, 15); initPixmapCursor(UI_CURSOR_TOOLOPEN, 20, 15); - initPixmapCursor(UI_CURSOR_TOOLPAY, 1, 1); + /*initPixmapCursor(UI_CURSOR_TOOLPATHFINDING, 16, 16); + initPixmapCursor(UI_CURSOR_TOOLPATHFINDING_PATH_START, 16, 16); + initPixmapCursor(UI_CURSOR_TOOLPATHFINDING_PATH_START_ADD, 16, 16); + initPixmapCursor(UI_CURSOR_TOOLPATHFINDING_PATH_END, 16, 16); + initPixmapCursor(UI_CURSOR_TOOLPATHFINDING_PATH_END_ADD, 16, 16); + initPixmapCursor(UI_CURSOR_TOOLNO, 8, 8);*/ initPixmapCursor(UI_CURSOR_SIZENWSE, 10, 10); initPixmapCursor(UI_CURSOR_SIZENESW, 10, 10); @@ -3021,14 +1619,14 @@ void LLWindowMacOSX::hideCursor() { if(!mCursorHidden) { - // llinfos << "hideCursor: hiding" << llendl; + // LL_INFOS() << "hideCursor: hiding" << LL_ENDL; mCursorHidden = TRUE; mHideCursorPermanent = TRUE; - ::HideCursor(); + hideNSCursor(); } else { - // llinfos << "hideCursor: already hidden" << llendl; + // LL_INFOS() << "hideCursor: already hidden" << LL_ENDL; } adjustCursorDecouple(); @@ -3038,14 +1636,14 @@ void LLWindowMacOSX::showCursor() { if(mCursorHidden) { - // llinfos << "showCursor: showing" << llendl; + // LL_INFOS() << "showCursor: showing" << LL_ENDL; mCursorHidden = FALSE; mHideCursorPermanent = FALSE; - ::ShowCursor(); + showNSCursor(); } else { - // llinfos << "showCursor: already visible" << llendl; + // LL_INFOS() << "showCursor: already visible" << LL_ENDL; } adjustCursorDecouple(); @@ -3085,53 +1683,18 @@ LLSplashScreenMacOSX::~LLSplashScreenMacOSX() void LLSplashScreenMacOSX::showImpl() { // This code _could_ be used to display a spash screen... -#if 0 - IBNibRef nib = NULL; - OSStatus err; - - err = CreateNibReference(CFSTR("SecondLife"), &nib); - - if(err == noErr) - { - CreateWindowFromNib(nib, CFSTR("Splash Screen"), &mWindow); - - DisposeNibReference(nib); - } - - if(mWindow != NULL) - { - ShowWindow(mWindow); - } -#endif } void LLSplashScreenMacOSX::updateImpl(const std::string& mesg) { +#if 0 if(mWindow != NULL) { CFStringRef string = NULL; string = CFStringCreateWithCString(NULL, mesg.c_str(), kCFStringEncodingUTF8); - - if(string != NULL) - { - ControlRef progressText = NULL; - ControlID id; - OSStatus err; - - id.signature = 'what'; - id.id = 0; - - err = GetControlByID(mWindow, &id, &progressText); - if(err == noErr) - { - err = SetControlData(progressText, kControlEntireControl, kControlStaticTextCFStringTag, sizeof(CFStringRef), (Ptr)&string); - Draw1Control(progressText); - } - - CFRelease(string); - } } +#endif } @@ -3139,132 +1702,30 @@ void LLSplashScreenMacOSX::hideImpl() { if(mWindow != NULL) { - DisposeWindow(mWindow); mWindow = NULL; } } - - S32 OSMessageBoxMacOSX(const std::string& text, const std::string& caption, U32 type) { - S32 result = OSBTN_CANCEL; - SInt16 retval_mac = 1; - AlertStdCFStringAlertParamRec params; - CFStringRef errorString = NULL; - CFStringRef explanationString = NULL; - DialogRef alert = NULL; - AlertType alertType = kAlertCautionAlert; - OSStatus err; - - explanationString = CFStringCreateWithCString(NULL, text.c_str(), kCFStringEncodingUTF8); - errorString = CFStringCreateWithCString(NULL, caption.c_str(), kCFStringEncodingUTF8); - - params.version = kStdCFStringAlertVersionOne; - params.movable = false; - params.helpButton = false; - params.defaultText = (CFStringRef)kAlertDefaultOKText; - params.cancelText = 0; - params.otherText = 0; - params.defaultButton = 1; - params.cancelButton = 0; - params.position = kWindowDefaultPosition; - params.flags = 0; - - switch(type) - { - case OSMB_OK: - default: - break; - case OSMB_OKCANCEL: - params.cancelText = (CFStringRef)kAlertDefaultCancelText; - params.cancelButton = 2; - break; - case OSMB_YESNO: - alertType = kAlertNoteAlert; - params.defaultText = CFSTR("Yes"); - params.cancelText = CFSTR("No"); - params.cancelButton = 2; - break; - } - - if(gWindowImplementation != NULL) - gWindowImplementation->beforeDialog(); - - err = CreateStandardAlert( - alertType, - errorString, - explanationString, - ¶ms, - &alert); - - if(err == noErr) - { - err = RunStandardAlert( - alert, - NULL, - &retval_mac); - } - - if(gWindowImplementation != NULL) - gWindowImplementation->afterDialog(); - - switch(type) - { - case OSMB_OK: - case OSMB_OKCANCEL: - default: - if(retval_mac == 1) - result = OSBTN_OK; - else - result = OSBTN_CANCEL; - break; - case OSMB_YESNO: - if(retval_mac == 1) - result = OSBTN_YES; - else - result = OSBTN_NO; - break; - } - - if(errorString != NULL) - { - CFRelease(errorString); - } - - if(explanationString != NULL) - { - CFRelease(explanationString); - } - - return result; + return showAlert(text, caption, type); } // Open a URL with the user's default web browser. // Must begin with protocol identifier. void LLWindowMacOSX::spawnWebBrowser(const std::string& escaped_url, bool async) { - bool found = false; - S32 i; - for (i = 0; i < gURLProtocolWhitelistCount; i++) - { - if (escaped_url.find(gURLProtocolWhitelist[i]) != std::string::npos) - { - found = true; - break; - } - } - - if (!found) + // I'm fairly certain that this is all legitimate under Apple's currently supported APIs. + if (!isWhitelistedProtocol(escaped_url)) { - llwarns << "spawn_web_browser called for url with protocol not on whitelist: " << escaped_url << llendl; + LL_WARNS() << "spawn_web_browser called for url with protocol not on whitelist: " << escaped_url << LL_ENDL; return; } - OSStatus result = noErr; + S32 result = 0; CFURLRef urlRef = NULL; - llinfos << "Opening URL " << escaped_url << llendl; + LL_INFOS() << "Opening URL " << escaped_url << LL_ENDL; CFStringRef stringRef = CFStringCreateWithCString(NULL, escaped_url.c_str(), kCFStringEncodingUTF8); if (stringRef) @@ -3284,101 +1745,50 @@ void LLWindowMacOSX::spawnWebBrowser(const std::string& escaped_url, bool async) if (result != noErr) { - llinfos << "Error " << result << " on open." << llendl; + LL_INFOS() << "Error " << result << " on open." << LL_ENDL; } CFRelease(urlRef); } else { - llinfos << "Error: couldn't create URL." << llendl; + LL_INFOS() << "Error: couldn't create URL." << LL_ENDL; } } -void LLWindowMacOSX::setTitle(const std::string &title) -{ - /*strncpy((char*)mWindowTitle + 1, title.c_str(), 253); - mWindowTitle[0] = title.length();*/ - - CFStringRef title_str = CFStringCreateWithCString(NULL, title.c_str(), kCFStringEncodingUTF8); - SetWindowTitleWithCFString(mWindow, title_str); -} - LLSD LLWindowMacOSX::getNativeKeyData() { LLSD result = LLSD::emptyMap(); if(mRawKeyEvent) { - char char_code = 0; - UInt32 key_code = 0; - UInt32 modifiers = 0; - UInt32 keyboard_type = 0; - - GetEventParameter (mRawKeyEvent, kEventParamKeyMacCharCodes, typeChar, NULL, sizeof(char), NULL, &char_code); - GetEventParameter (mRawKeyEvent, kEventParamKeyCode, typeUInt32, NULL, sizeof(UInt32), NULL, &key_code); - GetEventParameter (mRawKeyEvent, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers); - GetEventParameter (mRawKeyEvent, kEventParamKeyboardType, typeUInt32, NULL, sizeof(UInt32), NULL, &keyboard_type); - - result["char_code"] = (S32)char_code; - result["key_code"] = (S32)key_code; - result["modifiers"] = (S32)modifiers; - result["keyboard_type"] = (S32)keyboard_type; - -#if 0 - // This causes trouble for control characters -- apparently character codes less than 32 (escape, control-A, etc) - // cause llsd serialization to create XML that the llsd deserializer won't parse! - std::string unicode; - OSStatus err = noErr; - EventParamType actualType = typeUTF8Text; - UInt32 actualSize = 0; - char *buffer = NULL; - - err = GetEventParameter (mRawKeyEvent, kEventParamKeyUnicodes, typeUTF8Text, &actualType, 0, &actualSize, NULL); - if(err == noErr) - { - // allocate a buffer and get the actual data. - buffer = new char[actualSize]; - err = GetEventParameter (mRawKeyEvent, kEventParamKeyUnicodes, typeUTF8Text, &actualType, actualSize, &actualSize, buffer); - if(err == noErr) - { - unicode.assign(buffer, actualSize); - } - delete[] buffer; - } - - result["unicode"] = unicode; -#endif - + result["event_type"] = LLSD::Integer(mRawKeyEvent->mEventType); + result["event_modifiers"] = LLSD::Integer(mRawKeyEvent->mEventModifiers); + result["event_keycode"] = LLSD::Integer(mRawKeyEvent->mEventKeyCode); + result["event_chars"] = (mRawKeyEvent->mEventChars) ? LLSD(LLSD::Integer(mRawKeyEvent->mEventChars)) : LLSD(); + result["event_umodchars"] = (mRawKeyEvent->mEventUnmodChars) ? LLSD(LLSD::Integer(mRawKeyEvent->mEventUnmodChars)) : LLSD(); + result["event_isrepeat"] = LLSD::Boolean(mRawKeyEvent->mEventRepeat); } - - lldebugs << "native key data is: " << result << llendl; + LL_DEBUGS() << "native key data is: " << result << LL_ENDL; return result; } - BOOL LLWindowMacOSX::dialogColorPicker( F32 *r, F32 *g, F32 *b) { BOOL retval = FALSE; OSErr error = noErr; NColorPickerInfo info; - + memset(&info, 0, sizeof(info)); info.theColor.color.rgb.red = (UInt16)(*r * 65535.f); info.theColor.color.rgb.green = (UInt16)(*g * 65535.f); info.theColor.color.rgb.blue = (UInt16)(*b * 65535.f); info.placeWhere = kCenterOnMainScreen; - if(gWindowImplementation != NULL) - gWindowImplementation->beforeDialog(); - error = NPickColor(&info); - - if(gWindowImplementation != NULL) - gWindowImplementation->afterDialog(); - + if (error == noErr) { retval = info.newColorChosen; @@ -3389,54 +1799,18 @@ BOOL LLWindowMacOSX::dialogColorPicker( F32 *r, F32 *g, F32 *b) *b = ((float) info.theColor.color.rgb.blue) / 65535.0; } } + return (retval); } - void *LLWindowMacOSX::getPlatformWindow() { // NOTE: this will be NULL in fullscreen mode. Plan accordingly. return (void*)mWindow; } -void *LLWindowMacOSX::getMediaWindow() -{ - /* - Mozilla needs to be initialized with a WindowRef to function properly. - (There's no good reason for this, since it shouldn't be interacting with our window in any way, but that's another issue.) - If we're in windowed mode, we _could_ hand it our actual window pointer, but a subsequent switch to fullscreen will destroy that window, - which trips up Mozilla. - Instead of using our actual window, we create an invisible window which will persist for the lifetime of the application and pass that to Mozilla. - This satisfies its deep-seated need to latch onto a WindowRef and solves the issue with switching between fullscreen and windowed modes. - - Note that we will never destroy this window (by design!), but since only one will ever be created per run of the application, that's okay. - */ - - if(sMediaWindow == NULL) - { - Rect window_rect = {100, 100, 200, 200}; - - sMediaWindow = NewCWindow( - NULL, - &window_rect, - (ConstStr255Param) "\p", - false, // Create the window invisible. - zoomDocProc, // Window with a grow box and a zoom box - kLastWindowOfClass, // create it behind other windows - false, // no close box - 0); - } - - return (void*)sMediaWindow; -} - -void LLWindowMacOSX::stopDockTileBounce() -{ - NMRemove(&mBounceRec); - mBounceTimer.stop(); -} - // get a double value from a dictionary +/* static double getDictDouble (CFDictionaryRef refDict, CFStringRef key) { double double_value; @@ -3446,7 +1820,7 @@ static double getDictDouble (CFDictionaryRef refDict, CFStringRef key) if (!CFNumberGetValue(number_value, kCFNumberDoubleType, &double_value)) // or if cant convert it return -1; // fail return double_value; // otherwise return the long value -} +}*/ // get a long value from a dictionary static long getDictLong (CFDictionaryRef refDict, CFStringRef key) @@ -3462,8 +1836,6 @@ static long getDictLong (CFDictionaryRef refDict, CFStringRef key) void LLWindowMacOSX::allowLanguageTextInput(LLPreeditor *preeditor, BOOL b) { - ScriptLanguageRecord script_language; - if (preeditor != mPreeditor && !b) { // This condition may occur by a call to @@ -3474,9 +1846,7 @@ void LLWindowMacOSX::allowLanguageTextInput(LLPreeditor *preeditor, BOOL b) // is not disturbed. return; } - - UseInputWindow(mTSMDocument, !b); - + // Take care of old and new preeditors. if (preeditor != mPreeditor || !b) { @@ -3489,44 +1859,18 @@ void LLWindowMacOSX::allowLanguageTextInput(LLPreeditor *preeditor, BOOL b) } mPreeditor = (b ? preeditor : NULL); } - + if (b == mLanguageTextInputAllowed) { return; } mLanguageTextInputAllowed = b; - - if (b) - { - if (mTSMScriptCode != smRoman) - { - script_language.fScript = mTSMScriptCode; - script_language.fLanguage = mTSMLangCode; - SetTextServiceLanguage(&script_language); - } - } - else - { - GetTextServiceLanguage(&script_language); - mTSMScriptCode = script_language.fScript; - mTSMLangCode = script_language.fLanguage; - if (mTSMScriptCode != smRoman) - { - script_language.fScript = smRoman; - script_language.fLanguage = langEnglish; - SetTextServiceLanguage(&script_language); - } - } + allowDirectMarkedTextInput(b, mGLView); // mLanguageTextInputAllowed and mMarkedTextAllowed should be updated at once (by Pell Smit } void LLWindowMacOSX::interruptLanguageTextInput() { - if (mTSMDocument) - { - FixTSMDocument(mTSMDocument); - } - // Don't we need to call resetPreedit here? - // Well, if Apple's TSM document is correct, we don't. + commitCurrentPreedit(mGLView); } //static @@ -3537,24 +1881,35 @@ std::vector LLWindowMacOSX::getDynamicFallbackFontList() } // static -MASK LLWindowMacOSX::modifiersToMask(SInt16 modifiers) +MASK LLWindowMacOSX::modifiersToMask(S16 modifiers) { MASK mask = 0; - if(modifiers & shiftKey) { mask |= MASK_SHIFT; } - if(modifiers & (cmdKey | controlKey)) { mask |= MASK_CONTROL; } - if(modifiers & optionKey) { mask |= MASK_ALT; } + if(modifiers & MAC_SHIFT_KEY) { mask |= MASK_SHIFT; } + if(modifiers & (MAC_CMD_KEY | MAC_CTRL_KEY)) { mask |= MASK_CONTROL; } + if(modifiers & MAC_ALT_KEY) { mask |= MASK_ALT; } return mask; } -#if LL_OS_DRAGDROP_ENABLED +//[CR:Retina] +F32 LLWindowMacOSX::getScaleFactor() +{ + return ::getScaleFactor(mGLView); +} + +void LLWindowMacOSX::updateUnreadCount(S32 num_conversations) +{ + updateBadge(num_conversations); +} -OSErr LLWindowMacOSX::dragTrackingHandler(DragTrackingMessage message, WindowRef theWindow, +#if LL_OS_DRAGDROP_ENABLED +/* +S16 LLWindowMacOSX::dragTrackingHandler(DragTrackingMessage message, WindowRef theWindow, void * handlerRefCon, DragRef drag) { - OSErr result = noErr; + S16 result = 0; LLWindowMacOSX *self = (LLWindowMacOSX*)handlerRefCon; - lldebugs << "drag tracking handler, message = " << message << llendl; + LL_DEBUGS() << "drag tracking handler, message = " << message << LL_ENDL; switch(message) { @@ -3576,7 +1931,6 @@ OSErr LLWindowMacOSX::dragTrackingHandler(DragTrackingMessage message, WindowRef return result; } - OSErr LLWindowMacOSX::dragReceiveHandler(WindowRef theWindow, void * handlerRefCon, DragRef drag) { @@ -3584,126 +1938,69 @@ OSErr LLWindowMacOSX::dragReceiveHandler(WindowRef theWindow, void * handlerRefC return self->handleDragNDrop(drag, LLWindowCallbacks::DNDA_DROPPED); } - -OSErr LLWindowMacOSX::handleDragNDrop(DragRef drag, LLWindowCallbacks::DragNDropAction action) +*/ +void LLWindowMacOSX::handleDragNDrop(std::string url, LLWindowCallbacks::DragNDropAction action) { - OSErr result = dragNotAcceptedErr; // overall function result - OSErr err = noErr; // for local error handling + MASK mask = LLWindowMacOSX::modifiersToMask(getModifiers()); - // Get the mouse position and modifiers of this drag. - SInt16 modifiers, mouseDownModifiers, mouseUpModifiers; - ::GetDragModifiers(drag, &modifiers, &mouseDownModifiers, &mouseUpModifiers); - MASK mask = LLWindowMacOSX::modifiersToMask(modifiers); - - Point mouse_point; - // This will return the mouse point in global screen coords - ::GetDragMouse(drag, &mouse_point, NULL); - LLCoordScreen screen_coords(mouse_point.h, mouse_point.v); + float mouse_point[2]; + // This will return the mouse point in window coords + getCursorPos(mWindow, mouse_point); + LLCoordWindow window_coords(mouse_point[0], mouse_point[1]); LLCoordGL gl_pos; - convertCoords(screen_coords, &gl_pos); - - // Look at the pasteboard and try to extract an URL from it - PasteboardRef pasteboard; - if(GetDragPasteboard(drag, &pasteboard) == noErr) + convertCoords(window_coords, &gl_pos); + + if(!url.empty()) { - ItemCount num_items = 0; - // Treat an error here as an item count of 0 - (void)PasteboardGetItemCount(pasteboard, &num_items); - - // Only deal with single-item drags. - if(num_items == 1) - { - PasteboardItemID item_id = NULL; - CFArrayRef flavors = NULL; - CFDataRef data = NULL; - - err = PasteboardGetItemIdentifier(pasteboard, 1, &item_id); // Yes, this really is 1-based. - - // Try to extract an URL from the pasteboard - if(err == noErr) - { - err = PasteboardCopyItemFlavors( pasteboard, item_id, &flavors); - } - - if(err == noErr) - { - if(CFArrayContainsValue(flavors, CFRangeMake(0, CFArrayGetCount(flavors)), kUTTypeURL)) - { - // This is an URL. - err = PasteboardCopyItemFlavorData(pasteboard, item_id, kUTTypeURL, &data); - } - else if(CFArrayContainsValue(flavors, CFRangeMake(0, CFArrayGetCount(flavors)), kUTTypeUTF8PlainText)) + LLWindowCallbacks::DragNDropResult res = + mCallbacks->handleDragNDrop(this, gl_pos, mask, action, url); + + switch (res) { + case LLWindowCallbacks::DND_NONE: // No drop allowed + if (action == LLWindowCallbacks::DNDA_TRACK) { - // This is a string that might be an URL. - err = PasteboardCopyItemFlavorData(pasteboard, item_id, kUTTypeUTF8PlainText, &data); + mDragOverrideCursor = 0; } - - } - - if(flavors != NULL) - { - CFRelease(flavors); - } - - if(data != NULL) - { - std::string url; - url.assign((char*)CFDataGetBytePtr(data), CFDataGetLength(data)); - CFRelease(data); - - if(!url.empty()) - { - LLWindowCallbacks::DragNDropResult res = - mCallbacks->handleDragNDrop(this, gl_pos, mask, action, url); - - switch (res) { - case LLWindowCallbacks::DND_NONE: // No drop allowed - if (action == LLWindowCallbacks::DNDA_TRACK) - { - mDragOverrideCursor = kThemeNotAllowedCursor; - } - else { - mDragOverrideCursor = -1; - } - break; - case LLWindowCallbacks::DND_MOVE: // Drop accepted would result in a "move" operation - mDragOverrideCursor = kThemePointingHandCursor; - result = noErr; - break; - case LLWindowCallbacks::DND_COPY: // Drop accepted would result in a "copy" operation - mDragOverrideCursor = kThemeCopyArrowCursor; - result = noErr; - break; - case LLWindowCallbacks::DND_LINK: // Drop accepted would result in a "link" operation: - mDragOverrideCursor = kThemeAliasArrowCursor; - result = noErr; - break; - default: - mDragOverrideCursor = -1; - break; - } - // This overrides the cursor being set by setCursor. - // This is a bit of a hack workaround because lots of areas - // within the viewer just blindly set the cursor. - if (mDragOverrideCursor == -1) - { - // Restore the cursor - ECursorType temp_cursor = mCurrentCursor; - // get around the "setting the same cursor" code in setCursor() - mCurrentCursor = UI_CURSOR_COUNT; - setCursor(temp_cursor); - } - else { - // Override the cursor - SetThemeCursor(mDragOverrideCursor); - } - + else { + mDragOverrideCursor = -1; } - } + break; + case LLWindowCallbacks::DND_MOVE: // Drop accepted would result in a "move" operation + mDragOverrideCursor = UI_CURSOR_NO; + break; + case LLWindowCallbacks::DND_COPY: // Drop accepted would result in a "copy" operation + mDragOverrideCursor = UI_CURSOR_ARROWCOPY; + break; + default: + mDragOverrideCursor = -1; + break; + } + // This overrides the cursor being set by setCursor. + // This is a bit of a hack workaround because lots of areas + // within the viewer just blindly set the cursor. + if (mDragOverrideCursor == -1) + { + // Restore the cursor + ECursorType temp_cursor = mCurrentCursor; + // get around the "setting the same cursor" code in setCursor() + mCurrentCursor = UI_CURSOR_COUNT; + setCursor(temp_cursor); + } + else { + // Override the cursor + switch (mDragOverrideCursor) { + case 0: + setArrowCursor(); + break; + case UI_CURSOR_NO: + setNotAllowedCursor(); + case UI_CURSOR_ARROWCOPY: + setCopyCursor(); + default: + break; + }; } } - - return result; } #endif // LL_OS_DRAGDROP_ENABLED diff --git a/indra/llwindow/llwindowmacosx.h b/indra/llwindow/llwindowmacosx.h index 3f75dc9abd..581a445634 100644 --- a/indra/llwindow/llwindowmacosx.h +++ b/indra/llwindow/llwindowmacosx.h @@ -29,22 +29,23 @@ #include "llwindow.h" #include "llwindowcallbacks.h" +#include "llwindowmacosx-objc.h" #include "lltimer.h" -#include -#include +#include +#include // AssertMacros.h does bad things. +#include "fix_macros.h" #undef verify -#undef check #undef require class LLWindowMacOSX : public LLWindow { public: - /*virtual*/ void show(); + /*virtual*/ void show(bool focus = true); /*virtual*/ void hide(); /*virtual*/ void close(); /*virtual*/ BOOL getVisible(); @@ -60,7 +61,7 @@ class LLWindowMacOSX : public LLWindow /*virtual*/ BOOL setPosition(LLCoordScreen position); /*virtual*/ BOOL setSizeImpl(LLCoordScreen size); /*virtual*/ BOOL setSizeImpl(LLCoordWindow size); - /*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp = NULL); + /*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, const S32 vsync_mode, std::function stopFn, std::function restoreFn, const LLCoordScreen * const posp = nullptr); /*virtual*/ BOOL setCursorPosition(LLCoordWindow position); /*virtual*/ BOOL getCursorPosition(LLCoordWindow *position); /*virtual*/ void showCursor(); @@ -76,6 +77,7 @@ class LLWindowMacOSX : public LLWindow /*virtual*/ BOOL isClipboardTextAvailable(); /*virtual*/ BOOL pasteTextFromClipboard(LLWString &dst); /*virtual*/ BOOL copyTextToClipboard(const LLWString & src); + /*virtual*/ void setWindowTitle(const std::string& title); /*virtual*/ void flashIcon(F32 seconds); /*virtual*/ F32 getGamma(); /*virtual*/ BOOL setGamma(const F32 gamma); // Set the gamma @@ -86,7 +88,7 @@ class LLWindowMacOSX : public LLWindow /*virtual*/ void gatherInput(); /*virtual*/ void delayInputProcessing() {}; /*virtual*/ void swapBuffers(); - + // handy coordinate space conversion routines /*virtual*/ BOOL convertCoords(LLCoordScreen from, LLCoordWindow *to); /*virtual*/ BOOL convertCoords(LLCoordWindow from, LLCoordScreen *to); @@ -106,25 +108,34 @@ class LLWindowMacOSX : public LLWindow /*virtual*/ BOOL dialogColorPicker(F32 *r, F32 *g, F32 *b); /*virtual*/ void *getPlatformWindow(); - /*virtual*/ void *getMediaWindow(); /*virtual*/ void bringToFront() {}; /*virtual*/ void allowLanguageTextInput(LLPreeditor *preeditor, BOOL b); /*virtual*/ void interruptLanguageTextInput(); /*virtual*/ void spawnWebBrowser(const std::string& escaped_url, bool async); - - /*virtual*/ void setTitle(const std::string &title); + /*virtual*/ F32 getScaleFactor(); + /*virtual*/ void updateUnreadCount(S32 num_conversations); static std::vector getDynamicFallbackFontList(); // Provide native key event data /*virtual*/ LLSD getNativeKeyData(); - + + void* getWindow() { return mWindow; } + LLWindowCallbacks* getCallbacks() { return mCallbacks; } + LLPreeditor* getPreeditor() { return mPreeditor; } + + void updateMouseDeltas(double* deltas); + void getMouseDeltas(S32* delta); + + void handleDragNDrop(std::string url, LLWindowCallbacks::DragNDropAction action); + + bool allowsLanguageInput() { return mLanguageTextInputAllowed; } protected: LLWindowMacOSX(LLWindowCallbacks* callbacks, const std::string& title, const std::string& name, int x, int y, int width, int height, U32 flags, - BOOL fullscreen, BOOL clearBg, BOOL disable_vsync, + BOOL fullscreen, BOOL clearBg, S32 vsync_setting, BOOL ignore_pixel_depth, U32 fsaa_samples); ~LLWindowMacOSX(); @@ -145,6 +156,8 @@ class LLWindowMacOSX : public LLWindow BOOL shouldPostQuit() { return mPostQuit; } +private: + void restoreGLContext(); protected: // @@ -152,43 +165,36 @@ class LLWindowMacOSX : public LLWindow // // create or re-create the GL context/window. Called from the constructor and switchContext(). - BOOL createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, BOOL disable_vsync); + BOOL createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, S32 vsync_setting); void destroyContext(); void setupFailure(const std::string& text, const std::string& caption, U32 type); - static pascal OSStatus staticEventHandler (EventHandlerCallRef myHandler, EventRef event, void* userData); - static pascal Boolean staticMoveEventComparator( EventRef event, void* data); - OSStatus eventHandler (EventHandlerCallRef myHandler, EventRef event); void adjustCursorDecouple(bool warpingMouse = false); - void stopDockTileBounce(); - static MASK modifiersToMask(SInt16 modifiers); + static MASK modifiersToMask(S16 modifiers); #if LL_OS_DRAGDROP_ENABLED - static OSErr dragTrackingHandler(DragTrackingMessage message, WindowRef theWindow, - void * handlerRefCon, DragRef theDrag); - static OSErr dragReceiveHandler(WindowRef theWindow, void * handlerRefCon, DragRef theDrag); - OSErr handleDragNDrop(DragRef theDrag, LLWindowCallbacks::DragNDropAction action); + + //static OSErr dragTrackingHandler(DragTrackingMessage message, WindowRef theWindow, void * handlerRefCon, DragRef theDrag); + //static OSErr dragReceiveHandler(WindowRef theWindow, void * handlerRefCon, DragRef theDrag); + + #endif // LL_OS_DRAGDROP_ENABLED // // Platform specific variables // - WindowRef mWindow; - AGLContext mContext; - AGLPixelFormat mPixelFormat; + + // Use generic pointers here. This lets us do some funky Obj-C interop using Obj-C objects without having to worry about any compilation problems that may arise. + NSWindowRef mWindow; + GLViewRef mGLView; + CGLContextObj mContext; + CGLPixelFormatObj mPixelFormat; CGDirectDisplayID mDisplay; - CFDictionaryRef mOldDisplayMode; - EventLoopTimerRef mTimer; - EventHandlerUPP mEventHandlerUPP; - EventHandlerRef mGlobalHandlerRef; - EventHandlerRef mWindowHandlerRef; - EventComparatorUPP mMoveEventCampartorUPP; - Rect mOldMouseClip; // Screen rect to which the mouse cursor was globally constrained before we changed it in clipMouse() - Rect mPreviousWindowRect; // Save previous window for un-maximize event - Str255 mWindowTitle; + LLRect mOldMouseClip; // Screen rect to which the mouse cursor was globally constrained before we changed it in clipMouse() + std::string mWindowTitle; double mOriginalAspectRatio; BOOL mSimulatedRightClick; - UInt32 mLastModifiers; + U32 mLastModifiers; BOOL mHandsOffEvents; // When true, temporarially disable CarbonEvent processing. // Used to allow event processing when putting up dialogs in fullscreen mode. BOOL mCursorDecoupled; @@ -203,25 +209,16 @@ class LLWindowMacOSX : public LLWindow U32 mFSAASamples; BOOL mForceRebuild; - S32 mDragOverrideCursor; - - F32 mBounceTime; - NMRec mBounceRec; - LLTimer mBounceTimer; + S32 mDragOverrideCursor; // Input method management through Text Service Manager. - TSMDocumentID mTSMDocument; BOOL mLanguageTextInputAllowed; - ScriptCode mTSMScriptCode; - LangCode mTSMLangCode; LLPreeditor* mPreeditor; static BOOL sUseMultGL; friend class LLWindowManager; - static WindowRef sMediaWindow; - EventRef mRawKeyEvent; - + }; diff --git a/indra/llwindow/llwindowmesaheadless.cpp b/indra/llwindow/llwindowmesaheadless.cpp index 2b668d3fc4..f5a3277999 100644 --- a/indra/llwindow/llwindowmesaheadless.cpp +++ b/indra/llwindow/llwindowmesaheadless.cpp @@ -41,10 +41,10 @@ U16 *gMesaBuffer = NULL; LLWindowMesaHeadless::LLWindowMesaHeadless(LLWindowCallbacks* callbacks, const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height, U32 flags, BOOL fullscreen, BOOL clearBg, - BOOL disable_vsync, BOOL ignore_pixel_depth) + const S32 vsync_mode, BOOL ignore_pixel_depth) : LLWindow(callbacks, fullscreen, flags) { - llinfos << "MESA Init" << llendl; + LL_INFOS() << "MESA Init" << LL_ENDL; mMesaContext = OSMesaCreateContextExt( GL_RGBA, 32, 0, 0, NULL ); /* Allocate the image buffer */ @@ -56,7 +56,7 @@ LLWindowMesaHeadless::LLWindowMesaHeadless(LLWindowCallbacks* callbacks, /* Bind the buffer to the context and make it current */ if (!OSMesaMakeCurrent( mMesaContext, mMesaBuffer, MESA_CHANNEL_TYPE, width, height )) { - llerrs << "MESA: OSMesaMakeCurrent failed!" << llendl; + LL_ERRS() << "MESA: OSMesaMakeCurrent failed!" << LL_ENDL; } llverify(gGLManager.initGL()); diff --git a/indra/llwindow/llwindowmesaheadless.h b/indra/llwindow/llwindowmesaheadless.h index c8d2bf2824..e116225769 100644 --- a/indra/llwindow/llwindowmesaheadless.h +++ b/indra/llwindow/llwindowmesaheadless.h @@ -30,13 +30,12 @@ #if LL_MESA_HEADLESS #include "llwindow.h" -#include "GL/glu.h" #include "GL/osmesa.h" class LLWindowMesaHeadless : public LLWindow { public: - /*virtual*/ void show() {}; + /*virtual*/ void show(bool) {}; /*virtual*/ void hide() {}; /*virtual*/ void close() {}; /*virtual*/ BOOL getVisible() {return FALSE;}; @@ -52,7 +51,7 @@ class LLWindowMesaHeadless : public LLWindow /*virtual*/ BOOL setPosition(LLCoordScreen position) {return FALSE;}; /*virtual*/ BOOL setSizeImpl(LLCoordScreen size) {return FALSE;}; /*virtual*/ BOOL setSizeImpl(LLCoordWindow size) {return FALSE;}; - /*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp = NULL) {return FALSE;}; + /*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, const S32 vsync_mode, std::function stopFn, std::function restoreFn, const LLCoordScreen * const posp = NULL) {return FALSE;}; /*virtual*/ BOOL setCursorPosition(LLCoordWindow position) {return FALSE;}; /*virtual*/ BOOL getCursorPosition(LLCoordWindow *position) {return FALSE;}; /*virtual*/ void showCursor() {}; @@ -74,6 +73,8 @@ class LLWindowMesaHeadless : public LLWindow /*virtual*/ BOOL restoreGamma() {return FALSE; }; // Restore original gamma table (before updating gamma) /*virtual*/ void setFSAASamples(const U32 fsaa_samples) { /* FSAA not supported yet on Mesa headless.*/ } /*virtual*/ U32 getFSAASamples() { return 0; } + /*virtual*/ void setVsyncMode(const S32 vsync_mode) {} + /*virtual*/ S32 getVsyncMode() { return 0; } //virtual ESwapMethod getSwapMethod() { return mSwapMethod; } /*virtual*/ void gatherInput() {}; /*virtual*/ void delayInputProcessing() {}; @@ -98,7 +99,7 @@ class LLWindowMesaHeadless : public LLWindow LLWindowMesaHeadless(LLWindowCallbacks* callbacks, const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height, U32 flags, BOOL fullscreen, BOOL clearBg, - BOOL disable_vsync, BOOL ignore_pixel_depth); + const S32 vsync_mode, BOOL ignore_pixel_depth); ~LLWindowMesaHeadless(); private: diff --git a/indra/llwindow/llwindowsdl.cpp b/indra/llwindow/llwindowsdl.cpp index e1fa498fac..4502a57903 100644 --- a/indra/llwindow/llwindowsdl.cpp +++ b/indra/llwindow/llwindowsdl.cpp @@ -45,9 +45,13 @@ #if LL_GTK extern "C" { -# include "gtk/gtk.h" +#include +#include +#if GTK_CHECK_VERSION(2, 24, 0) +#include +#endif } -#include +#include #endif // LL_GTK extern "C" { @@ -75,6 +79,9 @@ static bool ATIbug = false; #if LL_X11 # include +#include +#include +#include #endif //LL_X11 // TOFU HACK -- (*exactly* the same hack as LLWindowMacOSX for a similar @@ -83,23 +90,6 @@ static bool ATIbug = false; // be only one object of this class at any time. Currently this is true. static LLWindowSDL *gWindowImplementation = NULL; - -void maybe_lock_display(void) -{ - if (gWindowImplementation && gWindowImplementation->Lock_Display) { - gWindowImplementation->Lock_Display(); - } -} - - -void maybe_unlock_display(void) -{ - if (gWindowImplementation && gWindowImplementation->Unlock_Display) { - gWindowImplementation->Unlock_Display(); - } -} - - #if LL_GTK // Lazily initialize and check the runtime GTK version for goodness. // static @@ -112,48 +102,44 @@ bool LLWindowSDL::ll_try_gtk_init(void) if (!done_setlocale) { - llinfos << "Starting GTK Initialization." << llendl; - maybe_lock_display(); + LL_INFOS() << "Starting GTK Initialization." << LL_ENDL; gtk_disable_setlocale(); - maybe_unlock_display(); done_setlocale = TRUE; } if (!tried_gtk_init) { tried_gtk_init = TRUE; +#if !GLIB_CHECK_VERSION(2, 32, 0) if (!g_thread_supported ()) g_thread_init (NULL); - maybe_lock_display(); +#endif gtk_is_good = gtk_init_check(NULL, NULL); - maybe_unlock_display(); if (!gtk_is_good) - llwarns << "GTK Initialization failed." << llendl; + LL_WARNS() << "GTK Initialization failed." << LL_ENDL; } if (gtk_is_good && !done_gtk_diag) { - llinfos << "GTK Initialized." << llendl; - llinfos << "- Compiled against GTK version " + LL_INFOS() << "GTK Initialized." << LL_ENDL; + LL_INFOS() << "- Compiled against GTK version " << GTK_MAJOR_VERSION << "." << GTK_MINOR_VERSION << "." - << GTK_MICRO_VERSION << llendl; - llinfos << "- Running against GTK version " + << GTK_MICRO_VERSION << LL_ENDL; + LL_INFOS() << "- Running against GTK version " << gtk_major_version << "." << gtk_minor_version << "." - << gtk_micro_version << llendl; - maybe_lock_display(); + << gtk_micro_version << LL_ENDL; const gchar* gtk_warning = gtk_check_version( GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION); - maybe_unlock_display(); if (gtk_warning) { - llwarns << "- GTK COMPATIBILITY WARNING: " << - gtk_warning << llendl; + LL_WARNS() << "- GTK COMPATIBILITY WARNING: " << + gtk_warning << LL_ENDL; gtk_is_good = FALSE; } else { - llinfos << "- GTK version is good." << llendl; + LL_INFOS() << "- GTK version is good." << LL_ENDL; } done_gtk_diag = TRUE; @@ -189,17 +175,17 @@ LLWindowSDL::LLWindowSDL(LLWindowCallbacks* callbacks, const std::string& title, S32 x, S32 y, S32 width, S32 height, U32 flags, BOOL fullscreen, BOOL clearBg, - BOOL disable_vsync, + const S32 vsync_mode, BOOL ignore_pixel_depth, U32 fsaa_samples) : LLWindow(callbacks, fullscreen, flags), - Lock_Display(NULL), - Unlock_Display(NULL), mGamma(1.0f) + mGamma(1.0f) { // Initialize the keyboard gKeyboard = new LLKeyboardSDL(); gKeyboard->setCallbacks(callbacks); // Note that we can't set up key-repeat until after SDL has init'd video + // Ignore use_gl for now, only used for drones on PC mWindow = NULL; mNeedsResize = FALSE; mOverrideAspectRatio = 0.f; @@ -225,15 +211,13 @@ LLWindowSDL::LLWindowSDL(LLWindowCallbacks* callbacks, mOriginalAspectRatio = 1024.0 / 768.0; if (title.empty()) - mWindowTitle = "SDL Window"; // *FIX: (???) + mWindowTitle = "SDL Window"; // *FIX: (?) else mWindowTitle = title; // Create the GL context and set it up for windowed or fullscreen, as appropriate. - if(createContext(x, y, width, height, 32, fullscreen, disable_vsync)) + if(createContext(x, y, width, height, 32, fullscreen, vsync_mode)) { - gGLManager.initGL(); - //start with arrow cursor initCursors(); setCursor( UI_CURSOR_ARROW ); @@ -270,57 +254,41 @@ static SDL_Surface *Load_BMP_Resource(const char *basename) } #if LL_X11 -// This is an XFree86/XOrg-specific hack for detecting the amount of Video RAM -// on this machine. It works by searching /var/log/var/log/Xorg.?.log or -// /var/log/XFree86.?.log for a ': (VideoRAM ?|Memory): (%d+) kB' regex, where -// '?' is the X11 display number derived from $DISPLAY -static int x11_detect_VRAM_kb_fp(FILE *fp, const char *prefix_str) -{ - const int line_buf_size = 1000; - char line_buf[line_buf_size]; - while (fgets(line_buf, line_buf_size, fp)) - { - //lldebugs << "XLOG: " << line_buf << llendl; - - // Why the ad-hoc parser instead of using a regex? Our - // favourite regex implementation - libboost_regex - is - // quite a heavy and troublesome dependency for the client, so - // it seems a shame to introduce it for such a simple task. - // *FIXME: libboost_regex is a dependency now anyway, so we may - // as well use it instead of this hand-rolled nonsense. - const char *part1_template = prefix_str; - const char part2_template[] = " kB"; - char *part1 = strstr(line_buf, part1_template); - if (part1) // found start of matching line - { - part1 = &part1[strlen(part1_template)]; // -> after - char *part2 = strstr(part1, part2_template); - if (part2) // found end of matching line - { - // now everything between part1 and part2 is - // supposed to be numeric, describing the - // number of kB of Video RAM supported - int rtn = 0; - for (; part1 < part2; ++part1) - { - if (*part1 < '0' || *part1 > '9') - { - // unexpected char, abort parse - rtn = 0; - break; - } - rtn *= 10; - rtn += (*part1) - '0'; - } - if (rtn > 0) - { - // got the kB number. return it now. - return rtn; - } - } - } - } - return 0; // 'could not detect' +// This function scrapes the Xorg log to determine the amount of VRAM available to the system. +// Believe it or not, this is the most reliable way at present to detect VRAM on Linux (until +// some angelic being ports the whole viewer to SDL 2.0 or something). +// +// Returns -1 if it couldn't open the file, +// 0 if it could open the file but couldn't detect the amount of VRAM, or +// >0 if it open the file and detect the amount of VRAM present. +// In that case, the number will be the amount of available VRAM in kilobytes. +// +// +static int x11_detect_VRAM_kb_br(std::string filename) { + boost::regex pattern(".*?(VRAM|Memory|Video\\s?RAM)\\D*(\\d+)\\s?([kK]B?)"); + std::string line; + std::ifstream in(filename.c_str()); + int matched = -1; + if(in.is_open()) { + matched = 0; + while (getline(in, line)) + { + // LL_DEBUGS() << "Processing line: " << line << LL_ENDL; + boost::cmatch match; + if(boost::regex_search(line.c_str(), match, pattern)) + { + matched = atoi(std::string(match[2]).c_str()); + LL_DEBUGS() << "VRAM found: " << matched << LL_ENDL; + LL_DEBUGS() << "Line matched: " << line << LL_ENDL; + } + } + in.close(); + } + else // We couldn't open the file, so bow out. + { + LL_DEBUGS() << "Couldn't open logfile " << filename << LL_ENDL; + } + return matched; } static int x11_detect_VRAM_kb() @@ -328,16 +296,23 @@ static int x11_detect_VRAM_kb() #if LL_SOLARIS && defined(__sparc) // NOTE: there's no Xorg server on SPARC so just return 0 // and allow SDL to attempt to get the amount of VRAM - return(0); + return 0; #else std::string x_log_location("/var/log/"); std::string fname; int rtn = 0; // 'could not detect' int display_num = 0; - FILE *fp; - char *display_env = getenv("DISPLAY"); // e.g. :0 or :0.0 or :1.0 etc - // parse DISPLAY number so we can go grab the right log file + char *display_env = getenv("VGL_DISPLAY"); // e.g. :0 or :0.0 or :1.0 etc + // We parse $VGL_DISPLAY first so we can grab the right Xorg filename + // if we're using VirtualGL (like Optimus systems do). + + if (display_env == NULL) { + // if $VGL_DISPLAY doesn't exist, then we're in a single-card setup + display_env = getenv("DISPLAY"); + } + + // parse display number so we can go grab the right log file if (display_env[0] == ':' && display_env[1] >= '0' && display_env[1] <= '9') { @@ -345,82 +320,46 @@ static int x11_detect_VRAM_kb() } // *TODO: we could be smarter and see which of Xorg/XFree86 has the - // freshest time-stamp. + // freshest time-stamp. (...but would it work with VirtualGL?) // Try Xorg log first fname = x_log_location; fname += "Xorg."; fname += ('0' + display_num); fname += ".log"; - fp = fopen(fname.c_str(), "r"); - if (fp) - { - llinfos << "Looking in " << fname - << " for VRAM info..." << llendl; - rtn = x11_detect_VRAM_kb_fp(fp, ": VideoRAM: "); - fclose(fp); - if (0 == rtn) - { - fp = fopen(fname.c_str(), "r"); - if (fp) - { - rtn = x11_detect_VRAM_kb_fp(fp, ": Video RAM: "); - fclose(fp); - if (0 == rtn) - { - fp = fopen(fname.c_str(), "r"); - if (fp) - { - rtn = x11_detect_VRAM_kb_fp(fp, ": Memory: "); - fclose(fp); - } - } - } - } - } - else + LL_INFOS() << "Looking in " << fname << " for VRAM info..." << LL_ENDL; + rtn = x11_detect_VRAM_kb_br(fname); + if(rtn == -1) // we couldn't read the Xorg file { - llinfos << "Could not open " << fname - << " - skipped." << llendl; + LL_INFOS() << "Could not open " << fname + << " - skipped." << LL_ENDL; // Try old XFree86 log otherwise fname = x_log_location; fname += "XFree86."; fname += ('0' + display_num); fname += ".log"; - fp = fopen(fname.c_str(), "r"); - if (fp) - { - llinfos << "Looking in " << fname - << " for VRAM info..." << llendl; - rtn = x11_detect_VRAM_kb_fp(fp, ": VideoRAM: "); - fclose(fp); - if (0 == rtn) - { - fp = fopen(fname.c_str(), "r"); - if (fp) - { - rtn = x11_detect_VRAM_kb_fp(fp, ": Memory: "); - fclose(fp); - } - } - } - else + LL_INFOS() << "Looking in " << fname << " for VRAM info..." << LL_ENDL; + rtn = x11_detect_VRAM_kb_br(fname); + if(rtn == -1) // couldn't read old X log file either { - llinfos << "Could not open " << fname - << " - skipped." << llendl; + LL_INFOS() << "Could not open " << fname + << " - skipped." << LL_ENDL; + //stumped here, return 0 + rtn = 0; } } + LL_INFOS() << "Amount of VRAM detected: "<< rtn << " KB" << LL_ENDL; return rtn; #endif // LL_SOLARIS } #endif // LL_X11 -BOOL LLWindowSDL::createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, BOOL disable_vsync) +BOOL LLWindowSDL::createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, const S32 vsync_mode) { //bool glneedsinit = false; - llinfos << "createContext, fullscreen=" << fullscreen << - " size=" << width << "x" << height << llendl; + LL_INFOS() << "createContext, fullscreen=" << fullscreen << + " size=" << width << "x" << height << LL_ENDL; // captures don't survive contexts mGrabbyKeyFlags = 0; @@ -428,28 +367,28 @@ BOOL LLWindowSDL::createContext(int x, int y, int width, int height, int bits, B if (SDL_Init(SDL_INIT_VIDEO) < 0) { - llinfos << "sdl_init() failed! " << SDL_GetError() << llendl; + LL_INFOS() << "sdl_init() failed! " << SDL_GetError() << LL_ENDL; setupFailure("sdl_init() failure, window creation error", "error", OSMB_OK); return false; } SDL_version c_sdl_version; SDL_VERSION(&c_sdl_version); - llinfos << "Compiled against SDL " + LL_INFOS() << "Compiled against SDL " << int(c_sdl_version.major) << "." << int(c_sdl_version.minor) << "." - << int(c_sdl_version.patch) << llendl; + << int(c_sdl_version.patch) << LL_ENDL; const SDL_version *r_sdl_version; r_sdl_version = SDL_Linked_Version(); - llinfos << " Running against SDL " + LL_INFOS() << " Running against SDL " << int(r_sdl_version->major) << "." << int(r_sdl_version->minor) << "." - << int(r_sdl_version->patch) << llendl; + << int(r_sdl_version->patch) << LL_ENDL; const SDL_VideoInfo *video_info = SDL_GetVideoInfo( ); if (!video_info) { - llinfos << "SDL_GetVideoInfo() failed! " << SDL_GetError() << llendl; + LL_INFOS() << "SDL_GetVideoInfo() failed! " << SDL_GetError() << LL_ENDL; setupFailure("SDL_GetVideoInfo() failed, Window creation error", "Error", OSMB_OK); return FALSE; } @@ -457,7 +396,7 @@ BOOL LLWindowSDL::createContext(int x, int y, int width, int height, int bits, B if (video_info->current_h > 0) { mOriginalAspectRatio = (float)video_info->current_w / (float)video_info->current_h; - llinfos << "Original aspect ratio was " << video_info->current_w << ":" << video_info->current_h << "=" << mOriginalAspectRatio << llendl; + LL_INFOS() << "Original aspect ratio was " << video_info->current_w << ":" << video_info->current_h << "=" << mOriginalAspectRatio << LL_ENDL; } SDL_EnableUNICODE(1); @@ -465,7 +404,7 @@ BOOL LLWindowSDL::createContext(int x, int y, int width, int height, int bits, B // Set the application icon. SDL_Surface *bmpsurface; - bmpsurface = Load_BMP_Resource("singularity_icon.BMP"); + bmpsurface = Load_BMP_Resource("viewer_icon.BMP"); if (bmpsurface) { // This attempts to give a black-keyed mask to the icon. @@ -527,7 +466,7 @@ BOOL LLWindowSDL::createContext(int x, int y, int width, int height, int bits, B if (mFullscreen) { - llinfos << "createContext: setting up fullscreen " << width << "x" << height << llendl; + LL_INFOS() << "createContext: setting up fullscreen " << width << "x" << height << LL_ENDL; // If the requested width or height is 0, find the best default for the monitor. if((width == 0) || (height == 0)) @@ -545,18 +484,18 @@ BOOL LLWindowSDL::createContext(int x, int y, int width, int height, int bits, B U32 closestWidth = 0; int i; - llinfos << "createContext: searching for a display mode, original aspect is " << mOriginalAspectRatio << llendl; + LL_INFOS() << "createContext: searching for a display mode, original aspect is " << mOriginalAspectRatio << LL_ENDL; for(i=0; i < resolutionCount; i++) { F32 aspect = (F32)resolutionList[i].mWidth / (F32)resolutionList[i].mHeight; - llinfos << "createContext: width " << resolutionList[i].mWidth << " height " << resolutionList[i].mHeight << " aspect " << aspect << llendl; + LL_INFOS() << "createContext: width " << resolutionList[i].mWidth << " height " << resolutionList[i].mHeight << " aspect " << aspect << LL_ENDL; if( (resolutionList[i].mHeight >= 700) && (resolutionList[i].mHeight <= 800) && (fabs(aspect - mOriginalAspectRatio) < fabs(closestAspect - mOriginalAspectRatio))) { - llinfos << " (new closest mode) " << llendl; + LL_INFOS() << " (new closest mode) " << LL_ENDL; // This is the closest mode we've seen yet. closestWidth = resolutionList[i].mWidth; @@ -592,15 +531,15 @@ BOOL LLWindowSDL::createContext(int x, int y, int width, int height, int bits, B mFullscreenBits = mWindow->format->BitsPerPixel; mFullscreenRefresh = -1; - llinfos << "Running at " << mFullscreenWidth + LL_INFOS() << "Running at " << mFullscreenWidth << "x" << mFullscreenHeight << "x" << mFullscreenBits << " @ " << mFullscreenRefresh - << llendl; + << LL_ENDL; } else { - llwarns << "createContext: fullscreen creation failure. SDL: " << SDL_GetError() << llendl; + LL_WARNS() << "createContext: fullscreen creation failure. SDL: " << SDL_GetError() << LL_ENDL; // No fullscreen support mFullscreen = FALSE; mFullscreenWidth = -1; @@ -620,7 +559,7 @@ BOOL LLWindowSDL::createContext(int x, int y, int width, int height, int bits, B if (height == 0) width = 768; - llinfos << "createContext: creating window " << width << "x" << height << "x" << bits << llendl; + LL_INFOS() << "createContext: creating window " << width << "x" << height << "x" << bits << LL_ENDL; mWindow = SDL_SetVideoMode(width, height, bits, sdlflags); if (!mWindow && bits > 16) { @@ -630,32 +569,32 @@ BOOL LLWindowSDL::createContext(int x, int y, int width, int height, int bits, B if (!mWindow && mFSAASamples > 0) { - llwarns << "Window creating is failing, disabling FSAA and trying again"<video_mem / 1024; if (gGLManager.mVRAM != 0) { - llinfos << "SDL detected " << gGLManager.mVRAM << "MB VRAM." << llendl; + LL_INFOS() << "SDL detected " << gGLManager.mVRAM << "MB VRAM." << LL_ENDL; } } // If VRAM is not detected, that is handled later @@ -681,13 +620,13 @@ BOOL LLWindowSDL::createContext(int x, int y, int width, int height, int bits, B glGetIntegerv(GL_DEPTH_BITS, &depthBits); glGetIntegerv(GL_STENCIL_BITS, &stencilBits); - llinfos << "GL buffer:" << llendl; - llinfos << " Red Bits " << S32(redBits) << llendl; - llinfos << " Green Bits " << S32(greenBits) << llendl; - llinfos << " Blue Bits " << S32(blueBits) << llendl; - llinfos << " Alpha Bits " << S32(alphaBits) << llendl; - llinfos << " Depth Bits " << S32(depthBits) << llendl; - llinfos << " Stencil Bits " << S32(stencilBits) << llendl; + LL_INFOS() << "GL buffer:" << LL_ENDL; + LL_INFOS() << " Red Bits " << S32(redBits) << LL_ENDL; + LL_INFOS() << " Green Bits " << S32(greenBits) << LL_ENDL; + LL_INFOS() << " Blue Bits " << S32(blueBits) << LL_ENDL; + LL_INFOS() << " Alpha Bits " << S32(alphaBits) << LL_ENDL; + LL_INFOS() << " Depth Bits " << S32(depthBits) << LL_ENDL; + LL_INFOS() << " Stencil Bits " << S32(stencilBits) << LL_ENDL; GLint colorBits = redBits + greenBits + blueBits + alphaBits; // fixme: actually, it's REALLY important for picking that we get at @@ -719,23 +658,6 @@ BOOL LLWindowSDL::createContext(int x, int y, int width, int height, int bits, B return FALSE; } -#if 0 // *FIX: we're going to brave it for now... - if (alphaBits < 8) - { - close(); - setupFailure( - "Second Life is unable to run because it can't get an 8 bit alpha\n" - "channel. Usually this is due to video card driver issues.\n" - "Please make sure you have the latest video card drivers installed.\n" - "Also be sure your monitor is set to True Color (32-bit) in\n" - "Control Panels -> Display -> Settings.\n" - "If you continue to receive this message, contact customer service.", - "Error", - OSMB_OK); - return FALSE; - } -#endif - #if LL_X11 /* Grab the window manager specific information */ SDL_SysWMinfo info; @@ -747,22 +669,57 @@ BOOL LLWindowSDL::createContext(int x, int y, int width, int height, int bits, B { mSDL_Display = info.info.x11.display; mSDL_XWindowID = info.info.x11.wmwindow; - Lock_Display = info.info.x11.lock_func; - Unlock_Display = info.info.x11.unlock_func; } else { - llwarns << "We're not running under X11? Wild." - << llendl; + LL_WARNS() << "We're not running under X11? Wild." + << LL_ENDL; } } else { - llwarns << "We're not running under any known WM. Wild." - << llendl; + LL_WARNS() << "We're not running under any known WM. Wild." + << LL_ENDL; } #endif // LL_X11 + gGLManager.initGL(); + +#if SDL_VERSION_ATLEAST(1,3,0) + // Disable vertical sync for swap + if (vsync_mode == 0 || (!gGLManager.mHasAdaptiveVsync && vsync_mode == -1)) + { + LL_DEBUGS("Window") << "Disabling vertical sync" << LL_ENDL; + SDL_GL_SetSwapInterval(0); + } + else if(vsync_mode == -1) + { + LL_DEBUGS("Window") << "Enabling adaptive vertical sync" << LL_ENDL; + if(SDL_GL_SetSwapInterval(-1) == -1) + { + LL_DEBUGS("Window") << "Failed to enable adaptive vertical sync. Disabling vsync." << LL_ENDL; + SDL_GL_SetSwapInterval(0); + } + } + else + { + LL_DEBUGS("Window") << "Enabling vertical sync" << LL_ENDL; + SDL_GL_SetSwapInterval(1); + } +#else // SDL_VERSION_ATLEAST(1,3,0) +#ifdef SDL_GL_SWAP_CONTROL + if (vsync_mode <= 0) + { + LL_DEBUGS("Window") << "Disabling vertical sync" << LL_ENDL; + SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 0); + } + else + { + LL_DEBUGS("Window") << "Enabling vertical sync" << LL_ENDL; + SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 1); + } +#endif // SDL_GL_SWAP_CONTROL +#endif // SDL_VERSION_ATLEAST(1,3,0) //make sure multisampling is disabled by default glDisable(GL_MULTISAMPLE_ARB); @@ -770,7 +727,7 @@ BOOL LLWindowSDL::createContext(int x, int y, int width, int height, int bits, B // We need to do this here, once video is init'd if (-1 == SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL)) - llwarns << "Couldn't enable key-repeat: " << SDL_GetError() < stopFn, std::function restoreFn, const LLCoordScreen * const posp) { const BOOL needsRebuild = TRUE; // Just nuke the context and start over. BOOL result = true; - llinfos << "switchContext, fullscreen=" << fullscreen << llendl; + LL_INFOS() << "switchContext, fullscreen=" << fullscreen << LL_ENDL; stop_glerror(); if(needsRebuild) { + if (stopFn) stopFn(); destroyContext(); - result = createContext(0, 0, size.mX, size.mY, 0, fullscreen, disable_vsync); + result = createContext(0, 0, size.mX, size.mY, 0, fullscreen, vsync_mode); if (result) { - gGLManager.initGL(); - //start with arrow cursor initCursors(); setCursor( UI_CURSOR_ARROW ); } + if (restoreFn) restoreFn(true); } stop_glerror(); @@ -806,19 +763,17 @@ BOOL LLWindowSDL::switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL void LLWindowSDL::destroyContext() { - llinfos << "destroyContext begins" << llendl; + LL_INFOS() << "destroyContext begins" << LL_ENDL; #if LL_X11 mSDL_Display = NULL; mSDL_XWindowID = None; - Lock_Display = NULL; - Unlock_Display = NULL; #endif // LL_X11 // Clean up remaining GL state before blowing away window - llinfos << "shutdownGL begins" << llendl; + LL_INFOS() << "shutdownGL begins" << LL_ENDL; gGLManager.shutdownGL(); - llinfos << "SDL_QuitSS/VID begins" << llendl; + LL_INFOS() << "SDL_QuitSS/VID begins" << LL_ENDL; SDL_QuitSubSystem(SDL_INIT_VIDEO); // *FIX: this might be risky... mWindow = NULL; @@ -838,7 +793,7 @@ LLWindowSDL::~LLWindowSDL() } -void LLWindowSDL::show() +void LLWindowSDL::show(bool focus) { // *FIX: What to do with SDL? } @@ -967,7 +922,7 @@ BOOL LLWindowSDL::setPosition(const LLCoordScreen position) { if(mWindow) { - // *FIX: (???) + // *FIX: (?) //MacMoveWindow(mWindow, position.mX, position.mY, false); } @@ -1029,6 +984,16 @@ void LLWindowSDL::setFSAASamples(const U32 samples) mFSAASamples = samples; } +S32 LLWindowSDL::getVsyncMode() +{ + return mVsyncMode; +} + +void LLWindowSDL::setVsyncMode(const S32 vsync_mode) +{ + mVsyncMode = vsync_mode; +} + F32 LLWindowSDL::getGamma() { return 1/mGamma; @@ -1092,12 +1057,12 @@ BOOL LLWindowSDL::setCursorPosition(const LLCoordWindow position) return FALSE; } - //llinfos << "setCursorPosition(" << screen_pos.mX << ", " << screen_pos.mY << ")" << llendl; + //LL_INFOS() << "setCursorPosition(" << screen_pos.mX << ", " << screen_pos.mY << ")" << LL_ENDL; // do the actual forced cursor move. SDL_WarpMouse(screen_pos.mX, screen_pos.mY); - //llinfos << llformat("llcw %d,%d -> scr %d,%d", position.mX, position.mY, screen_pos.mX, screen_pos.mY) << llendl; + //LL_INFOS() << llformat("llcw %d,%d -> scr %d,%d", position.mX, position.mY, screen_pos.mX, screen_pos.mY) << LL_ENDL; return result; } @@ -1182,7 +1147,7 @@ void LLWindowSDL::beforeDialog() running_x11 = (mSDL_XWindowID != None); #endif //LL_X11 - llinfos << "LLWindowSDL::beforeDialog()" << llendl; + LL_INFOS() << "LLWindowSDL::beforeDialog()" << LL_ENDL; if (SDLReallyCaptureInput(FALSE)) // must ungrab input so popup works! { @@ -1203,9 +1168,7 @@ void LLWindowSDL::beforeDialog() { // Everything that we/SDL asked for should happen before we // potentially hand control over to GTK. - maybe_lock_display(); XSync(mSDL_Display, False); - maybe_unlock_display(); } #endif // LL_X11 @@ -1214,8 +1177,6 @@ void LLWindowSDL::beforeDialog() // diagnostics, if not already done. ll_try_gtk_init(); #endif // LL_GTK - - maybe_lock_display(); } void LLWindowSDL::afterDialog() @@ -1225,9 +1186,7 @@ void LLWindowSDL::afterDialog() running_x11 = (mSDL_XWindowID != None); #endif //LL_X11 - llinfos << "LLWindowSDL::afterDialog()" << llendl; - - maybe_unlock_display(); + LL_INFOS() << "LLWindowSDL::afterDialog()" << LL_ENDL; if (mFullscreen) { @@ -1249,9 +1208,8 @@ void LLWindowSDL::x11_set_urgent(BOOL urgent) { XWMHints *wm_hints; - llinfos << "X11 hint for urgency, " << urgent << llendl; + LL_INFOS() << "X11 hint for urgency, " << urgent << LL_ENDL; - maybe_lock_display(); wm_hints = XGetWMHints(mSDL_Display, mSDL_XWindowID); if (!wm_hints) wm_hints = XAllocWMHints(); @@ -1264,7 +1222,6 @@ void LLWindowSDL::x11_set_urgent(BOOL urgent) XSetWMHints(mSDL_Display, mSDL_XWindowID, wm_hints); XFree(wm_hints); XSync(mSDL_Display, False); - maybe_unlock_display(); } } #endif // LL_X11 @@ -1272,9 +1229,9 @@ void LLWindowSDL::x11_set_urgent(BOOL urgent) void LLWindowSDL::flashIcon(F32 seconds) { #if !LL_X11 - llinfos << "Stub LLWindowSDL::flashIcon(" << seconds << ")" << llendl; + LL_INFOS() << "Stub LLWindowSDL::flashIcon(" << seconds << ")" << LL_ENDL; #else - llinfos << "X11 LLWindowSDL::flashIcon(" << seconds << ")" << llendl; + LL_INFOS() << "X11 LLWindowSDL::flashIcon(" << seconds << ")" << LL_ENDL; F32 remaining_time = mFlashTimer.getRemainingTimeF32(); if (remaining_time < seconds) @@ -1429,18 +1386,25 @@ LLWindow::LLWindowResolution* LLWindowSDL::getSupportedResolutions(S32 &num_reso { modes--; SDL_Rect *r = *modes; - int w = r->w; - int h = r->h; + S32 w = r->w; + S32 h = r->h; if ((w >= 800) && (h >= 600)) { // make sure we don't add the same resolution multiple times! - if ( (mNumSupportedResolutions == 0) || - ((mSupportedResolutions[mNumSupportedResolutions-1].mWidth != w) && - (mSupportedResolutions[mNumSupportedResolutions-1].mHeight != h)) ) + bool resolution_exists = false; + for (S32 i = 0; i < mNumSupportedResolutions; ++i) + { + if (mSupportedResolutions[i].mWidth == w && + mSupportedResolutions[i].mHeight == h) + { + resolution_exists = true; + break; + } + } + if (!resolution_exists) { mSupportedResolutions[mNumSupportedResolutions].mWidth = w; - mSupportedResolutions[mNumSupportedResolutions].mHeight = h; - mNumSupportedResolutions++; + mSupportedResolutions[mNumSupportedResolutions++].mHeight = h; } } } @@ -1541,7 +1505,7 @@ BOOL LLWindowSDL::SDLReallyCaptureInput(BOOL capture) if (mReallyCapturedCount < 0) // yuck, imbalance. { mReallyCapturedCount = 0; - llwarns << "ReallyCapture count was < 0" << llendl; + LL_WARNS() << "ReallyCapture count was < 0" << LL_ENDL; } if (!mFullscreen) /* only bother if we're windowed anyway */ @@ -1562,29 +1526,25 @@ BOOL LLWindowSDL::SDLReallyCaptureInput(BOOL capture) int result; if (wantmode == SDL_GRAB_ON) { - //llinfos << "X11 POINTER GRABBY" << llendl; + //LL_INFOS() << "X11 POINTER GRABBY" << LL_ENDL; //newmode = SDL_WM_GrabInput(wantmode); - maybe_lock_display(); result = XGrabPointer(mSDL_Display, mSDL_XWindowID, True, 0, GrabModeAsync, GrabModeAsync, None, None, CurrentTime); - maybe_unlock_display(); if (GrabSuccess == result) newmode = SDL_GRAB_ON; else newmode = SDL_GRAB_OFF; } else if (wantmode == SDL_GRAB_OFF) { - //llinfos << "X11 POINTER UNGRABBY" << llendl; + //LL_INFOS() << "X11 POINTER UNGRABBY" << LL_ENDL; newmode = SDL_GRAB_OFF; //newmode = SDL_WM_GrabInput(SDL_GRAB_OFF); - maybe_lock_display(); XUngrabPointer(mSDL_Display, CurrentTime); // Make sure the ungrab happens RIGHT NOW. - XSync(mSDL_Display, False); - maybe_unlock_display(); + XSync(mSDL_Display, FALSE); } else { newmode = SDL_GRAB_QUERY; // neutral @@ -1637,7 +1597,7 @@ U32 LLWindowSDL::SDLCheckGrabbyKeys(SDLKey keysym, BOOL gain) else mGrabbyKeyFlags &= ~mask; - //llinfos << "mGrabbyKeyFlags=" << mGrabbyKeyFlags << llendl; + //LL_INFOS() << "mGrabbyKeyFlags=" << mGrabbyKeyFlags << LL_ENDL; /* 0 means we don't need to mousegrab, otherwise grab. */ return mGrabbyKeyFlags; @@ -1678,18 +1638,18 @@ void check_vm_bloat() long long this_rss_size = getpagesize() * atoll(ptr); free(ptr); - llinfos << "VM SIZE IS NOW " << (this_vm_size/(1024*1024)) << " MB, RSS SIZE IS NOW " << (this_rss_size/(1024*1024)) << " MB" << llendl; + LL_INFOS() << "VM SIZE IS NOW " << (this_vm_size/(1024*1024)) << " MB, RSS SIZE IS NOW " << (this_rss_size/(1024*1024)) << " MB" << LL_ENDL; if (llabs(last_vm_size - this_vm_size) > significant_vm_difference) { if (this_vm_size > last_vm_size) { - llwarns << "VM size grew by " << (this_vm_size - last_vm_size)/(1024*1024) << " MB in last frame" << llendl; + LL_WARNS() << "VM size grew by " << (this_vm_size - last_vm_size)/(1024*1024) << " MB in last frame" << LL_ENDL; } else { - llinfos << "VM size shrank by " << (last_vm_size - this_vm_size)/(1024*1024) << " MB in last frame" << llendl; + LL_INFOS() << "VM size shrank by " << (last_vm_size - this_vm_size)/(1024*1024) << " MB in last frame" << LL_ENDL; } } @@ -1698,11 +1658,11 @@ void check_vm_bloat() { if (this_rss_size > last_rss_size) { - llwarns << "RSS size grew by " << (this_rss_size - last_rss_size)/(1024*1024) << " MB in last frame" << llendl; + LL_WARNS() << "RSS size grew by " << (this_rss_size - last_rss_size)/(1024*1024) << " MB in last frame" << LL_ENDL; } else { - llinfos << "RSS size shrank by " << (last_rss_size - this_rss_size)/(1024*1024) << " MB in last frame" << llendl; + LL_INFOS() << "RSS size shrank by " << (last_rss_size - this_rss_size)/(1024*1024) << " MB in last frame" << LL_ENDL; } } @@ -1781,6 +1741,7 @@ void LLWindowSDL::gatherInput() mKeyScanCode = event.key.keysym.scancode; mKeyVirtualKey = event.key.keysym.unicode; mKeyModifiers = event.key.keysym.mod; + mKeySym = event.key.keysym.sym; gKeyboard->handleKeyDown(event.key.keysym.sym, event.key.keysym.mod); // part of the fix for SL-13243 @@ -1798,6 +1759,7 @@ void LLWindowSDL::gatherInput() mKeyScanCode = event.key.keysym.scancode; mKeyVirtualKey = event.key.keysym.unicode; mKeyModifiers = event.key.keysym.mod; + mKeySym = event.key.keysym.sym; if (SDLCheckGrabbyKeys(event.key.keysym.sym, FALSE) == 0) SDLReallyCaptureInput(FALSE); // part of the fix for SL-13243 @@ -1893,8 +1855,8 @@ void LLWindowSDL::gatherInput() case SDL_VIDEORESIZE: { - llinfos << "Handling a resize event: " << event.resize.w << - "x" << event.resize.h << llendl; + LL_INFOS() << "Handling a resize event: " << event.resize.w << + "x" << event.resize.h << LL_ENDL; S32 width = llmax(event.resize.w, (S32)mMinWindowWidth); S32 height = llmax(event.resize.h, (S32)mMinWindowHeight); @@ -1906,7 +1868,7 @@ void LLWindowSDL::gatherInput() if (!mWindow) { // *FIX: More informative dialog? - llinfos << "Could not recreate context after resize! Quitting..." << llendl; + LL_INFOS() << "Could not recreate context after resize! Quitting..." << LL_ENDL; if(mCallbacks->handleCloseRequest(this)) { // Get the app to initiate cleanup. @@ -1947,11 +1909,11 @@ void LLWindowSDL::gatherInput() mIsMinimized = (!event.active.gain); mCallbacks->handleActivate(this, !mIsMinimized); - lldebugs << "SDL deiconification state switched to " << BOOL(event.active.gain) << llendl; + LL_DEBUGS() << "SDL deiconification state switched to " << BOOL(event.active.gain) << LL_ENDL; } else { - llinfos << "Ignored bogus redundant SDL deiconification state switch to " << BOOL(event.active.gain) << llendl; + LL_INFOS() << "Ignored bogus redundant SDL deiconification state switch to " << BOOL(event.active.gain) << LL_ENDL; } } break; @@ -1965,7 +1927,7 @@ void LLWindowSDL::gatherInput() } break; default: - //llinfos << "Unhandled SDL event type " << event.type << llendl; + //LL_INFOS() << "Unhandled SDL event type " << event.type << LL_ENDL; break; } } @@ -1993,8 +1955,8 @@ static SDL_Cursor *makeSDLCursorFromBMP(const char *filename, int hotx, int hoty if (bmpsurface && bmpsurface->w%8==0) { SDL_Surface *cursurface; - lldebugs << "Loaded cursor file " << filename << " " - << bmpsurface->w << "x" << bmpsurface->h << llendl; + LL_DEBUGS() << "Loaded cursor file " << filename << " " + << bmpsurface->w << "x" << bmpsurface->h << LL_ENDL; cursurface = SDL_CreateRGBSurface (SDL_SWSURFACE, bmpsurface->w, bmpsurface->h, @@ -2046,12 +2008,12 @@ static SDL_Cursor *makeSDLCursorFromBMP(const char *filename, int hotx, int hoty delete[] cursor_data; delete[] cursor_mask; } else { - llwarns << "CURSOR BLIT FAILURE, cursurface: " << cursurface << llendl; + LL_WARNS() << "CURSOR BLIT FAILURE, cursurface: " << cursurface << LL_ENDL; } SDL_FreeSurface(cursurface); SDL_FreeSurface(bmpsurface); } else { - llwarns << "CURSOR LOAD FAILURE " << filename << llendl; + LL_WARNS() << "CURSOR LOAD FAILURE " << filename << LL_ENDL; } return sdlcursor; @@ -2077,7 +2039,7 @@ void LLWindowSDL::updateCursor() if (sdlcursor) SDL_SetCursor(sdlcursor); } else { - llwarns << "Tried to set invalid cursor number " << mNextCursor << llendl; + LL_WARNS() << "Tried to set invalid cursor number " << mNextCursor << LL_ENDL; } mCurrentCursor = mNextCursor; } @@ -2134,7 +2096,7 @@ void LLWindowSDL::initCursors() mSDLCursors[UI_CURSOR_TOOLPAY] = makeSDLCursorFromBMP("toolpay.BMP",0,0); if (getenv("LL_ATI_MOUSE_CURSOR_BUG") != NULL) { - llinfos << "Disabling cursor updating due to LL_ATI_MOUSE_CURSOR_BUG" << llendl; + LL_INFOS() << "Disabling cursor updating due to LL_ATI_MOUSE_CURSOR_BUG" << LL_ENDL; ATIbug = true; } } @@ -2155,7 +2117,7 @@ void LLWindowSDL::quitCursors() } else { // SDL doesn't refcount cursors, so if the window has // already been destroyed then the cursors have gone with it. - llinfos << "Skipping quitCursors: mWindow already gone." << llendl; + LL_INFOS() << "Skipping quitCursors: mWindow already gone." << LL_ENDL; for (i=0; imSDL_XWindowID != None) { gtk_widget_realize(GTK_WIDGET(win)); // so we can get its gdkwin - GdkWindow *gdkwin = gdk_window_foreign_new(gWindowImplementation->mSDL_XWindowID); - gdk_window_set_transient_for(GTK_WIDGET(win)->window, - gdkwin); +#if GTK_CHECK_VERSION(2, 24, 0) + GdkWindow* gdkwin = gdk_x11_window_foreign_new_for_display(gdk_display_get_default(), static_cast(gWindowImplementation->mSDL_XWindowID)); +#else + GdkWindow* gdkwin = gdk_window_foreign_new(static_cast(gWindowImplementation->mSDL_XWindowID)); +#endif + gdk_window_set_transient_for(gtk_widget_get_window(GTK_WIDGET(win)), gdkwin); } # endif //LL_X11 @@ -2335,7 +2300,7 @@ S32 OSMessageBoxSDL(const std::string& text, const std::string& caption, U32 typ gtk_widget_show_all (win); gtk_main(); - //llinfos << "response: " << response << llendl; + //LL_INFOS() << "response: " << response << LL_ENDL; switch (response) { case GTK_RESPONSE_OK: rtn = OSBTN_OK; break; @@ -2351,8 +2316,8 @@ S32 OSMessageBoxSDL(const std::string& text, const std::string& caption, U32 typ } else { - llinfos << "MSGBOX: " << caption << ": " << text << llendl; - llinfos << "Skipping dialog because we're in fullscreen mode or GTK is not happy." << llendl; + LL_INFOS() << "MSGBOX: " << caption << ": " << text << LL_ENDL; + LL_INFOS() << "Skipping dialog because we're in fullscreen mode or GTK is not happy." << LL_ENDL; rtn = OSBTN_OK; } @@ -2399,6 +2364,7 @@ LLSD LLWindowSDL::getNativeKeyData() result["scan_code"] = (S32)mKeyScanCode; result["virtual_key"] = (S32)mKeyVirtualKey; result["modifiers"] = (S32)modifiers; + result[ "sdl_sym" ] = (S32)mKeySym; return result; } @@ -2423,13 +2389,16 @@ BOOL LLWindowSDL::dialogColorPicker( F32 *r, F32 *g, F32 *b) if (mSDL_XWindowID != None) { gtk_widget_realize(GTK_WIDGET(win)); // so we can get its gdkwin - GdkWindow *gdkwin = gdk_window_foreign_new(mSDL_XWindowID); - gdk_window_set_transient_for(GTK_WIDGET(win)->window, - gdkwin); +#if GTK_CHECK_VERSION(2, 24, 0) + GdkWindow* gdkwin = gdk_x11_window_foreign_new_for_display(gdk_display_get_default(), static_cast(mSDL_XWindowID)); +#else + GdkWindow* gdkwin = gdk_window_foreign_new(static_cast(mSDL_XWindowID)); +#endif + gdk_window_set_transient_for(gtk_widget_get_window(GTK_WIDGET(win)), gdkwin); } -# endif //LL_X11 +#endif //LL_X11 - GtkColorSelection *colorsel = GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG(win)->colorsel); + GtkColorSelection *colorsel = GTK_COLOR_SELECTION (gtk_color_selection_dialog_get_color_selection (GTK_COLOR_SELECTION_DIALOG(win))); GdkColor color, orig_color; orig_color.pixel = 0; @@ -2455,8 +2424,6 @@ BOOL LLWindowSDL::dialogColorPicker( F32 *r, F32 *g, F32 *b) gtk_window_set_modal(GTK_WINDOW(win), TRUE); gtk_widget_show_all(win); - // hide the help button - we don't service it. - gtk_widget_hide(GTK_COLOR_SELECTION_DIALOG(win)->help_button); gtk_main(); if (response == GTK_RESPONSE_OK && @@ -2478,7 +2445,7 @@ BOOL LLWindowSDL::dialogColorPicker( F32 *r, F32 *g, F32 *b) #else S32 OSMessageBoxSDL(const std::string& text, const std::string& caption, U32 type) { - llinfos << "MSGBOX: " << caption << ": " << text << llendl; + LL_INFOS() << "MSGBOX: " << caption << ": " << text << LL_ENDL; return 0; } @@ -2506,7 +2473,7 @@ void exec_cmd(const std::string& cmd, const std::string& arg) // end ourself by running the command execv(cmd.c_str(), argv); /* Flawfinder: ignore */ // if execv returns at all, there was a problem. - llwarns << "execv failure when trying to start " << cmd << llendl; + LL_WARNS() << "execv failure when trying to start " << cmd << LL_ENDL; _exit(1); // _exit because we don't want atexit() clean-up! } else { if (pid > 0) @@ -2515,7 +2482,7 @@ void exec_cmd(const std::string& cmd, const std::string& arg) int childExitStatus; waitpid(pid, &childExitStatus, 0); } else { - llwarns << "fork failure." << llendl; + LL_WARNS() << "fork failure." << LL_ENDL; } } } @@ -2525,62 +2492,42 @@ void exec_cmd(const std::string& cmd, const std::string& arg) // Must begin with protocol identifier. void LLWindowSDL::spawnWebBrowser(const std::string& escaped_url, bool async) { - bool found = false; - S32 i; - for (i = 0; i < gURLProtocolWhitelistCount; i++) - { - if (escaped_url.find(gURLProtocolWhitelist[i]) != std::string::npos) - { - found = true; - break; - } - } - - if (!found) + if (!isWhitelistedProtocol(escaped_url)) { - llwarns << "spawn_web_browser called for url with protocol not on whitelist: " << escaped_url << llendl; + LL_WARNS() << "spawn_web_browser called for url with protocol not on whitelist: " << escaped_url << LL_ENDL; return; } - llinfos << "spawn_web_browser: " << escaped_url << llendl; + LL_INFOS() << "spawn_web_browser: " << escaped_url << LL_ENDL; #if LL_LINUX || LL_SOLARIS # if LL_X11 if (mSDL_Display) { - maybe_lock_display(); // Just in case - before forking. - XSync(mSDL_Display, False); - maybe_unlock_display(); + XSync(mSDL_Display, FALSE); } # endif // LL_X11 std::string cmd, arg; cmd = gDirUtilp->getAppRODataDir(); cmd += gDirUtilp->getDirDelimiter(); - //cmd += "etc"; - //cmd += gDirUtilp->getDirDelimiter(); + cmd += "etc"; + cmd += gDirUtilp->getDirDelimiter(); cmd += "launch_url.sh"; arg = escaped_url; exec_cmd(cmd, arg); #endif // LL_LINUX || LL_SOLARIS - llinfos << "spawn_web_browser returning." << llendl; + LL_INFOS() << "spawn_web_browser returning." << LL_ENDL; } -void LLWindowSDL::setTitle(const std::string &title) -{ - mWindowTitle = title; - SDL_WM_SetCaption(mWindowTitle.c_str(),mWindowTitle.c_str()); -} void *LLWindowSDL::getPlatformWindow() { #if LL_GTK && LL_LLMOZLIB_ENABLED if (LLWindowSDL::ll_try_gtk_init()) { - maybe_lock_display(); - GtkWidget *owin = gtk_window_new(GTK_WINDOW_POPUP); // Why a layout widget? A MozContainer would be ideal, but // it involves exposing Mozilla headers to mozlib-using apps. @@ -2592,8 +2539,6 @@ void *LLWindowSDL::getPlatformWindow() gtk_widget_realize(rtnw); GTK_WIDGET_UNSET_FLAGS(GTK_WIDGET(rtnw), GTK_NO_WINDOW); - maybe_unlock_display(); - return rtnw; } #endif // LL_GTK && LL_LLMOZLIB_ENABLED @@ -2605,14 +2550,12 @@ void LLWindowSDL::bringToFront() { // This is currently used when we are 'launched' to a specific // map position externally. - llinfos << "bringToFront" << llendl; + LL_INFOS() << "bringToFront" << LL_ENDL; #if LL_X11 if (mSDL_Display && !mFullscreen) { - maybe_lock_display(); XRaiseWindow(mSDL_Display, mSDL_XWindowID); - XSync(mSDL_Display, False); - maybe_unlock_display(); + XSync(mSDL_Display, FALSE); } #endif // LL_X11 } @@ -2623,7 +2566,7 @@ std::vector LLWindowSDL::getDynamicFallbackFontList() // Use libfontconfig to find us a nice ordered list of fallback fonts // specific to this system. std::string final_fallback("/usr/share/fonts/truetype/kochi/kochi-gothic.ttf"); - const int max_font_count_cutoff = 100; // fonts are expensive in the current system, don't enumerate an arbitrary number of them + const int max_font_count_cutoff = 40; // fonts are expensive in the current system, don't enumerate an arbitrary number of them // Our 'ideal' font properties which define the sorting results. // slant=0 means Roman, index=0 means the first face in a font file // (the one we actually use), weight=80 means medium weight, @@ -2640,7 +2583,7 @@ std::vector LLWindowSDL::getDynamicFallbackFontList() FcFontSet *fs = NULL; FcPattern *sortpat = NULL; - llinfos << "Getting system font list from FontConfig..." << llendl; + LL_INFOS() << "Getting system font list from FontConfig..." << LL_ENDL; // If the user has a system-wide language preference, then favor // fonts from that language group. This doesn't affect the types @@ -2657,9 +2600,9 @@ std::vector LLWindowSDL::getDynamicFallbackFontList() LL_INFOS("AppInit") << "Location " << locale->country << LL_ENDL; LL_INFOS("AppInit") << "Variant " << locale->variant << LL_ENDL; - llinfos << "Preferring fonts of language: " + LL_INFOS() << "Preferring fonts of language: " << locale->lang - << llendl; + << LL_ENDL; sort_order = "lang=" + std::string(locale->lang) + ":" + sort_order; } @@ -2668,7 +2611,7 @@ std::vector LLWindowSDL::getDynamicFallbackFontList() if (!FcInit()) { - llwarns << "FontConfig failed to initialize." << llendl; + LL_WARNS() << "FontConfig failed to initialize." << LL_ENDL; rtns.push_back(final_fallback); return rtns; } @@ -2705,17 +2648,23 @@ std::vector LLWindowSDL::getDynamicFallbackFontList() FcFontSetDestroy (fs); } - lldebugs << "Using font list: " << llendl; + LL_DEBUGS() << "Using font list: " << LL_ENDL; for (std::vector::iterator it = rtns.begin(); it != rtns.end(); ++it) { - lldebugs << " file: " << *it << llendl; + LL_DEBUGS() << " file: " << *it << LL_ENDL; } - llinfos << "Using " << rtns.size() << "/" << found_font_count << " system fonts." << llendl; + LL_INFOS() << "Using " << rtns.size() << "/" << found_font_count << " system fonts." << LL_ENDL; //rtns.push_back(final_fallback); return rtns; } +void LLWindowSDL::setTitle(const std::string& title) +{ + mWindowTitle = title; + SDL_WM_SetCaption(mWindowTitle.c_str(),mWindowTitle.c_str()); +} + #endif // LL_SDL diff --git a/indra/llwindow/llwindowsdl.h b/indra/llwindow/llwindowsdl.h index 134554e6ec..3117821805 100644 --- a/indra/llwindow/llwindowsdl.h +++ b/indra/llwindow/llwindowsdl.h @@ -49,7 +49,7 @@ class LLWindowSDL : public LLWindow { public: - /*virtual*/ void show(); + /*virtual*/ void show(bool focus); /*virtual*/ void hide(); /*virtual*/ void close(); /*virtual*/ BOOL getVisible(); @@ -65,7 +65,7 @@ class LLWindowSDL : public LLWindow /*virtual*/ BOOL setPosition(LLCoordScreen position); /*virtual*/ BOOL setSizeImpl(LLCoordScreen size); /*virtual*/ BOOL setSizeImpl(LLCoordWindow size); - /*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp = NULL); + /*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, const S32 vsync_mode, std::function stopFn, std::function restoreFn, const LLCoordScreen * const posp = NULL); /*virtual*/ BOOL setCursorPosition(LLCoordWindow position); /*virtual*/ BOOL getCursorPosition(LLCoordWindow *position); /*virtual*/ void showCursor(); @@ -92,6 +92,8 @@ class LLWindowSDL : public LLWindow /*virtual*/ BOOL setGamma(const F32 gamma); // Set the gamma /*virtual*/ U32 getFSAASamples(); /*virtual*/ void setFSAASamples(const U32 samples); + /*virtual*/ void setVsyncMode(const S32 vsync_mode); + /*virtual*/ S32 getVsyncMode(); /*virtual*/ BOOL restoreGamma(); // Restore original gamma table (before updating gamma) /*virtual*/ ESwapMethod getSwapMethod() { return mSwapMethod; } /*virtual*/ void processMiscNativeEvents(); @@ -133,8 +135,6 @@ class LLWindowSDL : public LLWindow Window mSDL_XWindowID; Display *mSDL_Display; #endif - void (*Lock_Display)(void); - void (*Unlock_Display)(void); #if LL_GTK // Lazily initialize and check the runtime GTK version for goodness. @@ -149,7 +149,7 @@ class LLWindowSDL : public LLWindow protected: LLWindowSDL(LLWindowCallbacks* callbacks, const std::string& title, int x, int y, int width, int height, U32 flags, - BOOL fullscreen, BOOL clearBg, BOOL disable_vsync, + BOOL fullscreen, BOOL clearBg, const S32 vsync_mode, BOOL ignore_pixel_depth, U32 fsaa_samples); ~LLWindowSDL(); @@ -174,7 +174,7 @@ class LLWindowSDL : public LLWindow // // create or re-create the GL context/window. Called from the constructor and switchContext(). - BOOL createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, BOOL disable_vsync); + BOOL createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, const S32 vsync_mode); void destroyContext(); void setupFailure(const std::string& text, const std::string& caption, U32 type); void fixWindowSize(void); @@ -194,6 +194,7 @@ class LLWindowSDL : public LLWindow F32 mOverrideAspectRatio; F32 mGamma; U32 mFSAASamples; + S32 mVsyncMode; int mSDLFlags; @@ -213,6 +214,7 @@ class LLWindowSDL : public LLWindow U32 mKeyScanCode; U32 mKeyVirtualKey; SDLMod mKeyModifiers; + U32 mKeySym; }; diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 78f54a7a48..ded2d827ae 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -38,9 +38,11 @@ // Linden library includes #include "llerror.h" +#include "llfasttimer.h" #include "llgl.h" #include "llstring.h" #include "lldir.h" +#include "llsdutil.h" #include "llglslshader.h" // System includes @@ -51,6 +53,7 @@ #include #include #include +#include // Require DirectInput version 8 #define DIRECTINPUT_VERSION 0x0800 @@ -58,8 +61,6 @@ #include #include -#include "llfasttimer.h" - // culled from winuser.h #ifndef WM_MOUSEWHEEL /* Added to be compatible with later SDK's */ const S32 WM_MOUSEWHEEL = 0x020A; @@ -74,6 +75,27 @@ const F32 ICON_FLASH_TIME = 0.5f; extern BOOL gDebugWindowProc; +#ifndef WM_DPICHANGED +#define WM_DPICHANGED 0x02E0 +#endif + +#ifndef DPI_ENUMS_DECLARED + +typedef enum PROCESS_DPI_AWARENESS { + PROCESS_DPI_UNAWARE = 0, + PROCESS_SYSTEM_DPI_AWARE = 1, + PROCESS_PER_MONITOR_DPI_AWARE = 2 +} PROCESS_DPI_AWARENESS; + +typedef enum MONITOR_DPI_TYPE { + MDT_EFFECTIVE_DPI = 0, + MDT_ANGULAR_DPI = 1, + MDT_RAW_DPI = 2, + MDT_DEFAULT = MDT_EFFECTIVE_DPI +} MONITOR_DPI_TYPE; + +#endif + LPWSTR gIconResource = IDI_APPLICATION; LLW32MsgCallback gAsyncMsgCallback = NULL; @@ -87,6 +109,18 @@ void show_window_creation_error(const std::string& title) LL_WARNS("Window") << title << LL_ENDL; } +HGLRC SafeCreateContext(HDC hdc) +{ + __try + { + return wglCreateContext(hdc); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + return NULL; + } +} + //static BOOL LLWindowWin32::sIsClassRegistered = FALSE; @@ -161,9 +195,8 @@ LLWinImm LLWinImm::sTheInstance; LLWinImm::LLWinImm() : mHImmDll(NULL) { // Check system metrics - if ( !GetSystemMetrics( SM_DBCSENABLED ) ) + if ( !GetSystemMetrics( SM_IMMENABLED ) ) return; - mHImmDll = LoadLibraryA("Imm32"); if (mHImmDll != NULL) @@ -205,7 +238,7 @@ LLWinImm::LLWinImm() : mHImmDll(NULL) // the case, since it is very unusual; these APIs are available from // the beginning, and all versions of IMM32.DLL should have them all. // Unfortunately, this code may be executed before initialization of - // the logging channel (llwarns), and we can't do it here... Yes, this + // the logging channel (LL_WARNS()), and we can't do it here... Yes, this // is one of disadvantages to use static constraction to DLL loading. FreeLibrary(mHImmDll); mHImmDll = NULL; @@ -363,7 +396,7 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height, U32 flags, BOOL fullscreen, BOOL clearBg, - BOOL disable_vsync, + const S32 vsync_mode, BOOL ignore_pixel_depth, U32 fsaa_samples) : LLWindow(callbacks, fullscreen, flags) @@ -384,8 +417,14 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, mKeyVirtualKey = 0; mhDC = NULL; mhRC = NULL; + mUser32Lib = nullptr; + mSHCoreLib = nullptr; - llinfos<<"Desired FSAA Samples = "<handleDPIScaleChange(this, xDPIScale, yDPIScale); } -void LLWindowWin32::show() +void LLWindowWin32::show(bool take_focus) { ShowWindow(mWindowHandle, SW_SHOW); + if (!take_focus) return; SetForegroundWindow(mWindowHandle); SetFocus(mWindowHandle); } @@ -749,7 +803,7 @@ void LLWindowWin32::close() LL_DEBUGS("Window") << "Destroying Window" << LL_ENDL; // Don't process events in our mainWindowProc any longer. - SetWindowLong(mWindowHandle, GWL_USERDATA, NULL); + SetWindowLongPtr(mWindowHandle, GWLP_USERDATA, NULL); // // Make sure we don't leave a blank toolbar button. ShowWindow(mWindowHandle, SW_HIDE); @@ -903,7 +957,7 @@ BOOL LLWindowWin32::setSizeImpl(const LLCoordWindow size) } // changing fullscreen resolution -BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp) +BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, const S32 vsync_mode, std::function stopFn, std::function restoreFn, const LLCoordScreen * const posp) { GLuint pixel_format; DEVMODE dev_mode; @@ -933,20 +987,25 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BO } gGLManager.shutdownGL(); - //destroy gl context + class ContextHandle + { + public: + ContextHandle(HGLRC context) : mOldContext(context) + {} + ~ContextHandle() + { + wglDeleteContext(mOldContext); + } + operator HGLRC() const { return mOldContext; } + private: + HGLRC mOldContext; + } oldContext = mhRC; if (mhRC) { if (!wglMakeCurrent(NULL, NULL)) { LL_WARNS("Window") << "Release of DC and RC failed" << LL_ENDL; } - - if (!wglDeleteContext(mhRC)) - { - LL_WARNS("Window") << "Release of rendering context failed" << LL_ENDL; - } - - mhRC = NULL; } if (fullscreen) @@ -1012,7 +1071,8 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BO dw_ex_style = WS_EX_APPWINDOW; dw_style = WS_POPUP; - // Move window borders out not to cover window contents + // Move window borders out not to cover window contents. + // This converts client rect to window rect, i.e. expands it by the window border size. AdjustWindowRectEx(&window_rect, dw_style, FALSE, dw_ex_style); } // If it failed, we don't want to run fullscreen @@ -1059,7 +1119,7 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BO mhInstance, NULL); - LL_INFOS("Window") << "window is created." << llendl ; + LL_INFOS("Window") << "window is created." << LL_ENDL ; //----------------------------------------------------------------------- // Create GL drawing context @@ -1092,7 +1152,7 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BO return FALSE; } - LL_INFOS("Window") << "Device context retrieved." << llendl ; + LL_INFOS("Window") << "Device context retrieved." << LL_ENDL ; if (!(pixel_format = ChoosePixelFormat(mhDC, &pfd))) { @@ -1102,7 +1162,7 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BO return FALSE; } - LL_INFOS("Window") << "Pixel format chosen." << llendl ; + LL_INFOS("Window") << "Pixel format chosen." << LL_ENDL ; // Verify what pixel format we actually received. if (!DescribePixelFormat(mhDC, pixel_format, sizeof(PIXELFORMATDESCRIPTOR), @@ -1115,35 +1175,35 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BO } // (EXP-1765) dump pixel data to see if there is a pattern that leads to unreproducible crash - LL_INFOS("Window") << "--- begin pixel format dump ---" << llendl ; - LL_INFOS("Window") << "pixel_format is " << pixel_format << llendl ; - LL_INFOS("Window") << "pfd.nSize: " << pfd.nSize << llendl ; - LL_INFOS("Window") << "pfd.nVersion: " << pfd.nVersion << llendl ; - LL_INFOS("Window") << "pfd.dwFlags: 0x" << std::hex << pfd.dwFlags << std::dec << llendl ; - LL_INFOS("Window") << "pfd.iPixelType: " << (int)pfd.iPixelType << llendl ; - LL_INFOS("Window") << "pfd.cColorBits: " << (int)pfd.cColorBits << llendl ; - LL_INFOS("Window") << "pfd.cRedBits: " << (int)pfd.cRedBits << llendl ; - LL_INFOS("Window") << "pfd.cRedShift: " << (int)pfd.cRedShift << llendl ; - LL_INFOS("Window") << "pfd.cGreenBits: " << (int)pfd.cGreenBits << llendl ; - LL_INFOS("Window") << "pfd.cGreenShift: " << (int)pfd.cGreenShift << llendl ; - LL_INFOS("Window") << "pfd.cBlueBits: " << (int)pfd.cBlueBits << llendl ; - LL_INFOS("Window") << "pfd.cBlueShift: " << (int)pfd.cBlueShift << llendl ; - LL_INFOS("Window") << "pfd.cAlphaBits: " << (int)pfd.cAlphaBits << llendl ; - LL_INFOS("Window") << "pfd.cAlphaShift: " << (int)pfd.cAlphaShift << llendl ; - LL_INFOS("Window") << "pfd.cAccumBits: " << (int)pfd.cAccumBits << llendl ; - LL_INFOS("Window") << "pfd.cAccumRedBits: " << (int)pfd.cAccumRedBits << llendl ; - LL_INFOS("Window") << "pfd.cAccumGreenBits: " << (int)pfd.cAccumGreenBits << llendl ; - LL_INFOS("Window") << "pfd.cAccumBlueBits: " << (int)pfd.cAccumBlueBits << llendl ; - LL_INFOS("Window") << "pfd.cAccumAlphaBits: " << (int)pfd.cAccumAlphaBits << llendl ; - LL_INFOS("Window") << "pfd.cDepthBits: " << (int)pfd.cDepthBits << llendl ; - LL_INFOS("Window") << "pfd.cStencilBits: " << (int)pfd.cStencilBits << llendl ; - LL_INFOS("Window") << "pfd.cAuxBuffers: " << (int)pfd.cAuxBuffers << llendl ; - LL_INFOS("Window") << "pfd.iLayerType: " << (int)pfd.iLayerType << llendl ; - LL_INFOS("Window") << "pfd.bReserved: " << (int)pfd.bReserved << llendl ; - LL_INFOS("Window") << "pfd.dwLayerMask: " << pfd.dwLayerMask << llendl ; - LL_INFOS("Window") << "pfd.dwVisibleMask: " << pfd.dwVisibleMask << llendl ; - LL_INFOS("Window") << "pfd.dwDamageMask: " << pfd.dwDamageMask << llendl ; - LL_INFOS("Window") << "--- end pixel format dump ---" << llendl ; + LL_INFOS("Window") << "--- begin pixel format dump ---" << LL_ENDL ; + LL_INFOS("Window") << "pixel_format is " << pixel_format << LL_ENDL ; + LL_INFOS("Window") << "pfd.nSize: " << pfd.nSize << LL_ENDL ; + LL_INFOS("Window") << "pfd.nVersion: " << pfd.nVersion << LL_ENDL ; + LL_INFOS("Window") << "pfd.dwFlags: 0x" << std::hex << pfd.dwFlags << std::dec << LL_ENDL ; + LL_INFOS("Window") << "pfd.iPixelType: " << (int)pfd.iPixelType << LL_ENDL ; + LL_INFOS("Window") << "pfd.cColorBits: " << (int)pfd.cColorBits << LL_ENDL ; + LL_INFOS("Window") << "pfd.cRedBits: " << (int)pfd.cRedBits << LL_ENDL ; + LL_INFOS("Window") << "pfd.cRedShift: " << (int)pfd.cRedShift << LL_ENDL ; + LL_INFOS("Window") << "pfd.cGreenBits: " << (int)pfd.cGreenBits << LL_ENDL ; + LL_INFOS("Window") << "pfd.cGreenShift: " << (int)pfd.cGreenShift << LL_ENDL ; + LL_INFOS("Window") << "pfd.cBlueBits: " << (int)pfd.cBlueBits << LL_ENDL ; + LL_INFOS("Window") << "pfd.cBlueShift: " << (int)pfd.cBlueShift << LL_ENDL ; + LL_INFOS("Window") << "pfd.cAlphaBits: " << (int)pfd.cAlphaBits << LL_ENDL ; + LL_INFOS("Window") << "pfd.cAlphaShift: " << (int)pfd.cAlphaShift << LL_ENDL ; + LL_INFOS("Window") << "pfd.cAccumBits: " << (int)pfd.cAccumBits << LL_ENDL ; + LL_INFOS("Window") << "pfd.cAccumRedBits: " << (int)pfd.cAccumRedBits << LL_ENDL ; + LL_INFOS("Window") << "pfd.cAccumGreenBits: " << (int)pfd.cAccumGreenBits << LL_ENDL ; + LL_INFOS("Window") << "pfd.cAccumBlueBits: " << (int)pfd.cAccumBlueBits << LL_ENDL ; + LL_INFOS("Window") << "pfd.cAccumAlphaBits: " << (int)pfd.cAccumAlphaBits << LL_ENDL ; + LL_INFOS("Window") << "pfd.cDepthBits: " << (int)pfd.cDepthBits << LL_ENDL ; + LL_INFOS("Window") << "pfd.cStencilBits: " << (int)pfd.cStencilBits << LL_ENDL ; + LL_INFOS("Window") << "pfd.cAuxBuffers: " << (int)pfd.cAuxBuffers << LL_ENDL ; + LL_INFOS("Window") << "pfd.iLayerType: " << (int)pfd.iLayerType << LL_ENDL ; + LL_INFOS("Window") << "pfd.bReserved: " << (int)pfd.bReserved << LL_ENDL ; + LL_INFOS("Window") << "pfd.dwLayerMask: " << pfd.dwLayerMask << LL_ENDL ; + LL_INFOS("Window") << "pfd.dwVisibleMask: " << pfd.dwVisibleMask << LL_ENDL ; + LL_INFOS("Window") << "pfd.dwDamageMask: " << pfd.dwDamageMask << LL_ENDL ; + LL_INFOS("Window") << "--- end pixel format dump ---" << LL_ENDL ; if (pfd.cColorBits < 32) { @@ -1169,7 +1229,7 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BO return FALSE; } - if (!(mhRC = wglCreateContext(mhDC))) + if (!(mhRC = SafeCreateContext(mhDC))) { close(); OSMessageBox(mCallbacks->translateString("MBGLContextErr"), @@ -1185,7 +1245,7 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BO return FALSE; } - LL_INFOS("Window") << "Drawing context is created." << llendl ; + LL_INFOS("Window") << "Drawing context is created." << LL_ENDL ; gGLManager.initWGL(); @@ -1242,7 +1302,7 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BO while(!result && mFSAASamples > 0) { - llwarns << "FSAASamples: " << mFSAASamples << " not supported." << llendl ; + LL_WARNS() << "FSAASamples: " << mFSAASamples << " not supported." << LL_ENDL ; mFSAASamples /= 2 ; //try to decrease sample pixel number until to disable anti-aliasing if(mFSAASamples < 2) @@ -1264,13 +1324,13 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BO if(result) { - llwarns << "Only support FSAASamples: " << mFSAASamples << llendl ; + LL_WARNS() << "Only support FSAASamples: " << mFSAASamples << LL_ENDL ; } } if (!result) { - llwarns << "mFSAASamples: " << mFSAASamples << llendl ; + LL_WARNS() << "mFSAASamples: " << mFSAASamples << LL_ENDL ; close(); show_window_creation_error("Error after wglChoosePixelFormatARB 32-bit"); @@ -1323,142 +1383,15 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BO LL_INFOS("Window") << "Choosing pixel formats: " << num_formats << " pixel formats returned" << LL_ENDL; } - LL_INFOS("Window") << "pixel formats done." << llendl ; - - /*for(int i = 0; i <= num_formats-1; ++i) - { - GLint query[] = { WGL_SAMPLE_BUFFERS_ARB, - WGL_SAMPLES_ARB, - WGL_NUMBER_PIXEL_FORMATS_ARB, - WGL_DRAW_TO_WINDOW_ARB, - WGL_DRAW_TO_BITMAP_ARB, - WGL_ACCELERATION_ARB, - WGL_NEED_PALETTE_ARB, - WGL_NEED_SYSTEM_PALETTE_ARB, - WGL_SWAP_LAYER_BUFFERS_ARB, - WGL_SWAP_METHOD_ARB, - WGL_NUMBER_OVERLAYS_ARB, - WGL_NUMBER_UNDERLAYS_ARB, - WGL_TRANSPARENT_ARB, - WGL_TRANSPARENT_RED_VALUE_ARB, - WGL_TRANSPARENT_GREEN_VALUE_ARB, - WGL_TRANSPARENT_BLUE_VALUE_ARB, - WGL_TRANSPARENT_ALPHA_VALUE_ARB, - WGL_TRANSPARENT_INDEX_VALUE_ARB, - WGL_SHARE_DEPTH_ARB, - WGL_SHARE_STENCIL_ARB, - WGL_SHARE_ACCUM_ARB, - WGL_SUPPORT_GDI_ARB, - WGL_SUPPORT_OPENGL_ARB, - WGL_DOUBLE_BUFFER_ARB, - WGL_STEREO_ARB, - WGL_PIXEL_TYPE_ARB, - WGL_COLOR_BITS_ARB, - WGL_RED_BITS_ARB, - WGL_RED_SHIFT_ARB, - WGL_GREEN_BITS_ARB, - WGL_GREEN_SHIFT_ARB, - WGL_BLUE_BITS_ARB, - WGL_BLUE_SHIFT_ARB, - WGL_ALPHA_BITS_ARB, - WGL_ALPHA_SHIFT_ARB, - WGL_ACCUM_BITS_ARB, - WGL_ACCUM_RED_BITS_ARB, - WGL_ACCUM_GREEN_BITS_ARB, - WGL_ACCUM_BLUE_BITS_ARB, - WGL_ACCUM_ALPHA_BITS_ARB, - WGL_DEPTH_BITS_ARB, - WGL_STENCIL_BITS_ARB, - WGL_AUX_BUFFERS_ARB}; - std::string names[] = { "WGL_SAMPLE_BUFFERS_ARB", - "WGL_SAMPLES_ARB", - "WGL_NUMBER_PIXEL_FORMATS_ARB", - "WGL_DRAW_TO_WINDOW_ARB", - "WGL_DRAW_TO_BITMAP_ARB", - "WGL_ACCELERATION_ARB", - "WGL_NEED_PALETTE_ARB", - "WGL_NEED_SYSTEM_PALETTE_ARB", - "WGL_SWAP_LAYER_BUFFERS_ARB", - "WGL_SWAP_METHOD_ARB", - "WGL_NUMBER_OVERLAYS_ARB", - "WGL_NUMBER_UNDERLAYS_ARB", - "WGL_TRANSPARENT_ARB", - "WGL_TRANSPARENT_RED_VALUE_ARB", - "WGL_TRANSPARENT_GREEN_VALUE_ARB", - "WGL_TRANSPARENT_BLUE_VALUE_ARB", - "WGL_TRANSPARENT_ALPHA_VALUE_ARB", - "WGL_TRANSPARENT_INDEX_VALUE_ARB", - "WGL_SHARE_DEPTH_ARB", - "WGL_SHARE_STENCIL_ARB", - "WGL_SHARE_ACCUM_ARB", - "WGL_SUPPORT_GDI_ARB", - "WGL_SUPPORT_OPENGL_ARB", - "WGL_DOUBLE_BUFFER_ARB", - "WGL_STEREO_ARB", - "WGL_PIXEL_TYPE_ARB", - "WGL_COLOR_BITS_ARB", - "WGL_RED_BITS_ARB", - "WGL_RED_SHIFT_ARB", - "WGL_GREEN_BITS_ARB", - "WGL_GREEN_SHIFT_ARB", - "WGL_BLUE_BITS_ARB", - "WGL_BLUE_SHIFT_ARB", - "WGL_ALPHA_BITS_ARB", - "WGL_ALPHA_SHIFT_ARB", - "WGL_ACCUM_BITS_ARB", - "WGL_ACCUM_RED_BITS_ARB", - "WGL_ACCUM_GREEN_BITS_ARB", - "WGL_ACCUM_BLUE_BITS_ARB", - "WGL_ACCUM_ALPHA_BITS_ARB", - "WGL_DEPTH_BITS_ARB", - "WGL_STENCIL_BITS_ARB", - "WGL_AUX_BUFFERS_ARB"}; - S32 results[sizeof(query)/sizeof(query[0])]={0}; - - if(wglGetPixelFormatAttribivARB(mhDC, pixel_formats[i], 0, sizeof(query)/sizeof(query[0]), query, results)) - { - llinfos << i << ":" << llendl; - for(int j = 0; j < sizeof(query)/sizeof(query[0]); ++j) - { - switch(results[j]) - { - case WGL_NO_ACCELERATION_ARB: - llinfos << " " << names[j] << " = " << "WGL_NO_ACCELERATION_ARB" << llendl; - break; - case WGL_GENERIC_ACCELERATION_ARB: - llinfos << " " << names[j] << " = " << "WGL_GENERIC_ACCELERATION_ARB" << llendl; - break; - case WGL_FULL_ACCELERATION_ARB: - llinfos << " " << names[j] << " = " << "WGL_FULL_ACCELERATION_ARB" << llendl; - break; - case WGL_SWAP_EXCHANGE_ARB: - llinfos << " " << names[j] << " = " << "WGL_SWAP_EXCHANGE_ARB" << llendl; - break; - case WGL_SWAP_COPY_ARB: - llinfos << " " << names[j] << " = " << "WGL_SWAP_COPY_ARB" << llendl; - break; - case WGL_SWAP_UNDEFINED_ARB: - llinfos << " " << names[j] << " = " << "WGL_SWAP_UNDEFINED_ARB" << llendl; - break; - case WGL_TYPE_RGBA_ARB: - llinfos << " " << names[j] << " = " << "WGL_TYPE_RGBA_ARB" << llendl; - break; - case WGL_TYPE_COLORINDEX_ARB: - llinfos << " " << names[j] << " = " << "WGL_TYPE_COLORINDEX_ARB" << llendl; - break; - default: - llinfos << " " << names[j] << " = " << results[j] << llendl; - } - - } - } - }*/ + LL_INFOS("Window") << "pixel formats done." << LL_ENDL ; //Singu note: Reversed order of this loop. Generally, choosepixelformat returns an array with the closer matches towards the start. S32 swap_method = 0; S32 cur_format = 0;//num_formats-1; GLint swap_query = WGL_SWAP_METHOD_ARB; + BOOL found_format = FALSE; + while (!found_format && wglGetPixelFormatAttribivARB(mhDC, pixel_formats[cur_format], 0, 1, &swap_query, &swap_method)) { if (swap_method == WGL_SWAP_UNDEFINED_ARB /*|| cur_format <= 0*/) @@ -1507,7 +1440,7 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BO mhInstance, NULL); - LL_INFOS("Window") << "recreate window done." << llendl ; + LL_INFOS("Window") << "recreate window done." << LL_ENDL ; if (!(mhDC = GetDC(mWindowHandle))) { @@ -1582,13 +1515,14 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BO } mhRC = 0; + bool sharedContext = false; if (wglCreateContextAttribsARB) { //attempt to create a specific versioned context S32 attribs[] = { //start at 4.2 WGL_CONTEXT_MAJOR_VERSION_ARB, 4, WGL_CONTEXT_MINOR_VERSION_ARB, 2, - WGL_CONTEXT_PROFILE_MASK_ARB, LLRender::sGLCoreProfile ? WGL_CONTEXT_CORE_PROFILE_BIT_ARB : WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, + WGL_CONTEXT_PROFILE_MASK_ARB, /*LLRender::sGLCoreProfile ? WGL_CONTEXT_CORE_PROFILE_BIT_ARB :*/ WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, WGL_CONTEXT_FLAGS_ARB, gDebugGL ? WGL_CONTEXT_DEBUG_BIT_ARB : 0, 0 }; @@ -1596,8 +1530,11 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BO bool done = false; while (!done) { - mhRC = wglCreateContextAttribsARB(mhDC, mhRC, attribs); - + sharedContext = oldContext && (mhRC = wglCreateContextAttribsARB(mhDC, oldContext, attribs)) != nullptr; + if (!sharedContext) + { + mhRC = wglCreateContextAttribsARB(mhDC, nullptr, attribs); + } if (!mhRC) { if (attribs[3] > 0) @@ -1616,8 +1553,8 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BO } else { - llinfos << "Created OpenGL " << llformat("%d.%d", attribs[1], attribs[3]) << - (LLRender::sGLCoreProfile ? " core" : " compatibility") << " context." << llendl; + LL_INFOS() << "Created OpenGL " << llformat("%d.%d", attribs[1], attribs[3]) << + (LLRender::sGLCoreProfile ? " core" : " compatibility") << " context." << LL_ENDL; done = true; if (LLRender::sGLCoreProfile) @@ -1628,7 +1565,11 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BO } } - if (!mhRC && !(mhRC = wglCreateContext(mhDC))) + bool abort = !mhRC && !(mhRC = wglCreateContext(mhDC)); + + if (!sharedContext && stopFn) stopFn(); + + if (abort) { close(); OSMessageBox(mCallbacks->translateString("MBGLContextErr"), mCallbacks->translateString("MBError"), OSMB_OK); @@ -1650,17 +1591,30 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BO } // Disable vertical sync for swap - if (disable_vsync && wglSwapIntervalEXT) - { - LL_DEBUGS("Window") << "Disabling vertical sync" << LL_ENDL; - wglSwapIntervalEXT(0); - } - else + if(wglSwapIntervalEXT) { - LL_DEBUGS("Window") << "Keeping vertical sync" << LL_ENDL; + if (vsync_mode == 0 || (!gGLManager.mHasAdaptiveVsync && vsync_mode == -1)) + { + LL_INFOS("Window") << "Disabling vertical sync" << LL_ENDL; + wglSwapIntervalEXT(0); + } + else if(vsync_mode == -1) + { + LL_INFOS("Window") << "Enabling adaptive vertical sync" << LL_ENDL; + if(wglSwapIntervalEXT(-1) == 0) + { + LL_INFOS("Window") << "Failed to enable adaptive vertical sync. Disabling vsync." << LL_ENDL; + wglSwapIntervalEXT(0); + } + } + else + { + LL_INFOS("Window") << "Enabling vertical sync" << LL_ENDL; + wglSwapIntervalEXT(1); + } } - SetWindowLong(mWindowHandle, GWL_USERDATA, (U32)this); + SetWindowLongPtr(mWindowHandle, GWLP_USERDATA, (LONG_PTR)this); // register this window as handling drag/drop events from the OS DragAcceptFiles( mWindowHandle, TRUE ); @@ -1677,13 +1631,16 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BO { show(); glClearColor(0.0f, 0.0f, 0.0f, 0.f); + gGL.syncContextState(); glClear(GL_COLOR_BUFFER_BIT); swapBuffers(); } int buf = 0; glGetIntegerv(GL_SAMPLES, &buf); - llinfos << "Acquired FSAA Samples = " << buf << llendl; + LL_INFOS() << "Acquired FSAA Samples = " << buf << LL_ENDL; + + if(restoreFn) restoreFn(!sharedContext); return TRUE; } @@ -1734,6 +1691,7 @@ BOOL LLWindowWin32::setCursorPosition(const LLCoordWindow position) return FALSE; } + // Inform the application of the new mouse position (needed for per-frame // hover/picking to function). mCallbacks->handleMouseMove(this, position.convert(), (MASK)0); @@ -1874,7 +1832,50 @@ void LLWindowWin32::initCursors() } } +void LLWindowWin32::initDPIAwareness() +{ + mUser32Lib = LoadLibrary(L"user32.dll"); + mSHCoreLib = LoadLibrary(L"Shcore.dll"); + + if (mUser32Lib && mSHCoreLib) + { + MonitorFromWindowFn = reinterpret_cast(GetProcAddress(mUser32Lib, "MonitorFromWindow")); + GetDpiForMonitorFn = reinterpret_cast(GetProcAddress(mSHCoreLib, "GetDpiForMonitor")); + + if (MonitorFromWindowFn && GetDpiForMonitorFn) + { + HRESULT(WINAPI* SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS); + SetProcessDpiAwareness = reinterpret_cast(GetProcAddress(mSHCoreLib, "SetProcessDpiAwareness")); + if (SetProcessDpiAwareness && SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE) == S_OK) + return; + + BOOL(WINAPI* SetProcessDPIAware)(void); + SetProcessDPIAware = reinterpret_cast(GetProcAddress(mUser32Lib, "SetProcessDPIAware")); + if (SetProcessDPIAware && SetProcessDPIAware()) + return; + } + } + + FreeLibrary(mUser32Lib); + FreeLibrary(mSHCoreLib); + mUser32Lib = nullptr; + mSHCoreLib = nullptr; +} +void LLWindowWin32::getDPIScales(float &xDPIScale, float& yDPIScale) +{ + xDPIScale = yDPIScale = 1.f; + if (mUser32Lib) + { + uint32_t xDPI, yDPI; + auto window = MonitorFromWindowFn(mWindowHandle, MONITOR_DEFAULTTONEAREST); + if (GetDpiForMonitorFn(window, MDT_EFFECTIVE_DPI, &xDPI, &yDPI) == S_OK) + { + xDPIScale = (float)xDPI / (float)USER_DEFAULT_SCREEN_DPI; + yDPIScale = (float)yDPI / (float)USER_DEFAULT_SCREEN_DPI; + } + } +} void LLWindowWin32::updateCursor() { @@ -1974,8 +1975,8 @@ void LLWindowWin32::gatherInput() mMousePositionModified = FALSE; } -static LLFastTimer::DeclareTimer FTM_KEYHANDLER("Handle Keyboard"); -static LLFastTimer::DeclareTimer FTM_MOUSEHANDLER("Handle Mouse"); +static LLTrace::BlockTimerStatHandle FTM_KEYHANDLER("Handle Keyboard"); +static LLTrace::BlockTimerStatHandle FTM_MOUSEHANDLER("Handle Mouse"); LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_param, LPARAM l_param) { @@ -1983,7 +1984,11 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ // This helps prevent avatar walking after maximizing the window by double-clicking the title bar. static bool sHandleLeftMouseUp = true; - LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLong(h_wnd, GWL_USERDATA); + // Ignore the double click received right after activating app. + // This is to avoid triggering double click teleport after returning focus (see MAINT-3786). + static bool sHandleDoubleClick = true; + + LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLongPtr(h_wnd, GWLP_USERDATA); // if (NULL != window_imp) @@ -2029,8 +2034,8 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_DEVICECHANGE"); if (gDebugWindowProc) { - llinfos << " WM_DEVICECHANGE: wParam=" << w_param - << "; lParam=" << l_param << llendl; + LL_INFOS() << " WM_DEVICECHANGE: wParam=" << w_param + << "; lParam=" << l_param << LL_ENDL; } if (w_param == DBT_DEVNODES_CHANGED || w_param == DBT_DEVICEARRIVAL) { @@ -2110,6 +2115,11 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ } } + if (!activating) + { + sHandleDoubleClick = false; + } + window_imp->mCallbacks->handleActivateApp(window_imp, activating); break; @@ -2197,6 +2207,9 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ window_imp->mKeyCharCode = 0; // don't know until wm_char comes in next window_imp->mKeyScanCode = ( l_param >> 16 ) & 0xff; window_imp->mKeyVirtualKey = w_param; + window_imp->mRawMsg = u_msg; + window_imp->mRawWParam = w_param; + window_imp->mRawLParam = l_param; window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_KEYDOWN"); { @@ -2219,9 +2232,12 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ { window_imp->mKeyScanCode = ( l_param >> 16 ) & 0xff; window_imp->mKeyVirtualKey = w_param; + window_imp->mRawMsg = u_msg; + window_imp->mRawWParam = w_param; + window_imp->mRawLParam = l_param; window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_KEYUP"); - LLFastTimer t2(FTM_KEYHANDLER); + LL_RECORD_BLOCK_TIME(FTM_KEYHANDLER); if (gDebugWindowProc) { @@ -2241,7 +2257,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_IME_SETCONTEXT"); if (gDebugWindowProc) { - llinfos << "WM_IME_SETCONTEXT" << llendl; + LL_INFOS() << "WM_IME_SETCONTEXT" << LL_ENDL; } if (LLWinImm::isAvailable() && window_imp->mPreeditor) { @@ -2254,7 +2270,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_IME_STARTCOMPOSITION"); if (gDebugWindowProc) { - llinfos << "WM_IME_STARTCOMPOSITION" << llendl; + LL_INFOS() << "WM_IME_STARTCOMPOSITION" << LL_ENDL; } if (LLWinImm::isAvailable() && window_imp->mPreeditor) { @@ -2267,7 +2283,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_IME_ENDCOMPOSITION"); if (gDebugWindowProc) { - llinfos << "WM_IME_ENDCOMPOSITION" << llendl; + LL_INFOS() << "WM_IME_ENDCOMPOSITION" << LL_ENDL; } if (LLWinImm::isAvailable() && window_imp->mPreeditor) { @@ -2279,7 +2295,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_IME_COMPOSITION"); if (gDebugWindowProc) { - llinfos << "WM_IME_COMPOSITION" << llendl; + LL_INFOS() << "WM_IME_COMPOSITION" << LL_ENDL; } if (LLWinImm::isAvailable() && window_imp->mPreeditor) { @@ -2292,7 +2308,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_IME_REQUEST"); if (gDebugWindowProc) { - llinfos << "WM_IME_REQUEST" << llendl; + LL_INFOS() << "WM_IME_REQUEST" << LL_ENDL; } if (LLWinImm::isAvailable() && window_imp->mPreeditor) { @@ -2306,6 +2322,9 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ case WM_CHAR: window_imp->mKeyCharCode = w_param; + window_imp->mRawMsg = u_msg; + window_imp->mRawWParam = w_param; + window_imp->mRawLParam = l_param; // Should really use WM_UNICHAR eventually, but it requires a specific Windows version and I need // to figure out how that works. - Doug @@ -2334,13 +2353,14 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_NCLBUTTONDOWN"); // A click in a non-client area, e.g. title bar or window border. sHandleLeftMouseUp = false; + sHandleDoubleClick = true; } break; case WM_LBUTTONDOWN: { window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_LBUTTONDOWN"); - LLFastTimer t2(FTM_MOUSEHANDLER); + LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); sHandleLeftMouseUp = true; if (LLWinImm::isAvailable() && window_imp->mPreeditor) @@ -2378,6 +2398,13 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ //case WM_RBUTTONDBLCLK: { window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_LBUTTONDBLCLK"); + + if (!sHandleDoubleClick) + { + sHandleDoubleClick = true; + //break; // Broke first double click every session. + } + // Because we move the cursor position in the app, we need to query // to find out where the cursor at the time the event is handled. // If we don't do this, many clicks could get buffered up, and if the @@ -2406,7 +2433,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ case WM_LBUTTONUP: { window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_LBUTTONUP"); - LLFastTimer t2(FTM_MOUSEHANDLER); + LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); if (!sHandleLeftMouseUp) { @@ -2447,7 +2474,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ case WM_RBUTTONDOWN: { window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_RBUTTONDOWN"); - LLFastTimer t2(FTM_MOUSEHANDLER); + LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); if (LLWinImm::isAvailable() && window_imp->mPreeditor) { window_imp->interruptLanguageTextInput(); @@ -2481,7 +2508,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ case WM_RBUTTONUP: { window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_RBUTTONUP"); - LLFastTimer t2(FTM_MOUSEHANDLER); + LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); // Because we move the cursor position in the app, we need to query // to find out where the cursor at the time the event is handled. // If we don't do this, many clicks could get buffered up, and if the @@ -2511,7 +2538,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ // case WM_MBUTTONDBLCLK: { window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_MBUTTONDOWN"); - LLFastTimer t2(FTM_MOUSEHANDLER); + LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); if (LLWinImm::isAvailable() && window_imp->mPreeditor) { window_imp->interruptLanguageTextInput(); @@ -2545,7 +2572,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ case WM_MBUTTONUP: { window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_MBUTTONUP"); - LLFastTimer t2(FTM_MOUSEHANDLER); + LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); // Because we move the cursor position in the llviewer app, we need to query // to find out where the cursor at the time the event is handled. // If we don't do this, many clicks could get buffered up, and if the @@ -2612,21 +2639,11 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ } return 0; } - /* - // TODO: add this after resolving _WIN32_WINNT issue - case WM_MOUSELEAVE: + case WM_MOUSELEAVE: { - window_imp->mCallbacks->handleMouseLeave(window_imp); - - // TRACKMOUSEEVENT track_mouse_event; - // track_mouse_event.cbSize = sizeof( TRACKMOUSEEVENT ); - // track_mouse_event.dwFlags = TME_LEAVE; - // track_mouse_event.hwndTrack = h_wnd; - // track_mouse_event.dwHoverTime = HOVER_DEFAULT; - // TrackMouseEvent( &track_mouse_event ); - return 0; + window_imp->mCallbacks->handleMouseLeave(window_imp); + return 0; } - */ // Handle mouse movement within the window case WM_MOUSEMOVE: { @@ -2731,6 +2748,26 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ }; return 0; + case WM_DPICHANGED: + { + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_DPICHANGED"); + if (gDebugWindowProc) + { + LL_INFOS("Window") << "WM_DPICHANGED " << LOWORD(w_param) << " " << HIWORD(w_param) << LL_ENDL; + } + LPRECT rect = (LPRECT)l_param; + S32 width = ((LPRECT)l_param)->right - ((LPRECT)l_param)->left; + S32 height = ((LPRECT)l_param)->bottom - ((LPRECT)l_param)->top; + LL_INFOS() << "rect: " << width << "x" << height << LL_ENDL; + if(window_imp->mCallbacks->handleDPIScaleChange(window_imp, + (F32)LOWORD(w_param) / (F32)USER_DEFAULT_SCREEN_DPI, + (F32)HIWORD(w_param) / (F32)USER_DEFAULT_SCREEN_DPI, + width, + height)) + SetWindowPos(h_wnd, HWND_TOP, rect->left, rect->top, rect->right - rect->left, rect->bottom - rect->top, SWP_NOZORDER | SWP_NOACTIVATE); + } + return 0; + break; } @@ -2994,13 +3031,26 @@ F32 LLWindowWin32::getGamma() BOOL LLWindowWin32::restoreGamma() { - return SetDeviceGammaRamp(mhDC, mPrevGammaRamp); + if (mCustomGammaSet != FALSE) + { + mCustomGammaSet = FALSE; + return SetDeviceGammaRamp(mhDC, mPrevGammaRamp); + } + return TRUE; } BOOL LLWindowWin32::setGamma(const F32 gamma) { mCurrentGamma = gamma; + //Get the previous gamma ramp to restore later. + if (mCustomGammaSet == FALSE) + { + if (GetDeviceGammaRamp(mhDC, mPrevGammaRamp) == FALSE) + return FALSE; + mCustomGammaSet = TRUE; + } + LL_DEBUGS("Window") << "Setting gamma to " << gamma << LL_ENDL; for ( int i = 0; i < 256; ++i ) @@ -3012,9 +3062,9 @@ BOOL LLWindowWin32::setGamma(const F32 gamma) if ( value > 0xffff ) value = 0xffff; - mCurrentGammaRamp [ 0 * 256 + i ] = - mCurrentGammaRamp [ 1 * 256 + i ] = - mCurrentGammaRamp [ 2 * 256 + i ] = ( WORD )value; + mCurrentGammaRamp[0][i] = + mCurrentGammaRamp[1][i] = + mCurrentGammaRamp[2][i] = (WORD) value; }; return SetDeviceGammaRamp ( mhDC, mCurrentGammaRamp ); @@ -3030,6 +3080,16 @@ U32 LLWindowWin32::getFSAASamples() return mFSAASamples; } +S32 LLWindowWin32::getVsyncMode() +{ + return mVsyncMode; +} + +void LLWindowWin32::setVsyncMode(const S32 vsync_mode) +{ + mVsyncMode = vsync_mode; +} + LLWindow::LLWindowResolution* LLWindowWin32::getSupportedResolutions(S32 &num_resolutions) { if (!mSupportedResolutions) @@ -3306,34 +3366,9 @@ S32 OSMessageBoxWin32(const std::string& text, const std::string& caption, U32 t return retval; } -void LLWindowWin32::ShellEx(const std::string& command ) -{ - LLWString url_wstring = utf8str_to_wstring( command ); - llutf16string url_utf16 = wstring_to_utf16str( url_wstring ); - - SHELLEXECUTEINFO sei = { sizeof( sei ) }; - sei.fMask = SEE_MASK_FLAG_DDEWAIT; - sei.nShow = SW_SHOWNORMAL; - sei.lpVerb = L"open"; - sei.lpFile = url_utf16.c_str(); - ShellExecuteEx( &sei ); -} - - void LLWindowWin32::spawnWebBrowser(const std::string& escaped_url, bool async) { - bool found = false; - S32 i; - for (i = 0; i < gURLProtocolWhitelistCount; i++) - { - if (escaped_url.find(gURLProtocolWhitelist[i]) == 0) - { - found = true; - break; - } - } - - if (!found) + if (!isWhitelistedProtocol(escaped_url)) { LL_WARNS("Window") << "spawn_web_browser() called for url with protocol not on whitelist: " << escaped_url << LL_ENDL; return; @@ -3345,26 +3380,8 @@ void LLWindowWin32::spawnWebBrowser(const std::string& escaped_url, bool async) // reliablly on Vista. // this is madness.. no, this is.. - LLWString url_wstring = utf8str_to_wstring( escaped_url ); - llutf16string url_utf16 = wstring_to_utf16str( url_wstring ); - // let the OS decide what to use to open the URL - SHELLEXECUTEINFO sei = { sizeof( sei ) }; - // NOTE: this assumes that SL will stick around long enough to complete the DDE message exchange - // necessary for ShellExecuteEx to complete - if (async) - { - sei.fMask = SEE_MASK_ASYNCOK; - } - - else - { - sei.fMask = SEE_MASK_FLAG_DDEWAIT; - } - sei.nShow = SW_SHOWNORMAL; - sei.lpVerb = L"open"; - sei.lpFile = url_utf16.c_str(); - ShellExecuteEx( &sei ); + ShellEx(escaped_url); } void LLWindowWin32::setTitle(const std::string &title) @@ -3385,6 +3402,9 @@ LLSD LLWindowWin32::getNativeKeyData() result["scan_code"] = (S32)mKeyScanCode; result["virtual_key"] = (S32)mKeyVirtualKey; + result["msg"] = ll_sd_from_U32(mRawMsg); + result["w_param"] = ll_sd_from_U32(mRawWParam); + result["l_param"] = ll_sd_from_U32(mRawLParam); return result; } @@ -3895,11 +3915,11 @@ LLWindowCallbacks::DragNDropResult LLWindowWin32::completeDragNDropRequest( cons // When it handled the message, the value to be returned from // the Window Procedure is set to *result. -BOOL LLWindowWin32::handleImeRequests(U32 request, U32 param, LRESULT *result) +BOOL LLWindowWin32::handleImeRequests(WPARAM w_param, LPARAM l_param, LRESULT *result) { if ( mPreeditor ) { - switch (request) + switch (w_param) { case IMR_CANDIDATEWINDOW: // http://msdn2.microsoft.com/en-us/library/ms776080.aspx { @@ -3907,7 +3927,7 @@ BOOL LLWindowWin32::handleImeRequests(U32 request, U32 param, LRESULT *result) LLRect preedit_bounds; mPreeditor->getPreeditLocation(-1, &caret_coord, &preedit_bounds, NULL); - CANDIDATEFORM *const form = (CANDIDATEFORM *)param; + CANDIDATEFORM *const form = (CANDIDATEFORM *)l_param; DWORD const dwIndex = form->dwIndex; fillCandidateForm(caret_coord, preedit_bounds, form); form->dwIndex = dwIndex; @@ -3917,7 +3937,7 @@ BOOL LLWindowWin32::handleImeRequests(U32 request, U32 param, LRESULT *result) } case IMR_QUERYCHARPOSITION: { - IMECHARPOSITION *const char_position = (IMECHARPOSITION *)param; + IMECHARPOSITION *const char_position = (IMECHARPOSITION *)l_param; // char_position->dwCharPos counts in number of // WCHARs, i.e., UTF-16 encoding units, so we can't simply pass the @@ -3942,7 +3962,7 @@ BOOL LLWindowWin32::handleImeRequests(U32 request, U32 param, LRESULT *result) } case IMR_COMPOSITIONFONT: { - fillCompositionLogfont((LOGFONT *)param); + fillCompositionLogfont((LOGFONT *)l_param); *result = 1; return TRUE; @@ -3957,7 +3977,7 @@ BOOL LLWindowWin32::handleImeRequests(U32 request, U32 param, LRESULT *result) S32 context_offset; const LLWString context = find_context(wtext, select, select_length, &context_offset); - RECONVERTSTRING * const reconvert_string = (RECONVERTSTRING *)param; + RECONVERTSTRING * const reconvert_string = (RECONVERTSTRING *)l_param; const U32 size = fillReconvertString(context, select - context_offset, select_length, reconvert_string); if (reconvert_string) { @@ -4007,7 +4027,7 @@ BOOL LLWindowWin32::handleImeRequests(U32 request, U32 param, LRESULT *result) context.erase(preedit, preedit_length); } - RECONVERTSTRING *reconvert_string = (RECONVERTSTRING *)param; + RECONVERTSTRING *reconvert_string = (RECONVERTSTRING *)l_param; *result = fillReconvertString(context, preedit, 0, reconvert_string); return TRUE; } diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h index 9f678b96cc..63c31a4d5c 100644 --- a/indra/llwindow/llwindowwin32.h +++ b/indra/llwindow/llwindowwin32.h @@ -27,10 +27,7 @@ #ifndef LL_LLWINDOWWIN32_H #define LL_LLWINDOWWIN32_H -// Limit Windows API to small and manageable set. -#define WIN32_LEAN_AND_MEAN -#include -#include +#include "llwin32headerslean.h" #include "llwindow.h" #include "llwindowcallbacks.h" @@ -43,7 +40,8 @@ typedef void (*LLW32MsgCallback)(const MSG &msg); class LLWindowWin32 : public LLWindow { public: - /*virtual*/ void show(); + /*virtual*/ void postInitialized(); + /*virtual*/ void show(bool focus = true); /*virtual*/ void hide(); /*virtual*/ void close(); /*virtual*/ BOOL getVisible(); @@ -59,7 +57,7 @@ class LLWindowWin32 : public LLWindow /*virtual*/ BOOL setPosition(LLCoordScreen position); /*virtual*/ BOOL setSizeImpl(LLCoordScreen size); /*virtual*/ BOOL setSizeImpl(LLCoordWindow size); - /*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp = NULL); + /*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, const S32 vsync_mode, std::function stopFn, std::function restoreFn, const LLCoordScreen * const posp = NULL); /*virtual*/ BOOL setCursorPosition(LLCoordWindow position); /*virtual*/ BOOL getCursorPosition(LLCoordWindow *position); /*virtual*/ void showCursor(); @@ -80,6 +78,8 @@ class LLWindowWin32 : public LLWindow /*virtual*/ BOOL setGamma(const F32 gamma); // Set the gamma /*virtual*/ void setFSAASamples(const U32 fsaa_samples); /*virtual*/ U32 getFSAASamples(); + /*virtual*/ void setVsyncMode(const S32 vsync_mode); + /*virtual*/ S32 getVsyncMode(); /*virtual*/ BOOL restoreGamma(); // Restore original gamma table (before updating gamma) /*virtual*/ ESwapMethod getSwapMethod() { return mSwapMethod; } /*virtual*/ void gatherInput(); @@ -109,7 +109,6 @@ class LLWindowWin32 : public LLWindow /*virtual*/ void setLanguageTextInput( const LLCoordGL & pos ); /*virtual*/ void updateLanguageTextInputArea(); /*virtual*/ void interruptLanguageTextInput(); - void ShellEx(const std::string& command); /*virtual*/ void spawnWebBrowser(const std::string& escaped_url, bool async); /*virtual*/ void setTitle(const std::string &title); @@ -121,16 +120,18 @@ class LLWindowWin32 : public LLWindow protected: LLWindowWin32(LLWindowCallbacks* callbacks, const std::string& title, const std::string& name, int x, int y, int width, int height, U32 flags, - BOOL fullscreen, BOOL clearBg, BOOL disable_vsync, + BOOL fullscreen, BOOL clearBg, const S32 vsync_mode, BOOL ignore_pixel_depth, U32 fsaa_samples); ~LLWindowWin32(); void initCursors(); void initInputDevices(); + void initDPIAwareness(); + void getDPIScales(float& xDPIScale, float& yDPIScale); HCURSOR loadColorCursor(LPCTSTR name); BOOL isValid(); void moveWindow(const LLCoordScreen& position,const LLCoordScreen& size); - LLSD getNativeKeyData(); + virtual LLSD getNativeKeyData(); // Changes display resolution. Returns true if successful BOOL setDisplayResolution(S32 width, S32 height, S32 bits, S32 refresh); @@ -150,7 +151,7 @@ class LLWindowWin32 : public LLWindow U32 fillReconvertString(const LLWString &text, S32 focus, S32 focus_length, RECONVERTSTRING *reconvert_string); void handleStartCompositionMessage(); void handleCompositionMessage(U32 indexes); - BOOL handleImeRequests(U32 request, U32 param, LRESULT *result); + BOOL handleImeRequests(WPARAM request, LPARAM param, LRESULT *result); protected: // @@ -186,8 +187,10 @@ class LLWindowWin32 : public LLWindow F32 mCurrentGamma; U32 mFSAASamples; - WORD mPrevGammaRamp[256*3]; - WORD mCurrentGammaRamp[256*3]; + S32 mVsyncMode; + WORD mPrevGammaRamp[3][256]; + WORD mCurrentGammaRamp[3][256]; + BOOL mCustomGammaSet; LPWSTR mIconResource; BOOL mMousePositionModified; @@ -212,6 +215,14 @@ class LLWindowWin32 : public LLWindow U32 mKeyCharCode; U32 mKeyScanCode; U32 mKeyVirtualKey; + U32 mRawMsg; + U32 mRawWParam; + U32 mRawLParam; + + HMODULE mUser32Lib; + HMODULE mSHCoreLib; + HMONITOR(WINAPI *MonitorFromWindowFn)(HWND, DWORD); + HRESULT(WINAPI *GetDpiForMonitorFn)(HMONITOR, INT, UINT *, UINT *); friend class LLWindowManager; }; diff --git a/indra/llxml/CMakeLists.txt b/indra/llxml/CMakeLists.txt index 535cfc0106..576fb0ffec 100644 --- a/indra/llxml/CMakeLists.txt +++ b/indra/llxml/CMakeLists.txt @@ -13,6 +13,7 @@ include_directories( ) set(llxml_SOURCE_FILES + aixml.cpp llcontrol.cpp llxmlnode.cpp llxmlparser.cpp @@ -22,6 +23,7 @@ set(llxml_SOURCE_FILES set(llxml_HEADER_FILES CMakeLists.txt + aixml.h llcontrol.h llcontrolgroupreader.h llxmlnode.h @@ -35,8 +37,10 @@ set_source_files_properties(${llxml_HEADER_FILES} list(APPEND llxml_SOURCE_FILES ${llxml_HEADER_FILES}) add_library (llxml ${llxml_SOURCE_FILES}) -add_dependencies(llxml prepare) + target_link_libraries( llxml + PUBLIC + llcommon ${EXPAT_LIBRARIES} ) diff --git a/indra/llxml/aixml.cpp b/indra/llxml/aixml.cpp new file mode 100644 index 0000000000..02b972e806 --- /dev/null +++ b/indra/llxml/aixml.cpp @@ -0,0 +1,606 @@ +/** + * @file aixml.cpp + * @brief XML serialization support. + * + * Copyright (c) 2013, Aleric Inglewood. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution. + * + * CHANGELOG + * and additional copyright holders. + * + * 30/07/2013 + * Initial version, written by Aleric Inglewood @ SL + */ + +#include "sys.h" +#include "aixml.h" +#include "llmd5.h" +#include + +//============================================================================= +// Overview + +// The AIXML* classes provide an Object Oriented way to serialize objects +// to and from an XML file. +// +// The following classes are provided: +// +// AIXMLRootElement - Write an object to a file (including XML declaration at the top). +// AIXMLElement - Write an ojbect to an ostream (just one XML element). +// +// AIXMLParser - Read and deserialize an XML file written with AIXMLRootElement. +// AIXMLElementParser - Read and deserialize an XML stream written with AIXMLElement. +// +// Classes that need to be written to and from XML would typically +// supply two member functions. For example, + +#ifdef EXAMPLE_CODE // undefined + +class HelloWorld { + public: + // Write object to XML. + void toXML(std::ostream& os, int indentation) const; + // Read object from XML. + HelloWorld(AIXMLElementParser const& parser); + + private: + // Example member variables... + Attribute1 mAttribute1; + Attribute2 mAttribute2; + // etc. + Custom1 mCustom; + std::vector mContainer; + LLDate mDate; + LLMD5 mMd5; + LLUUID mUUID; +}; + +// Typical serialization member function. +void HelloWorld::toXML(std::ostream& os, int indentation) const +{ + AIXMLElement tag(os, "helloworld", indentation); + + // Zero or more attributes: + tag.attribute("attributename1", mAttribute1); // Uses operator<<(std::ostream&, Attribute1 const&) to write mAttribute1. + tag.attribute("attributename2", mAttribute2); // Uses operator<<(std::ostream&, Attribute2 const&) to write mAttribute2. + // etc. + + // Zero or more child elements: + tag.child("tagname", mChild1); + tag.child(mCustom); // Calls mCustom.toXML() to insert the object. + tag.child(mContainer.begin(), mContainer.end()); // Calls tag.child(element) for each element of the container. + // Special allowed cases: + tag.child(mDate); // Uses "date" as tag name. + tag.child(mMd5); // Uses "md5" as tag name. + tag.child(mUUID); // Uses "uuid" as tag name. +} + +// Typical deserialization member function. +HelloWorld::HelloWorld(AIXMLElementParser const& parser) +{ + // Zero or more attributes: + parser.attribute("attributename1", "foobar"); // Throws std::runtime_error is attributename1 is missing or does not have the value "foobar". + if (!parser.attribute("attributename2", mAttribute2)) // Reads value of attributename2 into mAttribute2 (throws if it could not be parsed). + { + throw std::runtime_error("..."); // Attribute was missing. + } + + // Zero or more child elements: + parser.child("tagname", mChild1); + parser.child("custom1", mCustom); + parser.insert_children("custom2", mContainer); + // Special allowed cases: + parser.child(mDate); + parser.child(mMd5); + parser.child(mUUID); +} + +// To actually write to an XML file one would do, for example: + + LLFILE* fp = fopen(...); + AIXMLRootElement tag(fp, "rootname"); + tag.attribute("version", "1.0"); + tag.child(LLDate::now()); + tag.child(mHelloWorld); + +// And to read it again, + + AIXMLParser helloworld(filename, "description of file used for error reporting", "rootname", 1); + helloworld.attribute("version", "1.0"); + helloworld.child("helloworld", mHelloWorld); + +// Of course, both would need to be in a try { } catch block. + +#endif // EXAMPLE_CODE + +// Do NOT change these - it would break old databases. +char const* const DEFAULT_LLUUID_NAME = "uuid"; +char const* const DEFAULT_MD5STR_NAME = "md5"; +char const* const DEFAULT_LLDATE_NAME = "date"; + +std::string const DEFAULT_MD5STR_ATTRIBUTE_NAME = DEFAULT_MD5STR_NAME; +std::string const DEFAULT_LLUUID_ATTRIBUTE_NAME = DEFAULT_LLUUID_NAME; +std::string const DEFAULT_LLDATE_ATTRIBUTE_NAME = DEFAULT_LLDATE_NAME; +std::string const DEFAULT_VERSION_ATTRIBUTE_NAME = "version"; + +struct xdigit { + bool isxdigit; + xdigit(void) : isxdigit(true) { } + void operator()(char c) { isxdigit = isxdigit && std::isxdigit(c); } + operator bool() const { return isxdigit; } +}; + +static bool is_valid_md5str(std::string const& str) +{ + return str.length() == MD5HEX_STR_BYTES && std::for_each(str.begin(), str.end(), xdigit()); +} + +// Conversion routine that is a lot more strict then LLStringUtil::convertToU32. +// This version does not allow leading or trailing spaces, nor does it allow a leading minus sign. +// Leading zeroes are not allowed except a 0 by itself. +bool convertToU32strict(std::string const& str, U32& value) +{ + bool first = true; + value = 0; + for (std::string::const_iterator i = str.begin(); i != str.end(); ++i) + { + if (value == 0 && !first || !std::isdigit(*i)) // Reject leading zeroes and non-digits. + return false; + value = value * 10 + *i - '0'; + first = false; + } + return !first; // Reject empty string. +} + +typedef boost::tokenizer > boost_tokenizer; + +bool decode_version(std::string const& version, U32& major, U32& minor) +{ + boost_tokenizer tokens(version, boost::char_separator("", ".")); + boost_tokenizer::const_iterator itTok = tokens.begin(); + return itTok != tokens.end() && convertToU32strict(*itTok++, major) && + itTok != tokens.end() && *itTok++ == "." && + itTok != tokens.end() && convertToU32strict(*itTok, minor); +} + +bool md5strFromXML(LLXmlTreeNode* node, std::string& md5str_out) +{ + static LLStdStringHandle const DEFAULT_MD5STR_ATTRIBUTE_NAME_HANDLE = LLXmlTree::addAttributeString(DEFAULT_MD5STR_ATTRIBUTE_NAME); + return node->getFastAttributeString(DEFAULT_MD5STR_ATTRIBUTE_NAME_HANDLE, md5str_out) && is_valid_md5str(md5str_out); +} + +bool md5strFromXML(LLXmlTreeNode* node, std::string& md5str_out, std::string const& attribute_name) +{ + return node->getAttributeString(attribute_name, md5str_out) && is_valid_md5str(md5str_out); +} + +bool UUIDFromXML(LLXmlTreeNode* node, LLUUID& uuid_out) +{ + static LLStdStringHandle const DEFAULT_LLUUID_ATTRIBUTE_NAME_HANDLE = LLXmlTree::addAttributeString(DEFAULT_LLUUID_ATTRIBUTE_NAME); + return node->getFastAttributeUUID(DEFAULT_LLUUID_ATTRIBUTE_NAME_HANDLE, uuid_out); +} + +bool UUIDFromXML(LLXmlTreeNode* node, LLUUID& uuid_out, std::string const& attribute_name) +{ + return node->getAttributeUUID(attribute_name, uuid_out); +} + +bool dateFromXML(LLXmlTreeNode* node, LLDate& date_out) +{ + static LLStdStringHandle const DEFAULT_LLDATE_ATTRIBUTE_NAME_HANDLE = LLXmlTree::addAttributeString(DEFAULT_LLDATE_ATTRIBUTE_NAME); + std::string date_s; + return node->getFastAttributeString(DEFAULT_LLDATE_ATTRIBUTE_NAME_HANDLE, date_s) && date_out.fromString(date_s); +} + +bool dateFromXML(LLXmlTreeNode* node, LLDate& date_out, std::string const& attribute_name) +{ + std::string date_s; + return node->getAttributeString(attribute_name, date_s) && date_out.fromString(date_s); +} + +bool versionFromXML(LLXmlTreeNode* node, U32& major_out, U32& minor_out) +{ + static LLStdStringHandle const DEFAULT_VERSION_ATTRIBUTE_NAME_HANDLE = LLXmlTree::addAttributeString(DEFAULT_VERSION_ATTRIBUTE_NAME); + major_out = minor_out = 0; + std::string version_s; + return node->getFastAttributeString(DEFAULT_VERSION_ATTRIBUTE_NAME_HANDLE, version_s) && decode_version(version_s, major_out, minor_out); +} + +bool versionFromXML(LLXmlTreeNode* node, U32& major_out, U32& minor_out, std::string const& attribute_name) +{ + major_out = minor_out = 0; + std::string version_s; + return node->getAttributeString(attribute_name, version_s) && decode_version(version_s, major_out, minor_out); +} + +//----------------------------------------------------------------------------- +// AIXMLElement + +AIXMLElement::AIXMLElement(std::ostream& os, char const* name, int indentation) : + mOs(os), mName(name), mIndentation(indentation), mHasChildren(false) +{ + mOs << std::string(mIndentation, ' ') << '<' << mName; + if (!mOs.good()) + { + THROW_ALERT("AIXMLElement_Failed_to_write_DATA", AIArgs("[DATA]", "<" + mName)); + } +} + +int AIXMLElement::open_child(void) +{ + if (!mHasChildren) + { + mOs << ">\n"; + if (!mOs.good()) + { + THROW_ALERT("AIXMLElement_closing_child_Failed_to_write_DATA", AIArgs("[DATA]", ">\\n")); + } + mHasChildren = true; + } + mIndentation += 2; + return mIndentation; +} + +void AIXMLElement::close_child(void) +{ + mIndentation -= 2; +} + +AIXMLElement::~AIXMLElement() noexcept(false) +{ + if (mHasChildren) + { + mOs << std::string(mIndentation, ' ') << "\n"; + if (!mOs.good()) + { + THROW_ALERT("AIXMLElement_closing_child_Failed_to_write_DATA", + AIArgs("[DATA]", "\\n" + std::string(mIndentation, ' ') + "\\n")); + } + } + else + { + mOs << " />\n"; + if (!mOs.good()) + { + THROW_ALERT("AIXMLElement_closing_child_Failed_to_write_DATA", AIArgs("[DATA]", " />\\n")); + } + } +} + +template<> +void AIXMLElement::child(LLUUID const& element) +{ + open_child(); + write_child(DEFAULT_LLUUID_NAME, element); + close_child(); +} + +template<> +void AIXMLElement::child(LLMD5 const& element) +{ + open_child(); + write_child(DEFAULT_MD5STR_NAME, element); + close_child(); +} + +template<> +void AIXMLElement::child(LLDate const& element) +{ + open_child(); + write_child(DEFAULT_LLDATE_NAME, element); + close_child(); +} + +//----------------------------------------------------------------------------- +// AIXMLStream + +AIXMLStream::AIXMLStream(const std::string& filename, bool standalone) : mOfs(filename) +{ + mOfs << "\n"; + if (!mOfs) + { + // I don't think that errno is set to anything else but EBADF here, + // so there is not really any informative message to add here. + THROW_MALERT("AIXMLStream_fprintf_failed_to_write_xml_header"); + } +} + +AIXMLStream::~AIXMLStream() +{ + if (mOfs.is_open()) + { + mOfs.close(); + } +} + +//----------------------------------------------------------------------------- +// AIXMLParser + +AIXMLParser::AIXMLParser(std::string const& filename, char const* file_desc, std::string const& name, U32 major_version) : + AIXMLElementParser(mFilename, mFileDesc, major_version), + mFilename(filename), mFileDesc(file_desc) +{ + char const* error = NULL; + AIArgs args; + if (!mXmlTree.parseFile(filename, TRUE)) + { + error = "AIXMLParser_Cannot_parse_FILEDESC_FILENAME"; + } + else + { + mNode = mXmlTree.getRoot(); + if (!mNode) + { + error = "AIXMLParser_No_root_node_found_in_FILEDESC_FILENAME"; + } + else if (!mNode->hasName(name)) + { + error = "AIXMLParser_Missing_header_NAME_invalid_FILEDESC_FILENAME"; + args("[NAME]", name); + } + else if (!versionFromXML(mNode, mVersionMajor, mVersionMinor)) + { + error = "AIXMLParser_Invalid_or_missing_NAME_version_attribute_in_FILEDESC_FILENAME"; + args("[NAME]", name); + } + else if (mVersionMajor != major_version) + { + error = "AIXMLParser_Incompatible_NAME_version_MAJOR_MINOR_in"; + args("[NAME]", name)("[MAJOR]", llformat("%u", mVersionMajor))("[MINOR]", llformat("%u", mVersionMinor)); + } + } + if (error) + { + THROW_MALERT(error, args("[FILEDESC]", mFileDesc)("[FILENAME]", mFilename)); + } +} + +//----------------------------------------------------------------------------- +// AIXMLElementParser + +template<> +LLMD5 AIXMLElementParser::read_string(std::string const& value) const +{ + if (!is_valid_md5str(value)) + { + THROW_MALERT("AIXMLElementParser_read_string_Invalid_MD5_VALUE_in_FILEDESC_FILENAME", + AIArgs("[VALUE]", value)("[FILEDESC]", mFileDesc)("[FILENAME]", mFilename)); + } + unsigned char digest[16]; + std::memset(digest, 0, sizeof(digest)); + for (int i = 0; i < 32; ++i) + { + int x = value[i]; + digest[i >> 1] += (x - (x & 0xf0) + (x >> 6) * 9) << ((~i & 1) << 2); + } + LLMD5 result; + result.clone(digest); + return result; +} + +template<> +LLDate AIXMLElementParser::read_string(std::string const& value) const +{ + LLDate result; + result.fromString(value); + return result; +} + +template +T AIXMLElementParser::read_integer(char const* type, std::string const& value) const +{ + long long int result; + sscanf(value.c_str(),"%lld", &result); + if (result < (std::numeric_limits::min)() || result > (std::numeric_limits::max)()) + { + THROW_MALERT("AIXMLElementParser_read_integer_Invalid_TYPE_VALUE_in_FILEDESC_FILENAME", + AIArgs("[TYPE]", type)("[VALUE]", value)("FILEDESC", mFileDesc)("[FILENAME]", mFilename)); + } + return result; +} + +template<> +U8 AIXMLElementParser::read_string(std::string const& value) const +{ + return read_integer("U8", value); +} + +template<> +S8 AIXMLElementParser::read_string(std::string const& value) const +{ + return read_integer("S8", value); +} + +template<> +U16 AIXMLElementParser::read_string(std::string const& value) const +{ + return read_integer("U16", value); +} + +template<> +S16 AIXMLElementParser::read_string(std::string const& value) const +{ + return read_integer("S16", value); +} + +template<> +U32 AIXMLElementParser::read_string(std::string const& value) const +{ + return read_integer("U32", value); +} + +template<> +S32 AIXMLElementParser::read_string(std::string const& value) const +{ + return read_integer("S32", value); +} + +double read_float(std::string const& value) +{ + double result; + sscanf(value.c_str(),"%lf", &result); + return result; +} + +template<> +F32 AIXMLElementParser::read_string(std::string const& value) const +{ + return read_float(value); +} + +template<> +F64 AIXMLElementParser::read_string(std::string const& value) const +{ + return read_float(value); +} + +template<> +bool AIXMLElementParser::read_string(std::string const& value) const +{ + if (value == "true") + { + return true; + } + else if (value != "false") + { + THROW_MALERT("AIXMLElementParser_read_string_Invalid_boolean_VALUE_in_FILEDESC_FILENAME", + AIArgs("[VALUE]", value)("FILEDESC]", mFileDesc)("[FILENAME]", mFilename)); + } + return false; +} + +void AIXMLElementParser::attribute(char const* name, char const* required_value) const +{ + char const* error = NULL; + AIArgs args; + std::string value; + if (!mNode->getAttributeString(name, value)) + { + error = "AIXMLElementParser_attribute_Missing_NAME_attribute_in_NODENAME_of_FILEDESC_FILENAME"; + } + else if (value != required_value) + { + error = "AIXMLElementParser_attribute_Invalid_NAME_attribute_should_be_REQUIRED_in_NODENAME_of_FILEDESC_FILENAME"; + args("[REQUIRED]", required_value); + } + if (error) + { + THROW_MALERT(error, args("[NAME]", name)("[NODENAME]", node_name())("[FILEDESC]", mFileDesc)("[FILENAME]", mFilename)); + } +} + +template<> +LLUUID AIXMLElementParser::read_child(LLXmlTreeNode* node) const +{ + LLUUID result; + if (!LLUUID::parseUUID(node->getContents(), &result)) + { + THROW_MALERT("AIXMLElementParser_read_child_Invalid_uuid_in_FILEDESC_FILENAME", + AIArgs("[FILEDESC]", mFileDesc)("[FILENAME]", mFilename)); + } + return result; +} + +template<> +LLMD5 AIXMLElementParser::read_child(LLXmlTreeNode* node) const +{ + return read_string(node->getContents()); +} + +template<> +LLDate AIXMLElementParser::read_child(LLXmlTreeNode* node) const +{ + LLDate result; + if (!result.fromString(node->getContents())) + { + THROW_MALERT("AIXMLElementParser_read_child_Invalid_date_DATE_in_FILEDESC_FILENAME", + AIArgs("[DATE]", node->getContents())("[FILEDESC]", mFileDesc)("[FILENAME]", mFilename)); + } + return result; +} + +template<> +S8 AIXMLElementParser::read_child(LLXmlTreeNode* node) const +{ + return read_integer("S8", node->getContents()); +} + +template<> +U8 AIXMLElementParser::read_child(LLXmlTreeNode* node) const +{ + return read_integer("U8", node->getContents()); +} + +template<> +S16 AIXMLElementParser::read_child(LLXmlTreeNode* node) const +{ + return read_integer("S16", node->getContents()); +} + +template<> +U16 AIXMLElementParser::read_child(LLXmlTreeNode* node) const +{ + return read_integer("U16", node->getContents()); +} + +template<> +S32 AIXMLElementParser::read_child(LLXmlTreeNode* node) const +{ + return read_integer("S32", node->getContents()); +} + +template<> +U32 AIXMLElementParser::read_child(LLXmlTreeNode* node) const +{ + return read_integer("U32", node->getContents()); +} + +template<> +F32 AIXMLElementParser::read_child(LLXmlTreeNode* node) const +{ + return read_string(node->getContents()); +} + +template<> +F64 AIXMLElementParser::read_child(LLXmlTreeNode* node) const +{ + return read_string(node->getContents()); +} + +template<> +bool AIXMLElementParser::read_child(LLXmlTreeNode* node) const +{ + return read_string(node->getContents()); +} + +bool AIXMLElementParser::child(LLUUID& uuid) const +{ + return child(DEFAULT_LLUUID_NAME, uuid); +} + +bool AIXMLElementParser::child(LLMD5& md5) const +{ + return child(DEFAULT_MD5STR_NAME, md5); +} + +bool AIXMLElementParser::child(LLDate& date) const +{ + return child(DEFAULT_LLDATE_NAME, date); +} + diff --git a/indra/llxml/aixml.h b/indra/llxml/aixml.h new file mode 100644 index 0000000000..358eed7561 --- /dev/null +++ b/indra/llxml/aixml.h @@ -0,0 +1,375 @@ +/** + * @file aixml.h + * @brief XML serialization support. + * + * Copyright (c) 2013, Aleric Inglewood. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution. + * + * CHANGELOG + * and additional copyright holders. + * + * 30/07/2013 + * Initial version, written by Aleric Inglewood @ SL + */ + +#ifndef AIXML_H +#define AIXML_H + +#include "llxmltree.h" +#include "llxmlnode.h" +#include "llfile.h" +#include +#include "aialert.h" + +extern char const* const DEFAULT_LLUUID_NAME; +extern char const* const DEFAULT_MD5STR_NAME; +extern char const* const DEFAULT_LLDATE_NAME; + +class LLUUID; +class LLMD5; +class LLDate; + +bool md5strFromXML(LLXmlTreeNode* node, std::string& md5str_out); +bool md5strFromXML(LLXmlTreeNode* node, std::string& md5str_out, std::string const& attribute_name); +bool UUIDFromXML(LLXmlTreeNode* node, LLUUID& uuid_out); +bool UUIDFromXML(LLXmlTreeNode* node, LLUUID& uuid_out, std::string const& attribute_name); +bool dateFromXML(LLXmlTreeNode* node, LLDate& date_out); +bool dateFromXML(LLXmlTreeNode* node, LLDate& date_out, std::string const& attribute_name); +bool versionFromXML(LLXmlTreeNode* node, U32& major_out, U32& minor_out); +bool versionFromXML(LLXmlTreeNode* node, U32& major_out, U32& minor_out, std::string const& attribute_name); + +class AIXMLElement +{ + private: + std::ostream& mOs; + std::string mName; + int mIndentation; + bool mHasChildren; + + public: + AIXMLElement(std::ostream& os, char const* name, int indentation); + ~AIXMLElement() noexcept(false); + + template + void attribute(char const* name, T const& attribute); + template + void child(T const& element); + template + void child(char const* name, T const& element); + template + void child(FWD_ITERATOR i1, FWD_ITERATOR const& i2); + + private: + template + void write_child(char const* name, T const& element); + + int open_child(void); + void close_child(void); +}; + +template +void AIXMLElement::attribute(char const* name, T const& attribute) +{ + std::ostringstream raw_attribute; + raw_attribute << attribute; + mOs << ' ' << name << "=\"" << LLXMLNode::escapeXML(raw_attribute.str()) << '"'; + if (!mOs.good()) + { + std::ostringstream ss; + ss << ' ' << name << "=\"" << LLXMLNode::escapeXML(raw_attribute.str()) << '"'; + THROW_FALERT("AIXMLElement_attribute_Failed_to_write_DATA", AIArgs("[DATA]", ss.str())); + } +} + +template +void AIXMLElement::child(T const& element) +{ + open_child(); + element.toXML(mOs, mIndentation); + if (!mOs.good()) // Normally toXML will already have thrown. + { + THROW_FALERT("AIXMLElement_child_Bad_ostream"); + } + close_child(); +} + +template<> +void AIXMLElement::child(LLUUID const& element); + +template<> +void AIXMLElement::child(LLMD5 const& element); + +template<> +void AIXMLElement::child(LLDate const& element); + +template +void AIXMLElement::write_child(char const* name, T const& element) +{ + mOs << std::string(mIndentation, ' ') << '<' << name << '>' << element << "\n"; + if (!mOs.good()) + { + std::ostringstream ss; + ss << std::string(mIndentation, ' ') << '<' << name << '>' << element << "\\n"; + THROW_FALERT("AIXMLElement_write_child_Failed_to_write_DATA", AIArgs("[DATA]", ss.str())); + } +} + +template +void AIXMLElement::child(char const* name, T const& element) +{ + open_child(); + write_child(name, element); + close_child(); +} + +template +void AIXMLElement::child(FWD_ITERATOR i1, FWD_ITERATOR const& i2) +{ + while (i1 != i2) + { + child(*i1++); + } +} + +// Helper class for AIXMLRootElement. +class AIXMLStream { + protected: + llofstream mOfs; + AIXMLStream(const std::string& filename, bool standalone); + ~AIXMLStream(); +}; + +// Class to write XML files. +class AIXMLRootElement : public AIXMLStream, public AIXMLElement +{ + public: + AIXMLRootElement(const std::string& filename, char const* name, bool standalone = true) : AIXMLStream(filename, standalone), AIXMLElement(mOfs, name, 0) { } +}; + +class AIXMLElementParser +{ + private: + U32 mVersion; + std::string const& mFilename; + std::string const& mFileDesc; + + protected: + LLXmlTreeNode* mNode; + + protected: + // Used by AIXMLParser, which initializes mNode directly. + AIXMLElementParser(std::string const& filename, std::string const& file_desc, U32 version) : mVersion(version), mFilename(filename), mFileDesc(file_desc) { } + virtual ~AIXMLElementParser() { } + + // Used for error reporting. + virtual std::string node_name(void) const { return "node '" + mNode->getName() + "'"; } + + // Parse the integer given as string 'value' and return it as type T (U8, S8, U16, S16, U32 or S32). + template + T read_integer(char const* type, std::string const& value) const; + + // Parse the string 'value' and return it as type T. + template + T read_string(std::string const& value) const; + + // Parse a child node and return it as type T. + template + T read_child(LLXmlTreeNode* node) const; + + public: + // Constructor for child member functions. + AIXMLElementParser(std::string const& filename, std::string const& file_desc, U32 version, LLXmlTreeNode* node) : mVersion(version), mFilename(filename), mFileDesc(file_desc), mNode(node) { } + + // Require the existence of some attribute with given value. + void attribute(char const* name, char const* required_value) const; + + // Read attribute. Returns true if attribute was found. + template + bool attribute(char const* name, T& attribute) const; + + // Read child element. Returns true if child was found. + template + bool child(char const* name, T& child) const; + // Read Linden types. Return true if the child was found. + bool child(LLUUID& uuid) const; + bool child(LLMD5& md5) const; + bool child(LLDate& date) const; + + // Append all elements with name 'name' to container. + template + void push_back_children(char const* name, CONTAINER& container) const; + + // Insert all elements with name 'name' into container. + template + void insert_children(char const* name, CONTAINER& container) const; + + // Set version of this particular element (if not set mVersion will be the version of the parent, all the way up to the xml header with a version of 1). + void setVersion(U32 version) { mVersion = version; } + + // Accessors. + std::string const& filename(void) const { return mFilename; } + std::string const& filedesc(void) const { return mFileDesc; } + U32 version(void) const { return mVersion; } +}; + +template +inline T AIXMLElementParser::read_string(std::string const& value) const +{ + // Construct from string. + return T(value); +} + +// Specializations. + +template<> +LLMD5 AIXMLElementParser::read_string(std::string const& value) const; + +template<> +LLDate AIXMLElementParser::read_string(std::string const& value) const; + +template<> +U8 AIXMLElementParser::read_string(std::string const& value) const; + +template<> +S8 AIXMLElementParser::read_string(std::string const& value) const; + +template<> +U16 AIXMLElementParser::read_string(std::string const& value) const; + +template<> +S16 AIXMLElementParser::read_string(std::string const& value) const; + +template<> +U32 AIXMLElementParser::read_string(std::string const& value) const; + +template<> +S32 AIXMLElementParser::read_string(std::string const& value) const; + +template<> +F32 AIXMLElementParser::read_string(std::string const& value) const; + +template<> +F64 AIXMLElementParser::read_string(std::string const& value) const; + +template<> +bool AIXMLElementParser::read_string(std::string const& value) const; + + +template +bool AIXMLElementParser::attribute(char const* name, T& attribute) const +{ + std::string value; + if (!mNode->getAttributeString(name, value)) + { + return false; + } + attribute = read_string(value); + return true; +} + +template +inline T AIXMLElementParser::read_child(LLXmlTreeNode* node) const +{ + return AIXMLElementParser(mFilename, mFileDesc, mVersion, node); +} + +// Specializations. + +template<> +inline std::string AIXMLElementParser::read_child(LLXmlTreeNode* node) const +{ + return node->getContents(); +} + +template<> +LLMD5 AIXMLElementParser::read_child(LLXmlTreeNode* node) const; + +template<> +LLUUID AIXMLElementParser::read_child(LLXmlTreeNode* node) const; + +template<> +LLDate AIXMLElementParser::read_child(LLXmlTreeNode* node) const; + +template<> +S32 AIXMLElementParser::read_child(LLXmlTreeNode* node) const; + +template<> +F32 AIXMLElementParser::read_child(LLXmlTreeNode* node) const; + +template<> +bool AIXMLElementParser::read_child(LLXmlTreeNode* node) const; + + +template +bool AIXMLElementParser::child(char const* name, T& child) const +{ + LLXmlTreeNode* node = mNode->getChildByName(name); + if (!node) + { + return false; + } + child = read_child(node); + return true; +} + +template +void AIXMLElementParser::insert_children(char const* name, CONTAINER& container) const +{ + for (LLXmlTreeNode* node = mNode->getFirstChild(); node; node = mNode->getNextChild()) + { + if (!node->hasName(name)) + continue; + container.insert(read_child(node)); + } +} + +template +void AIXMLElementParser::push_back_children(char const* name, CONTAINER& container) const +{ + for (LLXmlTreeNode* node = mNode->getFirstChild(); node; node = mNode->getNextChild()) + { + if (!node->hasName(name)) + continue; + container.push_back(read_child(node)); + } +} + +// Class to read XML files. +class AIXMLParser : public AIXMLElementParser +{ + private: + std::string mFilename; + std::string mFileDesc; + + LLXmlTree mXmlTree; + U32 mVersionMajor; + U32 mVersionMinor; + + public: + AIXMLParser(std::string const& filename, char const* file_desc, std::string const& name, U32 major_version); + + U32 version_major(void) const { return mVersionMajor; } + U32 version_minor(void) const { return mVersionMinor; } + + protected: + /*virtual*/ std::string node_name(void) const { return "root node"; } +}; + +#endif // AIXML_H + diff --git a/indra/llxml/llcontrol.cpp b/indra/llxml/llcontrol.cpp index 5fa9a34302..c6f1c4cb18 100644 --- a/indra/llxml/llcontrol.cpp +++ b/indra/llxml/llcontrol.cpp @@ -181,7 +181,7 @@ LLControlVariable::LLControlVariable(const std::string& name, eControlType type, { if (mPersist && mComment.empty()) { - llerrs << "Must supply a comment for control " << mName << llendl; + LL_ERRS() << "Must supply a comment for control " << mName << LL_ENDL; } //Push back versus setValue'ing here, since we don't want to call a signal yet mValues.push_back(initial); @@ -440,7 +440,7 @@ BOOL LLControlGroup::declareControl(const std::string& name, eControlType type, } else { - llwarns << "Control named " << name << " already exists, ignoring new declaration." << llendl; + LL_WARNS() << "Control named " << name << " already exists, ignoring new declaration." << LL_ENDL; } return TRUE; } @@ -674,7 +674,7 @@ void LLControlGroup::setUntypedValue(const std::string& name, const LLSD& val) } else { - CONTROL_ERRS << "Invalid control " << name << llendl; + CONTROL_ERRS << "Invalid control " << name << LL_ENDL; } } @@ -692,14 +692,14 @@ U32 LLControlGroup::loadFromFileLegacy(const std::string& filename, BOOL require if (!xml_controls.parseFile(filename)) { - llwarns << "Unable to open control file " << filename << llendl; + LL_WARNS() << "Unable to open control file " << filename << LL_ENDL; return 0; } LLXmlTreeNode* rootp = xml_controls.getRoot(); if (!rootp || !rootp->hasAttribute("version")) { - llwarns << "No valid settings header found in control file " << filename << llendl; + LL_WARNS() << "No valid settings header found in control file " << filename << LL_ENDL; return 0; } @@ -712,7 +712,7 @@ U32 LLControlGroup::loadFromFileLegacy(const std::string& filename, BOOL require // Check file version if (version != CURRENT_VERSION) { - llinfos << filename << " does not appear to be a version " << CURRENT_VERSION << " controls file" << llendl; + LL_INFOS() << filename << " does not appear to be a version " << CURRENT_VERSION << " controls file" << LL_ENDL; return 0; } @@ -730,7 +730,7 @@ U32 LLControlGroup::loadFromFileLegacy(const std::string& filename, BOOL require if (!name.empty()) { //read in to end of line - llwarns << "LLControlGroup::loadFromFile() : Trying to set \"" << name << "\", setting doesn't exist." << llendl; + LL_WARNS() << "LLControlGroup::loadFromFile() : Trying to set \"" << name << "\", setting doesn't exist." << LL_ENDL; } child_nodep = rootp->getNextChild(); continue; @@ -895,7 +895,7 @@ U32 LLControlGroup::saveToFile(const std::string& filename, BOOL nondefault_only LLControlVariable* control = iter->second; if (!control) { - llwarns << "Tried to save invalid control: " << iter->first << llendl; + LL_WARNS() << "Tried to save invalid control: " << iter->first << LL_ENDL; } if( control && control->isPersisted() ) @@ -910,7 +910,7 @@ U32 LLControlGroup::saveToFile(const std::string& filename, BOOL nondefault_only else { // Debug spam - // llinfos << "Skipping " << control->getName() << llendl; + // LL_INFOS() << "Skipping " << control->getName() << LL_ENDL; } } } @@ -920,12 +920,12 @@ U32 LLControlGroup::saveToFile(const std::string& filename, BOOL nondefault_only { LLSDSerialize::toPrettyXML(settings, file); file.close(); - llinfos << "Saved to " << filename << llendl; + LL_INFOS() << "Saved to " << filename << LL_ENDL; } else { // This is a warning because sometime we want to use settings files which can't be written... - llwarns << "Unable to open settings file: " << filename << llendl; + LL_WARNS() << "Unable to open settings file: " << filename << LL_ENDL; return 0; } return num_saved; @@ -941,7 +941,7 @@ U32 LLControlGroup::loadFromFile(const std::string& filename, bool set_default_v infile.open(filename); if(!infile.is_open()) { - llwarns << "Cannot find file " << filename << " to load." << llendl; + LL_WARNS() << "Cannot find file " << filename << " to load." << LL_ENDL; return 0; } @@ -950,7 +950,7 @@ U32 LLControlGroup::loadFromFile(const std::string& filename, bool set_default_v if (ret <= 0) { infile.close(); - llwarns << "Unable to open LLSD control file " << filename << ". Trying Legacy Method." << llendl; + LL_WARNS() << "Unable to open LLSD control file " << filename << ". Trying Legacy Method." << LL_ENDL; return loadFromFileLegacy(filename, TRUE, TYPE_STRING); } @@ -1016,9 +1016,9 @@ U32 LLControlGroup::loadFromFile(const std::string& filename, bool set_default_v } else { - llerrs << "Mismatched type of control variable '" + LL_ERRS() << "Mismatched type of control variable '" << name << "' found while loading '" - << filename << "'." << llendl; + << filename << "'." << LL_ENDL; } } else if(existing_control->isPersisted()) @@ -1184,7 +1184,7 @@ void main() BOOL_CONTROL baz; U32 count = gGlobals.loadFromFile("controls.ini"); - llinfos << "Loaded " << count << " controls" << llendl; + LL_INFOS() << "Loaded " << count << " controls" << LL_ENDL; // test insertion foo = new LLControlVariable("gFoo", 5.f, 1.f, 20.f); @@ -1341,7 +1341,7 @@ bool convert_from_llsd(const LLSD& sd, eControlType type, const std::strin return sd.asBoolean(); else { - CONTROL_ERRS << "Invalid BOOL value for " << control_name << ": " << sd << llendl; + CONTROL_ERRS << "Invalid BOOL value for " << control_name << ": " << sd << LL_ENDL; return FALSE; } } @@ -1353,7 +1353,7 @@ S32 convert_from_llsd(const LLSD& sd, eControlType type, const std::string& return sd.asInteger(); else { - CONTROL_ERRS << "Invalid S32 value for " << control_name << ": " << sd << llendl; + CONTROL_ERRS << "Invalid S32 value for " << control_name << ": " << sd << LL_ENDL; return 0; } } @@ -1365,7 +1365,7 @@ U32 convert_from_llsd(const LLSD& sd, eControlType type, const std::string& return sd.asInteger(); else { - CONTROL_ERRS << "Invalid U32 value for " << control_name << ": " << sd << llendl; + CONTROL_ERRS << "Invalid U32 value for " << control_name << ": " << sd << LL_ENDL; return 0; } } @@ -1377,7 +1377,7 @@ F32 convert_from_llsd(const LLSD& sd, eControlType type, const std::string& return (F32) sd.asReal(); else { - CONTROL_ERRS << "Invalid F32 value for " << control_name << ": " << sd << llendl; + CONTROL_ERRS << "Invalid F32 value for " << control_name << ": " << sd << LL_ENDL; return 0.0f; } } @@ -1389,7 +1389,7 @@ std::string convert_from_llsd(const LLSD& sd, eControlType type, co return sd.asString(); else { - CONTROL_ERRS << "Invalid string value for " << control_name << ": " << sd << llendl; + CONTROL_ERRS << "Invalid string value for " << control_name << ": " << sd << LL_ENDL; return LLStringUtil::null; } } @@ -1407,7 +1407,7 @@ LLVector3 convert_from_llsd(const LLSD& sd, eControlType type, const return (LLVector3)sd; else { - CONTROL_ERRS << "Invalid LLVector3 value for " << control_name << ": " << sd << llendl; + CONTROL_ERRS << "Invalid LLVector3 value for " << control_name << ": " << sd << LL_ENDL; return LLVector3::zero; } } @@ -1419,7 +1419,7 @@ LLVector3d convert_from_llsd(const LLSD& sd, eControlType type, cons return (LLVector3d)sd; else { - CONTROL_ERRS << "Invalid LLVector3d value for " << control_name << ": " << sd << llendl; + CONTROL_ERRS << "Invalid LLVector3d value for " << control_name << ": " << sd << LL_ENDL; return LLVector3d::zero; } } @@ -1431,7 +1431,7 @@ LLRect convert_from_llsd(const LLSD& sd, eControlType type, const std::s return LLRect(sd); else { - CONTROL_ERRS << "Invalid rect value for " << control_name << ": " << sd << llendl; + CONTROL_ERRS << "Invalid rect value for " << control_name << ": " << sd << LL_ENDL; return LLRect::null; } } @@ -1445,26 +1445,26 @@ LLColor4 convert_from_llsd(const LLSD& sd, eControlType type, const st LLColor4 color(sd); if (color.mV[VRED] < 0.f || color.mV[VRED] > 1.f) { - llwarns << "Color " << control_name << " red value out of range: " << color << llendflush; + LL_WARNS() << "Color " << control_name << " red value out of range: " << color << LL_ENDL; } else if (color.mV[VGREEN] < 0.f || color.mV[VGREEN] > 1.f) { - llwarns << "Color " << control_name << " green value out of range: " << color << llendflush; + LL_WARNS() << "Color " << control_name << " green value out of range: " << color << LL_ENDL; } else if (color.mV[VBLUE] < 0.f || color.mV[VBLUE] > 1.f) { - llwarns << "Color " << control_name << " blue value out of range: " << color << llendflush; + LL_WARNS() << "Color " << control_name << " blue value out of range: " << color << LL_ENDL; } else if (color.mV[VALPHA] < 0.f || color.mV[VALPHA] > 1.f) { - llwarns << "Color " << control_name << " alpha value out of range: " << color << llendflush; + LL_WARNS() << "Color " << control_name << " alpha value out of range: " << color << LL_ENDL; } return LLColor4(sd); } else { - CONTROL_ERRS << "Control " << control_name << " not a color" << llendl; + CONTROL_ERRS << "Control " << control_name << " not a color" << LL_ENDL; return LLColor4::white; } } @@ -1476,7 +1476,7 @@ LLColor3 convert_from_llsd(const LLSD& sd, eControlType type, const st return sd; else { - CONTROL_ERRS << "Invalid LLColor3 value for " << control_name << ": " << sd << llendl; + CONTROL_ERRS << "Invalid LLColor3 value for " << control_name << ": " << sd << LL_ENDL; return LLColor3::white; } } @@ -1510,16 +1510,16 @@ void test_cached_control() static const LLCachedControl mySetting_string("TestCachedControlstring", "Default String Value"); static const LLCachedControl test_BrowserHomePage("BrowserHomePage", "hahahahahha", "Not the real comment"); -#define TEST_LLCC(T, V) if((T)mySetting_##T != V) llerrs << "Fail "#T << llendl; \ +#define TEST_LLCC(T, V) if((T)mySetting_##T != V) LL_ERRS() << "Fail "#T << LL_ENDL; \ mySetting_##T = V;\ - if((T)mySetting_##T != V) llerrs << "Fail "#T << "Pass # 2" << llendl; + if((T)mySetting_##T != V) LL_ERRS() << "Fail "#T << "Pass # 2" << LL_ENDL; TEST_LLCC(U32, 666); TEST_LLCC(S32, (S32)-666); TEST_LLCC(F32, (F32)-666.666); TEST_LLCC(bool, true); TEST_LLCC(BOOL, FALSE); - if((std::string)mySetting_string != "Default String Value") llerrs << "Fail string" << llendl; + if((std::string)mySetting_string != "Default String Value") LL_ERRS() << "Fail string" << LL_ENDL; TEST_LLCC(LLVector3, LLVector3(1.0f, 2.0f, 3.0f)); TEST_LLCC(LLVector3d, LLVector3d(6.0f, 5.0f, 4.0f)); TEST_LLCC(LLRect, LLRect(0, 0, 100, 500)); @@ -1527,7 +1527,7 @@ void test_cached_control() TEST_LLCC(LLColor3, LLColor3(1.0f, 0.f, 0.5f)); //There's no LLSD comparsion for LLCC yet. TEST_LLCC(LLSD, test_llsd); - if((std::string)test_BrowserHomePage != "http://www.singularityviewer.org") llerrs << "Fail BrowserHomePage" << llendl; + if((std::string)test_BrowserHomePage != "http://www.singularityviewer.org") LL_ERRS() << "Fail BrowserHomePage" << LL_ENDL; } #endif // TEST_CACHED_CONTROL diff --git a/indra/llxml/llcontrol.h b/indra/llxml/llcontrol.h index 4d94deb4d3..85d168b703 100644 --- a/indra/llxml/llcontrol.h +++ b/indra/llxml/llcontrol.h @@ -198,7 +198,7 @@ typedef LLPointer LLControlVariablePtr; template eControlType get_control_type() { - llwarns << "Usupported control type: " << typeid(T).name() << "." << llendl; + LL_WARNS() << "Usupported control type: " << typeid(T).name() << "." << LL_ENDL; return TYPE_COUNT; } @@ -293,7 +293,7 @@ class LLControlGroup : public LLInstanceTracker } else { - llwarns << "Control " << name << " not found." << llendl; + LL_WARNS() << "Control " << name << " not found." << LL_ENDL; return T(); } return convert_from_llsd(value, type, name); @@ -325,7 +325,7 @@ class LLControlGroup : public LLInstanceTracker } else { - llwarns << "Invalid control " << name << llendl; + LL_WARNS() << "Invalid control " << name << LL_ENDL; } } @@ -380,10 +380,10 @@ class LLControlCache : public LLRefCount, public LLInstanceTrackermap.begin(); iter != mChildren->map.end(); ++iter) { - newnode->addChild(iter->second->deepCopy()); + LLXMLNodePtr temp_ptr_for_gcc(iter->second->deepCopy()); + newnode->addChild(temp_ptr_for_gcc); } } for (LLXMLAttribList::iterator iter = mAttributes.begin(); iter != mAttributes.end(); ++iter) { - newnode->addChild(iter->second->deepCopy()); + LLXMLNodePtr temp_ptr_for_gcc(iter->second->deepCopy()); + newnode->addChild(temp_ptr_for_gcc); } return newnode; @@ -259,7 +259,7 @@ BOOL LLXMLNode::removeChild(LLXMLNode *target_child) return FALSE; } -void LLXMLNode::addChild(LLXMLNodePtr new_child, LLXMLNodePtr after_child) +void LLXMLNode::addChild(LLXMLNodePtr& new_child, LLXMLNodePtr after_child) { if (new_child->mParent != NULL) { @@ -343,8 +343,9 @@ LLXMLNodePtr LLXMLNode::createChild(const char* name, BOOL is_attribute) // virtual LLXMLNodePtr LLXMLNode::createChild(LLStringTableEntry* name, BOOL is_attribute) { - LLXMLNode* ret = new LLXMLNode(name, is_attribute); + LLXMLNodePtr ret(new LLXMLNode(name, is_attribute)); ret->mID.clear(); + addChild(ret); return ret; } @@ -358,11 +359,12 @@ BOOL LLXMLNode::deleteChild(LLXMLNode *child) return FALSE; } -void LLXMLNode::setParent(LLXMLNodePtr new_parent) +void LLXMLNode::setParent(LLXMLNodePtr& new_parent) { if (new_parent.notNull()) { - new_parent->addChild(this); + LLXMLNodePtr this_ptr(this); + new_parent->addChild(this_ptr); } else { @@ -417,7 +419,7 @@ void XMLCALL StartXMLNode(void *userData, if (NULL == parent) { - llwarns << "parent (userData) is NULL; aborting function" << llendl; + LL_WARNS() << "parent (userData) is NULL; aborting function" << LL_ENDL; return; } @@ -555,6 +557,36 @@ void XMLCALL EndXMLNode(void *userData, node->setValue(value); } } + // Singu note: moved here from XMLData. + if (LLXMLNode::sStripEscapedStrings) + { + std::string value = node->getValue(); + int len = value.length(); + if (len > 1 && value[0] == '"' && value[len - 1] == '"') + { + // Special-case: Escaped string. + std::string unescaped_string; + for (S32 pos = 1; pos < len - 1; ++pos) + { + if (value[pos] == '\\' && value[pos + 1] == '\\') + { + unescaped_string += '\\'; + ++pos; + } + else if (value[pos] == '\\' && value[pos + 1] == '"') + { + unescaped_string += '"'; + ++pos; + } + else + { + unescaped_string += value[pos]; + } + } + value += unescaped_string; + node->setValue(value); + } + } } void XMLCALL XMLData(void *userData, @@ -563,6 +595,15 @@ void XMLCALL XMLData(void *userData, { LLXMLNode* current_node = (LLXMLNode *)userData; std::string value = current_node->getValue(); +#if 0 + // Apparently also Lindens who write XML parsers can't read documentation. + // "A single block of contiguous text free of markup may still result in a sequence + // of calls to this handler. In other words, if you're searching for a pattern in + // the text, it may be split across calls to this handler." + // (http://sepp.oetiker.ch/expat-1.95.6-rs.SEPP/expat-1.95.6/doc/reference.html#XML_SetCharacterDataHandler) + // + // In other words, this is not guaranteed to work at all -- Aleric. + if (LLXMLNode::sStripEscapedStrings) { if (s[0] == '\"' && s[len-1] == '\"') @@ -591,6 +632,7 @@ void XMLCALL XMLData(void *userData, return; } } +#endif value.append(std::string(s, len)); current_node->setValue(value); } @@ -605,7 +647,7 @@ bool LLXMLNode::updateNode( if (!node || !update_node) { - llwarns << "Node invalid" << llendl; + LL_WARNS() << "Node invalid" << LL_ENDL; return FALSE; } @@ -687,7 +729,7 @@ LLXMLNodePtr LLXMLNode::replaceNode(LLXMLNodePtr node, LLXMLNodePtr update_node) { if (!node || !update_node) { - llwarns << "Node invalid" << llendl; + LL_WARNS() << "Node invalid" << LL_ENDL; return node; } @@ -714,7 +756,7 @@ bool LLXMLNode::parseFile(const std::string& filename, LLXMLNodePtr& node, LLXML return false; } fseek(fp, 0, SEEK_END); - U32 length = ftell(fp); + size_t length = ftell(fp); fseek(fp, 0, SEEK_SET); U8* buffer = new U8[length+1]; @@ -750,10 +792,10 @@ bool LLXMLNode::parseBuffer( // Do the parsing if (XML_Parse(my_parser, (const char *)buffer, length, TRUE) != XML_STATUS_OK) { - llwarns << "Error parsing xml error code: " + LL_WARNS() << "Error parsing xml error code: " << XML_ErrorString(XML_GetErrorCode(my_parser)) << " on line " << XML_GetCurrentLineNumber(my_parser) - << llendl; + << LL_ENDL; } // Deinit @@ -761,8 +803,8 @@ bool LLXMLNode::parseBuffer( if (!file_node->mChildren || file_node->mChildren->map.size() != 1) { - llwarns << "Parse failure - wrong number of top-level nodes xml." - << llendl; + LL_WARNS() << "Parse failure - wrong number of top-level nodes xml." + << LL_ENDL; node = NULL ; return false; } @@ -805,10 +847,10 @@ bool LLXMLNode::parseStream( if (XML_Parse(my_parser, (const char *)buffer, count, !str.good()) != XML_STATUS_OK) { - llwarns << "Error parsing xml error code: " + LL_WARNS() << "Error parsing xml error code: " << XML_ErrorString(XML_GetErrorCode(my_parser)) << " on lne " << XML_GetCurrentLineNumber(my_parser) - << llendl; + << LL_ENDL; break; } } @@ -820,8 +862,8 @@ bool LLXMLNode::parseStream( if (!file_node->mChildren || file_node->mChildren->map.size() != 1) { - llwarns << "Parse failure - wrong number of top-level nodes xml." - << llendl; + LL_WARNS() << "Parse failure - wrong number of top-level nodes xml." + << LL_ENDL; node = NULL; return false; } @@ -889,7 +931,7 @@ bool LLXMLNode::getLayeredXMLNode(LLXMLNodePtr& root, if (!LLXMLNode::parseFile(filename, root, NULL)) { - llwarns << "Problem reading UI description file: " << filename << llendl; + LL_WARNS() << "Problem reading UI description file: " << filename << LL_ENDL; return false; } @@ -909,7 +951,7 @@ bool LLXMLNode::getLayeredXMLNode(LLXMLNodePtr& root, if (!LLXMLNode::parseFile(layer_filename, updateRoot, NULL)) { - llwarns << "Problem reading localized UI description file: " << layer_filename << llendl; + LL_WARNS() << "Problem reading localized UI description file: " << layer_filename << LL_ENDL; return false; } @@ -948,7 +990,7 @@ void LLXMLNode::writeToFile(LLFILE *out_file, const std::string& indent, bool us size_t written = fwrite(outstring.c_str(), 1, outstring.length(), out_file); if (written != outstring.length()) { - llwarns << "Short write" << llendl; + LL_WARNS() << "Short write" << LL_ENDL; } } @@ -1199,7 +1241,8 @@ void LLXMLNode::scrubToTree(LLXMLNode *tree) std::vector::iterator itor3; for (itor3=to_delete_list.begin(); itor3!=to_delete_list.end(); ++itor3) { - (*itor3)->setParent(NULL); + LLXMLNodePtr ptr; + (*itor3)->setParent(ptr); } } } @@ -1350,7 +1393,7 @@ BOOL LLXMLNode::getAttributeU8(const char* name, U8& value ) BOOL LLXMLNode::getAttributeS8(const char* name, S8& value ) { LLXMLNodePtr node; - S32 val; + S32 val = 0; if (!(getAttribute(name, node) && node->getIntValue(1, &val))) { return false; @@ -1362,7 +1405,7 @@ BOOL LLXMLNode::getAttributeS8(const char* name, S8& value ) BOOL LLXMLNode::getAttributeU16(const char* name, U16& value ) { LLXMLNodePtr node; - U32 val; + U32 val = 0; if (!(getAttribute(name, node) && node->getUnsignedValue(1, &val))) { return false; @@ -1374,7 +1417,7 @@ BOOL LLXMLNode::getAttributeU16(const char* name, U16& value ) BOOL LLXMLNode::getAttributeS16(const char* name, S16& value ) { LLXMLNodePtr node; - S32 val; + S32 val = 0; if (!(getAttribute(name, node) && node->getIntValue(1, &val))) { return false; @@ -1784,9 +1827,9 @@ U32 LLXMLNode::getBoolValue(U32 expected_length, BOOL *array) #if LL_DEBUG if (ret_length != expected_length) { - lldebugs << "LLXMLNode::getBoolValue() failed for node named '" + LL_DEBUGS() << "LLXMLNode::getBoolValue() failed for node named '" << mName->mString << "' -- expected " << expected_length << " but " - << "only found " << ret_length << llendl; + << "only found " << ret_length << LL_ENDL; } #endif return ret_length; @@ -1805,8 +1848,8 @@ U32 LLXMLNode::getByteValue(U32 expected_length, U8 *array, Encoding encoding) if (mLength > 0 && mLength != expected_length) { - llwarns << "XMLNode::getByteValue asked for " << expected_length - << " elements, while node has " << mLength << llendl; + LL_WARNS() << "XMLNode::getByteValue asked for " << expected_length + << " elements, while node has " << mLength << LL_ENDL; return 0; } @@ -1829,7 +1872,7 @@ U32 LLXMLNode::getByteValue(U32 expected_length, U8 *array, Encoding encoding) } if (value > 255 || is_negative) { - llwarns << "getByteValue: Value outside of valid range." << llendl; + LL_WARNS() << "getByteValue: Value outside of valid range." << LL_ENDL; break; } array[i] = U8(value); @@ -1837,9 +1880,9 @@ U32 LLXMLNode::getByteValue(U32 expected_length, U8 *array, Encoding encoding) #if LL_DEBUG if (i != expected_length) { - lldebugs << "LLXMLNode::getByteValue() failed for node named '" + LL_DEBUGS() << "LLXMLNode::getByteValue() failed for node named '" << mName->mString << "' -- expected " << expected_length << " but " - << "only found " << i << llendl; + << "only found " << i << LL_ENDL; } #endif return i; @@ -1857,8 +1900,8 @@ U32 LLXMLNode::getIntValue(U32 expected_length, S32 *array, Encoding encoding) if (mLength > 0 && mLength != expected_length) { - llwarns << "XMLNode::getIntValue asked for " << expected_length - << " elements, while node has " << mLength << llendl; + LL_WARNS() << "XMLNode::getIntValue asked for " << expected_length + << " elements, while node has " << mLength << LL_ENDL; return 0; } @@ -1881,7 +1924,7 @@ U32 LLXMLNode::getIntValue(U32 expected_length, S32 *array, Encoding encoding) } if (value > 0x7fffffff) { - llwarns << "getIntValue: Value outside of valid range." << llendl; + LL_WARNS() << "getIntValue: Value outside of valid range." << LL_ENDL; break; } array[i] = S32(value) * (is_negative?-1:1); @@ -1890,9 +1933,9 @@ U32 LLXMLNode::getIntValue(U32 expected_length, S32 *array, Encoding encoding) #if LL_DEBUG if (i != expected_length) { - lldebugs << "LLXMLNode::getIntValue() failed for node named '" + LL_DEBUGS() << "LLXMLNode::getIntValue() failed for node named '" << mName->mString << "' -- expected " << expected_length << " but " - << "only found " << i << llendl; + << "only found " << i << LL_ENDL; } #endif return i; @@ -1910,8 +1953,8 @@ U32 LLXMLNode::getUnsignedValue(U32 expected_length, U32 *array, Encoding encodi if (mLength > 0 && mLength != expected_length) { - llwarns << "XMLNode::getUnsignedValue asked for " << expected_length - << " elements, while node has " << mLength << llendl; + LL_WARNS() << "XMLNode::getUnsignedValue asked for " << expected_length + << " elements, while node has " << mLength << LL_ENDL; return 0; } @@ -1935,7 +1978,7 @@ U32 LLXMLNode::getUnsignedValue(U32 expected_length, U32 *array, Encoding encodi } if (is_negative || value > 0xffffffff) { - llwarns << "getUnsignedValue: Value outside of valid range." << llendl; + LL_WARNS() << "getUnsignedValue: Value outside of valid range." << LL_ENDL; break; } array[i] = U32(value); @@ -1944,9 +1987,9 @@ U32 LLXMLNode::getUnsignedValue(U32 expected_length, U32 *array, Encoding encodi #if LL_DEBUG if (i != expected_length) { - lldebugs << "LLXMLNode::getUnsignedValue() failed for node named '" + LL_DEBUGS() << "LLXMLNode::getUnsignedValue() failed for node named '" << mName->mString << "' -- expected " << expected_length << " but " - << "only found " << i << llendl; + << "only found " << i << LL_ENDL; } #endif @@ -1965,7 +2008,7 @@ U32 LLXMLNode::getLongValue(U32 expected_length, U64 *array, Encoding encoding) if (mLength > 0 && mLength != expected_length) { - llwarns << "XMLNode::getLongValue asked for " << expected_length << " elements, while node has " << mLength << llendl; + LL_WARNS() << "XMLNode::getLongValue asked for " << expected_length << " elements, while node has " << mLength << LL_ENDL; return 0; } @@ -1989,7 +2032,7 @@ U32 LLXMLNode::getLongValue(U32 expected_length, U64 *array, Encoding encoding) } if (is_negative) { - llwarns << "getLongValue: Value outside of valid range." << llendl; + LL_WARNS() << "getLongValue: Value outside of valid range." << LL_ENDL; break; } array[i] = value; @@ -1998,9 +2041,9 @@ U32 LLXMLNode::getLongValue(U32 expected_length, U64 *array, Encoding encoding) #if LL_DEBUG if (i != expected_length) { - lldebugs << "LLXMLNode::getLongValue() failed for node named '" + LL_DEBUGS() << "LLXMLNode::getLongValue() failed for node named '" << mName->mString << "' -- expected " << expected_length << " but " - << "only found " << i << llendl; + << "only found " << i << LL_ENDL; } #endif @@ -2019,7 +2062,7 @@ U32 LLXMLNode::getFloatValue(U32 expected_length, F32 *array, Encoding encoding) if (mLength > 0 && mLength != expected_length) { - llwarns << "XMLNode::getFloatValue asked for " << expected_length << " elements, while node has " << mLength << llendl; + LL_WARNS() << "XMLNode::getFloatValue asked for " << expected_length << " elements, while node has " << mLength << LL_ENDL; return 0; } @@ -2044,9 +2087,9 @@ U32 LLXMLNode::getFloatValue(U32 expected_length, F32 *array, Encoding encoding) #if LL_DEBUG if (i != expected_length) { - lldebugs << "LLXMLNode::getFloatValue() failed for node named '" + LL_DEBUGS() << "LLXMLNode::getFloatValue() failed for node named '" << mName->mString << "' -- expected " << expected_length << " but " - << "only found " << i << llendl; + << "only found " << i << LL_ENDL; } #endif return i; @@ -2064,7 +2107,7 @@ U32 LLXMLNode::getDoubleValue(U32 expected_length, F64 *array, Encoding encoding if (mLength > 0 && mLength != expected_length) { - llwarns << "XMLNode::getDoubleValue asked for " << expected_length << " elements, while node has " << mLength << llendl; + LL_WARNS() << "XMLNode::getDoubleValue asked for " << expected_length << " elements, while node has " << mLength << LL_ENDL; return 0; } @@ -2089,9 +2132,9 @@ U32 LLXMLNode::getDoubleValue(U32 expected_length, F64 *array, Encoding encoding #if LL_DEBUG if (i != expected_length) { - lldebugs << "LLXMLNode::getDoubleValue() failed for node named '" + LL_DEBUGS() << "LLXMLNode::getDoubleValue() failed for node named '" << mName->mString << "' -- expected " << expected_length << " but " - << "only found " << i << llendl; + << "only found " << i << LL_ENDL; } #endif return i; @@ -2105,7 +2148,7 @@ U32 LLXMLNode::getStringValue(U32 expected_length, std::string *array) if (mLength > 0 && mLength != expected_length) { - llwarns << "XMLNode::getStringValue asked for " << expected_length << " elements, while node has " << mLength << llendl; + LL_WARNS() << "XMLNode::getStringValue asked for " << expected_length << " elements, while node has " << mLength << LL_ENDL; return 0; } @@ -2137,9 +2180,9 @@ U32 LLXMLNode::getStringValue(U32 expected_length, std::string *array) #if LL_DEBUG if (num_returned_strings != expected_length) { - lldebugs << "LLXMLNode::getStringValue() failed for node named '" + LL_DEBUGS() << "LLXMLNode::getStringValue() failed for node named '" << mName->mString << "' -- expected " << expected_length << " but " - << "only found " << num_returned_strings << llendl; + << "only found " << num_returned_strings << LL_ENDL; } #endif @@ -2182,9 +2225,9 @@ U32 LLXMLNode::getUUIDValue(U32 expected_length, LLUUID *array) #if LL_DEBUG if (i != expected_length) { - lldebugs << "LLXMLNode::getUUIDValue() failed for node named '" + LL_DEBUGS() << "LLXMLNode::getUUIDValue() failed for node named '" << mName->mString << "' -- expected " << expected_length << " but " - << "only found " << i << llendl; + << "only found " << i << LL_ENDL; } #endif return i; @@ -2213,11 +2256,11 @@ U32 LLXMLNode::getNodeRefValue(U32 expected_length, LLXMLNode **array) root->findID(string_array[strnum], node_list); if (node_list.empty()) { - llwarns << "XML: Could not find node ID: " << string_array[strnum] << llendl; + LL_WARNS() << "XML: Could not find node ID: " << string_array[strnum] << LL_ENDL; } else if (node_list.size() > 1) { - llwarns << "XML: Node ID not unique: " << string_array[strnum] << llendl; + LL_WARNS() << "XML: Node ID not unique: " << string_array[strnum] << LL_ENDL; } else { @@ -2747,7 +2790,8 @@ void LLXMLNode::setName(LLStringTableEntry* name) mName = name; if (old_parent) { - old_parent->addChild(this); + LLXMLNodePtr this_ptr(this); + old_parent->addChild(this_ptr); } } diff --git a/indra/llxml/llxmlnode.h b/indra/llxml/llxmlnode.h index 78572603d6..b9eb429ff7 100644 --- a/indra/llxml/llxmlnode.h +++ b/indra/llxml/llxmlnode.h @@ -50,7 +50,6 @@ #include "llstringtable.h" #include "llfile.h" - class LLVector3; class LLVector3d; class LLQuaternion; @@ -133,8 +132,8 @@ class LLXMLNode : public LLThreadSafeRefCount BOOL isNull(); BOOL deleteChild(LLXMLNode* child); - void addChild(LLXMLNodePtr new_child, LLXMLNodePtr after_child = LLXMLNodePtr(NULL)); - void setParent(LLXMLNodePtr new_parent); // reparent if necessary + void addChild(LLXMLNodePtr& new_child, LLXMLNodePtr after_child = LLXMLNodePtr(NULL)); + void setParent(LLXMLNodePtr& new_parent); // reparent if necessary // Serialization static bool parseFile( @@ -157,11 +156,11 @@ class LLXMLNode : public LLThreadSafeRefCount static bool getLayeredXMLNode(LLXMLNodePtr& root, const std::vector& paths); - + // Write standard XML file header: // static void writeHeaderToFile(LLFILE *out_file); - + // Write XML to file with one attribute per line. // XML escapes values as they are written. void writeToFile(LLFILE *out_file, const std::string& indent = std::string(), bool use_type_decorations=true); @@ -330,7 +329,11 @@ class LLXMLNode : public LLThreadSafeRefCount protected: LLStringTableEntry *mName; // The name of this node - std::string mValue; // The value of this node (use getters/setters only) + + // The value of this node (use getters/setters only) + // Values are not XML-escaped in memory + // They may contain " (quot) ' (apos) & (amp) < (lt) > (gt) + std::string mValue; LLXMLNodePtr mDefault; // Mirror node in the default tree diff --git a/indra/llxml/llxmlparser.cpp b/indra/llxml/llxmlparser.cpp index 7d887f4ff2..cc5399efe1 100644 --- a/indra/llxml/llxmlparser.cpp +++ b/indra/llxml/llxmlparser.cpp @@ -89,7 +89,7 @@ BOOL LLXmlParser::parseFile(const std::string &path) S32 bytes_read = 0; fseek(file, 0L, SEEK_END); - S32 buffer_size = ftell(file); + size_t buffer_size = ftell(file); fseek(file, 0L, SEEK_SET); void* buffer = XML_GetBuffer(mParser, buffer_size); @@ -127,7 +127,7 @@ BOOL LLXmlParser::parseFile(const std::string &path) if( !success ) { - llwarns << mAuxErrorString << llendl; + LL_WARNS() << mAuxErrorString << LL_ENDL; } return success; diff --git a/indra/llxml/llxmltree.cpp b/indra/llxml/llxmltree.cpp index 90bec6903a..0ba7375b45 100644 --- a/indra/llxml/llxmltree.cpp +++ b/indra/llxml/llxmltree.cpp @@ -73,7 +73,7 @@ BOOL LLXmlTree::parseFile(const std::string &path, BOOL keep_contents) { S32 line_number = parser.getCurrentLineNumber(); const char* error = parser.getErrorString(); - llwarns << "LLXmlTree parse failed. Line " << line_number << ": " << error << llendl; + LL_WARNS() << "LLXmlTree parse failed. Line " << line_number << ": " << error << LL_ENDL; } return success; } @@ -95,7 +95,7 @@ bool LLXmlTree::parseBuffer(const char *buf, int len) if (!success) { S32 line_number = mParser->getCurrentLineNumber(); const char* error = mParser->getErrorString(); - llwarns << "LLXmlTree parse failed in line " << line_number << ": " << error << llendl; + LL_WARNS() << "LLXmlTree parse failed in line " << line_number << ": " << error << LL_ENDL; delete mParser; mParser = 0; } @@ -171,19 +171,19 @@ LLXmlTreeNode::~LLXmlTreeNode() void LLXmlTreeNode::dump( const std::string& prefix ) { - llinfos << prefix << mName ; + LL_INFOS() << prefix << mName ; if( !mContents.empty() ) { - llcont << " contents = \"" << mContents << "\""; + LL_CONT << " contents = \"" << mContents << "\""; } attribute_map_t::iterator iter; for (iter=mAttributes.begin(); iter != mAttributes.end(); iter++) { LLStdStringHandle key = iter->first; const std::string* value = iter->second; - llcont << prefix << " " << key << "=" << (value->empty() ? "NULL" : *value); + LL_CONT << prefix << " " << key << "=" << (value->empty() ? "NULL" : *value); } - llcont << llendl; + LL_CONT << LL_ENDL; } void LLXmlTreeNode::writeNoChild(std::string &buffer, const std::string &indent) const @@ -666,12 +666,12 @@ void LLXmlTreeParser::startElement(const char* name, const char **atts) { if( mDump ) { - llinfos << tabs() << "startElement " << name << llendl; + LL_INFOS() << tabs() << "startElement " << name << LL_ENDL; S32 i = 0; while( atts[i] && atts[i+1] ) { - llinfos << tabs() << "attribute: " << atts[i] << "=" << atts[i+1] << llendl; + LL_INFOS() << tabs() << "attribute: " << atts[i] << "=" << atts[i+1] << LL_ENDL; i += 2; } } @@ -708,7 +708,7 @@ void LLXmlTreeParser::endElement(const char* name) { if( mDump ) { - llinfos << tabs() << "endElement " << name << llendl; + LL_INFOS() << tabs() << "endElement " << name << LL_ENDL; } if( !mCurrent->mContents.empty() ) @@ -726,7 +726,7 @@ void LLXmlTreeParser::characterData(const char *s, int len) if (s) str = std::string(s, len); if( mDump ) { - llinfos << tabs() << "CharacterData " << str << llendl; + LL_INFOS() << tabs() << "CharacterData " << str << LL_ENDL; } if (mKeepContents) @@ -739,7 +739,7 @@ void LLXmlTreeParser::processingInstruction(const char *target, const char *data { if( mDump ) { - llinfos << tabs() << "processingInstruction " << data << llendl; + LL_INFOS() << tabs() << "processingInstruction " << data << LL_ENDL; } } @@ -747,7 +747,7 @@ void LLXmlTreeParser::comment(const char *data) { if( mDump ) { - llinfos << tabs() << "comment " << data << llendl; + LL_INFOS() << tabs() << "comment " << data << LL_ENDL; } } @@ -755,7 +755,7 @@ void LLXmlTreeParser::startCdataSection() { if( mDump ) { - llinfos << tabs() << "startCdataSection" << llendl; + LL_INFOS() << tabs() << "startCdataSection" << LL_ENDL; } } @@ -763,7 +763,7 @@ void LLXmlTreeParser::endCdataSection() { if( mDump ) { - llinfos << tabs() << "endCdataSection" << llendl; + LL_INFOS() << tabs() << "endCdataSection" << LL_ENDL; } } @@ -773,7 +773,7 @@ void LLXmlTreeParser::defaultData(const char *s, int len) { std::string str; if (s) str = std::string(s, len); - llinfos << tabs() << "defaultData " << str << llendl; + LL_INFOS() << tabs() << "defaultData " << str << LL_ENDL; } } @@ -786,12 +786,12 @@ void LLXmlTreeParser::unparsedEntityDecl( { if( mDump ) { - llinfos << tabs() << "unparsed entity:" << llendl; - llinfos << tabs() << " entityName " << entity_name << llendl; - llinfos << tabs() << " base " << base << llendl; - llinfos << tabs() << " systemId " << system_id << llendl; - llinfos << tabs() << " publicId " << public_id << llendl; - llinfos << tabs() << " notationName " << notation_name<< llendl; + LL_INFOS() << tabs() << "unparsed entity:" << LL_ENDL; + LL_INFOS() << tabs() << " entityName " << entity_name << LL_ENDL; + LL_INFOS() << tabs() << " base " << base << LL_ENDL; + LL_INFOS() << tabs() << " systemId " << system_id << LL_ENDL; + LL_INFOS() << tabs() << " publicId " << public_id << LL_ENDL; + LL_INFOS() << tabs() << " notationName " << notation_name<< LL_ENDL; } } diff --git a/indra/llxml/llxmltree.h b/indra/llxml/llxmltree.h index 9b0f2492f1..1ff917a982 100644 --- a/indra/llxml/llxmltree.h +++ b/indra/llxml/llxmltree.h @@ -32,7 +32,7 @@ #include #include "llstring.h" #include "llxmlparser.h" -#include "string_table.h" +#include "llstringtable.h" class LLColor4; class LLColor4U; diff --git a/indra/lscript/lscript_byteconvert.h b/indra/lscript/lscript_byteconvert.h index aa8c7ffb45..4cc118fab2 100644 --- a/indra/lscript/lscript_byteconvert.h +++ b/indra/lscript/lscript_byteconvert.h @@ -136,7 +136,7 @@ inline F32 bytestream2float(const U8 *stream, S32 &offset) { S32 value = bytestream2integer(stream, offset); F32 fpvalue = *(F32 *)&value; - if (!llfinite(fpvalue)) + if (!std::isfinite(fpvalue)) { fpvalue = 0; set_fault(stream, LSRF_MATH); @@ -155,7 +155,7 @@ inline void bytestream_int2float(U8 *stream, S32 &offset) S32 value = bytestream2integer(stream, offset); offset -= 4; F32 fpvalue = (F32)value; - if (!llfinite(fpvalue)) + if (!std::isfinite(fpvalue)) { fpvalue = 0; set_fault(stream, LSRF_MATH); @@ -230,21 +230,21 @@ inline void bytestream2vector(LLVector3 &vector, const U8 *stream, S32 &offset) { S32 value = bytestream2integer(stream, offset); vector.mV[VZ] = *(F32 *)&value; - if (!llfinite(vector.mV[VZ])) + if (!std::isfinite(vector.mV[VZ])) { vector.mV[VZ] = 0; set_fault(stream, LSRF_MATH); } value = bytestream2integer(stream, offset); vector.mV[VY] = *(F32 *)&value; - if (!llfinite(vector.mV[VY])) + if (!std::isfinite(vector.mV[VY])) { vector.mV[VY] = 0; set_fault(stream, LSRF_MATH); } value = bytestream2integer(stream, offset); vector.mV[VX] = *(F32 *)&value; - if (!llfinite(vector.mV[VX])) + if (!std::isfinite(vector.mV[VX])) { vector.mV[VX] = 0; set_fault(stream, LSRF_MATH); @@ -265,28 +265,28 @@ inline void bytestream2quaternion(LLQuaternion &quat, const U8 *stream, S32 &off { S32 value = bytestream2integer(stream, offset); quat.mQ[VS] = *(F32 *)&value; - if (!llfinite(quat.mQ[VS])) + if (!std::isfinite(quat.mQ[VS])) { quat.mQ[VS] = 0; set_fault(stream, LSRF_MATH); } value = bytestream2integer(stream, offset); quat.mQ[VZ] = *(F32 *)&value; - if (!llfinite(quat.mQ[VZ])) + if (!std::isfinite(quat.mQ[VZ])) { quat.mQ[VZ] = 0; set_fault(stream, LSRF_MATH); } value = bytestream2integer(stream, offset); quat.mQ[VY] = *(F32 *)&value; - if (!llfinite(quat.mQ[VY])) + if (!std::isfinite(quat.mQ[VY])) { quat.mQ[VY] = 0; set_fault(stream, LSRF_MATH); } value = bytestream2integer(stream, offset); quat.mQ[VX] = *(F32 *)&value; - if (!llfinite(quat.mQ[VX])) + if (!std::isfinite(quat.mQ[VX])) { quat.mQ[VX] = 0; set_fault(stream, LSRF_MATH); @@ -315,7 +315,7 @@ inline F32 get_register_fp(U8 *stream, LSCRIPTRegisters reg) { S32 offset = gLSCRIPTRegisterAddresses[reg]; F32 value = bytestream2float(stream, offset); - if (!llfinite(value)) + if (!std::isfinite(value)) { value = 0; set_fault(stream, LSRF_MATH); @@ -390,7 +390,7 @@ inline F32 add_register_fp(U8 *stream, LSCRIPTRegisters reg, F32 value) S32 offset = gLSCRIPTRegisterAddresses[reg]; F32 newvalue = bytestream2float(stream, offset); newvalue += value; - if (!llfinite(newvalue)) + if (!std::isfinite(newvalue)) { newvalue = 0; set_fault(stream, LSRF_MATH); @@ -587,7 +587,7 @@ inline F32 lscript_pop_float(U8 *stream) { S32 sp = get_register(stream, LREG_SP); F32 value = bytestream2float(stream, sp); - if (!llfinite(value)) + if (!std::isfinite(value)) { value = 0; set_fault(stream, LSRF_MATH); @@ -727,7 +727,7 @@ inline void lscript_local_get(U8 *stream, S32 address, F32 &value) { if (lscript_check_local(stream, address, LSCRIPTDataSize[LST_FLOATINGPOINT])) value = bytestream2float(stream, address); - if (!llfinite(value)) + if (!std::isfinite(value)) { value = 0; set_fault(stream, LSRF_MATH); @@ -757,7 +757,7 @@ inline void lscript_global_get(U8 *stream, S32 address, F32 &value) { if (lscript_check_global(stream, address, LSCRIPTDataSize[LST_FLOATINGPOINT])) value = bytestream2float(stream, address); - if (!llfinite(value)) + if (!std::isfinite(value)) { value = 0; set_fault(stream, LSRF_MATH); @@ -1058,7 +1058,7 @@ inline F32 safe_instruction_bytestream2float(U8 *stream, S32 &offset) if (safe_instruction_check_address(stream, offset, LSCRIPTDataSize[LST_INTEGER])) { F32 value = bytestream2float(stream, offset); - if (!llfinite(value)) + if (!std::isfinite(value)) { value = 0; set_fault(stream, LSRF_MATH); diff --git a/indra/lscript/lscript_byteformat.h b/indra/lscript/lscript_byteformat.h index 49e78e7176..679714e590 100644 --- a/indra/lscript/lscript_byteformat.h +++ b/indra/lscript/lscript_byteformat.h @@ -355,6 +355,10 @@ typedef enum e_lscript_state_event_type LSTT_REMOTE_DATA, LSTT_HTTP_RESPONSE, LSTT_HTTP_REQUEST, + LSTT_EXPERMISSIONS, + LSTT_TRANSACTION_RESULT, + LSTT_PATH_UPDATE, + LSTT_EXPERMISSIONS_DENIED, LSTT_EOF, LSTT_STATE_BEGIN = LSTT_STATE_ENTRY, @@ -397,7 +401,11 @@ const U64 LSCRIPTStateBitField[LSTT_EOF] = 0x0000000040000000, // LSTT_OBJECT_REZ 0x0000000080000000, // LSTT_REMOTE_DATA 0x0000000100000000LL, // LSTT_HTTP_RESPOSE - 0x0000000200000000LL // LSTT_HTTP_REQUEST + 0x0000000200000000LL, // LSTT_HTTP_REQUEST + 0x0000000400000000LL, // LSTT_EXPERMISSIONS + 0x0000000800000000LL, // LSTT_TRANSACTION_RESULT + 0x0000001000000000LL, // LSTT_PATH_UPDATE + 0x0000002000000000LL, //LSTT_EXPERMISSIONS_DENIED }; inline S32 get_event_handler_jump_position(U64 bit_field, LSCRIPTStateEventType type) @@ -511,6 +519,7 @@ typedef enum e_lscript_runtime_faults LSRF_TOO_MANY_LISTENS, LSRF_NESTING_LISTS, LSRF_CLI, + LSRF_INVALID_STATE, LSRF_EOF } LSCRIPTRunTimeFaults; @@ -551,10 +560,10 @@ const U32 LSCRIPTRunTimePermissionBits[SCRIPT_PERMISSION_EOF] = (0x1 << 10),// SCRIPT_PERMISSION_TRACK_CAMERA (0x1 << 11),// SCRIPT_PERMISSION_CONTROL_CAMERA (0x1 << 12),// SCRIPT_PERMISSION_TELEPORT - (0x1 << 13),// SCRIPT_PERMISSION_EXPERIENCE, - (0x1 << 14),// SCRIPT_PERMISSION_SILENT_ESTATE_MANAGEMENT, - (0x1 << 15),// SCRIPT_PERMISSION_OVERRIDE_ANIMATIONS, - (0x1 << 16),// SCRIPT_PERMISSION_RETURN_OBJECTS, + (0x1 << 13),// SCRIPT_PERMISSION_EXPERIENCE + (0x1 << 14),// SCRIPT_PERMISSION_SILENT_ESTATE_MANAGEMENT + (0x1 << 15),// SCRIPT_PERMISSION_OVERRIDE_ANIMATIONS + (0x1 << 16),// SCRIPT_PERMISSION_RETURN_OBJECTS }; // http_request string constants diff --git a/indra/lscript/lscript_compile/indra.l b/indra/lscript/lscript_compile/indra.l index d7d591cc5a..3fb834d17e 100644 --- a/indra/lscript/lscript_compile/indra.l +++ b/indra/lscript/lscript_compile/indra.l @@ -594,7 +594,8 @@ void parse_string(); "REGION_FLAG_SANDBOX" { count(); yylval.ival = REGION_FLAGS_SANDBOX; return(INTEGER_CONSTANT); } "REGION_FLAG_DISABLE_COLLISIONS" { count(); yylval.ival = REGION_FLAGS_SKIP_COLLISIONS; return(INTEGER_CONSTANT); } "REGION_FLAG_DISABLE_PHYSICS" { count(); yylval.ival = REGION_FLAGS_SKIP_PHYSICS; return(INTEGER_CONSTANT); } -"REGION_FLAG_BLOCK_FLY" { count(); yylval.ival = REGION_FLAGS_BLOCK_FLY; return(INTEGER_CONSTANT); } +"REGION_FLAG_BLOCK_FLY" { count(); yylval.ival = REGION_FLAGS_BLOCK_FLY; return(INTEGER_CONSTANT); } +"REGION_FLAG_BLOCK_FLYOVER" { count(); yylval.ival = REGION_FLAGS_BLOCK_FLYOVER; return(INTEGER_CONSTANT); } "REGION_FLAG_ALLOW_DIRECT_TELEPORT" { count(); yylval.ival = REGION_FLAGS_ALLOW_DIRECT_TELEPORT; return(INTEGER_CONSTANT); } "REGION_FLAG_RESTRICT_PUSHOBJECT" { count(); yylval.ival = REGION_FLAGS_RESTRICT_PUSHOBJECT; return(INTEGER_CONSTANT); } @@ -684,6 +685,23 @@ void parse_string(); "STATUS_INTERNAL_ERROR" { count(); yylval.ival = LSL_STATUS_INTERNAL_ERROR; return(INTEGER_CONSTANT); } "STATUS_WHITELIST_FAILED" { count(); yylval.ival = LSL_STATUS_WHITELIST_FAILED; return(INTEGER_CONSTANT); } +"XP_ERROR_NONE" { const char* sval= "no error"; yylval.sval = new char[strlen(sval)+1]; strcpy(yylval.sval, sval); return(STRING_CONSTANT); } +"XP_ERROR_THROTTLED" { const char* sval= "exceeded throttle"; yylval.sval = new char[strlen(sval)+1]; strcpy(yylval.sval, sval); return(STRING_CONSTANT); } +"XP_ERROR_EXPERIENCES_DISABLED" { const char* sval= "experiences are disabled"; yylval.sval = new char[strlen(sval)+1]; strcpy(yylval.sval, sval); return(STRING_CONSTANT); } +"XP_ERROR_INVALID_PARAMETERS" { const char* sval= "invalid parameters"; yylval.sval = new char[strlen(sval)+1]; strcpy(yylval.sval, sval); return(STRING_CONSTANT); } +"XP_ERROR_NOT_PERMITTED" { const char* sval= "operation not permitted"; yylval.sval = new char[strlen(sval)+1]; strcpy(yylval.sval, sval); return(STRING_CONSTANT); } +"XP_ERROR_NO_EXPERIENCE" { const char* sval= "script not associated with an experience";yylval.sval = new char[strlen(sval)+1]; strcpy(yylval.sval, sval); return(STRING_CONSTANT); } +"XP_ERROR_NOT_FOUND" { const char* sval= "not found"; yylval.sval = new char[strlen(sval)+1]; strcpy(yylval.sval, sval); return(STRING_CONSTANT); } +"XP_ERROR_INVALID_EXPERIENCE" { const char* sval= "invalid experience"; yylval.sval = new char[strlen(sval)+1]; strcpy(yylval.sval, sval); return(STRING_CONSTANT); } +"XP_ERROR_EXPERIENCE_DISABLED" { const char* sval= "experience is disabled"; yylval.sval = new char[strlen(sval)+1]; strcpy(yylval.sval, sval); return(STRING_CONSTANT); } +"XP_ERROR_EXPERIENCE_SUSPENDED" { const char* sval= "experience is suspended"; yylval.sval = new char[strlen(sval)+1]; strcpy(yylval.sval, sval); return(STRING_CONSTANT); } +"XP_ERROR_UNKNOWN_ERROR" { const char* sval= "unknown error"; yylval.sval = new char[strlen(sval)+1]; strcpy(yylval.sval, sval); return(STRING_CONSTANT); } +"XP_ERROR_QUOTA_EXCEEDED" { const char* sval= "experience data quota exceeded"; yylval.sval = new char[strlen(sval)+1]; strcpy(yylval.sval, sval); return(STRING_CONSTANT); } +"XP_ERROR_STORE_DISABLED" { const char* sval= "key-value store is disabled"; yylval.sval = new char[strlen(sval)+1]; strcpy(yylval.sval, sval); return(STRING_CONSTANT); } +"XP_ERROR_STORAGE_EXCEPTION" { const char* sval= "key-value store communication failed"; yylval.sval = new char[strlen(sval)+1]; strcpy(yylval.sval, sval); return(STRING_CONSTANT); } +"XP_ERROR_KEY_NOT_FOUND" { const char* sval= "key doesn't exist"; yylval.sval = new char[strlen(sval)+1]; strcpy(yylval.sval, sval); return(STRING_CONSTANT); } +"XP_ERROR_RETRY_UPDATE" { const char* sval= "retry update"; yylval.sval = new char[strlen(sval)+1]; strcpy(yylval.sval, sval); return(STRING_CONSTANT); } + "PROFILE_SCRIPT_NONE" { count(); yylval.ival = LSL_PROFILE_SCRIPT_NONE; return(INTEGER_CONSTANT); } "PROFILE_SCRIPT_MEMORY" { count(); yylval.ival = LSL_PROFILE_SCRIPT_MEMORY; return(INTEGER_CONSTANT); } diff --git a/indra/lscript/lscript_compile/indra.y b/indra/lscript/lscript_compile/indra.y index febf5f6751..3e4b6c6cea 100644 --- a/indra/lscript/lscript_compile/indra.y +++ b/indra/lscript/lscript_compile/indra.y @@ -179,6 +179,8 @@ %type money %type email %type run_time_permissions +%type experience_permissions +%type experience_permissions_denied %type inventory %type attach %type dataserver @@ -787,6 +789,16 @@ event $$ = new LLScriptEventHandler(gLine, gColumn, $1, $2); gAllocationManager->addAllocation($$); } + | experience_permissions compound_statement + { + $$ = new LLScriptEventHandler(gLine, gColumn, $1, $2); + gAllocationManager->addAllocation($$); + } + | experience_permissions_denied compound_statement + { + $$ = new LLScriptEventHandler(gLine, gColumn, $1, $2); + gAllocationManager->addAllocation($$); + } | inventory compound_statement { $$ = new LLScriptEventHandler(gLine, gColumn, $1, $2); @@ -1039,6 +1051,28 @@ run_time_permissions } ; +experience_permissions + : EXPERIENCE_PERMISSIONS '(' LLKEY IDENTIFIER ')' + { + LLScriptIdentifier *id1 = new LLScriptIdentifier(gLine, gColumn, $4); + gAllocationManager->addAllocation(id1); + $$ = new LLScriptEXPEvent(gLine, gColumn, id1); + gAllocationManager->addAllocation($$); + } + ; + +experience_permissions_denied + : EXPERIENCE_PERMISSIONS_DENIED '(' LLKEY IDENTIFIER ',' INTEGER IDENTIFIER ')' + { + LLScriptIdentifier *id1 = new LLScriptIdentifier(gLine, gColumn, $4); + gAllocationManager->addAllocation(id1); + LLScriptIdentifier *id2 = new LLScriptIdentifier(gLine, gColumn, $7); + gAllocationManager->addAllocation(id2); + $$ = new LLScriptEXPDeniedEvent(gLine, gColumn, id1, id2); + gAllocationManager->addAllocation($$); + } + ; + inventory : INVENTORY '(' INTEGER IDENTIFIER ')' { diff --git a/indra/lscript/lscript_compile/lscript_bytecode.cpp b/indra/lscript/lscript_compile/lscript_bytecode.cpp index 0e46064829..18707f2c51 100644 --- a/indra/lscript/lscript_compile/lscript_bytecode.cpp +++ b/indra/lscript/lscript_compile/lscript_bytecode.cpp @@ -314,7 +314,7 @@ void LLScriptScriptCodeChunk::build(LLFILE *efp, LLFILE *bcfp) if (fwrite(mCompleteCode, 1, mTotalSize, bcfp) != (size_t)mTotalSize) { - llwarns << "Short write" << llendl; + LL_WARNS() << "Short write" << LL_ENDL; } } else diff --git a/indra/lscript/lscript_compile/lscript_scope.h b/indra/lscript/lscript_compile/lscript_scope.h index ec36d37b7d..d5045458f5 100644 --- a/indra/lscript/lscript_compile/lscript_scope.h +++ b/indra/lscript/lscript_compile/lscript_scope.h @@ -33,7 +33,7 @@ #ifndef LL_LSCRIPT_SCOPE_H #define LL_LSCRIPT_SCOPE_H -#include "string_table.h" +#include "llstringtable.h" #include "llmap.h" #include "lscript_byteformat.h" diff --git a/indra/lscript/lscript_compile/lscript_tree.cpp b/indra/lscript/lscript_compile/lscript_tree.cpp index b737bff75f..e5e7bb3d05 100644 --- a/indra/lscript/lscript_compile/lscript_tree.cpp +++ b/indra/lscript/lscript_compile/lscript_tree.cpp @@ -3712,6 +3712,155 @@ S32 LLScriptNoSensorEvent::getSize() return 0; } +void LLScriptEXPEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePass pass, LSCRIPTPruneType ptype, BOOL &prunearg, LLScriptScope *scope, LSCRIPTType &type, LSCRIPTType basetype, U64 &count, LLScriptByteCodeChunk *chunk, LLScriptByteCodeChunk *heap, S32 stacksize, LLScriptScopeEntry *entry, S32 entrycount, LLScriptLibData **ldata) +{ + if (gErrorToText.getErrors()) + { + return; + } + switch(pass) + { + case LSCP_PRETTY_PRINT: + case LSCP_EMIT_ASSEMBLY: + fdotabs(fp, tabs, tabsize); + fprintf(fp, "experience_permissions( key "); + mName->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, " )\n"); + break; + case LSCP_SCOPE_PASS1: + checkForDuplicateHandler(fp, this, scope, "experience_permissions"); + if (scope->checkEntry(mName->mName)) + { + gErrorToText.writeError(fp, this, LSERROR_DUPLICATE_NAME); + } + else + { + mName->mScopeEntry = scope->addEntry(mName->mName, LIT_VARIABLE, LST_KEY); + } + break; + case LSCP_RESOURCE: + { + // we're just tryng to determine how much space the variable needs + if (mName->mScopeEntry) + { + mName->mScopeEntry->mOffset = (S32)count; + mName->mScopeEntry->mSize = 4; + count += mName->mScopeEntry->mSize; + } + } + break; + + case LSCP_EMIT_BYTE_CODE: + { +#ifdef LSL_INCLUDE_DEBUG_INFO + char name[] = "experience_permissions"; + chunk->addBytes(name, strlen(name) + 1); + chunk->addBytes(mName->mName, strlen(mName->mName) + 1); +#endif + } + break; + case LSCP_EMIT_CIL_ASSEMBLY: + fdotabs(fp, tabs, tabsize); + fprintf(fp, "experience_permissions( valuetype [ScriptTypes]LindenLab.SecondLife.Key "); + mName->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, " )"); + break; + default: + mName->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + break; + } +} + +S32 LLScriptEXPEvent::getSize() +{ + // key = 4 + return 4; +} + + +void LLScriptEXPDeniedEvent::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePass pass, LSCRIPTPruneType ptype, BOOL &prunearg, LLScriptScope *scope, LSCRIPTType &type, LSCRIPTType basetype, U64 &count, LLScriptByteCodeChunk *chunk, LLScriptByteCodeChunk *heap, S32 stacksize, LLScriptScopeEntry *entry, S32 entrycount, LLScriptLibData **ldata) +{ + if (gErrorToText.getErrors()) + { + return; + } + switch(pass) + { + case LSCP_PRETTY_PRINT: + case LSCP_EMIT_ASSEMBLY: + fdotabs(fp, tabs, tabsize); + fprintf(fp, "experience_permissions_denied( key "); + mName->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, ", integer "); + mReason->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, " )\n"); + break; + case LSCP_SCOPE_PASS1: + checkForDuplicateHandler(fp, this, scope, "experience_permissions_denied"); + if (scope->checkEntry(mName->mName)) + { + gErrorToText.writeError(fp, this, LSERROR_DUPLICATE_NAME); + } + else + { + mName->mScopeEntry = scope->addEntry(mName->mName, LIT_VARIABLE, LST_KEY); + } + if (scope->checkEntry(mReason->mName)) + { + gErrorToText.writeError(fp, this, LSERROR_DUPLICATE_NAME); + } + else + { + mReason->mScopeEntry = scope->addEntry(mReason->mName, LIT_VARIABLE, LST_INTEGER); + } + break; + case LSCP_RESOURCE: + { + // we're just trying to determine how much space the variable needs + if (mName->mScopeEntry) + { + mName->mScopeEntry->mOffset = (S32)count; + mName->mScopeEntry->mSize = 4; + count += mName->mScopeEntry->mSize; + + mReason->mScopeEntry->mOffset = (S32)count; + mReason->mScopeEntry->mSize = 4; + count += mReason->mScopeEntry->mSize; + } + } + break; + + case LSCP_EMIT_BYTE_CODE: + { +#ifdef LSL_INCLUDE_DEBUG_INFO + char name[] = "experience_permissions_denied"; + chunk->addBytes(name, strlen(name) + 1); + chunk->addBytes(mName->mName, strlen(mName->mName) + 1); + chunk->addBytes(mReason->mName, strlen(mReason->mName) + 1); +#endif + } + break; + case LSCP_EMIT_CIL_ASSEMBLY: + fdotabs(fp, tabs, tabsize); + fprintf(fp, "experience_permissions_denied( valuetype [ScriptTypes]LindenLab.SecondLife.Key "); + mName->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, ", int32 "); + mReason->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + fprintf(fp, " )"); + break; + default: + mName->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + mReason->recurse(fp, tabs, tabsize, pass, ptype, prunearg, scope, type, basetype, count, chunk, heap, stacksize, entry, entrycount, NULL); + break; + } +} + +S32 LLScriptEXPDeniedEvent::getSize() +{ + // key = 4 + integer + return LSCRIPTDataSize[LST_KEY]+LSCRIPTDataSize[LST_INTEGER]; +} + void LLScriptAtTarget::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePass pass, LSCRIPTPruneType ptype, BOOL &prunearg, LLScriptScope *scope, LSCRIPTType &type, LSCRIPTType basetype, U64 &count, LLScriptByteCodeChunk *chunk, LLScriptByteCodeChunk *heap, S32 stacksize, LLScriptScopeEntry *entry, S32 entrycount, LLScriptLibData **ldata) { if (gErrorToText.getErrors()) @@ -8577,6 +8726,7 @@ void LLScriptReturn::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePa } } prunearg = TRUE; + break; case LSCP_TYPE: // if there is a return expression, it must be promotable to the return type of the function if (mExpression) @@ -9775,7 +9925,13 @@ void LLScriptEventHandler::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCom mScopeEntry->mFunctionArgs.addType(LST_STRING); mScopeEntry->mFunctionArgs.addType(LST_STRING); break; - + case LSTT_EXPERMISSIONS: + mScopeEntry->mFunctionArgs.addType(LST_KEY); + break; + case LSTT_EXPERMISSIONS_DENIED: + mScopeEntry->mFunctionArgs.addType(LST_KEY); + mScopeEntry->mFunctionArgs.addType(LST_INTEGER); + break; default: break; } diff --git a/indra/lscript/lscript_compile/lscript_tree.h b/indra/lscript/lscript_compile/lscript_tree.h index 7de9606dfc..c7be5396a1 100644 --- a/indra/lscript/lscript_compile/lscript_tree.h +++ b/indra/lscript/lscript_compile/lscript_tree.h @@ -35,7 +35,6 @@ #include "v3math.h" #include "llquaternion.h" -#include "linked_lists.h" #include "lscript_error.h" #include "lscript_typecheck.h" #include "lscript_byteformat.h" @@ -634,6 +633,39 @@ class LLScriptRTPEvent : public LLScriptEvent LLScriptIdentifier *mRTPermissions; }; +class LLScriptEXPEvent : public LLScriptEvent +{ +public: + LLScriptEXPEvent(S32 line, S32 col, LLScriptIdentifier *name) + : LLScriptEvent(line, col, LSTT_EXPERMISSIONS), mName(name) + { + } + + ~LLScriptEXPEvent() {} + + void recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePass pass, LSCRIPTPruneType ptype, BOOL &prunearg, LLScriptScope *scope, LSCRIPTType &type, LSCRIPTType basetype, U64 &count, LLScriptByteCodeChunk *chunk, LLScriptByteCodeChunk *heap, S32 stacksize, LLScriptScopeEntry *entry, S32 entrycount, LLScriptLibData **ldata); + S32 getSize(); + + LLScriptIdentifier *mName; +}; + +class LLScriptEXPDeniedEvent : public LLScriptEvent +{ +public: + LLScriptEXPDeniedEvent(S32 line, S32 col, LLScriptIdentifier *name, LLScriptIdentifier *reason) + : LLScriptEvent(line, col, LSTT_EXPERMISSIONS_DENIED), mName(name), mReason(reason) + { + } + + ~LLScriptEXPDeniedEvent() {} + + void recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePass pass, LSCRIPTPruneType ptype, BOOL &prunearg, LLScriptScope *scope, LSCRIPTType &type, LSCRIPTType basetype, U64 &count, LLScriptByteCodeChunk *chunk, LLScriptByteCodeChunk *heap, S32 stacksize, LLScriptScopeEntry *entry, S32 entrycount, LLScriptLibData **ldata); + S32 getSize(); + + LLScriptIdentifier *mName; + LLScriptIdentifier *mReason; +}; + class LLScriptChatEvent : public LLScriptEvent { public: @@ -2310,20 +2342,20 @@ class LLScriptAllocationManager LLScriptAllocationManager() {} ~LLScriptAllocationManager() { - mAllocationList.deleteAllData(); + deleteAllocations(); } void addAllocation(LLScriptFilePosition *ptr) { - mAllocationList.addData(ptr); + mAllocationList.push_front(ptr); } void deleteAllocations() { - mAllocationList.deleteAllData(); + delete_and_clear(mAllocationList); } - LLLinkedList mAllocationList; + std::list mAllocationList; }; extern LLScriptAllocationManager *gAllocationManager; diff --git a/indra/lscript/lscript_execute.h b/indra/lscript/lscript_execute.h index 96855abea0..0812120ef1 100644 --- a/indra/lscript/lscript_execute.h +++ b/indra/lscript/lscript_execute.h @@ -33,9 +33,10 @@ #ifndef LL_LSCRIPT_EXECUTE_H #define LL_LSCRIPT_EXECUTE_H +#include "stdtypes.h" #include "lscript_byteconvert.h" -#include "linked_lists.h" #include "lscript_library.h" +#include "llstl.h" class LLTimer; @@ -268,7 +269,7 @@ class LLScriptEventData S32 i, number = bytestream2integer(src, offset); for (i = 0; i < number; i++) { - mEventDataList.addData(new LLScriptDataCollection(src, offset)); + mEventDataList.push_front(new LLScriptDataCollection(src, offset)); } } @@ -277,32 +278,32 @@ class LLScriptEventData S32 i, number = bytestream2integer(src, offset); for (i = 0; i < number; i++) { - mEventDataList.addData(new LLScriptDataCollection(src, offset)); + mEventDataList.push_front(new LLScriptDataCollection(src, offset)); } } ~LLScriptEventData() { - mEventDataList.deleteAllData(); + delete_and_clear(mEventDataList); } void addEventData(LLScriptDataCollection *data) { - if (mEventDataList.getLength() < MAX_EVENTS_IN_QUEUE) - mEventDataList.addDataAtEnd(data); + if (mEventDataList.size() < MAX_EVENTS_IN_QUEUE) + mEventDataList.push_back(data); else delete data; } LLScriptDataCollection *getNextEvent(LSCRIPTStateEventType type) { - LLScriptDataCollection *temp; - for (temp = mEventDataList.getFirstData(); - temp; - temp = mEventDataList.getNextData()) + for (std::list::iterator it = mEventDataList.begin(), end_it = mEventDataList.end(); + it != end_it; + ++it) { + LLScriptDataCollection* temp = *it; if (temp->mType == type) { - mEventDataList.removeCurrentData(); + mEventDataList.erase(it); return temp; } } @@ -311,24 +312,24 @@ class LLScriptEventData LLScriptDataCollection *getNextEvent() { LLScriptDataCollection *temp; - temp = mEventDataList.getFirstData(); + temp = mEventDataList.front(); if (temp) { - mEventDataList.removeCurrentData(); + mEventDataList.pop_front(); return temp; } return NULL; } void removeEventType(LSCRIPTStateEventType type) { - LLScriptDataCollection *temp; - for (temp = mEventDataList.getFirstData(); - temp; - temp = mEventDataList.getNextData()) + for (std::list::iterator it = mEventDataList.begin(), end_it = mEventDataList.end(); + it != end_it; + ++it) { - if (temp->mType == type) + if ((*it)->mType == type) { - mEventDataList.deleteCurrentData(); + delete *it; + mEventDataList.erase(it); } } } @@ -338,12 +339,11 @@ class LLScriptEventData S32 size = 0; // number in linked list size += 4; - LLScriptDataCollection *temp; - for (temp = mEventDataList.getFirstData(); - temp; - temp = mEventDataList.getNextData()) + for (std::list::iterator it = mEventDataList.begin(), end_it = mEventDataList.end(); + it != end_it; + ++it) { - size += temp->getSavedSize(); + size += (*it)->getSavedSize(); } return size; } @@ -352,19 +352,18 @@ class LLScriptEventData { S32 offset = 0; // number in linked list - S32 number = mEventDataList.getLength(); + S32 number = mEventDataList.size(); integer2bytestream(dest, offset, number); - LLScriptDataCollection *temp; - for (temp = mEventDataList.getFirstData(); - temp; - temp = mEventDataList.getNextData()) + for (std::list::iterator it = mEventDataList.begin(), end_it = mEventDataList.end(); + it != end_it; + ++it) { - offset += temp->write2bytestream(dest + offset); + offset += (*it)->write2bytestream(dest + offset); } return offset; } - LLLinkedList mEventDataList; + std::list mEventDataList; }; class LLScriptExecute @@ -480,9 +479,9 @@ class LLScriptExecuteLSL2 : public LLScriptExecute virtual ~LLScriptExecuteLSL2(); virtual S32 getVersion() const {return get_register(mBuffer, LREG_VN);} - virtual void deleteAllEvents() {mEventData.mEventDataList.deleteAllData();} + virtual void deleteAllEvents() {delete_and_clear(mEventData.mEventDataList);} virtual void addEvent(LLScriptDataCollection* event); - virtual U32 getEventCount() {return mEventData.mEventDataList.getLength();} + virtual U32 getEventCount() {return mEventData.mEventDataList.size();} virtual void removeEventType(LSCRIPTStateEventType event_type); virtual S32 getFaults() {return get_register(mBuffer, LREG_FR);} virtual void setFault(LSCRIPTRunTimeFaults fault) {set_fault(mBuffer, fault);} diff --git a/indra/lscript/lscript_execute/llscriptresourceconsumer.cpp b/indra/lscript/lscript_execute/llscriptresourceconsumer.cpp index 5bade41140..120100e197 100644 --- a/indra/lscript/lscript_execute/llscriptresourceconsumer.cpp +++ b/indra/lscript/lscript_execute/llscriptresourceconsumer.cpp @@ -62,7 +62,7 @@ bool LLScriptResourceConsumer::switchScriptResourcePools(LLScriptResourcePool& n { if (&new_pool == &LLScriptResourcePool::null) { - llwarns << "New pool is null" << llendl; + LL_WARNS() << "New pool is null" << LL_ENDL; } if (isInPool(new_pool)) diff --git a/indra/lscript/lscript_execute/lscript_execute.cpp b/indra/lscript/lscript_execute/lscript_execute.cpp index 8de54aeda5..65228fc54f 100644 --- a/indra/lscript/lscript_execute/lscript_execute.cpp +++ b/indra/lscript/lscript_execute/lscript_execute.cpp @@ -83,7 +83,7 @@ LLScriptExecuteLSL2::LLScriptExecuteLSL2(LLFILE *fp) S32 pos = 0; if (fread(&sizearray, 1, 4, fp) != 4) { - llwarns << "Short read" << llendl; + LL_WARNS() << "Short read" << LL_ENDL; filesize = 0; } else { filesize = bytestream2integer(sizearray, pos); @@ -92,7 +92,7 @@ LLScriptExecuteLSL2::LLScriptExecuteLSL2(LLFILE *fp) fseek(fp, 0, SEEK_SET); if (fread(mBuffer, 1, filesize, fp) != filesize) { - llwarns << "Short read" << llendl; + LL_WARNS() << "Short read" << LL_ENDL; } fclose(fp); @@ -296,7 +296,7 @@ void LLScriptExecuteLSL2::init() void LLScriptExecuteLSL2::recordBoundaryError( const LLUUID &id ) { set_fault(mBuffer, LSRF_BOUND_CHECK_ERROR); - llwarns << "Script boundary error for ID " << id << llendl; + LL_WARNS() << "Script boundary error for ID " << id << LL_ENDL; } @@ -520,7 +520,7 @@ void LLScriptExecuteLSL2::callNextQueuedEventHandler(U64 event_register, const L } else { - llwarns << "Somehow got an event that we're not registered for!" << llendl; + LL_WARNS() << "Somehow got an event that we're not registered for!" << LL_ENDL; } delete eventdata; } @@ -628,7 +628,7 @@ S32 LLScriptExecuteLSL2::writeState(U8 **dest, U32 header_size, U32 footer_size) // registers integer2bytestream(*dest, dest_offset, registers_size); - // llinfos << "Writing CE: " << getCurrentEvents() << llendl; + // LL_INFOS() << "Writing CE: " << getCurrentEvents() << LL_ENDL; bytestream2bytestream(*dest, dest_offset, mBuffer, src_offset, registers_size); // heap @@ -680,11 +680,11 @@ S32 LLScriptExecuteLSL2::readState(U8 *src) // copy data into register area bytestream2bytestream(mBuffer, dest_offset, src, src_offset, size); -// llinfos << "Read CE: " << getCurrentEvents() << llendl; +// LL_INFOS() << "Read CE: " << getCurrentEvents() << LL_ENDL; if (get_register(mBuffer, LREG_TM) != TOP_OF_MEMORY) { - llwarns << "Invalid state. Top of memory register does not match" - << " constant." << llendl; + LL_WARNS() << "Invalid state. Top of memory register does not match" + << " constant." << LL_ENDL; reset_hp_to_safe_spot(mBuffer); return -1; } @@ -4036,7 +4036,7 @@ void lscript_run(const std::string& filename, BOOL b_debug) if (filename.empty()) { - llerrs << "filename is NULL" << llendl; + LL_ERRS() << "filename is NULL" << LL_ENDL; // Just reporting error is likely not enough. Need // to check how to abort or error out gracefully // from this function. XXXTBD @@ -4061,8 +4061,8 @@ void lscript_run(const std::string& filename, BOOL b_debug) F32 time = timer.getElapsedTimeF32(); F32 ips = execute->mInstructionCount / time; - llinfos << execute->mInstructionCount << " instructions in " << time << " seconds" << llendl; - llinfos << ips/1000 << "K instructions per second" << llendl; + LL_INFOS() << execute->mInstructionCount << " instructions in " << time << " seconds" << LL_ENDL; + LL_INFOS() << ips/1000 << "K instructions per second" << LL_ENDL; printf("ip: 0x%X\n", get_register(execute->mBuffer, LREG_IP)); printf("sp: 0x%X\n", get_register(execute->mBuffer, LREG_SP)); printf("bp: 0x%X\n", get_register(execute->mBuffer, LREG_BP)); diff --git a/indra/lscript/lscript_execute/lscript_readlso.cpp b/indra/lscript/lscript_execute/lscript_readlso.cpp index a5dbd6221f..087abccf72 100644 --- a/indra/lscript/lscript_execute/lscript_readlso.cpp +++ b/indra/lscript/lscript_execute/lscript_readlso.cpp @@ -43,7 +43,7 @@ LLScriptLSOParse::LLScriptLSOParse(LLFILE *fp) S32 pos = 0; if (fread(&sizearray, 1, 4, fp) != 4) { - llwarns << "Short read" << llendl; + LL_WARNS() << "Short read" << LL_ENDL; filesize = 0; } else { filesize = bytestream2integer(sizearray, pos); @@ -52,7 +52,7 @@ LLScriptLSOParse::LLScriptLSOParse(LLFILE *fp) fseek(fp, 0, SEEK_SET); if (fread(mRawData, 1, filesize, fp) != filesize) { - llwarns << "Short read" << llendl; + LL_WARNS() << "Short read" << LL_ENDL; } initOpCodePrinting(); diff --git a/indra/lscript/lscript_execute/lscript_readlso.h b/indra/lscript/lscript_execute/lscript_readlso.h index 3b0b75cfed..78547aae95 100644 --- a/indra/lscript/lscript_execute/lscript_readlso.h +++ b/indra/lscript/lscript_execute/lscript_readlso.h @@ -34,7 +34,6 @@ #define LL_LSCRIPT_READLSO_H #include "lscript_byteconvert.h" -#include "linked_lists.h" // list of op code print functions void print_noop(LLFILE *fp, U8 *buffer, S32 &offset, S32 tabs); diff --git a/indra/lscript/lscript_execute_mono/size.cpp b/indra/lscript/lscript_execute_mono/size.cpp index 731eeb9af6..c126c2255d 100644 --- a/indra/lscript/lscript_execute_mono/size.cpp +++ b/indra/lscript/lscript_execute_mono/size.cpp @@ -169,8 +169,8 @@ GetMemoryUsage (MonoObject *obj) int printObjectSize(MonoObject* obj, MonoType* type, int total) { total += mono_object_get_size (obj); - llinfos << "Object type: " << mono_type_full_name(type) << " size: " - << total << llendl; + LL_INFOS() << "Object type: " << mono_type_full_name(type) << " size: " + << total << LL_ENDL; return total; } diff --git a/indra/lscript/lscript_library.h b/indra/lscript/lscript_library.h index 363d11f3aa..c3eb82f155 100644 --- a/indra/lscript/lscript_library.h +++ b/indra/lscript/lscript_library.h @@ -246,7 +246,7 @@ class LLScriptLibData mKey = new char[strlen(data.mKey) + 1]; /* Flawfinder: ignore */ if (mKey == NULL) { - llerrs << "Memory Allocation Failed" << llendl; + LL_ERRS() << "Memory Allocation Failed" << LL_ENDL; return; } strcpy(mKey, data.mKey); /* Flawfinder: ignore */ @@ -256,7 +256,7 @@ class LLScriptLibData mString = new char[strlen(data.mString) + 1]; /* Flawfinder: ignore */ if (mString == NULL) { - llerrs << "Memory Allocation Failed" << llendl; + LL_ERRS() << "Memory Allocation Failed" << LL_ENDL; return; } strcpy(mString, data.mString); /* Flawfinder: ignore */ @@ -281,7 +281,7 @@ class LLScriptLibData mKey = new char[strlen(temp) + 1]; /* Flawfinder: ignore */ if (mKey == NULL) { - llerrs << "Memory Allocation Failed" << llendl; + LL_ERRS() << "Memory Allocation Failed" << LL_ENDL; return; } strcpy(mKey, temp); /* Flawfinder: ignore */ @@ -293,7 +293,7 @@ class LLScriptLibData mString = new char[strlen(temp) + 1]; /* Flawfinder: ignore */ if (mString == NULL) { - llerrs << "Memory Allocation Failed" << llendl; + LL_ERRS() << "Memory Allocation Failed" << LL_ENDL; return; } strcpy(mString, temp); /* Flawfinder: ignore */ @@ -330,7 +330,7 @@ class LLScriptLibData mKey = new char[strlen(temp) + 1]; /* Flawfinder: ignore */ if (mKey == NULL) { - llerrs << "Memory Allocation Failed" << llendl; + LL_ERRS() << "Memory Allocation Failed" << LL_ENDL; return; } strcpy(mKey, temp); /* Flawfinder: ignore */ @@ -342,7 +342,7 @@ class LLScriptLibData mString = new char[strlen(temp) + 1]; /* Flawfinder: ignore */ if (mString == NULL) { - llerrs << "Memory Allocation Failed" << llendl; + LL_ERRS() << "Memory Allocation Failed" << LL_ENDL; return; } strcpy(mString, temp); /* Flawfinder: ignore */ @@ -370,7 +370,7 @@ class LLScriptLibData mString = new char[strlen(src) + 1]; /* Flawfinder: ignore */ if (mString == NULL) { - llerrs << "Memory Allocation Failed" << llendl; + LL_ERRS() << "Memory Allocation Failed" << LL_ENDL; return; } strcpy(mString, src); /* Flawfinder: ignore */ @@ -404,7 +404,7 @@ class LLScriptLibData mString = new char[strlen(string) + 1]; /* Flawfinder: ignore */ if (mString == NULL) { - llerrs << "Memory Allocation Failed" << llendl; + LL_ERRS() << "Memory Allocation Failed" << LL_ENDL; return; } strcpy(mString, string); /* Flawfinder: ignore */ diff --git a/indra/lscript/lscript_library/lscript_alloc.cpp b/indra/lscript/lscript_library/lscript_alloc.cpp index 2d47644df7..21039da27d 100644 --- a/indra/lscript/lscript_library/lscript_alloc.cpp +++ b/indra/lscript/lscript_library/lscript_alloc.cpp @@ -441,7 +441,7 @@ S32 lsa_create_data_block(U8 **buffer, LLScriptLibData *data, S32 base_offset) U8 *tbuff = new U8[size + listsize]; if (tbuff == NULL) { - llerrs << "Memory Allocation Failed" << llendl; + LL_ERRS() << "Memory Allocation Failed" << LL_ENDL; } memcpy(tbuff, *buffer, size); /*Flawfinder: ignore*/ memcpy(tbuff + size, listbuf, listsize); /*Flawfinder: ignore*/ diff --git a/indra/lscript/lscript_library/lscript_library.cpp b/indra/lscript/lscript_library/lscript_library.cpp index 3d91fafe8d..2a9292dfff 100644 --- a/indra/lscript/lscript_library/lscript_library.cpp +++ b/indra/lscript/lscript_library/lscript_library.cpp @@ -199,6 +199,8 @@ void LLScriptLibrary::init() addFunction(10.f, 0.f, dummy_func, "llStringLength", "i", "s"); addFunction(10.f, 0.f, dummy_func, "llStartAnimation", NULL, "s"); addFunction(10.f, 0.f, dummy_func, "llStopAnimation", NULL, "s"); + addFunction(10.f, 0.f, dummy_func, "llStartObjectAnimation", NULL, "s"); + addFunction(10.f, 0.f, dummy_func, "llStopObjectAnimation", NULL, "s"); addFunction(10.f, 0.f, dummy_func, "llPointAt", NULL, "v"); addFunction(10.f, 0.f, dummy_func, "llStopPointAt", NULL, NULL); addFunction(10.f, 0.f, dummy_func, "llTargetOmega", NULL, "vff"); @@ -540,6 +542,11 @@ void LLScriptLibrary::init() addFunction(0.f, 0.f, dummy_func, "llGetAnimationOverride", "s", "s"); addFunction(0.f, 0.f, dummy_func, "llResetAnimationOverride", NULL, "s"); + // Server RC LeTigre 13.12.20.285035 new function + addFunction(10.f, 0.f, dummy_func, "llScaleByFactor" , "i", "f"); + addFunction(10.f, 0.f, dummy_func, "llGetMinScaleFactor" , "f", NULL); + addFunction(10.f, 0.f, dummy_func, "llGetMaxScaleFactor" , "f", NULL); + // SL-LSL Functions to be added above this line // --------------------------------------------- // NOTE bytecode placement no longer applies, viewers do not compile scripts anymore (confirmed with LL, also noted by Phoenix/Firestorm team.) @@ -769,7 +776,7 @@ void LLScriptLibrary::assignExec(const char *name, void (*exec_func)(LLScriptLib } } - llerrs << "Unknown LSL function in assignExec: " << name << llendl; + LL_ERRS() << "Unknown LSL function in assignExec: " << name << LL_ENDL; } void LLScriptLibData::print(std::ostream &s, BOOL b_prepend_comma) diff --git a/indra/mac_crash_logger/CMakeLists.txt b/indra/mac_crash_logger/CMakeLists.txt deleted file mode 100644 index daf3e10857..0000000000 --- a/indra/mac_crash_logger/CMakeLists.txt +++ /dev/null @@ -1,76 +0,0 @@ -# -*- cmake -*- - -project(mac_crash_logger) - -include(00-Common) -include(LLCommon) -include(LLCrashLogger) -include(LLMath) -include(LLMessage) -include(LLVFS) -include(LLXML) -include(Linking) - -include_directories( - ${LLCOMMON_INCLUDE_DIRS} - ${LLCRASHLOGGER_INCLUDE_DIRS} - ${LLMATH_INCLUDE_DIRS} - ${LLVFS_INCLUDE_DIRS} - ${LLXML_INCLUDE_DIRS} - ) - -set(mac_crash_logger_SOURCE_FILES - mac_crash_logger.cpp - llcrashloggermac.cpp - ) - -set(mac_crash_logger_HEADER_FILES - CMakeLists.txt - - llcrashloggermac.h - ) - -set_source_files_properties(${mac_crash_logger_HEADER_FILES} - PROPERTIES HEADER_FILE_ONLY TRUE) -list(APPEND mac_crash_logger_SOURCE_FILES ${mac_crash_logger_HEADER_FILES}) - -set(mac_crash_logger_RESOURCE_FILES - CrashReporter.nib/ - ) -set_source_files_properties( - ${mac_crash_logger_RESOURCE_FILES} - PROPERTIES - HEADER_FILE_ONLY TRUE - ) -SOURCE_GROUP("Resources" FILES ${mac_crash_logger_RESOURCE_FILES}) -list(APPEND mac_crash_logger_SOURCE_FILES ${mac_crash_logger_RESOURCE_FILES}) - -add_executable(mac-crash-logger - MACOSX_BUNDLE - ${mac_crash_logger_SOURCE_FILES}) - -set_target_properties(mac-crash-logger - PROPERTIES - MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist - ) - -target_link_libraries(mac-crash-logger - ${LLCRASHLOGGER_LIBRARIES} - ${LLVFS_LIBRARIES} - ${LLXML_LIBRARIES} - ${LLMESSAGE_LIBRARIES} - ${LLVFS_LIBRARIES} - ${LLMATH_LIBRARIES} - ${LLCOMMON_LIBRARIES} - ) - -add_custom_command( - TARGET mac-crash-logger POST_BUILD - COMMAND ${CMAKE_COMMAND} - ARGS - -E - copy_directory - ${CMAKE_CURRENT_SOURCE_DIR}/CrashReporter.nib - ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/mac-crash-logger.app/Contents/Resources/CrashReporter.nib - ) - diff --git a/indra/mac_crash_logger/CrashReporter.nib/classes.nib b/indra/mac_crash_logger/CrashReporter.nib/classes.nib deleted file mode 100644 index c4b887e72b..0000000000 --- a/indra/mac_crash_logger/CrashReporter.nib/classes.nib +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IBVersion - 1 - - diff --git a/indra/mac_crash_logger/CrashReporter.nib/info.nib b/indra/mac_crash_logger/CrashReporter.nib/info.nib deleted file mode 100644 index 06805c0e4f..0000000000 --- a/indra/mac_crash_logger/CrashReporter.nib/info.nib +++ /dev/null @@ -1,18 +0,0 @@ - - - - - IBFramework Version - 629 - IBLastKnownRelativeProjectPath - ../../build-darwin-i386/SecondLife.xcodeproj - IBOldestOS - 5 - IBOpenObjects - - IBSystem Version - 9E17 - targetFramework - IBCarbonFramework - - diff --git a/indra/mac_crash_logger/CrashReporter.nib/objects.xib b/indra/mac_crash_logger/CrashReporter.nib/objects.xib deleted file mode 100644 index 634d1c5321..0000000000 --- a/indra/mac_crash_logger/CrashReporter.nib/objects.xib +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - - ok - Send Report - 414 273 434 378 - - - not! - 2 - Don't Send - 414 390 434 487 - - - Second Life appears to have crashed or frozen the last time it ran. This crash reporter collects information about your computer's hardware configuration, operating system, and some Second Life logs, all of which are used for debugging purposes only. In the space below, please briefly describe what you were doing or trying to do just prior to the crash. Thank you for your help! This report is NOT read by Customer Support. If you have billing or other questions, please go to: http://www.secondlife.com/support/ If you don't wish to send Linden Lab a crash report, press Cancel. - 20 20 231 487 - - - 2 - 3 - 7 - Second Life Crash Logger - - - - - - - text - TRUE - 242 23 391 484 - - - remb - Remember This Choice - 415 20 433 186 - - - 0 0 454 507 - - 257 653 711 1160 - 0 0 768 1024 - - - - - - - - - - - - - - - - CrashReporter - - File's Owner - - - IBCarbonFramework - 194 - diff --git a/indra/mac_crash_logger/Info.plist b/indra/mac_crash_logger/Info.plist deleted file mode 100644 index f48293e825..0000000000 --- a/indra/mac_crash_logger/Info.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - English - CFBundleExecutable - mac-crash-logger - CFBundleGetInfoString - - CFBundleIconFile - - CFBundleIdentifier - com.secondlife.indra.crashreporter - CFBundleInfoDictionaryVersion - 6.0 - CFBundlePackageType - APPL - CFBundleShortVersionString - - CFBundleSignature - ???? - CFBundleVersion - 1.0.0 - - diff --git a/indra/mac_crash_logger/llcrashloggermac.cpp b/indra/mac_crash_logger/llcrashloggermac.cpp deleted file mode 100644 index 16efa4fe2c..0000000000 --- a/indra/mac_crash_logger/llcrashloggermac.cpp +++ /dev/null @@ -1,345 +0,0 @@ -/** - * @file llcrashloggermac.cpp - * @brief Mac OSX crash logger implementation - * - * $LicenseInfo:firstyear=2003&license=viewergpl$ - * - * Copyright (c) 2003-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - - -#include "llcrashloggermac.h" - -#include -#include -#include - -#include "boost/tokenizer.hpp" - -#include "indra_constants.h" // CRASH_BEHAVIOR_ASK, CRASH_SETTING_NAME -#include "llerror.h" -#include "llfile.h" -#include "lltimer.h" -#include "llstring.h" -#include "lldir.h" -#include "llsdserialize.h" - -#define MAX_LOADSTRING 100 -const char* const SETTINGS_FILE_HEADER = "version"; -const S32 SETTINGS_FILE_VERSION = 101; - -// Windows Message Handlers - -BOOL gFirstDialog = TRUE; // Are we currently handling the Send/Don't Send dialog? -LLFILE *gDebugFile = NULL; - -WindowRef gWindow = NULL; -EventHandlerRef gEventHandler = NULL; -std::string gUserNotes = ""; -bool gSendReport = false; -bool gRememberChoice = false; -IBNibRef nib = NULL; - -OSStatus dialogHandler(EventHandlerCallRef handler, EventRef event, void *userdata) -{ - OSStatus result = eventNotHandledErr; - OSStatus err; - UInt32 evtClass = GetEventClass(event); - UInt32 evtKind = GetEventKind(event); - if((evtClass == kEventClassCommand) && (evtKind == kEventCommandProcess)) - { - HICommand cmd; - err = GetEventParameter(event, kEventParamDirectObject, typeHICommand, NULL, sizeof(cmd), NULL, &cmd); - - - - if(err == noErr) - { - //Get the value of the checkbox - ControlID id; - ControlRef checkBox = NULL; - id.signature = 'remb'; - id.id = 0; - err = GetControlByID(gWindow, &id, &checkBox); - - if(err == noErr) - { - if(GetControl32BitValue(checkBox) == kControlCheckBoxCheckedValue) - { - gRememberChoice = true; - } - else - { - gRememberChoice = false; - } - } - switch(cmd.commandID) - { - case kHICommandOK: - { - char buffer[65535]; /* Flawfinder: ignore */ - Size size = sizeof(buffer) - 1; - ControlRef textField = NULL; - - id.signature = 'text'; - id.id = 0; - - err = GetControlByID(gWindow, &id, &textField); - if(err == noErr) - { - // Get the user response text - err = GetControlData(textField, kControlNoPart, kControlEditTextTextTag, size, (Ptr)buffer, &size); - } - if(err == noErr) - { - // Make sure the string is terminated. - buffer[size] = 0; - gUserNotes = buffer; - - llinfos << buffer << llendl; - } - - // Send the report. - - QuitAppModalLoopForWindow(gWindow); - gSendReport = true; - result = noErr; - } - break; - - case kHICommandCancel: - QuitAppModalLoopForWindow(gWindow); - result = noErr; - break; - default: - result = eventNotHandledErr; - } - } - } - - return(result); -} - - -LLCrashLoggerMac::LLCrashLoggerMac(void) -{ -} - -LLCrashLoggerMac::~LLCrashLoggerMac(void) -{ -} - -bool LLCrashLoggerMac::init(void) -{ - bool ok = LLCrashLogger::init(); - if(!ok) return false; - if(mCrashBehavior != CRASH_BEHAVIOR_ASK) return true; - - // Real UI... - OSStatus err; - - err = CreateNibReference(CFSTR("CrashReporter"), &nib); - - if(err == noErr) - { - err = CreateWindowFromNib(nib, CFSTR("CrashReporter"), &gWindow); - } - - if(err == noErr) - { - // Set focus to the edit text area - ControlRef textField = NULL; - ControlID id; - - id.signature = 'text'; - id.id = 0; - - // Don't set err if any of this fails, since it's non-critical. - if(GetControlByID(gWindow, &id, &textField) == noErr) - { - SetKeyboardFocus(gWindow, textField, kControlFocusNextPart); - } - } - - if(err == noErr) - { - ShowWindow(gWindow); - } - - if(err == noErr) - { - // Set up an event handler for the window. - EventTypeSpec handlerEvents[] = - { - { kEventClassCommand, kEventCommandProcess } - }; - - InstallWindowEventHandler( - gWindow, - NewEventHandlerUPP(dialogHandler), - GetEventTypeCount (handlerEvents), - handlerEvents, - 0, - &gEventHandler); - } - return true; -} - -void LLCrashLoggerMac::gatherPlatformSpecificFiles() -{ - updateApplication("Gathering hardware information..."); - char path[MAX_PATH]; - FSRef folder; - - if(FSFindFolder(kUserDomain, kLogsFolderType, false, &folder) == noErr) - { - // folder is an FSRef to ~/Library/Logs/ - if(FSRefMakePath(&folder, (UInt8*)&path, sizeof(path)) == noErr) - { - struct stat dw_stat; - std::string mBuf; - bool isLeopard = false; - // Try the 10.3 path first... - std::string dw_file_name = std::string(path) + std::string("/CrashReporter/Second Life.crash.log"); - int res = stat(dw_file_name.c_str(), &dw_stat); - - if (res) - { - // Try the 10.2 one next... - dw_file_name = std::string(path) + std::string("/Second Life.crash.log"); - res = stat(dw_file_name.c_str(), &dw_stat); - } - - if(res) - { - //10.5: Like 10.3+, except it puts the crash time in the file instead of dividing it up - //using asterisks. Get a directory listing, search for files starting with second life, - //use the last one found. - std::string old_file_name, current_file_name, pathname, mask; - pathname = std::string(path) + std::string("/CrashReporter/"); - mask = "Second Life*"; - while(gDirUtilp->getNextFileInDir(pathname, mask, current_file_name, false)) - { - old_file_name = current_file_name; - } - if(old_file_name != "") - { - dw_file_name = pathname + old_file_name; - res=stat(dw_file_name.c_str(), &dw_stat); - isLeopard = true; - } - } - - if (!res) - { - std::ifstream fp(dw_file_name.c_str()); - std::stringstream str; - if(!fp.is_open()) return; - str << fp.rdbuf(); - mBuf = str.str(); - - if(!isLeopard) - { - // Crash logs consist of a number of entries, one per crash. - // Each entry is preceeded by "**********" on a line by itself. - // We want only the most recent (i.e. last) one. - const char *sep = "**********"; - const char *start = mBuf.c_str(); - const char *cur = start; - const char *temp = strstr(cur, sep); - - while(temp != NULL) - { - // Skip past the marker we just found - cur = temp + strlen(sep); /* Flawfinder: ignore */ - - // and try to find another - temp = strstr(cur, sep); - } - - // If there's more than one entry in the log file, strip all but the last one. - if(cur != start) - { - mBuf.erase(0, cur - start); - } - } - mCrashInfo["CrashLog"] = mBuf; - } - else - { - llwarns << "Couldn't find any CrashReporter files..." << llendl; - } - } - } -} - -bool LLCrashLoggerMac::mainLoop() -{ - OSStatus err = noErr; - - if(err == noErr && mCrashBehavior == CRASH_BEHAVIOR_ASK) - { - RunAppModalLoopForWindow(gWindow); - } - else if (mCrashBehavior == CRASH_BEHAVIOR_ALWAYS_SEND) - { - gSendReport = true; - } - - if(gRememberChoice) - { - if(gSendReport) saveCrashBehaviorSetting(CRASH_BEHAVIOR_ALWAYS_SEND); - else saveCrashBehaviorSetting(CRASH_BEHAVIOR_NEVER_SEND); - } - - if(gSendReport) - { - setUserText(gUserNotes); - sendCrashLogs(); - } - - if(gWindow != NULL) - { - DisposeWindow(gWindow); - } - - if(nib != NULL) - { - DisposeNibReference(nib); - } - - return true; -} - -void LLCrashLoggerMac::updateApplication(const std::string& message) -{ - LLCrashLogger::updateApplication(); -} - -bool LLCrashLoggerMac::cleanup() -{ - return true; -} diff --git a/indra/mac_crash_logger/llcrashloggermac.h b/indra/mac_crash_logger/llcrashloggermac.h deleted file mode 100644 index a76535afe7..0000000000 --- a/indra/mac_crash_logger/llcrashloggermac.h +++ /dev/null @@ -1,52 +0,0 @@ -/** - * @file llcrashloggermac.h - * @brief Mac OSX crash logger definition - * - * $LicenseInfo:firstyear=2003&license=viewergpl$ - * - * Copyright (c) 2003-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifndef LLCRASHLOGGERMAC_H -#define LLCRASHLOGGERMAC_H - -#include "linden_common.h" -#include "llcrashlogger.h" -#include "llstring.h" - -class LLCrashLoggerMac : public LLCrashLogger -{ -public: - LLCrashLoggerMac(void); - ~LLCrashLoggerMac(void); - virtual bool init(); - virtual bool mainLoop(); - virtual void updateApplication(const std::string& message = LLStringUtil::null); - virtual bool cleanup(); - virtual void gatherPlatformSpecificFiles(); -}; - -#endif diff --git a/indra/mac_crash_logger/mac_crash_logger.cpp b/indra/mac_crash_logger/mac_crash_logger.cpp deleted file mode 100644 index 1f5663d8a9..0000000000 --- a/indra/mac_crash_logger/mac_crash_logger.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/** - * @file mac_crash_logger.cpp - * @brief Mac OSX crash logger implementation - * - * $LicenseInfo:firstyear=2003&license=viewergpl$ - * - * Copyright (c) 2003-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include "llcrashloggermac.h" - -int main(int argc, char **argv) -{ - //time(&gLaunchTime); - - llinfos << "Starting Second Life Viewer Crash Reporter" << llendl; - - LLCrashLoggerMac app; - app.parseCommandOptions(argc, argv); - if(!app.init()) - { - return 0; - } - app.mainLoop(); - - return 0; -} diff --git a/indra/mac_updater/AutoUpdater.nib/classes.nib b/indra/mac_updater/AutoUpdater.nib/classes.nib deleted file mode 100644 index ea58db1189..0000000000 --- a/indra/mac_updater/AutoUpdater.nib/classes.nib +++ /dev/null @@ -1,4 +0,0 @@ -{ -IBClasses = (); -IBVersion = 1; -} diff --git a/indra/mac_updater/AutoUpdater.nib/info.nib b/indra/mac_updater/AutoUpdater.nib/info.nib deleted file mode 100644 index a49a92385b..0000000000 --- a/indra/mac_updater/AutoUpdater.nib/info.nib +++ /dev/null @@ -1,14 +0,0 @@ - - - - - IBDocumentLocation - 103 138 356 240 0 0 1280 1002 - IBFramework Version - 362.0 - IBSystem Version - 7D24 - targetFramework - IBCarbonFramework - - diff --git a/indra/mac_updater/AutoUpdater.nib/objects.xib b/indra/mac_updater/AutoUpdater.nib/objects.xib deleted file mode 100644 index 310411b711..0000000000 --- a/indra/mac_updater/AutoUpdater.nib/objects.xib +++ /dev/null @@ -1,56 +0,0 @@ - - - IBCarbonFramework - - NSApplication - - - - 405 222 533 663 - Second Life Updater - - 0 0 128 441 - - - 20 20 44 421 - what - Initializing… - - - 88 351 108 421 - Cancel - not! - 2 - - - 51 19 70 422 - prog - 50 - - - - FALSE - 2 - 3 - 7 - - - - - - - - - - - - - - - File's Owner - - Updater - - - 194 - diff --git a/indra/mac_updater/CMakeLists.txt b/indra/mac_updater/CMakeLists.txt deleted file mode 100644 index b769a2e170..0000000000 --- a/indra/mac_updater/CMakeLists.txt +++ /dev/null @@ -1,66 +0,0 @@ -# -*- cmake -*- - -project(mac_updater) - -include(00-Common) -include(CURL) -include(LLCommon) -include(LLVFS) -include(Linking) - -include_directories( - ${LLCOMMON_INCLUDE_DIRS} - ${LLVFS_INCLUDE_DIRS} - ) - -set(mac_updater_SOURCE_FILES - mac_updater.cpp - ) - -set(mac_updater_HEADER_FILES - CMakeLists.txt - ) - -set_source_files_properties(${mac_updater_HEADER_FILES} - PROPERTIES HEADER_FILE_ONLY TRUE) - -list(APPEND mac_updater_SOURCE_FILES ${mac_updater_HEADER_FILES}) - - -set(mac_updater_RESOURCE_FILES - AutoUpdater.nib/ - ) -set_source_files_properties( - ${mac_updater_RESOURCE_FILES} - PROPERTIES - HEADER_FILE_ONLY TRUE - ) -SOURCE_GROUP("Resources" FILES ${mac_updater_RESOURCE_FILES}) -list(APPEND mac_updater_SOURCE_FILES ${mac_updater_RESOURCE_FILES}) - -add_executable(mac-updater - MACOSX_BUNDLE - ${mac_updater_SOURCE_FILES}) - -set_target_properties(mac-updater - PROPERTIES - MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist - ) - -target_link_libraries(mac-updater - ${LLVFS_LIBRARIES} - ${CURL_LIBRARIES} - ${OPENSSL_LIBRARIES} - ${LLCOMMON_LIBRARIES} - ) - -add_custom_command( - TARGET mac-updater POST_BUILD - COMMAND ${CMAKE_COMMAND} - ARGS - -E - copy_directory - ${CMAKE_CURRENT_SOURCE_DIR}/AutoUpdater.nib - ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/mac-updater.app/Contents/Resources/AutoUpdater.nib - ) - diff --git a/indra/mac_updater/Info.plist b/indra/mac_updater/Info.plist deleted file mode 100644 index bb27fddb03..0000000000 --- a/indra/mac_updater/Info.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - English - CFBundleExecutable - mac-updater - CFBundleGetInfoString - - CFBundleIconFile - - CFBundleIdentifier - com.secondlife.indra.autoupdater - CFBundleInfoDictionaryVersion - 6.0 - CFBundlePackageType - APPL - CFBundleShortVersionString - - CFBundleSignature - ???? - CFBundleVersion - 1.0.0 - - diff --git a/indra/mac_updater/mac_updater.cpp b/indra/mac_updater/mac_updater.cpp deleted file mode 100644 index 0fd4615b48..0000000000 --- a/indra/mac_updater/mac_updater.cpp +++ /dev/null @@ -1,1204 +0,0 @@ -/** - * @file mac_updater.cpp - * @brief - * - * $LicenseInfo:firstyear=2006&license=viewergpl$ - * - * Copyright (c) 2006-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include -#include -#include - -#include -#include - -#include "llerror.h" -#include "lltimer.h" -#include "lldir.h" -#include "llfile.h" - -#include "llstring.h" - -#include - -#include "llerrorcontrol.h" - -enum -{ - kEventClassCustom = 'Cust', - kEventCustomProgress = 'Prog', - kEventParamCustomCurValue = 'Cur ', - kEventParamCustomMaxValue = 'Max ', - kEventParamCustomText = 'Text', - kEventCustomDone = 'Done', -}; - -WindowRef gWindow = NULL; -EventHandlerRef gEventHandler = NULL; -OSStatus gFailure = noErr; -Boolean gCancelled = false; - -const char *gUpdateURL; -const char *gProductName; -const char *gBundleID; - -void *updatethreadproc(void*); - -pthread_t updatethread; - -OSStatus setProgress(int cur, int max) -{ - OSStatus err; - ControlRef progressBar = NULL; - ControlID id; - - id.signature = 'prog'; - id.id = 0; - - err = GetControlByID(gWindow, &id, &progressBar); - if(err == noErr) - { - Boolean indeterminate; - - if(max == 0) - { - indeterminate = true; - err = SetControlData(progressBar, kControlEntireControl, kControlProgressBarIndeterminateTag, sizeof(Boolean), (Ptr)&indeterminate); - } - else - { - double percentage = (double)cur / (double)max; - SetControlMinimum(progressBar, 0); - SetControlMaximum(progressBar, 100); - SetControlValue(progressBar, (SInt16)(percentage * 100)); - - indeterminate = false; - err = SetControlData(progressBar, kControlEntireControl, kControlProgressBarIndeterminateTag, sizeof(Boolean), (Ptr)&indeterminate); - - Draw1Control(progressBar); - } - } - - return(err); -} - -OSStatus setProgressText(CFStringRef text) -{ - OSStatus err; - ControlRef progressText = NULL; - ControlID id; - - id.signature = 'what'; - id.id = 0; - - err = GetControlByID(gWindow, &id, &progressText); - if(err == noErr) - { - err = SetControlData(progressText, kControlEntireControl, kControlStaticTextCFStringTag, sizeof(CFStringRef), (Ptr)&text); - Draw1Control(progressText); - } - - return(err); -} - -OSStatus sendProgress(long cur, long max, CFStringRef text = NULL) -{ - OSStatus result; - EventRef evt; - - result = CreateEvent( - NULL, - kEventClassCustom, - kEventCustomProgress, - 0, - kEventAttributeNone, - &evt); - - // This event needs to be targeted at the window so it goes to the window's handler. - if(result == noErr) - { - EventTargetRef target = GetWindowEventTarget(gWindow); - result = SetEventParameter ( - evt, - kEventParamPostTarget, - typeEventTargetRef, - sizeof(target), - &target); - } - - if(result == noErr) - { - result = SetEventParameter ( - evt, - kEventParamCustomCurValue, - typeLongInteger, - sizeof(cur), - &cur); - } - - if(result == noErr) - { - result = SetEventParameter ( - evt, - kEventParamCustomMaxValue, - typeLongInteger, - sizeof(max), - &max); - } - - if(result == noErr) - { - if(text != NULL) - { - result = SetEventParameter ( - evt, - kEventParamCustomText, - typeCFStringRef, - sizeof(text), - &text); - } - } - - if(result == noErr) - { - // Send the event - PostEventToQueue( - GetMainEventQueue(), - evt, - kEventPriorityStandard); - - } - - return(result); -} - -OSStatus sendDone(void) -{ - OSStatus result; - EventRef evt; - - result = CreateEvent( - NULL, - kEventClassCustom, - kEventCustomDone, - 0, - kEventAttributeNone, - &evt); - - // This event needs to be targeted at the window so it goes to the window's handler. - if(result == noErr) - { - EventTargetRef target = GetWindowEventTarget(gWindow); - result = SetEventParameter ( - evt, - kEventParamPostTarget, - typeEventTargetRef, - sizeof(target), - &target); - } - - if(result == noErr) - { - // Send the event - PostEventToQueue( - GetMainEventQueue(), - evt, - kEventPriorityStandard); - - } - - return(result); -} - -OSStatus dialogHandler(EventHandlerCallRef handler, EventRef event, void *userdata) -{ - OSStatus result = eventNotHandledErr; - OSStatus err; - UInt32 evtClass = GetEventClass(event); - UInt32 evtKind = GetEventKind(event); - - if((evtClass == kEventClassCommand) && (evtKind == kEventCommandProcess)) - { - HICommand cmd; - err = GetEventParameter(event, kEventParamDirectObject, typeHICommand, NULL, sizeof(cmd), NULL, &cmd); - - if(err == noErr) - { - switch(cmd.commandID) - { - case kHICommandCancel: - gCancelled = true; -// QuitAppModalLoopForWindow(gWindow); - result = noErr; - break; - } - } - } - else if((evtClass == kEventClassCustom) && (evtKind == kEventCustomProgress)) - { - // Request to update the progress dialog - long cur = 0; - long max = 0; - CFStringRef text = NULL; - (void) GetEventParameter(event, kEventParamCustomCurValue, typeLongInteger, NULL, sizeof(cur), NULL, &cur); - (void) GetEventParameter(event, kEventParamCustomMaxValue, typeLongInteger, NULL, sizeof(max), NULL, &max); - (void) GetEventParameter(event, kEventParamCustomText, typeCFStringRef, NULL, sizeof(text), NULL, &text); - - err = setProgress(cur, max); - if(err == noErr) - { - if(text != NULL) - { - setProgressText(text); - } - } - - result = noErr; - } - else if((evtClass == kEventClassCustom) && (evtKind == kEventCustomDone)) - { - // We're done. Exit the modal loop. - QuitAppModalLoopForWindow(gWindow); - result = noErr; - } - - return(result); -} - -#if 0 -size_t curl_download_callback(void *data, size_t size, size_t nmemb, - void *user_data) -{ - S32 bytes = size * nmemb; - char *cdata = (char *) data; - for (int i =0; i < bytes; i += 1) - { - gServerResponse.append(cdata[i]); - } - return bytes; -} -#endif - -int curl_progress_callback_func(void *clientp, - double dltotal, - double dlnow, - double ultotal, - double ulnow) -{ - int max = (int)(dltotal / 1024.0); - int cur = (int)(dlnow / 1024.0); - sendProgress(cur, max); - - if(gCancelled) - return(1); - - return(0); -} - -int parse_args(int argc, char **argv) -{ - int j; - - for (j = 1; j < argc; j++) - { - if ((!strcmp(argv[j], "-url")) && (++j < argc)) - { - gUpdateURL = argv[j]; - } - else if ((!strcmp(argv[j], "-name")) && (++j < argc)) - { - gProductName = argv[j]; - } - else if ((!strcmp(argv[j], "-bundleid")) && (++j < argc)) - { - gBundleID = argv[j]; - } - } - - return 0; -} - -int main(int argc, char **argv) -{ - // We assume that all the logs we're looking for reside on the current drive - gDirUtilp->initAppDirs("SecondLife"); - - LLError::initForApplication( gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "")); - - // Rename current log file to ".old" - std::string old_log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "updater.log.old"); - std::string log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "updater.log"); - LLFile::rename(log_file.c_str(), old_log_file.c_str()); - - // Set the log file to updater.log - LLError::logToFile(log_file); - - ///////////////////////////////////////// - // - // Process command line arguments - // - gUpdateURL = NULL; - gProductName = NULL; - gBundleID = NULL; - parse_args(argc, argv); - if (!gUpdateURL) - { - llinfos << "Usage: mac_updater -url [-name ] [-program ]" << llendl; - exit(1); - } - else - { - llinfos << "Update url is: " << gUpdateURL << llendl; - if (gProductName) - { - llinfos << "Product name is: " << gProductName << llendl; - } - else - { - gProductName = "Second Life"; - } - if (gBundleID) - { - llinfos << "Bundle ID is: " << gBundleID << llendl; - } - else - { - gBundleID = "com.secondlife.indra.viewer"; - } - } - - llinfos << "Starting " << gProductName << " Updater" << llendl; - - // Real UI... - OSStatus err; - IBNibRef nib = NULL; - - err = CreateNibReference(CFSTR("AutoUpdater"), &nib); - - char windowTitle[MAX_PATH]; /* Flawfinder: ignore */ - snprintf(windowTitle, sizeof(windowTitle), "%s Updater", gProductName); - CFStringRef windowTitleRef = NULL; - windowTitleRef = CFStringCreateWithCString(NULL, windowTitle, kCFStringEncodingUTF8); - - if(err == noErr) - { - err = CreateWindowFromNib(nib, CFSTR("Updater"), &gWindow); - } - - if (err == noErr) - { - err = SetWindowTitleWithCFString(gWindow, windowTitleRef); - } - CFRelease(windowTitleRef); - - if(err == noErr) - { - // Set up an event handler for the window. - EventTypeSpec handlerEvents[] = - { - { kEventClassCommand, kEventCommandProcess }, - { kEventClassCustom, kEventCustomProgress }, - { kEventClassCustom, kEventCustomDone } - }; - InstallStandardEventHandler(GetWindowEventTarget(gWindow)); - InstallWindowEventHandler( - gWindow, - NewEventHandlerUPP(dialogHandler), - GetEventTypeCount (handlerEvents), - handlerEvents, - 0, - &gEventHandler); - } - - if(err == noErr) - { - ShowWindow(gWindow); - SelectWindow(gWindow); - } - - if(err == noErr) - { - pthread_create(&updatethread, - NULL, - &updatethreadproc, - NULL); - - } - - if(err == noErr) - { - RunAppModalLoopForWindow(gWindow); - } - - void *threadresult; - - pthread_join(updatethread, &threadresult); - - if(!gCancelled && (gFailure != noErr)) - { - // Something went wrong. Since we always just tell the user to download a new version, we don't really care what. - AlertStdCFStringAlertParamRec params; - SInt16 retval_mac = 1; - DialogRef alert = NULL; - OSStatus err; - - params.version = kStdCFStringAlertVersionOne; - params.movable = false; - params.helpButton = false; - params.defaultText = (CFStringRef)kAlertDefaultOKText; - params.cancelText = 0; - params.otherText = 0; - params.defaultButton = 1; - params.cancelButton = 0; - params.position = kWindowDefaultPosition; - params.flags = 0; - - err = CreateStandardAlert( - kAlertStopAlert, - CFSTR("Error"), - CFSTR("An error occurred while updating Second Life. Please download the latest version from www.secondlife.com."), - ¶ms, - &alert); - - if(err == noErr) - { - err = RunStandardAlert( - alert, - NULL, - &retval_mac); - } - - } - - // Don't dispose of things, just exit. This keeps the update thread from potentially getting hosed. - exit(0); - - if(gWindow != NULL) - { - DisposeWindow(gWindow); - } - - if(nib != NULL) - { - DisposeNibReference(nib); - } - - return 0; -} - -bool isDirWritable(FSRef &dir) -{ - bool result = false; - - // Test for a writable directory by creating a directory, then deleting it again. - // This is kinda lame, but will pretty much always give the right answer. - - OSStatus err = noErr; - char temp[PATH_MAX] = ""; /* Flawfinder: ignore */ - - err = FSRefMakePath(&dir, (UInt8*)temp, sizeof(temp)); - - if(err == noErr) - { - strncat(temp, "/.test_XXXXXX", (sizeof(temp) - strlen(temp)) - 1); - - if(mkdtemp(temp) != NULL) - { - // We were able to make the directory. This means the directory is writable. - result = true; - - // Clean up. - rmdir(temp); - } - } - -#if 0 - // This seemed like a good idea, but won't tell us if we're on a volume mounted read-only. - UInt8 perm; - err = FSGetUserPrivilegesPermissions(&targetParentRef, &perm, NULL); - if(err == noErr) - { - if(perm & kioACUserNoMakeChangesMask) - { - // Parent directory isn't writable. - llinfos << "Target parent directory not writable." << llendl; - err = -1; - replacingTarget = false; - } - } -#endif - - return result; -} - -static std::string HFSUniStr255_to_utf8str(const HFSUniStr255* src) -{ - llutf16string string16((U16*)&(src->unicode), src->length); - std::string result = utf16str_to_utf8str(string16); - return result; -} - -int restoreObject(const char* aside, const char* target, const char* path, const char* object) -{ - char source[PATH_MAX] = ""; /* Flawfinder: ignore */ - char dest[PATH_MAX] = ""; /* Flawfinder: ignore */ - snprintf(source, sizeof(source), "%s/%s/%s", aside, path, object); - snprintf(dest, sizeof(dest), "%s/%s", target, path); - FSRef sourceRef; - FSRef destRef; - OSStatus err; - err = FSPathMakeRef((UInt8 *)source, &sourceRef, NULL); - if(err != noErr) return false; - err = FSPathMakeRef((UInt8 *)dest, &destRef, NULL); - if(err != noErr) return false; - - llinfos << "Copying " << source << " to " << dest << llendl; - - err = FSCopyObjectSync( - &sourceRef, - &destRef, - NULL, - NULL, - kFSFileOperationOverwrite); - - if(err != noErr) return false; - return true; -} - -// Replace any mention of "Second Life" with the product name. -void filterFile(const char* filename) -{ - char temp[PATH_MAX] = ""; /* Flawfinder: ignore */ - // First copy the target's version, so we can run it through sed. - snprintf(temp, sizeof(temp), "cp '%s' '%s.tmp'", filename, filename); - system(temp); /* Flawfinder: ignore */ - - // Now run it through sed. - snprintf(temp, sizeof(temp), - "sed 's/Second Life/%s/g' '%s.tmp' > '%s'", gProductName, filename, filename); - system(temp); /* Flawfinder: ignore */ -} - -static bool isFSRefViewerBundle(FSRef *targetRef) -{ - bool result = false; - CFURLRef targetURL = NULL; - CFBundleRef targetBundle = NULL; - CFStringRef targetBundleID = NULL; - CFStringRef sourceBundleID = NULL; - - targetURL = CFURLCreateFromFSRef(NULL, targetRef); - - if(targetURL == NULL) - { - llinfos << "Error creating target URL." << llendl; - } - else - { - targetBundle = CFBundleCreate(NULL, targetURL); - } - - if(targetBundle == NULL) - { - llinfos << "Failed to create target bundle." << llendl; - } - else - { - targetBundleID = CFBundleGetIdentifier(targetBundle); - } - - if(targetBundleID == NULL) - { - llinfos << "Couldn't retrieve target bundle ID." << llendl; - } - else - { - sourceBundleID = CFStringCreateWithCString(NULL, gBundleID, kCFStringEncodingUTF8); - if(CFStringCompare(sourceBundleID, targetBundleID, 0) == kCFCompareEqualTo) - { - // This is the bundle we're looking for. - result = true; - } - else - { - llinfos << "Target bundle ID mismatch." << llendl; - } - } - - // Don't release targetBundleID -- since we don't retain it, it's released when targetBundle is released. - if(targetURL != NULL) - CFRelease(targetURL); - if(targetBundle != NULL) - CFRelease(targetBundle); - - return result; -} - -// Search through the directory specified by 'parent' for an item that appears to be a Second Life viewer. -static OSErr findAppBundleOnDiskImage(FSRef *parent, FSRef *app) -{ - FSIterator iterator; - bool found = false; - - OSErr err = FSOpenIterator( parent, kFSIterateFlat, &iterator ); - if(!err) - { - do - { - ItemCount actualObjects = 0; - Boolean containerChanged = false; - FSCatalogInfo info; - FSRef ref; - HFSUniStr255 unicodeName; - err = FSGetCatalogInfoBulk( - iterator, - 1, - &actualObjects, - &containerChanged, - kFSCatInfoNodeFlags, - &info, - &ref, - NULL, - &unicodeName ); - - if(actualObjects == 0) - break; - - if(!err) - { - // Call succeeded and not done with the iteration. - std::string name = HFSUniStr255_to_utf8str(&unicodeName); - - llinfos << "Considering \"" << name << "\"" << llendl; - - if(info.nodeFlags & kFSNodeIsDirectoryMask) - { - // This is a directory. See if it's a .app - if(name.find(".app") != std::string::npos) - { - // Looks promising. Check to see if it has the right bundle identifier. - if(isFSRefViewerBundle(&ref)) - { - // This is the one. Return it. - *app = ref; - found = true; - } - } - } - } - } - while(!err && !found); - - FSCloseIterator(iterator); - } - - if(!err && !found) - err = fnfErr; - - return err; -} - -void *updatethreadproc(void*) -{ - char tempDir[PATH_MAX] = ""; /* Flawfinder: ignore */ - FSRef tempDirRef; - char temp[PATH_MAX] = ""; /* Flawfinder: ignore */ - // *NOTE: This buffer length is used in a scanf() below. - char deviceNode[1024] = ""; /* Flawfinder: ignore */ - LLFILE *downloadFile = NULL; - OSStatus err; - ProcessSerialNumber psn; - char target[PATH_MAX] = ""; /* Flawfinder: ignore */ - FSRef targetRef; - FSRef targetParentRef; - FSVolumeRefNum targetVol; - FSRef trashFolderRef; - Boolean replacingTarget = false; - - memset(&tempDirRef, 0, sizeof(tempDirRef)); - memset(&targetRef, 0, sizeof(targetRef)); - memset(&targetParentRef, 0, sizeof(targetParentRef)); - - try - { - // Attempt to get a reference to the Second Life application bundle containing this updater. - // Any failures during this process will cause us to default to updating /Applications/Second Life.app - { - FSRef myBundle; - - err = GetCurrentProcess(&psn); - if(err == noErr) - { - err = GetProcessBundleLocation(&psn, &myBundle); - } - - if(err == noErr) - { - // Sanity check: Make sure the name of the item referenced by targetRef is "Second Life.app". - FSRefMakePath(&myBundle, (UInt8*)target, sizeof(target)); - - llinfos << "Updater bundle location: " << target << llendl; - } - - // Our bundle should be in Second Life.app/Contents/Resources/AutoUpdater.app - // so we need to go up 3 levels to get the path to the main application bundle. - if(err == noErr) - { - err = FSGetCatalogInfo(&myBundle, kFSCatInfoNone, NULL, NULL, NULL, &targetRef); - } - if(err == noErr) - { - err = FSGetCatalogInfo(&targetRef, kFSCatInfoNone, NULL, NULL, NULL, &targetRef); - } - if(err == noErr) - { - err = FSGetCatalogInfo(&targetRef, kFSCatInfoNone, NULL, NULL, NULL, &targetRef); - } - - // And once more to get the parent of the target - if(err == noErr) - { - err = FSGetCatalogInfo(&targetRef, kFSCatInfoNone, NULL, NULL, NULL, &targetParentRef); - } - - if(err == noErr) - { - FSRefMakePath(&targetRef, (UInt8*)target, sizeof(target)); - llinfos << "Path to target: " << target << llendl; - } - - // Sanity check: make sure the target is a bundle with the right identifier - if(err == noErr) - { - // Assume the worst... - err = -1; - - if(isFSRefViewerBundle(&targetRef)) - { - // This is the bundle we're looking for. - err = noErr; - replacingTarget = true; - } - } - - // Make sure the target's parent directory is writable. - if(err == noErr) - { - if(!isDirWritable(targetParentRef)) - { - // Parent directory isn't writable. - llinfos << "Target parent directory not writable." << llendl; - err = -1; - replacingTarget = false; - } - } - - if(err != noErr) - { - Boolean isDirectory; - llinfos << "Target search failed, defaulting to /Applications/" << gProductName << ".app." << llendl; - - // Set up the parent directory - err = FSPathMakeRef((UInt8*)"/Applications", &targetParentRef, &isDirectory); - if((err != noErr) || (!isDirectory)) - { - // We're so hosed. - llinfos << "Applications directory not found, giving up." << llendl; - throw 0; - } - - snprintf(target, sizeof(target), "/Applications/%s.app", gProductName); - - memset(&targetRef, 0, sizeof(targetRef)); - err = FSPathMakeRef((UInt8*)target, &targetRef, NULL); - if(err == fnfErr) - { - // This is fine, just means we're not replacing anything. - err = noErr; - replacingTarget = false; - } - else - { - replacingTarget = true; - } - - // Make sure the target's parent directory is writable. - if(err == noErr) - { - if(!isDirWritable(targetParentRef)) - { - // Parent directory isn't writable. - llinfos << "Target parent directory not writable." << llendl; - err = -1; - replacingTarget = false; - } - } - - } - - // If we haven't fixed all problems by this point, just bail. - if(err != noErr) - { - llinfos << "Unable to pick a target, giving up." << llendl; - throw 0; - } - } - - // Find the volID of the volume the target resides on - { - FSCatalogInfo info; - err = FSGetCatalogInfo( - &targetParentRef, - kFSCatInfoVolume, - &info, - NULL, - NULL, - NULL); - - if(err != noErr) - throw 0; - - targetVol = info.volume; - } - - // Find the temporary items and trash folders on that volume. - err = FSFindFolder( - targetVol, - kTrashFolderType, - true, - &trashFolderRef); - - if(err != noErr) - throw 0; - -#if 0 // *HACK for DEV-11935 see below for details. - - FSRef tempFolderRef; - - err = FSFindFolder( - targetVol, - kTemporaryFolderType, - true, - &tempFolderRef); - - if(err != noErr) - throw 0; - - err = FSRefMakePath(&tempFolderRef, (UInt8*)temp, sizeof(temp)); - - if(err != noErr) - throw 0; - -#else - - // *HACK for DEV-11935 the above kTemporaryFolderType query was giving - // back results with path names that seem to be too long to be used as - // mount points. I suspect this incompatibility was introduced in the - // Leopard 10.5.2 update, but I have not verified this. - char const HARDCODED_TMP[] = "/tmp"; - strncpy(temp, HARDCODED_TMP, sizeof(HARDCODED_TMP)); - -#endif // 0 *HACK for DEV-11935 - - strncat(temp, "/SecondLifeUpdate_XXXXXX", (sizeof(temp) - strlen(temp)) - 1); - if(mkdtemp(temp) == NULL) - { - throw 0; - } - - strncpy(tempDir, temp, sizeof(tempDir)); - temp[sizeof(tempDir) - 1] = '\0'; - - llinfos << "tempDir is " << tempDir << llendl; - - err = FSPathMakeRef((UInt8*)tempDir, &tempDirRef, NULL); - - if(err != noErr) - throw 0; - - chdir(tempDir); - - snprintf(temp, sizeof(temp), "SecondLife.dmg"); - - downloadFile = LLFile::fopen(temp, "wb"); /* Flawfinder: ignore */ - if(downloadFile == NULL) - { - throw 0; - } - - { - CURL *curl = curl_easy_init(); - - curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); - // curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &curl_download_callback); - curl_easy_setopt(curl, CURLOPT_FILE, downloadFile); - curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0); - curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, &curl_progress_callback_func); - curl_easy_setopt(curl, CURLOPT_URL, gUpdateURL); - curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); - - sendProgress(0, 1, CFSTR("Downloading...")); - - CURLcode result = curl_easy_perform(curl); - - curl_easy_cleanup(curl); - - if(gCancelled) - { - llinfos << "User cancel, bailing out."<< llendl; - throw 0; - } - - if(result != CURLE_OK) - { - llinfos << "Error " << result << " while downloading disk image."<< llendl; - throw 0; - } - - fclose(downloadFile); - downloadFile = NULL; - } - - sendProgress(0, 0, CFSTR("Mounting image...")); - LLFile::mkdir("mnt", 0700); - - // NOTE: we could add -private at the end of this command line to keep the image from showing up in the Finder, - // but if our cleanup fails, this makes it much harder for the user to unmount the image. - std::string mountOutput; - FILE* mounter = popen("hdiutil attach SecondLife.dmg -mountpoint mnt", "r"); /* Flawfinder: ignore */ - - if(mounter == NULL) - { - llinfos << "Failed to mount disk image, exiting."<< llendl; - throw 0; - } - - // We need to scan the output from hdiutil to find the device node it uses to attach the disk image. - // If we don't have this information, we can't detach it later. - while(mounter != NULL) - { - size_t len = fread(temp, 1, sizeof(temp)-1, mounter); - temp[len] = 0; - mountOutput.append(temp); - if(len < sizeof(temp)-1) - { - // End of file or error. - int result = pclose(mounter); - if(result != 0) - { - // NOTE: We used to abort here, but pclose() started returning - // -1, possibly when the size of the DMG passed a certain point - llinfos << "Unexpected result closing pipe: " << result << llendl; - } - mounter = NULL; - } - } - - if(!mountOutput.empty()) - { - const char *s = mountOutput.c_str(); - const char *prefix = "/dev/"; - char *sub = strstr(s, prefix); - - if(sub != NULL) - { - sub += strlen(prefix); /* Flawfinder: ignore */ - sscanf(sub, "%1023s", deviceNode); /* Flawfinder: ignore */ - } - } - - if(deviceNode[0] != 0) - { - llinfos << "Disk image attached on /dev/" << deviceNode << llendl; - } - else - { - llinfos << "Disk image device node not found!" << llendl; - throw 0; - } - - // Get an FSRef to the new application on the disk image - FSRef sourceRef; - FSRef mountRef; - snprintf(temp, sizeof(temp), "%s/mnt", tempDir); - - llinfos << "Disk image mount point is: " << temp << llendl; - - err = FSPathMakeRef((UInt8 *)temp, &mountRef, NULL); - if(err != noErr) - { - llinfos << "Couldn't make FSRef to disk image mount point." << llendl; - throw 0; - } - - err = findAppBundleOnDiskImage(&mountRef, &sourceRef); - if(err != noErr) - { - llinfos << "Couldn't find application bundle on mounted disk image." << llendl; - throw 0; - } - - FSRef asideRef; - char aside[MAX_PATH]; /* Flawfinder: ignore */ - - // this will hold the name of the destination target - CFStringRef appNameRef; - - if(replacingTarget) - { - // Get the name of the target we're replacing - HFSUniStr255 appNameUniStr; - err = FSGetCatalogInfo(&targetRef, 0, NULL, &appNameUniStr, NULL, NULL); - if(err != noErr) - throw 0; - appNameRef = FSCreateStringFromHFSUniStr(NULL, &appNameUniStr); - - // Move aside old version (into work directory) - err = FSMoveObject(&targetRef, &tempDirRef, &asideRef); - if(err != noErr) - throw 0; - - // Grab the path for later use. - err = FSRefMakePath(&asideRef, (UInt8*)aside, sizeof(aside)); - } - else - { - // Construct the name of the target based on the product name - char appName[MAX_PATH]; /* Flawfinder: ignore */ - snprintf(appName, sizeof(appName), "%s.app", gProductName); - appNameRef = CFStringCreateWithCString(NULL, appName, kCFStringEncodingUTF8); - } - - sendProgress(0, 0, CFSTR("Copying files...")); - - llinfos << "Starting copy..." << llendl; - - // Copy the new version from the disk image to the target location. - err = FSCopyObjectSync( - &sourceRef, - &targetParentRef, - appNameRef, - &targetRef, - kFSFileOperationDefaultOptions); - - // Grab the path for later use. - err = FSRefMakePath(&targetRef, (UInt8*)target, sizeof(target)); - if(err != noErr) - throw 0; - - llinfos << "Copy complete. Target = " << target << llendl; - - if(err != noErr) - { - // Something went wrong during the copy. Attempt to put the old version back and bail. - (void)FSDeleteObject(&targetRef); - if(replacingTarget) - { - (void)FSMoveObject(&asideRef, &targetParentRef, NULL); - } - throw 0; - } - else - { - // The update has succeeded. Clear the cache directory. - - sendProgress(0, 0, CFSTR("Clearing cache...")); - - llinfos << "Clearing cache..." << llendl; - - gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""),"*.*"); - - llinfos << "Clear complete." << llendl; - - } - } - catch(...) - { - if(!gCancelled) - if(gFailure == noErr) - gFailure = -1; - } - - // Failures from here on out are all non-fatal and not reported. - sendProgress(0, 3, CFSTR("Cleaning up...")); - - // Close disk image file if necessary - if(downloadFile != NULL) - { - llinfos << "Closing download file." << llendl; - - fclose(downloadFile); - downloadFile = NULL; - } - - sendProgress(1, 3); - // Unmount image - if(deviceNode[0] != 0) - { - llinfos << "Detaching disk image." << llendl; - - snprintf(temp, sizeof(temp), "hdiutil detach '%s'", deviceNode); - system(temp); /* Flawfinder: ignore */ - } - - sendProgress(2, 3); - - // Move work directory to the trash - if(tempDir[0] != 0) - { -// chdir("/"); -// FSDeleteObjects(tempDirRef); - - llinfos << "Moving work directory to the trash." << llendl; - - err = FSMoveObject(&tempDirRef, &trashFolderRef, NULL); - -// snprintf(temp, sizeof(temp), "rm -rf '%s'", tempDir); -// printf("%s\n", temp); -// system(temp); - } - - if(!gCancelled && !gFailure && (target[0] != 0)) - { - llinfos << "Touching application bundle." << llendl; - - snprintf(temp, sizeof(temp), "touch '%s'", target); - system(temp); /* Flawfinder: ignore */ - - llinfos << "Launching updated application." << llendl; - - snprintf(temp, sizeof(temp), "open '%s'", target); - system(temp); /* Flawfinder: ignore */ - } - - sendDone(); - - return(NULL); -} diff --git a/indra/newview/Ascent.icns b/indra/newview/Ascent.icns deleted file mode 100644 index b2d2aa3b83..0000000000 Binary files a/indra/newview/Ascent.icns and /dev/null differ diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 74cbf25a01..60d8e0ad99 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -3,22 +3,23 @@ project(viewer) include(00-Common) +# DON'T move Linking.cmake to its place in the alphabetized list below: it +# sets variables on which the 3p .cmake files depend. +include(Linking) + include(Boost) +include(BuildPackagesInfo) +include(BuildVersion) +include(BuildBranding) +include(CMakeCopyIfDifferent) +include(CrashPad) include(DBusGlib) -include(DirectX) -include(ELFIO) -if(FMODEX) - include(FMODEX) - set(FMOD OFF) -endif(FMODEX) -if(FMOD) - include(FMOD) -endif(FMOD) -include(OPENAL) -include(FindOpenGL) +include(FMODSTUDIO) +include(GeneratePrecompiledHeader) +include(GLOD) include(Hunspell) -include(JsonCpp) include(LLAddBuildTest) +include(LLAppearance) include(LLAudio) include(LLCharacter) include(LLCommon) @@ -35,36 +36,41 @@ include(LLUI) include(LLVFS) include(LLWindow) include(LLXML) -#include(LScript) -include(Linking) include(NDOF) +include(NVAPI) +include(OPENAL) +include(OpenGL) +include(OpenSSL) include(StateMachine) include(TemplateCheck) include(UI) include(ViewerMiscLibs) -include(GLOD) -include(LLAppearance) +include(WinManifest) +include(ZLIB) +include(URIPARSER) -if (WINDOWS) - include(CopyWinLibs) -endif (WINDOWS) + +if(USE_FMODSTUDIO) + include_directories(${FMODSTUDIO_INCLUDE_DIR}) +endif(USE_FMODSTUDIO) + +if(USE_CRASHPAD) + include_directories(${CRASHPAD_INCLUDE_DIRS}) +endif(USE_CRASHPAD) include_directories( - ${CMAKE_SOURCE_DIR}/newview ${STATEMACHINE_INCLUDE_DIRS} ${DBUSGLIB_INCLUDE_DIRS} - ${HUNSPELL_INCLUDE_DIR} - ${ELFIO_INCLUDE_DIR} - ${JSONCPP_INCLUDE_DIR} - ${GLOD_INCLUDE_DIRS} + ${ZLIB_INCLUDE_DIRS} + ${GLOD_INCLUDE_DIR} ${LLAUDIO_INCLUDE_DIRS} ${LLCHARACTER_INCLUDE_DIRS} ${LLCOMMON_INCLUDE_DIRS} + ${LLPHYSICSEXTENSIONS_INCLUDE_DIRS} ${LLIMAGE_INCLUDE_DIRS} ${LLINVENTORY_INCLUDE_DIRS} ${LLMATH_INCLUDE_DIRS} ${LLMESSAGE_INCLUDE_DIRS} - ${LLPHYSICSEXTENSIONS_INCLUDE_DIRS} ${LLPLUGIN_INCLUDE_DIRS} ${LLPRIMITIVE_INCLUDE_DIRS} ${LLRENDER_INCLUDE_DIRS} @@ -72,15 +78,19 @@ include_directories( ${LLVFS_INCLUDE_DIRS} ${LLWINDOW_INCLUDE_DIRS} ${LLXML_INCLUDE_DIRS} + ${HUNSPELL_INCLUDE_DIR} + ${OPENAL_LIB_INCLUDE_DIRS} ${LLAPPEARANCE_INCLUDE_DIRS} -# ${LSCRIPT_INCLUDE_DIRS} -# ${LSCRIPT_INCLUDE_DIRS}/lscript_compile + ${CMAKE_CURRENT_SOURCE_DIR} ) set(viewer_SOURCE_FILES NACLantispam.cpp aihttpview.cpp + aixmllindengenepool.cpp + alfloaterregiontracker.cpp aoremotectrl.cpp + aosystem.cpp ascentfloatercontactgroups.cpp ascentkeyword.cpp ascentprefschat.cpp @@ -91,10 +101,9 @@ set(viewer_SOURCE_FILES daeexport.cpp floaterao.cpp floaterlocalassetbrowse.cpp - floatervoicelicense.cpp - generichandlers.cpp - hbfloatergrouptitles.cpp + generichandlers.cpp groupchatlistener.cpp + hbfloatergrouptitles.cpp hippofloaterxml.cpp hippogridmanager.cpp hippolimits.cpp @@ -106,8 +115,10 @@ set(viewer_SOURCE_FILES lggdicdownload.cpp lgghunspell_wrapper.cpp llaccountingcostmanager.cpp + llaisapi.cpp llagent.cpp llagentaccess.cpp + llagentbenefits.cpp llagentcamera.cpp llagentdata.cpp llagentlanguage.cpp @@ -122,8 +133,10 @@ set(viewer_SOURCE_FILES llassetuploadresponders.cpp llattachmentsmgr.cpp llaudiosourcevo.cpp + llautoreplace.cpp llavataractions.cpp llavatarpropertiesprocessor.cpp + llavatarrenderinfoaccountant.cpp llbox.cpp llcallbacklist.cpp llcallingcard.cpp @@ -140,6 +153,7 @@ set(viewer_SOURCE_FILES llcompilequeue.cpp llconfirmationmanager.cpp llconsole.cpp + llcontrolavatar.cpp llcurrencyuimanager.cpp llcylinder.cpp lldaycyclemanager.cpp @@ -152,6 +166,7 @@ set(viewer_SOURCE_FILES lldrawpoolavatar.cpp lldrawpoolbump.cpp lldrawpoolground.cpp + lldrawpoolmaterials.cpp lldrawpoolsimple.cpp lldrawpoolsky.cpp lldrawpoolterrain.cpp @@ -166,19 +181,24 @@ set(viewer_SOURCE_FILES lleventinfo.cpp lleventnotifier.cpp lleventpoll.cpp + llexperiencelog.cpp llexternaleditor.cpp llface.cpp llfasttimerview.cpp + llfavoritesbar.cpp llfeaturemanager.cpp llfirstuse.cpp llflexibleobject.cpp llfloaterabout.cpp llfloateractivespeakers.cpp llfloaterauction.cpp + llfloaterautoreplacesettings.cpp + llfloateravatar.cpp llfloateravatarinfo.cpp llfloateravatarlist.cpp llfloateravatarpicker.cpp llfloateravatartextures.cpp + llfloaterbanduration.cpp llfloaterbeacons.cpp llfloaterblacklist.cpp llfloaterbuildoptions.cpp @@ -196,11 +216,15 @@ set(viewer_SOURCE_FILES llfloatercolorpicker.cpp llfloatercustomize.cpp llfloaterdaycycle.cpp + llfloaterdestinations.cpp llfloaterdirectory.cpp llfloaterdisplayname.cpp llfloatereditui.cpp llfloaterenvsettings.cpp llfloaterevent.cpp + llfloaterexperiencepicker.cpp + llfloaterexperienceprofile.cpp + llfloaterexperiences.cpp llfloaterexploreanimations.cpp llfloaterexploresounds.cpp llfloaterfeed.cpp @@ -208,6 +232,7 @@ set(viewer_SOURCE_FILES llfloaterfriends.cpp llfloatergesture.cpp llfloatergodtools.cpp + llfloatergroupbulkban.cpp llfloatergroupinfo.cpp llfloatergroupinvite.cpp llfloatergroups.cpp @@ -218,11 +243,12 @@ set(viewer_SOURCE_FILES llfloaterimagepreview.cpp llfloaterinspect.cpp llfloaterjoystick.cpp - llfloaterlagmeter.cpp llfloaterland.cpp llfloaterlandholdings.cpp llfloaterlandmark.cpp llfloatermap.cpp + llfloatermarketplacelistings.cpp + llfloatermediafilter.cpp llfloatermediasettings.cpp llfloatermemleak.cpp llfloatermessagelog.cpp @@ -232,13 +258,12 @@ set(viewer_SOURCE_FILES llfloaternamedesc.cpp llfloaternotificationsconsole.cpp llfloaterobjectiminfo.cpp + llfloaterobjectweights.cpp llfloateropenobject.cpp - llfloateroutbox.cpp llfloaterparcel.cpp llfloaterpathfindingcharacters.cpp llfloaterpathfindinglinksets.cpp llfloaterpathfindingobjects.cpp - llfloaterpermissionsmgr.cpp llfloaterperms.cpp llfloaterpostcard.cpp llfloaterpostprocess.cpp @@ -246,6 +271,7 @@ set(viewer_SOURCE_FILES llfloaterproperties.cpp llfloaterregiondebugconsole.cpp llfloaterregioninfo.cpp + llfloaterregionrestarting.cpp llfloaterreporter.cpp llfloaterscriptdebug.cpp llfloaterscriptlimits.cpp @@ -284,6 +310,7 @@ set(viewer_SOURCE_FILES llgroupnotify.cpp llhomelocationresponder.cpp llhoverview.cpp + llhttpretrypolicy.cpp llhudeffect.cpp llhudeffectbeam.cpp llhudeffectlookat.cpp @@ -297,6 +324,7 @@ set(viewer_SOURCE_FILES llhudtext.cpp llhudview.cpp llimpanel.cpp + llimprocessing.cpp llimview.cpp llinventoryactions.cpp llinventorybridge.cpp @@ -309,6 +337,7 @@ set(viewer_SOURCE_FILES llinventoryobserver.cpp llinventorypanel.cpp lljoystickbutton.cpp + lllandmarkactions.cpp lllandmarklist.cpp lllogchat.cpp llloginhandler.cpp @@ -324,6 +353,7 @@ set(viewer_SOURCE_FILES llmaterialmgr.cpp llmediactrl.cpp llmediadataclient.cpp + llmediafilter.cpp llmediaremotectrl.cpp llmenucommands.cpp llmenuoptionpathfindingrebakenavmesh.cpp @@ -335,6 +365,7 @@ set(viewer_SOURCE_FILES llnamebox.cpp llnameeditor.cpp llnamelistctrl.cpp + llnameui.cpp llnetmap.cpp llnotify.cpp lloutfitobserver.cpp @@ -356,9 +387,16 @@ set(viewer_SOURCE_FILES llpaneldisplay.cpp llpaneleditwearable.cpp llpanelevent.cpp + llpanelexperiencelisteditor.cpp + llpanelexperiencelog.cpp + llpanelexperiencepicker.cpp + llpanelexperiences.cpp llpanelface.cpp llpanelgeneral.cpp llpanelgroup.cpp + llpanelgroupbulk.cpp + llpanelgroupbulkban.cpp + llpanelgroupexperiences.cpp llpanelgroupgeneral.cpp llpanelgroupinvite.cpp llpanelgrouplandmoney.cpp @@ -373,7 +411,6 @@ set(viewer_SOURCE_FILES llpanellandoptions.cpp llpanellogin.cpp llpanelmaininventory.cpp - llpanelmarketplaceoutboxinventory.cpp llpanelmediasettingsgeneral.cpp llpanelmediasettingspermissions.cpp llpanelmediasettingssecurity.cpp @@ -427,7 +464,10 @@ set(viewer_SOURCE_FILES llsavedsettingsglue.cpp llscrollingpanelparam.cpp llscrollingpanelparambase.cpp + llsculptidsize.cpp llselectmgr.cpp + llshareavatarhandler.cpp + llskinningutil.cpp llsky.cpp llslurl.cpp llspatialpartition.cpp @@ -467,6 +507,7 @@ set(viewer_SOURCE_FILES lltoolselectrect.cpp lltoolview.cpp lltracker.cpp + lluiavatar.cpp lluploaddialog.cpp lluploadfloaterobservers.cpp llurl.cpp @@ -475,6 +516,7 @@ set(viewer_SOURCE_FILES llurlwhitelist.cpp lluserauth.cpp llvectorperfoptions.cpp + llversioninfo.cpp llvelocitybar.cpp llviewchildren.cpp llviewerassetstats.cpp @@ -505,6 +547,7 @@ set(viewer_SOURCE_FILES llviewerobject.cpp llviewerobjectbackup.cpp llviewerobjectlist.cpp + llvieweroctree.cpp llviewerparcelmedia.cpp llviewerparcelmediaautoplay.cpp llviewerparcelmgr.cpp @@ -565,12 +608,12 @@ set(viewer_SOURCE_FILES llworldmipmap.cpp llxmlrpcresponder.cpp m7wlinterface.cpp - noise.cpp pipeline.cpp qtoolalign.cpp + rlvactions.cpp rlvcommon.cpp rlvextensions.cpp - rlvfloaterbehaviour.cpp + rlvfloaters.cpp rlvhandler.cpp rlvhelper.cpp rlvinventory.cpp @@ -578,24 +621,23 @@ set(viewer_SOURCE_FILES rlvui.cpp scriptcounter.cpp sgmemstat.cpp - sgversion.cpp shcommandhandler.cpp + shupdatechecker.cpp shfloatermediaticker.cpp - slfloatermediafilter.cpp wlfPanel_AdvSettings.cpp ) -# This gets renamed in the packaging step -set(VIEWER_BINARY_NAME "secondlife-bin" CACHE STRING - "The name of the viewer executable to create.") - set(viewer_HEADER_FILES CMakeLists.txt ViewerInstall.cmake NACLantispam.h aihttpview.h + aixmllindengenepool.h + alfloaterregiontracker.h aoremotectrl.h + aostate.h + aosystem.h ascentfloatercontactgroups.h ascentkeyword.h ascentprefschat.h @@ -606,8 +648,7 @@ set(viewer_HEADER_FILES daeexport.h floaterao.h floaterlocalassetbrowse.h - floatervoicelicense.h - generichandlers.h + generichandlers.h groupchatlistener.h hbfloatergrouptitles.h hippofloaterxml.h @@ -621,8 +662,10 @@ set(viewer_HEADER_FILES lggdicdownload.h lgghunspell_wrapper.h llaccountingcostmanager.h + llaisapi.h llagent.h llagentaccess.h + llagentbenefits.h llagentcamera.h llagentdata.h llagentlanguage.h @@ -638,10 +681,11 @@ set(viewer_HEADER_FILES llassetuploadresponders.h llattachmentsmgr.h llaudiosourcevo.h + llautoreplace.h llavataractions.h llavatarpropertiesprocessor.h + llavatarrenderinfoaccountant.h llbox.h - llcallbacklist.h llcallingcard.h llcapabilitylistener.h llcaphttpsender.h @@ -656,6 +700,7 @@ set(viewer_HEADER_FILES llcompilequeue.h llconfirmationmanager.h llconsole.h + llcontrolavatar.h llcurrencyuimanager.h llcylinder.h lldaycyclemanager.h @@ -667,6 +712,7 @@ set(viewer_HEADER_FILES lldrawpoolalpha.h lldrawpoolavatar.h lldrawpoolbump.h + lldrawpoolmaterials.h lldrawpoolground.h lldrawpoolsimple.h lldrawpoolsky.h @@ -682,19 +728,24 @@ set(viewer_HEADER_FILES lleventinfo.h lleventnotifier.h lleventpoll.h + llexperiencelog.h llexternaleditor.h llface.h llfasttimerview.h + llfavoritesbar.h llfeaturemanager.h llfirstuse.h llflexibleobject.h llfloaterabout.h llfloateractivespeakers.h llfloaterauction.h + llfloaterautoreplacesettings.h + llfloateravatar.h llfloateravatarinfo.h llfloateravatarlist.h llfloateravatarpicker.h llfloateravatartextures.h + llfloaterbanduration.h llfloaterbeacons.h llfloaterblacklist.h llfloaterbuildoptions.h @@ -712,11 +763,15 @@ set(viewer_HEADER_FILES llfloatercolorpicker.h llfloatercustomize.h llfloaterdaycycle.h + llfloaterdestinations.h llfloaterdirectory.h llfloaterdisplayname.h llfloatereditui.h llfloaterenvsettings.h llfloaterevent.h + llfloaterexperiencepicker.h + llfloaterexperienceprofile.h + llfloaterexperiences.h llfloaterexploreanimations.h llfloaterexploresounds.h llfloaterfeed.h @@ -724,6 +779,7 @@ set(viewer_HEADER_FILES llfloaterfriends.h llfloatergesture.h llfloatergodtools.h + llfloatergroupbulkban.h llfloatergroupinfo.h llfloatergroupinvite.h llfloatergroups.h @@ -734,11 +790,12 @@ set(viewer_HEADER_FILES llfloaterimagepreview.h llfloaterinspect.h llfloaterjoystick.h - llfloaterlagmeter.h llfloaterland.h llfloaterlandholdings.h llfloaterlandmark.h llfloatermap.h + llfloatermarketplacelistings.h + llfloatermediafilter.h llfloatermediasettings.h llfloatermemleak.h llfloatermessagelog.h @@ -748,13 +805,12 @@ set(viewer_HEADER_FILES llfloaternamedesc.h llfloaternotificationsconsole.h llfloaterobjectiminfo.h + llfloaterobjectweights.h llfloateropenobject.h - llfloateroutbox.h llfloaterparcel.h llfloaterpathfindingcharacters.h llfloaterpathfindinglinksets.h llfloaterpathfindingobjects.h - llfloaterpermissionsmgr.h llfloaterperms.h llfloaterpostcard.h llfloaterpostprocess.h @@ -762,6 +818,7 @@ set(viewer_HEADER_FILES llfloaterproperties.h llfloaterregiondebugconsole.h llfloaterregioninfo.h + llfloaterregionrestarting.h llfloaterreporter.h llfloaterscriptdebug.h llfloaterscriptlimits.h @@ -798,6 +855,7 @@ set(viewer_HEADER_FILES llgroupactions.h llgroupmgr.h llgroupnotify.h + llhttpretrypolicy.h llhomelocationresponder.h llhoverview.h llhudeffect.h @@ -813,6 +871,7 @@ set(viewer_HEADER_FILES llhudtext.h llhudview.h llimpanel.h + llimprocessing.h llimview.h llinventorybridge.h llinventoryclipboard.h @@ -824,6 +883,7 @@ set(viewer_HEADER_FILES llinventoryobserver.h llinventorypanel.h lljoystickbutton.h + lllandmarkactions.h lllandmarklist.h lllightconstants.h lllogchat.h @@ -840,6 +900,7 @@ set(viewer_HEADER_FILES llmaterialmgr.h llmediactrl.h llmediadataclient.h + llmediafilter.h llmediaremotectrl.h llmenucommands.h llmenuoptionpathfindingrebakenavmesh.h @@ -851,6 +912,7 @@ set(viewer_HEADER_FILES llnamebox.h llnameeditor.h llnamelistctrl.h + llnameui.h llnetmap.h llnotify.h lloutfitobserver.h @@ -872,9 +934,17 @@ set(viewer_HEADER_FILES llpaneldisplay.h llpaneleditwearable.h llpanelevent.h + llpanelexperiencelisteditor.h + llpanelexperiencelog.h + llpanelexperiencepicker.h + llpanelexperiences.h llpanelface.h llpanelgeneral.h llpanelgroup.h + llpanelgroupbulk.h + llpanelgroupbulkban.h + llpanelgroupbulkimpl.h + llpanelgroupexperiences.h llpanelgroupgeneral.h llpanelgroupinvite.h llpanelgrouplandmoney.h @@ -889,7 +959,6 @@ set(viewer_HEADER_FILES llpanellandoptions.h llpanellogin.h llpanelmaininventory.h - llpanelmarketplaceoutboxinventory.h llpanelmediasettingsgeneral.h llpanelmediasettingspermissions.h llpanelmediasettingssecurity.h @@ -944,8 +1013,10 @@ set(viewer_HEADER_FILES llsavedsettingsglue.h llscrollingpanelparam.h llscrollingpanelparambase.h + llsculptidsize.h llselectmgr.h llsimplestat.h + llskinningutil.h llsky.h llslurl.h llspatialpartition.h @@ -988,6 +1059,7 @@ set(viewer_HEADER_FILES lltracker.h lltranslate.h lluiconstants.h + lluiavatar.h lluploaddialog.h lluploadfloaterobservers.h llurl.h @@ -997,6 +1069,7 @@ set(viewer_HEADER_FILES lluserauth.h llvectorperfoptions.h llvelocitybar.h + llversioninfo.h llviewchildren.h llviewerassetstats.h llviewerassetstorage.h @@ -1025,6 +1098,7 @@ set(viewer_HEADER_FILES llviewerobject.h llviewerobjectbackup.h llviewerobjectlist.h + llvieweroctree.h llviewerparcelmedia.h llviewerparcelmediaautoplay.h llviewerparcelmgr.h @@ -1088,31 +1162,46 @@ set(viewer_HEADER_FILES llxmlrpcresponder.h m7wlinterface.h macmain.h - noise.h pipeline.h qtoolalign.h + rlvactions.h rlvcommon.h rlvdefines.h rlvextensions.h - rlvfloaterbehaviour.h + rlvfloaters.h rlvhandler.h rlvhelper.h rlvinventory.h rlvlocks.h rlvui.h + roles_constants.h scriptcounter.h sgmemstat.h - sgversion.h shcommandhandler.h shfloatermediaticker.h - slfloatermediafilter.h + shupdatechecker.h wlfPanel_AdvSettings.h - VertexCache.h - VorbisFramework.h ) source_group("CMake Rules" FILES ViewerInstall.cmake) +#build_data.json creation moved to viewer_manifest.py MAINT-6413 +# the viewer_version.txt file created here is for passing to viewer_manifest and autobuild +# the summary.json file is created for the benefit of the TeamCity builds, where +# it is used to provide descriptive information to the build results page +add_custom_target(generate_viewer_version ALL + COMMAND ${CMAKE_COMMAND} -E echo ${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION} > ${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt + COMMENT "Generating viewer_version.txt for manifest processing" + ) + +set_source_files_properties( + llimpanel.cpp + llversioninfo.cpp + PROPERTIES + DEPENDS generate_viewer_version # dummy dependency to force recompile every time + COMPILE_DEFINITIONS "${VIEWER_CHANNEL_VERSION_DEFINES}" # see BuildVersion.cmake + ) + if (DARWIN) LIST(APPEND viewer_SOURCE_FILES llappviewermacosx.cpp) @@ -1129,10 +1218,8 @@ if (DARWIN) # Add resource files to the project. set(viewer_RESOURCE_FILES - ${VIEWER_BRANDING_ID}.icns macview.r gpu_table.txt - Info-${VIEWER_BRANDING_NAME_CAMELCASE}.plist SecondLife.nib/ # CMake doesn't seem to support Xcode language variants well just yet English.lproj/InfoPlist.strings @@ -1172,24 +1259,34 @@ if (WINDOWS) llwindebug.h ) - # precompiled header configuration - # llviewerprecompiledheaders.cpp generates - # the .pch file. - # All sources added to viewer_SOURCE_FILES - # at this point use it. - set_source_files_properties(llviewerprecompiledheaders.cpp - PROPERTIES - COMPILE_FLAGS "/Ycllviewerprecompiledheaders.h" - ) - foreach( src_file ${viewer_SOURCE_FILES} ) - set_source_files_properties( - ${src_file} - PROPERTIES - COMPILE_FLAGS "/Yullviewerprecompiledheaders.h" - ) - endforeach( src_file ${viewer_SOURCE_FILES} ) - list(APPEND viewer_SOURCE_FILES llviewerprecompiledheaders.cpp) - + if (USE_NVAPI) + set(APPVWRW32_COMPILE_FLAGS "${APPVWRW32_COMPILE_FLAGS} -DUSE_NVAPI=1") + else (USE_NVAPI) + set(APPVWRW32_COMPILE_FLAGS "${APPVWRW32_COMPILE_FLAGS} -UUSE_NVAPI") + endif (USE_NVAPI) + set_source_files_properties(llappviewerwin32.cpp PROPERTIES COMPILE_FLAGS "${APPVWRW32_COMPILE_FLAGS}") + + # Replace the icons with the appropriate ones for the channel + # ('test' is the default) + set(ICON_PATH "default") + set(VIEWER_MACOSX_PHASE "d") + message("Copying icons for ${ICON_PATH}") + execute_process( + COMMAND ${CMAKE_COMMAND} -E copy_if_different + "${CMAKE_CURRENT_SOURCE_DIR}/icons/${ICON_PATH}/viewer.ico" + "${CMAKE_CURRENT_SOURCE_DIR}/res/viewer_icon.ico" + ) + execute_process( + COMMAND ${CMAKE_COMMAND} -E copy_if_different + "${CMAKE_CURRENT_SOURCE_DIR}/icons/${ICON_PATH}/viewer_256.BMP" + "${CMAKE_CURRENT_SOURCE_DIR}/res/viewer_icon.BMP" + ) + execute_process( + COMMAND ${CMAKE_COMMAND} -E copy_if_different + "${CMAKE_CURRENT_SOURCE_DIR}/icons/${ICON_PATH}/viewer_256.BMP" + "${CMAKE_CURRENT_SOURCE_DIR}/res-sdl/viewer_icon.BMP" + ) + # Add resource files to the project. # viewerRes.rc is the only buildable file, but # the rest are all dependencies of it. @@ -1199,7 +1296,6 @@ if (WINDOWS) res/arrowcopmulti.cur res/arrowdrag.cur res/circleandline.cur - res/icon1.ico res/llarrow.cur res/llarrowdrag.cur res/llarrowdragmulti.cur @@ -1219,8 +1315,9 @@ if (WINDOWS) res/lltooltranslate.cur res/lltoolzoomin.cur res/lltoolzoomout.cur - res/snowglobe_icon.BMP - res/snowglobe_icon.ico + res-sdl/viewer_icon.BMP + res/viewer_icon.BMP + res/viewer_icon.ico res/resource.h res/toolpickobject.cur res/toolpickobject2.cur @@ -1235,30 +1332,26 @@ if (WINDOWS) set_source_files_properties(${viewer_RESOURCE_FILES} PROPERTIES HEADER_FILE_ONLY TRUE) - set(viewer_RESOURCE_FILES - res/resource.h - res/viewerRes.rc - ${viewer_RESOURCE_FILES} + + list(APPEND viewer_RESOURCE_FILES + ${CMAKE_CURRENT_BINARY_DIR}/viewerRes.rc ) - SOURCE_GROUP("Resource Files" FILES ${viewer_RESOURCE_FILES}) + set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/viewerRes.rc + PROPERTIES COMPILE_FLAGS "-I${CMAKE_CURRENT_SOURCE_DIR}/res" + ) + + source_group("Resource Files" FILES ${viewer_RESOURCE_FILES}) list(APPEND viewer_SOURCE_FILES ${viewer_RESOURCE_FILES}) - find_library(DINPUT_LIBRARY dinput8 ${DIRECTX_LIBRARY_DIR}) - find_library(DXGUID_LIBRARY dxguid ${DIRECTX_LIBRARY_DIR}) - mark_as_advanced( - DINPUT_LIBRARY - DXGUID_LIBRARY - ) - # see EXP-1765 - theory is opengl32.lib needs to be included before gdi32.lib (windows libs) set(viewer_LIBRARIES opengl32 advapi32 comdlg32 - ${DINPUT_LIBRARY} - ${DXGUID_LIBRARY} + dinput8 + dxguid gdi32 kernel32 odbc32 @@ -1268,27 +1361,11 @@ if (WINDOWS) shell32 user32 Vfw32 + wer + Wbemuuid winspool + Normaliz ) - - if(FMODEX) - list(APPEND viewer_LIBRARIES ${FMODEX_LIBRARY}) - endif(FMODEX) - if(FMOD) - list(APPEND viewer_LIBRARIES ${FMOD_LIBRARY}) - endif(FMOD) - - find_library(INTEL_MEMOPS_LIBRARY - NAMES ll_intel_memops - PATHS - optimized ${ARCH_PREBUILT_DIRS_RELEASE} - debug ${ARCH_PREBUILT_DIRS_DEBUG} - ) - mark_as_advanced(INTEL_MEMOPS_LIBRARY) - - if (INTEL_MEMOPS_LIBRARY) - list(APPEND viewer_LIBRARIES ${INTEL_MEMOPS_LIBRARY}) - endif (INTEL_MEMOPS_LIBRARY) endif (WINDOWS) # Add the xui files. This is handy for searching for xui elements @@ -1318,7 +1395,8 @@ set(viewer_APPSETTINGS_FILES app_settings/cmd_line.xml app_settings/grass.xml app_settings/high_graphics.xml - app_settings/keys.ini + app_settings/keys.xml + app_settings/keysZQSD.xml app_settings/keywords.ini app_settings/logcontrol.xml app_settings/low_graphics.xml @@ -1326,7 +1404,6 @@ set(viewer_APPSETTINGS_FILES app_settings/settings.xml app_settings/settings_ascent.xml app_settings/settings_ascent_coa.xml - app_settings/settings_crash_behavior.xml app_settings/settings_files.xml app_settings/settings_per_account.xml app_settings/settings_sh.xml @@ -1337,6 +1414,7 @@ set(viewer_APPSETTINGS_FILES app_settings/viewerart.xml ${CMAKE_SOURCE_DIR}/../etc/message.xml ${CMAKE_SOURCE_DIR}/../scripts/messages/message_template.msg + packages-info.txt ) source_group("App Settings" FILES ${viewer_APPSETTINGS_FILES}) @@ -1373,42 +1451,21 @@ if (WINDOWS) endif (WINDOWS) if (OPENAL) - set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_OPENAL") + list(APPEND LLSTARTUP_COMPILE_DEFINITIONS "LL_OPENAL=1") endif (OPENAL) -if (FMOD OR FMODEX) - if (FMODEX) - set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_FMODEX") - endif (FMODEX) - if (FMOD) - set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_FMOD") - endif (FMOD) - - if (DARWIN AND FMOD) - set(fmodwrapper_SOURCE_FILES fmodwrapper.cpp) - add_library(fmodwrapper SHARED ${fmodwrapper_SOURCE_FILES}) - set(fmodwrapper_needed_LIBRARIES ${FMOD_LIBRARY} ${CARBON_LIBRARY}) - set_target_properties( - fmodwrapper - PROPERTIES - BUILD_WITH_INSTALL_RPATH 1 - INSTALL_NAME_DIR "@executable_path/../Resources" - LINK_FLAGS "-unexported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/fmod_hidden_symbols.exp" - ) - set(FMODWRAPPER_LIBRARY fmodwrapper) - target_link_libraries(fmodwrapper ${fmodwrapper_needed_LIBRARIES}) - else (DARWIN AND FMOD) - # fmodwrapper unnecessary on linux or windows, for fmod and fmodex - if (FMODEX) - set(FMODWRAPPER_LIBRARY ${FMODEX_LIBRARY}) - endif (FMODEX) - if (FMOD) - set(FMODWRAPPER_LIBRARY ${FMOD_LIBRARY}) - endif (FMOD) - endif (DARWIN AND FMOD) -endif (FMOD OR FMODEX) - -set_source_files_properties(llstartup.cpp PROPERTIES COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS}") +if (USE_FMODSTUDIO) + list(APPEND LLSTARTUP_COMPILE_DEFINITIONS "LL_FMODSTUDIO=1") + set_source_files_properties(llpanellogin.cpp PROPERTIES COMPILE_DEFINITIONS "LL_FMODSTUDIO=1") +endif (USE_FMODSTUDIO) + +set_source_files_properties(llstartup.cpp PROPERTIES COMPILE_DEFINITIONS "${LLSTARTUP_COMPILE_DEFINITIONS}") + +if (LIBVLCPLUGIN) + set_source_files_properties(llfloaterabout.cpp PROPERTIES COMPILE_DEFINITIONS "VLCPLUGIN=1") +else (LIBVLCPLUGIN) + set_source_files_properties(llfloaterabout.cpp PROPERTIES COMPILE_DEFINITIONS "VLCPLUGIN=0") +endif (LIBVLCPLUGIN) list(APPEND viewer_SOURCE_FILES ${viewer_HEADER_FILES}) @@ -1421,129 +1478,189 @@ add_executable(${VIEWER_BINARY_NAME} ${viewer_SOURCE_FILES} ) -if (!DISABLE_TEMPLATE_CHECK) - check_message_template(${VIEWER_BINARY_NAME}) -endif (!DISABLE_TEMPLATE_CHECK) +if(USE_PRECOMPILED_HEADERS) + target_precompiled_header(${VIEWER_BINARY_NAME} + ${CMAKE_CURRENT_SOURCE_DIR}/llviewerprecompiledheaders.h + ${CMAKE_CURRENT_SOURCE_DIR}/llviewerprecompiledheaders.cpp) +endif(USE_PRECOMPILED_HEADERS) -# We package by default on Linux so we can run from newview/packaged. -if (LINUX) - set(PACKAGE_DEFAULT ON) -else (LINUX) - set(PACKAGE_DEFAULT OFF) -endif (LINUX) -set(PACKAGE ${PACKAGE_DEFAULT} CACHE BOOL - "Add a package target that builds an installer package.") +option(PACKAGE "Add a package target that builds an installer package." ON) if (WINDOWS) - if(MSVC10) - set(release_flags "/MAPRelease/${VIEWER_BINARY_NAME}.map") - else(MSVC10) - set(release_flags "/MAP:Release/${VIEWER_BINARY_NAME}.map") - endif(MSVC10) - - if (FMOD) - if(MANIFEST_LIBRARIES) - set(MANIFEST_LIBRARIES "${MANIFEST_LIBRARIES}|${FMOD_BINARY_DIR}/fmod.dll") - else(MANIFEST_LIBRARIES) - set(MANIFEST_LIBRARIES "--extra_libraries=${FMOD_BINARY_DIR}/fmod.dll") - endif(MANIFEST_LIBRARIES) - endif (FMOD) - if (FMODEX) - if(MANIFEST_LIBRARIES) - set(MANIFEST_LIBRARIES "${MANIFEST_LIBRARIES}|${FMODEX_BINARY_DIR}/fmodex.dll") - else(MANIFEST_LIBRARIES) - set(MANIFEST_LIBRARIES "--extra_libraries=${FMODEX_BINARY_DIR}/fmodex.dll") - endif(MANIFEST_LIBRARIES) - set(EXTRA_LINKER_FLAGS "/DELAYLOAD:fmodex.dll") - endif (FMODEX) + set(release_flags "/MAP") set_target_properties(${VIEWER_BINARY_NAME} PROPERTIES - LINK_FLAGS "/debug /NODEFAULTLIB:LIBCMT /SUBSYSTEM:WINDOWS ${GOOGLE_PERFTOOLS_LINKER_FLAGS} ${EXTRA_LINKER_FLAGS}" - LINK_FLAGS_DEBUG "/NODEFAULTLIB:\"LIBCMT;LIBCMTD;MSVCRT\"" - LINK_FLAGS_RELEASE ${release_flags} + LINK_FLAGS "/debug /NODEFAULTLIB:LIBCMT /SUBSYSTEM:WINDOWS ${GOOGLE_PERFTOOLS_LINKER_FLAGS}" + LINK_FLAGS_DEBUG "/NODEFAULTLIB:\"LIBCMT;LIBCMTD;MSVCRT\" ${EXTRA_LINKER_FLAGS_DEBUG}" + LINK_FLAGS_RELEASE "${release_flags} ${EXTRA_LINKER_FLAGS_RELEASE}" + LINK_FLAGS_RELWITHDEBINFO "${release_flags} ${EXTRA_LINKER_FLAGS_RELEASE}" ) - # sets the 'working directory' for debugging from visual studio. - if (NOT UNATTENDED) - add_custom_command( - TARGET ${VIEWER_BINARY_NAME} PRE_BUILD - COMMAND ${CMAKE_SOURCE_DIR}/tools/vstool/vstool.exe - ARGS - --solution - ${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}.sln - --workingdir - ${VIEWER_BINARY_NAME} - "${CMAKE_CURRENT_SOURCE_DIR}" - COMMENT "Setting the ${VIEWER_BINARY_NAME} working directory for debugging." + if(GEN_IS_MULTI_CONFIG) + set(VIEWER_BUILD_DEST_DIR "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}") + set_target_properties(${VIEWER_BINARY_NAME} PROPERTIES + VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}") + else() + set(VIEWER_BUILD_DEST_DIR "${CMAKE_CURRENT_BINARY_DIR}/package") + set_target_properties(${VIEWER_BINARY_NAME} PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${VIEWER_BUILD_DEST_DIR}") + endif() + + add_dependencies(${VIEWER_BINARY_NAME} generate_viewer_version) + + # If adding a file to viewer_manifest.py in the WindowsManifest.construct() method, be sure to add the dependency + # here. + # *NOTE:Mani - This is a crappy hack to have important dependencies for the viewer_manifest copy action + # be met. I'm looking forward to a source-code split-up project next year that will address this kind of thing. + # In the meantime, if you have any ideas on how to easily maintain one list, either here or in viewer_manifest.py + # and have the build deps get tracked *please* tell me about it. + + if(NOT DISABLE_TCMALLOC) + # Configure a var for tcmalloc location, if used. + # Note the need to specify multiple names explicitly. + set(GOOGLE_PERF_TOOLS_SOURCE + ${SHARED_LIB_STAGING_DIR}/Release/libtcmalloc_minimal.dll + ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/libtcmalloc_minimal.dll + ) + endif(NOT DISABLE_TCMALLOC) + + set(COPY_INPUT_DEPENDENCIES + # The following commented dependencies are determined at variably at build time. Can't do this here. + #${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/libtcmalloc_minimal.dll => None ... Skipping libtcmalloc_minimal.dll + ${CMAKE_SOURCE_DIR}/../etc/message.xml + ${CMAKE_SOURCE_DIR}/../scripts/messages/message_template.msg + ${SHARED_LIB_STAGING_DIR}/Release/glod.dll + ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/glod.dll + ${SHARED_LIB_STAGING_DIR}/Release/SLVoice.exe + ${SHARED_LIB_STAGING_DIR}/Release/vivoxplatform.dll + ${GOOGLE_PERF_TOOLS_SOURCE} + ${CMAKE_CURRENT_SOURCE_DIR}/licenses-win32.txt + ${CMAKE_CURRENT_SOURCE_DIR}/featuretable.txt + SLPlugin + media_plugin_libvlc + media_plugin_cef + basic_plugin_filepicker + ) + + if (ADDRESS_SIZE EQUAL 64) + list(APPEND COPY_INPUT_DEPENDENCIES + ${SHARED_LIB_STAGING_DIR}/Release/vivoxsdk_x64.dll + ${SHARED_LIB_STAGING_DIR}/Release/ortp_x64.dll + ) + else (ADDRESS_SIZE EQUAL 64) + list(APPEND COPY_INPUT_DEPENDENCIES + ${SHARED_LIB_STAGING_DIR}/Release/vivoxsdk.dll + ${SHARED_LIB_STAGING_DIR}/Release/ortp.dll + ) + endif (ADDRESS_SIZE EQUAL 64) + + if (USE_FMODSTUDIO) + if (ADDRESS_SIZE EQUAL 64) + list(APPEND COPY_INPUT_DEPENDENCIES + ${SHARED_LIB_STAGING_DIR}/Release/fmod64.dll + ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/fmod64.dll + ${SHARED_LIB_STAGING_DIR}/Debug/fmodL64.dll ) - endif (NOT UNATTENDED) + else (ADDRESS_SIZE EQUAL 64) + list(APPEND COPY_INPUT_DEPENDENCIES + ${SHARED_LIB_STAGING_DIR}/Release/fmod.dll + ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/fmod.dll + ) + endif (ADDRESS_SIZE EQUAL 64) + endif (USE_FMODSTUDIO) - add_custom_command( - TARGET ${VIEWER_BINARY_NAME} PRE_BUILD - COMMAND ${CMAKE_COMMAND} - ARGS - -E - copy_if_different - ${CMAKE_CURRENT_SOURCE_DIR}/../../scripts/messages/message_template.msg - ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/app_settings/message_template.msg - COMMENT "Copying message_template.msg to the runtime folder." - ) + if(MSVC_IDE) + set(VIEWER_BUILD_DEST_DIR "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}") + else() + set(VIEWER_BUILD_DEST_DIR "${CMAKE_CURRENT_BINARY_DIR}/packaged") + endif() add_custom_command( - TARGET ${VIEWER_BINARY_NAME} PRE_BUILD - COMMAND ${CMAKE_COMMAND} - ARGS - -E - copy_if_different - ${CMAKE_CURRENT_SOURCE_DIR}/../../etc/message.xml - ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/app_settings/message.xml - COMMENT "Copying message.xml to the runtime folder." - ) + OUTPUT ${VIEWER_BUILD_DEST_DIR}/copy_touched.bat + COMMAND ${PYTHON_EXECUTABLE} + ARGS + ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py + --actions=copy + --arch=${ARCH} + --artwork=${ARTWORK_DIR} + --branding_id=${VIEWER_BRANDING_ID} + --build=${CMAKE_CURRENT_BINARY_DIR} + --buildtype=${CMAKE_BUILD_TYPE} + --configuration=${VIEWER_BUILD_DEST_DIR} + --dest=${VIEWER_BUILD_DEST_DIR} + --grid=${GRID} + --channel=${VIEWER_CHANNEL} + --versionfile=${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt + --source=${CMAKE_CURRENT_SOURCE_DIR} + --touch=${VIEWER_BUILD_DEST_DIR}/copy_touched.bat + DEPENDS + ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py + generate_viewer_version + stage_third_party_libs + llcommon + ${COPY_INPUT_DEPENDENCIES} + COMMENT "Performing viewer_manifest copy" + ) - add_dependencies(${VIEWER_BINARY_NAME} copy_win_libs) + add_custom_target(copy_w_viewer_manifest ALL DEPENDS ${VIEWER_BUILD_DEST_DIR}/copy_touched.bat) + + add_dependencies(${VIEWER_BINARY_NAME} stage_third_party_libs llcommon copy_w_viewer_manifest) if (EXISTS ${CMAKE_SOURCE_DIR}/copy_win_scripts) add_dependencies(${VIEWER_BINARY_NAME} copy_win_scripts) endif (EXISTS ${CMAKE_SOURCE_DIR}/copy_win_scripts) + add_dependencies(${VIEWER_BINARY_NAME} + SLPlugin + ) + + EMBED_MANIFEST(${VIEWER_BINARY_NAME} 1) + + if (PACKAGE) + add_custom_command( - OUTPUT ${CMAKE_CFG_INTDIR}/touched.bat + OUTPUT ${VIEWER_BUILD_DEST_DIR}/touched.bat COMMAND ${PYTHON_EXECUTABLE} ARGS ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py + --arch=${ARCH} --artwork=${ARTWORK_DIR} --branding_id=${VIEWER_BRANDING_ID} --build=${CMAKE_CURRENT_BINARY_DIR} + --buildtype=${CMAKE_BUILD_TYPE} --channel=${VIEWER_CHANNEL} - --configuration=${CMAKE_CFG_INTDIR} - --dest=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR} + --versionfile=${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt + --configuration=${VIEWER_BUILD_DEST_DIR} + --dest=${VIEWER_BUILD_DEST_DIR} --grid=${GRID} - --login_channel=${VIEWER_LOGIN_CHANNEL} --source=${CMAKE_CURRENT_SOURCE_DIR} - --touch=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/touched.bat - ${MANIFEST_LIBRARIES} + --touch=${VIEWER_BUILD_DEST_DIR}/touched.bat DEPENDS ${VIEWER_BINARY_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py + ${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt + ${COPY_INPUT_DEPENDENCIES} ) - add_dependencies(${VIEWER_BINARY_NAME} SLPlugin media_plugin_quicktime media_plugin_webkit basic_plugin_filepicker winmm_shim) - - if (PACKAGE) - add_custom_target(package ALL DEPENDS ${CMAKE_CFG_INTDIR}/touched.bat) - add_dependencies(package windows-updater windows-crash-logger) + add_custom_target(llpackage ALL DEPENDS + ${VIEWER_BUILD_DEST_DIR}/touched.bat + windows-setup-build-all + ) endif (PACKAGE) endif (WINDOWS) -# *NOTE - this list is very sensitive to ordering, test carefully on all +# *NOTE: - this list is very sensitive to ordering, test carefully on all # platforms if you change the releative order of the entries here. # In particular, cmake 2.6.4 (when buidling with linux/makefile generators) # appears to sometimes de-duplicate redundantly listed dependencies improperly. # To work around this, higher level modules should be listed before the modules # that they depend upon. -brad target_link_libraries(${VIEWER_BINARY_NAME} + ${PNG_PRELOAD_ARCHIVES} + ${ZLIB_PRELOAD_ARCHIVES} ${GOOGLE_PERFTOOLS_LIBRARIES} + ${CRASHPAD_LIBRARIES} ${LLAUDIO_LIBRARIES} ${LLAUDIO_VORBIS_LIBRARIES} ${LLCHARACTER_LIBRARIES} @@ -1560,11 +1677,13 @@ target_link_libraries(${VIEWER_BINARY_NAME} ${LLVFS_LIBRARIES} ${LLWINDOW_LIBRARIES} ${LLXML_LIBRARIES} -# ${LSCRIPT_LIBRARIES} ${LLMATH_LIBRARIES} ${LLCOMMON_LIBRARIES} ${NDOF_LIBRARY} + ${NVAPI_LIBRARY} + ${URIPARSER_LIBRARY} ${viewer_LIBRARIES} + ${Boost_CONTEXT_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY} ${Boost_REGEX_LIBRARY} @@ -1572,42 +1691,42 @@ target_link_libraries(${VIEWER_BINARY_NAME} ${Boost_DATE_TIME_LIBRARY} ${DBUSGLIB_LIBRARIES} ${OPENGL_LIBRARIES} - ${FMODWRAPPER_LIBRARY} # must come after LLAudio + ${FMOD_LIBRARY} # must come after LLAudio ${GLOD_LIBRARIES} ${APRUTIL_LIBRARIES} ${OPENGL_LIBRARIES} - ${JSONCPP_LIBRARIES} ${SDL_LIBRARY} ${SMARTHEAP_LIBRARY} ${UI_LIBRARIES} ${WINDOWS_LIBRARIES} ${XMLRPCEPI_LIBRARIES} - ${ELFIO_LIBRARIES} + ${CRYPTO_LIBRARIES} + ${OPENSSL_LIBRARIES} + ${CRYPTO_LIBRARIES} ${HUNSPELL_LIBRARY} ${LLPHYSICSEXTENSIONS_LIBRARIES} ${LLAPPEARANCE_LIBRARIES} + absl::flat_hash_map + absl::node_hash_map + nlohmann_json::nlohmann_json + fmt::fmt ) if (LINUX) - add_custom_command( - OUTPUT secondlife-stripped - COMMAND strip - ARGS --strip-debug -o secondlife-stripped ${VIEWER_BINARY_NAME} - DEPENDS ${VIEWER_BINARY_NAME} - ) + set(product ${VIEWER_CHANNEL_NOSPACE}-${ARCH}-${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION}) - set(product ${VIEWER_BRANDING_NAME_CAMELCASE}-${ARCH}-${viewer_VERSION}) + # These are the generated targets that are copied to package/ + set(COPY_INPUT_DEPENDENCIES + ${VIEWER_BINARY_NAME} + SLPlugin + media_plugin_gstreamer010 + llcommon + ) - if (FMODEX) - if(MANIFEST_LIBRARIES) - set(MANIFEST_LIBRARIES "${MANIFEST_LIBRARIES}|${FMODEX_LIBRARY}") - else(MANIFEST_LIBRARIES) - set(MANIFEST_LIBRARIES "--extra_libraries=${FMODEX_LIBRARY}") - endif(MANIFEST_LIBRARIES) - endif (FMODEX) + add_dependencies(${VIEWER_BINARY_NAME} generate_viewer_version) add_custom_command( - OUTPUT ${product}.tar.bz2 + OUTPUT ${product}.tar.xz COMMAND ${PYTHON_EXECUTABLE} ARGS ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py @@ -1617,43 +1736,77 @@ if (LINUX) --build=${CMAKE_CURRENT_BINARY_DIR} --buildtype=${CMAKE_BUILD_TYPE} --channel=${VIEWER_CHANNEL} + --versionfile=${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt + --configuration=${CMAKE_CFG_INTDIR} --dest=${CMAKE_CURRENT_BINARY_DIR}/packaged --grid=${GRID} - --installer_name=${product} - --login_channel=${VIEWER_LOGIN_CHANNEL} --source=${CMAKE_CURRENT_SOURCE_DIR} --standalone=${STANDALONE} --touch=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/.${product}.touched - ${MANIFEST_LIBRARIES} DEPENDS - secondlife-stripped ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py + ${COPY_INPUT_DEPENDENCIES} + ) + + add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/.${product}.copy_touched + COMMAND ${PYTHON_EXECUTABLE} + ARGS + ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py + --arch=${ARCH} + --actions=copy + --artwork=${ARTWORK_DIR} + --branding_id=${VIEWER_BRANDING_ID} + --build=${CMAKE_CURRENT_BINARY_DIR} + --buildtype=${CMAKE_BUILD_TYPE} + --configuration=${CMAKE_CFG_INTDIR} + --dest=${CMAKE_CURRENT_BINARY_DIR}/packaged + --grid=${GRID} + --channel=${VIEWER_CHANNEL} + --versionfile=${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt + --source=${CMAKE_CURRENT_SOURCE_DIR} + DEPENDS + ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py + ${COPY_INPUT_DEPENDENCIES} + COMMENT "Performing viewer_manifest copy" ) - add_dependencies(${VIEWER_BINARY_NAME} SLPlugin media_plugin_gstreamer010 media_plugin_webkit basic_plugin_filepicker) + add_dependencies(${VIEWER_BINARY_NAME} SLPlugin media_plugin_gstreamer010 basic_plugin_filepicker) if (PACKAGE) - add_custom_target(package ALL DEPENDS ${product}.tar.bz2) - add_dependencies(package linux-crash-logger-strip-target) + add_custom_target(llpackage ALL DEPENDS ${product}.tar.xz) + check_message_template(llpackage) + else (PACKAGE) + add_custom_target(copy_l_viewer_manifest ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/.${product}.copy_touched) endif (PACKAGE) endif (LINUX) if (DARWIN) set(product ${VIEWER_BRANDING_NAME}) + set(MACOSX_BUNDLE_INFO_STRING "A stable third-party Second Life viewer.") + set(MACOSX_BUNDLE_ICON_FILE "viewer.icns") + set(MACOSX_BUNDLE_GUI_IDENTIFIER "${VIEWER_BRANDING_NAME}") + set(MACOSX_BUNDLE_LONG_VERSION_STRING "${VIEWER_CHANNEL} ${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION}") + set(MACOSX_BUNDLE_BUNDLE_NAME "${VIEWER_BRANDING_NAME}") + set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${VIEWER_SHORT_VERSION}") + set(MACOSX_BUNDLE_BUNDLE_VERSION "${${ROOT_PROJECT_NAME}_VERSION}") + set(MACOSX_BUNDLE_COPYRIGHT "Copyright 2010-2016 Siana Gearz") + set_target_properties( ${VIEWER_BINARY_NAME} PROPERTIES OUTPUT_NAME "${product}" - MACOSX_BUNDLE_INFO_STRING "A stable third-party Second Life viewer." - MACOSX_BUNDLE_ICON_FILE "${VIEWER_BRANDING_ID}.icns" - MACOSX_BUNDLE_GUI_IDENTIFIER "${VIEWER_BRANDING_NAME}" - MACOSX_BUNDLE_LONG_VERSION_STRING "${viewer_VERSION}" - MACOSX_BUNDLE_BUNDLE_NAME "${VIEWER_BRANDING_NAME}" - MACOSX_BUNDLE_SHORT_VERSION_STRING "${viewer_VERSION}" - MACOSX_BUNDLE_BUNDLE_VERSION "${viewer_VERSION}" - MACOSX_BUNDLE_COPYRIGHT "Copyright 2010 Balseraph Software Group" + MACOSX_BUNDLE_INFO_PLIST + "${CMAKE_CURRENT_SOURCE_DIR}/Info-SecondLife.plist" ) + configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/Info-SecondLife.plist" + "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${product}.app/Contents/Info.plist" + ) + + add_dependencies(${VIEWER_BINARY_NAME} generate_viewer_version) + add_custom_command( TARGET ${VIEWER_BINARY_NAME} POST_BUILD COMMAND ${PYTHON_EXECUTABLE} @@ -1668,65 +1821,39 @@ if (DARWIN) --dest=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${product}.app --grid=${GRID} --source=${CMAKE_CURRENT_SOURCE_DIR} - DEPENDS ${VIEWER_BINARY_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py + --extra_libraries="${MANIFEST_LIBRARIES}" + DEPENDS + ${VIEWER_BINARY_NAME} + ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py ) - add_dependencies(${VIEWER_BINARY_NAME} SLPlugin media_plugin_quicktime media_plugin_webkit basic_plugin_filepicker) - - if (FMODEX) - add_custom_command(OUTPUT "${FMODEX_LIBRARY}" - COMMAND cp "${FMODEX_ORIG_LIBRARY}" "${FMODEX_LIBRARY}" - COMMAND install_name_tool -id "@executable_path/../Resources/libfmodex.dylib" ${FMODEX_LIBRARY} - DEPENDS "${FMODEX_ORIG_LIBRARY}") - add_custom_target(fmodex_modified_library DEPENDS "${FMODEX_LIBRARY}") - add_dependencies(${VIEWER_BINARY_NAME} fmodex_modified_library) - endif (FMODEX) + add_dependencies(${VIEWER_BINARY_NAME} SLPlugin media_plugin_libvlc media_plugin_cef basic_plugin_filepicker) if (PACKAGE) - add_custom_target(package ALL DEPENDS ${VIEWER_BINARY_NAME}) - add_dependencies(package mac-updater mac-crash-logger) + add_custom_target(llpackage ALL DEPENDS ${VIEWER_BINARY_NAME}) + add_dependencies(llpackage generate_viewer_version) add_custom_command( - TARGET package POST_BUILD + TARGET llpackage POST_BUILD COMMAND ${PYTHON_EXECUTABLE} ARGS ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py + --arch=${ARCH} --artwork=${ARTWORK_DIR} - --branding_id=${VIEWER_BRANDING_ID} --build=${CMAKE_CURRENT_BINARY_DIR} --buildtype=${CMAKE_BUILD_TYPE} --channel=${VIEWER_CHANNEL} --configuration=${CMAKE_CFG_INTDIR} --dest=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${product}.app --grid=${GRID} - --login_channel=${VIEWER_LOGIN_CHANNEL} - --source=${CMAKE_CURRENT_SOURCE_DIR} - --touch=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/.${product}.touched - DEPENDS - ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py - ) -# Viewer-Development doesn't have this duplicate of the above command, here.. -# this may be a botched merge, but Mac seems to be picky, so I'm leaving it ~Liru - add_custom_command( - TARGET package POST_BUILD - COMMAND ${PYTHON_EXECUTABLE} - ARGS - ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py - --artwork=${ARTWORK_DIR} - --branding_id=${VIEWER_BRANDING_ID} - --build=${CMAKE_CURRENT_BINARY_DIR} - --buildtype=${CMAKE_BUILD_TYPE} --channel=${VIEWER_CHANNEL} - --configuration=${CMAKE_CFG_INTDIR} - --dest=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${product}.app - --grid=${GRID} - --login_channel=${VIEWER_LOGIN_CHANNEL} + --versionfile=${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt --source=${CMAKE_CURRENT_SOURCE_DIR} --touch=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/.${product}.touched DEPENDS + ${VIEWER_BINARY_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py ) - endif (PACKAGE) endif (DARWIN) @@ -1734,118 +1861,71 @@ if (INSTALL) include(${CMAKE_CURRENT_SOURCE_DIR}/ViewerInstall.cmake) endif (INSTALL) +if (FALSE) + # Breakpad symbol-file generation + set(SYMBOL_NAME ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${VIEWER_CHANNEL_NOSPACE}-${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION}-symbols) + + set(SYMBOL_SEARCH_DIRS "") + if (WINDOWS) + list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}") + set(VIEWER_SYMBOL_FILE "${SYMBOL_NAME}-${AUTOBUILD_PLATFORM_NAME}.tar.bz2") + # slplugin.exe failing symbols dump - need to debug, might have to do with updated version of google breakpad + # set(VIEWER_EXE_GLOBS "${VIEWER_BINARY_NAME}${CMAKE_EXECUTABLE_SUFFIX} slplugin.exe") + set(VIEWER_EXE_GLOBS "${VIEWER_BINARY_NAME}${CMAKE_EXECUTABLE_SUFFIX}") + set(VIEWER_LIB_GLOB "*${CMAKE_SHARED_MODULE_SUFFIX}") + set(VIEWER_COPY_MANIFEST copy_w_viewer_manifest) + endif (WINDOWS) + if (DARWIN) + list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}") + # *TODO: Generate these search dirs in the cmake files related to each binary. + list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/llplugin/slplugin/${CMAKE_CFG_INTDIR}") + list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/plugins/gstreamer010/${CMAKE_CFG_INTDIR}") + list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/plugins/quicktime/${CMAKE_CFG_INTDIR}") + list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/plugins/webkit/${CMAKE_CFG_INTDIR}") + set(VIEWER_SYMBOL_FILE "${SYMBOL_NAME}-darwin.tar.bz2") + set(VIEWER_EXE_GLOBS "'${VIEWER_BRANDING_NAME}' SLPlugin") + set(VIEWER_LIB_GLOB "*.dylib") + endif (DARWIN) + if (LINUX) + list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_CURRENT_BINARY_DIR}/packaged") + set(VIEWER_SYMBOL_FILE "${SYMBOL_NAME}-${AUTOBUILD_PLATFORM_NAME}.tar.bz2") + set(VIEWER_EXE_GLOBS "do-not-directly-run-${VIEWER_BINARY_NAME} SLPlugin") + set(VIEWER_LIB_GLOB "*${CMAKE_SHARED_MODULE_SUFFIX}*") + set(VIEWER_COPY_MANIFEST copy_l_viewer_manifest) + endif (LINUX) + + if(GEN_IS_MULTI_CONFIG) + set(LLBUILD_CONFIG ${CMAKE_BUILD_TYPE}) + else() + # set LLBUILD_CONFIG to be a shell variable evaluated at build time + # reflecting the configuration we are currently building. + set(LLBUILD_CONFIG ${CMAKE_CFG_INTDIR}) + endif() + add_custom_command(OUTPUT "${VIEWER_SYMBOL_FILE}" + COMMAND "${PYTHON_EXECUTABLE}" + ARGS + "${CMAKE_CURRENT_SOURCE_DIR}/generate_breakpad_symbols.py" + "${LLBUILD_CONFIG}" + "${SYMBOL_SEARCH_DIRS}" + "${VIEWER_EXE_GLOBS}" + "${VIEWER_LIB_GLOB}" + "${AUTOBUILD_INSTALL_DIR}/bin/dump_syms" + "${VIEWER_SYMBOL_FILE}" + DEPENDS generate_breakpad_symbols.py + VERBATIM) + + add_custom_target(generate_symbols DEPENDS "${VIEWER_SYMBOL_FILE}" ${VIEWER_BINARY_NAME} "${VIEWER_COPY_MANIFEST}") + add_dependencies(generate_symbols ${VIEWER_BINARY_NAME}) + if (WINDOWS OR LINUX) + add_dependencies(generate_symbols "${VIEWER_COPY_MANIFEST}") + endif (WINDOWS OR LINUX) + + add_dependencies(llpackage generate_symbols) +endif () + # Add tests if (LL_TESTS) - ADD_VIEWER_BUILD_TEST(llagentaccess viewer) - #ADD_VIEWER_BUILD_TEST(llworldmap viewer) - #ADD_VIEWER_BUILD_TEST(llworldmipmap viewer) - ADD_VIEWER_BUILD_TEST(lltextureinfo viewer) - ADD_VIEWER_BUILD_TEST(lltextureinfodetails viewer) - ADD_VIEWER_BUILD_TEST(lltexturestatsuploader viewer) - #ADD_VIEWER_COMM_BUILD_TEST(lltranslate viewer "") endif (LL_TESTS) -# Don't do these for DARWIN or LINUX here -- they're taken care of by viewer_manifest.py -if (WINDOWS) - - get_target_property(BUILT_LLCOMMON llcommon LOCATION) - - set_target_properties(llcommon - PROPERTIES - LINK_FLAGS "/debug /NODEFAULTLIB:LIBCMT" - LINK_FLAGS_DEBUG "/NODEFAULTLIB:\"LIBCMT;LIBCMTD;MSVCRT\"" - ) - - add_custom_command( - TARGET ${VIEWER_BINARY_NAME} POST_BUILD - COMMAND ${CMAKE_COMMAND} - ARGS - -E - copy_if_different - ${BUILT_LLCOMMON} - ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR} - COMMENT "Copying llcommon.dll to the runtime folder." - ) - - get_target_property(BUILT_SLPLUGIN SLPlugin LOCATION) - add_custom_command( - TARGET ${VIEWER_BINARY_NAME} POST_BUILD - COMMAND ${CMAKE_COMMAND} - ARGS - -E - copy_if_different - ${BUILT_SLPLUGIN} - ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR} - COMMENT "Copying SLPlugin executable to the runtime folder." - ) +check_message_template(${VIEWER_BINARY_NAME}) - get_target_property(BUILT_WEBKIT_PLUGIN media_plugin_webkit LOCATION) - add_custom_command( - TARGET ${VIEWER_BINARY_NAME} POST_BUILD - COMMAND ${CMAKE_COMMAND} - ARGS - -E - copy_if_different - ${BUILT_WEBKIT_PLUGIN} - ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/llplugin - COMMENT "Copying WebKit Plugin to the runtime folder." - ) - - get_target_property(BUILT_QUICKTIME_PLUGIN media_plugin_quicktime LOCATION) - add_custom_command( - TARGET ${VIEWER_BINARY_NAME} POST_BUILD - COMMAND ${CMAKE_COMMAND} - ARGS - -E - copy_if_different - ${BUILT_QUICKTIME_PLUGIN} - ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/llplugin - COMMENT "Copying Quicktime Plugin to the runtime folder." - ) - - get_target_property(BUILT_FILEPICKER_PLUGIN basic_plugin_filepicker LOCATION) - add_custom_command( - TARGET ${VIEWER_BINARY_NAME} POST_BUILD - COMMAND ${CMAKE_COMMAND} - ARGS - -E - copy_if_different - ${BUILT_FILEPICKER_PLUGIN} - ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/llplugin - COMMENT "Copying filepicker Plugin to the runtime folder." - ) - - get_target_property(BUILT_WINMM_SHIM_PLUGIN winmm_shim LOCATION) - add_custom_command( - TARGET ${VIEWER_BINARY_NAME} POST_BUILD - COMMAND ${CMAKE_COMMAND} - ARGS - -E - copy_if_different - ${BUILT_WINMM_SHIM_PLUGIN} - ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR} - COMMENT "Copying winmm.dll to the runtime folder." - ) - # Copying the mime_types.xml file to app_settings - set(mime_types_source "${CMAKE_SOURCE_DIR}/newview/skins/default/xui/en-us") - set(mime_types_dest "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/app_settings") - add_custom_command( - TARGET ${VIEWER_BINARY_NAME} POST_BUILD - COMMAND ${CMAKE_COMMAND} - ARGS - -E - copy_if_different - ${mime_types_source}/mime_types_windows.xml - ${mime_types_dest}/mime_types.xml - COMMENT "Copying mime_types_windows.xml to mime_types.xml." - ) - -endif (WINDOWS) - -if (DARWIN) -# Don't do this here -- it's taken care of by viewer_manifest.py -# add_custom_command(TARGET ${VIEWER_BINARY_NAME} POST_BUILD -# COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/../libraries/universal-darwin/lib/release/libllqtwebkit.dylib ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/llplugin/ -# DEPENDS ${CMAKE_SOURCE_DIR}/../libraries/universal-darwin/lib/release/libllqtwebkit.dylib -# ) -endif (DARWIN) diff --git a/indra/newview/English.lproj/InfoPlist.strings b/indra/newview/English.lproj/InfoPlist.strings deleted file mode 100644 index ca5535951c..0000000000 --- a/indra/newview/English.lproj/InfoPlist.strings +++ /dev/null @@ -1,7 +0,0 @@ -/* Localized versions of Info.plist keys */ - -CFBundleName = "Singularity"; - -CFBundleShortVersionString = "Singularity Viewer 1.7.0.0"; -CFBundleGetInfoString = "Singularity Viewer 1.7.0.0, Copyright 2012 Siana Gearz"; - diff --git a/indra/newview/English.lproj/InfoPlist.strings.in b/indra/newview/English.lproj/InfoPlist.strings.in new file mode 100644 index 0000000000..8a2f3a3811 --- /dev/null +++ b/indra/newview/English.lproj/InfoPlist.strings.in @@ -0,0 +1,6 @@ +/* Localized versions of Info.plist keys */ + +CFBundleName = "${VIEWER_CHANNEL_NOSPACE}"; + +CFBundleShortVersionString = "${VIEWER_CHANNEL} Viewer ${vMAJOR}.${vMINOR}.${vPATCH}.${vBUILD}"; +CFBundleGetInfoString = "${VIEWER_CHANNEL} Viewer ${vMAJOR}.${vMINOR}.${vPATCH}.${vBUILD}, Copyright 2012 Siana Gearz"; diff --git a/indra/newview/Info-Singularity.plist b/indra/newview/Info-Singularity.plist deleted file mode 100644 index 06a83b2fbc..0000000000 --- a/indra/newview/Info-Singularity.plist +++ /dev/null @@ -1,39 +0,0 @@ - - - - - CFBundleDevelopmentRegion - English - CFBundleExecutable - Singularity - CFBundleIconFile - singularity.icns - CFBundleIdentifier - org.singularityviewer.singularity - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - Singularity - CFBundlePackageType - APPL - CFBundleSignature - ???? - CFBundleURLTypes - - - CFBundleURLName - Second Life URL - CFBundleURLSchemes - - secondlife - - LSIsAppleDefaultForScheme - - - - CFBundleVersion - 1.0.0.0 - CSResourcesFileMapped - - - diff --git a/indra/newview/NACLantispam.cpp b/indra/newview/NACLantispam.cpp index 44d91cc138..2ad788a255 100644 --- a/indra/newview/NACLantispam.cpp +++ b/indra/newview/NACLantispam.cpp @@ -14,457 +14,299 @@ */ #include "llviewerprecompiledheaders.h" + #include "NACLantispam.h" -#include "llviewercontrol.h" -#include "llnotificationsutil.h" -#include "llviewerobjectlist.h" #include "llagent.h" +#include "llavataractions.h" +#include "llcallbacklist.h" // For idle cleaning +#include "llnotificationsutil.h" #include "lltrans.h" -#include -#include - -bool can_block(const LLUUID& id) -{ - if (id.isNull() || gAgent.getID() == id) return false; //Can't block system or self. - if (const LLViewerObject* obj = gObjectList.findObject(id)) //From an object, - return !obj->permYouOwner(); //not own object. - return true; -} - -U32 NACLAntiSpamRegistry::globalAmount; -U32 NACLAntiSpamRegistry::globalTime; -bool NACLAntiSpamRegistry::bGlobalQueue; -NACLAntiSpamQueue* NACLAntiSpamRegistry::queues[NACLAntiSpamRegistry::QUEUE_MAX] = {0}; -std::tr1::unordered_map NACLAntiSpamRegistry::globalEntries; -std::tr1::unordered_map::iterator NACLAntiSpamRegistry::it2; - -// The following sounds will be ignored for purposes of spam protection. They have been gathered from wiki documentation of frequent official sounds. -const std::string COLLISION_SOUNDS[] ={"dce5fdd4-afe4-4ea1-822f-dd52cac46b08","51011582-fbca-4580-ae9e-1a5593f094ec","68d62208-e257-4d0c-bbe2-20c9ea9760bb","75872e8c-bc39-451b-9b0b-042d7ba36cba","6a45ba0b-5775-4ea8-8513-26008a17f873","992a6d1b-8c77-40e0-9495-4098ce539694","2de4da5a-faf8-46be-bac6-c4d74f1e5767","6e3fb0f7-6d9c-42ca-b86b-1122ff562d7d","14209133-4961-4acc-9649-53fc38ee1667","bc4a4348-cfcc-4e5e-908e-8a52a8915fe6","9e5c1297-6eed-40c0-825a-d9bcd86e3193","e534761c-1894-4b61-b20c-658a6fb68157","8761f73f-6cf9-4186-8aaa-0948ed002db1","874a26fd-142f-4173-8c5b-890cd846c74d","0e24a717-b97e-4b77-9c94-b59a5a88b2da","75cf3ade-9a5b-4c4d-bb35-f9799bda7fb2","153c8bf7-fb89-4d89-b263-47e58b1b4774","55c3e0ce-275a-46fa-82ff-e0465f5e8703","24babf58-7156-4841-9a3f-761bdbb8e237","aca261d8-e145-4610-9e20-9eff990f2c12","0642fba6-5dcf-4d62-8e7b-94dbb529d117","25a863e8-dc42-4e8a-a357-e76422ace9b5","9538f37c-456e-4047-81be-6435045608d4","8c0f84c3-9afd-4396-b5f5-9bca2c911c20","be582e5d-b123-41a2-a150-454c39e961c8","c70141d4-ba06-41ea-bcbc-35ea81cb8335","7d1826f4-24c4-4aac-8c2e-eff45df37783","063c97d3-033a-4e9b-98d8-05c8074922cb","00000000-0000-0000-0000-000000000120"}; -const int COLLISION_SOUNDS_SIZE=29; - -// NaClAntiSpamQueueEntry - -NACLAntiSpamQueueEntry::NACLAntiSpamQueueEntry() -{ - entryTime=0; - entryAmount=0; - blocked=false; -} -void NACLAntiSpamQueueEntry::clearEntry() -{ - entryTime=0; - entryAmount=0; - blocked=false; -} -U32 NACLAntiSpamQueueEntry::getEntryAmount() const -{ - return entryAmount; -} -U32 NACLAntiSpamQueueEntry::getEntryTime() const -{ - return entryTime; -} -void NACLAntiSpamQueueEntry::updateEntryAmount() -{ - entryAmount++; -} -void NACLAntiSpamQueueEntry::updateEntryTime() -{ - entryTime=time(0); -} -void NACLAntiSpamQueueEntry::setBlocked() -{ - blocked=true; -} -bool NACLAntiSpamQueueEntry::getBlocked() const -{ - return blocked; -} +#include "llviewerobjectlist.h" -// NaClAntiSpamQueue +#include -NACLAntiSpamQueue::NACLAntiSpamQueue(U32 time, U32 amount) -{ - queueTime=time; - queueAmount=amount; -} -void NACLAntiSpamQueue::setAmount(U32 amount) -{ - queueAmount=amount; -} -void NACLAntiSpamQueue::setTime(U32 time) -{ - queueTime=time; -} -U32 NACLAntiSpamQueue::getAmount() const -{ - return queueAmount; -} -U32 NACLAntiSpamQueue::getTime() const -{ - return queueTime; -} -void NACLAntiSpamQueue::clearEntries() -{ - for(it = entries.begin(); it != entries.end(); it++) +class NACLAntiSpamQueue +{ + friend class NACLAntiSpamRegistry; +public: + const U32& getAmount() const { return mAmount; } + const U32& getTime() const { return mTime; } +protected: + NACLAntiSpamQueue(const U32& time, const U32& amount) : mTime(time), mAmount(amount) {} + void setAmount(const U32& amount) { mAmount = amount; } + void setTime(const U32& time) { mTime = time; } + void block(const LLUUID& source) { mEntries[source.asString()].block(); } + void reset() { mEntries.clear(); } + // Returns 0 if unblocked/disabled, 1 if check results in a new block, 2 if by an existing block + U8 check(const LLUUID& source, const U32& multiplier) { - it->second->clearEntry(); + const auto key = source.asString(); + auto it = mEntries.find(key); + if (it != mEntries.end()) + return it->second.blockIfNeeded(mAmount * multiplier, mTime); + mEntries[key]; // Default construct an Entry + return 0U; } -} -void NACLAntiSpamQueue::purgeEntries() -{ - for(it = entries.begin(); it != entries.end(); it++) + void idle() { - delete it->second; - } - entries.clear(); -} -void NACLAntiSpamQueue::blockEntry(LLUUID& source) -{ - it=entries.find(source.asString()); - if(it == entries.end()) - { - entries[source.asString()]=new NACLAntiSpamQueueEntry(); + // Clean out old unblocked entries + const auto time_limit = mTime + 1; // One second after time has gone up, the next offense would reset anyway + for (auto it = mEntries.begin(); it != mEntries.end();) + { + const auto& entry = it->second; + if (entry.getBlocked() || entry.withinBlockTime(time_limit)) + ++it; + else it = mEntries.erase(it); + } } - entries[source.asString()]->setBlocked(); -} -int NACLAntiSpamQueue::checkEntry(LLUUID& name, U32 multiplier) -// Returns 0 if unblocked/disabled, 1 if check results in a new block, 2 if by an existing block -{ - static LLCachedControl enabled(gSavedSettings,"AntiSpamEnabled",false); - if(!enabled) return 0; - it=entries.find(name.asString()); - if(it != entries.end()) + +private: + class Entry { - if(it->second->getBlocked()) return 2; - U32 eTime=it->second->getEntryTime(); - U32 currentTime=time(0); - if((currentTime-eTime) <= queueTime) + friend class NACLAntiSpamQueue; + protected: + void reset() { updateTime(); mAmount = 1; mBlocked = false; } + const U32& getAmount() const { return mAmount; } + const std::time_t& getTime() const { return mTime; } + void updateTime() { mTime = time(nullptr); } + void block() { mBlocked = true; } + bool withinBlockTime(const U32& time_limit) const { return (time(nullptr) - mTime) <= time_limit; } + U8 blockIfNeeded(const U32& amount, const U32& time_limit) { - it->second->updateEntryAmount(); - U32 eAmount=it->second->getEntryAmount(); - if(eAmount > (queueAmount*multiplier)) + if (mBlocked) return 2U; // Already blocked + if (withinBlockTime(time_limit)) { - it->second->setBlocked(); - return 1; + if (++mAmount > amount) + { + block(); + return 1U; + } } - else - return 0; - } - else - { - it->second->clearEntry(); - it->second->updateEntryAmount(); - it->second->updateEntryTime(); - return 0; + else reset(); // Enough time has passed to forgive or not already in list + return 0U; } - } - else - { - //lldebugs << "[antispam] New queue entry:" << name.asString() << llendl; - entries[name.asString()]=new NACLAntiSpamQueueEntry(); - entries[name.asString()]->updateEntryAmount(); - entries[name.asString()]->updateEntryTime(); - return 0; - } + bool getBlocked() const { return mBlocked; } + private: + U32 mAmount = 1; + std::time_t mTime = time(nullptr); + bool mBlocked = false; + }; + boost::unordered_map mEntries; + U32 mAmount, mTime; +}; + +bool can_block(const LLUUID& id) +{ + if (id.isNull() || gAgentID == id) return false; // Can't block system or self. + if (const LLViewerObject* obj = gObjectList.findObject(id)) // From an object, + return !obj->permYouOwner(); // not own object. + return true; } +bool is_collision_sound(const std::string& sound) +{ + // The following sounds will be ignored for purposes of spam protection. They have been gathered from wiki documentation of frequent official sounds. + const std::array COLLISION_SOUNDS = { + "dce5fdd4-afe4-4ea1-822f-dd52cac46b08", + "51011582-fbca-4580-ae9e-1a5593f094ec", + "68d62208-e257-4d0c-bbe2-20c9ea9760bb", + "75872e8c-bc39-451b-9b0b-042d7ba36cba", + "6a45ba0b-5775-4ea8-8513-26008a17f873", + "992a6d1b-8c77-40e0-9495-4098ce539694", + "2de4da5a-faf8-46be-bac6-c4d74f1e5767", + "6e3fb0f7-6d9c-42ca-b86b-1122ff562d7d", + "14209133-4961-4acc-9649-53fc38ee1667", + "bc4a4348-cfcc-4e5e-908e-8a52a8915fe6", + "9e5c1297-6eed-40c0-825a-d9bcd86e3193", + "e534761c-1894-4b61-b20c-658a6fb68157", + "8761f73f-6cf9-4186-8aaa-0948ed002db1", + "874a26fd-142f-4173-8c5b-890cd846c74d", + "0e24a717-b97e-4b77-9c94-b59a5a88b2da", + "75cf3ade-9a5b-4c4d-bb35-f9799bda7fb2", + "153c8bf7-fb89-4d89-b263-47e58b1b4774", + "55c3e0ce-275a-46fa-82ff-e0465f5e8703", + "24babf58-7156-4841-9a3f-761bdbb8e237", + "aca261d8-e145-4610-9e20-9eff990f2c12", + "0642fba6-5dcf-4d62-8e7b-94dbb529d117", + "25a863e8-dc42-4e8a-a357-e76422ace9b5", + "9538f37c-456e-4047-81be-6435045608d4", + "8c0f84c3-9afd-4396-b5f5-9bca2c911c20", + "be582e5d-b123-41a2-a150-454c39e961c8", + "c70141d4-ba06-41ea-bcbc-35ea81cb8335", + "7d1826f4-24c4-4aac-8c2e-eff45df37783", + "063c97d3-033a-4e9b-98d8-05c8074922cb", + "00000000-0000-0000-0000-000000000120" + }; + + for (const auto& collision : COLLISION_SOUNDS) + if (collision == sound) + return true; + return false; +} // NaClAntiSpamRegistry -static const char* QUEUE_NAME[NACLAntiSpamRegistry::QUEUE_MAX] = { -"Chat", -"Inventory", -"Instant Message", -"calling card", -"sound", -"Sound Preload", -"Script Dialog", -"Teleport"}; +constexpr std::array QUEUE_NAME = { + "Chat", + "Inventory", + "Instant Message", + "calling card", + "sound", + "Sound Preload", + "Script Dialog", + "Teleport" +}; -NACLAntiSpamRegistry::NACLAntiSpamRegistry(U32 time, U32 amount) +NACLAntiSpamRegistry::NACLAntiSpamRegistry() { - globalTime=time; - globalAmount=amount; - static LLCachedControl _NACL_AntiSpamGlobalQueue(gSavedSettings,"_NACL_AntiSpamGlobalQueue"); - bGlobalQueue=_NACL_AntiSpamGlobalQueue; - for(int queue = 0; queue < QUEUE_MAX; ++queue) - { - queues[queue] = new NACLAntiSpamQueue(time,amount); - } -} -//static -const char* NACLAntiSpamRegistry::getQueueName(U32 queue_id) -{ - if(queue_id >= QUEUE_MAX) - return "Unknown"; - return QUEUE_NAME[queue_id]; -} -//static -void NACLAntiSpamRegistry::registerQueues(U32 time, U32 amount) -{ - globalTime=time; - globalAmount=amount; - static LLCachedControl _NACL_AntiSpamGlobalQueue(gSavedSettings,"_NACL_AntiSpamGlobalQueue"); - bGlobalQueue=_NACL_AntiSpamGlobalQueue; - for(int queue = 0; queue < QUEUE_MAX; ++queue) - { - queues[queue] = new NACLAntiSpamQueue(time,amount); - } + auto control = gSavedSettings.getControl("_NACL_AntiSpamTime"); + const U32 time = control->get().asInteger(); + mConnections[0] = control->getSignal()->connect(boost::bind(&NACLAntiSpamRegistry::handleNaclAntiSpamTimeChanged, _2)); + + control = gSavedSettings.getControl("_NACL_AntiSpamAmount"); + const U32 amount = control->get().asInteger(); + mConnections[1] = control->getSignal()->connect(boost::bind(&NACLAntiSpamRegistry::handleNaclAntiSpamAmountChanged, _2)); + + control = gSavedSettings.getControl("_NACL_AntiSpamGlobalQueue"); + mConnections[2] = control->getSignal()->connect(boost::bind(&NACLAntiSpamRegistry::handleNaclAntiSpamGlobalQueueChanged, _2)); + initializeQueues(control->get(), time, amount); } -//static -/*void NACLAntiSpamRegistry::registerQueue(U32 name, U32 time, U32 amount) -{ - it=queues.find(name); - if(it == queues.end()) - { - queues[name]=new NACLAntiSpamQueue(time,amount); - } -}*/ -//static -void NACLAntiSpamRegistry::setRegisteredQueueTime(U32 name, U32 time) + +void NACLAntiSpamRegistry::initializeQueues(bool global, const U32& time, const U32& amount) { - if(name >= QUEUE_MAX || queues[name] == 0) + if (global) // If Global, initialize global queue + mGlobalQueue.reset(new NACLAntiSpamQueue(time, amount)); + else { - LL_ERRS("AntiSpam") << "CODE BUG: Attempting to set time of antispam queue that was outside of the reasonable range of queues or not created. Queue: " << getQueueName(name) << llendl; - return; + mQueues.reset(new std::array{{ + NACLAntiSpamQueue(time, amount), // QUEUE_CHAT + NACLAntiSpamQueue(time, amount), // QUEUE_INVENTORY + NACLAntiSpamQueue(time, amount), // QUEUE_IM + NACLAntiSpamQueue(time, amount), // QUEUE_CALLING_CARD + NACLAntiSpamQueue(time, amount), // QUEUE_SOUND + NACLAntiSpamQueue(time, amount), // QUEUE_SOUND_PRELOAD + NACLAntiSpamQueue(time, amount), // QUEUE_SCRIPT_DIALOG + NACLAntiSpamQueue(time, amount) // QUEUE_TELEPORT + }}); } - - queues[name]->setTime(time); } -//static -void NACLAntiSpamRegistry::setRegisteredQueueAmount(U32 name, U32 amount) + +constexpr const char* getQueueName(const NACLAntiSpamRegistry::Type& name) { - if(name >= QUEUE_MAX || queues[name] == 0) - { - LL_ERRS("AntiSpam") << "CODE BUG: Attempting to set amount for antispam queue that was outside of the reasonable range of queues or not created. Queue: " << getQueueName(name) << llendl; - return; - } - - queues[name]->setAmount(amount); + return name >= QUEUE_NAME.size() ? "Unknown" : QUEUE_NAME[name]; } -//static + void NACLAntiSpamRegistry::setAllQueueTimes(U32 time) { - globalTime=time; - for(int queue = 0; queue < QUEUE_MAX; ++queue) - if( queues[queue] ) - queues[queue]->setTime(time); + if (mGlobalQueue) mGlobalQueue->setTime(time); + else for(auto& queue : *mQueues) queue.setTime(time); } -//static + void NACLAntiSpamRegistry::setAllQueueAmounts(U32 amount) { - globalAmount=amount; - for(int queue = 0; queue < QUEUE_MAX; ++queue) + if (mGlobalQueue) mGlobalQueue->setAmount(amount); + else for (U8 queue = 0U; queue < QUEUE_MAX; ++queue) { - if(!queues[queue]) continue; - if(queue == QUEUE_SOUND || queue == QUEUE_SOUND_PRELOAD) - queues[queue]->setAmount(amount*5); + auto& q = (*mQueues)[queue]; + if (queue == QUEUE_SOUND || queue == QUEUE_SOUND_PRELOAD) + q.setAmount(amount*5); else - queues[queue]->setAmount(amount); - } -} -//static -void NACLAntiSpamRegistry::clearRegisteredQueue(U32 name) -{ - if(name >= QUEUE_MAX || queues[name] == 0) - { - LL_ERRS("AntiSpam") << "CODE BUG: Attempting to clear antispam queue that was outside of the reasonable range of queues or not created. Queue: " << getQueueName(name) << llendl; - return; - } - - queues[name]->clearEntries(); -} -//static -void NACLAntiSpamRegistry::purgeRegisteredQueue(U32 name) -{ - if(name >= QUEUE_MAX || queues[name] == 0) - { - LL_ERRS("AntiSpam") << "CODE BUG: Attempting to purge antispam queue that was outside of the reasonable range of queues or not created. Queue: " << getQueueName(name) << llendl; - return; - } - - queues[name]->purgeEntries(); -} -//static -void NACLAntiSpamRegistry::blockOnQueue(U32 name, LLUUID& source) -{ - if(bGlobalQueue) - { - NACLAntiSpamRegistry::blockGlobalEntry(source); - } - else - { - if(name >= QUEUE_MAX || queues[name] == 0) - { - LL_ERRS("AntiSpam") << "CODE BUG: Attempting to use a antispam queue that was outside of the reasonable range of queues or not created. Queue: " << getQueueName(name) << llendl; - return; - } - queues[name]->blockEntry(source); + q.setAmount(amount); } } -//static -void NACLAntiSpamRegistry::blockGlobalEntry(LLUUID& source) + +void NACLAntiSpamRegistry::blockOnQueue(const Type& name, const LLUUID& source) { - it2=globalEntries.find(source.asString()); - if(it2 == globalEntries.end()) - { - globalEntries[source.asString()]=new NACLAntiSpamQueueEntry(); - } - globalEntries[source.asString()]->setBlocked(); + if (name >= QUEUE_MAX) + LL_ERRS("AntiSpam") << "CODE BUG: Attempting to use a antispam queue that was outside of the reasonable range of queues. Queue: " << getQueueName(name) << LL_ENDL; + else (mGlobalQueue ? *mGlobalQueue : (*mQueues)[name]).block(source); } -//static -bool NACLAntiSpamRegistry::checkQueue(U32 name, LLUUID& source, U32 multiplier) + +bool NACLAntiSpamRegistry::checkQueue(const Type& name, const LLUUID& source, const LFIDBearer::Type& type, const U32& multiplier) //returns true if blocked { - if (!can_block(source)) return false; - - int result; - if(bGlobalQueue) - { - result=NACLAntiSpamRegistry::checkGlobalEntry(source,multiplier); - } - else + if (name >= QUEUE_MAX) { - if(name >= QUEUE_MAX || queues[name] == 0) - { - LL_ERRS("AntiSpam") << "CODE BUG: Attempting to check antispam queue that was outside of the reasonable range of queues or not created. Queue: " << getQueueName(name) << llendl; - return false; - } - result=queues[name]->checkEntry(source,multiplier); - } - if(result == 0) //Safe + LL_ERRS("AntiSpam") << "CODE BUG: Attempting to check antispam queue that was outside of the reasonable range of queues. Queue: " << getQueueName(name) << LL_ENDL; return false; - else if(result == 2) //Previously blocked - { - return true; } - else //Just blocked! + + if (!can_block(source)) return false; + + auto& queue = mGlobalQueue ? *mGlobalQueue : (*mQueues)[name]; + const auto result = queue.check(source, multiplier); + if (!result) return false; // Safe + + if (result != 2 // Not previously blocked + && gSavedSettings.getBOOL("AntiSpamNotify")) // and Just blocked! { - if(gSavedSettings.getBOOL("AntiSpamNotify")) - { - LLSD args; - args["SOURCE"] = source.asString().c_str(); - args["TYPE"] = LLTrans::getString(getQueueName(name)); - args["AMOUNT"] = boost::lexical_cast(multiplier * queues[name]->getAmount()); - args["TIME"] = boost::lexical_cast(queues[name]->getTime()); - LLNotificationsUtil::add("AntiSpamBlock", args); - } - return true; + const std::string get_slurl_for(const LLUUID& id, const LFIDBearer::Type& type); + const auto slurl = get_slurl_for(source, type); + LLSD args; + args["SOURCE"] = slurl.empty() ? source.asString() : slurl; + args["TYPE"] = LLTrans::getString(getQueueName(name)); + args["AMOUNT"] = (LLSD::Integer)(multiplier * queue.getAmount()); + args["TIME"] = (LLSD::Integer)queue.getTime(); + LLNotificationsUtil::add("AntiSpamBlock", args); } + return true; } -// Global queue stoof -//static -void NACLAntiSpamRegistry::setGlobalQueue(bool value) -{ - NACLAntiSpamRegistry::purgeAllQueues(); - bGlobalQueue=value; -} -//static -void NACLAntiSpamRegistry::setGlobalAmount(U32 amount) -{ - globalAmount=amount; -} -//static -void NACLAntiSpamRegistry::setGlobalTime(U32 time) +void NACLAntiSpamRegistry::idle() { - globalTime=time; + if (mGlobalQueue) mGlobalQueue->idle(); + else for (auto& queue : *mQueues) queue.idle(); } -//static -void NACLAntiSpamRegistry::clearAllQueues() + +void NACLAntiSpamRegistry::resetQueues() { - if(bGlobalQueue) - NACLAntiSpamRegistry::clearGlobalEntries(); - else - for(int queue = 0; queue < QUEUE_MAX; ++queue) - { - if(queues[queue]) queues[queue]->clearEntries(); - } + if (mGlobalQueue) mGlobalQueue->reset(); + else for (auto& queue : *mQueues) queue.reset(); + + LL_INFOS() << "AntiSpam Queues Reset" << LL_ENDL; } -//static + void NACLAntiSpamRegistry::purgeAllQueues() { - if(bGlobalQueue) - NACLAntiSpamRegistry::purgeGlobalEntries(); + // Note: These resets are upon the unique_ptr, not the Queue itself! + if (mGlobalQueue) + mGlobalQueue.reset(); else - for(int queue = 0; queue < QUEUE_MAX; ++queue) - { - if(queues[queue]) queues[queue]->purgeEntries(); - } - llinfos << "AntiSpam Queues Purged" << llendl; + mQueues.reset(); } -//static -int NACLAntiSpamRegistry::checkGlobalEntry(LLUUID& name, U32 multiplier) -{ - static LLCachedControl enabled(gSavedSettings,"AntiSpamEnabled",false); - if(!enabled) return 0; - it2=globalEntries.find(name.asString()); - if(it2 != globalEntries.end()) - { - if(it2->second->getBlocked()) return 2; - U32 eTime=it2->second->getEntryTime(); - U32 currentTime=time(0); - if((currentTime-eTime) <= globalTime) - { - it2->second->updateEntryAmount(); - U32 eAmount=it2->second->getEntryAmount(); - if(eAmount > (globalAmount*multiplier)) - return 1; - else - return 0; - } - else - { - it2->second->clearEntry(); - it2->second->updateEntryAmount(); - it2->second->updateEntryTime(); - return 0; - } - } - else - { - globalEntries[name.asString()]=new NACLAntiSpamQueueEntry(); - globalEntries[name.asString()]->updateEntryAmount(); - globalEntries[name.asString()]->updateEntryTime(); - return 0; - } -} -//static -void NACLAntiSpamRegistry::clearGlobalEntries() -{ - for(it2 = globalEntries.begin(); it2 != globalEntries.end(); it2++) - { - it2->second->clearEntry(); - } -} -//static -void NACLAntiSpamRegistry::purgeGlobalEntries() -{ - for(it2 = globalEntries.begin(); it2 != globalEntries.end(); it2++) - { - delete it2->second; - it2->second = 0; - } - globalEntries.clear(); + +// Handlers +// static +void NACLAntiSpamRegistry::startup() +{ + auto onAntiSpamToggle = [](const LLControlVariable*, const LLSD& value) { + if (value.asBoolean()) instance(); + else deleteSingleton(); + }; + auto control = gSavedSettings.getControl("AntiSpamEnabled"); + control->getSignal()->connect(onAntiSpamToggle); + onAntiSpamToggle(control, control->get()); } -//Handlers -//static +// static bool NACLAntiSpamRegistry::handleNaclAntiSpamGlobalQueueChanged(const LLSD& newvalue) { - setGlobalQueue(newvalue.asBoolean()); + if (instanceExists()) + { + auto& inst = instance(); + inst.purgeAllQueues(); + inst.initializeQueues(newvalue.asBoolean(), gSavedSettings.getU32("_NACL_AntiSpamTime"), gSavedSettings.getU32("_NACL_AntiSpamAmount")); + } return true; } //static bool NACLAntiSpamRegistry::handleNaclAntiSpamTimeChanged(const LLSD& newvalue) { - setAllQueueTimes(newvalue.asInteger()); + if (auto inst = getIfExists()) inst->setAllQueueTimes(newvalue.asInteger()); return true; } //static bool NACLAntiSpamRegistry::handleNaclAntiSpamAmountChanged(const LLSD& newvalue) { - setAllQueueAmounts(newvalue.asInteger()); + if (auto inst = getIfExists()) inst->setAllQueueAmounts(newvalue.asInteger()); return true; -} - +} \ No newline at end of file diff --git a/indra/newview/NACLantispam.h b/indra/newview/NACLantispam.h index e0476e267e..33c6d39d7c 100644 --- a/indra/newview/NACLantispam.h +++ b/indra/newview/NACLantispam.h @@ -13,72 +13,22 @@ * 0. You just DO WHAT THE FUCK YOU WANT TO. */ -#ifndef NACLANTISPAM_H -#define NACLANTISPAM_H -#include +#pragma once +#include +#include #include "stdtypes.h" +#include "lfidbearer.h" #include "lluuid.h" -class NACLAntiSpamQueueEntry -{ - friend class NACLAntiSpamQueue; - friend class NACLAntiSpamRegistry; -protected: - NACLAntiSpamQueueEntry(); - void clearEntry(); - U32 getEntryAmount() const; - U32 getEntryTime() const; - void updateEntryAmount(); - void updateEntryTime(); - bool getBlocked() const; - void setBlocked(); -private: - U32 entryAmount; - U32 entryTime; - bool blocked; -}; -class NACLAntiSpamQueue -{ - friend class NACLAntiSpamRegistry; -public: - U32 getAmount() const; - U32 getTime() const; -protected: - NACLAntiSpamQueue(U32 time, U32 amount); - void setAmount(U32 amount); - void setTime(U32 time); - void clearEntries(); - void purgeEntries(); - void blockEntry(LLUUID& source); - int checkEntry(LLUUID& source, U32 multiplier); -private: - std::tr1::unordered_map entries; - std::tr1::unordered_map::iterator it; - U32 queueAmount; - U32 queueTime; -}; -class NACLAntiSpamRegistry + +class NACLAntiSpamQueue; +class NACLAntiSpamRegistry final : public LLSingleton { + friend class LLSingleton; + NACLAntiSpamRegistry(); public: - NACLAntiSpamRegistry(U32 time=2, U32 amount=10); - static void registerQueues(U32 time=2, U32 amount=10); -// static void registerQueue(U32 name, U32 time, U32 amount); - static void setRegisteredQueueTime(U32 name, U32 time); - static void setRegisteredQueueAmount(U32 name,U32 amount); - static void setAllQueueTimes(U32 amount); - static void setAllQueueAmounts(U32 time); - static bool checkQueue(U32 name, LLUUID& source, U32 multiplier=1); - static bool handleNaclAntiSpamGlobalQueueChanged(const LLSD& newvalue); - static bool handleNaclAntiSpamTimeChanged(const LLSD& newvalue); - static bool handleNaclAntiSpamAmountChanged(const LLSD& newvalue); - static void clearRegisteredQueue(U32 name); - static void purgeRegisteredQueue(U32 name); - static void clearAllQueues(); - static void purgeAllQueues(); - static void setGlobalQueue(bool value); - static void setGlobalAmount(U32 amount); - static void setGlobalTime(U32 time); - static void blockOnQueue(U32 name,LLUUID& owner_id); - enum { + static void startup(); + + enum Type : U8 { QUEUE_CHAT, QUEUE_INVENTORY, QUEUE_IM, @@ -89,22 +39,19 @@ class NACLAntiSpamRegistry QUEUE_TELEPORT, QUEUE_MAX }; + bool checkQueue(const Type& name, const LLUUID& source, const LFIDBearer::Type& type = LFIDBearer::AVATAR, const U32& multiplier = 1); + void blockOnQueue(const Type& name, const LLUUID& owner_id); + void idle(); + void resetQueues(); private: - static const char* getQueueName(U32 queue_id); - static NACLAntiSpamQueue* queues[QUEUE_MAX]; - static std::tr1::unordered_map globalEntries; - static std::tr1::unordered_map::iterator it2; - static U32 globalTime; - static U32 globalAmount; - static bool bGlobalQueue; - - static int checkGlobalEntry(LLUUID& source, U32 multiplier); - static void clearGlobalEntries(); - static void purgeGlobalEntries(); - static void blockGlobalEntry(LLUUID& source); + void setAllQueueTimes(U32 amount); + void setAllQueueAmounts(U32 time); + void purgeAllQueues(); + void initializeQueues(bool global, const U32& time, const U32& amount); + static bool handleNaclAntiSpamGlobalQueueChanged(const LLSD& newvalue); + static bool handleNaclAntiSpamTimeChanged(const LLSD& newvalue); + static bool handleNaclAntiSpamAmountChanged(const LLSD& newvalue); + std::unique_ptr> mQueues; + std::unique_ptr mGlobalQueue; + std::array mConnections; }; - -extern const std::string COLLISION_SOUNDS[]; -extern const int COLLISION_SOUNDS_SIZE; - -#endif //NACLANTISPAM_H diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt new file mode 100644 index 0000000000..53ed4ba51e --- /dev/null +++ b/indra/newview/VIEWER_VERSION.txt @@ -0,0 +1 @@ +1.8.9 diff --git a/indra/newview/VertexCache.h b/indra/newview/VertexCache.h deleted file mode 100644 index e17e9d4705..0000000000 --- a/indra/newview/VertexCache.h +++ /dev/null @@ -1,111 +0,0 @@ -/** - * @file VertexCache.h - * @brief VertexCache class definition - * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - - -#ifndef VERTEX_CACHE_H - -#define VERTEX_CACHE_H - -class VertexCache -{ - -public: - - VertexCache(int size) - { - numEntries = size; - - entries = new int[numEntries]; - - for(int i = 0; i < numEntries; i++) - entries[i] = -1; - } - - VertexCache() { VertexCache(16); } - ~VertexCache() { delete[] entries; entries = 0; } - - bool InCache(int entry) - { - bool returnVal = false; - for(int i = 0; i < numEntries; i++) - { - if(entries[i] == entry) - { - returnVal = true; - break; - } - } - - return returnVal; - } - - int AddEntry(int entry) - { - int removed; - - removed = entries[numEntries - 1]; - - //push everything right one - for(int i = numEntries - 2; i >= 0; i--) - { - entries[i + 1] = entries[i]; - } - - entries[0] = entry; - - return removed; - } - - void Clear() - { - memset(entries, -1, sizeof(int) * numEntries); - } - - void Copy(VertexCache* inVcache) - { - for(int i = 0; i < numEntries; i++) - { - inVcache->Set(i, entries[i]); - } - } - - int At(int index) { return entries[index]; } - void Set(int index, int value) { entries[index] = value; } - -private: - - int *entries; - int numEntries; - -}; - -#endif diff --git a/indra/newview/VorbisFramework.h b/indra/newview/VorbisFramework.h deleted file mode 100644 index 18743444a7..0000000000 --- a/indra/newview/VorbisFramework.h +++ /dev/null @@ -1,86 +0,0 @@ -/** - * @file VorbisFramework.h - * @author Dave Camp - * @date Fri Oct 10 2003 - * @brief For the Macview project - * - * $LicenseInfo:firstyear=2003&license=viewergpl$ - * - * Copyright (c) 2003-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifdef __cplusplus -extern "C" { -#endif - -#include "ogg/ogg.h" -#include "vorbis/codec.h" -#include "vorbis/vorbisenc.h" - -extern int mac_vorbis_analysis(vorbis_block *vb,ogg_packet *op); - -extern int mac_vorbis_analysis_headerout(vorbis_dsp_state *v, - vorbis_comment *vc, - ogg_packet *op, - ogg_packet *op_comm, - ogg_packet *op_code); - -extern int mac_vorbis_analysis_init(vorbis_dsp_state *v,vorbis_info *vi); - -extern int mac_vorbis_encode_ctl(vorbis_info *vi,int number,void *arg); - -extern int mac_vorbis_encode_setup_init(vorbis_info *vi); - -extern int mac_vorbis_encode_setup_managed(vorbis_info *vi, - long channels, - long rate, - - long max_bitrate, - long nominal_bitrate, - long min_bitrate); - -extern void mac_vorbis_info_init(vorbis_info *vi); -extern void mac_vorbis_info_clear(vorbis_info *vi); -extern void mac_vorbis_comment_init(vorbis_comment *vc); -extern void mac_vorbis_comment_clear(vorbis_comment *vc); -extern int mac_vorbis_block_init(vorbis_dsp_state *v, vorbis_block *vb); -extern int mac_vorbis_block_clear(vorbis_block *vb); -extern void mac_vorbis_dsp_clear(vorbis_dsp_state *v); -extern float **mac_vorbis_analysis_buffer(vorbis_dsp_state *v,int vals); -extern int mac_vorbis_analysis_wrote(vorbis_dsp_state *v,int vals); -extern int mac_vorbis_analysis_blockout(vorbis_dsp_state *v,vorbis_block *vb); - -extern int mac_ogg_stream_packetin(ogg_stream_state *os, ogg_packet *op); -extern int mac_ogg_stream_init(ogg_stream_state *os,int serialno); -extern int mac_ogg_stream_flush(ogg_stream_state *os, ogg_page *og); -extern int mac_ogg_stream_pageout(ogg_stream_state *os, ogg_page *og); -extern int mac_ogg_page_eos(ogg_page *og); -extern int mac_ogg_stream_clear(ogg_stream_state *os); - - -#ifdef __cplusplus -} -#endif diff --git a/indra/newview/aihttpview.cpp b/indra/newview/aihttpview.cpp index 58bc2f689d..1e011e7bdf 100644 --- a/indra/newview/aihttpview.cpp +++ b/indra/newview/aihttpview.cpp @@ -80,6 +80,7 @@ void AIServiceBar::draw() U32 is_used; U32 is_inuse; int total_added; + int event_polls; int established_connections; int concurrent_connections; size_t bandwidth; @@ -88,6 +89,7 @@ void AIServiceBar::draw() is_used = per_service_r->is_used(); is_inuse = per_service_r->is_inuse(); total_added = per_service_r->mTotalAdded; + event_polls = per_service_r->mEventPolls; established_connections = per_service_r->mEstablishedConnections; concurrent_connections = per_service_r->mConcurrentConnections; bandwidth = per_service_r->bandwidth().truncateData(AIHTTPView::getTime_40ms()); @@ -107,14 +109,14 @@ void AIServiceBar::draw() { if (col < 2) { - text = llformat(" | %hu-%hu-%lu,{%hu/%hu,%u}/%u", + text = llformat(" | %hu-%hd-%lu,{%hu/%hu,%u}/%u", ct.mApprovedRequests, ct.mQueuedCommands, ct.mQueuedRequests.size(), ct.mAdded, ct.mConcurrentConnections, ct.mDownloading, ct.mMaxPipelinedRequests); } else { - text = llformat(" | --%hu-%lu,{%hu/%hu,%u}", + text = llformat(" | --%hd-%lu,{%hu/%hu,%u}", ct.mQueuedCommands, ct.mQueuedRequests.size(), ct.mAdded, ct.mConcurrentConnections, ct.mDownloading); } @@ -147,8 +149,8 @@ void AIServiceBar::draw() start += LLFontGL::getFontMonospace()->getWidth(text); } start = mHTTPView->updateColumn(mc_col, start); -#if defined(CWDEBUG) || defined(DEBUG_CURLIO) - text = llformat(" | %d,%d/%d", total_added, established_connections, concurrent_connections); +#ifdef CWDEBUG + text = llformat(" | %d,%d,%d/%d", total_added, event_polls, established_connections, concurrent_connections); #else text = llformat(" | %d/%d", total_added, concurrent_connections); #endif @@ -188,7 +190,7 @@ class AIGLHTTPHeaderBar : public LLView AIGLHTTPHeaderBar(std::string const& name, AIHTTPView* httpview) : LLView(name, FALSE), mHTTPView(httpview) { - sLineHeight = llround(LLFontGL::getFontMonospace()->getLineHeight()); + sLineHeight = ll_round(LLFontGL::getFontMonospace()->getLineHeight()); setRect(LLRect(0, 0, 200, sLineHeight * number_of_header_lines)); } @@ -227,6 +229,7 @@ void AIGLHTTPHeaderBar::draw(void) height -= sLineHeight; start = h_offset; text = "Service (host:port)"; + // This must match AICapabilityType! static char const* caption[number_of_capability_types] = { " | Textures", " | Inventory", " | Mesh", " | Other" }; @@ -288,9 +291,14 @@ AIHTTPView::~AIHTTPView() mGLHTTPHeaderBar = NULL; } -U32 AIHTTPView::updateColumn(int col, U32 start) +U32 AIHTTPView::updateColumn(U32 col, U32 start) { - llassert(col <= mStartColumn.size()); + if (col > mStartColumn.size()) + { + // This happens when AIGLHTTPHeaderBar::draw is called before AIServiceBar::draw, which + // happens when there are no services (visible) at the moment the HTTP console is opened. + return start; + } if (col == mStartColumn.size()) { mStartColumn.push_back(start); @@ -302,16 +310,12 @@ U32 AIHTTPView::updateColumn(int col, U32 start) return mStartColumn[col]; } -//static -void AIHTTPView::toggle_visibility(void* user_data) +// virtual +void AIHTTPView::setVisible(BOOL visible) { - LLView* viewp = (LLView*)user_data; - bool visible = !viewp->getVisible(); - if (visible) - { - AIPerService::resetUsed(); - } - viewp->setVisible(visible); + if (visible && visible != getVisible()) + AIPerService::resetUsed(); + LLContainerView::setVisible(visible); } U64 AIHTTPView::sTime_40ms; diff --git a/indra/newview/aihttpview.h b/indra/newview/aihttpview.h index 767d37e547..e9a749afdf 100644 --- a/indra/newview/aihttpview.h +++ b/indra/newview/aihttpview.h @@ -49,10 +49,11 @@ class AIHTTPView : public LLContainerView ~AIHTTPView(); /*virtual*/ void draw(void); + /*virtual*/ void setVisible(BOOL visible); /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask); /*virtual*/ BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); - U32 updateColumn(int col, U32 start); + U32 updateColumn(U32 col, U32 start); void setWidth(S32 width) { mWidth = width; } private: @@ -66,7 +67,6 @@ class AIHTTPView : public LLContainerView public: static U64 getTime_40ms(void) { return sTime_40ms; } - static void toggle_visibility(void* user_data); }; extern AIHTTPView *gHttpView; diff --git a/indra/newview/aixmllindengenepool.cpp b/indra/newview/aixmllindengenepool.cpp new file mode 100644 index 0000000000..c9d0b37aa2 --- /dev/null +++ b/indra/newview/aixmllindengenepool.cpp @@ -0,0 +1,219 @@ +/** + * @file aixmllindengenepool.cpp + * @brief XML linden_genepool serialization support. + * + * Copyright (c) 2013, Aleric Inglewood. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution. + * + * CHANGELOG + * and additional copyright holders. + * + * 01/11/2013 + * Initial version, written by Aleric Inglewood @ SL + */ + +// metaversion 1.0 +// =============== +// +// Added as child of : +// +// +// +// Optionally, as child of , the following node may appear: +// +// +// +// Furthermore, metaversion 1.0 and higher allow the occurance of one or more blocks. +// If this is used then it is strongly advised to use one per wearable, so that +// the the node makes sense (it then refers to the wearable of that ). +// +// The reason for this clumsy way to link wearable to extra meta data is to stay +// compatible with the older format (no metaversion). + +#include "llviewerprecompiledheaders.h" +#include "aixmllindengenepool.h" +#include "hippogridmanager.h" +#include "llinventorymodel.h" +#include "llvisualparam.h" +#include "llviewerwearable.h" +#include "llquantize.h" + +void AIXMLLindenGenepool::MetaData::toXML(std::ostream& os, int indentation) const +{ + AIXMLElement tag(os, "meta", indentation); + tag.attribute("gridnick", mGridNick); + tag.attribute(DEFAULT_LLDATE_NAME, mDate); +} + +AIXMLLindenGenepool::MetaData::MetaData(AIXMLElementParser const& parser) +{ + parser.attribute("gridnick", mGridNick); + parser.attribute(DEFAULT_LLDATE_NAME, mDate); +} + +AIXMLLindenGenepool::AIXMLLindenGenepool(const std::string& filename) : AIXMLRootElement(filename, "linden_genepool") +{ + attribute("version", "1.0"); + attribute("metaversion", "1.0"); + child(MetaData(gHippoGridManager->getConnectedGrid()->getGridNick(), LLDate::now())); +} + +void AIVisualParamIDValuePair::toXML(std::ostream& os, int indentation) const +{ + LLVisualParam const* visual_param = mVisualParam; + if (!visual_param && mWearable) + { + visual_param = mWearable->getVisualParam(mID); + } + if (visual_param) + { + AIXMLElement tag(os, "param", indentation); + tag.attribute("id", mID); + tag.attribute("name", visual_param->getName()); + tag.attribute("value", mValue); + tag.attribute("u8", (U32)F32_to_U8(mValue, visual_param->getMinWeight(), visual_param->getMaxWeight())); + tag.attribute("type", visual_param->getTypeString()); + tag.attribute("wearable", visual_param->getDumpWearableTypeName()); + } +} + +AIVisualParamIDValuePair::AIVisualParamIDValuePair(AIXMLElementParser const& parser) +{ + // Only id and value are relevant. Ignore all other attributes. + parser.attribute("id", mID); + parser.attribute("value", mValue); +} + +void AITextureIDUUIDPair::toXML(std::ostream& os, int indentation) const +{ + AIXMLElement tag(os, "texture", indentation); + tag.attribute("te", mID); + tag.attribute(DEFAULT_LLUUID_NAME, mUUID); +} + +AITextureIDUUIDPair::AITextureIDUUIDPair(AIXMLElementParser const& parser) +{ + parser.attribute("te", mID); + parser.attribute(DEFAULT_LLUUID_NAME, mUUID); +} + +void AIArchetype::MetaData::toXML(std::ostream& os, int indentation) const +{ + AIXMLElement tag(os, "meta", indentation); + tag.attribute("path", mPath); + tag.attribute("name", mName); + tag.attribute("description", mDescription); +} + +AIArchetype::MetaData::MetaData(AIXMLElementParser const& parser) +{ + char const* missing = NULL; + if (!parser.attribute("path", mPath)) + { + missing = "path"; + } + if (!parser.attribute("name", mName)) + { + missing = "name"; + } + if (!parser.attribute("description", mDescription)) + { + missing = "description"; + } + if (missing) + { + THROW_ALERT("AIArchetype_MetaData_archetype_meta_has_no_ATTRIBUTE", AIArgs("[ATTRIBUTE]", missing)); + } +} + +AIArchetype::MetaData::MetaData(LLViewerWearable const* wearable) : mName(wearable->getName()), mDescription(wearable->getDescription()) +{ + // Path should already end on '/' if it is not empty. + const LLUUID& root_id = gInventory.getRootFolderID(); + LLUUID id = wearable->getItemID(); + for(const LLInventoryObject* obj = gInventory.getObject(id); obj && id != root_id; obj = gInventory.getCategory(id)) + { + std::string temp(mPath); + mPath = obj->getName(); + if (!temp.empty()) + { + mPath.append(1, '/'); + mPath.append(temp); + } + id = obj->getParentUUID(); + } +} + +AIArchetype::AIArchetype(void) : mType(LLWearableType::WT_NONE) +{ +} + +AIArchetype::AIArchetype(LLWearableType::EType type) : mType(type) +{ +} + +AIArchetype::AIArchetype(LLViewerWearable const* wearable) : mType(wearable->getType()), mMetaData(wearable) +{ +} + +void AIArchetype::toXML(std::ostream& os, int indentation) const +{ + AIXMLElement tag(os, "archetype", indentation); + if (mType == LLWearableType::WT_NONE) + { + tag.attribute("name", "???"); + } + else + { + tag.attribute("name", LLWearableType::getTypeName(mType)); + } + // mMetaData.mPath can be empty even exporting from the Appearance editor: + // when the asset is in the "My Inventory" root. + if (!mMetaData.mPath.empty() || !mMetaData.mName.empty()) // Is this not an old-style linden_genepool? + { + tag.child(mMetaData); + } + tag.child(mParams.begin(), mParams.end()); + tag.child(mTextures.begin(), mTextures.end()); +} + +AIArchetype::AIArchetype(AIXMLElementParser const& parser) +{ + std::string name; + mType = LLWearableType::WT_NONE; + + if (!parser.attribute("name", name)) + { + LL_WARNS() << "The tag in file \"" << parser.filename() << "\" is missing the 'name' parameter." << LL_ENDL; + } + else if (name != "???") + { + mType = LLWearableType::typeNameToType(name); + } + if (parser.version() >= 1) + { + if (!parser.child("meta", mMetaData)) + { + THROW_ALERT("AIArchetype_archetype_has_no_meta"); + } + } + parser.push_back_children("param", mParams); + parser.push_back_children("texture", mTextures); +} + diff --git a/indra/newview/aixmllindengenepool.h b/indra/newview/aixmllindengenepool.h new file mode 100644 index 0000000000..42aa5d35c2 --- /dev/null +++ b/indra/newview/aixmllindengenepool.h @@ -0,0 +1,150 @@ +/** + * @file aixmllindengenepool.h + * @brief XML linden_genepool serialization support. + * + * Copyright (c) 2013, Aleric Inglewood. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution. + * + * CHANGELOG + * and additional copyright holders. + * + * 01/11/2013 + * Initial version, written by Aleric Inglewood @ SL + */ + +#ifndef AIXMLLINDENGENEPOOL_H +#define AIXMLLINDENGENEPOOL_H + +#include "aixml.h" +#include "llwearabletype.h" +#include "llviewervisualparam.h" +#include + +class LLViewerWearable; + +class AIXMLLindenGenepool : public AIXMLRootElement +{ + public: + struct MetaData + { + std::string mGridNick; + LLDate mDate; + + MetaData(void) { } + MetaData(std::string const& grid_nick, LLDate const& date) : mGridNick(grid_nick), mDate(date) { } + + void toXML(std::ostream& os, int indentation) const; + MetaData(AIXMLElementParser const& parser); + }; + + AIXMLLindenGenepool(const std::string& filename); +}; + +class AIVisualParamIDValuePair +{ + private: + // A wearable + ID define the LLVisualParam, but it also possible to specify the LLVisualParam directly. + LLVisualParam const* mVisualParam; // Specific LLVisualParam, given at construction, or ... + LLViewerWearable const* mWearable; // Underlaying wearable, if any. + + U32 mID; // The visual parameter id. + F32 mValue; // The value of the visual parameter. + + public: + AIVisualParamIDValuePair(LLVisualParam const* visual_param) : + mVisualParam(visual_param), mWearable(NULL), mID(visual_param->getID()), mValue(visual_param->getWeight()) { } + + AIVisualParamIDValuePair(LLVisualParam const* visual_param, F32 value) : + mVisualParam(visual_param), mWearable(NULL), mID(visual_param->getID()), mValue(value) { } + + AIVisualParamIDValuePair(LLViewerWearable const* wearable, U32 id, F32 value) : + mVisualParam(NULL), mWearable(wearable), mID(id), mValue(value) { } + + void toXML(std::ostream& os, int indentation) const; + AIVisualParamIDValuePair(AIXMLElementParser const& parser); + + // Accessors. + U32 getID(void) const { return mID; } + F32 getValue(void) const { return mValue; } +}; + +class AITextureIDUUIDPair +{ + private: + U32 mID; + LLUUID mUUID; + + public: + AITextureIDUUIDPair(U32 id, LLUUID const& uuid) : mID(id), mUUID(uuid) { } + + void toXML(std::ostream& os, int indentation) const; + AITextureIDUUIDPair(AIXMLElementParser const& parser); + + // Accessors. + U32 getID(void) const { return mID; } + LLUUID const& getUUID(void) const { return mUUID; } +}; + +class AIArchetype +{ + public: + struct MetaData + { + std::string mPath; // The wearable location in the inventory. + std::string mName; // The wearable name. + std::string mDescription; // The wearable description. + + MetaData(void) { } + MetaData(LLViewerWearable const* wearable); + + void toXML(std::ostream& os, int indentation) const; + MetaData(AIXMLElementParser const& parser); + }; + + typedef std::vector params_type; + typedef std::vector textures_type; + + private: + LLWearableType::EType mType; // The type of the wearable. + MetaData mMetaData; + params_type mParams; + textures_type mTextures; + + public: + // Accessors. + LLWearableType::EType getType(void) const { return mType; } + MetaData const& getMetaData(void) const { return mMetaData; } + params_type const& getParams(void) const { return mParams; } + textures_type const& getTextures(void) const { return mTextures; } + + public: + // An archtype without wearable has no (known) metadata. This is recognized because mPath will be empty. + // An archtype without type with get the attribute name="???". + AIArchetype(void); // + AIArchetype(LLWearableType::EType type); // + AIArchetype(LLViewerWearable const* wearable); // + + void add(AIVisualParamIDValuePair const& visual_param_id_value_pair) { mParams.push_back(visual_param_id_value_pair); } + void add(AITextureIDUUIDPair const& texture_id_uuid_pair) { mTextures.push_back(texture_id_uuid_pair); } + + void toXML(std::ostream& os, int indentation) const; + AIArchetype(AIXMLElementParser const& parser); +}; + +#endif // AIXMLLINDENGENEPOOL_H diff --git a/indra/newview/alfloaterregiontracker.cpp b/indra/newview/alfloaterregiontracker.cpp new file mode 100644 index 0000000000..f95967367a --- /dev/null +++ b/indra/newview/alfloaterregiontracker.cpp @@ -0,0 +1,298 @@ +/** +* @file alfloaterregiontracker.cpp +* @brief Region tracking floater +* +* $LicenseInfo:firstyear=2013&license=viewerlgpl$ +* Alchemy Viewer Source Code +* Copyright (C) 2014, Alchemy Viewer Project. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* $/LicenseInfo$ +*/ + +#include "llviewerprecompiledheaders.h" + +#include "alfloaterregiontracker.h" + +// library +#include "llbutton.h" +#include "lldir.h" +#include "llfile.h" +#include "llscrolllistctrl.h" +#include "llsd.h" +#include "llsdserialize.h" +#include "llsdserialize_xml.h" +#include "lltextbox.h" +#include "lluictrlfactory.h" + +// newview +#include "hippogridmanager.h" +#include "llagent.h" +#include "llfloaterworldmap.h" +//#include "llfloaterreg.h" +#include "llnotificationsutil.h" +#include "llviewermessage.h" +#include "llworldmap.h" +#include "llworldmapmessage.h" + +const std::string TRACKER_FILE = "tracked_regions.json"; + +ALFloaterRegionTracker::ALFloaterRegionTracker(const LLSD&) + : LLFloater(), + LLEventTimer(5.f) +{ + LLUICtrlFactory::instance().buildFloater(this, "floater_region_tracker.xml"); + loadFromJSON(); +} + +ALFloaterRegionTracker::~ALFloaterRegionTracker() +{ + saveToJSON(); +} + +BOOL ALFloaterRegionTracker::postBuild() +{ + mRefreshRegionListBtn = getChild("refresh"); + mRefreshRegionListBtn->setClickedCallback(boost::bind(&ALFloaterRegionTracker::refresh, this)); + + mRemoveRegionBtn = getChild("remove"); + mRemoveRegionBtn->setClickedCallback(boost::bind(&ALFloaterRegionTracker::removeRegions, this)); + + mOpenMapBtn = getChild("open_map"); + mOpenMapBtn->setClickedCallback(boost::bind(&ALFloaterRegionTracker::openMap, this)); + + mRegionScrollList = getChild("region_list"); + mRegionScrollList->setCommitOnSelectionChange(TRUE); + mRegionScrollList->setCommitCallback(boost::bind(&ALFloaterRegionTracker::updateHeader, this)); + mRegionScrollList->setDoubleClickCallback(boost::bind(&ALFloaterRegionTracker::openMap, this)); + + updateHeader(); + + return LLFloater::postBuild(); +} + +void ALFloaterRegionTracker::onOpen(/*const LLSD& key*/) +{ + requestRegionData(); + mEventTimer.start(); +} + +void ALFloaterRegionTracker::onClose(bool app_quitting) +{ + mEventTimer.stop(); + app_quitting ? destroy() : setVisible(false); +} + +void ALFloaterRegionTracker::updateHeader() +{ + S32 num_selected(mRegionScrollList->getNumSelected()); + mRefreshRegionListBtn->setEnabled(mRegionMap.size() != 0); + mRemoveRegionBtn->setEnabled(!!num_selected); + mOpenMapBtn->setEnabled(num_selected == 1); +} + +void ALFloaterRegionTracker::refresh() +{ + if (!mRegionMap.size()) + { + updateHeader(); + return; + } + + std::vector saved_selected_values; + for(const auto* item : mRegionScrollList->getAllSelected()) + { + saved_selected_values.push_back(item->getValue().asString()); + } + S32 saved_scroll_pos = mRegionScrollList->getScrollPos(); + auto sort_column_name = mRegionScrollList->getSortColumnName(); + auto sort_asending = mRegionScrollList->getSortAscending(); + mRegionScrollList->deleteAllItems(); + + const std::string& cur_region_name = gAgent.getRegion()->getName(); + + for (LLSD::map_const_iterator it = mRegionMap.beginMap(); it != mRegionMap.endMap(); it++) + { + const std::string& sim_name = it->first; + const LLSD& data = it->second; + if (data.isMap()) // Assume the rest is correct. + { + LLScrollListCell::Params label; + LLScrollListCell::Params maturity; + LLScrollListCell::Params region; + LLScrollListCell::Params count; + label.column("region_label").type("text").value(data["label"].asString()); + maturity.column("region_maturity_icon").type("icon").font_halign(LLFontGL::HCENTER); + region.column("region_name").type("text").value(sim_name); + count.column("region_agent_count").type("text").value("..."); + if (LLSimInfo* info = LLWorldMap::getInstance()->simInfoFromName(sim_name)) + { + maturity.value(info->getAccessIcon()); + maturity.tool_tip(info->getShortAccessString()); + + info->updateAgentCount(LLTimer::getElapsedSeconds()); + S32 agent_count = info->getAgentCount(); + if (info->isDown()) + { + label.color(LLColor4::red); + maturity.color(LLColor4::red); + region.color(LLColor4::red); + count.color(LLColor4::red); + count.value(0); + } + else + count.value((sim_name == cur_region_name) ? agent_count + 1 : agent_count); + } + else + { + label.color(LLColor4::grey); + maturity.color(LLColor4::grey); + region.color(LLColor4::grey); + count.color(LLColor4::grey); + + LLWorldMapMessage::getInstance()->sendNamedRegionRequest(sim_name); + if (!mEventTimer.getStarted()) mEventTimer.start(); + } + LLScrollListItem::Params row; + row.value = sim_name; + row.columns.add(label); + row.columns.add(maturity); + row.columns.add(region); + row.columns.add(count); + mRegionScrollList->addRow(row); + } + } + + mRegionScrollList->sortByColumn(sort_column_name, sort_asending); + if (!saved_selected_values.empty()) + mRegionScrollList->selectMultiple(saved_selected_values); + mRegionScrollList->setScrollPos(saved_scroll_pos); +} + +BOOL ALFloaterRegionTracker::tick() +{ + refresh(); + return FALSE; +} + +void ALFloaterRegionTracker::requestRegionData() +{ + if (!mRegionMap.size()) + return; + + for (LLSD::map_const_iterator it = mRegionMap.beginMap(); it != mRegionMap.endMap(); it++) + { + const auto& name = it->first; + if (LLSimInfo* info = LLWorldMap::getInstance()->simInfoFromName(name)) + { + info->updateAgentCount(LLTimer::getElapsedSeconds()); + } + else + { + LLWorldMapMessage::getInstance()->sendNamedRegionRequest(name); + } + } + mEventTimer.start(); +} + +void ALFloaterRegionTracker::removeRegions() +{ + for (const auto* item : mRegionScrollList->getAllSelected()) + { + mRegionMap.erase(item->getValue().asString()); + } + mRegionScrollList->deleteSelectedItems(); + saveToJSON(); + updateHeader(); +} + +std::string getGridSpecificFile(const std::string& file, const char& sep = '_') +{ + const HippoGridInfo& grid(*gHippoGridManager->getConnectedGrid()); + if (grid.isSecondLife()) return file; + return file + sep + grid.getGridNick(); +} + +bool ALFloaterRegionTracker::saveToJSON() +{ + const std::string& filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, TRACKER_FILE); + llofstream out_file; + out_file.open(getGridSpecificFile(filename)); + if (out_file.is_open()) + { + LLSDSerialize::toPrettyNotation(mRegionMap, out_file); + out_file.close(); + return true; + } + return false; +} + +bool ALFloaterRegionTracker::loadFromJSON() +{ + const std::string& filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, TRACKER_FILE); + llifstream in_file; + in_file.open(getGridSpecificFile(filename)); + if (in_file.is_open()) + { + LLSDSerialize::fromNotation(mRegionMap, in_file, LLSDSerialize::SIZE_UNLIMITED); + in_file.close(); + return true; + } + return false; +} + +std::string ALFloaterRegionTracker::getRegionLabelIfExists(const std::string& name) +{ + return mRegionMap.get(name)["label"].asString(); +} + +void ALFloaterRegionTracker::onRegionAddedCallback(const LLSD& notification, const LLSD& response) +{ + const S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option == 0) + { + const std::string& name = notification["payload"]["name"].asString(); + std::string label = response["label"].asString(); + LLStringUtil::trim(label); + if (!name.empty() && !label.empty()) + { + if (mRegionMap.has(name)) + { + for (LLSD::map_iterator it = mRegionMap.beginMap(); it != mRegionMap.endMap(); it++) + if (it->first == name) it->second["label"] = label; + } + else + { + LLSD region; + region["label"] = label; + mRegionMap.insert(name, region); + } + saveToJSON(); + refresh(); + } + } +} + +void ALFloaterRegionTracker::openMap() +{ + const std::string& region = mRegionScrollList->getFirstSelected()->getValue().asString(); + LLFloaterWorldMap* worldmap_floaterp = gFloaterWorldMap; + if (!region.empty() && worldmap_floaterp) + { + worldmap_floaterp->trackURL(region, 128, 128, 0); + worldmap_floaterp->show(true); + } +} diff --git a/indra/newview/alfloaterregiontracker.h b/indra/newview/alfloaterregiontracker.h new file mode 100644 index 0000000000..230973f6aa --- /dev/null +++ b/indra/newview/alfloaterregiontracker.h @@ -0,0 +1,69 @@ +/** +* @file alfloaterregiontracker.h +* @brief Region tracking floater +* +* $LicenseInfo:firstyear=2013&license=viewerlgpl$ +* Alchemy Viewer Source Code +* Copyright (C) 2014, Alchemy Viewer Project. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* $/LicenseInfo$ +*/ + +#pragma once + +#include "lleventtimer.h" +#include "llfloater.h" + +class LLButton; +class LLSD; +class LLScrollListCtrl; + +class ALFloaterRegionTracker : public LLFloater, public LLEventTimer +, public LLFloaterSingleton +{ + //friend class LLFloaterReg; + friend class LLUISingleton >; +private: + ALFloaterRegionTracker(const LLSD& key); + virtual ~ALFloaterRegionTracker(); +public: + BOOL postBuild() override; + void onOpen(/*const LLSD& key*/) override; + void onClose(bool app_quitting) override; + void refresh() override; + BOOL tick() override; + using LLFloaterSingleton::getInstance; + +private: + void updateHeader(); + void requestRegionData(); + void removeRegions(); + bool saveToJSON(); + bool loadFromJSON(); + void openMap(); + +public: + std::string getRegionLabelIfExists(const std::string& name); + void onRegionAddedCallback(const LLSD& notification, const LLSD& response); + +private: + LLSD mRegionMap; + LLButton* mRefreshRegionListBtn = nullptr; + LLButton* mRemoveRegionBtn = nullptr; + LLButton* mOpenMapBtn = nullptr; + LLScrollListCtrl* mRegionScrollList = nullptr; +}; diff --git a/indra/newview/aoremotectrl.cpp b/indra/newview/aoremotectrl.cpp index d9b782fca3..5f57bcd206 100644 --- a/indra/newview/aoremotectrl.cpp +++ b/indra/newview/aoremotectrl.cpp @@ -33,7 +33,6 @@ #include "aoremotectrl.h" #include "floaterao.h" -#include "llbutton.h" #include "lloverlaybar.h" #include "lluictrlfactory.h" #include "llviewercontrol.h" @@ -46,80 +45,23 @@ AORemoteCtrl::AORemoteCtrl() setFocusRoot(TRUE); } -AORemoteCtrl::~AORemoteCtrl() -{ -} - -void AORemoteCtrl::draw() -{ - LLButton* expand_button = getChild("popup_btn"); - if (expand_button) - { - if (expand_button->getToggleState()) - { - expand_button->setImageOverlay("arrow_down.tga"); - } - else - { - expand_button->setImageOverlay("arrow_up.tga"); - } - } - - LLPanel::draw(); -} - void AORemoteCtrl::build() { - if (gSavedSettings.getBOOL("ShowAOSitPopup")) - { - LLUICtrlFactory::getInstance()->buildPanel(this, "panel_ao_remote_expanded.xml"); - } - else - { - LLUICtrlFactory::getInstance()->buildPanel(this, "panel_ao_remote.xml"); - } + LLUICtrlFactory::getInstance()->buildPanel(this, gSavedSettings.getBOOL("ShowAOSitPopup") ? "panel_ao_remote_expanded.xml" : "panel_ao_remote.xml"); } BOOL AORemoteCtrl::postBuild() { - - childSetAction("ao_btn", onClickToggleAO, this); - if (gSavedSettings.getBOOL("ShowAOSitPopup")) - { - childSetAction("ao_sit_btn", onClickToggleAOSit, this); - //childSetAction("ao_show_btn", onClickShowAO, this); - } - childSetAction("popup_btn", onClickPopupBtn, this); + /*if (LLUICtrl* ctrl = findChild("ao_show_btn")) + ctrl->setCommitCallback(boost::bind(&LLFloaterAO::showInstance, LLSD()));*/ + getChild("popup_btn")->setCommitCallback(boost::bind(&AORemoteCtrl::onClickPopupBtn, this)); return TRUE; } -// static -void AORemoteCtrl::onClickToggleAO(void* data) -{ - BOOL ao_enable = gSavedSettings.getBOOL("AOEnabled"); - gSavedSettings.setBOOL("AOEnabled", !ao_enable); -} - -//static -void AORemoteCtrl::onClickToggleAOSit(void* data) +void AORemoteCtrl::onClickPopupBtn() { - BOOL sit_enable = gSavedSettings.getBOOL("AOSitsEnabled"); - gSavedSettings.setBOOL("AOSitsEnabled", !sit_enable); -} - -//static -void AORemoteCtrl::onClickShowAO(void* data) -{ - LLFloaterAO::show(NULL); -} - -//static -void AORemoteCtrl::onClickPopupBtn(void* data) -{ - AORemoteCtrl* remotep = (AORemoteCtrl*)data; - - remotep->deleteAllChildren(); - remotep->build(); + deleteAllChildren(); + build(); gOverlayBar->layoutButtons(); } diff --git a/indra/newview/aoremotectrl.h b/indra/newview/aoremotectrl.h index ca74e0de66..417f7b3292 100644 --- a/indra/newview/aoremotectrl.h +++ b/indra/newview/aoremotectrl.h @@ -37,18 +37,12 @@ class AORemoteCtrl : public LLPanel { public: AORemoteCtrl(); - virtual ~AORemoteCtrl(); - /*virtual*/ BOOL postBuild(); - /*virtual*/ void draw(); + BOOL postBuild() override; private: void build(); - - static void onClickToggleAO(void* data); - static void onClickToggleAOSit(void* data); - static void onClickShowAO(void* data); - static void onClickPopupBtn(void* data); + void onClickPopupBtn(); }; #endif // AOREMOTECTRL_H diff --git a/indra/newview/aostate.h b/indra/newview/aostate.h new file mode 100644 index 0000000000..8f8fbc6350 --- /dev/null +++ b/indra/newview/aostate.h @@ -0,0 +1,37 @@ +#pragma once + +enum AOState : U8 +{ + STATE_AGENT_IDLE, + STATE_AGENT_WALK, + STATE_AGENT_RUN, + + STATE_AGENT_PRE_JUMP, + STATE_AGENT_JUMP, + STATE_AGENT_TURNLEFT, + STATE_AGENT_TURNRIGHT, + + STATE_AGENT_SIT, + STATE_AGENT_SIT_GROUND, + + STATE_AGENT_HOVER, + STATE_AGENT_HOVER_DOWN, + STATE_AGENT_HOVER_UP, + + STATE_AGENT_CROUCH, + STATE_AGENT_CROUCHWALK, + STATE_AGENT_FALLDOWN, + STATE_AGENT_STANDUP, + STATE_AGENT_LAND, + + STATE_AGENT_FLY, + STATE_AGENT_FLYSLOW, + + STATE_AGENT_TYPE, + + STATE_AGENT_SWIM_DOWN, + STATE_AGENT_SWIM_UP, + STATE_AGENT_SWIM, + STATE_AGENT_FLOAT, + STATE_AGENT_END +}; diff --git a/indra/newview/aosystem.cpp b/indra/newview/aosystem.cpp new file mode 100644 index 0000000000..49650acf4a --- /dev/null +++ b/indra/newview/aosystem.cpp @@ -0,0 +1,596 @@ +/** + * @file aosystem.cpp + * @brief clientside animation overrider + * by Skills Hak & Liru Færs + */ + +#include "llviewerprecompiledheaders.h" + +#include "aosystem.h" + +#include "floaterao.h" +#include "llagent.h" +#include "llagentcamera.h" +#include "llanimationstates.h" +#include "llinventoryfunctions.h" +#include "llinventorypanel.h" +#include "llinventorymodelbackgroundfetch.h" +#include "llmemorystream.h" +#include "llnotecard.h" +#include "llstartup.h" +#include "llvoavatarself.h" +#include "llviewerregion.h" +#include "roles_constants.h" + +#include + +// Uncomment and use instead if we ever add the chatbar as a command line - MC +void cmdline_printchat(const std::string& message); + +namespace +{ + bool sSwimming = false; + bool enable_swim() + { + static const LLCachedControl swim(gSavedSettings, "AOSwimEnabled", false); + return swim; + } + bool is_underwater() { return enable_swim() && gAgentAvatarp && gAgentAvatarp->mBelowWater; } +} + +// ------------------------------------------------------- +void AOSystem::AOStandTimer::reset() +{ + mPeriod = gSavedSettings.getF32("AOStandInterval"); + mEventTimer.reset(); +// LL_INFOS() << "reset" << LL_ENDL; +} + +// ------------------------------------------------------- +class AOInvTimer final : public LLEventTimer, public LLSingleton +{ + friend class LLSingleton; + friend class AOSystem; + AOInvTimer() : LLEventTimer(1.0f) {} + ~AOInvTimer() {} + static void createIfNeeded() + { + if (needed()) LLSingleton::getInstance(); + else AOSystem::getInstance(); + } +public: + static bool needed() + { + return LLStartUp::getStartupState() < STATE_INVENTORY_SEND // Haven't done inventory transfer yet + || !LLInventoryModelBackgroundFetch::instance().isEverythingFetched(); // Everything hasn't been fetched yet + } + BOOL tick() override + { + if (!gSavedSettings.getBOOL("AOEnabled")) return true; // If disabled on a tick, we don't care anymore + if (!needed()) + { +// cmdline_printchat("Inventory fetched, loading AO."); + AOSystem::getInstance(); // Initializes everything + return true; + } + return false; + } +}; + +class ObjectNameMatches final : public LLInventoryCollectFunctor +{ +public: + ObjectNameMatches(const std::string& name, const LLUUID& folder) : mName(name), mFolder(folder) {} + virtual ~ObjectNameMatches() {} + bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) override + { + return item && item->getParentUUID() == mFolder && item->getName() == mName; + } +private: + const std::string& mName; + const LLUUID& mFolder; +}; + +static LLUUID invfolderid; +LLUUID getAssetIDByName(const std::string& name) +{ + if (name.empty()) return LLUUID::null; + + LLViewerInventoryCategory::cat_array_t cats; + LLViewerInventoryItem::item_array_t items; + ObjectNameMatches matches(name, invfolderid); + gInventory.collectDescendentsIf(LLUUID::null, cats, items, false, matches, true); + + return items.empty() ? LLUUID(name) : items[0]->getAssetUUID(); +}; + +void AOSystem::start() +{ + llassert(!instanceExists() && !AOInvTimer::instanceExists()); // This should only be run once! + + auto control(gSavedSettings.getControl("AOEnabled")); + if (control->get()) AOInvTimer::createIfNeeded(); // Start the clock + + control->getSignal()->connect([](LLControlVariable*, const LLSD& enabled) { + if (enabled.asBoolean()) AOInvTimer::createIfNeeded(); // Start the clock + else deleteSingleton(); + }); +} + +// STUFF ------------------------------------------------------- + +AOSystem::overrides::overrides(const char* setting_name) + : setting(setting_name ? gSavedPerAccountSettings.getControl("AODefault" + std::string(setting_name)) : nullptr) + , playing(false) +{ +} + +bool AOSystem::overrides::play_condition() const +{ + // Stop stand first then play + instance().stopCurrentStand(); + return false; +} + +void AOSystem::overrides::play(bool start) +{ + if (playing == start) return; +// LL_INFOS() << "st" << (start ? "art" : "op") << " override: " << aop->getOverride() << LL_ENDL; + // We can always stop, but starting is particular + if (start) + { + if (play_condition()) + return; + } + else if (playing && !isLowPriority()) // Stands were turned off if this isn't a low priority overrides + { + if (!isAgentAvatarValid() && !gAgentAvatarp->isSitting() && !gAgent.getFlying()) // check if sitting or hovering + instance().stand().play(); + } + playing = start; + gAgent.sendAnimationRequest(ao_id, start ? ANIM_REQUEST_START : ANIM_REQUEST_STOP); +} + +struct override_low_priority final : public AOSystem::overrides +{ + override_low_priority(const LLUUID& id, const char* setting_name = nullptr) + : overrides(setting_name), orig_id(id) {} + bool overrideAnim(bool swimming, const LLUUID& anim) const override { return orig_id == anim; } + bool play_condition() const override { return false; } + bool isLowPriority() const override { return true; } +private: + const LLUUID orig_id; +}; + +struct override_single final : public AOSystem::overrides +{ + override_single(const LLUUID& id, const char* setting_name = nullptr, U8 swim = 2) + : overrides(setting_name), orig_id(id), swim(swim) {} + bool overrideAnim(bool swimming, const LLUUID& anim) const override { return (swim == 2 || !!swim == swimming) && orig_id == anim; } +private: + const LLUUID orig_id; + const U8 swim; // 2 = irrelevant, 0 = flying, 1 = swimming +}; + +struct override_sit final : public AOSystem::overrides +{ + override_sit(const uuid_set_t& ids, const char* setting_name = nullptr) + : overrides(setting_name) + , orig_ids(ids) + {} + bool overrideAnim(bool swimming, const LLUUID& anim) const override { return orig_ids.find(anim) != orig_ids.end(); } + bool play_condition() const override + { + overrides::play_condition(); + return !gSavedSettings.getBOOL("AOSitsEnabled"); + } +private: + const uuid_set_t orig_ids; +}; + +bool AOSystem::override_stand::play_condition() const +{ + // Do not call base, stands do their own thing + // stands have lowest priority + return (!isAgentAvatarValid() || gAgentAvatarp->isSitting()) + && (gAgentCamera.cameraMouselook() && gSavedSettings.getBOOL("AONoStandsInMouselook")); +} + +bool AOSystem::override_stand::overrideAnim(bool swimming, const LLUUID& anim) const +{ + return anim == ANIM_AGENT_STAND; +} + +AOSystem::AOSystem() +: stand_iterator(0) +, mAOOverrides({}) +{ +// TODO: When we move to C++20 and when GCC and MSVC support it (at the time of writing, neither fully do), use __VA_OPT__ here instead. +#define ANY_OVERRIDE(which, state, ...) mAOOverrides[STATE_AGENT_##state] = new which(ANIM_AGENT_##state, ##__VA_ARGS__) +#define BASIC_OVERRIDE(state, ...) ANY_OVERRIDE(override_single, state, ##__VA_ARGS__) + mAOOverrides[STATE_AGENT_IDLE] = new override_stand(); + BASIC_OVERRIDE(WALK, "Walk"); + BASIC_OVERRIDE(RUN, "Run"); + BASIC_OVERRIDE(PRE_JUMP, "PreJump"); + BASIC_OVERRIDE(JUMP, "Jump"); + BASIC_OVERRIDE(TURNLEFT); + BASIC_OVERRIDE(TURNRIGHT); + +#define SIT_OVERRIDE(control, state, ...) mAOOverrides[STATE_AGENT_##state] = new override_sit(uuid_set_t{ANIM_AGENT_##state, __VA_ARGS__}, control) + SIT_OVERRIDE("Sit", SIT, ANIM_AGENT_SIT_FEMALE, ANIM_AGENT_SIT_GENERIC); + SIT_OVERRIDE("GroundSit", SIT_GROUND, ANIM_AGENT_SIT_GROUND_CONSTRAINED); +#undef SIT_OVERRIDE + + BASIC_OVERRIDE(HOVER, "Hover", false); + BASIC_OVERRIDE(HOVER_DOWN, "FlyDown", false); + BASIC_OVERRIDE(HOVER_UP, "FlyUp", false); + + BASIC_OVERRIDE(CROUCH, "Crouch"); + BASIC_OVERRIDE(CROUCHWALK, "CrouchWalk"); + BASIC_OVERRIDE(FALLDOWN, "Fall"); + BASIC_OVERRIDE(STANDUP, "StandUp"); + BASIC_OVERRIDE(LAND, "Land"); + + BASIC_OVERRIDE(FLY, "Fly", false); + BASIC_OVERRIDE(FLYSLOW, "FlySlow", false); + + ANY_OVERRIDE(override_low_priority, TYPE, "Typing"); + + mAOOverrides[STATE_AGENT_SWIM_DOWN] = new override_single(ANIM_AGENT_HOVER_DOWN, "SwimDown", true); + mAOOverrides[STATE_AGENT_SWIM_UP] = new override_single(ANIM_AGENT_HOVER_UP, "SwimUp", true); + mAOOverrides[STATE_AGENT_SWIM] = new override_single(ANIM_AGENT_FLY, "Swim", true); + mAOOverrides[STATE_AGENT_FLOAT] = new override_single(ANIM_AGENT_HOVER, "Float", true); +#undef BASIC_OVERRIDE +#undef ANY_OVERRIDE + + auto swim_forced = gSavedSettings.getControl("AOSwimForced"); + sSwimming = swim_forced->get().asBoolean() || is_underwater(); + mConnections[0] = gSavedSettings.getControl("AOSitsEnabled")->getSignal()->connect([this](LLControlVariable*, const LLSD& val) { + if (!isAgentAvatarValid() || !gAgentAvatarp->isSitting()) return; + gAgent.sendAnimationRequest(mAOOverrides[gAgentAvatarp->getParent() ? STATE_AGENT_SIT : STATE_AGENT_SIT_GROUND]->ao_id, val.asBoolean() ? ANIM_REQUEST_START : ANIM_REQUEST_STOP); + }); + const auto& swim_cb = [=](LLControlVariable*, const LLSD&){ toggleSwim(swim_forced->get().asBoolean() || is_underwater()); }; + auto swim_enabled = gSavedSettings.getControl("AOSwimEnabled"); + mConnections[1] = swim_enabled->getSignal()->connect(swim_cb); + mConnections[2] = swim_forced->getSignal()->connect([swim_cb, swim_enabled](LLControlVariable*, const LLSD& val) { + if (val.asBoolean()) // Automatically enable Swim AO. + swim_enabled->set(true); + swim_cb(nullptr, LLSD()); + }); +} + +AOSystem::~AOSystem() +{ + stopAllOverrides(); + for (auto& ao : mAOOverrides) + { + if (ao) + { + delete ao; + ao = nullptr; + } + } +} + +void AOSystem::requestConfigNotecard(bool reload) +{ + LLUUID configncitem = (LLUUID)gSavedPerAccountSettings.getString("AOConfigNotecardID"); + if (configncitem.notNull()) + { + bool success = false; + if (const LLInventoryItem* item = gInventory.getItem(configncitem)) + { + if (gAgent.allowOperation(PERM_COPY, item->getPermissions(), GP_OBJECT_MANIPULATE) || gAgent.isGodlike()) + { + if (item->getAssetUUID().notNull()) + { + invfolderid = item->getParentUUID(); + gAssetStorage->getInvItemAsset(LLHost::invalid, + gAgentID, + gAgentSessionID, + item->getPermissions().getOwner(), + LLUUID::null, + item->getUUID(), + item->getAssetUUID(), + item->getType(), + [reload](LLVFS* vfs, const LLUUID& asset_uuid, LLAssetType::EType type, void* user_data, S32 status, LLExtStat ext_status) + { + parseNotecard(vfs, asset_uuid, type, status, reload); + }, + nullptr, + true); + success = true; + } + } + } + if (!success) cmdline_printchat("Could not read the specified Config Notecard"); + } +} + +void AOSystem::initSingleton() +{ + mAOStands.clear(); + requestConfigNotecard(); +} + +void AOSystem::typing(bool start) +{ + uuid_vec_t anims; + // If we're stopping, stop regardless, just in case the setting was toggled during (e.g.: keyboard shortcut) + if (!start || gSavedSettings.getBOOL("PlayTypingAnim")) // Linden typing + anims.push_back(ANIM_AGENT_TYPE); + if (const auto& ao = getIfExists()) // Typing override + anims.push_back(ao->mAOOverrides[STATE_AGENT_TYPE]->getOverride()); + if (anims.empty()) return; + gAgent.sendAnimationRequests(anims, start ? ANIM_REQUEST_START : ANIM_REQUEST_STOP); +} + +AOState GetStateFromToken(const std::string& strtoken) +{ + if (strtoken == "[ Sitting On Ground ]") return STATE_AGENT_SIT_GROUND; + if (strtoken == "[ Sitting ]") return STATE_AGENT_SIT; + if (strtoken == "[ Crouching ]") return STATE_AGENT_CROUCH; + if (strtoken == "[ Crouch Walking ]") return STATE_AGENT_CROUCHWALK; + if (strtoken == "[ Standing Up ]") return STATE_AGENT_STANDUP; + if (strtoken == "[ Falling ]") return STATE_AGENT_FALLDOWN; + if (strtoken == "[ Flying Down ]") return STATE_AGENT_HOVER_DOWN; + if (strtoken == "[ Flying Up ]") return STATE_AGENT_HOVER_UP; + if (strtoken == "[ Flying Slow ]") return STATE_AGENT_FLYSLOW; + if (strtoken == "[ Flying ]") return STATE_AGENT_FLY; + if (strtoken == "[ Hovering ]") return STATE_AGENT_HOVER; + if (strtoken == "[ Jumping ]") return STATE_AGENT_JUMP; + if (strtoken == "[ Pre Jumping ]") return STATE_AGENT_PRE_JUMP; + if (strtoken == "[ Running ]") return STATE_AGENT_RUN; + if (strtoken == "[ Turning Right ]") return STATE_AGENT_TURNRIGHT; + if (strtoken == "[ Turning Left ]") return STATE_AGENT_TURNLEFT; + if (strtoken == "[ Walking ]") return STATE_AGENT_WALK; + if (strtoken == "[ Landing ]") return STATE_AGENT_LAND; + if (strtoken == "[ Standing ]") return STATE_AGENT_IDLE; + if (strtoken == "[ Swimming Down ]") return STATE_AGENT_SWIM_DOWN; + if (strtoken == "[ Swimming Up ]") return STATE_AGENT_SWIM_UP; + if (strtoken == "[ Swimming Forward ]") return STATE_AGENT_SWIM; + if (strtoken == "[ Floating ]") return STATE_AGENT_FLOAT; + if (strtoken == "[ Typing ]") return STATE_AGENT_TYPE; + return STATE_AGENT_END; +} + +void AOSystem::updateStand() +{ + auto& stand_ao = stand(); + bool is_standing = stand_ao.playing; + if (is_standing) stand_ao.play(false); // Stop stand first + stand_ao.update(mAOStands, stand_iterator); // Now update stand + if (is_standing && !mAOStands.empty()) // Play stand if needed + stand_ao.play(); +} + +int AOSystem::cycleStand(bool next, bool random) +{ + if (mAOStands.empty()) return -1; + const int size = mAOStands.size(); + if (size > 1) + { + if (random && gSavedSettings.getBOOL("AOStandRandomize")) + for (auto previous = stand_iterator; previous == stand_iterator; + stand_iterator = ll_rand(size)); + else + { + stand_iterator += next ? 1 : -1; + // Wrap around + if (stand_iterator == size) stand_iterator = 0; + else if (stand_iterator == -1) stand_iterator = size - 1; + } + if (auto floater = LLFloaterAO::findInstance()) + if (auto combo = floater->getComboFromState(STATE_AGENT_IDLE)) + combo->selectNthItem(stand_iterator); +// LL_INFOS() << "changing stand to " << mAOStands[stand_iterator].anim_name << LL_ENDL; + } + updateStand(); + return stand_iterator; +} + +void AOSystem::toggleSwim(bool underwater) +{ + sSwimming = underwater && enable_swim(); + + if (isStanding()) return; // Don't bother if we're just standing (Who pushed us?!) + + typedef std::array flies_t; + // Stop all of the previous states +#define AOO(state) mAOOverrides[STATE_AGENT_##state] + const flies_t swims = { AOO(FLOAT), AOO(SWIM), AOO(SWIM_UP), AOO(SWIM_DOWN) }; + const flies_t flies = { AOO(HOVER), AOO(FLY), AOO(HOVER_UP), AOO(HOVER_DOWN) }; +#undef AOO + const auto& oldaos = sSwimming ? flies : swims; + const auto& newaos = sSwimming ? swims : flies; + + for (auto i = 0; i < oldaos.size(); ++i) + { + auto& old = *oldaos[i]; + if (old.playing) + { + old.play(false); + newaos[i]->play(); + } + } +} + +void AOSystem::doMotion(const LLUUID& id, bool start) +{ + if (id.isNull() || !gAgentAvatarp) return; + + overrides* aop = nullptr; + AOState state = STATE_AGENT_IDLE; + for (U8 i = STATE_AGENT_IDLE; !aop && i < STATE_AGENT_END; ++i) + { + auto& ao = mAOOverrides[i]; + if (ao && ao->overrideAnim(sSwimming, id)) + { + aop = ao; + state = (AOState)i; + } + } + if (aop) + { +// LL_INFOS() << "st" << (start ? "art" : "op") << " anim " << id << " state " << state << LL_ENDL; + aop->play(start); + } +} + +void AOSystem::stopAllOverrides() const +{ + if (!isAgentAvatarValid()) return; + uuid_vec_t anims; + for (auto& ao : mAOOverrides) + { + if (ao->playing) + { + anims.push_back(ao->getOverride()); + ao->playing = false; + } + } + for (const auto& stand : mAOStands) + anims.push_back(stand.ao_id); + gAgent.sendAnimationRequests(anims, ANIM_REQUEST_STOP); +} + +void AOSystem::parseNotecard(LLVFS *vfs, const LLUUID& asset_uuid, LLAssetType::EType type, S32 status, bool reload) +{ + if (status == LL_ERR_NOERR) + { + if (type == LLAssetType::AT_NOTECARD) + { + AOSystem* self = getIfExists(); + S32 size = vfs->getSize(asset_uuid, LLAssetType::AT_NOTECARD); + U8* buffer = new U8[size]; + vfs->getData(asset_uuid, type, buffer, 0, size); + LLMemoryStream str(buffer, size); + LLNotecard nc; + if (nc.importStream(str)) + { + LL_INFOS() << "ao nc decode success" << LL_ENDL; + + if (self && reload) self->stopAllOverrides(); + + auto floater = LLFloaterAO::findInstance(); + if (floater) + for (auto& combo : floater->mCombos) + { + if (combo) + { + combo->clear(); + combo->removeall(); + } + } + + typedef boost::tokenizer > tokenizer; + boost::char_separator sep("\n"); + tokenizer tokline(nc.getText(), sep); + + for (const auto& strline : tokline) + { +// LL_INFOS() << "uncommented line: " << strline << LL_ENDL; + boost::regex type("^(\\s*)(\\[ )(.*)( \\])"); + boost::smatch what; + if (boost::regex_search(strline, what, type)) + { + const std::string strtoken(what[0]); + const AOState state = GetStateFromToken(strtoken); + if (state == STATE_AGENT_END) + { + LL_WARNS() << "Invalid token: " << strtoken << LL_ENDL; + continue; + } +// LL_INFOS() << "type: " << strtoken << LL_ENDL; + LLComboBox* combo = floater ? floater->getComboFromState(state) : nullptr; + auto aop = (reload && self) ? self->mAOOverrides[state] : nullptr; +// LL_INFOS() << "anims in type: " << boost::regex_replace(strline, type, "") << LL_ENDL; + + boost::char_separator sep("|,"); + std::string stranimnames(boost::regex_replace(strline, type, "")); + tokenizer tokanimnames(stranimnames, sep); + for (const auto& stranim : tokanimnames) + { + if (stranim.empty()) continue; + const auto& animid(getAssetIDByName(stranim)); + +// LL_INFOS() << invfolderid.asString().c_str() << LL_ENDL; +// LL_INFOS() << "anim: " << stranim.c_str() << " assetid: " << animid << LL_ENDL; + if (animid.notNull()) + { + if (aop) // If we're reloading + { + if (state == STATE_AGENT_IDLE) + self->mAOStands.push_back({ animid, stranim }); + else + aop->ao_id = animid; + } + + if (combo && !combo->selectByValue(stranim)) // check if exists + combo->add(stranim, ADD_BOTTOM, true); + } + else cmdline_printchat("Warning: animation '" + stranim + "' could not be found (Section: " + strtoken + ")."); + } + } + } + LL_INFOS() << "ao nc read sucess" << LL_ENDL; + + if (self) + { + if (auto combo = floater ? floater->getComboFromState(STATE_AGENT_IDLE) : nullptr) + combo->selectNthItem(self->stand_iterator); + + for (U8 i = STATE_AGENT_IDLE+1; i < STATE_AGENT_END; ++i) + { + auto& aop = self->mAOOverrides[i]; + if (!aop) continue; + auto& ao = *aop; + const auto& setting = ao.setting; + if (!setting && ao.ao_id.isNull()) continue; + const auto& defaultanim = setting ? setting->get().asStringRef() : ao.ao_id.asString(); + if (defaultanim.empty()) continue; + const LLUUID& ao_id = getAssetIDByName(defaultanim); + if (reload && ao_id.notNull()) ao.ao_id = ao_id; + if (LLComboBox* combo = floater ? floater->getComboFromState(i) : nullptr) + if (!combo->selectByValue(defaultanim)) + combo->add(defaultanim, ADD_BOTTOM, true); + } + + if (reload && isAgentAvatarValid()) + { + // Fix the stand iter, container size may have changed + auto& iter = self->stand_iterator; + const auto& stands = self->mAOStands; + iter = llmin(iter, (int)stands.size()-1); + // Update the current stand + self->stand().update(stands, iter); + self->mAOStandTimer.reset(); + + const auto& anims = gAgentAvatarp->mPlayingAnimations; + bool playing = false; + for (auto& aop : self->mAOOverrides) + { + for (const auto& anim : anims) + { + if (aop && aop->overrideAnim(sSwimming, anim.first)) + { + if (!aop->isLowPriority()) playing = true; + aop->play(); + break; + } + } + } + + if (!playing) self->stand().play(); // Play stand if nothing was being played, this sometimes happens + + // Toggle typing AO the moment we toggle AO + typing(gAgent.getRenderState() & AGENT_STATE_TYPING); + } + } + } + else LL_INFOS() << "ao nc decode error" << LL_ENDL; + delete[] buffer; + } + } + else LL_INFOS() << "ao nc read error" << LL_ENDL; +} diff --git a/indra/newview/aosystem.h b/indra/newview/aosystem.h new file mode 100644 index 0000000000..8dbfc6c78a --- /dev/null +++ b/indra/newview/aosystem.h @@ -0,0 +1,101 @@ +#pragma once + +#include "aostate.h" +#include "llcontrol.h" +#include "lleventtimer.h" + +class AOSystem final : public LLSingleton +{ + friend class LLSingleton; + friend class AOInvTimer; + friend class LLFloaterAO; + AOSystem(); + ~AOSystem(); +public: + static void start(); // Runs the necessary actions to get the AOSystem ready, then initializes it. + void initSingleton() override; + + static void typing(bool start); + + int stand_iterator; + bool isStanding() const { return stand().playing; } + void updateStand(); + int cycleStand(bool next = true, bool random = true); + void toggleSwim(bool underwater); + + void doMotion(const LLUUID& id, bool start); + void startMotion(const LLUUID& id) { doMotion(id, true); } + void stopMotion(const LLUUID& id) { doMotion(id, false); } + void stopCurrentStand() const { stand().play(false); } + void stopAllOverrides() const; + +protected: + struct struct_stands + { + LLUUID ao_id; + std::string anim_name; + }; + typedef std::vector stands_vec; + stands_vec mAOStands; + + struct overrides + { + virtual bool overrideAnim(bool swimming, const LLUUID& anim) const = 0; + virtual const LLUUID& getOverride() const { return ao_id; } + virtual bool play_condition() const; // True if prevented from playing + virtual bool isLowPriority() const { return false; } + void play(bool start = true); + LLUUID ao_id; + LLPointer setting; + bool playing; + virtual ~overrides() {} + protected: + overrides(const char* setting_name); + }; + friend struct override_low_priority; + friend struct override_single; + friend struct override_sit; + struct override_stand final : public overrides + { + override_stand() : overrides(nullptr) {} + bool overrideAnim(bool swimming, const LLUUID& anim) const override; + bool play_condition() const override; + bool isLowPriority() const override { return true; } + void update(const stands_vec& stands, const int& iter) + { + if (stands.empty()) ao_id.setNull(); + else ao_id = stands[iter].ao_id; + } + }; + std::array mAOOverrides; + + override_stand& stand() const { return static_cast(*mAOOverrides[STATE_AGENT_IDLE]); } + +private: + std::array mConnections; + + + class AOStandTimer final : public LLEventTimer + { + friend class AOSystem; + public: + AOStandTimer() : LLEventTimer(F32_MAX) {} + ~AOStandTimer() + { +// LL_INFOS() << "dead" << LL_ENDL; + } + BOOL tick() override + { +// LL_INFOS() << "tick" << LL_ENDL; + if (auto ao = AOSystem::getIfExists()) + ao->cycleStand(); + return false; + } + void reset(); + }; + AOStandTimer mAOStandTimer; + + static void requestConfigNotecard(bool reload = true); + static void parseNotecard(LLVFS* vfs, const LLUUID& asset_uuid, LLAssetType::EType type, S32 status, bool reload); +}; + diff --git a/indra/newview/app_settings/CA.pem b/indra/newview/app_settings/CA.pem deleted file mode 100644 index 8c1b9a1f37..0000000000 --- a/indra/newview/app_settings/CA.pem +++ /dev/null @@ -1,5573 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDfTCCAuagAwIBAgIDErvmMA0GCSqGSIb3DQEBBQUAME4xCzAJBgNVBAYTAlVT -MRAwDgYDVQQKEwdFcXVpZmF4MS0wKwYDVQQLEyRFcXVpZmF4IFNlY3VyZSBDZXJ0 -aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDIwNTIxMDQwMDAwWhcNMTgwODIxMDQwMDAw -WjBCMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UE -AxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB -CgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9m -OSm9BXiLnTjoBbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIu -T8rxh0PBFpVXLVDviS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6c -JmTM386DGXHKTubU1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmR -Cw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5asz -PeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQABo4HwMIHtMB8GA1UdIwQYMBaAFEjm -aPkr0rKV10fYIyAQTzOYkJ/UMB0GA1UdDgQWBBTAephojYn7qwVkDBF9qn1luMrM -TjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjA6BgNVHR8EMzAxMC+g -LaArhilodHRwOi8vY3JsLmdlb3RydXN0LmNvbS9jcmxzL3NlY3VyZWNhLmNybDBO -BgNVHSAERzBFMEMGBFUdIAAwOzA5BggrBgEFBQcCARYtaHR0cHM6Ly93d3cuZ2Vv -dHJ1c3QuY29tL3Jlc291cmNlcy9yZXBvc2l0b3J5MA0GCSqGSIb3DQEBBQUAA4GB -AHbhEm5OSxYShjAGsoEIz/AIx8dxfmbuwu3UOx//8PDITtZDOLC5MH0Y0FWDomrL -NhGc6Ehmo21/uBPUR/6LWlxz/K7ZGzIZOKuXNBSqltLroxwUCEm2u+WR74M26x1W -b8ravHNjkOR/ez4iyz0H7V84dJzjA1BOoa+Y7mHyhD8S ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIHhzCCBW+gAwIBAgIBLTANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJJTDEW -MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg -Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh -dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM3WhcNMzYwOTE3MTk0NjM2WjB9 -MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi -U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh -cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA -A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk -pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf -OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C -Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT -Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi -HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM -Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w -+2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+ -Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3 -Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B -26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID -AQABo4ICEDCCAgwwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD -VR0OBBYEFE4L7xqkQFulF2mHMMo0aEPQQa7yMB8GA1UdIwQYMBaAFE4L7xqkQFul -F2mHMMo0aEPQQa7yMIIBWgYDVR0gBIIBUTCCAU0wggFJBgsrBgEEAYG1NwEBATCC -ATgwLgYIKwYBBQUHAgEWImh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL3BvbGljeS5w -ZGYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL2ludGVybWVk -aWF0ZS5wZGYwgc8GCCsGAQUFBwICMIHCMCcWIFN0YXJ0IENvbW1lcmNpYWwgKFN0 -YXJ0Q29tKSBMdGQuMAMCAQEagZZMaW1pdGVkIExpYWJpbGl0eSwgcmVhZCB0aGUg -c2VjdGlvbiAqTGVnYWwgTGltaXRhdGlvbnMqIG9mIHRoZSBTdGFydENvbSBDZXJ0 -aWZpY2F0aW9uIEF1dGhvcml0eSBQb2xpY3kgYXZhaWxhYmxlIGF0IGh0dHA6Ly93 -d3cuc3RhcnRzc2wuY29tL3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgG -CWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1 -dGhvcml0eTANBgkqhkiG9w0BAQsFAAOCAgEAjo/n3JR5fPGFf59Jb2vKXfuM/gTF -wWLRfUKKvFO3lANmMD+x5wqnUCBVJX92ehQN6wQOQOY+2IirByeDqXWmN3PH/UvS -Ta0XQMhGvjt/UfzDtgUx3M2FIk5xt/JxXrAaxrqTi3iSSoX4eA+D/i+tLPfkpLst -0OcNOrg+zvZ49q5HJMqjNTbOx8aHmNrs++myziebiMMEofYLWWivydsQD032ZGNc -pRJvkrKTlMeIFw6Ttn5ii5B/q06f/ON1FE8qMt9bDeD1e5MNq6HPh+GlBEXoPBKl -CcWw0bdT82AUuoVpaiF8H3VhFyAXe2w7QSlc4axa0c2Mm+tgHRns9+Ww2vl5GKVF -P0lDV9LdJNUso/2RjSe15esUBppMeyG7Oq0wBhjA2MFrLH9ZXF2RsXAiV+uKa0hK -1Q8p7MZAwC+ITGgBF3f0JBlPvfrhsiAhS90a2Cl9qrjeVOwhVYBsHvUwyKMQ5bLm -KhQxw4UtjJixhlpPiVktucf3HMiKf8CdBUrmQk9io20ppB+Fq9vlgcitKj1MXVuE -JnHEhV5xJMqlG2zYYdMa4FTbzrqpMrUi9nNBCV24F10OD5mQ1kfabwo6YigUZ4LZ -8dCAWZvLMdibD4x3TrVoivJs9iQOLWxwxXPR3hTQcY+203sC9uO41Alua551hDnm -fyWl8kgAwKQB2j8= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEXDCCA0SgAwIBAgIEOGO5ZjANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML -RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp -bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5 -IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp -ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0xOTEy -MjQxODIwNTFaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3 -LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp -YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG -A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq -K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe -sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX -MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT -XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/ -HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH -4QIDAQABo3QwcjARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUVeSB0RGA -vtiJuQijMfmhJAkWuXAwHQYDVR0OBBYEFFXkgdERgL7YibkIozH5oSQJFrlwMB0G -CSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEA -WUesIYSKF8mciVMeuoCFGsY8Tj6xnLZ8xpJdGGQC49MGCBFhfGPjK50xA3B20qMo -oPS7mmNz7W3lKtvtFKkrxjYR0CvrB4ul2p5cGZ1WEvVUKcgF7bISKo30Axv/55IQ -h7A6tcOdBTcSo8f0FbnVpDkWm1M6I5HxqIKiaohowXkCIryqptau37AUX7iH0N18 -f3v/rxzP5tsHrV7bhZ3QKw0z2wTR5klAEyt2+z7pnIkPFc4YsIV4IU9rTw76NmfN -B/L/CNDi3tm/Kq+4h4YhPATKt5Rof8886ZjXOP/swNlQ8C5LWK5Gb9Auw2DaclVy -vUxFnmG6v4SBkgPR0ml8xQ== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEW -MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVy -c2FsIENBMB4XDTA0MDMwNDA1MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UE -BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xHjAcBgNVBAMTFUdlb1RydXN0 -IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKYV -VaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9tJPi8 -cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTT -QjOgNB0eRXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFh -F7em6fgemdtzbvQKoiFs7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2v -c7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d8Lsrlh/eezJS/R27tQahsiFepdaVaH/w -mZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7VqnJNk22CDtucvc+081xd -VHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3CgaRr0BHdCX -teGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZ -f9hBZ3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfRe -Bi9Fi1jUIxaS5BZuKGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+ -nhutxx9z3SxPGWX9f5NAEC7S8O08ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB -/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0XG0D08DYj3rWMB8GA1UdIwQY -MBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG -9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc -aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fX -IwjhmF7DWgh2qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzyn -ANXH/KttgCJwpQzgXQQpAvvLoJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0z -uzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsKxr2EoyNB3tZ3b4XUhRxQ4K5RirqN -Pnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxFKyDuSN/n3QmOGKja -QI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2DFKW -koRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9 -ER/frslKxfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQt -DF4JbAiXfKM9fJP/P6EUp8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/Sfuvm -bJxPgWp6ZKy7PtXny3YuxadIwVyQD8vIP/rmMuGNG2+k5o7Y+SlIis5z/iw= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDLTCCApagAwIBAgIBADANBgkqhkiG9w0BAQQFADCB0TELMAkGA1UEBhMCWkEx -FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMRowGAYD -VQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBT -ZXJ2aWNlcyBEaXZpc2lvbjEkMCIGA1UEAxMbVGhhd3RlIFBlcnNvbmFsIEZyZWVt -YWlsIENBMSswKQYJKoZIhvcNAQkBFhxwZXJzb25hbC1mcmVlbWFpbEB0aGF3dGUu -Y29tMB4XDTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgdExCzAJBgNVBAYT -AlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEa -MBgGA1UEChMRVGhhd3RlIENvbnN1bHRpbmcxKDAmBgNVBAsTH0NlcnRpZmljYXRp -b24gU2VydmljZXMgRGl2aXNpb24xJDAiBgNVBAMTG1RoYXd0ZSBQZXJzb25hbCBG -cmVlbWFpbCBDQTErMCkGCSqGSIb3DQEJARYccGVyc29uYWwtZnJlZW1haWxAdGhh -d3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1GnX1LCUZFtx6UfY -DFG26nKRsIRefS0Nj3sS34UldSh0OkIsYyeflXtL734Zhx2G6qPduc6WZBrCFG5E -rHzmj+hND3EfQDimAKOHePb5lIZererAXnbr2RSjXW56fAylS1V/Bhkpf56aJtVq -uzgkCGqYx7Hao5iR/Xnb5VrEHLkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zAN -BgkqhkiG9w0BAQQFAAOBgQDH7JJ+Tvj1lqVnYiqk8E0RYNBvjWBYYawmu1I1XAjP -MPuoSpaKH2JCI4wXD/S6ZJwXrEcp352YXtJsYHFcoqzceePnbgBHH7UNKOgCneSa -/RP0ptl8sfjcXyMmCZGAc9AUG95DqYMl8uacLxXK/qarigd1iwzdUYRr5PjRznei -gQ== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEvTCCA6WgAwIBAgIBADANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJFVTEn -MCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQL -ExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEiMCAGA1UEAxMZQ2hhbWJlcnMg -b2YgQ29tbWVyY2UgUm9vdDAeFw0wMzA5MzAxNjEzNDNaFw0zNzA5MzAxNjEzNDRa -MH8xCzAJBgNVBAYTAkVVMScwJQYDVQQKEx5BQyBDYW1lcmZpcm1hIFNBIENJRiBB -ODI3NDMyODcxIzAhBgNVBAsTGmh0dHA6Ly93d3cuY2hhbWJlcnNpZ24ub3JnMSIw -IAYDVQQDExlDaGFtYmVycyBvZiBDb21tZXJjZSBSb290MIIBIDANBgkqhkiG9w0B -AQEFAAOCAQ0AMIIBCAKCAQEAtzZV5aVdGDDg2olUkfzIx1L4L1DZ77F1c2VHfRtb -unXF/KGIJPov7coISjlUxFF6tdpg6jg8gbLL8bvZkSM/SAFwdakFKq0fcfPJVD0d -BmpAPrMMhe5cG3nCYsS4No41XQEMIwRHNaqbYE6gZj3LJgqcQKH0XZi/caulAGgq -7YN6D6IUtdQis4CwPAxaUWktWBiP7Zme8a7ileb2R6jWDA+wWFjbw2Y3npuRVDM3 -0pQcakjJyfKl2qUMI/cjDpwyVV5xnIQFUZot/eZOKjRa3spAN2cMVCFVd9oKDMyX -roDclDZK9D7ONhMeU+SsTjoF7Nuucpw4i9A5O4kKPnf+dQIBA6OCAUQwggFAMBIG -A1UdEwEB/wQIMAYBAf8CAQwwPAYDVR0fBDUwMzAxoC+gLYYraHR0cDovL2NybC5j -aGFtYmVyc2lnbi5vcmcvY2hhbWJlcnNyb290LmNybDAdBgNVHQ4EFgQU45T1sU3p -26EpW1eLTXYGduHRooowDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIA -BzAnBgNVHREEIDAegRxjaGFtYmVyc3Jvb3RAY2hhbWJlcnNpZ24ub3JnMCcGA1Ud -EgQgMB6BHGNoYW1iZXJzcm9vdEBjaGFtYmVyc2lnbi5vcmcwWAYDVR0gBFEwTzBN -BgsrBgEEAYGHLgoDATA+MDwGCCsGAQUFBwIBFjBodHRwOi8vY3BzLmNoYW1iZXJz -aWduLm9yZy9jcHMvY2hhbWJlcnNyb290Lmh0bWwwDQYJKoZIhvcNAQEFBQADggEB -AAxBl8IahsAifJ/7kPMa0QOx7xP5IV8EnNrJpY0nbJaHkb5BkAFyk+cefV/2icZd -p0AJPaxJRUXcLo0waLIJuvvDL8y6C98/d3tGfToSJI6WjzwFCm/SlCgdbQzALogi -1djPHRPH8EjX1wWnz8dHnjs8NMiAT9QUu/wNUPf6s+xCX6ndbcj0dc97wXImsQEc -XCz9ek60AcUFV7nnPKoF2YjpB0ZBzu9Bga5Y34OirsrXdx/nADydb47kMgkdTXg0 -eDQ8lJsm7U9xxhl6vSAiSFr+S30Dt+dYvsYyTnQeaN2oaFuzPu5ifdmA6Ap1erfu -tGWaIZDgqtCYvDi1czyL+Nw= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIID/TCCA2agAwIBAgIEP4/gkTANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQGEwJQ -TDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2Vu -dHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MR8wHQYDVQQDExZDQyBTaWduZXQgLSBD -QSBLbGFzYSAxMB4XDTAzMTAxNzEyMjkwMloXDTExMDkyMzExMTgxN1owdjELMAkG -A1UEBhMCUEwxHzAdBgNVBAoTFlRQIEludGVybmV0IFNwLiB6IG8uby4xJDAiBgNV -BAsTG0NlbnRydW0gQ2VydHlmaWthY2ppIFNpZ25ldDEgMB4GA1UEAxMXQ0MgU2ln -bmV0IC0gVFNBIEtsYXNhIDEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOJY -rISEtSsduHajROh5/n7NGrkpYTT9NEaPe9+ucuQ37KxIbfJwXJjgUc1dw4wCkcQ1 -2FJarD1X6mSQ4cfN/60vLfKI5ZD4nhJTMKlAj1pX9ScQ/MuyvKStCbn5WTkjPhjR -AM0tdwXSnzuTEunfw0Oup559y3Iqxg1cExflB6cfAgMBAAGjggGXMIIBkzBBBgNV -HR8EOjA4MDagNKAyhjBodHRwOi8vd3d3LnNpZ25ldC5wbC9yZXBvenl0b3JpdW0v -Y3JsL2tsYXNhMS5jcmwwDgYDVR0PAQH/BAQDAgeAMBYGA1UdJQEB/wQMMAoGCCsG -AQUFBwMIMIHaBgNVHSAEgdIwgc8wgcwGDSsGAQQBvj8CZAoRAgEwgbowbwYIKwYB -BQUHAgIwYxphQ2VydHlmaWthdCB3eXN0YXdpb255IHpnb2RuaWUgeiBkb2t1bWVu -dGVtICJQb2xpdHlrYSBDZXJ0eWZpa2FjamkgQ0MgU2lnbmV0IC0gWm5ha293YW5p -ZSBjemFzZW0iLjBHBggrBgEFBQcCARY7aHR0cDovL3d3dy5zaWduZXQucGwvcmVw -b3p5dG9yaXVtL2Rva3VtZW50eS9wY190c2ExXzJfMS5wZGYwHwYDVR0jBBgwFoAU -w4Me1Vl3VPtN+1dH+cQjXNHnieMwHQYDVR0OBBYEFJdDwEqtcavOYd9u9tej53vW -XwNBMAkGA1UdEwQCMAAwDQYJKoZIhvcNAQEFBQADgYEAnpiQkqLCJQYXUrqMHUEz -+z3rOqS0XzSFnVVLhkVssvXc8S3FkJIiQTUrkScjI4CToCzujj3EyfNxH6yiLlMb -skF8I31JxIeBvueqV+s+o76CZm3ycu9hb0I4lswuxoT+q5ZzPR8Irrb51rZXlolR -+7KtwMg4sFDJZ8RNgOf7tbA= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDlDCCAnygAwIBAgIQWAsFbFMk27JQVxhf+eWmUDANBgkqhkiG9w0BAQUFADAn -MQswCQYDVQQGEwJCRTEYMBYGA1UEAxMPQmVsZ2l1bSBSb290IENBMB4XDTAzMDEy -NjIzMDAwMFoXDTE0MDEyNjIzMDAwMFowJzELMAkGA1UEBhMCQkUxGDAWBgNVBAMT -D0JlbGdpdW0gUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB -AMihcekcRkJ5eHFvna6pqKsot03HIOswkVp19eLSz8hMFJhCWK3HEcVAQGpa+XQS -J4fpnOVxTiIs0RIYqjBeoiG52bv/9nTrMQHnO35YD5EWTXaJqAFPrSJmcPpLHZXB -MFjqvNll2Jq0iOtJRlLf0lMVdssUXRlJsW9q09P9vMIt7EU/CT9YvvzU7wCMgTVy -v/cY6pZifSsofxVsY9LKyn0FrMhtB20yvmi4BUCuVJhWPmbxMOjvxKuTXgfeMo8S -dKpbNCNUwOpszv42kqgJF+qhLc9s44Qd3ocuMws8dOIhUDiVLlzg5cYx+dtA+mqh -pIqTm6chBocdJ9PEoclMsG8CAwEAAaOBuzCBuDAOBgNVHQ8BAf8EBAMCAQYwDwYD -VR0TAQH/BAUwAwEB/zBCBgNVHSAEOzA5MDcGBWA4AQEBMC4wLAYIKwYBBQUHAgEW -IGh0dHA6Ly9yZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMB0GA1UdDgQWBBQQ8AxW -m2HqVzq2NZdtn925FI7b5jARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAU -EPAMVpth6lc6tjWXbZ/duRSO2+YwDQYJKoZIhvcNAQEFBQADggEBAMhtIlGKYfgP -lm7VILKB+MbcoxYA2s1q52sq+llIp0xJN9dzoWoBZV4yveeX09AuPHPTjHuD79ZC -wT+oqV0PN7p20kC9zC0/00RBSZz9Wyn0AiMiW3Ebv1jZKE4tRfTa57VjRUQRDSp/ -M382SbTObqkCMa5c/ciJv0J71/Fg8teH9lcuen5qE4Ad3OPQYx49cTGxYNSeCMqr -8JTHSHVUgfMbrXec6LKP24OsjzRr6L/D2fVDw2RV6xq9NoY2uiGMlxoh1OotO6y6 -7Kcdq765Sps1LxxcHVGnH1TtEpf/8m6HfUbJdNbv6z195lluBpQE5KJVhzgoaiJe -4r50ErAEQyo= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIH8jCCB1ugAwIBAgIBADANBgkqhkiG9w0BAQUFADCCARIxCzAJBgNVBAYTAkVT -MRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UE -ChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5sLjErMCkGA1UE -ChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1MjEuMCwGA1UECxMl -SVBTIENBIENMQVNFMSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEuMCwGA1UEAxMl -SVBTIENBIENMQVNFMSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEeMBwGCSqGSIb3 -DQEJARYPaXBzQG1haWwuaXBzLmVzMB4XDTAxMTIzMTExMTEwM1oXDTI1MTIyOTEx -MTEwM1owggESMQswCQYDVQQGEwJFUzESMBAGA1UECBMJQmFyY2Vsb25hMRIwEAYD -VQQHEwlCYXJjZWxvbmExLjAsBgNVBAoTJUlQUyBJbnRlcm5ldCBwdWJsaXNoaW5n -IFNlcnZpY2VzIHMubC4xKzApBgNVBAoUImlwc0BtYWlsLmlwcy5lcyBDLkkuRi4g -IEItNjA5Mjk0NTIxLjAsBgNVBAsTJUlQUyBDQSBDTEFTRTEgQ2VydGlmaWNhdGlv -biBBdXRob3JpdHkxLjAsBgNVBAMTJUlQUyBDQSBDTEFTRTEgQ2VydGlmaWNhdGlv -biBBdXRob3JpdHkxHjAcBgkqhkiG9w0BCQEWD2lwc0BtYWlsLmlwcy5lczCBnzAN -BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA55+R7+voFuF0vIkTodduR8ZfPxKU5u/h -M+GrgqufAwHmdG+KF5fPVy8Mdi7mbqfK2veLFBVADbNq2e2+s2q8Ai0chS3vl//P -l9rrR10eU79dVN4ndGMZfpXUMZblz0/Kq3Uvk5AsWUwfv1YokIhi4RMeBtOCVv3j -LSV1rDsiap8CAwEAAaOCBFIwggROMB0GA1UdDgQWBBRtW6MBjmE3nQR4tq+blh0C -QeXbeTCCAUQGA1UdIwSCATswggE3gBRtW6MBjmE3nQR4tq+blh0CQeXbeaGCARqk -ggEWMIIBEjELMAkGA1UEBhMCRVMxEjAQBgNVBAgTCUJhcmNlbG9uYTESMBAGA1UE -BxMJQmFyY2Vsb25hMS4wLAYDVQQKEyVJUFMgSW50ZXJuZXQgcHVibGlzaGluZyBT -ZXJ2aWNlcyBzLmwuMSswKQYDVQQKFCJpcHNAbWFpbC5pcHMuZXMgQy5JLkYuICBC -LTYwOTI5NDUyMS4wLAYDVQQLEyVJUFMgQ0EgQ0xBU0UxIENlcnRpZmljYXRpb24g -QXV0aG9yaXR5MS4wLAYDVQQDEyVJUFMgQ0EgQ0xBU0UxIENlcnRpZmljYXRpb24g -QXV0aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXOCAQAwDAYD -VR0TBAUwAwEB/zAMBgNVHQ8EBQMDB/+AMGsGA1UdJQRkMGIGCCsGAQUFBwMBBggr -BgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYKKwYBBAGCNwIB -FQYKKwYBBAGCNwIBFgYKKwYBBAGCNwoDAQYKKwYBBAGCNwoDBDARBglghkgBhvhC -AQEEBAMCAAcwGgYDVR0RBBMwEYEPaXBzQG1haWwuaXBzLmVzMBoGA1UdEgQTMBGB -D2lwc0BtYWlsLmlwcy5lczBCBglghkgBhvhCAQ0ENRYzQ0xBU0UxIENBIENlcnRp -ZmljYXRlIGlzc3VlZCBieSBodHRwczovL3d3dy5pcHMuZXMvMCoGCWCGSAGG+EIB -AgQdFhtodHRwczovL3d3dy5pcHMuZXMvaXBzMjAwMi8wOwYJYIZIAYb4QgEEBC4W -LGh0dHBzOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL2lwczIwMDJDTEFTRTEuY3JsMEAG -CWCGSAGG+EIBAwQzFjFodHRwczovL3d3dy5pcHMuZXMvaXBzMjAwMi9yZXZvY2F0 -aW9uQ0xBU0UxLmh0bWw/MD0GCWCGSAGG+EIBBwQwFi5odHRwczovL3d3dy5pcHMu -ZXMvaXBzMjAwMi9yZW5ld2FsQ0xBU0UxLmh0bWw/MDsGCWCGSAGG+EIBCAQuFixo -dHRwczovL3d3dy5pcHMuZXMvaXBzMjAwMi9wb2xpY3lDTEFTRTEuaHRtbDB1BgNV -HR8EbjBsMDKgMKAuhixodHRwczovL3d3dy5pcHMuZXMvaXBzMjAwMi9pcHMyMDAy -Q0xBU0UxLmNybDA2oDSgMoYwaHR0cHM6Ly93d3diYWNrLmlwcy5lcy9pcHMyMDAy -L2lwczIwMDJDTEFTRTEuY3JsMC8GCCsGAQUFBwEBBCMwITAfBggrBgEFBQcwAYYT -aHR0cDovL29jc3AuaXBzLmVzLzANBgkqhkiG9w0BAQUFAAOBgQBacEdMbCU0z2bO -X+iyJafrUbjPE+5KzJz2jB1YXC2d7kMy2Hhbp8gVyfUFQpd+F2IgBBj9z3IRNkDN -foHhdse5j2cUUH+fno9jj8EPE2GPhXVmCjIP6KuPp8yzz89gC+ry+bkfSFzjHUQt -K15I/jRAHfyJywwUrwtmklZIX0E5Og== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDWjCCAkKgAwIBAgIEO8rJUjANBgkqhkiG9w0BAQUFADBmMQswCQYDVQQGEwJE -SzEMMAoGA1UEChMDS01EMQ8wDQYDVQQLEwZLTUQtQ0ExFjAUBgNVBAMTDUtNRC1D -QSBTZXJ2ZXIxIDAeBgoJkiaJk/IsZAEDFBBpbmZvY2FAa21kLWNhLmRrMB4XDTk4 -MTAxNjE5MTkyMVoXDTE4MTAxMjE5MTkyMVowZjELMAkGA1UEBhMCREsxDDAKBgNV -BAoTA0tNRDEPMA0GA1UECxMGS01ELUNBMRYwFAYDVQQDEw1LTUQtQ0EgU2VydmVy -MSAwHgYKCZImiZPyLGQBAxQQaW5mb2NhQGttZC1jYS5kazCCASIwDQYJKoZIhvcN -AQEBBQADggEPADCCAQoCggEBAJsLpbSgFxQ7IhFgf5f+RfBxnbCkx5C7yTjfCZvp -/BP2LBD3OKjgLRwvASoCU3I5NMhccho6uhZVf1HC+Ac5HmXUUd+v92a7gDnohPPy -Rgv8c6f/+R2fFen37SBemYFDtZveamVXZ2To7xAxNiMKgPTPs/Rl7F6LDsYgv1bD -36FrjahNoSTmTbYRoK21eIOVwrZeNSzo9w3W8fj0n+V2IB1jsOh+AvjXkjbvAVky -0/57GMlyBNKP7JIGP7LXqwWfrBXuAph1DUMz467KlHZOMkPwCjTZOab7CcLQXCCY -12s5c5QAkwpf35hQRuOaNo6d/XFM6J9mofiWlGTT3Px1EX0CAwEAAaMQMA4wDAYD -VR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAPlA6VZ2C2cJbsI0SBIe9v+M9 -GxI45QI7P0D7QGyrqM7oNqGq7hJdN6NFb0LyPcF3/pVzmtYVJzaGKF6spaxOEveB -9ki1xRoXUKpaCxSweBpTzEktWa43OytRy0sbryEmHJCQkz8MPufWssf2yXHzgFFo -XMQpcMyT7JwxPlfYVvab9Kp+nW7fIyDOG0wdmBerZ+GEQJxJEkri1HskjigxhGze -ziocJatBuOWgqw5KRylgGIQjUGRTCbODVta+Kmqb9d+cB7FStbYtt2HebOXzBIY3 -XUM5KtGC++We7DqgU5Firek7brw8i2XsHPLKJTceb6Xo6DsSxLfBAWV6+8DCkQ== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIID+zCCAuOgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBtzE/MD0GA1UEAww2VMOc -UktUUlVTVCBFbGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sx -c8SxMQswCQYDVQQGDAJUUjEPMA0GA1UEBwwGQU5LQVJBMVYwVAYDVQQKDE0oYykg -MjAwNSBUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmlsacWfaW0gR8O8 -dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLjAeFw0wNTA1MTMxMDI3MTdaFw0xNTAz -MjIxMDI3MTdaMIG3MT8wPQYDVQQDDDZUw5xSS1RSVVNUIEVsZWt0cm9uaWsgU2Vy -dGlmaWthIEhpem1ldCBTYcSfbGF5xLFjxLFzxLExCzAJBgNVBAYMAlRSMQ8wDQYD -VQQHDAZBTktBUkExVjBUBgNVBAoMTShjKSAyMDA1IFTDnFJLVFJVU1QgQmlsZ2kg -xLBsZXRpxZ9pbSB2ZSBCaWxpxZ9pbSBHw7x2ZW5sacSfaSBIaXptZXRsZXJpIEEu -xZ4uMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAylIF1mMD2Bxf3dJ7 -XfIMYGFbazt0K3gNfUW9InTojAPBxhEqPZW8qZSwu5GXyGl8hMW0kWxsE2qkVa2k -heiVfrMArwDCBRj1cJ02i67L5BuBf5OI+2pVu32Fks66WJ/bMsW9Xe8iSi9BB35J -YbOG7E6mQW6EvAPs9TscyB/C7qju6hJKjRTP8wrgUDn5CDX4EVmt5yLqS8oUBt5C -urKZ8y1UiBAG6uEaPj1nH/vO+3yC6BFdSsG5FOpU2WabfIl9BJpiyelSPJ6c79L1 -JuTm5Rh8i27fbMx4W09ysstcP4wFjdFMjK2Sx+F4f2VsSQZQLJ4ywtdKxnWKWU51 -b0dewQIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAV -9VX/N5aAWSGk/KEVTCD21F/aAyT8z5Aa9CEKmu46sWrv7/hg0Uw2ZkUd82YCdAR7 -kjCo3gp2D++Vbr3JN+YaDayJSFvMgzbC9UZcWYJWtNX+I7TYVBxEq8Sn5RTOPEFh -fEPmzcSBCYsk+1Ql1haolgxnB2+zUEfjHCQo3SqYpGH+2+oSN7wBGjSFvW5P55Fy -B0SFHljKVETd96y5y4khctuPwGkplyqjrhgjlxxBKot8KsF8kOipKMDTkcatKIdA -aLX/7KfS0zgYnNN9aV3wxqUeJBujR/xpB2jn5Jq07Q+hh4cCzofSSE7hvP/L8XKS -RGQDJereW26fyfJOrN3H ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJVUzEc -MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBT -ZWN1cmUgZUJ1c2luZXNzIENBLTEwHhcNOTkwNjIxMDQwMDAwWhcNMjAwNjIxMDQw -MDAwWjBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5j -LjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNzIENBLTEwgZ8wDQYJ -KoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fek6lfWg0XTzQaDJj0ItlZ1MRo -RvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5/VGcqiTZ9J2DKocKIdMSODRsjQBu -WqDZQu4aIZX5UkxVWsUPOE9G+m34LjXWHXzr4vCwdYDIqROsvojvOm6rXyo4YgKw -Env+j6YDAgMBAAGjZjBkMBEGCWCGSAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTAD -AQH/MB8GA1UdIwQYMBaAFEp4MlIR21kWNl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRK -eDJSEdtZFjZe38EUNkBqR3xMoTANBgkqhkiG9w0BAQQFAAOBgQB1W6ibAxHm6VZM -zfmpTMANmvPMZWnmJXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5lSE/9dR+ -WB5Hh1Q+WKG1tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN -/Bf+KpYrtWKmpj29f5JZzVoqgrI3eQ== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFajCCBFKgAwIBAgIEPLU9RjANBgkqhkiG9w0BAQUFADBmMRIwEAYDVQQKEwli -ZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBSb290IENBczEzMDEGA1UEAxMq -YmVUUlVTVGVkIFJvb3QgQ0EtQmFsdGltb3JlIEltcGxlbWVudGF0aW9uMB4XDTAy -MDQxMTA3Mzg1MVoXDTIyMDQxMTA3Mzg1MVowZjESMBAGA1UEChMJYmVUUlVTVGVk -MRswGQYDVQQLExJiZVRSVVNUZWQgUm9vdCBDQXMxMzAxBgNVBAMTKmJlVFJVU1Rl -ZCBSb290IENBLUJhbHRpbW9yZSBJbXBsZW1lbnRhdGlvbjCCASIwDQYJKoZIhvcN -AQEBBQADggEPADCCAQoCggEBALx+xDmcjOPWHIb/ymKt4H8wRXqOGrO4x/nRNv8i -805qX4QQ+2aBw5R5MdKR4XeOGCrDFN5R9U+jK7wYFuK13XneIviCfsuBH/0nLI/6 -l2Qijvj/YaOcGx6Sj8CoCd8JEey3fTGaGuqDIQY8n7pc/5TqarjDa1U0Tz0yH92B -FODEPM2dMPgwqZfT7syj0B9fHBOB1BirlNFjw55/NZKeX0Tq7PQiXLfoPX2k+Ymp -kbIq2eszh+6l/ePazIjmiSZuxyuC0F6dWdsU7JGDBcNeDsYq0ATdcT0gTlgn/FP7 -eHgZFLL8kFKJOGJgB7Sg7KxrUNb9uShr71ItOrL/8QFArDcCAwEAAaOCAh4wggIa -MA8GA1UdEwEB/wQFMAMBAf8wggG1BgNVHSAEggGsMIIBqDCCAaQGDysGAQQBsT4A -AAEJKIORMTCCAY8wggFIBggrBgEFBQcCAjCCAToaggE2UmVsaWFuY2Ugb24gb3Ig -dXNlIG9mIHRoaXMgQ2VydGlmaWNhdGUgY3JlYXRlcyBhbiBhY2tub3dsZWRnbWVu -dCBhbmQgYWNjZXB0YW5jZSBvZiB0aGUgdGhlbiBhcHBsaWNhYmxlIHN0YW5kYXJk -IHRlcm1zIGFuZCBjb25kaXRpb25zIG9mIHVzZSwgdGhlIENlcnRpZmljYXRpb24g -UHJhY3RpY2UgU3RhdGVtZW50IGFuZCB0aGUgUmVseWluZyBQYXJ0eSBBZ3JlZW1l -bnQsIHdoaWNoIGNhbiBiZSBmb3VuZCBhdCB0aGUgYmVUUlVTVGVkIHdlYiBzaXRl -LCBodHRwOi8vd3d3LmJldHJ1c3RlZC5jb20vcHJvZHVjdHNfc2VydmljZXMvaW5k -ZXguaHRtbDBBBggrBgEFBQcCARY1aHR0cDovL3d3dy5iZXRydXN0ZWQuY29tL3By -b2R1Y3RzX3NlcnZpY2VzL2luZGV4Lmh0bWwwHQYDVR0OBBYEFEU9w6nR3D8kVpgc -cxiIav+DR+22MB8GA1UdIwQYMBaAFEU9w6nR3D8kVpgccxiIav+DR+22MA4GA1Ud -DwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEASZK8o+6svfoNyYt5hhwjdrCA -WXf82n+0S9/DZEtqTg6t8n1ZdwWtColzsPq8y9yNAIiPpqCy6qxSJ7+hSHyXEHu6 -7RMdmgduyzFiEuhjA6p9beP4G3YheBufS0OM00mG9htc9i5gFdPp43t1P9ACg9AY -gkHNZTfqjjJ+vWuZXTARyNtIVBw74acT02pIk/c9jH8F6M7ziCpjBLjqflh8AXtb -4cV97yHgjQ5dUX2xZ/2jvTg2xvI4hocalmhgRvsoFEdV4aeADGvi6t9NfJBIoDa9 -CReJf8Py05yc493EG931t3GzUwWJBtDLSoDByFOQtTwxiBdQn8nEDovYqAJjDQ== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkG -A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz -cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2 -MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV -BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt -YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN -ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE -BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is -I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G -CSqGSIb3DQEBAgUAA4GBALtMEivPLCYATxQT3ab7/AoRhIzzKBxnki98tsX63/Do -lbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59AhWM1pF+NEHJwZRDmJXNyc -AA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2OmufTqj/ZA1k ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/ -MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT -DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow -PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD -Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB -AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O -rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq -OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b -xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw -7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD -aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV -HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG -SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69 -ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr -AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz -R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5 -JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo -Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDUzCCAjugAwIBAgIBATANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEd -MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3Mg -Q2xhc3MgMiBDQSAxMB4XDTA2MTAxMzEwMjUwOVoXDTE2MTAxMzEwMjUwOVowSzEL -MAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MR0wGwYD -VQQDDBRCdXlwYXNzIENsYXNzIDIgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEP -ADCCAQoCggEBAIs8B0XY9t/mx8q6jUPFR42wWsE425KEHK8T1A9vNkYgxC7McXA0 -ojTTNy7Y3Tp3L8DrKehc0rWpkTSHIln+zNvnma+WwajHQN2lFYxuyHyXA8vmIPLX -l18xoS830r7uvqmtqEyeIWZDO6i88wmjONVZJMHCR3axiFyCO7srpgTXjAePzdVB -HfCuuCkslFJgNJQ72uA40Z0zPhX0kzLFANq1KWYOOngPIVJfAuWSeyXTkh4vFZ2B -5J2O6O+JzhRMVB0cgRJNcKi+EAUXfh/RuFdV7c27UsKwHnjCTTZoy1YmwVLBvXb3 -WNVyfh9EdrsAiR0WnVE1703CVu9r4Iw7DekCAwEAAaNCMEAwDwYDVR0TAQH/BAUw -AwEB/zAdBgNVHQ4EFgQUP42aWYv8e3uco684sDntkHGA1sgwDgYDVR0PAQH/BAQD -AgEGMA0GCSqGSIb3DQEBBQUAA4IBAQAVGn4TirnoB6NLJzKyQJHyIdFkhb5jatLP -gcIV1Xp+DCmsNx4cfHZSldq1fyOhKXdlyTKdqC5Wq2B2zha0jX94wNWZUYN/Xtm+ -DKhQ7SLHrQVMdvvt7h5HZPb3J31cKA9FxVxiXqaakZG3Uxcu3K1gnZZkOb1naLKu -BctN518fV4bVIJwo+28TOPX2EZL2fZleHwzoq0QkKXJAPTZSr4xYkHPB7GEseaHs -h7U/2k3ZIQAw3pDaDtMaSKk+hQsUi4y8QZ5q9w5wwDX3OaJdZtB7WZ+oRxKaJyOk -LY4ng5IgodcVf/EuGO70SH8vf/GhGLWhC5SgYiAynB321O+/TIho ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEqjCCA5KgAwIBAgIOSkcAAQAC5aBd1j8AUb8wDQYJKoZIhvcNAQEFBQAwdjEL -MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNV -BAsTGVRDIFRydXN0Q2VudGVyIENsYXNzIDMgQ0ExJTAjBgNVBAMTHFRDIFRydXN0 -Q2VudGVyIENsYXNzIDMgQ0EgSUkwHhcNMDYwMTEyMTQ0MTU3WhcNMjUxMjMxMjI1 -OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIgR21i -SDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQTElMCMGA1UEAxMc -VEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQAD -ggEPADCCAQoCggEBALTgu1G7OVyLBMVMeRwjhjEQY0NVJz/GRcekPewJDRoeIMJW -Ht4bNwcwIi9v8Qbxq63WyKthoy9DxLCyLfzDlml7forkzMA5EpBCYMnMNWju2l+Q -Vl/NHE1bWEnrDgFPZPosPIlY2C8u4rBo6SI7dYnWRBpl8huXJh0obazovVkdKyT2 -1oQDZogkAHhg8fir/gKya/si+zXmFtGt9i4S5Po1auUZuV3bOx4a+9P/FRQI2Alq -ukWdFHlgfa9Aigdzs5OW03Q0jTo3Kd5c7PXuLjHCINy+8U9/I1LZW+Jk2ZyqBwi1 -Rb3R0DHBq1SfqdLDYmAD8bs5SpJKPQq5ncWg/jcCAwEAAaOCATQwggEwMA8GA1Ud -EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTUovyfs8PYA9NX -XAek0CSnwPIA1DCB7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRy -dXN0Y2VudGVyLmRlL2NybC92Mi90Y19jbGFzc18zX2NhX0lJLmNybIaBn2xkYXA6 -Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBUcnVzdENlbnRlciUyMENsYXNz -JTIwMyUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21iSCxPVT1yb290 -Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u -TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEANmDkcPcGIEPZIxpC8vijsrlN -irTzwppVMXzEO2eatN9NDoqTSheLG43KieHPOh6sHfGcMrSOWXaiQYUlN6AT0PV8 -TtXqluJucsG7Kv5sbviRmEb8yRtXW+rIGjs/sFGYPAfaLFkB2otE6OF0/ado3VS6 -g0bsyEa1+K+XwDsJHI/OcpY9M1ZwvJbL2NV9IJqDnxrcOfHFcqMRA/07QlIp2+gB -95tejNaNhk4Z+rwcvsUhpYeeeC422wlxo3I0+GzjBgnyXlal092Y+tTmBvTwtiBj -S+opvaqCZh77gaqnN60TGOaSw4HBM7uIHqHn4rS9MWwOUT1v+5ZWgOI2F9Hc5A== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDKTCCApKgAwIBAgIENm7TzjANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQGEwJV -UzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREwDwYDVQQL -EwhEU1RDQSBFMjAeFw05ODEyMDkxOTE3MjZaFw0xODEyMDkxOTQ3MjZaMEYxCzAJ -BgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4x -ETAPBgNVBAsTCERTVENBIEUyMIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQC/ -k48Xku8zExjrEH9OFr//Bo8qhbxe+SSmJIi2A7fBw18DW9Fvrn5C6mYjuGODVvso -LeE4i7TuqAHhzhy2iCoiRoX7n6dwqUcUP87eZfCocfdPJmyMvMa1795JJ/9IKn3o -TQPMx7JSxhcxEzu1TdvIxPbDDyQq2gyd55FbgM2UnQIBA6OCASQwggEgMBEGCWCG -SAGG+EIBAQQEAwIABzBoBgNVHR8EYTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMx -JDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMI -RFNUQ0EgRTIxDTALBgNVBAMTBENSTDEwKwYDVR0QBCQwIoAPMTk5ODEyMDkxOTE3 -MjZagQ8yMDE4MTIwOTE5MTcyNlowCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFB6C -TShlgDzJQW6sNS5ay97u+DlbMB0GA1UdDgQWBBQegk0oZYA8yUFurDUuWsve7vg5 -WzAMBgNVHRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqG -SIb3DQEBBQUAA4GBAEeNg61i8tuwnkUiBbmi1gMOOHLnnvx75pO2mqWilMg0HZHR -xdf0CiUPPXiBng+xZ8SQTGPdXqfiup/1902lMXucKS1M/mQ+7LZT/uqb7YLbdHVL -B3luHtgZg3Pe9T7Qtd7nS2h9Qy4qIOF+oHhEngj1mPnHfxsb1gYgAlihw6ID ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UE -BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVz -dCBQcmVtaXVtMB4XDTEwMDEyOTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkG -A1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1U -cnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxBLf -qV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtnBKAQ -JG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ -+jjeRFcV5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrS -s8PhaJyJ+HoAVt70VZVs+7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5 -HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmdGPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d7 -70O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5Rp9EixAqnOEhss/n/fauG -V+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NIS+LI+H+S -qHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S -5u046uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4Ia -C1nEWTJ3s7xgaVY5/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TX -OwF0lkLgAOIua+rF7nKsu7/+6qqo+Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYE -FJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ -BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByvMiPIs0laUZx2 -KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg -Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B -8OWycvpEgjNC6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQ -MKSOyARiqcTtNd56l+0OOF6SL5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc -0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK+4w1IX2COPKpVJEZNZOUbWo6xbLQ -u4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmVBtWVyuEklut89pMF -u+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFgIxpH -YoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8 -GKa1qF60g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaO -RtGdFNrHF+QFlozEJLUbzxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6e -KeC2uAloGRwYQw== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDYTCCAkmgAwIBAgIQCgEBAQAAAnwAAAAKAAAAAjANBgkqhkiG9w0BAQUFADA6 -MRkwFwYDVQQKExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0EgU2VjdXJp -dHkgMjA0OCBWMzAeFw0wMTAyMjIyMDM5MjNaFw0yNjAyMjIyMDM5MjNaMDoxGTAX -BgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAbBgNVBAsTFFJTQSBTZWN1cml0eSAy -MDQ4IFYzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt49VcdKA3Xtp -eafwGFAyPGJn9gqVB93mG/Oe2dJBVGutn3y+Gc37RqtBaB4Y6lXIL5F4iSj7Jylg -/9+PjDvJSZu1pJTOAeo+tWN7fyb9Gd3AIb2E0S1PRsNO3Ng3OTsor8udGuorryGl -wSMiuLgbWhOHV4PR8CDn6E8jQrAApX2J6elhc5SYcSa8LWrg903w8bYqODGBDSnh -AMFRD0xS+ARaqn1y07iHKrtjEAMqs6FPDVpeRrc9DvV07Jmf+T0kgYim3WBU6JU2 -PcYJk5qjEoAAVZkZR73QpXzDuvsf9/UP+Ky5tfQ3mBMY3oVbtwyCO4dvlTlYMNpu -AWgXIszACwIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB -BjAfBgNVHSMEGDAWgBQHw1EwpKrpRa41JPr/JCwz0LGdjDAdBgNVHQ4EFgQUB8NR -MKSq6UWuNST6/yQsM9CxnYwwDQYJKoZIhvcNAQEFBQADggEBAF8+hnZuuDU8TjYc -HnmYv/3VEhF5Ug7uMYm83X/50cYVIeiKAVQNOvtUudZj1LGqlk2iQk3UUx+LEN5/ -Zb5gEydxiKRz44Rj0aRV4VCT5hsOedBnvEbIvz8XDZXmxpBp3ue0L96VfdASPz0+ -f00/FGj1EVDVwfSQpQgdMWD/YIwjVAqv/qFuxdF6Kmh4zx6CCiC0H63lhbJqaHVO -rSU3lIW+vaHU6rcMSzyd6BIA8F+sDeGscGNz9395nzIlQnQFgCi/vcEkllgVsRch -6YlL2weIZ/QVrXA+L02FO8K32/6YaCOJ4XQP3vTFhGMpG8zLB8kApKnXwiJPZ9d3 -7CAFYd4= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMCWkEx -FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD -VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv -biBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFByZW1pdW0gU2Vy -dmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNlcnZlckB0aGF3dGUuY29t -MB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgc4xCzAJBgNVBAYTAlpB -MRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEdMBsG -A1UEChMUVGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNVBAsTH0NlcnRpZmljYXRp -b24gU2VydmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNl -cnZlciBDQTEoMCYGCSqGSIb3DQEJARYZcHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNv -bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2aovXwlue2oFBYo847kkE -VdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIhUdib0GfQ -ug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMR -uHM/qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG -9w0BAQQFAAOBgQAmSCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUI -hfzJATj/Tb7yFkJD57taRvvBxhEf8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZa4JM -pAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7tUCemDaYj+bvLpgcUQg== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV -UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy -dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1 -MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx -dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B -AQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPRfM6f -BeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+A -cJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kC -AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQ -MA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlm -aWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgw -ODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gj -IBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQF -MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA -A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y -7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh -1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4 ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDfTCCAmWgAwIBAgIBADANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJKUDEl -MCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEqMCgGA1UECxMh -U2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBFViBSb290Q0ExMB4XDTA3MDYwNjAyMTIz -MloXDTM3MDYwNjAyMTIzMlowYDELMAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09N -IFRydXN0IFN5c3RlbXMgQ08uLExURC4xKjAoBgNVBAsTIVNlY3VyaXR5IENvbW11 -bmljYXRpb24gRVYgUm9vdENBMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC -ggEBALx/7FebJOD+nLpCeamIivqA4PUHKUPqjgo0No0c+qe1OXj/l3X3L+SqawSE -RMqm4miO/VVQYg+kcQ7OBzgtQoVQrTyWb4vVog7P3kmJPdZkLjjlHmy1V4qe70gO -zXppFodEtZDkBp2uoQSXWHnvIEqCa4wiv+wfD+mEce3xDuS4GBPMVjZd0ZoeUWs5 -bmB2iDQL87PRsJ3KYeJkHcFGB7hj3R4zZbOOCVVSPbW9/wfrrWFVGCypaZhKqkDF -MxRldAD5kd6vA0jFQFTcD4SQaCDFkpbcLuUCRarAX1T4bepJz11sS6/vmsJWXMY1 -VkJqMF/Cq/biPT+zyRGPMUzXn0kCAwEAAaNCMEAwHQYDVR0OBBYEFDVK9U2vP9eC -OKyrcWUXdYydVZPmMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0G -CSqGSIb3DQEBBQUAA4IBAQCoh+ns+EBnXcPBZsdAS5f8hxOQWsTvoMpfi7ent/HW -tWS3irO4G8za+6xmiEHO6Pzk2x6Ipu0nUBsCMCRGef4Eh3CXQHPRwMFXGZpppSeZ -q51ihPZRwSzJIxXYKLerJRO1RuGGAv8mjMSIkh1W/hln8lXkgKNrnKt34VFxDSDb -EJrbvXZ5B3eZKK2aXtqxT0QsNY6llsf9g/BYxnnWmHyojf6GPgcWkuF75x3sM3Z+ -Qi5KhfmRiWiEA4Glm5q+4zfFVKtWOxgtQaQM+ELbmaDgcm+7XeEWT1MKZPlO9L9O -VL14bIjqv5wTJMJwaaJ/D8g8rQjJsJhAoyrniIPtd490 ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICPDCCAaUCEAq6HgBiMui0NiZdH3zNiWYwDQYJKoZIhvcNAQEFBQAwXzELMAkG -A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz -cyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2 -MDEyOTAwMDAwMFoXDTI4MDgwMjIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV -BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAyIFB1YmxpYyBQcmlt -YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN -ADCBiQKBgQC2WoujDWojg4BrzzmH9CETMwZMJaLtVRKXxaeAufqDwSCg+i8VDXyh -YGt+eSz6Bg86rvYbb7HS/y8oUl+DfUvEerf4Zh+AVPy3wo5ZShRXRtGak75BkQO7 -FYCTXOvnzAhsPz6zSvz/S2wj1VCCJkQZjiPDceoZJEcEnnW/yKYAHwIDAQABMA0G -CSqGSIb3DQEBBQUAA4GBAIDToA+IyeVoW4R7gB+nt+MjWBEc9RTwWBKMi99x2ZAk -EXyge8N6GRm9cr0gvwA63/rVeszC42JFi8tJg5jBcGnQnl6CjDVHjk8btB9jAa3k -ltax7nosZm4XNq8afjgGhixrTcsnkm54vwDVAcCxB8MJqmSFKPKdc57PYDoKHUpI ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFTzCCBLigAwIBAgIBaDANBgkqhkiG9w0BAQQFADCBmzELMAkGA1UEBhMCSFUx -ETAPBgNVBAcTCEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0 -b25zYWdpIEtmdC4xGjAYBgNVBAsTEVRhbnVzaXR2YW55a2lhZG9rMTQwMgYDVQQD -EytOZXRMb2NrIEV4cHJlc3N6IChDbGFzcyBDKSBUYW51c2l0dmFueWtpYWRvMB4X -DTk5MDIyNTE0MDgxMVoXDTE5MDIyMDE0MDgxMVowgZsxCzAJBgNVBAYTAkhVMREw -DwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6dG9u -c2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE0MDIGA1UEAxMr -TmV0TG9jayBFeHByZXNzeiAoQ2xhc3MgQykgVGFudXNpdHZhbnlraWFkbzCBnzAN -BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA6+ywbGGKIyWvYCDj2Z/8kwvbXY2wobNA -OoLO/XXgeDIDhlqGlZHtU/qdQPzm6N3ZW3oDvV3zOwzDUXmbrVWg6dADEK8KuhRC -2VImESLH0iDMgqSaqf64gXadarfSNnU+sYYJ9m5tfk63euyucYT2BDMIJTLrdKwW -RMbkQJMdf60CAwEAAaOCAp8wggKbMBIGA1UdEwEB/wQIMAYBAf8CAQQwDgYDVR0P -AQH/BAQDAgAGMBEGCWCGSAGG+EIBAQQEAwIABzCCAmAGCWCGSAGG+EIBDQSCAlEW -ggJNRklHWUVMRU0hIEV6ZW4gdGFudXNpdHZhbnkgYSBOZXRMb2NrIEtmdC4gQWx0 -YWxhbm9zIFN6b2xnYWx0YXRhc2kgRmVsdGV0ZWxlaWJlbiBsZWlydCBlbGphcmFz -b2sgYWxhcGphbiBrZXN6dWx0LiBBIGhpdGVsZXNpdGVzIGZvbHlhbWF0YXQgYSBO -ZXRMb2NrIEtmdC4gdGVybWVrZmVsZWxvc3NlZy1iaXp0b3NpdGFzYSB2ZWRpLiBB -IGRpZ2l0YWxpcyBhbGFpcmFzIGVsZm9nYWRhc2FuYWsgZmVsdGV0ZWxlIGF6IGVs -b2lydCBlbGxlbm9yemVzaSBlbGphcmFzIG1lZ3RldGVsZS4gQXogZWxqYXJhcyBs -ZWlyYXNhIG1lZ3RhbGFsaGF0byBhIE5ldExvY2sgS2Z0LiBJbnRlcm5ldCBob25s -YXBqYW4gYSBodHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIGNpbWVuIHZhZ3kg -a2VyaGV0byBheiBlbGxlbm9yemVzQG5ldGxvY2submV0IGUtbWFpbCBjaW1lbi4g -SU1QT1JUQU5UISBUaGUgaXNzdWFuY2UgYW5kIHRoZSB1c2Ugb2YgdGhpcyBjZXJ0 -aWZpY2F0ZSBpcyBzdWJqZWN0IHRvIHRoZSBOZXRMb2NrIENQUyBhdmFpbGFibGUg -YXQgaHR0cHM6Ly93d3cubmV0bG9jay5uZXQvZG9jcyBvciBieSBlLW1haWwgYXQg -Y3BzQG5ldGxvY2submV0LjANBgkqhkiG9w0BAQQFAAOBgQAQrX/XDDKACtiG8XmY -ta3UzbM2xJZIwVzNmtkFLp++UOv0JhQQLdRmF/iewSf98e3ke0ugbLWrmldwpu2g -pO0u9f38vf5NNwgMvOOWgyL1SRt/Syu0VMGAfJlOHdCM7tCs5ZL6dVb+ZKATj7i4 -Fp1hBWeAyNDYpQcCNJgEjTME1A== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDkjCCAnqgAwIBAgIRAIW9S/PY2uNp9pTXX8OlRCMwDQYJKoZIhvcNAQEFBQAw -PTELMAkGA1UEBhMCRlIxETAPBgNVBAoTCENlcnRwbHVzMRswGQYDVQQDExJDbGFz -cyAyIFByaW1hcnkgQ0EwHhcNOTkwNzA3MTcwNTAwWhcNMTkwNzA2MjM1OTU5WjA9 -MQswCQYDVQQGEwJGUjERMA8GA1UEChMIQ2VydHBsdXMxGzAZBgNVBAMTEkNsYXNz -IDIgUHJpbWFyeSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANxQ -ltAS+DXSCHh6tlJw/W/uz7kRy1134ezpfgSN1sxvc0NXYKwzCkTsA18cgCSR5aiR -VhKC9+Ar9NuuYS6JEI1rbLqzAr3VNsVINyPi8Fo3UjMXEuLRYE2+L0ER4/YXJQyL -kcAbmXuZVg2v7tK8R1fjeUl7NIknJITesezpWE7+Tt9avkGtrAjFGA7v0lPubNCd -EgETjdyAYveVqUSISnFOYFWe2yMZeVYHDD9jC1yw4r5+FfyUM1hBOHTE4Y+L3yas -H7WLO7dDWWuwJKZtkIvEcupdM5i3y95ee++U8Rs+yskhwcWYAqqi9lt3m/V+llU0 -HGdpwPFC40es/CgcZlUCAwEAAaOBjDCBiTAPBgNVHRMECDAGAQH/AgEKMAsGA1Ud -DwQEAwIBBjAdBgNVHQ4EFgQU43Mt38sOKAze3bOkynm4jrvoMIkwEQYJYIZIAYb4 -QgEBBAQDAgEGMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly93d3cuY2VydHBsdXMu -Y29tL0NSTC9jbGFzczIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCnVM+IRBnL39R/ -AN9WM2K191EBkOvDP9GIROkkXe/nFL0gt5o8AP5tn9uQ3Nf0YtaLcF3n5QRIqWh8 -yfFC82x/xXp8HVGIutIKPidd3i1RTtMTZGnkLuPT55sJmabglZvOGtd/vjzOUrMR -FcEPF80Du5wlFbqidon8BvEY0JNLDnyCt6X09l/+7UCmnYR0ObncHoUW2ikbhiMA -ybuJfm6AiB4vFLQDJKgybwOaRywwvlbGp0ICcBvqQNi6BQNwB6SW//1IMwrh3KWB -kJtN3X3n57LNXMhqlfil9o3EXXgIvnsG1knPGTZQIy4I5p4FTUcY1Rbpsda2ENW7 -l7+ijrRU ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICoTCCAgqgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBizELMAkGA1UEBhMCWkEx -FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTEUMBIGA1UEBxMLRHVyYmFudmlsbGUxDzAN -BgNVBAoTBlRoYXd0ZTEdMBsGA1UECxMUVGhhd3RlIENlcnRpZmljYXRpb24xHzAd -BgNVBAMTFlRoYXd0ZSBUaW1lc3RhbXBpbmcgQ0EwHhcNOTcwMTAxMDAwMDAwWhcN -MjAxMjMxMjM1OTU5WjCBizELMAkGA1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4g -Q2FwZTEUMBIGA1UEBxMLRHVyYmFudmlsbGUxDzANBgNVBAoTBlRoYXd0ZTEdMBsG -A1UECxMUVGhhd3RlIENlcnRpZmljYXRpb24xHzAdBgNVBAMTFlRoYXd0ZSBUaW1l -c3RhbXBpbmcgQ0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANYrWHhhRYZT -6jR7UZztsOYuGA7+4F+oJ9O0yeB8WU4WDnNUYMF/9p8u6TqFJBU820cEY8OexJQa -Wt9MevPZQx08EHp5JduQ/vBR5zDWQQD9nyjfeb6Uu522FOMjhdepQeBMpHmwKxqL -8vg7ij5FrHGSALSQQZj7X+36ty6K+Ig3AgMBAAGjEzARMA8GA1UdEwEB/wQFMAMB -Af8wDQYJKoZIhvcNAQEEBQADgYEAZ9viwuaHPUCDhjc1fR/OmsMMZiCouqoEiYbC -9RAIDb/LogWK0E02PvTX72nGXuSwlG9KuefeW4i2e9vjJ+V2w/A1wcu1J5szedyQ -pgCed/r8zSeUQhac0xxo7L9c3eWpexAKMnRUEzGLhQOEkbdYATAUOK8oyvyxUBkZ -CayJSdM= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBi -MQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu -MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3Jp -dHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMxMjM1OTU5WjBiMQswCQYDVQQGEwJV -UzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydO -ZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0GCSqG -SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwz -c7MEL7xxjOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPP -OCwGJgl6cvf6UDL4wpPTaaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rl -mGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXTcrA/vGp97Eh/jcOrqnErU2lBUzS1sLnF -BgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc/Qzpf14Dl847ABSHJ3A4 -qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMBAAGjgZcw -gZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIB -BjAPBgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwu -bmV0c29sc3NsLmNvbS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3Jp -dHkuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc8 -6fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q4LqILPxFzBiwmZVRDuwduIj/ -h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/GGUsyfJj4akH -/nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv -wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHN -pGxlaKFJdlxDydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDgDCCAmigAwIBAgICAx4wDQYJKoZIhvcNAQEFBQAwYTELMAkGA1UEBhMCVVMx -DTALBgNVBAoTBFZJU0ExLzAtBgNVBAsTJlZpc2EgSW50ZXJuYXRpb25hbCBTZXJ2 -aWNlIEFzc29jaWF0aW9uMRIwEAYDVQQDEwlHUCBSb290IDIwHhcNMDAwODE2MjI1 -MTAwWhcNMjAwODE1MjM1OTAwWjBhMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklT -QTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRp -b24xEjAQBgNVBAMTCUdQIFJvb3QgMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC -AQoCggEBAKkBcLWqxEDwq2omYXkZAPy/mzdZDK9vZBv42pWUJGkzEXDK41Z0ohdX -ZFwgBuHW73G3O/erwWnQSaSxBNf0V2KJXLB1LRckaeNCYOTudNargFbYiCjh+20i -/SN8RnNPflRzHqgsVVh1t0zzWkWlAhr62p3DRcMiXvOL8WAp0sdftAw6UYPvMPjU -58fy+pmjIlC++QU3o63tmsPm7IgbthknGziLgE3sucfFicv8GjLtI/C1AVj59o/g -halMCXI5Etuz9c9OYmTaxhkVOmMd6RdVoUwiPDQyRvhlV7or7zaMavrZ2UT0qt2E -1w0cslSsMoW0ZA3eQbuxNMYBhjJk1Z8CAwEAAaNCMEAwHQYDVR0OBBYEFJ59SzS/ -ca3CBfYDdYDOqU8axCRMMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEG -MA0GCSqGSIb3DQEBBQUAA4IBAQAhpXYUVfmtJ3CPPPTVbMjMCqujmAuKBiPFyWHb -mQdpNSYx/scuhMKZYdQN6X0uEyt8joW2hcdLzzW2LEc9zikv2G+fiRxkk78IvXbQ -kIqUs38oW26sTTMs7WXcFsziza6kPWKSBpUmv9+55CCmc2rBvveURNZNbyoLaxhN -dBA2aGpawWqn3TYpjLgwi08hPwAuVDAHOrqK5MOeyti12HvOdUVmB/RtLdh6yumJ -ivIj2C/LbgA2T/vwLwHMD8AiZfSr4k5hLQOCfZEWtTDVFN5ex5D8ofyrEK9ca3Cn -B+8phuiyJccg/ybdd+95RBTEvd07xQObdyPsoOy7Wjm1zK0G ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEajCCA1KgAwIBAgIBATANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJKUDEN -MAsGA1UECgwESlBLSTEpMCcGA1UECwwgUHJlZmVjdHVyYWwgQXNzb2NpYXRpb24g -Rm9yIEpQS0kxETAPBgNVBAsMCEJyaWRnZUNBMB4XDTAzMTIyNzA1MDgxNVoXDTEz -MTIyNjE0NTk1OVowWjELMAkGA1UEBhMCSlAxDTALBgNVBAoMBEpQS0kxKTAnBgNV -BAsMIFByZWZlY3R1cmFsIEFzc29jaWF0aW9uIEZvciBKUEtJMREwDwYDVQQLDAhC -cmlkZ2VDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANTnUmg7K3m8 -52vd77kwkq156euwoWm5no8E8kmaTSc7x2RABPpqNTlMKdZ6ttsyYrqREeDkcvPL -yF7yf/I8+innasNtsytcTAy8xY8Avsbd4JkCGW9dyPjk9pzzc3yLQ64Rx2fujRn2 -agcEVdPCr/XpJygX8FD5bbhkZ0CVoiASBmlHOcC3YpFlfbT1QcpOSOb7o+VdKVEi -MMfbBuU2IlYIaSr/R1nO7RPNtkqkFWJ1/nKjKHyzZje7j70qSxb+BTGcNgTHa1YA -UrogKB+UpBftmb4ds+XlkEJ1dvwokiSbCDaWFKD+YD4B2s0bvjCbw8xuZFYGhNyR -/2D5XfN1s2MCAwEAAaOCATkwggE1MA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E -BTADAQH/MG0GA1UdHwRmMGQwYqBgoF6kXDBaMQswCQYDVQQGEwJKUDENMAsGA1UE -CgwESlBLSTEpMCcGA1UECwwgUHJlZmVjdHVyYWwgQXNzb2NpYXRpb24gRm9yIEpQ -S0kxETAPBgNVBAsMCEJyaWRnZUNBMIGDBgNVHREEfDB6pHgwdjELMAkGA1UEBhMC -SlAxJzAlBgNVBAoMHuWFrOeahOWAi+S6uuiqjeiovOOCteODvOODk+OCuTEeMBwG -A1UECwwV6YO96YGT5bqc55yM5Y2U6K2w5LyaMR4wHAYDVQQLDBXjg5bjg6rjg4Pj -grjoqo3oqLzlsYAwHQYDVR0OBBYEFNQXMiCqQNkR2OaZmQgLtf8mR8p8MA0GCSqG -SIb3DQEBBQUAA4IBAQATjJo4reTNPC5CsvAKu1RYT8PyXFVYHbKsEpGt4GR8pDCg -HEGAiAhHSNrGh9CagZMXADvlG0gmMOnXowriQQixrtpkmx0TB8tNAlZptZWkZC+R -8TnjOkHrk2nFAEC3ezbdK0R7MR4tJLDQCnhEWbg50rf0wZ/aF8uAaVeEtHXa6W0M -Xq3dSe0XAcrLbX4zZHQTaWvdpLAIjl6DZ3SCieRMyoWUL+LXaLFdTP5WBCd+No58 -IounD9X4xxze2aeRVaiV/WnQ0OSPNS7n7YXy6xQdnaOU4KRW/Lne1EDf5IfWC/ih -bVAmhZMbcrkWWcsR6aCPG+2mV3zTD6AUzuKPal8Y ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDzzCCAregAwIBAgIDAWweMA0GCSqGSIb3DQEBBQUAMIGNMQswCQYDVQQGEwJB -VDFIMEYGA1UECgw/QS1UcnVzdCBHZXMuIGYuIFNpY2hlcmhlaXRzc3lzdGVtZSBp -bSBlbGVrdHIuIERhdGVudmVya2VociBHbWJIMRkwFwYDVQQLDBBBLVRydXN0LW5R -dWFsLTAzMRkwFwYDVQQDDBBBLVRydXN0LW5RdWFsLTAzMB4XDTA1MDgxNzIyMDAw -MFoXDTE1MDgxNzIyMDAwMFowgY0xCzAJBgNVBAYTAkFUMUgwRgYDVQQKDD9BLVRy -dXN0IEdlcy4gZi4gU2ljaGVyaGVpdHNzeXN0ZW1lIGltIGVsZWt0ci4gRGF0ZW52 -ZXJrZWhyIEdtYkgxGTAXBgNVBAsMEEEtVHJ1c3QtblF1YWwtMDMxGTAXBgNVBAMM -EEEtVHJ1c3QtblF1YWwtMDMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB -AQCtPWFuA/OQO8BBC4SAzewqo51ru27CQoT3URThoKgtUaNR8t4j8DRE/5TrzAUj -lUC5B3ilJfYKvUWG6Nm9wASOhURh73+nyfrBJcyFLGM/BWBzSQXgYHiVEEvc+RFZ -znF/QJuKqiTfC0Li21a8StKlDJu3Qz7dg9MmEALP6iPESU7l0+m0iKsMrmKS1GWH -2WrX9IWf5DMiJaXlyDO6w8dB3F/GaswADm0yqLaHNgBid5seHzTLkDx4iHQF63n1 -k3Flyp3HaxgtPVxO59X4PzF9j4fsCiIvI+n+u33J4PTs63zEsMMtYrWacdaxaujs -2e3Vcuy+VwHOBVWf3tFgiBCzAgMBAAGjNjA0MA8GA1UdEwEB/wQFMAMBAf8wEQYD -VR0OBAoECERqlWdVeRFPMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOC -AQEAVdRU0VlIXLOThaq/Yy/kgM40ozRiPvbY7meIMQQDbwvUB/tOdQ/TLtPAF8fG -KOwGDREkDg6lXb+MshOWcdzUzg4NCmgybLlBMRmrsQd7TZjTXLDR8KdCoLXEjq/+ -8T/0709GAHbrAvv5ndJAlseIOrifEXnzgGWovR/TeIGgUUw3tKZdJXDRZslo+S4R -FGjxVJgIrCaSD96JntT6s3kr0qN51OyLrIdTaEJMUVF0HhsnLuP1Hyl0Te2v9+GS -mYHovjrHF1D2t8b8m7CKa9aIA5GPBnc6hQLdmNVDeD/GMBWsm2vLV7eJUYs66MmE -DNuxUCAKGkq6ahq97BvIxYSazQ== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx -EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT -EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp -ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIz -NTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH -EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UE -AxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIw -DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKD -E6bFIEMBO4Tx5oVJnyfq9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH -/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD+qK+ihVqf94Lw7YZFAXK6sOoBJQ7Rnwy -DfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutdfMh8+7ArU6SSYmlRJQVh -GkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMlNAJWJwGR -tDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEA -AaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE -FDqahQcQZyi27/a9BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmX -WWcDYfF+OwYxdS2hII5PZYe096acvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu -9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r5N9ss4UXnT3ZJE95kTXWXwTr -gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo -2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO -LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI -4uJEvlz36hz1 ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G -A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp -Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1 -MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG -A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL -v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8 -eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq -tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd -C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa -zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB -mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH -V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n -bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG -3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs -J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO -291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS -ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd -AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7 -TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G -A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp -Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4 -MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG -A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8 -RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT -gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm -KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd -QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ -XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw -DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o -LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU -RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp -jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK -6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX -mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs -Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH -WD9f ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDdTCCAl2gAwIBAgILAgAAAAAA1ni3lAUwDQYJKoZIhvcNAQEEBQAwVzELMAkG -A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv -b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw -MDBaFw0xNDAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i -YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT -aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ -jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp -xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp -1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG -snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ -U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8 -9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIABjAdBgNVHQ4EFgQU -YHtmGkUNl8qJUC99BM00qP/8/UswDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0B -AQQFAAOCAQEArqqf/LfSyx9fOSkoGJ40yWxPbxrwZKJwSk8ThptgKJ7ogUmYfQq7 -5bCdPTbbjwVR/wkxKh/diXeeDy5slQTthsu0AD+EAk2AaioteAuubyuig0SDH81Q -gkwkr733pbTIWg/050deSY43lv6aiAU62cDbKYfmGZZHpzqmjIs8d/5GY6dT2iHR -rH5Jokvmw2dZL7OKDrssvamqQnw1wdh/1acxOk5jQzmvCLBhNIzTmKlDNPYPhyk7 -ncJWWJh3w/cbrPad+D6qp1RF8PX51TFl/mtYnHGzHtdS6jIX/EBgHcl5JLL2bP2o -Zg6C3ZjL2sJETy6ge/L3ayx2EYRGinij4w== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIETTCCAzWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBtMQswCQYDVQQGEwJDSDEO -MAwGA1UEChMFYWRtaW4xETAPBgNVBAsTCFNlcnZpY2VzMSIwIAYDVQQLExlDZXJ0 -aWZpY2F0aW9uIEF1dGhvcml0aWVzMRcwFQYDVQQDEw5BZG1pbkNBLUNELVQwMTAe -Fw0wNjAxMjUxMzM2MTlaFw0xNjAxMjUxMjM2MTlaMG0xCzAJBgNVBAYTAkNIMQ4w -DAYDVQQKEwVhZG1pbjERMA8GA1UECxMIU2VydmljZXMxIjAgBgNVBAsTGUNlcnRp -ZmljYXRpb24gQXV0aG9yaXRpZXMxFzAVBgNVBAMTDkFkbWluQ0EtQ0QtVDAxMIIB -IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0jQlMZmpLDhV+GNR9TAoSNle -JgQB4xAXJELQf5/ySMfoFA4MmjKqYXQkB6MGPuQKwR9XRRSPf61vqb8YPsdjRmgp -byHBcUd5t0N8RX6wRZUnPMW+bCCo2VqAU4XFbnlc2gHKaam0wdTtbBTXEkv0ieIH -fxCfFxXqSsSr60IkF/2/xbrAgV/QD5yHk6Ie8feAVWwi5UtaFqtu4LiFEh2QMyxs -Oyz1OcvKzkM2g873tyiE7jzMgZP+Ww3tibk2F9+e6ZeiB37TLOmVtvgpmrws4fiI -rFNXEYSWBVrUTbn81U47yWzOgf5fEHP07bRV5QOCzCm99qNimsbL6CG7nT78CQID -AQABo4H3MIH0MBIGA1UdEwEB/wQIMAYBAf8CAQAwga4GA1UdIASBpjCBozCBoAYI -YIV0AREDFQEwgZMwSAYIKwYBBQUHAgIwPBo6VGhpcyBpcyB0aGUgQWRtaW5DQS1D -RC1UMDEgQ2VydGlmaWNhdGUgUHJhY3RpY2UgU3RhdGVtZW50LjBHBggrBgEFBQcC -ARY7aHR0cDovL3d3dy5wa2kuYWRtaW4uY2gvcG9saWN5L0NQU18yXzE2Xzc1Nl8x -XzE3XzNfMjFfMS5wZGYwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBQqxGkKocZV -xgNucM6GgbOkD6oZ2zANBgkqhkiG9w0BAQUFAAOCAQEAn356bbusjI5glGXRQ1DR -v21qQf0S4s3GHyZm7cqdOkFleM70ArBT+kOP5Nm7rlSAFyVgEkmBdOg7s9tlXClU -yeZFnp6UEYRUcijPN8D1VaNRK6PIUObpDBQT0C+kAfxG9z4v29T0SxT4sgAdC/xQ -Fyv58Fp9bPn7owuKwKcyCH1XSyi/Bp4XFELlLOaigBZO/w+dPBz4FcJSdZjU+BaJ -0E3nKAjHlShO5ouBSZnaJz3p+nkw2Wyo36s6GxCK0XbkSP45iniIG4FmwwZkonYF -ypQntHbx2oL7tUQQY0PDo8bGBMcPy/G2j+dciqZRlsnfgMy10SCzQ9MUx92xUG2V -eg== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQG -EwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3 -MDUGA1UECwwuVGFuw7pzw610dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNl -cnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBBcmFueSAoQ2xhc3MgR29sZCkgRsWR -dGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgxMjA2MTUwODIxWjCB -pzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxOZXRM -b2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlm -aWNhdGlvbiBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNz -IEdvbGQpIEbFkXRhbsO6c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A -MIIBCgKCAQEAxCRec75LbRTDofTjl5Bu0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrT -lF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw/HpYzY6b7cNGbIRwXdrz -AZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAkH3B5r9s5 -VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRG -ILdwfzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2 -BJtr+UBdADTHLpl1neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAG -AQH/AgEEMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2M -U9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwWqZw8UQCgwBEIBaeZ5m8BiFRh -bvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTtaYtOUZcTh5m2C -+C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC -bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2F -uLjbvrW5KfnaNwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2 -XjG4Kvte9nHfRCaexOYNkbQudZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBM -MSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5D -ZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBU -cnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIyMTIwNzM3WhcNMjkxMjMxMTIwNzM3 -WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMg -Uy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSIw -IAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0B -AQEFAAOCAQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rH -UV+rpDKmYYe2bg+G0jACl/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LM -TXPb865Px1bVWqeWifrzq2jUI4ZZJ88JJ7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVU -BBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4fOQtf/WsX+sWn7Et0brM -kUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0cvW0QM8x -AcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNV -HRMBAf8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNV -HQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15y -sHhE49wcrwn9I0j6vSrEuVUEtRCjjSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfL -I9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1mS1FhIrlQgnXdAIv94nYmem8 -J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5ajZt3hrvJBW8qY -VoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI -03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIF5zCCA8+gAwIBAgIITK9zQhyOdAIwDQYJKoZIhvcNAQEFBQAwgYAxODA2BgNV -BAMML0VCRyBFbGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sx -c8SxMTcwNQYDVQQKDC5FQkcgQmlsacWfaW0gVGVrbm9sb2ppbGVyaSB2ZSBIaXpt -ZXRsZXJpIEEuxZ4uMQswCQYDVQQGEwJUUjAeFw0wNjA4MTcwMDIxMDlaFw0xNjA4 -MTQwMDMxMDlaMIGAMTgwNgYDVQQDDC9FQkcgRWxla3Ryb25payBTZXJ0aWZpa2Eg -SGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTE3MDUGA1UECgwuRUJHIEJpbGnFn2ltIFRl -a25vbG9qaWxlcmkgdmUgSGl6bWV0bGVyaSBBLsWeLjELMAkGA1UEBhMCVFIwggIi -MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDuoIRh0DpqZhAy2DE4f6en5f2h -4fuXd7hxlugTlkaDT7byX3JWbhNgpQGR4lvFzVcfd2NR/y8927k/qqk153nQ9dAk -tiHq6yOU/im/+4mRDGSaBUorzAzu8T2bgmmkTPiab+ci2hC6X5L8GCcKqKpE+i4s -tPtGmggDg3KriORqcsnlZR9uKg+ds+g75AxuetpX/dfreYteIAbTdgtsApWjluTL -dlHRKJ2hGvxEok3MenaoDT2/F08iiFD9rrbskFBKW5+VQarKD7JK/oCZTqNGFav4 -c0JqwmZ2sQomFd2TkuzbqV9UIlKRcF0T6kjsbgNs2d1s/OsNA/+mgxKb8amTD8Um -TDGyY5lhcucqZJnSuOl14nypqZoaqsNW2xCaPINStnuWt6yHd6i58mcLlEOzrz5z -+kI2sSXFCjEmN1ZnuqMLfdb3ic1nobc6HmZP9qBVFCVMLDMNpkGMvQQxahByCp0O -Lna9XvNRiYuoP1Vzv9s6xiQFlpJIqkuNKgPlV5EQ9GooFW5Hd4RcUXSfGenmHmMW -OeMRFeNYGkS9y8RsZteEBt8w9DeiQyJ50hBs37vmExH8nYQKE3vwO9D8owrXieqW -fo1IhR5kX9tUoqzVegJ5a9KK8GfaZXINFHDk6Y54jzJ0fFfy1tb0Nokb+Clsi7n2 -l9GkLqq+CxnCRelwXQIDAJ3Zo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB -/wQEAwIBBjAdBgNVHQ4EFgQU587GT/wWZ5b6SqMHwQSny2re2kcwHwYDVR0jBBgw -FoAU587GT/wWZ5b6SqMHwQSny2re2kcwDQYJKoZIhvcNAQEFBQADggIBAJuYml2+ -8ygjdsZs93/mQJ7ANtyVDR2tFcU22NU57/IeIl6zgrRdu0waypIN30ckHrMk2pGI -6YNw3ZPX6bqz3xZaPt7gyPvT/Wwp+BVGoGgmzJNSroIBk5DKd8pNSe/iWtkqvTDO -TLKBtjDOWU/aWR1qeqRFsIImgYZ29fUQALjuswnoT4cCB64kXPBfrAowzIpAoHME -wfuJJPaaHFy3PApnNgUIMbOv2AFoKuB4j3TeuFGkjGwgPaL7s9QJ/XvCgKqTbCmY -Iai7FvOpEl90tYeY8pUm3zTvilORiF0alKM/fCL414i6poyWqD1SNGKfAB5UVUJn -xk1Gj7sURT0KlhaOEKGXmdXTMIXM3rRyt7yKPBgpaP3ccQfuJDlq+u2lrDgv+R4Q -DgZxGhBM/nV+/x5XOULK1+EVoVZVWRvRo68R2E7DpSvvkL/A7IITW43WciyTTo9q -Kd+FPNMN4KIYEsxVL0e3p5sC/kH2iExt2qkBR4NkJ2IQgtYSe14DHzSpyZH+r11t -hie3I6p1GMog57AP14kOpmciY/SDQSsGS7tY1dHXt7kQY9iJSrSq3RZj9W6+YKH4 -7ejWkE8axsWgKdOnIaj1Wjz3x0miIZpKlVIglnKaZsv30oZDfCK+lvm9AahH3eU7 -QPl1K5srRmSGjR70j/sHd9DqSaIcjVIUpgqT ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML -RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp -bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5 -IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp -ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0yOTA3 -MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3 -LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp -YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG -A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq -K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe -sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX -MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT -XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/ -HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH -4QIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV -HQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJKoZIhvcNAQEFBQADggEBADub -j1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPyT/4xmf3IDExo -U8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf -zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5b -u/8j72gZyxKTJ1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+ -bYQLCIt+jerXmCHG8+c8eS9enNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/Er -fF6adulZkMV8gzURZVE= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIGJDCCBY2gAwIBAgIEQoaroDANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UEBhMC -VVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50cnVzdC5u -ZXQvQ1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMc -KGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UEAxMxRW50cnVzdC5u -ZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjA3 -MTQxNzEwMjhaFw0xNDA3MTQxNzQwMjhaMFwxCzAJBgNVBAYTAlVTMRUwEwYDVQQK -EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xGzAZBgNV -BAMTEkRpZ2lDZXJ0IEdsb2JhbCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC -AQoCggEBAMQ8vMy66mLmnkIjr7SyEa5ijdmh04/MFHIZ7Zn2/d5du1nAsMKvaplS -lVcLNf/hhvqvosPBBWUnIHYvClQlfOor3ZVBV5sPO89H6AEGjMVESPwHLvNygzBR -lJ5pOoOph5AU2V7EoniPwT7UGWEOGufcGpUgQb5vF9q4HEHumLD61x01PxanBCgT -XT0FdZouhp4ssBeHIFhX7+HqVWC4LHAhrCljDBD8YLz51Rw3ZNW0+x6rJjlGiKTL -zTBnwCZ55cpo+SLX5dKxu0hMmwuYW0KS5dLtDkcw+t0nVmNqpQHHjq/wTjsbVRVE -1T5NVx7hkeq4oI/OOmNflom6CD7+RLsCAwEAAaOCAwUwggMBMBIGA1UdEwEB/wQI -MAYBAf8CAQAwggEyBgNVHSAEggEpMIIBJTCCASEGCSqGSIb2fQdLAjCCARIwJgYI -KwYBBQUHAgEWGmh0dHA6Ly93d3cuZW50cnVzdC5uZXQvY3BzMIHnBggrBgEFBQcC -AjCB2hqB10ZvciB1c2Ugc29sZWx5IHdpdGggU1NMIGFuZCBTL01JTUUgY2VydGlm -aWNhdGVzIGlzc3VlZCBieSBEaWdpY2VydCwgSW5jLiB0byBhdXRob3JpemVkIHN1 -YnNjcmliZXJzLg0KRE9FUyBOT1QgcmVwcmVzZW50IGFueSBlbmRvcnNlbWVudCBi -eSBFbnRydXN0IEluYy4gb3IgaXRzIGFmZmlsaWF0ZXMgYXMgdG8gdGhlIGlkZW50 -aXR5IG9mIGFueSBjZXJ0aWZpY2F0ZSBob2xkZXIuMDEGA1UdJQQqMCgGCCsGAQUF -BwMBBggrBgEFBQcDAgYIKwYBBQUHAwQGCCsGAQUFBwMJMIIBGAYDVR0fBIIBDzCC -AQswKKAmoCSGImh0dHA6Ly9jcmwuZW50cnVzdC5uZXQvc2VydmVyMS5jcmwwgd6g -gduggdikgdUwgdIxCzAJBgNVBAYTAlVTMRQwEgYDVQQKEwtFbnRydXN0Lm5ldDE7 -MDkGA1UECxMyd3d3LmVudHJ1c3QubmV0L0NQUyBpbmNvcnAuIGJ5IHJlZi4gKGxp -bWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0 -ZWQxOjA4BgNVBAMTMUVudHJ1c3QubmV0IFNlY3VyZSBTZXJ2ZXIgQ2VydGlmaWNh -dGlvbiBBdXRob3JpdHkxDTALBgNVBAMTBENSTDEwCwYDVR0PBAQDAgEGMB8GA1Ud -IwQYMBaAFPAXYhNVPbP/CgBr+1CEl/PtYtAaMB0GA1UdDgQWBBSnxxOgegE8ne+C -SIJI1XNRthJWKjAZBgkqhkiG9n0HQQAEDDAKGwRWNy4xAwIAgTANBgkqhkiG9w0B -AQUFAAOBgQBK8bPOaGnjWKNh7bYWyJOxGDA+4HLfTz3iTeG4/D/ByeNFqV2pwdqj -5TbXjtYPrTavbLxE5ppGlKYRoNBS59pVsPYchftjUnu2mY8f4stHZKLrCGXmUdsc -S21/U58eDTGT1DBdHm4BBydgXbvT9ONsHSAPdSozEKe3idepFxQyAw== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEPDCCAySgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvjE/MD0GA1UEAww2VMOc -UktUUlVTVCBFbGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sx -c8SxMQswCQYDVQQGEwJUUjEPMA0GA1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xS -S1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kg -SGl6bWV0bGVyaSBBLsWeLiAoYykgS2FzxLFtIDIwMDUwHhcNMDUxMTA3MTAwNzU3 -WhcNMTUwOTE2MTAwNzU3WjCBvjE/MD0GA1UEAww2VMOcUktUUlVTVCBFbGVrdHJv -bmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJU -UjEPMA0GA1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xSS1RSVVNUIEJpbGdpIMSw -bGV0acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWe -LiAoYykgS2FzxLFtIDIwMDUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB -AQCpNn7DkUNMwxmYCMjHWHtPFoylzkkBH3MOrHUTpvqeLCDe2JAOCtFp0if7qnef -J1Il4std2NiDUBd9irWCPwSOtNXwSadktx4uXyCcUHVPr+G1QRT0mJKIx+XlZEdh -R3n9wFHxwZnn3M5q+6+1ATDcRhzviuyV79z/rxAc653YsKpqhRgNF8k+v/Gb0AmJ -Qv2gQrSdiVFVKc8bcLyEVK3BEx+Y9C52YItdP5qtygy/p1Zbj3e41Z55SZI/4PGX -JHpsmxcPbe9TmJEr5A++WXkHeLuXlfSfadRYhwqp48y2WBmfJiGxxFmNskF1wK1p -zpwACPI2/z7woQ8arBT9pmAPAgMBAAGjQzBBMB0GA1UdDgQWBBTZN7NOBf3Zz58S -Fq62iS/rJTqIHDAPBgNVHQ8BAf8EBQMDBwYAMA8GA1UdEwEB/wQFMAMBAf8wDQYJ -KoZIhvcNAQEFBQADggEBAHJglrfJ3NgpXiOFX7KzLXb7iNcX/nttRbj2hWyfIvwq -ECLsqrkw9qtY1jkQMZkpAL2JZkH7dN6RwRgLn7Vhy506vvWolKMiVW4XSf/SKfE4 -Jl3vpao6+XF75tpYHdN0wgH6PmlYX63LaL4ULptswLbcoCb6dxriJNoaN+BnrdFz -gw2lGh1uEpJ+hGIAF728JRhX8tepb1mIvDS3LoV4nZbcFMMsilKbloxSZj2GFotH -uFEJjOp9zYhys2AzsfAKRO8P9Qk3iCQOLGsgOqL6EfJANZxEaGM7rDNvY7wsu/LS -y3Z9fYjYHcgFHW68lKlmjHdxx/qR+i9Rnuk5UrbnBEI= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICPDCCAaUCEC0b/EoXjaOR6+f/9YtFvgswDQYJKoZIhvcNAQECBQAwXzELMAkG -A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz -cyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2 -MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV -BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAyIFB1YmxpYyBQcmlt -YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN -ADCBiQKBgQC2WoujDWojg4BrzzmH9CETMwZMJaLtVRKXxaeAufqDwSCg+i8VDXyh -YGt+eSz6Bg86rvYbb7HS/y8oUl+DfUvEerf4Zh+AVPy3wo5ZShRXRtGak75BkQO7 -FYCTXOvnzAhsPz6zSvz/S2wj1VCCJkQZjiPDceoZJEcEnnW/yKYAHwIDAQABMA0G -CSqGSIb3DQEBAgUAA4GBAIobK/o5wXTXXtgZZKJYSi034DNHD6zt96rbHuSLBlxg -J8pFUs4W7z8GZOeUaHxgMxURaa+dYo2jA1Rrpr7l7gUYYAS/QoD90KioHgE796Nc -r6Pc5iaAIzy4RHT3Cq5Ji2F4zCS/iIqnDupzGUH9TQPwiNHleI2lKk/2lw0Xd8rY ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIETzCCAzegAwIBAgIEO63vKTANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJQ -TDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2Vu -dHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MRswGQYDVQQDExJDQyBTaWduZXQgLSBS -b290Q0EwHhcNMDEwOTIzMTQxODE3WhcNMTEwOTIzMTMxODE3WjB1MQswCQYDVQQG -EwJQTDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMb -Q2VudHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MR8wHQYDVQQDExZDQyBTaWduZXQg -LSBDQSBLbGFzYSAxMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC4SRW9Q58g -5DY1Hw7hgCRKBEdPdGn0MFHsfw7rlu/oQm7IChI/uWd9q5wwo77YojtTDjRnpgZs -jqBeynX8T90vFILqsY2K5CF1OESalwvVr3sZiQX79lisuFKat92u6hBFikFIVxfH -HB67Af+g7u0dEHdDW7lwy81MwFYxBTRy9wIDAQABo4IBbTCCAWkwDwYDVR0TAQH/ -BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwggEEBgNVHSAEgfwwgfkwgfYGDSsGAQQB -vj8CAQoBAQAwgeQwgZoGCCsGAQUFBwICMIGNGoGKQ2VydHlmaWthdCB3eXN0YXdp -b255IHpnb2RuaWUgeiBkb2t1bWVudGVtOiAiUG9saXR5a2EgQ2VydHlmaWthY2pp -IGRsYSBSb290Q0EiLiBDZXJ0eWZpa2F0IHd5c3Rhd2lvbnkgcHJ6ZXogUm9vdENB -IHcgaGllcmFyY2hpaSBDQyBTaWduZXQuMEUGCCsGAQUFBwIBFjlodHRwOi8vd3d3 -LnNpZ25ldC5wbC9yZXBvenl0b3JpdW0vZG9rdW1lbnR5L3BjX3Jvb3RjYS50eHQw -HwYDVR0jBBgwFoAUwJvFIw0C4aZOSGsfAOnjmhQbsa8wHQYDVR0OBBYEFMODHtVZ -d1T7TftXR/nEI1zR54njMA0GCSqGSIb3DQEBBQUAA4IBAQBRIHQBFIGh8Jpxt87A -gSLwIEEk4+oGy769u3NtoaR0R3WNMdmt7fXTi0tyTQ9V4AIszxVjhnUPaKnF1KYy -f8Tl+YTzk9ZfFkZ3kCdSaILZAOIrmqWNLPmjUQ5/JiMGho0e1YmWUcMci84+pIis -TsytFzVP32/W+sz2H4FQAvOIMmxB7EJX9AdbnXn9EXZ+4nCqi0ft5z96ZqOJJiCB -3vSaoYg+wdkcvb6souMJzuc2uptXtR1Xf3ihlHaGW+hmnpcwFA6AoNrom6Vgzk6U -1ienx0Cw28BhRSKqzKkyXkuK8gRflZUx84uftXncwKJrMiE3lvgOOBITRzcahirL -er4c ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDMDCCAhigAwIBAgICA+gwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCSEsx -FjAUBgNVBAoTDUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3Qg -Um9vdCBDQSAxMB4XDTAzMDUxNTA1MTMxNFoXDTIzMDUxNTA0NTIyOVowRzELMAkG -A1UEBhMCSEsxFjAUBgNVBAoTDUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdr -b25nIFBvc3QgUm9vdCBDQSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC -AQEArP84tulmAknjorThkPlAj3n54r15/gK97iSSHSL22oVyaf7XPwnU3ZG1ApzQ -jVrhVcNQhrkpJsLj2aDxaQMoIIBFIi1WpztUlVYiWR8o3x8gPW2iNr4joLFutbEn -PzlTCeqrauh0ssJlXI6/fMN4hM2eFvz1Lk8gKgifd/PFHsSaUmYeSF7jEAaPIpjh -ZY4bXSNmO7ilMlHIhqqhqZ5/dpTCpmy3QfDVyAY45tQM4vM7TG1QjMSDJ8EThFk9 -nnV0ttgCXjqQesBCNnLsak3c78QA3xMYV18meMjWCnl3v/evt3a5pQuEF10Q6m/h -q5URX208o1xNg1vysxmKgIsLhwIDAQABoyYwJDASBgNVHRMBAf8ECDAGAQH/AgED -MA4GA1UdDwEB/wQEAwIBxjANBgkqhkiG9w0BAQUFAAOCAQEADkbVPK7ih9legYsC -mEEIjEy82tvuJxuC52pF7BaLT4Wg87JwvVqWuspube5Gi27nKi6Wsxkz67SfqLI3 -7piol7Yutmcn1KZJ/RyTZXaeQi/cImyaT/JaFTmxcdcrUehtHJjA2Sr0oYJ71clB -oiMBdDhViw+5LmeiIAQ32pwL0xch4I+XeTRvhEgCIDMb5jREn5Fw9IBehEPCKdJs -EhTkYY2sEJCehFC78JZvRZ+K88psT/oROhUVRsPNH4NbLUES7VBnQRM9IauUiqpO -fMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilTc4afU9hDDl3WY4JxHYB0yvbi -AmvZWg== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCB -lzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug -Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho -dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3Qt -SGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgxOTIyWjCBlzELMAkG -A1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEe -MBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8v -d3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdh -cmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn -0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlIwrthdBKWHTxqctU8EGc6Oe0rE81m65UJ -M6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFdtqdt++BxF2uiiPsA3/4a -MXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8i4fDidNd -oI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqI -DsjfPe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9Ksy -oUhbAgMBAAGjgbkwgbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYD -VR0OBBYEFKFyXyYbKJhDlV0HN9WFlp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0 -dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZpcnN0LUhhcmR3YXJlLmNy -bDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEF -BQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM -//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28Gpgoiskli -CE7/yMgUsogWXecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gE -CJChicsZUN/KHAG8HQQZexB2lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t -3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kniCrVWFCVH/A7HFe7fRQ5YiuayZSS -KqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67nfhmqA== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIECTCCAvGgAwIBAgIQDV6ZCtadt3js2AdWO4YV2TANBgkqhkiG9w0BAQUFADBb -MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3Qx -ETAPBgNVBAsTCERTVCBBQ0VTMRcwFQYDVQQDEw5EU1QgQUNFUyBDQSBYNjAeFw0w -MzExMjAyMTE5NThaFw0xNzExMjAyMTE5NThaMFsxCzAJBgNVBAYTAlVTMSAwHgYD -VQQKExdEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdDERMA8GA1UECxMIRFNUIEFDRVMx -FzAVBgNVBAMTDkRTVCBBQ0VTIENBIFg2MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A -MIIBCgKCAQEAuT31LMmU3HWKlV1j6IR3dma5WZFcRt2SPp/5DgO0PWGSvSMmtWPu -ktKe1jzIDZBfZIGxqAgNTNj50wUoUrQBJcWVHAx+PhCEdc/BGZFjz+iokYi5Q1K7 -gLFViYsx+tC3dr5BPTCapCIlF3PoHuLTrCq9Wzgh1SpL11V94zpVvddtawJXa+ZH -fAjIgrrep4c9oW24MFbCswKBXy314powGCi4ZtPLAZZv6opFVdbgnf9nKxcCpk4a -ahELfrd755jWjHZvwTvbUJN+5dCOHze4vbrGn2zpfDPyMjwmR/onJALJfh1biEIT -ajV8fTXpLmaRcpPVMibEdPVTo7NdmvYJywIDAQABo4HIMIHFMA8GA1UdEwEB/wQF -MAMBAf8wDgYDVR0PAQH/BAQDAgHGMB8GA1UdEQQYMBaBFHBraS1vcHNAdHJ1c3Rk -c3QuY29tMGIGA1UdIARbMFkwVwYKYIZIAWUDAgEBATBJMEcGCCsGAQUFBwIBFjto -dHRwOi8vd3d3LnRydXN0ZHN0LmNvbS9jZXJ0aWZpY2F0ZXMvcG9saWN5L0FDRVMt -aW5kZXguaHRtbDAdBgNVHQ4EFgQUCXIGThhDD+XWzMNqizF7eI+og7gwDQYJKoZI -hvcNAQEFBQADggEBAKPYjtay284F5zLNAdMEA+V25FYrnJmQ6AgwbN99Pe7lv7Uk -QIRJ4dEorsTCOlMwiPH1d25Ryvr/ma8kXxug/fKshMrfqfBfBC6tFr8hlxCBPeP/ -h40y3JTlR4peahPJlJU90u7INJXQgNStMgiAVDzgvVJT11J8smk/f3rPanTK+gQq -nExaBqXpIK1FZg9p8d2/6eMyi/rgwYZNcjwu2JN4Cir42NInPRmJX1p7ijvMDNpR -rscL9yuwNwXsvFcj4jjSm2jzVhKIT0J8uDHEtdvkyCE06UgRNe76x5JXxZ805Mf2 -9w4LTJxoeHtxMcfrHuBnQfO3oKfN5XozNmr6mis= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIH9zCCB2CgAwIBAgIBADANBgkqhkiG9w0BAQUFADCCARwxCzAJBgNVBAYTAkVT -MRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UE -ChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5sLjErMCkGA1UE -ChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1MjEzMDEGA1UECxMq -SVBTIENBIENoYWluZWQgQ0FzIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MTMwMQYD -VQQDEypJUFMgQ0EgQ2hhaW5lZCBDQXMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkx -HjAcBgkqhkiG9w0BCQEWD2lwc0BtYWlsLmlwcy5lczAeFw0wMTEyMjkwMDUzNTha -Fw0yNTEyMjcwMDUzNThaMIIBHDELMAkGA1UEBhMCRVMxEjAQBgNVBAgTCUJhcmNl -bG9uYTESMBAGA1UEBxMJQmFyY2Vsb25hMS4wLAYDVQQKEyVJUFMgSW50ZXJuZXQg -cHVibGlzaGluZyBTZXJ2aWNlcyBzLmwuMSswKQYDVQQKFCJpcHNAbWFpbC5pcHMu -ZXMgQy5JLkYuICBCLTYwOTI5NDUyMTMwMQYDVQQLEypJUFMgQ0EgQ2hhaW5lZCBD -QXMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxMzAxBgNVBAMTKklQUyBDQSBDaGFp -bmVkIENBcyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEeMBwGCSqGSIb3DQEJARYP -aXBzQG1haWwuaXBzLmVzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDcVpJJ -spQgvJhPUOtopKdJC7/SMejHT8KGC/po/UNaivNgkjWZOLtNA1IhW/A3mTXhQSCB -hYEFcYGdtJUZqV92NC5jNzVXjrQfQj8VXOF6wV8TGDIxya2+o8eDZh65nAQTy2nB -Bt4wBrszo7Uf8I9vzv+W6FS+ZoCua9tBhDaiPQIDAQABo4IEQzCCBD8wHQYDVR0O -BBYEFKGtMbH5PuEXpsirNPxShwkeYlJBMIIBTgYDVR0jBIIBRTCCAUGAFKGtMbH5 -PuEXpsirNPxShwkeYlJBoYIBJKSCASAwggEcMQswCQYDVQQGEwJFUzESMBAGA1UE -CBMJQmFyY2Vsb25hMRIwEAYDVQQHEwlCYXJjZWxvbmExLjAsBgNVBAoTJUlQUyBJ -bnRlcm5ldCBwdWJsaXNoaW5nIFNlcnZpY2VzIHMubC4xKzApBgNVBAoUImlwc0Bt -YWlsLmlwcy5lcyBDLkkuRi4gIEItNjA5Mjk0NTIxMzAxBgNVBAsTKklQUyBDQSBD -aGFpbmVkIENBcyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEzMDEGA1UEAxMqSVBT -IENBIENoYWluZWQgQ0FzIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MR4wHAYJKoZI -hvcNAQkBFg9pcHNAbWFpbC5pcHMuZXOCAQAwDAYDVR0TBAUwAwEB/zAMBgNVHQ8E -BQMDB/+AMGsGA1UdJQRkMGIGCCsGAQUFBwMBBggrBgEFBQcDAgYIKwYBBQUHAwMG -CCsGAQUFBwMEBggrBgEFBQcDCAYKKwYBBAGCNwIBFQYKKwYBBAGCNwIBFgYKKwYB -BAGCNwoDAQYKKwYBBAGCNwoDBDARBglghkgBhvhCAQEEBAMCAAcwGgYDVR0RBBMw -EYEPaXBzQG1haWwuaXBzLmVzMBoGA1UdEgQTMBGBD2lwc0BtYWlsLmlwcy5lczBC -BglghkgBhvhCAQ0ENRYzQ2hhaW5lZCBDQSBDZXJ0aWZpY2F0ZSBpc3N1ZWQgYnkg -aHR0cDovL3d3dy5pcHMuZXMvMCkGCWCGSAGG+EIBAgQcFhpodHRwOi8vd3d3Lmlw -cy5lcy9pcHMyMDAyLzA3BglghkgBhvhCAQQEKhYoaHR0cDovL3d3dy5pcHMuZXMv -aXBzMjAwMi9pcHMyMDAyQ0FDLmNybDA8BglghkgBhvhCAQMELxYtaHR0cDovL3d3 -dy5pcHMuZXMvaXBzMjAwMi9yZXZvY2F0aW9uQ0FDLmh0bWw/MDkGCWCGSAGG+EIB -BwQsFipodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL3JlbmV3YWxDQUMuaHRtbD8w -NwYJYIZIAYb4QgEIBCoWKGh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvcG9saWN5 -Q0FDLmh0bWwwbQYDVR0fBGYwZDAuoCygKoYoaHR0cDovL3d3dy5pcHMuZXMvaXBz -MjAwMi9pcHMyMDAyQ0FDLmNybDAyoDCgLoYsaHR0cDovL3d3d2JhY2suaXBzLmVz -L2lwczIwMDIvaXBzMjAwMkNBQy5jcmwwLwYIKwYBBQUHAQEEIzAhMB8GCCsGAQUF -BzABhhNodHRwOi8vb2NzcC5pcHMuZXMvMA0GCSqGSIb3DQEBBQUAA4GBAERyMJ1W -WKJBGyi3leGmGpVfp3hAK+/blkr8THFj2XOVvQLiogbHvpcqk4A0hgP63Ng9HgfN -HnNDJGD1HWHc3JagvPsd4+cSACczAsDAK1M92GsDgaPb1pOVIO/Tln4mkImcJpvN -b2ar7QMiRDjMWb2f2/YHogF/JsRj9SVCXmK9 ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUFADBr -MQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRl -cm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNv -bW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2WhcNMjIwNjI0MDAxNjEyWjBrMQsw -CQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5h -dGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNvbW1l -cmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvV95WHm6h -2mCxlCfLF9sHP4CFT8icttD0b0/Pmdjh28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4E -lpF7sDPwsRROEW+1QK8bRaVK7362rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdV -ZqW1LS7YgFmypw23RuwhY/81q6UCzyr0TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq -299yOIzzlr3xF7zSujtFWsan9sYXiwGd/BmoKoMWuDpI/k4+oKsGGelT84ATB+0t -vz8KPFUgOSwsAGl0lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzsGHxBvfaL -dXe6YJ2E5/4tAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD -AgEGMB0GA1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUF -AAOCAQEAX/FBfXxcCLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcR -zCSs00Rsca4BIGsDoo8Ytyk6feUWYFN4PMCvFYP3j1IzJL1kk5fui/fbGKhtcbP3 -LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pzzkWKsKZJ/0x9nXGIxHYdkFsd -7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBuYQa7FkKMcPcw -++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/hC3euiInlhBx6yLt -398znM/jra6O1I7mT1GvFpLgXPYHDw== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIH8jCCB1ugAwIBAgIBADANBgkqhkiG9w0BAQUFADCCARIxCzAJBgNVBAYTAkVT -MRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UE -ChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5sLjErMCkGA1UE -ChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1MjEuMCwGA1UECxMl -SVBTIENBIENMQVNFMyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEuMCwGA1UEAxMl -SVBTIENBIENMQVNFMyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEeMBwGCSqGSIb3 -DQEJARYPaXBzQG1haWwuaXBzLmVzMB4XDTAxMTIzMTExMTkzMVoXDTI1MTIyOTEx -MTkzMVowggESMQswCQYDVQQGEwJFUzESMBAGA1UECBMJQmFyY2Vsb25hMRIwEAYD -VQQHEwlCYXJjZWxvbmExLjAsBgNVBAoTJUlQUyBJbnRlcm5ldCBwdWJsaXNoaW5n -IFNlcnZpY2VzIHMubC4xKzApBgNVBAoUImlwc0BtYWlsLmlwcy5lcyBDLkkuRi4g -IEItNjA5Mjk0NTIxLjAsBgNVBAsTJUlQUyBDQSBDTEFTRTMgQ2VydGlmaWNhdGlv -biBBdXRob3JpdHkxLjAsBgNVBAMTJUlQUyBDQSBDTEFTRTMgQ2VydGlmaWNhdGlv -biBBdXRob3JpdHkxHjAcBgkqhkiG9w0BCQEWD2lwc0BtYWlsLmlwcy5lczCBnzAN -BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAve2QhYLxoN2P3DVo4Xw+6Gyb2vDjfzvB -JRvH+WFIXO3KItC1dJk2W7iFnsZJnb65Q6NDKxhwfQ4XnLuBSPqMVJ6EHB++I1p2 -pg0j7YOtec++o3ysS6zf1r01HSh8i85+AcGcgLO4Z79w9jtEGlSdrFhCLUjJJSEs -XdzSbkEFrkMCAwEAAaOCBFIwggROMB0GA1UdDgQWBBT7o4z3Z4tAqk02rzCA6po7 -4C9o6DCCAUQGA1UdIwSCATswggE3gBT7o4z3Z4tAqk02rzCA6po74C9o6KGCARqk -ggEWMIIBEjELMAkGA1UEBhMCRVMxEjAQBgNVBAgTCUJhcmNlbG9uYTESMBAGA1UE -BxMJQmFyY2Vsb25hMS4wLAYDVQQKEyVJUFMgSW50ZXJuZXQgcHVibGlzaGluZyBT -ZXJ2aWNlcyBzLmwuMSswKQYDVQQKFCJpcHNAbWFpbC5pcHMuZXMgQy5JLkYuICBC -LTYwOTI5NDUyMS4wLAYDVQQLEyVJUFMgQ0EgQ0xBU0UzIENlcnRpZmljYXRpb24g -QXV0aG9yaXR5MS4wLAYDVQQDEyVJUFMgQ0EgQ0xBU0UzIENlcnRpZmljYXRpb24g -QXV0aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXOCAQAwDAYD -VR0TBAUwAwEB/zAMBgNVHQ8EBQMDB/+AMGsGA1UdJQRkMGIGCCsGAQUFBwMBBggr -BgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYKKwYBBAGCNwIB -FQYKKwYBBAGCNwIBFgYKKwYBBAGCNwoDAQYKKwYBBAGCNwoDBDARBglghkgBhvhC -AQEEBAMCAAcwGgYDVR0RBBMwEYEPaXBzQG1haWwuaXBzLmVzMBoGA1UdEgQTMBGB -D2lwc0BtYWlsLmlwcy5lczBCBglghkgBhvhCAQ0ENRYzQ0xBU0UzIENBIENlcnRp -ZmljYXRlIGlzc3VlZCBieSBodHRwczovL3d3dy5pcHMuZXMvMCoGCWCGSAGG+EIB -AgQdFhtodHRwczovL3d3dy5pcHMuZXMvaXBzMjAwMi8wOwYJYIZIAYb4QgEEBC4W -LGh0dHBzOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL2lwczIwMDJDTEFTRTMuY3JsMEAG -CWCGSAGG+EIBAwQzFjFodHRwczovL3d3dy5pcHMuZXMvaXBzMjAwMi9yZXZvY2F0 -aW9uQ0xBU0UzLmh0bWw/MD0GCWCGSAGG+EIBBwQwFi5odHRwczovL3d3dy5pcHMu -ZXMvaXBzMjAwMi9yZW5ld2FsQ0xBU0UzLmh0bWw/MDsGCWCGSAGG+EIBCAQuFixo -dHRwczovL3d3dy5pcHMuZXMvaXBzMjAwMi9wb2xpY3lDTEFTRTMuaHRtbDB1BgNV -HR8EbjBsMDKgMKAuhixodHRwczovL3d3dy5pcHMuZXMvaXBzMjAwMi9pcHMyMDAy -Q0xBU0UzLmNybDA2oDSgMoYwaHR0cHM6Ly93d3diYWNrLmlwcy5lcy9pcHMyMDAy -L2lwczIwMDJDTEFTRTMuY3JsMC8GCCsGAQUFBwEBBCMwITAfBggrBgEFBQcwAYYT -aHR0cDovL29jc3AuaXBzLmVzLzANBgkqhkiG9w0BAQUFAAOBgQAiu2FuR8MoQlYw -3QtFc/BI7DgkUUeSIM49JoMU0H3a4Y+JbQxQ4q/n6yAbEuMETUyqob/HmS/NkLJq -ur3RvGBseDXgxNyePGjFc97ITNWf5X1+4CXtBf+TTKNEMg1UpPbCz+9EkjzTcYj1 -5tjLbAp/mmLLZmCOV7cCGuXGSTBNzA== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIG0zCCBbugAwIBAgIBADANBgkqhkiG9w0BAQUFADCBzDELMAkGA1UEBhMCQVQx -EDAOBgNVBAgTB0F1c3RyaWExDzANBgNVBAcTBlZpZW5uYTE6MDgGA1UEChMxQVJH -RSBEQVRFTiAtIEF1c3RyaWFuIFNvY2lldHkgZm9yIERhdGEgUHJvdGVjdGlvbjEl -MCMGA1UECxMcQS1DRVJUIENlcnRpZmljYXRpb24gU2VydmljZTEYMBYGA1UEAxMP -QS1DRVJUIEFEVkFOQ0VEMR0wGwYJKoZIhvcNAQkBFg5pbmZvQGEtY2VydC5hdDAe -Fw0wNDEwMjMxNDE0MTRaFw0xMTEwMjMxNDE0MTRaMIHMMQswCQYDVQQGEwJBVDEQ -MA4GA1UECBMHQXVzdHJpYTEPMA0GA1UEBxMGVmllbm5hMTowOAYDVQQKEzFBUkdF -IERBVEVOIC0gQXVzdHJpYW4gU29jaWV0eSBmb3IgRGF0YSBQcm90ZWN0aW9uMSUw -IwYDVQQLExxBLUNFUlQgQ2VydGlmaWNhdGlvbiBTZXJ2aWNlMRgwFgYDVQQDEw9B -LUNFUlQgQURWQU5DRUQxHTAbBgkqhkiG9w0BCQEWDmluZm9AYS1jZXJ0LmF0MIIB -IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3euXIy+mnf6BYKbK+QH5k679 -tUFqeT8jlZxMew8eNiHuw9KoxWBzL6KksK+5uK7Gatw+sbAYntEGE80P+Jg1hADM -e+Fr5V0bc6QS3gkVtfUCW/RIvfMM39oxvmqJmOgPnJU7H6+nmLtsq61tv9kVJi/2 -4Y5wXW3odet72sF57EoG6s78w0BUVLNcMngS9bZZzmdG3/d6JbkGgoNF/8DcgCBJ -W/t0JrcIzyppXIOVtUzzOrrU86zuUgT3Rtkl5kjG7DEHpFb9H0fTOY1v8+gRoaO6 -2gA0PCiysgVZjwgVeYe3KAg11nznyleDv198uK3Dc1oXIGYjJx2FpKWUvAuAEwID -AQABo4ICvDCCArgwHQYDVR0OBBYEFDd/Pj6ZcWDKJNSRE3nQdCm0qCTYMIH5BgNV -HSMEgfEwge6AFDd/Pj6ZcWDKJNSRE3nQdCm0qCTYoYHSpIHPMIHMMQswCQYDVQQG -EwJBVDEQMA4GA1UECBMHQXVzdHJpYTEPMA0GA1UEBxMGVmllbm5hMTowOAYDVQQK -EzFBUkdFIERBVEVOIC0gQXVzdHJpYW4gU29jaWV0eSBmb3IgRGF0YSBQcm90ZWN0 -aW9uMSUwIwYDVQQLExxBLUNFUlQgQ2VydGlmaWNhdGlvbiBTZXJ2aWNlMRgwFgYD -VQQDEw9BLUNFUlQgQURWQU5DRUQxHTAbBgkqhkiG9w0BCQEWDmluZm9AYS1jZXJ0 -LmF0ggEAMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgHmMEcGA1UdJQRAMD4G -CCsGAQUFBwMBBggrBgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEFBQcD -CAYKKwYBBAGCNwoDBDARBglghkgBhvhCAQEEBAMCAP8wUQYDVR0gBEowSDBGBggq -KAAYAQEBAzA6MDgGCCsGAQUFBwIBFixodHRwOi8vd3d3LmEtY2VydC5hdC9jZXJ0 -aWZpY2F0ZS1wb2xpY3kuaHRtbDA7BglghkgBhvhCAQgELhYsaHR0cDovL3d3dy5h -LWNlcnQuYXQvY2VydGlmaWNhdGUtcG9saWN5Lmh0bWwwGQYDVR0RBBIwEIEOaW5m -b0BhLWNlcnQuYXQwLwYDVR0SBCgwJoEOaW5mb0BhLWNlcnQuYXSGFGh0dHA6Ly93 -d3cuYS1jZXJ0LmF0MEUGA1UdHwQ+MDwwOqA4oDaGNGh0dHBzOi8vc2VjdXJlLmEt -Y2VydC5hdC9jZ2ktYmluL2EtY2VydC1hZHZhbmNlZC5jZ2kwDQYJKoZIhvcNAQEF -BQADggEBACX1IvgfdG2rvfv35O48vSEvcVaEdlN8USFBHWz3JRAozgzvaBtwHkjK -Zwt5l/BWOtjbvHfRjDt7ijlBEcxOOrNC1ffyMHwHrXpvff6YpQ5wnxmIYEQcURiG -HMqruEX0WkuDNgSKwefsgXs27eeBauHgNGVcTYH1rmHu/ZyLpLxOyJQ2PCzA1DzW -3rWkIX92ogJ7lTRdWrbxwUL1XGinxnnaQ74+/y0pI9JNEv7ic2tpkweRMpkedaLW -msC1+orfKTebsg69aMaCx7o6jNONRmR/7TVaPf8/k6g52cHZ9YWjQvup22b5rWxG -J5r5LZ4vCPmF4+T4lutjUYAa/lGuQTg= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDDDCCAfSgAwIBAgIDAQAgMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBM -MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD -QTAeFw0wMjA2MTExMDQ2MzlaFw0yNzA2MTExMDQ2MzlaMD4xCzAJBgNVBAYTAlBM -MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD -QTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6xwS7TT3zNJc4YPk/E -jG+AanPIW1H4m9LcuwBcsaD8dQPugfCI7iNS6eYVM42sLQnFdvkrOYCJ5JdLkKWo -ePhzQ3ukYbDYWMzhbGZ+nPMJXlVjhNWo7/OxLjBos8Q82KxujZlakE403Daaj4GI -ULdtlkIJ89eVgw1BS7Bqa/j8D35in2fE7SZfECYPCE/wpFcozo+47UX2bu4lXapu -Ob7kky/ZR6By6/qmW6/KUz/iDsaWVhFu9+lmqSbYf5VT7QqFiLpPKaVCjF62/IUg -AKpoC6EahQGcxEZjgoi2IrHu/qpGWX7PNSzVttpd90gzFFS269lvzs2I1qsb2pY7 -HVkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEA -uI3O7+cUus/usESSbLQ5PqKEbq24IXfS1HeCh+YgQYHu4vgRt2PRFze+GXYkHAQa -TOs9qmdvLdTN/mUxcMUbpgIKumB7bVjCmkn+YzILa+M6wKyrO7Do0wlRjBCDxjTg -xSvgGrZgFCdsMneMvLJymM/NzD+5yCRCFNZX/OYmQ6kd5YCQzgNUKD73P9P4Te1q -CjqTE5s7FCMTY5w/0YcneeVMUeMBrYVdGjux1XMQpNPyvG5k9VpWkKjHDkx0Dy5x -O/fIR/RpbxXyEV6DHpx8Uq79AtoSqFlnGNu8cN2bsWntgM6JQEhqDjXKKWYVIZQs -6GAqm4VKQPNriiTsBhYscw== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j -ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL -MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 -LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug -RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm -+9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW -PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM -xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB -Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3 -hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg -EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF -MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA -FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec -nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z -eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF -hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2 -Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe -vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep -+OkuE6N36B9K ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIGfTCCBWWgAwIBAgICAQMwDQYJKoZIhvcNAQEEBQAwga8xCzAJBgNVBAYTAkhV -MRAwDgYDVQQIEwdIdW5nYXJ5MREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMe -TmV0TG9jayBIYWxvemF0Yml6dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0 -dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9jayBLb3pqZWd5em9pIChDbGFzcyBB -KSBUYW51c2l0dmFueWtpYWRvMB4XDTk5MDIyNDIzMTQ0N1oXDTE5MDIxOTIzMTQ0 -N1owga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQIEwdIdW5nYXJ5MREwDwYDVQQHEwhC -dWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6dG9uc2FnaSBLZnQu -MRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9jayBL -b3pqZWd5em9pIChDbGFzcyBBKSBUYW51c2l0dmFueWtpYWRvMIIBIjANBgkqhkiG -9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvHSMD7tM9DceqQWC2ObhbHDqeLVu0ThEDaiD -zl3S1tWBxdRL51uUcCbbO51qTGL3cfNk1mE7PetzozfZz+qMkjvN9wfcZnSX9EUi -3fRc4L9t875lM+QVOr/bmJBVOMTtplVjC7B4BPTjbsE/jvxReB+SnoPC/tmwqcm8 -WgD/qaiYdPv2LD4VOQ22BFWoDpggQrOxJa1+mm9dU7GrDPzr4PN6s6iz/0b2Y6LY -Oph7tqyF/7AlT3Rj5xMHpQqPBffAZG9+pyeAlt7ULoZgx2srXnN7F+eRP2QM2Esi -NCubMvJIH5+hCoR64sKtlz2O1cH5VqNQ6ca0+pii7pXmKgOM3wIDAQABo4ICnzCC -ApswDgYDVR0PAQH/BAQDAgAGMBIGA1UdEwEB/wQIMAYBAf8CAQQwEQYJYIZIAYb4 -QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaCAk1GSUdZRUxFTSEgRXplbiB0 -YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFub3MgU3pvbGdhbHRhdGFz -aSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBhbGFwamFuIGtlc3p1bHQu -IEEgaGl0ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExvY2sgS2Z0LiB0ZXJtZWtm -ZWxlbG9zc2VnLWJpenRvc2l0YXNhIHZlZGkuIEEgZGlnaXRhbGlzIGFsYWlyYXMg -ZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUgYXogZWxvaXJ0IGVsbGVub3J6ZXNpIGVs -amFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFzIGxlaXJhc2EgbWVndGFsYWxoYXRv -IGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGphbiBhIGh0dHBzOi8vd3d3 -Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJoZXRvIGF6IGVsbGVub3J6 -ZXNAbmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBPUlRBTlQhIFRoZSBpc3N1 -YW5jZSBhbmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3Qg -dG8gdGhlIE5ldExvY2sgQ1BTIGF2YWlsYWJsZSBhdCBodHRwczovL3d3dy5uZXRs -b2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFpbCBhdCBjcHNAbmV0bG9jay5uZXQuMA0G -CSqGSIb3DQEBBAUAA4IBAQBIJEb3ulZv+sgoA0BO5TE5ayZrU3/b39/zcT0mwBQO -xmd7I6gMc90Bu8bKbjc5VdXHjFYgDigKDtIqpLBJUsY4B/6+CgmM0ZjPytoUMaFP -0jn8DxEsQ8Pdq5PHVT5HfBgaANzze9jyf1JsIPQLX2lS9O74silg6+NJMSEN1rUQ -QeJBCWziGppWS3cC9qCbmieH6FUpccKQn0V4GuEVZD3QDtigdp+uxdAu6tYPVuxk -f1qbFFgBJ34TUMdrKuZoPL9coAob4Q566eKAw+np9v1sEZ7Q5SgnK1QyQhSCdeZK -8CtmdWOMovsEPoMOmzbwGOQmIMOM8CgHrTwXZoi1/baI ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDAjCCAmsCEEzH6qqYPnHTkxD4PTqJkZIwDQYJKoZIhvcNAQEFBQAwgcExCzAJ -BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh -c3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy -MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp -emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X -DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw -FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMSBQdWJsaWMg -UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo -YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5 -MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB -AQUAA4GNADCBiQKBgQCq0Lq+Fi24g9TK0g+8djHKlNgdk4xWArzZbxpvUjZudVYK -VdPfQ4chEWWKfo+9Id5rMj8bhDSVBZ1BNeuS65bdqlk/AVNtmU/t5eIqWpDBucSm -Fc/IReumXY6cPvBkJHalzasab7bYe1FhbqZ/h8jit+U03EGI6glAvnOSPWvndQID -AQABMA0GCSqGSIb3DQEBBQUAA4GBAKlPww3HZ74sy9mozS11534Vnjty637rXC0J -h9ZrbWB85a7FkCMMXErQr7Fd88e2CtvgFZMN3QO8x3aKtd1Pw5sTdbgBwObJW2ul -uIncrKTdcu1OofdPvAbT6shkdHvClUGcZXNY8ZCaPGqxmMnEh7zPRW1F4m4iP/68 -DzFc6PLZ ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFGjCCBAKgAwIBAgIEPV0tNDANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJQ -TDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2Vu -dHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MRswGQYDVQQDExJDQyBTaWduZXQgLSBS -b290Q0EwHhcNMDIwODE2MTY0OTU2WhcNMjYwOTIxMTU0MjE5WjB2MQswCQYDVQQG -EwJQTDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMb -Q2VudHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MSAwHgYDVQQDExdDQyBTaWduZXQg -LSBQQ0EgS2xhc2EgMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALN3 -LanJtdueNe6geWUTFENa+lEuzqELcoqhYB+a/tJcPEkc6TX/bYPzalRRjqs+quMP -6KZTU0DixOrV+K7iWaqAiQ913HX5IBLmKDCrTVW/ZvSDpiBKbxlHfSNuJxAuVT6H -dbzK7yAW38ssX+yS2tZYHZ5FhZcfqzPEOpO94mAKcBUhk6T/ki0evXX/ZvvktwmF -3hKattzwtM4JMLurAEl8SInyEYULw5JdlfcBez2Tg6Dbw34hA1A+ckTwhxzecrB8 -TUe2BnQKOs9vr2cCACpFFcOmPkM0Drtjctr1QHm1tYSqRFRf9VcV5tfC3P8QqoK4 -ONjtLPHc9x5NE1uK/FMCAwEAAaOCAbMwggGvMA8GA1UdEwEB/wQFMAMBAf8wDgYD -VR0PAQH/BAQDAgEGMIIBBAYDVR0gBIH8MIH5MIH2Bg0rBgEEAb4/AgEKAQECMIHk -MIGaBggrBgEFBQcCAjCBjRqBikNlcnR5ZmlrYXQgd3lzdGF3aW9ueSB6Z29kbmll -IHogZG9rdW1lbnRlbTogIlBvbGl0eWthIENlcnR5ZmlrYWNqaSBkbGEgUm9vdENB -Ii4gQ2VydHlmaWthdCB3eXN0YXdpb255IHByemV6IFJvb3RDQSB3IGhpZXJhcmNo -aWkgQ0MgU2lnbmV0LjBFBggrBgEFBQcCARY5aHR0cDovL3d3dy5zaWduZXQucGwv -cmVwb3p5dG9yaXVtL2Rva3VtZW50eS9wY19yb290Y2EudHh0MEQGA1UdHwQ9MDsw -OaA3oDWGM2h0dHA6Ly93d3cuc2lnbmV0LnBsL3JlcG96eXRvcml1bS9yb290Y2Ev -cm9vdGNhLmNybDAfBgNVHSMEGDAWgBTAm8UjDQLhpk5Iax8A6eOaFBuxrzAdBgNV -HQ4EFgQUXvthcPHlH5BgGhlMErJNXWlhlgAwDQYJKoZIhvcNAQEFBQADggEBACIc -e95Mvn710KCAISA0CuHD4aznTU6pLoCDShW47OR+GTpJUm1coTcUqlBHV9mra4VF -rBcBuOkHZoBLq/jmE0QJWnpSEULDcH9J3mF0nqO9SM+mWyJGdsJF/XU/7smummgj -MNQXwzQTtWORF+6v5KUbWX85anO2wR+M6YTBWC55zWpWi4RG3vkHFs5Ze2oFJTlp -uxw9ZgxTnWlwI9QR2MvEhYIUMKMOWxw1nt0kKj+5TCNQQGh/VJJ1dsiroGh/io1D -OcePEhKz1Ag52y6Wf0nJJB9yk0sFakqZH18F7eQecQImgZyyeRtsG95leNugB3BX -WCW+KxwiBrtQTXv4dTE= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEAjCCAuqgAwIBAgIFORFFEJQwDQYJKoZIhvcNAQEFBQAwgYUxCzAJBgNVBAYT -AkZSMQ8wDQYDVQQIEwZGcmFuY2UxDjAMBgNVBAcTBVBhcmlzMRAwDgYDVQQKEwdQ -TS9TR0ROMQ4wDAYDVQQLEwVEQ1NTSTEOMAwGA1UEAxMFSUdDL0ExIzAhBgkqhkiG -9w0BCQEWFGlnY2FAc2dkbi5wbS5nb3V2LmZyMB4XDTAyMTIxMzE0MjkyM1oXDTIw -MTAxNzE0MjkyMlowgYUxCzAJBgNVBAYTAkZSMQ8wDQYDVQQIEwZGcmFuY2UxDjAM -BgNVBAcTBVBhcmlzMRAwDgYDVQQKEwdQTS9TR0ROMQ4wDAYDVQQLEwVEQ1NTSTEO -MAwGA1UEAxMFSUdDL0ExIzAhBgkqhkiG9w0BCQEWFGlnY2FAc2dkbi5wbS5nb3V2 -LmZyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsh/R0GLFMzvABIaI -s9z4iPf930Pfeo2aSVz2TqrMHLmh6yeJ8kbpO0px1R2OLc/mratjUMdUC24SyZA2 -xtgv2pGqaMVy/hcKshd+ebUyiHDKcMCWSo7kVc0dJ5S/znIq7Fz5cyD+vfcuiWe4 -u0dzEvfRNWk68gq5rv9GQkaiv6GFGvm/5P9JhfejcIYyHF2fYPepraX/z9E0+X1b -F8bc1g4oa8Ld8fUzaJ1O/Id8NhLWo4DoQw1VYZTqZDdH6nfK0LJYBcNdfrGoRpAx -Vs5wKpayMLh35nnAvSk7/ZR3TL0gzUEl4C7HG7vupARB0l2tEmqKm0f7yd1GQOGd -PDPQtQIDAQABo3cwdTAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBRjAVBgNV -HSAEDjAMMAoGCCqBegF5AQEBMB0GA1UdDgQWBBSjBS8YYFDCiQrdKyFP/45OqDAx -NjAfBgNVHSMEGDAWgBSjBS8YYFDCiQrdKyFP/45OqDAxNjANBgkqhkiG9w0BAQUF -AAOCAQEABdwm2Pp3FURo/C9mOnTgXeQp/wYHE4RKq89toB9RlPhJy3Q2FLwV3duJ -L92PoF189RLrn544pEfMs5bZvpwlqwN+Mw+VgQ39FuCIvjfwbF3QMZsyK10XZZOY -YLxuj7GoPB7ZHPOpJkL5ZB3C55L29B5aqhlSXa/oovdgoPaN8In1buAKBQGVyYsg -Crpa/JosPL3Dt8ldeCUFP1YUmwza+zpI/pdpXsoQhvdOlgQITeywvl3cO45Pwf2a -NjSaTFR+FwNIlQgRHAdvhQh+XU3Endv7rs6y0bO4g2wdsrN58dhwmX7wEwLOXt1R -0982gaEbeC9xs/FZTEYYKKuF0mBWWg== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIH/zCCB2igAwIBAgIBADANBgkqhkiG9w0BAQUFADCCARwxCzAJBgNVBAYTAkVT -MRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UE -ChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5sLjErMCkGA1UE -ChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1MjEzMDEGA1UECxMq -SVBTIENBIENoYWluZWQgQ0FzIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MTMwMQYD -VQQDEypJUFMgQ0EgQ2hhaW5lZCBDQXMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkx -HjAcBgkqhkiG9w0BCQEWD2lwc0BtYWlsLmlwcy5lczAeFw0wMTEyMzExMTE0NTRa -Fw0yNTEyMjkxMTE0NTRaMIIBHDELMAkGA1UEBhMCRVMxEjAQBgNVBAgTCUJhcmNl -bG9uYTESMBAGA1UEBxMJQmFyY2Vsb25hMS4wLAYDVQQKEyVJUFMgSW50ZXJuZXQg -cHVibGlzaGluZyBTZXJ2aWNlcyBzLmwuMSswKQYDVQQKFCJpcHNAbWFpbC5pcHMu -ZXMgQy5JLkYuICBCLTYwOTI5NDUyMTMwMQYDVQQLEypJUFMgQ0EgQ2hhaW5lZCBD -QXMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxMzAxBgNVBAMTKklQUyBDQSBDaGFp -bmVkIENBcyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEeMBwGCSqGSIb3DQEJARYP -aXBzQG1haWwuaXBzLmVzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCpOZZJ -iHAzKHzoV9xIki3eLXp56UjxFehnY+c+Dh1nUiVO0t//vmGMP6B2LTFfx9FBKRBi -kYcW7raIcSDi62Or0sAG5UUgG4ruGLE7XtCnnx4xjgbFZ4tTjdgi5Wh9GVhfP7Oo -9ahi8Eqao+alFbhvB6LD3xZZqM2j9cmD8GzYAQIDAQABo4IESzCCBEcwHQYDVR0O -BBYEFAeUqHBsCqTumbhV3S5MRXf2Nq+5MIIBTgYDVR0jBIIBRTCCAUGAFAeUqHBs -CqTumbhV3S5MRXf2Nq+5oYIBJKSCASAwggEcMQswCQYDVQQGEwJFUzESMBAGA1UE -CBMJQmFyY2Vsb25hMRIwEAYDVQQHEwlCYXJjZWxvbmExLjAsBgNVBAoTJUlQUyBJ -bnRlcm5ldCBwdWJsaXNoaW5nIFNlcnZpY2VzIHMubC4xKzApBgNVBAoUImlwc0Bt -YWlsLmlwcy5lcyBDLkkuRi4gIEItNjA5Mjk0NTIxMzAxBgNVBAsTKklQUyBDQSBD -aGFpbmVkIENBcyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEzMDEGA1UEAxMqSVBT -IENBIENoYWluZWQgQ0FzIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MR4wHAYJKoZI -hvcNAQkBFg9pcHNAbWFpbC5pcHMuZXOCAQAwDAYDVR0TBAUwAwEB/zAMBgNVHQ8E -BQMDB/+AMGsGA1UdJQRkMGIGCCsGAQUFBwMBBggrBgEFBQcDAgYIKwYBBQUHAwMG -CCsGAQUFBwMEBggrBgEFBQcDCAYKKwYBBAGCNwIBFQYKKwYBBAGCNwIBFgYKKwYB -BAGCNwoDAQYKKwYBBAGCNwoDBDARBglghkgBhvhCAQEEBAMCAAcwGgYDVR0RBBMw -EYEPaXBzQG1haWwuaXBzLmVzMBoGA1UdEgQTMBGBD2lwc0BtYWlsLmlwcy5lczBD -BglghkgBhvhCAQ0ENhY0Q2hhaW5lZCBDQSBDZXJ0aWZpY2F0ZSBpc3N1ZWQgYnkg -aHR0cHM6Ly93d3cuaXBzLmVzLzAqBglghkgBhvhCAQIEHRYbaHR0cHM6Ly93d3cu -aXBzLmVzL2lwczIwMDIvMDgGCWCGSAGG+EIBBAQrFilodHRwczovL3d3dy5pcHMu -ZXMvaXBzMjAwMi9pcHMyMDAyQ0FDLmNybDA9BglghkgBhvhCAQMEMBYuaHR0cHM6 -Ly93d3cuaXBzLmVzL2lwczIwMDIvcmV2b2NhdGlvbkNBQy5odG1sPzA6BglghkgB -hvhCAQcELRYraHR0cHM6Ly93d3cuaXBzLmVzL2lwczIwMDIvcmVuZXdhbENBQy5o -dG1sPzA4BglghkgBhvhCAQgEKxYpaHR0cHM6Ly93d3cuaXBzLmVzL2lwczIwMDIv -cG9saWN5Q0FDLmh0bWwwbwYDVR0fBGgwZjAvoC2gK4YpaHR0cHM6Ly93d3cuaXBz -LmVzL2lwczIwMDIvaXBzMjAwMkNBQy5jcmwwM6AxoC+GLWh0dHBzOi8vd3d3YmFj -ay5pcHMuZXMvaXBzMjAwMi9pcHMyMDAyQ0FDLmNybDAvBggrBgEFBQcBAQQjMCEw -HwYIKwYBBQUHMAGGE2h0dHA6Ly9vY3NwLmlwcy5lcy8wDQYJKoZIhvcNAQEFBQAD -gYEATiRvY2nro9B6QNgTOgojWSrXMKpXHa6hLRxL2GZPEFg059x2ERs3pw7RlJJZ -ctupZam06zvBnGfQL4ZhevXl6ST6RAAmOikuj8kbiFSgujjCJY1wv5/7zzgBWzdL -NzqKC18p1T2KZa8B2qKfQCqzV/J3fgI/725+9ekqKNLiE5Q= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDnzCCAoegAwIBAgIBJjANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJERTEc -MBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxlU2Vj -IFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290IENB -IDIwHhcNOTkwNzA5MTIxMTAwWhcNMTkwNzA5MjM1OTAwWjBxMQswCQYDVQQGEwJE -RTEcMBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxl -U2VjIFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290 -IENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrC6M14IspFLEU -ha88EOQ5bzVdSq7d6mGNlUn0b2SjGmBmpKlAIoTZ1KXleJMOaAGtuU1cOs7TuKhC -QN/Po7qCWWqSG6wcmtoIKyUn+WkjR/Hg6yx6m/UTAtB+NHzCnjwAWav12gz1Mjwr -rFDa1sPeg5TKqAyZMg4ISFZbavva4VhYAUlfckE8FQYBjl2tqriTtM2e66foai1S -NNs671x1Udrb8zH57nGYMsRUFUQM+ZtV7a3fGAigo4aKSe5TBY8ZTNXeWHmb0moc -QqvF1afPaA+W5OFhmHZhyJF81j4A4pFQh+GdCuatl9Idxjp9y7zaAzTVjlsB9WoH -txa2bkp/AgMBAAGjQjBAMB0GA1UdDgQWBBQxw3kbuvVT1xfgiXotF2wKsyudMzAP -BgNVHRMECDAGAQH/AgEFMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOC -AQEAlGRZrTlk5ynrE/5aw4sTV8gEJPB0d8Bg42f76Ymmg7+Wgnxu1MM9756Abrsp -tJh6sTtU6zkXR34ajgv8HzFZMQSyzhfzLMdiNlXiItiJVbSYSKpk+tYcNthEeFpa -IzpXl/V6ME+un2pMSyuOoAPjPuCp1NJ70rOo4nI8rZ7/gFnkm0W09juwzTkZmDLl -6iFhkOQxIY40sfcvNUqFENrnijchvllj4PKFiDFT1FQUhXB59C4Gdyd1Lx+4ivn+ -xbrYNuSD7Odlt79jWvNGr4GUN9RBjNYj1h7P9WgbRGOiWrqnNVmh5XAFmw4jV5mU -Cm26OWMohpLzGITY+9HPBVZkVw== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFaDCCBFCgAwIBAgIQO1nHe81bV569N1KsdrSqGjANBgkqhkiG9w0BAQUFADBi -MRIwEAYDVQQKEwliZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBSb290IENB -czEvMC0GA1UEAxMmYmVUUlVTVGVkIFJvb3QgQ0EgLSBSU0EgSW1wbGVtZW50YXRp -b24wHhcNMDIwNDExMTExODEzWhcNMjIwNDEyMTEwNzI1WjBiMRIwEAYDVQQKEwli -ZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBSb290IENBczEvMC0GA1UEAxMm -YmVUUlVTVGVkIFJvb3QgQ0EgLSBSU0EgSW1wbGVtZW50YXRpb24wggEiMA0GCSqG -SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkujQwCY5X0LkGLG9uJIAiv11DpvpPrILn -HGhwhRujbrWqeNluB0s/6d/16uhUoWGKDi9pdRi3DOUUjXFumLhV/AyV0Jtu4S2I -1DpAa5LxmZZk3tv/ePTulh1HiXzUvrmIdyM6CeYEnm2qXtLIvZpOGd+J6lsOfsPk -tPDgaTuID0GQ+NRxQyTBjyZLO1bp/4xsN+lFrYWMU8NghpBKlsmzVLC7F/AcRdnU -GxlkVgoZ98zh/4avflherHqQH8koOUV7orbHnB/ahdQhhlkwk75TMzf270HPM8er -cmsl9fNTGwxMLvF1S++gh/f+ihXQbNXL+WhTuXAVE8L1LvtDNXUtAgMBAAGjggIY -MIICFDAMBgNVHRMEBTADAQH/MIIBtQYDVR0gBIIBrDCCAagwggGkBg8rBgEEAbE+ -AAADCSiDkTEwggGPMEEGCCsGAQUFBwIBFjVodHRwOi8vd3d3LmJldHJ1c3RlZC5j -b20vcHJvZHVjdHNfc2VydmljZXMvaW5kZXguaHRtbDCCAUgGCCsGAQUFBwICMIIB -OhqCATZSZWxpYW5jZSBvbiBvciB1c2Ugb2YgdGhpcyBDZXJ0aWZpY2F0ZSBjcmVh -dGVzIGFuIGFja25vd2xlZGdtZW50IGFuZCBhY2NlcHRhbmNlIG9mIHRoZSB0aGVu -IGFwcGxpY2FibGUgc3RhbmRhcmQgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YgdXNl -LCB0aGUgQ2VydGlmaWNhdGlvbiBQcmFjdGljZSBTdGF0ZW1lbnQgYW5kIHRoZSBS -ZWx5aW5nIFBhcnR5IEFncmVlbWVudCwgd2hpY2ggY2FuIGJlIGZvdW5kIGF0IHRo -ZSBiZVRSVVNUZWQgd2ViIHNpdGUsIGh0dHA6Ly93d3cuYmV0cnVzdGVkLmNvbS9w -cm9kdWN0c19zZXJ2aWNlcy9pbmRleC5odG1sMAsGA1UdDwQEAwIBBjAfBgNVHSME -GDAWgBSp7BR++dlDzFMrFK3P9/BZiUHNGTAdBgNVHQ4EFgQUqewUfvnZQ8xTKxSt -z/fwWYlBzRkwDQYJKoZIhvcNAQEFBQADggEBANuXsHXqDMTBmMpWBcCorSZIry0g -6IHHtt9DwSwddUvUQo3neqh03GZCWYez9Wlt2ames30cMcH1VOJZJEnl7r05pmuK -mET7m9cqg5c0Lcd9NUwtNLg+DcTsiCevnpL9UGGCqGAHFFPMZRPB9kdEadIxyKbd -LrML3kqNWz2rDcI1UqJWN8wyiyiFQpyRQHpwKzg21eFzGh/l+n5f3NacOzDq28Bb -J1zTcwfBwvNMm2+fG8oeqqg4MwlYsq78B+g23FW6L09A/nq9BqaBwZMifIYRCgZ3 -SK41ty8ymmFei74pnykkiFY5LKjSq5YDWtRIn7lAhAuYaPsBQ9Yb4gmxlxw= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UEBhMC -VVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50cnVzdC5u -ZXQvQ1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMc -KGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UEAxMxRW50cnVzdC5u -ZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05OTA1 -MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQswCQYDVQQGEwJVUzEUMBIGA1UE -ChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5j -b3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBF -bnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUg -U2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUA -A4GLADCBhwKBgQDNKIM0VBuJ8w+vN5Ex/68xYMmo6LIQaO2f55M28Qpku0f1BBc/ -I0dNxScZgSYMVHINiC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc1lB5gXpa0zf3 -wkrYKZImZNHkmGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQwIBA6OC -AdcwggHTMBEGCWCGSAGG+EIBAQQEAwIABzCCARkGA1UdHwSCARAwggEMMIHeoIHb -oIHYpIHVMIHSMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5 -BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1p -dHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1pdGVk -MTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRp -b24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCmgJ6AlhiNodHRwOi8vd3d3LmVu -dHJ1c3QubmV0L0NSTC9uZXQxLmNybDArBgNVHRAEJDAigA8xOTk5MDUyNTE2MDk0 -MFqBDzIwMTkwNTI1MTYwOTQwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAU8Bdi -E1U9s/8KAGv7UISX8+1i0BowHQYDVR0OBBYEFPAXYhNVPbP/CgBr+1CEl/PtYtAa -MAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EABAwwChsEVjQuMAMCBJAwDQYJKoZI -hvcNAQEFBQADgYEAkNwwAvpkdMKnCqV8IY00F6j7Rw7/JXyNEwr75Ji174z4xRAN -95K+8cPV1ZVqBLssziY2ZcgxxufuP+NXdYR6Ee9GTxj005i7qIcyunL2POI9n9cd -2cNgQ4xYDiKWL2KjLB+6rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEUzCCAzugAwIBAgIDAOJDMA0GCSqGSIb3DQEBBQUAMIHPMQswCQYDVQQGEwJB -VDGBizCBiAYDVQQKHoGAAEEALQBUAHIAdQBzAHQAIABHAGUAcwAuACAAZgD8AHIA -IABTAGkAYwBoAGUAcgBoAGUAaQB0AHMAcwB5AHMAdABlAG0AZQAgAGkAbQAgAGUA -bABlAGsAdAByAC4AIABEAGEAdABlAG4AdgBlAHIAawBlAGgAcgAgAEcAbQBiAEgx -GDAWBgNVBAsTD0EtVHJ1c3QtUXVhbC0wMTEYMBYGA1UEAxMPQS1UcnVzdC1RdWFs -LTAxMB4XDTA0MTEzMDIzMDAwMFoXDTE0MTEzMDIzMDAwMFowgc8xCzAJBgNVBAYT -AkFUMYGLMIGIBgNVBAoegYAAQQAtAFQAcgB1AHMAdAAgAEcAZQBzAC4AIABmAPwA -cgAgAFMAaQBjAGgAZQByAGgAZQBpAHQAcwBzAHkAcwB0AGUAbQBlACAAaQBtACAA -ZQBsAGUAawB0AHIALgAgAEQAYQB0AGUAbgB2AGUAcgBrAGUAaAByACAARwBtAGIA -SDEYMBYGA1UECxMPQS1UcnVzdC1RdWFsLTAxMRgwFgYDVQQDEw9BLVRydXN0LVF1 -YWwtMDEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCmhgdxIbxTGEOH -fXGiewI3NFldAWKFWfLofO+5I1UbvA5avt7IgsGXz/tI/f5HGUbascI0i7xG0tqV -lA5ctQgLRqxgxHtgTkMcqsAEYdsz3LZsCdXO1QrvEBGLTSABdxiL/gSWJ6z77CSw -x7Xg02HwxPV82cjGkSF3ENGJntuIAAnRDWn/ORHjFatNRymoMbHaOEZXSGhf7Y5F -rrHEqGyi9E6sv784De/T1aTvskn8cWeUmDzv//omiG/a/V9KQex/61XN8OthUQVn -X+u/liL2NKx74I2C/GgHX5B0WkPNqsSOgmlvJ/cKuT0PveUgVFDAA0oYBgcE1KDM -lBbN0kmPAgMBAAGjNjA0MA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0OBAoECEs8jB2F -6W+tMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAIUusmJzMJRiQ -8TAHrJAOelfuWoTGcqdIv7Tys/fNl2yF2fjvHT8J01aKialFVpbVeQ2XKb1O2bHO -QYAKgsdZ2jZ/sdL2UVFRTHmidLu6PdgWCBRhJYQELQophO9QVvfhAA0TwbESYqTz -+nlI5Gr7CZe8f6HEmhJmCtUQsdQCufGglRh4T+tIGiNGcnyVEHZ93mSVepFr1VA2 -9CTRPteuGjA81jeAz9peYiFE1CXvxK9cJiv0BcALFLWmADCoRLzIRZhA+sAwYUmw -M1rqVCPA3kBQvIC95tyQvNy2dG0Vs+O6PwLaNX/suSlElQ06X2l1VwMaYb4vZKFq -N0bOhBXEVg== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMC -VVMxFDASBgNVBAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQ -cmVtaXVtIEVDQzAeFw0xMDAxMjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJ -BgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1UcnVzdDEgMB4GA1UEAwwXQWZmaXJt -VHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQNMF4bFZ0D -0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQN8O9 -ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0G -A1UdDgQWBBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4G -A1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/Vs -aobgxCd05DhT1wV/GzTjxi+zygk8N53X57hG8f2h4nECMEJZh0PUUd+60wkyWs6I -flc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKMeQ== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV -BAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2ln -biBHb2xkIENBIC0gRzIwHhcNMDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBF -MQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMR8wHQYDVQQDExZT -d2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC -CgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUqt2/8 -76LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+ -bbqBHH5CjCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c -6bM8K8vzARO/Ws/BtQpgvd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqE -emA8atufK+ze3gE/bk3lUIbLtK/tREDFylqM2tIrfKjuvqblCqoOpd8FUrdVxyJd -MmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvRAiTysybUa9oEVeXBCsdt -MDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuendjIj3o02y -MszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69y -FGkOpeUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPi -aG59je883WX0XaxR7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxM -gI93e2CaHt+28kgeDrpOVG2Y4OGiGqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCB -qTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUWyV7 -lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64OfPAeGZe6Drn -8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov -L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe6 -45R88a7A3hfm5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczO -UYrHUDFu4Up+GC9pWbY9ZIEr44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5 -O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOfMke6UiI0HTJ6CVanfCU2qT1L2sCC -bwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6mGu6uLftIdxf+u+yv -GPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxpmo/a -77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCC -hdiDyyJkvC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid3 -92qgQmwLOM7XdVAyksLfKzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEpp -Ld6leNcG2mqeSz53OiATIgHQv2ieY2BrNU0LbbqhPcCT4H8js1WtciVORvnSFu+w -ZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6LqjviOvrv1vA+ACOzB2+htt -Qc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDEl -MCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMe -U2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoX -DTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRy -dXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3VyaXR5IENvbW11bmlj -YXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANAV -OVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGr -zbl+dp+++T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVM -VAX3NuRFg3sUZdbcDE3R3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQ -hNBqyjoGADdH5H5XTz+L62e4iKrFvlNVspHEfbmwhRkGeC7bYRr6hfVKkaHnFtWO -ojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1KEOtOghY6rCcMU/Gt1SSw -awNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8QIH4D5cs -OPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3 -DQEBCwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpF -coJxDjrSzG+ntKEju/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXc -okgfGT+Ok+vx+hfuzU7jBBJV1uXk3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8 -t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6qtnRGEmyR7jTV7JqR50S+kDFy -1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29mvVXIwAHIRc/ -SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03 ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDyzCCArOgAwIBAgIDAOJIMA0GCSqGSIb3DQEBBQUAMIGLMQswCQYDVQQGEwJB -VDFIMEYGA1UECgw/QS1UcnVzdCBHZXMuIGYuIFNpY2hlcmhlaXRzc3lzdGVtZSBp -bSBlbGVrdHIuIERhdGVudmVya2VociBHbWJIMRgwFgYDVQQLDA9BLVRydXN0LVF1 -YWwtMDIxGDAWBgNVBAMMD0EtVHJ1c3QtUXVhbC0wMjAeFw0wNDEyMDIyMzAwMDBa -Fw0xNDEyMDIyMzAwMDBaMIGLMQswCQYDVQQGEwJBVDFIMEYGA1UECgw/QS1UcnVz -dCBHZXMuIGYuIFNpY2hlcmhlaXRzc3lzdGVtZSBpbSBlbGVrdHIuIERhdGVudmVy -a2VociBHbWJIMRgwFgYDVQQLDA9BLVRydXN0LVF1YWwtMDIxGDAWBgNVBAMMD0Et -VHJ1c3QtUXVhbC0wMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJaR -q9eOsFm4Ab20Hq2Z/aH86gyWa48uSUjY6eQkguHYuszr3gdcSMYZggFHQgnhfLmf -ro/27l5rqKhWiDhWs+b+yZ1PNDhRPJy+86ycHMg9XJqErveULBSyZDdgjhSwOyrN -ibUir/fkf+4sKzP5jjytTKJXD/uCxY4fAd9TjMEVpN3umpIS0ijpYhclYDHvzzGU -833z5Dwhq5D8bc9jp8YSAHFJ1xzIoO1jmn3jjyjdYPnY5harJtHQL73nDQnfbtTs -5ThT9GQLulrMgLU4WeyAWWWEMWpfVZFMJOUkmoOEer6A8e5fIAeqdxdsC+JVqpZ4 -CAKel/Arrlj1gFA//jsCAwEAAaM2MDQwDwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4E -CgQIQj0rJKbBRc4wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQBG -yxFjUA2bPkXUSC2SfJ29tmrbiLKal+g6a9M8Xwd+Ejo+oYkNP6F4GfeDtAXpm7xb -9Ly8lhdbHcpRhzCUQHJ1tBCiGdLgmhSx7TXjhhanKOdDgkdsC1T+++piuuYL72TD -gUy2Sb1GHlJ1Nc6rvB4fpxSDAOHqGpUq9LWsc3tFkXqRqmQVtqtR77npKIFBioc6 -2jTBwDMPX3hDJDR1DSPc6BnZliaNw2IHdiMQ0mBoYeRnFdq+TyDKsjmJOOQPLzzL -/saaw6F891+gBjLFEFquDyR73lAPJS279R3csi8WWk4ZYUC/1V8H3Ktip/J6ac8e -qhLCbmJ81Lo92JGHz/ot ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEXzCCA0egAwIBAgIBATANBgkqhkiG9w0BAQUFADCB0DELMAkGA1UEBhMCRVMx -SDBGBgNVBAoTP0laRU5QRSBTLkEuIC0gQ0lGIEEtMDEzMzcyNjAtUk1lcmMuVml0 -b3JpYS1HYXN0ZWl6IFQxMDU1IEY2MiBTODFCMEAGA1UEBxM5QXZkYSBkZWwgTWVk -aXRlcnJhbmVvIEV0b3JiaWRlYSAzIC0gMDEwMTAgVml0b3JpYS1HYXN0ZWl6MRMw -EQYDVQQDEwpJemVucGUuY29tMR4wHAYJKoZIhvcNAQkBFg9JbmZvQGl6ZW5wZS5j -b20wHhcNMDMwMTMwMjMwMDAwWhcNMTgwMTMwMjMwMDAwWjCB0DELMAkGA1UEBhMC -RVMxSDBGBgNVBAoTP0laRU5QRSBTLkEuIC0gQ0lGIEEtMDEzMzcyNjAtUk1lcmMu -Vml0b3JpYS1HYXN0ZWl6IFQxMDU1IEY2MiBTODFCMEAGA1UEBxM5QXZkYSBkZWwg -TWVkaXRlcnJhbmVvIEV0b3JiaWRlYSAzIC0gMDEwMTAgVml0b3JpYS1HYXN0ZWl6 -MRMwEQYDVQQDEwpJemVucGUuY29tMR4wHAYJKoZIhvcNAQkBFg9JbmZvQGl6ZW5w -ZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC1btoCXXhp3xIW -D+Bxl8nUCxkyiazWfpt0e68t+Qt9+lZjKZSdEw2Omj4qvr+ovRmDXO3iWpWVOWDl -3JHJjAzFCe8ZEBNDH+QNYwZHmPBaMYFOYFdbAFVHWvys152C308hcFJ6xWWGmjvl -2eMiEl9P2nR2LWue368DCu+ak7j3gjAXaCOdP1a7Bfr+RW3X2SC5R4Xyp8iHlL5J -PHJD/WBkLrezwzQPdACw8m9EG7q9kUwlNpL32mROujS3ZkT6mQTzJieLiE3X04s0 -uIUqVkk5MhjcHFf7al0N5CzjtTcnXYJKN2Z9EDVskk4olAdGi46eSoZXbjUOP5gk -Ej6wVZAXAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEG -MB0GA1UdDgQWBBTqVk/sPIOhFIh4gbIrBSLAB0FbQjANBgkqhkiG9w0BAQUFAAOC -AQEAYp7mEzzhw6o5Hf5+T5kcI+t4BJyiIWy7vHlLs/G8dLYXO81aN/Mzg928eMTR -TxxYZL8dd9uwsJ50TVfX6L0R4Dyw6wikh3fHRrat9ufXi63j5K91Ysr7aXqnF38d -iAgHYkrwC3kuxHBb9C0KBz6h8Q45/KCyN7d37wWAq38yyhPDlaOvyoE6bdUuK5hT -m5EYA5JmPyrhQ1moDOyueWBAjxzMEMj+OAY1H90cLv6wszsqerxRrdTOHBdv7MjB -EIpvEEQkXUxVXAzFuuT6m2t91Lfnwfl/IvljHaVC7DlyyhRYHD6D4Rx+4QKp4tWL -vpw6LkI+gKNJ/YdMCsRZQzEEFA== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh -MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE -YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3 -MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo -ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg -MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN -ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA -PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w -wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi -EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY -avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+ -YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE -sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h -/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5 -IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj -YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD -ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy -OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P -TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ -HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER -dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf -ReYNnyicsbkqWletNw+vHX/bvZ8= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFSzCCBLSgAwIBAgIBaTANBgkqhkiG9w0BAQQFADCBmTELMAkGA1UEBhMCSFUx -ETAPBgNVBAcTCEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0 -b25zYWdpIEtmdC4xGjAYBgNVBAsTEVRhbnVzaXR2YW55a2lhZG9rMTIwMAYDVQQD -EylOZXRMb2NrIFV6bGV0aSAoQ2xhc3MgQikgVGFudXNpdHZhbnlraWFkbzAeFw05 -OTAyMjUxNDEwMjJaFw0xOTAyMjAxNDEwMjJaMIGZMQswCQYDVQQGEwJIVTERMA8G -A1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFsb3phdGJpenRvbnNh -Z2kgS2Z0LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxMjAwBgNVBAMTKU5l -dExvY2sgVXpsZXRpIChDbGFzcyBCKSBUYW51c2l0dmFueWtpYWRvMIGfMA0GCSqG -SIb3DQEBAQUAA4GNADCBiQKBgQCx6gTsIKAjwo84YM/HRrPVG/77uZmeBNwcf4xK -gZjupNTKihe5In+DCnVMm8Bp2GQ5o+2So/1bXHQawEfKOml2mrriRBf8TKPV/riX -iK+IA4kfpPIEPsgHC+b5sy96YhQJRhTKZPWLgLViqNhr1nGTLbO/CVRY7QbrqHvc -Q7GhaQIDAQABo4ICnzCCApswEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNVHQ8BAf8E -BAMCAAYwEQYJYIZIAYb4QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaCAk1G -SUdZRUxFTSEgRXplbiB0YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFu -b3MgU3pvbGdhbHRhdGFzaSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBh -bGFwamFuIGtlc3p1bHQuIEEgaGl0ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExv -Y2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2VnLWJpenRvc2l0YXNhIHZlZGkuIEEgZGln -aXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUgYXogZWxvaXJ0 -IGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFzIGxlaXJh -c2EgbWVndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGph -biBhIGh0dHBzOi8vd3d3Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJo -ZXRvIGF6IGVsbGVub3J6ZXNAbmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBP -UlRBTlQhIFRoZSBpc3N1YW5jZSBhbmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmlj -YXRlIGlzIHN1YmplY3QgdG8gdGhlIE5ldExvY2sgQ1BTIGF2YWlsYWJsZSBhdCBo -dHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFpbCBhdCBjcHNA -bmV0bG9jay5uZXQuMA0GCSqGSIb3DQEBBAUAA4GBAATbrowXr/gOkDFOzT4JwG06 -sPgzTEdM43WIEJessDgVkcYplswhwG08pXTP2IKlOcNl40JwuyKQ433bNXbhoLXa -n3BukxowOR0w2y7jfLKRstE3Kfq51hdcR0/jHTjrn9V7lagonhVK0dHQKwCXoOKS -NitjrFgBazMpUIaD8QFI ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICZzCCAdCgAwIBAgIBBDANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQGEwJVUzEY -MBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxDDAKBgNVBAsT -A1BLSTEcMBoGA1UEAxMTRG9EIENMQVNTIDMgUm9vdCBDQTAeFw0wMDA1MTkxMzEz -MDBaFw0yMDA1MTQxMzEzMDBaMGExCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMu -IEdvdmVybm1lbnQxDDAKBgNVBAsTA0RvRDEMMAoGA1UECxMDUEtJMRwwGgYDVQQD -ExNEb0QgQ0xBU1MgMyBSb290IENBMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB -gQC1MP5kvurMbe2BLPd/6Rm6DmlqKOGpqcuVWB/x5pppU+CIP5HFUbljl6jmIYwT -XjY8qFf6+HAsTGrLvzCnTBbkMlz4ErBR+BZXjS+0TfouqJToKmHUVw1Hzm4sL36Y -Z8wACKu2lhY1woWR5VugCsdmUmLzYXWVF668KlYppeArUwIDAQABoy8wLTAdBgNV -HQ4EFgQUbJyl8FyPbUGNxBc7kFfCD6PNbf4wDAYDVR0TBAUwAwEB/zANBgkqhkiG -9w0BAQUFAAOBgQCvcUT5lyPMaGmMQwdBuoggsyIAQciYoFUczT9usZNcrfoYmrsc -c2/9JEKPh59Rz76Gn+nXikhPCNlplKw/5g8tlw8ok3ZPYt//oM1h+KaGDDE0INx/ -L6j7Ob6V7jhZAmLB3mwVT+DfnbvkeXMk/WNklfdKqJkfSGWVx3u/eDLneg== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU -MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs -IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290 -MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux -FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h -bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v -dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt -H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9 -uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX -mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX -a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN -E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0 -WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD -VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0 -Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU -cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx -IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN -AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH -YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5 -6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC -Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX -c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a -mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDNjCCAp+gAwIBAgIQNhIilsXjOKUgodJfTNcJVDANBgkqhkiG9w0BAQUFADCB -zjELMAkGA1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJ -Q2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UE -CxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhh -d3RlIFByZW1pdW0gU2VydmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNl -cnZlckB0aGF3dGUuY29tMB4XDTk2MDgwMTAwMDAwMFoXDTIxMDEwMTIzNTk1OVow -gc4xCzAJBgNVBAYTAlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcT -CUNhcGUgVG93bjEdMBsGA1UEChMUVGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNV -BAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRo -YXd0ZSBQcmVtaXVtIFNlcnZlciBDQTEoMCYGCSqGSIb3DQEJARYZcHJlbWl1bS1z -ZXJ2ZXJAdGhhd3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2 -aovXwlue2oFBYo847kkEVdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560 -ZXUCTe/LCaIhUdib0GfQug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j -+ao6hnO2RlNYyIkFvYMRuHM/qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/ -BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQBlkKyID1bZ5jA01CbH0FDxkt5r1DmI -CSLGpmODA/eZd9iy5Ri4XWPz1HP7bJyZePFLeH0ZJMMrAoT4vCLZiiLXoPxx7JGH -IPG47LHlVYCsPVLIOQ7C8MAFT9aCdYy9X9LcdpoFEsmvcsPcJX6kTY4XpeCHf+Ga -WuFg3GQjPEIuTQ== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICXDCCAcWgAwIBAgIQCgEBAQAAAnwAAAALAAAAAjANBgkqhkiG9w0BAQUFADA6 -MRkwFwYDVQQKExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0EgU2VjdXJp -dHkgMTAyNCBWMzAeFw0wMTAyMjIyMTAxNDlaFw0yNjAyMjIyMDAxNDlaMDoxGTAX -BgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAbBgNVBAsTFFJTQSBTZWN1cml0eSAx -MDI0IFYzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDV3f5mCc8kPD6ugU5O -isRpgFtZO9+5TUzKtS3DJy08rwBCbbwoppbPf9dYrIMKo1W1exeQFYRMiu4mmdxY -78c4pqqv0I5CyGLXq6yp+0p9v+r+Ek3d/yYtbzZUaMjShFbuklNhCbM/OZuoyZu9 -zp9+1BlqFikYvtc6adwlWzMaUQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4G -A1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBTEwBykB5T9zU0B1FTapQxf3q4FWjAd -BgNVHQ4EFgQUxMAcpAeU/c1NAdRU2qUMX96uBVowDQYJKoZIhvcNAQEFBQADgYEA -Py1q4yZDlX2Jl2X7deRyHUZXxGFraZ8SmyzVWujAovBDleMf6XbN3Ou8k6BlCsdN -T1+nr6JGFLkM88y9am63nd4lQtBU/55oc2PcJOsiv6hy8l4A4Q1OOkNumU4/iXgD -mMrzVcydro7BqkWY+o8aoI2II/EVQQ2lRj6RP4vr93E= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIID3TCCAsWgAwIBAgIOHaIAAQAC7LdggHiNtgYwDQYJKoZIhvcNAQEFBQAweTEL -MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNV -BAsTG1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQTEmMCQGA1UEAxMdVEMgVHJ1 -c3RDZW50ZXIgVW5pdmVyc2FsIENBIEkwHhcNMDYwMzIyMTU1NDI4WhcNMjUxMjMx -MjI1OTU5WjB5MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIg -R21iSDEkMCIGA1UECxMbVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBMSYwJAYD -VQQDEx1UQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0EgSTCCASIwDQYJKoZIhvcN -AQEBBQADggEPADCCAQoCggEBAKR3I5ZEr5D0MacQ9CaHnPM42Q9e3s9B6DGtxnSR -JJZ4Hgmgm5qVSkr1YnwCqMqs+1oEdjneX/H5s7/zA1hV0qq34wQi0fiU2iIIAI3T -fCZdzHd55yx4Oagmcw6iXSVphU9VDprvxrlE4Vc93x9UIuVvZaozhDrzznq+VZeu -jRIPFDPiUHDDSYcTvFHe15gSWu86gzOSBnWLknwSaHtwag+1m7Z3W0hZneTvWq3z -wZ7U10VOylY0Ibw+F1tvdwxIAUMpsN0/lm7mlaoMwCC2/T42J5zjXM9OgdwZu5GQ -fezmlwQek8wiSdeXhrYTCjxDI3d+8NzmzSQfO4ObNDqDNOMCAwEAAaNjMGEwHwYD -VR0jBBgwFoAUkqR1LKSevoFE63n8isWVpesQdXMwDwYDVR0TAQH/BAUwAwEB/zAO -BgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFJKkdSyknr6BROt5/IrFlaXrEHVzMA0G -CSqGSIb3DQEBBQUAA4IBAQAo0uCG1eb4e/CX3CJrO5UUVg8RMKWaTzqwOuAGy2X1 -7caXJ/4l8lfmXpWMPmRgFVp/Lw0BxbFg/UU1z/CyvwbZ71q+s2IhtNerNXxTPqYn -8aEt2hojnczd7Dwtnic0XQ/CNnm8yUpiLe1r2X1BQ3y2qsrtYbE3ghUJGooWMNjs -ydZHcnhLEEYUjl8Or+zHL6sQ17bxbuyGssLoDZJz3KL0Dzq/YSMQiZxIQG5wALPT -ujdEWBF6AmqI8Dc08BnprNRlc/ZpjGSUOnmFKbAWKwyCPwacx/0QK54PLLae4xW/ -2TYcuiUaUj0a7CIMHOCkoj3w6DnPgcB77V0fb8XQC9eY ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIH/zCCB2igAwIBAgIBADANBgkqhkiG9w0BAQUFADCCARQxCzAJBgNVBAYTAkVT -MRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UE -ChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5sLjErMCkGA1UE -ChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1MjEvMC0GA1UECxMm -SVBTIENBIENMQVNFQTMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxLzAtBgNVBAMT -JklQUyBDQSBDTEFTRUEzIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MR4wHAYJKoZI -hvcNAQkBFg9pcHNAbWFpbC5pcHMuZXMwHhcNMDExMjMxMTEyMzU5WhcNMjUxMjI5 -MTEyMzU5WjCCARQxCzAJBgNVBAYTAkVTMRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQ -BgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UEChMlSVBTIEludGVybmV0IHB1Ymxpc2hp -bmcgU2VydmljZXMgcy5sLjErMCkGA1UEChQiaXBzQG1haWwuaXBzLmVzIEMuSS5G -LiAgQi02MDkyOTQ1MjEvMC0GA1UECxMmSVBTIENBIENMQVNFQTMgQ2VydGlmaWNh -dGlvbiBBdXRob3JpdHkxLzAtBgNVBAMTJklQUyBDQSBDTEFTRUEzIENlcnRpZmlj -YXRpb24gQXV0aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXMw -gZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMFh+lWUEmnBK5F6da6IALvvPO6f -MWYw9LFAmwJsjcdKTVElPugUKLwgPLHxjO19kdmXIqPVzGOxq9krIwvdppffBYRU -Fro6y8xja40gpdaeBXFGdVj19mR7C2adPoeVPTy1OTdSVLsWF8W/rdiLMy/p+PrV -gTP/t56Fpu9MOeDjAgMBAAGjggRbMIIEVzAdBgNVHQ4EFgQU/J6FGtwGJXEh8C+L -ElXQxYDuBq4wggFGBgNVHSMEggE9MIIBOYAU/J6FGtwGJXEh8C+LElXQxYDuBq6h -ggEcpIIBGDCCARQxCzAJBgNVBAYTAkVTMRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQ -BgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UEChMlSVBTIEludGVybmV0IHB1Ymxpc2hp -bmcgU2VydmljZXMgcy5sLjErMCkGA1UEChQiaXBzQG1haWwuaXBzLmVzIEMuSS5G -LiAgQi02MDkyOTQ1MjEvMC0GA1UECxMmSVBTIENBIENMQVNFQTMgQ2VydGlmaWNh -dGlvbiBBdXRob3JpdHkxLzAtBgNVBAMTJklQUyBDQSBDTEFTRUEzIENlcnRpZmlj -YXRpb24gQXV0aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXOC -AQAwDAYDVR0TBAUwAwEB/zAMBgNVHQ8EBQMDB/+AMGsGA1UdJQRkMGIGCCsGAQUF -BwMBBggrBgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYKKwYB -BAGCNwIBFQYKKwYBBAGCNwIBFgYKKwYBBAGCNwoDAQYKKwYBBAGCNwoDBDARBglg -hkgBhvhCAQEEBAMCAAcwGgYDVR0RBBMwEYEPaXBzQG1haWwuaXBzLmVzMBoGA1Ud -EgQTMBGBD2lwc0BtYWlsLmlwcy5lczBDBglghkgBhvhCAQ0ENhY0Q0xBU0VBMyBD -QSBDZXJ0aWZpY2F0ZSBpc3N1ZWQgYnkgaHR0cHM6Ly93d3cuaXBzLmVzLzAqBglg -hkgBhvhCAQIEHRYbaHR0cHM6Ly93d3cuaXBzLmVzL2lwczIwMDIvMDwGCWCGSAGG -+EIBBAQvFi1odHRwczovL3d3dy5pcHMuZXMvaXBzMjAwMi9pcHMyMDAyQ0xBU0VB -My5jcmwwQQYJYIZIAYb4QgEDBDQWMmh0dHBzOi8vd3d3Lmlwcy5lcy9pcHMyMDAy -L3Jldm9jYXRpb25DTEFTRUEzLmh0bWw/MD4GCWCGSAGG+EIBBwQxFi9odHRwczov -L3d3dy5pcHMuZXMvaXBzMjAwMi9yZW5ld2FsQ0xBU0VBMy5odG1sPzA8BglghkgB -hvhCAQgELxYtaHR0cHM6Ly93d3cuaXBzLmVzL2lwczIwMDIvcG9saWN5Q0xBU0VB -My5odG1sMHcGA1UdHwRwMG4wM6AxoC+GLWh0dHBzOi8vd3d3Lmlwcy5lcy9pcHMy -MDAyL2lwczIwMDJDTEFTRUEzLmNybDA3oDWgM4YxaHR0cHM6Ly93d3diYWNrLmlw -cy5lcy9pcHMyMDAyL2lwczIwMDJDTEFTRUEzLmNybDAvBggrBgEFBQcBAQQjMCEw -HwYIKwYBBQUHMAGGE2h0dHA6Ly9vY3NwLmlwcy5lcy8wDQYJKoZIhvcNAQEFBQAD -gYEAGG8JN0Ca0pQR0X/Lg33qtKfi2JPe2iRqdRswDoL3CTn+bRN20V/wbKDAwyxc -7eJOroysytPkEF4wZhipaKCjaWJROZGCeU1jM7mZe9pQPzeofT//VLi8zKaUA4lZ -BvYI44gntZQoaFxJna5NHHde+mbbPYlHb8c6g0mf9S3tODs= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDXTCCAkWgAwIBAgIDAOJCMA0GCSqGSIb3DQEBBQUAMFUxCzAJBgNVBAYTAkFU -MRAwDgYDVQQKEwdBLVRydXN0MRkwFwYDVQQLExBBLVRydXN0LW5RdWFsLTAxMRkw -FwYDVQQDExBBLVRydXN0LW5RdWFsLTAxMB4XDTA0MTEzMDIzMDAwMFoXDTE0MTEz -MDIzMDAwMFowVTELMAkGA1UEBhMCQVQxEDAOBgNVBAoTB0EtVHJ1c3QxGTAXBgNV -BAsTEEEtVHJ1c3QtblF1YWwtMDExGTAXBgNVBAMTEEEtVHJ1c3QtblF1YWwtMDEw -ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQD/9RyAEZ6eHmhYzNJ328f0 -jmdSUFi6EqRqOxb3jHNPTIpK82CR6z5lmSnZQNUuCPD+htbNZffd2DKVB06NOyZ1 -2zcOMCgj4GtkZoqE0zPpPT3bpoE55nkZZe/qWEX/64wz/L/4EdkvKDSKG/UsP75M -tmCVY5m2Eg73RVFRz4ccBIMpHel4lzEqSkdDtZOY5fnkrE333hx67nxq21vY8Eyf -8O4fPQ5RtN8eohQCcPQ1z6ypU1R7N9jPRpnI+yzMOiwd3+QcKhHi1miCzo0pkOaB -1CwmfsTyNl8qU0NJUL9Ta6cea7WThwTiWol2yD88cd2cy388xpbNkfrCPmZNGLoV -AgMBAAGjNjA0MA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0OBAoECE5ZzscCMocwMA4G -A1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEA69I9R1hU9Gbl9vV7W7AH -QpUJAlFAvv2It/eY8p2ouQUPVaSZikaKtAYrCD/arzfXB43Qet+dM6CpHsn8ikYR -vQKePjXv3Evf+C1bxwJAimcnZV6W+bNOTpdo8lXljxkmfN+Z5S+XzvK2ttUtP4Et -YOVaxHw2mPMNbvDeY+foJkiBn3KYjGabMaR8moZqof5ofj4iS/WyamTZti6v/fKx -n1vII+/uWkcxV5DT5+r9HLon0NYF0Vg317Wh+gWDV59VZo+dcwJDb+keYqMFYoqp -77SGkZGu41S8NGYkQY3X9rNHRkDbLfpKYDmy6NanpOE1EHW1/sNSFAs43qZZKJEQ -xg== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDMDCCApmgAwIBAgIQDY4VEuGsu3eNOOMk34ww8jANBgkqhkiG9w0BAQUFADCB -yzELMAkGA1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJ -Q2FwZSBUb3duMRowGAYDVQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMf -Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3Rl -IFBlcnNvbmFsIEJhc2ljIENBMSgwJgYJKoZIhvcNAQkBFhlwZXJzb25hbC1iYXNp -Y0B0aGF3dGUuY29tMB4XDTk2MDEwMTAwMDAwMFoXDTIxMDEwMTIzNTk1OVowgcsx -CzAJBgNVBAYTAlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNh -cGUgVG93bjEaMBgGA1UEChMRVGhhd3RlIENvbnN1bHRpbmcxKDAmBgNVBAsTH0Nl -cnRpZmljYXRpb24gU2VydmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQ -ZXJzb25hbCBCYXNpYyBDQTEoMCYGCSqGSIb3DQEJARYZcGVyc29uYWwtYmFzaWNA -dGhhd3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAvLyTU23AUE+C -FeZIlDWmWr5vQvoPR+53dXLdjUmbllegeNTKP1GzaQuRdhciB5dqxFGTS+CN7zeV -oQxN2jSQHReJl+A1OFdKwPQIcOk8RHtQfmGakOMj04gRRif1CwcOu93RfyAKiLlW -Cy4cgNrx454p7xS9CkT7G1sY0b8jkyECAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB -/zANBgkqhkiG9w0BAQUFAAOBgQCIO/64+XpCRhGgpKJkhc1IHJzVilHNL8F9sQfP -1wHeMj+W5IT+0V6tDH4OY0lqDhDkl9A/xacp2aZTHkseP1T6wIQ1c+qRqdxdk1cF -BgwHua8LRDmIIaDugnOpRi9pbCV0qc3fp9f9hTAElDVKpxszJCxEFu0KxN+AqmUa -v3Em8A== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD -QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT -MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j -b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG -9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB -CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 -nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt -43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P -T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 -gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO -BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR -TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw -DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr -hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg -06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF -PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls -YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk -CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx -EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT -HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs -ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw -MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 -b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj -aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp -Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC -ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg -nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1 -HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N -Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN -dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0 -HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO -BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G -CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU -sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3 -4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg -8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K -pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1 -mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEgzCCA+ygAwIBAgIEOJ725DANBgkqhkiG9w0BAQQFADCBtDEUMBIGA1UEChML -RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9HQ0NBX0NQUyBp -bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAyMDAw -IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENsaWVu -dCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMDAyMDcxNjE2NDBaFw0yMDAy -MDcxNjQ2NDBaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3 -LmVudHJ1c3QubmV0L0dDQ0FfQ1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp -YWIuKTElMCMGA1UECxMcKGMpIDIwMDAgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG -A1UEAxMqRW50cnVzdC5uZXQgQ2xpZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 -MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCTdLS25MVL1qFof2LV7PdRV7Ny -Spj10InJrWPNTTVRaoTUrcloeW+46xHbh65cJFET8VQlhK8pK5/jgOLZy93GRUk0 -iJBeAZfv6lOm3fzB3ksqJeTpNfpVBQbliXrqpBFXO/x8PTbNZzVtpKklWb1m9fkn -5JVn1j+SgF7yNH0rhQIDAQABo4IBnjCCAZowEQYJYIZIAYb4QgEBBAQDAgAHMIHd -BgNVHR8EgdUwgdIwgc+ggcyggcmkgcYwgcMxFDASBgNVBAoTC0VudHJ1c3QubmV0 -MUAwPgYDVQQLFDd3d3cuZW50cnVzdC5uZXQvR0NDQV9DUFMgaW5jb3JwLiBieSBy -ZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMjAwMCBFbnRydXN0Lm5l -dCBMaW1pdGVkMTMwMQYDVQQDEypFbnRydXN0Lm5ldCBDbGllbnQgQ2VydGlmaWNh -dGlvbiBBdXRob3JpdHkxDTALBgNVBAMTBENSTDEwKwYDVR0QBCQwIoAPMjAwMDAy -MDcxNjE2NDBagQ8yMDIwMDIwNzE2NDY0MFowCwYDVR0PBAQDAgEGMB8GA1UdIwQY -MBaAFISLdP3FjcD/J20gN0V8/i3OutN9MB0GA1UdDgQWBBSEi3T9xY3A/ydtIDdF -fP4tzrrTfTAMBgNVHRMEBTADAQH/MB0GCSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4w -AwIEkDANBgkqhkiG9w0BAQQFAAOBgQBObzWAO9GK9Q6nIMstZVXQkvTnhLUGJoMS -hAusO7JE7r3PQNsgDrpuFOow4DtifH+La3xKp9U1PL6oXOpLu5OOgGarDyn9TS2/ -GpsKkMWr2tGzhtQvJFJcem3G8v7lTRowjJDyutdKPkN+1MhQGof4T4HHdguEOnKd -zmVml64mXg== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDKTCCApKgAwIBAgIENnAVljANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQGEwJV -UzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREwDwYDVQQL -EwhEU1RDQSBFMTAeFw05ODEyMTAxODEwMjNaFw0xODEyMTAxODQwMjNaMEYxCzAJ -BgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4x -ETAPBgNVBAsTCERTVENBIEUxMIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQCg -bIGpzzQeJN3+hijM3oMv+V7UQtLodGBmE5gGHKlREmlvMVW5SXIACH7TpWJENySZ -j9mDSI+ZbZUTu0M7LklOiDfBu1h//uG9+LthzfNHwJmm8fOR6Hh8AMthyUQncWlV -Sn5JTe2io74CTADKAqjuAQIxZA9SLRN0dja1erQtcQIBA6OCASQwggEgMBEGCWCG -SAGG+EIBAQQEAwIABzBoBgNVHR8EYTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMx -JDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMI -RFNUQ0EgRTExDTALBgNVBAMTBENSTDEwKwYDVR0QBCQwIoAPMTk5ODEyMTAxODEw -MjNagQ8yMDE4MTIxMDE4MTAyM1owCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFGp5 -fpFpRhgTCgJ3pVlbYJglDqL4MB0GA1UdDgQWBBRqeX6RaUYYEwoCd6VZW2CYJQ6i -+DAMBgNVHRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqG -SIb3DQEBBQUAA4GBACIS2Hod3IEGtgllsofIH160L+nEHvI8wbsEkBFKg05+k7lN -QseSJqBcNJo4cvj9axY+IO6CizEqkzaFI4iKPANo08kJD038bKTaKHKTDomAsH3+ -gG9lbRgzl4vCa4nuYD3Im+9/KzJic5PLPON74nZ4RbyhkwS7hp86W0N6w4pl ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB -yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL -ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp -U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW -ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0 -aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL -MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW -ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln -biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp -U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y -aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1 -nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex -t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz -SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG -BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+ -rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/ -NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E -BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH -BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy -aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv -MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE -p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y -5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK -WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ -4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N -hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIESzCCAzOgAwIBAgIJAJigUTEEXRQpMA0GCSqGSIb3DQEBBQUAMHYxCzAJBgNV -BAYTAkRFMQ8wDQYDVQQIEwZIZXNzZW4xDjAMBgNVBAcTBUZ1bGRhMRAwDgYDVQQK -EwdEZWJjb25mMRMwEQYDVQQDEwpEZWJjb25mIENBMR8wHQYJKoZIhvcNAQkBFhBq -b2VyZ0BkZWJpYW4ub3JnMB4XDTA1MTEwNTE3NTUxNFoXDTE1MTEwMzE3NTUxNFow -djELMAkGA1UEBhMCREUxDzANBgNVBAgTBkhlc3NlbjEOMAwGA1UEBxMFRnVsZGEx -EDAOBgNVBAoTB0RlYmNvbmYxEzARBgNVBAMTCkRlYmNvbmYgQ0ExHzAdBgkqhkiG -9w0BCQEWEGpvZXJnQGRlYmlhbi5vcmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw -ggEKAoIBAQCvbOo0SrIwI5IMlsshH8WF3dHB9r9JlSKhMPaybawa1EyvZspMQ3wa -F5qxNf3Sj+NElEmjseEqvCZiIIzqwerHu0Qw62cDYCdCd2+Wb5m0bPYB5CGHiyU1 -eNP0je42O0YeXG2BvUujN8AviocVo39X2YwNQ0ryy4OaqYgm2pRlbtT2ESbF+SfV -Y2iqQj/f8ymF+lHo/pz8tbAqxWcqaSiHFAVQJrdqtFhtoodoNiE3q76zJoUkZTXB -k60Yc3MJSnatZCpnsSBr/D7zpntl0THrUjjtdRWCjQVhqfhM1yZJV+ApbLdheFh0 -ZWlSxdnp25p0q0XYw/7G92ELyFDfBUUNAgMBAAGjgdswgdgwHQYDVR0OBBYEFMuV -dFNb4mCWUFbcP5LOtxFLrEVTMIGoBgNVHSMEgaAwgZ2AFMuVdFNb4mCWUFbcP5LO -txFLrEVToXqkeDB2MQswCQYDVQQGEwJERTEPMA0GA1UECBMGSGVzc2VuMQ4wDAYD -VQQHEwVGdWxkYTEQMA4GA1UEChMHRGViY29uZjETMBEGA1UEAxMKRGViY29uZiBD -QTEfMB0GCSqGSIb3DQEJARYQam9lcmdAZGViaWFuLm9yZ4IJAJigUTEEXRQpMAwG -A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAGZXxHg4mnkvilRIM1EQfGdY -S5b/WcyF2MYSTeTvK4aIB6VHwpZoZCnDGj2m2D3CkHT0upAD9o0zM1tdsfncLzV+ -mDT/jNmBtYo4QXx5vEPwvEIcgrWjwk7SyaEUhZjtolTkHB7ACl0oD0r71St4iEPR -qTUCEXk2E47bg1Fz58wNt/yo2+4iqiRjg1XCH4evkQuhpW+dTZnDyFNqwSYZapOE -TBA+9zBb6xD1KM2DdY7r4GiyYItN0BKLfuWbh9LXGbl1C+f4P11g+m2MPiavIeCe -1iazG5pcS3KoTLACsYlEX24TINtg4kcuS81XdllcnsV3Kdts0nIqPj6uhTTZD0k= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICPTCCAaYCEQDNun9W8N/kvFT+IqyzcqpVMA0GCSqGSIb3DQEBAgUAMF8xCzAJ -BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xh -c3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05 -NjAxMjkwMDAwMDBaFw0yODA4MDEyMzU5NTlaMF8xCzAJBgNVBAYTAlVTMRcwFQYD -VQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xhc3MgMSBQdWJsaWMgUHJp -bWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCBnzANBgkqhkiG9w0BAQEFAAOB -jQAwgYkCgYEA5Rm/baNWYS2ZSHH2Z965jeu3noaACpEO+jglr0aIguVzqKCbJF0N -H8xlbgyw0FaEGIeaBpsQoXPftFg5a27B9hXVqKg/qhIGjTGsf7A01480Z4gJzRQR -4k5FVmkfeAKA2txHkSm7NsljXMXg1y2He6G3MrB7MLoqLzGq7qNn2tsCAwEAATAN -BgkqhkiG9w0BAQIFAAOBgQBMP7iLxmjf7kMzDl3ppssHhE16M/+SG/Q2rdiVIjZo -EWx8QszznC7EBz8UsA9P/5CSdvnivErpj82ggAr3xSnxgiJduLHdgSOjeyUVRjB5 -FvjqBUuUfx3CHMjjt/QQQDwTw18fU+hI5Ia0e6E1sHslurjTjqs/OJ0ANACY89Fx -lA== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICWjCCAcMCAgGlMA0GCSqGSIb3DQEBBAUAMHUxCzAJBgNVBAYTAlVTMRgwFgYD -VQQKEw9HVEUgQ29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRydXN0IFNv -bHV0aW9ucywgSW5jLjEjMCEGA1UEAxMaR1RFIEN5YmVyVHJ1c3QgR2xvYmFsIFJv -b3QwHhcNOTgwODEzMDAyOTAwWhcNMTgwODEzMjM1OTAwWjB1MQswCQYDVQQGEwJV -UzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQLEx5HVEUgQ3liZXJU -cnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRydXN0IEds -b2JhbCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVD6C28FCc6HrH -iM3dFw4usJTQGz0O9pTAipTHBsiQl8i4ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTS -r41tiGeA5u2ylc9yMcqlHHK6XALnZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X4 -04Wqk2kmhXBIgD8SFcd5tB8FLztimQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBAG3r -GwnpXtlR22ciYaQqPEh346B8pt5zohQDhT37qw4wxYMWM4ETCJ57NE7fQMh017l9 -3PR2VX2bY1QY6fDq81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OFNMQkpw0P -lZPvy5TYnh+dXIVtx6quTx8itc2VrbqnzPmrC3p/ ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEY -MBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21t -dW5pY2F0aW9uIFJvb3RDQTEwHhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5 -WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYD -VQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEwggEiMA0GCSqGSIb3 -DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw8yl8 -9f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJ -DKaVv0uMDPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9 -Ms+k2Y7CI9eNqPPYJayX5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/N -QV3Is00qVUarH9oe4kA92819uZKAnDfdDJZkndwi92SL32HeFZRSFaB9UslLqCHJ -xrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2JChzAgMBAAGjPzA9MB0G -A1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYwDwYDVR0T -AQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vG -kl3g0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfr -Uj94nK9NrvjVT8+amCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5 -Bw+SUEmK3TGXX8npN6o7WWWXlDLJs58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJU -JRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ6rBK+1YWc26sTfcioU+tHXot -RSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAiFL39vmwLAw== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIID2TCCAsGgAwIBAgIDAjbQMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT -MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i -YWwgQ0EwHhcNMTAwMjE5MjIzOTI2WhcNMjAwMjE4MjIzOTI2WjBAMQswCQYDVQQG -EwJVUzEXMBUGA1UEChMOR2VvVHJ1c3QsIEluYy4xGDAWBgNVBAMTD0dlb1RydXN0 -IFNTTCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJCzgMHk5Uat -cGA9uuUU3Z6KXot1WubKbUGlI+g5hSZ6p1V3mkihkn46HhrxJ6ujTDnMyz1Hr4Gu -FmpcN+9FQf37mpc8oEOdxt8XIdGKolbCA0mEEoE+yQpUYGa5jFTk+eb5lPHgX3UR -8im55IaisYmtph6DKWOy8FQchQt65+EuDa+kvc3nsVrXjAVaDktzKIt1XTTYdwvh -dGLicTBi2LyKBeUxY0pUiWozeKdOVSQdl+8a5BLGDzAYtDRN4dgjOyFbLTAZJQ50 -96QhS6CkIMlszZhWwPKoXz4mdaAN+DaIiixafWcwqQ/RmXAueOFRJq9VeiS+jDkN -d53eAsMMvR8CAwEAAaOB2TCB1jAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFEJ5 -VBthzVUrPmPVPEhX9Z/7Rc5KMB8GA1UdIwQYMBaAFMB6mGiNifurBWQMEX2qfWW4 -ysxOMBIGA1UdEwEB/wQIMAYBAf8CAQAwOgYDVR0fBDMwMTAvoC2gK4YpaHR0cDov -L2NybC5nZW90cnVzdC5jb20vY3Jscy9ndGdsb2JhbC5jcmwwNAYIKwYBBQUHAQEE -KDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5nZW90cnVzdC5jb20wDQYJKoZI -hvcNAQEFBQADggEBANTvU4ToGr2hiwTAqfVfoRB4RV2yV2pOJMtlTjGXkZrUJPji -J2ZwMZzBYlQG55cdOprApClICq8kx6jEmlTBfEx4TCtoLF0XplR4TEbigMMfOHES -0tdT41SFULgCy+5jOvhWiU1Vuy7AyBh3hjELC3DwfjWDpCoTZFZnNF0WX3OsewYk -2k9QbSqr0E1TQcKOu3EDSSmGGM8hQkx0YlEVxW+o78Qn5Rsz3VqI138S0adhJR/V -4NwdzxoQ2KDLX4z6DOW/cf/lXUQdpj6HR/oaToODEj+IZpWYeZqF6wJHzSXj8gYE -TpnKXKBuervdo5AaRTPvvz7SBMS24CqFZUE+ENQ= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDdjCCAl6gAwIBAgIEOhsEBTANBgkqhkiG9w0BAQUFADBRMQswCQYDVQQGEwJE -SzEMMAoGA1UEChMDS01EMQ8wDQYDVQQLEwZLTUQtQ0ExIzAhBgNVBAMTGktNRC1D -QSBLdmFsaWZpY2VyZXQgUGVyc29uMB4XDTAwMTEyMTIzMjQ1OVoXDTE1MTEyMjIz -MjQ1OVowUTELMAkGA1UEBhMCREsxDDAKBgNVBAoTA0tNRDEPMA0GA1UECxMGS01E -LUNBMSMwIQYDVQQDExpLTUQtQ0EgS3ZhbGlmaWNlcmV0IFBlcnNvbjCCASIwDQYJ -KoZIhvcNAQEBBQADggEPADCCAQoCggEBANriF4Xd6yD7ZlBE317UBDObn+vRMVc6 -p3wNQODdEDJe2z1ncCz9NJvhoLGdOJhyg7VVPh0P2c+KZ9WI9mWOKZI2bp2WkLju -jCcxbhTrurY3Wfc6gwLBqqFV8wWgaZKmvVWizjw9Kyi25f3yX4fOho6Qq2lvVbub -tvVFXAd51GJ+/2Yed+a4Or2bz2RcqHS81B3pywsD4mgJR5xREv5jqPfwNP+V7bkc -X+pfO4kVhZ/V+8MSPdQHgcV/iB3wP2mwgWyIBNc1reBidGTiz8unnWu55hcNfsvt -LJbTs9OHhsR7naRuy+S402nDnD5vnONOFEsiHn46w+T0rtu7h6j4OvkCAwEAAaNW -MFQwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUeWLqmhI42Jxj7DifDsW+ -DlQhKD0wHwYDVR0jBBgwFoAUeWLqmhI42Jxj7DifDsW+DlQhKD0wDQYJKoZIhvcN -AQEFBQADggEBANML/P42OuJ9aUV/0fItuIyc1JhqWvSqn5bXj+9eyEegcp8bHLHY -42D1O+z0lNipdjYPSdMJ0wZOEUhr+150SdDQ1P/zQL8AUaLEBkRt7ZdzXPVH3PER -qnf9IrpYBknZKfCAoVchA6Rr9WU3Sd8bMoRfMLKg8c0M8G6EPwCTcOFriSkbtvNG -zd8r8I+WfUYIN/p8DI9JT9qfjVODnYPRMUm6KPvq27TsrGruKrqyaV94kWc8co8A -v3zFLeCtghvUiRBdx+8Q7m5t4CkuSr0WINrqjIPFW2QrM1r82y09Fd16RkqL4LOg -Lh6vB5KnTApv62rWdw7zWwYnjY6/vXYY1Aw= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIGCDCCA/CgAwIBAgIBATANBgkqhkiG9w0BAQQFADB5MRAwDgYDVQQKEwdSb290 -IENBMR4wHAYDVQQLExVodHRwOi8vd3d3LmNhY2VydC5vcmcxIjAgBgNVBAMTGUNB -IENlcnQgU2lnbmluZyBBdXRob3JpdHkxITAfBgkqhkiG9w0BCQEWEnN1cHBvcnRA -Y2FjZXJ0Lm9yZzAeFw0wNTEwMTQwNzM2NTVaFw0zMzAzMjgwNzM2NTVaMFQxFDAS -BgNVBAoTC0NBY2VydCBJbmMuMR4wHAYDVQQLExVodHRwOi8vd3d3LkNBY2VydC5v -cmcxHDAaBgNVBAMTE0NBY2VydCBDbGFzcyAzIFJvb3QwggIiMA0GCSqGSIb3DQEB -AQUAA4ICDwAwggIKAoICAQCrSTURSHzSJn5TlM9Dqd0o10Iqi/OHeBlYfA+e2ol9 -4fvrcpANdKGWZKufoCSZc9riVXbHF3v1BKxGuMO+f2SNEGwk82GcwPKQ+lHm9WkB -Y8MPVuJKQs/iRIwlKKjFeQl9RrmK8+nzNCkIReQcn8uUBByBqBSzmGXEQ+xOgo0J -0b2qW42S0OzekMV/CsLj6+YxWl50PpczWejDAz1gM7/30W9HxM3uYoNSbi4ImqTZ -FRiRpoWSR7CuSOtttyHshRpocjWr//AQXcD0lKdq1TuSfkyQBX6TwSyLpI5idBVx -bgtxA+qvFTia1NIFcm+M+SvrWnIl+TlG43IbPgTDZCciECqKT1inA62+tC4T7V2q -SNfVfdQqe1z6RgRQ5MwOQluM7dvyz/yWk+DbETZUYjQ4jwxgmzuXVjit89Jbi6Bb -6k6WuHzX1aCGcEDTkSm3ojyt9Yy7zxqSiuQ0e8DYbF/pCsLDpyCaWt8sXVJcukfV -m+8kKHA4IC/VfynAskEDaJLM4JzMl0tF7zoQCqtwOpiVcK01seqFK6QcgCExqa5g -eoAmSAC4AcCTY1UikTxW56/bOiXzjzFU6iaLgVn5odFTEcV7nQP2dBHgbbEsPyyG -kZlxmqZ3izRg0RS0LKydr4wQ05/EavhvE/xzWfdmQnQeiuP43NJvmJzLR5iVQAX7 -6QIDAQABo4G/MIG8MA8GA1UdEwEB/wQFMAMBAf8wXQYIKwYBBQUHAQEEUTBPMCMG -CCsGAQUFBzABhhdodHRwOi8vb2NzcC5DQWNlcnQub3JnLzAoBggrBgEFBQcwAoYc -aHR0cDovL3d3dy5DQWNlcnQub3JnL2NhLmNydDBKBgNVHSAEQzBBMD8GCCsGAQQB -gZBKMDMwMQYIKwYBBQUHAgEWJWh0dHA6Ly93d3cuQ0FjZXJ0Lm9yZy9pbmRleC5w -aHA/aWQ9MTAwDQYJKoZIhvcNAQEEBQADggIBAH8IiKHaGlBJ2on7oQhy84r3HsQ6 -tHlbIDCxRd7CXdNlafHCXVRUPIVfuXtCkcKZ/RtRm6tGpaEQU55tiKxzbiwzpvD0 -nuB1wT6IRanhZkP+VlrRekF490DaSjrxC1uluxYG5sLnk7mFTZdPsR44Q4Dvmw2M -77inYACHV30eRBzLI++bPJmdr7UpHEV5FpZNJ23xHGzDwlVks7wU4vOkHx4y/CcV -Bc/dLq4+gmF78CEQGPZE6lM5+dzQmiDgxrvgu1pPxJnIB721vaLbLmINQjRBvP+L -ivVRIqqIMADisNS8vmW61QNXeZvo3MhN+FDtkaVSKKKs+zZYPumUK5FQhxvWXtaM -zPcPEAxSTtAWYeXlCmy/F8dyRlecmPVsYGN6b165Ti/Iubm7aoW8mA3t+T6XhDSU -rgCvoeXnkm5OvfPi2RSLXNLrAWygF6UtEOucekq9ve7O/e0iQKtwOIj1CodqwqsF -YMlIBdpTwd5Ed2qz8zw87YC8pjhKKSRf/lk7myV6VmMAZLldpGJ9VzZPrYPvH5JT -oI53V93lYRE9IwCQTDz6o2CTBKOvNfYOao9PSmCnhQVsRqGP9Md246FZV/dxssRu -FFxtbUFm3xuTsdQAw+7Lzzw9IYCpX2Nl/N3gX6T0K/CFcUHUZyX7GrGXrtaZghNB -0m6lG5kngOcLqagA ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIF8DCCA9igAwIBAgIPBuhGJy8fCo/RhFzjafbVMA0GCSqGSIb3DQEBBQUAMDgx -CzAJBgNVBAYTAkVTMRQwEgYDVQQKDAtJWkVOUEUgUy5BLjETMBEGA1UEAwwKSXpl -bnBlLmNvbTAeFw0wNzEyMTMxMzA4MjdaFw0zNzEyMTMwODI3MjVaMDgxCzAJBgNV -BAYTAkVTMRQwEgYDVQQKDAtJWkVOUEUgUy5BLjETMBEGA1UEAwwKSXplbnBlLmNv -bTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMnTesoPHqynhugWZWqx -whtFMnGV2f4QW8yv56V5AY+Jw8ryVXH3d753lPNypCxE2J6SmxQ6oeckkAoKVo7F -2CaU4dlI4S0+2gpy3aOZFdqBoof0e24md4lYrdbrDLJBenNubdt6eEHpCIgSfocu -ZhFjbFT7PJ1ywLwu/8K33Q124zrX97RovqL144FuwUZvXY3gTcZUVYkaMzEKsVe5 -o4qYw+w7NMWVQWl+dcI8IMVhulFHoCCQk6GQS/NOfIVFVJrRBSZBsLVNHTO+xAPI -JXzBcNs79AktVCdIrC/hxKw+yMuSTFM5NyPs0wH54AlETU1kwOENWocivK0bo/4m -tRXzp/yEGensoYi0RGmEg/OJ0XQGqcwL1sLeJ4VQJsoXuMl6h1YsGgEebL4TrRCs -tST1OJGh1kva8bvS3ke18byB9llrzxlT6Y0Vy0rLqW9E5RtBz+GGp8rQap+8TI0G -M1qiheWQNaBiXBZO8OOi+gMatCxxs1gs3nsL2xoP694hHwZ3BgOwye+Z/MC5TwuG -KP7Suerj2qXDR2kS4Nvw9hmL7Xtw1wLW7YcYKCwEJEx35EiKGsY7mtQPyvp10gFA -Wo15v4vPS8+qFsGV5K1Mij4XkdSxYuWC5YAEpAN+jb/af6IPl08M0w3719Hlcn4c -yHf/W5oPt64FRuXxqBbsR6QXAgMBAAGjgfYwgfMwgbAGA1UdEQSBqDCBpYEPaW5m -b0BpemVucGUuY29tpIGRMIGOMUcwRQYDVQQKDD5JWkVOUEUgUy5BLiAtIENJRiBB -MDEzMzcyNjAtUk1lcmMuVml0b3JpYS1HYXN0ZWl6IFQxMDU1IEY2MiBTODFDMEEG -A1UECQw6QXZkYSBkZWwgTWVkaXRlcnJhbmVvIEV0b3JiaWRlYSAxNCAtIDAxMDEw -IFZpdG9yaWEtR2FzdGVpejAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB -BjAdBgNVHQ4EFgQUHRxlDqjyJXu0kc/ksbHmvVV0bAUwDQYJKoZIhvcNAQEFBQAD -ggIBAMeBRm8hGE+gBe/n1bqXUKJg7aWSFBpSm/nxiEqg3Hh10dUflU7F57dp5iL0 -+CmoKom+z892j+Mxc50m0xwbRxYpB2iEitL7sRskPtKYGCwkjq/2e+pEFhsqxPqg -l+nqbFik73WrAGLRne0TNtsiC7bw0fRue0aHwp28vb5CO7dz0JoqPLRbEhYArxk5 -ja2DUBzIgU+9Ag89njWW7u/kwgN8KRwCfr00J16vU9adF79XbOnQgxCvv11N75B7 -XSus7Op9ACYXzAJcY9cZGKfsK8eKPlgOiofmg59OsjQerFQJTx0CCzl+gQgVuaBp -E8gyK+OtbBPWg50jLbJtooiGfqgNASYJQNntKE6MkyQP2/EeTXp6WuKlWPHcj1+Z -ggwuz7LdmMySlD/5CbOlliVbN/UShUHiGUzGigjB3Bh6Dx4/glmimj4/+eAJn/3B -kUtdyXvWton83x18hqrNA/ILUpLxYm9/h+qrdslsUMIZgq+qHfUgKGgu1fxkN0/P -pUTEvnK0jHS0bKf68r10OEMr3q/53NjgnZ/cPcqlY0S/kqJPTIAcuxrDmkoEVU3K -7iYLHL8CxWTTnn7S05EcS6L1HOUXHA0MUqORH5zwIe0ClG+poEnK6EOMxPQ02nwi -o8ZmPrgbBYhdurz3vOXcFD2nhqi2WVIhA16L4wTtSyoeo09Q ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICsDCCAhmgAwIBAgIQZ8jh6OO+HL38kTuOpiOHSTANBgkqhkiG9w0BAQUFADCB -izELMAkGA1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTEUMBIGA1UEBxML -RHVyYmFudmlsbGUxDzANBgNVBAoTBlRoYXd0ZTEdMBsGA1UECxMUVGhhd3RlIENl -cnRpZmljYXRpb24xHzAdBgNVBAMTFlRoYXd0ZSBUaW1lc3RhbXBpbmcgQ0EwHhcN -OTcwMTAxMDAwMDAwWhcNMjEwMTAxMjM1OTU5WjCBizELMAkGA1UEBhMCWkExFTAT -BgNVBAgTDFdlc3Rlcm4gQ2FwZTEUMBIGA1UEBxMLRHVyYmFudmlsbGUxDzANBgNV -BAoTBlRoYXd0ZTEdMBsGA1UECxMUVGhhd3RlIENlcnRpZmljYXRpb24xHzAdBgNV -BAMTFlRoYXd0ZSBUaW1lc3RhbXBpbmcgQ0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0A -MIGJAoGBANYrWHhhRYZT6jR7UZztsOYuGA7+4F+oJ9O0yeB8WU4WDnNUYMF/9p8u -6TqFJBU820cEY8OexJQaWt9MevPZQx08EHp5JduQ/vBR5zDWQQD9nyjfeb6Uu522 -FOMjhdepQeBMpHmwKxqL8vg7ij5FrHGSALSQQZj7X+36ty6K+Ig3AgMBAAGjEzAR -MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAS+mqF4EF+3kKMZ/F -QfRWVKvpwuWXjhj+kckMPiZkyaFMJ2SnvQGTVXFuF0853BvcSTUQOSP/ypvIz2Y/ -3Ewa1IEGQlIf4SaxFhe65nByMUToTo1b5NP50OOPJWQx5yr4GIg2GlLFDUE1G2m3 -JvUXzMEZXkt8XOKDgJH6L/uatxY= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDtDCCApygAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJKUDEc -MBoGA1UEChMTSmFwYW5lc2UgR292ZXJubWVudDEOMAwGA1UECxMFTVBIUFQxJjAk -BgNVBAsTHU1QSFBUIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTAyMDMxNDA3 -NTAyNloXDTEyMDMxMzE0NTk1OVowYzELMAkGA1UEBhMCSlAxHDAaBgNVBAoTE0ph -cGFuZXNlIEdvdmVybm1lbnQxDjAMBgNVBAsTBU1QSFBUMSYwJAYDVQQLEx1NUEhQ -VCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEP -ADCCAQoCggEBAI3GUWlK9G9FVm8DhpKu5t37oxZbj6lZcFvEZY07YrYojWO657ub -z56WE7q/PI/6Sm7i7qYE+Vp80r6thJvfmn7SS3BENrRqiapSenhooYD12jIe3iZQ -2SXqx7WgYwyBGdQwGaYTijzbRFpgc0K8o4a99fIoHhz9J8AKqXasddMCqfJRaH30 -YJ7HnOvRYGL6HBrGhJ7X4Rzijyk9a9+3VOBsYcnIlx9iODoiYhA6r0ojuIu8/JA1 -oTTZrS0MyU/SLdFdJze2O1wnqTULXQybzJz3ad6oC/F5a69c0m92akYd9nGBrPxj -EhucaQynC/QoCLs3aciLgioAnEJqy7i3EgUCAwEAAaNzMHEwHwYDVR0jBBgwFoAU -YML3pLoA0h93Yngl8Gb/UgAh73owHQYDVR0OBBYEFGDC96S6ANIfd2J4JfBm/1IA -Ie96MAwGA1UdEwQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQE -AwIABTANBgkqhkiG9w0BAQUFAAOCAQEANPR8DN66iWZBs/lSm1vOzhqRkXDLT6xL -LvJtjPLqmE469szGyFSKzsof6y+/8YgZlOoeX1inF4ox/SH1ATnwdIIsPbXuRLjt -axboXvBh5y2ffC3hmzJVvJ87tb6mVWQeL9VFUhNhAI0ib+9OIZVEYI/64MFkDk4e -iWG5ts6oqIJH1V7dVZg6pQ1Tc0Ckhn6N1m1hD30S0/zoPn/20Wq6OCF3he8VJrRG -dcW9BD/Bkesko1HKhMBDjHVrJ8cFwbnDSoo+Ki47eJWaz/cOzaSsaMVUsR5POava -/abhhgHn/eOJdXiVslyK0DYscjsdB3aBUfwZlomxYOzG6CgjQPhJdw== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEejCCA2KgAwIBAgIEP4vk6TANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQGEwJQ -TDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2Vu -dHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MR8wHQYDVQQDExZDQyBTaWduZXQgLSBD -QSBLbGFzYSAyMB4XDTAzMTAxNDExNTgyMloXDTE3MDQxODEyNTMwN1owdzELMAkG -A1UEBhMCUEwxHzAdBgNVBAoTFlRQIEludGVybmV0IFNwLiB6IG8uby4xJDAiBgNV -BAsTG0NlbnRydW0gQ2VydHlmaWthY2ppIFNpZ25ldDEhMB8GA1UEAxMYQ0MgU2ln -bmV0IC0gT0NTUCBLbGFzYSAyMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCo -VCsaBStblXQYVNthe3dvaCrfvKpPXngh4almm988iIlEv9CVTaAdCfaJNihvA+Vs -Qw8++ix1VqteMQE474/MV/YaXigP0Zr0QB+g+/7PWVlv+5U9Gzp9+Xx4DJay8AoI -iB7Iy5Qf9iZiHm5BiPRIuUXT4ZRbZRYPh0/76vgRsQIDAQABo4IBkjCCAY4wDgYD -VR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMJMEEGA1UdHwQ6MDgwNqA0 -oDKGMGh0dHA6Ly93d3cuc2lnbmV0LnBsL3JlcG96eXRvcml1bS9jcmwva2xhc2Ey -LmNybDCB2AYDVR0gBIHQMIHNMIHKBg4rBgEEAb4/AoFICgwBADCBtzBsBggrBgEF -BQcCAjBgGl5DZXJ0eWZpa2F0IHd5ZGFueSB6Z29kbmllIHogZG9rdW1lbnRlbSAi -UG9saXR5a2EgQ2VydHlmaWthY2ppIC0gQ2VydHlmaWthdHkgcmVzcG9uZGVyb3cg -T0NTUCIuMEcGCCsGAQUFBwIBFjtodHRwOi8vd3d3LnNpZ25ldC5wbC9yZXBvenl0 -b3JpdW0vZG9rdW1lbnR5L3BjX29jc3BfMV8wLnBkZjAfBgNVHSMEGDAWgBS7RQZS -C8uBzSlUs7x8QUzNBw6MJTAdBgNVHQ4EFgQUKEVrOY7cEHvsVgvoyZdytlbtgwEw -CQYDVR0TBAIwADANBgkqhkiG9w0BAQUFAAOCAQEAQrRg5MV6dxr0HU2IsLInxhvt -iUVmSFkIUsBCjzLoewOXA16d2oDyHhI/eE+VgAsp+2ANjZu4xRteHIHoYMsN218M -eD2MLRsYS0U9xxAFK9gDj/KscPbrrdoqLvtPSMhUb4adJS9HLhvUe6BicvBf3A71 -iCNe431axGNDWKnpuj2KUpj4CFHYsWCXky847YtTXDjri9NIwJJauazsrSjK+oXp -ngRS506mdQ7vWrtApkh8zhhWp7duCkjcCo1O8JxqYr2qEW1fXmgOISe010v2mmuv -hHxPyVwoAU4KkOw0nbXZn53yak0is5+XmAjh0wWue44AssHrjC9nUh3mkLt6eQ== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBI -MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x -FzAVBgNVBAMTDlNlY3VyZVRydXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIz -MTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1NlY3VyZVRydXN0IENv -cnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCCASIwDQYJKoZIhvcN -AQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQXOZEz -Zum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO -0gMdA+9tDWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIao -wW8xQmxSPmjL8xk037uHGFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj -7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b01k/unK8RCSc43Oz969XL0Imnal0ugBS -8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmHursCAwEAAaOBnTCBmjAT -BgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB -/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCeg -JYYjaHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGC -NxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt3 -6Z3q059c4EVlew3KW+JwULKUBRSuSceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/ -3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHfmbx8IVQr5Fiiu1cprp6poxkm -D5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZnMUFdAvnZyPS -CPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR -3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIIODCCB6GgAwIBAgIBADANBgkqhkiG9w0BAQUFADCCAR4xCzAJBgNVBAYTAkVT -MRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UE -ChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5sLjErMCkGA1UE -ChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1MjE0MDIGA1UECxMr -SVBTIENBIFRpbWVzdGFtcGluZyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTE0MDIG -A1UEAxMrSVBTIENBIFRpbWVzdGFtcGluZyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 -eTEeMBwGCSqGSIb3DQEJARYPaXBzQG1haWwuaXBzLmVzMB4XDTAxMTIyOTAxMTAx -OFoXDTI1MTIyNzAxMTAxOFowggEeMQswCQYDVQQGEwJFUzESMBAGA1UECBMJQmFy -Y2Vsb25hMRIwEAYDVQQHEwlCYXJjZWxvbmExLjAsBgNVBAoTJUlQUyBJbnRlcm5l -dCBwdWJsaXNoaW5nIFNlcnZpY2VzIHMubC4xKzApBgNVBAoUImlwc0BtYWlsLmlw -cy5lcyBDLkkuRi4gIEItNjA5Mjk0NTIxNDAyBgNVBAsTK0lQUyBDQSBUaW1lc3Rh -bXBpbmcgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxNDAyBgNVBAMTK0lQUyBDQSBU -aW1lc3RhbXBpbmcgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxHjAcBgkqhkiG9w0B -CQEWD2lwc0BtYWlsLmlwcy5lczCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA -vLjuVqWajOY2ycJioGaBjRrVetJznw6EZLqVtJCneK/K/lRhW86yIFcBrkSSQxA4 -Efdo/BdApWgnMjvEp+ZCccWZ73b/K5Uk9UmSGGjKALWkWi9uy9YbLA1UZ2t6KaFY -q6JaANZbuxjC3/YeE1Z2m6Vo4pjOxgOKNNtMg0GmqaMCAwEAAaOCBIAwggR8MB0G -A1UdDgQWBBSL0BBQCYHynQnVDmB4AyKiP8jKZjCCAVAGA1UdIwSCAUcwggFDgBSL -0BBQCYHynQnVDmB4AyKiP8jKZqGCASakggEiMIIBHjELMAkGA1UEBhMCRVMxEjAQ -BgNVBAgTCUJhcmNlbG9uYTESMBAGA1UEBxMJQmFyY2Vsb25hMS4wLAYDVQQKEyVJ -UFMgSW50ZXJuZXQgcHVibGlzaGluZyBTZXJ2aWNlcyBzLmwuMSswKQYDVQQKFCJp -cHNAbWFpbC5pcHMuZXMgQy5JLkYuICBCLTYwOTI5NDUyMTQwMgYDVQQLEytJUFMg -Q0EgVGltZXN0YW1waW5nIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MTQwMgYDVQQD -EytJUFMgQ0EgVGltZXN0YW1waW5nIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MR4w -HAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXOCAQAwDAYDVR0TBAUwAwEB/zAM -BgNVHQ8EBQMDB/+AMGsGA1UdJQRkMGIGCCsGAQUFBwMBBggrBgEFBQcDAgYIKwYB -BQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYKKwYBBAGCNwIBFQYKKwYBBAGCNwIB -FgYKKwYBBAGCNwoDAQYKKwYBBAGCNwoDBDARBglghkgBhvhCAQEEBAMCAAcwGgYD -VR0RBBMwEYEPaXBzQG1haWwuaXBzLmVzMBoGA1UdEgQTMBGBD2lwc0BtYWlsLmlw -cy5lczBHBglghkgBhvhCAQ0EOhY4VGltZXN0YW1waW5nIENBIENlcnRpZmljYXRl -IGlzc3VlZCBieSBodHRwOi8vd3d3Lmlwcy5lcy8wKQYJYIZIAYb4QgECBBwWGmh0 -dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvMEAGCWCGSAGG+EIBBAQzFjFodHRwOi8v -d3d3Lmlwcy5lcy9pcHMyMDAyL2lwczIwMDJUaW1lc3RhbXBpbmcuY3JsMEUGCWCG -SAGG+EIBAwQ4FjZodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL3Jldm9jYXRpb25U -aW1lc3RhbXBpbmcuaHRtbD8wQgYJYIZIAYb4QgEHBDUWM2h0dHA6Ly93d3cuaXBz -LmVzL2lwczIwMDIvcmVuZXdhbFRpbWVzdGFtcGluZy5odG1sPzBABglghkgBhvhC -AQgEMxYxaHR0cDovL3d3dy5pcHMuZXMvaXBzMjAwMi9wb2xpY3lUaW1lc3RhbXBp -bmcuaHRtbDB/BgNVHR8EeDB2MDegNaAzhjFodHRwOi8vd3d3Lmlwcy5lcy9pcHMy -MDAyL2lwczIwMDJUaW1lc3RhbXBpbmcuY3JsMDugOaA3hjVodHRwOi8vd3d3YmFj -ay5pcHMuZXMvaXBzMjAwMi9pcHMyMDAyVGltZXN0YW1waW5nLmNybDAvBggrBgEF -BQcBAQQjMCEwHwYIKwYBBQUHMAGGE2h0dHA6Ly9vY3NwLmlwcy5lcy8wDQYJKoZI -hvcNAQEFBQADgYEAZbrBzAAalZHK6Ww6vzoeFAh8+4Pua2JR0zORtWB5fgTYXXk3 -6MNbsMRnLWhasl8OCvrNPzpFoeo2zyYepxEoxZSPhExTCMWTs/zif/WN87GphV+I -3pGW7hdbrqXqcGV4LCFkAZXOzkw+UPS2Wctjjba9GNSHSl/c7+lW8AoM6HU= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFujCCBKKgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBhjELMAkGA1UEBhMCVVMx -HTAbBgNVBAoTFEFwcGxlIENvbXB1dGVyLCBJbmMuMS0wKwYDVQQLEyRBcHBsZSBD -b21wdXRlciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxKTAnBgNVBAMTIEFwcGxlIFJv -b3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTA1MDIxMDAwMTgxNFoXDTI1MDIx -MDAwMTgxNFowgYYxCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRBcHBsZSBDb21wdXRl -ciwgSW5jLjEtMCsGA1UECxMkQXBwbGUgQ29tcHV0ZXIgQ2VydGlmaWNhdGUgQXV0 -aG9yaXR5MSkwJwYDVQQDEyBBcHBsZSBSb290IENlcnRpZmljYXRlIEF1dGhvcml0 -eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOSRqQkfkdseR1DrBe1e -eYQt6zaiV0xV7IsZid75S2z1B6siMALoGD74UAnTf0GomPnRymacJGsR0KO75Bsq -wx+VnnoMpEeLW9QWNzPLxA9NzhRp0ckZcvVdDtV/X5vyJQO6VY9NXQ3xZDUjFUsV -WR2zlPf2nJ7PULrBWFBnjwi0IPfLrCwgb3C2PwEwjLdDzw+dPfMrSSgayP7OtbkO -2V4c1ss9tTqt9A8OAJILsSEWLnTVPA3bYharo3GSR1NVwa8vQbP4++NwzeajTEV+ -H0xrUJZBicR0YgsQg0GHM4qBsTBY7FoEMoxos48d3mVz/2deZbxJ2HafMxRloXeU -yS0CAwEAAaOCAi8wggIrMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/ -MB0GA1UdDgQWBBQr0GlHlHYJ/vRrjS5ApvdHTX8IXjAfBgNVHSMEGDAWgBQr0GlH -lHYJ/vRrjS5ApvdHTX8IXjCCASkGA1UdIASCASAwggEcMIIBGAYJKoZIhvdjZAUB -MIIBCTBBBggrBgEFBQcCARY1aHR0cHM6Ly93d3cuYXBwbGUuY29tL2NlcnRpZmlj -YXRlYXV0aG9yaXR5L3Rlcm1zLmh0bWwwgcMGCCsGAQUFBwICMIG2GoGzUmVsaWFu -Y2Ugb24gdGhpcyBjZXJ0aWZpY2F0ZSBieSBhbnkgcGFydHkgYXNzdW1lcyBhY2Nl -cHRhbmNlIG9mIHRoZSB0aGVuIGFwcGxpY2FibGUgc3RhbmRhcmQgdGVybXMgYW5k -IGNvbmRpdGlvbnMgb2YgdXNlLCBjZXJ0aWZpY2F0ZSBwb2xpY3kgYW5kIGNlcnRp -ZmljYXRpb24gcHJhY3RpY2Ugc3RhdGVtZW50cy4wRAYDVR0fBD0wOzA5oDegNYYz -aHR0cHM6Ly93d3cuYXBwbGUuY29tL2NlcnRpZmljYXRlYXV0aG9yaXR5L3Jvb3Qu -Y3JsMFUGCCsGAQUFBwEBBEkwRzBFBggrBgEFBQcwAoY5aHR0cHM6Ly93d3cuYXBw -bGUuY29tL2NlcnRpZmljYXRlYXV0aG9yaXR5L2Nhc2lnbmVycy5odG1sMA0GCSqG -SIb3DQEBBQUAA4IBAQCd2i0oWC99dgS5BNM+zrdmY06PL9T+S61yvaM5xlJNBZhS -9YlRASR5vhoy9+VEi0tEBzmC1lrKtCBe2a4VXR2MHTK/ODFiSF3H4ZCx+CRA+F9Y -m1FdV53B5f88zHIhbsTp6aF31ywXJsM/65roCwO66bNKcuszCVut5mIxauivL9Wv -Hld2j383LS4CXN1jyfJxuCZA3xWNdUQ/eb3mHZnhQyw+rW++uaT+DjUZUWOxw961 -kj5ReAFziqQjyqSI8R5cH0EWLX6VCqrpiUGYGxrdyyC/R14MJsVVNU3GMIuZZxTH -CR+6R8faAQmHJEKVvRNgGQrv6n8Obs3BREM6StXj ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIID4TCCAsmgAwIBAgIOYyUAAQACFI0zFQLkbPQwDQYJKoZIhvcNAQEFBQAwezEL -MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNV -BAsTG1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQTEoMCYGA1UEAxMfVEMgVHJ1 -c3RDZW50ZXIgVW5pdmVyc2FsIENBIElJSTAeFw0wOTA5MDkwODE1MjdaFw0yOTEy -MzEyMzU5NTlaMHsxCzAJBgNVBAYTAkRFMRwwGgYDVQQKExNUQyBUcnVzdENlbnRl -ciBHbWJIMSQwIgYDVQQLExtUQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0ExKDAm -BgNVBAMTH1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQSBJSUkwggEiMA0GCSqG -SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDC2pxisLlxErALyBpXsq6DFJmzNEubkKLF -5+cvAqBNLaT6hdqbJYUtQCggbergvbFIgyIpRJ9Og+41URNzdNW88jBmlFPAQDYv -DIRlzg9uwliT6CwLOunBjvvya8o84pxOjuT5fdMnnxvVZ3iHLX8LR7PH6MlIfK8v -zArZQe+f/prhsq75U7Xl6UafYOPfjdN/+5Z+s7Vy+EutCHnNaYlAJ/Uqwa1D7KRT -yGG299J5KmcYdkhtWyUB0SbFt1dpIxVbYYqt8Bst2a9c8SaQaanVDED1M4BDj5yj -dipFtK+/fz6HP3bFzSreIMUWWMv5G/UPyw0RUmS40nZid4PxWJ//AgMBAAGjYzBh -MB8GA1UdIwQYMBaAFFbn4VslQ4Dg9ozhcbyO5YAvxEjiMA8GA1UdEwEB/wQFMAMB -Af8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRW5+FbJUOA4PaM4XG8juWAL8RI -4jANBgkqhkiG9w0BAQUFAAOCAQEAg8ev6n9NCjw5sWi+e22JLumzCecYV42Fmhfz -dkJQEw/HkG8zrcVJYCtsSVgZ1OK+t7+rSbyUyKu+KGwWaODIl0YgoGhnYIg5IFHY -aAERzqf2EQf27OysGh+yZm5WZ2B6dF7AbZc2rrUNXWZzwCUyRdhKBgePxLcHsU0G -DeGl6/R1yrqc0L2z0zIkTO5+4nYES0lT2PLpVDP85XEfPRRclkvxOvIAu2y0+pZV -CIgJwcyRGSmwIC3/yzikQOEXvnlhgP8HA4ZMTnsGnxGGjYnuJ8Tb4rwZjgvDwxPH -LQNjO9Po5KIqwoIIlBZU8O8fJ5AluA0OKBtHd0e9HKgl8ZS0Zg== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDvjCCA3ygAwIBAgIFJQaThoEwCwYHKoZIzjgEAwUAMIGFMQswCQYDVQQGEwJG -UjEPMA0GA1UECBMGRnJhbmNlMQ4wDAYDVQQHEwVQYXJpczEQMA4GA1UEChMHUE0v -U0dETjEOMAwGA1UECxMFRENTU0kxDjAMBgNVBAMTBUlHQy9BMSMwIQYJKoZIhvcN -AQkBFhRpZ2NhQHNnZG4ucG0uZ291di5mcjAeFw0wMjEyMTMxNDM5MTVaFw0yMDEw -MTcxNDM5MTRaMIGFMQswCQYDVQQGEwJGUjEPMA0GA1UECBMGRnJhbmNlMQ4wDAYD -VQQHEwVQYXJpczEQMA4GA1UEChMHUE0vU0dETjEOMAwGA1UECxMFRENTU0kxDjAM -BgNVBAMTBUlHQy9BMSMwIQYJKoZIhvcNAQkBFhRpZ2NhQHNnZG4ucG0uZ291di5m -cjCCAbYwggErBgcqhkjOOAQBMIIBHgKBgQCFkMImdk9zDzJfTO4XPdAAmLbAdWws -ZiEMZh19RyTo3CyhFqO77OIXrwY6vc1pcc3MgWJ0dgQpAgrDMtmFFxpUu4gmjVsx -8GpxQC+4VOgLY8Cvmcd/UDzYg07EIRto8BwCpPJ/JfUxwzV2V3N713aAX+cEoKZ/ -s+kgxC6nZCA7oQIVALME/JYjkdW2uKIGngsEPbXAjdhDAoGADh/uqWJx94UBm31c -9d8ZTBfRGRnmSSRVFDgPWgA69JD4BR5da8tKz+1HjfMhDXljbMH86ixpD5Ka1Z0V -pRYUPbyAoB37tsmXMJY7kjyD19d5VdaZboUjVvhH6UJy5lpNNNGSvFl4fqkxyvw+ -pq1QV0N5RcvK120hlXdfHUX+YKYDgYQAAoGAQGr7IuKJcYIvJRMjxwl43KxXY2xC -aoCiM/bv117MfI94aNf1UusGhp7CbYAY9CXuL60P0oPMAajbaTE5Z34AuITeHq3Y -CNMHwxalip8BHqSSGmGiQsXeK7T+r1rPXsccZ1c5ikGDZ4xn5gUaCyy2rCmb+fOJ -6VAfCbAbAjmNKwejdzB1MA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgFGMBUG -A1UdIAQOMAwwCgYIKoF6AXkBAQEwHQYDVR0OBBYEFPkeNRcUf8idzpKblYbLNxs0 -MQhSMB8GA1UdIwQYMBaAFPkeNRcUf8idzpKblYbLNxs0MQhSMAsGByqGSM44BAMF -AAMvADAsAhRVh+CJA5eVyEYU5AO9Tm7GxX0rmQIUBCqsU5u1WxoZ5lEXicDX5/Ob -sRQ= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl -MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp -U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw -NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE -ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp -ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3 -DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf -8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN -+lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0 -X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa -K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA -1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G -A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR -zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0 -YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD -bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w -DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3 -L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D -eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl -xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp -VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY -WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJ -BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh -c3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy -MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp -emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X -DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw -FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMg -UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo -YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5 -MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB -AQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCOFoUgRm1HP9SFIIThbbP4 -pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71lSk8UOg0 -13gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwID -AQABMA0GCSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSk -U01UbSuvDV1Ai2TT1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7i -F6YM40AIOw7n60RzKprxaZLvcRTDOaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpY -oJ2daZH9 ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNV -BAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4X -DTA3MDYyOTE1MTMwNVoXDTI3MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQ -BgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwIQ2VydGlnbmEwggEiMA0GCSqGSIb3 -DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7qXOEm7RFHYeGifBZ4 -QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyHGxny -gQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbw -zBfsV1/pogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q -130yGLMLLGq/jj8UEYkgDncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2 -JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKfIrjxwo1p3Po6WAbfAgMBAAGjgbwwgbkw -DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQtCRZvgHyUtVF9lo53BEw -ZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJBgNVBAYT -AkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzj -AQ/JSP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG -9w0BAQUFAAOCAQEAhQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8h -bV6lUmPOEvjvKtpv6zf+EwLHyzs+ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFnc -fca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1kluPBS1xp81HlDQwY9qcEQCYsuu -HWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY1gkIl2PlwS6w -t0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw -WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG -A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv -b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw -MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i -YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT -aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ -jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp -xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp -1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG -snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ -U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8 -9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E -BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B -AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz -yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE -38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP -AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad -DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME -HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDIDCCAgigAwIBAgIBJDANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEP -MA0GA1UEChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MxIENBMB4XDTAx -MDQwNjEwNDkxM1oXDTIxMDQwNjEwNDkxM1owOTELMAkGA1UEBhMCRkkxDzANBgNV -BAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJhIENsYXNzMSBDQTCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBALWJHytPZwp5/8Ue+H887dF+2rDNbS82rDTG -29lkFwhjMDMiikzujrsPDUJVyZ0upe/3p4zDq7mXy47vPxVnqIJyY1MPQYx9EJUk -oVqlBvqSV536pQHydekfvFYmUk54GWVYVQNYwBSujHxVX3BbdyMGNpfzJLWaRpXk -3w0LBUXl0fIdgrvGE+D+qnr9aTCU89JFhfzyMlsy3uhsXR/LpCJ0sICOXZT3BgBL -qdReLjVQCfOAl/QMF6452F/NM8EcyonCIvdFEu1eEpOdY6uCLrnrQkFEy0oaAIIN -nvmLVz5MxxftLItyM19yejhW1ebZrgUaHXVFsculJRwSVzb9IjcCAwEAAaMzMDEw -DwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQIR+IMi/ZTiFIwCwYDVR0PBAQDAgEG -MA0GCSqGSIb3DQEBBQUAA4IBAQCLGrLJXWG04bkruVPRsoWdd44W7hE928Jj2VuX -ZfsSZ9gqXLar5V7DtxYvyOirHYr9qxp81V9jz9yw3Xe5qObSIjiHBxTZ/75Wtf0H -DjxVyhbMp6Z3N/vbXB9OWQaHowND9Rart4S9Tu+fMTfwRvFAttEMpWT4Y14h21VO -TzF2nBBhjrZTOqMRvq9tfB69ri3iDGnHhVNoomG6xT60eVR4ngrHAr5i0RGCS2Uv -kVrCqIexVmiUefkl98HVrhq4uz2PqYo4Ffdz0Fpg0YCw8NzVUM1O7pJIae2yIx4w -zMiUyLb1O4Z/P6Yun/Y+LLWSlj7fLJOK/4GMDw9ZIRlXvVWa ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIF5jCCA86gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBgzELMAkGA1UEBhMCVVMx -HTAbBgNVBAoTFEFPTCBUaW1lIFdhcm5lciBJbmMuMRwwGgYDVQQLExNBbWVyaWNh -IE9ubGluZSBJbmMuMTcwNQYDVQQDEy5BT0wgVGltZSBXYXJuZXIgUm9vdCBDZXJ0 -aWZpY2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyOTA2MDAwMFoXDTM3MDkyODIz -NDMwMFowgYMxCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRBT0wgVGltZSBXYXJuZXIg -SW5jLjEcMBoGA1UECxMTQW1lcmljYSBPbmxpbmUgSW5jLjE3MDUGA1UEAxMuQU9M -IFRpbWUgV2FybmVyIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMjCCAiIw -DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQ3WggWmRToVbEbJGv8x4vmh6mJ -7ouZzU9AhqS2TcnZsdw8TQ2FTBVsRotSeJ/4I/1n9SQ6aF3Q92RhQVSji6UI0ilb -m2BPJoPRYxJWSXakFsKlnUWsi4SVqBax7J/qJBrvuVdcmiQhLE0OcR+mrF1FdAOY -xFSMFkpBd4aVdQxHAWZg/BXxD+r1FHjHDtdugRxev17nOirYlxcwfACtCJ0zr7iZ -YYCLqJV+FNwSbKTQ2O9ASQI2+W6p1h2WVgSysy0WVoaP2SBXgM1nEG2wTPDaRrbq -JS5Gr42whTg0ixQmgiusrpkLjhTXUr2eacOGAgvqdnUxCc4zGSGFQ+aJLZ8lN2fx -I2rSAG2X+Z/nKcrdH9cG6rjJuQkhn8g/BsXS6RJGAE57COtCPStIbp1n3UsC5ETz -kxmlJ85per5n0/xQpCyrw2u544BMzwVhSyvcG7mm0tCq9Stz+86QNZ8MUhy/XCFh -EVsVS6kkUfykXPcXnbDS+gfpj1bkGoxoigTTfFrjnqKhynFbotSg5ymFXQNoKk/S -Btc9+cMDLz9l+WceR0DTYw/j1Y75hauXTLPXJuuWCpTehTacyH+BCQJJKg71ZDIM -gtG6aoIbs0t0EfOMd9afv9w3pKdVBC/UMejTRrkDfNoSTllkt1ExMVCgyhwn2RAu -rda9EGYrw7AiShJbAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE -FE9pbQN+nZ8HGEO8txBO1b+pxCAoMB8GA1UdIwQYMBaAFE9pbQN+nZ8HGEO8txBO -1b+pxCAoMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAgEAO/Ouyugu -h4X7ZVnnrREUpVe8WJ8kEle7+z802u6teio0cnAxa8cZmIDJgt43d15Ui47y6mdP -yXSEkVYJ1eV6moG2gcKtNuTxVBFT8zRFASbI5Rq8NEQh3q0l/HYWdyGQgJhXnU7q -7C+qPBR7V8F+GBRn7iTGvboVsNIYvbdVgaxTwOjdaRITQrcCtQVBynlQboIOcXKT -RuidDV29rs4prWPVVRaAMCf/drr3uNZK49m1+VLQTkCpx+XCMseqdiThawVQ68W/ -ClTluUI8JPu3B5wwn3la5uBAUhX0/Kr0VvlEl4ftDmVyXr4m+02kLQgH3thcoNyB -M5kYJRF3p+v9WAksmWsbivNSPxpNSGDxoPYzAlOL7SUJuA0t7Zdz7NeWH45gDtoQ -my8YJPamTQr5O8t1wswvziRpyQoijlmn94IM19drNZxDAGrElWe6nEXLuA4399xO -AU++CrYD062KRffaJ00psUjf5BHklka9bAI+1lHIlRcBFanyqqryvy9lG2/QuRqT -9Y41xICHPpQvZuTpqP9BnHAqTyo5GJUefvthATxRCC4oGKQWDzH9OmwjkyB24f0H -hdFbP9IcczLd+rn4jM8Ch3qaluTtT4mNU0OrDhPAARW0eTjb/G49nlG2uBOLZ8/5 -fNkiHfZdxRwBL5joeiQYvITX+txyW/fBOmg= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDIDCCAomgAwIBAgIEN3DPtTANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV -UzEXMBUGA1UEChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2Vj -dXJlIGVCdXNpbmVzcyBDQS0yMB4XDTk5MDYyMzEyMTQ0NVoXDTE5MDYyMzEyMTQ0 -NVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkVxdWlmYXggU2VjdXJlMSYwJAYD -VQQLEx1FcXVpZmF4IFNlY3VyZSBlQnVzaW5lc3MgQ0EtMjCBnzANBgkqhkiG9w0B -AQEFAAOBjQAwgYkCgYEA5Dk5kx5SBhsoNviyoynF7Y6yEb3+6+e0dMKP/wXn2Z0G -vxLIPw7y1tEkshHe0XMJitSxLJgJDR5QRrKDpkWNYmi7hRsgcDKqQM2mll/EcTc/ -BPO3QSQ5BxoeLmFYoBIL5aXfxavqN3HMHMg3OrmXUqesxWoklE6ce8/AatbfIb0C -AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEX -MBUGA1UEChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2VjdXJl -IGVCdXNpbmVzcyBDQS0yMQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTkw -NjIzMTIxNDQ1WjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUUJ4L6q9euSBIplBq -y/3YIHqngnYwHQYDVR0OBBYEFFCeC+qvXrkgSKZQasv92CB6p4J2MAwGA1UdEwQF -MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA -A4GBAAyGgq3oThr1jokn4jVYPSm0B482UJW/bsGe68SQsoWou7dC4A8HOd/7npCy -0cE+U58DRLB+S/Rv5Hwf5+Kx5Lia78O9zt4LMjTZ3ijtM2vE1Nc9ElirfQkty3D1 -E4qUoSek1nDFbZS1yX2doNLGCEnZZpum0/QL3MUmV+GRMOrN ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBe -MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0 -ZC4xKjAoBgNVBAsMIWVQS0kgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe -Fw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMxMjdaMF4xCzAJBgNVBAYTAlRXMSMw -IQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEqMCgGA1UECwwhZVBL -SSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEF -AAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAH -SyZbCUNsIZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAh -ijHyl3SJCRImHJ7K2RKilTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3X -DZoTM1PRYfl61dd4s5oz9wCGzh1NlDivqOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1 -TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX12ruOzjjK9SXDrkb5wdJ -fzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0OWQqraffA -sgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uU -WH1+ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLS -nT0IFaUQAS2zMnaolQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pH -dmX2Os+PYhcZewoozRrSgx4hxyy/vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJip -NiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXiZo1jDiVN1Rmy5nk3pyKdVDEC -AwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/QkqiMAwGA1UdEwQF -MAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH -ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGB -uvl2ICO1J2B01GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6Yl -PwZpVnPDimZI+ymBV3QGypzqKOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkP -JXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdVxrsStZf0X4OFunHB2WyBEXYKCrC/ -gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEPNXubrjlpC2JgQCA2 -j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+rGNm6 -5ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUB -o2M3IUxExJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS -/jQ6fbjpKdx2qcgw+BRxgMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2z -Gp1iro2C6pSe3VkQw63d4k3jMdXH7OjysP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTE -W9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmODBCEIZ43ygknQW/2xzQ+D -hNQ+IIX3Sj0rnP0qCglN6oH4EZw= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIF3zCCA8egAwIBAgIOGTMAAQACKBqaBLzyVUUwDQYJKoZIhvcNAQEFBQAwejEL -MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNV -BAsTG1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQTEnMCUGA1UEAxMeVEMgVHJ1 -c3RDZW50ZXIgVW5pdmVyc2FsIENBIElJMB4XDTA2MDMyMjE1NTgzNFoXDTMwMTIz -MTIyNTk1OVowejELMAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVy -IEdtYkgxJDAiBgNVBAsTG1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQTEnMCUG -A1UEAxMeVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBIElJMIICIjANBgkqhkiG -9w0BAQEFAAOCAg8AMIICCgKCAgEAi9R3azRs5TbYalxeOO781R15Azt7g2JEgk6I -7d6D/+7MUGIFBZWZdpj2ufJf2AaRksL2LWYXH/1TA+iojWOpbuHWG4y8mLOLO9Tk -Lsp9hUkmW3m4GotAnn+7yT9jLM/RWny6KCJBElpN+Rd3/IX9wkngKhh/6aAsnPlE -/AxoOUL1JwW+jhV6YJ3wO8c85j4WvK923mq3ouGrRkXrjGV90ZfzlxElq1nroCLZ -gt2Y7X7i+qBhCkoy3iwX921E6oFHWZdXNwM53V6CItQzuPomCba8OYgvURVOm8M7 -3xOCiN1LNPIz1pDp81PcNXzAw9l8eLPNcD+NauCjgUjkKa1juPD8KGQ7mbN9/pqd -iPaZIgiRRxaJNXhdd6HPv0nh/SSUK2k2e+gc5iqQilvVOzRZQtxtz7sPQRxVzfUN -Wy4WIibvYR6X/OJTyM9bo8ep8boOhhLLE8oVx+zkNo3aXBM9ZdIOXXB03L+PemrB -Lg/Txl4PK1lszGFs/sBhTtnmT0ayWuIZFHCE+CAA7QGnl37DvRJckiMXoKUdRRcV -I5qSCLUiiI3cKyTr4LEXaNOvYb3ZhXj2jbp4yjeNY77nrB/fpUcJucglMVRGURFV -DYlcjdrSGC1z8rjVJ/VIIjfRYvd7Dcg4i6FKsPzQ8eu3hmPn4A5zf/1yUbXpfeJV -BWR4Z38CAwEAAaNjMGEwHwYDVR0jBBgwFoAUzdeQoW6jv9sw1toyJZAM5jkegGUw -DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFM3XkKFu -o7/bMNbaMiWQDOY5HoBlMA0GCSqGSIb3DQEBBQUAA4ICAQB+FojoEw42zG4qhQc4 -xlaJeuNHIWZMUAgxWlHQ/KZeFHXeTDvs8e3MfhEHSmHu6rOOOqQzxu2KQmZP8Tx7 -yaUFQZmx7Cxb7tyW0ohTS3g0uW7muw/FeqZ8Dhjfbw90TNGp8aHp2FRkzF6WeKJW -GsFzshXGVwXf2vdIJIqOf2qp+U3pPmrOYCx9LZAI9mOPFdAtnIz/8f38DBZQVhT7 -upeG7rRJA1TuG1l/MDoCgoYhrv7wFfLfToPmmcW6NfcgkIw47XXP4S73BDD7Ua2O -giRAyn0pXdXZ92Vk/KqfdLh9kl3ShCngE+qK99CrxK7vFcXCifJ7tjtJmGHzTnKR -N4xJkunI7Cqg90lufA0kxmts8jgvynAF5X/fxisrgIDV2m/LQLvYG/AkyRDIRAJ+ -LtOYqqIN8SvQ2vqOHP9U6OFKbt2o1ni1N6WsZNUUI8cOpevhCTjXwHxgpV2Yj4wC -1dxWqPNNWKkL1HxkdAEy8t8PSoqpAqKiHYR3wvHMl700GXRd4nQ+dSf3r7/ufA5t -VIimVuImrTESPB5BeW0X6hNeH/Vcn0lZo7Ivo0LD+qh+v6WfSMlgYmIK371F3uNC -tVGW/cT1Gpm4UqJEzS1hjBWPgdVdotSQPYxuQGHDWV3Y2eH2dEcieXR92sqjbzcV -NvAsGnE8EXbfXRo+VGN4a2V+Hw== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIHqTCCBZGgAwIBAgIQYwaGp8U3ZaVDkKhqWMzUMjANBgkqhkiG9w0BAQUFADCB -jzELMAkGA1UEBhMCTFYxNTAzBgNVBAoTLFZBUyBMYXR2aWphcyBQYXN0cyAtIFZp -ZW4ucmVnLk5yLjQwMDAzMDUyNzkwMSMwIQYDVQQLExpTZXJ0aWZpa2FjaWphcyBw -YWthbHBvanVtaTEkMCIGA1UEAxMbVkFTIExhdHZpamFzIFBhc3RzIFNTSShSQ0Ep -MB4XDTA2MDkxMzA5MjIxMFoXDTI0MDkxMzA5Mjc1N1owgY8xCzAJBgNVBAYTAkxW -MTUwMwYDVQQKEyxWQVMgTGF0dmlqYXMgUGFzdHMgLSBWaWVuLnJlZy5Oci40MDAw -MzA1Mjc5MDEjMCEGA1UECxMaU2VydGlmaWthY2lqYXMgcGFrYWxwb2p1bWkxJDAi -BgNVBAMTG1ZBUyBMYXR2aWphcyBQYXN0cyBTU0koUkNBKTCCAiIwDQYJKoZIhvcN -AQEBBQADggIPADCCAgoCggIBAJu4+f1hVS9PpKUUtS6OuSSPrPuxVD9A/0/F5YZo -e1OT+zWCNahQLpRSoNuDPnXaFXCsCc/ugkmtNkm5tHGLtAChQgbKCApjl7YI/O60 -3Jh4GYLJ+H9kPqrJ/rGN67Bk9bzzxD46kOpOjj8bGbxqg8ORPGxV+wpSwOjhXXeF -M8VJ3+xqv79sN/6OSaIVGM6LjmseOKMwb4iBfnJWRBrEejkP9sSPltSy6wBOXN67 -5zu35iQFk2tN5pFEv+6YG8eFGxFBeyI2p74+6Ho33BjekJ2PzbLXmj/iF39bDOHv -P2Y9biTksM7DDIhslNo4JXxSOeNzFLMARWOaDEJAXgTG93JkzsluM7Pk020klTeT -fvIAXRmLH/NDc6ifRdIGqey0Qrv67gzHTz9RH9Gv0KwYf4eBIv6p3QeWbXz4TtlN -OlBp1UF+xdp02I5z5X6D4cMZgbe9v0COvi6aogyqTgIuuyrhCF0xA8msJ7Cv3NXI -FH1AnVWJIfmQzNTJYEFzq+jN2DpVOQqCmf6b9fU8HJHLwPpGVK4h/CqsXHveepdx -/WxrzUiapNuBfBg3L5B9YZS9F8lctlQWd8oJSqrpvE+UdQFaVryS0o+515feVnQB -9xZxSbH1GEaZQe5i4bMsZXVpKXJDA/ibH/o49J7sQBCOrJfVsDO+nxjcLfdBeFRK -YkTnAgMBAAGjggH9MIIB+TAOBgNVHQ8BAf8EBAMCAQYwGAYIKwYBBQUHAQMEDDAK -MAgGBgQAjkYBATAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTMw/Vm/3OsOFqW -GyGJuIFMH8teJTAQBgkrBgEEAYI3FQEEAwIBADCCAYkGA1UdIASCAYAwggF8MIIB -eAYLKwYBBAGBxFkBAQIwggFnMIIBOAYIKwYBBQUHAgIwggEqHoIBJgBTAGkAcwAg -AGkAcgAgAHMAZQByAHQAaQBmAGkAawBhAHQAcwAsACAAawBvACAAaQB6AGQAZQB2 -AGkAcwAgAFYAQQBTACAATABhAHQAdgBpAGoAYQBzACAAUABhAHMAdABzACwAIABu -AG8AZAByAG8AcwBpAG4AbwB0ACAAYQB0AGIAaQBsAHMAdABpAGIAdQAgAEUAbABl -AGsAdAByAG8AbgBpAHMAawBvACAAZABvAGsAdQBtAGUAbgB0AHUAIABsAGkAawB1 -AG0AYQBtACAAdQBuACAARQBpAHIAbwBwAGEAcwAgAFAAYQByAGwAYQBtAGUAbgB0 -AGEAIABkAGkAcgBlAGsAdABpAHYAYQBpACAAMQA5ADkAOQAvADkAMwAvAEUASzAp -BggrBgEFBQcCARYdaHR0cDovL3d3dy5lLW1lLmx2L3JlcG9zaXRvcnkwDQYJKoZI -hvcNAQEFBQADggIBAB8oSjWQIWNoCi94r6MegiaXoz8nGdJLo0J6BhNlW8EEy+t9 -fO+U8vGJ9bffUgIhadLqljTloM+XuJxVDhCFoxReLAX4tTp28/l6uN62DCdp8suU -kQsdudWOb5kvzfIZVjk6SFbwAf+Cdbay/dHU9fJjV0xNoX7MELoEae/0FPyzlx9F -7m9KKH/Rxie8x6Opa3vtghNvq94P+3HrXBEaqSzQMJ/8NjdW75XpurcTtq6fAmGt -nuxrBG82nw+Z98LJyEwouSjUIdeeVNXAzvSO5FWUe48kxjj8q3qkVnc9qEXvZJKk -0Ep+u3OL9A1Sc7g6SF5DgNOpcHdi/8coHHMeQ+YnJFtJueY2pI79xS0veqV5EnrX -IbIlbcgPosNhS+VI4le6n/KKId3bZPDaGd/OwJuAOcJ3d2MVU3KE+qSPBzeGIX1Q -+j1qN9uRDjez/c4Lynth0Jx0nH04aG3pex3W8Sq07ztgUncF5gLCX4xbvPB9t3PH -kWuyKrNjozTVq60lcUf/Gj56to2VdsPups0DCWzuRWeYz5lIdsHOinSaaFIBNCLI -7eIUC4S9bhCMsXKbvugI11fVf+q0AT1O5OLoZ+eMfunnQhHvlUbIkda+JxeAGTSY -58bfHvwhX56GPbx+8Jy9cp70R4JbcWfz+txUTKhc2FnH0AcOEzMnvPRp8Gsh ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDtTCCAp2gAwIBAgIIBhDCeat3PfIwDQYJKoZIhvcNAQEFBQAwdjELMAkGA1UE -BhMCQ0gxEjAQBgNVBAoTCVN3aXNzU2lnbjEyMDAGA1UEAxMpU3dpc3NTaWduIENB -IChSU0EgSUsgTWF5IDYgMTk5OSAxODowMDo1OCkxHzAdBgkqhkiG9w0BCQEWEGNh -QFN3aXNzU2lnbi5jb20wHhcNMDAxMTI2MjMyNzQxWhcNMzExMTI2MjMyNzQxWjB2 -MQswCQYDVQQGEwJDSDESMBAGA1UEChMJU3dpc3NTaWduMTIwMAYDVQQDEylTd2lz -c1NpZ24gQ0EgKFJTQSBJSyBNYXkgNiAxOTk5IDE4OjAwOjU4KTEfMB0GCSqGSIb3 -DQEJARYQY2FAU3dpc3NTaWduLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC -AQoCggEBAKw5fjnmNneLQlUCQG8jQLwwfbrOZoUwNX8cbNqhxK03/xUloFVgAt+S -Te2RxNXaCAXLBPn5ZST35TLV57aLmbHCtifv3YZqaaQGvjedltIBMJihJhZ+h3LY -SKsUb+xEJ3x5ZUf8jP+Q1g57y1s8SnBFWN/ni5NkF1Y1y31VwOi9wiOf/VISL+uu -SC4i1CP1Kbz3BDs6Hht1GpRYCbJ/K0bc9oJSpWpT5PGONsGIawqMbJuyoDghsXQ1 -pbn2e8K64BSscGZVZTNooSGgNiHmACNJBYXiWVWrwXPF4l6SddmC3Rj0aKXjgECc -FkHLDQcsM5JsK2ZLryTDUsQFbxVP2ikCAwEAAaNHMEUwCwYDVR0PBAQDAgEGMAwG -A1UdEwQFMAMBAf8wHQYDVR0OBBYEFJbXcc05KtT8iLGKq1N4ae+PR34WMAkGA1Ud -IwQCMAAwDQYJKoZIhvcNAQEFBQADggEBAKMy6W8HvZdS1fBpEUzl6Lvw50bgE1Xc -HU1JypSBG9mhdcXZo5AlPB4sCvx9Dmfwhyrdsshc0TP2V3Vh6eQqnEF5qB4lVziT -Bko9mW6Ot+pPnwsy4SHpx3rw6jCYnOqfUcZjWqqqRrq/3P1waz+Mn4cLMVEg3Xaz -qYov/khvSqS0JniwjRlo2H6f/1oVUKZvP+dUhpQepfZrOqMAWZW4otp6FolyQyeU -NN6UCRNiUKl5vTijbKwUUwfER/1Vci3M1/O1QCfttQ4vRN4Buc0xqYtGL3cd5WiO -vWzyhlTzAI6VUdNkQhhHJSAyTpj6dmXDRzrryoFGa2PjgESxz7XBaSI= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBK -MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x -GTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkx -MjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3Qg -Q29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwggEiMA0GCSqG -SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jxYDiJ -iQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa -/FHtaMbQbqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJ -jnIFHovdRIWCQtBJwB1g8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnI -HmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYVHDGA76oYa8J719rO+TMg1fW9ajMtgQT7 -sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi0XPnj3pDAgMBAAGjgZ0w -gZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQF -MAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCsw -KaAnoCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsG -AQQBgjcVAQQDAgEAMA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0L -URYD7xh8yOOvaliTFGCRsoTciE6+OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXO -H0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cnCDpOGR86p1hcF895P4vkp9Mm -I50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/53CYNv6ZHdAbY -iNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc -f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCB -kzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug -Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho -dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZBgNVBAMTElVUTiAtIERBVEFDb3Jw -IFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBaMIGTMQswCQYDVQQG -EwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYD -VQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cu -dXNlcnRydXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjAN -BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6 -E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ysraP6LnD43m77VkIVni5c7yPeIbkFdicZ -D0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlowHDyUwDAXlCCpVZvNvlK -4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA9P4yPykq -lXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulW -bfXv33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQAB -o4GrMIGoMAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRT -MtGzz3/64PGgXYVOktKeRR20TzA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3Js -LnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dDLmNybDAqBgNVHSUEIzAhBggr -BgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3DQEBBQUAA4IB -AQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowft -Gzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyj -j98C5OBxOvG0I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVH -KWss5nbZqSl9Mt3JNjy9rjXxEZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv -2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwPDPafepE39peC4N1xaf92P2BNPM/3 -mfnGV/TJVTl4uix5yaaIK/QI ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x -GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv -b3QgQ0EgMzAeFw0wNjExMjQxOTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNV -BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W -YWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDM -V0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNggDhoB -4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUr -H556VOijKTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd -8lyyBTNvijbO0BNO/79KDDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9Cabwv -vWhDFlaJKjdhkf2mrk7AyxRllDdLkgbvBNDInIjbC3uBr7E9KsRlOni27tyAsdLT -mZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwpp5ijJUMv7/FfJuGITfhe -btfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8nT8KKdjc -T5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDt -WAEXMJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZ -c6tsgLjoC2SToJyMGf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A -4iLItLRkT9a6fUg+qGkM17uGcclzuD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYD -VR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHTBgkrBgEEAb5YAAMwgcUwgZMG -CCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmljYXRlIGNvbnN0 -aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0 -aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVu -dC4wLQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2Nw -czALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4G -A1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4ywLQoUmkRzBFMQswCQYDVQQGEwJC -TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UEAxMSUXVvVmFkaXMg -Um9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZVqyM0 -7ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSem -d1o417+shvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd -+LJ2w/w4E6oM3kJpK27zPOuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B -4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadN -t54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp8kokUvd0/bpO5qgdAm6x -DYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBCbjPsMZ57 -k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6s -zHXug/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0j -Wy10QJLZYxkNc91pvGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeT -mJlglFwjz1onl14LBQaTNx47aTbrqZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK -4SVhM7JZG+Ju1zdXtg2pEto= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEDzCCAvegAwIBAgIBATANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQGEwJTSzET -MBEGA1UEBxMKQnJhdGlzbGF2YTETMBEGA1UEChMKRGlzaWcgYS5zLjERMA8GA1UE -AxMIQ0EgRGlzaWcwHhcNMDYwMzIyMDEzOTM0WhcNMTYwMzIyMDEzOTM0WjBKMQsw -CQYDVQQGEwJTSzETMBEGA1UEBxMKQnJhdGlzbGF2YTETMBEGA1UEChMKRGlzaWcg -YS5zLjERMA8GA1UEAxMIQ0EgRGlzaWcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw -ggEKAoIBAQCS9jHBfYj9mQGp2HvycXXxMcbzdWb6UShGhJd4NLxs/LxFWYgmGErE -Nx+hSkS943EE9UQX4j/8SFhvXJ56CbpRNyIjZkMhsDxkovhqFQ4/61HhVKndBpnX -mjxUizkDPw/Fzsbrg3ICqB9x8y34dQjbYkzo+s7552oftms1grrijxaSfQUMbEYD -XcDtab86wYqg6I7ZuUUohwjstMoVvoLdtUSLLa2GDGhibYVW8qwUYzrG0ZmsNHhW -S8+2rT+MitcE5eN4TPWGqvWP+j1scaMtymfraHtuM6kMgiioTGohQBUgDCZbg8Kp -FhXAJIJdKxatymP2dACw30PEEGBWZ2NFAgMBAAGjgf8wgfwwDwYDVR0TAQH/BAUw -AwEB/zAdBgNVHQ4EFgQUjbJJaJ1yCCW5wCf1UJNWSEZx+Y8wDgYDVR0PAQH/BAQD -AgEGMDYGA1UdEQQvMC2BE2Nhb3BlcmF0b3JAZGlzaWcuc2uGFmh0dHA6Ly93d3cu -ZGlzaWcuc2svY2EwZgYDVR0fBF8wXTAtoCugKYYnaHR0cDovL3d3dy5kaXNpZy5z -ay9jYS9jcmwvY2FfZGlzaWcuY3JsMCygKqAohiZodHRwOi8vY2EuZGlzaWcuc2sv -Y2EvY3JsL2NhX2Rpc2lnLmNybDAaBgNVHSAEEzARMA8GDSuBHpGT5goAAAABAQEw -DQYJKoZIhvcNAQEFBQADggEBAF00dGFMrzvY/59tWDYcPQuBDRIrRhCA/ec8J9B6 -yKm2fnQwM6M6int0wHl5QpNt/7EpFIKrIYwvF/k/Ji/1WcbvgAa3mkkp7M5+cTxq -EEHA9tOasnxakZzArFvITV734VP/Q3f8nktnbNfzg9Gg4H8l37iYC5oyOGwwoPP/ -CBUz91BKez6jPiCp3C9WgArtQVCwyfTssuMmRAAOb54GvCKWU3BlxFAKRmukLyeB -EicTXxChds6KezfqwzlhA5WYOudsiCUI/HloDYd9Yvi0X/vF2Ey9WLw/Q1vUHgFN -PGO+I++MzVpQuGhU+QqZMxEA4Z7CRneC9VkGjCFMhwnN5ag= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJTRTEU -MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3 -b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwHhcNMDAwNTMw -MTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQswCQYDVQQGEwJTRTEUMBIGA1UEChML -QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYD -VQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUA -A4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwzexODcEyPNwTXH+9ZOEQpnXvUGW2ul -CDtbKRY654eyNAbFvAWlA3yCyykQruGIgb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6n -tGO0/7Gcrjyvd7ZWxbWroulpOj0OM3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyl -dI+Yrsj5wAYi56xz36Uu+1LcsRVlIPo1Zmne3yzxbrww2ywkEtvrNTVokMsAsJch -PXQhI2U0K7t4WaPW4XY5mqRJjox0r26kmqPZm9I4XJuiGMx1I4S+6+JNM3GOGvDC -+Mcdoq0Dlyz4zyXG9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8wHQYDVR0O -BBYEFJWxtPCUtr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8E -BTADAQH/MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBl -MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFk -ZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENB -IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxtZBsfzQ3duQH6lmM0MkhHma6X -7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0PhiVYrqW9yTkkz -43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9tTEv2dB8Xfjea4MY -eDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL/bscVjby/rK25Xa71SJl -pz/+0WatC7xrmYbvP33zGDLKe8bjq2RGlfgmadlVg3sslgf/WSxEo8bl6ancoWOA -WiFeIc9TVPC6b4nbqKqVz4vjccweGyBECMB6tkD9xOQ14R0WHNC8K47Wcdk= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFGTCCBAGgAwIBAgIEPki9xDANBgkqhkiG9w0BAQUFADAxMQswCQYDVQQGEwJE -SzEMMAoGA1UEChMDVERDMRQwEgYDVQQDEwtUREMgT0NFUyBDQTAeFw0wMzAyMTEw -ODM5MzBaFw0zNzAyMTEwOTA5MzBaMDExCzAJBgNVBAYTAkRLMQwwCgYDVQQKEwNU -REMxFDASBgNVBAMTC1REQyBPQ0VTIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A -MIIBCgKCAQEArGL2YSCyz8DGhdfjeebM7fI5kqSXLmSjhFuHnEz9pPPEXyG9VhDr -2y5h7JNp46PMvZnDBfwGuMo2HP6QjklMxFaaL1a8z3sM8W9Hpg1DTeLpHTk0zY0s -2RKY+ePhwUp8hjjEqcRhiNJerxomTdXkoCJHhNlktxmW/OwZ5LKXJk5KTMuPJItU -GBxIYXvViGjaXbXqzRowwYCDdlCqT9HU3Tjw7xb04QxQBr/q+3pJoSgrHPb8FTKj -dGqPqcNiKXEx5TukYBdedObaE+3pHx8b0bJoc8YQNHVGEBDjkAB2QMuLt0MJIf+r -TpPGWOmlgtt3xDqZsXKVSQTwtyv6e1mO3QIDAQABo4ICNzCCAjMwDwYDVR0TAQH/ -BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwgewGA1UdIASB5DCB4TCB3gYIKoFQgSkB -AQEwgdEwLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuY2VydGlmaWthdC5kay9yZXBv -c2l0b3J5MIGdBggrBgEFBQcCAjCBkDAKFgNUREMwAwIBARqBgUNlcnRpZmlrYXRl -ciBmcmEgZGVubmUgQ0EgdWRzdGVkZXMgdW5kZXIgT0lEIDEuMi4yMDguMTY5LjEu -MS4xLiBDZXJ0aWZpY2F0ZXMgZnJvbSB0aGlzIENBIGFyZSBpc3N1ZWQgdW5kZXIg -T0lEIDEuMi4yMDguMTY5LjEuMS4xLjARBglghkgBhvhCAQEEBAMCAAcwgYEGA1Ud -HwR6MHgwSKBGoESkQjBAMQswCQYDVQQGEwJESzEMMAoGA1UEChMDVERDMRQwEgYD -VQQDEwtUREMgT0NFUyBDQTENMAsGA1UEAxMEQ1JMMTAsoCqgKIYmaHR0cDovL2Ny -bC5vY2VzLmNlcnRpZmlrYXQuZGsvb2Nlcy5jcmwwKwYDVR0QBCQwIoAPMjAwMzAy -MTEwODM5MzBagQ8yMDM3MDIxMTA5MDkzMFowHwYDVR0jBBgwFoAUYLWF7FZkfhIZ -J2cdUBVLc647+RIwHQYDVR0OBBYEFGC1hexWZH4SGSdnHVAVS3OuO/kSMB0GCSqG -SIb2fQdBAAQQMA4bCFY2LjA6NC4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEACrom -JkbTc6gJ82sLMJn9iuFXehHTuJTXCRBuo7E4A9G28kNBKWKnctj7fAXmMXAnVBhO -inxO5dHKjHiIzxvTkIvmI/gLDjNDfZziChmPyQE+dF10yYscA+UYyAFMP8uXBV2Y -caaYb7Z8vTd/vuGTJW1v8AqtFxjhA7wHKcitJuj4YfD9IQl+mo6paH1IYnK9AOoB -mbgGglGBTvH1tJFUuSN6AJqfXY3gPGS5GhKSKseCRHI53OI8xthV9RVOyAUO28bQ -YqbsFbS1AoLbrIyigfCbmTH1ICCoiGEKB5+U/NDXG8wuF/MEJ3Zn61SD/aSQfgY9 -BKNDLdr8C2LqL19iUw== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIG0TCCBbmgAwIBAgIBezANBgkqhkiG9w0BAQUFADCByTELMAkGA1UEBhMCSFUx -ETAPBgNVBAcTCEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0 -b25zYWdpIEtmdC4xGjAYBgNVBAsTEVRhbnVzaXR2YW55a2lhZG9rMUIwQAYDVQQD -EzlOZXRMb2NrIE1pbm9zaXRldHQgS296amVneXpvaSAoQ2xhc3MgUUEpIFRhbnVz -aXR2YW55a2lhZG8xHjAcBgkqhkiG9w0BCQEWD2luZm9AbmV0bG9jay5odTAeFw0w -MzAzMzAwMTQ3MTFaFw0yMjEyMTUwMTQ3MTFaMIHJMQswCQYDVQQGEwJIVTERMA8G -A1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFsb3phdGJpenRvbnNh -Z2kgS2Z0LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxQjBABgNVBAMTOU5l -dExvY2sgTWlub3NpdGV0dCBLb3pqZWd5em9pIChDbGFzcyBRQSkgVGFudXNpdHZh -bnlraWFkbzEeMBwGCSqGSIb3DQEJARYPaW5mb0BuZXRsb2NrLmh1MIIBIjANBgkq -hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx1Ilstg91IRVCacbvWy5FPSKAtt2/Goq -eKvld/Bu4IwjZ9ulZJm53QE+b+8tmjwi8F3JV6BVQX/yQ15YglMxZc4e8ia6AFQe -r7C8HORSjKAyr7c3sVNnaHRnUPYtLmTeriZ539+Zhqurf4XsoPuAzPS4DB6TRWO5 -3Lhbm+1bOdRfYrCnjnxmOCyqsQhjF2d9zL2z8cM/z1A57dEZgxXbhxInlrfa6uWd -vLrqOU+L73Sa58XQ0uqGURzk/mQIKAR5BevKxXEOC++r6uwSEaEYBTJp0QwsGj0l -mT+1fMptsK6ZmfoIYOcZwvK9UdPM0wKswREMgM6r3JSda6M5UzrWhQIDAMV9o4IC -wDCCArwwEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNVHQ8BAf8EBAMCAQYwggJ1Bglg -hkgBhvhCAQ0EggJmFoICYkZJR1lFTEVNISBFemVuIHRhbnVzaXR2YW55IGEgTmV0 -TG9jayBLZnQuIE1pbm9zaXRldHQgU3pvbGdhbHRhdGFzaSBTemFiYWx5emF0YWJh -biBsZWlydCBlbGphcmFzb2sgYWxhcGphbiBrZXN6dWx0LiBBIG1pbm9zaXRldHQg -ZWxla3Ryb25pa3VzIGFsYWlyYXMgam9naGF0YXMgZXJ2ZW55ZXN1bGVzZW5laywg -dmFsYW1pbnQgZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUgYSBNaW5vc2l0ZXR0IFN6 -b2xnYWx0YXRhc2kgU3phYmFseXphdGJhbiwgYXogQWx0YWxhbm9zIFN6ZXJ6b2Rl -c2kgRmVsdGV0ZWxla2JlbiBlbG9pcnQgZWxsZW5vcnplc2kgZWxqYXJhcyBtZWd0 -ZXRlbGUuIEEgZG9rdW1lbnR1bW9rIG1lZ3RhbGFsaGF0b2sgYSBodHRwczovL3d3 -dy5uZXRsb2NrLmh1L2RvY3MvIGNpbWVuIHZhZ3kga2VyaGV0b2sgYXogaW5mb0Bu -ZXRsb2NrLm5ldCBlLW1haWwgY2ltZW4uIFdBUk5JTkchIFRoZSBpc3N1YW5jZSBh -bmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGFyZSBzdWJqZWN0IHRvIHRo -ZSBOZXRMb2NrIFF1YWxpZmllZCBDUFMgYXZhaWxhYmxlIGF0IGh0dHBzOi8vd3d3 -Lm5ldGxvY2suaHUvZG9jcy8gb3IgYnkgZS1tYWlsIGF0IGluZm9AbmV0bG9jay5u -ZXQwHQYDVR0OBBYEFAlqYhaSsFq7VQ7LdTI6MuWyIckoMA0GCSqGSIb3DQEBBQUA -A4IBAQCRalCc23iBmz+LQuM7/KbD7kPgz/PigDVJRXYC4uMvBcXxKufAQTPGtpvQ -MznNwNuhrWw3AkxYQTvyl5LGSKjN5Yo5iWH5Upfpvfb5lHTocQ68d4bDBsxafEp+ -NFAwLvt/MpqNPfMgW/hqyobzMUwsWYACff44yTB1HLdV47yfuqhthCgFdbOLDcCR -VCHnpgu0mfVRQdzNo0ci2ccBgcTcR08m6h/t280NmPSjnLRzMkqWmf68f8glWPhY -83ZmiVSkpj7EUFy6iRiCdUgh0k8T6GB+B3bbELVR5qq5aKrN9p2QdRLqOBrKROi3 -macqaJVmlaut74nLYKkGEsaUR+ko ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICmDCCAgGgAwIBAgIBDjANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJVUzEY -MBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNFQ0ExFDASBgNVBAMT -C0VDQSBSb290IENBMB4XDTA0MDYxNDEwMjAwOVoXDTQwMDYxNDEwMjAwOVowSzEL -MAkGA1UEBhMCVVMxGDAWBgNVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMD -RUNBMRQwEgYDVQQDEwtFQ0EgUm9vdCBDQTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw -gYkCgYEArkr2eXIS6oAKIpDkOlcQZdMGdncoygCEIU+ktqY3of5SVVXU7/it7kJ1 -EUzR4ii2vthQtbww9aAnpQxcEmXZk8eEyiGEPy+cCQMllBY+efOtKgjbQNDZ3lB9 -19qzUJwBl2BMxslU1XsJQw9SK10lPbQm4asa8E8e5zTUknZBWnECAwEAAaOBizCB -iDAfBgNVHSMEGDAWgBT2uAQnDlYW2blj2f2hVGVBoAhILzAdBgNVHQ4EFgQU9rgE -Jw5WFtm5Y9n9oVRlQaAISC8wDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMB -Af8wJQYDVR0gBB4wHDAMBgpghkgBZQMCAQwBMAwGCmCGSAFlAwIBDAIwDQYJKoZI -hvcNAQEFBQADgYEAHh0EQY2cZ209aBb5q0wW1ER0dc4OGzsLyqjHfaQ4TEaMmUwL -AJRta/c4KVWLiwbODsvgJk+CaWmSL03gRW/ciVb/qDV7qh9Pyd1cOlanZTAnPog2 -i82yL3i2fK9DCC84uoxEQbgqK2jx9bIjFTwlAqITk9fGAm5mdT84IEwq1Gw= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEojCCA4qgAwIBAgIQRL4Mi1AAJLQR0zYlJWfJiTANBgkqhkiG9w0BAQUFADCB -rjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug -Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho -dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xNjA0BgNVBAMTLVVUTi1VU0VSRmlyc3Qt -Q2xpZW50IEF1dGhlbnRpY2F0aW9uIGFuZCBFbWFpbDAeFw05OTA3MDkxNzI4NTBa -Fw0xOTA3MDkxNzM2NThaMIGuMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAV -BgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5l -dHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRydXN0LmNvbTE2MDQGA1UE -AxMtVVROLVVTRVJGaXJzdC1DbGllbnQgQXV0aGVudGljYXRpb24gYW5kIEVtYWls -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsjmFpPJ9q0E7YkY3rs3B -YHW8OWX5ShpHornMSMxqmNVNNRm5pELlzkniii8efNIxB8dOtINknS4p1aJkxIW9 -hVE1eaROaJB7HHqkkqgX8pgV8pPMyaQylbsMTzC9mKALi+VuG6JG+ni8om+rWV6l -L8/K2m2qL+usobNqqrcuZzWLeeEeaYji5kbNoKXqvgvOdjp6Dpvq/NonWz1zHyLm -SGHGTPNpsaguG7bUMSAsvIKKjqQOpdeJQ/wWWq8dcdcRWdq6hw2v+vPhwvCkxWeM -1tZUOt4KpLoDd7NlyP0e03RiqhjKaJMeoYV+9Udly/hNVyh00jT/MLbu9mIwFIws -6wIDAQABo4G5MIG2MAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud -DgQWBBSJgmd9xJ0mcABLtFBIfN49rgRufTBYBgNVHR8EUTBPME2gS6BJhkdodHRw -Oi8vY3JsLnVzZXJ0cnVzdC5jb20vVVROLVVTRVJGaXJzdC1DbGllbnRBdXRoZW50 -aWNhdGlvbmFuZEVtYWlsLmNybDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUH -AwQwDQYJKoZIhvcNAQEFBQADggEBALFtYV2mGn98q0rkMPxTbyUkxsrt4jFcKw7u -7mFVbwQ+zznexRtJlOTrIEy05p5QLnLZjfWqo7NK2lYcYJeA3IKirUq9iiv/Cwm0 -xtcgBEXkzYABurorbs6q15L+5K/r9CYdFip/bDCVNy8zEqx/3cfREYxRmLLQo5HQ -rfafnoOTHh1CuEava2bwm3/q4wMC5QJRwarVNZ1yQAOJujEdxRBoUp7fooXFXAim -eOZTT7Hot9MUnpOmw2TjrH5xzbyf6QMbzPvprDHBr3wVdAKZw7JHpsIyYdfHb0gk -USeh1YdV8nuPmD0Wnu51tvjQjvLzxq4oW6fw8zYX/MMF08oDSlQ= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDIjCCAougAwIBAgIQNKT/9jCvTKU8MxdCoZRmdTANBgkqhkiG9w0BAQUFADCB -xDELMAkGA1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJ -Q2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UE -CxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhh -d3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0 -ZS5jb20wHhcNOTYwODAxMDAwMDAwWhcNMjEwMTAxMjM1OTU5WjCBxDELMAkGA1UE -BhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du -MR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlm -aWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZl -ciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wgZ8w -DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANOkUG7I/1Zr5s9dtuoMaHVHoqrC2oQl -/Kj0R1HahbUgdJSGHg91yekIYfUGbTBuFRkC6VLAYttNmZ7iagxEOM3+vuNkCXDF -/rFrKbYvScg71CcEJRCXL+eQbcAoQpnXTEPew/UhbVSfXcNY4cDk2VuwuNy0e982 -OsK1ZiIS1ocNAgMBAAGjEzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEF -BQADgYEAvkBpQW/G28GnvwfAReTQtUMeTJUzNelewj4o9qgNUNX/4gwP/FACjq6R -ua00io2fJ3GqGcxL6ATK1BdrEhrWxl/WzV7/iXa/2EjYWb0IiokdV81FHlK6EpqE -+hiJX+j5MDVqAWC5mYCDhQpu2vTJj15zLTFKY6B08h+LItIpPus= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDITCCAoqgAwIBAgIBADANBgkqhkiG9w0BAQQFADCByzELMAkGA1UEBhMCWkEx -FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMRowGAYD -VQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBT -ZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFBlcnNvbmFsIEJhc2lj -IENBMSgwJgYJKoZIhvcNAQkBFhlwZXJzb25hbC1iYXNpY0B0aGF3dGUuY29tMB4X -DTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgcsxCzAJBgNVBAYTAlpBMRUw -EwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEaMBgGA1UE -ChMRVGhhd3RlIENvbnN1bHRpbmcxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2Vy -dmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQZXJzb25hbCBCYXNpYyBD -QTEoMCYGCSqGSIb3DQEJARYZcGVyc29uYWwtYmFzaWNAdGhhd3RlLmNvbTCBnzAN -BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAvLyTU23AUE+CFeZIlDWmWr5vQvoPR+53 -dXLdjUmbllegeNTKP1GzaQuRdhciB5dqxFGTS+CN7zeVoQxN2jSQHReJl+A1OFdK -wPQIcOk8RHtQfmGakOMj04gRRif1CwcOu93RfyAKiLlWCy4cgNrx454p7xS9CkT7 -G1sY0b8jkyECAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQF -AAOBgQAt4plrsD16iddZopQBHyvdEktTwq1/qqcAXJFAVyVKOKqEcLnZgA+le1z7 -c8a914phXAPjLSeoF+CEhULcXpvGt7Jtu3Sv5D/Lp7ew4F2+eIMllNLbgQ95B21P -9DkVWlIBe94y1k049hJcBlDfBVu9FEuh3ym6O0GN92NWod8isQ== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCB -gjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEk -MCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRY -UmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQxMTAxMTcx -NDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3 -dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2Vy -dmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB -dXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS6 -38eMpSe2OAtp87ZOqCwuIR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCP -KZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMxfoArtYzAQDsRhtDLooY2YKTVMIJt2W7Q -DxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FEzG+gSqmUsE3a56k0enI4 -qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqsAxcZZPRa -JSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNVi -PvryxS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0P -BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASs -jVy16bYbMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0 -eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQEwDQYJKoZIhvcNAQEFBQAD -ggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc/Kh4ZzXxHfAR -vbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt -qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLa -IR9NmXmd4c8nnxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSy -i6mx5O+aGtA9aZnuqCij4Tyz8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQ -O+7ETPTsJ3xCwnR8gooJybQDJbw= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFpDCCA4ygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEc -MBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBP -bmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyODA2 -MDAwMFoXDTM3MDkyOTE0MDgwMFowYzELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0Ft -ZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2EgT25saW5lIFJvb3Qg -Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIP -ADCCAgoCggIBAMxBRR3pPU0Q9oyxQcngXssNt79Hc9PwVU3dxgz6sWYFas14tNwC -206B89enfHG8dWOgXeMHDEjsJcQDIPT/DjsS/5uN4cbVG7RtIuOx238hZK+GvFci -KtZHgVdEglZTvYYUAQv8f3SkWq7xuhG1m1hagLQ3eAkzfDJHA1zEpYNI9FdWboE2 -JxhP7JsowtS013wMPgwr38oE18aO6lhOqKSlGBxsRZijQdEt0sdtjRnxrXm3gT+9 -BoInLRBYBbV4Bbkv2wxrkJB+FFk4u5QkE+XRnRTf04JNRvCAOVIyD+OEsnpD8l7e -Xz8d3eOyG6ChKiMDbi4BFYdcpnV1x5dhvt6G3NRI270qv0pV2uh9UPu0gBe4lL8B -PeraunzgWGcXuVjgiIZGZ2ydEEdYMtA1fHkqkKJaEBEjNa0vzORKW6fIJ/KD3l67 -Xnfn6KVuY8INXWHQjNJsWiEOyiijzirplcdIz5ZvHZIlyMbGwcEMBawmxNJ10uEq -Z8A9W6Wa6897GqidFEXlD6CaZd4vKL3Ob5Rmg0gp2OpljK+T2WSfVVcmv2/LNzGZ -o2C7HK2JNDJiuEMhBnIMoVxtRsX6Kc8w3onccVvdtjc+31D1uAclJuW8tf48ArO3 -+L5DwYcRlJ4jbBeKuIonDFRH8KmzwICMoCfrHRnjB453cMor9H124HhnAgMBAAGj -YzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE1FwWg4u3OpaaEg5+31IqEj -FNeeMB8GA1UdIwQYMBaAFE1FwWg4u3OpaaEg5+31IqEjFNeeMA4GA1UdDwEB/wQE -AwIBhjANBgkqhkiG9w0BAQUFAAOCAgEAZ2sGuV9FOypLM7PmG2tZTiLMubekJcmn -xPBUlgtk87FYT15R/LKXeydlwuXK5w0MJXti4/qftIe3RUavg6WXSIylvfEWK5t2 -LHo1YGwRgJfMqZJS5ivmae2p+DYtLHe/YUjRYwu5W1LtGLBDQiKmsXeu3mnFzccc -obGlHBD7GL4acN3Bkku+KVqdPzW+5X1R+FXgJXUjhx5c3LqdsKyzadsXg8n33gy8 -CNyRnqjQ1xU3c6U1uPx+xURABsPr+CKAXEfOAuMRn0T//ZoyzH1kUQ7rVyZ2OuMe -IjzCpjbdGe+n/BLzJsBZMYVMnNjP36TMzCmT/5RtdlwTCJfy7aULTd3oyWgOZtMA -DjMSW7yV5TKQqLPGbIOtd+6Lfn6xqavT4fG2wLHqiMDn05DpKJKUe2h7lyoKZy2F -AjgQ5ANh1NolNscIWC2hp1GvMApJ9aZphwctREZ2jirlmjvXGKL8nDgQzMY70rUX -Om/9riW99XJZZLF0KjhfGEzfz3EEWjbUvy+ZnOjZurGV5gJLIaFb1cFPj65pbVPb -AZO1XB4Y3WRayhgoPmMEEf0cjQAPuDffZ4qdZqkCapH/E8ovXYO8h5Ns3CRRFgQl -Zvqz2cK6Kb6aSDiCmfS/O0oxGfm/jiEzFMpPVF/7zvuPcX/9XhmgD0uRuMRUvAaw -RY8mkaKO/qk= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEvTCCA6WgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBhTELMAkGA1UEBhMCVVMx -IDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxs -cyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9v -dCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDcxMjEzMTcwNzU0WhcNMjIxMjE0 -MDAwNzU0WjCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdl -bGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQD -DC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkw -ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDub7S9eeKPCCGeOARBJe+r -WxxTkqxtnt3CxC5FlAM1iGd0V+PfjLindo8796jE2yljDpFoNoqXjopxaAkH5OjU -Dk/41itMpBb570OYj7OeUt9tkTmPOL13i0Nj67eT/DBMHAGTthP796EfvyXhdDcs -HqRePGj4S78NuR4uNuip5Kf4D8uCdXw1LSLWwr8L87T8bJVhHlfXBIEyg1J55oNj -z7fLY4sR4r1e6/aN7ZVyKLSsEmLpSjPmgzKuBXWVvYSV2ypcm44uDLiBK0HmOFaf -SZtsdvqKXfcBeYF8wYNABf5x/Qw/zE5gCQ5lRxAvAcAFP4/4s0HvWkJ+We/Slwxl -AgMBAAGjggE0MIIBMDAPBgNVHRMBAf8EBTADAQH/MDkGA1UdHwQyMDAwLqAsoCqG -KGh0dHA6Ly9jcmwucGtpLndlbGxzZmFyZ28uY29tL3dzcHJjYS5jcmwwDgYDVR0P -AQH/BAQDAgHGMB0GA1UdDgQWBBQmlRkQ2eihl5H/3BnZtQQ+0nMKajCBsgYDVR0j -BIGqMIGngBQmlRkQ2eihl5H/3BnZtQQ+0nMKaqGBi6SBiDCBhTELMAkGA1UEBhMC -VVMxIDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNX -ZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMg -Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHmCAQEwDQYJKoZIhvcNAQEFBQADggEB -ALkVsUSRzCPIK0134/iaeycNzXK7mQDKfGYZUMbVmO2rvwNa5U3lHshPcZeG1eMd -/ZDJPHV3V3p9+N701NX3leZ0bh08rnyd2wIDBSxxSyU+B+NemvVmFymIGjifz6pB -A4SXa5M4esowRBskRDPQ5NHcKDj0E0M1NSljqHyita04pO2t/caaH/+Xc/77szWn -k4bGdpEA5qxRFsQnMlzbc9qlk1eOPm01JghZ1edE13YgY+esE2fDbbFwRnzVlhE9 -iW9dqKHrjQrawx0zbKPqZxmamX9LPYNRKh3KL4YMon4QLSvUFpULB6ouFJJJtylv -2G0xffX8oRAHh84vWdw+WNs= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDczCCAlugAwIBAgIQMDAwMDk3Mzc1NzM4NjAwMDANBgkqhkiG9w0BAQUFADBV -MQswCQYDVQQGEwJGUjETMBEGA1UEChMKQ2VydGlOb21pczEcMBoGA1UECxMTQUMg -UmFjaW5lIC0gUm9vdCBDQTETMBEGA1UEAxMKQ2VydGlOb21pczAeFw0wMDExMDkw -MDAwMDBaFw0xMjExMDkwMDAwMDBaMFUxCzAJBgNVBAYTAkZSMRMwEQYDVQQKEwpD -ZXJ0aU5vbWlzMRwwGgYDVQQLExNBQyBSYWNpbmUgLSBSb290IENBMRMwEQYDVQQD -EwpDZXJ0aU5vbWlzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8SWb -4mS5RXB3ENSIcfrEzCj/TRUQuT1tMCU0YUfXFSgcPdWglIzCv3kvh07QoB+8xMl+ -fQHvSSduAxnNewz0GBY9rApCPKlP6CcnJr74OSVZIiWt9wLfl4wwhNhZOiikIpZp -EdOXWqRc84P5cUlN3Lwmr1sjCWmHfTSS4cAKxfDbFLfE61etosyoFZUTQbIhb1Bf -JL5xRXAUZudQiU42n/yAoSUrN4FLUfPQNlOe1AB81pIgX8g2ojwxDjfgqSs1JmBF -uLKJ45uVLEenQBPmQCGjL3maV86IRmR3a9UGlgvKAk0NBdh8mrQyQvcUlLBIQBCm -l7wppt6maQHUNEPQSwIDAQABoz8wPTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUw -AwEB/zAdBgNVHQ4EFgQU+F4ho6ijFeb4tRG7/kIEXU2OgnowDQYJKoZIhvcNAQEF -BQADggEBACe9FJayK6bXkJQrilBFMh75QPdFOks9PJuo86OMUlBDZGYFTCh9Arex -N3KYCnAEzazYIALwr7eASJJDIQMu1Q+pkx/7ACde4kP47F27M2rm+v5HnGooCLz2 -s7Fe/WUycTQqgwF5lNp03m1ce/TvovgkEZeVN5wM/7+SsZLJGDigXGeq48j2g2hn -8OckX9Ciyo0U3/1IVeigNBisiaOlsHSZOEPBZQRiZULob+NVbXVPo8nM1OyP3aHI -LQex1yYcCr9m93nOiZyKkur3Uedf1yMTBe+fflnPFKGYnVqvTGXCKVdHzQBfpILA -AuaC+5ykZhSiSMf8nmL2oPMcLO7YQw4= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDZzCCAk+gAwIBAgIQGx+ttiD5JNM2a/fH8YygWTANBgkqhkiG9w0BAQUFADBF -MQswCQYDVQQGEwJHQjEYMBYGA1UEChMPVHJ1c3RpcyBMaW1pdGVkMRwwGgYDVQQL -ExNUcnVzdGlzIEZQUyBSb290IENBMB4XDTAzMTIyMzEyMTQwNloXDTI0MDEyMTEx -MzY1NFowRTELMAkGA1UEBhMCR0IxGDAWBgNVBAoTD1RydXN0aXMgTGltaXRlZDEc -MBoGA1UECxMTVHJ1c3RpcyBGUFMgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQAD -ggEPADCCAQoCggEBAMVQe547NdDfxIzNjpvto8A2mfRC6qc+gIMPpqdZh8mQRUN+ -AOqGeSoDvT03mYlmt+WKVoaTnGhLaASMk5MCPjDSNzoiYYkchU59j9WvezX2fihH -iTHcDnlkH5nSW7r+f2C/revnPDgpai/lkQtV/+xvWNUtyd5MZnGPDNcE2gfmHhjj -vSkCqPoc4Vu5g6hBSLwacY3nYuUtsuvffM/bq1rKMfFMIvMFE/eC+XN5DL7XSxzA -0RU8k0Fk0ea+IxciAIleH2ulrG6nS4zto3Lmr2NNL4XSFDWaLk6M6jKYKIahkQlB -OrTh4/L68MkKokHdqeMDx4gVOxzUGpTXn2RZEm0CAwEAAaNTMFEwDwYDVR0TAQH/ -BAUwAwEB/zAfBgNVHSMEGDAWgBS6+nEleYtXQSUhhgtx67JkDoshZzAdBgNVHQ4E -FgQUuvpxJXmLV0ElIYYLceuyZA6LIWcwDQYJKoZIhvcNAQEFBQADggEBAH5Y//01 -GX2cGE+esCu8jowU/yyg2kdbw++BLa8F6nRIW/M+TgfHbcWzk88iNVy2P3UnXwmW -zaD+vkAMXBJV+JOCyinpXj9WV4s4NvdFGkwozZ5BuO1WTISkQMi4sKUraXAEasP4 -1BIy+Q7DsdwyhEQsb8tGD+pmQQ9P8Vilpg0ND2HepZ5dfWWhPBfnqFVO76DH7cZE -f1T1o+CP8HxVIo8ptoGj4W1OLBuAZ+ytIJ8MYmHVl/9D7S3B2l0pKoU/rGXuhg8F -jZBf3+6f9L/uHfuY5H+QK4R4EA5sSVPvFVtlRkpdr7r7OnIdzfYliB6XzCGcKQEN -ZetX2fNXlrtIzYE= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIGUTCCBTmgAwIBAgIEPLVPQDANBgkqhkiG9w0BAQUFADBmMRIwEAYDVQQKEwli -ZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBSb290IENBczEzMDEGA1UEAxMq -YmVUUlVTVGVkIFJvb3QgQ0EgLSBFbnRydXN0IEltcGxlbWVudGF0aW9uMB4XDTAy -MDQxMTA4MjQyN1oXDTIyMDQxMTA4NTQyN1owZjESMBAGA1UEChMJYmVUUlVTVGVk -MRswGQYDVQQLExJiZVRSVVNUZWQgUm9vdCBDQXMxMzAxBgNVBAMTKmJlVFJVU1Rl -ZCBSb290IENBIC0gRW50cnVzdCBJbXBsZW1lbnRhdGlvbjCCASIwDQYJKoZIhvcN -AQEBBQADggEPADCCAQoCggEBALr0RAOqEmq1Q+xVkrYwfTVXDNvzDSduTPdQqJtO -K2/b9a0cS12zqcH+e0TrW6MFDR/FNCswACnxeECypP869AGIF37m1CbTukzqMvtD -d5eHI8XbQ6P1KqNRXuE70mVpflUVm3rnafdE4Fe1FehmYA8NA/uCjqPoEXtsvsdj -DheT389Lrm5zdeDzqrmkwAkbhepxKYhBMvnwKg5sCfJ0a2ZsUhMfGLzUPvfYbiCe -yv78IZTuEyhL11xeDGbu6bsPwTSxfwh28z0mcMmLJR1iJAzqHHVOwBLkuhMdMCkt -VjMFu5dZfsZJT4nXLySotohAtWSSU1Yk5KKghbNekLQSM80CAwEAAaOCAwUwggMB -MIIBtwYDVR0gBIIBrjCCAaowggGmBg8rBgEEAbE+AAACCSiDkTEwggGRMIIBSQYI -KwYBBQUHAgIwggE7GoIBN1JlbGlhbmNlIG9uIG9yIHVzZSBvZiB0aGlzIENlcnRp -ZmljYXRlIGNyZWF0ZXMgYW4gYWNrbm93bGVkZ21lbnQgYW5kIGFjY2VwdGFuY2Ug -b2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29uZGl0 -aW9ucyBvZiB1c2UsIHRoZSBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVu -dCBhbmQgdGhlIFJlbHlpbmcgUGFydHkgQWdyZWVtZW50LCB3aGljaCBjYW4gYmUg -Zm91bmQgYXQgdGhlIGJlVFJVU1RlZCB3ZWIgc2l0ZSwgaHR0cHM6Ly93d3cuYmV0 -cnVzdGVkLmNvbS9wcm9kdWN0c19zZXJ2aWNlcy9pbmRleC5odG1sMEIGCCsGAQUF -BwIBFjZodHRwczovL3d3dy5iZXRydXN0ZWQuY29tL3Byb2R1Y3RzX3NlcnZpY2Vz -L2luZGV4Lmh0bWwwEQYJYIZIAYb4QgEBBAQDAgAHMIGJBgNVHR8EgYEwfzB9oHug -eaR3MHUxEjAQBgNVBAoTCWJlVFJVU1RlZDEbMBkGA1UECxMSYmVUUlVTVGVkIFJv -b3QgQ0FzMTMwMQYDVQQDEypiZVRSVVNUZWQgUm9vdCBDQSAtIEVudHJ1c3QgSW1w -bGVtZW50YXRpb24xDTALBgNVBAMTBENSTDEwKwYDVR0QBCQwIoAPMjAwMjA0MTEw -ODI0MjdagQ8yMDIyMDQxMTA4NTQyN1owCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaA -FH1w5a44iwY/qhwaj/nPJDCqhIQWMB0GA1UdDgQWBBR9cOWuOIsGP6ocGo/5zyQw -qoSEFjAMBgNVHRMEBTADAQH/MB0GCSqGSIb2fQdBAAQQMA4bCFY2LjA6NC4wAwIE -kDANBgkqhkiG9w0BAQUFAAOCAQEAKrgXzh8QlOu4mre5X+za95IkrNySO8cgjfKZ -5V04ocI07cUTWVwFtStPYZuR+0H8/NU8TZh2BvWBfevdkObRVlTa4y0MnxEylCIB -evZsLHRnBMylj44ss0O1lKLQfelifwa+JwGDnjr9iu6YQ0pr17WXOzq/T220Y/oz -ADQuLW2WyXvKmWO6vvT2MKAtmJbpVkQFqUSjYRDrgqFnXbxdJ3Wqiig2KjiS2d2k -XgClzMx8KSreKJCrt+G2/30lC0DYqjSjLd4H61/OCt3Kfjp9JsFiaDrmLzfzgYYh -xKlkqu9FNtEaZnz46TfW1mG+oq1I59/mdP7TbX3SJdysYlep9w== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEuzCCA6OgAwIBAgIBAjANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQGEwJVUzET -MBEGA1UEChMKQXBwbGUgSW5jLjEmMCQGA1UECxMdQXBwbGUgQ2VydGlmaWNhdGlv -biBBdXRob3JpdHkxFjAUBgNVBAMTDUFwcGxlIFJvb3QgQ0EwHhcNMDYwNDI1MjE0 -MDM2WhcNMzUwMjA5MjE0MDM2WjBiMQswCQYDVQQGEwJVUzETMBEGA1UEChMKQXBw -bGUgSW5jLjEmMCQGA1UECxMdQXBwbGUgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkx -FjAUBgNVBAMTDUFwcGxlIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw -ggEKAoIBAQDkkakJH5HbHkdQ6wXtXnmELes2oldMVeyLGYne+Uts9QerIjAC6Bg+ -+FAJ039BqJj50cpmnCRrEdCju+QbKsMflZ56DKRHi1vUFjczy8QPTc4UadHJGXL1 -XQ7Vf1+b8iUDulWPTV0N8WQ1IxVLFVkds5T39pyez1C6wVhQZ48ItCD3y6wsIG9w -tj8BMIy3Q88PnT3zK0koGsj+zrW5DtleHNbLPbU6rfQPDgCSC7EhFi501TwN22IW -q6NxkkdTVcGvL0Gz+PvjcM3mo0xFfh9Ma1CWQYnEdGILEINBhzOKgbEwWOxaBDKM -aLOPHd5lc/9nXmW8Sdh2nzMUZaF3lMktAgMBAAGjggF6MIIBdjAOBgNVHQ8BAf8E -BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUK9BpR5R2Cf70a40uQKb3 -R01/CF4wHwYDVR0jBBgwFoAUK9BpR5R2Cf70a40uQKb3R01/CF4wggERBgNVHSAE -ggEIMIIBBDCCAQAGCSqGSIb3Y2QFATCB8jAqBggrBgEFBQcCARYeaHR0cHM6Ly93 -d3cuYXBwbGUuY29tL2FwcGxlY2EvMIHDBggrBgEFBQcCAjCBthqBs1JlbGlhbmNl -IG9uIHRoaXMgY2VydGlmaWNhdGUgYnkgYW55IHBhcnR5IGFzc3VtZXMgYWNjZXB0 -YW5jZSBvZiB0aGUgdGhlbiBhcHBsaWNhYmxlIHN0YW5kYXJkIHRlcm1zIGFuZCBj -b25kaXRpb25zIG9mIHVzZSwgY2VydGlmaWNhdGUgcG9saWN5IGFuZCBjZXJ0aWZp -Y2F0aW9uIHByYWN0aWNlIHN0YXRlbWVudHMuMA0GCSqGSIb3DQEBBQUAA4IBAQBc -NplMLXi37Yyb3PN3m/J20ncwT8EfhYOFG5k9RzfyqZtAjizUsZAS2L70c5vu0mQP -y3lPNNiiPvl4/2vIB+x9OYOLUyDTOMSxv5pPCmv/K/xZpwUJfBdAVhEedNO3iyM7 -R6PVbyTi69G3cN8PReEnyvFteO3ntRcXqNx+IjXKJdXZD9Zr1KIkIxH3oayPc4Fg -xhtbCS+SsvhESPBgOJ4V9T0mZyCKM2r3DYLP3uujL/lTaltkwGMzd/c6ByxW69oP -IQ7aunMZT7XZNn/Bh1XZp5m5MkL72NVxnn6hUrcbvZNCJBIqxw8dtk2cXmPIS4AX -UKqK1drk/NAJBzewdXUh ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEZjCCA06gAwIBAgIQRL4Mi1AAJLQR0zYt4LNfGzANBgkqhkiG9w0BAQUFADCB -lTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug -Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho -dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHTAbBgNVBAMTFFVUTi1VU0VSRmlyc3Qt -T2JqZWN0MB4XDTk5MDcwOTE4MzEyMFoXDTE5MDcwOTE4NDAzNlowgZUxCzAJBgNV -BAYTAlVTMQswCQYDVQQIEwJVVDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkxHjAc -BgNVBAoTFVRoZSBVU0VSVFJVU1QgTmV0d29yazEhMB8GA1UECxMYaHR0cDovL3d3 -dy51c2VydHJ1c3QuY29tMR0wGwYDVQQDExRVVE4tVVNFUkZpcnN0LU9iamVjdDCC -ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6qgT+jo2F4qjEAVZURnicP -HxzfOpuCaDDASmEd8S8O+r5596Uj71VRloTN2+O5bj4x2AogZ8f02b+U60cEPgLO -KqJdhwQJ9jCdGIqXsqoc/EHSoTbL+z2RuufZcDX65OeQw5ujm9M89RKZd7G3CeBo -5hy485RjiGpq/gt2yb70IuRnuasaXnfBhQfdDWy/7gbHd2pBnqcP1/vulBe3/IW+ -pKvEHDHd17bR5PDv3xaPslKT16HUiaEHLr/hARJCHhrh2JU022R5KP+6LhHC5ehb -kkj7RwvCbNqtMoNB86XlQXD9ZZBt+vpRxPm9lisZBCzTbafc8H9vg2XiaquHhnUC -AwEAAaOBrzCBrDALBgNVHQ8EBAMCAcYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E -FgQU2u1kdBScFDyr3ZmpvVsoTYs8ydgwQgYDVR0fBDswOTA3oDWgM4YxaHR0cDov -L2NybC51c2VydHJ1c3QuY29tL1VUTi1VU0VSRmlyc3QtT2JqZWN0LmNybDApBgNV -HSUEIjAgBggrBgEFBQcDAwYIKwYBBQUHAwgGCisGAQQBgjcKAwQwDQYJKoZIhvcN -AQEFBQADggEBAAgfUrE3RHjb/c652pWWmKpVZIC1WkDdIaXFwfNfLEzIR1pp6ujw -NTX00CXzyKakh0q9G7FzCL3Uw8q2NbtZhncxzaeAFK4T7/yxSPlrJSUtUbYsbUXB -mMiKVl0+7kNOPmsnjtA6S4ULX9Ptaqd1y9Fahy85dRNacrACgZ++8A+EVCBibGnU -4U3GDZlDAQ0Slox4nb9QorFEqmrPF3rPbw/U+CRVX/A0FklmPlBGyWNxODFiuGK5 -81OtbLUrohKqGU8J2l7nk8aOFAj+8DCAGKCGhU3IfdeLA/5u1fedFqySLKAj5ZyR -Uh+U3xeUc8OzwcFxBSAAeL0TUh2oPs0AH8g= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIH9zCCB2CgAwIBAgIBADANBgkqhkiG9w0BAQUFADCCARQxCzAJBgNVBAYTAkVT -MRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UE -ChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5sLjErMCkGA1UE -ChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1MjEvMC0GA1UECxMm -SVBTIENBIENMQVNFQTMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxLzAtBgNVBAMT -JklQUyBDQSBDTEFTRUEzIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MR4wHAYJKoZI -hvcNAQkBFg9pcHNAbWFpbC5pcHMuZXMwHhcNMDExMjI5MDEwNzUwWhcNMjUxMjI3 -MDEwNzUwWjCCARQxCzAJBgNVBAYTAkVTMRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQ -BgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UEChMlSVBTIEludGVybmV0IHB1Ymxpc2hp -bmcgU2VydmljZXMgcy5sLjErMCkGA1UEChQiaXBzQG1haWwuaXBzLmVzIEMuSS5G -LiAgQi02MDkyOTQ1MjEvMC0GA1UECxMmSVBTIENBIENMQVNFQTMgQ2VydGlmaWNh -dGlvbiBBdXRob3JpdHkxLzAtBgNVBAMTJklQUyBDQSBDTEFTRUEzIENlcnRpZmlj -YXRpb24gQXV0aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXMw -gZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAO6AAPYaZC6tasiDsYun7o/ZttvN -G7uGBiJ2MwwSbUhWYdLcgiViL5/SaTBlA0IjWLxH3GvWdV0XPOH/8lhneaDBgbHU -VqLyjRGZ/fZ98cfEXgIqmuJKtROKAP2Md4bm15T1IHUuDky/dMQ/gT6DtKM4Ninn -6Cr1jIhBqoCm42zvAgMBAAGjggRTMIIETzAdBgNVHQ4EFgQUHp9XUEe2YZM50yz8 -2l09BXW3mQIwggFGBgNVHSMEggE9MIIBOYAUHp9XUEe2YZM50yz82l09BXW3mQKh -ggEcpIIBGDCCARQxCzAJBgNVBAYTAkVTMRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQ -BgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UEChMlSVBTIEludGVybmV0IHB1Ymxpc2hp -bmcgU2VydmljZXMgcy5sLjErMCkGA1UEChQiaXBzQG1haWwuaXBzLmVzIEMuSS5G -LiAgQi02MDkyOTQ1MjEvMC0GA1UECxMmSVBTIENBIENMQVNFQTMgQ2VydGlmaWNh -dGlvbiBBdXRob3JpdHkxLzAtBgNVBAMTJklQUyBDQSBDTEFTRUEzIENlcnRpZmlj -YXRpb24gQXV0aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXOC -AQAwDAYDVR0TBAUwAwEB/zAMBgNVHQ8EBQMDB/+AMGsGA1UdJQRkMGIGCCsGAQUF -BwMBBggrBgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYKKwYB -BAGCNwIBFQYKKwYBBAGCNwIBFgYKKwYBBAGCNwoDAQYKKwYBBAGCNwoDBDARBglg -hkgBhvhCAQEEBAMCAAcwGgYDVR0RBBMwEYEPaXBzQG1haWwuaXBzLmVzMBoGA1Ud -EgQTMBGBD2lwc0BtYWlsLmlwcy5lczBCBglghkgBhvhCAQ0ENRYzQ0xBU0VBMyBD -QSBDZXJ0aWZpY2F0ZSBpc3N1ZWQgYnkgaHR0cDovL3d3dy5pcHMuZXMvMCkGCWCG -SAGG+EIBAgQcFhpodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyLzA7BglghkgBhvhC -AQQELhYsaHR0cDovL3d3dy5pcHMuZXMvaXBzMjAwMi9pcHMyMDAyQ0xBU0VBMy5j -cmwwQAYJYIZIAYb4QgEDBDMWMWh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvcmV2 -b2NhdGlvbkNMQVNFQTMuaHRtbD8wPQYJYIZIAYb4QgEHBDAWLmh0dHA6Ly93d3cu -aXBzLmVzL2lwczIwMDIvcmVuZXdhbENMQVNFQTMuaHRtbD8wOwYJYIZIAYb4QgEI -BC4WLGh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvcG9saWN5Q0xBU0VBMy5odG1s -MHUGA1UdHwRuMGwwMqAwoC6GLGh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvaXBz -MjAwMkNMQVNFQTMuY3JsMDagNKAyhjBodHRwOi8vd3d3YmFjay5pcHMuZXMvaXBz -MjAwMi9pcHMyMDAyQ0xBU0VBMy5jcmwwLwYIKwYBBQUHAQEEIzAhMB8GCCsGAQUF -BzABhhNodHRwOi8vb2NzcC5pcHMuZXMvMA0GCSqGSIb3DQEBBQUAA4GBAEo9IEca -2on0eisxeewBwMwB9dbB/MjD81ACUZBYKp/nNQlbMAqBACVHr9QPDp5gJqiVp4MI -3y2s6Q73nMify5NF8bpqxmdRSmlPa/59Cy9SKcJQrSRE7SOzSMtEQMEDlQwKeAYS -AfWRMS1Jjbs/RU4s4OjNtckUFQzjB4ObJnXv ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x -GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv -b3QgQ0EgMjAeFw0wNjExMjQxODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNV -BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W -YWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCa -GMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6XJxg -Fyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55J -WpzmM+Yklvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bB -rrcCaoF6qUWD4gXmuVbBlDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp -+ARz8un+XJiM9XOva7R+zdRcAitMOeGylZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1 -ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt66/3FsvbzSUr5R/7mp/i -Ucw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1JdxnwQ5hYIiz -PtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og -/zOhD7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UH -oycR7hYQe7xFSkyyBNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuI -yV77zGHcizN300QyNQliBJIWENieJ0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1Ud -EwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBQahGK8SEwzJQTU7tD2 -A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGUa6FJpEcwRTEL -MAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT -ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2f -BluornFdLwUvZ+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzn -g/iN/Ae42l9NLmeyhP3ZRPx3UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2Bl -fF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodmVjB3pjd4M1IQWK4/YY7yarHvGH5K -WWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK+JDSV6IZUaUtl0Ha -B0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrWIozc -hLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPR -TUIZ3Ph1WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWD -mbA4CD/pXvk1B+TJYm5Xf6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0Z -ohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y -4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8VCLAAVBpQ570su9t+Oza -8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDPDCCAqWgAwIBAgIQEj3w59oqIkekOIngiu7JZzANBgkqhkiG9w0BAQUFADCB -0TELMAkGA1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJ -Q2FwZSBUb3duMRowGAYDVQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMf -Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEkMCIGA1UEAxMbVGhhd3Rl -IFBlcnNvbmFsIEZyZWVtYWlsIENBMSswKQYJKoZIhvcNAQkBFhxwZXJzb25hbC1m -cmVlbWFpbEB0aGF3dGUuY29tMB4XDTk2MDEwMTAwMDAwMFoXDTIxMDEwMTIzNTk1 -OVowgdExCzAJBgNVBAYTAlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNV -BAcTCUNhcGUgVG93bjEaMBgGA1UEChMRVGhhd3RlIENvbnN1bHRpbmcxKDAmBgNV -BAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2aXNpb24xJDAiBgNVBAMTG1Ro -YXd0ZSBQZXJzb25hbCBGcmVlbWFpbCBDQTErMCkGCSqGSIb3DQEJARYccGVyc29u -YWwtZnJlZW1haWxAdGhhd3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC -gYEA1GnX1LCUZFtx6UfYDFG26nKRsIRefS0Nj3sS34UldSh0OkIsYyeflXtL734Z -hx2G6qPduc6WZBrCFG5ErHzmj+hND3EfQDimAKOHePb5lIZererAXnbr2RSjXW56 -fAylS1V/Bhkpf56aJtVquzgkCGqYx7Hao5iR/Xnb5VrEHLkCAwEAAaMTMBEwDwYD -VR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQAemGDU5fJUYLA9GoFkR/db -o9lvwykLp9KpgUn2w22FFChFRAH0cVyVLhQPGivRqWvBX2c9FvFyIK++FsoOMF/J -y6WTLMNnVB5yIoojdmyUHVFSbJ3E4EcC18y/8IB7GG4l3GJh1qb+wR1/2bP9jVxF -EFrGZWSa6yz1A0/WSGL7Lg== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UE -BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz -dCBOZXR3b3JraW5nMB4XDTEwMDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDEL -MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp -cm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC -AQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SEHi3y -YJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbua -kCNrmreIdIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRL -QESxG9fhwoXA3hA/Pe24/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp -6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gbh+0t+nvujArjqWaJGctB+d1ENmHP4ndG -yH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNVHQ4EFgQUBx/S55zawm6i -QLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ -KoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfO -tDIuUFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzu -QY0x2+c06lkh1QF612S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZ -Lgo/bNjR9eUJtGxUAArgFU2HdW23WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4u -olu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9/ZFvgrG+CJPbFEfxojfHRZ48 -x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMCWkEx -FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD -VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv -biBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZlciBDQTEm -MCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wHhcNOTYwODAx -MDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkGA1UEBhMCWkExFTATBgNVBAgT -DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3 -dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNl -cyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3 -DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQAD -gY0AMIGJAoGBANOkUG7I/1Zr5s9dtuoMaHVHoqrC2oQl/Kj0R1HahbUgdJSGHg91 -yekIYfUGbTBuFRkC6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg71CcEJRCX -L+eQbcAoQpnXTEPew/UhbVSfXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGj -EzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG -7oWDTSEwjsrZqG9JGubaUeNgcGyEYRGhGshIPllDfU+VPaGLtwtimHp1it2ITk6e -QNuozDJ0uW8NxuOzRAvZim+aKZuZGCg70eNAKJpaPNW15yAbi8qkq43pUdniTCxZ -qdq5snUb9kLy78fyGPmJvKP/iiMucEc= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEUDCCA7mgAwIBAgIJAN4ppNGwj6yIMA0GCSqGSIb3DQEBBAUAMIHMMQswCQYD -VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5j -aXNjbzEZMBcGA1UEChMQTGluZGVuIExhYiwgSW5jLjEpMCcGA1UECxMgTGluZGVu -IExhYiBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxKTAnBgNVBAMTIExpbmRlbiBMYWIg -Q2VydGlmaWNhdGUgQXV0aG9yaXR5MR8wHQYJKoZIhvcNAQkBFhBjYUBsaW5kZW5s -YWIuY29tMB4XDTA1MDQyMTAyNDAzMVoXDTI1MDQxNjAyNDAzMVowgcwxCzAJBgNV -BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNp -c2NvMRkwFwYDVQQKExBMaW5kZW4gTGFiLCBJbmMuMSkwJwYDVQQLEyBMaW5kZW4g -TGFiIENlcnRpZmljYXRlIEF1dGhvcml0eTEpMCcGA1UEAxMgTGluZGVuIExhYiBD -ZXJ0aWZpY2F0ZSBBdXRob3JpdHkxHzAdBgkqhkiG9w0BCQEWEGNhQGxpbmRlbmxh -Yi5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKXh1MThucdTbMg9bYBO -rAm8yWns32YojB0PRfbq8rUjepEhTm3/13s0u399Uc202v4ejcGhkIDWJZd2NZMF -oKrhmRfxGHSKPCuFaXC3jh0lRECj7k8FoPkcmaPjSyodrDFDUUuv+C06oYJoI+rk -8REyal9NwgHvqCzOrZtiTXAdAgMBAAGjggE2MIIBMjAdBgNVHQ4EFgQUO1zK2e1f -1wO1fHAjq6DTJobKDrcwggEBBgNVHSMEgfkwgfaAFDtcytntX9cDtXxwI6ug0yaG -yg63oYHSpIHPMIHMMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEW -MBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEZMBcGA1UEChMQTGluZGVuIExhYiwgSW5j -LjEpMCcGA1UECxMgTGluZGVuIExhYiBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxKTAn -BgNVBAMTIExpbmRlbiBMYWIgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MR8wHQYJKoZI -hvcNAQkBFhBjYUBsaW5kZW5sYWIuY29tggkA3imk0bCPrIgwDAYDVR0TBAUwAwEB -/zANBgkqhkiG9w0BAQQFAAOBgQA/ZkgfvwHYqk1UIAKZS3kMCxz0HvYuEQtviwnu -xA39CIJ65Zozs28Eg1aV9/Y+Of7TnWhW+U3J3/wD/GghaAGiKK6vMn9gJBIdBX/9 -e6ef37VGyiOEFFjnUIbuk0RWty0orN76q/lI/xjCi15XSA/VSq2j4vmnwfZcPTDu -glmQ1A== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv -b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG -EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl -cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi -MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c -JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP -mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+ -wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4 -VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/ -AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB -AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW -BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun -pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC -dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf -fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm -NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx -H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe -+o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEuDCCA6CgAwIBAgIBBDANBgkqhkiG9w0BAQUFADCBtDELMAkGA1UEBhMCQlIx -EzARBgNVBAoTCklDUC1CcmFzaWwxPTA7BgNVBAsTNEluc3RpdHV0byBOYWNpb25h -bCBkZSBUZWNub2xvZ2lhIGRhIEluZm9ybWFjYW8gLSBJVEkxETAPBgNVBAcTCEJy -YXNpbGlhMQswCQYDVQQIEwJERjExMC8GA1UEAxMoQXV0b3JpZGFkZSBDZXJ0aWZp -Y2Fkb3JhIFJhaXogQnJhc2lsZWlyYTAeFw0wMTExMzAxMjU4MDBaFw0xMTExMzAy -MzU5MDBaMIG0MQswCQYDVQQGEwJCUjETMBEGA1UEChMKSUNQLUJyYXNpbDE9MDsG -A1UECxM0SW5zdGl0dXRvIE5hY2lvbmFsIGRlIFRlY25vbG9naWEgZGEgSW5mb3Jt -YWNhbyAtIElUSTERMA8GA1UEBxMIQnJhc2lsaWExCzAJBgNVBAgTAkRGMTEwLwYD -VQQDEyhBdXRvcmlkYWRlIENlcnRpZmljYWRvcmEgUmFpeiBCcmFzaWxlaXJhMIIB -IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwPMudwX/hvm+Uh2b/lQAcHVA -isamaLkWdkwP9/S/tOKIgRrL6Oy+ZIGlOUdd6uYtk9Ma/3pUpgcfNAj0vYm5gsyj -Qo9emsc+x6m4VWwk9iqMZSCK5EQkAq/Ut4n7KuLE1+gdftwdIgxfUsPt4CyNrY50 -QV57KM2UT8x5rrmzEjr7TICGpSUAl2gVqe6xaii+bmYR1QrmWaBSAG59LrkrjrYt -bRhFboUDe1DK+6T8s5L6k8c8okpbHpa9veMztDVC9sPJ60MWXh6anVKo1UcLcbUR -yEeNvZneVRKAAU6ouwdjDvwlsaKydFKwed0ToQ47bmUKgcm+wV3eTRk36UOnTwID -AQABo4HSMIHPME4GA1UdIARHMEUwQwYFYEwBAQAwOjA4BggrBgEFBQcCARYsaHR0 -cDovL2FjcmFpei5pY3BicmFzaWwuZ292LmJyL0RQQ2FjcmFpei5wZGYwPQYDVR0f -BDYwNDAyoDCgLoYsaHR0cDovL2FjcmFpei5pY3BicmFzaWwuZ292LmJyL0xDUmFj -cmFpei5jcmwwHQYDVR0OBBYEFIr68VeEERM1kEL6V0lUaQ2kxPA3MA8GA1UdEwEB -/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQAZA5c1 -U/hgIh6OcgLAfiJgFWpvmDZWqlV30/bHFpj8iBobJSm5uDpt7TirYh1Uxe3fQaGl -YjJe+9zd+izPRbBqXPVQA34EXcwk4qpWuf1hHriWfdrx8AcqSqr6CuQFwSr75Fos -SzlwDADa70mT7wZjAmQhnZx2xJ6wfWlT9VQfS//JYeIc7Fue2JNLd00UOSMMaiK/ -t79enKNHEA2fupH3vEigf5Eh4bVAN5VohrTm6MY53x7XQZZr1ME7a55lFEnSeT0u -mlOAjR2mAbvSM5X5oSZNrmetdzyTj2flCM8CC7MLab0kkdngRIlUBGHF1/S5nmPb -K+9A46sd33oqK8n8 ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDoDCCAoigAwIBAgIBMTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJKUDEO -MAwGA1UEChMFTEdQS0kxGjAYBgNVBAsTEUFwcGxpY2F0aW9uIENBIEcyMB4XDTA2 -MDMzMTE1MDAwMFoXDTE2MDMzMTE0NTk1OVowOTELMAkGA1UEBhMCSlAxDjAMBgNV -BAoTBUxHUEtJMRowGAYDVQQLExFBcHBsaWNhdGlvbiBDQSBHMjCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBALk1xhD422jbB8RATLAdHjbcw0H2z1UVbQh/ -XMZoVeXnV/GWUebhTXgPbkAVcDtl/hHf59PWWDU74Z8C/JRSRi6znmCbAp7JgtL2 -464JT4REtmKbAFFouDqt7GTRMkvplESDtA7OIYlrsDbAmMZLnMI+W2AqCTErLatM -3rGg/VhWwoMdILzEhAmHe6iVl8YljoPgPpMN0cd9c6mo/BkAQC4iuHozQfV4/Vpx -54LZSIhc7KiFhy1tgIlnGmm+EMBaju2IfT5vLDhrN85H2KIxMN5+U2Vsi4ZTQSBs -vUilfq8AWlYSWIHR3IlZ+bXu+E2a2EQpi3mn9yKq6nxctBaIIA0CAwEAAaOBsjCB -rzAdBgNVHQ4EFgQUf7hdjsQYa8Z9zC7prs405xdd4KEwDgYDVR0PAQH/BAQDAgEG -MEwGA1UdHwRFMEMwQaA/oD2kOzA5MQswCQYDVQQGEwJKUDEOMAwGA1UEChMFTEdQ -S0kxGjAYBgNVBAsTEUFwcGxpY2F0aW9uIENBIEcyMA8GA1UdEwEB/wQFMAMBAf8w -HwYDVR0jBBgwFoAUf7hdjsQYa8Z9zC7prs405xdd4KEwDQYJKoZIhvcNAQEFBQAD -ggEBADzYczZABkhKVBn1J0g5JaVuQue2zRvLOTS3m+xPKr535MqE/B3rmyJA1fT7 -aIdy/Eddag5SSuO1XUjGIpbmM21tq/bN18skWoyoRZ4+YYJ9lNUF8Bo1X3EvLlS1 -QQXvhg1S75yYG/EsTDrR84bTjD56L4ZFjoMyJlu/U8oOUVbcmsJaMBkNp57Vqpsg -OWl4IfSXbdEOEUwu0xtasPmXeFwqj1Jl7kxCJcI3MA5tKzWUgwbor0U7BGanMLv5 -4CE7Y259RF06alPvERck/VSyWmxzViHJbC2XpEKzJ2EFIWNt6ii8TxpvQtyYq1XT -HhvAkj+bweY7F1bixJhDJe62ywA= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIGZjCCBE6gAwIBAgIPB35Sk3vgFeNX8GmMy+wMMA0GCSqGSIb3DQEBBQUAMHsx -CzAJBgNVBAYTAkNPMUcwRQYDVQQKDD5Tb2NpZWRhZCBDYW1lcmFsIGRlIENlcnRp -ZmljYWNpw7NuIERpZ2l0YWwgLSBDZXJ0aWPDoW1hcmEgUy5BLjEjMCEGA1UEAwwa -QUMgUmHDrXogQ2VydGljw6FtYXJhIFMuQS4wHhcNMDYxMTI3MjA0NjI5WhcNMzAw -NDAyMjE0MjAyWjB7MQswCQYDVQQGEwJDTzFHMEUGA1UECgw+U29jaWVkYWQgQ2Ft -ZXJhbCBkZSBDZXJ0aWZpY2FjacOzbiBEaWdpdGFsIC0gQ2VydGljw6FtYXJhIFMu -QS4xIzAhBgNVBAMMGkFDIFJhw616IENlcnRpY8OhbWFyYSBTLkEuMIICIjANBgkq -hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAq2uJo1PMSCMI+8PPUZYILrgIem08kBeG -qentLhM0R7LQcNzJPNCNyu5LF6vQhbCnIwTLqKL85XXbQMpiiY9QngE9JlsYhBzL -fDe3fezTf3MZsGqy2IiKLUV0qPezuMDU2s0iiXRNWhU5cxh0T7XrmafBHoi0wpOQ -Y5fzp6cSsgkiBzPZkc0OnB8OIMfuuzONj8LSWKdf/WU34ojC2I+GdV75LaeHM/J4 -Ny+LvB2GNzmxlPLYvEqcgxhaBvzz1NS6jBUJJfD5to0EfhcSM2tXSExP2yYe68yQ -54v5aHxwD6Mq0Do43zeX4lvegGHTgNiRg0JaTASJaBE8rF9ogEHMYELODVoqDA+b -MMCm8Ibbq0nXl21Ii/kDwFJnmxL3wvIumGVC2daa49AZMQyth9VXAnow6IYm+48j -ilSH5L887uvDdUhfHjlvgWJsxS3EF1QZtzeNnDeRyPYL1epjb4OsOMLzP96a++Ej -YfDIJss2yKHzMI+ko6Kh3VOz3vCaMh+DkXkwwakfU5tTohVTP92dsxA7SH2JD/zt -A/X7JWR1DhcZDY8AFmd5ekD8LVkH2ZD6mq093ICK5lw1omdMEWux+IBkAC1vImHF -rEsm5VoQgpukg3s0956JkSCXjrdCx2bD0Omk1vUgjcTDlaxECp1bczwmPS9KvqfJ -pxAe+59QafMCAwEAAaOB5jCB4zAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE -AwIBBjAdBgNVHQ4EFgQU0QnQ6dfOeXRU+Tows/RtLAMDG2gwgaAGA1UdIASBmDCB -lTCBkgYEVR0gADCBiTArBggrBgEFBQcCARYfaHR0cDovL3d3dy5jZXJ0aWNhbWFy -YS5jb20vZHBjLzBaBggrBgEFBQcCAjBOGkxMaW1pdGFjaW9uZXMgZGUgZ2FyYW50 -7WFzIGRlIGVzdGUgY2VydGlmaWNhZG8gc2UgcHVlZGVuIGVuY29udHJhciBlbiBs -YSBEUEMuMA0GCSqGSIb3DQEBBQUAA4ICAQBclLW4RZFNjmEfAygPU3zmpFmps4p6 -xbD/CHwso3EcIRNnoZUSQDWDg4902zNc8El2CoFS3UnUmjIz75uny3XlesuXEpBc -unvFm9+7OSPI/5jOCk0iAUgHforA1SBClETvv3eiiWdIG0ADBaGJ7M9i4z0ldma/ -Jre7Ir5v/zlXdLp6yQGVwZVR6Kss+LGGIOk/yzVb0hfpKv6DExdA7ohiZVvVO2Dp -ezy4ydV/NgIlqmjCMRW3MGXrfx1IebHPOeJCgBbT9ZMj/EyXyVo3bHwi2ErN0o42 -gzmRkBDI8ck1fj+404HGIGQatlDCIaR43NAvO2STdPCWkPHv+wlaNECW8DYSwaN0 -jJN+Qd53i+yG2dIPPy3RzECiiWZIHiCznCNZc6lEc7wkeZBWN7PGKX6jD/EpOe9+ -XCgycDWs2rjIdWb8m0w5R44bb5tNAlQiM+9hup4phO9OSzNHdpdqy35f/RWmnkJD -W2ZaiogN9xa5P1FlK2Zqi9E4UqLWRhH6/JocdJ6PlwsCT2TG9WjTSy3/pDceiz+/ -RL5hRqGEPQgnTIEgd4kI6mdAXmwIUV80WoyWaM3X94nCHNMyAK9Sy9NgWyo6R35r -MDOhYil/SrnhLecUIw4OGEfhefwVVdCx/CVxY3UzHCMrr1zZ7Ud3YA47Dx7SwNxk -BYn8eNZcLCZDqQ== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0 -IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz -BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y -aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG -9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNTIyMjM0OFoXDTE5MDYy -NTIyMjM0OFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y -azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs -YXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw -Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl -cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYWYJ6ibiWuqYvaG9Y -LqdUHAZu9OqNSLwxlBfw8068srg1knaw0KWlAdcAAxIiGQj4/xEjm84H9b9pGib+ -TunRf50sQB1ZaG6m+FiwnRqP0z/x3BkGgagO4DrdyFNFCQbmD3DD+kCmDuJWBQ8Y -TfwggtFzVXSNdnKgHZ0dwN0/cQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFBoPUn0 -LBwGlN+VYH+Wexf+T3GtZMjdd9LvWVXoP+iOBSoh8gfStadS/pyxtuJbdxdA6nLW -I8sogTLDAHkY7FkXicnGah5xyf23dKUlRWnFSKsZ4UWKJWsZ7uW7EvV/96aNUcPw -nXS3qT6gpf+2SQMT2iLM7XGCK5nPOrf1LXLI ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDKTCCApKgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBzzELMAkGA1UEBhMCWkEx -FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMRowGAYD -VQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBT -ZXJ2aWNlcyBEaXZpc2lvbjEjMCEGA1UEAxMaVGhhd3RlIFBlcnNvbmFsIFByZW1p -dW0gQ0ExKjAoBgkqhkiG9w0BCQEWG3BlcnNvbmFsLXByZW1pdW1AdGhhd3RlLmNv -bTAeFw05NjAxMDEwMDAwMDBaFw0yMDEyMzEyMzU5NTlaMIHPMQswCQYDVQQGEwJa -QTEVMBMGA1UECBMMV2VzdGVybiBDYXBlMRIwEAYDVQQHEwlDYXBlIFRvd24xGjAY -BgNVBAoTEVRoYXd0ZSBDb25zdWx0aW5nMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9u -IFNlcnZpY2VzIERpdmlzaW9uMSMwIQYDVQQDExpUaGF3dGUgUGVyc29uYWwgUHJl -bWl1bSBDQTEqMCgGCSqGSIb3DQEJARYbcGVyc29uYWwtcHJlbWl1bUB0aGF3dGUu -Y29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJZtn4B0TPuYwu8KHvE0Vs -Bd/eJxZRNkERbGw77f4QfRKe5ZtCmv5gMcNmt3M6SK5O0DI3lIi1DbbZ8/JE2dWI -Et12TfIa/G8jHnrx2JhFTgcQ7xZC0EN1bUre4qrJMf8fAHB8Zs8QJQi6+u4A6UYD -ZicRFTuqW/KY3TZCstqIdQIDAQABoxMwETAPBgNVHRMBAf8EBTADAQH/MA0GCSqG -SIb3DQEBBAUAA4GBAGk2ifc0KjNyL2071CKyuG+axTZmDhs8obF1Wub9NdP4qPIH -b4Vnjt4rueIXsDqg8A6iAJrf8xQVbrvIhVqYgPn/vnQdPfP+MCXRNzRn+qVxeTBh -KXLA4CxM+1bkOqhv5TJZUtt1KFBZDPgLGeSs2a+WjS9Q2wfD6h+rM+D1KzGJ ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb -MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow -GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj -YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL -MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE -BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM -GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP -ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua -BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe -3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4 -YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR -rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm -ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU -oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF -MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v -QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t -b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF -AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q -GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz -Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2 -G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi -l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3 -smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICPDCCAaUCED9pHoGc8JpK83P/uUii5N0wDQYJKoZIhvcNAQEFBQAwXzELMAkG -A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz -cyAxIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2 -MDEyOTAwMDAwMFoXDTI4MDgwMjIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV -BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAxIFB1YmxpYyBQcmlt -YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN -ADCBiQKBgQDlGb9to1ZhLZlIcfZn3rmN67eehoAKkQ76OCWvRoiC5XOooJskXQ0f -zGVuDLDQVoQYh5oGmxChc9+0WDlrbsH2FdWoqD+qEgaNMax/sDTXjzRniAnNFBHi -TkVWaR94AoDa3EeRKbs2yWNcxeDXLYd7obcysHswuiovMaruo2fa2wIDAQABMA0G -CSqGSIb3DQEBBQUAA4GBAFgVKTk8d6PaXCUDfGD67gmZPCcQcMgMCeazh88K4hiW -NWLMv5sneYlfycQJ9M61Hd8qveXbhpxoJeUwfLaJFf5n0a3hUKw8fGJLj7qE1xIV -Gx/KXQ/BUpQqEZnae88MNhPVNdwQGVnqlMEAv3WP2fr9dgTbYruQagPZRjXZ+Hxb ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDVTCCAj2gAwIBAgIESTMAATANBgkqhkiG9w0BAQUFADAyMQswCQYDVQQGEwJD -TjEOMAwGA1UEChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1QwHhcNMDcwNDE2 -MDcwOTE0WhcNMjcwNDE2MDcwOTE0WjAyMQswCQYDVQQGEwJDTjEOMAwGA1UEChMF -Q05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1QwggEiMA0GCSqGSIb3DQEBAQUAA4IB -DwAwggEKAoIBAQDTNfc/c3et6FtzF8LRb+1VvG7q6KR5smzDo+/hn7E7SIX1mlwh -IhAsxYLO2uOabjfhhyzcuQxauohV3/2q2x8x6gHx3zkBwRP9SFIhxFXf2tizVHa6 -dLG3fdfA6PZZxU3Iva0fFNrfWEQlMhkqx35+jq44sDB7R3IJMfAw28Mbdim7aXZO -V/kbZKKTVrdvmW7bCgScEeOAH8tjlBAKqeFkgjH5jCftppkA9nCTGPihNIaj3XrC -GHn2emU1z5DrvTOTn1OrczvmmzQgLx3vqR1jGqCA2wMv+SYahtKNu6m+UjqHZ0gN -v7Sg2Ca+I19zN38m5pIEo3/PIKe38zrKy5nLAgMBAAGjczBxMBEGCWCGSAGG+EIB -AQQEAwIABzAfBgNVHSMEGDAWgBRl8jGtKvf33VKWCscCwQ7vptU7ETAPBgNVHRMB -Af8EBTADAQH/MAsGA1UdDwQEAwIB/jAdBgNVHQ4EFgQUZfIxrSr3991SlgrHAsEO -76bVOxEwDQYJKoZIhvcNAQEFBQADggEBAEs17szkrr/Dbq2flTtLP1se31cpolnK -OOK5Gv+e5m4y3R6u6jW39ZORTtpC4cMXYFDy0VwmuYK36m3knITnA3kXr5g9lNvH -ugDnuL8BV8F3RTIMO/G0HAiw/VGgod2aHRM2mm23xzy54cXZF/qD1T0VoDy7Hgvi -yJA/qIYM/PmLXoXLT1tLYhFHxUV8BS9BsZ4QaRuZluBVeftOhpm4lNqGOGqTo+fL -buXf6iFViZx9fX+Y9QCJ7uOEwFyWtcVG6kbghVW2G8kS1sHNzYDzAgE8yGnLRUhj -2JTQ7IUOO04RZfSCjKY9ri4ilAnIXOo8gV0WKgOXFlUJ24pBgp5mmxE= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE -BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz -dCBDb21tZXJjaWFsMB4XDTEwMDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDEL -MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp -cm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC -AQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6EqdbDuKP -Hx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yr -ba0F8PrVC8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPAL -MeIrJmqbTFeurCA+ukV6BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1 -yHp52UKqK39c/s4mT6NmgTWvRLpUHhwwMmWd5jyTXlBOeuM61G7MGvv50jeuJCqr -VwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNVHQ4EFgQUnZPGU4teyq8/ -nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ -KoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYG -XUPGhi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNj -vbz4YYCanrHOQnDiqX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivt -Z8SOyUOyXGsViQK8YvxO8rUzqrJv0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9g -N53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0khsUlHRUe072o0EclNmsxZt9YC -nlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT -MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i -YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG -EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg -R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9 -9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq -fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv -iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU -1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+ -bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW -MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA -ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l -uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn -Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS -tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF -PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un -hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV -5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDoDCCAoigAwIBAgIBMTANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJKUDEc -MBoGA1UEChMTSmFwYW5lc2UgR292ZXJubWVudDEWMBQGA1UECxMNQXBwbGljYXRp -b25DQTAeFw0wNzEyMTIxNTAwMDBaFw0xNzEyMTIxNTAwMDBaMEMxCzAJBgNVBAYT -AkpQMRwwGgYDVQQKExNKYXBhbmVzZSBHb3Zlcm5tZW50MRYwFAYDVQQLEw1BcHBs -aWNhdGlvbkNBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp23gdE6H -j6UG3mii24aZS2QNcfAKBZuOquHMLtJqO8F6tJdhjYq+xpqcBrSGUeQ3DnR4fl+K -f5Sk10cI/VBaVuRorChzoHvpfxiSQE8tnfWuREhzNgaeZCw7NCPbXCbkcXmP1G55 -IrmTwcrNwVbtiGrXoDkhBFcsovW8R0FPXjQilbUfKW1eSvNNcr5BViCH/OlQR9cw -FO5cjFW6WY2H/CPek9AEjP3vbb3QesmlOmpyM8ZKDQUXKi17safY1vC+9D/qDiht -QWEjdnjDuGWk81quzMKq2edY3rZ+nYVunyoKb58DKTCXKB28t89UKU5RMfkntigm -/qJj5kEW8DOYRwIDAQABo4GeMIGbMB0GA1UdDgQWBBRUWssmP3HMlEYNllPqa0jQ -k/5CdTAOBgNVHQ8BAf8EBAMCAQYwWQYDVR0RBFIwUKROMEwxCzAJBgNVBAYTAkpQ -MRgwFgYDVQQKDA/ml6XmnKzlm73mlL/lupwxIzAhBgNVBAsMGuOCouODl+ODquOC -seODvOOCt+ODp+ODs0NBMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD -ggEBADlqRHZ3ODrso2dGD/mLBqj7apAxzn7s2tGJfHrrLgy9mTLnsCTWw//1sogJ -hyzjVOGjprIIC8CFqMjSnHH2HZ9g/DgzE+Ge3Atf2hZQKXsvcJEPmbo0NI2VdMV+ -eKlmXb3KIXdCEKxmJj3ekav9FfBv7WxfEPjzFvYDio+nEhEMy/0/ecGc/WLuo89U -DNErXxc+4z6/wCs+CZv+iKZ+tJIX/COUgb1up8WMwusRRdv4QcmWdupwX3kSa+Sj -B1oF7ydJzyGfikwJcGapJsErEU4z0g781mzSDjJkaP+tBXhfAx2o45CsJOAPQKdL -rosot4LKGAfmt1t06SAZf7IbiVQ= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDZjCCAk6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJVUzEW -MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFs -IENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMTkwMzA0MDUwMDAwWjBEMQswCQYDVQQG -EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3Qg -R2xvYmFsIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDvPE1A -PRDfO1MA4Wf+lGAVPoWI8YkNkMgoI5kF6CsgncbzYEbYwbLVjDHZ3CB5JIG/NTL8 -Y2nbsSpr7iFY8gjpeMtvy/wWUsiRxP89c96xPqfCfWbB9X5SJBri1WeR0IIQ13hL -TytCOb1kLUCgsBDTOEhGiKEMuzozKmKY+wCdE1l/bztyqu6mD4b5BWHqZ38MN5aL -5mkWRxHCJ1kDs6ZgwiFAVvqgx306E+PsV8ez1q6diYD3Aecs9pYrEw15LNnA5IZ7 -S4wMcoKK+xfNAGw6EzywhIdLFnopsk/bHdQL82Y3vdj2V7teJHq4PIu5+pIaGoSe -2HSPqht/XvT+RSIhAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE -FHE4NvICMVNHK266ZUapEBVYIAUJMB8GA1UdIwQYMBaAFHE4NvICMVNHK266ZUap -EBVYIAUJMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAQEAA/e1K6td -EPx7srJerJsOflN4WT5CBP51o62sgU7XAotexC3IUnbHLB/8gTKY0UvGkpMzNTEv -/NgdRN3ggX+d6YvhZJFiCzkIjKx0nVnZellSlxG5FntvRdOW2TF9AjYPnDtuzywN -A0ZF66D0f0hExghAzN4bcLUprbqLOzRldRtxIR0sFAqwlpW41uryZfspuk/qkZN0 -abby/+Ea0AzRdoXLiiW9l14sbxWZJue2Kf8i7MkCx1YAzUm5s2x7UwQa4qjJqhIF -I8LO57sEAszAR6LkxCkvW0VXiVHuPOtSCP8HNR6fNWpHSlaY0VqFH4z1Ir+rzoPz -4iIprn2DQKi6bA== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIE9zCCA9+gAwIBAgIEPL/xoTANBgkqhkiG9w0BAQUFADB2MQswCQYDVQQGEwJQ -TDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2Vu -dHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MSAwHgYDVQQDExdDQyBTaWduZXQgLSBQ -Q0EgS2xhc2EgMjAeFw0wMjA0MTkxMDI5NTNaFw0xNzA0MTgxMjUzMDdaMHUxCzAJ -BgNVBAYTAlBMMR8wHQYDVQQKExZUUCBJbnRlcm5ldCBTcC4geiBvLm8uMSQwIgYD -VQQLExtDZW50cnVtIENlcnR5ZmlrYWNqaSBTaWduZXQxHzAdBgNVBAMTFkNDIFNp -Z25ldCAtIENBIEtsYXNhIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB -AQCqgLJuQqY4yavbSgHg8CyfKTx4BokNSDOVz4eD9vptUr11Kqd06ED1hlH7Sg0g -oBFAfntNU/QTKwSBaNuime7C4sSEdgsKrPoAhGb4Mq8y7Ty7RqZz7mkzNMqzL2L2 -U4yQ2QjvpH8MH0IBqOWEcpSkpwnrCDImRoTfd+YlZWKi2JceQixUUYIQ45Ox8+x8 -hHbvvZdgqtcvo8PW27qoHkp/7hMuJ44kDAGrmxffBXl/OBRZp0uO1CSLcMcVJzyr -2phKhy406MYdWrtNPEluGs0GFDzd0nrIctiWAO4cmct4S72S9Q6e//0GO9f3/Ca5 -Kb2I1xYLj/xE+HgjHX9aD2MhAgMBAAGjggGMMIIBiDAPBgNVHRMBAf8EBTADAQH/ -MA4GA1UdDwEB/wQEAwIBBjCB4wYDVR0gBIHbMIHYMIHVBg0rBgEEAb4/AhQKAQEA -MIHDMHUGCCsGAQUFBwICMGkaZ0NlcnR5ZmlrYXQgd3lzdGF3aW9ueSB6Z29kbmll -IHogZG9rdW1lbnRlbTogIlBvbGl0eWthIENlcnR5ZmlrYWNqaSBQQ0EyIC0gQ2Vy -dHlmaWthdHkgVXJ6ZWRvdyBLbGFzeSAyIi4wSgYIKwYBBQUHAgEWPmh0dHA6Ly93 -d3cuc2lnbmV0LnBsL3JlcG96eXRvcml1bS9kb2t1bWVudHkva2xhc2EyL3BjX3Bj -YTIudHh0MD8GA1UdHwQ4MDYwNKAyoDCGLmh0dHA6Ly93d3cuc2lnbmV0LnBsL3Jl -cG96eXRvcml1bS9jcmwvcGNhMi5jcmwwHwYDVR0jBBgwFoAUwGxGyl2CfpYHRonE -82AVXO08kMIwHQYDVR0OBBYEFLtFBlILy4HNKVSzvHxBTM0HDowlMA0GCSqGSIb3 -DQEBBQUAA4IBAQBWTsCbqXrXhBBev5v5cIuc6gJM8ww7oR0uMQRZoFSqvQUPWBYM -2/TLI/f8UM9hSShUVj3zEsSj/vFHagUVmzuVXo5u0WK8iaqATSyEVBhADHrPG6wY -cLKJlagge/ILA0m+SieyP2sjYD9MUB9KZIEyBKv0429UuDTw6P7pslxMWJBSNyQx -aLIs0SRKsqZZWkc7ZYAj2apSkBMX2Is1oHA+PwkF6jQMwCao/+CndXPUzfCF6caa -9WwW31W26MlXCvSmJgfiTPwGvm4PkPmOnmWZ3CczzhHl4q7ztHFzshJH3sZWDnrW -wBFjzz5ePr3WHV1wA7EY6oT4zBx+2gT9XBTB ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIC+TCCAmKgAwIBAgIENvEbGTANBgkqhkiG9w0BAQUFADA2MQswCQYDVQQGEwJF -UzENMAsGA1UEChMERk5NVDEYMBYGA1UECxMPRk5NVCBDbGFzZSAyIENBMB4XDTk5 -MDMxODE0NTYxOVoXDTE5MDMxODE1MjYxOVowNjELMAkGA1UEBhMCRVMxDTALBgNV -BAoTBEZOTVQxGDAWBgNVBAsTD0ZOTVQgQ2xhc2UgMiBDQTCBnTANBgkqhkiG9w0B -AQEFAAOBiwAwgYcCgYEAmD+tGTaTPT7+dkIU/TVv8fqtInpY40bQXcZa+WItjzFe -/rQw/lB0rNadHeBixkndFBJ9cQusBsE/1waH4JCJ1uXjA7LyJ7GfM8iqazZKo8Q/ -eUGdiUYvKz5j1DhWkaodsQ1CdU3zh07jD03MtGy/YhOH6tCbjrbi/xn0lAnVlmEC -AQOjggEUMIIBEDARBglghkgBhvhCAQEEBAMCAAcwWAYDVR0fBFEwTzBNoEugSaRH -MEUxCzAJBgNVBAYTAkVTMQ0wCwYDVQQKEwRGTk1UMRgwFgYDVQQLEw9GTk1UIENs -YXNlIDIgQ0ExDTALBgNVBAMTBENSTDEwKwYDVR0QBCQwIoAPMTk5OTAzMTgxNDU2 -MTlagQ8yMDE5MDMxODE0NTYxOVowCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFECa -dkSXdAfErBTLHo1POkV8MNdhMB0GA1UdDgQWBBRAmnZEl3QHxKwUyx6NTzpFfDDX -YTAMBgNVHRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqG -SIb3DQEBBQUAA4GBAGFMoHxZY1tm+O5lE85DgEe5sjXJyITHa3NgReSdN531jiW5 -+aqqyuP4Q5wvoIkFsUUylCoeA41dpt7PV5Xa3yZgX8vflR64zgjY+IrJT6lodZPj -LwVMZGACokIeb4ZoZVUO2ENv8pExPqNHPCgFr0W2nSJMJntLfVsV+RlG3whd ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFyjCCA7KgAwIBAgIEAJiWjDANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJO -TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFh -dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQSAtIEcyMB4XDTA4MDMyNjExMTgxN1oX -DTIwMDMyNTExMDMxMFowWjELMAkGA1UEBhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRl -ciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5lZGVybGFuZGVuIFJv -b3QgQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMVZ5291 -qj5LnLW4rJ4L5PnZyqtdj7U5EILXr1HgO+EASGrP2uEGQxGZqhQlEq0i6ABtQ8Sp -uOUfiUtnvWFI7/3S4GCI5bkYYCjDdyutsDeqN95kWSpGV+RLufg3fNU254DBtvPU -Z5uW6M7XxgpT0GtJlvOjCwV3SPcl5XCsMBQgJeN/dVrlSPhOewMHBPqCYYdu8DvE -pMfQ9XQ+pV0aCPKbJdL2rAQmPlU6Yiile7Iwr/g3wtG61jj99O9JMDeZJiFIhQGp -5Rbn3JBV3w/oOM2ZNyFPXfUib2rFEhZgF1XyZWampzCROME4HYYEhLoaJXhena/M -UGDWE4dS7WMfbWV9whUYdMrhfmQpjHLYFhN9C0lK8SgbIHRrxT3dsKpICT0ugpTN -GmXZK4iambwYfp/ufWZ8Pr2UuIHOzZgweMFvZ9C+X+Bo7d7iscksWXiSqt8rYGPy -5V6548r6f1CGPqI0GAwJaCgRHOThuVw+R7oyPxjMW4T182t0xHJ04eOLoEq9jWYv -6q012iDTiIJh8BIitrzQ1aTsr1SIJSQ8p22xcik/Plemf1WvbibG/ufMQFxRRIEK -eN5KzlW/HdXZt1bv8Hb/C3m1r737qWmRRpdogBQ2HbN/uymYNqUg+oJgYjOk7Na6 -B6duxc8UpufWkjTYgfX8HV2qXB72o007uPc5AgMBAAGjgZcwgZQwDwYDVR0TAQH/ -BAUwAwEB/zBSBgNVHSAESzBJMEcGBFUdIAAwPzA9BggrBgEFBQcCARYxaHR0cDov -L3d3dy5wa2lvdmVyaGVpZC5ubC9wb2xpY2llcy9yb290LXBvbGljeS1HMjAOBgNV -HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJFoMocVHYnitfGsNig0jQt8YojrMA0GCSqG -SIb3DQEBCwUAA4ICAQCoQUpnKpKBglBu4dfYszk78wIVCVBR7y29JHuIhjv5tLyS -CZa59sCrI2AGeYwRTlHSeYAz+51IvuxBQ4EffkdAHOV6CMqqi3WtFMTC6GY8ggen -5ieCWxjmD27ZUD6KQhgpxrRW/FYQoAUXvQwjf/ST7ZwaUb7dRUG/kSS0H4zpX897 -IZmflZ85OkYcbPnNe5yQzSipx6lVu6xiNGI1E0sUOlWDuYaNkqbG9AclVMwWVxJK -gnjIFNkXgiYtXSAfea7+1HAWFpWD2DU5/1JddRwWxRNVz0fMdWVSSt7wsKfkCpYL -+63C4iWEst3kvX5ZbJvw8NjnyvLplzh+ib7M+zkXYT9y2zqR2GUBGR2tUKRXCnxL -vJxxcypFURmFzI79R6d0lR2o0a9OF7FpJsKqeFdbxU2n5Z4FF5TKsl+gSRiNNOkm -bEgeqmiSBeGCc1qb3AdbCG19ndeNIdn8FCCqwkXfP+cAslHkwvgFuXkajDTznlvk -N1trSt8sV4pAWja63XVECDdCcAz+3F4hoKOKwJCcaNpQ5kUQR3i2TtJlycM33+FC -Y7BXN0Ute4qcvwXqZVUz9zkQxSgqIXobisQk+T8VyJoVIPVVYpbtbZNQvOSqeK3Z -ywplh6ZmwcSBo3c6WB4L7oOLnR7SUqTMHW+wmG2UMbX4cQrcufx9MmDm66+KAQ== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDcDCCAligAwIBAgIBBTANBgkqhkiG9w0BAQUFADBbMQswCQYDVQQGEwJVUzEY -MBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxDDAKBgNVBAsT -A1BLSTEWMBQGA1UEAxMNRG9EIFJvb3QgQ0EgMjAeFw0wNDEyMTMxNTAwMTBaFw0y -OTEyMDUxNTAwMTBaMFsxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVy -bm1lbnQxDDAKBgNVBAsTA0RvRDEMMAoGA1UECxMDUEtJMRYwFAYDVQQDEw1Eb0Qg -Um9vdCBDQSAyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwCzB9o07 -rP8/PNZxvrh0IgfscEEV/KtA4weqwcPYn/7aTDq/P8jYKHtLNgHArEUlw9IOCo+F -GGQQPRoTcCpvjtfcjZOzQQ84Ic2tq8I9KgXTVxE3Dc2MUfmT48xGSSGOFLTNyxQ+ -OM1yMe6rEvJl6jQuVl3/7mN1y226kTT8nvP0LRy+UMRC31mI/2qz+qhsPctWcXEF -lrufgOWARVlnQbDrw61gpIB1BhecDvRD4JkOG/t/9bPMsoGCsf0ywbi+QaRktWA6 -WlEwjM7eQSwZR1xJEGS5dKmHQa99brrBuKG/ZTE6BGf5tbuOkooAY7ix5ow4X4P/ -UNU7ol1rshDMYwIDAQABoz8wPTAdBgNVHQ4EFgQUSXS7DF66ev4CVO97oMaVxgmA -cJYwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD -ggEBAJiRjT+JyLv1wGlzKTs1rLqzCHY9cAmS6YREIQF9FHYb7lFsHY0VNy17MWn0 -mkS4r0bMNPojywMnGdKDIXUr5+AbmSbchECV6KjSzPZYXGbvP0qXEIIdugqi3VsG -K52nZE7rLgE1pLQ/E61V5NVzqGmbEfGY8jEeb0DU+HifjpGgb3AEkGaqBivO4XqS -tX3h4NGW56E6LcyxnR8FRO2HmdNNGnA5wQQM5X7Z8a/XIA7xInolpHOZzD+kByeW -qKKV7YK5FtOeC4fCwfKI9WLfaN/HvGlR7bFc3FRUKQ8JOZqsA8HbDE2ubwp6Fknx -v5HSOJTT9pUst2zJQraNypCNhdk= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDczCCAlugAwIBAgIBBDANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJLUjEN -MAsGA1UECgwES0lTQTEuMCwGA1UECwwlS29yZWEgQ2VydGlmaWNhdGlvbiBBdXRo -b3JpdHkgQ2VudHJhbDEWMBQGA1UEAwwNS0lTQSBSb290Q0EgMTAeFw0wNTA4MjQw -ODA1NDZaFw0yNTA4MjQwODA1NDZaMGQxCzAJBgNVBAYTAktSMQ0wCwYDVQQKDARL -SVNBMS4wLAYDVQQLDCVLb3JlYSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBDZW50 -cmFsMRYwFAYDVQQDDA1LSVNBIFJvb3RDQSAxMIIBIDANBgkqhkiG9w0BAQEFAAOC -AQ0AMIIBCAKCAQEAvATk+hM58DSWIGtsaLv623f/J/es7C/n/fB/bW+MKs0lCVsk -9KFo/CjsySXirO3eyDOE9bClCTqnsUdIxcxPjHmc+QZXfd3uOPbPFLKc6tPAXXdi -8EcNuRpAU1xkcK8IWsD3z3X5bI1kKB4g/rcbGdNaZoNy4rCbvdMlFQ0yb2Q3lIVG -yHK+d9VuHygvx2nt54OJM1jT3qC/QOhDUO7cTWu8peqmyGGO9cNkrwYV3CmLP3WM -vHFE2/yttRcdbYmDz8Yzvb9Fov4Kn6MRXw+5H5wawkbMnChmn3AmPC7fqoD+jMUE -CSVPzZNHPDfqAmeS/vwiJFys0izgXAEzisEZ2wIBA6MyMDAwHQYDVR0OBBYEFL+2 -J9gDWnZlTGEBQVYx5Yt7OtnMMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEF -BQADggEBABOvUQveimpb5poKyLGQSk6hAp3MiNKrZr097LuxQpVqslxa/6FjZJap -aBV/JV6K+KRzwYCKhQoOUugy50X4TmWAkZl0Q+VFnUkq8JSV3enhMNITbslOsXfl -BM+tWh6UCVrXPAgcrnrpFDLBRa3SJkhyrKhB2vAhhzle3/xk/2F0KpzZm4tfwjeT -2KM3LzuTa7IbB6d/CVDv0zq+IWuKkDsnSlFOa56ch534eJAx7REnxqhZvvwYC/uO -fi5C4e3nCSG9uRPFVmf0JqZCQ5BEVLRxm3bkGhKsGigA35vB1fjbXKP4krG9tNT5 -UNkAAk/bg9ART6RCVmE6fhMy04Qfybo= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMx -EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT -HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVs -ZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5 -MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNVBAYTAlVTMRAwDgYD -VQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFy -ZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2Vy -dmljZXMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20p -OsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm2 -8xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4PahHQUw2eeBGg6345AWh1K -Ts9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLPLJGmpufe -hRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk -6mFBrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAw -DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+q -AdcwKziIorhtSpzyEZGDMA0GCSqGSIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMI -bw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPPE95Dz+I0swSdHynVv/heyNXB -ve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTyxQGjhdByPq1z -qwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd -iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn -0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCN -sSi6 ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ -RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD -VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX -DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y -ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy -VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr -mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr -IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK -mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu -XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy -dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye -jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1 -BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3 -DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92 -9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx -jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0 -Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz -ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS -R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIID8TCCAtmgAwIBAgIQQT1yx/RrH4FDffHSKFTfmjANBgkqhkiG9w0BAQUFADCB -ijELMAkGA1UEBhMCQ0gxEDAOBgNVBAoTB1dJU2VLZXkxGzAZBgNVBAsTEkNvcHly -aWdodCAoYykgMjAwNTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNl -ZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQSBDQTAeFw0w -NTEyMTExNjAzNDRaFw0zNzEyMTExNjA5NTFaMIGKMQswCQYDVQQGEwJDSDEQMA4G -A1UEChMHV0lTZUtleTEbMBkGA1UECxMSQ29weXJpZ2h0IChjKSAyMDA1MSIwIAYD -VQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBX -SVNlS2V5IEdsb2JhbCBSb290IEdBIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A -MIIBCgKCAQEAy0+zAJs9Nt350UlqaxBJH+zYK7LG+DKBKUOVTJoZIyEVRd7jyBxR -VVuuk+g3/ytr6dTqvirdqFEr12bDYVxgAsj1znJ7O7jyTmUIms2kahnBAbtzptf2 -w93NvKSLtZlhuAGio9RN1AU9ka34tAhxZK9w8RxrfvbDd50kc3vkDIzh2TbhmYsF -mQvtRTEJysIA2/dyoJaqlYfQjse2YXMNdmaM3Bu0Y6Kff5MTMPGhJ9vZ/yxViJGg -4E8HsChWjBgbl0SOid3gF27nKu+POQoxhILYQBRJLnpB5Kf+42TMwVlxSywhp1t9 -4B3RLoGbw9ho972WG6xwsRYUC9tguSYBBQIDAQABo1EwTzALBgNVHQ8EBAMCAYYw -DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUswN+rja8sHnR3JQmthG+IbJphpQw -EAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBAEuh/wuHbrP5wUOx -SPMowB0uyQlB+pQAHKSkq0lPjz0e701vvbyk9vImMMkQyh2I+3QZH4VFvbBsUfk2 -ftv1TDI6QU9bR8/oCy22xBmddMVHxjtqD6wU2zz0c5ypBd8A3HR4+vg1YFkCExh8 -vPtNsCBtQ7tgMHpnM1zFmdH4LTlSc/uMqpclXHLZCB6rTjzjgTGfA6b7wP4piFXa -hNVQA7bihKOmNqoROgHhGEvWRGizPflTdISzRpFGlgC3gCy24eMQ4tui5yiPAZZi -Fj4A4xylNoEYokxSdsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ -/L7fCg0= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEzzCCA7egAwIBAgIEO6ocGTANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJQ -TDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2Vu -dHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MRswGQYDVQQDExJDQyBTaWduZXQgLSBS -b290Q0EwHhcNMDEwOTIwMTY0MjE5WhcNMjYwOTIxMTU0MjE5WjBxMQswCQYDVQQG -EwJQTDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMb -Q2VudHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MRswGQYDVQQDExJDQyBTaWduZXQg -LSBSb290Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrr2vydnNp -ELfGW3KsARiDhJvwDtUe4AbWev+OfMc3+vA29nX8ZmIwno3gmItjo5DbUCCRiCMq -5c9epcGu+kg4a3BJChVXREl8gVh0ST15rr3RKrSc4VgsvQzl0ZUraeQLl8JoRT5P -LsUj3qwF78jUCQVckiiLVcnGfZtFCm+DCJXliQBDMB9XFAUEiO/DtEBs0B7wJGx7 -lgJeJpQUcGiaOPjcJDYOk7rNAYmmD2gWeSlepufO8luUYG/YDxTC4mqhRqfa4MnV -O5dqy+ICj2UvUpHbZDB0KfGRibgBYeQP1kuqgIzJN4UqknVAJb0aMBSPl+9k2fAU -dchx1njlbdcbAgMBAAGjggFtMIIBaTAPBgNVHRMBAf8EBTADAQH/MIIBBAYDVR0g -BIH8MIH5MIH2Bg0rBgEEAb4/AgEKAQEAMIHkMIGaBggrBgEFBQcCAjCBjRqBikNl -cnR5ZmlrYXQgd3lzdGF3aW9ueSB6Z29kbmllIHogZG9rdW1lbnRlbTogIlBvbGl0 -eWthIENlcnR5ZmlrYWNqaSBkbGEgUm9vdENBIi4gQ2VydHlmaWthdCB3eXN0YXdp -b255IHByemV6IFJvb3RDQSB3IGhpZXJhcmNoaWkgQ0MgU2lnbmV0LjBFBggrBgEF -BQcCARY5aHR0cDovL3d3dy5zaWduZXQucGwvcmVwb3p5dG9yaXVtL2Rva3VtZW50 -eS9wY19yb290Y2EudHh0MB0GA1UdDgQWBBTAm8UjDQLhpk5Iax8A6eOaFBuxrzAf -BgNVHSMEGDAWgBTAm8UjDQLhpk5Iax8A6eOaFBuxrzAOBgNVHQ8BAf8EBAMCAQYw -DQYJKoZIhvcNAQEFBQADggEBAGnY5QmYqnnO9OqFOWZxxb25UHRnaRF6IV9aaGit -5BZufZj2Tq3v8L3SgE34GOoIcdRMMG5JEpEU4mN/Ef3oY6Eo+7HfqaPHI4KFmbDS -PiK5s+wmf+bQSm0Yq5/h4ZOdcAESlLQeLSt1CQk2JoKQJ6pyAf6xJBgWEIlm4RXE -4J3324PUiOp83kW6MDvaa1xY976WyInr4rwoLgxVl11LZeKWha0RJJxJgw/NyWpK -G7LWCm1fglF8JH51vZNndGYq1iKtfnrIOvLZq6bzaCiZm1EurD8HE6P7pmABKK6o -3C2OXlNfNIgwkDN/cDqk5TYsTkrpfriJPdxXBH8hQOkW89g= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDAjCCAmsCEDKIjprS9esTR/h/xCA3JfgwDQYJKoZIhvcNAQEFBQAwgcExCzAJ -BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh -c3MgNCBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy -MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp -emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X -DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw -FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgNCBQdWJsaWMg -UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo -YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5 -MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB -AQUAA4GNADCBiQKBgQC68OTP+cSuhVS5B1f5j8V/aBH4xBewRNzjMHPVKmIquNDM -HO0oW369atyzkSTKQWI8/AIBvxwWMZQFl3Zuoq29YRdsTjCG8FE3KlDHqGKB3FtK -qsGgtG7rL+VXxbErQHDbWk2hjh+9Ax/YA9SPTJlxvOKCzFjomDqG04Y48wApHwID -AQABMA0GCSqGSIb3DQEBBQUAA4GBAIWMEsGnuVAVess+rLhDityq3RS6iYF+ATwj -cSGIL4LcY/oCRaxFWdcqWERbt5+BO5JoPeI3JPV7bI92NZYJqFmduc4jq3TWg/0y -cyfYaT5DdPauxYma51N86Xv2S/PBZYPejYqcPIiNOVn8qj8ijaHBZlCBckztImRP -T8qAkbYp ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICPDCCAaUCEDyRMcsf9tAbDpq40ES/Er4wDQYJKoZIhvcNAQEFBQAwXzELMAkG -A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz -cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2 -MDEyOTAwMDAwMFoXDTI4MDgwMjIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV -BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt -YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN -ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE -BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is -I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G -CSqGSIb3DQEBBQUAA4GBABByUqkFFBkyCEHwxWsKzH4PIRnN5GfcX6kb5sroc50i -2JhucwNhkcV8sEVAbkSdjbCxlnRhLQ2pRdKkkirWmnWXbj9T/UWZYB2oK0z5XqcJ -2HUw19JlYD1n1khVdWk/kfVIC0dpImmClr7JyDiGSnoscxlIaU5rfGW/D/xwzoiQ ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIH/zCCB2igAwIBAgIBADANBgkqhkiG9w0BAQUFADCCARQxCzAJBgNVBAYTAkVT -MRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UE -ChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5sLjErMCkGA1UE -ChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1MjEvMC0GA1UECxMm -SVBTIENBIENMQVNFQTEgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxLzAtBgNVBAMT -JklQUyBDQSBDTEFTRUExIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MR4wHAYJKoZI -hvcNAQkBFg9pcHNAbWFpbC5pcHMuZXMwHhcNMDExMjMxMTEyMTQxWhcNMjUxMjI5 -MTEyMTQxWjCCARQxCzAJBgNVBAYTAkVTMRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQ -BgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UEChMlSVBTIEludGVybmV0IHB1Ymxpc2hp -bmcgU2VydmljZXMgcy5sLjErMCkGA1UEChQiaXBzQG1haWwuaXBzLmVzIEMuSS5G -LiAgQi02MDkyOTQ1MjEvMC0GA1UECxMmSVBTIENBIENMQVNFQTEgQ2VydGlmaWNh -dGlvbiBBdXRob3JpdHkxLzAtBgNVBAMTJklQUyBDQSBDTEFTRUExIENlcnRpZmlj -YXRpb24gQXV0aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXMw -gZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM8g89BgSKoCxBXZ5C+NnlURLSnM -UWZoAGXaFFWf6q7f69uN1nXaUfTEzPstvTUfE7fpZmF8lEDz+2AvjBg086hVnra0 -b0APA0VnanJyW2ZIlkKFGMCB4WJqh7JB7i45jITVXthPV2vsjlKM97Pnnhimz8Fb -r+RZcsz69vRptMqxAgMBAAGjggRbMIIEVzAdBgNVHQ4EFgQUL8zsbGe+T/iqPIiN -EvvHnUxb9F4wggFGBgNVHSMEggE9MIIBOYAUL8zsbGe+T/iqPIiNEvvHnUxb9F6h -ggEcpIIBGDCCARQxCzAJBgNVBAYTAkVTMRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQ -BgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UEChMlSVBTIEludGVybmV0IHB1Ymxpc2hp -bmcgU2VydmljZXMgcy5sLjErMCkGA1UEChQiaXBzQG1haWwuaXBzLmVzIEMuSS5G -LiAgQi02MDkyOTQ1MjEvMC0GA1UECxMmSVBTIENBIENMQVNFQTEgQ2VydGlmaWNh -dGlvbiBBdXRob3JpdHkxLzAtBgNVBAMTJklQUyBDQSBDTEFTRUExIENlcnRpZmlj -YXRpb24gQXV0aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXOC -AQAwDAYDVR0TBAUwAwEB/zAMBgNVHQ8EBQMDB/+AMGsGA1UdJQRkMGIGCCsGAQUF -BwMBBggrBgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYKKwYB -BAGCNwIBFQYKKwYBBAGCNwIBFgYKKwYBBAGCNwoDAQYKKwYBBAGCNwoDBDARBglg -hkgBhvhCAQEEBAMCAAcwGgYDVR0RBBMwEYEPaXBzQG1haWwuaXBzLmVzMBoGA1Ud -EgQTMBGBD2lwc0BtYWlsLmlwcy5lczBDBglghkgBhvhCAQ0ENhY0Q0xBU0VBMSBD -QSBDZXJ0aWZpY2F0ZSBpc3N1ZWQgYnkgaHR0cHM6Ly93d3cuaXBzLmVzLzAqBglg -hkgBhvhCAQIEHRYbaHR0cHM6Ly93d3cuaXBzLmVzL2lwczIwMDIvMDwGCWCGSAGG -+EIBBAQvFi1odHRwczovL3d3dy5pcHMuZXMvaXBzMjAwMi9pcHMyMDAyQ0xBU0VB -MS5jcmwwQQYJYIZIAYb4QgEDBDQWMmh0dHBzOi8vd3d3Lmlwcy5lcy9pcHMyMDAy -L3Jldm9jYXRpb25DTEFTRUExLmh0bWw/MD4GCWCGSAGG+EIBBwQxFi9odHRwczov -L3d3dy5pcHMuZXMvaXBzMjAwMi9yZW5ld2FsQ0xBU0VBMS5odG1sPzA8BglghkgB -hvhCAQgELxYtaHR0cHM6Ly93d3cuaXBzLmVzL2lwczIwMDIvcG9saWN5Q0xBU0VB -MS5odG1sMHcGA1UdHwRwMG4wM6AxoC+GLWh0dHBzOi8vd3d3Lmlwcy5lcy9pcHMy -MDAyL2lwczIwMDJDTEFTRUExLmNybDA3oDWgM4YxaHR0cHM6Ly93d3diYWNrLmlw -cy5lcy9pcHMyMDAyL2lwczIwMDJDTEFTRUExLmNybDAvBggrBgEFBQcBAQQjMCEw -HwYIKwYBBQUHMAGGE2h0dHA6Ly9vY3NwLmlwcy5lcy8wDQYJKoZIhvcNAQEFBQAD -gYEAGY2khC4v4mlenqRcy8Mn8mcWca88t4CY9LCJMqlIt7i559BNkMMB66tXsNp9 -N2QhnTordKOjkdgZJmCb7DUdMJEQQT0Y5W7JA6WvHatAFu8feRJ4ImaTjI0Xz3Dd -Jbz6O++igCw0l4EY5gayn2BFpAm+7ZpEcdpR/OCOH80lNDo= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEKzCCAxOgAwIBAgIEOsylTDANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJE -SzEVMBMGA1UEChMMVERDIEludGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQg -Um9vdCBDQTAeFw0wMTA0MDUxNjMzMTdaFw0yMTA0MDUxNzAzMTdaMEMxCzAJBgNV -BAYTAkRLMRUwEwYDVQQKEwxUREMgSW50ZXJuZXQxHTAbBgNVBAsTFFREQyBJbnRl -cm5ldCBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxLhA -vJHVYx/XmaCLDEAedLdInUaMArLgJF/wGROnN4NrXceO+YQwzho7+vvOi20jxsNu -Zp+Jpd/gQlBn+h9sHvTQBda/ytZO5GhgbEaqHF1j4QeGDmUApy6mcca8uYGoOn0a -0vnRrEvLznWv3Hv6gXPU/Lq9QYjUdLP5Xjg6PEOo0pVOd20TDJ2PeAG3WiAfAzc1 -4izbSysseLlJ28TQx5yc5IogCSEWVmb/Bexb4/DPqyQkXsN/cHoSxNK1EKC2IeGN -eGlVRGn1ypYcNIUXJXfi9i8nmHj9eQY6otZaQ8H/7AQ77hPv01ha/5Lr7K7a8jcD -R0G2l8ktCkEiu7vmpwIDAQABo4IBJTCCASEwEQYJYIZIAYb4QgEBBAQDAgAHMGUG -A1UdHwReMFwwWqBYoFakVDBSMQswCQYDVQQGEwJESzEVMBMGA1UEChMMVERDIElu -dGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQgUm9vdCBDQTENMAsGA1UEAxME -Q1JMMTArBgNVHRAEJDAigA8yMDAxMDQwNTE2MzMxN1qBDzIwMjEwNDA1MTcwMzE3 -WjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUbGQBx/2FbazI2p5QCIUItTxWqFAw -HQYDVR0OBBYEFGxkAcf9hW2syNqeUAiFCLU8VqhQMAwGA1UdEwQFMAMBAf8wHQYJ -KoZIhvZ9B0EABBAwDhsIVjUuMDo0LjADAgSQMA0GCSqGSIb3DQEBBQUAA4IBAQBO -Q8zR3R0QGwZ/t6T609lN+yOfI1Rb5osvBCiLtSdtiaHsmGnc540mgwV5dOy0uaOX -wTUA/RXaOYE6lTGQ3pfphqiZdwzlWqCE/xIWrG64jcN7ksKsLtB9KOy282A4aW8+ -2ARVPp7MVdK6/rtHBNcK2RYKNCn1WBPVT8+PVkuzHu7TmHnaCB4Mb7j4Fifvwm89 -9qNLPg7kbWzbO0ESm70NRyN/PErQr8Cv9u8btRXE64PECV90i9kR+8JWsTz4cMo0 -jUNAE4z9mQNUecYu6oah9jrUCbz0vGbMPVjQV0kK7iXiQe4T+Zs4NNEA9X7nlB38 -aQNiuJkFBT1reBK9sG9l ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEGjCCAwICEQDsoKeLbnVqAc/EfMwvlF7XMA0GCSqGSIb3DQEBBQUAMIHKMQsw -CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl -cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu -LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT -aWduIENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp -dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD -VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT -aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ -bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu -IENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg -LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK3LpRFpxlmr8Y+1 -GQ9Wzsy1HyDkniYlS+BzZYlZ3tCD5PUPtbut8XzoIfzk6AzufEUiGXaStBO3IFsJ -+mGuqPKljYXCKtbeZjbSmwL0qJJgfJxptI8kHtCGUvYynEFYHiK9zUVilQhu0Gbd -U6LM8BDcVHOLBKFGMzNcF0C5nk3T875Vg+ixiY5afJqWIpA7iCXy0lOIAgwLePLm -NxdLMEYH5IBtptiWLugs+BGzOA1mppvqySNb247i8xOOGlktqgLw7KSHZtzBP/XY -ufTsgsbSPZUd5cBPhMnZo0QoBmrXRazwa2rvTl/4EYIeOGM0ZlDUPpNz+jDDZq3/ -ky2X7wMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAj/ola09b5KROJ1WrIhVZPMq1 -CtRK26vdoV9TxaBXOcLORyu+OshWv8LZJxA6sQU8wHcxuzrTBXttmhwwjIDLk5Mq -g6sFUYICABFna/OIYUdfA5PVWw3g8dShMjWFsjrbsIKr0csKvE+MW8VLADsfKoKm -fjaF3H48ZwC15DtS4KjrXRX5xm3wrR0OhbepmnMUWluPQSjA1egtTaRezarZ7c7c -2NU8Qh0XwRJdRTjDOPP8hS6DRkiy1yBfkjaP53kPmF6Z6PDQpLv1U70qzlmwr25/ -bLvSHgCwIe34QWKCudiyxLtGUPMxxY8BqHTr9Xgn2uf3ZkPznoM+IKrDNWCRzg== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJTRTEU -MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3 -b3JrMSMwIQYDVQQDExpBZGRUcnVzdCBRdWFsaWZpZWQgQ0EgUm9vdDAeFw0wMDA1 -MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcxCzAJBgNVBAYTAlNFMRQwEgYDVQQK -EwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5ldHdvcmsxIzAh -BgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBSb290MIIBIjANBgkqhkiG9w0B -AQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoekn0e+EV+vhDTbYjx5eLfpMLXsDBwq -xBb/4Oxx64r1EW7tTw2R0hIYLUkVAcKkIhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G -87B4pfYOQnrjfxvM0PC3KP0q6p6zsLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i -2O+tCBGaKZnhqkRFmhJePp1tUvznoD1oL/BLcHwTOK28FSXx1s6rosAx1i+f4P8U -WfyEk9mHfExUE+uf0S0R+Bg6Ot4l2ffTQO2kBhLEO+GRwVY18BTcZTYJbqukB8c1 -0cIDMzZbdSZtQvESa0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HUMIHRMB0G -A1UdDgQWBBQ5lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0T -AQH/BAUwAwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6Fr -pGkwZzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQL -ExRBZGRUcnVzdCBUVFAgTmV0d29yazEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVhbGlm -aWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBABmrder4i2VhlRO6aQTv -hsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxGGuoYQ992zPlm -hpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx95dr6h+sNNVJn0J6X -dgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKFYqa0p9m9N5xotS1WfbC3 -P6CxB9bpT9zeRXEwMn8bLgn5v1Kh7sKAPgZcLlVAwRv1cEWw3F369nJad9Jjzc9Y -iQBCYz95OdBEsIJuQRno3eDBiFrRHnGTHyQwdOUeqN48Jzd/g66ed8/wMLH/S5no -xqE= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJVUzEc -MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1aWZheCBT -ZWN1cmUgR2xvYmFsIGVCdXNpbmVzcyBDQS0xMB4XDTk5MDYyMTA0MDAwMFoXDTIw -MDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0VxdWlmYXggU2Vj -dXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJlIEdsb2JhbCBlQnVzaW5l -c3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuucXkAJlsTRVPEnC -UdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQytd4zjTov2/KaelpzmKNc6fuKcxtc -58O/gGzNqfTWK8D3+ZmqY6KxRwIP1ORROhI8bIpaVIRw28HFkM9yRcuoWcDNM50/ -o5brhTMhHD4ePmBudpxnhcXIw2ECAwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAH -MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUvqigdHJQa0S3ySPY+6j/s1dr -aGwwHQYDVR0OBBYEFL6ooHRyUGtEt8kj2Puo/7NXa2hsMA0GCSqGSIb3DQEBBAUA -A4GBADDiAVGqx+pf2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okENI7SS+RkA -Z70Br83gcfxaz2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv -8qIYNMR1pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDEL -MAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMp -IDIwMDcgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAi -BgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMjAeFw0wNzExMDUwMDAw -MDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh -d3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBGb3Ig -YXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9v -dCBDQSAtIEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/ -BebfowJPDQfGAFG6DAJSLSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6 -papu+7qzcMBniKI11KOasf2twu8x+qi58/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8E -BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUmtgAMADna3+FGO6Lts6K -DPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUNG4k8VIZ3 -KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41ox -XZ3Krr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFUjCCBDqgAwIBAgIBAjANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJLUjEN -MAsGA1UEChMES0lTQTEuMCwGA1UECxMlS29yZWEgQ2VydGlmaWNhdGlvbiBBdXRo -b3JpdHkgQ2VudHJhbDEWMBQGA1UEAxMNS0lTQSBSb290Q0EgMzAeFw0wNDExMTkw -NjM5NTFaFw0xNDExMTkwNjM5NTFaMGQxCzAJBgNVBAYTAktSMQ0wCwYDVQQKEwRL -SVNBMS4wLAYDVQQLEyVLb3JlYSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBDZW50 -cmFsMRYwFAYDVQQDEw1LSVNBIFJvb3RDQSAzMIIBIDANBgkqhkiG9w0BAQEFAAOC -AQ0AMIIBCAKCAQEA3rrtF2Wu0b1KPazbgHLMWOHn4ZPazDB6z+8Lri2nQ6u/p0LP -CFYIpEcdffqG79gwlyY0YTyADvjU65/8IjAboW0+40zSVU4WQDfC9gdu2we1pYyW -geKbXH6UYcjOhDyx+gDmctMJhXfp3F4hT7TkTvTiF6tQrxz/oTlYdVsSspa5jfBw -YkhbVigqpYeRNrkeJPW5unu2UlFbF1pgBWycwubGjD756t08jP+J3kNwrB248XXN -OMpTDUdoasY8GMq94bS+DvTQ49IT+rBRERHUQavo9DmO4TSETwuTqmo4/OXGeEeu -dhf6oYA3BgAVCP1rI476cg2V1ktisWjC3TSbXQIBA6OCAg8wggILMB8GA1UdIwQY -MBaAFI+B8NqmzXQ8vmb0FWtGpP4GKMyqMB0GA1UdDgQWBBSPgfDaps10PL5m9BVr -RqT+BijMqjAOBgNVHQ8BAf8EBAMCAQYwggEuBgNVHSAEggElMIIBITCCAR0GBFUd -IAAwggETMDAGCCsGAQUFBwIBFiRodHRwOi8vd3d3LnJvb3RjYS5vci5rci9yY2Ev -Y3BzLmh0bWwwgd4GCCsGAQUFBwICMIHRHoHOx3QAIMd4yZ3BHLKUACCs9cd4x3jJ -ncEcx4WyyLLkACgAVABoAGkAcwAgAGMAZQByAHQAaQBmAGkAYwBhAHQAZQAgAGkA -cwAgAGEAYwBjAHIAZQBkAGkAdABlAGQAIAB1AG4AZABlAHIAIABFAGwAZQBjAHQA -cgBvAG4AaQBjACAAUwBpAGcAbgBhAHQAdQByAGUAIABBAGMAdAAgAG8AZgAgAHQA -aABlACAAUgBlAHAAdQBiAGwAaQBjACAAbwBmACAASwBvAHIAZQBhACkwMwYDVR0R -BCwwKqQoMCYxJDAiBgNVBAMMG+2VnOq1reygleuztOuztO2YuOynhO2dpeybkDAz -BgNVHRIELDAqpCgwJjEkMCIGA1UEAwwb7ZWc6rWt7KCV67O067O07Zi47KeE7Z2l -7JuQMA8GA1UdEwEB/wQFMAMBAf8wDAYDVR0kBAUwA4ABADANBgkqhkiG9w0BAQUF -AAOCAQEAz9b3Dv2wjG4FFY6oXCuyWtEeV6ZeGKqCEQj8mbdbp+PI0qLT+SQ09+Pk -rolUR9NpScmAwRHr4inH9gaLX7riXs+rw87P7pIl3J85Hg4D9N6QW6FwmVzHc07J -pHVJeyWhn4KSjU3sYcUMMqfHODiAVToqgx2cZHm5Dac1Smjvj/8F2LpOVmHY+Epw -mAiWk9hgxzrsX58dKzVPSBShmrtv7tIDhlPxEMcHVGJeNo7iHCsdF03m9VrvirqC -6HfZKBF+N4dKlArJQOk1pTr7ZD7yXxZ683bXzu4/RB1Fql8RqlMcOh9SUWJUD6OQ -Nc9Nb7rHviwJ8TX4Absk3TC8SA/u2Q== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDoTCCAomgAwIBAgIQKTZHquOKrIZKI1byyrdhrzANBgkqhkiG9w0BAQUFADBO -MQswCQYDVQQGEwJ1czEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQ0wCwYDVQQL -EwRGQkNBMRYwFAYDVQQDEw1Db21tb24gUG9saWN5MB4XDTA3MTAxNTE1NTgwMFoX -DTI3MTAxNTE2MDgwMFowTjELMAkGA1UEBhMCdXMxGDAWBgNVBAoTD1UuUy4gR292 -ZXJubWVudDENMAsGA1UECxMERkJDQTEWMBQGA1UEAxMNQ29tbW9uIFBvbGljeTCC -ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJeNvTMn5K1b+3i9L0dHbsd4 -6ZOcpN7JHP0vGzk4rEcXwH53KQA7Ax9oD81Npe53uCxiazH2+nIJfTApBnznfKM9 -hBiKHa4skqgf6F5PjY7rPxr4nApnnbBnTfAu0DDew5SwoM8uCjR/VAnTNr2kSVdS -c+md/uRIeUYbW40y5KVIZPMiDZKdCBW/YDyD90ciJSKtKXG3d+8XyaK2lF7IMJCk -FEhcVlcLQUwF1CpMP64Sm1kRdXAHImktLNMxzJJ+zM2kfpRHqpwJCPZLr1LoakCR -xVW9QLHIbVeGlRfmH3O+Ry4+i0wXubklHKVSFzYIWcBCvgortFZRPBtVyYyQd+sC -AwEAAaN7MHkwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O -BBYEFC9Yl9ipBZilVh/72at17wI8NjTHMBIGCSsGAQQBgjcVAQQFAgMBAAEwIwYJ -KwYBBAGCNxUCBBYEFHa3YJbdFFYprHWF03BjwbxHhhyLMA0GCSqGSIb3DQEBBQUA -A4IBAQBgrvNIFkBypgiIybxHLCRLXaCRc+1leJDwZ5B6pb8KrbYq+Zln34PFdx80 -CTj5fp5B4Ehg/uKqXYeI6oj9XEWyyWrafaStsU+/HA2fHprA1RRzOCuKeEBuMPdi -4c2Z/FFpZ2wR3bgQo2jeJqVW/TZsN5hs++58PGxrcD/3SDcJjwtCga1GRrgLgwb0 -Gzigf0/NC++DiYeXHIowZ9z9VKEDfgHLhUyxCynDvux84T8PCVI8L6eaSP436REG -WOE2QYrEtr+O3c5Ks7wawM36GpnScZv6z7zyxFSjiDV2zBssRm8MtNHDYXaSdBHq -S4CNHIkRi+xb/xfJSPzn4AYR4oRe ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEPTCCAyWgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvzE/MD0GA1UEAww2VMOc -UktUUlVTVCBFbGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sx -c8SxMQswCQYDVQQGEwJUUjEPMA0GA1UEBwwGQW5rYXJhMV4wXAYDVQQKDFVUw5xS -S1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kg -SGl6bWV0bGVyaSBBLsWeLiAoYykgQXJhbMSxayAyMDA3MB4XDTA3MTIyNTE4Mzcx -OVoXDTE3MTIyMjE4MzcxOVowgb8xPzA9BgNVBAMMNlTDnFJLVFJVU1QgRWxla3Ry -b25payBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTELMAkGA1UEBhMC -VFIxDzANBgNVBAcMBkFua2FyYTFeMFwGA1UECgxVVMOcUktUUlVTVCBCaWxnaSDE -sGxldGnFn2ltIHZlIEJpbGnFn2ltIEfDvHZlbmxpxJ9pIEhpem1ldGxlcmkgQS7F -ni4gKGMpIEFyYWzEsWsgMjAwNzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC -ggEBAKu3PgqMyKVYFeaK7yc9SrToJdPNM8Ig3BnuiD9NYvDdE3ePYakqtdTyuTFY -KTsvP2qcb3N2Je40IIDu6rfwxArNK4aUyeNgsURSsloptJGXg9i3phQvKUmi8wUG -+7RP2qFsmmaf8EMJyupyj+sA1zU511YXRxcw9L6/P8JorzZAwan0qafoEGsIiveG -HtyaKhUG9qPw9ODHFNRRf8+0222vR5YXm3dx2KdxnSQM9pQ/hTEST7ruToK4uT6P -IzdezKKqdfcYbwnTrqdUKDT74eA7YH2gvnmJhsifLfkKS8RQouf9eRbHegsYz85M -733WB2+Y8a+xwXrXgTW4qhe04MsCAwEAAaNCMEAwHQYDVR0OBBYEFCnFkKslrxHk -Yb+j/4hhkeYO/pyBMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0G -CSqGSIb3DQEBBQUAA4IBAQAQDdr4Ouwo0RSVgrESLFF6QSU2TJ/sPx+EnWVUXKgW -AkD6bho3hO9ynYYKVZ1WKKxmLNA6VpM0ByWtCLCPyA8JWcqdmBzlVPi5RX9ql2+I -aE1KBiY3iAIOtsbWcpnOa3faYjGkVh+uX4132l32iPwa2Z61gfAyuOOI0JzzaqC5 -mxRZNTZPz/OOXl0XrRWV2N2y1RVuAE6zS89mlOTgzbUF2mNXi+WzqtvALhyQRNsa -XRik7r4EW5nVcV9VZWRi1aKbBFmGyGJ353yCRWo9F7/snXUMrqNvWtMvmDb08PUZ -qxFdyKbjKlhqQgnDvZImZjINXQhVdP+MmNAKpoRq0Tl9 ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCB -gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G -A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV -BAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEyMDEwMDAw -MDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl -YXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01P -RE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0 -aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3 -UcEbVASY06m/weaKXTuH+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI -2GqGd0S7WWaXUF601CxwRM/aN5VCaTwwxHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8 -Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV4EajcNxo2f8ESIl33rXp -+2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA1KGzqSX+ -DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5O -nKVIrLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW -/zAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6g -PKA6hjhodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9u -QXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOCAQEAPpiem/Yb6dc5t3iuHXIY -SdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CPOGEIqB6BCsAv -IC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/ -RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4 -zJVSk/BwJVmcIGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5dd -BA6+C4OmF4O5MBKgxTMVBbkN+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IB -ZQ== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIIQTCCB6qgAwIBAgIBADANBgkqhkiG9w0BAQUFADCCAR4xCzAJBgNVBAYTAkVT -MRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UE -ChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5sLjErMCkGA1UE -ChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1MjE0MDIGA1UECxMr -SVBTIENBIFRpbWVzdGFtcGluZyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTE0MDIG -A1UEAxMrSVBTIENBIFRpbWVzdGFtcGluZyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 -eTEeMBwGCSqGSIb3DQEJARYPaXBzQG1haWwuaXBzLmVzMB4XDTAxMTIzMTExMjY0 -M1oXDTI1MTIyOTExMjY0M1owggEeMQswCQYDVQQGEwJFUzESMBAGA1UECBMJQmFy -Y2Vsb25hMRIwEAYDVQQHEwlCYXJjZWxvbmExLjAsBgNVBAoTJUlQUyBJbnRlcm5l -dCBwdWJsaXNoaW5nIFNlcnZpY2VzIHMubC4xKzApBgNVBAoUImlwc0BtYWlsLmlw -cy5lcyBDLkkuRi4gIEItNjA5Mjk0NTIxNDAyBgNVBAsTK0lQUyBDQSBUaW1lc3Rh -bXBpbmcgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxNDAyBgNVBAMTK0lQUyBDQSBU -aW1lc3RhbXBpbmcgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxHjAcBgkqhkiG9w0B -CQEWD2lwc0BtYWlsLmlwcy5lczCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA -0umTdn+FPP2gAb0RL0ZCDyt/BZvGa/VRcayaUh8flSfMkO+WP45RNv0WAM43pSGU -Rmvt5P+hfuqf0aKbOPMTxLmYumVFQ/nXvRWdlC4AYN6YGrk8yfXh/NbEJN/n48iE -GRK0HFyz9eIWYSdg8vAt5PDzrPigeYSdReL2AfBE5ZECAwEAAaOCBIkwggSFMB0G -A1UdDgQWBBSR2UK8nKnK0Bw3E1JXFqANHikdPjCCAVAGA1UdIwSCAUcwggFDgBSR -2UK8nKnK0Bw3E1JXFqANHikdPqGCASakggEiMIIBHjELMAkGA1UEBhMCRVMxEjAQ -BgNVBAgTCUJhcmNlbG9uYTESMBAGA1UEBxMJQmFyY2Vsb25hMS4wLAYDVQQKEyVJ -UFMgSW50ZXJuZXQgcHVibGlzaGluZyBTZXJ2aWNlcyBzLmwuMSswKQYDVQQKFCJp -cHNAbWFpbC5pcHMuZXMgQy5JLkYuICBCLTYwOTI5NDUyMTQwMgYDVQQLEytJUFMg -Q0EgVGltZXN0YW1waW5nIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MTQwMgYDVQQD -EytJUFMgQ0EgVGltZXN0YW1waW5nIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MR4w -HAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXOCAQAwDAYDVR0TBAUwAwEB/zAM -BgNVHQ8EBQMDB/+AMGsGA1UdJQRkMGIGCCsGAQUFBwMBBggrBgEFBQcDAgYIKwYB -BQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYKKwYBBAGCNwIBFQYKKwYBBAGCNwIB -FgYKKwYBBAGCNwoDAQYKKwYBBAGCNwoDBDARBglghkgBhvhCAQEEBAMCAAcwGgYD -VR0RBBMwEYEPaXBzQG1haWwuaXBzLmVzMBoGA1UdEgQTMBGBD2lwc0BtYWlsLmlw -cy5lczBIBglghkgBhvhCAQ0EOxY5VGltZXN0YW1waW5nIENBIENlcnRpZmljYXRl -IGlzc3VlZCBieSBodHRwczovL3d3dy5pcHMuZXMvMCoGCWCGSAGG+EIBAgQdFhto -dHRwczovL3d3dy5pcHMuZXMvaXBzMjAwMi8wQQYJYIZIAYb4QgEEBDQWMmh0dHBz -Oi8vd3d3Lmlwcy5lcy9pcHMyMDAyL2lwczIwMDJUaW1lc3RhbXBpbmcuY3JsMEYG -CWCGSAGG+EIBAwQ5FjdodHRwczovL3d3dy5pcHMuZXMvaXBzMjAwMi9yZXZvY2F0 -aW9uVGltZXN0YW1waW5nLmh0bWw/MEMGCWCGSAGG+EIBBwQ2FjRodHRwczovL3d3 -dy5pcHMuZXMvaXBzMjAwMi9yZW5ld2FsVGltZXN0YW1waW5nLmh0bWw/MEEGCWCG -SAGG+EIBCAQ0FjJodHRwczovL3d3dy5pcHMuZXMvaXBzMjAwMi9wb2xpY3lUaW1l -c3RhbXBpbmcuaHRtbDCBgQYDVR0fBHoweDA4oDagNIYyaHR0cHM6Ly93d3cuaXBz -LmVzL2lwczIwMDIvaXBzMjAwMlRpbWVzdGFtcGluZy5jcmwwPKA6oDiGNmh0dHBz -Oi8vd3d3YmFjay5pcHMuZXMvaXBzMjAwMi9pcHMyMDAyVGltZXN0YW1waW5nLmNy -bDAvBggrBgEFBQcBAQQjMCEwHwYIKwYBBQUHMAGGE2h0dHA6Ly9vY3NwLmlwcy5l -cy8wDQYJKoZIhvcNAQEFBQADgYEAxKMCdGABCUwYXU900W1zDCfTSDC1TxFVGRnH -I4soqfp4D34sJ/adkgD2GMgkAMVf+C1MY/yQFV4nmOal9K7SNrG1JR8OeDoRjpM4 -rtO9qYbuHD3TW47/y/aZSZxP4ccocGpPOkvqfrnndKRKY0WUk/7Qg5aqpIXni2Gg -olkTZbQ= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIID9zCCAt+gAwIBAgIESJ8AATANBgkqhkiG9w0BAQUFADCBijELMAkGA1UEBhMC -Q04xMjAwBgNVBAoMKUNoaW5hIEludGVybmV0IE5ldHdvcmsgSW5mb3JtYXRpb24g -Q2VudGVyMUcwRQYDVQQDDD5DaGluYSBJbnRlcm5ldCBOZXR3b3JrIEluZm9ybWF0 -aW9uIENlbnRlciBFViBDZXJ0aWZpY2F0ZXMgUm9vdDAeFw0xMDA4MzEwNzExMjVa -Fw0zMDA4MzEwNzExMjVaMIGKMQswCQYDVQQGEwJDTjEyMDAGA1UECgwpQ2hpbmEg -SW50ZXJuZXQgTmV0d29yayBJbmZvcm1hdGlvbiBDZW50ZXIxRzBFBgNVBAMMPkNo -aW5hIEludGVybmV0IE5ldHdvcmsgSW5mb3JtYXRpb24gQ2VudGVyIEVWIENlcnRp -ZmljYXRlcyBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm35z -7r07eKpkQ0H1UN+U8i6yjUqORlTSIRLIOTJCBumD1Z9S7eVnAztUwYyZmczpwA// -DdmEEbK40ctb3B75aDFk4Zv6dOtouSCV98YPjUesWgbdYavi7NifFy2cyjw1l1Vx -zUOFsUcW9SxTgHbP0wBkvUCZ3czY28Sf1hNfQYOL+Q2HklY0bBoQCxfVWhyXWIQ8 -hBouXJE0bhlffxdpxWXvayHG1VA6v2G5BY3vbzQ6sm8UY78WO5upKv23KzhmBsUs -4qpnHkWnjQRmQvaPK++IIGmPMowUc9orhpFjIpryp9vOiYurXccUwVswah+xt54u -gQEC7c+WXmPbqOY4twIDAQABo2MwYTAfBgNVHSMEGDAWgBR8cks5x8DbYqVPm6oY -NJKiyoOCWTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4E -FgQUfHJLOcfA22KlT5uqGDSSosqDglkwDQYJKoZIhvcNAQEFBQADggEBACrDx0M3 -j92tpLIM7twUbY8opJhJywyA6vPtI2Z1fcXTIWd50XPFtQO3WKwMVC/GVhMPMdoG -52U7HW8228gd+f2ABsqjPWYWqJ1MFn3AlUa1UeTiH9fqBk1jjZaM7+czV0I664zB -echNdn3e9rG3geCg+aF4RhcaVpjwTj2rHO3sOdwHSPdj/gauwqRcalsyiMXHM4Ws -ZkJHwlgkmeHlPuV1LI5D1l08eB6olYIpUNHRFrrvwb562bTYzB5MRuF3sTGrvSrI -zo9uoV1/A3U05K2JRVRevq4opbs/eHnrc7MKDf2+yfdWrPa37S+bISnHOLaVxATy -wy39FCqQmbkHzJ8= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDpDCCAoygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEc -MBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBP -bmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyODA2 -MDAwMFoXDTM3MTExOTIwNDMwMFowYzELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0Ft -ZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2EgT25saW5lIFJvb3Qg -Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIwDQYJKoZIhvcNAQEBBQADggEP -ADCCAQoCggEBAKgv6KRpBgNHw+kqmP8ZonCaxlCyfqXfaE0bfA+2l2h9LaaLl+lk -hsmj76CGv2BlnEtUiMJIxUo5vxTjWVXlGbR0yLQFOVwWpeKVBeASrlmLojNoWBym -1BW32J/X3HGrfpq/m44zDyL9Hy7nBzbvYjnF3cu6JRQj3gzGPTzOggjmZj7aUTsW -OqMFf6Dch9Wc/HKpoH145LcxVR5lu9RhsCFg7RAycsWSJR74kEoYeEfffjA3PlAb -2xzTa5qGUwew76wGePiEmf4hjUyAtgyC9mZweRrTT6PP8c9GsEsPPt2IYriMqQko -O3rHl+Ee5fSfwMCuJKDIodkP1nsmgmkyPacCAwEAAaNjMGEwDwYDVR0TAQH/BAUw -AwEB/zAdBgNVHQ4EFgQUAK3Zo/Z59m50qX8zPYEX10zPM94wHwYDVR0jBBgwFoAU -AK3Zo/Z59m50qX8zPYEX10zPM94wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB -BQUAA4IBAQB8itEfGDeC4Liwo+1WlchiYZwFos3CYiZhzRAW18y0ZTTQEYqtqKkF -Zu90821fnZmv9ov761KyBZiibyrFVL0lvV+uyIbqRizBs73B6UlwGBaXCBOMIOAb -LjpHyx7kADCVW/RFo8AasAFOq73AI25jP4BKxQft3OJvx8Fi8eNy1gTIdGcL+oir -oQHIb/AUr9KZzVGTfu0uOMe9zkZQPXLjeSWdm4grECDdpbgyn43gKd8hdIaC2y+C -MMbHNYaz+ZZfRtsMRf3zUMNvxsNIrUam4SdHCh0Om7bCd39j8uB9Gr784N/Xx6ds -sPmuujz9dLQR6FgNgLzTqIA6me11zEZ7 ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0 -IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz -BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y -aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG -9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMjIzM1oXDTE5MDYy -NjAwMjIzM1owgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y -azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs -YXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw -Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl -cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDjmFGWHOjVsQaBalfD -cnWTq8+epvzzFlLWLU2fNUSoLgRNB0mKOCn1dzfnt6td3zZxFJmP3MKS8edgkpfs -2Ejcv8ECIMYkpChMMFp2bbFc893enhBxoYjHW5tBbcqwuI4V7q0zK89HBFx1cQqY -JJgpp0lZpd34t0NiYfPT4tBVPwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFa7AliE -Zwgs3x/be0kz9dNnnfS0ChCzycUs4pJqcXgn8nCDQtM+z6lU9PHYkhaM0QTLS6vJ -n0WuPIqpsHEzXcjFV9+vqDWzf4mH6eglkrh/hXqu1rweN1gqZ8mRzyqBPu3GOd/A -PhmcGcwTTYJBtYze4D1gCCAPRX5ron+jjBXu ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEZDCCA0ygAwIBAgIQRL4Mi1AAJLQR0zYwS8AzdzANBgkqhkiG9w0BAQUFADCB -ozELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug -Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho -dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzApBgNVBAMTIlVUTi1VU0VSRmlyc3Qt -TmV0d29yayBBcHBsaWNhdGlvbnMwHhcNOTkwNzA5MTg0ODM5WhcNMTkwNzA5MTg1 -NzQ5WjCBozELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0 -IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYD -VQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzApBgNVBAMTIlVUTi1VU0VS -Rmlyc3QtTmV0d29yayBBcHBsaWNhdGlvbnMwggEiMA0GCSqGSIb3DQEBAQUAA4IB -DwAwggEKAoIBAQCz+5Gh5DZVhawGNFugmliy+LUPBXeDrjKxdpJo7CNKyXY/45y2 -N3kDuatpjQclthln5LAbGHNhSuh+zdMvZOOmfAz6F4CjDUeJT1FxL+78P/m4FoCH -iZMlIJpDgmkkdihZNaEdwH+DBmQWICzTSaSFtMBhf1EI+GgVkYDLpdXuOzr0hARe -YFmnjDRy7rh4xdE7EkpvfmUnuaRVxblvQ6TFHSyZwFKkeEwVs0CYCGtDxgGwenv1 -axwiP8vv/6jQOkt2FZ7S0cYu49tXGzKiuG/ohqY/cKvlcJKrRB5AUPuco2LkbG6g -yN7igEL66S/ozjIEj3yNtxyjNTwV3Z7DrpelAgMBAAGjgZEwgY4wCwYDVR0PBAQD -AgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFPqGydvguul49Uuo1hXf8NPh -ahQ8ME8GA1UdHwRIMEYwRKBCoECGPmh0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9V -VE4tVVNFUkZpcnN0LU5ldHdvcmtBcHBsaWNhdGlvbnMuY3JsMA0GCSqGSIb3DQEB -BQUAA4IBAQCk8yXM0dSRgyLQzDKrm5ZONJFUICU0YV8qAhXhi6r/fWRRzwr/vH3Y -IWp4yy9Rb/hCHTO967V7lMPDqaAt39EpHx3+jz+7qEUqf9FuVSTiuwL7MT++6Lzs -QCv4AdRWOOTKRIK1YSAhZ2X28AvnNPilwpyjXEAfhZOVBt5P1CeptqX8Fs1zMT+4 -ZSfP1FMa8Kxun08FDAOBp4QpxFq9ZFdyrTvPNximmMatBrTcCKME1SmklpoSZ0qM -YEWd8SOasACcaLWYUNPvji6SZbFIPiG+FTAqDbUMo2s/rn9X9R+WfN9v3YIwLGUb -QErNaLly7HF27FSOH4UMAWr6pjisH8SE ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEW -MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVy -c2FsIENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYD -VQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1 -c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC -AQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0DE81 -WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUG -FF+3Qs17j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdq -XbboW0W63MOhBW9Wjo8QJqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxL -se4YuU6W3Nx2/zu+z18DwPw76L5GG//aQMJS9/7jOvdqdzXQ2o3rXhhqMcceujwb -KNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2WP0+GfPtDCapkzj4T8Fd -IgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP20gaXT73 -y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRt -hAAnZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgoc -QIgfksILAAX/8sgCSqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4 -Lt1ZrtmhN79UNdxzMk+MBB4zsslG8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNV -HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAfBgNV -HSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8EBAMCAYYwDQYJ -KoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z -dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQ -L1EuxBRa3ugZ4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgr -Fg5fNuH8KrUwJM/gYwx7WBr+mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSo -ag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpqA1Ihn0CoZ1Dy81of398j9tx4TuaY -T1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpgY+RdM4kX2TGq2tbz -GDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiPpm8m -1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJV -OCiNUW7dFGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH -6aLcr34YEoP9VhdBLtUpgn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwX -QMAJKOSLakhT2+zNVVXxxvjpoixMptEmX36vWkzaH6byHCx+rgIW0lbQL1dTR+iS ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFwTCCA6mgAwIBAgIITrIAZwwDXU8wDQYJKoZIhvcNAQEFBQAwSTELMAkGA1UE -BhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEjMCEGA1UEAxMaU3dpc3NTaWdu -IFBsYXRpbnVtIENBIC0gRzIwHhcNMDYxMDI1MDgzNjAwWhcNMzYxMDI1MDgzNjAw -WjBJMQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMSMwIQYDVQQD -ExpTd2lzc1NpZ24gUGxhdGludW0gQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEBBQAD -ggIPADCCAgoCggIBAMrfogLi2vj8Bxax3mCq3pZcZB/HL37PZ/pEQtZ2Y5Wu669y -IIpFR4ZieIbWIDkm9K6j/SPnpZy1IiEZtzeTIsBQnIJ71NUERFzLtMKfkr4k2Htn -IuJpX+UFeNSH2XFwMyVTtIc7KZAoNppVRDBopIOXfw0enHb/FZ1glwCNioUD7IC+ -6ixuEFGSzH7VozPY1kneWCqv9hbrS3uQMpe5up1Y8fhXSQQeol0GcN1x2/ndi5ob -jM89o03Oy3z2u5yg+gnOI2Ky6Q0f4nIoj5+saCB9bzuohTEJfwvH6GXp43gOCWcw -izSC+13gzJ2BbWLuCB4ELE6b7P6pT1/9aXjvCR+htL/68++QHkwFix7qepF6w9fl -+zC8bBsQWJj3Gl/QKTIDE0ZNYWqFTFJ0LwYfexHihJfGmfNtf9dng34TaNhxKFrY -zt3oEBSa/m0jh26OWnA81Y0JAKeqvLAxN23IhBQeW71FYyBrS3SMvds6DsHPWhaP -pZjydomyExI7C3d3rLvlPClKknLKYRorXkzig3R3+jVIeoVNjZpTxN94ypeRSCtF -KwH3HBqi7Ri6Cr2D+m+8jVeTO9TUps4e8aCxzqv9KyiaTxvXw3LbpMS/XUz13XuW -ae5ogObnmLo2t/5u7Su9IPhlGdpVCX4l3P5hYnL5fhgC72O00Puv5TtjjGePAgMB -AAGjgawwgakwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O -BBYEFFCvzAeHFUdvOMW0ZdHelarp35zMMB8GA1UdIwQYMBaAFFCvzAeHFUdvOMW0 -ZdHelarp35zMMEYGA1UdIAQ/MD0wOwYJYIV0AVkBAQEBMC4wLAYIKwYBBQUHAgEW -IGh0dHA6Ly9yZXBvc2l0b3J5LnN3aXNzc2lnbi5jb20vMA0GCSqGSIb3DQEBBQUA -A4ICAQAIhab1Fgz8RBrBY+D5VUYI/HAcQiiWjrfFwUF1TglxeeVtlspLpYhg0DB0 -uMoI3LQwnkAHFmtllXcBrqS3NQuB2nEVqXQXOHtYyvkv+8Bldo1bAbl93oI9ZLi+ -FHSjClTTLJUYFzX1UWs/j6KWYTl4a0vlpqD4U99REJNi54Av4tHgvI42Rncz7Lj7 -jposiU0xEQ8mngS7twSNC/K5/FqdOxa3L8iYq/6KUFkuozv8KV2LwUvJ4ooTHbG/ -u0IdUt1O2BReEMYxB+9xJ/cbOQncguqLs5WGXv312l0xpuAxtpTmREl0xRbl9x8D -YSjFyMsSoEJL+WuICI20MhjzdZ/EfwBPBZWcoxcCw7NTm6ogOSkrZvqdr16zktK1 -puEa+S1BaYEUtLS17Yk9zvupnTVCRLEcFHOBzyoBNZox1S2PbYTfgE1X4z/FhHXa -icYwu+uPyyIIoK6q8QNsOktNCaUOcsZWayFCTiMlFGiudgp8DAdwZPmaL/YFOSbG -DI8Zf0NebvRbFS/bYV3mZy8/CJT5YLSYMdp08YSTcU1f+2BY0fvEwW2JorsgH51x -kcsymxM9Pn2SUjWskpSi0xjCfMfqr3YFFt1nJ8J+HAciIfNAChs0B0QTwoRqjt8Z -Wr9/6x3iGjjRXK9HkmuAtTClyY3YqzGBH9/CZjfTk6mFhnll0g== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEW -MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg -Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh -dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM2WhcNMzYwOTE3MTk0NjM2WjB9 -MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi -U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh -cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA -A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk -pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf -OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C -Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT -Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi -HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM -Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w -+2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+ -Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3 -Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B -26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID -AQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE -FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9j -ZXJ0LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3Js -LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFM -BgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUHAgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0 -Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRwOi8vY2VydC5zdGFy -dGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYgU3Rh -cnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlh -YmlsaXR5LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2Yg -dGhlIFN0YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFp -bGFibGUgYXQgaHR0cDovL2NlcnQuc3RhcnRjb20ub3JnL3BvbGljeS5wZGYwEQYJ -YIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNT -TCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOCAgEAFmyZ -9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8 -jhvh3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUW -FjgKXlf2Ysd6AgXmvB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJz -ewT4F+irsfMuXGRuczE6Eri8sxHkfY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1 -ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3fsNrarnDy0RLrHiQi+fHLB5L -EUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZEoalHmdkrQYu -L6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq -yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuC -O3NJo2pXh5Tl1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6V -um0ABj6y6koQOdjQK/W/7HW/lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkySh -NOsF/5oirpt9P/FlUQqmMGqz9IgcgA38corog14= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIH9zCCB2CgAwIBAgIBADANBgkqhkiG9w0BAQUFADCCARQxCzAJBgNVBAYTAkVT -MRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UE -ChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5sLjErMCkGA1UE -ChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1MjEvMC0GA1UECxMm -SVBTIENBIENMQVNFQTEgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxLzAtBgNVBAMT -JklQUyBDQSBDTEFTRUExIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MR4wHAYJKoZI -hvcNAQkBFg9pcHNAbWFpbC5pcHMuZXMwHhcNMDExMjI5MDEwNTMyWhcNMjUxMjI3 -MDEwNTMyWjCCARQxCzAJBgNVBAYTAkVTMRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQ -BgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UEChMlSVBTIEludGVybmV0IHB1Ymxpc2hp -bmcgU2VydmljZXMgcy5sLjErMCkGA1UEChQiaXBzQG1haWwuaXBzLmVzIEMuSS5G -LiAgQi02MDkyOTQ1MjEvMC0GA1UECxMmSVBTIENBIENMQVNFQTEgQ2VydGlmaWNh -dGlvbiBBdXRob3JpdHkxLzAtBgNVBAMTJklQUyBDQSBDTEFTRUExIENlcnRpZmlj -YXRpb24gQXV0aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXMw -gZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALsw19zQVL01Tp/FTILq0VA8R5j8 -m2mdd81u4D/u6zJfX5/S0HnllXNEITLgCtud186Nq1KLK3jgm1t99P1tCeWu4Wwd -ByOgF9H5fahGRpEiqLJpxq339fWUoTCUvQDMRH/uxJ7JweaPCjbB/SQ9AaD1e+J8 -eGZDi09Z8pvZ+kmzAgMBAAGjggRTMIIETzAdBgNVHQ4EFgQUZyaW56G/2LUDnf47 -3P7yiuYV3TAwggFGBgNVHSMEggE9MIIBOYAUZyaW56G/2LUDnf473P7yiuYV3TCh -ggEcpIIBGDCCARQxCzAJBgNVBAYTAkVTMRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQ -BgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UEChMlSVBTIEludGVybmV0IHB1Ymxpc2hp -bmcgU2VydmljZXMgcy5sLjErMCkGA1UEChQiaXBzQG1haWwuaXBzLmVzIEMuSS5G -LiAgQi02MDkyOTQ1MjEvMC0GA1UECxMmSVBTIENBIENMQVNFQTEgQ2VydGlmaWNh -dGlvbiBBdXRob3JpdHkxLzAtBgNVBAMTJklQUyBDQSBDTEFTRUExIENlcnRpZmlj -YXRpb24gQXV0aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXOC -AQAwDAYDVR0TBAUwAwEB/zAMBgNVHQ8EBQMDB/+AMGsGA1UdJQRkMGIGCCsGAQUF -BwMBBggrBgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYKKwYB -BAGCNwIBFQYKKwYBBAGCNwIBFgYKKwYBBAGCNwoDAQYKKwYBBAGCNwoDBDARBglg -hkgBhvhCAQEEBAMCAAcwGgYDVR0RBBMwEYEPaXBzQG1haWwuaXBzLmVzMBoGA1Ud -EgQTMBGBD2lwc0BtYWlsLmlwcy5lczBCBglghkgBhvhCAQ0ENRYzQ0xBU0VBMSBD -QSBDZXJ0aWZpY2F0ZSBpc3N1ZWQgYnkgaHR0cDovL3d3dy5pcHMuZXMvMCkGCWCG -SAGG+EIBAgQcFhpodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyLzA7BglghkgBhvhC -AQQELhYsaHR0cDovL3d3dy5pcHMuZXMvaXBzMjAwMi9pcHMyMDAyQ0xBU0VBMS5j -cmwwQAYJYIZIAYb4QgEDBDMWMWh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvcmV2 -b2NhdGlvbkNMQVNFQTEuaHRtbD8wPQYJYIZIAYb4QgEHBDAWLmh0dHA6Ly93d3cu -aXBzLmVzL2lwczIwMDIvcmVuZXdhbENMQVNFQTEuaHRtbD8wOwYJYIZIAYb4QgEI -BC4WLGh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvcG9saWN5Q0xBU0VBMS5odG1s -MHUGA1UdHwRuMGwwMqAwoC6GLGh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvaXBz -MjAwMkNMQVNFQTEuY3JsMDagNKAyhjBodHRwOi8vd3d3YmFjay5pcHMuZXMvaXBz -MjAwMi9pcHMyMDAyQ0xBU0VBMS5jcmwwLwYIKwYBBQUHAQEEIzAhMB8GCCsGAQUF -BzABhhNodHRwOi8vb2NzcC5pcHMuZXMvMA0GCSqGSIb3DQEBBQUAA4GBAH66iqyA -AIQVCtWYUQxkxZwCWINmyq0eB81+atqAB98DNEock8RLWCA1NnHtogo1EqWmZaeF -aQoO42Hu6r4okzPV7Oi+xNtff6j5YzHIa5biKcJboOeXNp13XjFr/tOn2yrb25aL -H2betgPAK7N41lUH5Y85UN4HI3LmvSAUS7SG ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEGjCCAwKgAwIBAgIDAYagMA0GCSqGSIb3DQEBBQUAMIGjMQswCQYDVQQGEwJG -STEQMA4GA1UECBMHRmlubGFuZDEhMB8GA1UEChMYVmFlc3RvcmVraXN0ZXJpa2Vz -a3VzIENBMSkwJwYDVQQLEyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBTZXJ2aWNl -czEZMBcGA1UECxMQVmFybWVubmVwYWx2ZWx1dDEZMBcGA1UEAxMQVlJLIEdvdi4g -Um9vdCBDQTAeFw0wMjEyMTgxMzUzMDBaFw0yMzEyMTgxMzUxMDhaMIGjMQswCQYD -VQQGEwJGSTEQMA4GA1UECBMHRmlubGFuZDEhMB8GA1UEChMYVmFlc3RvcmVraXN0 -ZXJpa2Vza3VzIENBMSkwJwYDVQQLEyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBT -ZXJ2aWNlczEZMBcGA1UECxMQVmFybWVubmVwYWx2ZWx1dDEZMBcGA1UEAxMQVlJL -IEdvdi4gUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALCF -FdrIAzfQo0Y3bBseljDCWoUSZyPyu5/nioFgJ/gTqTy894aqqvTzJSm0/nWuHoGG -igWyHWWyOOi0zCia+xc28ZPVec7Bg4shT8MNrUHfeJ1I4x9CRPw8bSEga60ihCRC -jxdNwlAfZM0tOSJWiP2yY51U2kJpwMhP1xjiPshphJQ9LIDGfM6911Mf64i5psu7 -hVfvV3ZdDIvTXhJBnyHAOfQmbQj6OLOhd7HuFtjQaNq0mKWgZUZKa41+qk1guPjI -DfxxPu45h4G02fhukO4/DmHXHSto5i7hQkQmeCxY8n0Wf2HASSQqiYe2XS8pGfim -545SnkFLWg6quMJmQlMCAwEAAaNVMFMwDwYDVR0TAQH/BAUwAwEB/zARBglghkgB -hvhCAQEEBAMCAAcwDgYDVR0PAQH/BAQDAgHGMB0GA1UdDgQWBBTb6eGb0tEkC/yr -46Bn6q6cS3f0sDANBgkqhkiG9w0BAQUFAAOCAQEArX1ID1QRnljurw2bEi8hpM2b -uoRH5sklVSPj3xhYKizbXvfNVPVRJHtiZ+GxH0mvNNDrsczZog1Sf0JLiGCXzyVy -t08pLWKfT6HAVVdWDsRol5EfnGTCKTIB6dTI2riBmCguGMcs/OubUpbf9MiQGS0j -8/G7cdqehSO9Gu8u5Hp5t8OdhkktY7ktdM9lDzJmid87Ie4pbzlj2RXBbvbfgD5Q -eBmK3QOjFKU3p7UsfLYRh+cF8ry23tT/l4EohP7+bEaFEEGfTXWMB9SZZ291im/k -UJL2mdUQuMSpe/cXjUu/15WfCdxEDx4yw8DP03kN5Mc7h/CQNIghYkmSBAQfvA== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UE -BhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWdu -IFNpbHZlciBDQSAtIEcyMB4XDTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0Nlow -RzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMY -U3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A -MIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644N0Mv -Fz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7br -YT7QbNHm+/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieF -nbAVlDLaYQ1HTWBCrpJH6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH -6ATK72oxh9TAtvmUcXtnZLi2kUpCe2UuMGoM9ZDulebyzYLs2aFK7PayS+VFheZt -eJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5hqAaEuSh6XzjZG6k4sIN/ -c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5FZGkECwJ -MoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRH -HTBsROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTf -jNFusB3hB48IHpmccelM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb6 -5i/4z3GcRm25xBWNOHkDRUjvxF3XCO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOB -rDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU -F6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRBtjpbO8tFnb0c -wpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0 -cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIB -AHPGgeAn0i0P4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShp -WJHckRE1qTodvBqlYJ7YH39FkWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9 -xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L3XWgwF15kIwb4FDm3jH+mHtwX6WQ -2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx/uNncqCxv1yL5PqZ -IseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFaDGi8 -aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2X -em1ZqSqPe97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQR -dAtq/gsD/KNVV4n+SsuuWxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/ -OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJDIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+ -hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ubDgEj8Z+7fNzcbBGXJbLy -tGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIF2TCCA8GgAwIBAgIQXAuFXAvnWUHfV8w/f52oNjANBgkqhkiG9w0BAQUFADBk -MQswCQYDVQQGEwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0 -YWwgQ2VydGlmaWNhdGUgU2VydmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3Qg -Q0EgMTAeFw0wNTA4MTgxMjA2MjBaFw0yNTA4MTgyMjA2MjBaMGQxCzAJBgNVBAYT -AmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGlnaXRhbCBDZXJ0aWZp -Y2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAxMIICIjAN -BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0LmwqAzZuz8h+BvVM5OAFmUgdbI9 -m2BtRsiMMW8Xw/qabFbtPMWRV8PNq5ZJkCoZSx6jbVfd8StiKHVFXqrWW/oLJdih -FvkcxC7mlSpnzNApbjyFNDhhSbEAn9Y6cV9Nbc5fuankiX9qUvrKm/LcqfmdmUc/ -TilftKaNXXsLmREDA/7n29uj/x2lzZAeAR81sH8A25Bvxn570e56eqeqDFdvpG3F -EzuwpdntMhy0XmeLVNxzh+XTF3xmUHJd1BpYwdnP2IkCb6dJtDZd0KTeByy2dbco -kdaXvij1mB7qWybJvbCXc9qukSbraMH5ORXWZ0sKbU/Lz7DkQnGMU3nn7uHbHaBu -HYwadzVcFh4rUx80i9Fs/PJnB3r1re3WmquhsUvhzDdf/X/NTa64H5xD+SpYVUNF -vJbNcA78yeNmuk6NO4HLFWR7uZToXTNShXEuT46iBhFRyePLoW4xCGQMwtI89Tbo -19AOeCMgkckkKmUpWyL3Ic6DXqTz3kvTaI9GdVyDCW4pa8RwjPWd1yAv/0bSKzjC -L3UcPX7ape8eYIVpQtPM+GP+HkM5haa2Y0EQs3MevNP6yn0WR+Kn1dCjigoIlmJW -bjTb2QK5MHXjBNLnj8KwEUAKrNVxAmKLMb7dxiNYMUJDLXT5xp6mig/p/r+D5kNX -JLrvRjSq1xIBOO0CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0hBBYw -FDASBgdghXQBUwABBgdghXQBUwABMBIGA1UdEwEB/wQIMAYBAf8CAQcwHwYDVR0j -BBgwFoAUAyUv3m+CATpcLNwroWm1Z9SM0/0wHQYDVR0OBBYEFAMlL95vggE6XCzc -K6FptWfUjNP9MA0GCSqGSIb3DQEBBQUAA4ICAQA1EMvspgQNDQ/NwNurqPKIlwzf -ky9NfEBWMXrrpA9gzXrzvsMnjgM+pN0S734edAY8PzHyHHuRMSG08NBsl9Tpl7Ik -Vh5WwzW9iAUPWxAaZOHHgjD5Mq2eUCzneAXQMbFamIp1TpBcahQq4FJHgmDmHtqB -sfsUC1rxn9KVuj7QG9YVHaO+htXbD8BJZLsuUBlL0iT43R4HVtA4oJVwIHaM190e -3p9xxCPvgxNcoyQVTSlAPGrEqdi3pkSlDfTgnXceQHAm/NrZNuR55LU/vJtlvrsR -ls/bxig5OgjOR1tTWsWZ/l2p3e9M1MalrQLmjAcSHm8D0W+go/MpvRLHUKKwf4ip -mXeascClOS5cfGniLLDqN2qk4Vrh9VDlg++luyqI54zb/W1elxmofmZ1a3Hqv7HH -b6D0jqTsNFFbjCYDcKF31QESVwA12yPeDooomf2xEG9L/zgtYE4snOtnta1J7ksf -rK/7DZBaZmBwXarNeNQk7shBoJMBkpxqnvy5JMWzFYJ+vq6VK+uxwNrjAWALXmms -hFZhvnEX/h0TD/7Gh0Xp/jKgGg0TpJRVcaUWi7rKibCyx/yP2FS1k2Kdzs9Z+z0Y -zirLNRWCXf9UIltxUvu3yf5gmwBBZPCqKuy2QkPOiWaByIufOVQDJdMWNY6E0F/6 -MBr1mmz0DlP5OlvRHA== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDQzCCAiugAwIBAgIQX/h7KCtU3I1CoxW1aMmt/zANBgkqhkiG9w0BAQUFADA1 -MRYwFAYDVQQKEw1DaXNjbyBTeXN0ZW1zMRswGQYDVQQDExJDaXNjbyBSb290IENB -IDIwNDgwHhcNMDQwNTE0MjAxNzEyWhcNMjkwNTE0MjAyNTQyWjA1MRYwFAYDVQQK -Ew1DaXNjbyBTeXN0ZW1zMRswGQYDVQQDExJDaXNjbyBSb290IENBIDIwNDgwggEg -MA0GCSqGSIb3DQEBAQUAA4IBDQAwggEIAoIBAQCwmrmrp68Kd6ficba0ZmKUeIhH -xmJVhEAyv8CrLqUccda8bnuoqrpu0hWISEWdovyD0My5jOAmaHBKeN8hF570YQXJ -FcjPFto1YYmUQ6iEqDGYeJu5Tm8sUxJszR2tKyS7McQr/4NEb7Y9JHcJ6r8qqB9q -VvYgDxFUl4F1pyXOWWqCZe+36ufijXWLbvLdT6ZeYpzPEApk0E5tzivMW/VgpSdH -jWn0f84bcN5wGyDWbs2mAag8EtKpP6BrXruOIIt6keO1aO6g58QBdKhTCytKmg9l -Eg6CTY5j/e/rmxrbU6YTYK/CfdfHbBcl1HP7R2RQgYCUTOG/rksc35LtLgXfAgED -o1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUJ/PI -FR5umgIJFq0roIlgX9p7L6owEAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZIhvcNAQEF -BQADggEBAJ2dhISjQal8dwy3U8pORFBi71R803UXHOjgxkhLtv5MOhmBVrBW7hmW -Yqpao2TB9k5UM8Z3/sUcuuVdJcr18JOagxEu5sv4dEX+5wW4q+ffy0vhN4TauYuX -cB7w4ovXsNgOnbFp1iqRe6lJT37mjpXYgyc81WhJDtSd9i7rp77rMKSsH0T8lasz -Bvt9YAretIpjsJyp8qS5UwGH0GikJ3+r/+n6yUA4iGe0OcaEb1fJU9u6ju7AQ7L4 -CYNu/2bPPu8Xs1gYJQk0XuPL1hS27PKSb3TkL4Eq1ZKR4OCXPDJoBYVL0fdX4lId -kxpUnwVwwEpxYB5DC2Ae/qPOgRnhCzU= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFcjCCA1qgAwIBAgIQH51ZWtcvwgZEpYAIaeNe9jANBgkqhkiG9w0BAQUFADA/ -MQswCQYDVQQGEwJUVzEwMC4GA1UECgwnR292ZXJubWVudCBSb290IENlcnRpZmlj -YXRpb24gQXV0aG9yaXR5MB4XDTAyMTIwNTEzMjMzM1oXDTMyMTIwNTEzMjMzM1ow -PzELMAkGA1UEBhMCVFcxMDAuBgNVBAoMJ0dvdmVybm1lbnQgUm9vdCBDZXJ0aWZp -Y2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB -AJoluOzMonWoe/fOW1mKydGGEghU7Jzy50b2iPN86aXfTEc2pBsBHH8eV4qNw8XR -IePaJD9IK/ufLqGU5ywck9G/GwGHU5nOp/UKIXZ3/6m3xnOUT0b3EEk3+qhZSV1q -gQdW8or5BtD3cCJNtLdBuTK4sfCxw5w/cP1T3YGq2GN49thTbqGsaoQkclSGxtKy -yhwOeYHWtXBiCAEuTk8O1RGvqa/lmr/czIdtJuTJV6L7lvnM4T9TjGxMfptTCAts -F/tnyMKtsc2AtJfcdgEWFelq16TheEfOhtX7MfP6Mb40qij7cEwdScevLJ1tZqa2 -jWR+tSBqnTuBto9AAGdLiYa4zGX+FVPpBMHWXx1E1wovJ5pGfaENda1UhhXcSTvx -ls4Pm6Dso3pdvtUqdULle96ltqqvKKyskKw4t9VoNSZ63Pc78/1Fm9G7Q3hub/FC -VGqY8A2tl+lSXunVanLeavcbYBT0peS2cWeqH+riTcFCQP5nRhc4L0c/cZyu5SHK -YS1tB6iEfC3uUSXxY5Ce/eFXiGvviiNtsea9P63RPZYLhY3Naye7twWb7LuRqQoH -EgKXTiCQ8P8NHuJBO9NAOueNXdpm5AKwB1KYXA6OM5zCppX7VRluTI6uSw+9wThN -Xo+EHWbNxWCWtFJaBYmOlXqYwZE8lSOyDvR5tMl8wUohAgMBAAGjajBoMB0GA1Ud -DgQWBBTMzO/MKWCkO7GStjz6MmKPrCUVOzAMBgNVHRMEBTADAQH/MDkGBGcqBwAE -MTAvMC0CAQAwCQYFKw4DAhoFADAHBgVnKgMAAAQUA5vwIhP/lSg209yewDL7MTqK -UWUwDQYJKoZIhvcNAQEFBQADggIBAECASvomyc5eMN1PhnR2WPWus4MzeKR6dBcZ -TulStbngCnRiqmjKeKBMmo4sIy7VahIkv9Ro04rQ2JyftB8M3jh+Vzj8jeJPXgyf -qzvS/3WXy6TjZwj/5cAWtUgBfen5Cv8b5Wppv3ghqMKnI6mGq3ZW6A4M9hPdKmaK -ZEk9GhiHkASfQlK3T8v+R0F2Ne//AHY2RTKbxkaFXeIksB7jSJaYV0eUVXoPQbFE -JPPB/hprv4j9wabak2BegUqZIJxIZhm1AHlUD7gsL0u8qV1bYH+Mh6XgUmMqvtg7 -hUAV/h62ZT/FS9p+tXo1KaMuephgIqP0fSdOLeq0dDzpD6QzDxARvBMB1uUO07+1 -EqLhRSPAzAhuYbeJq4PjJB7mXQfnHyA+z2fI56wwbSdLaG5LKlwCCDTb+HbkZ6Mm -nD+iMsJKxYEYMRBWqoTvLQr/uB930r+lWKBi5NdLkXWNiYCYfm3LU05er/ayl4WX -udpVBrkk7tfGOB5jGxI7leFYrPLfhNVfmS8NVVvmONsuP3LpSIXLuykTjx44Vbnz -ssQwmSNOXfJIoRIM3BKQCZBUkQM8R+XVyWXgt0t97EfTsws+rZ7QdAAO671RrcDe -LMDDav7v3Aun+kbfYNucpllQdSNpc5Oy+fwC00fmcc4QAu4njIT/rEUNE1yDMuAl -pYYsfPQS ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC -VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0 -Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW -KGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENl -cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0MloXDTI2MTEyNzIw -NTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMTkw -NwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSBy -ZWZlcmVuY2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNV -BAMTJEVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJ -KoZIhvcNAQEBBQADggEPADCCAQoCggEBALaVtkNC+sZtKm9I35RMOVcF7sN5EUFo -Nu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYszA9u3g3s+IIRe7bJWKKf4 -4LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOwwCj0Yzfv9 -KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGI -rb68j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi -94DkZfs0Nw4pgHBNrziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOB -sDCBrTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAi -gA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1MzQyWjAfBgNVHSMEGDAWgBRo -kORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DHhmak8fdLQ/uE -vW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA -A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9t -O1KzKtvn1ISMY/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6Zua -AGAT/3B+XxFNSRuzFVJ7yVTav52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP -9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTSW3iDVuycNsMm4hH2Z0kdkquM++v/ -eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m -0vdXcDazv/wor3ElhVsT/h5/WrQ8 ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBY -MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMo -R2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEx -MjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgxCzAJBgNVBAYTAlVTMRYwFAYDVQQK -Ew1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQcmltYXJ5IENlcnRp -ZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC -AQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9 -AWbK7hWNb6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjA -ZIVcFU2Ix7e64HXprQU9nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE0 -7e9GceBrAqg1cmuXm2bgyxx5X9gaBGgeRwLmnWDiNpcB3841kt++Z8dtd1k7j53W -kBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGttm/81w7a4DSwDRp35+MI -mO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G -A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJ -KoZIhvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ1 -6CePbJC/kRYkRj5KTs4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl -4b7UVXGYNTq+k+qurUKykG/g/CFNNWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6K -oKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHaFloxt/m0cYASSJlyc1pZU8Fj -UjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG1riR/aYNKxoU -AT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJC -TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0 -aWZpY2F0aW9uIEF1dGhvcml0eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0 -aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAzMTkxODMzMzNaFw0yMTAzMTcxODMz -MzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUw -IwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQDEyVR -dW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG -9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Yp -li4kVEAkOPcahdxYTMukJ0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2D -rOpm2RgbaIr1VxqYuvXtdj182d6UajtLF8HVj71lODqV0D1VNk7feVcxKh7YWWVJ -WCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeLYzcS19Dsw3sgQUSj7cug -F+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWenAScOospU -xbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCC -Ak4wPQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVv -dmFkaXNvZmZzaG9yZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREw -ggENMIIBCQYJKwYBBAG+WAABMIH7MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNl -IG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBh -c3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFy -ZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh -Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYI -KwYBBQUHAgEWFmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3T -KbkGGew5Oanwl4Rqy+/fMIGuBgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rq -y+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1p -dGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYD -VQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6tlCL -MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSk -fnIYj9lofFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf8 -7C9TqnN7Az10buYWnuulLsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1R -cHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2xgI4JVrmcGmD+XcHXetwReNDWXcG31a0y -mQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi5upZIof4l/UO/erMkqQW -xFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi5nrQNiOK -SnQ2+Q== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEVzCCAz+gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBnTELMAkGA1UEBhMCRVMx -IjAgBgNVBAcTGUMvIE11bnRhbmVyIDI0NCBCYXJjZWxvbmExQjBABgNVBAMTOUF1 -dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2 -MjYzNDA2ODEmMCQGCSqGSIb3DQEJARYXY2FAZmlybWFwcm9mZXNpb25hbC5jb20w -HhcNMDExMDI0MjIwMDAwWhcNMTMxMDI0MjIwMDAwWjCBnTELMAkGA1UEBhMCRVMx -IjAgBgNVBAcTGUMvIE11bnRhbmVyIDI0NCBCYXJjZWxvbmExQjBABgNVBAMTOUF1 -dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2 -MjYzNDA2ODEmMCQGCSqGSIb3DQEJARYXY2FAZmlybWFwcm9mZXNpb25hbC5jb20w -ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDnIwNvbyOlXnjOlSztlB5u -Cp4Bx+ow0Syd3Tfom5h5VtP8c9/Qit5Vj1H5WuretXDE7aTt/6MNbg9kUDGvASdY -rv5sp0ovFy3Tc9UTHI9ZpTQsHVQERc1ouKDAA6XPhUJHlShbz++AbOCQl4oBPB3z -hxAwJkh91/zpnZFx/0GaqUC1N5wpIE8fUuOgfRNtVLcK3ulqTgesrBlf3H5idPay -BQC6haD9HThuy1q7hryUZzM1gywfI834yJFxzJeL764P3CkDG8A563DtwW4O2GcL -iam8NeTvtjS0pbbELaW+0MOUJEjb35bTALVmGotmBQ/dPz/LP6pemkr4tErvlTcb -AgMBAAGjgZ8wgZwwKgYDVR0RBCMwIYYfaHR0cDovL3d3dy5maXJtYXByb2Zlc2lv -bmFsLmNvbTASBgNVHRMBAf8ECDAGAQH/AgEBMCsGA1UdEAQkMCKADzIwMDExMDI0 -MjIwMDAwWoEPMjAxMzEwMjQyMjAwMDBaMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4E -FgQUMwugZtHq2s7eYpMEKFK1FH84aLcwDQYJKoZIhvcNAQEFBQADggEBAEdz/o0n -VPD11HecJ3lXV7cVVuzH2Fi3AQL0M+2TUIiefEaxvT8Ub/GzR0iLjJcG1+p+o1wq -u00vR+L4OQbJnC4xGgN49Lw4xiKLMzHwFgQEffl25EvXwOaD7FnMP97/T2u3Z36m -hoEyIwOdyPdfwUpgpZKpsaSgYMN4h7Mi8yrrW6ntBas3D7Hi05V2Y1Z0jFhyGzfl -ZKG+TQyTmAyX9odtsz/ny4Cm7YjHX1BiAuiZdBbQ5rQ58SfLyEDW44YQqSMSkuBp -QWOnryULwMWSyx6Yo1q6xTMPoJcB3X/ge9YGVM+h4k0460tQtcsm9MracEpqoeJ5 -quGnM/b9Sh/22WA= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEQzCCAyugAwIBAgIBATANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJHQjEb -MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow -GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDElMCMGA1UEAwwcVHJ1c3RlZCBDZXJ0 -aWZpY2F0ZSBTZXJ2aWNlczAeFw0wNDAxMDEwMDAwMDBaFw0yODEyMzEyMzU5NTla -MH8xCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO -BgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoMEUNvbW9kbyBDQSBMaW1pdGVkMSUwIwYD -VQQDDBxUcnVzdGVkIENlcnRpZmljYXRlIFNlcnZpY2VzMIIBIjANBgkqhkiG9w0B -AQEFAAOCAQ8AMIIBCgKCAQEA33FvNlhTWvI2VFeAxHQIIO0Yfyod5jWaHiWsnOWW -fnJSoBVC21ndZHoa0Lh73TkVvFVIxO06AOoxEbrycXQaZ7jPM8yoMa+j49d/vzMt -TGo87IvDktJTdyR0nAducPy9C1t2ul/y/9c3S0pgePfw+spwtOpZqqPOSC+pw7IL -fhdyFgymBwwbOM/JYrc/oJOlh0Hyt3BAd9i+FHzjqMB6juljatEPmsbS9Is6FARW -1O24zG71++IsWL1/T2sr92AkWCTOJu80kTrV44HQsvAEAtdbtz6SrGsSivnkBbA7 -kUlcsutT6vifR4buv5XAwAaf0lteERv0xwQ1KdJVXOTt6wIDAQABo4HJMIHGMB0G -A1UdDgQWBBTFe1i97doladL3WRaoszLAeydb9DAOBgNVHQ8BAf8EBAMCAQYwDwYD -VR0TAQH/BAUwAwEB/zCBgwYDVR0fBHwwejA8oDqgOIY2aHR0cDovL2NybC5jb21v -ZG9jYS5jb20vVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMuY3JsMDqgOKA2hjRo -dHRwOi8vY3JsLmNvbW9kby5uZXQvVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMu -Y3JsMA0GCSqGSIb3DQEBBQUAA4IBAQDIk4E7ibSvuIQSTI3S8NtwuleGFTQQuS9/ -HrCoiWChisJ3DFBKmwCL2Iv0QeLQg4pKHBQGsKNoBXAxMKdTmw7pSqBYaWcOrp32 -pSxBvzwGa+RZzG0Q8ZZvH9/0BAKkn0U+yNj6NkZEUD+Cl5EfKNsYEYwq5GWDVxIS -jBc/lDb+XbDABHcTuPQV1T84zJQ6VdCsmPW6AF/ghhmBeC8owH7TzEIK9a5QoNE+ -xqFx7D+gIIxmOom0jtTYsU0lR+4viMi14QVFwL4Ucd56/Y57fU0IlqUSc/Atyjcn -dBInTMu2l+nZrghtWjlA3QVHdWpaIbOjGM9O9y5Xt5hwXsjEeLBi ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEGjCCAwICEQCLW3VWhFSFCwDPrzhIzrGkMA0GCSqGSIb3DQEBBQUAMIHKMQsw -CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl -cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu -LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT -aWduIENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp -dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD -VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT -aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ -bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu -IENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg -LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN2E1Lm0+afY8wR4 -nN493GwTFtl63SRRZsDHJlkNrAYIwpTRMx/wgzUfbhvI3qpuFU5UJ+/EbRrsC+MO -8ESlV8dAWB6jRx9x7GD2bZTIGDnt/kIYVt/kTEkQeE4BdjVjEjbdZrwBBDajVWjV -ojYJrKshJlQGrT/KFOCsyq0GHZXi+J3x4GD/wn91K0zM2v6HmSHquv4+VNfSWXjb -PG7PoBMAGrgnoeS+Z5bKoMWznN3JdZ7rMJpfo83ZrngZPyPpXNspva1VyBtUjGP2 -6KbqxzcSXKMpHgLZ2x87tNcPVkeBFQRKr4Mn0cVYiMHd9qqnoxjaaKptEVHhv2Vr -n5Z20T0CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAq2aN17O6x5q25lXQBfGfMY1a -qtmqRiYPce2lrVNWYgFHKkTp/j90CxObufRNG7LRX7K20ohcs5/Ny9Sn2WCVhDr4 -wTcdYcrnsMXlkdpUpqwxga6X3s0IrLjAl4B/bnKk52kTlWUfxJM8/XmPBNQ+T+r3 -ns7NZ3xPZQL/kYVUc8f/NveGLezQXk//EZ9yBta4GvFMDSZl4kSAHsef493oCtrs -pSCAaWihT37ha88HQfqDjrw43bAuEbFrskLMmrz5SCJ5ShkPshw+IHTZasO+8ih4 -E1Z5T21Q6huwtVexN2ZYI/PcD98Kh8TvhgXVOBRgmaNL3gaWcSzy27YfpO8/7g== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEqjCCA5KgAwIBAgIOLmoAAQACH9dSISwRXDswDQYJKoZIhvcNAQEFBQAwdjEL -MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNV -BAsTGVRDIFRydXN0Q2VudGVyIENsYXNzIDIgQ0ExJTAjBgNVBAMTHFRDIFRydXN0 -Q2VudGVyIENsYXNzIDIgQ0EgSUkwHhcNMDYwMTEyMTQzODQzWhcNMjUxMjMxMjI1 -OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIgR21i -SDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQTElMCMGA1UEAxMc -VEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQAD -ggEPADCCAQoCggEBAKuAh5uO8MN8h9foJIIRszzdQ2Lu+MNF2ujhoF/RKrLqk2jf -tMjWQ+nEdVl//OEd+DFwIxuInie5e/060smp6RQvkL4DUsFJzfb95AhmC1eKokKg -uNV/aVyQMrKXDcpK3EY+AlWJU+MaWss2xgdW94zPEfRMuzBwBJWl9jmM/XOBCH2J -XjIeIqkiRUuwZi4wzJ9l/fzLganx4Duvo4bRierERXlQXa7pIXSSTYtZgo+U4+lK -8edJsBTj9WLL1XK9H7nSn6DNqPoByNkN39r8R52zyFTfSUrxIan+GE7uSNQZu+99 -5OKdy1u2bv/jzVrndIIFuoAlOMvkaZ6vQaoahPUCAwEAAaOCATQwggEwMA8GA1Ud -EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTjq1RMgKHbVkO3 -kUrL84J6E1wIqzCB7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRy -dXN0Y2VudGVyLmRlL2NybC92Mi90Y19jbGFzc18yX2NhX0lJLmNybIaBn2xkYXA6 -Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBUcnVzdENlbnRlciUyMENsYXNz -JTIwMiUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21iSCxPVT1yb290 -Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u -TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEAjNfffu4bgBCzg/XbEeprS6iS -GNn3Bzn1LL4GdXpoUxUc6krtXvwjshOg0wn/9vYua0Fxec3ibf2uWWuFHbhOIprt -ZjluS5TmVfwLG4t3wVMTZonZKNaL80VKY7f9ewthXbhtvsPcW3nS7Yblok2+XnR8 -au0WOB9/WIFaGusyiC2y8zl3gK9etmF1KdsjTYjKUCjLhdLTEKJZbtOTVAB6okaV -hgWcqRmY5TFyDADiZ9lA4CQze28suVyrZZ0srHbqNZn1l7kPJOzHdiEoZa5X6AeI -dUpWoNIFOqTmjZKILPPy4cHGYdtBxceb9w4aUUXCYWvcZCcXjFq32nQozZfkvQ== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCB -qTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf -Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw -MDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNV -BAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3MDAwMDAwWhcNMzYw -NzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5j -LjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYG -A1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl -IG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqG -SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsoPD7gFnUnMekz52hWXMJEEUMDSxuaPFs -W0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ1CRfBsDMRJSUjQJib+ta -3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGcq/gcfomk -6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6 -Sk/KaAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94J -NqR32HuHUETVPm4pafs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBA -MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XP -r87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUFAAOCAQEAeRHAS7ORtvzw6WfU -DW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeEuzLlQRHAd9mz -YJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX -xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2 -/qxAeeWsEG89jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/ -LHbTY5xZ3Y+m4Q6gLkH3LpVHz7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7 -jVaMaA== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEP -MA0GA1UEChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAx -MDQwNjA3Mjk0MFoXDTIxMDQwNjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNV -BAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJhIENsYXNzMiBDQTCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3/Ei9vX+ALTU74W+o -Z6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybTdXnt -5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s -3TmVToMGf+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2Ej -vOr7nQKV0ba5cTppCD8PtOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu -8nYybieDwnPz3BjotJPqdURrBGAgcVeHnfO+oJAjPYok4doh28MCAwEAAaMzMDEw -DwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITTXjwwCwYDVR0PBAQDAgEG -MA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt0jSv9zil -zqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/ -3DEIcbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvD -FNr450kkkdAdavphOe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6 -Tk6ezAyNlNzZRZxe7EJQY670XcSxEtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2 -ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLHllpwrN9M ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJTRTEU -MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3 -b3JrMSAwHgYDVQQDExdBZGRUcnVzdCBQdWJsaWMgQ0EgUm9vdDAeFw0wMDA1MzAx -MDQxNTBaFw0yMDA1MzAxMDQxNTBaMGQxCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtB -ZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5ldHdvcmsxIDAeBgNV -BAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOC -AQ8AMIIBCgKCAQEA6Rowj4OIFMEg2Dybjxt+A3S72mnTRqX4jsIMEZBRpS9mVEBV -6tsfSlbunyNu9DnLoblv8n75XYcmYZ4c+OLspoH4IcUkzBEMP9smcnrHAZcHF/nX -GCwwfQ56HmIexkvA/X1id9NEHif2P0tEs7c42TkfYNVRknMDtABp4/MUTu7R3AnP -dzRGULD4EfL+OHn3Bzn+UZKXC1sIXzSGAa2Il+tmzV7R/9x98oTaunet3IAIx6eH -1lWfl2royBFkuucZKT8Rs3iQhCBSWxHveNCD9tVIkNAwHM+A+WD+eeSI8t0A65RF -62WUaUC6wNW0uLp9BBGo6zEFlpROWCGOn9Bg/QIDAQABo4HRMIHOMB0GA1UdDgQW -BBSBPjfYkrAfd59ctKtzquf2NGAv+jALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUw -AwEB/zCBjgYDVR0jBIGGMIGDgBSBPjfYkrAfd59ctKtzquf2NGAv+qFopGYwZDEL -MAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRU -cnVzdCBUVFAgTmV0d29yazEgMB4GA1UEAxMXQWRkVHJ1c3QgUHVibGljIENBIFJv -b3SCAQEwDQYJKoZIhvcNAQEFBQADggEBAAP3FUr4JNojVhaTdt02KLmuG7jD8WS6 -IBh4lSknVwW8fCr0uVFV2ocC3g8WFzH4qnkuCRO7r7IgGRLlk/lL+YPoRNWyQSW/ -iHVv/xD8SlTQX/D67zZzfRs2RcYhbbQVuE7PnFylPVoAjgbjPGsye/Kf8Lb93/Ao -GEjwxrzQvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bYGozH7ZxOmuASu7VqTITh -4SINhwBk/ox9Yjllpu9CtoAlEmEBqCQTcAARJl/6NVDFSMwGR+gn2HCNX2TmoUQm -XiLsks3/QppEIW1cxeMiHV9HEufOX1362KqxMy3ZdvJOOjMMK7MtkAY= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIH6jCCB1OgAwIBAgIBADANBgkqhkiG9w0BAQUFADCCARIxCzAJBgNVBAYTAkVT -MRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UE -ChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5sLjErMCkGA1UE -ChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1MjEuMCwGA1UECxMl -SVBTIENBIENMQVNFMyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEuMCwGA1UEAxMl -SVBTIENBIENMQVNFMyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEeMBwGCSqGSIb3 -DQEJARYPaXBzQG1haWwuaXBzLmVzMB4XDTAxMTIyOTAxMDE0NFoXDTI1MTIyNzAx -MDE0NFowggESMQswCQYDVQQGEwJFUzESMBAGA1UECBMJQmFyY2Vsb25hMRIwEAYD -VQQHEwlCYXJjZWxvbmExLjAsBgNVBAoTJUlQUyBJbnRlcm5ldCBwdWJsaXNoaW5n -IFNlcnZpY2VzIHMubC4xKzApBgNVBAoUImlwc0BtYWlsLmlwcy5lcyBDLkkuRi4g -IEItNjA5Mjk0NTIxLjAsBgNVBAsTJUlQUyBDQSBDTEFTRTMgQ2VydGlmaWNhdGlv -biBBdXRob3JpdHkxLjAsBgNVBAMTJUlQUyBDQSBDTEFTRTMgQ2VydGlmaWNhdGlv -biBBdXRob3JpdHkxHjAcBgkqhkiG9w0BCQEWD2lwc0BtYWlsLmlwcy5lczCBnzAN -BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAqxf+DrDGaBtT8FK+n/ra+osTBLsBjzLZ -H49NzjaY2uQARIwo2BNEKqRrThckQpzTiKRBgtYj+4vJhuW5qYIF3PHeH+AMmVWY -8jjsbJ0gA8DvqqPGZARRLXgNo9KoOtYkTOmWehisEyMiG3zoMRGzXwmqMHBxRiVr -SXGAK5UBsh8CAwEAAaOCBEowggRGMB0GA1UdDgQWBBS4k/8uy9wsjqLnev42USGj -mFsMNDCCAUQGA1UdIwSCATswggE3gBS4k/8uy9wsjqLnev42USGjmFsMNKGCARqk -ggEWMIIBEjELMAkGA1UEBhMCRVMxEjAQBgNVBAgTCUJhcmNlbG9uYTESMBAGA1UE -BxMJQmFyY2Vsb25hMS4wLAYDVQQKEyVJUFMgSW50ZXJuZXQgcHVibGlzaGluZyBT -ZXJ2aWNlcyBzLmwuMSswKQYDVQQKFCJpcHNAbWFpbC5pcHMuZXMgQy5JLkYuICBC -LTYwOTI5NDUyMS4wLAYDVQQLEyVJUFMgQ0EgQ0xBU0UzIENlcnRpZmljYXRpb24g -QXV0aG9yaXR5MS4wLAYDVQQDEyVJUFMgQ0EgQ0xBU0UzIENlcnRpZmljYXRpb24g -QXV0aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXOCAQAwDAYD -VR0TBAUwAwEB/zAMBgNVHQ8EBQMDB/+AMGsGA1UdJQRkMGIGCCsGAQUFBwMBBggr -BgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYKKwYBBAGCNwIB -FQYKKwYBBAGCNwIBFgYKKwYBBAGCNwoDAQYKKwYBBAGCNwoDBDARBglghkgBhvhC -AQEEBAMCAAcwGgYDVR0RBBMwEYEPaXBzQG1haWwuaXBzLmVzMBoGA1UdEgQTMBGB -D2lwc0BtYWlsLmlwcy5lczBBBglghkgBhvhCAQ0ENBYyQ0xBU0UzIENBIENlcnRp -ZmljYXRlIGlzc3VlZCBieSBodHRwOi8vd3d3Lmlwcy5lcy8wKQYJYIZIAYb4QgEC -BBwWGmh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvMDoGCWCGSAGG+EIBBAQtFito -dHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL2lwczIwMDJDTEFTRTMuY3JsMD8GCWCG -SAGG+EIBAwQyFjBodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL3Jldm9jYXRpb25D -TEFTRTMuaHRtbD8wPAYJYIZIAYb4QgEHBC8WLWh0dHA6Ly93d3cuaXBzLmVzL2lw -czIwMDIvcmVuZXdhbENMQVNFMy5odG1sPzA6BglghkgBhvhCAQgELRYraHR0cDov -L3d3dy5pcHMuZXMvaXBzMjAwMi9wb2xpY3lDTEFTRTMuaHRtbDBzBgNVHR8EbDBq -MDGgL6AthitodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL2lwczIwMDJDTEFTRTMu -Y3JsMDWgM6Axhi9odHRwOi8vd3d3YmFjay5pcHMuZXMvaXBzMjAwMi9pcHMyMDAy -Q0xBU0UzLmNybDAvBggrBgEFBQcBAQQjMCEwHwYIKwYBBQUHMAGGE2h0dHA6Ly9v -Y3NwLmlwcy5lcy8wDQYJKoZIhvcNAQEFBQADgYEAF2VcmZVDAyevJuXr0LMXI/dD -qsfwfewPxqmurpYPdikc4gYtfibFPPqhwYHOU7BC0ZdXGhd+pFFhxu7pXu8Fuuu9 -D6eSb9ijBmgpjnn1/7/5p6/ksc7C0YBCJwUENPjDfxZ4IwwHJPJGR607VNCv1TGy -r33I6unUVtkOE7LFRVA= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzES -MBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFU -V0NBIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMz -WhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJVEFJV0FO -LUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlm -aWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB -AQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFE -AcK0HMMxQhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HH -K3XLfJ+utdGdIzdjp9xCoi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeX -RfwZVzsrb+RH9JlF/h3x+JejiB03HFyP4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/z -rX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1ry+UPizgN7gr8/g+YnzAx -3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV -HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkq -hkiG9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeC -MErJk/9q56YAf4lCmtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdls -XebQ79NqZp4VKIV66IIArB6nCWlWQtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62D -lhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVYT0bf+215WfKEIlKuD8z7fDvn -aspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocnyYh0igzyXxfkZ -YiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDODCCAqGgAwIBAgIQQAWyU6AaRkNQCYGPEhB27DANBgkqhkiG9w0BAQUFADCB -zzELMAkGA1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJ -Q2FwZSBUb3duMRowGAYDVQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMf -Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEjMCEGA1UEAxMaVGhhd3Rl -IFBlcnNvbmFsIFByZW1pdW0gQ0ExKjAoBgkqhkiG9w0BCQEWG3BlcnNvbmFsLXBy -ZW1pdW1AdGhhd3RlLmNvbTAeFw05NjAxMDEwMDAwMDBaFw0yMTAxMDEyMzU5NTla -MIHPMQswCQYDVQQGEwJaQTEVMBMGA1UECBMMV2VzdGVybiBDYXBlMRIwEAYDVQQH -EwlDYXBlIFRvd24xGjAYBgNVBAoTEVRoYXd0ZSBDb25zdWx0aW5nMSgwJgYDVQQL -Ex9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9uMSMwIQYDVQQDExpUaGF3 -dGUgUGVyc29uYWwgUHJlbWl1bSBDQTEqMCgGCSqGSIb3DQEJARYbcGVyc29uYWwt -cHJlbWl1bUB0aGF3dGUuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJ -Ztn4B0TPuYwu8KHvE0VsBd/eJxZRNkERbGw77f4QfRKe5ZtCmv5gMcNmt3M6SK5O -0DI3lIi1DbbZ8/JE2dWIEt12TfIa/G8jHnrx2JhFTgcQ7xZC0EN1bUre4qrJMf8f -AHB8Zs8QJQi6+u4A6UYDZicRFTuqW/KY3TZCstqIdQIDAQABoxMwETAPBgNVHRMB -Af8EBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBALpkCujztDHJJ2+idqAtNnHHhsAI -wk7t2pokGYf8WiOcck0I361cwzskgR1Xj7YSpSID7xK90S1elo8mJk9LG3w7oFIa -pag3hsRHKsrdQfho9cITQSma8AyozaH8FSMC23or1GJRQkfEox/00sVNVBDr2vDM -p083DL08yxDjGugV ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIH6jCCB1OgAwIBAgIBADANBgkqhkiG9w0BAQUFADCCARIxCzAJBgNVBAYTAkVT -MRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UE -ChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5sLjErMCkGA1UE -ChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1MjEuMCwGA1UECxMl -SVBTIENBIENMQVNFMSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEuMCwGA1UEAxMl -SVBTIENBIENMQVNFMSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEeMBwGCSqGSIb3 -DQEJARYPaXBzQG1haWwuaXBzLmVzMB4XDTAxMTIyOTAwNTkzOFoXDTI1MTIyNzAw -NTkzOFowggESMQswCQYDVQQGEwJFUzESMBAGA1UECBMJQmFyY2Vsb25hMRIwEAYD -VQQHEwlCYXJjZWxvbmExLjAsBgNVBAoTJUlQUyBJbnRlcm5ldCBwdWJsaXNoaW5n -IFNlcnZpY2VzIHMubC4xKzApBgNVBAoUImlwc0BtYWlsLmlwcy5lcyBDLkkuRi4g -IEItNjA5Mjk0NTIxLjAsBgNVBAsTJUlQUyBDQSBDTEFTRTEgQ2VydGlmaWNhdGlv -biBBdXRob3JpdHkxLjAsBgNVBAMTJUlQUyBDQSBDTEFTRTEgQ2VydGlmaWNhdGlv -biBBdXRob3JpdHkxHjAcBgkqhkiG9w0BCQEWD2lwc0BtYWlsLmlwcy5lczCBnzAN -BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4FEnpwvdr9G5Q1uCN0VWcu+atsIS7ywS -zHb5BlmvXSHU0lq4oNTzav3KaY1mSPd05u42veiWkXWmcSjK5yISMmmwPh5r9FBS -YmL9Yzt9fuzuOOpi9GyocY3h6YvJP8a1zZRCb92CRTzo3wno7wpVqVZHYUxJZHMQ -KD/Kvwn/xi8CAwEAAaOCBEowggRGMB0GA1UdDgQWBBTrsxl588GlHKzcuh9morKb -adB4CDCCAUQGA1UdIwSCATswggE3gBTrsxl588GlHKzcuh9morKbadB4CKGCARqk -ggEWMIIBEjELMAkGA1UEBhMCRVMxEjAQBgNVBAgTCUJhcmNlbG9uYTESMBAGA1UE -BxMJQmFyY2Vsb25hMS4wLAYDVQQKEyVJUFMgSW50ZXJuZXQgcHVibGlzaGluZyBT -ZXJ2aWNlcyBzLmwuMSswKQYDVQQKFCJpcHNAbWFpbC5pcHMuZXMgQy5JLkYuICBC -LTYwOTI5NDUyMS4wLAYDVQQLEyVJUFMgQ0EgQ0xBU0UxIENlcnRpZmljYXRpb24g -QXV0aG9yaXR5MS4wLAYDVQQDEyVJUFMgQ0EgQ0xBU0UxIENlcnRpZmljYXRpb24g -QXV0aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXOCAQAwDAYD -VR0TBAUwAwEB/zAMBgNVHQ8EBQMDB/+AMGsGA1UdJQRkMGIGCCsGAQUFBwMBBggr -BgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYKKwYBBAGCNwIB -FQYKKwYBBAGCNwIBFgYKKwYBBAGCNwoDAQYKKwYBBAGCNwoDBDARBglghkgBhvhC -AQEEBAMCAAcwGgYDVR0RBBMwEYEPaXBzQG1haWwuaXBzLmVzMBoGA1UdEgQTMBGB -D2lwc0BtYWlsLmlwcy5lczBBBglghkgBhvhCAQ0ENBYyQ0xBU0UxIENBIENlcnRp -ZmljYXRlIGlzc3VlZCBieSBodHRwOi8vd3d3Lmlwcy5lcy8wKQYJYIZIAYb4QgEC -BBwWGmh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvMDoGCWCGSAGG+EIBBAQtFito -dHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL2lwczIwMDJDTEFTRTEuY3JsMD8GCWCG -SAGG+EIBAwQyFjBodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL3Jldm9jYXRpb25D -TEFTRTEuaHRtbD8wPAYJYIZIAYb4QgEHBC8WLWh0dHA6Ly93d3cuaXBzLmVzL2lw -czIwMDIvcmVuZXdhbENMQVNFMS5odG1sPzA6BglghkgBhvhCAQgELRYraHR0cDov -L3d3dy5pcHMuZXMvaXBzMjAwMi9wb2xpY3lDTEFTRTEuaHRtbDBzBgNVHR8EbDBq -MDGgL6AthitodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL2lwczIwMDJDTEFTRTEu -Y3JsMDWgM6Axhi9odHRwOi8vd3d3YmFjay5pcHMuZXMvaXBzMjAwMi9pcHMyMDAy -Q0xBU0UxLmNybDAvBggrBgEFBQcBAQQjMCEwHwYIKwYBBQUHMAGGE2h0dHA6Ly9v -Y3NwLmlwcy5lcy8wDQYJKoZIhvcNAQEFBQADgYEAK9Dr/drIyllq2tPMMi7JVBuK -Yn4VLenZMdMu9Ccj/1urxUq2ckCuU3T0vAW0xtnIyXf7t/k0f3gA+Nak5FI/LEpj -V4F1Wo7ojPsCwJTGKbqz3Bzosq/SLmJbGqmODszFV0VRFOlOHIilkfSj945RyKm+ -hjM+5i9Ibq9UkE6tsSU= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQsw -CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl -cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu -LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT -aWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp -dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD -VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT -aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ -bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu -IENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg -LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMu6nFL8eB8aHm8b -N3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1EUGO+i2t -KmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGu -kxUccLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBm -CC+Vk7+qRy+oRpfwEuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJ -Xwzw3sJ2zq/3avL6QaaiMxTJ5Xpj055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWu -imi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAERSWwauSCPc/L8my/uRan2Te -2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5fj267Cz3qWhMe -DGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC -/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565p -F4ErWjfJXir0xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGt -TxzhT5yvDwyd93gN2PQ1VoDat20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFVTCCBD2gAwIBAgIEO/OB0DANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQGEwJj -aDEOMAwGA1UEChMFYWRtaW4xETAPBgNVBAsTCFNlcnZpY2VzMSIwIAYDVQQLExlD -ZXJ0aWZpY2F0aW9uIEF1dGhvcml0aWVzMRYwFAYDVQQDEw1BZG1pbi1Sb290LUNB -MB4XDTAxMTExNTA4NTEwN1oXDTIxMTExMDA3NTEwN1owbDELMAkGA1UEBhMCY2gx -DjAMBgNVBAoTBWFkbWluMREwDwYDVQQLEwhTZXJ2aWNlczEiMCAGA1UECxMZQ2Vy -dGlmaWNhdGlvbiBBdXRob3JpdGllczEWMBQGA1UEAxMNQWRtaW4tUm9vdC1DQTCC -ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMvgr0QUIv5qF0nyXZ3PXAJi -C4C5Wr+oVTN7oxIkXkxvO0GJToM9n7OVJjSmzBL0zJ2HXj0MDRcvhSY+KiZZc6Go -vDvr5Ua481l7ILFeQAFtumeza+vvxeL5Nd0Maga2miiacLNAKXbAcUYRa0Ov5VZB -++YcOYNNt/aisWbJqA2y8He+NsEgJzK5zNdayvYXQTZN+7tVgWOck16Da3+4FXdy -fH1NCWtZlebtMKtERtkVAaVbiWW24CjZKAiVfggjsiLo3yVMPGj3budLx5D9hEEm -vlyDOtcjebca+AcZglppWMX/iHIrx7740y0zd6cWEqiLIcZCrnpkr/KzwO135GkC -AwEAAaOCAf0wggH5MA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIASBkTCBjjCBiwYI -YIV0AREDAQAwfzArBggrBgEFBQcCAjAfGh1UaGlzIGlzIHRoZSBBZG1pbi1Sb290 -LUNBIENQUzBQBggrBgEFBQcCARZEaHR0cDovL3d3dy5pbmZvcm1hdGlrLmFkbWlu -LmNoL1BLSS9saW5rcy9DUFNfMl8xNl83NTZfMV8xN18zXzFfMC5wZGYwfwYDVR0f -BHgwdjB0oHKgcKRuMGwxFjAUBgNVBAMTDUFkbWluLVJvb3QtQ0ExIjAgBgNVBAsT -GUNlcnRpZmljYXRpb24gQXV0aG9yaXRpZXMxETAPBgNVBAsTCFNlcnZpY2VzMQ4w -DAYDVQQKEwVhZG1pbjELMAkGA1UEBhMCY2gwHQYDVR0OBBYEFIKf+iNzIPGXi7JM -Tb5CxX9mzWToMIGZBgNVHSMEgZEwgY6AFIKf+iNzIPGXi7JMTb5CxX9mzWTooXCk -bjBsMQswCQYDVQQGEwJjaDEOMAwGA1UEChMFYWRtaW4xETAPBgNVBAsTCFNlcnZp -Y2VzMSIwIAYDVQQLExlDZXJ0aWZpY2F0aW9uIEF1dGhvcml0aWVzMRYwFAYDVQQD -Ew1BZG1pbi1Sb290LUNBggQ784HQMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0B -AQUFAAOCAQEAeE96XCYRpy6umkPKXDWCRn7INo96ZrWpMggcDORuofHIwdTkgOeM -vWOxDN/yuT7CC3FAaUajbPRbDw0hRMcqKz0aC8CgwcyIyhw/rFK29mfNTG3EviP9 -QSsEbnelFnjpm1wjz4EaBiFjatwpUbI6+Zv3XbEt9QQXBn+c6DeFLe4xvC4B+MTr -a440xTk59pSYux8OHhEvqIwHCkiijGqZhTS3KmGFeBopaR+dJVBRBMoXwzk4B3Hn -0Zib1dEYFZa84vPJZyvxCbLOnPRDJgH6V2uQqbG+6DXVaf/wORVOvF/wzzv0viM/ -RWbEtJZdvo8N3sdtCULzifnxP/V0T9+4ZQ== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDOzCCAiOgAwIBAgIRANAeRlAAACmMAAAAAgAAAAIwDQYJKoZIhvcNAQEFBQAw -PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD -Ew5EU1QgUm9vdCBDQSBYNDAeFw0wMDA5MTMwNjIyNTBaFw0yMDA5MTMwNjIyNTBa -MD8xJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjEXMBUGA1UE -AxMORFNUIFJvb3QgQ0EgWDQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB -AQCthX3OFEYY8gSeIYur0O4ypOT68HnDrjLfIutL5PZHRwQGjzCPb9PFo/ihboJ8 -RvfGhBAqpQCo47zwYEhpWm1jB+L/OE/dBBiyn98krfU2NiBKSom2J58RBeAwHGEy -cO+lewyjVvbDDLUy4CheY059vfMjPAftCRXjqSZIolQb9FdPcAoa90mFwB7rKniE -J7vppdrUScSS0+eBrHSUPLdvwyn4RGp+lSwbWYcbg5EpSpE0GRJdchic0YDjvIoC -YHpe7Rkj93PYRTQyU4bhC88ck8tMqbvRYqMRqR+vobbkrj5LLCOQCHV5WEoxWh+0 -E2SpIFe7RkV++MmpIAc0h1tZAgMBAAGjMjAwMA8GA1UdEwEB/wQFMAMBAf8wHQYD -VR0OBBYEFPCD6nPIP1ubWzdf9UyPWvf0hki9MA0GCSqGSIb3DQEBBQUAA4IBAQCE -G85wl5eEWd7adH6XW/ikGN5salvpq/Fix6yVTzE6CrhlP5LBdkf6kx1bSPL18M45 -g0rw2zA/MWOhJ3+S6U+BE0zPGCuu8YQaZibR7snm3HiHUaZNMu5c8D0x0bcMxDjY -AVVcHCoNiL53Q4PLW27nbY6wwG0ffFKmgV3blxrYWfuUDgGpyPwHwkfVFvz9qjaV -mf12VJffL6W8omBPtgteb6UaT/k1oJ7YI0ldGf+ngpVbRhD+LC3cUtT6GO/BEPZu -8YTV/hbiDH5v3khVqMIeKT6o8IuXGG7F6a6vKwP1F1FwTXf4UC/ivhme7vdUH7B/ -Vv4AEbT8dNfEeFxrkDbh ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDAzCCAmwCEQC5L2DMiJ+hekYJuFtwbIqvMA0GCSqGSIb3DQEBBQUAMIHBMQsw -CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0Ns -YXNzIDIgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBH -MjE6MDgGA1UECxMxKGMpIDE5OTggVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9y -aXplZCB1c2Ugb25seTEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazAe -Fw05ODA1MTgwMDAwMDBaFw0yODA4MDEyMzU5NTlaMIHBMQswCQYDVQQGEwJVUzEX -MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0NsYXNzIDIgUHVibGlj -IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjE6MDgGA1UECxMx -KGMpIDE5OTggVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s -eTEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazCBnzANBgkqhkiG9w0B -AQEFAAOBjQAwgYkCgYEAp4gBIXQs5xoD8JjhlzwPIQjxnNuX6Zr8wgQGE75fUsjM -HiwSViy4AWkszJkfrbCWrnkE8hM5wXuYuggs6MKEEyyqaekJ9MepAqRCwiNPStjw -DqL7MWzJ5m+ZJwf15vRMeJ5t60aG+rmGyVTyssSv1EYcWskVMP8NbPUtDm3Of3cC -AwEAATANBgkqhkiG9w0BAQUFAAOBgQByLvl/0fFx+8Se9sVeUYpAmLho+Jscg9ji -nb3/7aHmZuovCfTK1+qlK5X2JGCGTUQug6XELaDTrnhpb3LabK4I8GOSN+a7xDAX -rXfMSTWqz9iP0b63GJZHc2pUIjRkLbYWm1lbtFFZOrMLFPQS32eg9K0yZF6xRnIn -jBJ7xUS0rg== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFGjCCBAKgAwIBAgIEPL7eEDANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJQ -TDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2Vu -dHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MRswGQYDVQQDExJDQyBTaWduZXQgLSBS -b290Q0EwHhcNMDIwNDE4MTQ1NDA4WhcNMjYwOTIxMTU0MjE5WjB2MQswCQYDVQQG -EwJQTDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMb -Q2VudHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MSAwHgYDVQQDExdDQyBTaWduZXQg -LSBQQ0EgS2xhc2EgMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM7B -rBlbN5maM5eg0BOTqoZ+9NBDvU8Lm5rTdrMswFTCathzpVVLK/JD4K3+4oCZ9SRA -spEXE4gvwb08ASY6w5s+HpRkeJw8YzMFR5kDZD5adgnCAy4vDfIXYZgppXPaTQ8w -nfUZ7BZ7Zfa7QBemUIcJIzJBB0UqgtxWCeol9IekpBRVmuuSA6QG0Jkm+pGDJ05y -j2eQG8jTcBENM7sVA8rGRMyFA4skSZ+D0OG6FS2xC1i9JyN0ag1yII/LPx8HK5J4 -W9MaPRNjAEeaa2qI9EpchwrOxnyVbQfSedCG1VRJfAsE/9tT9CMUPZ3xW20QjQcS -ZJqVcmGW9gVsXKQOVLsCAwEAAaOCAbMwggGvMA8GA1UdEwEB/wQFMAMBAf8wDgYD -VR0PAQH/BAQDAgEGMIIBBAYDVR0gBIH8MIH5MIH2Bg0rBgEEAb4/AgEKAQEBMIHk -MIGaBggrBgEFBQcCAjCBjRqBikNlcnR5ZmlrYXQgd3lzdGF3aW9ueSB6Z29kbmll -IHogZG9rdW1lbnRlbTogIlBvbGl0eWthIENlcnR5ZmlrYWNqaSBkbGEgUm9vdENB -Ii4gQ2VydHlmaWthdCB3eXN0YXdpb255IHByemV6IFJvb3RDQSB3IGhpZXJhcmNo -aWkgQ0MgU2lnbmV0LjBFBggrBgEFBQcCARY5aHR0cDovL3d3dy5zaWduZXQucGwv -cmVwb3p5dG9yaXVtL2Rva3VtZW50eS9wY19yb290Y2EudHh0MEQGA1UdHwQ9MDsw -OaA3oDWGM2h0dHA6Ly93d3cuc2lnbmV0LnBsL3JlcG96eXRvcml1bS9yb290Y2Ev -cm9vdGNhLmNybDAfBgNVHSMEGDAWgBTAm8UjDQLhpk5Iax8A6eOaFBuxrzAdBgNV -HQ4EFgQUwGxGyl2CfpYHRonE82AVXO08kMIwDQYJKoZIhvcNAQEFBQADggEBABp1 -TAUsa+BeVWg4cjowc8yTJ5XN3GvN96GObMkxUGY7U9kVrLI71xBgoNVyzXTiMNDB -vjh7vdPWjpl5SDiRpnnKiOFXA43HvNWzUaOkTu1mxjJsZsanot1Xt6j0ZDC+03Fj -LHdYMyM9kSWp6afb4980EPYZCcSzgM5TOGfJmNii5Tq468VFKrX+52Aou1G22Ohu -+EEOlOrG7ylKv1hHUJJCjwN0ZVEIn1nDbrU9FeGCz8J9ihVUvnENEBbBkU37PWqW -uHitKQDVtcwTwJJdR8cmKq3NmkwAm9fPacidQLpaw0WkuGrS+fEDhu1Nhy9xELP6 -NA9GRTCNxm/dXlcwnmY= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIElTCCA/6gAwIBAgIEOJsRPDANBgkqhkiG9w0BAQQFADCBujEUMBIGA1UEChML -RW50cnVzdC5uZXQxPzA9BgNVBAsUNnd3dy5lbnRydXN0Lm5ldC9TU0xfQ1BTIGlu -Y29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMcKGMpIDIwMDAg -RW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UEAxMxRW50cnVzdC5uZXQgU2VjdXJl -IFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMDAyMDQxNzIwMDBa -Fw0yMDAyMDQxNzUwMDBaMIG6MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDE/MD0GA1UE -CxQ2d3d3LmVudHJ1c3QubmV0L1NTTF9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1p -dHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMjAwMCBFbnRydXN0Lm5ldCBMaW1pdGVk -MTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRp -b24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDHwV9OcfHO -8GCGD9JYf9Mzly0XonUwtZZkJi9ow0SrqHXmAGc0V55lxyKbc+bT3QgON1WqJUaB -bL3+qPZ1V1eMkGxKwz6LS0MKyRFWmponIpnPVZ5h2QLifLZ8OAfc439PmrkDQYC2 -dWcTC5/oVzbIXQA23mYU2m52H083jIITiQIDAQABo4IBpDCCAaAwEQYJYIZIAYb4 -QgEBBAQDAgAHMIHjBgNVHR8EgdswgdgwgdWggdKggc+kgcwwgckxFDASBgNVBAoT -C0VudHJ1c3QubmV0MT8wPQYDVQQLFDZ3d3cuZW50cnVzdC5uZXQvU1NMX0NQUyBp -bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAyMDAw -IEVudHJ1c3QubmV0IExpbWl0ZWQxOjA4BgNVBAMTMUVudHJ1c3QubmV0IFNlY3Vy -ZSBTZXJ2ZXIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxDTALBgNVBAMTBENSTDEw -KwYDVR0QBCQwIoAPMjAwMDAyMDQxNzIwMDBagQ8yMDIwMDIwNDE3NTAwMFowCwYD -VR0PBAQDAgEGMB8GA1UdIwQYMBaAFMtswGvjuz7L/CKc/vuLkpyw8m4iMB0GA1Ud -DgQWBBTLbMBr47s+y/winP77i5KcsPJuIjAMBgNVHRMEBTADAQH/MB0GCSqGSIb2 -fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0BAQQFAAOBgQBi24GRzsia -d0Iv7L0no1MPUBvqTpLwqa+poLpIYcvvyQbvH9X07t9WLebKahlzqlO+krNQAraF -JnJj2HVQYnUUt7NQGj/KEQALhUVpbbalrlHhStyCP2yMNLJ3a9kC9n8O6mUE8c1U -yrrJzOCE98g+EZfTYAkYvAX/bIkz8OwVDw== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIExTCCA62gAwIBAgIBADANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJFVTEn -MCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQL -ExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEgMB4GA1UEAxMXR2xvYmFsIENo -YW1iZXJzaWduIFJvb3QwHhcNMDMwOTMwMTYxNDE4WhcNMzcwOTMwMTYxNDE4WjB9 -MQswCQYDVQQGEwJFVTEnMCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgy -NzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEgMB4G -A1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwggEgMA0GCSqGSIb3DQEBAQUA -A4IBDQAwggEIAoIBAQCicKLQn0KuWxfH2H3PFIP8T8mhtxOviteePgQKkotgVvq0 -Mi+ITaFgCPS3CU6gSS9J1tPfnZdan5QEcOw/Wdm3zGaLmFIoCQLfxS+EjXqXd7/s -QJ0lcqu1PzKY+7e3/HKE5TWH+VX6ox8Oby4o3Wmg2UIQxvi1RMLQQ3/bvOSiPGpV -eAp3qdjqGTK3L/5cPxvusZjsyq16aUXjlg9V9ubtdepl6DJWk0aJqCWKZQbua795 -B9Dxt6/tLE2Su8CoX6dnfQTyFQhwrJLWfQTSM/tMtgsL+xrJxI0DqX5c8lCrEqWh -z0hQpe/SyBoT+rB/sYIcd2oPX9wLlY/vQ37mRQklAgEDo4IBUDCCAUwwEgYDVR0T -AQH/BAgwBgEB/wIBDDA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3JsLmNoYW1i -ZXJzaWduLm9yZy9jaGFtYmVyc2lnbnJvb3QuY3JsMB0GA1UdDgQWBBRDnDafsJ4w -TcbOX60Qq+UDpfqpFDAOBgNVHQ8BAf8EBAMCAQYwEQYJYIZIAYb4QgEBBAQDAgAH -MCoGA1UdEQQjMCGBH2NoYW1iZXJzaWducm9vdEBjaGFtYmVyc2lnbi5vcmcwKgYD -VR0SBCMwIYEfY2hhbWJlcnNpZ25yb290QGNoYW1iZXJzaWduLm9yZzBbBgNVHSAE -VDBSMFAGCysGAQQBgYcuCgEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly9jcHMuY2hh -bWJlcnNpZ24ub3JnL2Nwcy9jaGFtYmVyc2lnbnJvb3QuaHRtbDANBgkqhkiG9w0B -AQUFAAOCAQEAPDtwkfkEVCeR4e3t/mh/YV3lQWVPMvEYBZRqHN4fcNs+ezICNLUM -bKGKfKX0j//U2K0X1S0E0T9YgOKBWYi+wONGkyT+kL0mojAt6JcmVzWJdJYY9hXi -ryQZVgICsroPFOrGimbBhkVVi76SvpykBMdJPJ7oKXqJ1/6v/2j1pReQvayZzKWG -VwlnRtvWFsJG8eSpUPWP0ZIV018+xgBJOm5YstHRJw0lyDL4IBHNfTIzSJRUTN3c -ecQwn+uOuFW114hcxWokPbLTBQNRxgfvzBRydD1ucs4YKIxKoHflCStFREest2d/ -AYoFWpO+ocH/+OcOZ6RHSXZddZAa9SaP8A== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIE7TCCBFagAwIBAgIEOAOR7jANBgkqhkiG9w0BAQQFADCByTELMAkGA1UEBhMC -VVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MUgwRgYDVQQLFD93d3cuZW50cnVzdC5u -ZXQvQ2xpZW50X0NBX0luZm8vQ1BTIGluY29ycC4gYnkgcmVmLiBsaW1pdHMgbGlh -Yi4xJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNV -BAMTKkVudHJ1c3QubmV0IENsaWVudCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe -Fw05OTEwMTIxOTI0MzBaFw0xOTEwMTIxOTU0MzBaMIHJMQswCQYDVQQGEwJVUzEU -MBIGA1UEChMLRW50cnVzdC5uZXQxSDBGBgNVBAsUP3d3dy5lbnRydXN0Lm5ldC9D -bGllbnRfQ0FfSW5mby9DUFMgaW5jb3JwLiBieSByZWYuIGxpbWl0cyBsaWFiLjEl -MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMq -RW50cnVzdC5uZXQgQ2xpZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0G -CSqGSIb3DQEBAQUAA4GLADCBhwKBgQDIOpleMRffrCdvkHvkGf9FozTC28GoT/Bo -6oT9n3V5z8GKUZSvx1cDR2SerYIbWtp/N3hHuzeYEpbOxhN979IMMFGpOZ5V+Pux -5zDeg7K6PvHViTs7hbqqdCz+PzFur5GVbgbUB01LLFZHGARS2g4Qk79jkJvh34zm -AqTmT173iwIBA6OCAeAwggHcMBEGCWCGSAGG+EIBAQQEAwIABzCCASIGA1UdHwSC -ARkwggEVMIHkoIHhoIHepIHbMIHYMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50 -cnVzdC5uZXQxSDBGBgNVBAsUP3d3dy5lbnRydXN0Lm5ldC9DbGllbnRfQ0FfSW5m -by9DUFMgaW5jb3JwLiBieSByZWYuIGxpbWl0cyBsaWFiLjElMCMGA1UECxMcKGMp -IDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQg -Q2xpZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCyg -KqAohiZodHRwOi8vd3d3LmVudHJ1c3QubmV0L0NSTC9DbGllbnQxLmNybDArBgNV -HRAEJDAigA8xOTk5MTAxMjE5MjQzMFqBDzIwMTkxMDEyMTkyNDMwWjALBgNVHQ8E -BAMCAQYwHwYDVR0jBBgwFoAUxPucKXuXzUyW/O5bs8qZdIuV6kwwHQYDVR0OBBYE -FMT7nCl7l81MlvzuW7PKmXSLlepMMAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EA -BAwwChsEVjQuMAMCBJAwDQYJKoZIhvcNAQEEBQADgYEAP66K8ddmAwWePvrqHEa7 -pFuPeJoSSJn59DXeDDYHAmsQOokUgZwxpnyyQbJq5wcBoUv5nyU7lsqZwz6hURzz -wy5E97BnRqqS5TvaHBkUODDV4qIxJS7x7EU47fgGWANzYrAQMY9Av2TgXD7FTx/a -EkP/TOYGJqibGapEPHayXOw= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEGTCCAwECEGFwy0mMX5hFKeewptlQW3owDQYJKoZIhvcNAQEFBQAwgcoxCzAJ -BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVy -aVNpZ24gVHJ1c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkgVmVyaVNpZ24s -IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNp -Z24gQ2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 -eSAtIEczMB4XDTk5MTAwMTAwMDAwMFoXDTM2MDcxNjIzNTk1OVowgcoxCzAJBgNV -BAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVyaVNp -Z24gVHJ1c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkgVmVyaVNpZ24sIElu -Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNpZ24g -Q2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAt -IEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArwoNwtUs22e5LeWU -J92lvuCwTY+zYVY81nzD9M0+hsuiiOLh2KRpxbXiv8GmR1BeRjmL1Za6tW8UvxDO -JxOeBUebMXoT2B/Z0wI3i60sR/COgQanDTAM6/c8DyAd3HJG7qUCyFvDyVZpTMUY -wZF7C9UTAJu878NIPkZgIIUq1ZC2zYugzDLdt/1AVbJQHFauzI13TccgTacxdu9o -koqQHgiBVrKtaaNS0MscxCM9H5n+TOgWY47GCI72MfbS+uV23bUckqNJzc0BzWjN -qWm6o+sdDZykIKbBoMXRRkwXbdKsZj+WjOCE1Db/IlnF+RFgqF8EffIa9iVCYQ/E -Srg+iQIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQA0JhU8wI1NQ0kdvekhktdmnLfe -xbjQ5F1fdiLAJvmEOjr5jLX77GDx6M4EsMjdpwOPMPOY36TmpDHf0xwLRtxyID+u -7gU8pDM/CzmscHhzS5kr3zDCVLCoO1Wh/hYozUK9dG6A2ydEp85EXdQbkJgNHkKU -sQAsBNB0owIFImNjzYO1+8FtYmtpdf1dcEG59b98377BMnMiIYtYgXsVkXq642RI -sH/7NiXaldDxJBQX3RiAa0YjOVT1jmIJBB2UkKab5iXiQkWquJCtvgiPqQtCGJTP -cjnhsUPgKM+351psE2tJs//jGHyJizNdrDPXp/naOlXJWBD5qu9ats9LS98q ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIID5TCCAs2gAwIBAgIEOeSXnjANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UEBhMC -VVMxFDASBgNVBAoTC1dlbGxzIEZhcmdvMSwwKgYDVQQLEyNXZWxscyBGYXJnbyBD -ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEvMC0GA1UEAxMmV2VsbHMgRmFyZ28gUm9v -dCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDAxMDExMTY0MTI4WhcNMjEwMTE0 -MTY0MTI4WjCBgjELMAkGA1UEBhMCVVMxFDASBgNVBAoTC1dlbGxzIEZhcmdvMSww -KgYDVQQLEyNXZWxscyBGYXJnbyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEvMC0G -A1UEAxMmV2VsbHMgRmFyZ28gUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEi -MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDVqDM7Jvk0/82bfuUER84A4n13 -5zHCLielTWi5MbqNQ1mXx3Oqfz1cQJ4F5aHiidlMuD+b+Qy0yGIZLEWukR5zcUHE -SxP9cMIlrCL1dQu3U+SlK93OvRw6esP3E48mVJwWa2uv+9iWsWCaSOAlIiR5NM4O -JgALTqv9i86C1y8IcGjBqAr5dE8Hq6T54oN+J3N0Prj5OEL8pahbSCOz6+MlsoCu -ltQKnMJ4msZoGK43YjdeUXWoWGPAUe5AeH6orxqg4bB4nVCMe+ez/I4jsNtlAHCE -AQgAFG5Uhpq6zPk3EPbg3oQtnaSFN9OH4xXQwReQfhkhahKpdv0SAulPIV4XAgMB -AAGjYTBfMA8GA1UdEwEB/wQFMAMBAf8wTAYDVR0gBEUwQzBBBgtghkgBhvt7hwcB -CzAyMDAGCCsGAQUFBwIBFiRodHRwOi8vd3d3LndlbGxzZmFyZ28uY29tL2NlcnRw -b2xpY3kwDQYJKoZIhvcNAQEFBQADggEBANIn3ZwKdyu7IvICtUpKkfnRLb7kuxpo -7w6kAOnu5+/u9vnldKTC2FJYxHT7zmu1Oyl5GFrvm+0fazbuSCUlFLZWohDo7qd/ -0D+j0MNdJu4HzMPBJCGHHt8qElNvQRbn7a6U+oxy+hNH8Dx+rn0ROhPs7fpvcmR7 -nX1/Jv16+yWt6j4pf0zjAFcysLPp7VMX2YuyFA4w6OXVE8Zkr8QA1dhYJPz1j+zx -x32l2w8n0cbyQIjmH/ZhqPRCyLk306m+LFZ4wnKbWV01QIroTmMatukgalHizqSQ -33ZwmVxwQ023tqcZZE6St8WRPH9IFmV7Fv3L/PvZ1dZPIWU7Sn9Ho/s= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDtjCCAp6gAwIBAgIOBcAAAQACQdAGCk3OdRAwDQYJKoZIhvcNAQEFBQAwdjEL -MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNV -BAsTGVRDIFRydXN0Q2VudGVyIENsYXNzIDQgQ0ExJTAjBgNVBAMTHFRDIFRydXN0 -Q2VudGVyIENsYXNzIDQgQ0EgSUkwHhcNMDYwMzIzMTQxMDIzWhcNMjUxMjMxMjI1 -OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIgR21i -SDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgNCBDQTElMCMGA1UEAxMc -VEMgVHJ1c3RDZW50ZXIgQ2xhc3MgNCBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQAD -ggEPADCCAQoCggEBALXNTJytrlG7fEjFDSmGehSt2VA9CXIgDRS2Y8b+WJ7gIV7z -jyIZ3E6RIM1viCmis8GsKnK6i1S4QF/yqvhDhsIwXMynXX/GCEnkDjkvjhjWkd0j -FnmA22xIHbzB3ygQY9GB493fL3l1oht48pQB5hBiecugfQLANIJ7x8CtHUzXapZ2 -W78mhEj9h/aECqqSB5lIPGG8ToVYx5ct/YFKocabEvVCUNFkPologiJw3fX64yhC -L04y87OjNopq1mJcrPoBbbTgci6VaLTxkwzGioLSHVPqfOA/QrcSWrjN2qUGZ8uh -d32llvCSHmcOHUJG5vnt+0dTf1cERh9GX8eu4I8CAwEAAaNCMEAwDwYDVR0TAQH/ -BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFB/quz4lGwa9pd1iBX7G -TFq/6A9DMA0GCSqGSIb3DQEBBQUAA4IBAQBYpCubTPfkpJKknGWYGWIi/HIy6QRd -xMRwLVpG3kxHiiW5ot3u6hKvSI3vK2fbO8w0mCr3CEf/Iq978fTr4jgCMxh1KBue -dmWsiANy8jhHHYz1nwqIUxAUu4DlDLNdjRfuHhkcho0UZ3iMksseIUn3f9MYv5x5 -+F0IebWqak2SNmy8eesOPXmK2PajVnBd3ttPedJ60pVchidlvqDTB4FAVd0Qy+BL -iILAkH0457+W4Ze6mqtCD9Of2J4VMxHL94J59bXAQVaS4d9VA61Iz9PyLrHHLVZM -ZHQqMc7cdalUR6SnQnIJ5+ECpkeyBM1CE+FhDOB4OiIgohxgQoaH96Xm ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDUzCCAjugAwIBAgIBAjANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEd -MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3Mg -Q2xhc3MgMyBDQSAxMB4XDTA1MDUwOTE0MTMwM1oXDTE1MDUwOTE0MTMwM1owSzEL -MAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MR0wGwYD -VQQDDBRCdXlwYXNzIENsYXNzIDMgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEP -ADCCAQoCggEBAKSO13TZKWTeXx+HgJHqTjnmGcZEC4DVC69TB4sSveZn8AKxifZg -isRbsELRwCGoy+Gb72RRtqfPFfV0gGgEkKBYouZ0plNTVUhjP5JW3SROjvi6K//z -NIqeKNc0n6wv1g/xpC+9UrJJhW05NfBEMJNGJPO251P7vGGvqaMU+8IXF4Rs4HyI -+MkcVyzwPX6UvCWThOiaAJpFBUJXgPROztmuOfbIUxAMZTpHe2DC1vqRycZxbL2R -hzyRhkmr8w+gbCZ2Xhysm3HljbybIR6c1jh+JIAVMYKWsUnTYjdbiAwKYjT+p0h+ -mbEwi5A3lRyoH6UsjfRVyNvdWQrCrXig9IsCAwEAAaNCMEAwDwYDVR0TAQH/BAUw -AwEB/zAdBgNVHQ4EFgQUOBTmyPCppAP0Tj4io1vy1uCtQHQwDgYDVR0PAQH/BAQD -AgEGMA0GCSqGSIb3DQEBBQUAA4IBAQABZ6OMySU9E2NdFm/soT4JXJEVKirZgCFP -Bdy7pYmrEzMqnji3jG8CcmPHc3ceCQa6Oyh7pEfJYWsICCD8igWKH7y6xsL+z27s -EzNxZy5p+qksP2bAEllNC1QCkoS72xLvg3BweMhT+t/Gxv/ciC8HwEmdMldg0/L2 -mSlf56oBzKwzqBwKu5HEA6BvtjT5htOzdlSY9EqBs1OdTUDs5XcTRa9bqh/YL0yC -e/4qxFi7T/ye/QNlGioOw6UgFpRreaaiErS7GqQjel/wroQk5PMr+4okoyeYZdow -dXb8GZHo2+ubPzK/QJcHJrrM85SFSnonk8+QQtS4Wxam58tAA915 ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIIDjCCBfagAwIBAgIJAOiOtsn4KhQoMA0GCSqGSIb3DQEBBQUAMIG8MQswCQYD -VQQGEwJVUzEQMA4GA1UECBMHSW5kaWFuYTEVMBMGA1UEBxMMSW5kaWFuYXBvbGlz -MSgwJgYDVQQKEx9Tb2Z0d2FyZSBpbiB0aGUgUHVibGljIEludGVyZXN0MRMwEQYD -VQQLEwpob3N0bWFzdGVyMR4wHAYDVQQDExVDZXJ0aWZpY2F0ZSBBdXRob3JpdHkx -JTAjBgkqhkiG9w0BCQEWFmhvc3RtYXN0ZXJAc3BpLWluYy5vcmcwHhcNMDgwNTEz -MDgwNzU2WhcNMTgwNTExMDgwNzU2WjCBvDELMAkGA1UEBhMCVVMxEDAOBgNVBAgT -B0luZGlhbmExFTATBgNVBAcTDEluZGlhbmFwb2xpczEoMCYGA1UEChMfU29mdHdh -cmUgaW4gdGhlIFB1YmxpYyBJbnRlcmVzdDETMBEGA1UECxMKaG9zdG1hc3RlcjEe -MBwGA1UEAxMVQ2VydGlmaWNhdGUgQXV0aG9yaXR5MSUwIwYJKoZIhvcNAQkBFhZo -b3N0bWFzdGVyQHNwaS1pbmMub3JnMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC -CgKCAgEA3DbmR0LCxFF1KYdAw9iOIQbSGE7r7yC9kDyFEBOMKVuUY/b0LfEGQpG5 -GcRCaQi/izZF6igFM0lIoCdDkzWKQdh4s/Dvs24t3dHLfer0dSbTPpA67tfnLAS1 -fOH1fMVO73e9XKKTM5LOfYFIz2u1IiwIg/3T1c87Lf21SZBb9q1NE8re06adU1Fx -Y0b4ShZcmO4tbZoWoXaQ4mBDmdaJ1mwuepiyCwMs43pPx93jzONKao15Uvr0wa8u -jyoIyxspgpJyQ7zOiKmqp4pRQ1WFmjcDeJPI8L20QcgHQprLNZd6ioFl3h1UCAHx -ZFy3FxpRvB7DWYd2GBaY7r/2Z4GLBjXFS21ZGcfSxki+bhQog0oQnBv1b7ypjvVp -/rLBVcznFMn5WxRTUQfqzj3kTygfPGEJ1zPSbqdu1McTCW9rXRTunYkbpWry9vjQ -co7qch8vNGopCsUK7BxAhRL3pqXTT63AhYxMfHMgzFMY8bJYTAH1v+pk1Vw5xc5s -zFNaVrpBDyXfa1C2x4qgvQLCxTtVpbJkIoRRKFauMe5e+wsWTUYFkYBE7axt8Feo -+uthSKDLG7Mfjs3FIXcDhB78rKNDCGOM7fkn77SwXWfWT+3Qiz5dW8mRvZYChD3F -TbxCP3T9PF2sXEg2XocxLxhsxGjuoYvJWdAY4wCAs1QnLpnwFVMCAwEAAaOCAg8w -ggILMB0GA1UdDgQWBBQ0cdE41xU2g0dr1zdkQjuOjVKdqzCB8QYDVR0jBIHpMIHm -gBQ0cdE41xU2g0dr1zdkQjuOjVKdq6GBwqSBvzCBvDELMAkGA1UEBhMCVVMxEDAO -BgNVBAgTB0luZGlhbmExFTATBgNVBAcTDEluZGlhbmFwb2xpczEoMCYGA1UEChMf -U29mdHdhcmUgaW4gdGhlIFB1YmxpYyBJbnRlcmVzdDETMBEGA1UECxMKaG9zdG1h -c3RlcjEeMBwGA1UEAxMVQ2VydGlmaWNhdGUgQXV0aG9yaXR5MSUwIwYJKoZIhvcN -AQkBFhZob3N0bWFzdGVyQHNwaS1pbmMub3JnggkA6I62yfgqFCgwDwYDVR0TAQH/ -BAUwAwEB/zARBglghkgBhvhCAQEEBAMCAAcwCQYDVR0SBAIwADAuBglghkgBhvhC -AQ0EIRYfU29mdHdhcmUgaW4gdGhlIFB1YmxpYyBJbnRlcmVzdDAwBglghkgBhvhC -AQQEIxYhaHR0cHM6Ly9jYS5zcGktaW5jLm9yZy9jYS1jcmwucGVtMDIGCWCGSAGG -+EIBAwQlFiNodHRwczovL2NhLnNwaS1pbmMub3JnL2NlcnQtY3JsLnBlbTAhBgNV -HREEGjAYgRZob3N0bWFzdGVyQHNwaS1pbmMub3JnMA4GA1UdDwEB/wQEAwIBBjAN -BgkqhkiG9w0BAQUFAAOCAgEAtM294LnqsgMrfjLp3nI/yUuCXp3ir1UJogxU6M8Y -PCggHam7AwIvUjki+RfPrWeQswN/2BXja367m1YBrzXU2rnHZxeb1NUON7MgQS4M -AcRb+WU+wmHo0vBqlXDDxm/VNaSsWXLhid+hoJ0kvSl56WEq2dMeyUakCHhBknIP -qxR17QnwovBc78MKYiC3wihmrkwvLo9FYyaW8O4x5otVm6o6+YI5HYg84gd1GuEP -sTC8cTLSOv76oYnzQyzWcsR5pxVIBcDYLXIC48s9Fmq6ybgREOJJhcyWR2AFJS7v -dVkz9UcZFu/abF8HyKZQth3LZjQl/GaD68W2MEH4RkRiqMEMVObqTFoo5q7Gt/5/ -O5aoLu7HaD7dAD0prypjq1/uSSotxdz70cbT0ZdWUoa2lOvUYFG3/B6bzAKb1B+P -+UqPti4oOxfMxaYF49LTtcYDyeFIQpvLP+QX4P4NAZUJurgNceQJcHdC2E3hQqlg -g9cXiUPS1N2nGLar1CQlh7XU4vwuImm9rWgs/3K1mKoGnOcqarihk3bOsPN/nOHg -T7jYhkalMwIsJWE3KpLIrIF0aGOHM3a9BX9e1dUCbb2v/ypaqknsmHlHU5H2DjRa -yaXG67Ljxay2oHA1u8hRadDytaIybrw/oDc5fHE2pgXfDBLkFqfF1stjo5VwP+YE -o2A= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIHPTCCBSWgAwIBAgIBADANBgkqhkiG9w0BAQQFADB5MRAwDgYDVQQKEwdSb290 -IENBMR4wHAYDVQQLExVodHRwOi8vd3d3LmNhY2VydC5vcmcxIjAgBgNVBAMTGUNB -IENlcnQgU2lnbmluZyBBdXRob3JpdHkxITAfBgkqhkiG9w0BCQEWEnN1cHBvcnRA -Y2FjZXJ0Lm9yZzAeFw0wMzAzMzAxMjI5NDlaFw0zMzAzMjkxMjI5NDlaMHkxEDAO -BgNVBAoTB1Jvb3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEi -MCAGA1UEAxMZQ0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJ -ARYSc3VwcG9ydEBjYWNlcnQub3JnMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC -CgKCAgEAziLA4kZ97DYoB1CW8qAzQIxL8TtmPzHlawI229Z89vGIj053NgVBlfkJ -8BLPRoZzYLdufujAWGSuzbCtRRcMY/pnCujW0r8+55jE8Ez64AO7NV1sId6eINm6 -zWYyN3L69wj1x81YyY7nDl7qPv4coRQKFWyGhFtkZip6qUtTefWIonvuLwphK42y -fk1WpRPs6tqSnqxEQR5YYGUFZvjARL3LlPdCfgv3ZWiYUQXw8wWRBB0bF4LsyFe7 -w2t6iPGwcswlWyCR7BYCEo8y6RcYSNDHBS4CMEK4JZwFaz+qOqfrU0j36NK2B5jc -G8Y0f3/JHIJ6BVgrCFvzOKKrF11myZjXnhCLotLddJr3cQxyYN/Nb5gznZY0dj4k -epKwDpUeb+agRThHqtdB7Uq3EvbXG4OKDy7YCbZZ16oE/9KTfWgu3YtLq1i6L43q -laegw1SJpfvbi1EinbLDvhG+LJGGi5Z4rSDTii8aP8bQUWWHIbEZAWV/RRyH9XzQ -QUxPKZgh/TMfdQwEUfoZd9vUFBzugcMd9Zi3aQaRIt0AUMyBMawSB3s42mhb5ivU -fslfrejrckzzAeVLIL+aplfKkQABi6F1ITe1Yw1nPkZPcCBnzsXWWdsC4PDSy826 -YreQQejdIOQpvGQpQsgi3Hia/0PsmBsJUUtaWsJx8cTLc6nloQsCAwEAAaOCAc4w -ggHKMB0GA1UdDgQWBBQWtTIb1Mfz4OaO873SsDrusjkY0TCBowYDVR0jBIGbMIGY -gBQWtTIb1Mfz4OaO873SsDrusjkY0aF9pHsweTEQMA4GA1UEChMHUm9vdCBDQTEe -MBwGA1UECxMVaHR0cDovL3d3dy5jYWNlcnQub3JnMSIwIAYDVQQDExlDQSBDZXJ0 -IFNpZ25pbmcgQXV0aG9yaXR5MSEwHwYJKoZIhvcNAQkBFhJzdXBwb3J0QGNhY2Vy -dC5vcmeCAQAwDwYDVR0TAQH/BAUwAwEB/zAyBgNVHR8EKzApMCegJaAjhiFodHRw -czovL3d3dy5jYWNlcnQub3JnL3Jldm9rZS5jcmwwMAYJYIZIAYb4QgEEBCMWIWh0 -dHBzOi8vd3d3LmNhY2VydC5vcmcvcmV2b2tlLmNybDA0BglghkgBhvhCAQgEJxYl -aHR0cDovL3d3dy5jYWNlcnQub3JnL2luZGV4LnBocD9pZD0xMDBWBglghkgBhvhC -AQ0ESRZHVG8gZ2V0IHlvdXIgb3duIGNlcnRpZmljYXRlIGZvciBGUkVFIGhlYWQg -b3ZlciB0byBodHRwOi8vd3d3LmNhY2VydC5vcmcwDQYJKoZIhvcNAQEEBQADggIB -ACjH7pyCArpcgBLKNQodgW+JapnM8mgPf6fhjViVPr3yBsOQWqy1YPaZQwGjiHCc -nWKdpIevZ1gNMDY75q1I08t0AoZxPuIrA2jxNGJARjtT6ij0rPtmlVOKTV39O9lg -18p5aTuxZZKmxoGCXJzN600BiqXfEVWqFcofN8CCmHBh22p8lqOOLlQ+TyGpkO/c -gr/c6EWtTZBzCDyUZbAEmXZ/4rzCahWqlwQ3JNgelE5tDlG+1sSPypZt90Pf6DBl -Jzt7u0NDY8RD97LsaMzhGY4i+5jhe1o+ATc7iwiwovOVThrLm82asduycPAtStvY -sONvRUgzEv/+PDIqVPfE94rwiCPCR/5kenHA0R6mY7AHfqQv0wGP3J8rtsYIqQ+T -SCX8Ev2fQtzzxD72V7DX3WnRBnc0CkvSyqD/HMaMyRa+xMwyN2hzXwj7UfdJUzYF -CpUCTPJ5GhD22Dp1nPMd8aINcGeGG7MW9S/lpOt5hvk9C8JzC6WZrG/8Z7jlLwum -GCSNe9FINSkYQKyTYOGWhlC0elnYjyELn8+CkcY7v2vcB5G5l1YjqrZslMZIBjzk -zk6q5PYvCdxTby78dOs6Y5nCpqyJvKeyRKANihDjbPIky/qbn3BHLt4Ui9SyIAmW -omTxJBzcoTWcFbLUvFUufQb1nA5V9FrWk9p2rSVzTMVD ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIID5jCCAs6gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBgzELMAkGA1UEBhMCVVMx -HTAbBgNVBAoTFEFPTCBUaW1lIFdhcm5lciBJbmMuMRwwGgYDVQQLExNBbWVyaWNh -IE9ubGluZSBJbmMuMTcwNQYDVQQDEy5BT0wgVGltZSBXYXJuZXIgUm9vdCBDZXJ0 -aWZpY2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyOTA2MDAwMFoXDTM3MTEyMDE1 -MDMwMFowgYMxCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRBT0wgVGltZSBXYXJuZXIg -SW5jLjEcMBoGA1UECxMTQW1lcmljYSBPbmxpbmUgSW5jLjE3MDUGA1UEAxMuQU9M -IFRpbWUgV2FybmVyIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIw -DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJnej8Mlo2k06AX3dLm/WpcZuS+U -0pPlLYnKhHw/EEMbjIt8hFj4JHxIzyr9wBXZGH6EGhfT257XyuTZ16pYUYfw8ItI -TuLCxFlpMGK2MKKMCxGZYTVtfu/FsRkGIBKOQuHfD5YQUqjPnF+VFNivO3ULMSAf -RC+iYkGzuxgh28pxPIzstrkNn+9R7017EvILDOGsQI93f7DKeHEMXRZxcKLXwjqF -zQ6axOAAsNUl6twr5JQtOJyJQVdkKGUZHLZEtMgxa44Be3ZZJX8VHIQIfHNlIAqh -BC4aMqiaILGcLCFZ5/vP7nAtCMpjPiybkxlqpMKX/7eGV4iFbJ4VFitNLLMCAwEA -AaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUoTYwFsuGkABFgFOxj8jY -PXy+XxIwHwYDVR0jBBgwFoAUoTYwFsuGkABFgFOxj8jYPXy+XxIwDgYDVR0PAQH/ -BAQDAgGGMA0GCSqGSIb3DQEBBQUAA4IBAQCKIBilvrMvtKaEAEAwKfq0FHNMeUWn -9nDg6H5kHgqVfGphwu9OH77/yZkfB2FK4V1Mza3u0FIy2VkyvNp5ctZ7CegCgTXT -Ct8RHcl5oIBN/lrXVtbtDyqvpxh1MwzqwWEFT2qaifKNuZ8u77BfWgDrvq2g+EQF -Z7zLBO+eZMXpyD8Fv8YvBxzDNnGGyjhmSs3WuEvGbKeXO/oTLW4jYYehY0KswsuX -n2Fozy1MBJ3XJU8KDk2QixhWqJNIV9xvrr2eZ1d3iVCzvhGbRWeDhhmH05i9CBoW -H1iCC+GWaQVLjuyDUTEH1dSf/1l7qG6Fz9NLqUmwX7A5KGgOc90lmt4S ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDfTCCAuagAwIBAgIDErvmMA0GCSqGSIb3DQEBBQUAME4xCzAJBgNVBAYTAlVT -MRAwDgYDVQQKEwdFcXVpZmF4MS0wKwYDVQQLEyRFcXVpZmF4IFNlY3VyZSBDZXJ0 -aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDIwNTIxMDQwMDAwWhcNMTgwODIxMDQwMDAw -WjBCMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UE -AxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB -CgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9m -OSm9BXiLnTjoBbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIu -T8rxh0PBFpVXLVDviS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6c -JmTM386DGXHKTubU1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmR -Cw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5asz -PeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQABo4HwMIHtMB8GA1UdIwQYMBaAFEjm -aPkr0rKV10fYIyAQTzOYkJ/UMB0GA1UdDgQWBBTAephojYn7qwVkDBF9qn1luMrM -TjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjA6BgNVHR8EMzAxMC+g -LaArhilodHRwOi8vY3JsLmdlb3RydXN0LmNvbS9jcmxzL3NlY3VyZWNhLmNybDBO -BgNVHSAERzBFMEMGBFUdIAAwOzA5BggrBgEFBQcCARYtaHR0cHM6Ly93d3cuZ2Vv -dHJ1c3QuY29tL3Jlc291cmNlcy9yZXBvc2l0b3J5MA0GCSqGSIb3DQEBBQUAA4GB -AHbhEm5OSxYShjAGsoEIz/AIx8dxfmbuwu3UOx//8PDITtZDOLC5MH0Y0FWDomrL -NhGc6Ehmo21/uBPUR/6LWlxz/K7ZGzIZOKuXNBSqltLroxwUCEm2u+WR74M26x1W -b8ravHNjkOR/ez4iyz0H7V84dJzjA1BOoa+Y7mHyhD8S ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEPzCCAyegAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MQswCQYDVQQGEwJHQjEb -MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow -GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEkMCIGA1UEAwwbU2VjdXJlIENlcnRp -ZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVow -fjELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G -A1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxJDAiBgNV -BAMMG1NlY3VyZSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEB -BQADggEPADCCAQoCggEBAMBxM4KK0HDrc4eCQNUd5MvJDkKQ+d40uaG6EfQlhfPM -cm3ye5drswfxdySRXyWP9nQ95IDC+DwN879A6vfIUtFyb+/Iq0G4bi4XKpVpDM3S -HpR7LZQdqnXXs5jLrLxkU0C8j6ysNstcrbvd4JQX7NFc0L/vpZXJkMWwrPsbQ996 -CF23uPJAGysnnlDOXmWCiIxe004MeuoIkbY2qitC++rCoznl2yY4rYsK7hljxxwk -3wN42ubqwUcaCwtGCd0C/N7Lh1/XMGNooa7cMqG6vv5Eq2i2pRcV/b3Vp6ea5EQz -6YiO/O1R65NxTq0B50SOqy3LqP4BSUjwwN3HaNiS/j0CAwEAAaOBxzCBxDAdBgNV -HQ4EFgQUPNiTiMLAggnMAZkGkyDpnnAJY08wDgYDVR0PAQH/BAQDAgEGMA8GA1Ud -EwEB/wQFMAMBAf8wgYEGA1UdHwR6MHgwO6A5oDeGNWh0dHA6Ly9jcmwuY29tb2Rv -Y2EuY29tL1NlY3VyZUNlcnRpZmljYXRlU2VydmljZXMuY3JsMDmgN6A1hjNodHRw -Oi8vY3JsLmNvbW9kby5uZXQvU2VjdXJlQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmww -DQYJKoZIhvcNAQEFBQADggEBAIcBbSMdflsXfcFhMs+P5/OKlFlm4J4oqF7Tt/Q0 -5qo5spcWxYJvMqTpjOev/e/C6LlLqqP05tqNZSH7uoDrJiiFGv45jN5bBAS0VPmj -Z55B+glSzAVIqMk/IQQezkhr/IXownuvf7fM+F86/TXGDe+X3EyrEeFryzHRbPtI -gKvcnDe4IRRLDXE97IMzbtFuMhbsmMcWi1mmNKsFVy2T96oTy9IT4rcuO81rUBcJ -aD61JlfutuC23bkpgHl9j6PwpCikFcSF9CfUa7/lXORlAnZUtOM3ZiTTGWHIUhDl -izeauan5Hb/qmZJhlv8BzaFfDbxxvA6sCx1HRR3B7Hzs/Sk= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0 -IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz -BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y -aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG -9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMTk1NFoXDTE5MDYy -NjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y -azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs -YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw -Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl -cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vY -dA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9 -WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QS -v4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9v -UJSZSWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTu -IYEZoDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwC -W/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFFjCCBH+gAwIBAgIBADANBgkqhkiG9w0BAQQFADCBsDELMAkGA1UEBhMCSUwx -DzANBgNVBAgTBklzcmFlbDEOMAwGA1UEBxMFRWlsYXQxFjAUBgNVBAoTDVN0YXJ0 -Q29tIEx0ZC4xGjAYBgNVBAsTEUNBIEF1dGhvcml0eSBEZXAuMSkwJwYDVQQDEyBG -cmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJARYS -YWRtaW5Ac3RhcnRjb20ub3JnMB4XDTA1MDMxNzE3Mzc0OFoXDTM1MDMxMDE3Mzc0 -OFowgbAxCzAJBgNVBAYTAklMMQ8wDQYDVQQIEwZJc3JhZWwxDjAMBgNVBAcTBUVp -bGF0MRYwFAYDVQQKEw1TdGFydENvbSBMdGQuMRowGAYDVQQLExFDQSBBdXRob3Jp -dHkgRGVwLjEpMCcGA1UEAxMgRnJlZSBTU0wgQ2VydGlmaWNhdGlvbiBBdXRob3Jp -dHkxITAfBgkqhkiG9w0BCQEWEmFkbWluQHN0YXJ0Y29tLm9yZzCBnzANBgkqhkiG -9w0BAQEFAAOBjQAwgYkCgYEA7YRgACOeyEpRKSfeOqE5tWmrCbIvNP1h3D3TsM+x -18LEwrHkllbEvqoUDufMOlDIOmKdw6OsWXuO7lUaHEe+o5c5s7XvIywI6Nivcy+5 -yYPo7QAPyHWlLzRMGOh2iCNJitu27Wjaw7ViKUylS7eYtAkUEKD4/mJ2IhULpNYI -LzUCAwEAAaOCAjwwggI4MA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgHmMB0G -A1UdDgQWBBQcicOWzL3+MtUNjIExtpidjShkjTCB3QYDVR0jBIHVMIHSgBQcicOW -zL3+MtUNjIExtpidjShkjaGBtqSBszCBsDELMAkGA1UEBhMCSUwxDzANBgNVBAgT -BklzcmFlbDEOMAwGA1UEBxMFRWlsYXQxFjAUBgNVBAoTDVN0YXJ0Q29tIEx0ZC4x -GjAYBgNVBAsTEUNBIEF1dGhvcml0eSBEZXAuMSkwJwYDVQQDEyBGcmVlIFNTTCBD -ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJARYSYWRtaW5Ac3Rh -cnRjb20ub3JnggEAMB0GA1UdEQQWMBSBEmFkbWluQHN0YXJ0Y29tLm9yZzAdBgNV -HRIEFjAUgRJhZG1pbkBzdGFydGNvbS5vcmcwEQYJYIZIAYb4QgEBBAQDAgAHMC8G -CWCGSAGG+EIBDQQiFiBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAy -BglghkgBhvhCAQQEJRYjaHR0cDovL2NlcnQuc3RhcnRjb20ub3JnL2NhLWNybC5j -cmwwKAYJYIZIAYb4QgECBBsWGWh0dHA6Ly9jZXJ0LnN0YXJ0Y29tLm9yZy8wOQYJ -YIZIAYb4QgEIBCwWKmh0dHA6Ly9jZXJ0LnN0YXJ0Y29tLm9yZy9pbmRleC5waHA/ -YXBwPTExMTANBgkqhkiG9w0BAQQFAAOBgQBscSXhnjSRIe/bbL0BCFaPiNhBOlP1 -ct8nV0t2hPdopP7rPwl+KLhX6h/BquL/lp9JmeaylXOWxkjHXo0Hclb4g4+fd68p -00UOpO6wNnQt8M2YI3s3S9r+UZjEHjQ8iP2ZO1CnwYszx8JSFhKVU2Ui77qLzmLb -cCOxgN8aIDjnfg== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIE5jCCA86gAwIBAgIEO45L/DANBgkqhkiG9w0BAQUFADBdMRgwFgYJKoZIhvcN -AQkBFglwa2lAc2suZWUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKExlBUyBTZXJ0aWZp -dHNlZXJpbWlza2Vza3VzMRAwDgYDVQQDEwdKdXVyLVNLMB4XDTAxMDgzMDE0MjMw -MVoXDTE2MDgyNjE0MjMwMVowXTEYMBYGCSqGSIb3DQEJARYJcGtpQHNrLmVlMQsw -CQYDVQQGEwJFRTEiMCAGA1UEChMZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czEQ -MA4GA1UEAxMHSnV1ci1TSzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB -AIFxNj4zB9bjMI0TfncyRsvPGbJgMUaXhvSYRqTCZUXP00B841oiqBB4M8yIsdOB -SvZiF3tfTQou0M+LI+5PAk676w7KvRhj6IAcjeEcjT3g/1tf6mTll+g/mX8MCgkz -ABpTpyHhOEvWgxutr2TC+Rx6jGZITWYfGAriPrsfB2WThbkasLnE+w0R9vXW+RvH -LCu3GFH+4Hv2qEivbDtPL+/40UceJlfwUR0zlv/vWT3aTdEVNMfqPxZIe5EcgEMP -PbgFPtGzlc3Yyg/CQ2fbt5PgIoIuvvVoKIO5wTtpeyDaTpxt4brNj3pssAki14sL -2xzVWiZbDcDq5WDQn/413z8CAwEAAaOCAawwggGoMA8GA1UdEwEB/wQFMAMBAf8w -ggEWBgNVHSAEggENMIIBCTCCAQUGCisGAQQBzh8BAQEwgfYwgdAGCCsGAQUFBwIC -MIHDHoHAAFMAZQBlACAAcwBlAHIAdABpAGYAaQBrAGEAYQB0ACAAbwBuACAAdgDk -AGwAagBhAHMAdABhAHQAdQBkACAAQQBTAC0AaQBzACAAUwBlAHIAdABpAGYAaQB0 -AHMAZQBlAHIAaQBtAGkAcwBrAGUAcwBrAHUAcwAgAGEAbABhAG0ALQBTAEsAIABz -AGUAcgB0AGkAZgBpAGsAYQBhAHQAaQBkAGUAIABrAGkAbgBuAGkAdABhAG0AaQBz -AGUAawBzMCEGCCsGAQUFBwIBFhVodHRwOi8vd3d3LnNrLmVlL2Nwcy8wKwYDVR0f -BCQwIjAgoB6gHIYaaHR0cDovL3d3dy5zay5lZS9qdXVyL2NybC8wHQYDVR0OBBYE -FASqekej5ImvGs8KQKcYP2/v6X2+MB8GA1UdIwQYMBaAFASqekej5ImvGs8KQKcY -P2/v6X2+MA4GA1UdDwEB/wQEAwIB5jANBgkqhkiG9w0BAQUFAAOCAQEAe8EYlFOi -CfP+JmeaUOTDBS8rNXiRTHyoERF5TElZrMj3hWVcRrs7EKACr81Ptcw2Kuxd/u+g -kcm2k298gFTsxwhwDY77guwqYHhpNjbRxZyLabVAyJRld/JXIWY7zoVAtjNjGr95 -HvxcHdMdkxuLDF2FvZkwMhgJkVLpfKG6/2SSmuz+Ne6ML678IIbsSt4beDI3poHS -na9aEhbKmVv8b20OxaAehsmR0FyYgl9jDIpaq9iVpszLita/ZEuOyoqysOkhMp6q -qIWYNIE5ITuoOlIyPfZrN4YGWhWY3PARZv40ILcD9EEQfTmEeZZyY7aWAuVrua0Z -TbvGRNs2yyqcjg== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDujCCAqKgAwIBAgIEAJiWijANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJO -TDEeMBwGA1UEChMVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSYwJAYDVQQDEx1TdGFh -dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQTAeFw0wMjEyMTcwOTIzNDlaFw0xNTEy -MTYwOTE1MzhaMFUxCzAJBgNVBAYTAk5MMR4wHAYDVQQKExVTdGFhdCBkZXIgTmVk -ZXJsYW5kZW4xJjAkBgNVBAMTHVN0YWF0IGRlciBOZWRlcmxhbmRlbiBSb290IENB -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmNK1URF6gaYUmHFtvszn -ExvWJw56s2oYHLZhWtVhCb/ekBPHZ+7d89rFDBKeNVU+LCeIQGv33N0iYfXCxw71 -9tV2U02PjLwYdjeFnejKScfST5gTCaI+Ioicf9byEGW07l8Y1Rfj+MX94p2i71MO -hXeiD+EwR+4A5zN9RGcaC1Hoi6CeUJhoNFIfLm0B8mBF8jHrqTFoKbt6QZ7GGX+U -tFE5A3+y3qcym7RHjm+0Sq7lr7HcsBthvJly3uSJt3omXdozSVtSnA71iq3DuD3o -BmrC1SoLbHuEvVYFy4ZlkuxEK7COudxwC0barbxjiDn622r+I/q85Ej0ZytqERAh -SQIDAQABo4GRMIGOMAwGA1UdEwQFMAMBAf8wTwYDVR0gBEgwRjBEBgRVHSAAMDww -OgYIKwYBBQUHAgEWLmh0dHA6Ly93d3cucGtpb3ZlcmhlaWQubmwvcG9saWNpZXMv -cm9vdC1wb2xpY3kwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSofeu8Y6R0E3QA -7Jbg0zTBLL9s+DANBgkqhkiG9w0BAQUFAAOCAQEABYSHVXQ2YcG70dTGFagTtJ+k -/rvuFbQvBgwp8qiSpGEN/KtcCFtREytNwiphyPgJWPwtArI5fZlmgb9uXJVFIGzm -eafR2Bwp/MIgJ1HI8XxdNGdphREwxgDS1/PTfLbwMVcoEoJz6TMvplW0C5GUR5z6 -u3pCMuiufi3IvKwUv9kP2Vv8wfl6leF9fpb8cbDCTMjfRTTJzg3ynGQI0DvDKcWy -7ZAEwbEpkcUwb8GpcjPM/l0WFywRaed+/sWDCN+83CI6LiBpIzlWYGeQiy52OfsR -iJf2fL1LuCAWZwWN4jvBcj+UlTfHXbme2JOhF4//DGYVwSR8MnwDHTuhWEUykw== ------END CERTIFICATE----- diff --git a/indra/newview/app_settings/ao_template.ini b/indra/newview/app_settings/ao_template.ini index 03f02e3059..ab4c68cac2 100644 --- a/indra/newview/app_settings/ao_template.ini +++ b/indra/newview/app_settings/ao_template.ini @@ -63,6 +63,7 @@ [ Running ] [ Turning Right ] [ Turning Left ] +[ Typing ] [ Floating ] [ Swimming Forward ] [ Swimming Up ] diff --git a/indra/newview/app_settings/autoreplace.xml b/indra/newview/app_settings/autoreplace.xml new file mode 100644 index 0000000000..f4075a16e0 --- /dev/null +++ b/indra/newview/app_settings/autoreplace.xml @@ -0,0 +1,8328 @@ + + + + name + Abbreviations + replacements + + afaic + As far as I am concerned + afaik + As far as I know + afk + away from keyboard + atm + at the moment + bbiab + be back in a bit + bbl + be back later + brb + be right back + btw + by the way + fyi + For your information + fwiw + For what its worth + gtg + got to go + idk + I don't know + iirc + if I recall correctly + imho + in my humble opinion + imo + in my opinion + irl + in real life + np + no problem + nsfw + not safe for work + nvm + nevermind + tc + take care + thx + thanks + ttfn + ta-ta for now + ttyl + talk to you later + ty + thank you + tyvm + thank you very much + wb + welcome back + yw + you're welcome + yvw + you're very welcome + + + + name + Spelling Corrections + replacements + + Amercia + America + Bernouilli + Bernoulli + Blitzkreig + Blitzkrieg + Bonnano + Bonanno + Brasillian + Brazilian + Britian + Britain + Brittish + British + Buddah + Buddha + Buddist + Buddhist + Cambrige + Cambridge + Capetown + Cape Town + Carmalite + Carmelite + Carnagie + Carnegie + Carnagie-Mellon + Carnegie-Mellon + Carnigie + Carnegie + Carnigie-Mellon + Carnegie-Mellon + Carribbean + Caribbean + Carribean + Caribbean + Carthagian + Carthaginian + Cataline + Catiline + Ceasar + Caesar + Celcius + Celsius + Champange + Champagne + Cincinatti + Cincinnati + Cincinnatti + Cincinnati + Conneticut + Connecticut + Dardenelles + Dardanelles + Dravadian + Dravidian + Enlish + English + Europian + European + Europians + Europeans + Eurpean + European + Eurpoean + European + Farenheit + Fahrenheit + Febuary + February + Feburary + February + Flemmish + Flemish + Formalhaut + Fomalhaut + Foundland + Newfoundland + Fransiscan + Franciscan + Fransiscans + Franciscans + Galations + Galatians + Gameboy + Game Boy + Ghandi + Gandhi + Godounov + Godunov + Gothenberg + Gothenburg + Gottleib + Gottlieb + Guaduloupe + Guadalupe + Guadulupe + Guadalupe + Guatamala + Guatemala + Guatamalan + Guatemalan + Guilia + Giulia + Guilio + Giulio + Guiness + Guinness + Guiseppe + Giuseppe + Habsbourg + Habsburg + Hallowean + Halloween + Heidelburg + Heidelberg + Ihaca + Ithaca + Israelies + Israelis + Janurary + January + Januray + January + Japanes + Japanese + Johanine + Johannine + Jospeh + Joseph + Juadaism + Judaism + Juadism + Judaism + Lybia + Libya + Malcom + Malcolm + Massachussets + Massachusetts + Massachussetts + Massachusetts + Mediteranean + Mediterranean + Michagan + Michigan + Misouri + Missouri + Missisipi + Mississippi + Missisippi + Mississippi + Monserrat + Montserrat + Montnana + Montana + Morisette + Morissette + Morrisette + Morissette + Mythraic + Mithraic + Naploeon + Napoleon + Napolean + Napoleon + Napoleonian + Napoleonic + Nazereth + Nazareth + Newyorker + New Yorker + Novermber + November + Nullabour + Nullarbor + Nuremburg + Nuremberg + Palistian + Palestinian + Palistinian + Palestinian + Palistinians + Palestinians + Papanicalou + Papanicolaou + Peloponnes + Peloponnesus + Pennyslvania + Pennsylvania + Pharoah + Pharaoh + Philipines + Philippines + Phillipine + Philippine + Phillipines + Philippines + Phillippines + Philippines + Phonecian + Phoenecian + Portugese + Portuguese + Postdam + Potsdam + Premonasterians + Premonstratensians + Pucini + Puccini + Puertorrican + Puerto Rican + Puertorricans + Puerto Ricans + Queenland + Queensland + Rockerfeller + Rockefeller + Russion + Russian + Sanhedrim + Sanhedrin + Saterday + Saturday + Saterdays + Saturdays + Sionist + Zionist + Sionists + Zionists + Sixtin + Sistine + Skagerak + Skagerrak + Tolkein + Tolkien + Tuscon + Tucson + Ukranian + Ukrainian + UnitesStates + UnitedStates + Yementite + Yemenite + abandonned + abandoned + aberation + aberration + abilties + abilities + abilty + ability + abondon + abandon + abondoned + abandoned + abondoning + abandoning + abondons + abandons + aborigene + aborigine + abortificant + abortifacient + abreviate + abbreviate + abreviated + abbreviated + abreviation + abbreviation + abritrary + arbitrary + absail + abseil + absailing + abseiling + absense + absence + absolutly + absolutely + absorbsion + absorption + absorbtion + absorption + abundacies + abundances + abundancies + abundances + abundunt + abundant + abutts + abuts + acadamy + academy + acadmic + academic + accademic + academic + accademy + academy + acccused + accused + accelleration + acceleration + accension + ascension + acceptence + acceptance + acceptible + acceptable + accessable + accessible + accidentaly + accidentally + accidently + accidentally + acclimitization + acclimatization + accomadate + accommodate + accomadated + accommodated + accomadates + accommodates + accomadating + accommodating + accomadation + accommodation + accomadations + accommodations + accomdate + accommodate + accomodate + accommodate + accomodated + accommodated + accomodates + accommodates + accomodating + accommodating + accomodation + accommodation + accomodations + accommodations + accompanyed + accompanied + accordeon + accordion + accordian + accordion + accoring + according + accoustic + acoustic + accquainted + acquainted + accrediation + accreditation + accredidation + accreditation + accross + across + accussed + accused + acedemic + academic + acheive + achieve + acheived + achieved + acheivement + achievement + acheivements + achievements + acheives + achieves + acheiving + achieving + acheivment + achievement + acheivments + achievements + achievment + achievement + achievments + achievements + achivement + achievement + achivements + achievements + acknowldeged + acknowledged + acknowledgeing + acknowledging + ackward + awkward + acommodate + accommodate + acomplish + accomplish + acomplished + accomplished + acomplishment + accomplishment + acomplishments + accomplishments + acording + according + acordingly + accordingly + acquaintence + acquaintance + acquaintences + acquaintances + acquiantence + acquaintance + acquiantences + acquaintances + acquited + acquitted + activites + activities + activly + actively + actualy + actually + acuracy + accuracy + acused + accused + acustom + accustom + acustommed + accustomed + adavanced + advanced + adbandon + abandon + additinally + additionally + additionaly + additionally + additonal + additional + additonally + additionally + addmission + admission + addopt + adopt + addopted + adopted + addoptive + adoptive + addres + address + addresable + addressable + addresed + addressed + addresing + addressing + addressess + addresses + addtion + addition + addtional + additional + adecuate + adequate + adequit + adequate + adhearing + adhering + adherance + adherence + admendment + amendment + admininistrative + administrative + adminstered + administered + adminstrate + administrate + adminstration + administration + adminstrative + administrative + adminstrator + administrator + admissability + admissibility + admissable + admissible + admited + admitted + admitedly + admittedly + adn + and + adolecent + adolescent + adquire + acquire + adquired + acquired + adquires + acquires + adquiring + acquiring + adres + address + adresable + addressable + adresing + addressing + adress + address + adressable + addressable + adressed + addressed + adressing + addressing + adventrous + adventurous + advertisment + advertisement + advertisments + advertisements + advesary + adversary + adviced + advised + aeriel + aerial + aeriels + aerials + afair + affair + afficianados + aficionados + afficionado + aficionado + afficionados + aficionados + affilate + affiliate + affilliate + affiliate + affort + afford + aforememtioned + aforementioned + againnst + against + agains + against + agaisnt + against + aganist + against + aggaravates + aggravates + aggreed + agreed + aggreement + agreement + aggregious + egregious + aggresive + aggressive + agian + again + agianst + against + agin + again + agina + again + aginst + against + agravate + aggravate + agre + agree + agred + agreed + agreeement + agreement + agreemnt + agreement + agregate + aggregate + agregates + aggregates + agreing + agreeing + agression + aggression + agressive + aggressive + agressively + aggressively + agressor + aggressor + agricuture + agriculture + agrieved + aggrieved + ahev + have + ahppen + happen + ahve + have + aicraft + aircraft + aiport + airport + airbourne + airborne + aircaft + aircraft + aircrafts + aircraft + airporta + airports + airrcraft + aircraft + aisian + asian + albiet + albeit + alchohol + alcohol + alchoholic + alcoholic + alchol + alcohol + alcholic + alcoholic + alcohal + alcohol + alcoholical + alcoholic + aledge + allege + aledged + alleged + aledges + alleges + alege + allege + aleged + alleged + alegience + allegiance + algebraical + algebraic + algorhitms + algorithms + algoritm + algorithm + algoritms + algorithms + alientating + alienating + alledge + allege + alledged + alleged + alledgedly + allegedly + alledges + alleges + allegedely + allegedly + allegedy + allegedly + allegely + allegedly + allegence + allegiance + allegience + allegiance + allign + align + alligned + aligned + alliviate + alleviate + allopone + allophone + allopones + allophones + allready + already + allthough + although + alltime + all-time + alltogether + altogether + almsot + almost + alochol + alcohol + alomst + almost + alot + a lot + alotted + allotted + alowed + allowed + alowing + allowing + alreayd + already + alse + else + alsot + also + alternitives + alternatives + altho + although + althought + although + altough + although + alusion + allusion + alwasy + always + alwyas + always + amalgomated + amalgamated + amatuer + amateur + amature + armature + amendmant + amendment + amerliorate + ameliorate + amke + make + amking + making + ammend + amend + ammended + amended + ammendment + amendment + ammendments + amendments + ammount + amount + ammused + amused + amoung + among + amoungst + amongst + amung + among + amunition + ammunition + analagous + analogous + analitic + analytic + analogeous + analogous + anarchim + anarchism + anarchistm + anarchism + anbd + and + ancestory + ancestry + ancilliary + ancillary + androgenous + androgynous + androgeny + androgyny + anihilation + annihilation + aniversary + anniversary + annoint + anoint + annointed + anointed + annointing + anointing + annoints + anoints + annouced + announced + annualy + annually + annuled + annulled + anohter + another + anomolies + anomalies + anomolous + anomalous + anomoly + anomaly + anonimity + anonymity + anounced + announced + anouncement + announcement + ansalisation + nasalisation + ansalization + nasalization + ansestors + ancestors + antartic + antarctic + anthromorphization + anthropomorphization + anthropolgist + anthropologist + anthropolgy + anthropology + anual + annual + anulled + annulled + anwsered + answered + anyhwere + anywhere + anyother + any other + anytying + anything + aparent + apparent + aparment + apartment + apenines + apennines + aplication + application + aplied + applied + apolegetics + apologetics + apon + apron + apparant + apparent + apparantly + apparently + appart + apart + appartment + apartment + appartments + apartments + appealling + appealing + appeareance + appearance + appearence + appearance + appearences + appearances + apperance + appearance + apperances + appearances + appereance + appearance + appereances + appearances + applicaiton + application + applicaitons + applications + appologies + apologies + appology + apology + apprearance + appearance + apprieciate + appreciate + approachs + approaches + appropiate + appropriate + appropraite + appropriate + appropropiate + appropriate + approproximate + approximate + approxamately + approximately + approxiately + approximately + approximitely + approximately + aprehensive + apprehensive + apropriate + appropriate + aproximate + approximate + aproximately + approximately + aquaduct + aqueduct + aquaintance + acquaintance + aquainted + acquainted + aquiantance + acquaintance + aquire + acquire + aquired + acquired + aquiring + acquiring + aquisition + acquisition + aquitted + acquitted + aranged + arranged + arangement + arrangement + arbitarily + arbitrarily + arbitary + arbitrary + archaelogists + archaeologists + archaelogy + archaeology + archaoelogy + archaeology + archaology + archaeology + archeaologist + archaeologist + archeaologists + archaeologists + archetect + architect + archetects + architects + archetectural + architectural + archetecturally + architecturally + archetecture + architecture + archiac + archaic + archictect + architect + archimedian + archimedean + architecht + architect + architechturally + architecturally + architechture + architecture + architechtures + architectures + architectual + architectural + archtype + archetype + archtypes + archetypes + aready + already + areodynamics + aerodynamics + argubly + arguably + arguement + argument + arguements + arguments + arised + arose + arival + arrival + armamant + armament + armistace + armistice + arogant + arrogant + arogent + arrogant + aroud + around + arrangment + arrangement + arrangments + arrangements + arround + around + artical + article + artice + article + articel + article + artifical + artificial + artifically + artificially + artillary + artillery + arund + around + asetic + ascetic + asfar + as far + asign + assign + aslo + also + asociated + associated + asorbed + absorbed + asphyxation + asphyxiation + assasin + assassin + assasinate + assassinate + assasinated + assassinated + assasinates + assassinates + assasination + assassination + assasinations + assassinations + assasined + assassinated + assasins + assassins + assassintation + assassination + assemple + assemble + assertation + assertion + asside + aside + assisnate + assassinate + assit + assist + assitant + assistant + assocation + association + assoicate + associate + assoicated + associated + assoicates + associates + assosication + assassination + asssassans + assassins + assualt + assault + assualted + assaulted + assymetric + asymmetric + assymetrical + asymmetrical + asteriod + asteroid + asthetic + aesthetic + asthetical + aesthetical + asthetically + aesthetically + asume + assume + aswell + as well + atain + attain + atempting + attempting + atheistical + atheistic + athenean + athenian + atheneans + athenians + athiesm + atheism + athiest + atheist + atorney + attorney + atribute + attribute + atributed + attributed + atributes + attributes + attaindre + attainder + attemp + attempt + attemped + attempted + attemt + attempt + attemted + attempted + attemting + attempting + attemts + attempts + attendence + attendance + attendent + attendant + attendents + attendants + attened + attended + attension + attention + attitide + attitude + attributred + attributed + attrocities + atrocities + audeince + audience + auromated + automated + austrailia + Australia + austrailian + Australian + auther + author + authobiographic + autobiographic + authobiography + autobiography + authorative + authoritative + authorites + authorities + authorithy + authority + authoritiers + authorities + authoritive + authoritative + authrorities + authorities + autochtonous + autochthonous + autoctonous + autochthonous + automaticly + automatically + automibile + automobile + automonomous + autonomous + autor + author + autority + authority + auxilary + auxiliary + auxillaries + auxiliaries + auxillary + auxiliary + auxilliaries + auxiliaries + auxilliary + auxiliary + availabe + available + availablity + availability + availaible + available + availble + available + availiable + available + availible + available + avalable + available + avalance + avalanche + avaliable + available + avation + aviation + avengence + a vengeance + averageed + averaged + avilable + available + awared + awarded + awya + away + baceause + because + backgorund + background + backrounds + backgrounds + bakc + back + banannas + bananas + bandwith + bandwidth + bankrupcy + bankruptcy + banruptcy + bankruptcy + baout + about + basicaly + basically + basicly + basically + bcak + back + beachead + beachhead + beacuse + because + beastiality + bestiality + beatiful + beautiful + beaurocracy + bureaucracy + beaurocratic + bureaucratic + beautyfull + beautiful + becamae + became + becames + becomes + becasue + because + beccause + because + becomeing + becoming + becomming + becoming + becouse + because + becuase + because + bedore + before + befoer + before + beggin + begin + begginer + beginner + begginers + beginners + beggining + beginning + begginings + beginnings + beggins + begins + begining + beginning + beginnig + beginning + behavour + behavior + beleagured + beleaguered + beleif + belief + beleive + believe + beleived + believed + beleives + believes + beleiving + believing + beligum + belgium + belive + believe + belived + believed + belives + believes + belligerant + belligerent + bellweather + bellwether + bemusemnt + bemusement + beneficary + beneficiary + beng + being + benificial + beneficial + benifit + benefit + benifits + benefits + bergamont + bergamot + beseige + besiege + beseiged + besieged + beseiging + besieging + betwen + between + beween + between + bewteen + between + bilateraly + bilaterally + billingualism + bilingualism + binominal + binomial + bizzare + bizarre + blaim + blame + blaimed + blamed + blessure + blessing + bodydbuilder + bodybuilder + bombardement + bombardment + bombarment + bombardment + bondary + boundary + borke + broke + boundry + boundary + bouyancy + buoyancy + bouyant + buoyant + boyant + buoyant + breakthough + breakthrough + breakthroughts + breakthroughs + breif + brief + breifly + briefly + brethen + brethren + bretheren + brethren + briliant + brilliant + brillant + brilliant + brimestone + brimstone + broacasted + broadcast + broadacasting + broadcasting + broady + broadly + buisness + business + buisnessman + businessman + buoancy + buoyancy + burried + buried + busineses + businesses + busness + business + bussiness + business + caculater + calculator + cacuses + caucuses + cahracters + characters + calaber + caliber + calculater + calculator + calculs + calculus + calenders + calendars + caligraphy + calligraphy + caluclate + calculate + caluclated + calculated + caluculate + calculate + caluculated + calculated + calulate + calculate + calulated + calculated + calulater + calculator + camoflage + camouflage + campain + campaign + campains + campaigns + candadate + candidate + candiate + candidate + candidiate + candidate + cannister + canister + cannisters + canisters + cannnot + cannot + cannonical + canonical + cannotation + connotation + cannotations + connotations + cant + can't + caost + coast + caperbility + capability + capible + capable + captial + capital + captued + captured + capturd + captured + carachter + character + caracterized + characterized + carcas + carcass + carefull + careful + careing + caring + carismatic + charismatic + carnege + carnage + carnige + carnage + carniverous + carnivorous + carreer + career + carrers + careers + cartdridge + cartridge + carthographer + cartographer + cartilege + cartilage + cartilidge + cartilage + cartrige + cartridge + casette + cassette + casion + caisson + cassawory + cassowary + cassowarry + cassowary + casulaties + casualties + casulaty + casualty + catagories + categories + catagorized + categorized + catagory + category + catapillar + caterpillar + catapillars + caterpillars + catapiller + caterpillar + catapillers + caterpillars + catepillar + caterpillar + catepillars + caterpillars + catergorize + categorize + catergorized + categorized + caterpilar + caterpillar + caterpilars + caterpillars + caterpiller + caterpillar + caterpillers + caterpillars + cathlic + catholic + catholocism + catholicism + catterpilar + caterpillar + catterpilars + caterpillars + catterpillar + caterpillar + catterpillars + caterpillars + cattleship + battleship + causalities + casualties + cellpading + cellpadding + cementary + cemetery + cemetarey + cemetery + cemetaries + cemeteries + cemetary + cemetery + cencus + census + censur + censor + cententenial + centennial + centruies + centuries + centruy + century + ceratin + certain + cerimonial + ceremonial + cerimonies + ceremonies + cerimonious + ceremonious + cerimony + ceremony + ceromony + ceremony + certainity + certainty + certian + certain + chalenging + challenging + challange + challenge + challanged + challenged + challege + challenge + changable + changeable + charachter + character + charachters + characters + charactersistic + characteristic + charactor + character + charactors + characters + charasmatic + charismatic + charaterized + characterized + chariman + chairman + charistics + characteristics + cheif + chief + cheifs + chiefs + chemcial + chemical + chemcially + chemically + chemestry + chemistry + chemicaly + chemically + childbird + childbirth + childen + children + choosen + chosen + chracter + character + chuch + church + churchs + churches + circulaton + circulation + circumsicion + circumcision + circut + circuit + ciricuit + circuit + ciriculum + curriculum + civillian + civilian + claer + clear + claerer + clearer + claerly + clearly + claimes + claims + clas + class + clasic + classic + clasical + classical + clasically + classically + cleareance + clearance + clera + clear + clincial + clinical + clinicaly + clinically + cmo + com + cmoputer + computer + co-incided + coincided + coctail + cocktail + coform + conform + cognizent + cognizant + coincedentally + coincidentally + colaborations + collaborations + colateral + collateral + colelctive + collective + collaberative + collaborative + collecton + collection + collegue + colleague + collegues + colleagues + collonade + colonnade + collonies + colonies + collony + colony + collosal + colossal + colonizators + colonizers + comander + commander + comando + commando + comandos + commandos + comany + company + comapany + company + comback + comeback + combanations + combinations + combinatins + combinations + combusion + combustion + comdemnation + condemnation + comemmorates + commemorates + comemoretion + commemoration + comision + commission + comisioned + commissioned + comisioner + commissioner + comisioning + commissioning + comisions + commissions + comission + commission + comissioned + commissioned + comissioner + commissioner + comissioning + commissioning + comissions + commissions + comited + committed + comiting + committing + comitted + committed + comittee + committee + comitting + committing + commandoes + commandos + commedic + comedic + commemerative + commemorative + commemmorate + commemorate + commemmorating + commemorating + commerical + commercial + commerically + commercially + commericial + commercial + commericially + commercially + commerorative + commemorative + comming + coming + comminication + communication + commision + commission + commisioned + commissioned + commisioner + commissioner + commisioning + commissioning + commisions + commissions + commited + committed + commitee + committee + commiting + committing + committe + committee + committment + commitment + committments + commitments + commmemorated + commemorated + commongly + commonly + commonweath + commonwealth + commuications + communications + commuinications + communications + communciation + communication + communiation + communication + communites + communities + compability + compatibility + comparision + comparison + comparisions + comparisons + comparitive + comparative + comparitively + comparatively + compatabilities + compatibilities + compatability + compatibility + compatable + compatible + compatablities + compatibilities + compatablity + compatibility + compatiable + compatible + compatiblities + compatibilities + compatiblity + compatibility + compeitions + competitions + compensantion + compensation + competance + competence + competant + competent + competative + competitive + competion + competition + competitiion + competition + competive + competitive + competiveness + competitiveness + comphrehensive + comprehensive + compitent + competent + completedthe + completed the + completelyl + completely + completetion + completion + complier + compiler + componant + component + comprable + comparable + comprimise + compromise + compulsary + compulsory + compulsery + compulsory + computarized + computerized + concensus + consensus + concider + consider + concidered + considered + concidering + considering + conciders + considers + concieted + conceited + concieved + conceived + concious + conscious + conciously + consciously + conciousness + consciousness + condamned + condemned + condemmed + condemned + condidtion + condition + condidtions + conditions + conditionsof + conditions of + conected + connected + conection + connection + conesencus + consensus + confidental + confidential + confidentally + confidentially + confids + confides + configureable + configurable + confortable + comfortable + congradulations + congratulations + congresional + congressional + conived + connived + conjecutre + conjecture + conjuction + conjunction + conotations + connotations + conquerd + conquered + conquerer + conqueror + conquerers + conquerors + conqured + conquered + conscent + consent + consciouness + consciousness + consdider + consider + consdidered + considered + consdiered + considered + consectutive + consecutive + consenquently + consequently + consentrate + concentrate + consentrated + concentrated + consentrates + concentrates + consept + concept + consequentually + consequently + consequeseces + consequences + consern + concern + conserned + concerned + conserning + concerning + conservitive + conservative + consiciousness + consciousness + consicousness + consciousness + considerd + considered + consideres + considered + consious + conscious + consistant + consistent + consistantly + consistently + consituencies + constituencies + consituency + constituency + consituted + constituted + consitution + constitution + consitutional + constitutional + consolodate + consolidate + consolodated + consolidated + consonent + consonant + consonents + consonants + consorcium + consortium + conspiracys + conspiracies + conspiriator + conspirator + constaints + constraints + constanly + constantly + constarnation + consternation + constatn + constant + constinually + continually + constituant + constituent + constituants + constituents + constituion + constitution + constituional + constitutional + consttruction + construction + constuction + construction + consulant + consultant + consumate + consummate + consumated + consummated + contaiminate + contaminate + containes + contains + contamporaries + contemporaries + contamporary + contemporary + contempoary + contemporary + contemporaneus + contemporaneous + contempory + contemporary + contendor + contender + contibute + contribute + contibuted + contributed + contibutes + contributes + contigent + contingent + contined + continued + continous + continuous + continously + continuously + continueing + continuing + contravercial + controversial + contraversy + controversy + contributer + contributor + contributers + contributors + contritutions + contributions + controled + controlled + controling + controlling + controll + control + controlls + controls + controvercial + controversial + controvercy + controversy + controveries + controversies + controversal + controversial + controversey + controversy + controvertial + controversial + controvery + controversy + contruction + construction + conveinent + convenient + convenant + covenant + convential + conventional + convertables + convertibles + convertion + conversion + conveyer + conveyor + conviced + convinced + convienient + convenient + coordiantion + coordination + coorperations + corporations + copmetitors + competitors + coputer + computer + copywrite + copyright + coridal + cordial + cornmitted + committed + corosion + corrosion + corparate + corporate + corperations + corporations + correcters + correctors + correponding + corresponding + correposding + corresponding + correspondant + correspondent + correspondants + correspondents + corridoors + corridors + corrispond + correspond + corrispondant + correspondent + corrispondants + correspondents + corrisponded + corresponded + corrisponding + corresponding + corrisponds + corresponds + costitution + constitution + coucil + council + counries + countries + countains + contains + countires + countries + coururier + courier + coverted + converted + cpoy + copy + creaeted + created + creedence + credence + critereon + criterion + criterias + criteria + criticists + critics + critising + criticising + critisising + criticising + critisism + criticism + critisisms + criticisms + critisize + criticise + critisized + criticised + critisizes + criticises + critisizing + criticising + critized + criticized + critizing + criticizing + crockodiles + crocodiles + crowm + crown + crtical + critical + crticised + criticised + crucifiction + crucifixion + crusies + cruises + crystalisation + crystallisation + culiminating + culminating + cumulatative + cumulative + curch + church + curcuit + circuit + currenly + currently + curriculem + curriculum + cxan + cyan + cyclinder + cylinder + dacquiri + daiquiri + dael + deal + dalmation + dalmatian + damenor + demeanor + dammage + damage + daugher + daughter + debateable + debatable + decendant + descendant + decendants + descendants + decendent + descendant + decendents + descendants + decideable + decidable + decidely + decidedly + decieved + deceived + decison + decision + decomissioned + decommissioned + decomposit + decompose + decomposited + decomposed + decompositing + decomposing + decomposits + decomposes + decress + decrees + decribe + describe + decribed + described + decribes + describes + decribing + describing + dectect + detect + defendent + defendant + defendents + defendants + deffensively + defensively + deffine + define + deffined + defined + definance + defiance + definate + definite + definately + definitely + definatly + definitely + definetly + definitely + definining + defining + definit + definite + definitly + definitely + definiton + definition + defintion + definition + degrate + degrade + delagates + delegates + delapidated + dilapidated + delerious + delirious + delevopment + development + deliberatly + deliberately + delusionally + delusively + demenor + demeanor + demographical + demographic + demolision + demolition + demorcracy + democracy + demostration + demonstration + denegrating + denigrating + densly + densely + deparment + department + deparmental + departmental + deparments + departments + dependance + dependence + dependancy + dependency + dependant + dependent + deram + dream + deriviated + derived + derivitive + derivative + derogitory + derogatory + descendands + descendants + descibed + described + descision + decision + descisions + decisions + descriibes + describes + descripters + descriptors + descripton + description + desctruction + destruction + descuss + discuss + desgined + designed + deside + decide + desigining + designing + desinations + destinations + desintegrated + disintegrated + desintegration + disintegration + desireable + desirable + desitned + destined + desktiop + desktop + desorder + disorder + desoriented + disoriented + desparate + desperate + despict + depict + despiration + desperation + dessicated + desiccated + dessigned + designed + destablized + destabilized + destory + destroy + detailled + detailed + detatched + detached + deteoriated + deteriorated + deteriate + deteriorate + deterioriating + deteriorating + determinining + determining + detremental + detrimental + devasted + devastated + develope + develop + developement + development + developped + developed + develpment + development + devels + delves + devestated + devastated + devestating + devastating + devide + divide + devided + divided + devistating + devastating + devolopement + development + diablical + diabolical + diamons + diamonds + diaster + disaster + dichtomy + dichotomy + diconnects + disconnects + dicover + discover + dicovered + discovered + dicovering + discovering + dicovers + discovers + dicovery + discovery + dicussed + discussed + didnt + didn't + diea + idea + dieing + dying + dieties + deities + diety + deity + diferent + different + diferrent + different + differentiatiations + differentiations + differnt + different + difficulity + difficulty + diffrent + different + dificulties + difficulties + dificulty + difficulty + dimenions + dimensions + dimention + dimension + dimentional + dimensional + dimentions + dimensions + dimesnional + dimensional + diminuitive + diminutive + dimunitive + diminutive + diosese + diocese + diphtong + diphthong + diphtongs + diphthongs + diplomancy + diplomacy + dipthong + diphthong + dipthongs + diphthongs + dirived + derived + disagreeed + disagreed + disapeared + disappeared + disapointing + disappointing + disappearred + disappeared + disaproval + disapproval + disasterous + disastrous + disatisfaction + dissatisfaction + disatisfied + dissatisfied + disatrous + disastrous + discontentment + discontent + discribe + describe + discribed + described + discribes + describes + discribing + describing + disctinction + distinction + disctinctive + distinctive + disemination + dissemination + disenchanged + disenchanted + disiplined + disciplined + disobediance + disobedience + disobediant + disobedient + disolved + dissolved + disover + discover + dispair + despair + disparingly + disparagingly + dispence + dispense + dispenced + dispensed + dispencing + dispensing + dispicable + despicable + dispite + despite + dispostion + disposition + disproportiate + disproportionate + disputandem + disputandum + disricts + districts + dissagreement + disagreement + dissapear + disappear + dissapearance + disappearance + dissapeared + disappeared + dissapearing + disappearing + dissapears + disappears + dissappear + disappear + dissappears + disappears + dissappointed + disappointed + dissarray + disarray + dissobediance + disobedience + dissobediant + disobedient + dissobedience + disobedience + dissobedient + disobedient + distiction + distinction + distingish + distinguish + distingished + distinguished + distingishes + distinguishes + distingishing + distinguishing + distingquished + distinguished + distrubution + distribution + distruction + destruction + distructive + destructive + ditributed + distributed + diversed + diverged + divice + device + divison + division + divisons + divisions + doccument + document + doccumented + documented + doccuments + documents + docrines + doctrines + doctines + doctrines + documenatry + documentary + doens + does + doesnt + doesn't + doign + doing + dominaton + domination + dominent + dominant + dominiant + dominant + donig + doing + dont + don't + dosen't + doesn't + doub + doubt + doulbe + double + dowloads + downloads + dramtic + dramatic + draughtman + draughtsman + dreasm + dreams + driectly + directly + drnik + drink + druming + drumming + drummless + drumless + dupicate + duplicate + durig + during + durring + during + duting + during + dyas + dryas + eahc + each + ealier + earlier + earlies + earliest + earnt + earned + ecclectic + eclectic + eceonomy + economy + ecidious + deciduous + eclispe + eclipse + ecomonic + economic + ect + etc + eearly + early + efel + evil + effeciency + efficiency + effecient + efficient + effeciently + efficiently + efficency + efficiency + efficent + efficient + efficently + efficiently + efford + effort + effords + efforts + effulence + effluence + eigth + eight + eiter + either + elction + election + electic + electric + electon + electron + electrial + electrical + electricly + electrically + electricty + electricity + elementay + elementary + eleminated + eliminated + eleminating + eliminating + eles + eels + eletricity + electricity + elicided + elicited + eligable + eligible + elimentary + elementary + ellected + elected + elphant + elephant + embarass + embarrass + embarassed + embarrassed + embarassing + embarrassing + embarassment + embarrassment + embargos + embargoes + embarras + embarrass + embarrased + embarrassed + embarrasing + embarrassing + embarrasment + embarrassment + embezelled + embezzled + emblamatic + emblematic + eminate + emanate + eminated + emanated + emision + emission + emited + emitted + emiting + emitting + emition + emission + emmediately + immediately + emmigrated + immigrated + emminently + eminently + emmisaries + emissaries + emmisarries + emissaries + emmisarry + emissary + emmisary + emissary + emmision + emission + emmisions + emissions + emmited + emitted + emmiting + emitting + emmitted + emitted + emmitting + emitting + emnity + enmity + emperical + empirical + emphaised + emphasised + emphsis + emphasis + emphysyma + emphysema + emprisoned + imprisoned + enameld + enameled + enchancement + enhancement + encouraing + encouraging + encryptiion + encryption + encylopedia + encyclopedia + endevors + endeavors + endevour + endeavour + endig + ending + endolithes + endoliths + enduce + induce + ened + need + enflamed + inflamed + enforceing + enforcing + engagment + engagement + engeneer + engineer + engeneering + engineering + engieneer + engineer + engieneers + engineers + enlargment + enlargement + enlargments + enlargements + enourmous + enormous + enourmously + enormously + ensconsed + ensconced + entaglements + entanglements + enteratinment + entertainment + enthusiatic + enthusiastic + entitity + entity + entitlied + entitled + entrepeneur + entrepreneur + entrepeneurs + entrepreneurs + enviorment + environment + enviormental + environmental + enviormentally + environmentally + enviorments + environments + enviornment + environment + enviornmental + environmental + enviornmentalist + environmentalist + enviornmentally + environmentally + enviornments + environments + enviroment + environment + enviromental + environmental + enviromentalist + environmentalist + enviromentally + environmentally + enviroments + environments + envolutionary + evolutionary + envrionments + environments + enxt + next + epidsodes + episodes + epsiode + episode + equialent + equivalent + equilibium + equilibrium + equilibrum + equilibrium + equiped + equipped + equippment + equipment + equitorial + equatorial + equivelant + equivalent + equivelent + equivalent + equivilant + equivalent + equivilent + equivalent + equivlalent + equivalent + erally + really + eratic + erratic + eratically + erratically + eraticly + erratically + errupted + erupted + esential + essential + esitmated + estimated + esle + else + especialy + especially + essencial + essential + essense + essence + essentail + essential + essentialy + essentially + essentual + essential + essesital + essential + estabishes + establishes + establising + establishing + ethnocentricm + ethnocentrism + ethose + those + evenhtually + eventually + eventally + eventually + eventhough + even though + eventially + eventually + eventualy + eventually + everthing + everything + everytime + every time + everyting + everything + eveyr + every + evidentally + evidently + exagerate + exaggerate + exagerated + exaggerated + exagerates + exaggerates + exagerating + exaggerating + exagerrate + exaggerate + exagerrated + exaggerated + exagerrates + exaggerates + exagerrating + exaggerating + examinated + examined + exampt + exempt + exapansion + expansion + excact + exact + excange + exchange + excecute + execute + excecuted + executed + excecutes + executes + excecuting + executing + excecution + execution + excedded + exceeded + excelent + excellent + excell + excel + excellance + excellence + excellant + excellent + excells + excels + excercise + exercise + exchanching + exchanging + excisted + existed + exculsivly + exclusively + execising + exercising + exection + execution + exectued + executed + exeedingly + exceedingly + exelent + excellent + exellent + excellent + exemple + example + exept + except + exeptional + exceptional + exerbate + exacerbate + exerbated + exacerbated + exerciese + exercises + exerpt + excerpt + exerpts + excerpts + exersize + exercise + exerternal + external + exhalted + exalted + exhibtion + exhibition + exibition + exhibition + exibitions + exhibitions + exicting + exciting + exinct + extinct + existance + existence + existant + existent + existince + existence + exliled + exiled + exludes + excludes + exmaple + example + exonorate + exonerate + exoskelaton + exoskeleton + expalin + explain + expatriot + expatriate + expeced + expected + expecially + especially + expeditonary + expeditionary + expeiments + experiments + expell + expel + expells + expels + experiance + experience + experianced + experienced + expiditions + expeditions + expierence + experience + explaination + explanation + explaning + explaining + explictly + explicitly + exploititive + exploitative + explotation + exploitation + expropiated + expropriated + expropiation + expropriation + exressed + expressed + extemely + extremely + extention + extension + extentions + extensions + extered + exerted + extermist + extremist + extint + extinct + extradiction + extradition + extraterrestial + extraterrestrial + extraterrestials + extraterrestrials + extravagent + extravagant + extrememly + extremely + extremeophile + extremophile + extremly + extremely + extrordinarily + extraordinarily + extrordinary + extraordinary + eyar + year + eyars + years + eyasr + years + faciliate + facilitate + faciliated + facilitated + faciliates + facilitates + facilites + facilities + facillitate + facilitate + facinated + fascinated + facist + fascist + familes + families + familliar + familiar + famoust + famous + fanatism + fanaticism + fatc + fact + faught + fought + favoutrable + favourable + feasable + feasible + fedreally + federally + feromone + pheromone + fertily + fertility + fianite + finite + fianlly + finally + ficticious + fictitious + fictious + fictitious + fidn + find + fiercly + fiercely + fightings + fighting + filiament + filament + fimilies + families + finacial + financial + finaly + finally + financialy + financially + firends + friends + firts + first + fisionable + fissionable + flamable + flammable + flawess + flawless + fleed + fled + florescent + fluorescent + flourescent + fluorescent + flourine + fluorine + fluorish + flourish + follwoing + following + folowing + following + fomed + formed + fomr + from + fonetic + phonetic + fontrier + fontier + foootball + football + forbad + forbade + forbiden + forbidden + foreward + foreword + forfiet + forfeit + forhead + forehead + foriegn + foreign + formallize + formalize + formallized + formalized + formaly + formally + formelly + formerly + formidible + formidable + formost + foremost + forsaw + foresaw + forseeable + foreseeable + fortelling + foretelling + forunner + forerunner + foucs + focus + foudn + found + fougth + fought + foundaries + foundries + foundary + foundry + fourties + forties + fourty + forty + fouth + fourth + foward + forward + freind + friend + freindly + friendly + frequentily + frequently + frome + from + fromed + formed + froniter + frontier + fucntion + function + fucntioning + functioning + fufill + fulfill + fufilled + fulfilled + fulfiled + fulfilled + fullfill + fulfill + fullfilled + fulfilled + fundametal + fundamental + fundametals + fundamentals + funguses + fungi + funtion + function + furuther + further + futher + further + futhermore + furthermore + galatic + galactic + gallaxies + galaxies + galvinized + galvanized + ganerate + generate + ganes + games + ganster + gangster + garantee + guarantee + garanteed + guaranteed + garantees + guarantees + garnison + garrison + gaurantee + guarantee + gauranteed + guaranteed + gaurantees + guarantees + gaurd + guard + gaurentee + guarantee + gaurenteed + guaranteed + gaurentees + guarantees + geneological + genealogical + geneologies + genealogies + geneology + genealogy + generaly + generally + generatting + generating + genialia + genitalia + geographicial + geographical + geometrician + geometer + geometricians + geometers + gerat + great + glight + flight + gnawwed + gnawed + godess + goddess + godesses + goddesses + gogin + going + goign + going + gonig + going + gouvener + governor + govement + government + govenment + government + govenrment + government + goverance + governance + goverment + government + govermental + governmental + governer + governor + governmnet + government + govorment + government + govormental + governmental + govornment + government + gracefull + graceful + graet + great + grafitti + graffiti + gramatically + grammatically + grammaticaly + grammatically + grammer + grammar + grat + great + gratuitious + gratuitous + greatful + grateful + greatfully + gratefully + greif + grief + gridles + griddles + gropu + group + grwo + grow + guage + gauge + guarentee + guarantee + guarenteed + guaranteed + guarentees + guarantees + guerilla + guerrilla + guerillas + guerrillas + guerrila + guerrilla + guerrilas + guerrillas + guidence + guidance + gunanine + guanine + gurantee + guarantee + guranteed + guaranteed + gurantees + guarantees + guttaral + guttural + gutteral + guttural + habaeus + habeas + habeus + habeas + haemorrage + haemorrhage + haev + have + halp + help + hapen + happen + hapened + happened + hapening + happening + happend + happened + happended + happened + happenned + happened + harased + harassed + harases + harasses + harasment + harassment + harasments + harassments + harassement + harassment + harras + harass + harrased + harassed + harrases + harasses + harrasing + harassing + harrasment + harassment + harrasments + harassments + harrassed + harassed + harrasses + harassed + harrassing + harassing + harrassment + harassment + harrassments + harassments + hasnt + hasn't + haviest + heaviest + headquarer + headquarter + headquater + headquarter + headquatered + headquartered + headquaters + headquarters + healthercare + healthcare + heared + heard + heathy + healthy + heigher + higher + heirarchy + hierarchy + heiroglyphics + hieroglyphics + helment + helmet + helpfull + helpful + helpped + helped + hemmorhage + hemorrhage + herad + heard + heridity + heredity + heroe + hero + heros + heroes + hertiage + heritage + hertzs + hertz + hesistant + hesitant + heterogenous + heterogeneous + hieght + height + hierachical + hierarchical + hierachies + hierarchies + hierachy + hierarchy + hierarcical + hierarchical + hierarcy + hierarchy + hieroglph + hieroglyph + hieroglphs + hieroglyphs + higer + higher + higest + highest + higway + highway + hillarious + hilarious + himselv + himself + hinderance + hindrance + hinderence + hindrance + hindrence + hindrance + hipopotamus + hippopotamus + hismelf + himself + histocompatability + histocompatibility + historicians + historians + hitsingles + hit singles + holliday + holiday + homestate + home state + homogeneize + homogenize + homogeneized + homogenized + honory + honorary + horrifing + horrifying + hosited + hoisted + hospitible + hospitable + hounour + honour + housr + hours + howver + however + hsitorians + historians + hstory + history + hten + then + htere + there + htey + they + htikn + think + hting + thing + htink + think + htis + this + humer + humor + humerous + humorous + huminoid + humanoid + humoural + humoral + humurous + humorous + husban + husband + hvae + have + hvaing + having + hvea + have + hwihc + which + hwile + while + hwole + whole + hydogen + hydrogen + hydropile + hydrophile + hydropilic + hydrophilic + hydropobe + hydrophobe + hydropobic + hydrophobic + hygeine + hygiene + hypocracy + hypocrisy + hypocrasy + hypocrisy + hypocricy + hypocrisy + hypocrit + hypocrite + hypocrits + hypocrites + i + I + iconclastic + iconoclastic + idaeidae + idea + idaes + ideas + idealogies + ideologies + idealogy + ideology + identicial + identical + identifers + identifiers + ideosyncratic + idiosyncratic + idesa + ideas + idiosyncracy + idiosyncrasy + illegimacy + illegitimacy + illegitmate + illegitimate + illess + illness + illiegal + illegal + illution + illusion + ilness + illness + ilogical + illogical + imagenary + imaginary + imagin + imagine + imaginery + imaginary + imcomplete + incomplete + imediately + immediately + imense + immense + immediatley + immediately + immediatly + immediately + immidately + immediately + immidiately + immediately + immitate + imitate + immitated + imitated + immitating + imitating + immitator + imitator + immunosupressant + immunosuppressant + impecabbly + impeccably + impedence + impedance + implamenting + implementing + impliment + implement + implimented + implemented + imploys + employs + importamt + important + imprioned + imprisoned + imprisonned + imprisoned + improvision + improvisation + improvments + improvements + inablility + inability + inaccessable + inaccessible + inadiquate + inadequate + inadquate + inadequate + inadvertant + inadvertent + inadvertantly + inadvertently + inagurated + inaugurated + inaguration + inauguration + inappropiate + inappropriate + inaugures + inaugurates + inbalance + imbalance + inbalanced + imbalanced + inbetween + between + incarcirated + incarcerated + incidentially + incidentally + incidently + incidentally + inclreased + increased + includ + include + includng + including + incompatabilities + incompatibilities + incompatability + incompatibility + incompatable + incompatible + incompatablities + incompatibilities + incompatablity + incompatibility + incompatiblities + incompatibilities + incompatiblity + incompatibility + incompetance + incompetence + incompetant + incompetent + incomptable + incompatible + incomptetent + incompetent + inconsistant + inconsistent + incoroporated + incorporated + incorperation + incorporation + incorportaed + incorporated + incorprates + incorporates + incorruptable + incorruptible + incramentally + incrementally + increadible + incredible + incredable + incredible + inctroduce + introduce + inctroduced + introduced + incuding + including + incunabla + incunabula + indefinately + indefinitely + indefineable + undefinable + indefinitly + indefinitely + indentical + identical + indepedantly + independently + indepedence + independence + independance + independence + independant + independent + independantly + independently + independece + independence + independendet + independent + indespensable + indispensable + indespensible + indispensable + indictement + indictment + indigineous + indigenous + indipendence + independence + indipendent + independent + indipendently + independently + indispensible + indispensable + indisputible + indisputable + indisputibly + indisputably + indite + indict + individualy + individually + indpendent + independent + indpendently + independently + indulgue + indulge + indutrial + industrial + indviduals + individuals + inefficienty + inefficiently + inevatible + inevitable + inevitible + inevitable + inevititably + inevitably + infalability + infallibility + infallable + infallible + infectuous + infectious + infered + inferred + infilitrate + infiltrate + infilitrated + infiltrated + infilitration + infiltration + infinit + infinite + inflamation + inflammation + influencial + influential + influented + influenced + infomation + information + informtion + information + infrantryman + infantryman + infrigement + infringement + ingenius + ingenious + ingreediants + ingredients + inhabitans + inhabitants + inherantly + inherently + inheritence + inheritance + inital + initial + initally + initially + initation + initiation + initiaitive + initiative + inlcuding + including + inmigrant + immigrant + inmigrants + immigrants + innoculated + inoculated + inocence + innocence + inofficial + unofficial + inot + into + inpeach + impeach + inpolite + impolite + inprisonment + imprisonment + inproving + improving + insectiverous + insectivorous + insensative + insensitive + inseperable + inseparable + insistance + insistence + insitution + institution + insitutions + institutions + inspite + in spite + instade + instead + instatance + instance + institue + institute + instuction + instruction + instuments + instruments + instutionalized + institutionalized + instutions + intuitions + insurence + insurance + intelectual + intellectual + inteligence + intelligence + inteligent + intelligent + intenational + international + intented + intended + intepretation + interpretation + intepretator + interpretor + interational + international + interbread + interbreed + interchangable + interchangeable + interchangably + interchangeably + intercontinetal + intercontinental + intered + interred + interelated + interrelated + interferance + interference + interfereing + interfering + intergrated + integrated + intergration + integration + interm + interim + internation + international + interpet + interpret + interrim + interim + interrugum + interregnum + intertaining + entertaining + interupt + interrupt + intervines + intervenes + intevene + intervene + intial + initial + intially + initially + intrduced + introduced + intrest + interest + introdued + introduced + intruduced + introduced + intrument + instrument + intrumental + instrumental + intruments + instruments + intrusted + entrusted + intutive + intuitive + intutively + intuitively + inudstry + industry + inventer + inventor + invertibrates + invertebrates + investingate + investigate + involvment + involvement + irelevent + irrelevant + iresistable + irresistible + iresistably + irresistibly + iresistible + irresistible + iresistibly + irresistibly + iritable + irritable + iritated + irritated + ironicly + ironically + irregardless + regardless + irrelevent + irrelevant + irreplacable + irreplaceable + irresistable + irresistible + irresistably + irresistibly + isnt + isn't + issueing + issuing + itnroduced + introduced + iunior + junior + iwll + will + iwth + with + jaques + jacques + jeapardy + jeopardy + jewllery + jewellery + jouney + journey + journied + journeyed + journies + journeys + jstu + just + jsut + just + judical + judicial + judisuary + judiciary + juducial + judicial + juristiction + jurisdiction + juristictions + jurisdictions + kindergarden + kindergarten + klenex + kleenex + knifes + knives + knive + knife + knowlege + knowledge + knowlegeable + knowledgeable + knwo + know + knwos + knows + konw + know + konws + knows + kwno + know + labatory + laboratory + labratory + laboratory + laguage + language + laguages + languages + larg + large + largst + largest + larrry + larry + lastr + last + lattitude + latitude + launhed + launched + lavae + larvae + layed + laid + lazyness + laziness + leage + league + leanr + learn + leathal + lethal + lefted + left + legitamate + legitimate + legitmate + legitimate + leibnitz + leibniz + lenght + length + leran + learn + lerans + learns + leutenant + lieutenant + levetate + levitate + levetated + levitated + levetates + levitates + levetating + levitating + levle + level + liasion + liaison + liason + liaison + liasons + liaisons + libary + library + libell + libel + libguistic + linguistic + libguistics + linguistics + libitarianisn + libertarianism + lieing + lying + liek + like + liekd + liked + liesure + leisure + lieuenant + lieutenant + lieved + lived + liftime + lifetime + lightyear + light year + lightyears + light years + likelyhood + likelihood + linnaena + linnaean + lippizaner + lipizzaner + liquify + liquefy + liscense + license + lisence + license + lisense + license + listners + listeners + litature + literature + literaly + literally + literture + literature + littel + little + litterally + literally + liuke + like + livley + lively + lmits + limits + loev + love + lonelyness + loneliness + longitudonal + longitudinal + lonley + lonely + lonly + lonely + loosing + losing + lotharingen + lothringen + lsat + last + lukid + likud + lveo + love + lvoe + love + maching + machine + mackeral + mackerel + magasine + magazine + magincian + magician + magnificient + magnificent + magolia + magnolia + mailny + mainly + maintainance + maintenance + maintainence + maintenance + maintance + maintenance + maintenence + maintenance + maintinaing + maintaining + maintioned + mentioned + majoroty + majority + maked + marked + makse + makes + maltesian + Maltese + mamal + mammal + mamalian + mammalian + managable + manageable + managment + management + maneouvre + manoeuvre + maneouvred + manoeuvred + maneouvres + manoeuvres + maneouvring + manoeuvring + manisfestations + manifestations + manoeuverability + maneuverability + manouver + maneuver + manouverability + maneuverability + manouverable + maneuverable + manouvers + maneuvers + mantained + maintained + manuever + maneuver + manuevers + maneuvers + manufacturedd + manufactured + manufature + manufacture + manufatured + manufactured + manufaturing + manufacturing + manuver + maneuver + mariage + marriage + marjority + majority + markes + marks + marketting + marketing + marmelade + marmalade + marrage + marriage + marraige + marriage + marrtyred + martyred + marryied + married + massmedia + mass media + masterbation + masturbation + mataphysical + metaphysical + materalists + materialist + mathamatics + mathematics + mathematican + mathematician + mathematicas + mathematics + matheticians + mathematicians + mathmatically + mathematically + mathmatician + mathematician + mathmaticians + mathematicians + mccarthyst + mccarthyist + mchanics + mechanics + meaninng + meaning + mear + wear + mechandise + merchandise + medacine + medicine + medeival + medieval + medevial + medieval + mediciney + mediciny + medievel + medieval + mediterainnean + mediterranean + meerkrat + meerkat + melieux + milieux + membranaphone + membranophone + memeber + member + menally + mentally + meranda + Miranda + mercentile + mercantile + messanger + messenger + messenging + messaging + metalic + metallic + metalurgic + metallurgic + metalurgical + metallurgical + metalurgy + metallurgy + metamorphysis + metamorphosis + metaphoricial + metaphorical + meterologist + meteorologist + meterology + meteorology + methaphor + metaphor + methaphors + metaphors + micoscopy + microscopy + midwifes + midwives + mileau + milieu + milennia + millennia + milennium + millennium + mileu + milieu + miliary + military + milion + million + miliraty + military + millenia + millennia + millenial + millennial + millenialism + millennialism + millenium + millennium + millepede + millipede + millioniare + millionaire + millitary + military + millon + million + miltary + military + minature + miniature + minerial + mineral + miniscule + minuscule + ministery + ministry + minstries + ministries + minstry + ministry + minumum + minimum + mirrorred + mirrored + miscelaneous + miscellaneous + miscellanious + miscellaneous + miscellanous + miscellaneous + mischeivous + mischievous + mischevious + mischievous + mischievious + mischievous + misdameanor + misdemeanor + misdameanors + misdemeanors + misdemenor + misdemeanor + misdemenors + misdemeanors + misfourtunes + misfortunes + misile + missile + mispell + misspell + mispelled + misspelled + mispelling + misspelling + missen + mizzen + missle + missile + missonary + missionary + misterious + mysterious + mistery + mystery + misteryous + mysterious + mkae + make + mkaes + makes + mkaing + making + mkea + make + moderm + modem + modle + model + moent + moment + moeny + money + mohammedans + muslims + moil + soil + moleclues + molecules + momento + memento + monestaries + monasteries + monestary + monastery + monickers + monikers + monolite + monolithic + montains + mountains + montanous + mountainous + monts + months + montypic + monotypic + moreso + more so + morgage + mortgage + morroccan + moroccan + morrocco + morocco + morroco + morocco + mortage + mortgage + mosture + moisture + motiviated + motivated + mounth + month + movei + movie + movment + movement + mroe + more + mucuous + mucous + muder + murder + mudering + murdering + muhammadan + muslim + multicultralism + multiculturalism + multipled + multiplied + multiplers + multipliers + munbers + numbers + muncipalities + municipalities + muncipality + municipality + munnicipality + municipality + muscels + muscles + muscial + musical + muscician + musician + muscicians + musicians + mutiliated + mutilated + myraid + myriad + mysef + myself + mysogynist + misogynist + mysogyny + misogyny + mysterous + mysterious + naieve + naive + naturaly + naturally + naturely + naturally + naturual + natural + naturually + naturally + neccesarily + necessarily + neccesary + necessary + neccessarily + necessarily + neccessary + necessary + neccessities + necessities + necesarily + necessarily + necesary + necessary + necessiate + necessitate + neglible + negligible + negligable + negligible + negociate + negotiate + negociation + negotiation + negociations + negotiations + negotation + negotiation + neice + niece + neigborhood + neighborhood + neigbour + neighbour + neigbourhood + neighbourhood + neolitic + neolithic + nessasarily + necessarily + nessecary + necessary + nestin + nesting + neverthless + nevertheless + newletters + newsletters + nickle + nickel + nightfa;; + nightfall + nightime + nighttime + nineth + ninth + ninteenth + nineteenth + ninties + 1990s + ninty + ninety + nkow + know + nkwo + know + nmae + name + noncombatents + noncombatants + nonsence + nonsense + nontheless + nonetheless + noone + no one + norhern + northern + northen + northern + northereastern + northeastern + notabley + notably + noteable + notable + noteably + notably + noteriety + notoriety + noth + north + nothern + northern + noticable + noticeable + noticably + noticeably + noticeing + noticing + noticible + noticeable + notwhithstanding + notwithstanding + noveau + nouveau + nowdays + nowadays + nowe + now + nto + not + nucular + nuclear + nuculear + nuclear + nuisanse + nuisance + numberous + numerous + nusance + nuisance + nutritent + nutrient + nutritents + nutrients + nuturing + nurturing + obediance + obedience + obediant + obedient + obession + obsession + obssessed + obsessed + obstacal + obstacle + obstancles + obstacles + obstruced + obstructed + ocasion + occasion + ocasional + occasional + ocasionally + occasionally + ocasionaly + occasionally + ocasioned + occasioned + ocasions + occasions + ocassion + occasion + ocassional + occasional + ocassionally + occasionally + ocassionaly + occasionally + ocassioned + occasioned + ocassions + occasions + occaison + occasion + occassion + occasion + occassional + occasional + occassionally + occasionally + occassionaly + occasionally + occassioned + occasioned + occassions + occasions + occationally + occasionally + occour + occur + occurance + occurrence + occurances + occurrences + occured + occurred + occurence + occurrence + occurences + occurrences + occuring + occurring + occurr + occur + occurrance + occurrence + occurrances + occurrences + octohedra + octahedra + octohedral + octahedral + octohedron + octahedron + ocuntries + countries + ocuntry + country + ocurr + occur + ocurrance + occurrence + ocurred + occurred + ocurrence + occurrence + offcers + officers + offcially + officially + offereings + offerings + offical + official + offically + officially + officals + officials + officaly + officially + officialy + officially + offred + offered + oftenly + often + oging + going + omision + omission + omited + omitted + omiting + omitting + omlette + omelette + ommision + omission + ommited + omitted + ommiting + omitting + ommitted + omitted + ommitting + omitting + omniverous + omnivorous + omniverously + omnivorously + omre + more + onot + note + onxy + onyx + onyl + only + openess + openness + oponent + opponent + oportunity + opportunity + opose + oppose + oposite + opposite + oposition + opposition + oppenly + openly + oppinion + opinion + opponant + opponent + oppononent + opponent + oppositition + opposition + oppossed + opposed + opprotunity + opportunity + opression + oppression + opressive + oppressive + opthalmic + ophthalmic + opthalmologist + ophthalmologist + opthalmology + ophthalmology + opthamologist + ophthalmologist + optmizations + optimizations + optomism + optimism + orded + ordered + organim + organism + organistion + organisation + organiztion + organization + orgin + origin + orginal + original + orginally + originally + orginize + organise + oridinarily + ordinarily + origanaly + originally + originall + original + originaly + originally + originially + originally + originnally + originally + origional + original + orignally + originally + orignially + originally + otehr + other + oublisher + publisher + ouevre + oeuvre + oustanding + outstanding + overshaddowed + overshadowed + overthere + over there + overwelming + overwhelming + overwheliming + overwhelming + owrk + work + owudl + would + oxigen + oxygen + oximoron + oxymoron + p0enis + penis + paide + paid + paitience + patience + palce + place + paleolitic + paleolithic + paliamentarian + parliamentarian + pallete + palette + pamflet + pamphlet + pamplet + pamphlet + pantomine + pantomime + paralel + parallel + paralell + parallel + paralelly + parallelly + paralely + parallelly + parallely + parallelly + paranthesis + parenthesis + paraphenalia + paraphernalia + parellels + parallels + parituclar + particular + parliment + parliament + parrakeets + parakeets + parralel + parallel + parrallel + parallel + parrallell + parallel + parrallelly + parallelly + parrallely + parallelly + partialy + partially + particually + particularly + particualr + particular + particuarly + particularly + particularily + particularly + particulary + particularly + pary + party + pased + passed + pasengers + passengers + passerbys + passersby + pasttime + pastime + pastural + pastoral + paticular + particular + pattented + patented + pavillion + pavilion + payed + paid + pblisher + publisher + pbulisher + publisher + peacefuland + peaceful and + peageant + pageant + peculure + peculiar + pedestrain + pedestrian + peformed + performed + peice + piece + penatly + penalty + penerator + penetrator + penisula + peninsula + penisular + peninsular + penninsula + peninsula + penninsular + peninsular + pennisula + peninsula + pensinula + peninsula + peom + poem + peoms + poems + peopel + people + peotry + poetry + perade + parade + percepted + perceived + percieve + perceive + percieved + perceived + perenially + perennially + perfomance + performance + perfomers + performers + performence + performance + performes + performed + perhasp + perhaps + perheaps + perhaps + perhpas + perhaps + peripathetic + peripatetic + peristent + persistent + perjery + perjury + perjorative + pejorative + permanant + permanent + permenant + permanent + permenantly + permanently + permissable + permissible + perogative + prerogative + peronal + personal + perosnality + personality + perphas + perhaps + perpindicular + perpendicular + perseverence + perseverance + persistance + persistence + persistant + persistent + personel + personnel + personell + personnel + personnell + personnel + persuded + persuaded + persue + pursue + persued + pursued + persuing + pursuing + persuit + pursuit + persuits + pursuits + pertubation + perturbation + pertubations + perturbations + pessiary + pessary + petetion + petition + phenomenom + phenomenon + phenomenonal + phenomenal + phenomenonly + phenomenally + phenomonenon + phenomenon + phenomonon + phenomenon + phenonmena + phenomena + philisopher + philosopher + philisophical + philosophical + philisophy + philosophy + phillosophically + philosophically + philospher + philosopher + philosphies + philosophies + philosphy + philosophy + phongraph + phonograph + phylosophical + philosophical + physicaly + physically + piblisher + publisher + pich + pitch + pilgrimmage + pilgrimage + pilgrimmages + pilgrimages + pinapple + pineapple + pinnaple + pineapple + pinoneered + pioneered + plagarism + plagiarism + planation + plantation + planed + planned + plantiff + plaintiff + plateu + plateau + plausable + plausible + playright + playwright + playwrite + playwright + playwrites + playwrights + pleasent + pleasant + plebicite + plebiscite + plesant + pleasant + poenis + penis + poeoples + peoples + poety + poetry + poisin + poison + polical + political + polinator + pollinator + polinators + pollinators + politican + politician + politicans + politicians + poltical + political + polute + pollute + poluted + polluted + polutes + pollutes + poluting + polluting + polution + pollution + polyphonyic + polyphonic + polysaccaride + polysaccharide + polysaccharid + polysaccharide + pomegranite + pomegranate + pomotion + promotion + poportional + proportional + popoulation + population + popularaty + popularity + populare + popular + populer + popular + portait + portrait + portayed + portrayed + portraing + portraying + portuguease + portuguese + portugues + Portuguese + posess + possess + posessed + possessed + posesses + possesses + posessing + possessing + posession + possession + posessions + possessions + posion + poison + positon + position + possable + possible + possably + possibly + posseses + possesses + possesing + possessing + possesion + possession + possessess + possesses + possibile + possible + possibilty + possibility + possiblility + possibility + possiblilty + possibility + possiblities + possibilities + possiblity + possibility + possition + position + posthomous + posthumous + postion + position + postive + positive + potatos + potatoes + potrait + portrait + potrayed + portrayed + poulations + populations + poverful + powerful + poweful + powerful + powerfull + powerful + ppublisher + publisher + practial + practical + practially + practically + practicaly + practically + practicioner + practitioner + practicioners + practitioners + practicly + practically + practioner + practitioner + practioners + practitioners + prairy + prairie + prarie + prairie + praries + prairies + pratice + practice + preample + preamble + precedessor + predecessor + preceed + precede + preceeded + preceded + preceeding + preceding + preceeds + precedes + precentage + percentage + precice + precise + precisly + precisely + precurser + precursor + predecesors + predecessors + predicatble + predictable + predicitons + predictions + predomiantly + predominately + prefered + preferred + prefering + preferring + preferrably + preferably + pregancies + pregnancies + preiod + period + preliferation + proliferation + premeire + premiere + premeired + premiered + premillenial + premillennial + preminence + preeminence + premission + permission + preocupation + preoccupation + prepair + prepare + prepartion + preparation + prepatory + preparatory + preperation + preparation + preperations + preparations + preriod + period + presedential + presidential + presense + presence + presidenital + presidential + presidental + presidential + presitgious + prestigious + prespective + perspective + prestigeous + prestigious + prestigous + prestigious + presumabely + presumably + presumibly + presumably + pretection + protection + prevelant + prevalent + preverse + perverse + previvous + previous + pricipal + principal + priciple + principle + priestood + priesthood + primarly + primarily + primative + primitive + primatively + primitively + primatives + primitives + primordal + primordial + priveledges + privileges + privelege + privilege + priveleged + privileged + priveleges + privileges + privelige + privilege + priveliged + privileged + priveliges + privileges + privelleges + privileges + privilage + privilege + priviledge + privilege + priviledges + privileges + privledge + privilege + privte + private + probabilaty + probability + probablistic + probabilistic + probablly + probably + probalibity + probability + probaly + probably + probelm + problem + proccess + process + proccessing + processing + procede + proceed + proceded + proceeded + procedes + proceeds + procedger + procedure + proceding + proceeding + procedings + proceedings + proceedure + procedure + proces + process + processer + processor + proclaimation + proclamation + proclamed + proclaimed + proclaming + proclaiming + proclomation + proclamation + profesion + profession + profesor + professor + professer + professor + proffesed + professed + proffesion + profession + proffesional + professional + proffesor + professor + profilic + prolific + progessed + progressed + programable + programmable + progrom + program + progroms + programs + prohabition + prohibition + prologomena + prolegomena + prominance + prominence + prominant + prominent + prominantly + prominently + prominately + prominently + promiscous + promiscuous + promotted + promoted + pronomial + pronominal + pronouced + pronounced + pronounched + pronounced + pronounciation + pronunciation + proove + prove + prooved + proved + prophacy + prophecy + propietary + proprietary + propmted + prompted + propoganda + propaganda + propogate + propagate + propogates + propagates + propogation + propagation + propostion + proposition + propotions + proportions + propper + proper + propperly + properly + proprietory + proprietary + proseletyzing + proselytizing + protaganist + protagonist + protaganists + protagonists + protocal + protocol + protoganist + protagonist + protrayed + portrayed + protruberance + protuberance + protruberances + protuberances + prouncements + pronouncements + provacative + provocative + provded + provided + provicial + provincial + provinicial + provincial + provisiosn + provision + provisonal + provisional + proximty + proximity + pseudononymous + pseudonymous + pseudonyn + pseudonym + psuedo + pseudo + psycology + psychology + psyhic + psychic + pubilsher + publisher + pubisher + publisher + publiaher + publisher + publically + publicly + publicaly + publicly + publicher + publisher + publihser + publisher + publisehr + publisher + publiser + publisher + publisger + publisher + publisheed + published + publisherr + publisher + publishher + publisher + publishor + publisher + publishre + publisher + publissher + publisher + publlisher + publisher + publsiher + publisher + publusher + publisher + puchasing + purchasing + pulisher + publisher + pumkin + pumpkin + puplisher + publisher + puritannical + puritanical + purposedly + purposely + purpotedly + purportedly + pursuade + persuade + pursuaded + persuaded + pursuades + persuades + pususading + persuading + puting + putting + pwoer + power + pyscic + psychic + qtuie + quiet + quantaty + quantity + quantitiy + quantity + quarantaine + quarantine + questonable + questionable + quicklyu + quickly + quinessential + quintessential + quitted + quit + quizes + quizzes + qutie + quiet + rabinnical + rabbinical + racaus + raucous + radiactive + radioactive + radify + ratify + raelly + really + rarified + rarefied + reaccurring + recurring + reacing + reaching + reacll + recall + readmition + readmission + realitvely + relatively + realsitic + realistic + realtions + relations + realy + really + realyl + really + reasearch + research + rebiulding + rebuilding + rebllions + rebellions + rebounce + rebound + reccomend + recommend + reccomendations + recommendations + reccomended + recommended + reccomending + recommending + reccommend + recommend + reccommended + recommended + reccommending + recommending + reccuring + recurring + receeded + receded + receeding + receding + receivedfrom + received from + recepient + recipient + recepients + recipients + receving + receiving + rechargable + rechargeable + reched + reached + recide + reside + recided + resided + recident + resident + recidents + residents + reciding + residing + reciepents + recipients + reciept + receipt + recieve + receive + recieved + received + reciever + receiver + recievers + receivers + recieves + receives + recieving + receiving + recipiant + recipient + recipiants + recipients + recived + received + recivership + receivership + recogise + recognise + recogize + recognize + recomend + recommend + recomended + recommended + recomending + recommending + recomends + recommends + recommedations + recommendations + reconaissance + reconnaissance + reconcilation + reconciliation + reconized + recognized + reconnaisance + reconnaissance + reconnaissence + reconnaissance + recontructed + reconstructed + recordproducer + record producer + recquired + required + recrational + recreational + recrod + record + recuiting + recruiting + recuring + recurring + recurrance + recurrence + rediculous + ridiculous + reedeming + redeeming + reenforced + reinforced + refect + reflect + refedendum + referendum + referal + referral + referece + reference + refereces + references + refered + referred + referemce + reference + referemces + references + referencs + references + referenece + reference + refereneced + referenced + refereneces + references + referiang + referring + refering + referring + refernce + references + refernces + references + referrence + reference + referrences + references + referrs + refers + reffered + referred + refference + reference + reffering + referring + refrence + reference + refrences + references + refrers + refers + refridgeration + refrigeration + refridgerator + refrigerator + refromist + reformist + refusla + refusal + regardes + regards + regluar + regular + reguarly + regularly + regulaion + regulation + regulaotrs + regulators + regularily + regularly + rehersal + rehearsal + reicarnation + reincarnation + reigining + reigning + reknown + renown + reknowned + renowned + rela + real + relaly + really + relatiopnship + relationship + relativly + relatively + relected + reelected + releive + relieve + releived + relieved + releiver + reliever + releses + releases + relevence + relevance + relevent + relevant + reliablity + reliability + relient + reliant + religeous + religious + religous + religious + religously + religiously + relinqushment + relinquishment + relitavely + relatively + relized + realized + relpacement + replacement + remaing + remaining + remeber + remember + rememberable + memorable + rememberance + remembrance + remembrence + remembrance + remenant + remnant + remenicent + reminiscent + reminent + remnant + reminescent + reminiscent + reminscent + reminiscent + reminsicent + reminiscent + rendevous + rendezvous + rendezous + rendezvous + renedered + rende + renewl + renewal + rennovate + renovate + rennovated + renovated + rennovating + renovating + rennovation + renovation + rentors + renters + reoccurrence + recurrence + reorganision + reorganisation + repatition + repetition + repectively + respectively + repeition + repetition + repentence + repentance + repentent + repentant + repeteadly + repeatedly + repetion + repetition + repid + rapid + reponse + response + reponsible + responsible + reportadly + reportedly + represantative + representative + representive + representative + representives + representatives + reproducable + reproducible + reprtoire + repertoire + repsectively + respectively + reptition + repetition + requirment + requirement + requred + required + resaurant + restaurant + resembelance + resemblance + resembes + resembles + resemblence + resemblance + resevoir + reservoir + residental + residential + resignement + resignment + resistable + resistible + resistence + resistance + resistent + resistant + respectivly + respectively + responce + response + responibilities + responsibilities + responisble + responsible + responnsibilty + responsibility + responsability + responsibility + responsibile + responsible + responsibilites + responsibilities + responsiblities + responsibilities + responsiblity + responsibility + ressemblance + resemblance + ressemble + resemble + ressembled + resembled + ressemblence + resemblance + ressembling + resembling + resssurecting + resurrecting + ressurect + resurrect + ressurected + resurrected + ressurection + resurrection + ressurrection + resurrection + restarant + restaurant + restarants + restaurants + restaraunt + restaurant + restaraunteur + restaurateur + restaraunteurs + restaurateurs + restaraunts + restaurants + restauranteurs + restaurateurs + restauration + restoration + restauraunt + restaurant + resteraunt + restaurant + resteraunts + restaurants + resticted + restricted + restraunt + restraint + resturant + restaurant + resturants + restaurants + resturaunt + restaurant + resturaunts + restaurants + resurecting + resurrecting + retalitated + retaliated + retalitation + retaliation + retreive + retrieve + returnd + returned + revaluated + reevaluated + reveiw + review + reveral + reversal + reversable + reversible + revolutionar + revolutionary + rewitten + rewritten + rewriet + rewrite + rference + reference + rferences + references + rhymme + rhyme + rhythem + rhythm + rhythim + rhythm + rhytmic + rhythmic + rigourous + rigorous + rininging + ringing + rised + rose + rococco + rococo + rocord + record + roomate + roommate + rougly + roughly + rucuperate + recuperate + rudimentatry + rudimentary + rulle + rule + runing + running + runnung + running + russina + Russian + rwite + write + rythem + rhythm + rythim + rhythm + rythm + rhythm + rythmic + rhythmic + rythyms + rhythms + sacrafice + sacrifice + sacreligious + sacrilegious + sacrifical + sacrificial + saftey + safety + safty + safety + salery + salary + sanctionning + sanctioning + sandwhich + sandwich + santioned + sanctioned + sargant + sergeant + sargeant + sergeant + satelite + satellite + satelites + satellites + satisfactority + satisfactorily + satric + satiric + satrical + satirical + satrically + satirically + sattelite + satellite + sattelites + satellites + saught + sought + saveing + saving + saxaphone + saxophone + scaleable + scalable + scandanavia + Scandinavia + scaricity + scarcity + scavanged + scavenged + schedual + schedule + scholarhip + scholarship + scholarstic + scholastic + scientfic + scientific + scientifc + scientific + scientis + scientist + scince + science + scinece + science + scirpt + script + scoll + scroll + screenwrighter + screenwriter + scrutinity + scrutiny + scuptures + sculptures + seach + search + seached + searched + seaches + searches + secratary + secretary + secretery + secretary + sedereal + sidereal + seeked + sought + segementation + segmentation + seguoys + segues + seige + siege + seing + seeing + seinor + senior + seldomly + seldom + senarios + scenarios + senstive + sensitive + sensure + censure + seperate + separate + seperated + separated + seperately + separately + seperates + separates + seperating + separating + seperation + separation + seperatism + separatism + seperatist + separatist + sepina + subpoena + sergent + sergeant + settelement + settlement + settlment + settlement + severeal + several + severley + severely + severly + severely + sevice + service + shadasloo + shadaloo + shaddow + shadow + shadoloo + shadaloo + shamen + shaman + sheat + sheath + sheild + shield + sherif + sheriff + shineing + shining + shiped + shipped + shiping + shipping + shopkeeepers + shopkeepers + shorly + shortly + shortwhile + short while + shoudl + should + shoudln + shouldn't + shouldnt + shouldn't + shreak + shriek + shrinked + shrunk + sicne + since + sideral + sidereal + siezure + seizure + siezures + seizures + siginificant + significant + signficant + significant + signficiant + significant + signfies + signifies + signifantly + significantly + significently + significantly + signifigant + significant + signifigantly + significantly + signitories + signatories + signitory + signatory + similarily + similarly + similiar + similar + similiarity + similarity + similiarly + similarly + simmilar + similar + simpley + simply + simplier + simpler + simultanous + simultaneous + simultanously + simultaneously + sincerley + sincerely + singsog + singsong + sinse + since + skateing + skating + slaugterhouses + slaughterhouses + slighly + slightly + slowy + slowly + smae + same + smealting + smelting + smoe + some + sneeks + sneaks + snese + sneeze + socalism + socialism + socities + societies + soem + some + sofware + software + sohw + show + soilders + soldiers + solatary + solitary + soley + solely + soliders + soldiers + soliliquy + soliloquy + soluable + soluble + somene + someone + somtimes + sometimes + somwhere + somewhere + sophicated + sophisticated + sophmore + sophomore + sorceror + sorcerer + sorrounding + surrounding + sotry + story + sotyr + story + soudn + sound + soudns + sounds + sould + could + sountrack + soundtrack + sourth + south + sourthern + southern + souvenier + souvenir + souveniers + souvenirs + soveits + soviets + sovereignity + sovereignty + soverign + sovereign + soverignity + sovereignty + soverignty + sovereignty + spainish + Spanish + speach + speech + specfic + specific + speciallized + specialized + specifiying + specifying + speciman + specimen + spectauclar + spectacular + spectaulars + spectaculars + spectum + spectrum + speices + species + spendour + splendour + spermatozoan + spermatozoon + spoace + space + sponser + sponsor + sponsered + sponsored + spontanous + spontaneous + sponzored + sponsored + spoonfulls + spoonfuls + sppeches + speeches + spreaded + spread + sprech + speech + spred + spread + spriritual + spiritual + spritual + spiritual + sqaure + square + stablility + stability + stainlees + stainless + staion + station + standars + standards + stange + strange + startegic + strategic + startegies + strategies + startegy + strategy + stateman + statesman + statememts + statements + statment + statement + steriods + steroids + sterotypes + stereotypes + stilus + stylus + stingent + stringent + stiring + stirring + stirrs + stirs + stlye + style + stomache + stomach + stong + strong + stopry + story + storeis + stories + storise + stories + stornegst + strongest + stoyr + story + stpo + stop + stradegies + strategies + stradegy + strategy + strat + start + stratagically + strategically + streemlining + streamlining + stregth + strength + strenghen + strengthen + strenghened + strengthened + strenghening + strengthening + strenght + strength + strenghten + strengthen + strenghtened + strengthened + strenghtening + strengthening + strengtened + strengthened + strenous + strenuous + strictist + strictest + strikely + strikingly + strnad + strand + stroy + story + structual + structural + stubborness + stubbornness + stucture + structure + stuctured + structured + studdy + study + studing + studying + stuggling + struggling + sturcture + structure + subcatagories + subcategories + subcatagory + subcategory + subconsiously + subconsciously + subjudgation + subjugation + submachne + submachine + subpecies + subspecies + subsidary + subsidiary + subsiduary + subsidiary + subsquent + subsequent + subsquently + subsequently + substace + substance + substancial + substantial + substatial + substantial + substituded + substituted + substract + subtract + substracted + subtracted + substracting + subtracting + substraction + subtraction + substracts + subtracts + subtances + substances + subterranian + subterranean + suburburban + suburban + succceeded + succeeded + succcesses + successes + succedded + succeeded + succeded + succeeded + succeds + succeeds + succesful + successful + succesfully + successfully + succesfuly + successfully + succesion + succession + succesive + successive + successfull + successful + successully + successfully + succsess + success + succsessfull + successful + suceed + succeed + suceeded + succeeded + suceeding + succeeding + suceeds + succeeds + sucesful + successful + sucesfully + successfully + sucesfuly + successfully + sucesion + succession + sucess + success + sucesses + successes + sucessful + successful + sucessfull + successful + sucessfully + successfully + sucessfuly + successfully + sucession + succession + sucessive + successive + sucessor + successor + sucessot + successor + sucide + suicide + sucidial + suicidal + sufferage + suffrage + sufferred + suffered + sufferring + suffering + sufficent + sufficient + sufficently + sufficiently + sumary + summary + sunglases + sunglasses + suop + soup + superceeded + superseded + superintendant + superintendent + suphisticated + sophisticated + suplimented + supplemented + supose + suppose + suposed + supposed + suposedly + supposedly + suposes + supposes + suposing + supposing + supplamented + supplemented + suppliementing + supplementing + suppoed + supposed + supposingly + supposedly + suppy + supply + supress + suppress + supressed + suppressed + supresses + suppresses + supressing + suppressing + suprise + surprise + suprised + surprised + suprising + surprising + suprisingly + surprisingly + suprize + surprise + suprized + surprised + suprizing + surprising + suprizingly + surprisingly + surfce + surface + surley + surely + suround + surround + surounded + surrounded + surounding + surrounding + suroundings + surroundings + surounds + surrounds + surplanted + supplanted + surpress + suppress + surpressed + suppressed + surprize + surprise + surprized + surprised + surprizing + surprising + surprizingly + surprisingly + surrended + surrendered + surrepetitious + surreptitious + surrepetitiously + surreptitiously + surreptious + surreptitious + surreptiously + surreptitiously + surronded + surrounded + surrouded + surrounded + surrouding + surrounding + surrundering + surrendering + surveilence + surveillance + surveill + surveil + surveyer + surveyor + surviver + survivor + survivers + survivors + survivied + survived + suseptable + susceptible + suseptible + susceptible + suspention + suspension + swaer + swear + swaers + swears + swepth + swept + swiming + swimming + syas + says + symetrical + symmetrical + symetrically + symmetrically + symetry + symmetry + symettric + symmetric + symmetral + symmetric + symmetricaly + symmetrically + synagouge + synagogue + syncronization + synchronization + synonomous + synonymous + synonymns + synonyms + synphony + symphony + syphyllis + syphilis + sypmtoms + symptoms + syrap + syrup + sysmatically + systematically + sytem + system + sytle + style + tabacco + tobacco + tahn + than + taht + that + talekd + talked + targetted + targeted + targetting + targeting + tast + taste + tath + that + tattooes + tattoos + taxanomic + taxonomic + taxanomy + taxonomy + teached + taught + techician + technician + techicians + technicians + techiniques + techniques + technitian + technician + technnology + technology + technolgy + technology + teh + the + tehy + they + telelevision + television + televsion + television + telphony + telephony + temerature + temperature + tempalte + template + tempaltes + templates + temparate + temperate + temperarily + temporarily + temperment + temperament + tempertaure + temperature + temperture + temperature + temprary + temporary + tenacle + tentacle + tenacles + tentacles + tendacy + tendency + tendancies + tendencies + tendancy + tendency + tennisplayer + tennis player + tepmorarily + temporarily + terrestial + terrestrial + terriories + territories + terriory + territory + territorist + terrorist + territoy + territory + terroist + terrorist + testiclular + testicular + tghe + the + thast + that's + theather + theater + theese + these + theif + thief + theives + thieves + themselfs + themselves + themslves + themselves + ther + there + therafter + thereafter + therby + thereby + theri + their + theyre + they're + thgat + that + thge + the + thier + their + thign + thing + thigns + things + thigsn + things + thikn + think + thikning + thinking + thikns + thinks + thiunk + think + thn + then + thna + than + thne + then + thnig + thing + thnigs + things + thoughout + throughout + threatend + threatened + threatning + threatening + threee + three + threshhold + threshold + thrid + third + throrough + thorough + throughly + thoroughly + throught + throat + througout + throughout + thru + through + thsi + this + thsoe + those + thta + that + thyat + that + tiem + time + tihkn + think + tihs + this + timne + time + tiome + time + tje + the + tjhe + the + tjpanishad + upanishad + tkae + take + tkaes + takes + tkaing + taking + tlaking + talking + tobbaco + tobacco + todays + today's + todya + today + toghether + together + toke + took + tolerence + tolerance + tomatos + tomatoes + tommorow + tomorrow + tommorrow + tomorrow + tongiht + tonight + toriodal + toroidal + tormenters + tormentors + tornadoe + tornado + torpeados + torpedoes + torpedos + torpedoes + tothe + to the + toubles + troubles + tounge + tongue + tourch + torch + towords + towards + towrad + toward + tradionally + traditionally + traditionaly + traditionally + traditionnal + traditional + traditition + tradition + tradtionally + traditionally + trafficed + trafficked + trafficing + trafficking + trafic + traffic + trancendent + transcendent + trancending + transcending + tranform + transform + tranformed + transformed + transcendance + transcendence + transcendant + transcendent + transcendentational + transcendental + transcripting + transcribing + transending + transcending + transesxuals + transsexuals + transfered + transferred + transfering + transferring + transformaton + transformation + transistion + transition + translater + translator + translaters + translators + transmissable + transmissible + transporation + transportation + tremelo + tremolo + tremelos + tremolos + triguered + triggered + triology + trilogy + troling + trolling + troup + troupe + troups + troops + truely + truly + trustworthyness + trustworthiness + turnk + trunk + tust + trust + twelth + twelfth + twon + town + twpo + two + tyhat + that + tyhe + they + typcial + typical + typicaly + typically + tyranies + tyrannies + tyrany + tyranny + tyrranies + tyrannies + tyrrany + tyranny + ubiquitious + ubiquitous + ublisher + publisher + uise + use + ultimely + ultimately + unacompanied + unaccompanied + unahppy + unhappy + unanymous + unanimous + unathorised + unauthorised + unavailible + unavailable + unballance + unbalance + unbeknowst + unbeknownst + unbeleivable + unbelievable + uncertainity + uncertainty + unchallengable + unchallengeable + unchangable + unchangeable + uncompetive + uncompetitive + unconcious + unconscious + unconciousness + unconsciousness + unconfortability + discomfort + uncontitutional + unconstitutional + unconvential + unconventional + undecideable + undecidable + understoon + understood + undesireable + undesirable + undetecable + undetectable + undoubtely + undoubtedly + undreground + underground + uneccesary + unnecessary + unecessary + unnecessary + unequalities + inequalities + unforetunately + unfortunately + unforgetable + unforgettable + unforgiveable + unforgivable + unfortunatley + unfortunately + unfortunatly + unfortunately + unfourtunately + unfortunately + unihabited + uninhabited + unilateraly + unilaterally + unilatreal + unilateral + unilatreally + unilaterally + uninterruped + uninterrupted + uninterupted + uninterrupted + univeral + universal + univeristies + universities + univeristy + university + univerity + university + universtiy + university + univesities + universities + univesity + university + unkown + unknown + unlikey + unlikely + unmanouverable + unmaneuverable + unmistakeably + unmistakably + unneccesarily + unnecessarily + unneccesary + unnecessary + unneccessarily + unnecessarily + unneccessary + unnecessary + unnecesarily + unnecessarily + unnecesary + unnecessary + unoffical + unofficial + unoperational + nonoperational + unoticeable + unnoticeable + unplease + displease + unplesant + unpleasant + unprecendented + unprecedented + unprecidented + unprecedented + unrepentent + unrepentant + unrepetant + unrepentant + unrepetent + unrepentant + unsed + unused + unsubstanciated + unsubstantiated + unsuccesful + unsuccessful + unsuccesfully + unsuccessfully + unsuccessfull + unsuccessful + unsucesful + unsuccessful + unsucesfuly + unsuccessfully + unsucessful + unsuccessful + unsucessfull + unsuccessful + unsucessfully + unsuccessfully + unsuprised + unsurprised + unsuprising + unsurprising + unsuprisingly + unsurprisingly + unsuprized + unsurprised + unsuprizing + unsurprising + unsuprizingly + unsurprisingly + unsurprized + unsurprised + unsurprizing + unsurprising + unsurprizingly + unsurprisingly + untill + until + untranslateable + untranslatable + unuseable + unusable + unusuable + unusable + unviersity + university + unwarrented + unwarranted + unweildly + unwieldy + unwieldly + unwieldy + upcomming + upcoming + upgradded + upgraded + upto + up to + usally + usually + useage + usage + usefull + useful + usefuly + usefully + useing + using + usualy + usually + ususally + usually + vaccum + vacuum + vaccume + vacuum + vacinity + vicinity + vaguaries + vagaries + vaieties + varieties + vailidty + validity + valetta + valletta + valuble + valuable + valueable + valuable + varations + variations + varient + variant + variey + variety + varing + varying + varities + varieties + varity + variety + vasall + vassal + vasalls + vassals + vegatarian + vegetarian + vegitable + vegetable + vegitables + vegetables + vegtable + vegetable + vehicule + vehicle + vell + well + venemous + venomous + vengance + vengeance + vengence + vengeance + verfication + verification + verison + version + verisons + versions + vermillion + vermilion + versitilaty + versatility + versitlity + versatility + vetween + between + veyr + very + vigeur + vigor + vigilence + vigilance + vigourous + vigorous + villian + villain + villification + vilification + villify + vilify + villin + villain + vincinity + vicinity + violentce + violence + virtualy + virtually + virutal + virtual + virutally + virtually + visable + visible + visably + visibly + visting + visiting + vistors + visitors + vitories + victories + volcanoe + volcano + voleyball + volleyball + volontary + voluntary + volonteer + volunteer + volonteered + volunteered + volonteering + volunteering + volonteers + volunteers + volounteer + volunteer + volounteered + volunteered + volounteering + volunteering + volounteers + volunteers + volumne + volume + vreity + variety + vrey + very + vriety + variety + vulnerablility + vulnerability + vyer + very + vyre + very + waht + what + warantee + warranty + wardobe + wardrobe + warrent + warrant + warrriors + warriors + wasnt + wasn't + wass + was + watn + want + wayword + wayward + weaponary + weaponry + weas + was + wehn + when + weild + wield + weilded + wielded + wendsay + Wednesday + wensday + Wednesday + wereabouts + whereabouts + whant + want + whants + wants + whcih + which + wheras + whereas + wherease + whereas + whereever + wherever + whic + which + whihc + which + whith + with + whlch + which + whn + when + wholey + wholly + wholy + holy + whta + what + whther + whether + wich + which + widesread + widespread + wief + wife + wierd + weird + wiew + view + wih + with + wiht + with + wille + will + willingless + willingness + wirting + writing + withdrawl + withdrawal + witheld + withheld + withh + with + withing + within + withold + withhold + witht + with + witn + with + wiull + will + wnat + want + wnated + wanted + wnats + wants + wohle + whole + wokr + work + wokring + working + wonderfull + wonderful + wont + won't + wordlwide + worldwide + workststion + workstation + worls + world + worstened + worsened + woudl + would + wresters + wrestlers + wriet + write + writen + written + wroet + wrote + wrok + work + wroking + working + wtih + with + wupport + support + xenophoby + xenophobia + yaching + yachting + yaer + year + yaerly + yearly + yaers + years + yatch + yacht + yearm + year + yeasr + years + yeild + yield + yeilding + yielding + yera + year + yeras + years + yersa + years + yotube + YouTube + youre + you're + youseff + yousef + youself + yourself + ytou + you + yuo + you + zeebra + zebra + + + + diff --git a/indra/newview/app_settings/ca-bundle.crt b/indra/newview/app_settings/ca-bundle.crt new file mode 100644 index 0000000000..e049f41fb0 --- /dev/null +++ b/indra/newview/app_settings/ca-bundle.crt @@ -0,0 +1,14600 @@ +## +## Bundle of CA Root Certificates +## +## Certificate data from Mozilla as of: Wed Jan 17 21:18:08 2018 GMT +## +## This is a bundle of X.509 certificates of public Certificate Authorities +## (CA). These were automatically extracted from Mozilla's root certificates +## file (certdata.txt). This file can be found in the mozilla source tree: +## https://hg.mozilla.org/releases/mozilla-release/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt +## +## It contains the certificates in plain text and PEM format and therefore +## can be directly used with curl / libcurl / php_curl, or with +## an Apache+mod_ssl webserver for SSL client authentication. +## Just configure this file as the SSLCACertificateFile. +## +## Conversion done with mk-ca-bundle.pl version 1.27. +## SHA256: a3ac15b98179dd2f3c5de076d10b1d53048754372f7207c2f327510cdd78fbd8 +## +LetsEncrypt Root CA2 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 03:74:f1:c1:0b:b8:be:e9:c5:30:d3:e4:43:db:f8:ff:05:0d + Signature Algorithm: sha256WithRSAEncryption + Issuer: C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3 + Validity + Not Before: Mar 10 21:26:03 2019 GMT + Not After : Jun 8 21:26:03 2019 GMT + Subject: CN = login.virtual-nexus.xyz + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (4096 bit) + Modulus: + 00:aa:ea:b2:94:3e:9e:bf:08:c7:9a:3b:93:9d:4a: + a4:8e:18:f1:60:a1:26:d1:78:c1:72:11:8e:da:3e: + fa:16:3a:f4:a4:b2:de:ee:ec:eb:86:f1:88:2e:78: + 1a:04:90:44:e4:c2:72:c3:85:cf:8e:3b:9a:cd:f6: + 2c:4e:cb:39:06:18:2a:b9:70:dd:a5:d0:d6:71:01: + e8:e6:cc:f4:86:dd:88:2b:d5:de:28:a4:6c:a2:c9: + ab:dd:8b:0f:12:2a:1d:67:0f:fe:02:f9:33:1e:0c: + 84:be:16:d2:f2:b0:4d:b3:54:3d:db:df:83:8d:9a: + 1e:16:46:0b:f5:42:fb:91:4b:6a:95:7e:6b:48:e3: + 86:d8:60:5d:4d:9a:4e:a6:82:e7:05:02:83:78:72: + b4:62:8b:27:30:3a:20:8f:72:95:58:56:45:43:db: + 4e:e3:4a:87:0a:c9:58:f9:ec:63:65:d4:eb:f7:1d: + cc:2b:5c:8d:7d:61:54:0f:83:78:9a:b3:bf:db:87: + 45:b9:99:9b:54:75:e8:1c:52:29:f8:37:ad:24:5a: + ca:2b:1a:b2:11:8e:d4:34:bb:00:a8:e2:ae:ed:34: + 14:30:13:e1:06:c5:ee:d4:b2:9b:94:8d:f5:dc:2b: + a0:d3:ab:35:32:8b:e5:cf:d5:44:68:69:5d:3f:22: + 86:c9:2d:14:b6:b1:82:0c:fe:87:4d:a0:0a:76:1d: + c3:be:b9:ff:6e:c4:9e:f7:2d:d2:f5:ad:4d:aa:7f: + 4e:44:d6:7b:b4:6a:d0:71:52:48:2c:30:bf:11:b5: + df:70:40:30:cc:1a:e4:c0:a0:90:86:56:bf:36:92: + 2a:00:a5:0d:3b:2d:42:29:c1:4c:d6:9f:47:83:ff: + c1:c4:cc:04:08:9f:8b:2c:ca:4c:f5:d4:a5:38:81: + 6a:d0:4d:68:d9:fb:fa:1e:de:a1:c2:47:ea:d4:a8: + a3:b2:ba:47:50:b4:0e:15:a7:a7:ac:e2:a4:21:7c: + 20:c3:6b:ef:4f:3d:57:d0:91:ce:19:b2:da:4d:cd: + 7f:2d:2e:12:9d:e8:55:fc:02:ad:ea:57:68:d6:f9: + 96:9f:85:98:56:10:a2:bb:b6:7b:24:34:ab:9d:d7: + c9:56:47:40:b5:b1:22:80:b1:ae:37:73:6c:94:93: + 6c:db:97:47:b1:86:3c:87:5d:ad:52:2a:44:16:ce: + 0c:5c:94:1d:c2:cd:17:76:89:9a:ec:80:78:b9:a9: + c7:90:d2:c6:de:22:bb:95:1e:f6:ad:04:a0:46:c9: + 4b:12:2e:8d:ff:89:6c:c8:69:91:78:a0:f3:cf:f2: + 22:7d:68:4e:ee:32:0f:61:17:09:ba:94:bd:88:6d: + a8:65:cd + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Digital Signature, Key Encipherment + X509v3 Extended Key Usage: + TLS Web Server Authentication, TLS Web Client Authentication + X509v3 Basic Constraints: critical + CA:FALSE + X509v3 Subject Key Identifier: + 2D:36:69:83:B8:E4:7D:38:D1:8F:8B:92:9E:A8:FD:6B:E9:25:29:97 + X509v3 Authority Key Identifier: + keyid:A8:4A:6A:63:04:7D:DD:BA:E6:D1:39:B7:A6:45:65:EF:F3:A8:EC:A1 + + Authority Information Access: + OCSP - URI:http://ocsp.int-x3.letsencrypt.org + CA Issuers - URI:http://cert.int-x3.letsencrypt.org/ + + X509v3 Subject Alternative Name: + DNS:login.virtual-nexus.xyz + X509v3 Certificate Policies: + Policy: 2.23.140.1.2.1 + Policy: 1.3.6.1.4.1.44947.1.1.1 + CPS: http://cps.letsencrypt.org + + CT Precertificate SCTs: + Signed Certificate Timestamp: + Version : v1 (0x0) + Log ID : 74:7E:DA:83:31:AD:33:10:91:21:9C:CE:25:4F:42:70: + C2:BF:FD:5E:42:20:08:C6:37:35:79:E6:10:7B:CC:56 + Timestamp : Mar 10 22:26:03.415 2019 GMT + Extensions: none + Signature : ecdsa-with-SHA256 + 30:45:02:21:00:98:49:3F:B0:C4:66:2D:CF:CE:91:36: + 15:AF:75:94:5B:FD:C2:CB:8F:F1:E2:8D:FA:C0:61:8E: + E6:F3:7B:A8:05:02:20:62:39:0F:66:B2:79:48:A8:49: + 41:2A:D4:59:86:C3:FA:AC:C1:5D:26:02:AC:E3:D8:C8: + 0F:40:34:64:F1:D1:36 + Signed Certificate Timestamp: + Version : v1 (0x0) + Log ID : 29:3C:51:96:54:C8:39:65:BA:AA:50:FC:58:07:D4:B7: + 6F:BF:58:7A:29:72:DC:A4:C3:0C:F4:E5:45:47:F4:78 + Timestamp : Mar 10 22:26:03.442 2019 GMT + Extensions: none + Signature : ecdsa-with-SHA256 + 30:46:02:21:00:C7:09:49:5A:96:E5:B5:15:2A:F1:EA: + 03:A4:7D:10:89:23:9A:C2:C9:9F:35:85:AD:87:11:58: + A8:95:5C:0A:C6:02:21:00:88:14:C8:48:C7:6B:96:DB: + A2:AB:91:BD:F7:3D:AD:FA:37:F6:AD:BF:D7:24:DC:F0: + 11:CF:0C:D4:42:E0:72:A5 + Signature Algorithm: sha256WithRSAEncryption + 42:55:9f:ea:ae:79:1d:9d:e9:06:23:a1:d0:a9:0f:d2:bc:08: + 92:b6:05:30:29:c2:00:fc:96:6e:b1:ff:9b:00:d7:c3:7b:34: + 47:02:81:2a:44:46:85:6c:7a:f5:c3:09:e2:9c:fd:1d:d3:2c: + a4:e9:a5:99:ec:47:bd:fe:39:d2:c9:d6:ac:dd:48:40:0b:9a: + 24:f1:0b:4e:02:62:aa:63:e4:dd:8f:ad:9a:6c:5a:0a:de:d0: + a2:67:b2:ea:fa:68:ff:18:ea:e1:73:35:89:45:dd:b7:ac:2d: + 58:8a:a3:6d:eb:41:f6:fa:60:8f:39:38:33:a0:d5:fd:56:5d: + 02:08:80:40:f6:f0:c1:68:e1:15:c8:fc:c3:64:a5:43:85:18: + ed:44:5d:f8:b9:20:43:9f:3d:8b:20:e0:55:cd:78:89:d4:db: + 80:23:88:0e:6f:f5:ef:66:52:a9:c6:b1:f1:5e:6c:d6:8e:18: + 7a:93:14:65:4b:1b:a7:55:7d:9d:a5:d2:15:a8:7d:a1:aa:dd: + ef:93:94:d5:3e:2f:ce:4b:bf:ac:e5:61:da:66:61:bd:42:08: + 53:58:73:a7:80:64:78:17:60:11:71:7f:75:17:bc:24:2f:57: + 8c:61:37:87:4e:0a:41:82:74:b0:69:14:5c:89:58:55:32:1f: + 06:1b:e2:24 +-----BEGIN CERTIFICATE----- +MIIFjTCCA3WgAwIBAgIRANOxciY0IzLc9AUoUSrsnGowDQYJKoZIhvcNAQELBQAw +TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh +cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTYxMDA2MTU0MzU1 +WhcNMjExMDA2MTU0MzU1WjBKMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg +RW5jcnlwdDEjMCEGA1UEAxMaTGV0J3MgRW5jcnlwdCBBdXRob3JpdHkgWDMwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCc0wzwWuUuR7dyXTeDs2hjMOrX +NSYZJeG9vjXxcJIvt7hLQQWrqZ41CFjssSrEaIcLo+N15Obzp2JxunmBYB/XkZqf +89B4Z3HIaQ6Vkc/+5pnpYDxIzH7KTXcSJJ1HG1rrueweNwAcnKx7pwXqzkrrvUHl +Npi5y/1tPJZo3yMqQpAMhnRnyH+lmrhSYRQTP2XpgofL2/oOVvaGifOFP5eGr7Dc +Gu9rDZUWfcQroGWymQQ2dYBrrErzG5BJeC+ilk8qICUpBMZ0wNAxzY8xOJUWuqgz +uEPxsR/DMH+ieTETPS02+OP88jNquTkxxa/EjQ0dZBYzqvqEKbbUC8DYfcOTAgMB +AAGjggFnMIIBYzAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADBU +BgNVHSAETTBLMAgGBmeBDAECATA/BgsrBgEEAYLfEwEBATAwMC4GCCsGAQUFBwIB +FiJodHRwOi8vY3BzLnJvb3QteDEubGV0c2VuY3J5cHQub3JnMB0GA1UdDgQWBBSo +SmpjBH3duubRObemRWXv86jsoTAzBgNVHR8ELDAqMCigJqAkhiJodHRwOi8vY3Js +LnJvb3QteDEubGV0c2VuY3J5cHQub3JnMHIGCCsGAQUFBwEBBGYwZDAwBggrBgEF +BQcwAYYkaHR0cDovL29jc3Aucm9vdC14MS5sZXRzZW5jcnlwdC5vcmcvMDAGCCsG +AQUFBzAChiRodHRwOi8vY2VydC5yb290LXgxLmxldHNlbmNyeXB0Lm9yZy8wHwYD +VR0jBBgwFoAUebRZ5nu25eQBc4AIiMgaWPbpm24wDQYJKoZIhvcNAQELBQADggIB +ABnPdSA0LTqmRf/Q1eaM2jLonG4bQdEnqOJQ8nCqxOeTRrToEKtwT++36gTSlBGx +A/5dut82jJQ2jxN8RI8L9QFXrWi4xXnA2EqA10yjHiR6H9cj6MFiOnb5In1eWsRM +UM2v3e9tNsCAgBukPHAg1lQh07rvFKm/Bz9BCjaxorALINUfZ9DD64j2igLIxle2 +DPxW8dI/F2loHMjXZjqG8RkqZUdoxtID5+90FgsGIfkMpqgRS05f4zPbCEHqCXl1 +eO5HyELTgcVlLXXQDgAWnRzut1hFJeczY1tjQQno6f6s+nMydLN26WuU4s3UYvOu +OsUxRlJu7TSRHqDC3lSE5XggVkzdaPkuKGQbGpny+01/47hfXXNB7HntWNZ6N2Vw +p7G6OfY+YQrZwIaQmhrIqJZuigsrbe3W+gdn5ykE9+Ky0VgVUsfxo52mwFYs1JKY +2PGDuWx8M6DlS6qQkvHaRUo0FMd8TsSlbF0/v965qGFKhSDeQoMpYnwcmQilRh/0 +ayLThlHLN81gSkJjVrPI0Y8xCVPB4twb1PFUd2fPM3sA1tJ83sZ5v8vgFv2yofKR +PB0t6JzUA81mSqM3kxl5e+IZwhYAyO0OTg3/fs8HqGTNKd9BqoUwSRBzp06JMg5b +rUCGwbCUDI0mxadJ3Bz4WxR6fyNpBK2yAinWEsikxqEt +-----END CERTIFICATE----- + +LetsEncrypt Root CA + +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 03:74:f1:c1:0b:b8:be:e9:c5:30:d3:e4:43:db:f8:ff:05:0d + Signature Algorithm: sha256WithRSAEncryption + Issuer: C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3 + Validity + Not Before: Mar 10 21:26:03 2019 GMT + Not After : Jun 8 21:26:03 2019 GMT + Subject: CN = login.virtual-nexus.xyz + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (4096 bit) + Modulus: + 00:aa:ea:b2:94:3e:9e:bf:08:c7:9a:3b:93:9d:4a: + a4:8e:18:f1:60:a1:26:d1:78:c1:72:11:8e:da:3e: + fa:16:3a:f4:a4:b2:de:ee:ec:eb:86:f1:88:2e:78: + 1a:04:90:44:e4:c2:72:c3:85:cf:8e:3b:9a:cd:f6: + 2c:4e:cb:39:06:18:2a:b9:70:dd:a5:d0:d6:71:01: + e8:e6:cc:f4:86:dd:88:2b:d5:de:28:a4:6c:a2:c9: + ab:dd:8b:0f:12:2a:1d:67:0f:fe:02:f9:33:1e:0c: + 84:be:16:d2:f2:b0:4d:b3:54:3d:db:df:83:8d:9a: + 1e:16:46:0b:f5:42:fb:91:4b:6a:95:7e:6b:48:e3: + 86:d8:60:5d:4d:9a:4e:a6:82:e7:05:02:83:78:72: + b4:62:8b:27:30:3a:20:8f:72:95:58:56:45:43:db: + 4e:e3:4a:87:0a:c9:58:f9:ec:63:65:d4:eb:f7:1d: + cc:2b:5c:8d:7d:61:54:0f:83:78:9a:b3:bf:db:87: + 45:b9:99:9b:54:75:e8:1c:52:29:f8:37:ad:24:5a: + ca:2b:1a:b2:11:8e:d4:34:bb:00:a8:e2:ae:ed:34: + 14:30:13:e1:06:c5:ee:d4:b2:9b:94:8d:f5:dc:2b: + a0:d3:ab:35:32:8b:e5:cf:d5:44:68:69:5d:3f:22: + 86:c9:2d:14:b6:b1:82:0c:fe:87:4d:a0:0a:76:1d: + c3:be:b9:ff:6e:c4:9e:f7:2d:d2:f5:ad:4d:aa:7f: + 4e:44:d6:7b:b4:6a:d0:71:52:48:2c:30:bf:11:b5: + df:70:40:30:cc:1a:e4:c0:a0:90:86:56:bf:36:92: + 2a:00:a5:0d:3b:2d:42:29:c1:4c:d6:9f:47:83:ff: + c1:c4:cc:04:08:9f:8b:2c:ca:4c:f5:d4:a5:38:81: + 6a:d0:4d:68:d9:fb:fa:1e:de:a1:c2:47:ea:d4:a8: + a3:b2:ba:47:50:b4:0e:15:a7:a7:ac:e2:a4:21:7c: + 20:c3:6b:ef:4f:3d:57:d0:91:ce:19:b2:da:4d:cd: + 7f:2d:2e:12:9d:e8:55:fc:02:ad:ea:57:68:d6:f9: + 96:9f:85:98:56:10:a2:bb:b6:7b:24:34:ab:9d:d7: + c9:56:47:40:b5:b1:22:80:b1:ae:37:73:6c:94:93: + 6c:db:97:47:b1:86:3c:87:5d:ad:52:2a:44:16:ce: + 0c:5c:94:1d:c2:cd:17:76:89:9a:ec:80:78:b9:a9: + c7:90:d2:c6:de:22:bb:95:1e:f6:ad:04:a0:46:c9: + 4b:12:2e:8d:ff:89:6c:c8:69:91:78:a0:f3:cf:f2: + 22:7d:68:4e:ee:32:0f:61:17:09:ba:94:bd:88:6d: + a8:65:cd + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Digital Signature, Key Encipherment + X509v3 Extended Key Usage: + TLS Web Server Authentication, TLS Web Client Authentication + X509v3 Basic Constraints: critical + CA:FALSE + X509v3 Subject Key Identifier: + 2D:36:69:83:B8:E4:7D:38:D1:8F:8B:92:9E:A8:FD:6B:E9:25:29:97 + X509v3 Authority Key Identifier: + keyid:A8:4A:6A:63:04:7D:DD:BA:E6:D1:39:B7:A6:45:65:EF:F3:A8:EC:A1 + + Authority Information Access: + OCSP - URI:http://ocsp.int-x3.letsencrypt.org + CA Issuers - URI:http://cert.int-x3.letsencrypt.org/ + + X509v3 Subject Alternative Name: + DNS:login.virtual-nexus.xyz + X509v3 Certificate Policies: + Policy: 2.23.140.1.2.1 + Policy: 1.3.6.1.4.1.44947.1.1.1 + CPS: http://cps.letsencrypt.org + + CT Precertificate SCTs: + Signed Certificate Timestamp: + Version : v1 (0x0) + Log ID : 74:7E:DA:83:31:AD:33:10:91:21:9C:CE:25:4F:42:70: + C2:BF:FD:5E:42:20:08:C6:37:35:79:E6:10:7B:CC:56 + Timestamp : Mar 10 22:26:03.415 2019 GMT + Extensions: none + Signature : ecdsa-with-SHA256 + 30:45:02:21:00:98:49:3F:B0:C4:66:2D:CF:CE:91:36: + 15:AF:75:94:5B:FD:C2:CB:8F:F1:E2:8D:FA:C0:61:8E: + E6:F3:7B:A8:05:02:20:62:39:0F:66:B2:79:48:A8:49: + 41:2A:D4:59:86:C3:FA:AC:C1:5D:26:02:AC:E3:D8:C8: + 0F:40:34:64:F1:D1:36 + Signed Certificate Timestamp: + Version : v1 (0x0) + Log ID : 29:3C:51:96:54:C8:39:65:BA:AA:50:FC:58:07:D4:B7: + 6F:BF:58:7A:29:72:DC:A4:C3:0C:F4:E5:45:47:F4:78 + Timestamp : Mar 10 22:26:03.442 2019 GMT + Extensions: none + Signature : ecdsa-with-SHA256 + 30:46:02:21:00:C7:09:49:5A:96:E5:B5:15:2A:F1:EA: + 03:A4:7D:10:89:23:9A:C2:C9:9F:35:85:AD:87:11:58: + A8:95:5C:0A:C6:02:21:00:88:14:C8:48:C7:6B:96:DB: + A2:AB:91:BD:F7:3D:AD:FA:37:F6:AD:BF:D7:24:DC:F0: + 11:CF:0C:D4:42:E0:72:A5 + Signature Algorithm: sha256WithRSAEncryption + 42:55:9f:ea:ae:79:1d:9d:e9:06:23:a1:d0:a9:0f:d2:bc:08: + 92:b6:05:30:29:c2:00:fc:96:6e:b1:ff:9b:00:d7:c3:7b:34: + 47:02:81:2a:44:46:85:6c:7a:f5:c3:09:e2:9c:fd:1d:d3:2c: + a4:e9:a5:99:ec:47:bd:fe:39:d2:c9:d6:ac:dd:48:40:0b:9a: + 24:f1:0b:4e:02:62:aa:63:e4:dd:8f:ad:9a:6c:5a:0a:de:d0: + a2:67:b2:ea:fa:68:ff:18:ea:e1:73:35:89:45:dd:b7:ac:2d: + 58:8a:a3:6d:eb:41:f6:fa:60:8f:39:38:33:a0:d5:fd:56:5d: + 02:08:80:40:f6:f0:c1:68:e1:15:c8:fc:c3:64:a5:43:85:18: + ed:44:5d:f8:b9:20:43:9f:3d:8b:20:e0:55:cd:78:89:d4:db: + 80:23:88:0e:6f:f5:ef:66:52:a9:c6:b1:f1:5e:6c:d6:8e:18: + 7a:93:14:65:4b:1b:a7:55:7d:9d:a5:d2:15:a8:7d:a1:aa:dd: + ef:93:94:d5:3e:2f:ce:4b:bf:ac:e5:61:da:66:61:bd:42:08: + 53:58:73:a7:80:64:78:17:60:11:71:7f:75:17:bc:24:2f:57: + 8c:61:37:87:4e:0a:41:82:74:b0:69:14:5c:89:58:55:32:1f: + 06:1b:e2:24 +-----BEGIN CERTIFICATE----- +MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/ +MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT +DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow +SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT +GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF +q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8 +SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0 +Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA +a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj +/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T +AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG +CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv +bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k +c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw +VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC +ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz +MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu +Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF +AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo +uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/ +wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu +X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG +PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6 +KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg== +-----END CERTIFICATE----- + + + + +GlobalSign Root CA +# Issuer: CN=GlobalSign Root CA,OU=Root CA,O=GlobalSign nv-sa,C=BE +# Serial Number:04:00:00:00:00:01:15:4b:5a:c3:94 +# Subject: CN=GlobalSign Root CA,OU=Root CA,O=GlobalSign nv-sa,C=BE +# Not Valid Before: Tue Sep 01 12:00:00 1998 +# Not Valid After : Fri Jan 28 12:00:00 2028 +# Fingerprint (MD5): 3E:45:52:15:09:51:92:E1:B7:5D:37:9F:B1:87:29:8A +# Fingerprint (SHA1): B1:BC:96:8B:D4:F4:9D:62:2A:A8:9A:81:F2:15:01:52:A4:1D:82:9C +MUST_VERIFY_TRUST: CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +================================================ +MD5 Fingerprint=3E:45:52:15:09:51:92:E1:B7:5D:37:9F:B1:87:29:8A +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 04:00:00:00:00:01:15:4b:5a:c3:94 + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=BE, O=GlobalSign nv-sa, OU=Root CA, CN=GlobalSign Root CA + Validity + Not Before: Sep 1 12:00:00 1998 GMT + Not After : Jan 28 12:00:00 2028 GMT + Subject: C=BE, O=GlobalSign nv-sa, OU=Root CA, CN=GlobalSign Root CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:da:0e:e6:99:8d:ce:a3:e3:4f:8a:7e:fb:f1:8b: + 83:25:6b:ea:48:1f:f1:2a:b0:b9:95:11:04:bd:f0: + 63:d1:e2:67:66:cf:1c:dd:cf:1b:48:2b:ee:8d:89: + 8e:9a:af:29:80:65:ab:e9:c7:2d:12:cb:ab:1c:4c: + 70:07:a1:3d:0a:30:cd:15:8d:4f:f8:dd:d4:8c:50: + 15:1c:ef:50:ee:c4:2e:f7:fc:e9:52:f2:91:7d:e0: + 6d:d5:35:30:8e:5e:43:73:f2:41:e9:d5:6a:e3:b2: + 89:3a:56:39:38:6f:06:3c:88:69:5b:2a:4d:c5:a7: + 54:b8:6c:89:cc:9b:f9:3c:ca:e5:fd:89:f5:12:3c: + 92:78:96:d6:dc:74:6e:93:44:61:d1:8d:c7:46:b2: + 75:0e:86:e8:19:8a:d5:6d:6c:d5:78:16:95:a2:e9: + c8:0a:38:eb:f2:24:13:4f:73:54:93:13:85:3a:1b: + bc:1e:34:b5:8b:05:8c:b9:77:8b:b1:db:1f:20:91: + ab:09:53:6e:90:ce:7b:37:74:b9:70:47:91:22:51: + 63:16:79:ae:b1:ae:41:26:08:c8:19:2b:d1:46:aa: + 48:d6:64:2a:d7:83:34:ff:2c:2a:c1:6c:19:43:4a: + 07:85:e7:d3:7c:f6:21:68:ef:ea:f2:52:9f:7f:93: + 90:cf + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + 60:7B:66:1A:45:0D:97:CA:89:50:2F:7D:04:CD:34:A8:FF:FC:FD:4B + Signature Algorithm: sha1WithRSAEncryption + d6:73:e7:7c:4f:76:d0:8d:bf:ec:ba:a2:be:34:c5:28:32:b5: + 7c:fc:6c:9c:2c:2b:bd:09:9e:53:bf:6b:5e:aa:11:48:b6:e5: + 08:a3:b3:ca:3d:61:4d:d3:46:09:b3:3e:c3:a0:e3:63:55:1b: + f2:ba:ef:ad:39:e1:43:b9:38:a3:e6:2f:8a:26:3b:ef:a0:50: + 56:f9:c6:0a:fd:38:cd:c4:0b:70:51:94:97:98:04:df:c3:5f: + 94:d5:15:c9:14:41:9c:c4:5d:75:64:15:0d:ff:55:30:ec:86: + 8f:ff:0d:ef:2c:b9:63:46:f6:aa:fc:df:bc:69:fd:2e:12:48: + 64:9a:e0:95:f0:a6:ef:29:8f:01:b1:15:b5:0c:1d:a5:fe:69: + 2c:69:24:78:1e:b3:a7:1c:71:62:ee:ca:c8:97:ac:17:5d:8a: + c2:f8:47:86:6e:2a:c4:56:31:95:d0:67:89:85:2b:f9:6c:a6: + 5d:46:9d:0c:aa:82:e4:99:51:dd:70:b7:db:56:3d:61:e4:6a: + e1:5c:d6:f6:fe:3d:de:41:cc:07:ae:63:52:bf:53:53:f4:2b: + e9:c7:fd:b6:f7:82:5f:85:d2:41:18:db:81:b3:04:1c:c5:1f: + a4:80:6f:15:20:c9:de:0c:88:0a:1d:d6:66:55:e2:fc:48:c9: + 29:26:69:e0 +-----BEGIN CERTIFICATE----- +MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG +A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv +b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw +MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i +YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT +aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ +jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp +xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp +1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG +snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ +U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8 +9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E +BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B +AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz +yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE +38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP +AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad +DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME +HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== +-----END CERTIFICATE----- + +GlobalSign Root CA - R2 +# Issuer: CN=GlobalSign,O=GlobalSign,OU=GlobalSign Root CA - R2 +# Serial Number:04:00:00:00:00:01:0f:86:26:e6:0d +# Subject: CN=GlobalSign,O=GlobalSign,OU=GlobalSign Root CA - R2 +# Not Valid Before: Fri Dec 15 08:00:00 2006 +# Not Valid After : Wed Dec 15 08:00:00 2021 +# Fingerprint (MD5): 94:14:77:7E:3E:5E:FD:8F:30:BD:41:B0:CF:E7:D0:30 +# Fingerprint (SHA1): 75:E0:AB:B6:13:85:12:27:1C:04:F8:5F:DD:DE:38:E4:B7:24:2E:FE +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +MUST_VERIFY_TRUST: CODE_SIGNING +================================================ +MD5 Fingerprint=94:14:77:7E:3E:5E:FD:8F:30:BD:41:B0:CF:E7:D0:30 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 04:00:00:00:00:01:0f:86:26:e6:0d + Signature Algorithm: sha1WithRSAEncryption + Issuer: OU=GlobalSign Root CA - R2, O=GlobalSign, CN=GlobalSign + Validity + Not Before: Dec 15 08:00:00 2006 GMT + Not After : Dec 15 08:00:00 2021 GMT + Subject: OU=GlobalSign Root CA - R2, O=GlobalSign, CN=GlobalSign + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:a6:cf:24:0e:be:2e:6f:28:99:45:42:c4:ab:3e: + 21:54:9b:0b:d3:7f:84:70:fa:12:b3:cb:bf:87:5f: + c6:7f:86:d3:b2:30:5c:d6:fd:ad:f1:7b:dc:e5:f8: + 60:96:09:92:10:f5:d0:53:de:fb:7b:7e:73:88:ac: + 52:88:7b:4a:a6:ca:49:a6:5e:a8:a7:8c:5a:11:bc: + 7a:82:eb:be:8c:e9:b3:ac:96:25:07:97:4a:99:2a: + 07:2f:b4:1e:77:bf:8a:0f:b5:02:7c:1b:96:b8:c5: + b9:3a:2c:bc:d6:12:b9:eb:59:7d:e2:d0:06:86:5f: + 5e:49:6a:b5:39:5e:88:34:ec:bc:78:0c:08:98:84: + 6c:a8:cd:4b:b4:a0:7d:0c:79:4d:f0:b8:2d:cb:21: + ca:d5:6c:5b:7d:e1:a0:29:84:a1:f9:d3:94:49:cb: + 24:62:91:20:bc:dd:0b:d5:d9:cc:f9:ea:27:0a:2b: + 73:91:c6:9d:1b:ac:c8:cb:e8:e0:a0:f4:2f:90:8b: + 4d:fb:b0:36:1b:f6:19:7a:85:e0:6d:f2:61:13:88: + 5c:9f:e0:93:0a:51:97:8a:5a:ce:af:ab:d5:f7:aa: + 09:aa:60:bd:dc:d9:5f:df:72:a9:60:13:5e:00:01: + c9:4a:fa:3f:a4:ea:07:03:21:02:8e:82:ca:03:c2: + 9b:8f + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + 9B:E2:07:57:67:1C:1E:C0:6A:06:DE:59:B4:9A:2D:DF:DC:19:86:2E + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.globalsign.net/root-r2.crl + + X509v3 Authority Key Identifier: + keyid:9B:E2:07:57:67:1C:1E:C0:6A:06:DE:59:B4:9A:2D:DF:DC:19:86:2E + + Signature Algorithm: sha1WithRSAEncryption + 99:81:53:87:1c:68:97:86:91:ec:e0:4a:b8:44:0b:ab:81:ac: + 27:4f:d6:c1:b8:1c:43:78:b3:0c:9a:fc:ea:2c:3c:6e:61:1b: + 4d:4b:29:f5:9f:05:1d:26:c1:b8:e9:83:00:62:45:b6:a9:08: + 93:b9:a9:33:4b:18:9a:c2:f8:87:88:4e:db:dd:71:34:1a:c1: + 54:da:46:3f:e0:d3:2a:ab:6d:54:22:f5:3a:62:cd:20:6f:ba: + 29:89:d7:dd:91:ee:d3:5c:a2:3e:a1:5b:41:f5:df:e5:64:43: + 2d:e9:d5:39:ab:d2:a2:df:b7:8b:d0:c0:80:19:1c:45:c0:2d: + 8c:e8:f8:2d:a4:74:56:49:c5:05:b5:4f:15:de:6e:44:78:39: + 87:a8:7e:bb:f3:79:18:91:bb:f4:6f:9d:c1:f0:8c:35:8c:5d: + 01:fb:c3:6d:b9:ef:44:6d:79:46:31:7e:0a:fe:a9:82:c1:ff: + ef:ab:6e:20:c4:50:c9:5f:9d:4d:9b:17:8c:0c:e5:01:c9:a0: + 41:6a:73:53:fa:a5:50:b4:6e:25:0f:fb:4c:18:f4:fd:52:d9: + 8e:69:b1:e8:11:0f:de:88:d8:fb:1d:49:f7:aa:de:95:cf:20: + 78:c2:60:12:db:25:40:8c:6a:fc:7e:42:38:40:64:12:f7:9e: + 81:e1:93:2e +-----BEGIN CERTIFICATE----- +MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G +A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp +Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1 +MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG +A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL +v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8 +eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq +tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd +C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa +zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB +mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH +V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n +bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG +3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs +J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO +291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS +ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd +AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7 +TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg== +-----END CERTIFICATE----- + +Verisign Class 3 Public Primary Certification Authority - G3 +# Issuer: CN=VeriSign Class 3 Public Primary Certification Authority - G3,OU="(c) 1999 VeriSign, Inc. - For authorized use only",OU=VeriSign Trust Network,O="VeriSign, Inc.",C=US +# Serial Number:00:9b:7e:06:49:a3:3e:62:b9:d5:ee:90:48:71:29:ef:57 +# Subject: CN=VeriSign Class 3 Public Primary Certification Authority - G3,OU="(c) 1999 VeriSign, Inc. - For authorized use only",OU=VeriSign Trust Network,O="VeriSign, Inc.",C=US +# Not Valid Before: Fri Oct 01 00:00:00 1999 +# Not Valid After : Wed Jul 16 23:59:59 2036 +# Fingerprint (MD5): CD:68:B6:A7:C7:C4:CE:75:E0:1D:4F:57:44:61:92:09 +# Fingerprint (SHA1): 13:2D:0D:45:53:4B:69:97:CD:B2:D5:C3:39:E2:55:76:60:9B:5C:C6 +MUST_VERIFY_TRUST: CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +============================================================ +MD5 Fingerprint=CD:68:B6:A7:C7:C4:CE:75:E0:1D:4F:57:44:61:92:09 +Certificate: + Data: + Version: 1 (0x0) + Serial Number: + 9b:7e:06:49:a3:3e:62:b9:d5:ee:90:48:71:29:ef:57 + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 1999 VeriSign, Inc. - For authorized use only, CN=VeriSign Class 3 Public Primary Certification Authority - G3 + Validity + Not Before: Oct 1 00:00:00 1999 GMT + Not After : Jul 16 23:59:59 2036 GMT + Subject: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 1999 VeriSign, Inc. - For authorized use only, CN=VeriSign Class 3 Public Primary Certification Authority - G3 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:cb:ba:9c:52:fc:78:1f:1a:1e:6f:1b:37:73:bd: + f8:c9:6b:94:12:30:4f:f0:36:47:f5:d0:91:0a:f5: + 17:c8:a5:61:c1:16:40:4d:fb:8a:61:90:e5:76:20: + c1:11:06:7d:ab:2c:6e:a6:f5:11:41:8e:fa:2d:ad: + 2a:61:59:a4:67:26:4c:d0:e8:bc:52:5b:70:20:04: + 58:d1:7a:c9:a4:69:bc:83:17:64:ad:05:8b:bc:d0: + 58:ce:8d:8c:f5:eb:f0:42:49:0b:9d:97:27:67:32: + 6e:e1:ae:93:15:1c:70:bc:20:4d:2f:18:de:92:88: + e8:6c:85:57:11:1a:e9:7e:e3:26:11:54:a2:45:96: + 55:83:ca:30:89:e8:dc:d8:a3:ed:2a:80:3f:7f:79: + 65:57:3e:15:20:66:08:2f:95:93:bf:aa:47:2f:a8: + 46:97:f0:12:e2:fe:c2:0a:2b:51:e6:76:e6:b7:46: + b7:e2:0d:a6:cc:a8:c3:4c:59:55:89:e6:e8:53:5c: + 1c:ea:9d:f0:62:16:0b:a7:c9:5f:0c:f0:de:c2:76: + ce:af:f7:6a:f2:fa:41:a6:a2:33:14:c9:e5:7a:63: + d3:9e:62:37:d5:85:65:9e:0e:e6:53:24:74:1b:5e: + 1d:12:53:5b:c7:2c:e7:83:49:3b:15:ae:8a:68:b9: + 57:97 + Exponent: 65537 (0x10001) + Signature Algorithm: sha1WithRSAEncryption + 11:14:96:c1:ab:92:08:f7:3f:2f:c9:b2:fe:e4:5a:9f:64:de: + db:21:4f:86:99:34:76:36:57:dd:d0:15:2f:c5:ad:7f:15:1f: + 37:62:73:3e:d4:e7:5f:ce:17:03:db:35:fa:2b:db:ae:60:09: + 5f:1e:5f:8f:6e:bb:0b:3d:ea:5a:13:1e:0c:60:6f:b5:c0:b5: + 23:22:2e:07:0b:cb:a9:74:cb:47:bb:1d:c1:d7:a5:6b:cc:2f: + d2:42:fd:49:dd:a7:89:cf:53:ba:da:00:5a:28:bf:82:df:f8: + ba:13:1d:50:86:82:fd:8e:30:8f:29:46:b0:1e:3d:35:da:38: + 62:16:18:4a:ad:e6:b6:51:6c:de:af:62:eb:01:d0:1e:24:fe: + 7a:8f:12:1a:12:68:b8:fb:66:99:14:14:45:5c:ae:e7:ae:69: + 17:81:2b:5a:37:c9:5e:2a:f4:c6:e2:a1:5c:54:9b:a6:54:00: + cf:f0:f1:c1:c7:98:30:1a:3b:36:16:db:a3:6e:ea:fd:ad:b2: + c2:da:ef:02:47:13:8a:c0:f1:b3:31:ad:4f:1c:e1:4f:9c:af: + 0f:0c:9d:f7:78:0d:d8:f4:35:56:80:da:b7:6d:17:8f:9d:1e: + 81:64:e1:fe:c5:45:ba:ad:6b:b9:0a:7a:4e:4f:4b:84:ee:4b: + f1:7d:dd:11 +-----BEGIN CERTIFICATE----- +MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl +cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu +LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT +aWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp +dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD +VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT +aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ +bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu +IENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg +LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMu6nFL8eB8aHm8b +N3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1EUGO+i2t +KmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGu +kxUccLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBm +CC+Vk7+qRy+oRpfwEuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJ +Xwzw3sJ2zq/3avL6QaaiMxTJ5Xpj055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWu +imi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAERSWwauSCPc/L8my/uRan2Te +2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5fj267Cz3qWhMe +DGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC +/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565p +F4ErWjfJXir0xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGt +TxzhT5yvDwyd93gN2PQ1VoDat20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ== +-----END CERTIFICATE----- + +Entrust.net Premium 2048 Secure Server CA +# Issuer: CN=Entrust.net Certification Authority (2048),OU=(c) 1999 Entrust.net Limited,OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.),O=Entrust.net +# Serial Number: 946069240 (0x3863def8) +# Subject: CN=Entrust.net Certification Authority (2048),OU=(c) 1999 Entrust.net Limited,OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.),O=Entrust.net +# Not Valid Before: Fri Dec 24 17:50:51 1999 +# Not Valid After : Tue Jul 24 14:15:12 2029 +# Fingerprint (MD5): EE:29:31:BC:32:7E:9A:E6:E8:B5:F7:51:B4:34:71:90 +# Fingerprint (SHA1): 50:30:06:09:1D:97:D4:F5:AE:39:F7:CB:E7:92:7D:7D:65:2D:34:31 +MUST_VERIFY_TRUST: CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +================================================ +MD5 Fingerprint=EE:29:31:BC:32:7E:9A:E6:E8:B5:F7:51:B4:34:71:90 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 946069240 (0x3863def8) + Signature Algorithm: sha1WithRSAEncryption + Issuer: O=Entrust.net, OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.), OU=(c) 1999 Entrust.net Limited, CN=Entrust.net Certification Authority (2048) + Validity + Not Before: Dec 24 17:50:51 1999 GMT + Not After : Jul 24 14:15:12 2029 GMT + Subject: O=Entrust.net, OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.), OU=(c) 1999 Entrust.net Limited, CN=Entrust.net Certification Authority (2048) + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:ad:4d:4b:a9:12:86:b2:ea:a3:20:07:15:16:64: + 2a:2b:4b:d1:bf:0b:4a:4d:8e:ed:80:76:a5:67:b7: + 78:40:c0:73:42:c8:68:c0:db:53:2b:dd:5e:b8:76: + 98:35:93:8b:1a:9d:7c:13:3a:0e:1f:5b:b7:1e:cf: + e5:24:14:1e:b1:81:a9:8d:7d:b8:cc:6b:4b:03:f1: + 02:0c:dc:ab:a5:40:24:00:7f:74:94:a1:9d:08:29: + b3:88:0b:f5:87:77:9d:55:cd:e4:c3:7e:d7:6a:64: + ab:85:14:86:95:5b:97:32:50:6f:3d:c8:ba:66:0c: + e3:fc:bd:b8:49:c1:76:89:49:19:fd:c0:a8:bd:89: + a3:67:2f:c6:9f:bc:71:19:60:b8:2d:e9:2c:c9:90: + 76:66:7b:94:e2:af:78:d6:65:53:5d:3c:d6:9c:b2: + cf:29:03:f9:2f:a4:50:b2:d4:48:ce:05:32:55:8a: + fd:b2:64:4c:0e:e4:98:07:75:db:7f:df:b9:08:55: + 60:85:30:29:f9:7b:48:a4:69:86:e3:35:3f:1e:86: + 5d:7a:7a:15:bd:ef:00:8e:15:22:54:17:00:90:26: + 93:bc:0e:49:68:91:bf:f8:47:d3:9d:95:42:c1:0e: + 4d:df:6f:26:cf:c3:18:21:62:66:43:70:d6:d5:c0: + 07:e1 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + 55:E4:81:D1:11:80:BE:D8:89:B9:08:A3:31:F9:A1:24:09:16:B9:70 + Signature Algorithm: sha1WithRSAEncryption + 3b:9b:8f:56:9b:30:e7:53:99:7c:7a:79:a7:4d:97:d7:19:95: + 90:fb:06:1f:ca:33:7c:46:63:8f:96:66:24:fa:40:1b:21:27: + ca:e6:72:73:f2:4f:fe:31:99:fd:c8:0c:4c:68:53:c6:80:82: + 13:98:fa:b6:ad:da:5d:3d:f1:ce:6e:f6:15:11:94:82:0c:ee: + 3f:95:af:11:ab:0f:d7:2f:de:1f:03:8f:57:2c:1e:c9:bb:9a: + 1a:44:95:eb:18:4f:a6:1f:cd:7d:57:10:2f:9b:04:09:5a:84: + b5:6e:d8:1d:3a:e1:d6:9e:d1:6c:79:5e:79:1c:14:c5:e3:d0: + 4c:93:3b:65:3c:ed:df:3d:be:a6:e5:95:1a:c3:b5:19:c3:bd: + 5e:5b:bb:ff:23:ef:68:19:cb:12:93:27:5c:03:2d:6f:30:d0: + 1e:b6:1a:ac:de:5a:f7:d1:aa:a8:27:a6:fe:79:81:c4:79:99: + 33:57:ba:12:b0:a9:e0:42:6c:93:ca:56:de:fe:6d:84:0b:08: + 8b:7e:8d:ea:d7:98:21:c6:f3:e7:3c:79:2f:5e:9c:d1:4c:15: + 8d:e1:ec:22:37:cc:9a:43:0b:97:dc:80:90:8d:b3:67:9b:6f: + 48:08:15:56:cf:bf:f1:2b:7c:5e:9a:76:e9:59:90:c5:7c:83: + 35:11:65:51 +-----BEGIN CERTIFICATE----- +MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML +RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp +bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5 +IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0yOTA3 +MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3 +LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp +YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG +A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq +K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe +sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX +MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT +XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/ +HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH +4QIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV +HQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJKoZIhvcNAQEFBQADggEBADub +j1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPyT/4xmf3IDExo +U8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf +zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5b +u/8j72gZyxKTJ1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+ +bYQLCIt+jerXmCHG8+c8eS9enNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/Er +fF6adulZkMV8gzURZVE= +-----END CERTIFICATE----- + +Baltimore CyberTrust Root +# Issuer: CN=Baltimore CyberTrust Root,OU=CyberTrust,O=Baltimore,C=IE +# Serial Number: 33554617 (0x20000b9) +# Subject: CN=Baltimore CyberTrust Root,OU=CyberTrust,O=Baltimore,C=IE +# Not Valid Before: Fri May 12 18:46:00 2000 +# Not Valid After : Mon May 12 23:59:00 2025 +# Fingerprint (MD5): AC:B6:94:A5:9C:17:E0:D7:91:52:9B:B1:97:06:A6:E4 +# Fingerprint (SHA1): D4:DE:20:D0:5E:66:FC:53:FE:1A:50:88:2C:78:DB:28:52:CA:E4:74 +MUST_VERIFY_TRUST: CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +================================================ +MD5 Fingerprint=AC:B6:94:A5:9C:17:E0:D7:91:52:9B:B1:97:06:A6:E4 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 33554617 (0x20000b9) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=IE, O=Baltimore, OU=CyberTrust, CN=Baltimore CyberTrust Root + Validity + Not Before: May 12 18:46:00 2000 GMT + Not After : May 12 23:59:00 2025 GMT + Subject: C=IE, O=Baltimore, OU=CyberTrust, CN=Baltimore CyberTrust Root + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:a3:04:bb:22:ab:98:3d:57:e8:26:72:9a:b5:79: + d4:29:e2:e1:e8:95:80:b1:b0:e3:5b:8e:2b:29:9a: + 64:df:a1:5d:ed:b0:09:05:6d:db:28:2e:ce:62:a2: + 62:fe:b4:88:da:12:eb:38:eb:21:9d:c0:41:2b:01: + 52:7b:88:77:d3:1c:8f:c7:ba:b9:88:b5:6a:09:e7: + 73:e8:11:40:a7:d1:cc:ca:62:8d:2d:e5:8f:0b:a6: + 50:d2:a8:50:c3:28:ea:f5:ab:25:87:8a:9a:96:1c: + a9:67:b8:3f:0c:d5:f7:f9:52:13:2f:c2:1b:d5:70: + 70:f0:8f:c0:12:ca:06:cb:9a:e1:d9:ca:33:7a:77: + d6:f8:ec:b9:f1:68:44:42:48:13:d2:c0:c2:a4:ae: + 5e:60:fe:b6:a6:05:fc:b4:dd:07:59:02:d4:59:18: + 98:63:f5:a5:63:e0:90:0c:7d:5d:b2:06:7a:f3:85: + ea:eb:d4:03:ae:5e:84:3e:5f:ff:15:ed:69:bc:f9: + 39:36:72:75:cf:77:52:4d:f3:c9:90:2c:b9:3d:e5: + c9:23:53:3f:1f:24:98:21:5c:07:99:29:bd:c6:3a: + ec:e7:6e:86:3a:6b:97:74:63:33:bd:68:18:31:f0: + 78:8d:76:bf:fc:9e:8e:5d:2a:86:a7:4d:90:dc:27: + 1a:39 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + E5:9D:59:30:82:47:58:CC:AC:FA:08:54:36:86:7B:3A:B5:04:4D:F0 + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:3 + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + Signature Algorithm: sha1WithRSAEncryption + 85:0c:5d:8e:e4:6f:51:68:42:05:a0:dd:bb:4f:27:25:84:03: + bd:f7:64:fd:2d:d7:30:e3:a4:10:17:eb:da:29:29:b6:79:3f: + 76:f6:19:13:23:b8:10:0a:f9:58:a4:d4:61:70:bd:04:61:6a: + 12:8a:17:d5:0a:bd:c5:bc:30:7c:d6:e9:0c:25:8d:86:40:4f: + ec:cc:a3:7e:38:c6:37:11:4f:ed:dd:68:31:8e:4c:d2:b3:01: + 74:ee:be:75:5e:07:48:1a:7f:70:ff:16:5c:84:c0:79:85:b8: + 05:fd:7f:be:65:11:a3:0f:c0:02:b4:f8:52:37:39:04:d5:a9: + 31:7a:18:bf:a0:2a:f4:12:99:f7:a3:45:82:e3:3c:5e:f5:9d: + 9e:b5:c8:9e:7c:2e:c8:a4:9e:4e:08:14:4b:6d:fd:70:6d:6b: + 1a:63:bd:64:e6:1f:b7:ce:f0:f2:9f:2e:bb:1b:b7:f2:50:88: + 73:92:c2:e2:e3:16:8d:9a:32:02:ab:8e:18:dd:e9:10:11:ee: + 7e:35:ab:90:af:3e:30:94:7a:d0:33:3d:a7:65:0f:f5:fc:8e: + 9e:62:cf:47:44:2c:01:5d:bb:1d:b5:32:d2:47:d2:38:2e:d0: + fe:81:dc:32:6a:1e:b5:ee:3c:d5:fc:e7:81:1d:19:c3:24:42: + ea:63:39:a9 +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ +RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD +VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX +DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y +ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy +VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr +mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr +IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK +mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu +XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy +dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye +jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1 +BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3 +DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92 +9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx +jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0 +Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz +ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS +R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp +-----END CERTIFICATE----- + +AddTrust External Root +# Issuer: CN=AddTrust External CA Root,OU=AddTrust External TTP Network,O=AddTrust AB,C=SE +# Serial Number: 1 (0x1) +# Subject: CN=AddTrust External CA Root,OU=AddTrust External TTP Network,O=AddTrust AB,C=SE +# Not Valid Before: Tue May 30 10:48:38 2000 +# Not Valid After : Sat May 30 10:48:38 2020 +# Fingerprint (MD5): 1D:35:54:04:85:78:B0:3F:42:42:4D:BF:20:73:0A:3F +# Fingerprint (SHA1): 02:FA:F3:E2:91:43:54:68:60:78:57:69:4D:F5:E4:5B:68:85:18:68 +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +MUST_VERIFY_TRUST: CODE_SIGNING +================================================ +MD5 Fingerprint=1D:35:54:04:85:78:B0:3F:42:42:4D:BF:20:73:0A:3F +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 1 (0x1) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=SE, O=AddTrust AB, OU=AddTrust External TTP Network, CN=AddTrust External CA Root + Validity + Not Before: May 30 10:48:38 2000 GMT + Not After : May 30 10:48:38 2020 GMT + Subject: C=SE, O=AddTrust AB, OU=AddTrust External TTP Network, CN=AddTrust External CA Root + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:b7:f7:1a:33:e6:f2:00:04:2d:39:e0:4e:5b:ed: + 1f:bc:6c:0f:cd:b5:fa:23:b6:ce:de:9b:11:33:97: + a4:29:4c:7d:93:9f:bd:4a:bc:93:ed:03:1a:e3:8f: + cf:e5:6d:50:5a:d6:97:29:94:5a:80:b0:49:7a:db: + 2e:95:fd:b8:ca:bf:37:38:2d:1e:3e:91:41:ad:70: + 56:c7:f0:4f:3f:e8:32:9e:74:ca:c8:90:54:e9:c6: + 5f:0f:78:9d:9a:40:3c:0e:ac:61:aa:5e:14:8f:9e: + 87:a1:6a:50:dc:d7:9a:4e:af:05:b3:a6:71:94:9c: + 71:b3:50:60:0a:c7:13:9d:38:07:86:02:a8:e9:a8: + 69:26:18:90:ab:4c:b0:4f:23:ab:3a:4f:84:d8:df: + ce:9f:e1:69:6f:bb:d7:42:d7:6b:44:e4:c7:ad:ee: + 6d:41:5f:72:5a:71:08:37:b3:79:65:a4:59:a0:94: + 37:f7:00:2f:0d:c2:92:72:da:d0:38:72:db:14:a8: + 45:c4:5d:2a:7d:b7:b4:d6:c4:ee:ac:cd:13:44:b7: + c9:2b:dd:43:00:25:fa:61:b9:69:6a:58:23:11:b7: + a7:33:8f:56:75:59:f5:cd:29:d7:46:b7:0a:2b:65: + b6:d3:42:6f:15:b2:b8:7b:fb:ef:e9:5d:53:d5:34: + 5a:27 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + AD:BD:98:7A:34:B4:26:F7:FA:C4:26:54:EF:03:BD:E0:24:CB:54:1A + X509v3 Key Usage: + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Authority Key Identifier: + keyid:AD:BD:98:7A:34:B4:26:F7:FA:C4:26:54:EF:03:BD:E0:24:CB:54:1A + DirName:/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root + serial:01 + + Signature Algorithm: sha1WithRSAEncryption + b0:9b:e0:85:25:c2:d6:23:e2:0f:96:06:92:9d:41:98:9c:d9: + 84:79:81:d9:1e:5b:14:07:23:36:65:8f:b0:d8:77:bb:ac:41: + 6c:47:60:83:51:b0:f9:32:3d:e7:fc:f6:26:13:c7:80:16:a5: + bf:5a:fc:87:cf:78:79:89:21:9a:e2:4c:07:0a:86:35:bc:f2: + de:51:c4:d2:96:b7:dc:7e:4e:ee:70:fd:1c:39:eb:0c:02:51: + 14:2d:8e:bd:16:e0:c1:df:46:75:e7:24:ad:ec:f4:42:b4:85: + 93:70:10:67:ba:9d:06:35:4a:18:d3:2b:7a:cc:51:42:a1:7a: + 63:d1:e6:bb:a1:c5:2b:c2:36:be:13:0d:e6:bd:63:7e:79:7b: + a7:09:0d:40:ab:6a:dd:8f:8a:c3:f6:f6:8c:1a:42:05:51:d4: + 45:f5:9f:a7:62:21:68:15:20:43:3c:99:e7:7c:bd:24:d8:a9: + 91:17:73:88:3f:56:1b:31:38:18:b4:71:0f:9a:cd:c8:0e:9e: + 8e:2e:1b:e1:8c:98:83:cb:1f:31:f1:44:4c:c6:04:73:49:76: + 60:0f:c7:f8:bd:17:80:6b:2e:e9:cc:4c:0e:5a:9a:79:0f:20: + 0a:2e:d5:9e:63:26:1e:55:92:94:d8:82:17:5a:7b:d0:bc:c7: + 8f:4e:86:04 +-----BEGIN CERTIFICATE----- +MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU +MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs +IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290 +MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux +FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h +bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v +dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt +H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9 +uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX +mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX +a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN +E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0 +WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD +VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0 +Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU +cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx +IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN +AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH +YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5 +6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC +Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX +c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a +mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ= +-----END CERTIFICATE----- + +Entrust Root Certification Authority +# Issuer: CN=Entrust Root Certification Authority,OU="(c) 2006 Entrust, Inc.",OU=www.entrust.net/CPS is incorporated by reference,O="Entrust, Inc.",C=US +# Serial Number: 1164660820 (0x456b5054) +# Subject: CN=Entrust Root Certification Authority,OU="(c) 2006 Entrust, Inc.",OU=www.entrust.net/CPS is incorporated by reference,O="Entrust, Inc.",C=US +# Not Valid Before: Mon Nov 27 20:23:42 2006 +# Not Valid After : Fri Nov 27 20:53:42 2026 +# Fingerprint (MD5): D6:A5:C3:ED:5D:DD:3E:00:C1:3D:87:92:1F:1D:3F:E4 +# Fingerprint (SHA1): B3:1E:B1:B7:40:E3:6C:84:02:DA:DC:37:D4:4D:F5:D4:67:49:52:F9 +TRUSTED_DELEGATOR: SERVER_AUTH +MUST_VERIFY_TRUST: EMAIL_PROTECTION, CODE_SIGNING +================================================= +MD5 Fingerprint=D6:A5:C3:ED:5D:DD:3E:00:C1:3D:87:92:1F:1D:3F:E4 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 1164660820 (0x456b5054) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=Entrust, Inc., OU=www.entrust.net/CPS is incorporated by reference, OU=(c) 2006 Entrust, Inc., CN=Entrust Root Certification Authority + Validity + Not Before: Nov 27 20:23:42 2006 GMT + Not After : Nov 27 20:53:42 2026 GMT + Subject: C=US, O=Entrust, Inc., OU=www.entrust.net/CPS is incorporated by reference, OU=(c) 2006 Entrust, Inc., CN=Entrust Root Certification Authority + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:b6:95:b6:43:42:fa:c6:6d:2a:6f:48:df:94:4c: + 39:57:05:ee:c3:79:11:41:68:36:ed:ec:fe:9a:01: + 8f:a1:38:28:fc:f7:10:46:66:2e:4d:1e:1a:b1:1a: + 4e:c6:d1:c0:95:88:b0:c9:ff:31:8b:33:03:db:b7: + 83:7b:3e:20:84:5e:ed:b2:56:28:a7:f8:e0:b9:40: + 71:37:c5:cb:47:0e:97:2a:68:c0:22:95:62:15:db: + 47:d9:f5:d0:2b:ff:82:4b:c9:ad:3e:de:4c:db:90: + 80:50:3f:09:8a:84:00:ec:30:0a:3d:18:cd:fb:fd: + 2a:59:9a:23:95:17:2c:45:9e:1f:6e:43:79:6d:0c: + 5c:98:fe:48:a7:c5:23:47:5c:5e:fd:6e:e7:1e:b4: + f6:68:45:d1:86:83:5b:a2:8a:8d:b1:e3:29:80:fe: + 25:71:88:ad:be:bc:8f:ac:52:96:4b:aa:51:8d:e4: + 13:31:19:e8:4e:4d:9f:db:ac:b3:6a:d5:bc:39:54: + 71:ca:7a:7a:7f:90:dd:7d:1d:80:d9:81:bb:59:26: + c2:11:fe:e6:93:e2:f7:80:e4:65:fb:34:37:0e:29: + 80:70:4d:af:38:86:2e:9e:7f:57:af:9e:17:ae:eb: + 1c:cb:28:21:5f:b6:1c:d8:e7:a2:04:22:f9:d3:da: + d8:cb + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Private Key Usage Period: + Not Before: Nov 27 20:23:42 2006 GMT, Not After: Nov 27 20:53:42 2026 GMT + X509v3 Authority Key Identifier: + keyid:68:90:E4:67:A4:A6:53:80:C7:86:66:A4:F1:F7:4B:43:FB:84:BD:6D + + X509v3 Subject Key Identifier: + 68:90:E4:67:A4:A6:53:80:C7:86:66:A4:F1:F7:4B:43:FB:84:BD:6D + 1.2.840.113533.7.65.0: + 0...V7.1:4.0.... + Signature Algorithm: sha1WithRSAEncryption + 93:d4:30:b0:d7:03:20:2a:d0:f9:63:e8:91:0c:05:20:a9:5f: + 19:ca:7b:72:4e:d4:b1:db:d0:96:fb:54:5a:19:2c:0c:08:f7: + b2:bc:85:a8:9d:7f:6d:3b:52:b3:2a:db:e7:d4:84:8c:63:f6: + 0f:cb:26:01:91:50:6c:f4:5f:14:e2:93:74:c0:13:9e:30:3a: + 50:e3:b4:60:c5:1c:f0:22:44:8d:71:47:ac:c8:1a:c9:e9:9b: + 9a:00:60:13:ff:70:7e:5f:11:4d:49:1b:b3:15:52:7b:c9:54: + da:bf:9d:95:af:6b:9a:d8:9e:e9:f1:e4:43:8d:e2:11:44:3a: + bf:af:bd:83:42:73:52:8b:aa:bb:a7:29:cf:f5:64:1c:0a:4d: + d1:bc:aa:ac:9f:2a:d0:ff:7f:7f:da:7d:ea:b1:ed:30:25:c1: + 84:da:34:d2:5b:78:83:56:ec:9c:36:c3:26:e2:11:f6:67:49: + 1d:92:ab:8c:fb:eb:ff:7a:ee:85:4a:a7:50:80:f0:a7:5c:4a: + 94:2e:5f:05:99:3c:52:41:e0:cd:b4:63:cf:01:43:ba:9c:83: + dc:8f:60:3b:f3:5a:b4:b4:7b:ae:da:0b:90:38:75:ef:81:1d: + 66:d2:f7:57:70:36:b3:bf:fc:28:af:71:25:85:5b:13:fe:1e: + 7f:5a:b4:3c +-----BEGIN CERTIFICATE----- +MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC +VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0 +Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW +KGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENl +cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0MloXDTI2MTEyNzIw +NTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMTkw +NwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSBy +ZWZlcmVuY2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNV +BAMTJEVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBALaVtkNC+sZtKm9I35RMOVcF7sN5EUFo +Nu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYszA9u3g3s+IIRe7bJWKKf4 +4LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOwwCj0Yzfv9 +KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGI +rb68j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi +94DkZfs0Nw4pgHBNrziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOB +sDCBrTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAi +gA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1MzQyWjAfBgNVHSMEGDAWgBRo +kORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DHhmak8fdLQ/uE +vW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA +A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9t +O1KzKtvn1ISMY/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6Zua +AGAT/3B+XxFNSRuzFVJ7yVTav52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP +9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTSW3iDVuycNsMm4hH2Z0kdkquM++v/ +eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m +0vdXcDazv/wor3ElhVsT/h5/WrQ8 +-----END CERTIFICATE----- + +GeoTrust Global CA +# Issuer: CN=GeoTrust Global CA,O=GeoTrust Inc.,C=US +# Serial Number: 144470 (0x23456) +# Subject: CN=GeoTrust Global CA,O=GeoTrust Inc.,C=US +# Not Valid Before: Tue May 21 04:00:00 2002 +# Not Valid After : Sat May 21 04:00:00 2022 +# Fingerprint (MD5): F7:75:AB:29:FB:51:4E:B7:77:5E:FF:05:3C:99:8E:F5 +# Fingerprint (SHA1): DE:28:F4:A4:FF:E5:B9:2F:A3:C5:03:D1:A3:49:A7:F9:96:2A:82:12 +MUST_VERIFY_TRUST: CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +================================================ +MD5 Fingerprint=F7:75:AB:29:FB:51:4E:B7:77:5E:FF:05:3C:99:8E:F5 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 144470 (0x23456) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=GeoTrust Inc., CN=GeoTrust Global CA + Validity + Not Before: May 21 04:00:00 2002 GMT + Not After : May 21 04:00:00 2022 GMT + Subject: C=US, O=GeoTrust Inc., CN=GeoTrust Global CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:da:cc:18:63:30:fd:f4:17:23:1a:56:7e:5b:df: + 3c:6c:38:e4:71:b7:78:91:d4:bc:a1:d8:4c:f8:a8: + 43:b6:03:e9:4d:21:07:08:88:da:58:2f:66:39:29: + bd:05:78:8b:9d:38:e8:05:b7:6a:7e:71:a4:e6:c4: + 60:a6:b0:ef:80:e4:89:28:0f:9e:25:d6:ed:83:f3: + ad:a6:91:c7:98:c9:42:18:35:14:9d:ad:98:46:92: + 2e:4f:ca:f1:87:43:c1:16:95:57:2d:50:ef:89:2d: + 80:7a:57:ad:f2:ee:5f:6b:d2:00:8d:b9:14:f8:14: + 15:35:d9:c0:46:a3:7b:72:c8:91:bf:c9:55:2b:cd: + d0:97:3e:9c:26:64:cc:df:ce:83:19:71:ca:4e:e6: + d4:d5:7b:a9:19:cd:55:de:c8:ec:d2:5e:38:53:e5: + 5c:4f:8c:2d:fe:50:23:36:fc:66:e6:cb:8e:a4:39: + 19:00:b7:95:02:39:91:0b:0e:fe:38:2e:d1:1d:05: + 9a:f6:4d:3e:6f:0f:07:1d:af:2c:1e:8f:60:39:e2: + fa:36:53:13:39:d4:5e:26:2b:db:3d:a8:14:bd:32: + eb:18:03:28:52:04:71:e5:ab:33:3d:e1:38:bb:07: + 36:84:62:9c:79:ea:16:30:f4:5f:c0:2b:e8:71:6b: + e4:f9 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + C0:7A:98:68:8D:89:FB:AB:05:64:0C:11:7D:AA:7D:65:B8:CA:CC:4E + X509v3 Authority Key Identifier: + keyid:C0:7A:98:68:8D:89:FB:AB:05:64:0C:11:7D:AA:7D:65:B8:CA:CC:4E + + Signature Algorithm: sha1WithRSAEncryption + 35:e3:29:6a:e5:2f:5d:54:8e:29:50:94:9f:99:1a:14:e4:8f: + 78:2a:62:94:a2:27:67:9e:d0:cf:1a:5e:47:e9:c1:b2:a4:cf: + dd:41:1a:05:4e:9b:4b:ee:4a:6f:55:52:b3:24:a1:37:0a:eb: + 64:76:2a:2e:2c:f3:fd:3b:75:90:bf:fa:71:d8:c7:3d:37:d2: + b5:05:95:62:b9:a6:de:89:3d:36:7b:38:77:48:97:ac:a6:20: + 8f:2e:a6:c9:0c:c2:b2:99:45:00:c7:ce:11:51:22:22:e0:a5: + ea:b6:15:48:09:64:ea:5e:4f:74:f7:05:3e:c7:8a:52:0c:db: + 15:b4:bd:6d:9b:e5:c6:b1:54:68:a9:e3:69:90:b6:9a:a5:0f: + b8:b9:3f:20:7d:ae:4a:b5:b8:9c:e4:1d:b6:ab:e6:94:a5:c1: + c7:83:ad:db:f5:27:87:0e:04:6c:d5:ff:dd:a0:5d:ed:87:52: + b7:2b:15:02:ae:39:a6:6a:74:e9:da:c4:e7:bc:4d:34:1e:a9: + 5c:4d:33:5f:92:09:2f:88:66:5d:77:97:c7:1d:76:13:a9:d5: + e5:f1:16:09:11:35:d5:ac:db:24:71:70:2c:98:56:0b:d9:17: + b4:d1:e3:51:2b:5e:75:e8:d5:d0:dc:4f:34:ed:c2:05:66:80: + a1:cb:e6:33 +-----BEGIN CERTIFICATE----- +MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT +MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i +YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG +EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg +R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9 +9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq +fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv +iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU +1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+ +bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW +MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA +ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l +uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn +Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS +tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF +PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un +hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV +5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw== +-----END CERTIFICATE----- + +GeoTrust Universal CA +# Issuer: CN=GeoTrust Universal CA,O=GeoTrust Inc.,C=US +# Serial Number: 1 (0x1) +# Subject: CN=GeoTrust Universal CA,O=GeoTrust Inc.,C=US +# Not Valid Before: Thu Mar 04 05:00:00 2004 +# Not Valid After : Sun Mar 04 05:00:00 2029 +# Fingerprint (MD5): 92:65:58:8B:A2:1A:31:72:73:68:5C:B4:A5:7A:07:48 +# Fingerprint (SHA1): E6:21:F3:35:43:79:05:9A:4B:68:30:9D:8A:2F:74:22:15:87:EC:79 +MUST_VERIFY_TRUST: CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +================================================ +MD5 Fingerprint=92:65:58:8B:A2:1A:31:72:73:68:5C:B4:A5:7A:07:48 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 1 (0x1) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=GeoTrust Inc., CN=GeoTrust Universal CA + Validity + Not Before: Mar 4 05:00:00 2004 GMT + Not After : Mar 4 05:00:00 2029 GMT + Subject: C=US, O=GeoTrust Inc., CN=GeoTrust Universal CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:a6:15:55:a0:a3:c6:e0:1f:8c:9d:21:50:d7:c1: + be:2b:5b:b5:a4:9e:a1:d9:72:58:bd:00:1b:4c:bf: + 61:c9:14:1d:45:82:ab:c6:1d:80:d6:3d:eb:10:9c: + 3a:af:6d:24:f8:bc:71:01:9e:06:f5:7c:5f:1e:c1: + 0e:55:ca:83:9a:59:30:ae:19:cb:30:48:95:ed:22: + 37:8d:f4:4a:9a:72:66:3e:ad:95:c0:e0:16:00:e0: + 10:1f:2b:31:0e:d7:94:54:d3:42:33:a0:34:1d:1e: + 45:76:dd:4f:ca:18:37:ec:85:15:7a:19:08:fc:d5: + c7:9c:f0:f2:a9:2e:10:a9:92:e6:3d:58:3d:a9:16: + 68:3c:2f:75:21:18:7f:28:77:a5:e1:61:17:b7:a6: + e9:f8:1e:99:db:73:6e:f4:0a:a2:21:6c:ee:da:aa: + 85:92:66:af:f6:7a:6b:82:da:ba:22:08:35:0f:cf: + 42:f1:35:fa:6a:ee:7e:2b:25:cc:3a:11:e4:6d:af: + 73:b2:76:1d:ad:d0:b2:78:67:1a:a4:39:1c:51:0b: + 67:56:83:fd:38:5d:0d:ce:dd:f0:bb:2b:96:1f:de: + 7b:32:52:fd:1d:bb:b5:06:a1:b2:21:5e:a5:d6:95: + 68:7f:f0:99:9e:dc:45:08:3e:e7:d2:09:0d:35:94: + dd:80:4e:53:97:d7:b5:09:44:20:64:16:17:03:02: + 4c:53:0d:68:de:d5:aa:72:4d:93:6d:82:0e:db:9c: + bd:cf:b4:f3:5c:5d:54:7a:69:09:96:d6:db:11:c1: + 8d:75:a8:b4:cf:39:c8:ce:3c:bc:24:7c:e6:62:ca: + e1:bd:7d:a7:bd:57:65:0b:e4:fe:25:ed:b6:69:10: + dc:28:1a:46:bd:01:1d:d0:97:b5:e1:98:3b:c0:37: + 64:d6:3d:94:ee:0b:e1:f5:28:ae:0b:56:bf:71:8b: + 23:29:41:8e:86:c5:4b:52:7b:d8:71:ab:1f:8a:15: + a6:3b:83:5a:d7:58:01:51:c6:4c:41:d9:7f:d8:41: + 67:72:a2:28:df:60:83:a9:9e:c8:7b:fc:53:73:72: + 59:f5:93:7a:17:76:0e:ce:f7:e5:5c:d9:0b:55:34: + a2:aa:5b:b5:6a:54:e7:13:ca:57:ec:97:6d:f4:5e: + 06:2f:45:8b:58:d4:23:16:92:e4:16:6e:28:63:59: + 30:df:50:01:9c:63:89:1a:9f:db:17:94:82:70:37: + c3:24:9e:9a:47:d6:5a:ca:4e:a8:69:89:72:1f:91: + 6c:db:7e:9e:1b:ad:c7:1f:73:dd:2c:4f:19:65:fd: + 7f:93:40:10:2e:d2:f0:ed:3c:9e:2e:28:3e:69:26: + 33:c5:7b + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + DA:BB:2E:AA:B0:0C:B8:88:26:51:74:5C:6D:03:D3:C0:D8:8F:7A:D6 + X509v3 Authority Key Identifier: + keyid:DA:BB:2E:AA:B0:0C:B8:88:26:51:74:5C:6D:03:D3:C0:D8:8F:7A:D6 + + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + Signature Algorithm: sha1WithRSAEncryption + 31:78:e6:c7:b5:df:b8:94:40:c9:71:c4:a8:35:ec:46:1d:c2: + 85:f3:28:58:86:b0:0b:fc:8e:b2:39:8f:44:55:ab:64:84:5c: + 69:a9:d0:9a:38:3c:fa:e5:1f:35:e5:44:e3:80:79:94:68:a4: + bb:c4:9f:3d:e1:34:cd:30:46:8b:54:2b:95:a5:ef:f7:3f:99: + 84:fd:35:e6:cf:31:c6:dc:6a:bf:a7:d7:23:08:e1:98:5e:c3: + 5a:08:76:a9:a6:af:77:2f:b7:60:bd:44:46:6a:ef:97:ff:73: + 95:c1:8e:e8:93:fb:fd:31:b7:ec:57:11:11:45:9b:30:f1:1a: + 88:39:c1:4f:3c:a7:00:d5:c7:fc:ab:6d:80:22:70:a5:0c:e0: + 5d:04:29:02:fb:cb:a0:91:d1:7c:d6:c3:7e:50:d5:9d:58:be: + 41:38:eb:b9:75:3c:15:d9:9b:c9:4a:83:59:c0:da:53:fd:33: + bb:36:18:9b:85:0f:15:dd:ee:2d:ac:76:93:b9:d9:01:8d:48: + 10:a8:fb:f5:38:86:f1:db:0a:c6:bd:84:a3:23:41:de:d6:77: + 6f:85:d4:85:1c:50:e0:ae:51:8a:ba:8d:3e:76:e2:b9:ca:27: + f2:5f:9f:ef:6e:59:0d:06:d8:2b:17:a4:d2:7c:6b:bb:5f:14: + 1a:48:8f:1a:4c:e7:b3:47:1c:8e:4c:45:2b:20:ee:48:df:e7: + dd:09:8e:18:a8:da:40:8d:92:26:11:53:61:73:5d:eb:bd:e7: + c4:4d:29:37:61:eb:ac:39:2d:67:2e:16:d6:f5:00:83:85:a1: + cc:7f:76:c4:7d:e4:b7:4b:66:ef:03:45:60:69:b6:0c:52:96: + 92:84:5e:a6:a3:b5:a4:3e:2b:d9:cc:d8:1b:47:aa:f2:44:da: + 4f:f9:03:e8:f0:14:cb:3f:f3:83:de:d0:c1:54:e3:b7:e8:0a: + 37:4d:8b:20:59:03:30:19:a1:2c:c8:bd:11:1f:df:ae:c9:4a: + c5:f3:27:66:66:86:ac:68:91:ff:d9:e6:53:1c:0f:8b:5c:69: + 65:0a:26:c8:1e:34:c3:5d:51:7b:d7:a9:9c:06:a1:36:dd:d5: + 89:94:bc:d9:e4:2d:0c:5e:09:6c:08:97:7c:a3:3d:7c:93:ff: + 3f:a1:14:a7:cf:b5:5d:eb:db:db:1c:c4:76:df:88:b9:bd:45: + 05:95:1b:ae:fc:46:6a:4c:af:48:e3:ce:ae:0f:d2:7e:eb:e6: + 6c:9c:4f:81:6a:7a:64:ac:bb:3e:d5:e7:cb:76:2e:c5:a7:48: + c1:5c:90:0f:cb:c8:3f:fa:e6:32:e1:8d:1b:6f:a4:e6:8e:d8: + f9:29:48:8a:ce:73:fe:2c +-----BEGIN CERTIFICATE----- +MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEW +MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVy +c2FsIENBMB4XDTA0MDMwNDA1MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UE +BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xHjAcBgNVBAMTFUdlb1RydXN0 +IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKYV +VaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9tJPi8 +cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTT +QjOgNB0eRXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFh +F7em6fgemdtzbvQKoiFs7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2v +c7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d8Lsrlh/eezJS/R27tQahsiFepdaVaH/w +mZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7VqnJNk22CDtucvc+081xd +VHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3CgaRr0BHdCX +teGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZ +f9hBZ3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfRe +Bi9Fi1jUIxaS5BZuKGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+ +nhutxx9z3SxPGWX9f5NAEC7S8O08ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB +/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0XG0D08DYj3rWMB8GA1UdIwQY +MBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG +9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc +aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fX +IwjhmF7DWgh2qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzyn +ANXH/KttgCJwpQzgXQQpAvvLoJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0z +uzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsKxr2EoyNB3tZ3b4XUhRxQ4K5RirqN +Pnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxFKyDuSN/n3QmOGKja +QI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2DFKW +koRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9 +ER/frslKxfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQt +DF4JbAiXfKM9fJP/P6EUp8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/Sfuvm +bJxPgWp6ZKy7PtXny3YuxadIwVyQD8vIP/rmMuGNG2+k5o7Y+SlIis5z/iw= +-----END CERTIFICATE----- + +GeoTrust Universal CA 2 +# Issuer: CN=GeoTrust Universal CA 2,O=GeoTrust Inc.,C=US +# Serial Number: 1 (0x1) +# Subject: CN=GeoTrust Universal CA 2,O=GeoTrust Inc.,C=US +# Not Valid Before: Thu Mar 04 05:00:00 2004 +# Not Valid After : Sun Mar 04 05:00:00 2029 +# Fingerprint (MD5): 34:FC:B8:D0:36:DB:9E:14:B3:C2:F2:DB:8F:E4:94:C7 +# Fingerprint (SHA1): 37:9A:19:7B:41:85:45:35:0C:A6:03:69:F3:3C:2E:AF:47:4F:20:79 +MUST_VERIFY_TRUST: CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +================================================ +MD5 Fingerprint=34:FC:B8:D0:36:DB:9E:14:B3:C2:F2:DB:8F:E4:94:C7 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 1 (0x1) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=GeoTrust Inc., CN=GeoTrust Universal CA 2 + Validity + Not Before: Mar 4 05:00:00 2004 GMT + Not After : Mar 4 05:00:00 2029 GMT + Subject: C=US, O=GeoTrust Inc., CN=GeoTrust Universal CA 2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:b3:54:52:c1:c9:3e:f2:d9:dc:b1:53:1a:59:29: + e7:b1:c3:45:28:e5:d7:d1:ed:c5:c5:4b:a1:aa:74: + 7b:57:af:4a:26:fc:d8:f5:5e:a7:6e:19:db:74:0c: + 4f:35:5b:32:0b:01:e3:db:eb:7a:77:35:ea:aa:5a: + e0:d6:e8:a1:57:94:f0:90:a3:74:56:94:44:30:03: + 1e:5c:4e:2b:85:26:74:82:7a:0c:76:a0:6f:4d:ce: + 41:2d:a0:15:06:14:5f:b7:42:cd:7b:8f:58:61:34: + dc:2a:08:f9:2e:c3:01:a6:22:44:1c:4c:07:82:e6: + 5b:ce:d0:4a:7c:04:d3:19:73:27:f0:aa:98:7f:2e: + af:4e:eb:87:1e:24:77:6a:5d:b6:e8:5b:45:ba:dc: + c3:a1:05:6f:56:8e:8f:10:26:a5:49:c3:2e:d7:41: + 87:22:e0:4f:86:ca:60:b5:ea:a1:63:c0:01:97:10: + 79:bd:00:3c:12:6d:2b:15:b1:ac:4b:b1:ee:18:b9: + 4e:96:dc:dc:76:ff:3b:be:cf:5f:03:c0:fc:3b:e8: + be:46:1b:ff:da:40:c2:52:f7:fe:e3:3a:f7:6a:77: + 35:d0:da:8d:eb:5e:18:6a:31:c7:1e:ba:3c:1b:28: + d6:6b:54:c6:aa:5b:d7:a2:2c:1b:19:cc:a2:02:f6: + 9b:59:bd:37:6b:86:b5:6d:82:ba:d8:ea:c9:56:bc: + a9:36:58:fd:3e:19:f3:ed:0c:26:a9:93:38:f8:4f: + c1:5d:22:06:d0:97:ea:e1:ad:c6:55:e0:81:2b:28: + 83:3a:fa:f4:7b:21:51:00:be:52:38:ce:cd:66:79: + a8:f4:81:56:e2:d0:83:09:47:51:5b:50:6a:cf:db: + 48:1a:5d:3e:f7:cb:f6:65:f7:6c:f1:95:f8:02:3b: + 32:56:82:39:7a:5b:bd:2f:89:1b:bf:a1:b4:e8:ff: + 7f:8d:8c:df:03:f1:60:4e:58:11:4c:eb:a3:3f:10: + 2b:83:9a:01:73:d9:94:6d:84:00:27:66:ac:f0:70: + 40:09:42:92:ad:4f:93:0d:61:09:51:24:d8:92:d5: + 0b:94:61:b2:87:b2:ed:ff:9a:35:ff:85:54:ca:ed: + 44:43:ac:1b:3c:16:6b:48:4a:0a:1c:40:88:1f:92: + c2:0b:00:05:ff:f2:c8:02:4a:a4:aa:a9:cc:99:96: + 9c:2f:58:e0:7d:e1:be:bb:07:dc:5f:04:72:5c:31: + 34:c3:ec:5f:2d:e0:3d:64:90:22:e6:d1:ec:b8:2e: + dd:59:ae:d9:a1:37:bf:54:35:dc:73:32:4f:8c:04: + 1e:33:b2:c9:46:f1:d8:5c:c8:55:50:c9:68:bd:a8: + ba:36:09 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + 76:F3:55:E1:FA:A4:36:FB:F0:9F:5C:62:71:ED:3C:F4:47:38:10:2B + X509v3 Authority Key Identifier: + keyid:76:F3:55:E1:FA:A4:36:FB:F0:9F:5C:62:71:ED:3C:F4:47:38:10:2B + + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + Signature Algorithm: sha1WithRSAEncryption + 66:c1:c6:23:f3:d9:e0:2e:6e:5f:e8:cf:ae:b0:b0:25:4d:2b: + f8:3b:58:9b:40:24:37:5a:cb:ab:16:49:ff:b3:75:79:33:a1: + 2f:6d:70:17:34:91:fe:67:7e:8f:ec:9b:e5:5e:82:a9:55:1f: + 2f:dc:d4:51:07:12:fe:ac:16:3e:2c:35:c6:63:fc:dc:10:eb: + 0d:a3:aa:d0:7c:cc:d1:d0:2f:51:2e:c4:14:5a:de:e8:19:e1: + 3e:c6:cc:a4:29:e7:2e:84:aa:06:30:78:76:54:73:28:98:59: + 38:e0:00:0d:62:d3:42:7d:21:9f:ae:3d:3a:8c:d5:fa:77:0d: + 18:2b:16:0e:5f:36:e1:fc:2a:b5:30:24:cf:e0:63:0c:7b:58: + 1a:fe:99:ba:42:12:b1:91:f4:7c:68:e2:c8:e8:af:2c:ea:c9: + 7e:ae:bb:2a:3d:0d:15:dc:34:95:b6:18:74:a8:6a:0f:c7:b4: + f4:13:c4:e4:5b:ed:0a:d2:a4:97:4c:2a:ed:2f:6c:12:89:3d: + f1:27:70:aa:6a:03:52:21:9f:40:a8:67:50:f2:f3:5a:1f:df: + df:23:f6:dc:78:4e:e6:98:4f:55:3a:53:e3:ef:f2:f4:9f:c7: + 7c:d8:58:af:29:22:97:b8:e0:bd:91:2e:b0:76:ec:57:11:cf: + ef:29:44:f3:e9:85:7a:60:63:e4:5d:33:89:17:d9:31:aa:da: + d6:f3:18:35:72:cf:87:2b:2f:63:23:84:5d:84:8c:3f:57:a0: + 88:fc:99:91:28:26:69:99:d4:8f:97:44:be:8e:d5:48:b1:a4: + 28:29:f1:15:b4:e1:e5:9e:dd:f8:8f:a6:6f:26:d7:09:3c:3a: + 1c:11:0e:a6:6c:37:f7:ad:44:87:2c:28:c7:d8:74:82:b3:d0: + 6f:4a:57:bb:35:29:27:a0:8b:e8:21:a7:87:64:36:5d:cc:d8: + 16:ac:c7:b2:27:40:92:55:38:28:8d:51:6e:dd:14:67:53:6c: + 71:5c:26:84:4d:75:5a:b6:7e:60:56:a9:4d:ad:fb:9b:1e:97: + f3:0d:d9:d2:97:54:77:da:3d:12:b7:e0:1e:ef:08:06:ac:f9: + 85:87:e9:a2:dc:af:7e:18:12:83:fd:56:17:41:2e:d5:29:82: + 7d:99:f4:31:f6:71:a9:cf:2c:01:27:a5:05:b9:aa:b2:48:4e: + 2a:ef:9f:93:52:51:95:3c:52:73:8e:56:4c:17:40:c0:09:28: + e4:8b:6a:48:53:db:ec:cd:55:55:f1:c6:f8:e9:a2:2c:4c:a6: + d1:26:5f:7e:af:5a:4c:da:1f:a6:f2:1c:2c:7e:ae:02:16:d2: + 56:d0:2f:57:53:47:e8:92 +-----BEGIN CERTIFICATE----- +MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEW +MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVy +c2FsIENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYD +VQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1 +c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC +AQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0DE81 +WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUG +FF+3Qs17j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdq +XbboW0W63MOhBW9Wjo8QJqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxL +se4YuU6W3Nx2/zu+z18DwPw76L5GG//aQMJS9/7jOvdqdzXQ2o3rXhhqMcceujwb +KNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2WP0+GfPtDCapkzj4T8Fd +IgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP20gaXT73 +y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRt +hAAnZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgoc +QIgfksILAAX/8sgCSqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4 +Lt1ZrtmhN79UNdxzMk+MBB4zsslG8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAfBgNV +HSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8EBAMCAYYwDQYJ +KoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z +dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQ +L1EuxBRa3ugZ4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgr +Fg5fNuH8KrUwJM/gYwx7WBr+mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSo +ag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpqA1Ihn0CoZ1Dy81of398j9tx4TuaY +T1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpgY+RdM4kX2TGq2tbz +GDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiPpm8m +1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJV +OCiNUW7dFGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH +6aLcr34YEoP9VhdBLtUpgn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwX +QMAJKOSLakhT2+zNVVXxxvjpoixMptEmX36vWkzaH6byHCx+rgIW0lbQL1dTR+iS +-----END CERTIFICATE----- + +Visa eCommerce Root +# Issuer: CN=Visa eCommerce Root,OU=Visa International Service Association,O=VISA,C=US +# Serial Number:13:86:35:4d:1d:3f:06:f2:c1:f9:65:05:d5:90:1c:62 +# Subject: CN=Visa eCommerce Root,OU=Visa International Service Association,O=VISA,C=US +# Not Valid Before: Wed Jun 26 02:18:36 2002 +# Not Valid After : Fri Jun 24 00:16:12 2022 +# Fingerprint (MD5): FC:11:B8:D8:08:93:30:00:6D:23:F9:7E:EB:52:1E:02 +# Fingerprint (SHA1): 70:17:9B:86:8C:00:A4:FA:60:91:52:22:3F:9F:3E:32:BD:E0:05:62 +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +MUST_VERIFY_TRUST: CODE_SIGNING +================================================ +MD5 Fingerprint=FC:11:B8:D8:08:93:30:00:6D:23:F9:7E:EB:52:1E:02 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 13:86:35:4d:1d:3f:06:f2:c1:f9:65:05:d5:90:1c:62 + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=VISA, OU=Visa International Service Association, CN=Visa eCommerce Root + Validity + Not Before: Jun 26 02:18:36 2002 GMT + Not After : Jun 24 00:16:12 2022 GMT + Subject: C=US, O=VISA, OU=Visa International Service Association, CN=Visa eCommerce Root + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:af:57:de:56:1e:6e:a1:da:60:b1:94:27:cb:17: + db:07:3f:80:85:4f:c8:9c:b6:d0:f4:6f:4f:cf:99: + d8:e1:db:c2:48:5c:3a:ac:39:33:c7:1f:6a:8b:26: + 3d:2b:35:f5:48:b1:91:c1:02:4e:04:96:91:7b:b0: + 33:f0:b1:14:4e:11:6f:b5:40:af:1b:45:a5:4a:ef: + 7e:b6:ac:f2:a0:1f:58:3f:12:46:60:3c:8d:a1:e0: + 7d:cf:57:3e:33:1e:fb:47:f1:aa:15:97:07:55:66: + a5:b5:2d:2e:d8:80:59:b2:a7:0d:b7:46:ec:21:63: + ff:35:ab:a5:02:cf:2a:f4:4c:fe:7b:f5:94:5d:84: + 4d:a8:f2:60:8f:db:0e:25:3c:9f:73:71:cf:94:df: + 4a:ea:db:df:72:38:8c:f3:96:bd:f1:17:bc:d2:ba: + 3b:45:5a:c6:a7:f6:c6:17:8b:01:9d:fc:19:a8:2a: + 83:16:b8:3a:48:fe:4e:3e:a0:ab:06:19:e9:53:f3: + 80:13:07:ed:2d:bf:3f:0a:3c:55:20:39:2c:2c:00: + 69:74:95:4a:bc:20:b2:a9:79:e5:18:89:91:a8:dc: + 1c:4d:ef:bb:7e:37:0b:5d:fe:39:a5:88:52:8c:00: + 6c:ec:18:7c:41:bd:f6:8b:75:77:ba:60:9d:84:e7: + fe:2d + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 15:38:83:0F:3F:2C:3F:70:33:1E:CD:46:FE:07:8C:20:E0:D7:C3:B7 + Signature Algorithm: sha1WithRSAEncryption + 5f:f1:41:7d:7c:5c:08:b9:2b:e0:d5:92:47:fa:67:5c:a5:13: + c3:03:21:9b:2b:4c:89:46:cf:59:4d:c9:fe:a5:40:b6:63:cd: + dd:71:28:95:67:11:cc:24:ac:d3:44:6c:71:ae:01:20:6b:03: + a2:8f:18:b7:29:3a:7d:e5:16:60:53:78:3c:c0:af:15:83:f7: + 8f:52:33:24:bd:64:93:97:ee:8b:f7:db:18:a8:6d:71:b3:f7: + 2c:17:d0:74:25:69:f7:fe:6b:3c:94:be:4d:4b:41:8c:4e:e2: + 73:d0:e3:90:22:73:43:cd:f3:ef:ea:73:ce:45:8a:b0:a6:49: + ff:4c:7d:9d:71:88:c4:76:1d:90:5b:1d:ee:fd:cc:f7:ee:fd: + 60:a5:b1:7a:16:71:d1:16:d0:7c:12:3c:6c:69:97:db:ae:5f: + 39:9a:70:2f:05:3c:19:46:04:99:20:36:d0:60:6e:61:06:bb: + 16:42:8c:70:f7:30:fb:e0:db:66:a3:00:01:bd:e6:2c:da:91: + 5f:a0:46:8b:4d:6a:9c:3d:3d:dd:05:46:fe:76:bf:a0:0a:3c: + e4:00:e6:27:b7:ff:84:2d:de:ba:22:27:96:10:71:eb:22:ed: + df:df:33:9c:cf:e3:ad:ae:8e:d4:8e:e6:4f:51:af:16:92:e0: + 5c:f6:07:0f +-----BEGIN CERTIFICATE----- +MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUFADBr +MQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRl +cm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNv +bW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2WhcNMjIwNjI0MDAxNjEyWjBrMQsw +CQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5h +dGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNvbW1l +cmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvV95WHm6h +2mCxlCfLF9sHP4CFT8icttD0b0/Pmdjh28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4E +lpF7sDPwsRROEW+1QK8bRaVK7362rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdV +ZqW1LS7YgFmypw23RuwhY/81q6UCzyr0TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq +299yOIzzlr3xF7zSujtFWsan9sYXiwGd/BmoKoMWuDpI/k4+oKsGGelT84ATB+0t +vz8KPFUgOSwsAGl0lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzsGHxBvfaL +dXe6YJ2E5/4tAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD +AgEGMB0GA1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUF +AAOCAQEAX/FBfXxcCLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcR +zCSs00Rsca4BIGsDoo8Ytyk6feUWYFN4PMCvFYP3j1IzJL1kk5fui/fbGKhtcbP3 +LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pzzkWKsKZJ/0x9nXGIxHYdkFsd +7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBuYQa7FkKMcPcw +++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/hC3euiInlhBx6yLt +398znM/jra6O1I7mT1GvFpLgXPYHDw== +-----END CERTIFICATE----- + +Comodo AAA Services root +# Issuer: CN=AAA Certificate Services,O=Comodo CA Limited,L=Salford,ST=Greater Manchester,C=GB +# Serial Number: 1 (0x1) +# Subject: CN=AAA Certificate Services,O=Comodo CA Limited,L=Salford,ST=Greater Manchester,C=GB +# Not Valid Before: Thu Jan 01 00:00:00 2004 +# Not Valid After : Sun Dec 31 23:59:59 2028 +# Fingerprint (MD5): 49:79:04:B0:EB:87:19:AC:47:B0:BC:11:51:9B:74:D0 +# Fingerprint (SHA1): D1:EB:23:A4:6D:17:D6:8F:D9:25:64:C2:F1:F1:60:17:64:D8:E3:49 +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +MUST_VERIFY_TRUST: CODE_SIGNING +================================================ +MD5 Fingerprint=49:79:04:B0:EB:87:19:AC:47:B0:BC:11:51:9B:74:D0 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 1 (0x1) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=GB, ST=Greater Manchester, L=Salford, O=Comodo CA Limited, CN=AAA Certificate Services + Validity + Not Before: Jan 1 00:00:00 2004 GMT + Not After : Dec 31 23:59:59 2028 GMT + Subject: C=GB, ST=Greater Manchester, L=Salford, O=Comodo CA Limited, CN=AAA Certificate Services + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:be:40:9d:f4:6e:e1:ea:76:87:1c:4d:45:44:8e: + be:46:c8:83:06:9d:c1:2a:fe:18:1f:8e:e4:02:fa: + f3:ab:5d:50:8a:16:31:0b:9a:06:d0:c5:70:22:cd: + 49:2d:54:63:cc:b6:6e:68:46:0b:53:ea:cb:4c:24: + c0:bc:72:4e:ea:f1:15:ae:f4:54:9a:12:0a:c3:7a: + b2:33:60:e2:da:89:55:f3:22:58:f3:de:dc:cf:ef: + 83:86:a2:8c:94:4f:9f:68:f2:98:90:46:84:27:c7: + 76:bf:e3:cc:35:2c:8b:5e:07:64:65:82:c0:48:b0: + a8:91:f9:61:9f:76:20:50:a8:91:c7:66:b5:eb:78: + 62:03:56:f0:8a:1a:13:ea:31:a3:1e:a0:99:fd:38: + f6:f6:27:32:58:6f:07:f5:6b:b8:fb:14:2b:af:b7: + aa:cc:d6:63:5f:73:8c:da:05:99:a8:38:a8:cb:17: + 78:36:51:ac:e9:9e:f4:78:3a:8d:cf:0f:d9:42:e2: + 98:0c:ab:2f:9f:0e:01:de:ef:9f:99:49:f1:2d:df: + ac:74:4d:1b:98:b5:47:c5:e5:29:d1:f9:90:18:c7: + 62:9c:be:83:c7:26:7b:3e:8a:25:c7:c0:dd:9d:e6: + 35:68:10:20:9d:8f:d8:de:d2:c3:84:9c:0d:5e:e8: + 2f:c9 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + A0:11:0A:23:3E:96:F1:07:EC:E2:AF:29:EF:82:A5:7F:D0:30:A4:B4 + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.comodoca.com/AAACertificateServices.crl + + Full Name: + URI:http://crl.comodo.net/AAACertificateServices.crl + + Signature Algorithm: sha1WithRSAEncryption + 08:56:fc:02:f0:9b:e8:ff:a4:fa:d6:7b:c6:44:80:ce:4f:c4: + c5:f6:00:58:cc:a6:b6:bc:14:49:68:04:76:e8:e6:ee:5d:ec: + 02:0f:60:d6:8d:50:18:4f:26:4e:01:e3:e6:b0:a5:ee:bf:bc: + 74:54:41:bf:fd:fc:12:b8:c7:4f:5a:f4:89:60:05:7f:60:b7: + 05:4a:f3:f6:f1:c2:bf:c4:b9:74:86:b6:2d:7d:6b:cc:d2:f3: + 46:dd:2f:c6:e0:6a:c3:c3:34:03:2c:7d:96:dd:5a:c2:0e:a7: + 0a:99:c1:05:8b:ab:0c:2f:f3:5c:3a:cf:6c:37:55:09:87:de: + 53:40:6c:58:ef:fc:b6:ab:65:6e:04:f6:1b:dc:3c:e0:5a:15: + c6:9e:d9:f1:59:48:30:21:65:03:6c:ec:e9:21:73:ec:9b:03: + a1:e0:37:ad:a0:15:18:8f:fa:ba:02:ce:a7:2c:a9:10:13:2c: + d4:e5:08:26:ab:22:97:60:f8:90:5e:74:d4:a2:9a:53:bd:f2: + a9:68:e0:a2:6e:c2:d7:6c:b1:a3:0f:9e:bf:eb:68:e7:56:f2: + ae:f2:e3:2b:38:3a:09:81:b5:6b:85:d7:be:2d:ed:3f:1a:b7: + b2:63:e2:f5:62:2c:82:d4:6a:00:41:50:f1:39:83:9f:95:e9: + 36:96:98:6e +-----BEGIN CERTIFICATE----- +MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb +MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow +GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj +YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL +MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE +BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM +GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua +BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe +3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4 +YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR +rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm +ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU +oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF +MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v +QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t +b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF +AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q +GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz +Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2 +G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi +l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3 +smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== +-----END CERTIFICATE----- + +QuoVadis Root CA +# Issuer: CN=QuoVadis Root Certification Authority,OU=Root Certification Authority,O=QuoVadis Limited,C=BM +# Serial Number: 985026699 (0x3ab6508b) +# Subject: CN=QuoVadis Root Certification Authority,OU=Root Certification Authority,O=QuoVadis Limited,C=BM +# Not Valid Before: Mon Mar 19 18:33:33 2001 +# Not Valid After : Wed Mar 17 18:33:33 2021 +# Fingerprint (MD5): 27:DE:36:FE:72:B7:00:03:00:9D:F4:F0:1E:6C:04:24 +# Fingerprint (SHA1): DE:3F:40:BD:50:93:D3:9B:6C:60:F6:DA:BC:07:62:01:00:89:76:C9 +MUST_VERIFY_TRUST: CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +================================================ +MD5 Fingerprint=27:DE:36:FE:72:B7:00:03:00:9D:F4:F0:1E:6C:04:24 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 985026699 (0x3ab6508b) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=BM, O=QuoVadis Limited, OU=Root Certification Authority, CN=QuoVadis Root Certification Authority + Validity + Not Before: Mar 19 18:33:33 2001 GMT + Not After : Mar 17 18:33:33 2021 GMT + Subject: C=BM, O=QuoVadis Limited, OU=Root Certification Authority, CN=QuoVadis Root Certification Authority + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:bf:61:b5:95:53:ba:57:fc:fa:f2:67:0b:3a:1a: + df:11:80:64:95:b4:d1:bc:cd:7a:cf:f6:29:96:2e: + 24:54:40:24:38:f7:1a:85:dc:58:4c:cb:a4:27:42: + 97:d0:9f:83:8a:c3:e4:06:03:5b:00:a5:51:1e:70: + 04:74:e2:c1:d4:3a:ab:d7:ad:3b:07:18:05:8e:fd: + 83:ac:ea:66:d9:18:1b:68:8a:f5:57:1a:98:ba:f5: + ed:76:3d:7c:d9:de:94:6a:3b:4b:17:c1:d5:8f:bd: + 65:38:3a:95:d0:3d:55:36:4e:df:79:57:31:2a:1e: + d8:59:65:49:58:20:98:7e:ab:5f:7e:9f:e9:d6:4d: + ec:83:74:a9:c7:6c:d8:ee:29:4a:85:2a:06:14:f9: + 54:e6:d3:da:65:07:8b:63:37:12:d7:d0:ec:c3:7b: + 20:41:44:a3:ed:cb:a0:17:e1:71:65:ce:1d:66:31: + f7:76:01:19:c8:7d:03:58:b6:95:49:1d:a6:12:26: + e8:c6:0c:76:e0:e3:66:cb:ea:5d:a6:26:ee:e5:cc: + 5f:bd:67:a7:01:27:0e:a2:ca:54:c5:b1:7a:95:1d: + 71:1e:4a:29:8a:03:dc:6a:45:c1:a4:19:5e:6f:36: + cd:c3:a2:b0:b7:fe:5c:38:e2:52:bc:f8:44:43:e6: + 90:bb + Exponent: 65537 (0x10001) + X509v3 extensions: + Authority Information Access: + OCSP - URI:https://ocsp.quovadisoffshore.com + + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Certificate Policies: + Policy: 1.3.6.1.4.1.8024.0.1 + User Notice: + Explicit Text: Reliance on the QuoVadis Root Certificate by any party assumes acceptance of the then applicable standard terms and conditions of use, certification practices, and the QuoVadis Certificate Policy. + CPS: http://www.quovadis.bm + + X509v3 Subject Key Identifier: + 8B:4B:6D:ED:D3:29:B9:06:19:EC:39:39:A9:F0:97:84:6A:CB:EF:DF + X509v3 Authority Key Identifier: + keyid:8B:4B:6D:ED:D3:29:B9:06:19:EC:39:39:A9:F0:97:84:6A:CB:EF:DF + DirName:/C=BM/O=QuoVadis Limited/OU=Root Certification Authority/CN=QuoVadis Root Certification Authority + serial:3A:B6:50:8B + + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + Signature Algorithm: sha1WithRSAEncryption + 8a:d4:14:b5:fe:f4:9a:92:a7:19:d4:a4:7e:72:18:8f:d9:68: + 7c:52:24:dd:67:6f:39:7a:c4:aa:5e:3d:e2:58:b0:4d:70:98: + 84:61:e8:1b:e3:69:18:0e:ce:fb:47:50:a0:4e:ff:f0:24:1f: + bd:b2:ce:f5:27:fc:ec:2f:53:aa:73:7b:03:3d:74:6e:e6:16: + 9e:eb:a5:2e:c4:bf:56:27:50:2b:62:ba:be:4b:1c:3c:55:5c: + 41:1d:24:be:82:20:47:5d:d5:44:7e:7a:16:68:df:7d:4d:51: + 70:78:57:1d:33:1e:fd:02:99:9c:0c:cd:0a:05:4f:c7:bb:8e: + a4:75:fa:4a:6d:b1:80:8e:09:56:b9:9c:1a:60:fe:5d:c1:d7: + 7a:dc:11:78:d0:d6:5d:c1:b7:d5:ad:32:99:03:3a:8a:cc:54: + 25:39:31:81:7b:13:22:51:ba:46:6c:a1:bb:9e:fa:04:6c:49: + 26:74:8f:d2:73:eb:cc:30:a2:e6:ea:59:22:87:f8:97:f5:0e: + fd:ea:cc:92:a4:16:c4:52:18:ea:21:ce:b1:f1:e6:84:81:e5: + ba:a9:86:28:f2:43:5a:5d:12:9d:ac:1e:d9:a8:e5:0a:6a:a7: + 7f:a0:87:29:cf:f2:89:4d:d4:ec:c5:e2:e6:7a:d0:36:23:8a: + 4a:74:36:f9 +-----BEGIN CERTIFICATE----- +MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJC +TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0 +aWZpY2F0aW9uIEF1dGhvcml0eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0 +aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAzMTkxODMzMzNaFw0yMTAzMTcxODMz +MzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUw +IwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQDEyVR +dW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Yp +li4kVEAkOPcahdxYTMukJ0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2D +rOpm2RgbaIr1VxqYuvXtdj182d6UajtLF8HVj71lODqV0D1VNk7feVcxKh7YWWVJ +WCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeLYzcS19Dsw3sgQUSj7cug +F+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWenAScOospU +xbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCC +Ak4wPQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVv +dmFkaXNvZmZzaG9yZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREw +ggENMIIBCQYJKwYBBAG+WAABMIH7MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNl +IG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBh +c3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFy +ZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh +Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYI +KwYBBQUHAgEWFmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3T +KbkGGew5Oanwl4Rqy+/fMIGuBgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rq +y+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1p +dGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYD +VQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6tlCL +MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSk +fnIYj9lofFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf8 +7C9TqnN7Az10buYWnuulLsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1R +cHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2xgI4JVrmcGmD+XcHXetwReNDWXcG31a0y +mQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi5upZIof4l/UO/erMkqQW +xFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi5nrQNiOK +SnQ2+Q== +-----END CERTIFICATE----- + +QuoVadis Root CA 2 +# Issuer: CN=QuoVadis Root CA 2,O=QuoVadis Limited,C=BM +# Serial Number: 1289 (0x509) +# Subject: CN=QuoVadis Root CA 2,O=QuoVadis Limited,C=BM +# Not Valid Before: Fri Nov 24 18:27:00 2006 +# Not Valid After : Mon Nov 24 18:23:33 2031 +# Fingerprint (MD5): 5E:39:7B:DD:F8:BA:EC:82:E9:AC:62:BA:0C:54:00:2B +# Fingerprint (SHA1): CA:3A:FB:CF:12:40:36:4B:44:B2:16:20:88:80:48:39:19:93:7C:F7 +MUST_VERIFY_TRUST: CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +================================================ +MD5 Fingerprint=5E:39:7B:DD:F8:BA:EC:82:E9:AC:62:BA:0C:54:00:2B +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 1289 (0x509) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=BM, O=QuoVadis Limited, CN=QuoVadis Root CA 2 + Validity + Not Before: Nov 24 18:27:00 2006 GMT + Not After : Nov 24 18:23:33 2031 GMT + Subject: C=BM, O=QuoVadis Limited, CN=QuoVadis Root CA 2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:9a:18:ca:4b:94:0d:00:2d:af:03:29:8a:f0:0f: + 81:c8:ae:4c:19:85:1d:08:9f:ab:29:44:85:f3:2f: + 81:ad:32:1e:90:46:bf:a3:86:26:1a:1e:fe:7e:1c: + 18:3a:5c:9c:60:17:2a:3a:74:83:33:30:7d:61:54: + 11:cb:ed:ab:e0:e6:d2:a2:7e:f5:6b:6f:18:b7:0a: + 0b:2d:fd:e9:3e:ef:0a:c6:b3:10:e9:dc:c2:46:17: + f8:5d:fd:a4:da:ff:9e:49:5a:9c:e6:33:e6:24:96: + f7:3f:ba:5b:2b:1c:7a:35:c2:d6:67:fe:ab:66:50: + 8b:6d:28:60:2b:ef:d7:60:c3:c7:93:bc:8d:36:91: + f3:7f:f8:db:11:13:c4:9c:77:76:c1:ae:b7:02:6a: + 81:7a:a9:45:83:e2:05:e6:b9:56:c1:94:37:8f:48: + 71:63:22:ec:17:65:07:95:8a:4b:df:8f:c6:5a:0a: + e5:b0:e3:5f:5e:6b:11:ab:0c:f9:85:eb:44:e9:f8: + 04:73:f2:e9:fe:5c:98:8c:f5:73:af:6b:b4:7e:cd: + d4:5c:02:2b:4c:39:e1:b2:95:95:2d:42:87:d7:d5: + b3:90:43:b7:6c:13:f1:de:dd:f6:c4:f8:89:3f:d1: + 75:f5:92:c3:91:d5:8a:88:d0:90:ec:dc:6d:de:89: + c2:65:71:96:8b:0d:03:fd:9c:bf:5b:16:ac:92:db: + ea:fe:79:7c:ad:eb:af:f7:16:cb:db:cd:25:2b:e5: + 1f:fb:9a:9f:e2:51:cc:3a:53:0c:48:e6:0e:bd:c9: + b4:76:06:52:e6:11:13:85:72:63:03:04:e0:04:36: + 2b:20:19:02:e8:74:a7:1f:b6:c9:56:66:f0:75:25: + dc:67:c1:0e:61:60:88:b3:3e:d1:a8:fc:a3:da:1d: + b0:d1:b1:23:54:df:44:76:6d:ed:41:d8:c1:b2:22: + b6:53:1c:df:35:1d:dc:a1:77:2a:31:e4:2d:f5:e5: + e5:db:c8:e0:ff:e5:80:d7:0b:63:a0:ff:33:a1:0f: + ba:2c:15:15:ea:97:b3:d2:a2:b5:be:f2:8c:96:1e: + 1a:8f:1d:6c:a4:61:37:b9:86:73:33:d7:97:96:9e: + 23:7d:82:a4:4c:81:e2:a1:d1:ba:67:5f:95:07:a3: + 27:11:ee:16:10:7b:bc:45:4a:4c:b2:04:d2:ab:ef: + d5:fd:0c:51:ce:50:6a:08:31:f9:91:da:0c:8f:64: + 5c:03:c3:3a:8b:20:3f:6e:8d:67:3d:3a:d6:fe:7d: + 5b:88:c9:5e:fb:cc:61:dc:8b:33:77:d3:44:32:35: + 09:62:04:92:16:10:d8:9e:27:47:fb:3b:21:e3:f8: + eb:1d:5b + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 1A:84:62:BC:48:4C:33:25:04:D4:EE:D0:F6:03:C4:19:46:D1:94:6B + X509v3 Authority Key Identifier: + keyid:1A:84:62:BC:48:4C:33:25:04:D4:EE:D0:F6:03:C4:19:46:D1:94:6B + DirName:/C=BM/O=QuoVadis Limited/CN=QuoVadis Root CA 2 + serial:05:09 + + Signature Algorithm: sha1WithRSAEncryption + 3e:0a:16:4d:9f:06:5b:a8:ae:71:5d:2f:05:2f:67:e6:13:45: + 83:c4:36:f6:f3:c0:26:0c:0d:b5:47:64:5d:f8:b4:72:c9:46: + a5:03:18:27:55:89:78:7d:76:ea:96:34:80:17:20:dc:e7:83: + f8:8d:fc:07:b8:da:5f:4d:2e:67:b2:84:fd:d9:44:fc:77:50: + 81:e6:7c:b4:c9:0d:0b:72:53:f8:76:07:07:41:47:96:0c:fb: + e0:82:26:93:55:8c:fe:22:1f:60:65:7c:5f:e7:26:b3:f7:32: + 90:98:50:d4:37:71:55:f6:92:21:78:f7:95:79:fa:f8:2d:26: + 87:66:56:30:77:a6:37:78:33:52:10:58:ae:3f:61:8e:f2:6a: + b1:ef:18:7e:4a:59:63:ca:8d:a2:56:d5:a7:2f:bc:56:1f:cf: + 39:c1:e2:fb:0a:a8:15:2c:7d:4d:7a:63:c6:6c:97:44:3c:d2: + 6f:c3:4a:17:0a:f8:90:d2:57:a2:19:51:a5:2d:97:41:da:07: + 4f:a9:50:da:90:8d:94:46:e1:3e:f0:94:fd:10:00:38:f5:3b: + e8:40:e1:b4:6e:56:1a:20:cc:6f:58:8d:ed:2e:45:8f:d6:e9: + 93:3f:e7:b1:2c:df:3a:d6:22:8c:dc:84:bb:22:6f:d0:f8:e4: + c6:39:e9:04:88:3c:c3:ba:eb:55:7a:6d:80:99:24:f5:6c:01: + fb:f8:97:b0:94:5b:eb:fd:d2:6f:f1:77:68:0d:35:64:23:ac: + b8:55:a1:03:d1:4d:42:19:dc:f8:75:59:56:a3:f9:a8:49:79: + f8:af:0e:b9:11:a0:7c:b7:6a:ed:34:d0:b6:26:62:38:1a:87: + 0c:f8:e8:fd:2e:d3:90:7f:07:91:2a:1d:d6:7e:5c:85:83:99: + b0:38:08:3f:e9:5e:f9:35:07:e4:c9:62:6e:57:7f:a7:50:95: + f7:ba:c8:9b:e6:8e:a2:01:c5:d6:66:bf:79:61:f3:3c:1c:e1: + b9:82:5c:5d:a0:c3:e9:d8:48:bd:19:a2:11:14:19:6e:b2:86: + 1b:68:3e:48:37:1a:88:b7:5d:96:5e:9c:c7:ef:27:62:08:e2: + 91:19:5c:d2:f1:21:dd:ba:17:42:82:97:71:81:53:31:a9:9f: + f6:7d:62:bf:72:e1:a3:93:1d:cc:8a:26:5a:09:38:d0:ce:d7: + 0d:80:16:b4:78:a5:3a:87:4c:8d:8a:a5:d5:46:97:f2:2c:10: + b9:bc:54:22:c0:01:50:69:43:9e:f4:b2:ef:6d:f8:ec:da:f1: + e3:b1:ef:df:91:8f:54:2a:0b:25:c1:26:19:c4:52:10:05:65: + d5:82:10:ea:c2:31:cd:2e +-----BEGIN CERTIFICATE----- +MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x +GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv +b3QgQ0EgMjAeFw0wNjExMjQxODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNV +BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W +YWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCa +GMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6XJxg +Fyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55J +WpzmM+Yklvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bB +rrcCaoF6qUWD4gXmuVbBlDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp ++ARz8un+XJiM9XOva7R+zdRcAitMOeGylZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1 +ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt66/3FsvbzSUr5R/7mp/i +Ucw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1JdxnwQ5hYIiz +PtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og +/zOhD7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UH +oycR7hYQe7xFSkyyBNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuI +yV77zGHcizN300QyNQliBJIWENieJ0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1Ud +EwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBQahGK8SEwzJQTU7tD2 +A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGUa6FJpEcwRTEL +MAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT +ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2f +BluornFdLwUvZ+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzn +g/iN/Ae42l9NLmeyhP3ZRPx3UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2Bl +fF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodmVjB3pjd4M1IQWK4/YY7yarHvGH5K +WWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK+JDSV6IZUaUtl0Ha +B0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrWIozc +hLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPR +TUIZ3Ph1WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWD +mbA4CD/pXvk1B+TJYm5Xf6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0Z +ohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y +4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8VCLAAVBpQ570su9t+Oza +8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u +-----END CERTIFICATE----- + +QuoVadis Root CA 3 +# Issuer: CN=QuoVadis Root CA 3,O=QuoVadis Limited,C=BM +# Serial Number: 1478 (0x5c6) +# Subject: CN=QuoVadis Root CA 3,O=QuoVadis Limited,C=BM +# Not Valid Before: Fri Nov 24 19:11:23 2006 +# Not Valid After : Mon Nov 24 19:06:44 2031 +# Fingerprint (MD5): 31:85:3C:62:94:97:63:B9:AA:FD:89:4E:AF:6F:E0:CF +# Fingerprint (SHA1): 1F:49:14:F7:D8:74:95:1D:DD:AE:02:C0:BE:FD:3A:2D:82:75:51:85 +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +MUST_VERIFY_TRUST: CODE_SIGNING +================================================ +MD5 Fingerprint=31:85:3C:62:94:97:63:B9:AA:FD:89:4E:AF:6F:E0:CF +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 1478 (0x5c6) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=BM, O=QuoVadis Limited, CN=QuoVadis Root CA 3 + Validity + Not Before: Nov 24 19:11:23 2006 GMT + Not After : Nov 24 19:06:44 2031 GMT + Subject: C=BM, O=QuoVadis Limited, CN=QuoVadis Root CA 3 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:cc:57:42:16:54:9c:e6:98:d3:d3:4d:ee:fe:ed: + c7:9f:43:39:4a:65:b3:e8:16:88:34:db:0d:59:91: + 74:cf:92:b8:04:40:ad:02:4b:31:ab:bc:8d:91:68: + d8:20:0e:1a:01:e2:1a:7b:4e:17:5d:e2:8a:b7:3f: + 99:1a:cd:eb:61:ab:c2:65:a6:1f:b7:b7:bd:b7:8f: + fc:fd:70:8f:0b:a0:67:be:01:a2:59:cf:71:e6:0f: + 29:76:ff:b1:56:79:45:2b:1f:9e:7a:54:e8:a3:29: + 35:68:a4:01:4f:0f:a4:2e:37:ef:1b:bf:e3:8f:10: + a8:72:ab:58:57:e7:54:86:c8:c9:f3:5b:da:2c:da: + 5d:8e:6e:3c:a3:3e:da:fb:82:e5:dd:f2:5c:b2:05: + 33:6f:8a:36:ce:d0:13:4e:ff:bf:4a:0c:34:4c:a6: + c3:21:bd:50:04:55:eb:b1:bb:9d:fb:45:1e:64:15: + de:55:01:8c:02:76:b5:cb:a1:3f:42:69:bc:2f:bd: + 68:43:16:56:89:2a:37:61:91:fd:a6:ae:4e:c0:cb: + 14:65:94:37:4b:92:06:ef:04:d0:c8:9c:88:db:0b: + 7b:81:af:b1:3d:2a:c4:65:3a:78:b6:ee:dc:80:b1: + d2:d3:99:9c:3a:ee:6b:5a:6b:b3:8d:b7:d5:ce:9c: + c2:be:a5:4b:2f:16:b1:9e:68:3b:06:6f:ae:7d:9f: + f8:de:ec:cc:29:a7:98:a3:25:43:2f:ef:f1:5f:26: + e1:88:4d:f8:5e:6e:d7:d9:14:6e:19:33:69:a7:3b: + 84:89:93:c4:53:55:13:a1:51:78:40:f8:b8:c9:a2: + ee:7b:ba:52:42:83:9e:14:ed:05:52:5a:59:56:a7: + 97:fc:9d:3f:0a:29:d8:dc:4f:91:0e:13:bc:de:95: + a4:df:8b:99:be:ac:9b:33:88:ef:b5:81:af:1b:c6: + 22:53:c8:f6:c7:ee:97:14:b0:c5:7c:78:52:c8:f0: + ce:6e:77:60:84:a6:e9:2a:76:20:ed:58:01:17:30: + 93:e9:1a:8b:e0:73:63:d9:6a:92:94:49:4e:b4:ad: + 4a:85:c4:a3:22:30:fc:09:ed:68:22:73:a6:88:0c: + 55:21:58:c5:e1:3a:9f:2a:dd:ca:e1:90:e0:d9:73: + ab:6c:80:b8:e8:0b:64:93:a0:9c:8c:19:ff:b3:d2: + 0c:ec:91:26:87:8a:b3:a2:e1:70:8f:2c:0a:e5:cd: + 6d:68:51:eb:da:3f:05:7f:8b:32:e6:13:5c:6b:fe: + 5f:40:e2:22:c8:b4:b4:64:4f:d6:ba:7d:48:3e:a8: + 69:0c:d7:bb:86:71:c9:73:b8:3f:3b:9d:25:4b:da: + ff:40:eb + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Certificate Policies: + Policy: 1.3.6.1.4.1.8024.0.3 + User Notice: + Explicit Text: Any use of this Certificate constitutes acceptance of the QuoVadis Root CA 3 Certificate Policy / Certification Practice Statement. + CPS: http://www.quovadisglobal.com/cps + + X509v3 Key Usage: + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + F2:C0:13:E0:82:43:3E:FB:EE:2F:67:32:96:35:5C:DB:B8:CB:02:D0 + X509v3 Authority Key Identifier: + keyid:F2:C0:13:E0:82:43:3E:FB:EE:2F:67:32:96:35:5C:DB:B8:CB:02:D0 + DirName:/C=BM/O=QuoVadis Limited/CN=QuoVadis Root CA 3 + serial:05:C6 + + Signature Algorithm: sha1WithRSAEncryption + 4f:ad:a0:2c:4c:fa:c0:f2:6f:f7:66:55:ab:23:34:ee:e7:29: + da:c3:5b:b6:b0:83:d9:d0:d0:e2:21:fb:f3:60:a7:3b:5d:60: + 53:27:a2:9b:f6:08:22:2a:e7:bf:a0:72:e5:9c:24:6a:31:b1: + 90:7a:27:db:84:11:89:27:a6:77:5a:38:d7:bf:ac:86:fc:ee: + 5d:83:bc:06:c6:d1:77:6b:0f:6d:24:2f:4b:7a:6c:a7:07:96: + ca:e3:84:9f:ad:88:8b:1d:ab:16:8d:5b:66:17:d9:16:f4:8b: + 80:d2:dd:f8:b2:76:c3:fc:38:13:aa:0c:de:42:69:2b:6e:f3: + 3c:eb:80:27:db:f5:a6:44:0d:9f:5a:55:59:0b:d5:0d:52:48: + c5:ae:9f:f2:2f:80:c5:ea:32:50:35:12:97:2e:c1:e1:ff:f1: + 23:88:51:38:9f:f2:66:56:76:e7:0f:51:97:a5:52:0c:4d:49: + 51:95:36:3d:bf:a2:4b:0c:10:1d:86:99:4c:aa:f3:72:11:93: + e4:ea:f6:9b:da:a8:5d:a7:4d:b7:9e:02:ae:73:00:c8:da:23: + 03:e8:f9:ea:19:74:62:00:94:cb:22:20:be:94:a7:59:b5:82: + 6a:be:99:79:7a:a9:f2:4a:24:52:f7:74:fd:ba:4e:e6:a8:1d: + 02:6e:b1:0d:80:44:c1:ae:d3:23:37:5f:bb:85:7c:2b:92:2e: + e8:7e:a5:8b:dd:99:e1:bf:27:6f:2d:5d:aa:7b:87:fe:0a:dd: + 4b:fc:8e:f5:26:e4:6e:70:42:6e:33:ec:31:9e:7b:93:c1:e4: + c9:69:1a:3d:c0:6b:4e:22:6d:ee:ab:58:4d:c6:d0:41:c1:2b: + ea:4f:12:87:5e:eb:45:d8:6c:f5:98:02:d3:a0:d8:55:8a:06: + 99:19:a2:a0:77:d1:30:9e:ac:cc:75:ee:83:f5:b0:62:39:cf: + 6c:57:e2:4c:d2:91:0b:0e:75:28:1b:9a:bf:fd:1a:43:f1:ca: + 77:fb:3b:8f:61:b8:69:28:16:42:04:5e:70:2a:1c:21:d8:8f: + e1:bd:23:5b:2d:74:40:92:d9:63:19:0d:73:dd:69:bc:62:47: + bc:e0:74:2b:b2:eb:7d:be:41:1b:b5:c0:46:c5:a1:22:cb:5f: + 4e:c1:28:92:de:18:ba:d5:2a:28:bb:11:8b:17:93:98:99:60: + 94:5c:23:cf:5a:27:97:5e:0b:05:06:93:37:1e:3b:69:36:eb: + a9:9e:61:1d:8f:32:da:8e:0c:d6:74:3e:7b:09:24:da:01:77: + 47:c4:3b:cd:34:8c:99:f5:ca:e1:25:61:33:b2:59:1b:e2:6e: + d7:37:57:b6:0d:a9:12:da +-----BEGIN CERTIFICATE----- +MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x +GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv +b3QgQ0EgMzAeFw0wNjExMjQxOTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNV +BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W +YWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDM +V0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNggDhoB +4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUr +H556VOijKTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd +8lyyBTNvijbO0BNO/79KDDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9Cabwv +vWhDFlaJKjdhkf2mrk7AyxRllDdLkgbvBNDInIjbC3uBr7E9KsRlOni27tyAsdLT +mZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwpp5ijJUMv7/FfJuGITfhe +btfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8nT8KKdjc +T5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDt +WAEXMJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZ +c6tsgLjoC2SToJyMGf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A +4iLItLRkT9a6fUg+qGkM17uGcclzuD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYD +VR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHTBgkrBgEEAb5YAAMwgcUwgZMG +CCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmljYXRlIGNvbnN0 +aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0 +aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVu +dC4wLQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2Nw +czALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4G +A1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4ywLQoUmkRzBFMQswCQYDVQQGEwJC +TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UEAxMSUXVvVmFkaXMg +Um9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZVqyM0 +7ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSem +d1o417+shvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd ++LJ2w/w4E6oM3kJpK27zPOuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B +4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadN +t54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp8kokUvd0/bpO5qgdAm6x +DYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBCbjPsMZ57 +k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6s +zHXug/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0j +Wy10QJLZYxkNc91pvGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeT +mJlglFwjz1onl14LBQaTNx47aTbrqZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK +4SVhM7JZG+Ju1zdXtg2pEto= +-----END CERTIFICATE----- + +Security Communication Root CA +# Issuer: OU=Security Communication RootCA1,O=SECOM Trust.net,C=JP +# Serial Number: 0 (0x0) +# Subject: OU=Security Communication RootCA1,O=SECOM Trust.net,C=JP +# Not Valid Before: Tue Sep 30 04:20:49 2003 +# Not Valid After : Sat Sep 30 04:20:49 2023 +# Fingerprint (MD5): F1:BC:63:6A:54:E0:B5:27:F5:CD:E7:1A:E3:4D:6E:4A +# Fingerprint (SHA1): 36:B1:2B:49:F9:81:9E:D7:4C:9E:BC:38:0F:C6:56:8F:5D:AC:B2:F7 +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +MUST_VERIFY_TRUST: CODE_SIGNING +================================================ +MD5 Fingerprint=F1:BC:63:6A:54:E0:B5:27:F5:CD:E7:1A:E3:4D:6E:4A +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 0 (0x0) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=JP, O=SECOM Trust.net, OU=Security Communication RootCA1 + Validity + Not Before: Sep 30 04:20:49 2003 GMT + Not After : Sep 30 04:20:49 2023 GMT + Subject: C=JP, O=SECOM Trust.net, OU=Security Communication RootCA1 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:b3:b3:fe:7f:d3:6d:b1:ef:16:7c:57:a5:0c:6d: + 76:8a:2f:4b:bf:64:fb:4c:ee:8a:f0:f3:29:7c:f5: + ff:ee:2a:e0:e9:e9:ba:5b:64:22:9a:9a:6f:2c:3a: + 26:69:51:05:99:26:dc:d5:1c:6a:71:c6:9a:7d:1e: + 9d:dd:7c:6c:c6:8c:67:67:4a:3e:f8:71:b0:19:27: + a9:09:0c:a6:95:bf:4b:8c:0c:fa:55:98:3b:d8:e8: + 22:a1:4b:71:38:79:ac:97:92:69:b3:89:7e:ea:21: + 68:06:98:14:96:87:d2:61:36:bc:6d:27:56:9e:57: + ee:c0:c0:56:fd:32:cf:a4:d9:8e:c2:23:d7:8d:a8: + f3:d8:25:ac:97:e4:70:38:f4:b6:3a:b4:9d:3b:97: + 26:43:a3:a1:bc:49:59:72:4c:23:30:87:01:58:f6: + 4e:be:1c:68:56:66:af:cd:41:5d:c8:b3:4d:2a:55: + 46:ab:1f:da:1e:e2:40:3d:db:cd:7d:b9:92:80:9c: + 37:dd:0c:96:64:9d:dc:22:f7:64:8b:df:61:de:15: + 94:52:15:a0:7d:52:c9:4b:a8:21:c9:c6:b1:ed:cb: + c3:95:60:d1:0f:f0:ab:70:f8:df:cb:4d:7e:ec:d6: + fa:ab:d9:bd:7f:54:f2:a5:e9:79:fa:d9:d6:76:24: + 28:73 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + A0:73:49:99:68:DC:85:5B:65:E3:9B:28:2F:57:9F:BD:33:BC:07:48 + X509v3 Key Usage: + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + Signature Algorithm: sha1WithRSAEncryption + 68:40:a9:a8:bb:e4:4f:5d:79:b3:05:b5:17:b3:60:13:eb:c6: + 92:5d:e0:d1:d3:6a:fe:fb:be:9b:6d:bf:c7:05:6d:59:20:c4: + 1c:f0:b7:da:84:58:02:63:fa:48:16:ef:4f:a5:0b:f7:4a:98: + f2:3f:9e:1b:ad:47:6b:63:ce:08:47:eb:52:3f:78:9c:af:4d: + ae:f8:d5:4f:cf:9a:98:2a:10:41:39:52:c4:dd:d9:9b:0e:ef: + 93:01:ae:b2:2e:ca:68:42:24:42:6c:b0:b3:3a:3e:cd:e9:da: + 48:c4:15:cb:e9:f9:07:0f:92:50:49:8a:dd:31:97:5f:c9:e9: + 37:aa:3b:59:65:97:94:32:c9:b3:9f:3e:3a:62:58:c5:49:ad: + 62:0e:71:a5:32:aa:2f:c6:89:76:43:40:13:13:67:3d:a2:54: + 25:10:cb:f1:3a:f2:d9:fa:db:49:56:bb:a6:fe:a7:41:35:c3: + e0:88:61:c9:88:c7:df:36:10:22:98:59:ea:b0:4a:fb:56:16: + 73:6e:ac:4d:f7:22:a1:4f:ad:1d:7a:2d:45:27:e5:30:c1:5e: + f2:da:13:cb:25:42:51:95:47:03:8c:6c:21:cc:74:42:ed:53: + ff:33:8b:8f:0f:57:01:16:2f:cf:a6:ee:c9:70:22:14:bd:fd: + be:6c:0b:03 +-----BEGIN CERTIFICATE----- +MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEY +MBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21t +dW5pY2F0aW9uIFJvb3RDQTEwHhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5 +WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYD +VQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw8yl8 +9f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJ +DKaVv0uMDPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9 +Ms+k2Y7CI9eNqPPYJayX5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/N +QV3Is00qVUarH9oe4kA92819uZKAnDfdDJZkndwi92SL32HeFZRSFaB9UslLqCHJ +xrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2JChzAgMBAAGjPzA9MB0G +A1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYwDwYDVR0T +AQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vG +kl3g0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfr +Uj94nK9NrvjVT8+amCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5 +Bw+SUEmK3TGXX8npN6o7WWWXlDLJs58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJU +JRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ6rBK+1YWc26sTfcioU+tHXot +RSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAiFL39vmwLAw== +-----END CERTIFICATE----- + +Sonera Class 2 Root CA +# Issuer: CN=Sonera Class2 CA,O=Sonera,C=FI +# Serial Number: 29 (0x1d) +# Subject: CN=Sonera Class2 CA,O=Sonera,C=FI +# Not Valid Before: Fri Apr 06 07:29:40 2001 +# Not Valid After : Tue Apr 06 07:29:40 2021 +# Fingerprint (MD5): A3:EC:75:0F:2E:88:DF:FA:48:01:4E:0B:5C:48:6F:FB +# Fingerprint (SHA1): 37:F7:6D:E6:07:7C:90:C5:B1:3E:93:1A:B7:41:10:B4:F2:E4:9A:27 +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +MUST_VERIFY_TRUST: CODE_SIGNING +================================================ +MD5 Fingerprint=A3:EC:75:0F:2E:88:DF:FA:48:01:4E:0B:5C:48:6F:FB +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 29 (0x1d) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=FI, O=Sonera, CN=Sonera Class2 CA + Validity + Not Before: Apr 6 07:29:40 2001 GMT + Not After : Apr 6 07:29:40 2021 GMT + Subject: C=FI, O=Sonera, CN=Sonera Class2 CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:90:17:4a:35:9d:ca:f0:0d:96:c7:44:fa:16:37: + fc:48:bd:bd:7f:80:2d:35:3b:e1:6f:a8:67:a9:bf: + 03:1c:4d:8c:6f:32:47:d5:41:68:a4:13:04:c1:35: + 0c:9a:84:43:fc:5c:1d:ff:89:b3:e8:17:18:cd:91: + 5f:fb:89:e3:ea:bf:4e:5d:7c:1b:26:d3:75:79:ed: + e6:84:e3:57:e5:ad:29:c4:f4:3a:28:e7:a5:7b:84: + 36:69:b3:fd:5e:76:bd:a3:2d:99:d3:90:4e:23:28: + 7d:18:63:f1:54:3b:26:9d:76:5b:97:42:b2:ff:ae: + f0:4e:ec:dd:39:95:4e:83:06:7f:e7:49:40:c8:c5: + 01:b2:54:5a:66:1d:3d:fc:f9:e9:3c:0a:9e:81:b8: + 70:f0:01:8b:e4:23:54:7c:c8:ae:f8:90:1e:00:96: + 72:d4:54:cf:61:23:bc:ea:fb:9d:02:95:d1:b6:b9: + 71:3a:69:08:3f:0f:b4:e1:42:c7:88:f5:3f:98:a8: + a7:ba:1c:e0:71:71:ef:58:57:81:50:7a:5c:6b:74: + 46:0e:83:03:98:c3:8e:a8:6e:f2:76:32:6e:27:83: + c2:73:f3:dc:18:e8:b4:93:ea:75:44:6b:04:60:20: + 71:57:87:9d:f3:be:a0:90:23:3d:8a:24:e1:da:21: + db:c3 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + 4A:A0:AA:58:84:D3:5E:3C + X509v3 Key Usage: + Certificate Sign, CRL Sign + Signature Algorithm: sha1WithRSAEncryption + 5a:ce:87:f9:16:72:15:57:4b:1d:d9:9b:e7:a2:26:30:ec:93: + 67:df:d6:2d:d2:34:af:f7:38:a5:ce:ab:16:b9:ab:2f:7c:35: + cb:ac:d0:0f:b4:4c:2b:fc:80:ef:6b:8c:91:5f:36:76:f7:db: + b3:1b:19:ea:f4:b2:11:fd:61:71:44:bf:28:b3:3a:1d:bf:b3: + 43:e8:9f:bf:dc:31:08:71:b0:9d:8d:d6:34:47:32:90:c6:65: + 24:f7:a0:4a:7c:04:73:8f:39:6f:17:8c:72:b5:bd:4b:c8:7a: + f8:7b:83:c3:28:4e:9c:09:ea:67:3f:b2:67:04:1b:c3:14:da: + f8:e7:49:24:91:d0:1d:6a:fa:61:39:ef:6b:e7:21:75:06:07: + d8:12:b4:21:20:70:42:71:81:da:3c:9a:36:be:a6:5b:0d:6a: + 6c:9a:1f:91:7b:f9:f9:ef:42:ba:4e:4e:9e:cc:0c:8d:94:dc: + d9:45:9c:5e:ec:42:50:63:ae:f4:5d:c4:b1:12:dc:ca:3b:a8: + 2e:9d:14:5a:05:75:b7:ec:d7:63:e2:ba:35:b6:04:08:91:e8: + da:9d:9c:f6:66:b5:18:ac:0a:a6:54:26:34:33:d2:1b:c1:d4: + 7f:1a:3a:8e:0b:aa:32:6e:db:fc:4f:25:9f:d9:32:c7:96:5a: + 70:ac:df:4c +-----BEGIN CERTIFICATE----- +MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEP +MA0GA1UEChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAx +MDQwNjA3Mjk0MFoXDTIxMDQwNjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNV +BAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJhIENsYXNzMiBDQTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3/Ei9vX+ALTU74W+o +Z6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybTdXnt +5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s +3TmVToMGf+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2Ej +vOr7nQKV0ba5cTppCD8PtOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu +8nYybieDwnPz3BjotJPqdURrBGAgcVeHnfO+oJAjPYok4doh28MCAwEAAaMzMDEw +DwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITTXjwwCwYDVR0PBAQDAgEG +MA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt0jSv9zil +zqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/ +3DEIcbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvD +FNr450kkkdAdavphOe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6 +Tk6ezAyNlNzZRZxe7EJQY670XcSxEtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2 +ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLHllpwrN9M +-----END CERTIFICATE----- + +Camerfirma Chambers of Commerce Root +# Issuer: CN=Chambers of Commerce Root,OU=http://www.chambersign.org,O=AC Camerfirma SA CIF A82743287,C=EU +# Serial Number: 0 (0x0) +# Subject: CN=Chambers of Commerce Root,OU=http://www.chambersign.org,O=AC Camerfirma SA CIF A82743287,C=EU +# Not Valid Before: Tue Sep 30 16:13:43 2003 +# Not Valid After : Wed Sep 30 16:13:44 2037 +# Fingerprint (MD5): B0:01:EE:14:D9:AF:29:18:94:76:8E:F1:69:33:2A:84 +# Fingerprint (SHA1): 6E:3A:55:A4:19:0C:19:5C:93:84:3C:C0:DB:72:2E:31:30:61:F0:B1 +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +MUST_VERIFY_TRUST: CODE_SIGNING +================================================ +MD5 Fingerprint=B0:01:EE:14:D9:AF:29:18:94:76:8E:F1:69:33:2A:84 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 0 (0x0) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=EU, O=AC Camerfirma SA CIF A82743287, OU=http://www.chambersign.org, CN=Chambers of Commerce Root + Validity + Not Before: Sep 30 16:13:43 2003 GMT + Not After : Sep 30 16:13:44 2037 GMT + Subject: C=EU, O=AC Camerfirma SA CIF A82743287, OU=http://www.chambersign.org, CN=Chambers of Commerce Root + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:b7:36:55:e5:a5:5d:18:30:e0:da:89:54:91:fc: + c8:c7:52:f8:2f:50:d9:ef:b1:75:73:65:47:7d:1b: + 5b:ba:75:c5:fc:a1:88:24:fa:2f:ed:ca:08:4a:39: + 54:c4:51:7a:b5:da:60:ea:38:3c:81:b2:cb:f1:bb: + d9:91:23:3f:48:01:70:75:a9:05:2a:ad:1f:71:f3: + c9:54:3d:1d:06:6a:40:3e:b3:0c:85:ee:5c:1b:79: + c2:62:c4:b8:36:8e:35:5d:01:0c:23:04:47:35:aa: + 9b:60:4e:a0:66:3d:cb:26:0a:9c:40:a1:f4:5d:98: + bf:71:ab:a5:00:68:2a:ed:83:7a:0f:a2:14:b5:d4: + 22:b3:80:b0:3c:0c:5a:51:69:2d:58:18:8f:ed:99: + 9e:f1:ae:e2:95:e6:f6:47:a8:d6:0c:0f:b0:58:58: + db:c3:66:37:9e:9b:91:54:33:37:d2:94:1c:6a:48: + c9:c9:f2:a5:da:a5:0c:23:f7:23:0e:9c:32:55:5e: + 71:9c:84:05:51:9a:2d:fd:e6:4e:2a:34:5a:de:ca: + 40:37:67:0c:54:21:55:77:da:0a:0c:cc:97:ae:80: + dc:94:36:4a:f4:3e:ce:36:13:1e:53:e4:ac:4e:3a: + 05:ec:db:ae:72:9c:38:8b:d0:39:3b:89:0a:3e:77: + fe:75 + Exponent: 3 (0x3) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:12 + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.chambersign.org/chambersroot.crl + + X509v3 Subject Key Identifier: + E3:94:F5:B1:4D:E9:DB:A1:29:5B:57:8B:4D:76:06:76:E1:D1:A2:8A + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + Netscape Cert Type: + SSL CA, S/MIME CA, Object Signing CA + X509v3 Subject Alternative Name: + email:chambersroot@chambersign.org + X509v3 Issuer Alternative Name: + email:chambersroot@chambersign.org + X509v3 Certificate Policies: + Policy: 1.3.6.1.4.1.17326.10.3.1 + CPS: http://cps.chambersign.org/cps/chambersroot.html + + Signature Algorithm: sha1WithRSAEncryption + 0c:41:97:c2:1a:86:c0:22:7c:9f:fb:90:f3:1a:d1:03:b1:ef: + 13:f9:21:5f:04:9c:da:c9:a5:8d:27:6c:96:87:91:be:41:90: + 01:72:93:e7:1e:7d:5f:f6:89:c6:5d:a7:40:09:3d:ac:49:45: + 45:dc:2e:8d:30:68:b2:09:ba:fb:c3:2f:cc:ba:0b:df:3f:77: + 7b:46:7d:3a:12:24:8e:96:8f:3c:05:0a:6f:d2:94:28:1d:6d: + 0c:c0:2e:88:22:d5:d8:cf:1d:13:c7:f0:48:d7:d7:05:a7:cf: + c7:47:9e:3b:3c:34:c8:80:4f:d4:14:bb:fc:0d:50:f7:fa:b3: + ec:42:5f:a9:dd:6d:c8:f4:75:cf:7b:c1:72:26:b1:01:1c:5c: + 2c:fd:7a:4e:b4:01:c5:05:57:b9:e7:3c:aa:05:d9:88:e9:07: + 46:41:ce:ef:41:81:ae:58:df:83:a2:ae:ca:d7:77:1f:e7:00: + 3c:9d:6f:8e:e4:32:09:1d:4d:78:34:78:34:3c:94:9b:26:ed: + 4f:71:c6:19:7a:bd:20:22:48:5a:fe:4b:7d:03:b7:e7:58:be: + c6:32:4e:74:1e:68:dd:a8:68:5b:b3:3e:ee:62:7d:d9:80:e8: + 0a:75:7a:b7:ee:b4:65:9a:21:90:e0:aa:d0:98:bc:38:b5:73: + 3c:8b:f8:dc +-----BEGIN CERTIFICATE----- +MIIEvTCCA6WgAwIBAgIBADANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJFVTEn +MCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQL +ExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEiMCAGA1UEAxMZQ2hhbWJlcnMg +b2YgQ29tbWVyY2UgUm9vdDAeFw0wMzA5MzAxNjEzNDNaFw0zNzA5MzAxNjEzNDRa +MH8xCzAJBgNVBAYTAkVVMScwJQYDVQQKEx5BQyBDYW1lcmZpcm1hIFNBIENJRiBB +ODI3NDMyODcxIzAhBgNVBAsTGmh0dHA6Ly93d3cuY2hhbWJlcnNpZ24ub3JnMSIw +IAYDVQQDExlDaGFtYmVycyBvZiBDb21tZXJjZSBSb290MIIBIDANBgkqhkiG9w0B +AQEFAAOCAQ0AMIIBCAKCAQEAtzZV5aVdGDDg2olUkfzIx1L4L1DZ77F1c2VHfRtb +unXF/KGIJPov7coISjlUxFF6tdpg6jg8gbLL8bvZkSM/SAFwdakFKq0fcfPJVD0d +BmpAPrMMhe5cG3nCYsS4No41XQEMIwRHNaqbYE6gZj3LJgqcQKH0XZi/caulAGgq +7YN6D6IUtdQis4CwPAxaUWktWBiP7Zme8a7ileb2R6jWDA+wWFjbw2Y3npuRVDM3 +0pQcakjJyfKl2qUMI/cjDpwyVV5xnIQFUZot/eZOKjRa3spAN2cMVCFVd9oKDMyX +roDclDZK9D7ONhMeU+SsTjoF7Nuucpw4i9A5O4kKPnf+dQIBA6OCAUQwggFAMBIG +A1UdEwEB/wQIMAYBAf8CAQwwPAYDVR0fBDUwMzAxoC+gLYYraHR0cDovL2NybC5j +aGFtYmVyc2lnbi5vcmcvY2hhbWJlcnNyb290LmNybDAdBgNVHQ4EFgQU45T1sU3p +26EpW1eLTXYGduHRooowDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIA +BzAnBgNVHREEIDAegRxjaGFtYmVyc3Jvb3RAY2hhbWJlcnNpZ24ub3JnMCcGA1Ud +EgQgMB6BHGNoYW1iZXJzcm9vdEBjaGFtYmVyc2lnbi5vcmcwWAYDVR0gBFEwTzBN +BgsrBgEEAYGHLgoDATA+MDwGCCsGAQUFBwIBFjBodHRwOi8vY3BzLmNoYW1iZXJz +aWduLm9yZy9jcHMvY2hhbWJlcnNyb290Lmh0bWwwDQYJKoZIhvcNAQEFBQADggEB +AAxBl8IahsAifJ/7kPMa0QOx7xP5IV8EnNrJpY0nbJaHkb5BkAFyk+cefV/2icZd +p0AJPaxJRUXcLo0waLIJuvvDL8y6C98/d3tGfToSJI6WjzwFCm/SlCgdbQzALogi +1djPHRPH8EjX1wWnz8dHnjs8NMiAT9QUu/wNUPf6s+xCX6ndbcj0dc97wXImsQEc +XCz9ek60AcUFV7nnPKoF2YjpB0ZBzu9Bga5Y34OirsrXdx/nADydb47kMgkdTXg0 +eDQ8lJsm7U9xxhl6vSAiSFr+S30Dt+dYvsYyTnQeaN2oaFuzPu5ifdmA6Ap1erfu +tGWaIZDgqtCYvDi1czyL+Nw= +-----END CERTIFICATE----- + +Camerfirma Global Chambersign Root +# Issuer: CN=Global Chambersign Root,OU=http://www.chambersign.org,O=AC Camerfirma SA CIF A82743287,C=EU +# Serial Number: 0 (0x0) +# Subject: CN=Global Chambersign Root,OU=http://www.chambersign.org,O=AC Camerfirma SA CIF A82743287,C=EU +# Not Valid Before: Tue Sep 30 16:14:18 2003 +# Not Valid After : Wed Sep 30 16:14:18 2037 +# Fingerprint (MD5): C5:E6:7B:BF:06:D0:4F:43:ED:C4:7A:65:8A:FB:6B:19 +# Fingerprint (SHA1): 33:9B:6B:14:50:24:9B:55:7A:01:87:72:84:D9:E0:2F:C3:D2:D8:E9 +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +MUST_VERIFY_TRUST: CODE_SIGNING +================================================ +MD5 Fingerprint=C5:E6:7B:BF:06:D0:4F:43:ED:C4:7A:65:8A:FB:6B:19 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 0 (0x0) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=EU, O=AC Camerfirma SA CIF A82743287, OU=http://www.chambersign.org, CN=Global Chambersign Root + Validity + Not Before: Sep 30 16:14:18 2003 GMT + Not After : Sep 30 16:14:18 2037 GMT + Subject: C=EU, O=AC Camerfirma SA CIF A82743287, OU=http://www.chambersign.org, CN=Global Chambersign Root + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:a2:70:a2:d0:9f:42:ae:5b:17:c7:d8:7d:cf:14: + 83:fc:4f:c9:a1:b7:13:af:8a:d7:9e:3e:04:0a:92: + 8b:60:56:fa:b4:32:2f:88:4d:a1:60:08:f4:b7:09: + 4e:a0:49:2f:49:d6:d3:df:9d:97:5a:9f:94:04:70: + ec:3f:59:d9:b7:cc:66:8b:98:52:28:09:02:df:c5: + 2f:84:8d:7a:97:77:bf:ec:40:9d:25:72:ab:b5:3f: + 32:98:fb:b7:b7:fc:72:84:e5:35:87:f9:55:fa:a3: + 1f:0e:6f:2e:28:dd:69:a0:d9:42:10:c6:f8:b5:44: + c2:d0:43:7f:db:bc:e4:a2:3c:6a:55:78:0a:77:a9: + d8:ea:19:32:b7:2f:fe:5c:3f:1b:ee:b1:98:ec:ca: + ad:7a:69:45:e3:96:0f:55:f6:e6:ed:75:ea:65:e8: + 32:56:93:46:89:a8:25:8a:65:06:ee:6b:bf:79:07: + d0:f1:b7:af:ed:2c:4d:92:bb:c0:a8:5f:a7:67:7d: + 04:f2:15:08:70:ac:92:d6:7d:04:d2:33:fb:4c:b6: + 0b:0b:fb:1a:c9:c4:8d:03:a9:7e:5c:f2:50:ab:12: + a5:a1:cf:48:50:a5:ef:d2:c8:1a:13:fa:b0:7f:b1: + 82:1c:77:6a:0f:5f:dc:0b:95:8f:ef:43:7e:e6:45: + 09:25 + Exponent: 3 (0x3) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:12 + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.chambersign.org/chambersignroot.crl + + X509v3 Subject Key Identifier: + 43:9C:36:9F:B0:9E:30:4D:C6:CE:5F:AD:10:AB:E5:03:A5:FA:A9:14 + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + Netscape Cert Type: + SSL CA, S/MIME CA, Object Signing CA + X509v3 Subject Alternative Name: + email:chambersignroot@chambersign.org + X509v3 Issuer Alternative Name: + email:chambersignroot@chambersign.org + X509v3 Certificate Policies: + Policy: 1.3.6.1.4.1.17326.10.1.1 + CPS: http://cps.chambersign.org/cps/chambersignroot.html + + Signature Algorithm: sha1WithRSAEncryption + 3c:3b:70:91:f9:04:54:27:91:e1:ed:ed:fe:68:7f:61:5d:e5: + 41:65:4f:32:f1:18:05:94:6a:1c:de:1f:70:db:3e:7b:32:02: + 34:b5:0c:6c:a1:8a:7c:a5:f4:8f:ff:d4:d8:ad:17:d5:2d:04: + d1:3f:58:80:e2:81:59:88:be:c0:e3:46:93:24:fe:90:bd:26: + a2:30:2d:e8:97:26:57:35:89:74:96:18:f6:15:e2:af:24:19: + 56:02:02:b2:ba:0f:14:ea:c6:8a:66:c1:86:45:55:8b:be:92: + be:9c:a4:04:c7:49:3c:9e:e8:29:7a:89:d7:fe:af:ff:68:f5: + a5:17:90:bd:ac:99:cc:a5:86:57:09:67:46:db:d6:16:c2:46: + f1:e4:a9:50:f5:8f:d1:92:15:d3:5f:3e:c6:00:49:3a:6e:58: + b2:d1:d1:27:0d:25:c8:32:f8:20:11:cd:7d:32:33:48:94:54: + 4c:dd:dc:79:c4:30:9f:eb:8e:b8:55:b5:d7:88:5c:c5:6a:24: + 3d:b2:d3:05:03:51:c6:07:ef:cc:14:72:74:3d:6e:72:ce:18: + 28:8c:4a:a0:77:e5:09:2b:45:44:47:ac:b7:67:7f:01:8a:05: + 5a:93:be:a1:c1:ff:f8:e7:0e:67:a4:47:49:76:5d:75:90:1a: + f5:26:8f:f0 +-----BEGIN CERTIFICATE----- +MIIExTCCA62gAwIBAgIBADANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJFVTEn +MCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQL +ExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEgMB4GA1UEAxMXR2xvYmFsIENo +YW1iZXJzaWduIFJvb3QwHhcNMDMwOTMwMTYxNDE4WhcNMzcwOTMwMTYxNDE4WjB9 +MQswCQYDVQQGEwJFVTEnMCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgy +NzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEgMB4G +A1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwggEgMA0GCSqGSIb3DQEBAQUA +A4IBDQAwggEIAoIBAQCicKLQn0KuWxfH2H3PFIP8T8mhtxOviteePgQKkotgVvq0 +Mi+ITaFgCPS3CU6gSS9J1tPfnZdan5QEcOw/Wdm3zGaLmFIoCQLfxS+EjXqXd7/s +QJ0lcqu1PzKY+7e3/HKE5TWH+VX6ox8Oby4o3Wmg2UIQxvi1RMLQQ3/bvOSiPGpV +eAp3qdjqGTK3L/5cPxvusZjsyq16aUXjlg9V9ubtdepl6DJWk0aJqCWKZQbua795 +B9Dxt6/tLE2Su8CoX6dnfQTyFQhwrJLWfQTSM/tMtgsL+xrJxI0DqX5c8lCrEqWh +z0hQpe/SyBoT+rB/sYIcd2oPX9wLlY/vQ37mRQklAgEDo4IBUDCCAUwwEgYDVR0T +AQH/BAgwBgEB/wIBDDA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3JsLmNoYW1i +ZXJzaWduLm9yZy9jaGFtYmVyc2lnbnJvb3QuY3JsMB0GA1UdDgQWBBRDnDafsJ4w +TcbOX60Qq+UDpfqpFDAOBgNVHQ8BAf8EBAMCAQYwEQYJYIZIAYb4QgEBBAQDAgAH +MCoGA1UdEQQjMCGBH2NoYW1iZXJzaWducm9vdEBjaGFtYmVyc2lnbi5vcmcwKgYD +VR0SBCMwIYEfY2hhbWJlcnNpZ25yb290QGNoYW1iZXJzaWduLm9yZzBbBgNVHSAE +VDBSMFAGCysGAQQBgYcuCgEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly9jcHMuY2hh +bWJlcnNpZ24ub3JnL2Nwcy9jaGFtYmVyc2lnbnJvb3QuaHRtbDANBgkqhkiG9w0B +AQUFAAOCAQEAPDtwkfkEVCeR4e3t/mh/YV3lQWVPMvEYBZRqHN4fcNs+ezICNLUM +bKGKfKX0j//U2K0X1S0E0T9YgOKBWYi+wONGkyT+kL0mojAt6JcmVzWJdJYY9hXi +ryQZVgICsroPFOrGimbBhkVVi76SvpykBMdJPJ7oKXqJ1/6v/2j1pReQvayZzKWG +VwlnRtvWFsJG8eSpUPWP0ZIV018+xgBJOm5YstHRJw0lyDL4IBHNfTIzSJRUTN3c +ecQwn+uOuFW114hcxWokPbLTBQNRxgfvzBRydD1ucs4YKIxKoHflCStFREest2d/ +AYoFWpO+ocH/+OcOZ6RHSXZddZAa9SaP8A== +-----END CERTIFICATE----- + +XRamp Global CA Root +# Issuer: CN=XRamp Global Certification Authority,O=XRamp Security Services Inc,OU=www.xrampsecurity.com,C=US +# Serial Number:50:94:6c:ec:18:ea:d5:9c:4d:d5:97:ef:75:8f:a0:ad +# Subject: CN=XRamp Global Certification Authority,O=XRamp Security Services Inc,OU=www.xrampsecurity.com,C=US +# Not Valid Before: Mon Nov 01 17:14:04 2004 +# Not Valid After : Mon Jan 01 05:37:19 2035 +# Fingerprint (MD5): A1:0B:44:B3:CA:10:D8:00:6E:9D:0F:D8:0F:92:0A:D1 +# Fingerprint (SHA1): B8:01:86:D1:EB:9C:86:A5:41:04:CF:30:54:F3:4C:52:B7:E5:58:C6 +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +MUST_VERIFY_TRUST: CODE_SIGNING +================================================ +MD5 Fingerprint=A1:0B:44:B3:CA:10:D8:00:6E:9D:0F:D8:0F:92:0A:D1 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 50:94:6c:ec:18:ea:d5:9c:4d:d5:97:ef:75:8f:a0:ad + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, OU=www.xrampsecurity.com, O=XRamp Security Services Inc, CN=XRamp Global Certification Authority + Validity + Not Before: Nov 1 17:14:04 2004 GMT + Not After : Jan 1 05:37:19 2035 GMT + Subject: C=US, OU=www.xrampsecurity.com, O=XRamp Security Services Inc, CN=XRamp Global Certification Authority + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:98:24:1e:bd:15:b4:ba:df:c7:8c:a5:27:b6:38: + 0b:69:f3:b6:4e:a8:2c:2e:21:1d:5c:44:df:21:5d: + 7e:23:74:fe:5e:7e:b4:4a:b7:a6:ad:1f:ae:e0:06: + 16:e2:9b:5b:d9:67:74:6b:5d:80:8f:29:9d:86:1b: + d9:9c:0d:98:6d:76:10:28:58:e4:65:b0:7f:4a:98: + 79:9f:e0:c3:31:7e:80:2b:b5:8c:c0:40:3b:11:86: + d0:cb:a2:86:36:60:a4:d5:30:82:6d:d9:6e:d0:0f: + 12:04:33:97:5f:4f:61:5a:f0:e4:f9:91:ab:e7:1d: + 3b:bc:e8:cf:f4:6b:2d:34:7c:e2:48:61:1c:8e:f3: + 61:44:cc:6f:a0:4a:a9:94:b0:4d:da:e7:a9:34:7a: + 72:38:a8:41:cc:3c:94:11:7d:eb:c8:a6:8c:b7:86: + cb:ca:33:3b:d9:3d:37:8b:fb:7a:3e:86:2c:e7:73: + d7:0a:57:ac:64:9b:19:eb:f4:0f:04:08:8a:ac:03: + 17:19:64:f4:5a:25:22:8d:34:2c:b2:f6:68:1d:12: + 6d:d3:8a:1e:14:da:c4:8f:a6:e2:23:85:d5:7a:0d: + bd:6a:e0:e9:ec:ec:17:bb:42:1b:67:aa:25:ed:45: + 83:21:fc:c1:c9:7c:d5:62:3e:fa:f2:c5:2d:d3:fd: + d4:65 + Exponent: 65537 (0x10001) + X509v3 extensions: + 1.3.6.1.4.1.311.20.2: + ...C.A + X509v3 Key Usage: + Digital Signature, Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + C6:4F:A2:3D:06:63:84:09:9C:CE:62:E4:04:AC:8D:5C:B5:E9:B6:1B + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.xrampsecurity.com/XGCA.crl + + 1.3.6.1.4.1.311.21.1: + ... + Signature Algorithm: sha1WithRSAEncryption + 91:15:39:03:01:1b:67:fb:4a:1c:f9:0a:60:5b:a1:da:4d:97: + 62:f9:24:53:27:d7:82:64:4e:90:2e:c3:49:1b:2b:9a:dc:fc: + a8:78:67:35:f1:1d:f0:11:bd:b7:48:e3:10:f6:0d:df:3f:d2: + c9:b6:aa:55:a4:48:ba:02:db:de:59:2e:15:5b:3b:9d:16:7d: + 47:d7:37:ea:5f:4d:76:12:36:bb:1f:d7:a1:81:04:46:20:a3: + 2c:6d:a9:9e:01:7e:3f:29:ce:00:93:df:fd:c9:92:73:89:89: + 64:9e:e7:2b:e4:1c:91:2c:d2:b9:ce:7d:ce:6f:31:99:d3:e6: + be:d2:1e:90:f0:09:14:79:5c:23:ab:4d:d2:da:21:1f:4d:99: + 79:9d:e1:cf:27:9f:10:9b:1c:88:0d:b0:8a:64:41:31:b8:0e: + 6c:90:24:a4:9b:5c:71:8f:ba:bb:7e:1c:1b:db:6a:80:0f:21: + bc:e9:db:a6:b7:40:f4:b2:8b:a9:b1:e4:ef:9a:1a:d0:3d:69: + 99:ee:a8:28:a3:e1:3c:b3:f0:b2:11:9c:cf:7c:40:e6:dd:e7: + 43:7d:a2:d8:3a:b5:a9:8d:f2:34:99:c4:d4:10:e1:06:fd:09: + 84:10:3b:ee:c4:4c:f4:ec:27:7c:42:c2:74:7c:82:8a:09:c9: + b4:03:25:bc +-----BEGIN CERTIFICATE----- +MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCB +gjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEk +MCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRY +UmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQxMTAxMTcx +NDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3 +dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2Vy +dmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS6 +38eMpSe2OAtp87ZOqCwuIR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCP +KZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMxfoArtYzAQDsRhtDLooY2YKTVMIJt2W7Q +DxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FEzG+gSqmUsE3a56k0enI4 +qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqsAxcZZPRa +JSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNVi +PvryxS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0P +BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASs +jVy16bYbMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0 +eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQEwDQYJKoZIhvcNAQEFBQAD +ggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc/Kh4ZzXxHfAR +vbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt +qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLa +IR9NmXmd4c8nnxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSy +i6mx5O+aGtA9aZnuqCij4Tyz8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQ +O+7ETPTsJ3xCwnR8gooJybQDJbw= +-----END CERTIFICATE----- + +Go Daddy Class 2 CA +# Issuer: OU=Go Daddy Class 2 Certification Authority,O="The Go Daddy Group, Inc.",C=US +# Serial Number: 0 (0x0) +# Subject: OU=Go Daddy Class 2 Certification Authority,O="The Go Daddy Group, Inc.",C=US +# Not Valid Before: Tue Jun 29 17:06:20 2004 +# Not Valid After : Thu Jun 29 17:06:20 2034 +# Fingerprint (MD5): 91:DE:06:25:AB:DA:FD:32:17:0C:BB:25:17:2A:84:67 +# Fingerprint (SHA1): 27:96:BA:E6:3F:18:01:E2:77:26:1B:A0:D7:77:70:02:8F:20:EE:E4 +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +MUST_VERIFY_TRUST: CODE_SIGNING +================================================ +MD5 Fingerprint=91:DE:06:25:AB:DA:FD:32:17:0C:BB:25:17:2A:84:67 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 0 (0x0) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=The Go Daddy Group, Inc., OU=Go Daddy Class 2 Certification Authority + Validity + Not Before: Jun 29 17:06:20 2004 GMT + Not After : Jun 29 17:06:20 2034 GMT + Subject: C=US, O=The Go Daddy Group, Inc., OU=Go Daddy Class 2 Certification Authority + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:de:9d:d7:ea:57:18:49:a1:5b:eb:d7:5f:48:86: + ea:be:dd:ff:e4:ef:67:1c:f4:65:68:b3:57:71:a0: + 5e:77:bb:ed:9b:49:e9:70:80:3d:56:18:63:08:6f: + da:f2:cc:d0:3f:7f:02:54:22:54:10:d8:b2:81:d4: + c0:75:3d:4b:7f:c7:77:c3:3e:78:ab:1a:03:b5:20: + 6b:2f:6a:2b:b1:c5:88:7e:c4:bb:1e:b0:c1:d8:45: + 27:6f:aa:37:58:f7:87:26:d7:d8:2d:f6:a9:17:b7: + 1f:72:36:4e:a6:17:3f:65:98:92:db:2a:6e:5d:a2: + fe:88:e0:0b:de:7f:e5:8d:15:e1:eb:cb:3a:d5:e2: + 12:a2:13:2d:d8:8e:af:5f:12:3d:a0:08:05:08:b6: + 5c:a5:65:38:04:45:99:1e:a3:60:60:74:c5:41:a5: + 72:62:1b:62:c5:1f:6f:5f:1a:42:be:02:51:65:a8: + ae:23:18:6a:fc:78:03:a9:4d:7f:80:c3:fa:ab:5a: + fc:a1:40:a4:ca:19:16:fe:b2:c8:ef:5e:73:0d:ee: + 77:bd:9a:f6:79:98:bc:b1:07:67:a2:15:0d:dd:a0: + 58:c6:44:7b:0a:3e:62:28:5f:ba:41:07:53:58:cf: + 11:7e:38:74:c5:f8:ff:b5:69:90:8f:84:74:ea:97: + 1b:af + Exponent: 3 (0x3) + X509v3 extensions: + X509v3 Subject Key Identifier: + D2:C4:B0:D2:91:D4:4C:11:71:B3:61:CB:3D:A1:FE:DD:A8:6A:D4:E3 + X509v3 Authority Key Identifier: + keyid:D2:C4:B0:D2:91:D4:4C:11:71:B3:61:CB:3D:A1:FE:DD:A8:6A:D4:E3 + DirName:/C=US/O=The Go Daddy Group, Inc./OU=Go Daddy Class 2 Certification Authority + serial:00 + + X509v3 Basic Constraints: + CA:TRUE + Signature Algorithm: sha1WithRSAEncryption + 32:4b:f3:b2:ca:3e:91:fc:12:c6:a1:07:8c:8e:77:a0:33:06: + 14:5c:90:1e:18:f7:08:a6:3d:0a:19:f9:87:80:11:6e:69:e4: + 96:17:30:ff:34:91:63:72:38:ee:cc:1c:01:a3:1d:94:28:a4: + 31:f6:7a:c4:54:d7:f6:e5:31:58:03:a2:cc:ce:62:db:94:45: + 73:b5:bf:45:c9:24:b5:d5:82:02:ad:23:79:69:8d:b8:b6:4d: + ce:cf:4c:ca:33:23:e8:1c:88:aa:9d:8b:41:6e:16:c9:20:e5: + 89:9e:cd:3b:da:70:f7:7e:99:26:20:14:54:25:ab:6e:73:85: + e6:9b:21:9d:0a:6c:82:0e:a8:f8:c2:0c:fa:10:1e:6c:96:ef: + 87:0d:c4:0f:61:8b:ad:ee:83:2b:95:f8:8e:92:84:72:39:eb: + 20:ea:83:ed:83:cd:97:6e:08:bc:eb:4e:26:b6:73:2b:e4:d3: + f6:4c:fe:26:71:e2:61:11:74:4a:ff:57:1a:87:0f:75:48:2e: + cf:51:69:17:a0:02:12:61:95:d5:d1:40:b2:10:4c:ee:c4:ac: + 10:43:a6:a5:9e:0a:d5:95:62:9a:0d:cf:88:82:c5:32:0c:e4: + 2b:9f:45:e6:0d:9f:28:9c:b1:b9:2a:5a:57:ad:37:0f:af:1d: + 7f:db:bd:9f +-----BEGIN CERTIFICATE----- +MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh +MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE +YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3 +MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo +ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg +MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN +ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA +PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w +wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi +EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY +avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+ +YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE +sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h +/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5 +IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD +ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy +OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P +TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ +HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER +dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf +ReYNnyicsbkqWletNw+vHX/bvZ8= +-----END CERTIFICATE----- + +Starfield Class 2 CA +# Issuer: OU=Starfield Class 2 Certification Authority,O="Starfield Technologies, Inc.",C=US +# Serial Number: 0 (0x0) +# Subject: OU=Starfield Class 2 Certification Authority,O="Starfield Technologies, Inc.",C=US +# Not Valid Before: Tue Jun 29 17:39:16 2004 +# Not Valid After : Thu Jun 29 17:39:16 2034 +# Fingerprint (MD5): 32:4A:4B:BB:C8:63:69:9B:BE:74:9A:C6:DD:1D:46:24 +# Fingerprint (SHA1): AD:7E:1C:28:B0:64:EF:8F:60:03:40:20:14:C3:D0:E3:37:0E:B5:8A +MUST_VERIFY_TRUST: CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +================================================ +MD5 Fingerprint=32:4A:4B:BB:C8:63:69:9B:BE:74:9A:C6:DD:1D:46:24 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 0 (0x0) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=Starfield Technologies, Inc., OU=Starfield Class 2 Certification Authority + Validity + Not Before: Jun 29 17:39:16 2004 GMT + Not After : Jun 29 17:39:16 2034 GMT + Subject: C=US, O=Starfield Technologies, Inc., OU=Starfield Class 2 Certification Authority + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:b7:32:c8:fe:e9:71:a6:04:85:ad:0c:11:64:df: + ce:4d:ef:c8:03:18:87:3f:a1:ab:fb:3c:a6:9f:f0: + c3:a1:da:d4:d8:6e:2b:53:90:fb:24:a4:3e:84:f0: + 9e:e8:5f:ec:e5:27:44:f5:28:a6:3f:7b:de:e0:2a: + f0:c8:af:53:2f:9e:ca:05:01:93:1e:8f:66:1c:39: + a7:4d:fa:5a:b6:73:04:25:66:eb:77:7f:e7:59:c6: + 4a:99:25:14:54:eb:26:c7:f3:7f:19:d5:30:70:8f: + af:b0:46:2a:ff:ad:eb:29:ed:d7:9f:aa:04:87:a3: + d4:f9:89:a5:34:5f:db:43:91:82:36:d9:66:3c:b1: + b8:b9:82:fd:9c:3a:3e:10:c8:3b:ef:06:65:66:7a: + 9b:19:18:3d:ff:71:51:3c:30:2e:5f:be:3d:77:73: + b2:5d:06:6c:c3:23:56:9a:2b:85:26:92:1c:a7:02: + b3:e4:3f:0d:af:08:79:82:b8:36:3d:ea:9c:d3:35: + b3:bc:69:ca:f5:cc:9d:e8:fd:64:8d:17:80:33:6e: + 5e:4a:5d:99:c9:1e:87:b4:9d:1a:c0:d5:6e:13:35: + 23:5e:df:9b:5f:3d:ef:d6:f7:76:c2:ea:3e:bb:78: + 0d:1c:42:67:6b:04:d8:f8:d6:da:6f:8b:f2:44:a0: + 01:ab + Exponent: 3 (0x3) + X509v3 extensions: + X509v3 Subject Key Identifier: + BF:5F:B7:D1:CE:DD:1F:86:F4:5B:55:AC:DC:D7:10:C2:0E:A9:88:E7 + X509v3 Authority Key Identifier: + keyid:BF:5F:B7:D1:CE:DD:1F:86:F4:5B:55:AC:DC:D7:10:C2:0E:A9:88:E7 + DirName:/C=US/O=Starfield Technologies, Inc./OU=Starfield Class 2 Certification Authority + serial:00 + + X509v3 Basic Constraints: + CA:TRUE + Signature Algorithm: sha1WithRSAEncryption + 05:9d:3f:88:9d:d1:c9:1a:55:a1:ac:69:f3:f3:59:da:9b:01: + 87:1a:4f:57:a9:a1:79:09:2a:db:f7:2f:b2:1e:cc:c7:5e:6a: + d8:83:87:a1:97:ef:49:35:3e:77:06:41:58:62:bf:8e:58:b8: + 0a:67:3f:ec:b3:dd:21:66:1f:c9:54:fa:72:cc:3d:4c:40:d8: + 81:af:77:9e:83:7a:bb:a2:c7:f5:34:17:8e:d9:11:40:f4:fc: + 2c:2a:4d:15:7f:a7:62:5d:2e:25:d3:00:0b:20:1a:1d:68:f9: + 17:b8:f4:bd:8b:ed:28:59:dd:4d:16:8b:17:83:c8:b2:65:c7: + 2d:7a:a5:aa:bc:53:86:6d:dd:57:a4:ca:f8:20:41:0b:68:f0: + f4:fb:74:be:56:5d:7a:79:f5:f9:1d:85:e3:2d:95:be:f5:71: + 90:43:cc:8d:1f:9a:00:0a:87:29:e9:55:22:58:00:23:ea:e3: + 12:43:29:5b:47:08:dd:8c:41:6a:65:06:a8:e5:21:aa:41:b4: + 95:21:95:b9:7d:d1:34:ab:13:d6:ad:bc:dc:e2:3d:39:cd:bd: + 3e:75:70:a1:18:59:03:c9:22:b4:8f:9c:d5:5e:2a:d7:a5:b6: + d4:0a:6d:f8:b7:40:11:46:9a:1f:79:0e:62:bf:0f:97:ec:e0: + 2f:1f:17:94 +-----BEGIN CERTIFICATE----- +MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl +MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp +U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw +NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE +ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp +ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3 +DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf +8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN ++lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0 +X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa +K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA +1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G +A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR +zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0 +YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD +bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w +DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3 +L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D +eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl +xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp +VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY +WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q= +-----END CERTIFICATE----- + +Taiwan GRCA +# Issuer: O=Government Root Certification Authority,C=TW +# Serial Number:1f:9d:59:5a:d7:2f:c2:06:44:a5:80:08:69:e3:5e:f6 +# Subject: O=Government Root Certification Authority,C=TW +# Not Valid Before: Thu Dec 05 13:23:33 2002 +# Not Valid After : Sun Dec 05 13:23:33 2032 +# Fingerprint (MD5): 37:85:44:53:32:45:1F:20:F0:F3:95:E1:25:C4:43:4E +# Fingerprint (SHA1): F4:8B:11:BF:DE:AB:BE:94:54:20:71:E6:41:DE:6B:BE:88:2B:40:B9 +MUST_VERIFY_TRUST: CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +================================================ +MD5 Fingerprint=37:85:44:53:32:45:1F:20:F0:F3:95:E1:25:C4:43:4E +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 1f:9d:59:5a:d7:2f:c2:06:44:a5:80:08:69:e3:5e:f6 + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=TW, O=Government Root Certification Authority + Validity + Not Before: Dec 5 13:23:33 2002 GMT + Not After : Dec 5 13:23:33 2032 GMT + Subject: C=TW, O=Government Root Certification Authority + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:9a:25:b8:ec:cc:a2:75:a8:7b:f7:ce:5b:59:8a: + c9:d1:86:12:08:54:ec:9c:f2:e7:46:f6:88:f3:7c: + e9:a5:df:4c:47:36:a4:1b:01:1c:7f:1e:57:8a:8d: + c3:c5:d1:21:e3:da:24:3f:48:2b:fb:9f:2e:a1:94: + e7:2c:1c:93:d1:bf:1b:01:87:53:99:ce:a7:f5:0a: + 21:76:77:ff:a9:b7:c6:73:94:4f:46:f7:10:49:37: + fa:a8:59:49:5d:6a:81:07:56:f2:8a:f9:06:d0:f7: + 70:22:4d:b4:b7:41:b9:32:b8:b1:f0:b1:c3:9c:3f: + 70:fd:53:dd:81:aa:d8:63:78:f6:d8:53:6e:a1:ac: + 6a:84:24:72:54:86:c6:d2:b2:ca:1c:0e:79:81:d6: + b5:70:62:08:01:2e:4e:4f:0e:d5:11:af:a9:af:e5: + 9a:bf:dc:cc:87:6d:26:e4:c9:57:a2:fb:96:f9:cc: + e1:3f:53:8c:6c:4c:7e:9b:53:08:0b:6c:17:fb:67: + c8:c2:ad:b1:cd:80:b4:97:dc:76:01:16:15:e9:6a: + d7:a4:e1:78:47:ce:86:d5:fb:31:f3:fa:31:be:34: + aa:28:fb:70:4c:1d:49:c7:af:2c:9d:6d:66:a6:b6: + 8d:64:7e:b5:20:6a:9d:3b:81:b6:8f:40:00:67:4b: + 89:86:b8:cc:65:fe:15:53:e9:04:c1:d6:5f:1d:44: + d7:0a:2f:27:9a:46:7d:a1:0d:75:ad:54:86:15:dc: + 49:3b:f1:96:ce:0f:9b:a0:ec:a3:7a:5d:be:d5:2a: + 75:42:e5:7b:de:a5:b6:aa:af:28:ac:ac:90:ac:38: + b7:d5:68:35:26:7a:dc:f7:3b:f3:fd:45:9b:d1:bb: + 43:78:6e:6f:f1:42:54:6a:98:f0:0d:ad:97:e9:52: + 5e:e9:d5:6a:72:de:6a:f7:1b:60:14:f4:a5:e4:b6: + 71:67:aa:1f:ea:e2:4d:c1:42:40:fe:67:46:17:38: + 2f:47:3f:71:9c:ae:e5:21:ca:61:2d:6d:07:a8:84: + 7c:2d:ee:51:25:f1:63:90:9e:fd:e1:57:88:6b:ef: + 8a:23:6d:b1:e6:bd:3f:ad:d1:3d:96:0b:85:8d:cd: + 6b:27:bb:b7:05:9b:ec:bb:91:a9:0a:07:12:02:97: + 4e:20:90:f0:ff:0d:1e:e2:41:3b:d3:40:3a:e7:8d: + 5d:da:66:e4:02:b0:07:52:98:5c:0e:8e:33:9c:c2: + a6:95:fb:55:19:6e:4c:8e:ae:4b:0f:bd:c1:38:4d: + 5e:8f:84:1d:66:cd:c5:60:96:b4:52:5a:05:89:8e: + 95:7a:98:c1:91:3c:95:23:b2:0e:f4:79:b4:c9:7c: + c1:4a:21 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + CC:CC:EF:CC:29:60:A4:3B:B1:92:B6:3C:FA:32:62:8F:AC:25:15:3B + X509v3 Basic Constraints: + CA:TRUE + setCext-hashedRoot: + 0/0-...0...+......0...g*........"...(6....2.1:.Qe + Signature Algorithm: sha1WithRSAEncryption + 40:80:4a:fa:26:c9:ce:5e:30:dd:4f:86:74:76:58:f5:ae:b3: + 83:33:78:a4:7a:74:17:19:4e:e9:52:b5:b9:e0:0a:74:62:aa: + 68:ca:78:a0:4c:9a:8e:2c:23:2e:d5:6a:12:24:bf:d4:68:d3: + 8a:d0:d8:9c:9f:b4:1f:0c:de:38:7e:57:38:fc:8d:e2:4f:5e: + 0c:9f:ab:3b:d2:ff:75:97:cb:a4:e3:67:08:ff:e5:c0:16:b5: + 48:01:7d:e9:f9:0a:ff:1b:e5:6a:69:bf:78:21:a8:c2:a7:23: + a9:86:ab:76:56:e8:0e:0c:f6:13:dd:2a:66:8a:64:49:3d:1a: + 18:87:90:04:9f:42:52:b7:4f:cb:fe:47:41:76:35:ef:ff:00: + 76:36:45:32:9b:c6:46:85:5d:e2:24:b0:1e:e3:48:96:98:57: + 47:94:55:7a:0f:41:b1:44:24:f3:c1:fe:1a:6b:bf:88:fd:c1: + a6:da:93:60:5e:81:4a:99:20:9c:48:66:19:b5:00:79:54:0f: + b8:2c:2f:4b:bc:a9:5d:5b:60:7f:8c:87:a5:e0:52:63:2a:be: + d8:3b:85:40:15:fe:1e:b6:65:3f:c5:4b:da:7e:b5:7a:35:29: + a3:2e:7a:98:60:22:a3:f4:7d:27:4e:2d:ea:b4:74:3c:e9:0f: + a4:33:0f:10:11:bc:13:01:d6:e5:0e:d3:bf:b5:12:a2:e1:45: + 23:c0:cc:08:6e:61:b7:89:ab:83:e3:24:1e:e6:5d:07:e7:1f: + 20:3e:cf:67:c8:e7:ac:30:6d:27:4b:68:6e:4b:2a:5c:02:08: + 34:db:f8:76:e4:67:a3:26:9c:3f:a2:32:c2:4a:c5:81:18:31: + 10:56:aa:84:ef:2d:0a:ff:b8:1f:77:d2:bf:a5:58:a0:62:e4: + d7:4b:91:75:8d:89:80:98:7e:6d:cb:53:4e:5e:af:f6:b2:97: + 85:97:b9:da:55:06:b9:24:ee:d7:c6:38:1e:63:1b:12:3b:95: + e1:58:ac:f2:df:84:d5:5f:99:2f:0d:55:5b:e6:38:db:2e:3f: + 72:e9:48:85:cb:bb:29:13:8f:1e:38:55:b9:f3:b2:c4:30:99: + 23:4e:5d:f2:48:a1:12:0c:dc:12:90:09:90:54:91:03:3c:47: + e5:d5:c9:65:e0:b7:4b:7d:ec:47:d3:b3:0b:3e:ad:9e:d0:74: + 00:0e:eb:bd:51:ad:c0:de:2c:c0:c3:6a:fe:ef:dc:0b:a7:fa: + 46:df:60:db:9c:a6:59:50:75:23:69:73:93:b2:f9:fc:02:d3: + 47:e6:71:ce:10:02:ee:27:8c:84:ff:ac:45:0d:13:5c:83:32: + e0:25:a5:86:2c:7c:f4:12 +-----BEGIN CERTIFICATE----- +MIIFcjCCA1qgAwIBAgIQH51ZWtcvwgZEpYAIaeNe9jANBgkqhkiG9w0BAQUFADA/ +MQswCQYDVQQGEwJUVzEwMC4GA1UECgwnR292ZXJubWVudCBSb290IENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5MB4XDTAyMTIwNTEzMjMzM1oXDTMyMTIwNTEzMjMzM1ow +PzELMAkGA1UEBhMCVFcxMDAuBgNVBAoMJ0dvdmVybm1lbnQgUm9vdCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB +AJoluOzMonWoe/fOW1mKydGGEghU7Jzy50b2iPN86aXfTEc2pBsBHH8eV4qNw8XR +IePaJD9IK/ufLqGU5ywck9G/GwGHU5nOp/UKIXZ3/6m3xnOUT0b3EEk3+qhZSV1q +gQdW8or5BtD3cCJNtLdBuTK4sfCxw5w/cP1T3YGq2GN49thTbqGsaoQkclSGxtKy +yhwOeYHWtXBiCAEuTk8O1RGvqa/lmr/czIdtJuTJV6L7lvnM4T9TjGxMfptTCAts +F/tnyMKtsc2AtJfcdgEWFelq16TheEfOhtX7MfP6Mb40qij7cEwdScevLJ1tZqa2 +jWR+tSBqnTuBto9AAGdLiYa4zGX+FVPpBMHWXx1E1wovJ5pGfaENda1UhhXcSTvx +ls4Pm6Dso3pdvtUqdULle96ltqqvKKyskKw4t9VoNSZ63Pc78/1Fm9G7Q3hub/FC +VGqY8A2tl+lSXunVanLeavcbYBT0peS2cWeqH+riTcFCQP5nRhc4L0c/cZyu5SHK +YS1tB6iEfC3uUSXxY5Ce/eFXiGvviiNtsea9P63RPZYLhY3Naye7twWb7LuRqQoH +EgKXTiCQ8P8NHuJBO9NAOueNXdpm5AKwB1KYXA6OM5zCppX7VRluTI6uSw+9wThN +Xo+EHWbNxWCWtFJaBYmOlXqYwZE8lSOyDvR5tMl8wUohAgMBAAGjajBoMB0GA1Ud +DgQWBBTMzO/MKWCkO7GStjz6MmKPrCUVOzAMBgNVHRMEBTADAQH/MDkGBGcqBwAE +MTAvMC0CAQAwCQYFKw4DAhoFADAHBgVnKgMAAAQUA5vwIhP/lSg209yewDL7MTqK +UWUwDQYJKoZIhvcNAQEFBQADggIBAECASvomyc5eMN1PhnR2WPWus4MzeKR6dBcZ +TulStbngCnRiqmjKeKBMmo4sIy7VahIkv9Ro04rQ2JyftB8M3jh+Vzj8jeJPXgyf +qzvS/3WXy6TjZwj/5cAWtUgBfen5Cv8b5Wppv3ghqMKnI6mGq3ZW6A4M9hPdKmaK +ZEk9GhiHkASfQlK3T8v+R0F2Ne//AHY2RTKbxkaFXeIksB7jSJaYV0eUVXoPQbFE +JPPB/hprv4j9wabak2BegUqZIJxIZhm1AHlUD7gsL0u8qV1bYH+Mh6XgUmMqvtg7 +hUAV/h62ZT/FS9p+tXo1KaMuephgIqP0fSdOLeq0dDzpD6QzDxARvBMB1uUO07+1 +EqLhRSPAzAhuYbeJq4PjJB7mXQfnHyA+z2fI56wwbSdLaG5LKlwCCDTb+HbkZ6Mm +nD+iMsJKxYEYMRBWqoTvLQr/uB930r+lWKBi5NdLkXWNiYCYfm3LU05er/ayl4WX +udpVBrkk7tfGOB5jGxI7leFYrPLfhNVfmS8NVVvmONsuP3LpSIXLuykTjx44Vbnz +ssQwmSNOXfJIoRIM3BKQCZBUkQM8R+XVyWXgt0t97EfTsws+rZ7QdAAO671RrcDe +LMDDav7v3Aun+kbfYNucpllQdSNpc5Oy+fwC00fmcc4QAu4njIT/rEUNE1yDMuAl +pYYsfPQS +-----END CERTIFICATE----- + +DigiCert Assured ID Root CA +# Issuer: CN=DigiCert Assured ID Root CA,OU=www.digicert.com,O=DigiCert Inc,C=US +# Serial Number:0c:e7:e0:e5:17:d8:46:fe:8f:e5:60:fc:1b:f0:30:39 +# Subject: CN=DigiCert Assured ID Root CA,OU=www.digicert.com,O=DigiCert Inc,C=US +# Not Valid Before: Fri Nov 10 00:00:00 2006 +# Not Valid After : Mon Nov 10 00:00:00 2031 +# Fingerprint (MD5): 87:CE:0B:7B:2A:0E:49:00:E1:58:71:9B:37:A8:93:72 +# Fingerprint (SHA1): 05:63:B8:63:0D:62:D7:5A:BB:C8:AB:1E:4B:DF:B5:A8:99:B2:4D:43 +MUST_VERIFY_TRUST: CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +================================================ +MD5 Fingerprint=87:CE:0B:7B:2A:0E:49:00:E1:58:71:9B:37:A8:93:72 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 0c:e7:e0:e5:17:d8:46:fe:8f:e5:60:fc:1b:f0:30:39 + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Assured ID Root CA + Validity + Not Before: Nov 10 00:00:00 2006 GMT + Not After : Nov 10 00:00:00 2031 GMT + Subject: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Assured ID Root CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:ad:0e:15:ce:e4:43:80:5c:b1:87:f3:b7:60:f9: + 71:12:a5:ae:dc:26:94:88:aa:f4:ce:f5:20:39:28: + 58:60:0c:f8:80:da:a9:15:95:32:61:3c:b5:b1:28: + 84:8a:8a:dc:9f:0a:0c:83:17:7a:8f:90:ac:8a:e7: + 79:53:5c:31:84:2a:f6:0f:98:32:36:76:cc:de:dd: + 3c:a8:a2:ef:6a:fb:21:f2:52:61:df:9f:20:d7:1f: + e2:b1:d9:fe:18:64:d2:12:5b:5f:f9:58:18:35:bc: + 47:cd:a1:36:f9:6b:7f:d4:b0:38:3e:c1:1b:c3:8c: + 33:d9:d8:2f:18:fe:28:0f:b3:a7:83:d6:c3:6e:44: + c0:61:35:96:16:fe:59:9c:8b:76:6d:d7:f1:a2:4b: + 0d:2b:ff:0b:72:da:9e:60:d0:8e:90:35:c6:78:55: + 87:20:a1:cf:e5:6d:0a:c8:49:7c:31:98:33:6c:22: + e9:87:d0:32:5a:a2:ba:13:82:11:ed:39:17:9d:99: + 3a:72:a1:e6:fa:a4:d9:d5:17:31:75:ae:85:7d:22: + ae:3f:01:46:86:f6:28:79:c8:b1:da:e4:57:17:c4: + 7e:1c:0e:b0:b4:92:a6:56:b3:bd:b2:97:ed:aa:a7: + f0:b7:c5:a8:3f:95:16:d0:ff:a1:96:eb:08:5f:18: + 77:4f + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + 45:EB:A2:AF:F4:92:CB:82:31:2D:51:8B:A7:A7:21:9D:F3:6D:C8:0F + X509v3 Authority Key Identifier: + keyid:45:EB:A2:AF:F4:92:CB:82:31:2D:51:8B:A7:A7:21:9D:F3:6D:C8:0F + + Signature Algorithm: sha1WithRSAEncryption + a2:0e:bc:df:e2:ed:f0:e3:72:73:7a:64:94:bf:f7:72:66:d8: + 32:e4:42:75:62:ae:87:eb:f2:d5:d9:de:56:b3:9f:cc:ce:14: + 28:b9:0d:97:60:5c:12:4c:58:e4:d3:3d:83:49:45:58:97:35: + 69:1a:a8:47:ea:56:c6:79:ab:12:d8:67:81:84:df:7f:09:3c: + 94:e6:b8:26:2c:20:bd:3d:b3:28:89:f7:5f:ff:22:e2:97:84: + 1f:e9:65:ef:87:e0:df:c1:67:49:b3:5d:eb:b2:09:2a:eb:26: + ed:78:be:7d:3f:2b:f3:b7:26:35:6d:5f:89:01:b6:49:5b:9f: + 01:05:9b:ab:3d:25:c1:cc:b6:7f:c2:f1:6f:86:c6:fa:64:68: + eb:81:2d:94:eb:42:b7:fa:8c:1e:dd:62:f1:be:50:67:b7:6c: + bd:f3:f1:1f:6b:0c:36:07:16:7f:37:7c:a9:5b:6d:7a:f1:12: + 46:60:83:d7:27:04:be:4b:ce:97:be:c3:67:2a:68:11:df:80: + e7:0c:33:66:bf:13:0d:14:6e:f3:7f:1f:63:10:1e:fa:8d:1b: + 25:6d:6c:8f:a5:b7:61:01:b1:d2:a3:26:a1:10:71:9d:ad:e2: + c3:f9:c3:99:51:b7:2b:07:08:ce:2e:e6:50:b2:a7:fa:0a:45: + 2f:a2:f0:f2 +-----BEGIN CERTIFICATE----- +MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv +b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl +cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c +JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP +mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+ +wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4 +VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/ +AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB +AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW +BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun +pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC +dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf +fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm +NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx +H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe ++o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== +-----END CERTIFICATE----- + +DigiCert Global Root CA +# Issuer: CN=DigiCert Global Root CA,OU=www.digicert.com,O=DigiCert Inc,C=US +# Serial Number:08:3b:e0:56:90:42:46:b1:a1:75:6a:c9:59:91:c7:4a +# Subject: CN=DigiCert Global Root CA,OU=www.digicert.com,O=DigiCert Inc,C=US +# Not Valid Before: Fri Nov 10 00:00:00 2006 +# Not Valid After : Mon Nov 10 00:00:00 2031 +# Fingerprint (MD5): 79:E4:A9:84:0D:7D:3A:96:D7:C0:4F:E2:43:4C:89:2E +# Fingerprint (SHA1): A8:98:5D:3A:65:E5:E5:C4:B2:D7:D6:6D:40:C6:DD:2F:B1:9C:54:36 +MUST_VERIFY_TRUST: CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +================================================ +MD5 Fingerprint=79:E4:A9:84:0D:7D:3A:96:D7:C0:4F:E2:43:4C:89:2E +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 08:3b:e0:56:90:42:46:b1:a1:75:6a:c9:59:91:c7:4a + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Global Root CA + Validity + Not Before: Nov 10 00:00:00 2006 GMT + Not After : Nov 10 00:00:00 2031 GMT + Subject: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Global Root CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:e2:3b:e1:11:72:de:a8:a4:d3:a3:57:aa:50:a2: + 8f:0b:77:90:c9:a2:a5:ee:12:ce:96:5b:01:09:20: + cc:01:93:a7:4e:30:b7:53:f7:43:c4:69:00:57:9d: + e2:8d:22:dd:87:06:40:00:81:09:ce:ce:1b:83:bf: + df:cd:3b:71:46:e2:d6:66:c7:05:b3:76:27:16:8f: + 7b:9e:1e:95:7d:ee:b7:48:a3:08:da:d6:af:7a:0c: + 39:06:65:7f:4a:5d:1f:bc:17:f8:ab:be:ee:28:d7: + 74:7f:7a:78:99:59:85:68:6e:5c:23:32:4b:bf:4e: + c0:e8:5a:6d:e3:70:bf:77:10:bf:fc:01:f6:85:d9: + a8:44:10:58:32:a9:75:18:d5:d1:a2:be:47:e2:27: + 6a:f4:9a:33:f8:49:08:60:8b:d4:5f:b4:3a:84:bf: + a1:aa:4a:4c:7d:3e:cf:4f:5f:6c:76:5e:a0:4b:37: + 91:9e:dc:22:e6:6d:ce:14:1a:8e:6a:cb:fe:cd:b3: + 14:64:17:c7:5b:29:9e:32:bf:f2:ee:fa:d3:0b:42: + d4:ab:b7:41:32:da:0c:d4:ef:f8:81:d5:bb:8d:58: + 3f:b5:1b:e8:49:28:a2:70:da:31:04:dd:f7:b2:16: + f2:4c:0a:4e:07:a8:ed:4a:3d:5e:b5:7f:a3:90:c3: + af:27 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + 03:DE:50:35:56:D1:4C:BB:66:F0:A3:E2:1B:1B:C3:97:B2:3D:D1:55 + X509v3 Authority Key Identifier: + keyid:03:DE:50:35:56:D1:4C:BB:66:F0:A3:E2:1B:1B:C3:97:B2:3D:D1:55 + + Signature Algorithm: sha1WithRSAEncryption + cb:9c:37:aa:48:13:12:0a:fa:dd:44:9c:4f:52:b0:f4:df:ae: + 04:f5:79:79:08:a3:24:18:fc:4b:2b:84:c0:2d:b9:d5:c7:fe: + f4:c1:1f:58:cb:b8:6d:9c:7a:74:e7:98:29:ab:11:b5:e3:70: + a0:a1:cd:4c:88:99:93:8c:91:70:e2:ab:0f:1c:be:93:a9:ff: + 63:d5:e4:07:60:d3:a3:bf:9d:5b:09:f1:d5:8e:e3:53:f4:8e: + 63:fa:3f:a7:db:b4:66:df:62:66:d6:d1:6e:41:8d:f2:2d:b5: + ea:77:4a:9f:9d:58:e2:2b:59:c0:40:23:ed:2d:28:82:45:3e: + 79:54:92:26:98:e0:80:48:a8:37:ef:f0:d6:79:60:16:de:ac: + e8:0e:cd:6e:ac:44:17:38:2f:49:da:e1:45:3e:2a:b9:36:53: + cf:3a:50:06:f7:2e:e8:c4:57:49:6c:61:21:18:d5:04:ad:78: + 3c:2c:3a:80:6b:a7:eb:af:15:14:e9:d8:89:c1:b9:38:6c:e2: + 91:6c:8a:ff:64:b9:77:25:57:30:c0:1b:24:a3:e1:dc:e9:df: + 47:7c:b5:b4:24:08:05:30:ec:2d:bd:0b:bf:45:bf:50:b9:a9: + f3:eb:98:01:12:ad:c8:88:c6:98:34:5f:8d:0a:3c:c6:e9:d5: + 95:95:6d:de +-----BEGIN CERTIFICATE----- +MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD +QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB +CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 +nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt +43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P +T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 +gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO +BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR +TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw +DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr +hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg +06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF +PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls +YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk +CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= +-----END CERTIFICATE----- + +DigiCert High Assurance EV Root CA +# Issuer: CN=DigiCert High Assurance EV Root CA,OU=www.digicert.com,O=DigiCert Inc,C=US +# Serial Number:02:ac:5c:26:6a:0b:40:9b:8f:0b:79:f2:ae:46:25:77 +# Subject: CN=DigiCert High Assurance EV Root CA,OU=www.digicert.com,O=DigiCert Inc,C=US +# Not Valid Before: Fri Nov 10 00:00:00 2006 +# Not Valid After : Mon Nov 10 00:00:00 2031 +# Fingerprint (MD5): D4:74:DE:57:5C:39:B2:D3:9C:85:83:C5:C0:65:49:8A +# Fingerprint (SHA1): 5F:B7:EE:06:33:E2:59:DB:AD:0C:4C:9A:E6:D3:8F:1A:61:C7:DC:25 +MUST_VERIFY_TRUST: CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +================================================ +MD5 Fingerprint=D4:74:DE:57:5C:39:B2:D3:9C:85:83:C5:C0:65:49:8A +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 02:ac:5c:26:6a:0b:40:9b:8f:0b:79:f2:ae:46:25:77 + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert High Assurance EV Root CA + Validity + Not Before: Nov 10 00:00:00 2006 GMT + Not After : Nov 10 00:00:00 2031 GMT + Subject: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert High Assurance EV Root CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:c6:cc:e5:73:e6:fb:d4:bb:e5:2d:2d:32:a6:df: + e5:81:3f:c9:cd:25:49:b6:71:2a:c3:d5:94:34:67: + a2:0a:1c:b0:5f:69:a6:40:b1:c4:b7:b2:8f:d0:98: + a4:a9:41:59:3a:d3:dc:94:d6:3c:db:74:38:a4:4a: + cc:4d:25:82:f7:4a:a5:53:12:38:ee:f3:49:6d:71: + 91:7e:63:b6:ab:a6:5f:c3:a4:84:f8:4f:62:51:be: + f8:c5:ec:db:38:92:e3:06:e5:08:91:0c:c4:28:41: + 55:fb:cb:5a:89:15:7e:71:e8:35:bf:4d:72:09:3d: + be:3a:38:50:5b:77:31:1b:8d:b3:c7:24:45:9a:a7: + ac:6d:00:14:5a:04:b7:ba:13:eb:51:0a:98:41:41: + 22:4e:65:61:87:81:41:50:a6:79:5c:89:de:19:4a: + 57:d5:2e:e6:5d:1c:53:2c:7e:98:cd:1a:06:16:a4: + 68:73:d0:34:04:13:5c:a1:71:d3:5a:7c:55:db:5e: + 64:e1:37:87:30:56:04:e5:11:b4:29:80:12:f1:79: + 39:88:a2:02:11:7c:27:66:b7:88:b7:78:f2:ca:0a: + a8:38:ab:0a:64:c2:bf:66:5d:95:84:c1:a1:25:1e: + 87:5d:1a:50:0b:20:12:cc:41:bb:6e:0b:51:38:b8: + 4b:cb + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + B1:3E:C3:69:03:F8:BF:47:01:D4:98:26:1A:08:02:EF:63:64:2B:C3 + X509v3 Authority Key Identifier: + keyid:B1:3E:C3:69:03:F8:BF:47:01:D4:98:26:1A:08:02:EF:63:64:2B:C3 + + Signature Algorithm: sha1WithRSAEncryption + 1c:1a:06:97:dc:d7:9c:9f:3c:88:66:06:08:57:21:db:21:47: + f8:2a:67:aa:bf:18:32:76:40:10:57:c1:8a:f3:7a:d9:11:65: + 8e:35:fa:9e:fc:45:b5:9e:d9:4c:31:4b:b8:91:e8:43:2c:8e: + b3:78:ce:db:e3:53:79:71:d6:e5:21:94:01:da:55:87:9a:24: + 64:f6:8a:66:cc:de:9c:37:cd:a8:34:b1:69:9b:23:c8:9e:78: + 22:2b:70:43:e3:55:47:31:61:19:ef:58:c5:85:2f:4e:30:f6: + a0:31:16:23:c8:e7:e2:65:16:33:cb:bf:1a:1b:a0:3d:f8:ca: + 5e:8b:31:8b:60:08:89:2d:0c:06:5c:52:b7:c4:f9:0a:98:d1: + 15:5f:9f:12:be:7c:36:63:38:bd:44:a4:7f:e4:26:2b:0a:c4: + 97:69:0d:e9:8c:e2:c0:10:57:b8:c8:76:12:91:55:f2:48:69: + d8:bc:2a:02:5b:0f:44:d4:20:31:db:f4:ba:70:26:5d:90:60: + 9e:bc:4b:17:09:2f:b4:cb:1e:43:68:c9:07:27:c1:d2:5c:f7: + ea:21:b9:68:12:9c:3c:9c:bf:9e:fc:80:5c:9b:63:cd:ec:47: + aa:25:27:67:a0:37:f3:00:82:7d:54:d7:a9:f8:e9:2e:13:a3: + 77:e8:1f:4a +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j +ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL +MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 +LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug +RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm ++9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW +PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM +xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB +Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3 +hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg +EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF +MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA +FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec +nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z +eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF +hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2 +Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe +vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep ++OkuE6N36B9K +-----END CERTIFICATE----- + +Certplus Class 2 Primary CA +# Issuer: CN=Class 2 Primary CA,O=Certplus,C=FR +# Serial Number:00:85:bd:4b:f3:d8:da:e3:69:f6:94:d7:5f:c3:a5:44:23 +# Subject: CN=Class 2 Primary CA,O=Certplus,C=FR +# Not Valid Before: Wed Jul 07 17:05:00 1999 +# Not Valid After : Sat Jul 06 23:59:59 2019 +# Fingerprint (MD5): 88:2C:8C:52:B8:A2:3C:F3:F7:BB:03:EA:AE:AC:42:0B +# Fingerprint (SHA1): 74:20:74:41:72:9C:DD:92:EC:79:31:D8:23:10:8D:C2:81:92:E2:BB +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +MUST_VERIFY_TRUST: CODE_SIGNING +================================================ +MD5 Fingerprint=88:2C:8C:52:B8:A2:3C:F3:F7:BB:03:EA:AE:AC:42:0B +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 85:bd:4b:f3:d8:da:e3:69:f6:94:d7:5f:c3:a5:44:23 + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=FR, O=Certplus, CN=Class 2 Primary CA + Validity + Not Before: Jul 7 17:05:00 1999 GMT + Not After : Jul 6 23:59:59 2019 GMT + Subject: C=FR, O=Certplus, CN=Class 2 Primary CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:dc:50:96:d0:12:f8:35:d2:08:78:7a:b6:52:70: + fd:6f:ee:cf:b9:11:cb:5d:77:e1:ec:e9:7e:04:8d: + d6:cc:6f:73:43:57:60:ac:33:0a:44:ec:03:5f:1c: + 80:24:91:e5:a8:91:56:12:82:f7:e0:2b:f4:db:ae: + 61:2e:89:10:8d:6b:6c:ba:b3:02:bd:d5:36:c5:48: + 37:23:e2:f0:5a:37:52:33:17:12:e2:d1:60:4d:be: + 2f:41:11:e3:f6:17:25:0c:8b:91:c0:1b:99:7b:99: + 56:0d:af:ee:d2:bc:47:57:e3:79:49:7b:34:89:27: + 24:84:de:b1:ec:e9:58:4e:fe:4e:df:5a:be:41:ad: + ac:08:c5:18:0e:ef:d2:53:ee:6c:d0:9d:12:01:13: + 8d:dc:80:62:f7:95:a9:44:88:4a:71:4e:60:55:9e: + db:23:19:79:56:07:0c:3f:63:0b:5c:b0:e2:be:7e: + 15:fc:94:33:58:41:38:74:c4:e1:8f:8b:df:26:ac: + 1f:b5:8b:3b:b7:43:59:6b:b0:24:a6:6d:90:8b:c4: + 72:ea:5d:33:98:b7:cb:de:5e:7b:ef:94:f1:1b:3e: + ca:c9:21:c1:c5:98:02:aa:a2:f6:5b:77:9b:f5:7e: + 96:55:34:1c:67:69:c0:f1:42:e3:47:ac:fc:28:1c: + 66:55 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:TRUE, pathlen:10 + X509v3 Key Usage: + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + E3:73:2D:DF:CB:0E:28:0C:DE:DD:B3:A4:CA:79:B8:8E:BB:E8:30:89 + Netscape Cert Type: + SSL CA, S/MIME CA + X509v3 CRL Distribution Points: + + Full Name: + URI:http://www.certplus.com/CRL/class2.crl + + Signature Algorithm: sha1WithRSAEncryption + a7:54:cf:88:44:19:cb:df:d4:7f:00:df:56:33:62:b5:f7:51: + 01:90:eb:c3:3f:d1:88:44:e9:24:5d:ef:e7:14:bd:20:b7:9a: + 3c:00:fe:6d:9f:db:90:dc:d7:f4:62:d6:8b:70:5d:e7:e5:04: + 48:a9:68:7c:c9:f1:42:f3:6c:7f:c5:7a:7c:1d:51:88:ba:d2: + 0a:3e:27:5d:de:2d:51:4e:d3:13:64:69:e4:2e:e3:d3:e7:9b: + 09:99:a6:e0:95:9b:ce:1a:d7:7f:be:3c:ce:52:b3:11:15:c1: + 0f:17:cd:03:bb:9c:25:15:ba:a2:76:89:fc:06:f1:18:d0:93: + 4b:0e:7c:82:b7:a5:f4:f6:5f:fe:ed:40:a6:9d:84:74:39:b9: + dc:1e:85:16:da:29:1b:86:23:00:c9:bb:89:7e:6e:80:88:1e: + 2f:14:b4:03:24:a8:32:6f:03:9a:47:2c:30:be:56:c6:a7:42: + 02:70:1b:ea:40:d8:ba:05:03:70:07:a4:96:ff:fd:48:33:0a: + e1:dc:a5:81:90:9b:4d:dd:7d:e7:e7:b2:cd:5c:c8:6a:95:f8: + a5:f6:8d:c4:5d:78:08:be:7b:06:d6:49:cf:19:36:50:23:2e: + 08:e6:9e:05:4d:47:18:d5:16:e9:b1:d6:b6:10:d5:bb:97:bf: + a2:8e:b4:54 +-----BEGIN CERTIFICATE----- +MIIDkjCCAnqgAwIBAgIRAIW9S/PY2uNp9pTXX8OlRCMwDQYJKoZIhvcNAQEFBQAw +PTELMAkGA1UEBhMCRlIxETAPBgNVBAoTCENlcnRwbHVzMRswGQYDVQQDExJDbGFz +cyAyIFByaW1hcnkgQ0EwHhcNOTkwNzA3MTcwNTAwWhcNMTkwNzA2MjM1OTU5WjA9 +MQswCQYDVQQGEwJGUjERMA8GA1UEChMIQ2VydHBsdXMxGzAZBgNVBAMTEkNsYXNz +IDIgUHJpbWFyeSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANxQ +ltAS+DXSCHh6tlJw/W/uz7kRy1134ezpfgSN1sxvc0NXYKwzCkTsA18cgCSR5aiR +VhKC9+Ar9NuuYS6JEI1rbLqzAr3VNsVINyPi8Fo3UjMXEuLRYE2+L0ER4/YXJQyL +kcAbmXuZVg2v7tK8R1fjeUl7NIknJITesezpWE7+Tt9avkGtrAjFGA7v0lPubNCd +EgETjdyAYveVqUSISnFOYFWe2yMZeVYHDD9jC1yw4r5+FfyUM1hBOHTE4Y+L3yas +H7WLO7dDWWuwJKZtkIvEcupdM5i3y95ee++U8Rs+yskhwcWYAqqi9lt3m/V+llU0 +HGdpwPFC40es/CgcZlUCAwEAAaOBjDCBiTAPBgNVHRMECDAGAQH/AgEKMAsGA1Ud +DwQEAwIBBjAdBgNVHQ4EFgQU43Mt38sOKAze3bOkynm4jrvoMIkwEQYJYIZIAYb4 +QgEBBAQDAgEGMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly93d3cuY2VydHBsdXMu +Y29tL0NSTC9jbGFzczIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCnVM+IRBnL39R/ +AN9WM2K191EBkOvDP9GIROkkXe/nFL0gt5o8AP5tn9uQ3Nf0YtaLcF3n5QRIqWh8 +yfFC82x/xXp8HVGIutIKPidd3i1RTtMTZGnkLuPT55sJmabglZvOGtd/vjzOUrMR +FcEPF80Du5wlFbqidon8BvEY0JNLDnyCt6X09l/+7UCmnYR0ObncHoUW2ikbhiMA +ybuJfm6AiB4vFLQDJKgybwOaRywwvlbGp0ICcBvqQNi6BQNwB6SW//1IMwrh3KWB +kJtN3X3n57LNXMhqlfil9o3EXXgIvnsG1knPGTZQIy4I5p4FTUcY1Rbpsda2ENW7 +l7+ijrRU +-----END CERTIFICATE----- + +DST Root CA X3 +# Issuer: CN=DST Root CA X3,O=Digital Signature Trust Co. +# Serial Number:44:af:b0:80:d6:a3:27:ba:89:30:39:86:2e:f8:40:6b +# Subject: CN=DST Root CA X3,O=Digital Signature Trust Co. +# Not Valid Before: Sat Sep 30 21:12:19 2000 +# Not Valid After : Thu Sep 30 14:01:15 2021 +# Fingerprint (MD5): 41:03:52:DC:0F:F7:50:1B:16:F0:02:8E:BA:6F:45:C5 +# Fingerprint (SHA1): DA:C9:02:4F:54:D8:F6:DF:94:93:5F:B1:73:26:38:CA:6A:D7:7C:13 +MUST_VERIFY_TRUST: EMAIL_PROTECTION, CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH +================================================= +MD5 Fingerprint=41:03:52:DC:0F:F7:50:1B:16:F0:02:8E:BA:6F:45:C5 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 44:af:b0:80:d6:a3:27:ba:89:30:39:86:2e:f8:40:6b + Signature Algorithm: sha1WithRSAEncryption + Issuer: O=Digital Signature Trust Co., CN=DST Root CA X3 + Validity + Not Before: Sep 30 21:12:19 2000 GMT + Not After : Sep 30 14:01:15 2021 GMT + Subject: O=Digital Signature Trust Co., CN=DST Root CA X3 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:df:af:e9:97:50:08:83:57:b4:cc:62:65:f6:90: + 82:ec:c7:d3:2c:6b:30:ca:5b:ec:d9:c3:7d:c7:40: + c1:18:14:8b:e0:e8:33:76:49:2a:e3:3f:21:49:93: + ac:4e:0e:af:3e:48:cb:65:ee:fc:d3:21:0f:65:d2: + 2a:d9:32:8f:8c:e5:f7:77:b0:12:7b:b5:95:c0:89: + a3:a9:ba:ed:73:2e:7a:0c:06:32:83:a2:7e:8a:14: + 30:cd:11:a0:e1:2a:38:b9:79:0a:31:fd:50:bd:80: + 65:df:b7:51:63:83:c8:e2:88:61:ea:4b:61:81:ec: + 52:6b:b9:a2:e2:4b:1a:28:9f:48:a3:9e:0c:da:09: + 8e:3e:17:2e:1e:dd:20:df:5b:c6:2a:8a:ab:2e:bd: + 70:ad:c5:0b:1a:25:90:74:72:c5:7b:6a:ab:34:d6: + 30:89:ff:e5:68:13:7b:54:0b:c8:d6:ae:ec:5a:9c: + 92:1e:3d:64:b3:8c:c6:df:bf:c9:41:70:ec:16:72: + d5:26:ec:38:55:39:43:d0:fc:fd:18:5c:40:f1:97: + eb:d5:9a:9b:8d:1d:ba:da:25:b9:c6:d8:df:c1:15: + 02:3a:ab:da:6e:f1:3e:2e:f5:5c:08:9c:3c:d6:83: + 69:e4:10:9b:19:2a:b6:29:57:e3:e5:3d:9b:9f:f0: + 02:5d + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + C4:A7:B1:A4:7B:2C:71:FA:DB:E1:4B:90:75:FF:C4:15:60:85:89:10 + Signature Algorithm: sha1WithRSAEncryption + a3:1a:2c:9b:17:00:5c:a9:1e:ee:28:66:37:3a:bf:83:c7:3f: + 4b:c3:09:a0:95:20:5d:e3:d9:59:44:d2:3e:0d:3e:bd:8a:4b: + a0:74:1f:ce:10:82:9c:74:1a:1d:7e:98:1a:dd:cb:13:4b:b3: + 20:44:e4:91:e9:cc:fc:7d:a5:db:6a:e5:fe:e6:fd:e0:4e:dd: + b7:00:3a:b5:70:49:af:f2:e5:eb:02:f1:d1:02:8b:19:cb:94: + 3a:5e:48:c4:18:1e:58:19:5f:1e:02:5a:f0:0c:f1:b1:ad:a9: + dc:59:86:8b:6e:e9:91:f5:86:ca:fa:b9:66:33:aa:59:5b:ce: + e2:a7:16:73:47:cb:2b:cc:99:b0:37:48:cf:e3:56:4b:f5:cf: + 0f:0c:72:32:87:c6:f0:44:bb:53:72:6d:43:f5:26:48:9a:52: + 67:b7:58:ab:fe:67:76:71:78:db:0d:a2:56:14:13:39:24:31: + 85:a2:a8:02:5a:30:47:e1:dd:50:07:bc:02:09:90:00:eb:64: + 63:60:9b:16:bc:88:c9:12:e6:d2:7d:91:8b:f9:3d:32:8d:65: + b4:e9:7c:b1:57:76:ea:c5:b6:28:39:bf:15:65:1c:c8:f6:77: + 96:6a:0a:8d:77:0b:d8:91:0b:04:8e:07:db:29:b6:0a:ee:9d: + 82:35:35:10 +-----BEGIN CERTIFICATE----- +MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/ +MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT +DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow +PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD +Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O +rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq +OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b +xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw +7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD +aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV +HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG +SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69 +ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr +AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz +R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5 +JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo +Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ +-----END CERTIFICATE----- + +SwissSign Gold CA - G2 +# Issuer: CN=SwissSign Gold CA - G2,O=SwissSign AG,C=CH +# Serial Number:00:bb:40:1c:43:f5:5e:4f:b0 +# Subject: CN=SwissSign Gold CA - G2,O=SwissSign AG,C=CH +# Not Valid Before: Wed Oct 25 08:30:35 2006 +# Not Valid After : Sat Oct 25 08:30:35 2036 +# Fingerprint (MD5): 24:77:D9:A8:91:D1:3B:FA:88:2D:C2:FF:F8:CD:33:93 +# Fingerprint (SHA1): D8:C5:38:8A:B7:30:1B:1B:6E:D4:7A:E6:45:25:3A:6F:9F:1A:27:61 +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +MUST_VERIFY_TRUST: CODE_SIGNING +================================================ +MD5 Fingerprint=24:77:D9:A8:91:D1:3B:FA:88:2D:C2:FF:F8:CD:33:93 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + bb:40:1c:43:f5:5e:4f:b0 + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=CH, O=SwissSign AG, CN=SwissSign Gold CA - G2 + Validity + Not Before: Oct 25 08:30:35 2006 GMT + Not After : Oct 25 08:30:35 2036 GMT + Subject: C=CH, O=SwissSign AG, CN=SwissSign Gold CA - G2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:af:e4:ee:7e:8b:24:0e:12:6e:a9:50:2d:16:44: + 3b:92:92:5c:ca:b8:5d:84:92:42:13:2a:bc:65:57: + 82:40:3e:57:24:cd:50:8b:25:2a:b7:6f:fc:ef:a2: + d0:c0:1f:02:24:4a:13:96:8f:23:13:e6:28:58:00: + a3:47:c7:06:a7:84:23:2b:bb:bd:96:2b:7f:55:cc: + 8b:c1:57:1f:0e:62:65:0f:dd:3d:56:8a:73:da:ae: + 7e:6d:ba:81:1c:7e:42:8c:20:35:d9:43:4d:84:fa: + 84:db:52:2c:f3:0e:27:77:0b:6b:bf:11:2f:72:78: + 9f:2e:d8:3e:e6:18:37:5a:2a:72:f9:da:62:90:92: + 95:ca:1f:9c:e9:b3:3c:2b:cb:f3:01:13:bf:5a:cf: + c1:b5:0a:60:bd:dd:b5:99:64:53:b8:a0:96:b3:6f: + e2:26:77:91:8c:e0:62:10:02:9f:34:0f:a4:d5:92: + 33:51:de:be:8d:ba:84:7a:60:3c:6a:db:9f:2b:ec: + de:de:01:3f:6e:4d:e5:50:86:cb:b4:af:ed:44:40: + c5:ca:5a:8c:da:d2:2b:7c:a8:ee:be:a6:e5:0a:aa: + 0e:a5:df:05:52:b7:55:c7:22:5d:32:6a:97:97:63: + 13:db:c9:db:79:36:7b:85:3a:4a:c5:52:89:f9:24: + e7:9d:77:a9:82:ff:55:1c:a5:71:69:2b:d1:02:24: + f2:b3:26:d4:6b:da:04:55:e5:c1:0a:c7:6d:30:37: + 90:2a:e4:9e:14:33:5e:16:17:55:c5:5b:b5:cb:34: + 89:92:f1:9d:26:8f:a1:07:d4:c6:b2:78:50:db:0c: + 0c:0b:7c:0b:8c:41:d7:b9:e9:dd:8c:88:f7:a3:4d: + b2:32:cc:d8:17:da:cd:b7:ce:66:9d:d4:fd:5e:ff: + bd:97:3e:29:75:e7:7e:a7:62:58:af:25:34:a5:41: + c7:3d:bc:0d:50:ca:03:03:0f:08:5a:1f:95:73:78: + 62:bf:af:72:14:69:0e:a5:e5:03:0e:78:8e:26:28: + 42:f0:07:0b:62:20:10:67:39:46:fa:a9:03:cc:04: + 38:7a:66:ef:20:83:b5:8c:4a:56:8e:91:00:fc:8e: + 5c:82:de:88:a0:c3:e2:68:6e:7d:8d:ef:3c:dd:65: + f4:5d:ac:51:ef:24:80:ae:aa:56:97:6f:f9:ad:7d: + da:61:3f:98:77:3c:a5:91:b6:1c:8c:26:da:65:a2: + 09:6d:c1:e2:54:e3:b9:ca:4c:4c:80:8f:77:7b:60: + 9a:1e:df:b6:f2:48:1e:0e:ba:4e:54:6d:98:e0:e1: + a2:1a:a2:77:50:cf:c4:63:92:ec:47:19:9d:eb:e6: + 6b:ce:c1 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + 5B:25:7B:96:A4:65:51:7E:B8:39:F3:C0:78:66:5E:E8:3A:E7:F0:EE + X509v3 Authority Key Identifier: + keyid:5B:25:7B:96:A4:65:51:7E:B8:39:F3:C0:78:66:5E:E8:3A:E7:F0:EE + + X509v3 Certificate Policies: + Policy: 2.16.756.1.89.1.2.1.1 + CPS: http://repository.swisssign.com/ + + Signature Algorithm: sha1WithRSAEncryption + 27:ba:e3:94:7c:f1:ae:c0:de:17:e6:e5:d8:d5:f5:54:b0:83: + f4:bb:cd:5e:05:7b:4f:9f:75:66:af:3c:e8:56:7e:fc:72:78: + 38:03:d9:2b:62:1b:00:b9:f8:e9:60:cd:cc:ce:51:8a:c7:50: + 31:6e:e1:4a:7e:18:2f:69:59:b6:3d:64:81:2b:e3:83:84:e6: + 22:87:8e:7d:e0:ee:02:99:61:b8:1e:f4:b8:2b:88:12:16:84: + c2:31:93:38:96:31:a6:b9:3b:53:3f:c3:24:93:56:5b:69:92: + ec:c5:c1:bb:38:00:e3:ec:17:a9:b8:dc:c7:7c:01:83:9f:32: + 47:ba:52:22:34:1d:32:7a:09:56:a7:7c:25:36:a9:3d:4b:da: + c0:82:6f:0a:bb:12:c8:87:4b:27:11:f9:1e:2d:c7:93:3f:9e: + db:5f:26:6b:52:d9:2e:8a:f1:14:c6:44:8d:15:a9:b7:bf:bd: + de:a6:1a:ee:ae:2d:fb:48:77:17:fe:bb:ec:af:18:f5:2a:51: + f0:39:84:97:95:6c:6e:1b:c3:2b:c4:74:60:79:25:b0:0a:27: + df:df:5e:d2:39:cf:45:7d:42:4b:df:b3:2c:1e:c5:c6:5d:ca: + 55:3a:a0:9c:69:9a:8f:da:ef:b2:b0:3c:9f:87:6c:12:2b:65: + 70:15:52:31:1a:24:cf:6f:31:23:50:1f:8c:4f:8f:23:c3:74: + 41:63:1c:55:a8:14:dd:3e:e0:51:50:cf:f1:1b:30:56:0e:92: + b0:82:85:d8:83:cb:22:64:bc:2d:b8:25:d5:54:a2:b8:06:ea: + ad:92:a4:24:a0:c1:86:b5:4a:13:6a:47:cf:2e:0b:56:95:54: + cb:ce:9a:db:6a:b4:a6:b2:db:41:08:86:27:77:f7:6a:a0:42: + 6c:0b:38:ce:d7:75:50:32:92:c2:df:2b:30:22:48:d0:d5:41: + 38:25:5d:a4:e9:5d:9f:c6:94:75:d0:45:fd:30:97:43:8f:90: + ab:0a:c7:86:73:60:4a:69:2d:de:a5:78:d7:06:da:6a:9e:4b: + 3e:77:3a:20:13:22:01:d0:bf:68:9e:63:60:6b:35:4d:0b:6d: + ba:a1:3d:c0:93:e0:7f:23:b3:55:ad:72:25:4e:46:f9:d2:16: + ef:b0:64:c1:01:9e:e9:ca:a0:6a:98:0e:cf:d8:60:f2:2f:49: + b8:e4:42:e1:38:35:16:f4:c8:6e:4f:f7:81:56:e8:ba:a3:be: + 23:af:ae:fd:6f:03:e0:02:3b:30:76:fa:1b:6d:41:cf:01:b1: + e9:b8:c9:66:f4:db:26:f3:3a:a4:74:f2:49:24:5b:c9:b0:d0: + 57:c1:fa:3e:7a:e1:97:c9 +-----BEGIN CERTIFICATE----- +MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV +BAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2ln +biBHb2xkIENBIC0gRzIwHhcNMDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBF +MQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMR8wHQYDVQQDExZT +d2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC +CgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUqt2/8 +76LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+ +bbqBHH5CjCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c +6bM8K8vzARO/Ws/BtQpgvd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqE +emA8atufK+ze3gE/bk3lUIbLtK/tREDFylqM2tIrfKjuvqblCqoOpd8FUrdVxyJd +MmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvRAiTysybUa9oEVeXBCsdt +MDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuendjIj3o02y +MszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69y +FGkOpeUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPi +aG59je883WX0XaxR7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxM +gI93e2CaHt+28kgeDrpOVG2Y4OGiGqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCB +qTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUWyV7 +lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64OfPAeGZe6Drn +8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov +L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe6 +45R88a7A3hfm5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczO +UYrHUDFu4Up+GC9pWbY9ZIEr44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5 +O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOfMke6UiI0HTJ6CVanfCU2qT1L2sCC +bwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6mGu6uLftIdxf+u+yv +GPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxpmo/a +77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCC +hdiDyyJkvC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid3 +92qgQmwLOM7XdVAyksLfKzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEpp +Ld6leNcG2mqeSz53OiATIgHQv2ieY2BrNU0LbbqhPcCT4H8js1WtciVORvnSFu+w +ZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6LqjviOvrv1vA+ACOzB2+htt +Qc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ +-----END CERTIFICATE----- + +SwissSign Silver CA - G2 +# Issuer: CN=SwissSign Silver CA - G2,O=SwissSign AG,C=CH +# Serial Number:4f:1b:d4:2f:54:bb:2f:4b +# Subject: CN=SwissSign Silver CA - G2,O=SwissSign AG,C=CH +# Not Valid Before: Wed Oct 25 08:32:46 2006 +# Not Valid After : Sat Oct 25 08:32:46 2036 +# Fingerprint (MD5): E0:06:A1:C9:7D:CF:C9:FC:0D:C0:56:75:96:D8:62:13 +# Fingerprint (SHA1): 9B:AA:E5:9F:56:EE:21:CB:43:5A:BE:25:93:DF:A7:F0:40:D1:1D:CB +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +MUST_VERIFY_TRUST: CODE_SIGNING +================================================ +MD5 Fingerprint=E0:06:A1:C9:7D:CF:C9:FC:0D:C0:56:75:96:D8:62:13 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 5700383053117599563 (0x4f1bd42f54bb2f4b) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=CH, O=SwissSign AG, CN=SwissSign Silver CA - G2 + Validity + Not Before: Oct 25 08:32:46 2006 GMT + Not After : Oct 25 08:32:46 2036 GMT + Subject: C=CH, O=SwissSign AG, CN=SwissSign Silver CA - G2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:c4:f1:87:7f:d3:78:31:f7:38:c9:f8:c3:99:43: + bc:c7:f7:bc:37:e7:4e:71:ba:4b:8f:a5:73:1d:5c: + 6e:98:ae:03:57:ae:38:37:43:2f:17:3d:1f:c8:ce: + 68:10:c1:78:ae:19:03:2b:10:fa:2c:79:83:f6:e8: + b9:68:b9:55:f2:04:44:a7:39:f9:fc:04:8b:1e:f1: + a2:4d:27:f9:61:7b:ba:b7:e5:a2:13:b6:eb:61:3e: + d0:6c:d1:e6:fb:fa:5e:ed:1d:b4:9e:a0:35:5b:a1: + 92:cb:f0:49:92:fe:85:0a:05:3e:e6:d9:0b:e2:4f: + bb:dc:95:37:fc:91:e9:32:35:22:d1:1f:3a:4e:27: + 85:9d:b0:15:94:32:da:61:0d:47:4d:60:42:ae:92: + 47:e8:83:5a:50:58:e9:8a:8b:b9:5d:a1:dc:dd:99: + 4a:1f:36:67:bb:48:e4:83:b6:37:eb:48:3a:af:0f: + 67:8f:17:07:e8:04:ca:ef:6a:31:87:d4:c0:b6:f9: + 94:71:7b:67:64:b8:b6:91:4a:42:7b:65:2e:30:6a: + 0c:f5:90:ee:95:e6:f2:cd:82:ec:d9:a1:4a:ec:f6: + b2:4b:e5:45:85:e6:6d:78:93:04:2e:9c:82:6d:36: + a9:c4:31:64:1f:86:83:0b:2a:f4:35:0a:78:c9:55: + cf:41:b0:47:e9:30:9f:99:be:61:a8:06:84:b9:28: + 7a:5f:38:d9:1b:a9:38:b0:83:7f:73:c1:c3:3b:48: + 2a:82:0f:21:9b:b8:cc:a8:35:c3:84:1b:83:b3:3e: + be:a4:95:69:01:3a:89:00:78:04:d9:c9:f4:99:19: + ab:56:7e:5b:8b:86:39:15:91:a4:10:2c:09:32:80: + 60:b3:93:c0:2a:b6:18:0b:9d:7e:8d:49:f2:10:4a: + 7f:f9:d5:46:2f:19:92:a3:99:a7:26:ac:bb:8c:3c: + e6:0e:bc:47:07:dc:73:51:f1:70:64:2f:08:f9:b4: + 47:1d:30:6c:44:ea:29:37:85:92:68:66:bc:83:38: + fe:7b:39:2e:d3:50:f0:1f:fb:5e:60:b6:a9:a6:fa: + 27:41:f1:9b:18:72:f2:f5:84:74:4a:c9:67:c4:54: + ae:48:64:df:8c:d1:6e:b0:1d:e1:07:8f:08:1e:99: + 9c:71:e9:4c:d8:a5:f7:47:12:1f:74:d1:51:9e:86: + f3:c2:a2:23:40:0b:73:db:4b:a6:e7:73:06:8c:c1: + a0:e9:c1:59:ac:46:fa:e6:2f:f8:cf:71:9c:46:6d: + b9:c4:15:8d:38:79:03:45:48:ef:c4:5d:d7:08:ee: + 87:39:22:86:b2:0d:0f:58:43:f7:71:a9:48:2e:fd: + ea:d6:1f + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + 17:A0:CD:C1:E4:41:B6:3A:5B:3B:CB:45:9D:BD:1C:C2:98:FA:86:58 + X509v3 Authority Key Identifier: + keyid:17:A0:CD:C1:E4:41:B6:3A:5B:3B:CB:45:9D:BD:1C:C2:98:FA:86:58 + + X509v3 Certificate Policies: + Policy: 2.16.756.1.89.1.3.1.1 + CPS: http://repository.swisssign.com/ + + Signature Algorithm: sha1WithRSAEncryption + 73:c6:81:e0:27:d2:2d:0f:e0:95:30:e2:9a:41:7f:50:2c:5f: + 5f:62:61:a9:86:6a:69:18:0c:74:49:d6:5d:84:ea:41:52:18: + 6f:58:ad:50:56:20:6a:c6:bd:28:69:58:91:dc:91:11:35:a9: + 3a:1d:bc:1a:a5:60:9e:d8:1f:7f:45:91:69:d9:7e:bb:78:72: + c1:06:0f:2a:ce:8f:85:70:61:ac:a0:cd:0b:b8:39:29:56:84: + 32:4e:86:bb:3d:c4:2a:d9:d7:1f:72:ee:fe:51:a1:22:41:b1: + 71:02:63:1a:82:b0:62:ab:5e:57:12:1f:df:cb:dd:75:a0:c0: + 5d:79:90:8c:1b:e0:50:e6:de:31:fe:98:7b:70:5f:a5:90:d8: + ad:f8:02:b6:6f:d3:60:dd:40:4b:22:c5:3d:ad:3a:7a:9f:1a: + 1a:47:91:79:33:ba:82:dc:32:69:03:96:6e:1f:4b:f0:71:fe: + e3:67:72:a0:b1:bf:5c:8b:e4:fa:99:22:c7:84:b9:1b:8d:23: + 97:3f:ed:25:e0:cf:65:bb:f5:61:04:ef:dd:1e:b2:5a:41:22: + 5a:a1:9f:5d:2c:e8:5b:c9:6d:a9:0c:0c:78:aa:60:c6:56:8f: + 01:5a:0c:68:bc:69:19:79:c4:1f:7e:97:05:bf:c5:e9:24:51: + 5e:d4:d5:4b:53:ed:d9:23:5a:36:03:65:a3:c1:03:ad:41:30: + f3:46:1b:85:90:af:65:b5:d5:b1:e4:16:5b:78:75:1d:97:7a: + 6d:59:a9:2a:8f:7b:de:c3:87:89:10:99:49:73:78:c8:3d:bd: + 51:35:74:2a:d5:f1:7e:69:1b:2a:bb:3b:bd:25:b8:9a:5a:3d: + 72:61:90:66:87:ee:0c:d6:4d:d4:11:74:0b:6a:fe:0b:03:fc: + a3:55:57:89:fe:4a:cb:ae:5b:17:05:c8:f2:8d:23:31:53:38: + d2:2d:6a:3f:82:b9:8d:08:6a:f7:5e:41:74:6e:c3:11:7e:07: + ac:29:60:91:3f:38:ca:57:10:0d:bd:30:2f:c7:a5:e6:41:a0: + da:ae:05:87:9a:a0:a4:65:6c:4c:09:0c:89:ba:b8:d3:b9:c0: + 93:8a:30:fa:8d:e5:9a:6b:15:01:4e:67:aa:da:62:56:3e:84: + 08:66:d2:c4:36:7d:a7:3e:10:fc:88:e0:d4:80:e5:00:bd:aa: + f3:4e:06:a3:7a:6a:f9:62:72:e3:09:4f:eb:9b:0e:01:23:f1: + 9f:bb:7c:dc:dc:6c:11:97:25:b2:f2:b4:63:14:d2:06:2a:67: + 8c:83:f5:ce:ea:07:d8:9a:6a:1e:ec:e4:0a:bb:2a:4c:eb:09: + 60:39:ce:ca:62:d8:2e:6e +-----BEGIN CERTIFICATE----- +MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UE +BhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWdu +IFNpbHZlciBDQSAtIEcyMB4XDTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0Nlow +RzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMY +U3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A +MIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644N0Mv +Fz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7br +YT7QbNHm+/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieF +nbAVlDLaYQ1HTWBCrpJH6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH +6ATK72oxh9TAtvmUcXtnZLi2kUpCe2UuMGoM9ZDulebyzYLs2aFK7PayS+VFheZt +eJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5hqAaEuSh6XzjZG6k4sIN/ +c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5FZGkECwJ +MoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRH +HTBsROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTf +jNFusB3hB48IHpmccelM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb6 +5i/4z3GcRm25xBWNOHkDRUjvxF3XCO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOB +rDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU +F6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRBtjpbO8tFnb0c +wpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0 +cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIB +AHPGgeAn0i0P4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShp +WJHckRE1qTodvBqlYJ7YH39FkWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9 +xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L3XWgwF15kIwb4FDm3jH+mHtwX6WQ +2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx/uNncqCxv1yL5PqZ +IseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFaDGi8 +aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2X +em1ZqSqPe97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQR +dAtq/gsD/KNVV4n+SsuuWxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/ +OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJDIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+ +hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ubDgEj8Z+7fNzcbBGXJbLy +tGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u +-----END CERTIFICATE----- + +GeoTrust Primary Certification Authority +# Issuer: CN=GeoTrust Primary Certification Authority,O=GeoTrust Inc.,C=US +# Serial Number:18:ac:b5:6a:fd:69:b6:15:3a:63:6c:af:da:fa:c4:a1 +# Subject: CN=GeoTrust Primary Certification Authority,O=GeoTrust Inc.,C=US +# Not Valid Before: Mon Nov 27 00:00:00 2006 +# Not Valid After : Wed Jul 16 23:59:59 2036 +# Fingerprint (MD5): 02:26:C3:01:5E:08:30:37:43:A9:D0:7D:CF:37:E6:BF +# Fingerprint (SHA1): 32:3C:11:8E:1B:F7:B8:B6:52:54:E2:E2:10:0D:D6:02:90:37:F0:96 +MUST_VERIFY_TRUST: EMAIL_PROTECTION, CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH +================================================= +MD5 Fingerprint=02:26:C3:01:5E:08:30:37:43:A9:D0:7D:CF:37:E6:BF +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 18:ac:b5:6a:fd:69:b6:15:3a:63:6c:af:da:fa:c4:a1 + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=GeoTrust Inc., CN=GeoTrust Primary Certification Authority + Validity + Not Before: Nov 27 00:00:00 2006 GMT + Not After : Jul 16 23:59:59 2036 GMT + Subject: C=US, O=GeoTrust Inc., CN=GeoTrust Primary Certification Authority + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:be:b8:15:7b:ff:d4:7c:7d:67:ad:83:64:7b:c8: + 42:53:2d:df:f6:84:08:20:61:d6:01:59:6a:9c:44: + 11:af:ef:76:fd:95:7e:ce:61:30:bb:7a:83:5f:02: + bd:01:66:ca:ee:15:8d:6f:a1:30:9c:bd:a1:85:9e: + 94:3a:f3:56:88:00:31:cf:d8:ee:6a:96:02:d9:ed: + 03:8c:fb:75:6d:e7:ea:b8:55:16:05:16:9a:f4:e0: + 5e:b1:88:c0:64:85:5c:15:4d:88:c7:b7:ba:e0:75: + e9:ad:05:3d:9d:c7:89:48:e0:bb:28:c8:03:e1:30: + 93:64:5e:52:c0:59:70:22:35:57:88:8a:f1:95:0a: + 83:d7:bc:31:73:01:34:ed:ef:46:71:e0:6b:02:a8: + 35:72:6b:97:9b:66:e0:cb:1c:79:5f:d8:1a:04:68: + 1e:47:02:e6:9d:60:e2:36:97:01:df:ce:35:92:df: + be:67:c7:6d:77:59:3b:8f:9d:d6:90:15:94:bc:42: + 34:10:c1:39:f9:b1:27:3e:7e:d6:8a:75:c5:b2:af: + 96:d3:a2:de:9b:e4:98:be:7d:e1:e9:81:ad:b6:6f: + fc:d7:0e:da:e0:34:b0:0d:1a:77:e7:e3:08:98:ef: + 58:fa:9c:84:b7:36:af:c2:df:ac:d2:f4:10:06:70: + 71:35 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 2C:D5:50:41:97:15:8B:F0:8F:36:61:5B:4A:FB:6B:D9:99:C9:33:92 + Signature Algorithm: sha1WithRSAEncryption + 5a:70:7f:2c:dd:b7:34:4f:f5:86:51:a9:26:be:4b:b8:aa:f1: + 71:0d:dc:61:c7:a0:ea:34:1e:7a:77:0f:04:35:e8:27:8f:6c: + 90:bf:91:16:24:46:3e:4a:4e:ce:2b:16:d5:0b:52:1d:fc:1f: + 67:a2:02:45:31:4f:ce:f3:fa:03:a7:79:9d:53:6a:d9:da:63: + 3a:f8:80:d7:d3:99:e1:a5:e1:be:d4:55:71:98:35:3a:be:93: + ea:ae:ad:42:b2:90:6f:e0:fc:21:4d:35:63:33:89:49:d6:9b: + 4e:ca:c7:e7:4e:09:00:f7:da:c7:ef:99:62:99:77:b6:95:22: + 5e:8a:a0:ab:f4:b8:78:98:ca:38:19:99:c9:72:9e:78:cd:4b: + ac:af:19:a0:73:12:2d:fc:c2:41:ba:81:91:da:16:5a:31:b7: + f9:b4:71:80:12:48:99:72:73:5a:59:53:c1:63:52:33:ed:a7: + c9:d2:39:02:70:fa:e0:b1:42:66:29:aa:9b:51:ed:30:54:22: + 14:5f:d9:ab:1d:c1:e4:94:f0:f8:f5:2b:f7:ea:ca:78:46:d6: + b8:91:fd:a6:0d:2b:1a:14:01:3e:80:f0:42:a0:95:07:5e:6d: + cd:cc:4b:a4:45:8d:ab:12:e8:b3:de:5a:e5:a0:7c:e8:0f:22: + 1d:5a:e9:59 +-----BEGIN CERTIFICATE----- +MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBY +MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMo +R2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEx +MjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgxCzAJBgNVBAYTAlVTMRYwFAYDVQQK +Ew1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQcmltYXJ5IENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9 +AWbK7hWNb6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjA +ZIVcFU2Ix7e64HXprQU9nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE0 +7e9GceBrAqg1cmuXm2bgyxx5X9gaBGgeRwLmnWDiNpcB3841kt++Z8dtd1k7j53W +kBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGttm/81w7a4DSwDRp35+MI +mO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G +A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJ +KoZIhvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ1 +6CePbJC/kRYkRj5KTs4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl +4b7UVXGYNTq+k+qurUKykG/g/CFNNWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6K +oKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHaFloxt/m0cYASSJlyc1pZU8Fj +UjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG1riR/aYNKxoU +AT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk= +-----END CERTIFICATE----- + +thawte Primary Root CA +# Issuer: CN=thawte Primary Root CA,OU="(c) 2006 thawte, Inc. - For authorized use only",OU=Certification Services Division,O="thawte, Inc.",C=US +# Serial Number:34:4e:d5:57:20:d5:ed:ec:49:f4:2f:ce:37:db:2b:6d +# Subject: CN=thawte Primary Root CA,OU="(c) 2006 thawte, Inc. - For authorized use only",OU=Certification Services Division,O="thawte, Inc.",C=US +# Not Valid Before: Fri Nov 17 00:00:00 2006 +# Not Valid After : Wed Jul 16 23:59:59 2036 +# Fingerprint (MD5): 8C:CA:DC:0B:22:CE:F5:BE:72:AC:41:1A:11:A8:D8:12 +# Fingerprint (SHA1): 91:C6:D6:EE:3E:8A:C8:63:84:E5:48:C2:99:29:5C:75:6C:81:7B:81 +MUST_VERIFY_TRUST: EMAIL_PROTECTION, CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH +================================================= +MD5 Fingerprint=8C:CA:DC:0B:22:CE:F5:BE:72:AC:41:1A:11:A8:D8:12 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 34:4e:d5:57:20:d5:ed:ec:49:f4:2f:ce:37:db:2b:6d + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=thawte, Inc., OU=Certification Services Division, OU=(c) 2006 thawte, Inc. - For authorized use only, CN=thawte Primary Root CA + Validity + Not Before: Nov 17 00:00:00 2006 GMT + Not After : Jul 16 23:59:59 2036 GMT + Subject: C=US, O=thawte, Inc., OU=Certification Services Division, OU=(c) 2006 thawte, Inc. - For authorized use only, CN=thawte Primary Root CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:ac:a0:f0:fb:80:59:d4:9c:c7:a4:cf:9d:a1:59: + 73:09:10:45:0c:0d:2c:6e:68:f1:6c:5b:48:68:49: + 59:37:fc:0b:33:19:c2:77:7f:cc:10:2d:95:34:1c: + e6:eb:4d:09:a7:1c:d2:b8:c9:97:36:02:b7:89:d4: + 24:5f:06:c0:cc:44:94:94:8d:02:62:6f:eb:5a:dd: + 11:8d:28:9a:5c:84:90:10:7a:0d:bd:74:66:2f:6a: + 38:a0:e2:d5:54:44:eb:1d:07:9f:07:ba:6f:ee:e9: + fd:4e:0b:29:f5:3e:84:a0:01:f1:9c:ab:f8:1c:7e: + 89:a4:e8:a1:d8:71:65:0d:a3:51:7b:ee:bc:d2:22: + 60:0d:b9:5b:9d:df:ba:fc:51:5b:0b:af:98:b2:e9: + 2e:e9:04:e8:62:87:de:2b:c8:d7:4e:c1:4c:64:1e: + dd:cf:87:58:ba:4a:4f:ca:68:07:1d:1c:9d:4a:c6: + d5:2f:91:cc:7c:71:72:1c:c5:c0:67:eb:32:fd:c9: + 92:5c:94:da:85:c0:9b:bf:53:7d:2b:09:f4:8c:9d: + 91:1f:97:6a:52:cb:de:09:36:a4:77:d8:7b:87:50: + 44:d5:3e:6e:29:69:fb:39:49:26:1e:09:a5:80:7b: + 40:2d:eb:e8:27:85:c9:fe:61:fd:7e:e6:7c:97:1d: + d5:9d + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 7B:5B:45:CF:AF:CE:CB:7A:FD:31:92:1A:6A:B6:F3:46:EB:57:48:50 + Signature Algorithm: sha1WithRSAEncryption + 79:11:c0:4b:b3:91:b6:fc:f0:e9:67:d4:0d:6e:45:be:55:e8: + 93:d2:ce:03:3f:ed:da:25:b0:1d:57:cb:1e:3a:76:a0:4c:ec: + 50:76:e8:64:72:0c:a4:a9:f1:b8:8b:d6:d6:87:84:bb:32:e5: + 41:11:c0:77:d9:b3:60:9d:eb:1b:d5:d1:6e:44:44:a9:a6:01: + ec:55:62:1d:77:b8:5c:8e:48:49:7c:9c:3b:57:11:ac:ad:73: + 37:8e:2f:78:5c:90:68:47:d9:60:60:e6:fc:07:3d:22:20:17: + c4:f7:16:e9:c4:d8:72:f9:c8:73:7c:df:16:2f:15:a9:3e:fd: + 6a:27:b6:a1:eb:5a:ba:98:1f:d5:e3:4d:64:0a:9d:13:c8:61: + ba:f5:39:1c:87:ba:b8:bd:7b:22:7f:f6:fe:ac:40:79:e5:ac: + 10:6f:3d:8f:1b:79:76:8b:c4:37:b3:21:18:84:e5:36:00:eb: + 63:20:99:b9:e9:fe:33:04:bb:41:c8:c1:02:f9:44:63:20:9e: + 81:ce:42:d3:d6:3f:2c:76:d3:63:9c:59:dd:8f:a6:e1:0e:a0: + 2e:41:f7:2e:95:47:cf:bc:fd:33:f3:f6:0b:61:7e:7e:91:2b: + 81:47:c2:27:30:ee:a7:10:5d:37:8f:5c:39:2b:e4:04:f0:7b: + 8d:56:8c:68 +-----BEGIN CERTIFICATE----- +MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCB +qTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf +Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw +MDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNV +BAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3MDAwMDAwWhcNMzYw +NzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5j +LjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYG +A1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl +IG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsoPD7gFnUnMekz52hWXMJEEUMDSxuaPFs +W0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ1CRfBsDMRJSUjQJib+ta +3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGcq/gcfomk +6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6 +Sk/KaAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94J +NqR32HuHUETVPm4pafs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBA +MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XP +r87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUFAAOCAQEAeRHAS7ORtvzw6WfU +DW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeEuzLlQRHAd9mz +YJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX +xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2 +/qxAeeWsEG89jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/ +LHbTY5xZ3Y+m4Q6gLkH3LpVHz7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7 +jVaMaA== +-----END CERTIFICATE----- + +VeriSign Class 3 Public Primary Certification Authority - G5 +# Issuer: CN=VeriSign Class 3 Public Primary Certification Authority - G5,OU="(c) 2006 VeriSign, Inc. - For authorized use only",OU=VeriSign Trust Network,O="VeriSign, Inc.",C=US +# Serial Number:18:da:d1:9e:26:7d:e8:bb:4a:21:58:cd:cc:6b:3b:4a +# Subject: CN=VeriSign Class 3 Public Primary Certification Authority - G5,OU="(c) 2006 VeriSign, Inc. - For authorized use only",OU=VeriSign Trust Network,O="VeriSign, Inc.",C=US +# Not Valid Before: Wed Nov 08 00:00:00 2006 +# Not Valid After : Wed Jul 16 23:59:59 2036 +# Fingerprint (MD5): CB:17:E4:31:67:3E:E2:09:FE:45:57:93:F3:0A:FA:1C +# Fingerprint (SHA1): 4E:B6:D5:78:49:9B:1C:CF:5F:58:1E:AD:56:BE:3D:9B:67:44:A5:E5 +MUST_VERIFY_TRUST: CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +============================================================ +MD5 Fingerprint=CB:17:E4:31:67:3E:E2:09:FE:45:57:93:F3:0A:FA:1C +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 18:da:d1:9e:26:7d:e8:bb:4a:21:58:cd:cc:6b:3b:4a + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 2006 VeriSign, Inc. - For authorized use only, CN=VeriSign Class 3 Public Primary Certification Authority - G5 + Validity + Not Before: Nov 8 00:00:00 2006 GMT + Not After : Jul 16 23:59:59 2036 GMT + Subject: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 2006 VeriSign, Inc. - For authorized use only, CN=VeriSign Class 3 Public Primary Certification Authority - G5 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:af:24:08:08:29:7a:35:9e:60:0c:aa:e7:4b:3b: + 4e:dc:7c:bc:3c:45:1c:bb:2b:e0:fe:29:02:f9:57: + 08:a3:64:85:15:27:f5:f1:ad:c8:31:89:5d:22:e8: + 2a:aa:a6:42:b3:8f:f8:b9:55:b7:b1:b7:4b:b3:fe: + 8f:7e:07:57:ec:ef:43:db:66:62:15:61:cf:60:0d: + a4:d8:de:f8:e0:c3:62:08:3d:54:13:eb:49:ca:59: + 54:85:26:e5:2b:8f:1b:9f:eb:f5:a1:91:c2:33:49: + d8:43:63:6a:52:4b:d2:8f:e8:70:51:4d:d1:89:69: + 7b:c7:70:f6:b3:dc:12:74:db:7b:5d:4b:56:d3:96: + bf:15:77:a1:b0:f4:a2:25:f2:af:1c:92:67:18:e5: + f4:06:04:ef:90:b9:e4:00:e4:dd:3a:b5:19:ff:02: + ba:f4:3c:ee:e0:8b:eb:37:8b:ec:f4:d7:ac:f2:f6: + f0:3d:af:dd:75:91:33:19:1d:1c:40:cb:74:24:19: + 21:93:d9:14:fe:ac:2a:52:c7:8f:d5:04:49:e4:8d: + 63:47:88:3c:69:83:cb:fe:47:bd:2b:7e:4f:c5:95: + ae:0e:9d:d4:d1:43:c0:67:73:e3:14:08:7e:e5:3f: + 9f:73:b8:33:0a:cf:5d:3f:34:87:96:8a:ee:53:e8: + 25:15 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + 1.3.6.1.5.5.7.1.12: + 0_.].[0Y0W0U..image/gif0!0.0...+..............k...j.H.,{..0%.#http://logo.verisign.com/vslogo.gif + X509v3 Subject Key Identifier: + 7F:D3:65:A7:C2:DD:EC:BB:F0:30:09:F3:43:39:FA:02:AF:33:31:33 + Signature Algorithm: sha1WithRSAEncryption + 93:24:4a:30:5f:62:cf:d8:1a:98:2f:3d:ea:dc:99:2d:bd:77: + f6:a5:79:22:38:ec:c4:a7:a0:78:12:ad:62:0e:45:70:64:c5: + e7:97:66:2d:98:09:7e:5f:af:d6:cc:28:65:f2:01:aa:08:1a: + 47:de:f9:f9:7c:92:5a:08:69:20:0d:d9:3e:6d:6e:3c:0d:6e: + d8:e6:06:91:40:18:b9:f8:c1:ed:df:db:41:aa:e0:96:20:c9: + cd:64:15:38:81:c9:94:ee:a2:84:29:0b:13:6f:8e:db:0c:dd: + 25:02:db:a4:8b:19:44:d2:41:7a:05:69:4a:58:4f:60:ca:7e: + 82:6a:0b:02:aa:25:17:39:b5:db:7f:e7:84:65:2a:95:8a:bd: + 86:de:5e:81:16:83:2d:10:cc:de:fd:a8:82:2a:6d:28:1f:0d: + 0b:c4:e5:e7:1a:26:19:e1:f4:11:6f:10:b5:95:fc:e7:42:05: + 32:db:ce:9d:51:5e:28:b6:9e:85:d3:5b:ef:a5:7d:45:40:72: + 8e:b7:0e:6b:0e:06:fb:33:35:48:71:b8:9d:27:8b:c4:65:5f: + 0d:86:76:9c:44:7a:f6:95:5c:f6:5d:32:08:33:a4:54:b6:18: + 3f:68:5c:f2:42:4a:85:38:54:83:5f:d1:e8:2c:f2:ac:11:d6: + a8:ed:63:6a +-----BEGIN CERTIFICATE----- +MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB +yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL +ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp +U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW +ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL +MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW +ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln +biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp +U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y +aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1 +nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex +t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz +SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG +BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+ +rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/ +NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E +BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH +BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy +aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv +MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE +p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y +5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK +WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ +4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N +hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq +-----END CERTIFICATE----- + +SecureTrust CA +# Issuer: CN=SecureTrust CA,O=SecureTrust Corporation,C=US +# Serial Number:0c:f0:8e:5c:08:16:a5:ad:42:7f:f0:eb:27:18:59:d0 +# Subject: CN=SecureTrust CA,O=SecureTrust Corporation,C=US +# Not Valid Before: Tue Nov 07 19:31:18 2006 +# Not Valid After : Mon Dec 31 19:40:55 2029 +# Fingerprint (MD5): DC:32:C3:A7:6D:25:57:C7:68:09:9D:EA:2D:A9:A2:D1 +# Fingerprint (SHA1): 87:82:C6:C3:04:35:3B:CF:D2:96:92:D2:59:3E:7D:44:D9:34:FF:11 +MUST_VERIFY_TRUST: EMAIL_PROTECTION, CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH +================================================= +MD5 Fingerprint=DC:32:C3:A7:6D:25:57:C7:68:09:9D:EA:2D:A9:A2:D1 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 0c:f0:8e:5c:08:16:a5:ad:42:7f:f0:eb:27:18:59:d0 + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=SecureTrust Corporation, CN=SecureTrust CA + Validity + Not Before: Nov 7 19:31:18 2006 GMT + Not After : Dec 31 19:40:55 2029 GMT + Subject: C=US, O=SecureTrust Corporation, CN=SecureTrust CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:ab:a4:81:e5:95:cd:f5:f6:14:8e:c2:4f:ca:d4: + e2:78:95:58:9c:41:e1:0d:99:40:24:17:39:91:33: + 66:e9:be:e1:83:af:62:5c:89:d1:fc:24:5b:61:b3: + e0:11:11:41:1c:1d:6e:f0:b8:bb:f8:de:a7:81:ba: + a6:48:c6:9f:1d:bd:be:8e:a9:41:3e:b8:94:ed:29: + 1a:d4:8e:d2:03:1d:03:ef:6d:0d:67:1c:57:d7:06: + ad:ca:c8:f5:fe:0e:af:66:25:48:04:96:0b:5d:a3: + ba:16:c3:08:4f:d1:46:f8:14:5c:f2:c8:5e:01:99: + 6d:fd:88:cc:86:a8:c1:6f:31:42:6c:52:3e:68:cb: + f3:19:34:df:bb:87:18:56:80:26:c4:d0:dc:c0:6f: + df:de:a0:c2:91:16:a0:64:11:4b:44:bc:1e:f6:e7: + fa:63:de:66:ac:76:a4:71:a3:ec:36:94:68:7a:77: + a4:b1:e7:0e:2f:81:7a:e2:b5:72:86:ef:a2:6b:8b: + f0:0f:db:d3:59:3f:ba:72:bc:44:24:9c:e3:73:b3: + f7:af:57:2f:42:26:9d:a9:74:ba:00:52:f2:4b:cd: + 53:7c:47:0b:36:85:0e:66:a9:08:97:16:34:57:c1: + 66:f7:80:e3:ed:70:54:c7:93:e0:2e:28:15:59:87: + ba:bb + Exponent: 65537 (0x10001) + X509v3 extensions: + 1.3.6.1.4.1.311.20.2: + ...C.A + X509v3 Key Usage: + Digital Signature, Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + 42:32:B6:16:FA:04:FD:FE:5D:4B:7A:C3:FD:F7:4C:40:1D:5A:43:AF + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.securetrust.com/STCA.crl + + 1.3.6.1.4.1.311.21.1: + ... + Signature Algorithm: sha1WithRSAEncryption + 30:ed:4f:4a:e1:58:3a:52:72:5b:b5:a6:a3:65:18:a6:bb:51: + 3b:77:e9:9d:ea:d3:9f:5c:e0:45:65:7b:0d:ca:5b:e2:70:50: + b2:94:05:14:ae:49:c7:8d:41:07:12:73:94:7e:0c:23:21:fd: + bc:10:7f:60:10:5a:72:f5:98:0e:ac:ec:b9:7f:dd:7a:6f:5d: + d3:1c:f4:ff:88:05:69:42:a9:05:71:c8:b7:ac:26:e8:2e:b4: + 8c:6a:ff:71:dc:b8:b1:df:99:bc:7c:21:54:2b:e4:58:a2:bb: + 57:29:ae:9e:a9:a3:19:26:0f:99:2e:08:b0:ef:fd:69:cf:99: + 1a:09:8d:e3:a7:9f:2b:c9:36:34:7b:24:b3:78:4c:95:17:a4: + 06:26:1e:b6:64:52:36:5f:60:67:d9:9c:c5:05:74:0b:e7:67: + 23:d2:08:fc:88:e9:ae:8b:7f:e1:30:f4:37:7e:fd:c6:32:da: + 2d:9e:44:30:30:6c:ee:07:de:d2:34:fc:d2:ff:40:f6:4b:f4: + 66:46:06:54:a6:f2:32:0a:63:26:30:6b:9b:d1:dc:8b:47:ba: + e1:b9:d5:62:d0:a2:a0:f4:67:05:78:29:63:1a:6f:04:d6:f8: + c6:4c:a3:9a:b1:37:b4:8d:e5:28:4b:1d:9e:2c:c2:b8:68:bc: + ed:02:ee:31 +-----BEGIN CERTIFICATE----- +MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBI +MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x +FzAVBgNVBAMTDlNlY3VyZVRydXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIz +MTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1NlY3VyZVRydXN0IENv +cnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQXOZEz +Zum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO +0gMdA+9tDWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIao +wW8xQmxSPmjL8xk037uHGFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj +7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b01k/unK8RCSc43Oz969XL0Imnal0ugBS +8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmHursCAwEAAaOBnTCBmjAT +BgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB +/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCeg +JYYjaHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGC +NxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt3 +6Z3q059c4EVlew3KW+JwULKUBRSuSceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/ +3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHfmbx8IVQr5Fiiu1cprp6poxkm +D5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZnMUFdAvnZyPS +CPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR +3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE= +-----END CERTIFICATE----- + +Secure Global CA +# Issuer: CN=Secure Global CA,O=SecureTrust Corporation,C=US +# Serial Number:07:56:22:a4:e8:d4:8a:89:4d:f4:13:c8:f0:f8:ea:a5 +# Subject: CN=Secure Global CA,O=SecureTrust Corporation,C=US +# Not Valid Before: Tue Nov 07 19:42:28 2006 +# Not Valid After : Mon Dec 31 19:52:06 2029 +# Fingerprint (MD5): CF:F4:27:0D:D4:ED:DC:65:16:49:6D:3D:DA:BF:6E:DE +# Fingerprint (SHA1): 3A:44:73:5A:E5:81:90:1F:24:86:61:46:1E:3B:9C:C4:5F:F5:3A:1B +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +MUST_VERIFY_TRUST: CODE_SIGNING +================================================ +MD5 Fingerprint=CF:F4:27:0D:D4:ED:DC:65:16:49:6D:3D:DA:BF:6E:DE +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 07:56:22:a4:e8:d4:8a:89:4d:f4:13:c8:f0:f8:ea:a5 + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=SecureTrust Corporation, CN=Secure Global CA + Validity + Not Before: Nov 7 19:42:28 2006 GMT + Not After : Dec 31 19:52:06 2029 GMT + Subject: C=US, O=SecureTrust Corporation, CN=Secure Global CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:af:35:2e:d8:ac:6c:55:69:06:71:e5:13:68:24: + b3:4f:d8:cc:21:47:f8:f1:60:38:89:89:03:e9:bd: + ea:5e:46:53:09:dc:5c:f5:5a:e8:f7:45:2a:02:eb: + 31:61:d7:29:33:4c:ce:c7:7c:0a:37:7e:0f:ba:32: + 98:e1:1d:97:af:8f:c7:dc:c9:38:96:f3:db:1a:fc: + 51:ed:68:c6:d0:6e:a4:7c:24:d1:ae:42:c8:96:50: + 63:2e:e0:fe:75:fe:98:a7:5f:49:2e:95:e3:39:33: + 64:8e:1e:a4:5f:90:d2:67:3c:b2:d9:fe:41:b9:55: + a7:09:8e:72:05:1e:8b:dd:44:85:82:42:d0:49:c0: + 1d:60:f0:d1:17:2c:95:eb:f6:a5:c1:92:a3:c5:c2: + a7:08:60:0d:60:04:10:96:79:9e:16:34:e6:a9:b6: + fa:25:45:39:c8:1e:65:f9:93:f5:aa:f1:52:dc:99: + 98:3d:a5:86:1a:0c:35:33:fa:4b:a5:04:06:15:1c: + 31:80:ef:aa:18:6b:c2:7b:d7:da:ce:f9:33:20:d5: + f5:bd:6a:33:2d:81:04:fb:b0:5c:d4:9c:a3:e2:5c: + 1d:e3:a9:42:75:5e:7b:d4:77:ef:39:54:ba:c9:0a: + 18:1b:12:99:49:2f:88:4b:fd:50:62:d1:73:e7:8f: + 7a:43 + Exponent: 65537 (0x10001) + X509v3 extensions: + 1.3.6.1.4.1.311.20.2: + ...C.A + X509v3 Key Usage: + Digital Signature, Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + AF:44:04:C2:41:7E:48:83:DB:4E:39:02:EC:EC:84:7A:E6:CE:C9:A4 + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.securetrust.com/SGCA.crl + + 1.3.6.1.4.1.311.21.1: + ... + Signature Algorithm: sha1WithRSAEncryption + 63:1a:08:40:7d:a4:5e:53:0d:77:d8:7a:ae:1f:0d:0b:51:16: + 03:ef:18:7c:c8:e3:af:6a:58:93:14:60:91:b2:84:dc:88:4e: + be:39:8a:3a:f3:e6:82:89:5d:01:37:b3:ab:24:a4:15:0e:92: + 35:5a:4a:44:5e:4e:57:fa:75:ce:1f:48:ce:66:f4:3c:40:26: + 92:98:6c:1b:ee:24:46:0c:17:b3:52:a5:db:a5:91:91:cf:37: + d3:6f:e7:27:08:3a:4e:19:1f:3a:a7:58:5c:17:cf:79:3f:8b: + e4:a7:d3:26:23:9d:26:0f:58:69:fc:47:7e:b2:d0:8d:8b:93: + bf:29:4f:43:69:74:76:67:4b:cf:07:8c:e6:02:f7:b5:e1:b4: + 43:b5:4b:2d:14:9f:f9:dc:26:0d:bf:a6:47:74:06:d8:88:d1: + 3a:29:30:84:ce:d2:39:80:62:1b:a8:c7:57:49:bc:6a:55:51: + 67:15:4a:be:35:07:e4:d5:75:98:37:79:30:14:db:29:9d:6c: + c5:69:cc:47:55:a2:30:f7:cc:5c:7f:c2:c3:98:1c:6b:4e:16: + 80:eb:7a:78:65:45:a2:00:1a:af:0c:0d:55:64:34:48:b8:92: + b9:f1:b4:50:29:f2:4f:23:1f:da:6c:ac:1f:44:e1:dd:23:78: + 51:5b:c7:16 +-----BEGIN CERTIFICATE----- +MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBK +MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x +GTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkx +MjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3Qg +Q29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jxYDiJ +iQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa +/FHtaMbQbqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJ +jnIFHovdRIWCQtBJwB1g8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnI +HmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYVHDGA76oYa8J719rO+TMg1fW9ajMtgQT7 +sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi0XPnj3pDAgMBAAGjgZ0w +gZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQF +MAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCsw +KaAnoCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsG +AQQBgjcVAQQDAgEAMA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0L +URYD7xh8yOOvaliTFGCRsoTciE6+OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXO +H0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cnCDpOGR86p1hcF895P4vkp9Mm +I50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/53CYNv6ZHdAbY +iNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc +f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW +-----END CERTIFICATE----- + +COMODO Certification Authority +# Issuer: CN=COMODO Certification Authority,O=COMODO CA Limited,L=Salford,ST=Greater Manchester,C=GB +# Serial Number:4e:81:2d:8a:82:65:e0:0b:02:ee:3e:35:02:46:e5:3d +# Subject: CN=COMODO Certification Authority,O=COMODO CA Limited,L=Salford,ST=Greater Manchester,C=GB +# Not Valid Before: Fri Dec 01 00:00:00 2006 +# Not Valid After : Mon Dec 31 23:59:59 2029 +# Fingerprint (MD5): 5C:48:DC:F7:42:72:EC:56:94:6D:1C:CC:71:35:80:75 +# Fingerprint (SHA1): 66:31:BF:9E:F7:4F:9E:B6:C9:D5:A6:0C:BA:6A:BE:D1:F7:BD:EF:7B +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +MUST_VERIFY_TRUST: CODE_SIGNING +================================================ +MD5 Fingerprint=5C:48:DC:F7:42:72:EC:56:94:6D:1C:CC:71:35:80:75 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 4e:81:2d:8a:82:65:e0:0b:02:ee:3e:35:02:46:e5:3d + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=GB, ST=Greater Manchester, L=Salford, O=COMODO CA Limited, CN=COMODO Certification Authority + Validity + Not Before: Dec 1 00:00:00 2006 GMT + Not After : Dec 31 23:59:59 2029 GMT + Subject: C=GB, ST=Greater Manchester, L=Salford, O=COMODO CA Limited, CN=COMODO Certification Authority + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:d0:40:8b:8b:72:e3:91:1b:f7:51:c1:1b:54:04: + 98:d3:a9:bf:c1:e6:8a:5d:3b:87:fb:bb:88:ce:0d: + e3:2f:3f:06:96:f0:a2:29:50:99:ae:db:3b:a1:57: + b0:74:51:71:cd:ed:42:91:4d:41:fe:a9:c8:d8:6a: + 86:77:44:bb:59:66:97:50:5e:b4:d4:2c:70:44:cf: + da:37:95:42:69:3c:30:c4:71:b3:52:f0:21:4d:a1: + d8:ba:39:7c:1c:9e:a3:24:9d:f2:83:16:98:aa:16: + 7c:43:9b:15:5b:b7:ae:34:91:fe:d4:62:26:18:46: + 9a:3f:eb:c1:f9:f1:90:57:eb:ac:7a:0d:8b:db:72: + 30:6a:66:d5:e0:46:a3:70:dc:68:d9:ff:04:48:89: + 77:de:b5:e9:fb:67:6d:41:e9:bc:39:bd:32:d9:62: + 02:f1:b1:a8:3d:6e:37:9c:e2:2f:e2:d3:a2:26:8b: + c6:b8:55:43:88:e1:23:3e:a5:d2:24:39:6a:47:ab: + 00:d4:a1:b3:a9:25:fe:0d:3f:a7:1d:ba:d3:51:c1: + 0b:a4:da:ac:38:ef:55:50:24:05:65:46:93:34:4f: + 2d:8d:ad:c6:d4:21:19:d2:8e:ca:05:61:71:07:73: + 47:e5:8a:19:12:bd:04:4d:ce:4e:9c:a5:48:ac:bb: + 26:f7 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + 0B:58:E5:8B:C6:4C:15:37:A4:40:A9:30:A9:21:BE:47:36:5A:56:FF + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.comodoca.com/COMODOCertificationAuthority.crl + + Signature Algorithm: sha1WithRSAEncryption + 3e:98:9e:9b:f6:1b:e9:d7:39:b7:78:ae:1d:72:18:49:d3:87: + e4:43:82:eb:3f:c9:aa:f5:a8:b5:ef:55:7c:21:52:65:f9:d5: + 0d:e1:6c:f4:3e:8c:93:73:91:2e:02:c4:4e:07:71:6f:c0:8f: + 38:61:08:a8:1e:81:0a:c0:2f:20:2f:41:8b:91:dc:48:45:bc: + f1:c6:de:ba:76:6b:33:c8:00:2d:31:46:4c:ed:e7:9d:cf:88: + 94:ff:33:c0:56:e8:24:86:26:b8:d8:38:38:df:2a:6b:dd:12: + cc:c7:3f:47:17:4c:a2:c2:06:96:09:d6:db:fe:3f:3c:46:41: + df:58:e2:56:0f:3c:3b:c1:1c:93:35:d9:38:52:ac:ee:c8:ec: + 2e:30:4e:94:35:b4:24:1f:4b:78:69:da:f2:02:38:cc:95:52: + 93:f0:70:25:59:9c:20:67:c4:ee:f9:8b:57:61:f4:92:76:7d: + 3f:84:8d:55:b7:e8:e5:ac:d5:f1:f5:19:56:a6:5a:fb:90:1c: + af:93:eb:e5:1c:d4:67:97:5d:04:0e:be:0b:83:a6:17:83:b9: + 30:12:a0:c5:33:15:05:b9:0d:fb:c7:05:76:e3:d8:4a:8d:fc: + 34:17:a3:c6:21:28:be:30:45:31:1e:c7:78:be:58:61:38:ac: + 3b:e2:01:65 +-----BEGIN CERTIFICATE----- +MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCB +gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G +A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV +BAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEyMDEwMDAw +MDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl +YXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01P +RE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3 +UcEbVASY06m/weaKXTuH+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI +2GqGd0S7WWaXUF601CxwRM/aN5VCaTwwxHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8 +Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV4EajcNxo2f8ESIl33rXp ++2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA1KGzqSX+ +DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5O +nKVIrLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW +/zAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6g +PKA6hjhodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9u +QXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOCAQEAPpiem/Yb6dc5t3iuHXIY +SdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CPOGEIqB6BCsAv +IC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/ +RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4 +zJVSk/BwJVmcIGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5dd +BA6+C4OmF4O5MBKgxTMVBbkN+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IB +ZQ== +-----END CERTIFICATE----- + +Network Solutions Certificate Authority +# Issuer: CN=Network Solutions Certificate Authority,O=Network Solutions L.L.C.,C=US +# Serial Number:57:cb:33:6f:c2:5c:16:e6:47:16:17:e3:90:31:68:e0 +# Subject: CN=Network Solutions Certificate Authority,O=Network Solutions L.L.C.,C=US +# Not Valid Before: Fri Dec 01 00:00:00 2006 +# Not Valid After : Mon Dec 31 23:59:59 2029 +# Fingerprint (MD5): D3:F3:A6:16:C0:FA:6B:1D:59:B1:2D:96:4D:0E:11:2E +# Fingerprint (SHA1): 74:F8:A3:C3:EF:E7:B3:90:06:4B:83:90:3C:21:64:60:20:E5:DF:CE +TRUSTED_DELEGATOR: SERVER_AUTH +MUST_VERIFY_TRUST: EMAIL_PROTECTION, CODE_SIGNING +================================================= +MD5 Fingerprint=D3:F3:A6:16:C0:FA:6B:1D:59:B1:2D:96:4D:0E:11:2E +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 57:cb:33:6f:c2:5c:16:e6:47:16:17:e3:90:31:68:e0 + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=Network Solutions L.L.C., CN=Network Solutions Certificate Authority + Validity + Not Before: Dec 1 00:00:00 2006 GMT + Not After : Dec 31 23:59:59 2029 GMT + Subject: C=US, O=Network Solutions L.L.C., CN=Network Solutions Certificate Authority + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:e4:bc:7e:92:30:6d:c6:d8:8e:2b:0b:bc:46:ce: + e0:27:96:de:de:f9:fa:12:d3:3c:33:73:b3:04:2f: + bc:71:8c:e5:9f:b6:22:60:3e:5f:5d:ce:09:ff:82: + 0c:1b:9a:51:50:1a:26:89:dd:d5:61:5d:19:dc:12: + 0f:2d:0a:a2:43:5d:17:d0:34:92:20:ea:73:cf:38: + 2c:06:26:09:7a:72:f7:fa:50:32:f8:c2:93:d3:69: + a2:23:ce:41:b1:cc:e4:d5:1f:36:d1:8a:3a:f8:8c: + 63:e2:14:59:69:ed:0d:d3:7f:6b:e8:b8:03:e5:4f: + 6a:e5:98:63:69:48:05:be:2e:ff:33:b6:e9:97:59: + 69:f8:67:19:ae:93:61:96:44:15:d3:72:b0:3f:bc: + 6a:7d:ec:48:7f:8d:c3:ab:aa:71:2b:53:69:41:53: + 34:b5:b0:b9:c5:06:0a:c4:b0:45:f5:41:5d:6e:89: + 45:7b:3d:3b:26:8c:74:c2:e5:d2:d1:7d:b2:11:d4: + fb:58:32:22:9a:80:c9:dc:fd:0c:e9:7f:5e:03:97: + ce:3b:00:14:87:27:70:38:a9:8e:6e:b3:27:76:98: + 51:e0:05:e3:21:ab:1a:d5:85:22:3c:29:b5:9a:16: + c5:80:a8:f4:bb:6b:30:8f:2f:46:02:a2:b1:0c:22: + e0:d3 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + 21:30:C9:FB:00:D7:4E:98:DA:87:AA:2A:D0:A7:2E:B1:40:31:A7:4C + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 CRL Distribution Points: + + Full Name: + URI:http://crl.netsolssl.com/NetworkSolutionsCertificateAuthority.crl + + Signature Algorithm: sha1WithRSAEncryption + bb:ae:4b:e7:b7:57:eb:7f:aa:2d:b7:73:47:85:6a:c1:e4:a5: + 1d:e4:e7:3c:e9:f4:59:65:77:b5:7a:5b:5a:8d:25:36:e0:7a: + 97:2e:38:c0:57:60:83:98:06:83:9f:b9:76:7a:6e:50:e0:ba: + 88:2c:fc:45:cc:18:b0:99:95:51:0e:ec:1d:b8:88:ff:87:50: + 1c:82:c2:e3:e0:32:80:bf:a0:0b:47:c8:c3:31:ef:99:67:32: + 80:4f:17:21:79:0c:69:5c:de:5e:34:ae:02:b5:26:ea:50:df: + 7f:18:65:2c:c9:f2:63:e1:a9:07:fe:7c:71:1f:6b:33:24:6a: + 1e:05:f7:05:68:c0:6a:12:cb:2e:5e:61:cb:ae:28:d3:7e:c2: + b4:66:91:26:5f:3c:2e:24:5f:cb:58:0f:eb:28:ec:af:11:96: + f3:dc:7b:6f:c0:a7:88:f2:53:77:b3:60:5e:ae:ae:28:da:35: + 2c:6f:34:45:d3:26:e1:de:ec:5b:4f:27:6b:16:7c:bd:44:04: + 18:82:b3:89:79:17:10:71:3d:7a:a2:16:4e:f5:01:cd:a4:6c: + 65:68:a1:49:76:5c:43:c9:d8:bc:36:67:6c:a5:94:b5:d4:cc: + b9:bd:6a:35:56:21:de:d8:c3:eb:fb:cb:a4:60:4c:b0:55:a0: + a0:7b:57:b2 +-----BEGIN CERTIFICATE----- +MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBi +MQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu +MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3Jp +dHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMxMjM1OTU5WjBiMQswCQYDVQQGEwJV +UzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydO +ZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwz +c7MEL7xxjOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPP +OCwGJgl6cvf6UDL4wpPTaaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rl +mGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXTcrA/vGp97Eh/jcOrqnErU2lBUzS1sLnF +BgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc/Qzpf14Dl847ABSHJ3A4 +qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMBAAGjgZcw +gZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIB +BjAPBgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwu +bmV0c29sc3NsLmNvbS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3Jp +dHkuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc8 +6fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q4LqILPxFzBiwmZVRDuwduIj/ +h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/GGUsyfJj4akH +/nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv +wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHN +pGxlaKFJdlxDydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey +-----END CERTIFICATE----- + +COMODO ECC Certification Authority +# Issuer: CN=COMODO ECC Certification Authority,O=COMODO CA Limited,L=Salford,ST=Greater Manchester,C=GB +# Serial Number:1f:47:af:aa:62:00:70:50:54:4c:01:9e:9b:63:99:2a +# Subject: CN=COMODO ECC Certification Authority,O=COMODO CA Limited,L=Salford,ST=Greater Manchester,C=GB +# Not Valid Before: Thu Mar 06 00:00:00 2008 +# Not Valid After : Mon Jan 18 23:59:59 2038 +# Fingerprint (MD5): 7C:62:FF:74:9D:31:53:5E:68:4A:D5:78:AA:1E:BF:23 +# Fingerprint (SHA1): 9F:74:4E:9F:2B:4D:BA:EC:0F:31:2C:50:B6:56:3B:8E:2D:93:C3:11 +MUST_VERIFY_TRUST: CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +================================================ +MD5 Fingerprint=7C:62:FF:74:9D:31:53:5E:68:4A:D5:78:AA:1E:BF:23 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 1f:47:af:aa:62:00:70:50:54:4c:01:9e:9b:63:99:2a + Signature Algorithm: ecdsa-with-SHA384 + Issuer: C=GB, ST=Greater Manchester, L=Salford, O=COMODO CA Limited, CN=COMODO ECC Certification Authority + Validity + Not Before: Mar 6 00:00:00 2008 GMT + Not After : Jan 18 23:59:59 2038 GMT + Subject: C=GB, ST=Greater Manchester, L=Salford, O=COMODO CA Limited, CN=COMODO ECC Certification Authority + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (384 bit) + pub: + 04:03:47:7b:2f:75:c9:82:15:85:fb:75:e4:91:16: + d4:ab:62:99:f5:3e:52:0b:06:ce:41:00:7f:97:e1: + 0a:24:3c:1d:01:04:ee:3d:d2:8d:09:97:0c:e0:75: + e4:fa:fb:77:8a:2a:f5:03:60:4b:36:8b:16:23:16: + ad:09:71:f4:4a:f4:28:50:b4:fe:88:1c:6e:3f:6c: + 2f:2f:09:59:5b:a5:5b:0b:33:99:e2:c3:3d:89:f9: + 6a:2c:ef:b2:d3:06:e9 + ASN1 OID: secp384r1 + X509v3 extensions: + X509v3 Subject Key Identifier: + 75:71:A7:19:48:19:BC:9D:9D:EA:41:47:DF:94:C4:48:77:99:D3:79 + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + Signature Algorithm: ecdsa-with-SHA384 + 30:65:02:31:00:ef:03:5b:7a:ac:b7:78:0a:72:b7:88:df:ff: + b5:46:14:09:0a:fa:a0:e6:7d:08:c6:1a:87:bd:18:a8:73:bd: + 26:ca:60:0c:9d:ce:99:9f:cf:5c:0f:30:e1:be:14:31:ea:02: + 30:14:f4:93:3c:49:a7:33:7a:90:46:47:b3:63:7d:13:9b:4e: + b7:6f:18:37:80:53:fe:dd:20:e0:35:9a:36:d1:c7:01:b9:e6: + dc:dd:f3:ff:1d:2c:3a:16:57:d9:92:39:d6 +-----BEGIN CERTIFICATE----- +MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTEL +MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE +BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT +IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwMzA2MDAw +MDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdy +ZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09N +T0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSR +FtSrYpn1PlILBs5BAH+X4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0J +cfRK9ChQtP6IHG4/bC8vCVlbpVsLM5niwz2J+Wos77LTBumjQjBAMB0GA1UdDgQW +BBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ +BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VGFAkK+qDm +fQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdv +GDeAU/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY= +-----END CERTIFICATE----- + +Security Communication EV RootCA1 +# Issuer: OU=Security Communication EV RootCA1,O="SECOM Trust Systems CO.,LTD.",C=JP +# Serial Number: 0 (0x0) +# Subject: OU=Security Communication EV RootCA1,O="SECOM Trust Systems CO.,LTD.",C=JP +# Not Valid Before: Wed Jun 06 02:12:32 2007 +# Not Valid After : Sat Jun 06 02:12:32 2037 +# Fingerprint (MD5): 22:2D:A6:01:EA:7C:0A:F7:F0:6C:56:43:3F:77:76:D3 +# Fingerprint (SHA1): FE:B8:C4:32:DC:F9:76:9A:CE:AE:3D:D8:90:8F:FD:28:86:65:64:7D +TRUSTED_DELEGATOR: SERVER_AUTH +MUST_VERIFY_TRUST: EMAIL_PROTECTION, CODE_SIGNING +================================================= +MD5 Fingerprint=22:2D:A6:01:EA:7C:0A:F7:F0:6C:56:43:3F:77:76:D3 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 0 (0x0) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=JP, O=SECOM Trust Systems CO.,LTD., OU=Security Communication EV RootCA1 + Validity + Not Before: Jun 6 02:12:32 2007 GMT + Not After : Jun 6 02:12:32 2037 GMT + Subject: C=JP, O=SECOM Trust Systems CO.,LTD., OU=Security Communication EV RootCA1 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:bc:7f:ec:57:9b:24:e0:fe:9c:ba:42:79:a9:88: + 8a:fa:80:e0:f5:07:29:43:ea:8e:0a:34:36:8d:1c: + fa:a7:b5:39:78:ff:97:75:f7:2f:e4:aa:6b:04:84: + 44:ca:a6:e2:68:8e:fd:55:50:62:0f:a4:71:0e:ce: + 07:38:2d:42:85:50:ad:3c:96:6f:8b:d5:a2:0e:cf: + de:49:89:3d:d6:64:2e:38:e5:1e:6c:b5:57:8a:9e: + ef:48:0e:cd:7a:69:16:87:44:b5:90:e4:06:9d:ae: + a1:04:97:58:79:ef:20:4a:82:6b:8c:22:bf:ec:1f: + 0f:e9:84:71:ed:f1:0e:e4:b8:18:13:cc:56:36:5d: + d1:9a:1e:51:6b:39:6e:60:76:88:34:0b:f3:b3:d1: + b0:9d:ca:61:e2:64:1d:c1:46:07:b8:63:dd:1e:33: + 65:b3:8e:09:55:52:3d:b5:bd:ff:07:eb:ad:61:55: + 18:2c:a9:69:98:4a:aa:40:c5:33:14:65:74:00:f9: + 91:de:af:03:48:c5:40:54:dc:0f:84:90:68:20:c5: + 92:96:dc:2e:e5:02:45:aa:c0:5f:54:f8:6d:ea:49: + cf:5d:6c:4b:af:ef:9a:c2:56:5c:c6:35:56:42:6a: + 30:5f:c2:ab:f6:e2:3d:3f:b3:c9:11:8f:31:4c:d7: + 9f:49 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + 35:4A:F5:4D:AF:3F:D7:82:38:AC:AB:71:65:17:75:8C:9D:55:93:E6 + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + Signature Algorithm: sha1WithRSAEncryption + a8:87:e9:ec:f8:40:67:5d:c3:c1:66:c7:40:4b:97:fc:87:13: + 90:5a:c4:ef:a0:ca:5f:8b:b7:a7:b7:f1:d6:b5:64:b7:8a:b3: + b8:1b:cc:da:fb:ac:66:88:41:ce:e8:fc:e4:db:1e:88:a6:ed: + 27:50:1b:02:30:24:46:79:fe:04:87:70:97:40:73:d1:c0:c1: + 57:19:9a:69:a5:27:99:ab:9d:62:84:f6:51:c1:2c:c9:23:15: + d8:28:b7:ab:25:13:b5:46:e1:86:02:ff:26:8c:c4:88:92:1d: + 56:fe:19:67:f2:55:e4:80:a3:6b:9c:ab:77:e1:51:71:0d:20: + db:10:9a:db:bd:76:79:07:77:99:28:ad:9a:5e:da:b1:4f:44: + 2c:35:8e:a5:96:c7:fd:83:f0:58:c6:79:d6:98:7c:a8:8d:fe: + 86:3e:07:16:92:e1:7b:e7:1d:ec:33:76:7e:42:2e:4a:85:f9: + 91:89:68:84:03:81:a5:9b:9a:be:e3:37:c5:54:ab:56:3b:18: + 2d:41:a4:0c:f8:42:db:99:a0:e0:72:6f:bb:5d:e1:16:4f:53: + 0a:64:f9:4e:f4:bf:4e:54:bd:78:6c:88:ea:bf:9c:13:24:c2: + 70:69:a2:7f:0f:c8:3c:ad:08:c9:b0:98:40:a3:2a:e7:88:83: + ed:77:8f:74 +-----BEGIN CERTIFICATE----- +MIIDfTCCAmWgAwIBAgIBADANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJKUDEl +MCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEqMCgGA1UECxMh +U2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBFViBSb290Q0ExMB4XDTA3MDYwNjAyMTIz +MloXDTM3MDYwNjAyMTIzMlowYDELMAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09N +IFRydXN0IFN5c3RlbXMgQ08uLExURC4xKjAoBgNVBAsTIVNlY3VyaXR5IENvbW11 +bmljYXRpb24gRVYgUm9vdENBMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBALx/7FebJOD+nLpCeamIivqA4PUHKUPqjgo0No0c+qe1OXj/l3X3L+SqawSE +RMqm4miO/VVQYg+kcQ7OBzgtQoVQrTyWb4vVog7P3kmJPdZkLjjlHmy1V4qe70gO +zXppFodEtZDkBp2uoQSXWHnvIEqCa4wiv+wfD+mEce3xDuS4GBPMVjZd0ZoeUWs5 +bmB2iDQL87PRsJ3KYeJkHcFGB7hj3R4zZbOOCVVSPbW9/wfrrWFVGCypaZhKqkDF +MxRldAD5kd6vA0jFQFTcD4SQaCDFkpbcLuUCRarAX1T4bepJz11sS6/vmsJWXMY1 +VkJqMF/Cq/biPT+zyRGPMUzXn0kCAwEAAaNCMEAwHQYDVR0OBBYEFDVK9U2vP9eC +OKyrcWUXdYydVZPmMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0G +CSqGSIb3DQEBBQUAA4IBAQCoh+ns+EBnXcPBZsdAS5f8hxOQWsTvoMpfi7ent/HW +tWS3irO4G8za+6xmiEHO6Pzk2x6Ipu0nUBsCMCRGef4Eh3CXQHPRwMFXGZpppSeZ +q51ihPZRwSzJIxXYKLerJRO1RuGGAv8mjMSIkh1W/hln8lXkgKNrnKt34VFxDSDb +EJrbvXZ5B3eZKK2aXtqxT0QsNY6llsf9g/BYxnnWmHyojf6GPgcWkuF75x3sM3Z+ +Qi5KhfmRiWiEA4Glm5q+4zfFVKtWOxgtQaQM+ELbmaDgcm+7XeEWT1MKZPlO9L9O +VL14bIjqv5wTJMJwaaJ/D8g8rQjJsJhAoyrniIPtd490 +-----END CERTIFICATE----- + +OISTE WISeKey Global Root GA CA +# Issuer: CN=OISTE WISeKey Global Root GA CA,OU=OISTE Foundation Endorsed,OU=Copyright (c) 2005,O=WISeKey,C=CH +# Serial Number:41:3d:72:c7:f4:6b:1f:81:43:7d:f1:d2:28:54:df:9a +# Subject: CN=OISTE WISeKey Global Root GA CA,OU=OISTE Foundation Endorsed,OU=Copyright (c) 2005,O=WISeKey,C=CH +# Not Valid Before: Sun Dec 11 16:03:44 2005 +# Not Valid After : Fri Dec 11 16:09:51 2037 +# Fingerprint (MD5): BC:6C:51:33:A7:E9:D3:66:63:54:15:72:1B:21:92:93 +# Fingerprint (SHA1): 59:22:A1:E1:5A:EA:16:35:21:F8:98:39:6A:46:46:B0:44:1B:0F:A9 +MUST_VERIFY_TRUST: CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +================================================ +MD5 Fingerprint=BC:6C:51:33:A7:E9:D3:66:63:54:15:72:1B:21:92:93 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 41:3d:72:c7:f4:6b:1f:81:43:7d:f1:d2:28:54:df:9a + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=CH, O=WISeKey, OU=Copyright (c) 2005, OU=OISTE Foundation Endorsed, CN=OISTE WISeKey Global Root GA CA + Validity + Not Before: Dec 11 16:03:44 2005 GMT + Not After : Dec 11 16:09:51 2037 GMT + Subject: C=CH, O=WISeKey, OU=Copyright (c) 2005, OU=OISTE Foundation Endorsed, CN=OISTE WISeKey Global Root GA CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:cb:4f:b3:00:9b:3d:36:dd:f9:d1:49:6a:6b:10: + 49:1f:ec:d8:2b:b2:c6:f8:32:81:29:43:95:4c:9a: + 19:23:21:15:45:de:e3:c8:1c:51:55:5b:ae:93:e8: + 37:ff:2b:6b:e9:d4:ea:be:2a:dd:a8:51:2b:d7:66: + c3:61:5c:60:02:c8:f5:ce:72:7b:3b:b8:f2:4e:65: + 08:9a:cd:a4:6a:19:c1:01:bb:73:a6:d7:f6:c3:dd: + cd:bc:a4:8b:b5:99:61:b8:01:a2:a3:d4:4d:d4:05: + 3d:91:ad:f8:b4:08:71:64:af:70:f1:1c:6b:7e:f6: + c3:77:9d:24:73:7b:e4:0c:8c:e1:d9:36:e1:99:8b: + 05:99:0b:ed:45:31:09:ca:c2:00:db:f7:72:a0:96: + aa:95:87:d0:8e:c7:b6:61:73:0d:76:66:8c:dc:1b: + b4:63:a2:9f:7f:93:13:30:f1:a1:27:db:d9:ff:2c: + 55:88:91:a0:e0:4f:07:b0:28:56:8c:18:1b:97:44: + 8e:89:dd:e0:17:6e:e7:2a:ef:8f:39:0a:31:84:82: + d8:40:14:49:2e:7a:41:e4:a7:fe:e3:64:cc:c1:59: + 71:4b:2c:21:a7:5b:7d:e0:1d:d1:2e:81:9b:c3:d8: + 68:f7:bd:96:1b:ac:70:b1:16:14:0b:db:60:b9:26: + 01:05 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: + Digital Signature, Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + B3:03:7E:AE:36:BC:B0:79:D1:DC:94:26:B6:11:BE:21:B2:69:86:94 + 1.3.6.1.4.1.311.21.1: + ... + Signature Algorithm: sha1WithRSAEncryption + 4b:a1:ff:0b:87:6e:b3:f9:c1:43:b1:48:f3:28:c0:1d:2e:c9: + 09:41:fa:94:00:1c:a4:a4:ab:49:4f:8f:3d:1e:ef:4d:6f:bd: + bc:a4:f6:f2:26:30:c9:10:ca:1d:88:fb:74:19:1f:85:45:bd: + b0:6c:51:f9:36:7e:db:f5:4c:32:3a:41:4f:5b:47:cf:e8:0b: + 2d:b6:c4:19:9d:74:c5:47:c6:3b:6a:0f:ac:14:db:3c:f4:73: + 9c:a9:05:df:00:dc:74:78:fa:f8:35:60:59:02:13:18:7c:bc: + fb:4d:b0:20:6d:43:bb:60:30:7a:67:33:5c:c5:99:d1:f8:2d: + 39:52:73:fb:8c:aa:97:25:5c:72:d9:08:1e:ab:4e:3c:e3:81: + 31:9f:03:a6:fb:c0:fe:29:88:55:da:84:d5:50:03:b6:e2:84: + a3:a6:36:aa:11:3a:01:e1:18:4b:d6:44:68:b3:3d:f9:53:74: + 84:b3:46:91:46:96:00:b7:80:2c:b6:e1:e3:10:e2:db:a2:e7: + 28:8f:01:96:62:16:3e:00:e3:1c:a5:36:81:18:a2:4c:52:76: + c0:11:a3:6e:e6:1d:ba:e3:5a:be:36:53:c5:3e:75:8f:86:69: + 29:58:53:b5:9c:bb:6f:9f:5c:c5:18:ec:dd:2f:e1:98:c9:fc: + be:df:0a:0d +-----BEGIN CERTIFICATE----- +MIID8TCCAtmgAwIBAgIQQT1yx/RrH4FDffHSKFTfmjANBgkqhkiG9w0BAQUFADCB +ijELMAkGA1UEBhMCQ0gxEDAOBgNVBAoTB1dJU2VLZXkxGzAZBgNVBAsTEkNvcHly +aWdodCAoYykgMjAwNTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNl +ZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQSBDQTAeFw0w +NTEyMTExNjAzNDRaFw0zNzEyMTExNjA5NTFaMIGKMQswCQYDVQQGEwJDSDEQMA4G +A1UEChMHV0lTZUtleTEbMBkGA1UECxMSQ29weXJpZ2h0IChjKSAyMDA1MSIwIAYD +VQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBX +SVNlS2V5IEdsb2JhbCBSb290IEdBIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAy0+zAJs9Nt350UlqaxBJH+zYK7LG+DKBKUOVTJoZIyEVRd7jyBxR +VVuuk+g3/ytr6dTqvirdqFEr12bDYVxgAsj1znJ7O7jyTmUIms2kahnBAbtzptf2 +w93NvKSLtZlhuAGio9RN1AU9ka34tAhxZK9w8RxrfvbDd50kc3vkDIzh2TbhmYsF +mQvtRTEJysIA2/dyoJaqlYfQjse2YXMNdmaM3Bu0Y6Kff5MTMPGhJ9vZ/yxViJGg +4E8HsChWjBgbl0SOid3gF27nKu+POQoxhILYQBRJLnpB5Kf+42TMwVlxSywhp1t9 +4B3RLoGbw9ho972WG6xwsRYUC9tguSYBBQIDAQABo1EwTzALBgNVHQ8EBAMCAYYw +DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUswN+rja8sHnR3JQmthG+IbJphpQw +EAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBAEuh/wuHbrP5wUOx +SPMowB0uyQlB+pQAHKSkq0lPjz0e701vvbyk9vImMMkQyh2I+3QZH4VFvbBsUfk2 +ftv1TDI6QU9bR8/oCy22xBmddMVHxjtqD6wU2zz0c5ypBd8A3HR4+vg1YFkCExh8 +vPtNsCBtQ7tgMHpnM1zFmdH4LTlSc/uMqpclXHLZCB6rTjzjgTGfA6b7wP4piFXa +hNVQA7bihKOmNqoROgHhGEvWRGizPflTdISzRpFGlgC3gCy24eMQ4tui5yiPAZZi +Fj4A4xylNoEYokxSdsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ +/L7fCg0= +-----END CERTIFICATE----- + +Certigna +# Issuer: CN=Certigna,O=Dhimyotis,C=FR +# Serial Number:00:fe:dc:e3:01:0f:c9:48:ff +# Subject: CN=Certigna,O=Dhimyotis,C=FR +# Not Valid Before: Fri Jun 29 15:13:05 2007 +# Not Valid After : Tue Jun 29 15:13:05 2027 +# Fingerprint (MD5): AB:57:A6:5B:7D:42:82:19:B5:D8:58:26:28:5E:FD:FF +# Fingerprint (SHA1): B1:2E:13:63:45:86:A4:6F:1A:B2:60:68:37:58:2D:C4:AC:FD:94:97 +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +MUST_VERIFY_TRUST: CODE_SIGNING +================================================ +MD5 Fingerprint=AB:57:A6:5B:7D:42:82:19:B5:D8:58:26:28:5E:FD:FF +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + fe:dc:e3:01:0f:c9:48:ff + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=FR, O=Dhimyotis, CN=Certigna + Validity + Not Before: Jun 29 15:13:05 2007 GMT + Not After : Jun 29 15:13:05 2027 GMT + Subject: C=FR, O=Dhimyotis, CN=Certigna + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:c8:68:f1:c9:d6:d6:b3:34:75:26:82:1e:ec:b4: + be:ea:5c:e1:26:ed:11:47:61:e1:a2:7c:16:78:40: + 21:e4:60:9e:5a:c8:63:e1:c4:b1:96:92:ff:18:6d: + 69:23:e1:2b:62:f7:dd:e2:36:2f:91:07:b9:48:cf: + 0e:ec:79:b6:2c:e7:34:4b:70:08:25:a3:3c:87:1b: + 19:f2:81:07:0f:38:90:19:d3:11:fe:86:b4:f2:d1: + 5e:1e:1e:96:cd:80:6c:ce:3b:31:93:b6:f2:a0:d0: + a9:95:12:7d:a5:9a:cc:6b:c8:84:56:8a:33:a9:e7: + 22:15:53:16:f0:cc:17:ec:57:5f:e9:a2:0a:98:09: + de:e3:5f:9c:6f:dc:48:e3:85:0b:15:5a:a6:ba:9f: + ac:48:e3:09:b2:f7:f4:32:de:5e:34:be:1c:78:5d: + 42:5b:ce:0e:22:8f:4d:90:d7:7d:32:18:b3:0b:2c: + 6a:bf:8e:3f:14:11:89:20:0e:77:14:b5:3d:94:08: + 87:f7:25:1e:d5:b2:60:00:ec:6f:2a:28:25:6e:2a: + 3e:18:63:17:25:3f:3e:44:20:16:f6:26:c8:25:ae: + 05:4a:b4:e7:63:2c:f3:8c:16:53:7e:5c:fb:11:1a: + 08:c1:46:62:9f:22:b8:f1:c2:8d:69:dc:fa:3a:58: + 06:df + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + 1A:ED:FE:41:39:90:B4:24:59:BE:01:F2:52:D5:45:F6:5A:39:DC:11 + X509v3 Authority Key Identifier: + keyid:1A:ED:FE:41:39:90:B4:24:59:BE:01:F2:52:D5:45:F6:5A:39:DC:11 + DirName:/C=FR/O=Dhimyotis/CN=Certigna + serial:FE:DC:E3:01:0F:C9:48:FF + + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + Netscape Cert Type: + SSL CA, S/MIME CA, Object Signing CA + Signature Algorithm: sha1WithRSAEncryption + 85:03:1e:92:71:f6:42:af:e1:a3:61:9e:eb:f3:c0:0f:f2:a5: + d4:da:95:e6:d6:be:68:36:3d:7e:6e:1f:4c:8a:ef:d1:0f:21: + 6d:5e:a5:52:63:ce:12:f8:ef:2a:da:6f:eb:37:fe:13:02:c7: + cb:3b:3e:22:6b:da:61:2e:7f:d4:72:3d:dd:30:e1:1e:4c:40: + 19:8c:0f:d7:9c:d1:83:30:7b:98:59:dc:7d:c6:b9:0c:29:4c: + a1:33:a2:eb:67:3a:65:84:d3:96:e2:ed:76:45:70:8f:b5:2b: + de:f9:23:d6:49:6e:3c:14:b5:c6:9f:35:1e:50:d0:c1:8f:6a: + 70:44:02:62:cb:ae:1d:68:41:a7:aa:57:e8:53:aa:07:d2:06: + f6:d5:14:06:0b:91:03:75:2c:6c:72:b5:61:95:9a:0d:8b:b9: + 0d:e7:f5:df:54:cd:de:e6:d8:d6:09:08:97:63:e5:c1:2e:b0: + b7:44:26:c0:26:c0:af:55:30:9e:3b:d5:36:2a:19:04:f4:5c: + 1e:ff:cf:2c:b7:ff:d0:fd:87:40:11:d5:11:23:bb:48:c0:21: + a9:a4:28:2d:fd:15:f8:b0:4e:2b:f4:30:5b:21:fc:11:91:34: + be:41:ef:7b:9d:97:75:ff:97:95:c0:96:58:2f:ea:bb:46:d7: + bb:e4:d9:2e +-----BEGIN CERTIFICATE----- +MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNV +BAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4X +DTA3MDYyOTE1MTMwNVoXDTI3MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQ +BgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwIQ2VydGlnbmEwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7qXOEm7RFHYeGifBZ4 +QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyHGxny +gQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbw +zBfsV1/pogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q +130yGLMLLGq/jj8UEYkgDncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2 +JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKfIrjxwo1p3Po6WAbfAgMBAAGjgbwwgbkw +DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQtCRZvgHyUtVF9lo53BEw +ZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJBgNVBAYT +AkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzj +AQ/JSP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG +9w0BAQUFAAOCAQEAhQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8h +bV6lUmPOEvjvKtpv6zf+EwLHyzs+ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFnc +fca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1kluPBS1xp81HlDQwY9qcEQCYsuu +HWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY1gkIl2PlwS6w +t0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw +WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg== +-----END CERTIFICATE----- + +Deutsche Telekom Root CA 2 +# Issuer: CN=Deutsche Telekom Root CA 2,OU=T-TeleSec Trust Center,O=Deutsche Telekom AG,C=DE +# Serial Number: 38 (0x26) +# Subject: CN=Deutsche Telekom Root CA 2,OU=T-TeleSec Trust Center,O=Deutsche Telekom AG,C=DE +# Not Valid Before: Fri Jul 09 12:11:00 1999 +# Not Valid After : Tue Jul 09 23:59:00 2019 +# Fingerprint (MD5): 74:01:4A:91:B1:08:C4:58:CE:47:CD:F0:DD:11:53:08 +# Fingerprint (SHA1): 85:A4:08:C0:9C:19:3E:5D:51:58:7D:CD:D6:13:30:FD:8C:DE:37:BF +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +MUST_VERIFY_TRUST: CODE_SIGNING +================================================ +MD5 Fingerprint=74:01:4A:91:B1:08:C4:58:CE:47:CD:F0:DD:11:53:08 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 38 (0x26) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=DE, O=Deutsche Telekom AG, OU=T-TeleSec Trust Center, CN=Deutsche Telekom Root CA 2 + Validity + Not Before: Jul 9 12:11:00 1999 GMT + Not After : Jul 9 23:59:00 2019 GMT + Subject: C=DE, O=Deutsche Telekom AG, OU=T-TeleSec Trust Center, CN=Deutsche Telekom Root CA 2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:ab:0b:a3:35:e0:8b:29:14:b1:14:85:af:3c:10: + e4:39:6f:35:5d:4a:ae:dd:ea:61:8d:95:49:f4:6f: + 64:a3:1a:60:66:a4:a9:40:22:84:d9:d4:a5:e5:78: + 93:0e:68:01:ad:b9:4d:5c:3a:ce:d3:b8:a8:42:40: + df:cf:a3:ba:82:59:6a:92:1b:ac:1c:9a:da:08:2b: + 25:27:f9:69:23:47:f1:e0:eb:2c:7a:9b:f5:13:02: + d0:7e:34:7c:c2:9e:3c:00:59:ab:f5:da:0c:f5:32: + 3c:2b:ac:50:da:d6:c3:de:83:94:ca:a8:0c:99:32: + 0e:08:48:56:5b:6a:fb:da:e1:58:58:01:49:5f:72: + 41:3c:15:06:01:8e:5d:ad:aa:b8:93:b4:cd:9e:eb: + a7:e8:6a:2d:52:34:db:3a:ef:5c:75:51:da:db:f3: + 31:f9:ee:71:98:32:c4:54:15:44:0c:f9:9b:55:ed: + ad:df:18:08:a0:a3:86:8a:49:ee:53:05:8f:19:4c: + d5:de:58:79:9b:d2:6a:1c:42:ab:c5:d5:a7:cf:68: + 0f:96:e4:e1:61:98:76:61:c8:91:7c:d6:3e:00:e2: + 91:50:87:e1:9d:0a:e6:ad:97:d2:1d:c6:3a:7d:cb: + bc:da:03:34:d5:8e:5b:01:f5:6a:07:b7:16:b6:6e: + 4a:7f + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + 31:C3:79:1B:BA:F5:53:D7:17:E0:89:7A:2D:17:6C:0A:B3:2B:9D:33 + X509v3 Basic Constraints: + CA:TRUE, pathlen:5 + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + Signature Algorithm: sha1WithRSAEncryption + 94:64:59:ad:39:64:e7:29:eb:13:fe:5a:c3:8b:13:57:c8:04: + 24:f0:74:77:c0:60:e3:67:fb:e9:89:a6:83:bf:96:82:7c:6e: + d4:c3:3d:ef:9e:80:6e:bb:29:b4:98:7a:b1:3b:54:eb:39:17: + 47:7e:1a:8e:0b:fc:1f:31:59:31:04:b2:ce:17:f3:2c:c7:62: + 36:55:e2:22:d8:89:55:b4:98:48:aa:64:fa:d6:1c:36:d8:44: + 78:5a:5a:23:3a:57:97:f5:7a:30:4f:ae:9f:6a:4c:4b:2b:8e: + a0:03:e3:3e:e0:a9:d4:d2:7b:d2:b3:a8:e2:72:3c:ad:9e:ff: + 80:59:e4:9b:45:b4:f6:3b:b0:cd:39:19:98:32:e5:ea:21:61: + 90:e4:31:21:8e:34:b1:f7:2f:35:4a:85:10:da:e7:8a:37:21: + be:59:63:e0:f2:85:88:31:53:d4:54:14:85:70:79:f4:2e:06: + 77:27:75:2f:1f:b8:8a:f9:fe:c5:ba:d8:36:e4:83:ec:e7:65: + b7:bf:63:5a:f3:46:af:81:94:37:d4:41:8c:d6:23:d6:1e:cf: + f5:68:1b:44:63:a2:5a:ba:a7:35:59:a1:e5:70:05:9b:0e:23: + 57:99:94:0a:6d:ba:39:63:28:86:92:f3:18:84:d8:fb:d1:cf: + 05:56:64:57 +-----BEGIN CERTIFICATE----- +MIIDnzCCAoegAwIBAgIBJjANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJERTEc +MBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxlU2Vj +IFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290IENB +IDIwHhcNOTkwNzA5MTIxMTAwWhcNMTkwNzA5MjM1OTAwWjBxMQswCQYDVQQGEwJE +RTEcMBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxl +U2VjIFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290 +IENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrC6M14IspFLEU +ha88EOQ5bzVdSq7d6mGNlUn0b2SjGmBmpKlAIoTZ1KXleJMOaAGtuU1cOs7TuKhC +QN/Po7qCWWqSG6wcmtoIKyUn+WkjR/Hg6yx6m/UTAtB+NHzCnjwAWav12gz1Mjwr +rFDa1sPeg5TKqAyZMg4ISFZbavva4VhYAUlfckE8FQYBjl2tqriTtM2e66foai1S +NNs671x1Udrb8zH57nGYMsRUFUQM+ZtV7a3fGAigo4aKSe5TBY8ZTNXeWHmb0moc +QqvF1afPaA+W5OFhmHZhyJF81j4A4pFQh+GdCuatl9Idxjp9y7zaAzTVjlsB9WoH +txa2bkp/AgMBAAGjQjBAMB0GA1UdDgQWBBQxw3kbuvVT1xfgiXotF2wKsyudMzAP +BgNVHRMECDAGAQH/AgEFMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOC +AQEAlGRZrTlk5ynrE/5aw4sTV8gEJPB0d8Bg42f76Ymmg7+Wgnxu1MM9756Abrsp +tJh6sTtU6zkXR34ajgv8HzFZMQSyzhfzLMdiNlXiItiJVbSYSKpk+tYcNthEeFpa +IzpXl/V6ME+un2pMSyuOoAPjPuCp1NJ70rOo4nI8rZ7/gFnkm0W09juwzTkZmDLl +6iFhkOQxIY40sfcvNUqFENrnijchvllj4PKFiDFT1FQUhXB59C4Gdyd1Lx+4ivn+ +xbrYNuSD7Odlt79jWvNGr4GUN9RBjNYj1h7P9WgbRGOiWrqnNVmh5XAFmw4jV5mU +Cm26OWMohpLzGITY+9HPBVZkVw== +-----END CERTIFICATE----- + +Cybertrust Global Root +# Issuer: CN=Cybertrust Global Root,O="Cybertrust, Inc" +# Serial Number:04:00:00:00:00:01:0f:85:aa:2d:48 +# Subject: CN=Cybertrust Global Root,O="Cybertrust, Inc" +# Not Valid Before: Fri Dec 15 08:00:00 2006 +# Not Valid After : Wed Dec 15 08:00:00 2021 +# Fingerprint (MD5): 72:E4:4A:87:E3:69:40:80:77:EA:BC:E3:F4:FF:F0:E1 +# Fingerprint (SHA1): 5F:43:E5:B1:BF:F8:78:8C:AC:1C:C7:CA:4A:9A:C6:22:2B:CC:34:C6 +TRUSTED_DELEGATOR: SERVER_AUTH +MUST_VERIFY_TRUST: EMAIL_PROTECTION, CODE_SIGNING +================================================= +MD5 Fingerprint=72:E4:4A:87:E3:69:40:80:77:EA:BC:E3:F4:FF:F0:E1 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 04:00:00:00:00:01:0f:85:aa:2d:48 + Signature Algorithm: sha1WithRSAEncryption + Issuer: O=Cybertrust, Inc, CN=Cybertrust Global Root + Validity + Not Before: Dec 15 08:00:00 2006 GMT + Not After : Dec 15 08:00:00 2021 GMT + Subject: O=Cybertrust, Inc, CN=Cybertrust Global Root + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:f8:c8:bc:bd:14:50:66:13:ff:f0:d3:79:ec:23: + f2:b7:1a:c7:8e:85:f1:12:73:a6:19:aa:10:db:9c: + a2:65:74:5a:77:3e:51:7d:56:f6:dc:23:b6:d4:ed: + 5f:58:b1:37:4d:d5:49:0e:6e:f5:6a:87:d6:d2:8c: + d2:27:c6:e2:ff:36:9f:98:65:a0:13:4e:c6:2a:64: + 9b:d5:90:12:cf:14:06:f4:3b:e3:d4:28:be:e8:0e: + f8:ab:4e:48:94:6d:8e:95:31:10:5c:ed:a2:2d:bd: + d5:3a:6d:b2:1c:bb:60:c0:46:4b:01:f5:49:ae:7e: + 46:8a:d0:74:8d:a1:0c:02:ce:ee:fc:e7:8f:b8:6b: + 66:f3:7f:44:00:bf:66:25:14:2b:dd:10:30:1d:07: + 96:3f:4d:f6:6b:b8:8f:b7:7b:0c:a5:38:eb:de:47: + db:d5:5d:39:fc:88:a7:f3:d7:2a:74:f1:e8:5a:a2: + 3b:9f:50:ba:a6:8c:45:35:c2:50:65:95:dc:63:82: + ef:dd:bf:77:4d:9c:62:c9:63:73:16:d0:29:0f:49: + a9:48:f0:b3:aa:b7:6c:c5:a7:30:39:40:5d:ae:c4: + e2:5d:26:53:f0:ce:1c:23:08:61:a8:94:19:ba:04: + 62:40:ec:1f:38:70:77:12:06:71:a7:30:18:5d:25: + 27:a5 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + B6:08:7B:0D:7A:CC:AC:20:4C:86:56:32:5E:CF:AB:6E:85:2D:70:57 + X509v3 CRL Distribution Points: + + Full Name: + URI:http://www2.public-trust.com/crl/ct/ctroot.crl + + X509v3 Authority Key Identifier: + keyid:B6:08:7B:0D:7A:CC:AC:20:4C:86:56:32:5E:CF:AB:6E:85:2D:70:57 + + Signature Algorithm: sha1WithRSAEncryption + 56:ef:0a:23:a0:54:4e:95:97:c9:f8:89:da:45:c1:d4:a3:00: + 25:f4:1f:13:ab:b7:a3:85:58:69:c2:30:ad:d8:15:8a:2d:e3: + c9:cd:81:5a:f8:73:23:5a:a7:7c:05:f3:fd:22:3b:0e:d1:06: + c4:db:36:4c:73:04:8e:e5:b0:22:e4:c5:f3:2e:a5:d9:23:e3: + b8:4e:4a:20:a7:6e:02:24:9f:22:60:67:7b:8b:1d:72:09:c5: + 31:5c:e9:79:9f:80:47:3d:ad:a1:0b:07:14:3d:47:ff:03:69: + 1a:0c:0b:44:e7:63:25:a7:7f:b2:c9:b8:76:84:ed:23:f6:7d: + 07:ab:45:7e:d3:df:b3:bf:e9:8a:b6:cd:a8:a2:67:2b:52:d5: + b7:65:f0:39:4c:63:a0:91:79:93:52:0f:54:dd:83:bb:9f:d1: + 8f:a7:53:73:c3:cb:ff:30:ec:7c:04:b8:d8:44:1f:93:5f:71: + 09:22:b7:6e:3e:ea:1c:03:4e:9d:1a:20:61:fb:81:37:ec:5e: + fc:0a:45:ab:d7:e7:17:55:d0:a0:ea:60:9b:a6:f6:e3:8c:5b: + 29:c2:06:60:14:9d:2d:97:4c:a9:93:15:9d:61:c4:01:5f:48: + d6:58:bd:56:31:12:4e:11:c8:21:e0:b3:11:91:65:db:b4:a6: + 88:38:ce:55 +-----BEGIN CERTIFICATE----- +MIIDoTCCAomgAwIBAgILBAAAAAABD4WqLUgwDQYJKoZIhvcNAQEFBQAwOzEYMBYG +A1UEChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2Jh +bCBSb290MB4XDTA2MTIxNTA4MDAwMFoXDTIxMTIxNTA4MDAwMFowOzEYMBYGA1UE +ChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2JhbCBS +b290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA+Mi8vRRQZhP/8NN5 +7CPytxrHjoXxEnOmGaoQ25yiZXRadz5RfVb23CO21O1fWLE3TdVJDm71aofW0ozS +J8bi/zafmGWgE07GKmSb1ZASzxQG9Dvj1Ci+6A74q05IlG2OlTEQXO2iLb3VOm2y +HLtgwEZLAfVJrn5GitB0jaEMAs7u/OePuGtm839EAL9mJRQr3RAwHQeWP032a7iP +t3sMpTjr3kfb1V05/Iin89cqdPHoWqI7n1C6poxFNcJQZZXcY4Lv3b93TZxiyWNz +FtApD0mpSPCzqrdsxacwOUBdrsTiXSZT8M4cIwhhqJQZugRiQOwfOHB3EgZxpzAY +XSUnpQIDAQABo4GlMIGiMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/ +MB0GA1UdDgQWBBS2CHsNesysIEyGVjJez6tuhS1wVzA/BgNVHR8EODA2MDSgMqAw +hi5odHRwOi8vd3d3Mi5wdWJsaWMtdHJ1c3QuY29tL2NybC9jdC9jdHJvb3QuY3Js +MB8GA1UdIwQYMBaAFLYIew16zKwgTIZWMl7Pq26FLXBXMA0GCSqGSIb3DQEBBQUA +A4IBAQBW7wojoFROlZfJ+InaRcHUowAl9B8Tq7ejhVhpwjCt2BWKLePJzYFa+HMj +Wqd8BfP9IjsO0QbE2zZMcwSO5bAi5MXzLqXZI+O4Tkogp24CJJ8iYGd7ix1yCcUx +XOl5n4BHPa2hCwcUPUf/A2kaDAtE52Mlp3+yybh2hO0j9n0Hq0V+09+zv+mKts2o +omcrUtW3ZfA5TGOgkXmTUg9U3YO7n9GPp1Nzw8v/MOx8BLjYRB+TX3EJIrduPuoc +A06dGiBh+4E37F78CkWr1+cXVdCg6mCbpvbjjFspwgZgFJ0tl0ypkxWdYcQBX0jW +WL1WMRJOEcgh4LMRkWXbtKaIOM5V +-----END CERTIFICATE----- + +ePKI Root Certification Authority +# Issuer: OU=ePKI Root Certification Authority,O="Chunghwa Telecom Co., Ltd.",C=TW +# Serial Number:15:c8:bd:65:47:5c:af:b8:97:00:5e:e4:06:d2:bc:9d +# Subject: OU=ePKI Root Certification Authority,O="Chunghwa Telecom Co., Ltd.",C=TW +# Not Valid Before: Mon Dec 20 02:31:27 2004 +# Not Valid After : Wed Dec 20 02:31:27 2034 +# Fingerprint (MD5): 1B:2E:00:CA:26:06:90:3D:AD:FE:6F:15:68:D3:6B:B3 +# Fingerprint (SHA1): 67:65:0D:F1:7E:8E:7E:5B:82:40:A4:F4:56:4B:CF:E2:3D:69:C6:F0 +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +MUST_VERIFY_TRUST: CODE_SIGNING +================================================ +MD5 Fingerprint=1B:2E:00:CA:26:06:90:3D:AD:FE:6F:15:68:D3:6B:B3 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 15:c8:bd:65:47:5c:af:b8:97:00:5e:e4:06:d2:bc:9d + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=TW, O=Chunghwa Telecom Co., Ltd., OU=ePKI Root Certification Authority + Validity + Not Before: Dec 20 02:31:27 2004 GMT + Not After : Dec 20 02:31:27 2034 GMT + Subject: C=TW, O=Chunghwa Telecom Co., Ltd., OU=ePKI Root Certification Authority + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:e1:25:0f:ee:8d:db:88:33:75:67:cd:ad:1f:7d: + 3a:4e:6d:9d:d3:2f:14:f3:63:74:cb:01:21:6a:37: + ea:84:50:07:4b:26:5b:09:43:6c:21:9e:6a:c8:d5: + 03:f5:60:69:8f:cc:f0:22:e4:1f:e7:f7:6a:22:31: + b7:2c:15:f2:e0:fe:00:6a:43:ff:87:65:c6:b5:1a: + c1:a7:4c:6d:22:70:21:8a:31:f2:97:74:89:09:12: + 26:1c:9e:ca:d9:12:a2:95:3c:da:e9:67:bf:08:a0: + 64:e3:d6:42:b7:45:ef:97:f4:f6:f5:d7:b5:4a:15: + 02:58:7d:98:58:4b:60:bc:cd:d7:0d:9a:13:33:53: + d1:61:f9:7a:d5:d7:78:b3:9a:33:f7:00:86:ce:1d: + 4d:94:38:af:a8:ec:78:51:70:8a:5c:10:83:51:21: + f7:11:3d:34:86:5e:e5:48:cd:97:81:82:35:4c:19: + ec:65:f6:6b:c5:05:a1:ee:47:13:d6:b3:21:27:94: + 10:0a:d9:24:3b:ba:be:44:13:46:30:3f:97:3c:d8: + d7:d7:6a:ee:3b:38:e3:2b:d4:97:0e:b9:1b:e7:07: + 49:7f:37:2a:f9:77:78:cf:54:ed:5b:46:9d:a3:80: + 0e:91:43:c1:d6:5b:5f:14:ba:9f:a6:8d:24:47:40: + 59:bf:72:38:b2:36:6c:37:ff:99:d1:5d:0e:59:0a: + ab:69:f7:c0:b2:04:45:7a:54:00:ae:be:53:f6:b5: + e7:e1:f8:3c:a3:31:d2:a9:fe:21:52:64:c5:a6:67: + f0:75:07:06:94:14:81:55:c6:27:e4:01:8f:17:c1: + 6a:71:d7:be:4b:fb:94:58:7d:7e:11:33:b1:42:f7: + 62:6c:18:d6:cf:09:68:3e:7f:6c:f6:1e:8f:62:ad: + a5:63:db:09:a7:1f:22:42:41:1e:6f:99:8a:3e:d7: + f9:3f:40:7a:79:b0:a5:01:92:d2:9d:3d:08:15:a5: + 10:01:2d:b3:32:76:a8:95:0d:b3:7a:9a:fb:07:10: + 78:11:6f:e1:8f:c7:ba:0f:25:1a:74:2a:e5:1c:98: + 41:99:df:21:87:e8:95:06:6a:0a:b3:6a:47:76:65: + f6:3a:cf:8f:62:17:19:7b:0a:28:cd:1a:d2:83:1e: + 21:c7:2c:bf:be:ff:61:68:b7:67:1b:bb:78:4d:8d: + ce:67:e5:e4:c1:8e:b7:23:66:e2:9d:90:75:34:98: + a9:36:2b:8a:9a:94:b9:9d:ec:cc:8a:b1:f8:25:89: + 5c:5a:b6:2f:8c:1f:6d:79:24:a7:52:68:c3:84:35: + e2:66:8d:63:0e:25:4d:d5:19:b2:e6:79:37:a7:22: + 9d:54:31 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + 1E:0C:F7:B6:67:F2:E1:92:26:09:45:C0:55:39:2E:77:3F:42:4A:A2 + X509v3 Basic Constraints: + CA:TRUE + setCext-hashedRoot: + 0/0-...0...+......0...g*.....E... +V|.[x....S..... + Signature Algorithm: sha1WithRSAEncryption + 09:b3:83:53:59:01:3e:95:49:b9:f1:81:ba:f9:76:20:23:b5: + 27:60:74:d4:6a:99:34:5e:6c:00:53:d9:9f:f2:a6:b1:24:07: + 44:6a:2a:c6:a5:8e:78:12:e8:47:d9:58:1b:13:2a:5e:79:9b: + 9f:0a:2a:67:a6:25:3f:06:69:56:73:c3:8a:66:48:fb:29:81: + 57:74:06:ca:9c:ea:28:e8:38:67:26:2b:f1:d5:b5:3f:65:93: + f8:36:5d:8e:8d:8d:40:20:87:19:ea:ef:27:c0:3d:b4:39:0f: + 25:7b:68:50:74:55:9c:0c:59:7d:5a:3d:41:94:25:52:08:e0: + 47:2c:15:31:19:d5:bf:07:55:c6:bb:12:b5:97:f4:5f:83:85: + ba:71:c1:d9:6c:81:11:76:0a:0a:b0:bf:82:97:f7:ea:3d:fa: + fa:ec:2d:a9:28:94:3b:56:dd:d2:51:2e:ae:c0:bd:08:15:8c: + 77:52:34:96:d6:9b:ac:d3:1d:8e:61:0f:35:7b:9b:ae:39:69: + 0b:62:60:40:20:36:8f:af:fb:36:ee:2d:08:4a:1d:b8:bf:9b: + 5c:f8:ea:a5:1b:a0:73:a6:d8:f8:6e:e0:33:04:5f:68:aa:27: + 87:ed:d9:c1:90:9c:ed:bd:e3:6a:35:af:63:df:ab:18:d9:ba: + e6:e9:4a:ea:50:8a:0f:61:93:1e:e2:2d:19:e2:30:94:35:92: + 5d:0e:b6:07:af:19:80:8f:47:90:51:4b:2e:4d:dd:85:e2:d2: + 0a:52:0a:17:9a:fc:1a:b0:50:02:e5:01:a3:63:37:21:4c:44: + c4:9b:51:99:11:0e:73:9c:06:8f:54:2e:a7:28:5e:44:39:87: + 56:2d:37:bd:85:44:94:e1:0c:4b:2c:9c:c3:92:85:34:61:cb: + 0f:b8:9b:4a:43:52:fe:34:3a:7d:b8:e9:29:dc:76:a9:c8:30: + f8:14:71:80:c6:1e:36:48:74:22:41:5c:87:82:e8:18:71:8b: + 41:89:44:e7:7e:58:5b:a8:b8:8d:13:e9:a7:6c:c3:47:ed:b3: + 1a:9d:62:ae:8d:82:ea:94:9e:dd:59:10:c3:ad:dd:e2:4d:e3: + 31:d5:c7:ec:e8:f2:b0:fe:92:1e:16:0a:1a:fc:d9:f3:f8:27: + b6:c9:be:1d:b4:6c:64:90:7f:f4:e4:c4:5b:d7:37:ae:42:0e: + dd:a4:1a:6f:7c:88:54:c5:16:6e:e1:7a:68:2e:f8:3a:bf:0d: + a4:3c:89:3b:78:a7:4e:63:83:04:21:08:67:8d:f2:82:49:d0: + 5b:fd:b1:cd:0f:83:84:d4:3e:20:85:f7:4a:3d:2b:9c:fd:2a: + 0a:09:4d:ea:81:f8:11:9c +-----BEGIN CERTIFICATE----- +MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBe +MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0 +ZC4xKjAoBgNVBAsMIWVQS0kgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe +Fw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMxMjdaMF4xCzAJBgNVBAYTAlRXMSMw +IQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEqMCgGA1UECwwhZVBL +SSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEF +AAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAH +SyZbCUNsIZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAh +ijHyl3SJCRImHJ7K2RKilTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3X +DZoTM1PRYfl61dd4s5oz9wCGzh1NlDivqOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1 +TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX12ruOzjjK9SXDrkb5wdJ +fzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0OWQqraffA +sgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uU +WH1+ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLS +nT0IFaUQAS2zMnaolQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pH +dmX2Os+PYhcZewoozRrSgx4hxyy/vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJip +NiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXiZo1jDiVN1Rmy5nk3pyKdVDEC +AwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/QkqiMAwGA1UdEwQF +MAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH +ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGB +uvl2ICO1J2B01GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6Yl +PwZpVnPDimZI+ymBV3QGypzqKOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkP +JXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdVxrsStZf0X4OFunHB2WyBEXYKCrC/ +gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEPNXubrjlpC2JgQCA2 +j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+rGNm6 +5ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUB +o2M3IUxExJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS +/jQ6fbjpKdx2qcgw+BRxgMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2z +Gp1iro2C6pSe3VkQw63d4k3jMdXH7OjysP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTE +W9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmODBCEIZ43ygknQW/2xzQ+D +hNQ+IIX3Sj0rnP0qCglN6oH4EZw= +-----END CERTIFICATE----- + +certSIGN ROOT CA +# Issuer: OU=certSIGN ROOT CA,O=certSIGN,C=RO +# Serial Number:20:06:05:16:70:02 +# Subject: OU=certSIGN ROOT CA,O=certSIGN,C=RO +# Not Valid Before: Tue Jul 04 17:20:04 2006 +# Not Valid After : Fri Jul 04 17:20:04 2031 +# Fingerprint (MD5): 18:98:C0:D6:E9:3A:FC:F9:B0:F5:0C:F7:4B:01:44:17 +# Fingerprint (SHA1): FA:B7:EE:36:97:26:62:FB:2D:B0:2A:F6:BF:03:FD:E8:7C:4B:2F:9B +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +MUST_VERIFY_TRUST: CODE_SIGNING +================================================ +MD5 Fingerprint=18:98:C0:D6:E9:3A:FC:F9:B0:F5:0C:F7:4B:01:44:17 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 35210227249154 (0x200605167002) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=RO, O=certSIGN, OU=certSIGN ROOT CA + Validity + Not Before: Jul 4 17:20:04 2006 GMT + Not After : Jul 4 17:20:04 2031 GMT + Subject: C=RO, O=certSIGN, OU=certSIGN ROOT CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:b7:33:b9:7e:c8:25:4a:8e:b5:db:b4:28:1b:aa: + 57:90:e8:d1:22:d3:64:ba:d3:93:e8:d4:ac:86:61: + 40:6a:60:57:68:54:84:4d:bc:6a:54:02:05:ff:df: + 9b:9a:2a:ae:5d:07:8f:4a:c3:28:7f:ef:fb:2b:fa: + 79:f1:c7:ad:f0:10:53:24:90:8b:66:c9:a8:88:ab: + af:5a:a3:00:e9:be:ba:46:ee:5b:73:7b:2c:17:82: + 81:5e:62:2c:a1:02:65:b3:bd:c5:2b:00:7e:c4:fc: + 03:33:57:0d:ed:e2:fa:ce:5d:45:d6:38:cd:35:b6: + b2:c1:d0:9c:81:4a:aa:e4:b2:01:5c:1d:8f:5f:99: + c4:b1:ad:db:88:21:eb:90:08:82:80:f3:30:a3:43: + e6:90:82:ae:55:28:49:ed:5b:d7:a9:10:38:0e:fe: + 8f:4c:5b:9b:46:ea:41:f5:b0:08:74:c3:d0:88:33: + b6:7c:d7:74:df:dc:84:d1:43:0e:75:39:a1:25:40: + 28:ea:78:cb:0e:2c:2e:39:9d:8c:8b:6e:16:1c:2f: + 26:82:10:e2:e3:65:94:0a:04:c0:5e:f7:5d:5b:f8: + 10:e2:d0:ba:7a:4b:fb:de:37:00:00:1a:5b:28:e3: + d2:9c:73:3e:32:87:98:a1:c9:51:2f:d7:de:ac:33: + b3:4f + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Digital Signature, Non Repudiation, Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + E0:8C:9B:DB:25:49:B3:F1:7C:86:D6:B2:42:87:0B:D0:6B:A0:D9:E4 + Signature Algorithm: sha1WithRSAEncryption + 3e:d2:1c:89:2e:35:fc:f8:75:dd:e6:7f:65:88:f4:72:4c:c9: + 2c:d7:32:4e:f3:dd:19:79:47:bd:8e:3b:5b:93:0f:50:49:24: + 13:6b:14:06:72:ef:09:d3:a1:a1:e3:40:84:c9:e7:18:32:74: + 3c:48:6e:0f:9f:4b:d4:f7:1e:d3:93:86:64:54:97:63:72:50: + d5:55:cf:fa:20:93:02:a2:9b:c3:23:93:4e:16:55:76:a0:70: + 79:6d:cd:21:1f:cf:2f:2d:bc:19:e3:88:31:f8:59:1a:81:09: + c8:97:a6:74:c7:60:c4:5b:cc:57:8e:b2:75:fd:1b:02:09:db: + 59:6f:72:93:69:f7:31:41:d6:88:38:bf:87:b2:bd:16:79:f9: + aa:e4:be:88:25:dd:61:27:23:1c:b5:31:07:04:36:b4:1a:90: + bd:a0:74:71:50:89:6d:bc:14:e3:0f:86:ae:f1:ab:3e:c7:a0: + 09:cc:a3:48:d1:e0:db:64:e7:92:b5:cf:af:72:43:70:8b:f9: + c3:84:3c:13:aa:7e:92:9b:57:53:93:fa:70:c2:91:0e:31:f9: + 9b:67:5d:e9:96:38:5e:5f:b3:73:4e:88:15:67:de:9e:76:10: + 62:20:be:55:69:95:43:00:39:4d:f6:ee:b0:5a:4e:49:44:54: + 58:5f:42:83 +-----BEGIN CERTIFICATE----- +MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYT +AlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBD +QTAeFw0wNjA3MDQxNzIwMDRaFw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJP +MREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTCC +ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7IJUqOtdu0KBuqV5Do +0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHHrfAQ +UySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5d +RdY4zTW2ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQ +OA7+j0xbm0bqQfWwCHTD0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwv +JoIQ4uNllAoEwF73XVv4EOLQunpL+943AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08C +AwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAcYwHQYDVR0O +BBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IBAQA+0hyJ +LjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecY +MnQ8SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ +44gx+FkagQnIl6Z0x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6I +Jd1hJyMctTEHBDa0GpC9oHRxUIltvBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNw +i/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7NzTogVZ96edhBiIL5VaZVDADlN +9u6wWk5JRFRYX0KD +-----END CERTIFICATE----- + +GeoTrust Primary Certification Authority - G3 +# Issuer: CN=GeoTrust Primary Certification Authority - G3,OU=(c) 2008 GeoTrust Inc. - For authorized use only,O=GeoTrust Inc.,C=US +# Serial Number:15:ac:6e:94:19:b2:79:4b:41:f6:27:a9:c3:18:0f:1f +# Subject: CN=GeoTrust Primary Certification Authority - G3,OU=(c) 2008 GeoTrust Inc. - For authorized use only,O=GeoTrust Inc.,C=US +# Not Valid Before: Wed Apr 02 00:00:00 2008 +# Not Valid After : Tue Dec 01 23:59:59 2037 +# Fingerprint (MD5): B5:E8:34:36:C9:10:44:58:48:70:6D:2E:83:D4:B8:05 +# Fingerprint (SHA1): 03:9E:ED:B8:0B:E7:A0:3C:69:53:89:3B:20:D2:D9:32:3A:4C:2A:FD +MUST_VERIFY_TRUST: CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +================================================ +MD5 Fingerprint=B5:E8:34:36:C9:10:44:58:48:70:6D:2E:83:D4:B8:05 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 15:ac:6e:94:19:b2:79:4b:41:f6:27:a9:c3:18:0f:1f + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=GeoTrust Inc., OU=(c) 2008 GeoTrust Inc. - For authorized use only, CN=GeoTrust Primary Certification Authority - G3 + Validity + Not Before: Apr 2 00:00:00 2008 GMT + Not After : Dec 1 23:59:59 2037 GMT + Subject: C=US, O=GeoTrust Inc., OU=(c) 2008 GeoTrust Inc. - For authorized use only, CN=GeoTrust Primary Certification Authority - G3 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:dc:e2:5e:62:58:1d:33:57:39:32:33:fa:eb:cb: + 87:8c:a7:d4:4a:dd:06:88:ea:64:8e:31:98:a5:38: + 90:1e:98:cf:2e:63:2b:f0:46:bc:44:b2:89:a1:c0: + 28:0c:49:70:21:95:9f:64:c0:a6:93:12:02:65:26: + 86:c6:a5:89:f0:fa:d7:84:a0:70:af:4f:1a:97:3f: + 06:44:d5:c9:eb:72:10:7d:e4:31:28:fb:1c:61:e6: + 28:07:44:73:92:22:69:a7:03:88:6c:9d:63:c8:52: + da:98:27:e7:08:4c:70:3e:b4:c9:12:c1:c5:67:83: + 5d:33:f3:03:11:ec:6a:d0:53:e2:d1:ba:36:60:94: + 80:bb:61:63:6c:5b:17:7e:df:40:94:1e:ab:0d:c2: + 21:28:70:88:ff:d6:26:6c:6c:60:04:25:4e:55:7e: + 7d:ef:bf:94:48:de:b7:1d:dd:70:8d:05:5f:88:a5: + 9b:f2:c2:ee:ea:d1:40:41:6d:62:38:1d:56:06:c5: + 03:47:51:20:19:fc:7b:10:0b:0e:62:ae:76:55:bf: + 5f:77:be:3e:49:01:53:3d:98:25:03:76:24:5a:1d: + b4:db:89:ea:79:e5:b6:b3:3b:3f:ba:4c:28:41:7f: + 06:ac:6a:8e:c1:d0:f6:05:1d:7d:e6:42:86:e3:a5: + d5:47 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + C4:79:CA:8E:A1:4E:03:1D:1C:DC:6B:DB:31:5B:94:3E:3F:30:7F:2D + Signature Algorithm: sha256WithRSAEncryption + 2d:c5:13:cf:56:80:7b:7a:78:bd:9f:ae:2c:99:e7:ef:da:df: + 94:5e:09:69:a7:e7:6e:68:8c:bd:72:be:47:a9:0e:97:12:b8: + 4a:f1:64:d3:39:df:25:34:d4:c1:cd:4e:81:f0:0f:04:c4:24: + b3:34:96:c6:a6:aa:30:df:68:61:73:d7:f9:8e:85:89:ef:0e: + 5e:95:28:4a:2a:27:8f:10:8e:2e:7c:86:c4:02:9e:da:0c:77: + 65:0e:44:0d:92:fd:fd:b3:16:36:fa:11:0d:1d:8c:0e:07:89: + 6a:29:56:f7:72:f4:dd:15:9c:77:35:66:57:ab:13:53:d8:8e: + c1:40:c5:d7:13:16:5a:72:c7:b7:69:01:c4:7a:b1:83:01:68: + 7d:8d:41:a1:94:18:c1:25:5c:fc:f0:fe:83:02:87:7c:0d:0d: + cf:2e:08:5c:4a:40:0d:3e:ec:81:61:e6:24:db:ca:e0:0e:2d: + 07:b2:3e:56:dc:8d:f5:41:85:07:48:9b:0c:0b:cb:49:3f:7d: + ec:b7:fd:cb:8d:67:89:1a:ab:ed:bb:1e:a3:00:08:08:17:2a: + 82:5c:31:5d:46:8a:2d:0f:86:9b:74:d9:45:fb:d4:40:b1:7a: + aa:68:2d:86:b2:99:22:e1:c1:2b:c7:9c:f8:f3:5f:a8:82:12: + eb:19:11:2d +-----BEGIN CERTIFICATE----- +MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCB +mDELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsT +MChjKSAyMDA4IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s +eTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv +cml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIzNTk1OVowgZgxCzAJ +BgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg +MjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0 +BgNVBAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg +LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz ++uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5jK/BGvESyiaHAKAxJcCGVn2TAppMSAmUm +hsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdEc5IiaacDiGydY8hS2pgn +5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3CIShwiP/W +JmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exAL +DmKudlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZC +huOl1UcCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw +HQYDVR0OBBYEFMR5yo6hTgMdHNxr2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IB +AQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9cr5HqQ6XErhK8WTTOd8lNNTB +zU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbEAp7aDHdlDkQN +kv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD +AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUH +SJsMC8tJP33st/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2G +spki4cErx5z481+oghLrGREt +-----END CERTIFICATE----- + +thawte Primary Root CA - G2 +# Issuer: CN=thawte Primary Root CA - G2,OU="(c) 2007 thawte, Inc. - For authorized use only",O="thawte, Inc.",C=US +# Serial Number:35:fc:26:5c:d9:84:4f:c9:3d:26:3d:57:9b:ae:d7:56 +# Subject: CN=thawte Primary Root CA - G2,OU="(c) 2007 thawte, Inc. - For authorized use only",O="thawte, Inc.",C=US +# Not Valid Before: Mon Nov 05 00:00:00 2007 +# Not Valid After : Mon Jan 18 23:59:59 2038 +# Fingerprint (MD5): 74:9D:EA:60:24:C4:FD:22:53:3E:CC:3A:72:D9:29:4F +# Fingerprint (SHA1): AA:DB:BC:22:23:8F:C4:01:A1:27:BB:38:DD:F4:1D:DB:08:9E:F0:12 +TRUSTED_DELEGATOR: SERVER_AUTH +MUST_VERIFY_TRUST: EMAIL_PROTECTION, CODE_SIGNING +================================================= +MD5 Fingerprint=74:9D:EA:60:24:C4:FD:22:53:3E:CC:3A:72:D9:29:4F +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 35:fc:26:5c:d9:84:4f:c9:3d:26:3d:57:9b:ae:d7:56 + Signature Algorithm: ecdsa-with-SHA384 + Issuer: C=US, O=thawte, Inc., OU=(c) 2007 thawte, Inc. - For authorized use only, CN=thawte Primary Root CA - G2 + Validity + Not Before: Nov 5 00:00:00 2007 GMT + Not After : Jan 18 23:59:59 2038 GMT + Subject: C=US, O=thawte, Inc., OU=(c) 2007 thawte, Inc. - For authorized use only, CN=thawte Primary Root CA - G2 + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (384 bit) + pub: + 04:a2:d5:9c:82:7b:95:9d:f1:52:78:87:fe:8a:16: + bf:05:e6:df:a3:02:4f:0d:07:c6:00:51:ba:0c:02: + 52:2d:22:a4:42:39:c4:fe:8f:ea:c9:c1:be:d4:4d: + ff:9f:7a:9e:e2:b1:7c:9a:ad:a7:86:09:73:87:d1: + e7:9a:e3:7a:a5:aa:6e:fb:ba:b3:70:c0:67:88:a2: + 35:d4:a3:9a:b1:fd:ad:c2:ef:31:fa:a8:b9:f3:fb: + 08:c6:91:d1:fb:29:95 + ASN1 OID: secp384r1 + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 9A:D8:00:30:00:E7:6B:7F:85:18:EE:8B:B6:CE:8A:0C:F8:11:E1:BB + Signature Algorithm: ecdsa-with-SHA384 + 30:66:02:31:00:dd:f8:e0:57:47:5b:a7:e6:0a:c3:bd:f5:80: + 8a:97:35:0d:1b:89:3c:54:86:77:28:ca:a1:f4:79:de:b5:e6: + 38:b0:f0:65:70:8c:7f:02:54:c2:bf:ff:d8:a1:3e:d9:cf:02: + 31:00:c4:8d:94:fc:dc:53:d2:dc:9d:78:16:1f:15:33:23:53: + 52:e3:5a:31:5d:9d:ca:ae:bd:13:29:44:0d:27:5b:a8:e7:68: + 9c:12:f7:58:3f:2e:72:02:57:a3:8f:a1:14:2e +-----BEGIN CERTIFICATE----- +MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDEL +MAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMp +IDIwMDcgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAi +BgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMjAeFw0wNzExMDUwMDAw +MDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh +d3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBGb3Ig +YXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9v +dCBDQSAtIEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/ +BebfowJPDQfGAFG6DAJSLSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6 +papu+7qzcMBniKI11KOasf2twu8x+qi58/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8E +BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUmtgAMADna3+FGO6Lts6K +DPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUNG4k8VIZ3 +KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41ox +XZ3Krr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg== +-----END CERTIFICATE----- + +thawte Primary Root CA - G3 +# Issuer: CN=thawte Primary Root CA - G3,OU="(c) 2008 thawte, Inc. - For authorized use only",OU=Certification Services Division,O="thawte, Inc.",C=US +# Serial Number:60:01:97:b7:46:a7:ea:b4:b4:9a:d6:4b:2f:f7:90:fb +# Subject: CN=thawte Primary Root CA - G3,OU="(c) 2008 thawte, Inc. - For authorized use only",OU=Certification Services Division,O="thawte, Inc.",C=US +# Not Valid Before: Wed Apr 02 00:00:00 2008 +# Not Valid After : Tue Dec 01 23:59:59 2037 +# Fingerprint (MD5): FB:1B:5D:43:8A:94:CD:44:C6:76:F2:43:4B:47:E7:31 +# Fingerprint (SHA1): F1:8B:53:8D:1B:E9:03:B6:A6:F0:56:43:5B:17:15:89:CA:F3:6B:F2 +MUST_VERIFY_TRUST: EMAIL_PROTECTION, CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH +================================================= +MD5 Fingerprint=FB:1B:5D:43:8A:94:CD:44:C6:76:F2:43:4B:47:E7:31 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 60:01:97:b7:46:a7:ea:b4:b4:9a:d6:4b:2f:f7:90:fb + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=thawte, Inc., OU=Certification Services Division, OU=(c) 2008 thawte, Inc. - For authorized use only, CN=thawte Primary Root CA - G3 + Validity + Not Before: Apr 2 00:00:00 2008 GMT + Not After : Dec 1 23:59:59 2037 GMT + Subject: C=US, O=thawte, Inc., OU=Certification Services Division, OU=(c) 2008 thawte, Inc. - For authorized use only, CN=thawte Primary Root CA - G3 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:b2:bf:27:2c:fb:db:d8:5b:dd:78:7b:1b:9e:77: + 66:81:cb:3e:bc:7c:ae:f3:a6:27:9a:34:a3:68:31: + 71:38:33:62:e4:f3:71:66:79:b1:a9:65:a3:a5:8b: + d5:8f:60:2d:3f:42:cc:aa:6b:32:c0:23:cb:2c:41: + dd:e4:df:fc:61:9c:e2:73:b2:22:95:11:43:18:5f: + c4:b6:1f:57:6c:0a:05:58:22:c8:36:4c:3a:7c:a5: + d1:cf:86:af:88:a7:44:02:13:74:71:73:0a:42:59: + 02:f8:1b:14:6b:42:df:6f:5f:ba:6b:82:a2:9d:5b: + e7:4a:bd:1e:01:72:db:4b:74:e8:3b:7f:7f:7d:1f: + 04:b4:26:9b:e0:b4:5a:ac:47:3d:55:b8:d7:b0:26: + 52:28:01:31:40:66:d8:d9:24:bd:f6:2a:d8:ec:21: + 49:5c:9b:f6:7a:e9:7f:55:35:7e:96:6b:8d:93:93: + 27:cb:92:bb:ea:ac:40:c0:9f:c2:f8:80:cf:5d:f4: + 5a:dc:ce:74:86:a6:3e:6c:0b:53:ca:bd:92:ce:19: + 06:72:e6:0c:5c:38:69:c7:04:d6:bc:6c:ce:5b:f6: + f7:68:9c:dc:25:15:48:88:a1:e9:a9:f8:98:9c:e0: + f3:d5:31:28:61:11:6c:67:96:8d:39:99:cb:c2:45: + 24:39 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + AD:6C:AA:94:60:9C:ED:E4:FF:FA:3E:0A:74:2B:63:03:F7:B6:59:BF + Signature Algorithm: sha256WithRSAEncryption + 1a:40:d8:95:65:ac:09:92:89:c6:39:f4:10:e5:a9:0e:66:53: + 5d:78:de:fa:24:91:bb:e7:44:51:df:c6:16:34:0a:ef:6a:44: + 51:ea:2b:07:8a:03:7a:c3:eb:3f:0a:2c:52:16:a0:2b:43:b9: + 25:90:3f:70:a9:33:25:6d:45:1a:28:3b:27:cf:aa:c3:29:42: + 1b:df:3b:4c:c0:33:34:5b:41:88:bf:6b:2b:65:af:28:ef:b2: + f5:c3:aa:66:ce:7b:56:ee:b7:c8:cb:67:c1:c9:9c:1a:18:b8: + c4:c3:49:03:f1:60:0e:50:cd:46:c5:f3:77:79:f7:b6:15:e0: + 38:db:c7:2f:28:a0:0c:3f:77:26:74:d9:25:12:da:31:da:1a: + 1e:dc:29:41:91:22:3c:69:a7:bb:02:f2:b6:5c:27:03:89:f4: + 06:ea:9b:e4:72:82:e3:a1:09:c1:e9:00:19:d3:3e:d4:70:6b: + ba:71:a6:aa:58:ae:f4:bb:e9:6c:b6:ef:87:cc:9b:bb:ff:39: + e6:56:61:d3:0a:a7:c4:5c:4c:60:7b:05:77:26:7a:bf:d8:07: + 52:2c:62:f7:70:63:d9:39:bc:6f:1c:c2:79:dc:76:29:af:ce: + c5:2c:64:04:5e:88:36:6e:31:d4:40:1a:62:34:36:3f:35:01: + ae:ac:63:a0 +-----BEGIN CERTIFICATE----- +MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCB +rjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf +Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw +MDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNV +BAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0wODA0MDIwMDAwMDBa +Fw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhhd3Rl +LCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9u +MTgwNgYDVQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXpl +ZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEcz +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsr8nLPvb2FvdeHsbnndm +gcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2AtP0LMqmsywCPLLEHd5N/8 +YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC+BsUa0Lf +b1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS9 +9irY7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2S +zhkGcuYMXDhpxwTWvGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUk +OQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNV +HQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJKoZIhvcNAQELBQADggEBABpA +2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweKA3rD6z8KLFIW +oCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu +t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7c +KUGRIjxpp7sC8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fM +m7v/OeZWYdMKp8RcTGB7BXcmer/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZu +MdRAGmI0Nj81Aa6sY6A= +-----END CERTIFICATE----- + +GeoTrust Primary Certification Authority - G2 +# Issuer: CN=GeoTrust Primary Certification Authority - G2,OU=(c) 2007 GeoTrust Inc. - For authorized use only,O=GeoTrust Inc.,C=US +# Serial Number:3c:b2:f4:48:0a:00:e2:fe:eb:24:3b:5e:60:3e:c3:6b +# Subject: CN=GeoTrust Primary Certification Authority - G2,OU=(c) 2007 GeoTrust Inc. - For authorized use only,O=GeoTrust Inc.,C=US +# Not Valid Before: Mon Nov 05 00:00:00 2007 +# Not Valid After : Mon Jan 18 23:59:59 2038 +# Fingerprint (MD5): 01:5E:D8:6B:BD:6F:3D:8E:A1:31:F8:12:E0:98:73:6A +# Fingerprint (SHA1): 8D:17:84:D5:37:F3:03:7D:EC:70:FE:57:8B:51:9A:99:E6:10:D7:B0 +MUST_VERIFY_TRUST: CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +================================================ +MD5 Fingerprint=01:5E:D8:6B:BD:6F:3D:8E:A1:31:F8:12:E0:98:73:6A +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 3c:b2:f4:48:0a:00:e2:fe:eb:24:3b:5e:60:3e:c3:6b + Signature Algorithm: ecdsa-with-SHA384 + Issuer: C=US, O=GeoTrust Inc., OU=(c) 2007 GeoTrust Inc. - For authorized use only, CN=GeoTrust Primary Certification Authority - G2 + Validity + Not Before: Nov 5 00:00:00 2007 GMT + Not After : Jan 18 23:59:59 2038 GMT + Subject: C=US, O=GeoTrust Inc., OU=(c) 2007 GeoTrust Inc. - For authorized use only, CN=GeoTrust Primary Certification Authority - G2 + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (384 bit) + pub: + 04:15:b1:e8:fd:03:15:43:e5:ac:eb:87:37:11:62: + ef:d2:83:36:52:7d:45:57:0b:4a:8d:7b:54:3b:3a: + 6e:5f:15:02:c0:50:a6:cf:25:2f:7d:ca:48:b8:c7: + 50:63:1c:2a:21:08:7c:9a:36:d8:0b:fe:d1:26:c5: + 58:31:30:28:25:f3:5d:5d:a3:b8:b6:a5:b4:92:ed: + 6c:2c:9f:eb:dd:43:89:a2:3c:4b:48:91:1d:50:ec: + 26:df:d6:60:2e:bd:21 + ASN1 OID: secp384r1 + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 15:5F:35:57:51:55:FB:25:B2:AD:03:69:FC:01:A3:FA:BE:11:55:D5 + Signature Algorithm: ecdsa-with-SHA384 + 30:64:02:30:64:96:59:a6:e8:09:de:8b:ba:fa:5a:88:88:f0: + 1f:91:d3:46:a8:f2:4a:4c:02:63:fb:6c:5f:38:db:2e:41:93: + a9:0e:e6:9d:dc:31:1c:b2:a0:a7:18:1c:79:e1:c7:36:02:30: + 3a:56:af:9a:74:6c:f6:fb:83:e0:33:d3:08:5f:a1:9c:c2:5b: + 9f:46:d6:b6:cb:91:06:63:a2:06:e7:33:ac:3e:a8:81:12:d0: + cb:ba:d0:92:0b:b6:9e:96:aa:04:0f:8a +-----BEGIN CERTIFICATE----- +MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDEL +MAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChj +KSAyMDA3IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2 +MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 +eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1OVowgZgxCzAJBgNV +BAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykgMjAw +NyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNV +BAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBH +MjB2MBAGByqGSM49AgEGBSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcL +So17VDs6bl8VAsBQps8lL33KSLjHUGMcKiEIfJo22Av+0SbFWDEwKCXzXV2juLal +tJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO +BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+EVXVMAoG +CCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGT +qQ7mndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBucz +rD6ogRLQy7rQkgu2npaqBA+K +-----END CERTIFICATE----- + +VeriSign Universal Root Certification Authority +# Issuer: CN=VeriSign Universal Root Certification Authority,OU="(c) 2008 VeriSign, Inc. - For authorized use only",OU=VeriSign Trust Network,O="VeriSign, Inc.",C=US +# Serial Number:40:1a:c4:64:21:b3:13:21:03:0e:bb:e4:12:1a:c5:1d +# Subject: CN=VeriSign Universal Root Certification Authority,OU="(c) 2008 VeriSign, Inc. - For authorized use only",OU=VeriSign Trust Network,O="VeriSign, Inc.",C=US +# Not Valid Before: Wed Apr 02 00:00:00 2008 +# Not Valid After : Tue Dec 01 23:59:59 2037 +# Fingerprint (MD5): 8E:AD:B5:01:AA:4D:81:E4:8C:1D:D1:E1:14:00:95:19 +# Fingerprint (SHA1): 36:79:CA:35:66:87:72:30:4D:30:A5:FB:87:3B:0F:A7:7B:B7:0D:54 +MUST_VERIFY_TRUST: CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +================================================ +MD5 Fingerprint=8E:AD:B5:01:AA:4D:81:E4:8C:1D:D1:E1:14:00:95:19 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 40:1a:c4:64:21:b3:13:21:03:0e:bb:e4:12:1a:c5:1d + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 2008 VeriSign, Inc. - For authorized use only, CN=VeriSign Universal Root Certification Authority + Validity + Not Before: Apr 2 00:00:00 2008 GMT + Not After : Dec 1 23:59:59 2037 GMT + Subject: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 2008 VeriSign, Inc. - For authorized use only, CN=VeriSign Universal Root Certification Authority + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:c7:61:37:5e:b1:01:34:db:62:d7:15:9b:ff:58: + 5a:8c:23:23:d6:60:8e:91:d7:90:98:83:7a:e6:58: + 19:38:8c:c5:f6:e5:64:85:b4:a2:71:fb:ed:bd:b9: + da:cd:4d:00:b4:c8:2d:73:a5:c7:69:71:95:1f:39: + 3c:b2:44:07:9c:e8:0e:fa:4d:4a:c4:21:df:29:61: + 8f:32:22:61:82:c5:87:1f:6e:8c:7c:5f:16:20:51: + 44:d1:70:4f:57:ea:e3:1c:e3:cc:79:ee:58:d8:0e: + c2:b3:45:93:c0:2c:e7:9a:17:2b:7b:00:37:7a:41: + 33:78:e1:33:e2:f3:10:1a:7f:87:2c:be:f6:f5:f7: + 42:e2:e5:bf:87:62:89:5f:00:4b:df:c5:dd:e4:75: + 44:32:41:3a:1e:71:6e:69:cb:0b:75:46:08:d1:ca: + d2:2b:95:d0:cf:fb:b9:40:6b:64:8c:57:4d:fc:13: + 11:79:84:ed:5e:54:f6:34:9f:08:01:f3:10:25:06: + 17:4a:da:f1:1d:7a:66:6b:98:60:66:a4:d9:ef:d2: + 2e:82:f1:f0:ef:09:ea:44:c9:15:6a:e2:03:6e:33: + d3:ac:9f:55:00:c7:f6:08:6a:94:b9:5f:dc:e0:33: + f1:84:60:f9:5b:27:11:b4:fc:16:f2:bb:56:6a:80: + 25:8d + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + 1.3.6.1.5.5.7.1.12: + 0_.].[0Y0W0U..image/gif0!0.0...+..............k...j.H.,{..0%.#http://logo.verisign.com/vslogo.gif + X509v3 Subject Key Identifier: + B6:77:FA:69:48:47:9F:53:12:D5:C2:EA:07:32:76:07:D1:97:07:19 + Signature Algorithm: sha256WithRSAEncryption + 4a:f8:f8:b0:03:e6:2c:67:7b:e4:94:77:63:cc:6e:4c:f9:7d: + 0e:0d:dc:c8:b9:35:b9:70:4f:63:fa:24:fa:6c:83:8c:47:9d: + 3b:63:f3:9a:f9:76:32:95:91:b1:77:bc:ac:9a:be:b1:e4:31: + 21:c6:81:95:56:5a:0e:b1:c2:d4:b1:a6:59:ac:f1:63:cb:b8: + 4c:1d:59:90:4a:ef:90:16:28:1f:5a:ae:10:fb:81:50:38:0c: + 6c:cc:f1:3d:c3:f5:63:e3:b3:e3:21:c9:24:39:e9:fd:15:66: + 46:f4:1b:11:d0:4d:73:a3:7d:46:f9:3d:ed:a8:5f:62:d4:f1: + 3f:f8:e0:74:57:2b:18:9d:81:b4:c4:28:da:94:97:a5:70:eb: + ac:1d:be:07:11:f0:d5:db:dd:e5:8c:f0:d5:32:b0:83:e6:57: + e2:8f:bf:be:a1:aa:bf:3d:1d:b5:d4:38:ea:d7:b0:5c:3a:4f: + 6a:3f:8f:c0:66:6c:63:aa:e9:d9:a4:16:f4:81:d1:95:14:0e: + 7d:cd:95:34:d9:d2:8f:70:73:81:7b:9c:7e:bd:98:61:d8:45: + 87:98:90:c5:eb:86:30:c6:35:bf:f0:ff:c3:55:88:83:4b:ef: + 05:92:06:71:f2:b8:98:93:b7:ec:cd:82:61:f1:38:e6:4f:97: + 98:2a:5a:8d +-----BEGIN CERTIFICATE----- +MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCB +vTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL +ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJp +U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MTgwNgYDVQQDEy9W +ZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe +Fw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJVUzEX +MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0 +IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9y +IGF1dGhvcml6ZWQgdXNlIG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNh +bCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj1mCOkdeQmIN65lgZOIzF +9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGPMiJhgsWH +H26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+H +LL729fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN +/BMReYTtXlT2NJ8IAfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPT +rJ9VAMf2CGqUuV/c4DPxhGD5WycRtPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1Ud +EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0GCCsGAQUFBwEMBGEwX6FdoFsw +WTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2Oa8PPgGrUSBgs +exkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud +DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4 +sAPmLGd75JR3Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+ +seQxIcaBlVZaDrHC1LGmWazxY8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz +4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTxP/jgdFcrGJ2BtMQo2pSXpXDrrB2+ +BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+PwGZsY6rp2aQW9IHR +lRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4mJO3 +7M2CYfE45k+XmCpajQ== +-----END CERTIFICATE----- + +VeriSign Class 3 Public Primary Certification Authority - G4 +# Issuer: CN=VeriSign Class 3 Public Primary Certification Authority - G4,OU="(c) 2007 VeriSign, Inc. - For authorized use only",OU=VeriSign Trust Network,O="VeriSign, Inc.",C=US +# Serial Number:2f:80:fe:23:8c:0e:22:0f:48:67:12:28:91:87:ac:b3 +# Subject: CN=VeriSign Class 3 Public Primary Certification Authority - G4,OU="(c) 2007 VeriSign, Inc. - For authorized use only",OU=VeriSign Trust Network,O="VeriSign, Inc.",C=US +# Not Valid Before: Mon Nov 05 00:00:00 2007 +# Not Valid After : Mon Jan 18 23:59:59 2038 +# Fingerprint (MD5): 3A:52:E1:E7:FD:6F:3A:E3:6F:F3:6F:99:1B:F9:22:41 +# Fingerprint (SHA1): 22:D5:D8:DF:8F:02:31:D1:8D:F7:9D:B7:CF:8A:2D:64:C9:3F:6C:3A +MUST_VERIFY_TRUST: CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +============================================================ +MD5 Fingerprint=3A:52:E1:E7:FD:6F:3A:E3:6F:F3:6F:99:1B:F9:22:41 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 2f:80:fe:23:8c:0e:22:0f:48:67:12:28:91:87:ac:b3 + Signature Algorithm: ecdsa-with-SHA384 + Issuer: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 2007 VeriSign, Inc. - For authorized use only, CN=VeriSign Class 3 Public Primary Certification Authority - G4 + Validity + Not Before: Nov 5 00:00:00 2007 GMT + Not After : Jan 18 23:59:59 2038 GMT + Subject: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 2007 VeriSign, Inc. - For authorized use only, CN=VeriSign Class 3 Public Primary Certification Authority - G4 + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (384 bit) + pub: + 04:a7:56:7a:7c:52:da:64:9b:0e:2d:5c:d8:5e:ac: + 92:3d:fe:01:e6:19:4a:3d:14:03:4b:fa:60:27:20: + d9:83:89:69:fa:54:c6:9a:18:5e:55:2a:64:de:06: + f6:8d:4a:3b:ad:10:3c:65:3d:90:88:04:89:e0:30: + 61:b3:ae:5d:01:a7:7b:de:7c:b2:be:ca:65:61:00: + 86:ae:da:8f:7b:d0:89:ad:4d:1d:59:9a:41:b1:bc: + 47:80:dc:9e:62:c3:f9 + ASN1 OID: secp384r1 + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + 1.3.6.1.5.5.7.1.12: + 0_.].[0Y0W0U..image/gif0!0.0...+..............k...j.H.,{..0%.#http://logo.verisign.com/vslogo.gif + X509v3 Subject Key Identifier: + B3:16:91:FD:EE:A6:6E:E4:B5:2E:49:8F:87:78:81:80:EC:E5:B1:B5 + Signature Algorithm: ecdsa-with-SHA384 + 30:65:02:30:66:21:0c:18:26:60:5a:38:7b:56:42:e0:a7:fc: + 36:84:51:91:20:2c:76:4d:43:3d:c4:1d:84:23:d0:ac:d6:7c: + 35:06:ce:cd:69:bd:90:0d:db:6c:48:42:1d:0e:aa:42:02:31: + 00:9c:3d:48:39:23:39:58:1a:15:12:59:6a:9e:ef:d5:59:b2: + 1d:52:2c:99:71:cd:c7:29:df:1b:2a:61:7b:71:d1:de:f3:c0: + e5:0d:3a:4a:aa:2d:a7:d8:86:2a:dd:2e:10 +-----BEGIN CERTIFICATE----- +MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjEL +MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW +ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2ln +biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp +U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y +aXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjELMAkG +A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJp +U2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwg +SW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2ln +biBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8Utpkmw4tXNherJI9/gHm +GUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGzrl0Bp3ve +fLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUw +AwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJ +aW1hZ2UvZ2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYj +aHR0cDovL2xvZ28udmVyaXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMW +kf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMDA2gAMGUCMGYhDBgmYFo4e1ZC +4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIxAJw9SDkjOVga +FRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA== +-----END CERTIFICATE----- + +NetLock Arany (Class Gold) Főtanúsítvány +# Issuer: CN=NetLock Arany (Class Gold) F..tan..s..tv..ny,OU=Tan..s..tv..nykiad..k (Certification Services),O=NetLock Kft.,L=Budapest,C=HU +# Serial Number:49:41:2c:e4:00:10 +# Subject: CN=NetLock Arany (Class Gold) F..tan..s..tv..ny,OU=Tan..s..tv..nykiad..k (Certification Services),O=NetLock Kft.,L=Budapest,C=HU +# Not Valid Before: Thu Dec 11 15:08:21 2008 +# Not Valid After : Wed Dec 06 15:08:21 2028 +# Fingerprint (MD5): C5:A1:B7:FF:73:DD:D6:D7:34:32:18:DF:FC:3C:AD:88 +# Fingerprint (SHA1): 06:08:3F:59:3F:15:A1:04:A0:69:A4:6B:A9:03:D0:06:B7:97:09:91 +MUST_VERIFY_TRUST: CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +================================================ +MD5 Fingerprint=C5:A1:B7:FF:73:DD:D6:D7:34:32:18:DF:FC:3C:AD:88 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 80544274841616 (0x49412ce40010) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=HU, L=Budapest, O=NetLock Kft., OU=Tan\xC3\xBAs\xC3\xADtv\xC3\xA1nykiad\xC3\xB3k (Certification Services), CN=NetLock Arany (Class Gold) F\xC5\x91tan\xC3\xBAs\xC3\xADtv\xC3\xA1ny + Validity + Not Before: Dec 11 15:08:21 2008 GMT + Not After : Dec 6 15:08:21 2028 GMT + Subject: C=HU, L=Budapest, O=NetLock Kft., OU=Tan\xC3\xBAs\xC3\xADtv\xC3\xA1nykiad\xC3\xB3k (Certification Services), CN=NetLock Arany (Class Gold) F\xC5\x91tan\xC3\xBAs\xC3\xADtv\xC3\xA1ny + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:c4:24:5e:73:be:4b:6d:14:c3:a1:f4:e3:97:90: + 6e:d2:30:45:1e:3c:ee:67:d9:64:e0:1a:8a:7f:ca: + 30:ca:83:e3:20:c1:e3:f4:3a:d3:94:5f:1a:7c:5b: + 6d:bf:30:4f:84:27:f6:9f:1f:49:bc:c6:99:0a:90: + f2:0f:f5:7f:43:84:37:63:51:8b:7a:a5:70:fc:7a: + 58:cd:8e:9b:ed:c3:46:6c:84:70:5d:da:f3:01:90: + 23:fc:4e:30:a9:7e:e1:27:63:e7:ed:64:3c:a0:b8: + c9:33:63:fe:16:90:ff:b0:b8:fd:d7:a8:c0:c0:94: + 43:0b:b6:d5:59:a6:9e:56:d0:24:1f:70:79:af:db: + 39:54:0d:65:75:d9:15:41:94:01:af:5e:ec:f6:8d: + f1:ff:ad:64:fe:20:9a:d7:5c:eb:fe:a6:1f:08:64: + a3:8b:76:55:ad:1e:3b:28:60:2e:87:25:e8:aa:af: + 1f:c6:64:46:20:b7:70:7f:3c:de:48:db:96:53:b7: + 39:77:e4:1a:e2:c7:16:84:76:97:5b:2f:bb:19:15: + 85:f8:69:85:f5:99:a7:a9:f2:34:a7:a9:b6:a6:03: + fc:6f:86:3d:54:7c:76:04:9b:6b:f9:40:5d:00:34: + c7:2e:99:75:9d:e5:88:03:aa:4d:f8:03:d2:42:76: + c0:1b + Exponent: 43147 (0xa88b) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:4 + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + CC:FA:67:93:F0:B6:B8:D0:A5:C0:1E:F3:53:FD:8C:53:DF:83:D7:96 + Signature Algorithm: sha256WithRSAEncryption + ab:7f:ee:1c:16:a9:9c:3c:51:00:a0:c0:11:08:05:a7:99:e6: + 6f:01:88:54:61:6e:f1:b9:18:ad:4a:ad:fe:81:40:23:94:2f: + fb:75:7c:2f:28:4b:62:24:81:82:0b:f5:61:f1:1c:6e:b8:61: + 38:eb:81:fa:62:a1:3b:5a:62:d3:94:65:c4:e1:e6:6d:82:f8: + 2f:25:70:b2:21:26:c1:72:51:1f:8c:2c:c3:84:90:c3:5a:8f: + ba:cf:f4:a7:65:a5:eb:98:d1:fb:05:b2:46:75:15:23:6a:6f: + 85:63:30:80:f0:d5:9e:1f:29:1c:c2:6c:b0:50:59:5d:90:5b: + 3b:a8:0d:30:cf:bf:7d:7f:ce:f1:9d:83:bd:c9:46:6e:20:a6: + f9:61:51:ba:21:2f:7b:be:a5:15:63:a1:d4:95:87:f1:9e:b9: + f3:89:f3:3d:85:b8:b8:db:be:b5:b9:29:f9:da:37:05:00:49: + 94:03:84:44:e7:bf:43:31:cf:75:8b:25:d1:f4:a6:64:f5:92: + f6:ab:05:eb:3d:e9:a5:0b:36:62:da:cc:06:5f:36:8b:b6:5e: + 31:b8:2a:fb:5e:f6:71:df:44:26:9e:c4:e6:0d:91:b4:2e:75: + 95:80:51:6a:4b:30:a6:b0:62:a1:93:f1:9b:d8:ce:c4:63:75: + 3f:59:47:b1 +-----BEGIN CERTIFICATE----- +MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQG +EwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3 +MDUGA1UECwwuVGFuw7pzw610dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNl +cnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBBcmFueSAoQ2xhc3MgR29sZCkgRsWR +dGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgxMjA2MTUwODIxWjCB +pzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxOZXRM +b2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlm +aWNhdGlvbiBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNz +IEdvbGQpIEbFkXRhbsO6c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAxCRec75LbRTDofTjl5Bu0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrT +lF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw/HpYzY6b7cNGbIRwXdrz +AZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAkH3B5r9s5 +VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRG +ILdwfzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2 +BJtr+UBdADTHLpl1neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAG +AQH/AgEEMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2M +U9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwWqZw8UQCgwBEIBaeZ5m8BiFRh +bvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTtaYtOUZcTh5m2C ++C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC +bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2F +uLjbvrW5KfnaNwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2 +XjG4Kvte9nHfRCaexOYNkbQudZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E= +-----END CERTIFICATE----- + +Staat der Nederlanden Root CA - G2 +# Issuer: CN=Staat der Nederlanden Root CA - G2,O=Staat der Nederlanden,C=NL +# Serial Number: 10000012 (0x98968c) +# Subject: CN=Staat der Nederlanden Root CA - G2,O=Staat der Nederlanden,C=NL +# Not Valid Before: Wed Mar 26 11:18:17 2008 +# Not Valid After : Wed Mar 25 11:03:10 2020 +# Fingerprint (MD5): 7C:A5:0F:F8:5B:9A:7D:6D:30:AE:54:5A:E3:42:A2:8A +# Fingerprint (SHA1): 59:AF:82:79:91:86:C7:B4:75:07:CB:CF:03:57:46:EB:04:DD:B7:16 +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +MUST_VERIFY_TRUST: CODE_SIGNING +================================================ +MD5 Fingerprint=7C:A5:0F:F8:5B:9A:7D:6D:30:AE:54:5A:E3:42:A2:8A +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 10000012 (0x98968c) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=NL, O=Staat der Nederlanden, CN=Staat der Nederlanden Root CA - G2 + Validity + Not Before: Mar 26 11:18:17 2008 GMT + Not After : Mar 25 11:03:10 2020 GMT + Subject: C=NL, O=Staat der Nederlanden, CN=Staat der Nederlanden Root CA - G2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:c5:59:e7:6f:75:aa:3e:4b:9c:b5:b8:ac:9e:0b: + e4:f9:d9:ca:ab:5d:8f:b5:39:10:82:d7:af:51:e0: + 3b:e1:00:48:6a:cf:da:e1:06:43:11:99:aa:14:25: + 12:ad:22:e8:00:6d:43:c4:a9:b8:e5:1f:89:4b:67: + bd:61:48:ef:fd:d2:e0:60:88:e5:b9:18:60:28:c3: + 77:2b:ad:b0:37:aa:37:de:64:59:2a:46:57:e4:4b: + b9:f8:37:7c:d5:36:e7:80:c1:b6:f3:d4:67:9b:96: + e8:ce:d7:c6:0a:53:d0:6b:49:96:f3:a3:0b:05:77: + 48:f7:25:e5:70:ac:30:14:20:25:e3:7f:75:5a:e5: + 48:f8:4e:7b:03:07:04:fa:82:61:87:6e:f0:3b:c4: + a4:c7:d0:f5:74:3e:a5:5d:1a:08:f2:9b:25:d2:f6: + ac:04:26:3e:55:3a:62:28:a5:7b:b2:30:af:f8:37: + c2:d1:ba:d6:38:fd:f4:ef:49:30:37:99:26:21:48: + 85:01:a9:e5:16:e7:dc:90:55:df:0f:e8:38:cd:99: + 37:21:4f:5d:f5:22:6f:6a:c5:12:16:60:17:55:f2: + 65:66:a6:a7:30:91:38:c1:38:1d:86:04:84:ba:1a: + 25:78:5e:9d:af:cc:50:60:d6:13:87:52:ed:63:1f: + 6d:65:7d:c2:15:18:74:ca:e1:7e:64:29:8c:72:d8: + 16:13:7d:0b:49:4a:f1:28:1b:20:74:6b:c5:3d:dd: + b0:aa:48:09:3d:2e:82:94:cd:1a:65:d9:2b:88:9a: + 99:bc:18:7e:9f:ee:7d:66:7c:3e:bd:94:b8:81:ce: + cd:98:30:78:c1:6f:67:d0:be:5f:e0:68:ed:de:e2: + b1:c9:2c:59:78:92:aa:df:2b:60:63:f2:e5:5e:b9: + e3:ca:fa:7f:50:86:3e:a2:34:18:0c:09:68:28:11: + 1c:e4:e1:b9:5c:3e:47:ba:32:3f:18:cc:5b:84:f5: + f3:6b:74:c4:72:74:e1:e3:8b:a0:4a:bd:8d:66:2f: + ea:ad:35:da:20:d3:88:82:61:f0:12:22:b6:bc:d0: + d5:a4:ec:af:54:88:25:24:3c:a7:6d:b1:72:29:3f: + 3e:57:a6:7f:55:af:6e:26:c6:fe:e7:cc:40:5c:51: + 44:81:0a:78:de:4a:ce:55:bf:1d:d5:d9:b7:56:ef: + f0:76:ff:0b:79:b5:af:bd:fb:a9:69:91:46:97:68: + 80:14:36:1d:b3:7f:bb:29:98:36:a5:20:fa:82:60: + 62:33:a4:ec:d6:ba:07:a7:6e:c5:cf:14:a6:e7:d6: + 92:34:d8:81:f5:fc:1d:5d:aa:5c:1e:f6:a3:4d:3b: + b8:f7:39 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: http://www.pkioverheid.nl/policies/root-policy-G2 + + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 91:68:32:87:15:1D:89:E2:B5:F1:AC:36:28:34:8D:0B:7C:62:88:EB + Signature Algorithm: sha256WithRSAEncryption + a8:41:4a:67:2a:92:81:82:50:6e:e1:d7:d8:b3:39:3b:f3:02: + 15:09:50:51:ef:2d:bd:24:7b:88:86:3b:f9:b4:bc:92:09:96: + b9:f6:c0:ab:23:60:06:79:8c:11:4e:51:d2:79:80:33:fb:9d: + 48:be:ec:41:43:81:1f:7e:47:40:1c:e5:7a:08:ca:aa:8b:75: + ad:14:c4:c2:e8:66:3c:82:07:a7:e6:27:82:5b:18:e6:0f:6e: + d9:50:3e:8a:42:18:29:c6:b4:56:fc:56:10:a0:05:17:bd:0c: + 23:7f:f4:93:ed:9c:1a:51:be:dd:45:41:bf:91:24:b4:1f:8c: + e9:5f:cf:7b:21:99:9f:95:9f:39:3a:46:1c:6c:f9:cd:7b:9c: + 90:cd:28:a9:c7:a9:55:bb:ac:62:34:62:35:13:4b:14:3a:55: + 83:b9:86:8d:92:a6:c6:f4:07:25:54:cc:16:57:12:4a:82:78: + c8:14:d9:17:82:26:2d:5d:20:1f:79:ae:fe:d4:70:16:16:95: + 83:d8:35:39:ff:52:5d:75:1c:16:c5:13:55:cf:47:cc:75:65: + 52:4a:de:f0:b0:a7:e4:0a:96:0b:fb:ad:c2:e2:25:84:b2:dd: + e4:bd:7e:59:6c:9b:f0:f0:d8:e7:ca:f2:e9:97:38:7e:89:be: + cc:fb:39:17:61:3f:72:db:3a:91:d8:65:01:19:1d:ad:50:a4: + 57:0a:7c:4b:bc:9c:71:73:2a:45:51:19:85:cc:8e:fd:47:a7: + 74:95:1d:a8:d1:af:4e:17:b1:69:26:c2:aa:78:57:5b:c5:4d: + a7:e5:9e:05:17:94:ca:b2:5f:a0:49:18:8d:34:e9:26:6c:48: + 1e:aa:68:92:05:e1:82:73:5a:9b:dc:07:5b:08:6d:7d:9d:d7: + 8d:21:d9:fc:14:20:aa:c2:45:df:3f:e7:00:b2:51:e4:c2:f8: + 05:b9:79:1a:8c:34:f3:9e:5b:e4:37:5b:6b:4a:df:2c:57:8a: + 40:5a:36:ba:dd:75:44:08:37:42:70:0c:fe:dc:5e:21:a0:a3: + 8a:c0:90:9c:68:da:50:e6:45:10:47:78:b6:4e:d2:65:c9:c3: + 37:df:e1:42:63:b0:57:37:45:2d:7b:8a:9c:bf:05:ea:65:55: + 33:f7:39:10:c5:28:2a:21:7a:1b:8a:c4:24:f9:3f:15:c8:9a: + 15:20:f5:55:62:96:ed:6d:93:50:bc:e4:aa:78:ad:d9:cb:0a: + 65:87:a6:66:c1:c4:81:a3:77:3a:58:1e:0b:ee:83:8b:9d:1e: + d2:52:a4:cc:1d:6f:b0:98:6d:94:31:b5:f8:71:0a:dc:b9:fc: + 7d:32:60:e6:eb:af:8a:01 +-----BEGIN CERTIFICATE----- +MIIFyjCCA7KgAwIBAgIEAJiWjDANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJO +TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFh +dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQSAtIEcyMB4XDTA4MDMyNjExMTgxN1oX +DTIwMDMyNTExMDMxMFowWjELMAkGA1UEBhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRl +ciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5lZGVybGFuZGVuIFJv +b3QgQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMVZ5291 +qj5LnLW4rJ4L5PnZyqtdj7U5EILXr1HgO+EASGrP2uEGQxGZqhQlEq0i6ABtQ8Sp +uOUfiUtnvWFI7/3S4GCI5bkYYCjDdyutsDeqN95kWSpGV+RLufg3fNU254DBtvPU +Z5uW6M7XxgpT0GtJlvOjCwV3SPcl5XCsMBQgJeN/dVrlSPhOewMHBPqCYYdu8DvE +pMfQ9XQ+pV0aCPKbJdL2rAQmPlU6Yiile7Iwr/g3wtG61jj99O9JMDeZJiFIhQGp +5Rbn3JBV3w/oOM2ZNyFPXfUib2rFEhZgF1XyZWampzCROME4HYYEhLoaJXhena/M +UGDWE4dS7WMfbWV9whUYdMrhfmQpjHLYFhN9C0lK8SgbIHRrxT3dsKpICT0ugpTN +GmXZK4iambwYfp/ufWZ8Pr2UuIHOzZgweMFvZ9C+X+Bo7d7iscksWXiSqt8rYGPy +5V6548r6f1CGPqI0GAwJaCgRHOThuVw+R7oyPxjMW4T182t0xHJ04eOLoEq9jWYv +6q012iDTiIJh8BIitrzQ1aTsr1SIJSQ8p22xcik/Plemf1WvbibG/ufMQFxRRIEK +eN5KzlW/HdXZt1bv8Hb/C3m1r737qWmRRpdogBQ2HbN/uymYNqUg+oJgYjOk7Na6 +B6duxc8UpufWkjTYgfX8HV2qXB72o007uPc5AgMBAAGjgZcwgZQwDwYDVR0TAQH/ +BAUwAwEB/zBSBgNVHSAESzBJMEcGBFUdIAAwPzA9BggrBgEFBQcCARYxaHR0cDov +L3d3dy5wa2lvdmVyaGVpZC5ubC9wb2xpY2llcy9yb290LXBvbGljeS1HMjAOBgNV +HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJFoMocVHYnitfGsNig0jQt8YojrMA0GCSqG +SIb3DQEBCwUAA4ICAQCoQUpnKpKBglBu4dfYszk78wIVCVBR7y29JHuIhjv5tLyS +CZa59sCrI2AGeYwRTlHSeYAz+51IvuxBQ4EffkdAHOV6CMqqi3WtFMTC6GY8ggen +5ieCWxjmD27ZUD6KQhgpxrRW/FYQoAUXvQwjf/ST7ZwaUb7dRUG/kSS0H4zpX897 +IZmflZ85OkYcbPnNe5yQzSipx6lVu6xiNGI1E0sUOlWDuYaNkqbG9AclVMwWVxJK +gnjIFNkXgiYtXSAfea7+1HAWFpWD2DU5/1JddRwWxRNVz0fMdWVSSt7wsKfkCpYL ++63C4iWEst3kvX5ZbJvw8NjnyvLplzh+ib7M+zkXYT9y2zqR2GUBGR2tUKRXCnxL +vJxxcypFURmFzI79R6d0lR2o0a9OF7FpJsKqeFdbxU2n5Z4FF5TKsl+gSRiNNOkm +bEgeqmiSBeGCc1qb3AdbCG19ndeNIdn8FCCqwkXfP+cAslHkwvgFuXkajDTznlvk +N1trSt8sV4pAWja63XVECDdCcAz+3F4hoKOKwJCcaNpQ5kUQR3i2TtJlycM33+FC +Y7BXN0Ute4qcvwXqZVUz9zkQxSgqIXobisQk+T8VyJoVIPVVYpbtbZNQvOSqeK3Z +ywplh6ZmwcSBo3c6WB4L7oOLnR7SUqTMHW+wmG2UMbX4cQrcufx9MmDm66+KAQ== +-----END CERTIFICATE----- + +Hongkong Post Root CA 1 +# Issuer: CN=Hongkong Post Root CA 1,O=Hongkong Post,C=HK +# Serial Number: 1000 (0x3e8) +# Subject: CN=Hongkong Post Root CA 1,O=Hongkong Post,C=HK +# Not Valid Before: Thu May 15 05:13:14 2003 +# Not Valid After : Mon May 15 04:52:29 2023 +# Fingerprint (MD5): A8:0D:6F:39:78:B9:43:6D:77:42:6D:98:5A:CC:23:CA +# Fingerprint (SHA1): D6:DA:A8:20:8D:09:D2:15:4D:24:B5:2F:CB:34:6E:B2:58:B2:8A:58 +TRUSTED_DELEGATOR: SERVER_AUTH +MUST_VERIFY_TRUST: EMAIL_PROTECTION, CODE_SIGNING +================================================= +MD5 Fingerprint=A8:0D:6F:39:78:B9:43:6D:77:42:6D:98:5A:CC:23:CA +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 1000 (0x3e8) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=HK, O=Hongkong Post, CN=Hongkong Post Root CA 1 + Validity + Not Before: May 15 05:13:14 2003 GMT + Not After : May 15 04:52:29 2023 GMT + Subject: C=HK, O=Hongkong Post, CN=Hongkong Post Root CA 1 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:ac:ff:38:b6:e9:66:02:49:e3:a2:b4:e1:90:f9: + 40:8f:79:f9:e2:bd:79:fe:02:bd:ee:24:92:1d:22: + f6:da:85:72:69:fe:d7:3f:09:d4:dd:91:b5:02:9c: + d0:8d:5a:e1:55:c3:50:86:b9:29:26:c2:e3:d9:a0: + f1:69:03:28:20:80:45:22:2d:56:a7:3b:54:95:56: + 22:59:1f:28:df:1f:20:3d:6d:a2:36:be:23:a0:b1: + 6e:b5:b1:27:3f:39:53:09:ea:ab:6a:e8:74:b2:c2: + 65:5c:8e:bf:7c:c3:78:84:cd:9e:16:fc:f5:2e:4f: + 20:2a:08:9f:77:f3:c5:1e:c4:9a:52:66:1e:48:5e: + e3:10:06:8f:22:98:e1:65:8e:1b:5d:23:66:3b:b8: + a5:32:51:c8:86:aa:a1:a9:9e:7f:76:94:c2:a6:6c: + b7:41:f0:d5:c8:06:38:e6:d4:0c:e2:f3:3b:4c:6d: + 50:8c:c4:83:27:c1:13:84:59:3d:9e:75:74:b6:d8: + 02:5e:3a:90:7a:c0:42:36:72:ec:6a:4d:dc:ef:c4: + 00:df:13:18:57:5f:26:78:c8:d6:0a:79:77:bf:f7: + af:b7:76:b9:a5:0b:84:17:5d:10:ea:6f:e1:ab:95: + 11:5f:6d:3c:a3:5c:4d:83:5b:f2:b3:19:8a:80:8b: + 0b:87 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:3 + X509v3 Key Usage: critical + Digital Signature, Non Repudiation, Certificate Sign, CRL Sign + Signature Algorithm: sha1WithRSAEncryption + 0e:46:d5:3c:ae:e2:87:d9:5e:81:8b:02:98:41:08:8c:4c:bc: + da:db:ee:27:1b:82:e7:6a:45:ec:16:8b:4f:85:a0:f3:b2:70: + bd:5a:96:ba:ca:6e:6d:ee:46:8b:6e:e7:2a:2e:96:b3:19:33: + eb:b4:9f:a8:b2:37:ee:98:a8:97:b6:2e:b6:67:27:d4:a6:49: + fd:1c:93:65:76:9e:42:2f:dc:22:6c:9a:4f:f2:5a:15:39:b1: + 71:d7:2b:51:e8:6d:1c:98:c0:d9:2a:f4:a1:82:7b:d5:c9:41: + a2:23:01:74:38:55:8b:0f:b9:2e:67:a2:20:04:37:da:9c:0b: + d3:17:21:e0:8f:97:79:34:6f:84:48:02:20:33:1b:e6:34:44: + 9f:91:70:f4:80:5e:84:43:c2:29:d2:6c:12:14:e4:61:8d:ac: + 10:90:9e:84:50:bb:f0:96:6f:45:9f:8a:f3:ca:6c:4f:fa:11: + 3a:15:15:46:c3:cd:1f:83:5b:2d:41:12:ed:50:67:41:13:3d: + 21:ab:94:8a:aa:4e:7c:c1:b1:fb:a7:d6:b5:27:2f:97:ab:6e: + e0:1d:e2:d1:1c:2c:1f:44:e2:fc:be:91:a1:9c:fb:d6:29:53: + 73:86:9f:53:d8:43:0e:5d:d6:63:82:71:1d:80:74:ca:f6:e2: + 02:6b:d9:5a +-----BEGIN CERTIFICATE----- +MIIDMDCCAhigAwIBAgICA+gwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCSEsx +FjAUBgNVBAoTDUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3Qg +Um9vdCBDQSAxMB4XDTAzMDUxNTA1MTMxNFoXDTIzMDUxNTA0NTIyOVowRzELMAkG +A1UEBhMCSEsxFjAUBgNVBAoTDUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdr +b25nIFBvc3QgUm9vdCBDQSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEArP84tulmAknjorThkPlAj3n54r15/gK97iSSHSL22oVyaf7XPwnU3ZG1ApzQ +jVrhVcNQhrkpJsLj2aDxaQMoIIBFIi1WpztUlVYiWR8o3x8gPW2iNr4joLFutbEn +PzlTCeqrauh0ssJlXI6/fMN4hM2eFvz1Lk8gKgifd/PFHsSaUmYeSF7jEAaPIpjh +ZY4bXSNmO7ilMlHIhqqhqZ5/dpTCpmy3QfDVyAY45tQM4vM7TG1QjMSDJ8EThFk9 +nnV0ttgCXjqQesBCNnLsak3c78QA3xMYV18meMjWCnl3v/evt3a5pQuEF10Q6m/h +q5URX208o1xNg1vysxmKgIsLhwIDAQABoyYwJDASBgNVHRMBAf8ECDAGAQH/AgED +MA4GA1UdDwEB/wQEAwIBxjANBgkqhkiG9w0BAQUFAAOCAQEADkbVPK7ih9legYsC +mEEIjEy82tvuJxuC52pF7BaLT4Wg87JwvVqWuspube5Gi27nKi6Wsxkz67SfqLI3 +7piol7Yutmcn1KZJ/RyTZXaeQi/cImyaT/JaFTmxcdcrUehtHJjA2Sr0oYJ71clB +oiMBdDhViw+5LmeiIAQ32pwL0xch4I+XeTRvhEgCIDMb5jREn5Fw9IBehEPCKdJs +EhTkYY2sEJCehFC78JZvRZ+K88psT/oROhUVRsPNH4NbLUES7VBnQRM9IauUiqpO +fMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilTc4afU9hDDl3WY4JxHYB0yvbi +AmvZWg== +-----END CERTIFICATE----- + +SecureSign RootCA11 +# Issuer: CN=SecureSign RootCA11,O="Japan Certification Services, Inc.",C=JP +# Serial Number: 1 (0x1) +# Subject: CN=SecureSign RootCA11,O="Japan Certification Services, Inc.",C=JP +# Not Valid Before: Wed Apr 08 04:56:47 2009 +# Not Valid After : Sun Apr 08 04:56:47 2029 +# Fingerprint (MD5): B7:52:74:E2:92:B4:80:93:F2:75:E4:CC:D7:F2:EA:26 +# Fingerprint (SHA1): 3B:C4:9F:48:F8:F3:73:A0:9C:1E:BD:F8:5B:B1:C3:65:C7:D8:11:B3 +MUST_VERIFY_TRUST: EMAIL_PROTECTION, CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH +================================================= +MD5 Fingerprint=B7:52:74:E2:92:B4:80:93:F2:75:E4:CC:D7:F2:EA:26 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 1 (0x1) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=JP, O=Japan Certification Services, Inc., CN=SecureSign RootCA11 + Validity + Not Before: Apr 8 04:56:47 2009 GMT + Not After : Apr 8 04:56:47 2029 GMT + Subject: C=JP, O=Japan Certification Services, Inc., CN=SecureSign RootCA11 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:fd:77:aa:a5:1c:90:05:3b:cb:4c:9b:33:8b:5a: + 14:45:a4:e7:90:16:d1:df:57:d2:21:10:a4:17:fd: + df:ac:d6:1f:a7:e4:db:7c:f7:ec:df:b8:03:da:94: + 58:fd:5d:72:7c:8c:3f:5f:01:67:74:15:96:e3:02: + 3c:87:db:ae:cb:01:8e:c2:f3:66:c6:85:45:f4:02: + c6:3a:b5:62:b2:af:fa:9c:bf:a4:e6:d4:80:30:98: + f3:0d:b6:93:8f:a9:d4:d8:36:f2:b0:fc:8a:ca:2c: + a1:15:33:95:31:da:c0:1b:f2:ee:62:99:86:63:3f: + bf:dd:93:2a:83:a8:76:b9:13:1f:b7:ce:4e:42:85: + 8f:22:e7:2e:1a:f2:95:09:b2:05:b5:44:4e:77:a1: + 20:bd:a9:f2:4e:0a:7d:50:ad:f5:05:0d:45:4f:46: + 71:fd:28:3e:53:fb:04:d8:2d:d7:65:1d:4a:1b:fa: + cf:3b:b0:31:9a:35:6e:c8:8b:06:d3:00:91:f2:94: + 08:65:4c:b1:34:06:00:7a:89:e2:f0:c7:03:59:cf: + d5:d6:e8:a7:32:b3:e6:98:40:86:c5:cd:27:12:8b: + cc:7b:ce:b7:11:3c:62:60:07:23:3e:2b:40:6e:94: + 80:09:6d:b6:b3:6f:77:6f:35:08:50:fb:02:87:c5: + 3e:89 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + 5B:F8:4D:4F:B2:A5:86:D4:3A:D2:F1:63:9A:A0:BE:09:F6:57:B7:DE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + Signature Algorithm: sha1WithRSAEncryption + a0:a1:38:16:66:2e:a7:56:1f:21:9c:06:fa:1d:ed:b9:22:c5: + 38:26:d8:4e:4f:ec:a3:7f:79:de:46:21:a1:87:77:8f:07:08: + 9a:b2:a4:c5:af:0f:32:98:0b:7c:66:29:b6:9b:7d:25:52:49: + 43:ab:4c:2e:2b:6e:7a:70:af:16:0e:e3:02:6c:fb:42:e6:18: + 9d:45:d8:55:c8:e8:3b:dd:e7:e1:f4:2e:0b:1c:34:5c:6c:58: + 4a:fb:8c:88:50:5f:95:1c:bf:ed:ab:22:b5:65:b3:85:ba:9e: + 0f:b8:ad:e5:7a:1b:8a:50:3a:1d:bd:0d:bc:7b:54:50:0b:b9: + 42:af:55:a0:18:81:ad:65:99:ef:be:e4:9c:bf:c4:85:ab:41: + b2:54:6f:dc:25:cd:ed:78:e2:8e:0c:8d:09:49:dd:63:7b:5a: + 69:96:02:21:a8:bd:52:59:e9:7d:35:cb:c8:52:ca:7f:81:fe: + d9:6b:d3:f7:11:ed:25:df:f8:e7:f9:a4:fa:72:97:84:53:0d: + a5:d0:32:18:51:76:59:14:6c:0f:eb:ec:5f:80:8c:75:43:83: + c3:85:98:ff:4c:9e:2d:0d:e4:77:83:93:4e:b5:96:07:8b:28: + 13:9b:8c:19:8d:41:27:49:40:ee:de:e6:23:44:39:dc:a1:22: + d6:ba:03:f2 +-----BEGIN CERTIFICATE----- +MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDEr +MCkGA1UEChMiSmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoG +A1UEAxMTU2VjdXJlU2lnbiBSb290Q0ExMTAeFw0wOTA0MDgwNDU2NDdaFw0yOTA0 +MDgwNDU2NDdaMFgxCzAJBgNVBAYTAkpQMSswKQYDVQQKEyJKYXBhbiBDZXJ0aWZp +Y2F0aW9uIFNlcnZpY2VzLCBJbmMuMRwwGgYDVQQDExNTZWN1cmVTaWduIFJvb3RD +QTExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/XeqpRyQBTvLTJsz +i1oURaTnkBbR31fSIRCkF/3frNYfp+TbfPfs37gD2pRY/V1yfIw/XwFndBWW4wI8 +h9uuywGOwvNmxoVF9ALGOrVisq/6nL+k5tSAMJjzDbaTj6nU2DbysPyKyiyhFTOV +MdrAG/LuYpmGYz+/3ZMqg6h2uRMft85OQoWPIucuGvKVCbIFtUROd6EgvanyTgp9 +UK31BQ1FT0Zx/Sg+U/sE2C3XZR1KG/rPO7AxmjVuyIsG0wCR8pQIZUyxNAYAeoni +8McDWc/V1uinMrPmmECGxc0nEovMe863ETxiYAcjPitAbpSACW22s293bzUIUPsC +h8U+iQIDAQABo0IwQDAdBgNVHQ4EFgQUW/hNT7KlhtQ60vFjmqC+CfZXt94wDgYD +VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEB +AKChOBZmLqdWHyGcBvod7bkixTgm2E5P7KN/ed5GIaGHd48HCJqypMWvDzKYC3xm +KbabfSVSSUOrTC4rbnpwrxYO4wJs+0LmGJ1F2FXI6Dvd5+H0LgscNFxsWEr7jIhQ +X5Ucv+2rIrVls4W6ng+4reV6G4pQOh29Dbx7VFALuUKvVaAYga1lme++5Jy/xIWr +QbJUb9wlze144o4MjQlJ3WN7WmmWAiGovVJZ6X01y8hSyn+B/tlr0/cR7SXf+Of5 +pPpyl4RTDaXQMhhRdlkUbA/r7F+AjHVDg8OFmP9Mni0N5HeDk061lgeLKBObjBmN +QSdJQO7e5iNEOdyhIta6A/I= +-----END CERTIFICATE----- + +Microsec e-Szigno Root CA 2009 +# Issuer: E=info@e-szigno.hu,CN=Microsec e-Szigno Root CA 2009,O=Microsec Ltd.,L=Budapest,C=HU +# Serial Number:00:c2:7e:43:04:4e:47:3f:19 +# Subject: E=info@e-szigno.hu,CN=Microsec e-Szigno Root CA 2009,O=Microsec Ltd.,L=Budapest,C=HU +# Not Valid Before: Tue Jun 16 11:30:18 2009 +# Not Valid After : Sun Dec 30 11:30:18 2029 +# Fingerprint (MD5): F8:49:F4:03:BC:44:2D:83:BE:48:69:7D:29:64:FC:B1 +# Fingerprint (SHA1): 89:DF:74:FE:5C:F4:0F:4A:80:F9:E3:37:7D:54:DA:91:E1:01:31:8E +MUST_VERIFY_TRUST: CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +================================================ +MD5 Fingerprint=F8:49:F4:03:BC:44:2D:83:BE:48:69:7D:29:64:FC:B1 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + c2:7e:43:04:4e:47:3f:19 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=HU, L=Budapest, O=Microsec Ltd., CN=Microsec e-Szigno Root CA 2009/emailAddress=info@e-szigno.hu + Validity + Not Before: Jun 16 11:30:18 2009 GMT + Not After : Dec 30 11:30:18 2029 GMT + Subject: C=HU, L=Budapest, O=Microsec Ltd., CN=Microsec e-Szigno Root CA 2009/emailAddress=info@e-szigno.hu + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:e9:f8:8f:f3:63:ad:da:86:d8:a7:e0:42:fb:cf: + 91:de:a6:26:f8:99:a5:63:70:ad:9b:ae:ca:33:40: + 7d:6d:96:6e:a1:0e:44:ee:e1:13:9d:94:42:52:9a: + bd:75:85:74:2c:a8:0e:1d:93:b6:18:b7:8c:2c:a8: + cf:fb:5c:71:b9:da:ec:fe:e8:7e:8f:e4:2f:1d:b2: + a8:75:87:d8:b7:a1:e5:3b:cf:99:4a:46:d0:83:19: + 7d:c0:a1:12:1c:95:6d:4a:f4:d8:c7:a5:4d:33:2e: + 85:39:40:75:7e:14:7c:80:12:98:50:c7:41:67:b8: + a0:80:61:54:a6:6c:4e:1f:e0:9d:0e:07:e9:c9:ba: + 33:e7:fe:c0:55:28:2c:02:80:a7:19:f5:9e:dc:55: + 53:03:97:7b:07:48:ff:99:fb:37:8a:24:c4:59:cc: + 50:10:63:8e:aa:a9:1a:b0:84:1a:86:f9:5f:bb:b1: + 50:6e:a4:d1:0a:cc:d5:71:7e:1f:a7:1b:7c:f5:53: + 6e:22:5f:cb:2b:e6:d4:7c:5d:ae:d6:c2:c6:4c:e5: + 05:01:d9:ed:57:fc:c1:23:79:fc:fa:c8:24:83:95: + f3:b5:6a:51:01:d0:77:d6:e9:12:a1:f9:1a:83:fb: + 82:1b:b9:b0:97:f4:76:06:33:43:49:a0:ff:0b:b5: + fa:b5 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + CB:0F:C6:DF:42:43:CC:3D:CB:B5:48:23:A1:1A:7A:A6:2A:BB:34:68 + X509v3 Authority Key Identifier: + keyid:CB:0F:C6:DF:42:43:CC:3D:CB:B5:48:23:A1:1A:7A:A6:2A:BB:34:68 + + X509v3 Subject Alternative Name: + email:info@e-szigno.hu + Signature Algorithm: sha256WithRSAEncryption + c9:d1:0e:5e:2e:d5:cc:b3:7c:3e:cb:fc:3d:ff:0d:28:95:93: + 04:c8:bf:da:cd:79:b8:43:90:f0:a4:be:ef:f2:ef:21:98:bc: + d4:d4:5d:06:f6:ee:42:ec:30:6c:a0:aa:a9:ca:f1:af:8a:fa: + 3f:0b:73:6a:3e:ea:2e:40:7e:1f:ae:54:61:79:eb:2e:08:37: + d7:23:f3:8c:9f:be:1d:b1:e1:a4:75:db:a0:e2:54:14:b1:ba: + 1c:29:a4:18:f6:12:ba:a2:14:14:e3:31:35:c8:40:ff:b7:e0: + 05:76:57:c1:1c:59:f2:f8:bf:e4:ed:25:62:5c:84:f0:7e:7e: + 1f:b3:be:f9:b7:21:11:cc:03:01:56:70:a7:10:92:1e:1b:34: + 81:1e:ad:9c:1a:c3:04:3c:ed:02:61:d6:1e:06:f3:5f:3a:87: + f2:2b:f1:45:87:e5:3d:ac:d1:c7:57:84:bd:6b:ae:dc:d8:f9: + b6:1b:62:70:0b:3d:36:c9:42:f2:32:d7:7a:61:e6:d2:db:3d: + cf:c8:a9:c9:9b:dc:db:58:44:d7:6f:38:af:7f:78:d3:a3:ad: + 1a:75:ba:1c:c1:36:7c:8f:1e:6d:1c:c3:75:46:ae:35:05:a6: + f6:5c:3d:21:ee:56:f0:c9:82:22:2d:7a:54:ab:70:c3:7d:22: + 65:82:70:96 +-----BEGIN CERTIFICATE----- +MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYD +VQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0 +ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0G +CSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTAeFw0wOTA2MTYxMTMwMThaFw0y +OTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3Qx +FjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3pp +Z25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o +dTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvP +kd6mJviZpWNwrZuuyjNAfW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tc +cbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG0IMZfcChEhyVbUr02MelTTMuhTlAdX4U +fIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKApxn1ntxVUwOXewdI/5n7 +N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm1HxdrtbC +xkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1 ++rUCAwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G +A1UdDgQWBBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPM +Pcu1SCOhGnqmKrs0aDAbBgNVHREEFDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqG +SIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0olZMEyL/azXm4Q5DwpL7v8u8h +mLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfXI/OMn74dseGk +ddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775 +tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c +2Pm2G2JwCz02yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5t +HMN1Rq41Bab2XD0h7lbwyYIiLXpUq3DDfSJlgnCW +-----END CERTIFICATE----- + +GlobalSign Root CA - R3 +# Issuer: CN=GlobalSign,O=GlobalSign,OU=GlobalSign Root CA - R3 +# Serial Number:04:00:00:00:00:01:21:58:53:08:a2 +# Subject: CN=GlobalSign,O=GlobalSign,OU=GlobalSign Root CA - R3 +# Not Valid Before: Wed Mar 18 10:00:00 2009 +# Not Valid After : Sun Mar 18 10:00:00 2029 +# Fingerprint (MD5): C5:DF:B8:49:CA:05:13:55:EE:2D:BA:1A:C3:3E:B0:28 +# Fingerprint (SHA1): D6:9B:56:11:48:F0:1C:77:C5:45:78:C1:09:26:DF:5B:85:69:76:AD +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +MUST_VERIFY_TRUST: CODE_SIGNING +================================================ +MD5 Fingerprint=C5:DF:B8:49:CA:05:13:55:EE:2D:BA:1A:C3:3E:B0:28 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 04:00:00:00:00:01:21:58:53:08:a2 + Signature Algorithm: sha256WithRSAEncryption + Issuer: OU=GlobalSign Root CA - R3, O=GlobalSign, CN=GlobalSign + Validity + Not Before: Mar 18 10:00:00 2009 GMT + Not After : Mar 18 10:00:00 2029 GMT + Subject: OU=GlobalSign Root CA - R3, O=GlobalSign, CN=GlobalSign + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:cc:25:76:90:79:06:78:22:16:f5:c0:83:b6:84: + ca:28:9e:fd:05:76:11:c5:ad:88:72:fc:46:02:43: + c7:b2:8a:9d:04:5f:24:cb:2e:4b:e1:60:82:46:e1: + 52:ab:0c:81:47:70:6c:dd:64:d1:eb:f5:2c:a3:0f: + 82:3d:0c:2b:ae:97:d7:b6:14:86:10:79:bb:3b:13: + 80:77:8c:08:e1:49:d2:6a:62:2f:1f:5e:fa:96:68: + df:89:27:95:38:9f:06:d7:3e:c9:cb:26:59:0d:73: + de:b0:c8:e9:26:0e:83:15:c6:ef:5b:8b:d2:04:60: + ca:49:a6:28:f6:69:3b:f6:cb:c8:28:91:e5:9d:8a: + 61:57:37:ac:74:14:dc:74:e0:3a:ee:72:2f:2e:9c: + fb:d0:bb:bf:f5:3d:00:e1:06:33:e8:82:2b:ae:53: + a6:3a:16:73:8c:dd:41:0e:20:3a:c0:b4:a7:a1:e9: + b2:4f:90:2e:32:60:e9:57:cb:b9:04:92:68:68:e5: + 38:26:60:75:b2:9f:77:ff:91:14:ef:ae:20:49:fc: + ad:40:15:48:d1:02:31:61:19:5e:b8:97:ef:ad:77: + b7:64:9a:7a:bf:5f:c1:13:ef:9b:62:fb:0d:6c:e0: + 54:69:16:a9:03:da:6e:e9:83:93:71:76:c6:69:85: + 82:17 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + 8F:F0:4B:7F:A8:2E:45:24:AE:4D:50:FA:63:9A:8B:DE:E2:DD:1B:BC + Signature Algorithm: sha256WithRSAEncryption + 4b:40:db:c0:50:aa:fe:c8:0c:ef:f7:96:54:45:49:bb:96:00: + 09:41:ac:b3:13:86:86:28:07:33:ca:6b:e6:74:b9:ba:00:2d: + ae:a4:0a:d3:f5:f1:f1:0f:8a:bf:73:67:4a:83:c7:44:7b:78: + e0:af:6e:6c:6f:03:29:8e:33:39:45:c3:8e:e4:b9:57:6c:aa: + fc:12:96:ec:53:c6:2d:e4:24:6c:b9:94:63:fb:dc:53:68:67: + 56:3e:83:b8:cf:35:21:c3:c9:68:fe:ce:da:c2:53:aa:cc:90: + 8a:e9:f0:5d:46:8c:95:dd:7a:58:28:1a:2f:1d:de:cd:00:37: + 41:8f:ed:44:6d:d7:53:28:97:7e:f3:67:04:1e:15:d7:8a:96: + b4:d3:de:4c:27:a4:4c:1b:73:73:76:f4:17:99:c2:1f:7a:0e: + e3:2d:08:ad:0a:1c:2c:ff:3c:ab:55:0e:0f:91:7e:36:eb:c3: + 57:49:be:e1:2e:2d:7c:60:8b:c3:41:51:13:23:9d:ce:f7:32: + 6b:94:01:a8:99:e7:2c:33:1f:3a:3b:25:d2:86:40:ce:3b:2c: + 86:78:c9:61:2f:14:ba:ee:db:55:6f:df:84:ee:05:09:4d:bd: + 28:d8:72:ce:d3:62:50:65:1e:eb:92:97:83:31:d9:b3:b5:ca: + 47:58:3f:5f +-----BEGIN CERTIFICATE----- +MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G +A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp +Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4 +MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG +A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8 +RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT +gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm +KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd +QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ +XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw +DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o +LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU +RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp +jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK +6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX +mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs +Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH +WD9f +-----END CERTIFICATE----- + +Autoridad de Certificacion Firmaprofesional CIF A62634068 +# Issuer: CN=Autoridad de Certificacion Firmaprofesional CIF A62634068,C=ES +# Serial Number:53:ec:3b:ee:fb:b2:48:5f +# Subject: CN=Autoridad de Certificacion Firmaprofesional CIF A62634068,C=ES +# Not Valid Before: Wed May 20 08:38:15 2009 +# Not Valid After : Tue Dec 31 08:38:15 2030 +# Fingerprint (MD5): 73:3A:74:7A:EC:BB:A3:96:A6:C2:E4:E2:C8:9B:C0:C3 +# Fingerprint (SHA1): AE:C5:FB:3F:C8:E1:BF:C4:E5:4F:03:07:5A:9A:E8:00:B7:F7:B6:FA +MUST_VERIFY_TRUST: CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +========================================================= +MD5 Fingerprint=73:3A:74:7A:EC:BB:A3:96:A6:C2:E4:E2:C8:9B:C0:C3 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 6047274297262753887 (0x53ec3beefbb2485f) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=ES, CN=Autoridad de Certificacion Firmaprofesional CIF A62634068 + Validity + Not Before: May 20 08:38:15 2009 GMT + Not After : Dec 31 08:38:15 2030 GMT + Subject: C=ES, CN=Autoridad de Certificacion Firmaprofesional CIF A62634068 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:ca:96:6b:8e:ea:f8:fb:f1:a2:35:e0:7f:4c:da: + e0:c3:52:d7:7d:b6:10:c8:02:5e:b3:43:2a:c4:4f: + 6a:b2:ca:1c:5d:28:9a:78:11:1a:69:59:57:af:b5: + 20:42:e4:8b:0f:e6:df:5b:a6:03:92:2f:f5:11:e4: + 62:d7:32:71:38:d9:04:0c:71:ab:3d:51:7e:0f:07: + df:63:05:5c:e9:bf:94:6f:c1:29:82:c0:b4:da:51: + b0:c1:3c:bb:ad:37:4a:5c:ca:f1:4b:36:0e:24:ab: + bf:c3:84:77:fd:a8:50:f4:b1:e7:c6:2f:d2:2d:59: + 8d:7a:0a:4e:96:69:52:02:aa:36:98:ec:fc:fa:14: + 83:0c:37:1f:c9:92:37:7f:d7:81:2d:e5:c4:b9:e0: + 3e:34:fe:67:f4:3e:66:d1:d3:f4:40:cf:5e:62:34: + 0f:70:06:3e:20:18:5a:ce:f7:72:1b:25:6c:93:74: + 14:93:a3:73:b1:0e:aa:87:10:23:59:5f:20:05:19: + 47:ed:68:8e:92:12:ca:5d:fc:d6:2b:b2:92:3c:20: + cf:e1:5f:af:20:be:a0:76:7f:76:e5:ec:1a:86:61: + 33:3e:e7:7b:b4:3f:a0:0f:8e:a2:b9:6a:6f:b9:87: + 26:6f:41:6c:88:a6:50:fd:6a:63:0b:f5:93:16:1b: + 19:8f:b2:ed:9b:9b:c9:90:f5:01:0c:df:19:3d:0f: + 3e:38:23:c9:2f:8f:0c:d1:02:fe:1b:55:d6:4e:d0: + 8d:3c:af:4f:a4:f3:fe:af:2a:d3:05:9d:79:08:a1: + cb:57:31:b4:9c:c8:90:b2:67:f4:18:16:93:3a:fc: + 47:d8:d1:78:96:31:1f:ba:2b:0c:5f:5d:99:ad:63: + 89:5a:24:20:76:d8:df:fd:ab:4e:a6:22:aa:9d:5e: + e6:27:8a:7d:68:29:a3:e7:8a:b8:da:11:bb:17:2d: + 99:9d:13:24:46:f7:c5:e2:d8:9f:8e:7f:c7:8f:74: + 6d:5a:b2:e8:72:f5:ac:ee:24:10:ad:2f:14:da:ff: + 2d:9a:46:71:47:be:42:df:bb:01:db:f4:7f:d3:28: + 8f:31:59:5b:d3:c9:02:a6:b4:52:ca:6e:97:fb:43: + c5:08:26:6f:8a:f4:bb:fd:9f:28:aa:0d:d5:45:f3: + 13:3a:1d:d8:c0:78:8f:41:67:3c:1e:94:64:ae:7b: + 0b:c5:e8:d9:01:88:39:1a:97:86:64:41:d5:3b:87: + 0c:6e:fa:0f:c6:bd:48:14:bf:39:4d:d4:9e:41:b6: + 8f:96:1d:63:96:93:d9:95:06:78:31:68:9e:37:06: + 3b:80:89:45:61:39:23:c7:1b:44:a3:15:e5:1c:f8: + 92:30:bb + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:1 + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 65:CD:EB:AB:35:1E:00:3E:7E:D5:74:C0:1C:B4:73:47:0E:1A:64:2F + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: http://www.firmaprofesional.com/cps + User Notice: + Explicit Text: + + Signature Algorithm: sha1WithRSAEncryption + 17:7d:a0:f9:b4:dd:c5:c5:eb:ad:4b:24:b5:a1:02:ab:dd:a5: + 88:4a:b2:0f:55:4b:2b:57:8c:3b:e5:31:dd:fe:c4:32:f1:e7: + 5b:64:96:36:32:18:ec:a5:32:77:d7:e3:44:b6:c0:11:2a:80: + b9:3d:6a:6e:7c:9b:d3:ad:fc:c3:d6:a3:e6:64:29:7c:d1:e1: + 38:1e:82:2b:ff:27:65:af:fb:16:15:c4:2e:71:84:e5:b5:ff: + fa:a4:47:bd:64:32:bb:f6:25:84:a2:27:42:f5:20:b0:c2:13: + 10:11:cd:10:15:ba:42:90:2a:d2:44:e1:96:26:eb:31:48:12: + fd:2a:da:c9:06:cf:74:1e:a9:4b:d5:87:28:f9:79:34:92:3e: + 2e:44:e8:f6:8f:4f:8f:35:3f:25:b3:39:dc:63:2a:90:6b:20: + 5f:c4:52:12:4e:97:2c:2a:ac:9d:97:de:48:f2:a3:66:db:c2: + d2:83:95:a6:66:a7:9e:25:0f:e9:0b:33:91:65:0a:5a:c3:d9: + 54:12:dd:af:c3:4e:0e:1f:26:5e:0d:dc:b3:8d:ec:d5:81:70: + de:d2:4f:24:05:f3:6c:4e:f5:4c:49:66:8d:d1:ff:d2:0b:25: + 41:48:fe:51:84:c6:42:af:80:04:cf:d0:7e:64:49:e4:f2:df: + a2:ec:b1:4c:c0:2a:1d:e7:b4:b1:65:a2:c4:bc:f1:98:f4:aa: + 70:07:63:b4:b8:da:3b:4c:fa:40:22:30:5b:11:a6:f0:05:0e: + c6:02:03:48:ab:86:9b:85:dd:db:dd:ea:a2:76:80:73:7d:f5: + 9c:04:c4:45:8d:e7:b9:1c:8b:9e:ea:d7:75:d1:72:b1:de:75: + 44:e7:42:7d:e2:57:6b:7d:dc:99:bc:3d:83:28:ea:80:93:8d: + c5:4c:65:c1:70:81:b8:38:fc:43:31:b2:f6:03:34:47:b2:ac: + fb:22:06:cb:1e:dd:17:47:1c:5f:66:b9:d3:1a:a2:da:11:b1: + a4:bc:23:c9:e4:be:87:ff:b9:94:b6:f8:5d:20:4a:d4:5f:e7: + bd:68:7b:65:f2:15:1e:d2:3a:a9:2d:e9:d8:6b:24:ac:97:58: + 44:47:ad:59:18:f1:21:65:70:de:ce:34:60:a8:40:f1:f3:3c: + a4:c3:28:23:8c:fe:27:33:43:40:a0:17:3c:eb:ea:3b:b0:72: + a6:a3:b9:4a:4b:5e:16:48:f4:b2:bc:c8:8c:92:c5:9d:9f:ac: + 72:36:bc:34:80:34:6b:a9:8b:92:c0:b8:17:ed:ec:76:53:f5: + 24:01:8c:b3:22:e8:4b:7c:55:c6:9d:fa:a3:14:bb:65:85:6e: + 6e:4f:12:7e:0a:3c:9d:95 +-----BEGIN CERTIFICATE----- +MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UE +BhMCRVMxQjBABgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1h +cHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEy +MzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIwQAYDVQQDDDlBdXRvcmlkYWQgZGUg +Q2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBBNjI2MzQwNjgwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDDUtd9 +thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQM +cas9UX4PB99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefG +L9ItWY16Ck6WaVICqjaY7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15i +NA9wBj4gGFrO93IbJWyTdBSTo3OxDqqHECNZXyAFGUftaI6SEspd/NYrspI8IM/h +X68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyIplD9amML9ZMWGxmPsu2b +m8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctXMbScyJCy +Z/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirja +EbsXLZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/T +KI8xWVvTyQKmtFLKbpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF +6NkBiDkal4ZkQdU7hwxu+g/GvUgUvzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVh +OSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1UdEwEB/wQIMAYBAf8CAQEwDgYD +VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNHDhpkLzCBpgYD +VR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp +cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBv +ACAAZABlACAAbABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBl +AGwAbwBuAGEAIAAwADgAMAAxADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF +661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx51tkljYyGOylMnfX40S2wBEqgLk9 +am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qkR71kMrv2JYSiJ0L1 +ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaPT481 +PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS +3a/DTg4fJl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5k +SeTy36LssUzAKh3ntLFlosS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF +3dvd6qJ2gHN99ZwExEWN57kci57q13XRcrHedUTnQn3iV2t93Jm8PYMo6oCTjcVM +ZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoRsaS8I8nkvof/uZS2+F0g +StRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTDKCOM/icz +Q0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQB +jLMi6Et8Vcad+qMUu2WFbm5PEn4KPJ2V +-----END CERTIFICATE----- + +Izenpe.com +# Issuer: CN=Izenpe.com,O=IZENPE S.A.,C=ES +# Serial Number:00:b0:b7:5a:16:48:5f:bf:e1:cb:f5:8b:d7:19:e6:7d +# Subject: CN=Izenpe.com,O=IZENPE S.A.,C=ES +# Not Valid Before: Thu Dec 13 13:08:28 2007 +# Not Valid After : Sun Dec 13 08:27:25 2037 +# Fingerprint (MD5): A6:B0:CD:85:80:DA:5C:50:34:A3:39:90:2F:55:67:73 +# Fingerprint (SHA1): 2F:78:3D:25:52:18:A7:4A:65:39:71:B5:2C:A2:9C:45:15:6F:E9:19 +TRUSTED_DELEGATOR: SERVER_AUTH +MUST_VERIFY_TRUST: EMAIL_PROTECTION, CODE_SIGNING +================================================= +MD5 Fingerprint=A6:B0:CD:85:80:DA:5C:50:34:A3:39:90:2F:55:67:73 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + b0:b7:5a:16:48:5f:bf:e1:cb:f5:8b:d7:19:e6:7d + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=ES, O=IZENPE S.A., CN=Izenpe.com + Validity + Not Before: Dec 13 13:08:28 2007 GMT + Not After : Dec 13 08:27:25 2037 GMT + Subject: C=ES, O=IZENPE S.A., CN=Izenpe.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:c9:d3:7a:ca:0f:1e:ac:a7:86:e8:16:65:6a:b1: + c2:1b:45:32:71:95:d9:fe:10:5b:cc:af:e7:a5:79: + 01:8f:89:c3:ca:f2:55:71:f7:77:be:77:94:f3:72: + a4:2c:44:d8:9e:92:9b:14:3a:a1:e7:24:90:0a:0a: + 56:8e:c5:d8:26:94:e1:d9:48:e1:2d:3e:da:0a:72: + dd:a3:99:15:da:81:a2:87:f4:7b:6e:26:77:89:58: + ad:d6:eb:0c:b2:41:7a:73:6e:6d:db:7a:78:41:e9: + 08:88:12:7e:87:2e:66:11:63:6c:54:fb:3c:9d:72: + c0:bc:2e:ff:c2:b7:dd:0d:76:e3:3a:d7:f7:b4:68: + be:a2:f5:e3:81:6e:c1:46:6f:5d:8d:e0:4d:c6:54: + 55:89:1a:33:31:0a:b1:57:b9:a3:8a:98:c3:ec:3b: + 34:c5:95:41:69:7e:75:c2:3c:20:c5:61:ba:51:47: + a0:20:90:93:a1:90:4b:f3:4e:7c:85:45:54:9a:d1: + 05:26:41:b0:b5:4d:1d:33:be:c4:03:c8:25:7c:c1: + 70:db:3b:f4:09:2d:54:27:48:ac:2f:e1:c4:ac:3e: + c8:cb:92:4c:53:39:37:23:ec:d3:01:f9:e0:09:44: + 4d:4d:64:c0:e1:0d:5a:87:22:bc:ad:1b:a3:fe:26: + b5:15:f3:a7:fc:84:19:e9:ec:a1:88:b4:44:69:84: + 83:f3:89:d1:74:06:a9:cc:0b:d6:c2:de:27:85:50: + 26:ca:17:b8:c9:7a:87:56:2c:1a:01:1e:6c:be:13: + ad:10:ac:b5:24:f5:38:91:a1:d6:4b:da:f1:bb:d2: + de:47:b5:f1:bc:81:f6:59:6b:cf:19:53:e9:8d:15: + cb:4a:cb:a9:6f:44:e5:1b:41:cf:e1:86:a7:ca:d0: + 6a:9f:bc:4c:8d:06:33:5a:a2:85:e5:90:35:a0:62: + 5c:16:4e:f0:e3:a2:fa:03:1a:b4:2c:71:b3:58:2c: + de:7b:0b:db:1a:0f:eb:de:21:1f:06:77:06:03:b0: + c9:ef:99:fc:c0:b9:4f:0b:86:28:fe:d2:b9:ea:e3: + da:a5:c3:47:69:12:e0:db:f0:f6:19:8b:ed:7b:70: + d7:02:d6:ed:87:18:28:2c:04:24:4c:77:e4:48:8a: + 1a:c6:3b:9a:d4:0f:ca:fa:75:d2:01:40:5a:8d:79: + bf:8b:cf:4b:cf:aa:16:c1:95:e4:ad:4c:8a:3e:17: + 91:d4:b1:62:e5:82:e5:80:04:a4:03:7e:8d:bf:da: + 7f:a2:0f:97:4f:0c:d3:0d:fb:d7:d1:e5:72:7e:1c: + c8:77:ff:5b:9a:0f:b7:ae:05:46:e5:f1:a8:16:ec: + 47:a4:17 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Alternative Name: + email:info@izenpe.com, DirName:/O=IZENPE S.A. - CIF A01337260-RMerc.Vitoria-Gasteiz T1055 F62 S8/street=Avda del Mediterraneo Etorbidea 14 - 01010 Vitoria-Gasteiz + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 1D:1C:65:0E:A8:F2:25:7B:B4:91:CF:E4:B1:B1:E6:BD:55:74:6C:05 + Signature Algorithm: sha256WithRSAEncryption + 78:a6:0c:16:4a:9f:4c:88:3a:c0:cb:0e:a5:16:7d:9f:b9:48: + 5f:18:8f:0d:62:36:f6:cd:19:6b:ac:ab:d5:f6:91:7d:ae:71: + f3:3f:b3:0e:78:85:9b:95:a4:27:21:47:42:4a:7c:48:3a:f5: + 45:7c:b3:0c:8e:51:78:ac:95:13:de:c6:fd:7d:b8:1a:90:4c: + ab:92:03:c7:ed:42:01:ce:0f:d8:b1:fa:a2:92:e1:60:6d:ae: + 7a:6b:09:aa:c6:29:ee:68:49:67:30:80:24:7a:31:16:39:5b: + 7e:f1:1c:2e:dd:6c:09:ad:f2:31:c1:82:4e:b9:bb:f9:be:bf: + 2a:85:3f:c0:40:a3:3a:59:fc:59:4b:3c:28:24:db:b4:15:75: + ae:0d:88:ba:2e:73:c0:bd:58:87:e5:42:f2:eb:5e:ee:1e:30: + 22:99:cb:37:d1:c4:21:6c:81:ec:be:6d:26:e6:1c:e4:42:20: + 9e:47:b0:ac:83:59:70:2c:35:d6:af:36:34:b4:cd:3b:f8:32: + a8:ef:e3:78:89:fb:8d:45:2c:da:9c:b8:7e:40:1c:61:e7:3e: + a2:92:2c:4b:f2:cd:fa:98:b6:29:ff:f3:f2:7b:a9:1f:2e:a0: + 93:57:2b:de:85:03:f9:69:37:cb:9e:78:6a:05:b4:c5:31:78: + 89:ec:7a:a7:85:e1:b9:7b:3c:de:be:1e:79:84:ce:9f:70:0e: + 59:c2:35:2e:90:2a:31:d9:e4:45:7a:41:a4:2e:13:9b:34:0e: + 66:7b:49:ab:64:97:d0:46:c3:79:9d:72:50:63:a6:98:5b:06: + bd:48:6d:d8:39:83:70:e8:35:f0:05:d1:aa:bc:e3:db:c8:02: + ea:7c:fd:82:da:c2:5b:52:35:ae:98:3a:ad:ba:35:93:23:a7: + 1f:48:dd:35:46:98:b2:10:68:e4:a5:31:c2:0a:58:2e:19:81: + 10:c9:50:75:fc:ea:5a:16:ce:11:d7:ee:ef:50:88:2d:61:ff: + 3f:42:73:05:94:43:d5:8e:3c:4e:01:3a:19:a5:1f:46:4e:77: + d0:5d:e5:81:22:21:87:fe:94:7d:84:d8:93:ad:d6:68:43:48: + b2:db:eb:73:24:e7:91:7f:54:a4:b6:80:3e:9d:a3:3c:4c:72: + c2:57:c4:a0:d4:cc:38:27:ce:d5:06:9e:a2:48:d9:e9:9f:ce: + 82:70:36:93:9a:3b:df:96:21:e3:59:b7:0c:da:91:37:f0:fd: + 59:5a:b3:99:c8:69:6c:43:26:01:35:63:60:55:89:03:3a:75: + d8:ba:4a:d9:54:ff:ee:de:80:d8:2d:d1:38:d5:5e:2d:0b:98: + 7d:3e:6c:db:fc:26:88:c7 +-----BEGIN CERTIFICATE----- +MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4 +MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6 +ZW5wZS5jb20wHhcNMDcxMjEzMTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYD +VQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5j +b20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ03rKDx6sp4boFmVq +scIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAKClaO +xdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6H +LmYRY2xU+zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFX +uaOKmMPsOzTFlUFpfnXCPCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQD +yCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxTOTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+ +JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbKF7jJeodWLBoBHmy+E60Q +rLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK0GqfvEyN +BjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8L +hij+0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIB +QFqNeb+Lz0vPqhbBleStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+ +HMh3/1uaD7euBUbl8agW7EekFwIDAQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2lu +Zm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+SVpFTlBFIFMuQS4gLSBDSUYg +QTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBGNjIgUzgxQzBB +BgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx +MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwHQYDVR0OBBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUA +A4ICAQB4pgwWSp9MiDrAyw6lFn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWb +laQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbgakEyrkgPH7UIBzg/YsfqikuFgba56 +awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8qhT/AQKM6WfxZSzwo +JNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Csg1lw +LDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCT +VyvehQP5aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGk +LhObNA5me0mrZJfQRsN5nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJb +UjWumDqtujWTI6cfSN01RpiyEGjkpTHCClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/ +QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZoQ0iy2+tzJOeRf1SktoA+ +naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1ZWrOZyGls +QyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw== +-----END CERTIFICATE----- + +Chambers of Commerce Root - 2008 +# Issuer: CN=Chambers of Commerce Root - 2008,O=AC Camerfirma S.A.,serialNumber=A82743287,L=Madrid (see current address at www.camerfirma.com/address),C=EU +# Serial Number:00:a3:da:42:7e:a4:b1:ae:da +# Subject: CN=Chambers of Commerce Root - 2008,O=AC Camerfirma S.A.,serialNumber=A82743287,L=Madrid (see current address at www.camerfirma.com/address),C=EU +# Not Valid Before: Fri Aug 01 12:29:50 2008 +# Not Valid After : Sat Jul 31 12:29:50 2038 +# Fingerprint (MD5): 5E:80:9E:84:5A:0E:65:0B:17:02:F3:55:18:2A:3E:D7 +# Fingerprint (SHA1): 78:6A:74:AC:76:AB:14:7F:9C:6A:30:50:BA:9E:A8:7E:FE:9A:CE:3C +MUST_VERIFY_TRUST: CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +================================================ +MD5 Fingerprint=5E:80:9E:84:5A:0E:65:0B:17:02:F3:55:18:2A:3E:D7 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + a3:da:42:7e:a4:b1:ae:da + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=EU, L=Madrid (see current address at www.camerfirma.com/address)/serialNumber=A82743287, O=AC Camerfirma S.A., CN=Chambers of Commerce Root - 2008 + Validity + Not Before: Aug 1 12:29:50 2008 GMT + Not After : Jul 31 12:29:50 2038 GMT + Subject: C=EU, L=Madrid (see current address at www.camerfirma.com/address)/serialNumber=A82743287, O=AC Camerfirma S.A., CN=Chambers of Commerce Root - 2008 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:af:00:cb:70:37:2b:80:5a:4a:3a:6c:78:94:7d: + a3:7f:1a:1f:f6:35:d5:bd:db:cb:0d:44:72:3e:26: + b2:90:52:ba:63:3b:28:58:6f:a5:b3:6d:94:a6:f3: + dd:64:0c:55:f6:f6:e7:f2:22:22:80:5e:e1:62:c6: + b6:29:e1:81:6c:f2:bf:e5:7d:32:6a:54:a0:32:19: + 59:fe:1f:8b:d7:3d:60:86:85:24:6f:e3:11:b3:77: + 3e:20:96:35:21:6b:b3:08:d9:70:2e:64:f7:84:92: + 53:d6:0e:b0:90:8a:8a:e3:87:8d:06:d3:bd:90:0e: + e2:99:a1:1b:86:0e:da:9a:0a:bb:0b:61:50:06:52: + f1:9e:7f:76:ec:cb:0f:d0:1e:0d:cf:99:30:3d:1c: + c4:45:10:58:ac:d6:d3:e8:d7:e5:ea:c5:01:07:77: + d6:51:e6:03:7f:8a:48:a5:4d:68:75:b9:e9:bc:9e: + 4e:19:71:f5:32:4b:9c:6d:60:19:0b:fb:cc:9d:75: + dc:bf:26:cd:8f:93:78:39:79:73:5e:25:0e:ca:5c: + eb:77:12:07:cb:64:41:47:72:93:ab:50:c3:eb:09: + 76:64:34:d2:39:b7:76:11:09:0d:76:45:c4:a9:ae: + 3d:6a:af:b5:7d:65:2f:94:58:10:ec:5c:7c:af:7e: + e2:b6:18:d9:d0:9b:4e:5a:49:df:a9:66:0b:cc:3c: + c6:78:7c:a7:9c:1d:e3:ce:8e:53:be:05:de:60:0f: + 6b:e5:1a:db:3f:e3:e1:21:c9:29:c1:f1:eb:07:9c: + 52:1b:01:44:51:3c:7b:25:d7:c4:e5:52:54:5d:25: + 07:ca:16:20:b8:ad:e4:41:ee:7a:08:fe:99:6f:83: + a6:91:02:b0:6c:36:55:6a:e7:7d:f5:96:e6:ca:81: + d6:97:f1:94:83:e9:ed:b0:b1:6b:12:69:1e:ac:fb: + 5d:a9:c5:98:e9:b4:5b:58:7a:be:3d:a2:44:3a:63: + 59:d4:0b:25:de:1b:4f:bd:e5:01:9e:cd:d2:29:d5: + 9f:17:19:0a:6f:bf:0c:90:d3:09:5f:d9:e3:8a:35: + cc:79:5a:4d:19:37:92:b7:c4:c1:ad:af:f4:79:24: + 9a:b2:01:0b:b1:af:5c:96:f3:80:32:fb:5c:3d:98: + f1:a0:3f:4a:de:be:af:94:2e:d9:55:9a:17:6e:60: + 9d:63:6c:b8:63:c9:ae:81:5c:18:35:e0:90:bb:be: + 3c:4f:37:22:b9:7e:eb:cf:9e:77:21:a6:3d:38:81: + fb:48:da:31:3d:2b:e3:89:f5:d0:b5:bd:7e:e0:50: + c4:12:89:b3:23:9a:10:31:85:db:ae:6f:ef:38:33: + 18:76:11 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:12 + X509v3 Subject Key Identifier: + F9:24:AC:0F:B2:B5:F8:79:C0:FA:60:88:1B:C4:D9:4D:02:9E:17:19 + X509v3 Authority Key Identifier: + keyid:F9:24:AC:0F:B2:B5:F8:79:C0:FA:60:88:1B:C4:D9:4D:02:9E:17:19 + DirName:/C=EU/L=Madrid (see current address at www.camerfirma.com/address)/serialNumber=A82743287/O=AC Camerfirma S.A./CN=Chambers of Commerce Root - 2008 + serial:A3:DA:42:7E:A4:B1:AE:DA + + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: http://policy.camerfirma.com + + Signature Algorithm: sha1WithRSAEncryption + 90:12:af:22:35:c2:a3:39:f0:2e:de:e9:b5:e9:78:7c:48:be: + 3f:7d:45:92:5e:e9:da:b1:19:fc:16:3c:9f:b4:5b:66:9e:6a: + e7:c3:b9:5d:88:e8:0f:ad:cf:23:0f:de:25:3a:5e:cc:4f:a5: + c1:b5:2d:ac:24:d2:58:07:de:a2:cf:69:84:60:33:e8:10:0d: + 13:a9:23:d0:85:e5:8e:7b:a6:9e:3d:72:13:72:33:f5:aa:7d: + c6:63:1f:08:f4:fe:01:7f:24:cf:2b:2c:54:09:de:e2:2b:6d: + 92:c6:39:4f:16:ea:3c:7e:7a:46:d4:45:6a:46:a8:eb:75:82: + 56:a7:ab:a0:7c:68:13:33:f6:9d:30:f0:6f:27:39:24:23:2a: + 90:fd:90:29:35:f2:93:df:34:a5:c6:f7:f8:ef:8c:0f:62:4a: + 7c:ae:d3:f5:54:f8:8d:b6:9a:56:87:16:82:3a:33:ab:5a:22: + 08:f7:82:ba:ea:2e:e0:47:9a:b4:b5:45:a3:05:3b:d9:dc:2e: + 45:40:3b:ea:dc:7f:e8:3b:eb:d1:ec:26:d8:35:a4:30:c5:3a: + ac:57:9e:b3:76:a5:20:7b:f9:1e:4a:05:62:01:a6:28:75:60: + 97:92:0d:6e:3e:4d:37:43:0d:92:15:9c:18:22:cd:51:99:a0: + 29:1a:3c:5f:8a:32:33:5b:30:c7:89:2f:47:98:0f:a3:03:c6: + f6:f1:ac:df:32:f0:d9:81:1a:e4:9c:bd:f6:80:14:f0:d1:2c: + b9:85:f5:d8:a3:b1:c8:a5:21:e5:1c:13:97:ee:0e:bd:df:29: + a9:ef:34:53:5b:d3:e4:6a:13:84:06:b6:32:02:c4:52:ae:22: + d2:dc:b2:21:42:1a:da:40:f0:29:c9:ec:0a:0c:5c:e2:d0:ba: + cc:48:d3:37:0a:cc:12:0a:8a:79:b0:3d:03:7f:69:4b:f4:34: + 20:7d:b3:34:ea:8e:4b:64:f5:3e:fd:b3:23:67:15:0d:04:b8: + f0:2d:c1:09:51:3c:b2:6c:15:f0:a5:23:d7:83:74:e4:e5:2e: + c9:fe:98:27:42:c6:ab:c6:9e:b0:d0:5b:38:a5:9b:50:de:7e: + 18:98:b5:45:3b:f6:79:b4:e8:f7:1a:7b:06:83:fb:d0:8b:da: + bb:c7:bd:18:ab:08:6f:3c:80:6b:40:3f:19:19:ba:65:8a:e6: + be:d5:5c:d3:36:d7:ef:40:52:24:60:38:67:04:31:ec:8f:f3: + 82:c6:de:b9:55:f3:3b:31:91:5a:dc:b5:08:15:ad:76:25:0a: + 0d:7b:2e:87:e2:0c:a6:06:bc:26:10:6d:37:9d:ec:dd:78:8c: + 7c:80:c5:f0:d9:77:48:d0 +-----BEGIN CERTIFICATE----- +MIIHTzCCBTegAwIBAgIJAKPaQn6ksa7aMA0GCSqGSIb3DQEBBQUAMIGuMQswCQYD +VQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0 +IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3 +MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xKTAnBgNVBAMTIENoYW1iZXJz +IG9mIENvbW1lcmNlIFJvb3QgLSAyMDA4MB4XDTA4MDgwMTEyMjk1MFoXDTM4MDcz +MTEyMjk1MFowga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBj +dXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIw +EAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEp +MCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDgwggIiMA0G +CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCvAMtwNyuAWko6bHiUfaN/Gh/2NdW9 +28sNRHI+JrKQUrpjOyhYb6WzbZSm891kDFX29ufyIiKAXuFixrYp4YFs8r/lfTJq +VKAyGVn+H4vXPWCGhSRv4xGzdz4gljUha7MI2XAuZPeEklPWDrCQiorjh40G072Q +DuKZoRuGDtqaCrsLYVAGUvGef3bsyw/QHg3PmTA9HMRFEFis1tPo1+XqxQEHd9ZR +5gN/ikilTWh1uem8nk4ZcfUyS5xtYBkL+8ydddy/Js2Pk3g5eXNeJQ7KXOt3EgfL +ZEFHcpOrUMPrCXZkNNI5t3YRCQ12RcSprj1qr7V9ZS+UWBDsXHyvfuK2GNnQm05a +Sd+pZgvMPMZ4fKecHePOjlO+Bd5gD2vlGts/4+EhySnB8esHnFIbAURRPHsl18Tl +UlRdJQfKFiC4reRB7noI/plvg6aRArBsNlVq5331lubKgdaX8ZSD6e2wsWsSaR6s ++12pxZjptFtYer49okQ6Y1nUCyXeG0+95QGezdIp1Z8XGQpvvwyQ0wlf2eOKNcx5 +Wk0ZN5K3xMGtr/R5JJqyAQuxr1yW84Ay+1w9mPGgP0revq+ULtlVmhduYJ1jbLhj +ya6BXBg14JC7vjxPNyK5fuvPnnchpj04gftI2jE9K+OJ9dC1vX7gUMQSibMjmhAx +hduub+84Mxh2EQIDAQABo4IBbDCCAWgwEgYDVR0TAQH/BAgwBgEB/wIBDDAdBgNV +HQ4EFgQU+SSsD7K1+HnA+mCIG8TZTQKeFxkwgeMGA1UdIwSB2zCB2IAU+SSsD7K1 ++HnA+mCIG8TZTQKeFxmhgbSkgbEwga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpN +YWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29t +L2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVy +ZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAt +IDIwMDiCCQCj2kJ+pLGu2jAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRV +HSAAMCowKAYIKwYBBQUHAgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20w +DQYJKoZIhvcNAQEFBQADggIBAJASryI1wqM58C7e6bXpeHxIvj99RZJe6dqxGfwW +PJ+0W2aeaufDuV2I6A+tzyMP3iU6XsxPpcG1Lawk0lgH3qLPaYRgM+gQDROpI9CF +5Y57pp49chNyM/WqfcZjHwj0/gF/JM8rLFQJ3uIrbZLGOU8W6jx+ekbURWpGqOt1 +glanq6B8aBMz9p0w8G8nOSQjKpD9kCk18pPfNKXG9/jvjA9iSnyu0/VU+I22mlaH +FoI6M6taIgj3grrqLuBHmrS1RaMFO9ncLkVAO+rcf+g769HsJtg1pDDFOqxXnrN2 +pSB7+R5KBWIBpih1YJeSDW4+TTdDDZIVnBgizVGZoCkaPF+KMjNbMMeJL0eYD6MD +xvbxrN8y8NmBGuScvfaAFPDRLLmF9dijscilIeUcE5fuDr3fKanvNFNb0+RqE4QG +tjICxFKuItLcsiFCGtpA8CnJ7AoMXOLQusxI0zcKzBIKinmwPQN/aUv0NCB9szTq +jktk9T79syNnFQ0EuPAtwQlRPLJsFfClI9eDdOTlLsn+mCdCxqvGnrDQWzilm1De +fhiYtUU79nm06PcaewaD+9CL2rvHvRirCG88gGtAPxkZumWK5r7VXNM21+9AUiRg +OGcEMeyP84LG3rlV8zsxkVrctQgVrXYlCg17LofiDKYGvCYQbTed7N14jHyAxfDZ +d0jQ +-----END CERTIFICATE----- + +Global Chambersign Root - 2008 +# Issuer: CN=Global Chambersign Root - 2008,O=AC Camerfirma S.A.,serialNumber=A82743287,L=Madrid (see current address at www.camerfirma.com/address),C=EU +# Serial Number:00:c9:cd:d3:e9:d5:7d:23:ce +# Subject: CN=Global Chambersign Root - 2008,O=AC Camerfirma S.A.,serialNumber=A82743287,L=Madrid (see current address at www.camerfirma.com/address),C=EU +# Not Valid Before: Fri Aug 01 12:31:40 2008 +# Not Valid After : Sat Jul 31 12:31:40 2038 +# Fingerprint (MD5): 9E:80:FF:78:01:0C:2E:C1:36:BD:FE:96:90:6E:08:F3 +# Fingerprint (SHA1): 4A:BD:EE:EC:95:0D:35:9C:89:AE:C7:52:A1:2C:5B:29:F6:D6:AA:0C +MUST_VERIFY_TRUST: CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +================================================ +MD5 Fingerprint=9E:80:FF:78:01:0C:2E:C1:36:BD:FE:96:90:6E:08:F3 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + c9:cd:d3:e9:d5:7d:23:ce + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=EU, L=Madrid (see current address at www.camerfirma.com/address)/serialNumber=A82743287, O=AC Camerfirma S.A., CN=Global Chambersign Root - 2008 + Validity + Not Before: Aug 1 12:31:40 2008 GMT + Not After : Jul 31 12:31:40 2038 GMT + Subject: C=EU, L=Madrid (see current address at www.camerfirma.com/address)/serialNumber=A82743287, O=AC Camerfirma S.A., CN=Global Chambersign Root - 2008 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:c0:df:56:d3:e4:3a:9b:76:45:b4:13:db:ff:c1: + b6:19:8b:37:41:18:95:52:47:eb:17:9d:29:88:8e: + 35:6c:06:32:2e:47:62:f3:49:04:bf:7d:44:36:b1: + 71:cc:bd:5a:09:73:d5:d9:85:44:ff:91:57:25:df: + 5e:36:8e:70:d1:5c:71:43:1d:d9:da:ef:5c:d2:fb: + 1b:bd:3a:b5:cb:ad:a3:cc:44:a7:0d:ae:21:15:3f: + b9:7a:5b:92:75:d8:a4:12:38:89:19:8a:b7:80:d2: + e2:32:6f:56:9c:91:d6:88:10:0b:b3:74:64:92:74: + 60:f3:f6:cf:18:4f:60:b2:23:d0:c7:3b:ce:61:4b: + 99:8f:c2:0c:d0:40:b2:98:dc:0d:a8:4e:a3:b9:0a: + ae:60:a0:ad:45:52:63:ba:66:bd:68:e0:f9:be:1a: + a8:81:bb:1e:41:78:75:d3:c1:fe:00:55:b0:87:54: + e8:27:90:35:1d:4c:33:ad:97:fc:97:2e:98:84:bf: + 2c:c9:a3:bf:d1:98:11:14:ed:63:f8:ca:98:88:58: + 17:99:ed:45:03:97:7e:3c:86:1e:88:8c:be:f2:91: + 84:8f:65:34:d8:00:4c:7d:b7:31:17:5a:29:7a:0a: + 18:24:30:a3:37:b5:7a:a9:01:7d:26:d6:f9:0e:8e: + 59:f1:fd:1b:33:b5:29:3b:17:3b:41:b6:21:dd:d4: + c0:3d:a5:9f:9f:1f:43:50:c9:bb:bc:6c:7a:97:98: + ee:cd:8c:1f:fb:9c:51:ae:8b:70:bd:27:9f:71:c0: + 6b:ac:7d:90:66:e8:d7:5d:3a:0d:b0:d5:c2:8d:d5: + c8:9d:9d:c1:6d:d0:d0:bf:51:e4:e3:f8:c3:38:36: + ae:d6:a7:75:e6:af:84:43:5d:93:92:0c:6a:07:de: + 3b:1d:98:22:d6:ac:c1:35:db:a3:a0:25:ff:72:b5: + 76:1d:de:6d:e9:2c:66:2c:52:84:d0:45:92:ce:1c: + e5:e5:33:1d:dc:07:53:54:a3:aa:82:3b:9a:37:2f: + dc:dd:a0:64:e9:e6:dd:bd:ae:fc:64:85:1d:3c:a7: + c9:06:de:84:ff:6b:e8:6b:1a:3c:c5:a2:b3:42:fb: + 8b:09:3e:5f:08:52:c7:62:c4:d4:05:71:bf:c4:64: + e4:f8:a1:83:e8:3e:12:9b:a8:1e:d4:36:4d:2f:71: + f6:8d:28:f6:83:a9:13:d2:61:c1:91:bb:48:c0:34: + 8f:41:8c:4b:4c:db:69:12:ff:50:94:9c:20:83:59: + 73:ed:7c:a1:f2:f1:fd:dd:f7:49:d3:43:58:a0:56: + 63:ca:3d:3d:e5:35:56:59:e9:0e:ca:20:cc:2b:4b: + 93:29:0f + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:12 + X509v3 Subject Key Identifier: + B9:09:CA:9C:1E:DB:D3:6C:3A:6B:AE:ED:54:F1:5B:93:06:35:2E:5E + X509v3 Authority Key Identifier: + keyid:B9:09:CA:9C:1E:DB:D3:6C:3A:6B:AE:ED:54:F1:5B:93:06:35:2E:5E + DirName:/C=EU/L=Madrid (see current address at www.camerfirma.com/address)/serialNumber=A82743287/O=AC Camerfirma S.A./CN=Global Chambersign Root - 2008 + serial:C9:CD:D3:E9:D5:7D:23:CE + + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: http://policy.camerfirma.com + + Signature Algorithm: sha1WithRSAEncryption + 80:88:7f:70:de:92:28:d9:05:94:46:ff:90:57:a9:f1:2f:df: + 1a:0d:6b:fa:7c:0e:1c:49:24:79:27:d8:46:aa:6f:29:59:52: + 88:70:12:ea:dd:3d:f5:9b:53:54:6f:e1:60:a2:a8:09:b9:ec: + eb:59:7c:c6:35:f1:dc:18:e9:f1:67:e5:af:ba:45:e0:09:de: + ca:44:0f:c2:17:0e:77:91:45:7a:33:5f:5f:96:2c:68:8b:c1: + 47:8f:98:9b:3d:c0:ec:cb:f5:d5:82:92:84:35:d1:be:36:38: + 56:72:31:5b:47:2d:aa:17:a4:63:51:eb:0a:01:ad:7f:ec:75: + 9e:cb:a1:1f:f1:7f:12:b1:b9:e4:64:7f:67:d6:23:2a:f4:b8: + 39:5d:98:e8:21:a7:e1:bd:3d:42:1a:74:9a:70:af:68:6c:50: + 5d:49:cf:ff:fb:0e:5d:e6:2c:47:d7:81:3a:59:00:b5:73:6b: + 63:20:f6:31:45:08:39:0e:f4:70:7e:40:70:5a:3f:d0:6b:42: + a9:74:3d:28:2f:02:6d:75:72:95:09:8d:48:63:c6:c6:23:57: + 92:93:5e:35:c1:8d:f9:0a:f7:2c:9d:62:1c:f6:ad:7c:dd:a6: + 31:1e:b6:b1:c7:7e:85:26:fa:a4:6a:b5:da:63:30:d1:ef:93: + 37:b2:66:2f:7d:05:f7:e7:b7:4b:98:94:35:c0:d9:3a:29:c1: + 9d:b2:50:33:1d:4a:a9:5a:a6:c9:03:ef:ed:f4:e7:a8:6e:8a: + b4:57:84:eb:a4:3f:d0:ee:aa:aa:87:5b:63:e8:93:e2:6b:a8: + d4:b8:72:78:6b:1b:ed:39:e4:5d:cb:9b:aa:87:d5:4f:4e:00: + fe:d9:6a:9f:3c:31:0f:28:02:01:7d:98:e8:a7:b0:a2:64:9e: + 79:f8:48:f2:15:a9:cc:e6:c8:44:eb:3f:78:99:f2:7b:71:3e: + 3c:f1:98:a7:c5:18:12:3f:e6:bb:28:33:42:e9:45:0a:7c:6d: + f2:86:79:2f:c5:82:19:7d:09:89:7c:b2:54:76:88:ae:de:c1: + f3:cc:e1:6e:db:31:d6:93:ae:99:a0:ef:25:6a:73:98:89:5b: + 3a:2e:13:88:1e:bf:c0:92:94:34:1b:e3:27:b7:8b:1e:6f:42: + ff:e7:e9:37:9b:50:1d:2d:a2:f9:02:ee:cb:58:58:3a:71:bc: + 68:e3:aa:c1:af:1c:28:1f:a2:dc:23:65:3f:81:ea:ae:99:d3: + d8:30:cf:13:0d:4f:15:c9:84:bc:a7:48:2d:f8:30:23:77:d8: + 46:4b:79:6d:f6:8c:ed:3a:7f:60:11:78:f4:e9:9b:ae:d5:54: + c0:74:80:d1:0b:42:9f:c1 +-----BEGIN CERTIFICATE----- +MIIHSTCCBTGgAwIBAgIJAMnN0+nVfSPOMA0GCSqGSIb3DQEBBQUAMIGsMQswCQYD +VQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0 +IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3 +MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAlBgNVBAMTHkdsb2JhbCBD +aGFtYmVyc2lnbiBSb290IC0gMjAwODAeFw0wODA4MDExMjMxNDBaFw0zODA3MzEx +MjMxNDBaMIGsMQswCQYDVQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3Vy +cmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAG +A1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAl +BgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAwODCCAiIwDQYJKoZI +hvcNAQEBBQADggIPADCCAgoCggIBAMDfVtPkOpt2RbQT2//BthmLN0EYlVJH6xed +KYiONWwGMi5HYvNJBL99RDaxccy9Wglz1dmFRP+RVyXfXjaOcNFccUMd2drvXNL7 +G706tcuto8xEpw2uIRU/uXpbknXYpBI4iRmKt4DS4jJvVpyR1ogQC7N0ZJJ0YPP2 +zxhPYLIj0Mc7zmFLmY/CDNBAspjcDahOo7kKrmCgrUVSY7pmvWjg+b4aqIG7HkF4 +ddPB/gBVsIdU6CeQNR1MM62X/JcumIS/LMmjv9GYERTtY/jKmIhYF5ntRQOXfjyG +HoiMvvKRhI9lNNgATH23MRdaKXoKGCQwoze1eqkBfSbW+Q6OWfH9GzO1KTsXO0G2 +Id3UwD2ln58fQ1DJu7xsepeY7s2MH/ucUa6LcL0nn3HAa6x9kGbo1106DbDVwo3V +yJ2dwW3Q0L9R5OP4wzg2rtandeavhENdk5IMagfeOx2YItaswTXbo6Al/3K1dh3e +beksZixShNBFks4c5eUzHdwHU1SjqoI7mjcv3N2gZOnm3b2u/GSFHTynyQbehP9r +6GsaPMWis0L7iwk+XwhSx2LE1AVxv8Rk5Pihg+g+EpuoHtQ2TS9x9o0o9oOpE9Jh +wZG7SMA0j0GMS0zbaRL/UJScIINZc+18ofLx/d33SdNDWKBWY8o9PeU1VlnpDsog +zCtLkykPAgMBAAGjggFqMIIBZjASBgNVHRMBAf8ECDAGAQH/AgEMMB0GA1UdDgQW +BBS5CcqcHtvTbDprru1U8VuTBjUuXjCB4QYDVR0jBIHZMIHWgBS5CcqcHtvTbDpr +ru1U8VuTBjUuXqGBsqSBrzCBrDELMAkGA1UEBhMCRVUxQzBBBgNVBAcTOk1hZHJp +ZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2FtZXJmaXJtYS5jb20vYWRk +cmVzcykxEjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UEChMSQUMgQ2FtZXJmaXJt +YSBTLkEuMScwJQYDVQQDEx5HbG9iYWwgQ2hhbWJlcnNpZ24gUm9vdCAtIDIwMDiC +CQDJzdPp1X0jzjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCow +KAYIKwYBBQUHAgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZI +hvcNAQEFBQADggIBAICIf3DekijZBZRG/5BXqfEv3xoNa/p8DhxJJHkn2EaqbylZ +UohwEurdPfWbU1Rv4WCiqAm57OtZfMY18dwY6fFn5a+6ReAJ3spED8IXDneRRXoz +X1+WLGiLwUePmJs9wOzL9dWCkoQ10b42OFZyMVtHLaoXpGNR6woBrX/sdZ7LoR/x +fxKxueRkf2fWIyr0uDldmOghp+G9PUIadJpwr2hsUF1Jz//7Dl3mLEfXgTpZALVz +a2Mg9jFFCDkO9HB+QHBaP9BrQql0PSgvAm11cpUJjUhjxsYjV5KTXjXBjfkK9yyd +Yhz2rXzdpjEetrHHfoUm+qRqtdpjMNHvkzeyZi99Bffnt0uYlDXA2TopwZ2yUDMd +SqlapskD7+3056huirRXhOukP9DuqqqHW2Pok+JrqNS4cnhrG+055F3Lm6qH1U9O +AP7Zap88MQ8oAgF9mOinsKJknnn4SPIVqczmyETrP3iZ8ntxPjzxmKfFGBI/5rso +M0LpRQp8bfKGeS/Fghl9CYl8slR2iK7ewfPM4W7bMdaTrpmg7yVqc5iJWzouE4ge +v8CSlDQb4ye3ix5vQv/n6TebUB0tovkC7stYWDpxvGjjqsGvHCgfotwjZT+B6q6Z +09gwzxMNTxXJhLynSC34MCN32EZLeW32jO06f2ARePTpm67VVMB0gNELQp/B +-----END CERTIFICATE----- + +Go Daddy Root Certificate Authority - G2 +# Issuer: CN=Go Daddy Root Certificate Authority - G2,O="GoDaddy.com, Inc.",L=Scottsdale,ST=Arizona,C=US +# Serial Number: 0 (0x0) +# Subject: CN=Go Daddy Root Certificate Authority - G2,O="GoDaddy.com, Inc.",L=Scottsdale,ST=Arizona,C=US +# Not Valid Before: Tue Sep 01 00:00:00 2009 +# Not Valid After : Thu Dec 31 23:59:59 2037 +# Fingerprint (MD5): 80:3A:BC:22:C1:E6:FB:8D:9B:3B:27:4A:32:1B:9A:01 +# Fingerprint (SHA1): 47:BE:AB:C9:22:EA:E8:0E:78:78:34:62:A7:9F:45:C2:54:FD:E6:8B +MUST_VERIFY_TRUST: EMAIL_PROTECTION, CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH +================================================= +MD5 Fingerprint=80:3A:BC:22:C1:E6:FB:8D:9B:3B:27:4A:32:1B:9A:01 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 0 (0x0) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, ST=Arizona, L=Scottsdale, O=GoDaddy.com, Inc., CN=Go Daddy Root Certificate Authority - G2 + Validity + Not Before: Sep 1 00:00:00 2009 GMT + Not After : Dec 31 23:59:59 2037 GMT + Subject: C=US, ST=Arizona, L=Scottsdale, O=GoDaddy.com, Inc., CN=Go Daddy Root Certificate Authority - G2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:bf:71:62:08:f1:fa:59:34:f7:1b:c9:18:a3:f7: + 80:49:58:e9:22:83:13:a6:c5:20:43:01:3b:84:f1: + e6:85:49:9f:27:ea:f6:84:1b:4e:a0:b4:db:70:98: + c7:32:01:b1:05:3e:07:4e:ee:f4:fa:4f:2f:59:30: + 22:e7:ab:19:56:6b:e2:80:07:fc:f3:16:75:80:39: + 51:7b:e5:f9:35:b6:74:4e:a9:8d:82:13:e4:b6:3f: + a9:03:83:fa:a2:be:8a:15:6a:7f:de:0b:c3:b6:19: + 14:05:ca:ea:c3:a8:04:94:3b:46:7c:32:0d:f3:00: + 66:22:c8:8d:69:6d:36:8c:11:18:b7:d3:b2:1c:60: + b4:38:fa:02:8c:ce:d3:dd:46:07:de:0a:3e:eb:5d: + 7c:c8:7c:fb:b0:2b:53:a4:92:62:69:51:25:05:61: + 1a:44:81:8c:2c:a9:43:96:23:df:ac:3a:81:9a:0e: + 29:c5:1c:a9:e9:5d:1e:b6:9e:9e:30:0a:39:ce:f1: + 88:80:fb:4b:5d:cc:32:ec:85:62:43:25:34:02:56: + 27:01:91:b4:3b:70:2a:3f:6e:b1:e8:9c:88:01:7d: + 9f:d4:f9:db:53:6d:60:9d:bf:2c:e7:58:ab:b8:5f: + 46:fc:ce:c4:1b:03:3c:09:eb:49:31:5c:69:46:b3: + e0:47 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 3A:9A:85:07:10:67:28:B6:EF:F6:BD:05:41:6E:20:C1:94:DA:0F:DE + Signature Algorithm: sha256WithRSAEncryption + 99:db:5d:79:d5:f9:97:59:67:03:61:f1:7e:3b:06:31:75:2d: + a1:20:8e:4f:65:87:b4:f7:a6:9c:bc:d8:e9:2f:d0:db:5a:ee: + cf:74:8c:73:b4:38:42:da:05:7b:f8:02:75:b8:fd:a5:b1:d7: + ae:f6:d7:de:13:cb:53:10:7e:8a:46:d1:97:fa:b7:2e:2b:11: + ab:90:b0:27:80:f9:e8:9f:5a:e9:37:9f:ab:e4:df:6c:b3:85: + 17:9d:3d:d9:24:4f:79:91:35:d6:5f:04:eb:80:83:ab:9a:02: + 2d:b5:10:f4:d8:90:c7:04:73:40:ed:72:25:a0:a9:9f:ec:9e: + ab:68:12:99:57:c6:8f:12:3a:09:a4:bd:44:fd:06:15:37:c1: + 9b:e4:32:a3:ed:38:e8:d8:64:f3:2c:7e:14:fc:02:ea:9f:cd: + ff:07:68:17:db:22:90:38:2d:7a:8d:d1:54:f1:69:e3:5f:33: + ca:7a:3d:7b:0a:e3:ca:7f:5f:39:e5:e2:75:ba:c5:76:18:33: + ce:2c:f0:2f:4c:ad:f7:b1:e7:ce:4f:a8:c4:9b:4a:54:06:c5: + 7f:7d:d5:08:0f:e2:1c:fe:7e:17:b8:ac:5e:f6:d4:16:b2:43: + 09:0c:4d:f6:a7:6b:b4:99:84:65:ca:7a:88:e2:e2:44:be:5c: + f7:ea:1c:f5 +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT +EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp +ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIz +NTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH +EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UE +AxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKD +E6bFIEMBO4Tx5oVJnyfq9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH +/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD+qK+ihVqf94Lw7YZFAXK6sOoBJQ7Rnwy +DfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutdfMh8+7ArU6SSYmlRJQVh +GkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMlNAJWJwGR +tDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEA +AaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE +FDqahQcQZyi27/a9BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmX +WWcDYfF+OwYxdS2hII5PZYe096acvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu +9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r5N9ss4UXnT3ZJE95kTXWXwTr +gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo +2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO +LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI +4uJEvlz36hz1 +-----END CERTIFICATE----- + +Starfield Root Certificate Authority - G2 +# Issuer: CN=Starfield Root Certificate Authority - G2,O="Starfield Technologies, Inc.",L=Scottsdale,ST=Arizona,C=US +# Serial Number: 0 (0x0) +# Subject: CN=Starfield Root Certificate Authority - G2,O="Starfield Technologies, Inc.",L=Scottsdale,ST=Arizona,C=US +# Not Valid Before: Tue Sep 01 00:00:00 2009 +# Not Valid After : Thu Dec 31 23:59:59 2037 +# Fingerprint (MD5): D6:39:81:C6:52:7E:96:69:FC:FC:CA:66:ED:05:F2:96 +# Fingerprint (SHA1): B5:1C:06:7C:EE:2B:0C:3D:F8:55:AB:2D:92:F4:FE:39:D4:E7:0F:0E +TRUSTED_DELEGATOR: SERVER_AUTH +MUST_VERIFY_TRUST: EMAIL_PROTECTION, CODE_SIGNING +================================================= +MD5 Fingerprint=D6:39:81:C6:52:7E:96:69:FC:FC:CA:66:ED:05:F2:96 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 0 (0x0) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, ST=Arizona, L=Scottsdale, O=Starfield Technologies, Inc., CN=Starfield Root Certificate Authority - G2 + Validity + Not Before: Sep 1 00:00:00 2009 GMT + Not After : Dec 31 23:59:59 2037 GMT + Subject: C=US, ST=Arizona, L=Scottsdale, O=Starfield Technologies, Inc., CN=Starfield Root Certificate Authority - G2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:bd:ed:c1:03:fc:f6:8f:fc:02:b1:6f:5b:9f:48: + d9:9d:79:e2:a2:b7:03:61:56:18:c3:47:b6:d7:ca: + 3d:35:2e:89:43:f7:a1:69:9b:de:8a:1a:fd:13:20: + 9c:b4:49:77:32:29:56:fd:b9:ec:8c:dd:22:fa:72: + dc:27:61:97:ee:f6:5a:84:ec:6e:19:b9:89:2c:dc: + 84:5b:d5:74:fb:6b:5f:c5:89:a5:10:52:89:46:55: + f4:b8:75:1c:e6:7f:e4:54:ae:4b:f8:55:72:57:02: + 19:f8:17:71:59:eb:1e:28:07:74:c5:9d:48:be:6c: + b4:f4:a4:b0:f3:64:37:79:92:c0:ec:46:5e:7f:e1: + 6d:53:4c:62:af:cd:1f:0b:63:bb:3a:9d:fb:fc:79: + 00:98:61:74:cf:26:82:40:63:f3:b2:72:6a:19:0d: + 99:ca:d4:0e:75:cc:37:fb:8b:89:c1:59:f1:62:7f: + 5f:b3:5f:65:30:f8:a7:b7:4d:76:5a:1e:76:5e:34: + c0:e8:96:56:99:8a:b3:f0:7f:a4:cd:bd:dc:32:31: + 7c:91:cf:e0:5f:11:f8:6b:aa:49:5c:d1:99:94:d1: + a2:e3:63:5b:09:76:b5:56:62:e1:4b:74:1d:96:d4: + 26:d4:08:04:59:d0:98:0e:0e:e6:de:fc:c3:ec:1f: + 90:f1 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 7C:0C:32:1F:A7:D9:30:7F:C4:7D:68:A3:62:A8:A1:CE:AB:07:5B:27 + Signature Algorithm: sha256WithRSAEncryption + 11:59:fa:25:4f:03:6f:94:99:3b:9a:1f:82:85:39:d4:76:05: + 94:5e:e1:28:93:6d:62:5d:09:c2:a0:a8:d4:b0:75:38:f1:34: + 6a:9d:e4:9f:8a:86:26:51:e6:2c:d1:c6:2d:6e:95:20:4a:92: + 01:ec:b8:8a:67:7b:31:e2:67:2e:8c:95:03:26:2e:43:9d:4a: + 31:f6:0e:b5:0c:bb:b7:e2:37:7f:22:ba:00:a3:0e:7b:52:fb: + 6b:bb:3b:c4:d3:79:51:4e:cd:90:f4:67:07:19:c8:3c:46:7a: + 0d:01:7d:c5:58:e7:6d:e6:85:30:17:9a:24:c4:10:e0:04:f7: + e0:f2:7f:d4:aa:0a:ff:42:1d:37:ed:94:e5:64:59:12:20:77: + 38:d3:32:3e:38:81:75:96:73:fa:68:8f:b1:cb:ce:1f:c5:ec: + fa:9c:7e:cf:7e:b1:f1:07:2d:b6:fc:bf:ca:a4:bf:d0:97:05: + 4a:bc:ea:18:28:02:90:bd:54:78:09:21:71:d3:d1:7d:1d:d9: + 16:b0:a9:61:3d:d0:0a:00:22:fc:c7:7b:cb:09:64:45:0b:3b: + 40:81:f7:7d:7c:32:f5:98:ca:58:8e:7d:2a:ee:90:59:73:64: + f9:36:74:5e:25:a1:f5:66:05:2e:7f:39:15:a9:2a:fb:50:8b: + 8e:85:69:f4 +-----BEGIN CERTIFICATE----- +MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT +HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs +ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw +MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 +b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj +aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp +Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg +nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1 +HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N +Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN +dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0 +HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO +BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G +CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU +sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3 +4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg +8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K +pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1 +mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 +-----END CERTIFICATE----- + +Starfield Services Root Certificate Authority - G2 +# Issuer: CN=Starfield Services Root Certificate Authority - G2,O="Starfield Technologies, Inc.",L=Scottsdale,ST=Arizona,C=US +# Serial Number: 0 (0x0) +# Subject: CN=Starfield Services Root Certificate Authority - G2,O="Starfield Technologies, Inc.",L=Scottsdale,ST=Arizona,C=US +# Not Valid Before: Tue Sep 01 00:00:00 2009 +# Not Valid After : Thu Dec 31 23:59:59 2037 +# Fingerprint (MD5): 17:35:74:AF:7B:61:1C:EB:F4:F9:3C:E2:EE:40:F9:A2 +# Fingerprint (SHA1): 92:5A:8F:8D:2C:6D:04:E0:66:5F:59:6A:FF:22:D8:63:E8:25:6F:3F +TRUSTED_DELEGATOR: SERVER_AUTH +MUST_VERIFY_TRUST: EMAIL_PROTECTION, CODE_SIGNING +================================================== +MD5 Fingerprint=17:35:74:AF:7B:61:1C:EB:F4:F9:3C:E2:EE:40:F9:A2 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 0 (0x0) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, ST=Arizona, L=Scottsdale, O=Starfield Technologies, Inc., CN=Starfield Services Root Certificate Authority - G2 + Validity + Not Before: Sep 1 00:00:00 2009 GMT + Not After : Dec 31 23:59:59 2037 GMT + Subject: C=US, ST=Arizona, L=Scottsdale, O=Starfield Technologies, Inc., CN=Starfield Services Root Certificate Authority - G2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:d5:0c:3a:c4:2a:f9:4e:e2:f5:be:19:97:5f:8e: + 88:53:b1:1f:3f:cb:cf:9f:20:13:6d:29:3a:c8:0f: + 7d:3c:f7:6b:76:38:63:d9:36:60:a8:9b:5e:5c:00: + 80:b2:2f:59:7f:f6:87:f9:25:43:86:e7:69:1b:52: + 9a:90:e1:71:e3:d8:2d:0d:4e:6f:f6:c8:49:d9:b6: + f3:1a:56:ae:2b:b6:74:14:eb:cf:fb:26:e3:1a:ba: + 1d:96:2e:6a:3b:58:94:89:47:56:ff:25:a0:93:70: + 53:83:da:84:74:14:c3:67:9e:04:68:3a:df:8e:40: + 5a:1d:4a:4e:cf:43:91:3b:e7:56:d6:00:70:cb:52: + ee:7b:7d:ae:3a:e7:bc:31:f9:45:f6:c2:60:cf:13: + 59:02:2b:80:cc:34:47:df:b9:de:90:65:6d:02:cf: + 2c:91:a6:a6:e7:de:85:18:49:7c:66:4e:a3:3a:6d: + a9:b5:ee:34:2e:ba:0d:03:b8:33:df:47:eb:b1:6b: + 8d:25:d9:9b:ce:81:d1:45:46:32:96:70:87:de:02: + 0e:49:43:85:b6:6c:73:bb:64:ea:61:41:ac:c9:d4: + 54:df:87:2f:c7:22:b2:26:cc:9f:59:54:68:9f:fc: + be:2a:2f:c4:55:1c:75:40:60:17:85:02:55:39:8b: + 7f:05 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 9C:5F:00:DF:AA:01:D7:30:2B:38:88:A2:B8:6D:4A:9C:F2:11:91:83 + Signature Algorithm: sha256WithRSAEncryption + 4b:36:a6:84:77:69:dd:3b:19:9f:67:23:08:6f:0e:61:c9:fd: + 84:dc:5f:d8:36:81:cd:d8:1b:41:2d:9f:60:dd:c7:1a:68:d9: + d1:6e:86:e1:88:23:cf:13:de:43:cf:e2:34:b3:04:9d:1f:29: + d5:bf:f8:5e:c8:d5:c1:bd:ee:92:6f:32:74:f2:91:82:2f:bd: + 82:42:7a:ad:2a:b7:20:7d:4d:bc:7a:55:12:c2:15:ea:bd:f7: + 6a:95:2e:6c:74:9f:cf:1c:b4:f2:c5:01:a3:85:d0:72:3e:ad: + 73:ab:0b:9b:75:0c:6d:45:b7:8e:94:ac:96:37:b5:a0:d0:8f: + 15:47:0e:e3:e8:83:dd:8f:fd:ef:41:01:77:cc:27:a9:62:85: + 33:f2:37:08:ef:71:cf:77:06:de:c8:19:1d:88:40:cf:7d:46: + 1d:ff:1e:c7:e1:ce:ff:23:db:c6:fa:8d:55:4e:a9:02:e7:47: + 11:46:3e:f4:fd:bd:7b:29:26:bb:a9:61:62:37:28:b6:2d:2a: + f6:10:86:64:c9:70:a7:d2:ad:b7:29:70:79:ea:3c:da:63:25: + 9f:fd:68:b7:30:ec:70:fb:75:8a:b7:6d:60:67:b2:1e:c8:b9: + e9:d8:a8:6f:02:8b:67:0d:4d:26:57:71:da:20:fc:c1:4a:50: + 8d:b1:28:ba +-----BEGIN CERTIFICATE----- +MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT +HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVs +ZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5 +MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNVBAYTAlVTMRAwDgYD +VQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFy +ZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2Vy +dmljZXMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20p +OsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm2 +8xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4PahHQUw2eeBGg6345AWh1K +Ts9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLPLJGmpufe +hRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk +6mFBrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAw +DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+q +AdcwKziIorhtSpzyEZGDMA0GCSqGSIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMI +bw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPPE95Dz+I0swSdHynVv/heyNXB +ve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTyxQGjhdByPq1z +qwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd +iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn +0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCN +sSi6 +-----END CERTIFICATE----- + +AffirmTrust Commercial +# Issuer: CN=AffirmTrust Commercial,O=AffirmTrust,C=US +# Serial Number:77:77:06:27:26:a9:b1:7c +# Subject: CN=AffirmTrust Commercial,O=AffirmTrust,C=US +# Not Valid Before: Fri Jan 29 14:06:06 2010 +# Not Valid After : Tue Dec 31 14:06:06 2030 +# Fingerprint (MD5): 82:92:BA:5B:EF:CD:8A:6F:A6:3D:55:F9:84:F6:D6:B7 +# Fingerprint (SHA1): F9:B5:B6:32:45:5F:9C:BE:EC:57:5F:80:DC:E9:6E:2C:C7:B2:78:B7 +MUST_VERIFY_TRUST: EMAIL_PROTECTION, CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH +================================================= +MD5 Fingerprint=82:92:BA:5B:EF:CD:8A:6F:A6:3D:55:F9:84:F6:D6:B7 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 8608355977964138876 (0x7777062726a9b17c) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=AffirmTrust, CN=AffirmTrust Commercial + Validity + Not Before: Jan 29 14:06:06 2010 GMT + Not After : Dec 31 14:06:06 2030 GMT + Subject: C=US, O=AffirmTrust, CN=AffirmTrust Commercial + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:f6:1b:4f:67:07:2b:a1:15:f5:06:22:cb:1f:01: + b2:e3:73:45:06:44:49:2c:bb:49:25:14:d6:ce:c3: + b7:ab:2c:4f:c6:41:32:94:57:fa:12:a7:5b:0e:e2: + 8f:1f:1e:86:19:a7:aa:b5:2d:b9:5f:0d:8a:c2:af: + 85:35:79:32:2d:bb:1c:62:37:f2:b1:5b:4a:3d:ca: + cd:71:5f:e9:42:be:94:e8:c8:de:f9:22:48:64:c6: + e5:ab:c6:2b:6d:ad:05:f0:fa:d5:0b:cf:9a:e5:f0: + 50:a4:8b:3b:47:a5:23:5b:7a:7a:f8:33:3f:b8:ef: + 99:97:e3:20:c1:d6:28:89:cf:94:fb:b9:45:ed:e3: + 40:17:11:d4:74:f0:0b:31:e2:2b:26:6a:9b:4c:57: + ae:ac:20:3e:ba:45:7a:05:f3:bd:9b:69:15:ae:7d: + 4e:20:63:c4:35:76:3a:07:02:c9:37:fd:c7:47:ee: + e8:f1:76:1d:73:15:f2:97:a4:b5:c8:7a:79:d9:42: + aa:2b:7f:5c:fe:ce:26:4f:a3:66:81:35:af:44:ba: + 54:1e:1c:30:32:65:9d:e6:3c:93:5e:50:4e:7a:e3: + 3a:d4:6e:cc:1a:fb:f9:d2:37:ae:24:2a:ab:57:03: + 22:28:0d:49:75:7f:b7:28:da:75:bf:8e:e3:dc:0e: + 79:31 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + 9D:93:C6:53:8B:5E:CA:AF:3F:9F:1E:0F:E5:99:95:BC:24:F6:94:8F + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + Signature Algorithm: sha256WithRSAEncryption + 58:ac:f4:04:0e:cd:c0:0d:ff:0a:fd:d4:ba:16:5f:29:bd:7b: + 68:99:58:49:d2:b4:1d:37:4d:7f:27:7d:46:06:5d:43:c6:86: + 2e:3e:73:b2:26:7d:4f:93:a9:b6:c4:2a:9a:ab:21:97:14:b1: + de:8c:d3:ab:89:15:d8:6b:24:d4:f1:16:ae:d8:a4:5c:d4:7f: + 51:8e:ed:18:01:b1:93:63:bd:bc:f8:61:80:9a:9e:b1:ce:42: + 70:e2:a9:7d:06:25:7d:27:a1:fe:6f:ec:b3:1e:24:da:e3:4b: + 55:1a:00:3b:35:b4:3b:d9:d7:5d:30:fd:81:13:89:f2:c2:06: + 2b:ed:67:c4:8e:c9:43:b2:5c:6b:15:89:02:bc:62:fc:4e:f2: + b5:33:aa:b2:6f:d3:0a:a2:50:e3:f6:3b:e8:2e:44:c2:db:66: + 38:a9:33:56:48:f1:6d:1b:33:8d:0d:8c:3f:60:37:9d:d3:ca: + 6d:7e:34:7e:0d:9f:72:76:8b:1b:9f:72:fd:52:35:41:45:02: + 96:2f:1c:b2:9a:73:49:21:b1:49:47:45:47:b4:ef:6a:34:11: + c9:4d:9a:cc:59:b7:d6:02:9e:5a:4e:65:b5:94:ae:1b:df:29: + b0:16:f1:bf:00:9e:07:3a:17:64:b5:04:b5:23:21:99:0a:95: + 3b:97:7c:ef +-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE +BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz +dCBDb21tZXJjaWFsMB4XDTEwMDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDEL +MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp +cm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6EqdbDuKP +Hx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yr +ba0F8PrVC8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPAL +MeIrJmqbTFeurCA+ukV6BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1 +yHp52UKqK39c/s4mT6NmgTWvRLpUHhwwMmWd5jyTXlBOeuM61G7MGvv50jeuJCqr +VwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNVHQ4EFgQUnZPGU4teyq8/ +nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ +KoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYG +XUPGhi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNj +vbz4YYCanrHOQnDiqX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivt +Z8SOyUOyXGsViQK8YvxO8rUzqrJv0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9g +N53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0khsUlHRUe072o0EclNmsxZt9YC +nlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8= +-----END CERTIFICATE----- + +AffirmTrust Networking +# Issuer: CN=AffirmTrust Networking,O=AffirmTrust,C=US +# Serial Number:7c:4f:04:39:1c:d4:99:2d +# Subject: CN=AffirmTrust Networking,O=AffirmTrust,C=US +# Not Valid Before: Fri Jan 29 14:08:24 2010 +# Not Valid After : Tue Dec 31 14:08:24 2030 +# Fingerprint (MD5): 42:65:CA:BE:01:9A:9A:4C:A9:8C:41:49:CD:C0:D5:7F +# Fingerprint (SHA1): 29:36:21:02:8B:20:ED:02:F5:66:C5:32:D1:D6:ED:90:9F:45:00:2F +MUST_VERIFY_TRUST: EMAIL_PROTECTION, CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH +================================================= +MD5 Fingerprint=42:65:CA:BE:01:9A:9A:4C:A9:8C:41:49:CD:C0:D5:7F +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 8957382827206547757 (0x7c4f04391cd4992d) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=AffirmTrust, CN=AffirmTrust Networking + Validity + Not Before: Jan 29 14:08:24 2010 GMT + Not After : Dec 31 14:08:24 2030 GMT + Subject: C=US, O=AffirmTrust, CN=AffirmTrust Networking + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:b4:84:cc:33:17:2e:6b:94:6c:6b:61:52:a0:eb: + a3:cf:79:94:4c:e5:94:80:99:cb:55:64:44:65:8f: + 67:64:e2:06:e3:5c:37:49:f6:2f:9b:84:84:1e:2d: + f2:60:9d:30:4e:cc:84:85:e2:2c:cf:1e:9e:fe:36: + ab:33:77:35:44:d8:35:96:1a:3d:36:e8:7a:0e:d8: + d5:47:a1:6a:69:8b:d9:fc:bb:3a:ae:79:5a:d5:f4: + d6:71:bb:9a:90:23:6b:9a:b7:88:74:87:0c:1e:5f: + b9:9e:2d:fa:ab:53:2b:dc:bb:76:3e:93:4c:08:08: + 8c:1e:a2:23:1c:d4:6a:ad:22:ba:99:01:2e:6d:65: + cb:be:24:66:55:24:4b:40:44:b1:1b:d7:e1:c2:85: + c0:de:10:3f:3d:ed:b8:fc:f1:f1:23:53:dc:bf:65: + 97:6f:d9:f9:40:71:8d:7d:bd:95:d4:ce:be:a0:5e: + 27:23:de:fd:a6:d0:26:0e:00:29:eb:3c:46:f0:3d: + 60:bf:3f:50:d2:dc:26:41:51:9e:14:37:42:04:a3: + 70:57:a8:1b:87:ed:2d:fa:7b:ee:8c:0a:e3:a9:66: + 89:19:cb:41:f9:dd:44:36:61:cf:e2:77:46:c8:7d: + f6:f4:92:81:36:fd:db:34:f1:72:7e:f3:0c:16:bd: + b4:15 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + 07:1F:D2:E7:9C:DA:C2:6E:A2:40:B4:B0:7A:50:10:50:74:C4:C8:BD + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + Signature Algorithm: sha1WithRSAEncryption + 89:57:b2:16:7a:a8:c2:fd:d6:d9:9b:9b:34:c2:9c:b4:32:14: + 4d:a7:a4:df:ec:be:a7:be:f8:43:db:91:37:ce:b4:32:2e:50: + 55:1a:35:4e:76:43:71:20:ef:93:77:4e:15:70:2e:87:c3:c1: + 1d:6d:dc:cb:b5:27:d4:2c:56:d1:52:53:3a:44:d2:73:c8:c4: + 1b:05:65:5a:62:92:9c:ee:41:8d:31:db:e7:34:ea:59:21:d5: + 01:7a:d7:64:b8:64:39:cd:c9:ed:af:ed:4b:03:48:a7:a0:99: + 01:80:dc:65:a3:36:ae:65:59:48:4f:82:4b:c8:65:f1:57:1d: + e5:59:2e:0a:3f:6c:d8:d1:f5:e5:09:b4:6c:54:00:0a:e0:15: + 4d:87:75:6d:b7:58:96:5a:dd:6d:d2:00:a0:f4:9b:48:be:c3: + 37:a4:ba:36:e0:7c:87:85:97:1a:15:a2:de:2e:a2:5b:bd:af: + 18:f9:90:50:cd:70:59:f8:27:67:47:cb:c7:a0:07:3a:7d:d1: + 2c:5d:6c:19:3a:66:b5:7d:fd:91:6f:82:b1:be:08:93:db:14: + 47:f1:a2:37:c7:45:9e:3c:c7:77:af:64:a8:93:df:f6:69:83: + 82:60:f2:49:42:34:ed:5a:00:54:85:1c:16:36:92:0c:5c:fa: + a6:ad:bf:db +-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UE +BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz +dCBOZXR3b3JraW5nMB4XDTEwMDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDEL +MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp +cm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SEHi3y +YJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbua +kCNrmreIdIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRL +QESxG9fhwoXA3hA/Pe24/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp +6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gbh+0t+nvujArjqWaJGctB+d1ENmHP4ndG +yH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNVHQ4EFgQUBx/S55zawm6i +QLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ +KoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfO +tDIuUFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzu +QY0x2+c06lkh1QF612S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZ +Lgo/bNjR9eUJtGxUAArgFU2HdW23WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4u +olu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9/ZFvgrG+CJPbFEfxojfHRZ48 +x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s= +-----END CERTIFICATE----- + +AffirmTrust Premium +# Issuer: CN=AffirmTrust Premium,O=AffirmTrust,C=US +# Serial Number:6d:8c:14:46:b1:a6:0a:ee +# Subject: CN=AffirmTrust Premium,O=AffirmTrust,C=US +# Not Valid Before: Fri Jan 29 14:10:36 2010 +# Not Valid After : Mon Dec 31 14:10:36 2040 +# Fingerprint (MD5): C4:5D:0E:48:B6:AC:28:30:4E:0A:BC:F9:38:16:87:57 +# Fingerprint (SHA1): D8:A6:33:2C:E0:03:6F:B1:85:F6:63:4F:7D:6A:06:65:26:32:28:27 +MUST_VERIFY_TRUST: EMAIL_PROTECTION, CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH +================================================= +MD5 Fingerprint=C4:5D:0E:48:B6:AC:28:30:4E:0A:BC:F9:38:16:87:57 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 7893706540734352110 (0x6d8c1446b1a60aee) + Signature Algorithm: sha384WithRSAEncryption + Issuer: C=US, O=AffirmTrust, CN=AffirmTrust Premium + Validity + Not Before: Jan 29 14:10:36 2010 GMT + Not After : Dec 31 14:10:36 2040 GMT + Subject: C=US, O=AffirmTrust, CN=AffirmTrust Premium + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:c4:12:df:a9:5f:fe:41:dd:dd:f5:9f:8a:e3:f6: + ac:e1:3c:78:9a:bc:d8:f0:7f:7a:a0:33:2a:dc:8d: + 20:5b:ae:2d:6f:e7:93:d9:36:70:6a:68:cf:8e:51: + a3:85:5b:67:04:a0:10:24:6f:5d:28:82:c1:97:57: + d8:48:29:13:b6:e1:be:91:4d:df:85:0c:53:18:9a: + 1e:24:a2:4f:8f:f0:a2:85:0b:cb:f4:29:7f:d2:a4: + 58:ee:26:4d:c9:aa:a8:7b:9a:d9:fa:38:de:44:57: + 15:e5:f8:8c:c8:d9:48:e2:0d:16:27:1d:1e:c8:83: + 85:25:b7:ba:aa:55:41:cc:03:22:4b:2d:91:8d:8b: + e6:89:af:66:c7:e9:ff:2b:e9:3c:ac:da:d2:b3:c3: + e1:68:9c:89:f8:7a:00:56:de:f4:55:95:6c:fb:ba: + 64:dd:62:8b:df:0b:77:32:eb:62:cc:26:9a:9b:bb: + aa:62:83:4c:b4:06:7a:30:c8:29:bf:ed:06:4d:97: + b9:1c:c4:31:2b:d5:5f:bc:53:12:17:9c:99:57:29: + 66:77:61:21:31:07:2e:25:49:9d:18:f2:ee:f3:2b: + 71:8c:b5:ba:39:07:49:77:fc:ef:2e:92:90:05:8d: + 2d:2f:77:7b:ef:43:bf:35:bb:9a:d8:f9:73:a7:2c: + f2:d0:57:ee:28:4e:26:5f:8f:90:68:09:2f:b8:f8: + dc:06:e9:2e:9a:3e:51:a7:d1:22:c4:0a:a7:38:48: + 6c:b3:f9:ff:7d:ab:86:57:e3:ba:d6:85:78:77:ba: + 43:ea:48:7f:f6:d8:be:23:6d:1e:bf:d1:36:6c:58: + 5c:f1:ee:a4:19:54:1a:f5:03:d2:76:e6:e1:8c:bd: + 3c:b3:d3:48:4b:e2:c8:f8:7f:92:a8:76:46:9c:42: + 65:3e:a4:1e:c1:07:03:5a:46:2d:b8:97:f3:b7:d5: + b2:55:21:ef:ba:dc:4c:00:97:fb:14:95:27:33:bf: + e8:43:47:46:d2:08:99:16:60:3b:9a:7e:d2:e6:ed: + 38:ea:ec:01:1e:3c:48:56:49:09:c7:4c:37:00:9e: + 88:0e:c0:73:e1:6f:66:e9:72:47:30:3e:10:e5:0b: + 03:c9:9a:42:00:6c:c5:94:7e:61:c4:8a:df:7f:82: + 1a:0b:59:c4:59:32:77:b3:bc:60:69:56:39:fd:b4: + 06:7b:2c:d6:64:36:d9:bd:48:ed:84:1f:7e:a5:22: + 8f:2a:b8:42:f4:82:b7:d4:53:90:78:4e:2d:1a:fd: + 81:6f:44:d7:3b:01:74:96:42:e0:00:e2:2e:6b:ea: + c5:ee:72:ac:bb:bf:fe:ea:aa:a8:f8:dc:f6:b2:79: + 8a:b6:67 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + 9D:C0:67:A6:0C:22:D9:26:F5:45:AB:A6:65:52:11:27:D8:45:AC:63 + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + Signature Algorithm: sha384WithRSAEncryption + b3:57:4d:10:62:4e:3a:e4:ac:ea:b8:1c:af:32:23:c8:b3:49: + 5a:51:9c:76:28:8d:79:aa:57:46:17:d5:f5:52:f6:b7:44:e8: + 08:44:bf:18:84:d2:0b:80:cd:c5:12:fd:00:55:05:61:87:41: + dc:b5:24:9e:3c:c4:d8:c8:fb:70:9e:2f:78:96:83:20:36:de: + 7c:0f:69:13:88:a5:75:36:98:08:a6:c6:df:ac:ce:e3:58:d6: + b7:3e:de:ba:f3:eb:34:40:d8:a2:81:f5:78:3f:2f:d5:a5:fc: + d9:a2:d4:5e:04:0e:17:ad:fe:41:f0:e5:b2:72:fa:44:82:33: + 42:e8:2d:58:f7:56:8c:62:3f:ba:42:b0:9c:0c:5c:7e:2e:65: + 26:5c:53:4f:00:b2:78:7e:a1:0d:99:2d:8d:b8:1d:8e:a2:c4: + b0:fd:60:d0:30:a4:8e:c8:04:62:a9:c4:ed:35:de:7a:97:ed: + 0e:38:5e:92:2f:93:70:a5:a9:9c:6f:a7:7d:13:1d:7e:c6:08: + 48:b1:5e:67:eb:51:08:25:e9:e6:25:6b:52:29:91:9c:d2:39: + 73:08:57:de:99:06:b4:5b:9d:10:06:e1:c2:00:a8:b8:1c:4a: + 02:0a:14:d0:c1:41:ca:fb:8c:35:21:7d:82:38:f2:a9:54:91: + 19:35:93:94:6d:6a:3a:c5:b2:d0:bb:89:86:93:e8:9b:c9:0f: + 3a:a7:7a:b8:a1:f0:78:46:fa:fc:37:2f:e5:8a:84:f3:df:fe: + 04:d9:a1:68:a0:2f:24:e2:09:95:06:d5:95:ca:e1:24:96:eb: + 7c:f6:93:05:bb:ed:73:e9:2d:d1:75:39:d7:e7:24:db:d8:4e: + 5f:43:8f:9e:d0:14:39:bf:55:70:48:99:57:31:b4:9c:ee:4a: + 98:03:96:30:1f:60:06:ee:1b:23:fe:81:60:23:1a:47:62:85: + a5:cc:19:34:80:6f:b3:ac:1a:e3:9f:f0:7b:48:ad:d5:01:d9: + 67:b6:a9:72:93:ea:2d:66:b5:b2:b8:e4:3d:3c:b2:ef:4c:8c: + ea:eb:07:bf:ab:35:9a:55:86:bc:18:a6:b5:a8:5e:b4:83:6c: + 6b:69:40:d3:9f:dc:f1:c3:69:6b:b9:e1:6d:09:f4:f1:aa:50: + 76:0a:7a:7d:7a:17:a1:55:96:42:99:31:09:dd:60:11:8d:05: + 30:7e:e6:8e:46:d1:9d:14:da:c7:17:e4:05:96:8c:c4:24:b5: + 1b:cf:14:07:b2:40:f8:a3:9e:41:86:bc:04:d0:6b:96:c8:2a: + 80:34:fd:bf:ef:06:a3:dd:58:c5:85:3d:3e:8f:fe:9e:29:e0: + b6:b8:09:68:19:1c:18:43 +-----BEGIN CERTIFICATE----- +MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UE +BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVz +dCBQcmVtaXVtMB4XDTEwMDEyOTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkG +A1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1U +cnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxBLf +qV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtnBKAQ +JG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ ++jjeRFcV5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrS +s8PhaJyJ+HoAVt70VZVs+7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5 +HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmdGPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d7 +70O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5Rp9EixAqnOEhss/n/fauG +V+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NIS+LI+H+S +qHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S +5u046uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4Ia +C1nEWTJ3s7xgaVY5/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TX +OwF0lkLgAOIua+rF7nKsu7/+6qqo+Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYE +FJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ +BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByvMiPIs0laUZx2 +KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg +Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B +8OWycvpEgjNC6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQ +MKSOyARiqcTtNd56l+0OOF6SL5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc +0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK+4w1IX2COPKpVJEZNZOUbWo6xbLQ +u4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmVBtWVyuEklut89pMF +u+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFgIxpH +YoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8 +GKa1qF60g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaO +RtGdFNrHF+QFlozEJLUbzxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6e +KeC2uAloGRwYQw== +-----END CERTIFICATE----- + +AffirmTrust Premium ECC +# Issuer: CN=AffirmTrust Premium ECC,O=AffirmTrust,C=US +# Serial Number:74:97:25:8a:c7:3f:7a:54 +# Subject: CN=AffirmTrust Premium ECC,O=AffirmTrust,C=US +# Not Valid Before: Fri Jan 29 14:20:24 2010 +# Not Valid After : Mon Dec 31 14:20:24 2040 +# Fingerprint (MD5): 64:B0:09:55:CF:B1:D5:99:E2:BE:13:AB:A6:5D:EA:4D +# Fingerprint (SHA1): B8:23:6B:00:2F:1D:16:86:53:01:55:6C:11:A4:37:CA:EB:FF:C3:BB +TRUSTED_DELEGATOR: SERVER_AUTH +MUST_VERIFY_TRUST: EMAIL_PROTECTION, CODE_SIGNING +================================================= +MD5 Fingerprint=64:B0:09:55:CF:B1:D5:99:E2:BE:13:AB:A6:5D:EA:4D +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 8401224907861490260 (0x7497258ac73f7a54) + Signature Algorithm: ecdsa-with-SHA384 + Issuer: C=US, O=AffirmTrust, CN=AffirmTrust Premium ECC + Validity + Not Before: Jan 29 14:20:24 2010 GMT + Not After : Dec 31 14:20:24 2040 GMT + Subject: C=US, O=AffirmTrust, CN=AffirmTrust Premium ECC + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (384 bit) + pub: + 04:0d:30:5e:1b:15:9d:03:d0:a1:79:35:b7:3a:3c: + 92:7a:ca:15:1c:cd:62:f3:9c:26:5c:07:3d:e5:54: + fa:a3:d6:cc:12:ea:f4:14:5f:e8:8e:19:ab:2f:2e: + 48:e6:ac:18:43:78:ac:d0:37:c3:bd:b2:cd:2c:e6: + 47:e2:1a:e6:63:b8:3d:2e:2f:78:c4:4f:db:f4:0f: + a4:68:4c:55:72:6b:95:1d:4e:18:42:95:78:cc:37: + 3c:91:e2:9b:65:2b:29 + ASN1 OID: secp384r1 + X509v3 extensions: + X509v3 Subject Key Identifier: + 9A:AF:29:7A:C0:11:35:35:26:51:30:00:C3:6A:FE:40:D5:AE:D6:3C + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + Signature Algorithm: ecdsa-with-SHA384 + 30:64:02:30:17:09:f3:87:88:50:5a:af:c8:c0:42:bf:47:5f: + f5:6c:6a:86:e0:c4:27:74:e4:38:53:d7:05:7f:1b:34:e3:c6: + 2f:b3:ca:09:3c:37:9d:d7:e7:b8:46:f1:fd:a1:e2:71:02:30: + 42:59:87:43:d4:51:df:ba:d3:09:32:5a:ce:88:7e:57:3d:9c: + 5f:42:6b:f5:07:2d:b5:f0:82:93:f9:59:6f:ae:64:fa:58:e5: + 8b:1e:e3:63:be:b5:81:cd:6f:02:8c:79 +-----BEGIN CERTIFICATE----- +MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMC +VVMxFDASBgNVBAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQ +cmVtaXVtIEVDQzAeFw0xMDAxMjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJ +BgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1UcnVzdDEgMB4GA1UEAwwXQWZmaXJt +VHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQNMF4bFZ0D +0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQN8O9 +ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0G +A1UdDgQWBBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4G +A1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/Vs +aobgxCd05DhT1wV/GzTjxi+zygk8N53X57hG8f2h4nECMEJZh0PUUd+60wkyWs6I +flc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKMeQ== +-----END CERTIFICATE----- + +Certum Trusted Network CA +# Issuer: CN=Certum Trusted Network CA,OU=Certum Certification Authority,O=Unizeto Technologies S.A.,C=PL +# Serial Number: 279744 (0x444c0) +# Subject: CN=Certum Trusted Network CA,OU=Certum Certification Authority,O=Unizeto Technologies S.A.,C=PL +# Not Valid Before: Wed Oct 22 12:07:37 2008 +# Not Valid After : Mon Dec 31 12:07:37 2029 +# Fingerprint (MD5): D5:E9:81:40:C5:18:69:FC:46:2C:89:75:62:0F:AA:78 +# Fingerprint (SHA1): 07:E0:32:E0:20:B7:2C:3F:19:2F:06:28:A2:59:3A:19:A7:0F:06:9E +MUST_VERIFY_TRUST: CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +================================================ +MD5 Fingerprint=D5:E9:81:40:C5:18:69:FC:46:2C:89:75:62:0F:AA:78 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 279744 (0x444c0) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=PL, O=Unizeto Technologies S.A., OU=Certum Certification Authority, CN=Certum Trusted Network CA + Validity + Not Before: Oct 22 12:07:37 2008 GMT + Not After : Dec 31 12:07:37 2029 GMT + Subject: C=PL, O=Unizeto Technologies S.A., OU=Certum Certification Authority, CN=Certum Trusted Network CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:e3:fb:7d:a3:72:ba:c2:f0:c9:14:87:f5:6b:01: + 4e:e1:6e:40:07:ba:6d:27:5d:7f:f7:5b:2d:b3:5a: + c7:51:5f:ab:a4:32:a6:61:87:b6:6e:0f:86:d2:30: + 02:97:f8:d7:69:57:a1:18:39:5d:6a:64:79:c6:01: + 59:ac:3c:31:4a:38:7c:d2:04:d2:4b:28:e8:20:5f: + 3b:07:a2:cc:4d:73:db:f3:ae:4f:c7:56:d5:5a:a7: + 96:89:fa:f3:ab:68:d4:23:86:59:27:cf:09:27:bc: + ac:6e:72:83:1c:30:72:df:e0:a2:e9:d2:e1:74:75: + 19:bd:2a:9e:7b:15:54:04:1b:d7:43:39:ad:55:28: + c5:e2:1a:bb:f4:c0:e4:ae:38:49:33:cc:76:85:9f: + 39:45:d2:a4:9e:f2:12:8c:51:f8:7c:e4:2d:7f:f5: + ac:5f:eb:16:9f:b1:2d:d1:ba:cc:91:42:77:4c:25: + c9:90:38:6f:db:f0:cc:fb:8e:1e:97:59:3e:d5:60: + 4e:e6:05:28:ed:49:79:13:4b:ba:48:db:2f:f9:72: + d3:39:ca:fe:1f:d8:34:72:f5:b4:40:cf:31:01:c3: + ec:de:11:2d:17:5d:1f:b8:50:d1:5e:19:a7:69:de: + 07:33:28:ca:50:95:f9:a7:54:cb:54:86:50:45:a9: + f9:49 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + 08:76:CD:CB:07:FF:24:F6:C5:CD:ED:BB:90:BC:E2:84:37:46:75:F7 + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + Signature Algorithm: sha1WithRSAEncryption + a6:a8:ad:22:ce:01:3d:a6:a3:ff:62:d0:48:9d:8b:5e:72:b0: + 78:44:e3:dc:1c:af:09:fd:23:48:fa:bd:2a:c4:b9:55:04:b5: + 10:a3:8d:27:de:0b:82:63:d0:ee:de:0c:37:79:41:5b:22:b2: + b0:9a:41:5c:a6:70:e0:d4:d0:77:cb:23:d3:00:e0:6c:56:2f: + e1:69:0d:0d:d9:aa:bf:21:81:50:d9:06:a5:a8:ff:95:37:d0: + aa:fe:e2:b3:f5:99:2d:45:84:8a:e5:42:09:d7:74:02:2f:f7: + 89:d8:99:e9:bc:27:d4:47:8d:ba:0d:46:1c:77:cf:14:a4:1c: + b9:a4:31:c4:9c:28:74:03:34:ff:33:19:26:a5:e9:0d:74:b7: + 3e:97:c6:76:e8:27:96:a3:66:dd:e1:ae:f2:41:5b:ca:98:56: + 83:73:70:e4:86:1a:d2:31:41:ba:2f:be:2d:13:5a:76:6f:4e: + e8:4e:81:0e:3f:5b:03:22:a0:12:be:66:58:11:4a:cb:03:c4: + b4:2a:2a:2d:96:17:e0:39:54:bc:48:d3:76:27:9d:9a:2d:06: + a6:c9:ec:39:d2:ab:db:9f:9a:0b:27:02:35:29:b1:40:95:e7: + f9:e8:9c:55:88:19:46:d6:b7:34:f5:7e:ce:39:9a:d9:38:f1: + 51:f7:4f:2c +-----BEGIN CERTIFICATE----- +MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBM +MSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5D +ZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBU +cnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIyMTIwNzM3WhcNMjkxMjMxMTIwNzM3 +WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMg +Uy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSIw +IAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rH +UV+rpDKmYYe2bg+G0jACl/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LM +TXPb865Px1bVWqeWifrzq2jUI4ZZJ88JJ7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVU +BBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4fOQtf/WsX+sWn7Et0brM +kUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0cvW0QM8x +AcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNV +HQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15y +sHhE49wcrwn9I0j6vSrEuVUEtRCjjSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfL +I9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1mS1FhIrlQgnXdAIv94nYmem8 +J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5ajZt3hrvJBW8qY +VoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI +03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= +-----END CERTIFICATE----- + +TWCA Root Certification Authority +# Issuer: CN=TWCA Root Certification Authority,OU=Root CA,O=TAIWAN-CA,C=TW +# Serial Number: 1 (0x1) +# Subject: CN=TWCA Root Certification Authority,OU=Root CA,O=TAIWAN-CA,C=TW +# Not Valid Before: Thu Aug 28 07:24:33 2008 +# Not Valid After : Tue Dec 31 15:59:59 2030 +# Fingerprint (MD5): AA:08:8F:F6:F9:7B:B7:F2:B1:A7:1E:9B:EA:EA:BD:79 +# Fingerprint (SHA1): CF:9E:87:6D:D3:EB:FC:42:26:97:A3:B5:A3:7A:A0:76:A9:06:23:48 +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +MUST_VERIFY_TRUST: CODE_SIGNING +================================================ +MD5 Fingerprint=AA:08:8F:F6:F9:7B:B7:F2:B1:A7:1E:9B:EA:EA:BD:79 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 1 (0x1) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=TW, O=TAIWAN-CA, OU=Root CA, CN=TWCA Root Certification Authority + Validity + Not Before: Aug 28 07:24:33 2008 GMT + Not After : Dec 31 15:59:59 2030 GMT + Subject: C=TW, O=TAIWAN-CA, OU=Root CA, CN=TWCA Root Certification Authority + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:b0:7e:72:b8:a4:03:94:e6:a7:de:09:38:91:4a: + 11:40:87:a7:7c:59:64:14:7b:b5:11:10:dd:fe:bf: + d5:c0:bb:56:e2:85:25:f4:35:72:0f:f8:53:d0:41: + e1:44:01:c2:b4:1c:c3:31:42:16:47:85:33:22:76: + b2:0a:6f:0f:e5:25:50:4f:85:86:be:bf:98:2e:10: + 67:1e:be:11:05:86:05:90:c4:59:d0:7c:78:10:b0: + 80:5c:b7:e1:c7:2b:75:cb:7c:9f:ae:b5:d1:9d:23: + 37:63:a7:dc:42:a2:2d:92:04:1b:50:c1:7b:b8:3e: + 1b:c9:56:04:8b:2f:52:9b:ad:a9:56:e9:c1:ff:ad: + a9:58:87:30:b6:81:f7:97:45:fc:19:57:3b:2b:6f: + e4:47:f4:99:45:fe:1d:f1:f8:97:a3:88:1d:37:1c: + 5c:8f:e0:76:25:9a:50:f8:a0:54:ff:44:90:76:23: + d2:32:c6:c3:ab:06:bf:fc:fb:bf:f3:ad:7d:92:62: + 02:5b:29:d3:35:a3:93:9a:43:64:60:5d:b2:fa:32: + ff:3b:04:af:4d:40:6a:f9:c7:e3:ef:23:fd:6b:cb: + e5:0f:8b:38:0d:ee:0a:fc:fe:0f:98:9f:30:31:dd: + 6c:52:65:f9:8b:81:be:22:e1:1c:58:03:ba:91:1b: + 89:07 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + 6A:38:5B:26:8D:DE:8B:5A:F2:4F:7A:54:83:19:18:E3:08:35:A6:BA + Signature Algorithm: sha1WithRSAEncryption + 3c:d5:77:3d:da:df:89:ba:87:0c:08:54:6a:20:50:92:be:b0: + 41:3d:b9:26:64:83:0a:2f:e8:40:c0:97:28:27:82:30:4a:c9: + 93:ff:6a:e7:a6:00:7f:89:42:9a:d6:11:e5:53:ce:2f:cc:f2: + da:05:c4:fe:e2:50:c4:3a:86:7d:cc:da:7e:10:09:3b:92:35: + 2a:53:b2:fe:eb:2b:05:d9:6c:5d:e6:d0:ef:d3:6a:66:9e:15: + 28:85:7a:e8:82:00:ac:1e:a7:09:69:56:42:d3:68:51:18:be: + 54:9a:bf:44:41:ba:49:be:20:ba:69:5c:ee:b8:77:cd:ce:6c: + 1f:ad:83:96:18:7d:0e:b5:14:39:84:f1:28:e9:2d:a3:9e:7b: + 1e:7a:72:5a:83:b3:79:6f:ef:b4:fc:d0:0a:a5:58:4f:46:df: + fb:6d:79:59:f2:84:22:52:ae:0f:cc:fb:7c:3b:e7:6a:ca:47: + 61:c3:7a:f8:d3:92:04:1f:b8:20:84:e1:36:54:16:c7:40:de: + 3b:8a:73:dc:df:c6:09:4c:df:ec:da:ff:d4:53:42:a1:c9:f2: + 62:1d:22:83:3c:97:c5:f9:19:62:27:ac:65:22:d7:d3:3c:c6: + e5:8e:b2:53:cc:49:ce:bc:30:fe:7b:0e:33:90:fb:ed:d2:14: + 91:1f:07:af +-----BEGIN CERTIFICATE----- +MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzES +MBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFU +V0NBIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMz +WhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJVEFJV0FO +LUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlm +aWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB +AQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFE +AcK0HMMxQhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HH +K3XLfJ+utdGdIzdjp9xCoi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeX +RfwZVzsrb+RH9JlF/h3x+JejiB03HFyP4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/z +rX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1ry+UPizgN7gr8/g+YnzAx +3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkq +hkiG9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeC +MErJk/9q56YAf4lCmtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdls +XebQ79NqZp4VKIV66IIArB6nCWlWQtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62D +lhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVYT0bf+215WfKEIlKuD8z7fDvn +aspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocnyYh0igzyXxfkZ +YiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw== +-----END CERTIFICATE----- + +Security Communication RootCA2 +# Issuer: OU=Security Communication RootCA2,O="SECOM Trust Systems CO.,LTD.",C=JP +# Serial Number: 0 (0x0) +# Subject: OU=Security Communication RootCA2,O="SECOM Trust Systems CO.,LTD.",C=JP +# Not Valid Before: Fri May 29 05:00:39 2009 +# Not Valid After : Tue May 29 05:00:39 2029 +# Fingerprint (MD5): 6C:39:7D:A4:0E:55:59:B2:3F:D6:41:B1:12:50:DE:43 +# Fingerprint (SHA1): 5F:3B:8C:F2:F8:10:B3:7D:78:B4:CE:EC:19:19:C3:73:34:B9:C7:74 +MUST_VERIFY_TRUST: CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +================================================ +MD5 Fingerprint=6C:39:7D:A4:0E:55:59:B2:3F:D6:41:B1:12:50:DE:43 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 0 (0x0) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=JP, O=SECOM Trust Systems CO.,LTD., OU=Security Communication RootCA2 + Validity + Not Before: May 29 05:00:39 2009 GMT + Not After : May 29 05:00:39 2029 GMT + Subject: C=JP, O=SECOM Trust Systems CO.,LTD., OU=Security Communication RootCA2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:d0:15:39:52:b1:52:b3:ba:c5:59:82:c4:5d:52: + ae:3a:43:65:80:4b:c7:f2:96:bc:db:36:97:d6:a6: + 64:8c:a8:5e:f0:e3:0a:1c:f7:df:97:3d:4b:ae:f6: + 5d:ec:21:b5:41:ab:cd:b9:7e:76:9f:be:f9:3e:36: + 34:a0:3b:c1:f6:31:11:45:74:93:3d:57:80:c5:f9: + 89:99:ca:e5:ab:6a:d4:b5:da:41:90:10:c1:d6:d6: + 42:89:c2:bf:f4:38:12:95:4c:54:05:f7:36:e4:45: + 83:7b:14:65:d6:dc:0c:4d:d1:de:7e:0c:ab:3b:c4: + 15:be:3a:56:a6:5a:6f:76:69:52:a9:7a:b9:c8:eb: + 6a:9a:5d:52:d0:2d:0a:6b:35:16:09:10:84:d0:6a: + ca:3a:06:00:37:47:e4:7e:57:4f:3f:8b:eb:67:b8: + 88:aa:c5:be:53:55:b2:91:c4:7d:b9:b0:85:19:06: + 78:2e:db:61:1a:fa:85:f5:4a:91:a1:e7:16:d5:8e: + a2:39:df:94:b8:70:1f:28:3f:8b:fc:40:5e:63:83: + 3c:83:2a:1a:99:6b:cf:de:59:6a:3b:fc:6f:16:d7: + 1f:fd:4a:10:eb:4e:82:16:3a:ac:27:0c:53:f1:ad: + d5:24:b0:6b:03:50:c1:2d:3c:16:dd:44:34:27:1a: + 75:fb + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + 0A:85:A9:77:65:05:98:7C:40:81:F8:0F:97:2C:38:F1:0A:EC:3C:CF + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + Signature Algorithm: sha256WithRSAEncryption + 4c:3a:a3:44:ac:b9:45:b1:c7:93:7e:c8:0b:0a:42:df:64:ea: + 1c:ee:59:6c:08:ba:89:5f:6a:ca:4a:95:9e:7a:8f:07:c5:da: + 45:72:82:71:0e:3a:d2:cc:6f:a7:b4:a1:23:bb:f6:24:9f:cb: + 17:fe:8c:a6:ce:c2:d2:db:cc:8d:fc:71:fc:03:29:c1:6c:5d: + 33:5f:64:b6:65:3b:89:6f:18:76:78:f5:dc:a2:48:1f:19:3f: + 8e:93:eb:f1:fa:17:ee:cd:4e:e3:04:12:55:d6:e5:e4:dd:fb: + 3e:05:7c:e2:1d:5e:c6:a7:bc:97:4f:68:3a:f5:e9:2e:0a:43: + b6:af:57:5c:62:68:7c:b7:fd:a3:8a:84:a0:ac:62:be:2b:09: + 87:34:f0:6a:01:bb:9b:29:56:3c:fe:00:37:cf:23:6c:f1:4e: + aa:b6:74:46:12:6c:91:ee:34:d5:ec:9a:91:e7:44:be:90:31: + 72:d5:49:02:f6:02:e5:f4:1f:eb:7c:d9:96:55:a9:ff:ec:8a: + f9:99:47:ff:35:5a:02:aa:04:cb:8a:5b:87:71:29:91:bd:a4: + b4:7a:0d:bd:9a:f5:57:23:00:07:21:17:3f:4a:39:d1:05:49: + 0b:a7:b6:37:81:a5:5d:8c:aa:33:5e:81:28:7c:a7:7d:27:eb: + 00:ae:8d:37 +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDEl +MCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMe +U2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoX +DTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRy +dXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3VyaXR5IENvbW11bmlj +YXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANAV +OVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGr +zbl+dp+++T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVM +VAX3NuRFg3sUZdbcDE3R3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQ +hNBqyjoGADdH5H5XTz+L62e4iKrFvlNVspHEfbmwhRkGeC7bYRr6hfVKkaHnFtWO +ojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1KEOtOghY6rCcMU/Gt1SSw +awNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8QIH4D5cs +OPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3 +DQEBCwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpF +coJxDjrSzG+ntKEju/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXc +okgfGT+Ok+vx+hfuzU7jBBJV1uXk3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8 +t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6qtnRGEmyR7jTV7JqR50S+kDFy +1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29mvVXIwAHIRc/ +SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03 +-----END CERTIFICATE----- + +EC-ACC +# Issuer: CN=EC-ACC,OU=Jerarquia Entitats de Certificacio Catalanes,OU=Vegeu https://www.catcert.net/verarrel (c)03,OU=Serveis Publics de Certificacio,O=Agencia Catalana de Certificacio (NIF Q-0801176-I),C=ES +# Serial Number:ee:2b:3d:eb:d4:21:de:14:a8:62:ac:04:f3:dd:c4:01 +# Subject: CN=EC-ACC,OU=Jerarquia Entitats de Certificacio Catalanes,OU=Vegeu https://www.catcert.net/verarrel (c)03,OU=Serveis Publics de Certificacio,O=Agencia Catalana de Certificacio (NIF Q-0801176-I),C=ES +# Not Valid Before: Tue Jan 07 23:00:00 2003 +# Not Valid After : Tue Jan 07 22:59:59 2031 +# Fingerprint (MD5): EB:F5:9D:29:0D:61:F9:42:1F:7C:C2:BA:6D:E3:15:09 +# Fingerprint (SHA1): 28:90:3A:63:5B:52:80:FA:E6:77:4C:0B:6D:A7:D6:BA:A6:4A:F2:E8 +TRUSTED_DELEGATOR: SERVER_AUTH +MUST_VERIFY_TRUST: EMAIL_PROTECTION, CODE_SIGNING +================================================= +MD5 Fingerprint=EB:F5:9D:29:0D:61:F9:42:1F:7C:C2:BA:6D:E3:15:09 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + (Negative)11:d4:c2:14:2b:de:21:eb:57:9d:53:fb:0c:22:3b:ff + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=ES, O=Agencia Catalana de Certificacio (NIF Q-0801176-I), OU=Serveis Publics de Certificacio, OU=Vegeu https://www.catcert.net/verarrel (c)03, OU=Jerarquia Entitats de Certificacio Catalanes, CN=EC-ACC + Validity + Not Before: Jan 7 23:00:00 2003 GMT + Not After : Jan 7 22:59:59 2031 GMT + Subject: C=ES, O=Agencia Catalana de Certificacio (NIF Q-0801176-I), OU=Serveis Publics de Certificacio, OU=Vegeu https://www.catcert.net/verarrel (c)03, OU=Jerarquia Entitats de Certificacio Catalanes, CN=EC-ACC + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:b3:22:c7:4f:e2:97:42:95:88:47:83:40:f6:1d: + 17:f3:83:73:24:1e:51:f3:98:8a:c3:92:b8:ff:40: + 90:05:70:87:60:c9:00:a9:b5:94:65:19:22:15:17: + c2:43:6c:66:44:9a:0d:04:3e:39:6f:a5:4b:7a:aa: + 63:b7:8a:44:9d:d9:63:91:84:66:e0:28:0f:ba:42: + e3:6e:8e:f7:14:27:93:69:ee:91:0e:a3:5f:0e:b1: + eb:66:a2:72:4f:12:13:86:65:7a:3e:db:4f:07:f4: + a7:09:60:da:3a:42:99:c7:b2:7f:b3:16:95:1c:c7: + f9:34:b5:94:85:d5:99:5e:a0:48:a0:7e:e7:17:65: + b8:a2:75:b8:1e:f3:e5:42:7d:af:ed:f3:8a:48:64: + 5d:82:14:93:d8:c0:e4:ff:b3:50:72:f2:76:f6:b3: + 5d:42:50:79:d0:94:3e:6b:0c:00:be:d8:6b:0e:4e: + 2a:ec:3e:d2:cc:82:a2:18:65:33:13:77:9e:9a:5d: + 1a:13:d8:c3:db:3d:c8:97:7a:ee:70:ed:a7:e6:7c: + db:71:cf:2d:94:62:df:6d:d6:f5:38:be:3f:a5:85: + 0a:19:b8:a8:d8:09:75:42:70:c4:ea:ef:cb:0e:c8: + 34:a8:12:22:98:0c:b8:13:94:b6:4b:ec:f0:d0:90: + e7:27 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Alternative Name: + email:ec_acc@catcert.net + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + A0:C3:8B:44:AA:37:A5:45:BF:97:80:5A:D1:F1:78:A2:9B:E9:5D:8D + X509v3 Certificate Policies: + Policy: 1.3.6.1.4.1.15096.1.3.1.10 + CPS: https://www.catcert.net/verarrel + User Notice: + Explicit Text: Vegeu https://www.catcert.net/verarrel + + Signature Algorithm: sha1WithRSAEncryption + a0:48:5b:82:01:f6:4d:48:b8:39:55:35:9c:80:7a:53:99:d5: + 5a:ff:b1:71:3b:cc:39:09:94:5e:d6:da:ef:be:01:5b:5d:d3: + 1e:d8:fd:7d:4f:cd:a0:41:e0:34:93:bf:cb:e2:86:9c:37:92: + 90:56:1c:dc:eb:29:05:e5:c4:9e:c7:35:df:8a:0c:cd:c5:21: + 43:e9:aa:88:e5:35:c0:19:42:63:5a:02:5e:a4:48:18:3a:85: + 6f:dc:9d:bc:3f:9d:9c:c1:87:b8:7a:61:08:e9:77:0b:7f:70: + ab:7a:dd:d9:97:2c:64:1e:85:bf:bc:74:96:a1:c3:7a:12:ec: + 0c:1a:6e:83:0c:3c:e8:72:46:9f:fb:48:d5:5e:97:e6:b1:a1: + f8:e4:ef:46:25:94:9c:89:db:69:38:be:ec:5c:0e:56:c7:65: + 51:e5:50:88:88:bf:42:d5:2b:3d:e5:f9:ba:9e:2e:b3:ca:f4: + 73:92:02:0b:be:4c:66:eb:20:fe:b9:cb:b5:99:7f:e6:b6:13: + fa:ca:4b:4d:d9:ee:53:46:06:3b:c6:4e:ad:93:5a:81:7e:6c: + 2a:4b:6a:05:45:8c:f2:21:a4:31:90:87:6c:65:9c:9d:a5:60: + 95:3a:52:7f:f5:d1:ab:08:6e:f3:ee:5b:f9:88:3d:7e:b8:6f: + 6e:03:e4:42 +-----BEGIN CERTIFICATE----- +MIIFVjCCBD6gAwIBAgIQ7is969Qh3hSoYqwE893EATANBgkqhkiG9w0BAQUFADCB +8zELMAkGA1UEBhMCRVMxOzA5BgNVBAoTMkFnZW5jaWEgQ2F0YWxhbmEgZGUgQ2Vy +dGlmaWNhY2lvIChOSUYgUS0wODAxMTc2LUkpMSgwJgYDVQQLEx9TZXJ2ZWlzIFB1 +YmxpY3MgZGUgQ2VydGlmaWNhY2lvMTUwMwYDVQQLEyxWZWdldSBodHRwczovL3d3 +dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAoYykwMzE1MDMGA1UECxMsSmVyYXJxdWlh +IEVudGl0YXRzIGRlIENlcnRpZmljYWNpbyBDYXRhbGFuZXMxDzANBgNVBAMTBkVD +LUFDQzAeFw0wMzAxMDcyMzAwMDBaFw0zMTAxMDcyMjU5NTlaMIHzMQswCQYDVQQG +EwJFUzE7MDkGA1UEChMyQWdlbmNpYSBDYXRhbGFuYSBkZSBDZXJ0aWZpY2FjaW8g +KE5JRiBRLTA4MDExNzYtSSkxKDAmBgNVBAsTH1NlcnZlaXMgUHVibGljcyBkZSBD +ZXJ0aWZpY2FjaW8xNTAzBgNVBAsTLFZlZ2V1IGh0dHBzOi8vd3d3LmNhdGNlcnQu +bmV0L3ZlcmFycmVsIChjKTAzMTUwMwYDVQQLEyxKZXJhcnF1aWEgRW50aXRhdHMg +ZGUgQ2VydGlmaWNhY2lvIENhdGFsYW5lczEPMA0GA1UEAxMGRUMtQUNDMIIBIjAN +BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsyLHT+KXQpWIR4NA9h0X84NzJB5R +85iKw5K4/0CQBXCHYMkAqbWUZRkiFRfCQ2xmRJoNBD45b6VLeqpjt4pEndljkYRm +4CgPukLjbo73FCeTae6RDqNfDrHrZqJyTxIThmV6PttPB/SnCWDaOkKZx7J/sxaV +HMf5NLWUhdWZXqBIoH7nF2W4onW4HvPlQn2v7fOKSGRdghST2MDk/7NQcvJ29rNd +QlB50JQ+awwAvthrDk4q7D7SzIKiGGUzE3eeml0aE9jD2z3Il3rucO2n5nzbcc8t +lGLfbdb1OL4/pYUKGbio2Al1QnDE6u/LDsg0qBIimAy4E5S2S+zw0JDnJwIDAQAB +o4HjMIHgMB0GA1UdEQQWMBSBEmVjX2FjY0BjYXRjZXJ0Lm5ldDAPBgNVHRMBAf8E +BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUoMOLRKo3pUW/l4Ba0fF4 +opvpXY0wfwYDVR0gBHgwdjB0BgsrBgEEAfV4AQMBCjBlMCwGCCsGAQUFBwIBFiBo +dHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbDA1BggrBgEFBQcCAjApGidW +ZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAwDQYJKoZIhvcN +AQEFBQADggEBAKBIW4IB9k1IuDlVNZyAelOZ1Vr/sXE7zDkJlF7W2u++AVtd0x7Y +/X1PzaBB4DSTv8vihpw3kpBWHNzrKQXlxJ7HNd+KDM3FIUPpqojlNcAZQmNaAl6k +SBg6hW/cnbw/nZzBh7h6YQjpdwt/cKt63dmXLGQehb+8dJahw3oS7AwaboMMPOhy +Rp/7SNVel+axofjk70YllJyJ22k4vuxcDlbHZVHlUIiIv0LVKz3l+bqeLrPK9HOS +Agu+TGbrIP65y7WZf+a2E/rKS03Z7lNGBjvGTq2TWoF+bCpLagVFjPIhpDGQh2xl +nJ2lYJU6Un/10asIbvPuW/mIPX64b24D5EI= +-----END CERTIFICATE----- + +Hellenic Academic and Research Institutions RootCA 2011 +# Issuer: CN=Hellenic Academic and Research Institutions RootCA 2011,O=Hellenic Academic and Research Institutions Cert. Authority,C=GR +# Serial Number: 0 (0x0) +# Subject: CN=Hellenic Academic and Research Institutions RootCA 2011,O=Hellenic Academic and Research Institutions Cert. Authority,C=GR +# Not Valid Before: Tue Dec 06 13:49:52 2011 +# Not Valid After : Mon Dec 01 13:49:52 2031 +# Fingerprint (MD5): 73:9F:4C:4B:73:5B:79:E9:FA:BA:1C:EF:6E:CB:D5:C9 +# Fingerprint (SHA1): FE:45:65:9B:79:03:5B:98:A1:61:B5:51:2E:AC:DA:58:09:48:22:4D +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +MUST_VERIFY_TRUST: CODE_SIGNING +======================================================= +MD5 Fingerprint=73:9F:4C:4B:73:5B:79:E9:FA:BA:1C:EF:6E:CB:D5:C9 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 0 (0x0) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=GR, O=Hellenic Academic and Research Institutions Cert. Authority, CN=Hellenic Academic and Research Institutions RootCA 2011 + Validity + Not Before: Dec 6 13:49:52 2011 GMT + Not After : Dec 1 13:49:52 2031 GMT + Subject: C=GR, O=Hellenic Academic and Research Institutions Cert. Authority, CN=Hellenic Academic and Research Institutions RootCA 2011 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:a9:53:00:e3:2e:a6:f6:8e:fa:60:d8:2d:95:3e: + f8:2c:2a:54:4e:cd:b9:84:61:94:58:4f:8f:3d:8b: + e4:43:f3:75:89:8d:51:e4:c3:37:d2:8a:88:4d:79: + 1e:b7:12:dd:43:78:4a:8a:92:e6:d7:48:d5:0f:a4: + 3a:29:44:35:b8:07:f6:68:1d:55:cd:38:51:f0:8c: + 24:31:85:af:83:c9:7d:e9:77:af:ed:1a:7b:9d:17: + f9:b3:9d:38:50:0f:a6:5a:79:91:80:af:37:ae:a6: + d3:31:fb:b5:26:09:9d:3c:5a:ef:51:c5:2b:df:96: + 5d:eb:32:1e:02:da:70:49:ec:6e:0c:c8:9a:37:8d: + f7:f1:36:60:4b:26:2c:82:9e:d0:78:f3:0d:0f:63: + a4:51:30:e1:f9:2b:27:12:07:d8:ea:bd:18:62:98: + b0:59:37:7d:be:ee:f3:20:51:42:5a:83:ef:93:ba: + 69:15:f1:62:9d:9f:99:39:82:a1:b7:74:2e:8b:d4: + c5:0b:7b:2f:f0:c8:0a:da:3d:79:0a:9a:93:1c:a5: + 28:72:73:91:43:9a:a7:d1:4d:85:84:b9:a9:74:8f: + 14:40:c7:dc:de:ac:41:64:6c:b4:19:9b:02:63:6d: + 24:64:8f:44:b2:25:ea:ce:5d:74:0c:63:32:5c:8d: + 87:e5 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + A6:91:42:FD:13:61:4A:23:9E:08:A4:29:E5:D8:13:04:23:EE:41:25 + X509v3 Name Constraints: + Permitted: + DNS:.gr + DNS:.eu + DNS:.edu + DNS:.org + email:.gr + email:.eu + email:.edu + email:.org + + Signature Algorithm: sha1WithRSAEncryption + 1f:ef:79:41:e1:7b:6e:3f:b2:8c:86:37:42:4a:4e:1c:37:1e: + 8d:66:ba:24:81:c9:4f:12:0f:21:c0:03:97:86:25:6d:5d:d3: + 22:29:a8:6c:a2:0d:a9:eb:3d:06:5b:99:3a:c7:cc:c3:9a:34: + 7f:ab:0e:c8:4e:1c:e1:fa:e4:dc:cd:0d:be:bf:24:fe:6c:e7: + 6b:c2:0d:c8:06:9e:4e:8d:61:28:a6:6a:fd:e5:f6:62:ea:18: + 3c:4e:a0:53:9d:b2:3a:9c:eb:a5:9c:91:16:b6:4d:82:e0:0c: + 05:48:a9:6c:f5:cc:f8:cb:9d:49:b4:f0:02:a5:fd:70:03:ed: + 8a:21:a5:ae:13:86:49:c3:33:73:be:87:3b:74:8b:17:45:26: + 4c:16:91:83:fe:67:7d:cd:4d:63:67:fa:f3:03:12:96:78:06: + 8d:b1:67:ed:8e:3f:be:9f:4f:02:f5:b3:09:2f:f3:4c:87:df: + 2a:cb:95:7c:01:cc:ac:36:7a:bf:a2:73:7a:f7:8f:c1:b5:9a: + a1:14:b2:8f:33:9f:0d:ef:22:dc:66:7b:84:bd:45:17:06:3d: + 3c:ca:b9:77:34:8f:ca:ea:cf:3f:31:3e:e3:88:e3:80:49:25: + c8:97:b5:9d:9a:99:4d:b0:3c:f8:4a:00:9b:64:dd:9f:39:4b: + d1:27:d7:b8 +-----BEGIN CERTIFICATE----- +MIIEMTCCAxmgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCR1Ix +RDBCBgNVBAoTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1 +dGlvbnMgQ2VydC4gQXV0aG9yaXR5MUAwPgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1p +YyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIFJvb3RDQSAyMDExMB4XDTExMTIw +NjEzNDk1MloXDTMxMTIwMTEzNDk1MlowgZUxCzAJBgNVBAYTAkdSMUQwQgYDVQQK +EztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIENl +cnQuIEF1dGhvcml0eTFAMD4GA1UEAxM3SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl +c2VhcmNoIEluc3RpdHV0aW9ucyBSb290Q0EgMjAxMTCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBAKlTAOMupvaO+mDYLZU++CwqVE7NuYRhlFhPjz2L5EPz +dYmNUeTDN9KKiE15HrcS3UN4SoqS5tdI1Q+kOilENbgH9mgdVc04UfCMJDGFr4PJ +fel3r+0ae50X+bOdOFAPplp5kYCvN66m0zH7tSYJnTxa71HFK9+WXesyHgLacEns +bgzImjeN9/E2YEsmLIKe0HjzDQ9jpFEw4fkrJxIH2Oq9GGKYsFk3fb7u8yBRQlqD +75O6aRXxYp2fmTmCobd0LovUxQt7L/DICto9eQqakxylKHJzkUOap9FNhYS5qXSP +FEDH3N6sQWRstBmbAmNtJGSPRLIl6s5ddAxjMlyNh+UCAwEAAaOBiTCBhjAPBgNV +HRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUppFC/RNhSiOeCKQp +5dgTBCPuQSUwRwYDVR0eBEAwPqA8MAWCAy5ncjAFggMuZXUwBoIELmVkdTAGggQu +b3JnMAWBAy5ncjAFgQMuZXUwBoEELmVkdTAGgQQub3JnMA0GCSqGSIb3DQEBBQUA +A4IBAQAf73lB4XtuP7KMhjdCSk4cNx6NZrokgclPEg8hwAOXhiVtXdMiKahsog2p +6z0GW5k6x8zDmjR/qw7IThzh+uTczQ2+vyT+bOdrwg3IBp5OjWEopmr95fZi6hg8 +TqBTnbI6nOulnJEWtk2C4AwFSKls9cz4y51JtPACpf1wA+2KIaWuE4ZJwzNzvoc7 +dIsXRSZMFpGD/md9zU1jZ/rzAxKWeAaNsWftjj++n08C9bMJL/NMh98qy5V8Acys +Nnq/onN694/BtZqhFLKPM58N7yLcZnuEvUUXBj08yrl3NI/K6s8/MT7jiOOASSXI +l7WdmplNsDz4SgCbZN2fOUvRJ9e4 +-----END CERTIFICATE----- + +Actalis Authentication Root CA +# Issuer: CN=Actalis Authentication Root CA,O=Actalis S.p.A./03358520967,L=Milan,C=IT +# Serial Number:57:0a:11:97:42:c4:e3:cc +# Subject: CN=Actalis Authentication Root CA,O=Actalis S.p.A./03358520967,L=Milan,C=IT +# Not Valid Before: Thu Sep 22 11:22:02 2011 +# Not Valid After : Sun Sep 22 11:22:02 2030 +# Fingerprint (MD5): 69:C1:0D:4F:07:A3:1B:C3:FE:56:3D:04:BC:11:F6:A6 +# Fingerprint (SHA1): F3:73:B3:87:06:5A:28:84:8A:F2:F3:4A:CE:19:2B:DD:C7:8E:9C:AC +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +MUST_VERIFY_TRUST: CODE_SIGNING +================================================ +MD5 Fingerprint=69:C1:0D:4F:07:A3:1B:C3:FE:56:3D:04:BC:11:F6:A6 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 6271844772424770508 (0x570a119742c4e3cc) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=IT, L=Milan, O=Actalis S.p.A./03358520967, CN=Actalis Authentication Root CA + Validity + Not Before: Sep 22 11:22:02 2011 GMT + Not After : Sep 22 11:22:02 2030 GMT + Subject: C=IT, L=Milan, O=Actalis S.p.A./03358520967, CN=Actalis Authentication Root CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:a7:c6:c4:a5:29:a4:2c:ef:e5:18:c5:b0:50:a3: + 6f:51:3b:9f:0a:5a:c9:c2:48:38:0a:c2:1c:a0:18: + 7f:91:b5:87:b9:40:3f:dd:1d:68:1f:08:83:d5:2d: + 1e:88:a0:f8:8f:56:8f:6d:99:02:92:90:16:d5:5f: + 08:6c:89:d7:e1:ac:bc:20:c2:b1:e0:83:51:8a:69: + 4d:00:96:5a:6f:2f:c0:44:7e:a3:0e:e4:91:cd:58: + ee:dc:fb:c7:1e:45:47:dd:27:b9:08:01:9f:a6:21: + 1d:f5:41:2d:2f:4c:fd:28:ad:e0:8a:ad:22:b4:56: + 65:8e:86:54:8f:93:43:29:de:39:46:78:a3:30:23: + ba:cd:f0:7d:13:57:c0:5d:d2:83:6b:48:4c:c4:ab: + 9f:80:5a:5b:3a:bd:c9:a7:22:3f:80:27:33:5b:0e: + b7:8a:0c:5d:07:37:08:cb:6c:d2:7a:47:22:44:35: + c5:cc:cc:2e:8e:dd:2a:ed:b7:7d:66:0d:5f:61:51: + 22:55:1b:e3:46:e3:e3:3d:d0:35:62:9a:db:af:14: + c8:5b:a1:cc:89:1b:e1:30:26:fc:a0:9b:1f:81:a7: + 47:1f:04:eb:a3:39:92:06:9f:99:d3:bf:d3:ea:4f: + 50:9c:19:fe:96:87:1e:3c:65:f6:a3:18:24:83:86: + 10:e7:54:3e:a8:3a:76:24:4f:81:21:c5:e3:0f:02: + f8:93:94:47:20:bb:fe:d4:0e:d3:68:b9:dd:c4:7a: + 84:82:e3:53:54:79:dd:db:9c:d2:f2:07:9b:2e:b6: + bc:3e:ed:85:6d:ef:25:11:f2:97:1a:42:61:f7:4a: + 97:e8:8b:b1:10:07:fa:65:81:b2:a2:39:cf:f7:3c: + ff:18:fb:c6:f1:5a:8b:59:e2:02:ac:7b:92:d0:4e: + 14:4f:59:45:f6:0c:5e:28:5f:b0:e8:3f:45:cf:cf: + af:9b:6f:fb:84:d3:77:5a:95:6f:ac:94:84:9e:ee: + bc:c0:4a:8f:4a:93:f8:44:21:e2:31:45:61:50:4e: + 10:d8:e3:35:7c:4c:19:b4:de:05:bf:a3:06:9f:c8: + b5:cd:e4:1f:d7:17:06:0d:7a:95:74:55:0d:68:1a: + fc:10:1b:62:64:9d:6d:e0:95:a0:c3:94:07:57:0d: + 14:e6:bd:05:fb:b8:9f:e6:df:8b:e2:c6:e7:7e:96: + f6:53:c5:80:34:50:28:58:f0:12:50:71:17:30:ba: + e6:78:63:bc:f4:b2:ad:9b:2b:b2:fe:e1:39:8c:5e: + ba:0b:20:94:de:7b:83:b8:ff:e3:56:8d:b7:11:e9: + 3b:8c:f2:b1:c1:5d:9d:a4:0b:4c:2b:d9:b2:18:f5: + b5:9f:4b + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + 52:D8:88:3A:C8:9F:78:66:ED:89:F3:7B:38:70:94:C9:02:02:36:D0 + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Authority Key Identifier: + keyid:52:D8:88:3A:C8:9F:78:66:ED:89:F3:7B:38:70:94:C9:02:02:36:D0 + + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + Signature Algorithm: sha256WithRSAEncryption + 0b:7b:72:87:c0:60:a6:49:4c:88:58:e6:1d:88:f7:14:64:48: + a6:d8:58:0a:0e:4f:13:35:df:35:1d:d4:ed:06:31:c8:81:3e: + 6a:d5:dd:3b:1a:32:ee:90:3d:11:d2:2e:f4:8e:c3:63:2e:23: + 66:b0:67:be:6f:b6:c0:13:39:60:aa:a2:34:25:93:75:52:de: + a7:9d:ad:0e:87:89:52:71:6a:16:3c:19:1d:83:f8:9a:29:65: + be:f4:3f:9a:d9:f0:f3:5a:87:21:71:80:4d:cb:e0:38:9b:3f: + bb:fa:e0:30:4d:cf:86:d3:65:10:19:18:d1:97:02:b1:2b:72: + 42:68:ac:a0:bd:4e:5a:da:18:bf:6b:98:81:d0:fd:9a:be:5e: + 15:48:cd:11:15:b9:c0:29:5c:b4:e8:88:f7:3e:36:ae:b7:62: + fd:1e:62:de:70:78:10:1c:48:5b:da:bc:a4:38:ba:67:ed:55: + 3e:5e:57:df:d4:03:40:4c:81:a4:d2:4f:63:a7:09:42:09:14: + fc:00:a9:c2:80:73:4f:2e:c0:40:d9:11:7b:48:ea:7a:02:c0: + d3:eb:28:01:26:58:74:c1:c0:73:22:6d:93:95:fd:39:7d:bb: + 2a:e3:f6:82:e3:2c:97:5f:4e:1f:91:94:fa:fe:2c:a3:d8:76: + 1a:b8:4d:b2:38:4f:9b:fa:1d:48:60:79:26:e2:f3:fd:a9:d0: + 9a:e8:70:8f:49:7a:d6:e5:bd:0a:0e:db:2d:f3:8d:bf:eb:e3: + a4:7d:cb:c7:95:71:e8:da:a3:7c:c5:c2:f8:74:92:04:1b:86: + ac:a4:22:53:40:b6:ac:fe:4c:76:cf:fb:94:32:c0:35:9f:76: + 3f:6e:e5:90:6e:a0:a6:26:a2:b8:2c:be:d1:2b:85:fd:a7:68: + c8:ba:01:2b:b1:6c:74:1d:b8:73:95:e7:ee:b7:c7:25:f0:00: + 4c:00:b2:7e:b6:0b:8b:1c:f3:c0:50:9e:25:b9:e0:08:de:36: + 66:ff:37:a5:d1:bb:54:64:2c:c9:27:b5:4b:92:7e:65:ff:d3: + 2d:e1:b9:4e:bc:7f:a4:41:21:90:41:77:a6:39:1f:ea:9e:e3: + 9f:d0:66:6f:05:ec:aa:76:7e:bf:6b:16:a0:eb:b5:c7:fc:92: + 54:2f:2b:11:27:25:37:78:4c:51:6a:b0:f3:cc:58:5d:14:f1: + 6a:48:15:ff:c2:07:b6:b1:8d:0f:8e:5c:50:46:b3:3d:bf:01: + 98:4f:b2:59:54:47:3e:34:7b:78:6d:56:93:2e:73:ea:66:28: + 78:cd:1d:14:bf:a0:8f:2f:2e:b8:2e:8e:f2:14:8a:cc:e9:b5: + 7c:fb:6c:9d:0c:a5:e1:96 +-----BEGIN CERTIFICATE----- +MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UE +BhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8w +MzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290 +IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDkyMjExMjIwMlowazELMAkGA1UEBhMC +SVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1 +ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENB +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNv +UTufClrJwkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX +4ay8IMKx4INRimlNAJZaby/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9 +KK3giq0itFZljoZUj5NDKd45RnijMCO6zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/ +gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1fYVEiVRvjRuPjPdA1Yprb +rxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2oxgkg4YQ +51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2F +be8lEfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxe +KF+w6D9Fz8+vm2/7hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4F +v6MGn8i1zeQf1xcGDXqVdFUNaBr8EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbn +fpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5jF66CyCU3nuDuP/jVo23Eek7 +jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLYiDrIn3hm7Ynz +ezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt +ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAL +e3KHwGCmSUyIWOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70 +jsNjLiNmsGe+b7bAEzlgqqI0JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDz +WochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKxK3JCaKygvU5a2hi/a5iB0P2avl4V +SM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+Xlff1ANATIGk0k9j +pwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC4yyX +X04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+Ok +fcvHlXHo2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7R +K4X9p2jIugErsWx0Hbhzlefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btU +ZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXemOR/qnuOf0GZvBeyqdn6/axag67XH/JJU +LysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9vwGYT7JZVEc+NHt4bVaT +LnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg== +-----END CERTIFICATE----- + +Trustis FPS Root CA +# Issuer: OU=Trustis FPS Root CA,O=Trustis Limited,C=GB +# Serial Number:1b:1f:ad:b6:20:f9:24:d3:36:6b:f7:c7:f1:8c:a0:59 +# Subject: OU=Trustis FPS Root CA,O=Trustis Limited,C=GB +# Not Valid Before: Tue Dec 23 12:14:06 2003 +# Not Valid After : Sun Jan 21 11:36:54 2024 +# Fingerprint (MD5): 30:C9:E7:1E:6B:E6:14:EB:65:B2:16:69:20:31:67:4D +# Fingerprint (SHA1): 3B:C0:38:0B:33:C3:F6:A6:0C:86:15:22:93:D9:DF:F5:4B:81:C0:04 +MUST_VERIFY_TRUST: CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +================================================ +MD5 Fingerprint=30:C9:E7:1E:6B:E6:14:EB:65:B2:16:69:20:31:67:4D +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 1b:1f:ad:b6:20:f9:24:d3:36:6b:f7:c7:f1:8c:a0:59 + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=GB, O=Trustis Limited, OU=Trustis FPS Root CA + Validity + Not Before: Dec 23 12:14:06 2003 GMT + Not After : Jan 21 11:36:54 2024 GMT + Subject: C=GB, O=Trustis Limited, OU=Trustis FPS Root CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:c5:50:7b:9e:3b:35:d0:df:c4:8c:cd:8e:9b:ed: + a3:c0:36:99:f4:42:ea:a7:3e:80:83:0f:a6:a7:59: + 87:c9:90:45:43:7e:00:ea:86:79:2a:03:bd:3d:37: + 99:89:66:b7:e5:8a:56:86:93:9c:68:4b:68:04:8c: + 93:93:02:3e:30:d2:37:3a:22:61:89:1c:85:4e:7d: + 8f:d5:af:7b:35:f6:7e:28:47:89:31:dc:0e:79:64: + 1f:99:d2:5b:ba:fe:7f:60:bf:ad:eb:e7:3c:38:29: + 6a:2f:e5:91:0b:55:ff:ec:6f:58:d5:2d:c9:de:4c: + 66:71:8f:0c:d7:04:da:07:e6:1e:18:e3:bd:29:02: + a8:fa:1c:e1:5b:b9:83:a8:41:48:bc:1a:71:8d:e7: + 62:e5:2d:b2:eb:df:7c:cf:db:ab:5a:ca:31:f1:4c: + 22:f3:05:13:f7:82:f9:73:79:0c:be:d7:4b:1c:c0: + d1:15:3c:93:41:64:d1:e6:be:23:17:22:00:89:5e: + 1f:6b:a5:ac:6e:a7:4b:8c:ed:a3:72:e6:af:63:4d: + 2f:85:d2:14:35:9a:2e:4e:8c:ea:32:98:28:86:a1: + 91:09:41:3a:b4:e1:e3:f2:fa:f0:c9:0a:a2:41:dd: + a9:e3:03:c7:88:15:3b:1c:d4:1a:94:d7:9f:64:59: + 12:6d + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Authority Key Identifier: + keyid:BA:FA:71:25:79:8B:57:41:25:21:86:0B:71:EB:B2:64:0E:8B:21:67 + + X509v3 Subject Key Identifier: + BA:FA:71:25:79:8B:57:41:25:21:86:0B:71:EB:B2:64:0E:8B:21:67 + Signature Algorithm: sha1WithRSAEncryption + 7e:58:ff:fd:35:19:7d:9c:18:4f:9e:b0:2b:bc:8e:8c:14:ff: + 2c:a0:da:47:5b:c3:ef:81:2d:af:05:ea:74:48:5b:f3:3e:4e: + 07:c7:6d:c5:b3:93:cf:22:35:5c:b6:3f:75:27:5f:09:96:cd: + a0:fe:be:40:0c:5c:12:55:f8:93:82:ca:29:e9:5e:3f:56:57: + 8b:38:36:f7:45:1a:4c:28:cd:9e:41:b8:ed:56:4c:84:a4:40: + c8:b8:b0:a5:2b:69:70:04:6a:c3:f8:d4:12:32:f9:0e:c3:b1: + dc:32:84:44:2c:6f:cb:46:0f:ea:66:41:0f:4f:f1:58:a5:a6: + 0d:0d:0f:61:de:a5:9e:5d:7d:65:a1:3c:17:e7:a8:55:4e:ef: + a0:c7:ed:c6:44:7f:54:f5:a3:e0:8f:f0:7c:55:22:8f:29:b6: + 81:a3:e1:6d:4e:2c:1b:80:67:ec:ad:20:9f:0c:62:61:d5:97: + ff:43:ed:2d:c1:da:5d:29:2a:85:3f:ac:65:ee:86:0f:05:8d: + 90:5f:df:ee:9f:f4:bf:ee:1d:fb:98:e4:7f:90:2b:84:78:10: + 0e:6c:49:53:ef:15:5b:65:46:4a:5d:af:ba:fb:3a:72:1d:cd: + f6:25:88:1e:97:cc:21:9c:29:01:0d:65:eb:57:d9:f3:57:96: + bb:48:cd:81 +-----BEGIN CERTIFICATE----- +MIIDZzCCAk+gAwIBAgIQGx+ttiD5JNM2a/fH8YygWTANBgkqhkiG9w0BAQUFADBF +MQswCQYDVQQGEwJHQjEYMBYGA1UEChMPVHJ1c3RpcyBMaW1pdGVkMRwwGgYDVQQL +ExNUcnVzdGlzIEZQUyBSb290IENBMB4XDTAzMTIyMzEyMTQwNloXDTI0MDEyMTEx +MzY1NFowRTELMAkGA1UEBhMCR0IxGDAWBgNVBAoTD1RydXN0aXMgTGltaXRlZDEc +MBoGA1UECxMTVHJ1c3RpcyBGUFMgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAMVQe547NdDfxIzNjpvto8A2mfRC6qc+gIMPpqdZh8mQRUN+ +AOqGeSoDvT03mYlmt+WKVoaTnGhLaASMk5MCPjDSNzoiYYkchU59j9WvezX2fihH +iTHcDnlkH5nSW7r+f2C/revnPDgpai/lkQtV/+xvWNUtyd5MZnGPDNcE2gfmHhjj +vSkCqPoc4Vu5g6hBSLwacY3nYuUtsuvffM/bq1rKMfFMIvMFE/eC+XN5DL7XSxzA +0RU8k0Fk0ea+IxciAIleH2ulrG6nS4zto3Lmr2NNL4XSFDWaLk6M6jKYKIahkQlB +OrTh4/L68MkKokHdqeMDx4gVOxzUGpTXn2RZEm0CAwEAAaNTMFEwDwYDVR0TAQH/ +BAUwAwEB/zAfBgNVHSMEGDAWgBS6+nEleYtXQSUhhgtx67JkDoshZzAdBgNVHQ4E +FgQUuvpxJXmLV0ElIYYLceuyZA6LIWcwDQYJKoZIhvcNAQEFBQADggEBAH5Y//01 +GX2cGE+esCu8jowU/yyg2kdbw++BLa8F6nRIW/M+TgfHbcWzk88iNVy2P3UnXwmW +zaD+vkAMXBJV+JOCyinpXj9WV4s4NvdFGkwozZ5BuO1WTISkQMi4sKUraXAEasP4 +1BIy+Q7DsdwyhEQsb8tGD+pmQQ9P8Vilpg0ND2HepZ5dfWWhPBfnqFVO76DH7cZE +f1T1o+CP8HxVIo8ptoGj4W1OLBuAZ+ytIJ8MYmHVl/9D7S3B2l0pKoU/rGXuhg8F +jZBf3+6f9L/uHfuY5H+QK4R4EA5sSVPvFVtlRkpdr7r7OnIdzfYliB6XzCGcKQEN +ZetX2fNXlrtIzYE= +-----END CERTIFICATE----- + +Buypass Class 2 Root CA +# Issuer: CN=Buypass Class 2 Root CA,O=Buypass AS-983163327,C=NO +# Serial Number: 2 (0x2) +# Subject: CN=Buypass Class 2 Root CA,O=Buypass AS-983163327,C=NO +# Not Valid Before: Tue Oct 26 08:38:03 2010 +# Not Valid After : Fri Oct 26 08:38:03 2040 +# Fingerprint (MD5): 46:A7:D2:FE:45:FB:64:5A:A8:59:90:9B:78:44:9B:29 +# Fingerprint (SHA1): 49:0A:75:74:DE:87:0A:47:FE:58:EE:F6:C7:6B:EB:C6:0B:12:40:99 +TRUSTED_DELEGATOR: SERVER_AUTH +MUST_VERIFY_TRUST: EMAIL_PROTECTION, CODE_SIGNING +================================================= +MD5 Fingerprint=46:A7:D2:FE:45:FB:64:5A:A8:59:90:9B:78:44:9B:29 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 2 (0x2) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=NO, O=Buypass AS-983163327, CN=Buypass Class 2 Root CA + Validity + Not Before: Oct 26 08:38:03 2010 GMT + Not After : Oct 26 08:38:03 2040 GMT + Subject: C=NO, O=Buypass AS-983163327, CN=Buypass Class 2 Root CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:d7:c7:5e:f7:c1:07:d4:77:fb:43:21:f4:f4:f5: + 69:e4:ee:32:01:db:a3:86:1f:e4:59:0d:ba:e7:75: + 83:52:eb:ea:1c:61:15:48:bb:1d:07:ca:8c:ae:b0: + dc:96:9d:ea:c3:60:92:86:82:28:73:9c:56:06:ff: + 4b:64:f0:0c:2a:37:49:b5:e5:cf:0c:7c:ee:f1:4a: + bb:73:30:65:f3:d5:2f:83:b6:7e:e3:e7:f5:9e:ab: + 60:f9:d3:f1:9d:92:74:8a:e4:1c:96:ac:5b:80:e9: + b5:f4:31:87:a3:51:fc:c7:7e:a1:6f:8e:53:77:d4: + 97:c1:55:33:92:3e:18:2f:75:d4:ad:86:49:cb:95: + af:54:06:6c:d8:06:13:8d:5b:ff:e1:26:19:59:c0: + 24:ba:81:71:79:90:44:50:68:24:94:5f:b8:b3:11: + f1:29:41:61:a3:41:cb:23:36:d5:c1:f1:32:50:10: + 4e:7f:f4:86:93:ec:84:d3:8e:bc:4b:bf:5c:01:4e: + 07:3d:dc:14:8a:94:0a:a4:ea:73:fb:0b:51:e8:13: + 07:18:fa:0e:f1:2b:d1:54:15:7d:3c:e1:f7:b4:19: + 42:67:62:5e:77:e0:a2:55:ec:b6:d9:69:17:d5:3a: + af:44:ed:4a:c5:9e:e4:7a:27:7c:e5:75:d7:aa:cb: + 25:e7:df:6b:0a:db:0f:4d:93:4e:a8:a0:cd:7b:2e: + f2:59:01:6a:b7:0d:b8:07:81:7e:8b:38:1b:38:e6: + 0a:57:99:3d:ee:21:e8:a3:f5:0c:16:dd:8b:ec:34: + 8e:9c:2a:1c:00:15:17:8d:68:83:d2:70:9f:18:08: + cd:11:68:d5:c9:6b:52:cd:c4:46:8f:dc:b5:f3:d8: + 57:73:1e:e9:94:39:04:bf:d3:de:38:de:b4:53:ec: + 69:1c:a2:7e:c4:8f:e4:1b:70:ad:f2:a2:f9:fb:f7: + 16:64:66:69:9f:49:51:a2:e2:15:18:67:06:4a:7f: + d5:6c:b5:4d:b3:33:e0:61:eb:5d:be:e9:98:0f:32: + d7:1d:4b:3c:2e:5a:01:52:91:09:f2:df:ea:8d:d8: + 06:40:63:aa:11:e4:fe:c3:37:9e:14:52:3f:f4:e2: + cc:f2:61:93:d1:fd:67:6b:d7:52:ae:bf:68:ab:40: + 43:a0:57:35:53:78:f0:53:f8:61:42:07:64:c6:d7: + 6f:9b:4c:38:0d:63:ac:62:af:36:8b:a2:73:0a:0d: + f5:21:bd:74:aa:4d:ea:72:03:49:db:c7:5f:1d:62: + 63:c7:fd:dd:91:ec:33:ee:f5:6d:b4:6e:30:68:de: + c8:d6:26:b0:75:5e:7b:b4:07:20:98:a1:76:32:b8: + 4d:6c:4f + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + C9:80:77:E0:62:92:82:F5:46:9C:F3:BA:F7:4C:C3:DE:B8:A3:AD:39 + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + Signature Algorithm: sha256WithRSAEncryption + 53:5f:21:f5:ba:b0:3a:52:39:2c:92:b0:6c:00:c9:ef:ce:20: + ef:06:f2:96:9e:e9:a4:74:7f:7a:16:fc:b7:f5:b6:fb:15:1b: + 3f:ab:a6:c0:72:5d:10:b1:71:ee:bc:4f:e3:ad:ac:03:6d:2e: + 71:2e:af:c4:e3:ad:a3:bd:0c:11:a7:b4:ff:4a:b2:7b:10:10: + 1f:a7:57:41:b2:c0:ae:f4:2c:59:d6:47:10:88:f3:21:51:29: + 30:ca:60:86:af:46:ab:1d:ed:3a:5b:b0:94:de:44:e3:41:08: + a2:c1:ec:1d:d6:fd:4f:b6:d6:47:d0:14:0b:ca:e6:ca:b5:7b: + 77:7e:41:1f:5e:83:c7:b6:8c:39:96:b0:3f:96:81:41:6f:60: + 90:e2:e8:f9:fb:22:71:d9:7d:b3:3d:46:bf:b4:84:af:90:1c: + 0f:8f:12:6a:af:ef:ee:1e:7a:ae:02:4a:8a:17:2b:76:fe:ac: + 54:89:24:2c:4f:3f:b6:b2:a7:4e:8c:a8:91:97:fb:29:c6:7b: + 5c:2d:b9:cb:66:b6:b7:a8:5b:12:51:85:b5:09:7e:62:78:70: + fe:a9:6a:60:b6:1d:0e:79:0c:fd:ca:ea:24:80:72:c3:97:3f: + f2:77:ab:43:22:0a:c7:eb:b6:0c:84:82:2c:80:6b:41:8a:08: + c0:eb:a5:6b:df:99:12:cb:8a:d5:5e:80:0c:91:e0:26:08:36: + 48:c5:fa:38:11:35:ff:25:83:2d:f2:7a:bf:da:fd:8e:fe:a5: + cb:45:2c:1f:c4:88:53:ae:77:0e:d9:9a:76:c5:8e:2c:1d:a3: + ba:d5:ec:32:ae:c0:aa:ac:f7:d1:7a:4d:eb:d4:07:e2:48:f7: + 22:8e:b0:a4:9f:6a:ce:8e:b2:b2:60:f4:a3:22:d0:23:eb:94: + 5a:7a:69:dd:0f:bf:40:57:ac:6b:59:50:d9:a3:99:e1:6e:fe: + 8d:01:79:27:23:15:de:92:9d:7b:09:4d:5a:e7:4b:48:30:5a: + 18:e6:0a:6d:e6:8f:e0:d2:bb:e6:df:7c:6e:21:82:c1:68:39: + 4d:b4:98:58:66:62:cc:4a:90:5e:c3:fa:27:04:b1:79:15:74: + 99:cc:be:ad:20:de:26:60:1c:eb:56:51:a6:a3:ea:e4:a3:3f: + a7:ff:61:dc:f1:5a:4d:6c:32:23:43:ee:ac:a8:ee:ee:4a:12: + 09:3c:5d:71:c2:be:79:fa:c2:87:68:1d:0b:fd:5c:69:cc:06: + d0:9a:7d:54:99:2a:c9:39:1a:19:af:4b:2a:43:f3:63:5d:5a: + 58:e2:2f:e3:1d:e4:a9:d6:d0:0a:d0:9e:bf:d7:81:09:f1:c9: + c7:26:0d:ac:98:16:56:a0 +-----BEGIN CERTIFICATE----- +MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd +MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg +Q2xhc3MgMiBSb290IENBMB4XDTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1ow +TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw +HgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB +BQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1g1Lr +6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPV +L4O2fuPn9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC91 +1K2GScuVr1QGbNgGE41b/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHx +MlAQTn/0hpPshNOOvEu/XAFOBz3cFIqUCqTqc/sLUegTBxj6DvEr0VQVfTzh97QZ +QmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeffawrbD02TTqigzXsu8lkB +arcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgIzRFo1clr +Us3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLi +FRhnBkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRS +P/TizPJhk9H9Z2vXUq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN +9SG9dKpN6nIDSdvHXx1iY8f93ZHsM+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxP +AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMmAd+BikoL1Rpzz +uvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAU18h +9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s +A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3t +OluwlN5E40EIosHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo ++fsicdl9sz1Gv7SEr5AcD48Saq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7 +KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYdDnkM/crqJIByw5c/8nerQyIKx+u2 +DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWDLfJ6v9r9jv6ly0Us +H8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0oyLQ +I+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK7 +5t98biGCwWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h +3PFaTWwyI0PurKju7koSCTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPz +Y11aWOIv4x3kqdbQCtCev9eBCfHJxyYNrJgWVqA= +-----END CERTIFICATE----- + +Buypass Class 3 Root CA +# Issuer: CN=Buypass Class 3 Root CA,O=Buypass AS-983163327,C=NO +# Serial Number: 2 (0x2) +# Subject: CN=Buypass Class 3 Root CA,O=Buypass AS-983163327,C=NO +# Not Valid Before: Tue Oct 26 08:28:58 2010 +# Not Valid After : Fri Oct 26 08:28:58 2040 +# Fingerprint (MD5): 3D:3B:18:9E:2C:64:5A:E8:D5:88:CE:0E:F9:37:C2:EC +# Fingerprint (SHA1): DA:FA:F7:FA:66:84:EC:06:8F:14:50:BD:C7:C2:81:A5:BC:A9:64:57 +MUST_VERIFY_TRUST: EMAIL_PROTECTION, CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH +================================================= +MD5 Fingerprint=3D:3B:18:9E:2C:64:5A:E8:D5:88:CE:0E:F9:37:C2:EC +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 2 (0x2) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=NO, O=Buypass AS-983163327, CN=Buypass Class 3 Root CA + Validity + Not Before: Oct 26 08:28:58 2010 GMT + Not After : Oct 26 08:28:58 2040 GMT + Subject: C=NO, O=Buypass AS-983163327, CN=Buypass Class 3 Root CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:a5:da:0a:95:16:50:e3:95:f2:5e:9d:76:31:06: + 32:7a:9b:f1:10:76:b8:00:9a:b5:52:36:cd:24:47: + b0:9f:18:64:bc:9a:f6:fa:d5:79:d8:90:62:4c:22: + 2f:de:38:3d:d6:e0:a8:e9:1c:2c:db:78:11:e9:8e: + 68:51:15:72:c7:f3:33:87:e4:a0:5d:0b:5c:e0:57: + 07:2a:30:f5:cd:c4:37:77:28:4d:18:91:e6:bf:d5: + 52:fd:71:2d:70:3e:e7:c6:c4:8a:e3:f0:28:0b:f4: + 76:98:a1:8b:87:55:b2:3a:13:fc:b7:3e:27:37:8e: + 22:e3:a8:4f:2a:ef:60:bb:3d:b7:39:c3:0e:01:47: + 99:5d:12:4f:db:43:fa:57:a1:ed:f9:9d:be:11:47: + 26:5b:13:98:ab:5d:16:8a:b0:37:1c:57:9d:45:ff: + 88:96:36:bf:bb:ca:07:7b:6f:87:63:d7:d0:32:6a: + d6:5d:6c:0c:f1:b3:6e:39:e2:6b:31:2e:39:00:27: + 14:de:38:c0:ec:19:66:86:12:e8:9d:72:16:13:64: + 52:c7:a9:37:1c:fd:82:30:ed:84:18:1d:f4:ae:5c: + ff:70:13:00:eb:b1:f5:33:7a:4b:d6:55:f8:05:8d: + 4b:69:b0:f5:b3:28:36:5c:14:c4:51:73:4d:6b:0b: + f1:34:07:db:17:39:d7:dc:28:7b:6b:f5:9f:f3:2e: + c1:4f:17:2a:10:f3:cc:ca:e8:eb:fd:6b:ab:2e:9a: + 9f:2d:82:6e:04:d4:52:01:93:2d:3d:86:fc:7e:fc: + df:ef:42:1d:a6:6b:ef:b9:20:c6:f7:bd:a0:a7:95: + fd:a7:e6:89:24:d8:cc:8c:34:6c:e2:23:2f:d9:12: + 1a:21:b9:55:91:6f:0b:91:79:19:0c:ad:40:88:0b: + 70:e2:7a:d2:0e:d8:68:48:bb:82:13:39:10:58:e9: + d8:2a:07:c6:12:db:58:db:d2:3b:55:10:47:05:15: + 67:62:7e:18:63:a6:46:3f:09:0e:54:32:5e:bf:0d: + 62:7a:27:ef:80:e8:db:d9:4b:06:5a:37:5a:25:d0: + 08:12:77:d4:6f:09:50:97:3d:c8:1d:c3:df:8c:45: + 30:56:c6:d3:64:ab:66:f3:c0:5e:96:9c:c3:c4:ef: + c3:7c:6b:8b:3a:79:7f:b3:49:cf:3d:e2:89:9f:a0: + 30:4b:85:b9:9c:94:24:79:8f:7d:6b:a9:45:68:0f: + 2b:d0:f1:da:1c:cb:69:b8:ca:49:62:6d:c8:d0:63: + 62:dd:60:0f:58:aa:8f:a1:bc:05:a5:66:a2:cf:1b: + 76:b2:84:64:b1:4c:39:52:c0:30:ba:f0:8c:4b:02: + b0:b6:b7 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + 47:B8:CD:FF:E5:6F:EE:F8:B2:EC:2F:4E:0E:F9:25:B0:8E:3C:6B:C3 + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + Signature Algorithm: sha256WithRSAEncryption + 00:20:23:41:35:04:90:c2:40:62:60:ef:e2:35:4c:d7:3f:ac: + e2:34:90:b8:a1:6f:76:fa:16:16:a4:48:37:2c:e9:90:c2:f2: + 3c:f8:0a:9f:d8:81:e5:bb:5b:da:25:2c:a4:a7:55:71:24:32: + f6:c8:0b:f2:bc:6a:f8:93:ac:b2:07:c2:5f:9f:db:cc:c8:8a: + aa:be:6a:6f:e1:49:10:cc:31:d7:80:bb:bb:c8:d8:a2:0e:64: + 57:ea:a2:f5:c2:a9:31:15:d2:20:6a:ec:fc:22:01:28:cf:86: + b8:80:1e:a9:cc:11:a5:3c:f2:16:b3:47:9d:fc:d2:80:21:c4: + cb:d0:47:70:41:a1:ca:83:19:08:2c:6d:f2:5d:77:9c:8a:14: + 13:d4:36:1c:92:f0:e5:06:37:dc:a6:e6:90:9b:38:8f:5c:6b: + 1b:46:86:43:42:5f:3e:01:07:53:54:5d:65:7d:f7:8a:73:a1: + 9a:54:5a:1f:29:43:14:27:c2:85:0f:b5:88:7b:1a:3b:94:b7: + 1d:60:a7:b5:9c:e7:29:69:57:5a:9b:93:7a:43:30:1b:03:d7: + 62:c8:40:a6:aa:fc:64:e4:4a:d7:91:53:01:a8:20:88:6e:9c: + 5f:44:b9:cb:60:81:34:ec:6f:d3:7d:da:48:5f:eb:b4:90:bc: + 2d:a9:1c:0b:ac:1c:d5:a2:68:20:80:04:d6:fc:b1:8f:2f:bb: + 4a:31:0d:4a:86:1c:eb:e2:36:29:26:f5:da:d8:c4:f2:75:61: + cf:7e:ae:76:63:4a:7a:40:65:93:87:f8:1e:80:8c:86:e5:86: + d6:8f:0e:fc:53:2c:60:e8:16:61:1a:a2:3e:43:7b:cd:39:60: + 54:6a:f5:f2:89:26:01:68:83:48:a2:33:e8:c9:04:91:b2:11: + 34:11:3e:ea:d0:43:19:1f:03:93:90:0c:ff:51:3d:57:f4:41: + 6e:e1:cb:a0:be:eb:c9:63:cd:6d:cc:e4:f8:36:aa:68:9d:ed: + bd:5d:97:70:44:0d:b6:0e:35:dc:e1:0c:5d:bb:a0:51:94:cb: + 7e:16:eb:11:2f:a3:92:45:c8:4c:71:d9:bc:c9:99:52:57:46: + 2f:50:cf:bd:35:69:f4:3d:15:ce:06:a5:2c:0f:3e:f6:81:ba: + 94:bb:c3:bb:bf:65:78:d2:86:79:ff:49:3b:1a:83:0c:f0:de: + 78:ec:c8:f2:4d:4c:1a:de:82:29:f8:c1:5a:da:ed:ee:e6:27: + 5e:e8:45:d0:9d:1c:51:a8:68:ab:44:e3:d0:8b:6a:e3:f8:3b: + bb:dc:4d:d7:64:f2:51:be:e6:aa:ab:5a:e9:31:ee:06:bc:73: + bf:13:62:0a:9f:c7:b9:97 +-----BEGIN CERTIFICATE----- +MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd +MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg +Q2xhc3MgMyBSb290IENBMB4XDTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFow +TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw +HgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB +BQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRHsJ8Y +ZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3E +N3coTRiR5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9 +tznDDgFHmV0ST9tD+leh7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX +0DJq1l1sDPGzbjniazEuOQAnFN44wOwZZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c +/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH2xc519woe2v1n/MuwU8X +KhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV/afmiSTY +zIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvS +O1UQRwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D +34xFMFbG02SrZvPAXpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgP +K9Dx2hzLabjKSWJtyNBjYt1gD1iqj6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3 +AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFEe4zf/lb+74suwv +Tg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAACAj +QTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV +cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXS +IGrs/CIBKM+GuIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2 +HJLw5QY33KbmkJs4j1xrG0aGQ0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsa +O5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8ZORK15FTAaggiG6cX0S5y2CBNOxv +033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2KSb12tjE8nVhz36u +dmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz6MkE +kbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg41 +3OEMXbugUZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvD +u79leNKGef9JOxqDDPDeeOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq +4/g7u9xN12TyUb7mqqta6THuBrxzvxNiCp/HuZc= +-----END CERTIFICATE----- + +T-TeleSec GlobalRoot Class 3 +# Issuer: CN=T-TeleSec GlobalRoot Class 3,OU=T-Systems Trust Center,O=T-Systems Enterprise Services GmbH,C=DE +# Serial Number: 1 (0x1) +# Subject: CN=T-TeleSec GlobalRoot Class 3,OU=T-Systems Trust Center,O=T-Systems Enterprise Services GmbH,C=DE +# Not Valid Before: Wed Oct 01 10:29:56 2008 +# Not Valid After : Sat Oct 01 23:59:59 2033 +# Fingerprint (MD5): CA:FB:40:A8:4E:39:92:8A:1D:FE:8E:2F:C4:27:EA:EF +# Fingerprint (SHA1): 55:A6:72:3E:CB:F2:EC:CD:C3:23:74:70:19:9D:2A:BE:11:E3:81:D1 +TRUSTED_DELEGATOR: SERVER_AUTH +MUST_VERIFY_TRUST: EMAIL_PROTECTION, CODE_SIGNING +================================================= +MD5 Fingerprint=CA:FB:40:A8:4E:39:92:8A:1D:FE:8E:2F:C4:27:EA:EF +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 1 (0x1) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=DE, O=T-Systems Enterprise Services GmbH, OU=T-Systems Trust Center, CN=T-TeleSec GlobalRoot Class 3 + Validity + Not Before: Oct 1 10:29:56 2008 GMT + Not After : Oct 1 23:59:59 2033 GMT + Subject: C=DE, O=T-Systems Enterprise Services GmbH, OU=T-Systems Trust Center, CN=T-TeleSec GlobalRoot Class 3 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:bd:75:93:f0:62:22:6f:24:ae:e0:7a:76:ac:7d: + bd:d9:24:d5:b8:b7:fc:cd:f0:42:e0:eb:78:88:56: + 5e:9b:9a:54:1d:4d:0c:8a:f6:d3:cf:70:f4:52:b5: + d8:93:04:e3:46:86:71:41:4a:2b:f0:2a:2c:55:03: + d6:48:c3:e0:39:38:ed:f2:5c:3c:3f:44:bc:93:3d: + 61:ab:4e:cd:0d:be:f0:20:27:58:0e:44:7f:04:1a: + 87:a5:d7:96:14:36:90:d0:49:7b:a1:75:fb:1a:6b: + 73:b1:f8:ce:a9:09:2c:f2:53:d5:c3:14:44:b8:86: + a5:f6:8b:2b:39:da:a3:33:54:d9:fa:72:1a:f7:22: + 15:1c:88:91:6b:7f:66:e5:c3:6a:80:b0:24:f3:df: + 86:45:88:fd:19:7f:75:87:1f:1f:b1:1b:0a:73:24: + 5b:b9:65:e0:2c:54:c8:60:d3:66:17:3f:e1:cc:54: + 33:73:91:02:3a:a6:7f:7b:76:39:a2:1f:96:b6:38: + ae:b5:c8:93:74:1d:9e:b9:b4:e5:60:9d:2f:56:d1: + e0:eb:5e:5b:4c:12:70:0c:6c:44:20:ab:11:d8:f4: + 19:f6:d2:9c:52:37:e7:fa:b6:c2:31:3b:4a:d4:14: + 99:ad:c7:1a:f5:5d:5f:fa:07:b8:7c:0d:1f:d6:83: + 1e:b3 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + B5:03:F7:76:3B:61:82:6A:12:AA:18:53:EB:03:21:94:BF:FE:CE:CA + Signature Algorithm: sha256WithRSAEncryption + 56:3d:ef:94:d5:bd:da:73:b2:58:be:ae:90:ad:98:27:97:fe: + 01:b1:b0:52:00:b8:4d:e4:1b:21:74:1b:7e:c0:ee:5e:69:2a: + 25:af:5c:d6:1d:da:d2:79:c9:f3:97:29:e0:86:87:de:04:59: + 0f:f1:59:d4:64:85:4b:99:af:25:04:1e:c9:46:a9:97:de:82: + b2:1b:70:9f:9c:f6:af:71:31:dd:7b:05:a5:2c:d3:b9:ca:47: + f6:ca:f2:f6:e7:ad:b9:48:3f:bc:16:b7:c1:6d:f4:ea:09:af: + ec:f3:b5:e7:05:9e:a6:1e:8a:53:51:d6:93:81:cc:74:93:f6: + b9:da:a6:25:05:74:79:5a:7e:40:3e:82:4b:26:11:30:6e:e1: + 3f:41:c7:47:00:35:d5:f5:d3:f7:54:3e:81:3d:da:49:6a:9a: + b3:ef:10:3d:e6:eb:6f:d1:c8:22:47:cb:cc:cf:01:31:92:d9: + 18:e3:22:be:09:1e:1a:3e:5a:b2:e4:6b:0c:54:7a:7d:43:4e: + b8:89:a5:7b:d7:a2:3d:96:86:cc:f2:26:34:2d:6a:92:9d:9a: + 1a:d0:30:e2:5d:4e:04:b0:5f:8b:20:7e:77:c1:3d:95:82:d1: + 46:9a:3b:3c:78:b8:6f:a1:d0:0d:64:a2:78:1e:29:4e:93:c3: + a4:54:14:5b +-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx +KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd +BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl +YyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgxMDAxMTAyOTU2WhcNMzMxMDAxMjM1 +OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy +aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50 +ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN +8ELg63iIVl6bmlQdTQyK9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/ +RLyTPWGrTs0NvvAgJ1gORH8EGoel15YUNpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4 +hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZFiP0Zf3WHHx+xGwpzJFu5 +ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W0eDrXltM +EnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGj +QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1 +A/d2O2GCahKqGFPrAyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOy +WL6ukK2YJ5f+AbGwUgC4TeQbIXQbfsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ +1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzTucpH9sry9uetuUg/vBa3wW30 +6gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7hP0HHRwA11fXT +91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml +e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4p +TpPDpFQUWw== +-----END CERTIFICATE----- + +EE Certification Centre Root CA +# Issuer: E=pki@sk.ee,CN=EE Certification Centre Root CA,O=AS Sertifitseerimiskeskus,C=EE +# Serial Number:54:80:f9:a0:73:ed:3f:00:4c:ca:89:d8:e3:71:e6:4a +# Subject: E=pki@sk.ee,CN=EE Certification Centre Root CA,O=AS Sertifitseerimiskeskus,C=EE +# Not Valid Before: Sat Oct 30 10:10:30 2010 +# Not Valid After : Tue Dec 17 23:59:59 2030 +# Fingerprint (MD5): 43:5E:88:D4:7D:1A:4A:7E:FD:84:2E:52:EB:01:D4:6F +# Fingerprint (SHA1): C9:A8:B9:E7:55:80:5E:58:E3:53:77:A7:25:EB:AF:C3:7B:27:CC:D7 +MUST_VERIFY_TRUST: EMAIL_PROTECTION, CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH +================================================= +MD5 Fingerprint=43:5E:88:D4:7D:1A:4A:7E:FD:84:2E:52:EB:01:D4:6F +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 54:80:f9:a0:73:ed:3f:00:4c:ca:89:d8:e3:71:e6:4a + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=EE, O=AS Sertifitseerimiskeskus, CN=EE Certification Centre Root CA/emailAddress=pki@sk.ee + Validity + Not Before: Oct 30 10:10:30 2010 GMT + Not After : Dec 17 23:59:59 2030 GMT + Subject: C=EE, O=AS Sertifitseerimiskeskus, CN=EE Certification Centre Root CA/emailAddress=pki@sk.ee + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:c8:20:c0:ec:e0:c5:4b:ab:07:78:95:f3:44:ee: + fb:0b:0c:ff:74:8e:61:bb:b1:62:ea:23:d8:ab:a1: + 65:32:7a:eb:8e:17:4f:96:d8:0a:7b:91:a2:63:6c: + c7:8c:4c:2e:79:bf:a9:05:fc:69:5c:95:8d:62:f9: + b9:70:ed:c3:51:7d:d0:93:e6:6c:eb:30:4b:e1:bc: + 7d:bf:52:9b:ce:6e:7b:65:f2:38:b1:c0:a2:32:ef: + 62:b2:68:e0:61:53:c1:36:95:ff:ec:94:ba:36:ae: + 9c:1c:a7:32:0f:e5:7c:b4:c6:6f:74:fd:7b:18:e8: + ac:57:ed:06:20:4b:32:30:58:5b:fd:cd:a8:e6:a1: + fc:70:bc:8e:92:73:db:97:a7:7c:21:ae:3d:c1:f5: + 48:87:6c:27:bd:9f:25:74:81:55:b0:f7:75:f6:3d: + a4:64:6b:d6:4f:e7:ce:40:ad:0f:dd:32:d3:bc:8a: + 12:53:98:c9:89:fb:10:1d:4d:7e:cd:7e:1f:56:0d: + 21:70:85:f6:20:83:1f:f6:ba:1f:04:8f:ea:77:88: + 35:c4:ff:ea:4e:a1:8b:4d:3f:63:1b:44:c3:44:d4: + 25:76:ca:b7:8d:d7:1e:4a:66:64:cd:5c:c5:9c:83: + e1:c2:08:88:9a:ec:4e:a3:f1:3e:1c:2c:d9:6c:1d: + a1:4b + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 12:F2:5A:3E:EA:56:1C:BF:CD:06:AC:F1:F1:25:C9:A9:4B:D4:14:99 + X509v3 Extended Key Usage: + TLS Web Client Authentication, TLS Web Server Authentication, Code Signing, E-mail Protection, Time Stamping, OCSP Signing + Signature Algorithm: sha1WithRSAEncryption + 7b:f6:e4:c0:0d:aa:19:47:b7:4d:57:a3:fe:ad:bb:b1:6a:d5: + 0f:9e:db:e4:63:c5:8e:a1:50:56:93:96:b8:38:c0:24:22:66: + bc:53:14:61:95:bf:d0:c7:2a:96:39:3f:7d:28:b3:10:40:21: + 6a:c4:af:b0:52:77:18:e1:96:d8:56:5d:e3:dd:36:5e:1d:a7: + 50:54:a0:c5:2a:e4:aa:8c:94:8a:4f:9d:35:ff:76:a4:06:13: + 91:a2:a2:7d:00:44:3f:55:d3:82:3c:1a:d5:5b:bc:56:4c:22: + 2e:46:43:8a:24:40:2d:f3:12:b8:3b:70:1a:a4:96:b9:1a:af: + 87:41:1a:6a:18:0d:06:4f:c7:3e:6e:b9:29:4d:0d:49:89:11: + 87:32:5b:e6:4b:04:c8:e4:5c:e6:74:73:94:5d:16:98:13:95: + fe:fb:db:b1:44:e5:3a:70:ac:37:6b:e6:b3:33:72:28:c9:b3: + 57:a0:f6:02:16:88:06:0b:b6:a6:4b:20:28:d4:de:3d:8b:ad: + 37:05:53:74:fe:6e:cc:bc:43:17:71:5e:f9:c5:cc:1a:a9:61: + ee:f7:76:0c:f3:72:f4:72:ad:cf:72:02:36:07:47:cf:ef:19: + 50:89:60:cc:e9:24:95:0f:c2:cb:1d:f2:6f:76:90:c7:cc:75: + c1:96:c5:9d +-----BEGIN CERTIFICATE----- +MIIEAzCCAuugAwIBAgIQVID5oHPtPwBMyonY43HmSjANBgkqhkiG9w0BAQUFADB1 +MQswCQYDVQQGEwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1 +czEoMCYGA1UEAwwfRUUgQ2VydGlmaWNhdGlvbiBDZW50cmUgUm9vdCBDQTEYMBYG +CSqGSIb3DQEJARYJcGtpQHNrLmVlMCIYDzIwMTAxMDMwMTAxMDMwWhgPMjAzMDEy +MTcyMzU5NTlaMHUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKDBlBUyBTZXJ0aWZpdHNl +ZXJpbWlza2Vza3VzMSgwJgYDVQQDDB9FRSBDZXJ0aWZpY2F0aW9uIENlbnRyZSBS +b290IENBMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQDIIMDs4MVLqwd4lfNE7vsLDP90jmG7sWLqI9iroWUy +euuOF0+W2Ap7kaJjbMeMTC55v6kF/GlclY1i+blw7cNRfdCT5mzrMEvhvH2/UpvO +bntl8jixwKIy72KyaOBhU8E2lf/slLo2rpwcpzIP5Xy0xm90/XsY6KxX7QYgSzIw +WFv9zajmofxwvI6Sc9uXp3whrj3B9UiHbCe9nyV0gVWw93X2PaRka9ZP585ArQ/d +MtO8ihJTmMmJ+xAdTX7Nfh9WDSFwhfYggx/2uh8Ej+p3iDXE/+pOoYtNP2MbRMNE +1CV2yreN1x5KZmTNXMWcg+HCCIia7E6j8T4cLNlsHaFLAgMBAAGjgYowgYcwDwYD +VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBLyWj7qVhy/ +zQas8fElyalL1BSZMEUGA1UdJQQ+MDwGCCsGAQUFBwMCBggrBgEFBQcDAQYIKwYB +BQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYIKwYBBQUHAwkwDQYJKoZIhvcNAQEF +BQADggEBAHv25MANqhlHt01Xo/6tu7Fq1Q+e2+RjxY6hUFaTlrg4wCQiZrxTFGGV +v9DHKpY5P30osxBAIWrEr7BSdxjhlthWXePdNl4dp1BUoMUq5KqMlIpPnTX/dqQG +E5Gion0ARD9V04I8GtVbvFZMIi5GQ4okQC3zErg7cBqklrkar4dBGmoYDQZPxz5u +uSlNDUmJEYcyW+ZLBMjkXOZ0c5RdFpgTlf7727FE5TpwrDdr5rMzcijJs1eg9gIW +iAYLtqZLICjU3j2LrTcFU3T+bsy8QxdxXvnFzBqpYe73dgzzcvRyrc9yAjYHR8/v +GVCJYMzpJJUPwssd8m92kMfMdcGWxZ0= +-----END CERTIFICATE----- + +D-TRUST Root Class 3 CA 2 2009 +# Issuer: CN=D-TRUST Root Class 3 CA 2 2009,O=D-Trust GmbH,C=DE +# Serial Number: 623603 (0x983f3) +# Subject: CN=D-TRUST Root Class 3 CA 2 2009,O=D-Trust GmbH,C=DE +# Not Valid Before: Thu Nov 05 08:35:58 2009 +# Not Valid After : Mon Nov 05 08:35:58 2029 +# Fingerprint (MD5): CD:E0:25:69:8D:47:AC:9C:89:35:90:F7:FD:51:3D:2F +# Fingerprint (SHA1): 58:E8:AB:B0:36:15:33:FB:80:F7:9B:1B:6D:29:D3:FF:8D:5F:00:F0 +TRUSTED_DELEGATOR: SERVER_AUTH +MUST_VERIFY_TRUST: EMAIL_PROTECTION, CODE_SIGNING +================================================= +MD5 Fingerprint=CD:E0:25:69:8D:47:AC:9C:89:35:90:F7:FD:51:3D:2F +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 623603 (0x983f3) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=DE, O=D-Trust GmbH, CN=D-TRUST Root Class 3 CA 2 2009 + Validity + Not Before: Nov 5 08:35:58 2009 GMT + Not After : Nov 5 08:35:58 2029 GMT + Subject: C=DE, O=D-Trust GmbH, CN=D-TRUST Root Class 3 CA 2 2009 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:d3:b2:4a:cf:7a:47:ef:75:9b:23:fa:3a:2f:d6: + 50:45:89:35:3a:c6:6b:db:fe:db:00:68:a8:e0:03: + 11:1d:37:50:08:9f:4d:4a:68:94:35:b3:53:d1:94: + 63:a7:20:56:af:de:51:78:ec:2a:3d:f3:48:48:50: + 3e:0a:df:46:55:8b:27:6d:c3:10:4d:0d:91:52:43: + d8:87:e0:5d:4e:36:b5:21:ca:5f:39:40:04:5f:5b: + 7e:cc:a3:c6:2b:a9:40:1e:d9:36:84:d6:48:f3:92: + 1e:34:46:20:24:c1:a4:51:8e:4a:1a:ef:50:3f:69: + 5d:19:7f:45:c3:c7:01:8f:51:c9:23:e8:72:ae:b4: + bc:56:09:7f:12:cb:1c:b1:af:29:90:0a:c9:55:cc: + 0f:d3:b4:1a:ed:47:35:5a:4a:ed:9c:73:04:21:d0: + aa:bd:0c:13:b5:00:ca:26:6c:c4:6b:0c:94:5a:95: + 94:da:50:9a:f1:ff:a5:2b:66:31:a4:c9:38:a0:df: + 1d:1f:b8:09:2e:f3:a7:e8:67:52:ab:95:1f:e0:46: + 3e:d8:a4:c3:ca:5a:c5:31:80:e8:48:9a:9f:94:69: + fe:19:dd:d8:73:7c:81:ca:96:de:8e:ed:b3:32:05: + 65:84:34:e6:e6:fd:57:10:b5:5f:76:bf:2f:b0:10: + 0d:c5 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + FD:DA:14:C4:9F:30:DE:21:BD:1E:42:39:FC:AB:63:23:49:E0:F1:84 + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 CRL Distribution Points: + + Full Name: + URI:ldap://directory.d-trust.net/CN=D-TRUST%20Root%20Class%203%20CA%202%202009,O=D-Trust%20GmbH,C=DE?certificaterevocationlist + + Full Name: + URI:http://www.d-trust.net/crl/d-trust_root_class_3_ca_2_2009.crl + + Signature Algorithm: sha256WithRSAEncryption + 7f:97:db:30:c8:df:a4:9c:7d:21:7a:80:70:ce:14:12:69:88: + 14:95:60:44:01:ac:b2:e9:30:4f:9b:50:c2:66:d8:7e:8d:30: + b5:70:31:e9:e2:69:c7:f3:70:db:20:15:86:d0:0d:f0:be:ac: + 01:75:84:ce:7e:9f:4d:bf:b7:60:3b:9c:f3:ca:1d:e2:5e:68: + d8:a3:9d:97:e5:40:60:d2:36:21:fe:d0:b4:b8:17:da:74:a3: + 7f:d4:df:b0:98:02:ac:6f:6b:6b:2c:25:24:72:a1:65:ee:25: + 5a:e5:e6:32:e7:f2:df:ab:49:fa:f3:90:69:23:db:04:d9:e7: + 5c:58:fc:65:d4:97:be:cc:fc:2e:0a:cc:25:2a:35:04:f8:60: + 91:15:75:3d:41:ff:23:1f:19:c8:6c:eb:82:53:04:a6:e4:4c: + 22:4d:8d:8c:ba:ce:5b:73:ec:64:54:50:6d:d1:9c:55:fb:69: + c3:36:c3:8c:bc:3c:85:a6:6b:0a:26:0d:e0:93:98:60:ae:7e: + c6:24:97:8a:61:5f:91:8e:66:92:09:87:36:cd:8b:9b:2d:3e: + f6:51:d4:50:d4:59:28:bd:83:f2:cc:28:7b:53:86:6d:d8:26: + 88:70:d7:ea:91:cd:3e:b9:ca:c0:90:6e:5a:c6:5e:74:65:d7: + 5c:fe:a3:e2 +-----BEGIN CERTIFICATE----- +MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRF +MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBD +bGFzcyAzIENBIDIgMjAwOTAeFw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NTha +ME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMM +HkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOADER03 +UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42 +tSHKXzlABF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9R +ySPocq60vFYJfxLLHLGvKZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsM +lFqVlNpQmvH/pStmMaTJOKDfHR+4CS7zp+hnUquVH+BGPtikw8paxTGA6Eian5Rp +/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUCAwEAAaOCARowggEWMA8G +A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ4PGEMA4G +A1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVj +dG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUy +MENBJTIwMiUyMDIwMDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRl +cmV2b2NhdGlvbmxpc3QwQ6BBoD+GPWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3Js +L2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAwOS5jcmwwDQYJKoZIhvcNAQEL +BQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm2H6NMLVwMeni +acfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0 +o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4K +zCUqNQT4YJEVdT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8 +PIWmawomDeCTmGCufsYkl4phX5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3Y +Johw1+qRzT65ysCQblrGXnRl11z+o+I= +-----END CERTIFICATE----- + +D-TRUST Root Class 3 CA 2 EV 2009 +# Issuer: CN=D-TRUST Root Class 3 CA 2 EV 2009,O=D-Trust GmbH,C=DE +# Serial Number: 623604 (0x983f4) +# Subject: CN=D-TRUST Root Class 3 CA 2 EV 2009,O=D-Trust GmbH,C=DE +# Not Valid Before: Thu Nov 05 08:50:46 2009 +# Not Valid After : Mon Nov 05 08:50:46 2029 +# Fingerprint (MD5): AA:C6:43:2C:5E:2D:CD:C4:34:C0:50:4F:11:02:4F:B6 +# Fingerprint (SHA1): 96:C9:1B:0B:95:B4:10:98:42:FA:D0:D8:22:79:FE:60:FA:B9:16:83 +MUST_VERIFY_TRUST: EMAIL_PROTECTION, CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH +================================================= +MD5 Fingerprint=AA:C6:43:2C:5E:2D:CD:C4:34:C0:50:4F:11:02:4F:B6 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 623604 (0x983f4) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=DE, O=D-Trust GmbH, CN=D-TRUST Root Class 3 CA 2 EV 2009 + Validity + Not Before: Nov 5 08:50:46 2009 GMT + Not After : Nov 5 08:50:46 2029 GMT + Subject: C=DE, O=D-Trust GmbH, CN=D-TRUST Root Class 3 CA 2 EV 2009 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:99:f1:84:34:70:ba:2f:b7:30:a0:8e:bd:7c:04: + cf:be:62:bc:99:fd:82:97:d2:7a:0a:67:96:38:09: + f6:10:4e:95:22:73:99:8d:da:15:2d:e7:05:fc:19: + 73:22:b7:8e:98:00:bc:3c:3d:ac:a1:6c:fb:d6:79: + 25:4b:ad:f0:cc:64:da:88:3e:29:b8:0f:09:d3:34: + dd:33:f5:62:d1:e1:cd:19:e9:ee:18:4f:4c:58:ae: + e2:1e:d6:0c:5b:15:5a:d8:3a:b8:c4:18:64:1e:e3: + 33:b2:b5:89:77:4e:0c:bf:d9:94:6b:13:97:6f:12: + a3:fe:99:a9:04:cc:15:ec:60:68:36:ed:08:7b:b7: + f5:bf:93:ed:66:31:83:8c:c6:71:34:87:4e:17:ea: + af:8b:91:8d:1c:56:41:ae:22:37:5e:37:f2:1d:d9: + d1:2d:0d:2f:69:51:a7:be:66:a6:8a:3a:2a:bd:c7: + 1a:b1:e1:14:f0:be:3a:1d:b9:cf:5b:b1:6a:fe:b4: + b1:46:20:a2:fb:1e:3b:70:ef:93:98:7d:8c:73:96: + f2:c5:ef:85:70:ad:29:26:fc:1e:04:3e:1c:a0:d8: + 0f:cb:52:83:62:7c:ee:8b:53:95:90:a9:57:a2:ea: + 61:05:d8:f9:4d:c4:27:fa:6e:ad:ed:f9:d7:51:f7: + 6b:a5 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + D3:94:8A:4C:62:13:2A:19:2E:CC:AF:72:8A:7D:36:D7:9A:1C:DC:67 + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 CRL Distribution Points: + + Full Name: + URI:ldap://directory.d-trust.net/CN=D-TRUST%20Root%20Class%203%20CA%202%20EV%202009,O=D-Trust%20GmbH,C=DE?certificaterevocationlist + + Full Name: + URI:http://www.d-trust.net/crl/d-trust_root_class_3_ca_2_ev_2009.crl + + Signature Algorithm: sha256WithRSAEncryption + 34:ed:7b:5a:3c:a4:94:88:ef:1a:11:75:07:2f:b3:fe:3c:fa: + 1e:51:26:eb:87:f6:29:de:e0:f1:d4:c6:24:09:e9:c1:cf:55: + 1b:b4:30:d9:ce:1a:fe:06:51:a6:15:a4:2d:ef:b2:4b:bf:20: + 28:25:49:d1:a6:36:77:34:e8:64:df:52:b1:11:c7:73:7a:cd: + 39:9e:c2:ad:8c:71:21:f2:5a:6b:af:df:3c:4e:55:af:b2:84: + 65:14:89:b9:77:cb:2a:31:be:cf:a3:6d:cf:6f:48:94:32:46: + 6f:e7:71:8c:a0:a6:84:19:37:07:f2:03:45:09:2b:86:75:7c: + df:5f:69:57:00:db:6e:d8:a6:72:22:4b:50:d4:75:98:56:df: + b7:18:ff:43:43:50:ae:7a:44:7b:f0:79:51:d7:43:3d:a7:d3: + 81:d3:f0:c9:4f:b9:da:c6:97:86:d0:82:c3:e4:42:6d:fe:b0: + e2:64:4e:0e:26:e7:40:34:26:b5:08:89:d7:08:63:63:38:27: + 75:1e:33:ea:6e:a8:dd:9f:99:4f:74:4d:81:89:80:4b:dd:9a: + 97:29:5c:2f:be:81:41:b9:8c:ff:ea:7d:60:06:9e:cd:d7:3d: + d3:2e:a3:15:bc:a8:e6:26:e5:6f:c3:dc:b8:03:21:ea:9f:16: + f1:2c:54:b5 +-----BEGIN CERTIFICATE----- +MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRF +MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBD +bGFzcyAzIENBIDIgRVYgMjAwOTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUw +NDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNV +BAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAwOTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfSegpn +ljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM0 +3TP1YtHhzRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6Z +qQTMFexgaDbtCHu39b+T7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lR +p75mpoo6Kr3HGrHhFPC+Oh25z1uxav60sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8 +HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure3511H3a6UCAwEAAaOCASQw +ggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyvcop9Ntea +HNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFw +Oi8vZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xh +c3MlMjAzJTIwQ0ElMjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1E +RT9jZXJ0aWZpY2F0ZXJldm9jYXRpb25saXN0MEagRKBChkBodHRwOi8vd3d3LmQt +dHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xhc3NfM19jYV8yX2V2XzIwMDku +Y3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+PPoeUSbrh/Yp +3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05 +nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNF +CSuGdXzfX2lXANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7na +xpeG0ILD5EJt/rDiZE4OJudANCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqX +KVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVvw9y4AyHqnxbxLFS1 +-----END CERTIFICATE----- + +CA Disig Root R1 +# Issuer: CN=CA Disig Root R1,O=Disig a.s.,L=Bratislava,C=SK +# Serial Number:00:c3:03:9a:ee:50:90:6e:28 +# Subject: CN=CA Disig Root R1,O=Disig a.s.,L=Bratislava,C=SK +# Not Valid Before: Thu Jul 19 09:06:56 2012 +# Not Valid After : Sat Jul 19 09:06:56 2042 +# Fingerprint (MD5): BE:EC:11:93:9A:F5:69:21:BC:D7:C1:C0:67:89:CC:2A +# Fingerprint (SHA1): 8E:1C:74:F8:A6:20:B9:E5:8A:F4:61:FA:EC:2B:47:56:51:1A:52:C6 +MUST_VERIFY_TRUST: CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +================================================ +MD5 Fingerprint=BE:EC:11:93:9A:F5:69:21:BC:D7:C1:C0:67:89:CC:2A +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + c3:03:9a:ee:50:90:6e:28 + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=SK, L=Bratislava, O=Disig a.s., CN=CA Disig Root R1 + Validity + Not Before: Jul 19 09:06:56 2012 GMT + Not After : Jul 19 09:06:56 2042 GMT + Subject: C=SK, L=Bratislava, O=Disig a.s., CN=CA Disig Root R1 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:aa:c3:78:f7:dc:98:a3:a7:5a:5e:77:18:b2:dd: + 04:64:0f:63:fd:9b:96:09:80:d5:e8:aa:a5:e2:9c: + 26:94:3a:e8:99:73:8c:9d:df:d7:df:83:f3:78:4f: + 40:e1:7f:d2:a7:d2:e5:ca:13:93:e7:ed:c6:77:5f: + 36:b5:94:af:e8:38:8e:db:9b:e5:7c:bb:cc:8d:eb: + 75:73:e1:24:cd:e6:a7:2d:19:2e:d8:d6:8a:6b:14: + eb:08:62:0a:d8:dc:b3:00:4d:c3:23:7c:5f:43:08: + 23:32:12:dc:ed:0c:ad:c0:7d:0f:a5:7a:42:d9:5a: + 70:d9:bf:a7:d7:01:1c:f6:9b:ab:8e:b7:4a:86:78: + a0:1e:56:31:ae:ef:82:0a:80:41:f7:1b:c9:ae:ab: + 32:26:d4:2c:6b:ed:7d:6b:e4:e2:5e:22:0a:45:cb: + 84:31:4d:ac:fe:db:d1:47:ba:f9:60:97:39:b1:65: + c7:de:fb:99:e4:0a:22:b1:2d:4d:e5:48:26:69:ab: + e2:aa:f3:fb:fc:92:29:32:e9:b3:3e:4d:1f:27:a1: + cd:8e:b9:17:fb:25:3e:c9:6e:f3:77:da:0d:12:f6: + 5d:c7:bb:36:10:d5:54:d6:f3:e0:e2:47:48:e6:de: + 14:da:61:52:af:26:b4:f5:71:4f:c9:d7:d2:06:df: + 63:ca:ff:21:e8:59:06:e0:08:d5:84:15:53:f7:43: + e5:7c:c5:a0:89:98:6b:73:c6:68:ce:65:de:bd:7f: + 05:f7:b1:ee:f6:57:a1:60:95:c5:cc:ea:93:3a:be: + 99:ae:9b:02:a3:ad:c9:16:b5:ce:dd:5e:99:78:7e: + 1a:39:7e:b2:c0:05:a4:c0:82:a5:a3:47:9e:8c:ea: + 5c:b6:bc:67:db:e6:2a:4d:d2:04:dc:a3:ae:45:f7: + bc:8b:9c:1c:a7:d6:d5:03:dc:08:cb:2e:16:ca:5c: + 40:33:e8:67:c3:2e:e7:a6:44:ea:11:45:1c:35:65: + 2d:1e:45:61:24:1b:82:2e:a5:9d:33:5d:65:f8:41: + f9:2e:cb:94:3f:1f:a3:0c:31:24:44:ed:c7:5e:ad: + 50:ba:c6:41:9b:ac:f0:17:65:c0:f8:5d:6f:5b:a0: + 0a:34:3c:ee:d7:ea:88:9f:98:f9:af:4e:24:fa:97: + b2:64:76:da:ab:f4:ed:e3:c3:60:ef:d5:f9:02:c8: + 2d:9f:83:af:67:69:06:a7:31:55:d5:cf:4b:6f:ff: + 04:05:c7:58:ac:5f:16:1b:e5:d2:a3:eb:31:db:1f: + 33:15:4d:d0:f2:a5:53:f5:cb:e1:3d:4e:68:2d:d8: + 12:dd:aa:f2:e6:4d:9b:49:e5:c5:28:a1:ba:b0:5a: + c6:a0:b5 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 89:0A:B4:38:93:1A:E6:AB:EE:9B:91:18:F9:F5:3C:3E:35:D0:D3:82 + Signature Algorithm: sha1WithRSAEncryption + 32:8b:f6:9d:4a:c9:be:14:e5:8c:ac:38:ca:3a:09:d4:1b:ce: + 86:b3:dd:eb:d4:ba:28:be:12:ae:45:2c:04:74:ac:13:51:c5: + 58:18:66:4d:82:da:d5:dc:93:c0:27:e1:be:7c:9f:52:9e:12: + 56:f6:d5:9c:a9:f4:75:9c:fa:37:12:8f:1c:93:ec:57:fe:07: + 0f:ab:d5:12:f7:0f:ae:61:5e:56:80:49:f5:fc:30:f5:9b:4f: + 1f:41:2f:1c:84:d3:89:c7:e2:da:02:76:ed:09:cf:6c:c1:b8: + 1c:83:1c:16:fa:94:cd:7d:a0:c8:18:d2:c8:9d:6e:f5:bd:69: + d4:6d:3d:35:e8:1e:a2:4f:60:d7:07:29:fc:b2:a3:a4:9d:6e: + 15:92:56:19:4c:0a:b0:e9:7c:d2:19:4d:42:46:ec:bd:fd:f6: + 57:5b:dd:98:7e:a4:4d:cc:72:03:83:58:5d:ef:93:3a:41:7a: + 63:aa:7c:3a:a8:f5:ac:a4:d1:dd:a2:2d:b6:2a:fc:9f:01:8e: + e2:10:b1:c4:ca:e4:67:db:55:25:19:3f:fd:e8:36:7e:b3:e1: + e1:81:af:11:16:8b:50:97:60:19:82:00:c0:6b:4d:73:b8:d1: + 13:07:3e:ea:b6:31:4f:f0:42:9a:6d:e2:11:74:e5:94:ac:8d: + 84:95:3c:21:af:c5:da:47:c8:df:39:62:62:cb:5b:50:0b:d7: + 81:40:05:9c:9b:ed:ba:b6:8b:1e:04:6f:96:20:39:ed:a4:7d: + 29:db:48:ce:82:dc:d4:02:8d:1d:04:31:5a:c7:4b:f0:6c:61: + 52:d7:b4:51:c2:81:6c:cd:e1:fb:a7:a1:d2:92:76:cf:b1:0f: + 37:58:a4:f2:52:71:67:3f:0c:88:78:80:89:c1:c8:b5:1f:92: + 63:be:a7:7a:8a:56:2c:1a:a8:a6:9c:b5:5d:b3:63:d0:13:20: + a1:eb:91:6c:d0:8d:7d:af:df:0b:e4:17:b9:86:9e:38:b1:94: + 0c:58:8c:e0:55:aa:3b:63:6d:9a:89:60:b8:64:2a:92:c6:37: + f4:7e:43:43:b7:73:e8:01:e7:7f:97:0f:d7:f2:7b:19:fd:1a: + d7:8f:c9:fa:85:6b:7a:9d:9e:89:b6:a6:28:99:93:88:40:f7: + 3e:cd:51:a3:ca:ea:ef:79:47:21:b5:fe:32:e2:c7:c3:51:6f: + be:80:74:f0:a4:c3:3a:f2:4f:e9:5f:df:19:0a:f2:3b:13:43: + ac:31:a4:b3:e7:eb:fc:18:d6:01:a9:f3:2a:8f:36:0e:eb:b4: + b1:bc:b7:4c:c9:6b:bf:a1:f3:d9:f4:ed:e2:f0:e3:ed:64:9e: + 3d:2f:96:52:4f:80:53:8b +-----BEGIN CERTIFICATE----- +MIIFaTCCA1GgAwIBAgIJAMMDmu5QkG4oMA0GCSqGSIb3DQEBBQUAMFIxCzAJBgNV +BAYTAlNLMRMwEQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMu +MRkwFwYDVQQDExBDQSBEaXNpZyBSb290IFIxMB4XDTEyMDcxOTA5MDY1NloXDTQy +MDcxOTA5MDY1NlowUjELMAkGA1UEBhMCU0sxEzARBgNVBAcTCkJyYXRpc2xhdmEx +EzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERpc2lnIFJvb3QgUjEw +ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCqw3j33Jijp1pedxiy3QRk +D2P9m5YJgNXoqqXinCaUOuiZc4yd39ffg/N4T0Dhf9Kn0uXKE5Pn7cZ3Xza1lK/o +OI7bm+V8u8yN63Vz4STN5qctGS7Y1oprFOsIYgrY3LMATcMjfF9DCCMyEtztDK3A +fQ+lekLZWnDZv6fXARz2m6uOt0qGeKAeVjGu74IKgEH3G8muqzIm1Cxr7X1r5OJe +IgpFy4QxTaz+29FHuvlglzmxZcfe+5nkCiKxLU3lSCZpq+Kq8/v8kiky6bM+TR8n +oc2OuRf7JT7JbvN32g0S9l3HuzYQ1VTW8+DiR0jm3hTaYVKvJrT1cU/J19IG32PK +/yHoWQbgCNWEFVP3Q+V8xaCJmGtzxmjOZd69fwX3se72V6FglcXM6pM6vpmumwKj +rckWtc7dXpl4fho5frLABaTAgqWjR56M6ly2vGfb5ipN0gTco65F97yLnByn1tUD +3AjLLhbKXEAz6GfDLuemROoRRRw1ZS0eRWEkG4IupZ0zXWX4Qfkuy5Q/H6MMMSRE +7cderVC6xkGbrPAXZcD4XW9boAo0PO7X6oifmPmvTiT6l7Jkdtqr9O3jw2Dv1fkC +yC2fg69naQanMVXVz0tv/wQFx1isXxYb5dKj6zHbHzMVTdDypVP1y+E9Tmgt2BLd +qvLmTZtJ5cUoobqwWsagtQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud +DwEB/wQEAwIBBjAdBgNVHQ4EFgQUiQq0OJMa5qvum5EY+fU8PjXQ04IwDQYJKoZI +hvcNAQEFBQADggIBADKL9p1Kyb4U5YysOMo6CdQbzoaz3evUuii+Eq5FLAR0rBNR +xVgYZk2C2tXck8An4b58n1KeElb21Zyp9HWc+jcSjxyT7Ff+Bw+r1RL3D65hXlaA +SfX8MPWbTx9BLxyE04nH4toCdu0Jz2zBuByDHBb6lM19oMgY0sidbvW9adRtPTXo +HqJPYNcHKfyyo6SdbhWSVhlMCrDpfNIZTUJG7L399ldb3Zh+pE3McgODWF3vkzpB +emOqfDqo9ayk0d2iLbYq/J8BjuIQscTK5GfbVSUZP/3oNn6z4eGBrxEWi1CXYBmC +AMBrTXO40RMHPuq2MU/wQppt4hF05ZSsjYSVPCGvxdpHyN85YmLLW1AL14FABZyb +7bq2ix4Eb5YgOe2kfSnbSM6C3NQCjR0EMVrHS/BsYVLXtFHCgWzN4funodKSds+x +DzdYpPJScWc/DIh4gInByLUfkmO+p3qKViwaqKactV2zY9ATIKHrkWzQjX2v3wvk +F7mGnjixlAxYjOBVqjtjbZqJYLhkKpLGN/R+Q0O3c+gB53+XD9fyexn9GtePyfqF +a3qdnom2piiZk4hA9z7NUaPK6u95RyG1/jLix8NRb76AdPCkwzryT+lf3xkK8jsT +Q6wxpLPn6/wY1gGp8yqPNg7rtLG8t0zJa7+h89n07eLw4+1knj0vllJPgFOL +-----END CERTIFICATE----- + +CA Disig Root R2 +# Issuer: CN=CA Disig Root R2,O=Disig a.s.,L=Bratislava,C=SK +# Serial Number:00:92:b8:88:db:b0:8a:c1:63 +# Subject: CN=CA Disig Root R2,O=Disig a.s.,L=Bratislava,C=SK +# Not Valid Before: Thu Jul 19 09:15:30 2012 +# Not Valid After : Sat Jul 19 09:15:30 2042 +# Fingerprint (MD5): 26:01:FB:D8:27:A7:17:9A:45:54:38:1A:43:01:3B:03 +# Fingerprint (SHA1): B5:61:EB:EA:A4:DE:E4:25:4B:69:1A:98:A5:57:47:C2:34:C7:D9:71 +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +MUST_VERIFY_TRUST: CODE_SIGNING +================================================ +MD5 Fingerprint=26:01:FB:D8:27:A7:17:9A:45:54:38:1A:43:01:3B:03 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 92:b8:88:db:b0:8a:c1:63 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=SK, L=Bratislava, O=Disig a.s., CN=CA Disig Root R2 + Validity + Not Before: Jul 19 09:15:30 2012 GMT + Not After : Jul 19 09:15:30 2042 GMT + Subject: C=SK, L=Bratislava, O=Disig a.s., CN=CA Disig Root R2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:a2:a3:c4:00:09:d6:85:5d:2d:6d:14:f6:c2:c3: + 73:9e:35:c2:71:55:7e:81:fb:ab:46:50:e0:c1:7c: + 49:78:e6:ab:79:58:3c:da:ff:7c:1c:9f:d8:97:02: + 78:3e:6b:41:04:e9:41:bd:be:03:2c:45:f6:2f:64: + d4:ab:5d:a3:47:3d:64:9b:e9:68:9a:c6:cc:1b:3f: + ba:be:b2:8b:34:02:2e:98:55:19:fc:8c:6f:aa:5f: + da:4c:ce:4d:03:21:a3:d8:d2:34:93:56:96:cb:4c: + 0c:00:16:3c:5f:1a:cd:c8:c7:6c:a6:ad:d3:31:a7: + bc:e8:e5:e1:66:d6:d2:fb:03:b4:41:65:c9:10:ae: + 0e:05:63:c6:80:6a:69:30:fd:d2:ee:90:ef:0d:27: + df:9f:95:73:f4:e1:25:da:6c:16:de:41:38:34:ea: + 8b:fc:d1:e8:04:14:61:2d:41:7e:ac:c7:77:4e:cb: + 51:54:fb:5e:92:18:1b:04:5a:68:c6:c9:c4:fa:b7: + 13:a0:98:b7:11:2b:b7:d6:57:cc:7c:9e:17:d1:cb: + 25:fe:86:4e:24:2e:56:0c:78:4d:9e:01:12:a6:2b: + a7:01:65:6e:7c:62:1d:84:84:df:ea:c0:6b:b5:a5: + 2a:95:83:c3:53:11:0c:73:1d:0b:b2:46:90:d1:42: + 3a:ce:40:6e:95:ad:ff:c6:94:ad:6e:97:84:8e:7d: + 6f:9e:8a:80:0d:49:6d:73:e2:7b:92:1e:c3:f3:c1: + f3:eb:2e:05:6f:d9:1b:cf:37:76:04:c8:b4:5a:e4: + 17:a7:cb:dd:76:1f:d0:19:76:e8:2c:05:b3:d6:9c: + 34:d8:96:dc:61:87:91:05:e4:44:08:33:c1:da:b9: + 08:65:d4:ae:b2:36:0d:eb:ba:38:ba:0c:e5:9b:9e: + eb:8d:66:dd:99:cf:d6:89:41:f6:04:92:8a:29:29: + 6d:6b:3a:1c:e7:75:7d:02:71:0e:f3:c0:e7:bd:cb: + 19:dd:9d:60:b2:c2:66:60:b6:b1:04:ee:c9:e6:86: + b9:9a:66:40:a8:e7:11:ed:81:45:03:8b:f6:67:59: + e8:c1:06:11:bd:dd:cf:80:02:4f:65:40:78:5c:47: + 50:c8:9b:e6:1f:81:7b:e4:44:a8:5b:85:9a:e2:de: + 5a:d5:c7:f9:3a:44:66:4b:e4:32:54:7c:e4:6c:9c: + b3:0e:3d:17:a2:b2:34:12:d6:7e:b2:a8:49:bb:d1: + 7a:28:40:be:a2:16:1f:df:e4:37:1f:11:73:fb:90: + 0a:65:43:a2:0d:7c:f8:06:01:55:33:7d:b0:0d:b8: + f4:f5:ae:a5:42:57:7c:36:11:8c:7b:5e:c4:03:9d: + 8c:79:9d + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + B5:99:F8:AF:B0:94:F5:E3:20:D6:0A:AD:CE:4E:56:A4:2E:6E:42:ED + Signature Algorithm: sha256WithRSAEncryption + 26:06:5e:70:e7:65:33:c8:82:6e:d9:9c:17:3a:1b:7a:66:b2: + 01:f6:78:3b:69:5e:2f:ea:ff:4e:f9:28:c3:98:2a:61:4c:b4: + 24:12:8a:7d:6d:11:14:f7:9c:b5:ca:e6:bc:9e:27:8e:4c:19: + c8:a9:bd:7a:c0:d7:36:0e:6d:85:72:6e:a8:c6:a2:6d:f6:fa: + 73:63:7f:bc:6e:79:08:1c:9d:8a:9f:1a:8a:53:a6:d8:bb:d9: + 35:55:b1:11:c5:a9:03:b3:56:3b:b9:84:93:22:5e:7e:c1:f6: + 12:52:8b:ea:2c:67:bc:fe:36:4c:f5:b8:cf:d1:b3:49:92:3b: + d3:29:0e:99:1b:96:f7:61:b8:3b:c4:2b:b6:78:6c:b4:23:6f: + f0:fd:d3:b2:5e:75:1f:99:95:a8:ac:f6:da:e1:c5:31:7b:fb: + d1:46:b3:d2:bc:67:b4:62:54:ba:09:f7:63:b0:93:a2:9a:f9: + e9:52:2e:8b:60:12:ab:fc:f5:60:56:ef:10:5c:8b:c4:1a:42: + dc:83:5b:64:0e:cb:b5:bc:d6:4f:c1:7c:3c:6e:8d:13:6d:fb: + 7b:eb:30:d0:dc:4d:af:c5:d5:b6:a5:4c:5b:71:c9:e8:31:be: + e8:38:06:48:a1:1a:e2:ea:d2:de:12:39:58:1a:ff:80:0e:82: + 75:e6:b7:c9:07:6c:0e:ef:ff:38:f1:98:71:c4:b7:7f:0e:15: + d0:25:69:bd:22:9d:2b:ed:05:f6:46:47:ac:ed:c0:f0:d4:3b: + e2:ec:ee:96:5b:90:13:4e:1e:56:3a:eb:b0:ef:96:bb:96:23: + 11:ba:f2:43:86:74:64:95:c8:28:75:df:1d:35:ba:d2:37:83: + 38:53:38:36:3b:cf:6c:e9:f9:6b:0e:d0:fb:04:e8:4f:77:d7: + 65:01:78:86:0c:7a:3e:21:62:f1:7f:63:71:0c:c9:9f:44:db: + a8:27:a2:75:be:6e:81:3e:d7:c0:eb:1b:98:0f:70:5c:34:b2: + 8a:cc:c0:85:18:eb:6e:7a:b3:f7:5a:a1:07:bf:a9:42:92:f3: + 60:22:97:e4:14:a1:07:9b:4e:76:c0:8e:7d:fd:a4:25:c7:47: + ed:ff:1f:73:ac:cc:c3:a5:e9:6f:0a:8e:9b:65:c2:50:85:b5: + a3:a0:53:12:cc:55:87:61:f3:81:ae:10:46:61:bd:44:21:b8: + c2:3d:74:cf:7e:24:35:fa:1c:07:0e:9b:3d:22:ca:ef:31:2f: + 8c:ac:12:bd:ef:40:28:fc:29:67:9f:b2:13:4f:66:24:c4:53: + 19:e9:1e:29:15:ef:e6:6d:b0:7f:2d:67:fd:f3:6c:1b:75:46: + a3:e5:4a:17:e9:a4:d7:0b +-----BEGIN CERTIFICATE----- +MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNV +BAYTAlNLMRMwEQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMu +MRkwFwYDVQQDExBDQSBEaXNpZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQy +MDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sxEzARBgNVBAcTCkJyYXRpc2xhdmEx +EzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERpc2lnIFJvb3QgUjIw +ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbCw3Oe +NcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNH +PWSb6WiaxswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3I +x2ymrdMxp7zo5eFm1tL7A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbe +QTg06ov80egEFGEtQX6sx3dOy1FU+16SGBsEWmjGycT6txOgmLcRK7fWV8x8nhfR +yyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqVg8NTEQxzHQuyRpDRQjrO +QG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa5Beny912 +H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJ +QfYEkoopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUD +i/ZnWejBBhG93c+AAk9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORs +nLMOPReisjQS1n6yqEm70XooQL6iFh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1 +rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud +DwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5uQu0wDQYJKoZI +hvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM +tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqf +GopTpti72TVVsRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkb +lvdhuDvEK7Z4bLQjb/D907JedR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka ++elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W81k/BfDxujRNt+3vrMNDcTa/F1bal +TFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjxmHHEt38OFdAlab0i +nSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01utI3 +gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18Dr +G5gPcFw0sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3Os +zMOl6W8KjptlwlCFtaOgUxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8x +L4ysEr3vQCj8KWefshNPZiTEUxnpHikV7+ZtsH8tZ/3zbBt1RqPlShfppNcL +-----END CERTIFICATE----- + +ACCVRAIZ1 +# Issuer: C=ES,O=ACCV,OU=PKIACCV,CN=ACCVRAIZ1 +# Serial Number:5e:c3:b7:a6:43:7f:a4:e0 +# Subject: C=ES,O=ACCV,OU=PKIACCV,CN=ACCVRAIZ1 +# Not Valid Before: Thu May 05 09:37:37 2011 +# Not Valid After : Tue Dec 31 09:37:37 2030 +# Fingerprint (MD5): D0:A0:5A:EE:05:B6:09:94:21:A1:7D:F1:B2:29:82:02 +# Fingerprint (SHA1): 93:05:7A:88:15:C6:4F:CE:88:2F:FA:91:16:52:28:78:BC:53:64:17 +MUST_VERIFY_TRUST: CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +================================================ +MD5 Fingerprint=D0:A0:5A:EE:05:B6:09:94:21:A1:7D:F1:B2:29:82:02 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 6828503384748696800 (0x5ec3b7a6437fa4e0) + Signature Algorithm: sha1WithRSAEncryption + Issuer: CN=ACCVRAIZ1, OU=PKIACCV, O=ACCV, C=ES + Validity + Not Before: May 5 09:37:37 2011 GMT + Not After : Dec 31 09:37:37 2030 GMT + Subject: CN=ACCVRAIZ1, OU=PKIACCV, O=ACCV, C=ES + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:9b:a9:ab:bf:61:4a:97:af:2f:97:66:9a:74:5f: + d0:d9:96:fd:cf:e2:e4:66:ef:1f:1f:47:33:c2:44: + a3:df:9a:de:1f:b5:54:dd:15:7c:69:35:11:6f:bb: + c8:0c:8e:6a:18:1e:d8:8f:d9:16:bc:10:48:36:5c: + f0:63:b3:90:5a:5c:24:37:d7:a3:d6:cb:09:71:b9: + f1:01:72:84:b0:7d:db:4d:80:cd:fc:d3:6f:c9:f8: + da:b6:0e:82:d2:45:85:a8:1b:68:a8:3d:e8:f4:44: + 6c:bd:a1:c2:cb:03:be:8c:3e:13:00:84:df:4a:48: + c0:e3:22:0a:e8:e9:37:a7:18:4c:b1:09:0d:23:56: + 7f:04:4d:d9:17:84:18:a5:c8:da:40:94:73:eb:ce: + 0e:57:3c:03:81:3a:9d:0a:a1:57:43:69:ac:57:6d: + 79:90:78:e5:b5:b4:3b:d8:bc:4c:8d:28:a1:a7:a3: + a7:ba:02:4e:25:d1:2a:ae:ed:ae:03:22:b8:6b:20: + 0f:30:28:54:95:7f:e0:ee:ce:0a:66:9d:d1:40:2d: + 6e:22:af:9d:1a:c1:05:19:d2:6f:c0:f2:9f:f8:7b: + b3:02:42:fb:50:a9:1d:2d:93:0f:23:ab:c6:c1:0f: + 92:ff:d0:a2:15:f5:53:09:71:1c:ff:45:13:84:e6: + 26:5e:f8:e0:88:1c:0a:fc:16:b6:a8:73:06:b8:f0: + 63:84:02:a0:c6:5a:ec:e7:74:df:70:ae:a3:83:25: + ea:d6:c7:97:87:93:a7:c6:8a:8a:33:97:60:37:10: + 3e:97:3e:6e:29:15:d6:a1:0f:d1:88:2c:12:9f:6f: + aa:a4:c6:42:eb:41:a2:e3:95:43:d3:01:85:6d:8e: + bb:3b:f3:23:36:c7:fe:3b:e0:a1:25:07:48:ab:c9: + 89:74:ff:08:8f:80:bf:c0:96:65:f3:ee:ec:4b:68: + bd:9d:88:c3:31:b3:40:f1:e8:cf:f6:38:bb:9c:e4: + d1:7f:d4:e5:58:9b:7c:fa:d4:f3:0e:9b:75:91:e4: + ba:52:2e:19:7e:d1:f5:cd:5a:19:fc:ba:06:f6:fb: + 52:a8:4b:99:04:dd:f8:f9:b4:8b:50:a3:4e:62:89: + f0:87:24:fa:83:42:c1:87:fa:d5:2d:29:2a:5a:71: + 7a:64:6a:d7:27:60:63:0d:db:ce:49:f5:8d:1f:90: + 89:32:17:f8:73:43:b8:d2:5a:93:86:61:d6:e1:75: + 0a:ea:79:66:76:88:4f:71:eb:04:25:d6:0a:5a:7a: + 93:e5:b9:4b:17:40:0f:b1:b6:b9:f5:de:4f:dc:e0: + b3:ac:3b:11:70:60:84:4a:43:6e:99:20:c0:29:71: + 0a:c0:65 + Exponent: 65537 (0x10001) + X509v3 extensions: + Authority Information Access: + CA Issuers - URI:http://www.accv.es/fileadmin/Archivos/certificados/raizaccv1.crt + OCSP - URI:http://ocsp.accv.es + + X509v3 Subject Key Identifier: + D2:87:B4:E3:DF:37:27:93:55:F6:56:EA:81:E5:36:CC:8C:1E:3F:BD + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Authority Key Identifier: + keyid:D2:87:B4:E3:DF:37:27:93:55:F6:56:EA:81:E5:36:CC:8C:1E:3F:BD + + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + User Notice: + Explicit Text: + CPS: http://www.accv.es/legislacion_c.htm + + X509v3 CRL Distribution Points: + + Full Name: + URI:http://www.accv.es/fileadmin/Archivos/certificados/raizaccv1_der.crl + + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Alternative Name: + email:accv@accv.es + Signature Algorithm: sha1WithRSAEncryption + 97:31:02:9f:e7:fd:43:67:48:44:14:e4:29:87:ed:4c:28:66: + d0:8f:35:da:4d:61:b7:4a:97:4d:b5:db:90:e0:05:2e:0e:c6: + 79:d0:f2:97:69:0f:bd:04:47:d9:be:db:b5:29:da:9b:d9:ae: + a9:99:d5:d3:3c:30:93:f5:8d:a1:a8:fc:06:8d:44:f4:ca:16: + 95:7c:33:dc:62:8b:a8:37:f8:27:d8:09:2d:1b:ef:c8:14:27: + 20:a9:64:44:ff:2e:d6:75:aa:6c:4d:60:40:19:49:43:54:63: + da:e2:cc:ba:66:e5:4f:44:7a:5b:d9:6a:81:2b:40:d5:7f:f9: + 01:27:58:2c:c8:ed:48:91:7c:3f:a6:00:cf:c4:29:73:11:36: + de:86:19:3e:9d:ee:19:8a:1b:d5:b0:ed:8e:3d:9c:2a:c0:0d: + d8:3d:66:e3:3c:0d:bd:d5:94:5c:e2:e2:a7:35:1b:04:00:f6: + 3f:5a:8d:ea:43:bd:5f:89:1d:a9:c1:b0:cc:99:e2:4d:00:0a: + da:c9:27:5b:e7:13:90:5c:e4:f5:33:a2:55:6d:dc:e0:09:4d: + 2f:b1:26:5b:27:75:00:09:c4:62:77:29:08:5f:9e:59:ac:b6: + 7e:ad:9f:54:30:22:03:c1:1e:71:64:fe:f9:38:0a:96:18:dd: + 02:14:ac:23:cb:06:1c:1e:a4:7d:8d:0d:de:27:41:e8:ad:da: + 15:b7:b0:23:dd:2b:a8:d3:da:25:87:ed:e8:55:44:4d:88:f4: + 36:7e:84:9a:78:ac:f7:0e:56:49:0e:d6:33:25:d6:84:50:42: + 6c:20:12:1d:2a:d5:be:bc:f2:70:81:a4:70:60:be:05:b5:9b: + 9e:04:44:be:61:23:ac:e9:a5:24:8c:11:80:94:5a:a2:a2:b9: + 49:d2:c1:dc:d1:a7:ed:31:11:2c:9e:19:a6:ee:e1:55:e1:c0: + ea:cf:0d:84:e4:17:b7:a2:7c:a5:de:55:25:06:ee:cc:c0:87: + 5c:40:da:cc:95:3f:55:e0:35:c7:b8:84:be:b4:5d:cd:7a:83: + 01:72:ee:87:e6:5f:1d:ae:b5:85:c6:26:df:e6:c1:9a:e9:1e: + 02:47:9f:2a:a8:6d:a9:5b:cf:ec:45:77:7f:98:27:9a:32:5d: + 2a:e3:84:ee:c5:98:66:2f:96:20:1d:dd:d8:c3:27:d7:b0:f9: + fe:d9:7d:cd:d0:9f:8f:0b:14:58:51:9f:2f:8b:c3:38:2d:de: + e8:8f:d6:8d:87:a4:f5:56:43:16:99:2c:f4:a4:56:b4:34:b8: + 61:37:c9:c2:58:80:1b:a0:97:a1:fc:59:8d:e9:11:f6:d1:0f: + 4b:55:34:46:2a:8b:86:3b +-----BEGIN CERTIFICATE----- +MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UE +AwwJQUNDVlJBSVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQsw +CQYDVQQGEwJFUzAeFw0xMTA1MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQ +BgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwHUEtJQUNDVjENMAsGA1UECgwEQUND +VjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCb +qau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gMjmoY +HtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWo +G2ioPej0RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpA +lHPrzg5XPAOBOp0KoVdDaaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhr +IA8wKFSVf+DuzgpmndFALW4ir50awQUZ0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/ +0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDGWuzndN9wrqODJerWx5eH +k6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs78yM2x/47 +4KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMO +m3WR5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpa +cXpkatcnYGMN285J9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPl +uUsXQA+xtrn13k/c4LOsOxFwYIRKQ26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYI +KwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRwOi8vd3d3LmFjY3YuZXMvZmls +ZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEuY3J0MB8GCCsG +AQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2 +VuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeT +VfZW6oHlNsyMHj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIG +CCsGAQUFBwICMIIBFB6CARAAQQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUA +cgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBhAO0AegAgAGQAZQAgAGwAYQAgAEEA +QwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUAYwBuAG8AbABvAGcA +7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBjAHQA +cgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAA +QwBQAFMAIABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUA +czAwBggrBgEFBQcCARYkaHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2Mu +aHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0dHA6Ly93d3cuYWNjdi5lcy9maWxlYWRt +aW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2MV9kZXIuY3JsMA4GA1Ud +DwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZIhvcNAQEF +BQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdp +D70ER9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gU +JyCpZET/LtZ1qmxNYEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+m +AM/EKXMRNt6GGT6d7hmKG9Ww7Y49nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepD +vV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJTS+xJlsndQAJxGJ3KQhfnlms +tn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3sCPdK6jT2iWH +7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h +I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szA +h1xA2syVP1XgNce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xF +d3+YJ5oyXSrjhO7FmGYvliAd3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2H +pPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3pEfbRD0tVNEYqi4Y7 +-----END CERTIFICATE----- + +TWCA Global Root CA +# Issuer: CN=TWCA Global Root CA,OU=Root CA,O=TAIWAN-CA,C=TW +# Serial Number: 3262 (0xcbe) +# Subject: CN=TWCA Global Root CA,OU=Root CA,O=TAIWAN-CA,C=TW +# Not Valid Before: Wed Jun 27 06:28:33 2012 +# Not Valid After : Tue Dec 31 15:59:59 2030 +# Fingerprint (MD5): F9:03:7E:CF:E6:9E:3C:73:7A:2A:90:07:69:FF:2B:96 +# Fingerprint (SHA1): 9C:BB:48:53:F6:A4:F6:D3:52:A4:E8:32:52:55:60:13:F5:AD:AF:65 +MUST_VERIFY_TRUST: CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +================================================ +MD5 Fingerprint=F9:03:7E:CF:E6:9E:3C:73:7A:2A:90:07:69:FF:2B:96 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 3262 (0xcbe) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=TW, O=TAIWAN-CA, OU=Root CA, CN=TWCA Global Root CA + Validity + Not Before: Jun 27 06:28:33 2012 GMT + Not After : Dec 31 15:59:59 2030 GMT + Subject: C=TW, O=TAIWAN-CA, OU=Root CA, CN=TWCA Global Root CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:b0:05:db:c8:eb:8c:c4:6e:8a:21:ef:8e:4d:9c: + 71:0a:1f:52:70:ed:6d:82:9c:97:c5:d7:4c:4e:45: + 49:cb:40:42:b5:12:34:6c:19:c2:74:a4:31:5f:85: + 02:97:ec:43:33:0a:53:d2:9c:8c:8e:b7:b8:79:db: + 2b:d5:6a:f2:8e:66:c4:ee:2b:01:07:92:d4:b3:d0: + 02:df:50:f6:55:af:66:0e:cb:e0:47:60:2f:2b:32: + 39:35:52:3a:28:83:f8:7b:16:c6:18:b8:62:d6:47: + 25:91:ce:f0:19:12:4d:ad:63:f5:d3:3f:75:5f:29: + f0:a1:30:1c:2a:a0:98:a6:15:bd:ee:fd:19:36:f0: + e2:91:43:8f:fa:ca:d6:10:27:49:4c:ef:dd:c1:f1: + 85:70:9b:ca:ea:a8:5a:43:fc:6d:86:6f:73:e9:37: + 45:a9:f0:36:c7:cc:88:75:1e:bb:6c:06:ff:9b:6b: + 3e:17:ec:61:aa:71:7c:c6:1d:a2:f7:49:e9:15:b5: + 3c:d6:a1:61:f5:11:f7:05:6f:1d:fd:11:be:d0:30: + 07:c2:29:b0:09:4e:26:dc:e3:a2:a8:91:6a:1f:c2: + 91:45:88:5c:e5:98:b8:71:a5:15:19:c9:7c:75:11: + cc:70:74:4f:2d:9b:1d:91:44:fd:56:28:a0:fe:bb: + 86:6a:c8:fa:5c:0b:58:dc:c6:4b:76:c8:ab:22:d9: + 73:0f:a5:f4:5a:02:89:3f:4f:9e:22:82:ee:a2:74: + 53:2a:3d:53:27:69:1d:6c:8e:32:2c:64:00:26:63: + 61:36:4e:a3:46:b7:3f:7d:b3:2d:ac:6d:90:a2:95: + a2:ce:cf:da:82:e7:07:34:19:96:e9:b8:21:aa:29: + 7e:a6:38:be:8e:29:4a:21:66:79:1f:b3:c3:b5:09: + 67:de:d6:d4:07:46:f3:2a:da:e6:22:37:60:cb:81: + b6:0f:a0:0f:e9:c8:95:7f:bf:55:91:05:7a:cf:3d: + 15:c0:6f:de:09:94:01:83:d7:34:1b:cc:40:a5:f0: + b8:9b:67:d5:98:91:3b:a7:84:78:95:26:a4:5a:08: + f8:2b:74:b4:00:04:3c:df:b8:14:8e:e8:df:a9:8d: + 6c:67:92:33:1d:c0:b7:d2:ec:92:c8:be:09:bf:2c: + 29:05:6f:02:6b:9e:ef:bc:bf:2a:bc:5b:c0:50:8f: + 41:70:71:87:b2:4d:b7:04:a9:84:a3:32:af:ae:ee: + 6b:17:8b:b2:b1:fe:6c:e1:90:8c:88:a8:97:48:ce: + c8:4d:cb:f3:06:cf:5f:6a:0a:42:b1:1e:1e:77:2f: + 8e:a0:e6:92:0e:06:fc:05:22:d2:26:e1:31:51:7d: + 32:dc:0f + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + Signature Algorithm: sha256WithRSAEncryption + 5f:34:81:76:ef:96:1d:d5:e5:b5:d9:02:63:84:16:c1:ae:a0: + 70:51:a7:f7:4c:47:35:c8:0b:d7:28:3d:89:71:d9:aa:33:41: + ea:14:1b:6c:21:00:c0:6c:42:19:7e:9f:69:5b:20:42:df:a2: + d2:da:c4:7c:97:4b:8d:b0:e8:ac:c8:ee:a5:69:04:99:0a:92: + a6:ab:27:2e:1a:4d:81:bf:84:d4:70:1e:ad:47:fe:fd:4a:9d: + 33:e0:f2:b9:c4:45:08:21:0a:da:69:69:73:72:0d:be:34:fe: + 94:8b:ad:c3:1e:35:d7:a2:83:ef:e5:38:c7:a5:85:1f:ab:cf: + 34:ec:3f:28:fe:0c:f1:57:86:4e:c9:55:f7:1c:d4:d8:a5:7d: + 06:7a:6f:d5:df:10:df:81:4e:21:65:b1:b6:e1:17:79:95:45: + 06:ce:5f:cc:dc:46:89:63:68:44:8d:93:f4:64:70:a0:3d:9d: + 28:05:c3:39:70:b8:62:7b:20:fd:e4:db:e9:08:a1:b8:9e:3d: + 09:c7:4f:fb:2c:f8:93:76:41:de:52:e0:e1:57:d2:9d:03:bc: + 77:9e:fe:9e:29:5e:f7:c1:51:60:1f:de:da:0b:b2:2d:75:b7: + 43:48:93:e7:f6:79:c6:84:5d:80:59:60:94:fc:78:98:8f:3c: + 93:51:ed:40:90:07:df:64:63:24:cb:4e:71:05:a1:d7:94:1a: + 88:32:f1:22:74:22:ae:a5:a6:d8:12:69:4c:60:a3:02:ee:2b: + ec:d4:63:92:0b:5e:be:2f:76:6b:a3:b6:26:bc:8f:03:d8:0a: + f2:4c:64:46:bd:39:62:e5:96:eb:34:63:11:28:cc:95:f1:ad: + ef:ef:dc:80:58:48:e9:4b:b8:ea:65:ac:e9:fc:80:b5:b5:c8: + 45:f9:ac:c1:9f:d9:b9:ea:62:88:8e:c4:f1:4b:83:12:ad:e6: + 8b:84:d6:9e:c2:eb:83:18:9f:6a:bb:1b:24:60:33:70:cc:ec: + f7:32:f3:5c:d9:79:7d:ef:9e:a4:fe:c9:23:c3:24:ee:15:92: + b1:3d:91:4f:26:86:bd:66:73:24:13:ea:a4:ae:63:c1:ad:7d: + 84:03:3c:10:78:86:1b:79:e3:c4:f3:f2:04:95:20:ae:23:82: + c4:b3:3a:00:62:bf:e6:36:24:e1:57:ba:c7:1e:90:75:d5:5f: + 3f:95:61:2b:c1:3b:cd:e5:b3:68:61:d0:46:26:a9:21:52:69: + 2d:eb:2e:c7:eb:77:ce:a6:3a:b5:03:33:4f:76:d1:e7:5c:54: + 01:5d:cb:78:f4:c9:0c:bf:cf:12:8e:17:2d:23:68:94:e7:ab: + fe:a9:b2:2b:06:d0:04:cd +-----BEGIN CERTIFICATE----- +MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcx +EjAQBgNVBAoTCVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMT +VFdDQSBHbG9iYWwgUm9vdCBDQTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5 +NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQKEwlUQUlXQU4tQ0ExEDAOBgNVBAsT +B1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3QgQ0EwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2CnJfF +10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz +0ALfUPZVr2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfCh +MBwqoJimFb3u/Rk28OKRQ4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbH +zIh1HrtsBv+baz4X7GGqcXzGHaL3SekVtTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc +46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1WKKD+u4ZqyPpcC1jcxkt2 +yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99sy2sbZCi +laLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYP +oA/pyJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQA +BDzfuBSO6N+pjWxnkjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcE +qYSjMq+u7msXi7Kx/mzhkIyIqJdIzshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm +4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB +/zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6gcFGn90xHNcgL +1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn +LhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WF +H6vPNOw/KP4M8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNo +RI2T9GRwoD2dKAXDOXC4Ynsg/eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+ +nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlglPx4mI88k1HtQJAH32RjJMtOcQWh +15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryPA9gK8kxkRr05YuWW +6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3mi4TW +nsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5j +wa19hAM8EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWz +aGHQRiapIVJpLesux+t3zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmy +KwbQBM0= +-----END CERTIFICATE----- + +TeliaSonera Root CA v1 +# Issuer: CN=TeliaSonera Root CA v1,O=TeliaSonera +# Serial Number:00:95:be:16:a0:f7:2e:46:f1:7b:39:82:72:fa:8b:cd:96 +# Subject: CN=TeliaSonera Root CA v1,O=TeliaSonera +# Not Valid Before: Thu Oct 18 12:00:50 2007 +# Not Valid After : Mon Oct 18 12:00:50 2032 +# Fingerprint (MD5): 37:41:49:1B:18:56:9A:26:F5:AD:C2:66:FB:40:A5:4C +# Fingerprint (SHA1): 43:13:BB:96:F1:D5:86:9B:C1:4E:6A:92:F6:CF:F6:34:69:87:82:37 +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +MUST_VERIFY_TRUST: CODE_SIGNING +================================================ +MD5 Fingerprint=37:41:49:1B:18:56:9A:26:F5:AD:C2:66:FB:40:A5:4C +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 95:be:16:a0:f7:2e:46:f1:7b:39:82:72:fa:8b:cd:96 + Signature Algorithm: sha1WithRSAEncryption + Issuer: O=TeliaSonera, CN=TeliaSonera Root CA v1 + Validity + Not Before: Oct 18 12:00:50 2007 GMT + Not After : Oct 18 12:00:50 2032 GMT + Subject: O=TeliaSonera, CN=TeliaSonera Root CA v1 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:c2:be:eb:27:f0:21:a3:f3:69:26:55:7e:9d:c5: + 55:16:91:5c:fd:ef:21:bf:53:80:7a:2d:d2:91:8c: + 63:31:f0:ec:24:f0:c3:a5:d2:72:7c:10:6d:f4:37: + b7:e5:e6:7c:79:ea:8c:b5:82:8b:ae:48:b6:ac:00: + dc:65:75:ec:2a:4d:5f:c1:87:f5:20:65:2b:81:a8: + 47:3e:89:23:95:30:16:90:7f:e8:57:07:48:e7:19: + ae:bf:45:67:b1:37:1b:06:2a:fe:de:f9:ac:7d:83: + fb:5e:ba:e4:8f:97:67:be:4b:8e:8d:64:07:57:38: + 55:69:34:36:3d:13:48:ef:4f:e2:d3:66:1e:a4:cf: + 1a:b7:5e:36:33:d4:b4:06:bd:18:01:fd:77:84:50: + 00:45:f5:8c:5d:e8:23:bc:7e:fe:35:e1:ed:50:7b: + a9:30:8d:19:d3:09:8e:68:67:5d:bf:3c:97:18:53: + bb:29:62:c5:ca:5e:72:c1:c7:96:d4:db:2d:a0:b4: + 1f:69:03:ec:ea:e2:50:f1:0c:3c:f0:ac:f3:53:2d: + f0:1c:f5:ed:6c:39:39:73:80:16:c8:52:b0:23:cd: + e0:3e:dc:dd:3c:47:a0:bb:35:8a:e2:98:68:8b:be: + e5:bf:72:ee:d2:fa:a5:ed:12:ed:fc:98:18:a9:26: + 76:dc:28:4b:10:20:1c:d3:7f:16:77:2d:ed:6f:80: + f7:49:bb:53:05:bb:5d:68:c7:d4:c8:75:16:3f:89: + 5a:8b:f7:17:47:d4:4c:f1:d2:89:79:3e:4d:3d:98: + a8:61:de:3a:1e:d2:f8:5e:03:e0:c1:c9:1c:8c:d3: + 8d:4d:d3:95:36:b3:37:5f:63:63:9b:33:14:f0:2d: + 26:6b:53:7c:89:8c:32:c2:6e:ec:3d:21:00:39:c9: + a1:68:e2:50:83:2e:b0:3a:2b:f3:36:a0:ac:2f:e4: + 6f:61:c2:51:09:39:3e:8b:53:b9:bb:67:da:dc:53: + b9:76:59:36:9d:43:e5:20:e0:3d:32:60:85:22:51: + b7:c7:33:bb:dd:15:2f:a4:78:a6:07:7b:81:46:36: + 04:86:dd:79:35:c7:95:2c:3b:b0:a3:17:35:e5:73: + 1f:b4:5c:59:ef:da:ea:10:65:7b:7a:d0:7f:9f:b3: + b4:2a:37:3b:70:8b:9b:5b:b9:2b:b7:ec:b2:51:12: + 97:53:29:5a:d4:f0:12:10:dc:4f:02:bb:12:92:2f: + 62:d4:3f:69:43:7c:0d:d6:fc:58:75:01:88:9d:58: + 16:4b:de:ba:90:ff:47:01:89:06:6a:f6:5f:b2:90: + 6a:b3:02:a6:02:88:bf:b3:47:7e:2a:d9:d5:fa:68: + 78:35:4d + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + F0:8F:59:38:00:B3:F5:8F:9A:96:0C:D5:EB:FA:7B:AA:17:E8:13:12 + Signature Algorithm: sha1WithRSAEncryption + be:e4:5c:62:4e:24:f4:0c:08:ff:f0:d3:0c:68:e4:93:49:22: + 3f:44:27:6f:bb:6d:de:83:66:ce:a8:cc:0d:fc:f5:9a:06:e5: + 77:14:91:eb:9d:41:7b:99:2a:84:e5:ff:fc:21:c1:5d:f0:e4: + 1f:57:b7:75:a9:a1:5f:02:26:ff:d7:c7:f7:4e:de:4f:f8:f7: + 1c:46:c0:7a:4f:40:2c:22:35:f0:19:b1:d0:6b:67:2c:b0:a8: + e0:c0:40:37:35:f6:84:5c:5c:e3:af:42:78:fe:a7:c9:0d:50: + ea:0d:84:76:f6:51:ef:83:53:c6:7a:ff:0e:56:49:2e:8f:7a: + d6:0c:e6:27:54:e3:4d:0a:60:72:62:cd:91:07:d6:a5:bf:c8: + 99:6b:ed:c4:19:e6:ab:4c:11:38:c5:6f:31:e2:6e:49:c8:3f: + 76:80:26:03:26:29:e0:36:f6:f6:20:53:e3:17:70:34:17:9d: + 63:68:1e:6b:ec:c3:4d:86:b8:13:30:2f:5d:46:0d:47:43:d5: + 1b:aa:59:0e:b9:5c:8d:06:48:ad:74:87:5f:c7:fc:31:54:41: + 13:e2:c7:21:0e:9e:e0:1e:0d:e1:c0:7b:43:85:90:c5:8a:58: + c6:65:0a:78:57:f2:c6:23:0f:01:d9:20:4b:de:0f:fb:92:85: + 75:2a:5c:73:8d:6d:7b:25:91:ca:ee:45:ae:06:4b:00:cc:d3: + b1:59:50:da:3a:88:3b:29:43:46:5e:97:2b:54:ce:53:6f:8d: + 4a:e7:96:fa:bf:71:0e:42:8b:7c:fd:28:a0:d0:48:ca:da:c4: + 81:4c:bb:a2:73:93:26:c8:eb:0c:d6:26:88:b6:c0:24:cf:bb: + bd:5b:eb:75:7d:e9:08:8e:86:33:2c:79:77:09:69:a5:89:fc: + b3:70:90:87:76:8f:d3:22:bb:42:ce:bd:73:0b:20:26:2a:d0: + 9b:3d:70:1e:24:6c:cd:87:76:a9:17:96:b7:cf:0d:92:fb:8e: + 18:a9:98:49:d1:9e:fe:60:44:72:21:b9:19:ed:c2:f5:31:f1: + 39:48:88:90:24:75:54:16:ad:ce:f4:f8:69:14:64:39:fb:a3: + b8:ba:70:40:c7:27:1c:bf:c4:56:53:fa:63:65:d0:f3:1c:0e: + 16:f5:6b:86:58:4d:18:d4:e4:0d:8e:a5:9d:5b:91:dc:76:24: + 50:3f:c6:2a:fb:d9:b7:9c:b5:d6:e6:d0:d9:e8:19:8b:15:71: + 48:ad:b7:ea:d8:59:88:d4:90:bf:16:b3:d9:e9:ac:59:61:54: + c8:1c:ba:ca:c1:ca:e1:b9:20:4c:8f:3a:93:89:a5:a0:cc:bf: + d3:f6:75:a4:75:96:6d:56 +-----BEGIN CERTIFICATE----- +MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAw +NzEUMBIGA1UECgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJv +b3QgQ0EgdjEwHhcNMDcxMDE4MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYD +VQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwWVGVsaWFTb25lcmEgUm9vdCBDQSB2 +MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK+6yfwIaPzaSZVfp3F +VRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA3GV1 +7CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+X +Z75Ljo1kB1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+ +/jXh7VB7qTCNGdMJjmhnXb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs +81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxHoLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkm +dtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3F0fUTPHSiXk+TT2YqGHe +Oh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJoWjiUIMu +sDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4 +pgd7gUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fs +slESl1MpWtTwEhDcTwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQ +arMCpgKIv7NHfirZ1fpoeDVNAgMBAAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYD +VR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qWDNXr+nuqF+gTEjANBgkqhkiG +9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNmzqjMDfz1mgbl +dxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx +0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1Tj +TQpgcmLNkQfWpb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBed +Y2gea+zDTYa4EzAvXUYNR0PVG6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7 +Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpcc41teyWRyu5FrgZLAMzTsVlQ2jqI +OylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOTJsjrDNYmiLbAJM+7 +vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2qReW +t88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcn +HL/EVlP6Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVx +SK236thZiNSQvxaz2emsWWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY= +-----END CERTIFICATE----- + +E-Tugra Certification Authority +# Issuer: CN=E-Tugra Certification Authority,OU=E-Tugra Sertifikasyon Merkezi,O=E-Tu..ra EBG Bili..im Teknolojileri ve Hizmetleri A....,L=Ankara,C=TR +# Serial Number:6a:68:3e:9c:51:9b:cb:53 +# Subject: CN=E-Tugra Certification Authority,OU=E-Tugra Sertifikasyon Merkezi,O=E-Tu..ra EBG Bili..im Teknolojileri ve Hizmetleri A....,L=Ankara,C=TR +# Not Valid Before: Tue Mar 05 12:09:48 2013 +# Not Valid After : Fri Mar 03 12:09:48 2023 +# Fingerprint (MD5): B8:A1:03:63:B0:BD:21:71:70:8A:6F:13:3A:BB:79:49 +# Fingerprint (SHA1): 51:C6:E7:08:49:06:6E:F3:92:D4:5C:A0:0D:6D:A3:62:8F:C3:52:39 +TRUSTED_DELEGATOR: SERVER_AUTH +MUST_VERIFY_TRUST: EMAIL_PROTECTION, CODE_SIGNING +================================================= +MD5 Fingerprint=B8:A1:03:63:B0:BD:21:71:70:8A:6F:13:3A:BB:79:49 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 7667447206703254355 (0x6a683e9c519bcb53) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=TR, L=Ankara, O=E-Tu\xC4\x9Fra EBG Bili\xC5\x9Fim Teknolojileri ve Hizmetleri A.\xC5\x9E., OU=E-Tugra Sertifikasyon Merkezi, CN=E-Tugra Certification Authority + Validity + Not Before: Mar 5 12:09:48 2013 GMT + Not After : Mar 3 12:09:48 2023 GMT + Subject: C=TR, L=Ankara, O=E-Tu\xC4\x9Fra EBG Bili\xC5\x9Fim Teknolojileri ve Hizmetleri A.\xC5\x9E., OU=E-Tugra Sertifikasyon Merkezi, CN=E-Tugra Certification Authority + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:e2:f5:3f:93:05:51:1e:85:62:54:5e:7a:0b:f5: + 18:07:83:ae:7e:af:7c:f7:d4:8a:6b:a5:63:43:39: + b9:4b:f7:c3:c6:64:89:3d:94:2e:54:80:52:39:39: + 07:4b:4b:dd:85:07:76:87:cc:bf:2f:95:4c:cc:7d: + a7:3d:bc:47:0f:98:70:f8:8c:85:1e:74:8e:92:6d: + 1b:40:d1:99:0d:bb:75:6e:c8:a9:6b:9a:c0:84:31: + af:ca:43:cb:eb:2b:34:e8:8f:97:6b:01:9b:d5:0e: + 4a:08:aa:5b:92:74:85:43:d3:80:ae:a1:88:5b:ae: + b3:ea:5e:cb:16:9a:77:44:c8:a1:f6:54:68:ce:de: + 8f:97:2b:ba:5b:40:02:0c:64:17:c0:b5:93:cd:e1: + f1:13:66:ce:0c:79:ef:d1:91:28:ab:5f:a0:12:52: + 30:73:19:8e:8f:e1:8c:07:a2:c3:bb:4a:f0:ea:1f: + 15:a8:ee:25:cc:a4:46:f8:1b:22:ef:b3:0e:43:ba: + 2c:24:b8:c5:2c:5c:d4:1c:f8:5d:64:bd:c3:93:5e: + 28:a7:3f:27:f1:8e:1e:d3:2a:50:05:a3:55:d9:cb: + e7:39:53:c0:98:9e:8c:54:62:8b:26:b0:f7:7d:8d: + 7c:e4:c6:9e:66:42:55:82:47:e7:b2:58:8d:66:f7: + 07:7c:2e:36:e6:50:1c:3f:db:43:24:c5:bf:86:47: + 79:b3:79:1c:f7:5a:f4:13:ec:6c:f8:3f:e2:59:1f: + 95:ee:42:3e:b9:ad:a8:32:85:49:97:46:fe:4b:31: + 8f:5a:cb:ad:74:47:1f:e9:91:b7:df:28:04:22:a0: + d4:0f:5d:e2:79:4f:ea:6c:85:86:bd:a8:a6:ce:e4: + fa:c3:e1:b3:ae:de:3c:51:ee:cb:13:7c:01:7f:84: + 0e:5d:51:94:9e:13:0c:b6:2e:a5:4c:f9:39:70:36: + 6f:96:ca:2e:0c:44:55:c5:ca:fa:5d:02:a3:df:d6: + 64:8c:5a:b3:01:0a:a9:b5:0a:47:17:ff:ef:91:40: + 2a:8e:a1:46:3a:31:98:e5:11:fc:cc:bb:49:56:8a: + fc:b9:d0:61:9a:6f:65:6c:e6:c3:cb:3e:75:49:fe: + 8f:a7:e2:89:c5:67:d7:9d:46:13:4e:31:76:3b:24: + b3:9e:11:65:86:ab:7f:ef:1d:d4:f8:bc:e7:ac:5a: + 5c:b7:5a:47:5c:55:ce:55:b4:22:71:5b:5b:0b:f0: + cf:dc:a0:61:64:ea:a9:d7:68:0a:63:a7:e0:0d:3f: + a0:af:d3:aa:d2:7e:ef:51:a0:e6:51:2b:55:92:15: + 17:53:cb:b7:66:0e:66:4c:f8:f9:75:4c:90:e7:12: + 70:c7:45 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + 2E:E3:DB:B2:49:D0:9C:54:79:5C:FA:27:2A:FE:CC:4E:D2:E8:4E:54 + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Authority Key Identifier: + keyid:2E:E3:DB:B2:49:D0:9C:54:79:5C:FA:27:2A:FE:CC:4E:D2:E8:4E:54 + + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + Signature Algorithm: sha256WithRSAEncryption + 05:37:3a:f4:4d:b7:45:e2:45:75:24:8f:b6:77:52:e8:1c:d8: + 10:93:65:f3:f2:59:06:a4:3e:1e:29:ec:5d:d1:d0:ab:7c:e0: + 0a:90:48:78:ed:4e:98:03:99:fe:28:60:91:1d:30:1d:b8:63: + 7c:a8:e6:35:b5:fa:d3:61:76:e6:d6:07:4b:ca:69:9a:b2:84: + 7a:77:93:45:17:15:9f:24:d0:98:13:12:ff:bb:a0:2e:fd:4e: + 4c:87:f8:ce:5c:aa:98:1b:05:e0:00:46:4a:82:80:a5:33:8b: + 28:dc:ed:38:d3:df:e5:3e:e9:fe:fb:59:dd:61:84:4f:d2:54: + 96:13:61:13:3e:8f:80:69:be:93:47:b5:35:43:d2:5a:bb:3d: + 5c:ef:b3:42:47:cd:3b:55:13:06:b0:09:db:fd:63:f6:3a:88: + 0a:99:6f:7e:e1:ce:1b:53:6a:44:66:23:51:08:7b:bc:5b:52: + a2:fd:06:37:38:40:61:8f:4a:96:b8:90:37:f8:66:c7:78:90: + 00:15:2e:8b:ad:51:35:53:07:a8:6b:68:ae:f9:4e:3c:07:26: + cd:08:05:70:cc:39:3f:76:bd:a5:d3:67:26:01:86:a6:53:d2: + 60:3b:7c:43:7f:55:8a:bc:95:1a:c1:28:39:4c:1f:43:d2:91: + f4:72:59:8a:b9:56:fc:3f:b4:9d:da:70:9c:76:5a:8c:43:50: + ee:8e:30:72:4d:df:ff:49:f7:c6:a9:67:d9:6d:ac:02:11:e2: + 3a:16:25:a7:58:08:cb:6f:53:41:9c:48:38:47:68:33:d1:d7: + c7:8f:d4:74:21:d4:c3:05:90:7a:ff:ce:96:88:b1:15:29:5d: + 23:ab:d0:60:a1:12:4f:de:f4:17:cd:32:e5:c9:bf:c8:43:ad: + fd:2e:8e:f1:af:e2:f4:98:fa:12:1f:20:d8:c0:a7:0c:85:c5: + 90:f4:3b:2d:96:26:b1:2c:be:4c:ab:eb:b1:d2:8a:c9:db:78: + 13:0f:1e:09:9d:6d:8f:00:9f:02:da:c1:fa:1f:7a:7a:09:c4: + 4a:e6:88:2a:97:9f:89:8b:fd:37:5f:5f:3a:ce:38:59:86:4b: + af:71:0b:b4:d8:f2:70:4f:9f:32:13:e3:b0:a7:57:e5:da:da: + 43:cb:84:34:f2:28:c4:ea:6d:f4:2a:ef:c1:6b:76:da:fb:7e: + bb:85:3c:d2:53:c2:4d:be:71:e1:45:d1:fd:23:67:0d:13:75: + fb:cf:65:67:22:9d:ae:b0:09:d1:09:ff:1d:34:bf:fe:23:97: + 37:d2:39:fa:3d:0d:06:0b:b4:db:3b:a3:ab:6f:5c:1d:b6:7e: + e8:b3:82:34:ed:06:5c:24 +-----BEGIN CERTIFICATE----- +MIIGSzCCBDOgAwIBAgIIamg+nFGby1MwDQYJKoZIhvcNAQELBQAwgbIxCzAJBgNV +BAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExQDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBC +aWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhpem1ldGxlcmkgQS7Fni4xJjAkBgNV +BAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBNZXJrZXppMSgwJgYDVQQDDB9FLVR1 +Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTEzMDMwNTEyMDk0OFoXDTIz +MDMwMzEyMDk0OFowgbIxCzAJBgNVBAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExQDA+ +BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhp +em1ldGxlcmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBN +ZXJrZXppMSgwJgYDVQQDDB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA4vU/kwVRHoViVF56C/UY +B4Oufq9899SKa6VjQzm5S/fDxmSJPZQuVIBSOTkHS0vdhQd2h8y/L5VMzH2nPbxH +D5hw+IyFHnSOkm0bQNGZDbt1bsipa5rAhDGvykPL6ys06I+XawGb1Q5KCKpbknSF +Q9OArqGIW66z6l7LFpp3RMih9lRozt6Plyu6W0ACDGQXwLWTzeHxE2bODHnv0ZEo +q1+gElIwcxmOj+GMB6LDu0rw6h8VqO4lzKRG+Bsi77MOQ7osJLjFLFzUHPhdZL3D +k14opz8n8Y4e0ypQBaNV2cvnOVPAmJ6MVGKLJrD3fY185MaeZkJVgkfnsliNZvcH +fC425lAcP9tDJMW/hkd5s3kc91r0E+xs+D/iWR+V7kI+ua2oMoVJl0b+SzGPWsut +dEcf6ZG33ygEIqDUD13ieU/qbIWGvaimzuT6w+Gzrt48Ue7LE3wBf4QOXVGUnhMM +ti6lTPk5cDZvlsouDERVxcr6XQKj39ZkjFqzAQqptQpHF//vkUAqjqFGOjGY5RH8 +zLtJVor8udBhmm9lbObDyz51Sf6Pp+KJxWfXnUYTTjF2OySznhFlhqt/7x3U+Lzn +rFpct1pHXFXOVbQicVtbC/DP3KBhZOqp12gKY6fgDT+gr9Oq0n7vUaDmUStVkhUX +U8u3Zg5mTPj5dUyQ5xJwx0UCAwEAAaNjMGEwHQYDVR0OBBYEFC7j27JJ0JxUeVz6 +Jyr+zE7S6E5UMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAULuPbsknQnFR5 +XPonKv7MTtLoTlQwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAF +Nzr0TbdF4kV1JI+2d1LoHNgQk2Xz8lkGpD4eKexd0dCrfOAKkEh47U6YA5n+KGCR +HTAduGN8qOY1tfrTYXbm1gdLymmasoR6d5NFFxWfJNCYExL/u6Au/U5Mh/jOXKqY +GwXgAEZKgoClM4so3O0409/lPun++1ndYYRP0lSWE2ETPo+Aab6TR7U1Q9Jauz1c +77NCR807VRMGsAnb/WP2OogKmW9+4c4bU2pEZiNRCHu8W1Ki/QY3OEBhj0qWuJA3 ++GbHeJAAFS6LrVE1Uweoa2iu+U48BybNCAVwzDk/dr2l02cmAYamU9JgO3xDf1WK +vJUawSg5TB9D0pH0clmKuVb8P7Sd2nCcdlqMQ1DujjByTd//SffGqWfZbawCEeI6 +FiWnWAjLb1NBnEg4R2gz0dfHj9R0IdTDBZB6/86WiLEVKV0jq9BgoRJP3vQXzTLl +yb/IQ639Lo7xr+L0mPoSHyDYwKcMhcWQ9DstliaxLL5Mq+ux0orJ23gTDx4JnW2P +AJ8C2sH6H3p6CcRK5ogql5+Ji/03X186zjhZhkuvcQu02PJwT58yE+Owp1fl2tpD +y4Q08ijE6m30Ku/Ba3ba+367hTzSU8JNvnHhRdH9I2cNE3X7z2VnIp2usAnRCf8d +NL/+I5c30jn6PQ0GC7TbO6Orb1wdtn7os4I07QZcJA== +-----END CERTIFICATE----- + +T-TeleSec GlobalRoot Class 2 +# Issuer: CN=T-TeleSec GlobalRoot Class 2,OU=T-Systems Trust Center,O=T-Systems Enterprise Services GmbH,C=DE +# Serial Number: 1 (0x1) +# Subject: CN=T-TeleSec GlobalRoot Class 2,OU=T-Systems Trust Center,O=T-Systems Enterprise Services GmbH,C=DE +# Not Valid Before: Wed Oct 01 10:40:14 2008 +# Not Valid After : Sat Oct 01 23:59:59 2033 +# Fingerprint (MD5): 2B:9B:9E:E4:7B:6C:1F:00:72:1A:CC:C1:77:79:DF:6A +# Fingerprint (SHA1): 59:0D:2D:7D:88:4F:40:2E:61:7E:A5:62:32:17:65:CF:17:D8:94:E9 +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +MUST_VERIFY_TRUST: CODE_SIGNING +================================================ +MD5 Fingerprint=2B:9B:9E:E4:7B:6C:1F:00:72:1A:CC:C1:77:79:DF:6A +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 1 (0x1) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=DE, O=T-Systems Enterprise Services GmbH, OU=T-Systems Trust Center, CN=T-TeleSec GlobalRoot Class 2 + Validity + Not Before: Oct 1 10:40:14 2008 GMT + Not After : Oct 1 23:59:59 2033 GMT + Subject: C=DE, O=T-Systems Enterprise Services GmbH, OU=T-Systems Trust Center, CN=T-TeleSec GlobalRoot Class 2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:aa:5f:da:1b:5f:e8:73:91:e5:da:5c:f4:a2:e6: + 47:e5:f3:68:55:60:05:1d:02:a4:b3:9b:59:f3:1e: + 8a:af:34:ad:fc:0d:c2:d9:48:19:ee:69:8f:c9:20: + fc:21:aa:07:19:ed:b0:5c:ac:65:c7:5f:ed:02:7c: + 7b:7c:2d:1b:d6:ba:b9:80:c2:18:82:16:84:fa:66: + b0:08:c6:54:23:81:e4:cd:b9:49:3f:f6:4f:6e:37: + 48:28:38:0f:c5:be:e7:68:70:fd:39:97:4d:d2:c7: + 98:91:50:aa:c4:44:b3:23:7d:39:47:e9:52:62:d6: + 12:93:5e:b7:31:96:42:05:fb:76:a7:1e:a3:f5:c2: + fc:e9:7a:c5:6c:a9:71:4f:ea:cb:78:bc:60:af:c7: + de:f4:d9:cb:be:7e:33:a5:6e:94:83:f0:34:fa:21: + ab:ea:8e:72:a0:3f:a4:de:30:5b:ef:86:4d:6a:95: + 5b:43:44:a8:10:15:1c:e5:01:57:c5:98:f1:e6:06: + 28:91:aa:20:c5:b7:53:26:51:43:b2:0b:11:95:58: + e1:c0:0f:76:d9:c0:8d:7c:81:f3:72:70:9e:6f:fe: + 1a:8e:d9:5f:35:c6:b2:6f:34:7c:be:48:4f:e2:5a: + 39:d7:d8:9d:78:9e:9f:86:3e:03:5e:19:8b:44:a2: + d5:c7 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + BF:59:20:36:00:79:A0:A0:22:6B:8C:D5:F2:61:D2:B8:2C:CB:82:4A + Signature Algorithm: sha256WithRSAEncryption + 31:03:a2:61:0b:1f:74:e8:72:36:c6:6d:f9:4d:9e:fa:22:a8: + e1:81:56:cf:cd:bb:9f:ea:ab:91:19:38:af:aa:7c:15:4d:f3: + b6:a3:8d:a5:f4:8e:f6:44:a9:a7:e8:21:95:ad:3e:00:62:16: + 88:f0:02:ba:fc:61:23:e6:33:9b:30:7a:6b:36:62:7b:ad:04: + 23:84:58:65:e2:db:2b:8a:e7:25:53:37:62:53:5f:bc:da:01: + 62:29:a2:a6:27:71:e6:3a:22:7e:c1:6f:1d:95:70:20:4a:07: + 34:df:ea:ff:15:80:e5:ba:d7:7a:d8:5b:75:7c:05:7a:29:47: + 7e:40:a8:31:13:77:cd:40:3b:b4:51:47:7a:2e:11:e3:47:11: + de:9d:66:d0:8b:d5:54:66:fa:83:55:ea:7c:c2:29:89:1b:e9: + 6f:b3:ce:e2:05:84:c9:2f:3e:78:85:62:6e:c9:5f:c1:78:63: + 74:58:c0:48:18:0c:99:39:eb:a4:cc:1a:b5:79:5a:8d:15:9c: + d8:14:0d:f6:7a:07:57:c7:22:83:05:2d:3c:9b:25:26:3d:18: + b3:a9:43:7c:c8:c8:ab:64:8f:0e:a3:bf:9c:1b:9d:30:db:da: + d0:19:2e:aa:3c:f1:fb:33:80:76:e4:cd:ad:19:4f:05:27:8e: + 13:a1:6e:c2 +-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx +KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd +BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl +YyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgxMDAxMTA0MDE0WhcNMzMxMDAxMjM1 +OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy +aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50 +ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUd +AqSzm1nzHoqvNK38DcLZSBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiC +FoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/FvudocP05l03Sx5iRUKrERLMjfTlH6VJi +1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx9702cu+fjOlbpSD8DT6Iavq +jnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGVWOHAD3bZ +wI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGj +QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/ +WSA2AHmgoCJrjNXyYdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhy +NsZt+U2e+iKo4YFWz827n+qrkRk4r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPAC +uvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNfvNoBYimipidx5joifsFvHZVw +IEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR3p1m0IvVVGb6 +g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN +9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlP +BSeOE6Fuwg== +-----END CERTIFICATE----- + +Atos TrustedRoot 2011 +# Issuer: C=DE,O=Atos,CN=Atos TrustedRoot 2011 +# Serial Number:5c:33:cb:62:2c:5f:b3:32 +# Subject: C=DE,O=Atos,CN=Atos TrustedRoot 2011 +# Not Valid Before: Thu Jul 07 14:58:30 2011 +# Not Valid After : Tue Dec 31 23:59:59 2030 +# Fingerprint (MD5): AE:B9:C4:32:4B:AC:7F:5D:66:CC:77:94:BB:2A:77:56 +# Fingerprint (SHA1): 2B:B1:F5:3E:55:0C:1D:C5:F1:D4:E6:B7:6A:46:4B:55:06:02:AC:21 +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +MUST_VERIFY_TRUST: CODE_SIGNING +================================================ +MD5 Fingerprint=AE:B9:C4:32:4B:AC:7F:5D:66:CC:77:94:BB:2A:77:56 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 6643877497813316402 (0x5c33cb622c5fb332) + Signature Algorithm: sha256WithRSAEncryption + Issuer: CN=Atos TrustedRoot 2011, O=Atos, C=DE + Validity + Not Before: Jul 7 14:58:30 2011 GMT + Not After : Dec 31 23:59:59 2030 GMT + Subject: CN=Atos TrustedRoot 2011, O=Atos, C=DE + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:95:85:3b:97:6f:2a:3b:2e:3b:cf:a6:f3:29:35: + be:cf:18:ac:3e:aa:d9:f8:4d:a0:3e:1a:47:b9:bc: + 9a:df:f2:fe:cc:3e:47:e8:7a:96:c2:24:8e:35:f4: + a9:0c:fc:82:fd:6d:c1:72:62:27:bd:ea:6b:eb:e7: + 8a:cc:54:3e:90:50:cf:80:d4:95:fb:e8:b5:82:d4: + 14:c5:b6:a9:55:25:57:db:b1:50:f6:b0:60:64:59: + 7a:69:cf:03:b7:6f:0d:be:ca:3e:6f:74:72:ea:aa: + 30:2a:73:62:be:49:91:61:c8:11:fe:0e:03:2a:f7: + 6a:20:dc:02:15:0d:5e:15:6a:fc:e3:82:c1:b5:c5: + 9d:64:09:6c:a3:59:98:07:27:c7:1b:96:2b:61:74: + 71:6c:43:f1:f7:35:89:10:e0:9e:ec:55:a1:37:22: + a2:87:04:05:2c:47:7d:b4:1c:b9:62:29:66:28:ca: + b7:e1:93:f5:a4:94:03:99:b9:70:85:b5:e6:48:ea: + 8d:50:fc:d9:de:cc:6f:07:0e:dd:0b:72:9d:80:30: + 16:07:95:3f:28:0e:fd:c5:75:4f:53:d6:74:9a:b4: + 24:2e:8e:02:91:cf:76:c5:9b:1e:55:74:9c:78:21: + b1:f0:2d:f1:0b:9f:c2:d5:96:18:1f:f0:54:22:7a: + 8c:07 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + A7:A5:06:B1:2C:A6:09:60:EE:D1:97:E9:70:AE:BC:3B:19:6C:DB:21 + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Authority Key Identifier: + keyid:A7:A5:06:B1:2C:A6:09:60:EE:D1:97:E9:70:AE:BC:3B:19:6C:DB:21 + + X509v3 Certificate Policies: + Policy: 1.3.6.1.4.1.6189.3.4.1.1 + + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + Signature Algorithm: sha256WithRSAEncryption + 26:77:34:db:94:48:86:2a:41:9d:2c:3e:06:90:60:c4:8c:ac: + 0b:54:b8:1f:b9:7b:d3:07:39:e4:fa:3e:7b:b2:3d:4e:ed:9f: + 23:bd:97:f3:6b:5c:ef:ee:fd:40:a6:df:a1:93:a1:0a:86:ac: + ef:20:d0:79:01:bd:78:f7:19:d8:24:31:34:04:01:a6:ba:15: + 9a:c3:27:dc:d8:4f:0f:cc:18:63:ff:99:0f:0e:91:6b:75:16: + e1:21:fc:d8:26:c7:47:b7:a6:cf:58:72:71:7e:ba:e1:4d:95: + 47:3b:c9:af:6d:a1:b4:c1:ec:89:f6:b4:0f:38:b5:e2:64:dc: + 25:cf:a6:db:eb:9a:5c:99:a1:c5:08:de:fd:e6:da:d5:d6:5a: + 45:0c:c4:b7:c2:b5:14:ef:b4:11:ff:0e:15:b5:f5:f5:db:c6: + bd:eb:5a:a7:f0:56:22:a9:3c:65:54:c6:15:a8:bd:86:9e:cd: + 83:96:68:7a:71:81:89:e1:0b:e1:ea:11:1b:68:08:cc:69:9e: + ec:9e:41:9e:44:32:26:7a:e2:87:0a:71:3d:eb:e4:5a:a4:d2: + db:c5:cd:c6:de:60:7f:b9:f3:4f:44:92:ef:2a:b7:18:3e:a7: + 19:d9:0b:7d:b1:37:41:42:b0:ba:60:1d:f2:fe:09:11:b0:f0: + 87:7b:a7:9d +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UE +AwwVQXRvcyBUcnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQG +EwJERTAeFw0xMTA3MDcxNDU4MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMM +FUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsGA1UECgwEQXRvczELMAkGA1UEBhMC +REUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCVhTuXbyo7LjvPpvMp +Nb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr54rM +VD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+ +SZFhyBH+DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ +4J7sVaE3IqKHBAUsR320HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0L +cp2AMBYHlT8oDv3FdU9T1nSatCQujgKRz3bFmx5VdJx4IbHwLfELn8LVlhgf8FQi +eowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7Rl+lwrrw7GWzbITAPBgNV +HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZbNshMBgG +A1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3 +DQEBCwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8j +vZfza1zv7v1Apt+hk6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kP +DpFrdRbhIfzYJsdHt6bPWHJxfrrhTZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pc +maHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a961qn8FYiqTxlVMYVqL2Gns2D +lmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G3mB/ufNPRJLv +KrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed +-----END CERTIFICATE----- + +QuoVadis Root CA 1 G3 +# Fingerprint (SHA1): 1B:8E:EA:57:96:29:1A:C9:39:EA:B8:0A:81:1A:73:73:C0:93:79:67 +MUST_VERIFY_TRUST: CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +================================================ +MD5 Fingerprint=A4:BC:5B:3F:FE:37:9A:FA:64:F0:E2:FA:05:3D:0B:AB +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 78:58:5f:2e:ad:2c:19:4b:e3:37:07:35:34:13:28:b5:96:d4:65:93 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=BM, O=QuoVadis Limited, CN=QuoVadis Root CA 1 G3 + Validity + Not Before: Jan 12 17:27:44 2012 GMT + Not After : Jan 12 17:27:44 2042 GMT + Subject: C=BM, O=QuoVadis Limited, CN=QuoVadis Root CA 1 G3 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:a0:be:50:10:8e:e9:f2:6c:40:b4:04:9c:85:b9: + 31:ca:dc:2d:e4:11:a9:04:3c:1b:55:c1:e7:58:30: + 1d:24:b4:c3:ef:85:de:8c:2c:e1:c1:3d:df:82:e6: + 4f:ad:47:87:6c:ec:5b:49:c1:4a:d5:bb:8f:ec:87: + ac:7f:82:9a:86:ec:3d:03:99:52:01:d2:35:9e:ac: + da:f0:53:c9:66:3c:d4:ac:02:01:da:24:d3:3b:a8: + 02:46:af:a4:1c:e3:f8:73:58:76:b7:f6:0e:90:0d: + b5:f0:cf:cc:fa:f9:c6:4c:e5:c3:86:30:0a:8d:17: + 7e:35:eb:c5:df:bb:0e:9c:c0:8d:87:e3:88:38:85: + 67:fa:3e:c7:ab:e0:13:9c:05:18:98:cf:93:f5:b1: + 92:b4:fc:23:d3:cf:d5:c4:27:49:e0:9e:3c:9b:08: + a3:8b:5d:2a:21:e0:fc:39:aa:53:da:7d:7e:cf:1a: + 09:53:bc:5d:05:04:cf:a1:4a:8f:8b:76:82:0d:a1: + f8:d2:c7:14:77:5b:90:36:07:81:9b:3e:06:fa:52: + 5e:63:c5:a6:00:fe:a5:e9:52:1b:52:b5:92:39:72: + 03:09:62:bd:b0:60:16:6e:a6:dd:25:c2:03:66:dd: + f3:04:d1:40:e2:4e:8b:86:f4:6f:e5:83:a0:27:84: + 5e:04:c1:f5:90:bd:30:3d:c4:ef:a8:69:bc:38:9b: + a4:a4:96:d1:62:da:69:c0:01:96:ae:cb:c4:51:34: + ea:0c:aa:ff:21:8e:59:8f:4a:5c:e4:61:9a:a7:d2: + e9:2a:78:8d:51:3d:3a:15:ee:a2:59:8e:a9:5c:de: + c5:f9:90:22:e5:88:45:71:dd:91:99:6c:7a:9f:3d: + 3d:98:7c:5e:f6:be:16:68:a0:5e:ae:0b:23:fc:5a: + 0f:aa:22:76:2d:c9:a1:10:1d:e4:d3:44:23:90:88: + 9f:c6:2a:e6:d7:f5:9a:b3:58:1e:2f:30:89:08:1b: + 54:a2:b5:98:23:ec:08:77:1c:95:5d:61:d1:cb:89: + 9c:5f:a2:4a:91:9a:ef:21:aa:49:16:08:a8:bd:61: + 28:31:c9:74:ad:85:f6:d9:c5:b1:8b:d1:e5:10:32: + 4d:5f:8b:20:3a:3c:49:1f:33:85:59:0d:db:cb:09: + 75:43:69:73:fb:6b:71:7d:f0:df:c4:4c:7d:c6:a3: + 2e:c8:95:79:cb:73:a2:8e:4e:4d:24:fb:5e:e4:04: + be:72:1b:a6:27:2d:49:5a:99:7a:d7:5c:09:20:b7: + 7f:94:b9:4f:f1:0d:1c:5e:88:42:1b:11:b7:e7:91: + db:9e:6c:f4:6a:df:8c:06:98:03:ad:cc:28:ef:a5: + 47:f3:53 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + A3:97:D6:F3:5E:A2:10:E1:AB:45:9F:3C:17:64:3C:EE:01:70:9C:CC + Signature Algorithm: sha256WithRSAEncryption + 18:fa:5b:75:fc:3e:7a:c7:5f:77:c7:ca:df:cf:5f:c3:12:c4: + 40:5d:d4:32:aa:b8:6a:d7:d5:15:15:46:98:23:a5:e6:90:5b: + 18:99:4c:e3:ad:42:a3:82:31:36:88:cd:e9:fb:c4:04:96:48: + 8b:01:c7:8d:01:cf:5b:33:06:96:46:66:74:1d:4f:ed:c1:b6: + b9:b4:0d:61:cc:63:7e:d7:2e:77:8c:96:1c:2a:23:68:6b:85: + 57:76:70:33:13:fe:e1:4f:a6:23:77:18:fa:1a:8c:e8:bd:65: + c9:cf:3f:f4:c9:17:dc:eb:c7:bc:c0:04:2e:2d:46:2f:69:66: + c3:1b:8f:fe:ec:3e:d3:ca:94:bf:76:0a:25:0d:a9:7b:02:1c: + a9:d0:3b:5f:0b:c0:81:3a:3d:64:e1:bf:a7:2d:4e:bd:4d:c4: + d8:29:c6:22:18:d0:c5:ac:72:02:82:3f:aa:3a:a2:3a:22:97: + 31:dd:08:63:c3:75:14:b9:60:28:2d:5b:68:e0:16:a9:66:82: + 23:51:f5:eb:53:d8:31:9b:7b:e9:b7:9d:4b:eb:88:16:cf:f9: + 5d:38:8a:49:30:8f:ed:f1:eb:19:f4:77:1a:31:18:4d:67:54: + 6c:2f:6f:65:f9:db:3d:ec:21:ec:5e:f4:f4:8b:ca:60:65:54: + d1:71:64:f4:f9:a6:a3:81:33:36:33:71:f0:a4:78:5f:4e:ad: + 83:21:de:34:49:8d:e8:59:ac:9d:f2:76:5a:36:f2:13:f4:af: + e0:09:c7:61:2a:6c:f7:e0:9d:ae:bb:86:4a:28:6f:2e:ee:b4: + 79:cd:90:33:c3:b3:76:fa:f5:f0:6c:9d:01:90:fa:9e:90:f6: + 9c:72:cf:47:da:c3:1f:e4:35:20:53:f2:54:d1:df:61:83:a6: + 02:e2:25:38:de:85:32:2d:5e:73:90:52:5d:42:c4:ce:3d:4b: + e1:f9:19:84:1d:d5:a2:50:cc:41:fb:41:14:c3:bd:d6:c9:5a: + a3:63:66:02:80:bd:05:3a:3b:47:9c:ec:00:26:4c:f5:88:51: + bf:a8:23:7f:18:07:b0:0b:ed:8b:26:a1:64:d3:61:4a:eb:5c: + 9f:de:b3:af:67:03:b3:1f:dd:6d:5d:69:68:69:ab:5e:3a:ec: + 7c:69:bc:c7:3b:85:4e:9e:15:b9:b4:15:4f:c3:95:7a:58:d7: + c9:6c:e9:6c:b9:f3:29:63:5e:b4:2c:f0:2d:3d:ed:5a:65:e0: + a9:5b:40:c2:48:99:81:6d:9e:1f:06:2a:3c:12:b4:8b:0f:9b: + a2:24:f0:a6:8d:d6:7a:e0:4b:b6:64:96:63:95:84:c2:4a:cd: + 1c:2e:24:87:33:60:e5:c3 +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQEL +BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc +BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMSBHMzAeFw0xMjAxMTIxNzI3NDRaFw00 +MjAxMTIxNzI3NDRaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDEgRzMwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQCgvlAQjunybEC0BJyFuTHK3C3kEakEPBtV +wedYMB0ktMPvhd6MLOHBPd+C5k+tR4ds7FtJwUrVu4/sh6x/gpqG7D0DmVIB0jWe +rNrwU8lmPNSsAgHaJNM7qAJGr6Qc4/hzWHa39g6QDbXwz8z6+cZM5cOGMAqNF341 +68Xfuw6cwI2H44g4hWf6Pser4BOcBRiYz5P1sZK0/CPTz9XEJ0ngnjybCKOLXSoh +4Pw5qlPafX7PGglTvF0FBM+hSo+LdoINofjSxxR3W5A2B4GbPgb6Ul5jxaYA/qXp +UhtStZI5cgMJYr2wYBZupt0lwgNm3fME0UDiTouG9G/lg6AnhF4EwfWQvTA9xO+o +abw4m6SkltFi2mnAAZauy8RRNOoMqv8hjlmPSlzkYZqn0ukqeI1RPToV7qJZjqlc +3sX5kCLliEVx3ZGZbHqfPT2YfF72vhZooF6uCyP8Wg+qInYtyaEQHeTTRCOQiJ/G +KubX9ZqzWB4vMIkIG1SitZgj7Ah3HJVdYdHLiZxfokqRmu8hqkkWCKi9YSgxyXSt +hfbZxbGL0eUQMk1fiyA6PEkfM4VZDdvLCXVDaXP7a3F98N/ETH3Goy7IlXnLc6KO +Tk0k+17kBL5yG6YnLUlamXrXXAkgt3+UuU/xDRxeiEIbEbfnkduebPRq34wGmAOt +zCjvpUfzUwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQUo5fW816iEOGrRZ88F2Q87gFwnMwwDQYJKoZIhvcNAQELBQAD +ggIBABj6W3X8PnrHX3fHyt/PX8MSxEBd1DKquGrX1RUVRpgjpeaQWxiZTOOtQqOC +MTaIzen7xASWSIsBx40Bz1szBpZGZnQdT+3Btrm0DWHMY37XLneMlhwqI2hrhVd2 +cDMT/uFPpiN3GPoajOi9ZcnPP/TJF9zrx7zABC4tRi9pZsMbj/7sPtPKlL92CiUN +qXsCHKnQO18LwIE6PWThv6ctTr1NxNgpxiIY0MWscgKCP6o6ojoilzHdCGPDdRS5 +YCgtW2jgFqlmgiNR9etT2DGbe+m3nUvriBbP+V04ikkwj+3x6xn0dxoxGE1nVGwv +b2X52z3sIexe9PSLymBlVNFxZPT5pqOBMzYzcfCkeF9OrYMh3jRJjehZrJ3ydlo2 +8hP0r+AJx2EqbPfgna67hkooby7utHnNkDPDs3b69fBsnQGQ+p6Q9pxyz0fawx/k +NSBT8lTR32GDpgLiJTjehTItXnOQUl1CxM49S+H5GYQd1aJQzEH7QRTDvdbJWqNj +ZgKAvQU6O0ec7AAmTPWIUb+oI38YB7AL7YsmoWTTYUrrXJ/es69nA7Mf3W1daWhp +q1467HxpvMc7hU6eFbm0FU/DlXpY18ls6Wy58yljXrQs8C097Vpl4KlbQMJImYFt +nh8GKjwStIsPm6Ik8KaN1nrgS7ZklmOVhMJKzRwuJIczYOXD +-----END CERTIFICATE----- + +QuoVadis Root CA 2 G3 +# Fingerprint (SHA1): 09:3C:61:F3:8B:8B:DC:7D:55:DF:75:38:02:05:00:E1:25:F5:C8:36 +MUST_VERIFY_TRUST: EMAIL_PROTECTION, CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH +================================================= +MD5 Fingerprint=AF:0C:86:6E:BF:40:2D:7F:0B:3E:12:50:BA:12:3D:06 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 44:57:34:24:5b:81:89:9b:35:f2:ce:b8:2b:3b:5b:a7:26:f0:75:28 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=BM, O=QuoVadis Limited, CN=QuoVadis Root CA 2 G3 + Validity + Not Before: Jan 12 18:59:32 2012 GMT + Not After : Jan 12 18:59:32 2042 GMT + Subject: C=BM, O=QuoVadis Limited, CN=QuoVadis Root CA 2 G3 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:a1:ae:25:b2:01:18:dc:57:88:3f:46:eb:f9:af: + e2:eb:23:71:e2:9a:d1:61:66:21:5f:aa:af:27:51: + e5:6e:1b:16:d4:2d:7d:50:b0:53:77:bd:78:3a:60: + e2:64:02:9b:7c:86:9b:d6:1a:8e:ad:ff:1f:15:7f: + d5:95:1e:12:cb:e6:14:84:04:c1:df:36:b3:16:9f: + 8a:e3:c9:db:98:34:ce:d8:33:17:28:46:fc:a7:c9: + f0:d2:b4:d5:4d:09:72:49:f9:f2:87:e3:a9:da:7d: + a1:7d:6b:b2:3a:25:a9:6d:52:44:ac:f8:be:6e:fb: + dc:a6:73:91:90:61:a6:03:14:20:f2:e7:87:a3:88: + ad:ad:a0:8c:ff:a6:0b:25:52:25:e7:16:01:d5:cb: + b8:35:81:0c:a3:3b:f0:e1:e1:fc:5a:5d:ce:80:71: + 6d:f8:49:ab:3e:3b:ba:b8:d7:80:01:fb:a5:eb:5b: + b3:c5:5e:60:2a:31:a0:af:37:e8:20:3a:9f:a8:32: + 2c:0c:cc:09:1d:d3:9e:8e:5d:bc:4c:98:ee:c5:1a: + 68:7b:ec:53:a6:e9:14:35:a3:df:cd:80:9f:0c:48: + fb:1c:f4:f1:bf:4a:b8:fa:d5:8c:71:4a:c7:1f:ad: + fe:41:9a:b3:83:5d:f2:84:56:ef:a5:57:43:ce:29: + ad:8c:ab:55:bf:c4:fb:5b:01:dd:23:21:a1:58:00: + 8e:c3:d0:6a:13:ed:13:e3:12:2b:80:dc:67:e6:95: + b2:cd:1e:22:6e:2a:f8:41:d4:f2:ca:14:07:8d:8a: + 55:12:c6:69:f5:b8:86:68:2f:53:5e:b0:d2:aa:21: + c1:98:e6:30:e3:67:55:c7:9b:6e:ac:19:a8:55:a6: + 45:06:d0:23:3a:db:eb:65:5d:2a:11:11:f0:3b:4f: + ca:6d:f4:34:c4:71:e4:ff:00:5a:f6:5c:ae:23:60: + 85:73:f1:e4:10:b1:25:ae:d5:92:bb:13:c1:0c:e0: + 39:da:b4:39:57:b5:ab:35:aa:72:21:3b:83:35:e7: + 31:df:7a:21:6e:b8:32:08:7d:1d:32:91:15:4a:62: + 72:cf:e3:77:a1:bc:d5:11:1b:76:01:67:08:e0:41: + 0b:c3:eb:15:6e:f8:a4:19:d9:a2:ab:af:e2:27:52: + 56:2b:02:8a:2c:14:24:f9:bf:42:02:bf:26:c8:c6: + 8f:e0:6e:38:7d:53:2d:e5:ed:98:b3:95:63:68:7f: + f9:35:f4:df:88:c5:60:35:92:c0:7c:69:1c:61:95: + 16:d0:eb:de:0b:af:3e:04:10:45:65:58:50:38:af: + 48:f2:59:b6:16:f2:3c:0d:90:02:c6:70:2e:01:ad: + 3c:15:d7 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + ED:E7:6F:76:5A:BF:60:EC:49:5B:C6:A5:77:BB:72:16:71:9B:C4:3D + Signature Algorithm: sha256WithRSAEncryption + 91:df:80:3f:43:09:7e:71:c2:f7:eb:b3:88:8f:e1:51:b2:bc: + 3d:75:f9:28:5d:c8:bc:99:9b:7b:5d:aa:e5:ca:e1:0a:f7:e8: + b2:d3:9f:dd:67:31:7e:ba:01:aa:c7:6a:41:3b:90:d4:08:5c: + b2:60:6a:90:f0:c8:ce:03:62:f9:8b:ed:fb:6e:2a:dc:06:4d: + 3c:29:0f:89:16:8a:58:4c:48:0f:e8:84:61:ea:3c:72:a6:77: + e4:42:ae:88:a3:43:58:79:7e:ae:ca:a5:53:0d:a9:3d:70:bd: + 20:19:61:a4:6c:38:fc:43:32:e1:c1:47:ff:f8:ec:f1:11:22: + 32:96:9c:c2:f6:5b:69:96:7b:20:0c:43:41:9a:5b:f6:59:19: + 88:de:55:88:37:51:0b:78:5c:0a:1e:a3:42:fd:c7:9d:88:0f: + c0:f2:78:02:24:54:93:af:89:87:88:c9:4a:80:1d:ea:d0:6e: + 3e:61:2e:36:bb:35:0e:27:96:fd:66:34:3b:61:72:73:f1:16: + 5c:47:06:54:49:00:7a:58:12:b0:0a:ef:85:fd:b1:b8:33:75: + 6a:93:1c:12:e6:60:5e:6f:1d:7f:c9:1f:23:cb:84:61:9f:1e: + 82:44:f9:5f:ad:62:55:24:9a:52:98:ed:51:e7:a1:7e:97:3a: + e6:2f:1f:11:da:53:80:2c:85:9e:ab:35:10:db:22:5f:6a:c5: + 5e:97:53:f2:32:02:09:30:a3:58:f0:0d:01:d5:72:c6:b1:7c: + 69:7b:c3:f5:36:45:cc:61:6e:5e:4c:94:c5:5e:ae:e8:0e:5e: + 8b:bf:f7:cd:e0:ed:a1:0e:1b:33:ee:54:18:fe:0f:be:ef:7e: + 84:6b:43:e3:70:98:db:5d:75:b2:0d:59:07:85:15:23:39:d6: + f1:df:a9:26:0f:d6:48:c7:b3:a6:22:f5:33:37:5a:95:47:9f: + 7b:ba:18:15:6f:ff:d6:14:64:83:49:d2:0a:67:21:db:0f:35: + 63:60:28:22:e3:b1:95:83:cd:85:a6:dd:2f:0f:e7:67:52:6e: + bb:2f:85:7c:f5:4a:73:e7:c5:3e:c0:bd:21:12:05:3f:fc:b7: + 03:49:02:5b:c8:25:e6:e2:54:38:f5:79:87:8c:1d:53:b2:4e: + 85:7b:06:38:c7:2c:f8:f8:b0:72:8d:25:e5:77:52:f4:03:1c: + 48:a6:50:5f:88:20:30:6e:f2:82:43:ab:3d:97:84:e7:53:fb: + 21:c1:4f:0f:22:9a:86:b8:59:2a:f6:47:3d:19:88:2d:e8:85: + e1:9e:ec:85:08:6a:b1:6c:34:c9:1d:ec:48:2b:3b:78:ed:66: + c4:8e:79:69:83:de:7f:8c +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQEL +BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc +BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMiBHMzAeFw0xMjAxMTIxODU5MzJaFw00 +MjAxMTIxODU5MzJaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDIgRzMwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQChriWyARjcV4g/Ruv5r+LrI3HimtFhZiFf +qq8nUeVuGxbULX1QsFN3vXg6YOJkApt8hpvWGo6t/x8Vf9WVHhLL5hSEBMHfNrMW +n4rjyduYNM7YMxcoRvynyfDStNVNCXJJ+fKH46nafaF9a7I6JaltUkSs+L5u+9ym +c5GQYaYDFCDy54ejiK2toIz/pgslUiXnFgHVy7g1gQyjO/Dh4fxaXc6AcW34Sas+ +O7q414AB+6XrW7PFXmAqMaCvN+ggOp+oMiwMzAkd056OXbxMmO7FGmh77FOm6RQ1 +o9/NgJ8MSPsc9PG/Srj61YxxSscfrf5BmrODXfKEVu+lV0POKa2Mq1W/xPtbAd0j +IaFYAI7D0GoT7RPjEiuA3GfmlbLNHiJuKvhB1PLKFAeNilUSxmn1uIZoL1NesNKq +IcGY5jDjZ1XHm26sGahVpkUG0CM62+tlXSoREfA7T8pt9DTEceT/AFr2XK4jYIVz +8eQQsSWu1ZK7E8EM4DnatDlXtas1qnIhO4M15zHfeiFuuDIIfR0ykRVKYnLP43eh +vNURG3YBZwjgQQvD6xVu+KQZ2aKrr+InUlYrAoosFCT5v0ICvybIxo/gbjh9Uy3l +7ZizlWNof/k19N+IxWA1ksB8aRxhlRbQ694Lrz4EEEVlWFA4r0jyWbYW8jwNkALG +cC4BrTwV1wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQU7edvdlq/YOxJW8ald7tyFnGbxD0wDQYJKoZIhvcNAQELBQAD +ggIBAJHfgD9DCX5xwvfrs4iP4VGyvD11+ShdyLyZm3tdquXK4Qr36LLTn91nMX66 +AarHakE7kNQIXLJgapDwyM4DYvmL7ftuKtwGTTwpD4kWilhMSA/ohGHqPHKmd+RC +roijQ1h5fq7KpVMNqT1wvSAZYaRsOPxDMuHBR//47PERIjKWnML2W2mWeyAMQ0Ga +W/ZZGYjeVYg3UQt4XAoeo0L9x52ID8DyeAIkVJOviYeIyUqAHerQbj5hLja7NQ4n +lv1mNDthcnPxFlxHBlRJAHpYErAK74X9sbgzdWqTHBLmYF5vHX/JHyPLhGGfHoJE ++V+tYlUkmlKY7VHnoX6XOuYvHxHaU4AshZ6rNRDbIl9qxV6XU/IyAgkwo1jwDQHV +csaxfGl7w/U2Rcxhbl5MlMVerugOXou/983g7aEOGzPuVBj+D77vfoRrQ+NwmNtd +dbINWQeFFSM51vHfqSYP1kjHs6Yi9TM3WpVHn3u6GBVv/9YUZINJ0gpnIdsPNWNg +KCLjsZWDzYWm3S8P52dSbrsvhXz1SnPnxT7AvSESBT/8twNJAlvIJebiVDj1eYeM +HVOyToV7BjjHLPj4sHKNJeV3UvQDHEimUF+IIDBu8oJDqz2XhOdT+yHBTw8imoa4 +WSr2Rz0ZiC3oheGe7IUIarFsNMkd7EgrO3jtZsSOeWmD3n+M +-----END CERTIFICATE----- + +QuoVadis Root CA 3 G3 +# Fingerprint (SHA1): 48:12:BD:92:3C:A8:C4:39:06:E7:30:6D:27:96:E6:A4:CF:22:2E:7D +MUST_VERIFY_TRUST: CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +================================================ +MD5 Fingerprint=DF:7D:B9:AD:54:6F:68:A1:DF:89:57:03:97:43:B0:D7 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 2e:f5:9b:02:28:a7:db:7a:ff:d5:a3:a9:ee:bd:03:a0:cf:12:6a:1d + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=BM, O=QuoVadis Limited, CN=QuoVadis Root CA 3 G3 + Validity + Not Before: Jan 12 20:26:32 2012 GMT + Not After : Jan 12 20:26:32 2042 GMT + Subject: C=BM, O=QuoVadis Limited, CN=QuoVadis Root CA 3 G3 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:b3:cb:0e:10:67:8e:ea:14:97:a7:32:2a:0a:56: + 36:7f:68:4c:c7:b3:6f:3a:23:14:91:ff:19:7f:a5: + ca:ac:ee:b3:76:9d:7a:e9:8b:1b:ab:6b:31:db:fa: + 0b:53:4c:af:c5:a5:1a:79:3c:8a:4c:ff:ac:df:25: + de:4e:d9:82:32:0b:44:de:ca:db:8c:ac:a3:6e:16: + 83:3b:a6:64:4b:32:89:fb:16:16:38:7e:eb:43:e2: + d3:74:4a:c2:62:0a:73:0a:dd:49:b3:57:d2:b0:0a: + 85:9d:71:3c:de:a3:cb:c0:32:f3:01:39:20:43:1b: + 35:d1:53:b3:b1:ee:c5:93:69:82:3e:16:b5:28:46: + a1:de:ea:89:09:ed:43:b8:05:46:8a:86:f5:59:47: + be:1b:6f:01:21:10:b9:fd:a9:d2:28:ca:10:39:09: + ca:13:36:cf:9c:ad:ad:40:74:79:2b:02:3f:34:ff: + fa:20:69:7d:d3:ee:61:f5:ba:b3:e7:30:d0:37:23: + 86:72:61:45:29:48:59:68:6f:77:a6:2e:81:be:07: + 4d:6f:af:ce:c4:45:13:91:14:70:06:8f:1f:9f:f8: + 87:69:b1:0e:ef:c3:89:19:eb:ea:1c:61:fc:7a:6c: + 8a:dc:d6:03:0b:9e:26:ba:12:dd:d4:54:39:ab:26: + a3:33:ea:75:81:da:2d:cd:0f:4f:e4:03:d1:ef:15: + 97:1b:6b:90:c5:02:90:93:66:02:21:b1:47:de:8b: + 9a:4a:80:b9:55:8f:b5:a2:2f:c0:d6:33:67:da:7e: + c4:a7:b4:04:44:eb:47:fb:e6:58:b9:f7:0c:f0:7b: + 2b:b1:c0:70:29:c3:40:62:2d:3b:48:69:dc:23:3c: + 48:eb:7b:09:79:a9:6d:da:a8:30:98:cf:80:72:03: + 88:a6:5b:46:ae:72:79:7c:08:03:21:65:ae:b7:e1: + 1c:a5:b1:2a:a2:31:de:66:04:f7:c0:74:e8:71:de: + ff:3d:59:cc:96:26:12:8b:85:95:57:1a:ab:6b:75: + 0b:44:3d:11:28:3c:7b:61:b7:e2:8f:67:4f:e5:ec: + 3c:4c:60:80:69:57:38:1e:01:5b:8d:55:e8:c7:df: + c0:cc:77:23:34:49:75:7c:f6:98:11:eb:2d:de:ed: + 41:2e:14:05:02:7f:e0:fe:20:eb:35:e7:11:ac:22: + ce:57:3d:de:c9:30:6d:10:03:85:cd:f1:ff:8c:16: + b5:c1:b2:3e:88:6c:60:7f:90:4f:95:f7:f6:2d:ad: + 01:39:07:04:fa:75:80:7d:bf:49:50:ed:ef:c9:c4: + 7c:1c:eb:80:7e:db:b6:d0:dd:13:fe:c9:d3:9c:d7: + b2:97:a9 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + C6:17:D0:BC:A8:EA:02:43:F2:1B:06:99:5D:2B:90:20:B9:D7:9C:E4 + Signature Algorithm: sha256WithRSAEncryption + 34:61:d9:56:b5:12:87:55:4d:dd:a3:35:31:46:bb:a4:07:72: + bc:5f:61:62:e8:a5:fb:0b:37:b1:3c:b6:b3:fa:29:9d:7f:02: + f5:a4:c9:a8:93:b7:7a:71:28:69:8f:73:e1:52:90:da:d5:be: + 3a:e5:b7:76:6a:56:80:21:df:5d:e6:e9:3a:9e:e5:3e:f6:a2: + 69:c7:2a:0a:b0:18:47:dc:20:70:7d:52:a3:3e:59:7c:c1:ba: + c9:c8:15:40:61:ca:72:d6:70:ac:d2:b7:f0:1c:e4:86:29:f0: + ce:ef:68:63:d0:b5:20:8a:15:61:9a:7e:86:98:b4:c9:c2:76: + fb:cc:ba:30:16:cc:a3:61:c6:74:13:e5:6b:ef:a3:15:ea:03: + fe:13:8b:64:e4:d3:c1:d2:e8:84:fb:49:d1:10:4d:79:66:eb: + aa:fd:f4:8d:31:1e:70:14:ad:dc:de:67:13:4c:81:15:61:bc: + b7:d9:91:77:71:19:81:60:bb:f0:58:a5:b5:9c:0b:f7:8f:22: + 55:27:c0:4b:01:6d:3b:99:0d:d4:1d:9b:63:67:2f:d0:ee:0d: + ca:66:bc:94:4f:a6:ad:ed:fc:ee:63:ac:57:3f:65:25:cf:b2: + 86:8f:d0:08:ff:b8:76:14:6e:de:e5:27:ec:ab:78:b5:53:b9: + b6:3f:e8:20:f9:d2:a8:be:61:46:ca:87:8c:84:f3:f9:f1:a0: + 68:9b:22:1e:81:26:9b:10:04:91:71:c0:06:1f:dc:a0:d3:b9: + 56:a7:e3:98:2d:7f:83:9d:df:8c:2b:9c:32:8e:32:94:f0:01: + 3c:22:2a:9f:43:c2:2e:c3:98:39:07:38:7b:fc:5e:00:42:1f: + f3:32:26:79:83:84:f6:e5:f0:c1:51:12:c0:0b:1e:04:23:0c: + 54:a5:4c:2f:49:c5:4a:d1:b6:6e:60:0d:6b:fc:6b:8b:85:24: + 64:b7:89:0e:ab:25:47:5b:3c:cf:7e:49:bd:c7:e9:0a:c6:da: + f7:7e:0e:17:08:d3:48:97:d0:71:92:f0:0f:39:3e:34:6a:1c: + 7d:d8:f2:22:ae:bb:69:f4:33:b4:a6:48:55:d1:0f:0e:26:e8: + ec:b6:0b:2d:a7:85:35:cd:fd:59:c8:9f:d1:cd:3e:5a:29:34: + b9:3d:84:ce:b1:65:d4:59:91:91:56:75:21:c1:77:9e:f9:7a: + e1:60:9d:d3:ad:04:18:f4:7c:eb:5e:93:8f:53:4a:22:29:f8: + 48:2b:3e:4d:86:ac:5b:7f:cb:06:99:59:60:d8:58:65:95:8d: + 44:d1:f7:7f:7e:27:7f:7d:ae:80:f5:07:4c:b6:3e:9c:71:54: + 99:04:4b:fd:58:f9:98:f4 +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQEL +BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc +BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMyBHMzAeFw0xMjAxMTIyMDI2MzJaFw00 +MjAxMTIyMDI2MzJaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDMgRzMwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQCzyw4QZ47qFJenMioKVjZ/aEzHs286IxSR +/xl/pcqs7rN2nXrpixurazHb+gtTTK/FpRp5PIpM/6zfJd5O2YIyC0TeytuMrKNu +FoM7pmRLMon7FhY4futD4tN0SsJiCnMK3UmzV9KwCoWdcTzeo8vAMvMBOSBDGzXR +U7Ox7sWTaYI+FrUoRqHe6okJ7UO4BUaKhvVZR74bbwEhELn9qdIoyhA5CcoTNs+c +ra1AdHkrAj80//ogaX3T7mH1urPnMNA3I4ZyYUUpSFlob3emLoG+B01vr87ERROR +FHAGjx+f+IdpsQ7vw4kZ6+ocYfx6bIrc1gMLnia6Et3UVDmrJqMz6nWB2i3ND0/k +A9HvFZcba5DFApCTZgIhsUfei5pKgLlVj7WiL8DWM2fafsSntARE60f75li59wzw +eyuxwHApw0BiLTtIadwjPEjrewl5qW3aqDCYz4ByA4imW0aucnl8CAMhZa634Ryl +sSqiMd5mBPfAdOhx3v89WcyWJhKLhZVXGqtrdQtEPREoPHtht+KPZ0/l7DxMYIBp +VzgeAVuNVejH38DMdyM0SXV89pgR6y3e7UEuFAUCf+D+IOs15xGsIs5XPd7JMG0Q +A4XN8f+MFrXBsj6IbGB/kE+V9/YtrQE5BwT6dYB9v0lQ7e/JxHwc64B+27bQ3RP+ +ydOc17KXqQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQUxhfQvKjqAkPyGwaZXSuQILnXnOQwDQYJKoZIhvcNAQELBQAD +ggIBADRh2Va1EodVTd2jNTFGu6QHcrxfYWLopfsLN7E8trP6KZ1/AvWkyaiTt3px +KGmPc+FSkNrVvjrlt3ZqVoAh313m6Tqe5T72omnHKgqwGEfcIHB9UqM+WXzBusnI +FUBhynLWcKzSt/Ac5IYp8M7vaGPQtSCKFWGafoaYtMnCdvvMujAWzKNhxnQT5Wvv +oxXqA/4Ti2Tk08HS6IT7SdEQTXlm66r99I0xHnAUrdzeZxNMgRVhvLfZkXdxGYFg +u/BYpbWcC/ePIlUnwEsBbTuZDdQdm2NnL9DuDcpmvJRPpq3t/O5jrFc/ZSXPsoaP +0Aj/uHYUbt7lJ+yreLVTubY/6CD50qi+YUbKh4yE8/nxoGibIh6BJpsQBJFxwAYf +3KDTuVan45gtf4Od34wrnDKOMpTwATwiKp9Dwi7DmDkHOHv8XgBCH/MyJnmDhPbl +8MFREsALHgQjDFSlTC9JxUrRtm5gDWv8a4uFJGS3iQ6rJUdbPM9+Sb3H6QrG2vd+ +DhcI00iX0HGS8A85PjRqHH3Y8iKuu2n0M7SmSFXRDw4m6Oy2Cy2nhTXN/VnIn9HN +PlopNLk9hM6xZdRZkZFWdSHBd575euFgndOtBBj0fOtek49TSiIp+EgrPk2GrFt/ +ywaZWWDYWGWVjUTR939+J399roD1B0y2PpxxVJkES/1Y+Zj0 +-----END CERTIFICATE----- + +DigiCert Assured ID Root G2 +# Fingerprint (SHA1): A1:4B:48:D9:43:EE:0A:0E:40:90:4F:3C:E0:A4:C0:91:93:51:5D:3F +MUST_VERIFY_TRUST: CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +================================================ +MD5 Fingerprint=92:38:B9:F8:63:24:82:65:2C:57:33:E6:FE:81:8F:9D +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 0b:93:1c:3a:d6:39:67:ea:67:23:bf:c3:af:9a:f4:4b + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Assured ID Root G2 + Validity + Not Before: Aug 1 12:00:00 2013 GMT + Not After : Jan 15 12:00:00 2038 GMT + Subject: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Assured ID Root G2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:d9:e7:28:2f:52:3f:36:72:49:88:93:34:f3:f8: + 6a:1e:31:54:80:9f:ad:54:41:b5:47:df:96:a8:d4: + af:80:2d:b9:0a:cf:75:fd:89:a5:7d:24:fa:e3:22: + 0c:2b:bc:95:17:0b:33:bf:19:4d:41:06:90:00:bd: + 0c:4d:10:fe:07:b5:e7:1c:6e:22:55:31:65:97:bd: + d3:17:d2:1e:62:f3:db:ea:6c:50:8c:3f:84:0c:96: + cf:b7:cb:03:e0:ca:6d:a1:14:4c:1b:89:dd:ed:00: + b0:52:7c:af:91:6c:b1:38:13:d1:e9:12:08:c0:00: + b0:1c:2b:11:da:77:70:36:9b:ae:ce:79:87:dc:82: + 70:e6:09:74:70:55:69:af:a3:68:9f:bf:dd:b6:79: + b3:f2:9d:70:29:55:f4:ab:ff:95:61:f3:c9:40:6f: + 1d:d1:be:93:bb:d3:88:2a:bb:9d:bf:72:5a:56:71: + 3b:3f:d4:f3:d1:0a:fe:28:ef:a3:ee:d9:99:af:03: + d3:8f:60:b7:f2:92:a1:b1:bd:89:89:1f:30:cd:c3: + a6:2e:62:33:ae:16:02:77:44:5a:e7:81:0a:3c:a7: + 44:2e:79:b8:3f:04:bc:5c:a0:87:e1:1b:af:51:8e: + cd:ec:2c:fa:f8:fe:6d:f0:3a:7c:aa:8b:e4:67:95: + 31:8d + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + CE:C3:4A:B9:99:55:F2:B8:DB:60:BF:A9:7E:BD:56:B5:97:36:A7:D6 + Signature Algorithm: sha256WithRSAEncryption + ca:a5:55:8c:e3:c8:41:6e:69:27:a7:75:11:ef:3c:86:36:6f: + d2:9d:c6:78:38:1d:69:96:a2:92:69:2e:38:6c:9b:7d:04:d4: + 89:a5:b1:31:37:8a:c9:21:cc:ab:6c:cd:8b:1c:9a:d6:bf:48: + d2:32:66:c1:8a:c0:f3:2f:3a:ef:c0:e3:d4:91:86:d1:50:e3: + 03:db:73:77:6f:4a:39:53:ed:de:26:c7:b5:7d:af:2b:42:d1: + 75:62:e3:4a:2b:02:c7:50:4b:e0:69:e2:96:6c:0e:44:66:10: + 44:8f:ad:05:eb:f8:79:ac:a6:1b:e8:37:34:9d:53:c9:61:aa: + a2:52:af:4a:70:16:86:c2:3a:c8:b1:13:70:36:d8:cf:ee:f4: + 0a:34:d5:5b:4c:fd:07:9c:a2:ba:d9:01:72:5c:f3:4d:c1:dd: + 0e:b1:1c:0d:c4:63:be:ad:f4:14:fb:89:ec:a2:41:0e:4c:cc: + c8:57:40:d0:6e:03:aa:cd:0c:8e:89:99:99:6c:f0:3c:30:af: + 38:df:6f:bc:a3:be:29:20:27:ab:74:ff:13:22:78:de:97:52: + 55:1e:83:b5:54:20:03:ee:ae:c0:4f:56:de:37:cc:c3:7f:aa: + 04:27:bb:d3:77:b8:62:db:17:7c:9c:28:22:13:73:6c:cf:26: + f5:8a:29:e7 +-----BEGIN CERTIFICATE----- +MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBl +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv +b3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl +cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSA +n61UQbVH35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4Htecc +biJVMWWXvdMX0h5i89vqbFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9Hp +EgjAALAcKxHad3A2m67OeYfcgnDmCXRwVWmvo2ifv922ebPynXApVfSr/5Vh88lA +bx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OPYLfykqGxvYmJHzDNw6Yu +YjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+RnlTGNAgMB +AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQW +BBTOw0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPI +QW5pJ6d1Ee88hjZv0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I +0jJmwYrA8y8678Dj1JGG0VDjA9tzd29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4Gni +lmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAWhsI6yLETcDbYz+70CjTVW0z9 +B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0MjomZmWzwPDCv +ON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo +IhNzbM8m9Yop5w== +-----END CERTIFICATE----- + +DigiCert Assured ID Root G3 +# Fingerprint (SHA1): F5:17:A2:4F:9A:48:C6:C9:F8:A2:00:26:9F:DC:0F:48:2C:AB:30:89 +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +MUST_VERIFY_TRUST: CODE_SIGNING +================================================ +MD5 Fingerprint=7C:7F:65:31:0C:81:DF:8D:BA:3E:99:E2:5C:AD:6E:FB +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 0b:a1:5a:fa:1d:df:a0:b5:49:44:af:cd:24:a0:6c:ec + Signature Algorithm: ecdsa-with-SHA384 + Issuer: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Assured ID Root G3 + Validity + Not Before: Aug 1 12:00:00 2013 GMT + Not After : Jan 15 12:00:00 2038 GMT + Subject: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Assured ID Root G3 + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (384 bit) + pub: + 04:19:e7:bc:ac:44:65:ed:cd:b8:3f:58:fb:8d:b1: + 57:a9:44:2d:05:15:f2:ef:0b:ff:10:74:9f:b5:62: + 52:5f:66:7e:1f:e5:dc:1b:45:79:0b:cc:c6:53:0a: + 9d:8d:5d:02:d9:a9:59:de:02:5a:f6:95:2a:0e:8d: + 38:4a:8a:49:c6:bc:c6:03:38:07:5f:55:da:7e:09: + 6e:e2:7f:5e:d0:45:20:0f:59:76:10:d6:a0:24:f0: + 2d:de:36:f2:6c:29:39 + ASN1 OID: secp384r1 + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + CB:D0:BD:A9:E1:98:05:51:A1:4D:37:A2:83:79:CE:8D:1D:2A:E4:84 + Signature Algorithm: ecdsa-with-SHA384 + 30:64:02:30:25:a4:81:45:02:6b:12:4b:75:74:4f:c8:23:e3: + 70:f2:75:72:de:7c:89:f0:cf:91:72:61:9e:5e:10:92:59:56: + b9:83:c7:10:e7:38:e9:58:26:36:7d:d5:e4:34:86:39:02:30: + 7c:36:53:f0:30:e5:62:63:3a:99:e2:b6:a3:3b:9b:34:fa:1e: + da:10:92:71:5e:91:13:a7:dd:a4:6e:92:cc:32:d6:f5:21:66: + c7:2f:ea:96:63:6a:65:45:92:95:01:b4 +-----BEGIN CERTIFICATE----- +MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQsw +CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu +ZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3Qg +RzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQGEwJV +UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu +Y29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQBgcq +hkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJf +Zn4f5dwbRXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17Q +RSAPWXYQ1qAk8C3eNvJsKTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ +BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgFUaFNN6KDec6NHSrkhDAKBggqhkjOPQQD +AwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5FyYZ5eEJJZVrmDxxDnOOlY +JjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy1vUhZscv +6pZjamVFkpUBtA== +-----END CERTIFICATE----- + +DigiCert Global Root G2 +# Fingerprint (SHA1): DF:3C:24:F9:BF:D6:66:76:1B:26:80:73:FE:06:D1:CC:8D:4F:82:A4 +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +MUST_VERIFY_TRUST: CODE_SIGNING +================================================ +MD5 Fingerprint=E4:A6:8A:C8:54:AC:52:42:46:0A:FD:72:48:1B:2A:44 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 03:3a:f1:e6:a7:11:a9:a0:bb:28:64:b1:1d:09:fa:e5 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Global Root G2 + Validity + Not Before: Aug 1 12:00:00 2013 GMT + Not After : Jan 15 12:00:00 2038 GMT + Subject: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Global Root G2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:bb:37:cd:34:dc:7b:6b:c9:b2:68:90:ad:4a:75: + ff:46:ba:21:0a:08:8d:f5:19:54:c9:fb:88:db:f3: + ae:f2:3a:89:91:3c:7a:e6:ab:06:1a:6b:cf:ac:2d: + e8:5e:09:24:44:ba:62:9a:7e:d6:a3:a8:7e:e0:54: + 75:20:05:ac:50:b7:9c:63:1a:6c:30:dc:da:1f:19: + b1:d7:1e:de:fd:d7:e0:cb:94:83:37:ae:ec:1f:43: + 4e:dd:7b:2c:d2:bd:2e:a5:2f:e4:a9:b8:ad:3a:d4: + 99:a4:b6:25:e9:9b:6b:00:60:92:60:ff:4f:21:49: + 18:f7:67:90:ab:61:06:9c:8f:f2:ba:e9:b4:e9:92: + 32:6b:b5:f3:57:e8:5d:1b:cd:8c:1d:ab:95:04:95: + 49:f3:35:2d:96:e3:49:6d:dd:77:e3:fb:49:4b:b4: + ac:55:07:a9:8f:95:b3:b4:23:bb:4c:6d:45:f0:f6: + a9:b2:95:30:b4:fd:4c:55:8c:27:4a:57:14:7c:82: + 9d:cd:73:92:d3:16:4a:06:0c:8c:50:d1:8f:1e:09: + be:17:a1:e6:21:ca:fd:83:e5:10:bc:83:a5:0a:c4: + 67:28:f6:73:14:14:3d:46:76:c3:87:14:89:21:34: + 4d:af:0f:45:0c:a6:49:a1:ba:bb:9c:c5:b1:33:83: + 29:85 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 4E:22:54:20:18:95:E6:E3:6E:E6:0F:FA:FA:B9:12:ED:06:17:8F:39 + Signature Algorithm: sha256WithRSAEncryption + 60:67:28:94:6f:0e:48:63:eb:31:dd:ea:67:18:d5:89:7d:3c: + c5:8b:4a:7f:e9:be:db:2b:17:df:b0:5f:73:77:2a:32:13:39: + 81:67:42:84:23:f2:45:67:35:ec:88:bf:f8:8f:b0:61:0c:34: + a4:ae:20:4c:84:c6:db:f8:35:e1:76:d9:df:a6:42:bb:c7:44: + 08:86:7f:36:74:24:5a:da:6c:0d:14:59:35:bd:f2:49:dd:b6: + 1f:c9:b3:0d:47:2a:3d:99:2f:bb:5c:bb:b5:d4:20:e1:99:5f: + 53:46:15:db:68:9b:f0:f3:30:d5:3e:31:e2:8d:84:9e:e3:8a: + da:da:96:3e:35:13:a5:5f:f0:f9:70:50:70:47:41:11:57:19: + 4e:c0:8f:ae:06:c4:95:13:17:2f:1b:25:9f:75:f2:b1:8e:99: + a1:6f:13:b1:41:71:fe:88:2a:c8:4f:10:20:55:d7:f3:14:45: + e5:e0:44:f4:ea:87:95:32:93:0e:fe:53:46:fa:2c:9d:ff:8b: + 22:b9:4b:d9:09:45:a4:de:a4:b8:9a:58:dd:1b:7d:52:9f:8e: + 59:43:88:81:a4:9e:26:d5:6f:ad:dd:0d:c6:37:7d:ed:03:92: + 1b:e5:77:5f:76:ee:3c:8d:c4:5d:56:5b:a2:d9:66:6e:b3:35: + 37:e5:32:b6 +-----BEGIN CERTIFICATE----- +MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH +MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI +2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx +1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ +q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz +tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ +vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP +BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV +5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY +1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4 +NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG +Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91 +8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe +pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl +MrY= +-----END CERTIFICATE----- + +DigiCert Global Root G3 +# Fingerprint (SHA1): 7E:04:DE:89:6A:3E:66:6D:00:E6:87:D3:3F:FA:D9:3B:E8:3D:34:9E +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +MUST_VERIFY_TRUST: CODE_SIGNING +================================================ +MD5 Fingerprint=F5:5D:A4:50:A5:FB:28:7E:1E:0F:0D:CC:96:57:56:CA +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 05:55:56:bc:f2:5e:a4:35:35:c3:a4:0f:d5:ab:45:72 + Signature Algorithm: ecdsa-with-SHA384 + Issuer: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Global Root G3 + Validity + Not Before: Aug 1 12:00:00 2013 GMT + Not After : Jan 15 12:00:00 2038 GMT + Subject: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Global Root G3 + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (384 bit) + pub: + 04:dd:a7:d9:bb:8a:b8:0b:fb:0b:7f:21:d2:f0:be: + be:73:f3:33:5d:1a:bc:34:ea:de:c6:9b:bc:d0:95: + f6:f0:cc:d0:0b:ba:61:5b:51:46:7e:9e:2d:9f:ee: + 8e:63:0c:17:ec:07:70:f5:cf:84:2e:40:83:9c:e8: + 3f:41:6d:3b:ad:d3:a4:14:59:36:78:9d:03:43:ee: + 10:13:6c:72:de:ae:88:a7:a1:6b:b5:43:ce:67:dc: + 23:ff:03:1c:a3:e2:3e + ASN1 OID: secp384r1 + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + B3:DB:48:A4:F9:A1:C5:D8:AE:36:41:CC:11:63:69:62:29:BC:4B:C6 + Signature Algorithm: ecdsa-with-SHA384 + 30:65:02:31:00:ad:bc:f2:6c:3f:12:4a:d1:2d:39:c3:0a:09: + 97:73:f4:88:36:8c:88:27:bb:e6:88:8d:50:85:a7:63:f9:9e: + 32:de:66:93:0f:f1:cc:b1:09:8f:dd:6c:ab:fa:6b:7f:a0:02: + 30:39:66:5b:c2:64:8d:b8:9e:50:dc:a8:d5:49:a2:ed:c7:dc: + d1:49:7f:17:01:b8:c8:86:8f:4e:8c:88:2b:a8:9a:a9:8a:c5: + d1:00:bd:f8:54:e2:9a:e5:5b:7c:b3:27:17 +-----BEGIN CERTIFICATE----- +MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQsw +CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu +ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe +Fw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVTMRUw +EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x +IDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0CAQYF +K4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FG +fp4tn+6OYwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPO +Z9wj/wMco+I+o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAd +BgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNpYim8S8YwCgYIKoZIzj0EAwMDaAAwZQIx +AK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y3maTD/HMsQmP3Wyr+mt/ +oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34VOKa5Vt8 +sycX +-----END CERTIFICATE----- + +DigiCert Trusted Root G4 +# Fingerprint (SHA1): DD:FB:16:CD:49:31:C9:73:A2:03:7D:3F:C8:3A:4D:7D:77:5D:05:E4 +MUST_VERIFY_TRUST: CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +================================================ +MD5 Fingerprint=78:F2:FC:AA:60:1F:2F:B4:EB:C9:37:BA:53:2E:75:49 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 05:9b:1b:57:9e:8e:21:32:e2:39:07:bd:a7:77:75:5c + Signature Algorithm: sha384WithRSAEncryption + Issuer: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Trusted Root G4 + Validity + Not Before: Aug 1 12:00:00 2013 GMT + Not After : Jan 15 12:00:00 2038 GMT + Subject: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Trusted Root G4 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:bf:e6:90:73:68:de:bb:e4:5d:4a:3c:30:22:30: + 69:33:ec:c2:a7:25:2e:c9:21:3d:f2:8a:d8:59:c2: + e1:29:a7:3d:58:ab:76:9a:cd:ae:7b:1b:84:0d:c4: + 30:1f:f3:1b:a4:38:16:eb:56:c6:97:6d:1d:ab:b2: + 79:f2:ca:11:d2:e4:5f:d6:05:3c:52:0f:52:1f:c6: + 9e:15:a5:7e:be:9f:a9:57:16:59:55:72:af:68:93: + 70:c2:b2:ba:75:99:6a:73:32:94:d1:10:44:10:2e: + df:82:f3:07:84:e6:74:3b:6d:71:e2:2d:0c:1b:ee: + 20:d5:c9:20:1d:63:29:2d:ce:ec:5e:4e:c8:93:f8: + 21:61:9b:34:eb:05:c6:5e:ec:5b:1a:bc:eb:c9:cf: + cd:ac:34:40:5f:b1:7a:66:ee:77:c8:48:a8:66:57: + 57:9f:54:58:8e:0c:2b:b7:4f:a7:30:d9:56:ee:ca: + 7b:5d:e3:ad:c9:4f:5e:e5:35:e7:31:cb:da:93:5e: + dc:8e:8f:80:da:b6:91:98:40:90:79:c3:78:c7:b6: + b1:c4:b5:6a:18:38:03:10:8d:d8:d4:37:a4:2e:05: + 7d:88:f5:82:3e:10:91:70:ab:55:82:41:32:d7:db: + 04:73:2a:6e:91:01:7c:21:4c:d4:bc:ae:1b:03:75: + 5d:78:66:d9:3a:31:44:9a:33:40:bf:08:d7:5a:49: + a4:c2:e6:a9:a0:67:dd:a4:27:bc:a1:4f:39:b5:11: + 58:17:f7:24:5c:46:8f:64:f7:c1:69:88:76:98:76: + 3d:59:5d:42:76:87:89:97:69:7a:48:f0:e0:a2:12: + 1b:66:9a:74:ca:de:4b:1e:e7:0e:63:ae:e6:d4:ef: + 92:92:3a:9e:3d:dc:00:e4:45:25:89:b6:9a:44:19: + 2b:7e:c0:94:b4:d2:61:6d:eb:33:d9:c5:df:4b:04: + 00:cc:7d:1c:95:c3:8f:f7:21:b2:b2:11:b7:bb:7f: + f2:d5:8c:70:2c:41:60:aa:b1:63:18:44:95:1a:76: + 62:7e:f6:80:b0:fb:e8:64:a6:33:d1:89:07:e1:bd: + b7:e6:43:a4:18:b8:a6:77:01:e1:0f:94:0c:21:1d: + b2:54:29:25:89:6c:e5:0e:52:51:47:74:be:26:ac: + b6:41:75:de:7a:ac:5f:8d:3f:c9:bc:d3:41:11:12: + 5b:e5:10:50:eb:31:c5:ca:72:16:22:09:df:7c:4c: + 75:3f:63:ec:21:5f:c4:20:51:6b:6f:b1:ab:86:8b: + 4f:c2:d6:45:5f:9d:20:fc:a1:1e:c5:c0:8f:a2:b1: + 7e:0a:26:99:f5:e4:69:2f:98:1d:2d:f5:d9:a9:b2: + 1d:e5:1b + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + EC:D7:E3:82:D2:71:5D:64:4C:DF:2E:67:3F:E7:BA:98:AE:1C:0F:4F + Signature Algorithm: sha384WithRSAEncryption + bb:61:d9:7d:a9:6c:be:17:c4:91:1b:c3:a1:a2:00:8d:e3:64: + 68:0f:56:cf:77:ae:70:f9:fd:9a:4a:99:b9:c9:78:5c:0c:0c: + 5f:e4:e6:14:29:56:0b:36:49:5d:44:63:e0:ad:9c:96:18:66: + 1b:23:0d:3d:79:e9:6d:6b:d6:54:f8:d2:3c:c1:43:40:ae:1d: + 50:f5:52:fc:90:3b:bb:98:99:69:6b:c7:c1:a7:a8:68:a4:27: + dc:9d:f9:27:ae:30:85:b9:f6:67:4d:3a:3e:8f:59:39:22:53: + 44:eb:c8:5d:03:ca:ed:50:7a:7d:62:21:0a:80:c8:73:66:d1: + a0:05:60:5f:e8:a5:b4:a7:af:a8:f7:6d:35:9c:7c:5a:8a:d6: + a2:38:99:f3:78:8b:f4:4d:d2:20:0b:de:04:ee:8c:9b:47:81: + 72:0d:c0:14:32:ef:30:59:2e:ae:e0:71:f2:56:e4:6a:97:6f: + 92:50:6d:96:8d:68:7a:9a:b2:36:14:7a:06:f2:24:b9:09:11: + 50:d7:08:b1:b8:89:7a:84:23:61:42:29:e5:a3:cd:a2:20:41: + d7:d1:9c:64:d9:ea:26:a1:8b:14:d7:4c:19:b2:50:41:71:3d: + 3f:4d:70:23:86:0c:4a:dc:81:d2:cc:32:94:84:0d:08:09:97: + 1c:4f:c0:ee:6b:20:74:30:d2:e0:39:34:10:85:21:15:01:08: + e8:55:32:de:71:49:d9:28:17:50:4d:e6:be:4d:d1:75:ac:d0: + ca:fb:41:b8:43:a5:aa:d3:c3:05:44:4f:2c:36:9b:e2:fa:e2: + 45:b8:23:53:6c:06:6f:67:55:7f:46:b5:4c:3f:6e:28:5a:79: + 26:d2:a4:a8:62:97:d2:1e:e2:ed:4a:8b:bc:1b:fd:47:4a:0d: + df:67:66:7e:b2:5b:41:d0:3b:e4:f4:3b:f4:04:63:e9:ef:c2: + 54:00:51:a0:8a:2a:c9:ce:78:cc:d5:ea:87:04:18:b3:ce:af: + 49:88:af:f3:92:99:b6:b3:e6:61:0f:d2:85:00:e7:50:1a:e4: + 1b:95:9d:19:a1:b9:9c:b1:9b:b1:00:1e:ef:d0:0f:4f:42:6c: + c9:0a:bc:ee:43:fa:3a:71:a5:c8:4d:26:a5:35:fd:89:5d:bc: + 85:62:1d:32:d2:a0:2b:54:ed:9a:57:c1:db:fa:10:cf:19:b7: + 8b:4a:1b:8f:01:b6:27:95:53:e8:b6:89:6d:5b:bc:68:d4:23: + e8:8b:51:a2:56:f9:f0:a6:80:a0:d6:1e:b3:bc:0f:0f:53:75: + 29:aa:ea:13:77:e4:de:8c:81:21:ad:07:10:47:11:ad:87:3d: + 07:d1:75:bc:cf:f3:66:7e +-----BEGIN CERTIFICATE----- +MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBi +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3Qg +RzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBiMQswCQYDVQQGEwJV +UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu +Y29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3y +ithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1If +xp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDV +ySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfISKhmV1efVFiO +DCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jHtrHEtWoYOAMQ +jdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6MUSaM0C/ +CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCi +EhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADM +fRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QY +uKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXK +chYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4KJpn15GkvmB0t +9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +hjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD +ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2 +SV1EY+CtnJYYZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd ++SeuMIW59mdNOj6PWTkiU0TryF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWc +fFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy7zBZLq7gcfJW5GqXb5JQbZaNaHqa +sjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iahixTXTBmyUEFxPT9N +cCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN5r5N +0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie +4u1Ki7wb/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mI +r/OSmbaz5mEP0oUA51Aa5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1 +/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tKG48BtieVU+i2iW1bvGjUI+iLUaJW+fCm +gKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+ +-----END CERTIFICATE----- + +COMODO RSA Certification Authority +# Fingerprint (SHA1): AF:E5:D2:44:A8:D1:19:42:30:FF:47:9F:E2:F8:97:BB:CD:7A:8C:B4 +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +MUST_VERIFY_TRUST: CODE_SIGNING +================================================ +MD5 Fingerprint=1B:31:B0:71:40:36:CC:14:36:91:AD:C4:3E:FD:EC:18 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 4c:aa:f9:ca:db:63:6f:e0:1f:f7:4e:d8:5b:03:86:9d + Signature Algorithm: sha384WithRSAEncryption + Issuer: C=GB, ST=Greater Manchester, L=Salford, O=COMODO CA Limited, CN=COMODO RSA Certification Authority + Validity + Not Before: Jan 19 00:00:00 2010 GMT + Not After : Jan 18 23:59:59 2038 GMT + Subject: C=GB, ST=Greater Manchester, L=Salford, O=COMODO CA Limited, CN=COMODO RSA Certification Authority + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:91:e8:54:92:d2:0a:56:b1:ac:0d:24:dd:c5:cf: + 44:67:74:99:2b:37:a3:7d:23:70:00:71:bc:53:df: + c4:fa:2a:12:8f:4b:7f:10:56:bd:9f:70:72:b7:61: + 7f:c9:4b:0f:17:a7:3d:e3:b0:04:61:ee:ff:11:97: + c7:f4:86:3e:0a:fa:3e:5c:f9:93:e6:34:7a:d9:14: + 6b:e7:9c:b3:85:a0:82:7a:76:af:71:90:d7:ec:fd: + 0d:fa:9c:6c:fa:df:b0:82:f4:14:7e:f9:be:c4:a6: + 2f:4f:7f:99:7f:b5:fc:67:43:72:bd:0c:00:d6:89: + eb:6b:2c:d3:ed:8f:98:1c:14:ab:7e:e5:e3:6e:fc: + d8:a8:e4:92:24:da:43:6b:62:b8:55:fd:ea:c1:bc: + 6c:b6:8b:f3:0e:8d:9a:e4:9b:6c:69:99:f8:78:48: + 30:45:d5:ad:e1:0d:3c:45:60:fc:32:96:51:27:bc: + 67:c3:ca:2e:b6:6b:ea:46:c7:c7:20:a0:b1:1f:65: + de:48:08:ba:a4:4e:a9:f2:83:46:37:84:eb:e8:cc: + 81:48:43:67:4e:72:2a:9b:5c:bd:4c:1b:28:8a:5c: + 22:7b:b4:ab:98:d9:ee:e0:51:83:c3:09:46:4e:6d: + 3e:99:fa:95:17:da:7c:33:57:41:3c:8d:51:ed:0b: + b6:5c:af:2c:63:1a:df:57:c8:3f:bc:e9:5d:c4:9b: + af:45:99:e2:a3:5a:24:b4:ba:a9:56:3d:cf:6f:aa: + ff:49:58:be:f0:a8:ff:f4:b8:ad:e9:37:fb:ba:b8: + f4:0b:3a:f9:e8:43:42:1e:89:d8:84:cb:13:f1:d9: + bb:e1:89:60:b8:8c:28:56:ac:14:1d:9c:0a:e7:71: + eb:cf:0e:dd:3d:a9:96:a1:48:bd:3c:f7:af:b5:0d: + 22:4c:c0:11:81:ec:56:3b:f6:d3:a2:e2:5b:b7:b2: + 04:22:52:95:80:93:69:e8:8e:4c:65:f1:91:03:2d: + 70:74:02:ea:8b:67:15:29:69:52:02:bb:d7:df:50: + 6a:55:46:bf:a0:a3:28:61:7f:70:d0:c3:a2:aa:2c: + 21:aa:47:ce:28:9c:06:45:76:bf:82:18:27:b4:d5: + ae:b4:cb:50:e6:6b:f4:4c:86:71:30:e9:a6:df:16: + 86:e0:d8:ff:40:dd:fb:d0:42:88:7f:a3:33:3a:2e: + 5c:1e:41:11:81:63:ce:18:71:6b:2b:ec:a6:8a:b7: + 31:5c:3a:6a:47:e0:c3:79:59:d6:20:1a:af:f2:6a: + 98:aa:72:bc:57:4a:d2:4b:9d:bb:10:fc:b0:4c:41: + e5:ed:1d:3d:5e:28:9d:9c:cc:bf:b3:51:da:a7:47: + e5:84:53 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + BB:AF:7E:02:3D:FA:A6:F1:3C:84:8E:AD:EE:38:98:EC:D9:32:32:D4 + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + Signature Algorithm: sha384WithRSAEncryption + 0a:f1:d5:46:84:b7:ae:51:bb:6c:b2:4d:41:14:00:93:4c:9c: + cb:e5:c0:54:cf:a0:25:8e:02:f9:fd:b0:a2:0d:f5:20:98:3c: + 13:2d:ac:56:a2:b0:d6:7e:11:92:e9:2e:ba:9e:2e:9a:72:b1: + bd:19:44:6c:61:35:a2:9a:b4:16:12:69:5a:8c:e1:d7:3e:a4: + 1a:e8:2f:03:f4:ae:61:1d:10:1b:2a:a4:8b:7a:c5:fe:05:a6: + e1:c0:d6:c8:fe:9e:ae:8f:2b:ba:3d:99:f8:d8:73:09:58:46: + 6e:a6:9c:f4:d7:27:d3:95:da:37:83:72:1c:d3:73:e0:a2:47: + 99:03:38:5d:d5:49:79:00:29:1c:c7:ec:9b:20:1c:07:24:69: + 57:78:b2:39:fc:3a:84:a0:b5:9c:7c:8d:bf:2e:93:62:27:b7: + 39:da:17:18:ae:bd:3c:09:68:ff:84:9b:3c:d5:d6:0b:03:e3: + 57:9e:14:f7:d1:eb:4f:c8:bd:87:23:b7:b6:49:43:79:85:5c: + ba:eb:92:0b:a1:c6:e8:68:a8:4c:16:b1:1a:99:0a:e8:53:2c: + 92:bb:a1:09:18:75:0c:65:a8:7b:cb:23:b7:1a:c2:28:85:c3: + 1b:ff:d0:2b:62:ef:a4:7b:09:91:98:67:8c:14:01:cd:68:06: + 6a:63:21:75:03:80:88:8a:6e:81:c6:85:f2:a9:a4:2d:e7:f4: + a5:24:10:47:83:ca:cd:f4:8d:79:58:b1:06:9b:e7:1a:2a:d9: + 9d:01:d7:94:7d:ed:03:4a:ca:f0:db:e8:a9:01:3e:f5:56:99: + c9:1e:8e:49:3d:bb:e5:09:b9:e0:4f:49:92:3d:16:82:40:cc: + cc:59:c6:e6:3a:ed:12:2e:69:3c:6c:95:b1:fd:aa:1d:7b:7f: + 86:be:1e:0e:32:46:fb:fb:13:8f:75:7f:4c:8b:4b:46:63:fe: + 00:34:40:70:c1:c3:b9:a1:dd:a6:70:e2:04:b3:41:bc:e9:80: + 91:ea:64:9c:7a:e1:22:03:a9:9c:6e:6f:0e:65:4f:6c:87:87: + 5e:f3:6e:a0:f9:75:a5:9b:40:e8:53:b2:27:9d:4a:b9:c0:77: + 21:8d:ff:87:f2:de:bc:8c:ef:17:df:b7:49:0b:d1:f2:6e:30: + 0b:1a:0e:4e:76:ed:11:fc:f5:e9:56:b2:7d:bf:c7:6d:0a:93: + 8c:a5:d0:c0:b6:1d:be:3a:4e:94:a2:d7:6e:6c:0b:c2:8a:7c: + fa:20:f3:c4:e4:e5:cd:0d:a8:cb:91:92:b1:7c:85:ec:b5:14: + 69:66:0e:82:e7:cd:ce:c8:2d:a6:51:7f:21:c1:35:53:85:06: + 4a:5d:9f:ad:bb:1b:5f:74 +-----BEGIN CERTIFICATE----- +MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCB +hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G +A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV +BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMTE5 +MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgT +EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR +Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR +6FSS0gpWsawNJN3Fz0RndJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8X +pz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZFGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC +9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+5eNu/Nio5JIk2kNrYrhV +/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pGx8cgoLEf +Zd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z ++pUX2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7w +qP/0uK3pN/u6uPQLOvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZah +SL0896+1DSJMwBGB7FY79tOi4lu3sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVIC +u9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+CGCe01a60y1Dma/RMhnEw6abf +Fobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5WdYgGq/yapiq +crxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E +FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB +/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvl +wFTPoCWOAvn9sKIN9SCYPBMtrFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM +4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+nq6PK7o9mfjYcwlYRm6mnPTXJ9OV +2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSgtZx8jb8uk2Intzna +FxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwWsRqZ +CuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiK +boHGhfKppC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmcke +jkk9u+UJueBPSZI9FoJAzMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yL +S0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHqZJx64SIDqZxubw5lT2yHh17zbqD5daWb +QOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk527RH89elWsn2/x20Kk4yl +0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7ILaZRfyHB +NVOFBkpdn627G190 +-----END CERTIFICATE----- + +USERTrust RSA Certification Authority +# Fingerprint (SHA1): 2B:8F:1B:57:33:0D:BB:A2:D0:7A:6C:51:F7:0E:E9:0D:DA:B9:AD:8E +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +MUST_VERIFY_TRUST: CODE_SIGNING +================================================ +MD5 Fingerprint=1B:FE:69:D1:91:B7:19:33:A3:72:A8:0F:E1:55:E5:B5 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 01:fd:6d:30:fc:a3:ca:51:a8:1b:bc:64:0e:35:03:2d + Signature Algorithm: sha384WithRSAEncryption + Issuer: C=US, ST=New Jersey, L=Jersey City, O=The USERTRUST Network, CN=USERTrust RSA Certification Authority + Validity + Not Before: Feb 1 00:00:00 2010 GMT + Not After : Jan 18 23:59:59 2038 GMT + Subject: C=US, ST=New Jersey, L=Jersey City, O=The USERTRUST Network, CN=USERTrust RSA Certification Authority + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:80:12:65:17:36:0e:c3:db:08:b3:d0:ac:57:0d: + 76:ed:cd:27:d3:4c:ad:50:83:61:e2:aa:20:4d:09: + 2d:64:09:dc:ce:89:9f:cc:3d:a9:ec:f6:cf:c1:dc: + f1:d3:b1:d6:7b:37:28:11:2b:47:da:39:c6:bc:3a: + 19:b4:5f:a6:bd:7d:9d:a3:63:42:b6:76:f2:a9:3b: + 2b:91:f8:e2:6f:d0:ec:16:20:90:09:3e:e2:e8:74: + c9:18:b4:91:d4:62:64:db:7f:a3:06:f1:88:18:6a: + 90:22:3c:bc:fe:13:f0:87:14:7b:f6:e4:1f:8e:d4: + e4:51:c6:11:67:46:08:51:cb:86:14:54:3f:bc:33: + fe:7e:6c:9c:ff:16:9d:18:bd:51:8e:35:a6:a7:66: + c8:72:67:db:21:66:b1:d4:9b:78:03:c0:50:3a:e8: + cc:f0:dc:bc:9e:4c:fe:af:05:96:35:1f:57:5a:b7: + ff:ce:f9:3d:b7:2c:b6:f6:54:dd:c8:e7:12:3a:4d: + ae:4c:8a:b7:5c:9a:b4:b7:20:3d:ca:7f:22:34:ae: + 7e:3b:68:66:01:44:e7:01:4e:46:53:9b:33:60:f7: + 94:be:53:37:90:73:43:f3:32:c3:53:ef:db:aa:fe: + 74:4e:69:c7:6b:8c:60:93:de:c4:c7:0c:df:e1:32: + ae:cc:93:3b:51:78:95:67:8b:ee:3d:56:fe:0c:d0: + 69:0f:1b:0f:f3:25:26:6b:33:6d:f7:6e:47:fa:73: + 43:e5:7e:0e:a5:66:b1:29:7c:32:84:63:55:89:c4: + 0d:c1:93:54:30:19:13:ac:d3:7d:37:a7:eb:5d:3a: + 6c:35:5c:db:41:d7:12:da:a9:49:0b:df:d8:80:8a: + 09:93:62:8e:b5:66:cf:25:88:cd:84:b8:b1:3f:a4: + 39:0f:d9:02:9e:eb:12:4c:95:7c:f3:6b:05:a9:5e: + 16:83:cc:b8:67:e2:e8:13:9d:cc:5b:82:d3:4c:b3: + ed:5b:ff:de:e5:73:ac:23:3b:2d:00:bf:35:55:74: + 09:49:d8:49:58:1a:7f:92:36:e6:51:92:0e:f3:26: + 7d:1c:4d:17:bc:c9:ec:43:26:d0:bf:41:5f:40:a9: + 44:44:f4:99:e7:57:87:9e:50:1f:57:54:a8:3e:fd: + 74:63:2f:b1:50:65:09:e6:58:42:2e:43:1a:4c:b4: + f0:25:47:59:fa:04:1e:93:d4:26:46:4a:50:81:b2: + de:be:78:b7:fc:67:15:e1:c9:57:84:1e:0f:63:d6: + e9:62:ba:d6:5f:55:2e:ea:5c:c6:28:08:04:25:39: + b8:0e:2b:a9:f2:4c:97:1c:07:3f:0d:52:f5:ed:ef: + 2f:82:0f + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + 53:79:BF:5A:AA:2B:4A:CF:54:80:E1:D8:9B:C0:9D:F2:B2:03:66:CB + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + Signature Algorithm: sha384WithRSAEncryption + 5c:d4:7c:0d:cf:f7:01:7d:41:99:65:0c:73:c5:52:9f:cb:f8: + cf:99:06:7f:1b:da:43:15:9f:9e:02:55:57:96:14:f1:52:3c: + 27:87:94:28:ed:1f:3a:01:37:a2:76:fc:53:50:c0:84:9b:c6: + 6b:4e:ba:8c:21:4f:a2:8e:55:62:91:f3:69:15:d8:bc:88:e3: + c4:aa:0b:fd:ef:a8:e9:4b:55:2a:06:20:6d:55:78:29:19:ee: + 5f:30:5c:4b:24:11:55:ff:24:9a:6e:5e:2a:2b:ee:0b:4d:9f: + 7f:f7:01:38:94:14:95:43:07:09:fb:60:a9:ee:1c:ab:12:8c: + a0:9a:5e:a7:98:6a:59:6d:8b:3f:08:fb:c8:d1:45:af:18:15: + 64:90:12:0f:73:28:2e:c5:e2:24:4e:fc:58:ec:f0:f4:45:fe: + 22:b3:eb:2f:8e:d2:d9:45:61:05:c1:97:6f:a8:76:72:8f:8b: + 8c:36:af:bf:0d:05:ce:71:8d:e6:a6:6f:1f:6c:a6:71:62:c5: + d8:d0:83:72:0c:f1:67:11:89:0c:9c:13:4c:72:34:df:bc:d5: + 71:df:aa:71:dd:e1:b9:6c:8c:3c:12:5d:65:da:bd:57:12:b6: + 43:6b:ff:e5:de:4d:66:11:51:cf:99:ae:ec:17:b6:e8:71:91: + 8c:de:49:fe:dd:35:71:a2:15:27:94:1c:cf:61:e3:26:bb:6f: + a3:67:25:21:5d:e6:dd:1d:0b:2e:68:1b:3b:82:af:ec:83:67: + 85:d4:98:51:74:b1:b9:99:80:89:ff:7f:78:19:5c:79:4a:60: + 2e:92:40:ae:4c:37:2a:2c:c9:c7:62:c8:0e:5d:f7:36:5b:ca: + e0:25:25:01:b4:dd:1a:07:9c:77:00:3f:d0:dc:d5:ec:3d:d4: + fa:bb:3f:cc:85:d6:6f:7f:a9:2d:df:b9:02:f7:f5:97:9a:b5: + 35:da:c3:67:b0:87:4a:a9:28:9e:23:8e:ff:5c:27:6b:e1:b0: + 4f:f3:07:ee:00:2e:d4:59:87:cb:52:41:95:ea:f4:47:d7:ee: + 64:41:55:7c:8d:59:02:95:dd:62:9d:c2:b9:ee:5a:28:74:84: + a5:9b:b7:90:c7:0c:07:df:f5:89:36:74:32:d6:28:c1:b0:b0: + 0b:e0:9c:4c:c3:1c:d6:fc:e3:69:b5:47:46:81:2f:a2:82:ab: + d3:63:44:70:c4:8d:ff:2d:33:ba:ad:8f:7b:b5:70:88:ae:3e: + 19:cf:40:28:d8:fc:c8:90:bb:5d:99:22:f5:52:e6:58:c5:1f: + 88:31:43:ee:88:1d:d7:c6:8e:3c:43:6a:1d:a7:18:de:7d:3d: + 16:f1:62:f9:ca:90:a8:fd +-----BEGIN CERTIFICATE----- +MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB +iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl +cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV +BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAw +MjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV +BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU +aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2Vy +dGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK +AoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B +3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkY +tJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/ +Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2 +VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT +79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6 +c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmT +Yo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97l +c6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4ee +UB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeE +Hg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd +BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8G +A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPF +Up/L+M+ZBn8b2kMVn54CVVeWFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KO +VWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ7l8wXEskEVX/JJpuXior7gtNn3/3 +ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQEg9zKC7F4iRO/Fjs +8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM8WcR +iQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYze +Sf7dNXGiFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZ +XHlKYC6SQK5MNyosycdiyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/ +qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB +VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB +L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG +jjxDah2nGN59PRbxYvnKkKj9 +-----END CERTIFICATE----- + +USERTrust ECC Certification Authority +# Fingerprint (SHA1): D1:CB:CA:5D:B2:D5:2A:7F:69:3B:67:4D:E5:F0:5A:1D:0C:95:7D:F0 +MUST_VERIFY_TRUST: CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +================================================ +MD5 Fingerprint=FA:68:BC:D9:B5:7F:AD:FD:C9:1D:06:83:28:CC:24:C1 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 5c:8b:99:c5:5a:94:c5:d2:71:56:de:cd:89:80:cc:26 + Signature Algorithm: ecdsa-with-SHA384 + Issuer: C=US, ST=New Jersey, L=Jersey City, O=The USERTRUST Network, CN=USERTrust ECC Certification Authority + Validity + Not Before: Feb 1 00:00:00 2010 GMT + Not After : Jan 18 23:59:59 2038 GMT + Subject: C=US, ST=New Jersey, L=Jersey City, O=The USERTRUST Network, CN=USERTrust ECC Certification Authority + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (384 bit) + pub: + 04:1a:ac:54:5a:a9:f9:68:23:e7:7a:d5:24:6f:53: + c6:5a:d8:4b:ab:c6:d5:b6:d1:e6:73:71:ae:dd:9c: + d6:0c:61:fd:db:a0:89:03:b8:05:14:ec:57:ce:ee: + 5d:3f:e2:21:b3:ce:f7:d4:8a:79:e0:a3:83:7e:2d: + 97:d0:61:c4:f1:99:dc:25:91:63:ab:7f:30:a3:b4: + 70:e2:c7:a1:33:9c:f3:bf:2e:5c:53:b1:5f:b3:7d: + 32:7f:8a:34:e3:79:79 + ASN1 OID: secp384r1 + X509v3 extensions: + X509v3 Subject Key Identifier: + 3A:E1:09:86:D4:CF:19:C2:96:76:74:49:76:DC:E0:35:C6:63:63:9A + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + Signature Algorithm: ecdsa-with-SHA384 + 30:65:02:30:36:67:a1:16:08:dc:e4:97:00:41:1d:4e:be:e1: + 63:01:cf:3b:aa:42:11:64:a0:9d:94:39:02:11:79:5c:7b:1d: + fa:64:b9:ee:16:42:b3:bf:8a:c2:09:c4:ec:e4:b1:4d:02:31: + 00:e9:2a:61:47:8c:52:4a:4b:4e:18:70:f6:d6:44:d6:6e:f5: + 83:ba:6d:58:bd:24:d9:56:48:ea:ef:c4:a2:46:81:88:6a:3a: + 46:d1:a9:9b:4d:c9:61:da:d1:5d:57:6a:18 +-----BEGIN CERTIFICATE----- +MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDEL +MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl +eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT +JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMjAx +MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgT +Ck5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVUaGUg +VVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlm +aWNhdGlvbiBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqflo +I+d61SRvU8Za2EurxtW20eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinng +o4N+LZfQYcTxmdwlkWOrfzCjtHDix6EznPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0G +A1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNVHQ8BAf8EBAMCAQYwDwYD +VR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBBHU6+4WMB +zzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbW +RNZu9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg= +-----END CERTIFICATE----- + +GlobalSign ECC Root CA - R4 +# Fingerprint (SHA1): 69:69:56:2E:40:80:F4:24:A1:E7:19:9F:14:BA:F3:EE:58:AB:6A:BB +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +MUST_VERIFY_TRUST: CODE_SIGNING +================================================ +MD5 Fingerprint=20:F0:27:68:D1:7E:A0:9D:0E:E6:2A:CA:DF:5C:89:8E +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 2a:38:a4:1c:96:0a:04:de:42:b2:28:a5:0b:e8:34:98:02 + Signature Algorithm: ecdsa-with-SHA256 + Issuer: OU=GlobalSign ECC Root CA - R4, O=GlobalSign, CN=GlobalSign + Validity + Not Before: Nov 13 00:00:00 2012 GMT + Not After : Jan 19 03:14:07 2038 GMT + Subject: OU=GlobalSign ECC Root CA - R4, O=GlobalSign, CN=GlobalSign + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:b8:c6:79:d3:8f:6c:25:0e:9f:2e:39:19:1c:03: + a4:ae:9a:e5:39:07:09:16:ca:63:b1:b9:86:f8:8a: + 57:c1:57:ce:42:fa:73:a1:f7:65:42:ff:1e:c1:00: + b2:6e:73:0e:ff:c7:21:e5:18:a4:aa:d9:71:3f:a8: + d4:b9:ce:8c:1d + ASN1 OID: prime256v1 + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + 54:B0:7B:AD:45:B8:E2:40:7F:FB:0A:6E:FB:BE:33:C9:3C:A3:84:D5 + Signature Algorithm: ecdsa-with-SHA256 + 30:45:02:21:00:dc:92:a1:a0:13:a6:cf:03:b0:e6:c4:21:97: + 90:fa:14:57:2d:03:ec:ee:3c:d3:6e:ca:a8:6c:76:bc:a2:de: + bb:02:20:27:a8:85:27:35:9b:56:c6:a3:f2:47:d2:b7:6e:1b: + 02:00:17:aa:67:a6:15:91:de:fa:94:ec:7b:0b:f8:9f:84 +-----BEGIN CERTIFICATE----- +MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEk +MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpH +bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX +DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD +QSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprlOQcJ +FspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAw +DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61F +uOJAf/sKbvu+M8k8o4TVMAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGX +kPoUVy0D7O48027KqGx2vKLeuwIgJ6iFJzWbVsaj8kfSt24bAgAXqmemFZHe+pTs +ewv4n4Q= +-----END CERTIFICATE----- + +GlobalSign ECC Root CA - R5 +# Fingerprint (SHA1): 1F:24:C6:30:CD:A4:18:EF:20:69:FF:AD:4F:DD:5F:46:3A:1B:69:AA +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +MUST_VERIFY_TRUST: CODE_SIGNING +================================================ +MD5 Fingerprint=9F:AD:3B:1C:02:1E:8A:BA:17:74:38:81:0C:A2:BC:08 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 60:59:49:e0:26:2e:bb:55:f9:0a:77:8a:71:f9:4a:d8:6c + Signature Algorithm: ecdsa-with-SHA384 + Issuer: OU=GlobalSign ECC Root CA - R5, O=GlobalSign, CN=GlobalSign + Validity + Not Before: Nov 13 00:00:00 2012 GMT + Not After : Jan 19 03:14:07 2038 GMT + Subject: OU=GlobalSign ECC Root CA - R5, O=GlobalSign, CN=GlobalSign + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (384 bit) + pub: + 04:47:45:0e:96:fb:7d:5d:bf:e9:39:d1:21:f8:9f: + 0b:b6:d5:7b:1e:92:3a:48:59:1c:f0:62:31:2d:c0: + 7a:28:fe:1a:a7:5c:b3:b6:cc:97:e7:45:d4:58:fa: + d1:77:6d:43:a2:c0:87:65:34:0a:1f:7a:dd:eb:3c: + 33:a1:c5:9d:4d:a4:6f:41:95:38:7f:c9:1e:84:eb: + d1:9e:49:92:87:94:87:0c:3a:85:4a:66:9f:9d:59: + 93:4d:97:61:06:86:4a + ASN1 OID: secp384r1 + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + 3D:E6:29:48:9B:EA:07:CA:21:44:4A:26:DE:6E:DE:D2:83:D0:9F:59 + Signature Algorithm: ecdsa-with-SHA384 + 30:65:02:31:00:e5:69:12:c9:6e:db:c6:31:ba:09:41:e1:97: + f8:fb:fd:9a:e2:7d:12:c9:ed:7c:64:d3:cb:05:25:8b:56:d9: + a0:e7:5e:5d:4e:0b:83:9c:5b:76:29:a0:09:26:21:6a:62:02: + 30:71:d2:b5:8f:5c:ea:3b:e1:78:09:85:a8:75:92:3b:c8:5c: + fd:48:ef:0d:74:22:a8:08:e2:6e:c5:49:ce:c7:0c:bc:a7:61: + 69:f1:f7:3b:e1:2a:cb:f9:2b:f3:66:90:37 +-----BEGIN CERTIFICATE----- +MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEk +MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpH +bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX +DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD +QSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu +MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6SFkc +8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8ke +hOvRnkmSh5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD +VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYI +KoZIzj0EAwMDaAAwZQIxAOVpEslu28YxuglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg +515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7yFz9SO8NdCKoCOJuxUnO +xwy8p2Fp8fc74SrL+SvzZpA3 +-----END CERTIFICATE----- + +Staat der Nederlanden Root CA - G3 +# Fingerprint (SHA1): D8:EB:6B:41:51:92:59:E0:F3:E7:85:00:C0:3D:B6:88:97:C9:EE:FC +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +MUST_VERIFY_TRUST: CODE_SIGNING +================================================ +MD5 Fingerprint=0B:46:67:07:DB:10:2F:19:8C:35:50:60:D1:0B:F4:37 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 10003001 (0x98a239) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=NL, O=Staat der Nederlanden, CN=Staat der Nederlanden Root CA - G3 + Validity + Not Before: Nov 14 11:28:42 2013 GMT + Not After : Nov 13 23:00:00 2028 GMT + Subject: C=NL, O=Staat der Nederlanden, CN=Staat der Nederlanden Root CA - G3 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:be:32:a2:54:0f:70:fb:2c:5c:59:eb:6c:c4:a4: + 51:e8:85:2a:b3:cc:4a:34:f2:b0:5f:f3:0e:c7:1c: + 3d:53:1e:88:08:68:d8:6f:3d:ad:c2:9e:cc:82:67: + 07:27:87:68:71:3a:9f:75:96:22:46:05:b0:ed:ad: + c7:5b:9e:2a:de:9c:fc:3a:c6:95:a7:f5:17:67:18: + e7:2f:49:08:0c:5c:cf:e6:cc:34:ed:78:fb:50:b1: + dc:6b:32:f0:a2:fe:b6:3c:e4:ec:5a:97:c7:3f:1e: + 70:08:30:a0:dc:c5:b3:6d:6f:d0:82:72:11:ab:d2: + 81:68:59:82:17:b7:78:92:60:fa:cc:de:3f:84:eb: + 8d:38:33:90:0a:72:23:fa:35:cc:26:71:31:d1:72: + 28:92:d9:5b:23:6d:66:b5:6d:07:42:eb:a6:33:ce: + 92:db:c0:f6:6c:63:78:cd:ca:4e:3d:b5:e5:52:9b: + f1:be:3b:e6:54:60:b0:66:1e:09:ab:07:fe:54:89: + 11:42:d1:f7:24:ba:60:78:1a:98:f7:c9:11:fd:16: + c1:35:1a:54:75:ef:43:d3:e5:ae:4e:ce:e7:7b:c3: + c6:4e:61:51:4b:ab:9a:45:4b:a1:1f:41:bd:48:53: + 15:71:64:0b:86:b3:e5:2e:be:ce:a4:1b:c1:29:84: + a2:b5:cb:08:23:76:43:22:24:1f:17:04:d4:6e:9c: + c6:fc:7f:2b:66:1a:ec:8a:e5:d6:cf:4d:f5:63:09: + b7:15:39:d6:7b:ac:eb:e3:7c:e9:4e:fc:75:42:c8: + ed:58:95:0c:06:42:a2:9c:f7:e4:70:b3:df:72:6f: + 5a:37:40:89:d8:85:a4:d7:f1:0b:de:43:19:d4:4a: + 58:2c:8c:8a:39:9e:bf:84:87:f1:16:3b:36:0c:e9: + d3:b4:ca:6c:19:41:52:09:a1:1d:b0:6a:bf:82:ef: + 70:51:21:32:dc:05:76:8c:cb:f7:64:e4:03:50:af: + 8c:91:67:ab:c5:f2:ee:58:d8:de:be:f7:e7:31:cf: + 6c:c9:3b:71:c1:d5:88:b5:65:bc:c0:e8:17:17:07: + 12:b5:5c:d2:ab:20:93:b4:e6:82:83:70:36:c5:cd: + a3:8d:ad:8b:ec:a3:c1:43:87:e6:43:e2:34:be:95: + 8b:35:ed:07:39:da:a8:1d:7a:9f:36:9e:12:b0:0c: + 65:12:90:15:60:d9:26:40:44:e3:56:60:a5:10:d4: + 6a:3c:fd:41:dc:0e:5a:47:b6:ef:97:61:75:4f:d9: + fe:c7:b2:1d:d4:ed:5d:49:b3:a9:6a:cb:66:84:13: + d5:5c:a0:dc:df:6e:77:06:d1:71:75:c8:57:6f:af: + 0f:77:5b + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 54:AD:FA:C7:92:57:AE:CA:35:9C:2E:12:FB:E4:BA:5D:20:DC:94:57 + Signature Algorithm: sha256WithRSAEncryption + 30:99:9d:05:32:c8:5e:0e:3b:98:01:3a:8a:a4:e7:07:f7:7a: + f8:e7:9a:df:50:43:53:97:2a:3d:ca:3c:47:98:2e:e1:15:7b: + f1:92:f3:61:da:90:25:16:65:c0:9f:54:5d:0e:03:3b:5b:77: + 02:9c:84:b6:0d:98:5f:34:dd:3b:63:c2:c3:28:81:c2:9c:29: + 2e:29:e2:c8:c3:01:f2:33:ea:2a:aa:cc:09:08:f7:65:67:c6: + cd:df:d3:b6:2b:a7:bd:cc:d1:0e:70:5f:b8:23:d1:cb:91:4e: + 0a:f4:c8:7a:e5:d9:63:36:c1:d4:df:fc:22:97:f7:60:5d:ea: + 29:2f:58:b2:bd:58:bd:8d:96:4f:10:75:bf:48:7b:3d:51:87: + a1:3c:74:22:c2:fc:07:7f:80:dc:c4:ac:fe:6a:c1:70:30:b0: + e9:8e:69:e2:2c:69:81:94:09:ba:dd:fe:4d:c0:83:8c:94:58: + c0:46:20:af:9c:1f:02:f8:35:55:49:2f:46:d4:c0:f0:a0:96: + 02:0f:33:c5:71:f3:9e:23:7d:94:b7:fd:3a:d3:09:83:06:21: + fd:60:3d:ae:32:c0:d2:ee:8d:a6:f0:e7:b4:82:7c:0a:cc:70: + c9:79:80:f8:fe:4c:f7:35:84:19:8a:31:fb:0a:d9:d7:7f:9b: + f0:a2:9a:6b:c3:05:4a:ed:41:60:14:30:d1:aa:11:42:6e:d3: + 23:02:04:0b:c6:65:dd:dd:52:77:da:81:6b:b2:a8:fa:01:38: + b9:96:ea:2a:6c:67:97:89:94:9e:bc:e1:54:d5:e4:6a:78:ef: + 4a:bd:2b:9a:3d:40:7e:c6:c0:75:d2:6e:fb:68:30:ec:ec:8b: + 9d:f9:49:35:9a:1a:2c:d9:b3:95:39:d5:1e:92:f7:a6:b9:65: + 2f:e5:3d:6d:3a:48:4c:08:dc:e4:28:12:28:be:7d:35:5c:ea: + e0:16:7e:13:1b:6a:d7:3e:d7:9e:fc:2d:75:b2:c1:14:d5:23: + 03:db:5b:6f:0b:3e:78:2f:0d:de:33:8d:16:b7:48:e7:83:9a: + 81:0f:7b:c1:43:4d:55:04:17:38:4a:51:d5:59:a2:89:74:d3: + 9f:be:1e:4b:d7:c6:6d:b7:88:24:6f:60:91:a4:82:85:5b:56: + 41:bc:d0:44:ab:6a:13:be:d1:2c:58:b7:12:33:58:b2:37:63: + dc:13:f5:94:1d:3f:40:51:f5:4f:f5:3a:ed:c8:c5:eb:c2:1e: + 1d:16:95:7a:c7:7e:42:71:93:6e:4b:15:b7:30:df:aa:ed:57: + 85:48:ac:1d:6a:dd:39:69:e4:e1:79:78:be:ce:05:bf:a1:0c: + f7:80:7b:21:67:27:30:59 +-----BEGIN CERTIFICATE----- +MIIFdDCCA1ygAwIBAgIEAJiiOTANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJO +TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFh +dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQSAtIEczMB4XDTEzMTExNDExMjg0MloX +DTI4MTExMzIzMDAwMFowWjELMAkGA1UEBhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRl +ciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5lZGVybGFuZGVuIFJv +b3QgQ0EgLSBHMzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL4yolQP +cPssXFnrbMSkUeiFKrPMSjTysF/zDsccPVMeiAho2G89rcKezIJnByeHaHE6n3WW +IkYFsO2tx1ueKt6c/DrGlaf1F2cY5y9JCAxcz+bMNO14+1Cx3Gsy8KL+tjzk7FqX +xz8ecAgwoNzFs21v0IJyEavSgWhZghe3eJJg+szeP4TrjTgzkApyI/o1zCZxMdFy +KJLZWyNtZrVtB0LrpjPOktvA9mxjeM3KTj215VKb8b475lRgsGYeCasH/lSJEULR +9yS6YHgamPfJEf0WwTUaVHXvQ9Plrk7O53vDxk5hUUurmkVLoR9BvUhTFXFkC4az +5S6+zqQbwSmEorXLCCN2QyIkHxcE1G6cxvx/K2Ya7Irl1s9N9WMJtxU51nus6+N8 +6U78dULI7ViVDAZCopz35HCz33JvWjdAidiFpNfxC95DGdRKWCyMijmev4SH8RY7 +Ngzp07TKbBlBUgmhHbBqv4LvcFEhMtwFdozL92TkA1CvjJFnq8Xy7ljY3r735zHP +bMk7ccHViLVlvMDoFxcHErVc0qsgk7TmgoNwNsXNo42ti+yjwUOH5kPiNL6VizXt +BznaqB16nzaeErAMZRKQFWDZJkBE41ZgpRDUajz9QdwOWke275dhdU/Z/seyHdTt +XUmzqWrLZoQT1Vyg3N9udwbRcXXIV2+vD3dbAgMBAAGjQjBAMA8GA1UdEwEB/wQF +MAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRUrfrHkleuyjWcLhL75Lpd +INyUVzANBgkqhkiG9w0BAQsFAAOCAgEAMJmdBTLIXg47mAE6iqTnB/d6+Oea31BD +U5cqPco8R5gu4RV78ZLzYdqQJRZlwJ9UXQ4DO1t3ApyEtg2YXzTdO2PCwyiBwpwp +LiniyMMB8jPqKqrMCQj3ZWfGzd/TtiunvczRDnBfuCPRy5FOCvTIeuXZYzbB1N/8 +Ipf3YF3qKS9Ysr1YvY2WTxB1v0h7PVGHoTx0IsL8B3+A3MSs/mrBcDCw6Y5p4ixp +gZQJut3+TcCDjJRYwEYgr5wfAvg1VUkvRtTA8KCWAg8zxXHzniN9lLf9OtMJgwYh +/WA9rjLA0u6NpvDntIJ8CsxwyXmA+P5M9zWEGYox+wrZ13+b8KKaa8MFSu1BYBQw +0aoRQm7TIwIEC8Zl3d1Sd9qBa7Ko+gE4uZbqKmxnl4mUnrzhVNXkanjvSr0rmj1A +fsbAddJu+2gw7OyLnflJNZoaLNmzlTnVHpL3prllL+U9bTpITAjc5CgSKL59NVzq +4BZ+Extq1z7XnvwtdbLBFNUjA9tbbws+eC8N3jONFrdI54OagQ97wUNNVQQXOEpR +1VmiiXTTn74eS9fGbbeIJG9gkaSChVtWQbzQRKtqE77RLFi3EjNYsjdj3BP1lB0/ +QFH1T/U67cjF68IeHRaVesd+QnGTbksVtzDfqu1XhUisHWrdOWnk4Xl4vs4Fv6EM +94B7IWcnMFk= +-----END CERTIFICATE----- + +Staat der Nederlanden EV Root CA +# Fingerprint (SHA1): 76:E2:7E:C1:4F:DB:82:C1:C0:A6:75:B5:05:BE:3D:29:B4:ED:DB:BB +MUST_VERIFY_TRUST: EMAIL_PROTECTION, CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH +================================================= +MD5 Fingerprint=FC:06:AF:7B:E8:1A:F1:9A:B4:E8:D2:70:1F:C0:F5:BA +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 10000013 (0x98968d) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=NL, O=Staat der Nederlanden, CN=Staat der Nederlanden EV Root CA + Validity + Not Before: Dec 8 11:19:29 2010 GMT + Not After : Dec 8 11:10:28 2022 GMT + Subject: C=NL, O=Staat der Nederlanden, CN=Staat der Nederlanden EV Root CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:e3:c7:7e:89:f9:24:4b:3a:d2:33:83:35:2c:69: + ec:dc:09:a4:e3:51:a8:25:2b:79:b8:08:3d:e0:91: + ba:84:85:c6:85:a4:ca:e6:c9:2e:53:a4:c9:24:1e: + fd:55:66:71:5d:2c:c5:60:68:04:b7:d9:c2:52:26: + 38:88:a4:d6:3b:40:a6:c2:cd:3f:cd:98:93:b3:54: + 14:58:96:55:d5:50:fe:86:ad:a4:63:7f:5c:87:f6: + 8e:e6:27:92:67:17:92:02:03:2c:dc:d6:66:74:ed: + dd:67:ff:c1:61:8d:63:4f:0f:9b:6d:17:30:26:ef: + ab:d2:1f:10:a0:f9:c5:7f:16:69:81:03:47:ed:1e: + 68:8d:72:a1:4d:b2:26:c6:ba:6c:5f:6d:d6:af:d1: + b1:13:8e:a9:ad:f3:5e:69:75:26:18:3e:41:2b:21: + 7f:ee:8b:5d:07:06:9d:43:c4:29:0a:2b:fc:2a:3e: + 86:cb:3c:83:3a:f9:c9:0d:da:c5:99:e2:bc:78:41: + 33:76:e1:bf:2f:5d:e5:a4:98:50:0c:15:dd:e0:fa: + 9c:7f:38:68:d0:b2:a6:7a:a7:d1:31:bd:7e:8a:58: + 27:43:b3:ba:33:91:d3:a7:98:15:5c:9a:e6:d3:0f: + 75:d9:fc:41:98:97:3e:aa:25:db:8f:92:2e:b0:7b: + 0c:5f:f1:63:a9:37:f9:9b:75:69:4c:28:26:25:da: + d5:f2:12:70:45:55:e3:df:73:5e:37:f5:21:6c:90: + 8e:35:5a:c9:d3:23:eb:d3:c0:be:78:ac:42:28:58: + 66:a5:46:6d:70:02:d7:10:f9:4b:54:fc:5d:86:4a: + 87:cf:7f:ca:45:ac:11:5a:b5:20:51:8d:2f:88:47: + 97:39:c0:cf:ba:c0:42:01:40:99:48:21:0b:6b:a7: + d2:fd:96:d5:d1:be:46:9d:49:e0:0b:a6:a0:22:4e: + 38:d0:c1:3c:30:bc:70:8f:2c:75:cc:d0:c5:8c:51: + 3b:3d:94:08:64:26:61:7d:b9:c3:65:8f:14:9c:21: + d0:aa:fd:17:72:03:8f:bd:9b:8c:e6:5e:53:9e:b9: + 9d:ef:82:bb:e1:bc:e2:72:41:5b:21:94:d3:45:37: + 94:d1:df:09:39:5d:e7:23:aa:9a:1d:ca:6d:a8:0a: + 86:85:8a:82:be:42:07:d6:f2:38:82:73:da:87:5b: + e5:3c:d3:9e:3e:a7:3b:9e:f4:03:b3:f9:f1:7d:13: + 74:02:ff:bb:a1:e5:fa:00:79:1c:a6:66:41:88:5c: + 60:57:a6:2e:09:c4:ba:fd:9a:cf:a7:1f:40:c3:bb: + cc:5a:0a:55:4b:3b:38:76:51:b8:63:8b:84:94:16: + e6:56:f3 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + FE:AB:00:90:98:9E:24:FC:A9:CC:1A:8A:FB:27:B8:BF:30:6E:A8:3B + Signature Algorithm: sha256WithRSAEncryption + cf:77:2c:6e:56:be:4e:b3:b6:84:00:94:ab:47:c9:0d:d2:76: + c7:86:9f:1d:07:d3:b6:b4:bb:08:78:af:69:d2:0b:49:de:33: + c5:ac:ad:c2:88:02:7d:06:b7:35:02:c1:60:c9:bf:c4:e8:94: + de:d4:d3:a9:13:25:5a:fe:6e:a2:ae:7d:05:dc:7d:f3:6c:f0: + 7e:a6:8d:ee:d9:d7:ce:58:17:e8:a9:29:ae:73:48:87:e7:9b: + ca:6e:29:a1:64:5f:19:13:f7:ae:06:10:ff:51:c6:9b:4d:55: + 25:4f:93:99:10:01:53:75:f1:13:ce:c7:a6:41:41:d2:bf:88: + a5:7f:45:fc:ac:b8:a5:b5:33:0c:82:c4:fb:07:f6:6a:e5:25: + 84:5f:06:ca:c1:86:39:11:db:58:cd:77:3b:2c:c2:4c:0f:5e: + 9a:e3:f0:ab:3e:61:1b:50:24:c2:c0:f4:f1:19:f0:11:29:b6: + a5:18:02:9b:d7:63:4c:70:8c:47:a3:03:43:5c:b9:5d:46:a0: + 0d:6f:ff:59:8e:be:dd:9f:72:c3:5b:2b:df:8c:5b:ce:e5:0c: + 46:6c:92:b2:0a:a3:4c:54:42:18:15:12:18:bd:da:fc:ba:74: + 6e:ff:c1:b6:a0:64:d8:a9:5f:55:ae:9f:5c:6a:76:96:d8:73: + 67:87:fb:4d:7f:5c:ee:69:ca:73:10:fb:8a:a9:fd:9e:bd:36: + 38:49:49:87:f4:0e:14:f0:e9:87:b8:3f:a7:4f:7a:5a:8e:79: + d4:93:e4:bb:68:52:84:ac:6c:e9:f3:98:70:55:72:32:f9:34: + ab:2b:49:b5:cd:20:62:e4:3a:7a:67:63:ab:96:dc:6d:ae:97: + ec:fc:9f:76:56:88:2e:66:cf:5b:b6:c9:a4:b0:d7:05:ba:e1: + 27:2f:93:bb:26:2a:a2:93:b0:1b:f3:8e:be:1d:40:a3:b9:36: + 8f:3e:82:1a:1a:5e:88:ea:50:f8:59:e2:83:46:29:0b:e3:44: + 5c:e1:95:b6:69:90:9a:14:6f:97:ae:81:cf:68:ef:99:9a:be: + b5:e7:e1:7f:f8:fa:13:47:16:4c:cc:6d:08:40:e7:8b:78:6f: + 50:82:44:50:3f:66:06:8a:ab:43:84:56:4a:0f:20:2d:86:0e: + f5:d2:db:d2:7a:8a:4b:cd:a5:e8:4e:f1:5e:26:25:01:59:23: + a0:7e:d2:f6:7e:21:57:d7:27:bc:15:57:4c:a4:46:c1:e0:83: + 1e:0c:4c:4d:1f:4f:06:19:e2:f9:a8:f4:3a:82:a1:b2:79:43: + 79:d6:ad:6f:7a:27:90:03:a4:ea:24:87:3f:d9:bd:d9:e9:f2: + 5f:50:49:1c:ee:ec:d7:2e +-----BEGIN CERTIFICATE----- +MIIFcDCCA1igAwIBAgIEAJiWjTANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJO +TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSkwJwYDVQQDDCBTdGFh +dCBkZXIgTmVkZXJsYW5kZW4gRVYgUm9vdCBDQTAeFw0xMDEyMDgxMTE5MjlaFw0y +MjEyMDgxMTEwMjhaMFgxCzAJBgNVBAYTAk5MMR4wHAYDVQQKDBVTdGFhdCBkZXIg +TmVkZXJsYW5kZW4xKTAnBgNVBAMMIFN0YWF0IGRlciBOZWRlcmxhbmRlbiBFViBS +b290IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA48d+ifkkSzrS +M4M1LGns3Amk41GoJSt5uAg94JG6hIXGhaTK5skuU6TJJB79VWZxXSzFYGgEt9nC +UiY4iKTWO0Cmws0/zZiTs1QUWJZV1VD+hq2kY39ch/aO5ieSZxeSAgMs3NZmdO3d +Z//BYY1jTw+bbRcwJu+r0h8QoPnFfxZpgQNH7R5ojXKhTbImxrpsX23Wr9GxE46p +rfNeaXUmGD5BKyF/7otdBwadQ8QpCiv8Kj6GyzyDOvnJDdrFmeK8eEEzduG/L13l +pJhQDBXd4Pqcfzho0LKmeqfRMb1+ilgnQ7O6M5HTp5gVXJrm0w912fxBmJc+qiXb +j5IusHsMX/FjqTf5m3VpTCgmJdrV8hJwRVXj33NeN/UhbJCONVrJ0yPr08C+eKxC +KFhmpUZtcALXEPlLVPxdhkqHz3/KRawRWrUgUY0viEeXOcDPusBCAUCZSCELa6fS +/ZbV0b5GnUngC6agIk440ME8MLxwjyx1zNDFjFE7PZQIZCZhfbnDZY8UnCHQqv0X +cgOPvZuM5l5Tnrmd74K74bzickFbIZTTRTeU0d8JOV3nI6qaHcptqAqGhYqCvkIH +1vI4gnPah1vlPNOePqc7nvQDs/nxfRN0Av+7oeX6AHkcpmZBiFxgV6YuCcS6/ZrP +px9Aw7vMWgpVSzs4dlG4Y4uElBbmVvMCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB +/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFP6rAJCYniT8qcwaivsnuL8wbqg7 +MA0GCSqGSIb3DQEBCwUAA4ICAQDPdyxuVr5Os7aEAJSrR8kN0nbHhp8dB9O2tLsI +eK9p0gtJ3jPFrK3CiAJ9Brc1AsFgyb/E6JTe1NOpEyVa/m6irn0F3H3zbPB+po3u +2dfOWBfoqSmuc0iH55vKbimhZF8ZE/euBhD/UcabTVUlT5OZEAFTdfETzsemQUHS +v4ilf0X8rLiltTMMgsT7B/Zq5SWEXwbKwYY5EdtYzXc7LMJMD16a4/CrPmEbUCTC +wPTxGfARKbalGAKb12NMcIxHowNDXLldRqANb/9Zjr7dn3LDWyvfjFvO5QxGbJKy +CqNMVEIYFRIYvdr8unRu/8G2oGTYqV9Vrp9canaW2HNnh/tNf1zuacpzEPuKqf2e +vTY4SUmH9A4U8OmHuD+nT3pajnnUk+S7aFKErGzp85hwVXIy+TSrK0m1zSBi5Dp6 +Z2Orltxtrpfs/J92VoguZs9btsmksNcFuuEnL5O7Jiqik7Ab846+HUCjuTaPPoIa +Gl6I6lD4WeKDRikL40Rc4ZW2aZCaFG+XroHPaO+Zmr615+F/+PoTRxZMzG0IQOeL +eG9QgkRQP2YGiqtDhFZKDyAthg710tvSeopLzaXoTvFeJiUBWSOgftL2fiFX1ye8 +FVdMpEbB4IMeDExNH08GGeL5qPQ6gqGyeUN51q1veieQA6TqJIc/2b3Z6fJfUEkc +7uzXLg== +-----END CERTIFICATE----- + +IdenTrust Commercial Root CA 1 +# Fingerprint (SHA1): DF:71:7E:AA:4A:D9:4E:C9:55:84:99:60:2D:48:DE:5F:BC:F0:3A:25 +MUST_VERIFY_TRUST: CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +================================================ +MD5 Fingerprint=B3:3E:77:73:75:EE:A0:D3:E3:7E:49:63:49:59:BB:C7 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 0a:01:42:80:00:00:01:45:23:c8:44:b5:00:00:00:02 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=IdenTrust, CN=IdenTrust Commercial Root CA 1 + Validity + Not Before: Jan 16 18:12:23 2014 GMT + Not After : Jan 16 18:12:23 2034 GMT + Subject: C=US, O=IdenTrust, CN=IdenTrust Commercial Root CA 1 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:a7:50:19:de:3f:99:3d:d4:33:46:f1:6f:51:61: + 82:b2:a9:4f:8f:67:89:5d:84:d9:53:dd:0c:28:d9: + d7:f0:ff:ae:95:43:72:99:f9:b5:5d:7c:8a:c1:42: + e1:31:50:74:d1:81:0d:7c:cd:9b:21:ab:43:e2:ac: + ad:5e:86:6e:f3:09:8a:1f:5a:32:bd:a2:eb:94:f9: + e8:5c:0a:ec:ff:98:d2:af:71:b3:b4:53:9f:4e:87: + ef:92:bc:bd:ec:4f:32:30:88:4b:17:5e:57:c4:53: + c2:f6:02:97:8d:d9:62:2b:bf:24:1f:62:8d:df:c3: + b8:29:4b:49:78:3c:93:60:88:22:fc:99:da:36:c8: + c2:a2:d4:2c:54:00:67:35:6e:73:bf:02:58:f0:a4: + dd:e5:b0:a2:26:7a:ca:e0:36:a5:19:16:f5:fd:b7: + ef:ae:3f:40:f5:6d:5a:04:fd:ce:34:ca:24:dc:74: + 23:1b:5d:33:13:12:5d:c4:01:25:f6:30:dd:02:5d: + 9f:e0:d5:47:bd:b4:eb:1b:a1:bb:49:49:d8:9f:5b: + 02:f3:8a:e4:24:90:e4:62:4f:4f:c1:af:8b:0e:74: + 17:a8:d1:72:88:6a:7a:01:49:cc:b4:46:79:c6:17: + b1:da:98:1e:07:59:fa:75:21:85:65:dd:90:56:ce: + fb:ab:a5:60:9d:c4:9d:f9:52:b0:8b:bd:87:f9:8f: + 2b:23:0a:23:76:3b:f7:33:e1:c9:00:f3:69:f9:4b: + a2:e0:4e:bc:7e:93:39:84:07:f7:44:70:7e:fe:07: + 5a:e5:b1:ac:d1:18:cc:f2:35:e5:49:49:08:ca:56: + c9:3d:fb:0f:18:7d:8b:3b:c1:13:c2:4d:8f:c9:4f: + 0e:37:e9:1f:a1:0e:6a:df:62:2e:cb:35:06:51:79: + 2c:c8:25:38:f4:fa:4b:a7:89:5c:9c:d2:e3:0d:39: + 86:4a:74:7c:d5:59:87:c2:3f:4e:0c:5c:52:f4:3d: + f7:52:82:f1:ea:a3:ac:fd:49:34:1a:28:f3:41:88: + 3a:13:ee:e8:de:ff:99:1d:5f:ba:cb:e8:1e:f2:b9: + 50:60:c0:31:d3:73:e5:ef:be:a0:ed:33:0b:74:be: + 20:20:c4:67:6c:f0:08:03:7a:55:80:7f:46:4e:96: + a7:f4:1e:3e:e1:f6:d8:09:e1:33:64:2b:63:d7:32: + 5e:9f:f9:c0:7b:0f:78:6f:97:bc:93:9a:f9:9c:12: + 90:78:7a:80:87:15:d7:72:74:9c:55:74:78:b1:ba: + e1:6e:70:04:ba:4f:a0:ba:68:c3:7b:ff:31:f0:73: + 3d:3d:94:2a:b1:0b:41:0e:a0:fe:4d:88:65:6b:79: + 33:b4:d7 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + ED:44:19:C0:D3:F0:06:8B:EE:A4:7B:BE:42:E7:26:54:C8:8E:36:76 + Signature Algorithm: sha256WithRSAEncryption + 0d:ae:90:32:f6:a6:4b:7c:44:76:19:61:1e:27:28:cd:5e:54: + ef:25:bc:e3:08:90:f9:29:d7:ae:68:08:e1:94:00:58:ef:2e: + 2e:7e:53:52:8c:b6:5c:07:ea:88:ba:99:8b:50:94:d7:82:80: + df:61:09:00:93:ad:0d:14:e6:ce:c1:f2:37:94:78:b0:5f:9c: + b3:a2:73:b8:8f:05:93:38:cd:8d:3e:b0:b8:fb:c0:cf:b1:f2: + ec:2d:2d:1b:cc:ec:aa:9a:b3:aa:60:82:1b:2d:3b:c3:84:3d: + 57:8a:96:1e:9c:75:b8:d3:30:cd:60:08:83:90:d3:8e:54:f1: + 4d:66:c0:5d:74:03:40:a3:ee:85:7e:c2:1f:77:9c:06:e8:c1: + a7:18:5d:52:95:ed:c9:dd:25:9e:6d:fa:a9:ed:a3:3a:34:d0: + 59:7b:da:ed:50:f3:35:bf:ed:eb:14:4d:31:c7:60:f4:da:f1: + 87:9c:e2:48:e2:c6:c5:37:fb:06:10:fa:75:59:66:31:47:29: + da:76:9a:1c:e9:82:ae:ef:9a:b9:51:f7:88:23:9a:69:95:62: + 3c:e5:55:80:36:d7:54:02:ff:f1:b9:5d:ce:d4:23:6f:d8:45: + 84:4a:5b:65:ef:89:0c:dd:14:a7:20:cb:18:a5:25:b4:0d:f9: + 01:f0:a2:d2:f4:00:c8:74:8e:a1:2a:48:8e:65:db:13:c4:e2: + 25:17:7d:eb:be:87:5b:17:20:54:51:93:4a:53:03:0b:ec:5d: + ca:33:ed:62:fd:45:c7:2f:5b:dc:58:a0:80:39:e6:fa:d7:fe: + 13:14:a6:ed:3d:94:4a:42:74:d4:c3:77:59:73:cd:8f:46:be: + 55:38:ef:fa:e8:91:32:ea:97:58:04:22:de:38:c3:cc:bc:6d: + c9:33:3a:6a:0a:69:3f:a0:c8:ea:72:8f:8c:63:86:23:bd:6d: + 3c:96:9e:95:e0:49:4c:aa:a2:b9:2a:1b:9c:36:81:78:ed:c3: + e8:46:e2:26:59:44:75:1e:d9:75:89:51:cd:10:84:9d:61:60: + cb:5d:f9:97:22:4d:8e:98:e6:e3:7f:f6:5b:bb:ae:cd:ca:4a: + 81:6b:5e:0b:f3:51:e1:74:2b:e9:7e:27:a7:d9:99:49:4e:f8: + a5:80:db:25:0f:1c:63:62:8a:c9:33:67:6b:3c:10:83:c6:ad: + de:a8:cd:16:8e:8d:f0:07:37:71:9f:f2:ab:fc:41:f5:c1:8b: + ec:00:37:5d:09:e5:4e:80:ef:fa:b1:5c:38:06:a5:1b:4a:e1: + dc:38:2d:3c:dc:ab:1f:90:1a:d5:4a:9c:ee:d1:70:6c:cc:ee: + f4:57:f8:18:ba:84:6e:87 +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBK +MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVu +VHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQw +MTE2MTgxMjIzWjBKMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScw +JQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQCnUBneP5k91DNG8W9RYYKyqU+PZ4ldhNlT +3Qwo2dfw/66VQ3KZ+bVdfIrBQuExUHTRgQ18zZshq0PirK1ehm7zCYofWjK9ouuU ++ehcCuz/mNKvcbO0U59Oh++SvL3sTzIwiEsXXlfEU8L2ApeN2WIrvyQfYo3fw7gp +S0l4PJNgiCL8mdo2yMKi1CxUAGc1bnO/AljwpN3lsKImesrgNqUZFvX9t++uP0D1 +bVoE/c40yiTcdCMbXTMTEl3EASX2MN0CXZ/g1Ue9tOsbobtJSdifWwLziuQkkORi +T0/Br4sOdBeo0XKIanoBScy0RnnGF7HamB4HWfp1IYVl3ZBWzvurpWCdxJ35UrCL +vYf5jysjCiN2O/cz4ckA82n5S6LgTrx+kzmEB/dEcH7+B1rlsazRGMzyNeVJSQjK +Vsk9+w8YfYs7wRPCTY/JTw436R+hDmrfYi7LNQZReSzIJTj0+kuniVyc0uMNOYZK +dHzVWYfCP04MXFL0PfdSgvHqo6z9STQaKPNBiDoT7uje/5kdX7rL6B7yuVBgwDHT +c+XvvqDtMwt0viAgxGds8AgDelWAf0ZOlqf0Hj7h9tgJ4TNkK2PXMl6f+cB7D3hv +l7yTmvmcEpB4eoCHFddydJxVdHixuuFucAS6T6C6aMN7/zHwcz09lCqxC0EOoP5N +iGVreTO01wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB +/zAdBgNVHQ4EFgQU7UQZwNPwBovupHu+QucmVMiONnYwDQYJKoZIhvcNAQELBQAD +ggIBAA2ukDL2pkt8RHYZYR4nKM1eVO8lvOMIkPkp165oCOGUAFjvLi5+U1KMtlwH +6oi6mYtQlNeCgN9hCQCTrQ0U5s7B8jeUeLBfnLOic7iPBZM4zY0+sLj7wM+x8uwt +LRvM7Kqas6pgghstO8OEPVeKlh6cdbjTMM1gCIOQ045U8U1mwF10A0Cj7oV+wh93 +nAbowacYXVKV7cndJZ5t+qntozo00Fl72u1Q8zW/7esUTTHHYPTa8Yec4kjixsU3 ++wYQ+nVZZjFHKdp2mhzpgq7vmrlR94gjmmmVYjzlVYA211QC//G5Xc7UI2/YRYRK +W2XviQzdFKcgyxilJbQN+QHwotL0AMh0jqEqSI5l2xPE4iUXfeu+h1sXIFRRk0pT +AwvsXcoz7WL9RccvW9xYoIA55vrX/hMUpu09lEpCdNTDd1lzzY9GvlU47/rokTLq +l1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG +4iZZRHUe2XWJUc0QhJ1hYMtd+ZciTY6Y5uN/9lu7rs3KSoFrXgvzUeF0K+l+J6fZ +mUlO+KWA2yUPHGNiiskzZ2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A +7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7RcGzM7vRX+Bi6hG6H +-----END CERTIFICATE----- + +IdenTrust Public Sector Root CA 1 +# Fingerprint (SHA1): BA:29:41:60:77:98:3F:F4:F3:EF:F2:31:05:3B:2E:EA:6D:4D:45:FD +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +MUST_VERIFY_TRUST: CODE_SIGNING +================================================ +MD5 Fingerprint=37:06:A5:B0:FC:89:9D:BA:F4:6B:8C:1A:64:CD:D5:BA +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 0a:01:42:80:00:00:01:45:23:cf:46:7c:00:00:00:02 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=IdenTrust, CN=IdenTrust Public Sector Root CA 1 + Validity + Not Before: Jan 16 17:53:32 2014 GMT + Not After : Jan 16 17:53:32 2034 GMT + Subject: C=US, O=IdenTrust, CN=IdenTrust Public Sector Root CA 1 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:b6:22:94:fc:a4:48:af:e8:47:6b:0a:fb:27:76: + e4:f2:3f:8a:3b:7a:4a:2c:31:2a:8c:8d:b0:a9:c3: + 31:6b:a8:77:76:84:26:b6:ac:81:42:0d:08:eb:55: + 58:bb:7a:f8:bc:65:7d:f2:a0:6d:8b:a8:47:e9:62: + 76:1e:11:ee:08:14:d1:b2:44:16:f4:ea:d0:fa:1e: + 2f:5e:db:cb:73:41:ae:bc:00:b0:4a:2b:40:b2:ac: + e1:3b:4b:c2:2d:9d:e4:a1:9b:ec:1a:3a:1e:f0:08: + b3:d0:e4:24:35:07:9f:9c:b4:c9:52:6d:db:07:ca: + 8f:b5:5b:f0:83:f3:4f:c7:2d:a5:c8:ad:cb:95:20: + a4:31:28:57:58:5a:e4:8d:1b:9a:ab:9e:0d:0c:f2: + 0a:33:39:22:39:0a:97:2e:f3:53:77:b9:44:45:fd: + 84:cb:36:20:81:59:2d:9a:6f:6d:48:48:61:ca:4c: + df:53:d1:af:52:bc:44:9f:ab:2f:6b:83:72:ef:75: + 80:da:06:33:1b:5d:c8:da:63:c6:4d:cd:ac:66:31: + cd:d1:de:3e:87:10:36:e1:b9:a4:7a:ef:60:50:b2: + cb:ca:a6:56:e0:37:af:ab:34:13:39:25:e8:39:66: + e4:98:7a:aa:12:98:9c:59:66:86:3e:ad:f1:b0:ca: + 3e:06:0f:7b:f0:11:4b:37:a0:44:6d:7b:cb:a8:8c: + 71:f4:d5:b5:91:36:cc:f0:15:c6:2b:de:51:17:b1: + 97:4c:50:3d:b1:95:59:7c:05:7d:2d:21:d5:00:bf: + 01:67:a2:5e:7b:a6:5c:f2:f7:22:f1:90:0d:93:db: + aa:44:51:66:cc:7d:76:03:eb:6a:a8:2a:38:19:97: + 76:0d:6b:8a:61:f9:bc:f6:ee:76:fd:70:2b:dd:29: + 3c:f8:0a:1e:5b:42:1c:8b:56:2f:55:1b:1c:a1:2e: + b5:c7:16:e6:f8:aa:3c:92:8e:69:b6:01:c1:b5:86: + 9d:89:0f:0b:38:94:54:e8:ea:dc:9e:3d:25:bc:53: + 26:ed:d5:ab:39:aa:c5:40:4c:54:ab:b2:b4:d9:d9: + f8:d7:72:db:1c:bc:6d:bd:65:5f:ef:88:35:2a:66: + 2f:ee:f6:b3:65:f0:33:8d:7c:98:41:69:46:0f:43: + 1c:69:fa:9b:b5:d0:61:6a:cd:ca:4b:d9:4c:90:46: + ab:15:59:a1:47:54:29:2e:83:28:5f:1c:c2:a2:ab: + 72:17:00:06:8e:45:ec:8b:e2:33:3d:7f:da:19:44: + e4:62:72:c3:df:22:c6:f2:56:d4:dd:5f:95:72:ed: + 6d:5f:f7:48:03:5b:fd:c5:2a:a0:f6:73:23:84:10: + 1b:01:e7 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + E3:71:E0:9E:D8:A7:42:D9:DB:71:91:6B:94:93:EB:C3:A3:D1:14:A3 + Signature Algorithm: sha256WithRSAEncryption + 47:fa:dd:0a:b0:11:91:38:ad:4d:5d:f7:e5:0e:97:54:19:82: + 48:87:54:8c:aa:64:99:d8:5a:fe:88:01:c5:58:a5:99:b1:23: + 54:23:b7:6a:1d:20:57:e5:01:62:41:17:d3:09:db:75:cb:6e: + 54:90:75:fe:1a:9f:81:0a:c2:dd:d7:f7:09:d0:5b:72:15:e4: + 1e:09:6a:3d:33:f3:21:9a:e6:15:7e:ad:51:d5:0d:10:ed:7d: + 42:c0:8f:ee:c0:9a:08:d5:41:d6:5c:0e:21:69:6e:80:61:0e: + 15:c0:b8:cf:c5:49:12:52:cc:be:3a:cc:d4:2e:38:05:de:35: + fd:1f:6f:b8:80:68:98:3d:4d:a0:ca:40:65:d2:73:7c:f5:8b: + d9:0a:95:3f:d8:3f:23:6d:1a:d1:2a:24:19:d9:85:b3:17:ef: + 78:6e:a9:58:d1:23:d3:c7:13:ed:72:25:7f:5d:b1:73:70:d0: + 7f:06:97:09:84:29:80:61:1d:fa:5e:ff:73:ac:a0:e3:89:b8: + 1c:71:15:c6:de:31:7f:12:dc:e1:6d:9b:af:e7:e8:9f:75:78: + 4c:ab:46:3b:9a:ce:bf:05:18:5d:4d:15:3c:16:9a:19:50:04: + 9a:b2:9a:6f:65:8b:52:5f:3c:58:04:28:25:c0:66:61:31:7e: + b9:e0:75:b9:1a:a8:81:d6:72:17:b3:c5:03:31:35:11:78:78: + a2:e0:e9:30:8c:7f:80:df:58:df:3c:ba:27:96:e2:80:34:6d: + e3:98:d3:64:27:ac:48:7e:28:77:5c:c6:25:61:25:f8:85:0c: + 65:fa:c4:32:2f:a5:98:05:e4:f8:0b:67:16:16:c6:82:b8:32: + 19:f9:f9:b9:79:dc:1f:cd:eb:af:ab:0e:dd:1b:db:45:e4:7a: + e7:02:e2:95:5d:fc:69:f0:53:69:61:95:75:79:0b:5e:55:e6: + 38:1c:94:a9:59:33:9e:c8:71:74:79:7f:51:89:b6:c8:6a:b8: + 30:c8:6a:38:c3:6e:9e:e1:37:16:ea:05:62:4c:5b:12:47:ed: + a7:b4:b3:58:56:c7:49:f3:7f:12:68:09:31:71:f0:6d:f8:4e: + 47:fb:d6:85:ee:c5:58:40:19:a4:1d:a7:f9:4b:43:37:dc:68: + 5a:4f:cf:eb:c2:64:74:de:b4:15:d9:f4:54:54:1a:2f:1c:d7: + 97:71:54:90:8e:d9:20:9d:53:2b:7f:ab:8f:e2:ea:30:bc:50: + 37:ef:f1:47:b5:7d:7c:2c:04:ec:68:9d:b4:49:44:10:f4:72: + 4b:1c:64:e7:fc:e6:6b:90:dd:69:7d:69:fd:00:56:a5:b7:ac: + b6:ad:b7:ca:3e:01:ef:9c +-----BEGIN CERTIFICATE----- +MIIFZjCCA06gAwIBAgIQCgFCgAAAAUUjz0Z8AAAAAjANBgkqhkiG9w0BAQsFADBN +MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVu +VHJ1c3QgUHVibGljIFNlY3RvciBSb290IENBIDEwHhcNMTQwMTE2MTc1MzMyWhcN +MzQwMTE2MTc1MzMyWjBNMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0 +MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3RvciBSb290IENBIDEwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2IpT8pEiv6EdrCvsnduTyP4o7 +ekosMSqMjbCpwzFrqHd2hCa2rIFCDQjrVVi7evi8ZX3yoG2LqEfpYnYeEe4IFNGy +RBb06tD6Hi9e28tzQa68ALBKK0CyrOE7S8ItneShm+waOh7wCLPQ5CQ1B5+ctMlS +bdsHyo+1W/CD80/HLaXIrcuVIKQxKFdYWuSNG5qrng0M8gozOSI5Cpcu81N3uURF +/YTLNiCBWS2ab21ISGHKTN9T0a9SvESfqy9rg3LvdYDaBjMbXcjaY8ZNzaxmMc3R +3j6HEDbhuaR672BQssvKplbgN6+rNBM5Jeg5ZuSYeqoSmJxZZoY+rfGwyj4GD3vw +EUs3oERte8uojHH01bWRNszwFcYr3lEXsZdMUD2xlVl8BX0tIdUAvwFnol57plzy +9yLxkA2T26pEUWbMfXYD62qoKjgZl3YNa4ph+bz27nb9cCvdKTz4Ch5bQhyLVi9V +GxyhLrXHFub4qjySjmm2AcG1hp2JDws4lFTo6tyePSW8Uybt1as5qsVATFSrsrTZ +2fjXctscvG29ZV/viDUqZi/u9rNl8DONfJhBaUYPQxxp+pu10GFqzcpL2UyQRqsV +WaFHVCkugyhfHMKiq3IXAAaOReyL4jM9f9oZRORicsPfIsbyVtTdX5Vy7W1f90gD +W/3FKqD2cyOEEBsB5wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ +BAUwAwEB/zAdBgNVHQ4EFgQU43HgntinQtnbcZFrlJPrw6PRFKMwDQYJKoZIhvcN +AQELBQADggIBAEf63QqwEZE4rU1d9+UOl1QZgkiHVIyqZJnYWv6IAcVYpZmxI1Qj +t2odIFflAWJBF9MJ23XLblSQdf4an4EKwt3X9wnQW3IV5B4Jaj0z8yGa5hV+rVHV +DRDtfULAj+7AmgjVQdZcDiFpboBhDhXAuM/FSRJSzL46zNQuOAXeNf0fb7iAaJg9 +TaDKQGXSc3z1i9kKlT/YPyNtGtEqJBnZhbMX73huqVjRI9PHE+1yJX9dsXNw0H8G +lwmEKYBhHfpe/3OsoOOJuBxxFcbeMX8S3OFtm6/n6J91eEyrRjuazr8FGF1NFTwW +mhlQBJqymm9li1JfPFgEKCXAZmExfrngdbkaqIHWchezxQMxNRF4eKLg6TCMf4Df +WN88uieW4oA0beOY02QnrEh+KHdcxiVhJfiFDGX6xDIvpZgF5PgLZxYWxoK4Mhn5 ++bl53B/N66+rDt0b20XkeucC4pVd/GnwU2lhlXV5C15V5jgclKlZM57IcXR5f1GJ +tshquDDIajjDbp7hNxbqBWJMWxJH7ae0s1hWx0nzfxJoCTFx8G34Tkf71oXuxVhA +GaQdp/lLQzfcaFpPz+vCZHTetBXZ9FRUGi8c15dxVJCO2SCdUyt/q4/i6jC8UDfv +8Ue1fXwsBOxonbRJRBD0ckscZOf85muQ3Wl9af0AVqW3rLatt8o+Ae+c +-----END CERTIFICATE----- + +Entrust Root Certification Authority - G2 +# Fingerprint (SHA1): 8C:F4:27:FD:79:0C:3A:D1:66:06:8D:E8:1E:57:EF:BB:93:22:72:D4 +MUST_VERIFY_TRUST: CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +================================================ +MD5 Fingerprint=4B:E2:C9:91:96:65:0C:F4:0E:5A:93:92:A0:0A:FE:B2 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 1246989352 (0x4a538c28) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=Entrust, Inc., OU=See www.entrust.net/legal-terms, OU=(c) 2009 Entrust, Inc. - for authorized use only, CN=Entrust Root Certification Authority - G2 + Validity + Not Before: Jul 7 17:25:54 2009 GMT + Not After : Dec 7 17:55:54 2030 GMT + Subject: C=US, O=Entrust, Inc., OU=See www.entrust.net/legal-terms, OU=(c) 2009 Entrust, Inc. - for authorized use only, CN=Entrust Root Certification Authority - G2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:ba:84:b6:72:db:9e:0c:6b:e2:99:e9:30:01:a7: + 76:ea:32:b8:95:41:1a:c9:da:61:4e:58:72:cf:fe: + f6:82:79:bf:73:61:06:0a:a5:27:d8:b3:5f:d3:45: + 4e:1c:72:d6:4e:32:f2:72:8a:0f:f7:83:19:d0:6a: + 80:80:00:45:1e:b0:c7:e7:9a:bf:12:57:27:1c:a3: + 68:2f:0a:87:bd:6a:6b:0e:5e:65:f3:1c:77:d5:d4: + 85:8d:70:21:b4:b3:32:e7:8b:a2:d5:86:39:02:b1: + b8:d2:47:ce:e4:c9:49:c4:3b:a7:de:fb:54:7d:57: + be:f0:e8:6e:c2:79:b2:3a:0b:55:e2:50:98:16:32: + 13:5c:2f:78:56:c1:c2:94:b3:f2:5a:e4:27:9a:9f: + 24:d7:c6:ec:d0:9b:25:82:e3:cc:c2:c4:45:c5:8c: + 97:7a:06:6b:2a:11:9f:a9:0a:6e:48:3b:6f:db:d4: + 11:19:42:f7:8f:07:bf:f5:53:5f:9c:3e:f4:17:2c: + e6:69:ac:4e:32:4c:62:77:ea:b7:e8:e5:bb:34:bc: + 19:8b:ae:9c:51:e7:b7:7e:b5:53:b1:33:22:e5:6d: + cf:70:3c:1a:fa:e2:9b:67:b6:83:f4:8d:a5:af:62: + 4c:4d:e0:58:ac:64:34:12:03:f8:b6:8d:94:63:24: + a4:71 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + 6A:72:26:7A:D0:1E:EF:7D:E7:3B:69:51:D4:6C:8D:9F:90:12:66:AB + Signature Algorithm: sha256WithRSAEncryption + 79:9f:1d:96:c6:b6:79:3f:22:8d:87:d3:87:03:04:60:6a:6b: + 9a:2e:59:89:73:11:ac:43:d1:f5:13:ff:8d:39:2b:c0:f2:bd: + 4f:70:8c:a9:2f:ea:17:c4:0b:54:9e:d4:1b:96:98:33:3c:a8: + ad:62:a2:00:76:ab:59:69:6e:06:1d:7e:c4:b9:44:8d:98:af: + 12:d4:61:db:0a:19:46:47:f3:eb:f7:63:c1:40:05:40:a5:d2: + b7:f4:b5:9a:36:bf:a9:88:76:88:04:55:04:2b:9c:87:7f:1a: + 37:3c:7e:2d:a5:1a:d8:d4:89:5e:ca:bd:ac:3d:6c:d8:6d:af: + d5:f3:76:0f:cd:3b:88:38:22:9d:6c:93:9a:c4:3d:bf:82:1b: + 65:3f:a6:0f:5d:aa:fc:e5:b2:15:ca:b5:ad:c6:bc:3d:d0:84: + e8:ea:06:72:b0:4d:39:32:78:bf:3e:11:9c:0b:a4:9d:9a:21: + f3:f0:9b:0b:30:78:db:c1:dc:87:43:fe:bc:63:9a:ca:c5:c2: + 1c:c9:c7:8d:ff:3b:12:58:08:e6:b6:3d:ec:7a:2c:4e:fb:83: + 96:ce:0c:3c:69:87:54:73:a4:73:c2:93:ff:51:10:ac:15:54: + 01:d8:fc:05:b1:89:a1:7f:74:83:9a:49:d7:dc:4e:7b:8a:48: + 6f:8b:45:f6 +-----BEGIN CERTIFICATE----- +MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMC +VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50 +cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3Qs +IEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVz +dCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwHhcNMDkwNzA3MTcy +NTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVu +dHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwt +dGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0 +aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP/vaCeb9zYQYKpSfYs1/T +RU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXzHHfV1IWN +cCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hW +wcKUs/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1 +U1+cPvQXLOZprE4yTGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0 +jaWvYkxN4FisZDQSA/i2jZRjJKRxAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAP +BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ60B7vfec7aVHUbI2fkBJmqzAN +BgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5ZiXMRrEPR9RP/ +jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ +Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v +1fN2D807iDginWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4R +nAuknZoh8/CbCzB428Hch0P+vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmH +VHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xOe4pIb4tF9g== +-----END CERTIFICATE----- + +Entrust Root Certification Authority - EC1 +# Fingerprint (SHA1): 20:D8:06:40:DF:9B:25:F5:12:25:3A:11:EA:F7:59:8A:EB:14:B5:47 +MUST_VERIFY_TRUST: CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +================================================ +MD5 Fingerprint=B6:7E:1D:F0:58:C5:49:6C:24:3B:3D:ED:98:18:ED:BC +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + a6:8b:79:29:00:00:00:00:50:d0:91:f9 + Signature Algorithm: ecdsa-with-SHA384 + Issuer: C=US, O=Entrust, Inc., OU=See www.entrust.net/legal-terms, OU=(c) 2012 Entrust, Inc. - for authorized use only, CN=Entrust Root Certification Authority - EC1 + Validity + Not Before: Dec 18 15:25:36 2012 GMT + Not After : Dec 18 15:55:36 2037 GMT + Subject: C=US, O=Entrust, Inc., OU=See www.entrust.net/legal-terms, OU=(c) 2012 Entrust, Inc. - for authorized use only, CN=Entrust Root Certification Authority - EC1 + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (384 bit) + pub: + 04:84:13:c9:d0:ba:6d:41:7b:e2:6c:d0:eb:55:5f: + 66:02:1a:24:f4:5b:89:69:47:e3:b8:c2:7d:f1:f2: + 02:c5:9f:a0:f6:5b:d5:8b:06:19:86:4f:53:10:6d: + 07:24:27:a1:a0:f8:d5:47:19:61:4c:7d:ca:93:27: + ea:74:0c:ef:6f:96:09:fe:63:ec:70:5d:36:ad:67: + 77:ae:c9:9d:7c:55:44:3a:a2:63:51:1f:f5:e3:62: + d4:a9:47:07:3e:cc:20 + ASN1 OID: secp384r1 + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + B7:63:E7:1A:DD:8D:E9:08:A6:55:83:A4:E0:6A:50:41:65:11:42:49 + Signature Algorithm: ecdsa-with-SHA384 + 30:64:02:30:61:79:d8:e5:42:47:df:1c:ae:53:99:17:b6:6f: + 1c:7d:e1:bf:11:94:d1:03:88:75:e4:8d:89:a4:8a:77:46:de: + 6d:61:ef:02:f5:fb:b5:df:cc:fe:4e:ff:fe:a9:e6:a7:02:30: + 5b:99:d7:85:37:06:b5:7b:08:fd:eb:27:8b:4a:94:f9:e1:fa: + a7:8e:26:08:e8:7c:92:68:6d:73:d8:6f:26:ac:21:02:b8:99: + b7:26:41:5b:25:60:ae:d0:48:1a:ee:06 +-----BEGIN CERTIFICATE----- +MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkG +A1UEBhMCVVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3 +d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVu +dHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEzMDEGA1UEAxMq +RW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRUMxMB4XDTEy +MTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYwFAYD +VQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0 +L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0g +Zm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBD +ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEVDMTB2MBAGByqGSM49AgEGBSuBBAAi +A2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHyAsWfoPZb1YsGGYZPUxBt +ByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef9eNi1KlH +Bz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O +BBYEFLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVC +R98crlOZF7ZvHH3hvxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nX +hTcGtXsI/esni0qU+eH6p44mCOh8kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G +-----END CERTIFICATE----- + +CFCA EV ROOT +# Fingerprint (SHA1): E2:B8:29:4B:55:84:AB:6B:58:C2:90:46:6C:AC:3F:B8:39:8F:84:83 +TRUSTED_DELEGATOR: SERVER_AUTH +MUST_VERIFY_TRUST: EMAIL_PROTECTION, CODE_SIGNING +================================================= +MD5 Fingerprint=74:E1:B6:ED:26:7A:7A:44:30:33:94:AB:7B:27:81:30 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 407555286 (0x184accd6) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=CN, O=China Financial Certification Authority, CN=CFCA EV ROOT + Validity + Not Before: Aug 8 03:07:01 2012 GMT + Not After : Dec 31 03:07:01 2029 GMT + Subject: C=CN, O=China Financial Certification Authority, CN=CFCA EV ROOT + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:d7:5d:6b:cd:10:3f:1f:05:59:d5:05:4d:37:b1: + 0e:ec:98:2b:8e:15:1d:fa:93:4b:17:82:21:71:10: + 52:d7:51:64:70:16:c2:55:69:4d:8e:15:6d:9f:bf: + 0c:1b:c2:e0:a3:67:d6:0c:ac:cf:22:ae:af:77:54: + 2a:4b:4c:8a:53:52:7a:c3:ee:2e:de:b3:71:25:c1: + e9:5d:3d:ee:a1:2f:a3:f7:2a:3c:c9:23:1d:6a:ab: + 1d:a1:a7:f1:f3:ec:a0:d5:44:cf:15:cf:72:2f:1d: + 63:97:e8:99:f9:fd:93:a4:54:80:4c:52:d4:52:ab: + 2e:49:df:90:cd:b8:5f:be:3f:de:a1:ca:4d:20:d4: + 25:e8:84:29:53:b7:b1:88:1f:ff:fa:da:90:9f:0a: + a9:2d:41:3f:b1:f1:18:29:ee:16:59:2c:34:49:1a: + a8:06:d7:a8:88:d2:03:72:7a:32:e2:ea:68:4d:6e: + 2c:96:65:7b:ca:59:fa:f2:e2:dd:ee:30:2c:fb:cc: + 46:ac:c4:63:eb:6f:7f:36:2b:34:73:12:94:7f:df: + cc:26:9e:f1:72:5d:50:65:59:8f:69:b3:87:5e:32: + 6f:c3:18:8a:b5:95:8f:b0:7a:37:de:5a:45:3b:c7: + 36:e1:ef:67:d1:39:d3:97:5b:73:62:19:48:2d:87: + 1c:06:fb:74:98:20:49:73:f0:05:d2:1b:b1:a0:a3: + b7:1b:70:d3:88:69:b9:5a:d6:38:f4:62:dc:25:8b: + 78:bf:f8:e8:7e:b8:5c:c9:95:4f:5f:a7:2d:b9:20: + 6b:cf:6b:dd:f5:0d:f4:82:b7:f4:b2:66:2e:10:28: + f6:97:5a:7b:96:16:8f:01:19:2d:6c:6e:7f:39:58: + 06:64:83:01:83:83:c3:4d:92:dd:32:c6:87:a4:37: + e9:16:ce:aa:2d:68:af:0a:81:65:3a:70:c1:9b:ad: + 4d:6d:54:ca:2a:2d:4b:85:1b:b3:80:e6:70:45:0d: + 6b:5e:35:f0:7f:3b:b8:9c:e4:04:70:89:12:25:93: + da:0a:99:22:60:6a:63:60:4e:76:06:98:4e:bd:83: + ad:1d:58:8a:25:85:d2:c7:65:1e:2d:8e:c6:df:b6: + c6:e1:7f:8a:04:21:15:29:74:f0:3e:9c:90:9d:0c: + 2e:f1:8a:3e:5a:aa:0c:09:1e:c7:d5:3c:a3:ed:97: + c3:1e:34:fa:38:f9:08:0e:e3:c0:5d:2b:83:d1:56: + 6a:c9:b6:a8:54:53:2e:78:32:67:3d:82:7f:74:d0: + fb:e1:b6:05:60:b9:70:db:8e:0b:f9:13:58:6f:71: + 60:10:52:10:b9:c1:41:09:ef:72:1f:67:31:78:ff: + 96:05:8d + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Authority Key Identifier: + keyid:E3:FE:2D:FD:28:D0:0B:B5:BA:B6:A2:C4:BF:06:AA:05:8C:93:FB:2F + + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + E3:FE:2D:FD:28:D0:0B:B5:BA:B6:A2:C4:BF:06:AA:05:8C:93:FB:2F + Signature Algorithm: sha256WithRSAEncryption + 25:c6:ba:6b:eb:87:cb:de:82:39:96:3d:f0:44:a7:6b:84:73: + 03:de:9d:2b:4f:ba:20:7f:bc:78:b2:cf:97:b0:1b:9c:f3:d7: + 79:2e:f5:48:b6:d2:fb:17:88:e6:d3:7a:3f:ed:53:13:d0:e2: + 2f:6a:79:cb:00:23:28:e6:1e:37:57:35:89:84:c2:76:4f:34: + 36:ad:67:c3:ce:41:06:88:c5:f7:ee:d8:1a:b8:d6:0b:7f:50: + ff:93:aa:17:4b:8c:ec:ed:52:60:b2:a4:06:ea:4e:eb:f4:6b: + 19:fd:eb:f5:1a:e0:25:2a:9a:dc:c7:41:36:f7:c8:74:05:84: + 39:95:39:d6:0b:3b:a4:27:fa:08:d8:5c:1e:f8:04:60:52:11: + 28:28:03:ff:ef:53:66:00:a5:4a:34:16:66:7c:fd:09:a4:ae: + 9e:67:1a:6f:41:0b:6b:06:13:9b:8f:86:71:05:b4:2f:8d:89: + 66:33:29:76:54:9a:11:f8:27:fa:b2:3f:91:e0:ce:0d:1b:f3: + 30:1a:ad:bf:22:5d:1b:d3:bf:25:05:4d:e1:92:1a:7f:99:9f: + 3c:44:93:ca:d4:40:49:6c:80:87:d7:04:3a:c3:32:52:35:0e: + 56:f8:a5:dd:7d:c4:8b:0d:11:1f:53:cb:1e:b2:17:b6:68:77: + 5a:e0:d4:cb:c8:07:ae:f5:3a:2e:8e:37:b7:d0:01:4b:43:29: + 77:8c:39:97:8f:82:5a:f8:51:e5:89:a0:18:e7:68:7f:5d:0a: + 2e:fb:a3:47:0e:3d:a6:23:7a:c6:01:c7:8f:c8:5e:bf:6d:80: + 56:be:8a:24:ba:33:ea:9f:e1:32:11:9e:f1:d2:4f:80:f6:1b: + 40:af:38:9e:11:50:79:73:12:12:cd:e6:6c:9d:2c:88:72:3c: + 30:81:06:91:22:ea:59:ad:da:19:2e:22:c2:8d:b9:8c:87:e0: + 66:bc:73:23:5f:21:64:63:80:48:f5:a0:3c:18:3d:94:c8:48: + 41:1d:40:ba:5e:fe:fe:56:39:a1:c8:cf:5e:9e:19:64:46:10: + da:17:91:b7:05:80:ac:8b:99:92:7d:e7:a2:d8:07:0b:36:27: + e7:48:79:60:8a:c3:d7:13:5c:f8:72:40:df:4a:cb:cf:99:00: + 0a:00:0b:11:95:da:56:45:03:88:0a:9f:67:d0:d5:79:b1:a8: + 8d:40:6d:0d:c2:7a:40:fa:f3:5f:64:47:92:cb:53:b9:bb:59: + ce:4f:fd:d0:15:53:01:d8:df:eb:d9:e6:76:ef:d0:23:bb:3b: + a9:79:b3:d5:02:29:cd:89:a3:96:0f:4a:35:e7:4e:42:c0:75: + cd:07:cf:e6:2c:eb:7b:2e +-----BEGIN CERTIFICATE----- +MIIFjTCCA3WgAwIBAgIEGErM1jANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJD +TjEwMC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9y +aXR5MRUwEwYDVQQDDAxDRkNBIEVWIFJPT1QwHhcNMTIwODA4MDMwNzAxWhcNMjkx +MjMxMDMwNzAxWjBWMQswCQYDVQQGEwJDTjEwMC4GA1UECgwnQ2hpbmEgRmluYW5j +aWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQDDAxDRkNBIEVWIFJP +T1QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXXWvNED8fBVnVBU03 +sQ7smCuOFR36k0sXgiFxEFLXUWRwFsJVaU2OFW2fvwwbwuCjZ9YMrM8irq93VCpL +TIpTUnrD7i7es3ElweldPe6hL6P3KjzJIx1qqx2hp/Hz7KDVRM8Vz3IvHWOX6Jn5 +/ZOkVIBMUtRSqy5J35DNuF++P96hyk0g1CXohClTt7GIH//62pCfCqktQT+x8Rgp +7hZZLDRJGqgG16iI0gNyejLi6mhNbiyWZXvKWfry4t3uMCz7zEasxGPrb382KzRz +EpR/38wmnvFyXVBlWY9ps4deMm/DGIq1lY+wejfeWkU7xzbh72fROdOXW3NiGUgt +hxwG+3SYIElz8AXSG7Ggo7cbcNOIabla1jj0Ytwli3i/+Oh+uFzJlU9fpy25IGvP +a931DfSCt/SyZi4QKPaXWnuWFo8BGS1sbn85WAZkgwGDg8NNkt0yxoekN+kWzqot +aK8KgWU6cMGbrU1tVMoqLUuFG7OA5nBFDWteNfB/O7ic5ARwiRIlk9oKmSJgamNg +TnYGmE69g60dWIolhdLHZR4tjsbftsbhf4oEIRUpdPA+nJCdDC7xij5aqgwJHsfV +PKPtl8MeNPo4+QgO48BdK4PRVmrJtqhUUy54Mmc9gn900PvhtgVguXDbjgv5E1hv +cWAQUhC5wUEJ73IfZzF4/5YFjQIDAQABo2MwYTAfBgNVHSMEGDAWgBTj/i39KNAL +tbq2osS/BqoFjJP7LzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAd +BgNVHQ4EFgQU4/4t/SjQC7W6tqLEvwaqBYyT+y8wDQYJKoZIhvcNAQELBQADggIB +ACXGumvrh8vegjmWPfBEp2uEcwPenStPuiB/vHiyz5ewG5zz13ku9Ui20vsXiObT +ej/tUxPQ4i9qecsAIyjmHjdXNYmEwnZPNDatZ8POQQaIxffu2Bq41gt/UP+TqhdL +jOztUmCypAbqTuv0axn96/Ua4CUqmtzHQTb3yHQFhDmVOdYLO6Qn+gjYXB74BGBS +ESgoA//vU2YApUo0FmZ8/Qmkrp5nGm9BC2sGE5uPhnEFtC+NiWYzKXZUmhH4J/qy +P5Hgzg0b8zAarb8iXRvTvyUFTeGSGn+ZnzxEk8rUQElsgIfXBDrDMlI1Dlb4pd19 +xIsNER9Tyx6yF7Zod1rg1MvIB671Oi6ON7fQAUtDKXeMOZePglr4UeWJoBjnaH9d +Ci77o0cOPaYjesYBx4/IXr9tgFa+iiS6M+qf4TIRnvHST4D2G0CvOJ4RUHlzEhLN +5mydLIhyPDCBBpEi6lmt2hkuIsKNuYyH4Ga8cyNfIWRjgEj1oDwYPZTISEEdQLpe +/v5WOaHIz16eGWRGENoXkbcFgKyLmZJ956LYBws2J+dIeWCKw9cTXPhyQN9Ky8+Z +AAoACxGV2lZFA4gKn2fQ1XmxqI1AbQ3CekD6819kR5LLU7m7Wc5P/dAVUwHY3+vZ +5nbv0CO7O6l5s9UCKc2Jo5YPSjXnTkLAdc0Hz+Ys63su +-----END CERTIFICATE----- + +TÜRKTRUST Elektronik Sertifika Hizmet Sağlayıcısı H5 +# Fingerprint (SHA1): C4:18:F6:4D:46:D1:DF:00:3D:27:30:13:72:43:A9:12:11:C6:75:FB +TRUSTED_DELEGATOR: SERVER_AUTH +MUST_VERIFY_TRUST: EMAIL_PROTECTION, CODE_SIGNING +==================================================== +MD5 Fingerprint=DA:70:8E:F0:22:DF:93:26:F6:5F:9F:D3:15:06:52:4E +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 156233699172481 (0x8e17fe242081) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=TR, L=Ankara, O=T\xC3\x9CRKTRUST Bilgi \xC4\xB0leti\xC5\x9Fim ve Bili\xC5\x9Fim G\xC3\xBCvenli\xC4\x9Fi Hizmetleri A.\xC5\x9E., CN=T\xC3\x9CRKTRUST Elektronik Sertifika Hizmet Sa\xC4\x9Flay\xC4\xB1c\xC4\xB1s\xC4\xB1 H5 + Validity + Not Before: Apr 30 08:07:01 2013 GMT + Not After : Apr 28 08:07:01 2023 GMT + Subject: C=TR, L=Ankara, O=T\xC3\x9CRKTRUST Bilgi \xC4\xB0leti\xC5\x9Fim ve Bili\xC5\x9Fim G\xC3\xBCvenli\xC4\x9Fi Hizmetleri A.\xC5\x9E., CN=T\xC3\x9CRKTRUST Elektronik Sertifika Hizmet Sa\xC4\x9Flay\xC4\xB1c\xC4\xB1s\xC4\xB1 H5 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:a4:25:19:e1:65:9e:eb:48:21:50:4a:08:e5:11: + f0:5a:ba:26:ff:83:59:ce:44:2a:2f:fe:e1:ce:60: + 03:fc:8d:03:a5:ed:ff:6b:a8:ba:cc:34:06:9f:59: + 35:f6:ec:2c:bb:9d:fb:8d:52:69:e3:9c:27:10:53: + f3:a4:02:c5:a7:f9:11:1a:69:75:6e:c3:1d:8b:d1: + 98:8d:93:87:a7:71:97:0d:21:c7:99:f9:52:d3:2c: + 63:5d:55:bc:e8:1f:01:48:b9:60:fe:42:4a:f6:c8: + 80:ae:cd:66:7a:9e:45:8a:68:77:e2:48:68:9f:a2: + da:f1:e1:c1:10:9f:eb:3c:29:81:a7:e1:32:08:d4: + a0:05:b1:8c:fb:8d:96:00:0e:3e:25:df:53:86:22: + 3b:fc:f4:bd:f3:09:7e:77:ec:86:eb:0f:33:e5:43: + 4f:f4:54:75:6d:29:99:2e:66:5a:43:df:cb:5c:ca: + c8:e5:38:f1:7e:3b:35:9d:0f:f4:c5:5a:a1:cc:f3: + 20:80:24:d3:57:ec:15:ba:75:25:9b:e8:64:4b:b3: + 34:84:ef:04:b8:f6:c9:6c:aa:02:3e:b6:55:e2:32: + 37:5f:fc:66:97:5f:cd:d6:9e:c7:20:bf:4d:c6:ac: + 3f:75:5f:1c:ed:32:9c:7c:69:00:69:91:e3:23:18: + 53:e9 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + 56:99:07:1E:D3:AC:0C:69:64:B4:0C:50:47:DE:43:2C:BE:20:C0:FB + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + Signature Algorithm: sha256WithRSAEncryption + 9e:45:76:7b:17:48:32:f2:38:8b:29:bd:ee:96:4a:4e:81:18: + b1:51:47:20:cd:d0:64:b1:0e:c9:d9:01:d9:09:ce:c8:99:dc: + 68:25:13:d4:5c:f2:a3:e8:04:fe:72:09:c7:0b:aa:1d:25:55: + 7e:96:9a:57:b7:ba:c5:11:7a:19:e6:a7:7e:3d:85:0e:f5:f9: + 2e:29:2f:e7:f9:6c:58:16:57:50:25:f6:3e:2e:3e:aa:ed:77: + 71:aa:aa:99:96:46:0a:ae:8e:ec:2a:51:16:b0:5e:cd:ea:67: + 04:1c:58:30:f5:60:8a:bd:a6:bd:4d:e5:96:b4:fc:42:89:01: + 6b:f6:70:c8:50:39:0c:2d:d5:66:d9:c8:d2:b3:32:b7:1b:19: + 6d:cb:33:f9:df:a5:e6:15:84:37:f0:c2:f2:65:96:92:90:77: + f0:ad:f4:90:e9:11:78:d7:93:89:c0:3d:0b:ba:29:f4:e8:99: + 9d:72:8e:ed:9d:2f:ee:92:7d:a1:f1:ff:5d:ba:33:60:85:62: + fe:07:02:a1:84:56:46:be:96:0a:9a:13:d7:21:4c:b7:7c:07: + 9f:4e:4e:3f:91:74:fb:27:9d:11:cc:dd:e6:b1:ca:71:4d:13: + 17:39:26:c5:29:21:2b:93:29:6a:96:fa:ab:41:e1:4b:b6:35: + 0b:c0:9b:15 +-----BEGIN CERTIFICATE----- +MIIEJzCCAw+gAwIBAgIHAI4X/iQggTANBgkqhkiG9w0BAQsFADCBsTELMAkGA1UE +BhMCVFIxDzANBgNVBAcMBkFua2FyYTFNMEsGA1UECgxEVMOcUktUUlVTVCBCaWxn +aSDEsGxldGnFn2ltIHZlIEJpbGnFn2ltIEfDvHZlbmxpxJ9pIEhpem1ldGxlcmkg +QS7Fni4xQjBABgNVBAMMOVTDnFJLVFJVU1QgRWxla3Ryb25payBTZXJ0aWZpa2Eg +SGl6bWV0IFNhxJ9sYXnEsWPEsXPEsSBINTAeFw0xMzA0MzAwODA3MDFaFw0yMzA0 +MjgwODA3MDFaMIGxMQswCQYDVQQGEwJUUjEPMA0GA1UEBwwGQW5rYXJhMU0wSwYD +VQQKDERUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmlsacWfaW0gR8O8 +dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLjFCMEAGA1UEAww5VMOcUktUUlVTVCBF +bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxIEg1MIIB +IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApCUZ4WWe60ghUEoI5RHwWrom +/4NZzkQqL/7hzmAD/I0Dpe3/a6i6zDQGn1k19uwsu537jVJp45wnEFPzpALFp/kR +Gml1bsMdi9GYjZOHp3GXDSHHmflS0yxjXVW86B8BSLlg/kJK9siArs1mep5Fimh3 +4khon6La8eHBEJ/rPCmBp+EyCNSgBbGM+42WAA4+Jd9ThiI7/PS98wl+d+yG6w8z +5UNP9FR1bSmZLmZaQ9/LXMrI5Tjxfjs1nQ/0xVqhzPMggCTTV+wVunUlm+hkS7M0 +hO8EuPbJbKoCPrZV4jI3X/xml1/N1p7HIL9Nxqw/dV8c7TKcfGkAaZHjIxhT6QID +AQABo0IwQDAdBgNVHQ4EFgQUVpkHHtOsDGlktAxQR95DLL4gwPswDgYDVR0PAQH/ +BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAJ5FdnsX +SDLyOIspve6WSk6BGLFRRyDN0GSxDsnZAdkJzsiZ3GglE9Rc8qPoBP5yCccLqh0l +VX6Wmle3usURehnmp349hQ71+S4pL+f5bFgWV1Al9j4uPqrtd3GqqpmWRgqujuwq +URawXs3qZwQcWDD1YIq9pr1N5Za0/EKJAWv2cMhQOQwt1WbZyNKzMrcbGW3LM/nf +peYVhDfwwvJllpKQd/Ct9JDpEXjXk4nAPQu6KfTomZ1yju2dL+6SfaHx/126M2CF +Yv4HAqGEVka+lgqaE9chTLd8B59OTj+RdPsnnRHM3eaxynFNExc5JsUpISuTKWqW ++qtB4Uu2NQvAmxU= +-----END CERTIFICATE----- + +Certinomis - Root CA +# Fingerprint (SHA1): 9D:70:BB:01:A5:A4:A0:18:11:2E:F7:1C:01:B9:32:C5:34:E7:88:A8 +MUST_VERIFY_TRUST: EMAIL_PROTECTION, CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH +================================================= +MD5 Fingerprint=14:0A:FD:8D:A8:28:B5:38:69:DB:56:7E:61:22:03:3F +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 1 (0x1) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=FR, O=Certinomis, OU=0002 433998903, CN=Certinomis - Root CA + Validity + Not Before: Oct 21 09:17:18 2013 GMT + Not After : Oct 21 09:17:18 2033 GMT + Subject: C=FR, O=Certinomis, OU=0002 433998903, CN=Certinomis - Root CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:d4:cc:09:0a:2c:3f:92:f6:7f:14:9e:0b:9c:9a: + 6a:1d:40:30:64:fd:aa:df:0e:1e:06:5b:9f:50:85: + ea:cd:8d:ab:43:67:de:b0:fa:7e:80:96:9e:84:78: + 92:48:d6:e3:39:ee:ce:e4:59:58:97:e5:2e:27:98: + ea:93:a8:77:9b:4a:f0:ef:74:80:2d:eb:30:1f:b5: + d9:c7:80:9c:62:27:91:88:f0:4a:89:dd:dc:88:e6: + 14:f9:d5:03:2f:ff:95:db:bd:9f:ec:2c:fa:14:15: + 59:95:0a:c6:47:7c:69:18:b9:a7:03:f9:ca:76:a9: + cf:c7:6f:b4:5e:05:fe:ee:c1:52:b2:75:32:87:ec: + ed:29:66:3b:f3:4a:16:82:f6:d6:9a:db:72:98:e9: + de:f0:c5:4c:a5:ab:b5:ea:01:e2:8c:2e:64:7f:64: + 6f:fd:a3:25:93:8b:c8:a2:0e:49:8d:34:f0:1f:ec: + 58:45:2e:34:aa:84:50:bd:e7:b2:4a:13:b8:b0:0f: + ae:38:5d:b0:a9:1b:e6:73:c9:5a:a1:d9:66:40:aa: + a9:4d:a6:34:02:ad:84:7e:b2:23:c1:fb:2a:c6:67: + f4:34:b6:b0:95:6a:33:4f:71:44:b5:ad:c0:79:33: + 88:e0:bf:ed:a3:a0:14:b4:9c:09:b0:0a:e3:60:be: + f8:f8:66:88:cd:5b:f1:77:05:e0:b5:73:6e:c1:7d: + 46:2e:8e:4b:27:a6:cd:35:0a:fd:e5:4d:7d:aa:2a: + a3:29:c7:5a:68:04:e8:e5:d6:93:a4:62:c2:c5:e6: + f4:4f:c6:f9:9f:1a:8d:82:49:19:8a:ca:59:43:3a: + e8:0d:32:c1:f4:4c:13:03:6f:6e:a6:3f:91:73:cb: + ca:73:6f:12:20:8b:ee:c0:82:78:de:4b:2e:c2:49: + c3:1d:ed:16:f6:24:f4:27:1b:5c:57:31:dc:55:ee: + a8:1e:6f:6c:ac:e2:45:cc:57:57:8a:75:57:19:e0: + b5:58:99:49:36:31:3c:33:01:6d:16:4a:cd:b8:2a: + 83:84:86:9b:f9:60:d2:1f:6d:91:03:d3:60:a6:d5: + 3d:9a:dd:77:90:3d:35:a4:9f:0f:5e:f5:52:44:69: + b9:c0:ba:dc:cf:7d:df:7c:d9:c4:ac:86:22:32:bc: + 7b:6b:91:ef:7a:f8:17:68:b0:e2:53:55:60:2d:af: + 3e:c2:83:d8:d9:09:2b:f0:c0:64:db:87:8b:91:cc: + 91:eb:04:fd:76:b4:95:9a:e6:14:06:1b:d5:34:1d: + be:d8:ff:74:1c:53:85:99:e0:59:52:4a:61:ed:88: + 9e:6b:49:89:46:7e:20:5a:d9:e7:4a:e5:6a:ee:d2: + 65:11:43 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + EF:91:4C:F5:A5:C3:30:E8:2F:08:EA:D3:71:22:A4:92:68:78:74:D9 + X509v3 Authority Key Identifier: + keyid:EF:91:4C:F5:A5:C3:30:E8:2F:08:EA:D3:71:22:A4:92:68:78:74:D9 + + Signature Algorithm: sha256WithRSAEncryption + 7e:3d:54:da:22:5d:1a:58:3e:3b:54:27:ba:ba:cc:c8:e3:1a: + 6a:ea:3e:f9:12:eb:56:5f:3d:50:ce:e0:ea:48:26:26:cf:79: + 56:7e:91:1c:99:3f:d0:a1:91:1c:2c:0f:4f:98:95:59:53:bd: + d0:22:d8:88:5d:9c:37:fc:fb:64:c1:78:8c:8b:9a:60:09:ea: + d5:fa:21:5f:d0:74:65:e7:50:c5:bf:2e:b9:0b:0b:ad:b5:b0: + 17:a6:12:8c:d4:62:78:ea:56:6a:ec:0a:d2:40:c3:3c:05:30: + 3e:4d:94:b7:9f:4a:03:d3:7d:27:4b:b6:fe:44:ce:fa:19:33: + 1a:6d:a4:42:d1:dd:cc:c8:c8:d7:16:52:83:4f:35:94:b3:12: + 55:7d:e5:e2:42:eb:e4:9c:93:09:c0:4c:5b:07:ab:c7:6d:11: + a0:50:17:94:23:a8:b5:0a:92:0f:b2:7a:c1:60:2c:38:cc:1a: + a6:5b:ff:f2:0c:e3:aa:1f:1c:dc:b8:a0:93:27:de:63:e3:7f: + 21:9f:3a:e5:9e:fa:e0:13:6a:75:eb:96:5c:62:91:94:8e:67: + 53:b6:89:f8:12:09:cb:6f:52:5b:03:72:86:50:95:08:d4:8d: + 87:86:15:1f:95:24:d8:a4:6f:9a:ce:a4:9d:9b:6d:d2:b2:76: + 06:86:c6:56:08:c5:eb:09:da:36:c2:1b:5b:41:be:61:2a:e3: + 70:e6:b8:a6:f8:b6:5a:c4:bd:21:f7:ff:aa:5f:a1:6c:76:39: + 66:d6:ea:4c:55:e1:00:33:9b:13:98:63:c9:6f:d0:01:20:09: + 37:52:e7:0c:4f:3e:cd:bc:f5:5f:96:27:a7:20:02:95:e0:2e: + e8:07:41:05:1f:15:6e:d6:b0:e4:19:e0:0f:02:93:00:27:72: + c5:8b:d1:54:1f:5d:4a:c3:40:97:7e:55:a6:7c:c1:33:04:14: + 01:1d:49:20:69:0b:19:93:9d:6e:58:22:f7:40:0c:46:0c:23: + 63:f3:39:d2:7f:76:51:a7:f4:c8:a1:f1:0c:76:22:23:46:52: + 29:2d:e2:a3:41:07:56:69:98:d2:05:09:bc:69:c7:5a:61:cd: + 8f:81:60:15:4d:80:dd:90:e2:7d:c4:50:f2:8c:3b:6e:4a:c7: + c6:e6:80:2b:3c:81:bc:11:80:16:10:27:d7:f0:cd:3f:79:cc: + 73:2a:c3:7e:53:91:d6:6e:f8:f5:f3:c7:d0:51:4d:8e:4b:a5: + 5b:e6:19:17:3b:d6:81:09:dc:22:dc:ee:8e:b9:c4:8f:53:e1: + 67:bb:33:b8:88:15:46:cf:ed:69:35:ff:75:0d:46:f3:ce:71: + e1:c5:6b:86:42:06:b9:41 +-----BEGIN CERTIFICATE----- +MIIFkjCCA3qgAwIBAgIBATANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJGUjET +MBEGA1UEChMKQ2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxHTAb +BgNVBAMTFENlcnRpbm9taXMgLSBSb290IENBMB4XDTEzMTAyMTA5MTcxOFoXDTMz +MTAyMTA5MTcxOFowWjELMAkGA1UEBhMCRlIxEzARBgNVBAoTCkNlcnRpbm9taXMx +FzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMR0wGwYDVQQDExRDZXJ0aW5vbWlzIC0g +Um9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANTMCQosP5L2 +fxSeC5yaah1AMGT9qt8OHgZbn1CF6s2Nq0Nn3rD6foCWnoR4kkjW4znuzuRZWJfl +LieY6pOod5tK8O90gC3rMB+12ceAnGInkYjwSond3IjmFPnVAy//ldu9n+ws+hQV +WZUKxkd8aRi5pwP5ynapz8dvtF4F/u7BUrJ1Mofs7SlmO/NKFoL21prbcpjp3vDF +TKWrteoB4owuZH9kb/2jJZOLyKIOSY008B/sWEUuNKqEUL3nskoTuLAPrjhdsKkb +5nPJWqHZZkCqqU2mNAKthH6yI8H7KsZn9DS2sJVqM09xRLWtwHkziOC/7aOgFLSc +CbAK42C++PhmiM1b8XcF4LVzbsF9Ri6OSyemzTUK/eVNfaoqoynHWmgE6OXWk6Ri +wsXm9E/G+Z8ajYJJGYrKWUM66A0ywfRMEwNvbqY/kXPLynNvEiCL7sCCeN5LLsJJ +wx3tFvYk9CcbXFcx3FXuqB5vbKziRcxXV4p1VxngtViZSTYxPDMBbRZKzbgqg4SG +m/lg0h9tkQPTYKbVPZrdd5A9NaSfD171UkRpucC63M9933zZxKyGIjK8e2uR73r4 +F2iw4lNVYC2vPsKD2NkJK/DAZNuHi5HMkesE/Xa0lZrmFAYb1TQdvtj/dBxThZng +WVJKYe2InmtJiUZ+IFrZ50rlau7SZRFDAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIB +BjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTvkUz1pcMw6C8I6tNxIqSSaHh0 +2TAfBgNVHSMEGDAWgBTvkUz1pcMw6C8I6tNxIqSSaHh02TANBgkqhkiG9w0BAQsF +AAOCAgEAfj1U2iJdGlg+O1QnurrMyOMaauo++RLrVl89UM7g6kgmJs95Vn6RHJk/ +0KGRHCwPT5iVWVO90CLYiF2cN/z7ZMF4jIuaYAnq1fohX9B0ZedQxb8uuQsLrbWw +F6YSjNRieOpWauwK0kDDPAUwPk2Ut59KA9N9J0u2/kTO+hkzGm2kQtHdzMjI1xZS +g081lLMSVX3l4kLr5JyTCcBMWwerx20RoFAXlCOotQqSD7J6wWAsOMwaplv/8gzj +qh8c3LigkyfeY+N/IZ865Z764BNqdeuWXGKRlI5nU7aJ+BIJy29SWwNyhlCVCNSN +h4YVH5Uk2KRvms6knZtt0rJ2BobGVgjF6wnaNsIbW0G+YSrjcOa4pvi2WsS9Iff/ +ql+hbHY5ZtbqTFXhADObE5hjyW/QASAJN1LnDE8+zbz1X5YnpyACleAu6AdBBR8V +btaw5BngDwKTACdyxYvRVB9dSsNAl35VpnzBMwQUAR1JIGkLGZOdblgi90AMRgwj +Y/M50n92Uaf0yKHxDHYiI0ZSKS3io0EHVmmY0gUJvGnHWmHNj4FgFU2A3ZDifcRQ +8ow7bkrHxuaAKzyBvBGAFhAn1/DNP3nMcyrDflOR1m749fPH0FFNjkulW+YZFzvW +gQncItzujrnEj1PhZ7szuIgVRs/taTX/dQ1G885x4cVrhkIGuUE= +-----END CERTIFICATE----- + +OISTE WISeKey Global Root GB CA +# Fingerprint (SHA1): 0F:F9:40:76:18:D3:D7:6A:4B:98:F0:A8:35:9E:0C:FD:27:AC:CC:ED +MUST_VERIFY_TRUST: CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +================================================ +MD5 Fingerprint=A4:EB:B9:61:28:2E:B7:2F:98:B0:35:26:90:99:51:1D +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 76:b1:20:52:74:f0:85:87:46:b3:f8:23:1a:f6:c2:c0 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=CH, O=WISeKey, OU=OISTE Foundation Endorsed, CN=OISTE WISeKey Global Root GB CA + Validity + Not Before: Dec 1 15:00:32 2014 GMT + Not After : Dec 1 15:10:31 2039 GMT + Subject: C=CH, O=WISeKey, OU=OISTE Foundation Endorsed, CN=OISTE WISeKey Global Root GB CA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:d8:17:b7:1c:4a:24:2a:d6:97:b1:ca:e2:1e:fb: + 7d:38:ef:98:f5:b2:39:98:4e:27:b8:11:5d:7b:d2: + 25:94:88:82:15:26:6a:1b:31:bb:a8:5b:21:21:2b: + d8:0f:4e:9f:5a:f1:b1:5a:e4:79:d6:32:23:2b:e1: + 53:cc:99:45:5c:7b:4f:ad:bc:bf:87:4a:0b:4b:97: + 5a:a8:f6:48:ec:7d:7b:0d:cd:21:06:df:9e:15:fd: + 41:8a:48:b7:20:f4:a1:7a:1b:57:d4:5d:50:ff:ba: + 67:d8:23:99:1f:c8:3f:e3:de:ff:6f:5b:77:b1:6b: + 6e:b8:c9:64:f7:e1:ca:41:46:0e:29:71:d0:b9:23: + fc:c9:81:5f:4e:f7:6f:df:bf:84:ad:73:64:bb:b7: + 42:8e:69:f6:d4:76:1d:7e:9d:a7:b8:57:8a:51:67: + 72:d7:d4:a8:b8:95:54:40:73:03:f6:ea:f4:eb:fe: + 28:42:77:3f:9d:23:1b:b2:b6:3d:80:14:07:4c:2e: + 4f:f7:d5:0a:16:0d:bd:66:43:37:7e:23:43:79:c3: + 40:86:f5:4c:29:da:8e:9a:ad:0d:a5:04:87:88:1e: + 85:e3:e9:53:d5:9b:c8:8b:03:63:78:eb:e0:19:4a: + 6e:bb:2f:6b:33:64:58:93:ad:69:bf:8f:1b:ef:82: + 48:c7 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: + Digital Signature, Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + 35:0F:C8:36:63:5E:E2:A3:EC:F9:3B:66:15:CE:51:52:E3:91:9A:3D + 1.3.6.1.4.1.311.21.1: + ... + Signature Algorithm: sha256WithRSAEncryption + 40:4c:fb:87:b2:99:81:90:7e:9d:c5:b0:b0:26:cd:88:7b:2b: + 32:8d:6e:b8:21:71:58:97:7d:ae:37:14:af:3e:e7:f7:9a:e2: + 7d:f6:71:98:99:04:aa:43:74:78:a3:e3:49:61:3e:73:8c:4d: + 94:e0:f9:71:c4:b6:16:0e:53:78:1f:d6:a2:87:2f:02:39:81: + 29:3c:af:15:98:21:30:fe:28:90:00:8c:d1:e1:cb:fa:5e:c8: + fd:f8:10:46:3b:a2:78:42:91:17:74:55:0a:de:50:67:4d:66: + d1:a7:ff:fd:d9:c0:b5:a8:a3:8a:ce:66:f5:0f:43:cd:a7:2b: + 57:7b:63:46:6a:aa:2e:52:d8:f4:ed:e1:6d:ad:29:90:78:48: + ba:e1:23:aa:a3:89:ec:b5:ab:96:c0:b4:4b:a2:1d:97:9e:7a: + f2:6e:40:71:df:68:f1:65:4d:ce:7c:05:df:53:65:a9:a5:f0: + b1:97:04:70:15:46:03:98:d4:d2:bf:54:b4:a0:58:7d:52:6f: + da:56:26:62:d4:d8:db:89:31:6f:1c:f0:22:c2:d3:62:1c:35: + cd:4c:69:15:54:1a:90:98:de:eb:1e:5f:ca:77:c7:cb:8e:3d: + 43:69:9c:9a:58:d0:24:3b:df:1b:40:96:7e:35:ad:81:c7:4e: + 71:ba:88:13 +-----BEGIN CERTIFICATE----- +MIIDtTCCAp2gAwIBAgIQdrEgUnTwhYdGs/gjGvbCwDANBgkqhkiG9w0BAQsFADBt +MQswCQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUg +Rm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9i +YWwgUm9vdCBHQiBDQTAeFw0xNDEyMDExNTAwMzJaFw0zOTEyMDExNTEwMzFaMG0x +CzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQLExlPSVNURSBG +b3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2Jh +bCBSb290IEdCIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2Be3 +HEokKtaXscriHvt9OO+Y9bI5mE4nuBFde9IllIiCFSZqGzG7qFshISvYD06fWvGx +WuR51jIjK+FTzJlFXHtPrby/h0oLS5daqPZI7H17Dc0hBt+eFf1Biki3IPShehtX +1F1Q/7pn2COZH8g/497/b1t3sWtuuMlk9+HKQUYOKXHQuSP8yYFfTvdv37+ErXNk +u7dCjmn21HYdfp2nuFeKUWdy19SouJVUQHMD9ur06/4oQnc/nSMbsrY9gBQHTC5P +99UKFg29ZkM3fiNDecNAhvVMKdqOmq0NpQSHiB6F4+lT1ZvIiwNjeOvgGUpuuy9r +M2RYk61pv48b74JIxwIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQUNQ/INmNe4qPs+TtmFc5RUuORmj0wEAYJKwYBBAGCNxUB +BAMCAQAwDQYJKoZIhvcNAQELBQADggEBAEBM+4eymYGQfp3FsLAmzYh7KzKNbrgh +cViXfa43FK8+5/ea4n32cZiZBKpDdHij40lhPnOMTZTg+XHEthYOU3gf1qKHLwI5 +gSk8rxWYITD+KJAAjNHhy/peyP34EEY7onhCkRd0VQreUGdNZtGn//3ZwLWoo4rO +ZvUPQ82nK1d7Y0Zqqi5S2PTt4W2tKZB4SLrhI6qjiey1q5bAtEuiHZeeevJuQHHf +aPFlTc58Bd9TZaml8LGXBHAVRgOY1NK/VLSgWH1Sb9pWJmLU2NuJMW8c8CLC02Ic +Nc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM= +-----END CERTIFICATE----- + +SZAFIR ROOT CA2 +# Fingerprint (SHA1): E2:52:FA:95:3F:ED:DB:24:60:BD:6E:28:F3:9C:CC:CF:5E:B3:3F:DE +MUST_VERIFY_TRUST: CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +================================================ +MD5 Fingerprint=11:64:C1:89:B0:24:B1:8C:B1:07:7E:89:9E:51:9E:99 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 3e:8a:5d:07:ec:55:d2:32:d5:b7:e3:b6:5f:01:eb:2d:dc:e4:d6:e4 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=PL, O=Krajowa Izba Rozliczeniowa S.A., CN=SZAFIR ROOT CA2 + Validity + Not Before: Oct 19 07:43:30 2015 GMT + Not After : Oct 19 07:43:30 2035 GMT + Subject: C=PL, O=Krajowa Izba Rozliczeniowa S.A., CN=SZAFIR ROOT CA2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:b7:bc:3e:50:a8:4b:cd:40:b5:ce:61:e7:96:ca: + b4:a1:da:0c:22:b0:fa:b5:7b:76:00:77:8c:0b:cf: + 7d:a8:86:cc:26:51:e4:20:3d:85:0c:d6:58:e3:e7: + f4:2a:18:9d:da:d1:ae:26:ee:eb:53:dc:f4:90:d6: + 13:4a:0c:90:3c:c3:f4:da:d2:8e:0d:92:3a:dc:b1: + b1:ff:38:de:c3:ba:2d:5f:80:b9:02:bd:4a:9d:1b: + 0f:b4:c3:c2:c1:67:03:dd:dc:1b:9c:3d:b3:b0:de: + 00:1e:a8:34:47:bb:9a:eb:fe:0b:14:bd:36:84:da: + 0d:20:bf:fa:5b:cb:a9:16:20:ad:39:60:ee:2f:75: + b6:e7:97:9c:f9:3e:fd:7e:4d:6f:4d:2f:ef:88:0d: + 6a:fa:dd:f1:3d:6e:20:a5:a0:12:b4:4d:70:b9:ce: + d7:72:3b:89:93:a7:80:84:1c:27:49:72:49:b5:ff: + 3b:95:9e:c1:cc:c8:01:ec:e8:0e:8a:0a:96:e7:b3: + a6:87:e5:d6:f9:05:2b:0d:97:40:70:3c:ba:ac:75: + 5a:9c:d5:4d:9d:02:0a:d2:4b:9b:66:4b:46:07:17: + 65:ad:9f:6c:88:00:dc:22:89:e0:e1:64:d4:67:bc: + 31:79:61:3c:bb:ca:41:cd:5c:6a:00:c8:3c:38:8e: + 58:af + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 2E:16:A9:4A:18:B5:CB:CC:F5:6F:50:F3:23:5F:F8:5D:E7:AC:F0:C8 + Signature Algorithm: sha256WithRSAEncryption + b5:73:f8:03:dc:59:5b:1d:76:e9:a3:2a:7b:90:28:b2:4d:c0: + 33:4f:aa:9a:b1:d4:b8:e4:27:ff:a9:96:99:ce:46:e0:6d:7c: + 4c:a2:38:a4:06:70:f0:f4:41:11:ec:3f:47:8d:3f:72:87:f9: + 3b:fd:a4:6f:2b:53:00:e0:ff:39:b9:6a:07:0e:eb:1d:1c:f6: + a2:72:90:cb:82:3d:11:82:8b:d2:bb:9f:2a:af:21:e6:63:86: + 9d:79:19:ef:f7:bb:0c:35:90:c3:8a:ed:4f:0f:f5:cc:12:d9: + a4:3e:bb:a0:fc:20:95:5f:4f:26:2f:11:23:83:4e:75:07:0f: + bf:9b:d1:b4:1d:e9:10:04:fe:ca:60:8f:a2:4c:b8:ad:cf:e1: + 90:0f:cd:ae:0a:c7:5d:7b:b7:50:d2:d4:61:fa:d5:15:db:d7: + 9f:87:51:54:eb:a5:e3:eb:c9:85:a0:25:20:37:fb:8e:ce:0c: + 34:84:e1:3c:81:b2:77:4e:43:a5:88:5f:86:67:a1:3d:e6:b4: + 5c:61:b6:3e:db:fe:b7:28:c5:a2:07:ae:b5:ca:ca:8d:2a:12: + ef:97:ed:c2:30:a4:c9:2a:7a:fb:f3:4d:23:1b:99:33:34:a0: + 2e:f5:a9:0b:3f:d4:5d:e1:cf:84:9f:e2:19:c2:5f:8a:d6:20: + 1e:e3:73:b7 +-----BEGIN CERTIFICATE----- +MIIDcjCCAlqgAwIBAgIUPopdB+xV0jLVt+O2XwHrLdzk1uQwDQYJKoZIhvcNAQEL +BQAwUTELMAkGA1UEBhMCUEwxKDAmBgNVBAoMH0tyYWpvd2EgSXpiYSBSb3psaWN6 +ZW5pb3dhIFMuQS4xGDAWBgNVBAMMD1NaQUZJUiBST09UIENBMjAeFw0xNTEwMTkw +NzQzMzBaFw0zNTEwMTkwNzQzMzBaMFExCzAJBgNVBAYTAlBMMSgwJgYDVQQKDB9L +cmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMRgwFgYDVQQDDA9TWkFGSVIg +Uk9PVCBDQTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3vD5QqEvN +QLXOYeeWyrSh2gwisPq1e3YAd4wLz32ohswmUeQgPYUM1ljj5/QqGJ3a0a4m7utT +3PSQ1hNKDJA8w/Ta0o4NkjrcsbH/ON7Dui1fgLkCvUqdGw+0w8LBZwPd3BucPbOw +3gAeqDRHu5rr/gsUvTaE2g0gv/pby6kWIK05YO4vdbbnl5z5Pv1+TW9NL++IDWr6 +3fE9biCloBK0TXC5ztdyO4mTp4CEHCdJckm1/zuVnsHMyAHs6A6KCpbns6aH5db5 +BSsNl0BwPLqsdVqc1U2dAgrSS5tmS0YHF2Wtn2yIANwiieDhZNRnvDF5YTy7ykHN +XGoAyDw4jlivAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD +AgEGMB0GA1UdDgQWBBQuFqlKGLXLzPVvUPMjX/hd56zwyDANBgkqhkiG9w0BAQsF +AAOCAQEAtXP4A9xZWx126aMqe5Aosk3AM0+qmrHUuOQn/6mWmc5G4G18TKI4pAZw +8PRBEew/R40/cof5O/2kbytTAOD/OblqBw7rHRz2onKQy4I9EYKL0rufKq8h5mOG +nXkZ7/e7DDWQw4rtTw/1zBLZpD67oPwglV9PJi8RI4NOdQcPv5vRtB3pEAT+ymCP +oky4rc/hkA/NrgrHXXu3UNLUYfrVFdvXn4dRVOul4+vJhaAlIDf7js4MNIThPIGy +d05DpYhfhmehPea0XGG2Ptv+tyjFogeutcrKjSoS75ftwjCkySp6+/NNIxuZMzSg +LvWpCz/UXeHPhJ/iGcJfitYgHuNztw== +-----END CERTIFICATE----- + +Certum Trusted Network CA 2 +# Fingerprint (SHA1): D3:DD:48:3E:2B:BF:4C:05:E8:AF:10:F5:FA:76:26:CF:D3:DC:30:92 +MUST_VERIFY_TRUST: CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +================================================ +MD5 Fingerprint=6D:46:9E:D9:25:6D:08:23:5B:5E:74:7D:1E:27:DB:F2 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 21:d6:d0:4a:4f:25:0f:c9:32:37:fc:aa:5e:12:8d:e9 + Signature Algorithm: sha512WithRSAEncryption + Issuer: C=PL, O=Unizeto Technologies S.A., OU=Certum Certification Authority, CN=Certum Trusted Network CA 2 + Validity + Not Before: Oct 6 08:39:56 2011 GMT + Not After : Oct 6 08:39:56 2046 GMT + Subject: C=PL, O=Unizeto Technologies S.A., OU=Certum Certification Authority, CN=Certum Trusted Network CA 2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:bd:f9:78:f8:e6:d5:80:0c:64:9d:86:1b:96:64: + 67:3f:22:3a:1e:75:01:7d:ef:fb:5c:67:8c:c9:cc: + 5c:6b:a9:91:e6:b9:42:e5:20:4b:9b:da:9b:7b:b9: + 99:5d:d9:9b:80:4b:d7:84:40:2b:27:d3:e8:ba:30: + bb:3e:09:1a:a7:49:95:ef:2b:40:24:c2:97:c7:a7: + ee:9b:25:ef:a8:0a:00:97:85:5a:aa:9d:dc:29:c9: + e2:35:07:eb:70:4d:4a:d6:c1:b3:56:b8:a1:41:38: + 9b:d1:fb:31:7f:8f:e0:5f:e1:b1:3f:0f:8e:16:49: + 60:d7:06:8d:18:f9:aa:26:10:ab:2a:d3:d0:d1:67: + 8d:1b:46:be:47:30:d5:2e:72:d1:c5:63:da:e7:63: + 79:44:7e:4b:63:24:89:86:2e:34:3f:29:4c:52:8b: + 2a:a7:c0:e2:91:28:89:b9:c0:5b:f9:1d:d9:e7:27: + ad:ff:9a:02:97:c1:c6:50:92:9b:02:2c:bd:a9:b9: + 34:59:0a:bf:84:4a:ff:df:fe:b3:9f:eb:d9:9e:e0: + 98:23:ec:a6:6b:77:16:2a:db:cc:ad:3b:1c:a4:87: + dc:46:73:5e:19:62:68:45:57:e4:90:82:42:bb:42: + d6:f0:61:e0:c1:a3:3d:66:a3:5d:f4:18:ee:88:c9: + 8d:17:45:29:99:32:75:02:31:ee:29:26:c8:6b:02: + e6:b5:62:45:7f:37:15:5a:23:68:89:d4:3e:de:4e: + 27:b0:f0:40:0c:bc:4d:17:cb:4d:a2:b3:1e:d0:06: + 5a:dd:f6:93:cf:57:75:99:f5:fa:86:1a:67:78:b3: + bf:96:fe:34:dc:bd:e7:52:56:e5:b3:e5:75:7b:d7: + 41:91:05:dc:5d:69:e3:95:0d:43:b9:fc:83:96:39: + 95:7b:6c:80:5a:4f:13:72:c6:d7:7d:29:7a:44:ba: + 52:a4:2a:d5:41:46:09:20:fe:22:a0:b6:5b:30:8d: + bc:89:0c:d5:d7:70:f8:87:52:fd:da:ef:ac:51:2e: + 07:b3:4e:fe:d0:09:da:70:ef:98:fa:56:e6:6d:db: + b5:57:4b:dc:e5:2c:25:15:c8:9e:2e:78:4e:f8:da: + 9c:9e:86:2c:ca:57:f3:1a:e5:c8:92:8b:1a:82:96: + 7a:c3:bc:50:12:69:d8:0e:5a:46:8b:3a:eb:26:fa: + 23:c9:b6:b0:81:be:42:00:a4:f8:d6:fe:30:2e:c7: + d2:46:f6:e5:8e:75:fd:f2:cc:b9:d0:87:5b:cc:06: + 10:60:bb:83:35:b7:5e:67:de:47:ec:99:48:f1:a4: + a1:15:fe:ad:8c:62:8e:39:55:4f:39:16:b9:b1:63: + 9d:ff:b7 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + B6:A1:54:39:02:C3:A0:3F:8E:8A:BC:FA:D4:F8:1C:A6:D1:3A:0E:FD + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + Signature Algorithm: sha512WithRSAEncryption + 71:a5:0e:ce:e4:e9:bf:3f:38:d5:89:5a:c4:02:61:fb:4c:c5: + 14:17:2d:8b:4f:53:6b:10:17:fc:65:84:c7:10:49:90:de:db: + c7:26:93:88:26:6f:70:d6:02:5e:39:a0:f7:8f:ab:96:b5:a5: + 13:5c:81:14:6d:0e:81:82:11:1b:8a:4e:c6:4f:a5:dd:62:1e: + 44:df:09:59:f4:5b:77:0b:37:e9:8b:20:c6:f8:0a:4e:2e:58: + 1c:eb:33:d0:cf:86:60:c9:da:fb:80:2f:9e:4c:60:84:78:3d: + 21:64:d6:fb:41:1f:18:0f:e7:c9:75:71:bd:bd:5c:de:34:87: + 3e:41:b0:0e:f6:b9:d6:3f:09:13:96:14:2f:de:9a:1d:5a:b9: + 56:ce:35:3a:b0:5f:70:4d:5e:e3:29:f1:23:28:72:59:b6:ab: + c2:8c:66:26:1c:77:2c:26:76:35:8b:28:a7:69:a0:f9:3b:f5: + 23:dd:85:10:74:c9:90:03:56:91:e7:af:ba:47:d4:12:97:11: + 22:e3:a2:49:94:6c:e7:b7:94:4b:ba:2d:a4:da:33:8b:4c:a6: + 44:ff:5a:3c:c6:1d:64:d8:b5:31:e4:a6:3c:7a:a8:57:0b:db: + ed:61:1a:cb:f1:ce:73:77:63:a4:87:6f:4c:51:38:d6:e4:5f: + c7:9f:b6:81:2a:e4:85:48:79:58:5e:3b:f8:db:02:82:67:c1: + 39:db:c3:74:4b:3d:36:1e:f9:29:93:88:68:5b:a8:44:19:21: + f0:a7:e8:81:0d:2c:e8:93:36:b4:37:b2:ca:b0:1b:26:7a:9a: + 25:1f:9a:9a:80:9e:4b:2a:3f:fb:a3:9a:fe:73:32:71:c2:9e: + c6:72:e1:8a:68:27:f1:e4:0f:b4:c4:4c:a5:61:93:f8:97:10: + 07:2a:30:25:a9:b9:c8:71:b8:ef:68:cc:2d:7e:f5:e0:7e:0f: + 82:a8:6f:b6:ba:6c:83:43:77:cd:8a:92:17:a1:9e:5b:78:16: + 3d:45:e2:33:72:dd:e1:66:ca:99:d3:c9:c5:26:fd:0d:68:04: + 46:ae:b6:d9:9b:8c:be:19:be:b1:c6:f2:19:e3:5c:02:ca:2c: + d8:6f:4a:07:d9:c9:35:da:40:75:f2:c4:a7:19:6f:9e:42:10: + 98:75:e6:95:8b:60:bc:ed:c5:12:d7:8a:ce:d5:98:5c:56:96: + 03:c5:ee:77:06:35:ff:cf:e4:ee:3f:13:61:ee:db:da:2d:85: + f0:cd:ae:9d:b2:18:09:45:c3:92:a1:72:17:fc:47:b6:a0:0b: + 2c:f1:c4:de:43:68:08:6a:5f:3b:f0:76:63:fb:cc:06:2c:a6: + c6:e2:0e:b5:b9:be:24:8f +-----BEGIN CERTIFICATE----- +MIIF0jCCA7qgAwIBAgIQIdbQSk8lD8kyN/yqXhKN6TANBgkqhkiG9w0BAQ0FADCB +gDELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu +QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIG +A1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0d29yayBDQSAyMCIYDzIwMTExMDA2MDgz +OTU2WhgPMjA0NjEwMDYwODM5NTZaMIGAMQswCQYDVQQGEwJQTDEiMCAGA1UEChMZ +VW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3 +b3JrIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC9+Xj45tWA +DGSdhhuWZGc/IjoedQF97/tcZ4zJzFxrqZHmuULlIEub2pt7uZld2ZuAS9eEQCsn +0+i6MLs+CRqnSZXvK0AkwpfHp+6bJe+oCgCXhVqqndwpyeI1B+twTUrWwbNWuKFB +OJvR+zF/j+Bf4bE/D44WSWDXBo0Y+aomEKsq09DRZ40bRr5HMNUuctHFY9rnY3lE +fktjJImGLjQ/KUxSiyqnwOKRKIm5wFv5HdnnJ63/mgKXwcZQkpsCLL2puTRZCr+E +Sv/f/rOf69me4Jgj7KZrdxYq28ytOxykh9xGc14ZYmhFV+SQgkK7QtbwYeDBoz1m +o130GO6IyY0XRSmZMnUCMe4pJshrAua1YkV/NxVaI2iJ1D7eTiew8EAMvE0Xy02i +sx7QBlrd9pPPV3WZ9fqGGmd4s7+W/jTcvedSVuWz5XV710GRBdxdaeOVDUO5/IOW +OZV7bIBaTxNyxtd9KXpEulKkKtVBRgkg/iKgtlswjbyJDNXXcPiHUv3a76xRLgez +Tv7QCdpw75j6VuZt27VXS9zlLCUVyJ4ueE742pyehizKV/Ma5ciSixqClnrDvFAS +adgOWkaLOusm+iPJtrCBvkIApPjW/jAux9JG9uWOdf3yzLnQh1vMBhBgu4M1t15n +3kfsmUjxpKEV/q2MYo45VU85FrmxY53/twIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MB0GA1UdDgQWBBS2oVQ5AsOgP46KvPrU+Bym0ToO/TAOBgNVHQ8BAf8EBAMC +AQYwDQYJKoZIhvcNAQENBQADggIBAHGlDs7k6b8/ONWJWsQCYftMxRQXLYtPU2sQ +F/xlhMcQSZDe28cmk4gmb3DWAl45oPePq5a1pRNcgRRtDoGCERuKTsZPpd1iHkTf +CVn0W3cLN+mLIMb4Ck4uWBzrM9DPhmDJ2vuAL55MYIR4PSFk1vtBHxgP58l1cb29 +XN40hz5BsA72udY/CROWFC/emh1auVbONTqwX3BNXuMp8SMoclm2q8KMZiYcdywm +djWLKKdpoPk79SPdhRB0yZADVpHnr7pH1BKXESLjokmUbOe3lEu6LaTaM4tMpkT/ +WjzGHWTYtTHkpjx6qFcL2+1hGsvxznN3Y6SHb0xRONbkX8eftoEq5IVIeVheO/jb +AoJnwTnbw3RLPTYe+SmTiGhbqEQZIfCn6IENLOiTNrQ3ssqwGyZ6miUfmpqAnksq +P/ujmv5zMnHCnsZy4YpoJ/HkD7TETKVhk/iXEAcqMCWpuchxuO9ozC1+9eB+D4Ko +b7a6bINDd82Kkhehnlt4Fj1F4jNy3eFmypnTycUm/Q1oBEauttmbjL4ZvrHG8hnj +XALKLNhvSgfZyTXaQHXyxKcZb55CEJh15pWLYLztxRLXis7VmFxWlgPF7ncGNf/P +5O4/E2Hu29othfDNrp2yGAlFw5Khchf8R7agCyzxxN5DaAhqXzvwdmP7zAYspsbi +DrW5viSP +-----END CERTIFICATE----- + +Hellenic Academic and Research Institutions RootCA 2015 +# Fingerprint (SHA1): 01:0C:06:95:A6:98:19:14:FF:BF:5F:C6:B0:B6:95:EA:29:E9:12:A6 +MUST_VERIFY_TRUST: CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +======================================================= +MD5 Fingerprint=CA:FF:E2:DB:03:D9:CB:4B:E9:0F:AD:84:FD:7B:18:CE +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 0 (0x0) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=GR, L=Athens, O=Hellenic Academic and Research Institutions Cert. Authority, CN=Hellenic Academic and Research Institutions RootCA 2015 + Validity + Not Before: Jul 7 10:11:21 2015 GMT + Not After : Jun 30 10:11:21 2040 GMT + Subject: C=GR, L=Athens, O=Hellenic Academic and Research Institutions Cert. Authority, CN=Hellenic Academic and Research Institutions RootCA 2015 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:c2:f8:a9:3f:1b:89:fc:3c:3c:04:5d:3d:90:36: + b0:91:3a:79:3c:66:5a:ef:6d:39:01:49:1a:b4:b7: + cf:7f:4d:23:53:b7:90:00:e3:13:2a:28:a6:31:f1: + 91:00:e3:28:ec:ae:21:41:ce:1f:da:fd:7d:12:5b: + 01:83:0f:b9:b0:5f:99:e1:f2:12:83:80:4d:06:3e: + df:ac:af:e7:a1:88:6b:31:af:f0:8b:d0:18:33:b8: + db:45:6a:34:f4:02:80:24:28:0a:02:15:95:5e:76: + 2a:0d:99:3a:14:5b:f6:cb:cb:53:bc:13:4d:01:88: + 37:94:25:1b:42:bc:22:d8:8e:a3:96:5e:3a:d9:32: + db:3e:e8:f0:10:65:ed:74:e1:2f:a7:7c:af:27:34: + bb:29:7d:9b:b6:cf:09:c8:e5:d3:0a:fc:88:65:65: + 74:0a:dc:73:1c:5c:cd:40:b1:1c:d4:b6:84:8c:4c: + 50:cf:68:8e:a8:59:ae:c2:27:4e:82:a2:35:dd:14: + f4:1f:ff:b2:77:d5:87:2f:aa:6e:7d:24:27:e7:c6: + cb:26:e6:e5:fe:67:07:63:d8:45:0d:dd:3a:59:65: + 39:58:7a:92:99:72:3d:9c:84:5e:88:21:b8:d5:f4: + 2c:fc:d9:70:52:4f:78:b8:bd:3c:2b:8b:95:98:f5: + b3:d1:68:cf:20:14:7e:4c:5c:5f:e7:8b:e5:f5:35: + 81:19:37:d7:11:08:b7:66:be:d3:4a:ce:83:57:00: + 3a:c3:81:f8:17:cb:92:36:5d:d1:a3:d8:75:1b:e1: + 8b:27:ea:7a:48:41:fd:45:19:06:ad:27:99:4e:c1: + 70:47:dd:b5:9f:81:53:12:e5:b1:8c:48:5d:31:43: + 17:e3:8c:c6:7a:63:96:4b:29:30:4e:84:4e:62:19: + 5e:3c:ce:97:90:a5:7f:01:eb:9d:e0:f8:8b:89:dd: + 25:98:3d:92:b6:7e:ef:d9:f1:51:51:7d:2d:26:c8: + 69:59:61:e0:ac:6a:b8:2a:36:11:04:7a:50:bd:32: + 84:be:2f:dc:72:d5:d7:1d:16:47:e4:47:66:20:3f: + f4:96:c5:af:8e:01:7a:a5:0f:7a:64:f5:0d:18:87: + d9:ae:88:d5:fa:84:c1:3a:c0:69:28:2d:f2:0d:68: + 51:aa:e3:a5:77:c6:a4:90:0e:a1:37:8b:31:23:47: + c1:09:08:eb:6e:f7:78:9b:d7:82:fc:84:20:99:49: + 19:b6:12:46:b1:fb:45:55:16:a9:a3:65:ac:9c:07: + 0f:ea:6b:dc:1f:2e:06:72:ec:86:88:12:e4:2d:db: + 5f:05:2f:e4:f0:03:d3:26:33:e7:80:c2:cd:42:a1: + 17:34:0b + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 71:15:67:C8:C8:C9:BD:75:5D:72:D0:38:18:6A:9D:F3:71:24:54:0B + Signature Algorithm: sha256WithRSAEncryption + 75:bb:6d:54:4b:aa:10:58:46:34:f2:62:d7:16:36:5d:08:5e: + d5:6c:c8:87:bd:b4:2e:46:f2:31:f8:7c:ea:42:b5:93:16:55: + dc:a1:0c:12:a0:da:61:7e:0f:58:58:73:64:72:c7:e8:45:8e: + dc:a9:f2:26:3f:c6:79:8c:b1:53:08:33:81:b0:56:13:be:e6: + 51:5c:d8:9b:0a:4f:4b:9c:56:53:02:e9:4f:f6:0d:60:ea:4d: + 42:55:e8:7c:1b:21:21:d3:1b:3a:cc:77:f2:b8:90:f1:68:c7: + f9:5a:fe:fa:2d:f4:bf:c9:f5:45:1b:ce:38:10:2a:37:8a:79: + a3:b4:e3:09:6c:85:86:93:ff:89:96:27:78:81:8f:67:e3:46: + 74:54:8e:d9:0d:69:e2:4a:f4:4d:74:03:ff:b2:77:ed:95:67: + 97:e4:b1:c5:ab:bf:6a:23:e8:d4:94:e2:44:28:62:c4:4b:e2: + f0:d8:e2:29:6b:1a:70:7e:24:61:93:7b:4f:03:32:25:0d:45: + 24:2b:96:b4:46:6a:bf:4a:0b:f7:9a:8f:c1:ac:1a:c5:67:f3: + 6f:34:d2:fa:73:63:8c:ef:16:b0:a8:a4:46:2a:f8:eb:12:ec: + 72:b4:ef:f8:2b:7e:8c:52:c0:8b:84:54:f9:2f:3e:e3:55:a8: + dc:66:b1:d9:e1:5f:d8:b3:8c:59:34:59:a4:ab:4f:6c:bb:1f: + 18:db:75:ab:d8:cb:92:cd:94:38:61:0e:07:06:1f:4b:46:10: + f1:15:be:8d:85:5c:3b:4a:2b:81:79:0f:b4:69:9f:49:50:97: + 4d:f7:0e:56:5d:c0:95:6a:c2:36:c3:1b:68:c9:f5:2a:dc:47: + 9a:be:b2:ce:c5:25:e8:fa:03:b9:da:f9:16:6e:91:84:f5:1c: + 28:c8:fc:26:cc:d7:1c:90:56:a7:5f:6f:3a:04:bc:cd:78:89: + 0b:8e:0f:2f:a3:aa:4f:a2:1b:12:3d:16:08:40:0f:f1:46:4c: + d7:aa:7b:08:c1:0a:f5:6d:27:de:02:8f:ca:c3:b5:2b:ca:e9: + eb:c8:21:53:38:a5:cc:3b:d8:77:37:30:a2:4f:d9:6f:d1:f2: + 40:ad:41:7a:17:c5:d6:4a:35:89:b7:41:d5:7c:86:7f:55:4d: + 83:4a:a5:73:20:c0:3a:af:90:f1:9a:24:8e:d9:8e:71:ca:7b: + b8:86:da:b2:8f:99:3e:1d:13:0d:12:11:ee:d4:ab:f0:e9:15: + 76:02:e4:e0:df:aa:20:1e:5b:61:85:64:40:a9:90:97:0d:ad: + 53:d2:5a:1d:87:6a:00:97:65:62:b4:be:6f:6a:a7:f5:2c:42: + ed:32:ad:b6:21:9e:be:bc +-----BEGIN CERTIFICATE----- +MIIGCzCCA/OgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBpjELMAkGA1UEBhMCR1Ix +DzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5k +IFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMT +N0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9v +dENBIDIwMTUwHhcNMTUwNzA3MTAxMTIxWhcNNDAwNjMwMTAxMTIxWjCBpjELMAkG +A1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNh +ZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkx +QDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1 +dGlvbnMgUm9vdENBIDIwMTUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC +AQDC+Kk/G4n8PDwEXT2QNrCROnk8ZlrvbTkBSRq0t89/TSNTt5AA4xMqKKYx8ZEA +4yjsriFBzh/a/X0SWwGDD7mwX5nh8hKDgE0GPt+sr+ehiGsxr/CL0BgzuNtFajT0 +AoAkKAoCFZVedioNmToUW/bLy1O8E00BiDeUJRtCvCLYjqOWXjrZMts+6PAQZe10 +4S+nfK8nNLspfZu2zwnI5dMK/IhlZXQK3HMcXM1AsRzUtoSMTFDPaI6oWa7CJ06C +ojXdFPQf/7J31Ycvqm59JCfnxssm5uX+Zwdj2EUN3TpZZTlYepKZcj2chF6IIbjV +9Cz82XBST3i4vTwri5WY9bPRaM8gFH5MXF/ni+X1NYEZN9cRCLdmvtNKzoNXADrD +gfgXy5I2XdGj2HUb4Ysn6npIQf1FGQatJ5lOwXBH3bWfgVMS5bGMSF0xQxfjjMZ6 +Y5ZLKTBOhE5iGV48zpeQpX8B653g+IuJ3SWYPZK2fu/Z8VFRfS0myGlZYeCsargq +NhEEelC9MoS+L9xy1dcdFkfkR2YgP/SWxa+OAXqlD3pk9Q0Yh9muiNX6hME6wGko +LfINaFGq46V3xqSQDqE3izEjR8EJCOtu93ib14L8hCCZSRm2Ekax+0VVFqmjZayc +Bw/qa9wfLgZy7IaIEuQt218FL+TwA9MmM+eAws1CoRc0CwIDAQABo0IwQDAPBgNV +HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUcRVnyMjJvXVd +ctA4GGqd83EkVAswDQYJKoZIhvcNAQELBQADggIBAHW7bVRLqhBYRjTyYtcWNl0I +XtVsyIe9tC5G8jH4fOpCtZMWVdyhDBKg2mF+D1hYc2Ryx+hFjtyp8iY/xnmMsVMI +M4GwVhO+5lFc2JsKT0ucVlMC6U/2DWDqTUJV6HwbISHTGzrMd/K4kPFox/la/vot +9L/J9UUbzjgQKjeKeaO04wlshYaT/4mWJ3iBj2fjRnRUjtkNaeJK9E10A/+yd+2V +Z5fkscWrv2oj6NSU4kQoYsRL4vDY4ilrGnB+JGGTe08DMiUNRSQrlrRGar9KC/ea +j8GsGsVn82800vpzY4zvFrCopEYq+OsS7HK07/grfoxSwIuEVPkvPuNVqNxmsdnh +X9izjFk0WaSrT2y7HxjbdavYy5LNlDhhDgcGH0tGEPEVvo2FXDtKK4F5D7Rpn0lQ +l033DlZdwJVqwjbDG2jJ9SrcR5q+ss7FJej6A7na+RZukYT1HCjI/CbM1xyQVqdf +bzoEvM14iQuODy+jqk+iGxI9FghAD/FGTNeqewjBCvVtJ94Cj8rDtSvK6evIIVM4 +pcw72Hc3MKJP2W/R8kCtQXoXxdZKNYm3QdV8hn9VTYNKpXMgwDqvkPGaJI7ZjnHK +e7iG2rKPmT4dEw0SEe7Uq/DpFXYC5ODfqiAeW2GFZECpkJcNrVPSWh2HagCXZWK0 +vm9qp/UsQu0yrbYhnr68 +-----END CERTIFICATE----- + +Hellenic Academic and Research Institutions ECC RootCA 2015 +# Fingerprint (SHA1): 9F:F1:71:8D:92:D5:9A:F3:7D:74:97:B4:BC:6F:84:68:0B:BA:B6:66 +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +MUST_VERIFY_TRUST: CODE_SIGNING +=========================================================== +MD5 Fingerprint=81:E5:B4:17:EB:C2:F5:E1:4B:0D:41:7B:49:92:FE:EF +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 0 (0x0) + Signature Algorithm: ecdsa-with-SHA256 + Issuer: C=GR, L=Athens, O=Hellenic Academic and Research Institutions Cert. Authority, CN=Hellenic Academic and Research Institutions ECC RootCA 2015 + Validity + Not Before: Jul 7 10:37:12 2015 GMT + Not After : Jun 30 10:37:12 2040 GMT + Subject: C=GR, L=Athens, O=Hellenic Academic and Research Institutions Cert. Authority, CN=Hellenic Academic and Research Institutions ECC RootCA 2015 + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (384 bit) + pub: + 04:92:a0:41:e8:4b:82:84:5c:e2:f8:31:11:99:86: + 64:4e:09:25:2f:9d:41:2f:0a:ae:35:4f:74:95:b2: + 51:64:6b:8d:6b:e6:3f:70:95:f0:05:44:47:a6:72: + 38:50:76:95:02:5a:8e:ae:28:9e:f9:2d:4e:99:ef: + 2c:48:6f:4c:25:29:e8:d1:71:5b:df:1d:c1:75:37: + b4:d7:fa:7b:7a:42:9c:6a:0a:56:5a:7c:69:0b:aa: + 80:09:24:6c:7e:c1:46 + ASN1 OID: secp384r1 + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + B4:22:0B:82:99:24:01:0E:9C:BB:E4:0E:FD:BF:FB:97:20:93:99:2A + Signature Algorithm: ecdsa-with-SHA256 + 30:64:02:30:67:ce:16:62:38:a2:ac:62:45:a7:a9:95:24:c0: + 1a:27:9c:32:3b:c0:c0:d5:ba:a9:e7:f8:04:43:53:85:ee:52: + 21:de:9d:f5:25:83:3e:9e:58:4b:2f:d7:67:13:0e:21:02:30: + 05:e1:75:01:de:68:ed:2a:1f:4d:4c:09:08:0d:ec:4b:ad:64: + 17:28:e7:75:ce:45:65:72:21:17:cb:22:41:0e:8c:13:98:38: + 9a:54:6d:9b:ca:e2:7c:ea:02:58:22:91 +-----BEGIN CERTIFICATE----- +MIICwzCCAkqgAwIBAgIBADAKBggqhkjOPQQDAjCBqjELMAkGA1UEBhMCR1IxDzAN +BgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl +c2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxRDBCBgNVBAMTO0hl +bGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgRUNDIFJv +b3RDQSAyMDE1MB4XDTE1MDcwNzEwMzcxMloXDTQwMDYzMDEwMzcxMlowgaoxCzAJ +BgNVBAYTAkdSMQ8wDQYDVQQHEwZBdGhlbnMxRDBCBgNVBAoTO0hlbGxlbmljIEFj +YWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9yaXR5 +MUQwQgYDVQQDEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0 +dXRpb25zIEVDQyBSb290Q0EgMjAxNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABJKg +QehLgoRc4vgxEZmGZE4JJS+dQS8KrjVPdJWyUWRrjWvmP3CV8AVER6ZyOFB2lQJa +jq4onvktTpnvLEhvTCUp6NFxW98dwXU3tNf6e3pCnGoKVlp8aQuqgAkkbH7BRqNC +MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFLQi +C4KZJAEOnLvkDv2/+5cgk5kqMAoGCCqGSM49BAMCA2cAMGQCMGfOFmI4oqxiRaep +lSTAGiecMjvAwNW6qef4BENThe5SId6d9SWDPp5YSy/XZxMOIQIwBeF1Ad5o7Sof +TUwJCA3sS61kFyjndc5FZXIhF8siQQ6ME5g4mlRtm8rifOoCWCKR +-----END CERTIFICATE----- + +Certplus Root CA G1 +# Fingerprint (SHA1): 22:FD:D0:B7:FD:A2:4E:0D:AC:49:2C:A0:AC:A6:7B:6A:1F:E3:F7:66 +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +MUST_VERIFY_TRUST: CODE_SIGNING +================================================ +MD5 Fingerprint=7F:09:9C:F7:D9:B9:5C:69:69:56:D5:37:3E:14:0D:42 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 11:20:55:83:e4:2d:3e:54:56:85:2d:83:37:b7:2c:dc:46:11 + Signature Algorithm: sha512WithRSAEncryption + Issuer: C=FR, O=Certplus, CN=Certplus Root CA G1 + Validity + Not Before: May 26 00:00:00 2014 GMT + Not After : Jan 15 00:00:00 2038 GMT + Subject: C=FR, O=Certplus, CN=Certplus Root CA G1 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:da:50:87:b6:da:b8:a9:3e:9d:64:fa:56:33:9a: + 56:3d:16:e5:03:95:b2:34:1c:9a:6d:62:05:d4:d8: + 8f:e7:89:64:9f:ba:db:64:8b:64:e6:79:2a:61:cd: + af:8f:5a:89:91:65:b9:58:fc:b4:03:5f:91:3f:2d: + 10:15:e0:7e:cf:bc:fc:7f:43:67:a8:ad:5e:36:23: + d8:98:b3:4d:f3:43:9e:39:7c:2a:fc:ec:88:d5:88: + ee:70:bd:85:16:2d:ea:4b:89:3c:a3:71:42:fe:1c: + fd:d3:1c:2d:10:b8:86:54:ea:43:b8:db:c6:87:da: + a8:ae:80:25:cf:7a:26:1d:aa:91:b0:48:6f:ae:b5: + de:9e:d8:d7:fa:00:fd:c6:8f:d0:51:bb:62:7d:a4: + b1:8c:b2:ff:20:11:ba:35:63:05:86:47:60:43:33: + 90:f6:47:a2:03:4f:96:4d:9d:4f:c1:ea:ea:9c:a2: + fe:34:2e:de:b7:ca:1b:76:a4:b7:ad:9f:e9:a8:d4: + 78:3f:78:fe:f2:38:09:36:1d:d2:16:02:c8:ec:2a: + 68:af:f5:8e:94:ef:2d:13:7a:1e:42:4a:1d:15:31: + ae:0c:04:57:fc:61:73:f3:31:56:86:31:80:a0:c4: + 11:6e:30:76:e3:94:f0:5f:04:c4:ac:87:72:89:98: + c5:9d:cc:57:08:9a:f4:0c:fc:7d:7a:05:3a:fa:47: + 80:39:b6:cf:84:13:77:6f:27:ea:ff:96:67:17:08: + 6d:e9:0d:d6:23:50:30:b0:15:74:13:3e:e5:2f:ff: + 0e:cd:c4:0b:4a:5d:f0:d8:00:33:49:66:eb:a1:18: + 7c:59:2e:3d:28:b9:61:71:cb:b5:a5:ba:b8:ea:dc: + e2:70:6f:08:6a:dc:87:67:34:ef:df:30:72:dd:f3: + c9:3f:23:ff:35:e1:be:21:29:20:30:81:e4:19:a5: + 20:e9:25:ca:73:31:74:29:be:e2:42:d5:f3:b2:26: + 66:c7:68:fd:19:b3:e7:20:93:99:e8:5d:e0:5e:87: + e7:46:e8:25:9c:0a:29:24:d4:cd:58:86:52:40:24: + b2:7b:0f:98:12:20:24:f6:90:6c:47:c8:0d:bb:18: + 20:2e:d9:fd:fc:8b:f2:29:ea:87:74:95:e0:42:50: + 78:84:04:41:61:b0:f4:21:23:8f:2d:cb:28:21:f2: + 6a:6c:f4:1a:a6:c5:14:b4:37:65:4f:95:fd:80:c8: + f8:72:e5:25:6b:c4:60:b1:7b:6d:8e:4a:8a:73:ce: + 59:fb:70:7a:73:06:13:d9:d3:74:37:24:41:0a:11: + 6f:97:dc:e7:e4:7e:a1:bd:15:f2:ba:87:0f:3d:68: + 8a:16:07 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + A8:C1:C0:9B:91:A8:43:15:7C:5D:06:27:B4:2A:51:D8:97:0B:81:B1 + X509v3 Authority Key Identifier: + keyid:A8:C1:C0:9B:91:A8:43:15:7C:5D:06:27:B4:2A:51:D8:97:0B:81:B1 + + Signature Algorithm: sha512WithRSAEncryption + 9c:56:6f:01:7e:d1:bd:4c:f5:8a:c6:f0:26:1f:e4:e0:38:18: + cc:32:c3:29:3b:9d:41:29:34:61:c6:d7:f0:00:a1:eb:a4:72: + 8f:94:17:bc:13:2c:75:b4:57:ee:0a:7c:09:7a:dc:d5:ca:a1: + d0:34:13:f8:77:ab:9f:e5:fe:d8:1e:74:8a:85:07:8f:7f:cc: + 79:7a:ca:96:cd:cd:fd:4f:fb:fd:23:0d:90:f5:f4:5e:d3:c6: + 61:7d:9e:11:e0:02:ee:09:04:d9:07:dd:a6:8a:b7:0c:83:24: + bb:83:50:92:fe:60:75:11:3e:d8:9d:b0:8a:7a:b5:e0:9d:9b: + cb:90:52:4b:b0:93:2a:d4:3e:16:33:e5:9e:c6:65:15:3e:64: + 3b:04:3f:db:0c:8f:5f:5c:1d:69:1f:af:f3:e9:21:8c:f3:ef: + 97:f6:9a:b7:19:b6:84:74:9c:a3:54:b5:70:4e:63:d8:57:5d: + 53:21:9b:40:92:43:fa:d6:77:55:33:4f:64:d5:fb:d0:2c:6a: + 8e:6d:25:a6:ef:85:e8:02:c4:53:3e:b9:9e:87:bc:cc:35:1a: + de:a1:e9:8a:63:87:65:1e:11:2a:db:63:77:97:14:be:9a:14: + 99:11:b2:c0:ee:b0:4f:f8:14:21:32:43:4f:9f:ab:a2:cb:a8: + 0f:aa:3b:06:55:c6:12:29:57:08:d4:37:d7:87:27:ad:49:59: + a7:91:ab:44:7a:5e:8d:70:db:97:ce:48:50:b1:73:93:f6:f0: + 83:60:f9:cd:f1:e1:31:fd:5b:7c:71:21:63:14:14:aa:af:c5: + de:93:7e:68:b1:ec:22:a2:aa:90:75:9e:b5:43:72:ea:64:a3: + 84:4b:fd:0c:a8:26:6b:71:97:ee:56:63:66:e8:42:54:f9:c7: + 1d:df:d0:8f:5b:df:c8:30:6f:88:fe:0d:c4:33:1c:53:a8:a3: + fd:48:10:f2:e4:0a:4e:e1:15:57:fc:6e:64:30:c2:55:11:dc: + ea:a9:cd:4a:54:ac:29:63:44:cf:4a:40:a0:d6:68:59:1b:33: + f9:ef:3a:8b:db:20:92:dc:42:84:bf:01:ab:87:c0:d5:20:82: + db:c6:b9:83:85:42:5c:0f:43:3b:6a:49:35:d5:98:f4:15:bf: + fa:61:81:0c:09:20:18:d2:d0:17:0c:cb:48:00:50:e9:76:82: + 8c:64:d7:3a:a0:07:55:cc:1e:31:c0:ef:3a:b4:65:fb:e3:bf: + 42:6b:9e:0f:a8:bd:6b:98:dc:d8:db:cb:8b:a4:dd:d7:59:f4: + 6e:dd:fe:aa:c3:91:d0:2e:42:07:c0:0c:4d:53:cd:24:b1:4c: + 5b:1e:51:f4:df:e9:92:fa +-----BEGIN CERTIFICATE----- +MIIFazCCA1OgAwIBAgISESBVg+QtPlRWhS2DN7cs3EYRMA0GCSqGSIb3DQEBDQUA +MD4xCzAJBgNVBAYTAkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2Vy +dHBsdXMgUm9vdCBDQSBHMTAeFw0xNDA1MjYwMDAwMDBaFw0zODAxMTUwMDAwMDBa +MD4xCzAJBgNVBAYTAkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2Vy +dHBsdXMgUm9vdCBDQSBHMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB +ANpQh7bauKk+nWT6VjOaVj0W5QOVsjQcmm1iBdTYj+eJZJ+622SLZOZ5KmHNr49a +iZFluVj8tANfkT8tEBXgfs+8/H9DZ6itXjYj2JizTfNDnjl8KvzsiNWI7nC9hRYt +6kuJPKNxQv4c/dMcLRC4hlTqQ7jbxofaqK6AJc96Jh2qkbBIb6613p7Y1/oA/caP +0FG7Yn2ksYyy/yARujVjBYZHYEMzkPZHogNPlk2dT8Hq6pyi/jQu3rfKG3akt62f +6ajUeD94/vI4CTYd0hYCyOwqaK/1jpTvLRN6HkJKHRUxrgwEV/xhc/MxVoYxgKDE +EW4wduOU8F8ExKyHcomYxZ3MVwia9Az8fXoFOvpHgDm2z4QTd28n6v+WZxcIbekN +1iNQMLAVdBM+5S//Ds3EC0pd8NgAM0lm66EYfFkuPSi5YXHLtaW6uOrc4nBvCGrc +h2c0798wct3zyT8j/zXhviEpIDCB5BmlIOklynMxdCm+4kLV87ImZsdo/Rmz5yCT +mehd4F6H50boJZwKKSTUzViGUkAksnsPmBIgJPaQbEfIDbsYIC7Z/fyL8inqh3SV +4EJQeIQEQWGw9CEjjy3LKCHyamz0GqbFFLQ3ZU+V/YDI+HLlJWvEYLF7bY5KinPO +WftwenMGE9nTdDckQQoRb5fc5+R+ob0V8rqHDz1oihYHAgMBAAGjYzBhMA4GA1Ud +DwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSowcCbkahDFXxd +Bie0KlHYlwuBsTAfBgNVHSMEGDAWgBSowcCbkahDFXxdBie0KlHYlwuBsTANBgkq +hkiG9w0BAQ0FAAOCAgEAnFZvAX7RvUz1isbwJh/k4DgYzDLDKTudQSk0YcbX8ACh +66Ryj5QXvBMsdbRX7gp8CXrc1cqh0DQT+Hern+X+2B50ioUHj3/MeXrKls3N/U/7 +/SMNkPX0XtPGYX2eEeAC7gkE2Qfdpoq3DIMku4NQkv5gdRE+2J2winq14J2by5BS +S7CTKtQ+FjPlnsZlFT5kOwQ/2wyPX1wdaR+v8+khjPPvl/aatxm2hHSco1S1cE5j +2FddUyGbQJJD+tZ3VTNPZNX70Cxqjm0lpu+F6ALEUz65noe8zDUa3qHpimOHZR4R +Kttjd5cUvpoUmRGywO6wT/gUITJDT5+rosuoD6o7BlXGEilXCNQ314cnrUlZp5Gr +RHpejXDbl85IULFzk/bwg2D5zfHhMf1bfHEhYxQUqq/F3pN+aLHsIqKqkHWetUNy +6mSjhEv9DKgma3GX7lZjZuhCVPnHHd/Qj1vfyDBviP4NxDMcU6ij/UgQ8uQKTuEV +V/xuZDDCVRHc6qnNSlSsKWNEz0pAoNZoWRsz+e86i9sgktxChL8Bq4fA1SCC28a5 +g4VCXA9DO2pJNdWY9BW/+mGBDAkgGNLQFwzLSABQ6XaCjGTXOqAHVcweMcDvOrRl +++O/QmueD6i9a5jc2NvLi6Td11n0bt3+qsOR0C5CB8AMTVPNJLFMWx5R9N/pkvo= +-----END CERTIFICATE----- + +Certplus Root CA G2 +# Fingerprint (SHA1): 4F:65:8E:1F:E9:06:D8:28:02:E9:54:47:41:C9:54:25:5D:69:CC:1A +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +MUST_VERIFY_TRUST: CODE_SIGNING +================================================ +MD5 Fingerprint=A7:EE:C4:78:2D:1B:EE:2D:B9:29:CE:D6:A7:96:32:31 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 11:20:d9:91:ce:ae:a3:e8:c5:e7:ff:e9:02:af:cf:73:bc:55 + Signature Algorithm: ecdsa-with-SHA384 + Issuer: C=FR, O=Certplus, CN=Certplus Root CA G2 + Validity + Not Before: May 26 00:00:00 2014 GMT + Not After : Jan 15 00:00:00 2038 GMT + Subject: C=FR, O=Certplus, CN=Certplus Root CA G2 + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (384 bit) + pub: + 04:cd:0f:5b:56:82:df:f0:45:1a:d6:ad:f7:79:f0: + 1d:c9:ac:96:d6:9e:4e:9c:1f:b4:42:11:ca:86:bf: + 6d:fb:85:a3:c5:e5:19:5c:d7:ee:a6:3f:69:67:d8: + 78:e2:a6:c9:c4:db:2d:79:2e:e7:8b:8d:02:6f:31: + 22:4d:06:e3:60:72:45:9d:0e:42:77:9e:ce:cf:e5: + 7f:85:9b:18:e4:fc:cc:2e:72:d3:16:93:4e:ca:99: + 63:5c:a1:05:2a:6c:06 + ASN1 OID: secp384r1 + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + DA:83:63:02:79:8E:DA:4C:C6:3C:23:14:D8:8F:C3:20:AB:28:60:59 + X509v3 Authority Key Identifier: + keyid:DA:83:63:02:79:8E:DA:4C:C6:3C:23:14:D8:8F:C3:20:AB:28:60:59 + + Signature Algorithm: ecdsa-with-SHA384 + 30:65:02:30:70:fe:b0:0b:d9:f7:83:97:ec:f3:55:1d:d4:dc: + b3:06:0e:fe:33:98:9d:8b:39:90:6b:94:21:ed:b6:d7:5d:d6: + 4c:d7:21:a7:e7:bf:21:0f:2b:cd:f7:2a:dc:85:07:9d:02:31: + 00:86:14:16:e5:dc:b0:65:c2:c0:8e:14:9f:bf:24:16:68:e5: + bc:f9:79:69:dc:ad:45:2b:f7:b6:31:73:cc:06:a5:53:93:91: + 1a:93:ae:70:6a:67:ba:d7:9e:e5:61:1a:5f +-----BEGIN CERTIFICATE----- +MIICHDCCAaKgAwIBAgISESDZkc6uo+jF5//pAq/Pc7xVMAoGCCqGSM49BAMDMD4x +CzAJBgNVBAYTAkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2VydHBs +dXMgUm9vdCBDQSBHMjAeFw0xNDA1MjYwMDAwMDBaFw0zODAxMTUwMDAwMDBaMD4x +CzAJBgNVBAYTAkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2VydHBs +dXMgUm9vdCBDQSBHMjB2MBAGByqGSM49AgEGBSuBBAAiA2IABM0PW1aC3/BFGtat +93nwHcmsltaeTpwftEIRyoa/bfuFo8XlGVzX7qY/aWfYeOKmycTbLXku54uNAm8x +Ik0G42ByRZ0OQneezs/lf4WbGOT8zC5y0xaTTsqZY1yhBSpsBqNjMGEwDgYDVR0P +AQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNqDYwJ5jtpMxjwj +FNiPwyCrKGBZMB8GA1UdIwQYMBaAFNqDYwJ5jtpMxjwjFNiPwyCrKGBZMAoGCCqG +SM49BAMDA2gAMGUCMHD+sAvZ94OX7PNVHdTcswYO/jOYnYs5kGuUIe22113WTNch +p+e/IQ8rzfcq3IUHnQIxAIYUFuXcsGXCwI4Un78kFmjlvPl5adytRSv3tjFzzAal +U5ORGpOucGpnutee5WEaXw== +-----END CERTIFICATE----- + +OpenTrust Root CA G1 +# Fingerprint (SHA1): 79:91:E8:34:F7:E2:EE:DD:08:95:01:52:E9:55:2D:14:E9:58:D5:7E +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +MUST_VERIFY_TRUST: CODE_SIGNING +================================================ +MD5 Fingerprint=76:00:CC:81:29:CD:55:5E:88:6A:7A:2E:F7:4D:39:DA +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 11:20:b3:90:55:39:7d:7f:36:6d:64:c2:a7:9f:6b:63:8e:67 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=FR, O=OpenTrust, CN=OpenTrust Root CA G1 + Validity + Not Before: May 26 08:45:50 2014 GMT + Not After : Jan 15 00:00:00 2038 GMT + Subject: C=FR, O=OpenTrust, CN=OpenTrust Root CA G1 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:f8:79:46:da:96:c5:30:5e:8a:71:03:2d:70:a4: + bb:b0:c5:08:dc:cd:e6:35:c0:80:a4:11:2d:dd:e6: + 87:ae:5d:3d:91:d2:87:6c:37:b7:da:62:9e:9b:c2: + 24:d7:8f:f1:db:a6:a6:df:46:6f:51:a6:71:cb:3e: + 1b:31:67:62:f7:11:5b:34:27:d5:79:4e:8c:9b:58: + bd:22:10:0d:5c:27:0c:dd:30:e5:a8:d3:5d:21:38: + 74:17:fe:e3:1f:b6:4f:3b:6b:2d:db:7d:60:1f:8c: + 7d:4c:05:c2:eb:01:16:15:98:14:8e:d1:90:77:22: + 3f:ec:c2:39:b8:79:3a:f0:49:24:e2:95:91:dc:61: + 34:92:8c:54:74:ef:b1:7d:8c:01:e2:38:7d:c1:5f: + 6a:5f:24:b2:8e:62:17:ad:79:20:ad:ab:1d:b7:e0: + b4:96:48:4f:66:43:10:06:16:24:03:e1:e0:9c:8e: + c6:46:4f:8e:1a:99:e1:8f:b9:8e:33:6c:69:de:58: + ad:a0:0e:a7:64:54:11:69:44:66:4f:4c:12:a7:8e: + 2c:7d:c4:d4:5b:c5:00:34:30:c1:d9:99:fe:32:ce: + 07:84:b4:4e:cd:0a:ff:36:4d:62:f1:a7:63:57:e4: + db:6a:a7:ae:bf:2b:b9:c9:e6:b2:27:89:e5:7e:9a: + 1c:4d:68:c6:c1:18:de:33:2b:51:46:4b:1c:8e:f7: + 3d:0c:f9:8a:34:14:c4:fb:33:35:23:f1:cc:f1:2a: + c7:a5:bb:b0:a2:ce:fe:53:6b:4d:41:1b:66:28:b2: + 96:fa:a7:ae:0a:4e:b9:39:33:44:9c:74:c1:93:1c: + f8:e0:9e:24:25:43:f1:9b:23:82:aa:df:2c:20:b0: + dc:36:4e:03:b3:7c:02:d4:e6:7b:1a:aa:87:13:bf: + 3e:a1:74:bb:9b:0e:e1:c0:93:9f:d7:a4:66:ca:bb: + 1b:3b:e3:30:f4:33:59:8a:07:72:03:55:e7:73:6a: + 03:31:6e:6f:96:1b:e3:a2:9f:af:92:c7:ed:f5:42: + b7:25:4c:3b:13:04:cf:1c:96:af:1c:22:a3:d0:ab: + 05:b2:4c:12:23:52:dc:fd:19:5b:27:9c:1e:3b:7a: + fd:42:23:db:23:80:13:f0:bc:51:15:54:94:a6:77: + 3e:d0:74:51:bd:51:14:08:39:37:cb:1f:34:a9:30: + 9d:52:84:2e:55:90:b1:ba:df:55:00:0b:d8:56:2d: + b1:49:49:72:80:a9:62:d7:c0:f6:18:11:04:55:cd: + 74:7b:cf:61:70:79:f4:7b:2c:5c:5c:92:fc:e5:b8: + 5a:ab:4c:93:95:a1:27:ee:a5:be:cf:71:23:42:ba: + 9b:76:2d + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + 97:46:21:57:21:35:DA:36:55:C7:F3:F1:37:70:E5:08:F6:93:29:B6 + X509v3 Authority Key Identifier: + keyid:97:46:21:57:21:35:DA:36:55:C7:F3:F1:37:70:E5:08:F6:93:29:B6 + + Signature Algorithm: sha256WithRSAEncryption + 1d:dd:02:60:7c:e0:35:a7:e6:98:7b:ea:44:ce:67:40:4f:f2: + 93:6e:66:d4:39:89:26:ac:d3:4d:04:3c:bb:87:21:3f:37:f4: + 71:25:da:4b:ba:ab:96:82:81:91:b6:ed:d9:b1:a4:65:97:e2: + 6f:64:59:a4:96:ee:60:ca:1f:23:fb:45:ba:ff:8f:24:f0:ca: + a9:31:7f:79:1f:80:b3:2d:32:ba:64:67:60:af:b9:59:cd:df: + 9a:49:d3:a8:82:b1:f9:98:94:8a:cc:e0:bb:e0:04:1b:99:60: + b1:46:65:dc:08:a2:b2:46:9e:44:88:ea:93:7e:57:16:d2:15: + 72:5f:2e:4b:ab:d4:9d:63:b8:e3:48:e5:fe:84:2e:58:0a:9f: + 43:1d:fe:b7:18:92:86:43:4b:0e:9c:32:86:2c:60:f5:e9:48: + ea:95:ed:70:29:f1:d5:2f:fd:35:b4:57:cf:db:85:48:99:b9: + c2:6f:6c:8f:cd:78:95:ac:64:28:fd:56:b0:c3:6f:c3:be:59: + 52:e1:5f:84:8f:80:f2:f4:0d:36:ad:76:b3:a3:b5:e1:64:76: + 3a:58:dc:7d:4f:5e:56:6c:e5:55:59:57:a5:df:f1:8a:66:30: + 8c:d4:52:62:38:77:b4:be:28:d7:ca:36:c4:9b:05:f0:f8:15: + db:db:f1:ef:34:9d:1d:78:4a:88:56:67:6e:60:ff:8f:c8:8b: + e1:8e:bd:42:a9:33:0a:59:42:12:12:2a:fa:b1:9d:43:8e:05: + 9b:99:da:62:ad:57:36:b3:1d:b6:0d:79:2d:96:b8:eb:f2:0c: + 4b:0c:a5:94:c6:30:a7:26:19:2d:ed:4c:06:50:30:f1:fd:58: + 3d:b9:4b:17:5f:19:b4:6a:84:54:b4:38:4f:39:a2:0d:96:68: + c3:28:94:fd:ed:2d:1f:4a:6b:43:96:2e:90:01:10:fb:38:a6: + 81:0b:d0:bf:75:d3:d4:b9:ce:f1:3f:6f:0e:1c:1e:37:71:e5: + 18:87:75:19:3f:50:b9:5e:a4:45:34:ad:b0:ca:e6:e5:13:76: + 0f:31:14:a9:8e:2d:94:d6:d5:85:4d:73:15:4f:4b:f2:b2:3e: + ed:6c:bd:fd:0e:9d:66:73:b0:3d:b4:f7:bf:a8:e0:11:a4:c4: + ae:75:09:4a:63:00:48:20:a6:c6:9d:0b:09:8a:b4:e0:e6:ce: + 3e:c7:3e:26:38:e9:2b:de:a6:08:49:03:04:90:8a:e9:8f:bf: + e8:b6:b4:2a:a3:23:8d:1c:1c:b2:39:92:a8:8f:02:5c:40:39: + 75:d4:73:41:02:77:de:cd:e0:43:87:d6:e4:ba:4a:c3:6c:12: + 7f:fe:2a:e6:23:d6:8c:71 +-----BEGIN CERTIFICATE----- +MIIFbzCCA1egAwIBAgISESCzkFU5fX82bWTCp59rY45nMA0GCSqGSIb3DQEBCwUA +MEAxCzAJBgNVBAYTAkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9w +ZW5UcnVzdCBSb290IENBIEcxMB4XDTE0MDUyNjA4NDU1MFoXDTM4MDExNTAwMDAw +MFowQDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCU9wZW5UcnVzdDEdMBsGA1UEAwwU +T3BlblRydXN0IFJvb3QgQ0EgRzEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK +AoICAQD4eUbalsUwXopxAy1wpLuwxQjczeY1wICkES3d5oeuXT2R0odsN7faYp6b +wiTXj/HbpqbfRm9RpnHLPhsxZ2L3EVs0J9V5ToybWL0iEA1cJwzdMOWo010hOHQX +/uMftk87ay3bfWAfjH1MBcLrARYVmBSO0ZB3Ij/swjm4eTrwSSTilZHcYTSSjFR0 +77F9jAHiOH3BX2pfJLKOYheteSCtqx234LSWSE9mQxAGFiQD4eCcjsZGT44ameGP +uY4zbGneWK2gDqdkVBFpRGZPTBKnjix9xNRbxQA0MMHZmf4yzgeEtE7NCv82TWLx +p2NX5Ntqp66/K7nJ5rInieV+mhxNaMbBGN4zK1FGSxyO9z0M+Yo0FMT7MzUj8czx +Kselu7Cizv5Ta01BG2Yospb6p64KTrk5M0ScdMGTHPjgniQlQ/GbI4Kq3ywgsNw2 +TgOzfALU5nsaqocTvz6hdLubDuHAk5/XpGbKuxs74zD0M1mKB3IDVedzagMxbm+W +G+Oin6+Sx+31QrclTDsTBM8clq8cIqPQqwWyTBIjUtz9GVsnnB47ev1CI9sjgBPw +vFEVVJSmdz7QdFG9URQIOTfLHzSpMJ1ShC5VkLG631UAC9hWLbFJSXKAqWLXwPYY +EQRVzXR7z2FwefR7LFxckvzluFqrTJOVoSfupb7PcSNCupt2LQIDAQABo2MwYTAO +BgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUl0YhVyE1 +2jZVx/PxN3DlCPaTKbYwHwYDVR0jBBgwFoAUl0YhVyE12jZVx/PxN3DlCPaTKbYw +DQYJKoZIhvcNAQELBQADggIBAB3dAmB84DWn5ph76kTOZ0BP8pNuZtQ5iSas000E +PLuHIT839HEl2ku6q5aCgZG27dmxpGWX4m9kWaSW7mDKHyP7Rbr/jyTwyqkxf3kf +gLMtMrpkZ2CvuVnN35pJ06iCsfmYlIrM4LvgBBuZYLFGZdwIorJGnkSI6pN+VxbS +FXJfLkur1J1juONI5f6ELlgKn0Md/rcYkoZDSw6cMoYsYPXpSOqV7XAp8dUv/TW0 +V8/bhUiZucJvbI/NeJWsZCj9VrDDb8O+WVLhX4SPgPL0DTatdrOjteFkdjpY3H1P +XlZs5VVZV6Xf8YpmMIzUUmI4d7S+KNfKNsSbBfD4Fdvb8e80nR14SohWZ25g/4/I +i+GOvUKpMwpZQhISKvqxnUOOBZuZ2mKtVzazHbYNeS2WuOvyDEsMpZTGMKcmGS3t +TAZQMPH9WD25SxdfGbRqhFS0OE85og2WaMMolP3tLR9Ka0OWLpABEPs4poEL0L91 +09S5zvE/bw4cHjdx5RiHdRk/ULlepEU0rbDK5uUTdg8xFKmOLZTW1YVNcxVPS/Ky +Pu1svf0OnWZzsD2097+o4BGkxK51CUpjAEggpsadCwmKtODmzj7HPiY46SvepghJ +AwSQiumPv+i2tCqjI40cHLI5kqiPAlxAOXXUc0ECd97N4EOH1uS6SsNsEn/+KuYj +1oxx +-----END CERTIFICATE----- + +OpenTrust Root CA G2 +# Fingerprint (SHA1): 79:5F:88:60:C5:AB:7C:3D:92:E6:CB:F4:8D:E1:45:CD:11:EF:60:0B +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +MUST_VERIFY_TRUST: CODE_SIGNING +================================================ +MD5 Fingerprint=57:24:B6:59:24:6B:AE:C8:FE:1C:0C:20:F2:C0:4E:EB +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 11:20:a1:69:1b:bf:bd:b9:bd:52:96:8f:23:e8:48:bf:26:11 + Signature Algorithm: sha512WithRSAEncryption + Issuer: C=FR, O=OpenTrust, CN=OpenTrust Root CA G2 + Validity + Not Before: May 26 00:00:00 2014 GMT + Not After : Jan 15 00:00:00 2038 GMT + Subject: C=FR, O=OpenTrust, CN=OpenTrust Root CA G2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:cc:b6:57:a5:33:94:10:81:32:53:df:61:7e:0f: + 76:39:cf:5c:c2:53:75:1d:49:7a:96:38:dd:a2:73: + 6a:f1:6f:de:5e:a2:5a:b9:71:21:be:36:d9:a1:fc: + bc:ee:6c:a8:7c:34:1a:71:1a:e8:1a:d8:5f:0e:44: + 06:ed:a7:e0:f3:d2:61:0b:e0:32:a2:96:d1:38:f0: + c2:da:01:17:fc:e4:ac:4f:e8:ee:89:1e:74:ab:4f: + bf:1e:09:b6:36:6a:56:f3:e1:ee:96:89:66:24:06: + e4:cd:42:3a:4a:dd:e0:9a:b0:c4:82:45:b3:fe:c9: + ab:5c:7c:3e:c9:eb:17:2f:0c:7d:6e:ae:a5:8f:c8: + ac:25:0a:6f:fa:d5:45:98:d2:35:09:f6:03:43:94: + fe:d9:bf:20:95:79:80:98:8a:d9:89:35:bb:51:1b: + a4:37:7d:fc:99:3b:ab:ff:bf:ac:0d:8f:43:b1:99: + 7b:16:10:7e:1d:6f:47:c4:15:8f:04:96:08:06:42: + 04:f8:84:d6:1d:bc:91:a6:42:be:49:d5:6a:88:3f: + bc:2d:51:d1:9e:8d:e0:52:cc:57:dd:35:35:58:db: + b4:8f:24:88:e4:8b:df:dc:6b:54:d2:81:2b:b2:ce: + 92:4b:1c:1f:46:fa:1d:d8:92:cb:76:67:b5:09:99: + 09:e5:ac:17:14:55:70:c6:3c:a0:56:0a:03:b3:dc: + 62:19:df:c8:b5:30:7f:f5:3c:26:75:11:bd:d7:1b: + b3:87:9e:07:af:65:71:e5:a0:cf:1a:a7:09:10:1d: + 93:89:66:5b:e8:3c:62:32:b5:b5:3a:6e:e9:85:01: + 8b:9e:43:8c:67:73:28:59:5b:eb:e3:dc:2c:cc:a5: + 26:72:62:12:b4:e6:9c:83:44:f6:51:a4:e2:c0:7a: + 24:57:ca:0e:a5:3f:3a:b5:3b:8b:e5:76:ee:70:e6: + 92:de:16:5c:28:5b:97:19:27:92:fe:7a:92:54:ce: + 93:39:0a:16:87:bc:63:b3:f5:b1:93:5c:e0:6e:b7: + d0:ea:f9:62:32:88:44:fb:bf:27:28:b6:30:95:5d: + 12:28:b9:95:be:8f:53:18:e5:a2:18:16:e2:56:a4: + b2:2c:10:f5:1d:37:a6:f8:b7:f6:d0:59:5c:89:f7: + c2:d5:b5:94:74:d1:d5:fe:1b:b6:f0:e6:d6:1e:7b: + d2:3c:cb:a8:e3:f5:18:f3:21:1f:6e:ef:4d:68:06: + 7b:2d:5d:6e:43:89:a6:c0:f9:a0:bf:82:1e:cf:53: + 7f:b4:eb:2c:db:5d:f6:6a:7d:40:24:05:72:89:38: + 01:93:cb:71:c2:39:5d:06:11:f6:6f:78:f8:37:0d: + 39:84:27 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + 6A:39:FA:42:22:F7:E6:89:00:4D:5E:7D:33:83:CB:B8:6E:77:86:AF + X509v3 Authority Key Identifier: + keyid:6A:39:FA:42:22:F7:E6:89:00:4D:5E:7D:33:83:CB:B8:6E:77:86:AF + + Signature Algorithm: sha512WithRSAEncryption + 98:cb:ab:40:3c:e5:33:02:97:7f:2d:87:a6:8f:d4:5e:4a:af: + b8:1e:e7:bb:71:fb:80:64:25:a9:b3:1a:3e:68:5d:27:26:a7: + ba:2a:e1:f0:57:83:0a:64:4f:1e:22:74:1b:e9:90:5f:f0:ac: + cf:ff:4f:68:7a:38:a4:10:6c:0d:b1:c7:a4:77:80:18:b6:a2: + 28:44:76:a7:34:9d:71:84:2f:ca:59:d2:47:88:99:41:22:c9: + 30:98:61:6e:3d:a8:a8:05:6d:d1:1f:c0:51:44:56:7f:27:35: + 02:dd:5e:98:0a:42:eb:30:bf:8d:a1:9b:51:aa:3b:ea:93:46: + 64:c5:00:79:de:21:6b:f6:57:a0:86:d7:06:72:ec:70:46:4b: + 8b:73:dd:a0:21:75:3e:dc:1d:c0:8f:d3:4f:73:1c:85:d9:fe: + 7f:62:c8:95:6f:b6:d3:7b:8c:ba:53:c2:6f:9b:44:4c:79:d0: + 1d:70:b3:d7:9f:02:f4:b2:07:b0:c7:e5:f8:ad:23:0e:a6:56: + c9:29:12:77:48:d9:2f:46:fd:3b:f0:fc:74:70:92:a5:8e:38: + 08:1f:64:30:b6:b7:4b:fb:36:ac:10:8e:a0:52:33:63:9d:03: + 35:56:c5:69:bd:c6:23:5a:27:94:f6:a4:12:f8:2d:33:3c:a1: + 56:a5:5f:d6:19:e9:ed:7c:08:bd:77:cd:27:64:cc:94:da:4e: + 46:50:87:e0:f9:c1:53:80:1e:bb:ad:fb:47:52:8b:1b:fd:a2: + f9:de:0e:22:b7:3d:33:59:6c:d4:de:f5:95:06:32:0d:51:19: + 41:5c:3e:4f:06:f7:b9:2b:80:27:f6:a3:aa:7a:7c:06:e1:43: + c3:13:39:62:1a:36:bd:e0:28:2e:94:02:e4:29:2e:60:55:ae: + 40:3d:b0:74:92:5e:f0:20:64:96:3f:5f:45:5d:88:b5:8a:da: + 02:a0:5b:45:54:de:38:3d:09:c0:a8:4a:65:46:16:fc:aa:bf: + 54:4e:4d:5b:be:38:43:b7:28:ca:8b:33:aa:1a:25:ba:25:5c: + 29:2f:5b:4a:6e:8c:ea:2d:9c:2a:f6:05:76:e0:77:97:80:88: + dd:67:13:6f:1d:68:24:8b:4f:b7:74:81:e5:f4:60:9f:7a:55: + d7:3e:37:da:16:6b:3e:77:ac:ae:18:70:95:08:79:29:03:8a: + fe:c1:3b:b3:3f:1a:0f:a4:3b:5e:1f:58:a1:95:c9:ab:2f:73: + 4a:d0:2d:6e:9a:59:0f:55:18:78:2d:3c:51:a6:97:8b:e6:bb: + b2:70:aa:4c:11:de:ff:7c:2b:37:d4:7a:d1:77:34:8f:e7:f9: + 42:f7:3c:81:0c:4b:52:0a +-----BEGIN CERTIFICATE----- +MIIFbzCCA1egAwIBAgISESChaRu/vbm9UpaPI+hIvyYRMA0GCSqGSIb3DQEBDQUA +MEAxCzAJBgNVBAYTAkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9w +ZW5UcnVzdCBSb290IENBIEcyMB4XDTE0MDUyNjAwMDAwMFoXDTM4MDExNTAwMDAw +MFowQDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCU9wZW5UcnVzdDEdMBsGA1UEAwwU +T3BlblRydXN0IFJvb3QgQ0EgRzIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK +AoICAQDMtlelM5QQgTJT32F+D3Y5z1zCU3UdSXqWON2ic2rxb95eolq5cSG+Ntmh +/LzubKh8NBpxGuga2F8ORAbtp+Dz0mEL4DKiltE48MLaARf85KxP6O6JHnSrT78e +CbY2albz4e6WiWYkBuTNQjpK3eCasMSCRbP+yatcfD7J6xcvDH1urqWPyKwlCm/6 +1UWY0jUJ9gNDlP7ZvyCVeYCYitmJNbtRG6Q3ffyZO6v/v6wNj0OxmXsWEH4db0fE +FY8ElggGQgT4hNYdvJGmQr5J1WqIP7wtUdGejeBSzFfdNTVY27SPJIjki9/ca1TS +gSuyzpJLHB9G+h3Ykst2Z7UJmQnlrBcUVXDGPKBWCgOz3GIZ38i1MH/1PCZ1Eb3X +G7OHngevZXHloM8apwkQHZOJZlvoPGIytbU6bumFAYueQ4xncyhZW+vj3CzMpSZy +YhK05pyDRPZRpOLAeiRXyg6lPzq1O4vldu5w5pLeFlwoW5cZJ5L+epJUzpM5ChaH +vGOz9bGTXOBut9Dq+WIyiET7vycotjCVXRIouZW+j1MY5aIYFuJWpLIsEPUdN6b4 +t/bQWVyJ98LVtZR00dX+G7bw5tYee9I8y6jj9RjzIR9u701oBnstXW5DiabA+aC/ +gh7PU3+06yzbXfZqfUAkBXKJOAGTy3HCOV0GEfZvePg3DTmEJwIDAQABo2MwYTAO +BgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUajn6QiL3 +5okATV59M4PLuG53hq8wHwYDVR0jBBgwFoAUajn6QiL35okATV59M4PLuG53hq8w +DQYJKoZIhvcNAQENBQADggIBAJjLq0A85TMCl38th6aP1F5Kr7ge57tx+4BkJamz +Gj5oXScmp7oq4fBXgwpkTx4idBvpkF/wrM//T2h6OKQQbA2xx6R3gBi2oihEdqc0 +nXGEL8pZ0keImUEiyTCYYW49qKgFbdEfwFFEVn8nNQLdXpgKQuswv42hm1GqO+qT +RmTFAHneIWv2V6CG1wZy7HBGS4tz3aAhdT7cHcCP009zHIXZ/n9iyJVvttN7jLpT +wm+bREx50B1ws9efAvSyB7DH5fitIw6mVskpEndI2S9G/Tvw/HRwkqWOOAgfZDC2 +t0v7NqwQjqBSM2OdAzVWxWm9xiNaJ5T2pBL4LTM8oValX9YZ6e18CL13zSdkzJTa +TkZQh+D5wVOAHrut+0dSixv9ovneDiK3PTNZbNTe9ZUGMg1RGUFcPk8G97krgCf2 +o6p6fAbhQ8MTOWIaNr3gKC6UAuQpLmBVrkA9sHSSXvAgZJY/X0VdiLWK2gKgW0VU +3jg9CcCoSmVGFvyqv1ROTVu+OEO3KMqLM6oaJbolXCkvW0pujOotnCr2BXbgd5eA +iN1nE28daCSLT7d0geX0YJ96Vdc+N9oWaz53rK4YcJUIeSkDiv7BO7M/Gg+kO14f +WKGVyasvc0rQLW6aWQ9VGHgtPFGml4vmu7JwqkwR3v98KzfUetF3NI/n+UL3PIEM +S1IK +-----END CERTIFICATE----- + +OpenTrust Root CA G3 +# Fingerprint (SHA1): 6E:26:64:F3:56:BF:34:55:BF:D1:93:3F:7C:01:DE:D8:13:DA:8A:A6 +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +MUST_VERIFY_TRUST: CODE_SIGNING +================================================ +MD5 Fingerprint=21:37:B4:17:16:92:7B:67:46:70:A9:96:D7:A8:13:24 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 11:20:e6:f8:4c:fc:24:b0:be:05:40:ac:da:83:1b:34:60:3f + Signature Algorithm: ecdsa-with-SHA384 + Issuer: C=FR, O=OpenTrust, CN=OpenTrust Root CA G3 + Validity + Not Before: May 26 00:00:00 2014 GMT + Not After : Jan 15 00:00:00 2038 GMT + Subject: C=FR, O=OpenTrust, CN=OpenTrust Root CA G3 + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (384 bit) + pub: + 04:4a:ee:58:ae:4d:ca:66:de:06:3a:a3:11:fc:e0: + 18:f0:6e:1c:ba:2d:30:0c:89:d9:d6:ee:9b:73:83: + a9:23:15:8c:2f:59:8a:5a:dd:14:ea:9d:59:2b:43: + b7:06:ec:32:b6:ba:ee:41:b5:ad:5d:a1:85:cc:ea: + 1d:14:66:a3:67:7e:46:e2:94:f3:e7:b6:56:a1:15: + 59:a1:4f:37:97:b9:22:1e:bd:11:eb:f4:b2:1f:5e: + c3:14:9a:e5:d9:97:99 + ASN1 OID: secp384r1 + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + 47:77:C3:14:8B:62:39:0C:C9:6F:E1:50:4D:D0:10:58:DC:95:88:6D + X509v3 Authority Key Identifier: + keyid:47:77:C3:14:8B:62:39:0C:C9:6F:E1:50:4D:D0:10:58:DC:95:88:6D + + Signature Algorithm: ecdsa-with-SHA384 + 30:66:02:31:00:8f:a8:dc:9d:ba:0c:04:17:fa:15:e9:3d:2f: + 29:01:97:bf:81:16:33:40:93:6c:fc:f9:ed:80:70:6f:aa:8f: + db:84:c2:8b:f5:35:ca:06:dc:64:6f:68:16:e1:8f:91:b9:02: + 31:00:d8:4b:a5:cb:c2:d0:08:6c:e9:18:fb:5a:dd:4d:5f:24: + 0b:b0:00:21:25:ef:8f:a7:04:26:71:e2:7c:69:e5:5d:9a:f8: + 41:1f:3b:39:93:93:9d:55:ea:cd:8d:f1:fb:c1 +-----BEGIN CERTIFICATE----- +MIICITCCAaagAwIBAgISESDm+Ez8JLC+BUCs2oMbNGA/MAoGCCqGSM49BAMDMEAx +CzAJBgNVBAYTAkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9wZW5U +cnVzdCBSb290IENBIEczMB4XDTE0MDUyNjAwMDAwMFoXDTM4MDExNTAwMDAwMFow +QDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCU9wZW5UcnVzdDEdMBsGA1UEAwwUT3Bl +blRydXN0IFJvb3QgQ0EgRzMwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARK7liuTcpm +3gY6oxH84Bjwbhy6LTAMidnW7ptzg6kjFYwvWYpa3RTqnVkrQ7cG7DK2uu5Bta1d +oYXM6h0UZqNnfkbilPPntlahFVmhTzeXuSIevRHr9LIfXsMUmuXZl5mjYzBhMA4G +A1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRHd8MUi2I5 +DMlv4VBN0BBY3JWIbTAfBgNVHSMEGDAWgBRHd8MUi2I5DMlv4VBN0BBY3JWIbTAK +BggqhkjOPQQDAwNpADBmAjEAj6jcnboMBBf6Fek9LykBl7+BFjNAk2z8+e2AcG+q +j9uEwov1NcoG3GRvaBbhj5G5AjEA2Euly8LQCGzpGPta3U1fJAuwACEl74+nBCZx +4nxp5V2a+EEfOzmTk51V6s2N8fvB +-----END CERTIFICATE----- + +ISRG Root X1 +# Fingerprint (SHA1): CA:BD:2A:79:A1:07:6A:31:F2:1D:25:36:35:CB:03:9D:43:29:A5:E8 +TRUSTED_DELEGATOR: SERVER_AUTH +MUST_VERIFY_TRUST: EMAIL_PROTECTION, CODE_SIGNING +================================================= +MD5 Fingerprint=0C:D2:F9:E0:DA:17:73:E9:ED:86:4D:A5:E3:70:E7:4E +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 82:10:cf:b0:d2:40:e3:59:44:63:e0:bb:63:82:8b:00 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=Internet Security Research Group, CN=ISRG Root X1 + Validity + Not Before: Jun 4 11:04:38 2015 GMT + Not After : Jun 4 11:04:38 2035 GMT + Subject: C=US, O=Internet Security Research Group, CN=ISRG Root X1 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:ad:e8:24:73:f4:14:37:f3:9b:9e:2b:57:28:1c: + 87:be:dc:b7:df:38:90:8c:6e:3c:e6:57:a0:78:f7: + 75:c2:a2:fe:f5:6a:6e:f6:00:4f:28:db:de:68:86: + 6c:44:93:b6:b1:63:fd:14:12:6b:bf:1f:d2:ea:31: + 9b:21:7e:d1:33:3c:ba:48:f5:dd:79:df:b3:b8:ff: + 12:f1:21:9a:4b:c1:8a:86:71:69:4a:66:66:6c:8f: + 7e:3c:70:bf:ad:29:22:06:f3:e4:c0:e6:80:ae:e2: + 4b:8f:b7:99:7e:94:03:9f:d3:47:97:7c:99:48:23: + 53:e8:38:ae:4f:0a:6f:83:2e:d1:49:57:8c:80:74: + b6:da:2f:d0:38:8d:7b:03:70:21:1b:75:f2:30:3c: + fa:8f:ae:dd:da:63:ab:eb:16:4f:c2:8e:11:4b:7e: + cf:0b:e8:ff:b5:77:2e:f4:b2:7b:4a:e0:4c:12:25: + 0c:70:8d:03:29:a0:e1:53:24:ec:13:d9:ee:19:bf: + 10:b3:4a:8c:3f:89:a3:61:51:de:ac:87:07:94:f4: + 63:71:ec:2e:e2:6f:5b:98:81:e1:89:5c:34:79:6c: + 76:ef:3b:90:62:79:e6:db:a4:9a:2f:26:c5:d0:10: + e1:0e:de:d9:10:8e:16:fb:b7:f7:a8:f7:c7:e5:02: + 07:98:8f:36:08:95:e7:e2:37:96:0d:36:75:9e:fb: + 0e:72:b1:1d:9b:bc:03:f9:49:05:d8:81:dd:05:b4: + 2a:d6:41:e9:ac:01:76:95:0a:0f:d8:df:d5:bd:12: + 1f:35:2f:28:17:6c:d2:98:c1:a8:09:64:77:6e:47: + 37:ba:ce:ac:59:5e:68:9d:7f:72:d6:89:c5:06:41: + 29:3e:59:3e:dd:26:f5:24:c9:11:a7:5a:a3:4c:40: + 1f:46:a1:99:b5:a7:3a:51:6e:86:3b:9e:7d:72:a7: + 12:05:78:59:ed:3e:51:78:15:0b:03:8f:8d:d0:2f: + 05:b2:3e:7b:4a:1c:4b:73:05:12:fc:c6:ea:e0:50: + 13:7c:43:93:74:b3:ca:74:e7:8e:1f:01:08:d0:30: + d4:5b:71:36:b4:07:ba:c1:30:30:5c:48:b7:82:3b: + 98:a6:7d:60:8a:a2:a3:29:82:cc:ba:bd:83:04:1b: + a2:83:03:41:a1:d6:05:f1:1b:c2:b6:f0:a8:7c:86: + 3b:46:a8:48:2a:88:dc:76:9a:76:bf:1f:6a:a5:3d: + 19:8f:eb:38:f3:64:de:c8:2b:0d:0a:28:ff:f7:db: + e2:15:42:d4:22:d0:27:5d:e1:79:fe:18:e7:70:88: + ad:4e:e6:d9:8b:3a:c6:dd:27:51:6e:ff:bc:64:f5: + 33:43:4f + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + 79:B4:59:E6:7B:B6:E5:E4:01:73:80:08:88:C8:1A:58:F6:E9:9B:6E + Signature Algorithm: sha256WithRSAEncryption + 55:1f:58:a9:bc:b2:a8:50:d0:0c:b1:d8:1a:69:20:27:29:08: + ac:61:75:5c:8a:6e:f8:82:e5:69:2f:d5:f6:56:4b:b9:b8:73: + 10:59:d3:21:97:7e:e7:4c:71:fb:b2:d2:60:ad:39:a8:0b:ea: + 17:21:56:85:f1:50:0e:59:eb:ce:e0:59:e9:ba:c9:15:ef:86: + 9d:8f:84:80:f6:e4:e9:91:90:dc:17:9b:62:1b:45:f0:66:95: + d2:7c:6f:c2:ea:3b:ef:1f:cf:cb:d6:ae:27:f1:a9:b0:c8:ae: + fd:7d:7e:9a:fa:22:04:eb:ff:d9:7f:ea:91:2b:22:b1:17:0e: + 8f:f2:8a:34:5b:58:d8:fc:01:c9:54:b9:b8:26:cc:8a:88:33: + 89:4c:2d:84:3c:82:df:ee:96:57:05:ba:2c:bb:f7:c4:b7:c7: + 4e:3b:82:be:31:c8:22:73:73:92:d1:c2:80:a4:39:39:10:33: + 23:82:4c:3c:9f:86:b2:55:98:1d:be:29:86:8c:22:9b:9e:e2: + 6b:3b:57:3a:82:70:4d:dc:09:c7:89:cb:0a:07:4d:6c:e8:5d: + 8e:c9:ef:ce:ab:c7:bb:b5:2b:4e:45:d6:4a:d0:26:cc:e5:72: + ca:08:6a:a5:95:e3:15:a1:f7:a4:ed:c9:2c:5f:a5:fb:ff:ac: + 28:02:2e:be:d7:7b:bb:e3:71:7b:90:16:d3:07:5e:46:53:7c: + 37:07:42:8c:d3:c4:96:9c:d5:99:b5:2a:e0:95:1a:80:48:ae: + 4c:39:07:ce:cc:47:a4:52:95:2b:ba:b8:fb:ad:d2:33:53:7d: + e5:1d:4d:6d:d5:a1:b1:c7:42:6f:e6:40:27:35:5c:a3:28:b7: + 07:8d:e7:8d:33:90:e7:23:9f:fb:50:9c:79:6c:46:d5:b4:15: + b3:96:6e:7e:9b:0c:96:3a:b8:52:2d:3f:d6:5b:e1:fb:08:c2: + 84:fe:24:a8:a3:89:da:ac:6a:e1:18:2a:b1:a8:43:61:5b:d3: + 1f:dc:3b:8d:76:f2:2d:e8:8d:75:df:17:33:6c:3d:53:fb:7b: + cb:41:5f:ff:dc:a2:d0:61:38:e1:96:b8:ac:5d:8b:37:d7:75: + d5:33:c0:99:11:ae:9d:41:c1:72:75:84:be:02:41:42:5f:67: + 24:48:94:d1:9b:27:be:07:3f:b9:b8:4f:81:74:51:e1:7a:b7: + ed:9d:23:e2:be:e0:d5:28:04:13:3c:31:03:9e:dd:7a:6c:8f: + c6:07:18:c6:7f:de:47:8e:3f:28:9e:04:06:cf:a5:54:34:77: + bd:ec:89:9b:e9:17:43:df:5b:db:5f:fe:8e:1e:57:a2:cd:40: + 9d:7e:62:22:da:de:18:27 +-----BEGIN CERTIFICATE----- +MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw +TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh +cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 +WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu +ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY +MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc +h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ +0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U +A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW +T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH +B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC +B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv +KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn +OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn +jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw +qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI +rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq +hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL +ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ +3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK +NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 +ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur +TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC +jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc +oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq +4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA +mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d +emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= +-----END CERTIFICATE----- + +AC RAIZ FNMT-RCM +# Fingerprint (SHA1): EC:50:35:07:B2:15:C4:95:62:19:E2:A8:9A:5B:42:99:2C:4C:2C:20 +MUST_VERIFY_TRUST: EMAIL_PROTECTION, CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH +================================================= +MD5 Fingerprint=E2:09:04:B4:D3:BD:D1:A0:14:FD:1A:D2:47:C4:57:1D +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 5d:93:8d:30:67:36:c8:06:1d:1a:c7:54:84:69:07 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=ES, O=FNMT-RCM, OU=AC RAIZ FNMT-RCM + Validity + Not Before: Oct 29 15:59:56 2008 GMT + Not After : Jan 1 00:00:00 2030 GMT + Subject: C=ES, O=FNMT-RCM, OU=AC RAIZ FNMT-RCM + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:ba:71:80:7a:4c:86:6e:7f:c8:13:6d:c0:c6:7d: + 1c:00:97:8f:2c:0c:23:bb:10:9a:40:a9:1a:b7:87: + 88:f8:9b:56:6a:fb:e6:7b:8e:8b:92:8e:a7:25:5d: + 59:11:db:36:2e:b7:51:17:1f:a9:08:1f:04:17:24: + 58:aa:37:4a:18:df:e5:39:d4:57:fd:d7:c1:2c:91: + 01:91:e2:22:d4:03:c0:58:fc:77:47:ec:8f:3e:74: + 43:ba:ac:34:8d:4d:38:76:67:8e:b0:c8:6f:30:33: + 58:71:5c:b4:f5:6b:6e:d4:01:50:b8:13:7e:6c:4a: + a3:49:d1:20:19:ee:bc:c0:29:18:65:a7:de:fe:ef: + dd:0a:90:21:e7:1a:67:92:42:10:98:5f:4f:30:bc: + 3e:1c:45:b4:10:d7:68:40:14:c0:40:fa:e7:77:17: + 7a:e6:0b:8f:65:5b:3c:d9:9a:52:db:b5:bd:9e:46: + cf:3d:eb:91:05:02:c0:96:b2:76:4c:4d:10:96:3b: + 92:fa:9c:7f:0f:99:df:be:23:35:45:1e:02:5c:fe: + b5:a8:9b:99:25:da:5e:f3:22:c3:39:f5:e4:2a:2e: + d3:c6:1f:c4:6c:aa:c5:1c:6a:01:05:4a:2f:d2:c5: + c1:a8:34:26:5d:66:a5:d2:02:21:f9:18:b7:06:f5: + 4e:99:6f:a8:ab:4c:51:e8:cf:50:18:c5:77:c8:39: + 09:2c:49:92:32:99:a8:bb:17:17:79:b0:5a:c5:e6: + a3:c4:59:65:47:35:83:5e:a9:e8:35:0b:99:bb:e4: + cd:20:c6:9b:4a:06:39:b5:68:fc:22:ba:ee:55:8c: + 2b:4e:ea:f3:b1:e3:fc:b6:99:9a:d5:42:fa:71:4d: + 08:cf:87:1e:6a:71:7d:f9:d3:b4:e9:a5:71:81:7b: + c2:4e:47:96:a5:f6:76:85:a3:28:8f:e9:80:6e:81: + 53:a5:6d:5f:b8:48:f9:c2:f9:36:a6:2e:49:ff:b8: + 96:c2:8c:07:b3:9b:88:58:fc:eb:1b:1c:de:2d:70: + e2:97:92:30:a1:89:e3:bc:55:a8:27:d6:4b:ed:90: + ad:8b:fa:63:25:59:2d:a8:35:dd:ca:97:33:bc:e5: + cd:c7:9d:d1:ec:ef:5e:0e:4a:90:06:26:63:ad:b9: + d9:35:2d:07:ba:76:65:2c:ac:57:8f:7d:f4:07:94: + d7:81:02:96:5d:a3:07:49:d5:7a:d0:57:f9:1b:e7: + 53:46:75:aa:b0:79:42:cb:68:71:08:e9:60:bd:39: + 69:ce:f4:af:c3:56:40:c7:ad:52:a2:09:e4:6f:86: + 47:8a:1f:eb:28:27:5d:83:20:af:04:c9:6c:56:9a: + 8b:46:f5 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + F7:7D:C5:FD:C4:E8:9A:1B:77:64:A7:F5:1D:A0:CC:BF:87:60:9A:6D + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: http://www.cert.fnmt.es/dpcs/ + + Signature Algorithm: sha256WithRSAEncryption + 07:90:4a:df:f3:23:4e:f0:c3:9c:51:65:9b:9c:22:a2:8a:0c: + 85:f3:73:29:6b:4d:fe:01:e2:a9:0c:63:01:bf:04:67:a5:9d: + 98:5f:fd:01:13:fa:ec:9a:62:e9:86:fe:b6:62:d2:6e:4c:94: + fb:c0:75:45:7c:65:0c:f8:b2:37:cf:ac:0f:cf:8d:6f:f9:19: + f7:8f:ec:1e:f2:70:9e:f0:ca:b8:ef:b7:ff:76:37:76:5b:f6: + 6e:88:f3:af:62:32:22:93:0d:3a:6a:8e:14:66:0c:2d:53:74: + 57:65:1e:d5:b2:dd:23:81:3b:a5:66:23:27:67:09:8f:e1:77: + aa:43:cd:65:51:08:ed:51:58:fe:e6:39:f9:cb:47:84:a4:15: + f1:76:bb:a4:ee:a4:3b:c4:5f:ef:b2:33:96:11:18:b7:c9:65: + be:18:e1:a3:a4:dc:fa:18:f9:d3:bc:13:9b:39:7a:34:ba:d3: + 41:fb:fa:32:8a:2a:b7:2b:86:0b:69:83:38:be:cd:8a:2e:0b: + 70:ad:8d:26:92:ee:1e:f5:01:2b:0a:d9:d6:97:9b:6e:e0:a8: + 19:1c:3a:21:8b:0c:1e:40:ad:03:e7:dd:66:7e:f5:b9:20:0d: + 03:e8:96:f9:82:45:d4:39:e0:a0:00:5d:d7:98:e6:7d:9e:67: + 73:c3:9a:2a:f7:ab:8b:a1:3a:14:ef:34:bc:52:0e:89:98:9a: + 04:40:84:1d:7e:45:69:93:57:ce:eb:ce:f8:50:7c:4f:1c:6e: + 04:43:9b:f9:d6:3b:23:18:e9:ea:8e:d1:4d:46:8d:f1:3b:e4: + 6a:ca:ba:fb:23:b7:9b:fa:99:01:29:5a:58:5a:2d:e3:f9:d4: + 6d:0e:26:ad:c1:6e:34:bc:32:f8:0c:05:fa:65:a3:db:3b:37: + 83:22:e9:d6:dc:72:33:fd:5d:f2:20:bd:76:3c:23:da:28:f7: + f9:1b:eb:59:64:d5:dc:5f:72:7e:20:fc:cd:89:b5:90:67:4d: + 62:7a:3f:4e:ad:1d:c3:39:fe:7a:f4:28:16:df:41:f6:48:80: + 05:d7:0f:51:79:ac:10:ab:d4:ec:03:66:e6:6a:b0:ba:31:92: + 42:40:6a:be:3a:d3:72:e1:6a:37:55:bc:ac:1d:95:b7:69:61: + f2:43:91:74:e6:a0:d3:0a:24:46:a1:08:af:d6:da:45:19:96: + d4:53:1d:5b:84:79:f0:c0:f7:47:ef:8b:8f:c5:06:ae:9d:4c: + 62:9d:ff:46:04:f8:d3:c9:b6:10:25:40:75:fe:16:aa:c9:4a: + 60:86:2f:ba:ef:30:77:e4:54:e2:b8:84:99:58:80:aa:13:8b: + 51:3a:4f:48:f6:8b:b6:b3 +-----BEGIN CERTIFICATE----- +MIIFgzCCA2ugAwIBAgIPXZONMGc2yAYdGsdUhGkHMA0GCSqGSIb3DQEBCwUAMDsx +CzAJBgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJ +WiBGTk1ULVJDTTAeFw0wODEwMjkxNTU5NTZaFw0zMDAxMDEwMDAwMDBaMDsxCzAJ +BgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJWiBG +Tk1ULVJDTTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALpxgHpMhm5/ +yBNtwMZ9HACXjywMI7sQmkCpGreHiPibVmr75nuOi5KOpyVdWRHbNi63URcfqQgf +BBckWKo3Shjf5TnUV/3XwSyRAZHiItQDwFj8d0fsjz50Q7qsNI1NOHZnjrDIbzAz +WHFctPVrbtQBULgTfmxKo0nRIBnuvMApGGWn3v7v3QqQIecaZ5JCEJhfTzC8PhxF +tBDXaEAUwED653cXeuYLj2VbPNmaUtu1vZ5Gzz3rkQUCwJaydkxNEJY7kvqcfw+Z +374jNUUeAlz+taibmSXaXvMiwzn15Cou08YfxGyqxRxqAQVKL9LFwag0Jl1mpdIC +IfkYtwb1TplvqKtMUejPUBjFd8g5CSxJkjKZqLsXF3mwWsXmo8RZZUc1g16p6DUL +mbvkzSDGm0oGObVo/CK67lWMK07q87Hj/LaZmtVC+nFNCM+HHmpxffnTtOmlcYF7 +wk5HlqX2doWjKI/pgG6BU6VtX7hI+cL5NqYuSf+4lsKMB7ObiFj86xsc3i1w4peS +MKGJ47xVqCfWS+2QrYv6YyVZLag13cqXM7zlzced0ezvXg5KkAYmY6252TUtB7p2 +ZSysV4999AeU14ECll2jB0nVetBX+RvnU0Z1qrB5QstocQjpYL05ac70r8NWQMet +UqIJ5G+GR4of6ygnXYMgrwTJbFaai0b1AgMBAAGjgYMwgYAwDwYDVR0TAQH/BAUw +AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFPd9xf3E6Jobd2Sn9R2gzL+H +YJptMD4GA1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1odHRwOi8vd3d3 +LmNlcnQuZm5tdC5lcy9kcGNzLzANBgkqhkiG9w0BAQsFAAOCAgEAB5BK3/MjTvDD +nFFlm5wioooMhfNzKWtN/gHiqQxjAb8EZ6WdmF/9ARP67Jpi6Yb+tmLSbkyU+8B1 +RXxlDPiyN8+sD8+Nb/kZ94/sHvJwnvDKuO+3/3Y3dlv2bojzr2IyIpMNOmqOFGYM +LVN0V2Ue1bLdI4E7pWYjJ2cJj+F3qkPNZVEI7VFY/uY5+ctHhKQV8Xa7pO6kO8Rf +77IzlhEYt8llvhjho6Tc+hj507wTmzl6NLrTQfv6MooqtyuGC2mDOL7Nii4LcK2N +JpLuHvUBKwrZ1pebbuCoGRw6IYsMHkCtA+fdZn71uSANA+iW+YJF1DngoABd15jm +fZ5nc8OaKveri6E6FO80vFIOiZiaBECEHX5FaZNXzuvO+FB8TxxuBEOb+dY7Ixjp +6o7RTUaN8Tvkasq6+yO3m/qZASlaWFot4/nUbQ4mrcFuNLwy+AwF+mWj2zs3gyLp +1txyM/1d8iC9djwj2ij3+RvrWWTV3F9yfiD8zYm1kGdNYno/Tq0dwzn+evQoFt9B +9kiABdcPUXmsEKvU7ANm5mqwujGSQkBqvjrTcuFqN1W8rB2Vt2lh8kORdOag0wok +RqEIr9baRRmW1FMdW4R58MD3R++Lj8UGrp1MYp3/RgT408m2ECVAdf4WqslKYIYv +uu8wd+RU4riEmViAqhOLUTpPSPaLtrM= +-----END CERTIFICATE----- + +Amazon Root CA 1 +# Fingerprint (SHA1): 8D:A7:F9:65:EC:5E:FC:37:91:0F:1C:6E:59:FD:C1:CC:6A:6E:DE:16 +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +MUST_VERIFY_TRUST: CODE_SIGNING +================================================ +MD5 Fingerprint=43:C6:BF:AE:EC:FE:AD:2F:18:C6:88:68:30:FC:C8:E6 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 06:6c:9f:cf:99:bf:8c:0a:39:e2:f0:78:8a:43:e6:96:36:5b:ca + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, O=Amazon, CN=Amazon Root CA 1 + Validity + Not Before: May 26 00:00:00 2015 GMT + Not After : Jan 17 00:00:00 2038 GMT + Subject: C=US, O=Amazon, CN=Amazon Root CA 1 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:b2:78:80:71:ca:78:d5:e3:71:af:47:80:50:74: + 7d:6e:d8:d7:88:76:f4:99:68:f7:58:21:60:f9:74: + 84:01:2f:ac:02:2d:86:d3:a0:43:7a:4e:b2:a4:d0: + 36:ba:01:be:8d:db:48:c8:07:17:36:4c:f4:ee:88: + 23:c7:3e:eb:37:f5:b5:19:f8:49:68:b0:de:d7:b9: + 76:38:1d:61:9e:a4:fe:82:36:a5:e5:4a:56:e4:45: + e1:f9:fd:b4:16:fa:74:da:9c:9b:35:39:2f:fa:b0: + 20:50:06:6c:7a:d0:80:b2:a6:f9:af:ec:47:19:8f: + 50:38:07:dc:a2:87:39:58:f8:ba:d5:a9:f9:48:67: + 30:96:ee:94:78:5e:6f:89:a3:51:c0:30:86:66:a1: + 45:66:ba:54:eb:a3:c3:91:f9:48:dc:ff:d1:e8:30: + 2d:7d:2d:74:70:35:d7:88:24:f7:9e:c4:59:6e:bb: + 73:87:17:f2:32:46:28:b8:43:fa:b7:1d:aa:ca:b4: + f2:9f:24:0e:2d:4b:f7:71:5c:5e:69:ff:ea:95:02: + cb:38:8a:ae:50:38:6f:db:fb:2d:62:1b:c5:c7:1e: + 54:e1:77:e0:67:c8:0f:9c:87:23:d6:3f:40:20:7f: + 20:80:c4:80:4c:3e:3b:24:26:8e:04:ae:6c:9a:c8: + aa:0d + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 84:18:CC:85:34:EC:BC:0C:94:94:2E:08:59:9C:C7:B2:10:4E:0A:08 + Signature Algorithm: sha256WithRSAEncryption + 98:f2:37:5a:41:90:a1:1a:c5:76:51:28:20:36:23:0e:ae:e6: + 28:bb:aa:f8:94:ae:48:a4:30:7f:1b:fc:24:8d:4b:b4:c8:a1: + 97:f6:b6:f1:7a:70:c8:53:93:cc:08:28:e3:98:25:cf:23:a4: + f9:de:21:d3:7c:85:09:ad:4e:9a:75:3a:c2:0b:6a:89:78:76: + 44:47:18:65:6c:8d:41:8e:3b:7f:9a:cb:f4:b5:a7:50:d7:05: + 2c:37:e8:03:4b:ad:e9:61:a0:02:6e:f5:f2:f0:c5:b2:ed:5b: + b7:dc:fa:94:5c:77:9e:13:a5:7f:52:ad:95:f2:f8:93:3b:de: + 8b:5c:5b:ca:5a:52:5b:60:af:14:f7:4b:ef:a3:fb:9f:40:95: + 6d:31:54:fc:42:d3:c7:46:1f:23:ad:d9:0f:48:70:9a:d9:75: + 78:71:d1:72:43:34:75:6e:57:59:c2:02:5c:26:60:29:cf:23: + 19:16:8e:88:43:a5:d4:e4:cb:08:fb:23:11:43:e8:43:29:72: + 62:a1:a9:5d:5e:08:d4:90:ae:b8:d8:ce:14:c2:d0:55:f2:86: + f6:c4:93:43:77:66:61:c0:b9:e8:41:d7:97:78:60:03:6e:4a: + 72:ae:a5:d1:7d:ba:10:9e:86:6c:1b:8a:b9:59:33:f8:eb:c4: + 90:be:f1:b9 +-----BEGIN CERTIFICATE----- +MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF +ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 +b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL +MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv +b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj +ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM +9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw +IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6 +VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L +93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm +jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA +A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI +U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs +N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv +o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU +5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy +rqXRfboQnoZsG4q5WTP468SQvvG5 +-----END CERTIFICATE----- + +Amazon Root CA 2 +# Fingerprint (SHA1): 5A:8C:EF:45:D7:A6:98:59:76:7A:8C:8B:44:96:B5:78:CF:47:4B:1A +MUST_VERIFY_TRUST: CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +================================================ +MD5 Fingerprint=C8:E5:8D:CE:A8:42:E2:7A:C0:2A:5C:7C:9E:26:BF:66 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 06:6c:9f:d2:96:35:86:9f:0a:0f:e5:86:78:f8:5b:26:bb:8a:37 + Signature Algorithm: sha384WithRSAEncryption + Issuer: C=US, O=Amazon, CN=Amazon Root CA 2 + Validity + Not Before: May 26 00:00:00 2015 GMT + Not After : May 26 00:00:00 2040 GMT + Subject: C=US, O=Amazon, CN=Amazon Root CA 2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:ad:96:9f:2d:9c:4a:4c:4a:81:79:51:99:ec:8a: + cb:6b:60:51:13:bc:4d:6d:06:fc:b0:08:8d:dd:19: + 10:6a:c7:26:0c:35:d8:c0:6f:20:84:e9:94:b1:9b: + 85:03:c3:5b:db:4a:e8:c8:f8:90:76:d9:5b:4f:e3: + 4c:e8:06:36:4d:cc:9a:ac:3d:0c:90:2b:92:d4:06: + 19:60:ac:37:44:79:85:81:82:ad:5a:37:e0:0d:cc: + 9d:a6:4c:52:76:ea:43:9d:b7:04:d1:50:f6:55:e0: + d5:d2:a6:49:85:e9:37:e9:ca:7e:ae:5c:95:4d:48: + 9a:3f:ae:20:5a:6d:88:95:d9:34:b8:52:1a:43:90: + b0:bf:6c:05:b9:b6:78:b7:ea:d0:e4:3a:3c:12:53: + 62:ff:4a:f2:7b:be:35:05:a9:12:34:e3:f3:64:74: + 62:2c:3d:00:49:5a:28:fe:32:44:bb:87:dd:65:27: + 02:71:3b:da:4a:f7:1f:da:cd:f7:21:55:90:4f:0f: + ec:ae:82:e1:9f:6b:d9:45:d3:bb:f0:5f:87:ed:3c: + 2c:39:86:da:3f:de:ec:72:55:eb:79:a3:ad:db:dd: + 7c:b0:ba:1c:ce:fc:de:4f:35:76:cf:0f:f8:78:1f: + 6a:36:51:46:27:61:5b:e9:9e:cf:f0:a2:55:7d:7c: + 25:8a:6f:2f:b4:c5:cf:84:2e:2b:fd:0d:51:10:6c: + fb:5f:1b:bc:1b:7e:c5:ae:3b:98:01:31:92:ff:0b: + 57:f4:9a:b2:b9:57:e9:ab:ef:0d:76:d1:f0:ee:f4: + ce:86:a7:e0:6e:e9:b4:69:a1:df:69:f6:33:c6:69: + 2e:97:13:9e:a5:87:b0:57:10:81:37:c9:53:b3:bb: + 7f:f6:92:d1:9c:d0:18:f4:92:6e:da:83:4f:a6:63: + 99:4c:a5:fb:5e:ef:21:64:7a:20:5f:6c:64:85:15: + cb:37:e9:62:0c:0b:2a:16:dc:01:2e:32:da:3e:4b: + f5:9e:3a:f6:17:40:94:ef:9e:91:08:86:fa:be:63: + a8:5a:33:ec:cb:74:43:95:f9:6c:69:52:36:c7:29: + 6f:fc:55:03:5c:1f:fb:9f:bd:47:eb:e7:49:47:95: + 0b:4e:89:22:09:49:e0:f5:61:1e:f1:bf:2e:8a:72: + 6e:80:59:ff:57:3a:f9:75:32:a3:4e:5f:ec:ed:28: + 62:d9:4d:73:f2:cc:81:17:60:ed:cd:eb:dc:db:a7: + ca:c5:7e:02:bd:f2:54:08:54:fd:b4:2d:09:2c:17: + 54:4a:98:d1:54:e1:51:67:08:d2:ed:6e:7e:6f:3f: + d2:2d:81:59:29:66:cb:90:39:95:11:1e:74:27:fe: + dd:eb:af + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + B0:0C:F0:4C:30:F4:05:58:02:48:FD:33:E5:52:AF:4B:84:E3:66:52 + Signature Algorithm: sha384WithRSAEncryption + aa:a8:80:8f:0e:78:a3:e0:a2:d4:cd:e6:f5:98:7a:3b:ea:00: + 03:b0:97:0e:93:bc:5a:a8:f6:2c:8c:72:87:a9:b1:fc:7f:73: + fd:63:71:78:a5:87:59:cf:30:e1:0d:10:b2:13:5a:6d:82:f5: + 6a:e6:80:9f:a0:05:0b:68:e4:47:6b:c7:6a:df:b6:fd:77:32: + 72:e5:18:fa:09:f4:a0:93:2c:5d:d2:8c:75:85:76:65:90:0c: + 03:79:b7:31:23:63:ad:78:83:09:86:68:84:ca:ff:f9:cf:26: + 9a:92:79:e7:cd:4b:c5:e7:61:a7:17:cb:f3:a9:12:93:93:6b: + a7:e8:2f:53:92:c4:60:58:b0:cc:02:51:18:5b:85:8d:62:59: + 63:b6:ad:b4:de:9a:fb:26:f7:00:27:c0:5d:55:37:74:99:c9: + 50:7f:e3:59:2e:44:e3:2c:25:ee:ec:4c:32:77:b4:9f:1a:e9: + 4b:5d:20:c5:da:fd:1c:87:16:c6:43:e8:d4:bb:26:9a:45:70: + 5e:a9:0b:37:53:e2:46:7b:27:fd:e0:46:f2:89:b7:cc:42:b6: + cb:28:26:6e:d9:a5:c9:3a:c8:41:13:60:f7:50:8c:15:ae:b2: + 6d:1a:15:1a:57:78:e6:92:2a:d9:65:90:82:3f:6c:02:af:ae: + 12:3a:27:96:36:04:d7:1d:a2:80:63:a9:9b:f1:e5:ba:b4:7c: + 14:b0:4e:c9:b1:1f:74:5f:38:f6:51:ea:9b:fa:2c:a2:11:d4: + a9:2d:27:1a:45:b1:af:b2:4e:71:0d:c0:58:46:d6:69:06:cb: + 53:cb:b3:fe:6b:41:cd:41:7e:7d:4c:0f:7c:72:79:7a:59:cd: + 5e:4a:0e:ac:9b:a9:98:73:79:7c:b4:f4:cc:b9:b8:07:0c:b2: + 74:5c:b8:c7:6f:88:a1:90:a7:f4:aa:f9:bf:67:3a:f4:1a:15: + 62:1e:b7:9f:be:3d:b1:29:af:67:a1:12:f2:58:10:19:53:03: + 30:1b:b8:1a:89:f6:9c:bd:97:03:8e:a3:09:f3:1d:8b:21:f1: + b4:df:e4:1c:d1:9f:65:02:06:ea:5c:d6:13:b3:84:ef:a2:a5: + 5c:8c:77:29:a7:68:c0:6b:ae:40:d2:a8:b4:ea:cd:f0:8d:4b: + 38:9c:19:9a:1b:28:54:b8:89:90:ef:ca:75:81:3e:1e:f2:64: + 24:c7:18:af:4e:ff:47:9e:07:f6:35:65:a4:d3:0a:56:ff:f5: + 17:64:6c:ef:a8:22:25:49:93:b6:df:00:17:da:58:7e:5d:ee: + c5:1b:b0:d1:d1:5f:21:10:c7:f9:f3:ba:02:0a:27:07:c5:f1: + d6:c7:d3:e0:fb:09:60:6c +-----BEGIN CERTIFICATE----- +MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwF +ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 +b24gUm9vdCBDQSAyMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTEL +MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv +b3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK2Wny2cSkxK +gXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4kHbZ +W0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg +1dKmSYXpN+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K +8nu+NQWpEjTj82R0Yiw9AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r +2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvdfLC6HM783k81ds8P+HgfajZRRidhW+me +z/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAExkv8LV/SasrlX6avvDXbR +8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSSbtqDT6Zj +mUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz +7Mt0Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6 ++XUyo05f7O0oYtlNc/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI +0u1ufm8/0i2BWSlmy5A5lREedCf+3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMB +Af8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSwDPBMMPQFWAJI/TPlUq9LhONm +UjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oAA7CXDpO8Wqj2 +LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY ++gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kS +k5Nrp+gvU5LEYFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl +7uxMMne0nxrpS10gxdr9HIcWxkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygm +btmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQgj9sAq+uEjonljYE1x2igGOpm/Hl +urR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbWaQbLU8uz/mtBzUF+ +fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoVYh63 +n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE +76KlXIx3KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H +9jVlpNMKVv/1F2Rs76giJUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT +4PsJYGw= +-----END CERTIFICATE----- + +Amazon Root CA 3 +# Fingerprint (SHA1): 0D:44:DD:8C:3C:8C:1A:1A:58:75:64:81:E9:0F:2E:2A:FF:B3:D2:6E +MUST_VERIFY_TRUST: CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +================================================ +MD5 Fingerprint=A0:D4:EF:0B:F7:B5:D8:49:95:2A:EC:F5:C4:FC:81:87 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 06:6c:9f:d5:74:97:36:66:3f:3b:0b:9a:d9:e8:9e:76:03:f2:4a + Signature Algorithm: ecdsa-with-SHA256 + Issuer: C=US, O=Amazon, CN=Amazon Root CA 3 + Validity + Not Before: May 26 00:00:00 2015 GMT + Not After : May 26 00:00:00 2040 GMT + Subject: C=US, O=Amazon, CN=Amazon Root CA 3 + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:29:97:a7:c6:41:7f:c0:0d:9b:e8:01:1b:56:c6: + f2:52:a5:ba:2d:b2:12:e8:d2:2e:d7:fa:c9:c5:d8: + aa:6d:1f:73:81:3b:3b:98:6b:39:7c:33:a5:c5:4e: + 86:8e:80:17:68:62:45:57:7d:44:58:1d:b3:37:e5: + 67:08:eb:66:de + ASN1 OID: prime256v1 + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + AB:B6:DB:D7:06:9E:37:AC:30:86:07:91:70:C7:9C:C4:19:B1:78:C0 + Signature Algorithm: ecdsa-with-SHA256 + 30:46:02:21:00:e0:85:92:a3:17:b7:8d:f9:2b:06:a5:93:ac: + 1a:98:68:61:72:fa:e1:a1:d0:fb:1c:78:60:a6:43:99:c5:b8: + c4:02:21:00:9c:02:ef:f1:94:9c:b3:96:f9:eb:c6:2a:f8:b6: + 2c:fe:3a:90:14:16:d7:8c:63:24:48:1c:df:30:7d:d5:68:3b +-----BEGIN CERTIFICATE----- +MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5 +MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g +Um9vdCBDQSAzMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG +A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg +Q0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZBf8ANm+gBG1bG8lKl +ui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjrZt6j +QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSr +ttvXBp43rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkr +BqWTrBqYaGFy+uGh0PsceGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteM +YyRIHN8wfdVoOw== +-----END CERTIFICATE----- + +Amazon Root CA 4 +# Fingerprint (SHA1): F6:10:84:07:D6:F8:BB:67:98:0C:C2:E2:44:C2:EB:AE:1C:EF:63:BE +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +MUST_VERIFY_TRUST: CODE_SIGNING +================================================ +MD5 Fingerprint=89:BC:27:D5:EB:17:8D:06:6A:69:D5:FD:89:47:B4:CD +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 06:6c:9f:d7:c1:bb:10:4c:29:43:e5:71:7b:7b:2c:c8:1a:c1:0e + Signature Algorithm: ecdsa-with-SHA384 + Issuer: C=US, O=Amazon, CN=Amazon Root CA 4 + Validity + Not Before: May 26 00:00:00 2015 GMT + Not After : May 26 00:00:00 2040 GMT + Subject: C=US, O=Amazon, CN=Amazon Root CA 4 + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (384 bit) + pub: + 04:d2:ab:8a:37:4f:a3:53:0d:fe:c1:8a:7b:4b:a8: + 7b:46:4b:63:b0:62:f6:2d:1b:db:08:71:21:d2:00: + e8:63:bd:9a:27:fb:f0:39:6e:5d:ea:3d:a5:c9:81: + aa:a3:5b:20:98:45:5d:16:db:fd:e8:10:6d:e3:9c: + e0:e3:bd:5f:84:62:f3:70:64:33:a0:cb:24:2f:70: + ba:88:a1:2a:a0:75:f8:81:ae:62:06:c4:81:db:39: + 6e:29:b0:1e:fa:2e:5c + ASN1 OID: secp384r1 + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + D3:EC:C7:3A:65:6E:CC:E1:DA:76:9A:56:FB:9C:F3:86:6D:57:E5:81 + Signature Algorithm: ecdsa-with-SHA384 + 30:65:02:30:3a:8b:21:f1:bd:7e:11:ad:d0:ef:58:96:2f:d6: + eb:9d:7e:90:8d:2b:cf:66:55:c3:2c:e3:28:a9:70:0a:47:0e: + f0:37:59:12:ff:2d:99:94:28:4e:2a:4f:35:4d:33:5a:02:31: + 00:ea:75:00:4e:3b:c4:3a:94:12:91:c9:58:46:9d:21:13:72: + a7:88:9c:8a:e4:4c:4a:db:96:d4:ac:8b:6b:6b:49:12:53:33: + ad:d7:e4:be:24:fc:b5:0a:76:d4:a5:bc:10 +-----BEGIN CERTIFICATE----- +MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5 +MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g +Um9vdCBDQSA0MB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG +A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg +Q0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN/sGKe0uoe0ZLY7Bi +9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri83Bk +M6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB +/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WB +MAoGCCqGSM49BAMDA2gAMGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlw +CkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1AE47xDqUEpHJWEadIRNyp4iciuRMStuW +1KyLa2tJElMzrdfkviT8tQp21KW8EA== +-----END CERTIFICATE----- + +LuxTrust Global Root 2 +# Fingerprint (SHA1): 1E:0E:56:19:0A:D1:8B:25:98:B2:04:44:FF:66:8A:04:17:99:5F:3F +MUST_VERIFY_TRUST: EMAIL_PROTECTION, CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH +================================================= +MD5 Fingerprint=B2:E1:09:00:61:AF:F7:F1:91:6F:C4:AD:8D:5E:3B:7C +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 0a:7e:a6:df:4b:44:9e:da:6a:24:85:9e:e6:b8:15:d3:16:7f:bb:b1 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=LU, O=LuxTrust S.A., CN=LuxTrust Global Root 2 + Validity + Not Before: Mar 5 13:21:57 2015 GMT + Not After : Mar 5 13:21:57 2035 GMT + Subject: C=LU, O=LuxTrust S.A., CN=LuxTrust Global Root 2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:d7:85:97:bf:11:98:e9:f0:62:83:4c:3c:87:f9: + 53:6a:37:0b:f2:0f:3c:87:ce:6f:dc:26:29:bd:c5: + 89:ba:c9:83:3d:f7:ee:ca:5b:c6:6d:49:73:b4:c9: + 46:a3:1b:34:13:3f:c1:89:45:57:f4:d9:b1:fb:36: + 65:4b:fb:08:e2:48:71:11:c8:6e:3b:9e:9d:df:89: + 65:37:a6:85:f6:3b:44:18:b6:c6:37:30:62:44:92: + 97:69:7d:42:30:24:e4:0d:0c:89:6b:63:de:c5:e1: + df:4e:a9:14:6c:53:e0:61:ce:f6:17:2f:1d:3c:bd: + e6:22:4c:1d:93:f5:10:c4:a1:76:ec:6a:de:c5:6c: + df:96:b4:56:40:42:c0:62:92:30:a1:2d:15:94:a0: + d2:20:06:09:6e:6a:6d:e5:eb:b7:be:d4:f0:f1:15: + 7c:8b:e6:4e:ba:13:cc:4b:27:5e:99:3c:17:5d:8f: + 81:7f:33:3d:4f:d3:3f:1b:ec:5c:3f:f0:3c:4c:75: + 6e:f2:a6:d5:9d:da:2d:07:63:02:c6:72:e9:94:bc: + 4c:49:95:4f:88:52:c8:db:e8:69:82:f8:cc:34:5b: + 22:f0:86:a7:89:bd:48:0a:6d:66:81:6d:c8:c8:64: + fb:01:e1:f4:e1:de:d9:9e:dd:db:5b:d4:2a:99:26: + 15:1b:1e:4c:92:29:82:9e:d5:92:81:92:41:70:19: + f7:a4:e5:93:4b:bc:77:67:31:dd:1c:fd:31:70:0d: + 17:99:0c:f9:0c:39:19:2a:17:b5:30:71:55:d5:0f: + ae:58:e1:3d:2f:34:9b:cf:9f:f6:78:85:c2:93:7a: + 72:3e:66:8f:9c:16:11:60:8f:9e:89:6f:67:be:e0: + 47:5a:3b:0c:9a:67:8b:cf:46:c6:ae:38:a3:f2:a7: + bc:e6:d6:85:6b:33:24:70:22:4b:cb:08:9b:bb:c8: + f8:02:29:1d:be:20:0c:46:bf:6b:87:9b:b3:2a:66: + 42:35:46:6c:aa:ba:ad:f9:98:7b:e9:50:55:14:31: + bf:b1:da:2d:ed:80:ad:68:24:fb:69:ab:d8:71:13: + 30:e6:67:b3:87:40:fd:89:7e:f2:43:d1:11:df:2f: + 65:2f:64:ce:5f:14:b9:b1:bf:31:bd:87:78:5a:59: + 65:88:aa:fc:59:32:48:86:d6:4c:b9:29:4b:95:d3: + 76:f3:77:25:6d:42:1c:38:83:4d:fd:a3:5f:9b:7f: + 2d:ac:79:1b:0e:42:31:97:63:a4:fb:8a:69:d5:22: + 0d:34:90:30:2e:a8:b4:e0:6d:b6:94:ac:bc:8b:4e: + d7:70:fc:c5:38:8e:64:25:e1:4d:39:90:ce:c9:87: + 84:58:71 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Certificate Policies: + Policy: 1.3.171.1.1.1.10 + CPS: https://repository.luxtrust.lu + + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Authority Key Identifier: + keyid:FF:18:28:76:F9:48:05:2C:A1:AE:F1:2B:1B:2B:B2:53:F8:4B:7C:B3 + + X509v3 Subject Key Identifier: + FF:18:28:76:F9:48:05:2C:A1:AE:F1:2B:1B:2B:B2:53:F8:4B:7C:B3 + Signature Algorithm: sha256WithRSAEncryption + 6a:19:14:ed:6e:79:c1:2c:87:d4:0d:70:7e:d7:f6:78:c9:0b: + 04:4e:c4:b1:ce:93:70:fe:b0:54:c0:32:cd:99:30:64:17:bf: + 0f:e5:e2:33:fd:07:36:40:72:0e:1a:b6:6a:59:d6:00:e5:68: + 20:dd:2e:72:0d:1f:6a:64:31:20:84:7d:49:a6:5a:37:eb:45: + c9:85:f5:d4:c7:17:99:07:e6:9b:55:e4:0c:e8:a9:b4:ce:8c: + 5b:b5:11:5c:cf:8a:0e:0d:d6:ac:77:81:fe:32:9c:24:9e:72: + ce:54:f3:d0:6f:a2:56:d6:ec:c3:37:2c:65:58:be:57:00:1a: + f2:35:fa:eb:7b:31:5d:c2:c1:12:3d:96:81:88:96:89:c1:59: + 5c:7a:e6:7f:70:34:e7:83:e2:b1:e1:e1:b8:58:ef:d4:95:e4: + 60:9c:f0:96:97:72:8c:eb:84:02:2e:65:8f:a4:b7:d2:7f:67: + dd:c8:d3:9e:5c:aa:a9:a4:a0:25:14:06:9b:ec:4f:7e:2d:0b: + 7f:1d:75:f1:33:d8:ed:ce:b8:75:6d:3e:5b:b9:98:1d:31:0d: + 56:d8:43:0f:30:91:b2:04:6b:dd:56:be:95:80:55:67:be:d8: + cd:83:d9:18:ee:2e:0f:86:2d:92:9e:70:13:ec:de:51:c9:43: + 78:02:a5:4d:c8:f9:5f:c4:91:58:46:16:77:5a:74:aa:40:bc: + 07:9f:30:b9:b1:f7:12:17:dd:e3:ff:24:40:1d:7a:6a:d1:4f: + 18:0a:aa:90:1d:eb:40:1e:df:a1:1e:44:92:10:9a:f2:8d:e1: + d1:4b:46:9e:e8:45:42:97:ea:45:99:f3:ec:66:d5:02:fa:f2: + a6:4a:24:aa:de:ce:b9:ca:f9:3f:93:6f:f9:a3:ba:ea:a5:3e: + 99:ad:fd:ff:7b:99:f5:65:ee:f0:59:28:67:d7:90:95:a4:13: + 84:a9:84:c1:e8:ce:ce:75:93:63:1a:bc:3c:ea:d5:64:1f:2d: + 2a:12:39:c6:c3:5a:32:ed:47:91:16:0e:bc:38:c1:50:de:8f: + ca:2a:90:34:1c:ee:41:94:9c:5e:19:2e:f8:45:49:99:74:91: + b0:04:6f:e3:04:5a:b1:ab:2a:ab:fe:c7:d0:96:b6:da:e1:4a: + 64:06:6e:60:4d:bd:42:4e:ff:78:da:24:ca:1b:b4:d7:96:39: + 6c:ae:f1:0e:aa:a7:7d:48:8b:20:4c:cf:64:d6:b8:97:46:b0: + 4e:d1:2a:56:3a:a0:93:bd:af:80:24:e0:0a:7e:e7:ca:d5:ca: + e8:85:55:dc:36:2a:e1:94:68:93:c7:66:72:44:0f:80:21:32: + 6c:25:c7:23:80:83:0a:eb +-----BEGIN CERTIFICATE----- +MIIFwzCCA6ugAwIBAgIUCn6m30tEntpqJIWe5rgV0xZ/u7EwDQYJKoZIhvcNAQEL +BQAwRjELMAkGA1UEBhMCTFUxFjAUBgNVBAoMDUx1eFRydXN0IFMuQS4xHzAdBgNV +BAMMFkx1eFRydXN0IEdsb2JhbCBSb290IDIwHhcNMTUwMzA1MTMyMTU3WhcNMzUw +MzA1MTMyMTU3WjBGMQswCQYDVQQGEwJMVTEWMBQGA1UECgwNTHV4VHJ1c3QgUy5B +LjEfMB0GA1UEAwwWTHV4VHJ1c3QgR2xvYmFsIFJvb3QgMjCCAiIwDQYJKoZIhvcN +AQEBBQADggIPADCCAgoCggIBANeFl78RmOnwYoNMPIf5U2o3C/IPPIfOb9wmKb3F +ibrJgz337spbxm1Jc7TJRqMbNBM/wYlFV/TZsfs2ZUv7COJIcRHIbjuend+JZTem +hfY7RBi2xjcwYkSSl2l9QjAk5A0MiWtj3sXh306pFGxT4GHO9hcvHTy95iJMHZP1 +EMShduxq3sVs35a0VkBCwGKSMKEtFZSg0iAGCW5qbeXrt77U8PEVfIvmTroTzEsn +Xpk8F12PgX8zPU/TPxvsXD/wPEx1bvKm1Z3aLQdjAsZy6ZS8TEmVT4hSyNvoaYL4 +zDRbIvCGp4m9SAptZoFtyMhk+wHh9OHe2Z7d21vUKpkmFRseTJIpgp7VkoGSQXAZ +96Tlk0u8d2cx3Rz9MXANF5kM+Qw5GSoXtTBxVdUPrljhPS80m8+f9niFwpN6cj5m +j5wWEWCPnolvZ77gR1o7DJpni89Gxq44o/KnvObWhWszJHAiS8sIm7vI+AIpHb4g +DEa/a4ebsypmQjVGbKq6rfmYe+lQVRQxv7HaLe2ArWgk+2mr2HETMOZns4dA/Yl+ +8kPREd8vZS9kzl8UubG/Mb2HeFpZZYiq/FkySIbWTLkpS5XTdvN3JW1CHDiDTf2j +X5t/Lax5Gw5CMZdjpPuKadUiDTSQMC6otOBttpSsvItO13D8xTiOZCXhTTmQzsmH +hFhxAgMBAAGjgagwgaUwDwYDVR0TAQH/BAUwAwEB/zBCBgNVHSAEOzA5MDcGByuB +KwEBAQowLDAqBggrBgEFBQcCARYeaHR0cHM6Ly9yZXBvc2l0b3J5Lmx1eHRydXN0 +Lmx1MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBT/GCh2+UgFLKGu8SsbK7JT ++Et8szAdBgNVHQ4EFgQU/xgodvlIBSyhrvErGyuyU/hLfLMwDQYJKoZIhvcNAQEL +BQADggIBAGoZFO1uecEsh9QNcH7X9njJCwROxLHOk3D+sFTAMs2ZMGQXvw/l4jP9 +BzZAcg4atmpZ1gDlaCDdLnINH2pkMSCEfUmmWjfrRcmF9dTHF5kH5ptV5AzoqbTO +jFu1EVzPig4N1qx3gf4ynCSecs5U89BvolbW7MM3LGVYvlcAGvI1+ut7MV3CwRI9 +loGIlonBWVx65n9wNOeD4rHh4bhY79SV5GCc8JaXcozrhAIuZY+kt9J/Z93I055c +qqmkoCUUBpvsT34tC38ddfEz2O3OuHVtPlu5mB0xDVbYQw8wkbIEa91WvpWAVWe+ +2M2D2RjuLg+GLZKecBPs3lHJQ3gCpU3I+V/EkVhGFndadKpAvAefMLmx9xIX3eP/ +JEAdemrRTxgKqpAd60Ae36EeRJIQmvKN4dFLRp7oRUKX6kWZ8+xm1QL68qZKJKre +zrnK+T+Tb/mjuuqlPpmt/f97mfVl7vBZKGfXkJWkE4SphMHozs51k2MavDzq1WQf +LSoSOcbDWjLtR5EWDrw4wVDej8oqkDQc7kGUnF4ZLvhFSZl0kbAEb+MEWrGrKqv+ +x9CWttrhSmQGbmBNvUJO/3jaJMobtNeWOWyu8Q6qp31IiyBMz2TWuJdGsE7RKlY6 +oJO9r4Ak4Ap+58rVyuiFVdw2KuGUaJPHZnJED4AhMmwlxyOAgwrr +-----END CERTIFICATE----- + +TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1 +# Fingerprint (SHA1): 31:43:64:9B:EC:CE:27:EC:ED:3A:3F:0B:8F:0D:E4:E8:91:DD:EE:CA +TRUSTED_DELEGATOR: SERVER_AUTH +MUST_VERIFY_TRUST: EMAIL_PROTECTION, CODE_SIGNING +================================================= +MD5 Fingerprint=DC:00:81:DC:69:2F:3E:2F:B0:3B:F6:3D:5A:91:8E:49 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 1 (0x1) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=TR, L=Gebze - Kocaeli, O=Turkiye Bilimsel ve Teknolojik Arastirma Kurumu - TUBITAK, OU=Kamu Sertifikasyon Merkezi - Kamu SM, CN=TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1 + Validity + Not Before: Nov 25 08:25:55 2013 GMT + Not After : Oct 25 08:25:55 2043 GMT + Subject: C=TR, L=Gebze - Kocaeli, O=Turkiye Bilimsel ve Teknolojik Arastirma Kurumu - TUBITAK, OU=Kamu Sertifikasyon Merkezi - Kamu SM, CN=TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:af:75:30:33:aa:bb:6b:d3:99:2c:12:37:84:d9: + 8d:7b:97:80:d3:6e:e7:ff:9b:50:95:3e:90:95:56: + 42:d7:19:7c:26:84:8d:92:fa:01:1d:3a:0f:e2:64: + 38:b7:8c:bc:e8:88:f9:8b:24:ab:2e:a3:f5:37:e4: + 40:8e:18:25:79:83:75:1f:3b:ff:6c:a8:c5:c6:56: + f8:b4:ed:8a:44:a3:ab:6c:4c:fc:1d:d0:dc:ef:68: + bd:cf:e4:aa:ce:f0:55:f7:a2:34:d4:83:6b:37:7c: + 1c:c2:fe:b5:03:ec:57:ce:bc:b4:b5:c5:ed:00:0f: + 53:37:2a:4d:f4:4f:0c:83:fb:86:cf:cb:fe:8c:4e: + bd:87:f9:a7:8b:21:57:9c:7a:df:03:67:89:2c:9d: + 97:61:a7:10:b8:55:90:7f:0e:2d:27:38:74:df:e7: + fd:da:4e:12:e3:4d:15:22:02:c8:e0:e0:fc:0f:ad: + 8a:d7:c9:54:50:cc:3b:0f:ca:16:80:84:d0:51:56: + c3:8e:56:7f:89:22:33:2f:e6:85:0a:bd:a5:a8:1b: + 36:de:d3:dc:2c:6d:3b:c7:13:bd:59:23:2c:e6:e5: + a4:f7:d8:0b:ed:ea:90:40:44:a8:95:bb:93:d5:d0: + 80:34:b6:46:78:0e:1f:00:93:46:e1:ee:e9:f9:ec: + 4f:17 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + 65:3F:C7:8A:86:C6:3C:DD:3C:54:5C:35:F8:3A:ED:52:0C:47:57:C8 + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + Signature Algorithm: sha256WithRSAEncryption + 2a:3f:e1:f1:32:8e:ae:e1:98:5c:4b:5e:cf:6b:1e:6a:09:d2: + 22:a9:12:c7:5e:57:7d:73:56:64:80:84:7a:93:e4:09:b9:10: + cd:9f:2a:27:e1:00:77:be:48:c8:35:a8:81:9f:e4:b8:2c:c9: + 7f:0e:b0:d2:4b:37:5d:ea:b9:d5:0b:5e:34:bd:f4:73:29:c3: + ed:26:15:9c:7e:08:53:8a:58:8d:d0:4b:28:df:c1:b3:df:20: + f3:f9:e3:e3:3a:df:cc:9c:94:d8:4e:4f:c3:6b:17:b7:f7:72: + e8:ad:66:33:b5:25:53:ab:e0:f8:4c:a9:9d:fd:f2:0d:ba:ae: + b9:d9:aa:c6:6b:f9:93:bb:ae:ab:b8:97:3c:03:1a:ba:43:c6: + 96:b9:45:72:38:b3:a7:a1:96:3d:91:7b:7e:c0:21:53:4c:87: + ed:f2:0b:54:95:51:93:d5:22:a5:0d:8a:f1:93:0e:3e:54:0e: + b0:d8:c9:4e:dc:f2:31:32:56:ea:64:f9:ea:b5:9d:16:66:42: + 72:f3:7f:d3:b1:31:43:fc:a4:8e:17:f1:6d:23:ab:94:66:f8: + ad:fb:0f:08:6e:26:2d:7f:17:07:09:b2:8c:fb:50:c0:9f:96: + 8d:cf:b6:fd:00:9d:5a:14:9a:bf:02:44:f5:c1:c2:9f:22:5e: + a2:0f:a1:e3 +-----BEGIN CERTIFICATE----- +MIIEYzCCA0ugAwIBAgIBATANBgkqhkiG9w0BAQsFADCB0jELMAkGA1UEBhMCVFIx +GDAWBgNVBAcTD0dlYnplIC0gS29jYWVsaTFCMEAGA1UEChM5VHVya2l5ZSBCaWxp +bXNlbCB2ZSBUZWtub2xvamlrIEFyYXN0aXJtYSBLdXJ1bXUgLSBUVUJJVEFLMS0w +KwYDVQQLEyRLYW11IFNlcnRpZmlrYXN5b24gTWVya2V6aSAtIEthbXUgU00xNjA0 +BgNVBAMTLVRVQklUQUsgS2FtdSBTTSBTU0wgS29rIFNlcnRpZmlrYXNpIC0gU3Vy +dW0gMTAeFw0xMzExMjUwODI1NTVaFw00MzEwMjUwODI1NTVaMIHSMQswCQYDVQQG +EwJUUjEYMBYGA1UEBxMPR2ViemUgLSBLb2NhZWxpMUIwQAYDVQQKEzlUdXJraXll +IEJpbGltc2VsIHZlIFRla25vbG9qaWsgQXJhc3Rpcm1hIEt1cnVtdSAtIFRVQklU +QUsxLTArBgNVBAsTJEthbXUgU2VydGlmaWthc3lvbiBNZXJrZXppIC0gS2FtdSBT +TTE2MDQGA1UEAxMtVFVCSVRBSyBLYW11IFNNIFNTTCBLb2sgU2VydGlmaWthc2kg +LSBTdXJ1bSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr3UwM6q7 +a9OZLBI3hNmNe5eA027n/5tQlT6QlVZC1xl8JoSNkvoBHToP4mQ4t4y86Ij5iySr +LqP1N+RAjhgleYN1Hzv/bKjFxlb4tO2KRKOrbEz8HdDc72i9z+SqzvBV96I01INr +N3wcwv61A+xXzry0tcXtAA9TNypN9E8Mg/uGz8v+jE69h/mniyFXnHrfA2eJLJ2X +YacQuFWQfw4tJzh03+f92k4S400VIgLI4OD8D62K18lUUMw7D8oWgITQUVbDjlZ/ +iSIzL+aFCr2lqBs23tPcLG07xxO9WSMs5uWk99gL7eqQQESolbuT1dCANLZGeA4f +AJNG4e7p+exPFwIDAQABo0IwQDAdBgNVHQ4EFgQUZT/HiobGPN08VFw1+DrtUgxH +V8gwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL +BQADggEBACo/4fEyjq7hmFxLXs9rHmoJ0iKpEsdeV31zVmSAhHqT5Am5EM2fKifh +AHe+SMg1qIGf5LgsyX8OsNJLN13qudULXjS99HMpw+0mFZx+CFOKWI3QSyjfwbPf +IPP54+M638yclNhOT8NrF7f3cuitZjO1JVOr4PhMqZ398g26rrnZqsZr+ZO7rqu4 +lzwDGrpDxpa5RXI4s6ehlj2Re37AIVNMh+3yC1SVUZPVIqUNivGTDj5UDrDYyU7c +8jEyVupk+eq1nRZmQnLzf9OxMUP8pI4X8W0jq5Rm+K37DwhuJi1/FwcJsoz7UMCf +lo3Ptv0AnVoUmr8CRPXBwp8iXqIPoeM= +-----END CERTIFICATE----- + +GDCA TrustAUTH R5 ROOT +# Fingerprint (SHA1): 0F:36:38:5B:81:1A:25:C3:9B:31:4E:83:CA:E9:34:66:70:CC:74:B4 +TRUSTED_DELEGATOR: SERVER_AUTH +MUST_VERIFY_TRUST: EMAIL_PROTECTION, CODE_SIGNING +================================================= +MD5 Fingerprint=63:CC:D9:3D:34:35:5C:6F:53:A3:E2:08:70:48:1F:B4 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 9009899650740120186 (0x7d0997fef047ea7a) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=CN, O=GUANG DONG CERTIFICATE AUTHORITY CO.,LTD., CN=GDCA TrustAUTH R5 ROOT + Validity + Not Before: Nov 26 05:13:15 2014 GMT + Not After : Dec 31 15:59:59 2040 GMT + Subject: C=CN, O=GUANG DONG CERTIFICATE AUTHORITY CO.,LTD., CN=GDCA TrustAUTH R5 ROOT + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:d9:a3:16:f0:c8:74:74:77:9b:ef:33:0d:3b:06: + 7e:55:fc:b5:60:8f:76:86:12:42:7d:56:66:3e:88: + 82:ed:72:63:0e:9e:8b:dd:34:2c:02:51:51:c3:19: + fd:59:54:84:c9:f1:6b:b3:4c:b0:e9:e8:46:5d:38: + c6:a2:a7:2e:11:57:ba:82:15:a2:9c:8f:6d:b0:99: + 4a:0a:f2:eb:89:70:63:4e:79:c4:b7:5b:bd:a2:5d: + b1:f2:41:02:2b:ad:a9:3a:a3:ec:79:0a:ec:5f:3a: + e3:fd:ef:80:3c:ad:34:9b:1a:ab:88:26:7b:56:a2: + 82:86:1f:eb:35:89:83:7f:5f:ae:29:4e:3d:b6:6e: + ec:ae:c1:f0:27:9b:ae:e3:f4:ec:ef:ae:7f:f7:86: + 3d:72:7a:eb:a5:fb:59:4e:a7:eb:95:8c:22:39:79: + e1:2d:08:8f:cc:bc:91:b8:41:f7:14:c1:23:a9:c3: + ad:9a:45:44:b3:b2:d7:2c:cd:c6:29:e2:50:10:ae: + 5c:cb:82:8e:17:18:36:7d:97:e6:88:9a:b0:4d:34: + 09:f4:2c:b9:5a:66:2a:b0:17:9b:9e:1e:76:9d:4a: + 66:31:41:df:3f:fb:c5:06:ef:1b:b6:7e:1a:46:36: + f7:64:63:3b:e3:39:18:23:e7:67:75:14:d5:75:57: + 92:37:bd:be:6a:1b:26:50:f2:36:26:06:90:c5:70: + 01:64:6d:76:66:e1:91:db:6e:07:c0:61:80:2e:b2: + 2e:2f:8c:70:a7:d1:3b:3c:b3:91:e4:6e:b6:c4:3b: + 70:f2:6c:92:97:09:cd:47:7d:18:c0:f3:bb:9e:0f: + d6:8b:ae:07:b6:5a:0f:ce:0b:0c:47:a7:e5:3e:b8: + bd:7d:c7:9b:35:a0:61:97:3a:41:75:17:cc:2b:96: + 77:2a:92:21:1e:d9:95:76:20:67:68:cf:0d:bd:df: + d6:1f:09:6a:9a:e2:cc:73:71:a4:2f:7d:12:80:b7: + 53:30:46:5e:4b:54:99:0f:67:c9:a5:c8:f2:20:c1: + 82:ec:9d:11:df:c2:02:fb:1a:3b:d1:ed:20:9a:ef: + 65:64:92:10:0d:2a:e2:de:70:f1:18:67:82:8c:61: + de:b8:bc:d1:2f:9c:fb:0f:d0:2b:ed:1b:76:b9:e4: + 39:55:f8:f8:a1:1d:b8:aa:80:00:4c:82:e7:b2:7f: + 09:b8:bc:30:a0:2f:0d:f5:52:9e:8e:f7:92:b3:0a: + 00:1d:00:54:97:06:e0:b1:07:d9:c7:0f:5c:65:7d: + 3c:6d:59:57:e4:ed:a5:8d:e9:40:53:9f:15:4b:a0: + 71:f6:1a:21:e3:da:70:06:21:58:14:87:85:77:79: + aa:82:79 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + E2:C9:40:9F:4D:CE:E8:9A:A1:7C:CF:0E:3F:65:C5:29:88:6A:19:51 + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + Signature Algorithm: sha256WithRSAEncryption + d1:49:57:e0:a7:cc:68:58:ba:01:0f:2b:19:cd:8d:b0:61:45: + ac:11:ed:63:50:69:f8:1f:7f:be:16:8f:fd:9d:eb:0b:aa:32: + 47:76:d2:67:24:ed:bd:7c:33:32:97:2a:c7:05:86:66:0d:17: + 7d:14:15:1b:d4:eb:fd:1f:9a:f6:5e:97:69:b7:1a:25:a4:0a: + b3:91:3f:5f:36:ac:8b:ec:57:a8:3e:e7:81:8a:18:57:39:85: + 74:1a:42:c7:e9:5b:13:5f:8f:f9:08:e9:92:74:8d:f5:47:d2: + ab:3b:d6:fb:78:66:4e:36:7d:f9:e9:92:e9:04:de:fd:49:63: + fc:6d:fb:14:71:93:67:2f:47:4a:b7:b9:ff:1e:2a:73:70:46: + 30:bf:5a:f2:2f:79:a5:e1:8d:0c:d9:f9:b2:63:37:8c:37:65: + 85:70:6a:5c:5b:09:72:b9:ad:63:3c:b1:dd:f8:fc:32:bf:37: + 86:e4:bb:8e:98:27:7e:ba:1f:16:e1:70:11:f2:03:df:25:62: + 32:27:26:18:32:84:9f:ff:00:3a:13:ba:9a:4d:f4:4f:b8:14: + 70:22:b1:ca:2b:90:ce:29:c1:70:f4:2f:9d:7f:f2:90:1e:d6: + 5a:df:b7:46:fc:e6:86:fa:cb:e0:20:76:7a:ba:a6:cb:f5:7c: + de:62:a5:b1:8b:ee:de:82:66:8a:4e:3a:30:1f:3f:80:cb:ad: + 27:ba:0c:5e:d7:d0:b1:56:ca:77:71:b2:b5:75:a1:50:a9:40: + 43:17:c2:28:d9:cf:52:8b:5b:c8:63:d4:42:3e:a0:33:7a:46: + 2e:f7:0a:20:46:54:7e:6a:4f:31:f1:81:7e:42:74:38:65:73: + 27:ee:c6:7c:b8:8e:d7:a5:3a:d7:98:a1:9c:8c:10:55:d3:db: + 4b:ec:40:90:f2:cd:6e:57:d2:62:0e:7c:57:93:b1:a7:6d:cd: + 9d:83:bb:2a:e7:e5:b6:3b:71:58:ad:fd:d1:45:bc:5a:91:ee: + 53:15:6f:d3:45:09:75:6e:ba:90:5d:1e:04:cf:37:df:1e:a8: + 66:b1:8c:e6:20:6a:ef:fc:48:4e:74:98:42:af:29:6f:2e:6a: + c7:fb:7d:d1:66:31:22:cc:86:00:7e:66:83:0c:42:f4:bd:34: + 92:c3:1a:ea:4f:ca:7e:72:4d:0b:70:8c:a6:48:bb:a6:a1:14: + f6:fb:58:44:99:14:ae:aa:0b:93:69:a0:29:25:4a:a5:cb:2b: + dd:8a:66:07:16:78:15:57:71:1b:ec:f5:47:84:f3:9e:31:37: + 7a:d5:7f:24:ad:e4:bc:fd:fd:cc:6e:83:e8:0c:a8:b7:41:6c: + 07:dd:bd:3c:86:97:2f:d2 +-----BEGIN CERTIFICATE----- +MIIFiDCCA3CgAwIBAgIIfQmX/vBH6nowDQYJKoZIhvcNAQELBQAwYjELMAkGA1UE +BhMCQ04xMjAwBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZ +IENPLixMVEQuMR8wHQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMB4XDTE0 +MTEyNjA1MTMxNVoXDTQwMTIzMTE1NTk1OVowYjELMAkGA1UEBhMCQ04xMjAwBgNV +BAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZIENPLixMVEQuMR8w +HQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMIICIjANBgkqhkiG9w0BAQEF +AAOCAg8AMIICCgKCAgEA2aMW8Mh0dHeb7zMNOwZ+Vfy1YI92hhJCfVZmPoiC7XJj +Dp6L3TQsAlFRwxn9WVSEyfFrs0yw6ehGXTjGoqcuEVe6ghWinI9tsJlKCvLriXBj +TnnEt1u9ol2x8kECK62pOqPseQrsXzrj/e+APK00mxqriCZ7VqKChh/rNYmDf1+u +KU49tm7srsHwJ5uu4/Ts765/94Y9cnrrpftZTqfrlYwiOXnhLQiPzLyRuEH3FMEj +qcOtmkVEs7LXLM3GKeJQEK5cy4KOFxg2fZfmiJqwTTQJ9Cy5WmYqsBebnh52nUpm +MUHfP/vFBu8btn4aRjb3ZGM74zkYI+dndRTVdVeSN72+ahsmUPI2JgaQxXABZG12 +ZuGR224HwGGALrIuL4xwp9E7PLOR5G62xDtw8mySlwnNR30YwPO7ng/Wi64HtloP +zgsMR6flPri9fcebNaBhlzpBdRfMK5Z3KpIhHtmVdiBnaM8Nvd/WHwlqmuLMc3Gk +L30SgLdTMEZeS1SZD2fJpcjyIMGC7J0R38IC+xo70e0gmu9lZJIQDSri3nDxGGeC +jGHeuLzRL5z7D9Ar7Rt2ueQ5Vfj4oR24qoAATILnsn8JuLwwoC8N9VKejveSswoA +HQBUlwbgsQfZxw9cZX08bVlX5O2ljelAU58VS6Bx9hoh49pwBiFYFIeFd3mqgnkC +AwEAAaNCMEAwHQYDVR0OBBYEFOLJQJ9NzuiaoXzPDj9lxSmIahlRMA8GA1UdEwEB +/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQDRSVfg +p8xoWLoBDysZzY2wYUWsEe1jUGn4H3++Fo/9nesLqjJHdtJnJO29fDMylyrHBYZm +DRd9FBUb1Ov9H5r2XpdptxolpAqzkT9fNqyL7FeoPueBihhXOYV0GkLH6VsTX4/5 +COmSdI31R9KrO9b7eGZONn356ZLpBN79SWP8bfsUcZNnL0dKt7n/HipzcEYwv1ry +L3ml4Y0M2fmyYzeMN2WFcGpcWwlyua1jPLHd+PwyvzeG5LuOmCd+uh8W4XAR8gPf +JWIyJyYYMoSf/wA6E7qaTfRPuBRwIrHKK5DOKcFw9C+df/KQHtZa37dG/OaG+svg +IHZ6uqbL9XzeYqWxi+7egmaKTjowHz+Ay60nugxe19CxVsp3cbK1daFQqUBDF8Io +2c9Si1vIY9RCPqAzekYu9wogRlR+ak8x8YF+QnQ4ZXMn7sZ8uI7XpTrXmKGcjBBV +09tL7ECQ8s1uV9JiDnxXk7Gnbc2dg7sq5+W2O3FYrf3RRbxake5TFW/TRQl1brqQ +XR4EzzffHqhmsYzmIGrv/EhOdJhCrylvLmrH+33RZjEizIYAfmaDDEL0vTSSwxrq +T8p+ck0LcIymSLumoRT2+1hEmRSuqguTaaApJUqlyyvdimYHFngVV3Eb7PVHhPOe +MTd61X8kreS8/f3MboPoDKi3QWwH3b08hpcv0g== +-----END CERTIFICATE----- + +TrustCor RootCert CA-1 +# Fingerprint (SHA1): FF:BD:CD:E7:82:C8:43:5E:3C:6F:26:86:5C:CA:A8:3A:45:5B:C3:0A +MUST_VERIFY_TRUST: CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +================================================ +MD5 Fingerprint=6E:85:F1:DC:1A:00:D3:22:D5:B2:B2:AC:6B:37:05:45 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + da:9b:ec:71:f3:03:b0:19 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=PA, ST=Panama, L=Panama City, O=TrustCor Systems S. de R.L., OU=TrustCor Certificate Authority, CN=TrustCor RootCert CA-1 + Validity + Not Before: Feb 4 12:32:16 2016 GMT + Not After : Dec 31 17:23:16 2029 GMT + Subject: C=PA, ST=Panama, L=Panama City, O=TrustCor Systems S. de R.L., OU=TrustCor Certificate Authority, CN=TrustCor RootCert CA-1 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:bf:8e:b7:95:e2:c2:26:12:6b:33:19:c7:40:58: + 0a:ab:59:aa:8d:00:a3:fc:80:c7:50:7b:8e:d4:20: + 26:ba:32:12:d8:23:54:49:25:10:22:98:9d:46:d2: + c1:c9:9e:4e:1b:2e:2c:0e:38:f3:1a:25:68:1c:a6: + 5a:05:e6:1e:8b:48:bf:98:96:74:3e:69:ca:e9:b5: + 78:a5:06:bc:d5:00:5e:09:0a:f2:27:7a:52:fc:2d: + d5:b1:ea:b4:89:61:24:f3:1a:13:db:a9:cf:52:ed: + 0c:24:ba:b9:9e:ec:7e:00:74:fa:93:ad:6c:29:92: + ae:51:b4:bb:d3:57:bf:b3:f3:a8:8d:9c:f4:24:4b: + 2a:d6:99:9e:f4:9e:fe:c0:7e:42:3a:e7:0b:95:53: + da:b7:68:0e:90:4c:fb:70:3f:8f:4a:2c:94:f3:26: + dd:63:69:a9:94:d8:10:4e:c5:47:08:90:99:1b:17: + 4d:b9:6c:6e:ef:60:95:11:8e:21:80:b5:bd:a0:73: + d8:d0:b2:77:c4:45:ea:5a:26:fb:66:76:76:f8:06: + 1f:61:6d:0f:55:c5:83:b7:10:56:72:06:07:a5:f3: + b1:1a:03:05:64:0e:9d:5a:8a:d6:86:70:1b:24:de: + fe:28:8a:2b:d0:6a:b0:fc:7a:a2:dc:b2:79:0e:8b: + 65:0f + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + EE:6B:49:3C:7A:3F:0D:E3:B1:09:B7:8A:C8:AB:19:9F:73:33:50:E7 + X509v3 Authority Key Identifier: + keyid:EE:6B:49:3C:7A:3F:0D:E3:B1:09:B7:8A:C8:AB:19:9F:73:33:50:E7 + + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + Signature Algorithm: sha256WithRSAEncryption + 25:18:d4:91:8f:13:ee:8f:1e:1d:11:53:da:2d:44:29:19:a0: + 1e:6b:31:9e:4d:0e:9e:ad:3d:5c:41:6f:95:2b:24:a1:79:98: + 3a:38:36:fb:bb:66:9e:48:ff:90:90:ef:3d:d4:b8:9b:b4:87: + 75:3f:20:9b:ce:72:cf:a1:55:c1:4d:64:a2:19:06:a1:07:33: + 0c:0b:29:e5:f1:ea:ab:a3:ec:b5:0a:74:90:c7:7d:72:f2:d7: + 5c:9f:91:ef:91:8b:b7:dc:ed:66:a2:cf:8e:66:3b:bc:9f:3a: + 02:e0:27:dd:16:98:c0:95:d4:0a:a4:e4:81:9a:75:94:35:9c: + 90:5f:88:37:06:ad:59:95:0a:b0:d1:67:d3:19:ca:89:e7:32: + 5a:36:1c:3e:82:a8:5a:93:be:c6:d0:64:91:b6:cf:d9:b6:18: + cf:db:7e:d2:65:a3:a6:c4:8e:17:31:c1:fb:7e:76:db:d3:85: + e3:58:b2:77:7a:76:3b:6c:2f:50:1c:e7:db:f6:67:79:1f:f5: + 82:95:9a:07:a7:14:af:8f:dc:28:21:67:09:d2:d6:4d:5a:1c: + 19:1c:8e:77:5c:c3:94:24:3d:32:6b:4b:7e:d4:78:94:83:be: + 37:4d:ce:5f:c7:1e:4e:3c:e0:89:33:95:0b:0f:a5:32:d6:3c: + 5a:79:2c:19 +-----BEGIN CERTIFICATE----- +MIIEMDCCAxigAwIBAgIJANqb7HHzA7AZMA0GCSqGSIb3DQEBCwUAMIGkMQswCQYD +VQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEk +MCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5U +cnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxHzAdBgNVBAMMFlRydXN0Q29y +IFJvb3RDZXJ0IENBLTEwHhcNMTYwMjA0MTIzMjE2WhcNMjkxMjMxMTcyMzE2WjCB +pDELMAkGA1UEBhMCUEExDzANBgNVBAgMBlBhbmFtYTEUMBIGA1UEBwwLUGFuYW1h +IENpdHkxJDAiBgNVBAoMG1RydXN0Q29yIFN5c3RlbXMgUy4gZGUgUi5MLjEnMCUG +A1UECwweVHJ1c3RDb3IgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MR8wHQYDVQQDDBZU +cnVzdENvciBSb290Q2VydCBDQS0xMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAv463leLCJhJrMxnHQFgKq1mqjQCj/IDHUHuO1CAmujIS2CNUSSUQIpid +RtLByZ5OGy4sDjjzGiVoHKZaBeYei0i/mJZ0PmnK6bV4pQa81QBeCQryJ3pS/C3V +seq0iWEk8xoT26nPUu0MJLq5nux+AHT6k61sKZKuUbS701e/s/OojZz0JEsq1pme +9J7+wH5COucLlVPat2gOkEz7cD+PSiyU8ybdY2mplNgQTsVHCJCZGxdNuWxu72CV +EY4hgLW9oHPY0LJ3xEXqWib7ZnZ2+AYfYW0PVcWDtxBWcgYHpfOxGgMFZA6dWorW +hnAbJN7+KIor0Gqw/Hqi3LJ5DotlDwIDAQABo2MwYTAdBgNVHQ4EFgQU7mtJPHo/ +DeOxCbeKyKsZn3MzUOcwHwYDVR0jBBgwFoAU7mtJPHo/DeOxCbeKyKsZn3MzUOcw +DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQAD +ggEBACUY1JGPE+6PHh0RU9otRCkZoB5rMZ5NDp6tPVxBb5UrJKF5mDo4Nvu7Zp5I +/5CQ7z3UuJu0h3U/IJvOcs+hVcFNZKIZBqEHMwwLKeXx6quj7LUKdJDHfXLy11yf +ke+Ri7fc7Waiz45mO7yfOgLgJ90WmMCV1Aqk5IGadZQ1nJBfiDcGrVmVCrDRZ9MZ +yonnMlo2HD6CqFqTvsbQZJG2z9m2GM/bftJlo6bEjhcxwft+dtvTheNYsnd6djts +L1Ac59v2Z3kf9YKVmgenFK+P3CghZwnS1k1aHBkcjndcw5QkPTJrS37UeJSDvjdN +zl/HHk484IkzlQsPpTLWPFp5LBk= +-----END CERTIFICATE----- + +TrustCor RootCert CA-2 +# Fingerprint (SHA1): B8:BE:6D:CB:56:F1:55:B9:63:D4:12:CA:4E:06:34:C7:94:B2:1C:C0 +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +MUST_VERIFY_TRUST: CODE_SIGNING +================================================ +MD5 Fingerprint=A2:E1:F8:18:0B:BA:45:D5:C7:41:2A:BB:37:52:45:64 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 2711694510199101698 (0x25a1dfca33cb5902) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=PA, ST=Panama, L=Panama City, O=TrustCor Systems S. de R.L., OU=TrustCor Certificate Authority, CN=TrustCor RootCert CA-2 + Validity + Not Before: Feb 4 12:32:23 2016 GMT + Not After : Dec 31 17:26:39 2034 GMT + Subject: C=PA, ST=Panama, L=Panama City, O=TrustCor Systems S. de R.L., OU=TrustCor Certificate Authority, CN=TrustCor RootCert CA-2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:a7:20:6e:c2:2a:a2:62:24:95:90:76:c8:38:7e: + 80:d2:ab:c1:9b:65:05:94:f4:c1:0a:10:d5:02:ac: + ed:9f:93:c7:87:c8:b0:27:2b:42:0c:3d:0a:3e:41: + 5a:9e:75:dd:8d:ca:e0:9b:ec:68:32:a4:69:92:68: + 8c:0b:81:0e:56:a0:3e:1a:dd:2c:25:14:82:2f:97: + d3:64:46:f4:54:a9:dc:3a:54:2d:31:2b:99:82:f2: + d9:2a:d7:ef:71:00:b8:31:a4:be:7a:24:07:c3:42: + 20:f2:8a:d4:92:04:1b:65:56:4c:6c:d4:fb:b6:61: + 5a:47:23:b4:d8:69:b4:b7:3a:d0:74:3c:0c:75:a1: + 8c:4e:76:a1:e9:db:2a:a5:3b:fa:ce:b0:ff:7e:6a: + 28:fd:27:1c:c8:b1:e9:29:f1:57:6e:64:b4:d0:c1: + 15:6d:0e:be:2e:0e:46:c8:5e:f4:51:fe:ef:0e:63: + 3a:3b:71:ba:cf:6f:59:ca:0c:e3:9b:5d:49:b8:4c: + e2:57:b1:98:8a:42:57:9c:76:ef:ef:bd:d1:68:a8: + d2:f4:09:bb:77:35:be:25:82:08:c4:16:2c:44:20: + 56:a9:44:11:77:ef:5d:b4:1d:aa:5e:6b:3e:8b:32: + f6:07:2f:57:04:92:ca:f5:fe:9d:c2:e9:e8:b3:8e: + 4c:4b:02:31:d9:e4:3c:48:82:27:f7:18:82:76:48: + 3a:71:b1:13:a1:39:d5:2e:c5:34:c2:1d:62:85:df: + 03:fe:4d:f4:af:3d:df:5c:5b:8d:fa:70:e1:a5:7e: + 27:c7:86:2e:6a:8f:12:c6:84:5e:43:51:50:9c:19: + 9b:78:e6:fc:f6:ed:47:7e:7b:3d:66:ef:13:13:88: + 5f:3c:a1:63:fb:f9:ac:87:35:9f:f3:82:9e:a4:3f: + 0a:9c:31:69:8b:99:a4:88:4a:8e:6e:66:4d:ef:16: + c4:0f:79:28:21:60:0d:85:16:7d:d7:54:38:f1:92: + 56:fd:b5:33:4c:83:dc:d7:10:9f:4b:fd:c6:f8:42: + bd:ba:7c:73:02:e0:ff:7d:cd:5b:e1:d4:ac:61:7b: + 57:d5:4a:7b:5b:d4:85:58:27:5d:bf:f8:2b:60:ac: + a0:26:ae:14:21:27:c6:77:9a:33:80:3c:5e:46:3f: + f7:c3:b1:a3:86:33:c6:e8:5e:0d:b9:35:2c:aa:46: + c1:85:02:75:80:a0:eb:24:fb:15:aa:e4:67:7f:6e: + 77:3f:f4:04:8a:2f:7c:7b:e3:17:61:f0:dd:09:a9: + 20:c8:be:09:a4:d0:7e:44:c3:b2:30:4a:38:aa:a9: + ec:18:9a:07:82:2b:db:b8:9c:18:ad:da:e0:46:17: + ac:cf:5d + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + D9:FE:21:40:6E:94:9E:BC:9B:3D:9C:7D:98:20:19:E5:8C:30:62:B2 + X509v3 Authority Key Identifier: + keyid:D9:FE:21:40:6E:94:9E:BC:9B:3D:9C:7D:98:20:19:E5:8C:30:62:B2 + + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + Signature Algorithm: sha256WithRSAEncryption + 9e:45:9e:0c:3b:b6:ef:e1:3a:c8:7c:d1:00:3d:cf:e2:ea:06: + b5:b2:3a:bb:06:4b:68:7a:d0:23:97:74:a7:2c:f0:08:d8:79: + 5a:d7:5a:84:8a:d8:12:9a:1b:d9:7d:5c:4d:70:c5:a5:f9:ab: + e5:a3:89:89:dd:01:fa:ec:dd:f9:e9:92:97:db:b0:46:42:f3: + d3:62:aa:95:fe:31:67:14:69:58:90:0a:aa:0b:ee:37:23:c7: + 50:51:b4:f5:7e:9e:e3:7b:f7:e4:cc:42:32:2d:49:0c:cb:ff: + 49:0c:9b:1e:34:fd:6e:6e:96:8a:79:03:b6:6f:db:09:cb:fd: + 5f:65:14:37:e1:38:f5:f3:61:16:58:e4:b5:6d:0d:0b:04:1b: + 3f:50:2d:7f:b3:c7:7a:1a:16:80:60:f8:8a:1f:e9:1b:2a:c6: + f9:ba:01:1a:69:bf:d2:58:c7:54:57:08:8f:e1:39:60:77:4b: + ac:59:84:1a:88:f1:dd:cb:4f:78:d7:e7:e1:33:2d:fc:ee:41: + fa:20:b0:be:cb:f7:38:94:c0:e1:d0:85:0f:bb:ed:2c:73:ab: + ed:fe:92:76:1a:64:7f:5b:0d:33:09:07:33:7b:06:3f:11:a4: + 5c:70:3c:85:c0:cf:e3:90:a8:83:77:fa:db:e6:c5:8c:68:67: + 10:67:a5:52:2d:f0:c4:99:8f:7f:bf:d1:6b:e2:b5:47:d6:d9: + d0:85:99:4d:94:9b:0f:4b:8d:ee:00:5a:47:1d:11:03:ac:41: + 18:af:87:b7:6f:0c:3a:8f:ca:cf:dc:03:c1:a2:09:c8:e5:fd: + 80:5e:c8:60:42:01:1b:1a:53:5a:bb:37:a6:b7:bc:ba:84:e9: + 1e:6c:1a:d4:64:da:d4:43:fe:93:8b:4b:f2:2c:79:16:10:d4: + 93:0b:88:8f:a1:d8:86:14:46:91:47:9b:28:24:ef:57:52:4e: + 5c:42:9c:aa:f7:49:ec:27:e8:40:1e:b3:a6:89:22:72:9c:f5: + 0d:33:b4:58:a3:30:3b:dd:d4:6a:54:93:be:1a:4d:f3:93:94: + f7:fc:84:0b:3f:84:20:5c:34:03:44:c5:da:ad:bc:0a:c1:02: + cf:1e:e5:94:d9:f3:8e:5b:d8:4c:f0:9d:ec:61:17:bb:14:32: + 54:0c:02:29:93:1e:92:86:f6:7f:ef:e7:92:05:0e:59:dd:99: + 08:2e:2e:fa:9c:00:52:d3:c5:66:29:e4:a7:97:44:a4:0e:28: + 81:13:35:c5:f6:6f:64:e6:41:c4:d5:2f:cc:34:45:25:cf:41: + 00:96:3d:4a:2e:c2:96:98:4f:4e:4a:9c:97:b7:db:1f:92:32: + c8:ff:0f:51:6e:d6:ec:09 +-----BEGIN CERTIFICATE----- +MIIGLzCCBBegAwIBAgIIJaHfyjPLWQIwDQYJKoZIhvcNAQELBQAwgaQxCzAJBgNV +BAYTAlBBMQ8wDQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1BhbmFtYSBDaXR5MSQw +IgYDVQQKDBtUcnVzdENvciBTeXN0ZW1zIFMuIGRlIFIuTC4xJzAlBgNVBAsMHlRy +dXN0Q29yIENlcnRpZmljYXRlIEF1dGhvcml0eTEfMB0GA1UEAwwWVHJ1c3RDb3Ig +Um9vdENlcnQgQ0EtMjAeFw0xNjAyMDQxMjMyMjNaFw0zNDEyMzExNzI2MzlaMIGk +MQswCQYDVQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEg +Q2l0eTEkMCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYD +VQQLDB5UcnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxHzAdBgNVBAMMFlRy +dXN0Q29yIFJvb3RDZXJ0IENBLTIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK +AoICAQCnIG7CKqJiJJWQdsg4foDSq8GbZQWU9MEKENUCrO2fk8eHyLAnK0IMPQo+ +QVqedd2NyuCb7GgypGmSaIwLgQ5WoD4a3SwlFIIvl9NkRvRUqdw6VC0xK5mC8tkq +1+9xALgxpL56JAfDQiDyitSSBBtlVkxs1Pu2YVpHI7TYabS3OtB0PAx1oYxOdqHp +2yqlO/rOsP9+aij9JxzIsekp8VduZLTQwRVtDr4uDkbIXvRR/u8OYzo7cbrPb1nK +DOObXUm4TOJXsZiKQlecdu/vvdFoqNL0Cbt3Nb4lggjEFixEIFapRBF37120Hape +az6LMvYHL1cEksr1/p3C6eizjkxLAjHZ5DxIgif3GIJ2SDpxsROhOdUuxTTCHWKF +3wP+TfSvPd9cW436cOGlfifHhi5qjxLGhF5DUVCcGZt45vz27Ud+ez1m7xMTiF88 +oWP7+ayHNZ/zgp6kPwqcMWmLmaSISo5uZk3vFsQPeSghYA2FFn3XVDjxklb9tTNM +g9zXEJ9L/cb4Qr26fHMC4P99zVvh1Kxhe1fVSntb1IVYJ12/+CtgrKAmrhQhJ8Z3 +mjOAPF5GP/fDsaOGM8boXg25NSyqRsGFAnWAoOsk+xWq5Gd/bnc/9ASKL3x74xdh +8N0JqSDIvgmk0H5Ew7IwSjiqqewYmgeCK9u4nBit2uBGF6zPXQIDAQABo2MwYTAd +BgNVHQ4EFgQU2f4hQG6UnrybPZx9mCAZ5YwwYrIwHwYDVR0jBBgwFoAU2f4hQG6U +nrybPZx9mCAZ5YwwYrIwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYw +DQYJKoZIhvcNAQELBQADggIBAJ5Fngw7tu/hOsh80QA9z+LqBrWyOrsGS2h60COX +dKcs8AjYeVrXWoSK2BKaG9l9XE1wxaX5q+WjiYndAfrs3fnpkpfbsEZC89NiqpX+ +MWcUaViQCqoL7jcjx1BRtPV+nuN79+TMQjItSQzL/0kMmx40/W5ulop5A7Zv2wnL +/V9lFDfhOPXzYRZY5LVtDQsEGz9QLX+zx3oaFoBg+Iof6Rsqxvm6ARppv9JYx1RX +CI/hOWB3S6xZhBqI8d3LT3jX5+EzLfzuQfogsL7L9ziUwOHQhQ+77Sxzq+3+knYa +ZH9bDTMJBzN7Bj8RpFxwPIXAz+OQqIN3+tvmxYxoZxBnpVIt8MSZj3+/0WvitUfW +2dCFmU2Umw9Lje4AWkcdEQOsQRivh7dvDDqPys/cA8GiCcjl/YBeyGBCARsaU1q7 +N6a3vLqE6R5sGtRk2tRD/pOLS/IseRYQ1JMLiI+h2IYURpFHmygk71dSTlxCnKr3 +Sewn6EAes6aJInKc9Q0ztFijMDvd1GpUk74aTfOTlPf8hAs/hCBcNANExdqtvArB +As8e5ZTZ845b2EzwnexhF7sUMlQMAimTHpKG9n/v55IFDlndmQguLvqcAFLTxWYp +5KeXRKQOKIETNcX2b2TmQcTVL8w0RSXPQQCWPUouwpaYT05KnJe32x+SMsj/D1Fu +1uwJ +-----END CERTIFICATE----- + +TrustCor ECA-1 +# Fingerprint (SHA1): 58:D1:DF:95:95:67:6B:63:C0:F0:5B:1C:17:4D:8B:84:0B:C8:78:BD +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +MUST_VERIFY_TRUST: CODE_SIGNING +================================================ +MD5 Fingerprint=27:92:23:1D:0A:F5:40:7C:E9:E6:6B:9D:D8:F5:E7:6C +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 84:82:2c:5f:1c:62:d0:40 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=PA, ST=Panama, L=Panama City, O=TrustCor Systems S. de R.L., OU=TrustCor Certificate Authority, CN=TrustCor ECA-1 + Validity + Not Before: Feb 4 12:32:33 2016 GMT + Not After : Dec 31 17:28:07 2029 GMT + Subject: C=PA, ST=Panama, L=Panama City, O=TrustCor Systems S. de R.L., OU=TrustCor Certificate Authority, CN=TrustCor ECA-1 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:cf:8f:e0:11:b5:9f:a8:76:76:db:df:0f:54:ef: + 73:63:29:82:ad:47:c6:a3:6b:ed:fe:5f:33:f8:43: + 51:e9:1a:33:91:31:17:a0:74:c4:d4:a7:01:e6:b2: + 92:3e:6a:9d:ed:0e:f9:74:98:40:d3:3f:03:80:06: + 82:40:e8:b1:e2:a7:51:a7:1d:83:26:6b:ab:de:fa: + 17:91:2b:d8:c6:ac:1e:b1:9e:19:01:d5:97:a6:ea: + 0d:b7:c4:55:1f:27:7c:d2:08:d5:76:1f:29:15:87: + 40:39:dd:38:45:11:75:d0:9a:a7:34:e0:bf:cd:c8: + 52:1d:b9:47:7e:0d:b8:bb:c6:0c:f6:73:57:16:5a: + 7e:43:91:1f:55:3a:c6:6d:44:04:aa:9c:a9:9c:a7: + 4c:89:17:83:ae:a3:04:5e:52:80:8b:1e:12:25:11: + 19:d7:0c:7d:7d:31:44:41:ea:db:af:b0:1c:ef:81: + d0:2c:c5:9a:21:9b:3d:ed:42:3b:50:26:f2:ec:ce: + 71:61:06:62:21:54:4e:7f:c1:9d:3e:7f:20:8c:80: + cb:2a:d8:97:62:c8:83:33:91:7d:b0:a2:5a:0f:57: + e8:3b:cc:f2:25:b2:d4:7c:2f:ec:4d:c6:a1:3a:15: + 7a:e7:b6:5d:35:f5:f6:48:4a:36:45:66:d4:ba:98: + 58:c1 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + 44:9E:48:F5:CC:6D:48:D4:A0:4B:7F:FE:59:24:2F:83:97:99:9A:86 + X509v3 Authority Key Identifier: + keyid:44:9E:48:F5:CC:6D:48:D4:A0:4B:7F:FE:59:24:2F:83:97:99:9A:86 + + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + Signature Algorithm: sha256WithRSAEncryption + 05:3e:35:5c:15:70:9b:c9:c7:73:61:6f:72:2b:d4:c2:8f:f2: + 43:5d:02:ce:c4:94:b9:94:11:83:67:5d:e2:67:6c:75:76:bf: + bb:0c:aa:36:c6:ad:47:93:63:dc:1e:7e:d6:de:2e:fe:e9:19: + 32:38:03:7f:14:f6:00:73:2c:59:b1:21:06:e1:fb:ac:18:95: + 0c:a3:ff:99:96:f7:2b:27:9b:d5:24:cc:1d:dd:c1:3a:e0:98: + 44:b0:c4:e4:3e:77:b1:73:a9:64:2c:f6:1c:01:7c:3f:5d:45: + 85:c0:85:e7:25:8f:95:dc:17:f3:3c:9f:1a:6e:b0:ca:e3:1d: + 2a:e9:4c:63:fa:24:61:62:d6:da:7e:b6:1c:6c:f5:02:1d:d4: + 2a:dd:55:90:eb:2a:11:47:3c:2e:5e:74:b2:82:22:a5:7d:53: + 1f:45:ec:27:91:7d:e7:22:16:e8:c0:68:36:d8:c6:f1:4f:80: + 44:32:f9:e1:d1:d1:1d:aa:de:a8:ab:9c:04:af:ad:20:0e:64: + 98:4d:a5:6b:c0:48:58:96:69:4d:dc:07:8c:51:93:a2:df:9f: + 0f:3d:8b:60:b4:82:8d:aa:08:4e:62:45:e0:f9:0b:d2:e0:e0: + 3c:5b:de:5c:71:27:25:c2:e6:03:81:8b:10:53:e3:c7:55:a2: + b4:9f:d7:e6 +-----BEGIN CERTIFICATE----- +MIIEIDCCAwigAwIBAgIJAISCLF8cYtBAMA0GCSqGSIb3DQEBCwUAMIGcMQswCQYD +VQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEk +MCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5U +cnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxFzAVBgNVBAMMDlRydXN0Q29y +IEVDQS0xMB4XDTE2MDIwNDEyMzIzM1oXDTI5MTIzMTE3MjgwN1owgZwxCzAJBgNV +BAYTAlBBMQ8wDQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1BhbmFtYSBDaXR5MSQw +IgYDVQQKDBtUcnVzdENvciBTeXN0ZW1zIFMuIGRlIFIuTC4xJzAlBgNVBAsMHlRy +dXN0Q29yIENlcnRpZmljYXRlIEF1dGhvcml0eTEXMBUGA1UEAwwOVHJ1c3RDb3Ig +RUNBLTEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDPj+ARtZ+odnbb +3w9U73NjKYKtR8aja+3+XzP4Q1HpGjORMRegdMTUpwHmspI+ap3tDvl0mEDTPwOA +BoJA6LHip1GnHYMma6ve+heRK9jGrB6xnhkB1Zem6g23xFUfJ3zSCNV2HykVh0A5 +3ThFEXXQmqc04L/NyFIduUd+Dbi7xgz2c1cWWn5DkR9VOsZtRASqnKmcp0yJF4Ou +owReUoCLHhIlERnXDH19MURB6tuvsBzvgdAsxZohmz3tQjtQJvLsznFhBmIhVE5/ +wZ0+fyCMgMsq2JdiyIMzkX2woloPV+g7zPIlstR8L+xNxqE6FXrntl019fZISjZF +ZtS6mFjBAgMBAAGjYzBhMB0GA1UdDgQWBBREnkj1zG1I1KBLf/5ZJC+Dl5mahjAf +BgNVHSMEGDAWgBREnkj1zG1I1KBLf/5ZJC+Dl5mahjAPBgNVHRMBAf8EBTADAQH/ +MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAQEABT41XBVwm8nHc2Fv +civUwo/yQ10CzsSUuZQRg2dd4mdsdXa/uwyqNsatR5Nj3B5+1t4u/ukZMjgDfxT2 +AHMsWbEhBuH7rBiVDKP/mZb3Kyeb1STMHd3BOuCYRLDE5D53sXOpZCz2HAF8P11F +hcCF5yWPldwX8zyfGm6wyuMdKulMY/okYWLW2n62HGz1Ah3UKt1VkOsqEUc8Ll50 +soIipX1TH0XsJ5F95yIW6MBoNtjG8U+ARDL54dHRHareqKucBK+tIA5kmE2la8BI +WJZpTdwHjFGTot+fDz2LYLSCjaoITmJF4PkL0uDgPFveXHEnJcLmA4GLEFPjx1Wi +tJ/X5g== +-----END CERTIFICATE----- + +SSL.com Root Certification Authority RSA +# Fingerprint (SHA1): B7:AB:33:08:D1:EA:44:77:BA:14:80:12:5A:6F:BD:A9:36:49:0C:BB +MUST_VERIFY_TRUST: CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +================================================ +MD5 Fingerprint=86:69:12:C0:70:F1:EC:AC:AC:C2:D5:BC:A5:5B:A1:29 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 8875640296558310041 (0x7b2c9bd316803299) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, ST=Texas, L=Houston, O=SSL Corporation, CN=SSL.com Root Certification Authority RSA + Validity + Not Before: Feb 12 17:39:39 2016 GMT + Not After : Feb 12 17:39:39 2041 GMT + Subject: C=US, ST=Texas, L=Houston, O=SSL Corporation, CN=SSL.com Root Certification Authority RSA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:f9:0f:dd:a3:2b:7d:cb:d0:2a:fe:ec:67:85:a6: + e7:2e:1b:ba:77:e1:e3:f5:af:a4:ec:fa:4a:5d:91: + c4:57:47:6b:18:77:6b:76:f2:fd:93:e4:3d:0f:c2: + 16:9e:0b:66:c3:56:94:9e:17:83:85:ce:56:ef:f2: + 16:fd:00:62:f5:22:09:54:e8:65:17:4e:41:b9:e0: + 4f:46:97:aa:1b:c8:b8:6e:62:5e:69:b1:5f:db:2a: + 02:7e:fc:6c:ca:f3:41:d8:ed:d0:e8:fc:3f:61:48: + ed:b0:03:14:1d:10:0e:4b:19:e0:bb:4e:ec:86:65: + ff:36:f3:5e:67:02:0b:9d:86:55:61:fd:7a:38:ed: + fe:e2:19:00:b7:6f:a1:50:62:75:74:3c:a0:fa:c8: + 25:92:b4:6e:7a:22:c7:f8:1e:a1:e3:b2:dd:91:31: + ab:2b:1d:04:ff:a5:4a:04:37:e9:85:a4:33:2b:fd: + e2:d6:55:34:7c:19:a4:4a:68:c7:b2:a8:d3:b7:ca: + a1:93:88:eb:c1:97:bc:8c:f9:1d:d9:22:84:24:74: + c7:04:3d:6a:a9:29:93:cc:eb:b8:5b:e1:fe:5f:25: + aa:34:58:c8:c1:23:54:9d:1b:98:11:c3:38:9c:7e: + 3d:86:6c:a5:0f:40:86:7c:02:f4:5c:02:4f:28:cb: + ae:71:9f:0f:3a:c8:33:fe:11:25:35:ea:fc:ba:c5: + 60:3d:d9:7c:18:d5:b2:a9:d3:75:78:03:72:22:ca: + 3a:c3:1f:ef:2c:e5:2e:a9:fa:9e:2c:b6:51:46:fd: + af:03:d6:ea:60:68:ea:85:16:36:6b:85:e9:1e:c0: + b3:dd:c4:24:dc:80:2a:81:41:6d:94:3e:c8:e0:c9: + 81:41:00:9e:5e:bf:7f:c5:08:98:a2:18:2c:42:40: + b3:f9:6f:38:27:4b:4e:80:f4:3d:81:47:e0:88:7c: + ea:1c:ce:b5:75:5c:51:2e:1c:2b:7f:1a:72:28:e7: + 00:b5:d1:74:c6:d7:e4:9f:ad:07:93:b6:53:35:35: + fc:37:e4:c3:f6:5d:16:be:21:73:de:92:0a:f8:a0: + 63:6a:bc:96:92:6a:3e:f8:bc:65:55:9b:de:f5:0d: + 89:26:04:fc:25:1a:a6:25:69:cb:c2:6d:ca:7c:e2: + 59:5f:97:ac:eb:ef:2e:c8:bc:d7:1b:59:3c:2b:cc: + f2:19:c8:93:6b:27:63:19:cf:fc:e9:26:f8:ca:71: + 9b:7f:93:fe:34:67:84:4e:99:eb:fc:b3:78:09:33: + 70:ba:66:a6:76:ed:1b:73:eb:1a:a5:0d:c4:22:13: + 20:94:56:0a:4e:2c:6c:4e:b1:fd:cf:9c:09:ba:a2: + 33:ed:87 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + DD:04:09:07:A2:F5:7A:7D:52:53:12:92:95:EE:38:80:25:0D:A6:59 + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Authority Key Identifier: + keyid:DD:04:09:07:A2:F5:7A:7D:52:53:12:92:95:EE:38:80:25:0D:A6:59 + + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + Signature Algorithm: sha256WithRSAEncryption + 20:18:11:94:29:fb:26:9d:1c:1e:1e:70:61:f1:95:72:93:71: + 24:ad:68:93:58:8e:32:af:1b:b3:70:03:fc:25:2b:74:85:90: + 3d:78:6a:f4:b9:8b:a5:97:3b:b5:18:91:bb:1e:a7:f9:40:5b: + 91:f9:55:99:af:1e:11:d0:5c:1d:a7:66:e3:b1:94:07:0c:32: + 39:a6:ea:1b:b0:79:d8:1d:9c:70:44:e3:8a:dd:c4:f9:95:1f: + 8a:38:43:3f:01:85:a5:47:a7:3d:46:b2:bc:e5:22:68:f7:7b: + 9c:d8:2c:3e:0a:21:c8:2d:33:ac:bf:c5:81:99:31:74:c1:75: + 71:c5:be:b1:f0:23:45:f4:9d:6b:fc:19:63:9d:a3:bc:04:c6: + 18:0b:25:bb:53:89:0f:b3:80:50:de:45:ee:44:7f:ab:94:78: + 64:98:d3:f6:28:dd:87:d8:70:65:74:fb:0e:b9:13:eb:a7:0f: + 61:a9:32:96:cc:de:bb:ed:63:4c:18:bb:a9:40:f7:a0:54:6e: + 20:88:71:75:18:ea:7a:b4:34:72:e0:23:27:77:5c:b6:90:ea: + 86:25:40:ab:ef:33:0f:cb:9f:82:be:a2:20:fb:f6:b5:2d:1a: + e6:c2:85:b1:74:0f:fb:c8:65:02:a4:52:01:47:dd:49:22:c1: + bf:d8:eb:6b:ac:7e:de:ec:63:33:15:b7:23:08:8f:c6:0f:8d: + 41:5a:dd:8e:c5:b9:8f:e5:45:3f:78:db:ba:d2:1b:40:b1:fe: + 71:4d:3f:e0:81:a2:ba:5e:b4:ec:15:e0:93:dd:08:1f:7e:e1: + 55:99:0b:21:de:93:9e:0a:fb:e6:a3:49:bd:36:30:fe:e7:77: + b2:a0:75:97:b5:2d:81:88:17:65:20:f7:da:90:00:9f:c9:52: + cc:32:ca:35:7c:f5:3d:0f:d8:2b:d7:f5:26:6c:c9:06:34:96: + 16:ea:70:59:1a:32:79:79:0b:b6:88:7f:0f:52:48:3d:bf:6c: + d8:a2:44:2e:d1:4e:b7:72:58:d3:89:13:95:fe:44:ab:f8:d7: + 8b:1b:6e:9c:bc:2c:a0:5b:d5:6a:00:af:5f:37:e1:d5:fa:10: + 0b:98:9c:86:e7:26:8f:ce:f0:ec:6e:8a:57:0b:80:e3:4e:b2: + c0:a0:63:61:90:ba:55:68:37:74:6a:b6:92:db:9f:a1:86:22: + b6:65:27:0e:ec:b6:9f:42:60:e4:67:c2:b5:da:41:0b:c4:d3: + 8b:61:1b:bc:fa:1f:91:2b:d7:44:07:5e:ba:29:ac:d9:c5:e9: + ef:53:48:5a:eb:80:f1:28:58:21:cd:b0:06:55:fb:27:3f:53: + 90:70:a9:04:1e:57:27:b9 +-----BEGIN CERTIFICATE----- +MIIF3TCCA8WgAwIBAgIIeyyb0xaAMpkwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UE +BhMCVVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQK +DA9TU0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eSBSU0EwHhcNMTYwMjEyMTczOTM5WhcNNDEwMjEyMTcz +OTM5WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hv +dXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNv +bSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTCCAiIwDQYJKoZIhvcN +AQEBBQADggIPADCCAgoCggIBAPkP3aMrfcvQKv7sZ4Wm5y4bunfh4/WvpOz6Sl2R +xFdHaxh3a3by/ZPkPQ/CFp4LZsNWlJ4Xg4XOVu/yFv0AYvUiCVToZRdOQbngT0aX +qhvIuG5iXmmxX9sqAn78bMrzQdjt0Oj8P2FI7bADFB0QDksZ4LtO7IZl/zbzXmcC +C52GVWH9ejjt/uIZALdvoVBidXQ8oPrIJZK0bnoix/geoeOy3ZExqysdBP+lSgQ3 +6YWkMyv94tZVNHwZpEpox7Ko07fKoZOI68GXvIz5HdkihCR0xwQ9aqkpk8zruFvh +/l8lqjRYyMEjVJ0bmBHDOJx+PYZspQ9AhnwC9FwCTyjLrnGfDzrIM/4RJTXq/LrF +YD3ZfBjVsqnTdXgDciLKOsMf7yzlLqn6niy2UUb9rwPW6mBo6oUWNmuF6R7As93E +JNyAKoFBbZQ+yODJgUEAnl6/f8UImKIYLEJAs/lvOCdLToD0PYFH4Ih86hzOtXVc +US4cK38acijnALXRdMbX5J+tB5O2UzU1/Dfkw/ZdFr4hc96SCvigY2q8lpJqPvi8 +ZVWb3vUNiSYE/CUapiVpy8JtynziWV+XrOvvLsi81xtZPCvM8hnIk2snYxnP/Okm ++Mpxm3+T/jRnhE6Z6/yzeAkzcLpmpnbtG3PrGqUNxCITIJRWCk4sbE6x/c+cCbqi +M+2HAgMBAAGjYzBhMB0GA1UdDgQWBBTdBAkHovV6fVJTEpKV7jiAJQ2mWTAPBgNV +HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFN0ECQei9Xp9UlMSkpXuOIAlDaZZMA4G +A1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAIBgRlCn7Jp0cHh5wYfGV +cpNxJK1ok1iOMq8bs3AD/CUrdIWQPXhq9LmLpZc7tRiRux6n+UBbkflVma8eEdBc +Hadm47GUBwwyOabqG7B52B2ccETjit3E+ZUfijhDPwGFpUenPUayvOUiaPd7nNgs +PgohyC0zrL/FgZkxdMF1ccW+sfAjRfSda/wZY52jvATGGAslu1OJD7OAUN5F7kR/ +q5R4ZJjT9ijdh9hwZXT7DrkT66cPYakylszeu+1jTBi7qUD3oFRuIIhxdRjqerQ0 +cuAjJ3dctpDqhiVAq+8zD8ufgr6iIPv2tS0a5sKFsXQP+8hlAqRSAUfdSSLBv9jr +a6x+3uxjMxW3IwiPxg+NQVrdjsW5j+VFP3jbutIbQLH+cU0/4IGiul607BXgk90I +H37hVZkLId6Tngr75qNJvTYw/ud3sqB1l7UtgYgXZSD32pAAn8lSzDLKNXz1PQ/Y +K9f1JmzJBjSWFupwWRoyeXkLtoh/D1JIPb9s2KJELtFOt3JY04kTlf5Eq/jXixtu +nLwsoFvVagCvXzfh1foQC5ichucmj87w7G6KVwuA406ywKBjYZC6VWg3dGq2ktuf +oYYitmUnDuy2n0Jg5GfCtdpBC8TTi2EbvPofkSvXRAdeuims2cXp71NIWuuA8ShY +Ic2wBlX7Jz9TkHCpBB5XJ7k= +-----END CERTIFICATE----- + +SSL.com Root Certification Authority ECC +# Fingerprint (SHA1): C3:19:7C:39:24:E6:54:AF:1B:C4:AB:20:95:7A:E2:C3:0E:13:02:6A +TRUSTED_DELEGATOR: SERVER_AUTH, EMAIL_PROTECTION +MUST_VERIFY_TRUST: CODE_SIGNING +================================================ +MD5 Fingerprint=2E:DA:E4:39:7F:9C:8F:37:D1:70:9F:26:17:51:3A:8E +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 8495723813297216424 (0x75e6dfcbc1685ba8) + Signature Algorithm: ecdsa-with-SHA256 + Issuer: C=US, ST=Texas, L=Houston, O=SSL Corporation, CN=SSL.com Root Certification Authority ECC + Validity + Not Before: Feb 12 18:14:03 2016 GMT + Not After : Feb 12 18:14:03 2041 GMT + Subject: C=US, ST=Texas, L=Houston, O=SSL Corporation, CN=SSL.com Root Certification Authority ECC + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (384 bit) + pub: + 04:45:6e:a9:50:c4:a6:23:36:9e:5f:28:8d:17:cb: + 96:22:64:3f:dc:7a:8e:1d:cc:08:b3:a2:71:24:ba: + 8e:49:b9:04:1b:47:96:58:ab:2d:95:c8:ed:9e:08: + 35:c8:27:eb:89:8c:53:58:eb:62:8a:fe:f0:5b:0f: + 6b:31:52:63:41:3b:89:cd:ec:ec:b6:8d:19:d3:34: + 07:dc:bb:c6:06:7f:c2:45:95:ec:cb:7f:a8:23:e0: + 09:e9:81:fa:f3:47:d3 + ASN1 OID: secp384r1 + X509v3 extensions: + X509v3 Subject Key Identifier: + 82:D1:85:73:30:E7:35:04:D3:8E:02:92:FB:E5:A4:D1:C4:21:E8:CD + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Authority Key Identifier: + keyid:82:D1:85:73:30:E7:35:04:D3:8E:02:92:FB:E5:A4:D1:C4:21:E8:CD + + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + Signature Algorithm: ecdsa-with-SHA256 + 30:64:02:30:6f:e7:eb:59:11:a4:60:cf:61:b0:96:7b:ed:05: + f9:2f:13:91:dc:ed:e5:fc:50:6b:11:46:46:b3:1c:21:00:62: + bb:be:c3:e7:e8:cd:07:99:f9:0d:0b:5d:72:3e:c4:aa:02:30: + 1f:bc:ba:0b:e2:30:24:fb:7c:6d:80:55:0a:99:3e:80:0d:33: + e5:66:a3:b3:a3:bb:a5:d5:8b:8f:09:2c:a6:5d:7e:e2:f0:07: + 08:68:6d:d2:7c:69:6e:5f:df:e5:6a:65 +-----BEGIN CERTIFICATE----- +MIICjTCCAhSgAwIBAgIIdebfy8FoW6gwCgYIKoZIzj0EAwIwfDELMAkGA1UEBhMC +VVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T +U0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0 +aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEyMTgxNDAzWhcNNDEwMjEyMTgxNDAz +WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0 +b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNvbSBS +b290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuB +BAAiA2IABEVuqVDEpiM2nl8ojRfLliJkP9x6jh3MCLOicSS6jkm5BBtHllirLZXI +7Z4INcgn64mMU1jrYor+8FsPazFSY0E7ic3s7LaNGdM0B9y7xgZ/wkWV7Mt/qCPg +CemB+vNH06NjMGEwHQYDVR0OBBYEFILRhXMw5zUE044CkvvlpNHEIejNMA8GA1Ud +EwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUgtGFczDnNQTTjgKS++Wk0cQh6M0wDgYD +VR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2cAMGQCMG/n61kRpGDPYbCWe+0F+S8T +kdzt5fxQaxFGRrMcIQBiu77D5+jNB5n5DQtdcj7EqgIwH7y6C+IwJPt8bYBVCpk+ +gA0z5Wajs6O7pdWLjwkspl1+4vAHCGht0nxpbl/f5Wpl +-----END CERTIFICATE----- + +SSL.com EV Root Certification Authority RSA R2 +# Fingerprint (SHA1): 74:3A:F0:52:9B:D0:32:A0:F4:4A:83:CD:D4:BA:A9:7B:7C:2E:C4:9A +TRUSTED_DELEGATOR: SERVER_AUTH +MUST_VERIFY_TRUST: EMAIL_PROTECTION, CODE_SIGNING +================================================= +MD5 Fingerprint=E1:1E:31:58:1A:AE:54:53:02:F6:17:6A:11:7B:4D:95 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 6248227494352943350 (0x56b629cd34bc78f6) + Signature Algorithm: sha256WithRSAEncryption + Issuer: C=US, ST=Texas, L=Houston, O=SSL Corporation, CN=SSL.com EV Root Certification Authority RSA R2 + Validity + Not Before: May 31 18:14:37 2017 GMT + Not After : May 30 18:14:37 2042 GMT + Subject: C=US, ST=Texas, L=Houston, O=SSL Corporation, CN=SSL.com EV Root Certification Authority RSA R2 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:8f:36:65:40:e1:d6:4d:c0:d7:b4:e9:46:da:6b: + ea:33:47:cd:4c:f9:7d:7d:be:bd:2d:3d:f0:db:78: + e1:86:a5:d9:ba:09:57:68:ed:57:3e:a0:d0:08:41: + 83:e7:28:41:24:1f:e3:72:15:d0:01:1a:fb:5e:70: + 23:b2:cb:9f:39:e3:cf:c5:4e:c6:92:6d:26:c6:7b: + bb:b3:da:27:9d:0a:86:e9:81:37:05:fe:f0:71:71: + ec:c3:1c:e9:63:a2:17:14:9d:ef:1b:67:d3:85:55: + 02:02:d6:49:c9:cc:5a:e1:b1:f7:6f:32:9f:c9:d4: + 3b:88:41:a8:9c:bd:cb:ab:db:6d:7b:09:1f:a2:4c: + 72:90:da:2b:08:fc:cf:3c:54:ce:67:0f:a8:cf:5d: + 96:19:0b:c4:e3:72:eb:ad:d1:7d:1d:27:ef:92:eb: + 10:bf:5b:eb:3b:af:cf:80:dd:c1:d2:96:04:5b:7a: + 7e:a4:a9:3c:38:76:a4:62:8e:a0:39:5e:ea:77:cf: + 5d:00:59:8f:66:2c:3e:07:a2:a3:05:26:11:69:97: + ea:85:b7:0f:96:0b:4b:c8:40:e1:50:ba:2e:8a:cb: + f7:0f:9a:22:e7:7f:9a:37:13:cd:f2:4d:13:6b:21: + d1:c0:cc:22:f2:a1:46:f6:44:69:9c:ca:61:35:07: + 00:6f:d6:61:08:11:ea:ba:b8:f6:e9:b3:60:e5:4d: + b9:ec:9f:14:66:c9:57:58:db:cd:87:69:f8:8a:86: + 12:03:47:bf:66:13:76:ac:77:7d:34:24:85:83:cd: + d7:aa:9c:90:1a:9f:21:2c:7f:78:b7:64:b8:d8:e8: + a6:f4:78:b3:55:cb:84:d2:32:c4:78:ae:a3:8f:61: + dd:ce:08:53:ad:ec:88:fc:15:e4:9a:0d:e6:9f:1a: + 77:ce:4c:8f:b8:14:15:3d:62:9c:86:38:06:00:66: + 12:e4:59:76:5a:53:c0:02:98:a2:10:2b:68:44:7b: + 8e:79:ce:33:4a:76:aa:5b:81:16:1b:b5:8a:d8:d0: + 00:7b:5e:62:b4:09:d6:86:63:0e:a6:05:95:49:ba: + 28:8b:88:93:b2:34:1c:d8:a4:55:6e:b7:1c:d0:de: + 99:55:3b:23:f4:22:e0:f9:29:66:26:ec:20:50:77: + db:4a:0b:8f:be:e5:02:60:70:41:5e:d4:ae:50:39: + 22:14:26:cb:b2:3b:73:74:55:47:07:79:81:39:a8: + 30:13:44:e5:04:8a:ae:96:13:25:42:0f:b9:53:c4: + 9b:fc:cd:e4:1c:de:3c:fa:ab:d6:06:4a:1f:67:a6: + 98:30:1c:dd:2c:db:dc:18:95:57:66:c6:ff:5c:8b: + 56:f5:77 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Authority Key Identifier: + keyid:F9:60:BB:D4:E3:D5:34:F6:B8:F5:06:80:25:A7:73:DB:46:69:A8:9E + + X509v3 Subject Key Identifier: + F9:60:BB:D4:E3:D5:34:F6:B8:F5:06:80:25:A7:73:DB:46:69:A8:9E + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + Signature Algorithm: sha256WithRSAEncryption + 56:b3:8e:cb:0a:9d:49:8e:bf:a4:c4:91:bb:66:17:05:51:98: + 75:fb:e5:50:2c:7a:9e:f1:14:fa:ab:d3:8a:3e:ff:91:29:8f: + 63:8b:d8:b4:a9:54:01:0d:be:93:86:2f:f9:4a:6d:c7:5e:f5: + 57:f9:ca:55:1c:12:be:47:0f:36:c5:df:6a:b7:db:75:c2:47: + 25:7f:b9:f1:63:f8:68:2d:55:04:d1:f2:8d:b0:a4:cf:bc:3c: + 5e:1f:78:e7:a5:a0:20:70:b0:04:c5:b7:f7:72:a7:de:22:0d: + bd:33:25:46:8c:64:92:26:e3:3e:2e:63:96:da:9b:8c:3d:f8: + 18:09:d7:03:cc:7d:86:82:e0:ca:04:07:51:50:d7:ff:92:d5: + 0c:ef:da:86:9f:99:d7:eb:b7:af:68:e2:39:26:94:ba:68:b7: + bf:83:d3:ea:7a:67:3d:62:67:ae:25:e5:72:e8:e2:e4:ec:ae: + 12:f6:4b:2b:3c:9f:e9:b0:40:f3:38:54:b3:fd:b7:68:c8:da: + c6:8f:51:3c:b2:fb:91:dc:1c:e7:9b:9d:e1:b7:0d:72:8f:e2: + a4:c4:a9:78:f9:eb:14:ac:c6:43:05:c2:65:39:28:18:02:c3: + 82:b2:9d:05:be:65:ed:96:5f:65:74:3c:fb:09:35:2e:7b:9c: + 13:fd:1b:0f:5d:c7:6d:81:3a:56:0f:cc:3b:e1:af:02:2f:22: + ac:46:ca:46:3c:a0:1c:4c:d6:44:b4:5e:2e:5c:15:66:09:e1: + 26:29:fe:c6:52:61:ba:b1:73:ff:c3:0c:9c:e5:6c:6a:94:3f: + 14:ca:40:16:95:84:f3:59:a9:ac:5f:4c:61:93:6d:d1:3b:cc: + a2:95:0c:22:a6:67:67:44:2e:b9:d9:d2:8a:41:b3:66:0b:5a: + fb:7d:23:a5:f2:1a:b0:ff:de:9b:83:94:2e:d1:3f:df:92:b7: + 91:af:05:3b:65:c7:a0:6c:b1:cd:62:12:c3:90:1b:e3:25:ce: + 34:bc:6f:77:76:b1:10:c3:f7:05:1a:c0:d6:af:74:62:48:17: + 77:92:69:90:61:1c:de:95:80:74:54:8f:18:1c:c3:f3:03:d0: + bf:a4:43:75:86:53:18:7a:0a:2e:09:1c:36:9f:91:fd:82:8a: + 22:4b:d1:0e:50:25:dd:cb:03:0c:17:c9:83:00:08:4e:35:4d: + 8a:8b:ed:f0:02:94:66:2c:44:7f:cb:95:27:96:17:ad:09:30: + ac:b6:71:17:6e:8b:17:f6:1c:09:d4:2d:3b:98:a5:71:d3:54: + 13:d9:60:f3:f5:4b:66:4f:fa:f1:ee:20:12:8d:b4:ac:57:b1: + 45:63:a1:ac:76:a9:c2:fb +-----BEGIN CERTIFICATE----- +MIIF6zCCA9OgAwIBAgIIVrYpzTS8ePYwDQYJKoZIhvcNAQELBQAwgYIxCzAJBgNV +BAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UE +CgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQDDC5TU0wuY29tIEVWIFJvb3QgQ2Vy +dGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIyMB4XDTE3MDUzMTE4MTQzN1oXDTQy +MDUzMDE4MTQzN1owgYIxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4G +A1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQD +DC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIy +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjzZlQOHWTcDXtOlG2mvq +M0fNTPl9fb69LT3w23jhhqXZuglXaO1XPqDQCEGD5yhBJB/jchXQARr7XnAjssuf +OePPxU7Gkm0mxnu7s9onnQqG6YE3Bf7wcXHswxzpY6IXFJ3vG2fThVUCAtZJycxa +4bH3bzKfydQ7iEGonL3Lq9ttewkfokxykNorCPzPPFTOZw+oz12WGQvE43LrrdF9 +HSfvkusQv1vrO6/PgN3B0pYEW3p+pKk8OHakYo6gOV7qd89dAFmPZiw+B6KjBSYR +aZfqhbcPlgtLyEDhULouisv3D5oi53+aNxPN8k0TayHRwMwi8qFG9kRpnMphNQcA +b9ZhCBHqurj26bNg5U257J8UZslXWNvNh2n4ioYSA0e/ZhN2rHd9NCSFg83XqpyQ +Gp8hLH94t2S42Oim9HizVcuE0jLEeK6jj2HdzghTreyI/BXkmg3mnxp3zkyPuBQV +PWKchjgGAGYS5Fl2WlPAApiiECtoRHuOec4zSnaqW4EWG7WK2NAAe15itAnWhmMO +pgWVSbooi4iTsjQc2KRVbrcc0N6ZVTsj9CLg+SlmJuwgUHfbSguPvuUCYHBBXtSu +UDkiFCbLsjtzdFVHB3mBOagwE0TlBIqulhMlQg+5U8Sb/M3kHN48+qvWBkofZ6aY +MBzdLNvcGJVXZsb/XItW9XcCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNV +HSMEGDAWgBT5YLvU49U09rj1BoAlp3PbRmmonjAdBgNVHQ4EFgQU+WC71OPVNPa4 +9QaAJadz20ZpqJ4wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBW +s47LCp1Jjr+kxJG7ZhcFUZh1++VQLHqe8RT6q9OKPv+RKY9ji9i0qVQBDb6Thi/5 +Sm3HXvVX+cpVHBK+Rw82xd9qt9t1wkclf7nxY/hoLVUE0fKNsKTPvDxeH3jnpaAg +cLAExbf3cqfeIg29MyVGjGSSJuM+LmOW2puMPfgYCdcDzH2GguDKBAdRUNf/ktUM +79qGn5nX67evaOI5JpS6aLe/g9Pqemc9YmeuJeVy6OLk7K4S9ksrPJ/psEDzOFSz +/bdoyNrGj1E8svuR3Bznm53htw1yj+KkxKl4+esUrMZDBcJlOSgYAsOCsp0FvmXt +ll9ldDz7CTUue5wT/RsPXcdtgTpWD8w74a8CLyKsRspGPKAcTNZEtF4uXBVmCeEm +Kf7GUmG6sXP/wwyc5WxqlD8UykAWlYTzWamsX0xhk23RO8yilQwipmdnRC652dKK +QbNmC1r7fSOl8hqw/96bg5Qu0T/fkreRrwU7ZcegbLHNYhLDkBvjJc40vG93drEQ +w/cFGsDWr3RiSBd3kmmQYRzelYB0VI8YHMPzA9C/pEN1hlMYegouCRw2n5H9gooi +S9EOUCXdywMMF8mDAAhONU2Ki+3wApRmLER/y5UnlhetCTCstnEXbosX9hwJ1C07 +mKVx01QT2WDz9UtmT/rx7iASjbSsV7FFY6GsdqnC+w== +-----END CERTIFICATE----- + +SSL.com EV Root Certification Authority ECC +# Fingerprint (SHA1): 4C:DD:51:A3:D1:F5:20:32:14:B0:C6:C5:32:23:03:91:C7:46:42:6D +MUST_VERIFY_TRUST: EMAIL_PROTECTION, CODE_SIGNING +TRUSTED_DELEGATOR: SERVER_AUTH +================================================= +MD5 Fingerprint=59:53:22:65:83:42:01:54:C0:CE:42:B9:5A:7C:F2:90 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 3182246526754555285 (0x2c299c5b16ed0595) + Signature Algorithm: ecdsa-with-SHA256 + Issuer: C=US, ST=Texas, L=Houston, O=SSL Corporation, CN=SSL.com EV Root Certification Authority ECC + Validity + Not Before: Feb 12 18:15:23 2016 GMT + Not After : Feb 12 18:15:23 2041 GMT + Subject: C=US, ST=Texas, L=Houston, O=SSL Corporation, CN=SSL.com EV Root Certification Authority ECC + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (384 bit) + pub: + 04:aa:12:47:90:98:1b:fb:ef:c3:40:07:83:20:4e: + f1:30:82:a2:06:d1:f2:92:86:61:f2:f6:21:68:ca: + 00:c4:c7:ea:43:00:54:86:dc:fd:1f:df:00:b8:41: + 62:5c:dc:70:16:32:de:1f:99:d4:cc:c5:07:c8:08: + 1f:61:16:07:51:3d:7d:5c:07:53:e3:35:38:8c:df: + cd:9f:d9:2e:0d:4a:b6:19:2e:5a:70:5a:06:ed:be: + f0:a1:b0:ca:d0:09:29 + ASN1 OID: secp384r1 + X509v3 extensions: + X509v3 Subject Key Identifier: + 5B:CA:5E:E5:DE:D2:81:AA:CD:A8:2D:64:51:B6:D9:72:9B:97:E6:4F + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Authority Key Identifier: + keyid:5B:CA:5E:E5:DE:D2:81:AA:CD:A8:2D:64:51:B6:D9:72:9B:97:E6:4F + + X509v3 Key Usage: critical + Digital Signature, Certificate Sign, CRL Sign + Signature Algorithm: ecdsa-with-SHA256 + 30:65:02:31:00:8a:e6:40:89:37:eb:e9:d5:13:d9:ca:d4:6b: + 24:f3:b0:3d:87:46:58:1a:ec:b1:df:6f:fb:56:ba:70:6b:c7: + 38:cc:e8:b1:8c:4f:0f:f7:f1:67:76:0e:83:d0:1e:51:8f:02: + 30:3d:f6:23:28:26:4c:c6:60:87:93:26:9b:b2:35:1e:ba:d6: + f7:3c:d1:1c:ce:fa:25:3c:a6:1a:81:15:5b:f3:12:0f:6c:ee: + 65:8a:c9:87:a8:f9:07:e0:62:9a:8c:5c:4a +-----BEGIN CERTIFICATE----- +MIIClDCCAhqgAwIBAgIILCmcWxbtBZUwCgYIKoZIzj0EAwIwfzELMAkGA1UEBhMC +VVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T +U0wgQ29ycG9yYXRpb24xNDAyBgNVBAMMK1NTTC5jb20gRVYgUm9vdCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEyMTgxNTIzWhcNNDEwMjEyMTgx +NTIzWjB/MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hv +dXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjE0MDIGA1UEAwwrU1NMLmNv +bSBFViBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49 +AgEGBSuBBAAiA2IABKoSR5CYG/vvw0AHgyBO8TCCogbR8pKGYfL2IWjKAMTH6kMA +VIbc/R/fALhBYlzccBYy3h+Z1MzFB8gIH2EWB1E9fVwHU+M1OIzfzZ/ZLg1Kthku +WnBaBu2+8KGwytAJKaNjMGEwHQYDVR0OBBYEFFvKXuXe0oGqzagtZFG22XKbl+ZP +MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUW8pe5d7SgarNqC1kUbbZcpuX +5k8wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2gAMGUCMQCK5kCJN+vp1RPZ +ytRrJPOwPYdGWBrssd9v+1a6cGvHOMzosYxPD/fxZ3YOg9AeUY8CMD32IygmTMZg +h5Mmm7I1HrrW9zzRHM76JTymGoEVW/MSD2zuZYrJh6j5B+BimoxcSg== +-----END CERTIFICATE----- +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + de:29:a4:d1:b0:8f:ac:88 + Signature Algorithm: md5WithRSAEncryption + Issuer: C=US, ST=California, L=San Francisco, O=Linden Lab, Inc., OU=Linden Lab Certificate Authority, CN=Linden Lab Certificate Authority/emailAddress=ca@lindenlab.com + Validity + Not Before: Apr 21 02:40:31 2005 GMT + Not After : Apr 16 02:40:31 2025 GMT + Subject: C=US, ST=California, L=San Francisco, O=Linden Lab, Inc., OU=Linden Lab Certificate Authority, CN=Linden Lab Certificate Authority/emailAddress=ca@lindenlab.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (1024 bit) + Modulus: + 00:a5:e1:d4:c4:e1:b9:c7:53:6c:c8:3d:6d:80:4e: + ac:09:bc:c9:69:ec:df:66:28:8c:1d:0f:45:f6:ea: + f2:b5:23:7a:91:21:4e:6d:ff:d7:7b:34:bb:7f:7d: + 51:cd:b4:da:fe:1e:8d:c1:a1:90:80:d6:25:97:76: + 35:93:05:a0:aa:e1:99:17:f1:18:74:8a:3c:2b:85: + 69:70:b7:8e:1d:25:44:40:a3:ee:4f:05:a0:f9:1c: + 99:a3:e3:4b:2a:1d:ac:31:43:51:4b:af:f8:2d:3a: + a1:82:68:23:ea:e4:f1:11:32:6a:5f:4d:c2:01:ef: + a8:2c:ce:ad:9b:62:4d:70:1d + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + 3B:5C:CA:D9:ED:5F:D7:03:B5:7C:70:23:AB:A0:D3:26:86:CA:0E:B7 + X509v3 Authority Key Identifier: + keyid:3B:5C:CA:D9:ED:5F:D7:03:B5:7C:70:23:AB:A0:D3:26:86:CA:0E:B7 + DirName:/C=US/ST=California/L=San Francisco/O=Linden Lab, Inc./OU=Linden Lab Certificate Authority/CN=Linden Lab Certificate Authority/emailAddress=ca@lindenlab.com + serial:DE:29:A4:D1:B0:8F:AC:88 + + X509v3 Basic Constraints: + CA:TRUE + Signature Algorithm: md5WithRSAEncryption + 3f:66:48:1f:bf:01:d8:aa:4d:54:20:02:99:4b:79:0c:0b:1c: + f4:1e:f6:2e:11:0b:6f:8b:09:ee:c4:0d:fd:08:82:7a:e5:9a: + 33:b3:6f:04:83:56:95:f7:f6:3e:39:fe:d3:9d:68:56:f9:4d: + c9:df:fc:03:fc:68:21:68:01:a2:28:ae:af:32:7f:60:24:12: + 1d:05:7f:fd:7b:a7:9f:df:b5:46:ca:23:84:14:58:e7:50:86: + ee:93:44:56:b7:2d:28:ac:de:fa:ab:f9:48:ff:18:c2:8b:5e: + 57:48:0f:d5:4a:ad:a3:e2:f9:a7:c1:f6:5c:3d:30:ee:82:59: + 90:d4 +-----BEGIN CERTIFICATE----- +MIIEUDCCA7mgAwIBAgIJAN4ppNGwj6yIMA0GCSqGSIb3DQEBBAUAMIHMMQswCQYD +VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5j +aXNjbzEZMBcGA1UEChMQTGluZGVuIExhYiwgSW5jLjEpMCcGA1UECxMgTGluZGVu +IExhYiBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxKTAnBgNVBAMTIExpbmRlbiBMYWIg +Q2VydGlmaWNhdGUgQXV0aG9yaXR5MR8wHQYJKoZIhvcNAQkBFhBjYUBsaW5kZW5s +YWIuY29tMB4XDTA1MDQyMTAyNDAzMVoXDTI1MDQxNjAyNDAzMVowgcwxCzAJBgNV +BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNp +c2NvMRkwFwYDVQQKExBMaW5kZW4gTGFiLCBJbmMuMSkwJwYDVQQLEyBMaW5kZW4g +TGFiIENlcnRpZmljYXRlIEF1dGhvcml0eTEpMCcGA1UEAxMgTGluZGVuIExhYiBD +ZXJ0aWZpY2F0ZSBBdXRob3JpdHkxHzAdBgkqhkiG9w0BCQEWEGNhQGxpbmRlbmxh +Yi5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKXh1MThucdTbMg9bYBO +rAm8yWns32YojB0PRfbq8rUjepEhTm3/13s0u399Uc202v4ejcGhkIDWJZd2NZMF +oKrhmRfxGHSKPCuFaXC3jh0lRECj7k8FoPkcmaPjSyodrDFDUUuv+C06oYJoI+rk +8REyal9NwgHvqCzOrZtiTXAdAgMBAAGjggE2MIIBMjAdBgNVHQ4EFgQUO1zK2e1f +1wO1fHAjq6DTJobKDrcwggEBBgNVHSMEgfkwgfaAFDtcytntX9cDtXxwI6ug0yaG +yg63oYHSpIHPMIHMMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEW +MBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEZMBcGA1UEChMQTGluZGVuIExhYiwgSW5j +LjEpMCcGA1UECxMgTGluZGVuIExhYiBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxKTAn +BgNVBAMTIExpbmRlbiBMYWIgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MR8wHQYJKoZI +hvcNAQkBFhBjYUBsaW5kZW5sYWIuY29tggkA3imk0bCPrIgwDAYDVR0TBAUwAwEB +/zANBgkqhkiG9w0BAQQFAAOBgQA/ZkgfvwHYqk1UIAKZS3kMCxz0HvYuEQtviwnu +xA39CIJ65Zozs28Eg1aV9/Y+Of7TnWhW+U3J3/wD/GghaAGiKK6vMn9gJBIdBX/9 +e6ef37VGyiOEFFjnUIbuk0RWty0orN76q/lI/xjCi15XSA/VSq2j4vmnwfZcPTDu +glmQ1A== +-----END CERTIFICATE----- diff --git a/indra/newview/app_settings/cmd_line.xml b/indra/newview/app_settings/cmd_line.xml index 7e35949ed1..fbb2bb10f5 100644 --- a/indra/newview/app_settings/cmd_line.xml +++ b/indra/newview/app_settings/cmd_line.xml @@ -211,12 +211,6 @@ NoHardwareProbe - noquicktime - - map-to - NoQuickTime - - nosound map-to @@ -253,6 +247,12 @@ UserConnectionPort + portable + + count + 0 + + purge desc diff --git a/indra/newview/app_settings/default_grids.xml b/indra/newview/app_settings/default_grids.xml index b86d64ac3b..78c82ebdb6 100644 --- a/indra/newview/app_settings/default_grids.xml +++ b/indra/newview/app_settings/default_grids.xml @@ -2,7 +2,7 @@ - default_grids_version21 + default_grids_version23 @@ -11,22 +11,22 @@ gridnameSecond Life platformSecondLife loginurihttps://login.agni.lindenlab.com/cgi-bin/login.cgi - loginpagehttp://viewer-login.agni.lindenlab.com/ + loginpagehttps://viewer-splash.secondlife.com/ helperurihttps://secondlife.com/helpers/ websitehttp://secondlife.com/ supporthttp://secondlife.com/support/ registerhttp://secondlife.com/registration/ passwordhttp://secondlife.com/account/request.php render_compat1 - inventory_links1 auto_update0 + locked1 gridnicksecondlife_beta gridnameSecond Life BETA helperurihttp://aditi-secondlife.webdev.lindenlab.com/helpers/ - loginpagehttp://viewer-login.agni.lindenlab.com/ + loginpagehttps://viewer-splash.secondlife.com/ loginurihttps://login.aditi.lindenlab.com/cgi-bin/login.cgi passwordhttp://secondlife.com/account/request.php platformSecondLife @@ -34,7 +34,6 @@ supporthttp://secondlife.com/support/ registerhttp://secondlife.com/registration/ render_compat0 - inventory_links1 auto_update0 @@ -44,7 +43,6 @@ gridname OSGrid gridnick osgrid helperuri http://helper.osgrid.org/ - inventory_links 0 loginpage http://www.osgrid.org/splash/ loginuri http://login.osgrid.org/ password http://www.osgrid.org/ diff --git a/indra/newview/app_settings/dictionaries/en_sl.dic b/indra/newview/app_settings/dictionaries/en_sl.dic index 0f25bd2335..c2ab720884 100644 --- a/indra/newview/app_settings/dictionaries/en_sl.dic +++ b/indra/newview/app_settings/dictionaries/en_sl.dic @@ -730,6 +730,8 @@ llRotLookAt llStringLength llStartAnimation llStopAnimation +llStartObjectAnimation +llStopObjectAnimation llPointAt llStopPointAt llTargetOmega diff --git a/indra/newview/app_settings/keys.ini b/indra/newview/app_settings/keys.ini deleted file mode 100644 index eebb5dc332..0000000000 --- a/indra/newview/app_settings/keys.ini +++ /dev/null @@ -1,362 +0,0 @@ -# keys.ini -# -# keyboard binding initialization -# -# comments must have # in the first column -# blank lines OK -# -# Format: -# mode key mask function -# -# mode must be one of FIRST_PERSON, THIRD_PERSON, EDIT, EDIT_AVATAR, or CONVERSATION -# key must be upper case, or SPACE, HOME, END, PGUP, PGDN, LEFT, RIGHT, UP, DOWN, -# or one of ,.;'[] -# mask must be NONE, SHIFT, ALT, ALT_SHIFT. -# Control is reserved for user commands. -# function must be a function named in llkeyboard.cpp - -FIRST_PERSON A NONE slide_left -FIRST_PERSON D NONE slide_right -FIRST_PERSON W NONE push_forward -FIRST_PERSON S NONE push_backward -FIRST_PERSON E NONE jump -FIRST_PERSON C NONE push_down -FIRST_PERSON F NONE toggle_fly - -FIRST_PERSON LEFT NONE slide_left -FIRST_PERSON RIGHT NONE slide_right -FIRST_PERSON UP NONE push_forward -FIRST_PERSON DOWN NONE push_backward -FIRST_PERSON PGUP NONE jump -FIRST_PERSON PGDN NONE push_down -FIRST_PERSON HOME NONE toggle_fly - -FIRST_PERSON PAD_LEFT NONE slide_left -FIRST_PERSON PAD_RIGHT NONE slide_right -FIRST_PERSON PAD_UP NONE push_forward -FIRST_PERSON PAD_DOWN NONE push_backward -FIRST_PERSON PAD_PGUP NONE jump -FIRST_PERSON PAD_PGDN NONE push_down -FIRST_PERSON PAD_HOME NONE toggle_fly -FIRST_PERSON PAD_CENTER NONE stop_moving -FIRST_PERSON PAD_ENTER NONE start_chat -FIRST_PERSON PAD_DIVIDE NONE start_gesture - -FIRST_PERSON A SHIFT slide_left -FIRST_PERSON D SHIFT slide_right -FIRST_PERSON W SHIFT push_forward -FIRST_PERSON S SHIFT push_backward -FIRST_PERSON E SHIFT jump -FIRST_PERSON C SHIFT toggle_down -FIRST_PERSON F SHIFT toggle_fly - -FIRST_PERSON SPACE NONE stop_moving -FIRST_PERSON ENTER NONE start_chat -FIRST_PERSON DIVIDE NONE start_gesture -FIRST_PERSON / NONE start_gesture - -FIRST_PERSON LEFT SHIFT slide_left -FIRST_PERSON RIGHT SHIFT slide_right -FIRST_PERSON UP SHIFT push_forward -FIRST_PERSON DOWN SHIFT push_backward -FIRST_PERSON PGUP SHIFT jump -FIRST_PERSON PGDN SHIFT toggle_down - -FIRST_PERSON PAD_LEFT SHIFT slide_left -FIRST_PERSON PAD_RIGHT SHIFT slide_right -FIRST_PERSON PAD_UP SHIFT push_forward -FIRST_PERSON PAD_DOWN SHIFT push_backward -FIRST_PERSON PAD_PGUP SHIFT jump -FIRST_PERSON PAD_PGDN SHIFT toggle_down -FIRST_PERSON PAD_HOME SHIFT toggle_fly -FIRST_PERSON PAD_ENTER SHIFT start_chat -FIRST_PERSON PAD_DIVIDE SHIFT start_gesture - -THIRD_PERSON A NONE turn_left -THIRD_PERSON D NONE turn_right -THIRD_PERSON A SHIFT slide_left -THIRD_PERSON D SHIFT slide_right -THIRD_PERSON W NONE push_forward -THIRD_PERSON S NONE push_backward -THIRD_PERSON W SHIFT push_forward -THIRD_PERSON S SHIFT push_backward -THIRD_PERSON E NONE jump -THIRD_PERSON C NONE push_down -THIRD_PERSON E SHIFT jump -THIRD_PERSON C SHIFT toggle_down - -THIRD_PERSON F NONE toggle_fly -THIRD_PERSON F SHIFT toggle_fly - -THIRD_PERSON SPACE NONE stop_moving -THIRD_PERSON ENTER NONE start_chat -THIRD_PERSON DIVIDE NONE start_gesture -THIRD_PERSON / NONE start_gesture - -THIRD_PERSON LEFT NONE turn_left -THIRD_PERSON LEFT SHIFT slide_left -THIRD_PERSON RIGHT NONE turn_right -THIRD_PERSON RIGHT SHIFT slide_right -THIRD_PERSON UP NONE push_forward -THIRD_PERSON DOWN NONE push_backward -THIRD_PERSON UP SHIFT push_forward -THIRD_PERSON DOWN SHIFT push_backward -THIRD_PERSON PGUP NONE jump -THIRD_PERSON PGDN NONE push_down -THIRD_PERSON PGUP SHIFT jump -THIRD_PERSON PGDN SHIFT toggle_down -THIRD_PERSON HOME SHIFT toggle_fly -THIRD_PERSON HOME NONE toggle_fly - -THIRD_PERSON PAD_LEFT NONE turn_left -THIRD_PERSON PAD_LEFT SHIFT slide_left -THIRD_PERSON PAD_RIGHT NONE turn_right -THIRD_PERSON PAD_RIGHT SHIFT slide_right -THIRD_PERSON PAD_UP NONE push_forward -THIRD_PERSON PAD_DOWN NONE push_backward -THIRD_PERSON PAD_UP SHIFT push_forward -THIRD_PERSON PAD_DOWN SHIFT push_backward -THIRD_PERSON PAD_PGUP NONE jump -THIRD_PERSON PAD_PGDN NONE push_down -THIRD_PERSON PAD_PGUP SHIFT jump -THIRD_PERSON PAD_PGDN SHIFT toggle_down -THIRD_PERSON PAD_HOME NONE toggle_fly -THIRD_PERSON PAD_HOME SHIFT toggle_fly -THIRD_PERSON PAD_CENTER NONE stop_moving -THIRD_PERSON PAD_CENTER SHIFT stop_moving -THIRD_PERSON PAD_ENTER NONE start_chat -THIRD_PERSON PAD_ENTER SHIFT start_chat -THIRD_PERSON PAD_DIVIDE NONE start_gesture -THIRD_PERSON PAD_DIVIDE SHIFT start_gesture - -# Camera controls in third person on Alt -THIRD_PERSON LEFT ALT spin_around_cw -THIRD_PERSON RIGHT ALT spin_around_ccw -THIRD_PERSON UP ALT move_forward -THIRD_PERSON DOWN ALT move_backward -THIRD_PERSON PGUP ALT spin_over -THIRD_PERSON PGDN ALT spin_under - -THIRD_PERSON A ALT spin_around_cw -THIRD_PERSON D ALT spin_around_ccw -THIRD_PERSON W ALT move_forward -THIRD_PERSON S ALT move_backward -THIRD_PERSON E ALT spin_over -THIRD_PERSON C ALT spin_under - -THIRD_PERSON PAD_LEFT ALT spin_around_cw -THIRD_PERSON PAD_RIGHT ALT spin_around_ccw -THIRD_PERSON PAD_UP ALT move_forward -THIRD_PERSON PAD_DOWN ALT move_backward -THIRD_PERSON PAD_PGUP ALT spin_over -THIRD_PERSON PAD_PGDN ALT spin_under -THIRD_PERSON PAD_ENTER ALT start_chat -THIRD_PERSON PAD_DIVIDE ALT start_gesture - -# mimic alt zoom behavior with keyboard only -THIRD_PERSON A CTL_ALT spin_around_cw -THIRD_PERSON D CTL_ALT spin_around_ccw -THIRD_PERSON W CTL_ALT spin_over -THIRD_PERSON S CTL_ALT spin_under -THIRD_PERSON E CTL_ALT spin_over -THIRD_PERSON C CTL_ALT spin_under - -THIRD_PERSON LEFT CTL_ALT spin_around_cw -THIRD_PERSON RIGHT CTL_ALT spin_around_ccw -THIRD_PERSON UP CTL_ALT spin_over -THIRD_PERSON DOWN CTL_ALT spin_under -THIRD_PERSON PGUP CTL_ALT spin_over -THIRD_PERSON PGDN CTL_ALT spin_under - -THIRD_PERSON PAD_LEFT CTL_ALT spin_around_cw -THIRD_PERSON PAD_RIGHT CTL_ALT spin_around_ccw -THIRD_PERSON PAD_UP CTL_ALT spin_over -THIRD_PERSON PAD_DOWN CTL_ALT spin_under -THIRD_PERSON PAD_PGUP CTL_ALT spin_over -THIRD_PERSON PAD_PGDN CTL_ALT spin_under -THIRD_PERSON PAD_ENTER CTL_ALT start_chat -THIRD_PERSON PAD_DIVIDE CTL_ALT start_gesture - -# Therefore pan on Alt-Shift -THIRD_PERSON A CTL_ALT_SHIFT pan_left -THIRD_PERSON D CTL_ALT_SHIFT pan_right -THIRD_PERSON W CTL_ALT_SHIFT pan_up -THIRD_PERSON S CTL_ALT_SHIFT pan_down - -THIRD_PERSON LEFT CTL_ALT_SHIFT pan_left -THIRD_PERSON RIGHT CTL_ALT_SHIFT pan_right -THIRD_PERSON UP CTL_ALT_SHIFT pan_up -THIRD_PERSON DOWN CTL_ALT_SHIFT pan_down - -THIRD_PERSON PAD_LEFT CTL_ALT_SHIFT pan_left -THIRD_PERSON PAD_RIGHT CTL_ALT_SHIFT pan_right -THIRD_PERSON PAD_UP CTL_ALT_SHIFT pan_up -THIRD_PERSON PAD_DOWN CTL_ALT_SHIFT pan_down -THIRD_PERSON PAD_ENTER CTL_ALT_SHIFT start_chat -THIRD_PERSON PAD_DIVIDE CTL_ALT_SHIFT start_gesture - -# Basic editing camera control -EDIT A NONE spin_around_cw -EDIT D NONE spin_around_ccw -EDIT W NONE move_forward -EDIT S NONE move_backward -EDIT E NONE spin_over -EDIT C NONE spin_under -EDIT ENTER NONE start_chat -EDIT DIVIDE NONE start_gesture -EDIT / NONE start_gesture -EDIT PAD_ENTER NONE start_chat -EDIT PAD_DIVIDE NONE start_gesture - -EDIT LEFT NONE spin_around_cw -EDIT RIGHT NONE spin_around_ccw -EDIT UP NONE move_forward -EDIT DOWN NONE move_backward -EDIT PGUP NONE spin_over -EDIT PGDN NONE spin_under - -EDIT A SHIFT pan_left -EDIT D SHIFT pan_right -EDIT W SHIFT pan_up -EDIT S SHIFT pan_down - -EDIT LEFT SHIFT pan_left -EDIT RIGHT SHIFT pan_right -EDIT UP SHIFT pan_up -EDIT DOWN SHIFT pan_down - -# Walking works with ALT held down. -EDIT A ALT slide_left -EDIT D ALT slide_right -EDIT W ALT push_forward -EDIT S ALT push_backward -EDIT E ALT jump -EDIT C ALT push_down - -EDIT LEFT ALT slide_left -EDIT RIGHT ALT slide_right -EDIT UP ALT push_forward -EDIT DOWN ALT push_backward -EDIT PGUP ALT jump -EDIT PGDN ALT push_down -EDIT HOME ALT toggle_fly - -EDIT PAD_LEFT ALT slide_left -EDIT PAD_RIGHT ALT slide_right -EDIT PAD_UP ALT push_forward -EDIT PAD_DOWN ALT push_backward -EDIT PAD_PGUP ALT jump -EDIT PAD_PGDN ALT push_down -EDIT PAD_ENTER ALT start_chat -EDIT PAD_DIVIDE ALT start_gesture - -SITTING A ALT spin_around_cw -SITTING D ALT spin_around_ccw -SITTING W ALT move_forward -SITTING S ALT move_backward -SITTING E ALT spin_over_sitting -SITTING C ALT spin_under_sitting - -SITTING LEFT ALT spin_around_cw -SITTING RIGHT ALT spin_around_ccw -SITTING UP ALT move_forward -SITTING DOWN ALT move_backward -SITTING PGUP ALT spin_over -SITTING PGDN ALT spin_under - -SITTING A CTL_ALT spin_around_cw -SITTING D CTL_ALT spin_around_ccw -SITTING W CTL_ALT spin_over -SITTING S CTL_ALT spin_under -SITTING E CTL_ALT spin_over -SITTING C CTL_ALT spin_under - -SITTING LEFT CTL_ALT spin_around_cw -SITTING RIGHT CTL_ALT spin_around_ccw -SITTING UP CTL_ALT spin_over -SITTING DOWN CTL_ALT spin_under -SITTING PGUP CTL_ALT spin_over -SITTING PGDN CTL_ALT spin_under - - -SITTING A NONE spin_around_cw_sitting -SITTING D NONE spin_around_ccw_sitting -SITTING W NONE move_forward_sitting -SITTING S NONE move_backward_sitting -SITTING E NONE spin_over_sitting -SITTING C NONE spin_under_sitting - -SITTING LEFT NONE spin_around_cw_sitting -SITTING RIGHT NONE spin_around_ccw_sitting -SITTING UP NONE move_forward_sitting -SITTING DOWN NONE move_backward_sitting -SITTING PGUP NONE spin_over_sitting -SITTING PGDN NONE spin_under_sitting - -SITTING PAD_LEFT NONE spin_around_cw_sitting -SITTING PAD_RIGHT NONE spin_around_ccw_sitting -SITTING PAD_UP NONE move_forward_sitting -SITTING PAD_DOWN NONE move_backward_sitting -SITTING PAD_PGUP NONE spin_over_sitting -SITTING PAD_PGDN NONE spin_under_sitting -SITTING PAD_CENTER NONE stop_moving -SITTING PAD_ENTER NONE start_chat -SITTING PAD_DIVIDE NONE start_gesture - -# these are for passing controls when sitting on vehicles -SITTING A SHIFT slide_left -SITTING D SHIFT slide_right -SITTING LEFT SHIFT slide_left -SITTING RIGHT SHIFT slide_right - -SITTING PAD_LEFT SHIFT slide_left -SITTING PAD_RIGHT SHIFT slide_right -SITTING PAD_ENTER SHIFT start_chat -SITTING PAD_DIVIDE SHIFT start_gesture - -# pan on Alt-Shift -SITTING A CTL_ALT_SHIFT pan_left -SITTING D CTL_ALT_SHIFT pan_right -SITTING W CTL_ALT_SHIFT pan_up -SITTING S CTL_ALT_SHIFT pan_down - -SITTING LEFT CTL_ALT_SHIFT pan_left -SITTING RIGHT CTL_ALT_SHIFT pan_right -SITTING UP CTL_ALT_SHIFT pan_up -SITTING DOWN CTL_ALT_SHIFT pan_down - -SITTING PAD_LEFT CTL_ALT_SHIFT pan_left -SITTING PAD_RIGHT CTL_ALT_SHIFT pan_right -SITTING PAD_UP CTL_ALT_SHIFT pan_up -SITTING PAD_DOWN CTL_ALT_SHIFT pan_down -SITTING PAD_ENTER CTL_ALT_SHIFT start_chat -SITTING PAD_DIVIDE CTL_ALT_SHIFT start_gesture - -SITTING ENTER NONE start_chat -SITTING DIVIDE NONE start_gesture -SITTING / NONE start_gesture - -# Avatar editing camera controls -EDIT_AVATAR A NONE edit_avatar_spin_cw -EDIT_AVATAR D NONE edit_avatar_spin_ccw -EDIT_AVATAR W NONE edit_avatar_move_forward -EDIT_AVATAR S NONE edit_avatar_move_backward -EDIT_AVATAR E NONE edit_avatar_spin_over -EDIT_AVATAR C NONE edit_avatar_spin_under -EDIT_AVATAR LEFT NONE edit_avatar_spin_cw -EDIT_AVATAR RIGHT NONE edit_avatar_spin_ccw -EDIT_AVATAR UP NONE edit_avatar_move_forward -EDIT_AVATAR DOWN NONE edit_avatar_move_backward -EDIT_AVATAR PGUP NONE edit_avatar_spin_over -EDIT_AVATAR PGDN NONE edit_avatar_spin_under -EDIT_AVATAR ENTER NONE start_chat -EDIT_AVATAR DIVIDE NONE start_gesture -EDIT_AVATAR / NONE start_gesture -EDIT_AVATAR PAD_LEFT NONE edit_avatar_spin_cw -EDIT_AVATAR PAD_RIGHT NONE edit_avatar_spin_ccw -EDIT_AVATAR PAD_UP NONE edit_avatar_move_forward -EDIT_AVATAR PAD_DOWN NONE edit_avatar_move_backward -EDIT_AVATAR PAD_PGUP NONE edit_avatar_spin_over -EDIT_AVATAR PAD_PGDN NONE edit_avatar_spin_under -EDIT_AVATAR PAD_ENTER NONE start_chat -EDIT_AVATAR PAD_DIVIDE NONE start_gesture diff --git a/indra/newview/app_settings/keys.xml b/indra/newview/app_settings/keys.xml new file mode 100644 index 0000000000..cb7546aec6 --- /dev/null +++ b/indra/newview/app_settings/keys.xml @@ -0,0 +1,380 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/indra/newview/app_settings/keysZQSD.xml b/indra/newview/app_settings/keysZQSD.xml new file mode 100644 index 0000000000..c75b935b28 --- /dev/null +++ b/indra/newview/app_settings/keysZQSD.xml @@ -0,0 +1,380 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/indra/newview/app_settings/keywords.ini b/indra/newview/app_settings/keywords.ini index 503242ade2..3efc914cda 100644 --- a/indra/newview/app_settings/keywords.ini +++ b/indra/newview/app_settings/keywords.ini @@ -2,128 +2,131 @@ llkeywords version 2 # sections [word .5, .1, .3] -default Name of default state that all scripts must have -state Keyword to indicate state block or state transition +default Name of default state that all scripts must have +state Keyword to indicate state block or state transition # data types [word .1, .3, .1] -integer Integer type -float Floating-point type -string String type -key Key type. Use NULL_KEY to test for empty keys -vector Vector type of 3 floats. Used to represent 3D motion, Euler angles, and color.:Access components by .x, .y. or .z -rotation Rotation type of 4 floats. Used to represent rotation.:Access components by .x, .y., .z, or .w -list List of various data types -quaternion Rotation type of 4 floats. Used to represent rotation.:Access components by .x, .y, .z, or .w +integer Integer type +float Floating-point type +string String type +key Key type. Use NULL_KEY to test for empty keys +vector Vector type of 3 floats. Used to represent 3D motion, Euler angles, and color.:Access components by .x, .y. or .z +rotation Rotation type of 4 floats. Used to represent rotation.:Access components by .x, .y., .z, or .w +list List of various data types +quaternion Rotation type of 4 floats. Used to represent rotation.:Access components by .x, .y, .z, or .w # events [word 0, .3, .5] -state_entry state_entry():Triggered on any state transition and startup -state_exit state_exit():Triggered on any state transition -touch_start touch_start(integer num_detected):Triggered by the start of agent clicking on task -touch touch(integer num_detected):Triggered while agent is clicking on task -touch_end touch_end(integer num_detected):Triggered when agent stops clicking on task -collision_start collision_start(integer num_detected):Triggered when task starts colliding with another task -collision collision(integer num_detected):Triggered while task is colliding with another task -collision_end collision_end(integer num_detected):Triggered when task stops colliding with another task -land_collision_start land_collision_start(vector pos):Triggered when task starts colliding with land -land_collision land_collision(vector pos):Triggered when task is colliding with land -land_collision_end land_collision_end(vector pos):Triggered when task stops colliding with land -timer timer():Result of the llSetTimerEvent library function call -listen listen(integer channel, string name, key id, string message):Result of the llListen library function call -sensor sensor(integer num_detected):Result of the llSensor library function call -no_sensor no_sensor():Result of the llSensor library function call -control control(key id, integer level, integer edge):Result of llTakeControls library function call -at_target at_target(integer tnum, vector targetpos, vector ourpos):Result of llTarget library function call -not_at_target not_at_target():Result of llTarget library function call -at_rot_target at_rot_target(integer tnum, rotation targetrot, rotation ourrot):Result of LLRotTarget library function call -not_at_rot_target not_at_rot_target():Result of LLRotTarget library function call -money money(key id, integer amount):Triggered when L$ is given to task -email email(string time, string address, string subj, string message, integer num_left):Triggered when task receives email -run_time_permissions run_time_permissions(integer perm):Triggered when an agent grants run time permissions to task -attach attach(key id):Triggered when task attaches or detaches from agent -dataserver dataserver(key queryid, string data):Triggered when task receives asynchronous data -moving_start moving_start():Triggered when task begins moving -moving_end moving_end():Triggered when task stops moving -on_rez on_rez(integer start_param):Triggered when task is rezzed in from inventory or another task -object_rez object_rez(key id):Triggered when task rezzes in another task -link_message link_message(integer sender_num, integer num, string str, key id):Triggered when task receives a link message via LLMessageLinked library function call -changed changed( integer change ):Triggered various event change the task:(test change with CHANGED_INVENTORY, CHANGED_COLOR, CHANGED_SHAPE, CHANGED_SCALE, CHANGED_TEXTURE, CHANGED_LINK, CHANGED_ALLOWED_DROP, CHANGED_OWNER, CHANGED_REGION, CHANGED_TELEPORT, CHANGED_REGION_START, CHANGED_MEDIA) -remote_data remote_data(integer event_type, key channel, key message_id, string sender,integer idata, string sdata):Triggered by various XML-RPC calls (event_type will be one of REMOTE_DATA_CHANNEL, REMOTE_DATA_REQUEST, REMOTE_DATA_REPLY) -http_response http_response(key request_id, integer status, list metadata, string body):Triggered when task receives a response to one of its llHTTPRequests -http_request http_request(key id, string method, string body):Triggered when task receives an http request against a public URL -transaction_result transaction_result(key id, integer success, string data): Triggered when currency is given to task -path_update path_update(integer type, list reserved):Triggered when the state of a pathfinder character changes. Note; "list reserved" is not currently used +state_entry state_entry():Triggered on any state transition and startup +state_exit state_exit():Triggered on any state transition +touch_start touch_start(integer num_detected):Triggered by the start of agent clicking on task +touch touch(integer num_detected):Triggered while agent is clicking on task +touch_end touch_end(integer num_detected):Triggered when agent stops clicking on task +collision_start collision_start(integer num_detected):Triggered when task starts colliding with another task +collision collision(integer num_detected):Triggered while task is colliding with another task +collision_end collision_end(integer num_detected):Triggered when task stops colliding with another task +land_collision_start land_collision_start(vector pos):Triggered when task starts colliding with land +land_collision land_collision(vector pos):Triggered when task is colliding with land +land_collision_end land_collision_end(vector pos):Triggered when task stops colliding with land +timer timer():Result of the llSetTimerEvent library function call +listen listen(integer channel, string name, key id, string message):Result of the llListen library function call +sensor sensor(integer num_detected):Result of the llSensor library function call +no_sensor no_sensor():Result of the llSensor library function call +control control(key id, integer level, integer edge):Result of llTakeControls library function call +at_target at_target(integer tnum, vector targetpos, vector ourpos):Result of llTarget library function call +not_at_target not_at_target():Result of llTarget library function call +at_rot_target at_rot_target(integer tnum, rotation targetrot, rotation ourrot):Result of LLRotTarget library function call +not_at_rot_target not_at_rot_target():Result of LLRotTarget library function call +money money(key id, integer amount):Triggered when L$ is given to task +email email(string time, string address, string subj, string message, integer num_left):Triggered when task receives email +run_time_permissions run_time_permissions(integer perm):Triggered when an agent grants run time permissions to task +attach attach(key id):Triggered when task attaches or detaches from agent +dataserver dataserver(key queryid, string data):Triggered when task receives asynchronous data +moving_start moving_start():Triggered when task begins moving +moving_end moving_end():Triggered when task stops moving +on_rez on_rez(integer start_param):Triggered when task is rezzed in from inventory or another task +object_rez object_rez(key id):Triggered when task rezzes in another task +link_message link_message(integer sender_num, integer num, string str, key id):Triggered when task receives a link message via LLMessageLinked library function call +changed changed( integer change ):Triggered various event change the task:(test change with CHANGED_INVENTORY, CHANGED_COLOR, CHANGED_SHAPE, CHANGED_SCALE, CHANGED_TEXTURE, CHANGED_LINK, CHANGED_ALLOWED_DROP, CHANGED_OWNER, CHANGED_REGION, CHANGED_TELEPORT, CHANGED_REGION_START, CHANGED_MEDIA) +remote_data remote_data(integer event_type, key channel, key message_id, string sender,integer idata, string sdata):Triggered by various XML-RPC calls (event_type will be one of REMOTE_DATA_CHANNEL, REMOTE_DATA_REQUEST, REMOTE_DATA_REPLY) +http_response http_response(key request_id, integer status, list metadata, string body):Triggered when task receives a response to one of its llHTTPRequests +http_request http_request(key id, string method, string body):Triggered when task receives an http request against a public URL +transaction_result transaction_result(key id, integer success, string data): Triggered when currency is given to task +path_update path_update(integer type, list reserved):Triggered when the state of a pathfinder character changes. Note; "list reserved" is not currently used +experience_permissions experience_permissions(key agent): Triggered when agent has approved an experience permissions request. This may be through interaction with the experience permission dialog or the experience profile, or automatically if the agent has previously approved the experience. +experience_permissions_denied experience_permissions_denied(key agent, integer reason): Triggered when agent has denied experience permission. reason is the reason for denial; one of the Experience Tools XP_ERROR_* errors flags. + # integer constants [word .1, .1, .5] -TRUE Integer constant for Boolean operations -FALSE Integer constant for Boolean operations -STATUS_PHYSICS Passed in the llSetStatus library function. If TRUE, object moves physically -STATUS_PHANTOM Passed in the llSetStatus library function. If TRUE, object doesn't collide with other objects -STATUS_ROTATE_X Passed in the llSetStatus library function. If FALSE, object doesn't rotate around local X axis -STATUS_ROTATE_Y Passed in the llSetStatus library function. If FALSE, object doesn't rotate around local Y axis -STATUS_ROTATE_Z Passed in the llSetStatus library function. If FALSE, object doesn't rotate around local Z axis -STATUS_SANDBOX Passed in the llSetStatus library function. If TRUE, object can't cross region boundaries or move more than 10 meters from its start location -STATUS_BLOCK_GRAB Passed in the llSetStatus library function. If TRUE, object can't be grabbed and physically dragged -STATUS_BLOCK_GRAB_OBJECT This status flag keeps the object from being moved by grabs. This flag applies to the entire linkset -STATUS_DIE_AT_EDGE Passed in the llSetStatus library function. If TRUE, objects that reach the edge of the world just die:rather than teleporting back to the owner -STATUS_RETURN_AT_EDGE Passed in the llSetStatus library function. If TRUE, script rezzed objects that reach the edge of the world:are returned rather than killed:STATUS_RETURN_AT_EDGE trumps STATUS_DIE_AT_EDGE if both are set -STATUS_CAST_SHADOWS Passed in the llSetStatus library function. If TRUE, object casts shadows on other objects - -AGENT Passed in llSensor library function to look for other Agents; DEPRECATED: Use AGENT_BY_LEGACY_NAME -AGENT_BY_LEGACY_NAME Passed in llSensor library function to look for other Agents by legacy name -AGENT_BY_USERNAME Passed in llSensor library function to look for other Agents by username -ACTIVE Passed in llSensor library function to look for moving objects -PASSIVE Passed in llSensor library function to look for objects that aren't moving -SCRIPTED Passed in llSensor library function to look for scripted objects -CONTROL_FWD Passed to llTakeControls library function and used control event handler to test for agent forward control -CONTROL_BACK Passed to llTakeControls library function and used control event handler to test for agent back control -CONTROL_LEFT Passed to llTakeControls library function and used control event handler to test for agent left control -CONTROL_RIGHT Passed to llTakeControls library function and used control event handler to test for agent right control -CONTROL_ROT_LEFT Passed to llTakeControls library function and used control event handler to test for agent rotate left control -CONTROL_ROT_RIGHT Passed to llTakeControls library function and used control event handler to test for agent rotate right control -CONTROL_UP Passed to llTakeControls library function and used control event handler to test for agent up control -CONTROL_DOWN Passed to llTakeControls library function and used control event handler to test for agent down control -CONTROL_LBUTTON Passed to llTakeControls library function and used control event handler to test for agent left button control -CONTROL_ML_LBUTTON Passed to llTakeControls library function and used control event handler to test for agent left button control with the agent in mouse look -PERMISSION_DEBIT Passed to llRequestPermissions library function to request permission to take L$ from agent's account -PERMISSION_TAKE_CONTROLS Passed to llRequestPermissions library function to request permission to take agent's controls -# PERMISSION_REMAP_CONTROLS Passed to llRequestPermissions library function to request permission to remap agent's controls (not implemented yet) -PERMISSION_TRIGGER_ANIMATION Passed to llRequestPermissions library function to request permission to trigger animation on agent -PERMISSION_ATTACH Passed to llRequestPermissions library function to request permission to attach/detach from agent -# PERMISSION_RELEASE_OWNERSHIP Passed to llRequestPermissions library function to request permission to release ownership (not implemented) -PERMISSION_CHANGE_LINKS Passed to llRequestPermissions library function to request permission to change links -# PERMISSION_CHANGE_JOINTS Passed to llRequestPermissions library function to request permission to change joints (not implemented) +TRUE Integer constant for Boolean operations +FALSE Integer constant for Boolean operations +STATUS_PHYSICS Passed in the llSetStatus library function. If TRUE, object moves physically +STATUS_PHANTOM Passed in the llSetStatus library function. If TRUE, object doesn't collide with other objects +STATUS_ROTATE_X Passed in the llSetStatus library function. If FALSE, object doesn't rotate around local X axis +STATUS_ROTATE_Y Passed in the llSetStatus library function. If FALSE, object doesn't rotate around local Y axis +STATUS_ROTATE_Z Passed in the llSetStatus library function. If FALSE, object doesn't rotate around local Z axis +STATUS_SANDBOX Passed in the llSetStatus library function. If TRUE, object can't cross region boundaries or move more than 10 meters from its start location +STATUS_BLOCK_GRAB Passed in the llSetStatus library function. If TRUE, root prim of linkset (or unlinked prim) can't be grabbed and physically dragged +STATUS_DIE_AT_EDGE Passed in the llSetStatus library function. If TRUE, objects that reach the edge of the world just die:rather than teleporting back to the owner +STATUS_RETURN_AT_EDGE Passed in the llSetStatus library function. If TRUE, script rezzed objects that reach the edge of the world:are returned rather than killed:STATUS_RETURN_AT_EDGE trumps STATUS_DIE_AT_EDGE if both are set +STATUS_CAST_SHADOWS Passed in the llSetStatus library function. If TRUE, object casts shadows on other objects +STATUS_BLOCK_GRAB_OBJECT Passed in the llSetStatus library function. If TRUE, no prims in linkset can be grabbed or physically dragged + +AGENT Passed in llSensor library function to look for other Agents; DEPRECATED: Use AGENT_BY_LEGACY_NAME +AGENT_BY_LEGACY_NAME Passed in llSensor library function to look for other Agents by legacy name +AGENT_BY_USERNAME Passed in llSensor library function to look for other Agents by username +ACTIVE Passed in llSensor library function to look for moving objects +PASSIVE Passed in llSensor library function to look for objects that aren't moving +SCRIPTED Passed in llSensor library function to look for scripted objects +CONTROL_FWD Passed to llTakeControls library function and used control event handler to test for agent forward control +CONTROL_BACK Passed to llTakeControls library function and used control event handler to test for agent back control +CONTROL_LEFT Passed to llTakeControls library function and used control event handler to test for agent left control +CONTROL_RIGHT Passed to llTakeControls library function and used control event handler to test for agent right control +CONTROL_ROT_LEFT Passed to llTakeControls library function and used control event handler to test for agent rotate left control +CONTROL_ROT_RIGHT Passed to llTakeControls library function and used control event handler to test for agent rotate right control +CONTROL_UP Passed to llTakeControls library function and used control event handler to test for agent up control +CONTROL_DOWN Passed to llTakeControls library function and used control event handler to test for agent down control +CONTROL_LBUTTON Passed to llTakeControls library function and used control event handler to test for agent left button control +CONTROL_ML_LBUTTON Passed to llTakeControls library function and used control event handler to test for agent left button control with the agent in mouse look +PERMISSION_DEBIT Passed to llRequestPermissions library function to request permission to take L$ from agent's account +PERMISSION_TAKE_CONTROLS Passed to llRequestPermissions library function to request permission to take agent's controls +# PERMISSION_REMAP_CONTROLS Passed to llRequestPermissions library function to request permission to remap agent's controls (not implemented yet) +PERMISSION_TRIGGER_ANIMATION Passed to llRequestPermissions library function to request permission to trigger animation on agent +PERMISSION_ATTACH Passed to llRequestPermissions library function to request permission to attach/detach from agent +# PERMISSION_RELEASE_OWNERSHIP Passed to llRequestPermissions library function to request permission to release ownership (not implemented) +PERMISSION_CHANGE_LINKS Passed to llRequestPermissions library function to request permission to change links +# PERMISSION_CHANGE_JOINTS Passed to llRequestPermissions library function to request permission to change joints (not implemented) # PERMISSION_CHANGE_PERMISSIONS Passed to llRequestPermissions library function to request permission to change permissions -PERMISSION_TRACK_CAMERA Passed to llRequestPermissions library function to request permission to track agent's camera -PERMISSION_CONTROL_CAMERA Passed to llRequestPermissions library function to request permission to change agent's camera -PERMISSION_TELEPORT Passed to llRequestPermissions library function to request permission to teleport agent -SCRIPT_PERMISSION_SILENT_ESTATE_MANAGEMENT Passed to llRequestPermissions library function to request permission to silently modify estate access lists -PERMISSION_OVERRIDE_ANIMATIONS Passed to llRequestPermissions library function to request permission to override animations on agent -PERMISSION_RETURN_OBJECTS Passed to llRequestPermissions library function to request permission to return objects - -DEBUG_CHANNEL Chat channel reserved for debug and error messages from scripts -PUBLIC_CHANNEL Chat channel that broadcasts to all nearby users - -AGENT_FLYING Returned by llGetAgentInfo if the Agent is flying -AGENT_ATTACHMENTS Returned by llGetAgentInfo if the Agent has attachments -AGENT_SCRIPTED Returned by llGetAgentInfo if the Agent has scripted attachments -AGENT_SITTING Returned by llGetAgentInfo if the Agent is sitting -AGENT_ON_OBJECT Returned by llGetAgentInfo if the Agent is sitting on an object -AGENT_MOUSELOOK Returned by llGetAgentInfo if the Agent is in mouselook -AGENT_AWAY Returned by llGetAgentInfo if the Agent is in away mode -AGENT_WALKING Returned by llGetAgentInfo if the Agent is walking -AGENT_IN_AIR Returned by llGetAgentInfo if the Agent is in the air -AGENT_TYPING Returned by llGetAgentInfo if the Agent is typing -AGENT_CROUCHING Returned by llGetAgentInfo if the Agent is crouching -AGENT_BUSY Returned by llGetAgentInfo if the Agent is busy -AGENT_ALWAYS_RUN Returned by llGetAgentInfo if the Agent has 'Always Run' enabled -AGENT_AUTOPILOT Returned by llGetAgentInfo if the Agent is under autopilot control - -AGENT_LIST_PARCEL Passed to llGetAgentList to return only agents on the same parcel where the script is running +PERMISSION_TRACK_CAMERA Passed to llRequestPermissions library function to request permission to track agent's camera +PERMISSION_CONTROL_CAMERA Passed to llRequestPermissions library function to request permission to change agent's camera +PERMISSION_TELEPORT Passed to llRequestPermissions library function to request permission to teleport agent +SCRIPT_PERMISSION_SILENT_ESTATE_MANAGEMENT Passed to llRequestPermissions library function to request permission to silently modify estate access lists +PERMISSION_OVERRIDE_ANIMATIONS Passed to llRequestPermissions library function to request permission to override animations on agent +PERMISSION_RETURN_OBJECTS Passed to llRequestPermissions library function to request permission to return objects + +DEBUG_CHANNEL Chat channel reserved for debug and error messages from scripts +PUBLIC_CHANNEL Chat channel that broadcasts to all nearby users + +AGENT_FLYING Returned by llGetAgentInfo if the Agent is flying +AGENT_ATTACHMENTS Returned by llGetAgentInfo if the Agent has attachments +AGENT_SCRIPTED Returned by llGetAgentInfo if the Agent has scripted attachments +AGENT_SITTING Returned by llGetAgentInfo if the Agent is sitting +AGENT_ON_OBJECT Returned by llGetAgentInfo if the Agent is sitting on an object +AGENT_MOUSELOOK Returned by llGetAgentInfo if the Agent is in mouselook +AGENT_AWAY Returned by llGetAgentInfo if the Agent is in away mode +AGENT_WALKING Returned by llGetAgentInfo if the Agent is walking +AGENT_IN_AIR Returned by llGetAgentInfo if the Agent is in the air +AGENT_TYPING Returned by llGetAgentInfo if the Agent is typing +AGENT_CROUCHING Returned by llGetAgentInfo if the Agent is crouching +AGENT_BUSY Returned by llGetAgentInfo if the Agent is busy +AGENT_ALWAYS_RUN Returned by llGetAgentInfo if the Agent has 'Always Run' enabled +AGENT_AUTOPILOT Returned by llGetAgentInfo if the Agent is under autopilot control + +AGENT_LIST_PARCEL Passed to llGetAgentList to return only agents on the same parcel where the script is running AGENT_LIST_PARCEL_OWNER Passed to llGetAgentList to return only agents on any parcel in the region where the parcel owner is the same as the owner of the parcel under the scripted object -AGENT_LIST_REGION Passed to llGetAgentList to return any/all agents in the region +AGENT_LIST_REGION Passed to llGetAgentList to return any/all agents in the region PSYS_PART_FLAGS PSYS_PART_START_COLOR @@ -150,18 +153,9 @@ PSYS_PART_EMISSIVE_MASK PSYS_PART_TARGET_LINEAR_MASK PSYS_PART_RIBBON_MASK -PSYS_PART_BF_ONE -PSYS_PART_BF_ZERO -PSYS_PART_BF_DEST_COLOR -PSYS_PART_BF_SOURCE_COLOR -PSYS_PART_BF_ONE_MINUS_DEST_COLOR -PSYS_PART_BF_ONE_MINUS_SOURCE_COLOR -PSYS_PART_BF_SOURCE_ALPHA -PSYS_PART_BF_ONE_MINUS_SOURCE_ALPHA - PSYS_SRC_PATTERN -PSYS_SRC_INNERANGLE Deprecated -- Use PSYS_SRC_ANGLE_BEGIN -PSYS_SRC_OUTERANGLE Deprecated -- Use PSYS_SRC_ANGLE_END +PSYS_SRC_INNERANGLE Deprecated -- Use PSYS_SRC_ANGLE_BEGIN +PSYS_SRC_OUTERANGLE Deprecated -- Use PSYS_SRC_ANGLE_END PSYS_SRC_ANGLE_BEGIN PSYS_SRC_ANGLE_END PSYS_SRC_BURST_RATE @@ -180,409 +174,432 @@ PSYS_SRC_PATTERN_EXPLODE PSYS_SRC_PATTERN_ANGLE PSYS_SRC_PATTERN_ANGLE_CONE PSYS_SRC_PATTERN_ANGLE_CONE_EMPTY +PSYS_PART_BF_ONE +PSYS_PART_BF_ZERO +PSYS_PART_BF_DEST_COLOR +PSYS_PART_BF_SOURCE_COLOR +PSYS_PART_BF_ONE_MINUS_DEST_COLOR +PSYS_PART_BF_ONE_MINUS_SOURCE_COLOR +PSYS_PART_BF_SOURCE_ALPHA +PSYS_PART_BF_ONE_MINUS_SOURCE_ALPHA -OBJECT_UNKNOWN_DETAIL Returned by llGetObjectDetails when passed an invalid object parameter type -OBJECT_NAME Used with llGetObjectDetails to get an object's name -OBJECT_DESC Used with llGetObjectDetails to get an object's description -OBJECT_POS Used with llGetObjectDetails to get an object's position -OBJECT_ROT Used with llGetObjectDetails to get an object's rotation -OBJECT_VELOCITY Used with llGetObjectDetails to get an object's velocity -OBJECT_OWNER Used with llGetObjectDetails to get an object's owner's key. Will be NULL_KEY if group owned -OBJECT_GROUP Used with llGetObjectDetails to get an object's group's key -OBJECT_CREATOR Used with llGetObjectDetails to get an object's creator's key -OBJECT_RUNNING_SCRIPT_COUNT Gets the number of running scripts attached to the object or agent -OBJECT_TOTAL_SCRIPT_COUNT Gets the number of scripts, both running and stopped, attached to the object or agent. -OBJECT_SCRIPT_MEMORY Gets the total amount of script memory allocated to the object or agent, in bytes. -OBJECT_SCRIPT_TIME Gets the total amount of average script CPU time used by the object or agent, in seconds. -OBJECT_PRIM_EQUIVALENCE Gets the prim equivalence of the object. -OBJECT_SERVER_COST Used with llGetObjectDetails to get the server cost. -OBJECT_STREAMING_COST Used with llGetObjectDetails to get the streaming (download) cost. -OBJECT_PHYSICS_COST Used with llGetObjectDetails to get the physics cost. -OBJECT_PATHFINDING_TYPE Used with llGetObjectDetails to get an object's pathfinding settings. -OBJECT_CHARACTER_TIME Used with llGetObjectDetails to get an object's average CPU time (in seconds) used by the object for navigation, if the object is a pathfinding character. Returns 0 for non-characters. -OBJECT_ROOT Used with llGetObjectDetails to get an object's root prim ID. -OBJECT_ATTACHED_POINT Used with llGetObjectDetails to get an object's attachment point. -OBJECT_RETURN_PARCEL Used with llReturnObjectsByOwner to return all objects on the same parcel as the script which are owned by 'owner'. -OBJECT_RETURN_PARCEL_OWNER Used with llReturnObjectsByOwner to return all objects owned by 'owner' which are over parcels owned by the owner of the script. -OBJECT_RETURN_REGION Used with llReturnObjectsByOwner to return all objects in the region owned by 'owner' - only works when the script is owned by the estate owner or an estate manager. - -OPT_UNKNOWN Returned object pathfinding type by llGetObjectDetails for attachments, Linden trees and grass. -OPT_LEGACY_LINKSET Returned object pathfinding type by llGetObjectDetails for movable obstacles, movable phantoms, physical, and volumedetect objects. -OPT_AVATAR Returned object pathfinding type by llGetObjectDetails for avatars. -OPT_PATHFINDING_CHARACTER Returned object pathfinding type by llGetObjectDetails for pathfinding characters. -OPT_WALKABLE Returned object pathfinding type by llGetObjectDetails for walkable objects. -OPT_STATIC_OBSTACLE Returned object pathfinding type by llGetObjectDetails for static obstacles. -OPT_MATERIAL_VOLUME Returned object pathfinding type by llGetObjectDetails for material volumes. -OPT_EXCLUSION_VOLUME Returned object pathfinding type by llGetObjectDetails for exclusion volumes. +OBJECT_UNKNOWN_DETAIL Returned by llGetObjectDetails when passed an invalid object parameter type +OBJECT_HOVER_HEIGHT This is a flag used with llGetObjectDetails to get hover height of the avatar. If no data is available, 0.0 is returned. +OBJECT_LAST_OWNER_ID Gets the object's last owner ID. +OBJECT_NAME Used with llGetObjectDetails to get an object's name +OBJECT_DESC Used with llGetObjectDetails to get an object's description +OBJECT_POS Used with llGetObjectDetails to get an object's position +OBJECT_ROT Used with llGetObjectDetails to get an object's rotation +OBJECT_VELOCITY Used with llGetObjectDetails to get an object's velocity +OBJECT_OWNER Used with llGetObjectDetails to get an object's owner's key. Will be NULL_KEY if group owned +OBJECT_GROUP Used with llGetObjectDetails to get an object's group's key +OBJECT_CLICK_ACTION This is a flag used with llGetObjectDetails to get the click action. The default is 0. +OBJECT_CREATOR Used with llGetObjectDetails to get an object's creator's key +OBJECT_RUNNING_SCRIPT_COUNT Gets the number of running scripts attached to the object or agent +OBJECT_TOTAL_SCRIPT_COUNT Gets the number of scripts, both running and stopped, attached to the object or agent. +OBJECT_SCRIPT_MEMORY Gets the total amount of script memory allocated to the object or agent, in bytes. +OBJECT_SCRIPT_TIME Gets the total amount of average script CPU time used by the object or agent, in seconds. +OBJECT_PRIM_EQUIVALENCE Gets the prim equivalence of the object. +OBJECT_SERVER_COST Used with llGetObjectDetails to get the server cost. +OBJECT_STREAMING_COST Used with llGetObjectDetails to get the streaming (download) cost. +OBJECT_PHYSICS_COST Used with llGetObjectDetails to get the physics cost. +OBJECT_PATHFINDING_TYPE Used with llGetObjectDetails to get an object's pathfinding settings. +OBJECT_BODY_SHAPE_TYPE This is a flag used with llGetObjectDetails to get the body type of the avatar, based on shape data. If no data is available, -1.0 is returned. This is normally between 0 and 1.0, with 0.5 and larger considered 'male' +OBJECT_CHARACTER_TIME Used with llGetObjectDetails to get an object's average CPU time (in seconds) used by the object for navigation, if the object is a pathfinding character. Returns 0 for non-characters. +OBJECT_ROOT Used with llGetObjectDetails to get an object's root prim ID. +OBJECT_ATTACHED_POINT Used with llGetObjectDetails to get an object's attachment point. +OBJECT_RETURN_PARCEL Used with llReturnObjectsByOwner to return all objects on the same parcel as the script which are owned by 'owner'. +OBJECT_RETURN_PARCEL_OWNER Used with llReturnObjectsByOwner to return all objects owned by 'owner' which are over parcels owned by the owner of the script. +OBJECT_RETURN_REGION Used with llReturnObjectsByOwner to return all objects in the region owned by 'owner' - only works when the script is owned by the estate owner or an estate manager. + +OPT_UNKNOWN Returned object pathfinding type by llGetObjectDetails for attachments, Linden trees and grass. +OPT_LEGACY_LINKSET Returned object pathfinding type by llGetObjectDetails for movable obstacles, movable phantoms, physical, and volumedetect objects. +OPT_AVATAR Returned object pathfinding type by llGetObjectDetails for avatars. +OPT_PATHFINDING_CHARACTER Returned object pathfinding type by llGetObjectDetails for pathfinding characters. +OPT_WALKABLE Returned object pathfinding type by llGetObjectDetails for walkable objects. +OPT_STATIC_OBSTACLE Returned object pathfinding type by llGetObjectDetails for static obstacles. +OPT_MATERIAL_VOLUME Returned object pathfinding type by llGetObjectDetails for material volumes. +OPT_EXCLUSION_VOLUME Returned object pathfinding type by llGetObjectDetails for exclusion volumes. # some vehicle params -VEHICLE_TYPE_NONE Used with llSetVehicleType to turn off vehicle support -VEHICLE_TYPE_SLED Used with llSetVehicleType to make a simple vehicle that bumps along the ground, and likes to move along its local x-axis -VEHICLE_TYPE_CAR Used with llSetVehicleType to make a vehicle that bounces along the ground but needs the motors to be driven from external controls or timer events -VEHICLE_TYPE_BOAT Used with llSetVehicleType to make a vehicle that hovers over water with lots of friction and some angular deflection -VEHICLE_TYPE_AIRPLANE Used with llSetVehicleType to make a vehicle that uses linear deflection for lift, and banking to turn, but doesn't hover -VEHICLE_TYPE_BALLOON Used with llSetVehicleType to make a vehicle that uses hover, and friction, but doesn't use deflection - -VEHICLE_REFERENCE_FRAME Rotation of vehicle axes relative to local frame - -VEHICLE_LINEAR_FRICTION_TIMESCALE A vector of timescales for exponential decay of linear velocity along the three vehicle axes -VEHICLE_ANGULAR_FRICTION_TIMESCALE A vector of timescales for exponential decay of angular velocity about the three vehicle axes -VEHICLE_LINEAR_MOTOR_DIRECTION The linear velocity that the vehicle will try to achieve -VEHICLE_LINEAR_MOTOR_OFFSET An offset from the center of mass of the vehicle where the linear motor is applied -VEHICLE_ANGULAR_MOTOR_DIRECTION The angular velocity that the vehicle will try to achieve - -VEHICLE_HOVER_HEIGHT The height the vehicle will try to hover -VEHICLE_HOVER_EFFICIENCY A slider between 0 (bouncy) and 1 (critically damped) hover behavior -VEHICLE_HOVER_TIMESCALE The period of time for the vehicle to achieve its hover height -VEHICLE_BUOYANCY A slider between 0 (no anti-gravity) and 1 (full anti-gravity) - -VEHICLE_LINEAR_DEFLECTION_EFFICIENCY A slider between 0 (no deflection) and 1 (maximum strength) -VEHICLE_LINEAR_DEFLECTION_TIMESCALE The exponential timescale for the vehicle to redirect its velocity to be along its x-axis - -VEHICLE_LINEAR_MOTOR_TIMESCALE The exponential timescale for the vehicle to achive its full linear motor velocity -VEHICLE_LINEAR_MOTOR_DECAY_TIMESCALE The exponential timescale for the linear motor's effectiveness to decay toward zero - -VEHICLE_ANGULAR_DEFLECTION_EFFICIENCY A slider between 0 (no deflection) and 1 (maximum strength) -VEHICLE_ANGULAR_DEFLECTION_TIMESCALE The exponential timescale for the vehicle to achieve full angular deflection - -VEHICLE_ANGULAR_MOTOR_TIMESCALE The exponential timescale for the vehicle to achive its full angular motor velocity -VEHICLE_ANGULAR_MOTOR_DECAY_TIMESCALE The exponential timescale for the angular motor's effectiveness to decay toward zero - -VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY A slider between 0 (bouncy) and 1 (critically damped) attraction of vehicle z-axis to world z-axis (vertical) -VEHICLE_VERTICAL_ATTRACTION_TIMESCALE The exponential timescale for the vehicle to align its z-axis to the world z-axis (vertical) - -VEHICLE_BANKING_EFFICIENCY A slider between -1 (leans out of turns), 0 (no banking), and +1 (leans into turns) -VEHICLE_BANKING_MIX A slider between 0 (static banking) and 1 (dynamic banking) -VEHICLE_BANKING_TIMESCALE The exponential timescale for the banking behavior to take full effect - -VEHICLE_FLAG_NO_DEFLECTION_UP Prevents linear deflection along world-z axis -VEHICLE_FLAG_LIMIT_ROLL_ONLY Removes vertical attraction for changes in vehicle pitch -VEHICLE_FLAG_HOVER_WATER_ONLY Hover only pays attention to water level -VEHICLE_FLAG_HOVER_TERRAIN_ONLY Hover only pays attention to terrain height -VEHICLE_FLAG_HOVER_GLOBAL_HEIGHT Hover only pays attention to global height -VEHICLE_FLAG_HOVER_UP_ONLY Hover only pushes up -VEHICLE_FLAG_LIMIT_MOTOR_UP Prevents ground vehicles from motoring into the sky -VEHICLE_FLAG_MOUSELOOK_STEER Makes vehicle try to turn toward mouselook direction -VEHICLE_FLAG_MOUSELOOK_BANK Makes vehicle try to turn toward mouselook direction assuming banking is enabled -VEHICLE_FLAG_CAMERA_DECOUPLED Causes the camera look-at axis to NOT move when the vehicle rotates - -CAMERA_PITCH (-45 to 80) (Adjusts the angular amount that the camera aims straight ahead vs. straight down, maintaining the same distance. Analogous to 'incidence'.") -CAMERA_FOCUS_OFFSET (-10 to 10) A vector that adjusts the position of the camera focus position relative to the subject -CAMERA_POSITION_LAG (0.0 to 3.0) How much the camera lags as it tries to move towards its 'ideal' position -CAMERA_FOCUS_LAG (0.0 to 3.0) How much the camera lags as it tries to aim towards the subject -CAMERA_DISTANCE (0.5 to 10) Sets how far away the camera wants to be from its subject -CAMERA_BEHINDNESS_ANGLE (0 to 180) Sets the angle in degrees within which the camera is not constrained by changes in subject rotation -CAMERA_BEHINDNESS_LAG (0.0 to 3.0) Sets how strongly the camera is forced to stay behind the target if outside of behindness angle -CAMERA_POSITION_THRESHOLD (0.0 to 4.0) Sets the radius of a sphere around the camera's ideal position within which it is not affected by subject motion -CAMERA_FOCUS_THRESHOLD (0.0 to 4.0) Sets the radius of a sphere around the camera's subject position within which its focus is not affected by subject motion -CAMERA_ACTIVE (0 or 1) Turns on or off scripted control of the camera -CAMERA_POSITION Sets the position of the camera -CAMERA_FOCUS Sets the focus (target position) of the camera -CAMERA_POSITION_LOCKED (0 or 1) Locks the camera position so it will not move -CAMERA_FOCUS_LOCKED (0 or 1) Locks the camera focus so it will not move - -INVENTORY_TEXTURE Passed to task inventory library functions to reference textures -INVENTORY_SOUND Passed to task inventory library functions to reference sounds -INVENTORY_OBJECT Passed to task inventory library functions to reference objects -INVENTORY_SCRIPT Passed to task inventory library functions to reference scripts -INVENTORY_LANDMARK Passed to task inventory library functions to reference landmarks -INVENTORY_CLOTHING Passed to task inventory library functions to reference clothing -INVENTORY_NOTECARD Passed to task inventory library functions to reference notecards -INVENTORY_BODYPART Passed to task inventory library functions to reference body parts -INVENTORY_ANIMATION Passed to task inventory library functions to reference animations -INVENTORY_GESTURE Passed to task inventory library functions to reference gestures -INVENTORY_ALL Passed to task inventory library functions to reference all inventory items -INVENTORY_NONE Returned by llGetInventoryType when no item is found - -ATTACH_CHEST Passed to llAttachToAvatar to attach task to chest -ATTACH_HEAD Passed to llAttachToAvatar to attach task to head -ATTACH_LSHOULDER Passed to llAttachToAvatar to attach task to left shoulder -ATTACH_RSHOULDER Passed to llAttachToAvatar to attach task to right shoulder -ATTACH_LHAND Passed to llAttachToAvatar to attach task to left hand -ATTACH_RHAND Passed to llAttachToAvatar to attach task to right hand -ATTACH_LFOOT Passed to llAttachToAvatar to attach task to left foot -ATTACH_RFOOT Passed to llAttachToAvatar to attach task to right foot -ATTACH_BACK Passed to llAttachToAvatar to attach task to back -ATTACH_PELVIS Passed to llAttachToAvatar to attach task to pelvis -ATTACH_MOUTH Passed to llAttachToAvatar to attach task to mouth -ATTACH_CHIN Passed to llAttachToAvatar to attach task to chin -ATTACH_LEAR Passed to llAttachToAvatar to attach task to left ear -ATTACH_REAR Passed to llAttachToAvatar to attach task to right ear -ATTACH_LEYE Passed to llAttachToAvatar to attach task to left eye -ATTACH_REYE Passed to llAttachToAvatar to attach task to right eye -ATTACH_NOSE Passed to llAttachToAvatar to attach task to nose -ATTACH_RUARM Passed to llAttachToAvatar to attach task to right upper arm -ATTACH_RLARM Passed to llAttachToAvatar to attach task to right lower arm -ATTACH_LUARM Passed to llAttachToAvatar to attach task to left upper arm -ATTACH_LLARM Passed to llAttachToAvatar to attach task to left lower arm -ATTACH_RHIP Passed to llAttachToAvatar to attach task to right hip -ATTACH_RULEG Passed to llAttachToAvatar to attach task to right upper leg -ATTACH_RLLEG Passed to llAttachToAvatar to attach task to right lower leg -ATTACH_LHIP Passed to llAttachToAvatar to attach task to left hip -ATTACH_LULEG Passed to llAttachToAvatar to attach task to left upper leg -ATTACH_LLLEG Passed to llAttachToAvatar to attach task to left lower leg -ATTACH_BELLY Passed to llAttachToAvatar to attach task to belly -ATTACH_LEFT_PEC Passed to llAttachToAvatar to attach task to left pectoral -ATTACH_RIGHT_PEC Passed to llAttachToAvatar to attach task to right pectoral -ATTACH_HUD_BOTTOM Passed to llAttachToAvatar to attach task to bottom hud area -ATTACH_HUD_BOTTOM_LEFT Passed to llAttachToAvatar to attach task to bottom left hud area -ATTACH_HUD_BOTTOM_RIGHT Passed to llAttachToAvatar to attach task to bottom right hud area -ATTACH_HUD_CENTER_1 Passed to llAttachToAvatar to attach task to center 1 hud area -ATTACH_HUD_CENTER_2 Passed to llAttachToAvatar to attach task to center 2 hud area -ATTACH_HUD_TOP_CENTER Passed to llAttachToAvatar to attach task to top center hud area -ATTACH_HUD_TOP_LEFT Passed to llAttachToAvatar to attach task to top left hud area -ATTACH_HUD_TOP_RIGHT Passed to llAttachToAvatar to attach task to top right hud area -ATTACH_NECK Passed to llAttachToAvatar to attach task to neck -ATTACH_AVATAR_CENTER Passed to llAttachToAvatar to attach task to avatar center - -LAND_LEVEL Passed to llModifyLand to level terrain -LAND_RAISE Passed to llModifyLand to raise terrain -LAND_LOWER Passed to llModifyLand to lower terrain -LAND_SMOOTH Passed to llModifyLand to smooth terrain -LAND_NOISE Passed to llModifyLand to randomize terrain -LAND_REVERT Passed to llModifyLand to revert terrain toward original state -LAND_SMALL_BRUSH Passed to llModifyLand to modify small land areas -LAND_MEDIUM_BRUSH Passed to llModifyLand to modify medium land areas -LAND_LARGE_BRUSH Passed to llModifyLand to modify large land areas - -DATA_PAYINFO Passed to llRequestAgentData to get payment status of an agent -DATA_ONLINE Passed to llRequestAgentData to determine if agent is online -DATA_NAME Passed to llRequestAgentData to get full agent name -DATA_BORN Passed to llRequestAgentData to get born on date as a string -DATA_RATING Passed to llRequestAgentData to get a comma separated sting of integer ratings -DATA_SIM_POS Passed to llRequestSimulatorData to get a string (cast to vector) of a simulator's global position -DATA_SIM_STATUS Passed to llRequestSimulatorData to get the status of a simulator -DATA_SIM_RATING Passed to llRequestSimulatorData to get the rating of a simulator - -PAYMENT_INFO_ON_FILE Used with llRequestAgentData to tell if Agent is of "Payment Info On File" status -PAYMENT_INFO_USED Used with llRequestAgentData to tell if Agent is of "Payment Info Used" status - -ANIM_ON Enable texture animation -LOOP Loop when animating textures -REVERSE Animate in the reverse direction -PING_PONG Animate forward, then reverse -SMOOTH Textures slides, instead of stepping -ROTATE Rotates the texture, instead of using frames -SCALE Scales the texture, instead of using frames - -ALL_SIDES Passed to various texture and color library functions to modify all sides - -LINK_SET Passed to various link functions to modify all blocks in the object -LINK_ROOT Passed to various link functions to modify only the root block (no effect on single block objects) -LINK_ALL_OTHERS Passed to various link functions to modify all other blocks in the object -LINK_ALL_CHILDREN Passed to various link functions to modify all child blocks in the object -LINK_THIS Passed to various link functions to modify only the calling block - -CHANGED_INVENTORY Parameter of changed event handler used to indicate change to task's inventory -CHANGED_COLOR Parameter of changed event handler used to indicate change to task's color -CHANGED_SHAPE Parameter of changed event handler used to indicate change to task's shape parameters -CHANGED_SCALE Parameter of changed event handler used to indicate change to task's scale -CHANGED_TEXTURE Parameter of changed event handler used to indicate change to task's texture -CHANGED_LINK Parameter of changed event handler used to indicate change to task's link status -CHANGED_ALLOWED_DROP Parameter of changed event handler used to indicate a user dropped an inventory item:onto task that was allowed only by llAllowInventoryDrop function call -CHANGED_OWNER Parameter of changed event handler used to indicate change to task's owner ONLY when an object is sold as original or deeded to group -CHANGED_REGION Parameter of changed event handler used to indicate the region has changed -CHANGED_TELEPORT Parameter of changed event handler used to indicate teleport has completed -CHANGED_REGION_START Parameter of changed event handler used to indicate the region has been restarted -CHANGED_MEDIA Parameter of changed event handler used to indicate that media has changed on a face of the task - -TYPE_INTEGER Indicates that the list entry is holding an integer -TYPE_FLOAT Indicates that the list entry is holding an float -TYPE_STRING Indicates that the list entry is holding an string -TYPE_KEY Indicates that the list entry is holding an key -TYPE_VECTOR Indicates that the list entry is holding an vector -TYPE_ROTATION Indicates that the list entry is holding an rotation -TYPE_INVALID Indicates that this wasn't a valid list entry - - -REMOTE_DATA_CHANNEL Value of event_type in remote_event after successful llOpenRemoteDataChannel -REMOTE_DATA_REQUEST Value of event_type in remote_event if XML-RPC request is received -REMOTE_DATA_REPLY Value of event_type in remote_event if XML-RPC reply is received - - -PRIM_NAME Sets the prim's name -PRIM_DESC Sets the prim's description -PRIM_TYPE Followed by PRIM_TYPE_BOX, PRIM_TYPE_CYLINDER, PRIM_TYPE_PRISM, PRIM_TYPE_SPHERE, PRIM_TYPE_TORUS, PRIM_TYPE_TUBE, or PRIM_TYPE_SCULPT and their arguments -PRIM_MATERIAL Followed by PRIM_MATERIAL_STONE, PRIM_MATERIAL_METAL, PRIM_MATERIAL_GLASS, PRIM_MATERIAL_WOOD, PRIM_MATERIAL_FLESH, PRIM_MATERIAL_PLASTIC, or PRIM_MATERIAL_RUBBER -PRIM_PHYSICS Sets physics to TRUE or FALSE -PRIM_FLEXIBLE Followed by TRUE or FALSE, integer softness, float gravity, float friction, float wind, float tension, and vector force -PRIM_POINT_LIGHT Followed by TRUE or FALSE, vector color, float intensity, float radius, float falloff -PRIM_TEMP_ON_REZ Sets temporary on rez to TRUE or FALSE -PRIM_PHANTOM Sets phantom to TRUE or FALSE -PRIM_CAST_SHADOWS DEPRECATED. Takes 1 parameter, an integer, but has no effect when set and always returns 0 if used in llGetPrimitiveParams -PRIM_POSITION Sets primitive position to a vector position -PRIM_SIZE Sets primitive size to a vector size -PRIM_ROTATION Sets primitive rotation -PRIM_TEXT Used to get or set the object's floating text. -PRIM_TEXTURE Followed by an integer face, key id, vector repeats, vector offsets,:and float rotation in radians -PRIM_COLOR Followed by an integer face, vector color, and float alpha -PRIM_BUMP_SHINY Followed by an integer face, one of PRIM_SHINY_NONE, PRIM_SHINY_LOW,:PRIM_SHINY_MEDIUM, or PRIM_SHINY_HIGH,:and one of PRIM_BUMP_NONE, PRIM_BUMP_BRIGHT, PRIM_BUMP_DARK, etc -PRIM_FULLBRIGHT Followed by an integer face, and TRUE or FALSE -PRIM_TEXGEN Followed by an integer face, and one of PRIM_TEXGEN_DEFAULT or PRIM_TEXGEN_PLANAR -PRIM_GLOW Followed by an integer face, and a float from 0.0 to 1.0 specifying glow amount -PRIM_POS_LOCAL Sets the prim's local position -PRIM_ROT_LOCAL Sets the prim's local rotation -PRIM_OMEGA Makes the object spin at the specified axis and rate -PRIM_LINK_TARGET Used to get or set multiple links with a single PrimParameters call. -PRIM_SLICE Get and set the 'slice' parameter of all shapes. Takes a vector parameter of the form - -PRIM_TYPE_BOX Followed by integer hole shape, vector cut, float hollow, vector twist,:vector top size, and vector top shear -PRIM_TYPE_CYLINDER Followed by integer hole shape, vector cut, float hollow, vector twist,:vector top size, and vector top shear -PRIM_TYPE_PRISM Followed by integer hole shape, vector cut, float hollow, vector twist,:vector top size, and vector top shear -PRIM_TYPE_SPHERE Followed by integer hole shape, vector cut, float hollow, vector twist,:and vector dimple -PRIM_TYPE_TORUS Followed by integer hole shape, vector cut, float hollow, vector twist,:vector hole size, vector top shear, vector advanced cut, vector taper,:float revolutions, float radius offset, and float skew -PRIM_TYPE_TUBE Followed by integer hole shape, vector cut, float hollow, vector twist,:vector hole size, vector top shear, vector advanced cut, vector taper,:float revolutions, float radius offset, and float skew -PRIM_TYPE_RING Followed by integer hole shape, vector cut, float hollow, vector twist,:vector hole size, vector top shear, vector advanced cut, vector taper,:float revolutions, float radius offset, and float skew -PRIM_TYPE_SCULPT Followed by a key/string texture uuid, and one of PRIM_SCULPT_TYPE_SPHERE, PRIM_SCULPT_TYPE_TORUS, PRIM_SCULPT_TYPE_PLANE, or PRIM_SCULPT_TYPE_CYLINDER - -PRIM_HOLE_DEFAULT Sets hole type to match the prim type -PRIM_HOLE_SQUARE Sets hole type to square -PRIM_HOLE_CIRCLE Sets hole type to circle -PRIM_HOLE_TRIANGLE Sets hole type to triangle - -PRIM_MATERIAL_STONE Sets material to stone -PRIM_MATERIAL_METAL Sets material to metal -PRIM_MATERIAL_GLASS Sets material to glass -PRIM_MATERIAL_WOOD Sets material to wood -PRIM_MATERIAL_FLESH Sets material to flesh -PRIM_MATERIAL_PLASTIC Sets material to plastic -PRIM_MATERIAL_RUBBER Sets material to rubber -PRIM_MATERIAL_LIGHT Sets material to light - -PRIM_SHINY_NONE No shininess -PRIM_SHINY_LOW Low shininess -PRIM_SHINY_MEDIUM Medium shininess -PRIM_SHINY_HIGH High shininess - -PRIM_BUMP_NONE No bump map -PRIM_BUMP_BRIGHT Generate bump map from highlights -PRIM_BUMP_DARK Generate bump map from lowlights -PRIM_BUMP_WOOD Wood bump map -PRIM_BUMP_BARK Bark bump map -PRIM_BUMP_BRICKS Brick bump map -PRIM_BUMP_CHECKER Checker bump map -PRIM_BUMP_CONCRETE Concrete bump map -PRIM_BUMP_TILE Tile bump map -PRIM_BUMP_STONE Stone bump map -PRIM_BUMP_DISKS Disk bump map -PRIM_BUMP_GRAVEL Gravel bump map -PRIM_BUMP_BLOBS Blob bump map -PRIM_BUMP_SIDING Siding bump map -PRIM_BUMP_LARGETILE Large tile bump map -PRIM_BUMP_STUCCO Stucco bump map -PRIM_BUMP_SUCTION Suction cup bump map -PRIM_BUMP_WEAVE Weave bump map - -PRIM_TEXGEN_DEFAULT Default texture mapping -PRIM_TEXGEN_PLANAR Planar texture mapping - -PRIM_SCULPT_TYPE_SPHERE Stitch edges in a sphere-like way -PRIM_SCULPT_TYPE_TORUS Stitch edges in a torus-like way -PRIM_SCULPT_TYPE_PLANE Do not stitch edges -PRIM_SCULPT_TYPE_CYLINDER Stitch edges in a cylinder-like way -PRIM_SCULPT_TYPE_MASK Mask used to determine stitching type -PRIM_SCULPT_FLAG_INVERT Flag to specify that the surface normals should be inverted -PRIM_SCULPT_FLAG_MIRROR Flag to specify that the prim should be reflected along X axis - -PRIM_PHYSICS_SHAPE_TYPE For primitive physics shape type. Followed with either PRIM_PHYSICS_SHAPE_PRIM, PRIM_PHYSICS_SHAPE_NONE or PRIM_PHYSICS_SHAPE_CONVEX. -PRIM_PHYSICS_SHAPE_PRIM Use the normal prim shape for physics (this is the default for all non-mesh objects) -PRIM_PHYSICS_SHAPE_NONE Use the convex hull of the prim shape for physics (this is the default for mesh objects) -PRIM_PHYSICS_SHAPE_CONVEX Ignore this prim in the physics shape. This cannot be applied to the root prim. - -MASK_BASE Base permissions -MASK_OWNER Owner permissions -MASK_GROUP Group permissions -MASK_EVERYONE Everyone permissions -MASK_NEXT Next owner permissions - -PERM_TRANSFER Transfer permission -PERM_MODIFY Modify permission -PERM_COPY Copy permission -PERM_MOVE Move permission -PERM_ALL Move/Modify/Copy/Transfer permissions - -PARCEL_MEDIA_COMMAND_STOP Stop media stream -PARCEL_MEDIA_COMMAND_PAUSE Pause media stream -PARCEL_MEDIA_COMMAND_PLAY Play media stream -PARCEL_MEDIA_COMMAND_LOOP Loop media stream -PARCEL_MEDIA_COMMAND_LOOP_SET Used to get or set the parcel's media loop duration -PARCEL_MEDIA_COMMAND_TEXTURE Get or set the parcel's media texture -PARCEL_MEDIA_COMMAND_URL Get or set the parcel's media url -PARCEL_MEDIA_COMMAND_TYPE Get or set the parcel's media mimetype -PARCEL_MEDIA_COMMAND_DESC Get or set the parcel's media description -PARCEL_MEDIA_COMMAND_TIME Set media stream to specific time -PARCEL_MEDIA_COMMAND_SIZE Get or set the parcel's media pixel resolution -PARCEL_MEDIA_COMMAND_AGENT Allows media stream commands to apply to only one agent -PARCEL_MEDIA_COMMAND_UNLOAD Unloads the media stream -PARCEL_MEDIA_COMMAND_AUTO_ALIGN Auto aligns the media stream to the texture size. May cause a performance hit and loss of some visual quality - -PAY_HIDE Used with llSetPayPrice to hide a button -PAY_DEFAULT Used with llSetPayPrice to use the default price for a button - -LIST_STAT_MAX Used with llListStatistics to find the largest number in a list -LIST_STAT_MIN Used with llListStatistics to find the smallest number in a list -LIST_STAT_MEAN Used with llListStatistics to find the mean of the numbers in a list -LIST_STAT_MEDIAN Used with llListStatistics to find the median of the numbers in a list -LIST_STAT_STD_DEV Used with llListStatistics to find the standard deviation of the numbers in a list -LIST_STAT_SUM Used with llListStatistics to find the sum of the numbers in a list -LIST_STAT_SUM_SQUARES Used with llListStatistics to find the sum of the squares of the numbers in a list -LIST_STAT_NUM_COUNT Used with llListStatistics to find how many numbers are in a list -LIST_STAT_GEOMETRIC_MEAN Used with llListStatistics to find the geometric mean of the numbers in a list (all numbers must be > 0) -LIST_STAT_RANGE Used with llListStatistics to find the range of the numbers in a list - -PARCEL_FLAG_ALLOW_FLY Used with llGetParcelFlags to find if a parcel allows flying -PARCEL_FLAG_ALLOW_GROUP_SCRIPTS Used with llGetParcelFlags to find if a parcel allows group scripts -PARCEL_FLAG_ALLOW_SCRIPTS Used with llGetParcelFlags to find if a parcel allows outside scripts -PARCEL_FLAG_ALLOW_LANDMARK Used with llGetParcelFlags to find if a parcel allows landmarks to be created -PARCEL_FLAG_ALLOW_TERRAFORM Used with llGetParcelFlags to find if a parcel allows anyone to terraform the land -PARCEL_FLAG_ALLOW_DAMAGE Used with llGetParcelFlags to find if a parcel allows damage -PARCEL_FLAG_ALLOW_CREATE_OBJECTS Used with llGetParcelFlags to find if a parcel allows anyone to create objects -PARCEL_FLAG_ALLOW_CREATE_GROUP_OBJECTS Used with llGetParcelFlags to find if a parcel allows group members or objects to create objects -PARCEL_FLAG_USE_ACCESS_GROUP Used with llGetParcelFlags to find if a parcel limits access to a group -PARCEL_FLAG_USE_ACCESS_LIST Used with llGetParcelFlags to find if a parcel limits access to a list of residents -PARCEL_FLAG_USE_BAN_LIST Used with llGetParcelFlags to find if a parcel uses a ban list -PARCEL_FLAG_USE_LAND_PASS_LIST Used with llGetParcelFlags to find if a parcel allows passes to be purchased -PARCEL_FLAG_LOCAL_SOUND_ONLY Used with llGetParcelFlags to find if a parcel restricts spacialized sound to the parcel -PARCEL_FLAG_RESTRICT_PUSHOBJECT Used with llGetParcelFlags to find if a parcel restricts llPushObject() calls -PARCEL_FLAG_ALLOW_ALL_OBJECT_ENTRY Used with llGetParcelFlags to find if a parcel allows all objects to enter -PARCEL_FLAG_ALLOW_GROUP_OBJECT_ENTRY Used with llGetParcelFlags to find if a parcel only allows group (and owner) objects to enter - -REGION_FLAG_ALLOW_DAMAGE Used with llGetRegionFlags to find if a region is entirely damage enabled -REGION_FLAG_FIXED_SUN Used with llGetRegionFlags to find if a region has a fixed sun position -REGION_FLAG_BLOCK_TERRAFORM Used with llGetRegionFlags to find if a region terraforming disabled -REGION_FLAG_SANDBOX Used with llGetRegionFlags to find if a region is a sandbox -REGION_FLAG_DISABLE_COLLISIONS Used with llGetRegionFlags to find if a region has disabled collisions -REGION_FLAG_DISABLE_PHYSICS Used with llGetRegionFlags to find if a region has disabled physics -REGION_FLAG_BLOCK_FLY Used with llGetRegionFlags to find if a region blocks flying -REGION_FLAG_ALLOW_DIRECT_TELEPORT Used with llGetRegionFlags to find if a region allows direct teleports -REGION_FLAG_RESTRICT_PUSHOBJECT Used with llGetRegionFlags to find if a region restricts llPushObject() calls - -HTTP_METHOD Used with llHTTPRequest to specify the method, "GET", "POST", "PUT", or "DELETE" -HTTP_MIMETYPE Used with llHTTPRequest to specify the MIME type, defaults to "text/plain" -HTTP_BODY_MAXLENGTH Used with llHTTPRequest to specify the maximum response body to return -HTTP_VERIFY_CERT Used with llHTTPRequest to specify SSL certificate verification -HTTP_BODY_TRUNCATED Used with http_response to indicate truncation point in bytes -HTTP_VERBOSE_THROTTLE Used with llHTTPRequest to shout error messages to DEBUG_CHANNEL if the outgoing request rate exceeds the server limit. -HTTP_BODY_MAXLENGTH Used with llHTTPRequest to specify the maximum body size for the date returned from the request. Mono scripts can request from 1byte to 16k, non-mono scripts can request from 1byte to 4k. The default is 2k. - -PARCEL_COUNT_TOTAL Used with llGetParcelPrimCount to get the total number of prims on the parcel -PARCEL_COUNT_OWNER Used with llGetParcelPrimCount to get the number of prims on the parcel owned by the owner -PARCEL_COUNT_GROUP Used with llGetParcelPrimCount to get the number of prims on the parcel owned by the group -PARCEL_COUNT_OTHER Used with llGetParcelPrimCount to get the number of prims on the parcel owned by others -PARCEL_COUNT_SELECTED Used with llGetParcelPrimCount to get the number of prims on the parcel currently selected or sat upon -PARCEL_COUNT_TEMP Used with llGetParcelPrimCount to get the number of prims on the parcel that are temp on rez - -PARCEL_DETAILS_NAME Used with llGetParcelDetails to get the parcel name -PARCEL_DETAILS_DESC Used with llGetParcelDetails to get the parcel description -PARCEL_DETAILS_OWNER Used with llGetParcelDetails to get the parcel owner id -PARCEL_DETAILS_GROUP Used with llGetParcelDetails to get the parcel group id -PARCEL_DETAILS_AREA Used with llGetParcelDetails to get the parcel area in square meters -PARCEL_DETAILS_ID Used with llGetParcelDetails to get the parcel id -PARCEL_DETAILS_SEE_AVATARS Used with llGetParcelDetails to get the avatars visibility setting - -STRING_TRIM_HEAD Used with llStringTrim to trim leading spaces from a string -STRING_TRIM_TAIL Used with llStringTrim to trim trailing spaces from a string -STRING_TRIM Used with llStringTrim to trim both leading and trailing spaces from a string +VEHICLE_TYPE_NONE Used with llSetVehicleType to turn off vehicle support +VEHICLE_TYPE_SLED Used with llSetVehicleType to make a simple vehicle that bumps along the ground, and likes to move along its local x-axis +VEHICLE_TYPE_CAR Used with llSetVehicleType to make a vehicle that bounces along the ground but needs the motors to be driven from external controls or timer events +VEHICLE_TYPE_BOAT Used with llSetVehicleType to make a vehicle that hovers over water with lots of friction and some angular deflection +VEHICLE_TYPE_AIRPLANE Used with llSetVehicleType to make a vehicle that uses linear deflection for lift, and banking to turn, but doesn't hover +VEHICLE_TYPE_BALLOON Used with llSetVehicleType to make a vehicle that uses hover, and friction, but doesn't use deflection + +VEHICLE_REFERENCE_FRAME Rotation of vehicle axes relative to local frame + +VEHICLE_LINEAR_FRICTION_TIMESCALE A vector of timescales for exponential decay of linear velocity along the three vehicle axes +VEHICLE_ANGULAR_FRICTION_TIMESCALE A vector of timescales for exponential decay of angular velocity about the three vehicle axes +VEHICLE_LINEAR_MOTOR_DIRECTION The linear velocity that the vehicle will try to achieve +VEHICLE_LINEAR_MOTOR_OFFSET An offset from the center of mass of the vehicle where the linear motor is applied +VEHICLE_ANGULAR_MOTOR_DIRECTION The angular velocity that the vehicle will try to achieve + +VEHICLE_HOVER_HEIGHT The height the vehicle will try to hover +VEHICLE_HOVER_EFFICIENCY A slider between 0 (bouncy) and 1 (critically damped) hover behavior +VEHICLE_HOVER_TIMESCALE The period of time for the vehicle to achieve its hover height +VEHICLE_BUOYANCY A slider between 0 (no anti-gravity) and 1 (full anti-gravity) + +VEHICLE_LINEAR_DEFLECTION_EFFICIENCY A slider between 0 (no deflection) and 1 (maximum strength) +VEHICLE_LINEAR_DEFLECTION_TIMESCALE The exponential timescale for the vehicle to redirect its velocity to be along its x-axis + +VEHICLE_LINEAR_MOTOR_TIMESCALE The exponential timescale for the vehicle to achive its full linear motor velocity +VEHICLE_LINEAR_MOTOR_DECAY_TIMESCALE The exponential timescale for the linear motor's effectiveness to decay toward zero + +VEHICLE_ANGULAR_DEFLECTION_EFFICIENCY A slider between 0 (no deflection) and 1 (maximum strength) +VEHICLE_ANGULAR_DEFLECTION_TIMESCALE The exponential timescale for the vehicle to achieve full angular deflection + +VEHICLE_ANGULAR_MOTOR_TIMESCALE The exponential timescale for the vehicle to achive its full angular motor velocity +VEHICLE_ANGULAR_MOTOR_DECAY_TIMESCALE The exponential timescale for the angular motor's effectiveness to decay toward zero + +VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY A slider between 0 (bouncy) and 1 (critically damped) attraction of vehicle z-axis to world z-axis (vertical) +VEHICLE_VERTICAL_ATTRACTION_TIMESCALE The exponential timescale for the vehicle to align its z-axis to the world z-axis (vertical) + +VEHICLE_BANKING_EFFICIENCY A slider between -1 (leans out of turns), 0 (no banking), and +1 (leans into turns) +VEHICLE_BANKING_MIX A slider between 0 (static banking) and 1 (dynamic banking) +VEHICLE_BANKING_TIMESCALE The exponential timescale for the banking behavior to take full effect + +VEHICLE_FLAG_NO_DEFLECTION_UP Prevents linear deflection along world-z axis +VEHICLE_FLAG_LIMIT_ROLL_ONLY Removes vertical attraction for changes in vehicle pitch +VEHICLE_FLAG_HOVER_WATER_ONLY Hover only pays attention to water level +VEHICLE_FLAG_HOVER_TERRAIN_ONLY Hover only pays attention to terrain height +VEHICLE_FLAG_HOVER_GLOBAL_HEIGHT Hover only pays attention to global height +VEHICLE_FLAG_HOVER_UP_ONLY Hover only pushes up +VEHICLE_FLAG_LIMIT_MOTOR_UP Prevents ground vehicles from motoring into the sky +VEHICLE_FLAG_MOUSELOOK_STEER Makes vehicle try to turn toward mouselook direction +VEHICLE_FLAG_MOUSELOOK_BANK Makes vehicle try to turn toward mouselook direction assuming banking is enabled +VEHICLE_FLAG_CAMERA_DECOUPLED Causes the camera look-at axis to NOT move when the vehicle rotates + +CAMERA_PITCH (-45 to 80) (Adjusts the angular amount that the camera aims straight ahead vs. straight down, maintaining the same distance. Analogous to 'incidence'.") +CAMERA_FOCUS_OFFSET (-10 to 10) A vector that adjusts the position of the camera focus position relative to the subject +CAMERA_POSITION_LAG (0.0 to 3.0) How much the camera lags as it tries to move towards its 'ideal' position +CAMERA_FOCUS_LAG (0.0 to 3.0) How much the camera lags as it tries to aim towards the subject +CAMERA_DISTANCE (0.5 to 10) Sets how far away the camera wants to be from its subject +CAMERA_BEHINDNESS_ANGLE (0 to 180) Sets the angle in degrees within which the camera is not constrained by changes in subject rotation +CAMERA_BEHINDNESS_LAG (0.0 to 3.0) Sets how strongly the camera is forced to stay behind the target if outside of behindness angle +CAMERA_POSITION_THRESHOLD (0.0 to 4.0) Sets the radius of a sphere around the camera's ideal position within which it is not affected by subject motion +CAMERA_FOCUS_THRESHOLD (0.0 to 4.0) Sets the radius of a sphere around the camera's subject position within which its focus is not affected by subject motion +CAMERA_ACTIVE (0 or 1) Turns on or off scripted control of the camera +CAMERA_POSITION Sets the position of the camera +CAMERA_FOCUS Sets the focus (target position) of the camera +CAMERA_POSITION_LOCKED (0 or 1) Locks the camera position so it will not move +CAMERA_FOCUS_LOCKED (0 or 1) Locks the camera focus so it will not move + +INVENTORY_TEXTURE Passed to task inventory library functions to reference textures +INVENTORY_SOUND Passed to task inventory library functions to reference sounds +INVENTORY_OBJECT Passed to task inventory library functions to reference objects +INVENTORY_SCRIPT Passed to task inventory library functions to reference scripts +INVENTORY_LANDMARK Passed to task inventory library functions to reference landmarks +INVENTORY_CLOTHING Passed to task inventory library functions to reference clothing +INVENTORY_NOTECARD Passed to task inventory library functions to reference notecards +INVENTORY_BODYPART Passed to task inventory library functions to reference body parts +INVENTORY_ANIMATION Passed to task inventory library functions to reference animations +INVENTORY_GESTURE Passed to task inventory library functions to reference gestures +INVENTORY_ALL Passed to task inventory library functions to reference all inventory items +INVENTORY_NONE Returned by llGetInventoryType when no item is found + +ATTACH_CHEST Passed to llAttachToAvatar to attach task to chest +ATTACH_HEAD Passed to llAttachToAvatar to attach task to head +ATTACH_LSHOULDER Passed to llAttachToAvatar to attach task to left shoulder +ATTACH_RSHOULDER Passed to llAttachToAvatar to attach task to right shoulder +ATTACH_LHAND Passed to llAttachToAvatar to attach task to left hand +ATTACH_RHAND Passed to llAttachToAvatar to attach task to right hand +ATTACH_LFOOT Passed to llAttachToAvatar to attach task to left foot +ATTACH_RFOOT Passed to llAttachToAvatar to attach task to right foot +ATTACH_BACK Passed to llAttachToAvatar to attach task to back +ATTACH_PELVIS Passed to llAttachToAvatar to attach task to pelvis +ATTACH_MOUTH Passed to llAttachToAvatar to attach task to mouth +ATTACH_CHIN Passed to llAttachToAvatar to attach task to chin +ATTACH_LEAR Passed to llAttachToAvatar to attach task to left ear +ATTACH_REAR Passed to llAttachToAvatar to attach task to right ear +ATTACH_LEYE Passed to llAttachToAvatar to attach task to left eye +ATTACH_REYE Passed to llAttachToAvatar to attach task to right eye +ATTACH_NOSE Passed to llAttachToAvatar to attach task to nose +ATTACH_RUARM Passed to llAttachToAvatar to attach task to right upper arm +ATTACH_RLARM Passed to llAttachToAvatar to attach task to right lower arm +ATTACH_LUARM Passed to llAttachToAvatar to attach task to left upper arm +ATTACH_LLARM Passed to llAttachToAvatar to attach task to left lower arm +ATTACH_RHIP Passed to llAttachToAvatar to attach task to right hip +ATTACH_RULEG Passed to llAttachToAvatar to attach task to right upper leg +ATTACH_RLLEG Passed to llAttachToAvatar to attach task to right lower leg +ATTACH_LHIP Passed to llAttachToAvatar to attach task to left hip +ATTACH_LULEG Passed to llAttachToAvatar to attach task to left upper leg +ATTACH_LLLEG Passed to llAttachToAvatar to attach task to left lower leg +ATTACH_BELLY Passed to llAttachToAvatar to attach task to belly +ATTACH_LEFT_PEC Passed to llAttachToAvatar to attach task to left pectoral +ATTACH_RIGHT_PEC Passed to llAttachToAvatar to attach task to right pectoral +ATTACH_HUD_BOTTOM Passed to llAttachToAvatar to attach task to bottom hud area +ATTACH_HUD_BOTTOM_LEFT Passed to llAttachToAvatar to attach task to bottom left hud area +ATTACH_HUD_BOTTOM_RIGHT Passed to llAttachToAvatar to attach task to bottom right hud area +ATTACH_HUD_CENTER_1 Passed to llAttachToAvatar to attach task to center 1 hud area +ATTACH_HUD_CENTER_2 Passed to llAttachToAvatar to attach task to center 2 hud area +ATTACH_HUD_TOP_CENTER Passed to llAttachToAvatar to attach task to top center hud area +ATTACH_HUD_TOP_LEFT Passed to llAttachToAvatar to attach task to top left hud area +ATTACH_HUD_TOP_RIGHT Passed to llAttachToAvatar to attach task to top right hud area +ATTACH_NECK Passed to llAttachToAvatar to attach task to neck +ATTACH_AVATAR_CENTER Passed to llAttachToAvatar to attach task to avatar center + +LAND_LEVEL Passed to llModifyLand to level terrain +LAND_RAISE Passed to llModifyLand to raise terrain +LAND_LOWER Passed to llModifyLand to lower terrain +LAND_SMOOTH Passed to llModifyLand to smooth terrain +LAND_NOISE Passed to llModifyLand to randomize terrain +LAND_REVERT Passed to llModifyLand to revert terrain toward original state +LAND_SMALL_BRUSH Passed to llModifyLand to modify small land areas +LAND_MEDIUM_BRUSH Passed to llModifyLand to modify medium land areas +LAND_LARGE_BRUSH Passed to llModifyLand to modify large land areas + +DATA_PAYINFO Passed to llRequestAgentData to get payment status of an agent +DATA_ONLINE Passed to llRequestAgentData to determine if agent is online +DATA_NAME Passed to llRequestAgentData to get full agent name +DATA_BORN Passed to llRequestAgentData to get born on date as a string +DATA_RATING Passed to llRequestAgentData to get a comma separated sting of integer ratings +DATA_SIM_POS Passed to llRequestSimulatorData to get a string (cast to vector) of a simulator's global position +DATA_SIM_STATUS Passed to llRequestSimulatorData to get the status of a simulator +DATA_SIM_RATING Passed to llRequestSimulatorData to get the rating of a simulator + +PAYMENT_INFO_ON_FILE Used with llRequestAgentData to tell if Agent is of "Payment Info On File" status +PAYMENT_INFO_USED Used with llRequestAgentData to tell if Agent is of "Payment Info Used" status + +ANIM_ON Enable texture animation +LOOP Loop when animating textures +REVERSE Animate in the reverse direction +PING_PONG Animate forward, then reverse +SMOOTH Textures slides, instead of stepping +ROTATE Rotates the texture, instead of using frames +SCALE Scales the texture, instead of using frames + +ALL_SIDES Passed to various texture and color library functions to modify all sides + +LINK_SET Passed to various link functions to modify all blocks in the object +LINK_ROOT Passed to various link functions to modify only the root block (no effect on single block objects) +LINK_ALL_OTHERS Passed to various link functions to modify all other blocks in the object +LINK_ALL_CHILDREN Passed to various link functions to modify all child blocks in the object +LINK_THIS Passed to various link functions to modify only the calling block + +CHANGED_INVENTORY Parameter of changed event handler used to indicate change to task's inventory +CHANGED_COLOR Parameter of changed event handler used to indicate change to task's color +CHANGED_SHAPE Parameter of changed event handler used to indicate change to task's shape parameters +CHANGED_SCALE Parameter of changed event handler used to indicate change to task's scale +CHANGED_TEXTURE Parameter of changed event handler used to indicate change to task's texture +CHANGED_LINK Parameter of changed event handler used to indicate change to task's link status +CHANGED_ALLOWED_DROP Parameter of changed event handler used to indicate a user dropped an inventory item:onto task that was allowed only by llAllowInventoryDrop function call +CHANGED_OWNER Parameter of changed event handler used to indicate change to task's owner ONLY when an object is sold as original or deeded to group +CHANGED_REGION Parameter of changed event handler used to indicate the region has changed +CHANGED_TELEPORT Parameter of changed event handler used to indicate teleport has completed +CHANGED_REGION_START Parameter of changed event handler used to indicate the region has been restarted +CHANGED_MEDIA Parameter of changed event handler used to indicate that media has changed on a face of the task + +TYPE_INTEGER Indicates that the list entry is holding an integer +TYPE_FLOAT Indicates that the list entry is holding an float +TYPE_STRING Indicates that the list entry is holding an string +TYPE_KEY Indicates that the list entry is holding an key +TYPE_VECTOR Indicates that the list entry is holding an vector +TYPE_ROTATION Indicates that the list entry is holding an rotation +TYPE_INVALID Indicates that this wasn't a valid list entry + + +REMOTE_DATA_CHANNEL Value of event_type in remote_event after successful llOpenRemoteDataChannel +REMOTE_DATA_REQUEST Value of event_type in remote_event if XML-RPC request is received +REMOTE_DATA_REPLY Value of event_type in remote_event if XML-RPC reply is received + + +PRIM_TYPE Followed by PRIM_TYPE_BOX, PRIM_TYPE_CYLINDER, PRIM_TYPE_PRISM, PRIM_TYPE_SPHERE, PRIM_TYPE_TORUS, PRIM_TYPE_TUBE, or PRIM_TYPE_SCULPT and their arguments +PRIM_MATERIAL Followed by PRIM_MATERIAL_STONE, PRIM_MATERIAL_METAL, PRIM_MATERIAL_GLASS, PRIM_MATERIAL_WOOD, PRIM_MATERIAL_FLESH, PRIM_MATERIAL_PLASTIC, or PRIM_MATERIAL_RUBBER +PRIM_PHYSICS Sets physics to TRUE or FALSE +PRIM_FLEXIBLE Followed by TRUE or FALSE, integer softness, float gravity, float friction, float wind, float tension, and vector force +PRIM_POINT_LIGHT Followed by TRUE or FALSE, vector color, float intensity, float radius, float falloff +PRIM_TEMP_ON_REZ Sets temporary on rez to TRUE or FALSE +PRIM_PHANTOM Sets phantom to TRUE or FALSE +PRIM_CAST_SHADOWS DEPRECATED. Takes 1 parameter, an integer, but has no effect when set and always returns 0 if used in llGetPrimitiveParams +PRIM_POSITION Sets primitive position to a vector position +PRIM_SIZE Sets primitive size to a vector size +PRIM_ROTATION Sets primitive rotation +PRIM_TEXTURE Followed by an integer face, key id, vector repeats, vector offsets,:and float rotation in radians +PRIM_COLOR Followed by an integer face, vector color, and float alpha +PRIM_BUMP_SHINY Followed by an integer face, one of PRIM_SHINY_NONE, PRIM_SHINY_LOW,:PRIM_SHINY_MEDIUM, or PRIM_SHINY_HIGH,:and one of PRIM_BUMP_NONE, PRIM_BUMP_BRIGHT, PRIM_BUMP_DARK, etc +PRIM_FULLBRIGHT Followed by an integer face, and TRUE or FALSE +PRIM_TEXGEN Followed by an integer face, and one of PRIM_TEXGEN_DEFAULT or PRIM_TEXGEN_PLANAR +PRIM_GLOW Followed by an integer face, and a float from 0.0 to 1.0 specifying glow amount +PRIM_TEXT Used to get or set the object's floating text. +PRIM_NAME Sets the prim's name +PRIM_DESC Sets the prim's description +PRIM_ROT_LOCAL Sets the prim's local rotation +PRIM_PHYSICS_SHAPE_TYPE For primitive physics shape type. Followed with either PRIM_PHYSICS_SHAPE_PRIM, PRIM_PHYSICS_SHAPE_NONE or PRIM_PHYSICS_SHAPE_CONVEX. +PRIM_OMEGA Makes the object spin at the specified axis and rate +PRIM_POS_LOCAL Sets the prim's local position +PRIM_LINK_TARGET Used to get or set multiple links with a single PrimParameters call. +PRIM_SLICE Get and set the 'slice' parameter of all shapes. Takes a vector parameter of the form + +PRIM_PHYSICS_SHAPE_PRIM Use the normal prim shape for physics (this is the default for all non-mesh objects) +PRIM_PHYSICS_SHAPE_NONE Use the convex hull of the prim shape for physics (this is the default for mesh objects) +PRIM_PHYSICS_SHAPE_CONVEX Ignore this prim in the physics shape. This cannot be applied to the root prim. + +PRIM_TYPE_BOX Followed by integer hole shape, vector cut, float hollow, vector twist,:vector top size, and vector top shear +PRIM_TYPE_CYLINDER Followed by integer hole shape, vector cut, float hollow, vector twist,:vector top size, and vector top shear +PRIM_TYPE_PRISM Followed by integer hole shape, vector cut, float hollow, vector twist,:vector top size, and vector top shear +PRIM_TYPE_SPHERE Followed by integer hole shape, vector cut, float hollow, vector twist,:and vector dimple +PRIM_TYPE_TORUS Followed by integer hole shape, vector cut, float hollow, vector twist,:vector hole size, vector top shear, vector advanced cut, vector taper,:float revolutions, float radius offset, and float skew +PRIM_TYPE_TUBE Followed by integer hole shape, vector cut, float hollow, vector twist,:vector hole size, vector top shear, vector advanced cut, vector taper,:float revolutions, float radius offset, and float skew +PRIM_TYPE_RING Followed by integer hole shape, vector cut, float hollow, vector twist,:vector hole size, vector top shear, vector advanced cut, vector taper,:float revolutions, float radius offset, and float skew +PRIM_TYPE_SCULPT Followed by a key/string texture uuid, and one of PRIM_SCULPT_TYPE_SPHERE, PRIM_SCULPT_TYPE_TORUS, PRIM_SCULPT_TYPE_PLANE, or PRIM_SCULPT_TYPE_CYLINDER + +PRIM_HOLE_DEFAULT Sets hole type to match the prim type +PRIM_HOLE_SQUARE Sets hole type to square +PRIM_HOLE_CIRCLE Sets hole type to circle +PRIM_HOLE_TRIANGLE Sets hole type to triangle + +PRIM_MATERIAL_STONE Sets material to stone +PRIM_MATERIAL_METAL Sets material to metal +PRIM_MATERIAL_GLASS Sets material to glass +PRIM_MATERIAL_WOOD Sets material to wood +PRIM_MATERIAL_FLESH Sets material to flesh +PRIM_MATERIAL_PLASTIC Sets material to plastic +PRIM_MATERIAL_RUBBER Sets material to rubber +PRIM_MATERIAL_LIGHT Sets material to light + +PRIM_SHINY_NONE No shininess +PRIM_SHINY_LOW Low shininess +PRIM_SHINY_MEDIUM Medium shininess +PRIM_SHINY_HIGH High shininess + + +PRIM_BUMP_NONE No bump map +PRIM_BUMP_BRIGHT Generate bump map from highlights +PRIM_BUMP_DARK Generate bump map from lowlights +PRIM_BUMP_WOOD Wood bump map +PRIM_BUMP_BARK Bark bump map +PRIM_BUMP_BRICKS Brick bump map +PRIM_BUMP_CHECKER Checker bump map +PRIM_BUMP_CONCRETE Concrete bump map +PRIM_BUMP_TILE Tile bump map +PRIM_BUMP_STONE Stone bump map +PRIM_BUMP_DISKS Disk bump map +PRIM_BUMP_GRAVEL Gravel bump map +PRIM_BUMP_BLOBS Blob bump map +PRIM_BUMP_SIDING Siding bump map +PRIM_BUMP_LARGETILE Large tile bump map +PRIM_BUMP_STUCCO Stucco bump map +PRIM_BUMP_SUCTION Suction cup bump map +PRIM_BUMP_WEAVE Weave bump map + +PRIM_TEXGEN_DEFAULT Default texture mapping +PRIM_TEXGEN_PLANAR Planar texture mapping + +PRIM_SCULPT_TYPE_SPHERE Stitch edges in a sphere-like way +PRIM_SCULPT_TYPE_TORUS Stitch edges in a torus-like way +PRIM_SCULPT_TYPE_PLANE Do not stitch edges +PRIM_SCULPT_TYPE_CYLINDER Stitch edges in a cylinder-like way +PRIM_SCULPT_TYPE_MASK Mask used to determine stitching type +PRIM_SCULPT_FLAG_INVERT Flag to specify that the surface normals should be inverted +PRIM_SCULPT_FLAG_MIRROR Flag to specify that the prim should be reflected along X axis + +PRIM_SPECULAR Used to get or set the specular map texture settings of a prim's face. +PRIM_NORMAL Used to get or set the normal map texture settings of a prim's face. + +PRIM_ALPHA_MODE Used to specify how the alpha channel of the diffuse texture should affect rendering of a prims face. +PRIM_ALPHA_MODE_NONE Render the diffuse texture as though the alpha channel were nonexistent. +PRIM_ALPHA_MODE_BLEND Render the diffuse texture with alpha-blending. +PRIM_ALPHA_MODE_MASK Render the prim face in alpha-masked mode. +PRIM_ALPHA_MODE_EMISSIVE Render the prim face in emissivity mode. + +MASK_BASE Base permissions +MASK_OWNER Owner permissions +MASK_GROUP Group permissions +MASK_EVERYONE Everyone permissions +MASK_NEXT Next owner permissions + +PERM_TRANSFER Transfer permission +PERM_MODIFY Modify permission +PERM_COPY Copy permission +PERM_MOVE Move permission +PERM_ALL Move/Modify/Copy/Transfer permissions + +PARCEL_MEDIA_COMMAND_STOP Stop media stream +PARCEL_MEDIA_COMMAND_PAUSE Pause media stream +PARCEL_MEDIA_COMMAND_PLAY Play media stream +PARCEL_MEDIA_COMMAND_LOOP Loop media stream +PARCEL_MEDIA_COMMAND_LOOP_SET Used to get or set the parcel's media loop duration. +PARCEL_MEDIA_COMMAND_TEXTURE Get or set the parcel's media texture +PARCEL_MEDIA_COMMAND_URL Get or set the parcel's media url +PARCEL_MEDIA_COMMAND_TYPE Get or set the parcel's media mimetype +PARCEL_MEDIA_COMMAND_DESC Get or set the parcel's media description +PARCEL_MEDIA_COMMAND_TIME Set media stream to specific time +PARCEL_MEDIA_COMMAND_SIZE Get or set the parcel's media pixel resolution +PARCEL_MEDIA_COMMAND_AGENT Allows media stream commands to apply to only one agent +PARCEL_MEDIA_COMMAND_UNLOAD Unloads the media stream +PARCEL_MEDIA_COMMAND_AUTO_ALIGN Auto aligns the media stream to the texture size. May cause a performance hit and loss of some visual quality + +PAY_HIDE Used with llSetPayPrice to hide a button +PAY_DEFAULT Used with llSetPayPrice to use the default price for a button + +LIST_STAT_MAX Used with llListStatistics to find the largest number in a list +LIST_STAT_MIN Used with llListStatistics to find the smallest number in a list +LIST_STAT_MEAN Used with llListStatistics to find the mean of the numbers in a list +LIST_STAT_MEDIAN Used with llListStatistics to find the median of the numbers in a list +LIST_STAT_STD_DEV Used with llListStatistics to find the standard deviation of the numbers in a list +LIST_STAT_SUM Used with llListStatistics to find the sum of the numbers in a list +LIST_STAT_SUM_SQUARES Used with llListStatistics to find the sum of the squares of the numbers in a list +LIST_STAT_NUM_COUNT Used with llListStatistics to find how many numbers are in a list +LIST_STAT_GEOMETRIC_MEAN Used with llListStatistics to find the geometric mean of the numbers in a list (all numbers must be > 0) +LIST_STAT_RANGE Used with llListStatistics to find the range of the numbers in a list + +PARCEL_FLAG_ALLOW_FLY Used with llGetParcelFlags to find if a parcel allows flying +PARCEL_FLAG_ALLOW_GROUP_SCRIPTS Used with llGetParcelFlags to find if a parcel allows group scripts +PARCEL_FLAG_ALLOW_SCRIPTS Used with llGetParcelFlags to find if a parcel allows outside scripts +PARCEL_FLAG_ALLOW_LANDMARK Used with llGetParcelFlags to find if a parcel allows landmarks to be created +PARCEL_FLAG_ALLOW_TERRAFORM Used with llGetParcelFlags to find if a parcel allows anyone to terraform the land +PARCEL_FLAG_ALLOW_DAMAGE Used with llGetParcelFlags to find if a parcel allows damage +PARCEL_FLAG_ALLOW_CREATE_OBJECTS Used with llGetParcelFlags to find if a parcel allows anyone to create objects +PARCEL_FLAG_ALLOW_CREATE_GROUP_OBJECTS Used with llGetParcelFlags to find if a parcel allows group members or objects to create objects +PARCEL_FLAG_USE_ACCESS_GROUP Used with llGetParcelFlags to find if a parcel limits access to a group +PARCEL_FLAG_USE_ACCESS_LIST Used with llGetParcelFlags to find if a parcel limits access to a list of residents +PARCEL_FLAG_USE_BAN_LIST Used with llGetParcelFlags to find if a parcel uses a ban list +PARCEL_FLAG_USE_LAND_PASS_LIST Used with llGetParcelFlags to find if a parcel allows passes to be purchased +PARCEL_FLAG_LOCAL_SOUND_ONLY Used with llGetParcelFlags to find if a parcel restricts spacialized sound to the parcel +PARCEL_FLAG_RESTRICT_PUSHOBJECT Used with llGetParcelFlags to find if a parcel restricts llPushObject() calls +PARCEL_FLAG_ALLOW_ALL_OBJECT_ENTRY Used with llGetParcelFlags to find if a parcel allows all objects to enter +PARCEL_FLAG_ALLOW_GROUP_OBJECT_ENTRY Used with llGetParcelFlags to find if a parcel only allows group (and owner) objects to enter + +REGION_FLAG_ALLOW_DAMAGE Used with llGetRegionFlags to find if a region is entirely damage enabled +REGION_FLAG_FIXED_SUN Used with llGetRegionFlags to find if a region has a fixed sun position +REGION_FLAG_BLOCK_TERRAFORM Used with llGetRegionFlags to find if a region terraforming disabled +REGION_FLAG_SANDBOX Used with llGetRegionFlags to find if a region is a sandbox +REGION_FLAG_DISABLE_COLLISIONS Used with llGetRegionFlags to find if a region has disabled collisions +REGION_FLAG_DISABLE_PHYSICS Used with llGetRegionFlags to find if a region has disabled physics +REGION_FLAG_BLOCK_FLY Used with llGetRegionFlags to find if a region blocks flying +REGION_FLAG_BLOCK_FLYOVER Used with llGetRegionFlags to find if a region enforces higher altitude parcel access rules +REGION_FLAG_ALLOW_DIRECT_TELEPORT Used with llGetRegionFlags to find if a region allows direct teleports +REGION_FLAG_RESTRICT_PUSHOBJECT Used with llGetRegionFlags to find if a region restricts llPushObject() calls + +HTTP_METHOD Used with llHTTPRequest to specify the method, "GET", "POST", "PUT", or "DELETE" +HTTP_MIMETYPE Used with llHTTPRequest to specify the MIME type, defaults to "text/plain" +HTTP_BODY_MAXLENGTH Used with llHTTPRequest to specify the maximum response body to return +HTTP_VERIFY_CERT Used with llHTTPRequest to specify SSL certificate verification +HTTP_BODY_TRUNCATED Used with http_response to indicate truncation point in bytes +HTTP_VERBOSE_THROTTLE Used with llHTTPRequest to shout error messages to DEBUG_CHANNEL if the outgoing request rate exceeds the server limit. +HTTP_BODY_MAXLENGTH Used with llHTTPRequest to specify the maximum body size for the date returned from the request. Mono scripts can request from 1byte to 16k, non-mono scripts can request from 1byte to 4k. The default is 2k. + +PARCEL_COUNT_TOTAL Used with llGetParcelPrimCount to get the total number of prims on the parcel +PARCEL_COUNT_OWNER Used with llGetParcelPrimCount to get the number of prims on the parcel owned by the owner +PARCEL_COUNT_GROUP Used with llGetParcelPrimCount to get the number of prims on the parcel owned by the group +PARCEL_COUNT_OTHER Used with llGetParcelPrimCount to get the number of prims on the parcel owned by others +PARCEL_COUNT_SELECTED Used with llGetParcelPrimCount to get the number of prims on the parcel currently selected or sat upon +PARCEL_COUNT_TEMP Used with llGetParcelPrimCount to get the number of prims on the parcel that are temp on rez + +PARCEL_DETAILS_NAME Used with llGetParcelDetails to get the parcel name +PARCEL_DETAILS_DESC Used with llGetParcelDetails to get the parcel description +PARCEL_DETAILS_OWNER Used with llGetParcelDetails to get the parcel owner id +PARCEL_DETAILS_GROUP Used with llGetParcelDetails to get the parcel group id +PARCEL_DETAILS_AREA Used with llGetParcelDetails to get the parcel area in square meters +PARCEL_DETAILS_ID Used with llGetParcelDetails to get the parcel id +PARCEL_DETAILS_SEE_AVATARS Used with llGetParcelDetails to get the avatars visibility setting + +STRING_TRIM_HEAD Used with llStringTrim to trim leading spaces from a string +STRING_TRIM_TAIL Used with llStringTrim to trim trailing spaces from a string +STRING_TRIM Used with llStringTrim to trim both leading and trailing spaces from a string CLICK_ACTION_NONE Used with llSetClickAction to disable the click action CLICK_ACTION_TOUCH Used with llSetClickAction to set touch as the default action when object is clicked @@ -641,77 +658,78 @@ STATUS_WHITELIST_FAILED URL failed to pass whitelist PROFILE_NONE Disables profiling PROFILE_SCRIPT_MEMORY Enables memory profiling -RC_DATA_FLAGS Option for llCastRay() followed with a bitwise combination of RC_GET_NORMAL, RC_GET_ROOT_KEY and RC_GET_LINK_NUM. -RC_DETECT_PHANTOM Option for llCastRay() followed with TRUE to detect phantom AND volume detect objects, FASLE otherwise. -RC_GET_LINK_NUM Flag used in the RC_DATA_FLAGS mask to get link numbers in llCastRay() results. -RC_GET_NORMAL Flag used in the RC_DATA_FLAGS mask to get hit normals in llCastRay() results. -RC_GET_ROOT_KEY Flag used in the RC_DATA_FLAGS mask to get root keys in llCastRay() results. -RC_MAX_HITS Option for llCastRay() followed with an integer specifying the maximum number of hits to return (must be <= 256). -RC_REJECT_TYPES Option for llCastRay() used to ignore specific types of objects, followed with a bitwise combination of RC_REJECT_AGENTS, RC_REJECT_PHYSICAL, RC_REJECT_NONPHYSICAL and RC_REJECT_LAND. -RC_REJECT_AGENTS Flag used in the RC_REJECT_TYPES mask to reject agents in llCastRay(). -RC_REJECT_PHYSICAL Flag used in the RC_REJECT_TYPES mask to reject physical objects in llCastRay(). -RC_REJECT_NONPHYSICAL Flag used in the RC_REJECT_TYPES mask to reject non-physical objects in llCastRay(). -RC_REJECT_LAND Flag used in the RC_REJECT_TYPES mask to reject land in llCastRay(). - -RCERR_CAST_TIME_EXCEEDED Returned by llCastRay() when the raycast failed because the parcel or agent has exceeded the maximum time allowed for raycasting. -RCERR_SIM_PERF_LOW Returned by llCastRay() when the raycast failed because simulator performance is low. -RCERR_UNKNOWN Returned by llCastRay() when the raycast failed for an unspecified reason. - -ESTATE_ACCESS_ALLOWED_AGENT_ADD Used with llManageEstateAccess to add an agent to this estate's allowed residents list. -ESTATE_ACCESS_ALLOWED_AGENT_REMOVE Used with llManageEstateAccess to remove an agent from this estate's allowed residents list. -ESTATE_ACCESS_ALLOWED_GROUP_ADD Used with llManageEstateAccess to add a group to this estate's allowed groups list. -ESTATE_ACCESS_ALLOWED_GROUP_REMOVE Used with llManageEstateAccess to remove a group from this estate's allowed groups list. -ESTATE_ACCESS_BANNED_AGENT_ADD Used with llManageEstateAccess to add an agent to this estate's banned residents list. -ESTATE_ACCESS_BANNED_AGENT_REMOVE Used with llManageEstateAccess to remove an agent from this estate's banned residents list. - -DENSITY For use with llSetPhysicsMaterial() as a bitwise value in its material_bits parameter, to set the density. -FRICTION For use with llSetPhysicsMaterial() as a bitwise value in its material_bits parameter, to set the friction. -RESTITUTION For use with llSetPhysicsMaterial() as a bitwise value in its material_bits parameter, to set the restitution. -GRAVITY_MULTIPLIER For use with llSetPhysicsMaterial() as a bitwise value in its material_bits parameter, to set the gravity multiplier. - -SIM_STAT_PCT_CHARS_STEPPED Option for llGetSimStats() to return the % of pathfinding characters skipped each frame, averaged over the last minute. - -KFM_COMMAND Option for llSetKeyframedMotion(), followed by one of KFM_CMD_STOP, KFM_CMD_PLAY, KFM_CMD_PAUSE. Note that KFM_COMMAND must be the only option in the list, and cannot be specified in the same function call that sets the keyframes list. -KFM_CMD_PLAY Option for llSetKeyframedMotion(), used after KFM_COMMAND to play the motion. -KFM_CMD_STOP Option for llSetKeyframedMotion(), used after KFM_COMMAND to stop the motion. -KFM_CMD_PAUSE Option for llSetKeyframedMotion(), used after KFM_COMMAND to pause the motion. -KFM_MODE Option for llSetKeyframedMotion(), used to specify the playback mode, followed by one of KFM_FORWARD, KFM_LOOP, KFM_PING_PONG or KFM_REVERSE. -KFM_FORWARD Option for llSetKeyframedMotion(), used after KFM_MODE to specify the forward playback mode. -KFM_LOOP Option for llSetKeyframedMotion(), used after KFM_MODE to specify the loop playback mode. -KFM_PING_PONG Option for llSetKeyframedMotion(), used after KFM_MODE to specify the ping pong playback mode. -KFM_REVERSE Option for llSetKeyframedMotion(), used after KFM_MODE to specify the reverse playback mode. -KFM_DATA Option for llSetKeyframedMotion(), followed by a bitwise combination of KFM_TRANSLATION and KFM_ROTATION. If you specify one or the other, you should only include translations or rotations in your keyframe list. -KFM_ROTATION Option for llSetKeyframedMotion(), used after KFM_DATA, possibly as a bitwise combination with KFM_TRANSLATION. -KFM_TRANSLATION Option for llSetKeyframedMotion(), used after KFM_DATA, possibly as a bitwise combination with KFM_ROTATION. - -CHARACTER_CMD_STOP Used with llExecCharacterCmd(). Makes the character jump. -CHARACTER_CMD_SMOOTH_STOP Used with llExecCharacterCmd(). Stops any current pathfinding operation in a smooth like fashion. -CHARACTER_CMD_JUMP Used with llExecCharacterCmd(). Stops any current pathfinding operation. - -CHARACTER_DESIRED_SPEED Speed of pursuit in meters per second. -CHARACTER_RADIUS Set collision capsule radius. -CHARACTER_LENGTH Set collision capsule length. -CHARACTER_ORIENTATION Set the character orientation. -CHARACTER_AVOIDANCE_MODE Allows you to specify that a character should not try to avoid other characters, should not try to avoid dynamic obstacles (relatively fast moving objects and avatars), or both. -CHARACTER_ACCOUNT_FOR_SKIPPED_FRAMES Defines if a character will attempt to catch up lost time if pathfinding performance is low. -PURSUIT_OFFSET Used with llPursue(). Go to a position offset from the target. -REQUIRE_LINE_OF_SIGHT Used with llPursue(). Define whether the character needs a physical line-of-sight to give chase. When enabled, the character will not pick a new target position while there is a something solid between the character and the target object/agent. -PURSUIT_FUZZ_FACTOR Used with llPursue(). Selects a random destination near the PURSUIT_OFFSET. The valid fuzz factor range is from 0 to 1, where 1 is most random. This option requires a nonzero PURSUIT_OFFSET. -PURSUIT_INTERCEPT Used with llPursue(). Define whether the character attempts to predict the target's future location. -PURSUIT_GOAL_TOLERANCE Used with llPursue(). Defines approximately how close the character must be to the current goal to consider itself to be at the desired position. The valid range is from 0.25 to 10m. -FORCE_DIRECT_PATH Used with llNavigateTo(). Makes character navigate in a straight line toward pos. May be set to TRUE or FALSE. -VERTICAL Constant to indicate that the orientation of the capsule for a Pathfinding character is vertical. -HORIZONTAL Constant to indicate that the orientation of the capsule for a Pathfinding character is horizontal. -AVOID_CHARACTERS TODO: add documentation -AVOID_DYNAMIC_OBSTACLES TODO: add documentation -AVOID_NONE TODO: add documentation +RC_DATA_FLAGS Option for llCastRay() followed with a bitwise combination of RC_GET_NORMAL, RC_GET_ROOT_KEY and RC_GET_LINK_NUM. +RC_DETECT_PHANTOM Option for llCastRay() followed with TRUE to detect phantom AND volume detect objects, FASLE otherwise. +RC_GET_LINK_NUM Flag used in the RC_DATA_FLAGS mask to get link numbers in llCastRay() results. +RC_GET_NORMAL Flag used in the RC_DATA_FLAGS mask to get hit normals in llCastRay() results. +RC_GET_ROOT_KEY Flag used in the RC_DATA_FLAGS mask to get root keys in llCastRay() results. +RC_MAX_HITS Option for llCastRay() followed with an integer specifying the maximum number of hits to return (must be <= 256). +RC_REJECT_TYPES Option for llCastRay() used to ignore specific types of objects, followed with a bitwise combination of RC_REJECT_AGENTS, RC_REJECT_PHYSICAL, RC_REJECT_NONPHYSICAL and RC_REJECT_LAND. +RC_REJECT_AGENTS Flag used in the RC_REJECT_TYPES mask to reject agents in llCastRay(). +RC_REJECT_PHYSICAL Flag used in the RC_REJECT_TYPES mask to reject physical objects in llCastRay(). +RC_REJECT_NONPHYSICAL Flag used in the RC_REJECT_TYPES mask to reject non-physical objects in llCastRay(). +RC_REJECT_LAND Flag used in the RC_REJECT_TYPES mask to reject land in llCastRay(). + +RCERR_CAST_TIME_EXCEEDED Returned by llCastRay() when the raycast failed because the parcel or agent has exceeded the maximum time allowed for raycasting. +RCERR_SIM_PERF_LOW Returned by llCastRay() when the raycast failed because simulator performance is low. +RCERR_UNKNOWN Returned by llCastRay() when the raycast failed for an unspecified reason. + +ESTATE_ACCESS_ALLOWED_AGENT_ADD Passed to llManageEstateAccess to add the agent to this estate's Allowed Residents list +ESTATE_ACCESS_ALLOWED_AGENT_REMOVE Passed to llManageEstateAccess to remove the agent from this estate's Allowed Residents list +ESTATE_ACCESS_ALLOWED_GROUP_ADD Passed to llManageEstateAccess to add the group to this estate's Allowed groups list +ESTATE_ACCESS_ALLOWED_GROUP_REMOVE Passed to llManageEstateAccess to remove the group from this estate's Allowed groups list +ESTATE_ACCESS_BANNED_AGENT_ADD Passed to llManageEstateAccess to add the agent to this estate's Banned residents list +ESTATE_ACCESS_BANNED_AGENT_REMOVE Passed to llManageEstateAccess to remove the agent from this estate's Banned residents list + +DENSITY For use with llSetPhysicsMaterial() as a bitwise value in its material_bits parameter, to set the density. +FRICTION For use with llSetPhysicsMaterial() as a bitwise value in its material_bits parameter, to set the friction. +RESTITUTION For use with llSetPhysicsMaterial() as a bitwise value in its material_bits parameter, to set the restitution. +GRAVITY_MULTIPLIER For use with llSetPhysicsMaterial() as a bitwise value in its material_bits parameter, to set the gravity multiplier. + +SIM_STAT_PCT_CHARS_STEPPED Option for llGetSimStats() to return the % of pathfinding characters skipped each frame, averaged over the last minute. + +KFM_COMMAND Option for llSetKeyframedMotion(), followed by one of KFM_CMD_STOP, KFM_CMD_PLAY, KFM_CMD_PAUSE. Note that KFM_COMMAND must be the only option in the list, and cannot be specified in the same function call that sets the keyframes list. +KFM_CMD_PLAY Option for llSetKeyframedMotion(), used after KFM_COMMAND to play the motion. +KFM_CMD_STOP Option for llSetKeyframedMotion(), used after KFM_COMMAND to stop the motion. +KFM_CMD_PAUSE Option for llSetKeyframedMotion(), used after KFM_COMMAND to pause the motion. +#KFM_CMD_SET_MODE TODO: add documentation +KFM_MODE Option for llSetKeyframedMotion(), used to specify the playback mode, followed by one of KFM_FORWARD, KFM_LOOP, KFM_PING_PONG or KFM_REVERSE. +KFM_FORWARD Option for llSetKeyframedMotion(), used after KFM_MODE to specify the forward playback mode. +KFM_LOOP Option for llSetKeyframedMotion(), used after KFM_MODE to specify the loop playback mode. +KFM_PING_PONG Option for llSetKeyframedMotion(), used after KFM_MODE to specify the ping pong playback mode. +KFM_REVERSE Option for llSetKeyframedMotion(), used after KFM_MODE to specify the reverse playback mode. +KFM_DATA Option for llSetKeyframedMotion(), followed by a bitwise combination of KFM_TRANSLATION and KFM_ROTATION. If you specify one or the other, you should only include translations or rotations in your keyframe list. +KFM_ROTATION Option for llSetKeyframedMotion(), used after KFM_DATA, possibly as a bitwise combination with KFM_TRANSLATION. +KFM_TRANSLATION Option for llSetKeyframedMotion(), used after KFM_DATA, possibly as a bitwise combination with KFM_ROTATION. + +CHARACTER_CMD_STOP Used with llExecCharacterCmd(). Makes the character jump. +CHARACTER_CMD_SMOOTH_STOP Used with llExecCharacterCmd(). Stops any current pathfinding operation in a smooth like fashion. +CHARACTER_CMD_JUMP Used with llExecCharacterCmd(). Stops any current pathfinding operation. + +CHARACTER_DESIRED_SPEED Speed of pursuit in meters per second. +CHARACTER_RADIUS Set collision capsule radius. +CHARACTER_LENGTH Set collision capsule length. +CHARACTER_ORIENTATION Set the character orientation. +CHARACTER_AVOIDANCE_MODE Allows you to specify that a character should not try to avoid other characters, should not try to avoid dynamic obstacles (relatively fast moving objects and avatars), or both. +CHARACTER_ACCOUNT_FOR_SKIPPED_FRAMES Defines if a character will attempt to catch up lost time if pathfinding performance is low. +PURSUIT_OFFSET Used with llPursue(). Go to a position offset from the target. +REQUIRE_LINE_OF_SIGHT Used with llPursue(). Define whether the character needs a physical line-of-sight to give chase. When enabled, the character will not pick a new target position while there is a something solid between the character and the target object/agent. +PURSUIT_FUZZ_FACTOR Used with llPursue(). Selects a random destination near the PURSUIT_OFFSET. The valid fuzz factor range is from 0 to 1, where 1 is most random. This option requires a nonzero PURSUIT_OFFSET. +PURSUIT_INTERCEPT Used with llPursue(). Define whether the character attempts to predict the target's future location. +PURSUIT_GOAL_TOLERANCE Used with llPursue(). Defines approximately how close the character must be to the current goal to consider itself to be at the desired position. The valid range is from 0.25 to 10m. +FORCE_DIRECT_PATH Used with llNavigateTo(). Makes character navigate in a straight line toward pos. May be set to TRUE or FALSE. +VERTICAL Constant to indicate that the orientation of the capsule for a Pathfinding character is vertical. +HORIZONTAL Constant to indicate that the orientation of the capsule for a Pathfinding character is horizontal. +AVOID_CHARACTERS TODO: add documentation +AVOID_DYNAMIC_OBSTACLES TODO: add documentation +AVOID_NONE TODO: add documentation PU_EVADE_HIDDEN Triggered when an llEvade character thinks it has hidden from its pursuer. PU_EVADE_SPOTTED Triggered when an llEvade character switches from hiding to running PU_FAILURE_INVALID_GOAL Goal is not on the navigation-mesh and cannot be reached. PU_FAILURE_INVALID_START Character cannot navigate from the current location - e.g., the character is off the navmesh or too high above it. PU_FAILURE_NO_VALID_DESTINATION There's no good place for the character to go - e.g., it is patrolling and all the patrol points are now unreachable. -PU_FAILURE_OTHER Unknown failure +PU_FAILURE_OTHER Unknown failure PU_FAILURE_TARGET_GONE Target (for llPursue or llEvade) can no longer be tracked - e.g., it left the region or is an avatar that is now more than about 30m outside the region. PU_FAILURE_UNREACHABLE Goal is no longer reachable for some reason - e.g., an obstacle blocks the path. PU_GOAL_REACHED Character has reached the goal and will stop or choose a new goal (if wandering). @@ -720,56 +738,56 @@ PU_FAILURE_NO_NAVMESH Triggered if no navmesh is available for the re PU_FAILURE_DYNAMIC_PATHFINDING_DISABLED Triggered when a character enters a region with dynamic pathfinding disabled. PU_FAILURE_PARCEL_UNREACHABLE Triggered when a character failed to enter a parcel because it is not allowed to enter, e.g. because the parcel is already full or because object entry was disabled after the navmesh was baked. -CHARACTER_TYPE Specifies which walkability coefficient will be used by this character. -CHARACTER_TYPE_A Used for character types that you prefer move in a way consistent with humanoids. -CHARACTER_TYPE_B Used for character types that you prefer move in a way consistent with wild animals or off road vehicles. -CHARACTER_TYPE_C Used for mechanical character types or road going vehicles. -CHARACTER_TYPE_D Used for character types that are not consistent with the A, B, or C type. -CHARACTER_TYPE_NONE Used to set no specific character type. - -TRAVERSAL_TYPE Controls the speed at which characters moves on terrain that is less than 100% walkable will move faster (e.g., a cat crossing a street) or slower (e.g., a car driving in a swamp). -TRAVERSAL_TYPE_SLOW TODO: add documentation -TRAVERSAL_TYPE_FAST TODO: add documentation -TRAVERSAL_TYPE_NONE TODO: add documentation - -CHARACTER_MAX_ACCEL The character's maximum acceleration rate. -CHARACTER_MAX_DECEL The character's maximum deceleration rate. -CHARACTER_MAX_ANGULAR_SPEED TODO: add documentation -CHARACTER_MAX_ANGULAR_ACCEL TODO: add documentation -CHARACTER_TURN_SPEED_MULTIPLIER TODO: add documentation -CHARACTER_DESIRED_TURN_SPEED The character's maximum speed while turning--note that this is only loosely enforced (i.e., a character may turn at higher speeds under certain conditions) -CHARACTER_MAX_TURN_RADIUS The character's turn radius when traveling at CHARACTER_DESIRED_TURN_SPEED. -CHARACTER_MAX_SPEED The character's maximum speed. Affects speed when avoiding dynamic obstacles and when traversing low-walkability objects in TRAVERSAL_TYPE_FAST mode. -CHARACTER_STAY_WITHIN_PARCEL Characters which have CHARACTER_STAY_WITHIN_PARCEL set to TRUE treat the parcel boundaries as one-way obstacles. - -PATROL_PAUSE_AT_WAYPOINTS Used with llPatrolPoints(). Defines if characters slow down and momentarily pause at each waypoint. -WANDER_PAUSE_AT_WAYPOINTS Used with llWanderWithin(). Defines if characters should pause after reaching each wander waypoint. - -CONTENT_TYPE_TEXT text/plain -CONTENT_TYPE_HTML text/html -CONTENT_TYPE_XML application/xml -CONTENT_TYPE_XHTML application/xhtml+xml -CONTENT_TYPE_ATOM application/atom+xml -CONTENT_TYPE_JSON application/json -CONTENT_TYPE_LLSD application/llsd+xml -CONTENT_TYPE_FORM application/x-www-form-urlencoded -CONTENT_TYPE_RSS application/rss+xml - -JSON_INVALID Returned by llJsonGetValue and llJsonValueType if the specifiers to do specify a valid in the json value. -JSON_OBJECT Represents a json datatype represented in LSL as a strided list of name/value pairs -JSON_ARRAY Represents a json datatype mappable to the LSL datatype "list" -JSON_NUMBER Represents a json datatype mappable to the LSL datatypes "integer" and "float" -JSON_STRING Represents a json datatype mappable to the LSL datatype "string" -JSON_TRUE Represents the constant "true" of a json value. -JSON_FALSE Represents the constant "false" of a json value. -JSON_NULL Represents the constant "null" of a json value. -JSON_APPEND Used with llJsonSetValue as a specifier to indicate appending the value to the end of the array at that level. - -ERR_GENERIC Returned by llReturnObjectsByID and llReturnObjectsByOwner in case of a general error. -ERR_PARCEL_PERMISSIONS Returned by llReturnObjectsByID and llReturnObjectsByOwner in case of a parcel owner permission error. -ERR_MALFORMED_PARAMS Returned by llReturnObjectsByID and llReturnObjectsByOwner in case of malformed parameters. -ERR_RUNTIME_PERMISSIONS Returned by llReturnObjectsByID and llReturnObjectsByOwner in case of a runtime permission error. -ERR_THROTTLED Returned by llReturnObjectsByID and llReturnObjectsByOwner in case of being throttled. +CHARACTER_TYPE Specifies which walkability coefficient will be used by this character. Used in combination with one of the character type flags. +CHARACTER_TYPE_A Used for character types that you prefer move in a way consistent with humanoids. +CHARACTER_TYPE_B Used for character types that you prefer move in a way consistent with wild animals or off road vehicles. +CHARACTER_TYPE_C Used for mechanical character types or road going vehicles. +CHARACTER_TYPE_D Used for character types that are not consistent with the A, B, or C type. +CHARACTER_TYPE_NONE Used to set no specific character type. + +TRAVERSAL_TYPE Controls the speed at which characters moves on terrain that is less than 100% walkable will move faster (e.g., a cat crossing a street) or slower (e.g., a car driving in a swamp). +TRAVERSAL_TYPE_SLOW TODO: add documentation +TRAVERSAL_TYPE_FAST TODO: add documentation +TRAVERSAL_TYPE_NONE TODO: add documentation + +CHARACTER_MAX_ACCEL The character's maximum acceleration rate. +CHARACTER_MAX_DECEL The character's maximum deceleration rate. +CHARACTER_MAX_ANGULAR_SPEED TODO: add documentation +CHARACTER_MAX_ANGULAR_ACCEL TODO: add documentation +CHARACTER_TURN_SPEED_MULTIPLIER TODO: add documentation +CHARACTER_DESIRED_TURN_SPEED The character's maximum speed while turning--note that this is only loosely enforced (i.e., a character may turn at higher speeds under certain conditions) +CHARACTER_MAX_TURN_RADIUS The character's turn radius when traveling at CHARACTER_DESIRED_TURN_SPEED. +CHARACTER_MAX_SPEED The character's maximum speed. Affects speed when avoiding dynamic obstacles and when traversing low-walkability objects in TRAVERSAL_TYPE_FAST mode. +CHARACTER_STAY_WITHIN_PARCEL Characters which have CHARACTER_STAY_WITHIN_PARCEL set to TRUE treat the parcel boundaries as one-way obstacles. + +PATROL_PAUSE_AT_WAYPOINTS Used with llPatrolPoints(). Defines if characters slow down and momentarily pause at each waypoint. +WANDER_PAUSE_AT_WAYPOINTS Used with llWanderWithin(). Defines if characters should pause after reaching each wander waypoint. + +CONTENT_TYPE_TEXT text/plain +CONTENT_TYPE_HTML text/html +CONTENT_TYPE_XML application/xml +CONTENT_TYPE_XHTML application/xhtml+xml +CONTENT_TYPE_ATOM application/atom+xml +CONTENT_TYPE_JSON application/json +CONTENT_TYPE_LLSD application/llsd+xml +CONTENT_TYPE_FORM application/x-www-form-urlencoded +CONTENT_TYPE_RSS application/rss+xml + +JSON_INVALID Returned by llJsonGetValue and llJsonValueType if the specifiers to do specify a valid in the json value. +JSON_OBJECT Represents a json datatype represented in LSL as a strided list of name/value pairs +JSON_ARRAY Represents a json datatype mappable to the LSL datatype "list" +JSON_NUMBER Represents a json datatype mappable to the LSL datatypes "integer" and "float" +JSON_STRING Represents a json datatype mappable to the LSL datatype "string" +JSON_TRUE Represents the constant "true" of a json value. +JSON_FALSE Represents the constant "false" of a json value. +JSON_NULL Represents the constant "null" of a json value. +JSON_APPEND Used with llJsonSetValue as a specifier to indicate appending the value to the end of the array at that level. + +ERR_GENERIC Returned by llReturnObjectsByID and llReturnObjectsByOwner in case of a general error. +ERR_PARCEL_PERMISSIONS Returned by llReturnObjectsByID and llReturnObjectsByOwner in case of a parcel owner permission error. +ERR_MALFORMED_PARAMS Returned by llReturnObjectsByID and llReturnObjectsByOwner in case of malformed parameters. +ERR_RUNTIME_PERMISSIONS Returned by llReturnObjectsByID and llReturnObjectsByOwner in case of a runtime permission error. +ERR_THROTTLED Returned by llReturnObjectsByID and llReturnObjectsByOwner in case of being throttled. # --- OpenSim and Aurora-Sim constants Below --- # OpenSim Constants (\OpenSim\Region\ScriptEngine\Shared\Api\Runtime\LSL_Constants.cs) @@ -793,26 +811,26 @@ OS_ATTACH_MSG_SCRIPT_CREATOR Used with osMessageAttachements PARCEL_DETAILS_CLAIMDATE Used with osSetParcelDetails # osGetRegionStats STATS_TIME_DILATION returned value from osGetRegionStats(), 1st of 21 items in returned list. -STATS_SIM_FPS returned value from osGetRegionStats(), 2nd of 21 items in returned list. -STATS_PHYSICS_FPS returned value from osGetRegionStats(), 3rd of 21 items in returned list. +STATS_SIM_FPS returned value from osGetRegionStats(), 2nd of 21 items in returned list. +STATS_PHYSICS_FPS returned value from osGetRegionStats(), 3rd of 21 items in returned list. STATS_AGENT_UPDATES returned value from osGetRegionStats(), 4th of 21 items in returned list. -STATS_ROOT_AGENTS returned value from osGetRegionStats(), 5th of 21 items in returned list. -STATS_CHILD_AGENTS returned value from osGetRegionStats(), 6th of 21 items in returned list. -STATS_TOTAL_PRIMS returned value from osGetRegionStats(), 7th of 21 items in returned list. -STATS_ACTIVE_PRIMS returned value from osGetRegionStats(), 8th of 21 items in returned list. +STATS_ROOT_AGENTS returned value from osGetRegionStats(), 5th of 21 items in returned list. +STATS_CHILD_AGENTS returned value from osGetRegionStats(), 6th of 21 items in returned list. +STATS_TOTAL_PRIMS returned value from osGetRegionStats(), 7th of 21 items in returned list. +STATS_ACTIVE_PRIMS returned value from osGetRegionStats(), 8th of 21 items in returned list. STATS_FRAME_MS returned value from osGetRegionStats(), 9th of 21 items in returned list. STATS_NET_MS returned value from osGetRegionStats(), 10th of 21 items in returned list. -STATS_PHYSICS_MS returned value from osGetRegionStats(), 11th of 21 items in returned list. +STATS_PHYSICS_MS returned value from osGetRegionStats(), 11th of 21 items in returned list. STATS_IMAGE_MS returned value from osGetRegionStats(), 12th of 21 items in returned list. STATS_OTHER_MS returned value from osGetRegionStats(), 13th of 21 items in returned list. STATS_IN_PACKETS_PER_SECOND returned value from osGetRegionStats(), 14th of 21 items in returned list. STATS_OUT_PACKETS_PER_SECOND returned value from osGetRegionStats(), 15th of 21 items in returned list. STATS_UNACKED_BYTES returned value from osGetRegionStats(), 16th of 21 items in returned list. -STATS_AGENT_MS returned value from osGetRegionStats(), 17th of 21 items in returned list. +STATS_AGENT_MS returned value from osGetRegionStats(), 17th of 21 items in returned list. STATS_PENDING_DOWNLOADS returned value from osGetRegionStats(), 18th of 21 items in returned list. STATS_PENDING_UPLOADS returned value from osGetRegionStats(), 19th of 21 items in returned list. -STATS_ACTIVE_SCRIPTS returned value from osGetRegionStats(), 20th of 21 items in returned list. -STATS_SCRIPT_LPS returned value from osGetRegionStats(), 21st of 21 items in returned list. +STATS_ACTIVE_SCRIPTS returned value from osGetRegionStats(), 20th of 21 items in returned list. +STATS_SCRIPT_LPS returned value from osGetRegionStats(), 21st of 21 items in returned list. # OpenSim NPC OS_NPC used by osNPC. Value 0x01000000 OS_NPC_FLY used by osNPC. Value 0 @@ -824,43 +842,43 @@ OS_NPC_NOT_OWNED used by osNPC. Value 0x2 OS_NPC_SENSE_AS_AGENT used by osNPC. Value 0x4 OS_NPC_RUNNING used by osNPC. Value 4 # Windlight/Lightshare -WL_WATER_COLOR Windlight Water Colour -WL_WATER_FOG_DENSITY_EXPONENT Windlight Water Fog Density Exponent -WL_UNDERWATER_FOG_MODIFIER Windlight Underwater Fog Modifier -WL_REFLECTION_WAVELET_SCALE Windlight Reflection Wavelet Scale -WL_FRESNEL_SCALE Windlight Fresnel Scale -WL_FRESNEL_OFFSET Windlight Fresnel Offset -WL_REFRACT_SCALE_ABOVE Windlight Refract Scale Above -WL_REFRACT_SCALE_BELOW Windlight Refract Scale Below -WL_BLUR_MULTIPLIER Windlight Blur Multiplier -WL_BIG_WAVE_DIRECTION Windlight Big Wave Direction -WL_LITTLE_WAVE_DIRECTION Windlight Little Wave Direction -WL_NORMAL_MAP_TEXTURE Windlight Normal Map Texture -WL_HORIZON Windlight Horizon Colour -WL_HAZE_HORIZON Windlight Haze Horizon -WL_BLUE_DENSITY Windlight Blue Density -WL_HAZE_DENSITY Windlight Haze Density -WL_DENSITY_MULTIPLIER Windlight Density Multiplier -WL_DISTANCE_MULTIPLIER Windlight Distance Multiplier -WL_MAX_ALTITUDE Windlight Max Altitude -WL_SUN_MOON_COLOR Windlight Sun/Moon Colour -WL_SUN_MOON_POSITION Windlight Sun/Moon Position -WL_AMBIENT Windlight Ambient Colour -WL_EAST_ANGLE Windlight Sun/Position East -WL_SUN_GLOW_FOCUS Windlight Sun Glow Focus -WL_SUN_GLOW_SIZE Windlight Sun Glow Size -WL_SCENE_GAMMA Windlight Scene Gamma -WL_STAR_BRIGHTNESS Windlight Star Brightness -WL_CLOUD_COLOR Windlight Cloud Colour -WL_CLOUD_XY_DENSITY Windlight Cloud X/Y/Density -WL_CLOUD_COVERAGE Windlight Cloud Coverage -WL_CLOUD_SCALE Windlight Cloud Scale -WL_CLOUD_DETAIL_XY_DENSITY Windlight Cloud Detail X/Y/Density -WL_CLOUD_SCROLL_X Windlight Cloud Scroll X -WL_CLOUD_SCROLL_Y Windlight Cloud Scroll Y -WL_CLOUD_SCROLL_Y_LOCK Windlight Cloud Scroll Y Lock -WL_CLOUD_SCROLL_X_LOCK Windlight Cloud Scroll X Lock -WL_DRAW_CLASSIC_CLOUDS Windlight Draw Classic Clouds +WL_WATER_COLOR Windlight Water Colour +WL_WATER_FOG_DENSITY_EXPONENT Windlight Water Fog Density Exponent +WL_UNDERWATER_FOG_MODIFIER Windlight Underwater Fog Modifier +WL_REFLECTION_WAVELET_SCALE Windlight Reflection Wavelet Scale +WL_FRESNEL_SCALE Windlight Fresnel Scale +WL_FRESNEL_OFFSET Windlight Fresnel Offset +WL_REFRACT_SCALE_ABOVE Windlight Refract Scale Above +WL_REFRACT_SCALE_BELOW Windlight Refract Scale Below +WL_BLUR_MULTIPLIER Windlight Blur Multiplier +WL_BIG_WAVE_DIRECTION Windlight Big Wave Direction +WL_LITTLE_WAVE_DIRECTION Windlight Little Wave Direction +WL_NORMAL_MAP_TEXTURE Windlight Normal Map Texture +WL_HORIZON Windlight Horizon Colour +WL_HAZE_HORIZON Windlight Haze Horizon +WL_BLUE_DENSITY Windlight Blue Density +WL_HAZE_DENSITY Windlight Haze Density +WL_DENSITY_MULTIPLIER Windlight Density Multiplier +WL_DISTANCE_MULTIPLIER Windlight Distance Multiplier +WL_MAX_ALTITUDE Windlight Max Altitude +WL_SUN_MOON_COLOR Windlight Sun/Moon Colour +WL_SUN_MOON_POSITION Windlight Sun/Moon Position +WL_AMBIENT Windlight Ambient Colour +WL_EAST_ANGLE Windlight Sun/Position East +WL_SUN_GLOW_FOCUS Windlight Sun Glow Focus +WL_SUN_GLOW_SIZE Windlight Sun Glow Size +WL_SCENE_GAMMA Windlight Scene Gamma +WL_STAR_BRIGHTNESS Windlight Star Brightness +WL_CLOUD_COLOR Windlight Cloud Colour +WL_CLOUD_XY_DENSITY Windlight Cloud X/Y/Density +WL_CLOUD_COVERAGE Windlight Cloud Coverage +WL_CLOUD_SCALE Windlight Cloud Scale +WL_CLOUD_DETAIL_XY_DENSITY Windlight Cloud Detail X/Y/Density +WL_CLOUD_SCROLL_X Windlight Cloud Scroll X +WL_CLOUD_SCROLL_Y Windlight Cloud Scroll Y +WL_CLOUD_SCROLL_Y_LOCK Windlight Cloud Scroll Y Lock +WL_CLOUD_SCROLL_X_LOCK Windlight Cloud Scroll X Lock +WL_DRAW_CLASSIC_CLOUDS Windlight Draw Classic Clouds # WL Constants added unique to Aurora-Sim WL_OK Value -1 WL_ERROR Value -2 @@ -874,74 +892,94 @@ ENABLE_GRAVITY enable_gravity. GRAVITY_FORCE_X gravity_force_x. GRAVITY_FORCE_Y gravity_force_y. GRAVITY_FORCE_Z gravity_force_z. -ADD_GRAVITY_POINT add_gravity_point. -ADD_GRAVITY_FORCE add_gravity_force. -START_TIME_REVERSAL_SAVING start_time_reversal_saving. -STOP_TIME_REVERSAL_SAVING stop_time_reversal_saving. -START_TIME_REVERSAL start_time_reversal. -STOP_TIME_REVERSAL stop_time_reversal. +ADD_GRAVITY_POINT add_gravity_point. +ADD_GRAVITY_FORCE add_gravity_force. +START_TIME_REVERSAL_SAVING start_time_reversal_saving. +STOP_TIME_REVERSAL_SAVING stop_time_reversal_saving. +START_TIME_REVERSAL start_time_reversal. +STOP_TIME_REVERSAL stop_time_reversal. # Aurora botFunctions -BOT_FOLLOW_FLAG_NONE value 0. +BOT_FOLLOW_FLAG_NONE value 0. BOT_FOLLOW_FLAG_INDEFINITELY value 1. -BOT_TAG_FIND_ALL value AllBots. +BOT_TAG_FIND_ALL value AllBots. BOT_FOLLOW_WALK value 0. BOT_FOLLOW_RUN value 1. BOT_FOLLOW_FLY value 2. -BOT_FOLLOW_TELEPORT value 3. +BOT_FOLLOW_TELEPORT value 3. BOT_FOLLOW_WAIT value 4. -BOT_FOLLOW_TRIGGER_HERE_EVENT value 1. +BOT_FOLLOW_TRIGGER_HERE_EVENT value 1. BOT_FOLLOW_FLAG_FORCEDIRECTPATH value 4. # string constants [word .1, .3, .5] -NULL_KEY Indicates an empty key -EOF Indicates the last line of a notecard was read -TEXTURE_BLANK UUID for the "Blank" texture -TEXTURE_DEFAULT Alias for TEXTURE_PLYWOOD -TEXTURE_MEDIA UUID for the "Default Media" texture -TEXTURE_PLYWOOD UUID for the default "Plywood" texture -TEXTURE_TRANSPARENT UUID for the "White - Transparent" texture +NULL_KEY Indicates an empty key +EOF Indicates the last line of a notecard was read +TEXTURE_BLANK UUID for the "Blank" texture +TEXTURE_DEFAULT Alias for TEXTURE_PLYWOOD +TEXTURE_MEDIA UUID for the "Default Media" texture +TEXTURE_PLYWOOD UUID for the default "Plywood" texture +TEXTURE_TRANSPARENT UUID for the "White - Transparent" texture + +URL_REQUEST_GRANTED Used with http_request when a public URL is successfully granted +URL_REQUEST_DENIED Used with http_request when a public URL is not available + +XP_ERROR_NONE No error was detected +XP_ERROR_THROTTLED The call failed due to too many recent calls. +XP_ERROR_EXPERIENCES_DISABLED The region currently has experiences disabled. +XP_ERROR_INVALID_PARAMETERS One of the string arguments was too big to fit in the key-value store. +XP_ERROR_NOT_PERMITTED This experience is not allowed to run on the current region. +XP_ERROR_NO_EXPERIENCE This script is not associated with an experience. +XP_ERROR_NOT_FOUND The sim was unable to verify the validity of the experience. Retrying after a short wait is advised. +XP_ERROR_INVALID_EXPERIENCE The script is associated with an experience that no longer exists. +XP_ERROR_EXPERIENCE_DISABLED The experience owner has temporarily disabled the experience. +XP_ERROR_EXPERIENCE_SUSPENDED The experience has been suspended by Linden Customer Support. +XP_ERROR_QUOTA_EXCEEDED An attempted write data to the key-value store failed due to the data quota being met. +XP_ERROR_STORE_DISABLED The key-value store is currently disabled on this region. +XP_ERROR_STORAGE_EXCEPTION Unable to communicate with the key-value store. +XP_ERROR_KEY_NOT_FOUND The requested key does not exist. +XP_ERROR_RETRY_UPDATE A checked update failed due to an out of date request. +XP_ERROR_MATURITY_EXCEEDED The request failed due to agent content preferences. +XP_ERROR_UNKNOWN_ERROR Other unknown error. +XP_ERROR_INVALID_PARAMETERS One of the string arguments was too big to fit in the key-value store. -URL_REQUEST_GRANTED Used with http_request when a public URL is successfully granted -URL_REQUEST_DENIED Used with http_request when a public URL is not available # float constants [word .3, .1, .5] -PI 3.1415926535897932384626433832795 -TWO_PI 6.283185307179586476925286766559 -PI_BY_TWO 1.5707963267948966192313216916398 -DEG_TO_RAD To convert from degrees to radians -RAD_TO_DEG To convert from radians to degrees -SQRT2 1.4142135623730950488016887242097 +PI 3.1415926535897932384626433832795 +TWO_PI 6.283185307179586476925286766559 +PI_BY_TWO 1.5707963267948966192313216916398 +DEG_TO_RAD To convert from degrees to radians +RAD_TO_DEG To convert from radians to degrees +SQRT2 1.4142135623730950488016887242097 # compound constants [word .4, .2, .4] -ZERO_VECTOR <0.0, 0.0, 0.0> -ZERO_ROTATION <0.0, 0.0, 0.0, 1.0> +ZERO_VECTOR <0.0, 0.0, 0.0> +ZERO_ROTATION <0.0, 0.0, 0.0, 1.0> # flow control keywords [word 0, 0, .8] -for for loop:for (initializer; test; iteration):{: statements:} -do do loop:do:{: statements:} while (test); -while while loop:while (test):{ statements:} -if if statement:if (test):{ statements:} -else else clause:if (test):{ statements:}:else:{ statements:} -jump jump statement:jump label;: -return Leave current function or event handler +for for loop:for (initializer; test; iteration):{: statements:} +do do loop:do:{: statements:} while (test); +while while loop:while (test):{ statements:} +if if statement:if (test):{ statements:} +else else clause:if (test):{ statements:}:else:{ statements:} +jump jump statement:jump label;: +return Leave current function or event handler # flow control label [line 0, 0, .8] -@ Label:Target for jump statement +@ Label:Target for jump statement # Comment [one_sided_delimiter .8, .3, .15] -// Comment:Non-functional commentary or disabled code +// Comment:Non-functional commentary or disabled code [two_sided_delimiter .8, .3, .15] -/* */ Comment:Non-functional commentary or disabled code +/* */ Comment:Non-functional commentary or disabled code # String literals [double_quotation_marks 0, .2, 0] -" String literal +" String literal #functions are supplied by the program now diff --git a/indra/newview/app_settings/logcontrol.xml b/indra/newview/app_settings/logcontrol.xml index cbfda6de47..dcb34a4a63 100644 --- a/indra/newview/app_settings/logcontrol.xml +++ b/indra/newview/app_settings/logcontrol.xml @@ -40,7 +40,7 @@ tags - ShaderLoading + Openjpeg Plugin diff --git a/indra/newview/app_settings/low_graphics.xml b/indra/newview/app_settings/low_graphics.xml index 9e9be14bb9..0e589e602e 100644 --- a/indra/newview/app_settings/low_graphics.xml +++ b/indra/newview/app_settings/low_graphics.xml @@ -25,7 +25,7 @@ - + diff --git a/indra/newview/app_settings/lsl_functions_os.xml b/indra/newview/app_settings/lsl_functions_os.xml index f7f0ab1e8c..bfda9ca092 100644 --- a/indra/newview/app_settings/lsl_functions_os.xml +++ b/indra/newview/app_settings/lsl_functions_os.xml @@ -287,6 +287,16 @@ osRegexIsMatch + osForceCreateLink + + osForceBreakLink + + osForceBreakAllLinks + + osGetRegionSize + + osGetPhysicsEngineType + osReturnObject diff --git a/indra/newview/app_settings/lsl_functions_sl.xml b/indra/newview/app_settings/lsl_functions_sl.xml index 31a4558888..7bb14209c5 100644 --- a/indra/newview/app_settings/lsl_functions_sl.xml +++ b/indra/newview/app_settings/lsl_functions_sl.xml @@ -305,6 +305,10 @@ llStopAnimation + llStartObjectAnimation + + llStopObjectAnimation + llPointAt llStopPointAt @@ -793,6 +797,8 @@ llClearCameraParams + llListStatistics + llGetUnixTime llGetParcelFlags @@ -1039,5 +1045,35 @@ llXorBase64 + + llScaleByFactor + + llGetMinScaleFactor + + llGetMaxScaleFactor + + + llAgentInExperience + + llGetExperienceDetails + + llRequestExperiencePermissions + + llReadKeyValue + + llCreateKeyValue + + llUpdateKeyValue + + llDeleteKeyValue + + llDataSizeKeyValue + + llKeysKeyValue + + llKeyCountKeyValue + + llGetExperienceErrorMessage + diff --git a/indra/newview/app_settings/mid_graphics.xml b/indra/newview/app_settings/mid_graphics.xml index 4c1ec5494d..3e22920b9a 100644 --- a/indra/newview/app_settings/mid_graphics.xml +++ b/indra/newview/app_settings/mid_graphics.xml @@ -25,7 +25,7 @@ - + diff --git a/indra/newview/app_settings/mime_types.xml b/indra/newview/app_settings/mime_types.xml index 61067da063..9182f5742b 100644 --- a/indra/newview/app_settings/mime_types.xml +++ b/indra/newview/app_settings/mime_types.xml @@ -7,7 +7,7 @@ none - media_plugin_webkit + media_plugin_cef + + + + none/none + + + icn_media_web.tga + + + No media here + + + + false + + + false + + + + + + movie + + + media_plugin_example - + + + + movie + + + media_plugin_libvlc + + + @@ -120,7 +163,7 @@ none - media_plugin_webkit + media_plugin_cef @@ -131,7 +174,7 @@ none - media_plugin_webkit + media_plugin_cef @@ -142,7 +185,7 @@ audio - media_plugin_quicktime + media_plugin_libvlc @@ -153,7 +196,7 @@ movie - media_plugin_quicktime + media_plugin_libvlc @@ -164,7 +207,7 @@ image - media_plugin_webkit + media_plugin_cef @@ -175,8 +218,8 @@ movie - media_plugin_quicktime - + media_plugin_libvlc + @@ -197,7 +240,7 @@ audio - media_plugin_quicktime + media_plugin_cef @@ -208,7 +251,7 @@ image - media_plugin_webkit + media_plugin_cef @@ -219,7 +262,7 @@ image - media_plugin_webkit + media_plugin_cef @@ -230,18 +273,18 @@ image - media_plugin_webkit + media_plugin_cef movie - media_plugin_webkit + media_plugin_cef @@ -252,7 +295,7 @@ web - media_plugin_webkit + media_plugin_cef @@ -263,7 +306,7 @@ image - media_plugin_webkit + media_plugin_cef @@ -274,7 +317,7 @@ audio - media_plugin_quicktime + media_plugin_cef @@ -285,7 +328,7 @@ audio - media_plugin_quicktime + media_plugin_libvlc @@ -296,7 +339,7 @@ audio - media_plugin_quicktime + media_plugin_libvlc @@ -307,7 +350,7 @@ audio - media_plugin_quicktime + media_plugin_libvlc @@ -318,7 +361,7 @@ image - media_plugin_webkit + media_plugin_cef @@ -329,7 +372,7 @@ image - media_plugin_webkit + media_plugin_cef @@ -340,7 +383,7 @@ image - media_plugin_webkit + media_plugin_cef @@ -351,7 +394,7 @@ image - media_plugin_webkit + media_plugin_cef @@ -362,7 +405,7 @@ image - media_plugin_webkit + media_plugin_cef @@ -373,7 +416,7 @@ image - media_plugin_webkit + media_plugin_cef @@ -384,8 +427,8 @@ web - media_plugin_webkit - + media_plugin_cef + @@ -406,7 +449,7 @@ text - media_plugin_webkit + media_plugin_cef @@ -417,8 +460,8 @@ movie - media_plugin_quicktime - + media_plugin_libvlc + + + + + movie + + + media_plugin_libvlc - + @@ -439,8 +493,8 @@ movie - media_plugin_quicktime - + media_plugin_libvlc + diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 12a4cb8904..dfc144343d 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -8,7 +8,17 @@ settings_sh.xml settings_rlv.xml - + SinguOffsetScrollKeys + + Comment + Enable keys to modify camera and focus offsets + Persist + 1 + Type + Boolean + Value + 0 + PhoenixIMAnnounceStealFocus Comment @@ -45,11 +55,14 @@ SGAllowRiggedMeshSelection Comment - Allow selection of your worn rigged meshes in build mode + Rigged mesh selection behavior: +0 = Never select, +1 = Hold shift to select, +2 = Hold shift or have build or inspect floater open Persist 1 Type - Boolean + S32 Value 0 @@ -76,18 +89,6 @@ 0 - SianaRenderDeferredInvisiprim - - Comment - Support invisiprims in deferred mode - Persist - 1 - Type - Boolean - Value - 1 - - SianaVoidWaterSubdivision Comment @@ -210,61 +211,44 @@ 100 - zmm_deffov + ExodusAlternativeFOV Comment - Default field of viewer for right click mouse zoom. + Adjusted when scrolling back and forth while holding rightclick in mouselook (Zoomed in < 1.037 < Zoomed out) Persist 1 Type F32 Value - 1.0 + 0.5 - zmm_mlfov + + AllowLargeSounds Comment - 1=Normal, Under 1 Zoom Out, Over 1 Zoom in + Bypass stricter sound size/sample checks, which were introduced in SL2.x, for sound decoding. Persist 1 Type - F32 - Value - 1 - - zmm_isinml - - Comment - mouselook - Persist - 0 - Type - Boolean - Value - 0 - - zmm_rightmousedown - - Comment - insert rude comment here - Persist - 0 - Type Boolean Value 0 - - AllowLargeSounds + FloaterAvatarRect Comment - Bypass stricter sound size/sample checks, which were introduced in SL2.x, for sound decoding. + Avatar picker floater position Persist 1 Type - Boolean + Rect Value - 0 + + 30 + 505 + 580 + 275 + FloaterAvatarTextRect @@ -368,17 +352,6 @@ - MediaEnableFilter - - Comment - Enable media domain filtering - Persist - 1 - Type - Boolean - Value - 1 - MediaFilterRect Comment @@ -484,6 +457,8 @@ Boolean Value 0 + IsCOA + 1 AOAdvanced @@ -506,6 +481,34 @@ Boolean Value 1 + IsCOA + 1 + + AOSwimEnabled + + Comment + Overrides fly animations with swims when underwater. + Persist + 1 + Type + Boolean + Value + 1 + IsCOA + 1 + + AOSwimForced + + Comment + Sets AOSwimEnabled to true, and plays swims instead of flies, even if not underwater. + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 AONoStandsInMouselook @@ -581,22 +584,11 @@ Value - ShowcaseURLDefault - - Comment - URL to load for the Showcase tab in Second Life - Persist - 1 - Type - String - Value - http://secondlife.com/app/showcase/index.php? - CheckForGridUpdates Comment - Fetch list of grids from Hippo server + Fetch list of grids from location set in GridUpdateList Persist 1 Type @@ -615,6 +607,17 @@ Value Second Life + GridUpdateList + + Comment + URL to fetch Grid updates from + Persist + 1 + Type + String + Value + + VivoxLicenseAccepted @@ -663,76 +666,85 @@ Value 0 - LiruContinueFlyingOnUnsit + LiruBlockConferences Comment - Fly after standing up, if you were flying when you sat down + When not zero, new incoming conference chats will not be opened, if 2 only those from nonfriends will be blocked. Persist 1 Type - Boolean + U32 Value 0 - LiruGroupNoticeTimes + LiruContinueFlyingOnUnsit Comment - Append timestamp to date in the lists of past group notices + Fly after standing up, if you were flying when you sat down Persist 1 Type Boolean Value - 0 + 0 - LiruItalicizeActions + LiruCrosshairColor Comment - When enabled, /me chat will be italicized. + Color of crosshairs in mouselook Persist 1 Type - Boolean + Color4 Value - 0 + + 1.0 + 1.0 + 1.0 + 1.0 + - LiruFlyAfterTeleport + LiruCustomizeAnim Comment - Fly after teleports + Whether or not to animate when going into appearance mode. Persist 1 Type Boolean Value - 0 + 1 + IsCOA + 1 - LiruLegacyLandmarks + LiruGridInTitle Comment - When creating a new landmark, the legacy format (parcel name, region name (x, y, z)) will be used. + Show grid name in the viewer window title (takes effect upon next login) Persist 1 Type Boolean Value + 0 + IsCOA 1 - LiruLegacyOutfitStoreObjChanges + LiruGroupNoticeTimes Comment - While true, automatic detach is performed upon all copyable attachments just before legacy outfit creation to preserve any modifications to them. As a last resort, setting this false allows creating a legacy outfit that won't save changes made to copyable attachments since wearing them or login. + Append timestamp to date in the lists of past group notices Persist 1 Type Boolean Value - 1 + 0 - LiruLegacySpeakerNames + LiruItalicizeActions Comment - Whether all lists of speakers use legacy names, or your desired way of displaying names. + When enabled, /me chat will be italicized. Persist 1 Type @@ -740,10 +752,10 @@ Value 0 - LiruMapShowAvCount + LiruFlyAfterTeleport Comment - Whether or not to display the count of avatars in each region on the world map as part of the region name and maturity label. + Fly after teleports Persist 1 Type @@ -751,21 +763,21 @@ Value 0 - LiruNewARCLimit + LiruHighlightNewInventory Comment - The high threshold number used to calculate the colors displayed for new ARC numbers, when LiruSensibleARC is false. Default is 20000. + When false, new inventory items will not be highlighted upon being accepted. Persist 1 Type - U32 + Boolean Value - 20000 + 1 - LiruNoTransactionClutter + LiruLegacyDisplayMuteds Comment - Use notifytips for transactions instead of notifys, this way they do not collect in the top right of the screen. + When off, muted people will go unrendered... Persist 1 Type @@ -773,10 +785,10 @@ Value 0 - LiruScriptErrorsStealFocus + LiruLegacyLandmarks Comment - When false, scripts that have errors won't steal focus once they've been failed to compile + When creating a new landmark, the legacy format (parcel name, region name (x, y, z)) will be used. Persist 1 Type @@ -784,259 +796,249 @@ Value 1 - LiruSensibleARC + LiruLegacyLogLaunch Comment - Use the old-style way to calculate Avatar Render Cost. -Found in Advanced->Rendering->Info Displays + When opening a chat log, open in an external text editor instead of a browser floater(Windows and Mac Only). Persist 1 Type Boolean Value - 1 + 1 - LiruShowLastNameResident + LiruLegacyOutfitAllLinks Comment - Whether or not to bypass stripping out the last name Resident + Legacy outfits in clothing folder, completely made of links.. no other settings will apply for legacy outfits as they'll all be links. Persist 1 Type Boolean Value - 0 + 0 - ContactsUseHorizontalButtons + LiruLegacyOutfitStoreObjChanges Comment - Whether or not groups and friends lists use horizontal buttons at the bottom of the panel or vertical ones on the right, requires a restart. + While true, automatic detach is performed upon all copyable attachments just before legacy outfit creation to preserve any modifications to them. As a last resort, setting this false allows creating a legacy outfit that won't save changes made to copyable attachments since wearing them or login. Persist 1 Type Boolean Value - 0 + 1 - FakeAway + LiruLegacyScrollToEnd - HideFromEditor - 1 + Comment + Automatically scroll to the end of a chat's history when the chat regains focus. Persist - 0 + 1 Type Boolean Value 0 - FloaterUnfocusedBackgroundOpaque + LiruLocalTime Comment - Disables floaters going transparent when not in focus, may conflict with some skins, though. + Whether or not to display system time in the top bar instead of server time. Persist 1 Type Boolean Value - 0 + 0 - InstantMessageLogPathAnyAccount + LiruMapShowAvCount Comment - Path to your log files if you've never set the path while logged in on this account. + Whether or not to display the count of avatars in each region on the world map as part of the region name and maturity label. Persist 1 Type - String + Boolean Value - + 1 - UseConciseIMButtons + LiruMiniBuildFloater Comment - Whether or not IMs use buttons concisely on the same line as the name of the receiver, changes apply to new IMs only. + Whether or not the build tools floater is tinified (except in Land tool) Persist 1 Type Boolean Value - 0 + 0 - UseConciseGroupChatButtons + LiruMouselookHidesFloaters Comment - Whether or not group chats use buttons concisely on the same line as the group name, changes apply to new group chats only. + Whether or not floaters open during third person will be hidden while in mouselook Persist 1 Type Boolean Value - 0 + 1 - UseConciseConferenceButtons + LiruMouselookHidesMenubar Comment - Whether or not conferences use buttons concisely on the same line as the name of the conference, changes apply to new conferences only. + Whether or not the main menu bar will be hidden in mouselook Persist 1 Type Boolean Value - 0 + 1 - ShowLocalChatFloaterBar + LiruMouselookHidesNotices Comment - Whether or not local chat should have an input bar when undocked. + Whether or not notices will be hidden in mouselook Persist 1 Type Boolean Value - 1 + 0 - OtherChatsTornOff + LiruMouselookHidesToolbar Comment - When true, chats other than local chat open torn off of the Communicate window. + Whether or not the toolbar will be hidden in mouselook Persist 1 Type Boolean Value - 0 + 1 - OtherChatsTornOffAndMinimized + LiruMouselookInstantZoom Comment - When this and OtherChatsTornOff are true, new chats open torn off and minimized. + Whether or not the right click zoom in mouselook will be instant or smoothly transition between zooms Persist 1 Type Boolean Value - 1 + 0 - CommunicateSpecificShortcut + LiruMouselookMenu Comment - When true, the keyboard shortcut for Communicate will not bring up the torn off Friends List. + Controls if holding Alt and right clicking in mouselook will bring up a menu Persist 1 Type Boolean Value - 0 + 1 - MarketImporterUpdateFreq + LiruNewARCLimit Comment - How fast, in seconds, the Merchant Outbox will update through all phases -This should be as low as possible, but too low may break functionality + The high threshold number used to calculate the colors displayed for new ARC numbers, when LiruSensibleARC is false. Default is 20000. Persist 1 Type - F32 + U32 Value - 60.0 + 20000 - NewIMsPerConversation + LiruNewMessageSound Comment - The New IMs button in the bottom left will show the count of unread conversations instead of the total count of unread IMs if this is true. + Sound ID to play when ding is on for an IM session and an IM comes in. Persist 1 Type - Boolean + String Value - 0 + 67cc2844-00f3-2b3c-b991-6418d01e1bb7 + IsCOA + 1 - ResetFocusOnSelfClick - - Comment - Setting this to TRUE resets your camera when you left-click your avatar - Persist - 1 - Type - Boolean - Value - 1 - - ShowDisplayNameChanges + LiruNewMessageSoundForSystemMessages Comment - Show a notification when someone changes their display name + Sound ID to play when ding is on for an IM session and a system message comes through, like when the correspondent starts typing or logs off. (Defaults to off) Persist 1 Type - Boolean + String Value + + IsCOA 1 - ShowSimChannel + LiruNewMessageSoundIMsOn Comment - Show the channel information for the current sim in the status bar + Whether or not ding defaults to being on for new IMs. Persist 1 Type Boolean Value - 0 + 0 + IsCOA + 1 - ShowUnreadIMsCounts + LiruNoTransactionClutter Comment - Show the count of unread IMs in the communicate flyout list + Use notifytips for transactions instead of notifys, this way they do not collect in the top right of the screen. Persist 1 Type Boolean Value - 1 + 0 - StatusBarPositionBeforeParcel + LiruOnlineNotificationBehavior Comment - Show your position coordinates before the name of the parcel in the status bar + Determines if Friend is Online notifications will do anything when clicked. (0 does nothing, 1 starts an IM (default), 2 opens profile. Persist 1 Type - Boolean + S32 Value - 0 + 1 - MoyFastMiniMap + LiruRegionRestartMinimized Comment - Don't show buildings on mini-map + Whether or not to spawn the region restart notice minimized (Useful for sim owners and people who need to pack up before leaving) Persist 1 Type Boolean Value 0 + IsCOA + 1 - BeauchampFloaterGroupTitlesRect + LiruResizeRootWithScreen Comment - Rectangle for group titles window + When false, the ui view won't resize when the screen does (floaters won't move around without user interaction, but they also might be restricted from moving everywhere). Persist 1 Type - Rect + Boolean Value - - 0 - 400 - 500 - 0 - + 1 - OptionShowGroupNameInChatIM + LiruScriptErrorsStealFocus Comment - Show group name in IM notification + When false, scripts that have errors won't steal focus once they've been failed to compile Persist 1 Type @@ -1044,21 +1046,22 @@ This should be as low as possible, but too low may break functionality Value 1 - OptionPlayTpSound + LiruSensibleARC Comment - Play sound effect on teleport + Use the old-style way to calculate Avatar Render Cost. +Found in Advanced->Rendering->Info Displays Persist 1 Type Boolean Value - 1 + 0 - OptionRotateCamAfterLocalTP + LiruShowLastNameResident Comment - Play sound effect on teleport + Whether or not to bypass stripping out the last name Resident Persist 1 Type @@ -1066,87 +1069,87 @@ This should be as low as possible, but too low may break functionality Value 0 - OptionOffsetTPByAgentHeight + LiruShowTransactionThreshold Comment - Play sound effect on teleport + Threshold of money changes before which transaction notifications will not be shown. Persist 1 Type - Boolean + U32 Value - 1 + 0 - AnnounceSnapshots + LiruUseAdvancedMenuShortcut Comment - Announce if someone nearby has taken a snapshot in chat (Won't work on people who hide/quiet snapshots) + Use ctrl-alt(-shift)-d to toggle the advanced menu. Persist 1 Type Boolean Value - 0 + 1 - AnnounceStreamMetadata + LiruUseContextMenus Comment - Announce the metadata of the track playing, in chat, during streams. + Use context menus instead of the default pie menus we all know and love. Persist 1 Type Boolean Value - 0 + 0 - InventorySortOrder + LiruUseZQSDKeys Comment - Specifies sort key for inventory items (+0 = name, +1 = date, +2 = folders always by name, +4 = system folders to top) + Use ZQSD layout instead of WASD. + Persist + 1 Type - U32 + Boolean Value - 3 + 0 - Blacklist.Settings + SFMapShowRegionPositions Comment - List for blacklisting assets DO NOT EDIT DIRECTLY use the floater + Shows the X and Y coordinates above the sim name in the world map. Persist 1 Type - LLSD + Boolean Value - - - + 0 - LinksForChattingObjects + SLBShowFPS Comment - Show links for chatting objects (0=no, 1=for others' objects, 2=for all objects) + Show FPS Persist 1 Type - U32 + Boolean Value - 0 + 0 - DisablePointAtAndBeam + SLBDisplayClientTagOnNewLine Comment - Disable pointing at objects and the pointat beam + Display the client tag on a new line Persist 1 Type Boolean Value - 0 + 1 - PrivateLookAt + UseRealisticMouselook Comment - When TRUE, do not disclose what we are looking at + Use a realistic first person view, this prevents your camera from being the center of everything and your avatar always beeing locked below you, it allows your Avatar to move around freely in mouselook while your camera will follow it around. Prepare your seatbelts for an awesome shaky View! May break with certain super unrealistic animations. Persist 1 Type @@ -1154,109 +1157,126 @@ This should be as low as possible, but too low may break functionality Value 0
    - BroadcastViewerEffects + LogShowHistoryLines Comment - Broadcast Viewer Effects + Lines of history to load from log file if LogShowHistory is true. Persist 1 Type - Boolean + U32 Value + 32 + IsCOA 1 - TurnAroundWhenWalkingBackwards + ContactsUseHorizontalButtons Comment - Turn your avatar around to face the camera while walking backwards. + Whether or not groups and friends lists use horizontal buttons at the bottom of the panel or vertical ones on the right, requires a restart. Persist 1 Type Boolean Value + 0 + + FakeAway + + HideFromEditor 1 + Persist + 0 + Type + Boolean + Value + 0 - EmeraldBoobMass + FSSynchronizeTextureMaps Comment - Mass of boobs. + Align texture maps (texture, bumpy, shiny) across the faces of a prim Persist 1 Type - F32 + Boolean Value - 54.0 + 1 - EmeraldBoobHardness + LocalBitmapUpdate Comment - Hardness (dampening) of boobs. + Default setting for whether local textures should update or not upon change, changed by toggling on or off. Persist 1 Type - F32 + Boolean Value - 51 + 1 - EmeraldBreastPhysicsToggle + InstantMessageLogPathAnyAccount Comment - Enables/Disables breast physics + Path to your log files if you've never set the path while logged in on this account. Persist 1 Type - Boolean + String Value - 0 + - EmeraldBoobVelMax + ScriptMessageAPI Comment - Max amount of velocity boobs can have + Channel used for interaction with the Script Message API Persist 1 Type - F32 + S32 Value - 64 + 0 + IsCOA + 1 - EmeraldBoobFriction + ScriptMessageAPIKey Comment - Internal friction (brings boobs to rest). Shouldn't ever be above 1. + Key to encode messages sent to the Script Message API Persist 1 Type - F32 + String Value - 80 + Enter Key Here + IsCOA + 1 - EmeraldBoobVelMin + UseConciseIMButtons Comment - Friction Fraction of FPS (used to keep friction uniform through FPS change). + Whether or not IMs use buttons concisely on the same line as the name of the receiver, changes apply to new IMs only. Persist 1 Type - F32 + Boolean Value - 24 + 0 - EmeraldBoobXYInfluence + UseConciseGroupChatButtons Comment - Amount of influence along the X and Y planes. + Whether or not group chats use buttons concisely on the same line as the group name, changes apply to new group chats only. Persist 1 Type - F32 + Boolean Value - 0.1 + 0 - wlfAdvSettingsPopup + UseConciseConferenceButtons Comment - Show Windlight popup + Whether or not conferences use buttons concisely on the same line as the name of the conference, changes apply to new conferences only. Persist 1 Type @@ -1264,10 +1284,10 @@ This should be as low as possible, but too low may break functionality Value 0 - WoLfVerticalIMTabs + ShowLocalChatFloaterBar Comment - Vertical IM Tabs + Whether or not local chat should have an input bar when undocked. Persist 1 Type @@ -1275,10 +1295,10 @@ This should be as low as possible, but too low may break functionality Value 1 - AntiSpamAlerts + ShowMutedText Comment - When true, dialogs from alerts will be blocked. + Whether or not to show chat from muted people in local chat. Persist 1 Type @@ -1286,10 +1306,10 @@ This should be as low as possible, but too low may break functionality Value 0 - AntiSpamEnabled + OtherChatsTornOff Comment - When false, antispam, not relating to dialog blocking, will be turned off. + When true, chats other than local chat open torn off of the Communicate window. Persist 1 Type @@ -1297,21 +1317,21 @@ This should be as low as possible, but too low may break functionality Value 0 - AntiSpamFriendshipOffers + OtherChatsTornOffAndMinimized Comment - When true, dialogs from friendship requests will be blocked. + When this and OtherChatsTornOff are true, new chats open torn off and minimized. Persist 1 Type Boolean Value - 0 + 1 - AntiSpamGroupInvites + CommunicateSpecificShortcut Comment - When true, dialogs from group invites will be blocked. + When true, the keyboard shortcut for Communicate will not bring up the torn off Friends List. Persist 1 Type @@ -1319,65 +1339,77 @@ This should be as low as possible, but too low may break functionality Value 0 - AntiSpamGroupFeeInvites + MarketImporterUpdateFreq Comment - When true, dialogs from group invites that require an entry fee will be blocked. + How fast, in seconds, the Merchant Outbox will update through all phases +This should be as low as possible, but too low may break functionality Persist 1 Type - Boolean + F32 Value - 0 + 60.0 - AntiSpamGroupNotices + NewIMsPerConversation Comment - When true, dialogs from group notices will be blocked. + The New IMs button in the bottom left will show the count of unread conversations instead of the total count of unread IMs if this is true. Persist 1 Type Boolean Value - 0 + 0 - AntiSpamItemOffers + NewIMsPerConversationReset Comment - When true, dialogs from inventory item offers will be blocked. + When NewIMsPerConversation is on, this determines when the New IMs button becomes visible while the communicate floater is closed. True will wait until a new IM is received, false displays as long as a conversation is unread. Persist 1 Type Boolean Value - 0 + 1 - AntiSpamNotFriend + ResetFocusOnSelfClick + + Comment + Setting this to TRUE resets your camera when you left-click your avatar + Persist + 1 + Type + Boolean + Value + 1 + + ResetViewTurnsAvatar Comment - When true, dialogs from friends will not be blocked unless the _NACL_Antispam is true. + When true, resetting view by hitting escape or using the menu entry will turn your avatar to the direction the camera was pointed Persist 1 Type Boolean Value - 0 + 0 - AntiSpamNotMine + RightClickTurnsAvatar Comment - When true, dialogs from your own objects will not be blocked unless the _NACL_Antispam is true. + When false, right clicking on objects that are certain angles from the direction your avatar is facing will not turn your avatar to face them. Persist 1 Type Boolean Value - 0 + 1 - AntiSpamNotify + ShowDisplayNameChanges Comment - When true, notifications will appear any time a spamtype is blocked. + Show a notification when someone changes their display name Persist 1 Type @@ -1385,10 +1417,10 @@ This should be as low as possible, but too low may break functionality Value 1 - AntiSpamScripts + ShowSimChannel Comment - When true, dialogs from scripts, including script-driven teleports and questions, and other interactive script stuff, will be blocked. + Show the channel information for the current sim in the status bar Persist 1 Type @@ -1396,21 +1428,21 @@ This should be as low as possible, but too low may break functionality Value 0 - AntiSpamTeleportRequests + ShowUnreadIMsCounts Comment - When true, dialogs from teleport requests from other residents will be blocked. + Show the count of unread IMs in the communicate flyout list Persist 1 Type Boolean Value - 0 + 1 - AntiSpamTeleports + StatusBarPositionBeforeParcel Comment - When true, dialogs from teleport offers from other residents will be blocked. + Show your position coordinates before the name of the parcel in the status bar Persist 1 Type @@ -1418,656 +1450,513 @@ This should be as low as possible, but too low may break functionality Value 0 - _NACL_Antispam + ShowMiniMapObjects Comment - When true, all dialogs will be blocked, resets on restart. + Show buildings and megaprims on the mini-map Persist - 0 + 1 Type Boolean Value - 0 + 1 - _NACL_AntiSpamGlobalQueue + BeauchampFloaterGroupTitlesRect - Comment - Collect spamtypes together, instead of individually counting them; Use in cases of extreme spam, only. - Persist - 1 - Type - Boolean - Value + Comment + Rectangle for group titles window + Persist + 1 + Type + Rect + Value + + 0 + 400 + 500 0 + - _NACL_AntiSpamTime - - Comment - Time in seconds for spamtype to accumulate to more than _NACL_AntiSpamAmount and be blocked - Persist - 1 - Type - U32 - Value - 1 - - _NACL_AntiSpamAmount - - Comment - Count of spamtype to be reached during _NACL_AntiSpamTime before the spam blocking will occur. - Persist - 1 - Type - U32 - Value - 30 - - _NACL_AntiSpamSoundMulti - - Comment - Multiplier for _NACL_AntiSpamTime for sounds heard in _NACL_AntiSpamTime interval needed to trigger a block, since sounds are more common than messages - Persist - 1 - Type - U32 - Value - 100 - - _NACL_AntiSpamNewlines - - Comment - How many newlines a message is allowed to have without being considered spam. - Persist - 1 - Type - U32 - Value - 70 - - _NACL_AntiSpamSoundPreloadMulti - - Comment - Multiplier for _NACL_AntiSpamTime for sounds preloaded in _NACL_AntiSpamTime interval needed to trigger a block, since sound preloads are more common than messages - Persist - 1 - Type - U32 - Value - 100 - - - AgentChatColor + OptionShowGroupNameInChatIM Comment - Color of chat messages from other residents + Show group name in IM notification Persist 1 Type - Color4 + Boolean Value - - 1.0 - 1.0 - 1.0 - 1.0 - - IsCOA - 1 + 1 - BackgroundChatColor + OptionPlayTpSound Comment - Color of chat bubble background + Play sound effect on teleport Persist 1 Type - Color4 + Boolean Value - - 0.0 - 0.0 - 0.0 - 1.0 - - IsCOA - 1 + 1 - EffectColor + OptionRotateCamAfterLocalTP Comment - Particle effects color + Play sound effect on teleport Persist 1 Type - Color4 + Boolean Value - - 1.0 - 1.0 - 1.0 - 1.0 - - IsCOA - 1 + 0 - IMChatColor + OptionOffsetTPByAgentHeight Comment - Color of instant messages from other residents + Play sound effect on teleport Persist 1 Type - Color4 + Boolean Value - - 1.0 - 1.0 - 1.0 - 1.0 - - IsCOA - 1 + 1 - llOwnerSayChatColor + AnnounceBumps Comment - Color of chat messages from objects only visible to the owner + Announce if someone bumps into you. Persist 1 Type - Color4 + Boolean Value - - 0.990000009537 - 0.990000009537 - 0.689999997616 - 1.0 - - IsCOA - 1 + 0 - ObjectChatColor + AnnounceSnapshots Comment - Color of chat messages from objects + Announce if someone nearby has taken a snapshot in chat (Won't work on people who hide/quiet snapshots) Persist 1 Type - Color4 + Boolean Value - - 0.699999988079 - 0.899999976158 - 0.699999988079 - 1 - - IsCOA - 1 + 0 - SkinCurrent + AnnounceStreamMetadata Comment - The currently selected skin. + Announce the metadata of the track playing, in chat, during streams. Persist 1 Type - String + Boolean Value - dark - IsCOA - 1 + 0 - SystemChatColor + Blacklist.Settings Comment - Color of chat messages from SL System + List for blacklisting assets DO NOT EDIT DIRECTLY use the floater Persist 1 Type - Color4 + LLSD Value - 0.800000011921 - 1.0 - 1.0 - 1.0 + - IsCOA - 1 - UISndAlert + LinksForChattingObjects Comment - Sound file for alerts (uuid for sound asset) + Show links for chatting objects (0=no, 1=for others' objects, 2=for all objects) Persist 1 Type - String + U32 Value - ed124764-705d-d497-167a-182cd9fa2e6c - IsCOA - 1 + 0 - UISndBadKeystroke + DisablePointAtAndBeam Comment - Sound file for invalid keystroke (uuid for sound asset) + Disable pointing at objects and the pointat beam Persist 1 Type - String + Boolean Value - 2ca849ba-2885-4bc3-90ef-d4987a5b983a - IsCOA - 1 + 0 - UISndClick + PrivateLookAt Comment - Sound file for mouse click (uuid for sound asset) + When TRUE, do not disclose what we are looking at Persist 1 Type - String + Boolean Value - 4c8c3c77-de8d-bde2-b9b8-32635e0fd4a6 - IsCOA - 1 + 0 - UISndClickRelease + BroadcastViewerEffects Comment - Sound file for mouse button release (uuid for sound asset) + Broadcast Viewer Effects Persist 1 Type - String + Boolean Value - 4c8c3c77-de8d-bde2-b9b8-32635e0fd4a6 - IsCOA - 1 + 1 - UISndDebugSpamToggle + TurnAroundWhenWalkingBackwards Comment - Log UI sound effects as they are played + Turn your avatar around to face the camera while walking backwards. Persist 1 Type Boolean Value - 0 - IsCOA - 1 + 1 - UISndHealthReductionF + EmeraldBoobMass Comment - Sound file for female pain (uuid for sound asset) + Mass of boobs. Persist 1 Type - String + F32 Value - 219c5d93-6c09-31c5-fb3f-c5fe7495c115 - IsCOA - 1 + 54.0 - UISndHealthReductionM + EmeraldBoobHardness Comment - Sound file for male pain (uuid for sound asset) + Hardness (dampening) of boobs. Persist 1 Type - String + F32 Value - e057c244-5768-1056-c37e-1537454eeb62 - IsCOA - 1 + 51 - UISndHealthReductionThreshold + EmeraldBreastPhysicsToggle Comment - Amount of health reduction required to trigger "pain" sound + Enables/Disables breast physics Persist 1 Type - F32 + Boolean Value - 10.0 - IsCOA - 1 + 0 - UISndInvalidOp + EmeraldBoobVelMax Comment - Sound file for invalid operations (uuid for sound asset) + Max amount of velocity boobs can have Persist 1 Type - String + F32 Value - 4174f859-0d3d-c517-c424-72923dc21f65 - IsCOA - 1 + 64 - UISndMoneyChangeDown + EmeraldBoobFriction Comment - Sound file for L$ balance increase (uuid for sound asset) + Internal friction (brings boobs to rest). Shouldn't ever be above 1. Persist 1 Type - String + F32 Value - 104974e3-dfda-428b-99ee-b0d4e748d3a3 - IsCOA - 1 + 80 - UISndMoneyChangeThreshold + EmeraldBoobVelMin Comment - Amount of change in L$ balance required to trigger "money" sound + Friction Fraction of FPS (used to keep friction uniform through FPS change). Persist 1 Type F32 Value - 50.0 - IsCOA - 1 + 24 - UISndMoneyChangeUp + EmeraldBoobXYInfluence Comment - Sound file for L$ balance decrease(uuid for sound asset) + Amount of influence along the X and Y planes. Persist 1 Type - String + F32 Value - 77a018af-098e-c037-51a6-178f05877c6f - IsCOA - 1 + 0.1 - UISndNewIncomingIMSession + wlfAdvSettingsPopup Comment - Sound file for new instant message session(uuid for sound asset) + Show Windlight popup Persist 1 Type - String + Boolean Value - 67cc2844-00f3-2b3c-b991-6418d01e1bb7 - IsCOA - 1 + 0 - UISndObjectCreate + WoLfVerticalIMTabs Comment - Sound file for object creation (uuid for sound asset) + Vertical IM Tabs Persist 1 Type - String + Boolean Value - f4a0660f-5446-dea2-80b7-6482a082803c - IsCOA - 1 - - UISndObjectDelete - - Comment - Sound file for object deletion (uuid for sound asset) - Persist 1 - Type - String - Value - 0cb7b00a-4c10-6948-84de-a93c09af2ba9 - IsCOA - 1 - UISndObjectRezIn + AntiSpamAlerts Comment - Sound file for rezzing objects (uuid for sound asset) + When true, dialogs from alerts will be blocked. Persist 1 Type - String + Boolean Value - 3c8fc726-1fd6-862d-fa01-16c5b2568db6 - IsCOA - 1 + 0 - UISndObjectRezOut + AntiSpamEnabled Comment - Sound file for derezzing objects (uuid for sound asset) + When false, antispam, not relating to dialog blocking, will be turned off. Persist 1 Type - String + Boolean Value - 00000000-0000-0000-0000-000000000000 - IsCOA - 1 + 0 - UISndPieMenuAppear + AntiSpamFriendshipOffers Comment - Sound file for opening pie menu (uuid for sound asset) + When true, dialogs from friendship requests will be blocked. Persist 1 Type - String + Boolean Value - 8eaed61f-92ff-6485-de83-4dcc938a478e - IsCOA - 1 + 0 - UISndPieMenuHide + AntiSpamGroupInvites Comment - Sound file for closing pie menu (uuid for sound asset) + When true, dialogs from group invites will be blocked. Persist 1 Type - String + Boolean Value - 00000000-0000-0000-0000-000000000000 - IsCOA - 1 + 0 - UISndPieMenuSliceHighlight0 + AntiSpamGroupFeeInvites Comment - Sound file for selecting pie menu item 0 (uuid for sound asset) + When true, dialogs from group invites that require an entry fee will be blocked. Persist 1 Type - String + Boolean Value - d9f73cf8-17b4-6f7a-1565-7951226c305d - IsCOA - 1 + 0 - UISndPieMenuSliceHighlight1 + AntiSpamGroupNotices Comment - Sound file for selecting pie menu item 1 (uuid for sound asset) + When true, dialogs from group notices will be blocked. Persist 1 Type - String + Boolean Value - f6ba9816-dcaf-f755-7b67-51b31b6233e5 - IsCOA - 1 + 0 - UISndPieMenuSliceHighlight2 + AntiSpamItemOffers Comment - Sound file for selecting pie menu item 2 (uuid for sound asset) + When true, dialogs from inventory item offers will be blocked. Persist 1 Type - String + Boolean Value - 7aff2265-d05b-8b72-63c7-dbf96dc2f21f - IsCOA - 1 + 0 - UISndPieMenuSliceHighlight3 + AntiSpamItemOffersLandmarks Comment - Sound file for selecting pie menu item 3 (uuid for sound asset) + When AntiSpamItemOffers is false but this is true, dialogs from inventory item offers of landmarks will be blocked. Persist 1 Type - String + Boolean Value - 09b2184e-8601-44e2-afbb-ce37434b8ba1 - IsCOA - 1 + 0 - UISndPieMenuSliceHighlight4 + AntiSpamNotFriend Comment - Sound file for selecting pie menu item 4 (uuid for sound asset) + When true, dialogs from friends will not be blocked unless the _NACL_Antispam is true. Persist 1 Type - String + Boolean Value - bbe4c7fc-7044-b05e-7b89-36924a67593c - IsCOA - 1 + 0 - UISndPieMenuSliceHighlight5 + AntiSpamNotMine Comment - Sound file for selecting pie menu item 5 (uuid for sound asset) + When true, dialogs from your own objects will not be blocked unless the _NACL_Antispam is true. Persist 1 Type - String + Boolean Value - d166039b-b4f5-c2ec-4911-c85c727b016c - IsCOA - 1 + 0 - UISndPieMenuSliceHighlight6 + AntiSpamNotify Comment - Sound file for selecting pie menu item 6 (uuid for sound asset) + When true, notifications will appear any time a spamtype is blocked. Persist 1 Type - String + Boolean Value - 242af82b-43c2-9a3b-e108-3b0c7e384981 - IsCOA - 1 - - UISndPieMenuSliceHighlight7 - - Comment - Sound file for selecting pie menu item 7 (uuid for sound asset) - Persist 1 - Type - String - Value - c1f334fb-a5be-8fe7-22b3-29631c21cf0b - IsCOA - 1 - UISndSnapshot + AntiSpamScripts Comment - Sound file for taking a snapshot (uuid for sound asset) + When true, dialogs from scripts, including script-driven teleports and questions, and other interactive script stuff, will be blocked. Persist 1 Type - String + Boolean Value - 3d09f582-3851-c0e0-f5ba-277ac5c73fb4 - IsCOA - 1 + 0 - UISndStartIM + AntiSpamTeleportRequests Comment - Sound file for starting a new IM session (uuid for sound asset) + When true, dialogs from teleport requests from other residents will be blocked. Persist 1 Type - String + Boolean Value - c825dfbc-9827-7e02-6507-3713d18916c1 - IsCOA - 1 + 0 - UISndTeleportOut + AntiSpamTeleports Comment - Sound file for teleporting (uuid for sound asset) + When true, dialogs from teleport offers from other residents will be blocked. Persist 1 Type - String + Boolean Value - d7a9a565-a013-2a69-797d-5332baa1a947 - IsCOA - 1 + 0 - UISndTyping + _NACL_Antispam Comment - Sound file for starting to type a chat message (uuid for sound asset) + When true, all dialogs will be blocked, resets on restart. Persist - 1 + 0 Type - String + Boolean Value - 5e191c7b-8996-9ced-a177-b2ac32bfea06 - IsCOA - 1 + 0 - UISndWindowClose + _NACL_AntiSpamGlobalQueue - Comment - Sound file for closing a window (uuid for sound asset) - Persist - 1 - Type - String - Value - 2c346eda-b60c-ab33-1119-b8941916a499 - IsCOA - 1 + Comment + Collect spamtypes together, instead of individually counting them; Use in cases of extreme spam, only. + Persist + 1 + Type + Boolean + Value + 0 - UISndWindowOpen + _NACL_AntiSpamTime - Comment - Sound file for opening a window (uuid for sound asset) - Persist - 1 - Type - String - Value - c80260ba-41fd-8a46-768a-6bf236360e3a - IsCOA - 1 + Comment + Time in seconds for spamtype to accumulate to more than _NACL_AntiSpamAmount and be blocked + Persist + 1 + Type + U32 + Value + 1 - UserChatColor - - Comment - Color of your chat messages + _NACL_AntiSpamAmount + + Comment + Count of spamtype to be reached during _NACL_AntiSpamTime before the spam blocking will occur. + Persist + 1 + Type + U32 + Value + 30 + + _NACL_AntiSpamSoundMulti + + Comment + Multiplier for _NACL_AntiSpamTime for sounds heard in _NACL_AntiSpamTime interval needed to trigger a block, since sounds are more common than messages + Persist + 1 + Type + U32 + Value + 100 + + _NACL_AntiSpamNewlines + + Comment + How many newlines a message is allowed to have without being considered spam. + Persist + 1 + Type + U32 + Value + 70 + + _NACL_AntiSpamSoundPreloadMulti + + Comment + Multiplier for _NACL_AntiSpamTime for sounds preloaded in _NACL_AntiSpamTime interval needed to trigger a block, since sound preloads are more common than messages + Persist + 1 + Type + U32 + Value + 100 + + + AgentChatColor + + Comment + Color of chat messages from other residents Persist 1 Type @@ -2079,685 +1968,809 @@ This should be as low as possible, but too low may break functionality 1.0 1.0 - IsCOA - 1 + IsCOA + 1 - - AFKTimeout + BackgroundChatColor Comment - Time before automatically setting AFK (away from keyboard) mode (seconds) + Color of chat bubble background Persist 1 Type - F32 + Color4 Value - 300.0 + + 0.0 + 0.0 + 0.0 + 1.0 + + IsCOA + 1 - AdvanceSnapshot + EffectColor Comment - Display advanced parameter settings in snaphot interface + Particle effects color Persist 1 Type - Boolean + Color4 Value - 0 + + 1.0 + 1.0 + 1.0 + 1.0 + + IsCOA + 1 - AgentAppearanceServiceURL + IMChatColor Comment - Current Session Agent Appearance Service URL + Color of instant messages from other residents Persist - 0 + 1 Type - String + Color4 Value - + + 1.0 + 1.0 + 1.0 + 1.0 + + IsCOA + 1 - AlertedUnsupportedHardware + llOwnerSayChatColor Comment - Set if there's unsupported hardware and we've already done a notification. + Color of chat messages from objects only visible to the owner Persist 1 Type - Boolean + Color4 Value - 0 + + 0.990000009537 + 0.990000009537 + 0.689999997616 + 1.0 + + IsCOA + 1 - AllowIdleAFK + ObjectChatColor Comment - Automatically set AFK (away from keyboard) mode when idle + Color of chat messages from objects Persist 1 Type - Boolean + Color4 Value - 1 + + 0.699999988079 + 0.899999976158 + 0.699999988079 + 1 + + IsCOA + 1 - AllowMultipleViewers + SkinCurrent Comment - Allow multiple viewers. + The currently selected skin. Persist 1 Type - Boolean + String Value - 1 + dark + IsCOA + 1 - AllowTapTapHoldRun + SystemChatColor Comment - Tapping a direction key twice and holding it down makes avatar run + Color of chat messages from SL System Persist 1 Type - Boolean + Color4 Value - 1 + + 0.800000011921 + 1.0 + 1.0 + 1.0 + + IsCOA + 1 - AnimateTextures + LogChatColor Comment - Enable texture animation (debug) + Color of chat messages loaded from your log Persist 1 Type - Boolean + Color4 Value - 1 + + 0.5 + 0.5 + 0.5 + 1.0 + + IsCOA + 1 - AnimationDebug + UISndAlert Comment - Show active animations in a bubble above avatars head + Sound file for alerts (uuid for sound asset) Persist 1 Type - Boolean + String Value - 0 + ed124764-705d-d497-167a-182cd9fa2e6c + IsCOA + 1 - PreviewAnimInWorld + UISndBadKeystroke Comment - Play animation preview in-world when uploading + Sound file for invalid keystroke (uuid for sound asset) Persist 1 Type - Boolean + String Value - 0 + 2ca849ba-2885-4bc3-90ef-d4987a5b983a + IsCOA + 1 - AppearanceCameraMovement + UISndClick Comment - When entering appearance editing mode, camera zooms in on currently selected portion of avatar + Sound file for mouse click (uuid for sound asset) Persist 1 Type - Boolean + String Value - 1 + 4c8c3c77-de8d-bde2-b9b8-32635e0fd4a6 + IsCOA + 1 - AppearanceCloseOnEscape + UISndClickRelease Comment - When in appearance editing mode, hitting escape will work the same as the close button + Sound file for mouse button release (uuid for sound asset) Persist 1 Type - Boolean + String Value - 0 + 4c8c3c77-de8d-bde2-b9b8-32635e0fd4a6 + IsCOA + 1 - AppearanceSpecialLighting + UISndDebugSpamToggle Comment - When in appearance editing mode, avatar is shown with special lighting + Log UI sound effects as they are played Persist 1 Type Boolean Value - 1 + 0 + IsCOA + 1 - ApplyColorImmediately + UISndHealthReductionF Comment - Preview selections in color picker immediately + Sound file for female pain (uuid for sound asset) Persist 1 Type - Boolean + String Value - 1 + 219c5d93-6c09-31c5-fb3f-c5fe7495c115 + IsCOA + 1 - ApplyTextureImmediately + UISndHealthReductionM Comment - Preview selections in texture picker immediately + Sound file for male pain (uuid for sound asset) Persist 1 Type - Boolean + String Value - 1 + e057c244-5768-1056-c37e-1537454eeb62 + IsCOA + 1 - ArrowKeysMoveAvatar + UISndHealthReductionThreshold Comment - While cursor is in chat entry box, arrow keys still control your avatar + Amount of health reduction required to trigger "pain" sound Persist 1 Type - Boolean + F32 Value - 1 + 10.0 + IsCOA + 1 - AskedAboutCrashReports + UISndInvalidOp Comment - Turns off dialog asking if you want to enable crash reporting + Sound file for invalid operations (uuid for sound asset) Persist 1 Type - Boolean + String Value - 0 - - AuctionShowFence + 4174f859-0d3d-c517-c424-72923dc21f65 + IsCOA + 1 + + UISndMoneyChangeDown Comment - When auctioning land, include parcel boundary marker in snapshot + Sound file for L$ balance increase (uuid for sound asset) Persist 1 Type - Boolean + String Value - 1 + 104974e3-dfda-428b-99ee-b0d4e748d3a3 + IsCOA + 1 - AudioLevelAmbient + UISndMoneyChangeThreshold Comment - Audio level of environment sounds + Amount of change in L$ balance required to trigger "money" sound Persist 1 Type F32 Value - 0.5 + 50.0 + IsCOA + 1 - AudioLevelDoppler + UISndMoneyChangeUp Comment - Scale of doppler effect on moving audio sources (1.0 = normal, <1.0 = diminished doppler effect, >1.0 = enhanced doppler effect) + Sound file for L$ balance decrease(uuid for sound asset) Persist 1 Type - F32 + String Value - 1.0 + 77a018af-098e-c037-51a6-178f05877c6f + IsCOA + 1 - AudioLevelMaster + UISndNewIncomingIMSession Comment - Master audio level, or overall volume + Sound file for new instant message session(uuid for sound asset) Persist 1 Type - F32 + String Value - 1.0 + 67cc2844-00f3-2b3c-b991-6418d01e1bb7 + IsCOA + 1 - AudioLevelMedia + UISndObjectCreate Comment - Audio level of Quicktime movies + Sound file for object creation (uuid for sound asset) Persist 1 Type - F32 + String Value - 1.0 + f4a0660f-5446-dea2-80b7-6482a082803c + IsCOA + 1 - AudioLevelMic + UISndObjectDelete Comment - Audio level of microphone input + Sound file for object deletion (uuid for sound asset) Persist 1 Type - F32 + String Value - 1.0 + 0cb7b00a-4c10-6948-84de-a93c09af2ba9 + IsCOA + 1 - AudioLevelMusic + UISndObjectRezIn Comment - Audio level of streaming music + Sound file for rezzing objects (uuid for sound asset) Persist 1 Type - F32 + String Value - 1.0 + 3c8fc726-1fd6-862d-fa01-16c5b2568db6 + IsCOA + 1 - AudioLevelRolloff + UISndObjectRezOut Comment - Controls the distance-based dropoff of audio volume (fraction or multiple of default audio rolloff) + Sound file for derezzing objects (uuid for sound asset) Persist 1 Type - F32 + String Value - 1.0 + 00000000-0000-0000-0000-000000000000 + IsCOA + 1 - AudioLevelUnderwaterRolloff + UISndPieMenuAppear Comment - Controls the distance-based dropoff of audio volume when camera is submerged (fraction or multiple of default audio rolloff) + Sound file for opening pie menu (uuid for sound asset) Persist 1 Type - F32 + String Value - 4.0 + 8eaed61f-92ff-6485-de83-4dcc938a478e + IsCOA + 1 - AudioLevelSFX + UISndPieMenuHide Comment - Audio level of in-world sound effects + Sound file for closing pie menu (uuid for sound asset) Persist 1 Type - F32 + String Value - 1.0 + 00000000-0000-0000-0000-000000000000 + IsCOA + 1 - AudioLevelUI + UISndPieMenuSliceHighlight0 Comment - Audio level of UI sound effects + Sound file for selecting pie menu item 0 (uuid for sound asset) Persist 1 Type - F32 + String Value - 0.5 + d9f73cf8-17b4-6f7a-1565-7951226c305d + IsCOA + 1 - AudioLevelVoice + UISndPieMenuSliceHighlight1 Comment - Audio level of voice chat + Sound file for selecting pie menu item 1 (uuid for sound asset) Persist 1 Type - F32 + String Value - 0.5 + f6ba9816-dcaf-f755-7b67-51b31b6233e5 + IsCOA + 1 - AudioLevelWind + UISndPieMenuSliceHighlight2 Comment - Audio level of wind noise when standing still + Sound file for selecting pie menu item 2 (uuid for sound asset) Persist 1 Type - F32 + String Value - 0.075 + 7aff2265-d05b-8b72-63c7-dbf96dc2f21f + IsCOA + 1 - AudioStreamingMedia + UISndPieMenuSliceHighlight3 Comment - Enable streaming + Sound file for selecting pie menu item 3 (uuid for sound asset) Persist 1 Type - Boolean + String Value - 1 + 09b2184e-8601-44e2-afbb-ce37434b8ba1 + IsCOA + 1 - AudioStreamingMusic + UISndPieMenuSliceHighlight4 Comment - Enable streaming audio + Sound file for selecting pie menu item 4 (uuid for sound asset) Persist 1 Type - Boolean + String Value - 1 + bbe4c7fc-7044-b05e-7b89-36924a67593c + IsCOA + 1 - AuditTexture + UISndPieMenuSliceHighlight5 Comment - Enable texture auditting. + Sound file for selecting pie menu item 5 (uuid for sound asset) Persist - 0 + 1 Type - Boolean + String Value - 0 + d166039b-b4f5-c2ec-4911-c85c727b016c + IsCOA + 1 - AutoAcceptAllNewInventory + UISndPieMenuSliceHighlight6 Comment - Automatically accept new inventory, regardless of type + Sound file for selecting pie menu item 6 (uuid for sound asset) Persist 1 Type - Boolean + String Value - 0 + 242af82b-43c2-9a3b-e108-3b0c7e384981 + IsCOA + 1 - AutoAcceptNewInventory + UISndPieMenuSliceHighlight7 Comment - Automatically accept new notecards/textures/landmarks + Sound file for selecting pie menu item 7 (uuid for sound asset) Persist 1 Type - Boolean + String Value - 0 + c1f334fb-a5be-8fe7-22b3-29631c21cf0b + IsCOA + 1 - AutoLeveling + UISndRestart Comment - Keep Flycam level. + Sound file for region restarting (uuid for sound asset) Persist 1 Type - Boolean + String Value - 1 + 1e506d0c-4811-bdf3-5ec7-d624284c9040 - AutoLoadWebProfiles + UISndSnapshot Comment - Automatically load ALL profile webpages without asking first. + Sound file for taking a snapshot (uuid for sound asset) Persist 1 Type - Boolean + String Value - 0 + 3d09f582-3851-c0e0-f5ba-277ac5c73fb4 + IsCOA + 1 - AutoLogin + UISndStartIM Comment - Login automatically using last username/password combination + Sound file for starting a new IM session (uuid for sound asset) Persist - 0 + 1 Type - Boolean + String Value - 0 + c825dfbc-9827-7e02-6507-3713d18916c1 + IsCOA + 1 - AutoMimeDiscovery + UISndTeleportOut Comment - Enable viewer mime type discovery of media URLs + Sound file for teleporting (uuid for sound asset) Persist 1 Type - Boolean + String Value - 0 + d7a9a565-a013-2a69-797d-5332baa1a947 + IsCOA + 1 - AutoPilotLocksCamera + UISndTyping Comment - Keep camera position locked when avatar walks to selected position + Sound file for starting to type a chat message (uuid for sound asset) Persist 1 Type - Boolean + String Value - 0 + 5e191c7b-8996-9ced-a177-b2ac32bfea06 + IsCOA + 1 - AutoSnapshot + UISndWindowClose Comment - Update snapshot when camera stops moving, or any parameter changes + Sound file for closing a window (uuid for sound asset) Persist 1 Type - Boolean + String Value - 0 + 2c346eda-b60c-ab33-1119-b8941916a499 + IsCOA + 1 - AutomaticFly + UISndWindowOpen Comment - Fly by holding jump key or using "Fly" command (FALSE = fly by using "Fly" command only) + Sound file for opening a window (uuid for sound asset) Persist 1 Type - Boolean + String Value - 1 + c80260ba-41fd-8a46-768a-6bf236360e3a + IsCOA + 1 - AvatarAxisDeadZone0 + UserChatColor Comment - Avatar axis 0 dead zone. + Color of your chat messages Persist 1 Type - F32 + Color4 Value - 0.1 + + 1.0 + 1.0 + 1.0 + 1.0 + + IsCOA + 1 - AvatarAxisDeadZone1 + + CrashHostUrl Comment - Avatar axis 1 dead zone. + A URL pointing to a crash report handler; overrides cluster negotiation to locate crash handler. Persist 1 Type - F32 + String Value - 0.1 + - AvatarAxisDeadZone2 + AFKTimeout Comment - Avatar axis 2 dead zone. + Time before automatically setting AFK (away from keyboard) mode (seconds) Persist 1 Type F32 Value - 0.1 + 300.0 - AvatarAxisDeadZone3 + ActiveFloaterTransparency Comment - Avatar axis 3 dead zone. + Transparency of active floaters (floaters that have focus) Persist 1 Type F32 Value - 0.1 + 1 - AvatarAxisDeadZone4 + AdvanceSnapshot Comment - Avatar axis 4 dead zone. + Display advanced parameter settings in snaphot interface Persist 1 Type - F32 + Boolean Value - 0.1 + 0 - AvatarAxisDeadZone5 + AgentAppearanceServiceURL Comment - Avatar axis 5 dead zone. + Current Session Agent Appearance Service URL Persist - 1 + 0 Type - F32 + String Value - 0.1 + - AvatarAxisScale0 + AlertedUnsupportedHardware Comment - Avatar axis 0 scaler. + Set if there's unsupported hardware and we've already done a notification. Persist 1 Type - F32 + Boolean Value - 1.0 + 0 - AvatarAxisScale1 + AllowIdleAFK Comment - Avatar axis 1 scaler. + Automatically set AFK (away from keyboard) mode when idle Persist 1 Type - F32 + Boolean Value - 1.0 + 1 - AvatarAxisScale2 + AllowMultipleViewers Comment - Avatar axis 2 scaler. + Allow multiple viewers. Persist 1 Type - F32 + Boolean Value - 1.0 + 1 - AvatarAxisScale3 + AllowSelectAvatar Comment - Avatar axis 3 scaler. + Allow selecting an avatar that you have modify rights on (via tag) while in edit mode to reposition them Persist 1 Type - F32 + Boolean Value - 1.0 + 0 - AvatarAxisScale4 + AllowTapTapHoldRun Comment - Avatar axis 4 scaler. + Tapping a direction key twice and holding it down makes avatar run Persist 1 Type - F32 + Boolean Value - 1.0 + 1 - AvatarAxisScale5 + AnimateTextures Comment - Avatar axis 5 scaler. + Enable texture animation (debug) Persist 1 Type - F32 + Boolean Value - 1.0 + 1 - AvatarBacklight + AnimationDebug Comment - Add rim lighting to avatar rendering to approximate shininess of skin + Show active animations in a bubble above avatars head Persist 1 Type Boolean Value - 1 + 0 - AvatarFeathering + PreviewAnimInWorld Comment - Avatar feathering (less is softer) + Play animation preview in-world when uploading Persist 1 Type - F32 + Boolean Value - 16.0 + 0 - AvatarPickerSortOrder + AppearanceCameraMovement Comment - Specifies sort key for textures in avatar picker (+0 = name, +1 = date, +2 = folders always by name, +4 = system folders to top) + When entering appearance editing mode, camera zooms in on currently selected portion of avatar Persist 1 Type - U32 + Boolean Value - 2 + 1 - AvatarRotateThresholdSlow + AppearanceCloseOnEscape Comment - Angle between avatar facing and camera facing at which avatar turns to face same direction as camera, when moving slowly (degrees) + When in appearance editing mode, hitting escape will work the same as the close button Persist 1 Type - F32 + Boolean Value - 60 - - AvatarRotateThresholdFast + 0 +
    + AppearanceSpecialLighting Comment - Angle between avatar facing and camera facing at which avatar turns to face same direction as camera, when moving fast (degrees) + When in appearance editing mode, avatar is shown with special lighting Persist 1 Type - F32 + Boolean Value - 2 - - AvatarBakedTextureUploadTimeout + 1 + + ApplyColorImmediately Comment - Specifes the maximum time in seconds to wait before sending your baked textures for avatar appearance. Set to 0 to disable and wait until all baked textures are at highest resolution. + Preview selections in color picker immediately Persist 1 Type - U32 + Boolean Value - 60 + 1 - AvatarBakedLocalTextureUpdateTimeout + ApplyTextureImmediately Comment - Specifes the maximum time in seconds to wait before updating your appearance during appearance mode. + Preview selections in texture picker immediately Persist 1 Type - U32 + Boolean Value - 10 + 1 - AvatarPhysics + ArrowKeysMoveAvatar Comment - Enable avatar wearable physics. + While cursor is in chat entry box, arrow keys still control your avatar Persist 1 Type @@ -2765,223 +2778,197 @@ This should be as low as possible, but too low may break functionality Value 1 - AvatarSex + AskedAboutCrashReports Comment - + Turns off dialog asking if you want to enable crash reporting Persist - 0 + 1 Type - U32 + Boolean Value 0 - BackgroundYieldTime + AuctionShowFence Comment - Amount of time to yield every frame to other applications when SL is not the foreground window (milliseconds) + When auctioning land, include parcel boundary marker in snapshot Persist 1 Type - S32 + Boolean Value - 40 + 1 - FloaterBlacklistRect + AudioLevelAmbient Comment - LOLRectangle + Audio level of environment sounds Persist 1 Type - Rect + F32 Value - - 0 - 400 - 400 - 0 - + 0.5 - BackwardBtnRect + AudioLevelDoppler Comment - + Scale of doppler effect on moving audio sources (1.0 = normal, <1.0 = diminished doppler effect, >1.0 = enhanced doppler effect) Persist - 0 + 1 Type - Rect + F32 Value - - 45 - 29 - 66 - 4 - + 1.0 - BasicHelpRect + AudioLevelMaster Comment - Rectangle for help window + Master audio level, or overall volume Persist 1 Type - Rect + F32 Value - - 0 - 404 - 467 - 0 - + 1.0 - ShowBeaconsFloater + AudioLevelMedia Comment - Show beacons floater + Audio level of Quicktime movies Persist 1 Type - Boolean + F32 Value - 0 + 1.0 - BeaconsKeepVisible + AudioLevelMic Comment - Don't turn off BeaconsVisible when beacons floater is closed + Audio level of microphone input Persist 1 Type - Boolean + F32 Value - 0 + 1.0 - BeaconsVisible + AudioLevelMusic Comment - Show beacons / highlighting + Audio level of streaming music Persist - 0 + 1 Type - Boolean + F32 Value - 0 + 1.0 - BrowserHomePage + AudioLevelRolloff Comment - [NOT USED] + Controls the distance-based dropoff of audio volume (fraction or multiple of default audio rolloff) Persist 1 Type - String + F32 Value - http://www.singularityviewer.org + 1.0 - BrowserIgnoreSSLCertErrors + AudioLevelUnderwaterRolloff Comment - FOR TESTING ONLY: Tell the built-in web browser to ignore SSL cert errors. + Controls the distance-based dropoff of audio volume when camera is submerged (fraction or multiple of default audio rolloff) Persist 1 Type - Boolean + F32 Value - 0 + 4.0 - BrowserEnableJSObject + AudioLevelSFX Comment - (WARNING: Advanced feature. Use if you are aware of the implications). Enable or disable the viewer to Javascript bridge object. + Audio level of in-world sound effects Persist - 0 + 1 Type - Boolean + F32 Value - 0 + 1.0 - BlockAvatarAppearanceMessages - - Comment - Ignores appearance messages (for simulating Ruth) - Persist - 1 + AudioLevelUI + + Comment + Audio level of UI sound effects + Persist + 1 Type - Boolean + F32 Value - 0 - - BlockSomeAvatarAppearanceVisualParams - - Comment - Drop around 50% of VisualParam occurances in appearance messages (for simulating Ruth) - Persist - 1 - Type - Boolean - Value - 0 - - BrowserProxyAddress + 0.5 + + AudioLevelVoice Comment - Address for the Web Proxy + Audio level of voice chat Persist 1 Type - String + F32 Value - + 0.5 - BrowserProxyEnabled + AudioLevelWind Comment - Use Web Proxy + Audio level of wind noise when standing still Persist 1 Type - Boolean + F32 Value - 0 + 0.075 - BrowserProxyExclusions + AudioStreamingMedia Comment - [NOT USED] + Enable streaming Persist 1 Type - String + Boolean Value - + 1 - BrowserProxyPort + AudioStreamingMusic Comment - Port for Web Proxy + Enable streaming audio Persist 1 Type - S32 + Boolean Value - 3128 + 1 - BrowserProxySocks45 + AuditTexture Comment - [NOT USED] + Enable texture auditting. Persist - 1 + 0 Type - S32 + Boolean Value - 5 + 0 - Socks5ProxyEnabled + AutoReplace Comment - Use Socks5 Proxy + Replaces keywords with a configured word or phrase Persist 1 Type @@ -2989,98 +2976,109 @@ This should be as low as possible, but too low may break functionality Value 0 - Socks5HttpProxyType + AutoAcceptAllNewInventory Comment - Proxy type to use for HTTP operations + Automatically accept new inventory, regardless of type Persist 1 Type - String + Boolean Value - None + 0 - Socks5ProxyHost + AutoAcceptNewInventory Comment - Socks 5 Proxy Host + Automatically accept new notecards/textures/landmarks Persist 1 Type - String + Boolean Value - + 0 - Socks5ProxyPort + AutoLeveling Comment - Socks 5 Proxy Port + Keep Flycam level. Persist 1 Type - U32 + Boolean Value - 1080 + 1 - Socks5Username + AutoLoadWebProfiles Comment - Socks 5 Username + Automatically load ALL profile webpages without asking first. Persist 1 Type - String + Boolean Value - + 0 - Socks5Password + AutoLogin Comment - Socks 5 Password + Login automatically using last username/password combination + Persist + 0 + Type + Boolean + Value + 0 + + AutoMimeDiscovery + + Comment + Enable viewer mime type discovery of media URLs Persist 1 Type - String + Boolean Value - + 0 - Socks5AuthType + AutoPilotLocksCamera Comment - Selected Auth mechanism for Socks5 + Keep camera position locked when avatar walks to selected position Persist 1 Type - String + Boolean Value - None + 0 - BuildAxisDeadZone0 + AutoSnapshot Comment - Build axis 0 dead zone. + Update snapshot when camera stops moving, or any parameter changes Persist 1 Type - F32 + Boolean Value - 0.1 + 0 - BuildAxisDeadZone1 + AutomaticFly Comment - Build axis 1 dead zone. + Fly by holding jump key or using "Fly" command (FALSE = fly by using "Fly" command only) Persist 1 Type - F32 + Boolean Value - 0.1 + 1 - BuildAxisDeadZone2 + AvatarAxisDeadZone0 Comment - Build axis 2 dead zone. + Avatar axis 0 dead zone. Persist 1 Type @@ -3088,10 +3086,10 @@ This should be as low as possible, but too low may break functionality Value 0.1 - BuildAxisDeadZone3 + AvatarAxisDeadZone1 Comment - Build axis 3 dead zone. + Avatar axis 1 dead zone. Persist 1 Type @@ -3099,10 +3097,10 @@ This should be as low as possible, but too low may break functionality Value 0.1 - BuildAxisDeadZone4 + AvatarAxisDeadZone2 Comment - Build axis 4 dead zone. + Avatar axis 2 dead zone. Persist 1 Type @@ -3110,10 +3108,10 @@ This should be as low as possible, but too low may break functionality Value 0.1 - BuildAxisDeadZone5 + AvatarAxisDeadZone3 Comment - Build axis 5 dead zone. + Avatar axis 3 dead zone. Persist 1 Type @@ -3121,32 +3119,32 @@ This should be as low as possible, but too low may break functionality Value 0.1 - BuildAxisScale0 + AvatarAxisDeadZone4 Comment - Build axis 0 scaler. + Avatar axis 4 dead zone. Persist 1 Type F32 Value - 1.0 + 0.1 - BuildAxisScale1 + AvatarAxisDeadZone5 Comment - Build axis 1 scaler. + Avatar axis 5 dead zone. Persist 1 Type F32 Value - 1.0 + 0.1 - BuildAxisScale2 + AvatarAxisScale0 Comment - Build axis 2 scaler. + Avatar axis 0 scaler. Persist 1 Type @@ -3154,10 +3152,10 @@ This should be as low as possible, but too low may break functionality Value 1.0 - BuildAxisScale3 + AvatarAxisScale1 Comment - Build axis 3 scaler. + Avatar axis 1 scaler. Persist 1 Type @@ -3165,10 +3163,10 @@ This should be as low as possible, but too low may break functionality Value 1.0 - BuildAxisScale4 + AvatarAxisScale2 Comment - Build axis 4 scaler. + Avatar axis 2 scaler. Persist 1 Type @@ -3176,10 +3174,10 @@ This should be as low as possible, but too low may break functionality Value 1.0 - BuildAxisScale5 + AvatarAxisScale3 Comment - Build axis 5 scaler. + Avatar axis 3 scaler. Persist 1 Type @@ -3187,32 +3185,32 @@ This should be as low as possible, but too low may break functionality Value 1.0 - BuildBtnState + AvatarAxisScale4 Comment - + Avatar axis 4 scaler. Persist - 0 + 1 Type - Boolean + F32 Value - 0 + 1.0 - BuildFeathering + AvatarAxisScale5 Comment - Build feathering (less is softer) + Avatar axis 5 scaler. Persist 1 Type F32 Value - 16.0 + 1.0 - BulkChangeIncludeAnimations + AvatarBacklight Comment - Bulk permission changes affect animations + Add rim lighting to avatar rendering to approximate shininess of skin Persist 1 Type @@ -3220,76 +3218,87 @@ This should be as low as possible, but too low may break functionality Value 1 - BulkChangeIncludeAnimations + AvatarFeathering Comment - Bulk permission changes affect animations + Avatar feathering (less is softer) Persist 1 Type - Boolean + F32 Value - 1 + 16.0 - BulkChangeIncludeAnimations + AvatarPickerSortOrder Comment - Bulk permission changes affect animations + Specifies sort key for textures in avatar picker (+0 = name, +1 = date, +2 = folders always by name, +4 = system folders to top) Persist 1 Type - Boolean + U32 Value - 1 + 2 - BulkChangeIncludeAnimations + AvatarPickerURL Comment - Bulk permission changes affect animations + Avatar picker contents Persist - 1 + 0 Type - Boolean + String Value - 1 + http://lecs-viewer-web-components.s3.amazonaws.com/v3.0/[GRID_LOWERCASE]/avatars.html - BulkChangeIncludeBodyParts + AvatarRotateThresholdSlow Comment - Bulk permission changes affect body parts + Angle between avatar facing and camera facing at which avatar turns to face same direction as camera, when moving slowly (degrees) Persist 1 Type - Boolean + F32 Value - 1 - - BulkChangeIncludeClothing + 60 + + AvatarRotateThresholdFast Comment - Bulk permission changes affect clothing + Angle between avatar facing and camera facing at which avatar turns to face same direction as camera, when moving fast (degrees) Persist 1 Type - Boolean + F32 Value + 2 + + AvatarBakedTextureUploadTimeout + + Comment + Specifes the maximum time in seconds to wait before sending your baked textures for avatar appearance. Set to 0 to disable and wait until all baked textures are at highest resolution. + Persist 1 + Type + U32 + Value + 60 - BulkChangeIncludeGestures + AvatarBakedLocalTextureUpdateTimeout Comment - Bulk permission changes affect gestures + Specifes the maximum time in seconds to wait before updating your appearance during appearance mode. Persist 1 Type - Boolean + U32 Value - 1 + 10 - BulkChangeIncludeLandmarks + AvatarPhysics Comment - Bulk permission changes affect landmarks + Enable avatar wearable physics. Persist 1 Type @@ -3297,65 +3306,80 @@ This should be as low as possible, but too low may break functionality Value 1 - BulkChangeIncludeNotecards + AvatarSex Comment - Bulk permission changes affect notecards + Persist - 1 + 0 Type - Boolean + U32 Value - 1 + 0 - BulkChangeIncludeObjects + BackgroundYieldTime Comment - Bulk permission changes affect objects + Amount of time to yield every frame to other applications when SL is not the foreground window (milliseconds) Persist 1 Type - Boolean + S32 Value - 1 + 40 - BulkChangeIncludeScripts + FloaterBlacklistRect Comment - Bulk permission changes affect scripts + LOLRectangle Persist 1 Type - Boolean + Rect Value - 1 + + 0 + 400 + 400 + 0 + - BulkChangeIncludeSounds + BackwardBtnRect Comment - Bulk permission changes affect sounds + Persist - 1 + 0 Type - Boolean + Rect Value - 1 + + 45 + 29 + 66 + 4 + - BulkChangeIncludeTextures + BasicHelpRect Comment - Bulk permission changes affect textures + Rectangle for help window Persist 1 Type - Boolean + Rect Value - 1 + + 0 + 404 + 467 + 0 + - BulkChangeEveryoneCopy + ShowBeaconsFloater Comment - Bulk changed objects can be copied by everyone + Show beacons floater Persist 1 Type @@ -3363,10 +3387,10 @@ This should be as low as possible, but too low may break functionality Value 0 - BulkChangeNextOwnerCopy + BeaconsKeepVisible Comment - Bulk changed objects can be copied by next owner + Don't turn off BeaconsVisible when beacons floater is closed Persist 1 Type @@ -3374,32 +3398,32 @@ This should be as low as possible, but too low may break functionality Value 0 - BulkChangeNextOwnerModify + BeaconsVisible Comment - Bulk changed objects can be modified by next owner + Show beacons / highlighting Persist - 1 + 0 Type Boolean Value 0 - BulkChangeNextOwnerTransfer + BrowserHomePage Comment - Bulk changed objects can be resold or given away by next owner + [NOT USED] Persist 1 Type - Boolean + String Value - 0 + http://www.singularityviewer.org - BulkChangeShareWithGroup + BrowserIgnoreSSLCertErrors Comment - Bulk changed objects are shared with the currently active group + FOR TESTING ONLY: Tell the built-in web browser to ignore SSL cert errors. Persist 1 Type @@ -3407,421 +3431,362 @@ This should be as low as possible, but too low may break functionality Value 0 - ButtonFlashCount + BrowserEnableJSObject Comment - Number of flashes after which flashing buttons stay lit up + (WARNING: Advanced feature. Use if you are aware of the implications). Enable or disable the viewer to Javascript bridge object. Persist - 1 + 0 Type - S32 + Boolean Value - 8 + 0 - ButtonFlashRate + BlockAvatarAppearanceMessages + + Comment + Ignores appearance messages (for simulating Ruth) + Persist + 1 + Type + Boolean + Value + 0 + + BlockSomeAvatarAppearanceVisualParams + + Comment + Drop around 50% of VisualParam occurances in appearance messages (for simulating Ruth) + Persist + 1 + Type + Boolean + Value + 0 + + BrowserProxyAddress Comment - Frequency at which buttons flash (hz) + Address for the Web Proxy Persist 1 Type - F32 + String Value - 1.25 + - ButtonHPad + BrowserProxyEnabled Comment - Default horizontal spacing between buttons (pixels) + Use Web Proxy Persist 1 Type - S32 + Boolean Value - 10 + 0 - ButtonHeight + BrowserProxyExclusions Comment - Default height for normal buttons (pixels) + [NOT USED] Persist 1 Type - S32 + String Value - 20 + - ButtonHeightSmall + BrowserProxyPort Comment - Default height for small buttons (pixels) + Port for Web Proxy Persist 1 Type S32 Value - 16 + 3128 - ButtonVPad + BrowserProxyType Comment - Default vertical spacing between buttons (pixels) + Type of proxy for Web Browser Persist 1 Type S32 Value - 1 + 0 - CacheLocation + BrowserProxyUsername Comment - Controls the location of the local disk cache + Username for Web Proxy authentication Persist 1 Type String Value - + - CacheNumberOfRegionsForObjects + BrowserProxyPassword Comment - Controls number of regions to be cached for objects. + Password for Web Proxy authentication Persist 1 Type - U32 + String Value - 128 + - CacheSize + BrowserProxySocks45 Comment - Controls amount of hard drive space reserved for local file caching in MB + [NOT USED] Persist 1 Type - U32 + S32 Value - 512 + 5 - CacheValidateCounter + Socks5ProxyEnabled Comment - Used to distribute cache validation + Use Socks5 Proxy Persist 1 Type - U32 + Boolean Value 0 - CameraMouseWheelZoom + Socks5HttpProxyType Comment - Camera zooms in and out with mousewheel + Proxy type to use for HTTP operations Persist 1 Type - Boolean + String Value - 1 + None - CameraAngle + Socks5ProxyHost Comment - Camera field of view angle (Radians) + Socks 5 Proxy Host Persist 1 Type - F32 + String Value - 1.047197551 + - CameraOffset + Socks5ProxyPort Comment - Render with camera offset from view frustum (rendering debug) + Socks 5 Proxy Port Persist 1 Type - Boolean + U32 Value - 0 + 1080 - CameraOffsetBuild + Socks5Username Comment - Default camera position relative to focus point when entering build mode + Socks 5 Username Persist 1 Type - Vector3 + String Value - - -6.0 - 0.0 - 6.0 - + - CameraOffsetRearView + Socks5Password Comment - Initial camera offset from avatar in Rear View + Socks 5 Password Persist 1 Type - Vector3 + String Value - - -3.0 - 0.0 - 0.75 - + - CameraOffsetFrontView + Socks5AuthType Comment - Initial camera offset from avatar in Front View + Selected Auth mechanism for Socks5 Persist 1 Type - Vector3 + String Value - - 2.2 - 0.0 - 0.0 - + None - CameraOffsetGroupView + BuildAxisDeadZone0 Comment - Initial camera offset from avatar in Group View + Build axis 0 dead zone. Persist 1 Type - Vector3 + F32 Value - - -1.0 - 0.7 - 0.5 - + 0.1 - CameraOffsetScale + BuildAxisDeadZone1 Comment - Scales the default offset + Build axis 1 dead zone. Persist 1 Type F32 Value - 1.0 + 0.1 - CameraPosOnLogout + BuildAxisDeadZone2 Comment - Camera position when last logged out (global coordinates) + Build axis 2 dead zone. Persist 1 Type - Vector3D + F32 Value - - 0.0 - 0.0 - 0.0 - + 0.1 - CameraPositionSmoothing + BuildAxisDeadZone3 Comment - Smooths camera position over time + Build axis 3 dead zone. Persist 1 Type F32 Value - 1.0 + 0.1 - CameraPreset + BuildAxisDeadZone4 Comment - Preset camera position - view (0 - rear, 1 - front, 2 - group) + Build axis 4 dead zone. Persist 1 Type - U32 + F32 Value - 0 + 0.1 - - CameraFocusTransitionTime - - Comment - How many seconds it takes the camera to transition between focal distances - Persist - 1 - Type - F32 - Value - 0.5 - - - CameraMaxCoF - - Comment - Maximum camera circle of confusion for DoF effect - Persist - 1 - Type - F32 - Value - 10.0 - - - CameraFNumber - - Comment - Camera f-number value for DoF effect - Persist - 1 - Type - F32 - Value - 9.0 - - - CameraFocalLength - - Comment - Camera focal length for DoF effect (in millimeters) - Persist - 1 - Type - F32 - Value - 50 - - - CameraFieldOfView - - Comment - Vertical camera field of view for DoF effect (in degrees) - Persist - 1 - Type - F32 - Value - 60.0 - - - CameraAspectRatio - - Comment - Camera aspect ratio for DoF effect - Persist - 1 - Type - F32 - Value - 1.5 - - ChatBarStealsFocus + BuildAxisDeadZone5 Comment - Whenever keyboard focus is removed from the UI, and the chat bar is visible, the chat bar takes focus + Build axis 5 dead zone. Persist 1 Type - Boolean + F32 Value - 1 + 0.1 - ChatBubbleOpacity + BuildAxisScale0 Comment - Opacity of chat bubble background (0.0 = completely transparent, 1.0 = completely opaque) + Build axis 0 scaler. Persist 1 Type F32 Value - 0.5 + 1.0 - ChatFontSize + BuildAxisScale1 Comment - Size of chat text in chat console (0 = small, 1 = big) + Build axis 1 scaler. Persist 1 Type - S32 + F32 Value - 1 + 1.0 - ChatFullWidth + BuildAxisScale2 Comment - Chat console takes up full width of SL window + Build axis 2 scaler. Persist 1 Type - Boolean + F32 Value - 1 + 1.0 - ChatHistoryTornOff + BuildAxisScale3 Comment - Show chat history window separately from Communicate window. + Build axis 3 scaler. Persist 1 Type - Boolean + F32 Value - 0 + 1.0 - ChatOnlineNotification + BuildAxisScale4 Comment - Provide notifications for when friend log on and off of SL + Build axis 4 scaler. Persist 1 Type - Boolean + F32 Value - 1 + 1.0 - HideNotificationsInChat + BuildAxisScale5 Comment - Do not echo/log notifications in chat + Build axis 5 scaler. Persist 1 Type + F32 + Value + 1.0 + + BuildBtnState + + Comment + + Persist + 0 + Type Boolean Value 0 - ChatPersistTime + BuildFeathering Comment - Time for which chat stays visible in console (seconds) + Build feathering (less is softer) Persist 1 Type F32 Value - 20.0 + 16.0 - ChatShowTimestamps + BulkChangeIncludeAnimations Comment - Show timestamps in chat + Bulk permission changes affect animations Persist 1 Type @@ -3829,21 +3794,21 @@ This should be as low as possible, but too low may break functionality Value 1 - ChatSpacing + BulkChangeIncludeAnimations Comment - Add extra vertical spacing between local chat lines + Bulk permission changes affect animations Persist 1 Type - S32 + Boolean Value - 0 + 1 - ChatVisible + BulkChangeIncludeAnimations Comment - Chat bar is visible + Bulk permission changes affect animations Persist 1 Type @@ -3851,59 +3816,54 @@ This should be as low as possible, but too low may break functionality Value 1 - ChatterboxRect + BulkChangeIncludeAnimations Comment - Rectangle for chatterbox window + Bulk permission changes affect animations Persist 1 Type - Rect + Boolean Value - - 0 - 400 - 350 - 0 - + 1 - CheesyBeacon + BulkChangeIncludeBodyParts Comment - Enable cheesy beacon effects + Bulk permission changes affect body parts Persist 1 Type Boolean Value - 0 + 1 - ClientSettingsFile + BulkChangeIncludeClothing Comment - Persisted client settings file name (per install). + Bulk permission changes affect clothing Persist - 0 + 1 Type - String + Boolean Value - + 1 - CloseChatOnReturn + BulkChangeIncludeGestures Comment - Close chat after hitting return + Bulk permission changes affect gestures Persist 1 Type Boolean Value - 0 + 1 - CloseSnapshotOnKeep + BulkChangeIncludeLandmarks Comment - Close snapshot window after saving snapshot + Bulk permission changes affect landmarks Persist 1 Type @@ -3911,617 +3871,542 @@ This should be as low as possible, but too low may break functionality Value 1 - CmdLineDisableVoice + BulkChangeIncludeNotecards Comment - Disable Voice. + Bulk permission changes affect notecards Persist - 0 + 1 Type Boolean Value - 0 + 1 - CmdLineAgentURI + BulkChangeIncludeObjects Comment - URL of agent host to connect to in Agent Domain. + Bulk permission changes affect objects Persist - 0 + 1 Type - String + Boolean Value - + 1 - CmdLineGridChoice + BulkChangeIncludeScripts Comment - The user's grid choice or ip address. + Bulk permission changes affect scripts Persist - 0 + 1 Type - String + Boolean Value - + 1 - CmdLineHelperURI + BulkChangeIncludeSounds Comment - Command line specified helper web CGI prefix to use. + Bulk permission changes affect sounds Persist - 0 + 1 Type - String + Boolean Value - + 1 - CmdLineLoginURI + BulkChangeIncludeTextures Comment - Command line specified login server and CGI prefix to use. + Bulk permission changes affect textures Persist - 0 + 1 Type - LLSD + Boolean Value - - - + 1 - ColorPaletteEntry01 + BulkChangeEveryoneCopy Comment - Color picker palette entry + Bulk changed objects can be copied by everyone Persist 1 Type - Color4 + Boolean Value - - 0.0 - 0.0 - 0.0 - 1.0 - + 0 - ColorPaletteEntry02 + BulkChangeNextOwnerCopy Comment - Color picker palette entry + Bulk changed objects can be copied by next owner Persist 1 Type - Color4 + Boolean Value - - 0.5 - 0.5 - 0.5 - 1.0 - + 0 - ColorPaletteEntry03 + BulkChangeNextOwnerModify Comment - Color picker palette entry + Bulk changed objects can be modified by next owner Persist 1 Type - Color4 + Boolean Value - - 0.5 - 0.0 - 0.0 - 1.0 - + 0 - ColorPaletteEntry04 + BulkChangeNextOwnerTransfer Comment - Color picker palette entry + Bulk changed objects can be resold or given away by next owner Persist 1 Type - Color4 + Boolean Value - - 0.5 - 0.5 - 0.0 - 1.0 - + 0 - ColorPaletteEntry05 + BulkChangeShareWithGroup Comment - Color picker palette entry + Bulk changed objects are shared with the currently active group Persist 1 Type - Color4 + Boolean Value - - 0.0 - 0.5 - 0.0 - 1.0 - + 0 - ColorPaletteEntry06 + ButtonFlashCount Comment - Color picker palette entry + Number of flashes after which flashing buttons stay lit up Persist 1 Type - Color4 + S32 Value - - 0.0 - 0.5 - 0.5 - 1.0 - + 8 - ColorPaletteEntry07 + ButtonFlashRate Comment - Color picker palette entry + Frequency at which buttons flash (hz) Persist 1 Type - Color4 + F32 Value - - 0.0 - 0.0 - 0.5 - 1.0 - + 1.25 - ColorPaletteEntry08 + ButtonHPad Comment - Color picker palette entry + Default horizontal spacing between buttons (pixels) Persist 1 Type - Color4 + S32 Value - - 0.5 - 0.0 - 0.5 - 1.0 - + 10 - ColorPaletteEntry09 + ButtonHeight Comment - Color picker palette entry + Default height for normal buttons (pixels) Persist 1 Type - Color4 + S32 Value - - 0.5 - 0.5 - 0.0 - 1.0 - + 20 - ColorPaletteEntry10 + ButtonHeightSmall Comment - Color picker palette entry + Default height for small buttons (pixels) Persist 1 Type - Color4 + S32 Value - - 0.0 - 0.25 - 0.25 - 1.0 - + 16 - ColorPaletteEntry11 + ButtonVPad Comment - Color picker palette entry + Default vertical spacing between buttons (pixels) Persist 1 Type - Color4 + S32 Value - - 0.0 - 0.5 - 1.0 - 1.0 - + 1 - ColorPaletteEntry12 + CacheLocation Comment - Color picker palette entry + Controls the location of the local disk cache Persist 1 Type - Color4 + String Value - - 0.0 - 0.25 - 0.5 - 1.0 - + - ColorPaletteEntry13 + CacheNumberOfRegionsForObjects Comment - Color picker palette entry + Controls number of regions to be cached for objects. Persist 1 Type - Color4 + U32 Value - - 0.5 - 0.0 - 1.0 - 1.0 - + 128 - ColorPaletteEntry14 + CacheSize Comment - Color picker palette entry + Controls amount of hard drive space reserved for local file caching in MB Persist 1 Type - Color4 + U32 Value - - 0.5 - 0.25 - 0.0 - 1.0 - + 512 - ColorPaletteEntry15 + CacheValidateCounter Comment - Color picker palette entry + Used to distribute cache validation Persist 1 Type - Color4 + U32 Value - - 1.0 - 1.0 - 1.0 - 1.0 - + 0 - ColorPaletteEntry16 + CameraMouseWheelZoom Comment - Color picker palette entry + Camera zooms in and out with mousewheel Persist 1 Type - Color4 + Boolean Value - - 1.0 - 1.0 - 1.0 - 1.0 - + 1 - ColorPaletteEntry17 + CameraAngle Comment - Color picker palette entry + Camera field of view angle (Radians) Persist 1 Type - Color4 + F32 Value - - 1.0 - 1.0 - 1.0 - 1.0 - + 1.047197551 - ColorPaletteEntry18 + CameraOffset Comment - Color picker palette entry + Render with camera offset from view frustum (rendering debug) Persist 1 Type - Color4 + Boolean Value - - 0.75 - 0.75 - 0.75 - 1.0 - + 0 - ColorPaletteEntry19 + CameraOffsetBuild Comment - Color picker palette entry + Default camera position relative to focus point when entering build mode Persist 1 Type - Color4 + Vector3 Value - 1.0 - 0.0 + -6.0 0.0 - 1.0 + 6.0 - ColorPaletteEntry20 + CameraOffsetRearView Comment - Color picker palette entry + Initial camera offset from avatar in Rear View Persist 1 Type - Color4 + Vector3 Value - 1.0 - 1.0 + -3.0 0.0 - 1.0 + 0.75 - ColorPaletteEntry21 + CameraOffsetFrontView Comment - Color picker palette entry + Initial camera offset from avatar in Front View Persist 1 Type - Color4 + Vector3 Value + 2.2 0.0 - 1.0 0.0 - 1.0 - ColorPaletteEntry22 + CameraOffsetGroupView Comment - Color picker palette entry + Initial camera offset from avatar in Group View Persist 1 Type - Color4 + Vector3 Value - 0.0 - 1.0 - 1.0 - 1.0 + -1.0 + 0.7 + 0.5 - ColorPaletteEntry23 + CameraOffsetScale Comment - Color picker palette entry + Scales the default offset Persist 1 Type - Color4 + F32 Value - - 0.0 - 0.0 - 1.0 - 1.0 - + 1.0 - ColorPaletteEntry24 + CameraPosOnLogout Comment - Color picker palette entry + Camera position when last logged out (global coordinates) Persist 1 Type - Color4 + Vector3D Value - 1.0 0.0 - 1.0 - 1.0 + 0.0 + 0.0 - ColorPaletteEntry25 + CameraPositionSmoothing Comment - Color picker palette entry + Smooths camera position over time Persist 1 Type - Color4 + F32 Value - - 1.0 - 1.0 - 0.5 - 1.0 - + 1.0 - ColorPaletteEntry26 + CameraPreset Comment - Color picker palette entry + Preset camera position - view (0 - rear, 1 - front, 2 - group) Persist 1 Type - Color4 + U32 Value - - 0.0 - 1.0 - 0.5 - 1.0 - + 0 - ColorPaletteEntry27 + + CameraFocusTransitionTime + + Comment + How many seconds it takes the camera to transition between focal distances + Persist + 1 + Type + F32 + Value + 0.5 + + + CameraMaxCoF + + Comment + Maximum camera circle of confusion for DoF effect + Persist + 1 + Type + F32 + Value + 10.0 + + + CameraFNumber + + Comment + Camera f-number value for DoF effect + Persist + 1 + Type + F32 + Value + 9.0 + + + CameraFocalLength + + Comment + Camera focal length for DoF effect (in millimeters) + Persist + 1 + Type + F32 + Value + 50 + + + CameraFieldOfView + + Comment + Vertical camera field of view for DoF effect (in degrees) + Persist + 1 + Type + F32 + Value + 60.0 + + + CameraAspectRatio + + Comment + Camera aspect ratio for DoF effect + Persist + 1 + Type + F32 + Value + 1.5 + + ChatBarStealsFocus Comment - Color picker palette entry + Whenever keyboard focus is removed from the UI, and the chat bar is visible, the chat bar takes focus Persist 1 Type - Color4 + Boolean Value - - 0.5 - 1.0 - 1.0 - 1.0 - + 1 - ColorPaletteEntry28 + LetterKeysFocusChatBar Comment - Color picker palette entry + When printable characters keys (possibly with Shift held) are pressed, the chatbar takes focus Persist 1 Type - Color4 + Boolean Value - - 0.5 - 0.5 - 1.0 - 1.0 - + 0 - ColorPaletteEntry29 + ChatBubbleOpacity Comment - Color picker palette entry + Opacity of chat bubble background (0.0 = completely transparent, 1.0 = completely opaque) Persist 1 Type - Color4 + F32 Value - - 1.0 - 0.0 - 0.5 - 1.0 - + 0.5 - ColorPaletteEntry30 + ChatFontSize Comment - Color picker palette entry + Size of chat text in chat console (0 = small, 1 = big) Persist 1 Type - Color4 + S32 Value - - 1.0 - 0.5 - 0.0 - 1.0 - + 1 - ColorPaletteEntry31 + ChatFullWidth Comment - Color picker palette entry + Chat console takes up full width of SL window Persist 1 Type - Color4 + Boolean Value - - 1.0 - 1.0 - 1.0 - 1.0 - + 1 - ColorPaletteEntry32 + ChatHistoryTornOff Comment - Color picker palette entry + Show chat history window separately from Communicate window. Persist 1 Type - Color4 + Boolean Value - - 1.0 - 1.0 - 1.0 - 1.0 - + 0 - CompileOutputRect + ChatLoadGroupMaxMembers - Comment - Rectangle for script Recompile Everything output window - Persist - 1 - Type - Rect - Value - - 0 - 400 - 300 - 0 - + Comment + Max number of active members we'll show up for an unresponsive group + Persist + 1 + Type + S32 + Value + 100 - ConnectAsGod + ChatLoadGroupTimeout - Comment - Log in a god if you have god access. - Persist - 1 - Type - Boolean - Value - 0 + Comment + Time we give the server to send group participants before we hit the server for group info (seconds) + Persist + 1 + Type + F32 + Value + 10.0 - ConnectionPort + ChatOnlineNotification Comment - Custom connection port number + Provide notifications for when friend log on and off of SL Persist 1 Type - U32 + Boolean Value - 13000 + 1 - ConnectionPortEnabled + HideNotificationsInChat Comment - Use the custom connection port? + Do not echo/log notifications in chat Persist 1 Type @@ -4529,109 +4414,114 @@ This should be as low as possible, but too low may break functionality Value 0 - ConsoleBackgroundOpacity + ChatPersistTime Comment - Opacity of chat console (0.0 = completely transparent, 1.0 = completely opaque) + Time for which chat stays visible in console (seconds) Persist 1 Type F32 Value - 0.700 + 20.0 - ConsoleBottomOffset + ChatShowTimestamps Comment - User definable offset between the bottom of the chat console and the bottom of the window; increase to move text in the console up + Show timestamps in chat Persist 1 Type - S32 + Boolean Value - 0 + 1 - ConsoleBufferSize + ChatSpacing Comment - Size of chat console history (lines of chat) + Add extra vertical spacing between local chat lines Persist 1 Type S32 Value - 40 + 0 - ConsoleMaxLines + ChatVisible Comment - Max number of lines of chat text visible in console. + Chat bar is visible Persist 1 Type - S32 + Boolean Value - 40 + 1 - ContactsTornOff + ChatterboxRect Comment - Show contacts window separately from Communicate window. + Rectangle for chatterbox window Persist 1 Type - Boolean + Rect Value - 0 + + 0 + 400 + 350 + 0 + - CookiesEnabled + CheesyBeacon Comment - Accept cookies from Web sites? + Enable cheesy beacon effects Persist 1 Type Boolean Value - 1 + 0 - BrowserJavascriptEnabled + ClientSettingsFile Comment - Enable Javascript in the built-in Web browser? + Persisted client settings file name (per install). Persist - 1 + 0 Type - Boolean + String Value - 1 + - BrowserPluginsEnabled + CloseChatOnReturn Comment - Enable Web plugins in the built-in Web browser? + Close chat after hitting return Persist 1 Type Boolean Value - 1 + 0 - CreateToolCopyCenters + CloseSnapshotOnKeep Comment - + Close snapshot window after saving snapshot Persist - 0 + 1 Type Boolean Value 1 - CreateToolCopyRotates + CmdLineDisableVoice Comment - + Disable Voice. Persist 0 Type @@ -4639,898 +4529,1131 @@ This should be as low as possible, but too low may break functionality Value 0 - CreateToolCopySelection + CmdLineAgentURI Comment - + URL of agent host to connect to in Agent Domain. Persist 0 Type - Boolean + String Value - 0 + - CreateToolKeepSelected + CmdLineGridChoice Comment - After using create tool, keep the create tool active + The user's grid choice or ip address. Persist - 1 + 0 Type - Boolean + String Value - 0 + - CurlMaxTotalConcurrentConnections + CmdLineHelperURI Comment - Maximum total number of simultaneous curl connections + Command line specified helper web CGI prefix to use. Persist - 1 + 0 Type - U32 + String Value - 64 + - CurlConcurrentConnectionsPerService + CmdLineLoginURI Comment - Maximum number of simultaneous curl connections per host:port service + Command line specified login server and CGI prefix to use. Persist 0 Type - U32 + LLSD Value - 8 + + + - CurlTimeoutDNSLookup + ColorPaletteEntry01 Comment - Extra time in seconds added to CurlTimeoutConnect for the initial connect to a host + Color picker palette entry Persist 1 Type - U32 + Color4 Value - 60 + + 0.0 + 0.0 + 0.0 + 1.0 + - CurlTimeoutConnect + ColorPaletteEntry02 Comment - Maximum time allowed until a connection is established (after adding the easy handle) until the server is considered unreachable and the connection is terminated + Color picker palette entry Persist 1 Type - U32 + Color4 Value - 10 + + 0.5 + 0.5 + 0.5 + 1.0 + - CurlTimeoutReplyDelay + ColorPaletteEntry03 Comment - Maximum time the viewer will wait between sending data to the server and receiving (a partial) reply + Color picker palette entry Persist 1 Type - U32 + Color4 Value - 60 + + 0.5 + 0.0 + 0.0 + 1.0 + - CurlTimeoutLowSpeedLimit + ColorPaletteEntry04 Comment - If a transfer speed drops below this value (in bytes/s) during CurlTimeoutLowSpeedTime seconds, the transfer is considered too slow and is terminated + Color picker palette entry Persist 1 Type - U32 + Color4 Value - 7000 + + 0.5 + 0.5 + 0.0 + 1.0 + - CurlTimeoutLowSpeedTime + ColorPaletteEntry05 Comment - If a transfer speed drops below CurlTimeoutLowSpeedLimit (in bytes/s) during this amount of seconds, the transfer is considered too slow and is terminated + Color picker palette entry Persist 1 Type - U32 + Color4 Value - 30 + + 0.0 + 0.5 + 0.0 + 1.0 + - CurlTimeoutMaxTransaction + ColorPaletteEntry06 Comment - Maximum total time of a curl transaction, from when the easy handle is added till the transaction has completed. This INCLUDES DNS lookups (CurlTimeoutDNSLookup), connect time (CurlTimeoutConnect) and waiting for the first server reply (CurlTimeoutReply) as well as the actually time needed for data transfer + Color picker palette entry Persist 1 Type - U32 + Color4 Value - 300 + + 0.0 + 0.5 + 0.5 + 1.0 + - CurlTimeoutMaxTotalDelay + ColorPaletteEntry07 Comment - Maximum total time of a curl request, from when it is requested till the transaction has completed. This includes queuing due to connection throttling on top of the events covered by CurlTimeoutMaxTransaction + Color picker palette entry Persist 1 Type - U32 + Color4 Value - 600 + + 0.0 + 0.0 + 0.5 + 1.0 + - Cursor3D + ColorPaletteEntry08 Comment - Treat Joystick values as absolute positions (not deltas). + Color picker palette entry Persist 1 Type - Boolean + Color4 Value - 1 - - CustomServer + + 0.5 + 0.0 + 0.5 + 1.0 + + + ColorPaletteEntry09 Comment - Specifies IP address or hostname of grid to which you connect + Color picker palette entry Persist 1 Type - String + Color4 Value - + + 0.5 + 0.5 + 0.0 + 1.0 + - DebugAvatarAppearanceMessage - - Comment - Dump a bunch of XML files when handling appearance messages - Persist - 1 - Type - Boolean - Value - 0 - - DebugAvatarRezTime - - Comment - Display times for avatars to resolve. - Persist - 1 - Type - Boolean - Value - 0 - - DebugAvatarLocalTexLoadedTime - - Comment - Display time for loading avatar local textures. - Persist - 1 - Type - Boolean - Value - 1 - - DebugAvatarCompositeBaked - - Comment - Colorize avatar meshes based on baked/composite state. - Persist - 1 - Type - Boolean - Value - 0 - - DebugBeaconLineWidth + ColorPaletteEntry10 Comment - Size of lines for Debug Beacons + Color picker palette entry Persist 1 Type - S32 + Color4 Value - 1 + + 0.0 + 0.25 + 0.25 + 1.0 + - DebugInventoryFilters + ColorPaletteEntry11 Comment - Turn on debugging display for inventory filtering + Color picker palette entry Persist 1 Type - Boolean + Color4 Value - 0 + + 0.0 + 0.5 + 1.0 + 1.0 + - DebugPermissions + ColorPaletteEntry12 Comment - Log permissions for selected inventory items + Color picker palette entry Persist 1 Type - Boolean + Color4 Value - 0 + + 0.0 + 0.25 + 0.5 + 1.0 + - DebugPluginDisableTimeout + ColorPaletteEntry13 Comment - Disable the code which watches for plugins that are crashed or hung + Color picker palette entry Persist 1 Type - Boolean + Color4 Value - 0 + + 0.5 + 0.0 + 1.0 + 1.0 + - DebugShowColor + ColorPaletteEntry14 Comment - Show color under cursor + Color picker palette entry Persist 1 Type - Boolean + Color4 Value - 0 + + 0.5 + 0.25 + 0.0 + 1.0 + - DebugShowMemory + ColorPaletteEntry15 Comment - Show Total Allocated Memory + Color picker palette entry Persist 1 Type - Boolean + Color4 Value - 0 + + 1.0 + 1.0 + 1.0 + 1.0 + - DebugShowPrivateMem + ColorPaletteEntry16 Comment - Show Private Mem Info + Color picker palette entry Persist 1 Type - Boolean + Color4 Value - 0 + + 1.0 + 1.0 + 1.0 + 1.0 + - DebugShowRenderInfo + ColorPaletteEntry17 Comment - Show stats about current scene + Color picker palette entry Persist 1 Type - Boolean + Color4 Value - 0 + + 1.0 + 1.0 + 1.0 + 1.0 + - DebugShowRenderMatrices + ColorPaletteEntry18 Comment - Display values of current view and projection matrices. + Color picker palette entry Persist 1 Type - Boolean + Color4 Value - 0 + + 0.75 + 0.75 + 0.75 + 1.0 + - DebugShowTime + ColorPaletteEntry19 Comment - Show time info + Color picker palette entry Persist 1 Type - Boolean + Color4 Value - 0 + + 1.0 + 0.0 + 0.0 + 1.0 + - DebugStatModeFPS + ColorPaletteEntry20 Comment - Mode of stat in Statistics floater + Color picker palette entry Persist 1 Type - S32 + Color4 Value - -1 + + 1.0 + 1.0 + 0.0 + 1.0 + - DebugStatModeBandwidth + ColorPaletteEntry21 Comment - Mode of stat in Statistics floater + Color picker palette entry Persist 1 Type - S32 + Color4 Value - -1 + + 0.0 + 1.0 + 0.0 + 1.0 + - DebugStatModePacketLoss + ColorPaletteEntry22 Comment - Mode of stat in Statistics floater + Color picker palette entry Persist 1 Type - S32 + Color4 Value - -1 + + 0.0 + 1.0 + 1.0 + 1.0 + - DebugStatMode + ColorPaletteEntry23 Comment - Mode of stat in Statistics floater + Color picker palette entry Persist 1 Type - S32 + Color4 Value - -1 + + 0.0 + 0.0 + 1.0 + 1.0 + - DebugStatModeKTrisDrawnFr + ColorPaletteEntry24 Comment - Mode of stat in Statistics floater + Color picker palette entry Persist 1 Type - S32 + Color4 Value - -1 - - DebugStatModeKTrisDrawnSec - + + 1.0 + 0.0 + 1.0 + 1.0 + + + ColorPaletteEntry25 + Comment - Mode of stat in Statistics floater + Color picker palette entry Persist 1 Type - S32 + Color4 Value - -1 + + 1.0 + 1.0 + 0.5 + 1.0 + - DebugStatModeTotalObjs + ColorPaletteEntry26 Comment - Mode of stat in Statistics floater + Color picker palette entry Persist 1 Type - S32 + Color4 Value - -1 + + 0.0 + 1.0 + 0.5 + 1.0 + - DebugStatModeNewObjs + ColorPaletteEntry27 Comment - Mode of stat in Statistics floater + Color picker palette entry Persist 1 Type - S32 + Color4 Value - -1 + + 0.5 + 1.0 + 1.0 + 1.0 + - DebugStatModeTextureCount + ColorPaletteEntry28 Comment - Mode of stat in Statistics floater + Color picker palette entry Persist 1 Type - S32 + Color4 Value - -1 + + 0.5 + 0.5 + 1.0 + 1.0 + - DebugStatModeRawCount + ColorPaletteEntry29 Comment - Mode of stat in Statistics floater + Color picker palette entry Persist 1 Type - S32 + Color4 Value - -1 + + 1.0 + 0.0 + 0.5 + 1.0 + - DebugStatModeGLMem + ColorPaletteEntry30 Comment - Mode of stat in Statistics floater + Color picker palette entry Persist 1 Type - S32 + Color4 Value - -1 + + 1.0 + 0.5 + 0.0 + 1.0 + - DebugStatModeMalloc + ColorPaletteEntry31 Comment - Mode of stat in Statistics floater + Color picker palette entry Persist 1 Type - S32 + Color4 Value - -1 - - DebugStatModeFormattedMem + + 1.0 + 1.0 + 1.0 + 1.0 + + + ColorPaletteEntry32 Comment - Mode of stat in Statistics floater + Color picker palette entry Persist 1 Type - S32 + Color4 Value - -1 + + 1.0 + 1.0 + 1.0 + 1.0 + - DebugStatModeRawMem + CompileOutputRect Comment - Mode of stat in Statistics floater + Rectangle for script Recompile Everything output window Persist 1 Type - S32 + Rect Value - -1 + + 0 + 400 + 300 + 0 + - DebugStatModeBoundMem + ConnectAsGod Comment - Mode of stat in Statistics floater + Log in a god if you have god access. Persist 1 Type - S32 + Boolean Value - -1 + 0 - DebugStatModePacketsIn + ConnectionPort Comment - Mode of stat in Statistics floater + Custom connection port number Persist 1 Type - S32 + U32 Value - -1 + 13000 - DebugStatModePacketsOut + ConnectionPortEnabled Comment - Mode of stat in Statistics floater + Use the custom connection port? Persist 1 Type - S32 + Boolean Value - -1 + 0 - DebugStatModeObjects + ConsoleBackgroundOpacity Comment - Mode of stat in Statistics floater + Opacity of chat console (0.0 = completely transparent, 1.0 = completely opaque) Persist 1 Type - S32 + F32 Value - -1 + 0.700 - DebugStatModeHTTPTexture + ConsoleBottomOffset Comment - Mode of stat in Statistics floater + User definable offset between the bottom of the chat console and the bottom of the window; increase to move text in the console up Persist 1 Type S32 Value - -1 + 0 - DebugStatModeUDPTexture + ConsoleBufferSize Comment - Mode of stat in Statistics floater + Size of chat console history (lines of chat) Persist 1 Type S32 Value - -1 + 40 - DebugStatModeAsset + ConsoleMaxLines Comment - Mode of stat in Statistics floater + Max number of lines of chat text visible in console. Persist 1 Type S32 Value - -1 + 40 - DebugStatModeLayers + ContactsTornOff Comment - Mode of stat in Statistics floater + Show contacts window separately from Communicate window. Persist 1 Type - S32 + Boolean Value - -1 + 0 - DebugStatModeActualIn + ContextConeInAlpha Comment - Mode of stat in Statistics floater + Cone In Alpha Persist - 1 + 0 Type - S32 + F32 Value - -1 + 0.0 - DebugStatModeActualOut + ContextConeOutAlpha Comment - Mode of stat in Statistics floater + Cone Out Alpha Persist - 1 + 0 Type - S32 + F32 Value - -1 + 1.0 - DebugStatModeVFSPendingOps + ContextConeFadeTime Comment - Mode of stat in Statistics floater + Cone Fade Time Persist - 1 + 0 Type - S32 + F32 Value - -1 + .08 - DebugStatModeTimeDialation + CookiesEnabled Comment - Mode of stat in Statistics floater + Accept cookies from Web sites? Persist 1 Type - S32 + Boolean Value - -1 + 1 - DebugStatModeSimFPS + BrowserJavascriptEnabled Comment - Mode of stat in Statistics floater + Enable Javascript in the built-in Web browser? Persist 1 Type - S32 + Boolean Value - -1 + 1 - DebugStatModePhysicsFPS + BrowserPluginsEnabled Comment - Mode of stat in Statistics floater + Enable Web plugins in the built-in Web browser? Persist 1 Type - S32 + Boolean Value - -1 + 1 - DebugStatModePinnedObjects + CreateToolCopyCenters Comment - Mode of stat in Statistics floater + Persist - 1 + 0 Type - S32 + Boolean Value - -1 + 1 - DebugStatModeLowLODObjects + CreateToolCopyRotates Comment - Mode of stat in Statistics floater + Persist - 1 + 0 Type - S32 + Boolean Value - -1 + 0 - DebugStatModeMemoryAllocated + CreateToolCopySelection Comment - Mode of stat in Statistics floater + Persist - 1 + 0 Type - S32 + Boolean Value - -1 + 0 - DebugStatModeAgentUpdatesSec + CreateToolKeepSelected Comment - Mode of stat in Statistics floater + After using create tool, keep the create tool active Persist 1 Type - S32 + Boolean Value - -1 + 0 - DebugStatModeMainAgents + CurlMaxTotalConcurrentConnections Comment - Mode of stat in Statistics floater + Maximum total number of simultaneous curl connections Persist 1 Type - S32 + U32 Value - -1 + 64 - DebugStatModeChildAgents + CurlConcurrentConnectionsPerService Comment - Mode of stat in Statistics floater + Maximum number of simultaneous curl connections per host:port service Persist - 1 + 0 Type - S32 + U32 Value - -1 + 8 - DebugStatModeSimObjects + CurlTimeoutDNSLookup Comment - Mode of stat in Statistics floater + Extra time in seconds added to CurlTimeoutConnect for the initial connect to a host Persist 1 Type - S32 + U32 Value - -1 + 60 - DebugStatModeSimActiveObjects + CurlTimeoutConnect Comment - Mode of stat in Statistics floater + Maximum time allowed until a connection is established (after adding the easy handle) until the server is considered unreachable and the connection is terminated Persist 1 Type - S32 + U32 Value - -1 + 10 - DebugStatModeSimActiveScripts + CurlTimeoutReplyDelay Comment - Mode of stat in Statistics floater + Maximum time the viewer will wait between sending data to the server and receiving (a partial) reply Persist 1 Type - S32 + U32 Value - -1 + 60 - DebugStatModeSimScriptEvents + CurlTimeoutLowSpeedLimit Comment - Mode of stat in Statistics floater + If a transfer speed drops below this value (in bytes/s) during CurlTimeoutLowSpeedTime seconds, the transfer is considered too slow and is terminated Persist 1 Type - S32 + U32 Value - -1 + 7000 - DebugStatModeSimInPPS + CurlTimeoutLowSpeedTime Comment - Mode of stat in Statistics floater + If a transfer speed drops below CurlTimeoutLowSpeedLimit (in bytes/s) during this amount of seconds, the transfer is considered too slow and is terminated Persist 1 Type - S32 + U32 Value - -1 + 30 - DebugStatModeSimOutPPS + CurlTimeoutMaxTransaction Comment - Mode of stat in Statistics floater + Maximum total time of a curl transaction, from when the easy handle is added till the transaction has completed. This INCLUDES DNS lookups (CurlTimeoutDNSLookup), connect time (CurlTimeoutConnect) and waiting for the first server reply (CurlTimeoutReply) as well as the actually time needed for data transfer Persist 1 Type - S32 + U32 Value - -1 + 300 - DebugStatModeSimPendingDownloads + CurlTimeoutMaxTotalDelay Comment - Mode of stat in Statistics floater + Maximum total time of a curl request, from when it is requested till the transaction has completed. This includes queuing due to connection throttling on top of the events covered by CurlTimeoutMaxTransaction Persist 1 Type - S32 + U32 Value - -1 + 600 - SimPendingUploads + Cursor3D Comment - Mode of stat in Statistics floater + Treat Joystick values as absolute positions (not deltas). Persist 1 Type - S32 + Boolean Value - -1 + 1 - DebugStatModeSimTotalUnackedBytes + CustomServer Comment - Mode of stat in Statistics floater + Specifies IP address or hostname of grid to which you connect Persist 1 Type - S32 + String Value - -1 + - DebugStatModeSimFrameMsec + AnimatedObjectsIgnoreLimits + + Comment + Ignore server-enforced limits on animated objects. This is only useful for server testing. + Persist + 1 + Type + Boolean + Value + 0 + + AnimatedObjectsAllowLeftClick + + Comment + Allow left-click interaction with animated objects. Uncertain how much performance impact this will have. + Persist + 1 + Type + Boolean + Value + 0 + + AnimatedObjectsGlobalScale + + Comment + Temporary testing: allow an extra scale factor to be forced on animated objects. + Persist + 1 + Type + F32 + Value + 1.00 + + AnimatedObjectsMaxLegalOffset + + Comment + Max visual offset between object position and rendered position + Persist + 1 + Type + F32 + Value + 3.0 + + AnimatedObjectsMaxLegalSize + + Comment + Max bounding box size for animated object's rendered position + Persist + 1 + Type + F32 + Value + 64.0 + + AvatarBoundingBoxComplexity + + Comment + How many aspects to consider for avatar bounding box + Persist + 1 + Type + S32 + Value + 3 + + DebugAvatarAppearanceMessage + + Comment + Dump a bunch of XML files when handling appearance messages + Persist + 1 + Type + Boolean + Value + 0 + + DebugAvatarRezTime + + Comment + Display times for avatars to resolve. + Persist + 1 + Type + Boolean + Value + 0 + + DebugAvatarLocalTexLoadedTime + + Comment + Display time for loading avatar local textures. + Persist + 1 + Type + Boolean + Value + 1 + + DebugAvatarCompositeBaked + + Comment + Colorize avatar meshes based on baked/composite state. + Persist + 1 + Type + Boolean + Value + 0 + + DebugBeaconLineWidth Comment - Mode of stat in Statistics floater + Size of lines for Debug Beacons Persist 1 Type S32 Value - -1 + 1 - DebugStatModeSimNetMsec + DebugHideEmptySystemFolders Comment - Mode of stat in Statistics floater + Hide empty system folders when on Persist 1 Type - S32 + Boolean Value - -1 + 1 - DebugStatModeSimSimPhysicsMsec + DebugInventoryFilters Comment - Mode of stat in Statistics floater + Turn on debugging display for inventory filtering Persist 1 Type - S32 + Boolean Value - -1 + 0 - DebugStatModeSimSimOtherMsec + DebugPermissions Comment - Mode of stat in Statistics floater + Log permissions for selected inventory items Persist 1 Type - S32 + Boolean Value - -1 + 0 - DebugStatModeSimAgentMsec + DebugPluginDisableTimeout Comment - Mode of stat in Statistics floater + Disable the code which watches for plugins that are crashed or hung Persist 1 Type - S32 + Boolean Value - -1 + 0 - DebugStatModeSimImagesMsec + DebugShowColor Comment - Mode of stat in Statistics floater + Show color under cursor Persist 1 Type - S32 + Boolean Value - -1 + 0 - DebugStatModeSimScriptMsec + DebugShowMemory Comment - Mode of stat in Statistics floater + Show Total Allocated Memory Persist 1 Type - S32 + Boolean Value - -1 + 0 - DebugStatModeSimSpareMsec + DebugShowPrivateMem Comment - Mode of stat in Statistics floater + Show Private Mem Info Persist 1 Type - S32 + Boolean Value - -1 + 0 - DebugStatModeSimSimPhysicsStepMsec + DebugShowRenderInfo Comment - Mode of stat in Statistics floater + Show stats about current scene Persist 1 Type - S32 + Boolean Value - -1 + 0 - DebugStatModeSimSimPhysicsShapeUpdateMsec + DebugShowRenderMatrices Comment - Mode of stat in Statistics floater + Display values of current view and projection matrices. Persist 1 Type - S32 + Boolean Value - -1 + 0 - DebugStatModeSimSimPhysicsOtherMsec + DebugShowTime Comment - Mode of stat in Statistics floater + Show time info Persist 1 Type - S32 + Boolean Value - -1 + 0 - DebugStatModeSimSleepMsec + DebugStatModeFPS Comment Mode of stat in Statistics floater @@ -5541,7 +5664,7 @@ This should be as low as possible, but too low may break functionality Value -1 - DebugStatModeSimPumpIOMsec + DebugStatModeBandwidth Comment Mode of stat in Statistics floater @@ -5552,605 +5675,604 @@ This should be as low as possible, but too low may break functionality Value -1 - DebugViews + DebugStatModePacketLoss Comment - Display debugging info for views. + Mode of stat in Statistics floater Persist 1 Type - Boolean + S32 Value - 0 + -1 - DebugWindowProc + DebugStatMode Comment - Log windows messages + Mode of stat in Statistics floater Persist 1 Type - Boolean + S32 Value - 0 + -1 - DefaultObjectTexture + DebugStatModeKTrisDrawnFr Comment - Texture used as 'Default' in texture picker. (UUID texture reference) + Mode of stat in Statistics floater Persist 1 Type - String + S32 Value - 89556747-24cb-43ed-920b-47caed15465f + -1 - DisableCameraConstraints + DebugStatModeKTrisDrawnSec Comment - Disable the normal bounds put on the camera by avatar position + Mode of stat in Statistics floater Persist 1 Type - Boolean + S32 Value - 0 + -1 - DisableExternalBrowser + DebugStatModeTotalObjs Comment - Disable opening an external browser. + Mode of stat in Statistics floater Persist 1 Type - Boolean + S32 Value - 0 + -1 - DisableRendering + DebugStatModeNewObjs Comment - Disable GL rendering and GUI (load testing) + Mode of stat in Statistics floater Persist 1 Type - Boolean + S32 Value - 0 + -1 - DisableTextHyperlinkActions + DebugStatModeTextureCount Comment - Disable highlighting and linking of URLs in XUI text boxes + Mode of stat in Statistics floater Persist 1 Type - Boolean + S32 Value - 0 + -1 - DisableVerticalSync + DebugStatModeRawCount Comment - Update frames as fast as possible (FALSE = update frames between display scans) + Mode of stat in Statistics floater Persist 1 Type - Boolean + S32 Value - 1 + -1 - DisplayAvatarAgentTarget + DebugStatModeGLMem Comment - Show avatar positioning locators (animation debug) + Mode of stat in Statistics floater Persist 1 Type - Boolean + S32 Value - 0 + -1 - DisplayChat + DebugStatModeMalloc Comment - Display Latest Chat message on LCD + Mode of stat in Statistics floater Persist 1 Type - Boolean + S32 Value - 1 - - DisplayDebug + -1 + + DebugStatModeFormattedMem Comment - Display Network Information on LCD + Mode of stat in Statistics floater Persist 1 Type - Boolean + S32 Value - 1 + -1 - DisplayDebugConsole + DebugStatModeRawMem Comment - Display Console Debug Information on LCD + Mode of stat in Statistics floater Persist 1 Type - Boolean + S32 Value - 1 + -1 - DisplayIM + DebugStatModeBoundMem Comment - Display Latest IM message on LCD + Mode of stat in Statistics floater Persist 1 Type - Boolean + S32 Value - 1 + -1 - DisplayLinden + DebugStatModePacketsIn Comment - Display Account Information on LCD + Mode of stat in Statistics floater Persist 1 Type - Boolean + S32 Value - 1 + -1 - DisplayRegion + DebugStatModePacketsOut Comment - Display Location information on LCD + Mode of stat in Statistics floater Persist 1 Type - Boolean + S32 Value - 1 + -1 - DisplayTimecode + DebugStatModeObjects Comment - Display timecode on screen + Mode of stat in Statistics floater Persist 1 Type - Boolean + S32 Value - 0 + -1 - Disregard128DefaultDrawDistance + DebugStatModeHTTPTexture Comment - Whether to use the auto default to 128 draw distance + Mode of stat in Statistics floater Persist 1 Type - Boolean + S32 Value - 1 + -1 - Disregard96DefaultDrawDistance + DebugStatModeUDPTexture Comment - Whether to use the auto default to 96 draw distance + Mode of stat in Statistics floater Persist 1 Type - Boolean + S32 Value - 1 + -1 - ClickActionBuyEnabled + DebugStatModeAsset Comment - Enable click to buy actions in tool pie menu + Mode of stat in Statistics floater Persist 1 Type - Boolean + S32 Value - 1 + -1 - ClickActionPayEnabled + DebugStatModeLayers Comment - Enable click to pay actions in tool pie menu + Mode of stat in Statistics floater Persist 1 Type - Boolean + S32 Value - 1 + -1 - DoubleClickAutoPilot + DebugStatModeActualIn Comment - Enable double-click auto pilot + Mode of stat in Statistics floater Persist 1 Type - Boolean + S32 Value - 0 + -1 - DoubleClickTeleport + DebugStatModeActualOut Comment - Enable double-click to teleport where allowed + Mode of stat in Statistics floater Persist 1 Type - Boolean + S32 Value - 0 + -1 - DoubleClickTeleportMiniMap + DebugStatModeVFSPendingOps Comment - Enable double-click-teleport for the mini-map + Mode of stat in Statistics floater Persist 1 Type - Boolean + S32 Value - 0 + -1 - DragAndDropToolTipDelay + DebugStatModeTimeDialation Comment - Seconds before displaying tooltip when performing drag and drop operation + Mode of stat in Statistics floater Persist 1 Type - F32 + S32 Value - 0.10000000149 + -1 - DragAndDropDistanceThreshold + DebugStatModeSimFPS Comment - Number of pixels that mouse should move before triggering drag and drop mode + Mode of stat in Statistics floater Persist 1 Type S32 Value - 3 + -1 - DropShadowButton + DebugStatModePhysicsFPS Comment - Drop shadow width for buttons (pixels) + Mode of stat in Statistics floater Persist 1 Type S32 Value - 2 + -1 - DropShadowFloater + DebugStatModePinnedObjects Comment - Drop shadow width for floaters (pixels) + Mode of stat in Statistics floater Persist 1 Type S32 Value - 5 + -1 - DropShadowSlider + DebugStatModeLowLODObjects Comment - Drop shadow width for sliders (pixels) + Mode of stat in Statistics floater Persist 1 Type S32 Value - 3 + -1 - DropShadowTooltip + DebugStatModeMemoryAllocated Comment - Drop shadow width for tooltips (pixels) + Mode of stat in Statistics floater Persist 1 Type S32 Value - 4 + -1 - DumpVFSCaches + DebugStatModeAgentUpdatesSec Comment - Dump VFS caches on startup. + Mode of stat in Statistics floater Persist 1 Type - Boolean + S32 Value - 0 + -1 - DynamicCameraStrength + DebugStatModeMainAgents Comment - Amount camera lags behind avatar motion (0 = none, 30 = avatar velocity) + Mode of stat in Statistics floater Persist 1 Type - F32 + S32 Value - 2.0 + -1 - EditCameraMovement + DebugStatModeChildAgents Comment - When entering build mode, camera moves up above avatar + Mode of stat in Statistics floater Persist 1 Type - Boolean + S32 Value - 0 + -1 - EditLinkedParts + DebugStatModeSimObjects Comment - Select individual parts of linked objects + Mode of stat in Statistics floater Persist - 0 + 1 Type - Boolean + S32 Value - 0 + -1 - DecimalsForTools + DebugStatModeSimActiveObjects Comment - Number of decimals for the edit tool position, size and rotation settings (0 to 5) + Mode of stat in Statistics floater Persist 1 Type - U32 + S32 Value - 5 + -1 - EffectScriptChatParticles + DebugStatModeSimActiveScripts Comment - 1 = normal behavior, 0 = disable display of swirling lights when scripts communicate + Mode of stat in Statistics floater Persist 1 Type - Boolean + S32 Value - 1 + -1 - EnableGrab + DebugStatModeSimScriptEvents Comment - Use Ctrl+mouse to grab and manipulate objects + Mode of stat in Statistics floater Persist 1 Type - Boolean + S32 Value - 1 + -1 - EnableGestureSounds + DebugStatModeSimInPPS Comment - Play sounds from gestures + Mode of stat in Statistics floater Persist 1 Type - Boolean + S32 Value - 1 + -1 - EnableGestureSoundsSelf + DebugStatModeSimOutPPS Comment - Play sounds from your gestures when EnableGestureSounds is false. (Useless otherwise) + Mode of stat in Statistics floater Persist 1 Type - Boolean + S32 Value - 1 + -1 - EnableMouselook + DebugStatModeSimPendingDownloads Comment - Allow first person perspective and mouse control of camera + Mode of stat in Statistics floater Persist 1 Type - Boolean + S32 Value - 1 + -1 - EnableVoiceChat + SimPendingUploads Comment - Enable talking to other residents with a microphone + Mode of stat in Statistics floater Persist 1 Type - Boolean + S32 Value - 0 + -1 - EnergyFromTop + DebugStatModeSimTotalUnackedBytes Comment - + Mode of stat in Statistics floater Persist - 0 + 1 Type S32 Value - 20 + -1 - EnergyHeight + DebugStatModeSimFrameMsec Comment - + Mode of stat in Statistics floater Persist - 0 + 1 Type S32 Value - 40 + -1 - EnergyWidth + DebugStatModeSimNetMsec Comment - + Mode of stat in Statistics floater Persist - 0 + 1 Type S32 Value - 175 + -1 - EveryoneCopy + DebugStatModeSimSimPhysicsMsec Comment - Everyone can copy the newly created objects + Mode of stat in Statistics floater Persist 1 Type - Boolean + S32 Value - 0 + -1 - FPSLogFrequency + DebugStatModeSimSimOtherMsec Comment - Seconds between display of FPS in log (0 for never) + Mode of stat in Statistics floater Persist 1 Type - F32 + S32 Value - 60.0 + -1 - FPSLogFrequency + DebugStatModeSimAgentMsec Comment - Seconds between display of FPS in log (0 for never) + Mode of stat in Statistics floater Persist 1 Type - F32 + S32 Value - 10.0 + -1 - FilterGamingSearchAll + DebugStatModeSimImagesMsec Comment - Filter results flagged gaming in everything search + Mode of stat in Statistics floater Persist 1 - HideFromEditor - 1 Type - Boolean + S32 Value - 1 + -1 - FilterGamingClassifieds + DebugStatModeSimScriptMsec Comment - Filter results flagged gaming in classifieds search + Mode of stat in Statistics floater Persist 1 - HideFromEditor - 1 Type - Boolean + S32 Value - 1 + -1 - FilterGamingEvents + DebugStatModeSimSpareMsec Comment - Filter results flagged gaming in event search + Mode of stat in Statistics floater Persist 1 - HideFromEditor - 1 Type - Boolean + S32 Value - 1 + -1 - FilterGamingGroups + DebugStatModeSimSimPhysicsStepMsec Comment - Filter results flagged gaming in groups search + Mode of stat in Statistics floater Persist 1 - HideFromEditor - 1 Type - Boolean + S32 Value - 1 + -1 - FilterGamingLand + DebugStatModeSimSimPhysicsShapeUpdateMsec Comment - Filter results flagged gaming in land search + Mode of stat in Statistics floater Persist 1 - HideFromEditor - 1 Type - Boolean + S32 Value - 1 + -1 - FilterGamingSims + DebugStatModeSimSimPhysicsOtherMsec Comment - Filter results flagged gaming in sim search + Mode of stat in Statistics floater Persist 1 - HideFromEditor - 1 Type - Boolean + S32 Value + -1 + + DebugStatModeSimSleepMsec + + Comment + Mode of stat in Statistics floater + Persist 1 + Type + S32 + Value + -1 - FilterItemsPerFrame + DebugStatModeSimPumpIOMsec Comment - Maximum number of inventory items to match against search filter every frame (lower to increase framerate while searching, higher to improve search speed) + Mode of stat in Statistics floater Persist 1 Type S32 Value - 500 + -1 - FindLandArea + DebugViews Comment - Enables filtering of land search results by area + Display debugging info for views. Persist 1 Type @@ -6158,109 +6280,114 @@ This should be as low as possible, but too low may break functionality Value 0 - FindLandPrice + DebugWindowProc Comment - Enables filtering of land search results by price + Log windows messages Persist 1 Type Boolean Value - 1 + 0 - FindLandType + DefaultBlankNormalTexture Comment - Controls which type of land you are searching for in Find Land interface ("All", "Auction", "For Sale") + Texture used as 'Blank' in texture picker for normal map. (UUID texture reference) Persist 1 Type String Value - All + 5b53359e-59dd-d8a2-04c3-9e65134da47a - FindPeopleOnline + DefaultObjectNormalTexture Comment - Limits people search to only users who are logged on + Texture used as 'Default' in texture picker for normal map. (UUID texture reference) Persist 1 Type - Boolean + String Value - 1 + 85f28839-7a1c-b4e3-d71d-967792970a7b - FindPlacesPictures + DefaultObjectSpecularTexture Comment - Display only results of find places that have pictures + Texture used as 'Default' in texture picker for specular map. (UUID texture reference) Persist 1 Type - Boolean + String Value - 1 + 87e0e8f7-8729-1ea8-cfc9-8915773009db - FirstName + DefaultObjectTexture Comment - Login first name + Texture used as 'Default' in texture picker. (UUID texture reference) Persist 1 Type String Value - + 89556747-24cb-43ed-920b-47caed15465f - FirstPersonAvatarVisible + DestinationGuideRect Comment - Display avatar and attachments below neck while in mouselook + Rectangle for destination guide Persist 1 Type - Boolean + Rect Value - 0 + + 30 + 505 + 580 + 275 + - FirstPersonBtnState + DestinationGuideShown Comment - + Show destination guide Persist - 0 + 1 Type Boolean Value 0 - FirstRunThisInstall + DestinationGuideURL Comment - Specifies that you have not run the viewer since you installed the latest update + Destination guide contents Persist - 1 + 0 Type - Boolean + String Value - 1 + http://lecs-viewer-web-components.s3.amazonaws.com/v3.0/[GRID_LOWERCASE]/guide.html - FirstLoginThisInstall + DisableCameraConstraints Comment - Specifies that you have not successfully logged in since you installed the latest update + Disable the normal bounds put on the camera by avatar position Persist 1 Type Boolean Value - 1 + 0 - FixedWeather + DisableExternalBrowser Comment - Weather effects do not change over time + Disable opening an external browser. Persist 1 Type @@ -6268,119 +6395,109 @@ This should be as low as possible, but too low may break functionality Value 0 - LongDateFormat + DisableRendering Comment - Long date format to use + Disable GL rendering and GUI (load testing) Persist 1 Type - String + Boolean Value - %A %d %B %Y + 0 - ShortDateFormat + DisableTextHyperlinkActions Comment - Short date format to use + Disable highlighting and linking of URLs in XUI text boxes Persist 1 Type - String + Boolean Value - %Y-%m-%d + 0 - ShortTimeFormat + DisableVerticalSync Comment - Short time format (hours and minutes) to use + Update frames as fast as possible (FALSE = update frames between display scans) Persist 1 Type - String + Boolean Value - %H:%M + 1 - LongTimeFormat + DisplayAvatarAgentTarget Comment - Long time format (hours, minutes and seconds) to use + Show avatar positioning locators (animation debug) Persist 1 Type - String + Boolean Value - %H:%M:%S + 0 - TimestampFormat + DisplayChat Comment - Timestamp format to use + Display Latest Chat message on LCD Persist 1 Type - String + Boolean Value - %a %d %b %Y %H:%M:%S + 1 - SecondsInChatAndIMs + DisplayDebug Comment - TRUE to add seconds to timestamps for IM and chat + Display Network Information on LCD Persist 1 Type Boolean Value - 0 + 1 - SecondsInLog + DisplayDebugConsole Comment - TRUE to add seconds to timestamps for Log + Display Console Debug Information on LCD Persist 1 Type Boolean Value - 0 + 1 - FloaterAboutRect + DisplayIM Comment - Rectangle for About window + Display Latest IM message on LCD Persist 1 Type - Rect + Boolean Value - - 0 - 440 - 470 - 0 - + 1 - FloaterActiveSpeakersRect + DisplayLinden Comment - Rectangle for active speakers window + Display Account Information on LCD Persist 1 Type - Rect + Boolean Value - - 0 - 300 - 250 - 0 - + 1 - FloaterActiveSpeakersSortAscending + DisplayRegion Comment - Whether to sort up or down + Display Location information on LCD Persist 1 Type @@ -6388,624 +6505,473 @@ This should be as low as possible, but too low may break functionality Value 1 - FloaterActiveSpeakersSortColumn + DisplayTimecode Comment - Column name to sort on + Display timecode on screen Persist 1 Type - String + Boolean Value - speaking_status + 0 - FloaterAreaSearchRect + Disregard128DefaultDrawDistance Comment - Rectangle for the area search floater + Whether to use the auto default to 128 draw distance Persist 1 Type - Rect + Boolean Value - - 0 - 400 - 200 - 0 - + 1 - FloaterAdvancedSkyRect + Disregard96DefaultDrawDistance Comment - Rectangle for Advanced Sky Editor + Whether to use the auto default to 96 draw distance Persist 1 Type - Rect + Boolean Value - - 0 - 220 - 700 - 0 - + 1 - FloaterAdvancedWaterRect + ClickActionBuyEnabled Comment - Rectangle for Advanced Water Editor + Enable click to buy actions in tool pie menu Persist 1 Type - Rect + Boolean Value - - 0 - 240 - 700 - 0 - + 1 - FloaterAudioVolumeRect + ClickActionPayEnabled Comment - Rectangle for Audio Volume window + Enable click to pay actions in tool pie menu Persist 1 Type - Rect + Boolean Value - - 0 - 440 - 470 - 0 - + 1 - FloaterBeaconsRect + DoubleClickAutoPilot Comment - Rectangle for beacon and highlight controls + Enable double-click auto pilot Persist 1 Type - Rect + Boolean Value - - 200 - 250 - 250 - 200 - + 0 - FloaterBuildOptionsRect + DoubleClickTeleport Comment - Rectangle for build options window. + Enable double-click to teleport where allowed Persist 1 Type - Rect + Boolean Value - - 0 - 0 - 0 - 0 - + 0 - FloaterVFSRect + DoubleClickTeleportMap Comment - Rectangle for local assets window. + Enable double-click-teleport for the map Persist 1 Type - Rect + Boolean Value - - 0 - 0 - 0 - 0 - + 1 - FloaterBumpRect + DoubleClickTeleportMiniMap Comment - Rectangle for Bumps/Hits window + Enable double-click-teleport for the mini-map Persist 1 Type - Rect + Boolean Value - - 0 - 180 - 400 - 0 - + 0 - FloaterBuyContentsRect + DoubleClickShowWorldMap Comment - Rectangle for Buy Contents window + Enable double-click to show world map from mini map Persist 1 Type - Rect + Boolean Value - - 0 - 250 - 300 - 0 - + 1 - FloaterBuyRect + DragAndDropToolTipDelay Comment - Rectangle for buy window + Seconds before displaying tooltip when performing drag and drop operation Persist 1 Type - Rect + F32 Value - - 0 - 250 - 300 - 0 - + 0.10000000149 - FloaterCameraRect3 + DragAndDropDistanceThreshold Comment - Rectangle for camera control window + Number of pixels that mouse should move before triggering drag and drop mode Persist 1 Type - Rect + S32 Value - - 0 - 64 - 176 - 0 - + 3 - FloaterChatRect + DropShadowButton Comment - Rectangle for chat history + Drop shadow width for buttons (pixels) Persist 1 Type - Rect + S32 Value - - 0 - 172 - 500 - 0 - + 2 - FloaterClothingRect + DropShadowFloater Comment - Rectangle for clothing window + Drop shadow width for floaters (pixels) Persist 1 Type - Rect + S32 Value - - 0 - 480 - 320 - 0 - + 5 - FloaterContactsRect + DropShadowSlider Comment - Rectangle for contacts floater + Drop shadow width for sliders (pixels) Persist 1 Type - Rect + S32 Value - - 0 - 390 - 395 - 0 - + 3 - FloaterContactsHorizRect + DropShadowTooltip Comment - Rectangle for contacts floater in horizontal mode + Drop shadow width for tooltips (pixels) Persist 1 Type - Rect + S32 Value - - 0 - 390 - 395 - 0 - + 4 - FloaterCustomizeAppearanceRect + DumpVFSCaches Comment - Rectangle for avatar customization window + Dump VFS caches on startup. Persist 1 Type - Rect + Boolean Value - - 0 - 540 - 494 - 0 - + 0 - FloaterDayCycleRect + DynamicCameraStrength Comment - Rectangle for Day Cycle Editor + Amount camera lags behind avatar motion (0 = none, 30 = avatar velocity) Persist 1 Type - Rect + F32 Value - - 0 - 646 - 275 - 0 - + 2.0 - FloaterDebugSettingsRect + EditCameraMovement Comment - Rectangle for the Debug Settings floater + When entering build mode, camera moves up above avatar Persist 1 Type - Rect + Boolean Value - - 0 - 300 - 245 - 0 - + 0 - FloaterEnvRect + EditLinkedParts Comment - Rectangle for Environment Editor + Select individual parts of linked objects Persist - 1 + 0 Type - Rect + Boolean Value - - 0 - 150 - 600 - 0 - + 0 - FloaterFavoritesRect + DecimalsForTools Comment - Rectangle for favorites window + Number of decimals for the edit tool position, size and rotation settings (0 to 5) Persist 1 Type - Rect + U32 Value - - 0 - 400 - 250 - 0 - + 5 - FloaterFindRect2 + EffectScriptChatParticles Comment - Rectangle for Find window + 1 = normal behavior, 0 = disable display of swirling lights when scripts communicate Persist 1 Type - Rect + Boolean Value - - 0 - 570 - 780 - 0 - + 1 - FloaterFriendsRect + EnableGrab Comment - Rectangle for friends window + Use Ctrl+mouse to grab and manipulate objects Persist 1 Type - Rect + Boolean Value - - 0 - 400 - 250 - 0 - + 1 - FloaterGestureRect2 + EnableGestureSounds Comment - Rectangle for gestures window + Play sounds from gestures Persist 1 Type - Rect + Boolean Value - - 0 - 465 - 350 - 0 - + 1 - FloaterHUDRect2 + EnableGestureSoundsSelf Comment - Rectangle for HUD Floater window + Play sounds from your gestures when EnableGestureSounds is false. (Useless otherwise) Persist 1 Type - Rect + Boolean Value - - - 0 - 292 - 362 - 0 - + 1 - FloaterHtmlRect + EnableNongestureSounds Comment - Rectangle for HTML window + Play sounds from non-gestures Persist 1 Type - Rect + Boolean Value - - 100 - 460 - 370 - 100 - + 1 - FloaterIMRect + EnableNongestureSoundsSelf Comment - Rectangle for IM window + Play sounds from your non-gestures when EnableNongestureSounds is false. (Useless otherwise) Persist 1 Type - Rect + Boolean Value - - 0 - 160 - 500 - 0 - + 1 - FloaterInspectRect + EnableMouselook Comment - Rectangle for Object Inspect window + Allow first person perspective and mouse control of camera Persist 1 Type - Rect + Boolean Value - - 0 - 400 - 400 - 0 - + 1 - FloaterInventoryRect + EnableVoiceChat Comment - Rectangle for inventory window + Enable talking to other residents with a microphone Persist 1 Type - Rect + Boolean Value - - 0 - 400 - 300 - 0 - + 0 - FloaterInvPanelRect + EnergyFromTop Comment - Rectangle for new inventory windows a folder is opened in + Persist - 1 + 0 Type - Rect + S32 Value - - 0 - 400 - 300 - 0 - + 20 - FloaterJoystickRect + EnergyHeight Comment - Rectangle for joystick controls window. + Persist - 1 + 0 Type - Rect + S32 Value - - 0 - 0 - 0 - 0 - + 40 - FloaterLagMeter + EnergyWidth Comment - Rectangle for lag meter + Persist - 1 + 0 Type - Rect + S32 Value - - 0 - 142 - 350 - 0 - + 175 - ShowRadar + FPSLogFrequency Comment - Show the radar floater + Seconds between display of FPS in log (0 for never) Persist 1 Type - Boolean + F32 Value - 0 + 60.0 - FloaterRadarRect + FPSLogFrequency Comment - Rectangle for Radar + Seconds between display of FPS in log (0 for never) Persist 1 Type - Rect + F32 Value - - 0 - 400 - 200 - 0 - + 10.0 - RadarColumnMarkWidth + FilterGamingSearchAll Comment - Width for radar's mark column + Filter results flagged gaming in everything search Persist 1 + HideFromEditor + 1 Type - S32 + Boolean Value - 12 + 1 - RadarColumnPositionWidth + FilterGamingClassifieds Comment - Width for radar's position column + Filter results flagged gaming in classifieds search Persist 1 + HideFromEditor + 1 Type - S32 + Boolean Value - 60 + 1 - RadarColumnAltitudeWidth + FilterGamingEvents Comment - Width for radar's altitude column + Filter results flagged gaming in event search Persist 1 + HideFromEditor + 1 Type - S32 + Boolean Value - 48 + 1 - RadarColumnActivityWidth + FilterGamingGroups Comment - Width for radar's activity column + Filter results flagged gaming in groups search Persist 1 + HideFromEditor + 1 Type - S32 + Boolean Value - 24 + 1 - RadarColumnAgeWidth + FilterGamingLand Comment - Width for radar's age column + Filter results flagged gaming in land search Persist 1 + HideFromEditor + 1 Type - S32 + Boolean Value - 45 + 1 - RadarColumnTimeWidth + FilterGamingSims Comment - Width for radar's time column + Filter results flagged gaming in sim search Persist 1 + HideFromEditor + 1 Type - S32 + Boolean Value - 52 + 1 - RadarColumnNameWidth + FilterItemsPerFrame Comment - Width for radar's name column + Maximum number of inventory items to match against search filter every frame (lower to increase framerate while searching, higher to improve search speed) Persist 1 Type S32 Value - 80 + 500 - RadarColumnMarkHidden + FindLandArea Comment - Hide radar's mark column + Enables filtering of land search results by area Persist 1 Type @@ -7013,54 +6979,43 @@ This should be as low as possible, but too low may break functionality Value 0 - RadarColumnPositionHidden + FindLandPrice Comment - Hide radar's position column + Enables filtering of land search results by price Persist 1 Type Boolean Value - 0 - - RadarColumnAltitudeHidden - - Comment - Hide radar's altitude column - Persist 1 - Type - Boolean - Value - 0 - RadarColumnActivityHidden + FindLandType Comment - Hide radar's activity column + Controls which type of land you are searching for in Find Land interface ("All", "Auction", "For Sale") Persist 1 Type - Boolean + String Value - 0 + All - RadarColumnAgeHidden + FindPeopleOnline Comment - Hide radar's age column + Limits people search to only users who are logged on Persist 1 Type Boolean Value - 0 + 1 - RadarColumnTimeHidden + FindPlacesPictures Comment - Hide radar's time column + Display only results of find places that have pictures Persist 1 Type @@ -7068,21 +7023,21 @@ This should be as low as possible, but too low may break functionality Value 1 - RadarColumnClientHidden + FirstName Comment - Hide radar's client column + Login first name Persist 1 Type - Boolean + String Value - 0 + - RadarKeepOpen + FirstPersonAvatarVisible Comment - Keeps radar updates running in background + Display avatar and attachments below neck while in mouselook Persist 1 Type @@ -7090,45 +7045,43 @@ This should be as low as possible, but too low may break functionality Value 0 - RadarRangeRadius + FirstPersonBtnState Comment - How far away avatars on the radar can be, 0 for no limit + Persist - 1 + 0 Type - F32 + Boolean Value - 0 + 0 - RadarUpdateEnabled + FirstRunThisInstall Comment - When false, pauses the radar until further notice, good for banning someone who just left. + Specifies that you have not run the viewer since you installed the latest update Persist - 0 - HideFromEditor 1 Type Boolean Value 1 - RadarUpdateRate + FirstLoginThisInstall Comment - Radar update rate (0 = high, 1 = medium, 2 = low) + Specifies that you have not successfully logged in since you installed the latest update Persist 1 Type - U32 + Boolean Value 1 - RadarAlertSim + FixedWeather Comment - Whether the radar emits chat alerts for avatars entering/exiting sim + Weather effects do not change over time Persist 1 Type @@ -7136,65 +7089,65 @@ This should be as low as possible, but too low may break functionality Value 0 - RadarAlertDraw + LongDateFormat Comment - Whether the radar emits chat alerts for avatars entering/exiting draw distance + Long date format to use Persist 1 Type - Boolean + String Value - 0 + %A %d %B %Y - RadarAlertShoutRange + ShortDateFormat Comment - Whether the radar emits chat alerts for avatars entering/exiting shout range + Short date format to use Persist 1 Type - Boolean + String Value - 0 + %F - RadarAlertChatRange + ShortTimeFormat Comment - Whether the radar emits chat alerts for avatars entering/exiting chat range + Short time format (hours and minutes) to use Persist 1 Type - Boolean + String Value - 1 + %R - RadarAlertAge + LongTimeFormat Comment - Whether the radar emits chat alerts for avatars younger than AvatarAgeAlertDays appearing. + Long time format (hours, minutes and seconds) to use Persist 1 Type - Boolean + String Value - 0 + %T - AvatarAgeAlertDays + TimestampFormat Comment - Age below which avatars will be made known to you + Timestamp format to use Persist 1 Type - U32 + String Value - 3 + %a %d %b %Y %T - RadarChatAlerts + SecondsInChatAndIMs Comment - Whether the radar emits chat alerts regarding the status of avatars it displays + TRUE to add seconds to timestamps for IM and chat Persist 1 Type @@ -7202,32 +7155,37 @@ This should be as low as possible, but too low may break functionality Value 0 - RadarChatKeys + SecondsInLog Comment - Enable alerting scripts about avatars detected by the radar + TRUE to add seconds to timestamps for Log Persist 1 Type Boolean Value - 0 + 1 - RadarChatKeysStopAsking + FloaterAboutRect Comment - Do not ask if RadarChatKeys should be enabled when a script requests for the radar's keys. + Rectangle for About window Persist 1 Type - Boolean + Rect Value - 0 + + 0 + 440 + 470 + 0 + - FloaterLandRect5 + FloaterActiveSpeakersRect Comment - Rectangle for About Land window + Rectangle for active speakers window Persist 1 Type @@ -7235,47 +7193,37 @@ This should be as low as possible, but too low may break functionality Value 0 - 370 - 460 + 300 + 250 0 - FloaterLandmarkRect + FloaterActiveSpeakersSortAscending Comment - Rectangle for landmark picker + Whether to sort up or down Persist 1 Type - Rect + Boolean Value - - 0 - 290 - 310 - 0 - + 1 - FloaterMediaRect + FloaterActiveSpeakersSortColumn Comment - Rectangle for media browser window + Column name to sort on Persist 1 Type - Rect + String Value - - 16 - 650 - 600 - 128 - + speaking_status - FloaterMiniMapRect + FloaterAreaSearchRect Comment - Rectangle for world map + Rectangle for the area search floater Persist 1 Type @@ -7283,15 +7231,15 @@ This should be as low as possible, but too low may break functionality Value 0 - 225 + 400 200 0 - FloaterModelUploadRect + FloaterAdvancedSkyRect Comment - Rectangle for mesh upload floater + Rectangle for Advanced Sky Editor Persist 1 Type @@ -7299,15 +7247,15 @@ This should be as low as possible, but too low may break functionality Value 0 - 480 - 940 - 52 + 220 + 700 + 0 - FloaterMoveRect2 + FloaterAdvancedWaterRect Comment - Rectangle for avatar control window + Rectangle for Advanced Water Editor Persist 1 Type @@ -7315,15 +7263,15 @@ This should be as low as possible, but too low may break functionality Value 0 - 58 - 135 + 240 + 700 0 - FloaterMuteRect3 + FloaterAudioVolumeRect Comment - Rectangle for mute window + Rectangle for Audio Volume window Persist 1 Type @@ -7331,31 +7279,31 @@ This should be as low as possible, but too low may break functionality Value 0 - 300 - 300 + 440 + 470 0 - FloaterMyOutfitsRect + FloaterBeaconsRect Comment - Rectangle for My Outfits window + Rectangle for beacon and highlight controls Persist 1 Type Rect Value - 0 - 400 + 200 250 - 0 + 250 + 200 - FloaterObjectIMInfo + FloaterBuildOptionsRect Comment - Rectangle for floater object im info windows + Rectangle for build options window. Persist 1 Type @@ -7363,15 +7311,15 @@ This should be as low as possible, but too low may break functionality Value 0 - 300 - 300 + 0 + 0 0 - FloaterOpenObjectRect + FloaterVFSRect Comment - Rectangle for Open Object window + Rectangle for local assets window. Persist 1 Type @@ -7379,31 +7327,31 @@ This should be as low as possible, but too low may break functionality Value 0 - 350 - 300 + 0 + 0 0 - FloaterOutboxRect + FloaterBumpRect Comment - Rectangle for merchant outbox window + Rectangle for Bumps/Hits window Persist 1 Type Rect Value - 0 - 342 - 310 - 52 + 0 + 180 + 400 + 0 - FloaterPayRectB + FloaterBuyContentsRect Comment - Rectangle for pay window + Rectangle for Buy Contents window Persist 1 Type @@ -7411,31 +7359,31 @@ This should be as low as possible, but too low may break functionality Value 0 - 150 - 400 + 250 + 300 0 - FloaterPermPrefsRect + FloaterBuyRect Comment - Rectangle for initial permissions preferences + Rectangle for buy window Persist 1 Type Rect Value - 200 - 250 + 0 250 - 200 + 300 + 0 - FloaterRegionInfo + FloaterCameraRect3 Comment - Rectangle for region info window + Rectangle for camera control window Persist 1 Type @@ -7443,15 +7391,15 @@ This should be as low as possible, but too low may break functionality Value 0 - 512 - 480 + 64 + 176 0 - FloaterScriptDebugRect + FloaterChatRect Comment - Rectangle for Script Error/Debug window + Rectangle for chat history Persist 1 Type @@ -7459,15 +7407,15 @@ This should be as low as possible, but too low may break functionality Value 0 - 130 - 450 + 172 + 500 0 - FloaterScriptLimitsRect + FloaterClothingRect Comment - Rectangle for Script Limits window + Rectangle for clothing window Persist 1 Type @@ -7475,31 +7423,31 @@ This should be as low as possible, but too low may break functionality Value 0 - 500 480 + 320 0 - FloaterSearchRect + FloaterContactsRect Comment - Rectangle for web search browser window + Rectangle for contacts floater Persist 1 Type Rect Value - 16 - 650 - 600 - 128 + 0 + 390 + 395 + 0 - FloaterSnapshotRect + FloaterContactsHorizRect Comment - Rectangle for snapshot window + Rectangle for contacts floater in horizontal mode Persist 1 Type @@ -7507,15 +7455,15 @@ This should be as low as possible, but too low may break functionality Value 0 - 200 - 200 - 400 + 390 + 395 + 0 - FloaterSnapshotFeedRect + FloaterCustomizeAppearanceRect Comment - Rectangle for snapshot feed window + Rectangle for avatar customization window Persist 1 Type @@ -7523,15 +7471,15 @@ This should be as low as possible, but too low may break functionality Value 0 - 200 - 200 - 400 + 540 + 494 + 0 - FloaterSnapshotPostcardRect + FloaterDayCycleRect Comment - Rectangle for snapshot postcard window + Rectangle for Day Cycle Editor Persist 1 Type @@ -7539,15 +7487,15 @@ This should be as low as possible, but too low may break functionality Value 0 - 346 - 450 - 400 + 646 + 275 + 0 - FloaterSoundsRect + FloaterDebugSettingsRect Comment - Rectangle for sounds log floater. + Rectangle for the Debug Settings floater Persist 1 Type @@ -7555,59 +7503,95 @@ This should be as low as possible, but too low may break functionality Value 0 + 300 + 245 0 + + + FloaterEnvRect + + Comment + Rectangle for Environment Editor + Persist + 1 + Type + Rect + Value + 0 + 150 + 600 0 - FloaterSoundsLogAvatars + FloaterExperiencePickerRect Comment - Show SoundTriggers/gestures played by agents in the log. Also includes collision sounds if enabled + Rectangle for experience picker floater Persist 1 Type - Boolean + Rect Value - 1 + + 300 + 600 + 800 + 700 + - FloaterSoundsLogObjects + FloaterExperienceProfileRect Comment - Show sounds played by objects in the log. Also includes collision sounds if enabled + Rectangle for experience profile floaters Persist 1 Type - Boolean + Rect Value - 1 + + 377 + 650 + 345 + 128 + - FloaterSoundsLogCollisions + FloaterExperiencesRect Comment - Don't filter out default collision sounds in the log + Rectangle for experiences floater Persist 1 Type - Boolean + Rect Value - 1 + + 300 + 600 + 700 + 700 + - FloaterSoundsLogRepeats + FloaterFindRect2 Comment - Only show one entry for each unique asset ID in the log + Rectangle for Find window Persist 1 Type - Boolean + Rect Value - 1 + + 0 + 570 + 780 + 0 + - FloaterStatisticsRect + FloaterFriendsRect Comment - Rectangle for chat history + Rectangle for friends window Persist 1 Type @@ -7620,53 +7604,61 @@ This should be as low as possible, but too low may break functionality 0 - FloaterTeleportHistoryRect + FloaterGestureRect2 Comment - Rectangle for teleport history window + Rectangle for gestures window Persist 1 Type Rect Value - 20 - 20 - 470 - 200 + 0 + 465 + 350 + 0 - FloaterViewBottom + FloaterHUDRect2 Comment - [DO NOT MODIFY] Controls layout of floating windows within SL window + Rectangle for HUD Floater window Persist 1 Type - S32 + Rect Value - -1 + + + 0 + 292 + 362 + 0 + - FloaterVoiceEffectRect + FloaterHtmlRect Comment - Rectangle for voice morpher floater + Rectangle for HTML window Persist 1 Type Rect Value - 0 - 300 - 360 - 0 + 100 + 460 + 370 + 100 - FloaterWorldMapRect2 + FloaterInspectRect Comment - Rectangle for world map window + Rectangle for Object Inspect window Persist 1 Type @@ -7674,15 +7666,15 @@ This should be as low as possible, but too low may break functionality Value 0 - 0 - 0 + 400 + 400 0 - FloaterAORect + FloaterInventoryRect Comment - Rectangle for AO editor. + Rectangle for inventory window Persist 1 Type @@ -7690,31 +7682,42 @@ This should be as low as possible, but too low may break functionality Value 0 - 0 - 0 + 400 + 300 0 - FloaterAvatarsRect + FloaterJoystickRect Comment - Rectangle for avatar radar. + Rectangle for joystick controls window. Persist 1 Type Rect Value - 200 - 905 - 396 - 734 + 0 + 0 + 0 + 0 - FloaterInterceptorRect + ShowRadar Comment - Rectangle for interceptor floater. + Show the radar floater + Persist + 1 + Type + Boolean + Value + 0 + + FloaterRadarRect + + Comment + Rectangle for Radar Persist 1 Type @@ -7722,124 +7725,125 @@ This should be as low as possible, but too low may break functionality Value 0 - 0 - 0 + 400 + 200 0 - FloaterKeyToolRect + RadarColumnMarkWidth Comment - Rectangle for KeyTool floater. + Width for radar's mark column Persist 1 Type - Rect + S32 Value - - 439 - 759 - 593 - 443 - + 12 - KeyToolAutomaticOpen + RadarColumnPositionWidth Comment - Automatically open KeyTool results + Width for radar's position column Persist 1 Type - Boolean + S32 Value - 1 + 60 - KeyToolAutomaticClose + RadarColumnAltitudeWidth Comment - Automatically close KeyTool floater when a result is found + Width for radar's altitude column Persist 1 Type - Boolean + S32 Value - 1 + 48 - FloaterSoundsRect + RadarColumnActivityWidth Comment - Rectangle for sounds log floater. + Width for radar's activity column Persist 1 Type - Rect + S32 Value - - 0 - 0 - 0 - 0 - + 24 - FloaterSoundsLogAvatars + RadarColumnVoiceWidth Comment - Show SoundTriggers/gestures played by agents in the log. Also includes collision sounds if enabled + Width for radar's voice status column Persist 1 Type - Boolean + S32 Value - 1 + 24 - FloaterSoundsLogObjects + RadarColumnNotesWidth Comment - Show sounds played by objects in the log. Also includes collision sounds if enabled + Width for radar's notes column Persist 1 Type - Boolean + S32 Value - 1 + 24 - FloaterSoundsLogCollisions + RadarColumnAgeWidth Comment - Don't filter out default collision sounds in the log + Width for radar's age column Persist 1 Type - Boolean + S32 Value - 1 + 45 - FloaterSoundsLogRepeats + RadarColumnTimeWidth Comment - Only show one entry for each unique asset ID in the log + Width for radar's time column Persist 1 Type - Boolean + S32 Value + 52 + + RadarColumnNameWidth + + Comment + Width for radar's name column + Persist 1 + Type + S32 + Value + 80 - FlyBtnState + RadarColumnMarkHidden Comment - + Hide radar's mark column Persist - 0 + 1 Type Boolean Value 0 - AlwaysAllowFly + RadarColumnPositionHidden Comment - Ignore parcel/region setting that blocks flying + Hide radar's position column Persist 1 Type @@ -7847,10 +7851,10 @@ This should be as low as possible, but too low may break functionality Value 0 - FlycamAbsolute + RadarColumnAltitudeHidden Comment - Treat Flycam values as absolute positions (not deltas). + Hide radar's altitude column Persist 1 Type @@ -7858,186 +7862,188 @@ This should be as low as possible, but too low may break functionality Value 0 - FlycamAxisDeadZone0 + RadarColumnActivityHidden Comment - Flycam axis 0 dead zone. + Hide radar's activity column Persist 1 Type - F32 + Boolean Value - 0.1 + 0 - FlycamAxisDeadZone1 + RadarColumnVoiceHidden Comment - Flycam axis 1 dead zone. + Hide radar's voice status column Persist 1 Type - F32 + Boolean Value - 0.1 + 0 - FlycamAxisDeadZone2 + RadarColumnNotesHidden Comment - Flycam axis 2 dead zone. + Hide radar's notes column Persist 1 Type - F32 + Boolean Value - 0.1 + 1 - FlycamAxisDeadZone3 + RadarColumnAgeHidden Comment - Flycam axis 3 dead zone. + Hide radar's age column Persist 1 Type - F32 + Boolean Value - 0.1 + 0 - FlycamAxisDeadZone4 + RadarColumnTimeHidden Comment - Flycam axis 4 dead zone. + Hide radar's time column Persist 1 Type - F32 + Boolean Value - 0.1 + 1 - FlycamAxisDeadZone5 + RadarColumnClientHidden Comment - Flycam axis 5 dead zone. + Hide radar's client column Persist 1 Type - F32 + Boolean Value - 0.1 + 0 - FlycamAxisDeadZone6 + RadarKeepOpen Comment - Flycam axis 6 dead zone. + Keeps radar updates running in background Persist 1 Type - F32 + Boolean Value - 0.1 + 0 - FlycamAxisScale0 + RadarRangeRadius Comment - Flycam axis 0 scaler. + How far away avatars on the radar can be, 0 for no limit Persist 1 Type F32 Value - 1.0 + 0 - FlycamAxisScale1 + RadarUpdateEnabled Comment - Flycam axis 1 scaler. + When false, pauses the radar until further notice, good for banning someone who just left. Persist + 0 + HideFromEditor 1 Type - F32 + Boolean Value - 1.0 + 1 - FlycamAxisScale2 + RadarAlertFlood Comment - Flycam axis 2 scaler. + Show the flood of people arriving and (if RadarAlertFloodLeaving) leaving when you login and when you open/close the Radar with RadarKeepOpen off. Persist 1 Type - F32 + Boolean Value - 1.0 + 0 - FlycamAxisScale3 + RadarAlertFloodLeaving Comment - Flycam axis 3 scaler. + When activated along with RadarAlertFlood shows the flood of people leaving when you close the Radar with RadarKeepOpen off. Persist 1 Type - F32 + Boolean Value - 1.0 + 0 - FlycamAxisScale4 + RadarAlertShowDist Comment - Flycam axis 4 scaler. + Show distance in radar announcements. Persist 1 Type - F32 + Boolean Value - 1.0 + 1 - FlycamAxisScale5 + RadarAlertSim Comment - Flycam axis 5 scaler. + Whether the radar emits chat alerts for avatars entering/exiting sim Persist 1 Type - F32 + Boolean Value - 1.0 + 0 - FlycamAxisScale6 + RadarAlertDraw Comment - Flycam axis 6 scaler. + Whether the radar emits chat alerts for avatars entering/exiting draw distance Persist 1 Type - F32 + Boolean Value - 1.0 + 0 - FlycamFeathering + RadarAlertShoutRange Comment - Flycam feathering (less is softer) + Whether the radar emits chat alerts for avatars entering/exiting shout range Persist 1 Type - F32 + Boolean Value - 16.0 + 0 - FlycamZoomDirect + RadarAlertChatRange Comment - Map flycam zoom axis directly to camera zoom. + Whether the radar emits chat alerts for avatars entering/exiting chat range Persist 1 Type Boolean Value - 0 + 1 - FlyingAtExit + RadarAlertAge Comment - Was flying when last logged out, so fly when logging in + Whether the radar emits chat alerts for avatars younger than AvatarAgeAlertDays appearing. Persist 1 Type @@ -8045,491 +8051,598 @@ This should be as low as possible, but too low may break functionality Value 0 - FocusOffsetRearView + AvatarAgeAlertDays Comment - Initial focus point offset relative to avatar for the camera preset Rear View (x-axis is forward) + Age below which avatars will be made known to you Persist 1 Type - Vector3D + U32 Value - - 1.0 - 0.0 - 1.0 - + 3 - FocusOffsetFrontView + RadarChatAlerts Comment - Initial focus point offset relative to avatar for the camera preset Front View + Whether the radar emits chat alerts regarding the status of avatars it displays Persist 1 Type - Vector3D + Boolean Value - - 0.0 - 0.0 - 0.0 - + 0 - FocusOffsetGroupView + RadarChatKeys Comment - Initial focus point offset relative to avatar for the camera preset Group View + Enable alerting scripts about avatars detected by the radar Persist 1 Type - Vector3D + Boolean Value - - 1.5 - 0.7 - 1.0 - + 0 - FocusPosOnLogout + RadarChatKeysStopAsking Comment - Camera focus point when last logged out (global coordinates) + Do not ask if RadarChatKeys should be enabled when a script requests for the radar's keys. Persist 1 Type - Vector3D + Boolean Value - - 0.0 - 0.0 - 0.0 - + 0 - FolderAutoOpenDelay + RadarSortOrder Comment - Seconds before automatically expanding the folder under the mouse when performing inventory drag and drop + Sort order for the radar, map of column names to ascending boolean Persist 1 Type - F32 + LLSD Value - 0.75 + + distance + 1 + - FolderLoadingMessageWaitTime + FloaterLandRect5 Comment - Seconds to wait before showing the LOADING... text in folder views + Rectangle for About Land window Persist 1 Type - F32 + Rect Value - 0.5 + + 0 + 370 + 460 + 0 + - FontScreenDPI + FloaterLandmarkRect Comment - Font resolution, higher is bigger (pixels per inch) + Rectangle for landmark picker Persist 1 Type - F32 + Rect Value - 96.0 + + 0 + 290 + 310 + 0 + - ForceNotecardDragCargoPermissive + FloaterMediaRect Comment - For testing what does and does not work when using HTTPS upload + Rectangle for media browser window Persist 1 Type - Boolean + Rect Value - 0 + + 16 + 650 + 600 + 128 + - ForceNotecardDragCargoAcceptance + FloaterMiniMapRect Comment - For testing what does and does not work when using HTTPS upload + Rectangle for world map Persist 1 Type - Boolean + Rect Value - 0 + + 0 + 225 + 200 + 0 + - ForceAssetFail + FloaterModelUploadRect Comment - Force wearable fetches to fail for this asset type. + Rectangle for mesh upload floater Persist 1 Type - U32 + Rect Value - 255 + + 0 + 480 + 940 + 52 + - ForceShowGrid + FloaterMoveRect2 Comment - Always show grid dropdown on login screen + Rectangle for avatar control window Persist 1 Type - Boolean + Rect Value - 0 + + 0 + 58 + 135 + 0 + - ForceMandatoryUpdate + FloaterMuteRect3 Comment - For QA: On next startup, forces the auto-updater to run + Rectangle for mute window Persist 1 Type - Boolean + Rect Value - 0 + + 0 + 300 + 300 + 0 + - ForwardBtnRect + FloaterObjectIMInfo Comment - + Rectangle for floater object im info windows Persist - 0 + 1 Type Rect Value - 45 - 54 - 66 - 29 + 0 + 300 + 300 + 0 - FreezeTime + FloaterOpenObjectRect Comment - + Rectangle for Open Object window Persist - 0 + 1 Type - Boolean + Rect Value - 0 + + 0 + 350 + 300 + 0 + - FullScreenAspectRatio + FloaterMarketplaceListingsRect Comment - Aspect ratio of fullscreen display (width / height) + Rectangle for Marketplace Listings window Persist 1 Type - F32 + Rect Value - 1.33329999447 + + 0 + 342 + 310 + 52 + - FullScreenAutoDetectAspectRatio + FloaterMarketplaceValidationRect Comment - Automatically detect proper aspect ratio for fullscreen display + Rectangle for Marketplace Validation window Persist 1 Type - Boolean + Rect Value - 1 + + 0 + 342 + 310 + 52 + - FullScreenHeight + FloaterPayRectB Comment - Fullscreen resolution in height + Rectangle for pay window Persist 1 Type - S32 + Rect Value - 768 + + 0 + 150 + 400 + 0 + - FullScreenWidth + FloaterPermPrefsRect Comment - Fullscreen resolution in width + Rectangle for initial permissions preferences Persist 1 Type - S32 + Rect Value - 1024 + + 200 + 250 + 250 + 200 + - GridCrossSections + FloaterRegionInfo Comment - Highlight cross sections of prims with grid manipulation plane. + Rectangle for region info window Persist 1 Type - Boolean + Rect Value - 0 + + 0 + 512 + 500 + 0 + - GridDrawSize + FloaterScriptDebugRect Comment - Visible extent of 2D snap grid (meters) + Rectangle for Script Error/Debug window Persist 1 Type - F32 + Rect Value - 12.0 + + 0 + 130 + 450 + 0 + - GridMode + FloaterScriptLimitsRect Comment - Snap grid reference frame (0 = world, 1 = local, 2 = reference object) + Rectangle for Script Limits window Persist 1 Type - S32 + Rect Value - 0 + + 0 + 500 + 480 + 0 + - GridOpacity + FloaterSearchRect Comment - Grid line opacity (0.0 = completely transparent, 1.0 = completely opaque) + Rectangle for web search browser window Persist 1 Type - F32 + Rect Value - 0.699999988079 - - GridResolution - - Comment - Size of single grid step (meters) + + 16 + 650 + 600 + 128 + + + FloaterSnapshotRect + + Comment + Rectangle for snapshot window Persist 1 Type - F32 + Rect Value - 0.5 + + 0 + 200 + 200 + 400 + - GridSubUnit + FloaterSnapshotFeedRect Comment - Display fractional grid steps, relative to grid size + Rectangle for snapshot feed window Persist 1 Type - Boolean + Rect Value - 0 + + 0 + 200 + 200 + 400 + - GridSubdivision + FloaterSnapshotPostcardRect Comment - Maximum number of times to divide single snap grid unit when GridSubUnit is true + Rectangle for snapshot postcard window Persist 1 Type - S32 + Rect Value - 32 + + 0 + 346 + 450 + 400 + - GroupNotifyBoxHeight + FloaterSoundsRect Comment - Height of group notice messages + Rectangle for sounds log floater. Persist 1 Type - S32 + Rect Value - 260 + + 0 + 0 + 0 + 0 + - GroupNotifyBoxWidth + FloaterSoundsLogAvatars Comment - Width of group notice messages + Show SoundTriggers/gestures played by agents in the log. Also includes collision sounds if enabled Persist 1 Type - S32 + Boolean Value - 400 + 1 - HTMLLinkColor + FloaterSoundsLogObjects Comment - Color of hyperlinks + Show sounds played by objects in the log. Also includes collision sounds if enabled Persist 1 Type - Color4 + Boolean Value - - 0.600000023842 - 0.600000023842 - 1.0 - 1.0 - + 1 - HelpHomeURL + FloaterSoundsLogCollisions Comment - URL of initial help page + Don't filter out default collision sounds in the log Persist 1 Type - String + Boolean Value - help/index.html + 1 - HelpLastVisitedURL + FloaterSoundsLogRepeats Comment - URL of last help page, will be shown next time help is accessed + Only show one entry for each unique asset ID in the log Persist 1 Type - String + Boolean Value - help/index.html + 1 - SearchURL + FloaterStatisticsRect Comment - URL for Search website, displayed in the Find floater + Rectangle for chat history Persist - 0 + 1 Type - String + Rect Value - http://search.secondlife.com/viewer/[CATEGORY]/?q=[QUERY]&p=[AUTH_TOKEN]&r=[MATURITY]&lang=[LANGUAGE]&g=[GODLIKE]&sid=[SESSION_ID]&rid=[REGION_ID]&pid=[PARCEL_ID]&channel=[CHANNEL]&version=[VERSION]&major=[VERSION_MAJOR]&minor=[VERSION_MINOR]&patch=[VERSION_PATCH]&build=[VERSION_BUILD] + + 0 + 400 + 250 + 0 + - WebProfileURL + FloaterTeleportHistoryRect Comment - URL for Web Profiles + Rectangle for teleport history window Persist - 0 + 1 Type - String + Rect Value - https://my.secondlife.com/[AGENT_NAME] + + 20 + 20 + 470 + 200 + - HighResSnapshot + FloaterViewBottom Comment - Double resolution of snapshot from current window resolution + [DO NOT MODIFY] Controls layout of floating windows within SL window Persist 1 Type - Boolean + S32 Value - 0 + -1 - HideSelectedObjects + FloaterVoiceEffectRect Comment - Hide Selected Objects + Rectangle for voice morpher floater Persist 1 Type - Boolean + Rect Value - 0 + + 0 + 300 + 360 + 0 + - HtmlFindRect + FloaterWorldMapRect2 Comment - Rectangle for HTML find window + Rectangle for world map window Persist 1 Type Rect Value - 16 - 650 - 600 - 128 + 0 + 0 + 0 + 0 - HtmlHelpLastPage + FloaterAORect Comment - Last URL visited via help system + Rectangle for AO editor. Persist 1 Type - String + Rect Value - + + 0 + 0 + 0 + 0 + - HtmlHelpRect + FloaterAvatarsRect Comment - Rectangle for HTML help window + Rectangle for avatar radar. Persist 1 Type Rect Value - 16 - 650 - 600 - 128 + 200 + 905 + 396 + 734 - HtmlReleaseMessage + FloaterInterceptorRect Comment - Rectangle for HTML Release Message Floater window + Rectangle for interceptor floater. Persist 1 Type Rect Value - 46 - 520 - 400 - 128 + 0 + 0 + 0 + 0 - IMInChatConsole + FloaterKeyToolRect Comment - Copy IM into chat console + Rectangle for KeyTool floater. Persist 1 Type - Boolean + Rect Value - 1 + + 439 + 759 + 593 + 443 + - IMInChatHistory + KeyToolAutomaticOpen Comment - Copy IM into chat history + Automatically open KeyTool results Persist 1 Type Boolean Value - 0 + 1 - IMShowTimestamps + KeyToolAutomaticClose Comment - Show timestamps in IM + Automatically close KeyTool floater when a result is found Persist 1 Type @@ -8537,21 +8650,26 @@ This should be as low as possible, but too low may break functionality Value 1 - IgnorePixelDepth + FloaterSoundsRect Comment - Ignore pixel depth settings. + Rectangle for sounds log floater. Persist 1 Type - Boolean + Rect Value - 0 + + 0 + 0 + 0 + 0 + - ImagePipelineUseHTTP + FloaterSoundsLogAvatars Comment - If TRUE use HTTP GET to fetch textures from the server + Show SoundTriggers/gestures played by agents in the log. Also includes collision sounds if enabled Persist 1 Type @@ -8559,32 +8677,32 @@ This should be as low as possible, but too low may break functionality Value 1 - InBandwidth + FloaterSoundsLogObjects Comment - Incoming bandwidth throttle (bps) + Show sounds played by objects in the log. Also includes collision sounds if enabled Persist 1 Type - F32 + Boolean Value - 0.0 + 1 - InstallLanguage + FloaterSoundsLogCollisions Comment - Language passed from installer (for UI) + Don't filter out default collision sounds in the log Persist 1 Type - String + Boolean Value - en-us + 1 - FetchInventoryOnLogin + FloaterSoundsLogRepeats Comment - Automatically fetch the inventory in the background after login + Only show one entry for each unique asset ID in the log Persist 1 Type @@ -8592,230 +8710,219 @@ This should be as low as possible, but too low may break functionality Value 1 - InventoryAutoOpenDelay + FlyBtnState Comment - Seconds before automatically opening inventory when mouse is over inventory button when performing inventory drag and drop + Persist - 1 + 0 Type - F32 + Boolean Value - 1.0 + 0 - InventoryDebugSimulateOpFailureRate + AlwaysAllowFly Comment - Rate at which we simulate failures of copy/link requests in some operations + Ignore parcel/region setting that blocks flying Persist - 1 + 1 Type - F32 + Boolean Value - 0.0 + 0 - InventoryDebugSimulateLateOpRate + FlycamAbsolute Comment - Rate at which we simulate late-completing copy/link requests in some operations + Treat Flycam values as absolute positions (not deltas). Persist - 1 + 1 Type - F32 + Boolean Value - 0.0 + 0 - InventoryDisplayInbox + FlycamAxisDeadZone0 - Comment - Override received items inventory inbox display - Persist - 0 - Type - Boolean - Value - 0 + Comment + Flycam axis 0 dead zone. + Persist + 1 + Type + F32 + Value + 0.1 - InventoryDisplayOutbox + FlycamAxisDeadZone1 - Comment - Override merchant inventory outbox display - Persist - 0 - Type - Boolean - Value - 0 + Comment + Flycam axis 1 dead zone. + Persist + 1 + Type + F32 + Value + 0.1 - InventoryOutboxLogging - - Comment - Enable debug output associated with the Merchant Outbox. - Persist - 1 - Type - Boolean - Value - 0 - - InventoryOutboxMaxFolderCount + FlycamAxisDeadZone2 Comment - Maximum number of subfolders allowed in a listing in the merchant outbox. + Flycam axis 2 dead zone. Persist - 0 + 1 Type - U32 + F32 Value - 21 + 0.1 - InventoryOutboxMaxFolderDepth + FlycamAxisDeadZone3 Comment - Maximum number of nested levels of subfolders allowed in a listing in the merchant outbox. + Flycam axis 3 dead zone. Persist - 0 + 1 Type - U32 + F32 Value - 4 + 0.1 - InventoryOutboxMaxItemCount + FlycamAxisDeadZone4 Comment - Maximum number of items allowed in a listing in the merchant outbox. + Flycam axis 4 dead zone. Persist - 0 + 1 Type - U32 + F32 Value - 200 + 0.1 - InventorySortOrder + FlycamAxisDeadZone5 Comment - Specifies sort key for inventory items (+0 = name, +1 = date, +2 = folders always by name, +4 = system folders to top) + Flycam axis 5 dead zone. Persist 1 Type - U32 + F32 Value - 7 + 0.1 - InvertMouse + FlycamAxisDeadZone6 Comment - When in mouselook, moving mouse up looks down and vice verse (FALSE = moving up looks up) + Flycam axis 6 dead zone. Persist 1 Type - Boolean + F32 Value - 0 + 0.1 - JoystickAvatarEnabled + FlycamAxisScale0 Comment - Enables the Joystick to control Avatar movement. + Flycam axis 0 scaler. Persist 1 Type - Boolean + F32 Value - 1 + 1.0 - JoystickAxis0 + FlycamAxisScale1 Comment - Flycam hardware axis mapping for internal axis 0 ([0, 5]). + Flycam axis 1 scaler. Persist 1 Type - S32 + F32 Value - 1 + 1.0 - JoystickAxis1 + FlycamAxisScale2 Comment - Flycam hardware axis mapping for internal axis 1 ([0, 5]). + Flycam axis 2 scaler. Persist 1 Type - S32 + F32 Value - 0 + 1.0 - JoystickAxis2 + FlycamAxisScale3 Comment - Flycam hardware axis mapping for internal axis 2 ([0, 5]). + Flycam axis 3 scaler. Persist 1 Type - S32 + F32 Value - 2 + 1.0 - JoystickAxis3 + FlycamAxisScale4 Comment - Flycam hardware axis mapping for internal axis 3 ([0, 5]). + Flycam axis 4 scaler. Persist 1 Type - S32 + F32 Value - 4 + 1.0 - JoystickAxis4 + FlycamAxisScale5 Comment - Flycam hardware axis mapping for internal axis 4 ([0, 5]). + Flycam axis 5 scaler. Persist 1 Type - S32 + F32 Value - 3 + 1.0 - JoystickAxis5 + FlycamAxisScale6 Comment - Flycam hardware axis mapping for internal axis 5 ([0, 5]). + Flycam axis 6 scaler. Persist 1 Type - S32 + F32 Value - 5 + 1.0 - JoystickAxis6 + FlycamBuildModeScale Comment - Flycam hardware axis mapping for internal axis 6 ([0, 5]). + Scale factor to apply to flycam movements when in build mode. Persist 1 Type - S32 + F32 Value - -1 + 0.3333333 - JoystickBuildEnabled + FlycamFeathering Comment - Enables the Joystick to move edited objects. + Flycam feathering (less is softer) Persist 1 Type - Boolean + F32 Value - 0 + 16.0 - JoystickEnabled + FlycamZoomDirect Comment - Enables Joystick Input. + Map flycam zoom axis directly to camera zoom. Persist 1 Type @@ -8823,98 +8930,125 @@ This should be as low as possible, but too low may break functionality Value 0 - JoystickFlycamEnabled + FlyingAtExit Comment - Enables the Joystick to control the flycam. + Was flying when last logged out, so fly when logging in Persist - 0 + 1 Type Boolean Value - 1 + 0 - JoystickInitialized + FocusOffsetRearView Comment - Whether or not a joystick has been detected and initiailized. + Initial focus point offset relative to avatar for the camera preset Rear View (x-axis is forward) Persist 1 Type - String + Vector3D Value - + + 1.0 + 0.0 + 1.0 + - JoystickRunThreshold + FocusOffsetFrontView Comment - Input threshold to initiate running + Initial focus point offset relative to avatar for the camera preset Front View Persist 1 Type - F32 + Vector3D Value - 0.25 - - Jpeg2000AdvancedCompression - + + 0.0 + 0.0 + 0.0 + + + FocusOffsetGroupView + Comment - Use advanced Jpeg2000 compression options (precincts, blocks, ordering, markers) + Initial focus point offset relative to avatar for the camera preset Group View Persist - 1 + 1 Type - Boolean + Vector3D Value - 0 - - Jpeg2000PrecinctsSize - + + 1.5 + 0.7 + 1.0 + + + FocusPosOnLogout + Comment - Size of image precincts. Assumed square and same for all levels. Must be power of 2. + Camera focus point when last logged out (global coordinates) Persist - 1 + 1 Type - S32 + Vector3D Value - 256 - - Jpeg2000BlocksSize - + + 0.0 + 0.0 + 0.0 + + + FolderAutoOpenDelay + Comment - Size of encoding blocks. Assumed square and same for all levels. Must be power of 2. Max 64, Min 4. + Seconds before automatically expanding the folder under the mouse when performing inventory drag and drop Persist - 1 + 1 Type - S32 + F32 Value - 64 - - LandBrushSize + 0.75 + + FolderLoadingMessageWaitTime Comment - Size of affected region when using teraform tool + Seconds to wait before showing the LOADING... text in folder views Persist 1 Type F32 Value - 2.0 + 0.5 - LCDDestination + FontScreenDPI Comment - Which LCD to use + Font resolution, higher is bigger (pixels per inch) Persist 1 Type - S32 + F32 + Value + 96.0 + + ForceNotecardDragCargoPermissive + + Comment + For testing what does and does not work when using HTTPS upload + Persist + 1 + Type + Boolean Value 0 - LSLFindCaseInsensitivity + ForceNotecardDragCargoAcceptance Comment - Use case insensitivity when searching in LSL editor + For testing what does and does not work when using HTTPS upload Persist 1 Type @@ -8922,37 +9056,32 @@ This should be as low as possible, but too low may break functionality Value 0 - LSLHelpRect + ForceAssetFail Comment - Rectangle for LSL help window + Force wearable fetches to fail for this asset type. Persist 1 Type - Rect + U32 Value - - 0 - 400 - 400 - 0 - + 255 - LSLHelpURL + ForceShowGrid Comment - URL that points to LSL help files, with [LSL_STRING] corresponding to the referenced LSL function or keyword + Always show grid dropdown on login screen Persist 1 Type - String + Boolean Value - http://wiki.secondlife.com/wiki/[LSL_STRING] + 1 - LagMeterShrunk + ForceMandatoryUpdate Comment - Last large/small state for lag meter + For QA: On next startup, forces the auto-updater to run Persist 1 Type @@ -8960,98 +9089,103 @@ This should be as low as possible, but too low may break functionality Value 0 - Language + ForwardBtnRect Comment - Language specifier (for UI) + Persist - 1 + 0 Type - String + Rect Value - default + + 45 + 54 + 66 + 29 + - LanguageIsPublic + FreezeTime Comment - Let other residents see our language information + Persist - 1 + 0 Type Boolean Value - 1 + 0 - TranslateLanguage + FullScreenAspectRatio Comment - Translate Language specifier + Aspect ratio of fullscreen display (width / height) Persist 1 Type - String + F32 Value - default + 1.33329999447 - TranslateChat + FullScreenAutoDetectAspectRatio Comment - Translate incoming chat messages + Automatically detect proper aspect ratio for fullscreen display Persist - 0 + 1 Type Boolean Value - 0 + 1 - LastFeatureVersion + FullScreenHeight Comment - [DO NOT MODIFY] Version number for tracking hardware changes + Fullscreen resolution in height Persist 1 Type S32 Value - 0 + 768 - LastFindPanel + FullScreenWidth Comment - Controls which find operation appears by default when clicking "Find" button + Fullscreen resolution in width Persist 1 Type - String + S32 Value - find_all_panel + 1024 - LastName + GridCrossSections Comment - Login last name + Highlight cross sections of prims with grid manipulation plane. Persist 1 Type - String + Boolean Value - + 0 - LastPrefTab + GridDrawSize Comment - Last selected tab in preferences window + Visible extent of 2D snap grid (meters) Persist 1 Type - S32 + F32 Value - 0 + 12.0 - LastMediaSettingsTab + GridMode Comment - Last selected tab in media settings window + Snap grid reference frame (0 = world, 1 = local, 2 = reference object) Persist 1 Type @@ -9059,197 +9193,277 @@ This should be as low as possible, but too low may break functionality Value 0 - LastRunVersion + GridOpacity Comment - Version number of last instance of the viewer that you ran + Grid line opacity (0.0 = completely transparent, 1.0 = completely opaque) Persist 1 Type - String + F32 Value - 0.0.0 + 0.699999988079 - LastSnapshotToFeedAspect + GridResolution Comment - The aspect ratio spinner value for snapshots uploaded to my.secondlife.com + Size of single grid step (meters) Persist - 0 + 1 Type F32 Value - 1.33333 + 0.5 - LastSnapshotToFeedHeight + GridSubUnit Comment - The height of the last my.secondlife.com feed snapshot, in px + Display fractional grid steps, relative to grid size Persist 1 Type - S32 + Boolean Value - 525 + 0 - LastSnapshotToFeedWidth + GridSubdivision Comment - The width of the last my.secondlife.com feed snapshot, in px + Maximum number of times to divide single snap grid unit when GridSubUnit is true Persist 1 Type S32 Value - 700 + 32 - LastSnapshotToEmailAspect + GroupNotifyBoxHeight Comment - The aspect ratio spinner value for snapshots sent by email + Height of group notice messages Persist - 0 + 1 Type - F32 + S32 Value - 0 + 260 - LastSnapshotToEmailHeight + GroupNotifyBoxWidth Comment - The height of the last email snapshot, in px + Width of group notice messages Persist 1 Type S32 Value - 768 + 400 - LastSnapshotToEmailWidth + HTMLAgentColor Comment - The width of the last email snapshot, in px + Color of hyperlinked user/object names Persist 1 Type - S32 + Color4 Value - 1024 + + 0.600000023842 + 0.600000023842 + 1.0 + 1.0 + - LastSnapshotToDiskAspect + HTMLLinkColor Comment - The aspect ratio spinner value for snapshots written to disk + Color of hyperlinks Persist - 0 + 1 Type - F32 + Color4 Value - 0 + + 0.600000023842 + 0.600000023842 + 1.0 + 1.0 + - LastSnapshotToDiskHeight + HelpHomeURL Comment - The height of the last disk snapshot, in px + URL of initial help page Persist 1 Type - S32 + String Value - 768 + help/index.html - LastSnapshotToDiskWidth + HelpLastVisitedURL Comment - The width of the last disk snapshot, in px + URL of last help page, will be shown next time help is accessed Persist 1 Type - S32 + String Value - 1024 + help/index.html - LastSnapshotToInventoryAspect + SearchURL Comment - The aspect ratio spinner value for snapshots uploaded to inventory + URL for Search website, displayed in the Find floater Persist 0 Type - F32 + String Value - 0 + http://search.secondlife.com/viewer/[CATEGORY]/?q=[QUERY]&p=[AUTH_TOKEN]&r=[MATURITY]&lang=[LANGUAGE]&g=[GODLIKE]&sid=[SESSION_ID]&rid=[REGION_ID]&pid=[PARCEL_ID]&channel=[CHANNEL]&version=[VERSION]&major=[VERSION_MAJOR]&minor=[VERSION_MINOR]&patch=[VERSION_PATCH]&build=[VERSION_BUILD] - LastSnapshotToInventoryHeight + WebProfileURL Comment - The height of the last texture snapshot, in px + URL for Web Profiles Persist - 1 + 0 Type - S32 + String Value - 512 + https://my.secondlife.com/[AGENT_NAME] - LastSnapshotToInventoryWidth + HighResSnapshot Comment - The width of the last texture snapshot, in px + Double resolution of snapshot from current window resolution Persist 1 Type - S32 + Boolean Value - 512 + 0 - LastSnapshotType + HideSelectedObjects Comment - Select this as next type of snapshot to take (0 = feed, 1 = postcard, 2 = texture, 3 = local image) + Hide Selected Objects Persist 1 Type - S32 + Boolean Value 0 - SnapshotFeedAddLocation + HtmlFindRect Comment - Include your location in your uploads to profile feed. + Rectangle for HTML find window Persist 1 Type - Boolean + Rect Value - 0 + + 16 + 650 + 600 + 128 + - LeftClickShowMenu + HtmlHelpLastPage Comment - Left click opens pie menu (FALSE = left click touches or grabs object) + Last URL visited via help system Persist 1 Type - Boolean + String Value - 0 + - LegacyMultiAttachmentSupport + HtmlHelpRect Comment - Converts legacy "secondary attachment points" to multi-attachments for other avatars + Rectangle for HTML help window Persist 1 Type - Boolean + Rect Value + + 16 + 650 + 600 + 128 + + + HtmlReleaseMessage + + Comment + Rectangle for HTML Release Message Floater window + Persist 1 + Type + Rect + Value + + 46 + 520 + 400 + 128 + - LimitDragDistance + ImporterDebug + + Comment + Enable debug output to more precisely identify sources of import errors. Warning: the output can slow down import on many machines. + Persist + 1 + Type + Boolean + Value + 0 + + ImporterLegacyMatching + + Comment + Enable index based model matching. + Persist + 1 + Type + Boolean + Value + 0 + + ImporterModelLimit + + Comment + Limits amount of importer generated models for dae files + Persist + 1 + Type + U32 + Value + 768 + + ImporterPreprocessDAE + + Comment + Enable preprocessing for DAE files to fix some ColladaDOM related problems (like support for space characters within names and ids). + Persist + 1 + Type + Boolean + Value + 1 + + IMInChatConsole Comment - Limit translation of object via translate tool + Copy IM into chat console Persist 1 Type @@ -9257,10 +9471,10 @@ This should be as low as possible, but too low may break functionality Value 1 - LimitSelectDistance + IMInChatHistory Comment - Disallow selection of objects beyond max select distance + Copy IM into chat history Persist 1 Type @@ -9268,32 +9482,32 @@ This should be as low as possible, but too low may break functionality Value 0 - LipSyncAah + IMShowTimestamps Comment - Aah (jaw opening) babble loop + Show timestamps in IM Persist 1 Type - String + Boolean Value - 257998776531013446642343 + 1 - LipSyncAahPowerTransfer + IgnorePixelDepth Comment - Transfer curve for Voice Interface power to aah lip sync amplitude + Ignore pixel depth settings. Persist 1 Type - String + Boolean Value - 0000123456789 + 0 - LipSyncEnabled + ImagePipelineUseHTTP Comment - 0 disable lip-sync, 1 enable babble loop + If TRUE use HTTP GET to fetch textures from the server Persist 1 Type @@ -9301,230 +9515,296 @@ This should be as low as possible, but too low may break functionality Value 1 - LipSyncOoh + InactiveFloaterTransparency Comment - Ooh (mouth width) babble loop + Transparency of inactive floaters (floaters that have no focus) Persist 1 Type - String + F32 Value - 1247898743223344444443200000 + 1 - LipSyncOohAahRate + InBandwidth Comment - Rate to babble Ooh and Aah (/sec) + Incoming bandwidth throttle (bps) Persist 1 Type F32 Value - 24.0 + 0.0 - LipSyncOohPowerTransfer + InstallLanguage Comment - Transfer curve for Voice Interface power to ooh lip sync amplitude + Language passed from installer (for UI) Persist 1 Type String Value - 0012345566778899 + en-us - LocalCacheVersion + FetchInventoryOnLogin Comment - Version number of cache + Automatically fetch the inventory in the background after login Persist 1 Type - S32 + Boolean Value - 0 + 1 - LogMessages + InventoryAutoOpenDelay Comment - Log network traffic + Seconds before automatically opening inventory when mouse is over inventory button when performing inventory drag and drop Persist 1 Type - Boolean + F32 Value - 0 + 1.0 - LogTextureNetworkTraffic + InventoryDebugSimulateOpFailureRate Comment - Log network traffic for textures + Rate at which we simulate failures of copy/link requests in some operations Persist - 1 + 1 Type - Boolean + F32 Value - 0 + 0.0 - LoginAsGod + InventoryDebugSimulateLateOpRate Comment - Attempt to login with god powers (Linden accounts only) + Rate at which we simulate late-completing copy/link requests in some operations Persist - 1 + 1 Type - Boolean + F32 Value - 0 + 0.0 - LoginLocation + InventoryDisplayInbox + + Comment + Override received items inventory inbox display + Persist + 0 + Type + Boolean + Value + 0 + + InventoryOutboxDisplayBoth + + Comment + Show the legacy Merchant Outbox UI as well as the Marketplace Listings UI + Persist + 1 + Type + Boolean + Value + 0 + + InventoryOutboxLogging + + Comment + Enable debug output associated with the Merchant Outbox. + Persist + 1 + Type + Boolean + Value + 0 + + InventoryOutboxMakeVisible + + Comment + Enable making the Merchant Outbox and Inbox visible in the inventory for debug purposes. + Persist + 1 + Type + Boolean + Value + 1 + + InventoryOutboxMaxFolderCount Comment - Default Login location ('last', 'home') preference + Maximum number of subfolders allowed in a listing in the merchant outbox. Persist - 1 + 0 Type - String + U32 Value - last + 20 - LoginPage + InventoryOutboxMaxFolderDepth Comment - Login authentication page. + Maximum number of nested levels of subfolders allowed in a listing in the merchant outbox. Persist - 1 + 0 Type - String + U32 Value - + 4 - LosslessJ2CUpload + InventoryOutboxMaxItemCount Comment - Use lossless compression for small image uploads + Maximum number of items allowed in a listing in the merchant outbox. Persist - 1 + 0 Type - Boolean + U32 Value - 0 + 200 - MainloopTimeoutDefault + InventoryOutboxMaxStockItemCount Comment - Timeout duration for mainloop lock detection, in seconds. + Maximum number of items allowed in a stock folder. Persist - 1 + 0 Type - F32 + U32 Value - 20.0 + 200 - UseWebMapTiles + InventorySortOrder Comment - Use web map tiles whenever possible + Specifies sort key for inventory items (+0 = name, +1 = date, +2 = folders always by name, +4 = system folders to top) Persist 1 Type - Boolean + U32 Value - 1 + 7 - MapOverlayIndex + MarketplaceListingsSortOrder Comment - Currently selected world map type + Specifies sort for marketplace listings Persist 1 Type - S32 + U32 Value - 0 + 2 - MapScale + InvertMouse Comment - World map zoom level (pixels per region) + When in mouselook, moving mouse up looks down and vice verse (FALSE = moving up looks up) Persist 1 Type - F32 + Boolean Value - 128.0 + 0 - MapServerURL + JoystickAvatarEnabled Comment - World map URL template for locating map tiles + Enables the Joystick to control Avatar movement. Persist - 0 + 1 Type - String + Boolean Value - http://map.secondlife.com.s3.amazonaws.com/ + 1 - MapShowAgentCount + JoystickAxis0 Comment - Show number of agents next to region names on world map + Flycam hardware axis mapping for internal axis 0 ([0, 5]). Persist 1 Type - Boolean + S32 Value 1 - MapShowPGEvents + JoystickAxis1 Comment - Show PG events on world map + Flycam hardware axis mapping for internal axis 1 ([0, 5]). Persist 1 Type - Boolean + S32 Value + 0 + + JoystickAxis2 + + Comment + Flycam hardware axis mapping for internal axis 2 ([0, 5]). + Persist 1 + Type + S32 + Value + 2 - MapShowMatureEvents + JoystickAxis3 Comment - Show mature events on world map + Flycam hardware axis mapping for internal axis 3 ([0, 5]). Persist 1 Type - Boolean + S32 Value - 0 + 4 - MapShowAdultEvents + JoystickAxis4 Comment - Show adult events on world map + Flycam hardware axis mapping for internal axis 4 ([0, 5]). Persist 1 Type - Boolean + S32 Value - 0 + 3 - MapShowInfohubs + JoystickAxis5 Comment - Show infohubs on the world map + Flycam hardware axis mapping for internal axis 5 ([0, 5]). Persist 1 Type - Boolean + S32 Value + 5 + + JoystickAxis6 + + Comment + Flycam hardware axis mapping for internal axis 6 ([0, 5]). + Persist 1 + Type + S32 + Value + -1 - MapShowLandForSale + JoystickBuildEnabled Comment - Show land for sale on world map + Enables the Joystick to move edited objects. Persist 1 Type @@ -9532,32 +9812,32 @@ This should be as low as possible, but too low may break functionality Value 0 - MapShowPeople + JoystickEnabled Comment - Show other users on world map + Enables Joystick Input. Persist 1 Type Boolean Value - 1 + 0 - MapShowTelehubs + JoystickFlycamEnabled Comment - Show telehubs on world map + Enables the Joystick to control the flycam. Persist - 1 + 0 Type Boolean Value 1 - Marker + JoystickInitialized Comment - [NOT USED] + Whether or not a joystick has been detected and initiailized. Persist 1 Type @@ -9565,548 +9845,488 @@ This should be as low as possible, but too low may break functionality Value - MaxDragDistance + JoystickRunThreshold Comment - Maximum allowed translation distance in a single operation of translate tool (meters from start point) + Input threshold to initiate running Persist 1 Type F32 Value - 48.0 - - MaxHeapSize + 0.25 + + Jpeg2000AdvancedCompression + + Comment + Use advanced Jpeg2000 compression options (precincts, blocks, ordering, markers) + Persist + 1 + Type + Boolean + Value + 0 + + Jpeg2000PrecinctsSize + + Comment + Size of image precincts. Assumed square and same for all levels. Must be power of 2. + Persist + 1 + Type + S32 + Value + 256 + + Jpeg2000BlocksSize + + Comment + Size of encoding blocks. Assumed square and same for all levels. Must be power of 2. Max 64, Min 4. + Persist + 1 + Type + S32 + Value + 64 + + LandBrushSize Comment - Maximum heap size (GB) + Size of affected region when using teraform tool Persist 1 Type F32 Value - 1.6 + 2.0 - MaxSelectDistance + LCDDestination Comment - Maximum allowed selection distance (meters from avatar) + Which LCD to use Persist 1 Type - F32 + S32 Value - 128.0 + 0 - MaxWearableWaitTime + LSLFindCaseInsensitivity Comment - Max seconds to wait for wearable assets to fetch. + Use case insensitivity when searching in LSL editor Persist 1 Type - F32 + Boolean Value - 60.0 + 0 - MeanCollisionBump + LSLHelpRect Comment - You have experienced an abuse of being bumped by an object or avatar + Rectangle for LSL help window Persist 1 Type - Boolean + Rect Value - 0 + + 0 + 400 + 400 + 0 + - MeanCollisionPhysical + LSLHelpURL Comment - You have experienced an abuse from a physical object + URL that points to LSL help files, with [LSL_STRING] corresponding to the referenced LSL function or keyword Persist 1 Type - Boolean + String Value - 0 + http://wiki.secondlife.com/wiki/[LSL_STRING] - MeanCollisionPushObject + Language Comment - You have experienced an abuse of being pushed by a scripted object + Language specifier (for UI) Persist 1 Type - Boolean + String Value - 0 + default - MeanCollisionScripted + LanguageIsPublic Comment - You have experienced an abuse from a scripted object + Let other residents see our language information Persist 1 Type Boolean Value - 0 + 1 - MeanCollisionSelected + TranslateLanguage Comment - You have experienced an abuse of being pushed via a selected object + Translate Language specifier Persist 1 Type + String + Value + default + + TranslateChat + + Comment + Translate incoming chat messages + Persist + 0 + Type Boolean Value 0 - MediaPluginDebugging + LastFeatureVersion Comment - Turn on debugging messages that may help diagnosing media issues (WARNING: May reduce performance). + [DO NOT MODIFY] Version number for tracking hardware changes Persist 1 Type - Boolean + S32 Value 0 - MediaControlFadeTime + LastFindPanel Comment - Amount of time (in seconds) that the media control fades + Controls which find operation appears by default when clicking "Find" button Persist 1 Type - F32 + String Value - 1.5 + find_all_panel - MediaControlTimeout + LastName Comment - Amount of time (in seconds) for media controls to fade with no mouse activity + Login last name Persist 1 Type - F32 + String Value - 3.0 + - MediaOnAPrimUI + LastPrefTab Comment - Whether or not to show the "link sharing" UI + Last selected tab in preferences window Persist 1 Type - Boolean - Value - 1 - - MediaPerformanceManagerDebug - - Comment - Whether to show debug data for the media performance manager in the nearby media list. - Persist - 1 - Type - Boolean - Value - 0 - - MediaShowOnOthers - - Comment - Whether or not to show media on other avatars - Persist - 1 - Type - Boolean - Value - 0 - - MediaShowOutsideParcel - - Comment - Whether or not to show media from outside the current parcel - Persist - 1 - Type - Boolean - Value - 1 - - MediaShowWithinParcel - - Comment - Whether or not to show media within the current parcel - Persist - 1 - Type - Boolean - Value - 1 - - MediaTentativeAutoPlay - - Comment - This is a tentative flag that may be temporarily set off by the user, until she teleports - Persist - 0 - Type - Boolean - Value - 1 - - MemoryFailurePreventionEnabled - - Comment - If set, the viewer will quit to avoid crash when memory failure happens + S32 + Value + 0 + + LastMediaSettingsTab + + Comment + Last selected tab in media settings window Persist 1 Type - Boolean + S32 Value 0 - MemoryLogFrequency + LastRunVersion Comment - Seconds between display of Memory in log (0 for never) + Version number of last instance of the viewer that you ran Persist 1 Type - F32 + String Value - 30.0 + 0.0.0 - MemoryPrivatePoolEnabled + LastSnapshotToFeedAspect Comment - Enable the private memory pool management + The aspect ratio spinner value for snapshots uploaded to my.secondlife.com Persist - 1 + 0 Type - Boolean + F32 Value - 0 + 1.33333 - MemoryPrivatePoolSize + LastSnapshotToFeedHeight Comment - Size of the private memory pool in MB (min. value is 256) + The height of the last my.secondlife.com feed snapshot, in px Persist 1 Type - U32 + S32 Value - 512 + 525 - MemProfiling + LastSnapshotToFeedWidth Comment - You want to use tcmalloc's memory profiling options. + The width of the last my.secondlife.com feed snapshot, in px Persist 1 Type - Boolean + S32 Value - 0 - - MenuAccessKeyTime + 700 + + LastSnapshotToEmailAspect Comment - Time (seconds) in which the menu key must be tapped to move focus to the menu bar + The aspect ratio spinner value for snapshots sent by email Persist - 1 + 0 Type F32 Value - 0.25 + 0 - MenuBarHeight + LastSnapshotToEmailHeight Comment - + The height of the last email snapshot, in px Persist - 0 + 1 Type S32 Value - 18 + 768 - MenuBarWidth + LastSnapshotToEmailWidth Comment - + The width of the last email snapshot, in px Persist - 0 + 1 Type S32 Value - 410 + 1024 - MeshEnabled - - Comment - Expose UI for mesh functionality (may require restart to take effect). - Persist - 1 - Type - Boolean - Value - 1 - - MeshImportUseSLM - - Comment - Use cached copy of last upload for a dae if available instead of loading dae file from scratch. - Persist - 1 - Type - Boolean - Value - 0 - - MeshUploadLogXML - - Comment - Verbose XML logging on mesh upload - Persist - 1 - Type - Boolean - Value - 0 - - MeshUploadFakeErrors - - Comment - Force upload errors (for testing) - Persist - 1 - Type - S32 - Value - 0 - - MeshUploadTimeOut - - Comment - Maximum time in seconds for llcurl to execute a mesh uploading request - Persist - 1 - Type - S32 - Value - 600 - - MigrateCacheDirectory + LastSnapshotToDiskAspect Comment - Check for old version of disk cache to migrate to current location + The aspect ratio spinner value for snapshots written to disk Persist - 1 + 0 Type - Boolean + F32 Value - 1 + 0 - MiniMapPrimMaxRadius + LastSnapshotToDiskHeight Comment - Radius of the largest prim to show on the MiniMap. Increasing beyond 256 may cause client lag. + The height of the last disk snapshot, in px Persist 1 Type - F32 + S32 Value - 256.0 + 768 - MiniMapCenter + LastSnapshotToDiskWidth Comment - Sets the focal point of the minimap. (0=None, 1=Camera) + The width of the last disk snapshot, in px Persist 1 Type S32 Value - 1 + 1024 - MiniMapRotate + LastSnapshotToInventoryAspect Comment - Rotate miniature world map to avatar direction + The aspect ratio spinner value for snapshots uploaded to inventory Persist - 1 + 0 Type - Boolean + F32 Value - 1 + 0 - MiniMapScale + LastSnapshotToInventoryHeight Comment - Miniature world map zoom level (pixels per region) + The height of the last texture snapshot, in px Persist 1 Type - F32 + S32 Value - 128.0 + 512 - MouseSensitivity + LastSnapshotToInventoryWidth Comment - Controls responsiveness of mouse when in mouselook mode (fraction or multiple of default mouse sensitivity) + The width of the last texture snapshot, in px Persist 1 Type - F32 + S32 Value - 3.0 + 512 - MouseSmooth + LastSnapshotType Comment - Smooths out motion of mouse when in mouselook mode. + Select this as next type of snapshot to take (0 = feed, 1 = postcard, 2 = texture, 3 = local image) Persist 1 Type - Boolean + S32 Value 0 - MouseSun + SnapshotFeedAddLocation Comment - + Include your location in your uploads to profile feed. Persist - 0 + 1 Type Boolean Value 0 - MouselookBtnState + LeftClickShowMenu Comment - + Left click opens pie menu (FALSE = left click touches or grabs object) Persist - 0 + 1 Type Boolean Value 0 - MoveDownBtnRect + LimitDragDistance Comment - + Limit translation of object via translate tool Persist - 0 + 1 Type - Rect + Boolean Value - - 91 - 29 - 116 - 4 - + 1 - MoveUpBtnRect + LimitSelectDistance Comment - + Disallow selection of objects beyond max select distance Persist + 1 + Type + Boolean + Value 0 + + LipSyncAah + + Comment + Aah (jaw opening) babble loop + Persist + 1 Type - Rect + String Value - - 91 - 54 - 116 - 29 - + 257998776531013446642343 - MuteWind + LipSyncAahPowerTransfer Comment - Disable the wind audio effect + Transfer curve for Voice Interface power to aah lip sync amplitude Persist 1 Type - Boolean + String Value - 0 + 0000123456789 - MuteAmbient + LipSyncEnabled Comment - Ambient sound effects, such as wind noise, play at 0 volume + 0 disable lip-sync, 1 enable babble loop Persist 1 Type Boolean Value - 0 + 1 - MuteAudio + LipSyncOoh Comment - All audio plays at 0 volume (streaming audio still takes up bandwidth, for example) + Ooh (mouth width) babble loop Persist 1 Type - Boolean + String Value - 0 + 1247898743223344444443200000 - MuteMedia + LipSyncOohAahRate Comment - Media plays at 0 volume (streaming audio still takes up bandwidth) + Rate to babble Ooh and Aah (/sec) Persist 1 Type - Boolean + F32 Value - 0 + 24.0 - MuteMusic + LipSyncOohPowerTransfer Comment - Music plays at 0 volume (streaming audio still takes up bandwidth) + Transfer curve for Voice Interface power to ooh lip sync amplitude Persist 1 Type - Boolean + String Value - 0 + 0012345566778899 - MuteSounds + LocalCacheVersion Comment - Sound effects play at 0 volume + Version number of cache Persist 1 Type - Boolean + S32 Value 0 - MuteUI + LogMessages Comment - UI sound effects play at 0 volume + Log network traffic Persist 1 Type @@ -10114,10 +10334,10 @@ This should be as low as possible, but too low may break functionality Value 0 - MuteVoice + LogTextureNetworkTraffic Comment - Voice plays at 0 volume (streaming audio still takes up bandwidth) + Log network traffic for textures Persist 1 Type @@ -10125,10 +10345,10 @@ This should be as low as possible, but too low may break functionality Value 0 - MuteWhenMinimized + LoginAsGod Comment - Mute audio when SL window is minimized + Attempt to login with god powers (Linden accounts only) Persist 1 Type @@ -10136,43 +10356,32 @@ This should be as low as possible, but too low may break functionality Value 0 - MyOutfitsAutofill - - Comment - Always autofill My Outfits from library when empty (else happens just once). - Persist - 1 - Type - Boolean - Value - 0 - - NearMeRange + LoginLocation Comment - Search radius for nearby avatars + Default Login location ('last', 'home') preference Persist 1 Type - F32 + String Value - 20 + last - NextOwnerCopy + LoginPage Comment - Newly created objects can be copied by next owner + Login authentication page. Persist 1 Type - Boolean + String Value - 0 + - NextOwnerModify + LosslessJ2CUpload Comment - Newly created objects can be modified by next owner + Use lossless compression for small image uploads Persist 1 Type @@ -10180,10 +10389,21 @@ This should be as low as possible, but too low may break functionality Value 0 - NextOwnerTransfer + MainloopTimeoutDefault Comment - Newly created objects can be resold or given away by next owner + Timeout duration for mainloop lock detection, in seconds. + Persist + 1 + Type + F32 + Value + 20.0 + + UseWebMapTiles + + Comment + Use web map tiles whenever possible Persist 1 Type @@ -10191,54 +10411,65 @@ This should be as low as possible, but too low may break functionality Value 1 - NewCacheLocation + MapOverlayIndex Comment - Change the location of the local disk cache to this + Currently selected world map type Persist 1 Type - String + S32 Value - + 0 - NextLoginLocation + MapScale Comment - Location to log into by default. + World map zoom level (pixels per region) Persist 1 Type + F32 + Value + 128.0 + + MapServerURL + + Comment + World map URL template for locating map tiles + Persist + 0 + Type String Value - + http://map.secondlife.com.s3.amazonaws.com/ - Nimble + MapShowAgentCount Comment - Disables landing and jumping delays. + Show number of agents next to region names on world map Persist 1 Type Boolean Value - 0 + 1 - NoAudio + MapShowPGEvents Comment - Disable audio playback. + Show PG events on world map Persist 1 Type Boolean Value - 0 + 1 - NoHardwareProbe + MapShowMatureEvents Comment - Disable hardware probe. + Show mature events on world map Persist 1 Type @@ -10246,10 +10477,10 @@ This should be as low as possible, but too low may break functionality Value 0 - NoInventoryLibrary + MapShowAdultEvents Comment - Do not request inventory library. + Show adult events on world map Persist 1 Type @@ -10257,21 +10488,21 @@ This should be as low as possible, but too low may break functionality Value 0 - NoPreload + MapShowInfohubs Comment - Disable sound and image preload. + Show infohubs on the world map Persist 1 Type Boolean Value - 0 + 1 - NoVerifySSLCert + MapShowLandForSale Comment - Do not verify SSL certificates. WARNING: Setting this to TRUE allows anyone to impersonate the server and intercept your data (man in the middle attack). + Show land for sale on world map Persist 1 Type @@ -10279,158 +10510,153 @@ This should be as low as possible, but too low may break functionality Value 0 - NotecardEditorRect + MapShowPeople Comment - Rectangle for notecard editor + Show other users on world map Persist 1 Type - Rect + Boolean Value - - 0 - 400 - 400 - 0 - + 1 - NotifyBoxHeight + MapShowTelehubs Comment - Height of notification messages + Show telehubs on world map Persist 1 Type - S32 + Boolean Value - 200 + 1 - NotifyBoxWidth + Marker Comment - Width of notification messages + [NOT USED] Persist 1 Type - S32 + String Value - 350 + - NotifyMoneyChange + MarketplaceListingsLogging Comment - Pop up notifications for all L$ transactions + Enable debug output associated with the Marketplace Listings (SLM) API. Persist 1 Type Boolean Value - 1 + 0 - NotifyTipDuration + MaxDragDistance Comment - Length of time that notification tips stay on screen (seconds) + Maximum allowed translation distance in a single operation of translate tool (meters from start point) Persist 1 Type F32 Value - 4.0 + 48.0 - NumSessions + MaxHeapSize Comment - Number of successful logins to Second Life + Maximum heap size (GB) Persist 1 Type - S32 + F32 Value - 0 + 1.6 - NumpadControl + MaxPersistentNotifications Comment - How numpad keys control your avatar. 0 = Like the normal arrow keys, 1 = Numpad moves avatar when numlock is off, 2 = Numpad moves avatar regardless of numlock (use this if you have no numlock) + Maximum amount of persistent notifications Persist 1 Type S32 Value - 0 + 250 - ObjectCacheEnabled + MaxSelectDistance Comment - Enable the object cache. + Maximum allowed selection distance (meters from avatar) Persist 1 Type - Boolean + F32 Value - 1 + 128.0 - OpenDebugStatAdvanced + MaxWearableWaitTime Comment - Expand advanced performance stats display + Max seconds to wait for wearable assets to fetch. Persist 1 Type - Boolean + F32 Value - 0 + 60.0 - OpenDebugStatBasic + MeanCollisionBump Comment - Expand basic performance stats display + You have experienced an abuse of being bumped by an object or avatar Persist 1 Type Boolean Value - 1 + 0 - OpenDebugStatNet + MeanCollisionPhysical Comment - Expand network stats display + You have experienced an abuse from a physical object Persist 1 Type Boolean Value - 1 + 0 - OpenDebugStatRender + MeanCollisionPushObject Comment - Expand render stats display + You have experienced an abuse of being pushed by a scripted object Persist 1 Type Boolean Value - 1 + 0 - OpenDebugStatSim + MeanCollisionScripted Comment - Expand simulator performance stats display + You have experienced an abuse from a scripted object Persist 1 Type Boolean Value - 1 + 0 - OpenDebugStatTexture + MeanCollisionSelected Comment - Expand Texture performance stats display + You have experienced an abuse of being pushed via a selected object Persist 1 Type @@ -10438,10 +10664,10 @@ This should be as low as possible, but too low may break functionality Value 0 - OpenDebugStatPhysicsDetails + MediaPluginDebugging Comment - Expand Physics Details performance stats display + Turn on debugging messages that may help diagnosing media issues (WARNING: May reduce performance). Persist 1 Type @@ -10449,21 +10675,98 @@ This should be as low as possible, but too low may break functionality Value 0 - OpenDebugStatSimTime + MediaControlFadeTime Comment - Expand Simulator Time performance stats display + Amount of time (in seconds) that the media control fades Persist 1 Type - Boolean + F32 Value - 0 + 1.5 - OpenDebugStatSimTimeDetails + MediaControlTimeout Comment - Expand Simulator Time Details performance stats display + Amount of time (in seconds) for media controls to fade with no mouse activity + Persist + 1 + Type + F32 + Value + 3.0 + + MediaOnAPrimUI + + Comment + Whether or not to show the "link sharing" UI + Persist + 1 + Type + Boolean + Value + 1 + + MediaPerformanceManagerDebug + + Comment + Whether to show debug data for the media performance manager in the nearby media list. + Persist + 1 + Type + Boolean + Value + 0 + + MediaShowOnOthers + + Comment + Whether or not to show media on other avatars + Persist + 1 + Type + Boolean + Value + 0 + + MediaShowOutsideParcel + + Comment + Whether or not to show media from outside the current parcel + Persist + 1 + Type + Boolean + Value + 1 + + MediaShowWithinParcel + + Comment + Whether or not to show media within the current parcel + Persist + 1 + Type + Boolean + Value + 1 + + MediaTentativeAutoPlay + + Comment + This is a tentative flag that may be temporarily set off by the user, until she teleports + Persist + 0 + Type + Boolean + Value + 1 + + MemoryFailurePreventionEnabled + + Comment + If set, the viewer will quit to avoid crash when memory failure happens Persist 1 Type @@ -10471,267 +10774,295 @@ This should be as low as possible, but too low may break functionality Value 0 - OutBandwidth + MemoryLogFrequency Comment - Outgoing bandwidth throttle (bps) + Seconds between display of Memory in log (0 for never) Persist 1 Type F32 Value - 0.0 + 30.0 - OverdrivenColor + MemoryPrivatePoolEnabled Comment - Color of various indicators when resident is speaking too loud. + Enable the private memory pool management Persist 1 Type - Color4 + Boolean Value - - 1.0 - 0.0 - 0.0 - 1.0 - + 0 - OverlayTitle + MemoryPrivatePoolSize Comment - Controls watermark text message displayed on screen when "ShowOverlayTitle" is enabled (one word, underscores become spaces) + Size of the private memory pool in MB (min. value is 256) Persist 1 Type - String + U32 Value - Set_via_OverlayTitle_in_settings.xml + 512 - PTTCurrentlyEnabled + MemProfiling Comment - Use Push to Talk mode + You want to use tcmalloc's memory profiling options. Persist - 0 + 1 Type Boolean Value - 1 - - PacketDropPercentage + 0 + + MenuAccessKeyTime Comment - Percentage of packets dropped by the client. + Time (seconds) in which the menu key must be tapped to move focus to the menu bar Persist 1 Type F32 Value - 0.0 + 0.25 - ObjectCostHighThreshold + MenuBarHeight + + Comment + + Persist + 0 + Type + S32 + Value + 18 + + MeshEnabled Comment - Threshold at which object cost is considered high (displayed in red). + Expose UI for mesh functionality (may require restart to take effect). Persist 1 Type - F32 + Boolean Value - 50.0 + 1 - ObjectCostLowColor + MeshImportUseSLM Comment - Color for object with a low object cost. + Use cached copy of last upload for a dae if available instead of loading dae file from scratch. Persist 1 Type - Color4 + Boolean Value - - 0.0 - 0.5 - 1.0 - 0.5 - + 0 - ObjectCostMidColor + MeshUploadLogXML Comment - Color for object with a medium object cost. + Verbose XML logging on mesh upload Persist 1 Type - Color4 + Boolean Value - - 1.0 - 0.75 - 0.0 - 0.65 - + 0 - ObjectCostHighColor + MeshUploadFakeErrors Comment - Color for object a high object cost. + Force upload errors (for testing) Persist 1 Type - Color4 + S32 Value - - 1.0 - 0.0 - 0.0 - 0.75 - + 0 - - ParcelMediaAutoPlayEnable + MeshUploadTimeOut + + Comment + Maximum time in seconds for llcurl to execute a mesh uploading request + Persist + 1 + Type + S32 + Value + 600 + + MigrateCacheDirectory Comment - Auto play parcel media when available + Check for old version of disk cache to migrate to current location Persist 1 Type Boolean Value - 0 + 1 - PrimMediaAutoPlayEnable + MiniMapCollisionParcels Comment - Auto play prim media when available + Show collision parcels on the mini-map as they become available Persist 1 Type Boolean Value - 0 + 0 - PerAccountSettingsFile + MiniMapForSaleParcels Comment - Persisted client settings file name (per user). + Show for-sale parcels with a yellow highlight on the mini-map Persist - 0 + 1 Type - String + Boolean Value - + 0 - PermissionsCautionEnabled + MiniMapPrimMaxAltitudeDelta Comment - When enabled, changes the handling of script permission requests to help avoid accidental granting of certain permissions, such as the debit permission + Max allowed altitude difference between your avatar and prims others own for them to be displayed on the minimap (0 means unlimited). Persist - 0 + 1 Type - Boolean + U32 Value - 1 + 256 - PermissionsCautionNotifyBoxHeight + MiniMapPrimMaxAltitudeDeltaOwn Comment - Height of caution-style notification messages + Max allowed altitude difference between your avatar and prims you own for them to be displayed on the minimap (0 means unlimited). Persist - 0 + 1 Type - S32 + U32 Value - 344 + 0 - RevokePermsOnStandUp + MiniMapPrimMaxRadius Comment - When enabled, revokes any permission granted to an object you don't own and from which your avatar is standing up + Radius of the largest prim to show on the MiniMap. Increasing beyond 256 may cause client lag. + Persist + 1 + Type + F32 + Value + 256.0 + + MiniMapPropertyLines + + Comment + Show property boundaries on the mini-map Persist 1 Type Boolean Value - 0 + 0 - PermissionsManagerRect + MiniMapRadarTrackingCircles Comment - Rectangle for permissions manager window + Show tracking circles around the avatars you've selected on the radar in the minimap Persist 1 Type - Rect + Boolean Value - - 0 - 85 - 300 - 0 - + 0 - PickerContextOpacity + MiniMapCenter Comment - Controls overall opacity of context frustrum connecting color and texture pickers with their swatches + Sets the focal point of the minimap. (0=None, 1=Camera) Persist 1 Type - F32 + S32 Value - 0.34999999404 + 1 - PicksPerSecondMouseMoving + MiniMapRotate Comment - How often to perform hover picks while the mouse is moving (picks per second) + Rotate miniature world map to avatar direction Persist 1 Type - F32 + Boolean Value - 5.0 + 1 - PicksPerSecondMouseStationary + MiniMapWhisperRing Comment - How often to perform hover picks while the mouse is stationary (picks per second) + Display whisper distance ring on mini map Persist 1 Type - F32 + Boolean Value - 0.0 + 0 - PieMenuLineWidth + MiniMapWhisperRingColor Comment - Width of lines in pie menu display (pixels) + Color for whisper distance ring on mini map Persist 1 Type - F32 + Color4 Value - 2.5 + + 0.0 + 1.0 + 0.0 + 0.5 + - PinTalkViewOpen + MiniMapChatRing Comment - Stay in IM after hitting return + Display chat distance ring on mini map Persist 1 Type Boolean Value + 0 + + MiniMapChatRingColor + + Comment + Color for chat distance ring on mini map + Persist 1 + Type + Color4 + Value + + 1.0 + 1.0 + 0.0 + 0.5 + - PingInterpolate + MiniMapShoutRing Comment - Extrapolate object position along velocity vector based on ping delay + Display shout distance ring on mini map Persist 1 Type @@ -10739,32 +11070,59 @@ This should be as low as possible, but too low may break functionality Value 0 - PitchFromMousePosition + MiniMapShoutRingColor Comment - Vertical range over which avatar head tracks mouse position (degrees of head rotation from top of window to bottom) + Color for shout distance ring on mini map + Persist + 1 + Type + Color4 + Value + + 1.0 + 0.0 + 0.0 + 0.5 + + + MiniMapScale + + Comment + Miniature world map zoom level (pixels per region) Persist 1 Type F32 Value - 90.0 + 128.0 - PlayTypingAnim + MiniMapWorldMapTextures Comment - Your avatar plays the typing animation whenever you type in the chat bar + Use the world map texture tile on the mini-map rather than the terrain texture Persist 1 Type Boolean Value + 0 + + MouseSensitivity + + Comment + Controls responsiveness of mouse when in mouselook mode (fraction or multiple of default mouse sensitivity) + Persist 1 + Type + F32 + Value + 3.0 - PluginAttachDebuggerToPlugins + MouseSmooth Comment - If true, attach a debugger session to each plugin process as it's launched. + Smooths out motion of mouse when in mouselook mode. Persist 1 Type @@ -10772,22 +11130,75 @@ This should be as low as possible, but too low may break functionality Value 0 - PluginInstancesCPULimit + MouseSun Comment - Amount of total plugin CPU usage before inworld plugins start getting turned down to "slideshow" priority. Set to 0 to disable this check. + + Persist + 0 + Type + Boolean + Value + 0 + + MouselookBtnState + + Comment + + Persist + 0 + Type + Boolean + Value + 0 + + MoveDownBtnRect + + Comment + + Persist + 0 + Type + Rect + Value + + 91 + 29 + 116 + 4 + + + MoveUpBtnRect + + Comment + + Persist + 0 + Type + Rect + Value + + 91 + 54 + 116 + 29 + + + MuteWind + + Comment + Disable the wind audio effect Persist 1 Type - F32 + Boolean Value - 0.9 + 0 - - PlainTextChatHistory + MuteAmbient Comment - Enable/Disable plain text chat history style + Ambient sound effects, such as wind noise, play at 0 volume Persist 1 Type @@ -10795,45 +11206,43 @@ This should be as low as possible, but too low may break functionality Value 0 - - PluginInstancesLow + MuteAudio Comment - Limit on the number of inworld media plugins that will run at "low" priority + All audio plays at 0 volume (streaming audio still takes up bandwidth, for example) Persist 1 Type - U32 + Boolean Value - 4 + 0 - PluginInstancesNormal + MuteMedia Comment - Limit on the number of inworld media plugins that will run at "normal" or higher priority + Media plays at 0 volume (streaming audio still takes up bandwidth) Persist 1 Type - U32 + Boolean Value - 2 + 0 - PluginInstancesTotal + MuteMusic Comment - Hard limit on the number of plugins that will be instantiated at once for inworld media + Music plays at 0 volume (streaming audio still takes up bandwidth) Persist 1 Type - U32 + Boolean Value - 8 + 0 - - PluginUseReadThread + MuteSounds Comment - Use a separate thread to read incoming messages from plugins + Sound effects play at 0 volume Persist 1 Type @@ -10841,224 +11250,87 @@ This should be as low as possible, but too low may break functionality Value 0 - PlayTypingSound + MuteUI Comment - TRUE to play and hear the typing sound whenever you or another avatar types in the chat bar + UI sound effects play at 0 volume Persist 1 Type Boolean Value + 0 + + MuteVoice + + Comment + Voice plays at 0 volume (streaming audio still takes up bandwidth) + Persist 1 + Type + Boolean + Value + 0 - PrecachingDelay + MuteWhenMinimized Comment - Delay when logging in to load world before showing it (seconds) + Mute audio when SL window is minimized Persist 1 Type - F32 + Boolean Value - 6.0 + 0 - PreferredMaturity + MyOutfitsAutofill + + Comment + Always autofill My Outfits from library when empty (else happens just once). + Persist + 1 + Type + Boolean + Value + 0 + + NearMeRange Comment - Setting for the user's preferred maturity level. + Search radius for nearby avatars Persist 1 Type - U32 + F32 Value - 13 + 20 - - PreviewAmbientColor - - Comment - Ambient color of preview render. - Persist - 1 - Type - Color4 - Value - - 0.0 - 0.0 - 0.0 - 1.0 - - - - - PreviewDiffuse0 - - Comment - Diffise color of preview light 0. - Persist - 1 - Type - Color4 - Value - - 1.0 - 1.0 - 1.0 - 1.0 - - - - PreviewDiffuse1 - - Comment - Diffise color of preview light 1. - Persist - 1 - Type - Color4 - Value - - 0.25 - 0.25 - 0.25 - 1.0 - - - - PreviewDiffuse2 - - Comment - Diffise color of preview light 2. - Persist - 1 - Type - Color4 - Value - - 1.0 - 1.0 - 1.0 - 1.0 - - - - PreviewSpecular0 - - Comment - Diffise color of preview light 0. - Persist - 1 - Type - Color4 - Value - - 1.0 - 1.0 - 1.0 - 1.0 - - - - PreviewSpecular1 - - Comment - Diffise color of preview light 1. - Persist - 1 - Type - Color4 - Value - - 1.0 - 1.0 - 1.0 - 1.0 - - - - PreviewSpecular2 - - Comment - Diffise color of preview light 2. - Persist - 1 - Type - Color4 - Value - - 1.0 - 1.0 - 1.0 - 1.0 - - - - - PreviewDirection0 - - Comment - Direction of light 0 for preview render. - Persist - 1 - Type - Vector3 - Value - - -0.75 - 1 - 1.0 - - - - PreviewDirection1 - - Comment - Direction of light 1 for preview render. - Persist - 1 - Type - Vector3 - Value - - 0.5 - -0.6 - 0.4 - - - - PreviewDirection2 - - Comment - Direction of light 2 for preview render. - Persist - 1 - Type - Vector3 - Value - - 0.5 - -0.8 - 0.3 - - - - PrimMediaMasterEnabled - - Comment - Whether or not Media on a Prim is enabled. + NewCacheLocation + + Comment + Change the location of the local disk cache to this Persist 1 Type - Boolean + String Value + + + NextLoginLocation + + Comment + Location to log into by default. + Persist 1 + Type + String + Value + - PrimMediaControlsUseHoverControlSet - - Comment - Whether or not hovering over prim media uses minimal "hover" controls or the authored control set. + Nimble + + Comment + Disables landing and jumping delays. Persist 1 Type @@ -11066,76 +11338,65 @@ This should be as low as possible, but too low may break functionality Value 0 - PrimMediaDragNDrop - - Comment - Enable drag and drop of URLs onto prim faces - Persist - 1 - Type - Boolean - Value - 1 - - PrimMediaMaxRetries + NoAudio Comment - Maximum number of retries for media queries. + Disable audio playback. Persist 1 Type - U32 + Boolean Value - 4 + 0 - PrimMediaRequestQueueDelay + NoHardwareProbe Comment - Timer delay for fetching media from the queue (in seconds). + Disable hardware probe. Persist 1 Type - F32 + Boolean Value - 1.0 + 0 - PrimMediaRetryTimerDelay + NoInventoryLibrary Comment - Timer delay for retrying on media queries (in seconds). + Do not request inventory library. Persist 1 Type - F32 + Boolean Value - 5.0 + 0 - PrimMediaMaxSortedQueueSize + NoPreload Comment - Maximum number of objects the viewer will load media for initially + Disable sound and image preload. Persist 1 Type - U32 + Boolean Value - 100000 + 0 - PrimMediaMaxRoundRobinQueueSize + NoVerifySSLCert Comment - Maximum number of objects the viewer will continuously update media for + Do not verify SSL certificates. WARNING: Setting this to TRUE allows anyone to impersonate the server and intercept your data (man in the middle attack). Persist 1 Type - U32 + Boolean Value - 100000 + 0 - PreviewAnimRect + NotecardEditorRect Comment - Rectangle for animation preview window + Rectangle for notecard editor Persist 1 Type @@ -11143,159 +11404,103 @@ This should be as low as possible, but too low may break functionality Value 0 - 85 - 300 + 400 + 400 0 - PreviewClassifiedRect + NotifyBoxHeight Comment - Rectangle for URL preview window + Height of notification messages Persist 1 Type - Rect + S32 Value - - 0 - 530 - 420 - 0 - + 200 - PreviewEventRect + NotifyBoxWidth Comment - Rectangle for Event preview window + Width of notification messages Persist 1 Type - Rect + S32 Value - - 0 - 530 - 420 - 0 - + 350 - PreviewLandmarkRect + NotifyMoneyChange Comment - Rectangle for landmark preview window + Pop up notifications for all L$ transactions Persist 1 Type - Rect + Boolean Value - - 0 - 90 - 300 - 0 - - - PreviewObjectRect - - Comment - Rectangle for object preview window - Persist 1 - Type - Rect - Value - - 0 - 85 - 300 - 0 - - PreviewScriptRect + NotifyTipDuration Comment - Rectangle for script preview window + Length of time that notification tips stay on screen (seconds) Persist 1 Type - Rect + F32 Value - - 0 - 586 - 576 - 0 - + 4.0 - PreviewSoundRect + NumSessions Comment - Rectangle for sound preview window + Number of successful logins to Second Life Persist 1 Type - Rect + S32 Value - - 0 - 85 - 300 - 0 - + 0 - PreviewTextureRect + NumpadControl Comment - Rectangle for texture preview window + How numpad keys control your avatar. 0 = Like the normal arrow keys, 1 = Numpad moves avatar when numlock is off, 2 = Numpad moves avatar regardless of numlock (use this if you have no numlock) Persist 1 Type - Rect + S32 Value - - 0 - 400 - 400 - 0 - + 0 - PreviewURLRect + ObjectCacheEnabled Comment - Rectangle for URL preview window + Enable the object cache. Persist 1 Type - Rect + Boolean Value - - 0 - 90 - 300 - 0 - + 1 - PreviewWearableRect + OpenDebugStatAdvanced Comment - Rectangle for wearable preview window + Expand advanced performance stats display Persist 1 Type - Rect + Boolean Value - - 0 - 85 - 300 - 0 - + 0 - ProbeHardwareOnStartup + OpenDebugStatBasic Comment - Query current hardware configuration on application startup + Expand basic performance stats display Persist 1 Type @@ -11303,59 +11508,43 @@ This should be as low as possible, but too low may break functionality Value 1 - PropertiesRect + OpenDebugStatNet Comment - Rectangle for inventory item properties window + Expand network stats display Persist 1 Type - Rect + Boolean Value - - 0 - 320 - 350 - 0 - + 1 - PurgeCacheOnNextStartup + OpenDebugStatRender Comment - Clear local file cache next time viewer is run + Expand render stats display Persist 1 Type Boolean Value - 0 + 1 - PurgeCacheOnStartup + OpenDebugStatSim Comment - Clear local file cache every time viewer is run + Expand simulator performance stats display Persist 1 Type Boolean Value - 0 - - PushToTalkButton - - Comment - Which button or keyboard key is used for push-to-talk - Persist 1 - Type - String - Value - MiddleMouse - PushToTalkToggle + OpenDebugStatTexture Comment - Should the push-to-talk button behave as a toggle + Expand Texture performance stats display Persist 1 Type @@ -11363,10 +11552,10 @@ This should be as low as possible, but too low may break functionality Value 0 - QAMode + OpenDebugStatPhysicsDetails Comment - Enable Testing Features. + Expand Physics Details performance stats display Persist 1 Type @@ -11374,10 +11563,10 @@ This should be as low as possible, but too low may break functionality Value 0 - QAModeMetrics + OpenDebugStatSimTime Comment - "Enables QA features (logging, faster cycling) for metrics collector" + Expand Simulator Time performance stats display Persist 1 Type @@ -11385,10 +11574,10 @@ This should be as low as possible, but too low may break functionality Value 0 - QuietSnapshotsToDisk + OpenDebugStatSimTimeDetails Comment - Take snapshots to disk without playing animation or sound + Expand Simulator Time Details performance stats display Persist 1 Type @@ -11396,10 +11585,10 @@ This should be as low as possible, but too low may break functionality Value 0 - QuitAfterSeconds + OutBandwidth Comment - The duration allowed before quitting. + Outgoing bandwidth throttle (bps) Persist 1 Type @@ -11407,266 +11596,218 @@ This should be as low as possible, but too low may break functionality Value 0.0 - RadioLandBrushAction + OverdrivenColor Comment - Last selected land modification operation (0 = flatten, 1 = raise, 2 = lower, 3 = smooth, 4 = roughen, 5 = revert) + Color of various indicators when resident is speaking too loud. Persist 1 Type - S32 + Color4 Value - 0 + + 1.0 + 0.0 + 0.0 + 1.0 + - RadioLandBrushSize + OverlayTitle Comment - Size of land modification brush (0 = small, 1 = medium, 2 = large) + Controls watermark text message displayed on screen when "ShowOverlayTitle" is enabled (one word, underscores become spaces) Persist 1 Type - S32 + String Value - 0 + Set_via_OverlayTitle_in_settings.xml - LandBrushForce + PTTCurrentlyEnabled Comment - Multiplier for land modification brush force. + Use Push to Talk mode Persist - 1 + 0 Type - F32 + Boolean Value - 1.0 + 1 - WebContentWindowLimit + PacketDropPercentage Comment - Maximum number of web browser windows that can be open at once in the Web content floater (0 for no limit) + Percentage of packets dropped by the client. Persist 1 Type - S32 + F32 Value - 5 + 0.0 - MediaRollOffRate + ObjectCostHighThreshold Comment - Multiplier to change rate of media attenuation + Threshold at which object cost is considered high (displayed in red). Persist 1 Type F32 Value - 0.125 + 50.0 - MediaRollOffMin + ObjectCostLowColor Comment - Adjusts the distance at which media attentuation starts + Color for object with a low object cost. Persist 1 Type - F32 + Color4 Value - 5.0 + + 0.0 + 0.5 + 1.0 + 0.5 + - MediaRollOffMax + ObjectCostMidColor Comment - Distance at which media volume is set to 0 + Color for object with a medium object cost. Persist 1 Type - F32 + Color4 Value - 30.0 + + 1.0 + 0.75 + 0.0 + 0.65 + - RecentItemsSortOrder - - Comment - Specifies sort key for recent inventory items (+0 = name, +1 = date, +2 = folders always by name, +4 = system folders to top) - Persist - 1 - Type - U32 - Value - 1 - - RectangleSelectInclusive + ObjectCostHighColor + + Comment + Color for object a high object cost. + Persist + 1 + Type + Color4 + Value + + 1.0 + 0.0 + 0.0 + 0.75 + + + + ParcelMediaAutoPlayEnable Comment - Select objects that have at least one vertex inside selection rectangle + Auto play parcel media when available Persist 1 Type Boolean Value - 1 + 0 - RegionTextureSize + PrimMediaAutoPlayEnable Comment - Terrain texture dimensions (power of 2) + Auto play prim media when available Persist 1 Type - U32 + Boolean Value - 256 + 0 - RememberName + PerAccountSettingsFile Comment - Add name to list of saved names offered on login + Persisted client settings file name (per user). Persist - 1 + 0 Type - Boolean + String Value - 1 + - RememberPassword + PermissionsCautionEnabled Comment - Keep password (in encrypted form) for next login + When enabled, changes the handling of script permission requests to help avoid accidental granting of certain permissions, such as the debit permission Persist - 1 + 0 Type Boolean Value 1 - - OctreeMaxNodeCapacity - - Comment - Maximum number of elements to store in a single octree node - Persist - 1 - Type - U32 - Value - 128 - - - OctreeReserveNodeCapacity + PermissionsCautionNotifyBoxHeight Comment - Default number of elements to pre-allocate for in a single octree node + Height of caution-style notification messages Persist - 1 + 0 Type - U32 + S32 Value - 4 - - - OctreeStaticObjectSizeFactor - - Comment - Multiplier on static object size for determining octree node size - Persist - 1 - Type - S32 - Value - 4 - - - OctreeAlphaDistanceFactor - - Comment - Multiplier on alpha object distance for determining octree node size - Persist - 1 - Type - Vector3 - Value - - 0.1 - 0.0 - 0.0 - - - - OctreeAttachmentSizeFactor - - Comment - Multiplier on attachment size for determining octree node size - Persist - 1 - Type - S32 - Value - 4 - - - OctreeDistanceFactor - - Comment - Multiplier on distance for determining octree node size - Persist - 1 - Type - Vector3 - Value - - 0.01 - 0.0 - 0.0 - - - RenderAnisotropic + 344 + + PickerContextOpacity Comment - Render textures using anisotropic filtering + Controls overall opacity of context frustrum connecting color and texture pickers with their swatches Persist 1 Type - Boolean + F32 Value - 0 + 0.34999999404 - RenderAppleUseMultGL + PicksPerSecondMouseMoving Comment - Whether we want to use multi-threaded OpenGL on Apple hardware (requires restart of SL). + How often to perform hover picks while the mouse is moving (picks per second) Persist 1 Type - Boolean + F32 Value - 0 + 5.0 - RenderAttachedLights + PicksPerSecondMouseStationary Comment - Render lighted prims that are attached to avatars + How often to perform hover picks while the mouse is stationary (picks per second) Persist 1 Type - Boolean + F32 Value - 1 + 0.0 - RenderAttachedParticles + PieMenuLineWidth Comment - Render particle systems that are attached to avatars + Width of lines in pie menu display (pixels) Persist 1 Type - Boolean + F32 Value - 1 + 2.5 - RenderAvatarCloth + PinTalkViewOpen Comment - Controls if avatars use wavy cloth + Stay in IM after hitting return Persist 1 Type @@ -11674,136 +11815,123 @@ This should be as low as possible, but too low may break functionality Value 1 - RenderAvatarComplexityLimit + PingInterpolate Comment - Max visual complexity of avatars in a scene + Extrapolate object position along velocity vector based on ping delay Persist 1 Type - S32 + Boolean Value - -1 + 0 - RenderComplexityColorMin + PitchFromMousePosition Comment - Max visual complexity of avatars in a scene + Vertical range over which avatar head tracks mouse position (degrees of head rotation from top of window to bottom) Persist 1 Type - Color4 + F32 Value - - 0.0 - 0.0 - 1.0 - 0.5 - + 90.0 - RenderComplexityColorMid + PlayTypingAnim Comment - Max visual complexity of avatars in a scene + Your avatar plays the typing animation whenever you type in the chat bar Persist 1 Type - Color4 + Boolean Value - - 0.0 - 1.0 - 0.0 - 0.5 - + 1 - RenderComplexityColorMax + PluginAttachDebuggerToPlugins Comment - Max visual complexity of avatars in a scene + If true, attach a debugger session to each plugin process as it's launched. Persist 1 Type - Color4 + Boolean Value - - 1.0 - 0.0 - 0.0 - 0.5 - + 0 - RenderComplexityThreshold + PluginInstancesCPULimit Comment - Only color objects higher than render threshold + Amount of total plugin CPU usage before inworld plugins start getting turned down to "slideshow" priority. Set to 0 to disable this check. Persist 1 Type - S32 + F32 Value - -1 + 0.9 - RenderComplexityStaticMax + + PlainTextChatHistory Comment - Sets a static max value for scaling of RenderComplexity - display (-1 for dynamic scaling) + Enable/Disable plain text chat history style Persist 1 Type - S32 + Boolean Value - -1 + 0 - RenderAvatarLODFactor + + PluginInstancesLow Comment - Controls level of detail of avatars (multiplier for current screen area when calculated level of detail) + Limit on the number of inworld media plugins that will run at "low" priority Persist 1 Type - F32 + U32 Value - 0.5 + 4 - RenderAvatarMaxVisible + PluginInstancesNormal Comment - Maximum number of avatars to display at any one time + Limit on the number of inworld media plugins that will run at "normal" or higher priority Persist 1 Type - S32 + U32 Value - 12 + 2 - RenderAvatarPhysicsLODFactor + PluginInstancesTotal Comment - Controls level of detail of avatar physics (such as breast physics). + Hard limit on the number of plugins that will be instantiated at once for inworld media Persist 1 Type - F32 + U32 Value - 1.0 + 8 - RenderAvatarInvisible - + + PluginUseReadThread + Comment - Set your avatar as Invisible + Use a separate thread to read incoming messages from plugins Persist - 0 + 1 Type Boolean Value 0 - RenderAvatarVP + PlayTypingSound Comment - Use vertex programs to perform hardware skinning of avatar + TRUE to play and hear the typing sound whenever you or another avatar types in the chat bar Persist 1 Type @@ -11811,497 +11939,1482 @@ This should be as low as possible, but too low may break functionality Value 1 - RenderCompressTextures - - Comment - Enable texture compression on OpenGL 3.0 and later implementations (EXPERIMENTAL, requires restart) - Persist - 1 - Type - Boolean - Value - 0 - - RenderPerformanceTest + PrecachingDelay Comment - - Disable rendering of everything but in-world content for - performance testing - + Delay when logging in to load world before showing it (seconds) Persist 1 - Type - Boolean - Value - 0 - - - RenderLocalLights - - Comment - Whether or not to render local lights. - Persist - 1 - Type - Boolean - Value - 1 - + Type + F32 + Value + 6.0 + + PreferredMaturity + + Comment + Setting for the user's preferred maturity level. + Persist + 1 + Type + U32 + Value + 13 + - RenderShadowNearDist + PreviewAmbientColor Comment - Near clip plane of shadow camera (affects precision of depth shadows). + Ambient color of preview render. Persist 1 Type - Vector3 + Color4 Value - 256 - 256 - 256 + 0.0 + 0.0 + 0.0 + 1.0 - RenderShadowClipPlanes + + + PreviewDiffuse0 Comment - Near clip plane split distances for shadow map frusta. + Diffise color of preview light 0. Persist 1 Type - Vector3 + Color4 Value 1.0 - 12.0 - 32.0 + 1.0 + 1.0 + 1.0 - RenderShadowSplitExponent + + PreviewDiffuse1 Comment - Near clip plane split distances for shadow map frusta (x=perspective, y=ortho, z=transition rate). + Diffise color of preview light 1. Persist 1 Type - Vector3 + Color4 Value - 3.0 - 3.0 - 2.0 + 0.25 + 0.25 + 0.25 + 1.0 - RenderShadowOrthoClipPlanes + + PreviewDiffuse2 Comment - Near clip plane split distances for orthographic shadow map frusta. + Diffise color of preview light 2. Persist 1 Type - Vector3 + Color4 Value - 4.0 - 8.0 - 24.0 + 1.0 + 1.0 + 1.0 + 1.0 - RenderShadowProjOffset - - Comment - Amount to scale distance to virtual origin of shadow perspective projection. - Persist - 1 - Type - F32 - Value - 2.0 - - RenderShadowSlopeThreshold + + PreviewSpecular0 Comment - Cutoff slope value for points to affect perspective shadow generation + Diffise color of preview light 0. Persist 1 Type - F32 + Color4 Value - 0.0 + + 1.0 + 1.0 + 1.0 + 1.0 + - RenderShadowProjExponent + + PreviewSpecular1 Comment - Exponent applied to transition between ortho and perspective shadow projections based on viewing angle and light vector. + Diffise color of preview light 1. Persist 1 Type - F32 + Color4 Value - 0.5 + + 1.0 + 1.0 + 1.0 + 1.0 + - RenderSSAOScale + + PreviewSpecular2 Comment - Scaling factor for the area to sample for occluders (pixels at 1 meter away, inversely varying with distance) + Diffise color of preview light 2. Persist 1 Type - F32 + Color4 Value - 1500.0 + + 1.0 + 1.0 + 1.0 + 1.0 + - RenderSSAOMaxScale + + + PreviewDirection0 Comment - Maximum screen radius for sampling (pixels) + Direction of light 0 for preview render. Persist 1 Type - U32 + Vector3 Value - 250 + + -0.75 + 1 + 1.0 + - RenderSSAOFactor + + PreviewDirection1 Comment - Occlusion sensitivity factor for ambient occlusion (larger is more) + Direction of light 1 for preview render. Persist 1 Type - F32 + Vector3 Value - 5.0 + + 0.5 + -0.6 + 0.4 + - RenderSSAOEffect + + PreviewDirection2 Comment - Multiplier for (1) value for areas which are totally occluded. Blends with original color for partly-occluded areas. (Third component is unused.) + Direction of light 2 for preview render. Persist 1 Type Vector3 Value - 0.50 - 1.00 - 0.00 + 0.5 + -0.8 + 0.3 - RenderBumpmapMinDistanceSquared - - Comment - Maximum distance at which to render bumpmapped primitives (distance in meters, squared) + + PrimMediaMasterEnabled + + Comment + Whether or not Media on a Prim is enabled. Persist 1 Type - F32 + Boolean Value - 100.0 + 1 - RenderNormalMapScale - - Comment - Scaler applied to height map when generating normal maps - Persist - 1 - Type - F32 - Value - 64 - - RenderCubeMap - - Comment - Whether we can render the cube map or not + PrimMediaControlsUseHoverControlSet + + Comment + Whether or not hovering over prim media uses minimal "hover" controls or the authored control set. Persist 1 Type Boolean Value - 1 + 0 - RenderCustomSettings + PrimMediaDragNDrop + + Comment + Enable drag and drop of URLs onto prim faces + Persist + 1 + Type + Boolean + Value + 1 + + PrimMediaMaxRetries Comment - Do you want to set the graphics settings yourself + Maximum number of retries for media queries. Persist 1 Type - Boolean + U32 Value - 0 + 4 - RenderDebugGL + PrimMediaRequestQueueDelay Comment - Enable strict GL debugging. + Timer delay for fetching media from the queue (in seconds). Persist 1 Type - Boolean + F32 Value - 0 + 1.0 - RenderDebugNormalScale - - Comment - Scale of normals in debug display. - Persist - 1 - Type - F32 - Value - 0.03 - - RenderDebugPipeline + PrimMediaRetryTimerDelay Comment - Enable strict pipeline debugging. + Timer delay for retrying on media queries (in seconds). Persist 1 Type - Boolean + F32 Value - 0 + 5.0 - RenderMaxTextureIndex - - Comment - Maximum texture index to use for indexed texture rendering. - Persist - 1 - Type - U32 - Value - 16 - - RenderDebugTextureBind + PrimMediaMaxSortedQueueSize Comment - Enable texture bind performance test. + Maximum number of objects the viewer will load media for initially Persist 1 Type - Boolean + U32 Value - 0 + 100000 - RenderDelayCreation - - Comment - Throttle creation of drawables. - Persist - 1 - Type - Boolean - Value - 0 - - - RenderAnimateRes - - Comment - Animate rezing prims. - Persist - 1 - Type - Boolean - Value - 0 - - - RenderBakeSunlight - - Comment - Bake sunlight into vertex buffers for static objects. - Persist - 1 - Type - Boolean - Value - 0 - - - - RenderNoAlpha - - Comment - Disable rendering of alpha objects (render all alpha objects as alpha masks). - Persist - 1 - Type - Boolean - Value - 0 - - - - RenderEdgeDepthCutoff - - Comment - Cutoff for depth difference that amounts to an edge. - Persist - 1 - Type - F32 - Value - 0.01 - - RenderEdgeNormCutoff - - Comment - Cutoff for normal difference that amounts to an edge. - Persist - 1 - Type - F32 - Value - 0.25 - - - RenderDeferredAlphaSoften - - Comment - Scalar for softening alpha surfaces (for soft particles). - Persist - 1 - Type - F32 - Value - 0.75 - - RenderDeferredNoise - - Comment - Noise scalar to hide banding in deferred render. - Persist - 1 - Type - F32 - Value - 4 - - RenderDeferredSpotShadowBias - - Comment - Bias value for spot shadows (prevent shadow acne). - Persist - 1 - Type - F32 - Value - -64.0 - - RenderDeferredSpotShadowOffset - - Comment - Offset value for spot shadows (prevent shadow acne). - Persist - 1 - Type - F32 - Value - 0.8 - - - RenderShadowBias - - Comment - Bias value for shadows (prevent shadow acne). - Persist - 1 - Type - F32 - Value - -0.008 - - RenderShadowOffset - - Comment - Offset value for shadows (prevent shadow acne). - Persist - 1 - Type - F32 - Value - 0.01 - - RenderShadowBiasError - - Comment - Error scale for shadow bias (based on altitude). - Persist - 1 - Type - F32 - Value - 0 - - RenderShadowOffsetError - - Comment - Error scale for shadow offset (based on altitude). - Persist - 1 - Type - F32 - Value - 0 - - - RenderDepthPrePass - - Comment - EXPERIMENTAL: Prime the depth buffer with simple prim geometry before rendering with textures. - Persist - 1 - Type - Boolean - Value - 0 - - - RenderDepthOfField - - Comment - Whether to use depth of field effect when lighting and shadows are enabled - Persist - 1 - Type - Boolean - Value - 0 - - - CameraDoFResScale - - Comment - Amount to scale down depth of field resolution. Valid range is 0.25 (quarter res) to 1.0 (full res) - Persist - 1 - Type - F32 - Value - 0.7 - - - RenderSpotLightsInNondeferred - - Comment - Whether to support projectors as spotlights when Lighting and Shadows is disabled + 100000 + + PreviewAnimRect + + Comment + Rectangle for animation preview window + Persist + 1 + Type + Rect + Value + + 0 + 85 + 300 + 0 + + + PreviewClassifiedRect + + Comment + Rectangle for URL preview window + Persist + 1 + Type + Rect + Value + + 0 + 530 + 420 + 0 + + + PreviewEventRect + + Comment + Rectangle for Event preview window + Persist + 1 + Type + Rect + Value + + 0 + 530 + 420 + 0 + + + PreviewLandmarkRect + + Comment + Rectangle for landmark preview window + Persist + 1 + Type + Rect + Value + + 0 + 90 + 300 + 0 + + + PreviewObjectRect + + Comment + Rectangle for object preview window + Persist + 1 + Type + Rect + Value + + 0 + 85 + 300 + 0 + + + PreviewScriptRect + + Comment + Rectangle for script preview window + Persist + 1 + Type + Rect + Value + + 0 + 586 + 576 + 0 + + + PreviewSoundRect + + Comment + Rectangle for sound preview window + Persist + 1 + Type + Rect + Value + + 0 + 85 + 300 + 0 + + + PreviewTextureRect + + Comment + Rectangle for texture preview window + Persist + 1 + Type + Rect + Value + + 0 + 400 + 400 + 0 + + + PreviewURLRect + + Comment + Rectangle for URL preview window + Persist + 1 + Type + Rect + Value + + 0 + 90 + 300 + 0 + + + PreviewWearableRect + + Comment + Rectangle for wearable preview window + Persist + 1 + Type + Rect + Value + + 0 + 85 + 300 + 0 + + + ProbeHardwareOnStartup + + Comment + Query current hardware configuration on application startup + Persist + 1 + Type + Boolean + Value + 1 + + PropertiesRect + + Comment + Rectangle for inventory item properties window + Persist + 1 + Type + Rect + Value + + 0 + 320 + 350 + 0 + + + PurgeCacheOnNextStartup + + Comment + Clear local file cache next time viewer is run + Persist + 1 + Type + Boolean + Value + 0 + + PurgeCacheOnStartup + + Comment + Clear local file cache every time viewer is run + Persist + 1 + Type + Boolean + Value + 0 + + PushToTalkButton + + Comment + Which button or keyboard key is used for push-to-talk + Persist + 1 + Type + String + Value + MiddleMouse + + PushToTalkToggle + + Comment + Should the push-to-talk button behave as a toggle + Persist + 1 + Type + Boolean + Value + 0 + + QAMode + + Comment + Enable Testing Features. + Persist + 1 + Type + Boolean + Value + 0 + + QAModeMetrics + + Comment + "Enables QA features (logging, faster cycling) for metrics collector" + Persist + 1 + Type + Boolean + Value + 0 + + QuietSnapshotsToDisk + + Comment + Take snapshots to disk without playing animation or sound + Persist + 1 + Type + Boolean + Value + 0 + + QuitAfterSeconds + + Comment + The duration allowed before quitting. + Persist + 1 + Type + F32 + Value + 0.0 + + RadioLandBrushAction + + Comment + Last selected land modification operation (0 = flatten, 1 = raise, 2 = lower, 3 = smooth, 4 = roughen, 5 = revert) + Persist + 1 + Type + S32 + Value + 0 + + RadioLandBrushSize + + Comment + Size of land modification brush (0 = small, 1 = medium, 2 = large) + Persist + 1 + Type + S32 + Value + 0 + + LandBrushForce + + Comment + Multiplier for land modification brush force. + Persist + 1 + Type + F32 + Value + 1.0 + + WebContentWindowLimit + + Comment + Maximum number of web browser windows that can be open at once in the Web content floater (0 for no limit) + Persist + 1 + Type + S32 + Value + 5 + + MediaRollOffRate + + Comment + Multiplier to change rate of media attenuation + Persist + 1 + Type + F32 + Value + 0.125 + + MediaRollOffMin + + Comment + Adjusts the distance at which media attentuation starts + Persist + 1 + Type + F32 + Value + 5.0 + + MediaRollOffMax + + Comment + Distance at which media volume is set to 0 + Persist + 1 + Type + F32 + Value + 30.0 + + RecentItemsSortOrder + + Comment + Specifies sort key for recent inventory items (+0 = name, +1 = date, +2 = folders always by name, +4 = system folders to top) + Persist + 1 + Type + U32 + Value + 1 + + RectangleSelectInclusive + + Comment + Select objects that have at least one vertex inside selection rectangle + Persist + 1 + Type + Boolean + Value + 1 + + RegionTextureSize + + Comment + Terrain texture dimensions (power of 2) + Persist + 1 + Type + U32 + Value + 256 + + RememberName + + Comment + Add name to list of saved names offered on login + Persist + 1 + Type + Boolean + Value + 1 + + RememberPassword + + Comment + Keep password (in encrypted form) for next login + Persist + 1 + Type + Boolean + Value + 1 + + + OctreeMaxNodeCapacity + + Comment + Maximum number of elements to store in a single octree node + Persist + 1 + Type + U32 + Value + 128 + + + OctreeMinimumNodeSize + + Comment + Minimum size of any octree node + Persist + 1 + Type + F32 + Value + 0.01 + + + OctreeReserveNodeCapacity + + Comment + Default number of elements to pre-allocate for in a single octree node + Persist + 1 + Type + U32 + Value + 4 + + + OctreeStaticObjectSizeFactor + + Comment + Multiplier on static object size for determining octree node size + Persist + 1 + Type + S32 + Value + 4 + + + OctreeAlphaDistanceFactor + + Comment + Multiplier on alpha object distance for determining octree node size + Persist + 1 + Type + Vector3 + Value + + 0.1 + 0.0 + 0.0 + + + + OctreeAttachmentSizeFactor + + Comment + Multiplier on attachment size for determining octree node size + Persist + 1 + Type + S32 + Value + 4 + + + OctreeDistanceFactor + + Comment + Multiplier on distance for determining octree node size + Persist + 1 + Type + Vector3 + Value + + 0.01 + 0.0 + 0.0 + + + RenderAnisotropic + + Comment + Render textures using anisotropic filtering + Persist + 1 + Type + Boolean + Value + 0 + + RenderAppleUseMultGL + + Comment + Whether we want to use multi-threaded OpenGL on Apple hardware (requires restart of SL). + Persist + 1 + Type + Boolean + Value + 0 + + RenderAttachedLights + + Comment + Render lighted prims that are attached to avatars + Persist + 1 + Type + Boolean + Value + 1 + + RenderAttachedParticles + + Comment + Render particle systems that are attached to avatars + Persist + 1 + Type + Boolean + Value + 1 + + AlwaysRenderFriends + + Comment + 0 - Render avatars with complexity below RenderAvatarMaxComplexity +1 - Always renders friends, regardless of max complexity +2 - Only renders friends +3 - Only renders self + Persist + 1 + Type + S32 + Value + 0 + + RenderAvatarCloth + + Comment + Controls if avatars use wavy cloth + Persist + 1 + Type + Boolean + Value + 1 + + RenderAvatarComplexityLimit + + Comment + Max visual complexity of avatars in a scene + Persist + 1 + Type + S32 + Value + -1 + + RenderComplexityColorMin + + Comment + Max visual complexity of avatars in a scene + Persist + 1 + Type + Color4 + Value + + 0.0 + 0.0 + 1.0 + 0.5 + + + RenderComplexityColorMid + + Comment + Max visual complexity of avatars in a scene + Persist + 1 + Type + Color4 + Value + + 0.0 + 1.0 + 0.0 + 0.5 + + + RenderComplexityColorMax + + Comment + Max visual complexity of avatars in a scene + Persist + 1 + Type + Color4 + Value + + 1.0 + 0.0 + 0.0 + 0.5 + + + RenderComplexityThreshold + + Comment + Only color objects higher than render threshold + Persist + 1 + Type + S32 + Value + -1 + + RenderComplexityStaticMax + + Comment + Sets a static max value for scaling of RenderComplexity + display (-1 for dynamic scaling) + Persist + 1 + Type + S32 + Value + -1 + + RenderAvatarLODFactor + + Comment + Controls level of detail of avatars (multiplier for current screen area when calculated level of detail) + Persist + 1 + Type + F32 + Value + 0.5 + + RenderAvatarMaxVisible + + Comment + Maximum number of avatars to display at any one time + Persist + 1 + Type + S32 + Value + 12 + + RenderAvatarPhysicsLODFactor + + Comment + Controls level of detail of avatar physics (such as breast physics). + Persist + 1 + Type + F32 + Value + 1.0 + + RenderAvatarInvisible + + Comment + Set your avatar as Invisible + Persist + 0 + Type + Boolean + Value + 0 + + RenderAvatarVP + + Comment + Use vertex programs to perform hardware skinning of avatar + Persist + 1 + Type + Boolean + Value + 1 + + RenderCompressTextures + + Comment + Enable texture compression on OpenGL 2.1 and later implementations (requires restart) + Persist + 1 + Type + Boolean + Value + 0 + + RenderPerformanceTest + + Comment + + Disable rendering of everything but in-world content for + performance testing + + Persist + 1 + Type + Boolean + Value + 0 + + + RenderLocalLights + + Comment + Whether or not to render local lights. + Persist + 1 + Type + Boolean + Value + 1 + + + RenderShadowNearDist + + Comment + Near clip plane of shadow camera (affects precision of depth shadows). + Persist + 1 + Type + Vector3 + Value + + 256 + 256 + 256 + + + RenderShadowClipPlanes + + Comment + Near clip plane split distances for shadow map frusta. + Persist + 1 + Type + Vector3 + Value + + 1.0 + 12.0 + 32.0 + + + RenderShadowSplitExponent + + Comment + Near clip plane split distances for shadow map frusta (x=perspective, y=ortho, z=transition rate). + Persist + 1 + Type + Vector3 + Value + + 3.0 + 3.0 + 2.0 + + + RenderShadowOrthoClipPlanes + + Comment + Near clip plane split distances for orthographic shadow map frusta. + Persist + 1 + Type + Vector3 + Value + + 4.0 + 8.0 + 24.0 + + + RenderShadowProjOffset + + Comment + Amount to scale distance to virtual origin of shadow perspective projection. + Persist + 1 + Type + F32 + Value + 2.0 + + RenderShadowSlopeThreshold + + Comment + Cutoff slope value for points to affect perspective shadow generation + Persist + 1 + Type + F32 + Value + 0.0 + + RenderShadowProjExponent + + Comment + Exponent applied to transition between ortho and perspective shadow projections based on viewing angle and light vector. + Persist + 1 + Type + F32 + Value + 0.5 + + RenderSSAOScale + + Comment + Scaling factor for the area to sample for occluders (pixels at 1 meter away, inversely varying with distance) + Persist + 1 + Type + F32 + Value + 1500.0 + + RenderSSAOMaxScale + + Comment + Maximum screen radius for sampling (pixels) + Persist + 1 + Type + U32 + Value + 250 + + RenderSSAOFactor + + Comment + Occlusion sensitivity factor for ambient occlusion (larger is more) + Persist + 1 + Type + F32 + Value + 5.0 + + RenderSSAOEffect + + Comment + Multiplier for (1) value and (2) saturation (HSV definition), for areas which are totally occluded. Blends with original color for partly-occluded areas. (Third component is unused.) + Persist + 1 + Type + Vector3 + Value + + 0.50 + 1.00 + 0.00 + + + RenderBumpmapMinDistanceSquared + + Comment + Maximum distance at which to render bumpmapped primitives (distance in meters, squared) + Persist + 1 + Type + F32 + Value + 100.0 + + RenderNormalMapScale + + Comment + Scaler applied to height map when generating normal maps + Persist + 1 + Type + F32 + Value + 64 + + RenderCubeMap + + Comment + Whether we can render the cube map or not + Persist + 1 + Type + Boolean + Value + 1 + + RenderCustomSettings + + Comment + Do you want to set the graphics settings yourself + Persist + 1 + Type + Boolean + Value + 1 + + RenderDebugGL + + Comment + Enable strict GL debugging. + Persist + 1 + Type + Boolean + Value + 0 + + RenderDebugNormalScale + + Comment + Scale of normals in debug display. + Persist + 1 + Type + F32 + Value + 0.03 + + RenderDebugPipeline + + Comment + Enable strict pipeline debugging. + Persist + 1 + Type + Boolean + Value + 0 + + RenderMaxTextureIndex + + Comment + Maximum texture index to use for indexed texture rendering. + Persist + 1 + Type + U32 + Value + 16 + + RenderDebugTextureBind + + Comment + Enable texture bind performance test. + Persist + 1 + Type + Boolean + Value + 0 + + RenderDelayCreation + + Comment + Throttle creation of drawables. + Persist + 1 + Type + Boolean + Value + 0 + + + RenderAnimateRes + + Comment + Animate rezing prims. + Persist + 1 + Type + Boolean + Value + 0 + + + RenderBakeSunlight + + Comment + Bake sunlight into vertex buffers for static objects. + Persist + 1 + Type + Boolean + Value + 0 + + + RenderAnimateTrees + + Comment + Use GL matrix ops to animate tree branches. + Persist + 1 + Type + Boolean + Value + 0 + + RenderNoAlpha + + Comment + Disable rendering of alpha objects (render all alpha objects as alpha masks). + Persist + 1 + Type + Boolean + Value + 0 + + + + RenderEdgeDepthCutoff + + Comment + Cutoff for depth difference that amounts to an edge. + Persist + 1 + Type + F32 + Value + 0.01 + + RenderEdgeNormCutoff + + Comment + Cutoff for normal difference that amounts to an edge. + Persist + 1 + Type + F32 + Value + 0.25 + + + RenderDeferredAlphaSoften + + Comment + Scalar for softening alpha surfaces (for soft particles). + Persist + 1 + Type + F32 + Value + 0.75 + + RenderDeferredNoise + + Comment + Noise scalar to hide banding in deferred render. + Persist + 1 + Type + F32 + Value + 4 + + RenderDeferredSpotShadowBias + + Comment + Bias value for spot shadows (prevent shadow acne). + Persist + 1 + Type + F32 + Value + -64.0 + + RenderDeferredSpotShadowOffset + + Comment + Offset value for spot shadows (prevent shadow acne). + Persist + 1 + Type + F32 + Value + 0.8 + + + RenderShadowBias + + Comment + Bias value for shadows (prevent shadow acne). + Persist + 1 + Type + F32 + Value + -0.008 + + RenderShadowOffset + + Comment + Offset value for shadows (prevent shadow acne). + Persist + 1 + Type + F32 + Value + 0.01 + + RenderShadowBiasError + + Comment + Error scale for shadow bias (based on altitude). + Persist + 1 + Type + F32 + Value + 0 + + RenderShadowOffsetError + + Comment + Error scale for shadow offset (based on altitude). + Persist + 1 + Type + F32 + Value + 0 + + + RenderDepthPrePass + + Comment + EXPERIMENTAL: Prime the depth buffer with simple prim geometry before rendering with textures. + Persist + 1 + Type + Boolean + Value + 0 + + + RenderDepthOfField + + Comment + Whether to use depth of field effect when lighting and shadows are enabled + Persist + 1 + Type + Boolean + Value + 0 + + + CameraDoFResScale + + Comment + Amount to scale down depth of field resolution. Valid range is 0.25 (quarter res) to 1.0 (full res) + Persist + 1 + Type + F32 + Value + 0.7 + + + RenderSpotLightsInNondeferred + + Comment + Whether to support projectors as spotlights when Lighting and Shadows is disabled Persist 1 Type @@ -12466,13 +13579,13 @@ This should be as low as possible, but too low may break functionality Type F32 Value - 384 + 368.0 RenderDeferred Comment - Use deferred rendering pipeline. + Use deferred rendering pipeline (Advanced Lighting Model). Persist 1 Type @@ -12585,126 +13698,508 @@ This should be as low as possible, but too low may break functionality Value 1.0 - 2.0 + 2.0 + 0.0 + + + + RenderShadowBlurSize + + Comment + Scale of shadow softening kernel. + Persist + 1 + Type + F32 + Value + 3.0 + + RenderShadowBlurSamples + + Comment + Number of samples to take for each pass of shadow blur (value range 1-16). Actual number of samples is value * 2 - 1. + Persist + 1 + Type + U32 + Value + 4 + + RenderShadowBlurDistFactor + + Comment + Distance scaler for shadow blur. + Persist + 1 + Type + F32 + Value + 0.1 + + + RenderDynamicLOD + + Comment + Dynamically adjust level of detail. + Persist + 1 + Type + Boolean + Value + 1 + + RenderFSAASamples + + Comment + Number of samples to use for FSAA (0 = no AA). + Persist + 1 + Type + U32 + Value + 0 + + RenderFarClip + + Comment + Distance of far clip plane from camera (meters) + Persist + 1 + Type + F32 + Value + 256.0 + + SavedRenderFarClip + + Comment + Saved draw distance (used in case of logout during speed rezzing) + Persist + 1 + Type + F32 + Value + 0.0 + + SpeedRez + + Comment + Set to TRUE to increase rezzing speed via draw distance stepping + Persist + 1 + Type + Boolean + Value + 0 + + SpeedRezInterval + + Comment + Interval in seconds between each draw distance increment + Persist + 1 + Type + U32 + Value + 20 + + RenderAutoMaskAlphaNonDeferred + + Comment + Use alpha masks where appropriate, in the non-deferred (non-'Lighting and Shadows') graphics mode + Persist + 1 + Type + Boolean + Value + 1 + + RenderAutoMaskAlphaDeferred + + Comment + Use alpha masks where appropriate, in the deferred ('Lighting and Shadows') graphics mode + Persist + 1 + Type + Boolean + Value + 1 + + RenderFlexTimeFactor + + Comment + Controls level of detail of flexible objects (multiplier for amount of time spent processing flex objects) + Persist + 1 + Type + F32 + Value + 1.0 + + RenderFogRatio + + Comment + Distance from camera where fog reaches maximum density (fraction or multiple of far clip distance) + Persist + 1 + Type + F32 + Value + 4.0 + + RenderGamma + + Comment + Sets gamma exponent for renderer + Persist + 1 + Type + F32 + Value + 0.0 + + RenderGammaFull + + Comment + Use fully controllable gamma correction, instead of faster, hard-coded gamma correction of 2. + Persist + 1 + Type + Boolean + Value + 1.0 + + RenderGLCoreProfile + + Comment + Don't use a compatibility profile OpenGL context. Requires restart. Basic shaders MUST be enabled. + Persist + 1 + Type + Boolean + Value + 0 + + RenderGlow + + Comment + Render bloom post effect. + Persist + 1 + Type + Boolean + Value + 1 + + RenderGlowIterations + + Comment + Number of times to iterate the glow (higher = wider and smoother but slower) + Persist + 1 + Type + S32 + Value + 2 + + RenderGlowLumWeights + + Comment + Weights for each color channel to be used in calculating luminance (should add up to 1.0) + Persist + 1 + Type + Vector3 + Value + + 0.299 + 0.587 + 0.114 + + + RenderGlowMaxExtractAlpha + + Comment + Max glow alpha value for brightness extraction to auto-glow. + Persist + 1 + Type + F32 + Value + 0.065 + + RenderGlowMinLuminance + + Comment + Min luminance intensity necessary to consider an object bright enough to automatically glow. + Persist + 1 + Type + F32 + Value + 2.5 + + RenderGlowResolutionPow + + Comment + Glow map resolution power of two. + Persist + 1 + Type + S32 + Value + 9 + + RenderGlowStrength + + Comment + Additive strength of glow. + Persist + 1 + Type + F32 + Value + 0.35 + + RenderGlowWarmthAmount + + Comment + Amount of warmth extraction to use (versus luminance extraction). 0 = lum, 1.0 = warmth + Persist + 1 + Type + F32 + Value 0.0 - - - - RenderShadowBlurSize - - Comment - Scale of shadow softening kernel. - Persist - 1 - Type - F32 - Value - 3.0 - - RenderShadowBlurSamples - - Comment - Number of samples to take for each pass of shadow blur (value range 1-16). Actual number of samples is value * 2 - 1. - Persist - 1 - Type - U32 - Value - 4 - - RenderShadowBlurDistFactor - - Comment - Distance scaler for shadow blur. - Persist - 1 - Type - F32 - Value - 0.1 - - - RenderDynamicLOD + + RenderGlowWarmthWeights + + Comment + Weight of each color channel used before finding the max warmth + Persist + 1 + Type + Vector3 + Value + + 1.0 + 0.5 + 0.7 + + + RenderGlowWidth + + Comment + Glow sample size (higher = wider and softer but eventually more pixelated) + Persist + 1 + Type + F32 + Value + 1.3 + + RenderGround + + Comment + Determines whether we can render the ground pool or not + Persist + 1 + Type + Boolean + Value + 1 + + DisableAllRenderTypes + + Comment + Disables all rendering types. + Persist + 0 + Type + Boolean + Value + 0 + + DisableAllRenderFeatures + + Comment + Disables all rendering features. + Persist + 0 + Type + Boolean + Value + 0 + + RenderHUDInSnapshot + + Comment + Display HUD attachments in snapshot + Persist + 1 + Type + Boolean + Value + 0 + + RenderHUDParticles + + Comment + Display particle systems in HUD attachments (experimental) + Persist + 1 + Type + Boolean + Value + 0 + + RenderHighlightSelections + + Comment + Show selection outlines on objects + Persist + 0 + Type + Boolean + Value + 1 + + RenderHiddenSelections + + Comment + Show selection lines on objects that are behind other objects + Persist + 1 + Type + Boolean + Value + 0 + + RenderHideGroupTitle + + Comment + Don't show my group title in my name label + Persist + 1 + Type + Boolean + Value + 0 + + RenderHideGroupTitleAll Comment - Dynamically adjust level of detail. + Show group titles in name labels Persist 1 Type Boolean Value + 0 + + RenderInitError + + Comment + Error occured while initializing GL + Persist 1 + Type + Boolean + Value + 0 - RenderFSAASamples + RenderLightRadius Comment - Number of samples to use for FSAA (0 = no AA). + Render the radius of selected lights Persist 1 Type - U32 + Boolean Value 0 - RenderFarClip + RenderMaxPartCount Comment - Distance of far clip plane from camera (meters) + Maximum number of particles to display on screen Persist 1 Type - F32 + S32 Value - 256.0 + 4096 - SavedRenderFarClip + RenderMaxNodeSize Comment - Saved draw distance (used in case of logout during speed rezzing) + Maximum size of a single node's vertex data (in KB). Persist 1 Type - F32 + S32 Value - 0.0 + 65536 - SpeedRez + RenderMaxVBOSize Comment - Set to TRUE to increase rezzing speed via draw distance stepping + Maximum size of a vertex buffer (in KB). Persist 1 Type - Boolean + S32 Value - 0 + 512 - SpeedRezInterval + RenderName Comment - Interval in seconds between each draw distance increment + Controls display of names above avatars (0 = never, 1 = fade, 2 = always) Persist 1 Type - U32 + S32 Value - 20 + 2 - RenderAutoMaskAlphaNonDeferred + RenderNameFadeDuration Comment - Use alpha masks where appropriate, in the non-deferred (non-'Lighting and Shadows') graphics mode + Time interval over which to fade avatar names (seconds) + Persist + 1 + Type + F32 + Value + 1.0 + + RenderNameHideSelf + + Comment + Don't display own name above avatar Persist 1 Type Boolean Value + 0 + + RenderNameShowTime + + Comment + Fade avatar names after specified time (seconds) + Persist 1 + Type + F32 + Value + 10.0 - RenderAutoMaskAlphaDeferred + RenderObjectBump Comment - Use alpha masks where appropriate, in the deferred ('Lighting and Shadows') graphics mode + Show bumpmapping on primitives Persist 1 Type @@ -12712,76 +14207,76 @@ This should be as low as possible, but too low may break functionality Value 1 - RenderFlexTimeFactor + SpecifiedChannel Comment - Controls level of detail of flexible objects (multiplier for amount of time spent processing flex objects) + What the viewer identifies itself as Persist 1 Type - F32 + String Value - 1.0 + AscentViewer - RenderFogRatio + SpecifiedVersionMaj Comment - Distance from camera where fog reaches maximum density (fraction or multiple of far clip distance) + Client's Major Version Persist 1 Type - F32 + U32 Value - 4.0 + 1 - RenderGamma + SpecifiedVersionMin Comment - Sets gamma exponent for renderer + Client's Minor Version Persist 1 Type - F32 + U32 Value - 0.0 + 4 - RenderGammaFull + SpecifiedVersionPatch Comment - Use fully controllable gamma correction, instead of faster, hard-coded gamma correction of 2. + Client's Patch Version Persist 1 Type - Boolean + U32 Value - 1.0 + 0 - RenderGLCoreProfile + SpecifiedVersionBuild Comment - Don't use a compatibility profile OpenGL context. Requires restart. Basic shaders MUST be enabled. + Client's Build Version Persist 1 Type - Boolean + U32 Value - 0 + 100000 - RenderGlow + RenderQualityPerformance Comment - Render bloom post effect. + Which graphics settings you've chosen Persist 1 Type - Boolean + U32 Value 1 - RenderGlowIterations + RenderReflectionDetail Comment - Number of times to iterate the glow (higher = wider and smoother but slower) + Detail of reflection render pass. Persist 1 Type @@ -12789,139 +14284,154 @@ This should be as low as possible, but too low may break functionality Value 2 - RenderGlowLumWeights + RenderShadowDetail Comment - Weights for each color channel to be used in calculating luminance (should add up to 1.0) + Detail of shadows. Persist 1 Type - Vector3 + S32 Value - - 0.299 - 0.587 - 0.114 - + 0 - RenderGlowMaxExtractAlpha + + RenderReflectionRes Comment - Max glow alpha value for brightness extraction to auto-glow. + Reflection map resolution. Persist 1 Type - F32 + S32 Value - 0.065 + 64 - RenderGlowMinLuminance + RenderResolutionDivisor Comment - Min luminance intensity necessary to consider an object bright enough to automatically glow. + Divisor for rendering 3D scene at reduced resolution. Persist 1 Type - F32 + U32 Value - 2.5 + 1 - RenderGlowResolutionPow + RenderShaderLightingMaxLevel Comment - Glow map resolution power of two. + Max lighting level to use in the shader (class 3 is default, 2 is less lights, 1 is sun/moon only. Works around shader compiler bugs on certain platforms.) Persist 1 Type S32 Value - 9 + 3 - RenderGlowStrength + RenderShaderLODThreshold Comment - Additive strength of glow. + Fraction of draw distance defining the switch to a different shader LOD Persist 1 Type F32 Value - 0.35 + 1.0 - RenderGlowWarmthAmount + RenderShaderParticleThreshold Comment - Amount of warmth extraction to use (versus luminance extraction). 0 = lum, 1.0 = warmth + Fraction of draw distance to not use shader on particles Persist 1 Type F32 Value - 0.0 + 0.25 - RenderGlowWarmthWeights + RenderSunDynamicRange Comment - Weight of each color channel used before finding the max warmth + Defines what percent brighter the sun is than local point lights (1.0 = 100% brighter. Value should not be less than 0. ). Persist 1 Type - Vector3 + F32 Value - - 1.0 - 0.5 - 0.7 - + 1.0 - RenderGlowWidth + RenderTerrainDetail Comment - Glow sample size (higher = wider and softer but eventually more pixelated) + Detail applied to terrain texturing (0 = none, 1 or 2 = full) Persist 1 Type - F32 + S32 Value - 1.3 + 2 - RenderGround + RenderTerrainLODFactor Comment - Determines whether we can render the ground pool or not + Controls level of detail of terrain (multiplier for current screen area when calculated level of detail) Persist 1 Type - Boolean + F32 Value - 1 + 1.0 - DisableAllRenderTypes + RenderTerrainScale Comment - Disables all rendering types. + Terrain detail texture scale Persist - 0 + 1 Type - Boolean + F32 Value - 0 + 12.0 - DisableAllRenderFeatures + RenderTextureMemoryMultiple Comment - Disables all rendering features. + Multiple of texture memory value to use (should fit: 0 < value <= 1.0) Persist - 0 + 1 + Type + F32 + Value + 1.0 + + RenderTransparentWater + + Comment + Render water as transparent. Setting to false renders water as opaque with a simple texture applied. + Persist + 1 Type Boolean Value - 0 + 1 + + RenderTreeLODFactor + + Comment + Controls level of detail of vegetation (multiplier for current screen area when calculated level of detail) + Persist + 1 + Type + F32 + Value + 0.5 - RenderHUDInSnapshot + RenderUIInSnapshot Comment - Display HUD attachments in snapshot + Display user interface in snapshot Persist 1 Type @@ -12929,10 +14439,10 @@ This should be as low as possible, but too low may break functionality Value 0 - RenderHUDParticles + RenderUnloadedAvatar Comment - Display particle systems in HUD attachments (experimental) + Show avatars which haven't finished loading Persist 1 Type @@ -12940,21 +14450,21 @@ This should be as low as possible, but too low may break functionality Value 0 - RenderHighlightSelections + RenderUseFBO Comment - Show selection outlines on objects + Whether we want to use GL_EXT_framebuffer_objects. Persist - 0 + 1 Type Boolean Value - 1 + 0 - RenderHiddenSelections + RenderUseFarClip Comment - Show selection lines on objects that are behind other objects + If false, frustum culling will ignore far clip plane. Persist 1 Type @@ -12962,32 +14472,102 @@ This should be as low as possible, but too low may break functionality Value 1 - RenderHideGroupTitle + RenderUseImpostors Comment - Don't show my group title in my name label + Whether we want to use impostors for far away avatars. Persist 1 Type Boolean Value - 0 + 1 - RenderHideGroupTitleAll + RenderAutoMuteByteLimit + + Comment + If avatar attachment size exceed this value (in bytes) attachment will not be rendered. Excludes attachments worn by own avatar. + Persist + 1 + Type + U32 + Value + 0 + + MaxAttachmentComplexity + + Comment + Attachment's render weight limit + Persist + 1 + Type + F32 + Value + 1.0E6 + + RenderAvatarMaxComplexity + + Comment + Maximum Avatar Complexity; above this value, the avatar is + rendered as a solid color outline (0 to disable this limit). + Persist + 1 + Type + U32 + Value + 0 + + RenderAutoMuteSurfaceAreaLimit + + Comment + Maximum surface area of attachments before an avatar is + rendered as a simple impostor (to not use this limit, set to zero + or set RenderAvatarMaxComplexity to zero). + Persist + 1 + Type + F32 + Value + 0 + + RenderAutoMuteLogging + + Comment + Show extra information in viewer logs about avatar rendering costs + Persist + 1 + Type + Boolean + Value + 0 + + RenderAutoHideSurfaceAreaLimit + + Comment + Maximum surface area of a set of proximal objects inworld before automatically hiding geometry to prevent system overload. + Persist + 1 + Type + F32 + Value + 0 + + + RenderVBOEnable Comment - Show group titles in name labels + Use GL Vertex Buffer Objects Persist 1 Type Boolean Value - 0 + 1 - RenderInitError + RenderUseVAO Comment - Error occured while initializing GL + [EXPERIMENTAL] Use GL Vertex Array Objects Persist 1 Type @@ -12995,76 +14575,98 @@ This should be as low as possible, but too low may break functionality Value 0 - RenderLightRadius + RenderUseTransformFeedback + + Comment + [EXPERIMENTAL] Use transform feedback shaders for LoD updates + Persist + 1 + Type + Boolean + Value + 0 + + RenderVBOMappingDisable Comment - Render the radius of selected lights + Disable VBO glMapBufferARB Persist 1 Type Boolean Value - 0 + 1 - RenderMaxPartCount + RenderPreferStreamDraw + + Comment + Use GL_STREAM_DRAW in place of GL_DYNAMIC_DRAW + Persist + 1 + Type + Boolean + Value + 0 + + RenderVolumeLODFactor Comment - Maximum number of particles to display on screen + Controls level of detail of primitives (multiplier for current screen area when calculated level of detail) Persist 1 Type - S32 + F32 Value - 4096 + 1.0 - RenderMaxNodeSize + RenderWater Comment - Maximum size of a single node's vertex data (in KB). + Display water Persist 1 Type - S32 + Boolean Value - 65536 + 1 - RenderMaxVBOSize + RenderWaterMipNormal Comment - Maximum size of a vertex buffer (in KB). + Use mip maps for water normal map. Persist 1 Type - S32 + Boolean Value - 512 + 1 - RenderName + RenderWaterRefResolution Comment - Controls display of names above avatars (0 = never, 1 = fade, 2 = always) + Water planar reflection resolution. Persist 1 Type S32 Value - 2 + 512 - RenderNameFadeDuration + RenderParcelSelection Comment - Time interval over which to fade avatar names (seconds) + Display selected parcel outline Persist 1 Type - F32 + Boolean Value - 1.0 + 1 - RenderNameHideSelf + RevokePermsOnStandUp Comment - Don't display own name above avatar + When enabled, revokes any permission granted to an object you don't own and from which your avatar is standing up Persist 1 Type @@ -13072,21 +14674,10 @@ This should be as low as possible, but too low may break functionality Value 0 - RenderNameShowTime - - Comment - Fade avatar names after specified time (seconds) - Persist - 1 - Type - F32 - Value - 10.0 - - RenderObjectBump + RevokePermsOnStopAnimation Comment - Show bumpmapping on primitives + Clear animation permssions when choosing "Stop Animating Me" Persist 1 Type @@ -13094,242 +14685,242 @@ This should be as low as possible, but too low may break functionality Value 1 - SpecifiedChannel + RotateRight Comment - What the viewer identifies itself as + Make the agent rotate to its right. Persist 1 Type - String + Boolean Value - AscentViewer + 0 - SpecifiedVersionMaj + RotationStep Comment - Client's Major Version + All rotations via rotation tool are constrained to multiples of this unit (degrees) Persist 1 Type - U32 + F32 Value - 1 + 1.0 - SpecifiedVersionMin + MeshTriangleBudget + + Comment + Target visible triangle budget to use when estimating streaming cost. + Persist + 1 + Type + U32 + Value + 250000 + + MeshMetaDataDiscount + + Comment + Number of bytes to deduct for metadata when determining streaming cost. + Persist + 1 + Type + U32 + Value + 384 + + MeshMinimumByteSize + + Comment + Minimum number of bytes per LoD block when determining streaming cost. + Persist + 1 + Type + U32 + Value + 16 + + MeshBytesPerTriangle + + Comment + Approximation of bytes per triangle to use for determining mesh streaming cost. + Persist + 1 + Type + U32 + Value + 16 + + + MeshMaxConcurrentRequests + + Comment + Number of threads to use for loading meshes. + Persist + 1 + Type + U32 + Value + 32 + + RunBtnState + + Comment + + Persist + 0 + Type + Boolean + Value + 0 + + RunMultipleThreads Comment - Client's Minor Version + If TRUE keep background threads active during render Persist 1 Type - U32 + Boolean Value - 4 + 1 - SpecifiedVersionPatch + SafeMode Comment - Client's Patch Version + Reset preferences, run in safe mode. Persist 1 Type - U32 + Boolean Value 0 - SpecifiedVersionBuild + SaveInventoryScriptsAsMono Comment - Client's Build Version + When editing and saving a script in inventory, configure it to compile as mono when dragged into a task Persist 1 Type - U32 + Boolean Value - 100000 + 0 - RenderQualityPerformance + SaveMinidump Comment - Which graphics settings you've chosen + Save minidump for developer debugging on crash Persist 1 Type - U32 + Boolean Value 1 - RenderReflectionDetail - - Comment - Detail of reflection render pass. - Persist - 1 - Type - S32 - Value - 2 - - RenderShadowDetail + ShowMapDestinationInChat Comment - Detail of shadows. + Show llMapDestination as slurl in chat Persist 1 Type - S32 + Boolean Value 0 - - RenderReflectionRes - - Comment - Reflection map resolution. - Persist - 1 - Type - S32 - Value - 64 - - RenderResolutionDivisor + DisableScriptTeleportRequest Comment - Divisor for rendering 3D scene at reduced resolution. + Don't allow scripts to pop the map Persist 1 Type - U32 + Boolean Value - 1 + 0 - RenderShaderLightingMaxLevel + DisableClickSit Comment - Max lighting level to use in the shader (class 3 is default, 2 is less lights, 1 is sun/moon only. Works around shader compiler bugs on certain platforms.) + Never sit by clicking a prim Persist 1 Type - S32 + Boolean Value - 3 + 0 - RenderShaderLODThreshold + DisableClickSitOtherOwner Comment - Fraction of draw distance defining the switch to a different shader LOD + Never sit by clicking a prim that isn't owned by you Persist 1 Type - F32 + Boolean Value - 1.0 + 0 - RenderShaderParticleThreshold + PlayIMSound Comment - Fraction of draw distance to not use shader on particles + Play sound when receiving an IM Persist 1 Type - F32 + Boolean Value - 0.25 - - RenderSunDynamicRange - - Comment - Defines what percent brighter the sun is than local point lights (1.0 = 100% brighter. Value should not be less than 0. ). - Persist 1 - Type - F32 - Value - 1.0 - RenderTerrainDetail + IMSoundID Comment - Detail applied to terrain texturing (0 = none, 1 or 2 = full) + UUID of sound to play if PlayIMSound enabled Persist 1 Type - S32 + String Value - 2 + 4c366008-65da-2e84-9b74-f58a392b94c6 - RenderTerrainLODFactor + OpenIMOnTyping Comment - Controls level of detail of terrain (multiplier for current screen area when calculated level of detail) + Open IM tab when typing message received Persist 1 Type - F32 + Boolean Value - 1.0 - - RenderTerrainScale - - Comment - Terrain detail texture scale - Persist 1 - Type - F32 - Value - 12.0 - RenderTextureMemoryMultiple + EnableGestures Comment - Multiple of texture memory value to use (should fit: 0 < value <= 1.0) - Persist - 1 - Type - F32 - Value - 1.0 - - RenderTransparentWater - - Comment - Render water as transparent. Setting to false renders water as opaque with a simple texture applied. + Enables gestures Persist 1 Type Boolean Value 1 - - RenderTreeLODFactor - - Comment - Controls level of detail of vegetation (multiplier for current screen area when calculated level of detail) - Persist - 1 - Type - F32 - Value - 0.5 - RenderUIInSnapshot + DisableAgentUpdates Comment - Display user interface in snapshot + Stops regular agent updates Persist - 1 + 0 Type Boolean Value 0 - RenderUnloadedAvatar + ScaleShowAxes Comment - Show avatars which haven't finished loading + Show indicator of selected scale axis when scaling Persist 1 Type @@ -13337,78 +14928,43 @@ This should be as low as possible, but too low may break functionality Value 0 - RenderUseFBO + RectangleSelectOverlap Comment - Whether we want to use GL_EXT_framebuffer_objects. + Selection box works as long as it remotely touches or something Persist - 1 + 0 Type Boolean Value 0 - RenderUseFarClip + InterceptorAffectYours Comment - If false, frustum culling will ignore far clip plane. + Controls whether the interceptor stops your own objects too Persist 1 Type Boolean Value - 1 + 0 - RenderUseImpostors + InterceptorRange Comment - Whether we want to use impostors for far away avatars. + Controls the range of the interceptor effect Persist 1 Type - Boolean + F32 Value - 1 + 10.0 - RenderAutoMuteByteLimit - - Comment - Maximum bytes of attachments before an avatar is automatically visually muted (0 for no limit). - Persist - 1 - Type - U32 - Value - 0 - - RenderAutoMuteSurfaceAreaLimit - - Comment - Maximum surface area of attachments before an avatar is automatically visually muted (0 for no limit). - Persist - 1 - Type - F32 - Value - 0 - - - RenderAutoHideSurfaceAreaLimit - - Comment - Maximum surface area of a set of proximal objects inworld before automatically hiding geometry to prevent system overload. - Persist - 1 - Type - F32 - Value - 0 - - - RenderVBOEnable + ScaleStretchTextures Comment - Use GL Vertex Buffer Objects + Stretch textures along with object when scaling Persist 1 Type @@ -13416,10 +14972,10 @@ This should be as low as possible, but too low may break functionality Value 1 - RenderUseVAO + ScaleUniform Comment - [EXPERIMENTAL] Use GL Vertex Array Objects + Scale selected objects evenly about center of selection Persist 1 Type @@ -13427,98 +14983,100 @@ This should be as low as possible, but too low may break functionality Value 0 - RenderUseTransformFeedback - - Comment - [EXPERIMENTAL] Use transform feedback shaders for LoD updates - Persist - 1 - Type - Boolean - Value - 0 - - RenderVBOMappingDisable + ScriptErrorColor Comment - Disable VBO glMapBufferARB + Color of script error messages Persist 1 Type - Boolean + Color4 Value - 1 + + 0.8235294117 + 0.2745098039 + 0.2745098039 + 1.0 + - RenderPreferStreamDraw - - Comment - Use GL_STREAM_DRAW in place of GL_DYNAMIC_DRAW - Persist - 1 - Type - Boolean - Value - 0 - - RenderVolumeLODFactor + ScriptErrorsAsChat Comment - Controls level of detail of primitives (multiplier for current screen area when calculated level of detail) + Display script errors and warning in chat history Persist 1 Type - F32 + Boolean Value - 1.0 + 0 - RenderWater + ScriptHelpFollowsCursor Comment - Display water + Scripting help window updates contents based on script editor contents under text cursor Persist 1 Type Boolean Value - 1 + 0 - RenderWaterMipNormal + SearchURLDefault Comment - Use mip maps for water normal map. + URL to load for empty searches Persist 1 + HideFromEditor + 1 Type - Boolean + String Value - 1 + http://search.secondlife.com/client_search.php? - RenderWaterRefResolution + SearchURLDefaultOpenSim + + Comment + URL to load for empty OpenSim searches + Persist + 1 + HideFromEditor + 0 + Type + String + Value + http://webi.metaverseink.com/opensim/results.jsp? + + SearchURLQuery Comment - Water planar reflection resolution. + URL to use for searches Persist 1 + HideFromEditor + 1 Type - S32 + String Value - 512 + http://search.secondlife.com/client_search.php?q=[QUERY]&s=[COLLECTION]& - RenderParcelSelection + SearchURLSuffix2 Comment - Display selected parcel outline + Parameters added to end of search queries Persist 1 + HideFromEditor + 1 Type - Boolean + String Value - 1 + lang=[LANG]&mat=[MATURITY]&t=[TEEN]&region=[REGION]&x=[X]&y=[Y]&z=[Z]&session=[SESSION] - RotateRight + SelectMovableOnly Comment - Make the agent rotate to its right. + Select only objects you can move Persist 1 Type @@ -13526,231 +15084,164 @@ This should be as low as possible, but too low may break functionality Value 0 - RotationStep + SelectOwnedOnly Comment - All rotations via rotation tool are constrained to multiples of this unit (degrees) + Select only objects you own Persist 1 Type - F32 + Boolean Value - 1.0 + 0 - MeshTriangleBudget - - Comment - Target visible triangle budget to use when estimating streaming cost. - Persist - 1 - Type - U32 - Value - 250000 - - MeshMetaDataDiscount - - Comment - Number of bytes to deduct for metadata when determining streaming cost. - Persist - 1 - Type - U32 - Value - 384 - - MeshMinimumByteSize - - Comment - Minimum number of bytes per LoD block when determining streaming cost. - Persist - 1 - Type - U32 - Value - 16 - - MeshBytesPerTriangle - - Comment - Approximation of bytes per triangle to use for determining mesh streaming cost. - Persist - 1 - Type - U32 - Value - 16 - - - MeshMaxConcurrentRequests - - Comment - Number of threads to use for loading meshes. - Persist - 1 - Type - U32 - Value - 32 - - RunBtnState - - Comment - - Persist - 0 - Type - Boolean - Value - 0 - - RunMultipleThreads + SelectionHighlightAlpha Comment - If TRUE keep background threads active during render + Opacity of selection highlight (0.0 = completely transparent, 1.0 = completely opaque) Persist 1 Type - Boolean + F32 Value - 1 + 0.40000000596 - SafeMode + SelectionHighlightAlphaTest Comment - Reset preferences, run in safe mode. + Alpha value below which pixels are displayed on selection highlight line (0.0 = show all pixels, 1.0 = show now pixels) Persist 1 Type - Boolean + F32 Value - 0 + 0.1 - SaveInventoryScriptsAsMono + SelectionHighlightThickness Comment - When editing and saving a script in inventory, configure it to compile as mono when dragged into a task + Thickness of selection highlight line (fraction of view distance) Persist 1 Type - Boolean + F32 Value - 0 + 0.00999999977648 - SaveMinidump + SelectionHighlightUAnim Comment - Save minidump for developer debugging on crash + Rate at which texture animates along U direction in selection highlight line (fraction of texture per second) Persist 1 Type - Boolean + F32 Value - 1 + 0.0 - ShowMapDestinationInChat + SelectionHighlightUScale Comment - Show llMapDestination as slurl in chat + Scale of texture display on selection highlight line (fraction of texture size) Persist 1 Type - Boolean + F32 Value - 0 + 0.1 - DisableScriptTeleportRequest + SelectionHighlightVAnim Comment - Don't allow scripts to pop the map + Rate at which texture animates along V direction in selection highlight line (fraction of texture per second) Persist 1 Type - Boolean + F32 Value - 0 + 0.5 - DisableClickSit + SelectionHighlightVScale Comment - Never sit by clicking a prim + Scale of texture display on selection highlight line (fraction of texture size) Persist 1 Type - Boolean + F32 Value - 0 + 1.0 - DisableClickSitOtherOwner + ServerChoice Comment - Never sit by clicking a prim that isn't owned by you + [DO NOT MODIFY] Controls which grid you connect to Persist 1 Type - Boolean + S32 Value 0 - PlayIMSound + ShowActiveSpeakers Comment - Play sound when receiving an IM + Display active speakers list on login Persist 1 Type Boolean Value - 1 + 0 - IMSoundID + ShowAllObjectHoverTip Comment - UUID of sound to play if PlayIMSound enabled + Show descriptive tooltip when mouse hovers over non-interactive and interactive objects. Persist 1 Type - String + Boolean Value - 4c366008-65da-2e84-9b74-f58a392b94c6 + 0 - OpenIMOnTyping + ShowAvatarFloater Comment - Open IM tab when typing message received + Display avatar picker floater on login Persist 1 Type Boolean Value - 1 + 0 - EnableGestures + ShowAxes Comment - Enables gestures + Render coordinate frame at your position Persist 1 Type Boolean Value - 1 + 0 - DisableAgentUpdates + ShowBanLines Comment - Stops regular agent updates + Show in-world ban/access borders Persist - 0 + 1 Type Boolean Value - 0 + 1 - ScaleShowAxes + ShowCameraControls Comment - Show indicator of selected scale axis when scaling + Display camera controls on login Persist 1 Type @@ -13758,21 +15249,21 @@ This should be as low as possible, but too low may break functionality Value 0 - RectangleSelectOverlap + ShowChatHistory Comment - Selection box works as long as it remotely touches or something + Open local chat window on login Persist - 0 + 1 Type Boolean Value 0 - InterceptorAffectYours + ShowCommunicate Comment - Controls whether the interceptor stops your own objects too + Open communicate window on login Persist 1 Type @@ -13780,59 +15271,54 @@ This should be as low as possible, but too low may break functionality Value 0 - InterceptorRange + ShowContacts Comment - Controls the range of the interceptor effect + Open contacts window on login Persist 1 Type - F32 + Boolean Value - 10.0 + 0 - ScaleStretchTextures + ShowConsoleWindow Comment - Stretch textures along with object when scaling + Show log in separate OS window Persist 1 Type Boolean Value - 1 + 0 - ScaleUniform + ShowCrosshairs Comment - Scale selected objects evenly about center of selection + Display crosshairs when in mouselook mode Persist 1 Type Boolean Value - 0 + 1 - ScriptErrorColor + ShowDebugConsole Comment - Color of script error messages + Show log in SL window Persist 1 Type - Color4 + Boolean Value - - 0.8235294117 - 0.2745098039 - 0.2745098039 - 1.0 - + 0 - ScriptErrorsAsChat + ShowDebugStats Comment - Display script errors and warning in chat history + Show performance stats display Persist 1 Type @@ -13840,73 +15326,54 @@ This should be as low as possible, but too low may break functionality Value 0 - ScriptHelpFollowsCursor + ShowDirectory Comment - Scripting help window updates contents based on script editor contents under text cursor + Persist - 1 + 0 Type Boolean Value 0 - SearchURLDefault + ShowEmptyFoldersWhenSearching Comment - URL to load for empty searches + Shows folders that do not have any visible contents when applying a filter to inventory Persist 1 - HideFromEditor - 1 Type - String + Boolean Value - http://search.secondlife.com/client_search.php? + 0 - SearchURLDefaultOpenSim - - Comment - URL to load for empty OpenSim searches - Persist - 1 - HideFromEditor - 0 - Type - String - Value - http://webi.metaverseink.com/opensim/results.jsp? - - SearchURLQuery + ShowHoverTips Comment - URL to use for searches + Show descriptive tooltip when mouse hovers over items in world Persist 1 - HideFromEditor - 1 Type - String + Boolean Value - http://search.secondlife.com/client_search.php?q=[QUERY]&s=[COLLECTION]& + 1 - SearchURLSuffix2 + ShowInventory Comment - Parameters added to end of search queries + Open inventory window on login Persist 1 - HideFromEditor - 1 Type - String + Boolean Value - lang=[LANG]&mat=[MATURITY]&t=[TEEN]&region=[REGION]&x=[X]&y=[Y]&z=[Z]&session=[SESSION] + 0 - SelectMovableOnly + ShowLandHoverTip Comment - Select only objects you can move + Show descriptive tooltip when mouse hovers over land Persist 1 Type @@ -13914,230 +15381,266 @@ This should be as low as possible, but too low may break functionality Value 0 - SelectOwnedOnly + ShowLeaders Comment - Select only objects you own + Persist - 1 + 0 Type Boolean Value 0 - SelectionHighlightAlpha + ShowPGSearchAll Comment - Opacity of selection highlight (0.0 = completely transparent, 1.0 = completely opaque) + Display results of search All that are flagged as PG Persist 1 + HideFromEditor + 1 Type - F32 + Boolean Value - 0.40000000596 + 1 - SelectionHighlightAlphaTest + ShowMatureSearchAll Comment - Alpha value below which pixels are displayed on selection highlight line (0.0 = show all pixels, 1.0 = show now pixels) + Display results of search All that are flagged as mature Persist 1 + HideFromEditor + 1 Type - F32 + Boolean Value - 0.1 + 0 - SelectionHighlightThickness + ShowAdultSearchAll Comment - Thickness of selection highlight line (fraction of view distance) + Display results of search All that are flagged as adult Persist 1 + HideFromEditor + 1 Type - F32 + Boolean Value - 0.00999999977648 + 0 - SelectionHighlightUAnim + ShowPGGroups Comment - Rate at which texture animates along U direction in selection highlight line (fraction of texture per second) + Display results of find groups that are flagged as PG Persist 1 + HideFromEditor + 1 Type - F32 + Boolean Value - 0.0 + 1 - SelectionHighlightUScale + ShowMatureGroups Comment - Scale of texture display on selection highlight line (fraction of texture size) + Display results of find groups that are flagged as mature Persist 1 + HideFromEditor + 1 Type - F32 + Boolean Value - 0.1 + 0 - SelectionHighlightVAnim + ShowAdultGroups Comment - Rate at which texture animates along V direction in selection highlight line (fraction of texture per second) + Display results of find groups that are flagged as adult Persist 1 + HideFromEditor + 1 Type - F32 + Boolean Value - 0.5 + 0 - SelectionHighlightVScale + ShowPGClassifieds Comment - Scale of texture display on selection highlight line (fraction of texture size) + Display results of find classifieds that are flagged as PG Persist 1 + HideFromEditor + 1 Type - F32 + Boolean Value - 1.0 + 1 - ServerChoice + ShowMatureClassifieds Comment - [DO NOT MODIFY] Controls which grid you connect to + Display results of find classifieds that are flagged as mature Persist 1 + HideFromEditor + 1 Type - S32 + Boolean Value 0 - ShareWithGroup + ShowAdultClassifieds Comment - Newly created objects are shared with the currently active group + Display results of find classifieds that are flagged as adult Persist 1 + HideFromEditor + 1 Type Boolean Value 0 - ShowActiveSpeakers + ShowPGEvents Comment - Display active speakers list on login + Display results of find events that are flagged as PG Persist 1 + HideFromEditor + 1 Type Boolean Value - 0 + 1 - ShowAllObjectHoverTip + ShowMatureEvents Comment - Show descriptive tooltip when mouse hovers over non-interactive and interactive objects. + Display results of find events that are flagged as mature Persist 1 + HideFromEditor + 1 Type Boolean Value 0 - ShowAxes + ShowAdultEvents Comment - Render coordinate frame at your position + Display results of find events that are flagged as adult Persist 1 + HideFromEditor + 1 Type Boolean Value 0 - ShowBanLines + ShowPGLand Comment - Show in-world ban/access borders + Display results of find land sales that are flagged as PG Persist 1 + HideFromEditor + 1 Type Boolean Value 1 - ShowCameraControls + ShowMatureLand Comment - Display camera controls on login + Display results of find land sales that are flagged as mature Persist 1 + HideFromEditor + 1 Type Boolean Value 0 - ShowChatHistory + ShowAdultLand Comment - + Display results of find land sales that are flagged as adult Persist - 0 + 1 + HideFromEditor + 1 Type Boolean Value 0 - ShowCommunicate + ShowPGSims Comment - + Display results of find places or find popular that are in PG sims Persist - 0 + 1 + HideFromEditor + 1 Type Boolean Value - 0 + 1 - ShowConsoleWindow + ShowMatureSims Comment - Show log in separate OS window + Display results of find places or find popular that are in mature sims Persist 1 + HideFromEditor + 1 Type Boolean Value 0 - ShowCrosshairs + ShowAdultSims Comment - Display crosshairs when in mouselook mode + Display results of find places or find popular that are in adult sims Persist 1 + HideFromEditor + 1 Type Boolean Value - 1 + 0 - ShowDebugConsole + ShowMiniMap Comment - Show log in SL window + Display mini map on login Persist 1 Type Boolean Value - 0 + 1 - ShowDebugStats + ShowMovementControls Comment - Show performance stats display + Display movement controls on login Persist 1 Type @@ -14145,7 +15648,7 @@ This should be as low as possible, but too low may break functionality Value 0 - ShowDirectory + ShowNearClip Comment @@ -14156,21 +15659,21 @@ This should be as low as possible, but too low may break functionality Value 0 - ShowEmptyFoldersWhenSearching + ShowNewInventory Comment - Shows folders that do not have any visible contents when applying a filter to inventory + Automatically views new notecards/textures/landmarks Persist 1 Type Boolean Value - 0 + 1 - ShowHoverTips + ShowInInventory Comment - Show descriptive tooltip when mouse hovers over items in world + Automatically opens inventory to show accepted objects Persist 1 Type @@ -14178,21 +15681,21 @@ This should be as low as possible, but too low may break functionality Value 1 - ShowInventory + ShowObjectUpdates Comment - Open inventory window on login + Show when update messages are received for individual objects Persist - 1 + 0 Type Boolean Value 0 - ShowLandHoverTip + ShowOverlayTitle Comment - Show descriptive tooltip when mouse hovers over land + Prints watermark text message on screen Persist 1 Type @@ -14200,7 +15703,7 @@ This should be as low as possible, but too low may break functionality Value 0 - ShowLeaders + ShowParcelOwners Comment @@ -14211,277 +15714,281 @@ This should be as low as possible, but too low may break functionality Value 0 - ShowPGSearchAll + ShowPermissions Comment - Display results of search All that are flagged as PG + Persist - 1 - HideFromEditor - 1 + 0 Type Boolean Value - 1 + 0 - ShowMatureSearchAll + ShowPropertyLines Comment - Display results of search All that are flagged as mature + Show line overlay demarking property boundaries Persist 1 - HideFromEditor - 1 Type Boolean Value 0 - ShowAdultSearchAll + ShowSearchBar Comment - Display results of search All that are flagged as adult + Show the Search Bar in the Status Overlay Persist 1 - HideFromEditor - 1 Type Boolean Value 0 - ShowPGGroups + ShowSelectionBeam Comment - Display results of find groups that are flagged as PG + Show selection particle beam when selecting or interacting with objects. Persist 1 - HideFromEditor - 1 Type Boolean Value 1 - ShowMatureGroups + ShowStartLocation Comment - Display results of find groups that are flagged as mature + Display starting location menu on login screen Persist 1 - HideFromEditor - 1 Type Boolean Value - 0 + 1 - ShowAdultGroups + ShowTangentBasis Comment - Display results of find groups that are flagged as adult + Render normal and binormal (debugging bump mapping) Persist 1 - HideFromEditor - 1 Type Boolean Value 0 - ShowPGClassifieds + ShowToolBar Comment - Display results of find classifieds that are flagged as PG + Show toolbar at bottom of screen Persist 1 - HideFromEditor - 1 Type Boolean Value 1 - ShowMatureClassifieds + ShowTools Comment - Display results of find classifieds that are flagged as mature + Persist - 1 - HideFromEditor - 1 + 0 Type Boolean Value 0 - ShowAdultClassifieds + ShowTutorial Comment - Display results of find classifieds that are flagged as adult + Show tutorial window on login Persist 1 - HideFromEditor - 1 Type Boolean Value 0 - ShowPGEvents + ShowVoiceChannelPopup Comment - Display results of find events that are flagged as PG + Controls visibility of the current voice channel popup above the voice tab Persist 1 - HideFromEditor - 1 Type Boolean Value - 1 + 0 - ShowMatureEvents + ShowVoiceVisualizersInCalls Comment - Display results of find events that are flagged as mature + Enables in-world voice visualizers, voice gestures and lip-sync while in group or P2P calls. Persist 1 - HideFromEditor - 1 Type Boolean Value 0 - ShowAdultEvents + ShowVolumeSettingsPopup Comment - Display results of find events that are flagged as adult + Show individual volume slider for voice, sound effects, etc Persist 1 - HideFromEditor - 1 Type Boolean Value 0 - ShowPGLand + ShowWorldMap Comment - Display results of find land sales that are flagged as PG + Display world map on login Persist 1 - HideFromEditor - 1 Type Boolean Value - 1 + 0 - ShowMatureLand + ShowXUINames Comment - Display results of find land sales that are flagged as mature + Display XUI Names as Tooltips Persist - 1 - HideFromEditor - 1 + 0 Type Boolean Value 0 - ShowAdultLand + SitBtnState Comment - Display results of find land sales that are flagged as adult + Persist - 1 - HideFromEditor - 1 + 0 Type Boolean Value 0 - ShowPGSims + SkyAmbientScale Comment - Display results of find places or find popular that are in PG sims + Controls strength of ambient, or non-directional light from the sun and moon (fraction or multiple of default ambient level) Persist 1 - HideFromEditor - 1 Type - Boolean + F32 Value - 1 + 0.300000011921 - ShowMatureSims + SkyEditPresets Comment - Display results of find places or find popular that are in mature sims + Whether to be able to edit the sky defaults or not Persist 1 - HideFromEditor - 1 Type Boolean Value 0 - ShowAdultSims + SkyNightColorShift Comment - Display results of find places or find popular that are in adult sims + Controls moonlight color (base color applied to moon as light source) Persist 1 - HideFromEditor - 1 + Type + Color3 + Value + + 0.699999988079 + 0.699999988079 + 1.0 + + + SkyOverrideSimSunPosition + + Comment + + Persist + 0 Type Boolean Value 0 - ShowMiniMap + SkySunDefaultPosition Comment - Display mini map on login + Default position of sun in sky (direction in world coordinates) Persist 1 Type - Boolean + Vector3 Value - 1 + + 1.0 + 0.0 + 0.1 + - ShowMovementControls + SkyUseClassicClouds Comment - Display movement controls on login + Whether to use the old Second Life particle clouds or not Persist 1 Type Boolean Value - 0 + 1 - ShowNearClip + SlideLeftBtnRect Comment Persist 0 Type - Boolean + Rect Value + + 20 + 54 + 45 + 29 + + + SlideRightBtnRect + + Comment + + Persist 0 + Type + Rect + Value + + 66 + 54 + 91 + 29 + - ShowNewInventory + SmallAvatarNames Comment - Automatically views new notecards/textures/landmarks + Display avatar name text in smaller font Persist 1 Type @@ -14489,10 +15996,10 @@ This should be as low as possible, but too low may break functionality Value 1 - ShowInInventory + SnapEnabled Comment - Automatically opens inventory to show accepted objects + Enable snapping to grid Persist 1 Type @@ -14500,21 +16007,21 @@ This should be as low as possible, but too low may break functionality Value 1 - ShowObjectUpdates + SnapMargin Comment - Show when update messages are received for individual objects + Controls maximum distance between windows before they auto-snap together (pixels) Persist - 0 + 1 Type - Boolean + S32 Value - 0 + 10 - ShowOverlayTitle + SnapToMouseCursor Comment - Prints watermark text message on screen + When snapping to grid, center object on nearest grid point to mouse cursor Persist 1 Type @@ -14522,7 +16029,7 @@ This should be as low as possible, but too low may break functionality Value 0 - ShowParcelOwners + SnapshotBtnState Comment @@ -14533,98 +16040,131 @@ This should be as low as possible, but too low may break functionality Value 0 - ShowPermissions + SnapshotFeedLastAspect Comment - + Take next feed snapshot at this aspect Persist 0 Type - Boolean + S32 Value 0 - ShowPropertyLines + SnapshotFeedLastResolution Comment - Show line overlay demarking property boundaries + Take next feed snapshot at this resolution + Persist + 1 + Type + S32 + Value + 0 + + SnapshotFormat + + Comment + Save snapshots in this format (0 = PNG, 1 = JPEG, 2 = BMP) + Persist + 1 + Type + S32 + Value + 0 + + SnapshotLayerType + + Comment + Save snapshots in this format (0 = Colors, 1 = Depth) Persist 1 Type - Boolean + S32 + Value + 0 + + SnapshotLocalLastAspect + + Comment + Take next local snapshot at this aspect + Persist + 0 + Type + S32 Value 0 - ShowSearchBar + SnapshotLocalLastResolution Comment - Show the Search Bar in the Status Overlay + Take next local snapshot at this resolution Persist 1 Type - Boolean + S32 Value 0 - ShowSelectionBeam + SnapshotPostcardLastAspect Comment - Show selection particle beam when selecting or interacting with objects. + Take next postcard snapshot at this aspect Persist - 1 + 0 Type - Boolean + S32 Value - 1 + 0 - ShowStartLocation + SnapshotPostcardLastResolution Comment - Display starting location menu on login screen + Take next postcard snapshot at this resolution Persist 1 Type - Boolean + S32 Value - 1 + 0 - ShowTangentBasis + SnapshotQuality Comment - Render normal and binormal (debugging bump mapping) + Quality setting of postcard JPEGs (0 = worst, 100 = best) Persist 1 Type - Boolean + S32 Value - 0 + 75 - ShowToolBar + SnapshotTextureLastAspect Comment - Show toolbar at bottom of screen + Take next texture snapshot at this aspect Persist - 1 + 0 Type - Boolean + S32 Value - 1 + 0 - ShowTools + SnapshotTextureLastResolution Comment - + Take next texture snapshot at this resolution Persist - 0 + 1 Type - Boolean + S32 Value 0 - ShowTutorial + SnapshotFeedKeepAspect Comment - Show tutorial window on login + When adjusting feed resolution keep its aspect ratio constant and equal to the target aspect. Persist 1 Type @@ -14632,10 +16172,10 @@ This should be as low as possible, but too low may break functionality Value 0 - ShowVoiceChannelPopup + SnapshotPostcardKeepAspect Comment - Controls visibility of the current voice channel popup above the voice tab + When adjusting postcard resolution keep its aspect ratio constant and equal to the target aspect. Persist 1 Type @@ -14643,10 +16183,10 @@ This should be as low as possible, but too low may break functionality Value 0 - ShowVoiceVisualizersInCalls + SnapshotTextureKeepAspect Comment - Enables in-world voice visualizers, voice gestures and lip-sync while in group or P2P calls. + When adjusting texture resolution keep its aspect ratio constant and equal to the target aspect. Persist 1 Type @@ -14654,10 +16194,10 @@ This should be as low as possible, but too low may break functionality Value 0 - ShowVolumeSettingsPopup + SnapshotLocalKeepAspect Comment - Show individual volume slider for voice, sound effects, etc + When adjusting local resolution keep its aspect ratio constant and equal to the target aspect. Persist 1 Type @@ -14665,10 +16205,10 @@ This should be as low as possible, but too low may break functionality Value 0 - ShowWorldMap + SnapshotOpenFreezeTime Comment - Display world map on login + When opening the snapshot floater, immediately freeze time. Persist 1 Type @@ -14676,43 +16216,48 @@ This should be as low as possible, but too low may break functionality Value 0 - ShowXUINames + SpeakingColor Comment - Display XUI Names as Tooltips + Color of various indicators when resident is speaking on a voice channel. Persist - 0 + 1 Type - Boolean + Color4 Value - 0 + + 0.0 + 1.0 + 0.0 + 1.0 + - SitBtnState + SpeedTest Comment - + Performance testing mode, no network Persist - 0 + 1 Type Boolean Value 0 - SkyAmbientScale + StateMachineMaxTime Comment - Controls strength of ambient, or non-directional light from the sun and moon (fraction or multiple of default ambient level) + Maximum time per frame spent executing AIStateMachine objects, in miliseconds Persist 1 Type - F32 + U32 Value - 0.300000011921 + 20 - SkyEditPresets + StatsAutoRun Comment - Whether to be able to edit the sky defaults or not + Play back autopilot Persist 1 Type @@ -14720,127 +16265,109 @@ This should be as low as possible, but too low may break functionality Value 0 - SkyNightColorShift + StatsFile Comment - Controls moonlight color (base color applied to moon as light source) + Filename for stats logging output Persist 1 Type - Color3 + String Value - - 0.699999988079 - 0.699999988079 - 1.0 - + fs.txt - SkyOverrideSimSunPosition + StatsNumRuns Comment - + Loop autopilot playback this number of times Persist - 0 + 1 Type - Boolean + S32 Value - 0 + -1 - SkySunDefaultPosition + StatsPilotFile Comment - Default position of sun in sky (direction in world coordinates) + Filename for stats logging autopilot path Persist 1 Type - Vector3 + String Value - - 1.0 - 0.0 - 0.1 - + pilot.txt - SkyUseClassicClouds + StatsQuitAfterRuns Comment - Whether to use the old Second Life particle clouds or not + Quit application after this number of autopilot playback runs Persist 1 Type Boolean Value - 1 + 0 - SlideLeftBtnRect + StatsSessionTrackFrameStats Comment - + Track rendering and network statistics Persist - 0 + 1 Type - Rect + Boolean Value - - 20 - 54 - 45 - 29 - + 0 - SlideRightBtnRect + StatsSummaryFile Comment - + Filename for stats logging summary Persist - 0 + 1 Type - Rect + String Value - - 66 - 54 - 91 - 29 - + fss.txt - SmallAvatarNames + StatusBarHeight Comment - Display avatar name text in smaller font + Height of menu/status bar at top of screen (pixels) Persist 1 Type - Boolean + S32 Value - 1 + 26 - SnapEnabled + StatusBarPad Comment - Enable snapping to grid + Spacing between popup buttons at bottom of screen (Stand up, Release Controls) Persist 1 Type - Boolean + S32 Value - 1 + 5 - SnapMargin + SystemLanguage Comment - Controls maximum distance between windows before they auto-snap together (pixels) + Language indicated by system settings (for UI) Persist 1 Type - S32 + String Value - 10 + en-us - SnapToMouseCursor + TabToTextFieldsOnly Comment - When snapping to grid, center object on nearest grid point to mouse cursor + TAB key takes you to next text entry field, instead of next widget Persist 1 Type @@ -14848,10 +16375,10 @@ This should be as low as possible, but too low may break functionality Value 0 - SnapshotBtnState + TemporaryUpload Comment - + Whether or not a upload is temporary Persist 0 Type @@ -14859,142 +16386,142 @@ This should be as low as possible, but too low may break functionality Value 0 - SnapshotFeedLastAspect + TerrainColorHeightRange Comment - Take next feed snapshot at this aspect + Altitude range over which a given terrain texture has effect (meters) Persist - 0 + 1 Type - S32 + F32 Value - 0 + 60.0 - SnapshotFeedLastResolution + TerrainColorStartHeight Comment - Take next feed snapshot at this resolution + Starting altitude for terrain texturing (meters) Persist 1 Type - S32 + F32 Value - 0 + 20.0 - SnapshotFormat + TexelPixelRatio Comment - Save snapshots in this format (0 = PNG, 1 = JPEG, 2 = BMP) + texel pixel ratio = texel / pixel Persist 1 Type - S32 + F32 Value - 0 + 1.0 - SnapshotLayerType + TextureCameraMotionThreshold Comment - Save snapshots in this format (0 = Colors, 1 = Depth) + If the overall motion is lower than this value, textures will be loaded faster Persist 1 Type - S32 + F32 Value - 0 + 0.2 - SnapshotLocalLastAspect + TextureCameraMotionBoost Comment - Take next local snapshot at this aspect + Progressive discard level decrement when the camera is still Persist - 0 + 1 Type S32 Value - 0 + 3 - SnapshotLocalLastResolution + TextureDecodeDisabled Comment - Take next local snapshot at this resolution + If TRUE, do not fetch and decode any textures Persist 1 Type - S32 + Boolean Value 0 - SnapshotPostcardLastAspect + TextureDisable Comment - Take next postcard snapshot at this aspect + If TRUE, do not load textures for in-world content Persist - 0 + 1 Type - S32 + Boolean Value 0 - SnapshotPostcardLastResolution + TextureDiscardLevel Comment - Take next postcard snapshot at this resolution + Specify texture resolution (0 = highest, 5 = lowest) Persist 1 Type - S32 + U32 Value 0 - SnapshotQuality + TextureFetchUpdateHighPriority Comment - Quality setting of postcard JPEGs (0 = worst, 100 = best) + Number of high priority textures to update per frame Persist 1 Type S32 Value - 75 + 32 - SnapshotTextureLastAspect + TextureFetchUpdateMaxMediumPriority Comment - Take next texture snapshot at this aspect + Maximum number of medium priority textures to update per frame Persist - 0 + 1 Type S32 Value - 0 + 256 - SnapshotTextureLastResolution + TextureFetchUpdateMinMediumPriority Comment - Take next texture snapshot at this resolution + Minimum number of medium priority textures to update per frame Persist 1 Type S32 Value - 0 + 32 - SnapshotFeedKeepAspect + TextureFetchUpdatePriorityThreshold Comment - When adjusting feed resolution keep its aspect ratio constant and equal to the target aspect. + Threshold under which textures will be considered too low priority and skipped for update Persist 1 Type - Boolean + F32 Value - 0 + 0.0 - SnapshotPostcardKeepAspect + TextureFetchUpdateSkipLowPriority Comment - When adjusting postcard resolution keep its aspect ratio constant and equal to the target aspect. + Flag indicating if we want to skip textures with too low of a priority Persist 1 Type @@ -15002,21 +16529,21 @@ This should be as low as possible, but too low may break functionality Value 0 - SnapshotTextureKeepAspect + TextureFetchUpdatePriorities Comment - When adjusting texture resolution keep its aspect ratio constant and equal to the target aspect. + Number of priority texture to update per frame Persist 1 Type - Boolean + S32 Value - 0 + 32 - SnapshotLocalKeepAspect + TextureLoadFullRes Comment - When adjusting local resolution keep its aspect ratio constant and equal to the target aspect. + If TRUE, always load textures at full resolution (discard = 0) Persist 1 Type @@ -15024,103 +16551,108 @@ This should be as low as possible, but too low may break functionality Value 0 - SnapshotOpenFreezeTime + TextureMemory Comment - When opening the snapshot floater, immediately freeze time. + Amount of memory to use for textures in MB (0 = autodetect) Persist 1 Type - Boolean + S32 Value 0 - SpeakingColor + TexturePickerRect Comment - Color of various indicators when resident is speaking on a voice channel. + Rectangle for texture picker Persist 1 Type - Color4 + Rect Value - 0.0 - 1.0 - 0.0 - 1.0 + 0 + 290 + 350 + 0 - SpeedTest + TexturePickerShowFolders Comment - Performance testing mode, no network + Show folders with no texures in texture picker Persist 1 Type Boolean Value - 0 + 1 - StateMachineMaxTime + TexturePickerSortOrder Comment - Maximum time per frame spent executing AIStateMachine objects, in miliseconds + Specifies sort key for textures in texture picker (+0 = name, +1 = date, +2 = folders always by name, +4 = system folders to top) Persist 1 Type U32 Value - 20 + 2 - StatsAutoRun + ThirdPersonBtnState Comment - Play back autopilot + Persist - 1 + 0 Type Boolean Value - 0 + 1 - StatsFile + ThrottleBandwidthKBPS Comment - Filename for stats logging output + Maximum allowable downstream bandwidth (kilo bits per second) Persist 1 Type - String + F32 Value - fs.txt + 2000.0 - StatsNumRuns + ToolHelpRect Comment - Loop autopilot playback this number of times + Persist - 1 + 0 Type - S32 + Rect Value - -1 + + 8 + 178 + 75 + 162 + - StatsPilotFile + ToolTipDelay Comment - Filename for stats logging autopilot path + Seconds before displaying tooltip when mouse stops over UI element Persist 1 Type - String + F32 Value - pilot.txt + 0.699999988079 - StatsQuitAfterRuns + ToolboxAutoMove Comment - Quit application after this number of autopilot playback runs + [NOT USED] Persist 1 Type @@ -15128,442 +16660,421 @@ This should be as low as possible, but too low may break functionality Value 0 - StatsSessionTrackFrameStats + ToolboxRect Comment - Track rendering and network statistics + Rectangle for tools window Persist 1 Type - Boolean + Rect Value - 0 + + 0 + 100 + 100 + 100 + - StatsSummaryFile + TrackFocusObject Comment - Filename for stats logging summary + Camera tracks last object zoomed on Persist 1 Type - String + Boolean Value - fss.txt + 1 - StatusBarHeight + TurnLeftBtnRect Comment - Height of menu/status bar at top of screen (pixels) + Persist - 1 + 0 Type - S32 + Rect Value - 26 + + 20 + 29 + 45 + 4 + - StatusBarPad + TurnRightBtnRect Comment - Spacing between popup buttons at bottom of screen (Stand up, Release Controls) + Persist - 1 + 0 Type - S32 + Rect Value - 5 + + 66 + 29 + 91 + 4 + - SystemLanguage + TutorialURL Comment - Language indicated by system settings (for UI) + URL for tutorial menu item, set automatically during login Persist - 1 + 0 Type String Value - en-us + - TabToTextFieldsOnly + TypeAheadTimeout Comment - TAB key takes you to next text entry field, instead of next widget + Time delay before clearing type-ahead buffer in lists (seconds) Persist 1 Type - Boolean + F32 Value - 0 + 1.5 - TemporaryUpload + UIAutoScale Comment - Whether or not a upload is temporary + Keep UI scale consistent across different resolutions Persist - 0 + 1 Type Boolean Value - 0 + 1 - TerrainColorHeightRange + UIFloaterTestBool Comment - Altitude range over which a given terrain texture has effect (meters) + Example saved setting for the test floater Persist 1 Type - F32 + Boolean Value - 60.0 + 0 - TerrainColorStartHeight + UIImgDefaultEyesUUID Comment - Starting altitude for terrain texturing (meters) + Persist - 1 + 0 Type - F32 + String Value - 20.0 + 6522e74d-1660-4e7f-b601-6f48c1659a77 - TexelPixelRatio + UIImgDefaultGlovesUUID Comment - texel pixel ratio = texel / pixel + Persist - 1 + 0 Type - F32 + String Value - 1.0 + 5748decc-f629-461c-9a36-a35a221fe21f - TextureCameraMotionThreshold + UIImgDefaultHairUUID Comment - If the overall motion is lower than this value, textures will be loaded faster + Persist - 1 + 0 Type - F32 + String Value - 0.2 + 7ca39b4c-bd19-4699-aff7-f93fd03d3e7b - TextureCameraMotionBoost + UIImgDefaultJacketUUID Comment - Progressive discard level decrement when the camera is still + Persist - 1 + 0 Type - S32 + String Value - 3 + 5748decc-f629-461c-9a36-a35a221fe21f - TextureDecodeDisabled + UIImgDefaultPantsUUID Comment - If TRUE, do not fetch and decode any textures + Persist - 1 + 0 Type - Boolean + String Value - 0 + 5748decc-f629-461c-9a36-a35a221fe21f - TextureDisable + UIImgDefaultShirtUUID Comment - If TRUE, do not load textures for in-world content + Persist - 1 + 0 Type - Boolean + String Value - 0 + 5748decc-f629-461c-9a36-a35a221fe21f - TextureDiscardLevel + UIImgDefaultShoesUUID Comment - Specify texture resolution (0 = highest, 5 = lowest) + Persist - 1 + 0 Type - U32 + String Value - 0 + 5748decc-f629-461c-9a36-a35a221fe21f - TextureFetchUpdateHighPriority + UIImgDefaultSkirtUUID Comment - Number of high priority textures to update per frame + Persist - 1 + 0 Type - S32 + String Value - 32 + 5748decc-f629-461c-9a36-a35a221fe21f - TextureFetchUpdateMaxMediumPriority + UIImgDefaultSocksUUID Comment - Maximum number of medium priority textures to update per frame + Persist - 1 + 0 Type - S32 + String Value - 256 + 5748decc-f629-461c-9a36-a35a221fe21f - TextureFetchUpdateMinMediumPriority + UIImgDefaultAlphaUUID Comment - Minimum number of medium priority textures to update per frame + Persist - 1 + 0 Type - S32 + String Value - 32 + 5748decc-f629-461c-9a36-a35a221fe21f - TextureFetchUpdatePriorityThreshold + UIImgDefaultUnderwearUUID Comment - Threshold under which textures will be considered too low priority and skipped for update + Persist - 1 + 0 Type - F32 + String Value - 0.0 + 5748decc-f629-461c-9a36-a35a221fe21f - TextureFetchUpdateSkipLowPriority + UIImgWhiteUUID Comment - Flag indicating if we want to skip textures with too low of a priority + Persist - 1 + 0 Type - Boolean + String Value - 0 + 5748decc-f629-461c-9a36-a35a221fe21f - TextureFetchUpdatePriorities + UIImgInvisibleUUID Comment - Number of priority texture to update per frame + Persist - 1 + 0 Type - S32 + String Value - 32 + 38b86f85-2575-52a9-a531-23108d8da837 - TextureLoadFullRes + UIScaleFactor Comment - If TRUE, always load textures at full resolution (discard = 0) + Size of UI relative to default layout on 1024x768 screen Persist 1 Type - Boolean + F32 Value - 0 + 1.0 - TextureMemory + UploadBakedTexOld Comment - Amount of memory to use for textures in MB (0 = autodetect) + Forces the baked texture pipeline to upload using the old method. Persist 1 Type - S32 + Boolean Value 0 - TexturePickerRect + UseAltKeyForMenus Comment - Rectangle for texture picker + Access menus via keyboard by tapping Alt Persist 1 Type - Rect + Boolean Value - - 0 - 290 - 350 - 0 - + 0 - TexturePickerShowFolders + UseChatBubbles Comment - Show folders with no texures in texture picker + Show chat above avatars head in chat bubbles Persist 1 Type Boolean Value - 1 + 0 - TexturePickerSortOrder + UseTypingBubbles Comment - Specifies sort key for textures in texture picker (+0 = name, +1 = date, +2 = folders always by name, +4 = system folders to top) + Show typing indicator in avatar nametags Persist 1 Type - U32 + Boolean Value - 2 + 0 - ThirdPersonBtnState + UseDebugMenus Comment - + Turns on "Debug" menu Persist - 0 + 1 Type Boolean Value 1 - ThrottleBandwidthKBPS + UseDefaultColorPicker Comment - Maximum allowable downstream bandwidth (kilo bits per second) + Use color picker supplied by operating system Persist 1 Type - F32 + Boolean Value - 2000.0 + 0 - ToolHelpRect + UseEnergy Comment Persist 0 Type - Rect + Boolean Value - - 8 - 178 - 75 - 162 - - - ToolTipDelay - - Comment - Seconds before displaying tooltip when mouse stops over UI element - Persist 1 - Type - F32 - Value - 0.699999988079 - ToolboxAutoMove + UseEnvironmentFromRegion Comment - [NOT USED] + Choose whether to use the region's environment settings, or override them with the local settings. Persist 1 Type Boolean Value - 0 - - ToolboxRect - - Comment - Rectangle for tools window - Persist 1 - Type - Rect - Value - - 0 - 100 - 100 - 100 - - TrackFocusObject - + UseDayCycle + + Comment + Whether to use use a day cycle or a fixed sky. + Persist + 1 + Type + Boolean + Value + 1 + + WaterPresetName + Comment - Camera tracks last object zoomed on + Water preset to use. May be superseded by region settings. Persist 1 Type - Boolean + String Value - 1 + Default - TurnLeftBtnRect + SkyPresetName Comment - + Sky preset to use. May be superseded by region settings or by a day cycle (see DayCycleName). Persist - 0 + 1 Type - Rect + String Value - - 20 - 29 - 45 - 4 - + Default - TurnRightBtnRect + DayCycleName Comment - + Day cycle to use. May be superseded by region settings. Persist - 0 + 1 Type - Rect + String Value - - 66 - 29 - 91 - 4 - + Default - TutorialURL + UseExternalBrowser Comment - URL for tutorial menu item, set automatically during login + Use default browser when opening web pages instead of in-world browser. Persist - 0 + 1 Type - String + Boolean Value - + 1 - TypeAheadTimeout + UseInventoryLinks Comment - Time delay before clearing type-ahead buffer in lists (seconds) + When making a new outfit, use links for no-copy items Persist 1 Type - F32 + Boolean Value - 1.5 + 1 - UIAutoScale + UseOcclusion Comment - Keep UI scale consistent across different resolutions + Enable object culling based on occlusion (coverage) by other objects Persist 1 Type @@ -15571,10 +17082,21 @@ This should be as low as possible, but too low may break functionality Value 1 - UIFloaterTestBool + RenderSynchronousOcclusion + + Comment + Don't let occlusion queries get more than one frame behind (block until they complete). + Persist + 1 + Type + Boolean + Value + 1 + + SkipReflectOcclusionUpdates Comment - Example saved setting for the test floater + Enable optimization that prevents occlusion updates for refelction pass Persist 1 Type @@ -15582,197 +17104,196 @@ This should be as low as possible, but too low may break functionality Value 0 - UIImgDefaultEyesUUID + UseOutfitFolders Comment - + When making a new outfit, use Viewer 2 outfit folders Persist - 0 + 1 Type - String + Boolean Value - 6522e74d-1660-4e7f-b601-6f48c1659a77 + 1 - UIImgDefaultGlovesUUID + RenderDelayVBUpdate Comment - + Delay vertex buffer updates until just before rendering Persist - 0 + 1 Type - String + Boolean Value - 5748decc-f629-461c-9a36-a35a221fe21f - - UIImgDefaultHairUUID - - Comment - - Persist 0 - Type - String - Value - 7ca39b4c-bd19-4699-aff7-f93fd03d3e7b - UIImgDefaultJacketUUID + SpeakerParticipantDefaultOrder Comment - + Order for displaying speakers in voice controls. 0 = alphabetical. 1 = recent. Persist - 0 + 1 Type - String + U32 Value - 5748decc-f629-461c-9a36-a35a221fe21f + 1 - UIImgDefaultPantsUUID + SpeakerParticipantRemoveDelay Comment - + Timeout to remove participants who is not in channel before removed from list of active speakers (text/voice chat) Persist - 0 + 1 Type - String + F32 Value - 5748decc-f629-461c-9a36-a35a221fe21f + 10.0 - UIImgDefaultShirtUUID + UseNewWalkRun Comment - + Replace standard walk/run animations with new ones. Persist - 0 + 1 Type - String + Boolean Value - 5748decc-f629-461c-9a36-a35a221fe21f + 1 - UIImgDefaultShoesUUID + UseCrossWalkRun Comment - + Use opposite gender walk/run animations. Persist - 0 + 1 Type - String + Boolean Value - 5748decc-f629-461c-9a36-a35a221fe21f + 0 - UIImgDefaultSkirtUUID + UsePeopleAPI + + Comment + Use the people API cap for avatar name fetching, use old legacy protocol if false. Requires restart. + Persist + 1 + Type + Boolean + Value + 1 + + UseStartScreen Comment - + Whether to load a start screen image or not. Persist - 0 + 1 Type - String + Boolean Value - 5748decc-f629-461c-9a36-a35a221fe21f + 1 - UIImgDefaultSocksUUID + UseWebPagesOnPrims Comment - + [NOT USED] Persist - 0 + 1 Type - String + Boolean Value - 5748decc-f629-461c-9a36-a35a221fe21f + 0 - UIImgDefaultAlphaUUID + UserConnectionPort Comment - + Port that this client transmits on. Persist - 0 + 1 Type - String + U32 Value - 5748decc-f629-461c-9a36-a35a221fe21f + 0 - UIImgDefaultUnderwearUUID + UserLogFile Comment - + User specified log file name. Persist - 0 + 1 Type String Value - 5748decc-f629-461c-9a36-a35a221fe21f + - UIImgWhiteUUID + UserLoginInfo Comment - + Users loging data. Persist - 0 + 1 Type - String + LLSD Value - 5748decc-f629-461c-9a36-a35a221fe21f - UIImgInvisibleUUID + VFSOldSize Comment - + [DO NOT MODIFY] Controls resizing of local file cache Persist - 0 + 1 Type - String + U32 Value - 38b86f85-2575-52a9-a531-23108d8da837 + 0 - UIScaleFactor + VFSSalt Comment - Size of UI relative to default layout on 1024x768 screen + [DO NOT MODIFY] Controls local file caching behavior Persist 1 Type - F32 + U32 Value - 1.0 + 1 - UploadBakedTexOld + VelocityInterpolate Comment - Forces the baked texture pipeline to upload using the old method. + Extrapolate object motion from last packet based on received velocity Persist 1 Type Boolean Value - 0 + 1 - UseAltKeyForMenus + InterpolationTime Comment - Access menus via keyboard by tapping Alt + How long to extrapolate object motion after last packet received Persist 1 Type - Boolean + F32 Value - 0 + 3 - UseChatBubbles + InterpolationPhaseOut Comment - Show chat above avatars head in chat bubbles + Seconds to phase out interpolated motion Persist 1 Type - Boolean + F32 Value - 0 + 1 - UseTypingBubbles + VerboseLogs Comment - Show typing indicator in avatar nametags + Display source file and line number for each log item for debugging purposes Persist 1 Type @@ -15780,21 +17301,21 @@ This should be as low as possible, but too low may break functionality Value 0 - UseDebugMenus + VersionChannelName Comment - Turns on "Debug" menu + Versioning Channel Name. Persist 1 Type - Boolean + String Value - 1 + Ascent Viewer Release - UseDefaultColorPicker + VertexShaderEnable Comment - Use color picker supplied by operating system + Enable/disable all GLSL shaders (debug) Persist 1 Type @@ -15802,120 +17323,87 @@ This should be as low as possible, but too low may break functionality Value 0 - UseEnergy - - Comment - - Persist - 0 - Type - Boolean - Value - 1 - - UseEnvironmentFromRegion + VivoxAutoPostCrashDumps Comment - Choose whether to use the region's environment settings, or override them with the local settings. + If true, SLVoice will automatically send crash dumps directly to Vivox. Persist 1 Type Boolean Value - 1 + 0 - UseDayCycle - - Comment - Whether to use use a day cycle or a fixed sky. - Persist - 1 - Type - Boolean - Value - 1 - - WaterPresetName - + VivoxDebugLevel + Comment - Water preset to use. May be superseded by region settings. + Logging level to use when launching the vivox daemon Persist 1 Type String Value - Default + 0 - SkyPresetName + VivoxShutdownTimeout Comment - Sky preset to use. May be superseded by region settings or by a day cycle (see DayCycleName). + shutdown timeout in miliseconds. The amount of time to wait for the service to shutdown gracefully after the last disconnect Persist 1 Type String Value - Default + 5 - DayCycleName + VivoxLogDirectory Comment - Day cycle to use. May be superseded by region settings. + Default log path is Application Support/SecondLife/logs specify alternate absolute path here. Persist 1 Type String Value - Default + - UseExternalBrowser + VivoxDebugSIPURIHostName Comment - Use default browser when opening web pages instead of in-world browser. + Hostname portion of vivox SIP URIs (empty string for the default). Persist 1 Type - Boolean + String Value - 1 + - UseInventoryLinks + VivoxDebugVoiceAccountServerURI Comment - When making a new outfit, use links for no-copy items + URI to the vivox account management server (empty string for the default). Persist 1 Type - Boolean + String Value - 1 + - UseOcclusion + VoiceCallsFriendsOnly Comment - Enable object culling based on occlusion (coverage) by other objects + Only accept voice calls from residents on your friends list Persist 1 Type Boolean Value - 1 + 0 - RenderSynchronousOcclusion - - Comment - Don't let occlusion queries get more than one frame behind (block until they complete). - Persist - 1 - Type - Boolean - Value - 1 - - SkipReflectOcclusionUpdates + InstantMessagesFriendsOnly Comment - Enable optimization that prevents occlusion updates for refelction pass + Only accept instant messages from residents on your friends list Persist 1 Type @@ -15923,21 +17411,21 @@ This should be as low as possible, but too low may break functionality Value 0 - UseOutfitFolders + VoiceCallsRejectGroup Comment - When making a new outfit, use Viewer 2 outfit folders + Silently reject all incoming group voice calls. Persist 1 Type Boolean Value - 1 + 0 - RenderDelayVBUpdate + VoiceDisableMic Comment - Delay vertex buffer updates until just before rendering + Completely disable the ability to open the mic. Persist 1 Type @@ -15945,32 +17433,32 @@ This should be as low as possible, but too low may break functionality Value 0 - SpeakerParticipantDefaultOrder + VoiceEffectExpiryWarningTime Comment - Order for displaying speakers in voice controls. 0 = alphabetical. 1 = recent. + How much notice to give of Voice Morph subscriptions expiry, in seconds. Persist 1 Type - U32 + S32 Value - 1 + 259200 - SpeakerParticipantRemoveDelay + VoiceMorphingEnabled Comment - Timeout to remove participants who is not in channel before removed from list of active speakers (text/voice chat) + Whether or not to enable Voice Morphs and show the UI. Persist - 1 + 0 Type - F32 + Boolean Value - 10.0 + 1 - UseNewWalkRun + AutoDisengageMic Comment - Replace standard walk/run animations with new ones. + Automatically turn off the microphone when ending IM calls. Persist 1 Type @@ -15978,163 +17466,164 @@ This should be as low as possible, but too low may break functionality Value 1 - UseCrossWalkRun + ShowDeviceSettings Comment - Use opposite gender walk/run animations. + Show device settings Persist - 1 + 0 Type Boolean Value 0 - UseStartScreen + VoiceEarLocation Comment - Whether to load a start screen image or not. + Location of the virtual ear for voice Persist 1 Type - Boolean + S32 Value - 1 + 0 - UseWebPagesOnPrims + VoiceHost Comment - [NOT USED] + Client SLVoice host to connect to Persist 1 Type - Boolean + String Value - 0 + 127.0.0.1 - UserConnectionPort + VoiceImageLevel0 Comment - Port that this client transmits on. + Texture UUID for voice image level 0 Persist 1 Type - U32 + String Value - 0 + 041ee5a0-cb6a-9ac5-6e49-41e9320507d5 - UserLogFile + VoiceImageLevel1 Comment - User specified log file name. + Texture UUID for voice image level 1 Persist 1 Type String Value - + 29de489d-0491-fb00-7dab-f9e686d31e83 - UserLoginInfo + VoiceImageLevel2 Comment - Users loging data. + Texture UUID for voice image level 2 Persist 1 Type - LLSD + String Value + 29de489d-0491-fb00-7dab-f9e686d31e83 - VFSOldSize + VoiceImageLevel3 Comment - [DO NOT MODIFY] Controls resizing of local file cache + Texture UUID for voice image level 3 Persist 1 Type - U32 + String Value - 0 + 29de489d-0491-fb00-7dab-f9e686d31e83 - VFSSalt + VoiceImageLevel4 Comment - [DO NOT MODIFY] Controls local file caching behavior + Texture UUID for voice image level 4 Persist 1 Type - U32 + String Value - 1 + 29de489d-0491-fb00-7dab-f9e686d31e83 - VelocityInterpolate + VoiceImageLevel5 Comment - Extrapolate object motion from last packet based on received velocity + Texture UUID for voice image level 5 Persist 1 Type - Boolean + String Value - 1 + 29de489d-0491-fb00-7dab-f9e686d31e83 - InterpolationTime + VoiceImageLevel6 Comment - How long to extrapolate object motion after last packet received + Texture UUID for voice image level 6 Persist 1 Type - F32 + String Value - 3 + 29de489d-0491-fb00-7dab-f9e686d31e83 - InterpolationPhaseOut + VoiceInputAudioDevice Comment - Seconds to phase out interpolated motion + Audio input device to use for voice Persist 1 Type - F32 + String Value - 1 + Default - VerboseLogs + VoiceLogFile Comment - Display source file and line number for each log item for debugging purposes + Log file to use when launching the voice daemon Persist 1 Type - Boolean + String Value - 0 + - VersionChannelName + VoiceOutputAudioDevice Comment - Versioning Channel Name. + Audio output device to use for voice Persist 1 Type String Value - Ascent Viewer Release + Default - VertexShaderEnable + VoicePort Comment - Enable/disable all GLSL shaders (debug) + Client SLVoice port to connect to Persist 1 Type - Boolean + U32 Value - 0 + 44125 - VivoxAutoPostCrashDumps + VoiceMultiInstance Comment - If true, SLVoice will automatically send crash dumps directly to Vivox. + Allow multiple viewers to have the voice enabled at the same time Persist 1 Type @@ -16142,109 +17631,109 @@ This should be as low as possible, but too low may break functionality Value 0 - VivoxDebugLevel + VoiceServerType Comment - Logging level to use when launching the vivox daemon + The type of voice server to connect to. Persist - 1 + 0 Type String Value - -1 + vivox - VivoxDebugSIPURIHostName + WLSkyDetail Comment - Hostname portion of vivox SIP URIs (empty string for the default). + Controls vertex detail on the WindLight sky. Lower numbers will give better performance and uglier skies. Persist 1 Type - String + U32 Value - + 64 - VivoxDebugVoiceAccountServerURI + WarnAboutBadPCI Comment - URI to the vivox account management server (empty string for the default). + Enables AboutBadPCI warning dialog Persist 1 Type - String + Boolean Value - + 1 - VoiceCallsFriendsOnly + WarnAboutDirectX9 Comment - Only accept voice calls from residents on your friends list + Enables AboutDirectX9 warning dialog Persist 1 Type Boolean Value - 0 + 1 - InstantMessagesFriendsOnly + WarnAboutOldGraphicsDriver Comment - Only accept instant messages from residents on your friends list + Enables AboutOldGraphicsDriver warning dialog Persist 1 Type Boolean Value - 0 + 1 - VoiceCallsRejectGroup + WarnAboutPCIGraphics Comment - Silently reject all incoming group voice calls. + Enables AboutPCIGraphics warning dialog Persist 1 Type Boolean Value - 0 + 1 - VoiceDisableMic + WarnBrowserLaunch Comment - Completely disable the ability to open the mic. + Enables BrowserLaunch warning dialog Persist 1 Type Boolean Value - 0 + 1 - VoiceEffectExpiryWarningTime + WarnDeedObject Comment - How much notice to give of Voice Morph subscriptions expiry, in seconds. + Enables DeedObject warning dialog Persist 1 Type - S32 + Boolean Value - 259200 + 1 - VoiceMorphingEnabled + WarnFirstAO Comment - Whether or not to enable Voice Morphs and show the UI. + Enables FirstAO warning dialog Persist - 0 + 1 Type Boolean Value 1 - AutoDisengageMic + WarnFirstAppearance Comment - Automatically turn off the microphone when ending IM calls. + Enables FirstAppearance warning dialog Persist 1 Type @@ -16252,197 +17741,197 @@ This should be as low as possible, but too low may break functionality Value 1 - ShowDeviceSettings + WarnFirstAttach Comment - Show device settings + Enables FirstAttach warning dialog Persist - 0 + 1 Type Boolean Value - 0 + 1 - VoiceEarLocation + WarnFirstBalanceDecrease Comment - Location of the virtual ear for voice + Enables FirstBalanceDecrease warning dialog Persist 1 Type - S32 + Boolean Value - 0 + 1 - VoiceHost + WarnFirstBalanceIncrease Comment - Client SLVoice host to connect to + Enables FirstBalanceIncrease warning dialog Persist 1 Type - String + Boolean Value - 127.0.0.1 + 1 - VoiceImageLevel0 + WarnFirstBuild Comment - Texture UUID for voice image level 0 + Enables FirstBuild warning dialog Persist 1 Type - String + Boolean Value - 041ee5a0-cb6a-9ac5-6e49-41e9320507d5 + 1 - VoiceImageLevel1 + WarnFirstDebugMenus Comment - Texture UUID for voice image level 1 + Enables FirstDebugMenus warning dialog Persist 1 Type - String + Boolean Value - 29de489d-0491-fb00-7dab-f9e686d31e83 + 1 - VoiceImageLevel2 + WarnFirstFlexible Comment - Texture UUID for voice image level 2 + Enables FirstFlexible warning dialog Persist 1 Type - String + Boolean Value - 29de489d-0491-fb00-7dab-f9e686d31e83 + 1 - VoiceImageLevel3 + WarnFirstGoTo Comment - Texture UUID for voice image level 3 + Enables FirstGoTo warning dialog Persist 1 Type - String + Boolean Value - 29de489d-0491-fb00-7dab-f9e686d31e83 + 1 - VoiceImageLevel4 + WarnFirstInventory Comment - Texture UUID for voice image level 4 + Enables FirstInventory warning dialog Persist 1 Type - String + Boolean Value - 29de489d-0491-fb00-7dab-f9e686d31e83 + 1 - VoiceImageLevel5 + WarnFirstLeftClickNoHit Comment - Texture UUID for voice image level 5 + Enables FirstLeftClickNoHit warning dialog Persist 1 Type - String + Boolean Value - 29de489d-0491-fb00-7dab-f9e686d31e83 + 1 - VoiceImageLevel6 + WarnFirstMap Comment - Texture UUID for voice image level 6 + Enables FirstMap warning dialog Persist 1 Type - String + Boolean Value - 29de489d-0491-fb00-7dab-f9e686d31e83 + 1 - VoiceInputAudioDevice + WarnFirstMedia Comment - Audio input device to use for voice + Enables FirstMedia warning dialog Persist 1 Type - String + Boolean Value - Default + 1 - VoiceLogFile + WarnFirstOverrideKeys Comment - Log file to use when launching the voice daemon + Enables FirstOverrideKeys warning dialog Persist 1 Type - String + Boolean Value - + 1 - VoiceOutputAudioDevice + WarnFirstSandbox Comment - Audio output device to use for voice + Enables FirstSandbox warning dialog Persist 1 Type - String + Boolean Value - Default + 1 - VoicePort + WarnFirstSculptedPrim Comment - Client SLVoice port to connect to + Enables FirstSculptedPrim warning dialog Persist 1 Type - U32 + Boolean Value - 44125 + 1 - VoiceMultiInstance + WarnFirstSit Comment - Allow multiple viewers to have the voice enabled at the same time + Enables FirstSit warning dialog Persist 1 Type Boolean Value - 0 + 1 - VoiceServerType + WarnFirstStreamingMusic Comment - The type of voice server to connect to. + Enables FirstStreamingMusic warning dialog Persist - 0 + 1 Type - String + Boolean Value - vivox + 1 - WLSkyDetail + WarnFirstStreamingVideo Comment - Controls vertex detail on the WindLight sky. Lower numbers will give better performance and uglier skies. + Enables FirstStreamingVideo warning dialog Persist 1 Type - U32 + Boolean Value - 64 + 1 - WarnAboutBadPCI + WarnFirstTeleport Comment - Enables AboutBadPCI warning dialog + Enables FirstTeleport warning dialog Persist 1 Type @@ -16450,10 +17939,10 @@ This should be as low as possible, but too low may break functionality Value 1 - WarnAboutDirectX9 + WarnFirstVoice Comment - Enables AboutDirectX9 warning dialog + Enables FirstVoice warning dialog Persist 1 Type @@ -16461,10 +17950,10 @@ This should be as low as possible, but too low may break functionality Value 1 - WarnAboutOldGraphicsDriver + WarnNewClassified Comment - Enables AboutOldGraphicsDriver warning dialog + Enables NewClassified warning dialog Persist 1 Type @@ -16472,10 +17961,10 @@ This should be as low as possible, but too low may break functionality Value 1 - WarnAboutPCIGraphics + WarnReturnToOwner Comment - Enables AboutPCIGraphics warning dialog + Enables ReturnToOwner warning dialog Persist 1 Type @@ -16483,10 +17972,10 @@ This should be as low as possible, but too low may break functionality Value 1 - WarnBrowserLaunch + WarnFirstPhysicsWearable Comment - Enables BrowserLaunch warning dialog + Enables Physics Wearable warning dialog Persist 1 Type @@ -16494,65 +17983,65 @@ This should be as low as possible, but too low may break functionality Value 1 - WarnDeedObject + WatchdogEnabled Comment - Enables DeedObject warning dialog + Controls whether the thread watchdog timer is activated. Persist - 1 + 0 Type Boolean Value - 1 + 0 - WarnFirstAO + WaterEditPresets Comment - Enables FirstAO warning dialog + Whether to be able to edit the water defaults or not Persist 1 Type Boolean Value - 1 + 0 - WarnFirstAppearance + WaterGLFogDensityScale Comment - Enables FirstAppearance warning dialog + Maps shader water fog density to gl fog density Persist 1 Type - Boolean + F32 Value - 1 + 0.02 - WarnFirstAttach + WaterGLFogDepthFloor Comment - Enables FirstAttach warning dialog + Controls how dark water gl fog can get Persist 1 Type - Boolean + F32 Value - 1 + 0.25 - WarnFirstBalanceDecrease + WaterGLFogDepthScale Comment - Enables FirstBalanceDecrease warning dialog + Controls how quickly gl fog gets dark under water Persist 1 Type - Boolean + F32 Value - 1 + 50.0 - WarnFirstBalanceIncrease + WindLightUseAtmosShaders Comment - Enables FirstBalanceIncrease warning dialog + Whether to enable or disable WindLight atmospheric shaders. Persist 1 Type @@ -16560,186 +18049,186 @@ This should be as low as possible, but too low may break functionality Value 1 - WarnFirstBuild + FullScreen Comment - Enables FirstBuild warning dialog + run a fullscreen session Persist 1 Type Boolean Value - 1 + 0 - WarnFirstDebugMenus + WindowHeight Comment - Enables FirstDebugMenus warning dialog + SL viewer window height Persist 1 Type - Boolean + S32 Value - 1 + 700 - WarnFirstFlexible + WindowMaximized Comment - Enables FirstFlexible warning dialog + SL viewer window maximized on login Persist 1 Type Boolean Value - 1 + 0 - WarnFirstGoTo + WindowWidth Comment - Enables FirstGoTo warning dialog + SL viewer window width Persist 1 Type - Boolean + S32 Value - 1 + 1000 - WarnFirstInventory + WindowX Comment - Enables FirstInventory warning dialog + X coordinate of lower left corner of SL viewer window, relative to primary display (pixels) Persist 1 Type - Boolean + S32 Value - 1 + 10 - WarnFirstLeftClickNoHit + WindowY Comment - Enables FirstLeftClickNoHit warning dialog + Y coordinate of lower left corner of SL viewer window, relative to primary display (pixels) Persist 1 Type - Boolean + S32 Value - 1 + 10 - WarnFirstMap + WornItemsSortOrder Comment - Enables FirstMap warning dialog + Specifies sort key for worn inventory items (+0 = name, +1 = date, +2 = folders always by name, +4 = system folders to top) Persist 1 Type - Boolean + U32 Value - 1 + 7 - WarnFirstMedia + XferThrottle Comment - Enables FirstMedia warning dialog + Maximum allowable downstream bandwidth for asset transfers (bits per second) Persist 1 Type - Boolean + F32 Value - 1 + 150000.0 - WarnFirstOverrideKeys + ExternalEditor Comment - Enables FirstOverrideKeys warning dialog + Path to program used to edit LSL scripts and XUI files, e.g.: /usr/bin/gedit --new-window "%s" Persist 1 Type - Boolean + String Value - 1 + - WarnFirstSandbox + YawFromMousePosition Comment - Enables FirstSandbox warning dialog + Horizontal range over which avatar head tracks mouse position (degrees of head rotation from left of window to right) Persist 1 Type - Boolean + F32 Value - 1 + 90.0 - WarnFirstSculptedPrim + YieldTime Comment - Enables FirstSculptedPrim warning dialog + Yield some time to the local host. Persist 1 Type - Boolean + S32 Value - 1 + -1 - WarnFirstSit + ForcePeriodicRenderingTime Comment - Enables FirstSit warning dialog + Periodically enable all rendering masks for a single frame. Persist 1 Type - Boolean + F32 Value - 1 + -1.0 - WarnFirstStreamingMusic + ZoomDirect Comment - Enables FirstStreamingMusic warning dialog + Map Joystick zoom axis directly to camera zoom. Persist 1 Type Boolean Value - 1 + 0 - WarnFirstStreamingVideo + ZoomTime Comment - Enables FirstStreamingVideo warning dialog + Time of transition between different camera modes (seconds) Persist 1 Type - Boolean + F32 Value - 1 + 0.40000000596 - WarnFirstTeleport + moapbeacon Comment - Enables FirstTeleport warning dialog + Beacon / Highlight media on a prim sources Persist 1 Type Boolean Value - 1 + 0 - WarnFirstVoice + particlesbeacon Comment - Enables FirstVoice warning dialog + Beacon / Highlight particle generators Persist 1 Type Boolean Value - 1 + 0 - WarnNewClassified + physicalbeacon Comment - Enables NewClassified warning dialog + Beacon / Highlight physical objects Persist 1 Type @@ -16747,21 +18236,21 @@ This should be as low as possible, but too low may break functionality Value 1 - WarnQuickTimeInstalled + renderbeacons Comment - Enables QuickTimeInstalled warning dialog + Beacon / Highlight particle generators Persist 1 Type Boolean Value - 1 + 0 - WarnReturnToOwner + renderhighlights Comment - Enables ReturnToOwner warning dialog + Beacon / Highlight scripted objects with touch function Persist 1 Type @@ -16769,32 +18258,32 @@ This should be as low as possible, but too low may break functionality Value 1 - WarnFirstPhysicsWearable + renderattachment Comment - Enables Physics Wearable warning dialog + Render beacons for / Highlight attached objects as well Persist 1 Type Boolean Value - 1 + 0 - WatchdogEnabled + renderbyowner Comment - Controls whether the thread watchdog timer is activated. + Render beacons/highlights for objects owned by anyone (0), you (1) or others (2) Persist - 0 + 1 Type - Boolean + U32 Value 0 - WaterEditPresets + invisiblesoundsbeacon Comment - Whether to be able to edit the water defaults or not + Beacon / Highlight invisible (non-object) sound generators Persist 1 Type @@ -16802,54 +18291,76 @@ This should be as low as possible, but too low may break functionality Value 0 - WaterGLFogDensityScale + scriptsbeacon Comment - Maps shader water fog density to gl fog density + Beacon / Highlight scripted objects Persist 1 Type - F32 + Boolean Value - 0.02 + 0 - WaterGLFogDepthFloor + scripttouchbeacon Comment - Controls how dark water gl fog can get + Beacon / Highlight scripted objects with touch function Persist 1 Type - F32 + Boolean Value - 0.25 + 1 - WaterGLFogDepthScale + SLURLDragNDrop + + Comment + Enable drag and drop of SLURLs onto the viewer + Persist + 1 + Type + Boolean + Value + 1 + + SLURLPassToOtherInstance + + Comment + Pass execution to prevoius viewer instances if there is a given slurl + Persist + 1 + Type + Boolean + Value + 1 + + soundsbeacon Comment - Controls how quickly gl fog gets dark under water + Beacon / Highlight sound generators Persist 1 Type - F32 + Boolean Value - 50.0 + 0 - WindLightUseAtmosShaders + ClearBeaconAfterTeleport Comment - Whether to enable or disable WindLight atmospheric shaders. + Clear the red tracker beacon after you teleport Persist 1 Type Boolean Value - 1 + 0 - FullScreen + LogTextureDownloadsToViewerLog Comment - run a fullscreen session + Send texture download details to the viewer log Persist 1 Type @@ -16857,153 +18368,171 @@ This should be as low as possible, but too low may break functionality Value 0 - WindowHeight + LogTextureDownloadsToSimulator Comment - SL viewer window height + Send a digest of texture info to the sim Persist 1 Type - S32 + Boolean Value - 700 + 0 - WindowMaximized + TextureLoggingThreshold Comment - SL viewer window maximized on login + Specifies the byte threshold at which texture download data should be sent to the sim. Persist 1 Type - Boolean + U32 Value - 0 + 1 - WindowWidth + OutfitOperationsTimeout Comment - SL viewer window width + Timeout for outfit related operations. Persist 1 Type S32 Value - 1000 + 180 - WindowX + + SLURLTeleportDirectly Comment - X coordinate of lower left corner of SL viewer window, relative to primary display (pixels) + Clicking on a slurl will teleport you directly instead of opening places panel Persist 1 Type - S32 + Boolean Value - 10 + 0 - WindowY + + LogInventoryDecline Comment - Y coordinate of lower left corner of SL viewer window, relative to primary display (pixels) + Log in system chat whenever an inventory offer is declined Persist 1 Type - S32 + Boolean Value - 10 + 1 - WornItemsSortOrder + UseHTTPInventory Comment - Specifies sort key for worn inventory items (+0 = name, +1 = date, +2 = folders always by name, +4 = system folders to top) + Allow use of http inventory transfers instead of UDP Persist 1 Type - U32 + Boolean Value - 7 + 1 - XferThrottle + ClickToWalk Comment - Maximum allowable downstream bandwidth for asset transfers (bits per second) + Click in world to walk to location Persist 1 Type - F32 + Boolean Value - 150000.0 + 0 - ExternalEditor + GenericErrorPageURL Comment - Path to program used to edit LSL scripts and XUI files, e.g.: /usr/bin/gedit --new-window "%s" + URL to set as a property on LLMediaControl to navigate to if the a page completes with a 400-499 HTTP status code Persist 1 Type String Value - + http://common-flash-secondlife-com.s3.amazonaws.com/viewer/v2.6/agni/404.html - YawFromMousePosition + WebProfileFloaterRect Comment - Horizontal range over which avatar head tracks mouse position (degrees of head rotation from left of window to right) + Web profile floater dimensions Persist 1 Type - F32 + Rect Value - 90.0 + + 0 + 680 + 485 + 0 + - YieldTime + ObjectsNextOwnerCopy Comment - Yield some time to the local host. + Newly created objects can be copied by next owner Persist 1 Type - S32 + Boolean Value - -1 + 0 - ForcePeriodicRenderingTime + ObjectsNextOwnerModify Comment - Periodically enable all rendering masks for a single frame. + Newly created objects can be modified by next owner Persist 1 Type - F32 + Boolean Value - -1.0 + 0 - ZoomDirect + ObjectsNextOwnerTransfer Comment - Map Joystick zoom axis directly to camera zoom. + Newly created objects can be resold or given away by next owner Persist 1 Type Boolean Value - 0 + 1 - ZoomTime + ObjectsEveryoneCopy + + Comment + Everyone can copy the newly created object + Persist + 1 + Type + Boolean + Value + 0 + + ObjectsShareWithGroup Comment - Time of transition between different camera modes (seconds) + Newly created objects are shared with the currently active group Persist 1 Type - F32 + Boolean Value - 0.40000000596 + 0 - moapbeacon + UploadsNextOwnerCopy Comment - Beacon / Highlight media on a prim sources + Newly uploaded items can be copied by next owner Persist 1 Type @@ -17011,10 +18540,10 @@ This should be as low as possible, but too low may break functionality Value 0 - particlesbeacon + UploadsNextOwnerModify Comment - Beacon / Highlight particle generators + Newly uploaded items can be modified by next owner Persist 1 Type @@ -17022,10 +18551,10 @@ This should be as low as possible, but too low may break functionality Value 0 - physicalbeacon + UploadsNextOwnerTransfer Comment - Beacon / Highlight physical objects + Newly uploaded items can be resold or given away by next owner Persist 1 Type @@ -17033,10 +18562,21 @@ This should be as low as possible, but too low may break functionality Value 1 - renderbeacons + UploadsEveryoneCopy + + Comment + Everyone can copy the newly uploaded item + Persist + 1 + Type + Boolean + Value + 0 + + UploadsShareWithGroup Comment - Beacon / Highlight particle generators + Newly uploaded items are shared with the currently active group Persist 1 Type @@ -17044,21 +18584,21 @@ This should be as low as possible, but too low may break functionality Value 0 - renderhighlights + ScriptsNextOwnerCopy Comment - Beacon / Highlight scripted objects with touch function + Newly created scripts can be copied by next owner Persist 1 Type Boolean Value - 1 + 0 - renderattachment + ScriptsNextOwnerModify Comment - Render beacons for / Highlight attached objects as well + Newly created scripts can be modified by next owner Persist 1 Type @@ -17066,43 +18606,65 @@ This should be as low as possible, but too low may break functionality Value 0 - renderbyowner + ScriptsNextOwnerTransfer + + Comment + Newly created scripts can be resold or given away by next owner + Persist + 1 + Type + Boolean + Value + 1 + + ScriptsEveryoneCopy + + Comment + Everyone can copy the newly created script + Persist + 1 + Type + Boolean + Value + 0 + + ScriptsShareWithGroup Comment - Render beacons/highlights for objects owned by anyone (0), you (1) or others (2) + Newly created scripts are shared with the currently active group Persist 1 Type - U32 + Boolean Value 0 - invisiblesoundsbeacon + NotecardsNextOwnerCopy Comment - Beacon / Highlight invisible (non-object) sound generators + Newly created notecards can be copied by next owner Persist 1 Type Boolean Value - 0 + 1 - scriptsbeacon + NotecardsNextOwnerModify Comment - Beacon / Highlight scripted objects + Newly created notecards can be modified by next owner Persist 1 Type Boolean Value - 0 + 1 - scripttouchbeacon + NotecardsNextOwnerTransfer Comment - Beacon / Highlight scripted objects with touch function + Newly created notecards can be resold or given away by next owner Persist 1 Type @@ -17110,32 +18672,21 @@ This should be as low as possible, but too low may break functionality Value 1 - SLURLDragNDrop - - Comment - Enable drag and drop of SLURLs onto the viewer - Persist - 1 - Type - Boolean - Value - 1 - - SLURLPassToOtherInstance + NotecardsEveryoneCopy - Comment - Pass execution to prevoius viewer instances if there is a given slurl - Persist - 1 - Type - Boolean - Value - 1 + Comment + Everyone can copy the newly created notecard + Persist + 1 + Type + Boolean + Value + 0 - soundsbeacon + NotecardsShareWithGroup Comment - Beacon / Highlight sound generators + Newly created scripts are shared with the currently active group Persist 1 Type @@ -17143,66 +18694,65 @@ This should be as low as possible, but too low may break functionality Value 0 - ClearBeaconAfterTeleport + GesturesNextOwnerCopy Comment - Clear the red tracker beacon after you teleport + Newly created gestures can be copied by next owner Persist 1 Type Boolean Value - 0 + 1 - LogTextureDownloadsToViewerLog + GesturesNextOwnerModify Comment - Send texture download details to the viewer log + Newly created gestures can be modified by next owner Persist 1 Type Boolean Value - 0 + 1 - LogTextureDownloadsToSimulator + GesturesNextOwnerTransfer Comment - Send a digest of texture info to the sim + Newly created gestures can be resold or given away by next owner Persist 1 Type Boolean Value - 0 + 1 - TextureLoggingThreshold + GesturesEveryoneCopy - Comment - Specifies the byte threshold at which texture download data should be sent to the sim. - Persist - 1 - Type - U32 - Value - 1 + Comment + Everyone can copy the newly created gesture + Persist + 1 + Type + Boolean + Value + 0 - OutfitOperationsTimeout + GesturesShareWithGroup Comment - Timeout for outfit related operations. + Newly created gestures are shared with the currently active group Persist 1 Type - S32 + Boolean Value - 180 + 0 - - SLURLTeleportDirectly + WearablesNextOwnerCopy Comment - Clicking on a slurl will teleport you directly instead of opening places panel + Newly created clothing or body part can be copied by next owner Persist 1 Type @@ -17210,44 +18760,49 @@ This should be as low as possible, but too low may break functionality Value 0 - - UseHTTPInventory + WearablesNextOwnerModify Comment - Allow use of http inventory transfers instead of UDP + Newly created clothing or body part can be modified by next owner Persist 1 Type Boolean Value - 1 + 0 - ClickToWalk + WearablesNextOwnerTransfer Comment - Click in world to walk to location + Newly created clothing or body part can be resold or given away by next owner Persist 1 Type Boolean Value - 0 + 1 - WebProfileFloaterRect + WearablesEveryoneCopy + + Comment + Everyone can copy the newly created clothing or body part + Persist + 1 + Type + Boolean + Value + 0 + + WearablesShareWithGroup Comment - Web profile floater dimensions + Newly created clothing or body part is shared with the currently active group Persist 1 Type - Rect + Boolean Value - - 0 - 680 - 485 - 0 - + 0 SimulateFBOFailure @@ -17362,6 +18917,22 @@ This should be as low as possible, but too low may break functionality 0 + FloaterRegionTrackerRect + + Comment + Rectangle for Region Tracker Floater + Persist + 1 + Type + Rect + Value + + 500 + 450 + 850 + 400 + + WindEnabled Comment @@ -17428,6 +18999,155 @@ This should be as low as possible, but too low may break functionality Value 1280.0 + ColladaExportFloaterRect + + Comment + Collada floater position + Persist + 1 + Type + Rect + Value + + 0 + 0 + 0 + 0 + + + DAEExportConsolidateMaterials + + Comment + Combine faces with same texture + Persist + 1 + Type + Boolean + Value + 1 + + DAEExportSkipTransparent + + Comment + Skip exporting faces with default transparent texture or full transparent + Persist + 1 + Type + Boolean + Value + 0 + + DAEExportTextures + + Comment + Export textures when exporting Collada + Persist + 1 + Type + Boolean + Value + 1 + + DAEExportTextureParams + + Comment + Apply texture params suchs as repeats to the exported UV map + Persist + 1 + Type + Boolean + Value + 1 + + DAEExportTexturesType + + Comment + Image file format to use when exporting Collada + Persist + 1 + Type + S32 + Value + 0 + + CrashSubmitBehavior + + Comment + Controls behavior when viewer crashes (0 = never send crash report, 1 = always send crash report) + Persist + 1 + Type + S32 + Value + -1 + + + EveryoneCopy + + Comment + (obsolete) Everyone can copy the newly created objects + Persist + 1 + Type + Boolean + Value + 0 + + NextOwnerCopy + + Comment + (obsolete) Newly created objects can be copied by next owner + Persist + 1 + Type + Boolean + Value + 0 + + NextOwnerModify + + Comment + (obsolete) Newly created objects can be modified by next owner + Persist + 1 + Type + Boolean + Value + 0 + + NextOwnerTransfer + + Comment + (obsolete) Newly created objects can be resold or given away by next owner + Persist + 1 + Type + Boolean + Value + 1 + + ShareWithGroup + + Comment + (obsolete) Newly created objects are shared with the currently active group + Persist + 1 + Type + Boolean + Value + 0 + + MediaFilterEnable + + Comment + Enable media domain filtering (0 = Off, 1 = Blacklist only, 2 = Prompt) + Persist + 1 + Type + U32 + Value + 0 + diff --git a/indra/newview/app_settings/settings_ascent.xml b/indra/newview/app_settings/settings_ascent.xml index 4bd498e044..564e797c3c 100644 --- a/indra/newview/app_settings/settings_ascent.xml +++ b/indra/newview/app_settings/settings_ascent.xml @@ -25,10 +25,65 @@ Value 0 + FriendNameSystem + + Comment + For friends list names. 0 = Old Style, 1 = Display Names and Username, 2 = Displayname only, 3 = Old Style (Display Name) + Persist + 1 + Type + S32 + Value + 1 + + GroupMembersNameSystem + + Comment + For lists of group members names. 0 = Old Style, 1 = Display Names and Username, 2 = Displayname only, 3 = Old Style (Display Name) + Persist + 1 + Type + S32 + Value + 1 + + IMNameSystem + + Comment + For names in chat tabs. 0 = Old Style, 1 = Display Names and Username, 2 = Displayname only, 3 = Old Style (Display Name) + Persist + 1 + Type + S32 + Value + 0 + + LandManagementNameSystem + + Comment + For names land management lists. 0 = Old Style, 1 = Display Names and Username, 2 = Displayname only, 3 = Old Style (Display Name) + Persist + 1 + Type + S32 + Value + 1 + + LookAtNameSystem + + Comment + For name on lookat crosshairs. 0 = Old Style, 1 = Display Names and Username, 2 = Displayname only, 3 = Old Style (Display Name), less than 0 for off + Persist + 1 + Type + S32 + Value + 0 + PhoenixNameSystem Comment - Use Display Names instead of Legacy Names. 0 = Old Style, 1 = Display Names and Username, 2 = Displayname only + For general purpose names in the viewer. 0 = Old Style, 1 = Display Names and Username, 2 = Displayname only, 3 = Old Style (Display Name) Persist 2 Type @@ -36,6 +91,204 @@ Value 1 + ProfileNameSystem + + Comment + For a name displayed on its profile. 0 = Old Style, 1 = Display Names and Username, 2 = Displayname only, 3 = Old Style (Display Name) + Persist + 1 + Type + S32 + Value + 1 + + RadarNameSystem + + Comment + For names in the radar. 0 = Old Style, 1 = Display Names and Username, 2 = Displayname only, 3 = Old Style (Display Name) + Persist + 1 + Type + S32 + Value + 1 + + SpeakerNameSystem + + Comment + For names in lists of speakers. 0 = Old Style, 1 = Display Names and Username, 2 = Displayname only, 3 = Old Style (Display Name) + Persist + 1 + Type + S32 + Value + 1 + + AlchemyChatCommandHoverHeight + + Comment + Command to hover your height or something + Persist + 1 + Type + String + Value + /hover + + AlchemyChatCommandResyncAnim + + Comment + Command to stop/start in order to resync animations + Persist + 1 + Type + String + Value + /resync + + AlchemyChatCommandSetChatChannel + + Comment + Command to set nearby chat channel + Persist + 1 + Type + String + Value + /setchannel + + AlchemyChatCommandSetHome + + Comment + Command to set the avatar home + Persist + 1 + Type + String + Value + /sethome + + AlchemyConnectToNeighbors + + Comment + If false, disconnect from neighboring regions and all further neighbors on teleport + Persist + 1 + Type + Boolean + Value + 1 + + AlchemyLookAtLines + + Comment + Render a line from Look At beacon to the originating avatar + Persist + 1 + Type + Boolean + Value + 0 + + AlchemyLookAtHideSelf + + Comment + Hide own Look At beacon when Look At render is enabled + Persist + 1 + Type + Boolean + Value + 0 + + AlchemyMouselookIFF + + Comment + Display user that is currently focused upon by crosshair in mouselook + Persist + 1 + Type + Boolean + Value + 1 + + AlchemyMouselookIFFRange + + Comment + Range of IFF display + Persist + 1 + Type + F32 + Value + 380.0 + + AlchemyMouselookInstructions + + Comment + Draw Mouselook Instructions + Persist + 1 + Type + Boolean + Value + 1 + + AlchemyNearbyChatChannel + + Comment + Chat channel used for sending nearby chat from the viewer + Persist + 0 + Type + S32 + Value + 0 + + AlchemyRainbowEffects + + Comment + Makes agent effects rainbows! + Persist + 1 + Type + Boolean + Value + 0 + + AlchemyRegionRestartShake + + Comment + Shake the screen when the region restart floater is displayed + Persist + 1 + Type + Boolean + Value + 0 + + AlchemySitOnAway + + Comment + Agent groundsits in away mode + Persist + 1 + Type + Boolean + Value + 0 + + AlchemyWLCloudTexture + + Comment + Name of local cloud texture to use for windlight + Persist + 1 + Type + String + Value + Altocumulus.tga + AscentPowerfulWizard Comment @@ -277,7 +530,7 @@ Type Boolean Value - 1 + 0 AscentShowOthersTagColor @@ -312,6 +565,17 @@ Value 1 + AlchemyDisableSimCamConstraint + + Comment + Disable the push the simulator applies when camera collides with objects + Persist + 1 + Type + Boolean + Value + 0 + AscentFlyAlwaysEnabled Comment @@ -554,6 +818,17 @@ Value key2name + AscentCmdLineKeyToNameNameSystem + + Comment + For key to name command defined by AscentCmdLineKeyToName, the format to show the key's name in. 0 = Old Style, 1 = Display Names and Username, 2 = Displayname only, 3 = Old Style (Display Name) + Persist + 1 + Type + S32 + Value + 1 + AscentCmdLineOfferTp Comment @@ -598,27 +873,38 @@ Value /away - SinguCmdLineURL + SinguCmdLineRegionSay Comment - Open SLURLS and URLs from chatbar. + Command prefix for chat to say to entire region, if allowed(EM). Persist 1 Type String Value - /open + /regionsay - SinguCompleteNameProfiles + SinguCmdLineSetting Comment - Use the complete name "Display Name (legacy.name)" in profiles, instead of following the choice set by PhoenixNameSystem. + Set or toggle debug settings from the chatbar. Persist 1 Type - Boolean + String Value - 0 + /setdebug + + SinguCmdLineURL + + Comment + Open SLURLS and URLs from chatbar. + Persist + 1 + Type + String + Value + /open SinguDefaultEaseIn @@ -642,6 +928,39 @@ Value 0 + SinguFollowDistance + + Comment + Distance at which to follow objects and avatars at, from menus that offer follow (minimum 0.5) + Persist + 1 + Type + F32 + Value + 1.0 + + SinguLastKnownReleaseBuild + + Comment + Latest known available verson. + Persist + 1 + Type + S32 + Value + 0 + + SinguLastKnownAlphaBuild + + Comment + Latest known available verson. + Persist + 1 + Type + S32 + Value + 0 + SinguMotionResetsCamera Comment @@ -653,21 +972,22 @@ Value 1 - UseWebProfiles + SinguMotionResetsCameraReset Comment - Always use web profiles floaters instead of legacy profile floaters. + Disable for the behavior Liru intended SinguMotionResetsCamera to have, wherein it doesn't reset every time you press escape, teleport, or whatever else! So you can walk around and your camera won't reset at all like it was meant to be. +RIP Latif Khalifa. Persist 1 Type Boolean Value - 0 + 1 - UseWebSearch + SinguOwnerSayAsErrors Comment - Always use web-based search instead of legacy search. + llOwnerSay will show up in the script error console instead of in chat. Persist 1 Type @@ -675,17 +995,208 @@ Value 0 - UseWebSearchSLURL + SinguPostProcessDefault Comment - When clicking search SLURLs, or using an SLapp that uses these, display the web-based search (When false, some search SLURLs may display somewhat improperly). + Default post process preset, changing this will change your active preset Persist 1 Type - Boolean + String + Value + Default + + SinguReplaceLinks + + Comment + Whether or not to visually replace special links like SLURLs with labels where applicable. +While having this on allows people to mislead you with links that look like other links, it also allows you to use SLURLs that appear as people's names and increasingly more scripts use this to run faster. +You can always select the text, right click and select Copy Raw to copy the hidden contents of the link. +Changing this setting only affects new text. + Persist + 1 + Type + Boolean + Value + 1 + + SupportChatDisplayBuild + + Comment + Whether or not to display your current build (and its channel indicator) when you speak in identified support group chats + Persist + 1 + Type + S32 + Value + -1 + + WarnRecommendedUpdate + + Comment + Enables recommended update notification dialog + Persist + 1 + Type + Boolean + Value + 1 + + WarnUrgentUpdate + + Comment + Enables critical update notification dialog + Persist + 1 + Type + Boolean + Value + 1 + + WarnUrgentUpdateModal + + Comment + Enables critical update modal dialog + Persist + 1 + Type + Boolean + Value + 1 + + UseWebProfiles + + Comment + Always use web profiles floaters instead of legacy profile floaters. + Persist + 1 + Type + Boolean + Value + 0 + + UseWebSearch + + Comment + Always use web-based search instead of legacy search. + Persist + 1 + Type + Boolean + Value + 0 + + UseWebSearchSLURL + + Comment + When clicking search SLURLs, or using an SLapp that uses these, display the web-based search (When false, some search SLURLs may display somewhat improperly). + Persist + 1 + Type + Boolean Value 0 + ExodusMapRolloverCircleColor + + Comment + Color setting of circle for rollovers on the minimap. + Persist + 1 + Type + Color4 + Value + Value + + 1.0 + 1.0 + 1.0 + 0.05 + + + ExodusMapRolloverColor + + Comment + Color setting for rollovers on the minimap. + Persist + 1 + Type + Color4 + Value + Value + + 0.0 + 1.0 + 1.0 + 1.0 + + + ExodusMinimapAreaEffect + + Comment + Radius of the area of affect for the minimap, adjusted by shift scrolling over the minimap. + Persist + 1 + Type + F32 + Value + 3.5 + + EmergencyTeleportSeconds + + Comment + The remaining time left in seconds when to execute an emergency teleport out of a restarting region. + Persist + 1 + Type + U32 + Value + 20 + + LiruEnableWIPUI + + Comment + Whether or not to enable UI components that probably don't work yet. + Persist + 1 + Type + Boolean + Value + 0 + + LiruFlashWhenMinimized + + Comment + Whether or not to flash the taskbar when a message comes in while minimized. + Persist + 1 + Type + Boolean + Value + 1 + + LiruReceivedItemsNotify + + Comment + Whether or not to spawn a notification in addition to the chat message when you receive items from the marketplace. + Persist + 1 + Type + Boolean + Value + 1 + + LiruUseMarkedColor + + Comment + Whether or not to use the color of marks done on radar and minimap to color tags and chat from those individuals + Persist + 1 + Type + Boolean + Value + 1 + OBJExportNotifyFailed Comment @@ -719,6 +1230,17 @@ Value 0 + SinguAlwaysUnderlineLinks + + Comment + Enable to always underline new links in text editors (and any you hover over after enabling this) + Persist + 1 + Type + Boolean + Value + 0 + SingularitySplashPagePrefix Comment @@ -728,7 +1250,7 @@ Type String Value - http://singularity-viewer.github.io + SingularitySplashPagePath @@ -741,5 +1263,1259 @@ Value pages/login/ + + ToolbarVisibleAbout + + Comment + Whether or not the button for about is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleAboutLand + + Comment + Whether or not the button for about land is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleAboutRegion + + Comment + Whether or not the button for region/estate is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleActiveSpeakers + + Comment + Whether or not the button for active speakers is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleAlwaysRun + + Comment + Whether or not the button for run is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleAnimsExplorer + + Comment + Whether or not the button for anims explorer is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleAO + + Comment + Whether or not the button for the AO Floater is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleAppearance + + Comment + Whether or not the button for appearance is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleAreaSearch + + Comment + Whether or not the button for areasearch is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleAssetBlacklist + + Comment + Whether or not the button for asset blacklist is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleAutoReplace + + Comment + Whether or not the button for autoreplace is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleAvatar + + Comment + Whether or not the button for default avatars is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleBeacons + + Comment + Whether or not the button for beacons is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleBuild + + Comment + Whether or not the button for build is on the toolbar + Persist + 1 + Type + Boolean + Value + 1 + IsCOA + 1 + + ToolbarVisibleBuyCurrency + + Comment + Whether or not the button for buy currency is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleBuyLand + + Comment + Whether or not the button for buy land is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleCameraControls + + Comment + Whether or not the button for camera controls is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleChatbar + + Comment + Whether or not the button for toggling the chatbar is on the toolbar + Persist + 1 + Type + Boolean + Value + 1 + IsCOA + 1 + + ToolbarVisibleChatHistory + + Comment + Whether or not the button for local chat history is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleCommunicate + + Comment + Whether or not the button for communicate floater is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleCommunicateIM + + Comment + Whether or not the flyout button for communicate is on the toolbar + Persist + 1 + Type + Boolean + Value + 1 + IsCOA + 1 + + ToolbarVisibleComplaintReporter + + Comment + Whether or not the button for abuse report is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleDayCycle + + Comment + Whether or not the button for day cycle editor is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleDebugAvatar + + Comment + Whether or not the button for debug avatar textures is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleDebugConsole + + Comment + Whether or not the button for the debug console is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleDebugSettings + + Comment + Whether or not the button for debug settings is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleDestinations + + Comment + Whether or not the button for destinations is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleDisplayName + + Comment + Whether or not the button for display name is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleEditUI + + Comment + Whether or not the button for edit ui is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleEnvSettings + + Comment + Whether or not the button for the environment settings editor is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleExperiences + + Comment + Whether or not the button for the experiences floater is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleFastTimers + + Comment + Whether or not the button for fast timers is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleFly + + Comment + Whether or not the button for fly is on the toolbar + Persist + 1 + Type + Boolean + Value + 1 + IsCOA + 1 + + ToolbarVisibleFontTest + + Comment + Whether or not the button for font test is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleFrameConsole + + Comment + Whether or not the button for the frame console is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleFriends + + Comment + Whether or not the button for friends is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleGestures + + Comment + Whether or not the button for gestures is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleGodTools + + Comment + Whether or not the button for god tools is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleGridOptions + + Comment + Whether or not the button for grid options for the build tools is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleGroups + + Comment + Whether or not the button for groups is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleGroupTitles + + Comment + Whether or not the button for group titles is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + + ToolbarVisibleHelpTutorial + + Comment + Whether or not the button for the tutorial is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleHTTPConsole + + Comment + Whether or not the button for the http console is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleInspect + + Comment + Whether or not the button for inspect is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleInventory + + Comment + Whether or not the button for inventory is on the toolbar + Persist + 1 + Type + Boolean + Value + 1 + IsCOA + 1 + + ToolbarVisibleInventoryFavs + + Comment + Whether or not the button for favorites is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleInventoryOutfits + + Comment + Whether or not the button for outfits is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleInventoryReceivedItems + + Comment + Whether or not the button for received items is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleJoystick + + Comment + Whether or not the button for joystick configuration is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleLocalAssets + + Comment + Whether or not the button for local textures is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleMarketplace + + Comment + Whether or not the button for marketplace is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleMarketplaceListings + + Comment + Whether or not the button for marketplace listings is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleMeanEvents + + Comment + Whether or not the button for bumps, pushes, and hits is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleMediaFilter + + Comment + Whether or not the button for media filter is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleMediaTicker + + Comment + Whether or not the button for the streaming audio display is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleMemLeak + + Comment + Whether or not the button for memory leak is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleMessageLog + + Comment + Whether or not the button for message log is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleMiniMap + + Comment + Whether or not the button for the mini-map is on the toolbar + Persist + 1 + Type + Boolean + Value + 1 + IsCOA + 1 + + ToolbarVisibleMouselook + + Comment + Whether or not the button for mouselook is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleMovementControls + + Comment + Whether or not the button for movement controls is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleMuteList + + Comment + Whether or not the button for mute list is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleMyLand + + Comment + Whether or not the button for my land is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleNotificationsConsole + + Comment + Whether or not the button for the notifications console is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleOutfit + + Comment + Whether or not the button for make outfit is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisiblePathfindingCharacters + + Comment + Whether or not the button for pathfinding characters is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisiblePathfindingLinksets + + Comment + Whether or not the button for pathfinding linksets is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisiblePermPrefs + + Comment + Whether or not the button for default upload permissions is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisiblePostProcess + + Comment + Whether or not the button for post-processing effects is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisiblePreferences + + Comment + Whether or not the button for preferences is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleQuit + + Comment + Whether or not the button to quit is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleRadar + + Comment + Whether or not the button for the radar is on the toolbar + Persist + 1 + Type + Boolean + Value + 1 + IsCOA + 1 + + ToolbarVisibleRegionDebugConsole + + Comment + Whether or not the button for the region debug console is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleRegionTracker + + Comment + Whether or not the button for the region tracker is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleScriptErrors + + Comment + Whether or not the button for script errors is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleScriptInfo + + Comment + Whether or not the button for script info is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleSearch + + Comment + Whether or not the button for search is on the toolbar + Persist + 1 + Type + Boolean + Value + 1 + IsCOA + 1 + + ToolbarVisibleSit + + Comment + Whether or not the button for sit is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleSnapshot + + Comment + Whether or not the button for snapshot is on the toolbar + Persist + 1 + Type + Boolean + Value + 1 + IsCOA + 1 + + ToolbarVisibleSoundExplorer + + Comment + Whether or not the button for the sound explorer is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleStatBar + + Comment + Whether or not the button for the statistics bar is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleTeleportHistory + + Comment + Whether or not the button for teleport history is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleTest + + Comment + Whether or not the button for the test floater is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleTextureCategoryConsole + + Comment + Whether or not the button for the texture category console is on the toolbar (requires a relog with AuditTexture true for the button to work) + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleTextureConsole + + Comment + Whether or not the button for the texture console is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleTextureSizeConsole + + Comment + Whether or not the button for the texture size console is on the toolbar (requires a relog with AuditTexture true for the button to work) + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleToolbarPrefs + + Comment + Whether or not the button for the floater to change buttons on the toolbar is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleVelocity + + Comment + Whether or not the button for velocity is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleVoiceEffect + + Comment + Whether or not the button for voice effects is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleWaterSettings + + Comment + Whether or not the button for the water editor is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleWeb + + Comment + Whether or not the button for the web browser is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleWindlight + + Comment + Whether or not the button for the windlight editor is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleWorldMap + + Comment + Whether or not the button for the world map is on the toolbar + Persist + 1 + Type + Boolean + Value + 1 + IsCOA + 1 + + + ToolbarVisibleRLVLocks + + Comment + Whether or not the button for RLVa Locks is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleRLVRestrictions + + Comment + Whether or not the button for RLVa Restrictions is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + ToolbarVisibleRLVStrings + + Comment + Whether or not the button for RLVa Strings is on the toolbar + Persist + 1 + Type + Boolean + Value + 0 + IsCOA + 1 + + diff --git a/indra/newview/app_settings/settings_ascent_coa.xml b/indra/newview/app_settings/settings_ascent_coa.xml index 2cb8096792..31290185b0 100644 --- a/indra/newview/app_settings/settings_ascent_coa.xml +++ b/indra/newview/app_settings/settings_ascent_coa.xml @@ -204,6 +204,24 @@ IsCOA 1 + MapAvatar + + Comment + Color for map dots of residents who don't qualify for any color else. + Persist + 1 + Type + Color4 + Value + + 0.0 + 1.0 + 0.0 + 1.0 + + IsCOA + 1 + ColorFriendChat Comment diff --git a/indra/newview/app_settings/settings_crash_behavior.xml b/indra/newview/app_settings/settings_crash_behavior.xml deleted file mode 100644 index 0665d86f26..0000000000 --- a/indra/newview/app_settings/settings_crash_behavior.xml +++ /dev/null @@ -1,48 +0,0 @@ - - - CrashSubmitBehavior - - Comment - Controls behavior when viewer crashes (0 = ask before sending crash report, 1 = always send crash report, 2 = never send crash report) - Persist - 2 - Type - S32 - Value - 2 - - CurlMaxTotalConcurrentConnections - - Comment - Maximum total number of simultaneous curl connections - Persist - 1 - Type - U32 - Value - 64 - - CurlConcurrentConnectionsPerService - - Comment - Maximum number of simultaneous curl connections per host:port service - Persist - 0 - Type - U32 - Value - 8 - - NoVerifySSLCert - - Comment - Do not verify SSL certificates. - Persist - 1 - Type - Boolean - Value - 1 - - - diff --git a/indra/newview/app_settings/settings_files.xml b/indra/newview/app_settings/settings_files.xml index ac304f7593..cfb4504f2d 100644 --- a/indra/newview/app_settings/settings_files.xml +++ b/indra/newview/app_settings/settings_files.xml @@ -43,13 +43,6 @@ Requirement 1 - CrashSettings - - Name - settings_crash_behavior.xml - Requirement - 1 - User @@ -65,11 +58,6 @@ NameFromSetting ClientSettingsFile - CrashSettings - - Name - settings_crash_behavior.xml - Account diff --git a/indra/newview/app_settings/settings_per_account.xml b/indra/newview/app_settings/settings_per_account.xml index b5d15381db..27a01079cb 100644 --- a/indra/newview/app_settings/settings_per_account.xml +++ b/indra/newview/app_settings/settings_per_account.xml @@ -8,6 +8,17 @@ + AvatarHoverOffsetZ + + Comment + After-everything-else fixup for avatar Z position. + Persist + 1 + Type + F32 + Value + 0.0 + AOConfigNotecardID @@ -175,6 +186,61 @@ Value + AODefaultTyping + + Comment + Default typing anim + Persist + 1 + Type + String + Value + + + AODefaultFloat + + Comment + Default float anim + Persist + 1 + Type + String + Value + + + AODefaultSwim + + Comment + Default swim anim + Persist + 1 + Type + String + Value + + + AODefaultSwimUp + + Comment + Default swimup anim + Persist + 1 + Type + String + Value + + + AODefaultSwimDown + + Comment + Default swimdown anim + Persist + 1 + Type + String + Value + + AODefaultStandUp Comment @@ -216,31 +282,18 @@ - AscentInstantMessageResponseRepeat - - Comment - Whether to keep on resending the autoresponse every line they send - Persist - 1 - Type - Boolean - Value - 0 - - - AscentInstantMessageShowOnTyping - - Comment - Whether to perform the autorespond the moment they begin to type instead of waiting for an actual message - Persist - 1 - Type - Boolean - Value - 0 - - + AscentInstantMessageResponseRepeat + + Comment + Whether to keep on resending the autoresponse every line they send + Persist + 1 + Type + Boolean + Value + 0 + AutoresponseAnyone Comment @@ -406,6 +459,28 @@ Value This is an autoresponse! + AutoresponseMutedShow + + Comment + Whether to show that AutoresponseMuted's were sent + Persist + 1 + Type + Boolean + Value + 0 + + AutoresponseOnlyIfAway + + Comment + When true, enabled autoresponses (not busy responses) will only be sent while in away (or Fake Away) mode. Does not apply to autoresponses to muted persons, they don't need to know you're away. + Persist + 1 + Type + Boolean + Value + 0 + BusyModeResponse Comment @@ -427,7 +502,7 @@ Boolean Value 0 - + BusyModeResponseItemID Comment @@ -452,7 +527,40 @@ + DefaultUploadPermissionsConverted + + Comment + Default upload permissions have been converted to default creation permissions + Persist + 1 + Type + Boolean + Value + 0 + EveryoneExport + + Comment + (obsolete) Whether content you upload has exportability permission by default + Persist + 1 + Type + Boolean + Value + 0 + + ObjectsEveryoneExport + + Comment + Whether objects you create have exportability permission by default + Persist + 1 + Type + Boolean + Value + 0 + + UploadsEveryoneExport Comment Whether content you upload has exportability permission by default @@ -463,6 +571,50 @@ Value 0 + ScriptsEveryoneExport + + Comment + Whether scripts you make have exportability permission by default + Persist + 1 + Type + Boolean + Value + 0 + + NotecardsEveryoneExport + + Comment + Whether notecards you make have exportability permission by default + Persist + 1 + Type + Boolean + Value + 0 + + GesturesEveryoneExport + + Comment + Whether gestures you make have exportability permission by default + Persist + 1 + Type + Boolean + Value + 0 + + WearablesEveryoneExport + + Comment + Whether wearables you make have exportability permission by default + Persist + 1 + Type + Boolean + Value + 0 + RLVaLoginLastLocation Comment @@ -618,6 +770,17 @@ Value -%Y-%m + ShowFavoritesOnLogin + + Comment + Determines whether favorites of last logged in user will be saved on exit from viewer and shown on login screen + Persist + 1 + Type + Boolean + Value + 1 + KeywordsChangeColor @@ -723,6 +886,27 @@ Value - + EmergencyTeleportLandmark + + Comment + UUID of the landmark to teleport to in the last twenty seconds before a region will restart, empty is none. + Persist + 1 + Type + String + Value + + + EmergencyTeleportLandmarkBackup + + Comment + UUID of the landmark to teleport to in the last twenty seconds before a region will restart if you're already in the region of EmergencyTeleportLandmark or if EmergencyTeleportLandmark is set but canot be found, empty is none. + Persist + 1 + Type + String + Value + + diff --git a/indra/newview/app_settings/settings_rlv.xml b/indra/newview/app_settings/settings_rlv.xml index 7dd83af41f..5e645f404f 100644 --- a/indra/newview/app_settings/settings_rlv.xml +++ b/indra/newview/app_settings/settings_rlv.xml @@ -11,7 +11,7 @@ Type Boolean Value - 1 + 1 RestrainedLoveDebug @@ -22,7 +22,7 @@ Type Boolean Value - 0 + 0 RestrainedLoveCanOOC @@ -33,7 +33,7 @@ Type Boolean Value - 1 + 1 RestrainedLoveForbidGiveToRLV @@ -44,7 +44,7 @@ Type Boolean Value - 0 + 0 RestrainedLoveNoSetEnv @@ -55,19 +55,8 @@ Type Boolean Value - 0 + 0 - RestrainedLoveOffsetAvatarZ - - Comment - Offset the avatar. - Persist - 1 - Type - F32 - Value - 0.0 - RestrainedLoveReplaceWhenFolderBeginsWith Comment @@ -88,7 +77,7 @@ Type Boolean Value - 1 + 1 RestrainedLoveStackWhenFolderBeginsWith @@ -101,6 +90,17 @@ Value + + RLVaDebugDeprecateExplicitPoint + + Comment + Ignore attachment point names on inventory items and categories (incomplete) + Persist + 1 + Type + Boolean + Value + 0 + RLVaDebugHideUnsetDuplicate Comment @@ -110,7 +110,7 @@ Type Boolean Value - 0 + 0 RLVaEnableCompositeFolders @@ -121,7 +121,7 @@ Type Boolean Value - 0 + 0 RLVaEnableLegacyNaming @@ -132,7 +132,7 @@ Type Boolean Value - 1 + 1 RLVaEnableSharedWear @@ -143,7 +143,7 @@ Type Boolean Value - 1 + 1 RLVaHideLockedLayers @@ -154,7 +154,7 @@ Type Boolean Value - 0 + 0 RLVaHideLockedAttachments @@ -165,7 +165,7 @@ Type Boolean Value - 0 + 0 RLVaSharedInvAutoRename @@ -176,7 +176,7 @@ Type Boolean Value - 1 + 1 RLVaShowAssertionFailures @@ -187,7 +187,7 @@ Type Boolean Value - 1 + 1 RLVaShowNameTags @@ -198,7 +198,7 @@ Type Boolean Value - 0 + 0 RLVaTopLevelMenu @@ -209,7 +209,7 @@ Type Boolean Value - 0 + 0 RLVaWearReplaceUnlocked @@ -220,18 +220,7 @@ Type Boolean Value - 0 - - WarnFirstRLVGiveToRLV - - Comment - Enables FirstRLVGiveToRLV warning dialog - Persist - 1 - Type - Boolean - Value - 1 + 0 ForceInitialCOFDelay diff --git a/indra/newview/app_settings/settings_sh.xml b/indra/newview/app_settings/settings_sh.xml index 732da64bf1..f9b11e704f 100644 --- a/indra/newview/app_settings/settings_sh.xml +++ b/indra/newview/app_settings/settings_sh.xml @@ -185,32 +185,43 @@ Value 0 - SHPackDeferredNormals + SHOcclusionFudge Comment - Pack deferred normals into two components. + Padding added to occlusion bounds. Larger = less aggressive occlusion/less pop-in. Persist 1 Type - Boolean + F32 Value - 0 + 0.25 - SHPrecisionDeferredNormals + SHUseRMSEAutoMask Comment - Enable usage of RGB10A2 for the deferred normalMap format. Reduces normalmapping artifacts. + Use alternative method of detecing suitable textures for alphamasking. Less prone to excluding textures than standard method. Persist 1 Type Boolean Value - 0 + 1 - SHOcclusionFudge + SHAutoMaskMaxRMSE Comment - Padding added to occlusion bounds. Larger = less aggressive occlusion/less pop-in. + Sets the maximum random mean square error cutoff used when detecting suitable textures for alphamasking. (SHUseRMSEAutoMask must be TRUE for this to have any effect) + Persist + 1 + Type + F32 + Value + 0.18 + + SHAutoMaskMaxMid + + Comment + Sets the maximum percent of mid-range alpha pixels textures for alphamasking. (SHUseRMSEAutoMask must be TRUE for this to have any effect) Persist 1 Type @@ -218,10 +229,10 @@ Value 0.25 - SHUseRMSEAutoMask + SHAlwaysSoftenShadows Comment - Use alternative method of detecing suitable textures for alphamasking. Less prone to excluding textures than standard method. + Enable optional blur pass on shadows. Persist 1 Type @@ -229,16 +240,49 @@ Value 1 - SHAutoMaskMaxRMSE + SHRenderSSAOResolutionScale Comment - Sets the maximum random mean square error cutoff used when detecting suitable textures for alphamasking. (SHUseRMSEAutoMask must be TRUE for this to have any effect) + SSAO resolution scale. Valid values: 0.01-1.0 Persist 1 Type F32 Value - 0.09 + .5 + + SHAltBatching + + Comment + Experimental retooling of face batching. + Persist + 1 + Type + Boolean + Value + 1 + + SHRenderVsyncMode + + Comment + Desired vertical sychronization method. (0 = Disabled, 1 = Standard [Double-buffered], -1 = Adaptive [if supported]) + Persist + 1 + Type + S32 + Value + 0 + + SHSkipResetVBOsOnTeleport + + Comment + Skip VBO auto-recreation upon teleport. Setting to true may help avoid attachments dissipearing on teleport. + Persist + 1 + Type + Boolean + Value + 0 diff --git a/indra/newview/app_settings/shaders/class1/avatar/objectSkinV.glsl b/indra/newview/app_settings/shaders/class1/avatar/objectSkinV.glsl index 4005341c63..adcb92a98a 100644 --- a/indra/newview/app_settings/shaders/class1/avatar/objectSkinV.glsl +++ b/indra/newview/app_settings/shaders/class1/avatar/objectSkinV.glsl @@ -22,30 +22,54 @@ * $/LicenseInfo$ */ - +#define FLT_MAX 3.402823466e+38 ATTRIBUTE vec4 weight4; -uniform mat4 matrixPalette[32]; +uniform mat3x4 matrixPalette[MAX_JOINTS_PER_MESH_OBJECT]; +uniform float maxWeight; mat4 getObjectSkinnedTransform() { - float w0 = fract(weight4.x); - float w1 = fract(weight4.y); - float w2 = fract(weight4.z); - float w3 = fract(weight4.w); - - int i0 = int(floor(weight4.x)); - int i1 = int(floor(weight4.y)); - int i2 = int(floor(weight4.z)); - int i3 = int(floor(weight4.w)); + + + + int i; - //float scale = 1.0/(w.x+w.y+w.z+w.w); - //w *= scale; - mat4 mat = matrixPalette[i0]*w0; - mat += matrixPalette[i1]*w1; - mat += matrixPalette[i2]*w2; - mat += matrixPalette[i3]*w3; - - return mat; + vec4 w = fract(weight4); + vec4 index = floor(weight4); + + index = min(index, vec4(maxWeight)); + index = max(index, vec4( 0.0)); + + float sum = (w.x+w.y+w.z+w.w); + if(sum > 0.0) + w*=1.0/sum; + else + w=vec4(FLT_MAX); + + int i1 = int(index.x); + int i2 = int(index.y); + int i3 = int(index.z); + int i4 = int(index.w); + + mat3 mat = mat3(matrixPalette[i1])*w.x; + mat += mat3(matrixPalette[i2])*w.y; + mat += mat3(matrixPalette[i3])*w.z; + mat += mat3(matrixPalette[i4])*w.w; + + vec3 trans = vec3(matrixPalette[i1][0].w,matrixPalette[i1][1].w,matrixPalette[i1][2].w)*w.x; + trans += vec3(matrixPalette[i2][0].w,matrixPalette[i2][1].w,matrixPalette[i2][2].w)*w.y; + trans += vec3(matrixPalette[i3][0].w,matrixPalette[i3][1].w,matrixPalette[i3][2].w)*w.z; + trans += vec3(matrixPalette[i4][0].w,matrixPalette[i4][1].w,matrixPalette[i4][2].w)*w.w; + + mat4 ret; + + ret[0] = vec4(mat[0], 0); + ret[1] = vec4(mat[1], 0); + ret[2] = vec4(mat[2], 0); + ret[3] = vec4(trans, 1.0); + + return ret; } + diff --git a/indra/newview/app_settings/shaders/class1/deferred/SSAOF.glsl b/indra/newview/app_settings/shaders/class1/deferred/SSAOF.glsl new file mode 100644 index 0000000000..acb2f173ed --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/SSAOF.glsl @@ -0,0 +1,119 @@ +/** + * @file sunLightF.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2007, 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$ + */ + + + +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_color; +#else +#define frag_color gl_FragColor +#endif + +VARYING vec2 vary_fragcoord; + +uniform sampler2D depthMapDownsampled; +uniform sampler2D normalMap; +uniform sampler2D noiseMap; + +uniform mat4 inv_proj; + +uniform float ssao_radius; +uniform float ssao_max_radius; +uniform float ssao_factor; +uniform vec2 kern_scale; +uniform vec2 noise_scale; + +vec3 decode_normal(vec2 enc); +vec4 getPosition(vec2 pos_screen); + +vec2 getKern(int i) +{ + vec2 kern[8]; + // exponentially (^2) distant occlusion samples spread around origin + kern[0] = vec2(-1.0, 0.0) * (0.125*0.125*.9+.1); + kern[1] = vec2(1.0, 0.0) * (0.250*0.250*.9+.1); + kern[2] = vec2(0.0, 1.0) * (0.375*0.375*.9+.1); + kern[3] = vec2(0.0, -1.0) * (0.500*0.500*.9+.1); + kern[4] = vec2(0.7071, 0.7071) * (0.625*0.625*.9+.1); + kern[5] = vec2(-0.7071, -0.7071) * (0.750*0.750*.9+.1); + kern[6] = vec2(-0.7071, 0.7071) * (0.875*0.875*.9+.1); + kern[7] = vec2(0.7071, -0.7071) * (1.000*1.000*.9+.1); + + return kern[i]; +} + +//calculate decreases in ambient lighting when crowded out (SSAO) +float calcAmbientOcclusion(vec4 pos, vec3 norm) +{ + vec2 pos_screen = vary_fragcoord.xy; + vec2 noise_reflect = texture2D(noiseMap, vary_fragcoord.xy * noise_scale).xy; + + // We treat the first sample as the origin, which definitely doesn't obscure itself thanks to being visible for sampling in the first place. + float points = 1.0; + float angle_hidden = 0.0; + + // use a kernel scale that diminishes with distance. + // a scale of less than 32 is just wasting good samples, though. + vec2 scale = max(32.0, min(ssao_radius / -pos.z, ssao_max_radius)) * kern_scale; + + // it was found that keeping # of samples a constant was the fastest, probably due to compiler optimizations (unrolling?) + for (int i = 0; i < 8; i++) + { + vec2 samppos_screen = pos_screen + scale * reflect(getKern(i), noise_reflect); + vec3 samppos_world = getPosition(samppos_screen).xyz; + + vec3 diff = samppos_world - pos.xyz; + + if (diff.z < ssao_factor && diff.z != 0.0) + { + float dist = length(diff); + float angrel = max(0.0, dot(norm.xyz, diff/dist)); + float distrel = 1.0/(1.0+dist*dist); + float samplehidden = min(angrel, distrel); + + angle_hidden += (samplehidden); + points += 1.0; + } + } + + angle_hidden /= points; + + float rtn = (1.0 - angle_hidden); + return (rtn * rtn) * (rtn * rtn); //Pow2 to increase darkness to match previous behavior. +} + +void main() +{ + vec2 pos_screen = vary_fragcoord.xy; + + //try doing an unproject here + + vec4 pos = getPosition(pos_screen); + + vec3 norm = texture2D(normalMap, pos_screen).xyz; + norm = decode_normal(norm.xy); + + frag_color = vec4(calcAmbientOcclusion(pos,norm),0,0,0); +} diff --git a/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl b/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl index dd87ddb330..334c3e0dbf 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl @@ -23,7 +23,11 @@ * $/LicenseInfo$ */ -#extension GL_ARB_texture_rectangle : enable + + +#define INDEXED 1 +#define NON_INDEXED 2 +#define NON_INDEXED_NO_COLOR 3 #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_color; @@ -31,43 +35,539 @@ out vec4 frag_color; #define frag_color gl_FragColor #endif -uniform sampler2DRect depthMap; +//uniform float display_gamma; +uniform vec4 gamma; +uniform vec4 lightnorm; +uniform vec4 sunlight_color; +uniform vec4 ambient; +uniform vec4 blue_horizon; +uniform vec4 blue_density; +uniform float haze_horizon; +uniform float haze_density; +uniform float cloud_shadow; +uniform float density_multiplier; +uniform float distance_multiplier; +uniform float max_y; +uniform vec4 glow; +uniform float scene_light_strength; +uniform mat3 env_mat; + +uniform vec3 sun_dir; -vec4 diffuseLookup(vec2 texcoord); +#if HAS_SHADOW +uniform sampler2DShadow shadowMap0; +uniform sampler2DShadow shadowMap1; +uniform sampler2DShadow shadowMap2; +uniform sampler2DShadow shadowMap3; +//uniform sampler2D noiseMap; //Random dither. -uniform vec2 screen_res; +uniform vec2 shadow_res; -vec3 atmosLighting(vec3 light); -vec3 scaleSoftClip(vec3 light); +uniform mat4 shadow_matrix[6]; +uniform vec4 shadow_clip; +uniform float shadow_bias; + +#endif + +#ifdef USE_DIFFUSE_TEX +uniform sampler2D diffuseMap; +#endif + +#ifdef IS_AVATAR_SKIN +uniform float minimum_alpha; +#endif -VARYING vec3 vary_ambient; -VARYING vec3 vary_directional; VARYING vec3 vary_fragcoord; VARYING vec3 vary_position; -VARYING vec3 vary_pointlight_col; +VARYING vec2 vary_texcoord0; +VARYING vec3 vary_norm; +#ifdef USE_VERTEX_COLOR VARYING vec4 vertex_color; -VARYING vec2 vary_texcoord0; +#endif + +vec3 vary_PositionEye; +vec3 vary_SunlitColor; +vec3 vary_AmblitColor; +vec3 vary_AdditiveColor; +vec3 vary_AtmosAttenuation; uniform mat4 inv_proj; +uniform vec4 light_position[8]; +uniform vec3 light_direction[8]; +uniform vec3 light_attenuation[8]; +uniform vec3 light_diffuse[8]; + +vec2 encode_normal(vec3 n); +vec3 decode_normal(vec2 enc); +vec3 srgb_to_linear(vec3 cs); +vec3 linear_to_srgb(vec3 cl); + +vec3 calcDirectionalLight(vec3 n, vec3 l) +{ + float a = max(dot(n,l),0.0); + a = pow(a, 1.0/1.3); + return vec3(a,a,a); +} + +vec3 calcPointLightOrSpotLight(vec3 light_col, vec3 diffuse, vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float fa, float is_pointlight) +{ + //get light vector + vec3 lv = lp.xyz-v; + + //get distance + float d = length(lv); + + float da = 1.0; + + vec3 col = vec3(0); + + if (d > 0.0 && la > 0.0 && fa > 0.0) + { + //normalize light vector + lv = normalize(lv); + + //distance attenuation + float dist = d/la; + float dist_atten = clamp(1.0-(dist-1.0*(1.0-fa))/fa, 0.0, 1.0); + dist_atten *= dist_atten; + dist_atten *= 2.0; + + // spotlight coefficient. + float spot = max(dot(-ln, lv), is_pointlight); + da *= spot*spot; // GL_SPOT_EXPONENT=2 + + //angular attenuation + da *= max(dot(n, lv), 0.0); + + float lit = max(da * dist_atten,0.0); + + col = light_col * lit * diffuse; + + // no spec for alpha shader... + } + + return max(col, vec3(0.0,0.0,0.0)); +} + +#if HAS_SHADOW +float pcfShadow(sampler2DShadow shadowMap, vec4 stc, vec2 pos_screen) +{ + stc.xyz /= stc.w; + stc.z += shadow_bias; + + //stc.x += (((texture2D(noiseMap, pos_screen/128.0).x)-.5)/shadow_res.x); //Random dither. + stc.x = floor(stc.x*shadow_res.x + fract(pos_screen.y*0.666666666))/shadow_res.x; // add some chaotic jitter to X sample pos according to Y to disguise the snapping going on here + + float cs = shadow2D(shadowMap, stc.xyz).x; + + float shadow = cs; + + shadow += shadow2D(shadowMap, stc.xyz+vec3(2.0/shadow_res.x, 1.5/shadow_res.y, 0.0)).x; + shadow += shadow2D(shadowMap, stc.xyz+vec3(1.0/shadow_res.x, -1.5/shadow_res.y, 0.0)).x; + shadow += shadow2D(shadowMap, stc.xyz+vec3(-1.0/shadow_res.x, 1.5/shadow_res.y, 0.0)).x; + shadow += shadow2D(shadowMap, stc.xyz+vec3(-2.0/shadow_res.x, -1.5/shadow_res.y, 0.0)).x; + + return shadow*0.2; +} +#endif + +#ifdef WATER_FOG +uniform vec4 waterPlane; +uniform vec4 waterFogColor; +uniform float waterFogDensity; +uniform float waterFogKS; + +vec4 applyWaterFogDeferred(vec3 pos, vec4 color) +{ + //normalize view vector + vec3 view = normalize(pos); + float es = -(dot(view, waterPlane.xyz)); + + //find intersection point with water plane and eye vector + + //get eye depth + float e0 = max(-waterPlane.w, 0.0); + + vec3 int_v = waterPlane.w > 0.0 ? view * waterPlane.w/es : vec3(0.0, 0.0, 0.0); + + //get object depth + float depth = length(pos - int_v); + + //get "thickness" of water + float l = max(depth, 0.1); + + float kd = waterFogDensity; + float ks = waterFogKS; + vec4 kc = waterFogColor; + + float F = 0.98; + + float t1 = -kd * pow(F, ks * e0); + float t2 = kd + ks * es; + float t3 = pow(F, t2*l) - 1.0; + + float L = min(t1/t2*t3, 1.0); + + float D = pow(0.98, l*kd); + + color.rgb = color.rgb * D + kc.rgb * L; + color.a = kc.a + color.a; + + return color; +} +#endif + +vec3 getSunlitColor() +{ + return vary_SunlitColor; +} +vec3 getAmblitColor() +{ + return vary_AmblitColor; +} +vec3 getAdditiveColor() +{ + return vary_AdditiveColor; +} +vec3 getAtmosAttenuation() +{ + return vary_AtmosAttenuation; +} + +void setPositionEye(vec3 v) +{ + vary_PositionEye = v; +} + +void setSunlitColor(vec3 v) +{ + vary_SunlitColor = v; +} + +void setAmblitColor(vec3 v) +{ + vary_AmblitColor = v; +} + +void setAdditiveColor(vec3 v) +{ + vary_AdditiveColor = v; +} + +void setAtmosAttenuation(vec3 v) +{ + vary_AtmosAttenuation = v; +} + +void calcAtmospherics(vec3 inPositionEye) { + + vec3 P = inPositionEye; + setPositionEye(P); + + vec3 tmpLightnorm = lightnorm.xyz; + + vec3 Pn = normalize(P); + float Plen = length(P); + + vec4 temp1 = vec4(0); + vec3 temp2 = vec3(0); + vec4 blue_weight; + vec4 haze_weight; + vec4 sunlight = sunlight_color; + vec4 light_atten; + + //sunlight attenuation effect (hue and brightness) due to atmosphere + //this is used later for sunlight modulation at various altitudes + light_atten = (blue_density + vec4(haze_density * 0.25)) * (density_multiplier * max_y); + //I had thought blue_density and haze_density should have equal weighting, + //but attenuation due to haze_density tends to seem too strong + + temp1 = blue_density + vec4(haze_density); + blue_weight = blue_density / temp1; + haze_weight = vec4(haze_density) / temp1; + + //(TERRAIN) compute sunlight from lightnorm only (for short rays like terrain) + temp2.y = max(0.0, tmpLightnorm.y); + temp2.y = 1. / temp2.y; + sunlight *= exp( - light_atten * temp2.y); + + // main atmospheric scattering line integral + temp2.z = Plen * density_multiplier; + + // Transparency (-> temp1) + // ATI Bugfix -- can't store temp1*temp2.z*distance_multiplier in a variable because the ati + // compiler gets confused. + temp1 = exp(-temp1 * temp2.z * distance_multiplier); + + //final atmosphere attenuation factor + setAtmosAttenuation(temp1.rgb); + + //compute haze glow + //(can use temp2.x as temp because we haven't used it yet) + temp2.x = dot(Pn, tmpLightnorm.xyz); + temp2.x = 1. - temp2.x; + //temp2.x is 0 at the sun and increases away from sun + temp2.x = max(temp2.x, .03); //was glow.y + //set a minimum "angle" (smaller glow.y allows tighter, brighter hotspot) + temp2.x *= glow.x; + //higher glow.x gives dimmer glow (because next step is 1 / "angle") + temp2.x = pow(temp2.x, glow.z); + //glow.z should be negative, so we're doing a sort of (1 / "angle") function + + //add "minimum anti-solar illumination" + temp2.x += .25; + + //increase ambient when there are more clouds + vec4 tmpAmbient = ambient + (vec4(1.) - ambient) * cloud_shadow * 0.5; + + //haze color + setAdditiveColor( + vec3(blue_horizon * blue_weight * (sunlight*(1.-cloud_shadow) + tmpAmbient) + + (haze_horizon * haze_weight) * (sunlight*(1.-cloud_shadow) * temp2.x + + tmpAmbient))); + + //brightness of surface both sunlight and ambient + setSunlitColor(vec3(sunlight * .5)); + setAmblitColor(vec3(tmpAmbient * .25)); + setAdditiveColor(getAdditiveColor() * vec3(1.0 - temp1)); +} + +vec3 atmosLighting(vec3 light) +{ + light *= getAtmosAttenuation().r; + light += getAdditiveColor(); + return (2.0 * light); +} + +vec3 atmosTransport(vec3 light) { + light *= getAtmosAttenuation().r; + light += getAdditiveColor() * 2.0; + return light; +} +vec3 atmosGetDiffuseSunlightColor() +{ + return getSunlitColor(); +} + +vec3 scaleDownLight(vec3 light) +{ + return (light / vec3(scene_light_strength, scene_light_strength, scene_light_strength)); +} + +vec3 scaleUpLight(vec3 light) +{ + return (light * vec3(scene_light_strength, scene_light_strength, scene_light_strength)); +} + +vec3 atmosAmbient(vec3 light) +{ + return getAmblitColor() + (light * vec3(0.5f, 0.5f, 0.5f)); +} + +vec3 atmosAffectDirectionalLight(float lightIntensity) +{ + return getSunlitColor() * vec3(lightIntensity, lightIntensity, lightIntensity); +} + +vec3 scaleSoftClip(vec3 light) +{ + //soft clip effect: + vec3 zeroes = vec3(0.0f, 0.0f, 0.0f); + vec3 ones = vec3(1.0f, 1.0f, 1.0f); + + light = ones - clamp(light, zeroes, ones); + light = ones - pow(light, gamma.xxx); + + return light; +} + +vec3 fullbrightAtmosTransport(vec3 light) { + float brightness = dot(light.rgb, vec3(0.33333)); + + return mix(atmosTransport(light.rgb), light.rgb + getAdditiveColor().rgb, brightness * brightness); +} + +vec3 fullbrightScaleSoftClip(vec3 light) +{ + //soft clip effect: + return light; +} + void main() { - vec2 frag = vary_fragcoord.xy/vary_fragcoord.z*0.5+0.5; - frag *= screen_res; +#ifdef USE_INDEXED_TEX + vec4 diff = diffuseLookup(vary_texcoord0.xy); +#else + vec4 diff = texture2D(diffuseMap,vary_texcoord0.xy); +#endif +#ifdef USE_VERTEX_COLOR + float final_alpha = diff.a * vertex_color.a; + diff.rgb *= vertex_color.rgb; +#else + float final_alpha = diff.a; +#endif + +#ifdef IS_AVATAR_SKIN + if(final_alpha < minimum_alpha) + { + discard; + } +#endif +/*#ifdef FOR_IMPOSTOR + // Insure we don't pollute depth with invis pixels in impostor rendering + // + if (final_alpha < 0.01) + { + discard; + } +#endif*/ + + //Always do this. + if (final_alpha < 0.004) + { + discard; + } vec4 pos = vec4(vary_position, 1.0); - vec4 diff= diffuseLookup(vary_texcoord0.xy); + float shadow = 1.0; - vec4 col = vec4(vary_ambient + vary_directional.rgb, vertex_color.a); - vec4 color = diff * col; +#if HAS_SHADOW + vec2 frag = vary_fragcoord.xy/vary_fragcoord.z*0.5+0.5; + vec4 spos = pos; + + if (spos.z > -shadow_clip.w) + { + shadow = 0.0; + + vec4 lpos; + + vec4 near_split = shadow_clip*-0.75; + vec4 far_split = shadow_clip*-1.25; + vec4 transition_domain = near_split-far_split; + float weight = 0.0; + + if (spos.z < near_split.z) + { + lpos = shadow_matrix[3]*spos; + + float w = 1.0; + w -= max(spos.z-far_split.z, 0.0)/transition_domain.z; + shadow += pcfShadow(shadowMap3, lpos,frag.xy)*w; + weight += w; + shadow += max((pos.z+shadow_clip.z)/(shadow_clip.z-shadow_clip.w)*2.0-1.0, 0.0); + } + + if (spos.z < near_split.y && spos.z > far_split.z) + { + lpos = shadow_matrix[2]*spos; + + float w = 1.0; + w -= max(spos.z-far_split.y, 0.0)/transition_domain.y; + w -= max(near_split.z-spos.z, 0.0)/transition_domain.z; + shadow += pcfShadow(shadowMap2, lpos,frag.xy)*w; + weight += w; + } + + if (spos.z < near_split.x && spos.z > far_split.y) + { + lpos = shadow_matrix[1]*spos; + + float w = 1.0; + w -= max(spos.z-far_split.x, 0.0)/transition_domain.x; + w -= max(near_split.y-spos.z, 0.0)/transition_domain.y; + shadow += pcfShadow(shadowMap1, lpos,frag.xy)*w; + weight += w; + } + + if (spos.z > far_split.x) + { + lpos = shadow_matrix[0]*spos; + + float w = 1.0; + w -= max(near_split.x-spos.z, 0.0)/transition_domain.x; + + shadow += pcfShadow(shadowMap0, lpos,frag.xy)*w; + weight += w; + } + + + shadow /= weight; + } + else + { + shadow = 1.0; + } +#endif + + +#ifdef FOR_IMPOSTOR + vec4 color = vec4(diff.rgb,final_alpha); //Impostor needs alpha. +#else + + vec4 gamma_diff = diff; + diff.rgb = srgb_to_linear(diff.rgb); + + vec3 norm = vary_norm; + + calcAtmospherics(pos.xyz); + + vec2 abnormal = encode_normal(norm.xyz); + norm.xyz = decode_normal(abnormal.xy); + + float da = dot(norm.xyz, sun_dir.xyz); + + float final_da = da; + final_da = min(final_da, shadow); + final_da = max(final_da, 0.0f); + final_da = min(final_da, 1.0f); + final_da = pow(final_da, 1.0/1.3); + + vec4 color = vec4(getAmblitColor(),final_alpha); + + float ambient = abs(da); + ambient *= 0.5; + ambient *= ambient; + ambient = (1.0-ambient); + + color.rgb *= ambient; + color.rgb += atmosAffectDirectionalLight(final_da); + color.rgb *= gamma_diff.rgb; + + //color.rgb = mix(diff.rgb, color.rgb, final_alpha); color.rgb = atmosLighting(color.rgb); - color.rgb = scaleSoftClip(color.rgb); - color.rgb += diff.rgb * vary_pointlight_col.rgb; + vec4 light = vec4(0,0,0,0); + + color.rgb = srgb_to_linear(color.rgb); + + #define LIGHT_LOOP(i) light.rgb += calcPointLightOrSpotLight(light_diffuse[i].rgb, diff.rgb, pos.xyz, norm, light_position[i], light_direction[i].xyz, light_attenuation[i].x, light_attenuation[i].y, light_attenuation[i].z); + + LIGHT_LOOP(1) + LIGHT_LOOP(2) + LIGHT_LOOP(3) + LIGHT_LOOP(4) + LIGHT_LOOP(5) + LIGHT_LOOP(6) + LIGHT_LOOP(7) + + // keep it linear + // + color.rgb += light.rgb; + + // straight to display gamma, we're post-deferred + // + color.rgb = linear_to_srgb(color.rgb); + +#ifdef WATER_FOG + color = applyWaterFogDeferred(pos.xyz, color); +#endif + +#endif frag_color = color; } diff --git a/indra/newview/app_settings/shaders/class1/deferred/alphaNonIndexedF.glsl b/indra/newview/app_settings/shaders/class1/deferred/alphaNonIndexedF.glsl deleted file mode 100644 index beb3290187..0000000000 --- a/indra/newview/app_settings/shaders/class1/deferred/alphaNonIndexedF.glsl +++ /dev/null @@ -1,89 +0,0 @@ -/** - * @file alphaF.glsl - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2007, 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$ - */ - -#extension GL_ARB_texture_rectangle : enable - -#ifdef DEFINE_GL_FRAGCOLOR -out vec4 frag_color; -#else -#define frag_color gl_FragColor -#endif - -uniform sampler2DRect depthMap; -uniform sampler2D diffuseMap; - - -uniform vec2 screen_res; - -vec3 atmosLighting(vec3 light); -vec3 scaleSoftClip(vec3 light); - -VARYING vec3 vary_ambient; -VARYING vec3 vary_directional; -VARYING vec3 vary_fragcoord; -VARYING vec3 vary_position; -VARYING vec3 vary_pointlight_col; -VARYING vec2 vary_texcoord0; -VARYING vec4 vertex_color; - -uniform mat4 inv_proj; - -vec4 getPosition(vec2 pos_screen) -{ - float depth = texture2DRect(depthMap, pos_screen.xy).a; - vec2 sc = pos_screen.xy*2.0; - sc /= screen_res; - sc -= vec2(1.0,1.0); - vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0); - vec4 pos = inv_proj * ndc; - pos /= pos.w; - pos.w = 1.0; - return pos; -} - -void main() -{ - vec2 frag = vary_fragcoord.xy/vary_fragcoord.z*0.5+0.5; - frag *= screen_res; - - vec4 pos = vec4(vary_position, 1.0); - - vec4 diff= texture2D(diffuseMap,vary_texcoord0.xy); - - vec4 col = vec4(vary_ambient + vary_directional.rgb, vertex_color.a); - vec4 color = diff * col; - - color.rgb = atmosLighting(color.rgb); - - color.rgb = scaleSoftClip(color.rgb); - - color.rgb += diff.rgb * vary_pointlight_col.rgb; - - frag_color = color; - //frag_color = vec4(1,0,1,1); - //frag_color = vec4(1,0,1,1)*shadow; - -} - diff --git a/indra/newview/app_settings/shaders/class1/deferred/alphaNonIndexedNoColorF.glsl b/indra/newview/app_settings/shaders/class1/deferred/alphaNonIndexedNoColorF.glsl deleted file mode 100644 index 1113a9845b..0000000000 --- a/indra/newview/app_settings/shaders/class1/deferred/alphaNonIndexedNoColorF.glsl +++ /dev/null @@ -1,92 +0,0 @@ -/** - * @file alphaNonIndexedNoColorF.glsl - * - * $LicenseInfo:firstyear=2005&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2005, 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$ - */ - -#extension GL_ARB_texture_rectangle : enable - -#ifdef DEFINE_GL_FRAGCOLOR -out vec4 frag_color; -#else -#define frag_color gl_FragColor -#endif - -uniform float minimum_alpha; - -uniform sampler2DRect depthMap; -uniform sampler2D diffuseMap; - -uniform vec2 screen_res; - -vec3 atmosLighting(vec3 light); -vec3 scaleSoftClip(vec3 light); - -VARYING vec3 vary_ambient; -VARYING vec3 vary_directional; -VARYING vec3 vary_fragcoord; -VARYING vec3 vary_position; -VARYING vec3 vary_pointlight_col; -VARYING vec2 vary_texcoord0; - -uniform mat4 inv_proj; - -vec4 getPosition(vec2 pos_screen) -{ - float depth = texture2DRect(depthMap, pos_screen.xy).a; - vec2 sc = pos_screen.xy*2.0; - sc /= screen_res; - sc -= vec2(1.0,1.0); - vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0); - vec4 pos = inv_proj * ndc; - pos /= pos.w; - pos.w = 1.0; - return pos; -} - -void main() -{ - vec2 frag = vary_fragcoord.xy/vary_fragcoord.z*0.5+0.5; - frag *= screen_res; - - vec4 pos = vec4(vary_position, 1.0); - - vec4 diff= texture2D(diffuseMap,vary_texcoord0.xy); - - if (diff.a < minimum_alpha) - { - discard; - } - - vec4 col = vec4(vary_ambient + vary_directional.rgb, 1.0); - vec4 color = diff * col; - - - color.rgb = atmosLighting(color.rgb); - - color.rgb = scaleSoftClip(color.rgb); - - color.rgb += diff.rgb * vary_pointlight_col.rgb; - - frag_color = color; -} - diff --git a/indra/newview/app_settings/shaders/class1/deferred/alphaSkinnedV.glsl b/indra/newview/app_settings/shaders/class1/deferred/alphaSkinnedV.glsl deleted file mode 100644 index 5a0e8ff684..0000000000 --- a/indra/newview/app_settings/shaders/class1/deferred/alphaSkinnedV.glsl +++ /dev/null @@ -1,144 +0,0 @@ -/** - * @file alphaSkinnedV.glsl - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2007, 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$ - */ - -uniform mat4 projection_matrix; -uniform mat4 modelview_matrix; - -ATTRIBUTE vec3 position; -ATTRIBUTE vec3 normal; -ATTRIBUTE vec4 diffuse_color; -ATTRIBUTE vec2 texcoord0; - -mat4 getObjectSkinnedTransform(); -void calcAtmospherics(vec3 inPositionEye); - -float calcDirectionalLight(vec3 n, vec3 l); - -vec3 atmosAmbient(vec3 light); -vec3 atmosAffectDirectionalLight(float lightIntensity); - -VARYING vec3 vary_position; -VARYING vec3 vary_ambient; -VARYING vec3 vary_directional; -VARYING vec3 vary_fragcoord; -VARYING vec3 vary_pointlight_col; -VARYING vec4 vertex_color; -VARYING vec2 vary_texcoord0; - - -uniform float near_clip; - -uniform vec4 light_position[8]; -uniform vec3 light_direction[8]; -uniform vec3 light_attenuation[8]; -uniform vec3 light_diffuse[8]; - -float calcDirectionalLight(vec3 n, vec3 l) -{ - float a = max(dot(n,l),0.0); - return a; -} - -float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float fa, float is_pointlight) -{ - //get light vector - vec3 lv = lp.xyz-v; - - //get distance - float d = dot(lv,lv); - - float da = 0.0; - - if (d > 0.0 && la > 0.0 && fa > 0.0) - { - //normalize light vector - lv = normalize(lv); - - //distance attenuation - float dist2 = d/la; - da = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0); - - // spotlight coefficient. - float spot = max(dot(-ln, lv), is_pointlight); - da *= spot*spot; // GL_SPOT_EXPONENT=2 - - //angular attenuation - da *= max(dot(n, lv), 0.0); - } - - return da; -} - -void main() -{ - vary_texcoord0 = texcoord0; - - vec4 pos; - vec3 norm; - - mat4 trans = getObjectSkinnedTransform(); - trans = modelview_matrix * trans; - - pos = trans * vec4(position.xyz, 1.0); - - norm = position.xyz + normal.xyz; - norm = normalize(( trans*vec4(norm, 1.0) ).xyz-pos.xyz); - - vec4 frag_pos = projection_matrix * pos; - gl_Position = frag_pos; - - vary_position = pos.xyz; - - calcAtmospherics(pos.xyz); - - vec4 col = vec4(0.0, 0.0, 0.0, diffuse_color.a); - - // Collect normal lights - col.rgb += light_diffuse[2].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[2], light_direction[2], light_attenuation[2].x, light_attenuation[2].y, light_attenuation[2].z); - col.rgb += light_diffuse[3].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[3], light_direction[3], light_attenuation[3].x, light_attenuation[3].y, light_attenuation[3].z); - col.rgb += light_diffuse[4].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[4], light_direction[4], light_attenuation[4].x, light_attenuation[4].y, light_attenuation[4].z); - col.rgb += light_diffuse[5].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[5], light_direction[5], light_attenuation[5].x, light_attenuation[5].y, light_attenuation[5].z); - col.rgb += light_diffuse[6].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[6], light_direction[6], light_attenuation[6].x, light_attenuation[6].y, light_attenuation[6].z); - col.rgb += light_diffuse[7].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[7], light_direction[7], light_attenuation[7].x, light_attenuation[7].y, light_attenuation[7].z); - - vary_pointlight_col = col.rgb*diffuse_color.rgb; - - col.rgb = vec3(0,0,0); - - // Add windlight lights - col.rgb = atmosAmbient(vec3(0.)); - - vary_ambient = col.rgb*diffuse_color.rgb; - vary_directional = diffuse_color.rgb*atmosAffectDirectionalLight(max(calcDirectionalLight(norm, light_position[0].xyz), (1.0-diffuse_color.a)*(1.0-diffuse_color.a))); - - col.rgb = min(col.rgb*diffuse_color.rgb, 1.0); - - vertex_color = col; - - - - vary_fragcoord.xyz = frag_pos.xyz + vec3(0,0,near_clip); -} - - diff --git a/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl b/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl index cf38a2f4f7..4858f43afd 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl @@ -23,126 +23,117 @@ * $/LicenseInfo$ */ +#define INDEXED 1 +#define NON_INDEXED 2 +#define NON_INDEXED_NO_COLOR 3 + uniform mat3 normal_matrix; uniform mat4 texture_matrix0; +uniform mat4 projection_matrix; uniform mat4 modelview_matrix; uniform mat4 modelview_projection_matrix; ATTRIBUTE vec3 position; + +#ifdef USE_INDEXED_TEX void passTextureIndex(); +#endif + ATTRIBUTE vec3 normal; -ATTRIBUTE vec4 diffuse_color; -ATTRIBUTE vec2 texcoord0; -vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol); -void calcAtmospherics(vec3 inPositionEye); +#ifdef USE_VERTEX_COLOR +ATTRIBUTE vec4 diffuse_color; +#endif -float calcDirectionalLight(vec3 n, vec3 l); +ATTRIBUTE vec2 texcoord0; -vec3 atmosAmbient(vec3 light); -vec3 atmosAffectDirectionalLight(float lightIntensity); -vec3 scaleDownLight(vec3 light); -vec3 scaleUpLight(vec3 light); +#ifdef HAS_SKIN +mat4 getObjectSkinnedTransform(); +#else +#ifdef IS_AVATAR_SKIN +mat4 getSkinnedTransform(); +#endif +#endif -VARYING vec3 vary_ambient; -VARYING vec3 vary_directional; VARYING vec3 vary_fragcoord; VARYING vec3 vary_position; -VARYING vec3 vary_pointlight_col; +#ifdef USE_VERTEX_COLOR VARYING vec4 vertex_color; -VARYING vec2 vary_texcoord0; +#endif +VARYING vec2 vary_texcoord0; +VARYING vec3 vary_norm; uniform float near_clip; -uniform float shadow_offset; -uniform float shadow_bias; - -uniform vec4 light_position[8]; -uniform vec3 light_direction[8]; -uniform vec3 light_attenuation[8]; -uniform vec3 light_diffuse[8]; -float calcDirectionalLight(vec3 n, vec3 l) -{ - float a = max(dot(n,l),0.0); - return a; -} - -float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float fa, float is_pointlight) +void main() { - //get light vector - vec3 lv = lp.xyz-v; + vec4 pos; + vec3 norm; - //get distance - float d = dot(lv,lv); + //transform vertex +#ifdef HAS_SKIN + mat4 trans = modelview_matrix * getObjectSkinnedTransform(); - float da = 0.0; - - if (d > 0.0 && la > 0.0 && fa > 0.0) - { - //normalize light vector - lv = normalize(lv); + pos = trans * vec4(position.xyz, 1.0); - //distance attenuation - float dist2 = d/la; - da = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0); - - // spotlight coefficient. - float spot = max(dot(-ln, lv), is_pointlight); - da *= spot*spot; // GL_SPOT_EXPONENT=2 - - //angular attenuation - da *= max(dot(n, lv), 0.0); - } - - return da; -} - -void main() -{ - //transform vertex + norm = position.xyz + normal.xyz; + norm = normalize((trans * vec4(norm, 1.0)).xyz - pos.xyz); + vec4 frag_pos = projection_matrix * pos; + gl_Position = frag_pos; +#else + +#ifdef IS_AVATAR_SKIN + mat4 trans = getSkinnedTransform(); + vec4 pos_in = vec4(position.xyz, 1.0); + pos.x = dot(trans[0], pos_in); + pos.y = dot(trans[1], pos_in); + pos.z = dot(trans[2], pos_in); + pos.w = 1.0; + + norm.x = dot(trans[0].xyz, normal); + norm.y = dot(trans[1].xyz, normal); + norm.z = dot(trans[2].xyz, normal); + norm = normalize(norm); + + vec4 frag_pos = projection_matrix * pos; + gl_Position = frag_pos; +#else + norm = normalize(normal_matrix * normal); vec4 vert = vec4(position.xyz, 1.0); - passTextureIndex(); - vec4 pos = (modelview_matrix * vert); + pos = (modelview_matrix * vert); gl_Position = modelview_projection_matrix*vec4(position.xyz, 1.0); +#endif +#endif + +#ifdef USE_INDEXED_TEX + passTextureIndex(); vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; +#else + vary_texcoord0 = texcoord0; +#endif - vec3 norm = normalize(normal_matrix * normal); - - float dp_directional_light = max(0.0, dot(norm, light_position[0].xyz)); - vary_position = pos.xyz + light_position[0].xyz * (1.0-dp_directional_light)*shadow_offset; - - calcAtmospherics(pos.xyz); - - //vec4 color = calcLighting(pos.xyz, norm, diffuse_color, vec4(0.)); - vec4 col = vec4(0.0, 0.0, 0.0, diffuse_color.a); - - // Collect normal lights - col.rgb += light_diffuse[2].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[2], light_direction[2], light_attenuation[2].x, light_attenuation[2].y, light_attenuation[2].z); - col.rgb += light_diffuse[3].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[3], light_direction[3], light_attenuation[3].x, light_attenuation[3].y, light_attenuation[3].z); - col.rgb += light_diffuse[4].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[4], light_direction[4], light_attenuation[4].x, light_attenuation[4].y, light_attenuation[4].z); - col.rgb += light_diffuse[5].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[5], light_direction[5], light_attenuation[5].x, light_attenuation[5].y, light_attenuation[5].z); - col.rgb += light_diffuse[6].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[6], light_direction[6], light_attenuation[6].x, light_attenuation[6].y, light_attenuation[6].z); - col.rgb += light_diffuse[7].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[7], light_direction[7], light_attenuation[7].x, light_attenuation[7].y, light_attenuation[7].z); - - vary_pointlight_col = col.rgb*diffuse_color.rgb; - col.rgb = vec3(0,0,0); + vary_norm = norm; + vary_position = pos.xyz; - // Add windlight lights - col.rgb = atmosAmbient(vec3(0.)); - - vary_ambient = col.rgb*diffuse_color.rgb; - vary_directional.rgb = diffuse_color.rgb*atmosAffectDirectionalLight(max(calcDirectionalLight(norm, light_position[0].xyz), (1.0-diffuse_color.a)*(1.0-diffuse_color.a))); +#ifdef USE_VERTEX_COLOR + vertex_color = diffuse_color; +#endif - col.rgb = col.rgb*diffuse_color.rgb; - - vertex_color = col; +#ifdef HAS_SKIN + vary_fragcoord.xyz = frag_pos.xyz + vec3(0,0,near_clip); +#else - - +#ifdef IS_AVATAR_SKIN + vary_fragcoord.xyz = pos.xyz + vec3(0,0,near_clip); +#else pos = modelview_projection_matrix * vert; vary_fragcoord.xyz = pos.xyz + vec3(0,0,near_clip); +#endif +#endif + } + diff --git a/indra/newview/app_settings/shaders/class1/deferred/attachmentShadowV.glsl b/indra/newview/app_settings/shaders/class1/deferred/attachmentShadowV.glsl index 81961d7746..7b1360ad16 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/attachmentShadowV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/attachmentShadowV.glsl @@ -34,11 +34,11 @@ mat4 getObjectSkinnedTransform(); void main() { //transform vertex - mat4 mat = getObjectSkinnedTransform(); + mat4 mat = modelview_matrix * getObjectSkinnedTransform(); - mat = modelview_matrix * mat; vec3 pos = (mat*vec4(position.xyz, 1.0)).xyz; + vec4 p = projection_matrix * vec4(pos, 1.0); p.z = max(p.z, -p.w+0.01); gl_Position = p; diff --git a/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaNoColorV.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaNoColorV.glsl index 5f395801e5..c8ddefac26 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaNoColorV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaNoColorV.glsl @@ -47,6 +47,7 @@ VARYING vec3 vary_directional; VARYING vec3 vary_fragcoord; VARYING vec3 vary_pointlight_col; VARYING vec2 vary_texcoord0; +VARYING vec3 vary_norm; uniform float near_clip; @@ -112,6 +113,7 @@ void main() norm.y = dot(trans[1].xyz, normal); norm.z = dot(trans[2].xyz, normal); norm = normalize(norm); + vary_norm = norm; vec4 frag_pos = projection_matrix * pos; gl_Position = frag_pos; diff --git a/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaV.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaV.glsl deleted file mode 100644 index d6149fcc32..0000000000 --- a/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaV.glsl +++ /dev/null @@ -1,153 +0,0 @@ -/** - * @file avatarAlphaV.glsl - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2007, 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$ - */ - -uniform mat4 projection_matrix; - -ATTRIBUTE vec3 position; -ATTRIBUTE vec3 normal; -ATTRIBUTE vec2 texcoord0; - -vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol); -mat4 getSkinnedTransform(); -void calcAtmospherics(vec3 inPositionEye); - -float calcDirectionalLight(vec3 n, vec3 l); -float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float is_pointlight); - -vec3 atmosAmbient(vec3 light); -vec3 atmosAffectDirectionalLight(float lightIntensity); -vec3 scaleDownLight(vec3 light); -vec3 scaleUpLight(vec3 light); - -VARYING vec3 vary_position; -VARYING vec3 vary_ambient; -VARYING vec3 vary_directional; -VARYING vec3 vary_fragcoord; -VARYING vec3 vary_pointlight_col; -VARYING vec4 vertex_color; -VARYING vec2 vary_texcoord0; - - -uniform float near_clip; - -uniform vec4 color; - -uniform vec4 light_position[8]; -uniform vec3 light_direction[8]; -uniform vec3 light_attenuation[8]; -uniform vec3 light_diffuse[8]; - -float calcDirectionalLight(vec3 n, vec3 l) -{ - float a = max(dot(n,l),0.0); - return a; -} - -float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float fa, float is_pointlight) -{ - //get light vector - vec3 lv = lp.xyz-v; - - //get distance - float d = dot(lv,lv); - - float da = 0.0; - - if (d > 0.0 && la > 0.0 && fa > 0.0) - { - //normalize light vector - lv = normalize(lv); - - //distance attenuation - float dist2 = d/la; - da = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0); - - // spotlight coefficient. - float spot = max(dot(-ln, lv), is_pointlight); - da *= spot*spot; // GL_SPOT_EXPONENT=2 - - //angular attenuation - da *= max(dot(n, lv), 0.0); - } - - return da; -} - -void main() -{ - vary_texcoord0 = texcoord0; - - vec4 pos; - vec3 norm; - - mat4 trans = getSkinnedTransform(); - vec4 pos_in = vec4(position.xyz, 1.0); - pos.x = dot(trans[0], pos_in); - pos.y = dot(trans[1], pos_in); - pos.z = dot(trans[2], pos_in); - pos.w = 1.0; - - norm.x = dot(trans[0].xyz, normal); - norm.y = dot(trans[1].xyz, normal); - norm.z = dot(trans[2].xyz, normal); - norm = normalize(norm); - - vec4 frag_pos = projection_matrix * pos; - gl_Position = frag_pos; - - vary_position = pos.xyz; - - calcAtmospherics(pos.xyz); - - vec4 col = vec4(0.0, 0.0, 0.0, 1.0); - - // Collect normal lights - col.rgb += light_diffuse[2].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[2], light_direction[2], light_attenuation[2].x, light_attenuation[2].y, light_attenuation[2].z); - col.rgb += light_diffuse[3].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[3], light_direction[3], light_attenuation[3].x, light_attenuation[3].y, light_attenuation[3].z); - col.rgb += light_diffuse[4].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[4], light_direction[4], light_attenuation[4].x, light_attenuation[4].y, light_attenuation[4].z); - col.rgb += light_diffuse[5].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[5], light_direction[5], light_attenuation[5].x, light_attenuation[5].y, light_attenuation[5].z); - col.rgb += light_diffuse[6].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[6], light_direction[6], light_attenuation[6].x, light_attenuation[6].y, light_attenuation[6].z); - col.rgb += light_diffuse[7].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[7], light_direction[7], light_attenuation[7].x, light_attenuation[7].y, light_attenuation[7].z); - - vary_pointlight_col = col.rgb*color.rgb; - - col.rgb = vec3(0,0,0); - - // Add windlight lights - col.rgb = atmosAmbient(vec3(0.)); - - vary_ambient = col.rgb*color.rgb; - vary_directional = color.rgb*atmosAffectDirectionalLight(max(calcDirectionalLight(norm, light_position[0].xyz), 0.0)); - - col.rgb = col.rgb * color.rgb; - - vertex_color = col; - - - - vary_fragcoord.xyz = frag_pos.xyz + vec3(0,0,near_clip); -} - - diff --git a/indra/newview/app_settings/shaders/class1/deferred/avatarF.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarF.glsl index cf57a33d92..e52ff0e22f 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/avatarF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/avatarF.glsl @@ -31,25 +31,18 @@ out vec4 frag_data[3]; uniform sampler2D diffuseMap; +uniform float minimum_alpha; + VARYING vec3 vary_normal; VARYING vec2 vary_texcoord0; -vec3 pack(vec3 norm) -{ -//#define PACK_NORMALS -#ifdef PACK_NORMALS - float p = sqrt(8.0*norm.z+8.0); - return vec3(norm.xy/p + 0.5, 0.0); -#else - return norm.xyz*0.5+0.5; -#endif -} +vec2 encode_normal(vec3 n); void main() { vec4 diff = texture2D(diffuseMap, vary_texcoord0.xy); - if (diff.a < 0.2) + if (diff.a < minimum_alpha) { discard; } @@ -57,6 +50,6 @@ void main() frag_data[0] = vec4(diff.rgb, 0.0); frag_data[1] = vec4(0,0,0,0); vec3 nvn = normalize(vary_normal); - frag_data[2] = vec4(pack(nvn), 0.0); + frag_data[2] = vec4(encode_normal(nvn.xyz), 0.0, 0.0); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl index 9a9b889da2..27d2991b17 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl @@ -23,7 +23,7 @@ * $/LicenseInfo$ */ -#extension GL_ARB_texture_rectangle : enable + #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_color; @@ -31,62 +31,43 @@ out vec4 frag_color; #define frag_color gl_FragColor #endif -uniform sampler2DRect depthMap; -uniform sampler2DRect normalMap; -uniform sampler2DRect lightMap; +uniform sampler2D depthMap; +uniform sampler2D normalMap; +uniform sampler2D lightMap; uniform float dist_factor; uniform float blur_size; uniform vec2 delta; -uniform vec3 kern[4]; -uniform float kern_scale; +uniform vec2 kern_scale; VARYING vec2 vary_fragcoord; uniform mat4 inv_proj; -uniform vec2 screen_res; - -vec3 getKern(int i) -{ - return kern[i]; -} -vec4 getPosition(vec2 pos_screen) -{ - float depth = texture2DRect(depthMap, pos_screen.xy).r; - vec2 sc = pos_screen.xy*2.0; - sc /= screen_res; - sc -= vec2(1.0,1.0); - vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0); - vec4 pos = inv_proj * ndc; - pos /= pos.w; - pos.w = 1.0; - return pos; -} +vec3 decode_normal(vec2 enc); +vec4 getPosition(vec2 pos_screen); -vec3 unpack(vec2 tc) +vec2 getKern(int i) { -//#define PACK_NORMALS -#ifdef PACK_NORMALS - vec2 enc = texture2DRect(normalMap, tc).xy; - enc = enc*4.0-2.0; - float prod = dot(enc,enc); - return vec3(enc*sqrt(1.0-prod*.25),1.0-prod*.5); -#else - vec3 norm = texture2DRect(normalMap, tc).xyz; - return norm*2.0-1.0; -#endif + vec2 kern[4]; + + kern[0] = vec2(0.3989422804,0.1994711402); + kern[1] = vec2(0.2419707245,0.1760326634); + kern[2] = vec2(0.0539909665,0.1209853623); + kern[3] = vec2(0.0044318484,0.0647587978); + return kern[i]; } void main() { - vec2 tc = vary_fragcoord.xy; - vec3 norm = unpack(tc); // unpack norm + vec2 tc = vary_fragcoord.xy; + vec3 norm = texture2D(normalMap, tc).xyz; + norm = decode_normal(norm.xy); // unpack norm vec3 pos = getPosition(tc).xyz; - vec4 ccol = texture2DRect(lightMap, tc).rgba; - - vec2 dlt = kern_scale * delta / (vec2(1.0)+norm.xy*norm.xy); + vec4 ccol = texture2D(lightMap, tc).rgba; + + vec2 dlt = delta / (vec2(1.0)+norm.xy*norm.xy); dlt /= max(-pos.z*dist_factor, 1.0); vec2 defined_weight = getKern(0).xy; // special case the first (centre) sample's weight in the blur; we have to sample it anyway so we get it for 'free' @@ -96,35 +77,39 @@ void main() float pointplanedist_tolerance_pow2 = pos.z*-0.001; // perturb sampling origin slightly in screen-space to hide edge-ghosting artifacts where smoothing radius is quite large - vec2 tc_v = fract(0.5 * tc.xy); // we now have floor(mod(tc,2.0))*0.5 + vec2 tc_v = fract(0.5 * tc.xy / kern_scale); // we now have floor(mod(tc,2.0))*0.5 float tc_mod = 2.0 * abs(tc_v.x - tc_v.y); // diff of x,y makes checkerboard - tc += ( (tc_mod - 0.5) * getKern(1).z * dlt * 0.5 ); + tc += ( (tc_mod - 0.5) * dlt * 0.5 ) * kern_scale; for (int i = 1; i < 4; i++) { - vec2 samptc = (tc + getKern(i).z * dlt); - vec3 samppos = getPosition(samptc).xyz; + vec2 samptc = (tc + i * dlt); + vec3 samppos = getPosition(samptc).xyz; float d = dot(norm.xyz, samppos.xyz-pos.xyz);// dist from plane + if (d*d <= pointplanedist_tolerance_pow2) { - col += texture2DRect(lightMap, samptc)*getKern(i).xyxx; - defined_weight += getKern(i).xy; + vec4 weight = getKern(i).xyxx; + col += texture2D(lightMap, samptc)*weight; + defined_weight += weight.xy; } } for (int i = 1; i < 4; i++) { - vec2 samptc = (tc - getKern(i).z * dlt); - vec3 samppos = getPosition(samptc).xyz; + vec2 samptc = (tc - i * dlt); + vec3 samppos = getPosition(samptc).xyz; float d = dot(norm.xyz, samppos.xyz-pos.xyz);// dist from plane + if (d*d <= pointplanedist_tolerance_pow2) { - col += texture2DRect(lightMap, samptc)*getKern(i).xyxx; - defined_weight += getKern(i).xy; + vec4 weight = getKern(i).xyxx; + col += texture2D(lightMap, samptc)*weight; + defined_weight += weight.xy; } } col /= defined_weight.xyxx; - col.y *= col.y; // delinearize SSAO effect post-blur + //col.y *= col.y; // delinearize SSAO effect post-blur // Singu note: Performed pre-blur as to remove blur requirement frag_color = col; } diff --git a/indra/newview/app_settings/shaders/class1/deferred/blurLightV.glsl b/indra/newview/app_settings/shaders/class1/deferred/blurLightV.glsl deleted file mode 100644 index 212f7e56ad..0000000000 --- a/indra/newview/app_settings/shaders/class1/deferred/blurLightV.glsl +++ /dev/null @@ -1,39 +0,0 @@ -/** - * @file blurLightF.glsl - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2007, 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$ - */ - -uniform mat4 modelview_projection_matrix; - -ATTRIBUTE vec3 position; - -VARYING vec2 vary_fragcoord; -uniform vec2 screen_res; - -void main() -{ - //transform vertex - vec4 pos = modelview_projection_matrix * vec4(position.xyz, 1.0); - gl_Position = pos; - vary_fragcoord = (pos.xy*0.5+0.5)*screen_res; -} diff --git a/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl b/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl index db80a8e870..3827f4759c 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl @@ -39,16 +39,7 @@ VARYING vec3 vary_mat2; VARYING vec4 vertex_color; VARYING vec2 vary_texcoord0; -vec3 pack(vec3 norm) -{ -//#define PACK_NORMALS -#ifdef PACK_NORMALS - float p = sqrt(8.0*norm.z+8.0); - return vec3(norm.xy/p + 0.5, 0.0); -#else - return norm.xyz*0.5+0.5; -#endif -} +vec2 encode_normal(vec3 n); void main() { @@ -63,5 +54,5 @@ void main() frag_data[1] = vertex_color.aaaa; // spec //frag_data[1] = vec4(vec3(vertex_color.a), vertex_color.a+(1.0-vertex_color.a)*vertex_color.a); // spec - from former class3 - maybe better, but not so well tested vec3 nvn = normalize(tnorm); - frag_data[2] = vec4(pack(nvn), 0.0); + frag_data[2] = vec4(encode_normal(nvn.xyz), vertex_color.a, 0.0); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/bumpSkinnedV.glsl b/indra/newview/app_settings/shaders/class1/deferred/bumpSkinnedV.glsl index 8ba75010a2..8bc0589681 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/bumpSkinnedV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/bumpSkinnedV.glsl @@ -30,7 +30,7 @@ ATTRIBUTE vec3 position; ATTRIBUTE vec4 diffuse_color; ATTRIBUTE vec3 normal; ATTRIBUTE vec2 texcoord0; -ATTRIBUTE vec3 binormal; +ATTRIBUTE vec4 tangent; VARYING vec3 vary_mat0; VARYING vec3 vary_mat1; @@ -44,16 +44,14 @@ void main() { vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; - mat4 mat = getObjectSkinnedTransform(); - - mat = modelview_matrix * mat; + mat4 mat = modelview_matrix * getObjectSkinnedTransform(); vec3 pos = (mat*vec4(position.xyz, 1.0)).xyz; vec3 n = normalize((mat * vec4(normal.xyz+position.xyz, 1.0)).xyz-pos.xyz); - vec3 b = normalize((mat * vec4(binormal.xyz+position.xyz, 1.0)).xyz-pos.xyz); - vec3 t = cross(b, n); + vec3 t = normalize((mat * vec4(tangent.xyz+position.xyz, 1.0)).xyz-pos.xyz); + vec3 b = cross(n, t) * tangent.w; vary_mat0 = vec3(t.x, b.x, n.x); vary_mat1 = vec3(t.y, b.y, n.y); diff --git a/indra/newview/app_settings/shaders/class1/deferred/bumpV.glsl b/indra/newview/app_settings/shaders/class1/deferred/bumpV.glsl index c8d38bb8f7..9f9749394e 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/bumpV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/bumpV.glsl @@ -31,7 +31,7 @@ ATTRIBUTE vec3 position; ATTRIBUTE vec4 diffuse_color; ATTRIBUTE vec3 normal; ATTRIBUTE vec2 texcoord0; -ATTRIBUTE vec3 binormal; +ATTRIBUTE vec4 tangent; VARYING vec3 vary_mat0; VARYING vec3 vary_mat1; @@ -46,8 +46,8 @@ void main() vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; vec3 n = normalize(normal_matrix * normal); - vec3 b = normalize(normal_matrix * binormal); - vec3 t = cross(b, n); + vec3 t = normalize(normal_matrix * tangent.xyz); + vec3 b = cross(n, t) * tangent.w; vary_mat0 = vec3(t.x, b.x, n.x); vary_mat1 = vec3(t.y, b.y, n.y); diff --git a/indra/newview/app_settings/shaders/class1/deferred/cloudsF.glsl b/indra/newview/app_settings/shaders/class1/deferred/cloudsF.glsl index 9f6b1ea1f0..bb10930826 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/cloudsF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/cloudsF.glsl @@ -102,11 +102,6 @@ void main() /// Gamma correct for WL (soft clip effect). frag_data[0] = vec4(scaleSoftClip(color.rgb), alpha1); frag_data[1] = vec4(0.0,0.0,0.0,0.0); -//#define PACK_NORMALS -#ifdef PACK_NORMALS frag_data[2] = vec4(0.5,0.5,0.0,0.0); -#else - frag_data[2] = vec4(0.0,0.0,1.0,0.0); -#endif } diff --git a/indra/newview/app_settings/shaders/class1/deferred/cofF.glsl b/indra/newview/app_settings/shaders/class1/deferred/cofF.glsl index ccbc3c557c..16117acb3d 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/cofF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/cofF.glsl @@ -23,7 +23,7 @@ * $/LicenseInfo$ */ -#extension GL_ARB_texture_rectangle : enable + #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_color; @@ -31,8 +31,8 @@ out vec4 frag_color; #define frag_color gl_FragColor #endif -uniform sampler2DRect diffuseRect; -uniform sampler2DRect depthMap; +uniform sampler2D diffuseRect; +uniform sampler2D depthMap; uniform sampler2D bloomMap; uniform float depth_cutoff; @@ -44,13 +44,12 @@ uniform float magnification; uniform float max_cof; uniform mat4 inv_proj; -uniform vec2 screen_res; VARYING vec2 vary_fragcoord; float getDepth(vec2 pos_screen) { - float z = texture2DRect(depthMap, pos_screen.xy).r; + float z = texture2D(depthMap, pos_screen.xy).r; z = z*2.0-1.0; vec4 ndc = vec4(0.0, 0.0, z, 1.0); vec4 p = inv_proj*ndc; @@ -78,13 +77,13 @@ void main() float depth = getDepth(tc); - vec4 diff = texture2DRect(diffuseRect, vary_fragcoord.xy); + vec4 diff = texture2D(diffuseRect, vary_fragcoord.xy); float sc = calc_cof(depth); sc = min(sc, max_cof); sc = max(sc, -max_cof); - vec4 bloom = texture2D(bloomMap, vary_fragcoord.xy/screen_res); + vec4 bloom = texture2D(bloomMap, vary_fragcoord.xy); frag_color.rgb = diff.rgb + bloom.rgb; frag_color.a = sc/max_cof*0.5+0.5; } diff --git a/indra/newview/app_settings/shaders/class1/deferred/components/utilityFuncF.glsl b/indra/newview/app_settings/shaders/class1/deferred/components/utilityFuncF.glsl new file mode 100644 index 0000000000..806e651697 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/components/utilityFuncF.glsl @@ -0,0 +1,104 @@ +/** + * @file utilityFuncF.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2007, 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$ + */ + +uniform mat4 inv_proj; +uniform vec2 screen_res; +uniform sampler2D depthMap; + +vec2 encode_normal(vec3 n) +{ + float f = sqrt(8 * n.z + 8); + return n.xy / f + 0.5; +} + +vec3 decode_normal(vec2 enc) +{ + vec2 fenc = enc*4-2; + float f = dot(fenc,fenc); + float g = sqrt(1-f/4); + vec3 n; + n.xy = fenc*g; + n.z = 1-f/2; + return n; +} + +vec4 getPosition(vec2 pos_screen) +{ + float depth = texture2D(depthMap, pos_screen.xy).r; + vec2 sc = pos_screen.xy*2.0; + sc -= vec2(1.0,1.0); + vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0); + vec4 pos = inv_proj * ndc; + pos /= pos.w; + pos.w = 1.0; + return pos; +} + +vec3 srgb_to_linear(vec3 cs) +{ + vec3 low_range = cs / vec3(12.92); + vec3 high_range = pow((cs+vec3(0.055))/vec3(1.055), vec3(2.4)); + + bvec3 lte = lessThanEqual(cs,vec3(0.04045)); + vec3 result; +#ifdef OLD_SELECT + vec3 result; + result.r = lte.r ? low_range.r : high_range.r; + result.g = lte.g ? low_range.g : high_range.g; + result.b = lte.b ? low_range.b : high_range.b; + return result; +#else + return mix(high_range, low_range, lte); +#endif +} + +vec4 srgb_to_linear(vec4 cs) +{ + return vec4(srgb_to_linear(cs.rgb), cs.a); +} + +vec3 linear_to_srgb(vec3 cl) +{ + cl = clamp(cl, vec3(0), vec3(1)); + vec3 low_range = cl * 12.92; + vec3 high_range = 1.055 * pow(cl, vec3(0.41666)) - 0.055; + + bvec3 lt = lessThan(cl,vec3(0.0031308)); +#ifdef OLD_SELECT + vec3 result; + result.r = lt.r ? low_range.r : high_range.r; + result.g = lt.g ? low_range.g : high_range.g; + result.b = lt.b ? low_range.b : high_range.b; + return result; +#else + return mix(high_range, low_range, lt); +#endif + +} + +vec4 linear_to_srgb(vec4 cl) +{ + return vec4(linear_to_srgb(cl.rgb), cl.a); +} diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskF.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskF.glsl index d31cbfa284..7310f1ebbd 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskF.glsl @@ -37,16 +37,7 @@ VARYING vec3 vary_normal; VARYING vec4 vertex_color; VARYING vec2 vary_texcoord0; -vec3 pack(vec3 norm) -{ -//#define PACK_NORMALS -#ifdef PACK_NORMALS - float p = sqrt(8.0*norm.z+8.0); - return vec3(norm.xy/p + 0.5, 0.0); -#else - return norm.xyz*0.5+0.5; -#endif -} +vec2 encode_normal(vec3 n); void main() { @@ -60,6 +51,6 @@ void main() frag_data[0] = vec4(col.rgb, 0.0); frag_data[1] = vec4(0,0,0,0); // spec vec3 nvn = normalize(vary_normal); - frag_data[2] = vec4(pack(nvn),0.0); + frag_data[2] = vec4(encode_normal(nvn.xyz), 0.0, 0.0); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskIndexedF.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskIndexedF.glsl index c65539d439..08ce605258 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskIndexedF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskIndexedF.glsl @@ -36,16 +36,7 @@ uniform float minimum_alpha; VARYING vec4 vertex_color; VARYING vec2 vary_texcoord0; -vec3 pack(vec3 norm) -{ -//#define PACK_NORMALS -#ifdef PACK_NORMALS - float p = sqrt(8.0*norm.z+8.0); - return vec3(norm.xy/p + 0.5, 0.0); -#else - return norm.xyz*0.5+0.5; -#endif -} +vec2 encode_normal(vec3 n); void main() { @@ -55,9 +46,9 @@ void main() { discard; } - + frag_data[0] = vec4(col.rgb, 0.0); frag_data[1] = vec4(0,0,0,0); vec3 nvn = normalize(vary_normal); - frag_data[2] = vec4(pack(nvn), 0.0); + frag_data[2] = vec4(encode_normal(nvn.xyz), 0.0, 0.0); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskNoColorF.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskNoColorF.glsl index 252975aad6..e6de9bcf03 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskNoColorF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskNoColorF.glsl @@ -37,16 +37,7 @@ uniform sampler2D diffuseMap; VARYING vec3 vary_normal; VARYING vec2 vary_texcoord0; -vec3 pack(vec3 norm) -{ -//#define PACK_NORMALS -#ifdef PACK_NORMALS - float p = sqrt(8.0*norm.z+8.0); - return vec3(norm.xy/p + 0.5, 0.0); -#else - return norm.xyz*0.5+0.5; -#endif -} +vec2 encode_normal(vec3 n); void main() { @@ -60,6 +51,6 @@ void main() frag_data[0] = vec4(col.rgb, 0.0); frag_data[1] = vec4(0,0,0,0); // spec vec3 nvn = normalize(vary_normal); - frag_data[2] = vec4(pack(nvn),0.0); + frag_data[2] = vec4(encode_normal(nvn.xyz), 0.0, 0.0); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseF.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseF.glsl index ac33fd2615..d104c7d025 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/diffuseF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseF.glsl @@ -35,16 +35,7 @@ VARYING vec3 vary_normal; VARYING vec4 vertex_color; VARYING vec2 vary_texcoord0; -vec3 pack(vec3 norm) -{ -//#define PACK_NORMALS -#ifdef PACK_NORMALS - float p = sqrt(8.0*norm.z+8.0); - return vec3(norm.xy/p + 0.5, 0.0); -#else - return norm.xyz*0.5+0.5; -#endif -} +vec2 encode_normal(vec3 n); void main() { @@ -53,6 +44,6 @@ void main() frag_data[1] = vertex_color.aaaa; // spec //frag_data[1] = vec4(vec3(vertex_color.a), vertex_color.a+(1.0-vertex_color.a)*vertex_color.a); // spec - from former class3 - maybe better, but not so well tested vec3 nvn = normalize(vary_normal); - frag_data[2] = vec4(pack(nvn),0.0); + frag_data[2] = vec4(encode_normal(nvn.xyz), vertex_color.a, 0.0); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseIndexedF.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseIndexedF.glsl index b97cd060de..4a195bbb34 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/diffuseIndexedF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseIndexedF.glsl @@ -33,24 +33,17 @@ VARYING vec3 vary_normal; VARYING vec4 vertex_color; VARYING vec2 vary_texcoord0; -vec3 pack(vec3 norm) -{ -//#define PACK_NORMALS -#ifdef PACK_NORMALS - float p = sqrt(8.0*norm.z+8.0); - return vec3(norm.xy/p + 0.5, 0.0); -#else - return norm.xyz*0.5+0.5; -#endif -} +vec2 encode_normal(vec3 n); void main() { vec3 col = vertex_color.rgb * diffuseLookup(vary_texcoord0.xy).rgb; + + vec3 spec; + spec.rgb = vec3(vertex_color.a); frag_data[0] = vec4(col, 0.0); - frag_data[1] = vertex_color.aaaa; // spec - //frag_data[1] = vec4(vec3(vertex_color.a), vertex_color.a+(1.0-vertex_color.a)*vertex_color.a); // spec - from former class3 - maybe better, but not so well tested + frag_data[1] = vec4(spec, vertex_color.a); // spec vec3 nvn = normalize(vary_normal); - frag_data[2] = vec4(pack(nvn),0.0); + frag_data[2] = vec4(encode_normal(nvn.xyz), vertex_color.a, 0.0); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseSkinnedV.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseSkinnedV.glsl index a74290bfcd..7a875a9bbd 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/diffuseSkinnedV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseSkinnedV.glsl @@ -41,9 +41,8 @@ void main() { vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; - mat4 mat = getObjectSkinnedTransform(); + mat4 mat = modelview_matrix * getObjectSkinnedTransform(); - mat = modelview_matrix * mat; vec3 pos = (mat*vec4(position.xyz, 1.0)).xyz; vec4 norm = vec4(position.xyz, 1.0); diff --git a/indra/newview/app_settings/shaders/class1/deferred/dofCombineF.glsl b/indra/newview/app_settings/shaders/class1/deferred/dofCombineF.glsl index a425e5062e..550d2fa073 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/dofCombineF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/dofCombineF.glsl @@ -23,7 +23,7 @@ * $/LicenseInfo$ */ -#extension GL_ARB_texture_rectangle : enable + #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_color; @@ -31,34 +31,34 @@ out vec4 frag_color; #define frag_color gl_FragColor #endif -uniform sampler2DRect diffuseRect; -uniform sampler2DRect lightMap; +uniform sampler2D diffuseRect; +uniform sampler2D lightMap; uniform mat4 inv_proj; -uniform vec2 screen_res; uniform float max_cof; uniform float res_scale; uniform float dof_width; uniform float dof_height; +uniform vec2 kern_scale; VARYING vec2 vary_fragcoord; -vec4 dofSample(sampler2DRect tex, vec2 tc) +vec4 dofSample(sampler2D tex, vec2 tc) { tc.x = min(tc.x, dof_width); tc.y = min(tc.y, dof_height); - return texture2DRect(tex, tc); + return texture2D(tex, tc); } void main() { - vec2 tc = vary_fragcoord.xy; + vec2 tc = vary_fragcoord.xy * res_scale; - vec4 dof = dofSample(diffuseRect, vary_fragcoord.xy*res_scale); + vec4 dof = dofSample(diffuseRect, tc); - vec4 diff = texture2DRect(lightMap, vary_fragcoord.xy); + vec4 diff = texture2D(lightMap, vary_fragcoord.xy); float a = min(abs(diff.a*2.0-1.0) * max_cof*res_scale*res_scale, 1.0); @@ -67,10 +67,10 @@ void main() float sc = a/res_scale; vec4 col; - col = texture2DRect(lightMap, vary_fragcoord.xy+vec2(sc,sc)); - col += texture2DRect(lightMap, vary_fragcoord.xy+vec2(-sc,sc)); - col += texture2DRect(lightMap, vary_fragcoord.xy+vec2(sc,-sc)); - col += texture2DRect(lightMap, vary_fragcoord.xy+vec2(-sc,-sc)); + col = texture2D(lightMap, vary_fragcoord.xy+vec2(sc,sc)*kern_scale); + col += texture2D(lightMap, vary_fragcoord.xy+vec2(-sc,sc)*kern_scale); + col += texture2D(lightMap, vary_fragcoord.xy+vec2(sc,-sc)*kern_scale); + col += texture2D(lightMap, vary_fragcoord.xy+vec2(-sc,-sc)*kern_scale); diff = mix(diff, col*0.25, a); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/downsampleDepthNearestF.glsl b/indra/newview/app_settings/shaders/class1/deferred/downsampleDepthNearestF.glsl new file mode 100644 index 0000000000..89eff19785 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/downsampleDepthNearestF.glsl @@ -0,0 +1,41 @@ +/** + * @file sunLightF.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2007, 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$ + */ + + + +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_color; +#else +#define frag_color gl_FragColor +#endif + +uniform sampler2D depthMap; + +VARYING vec2 vary_fragcoord; + +void main() +{ + gl_FragDepth = texture2D(depthMap, vary_fragcoord.xy).r; +} diff --git a/indra/newview/app_settings/shaders/class1/deferred/emissiveF.glsl b/indra/newview/app_settings/shaders/class1/deferred/emissiveF.glsl index 6aa4d7b4ed..4fa5f7a9bd 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/emissiveF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/emissiveF.glsl @@ -23,7 +23,7 @@ * $/LicenseInfo$ */ -#extension GL_ARB_texture_rectangle : enable + #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_color; @@ -39,14 +39,10 @@ VARYING vec2 vary_texcoord0; void main() { - float shadow = 1.0; - - vec4 color = diffuseLookup(vary_texcoord0.xy)*vertex_color; - - color.rgb = fullbrightAtmosTransport(color.rgb); - - color.rgb = fullbrightScaleSoftClip(color.rgb); + float alpha = diffuseLookup(vary_texcoord0.xy).a*vertex_color.a; + if(alpha < .01) + discard; - frag_color = color; + frag_color = vec4(0,0,0,alpha); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/emissiveV.glsl b/indra/newview/app_settings/shaders/class1/deferred/emissiveV.glsl index 115b04797f..3252b441ff 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/emissiveV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/emissiveV.glsl @@ -46,17 +46,12 @@ VARYING vec2 vary_texcoord0; void main() { - //transform vertex - vec4 vert = vec4(position.xyz, 1.0); - vec4 pos = (modelview_matrix * vert); passTextureIndex(); gl_Position = modelview_projection_matrix*vec4(position.xyz, 1.0); vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; - calcAtmospherics(pos.xyz); - vertex_color = emissive; diff --git a/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl index 36433a5827..5e73b8be0b 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl @@ -23,7 +23,7 @@ * $/LicenseInfo$ */ -#extension GL_ARB_texture_rectangle : enable + #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_color; @@ -31,23 +31,119 @@ out vec4 frag_color; #define frag_color gl_FragColor #endif +#if !HAS_DIFFUSE_LOOKUP +uniform sampler2D diffuseMap; +#endif + +VARYING vec3 vary_position; VARYING vec4 vertex_color; VARYING vec2 vary_texcoord0; -vec3 fullbrightAtmosTransport(vec3 light); -vec3 fullbrightScaleSoftClip(vec3 light); +vec3 srgb_to_linear(vec3 cs); +vec3 linear_to_srgb(vec3 cl); + +vec3 fullbrightAtmosTransportDeferred(vec3 light) +{ + return light; +} + +vec3 fullbrightScaleSoftClipDeferred(vec3 light) +{ + //soft clip effect: + return light; +} + +#ifdef HAS_ALPHA_MASK +uniform float minimum_alpha; +#endif +#ifdef WATER_FOG +uniform vec4 waterPlane; +uniform vec4 waterFogColor; +uniform float waterFogDensity; +uniform float waterFogKS; + +vec4 applyWaterFogDeferred(vec3 pos, vec4 color) +{ + //normalize view vector + vec3 view = normalize(pos); + float es = -(dot(view, waterPlane.xyz)); + + //find intersection point with water plane and eye vector + + //get eye depth + float e0 = max(-waterPlane.w, 0.0); + + vec3 int_v = waterPlane.w > 0.0 ? view * waterPlane.w/es : vec3(0.0, 0.0, 0.0); + + //get object depth + float depth = length(pos - int_v); + + //get "thickness" of water + float l = max(depth, 0.1); + + float kd = waterFogDensity; + float ks = waterFogKS; + vec4 kc = waterFogColor; + + float F = 0.98; + + float t1 = -kd * pow(F, ks * e0); + float t2 = kd + ks * es; + float t3 = pow(F, t2*l) - 1.0; + + float L = min(t1/t2*t3, 1.0); + + float D = pow(0.98, l*kd); + + color.rgb = color.rgb * D + kc.rgb * L; + color.a = kc.a + color.a; + + return color; +} +#endif void main() { - float shadow = 1.0; +#if HAS_DIFFUSE_LOOKUP + vec4 color = diffuseLookup(vary_texcoord0.xy); +#else + vec4 color = texture2D(diffuseMap, vary_texcoord0.xy); +#endif + + float final_alpha = color.a * vertex_color.a; + +#ifdef HAS_ALPHA_MASK + if (color.a < minimum_alpha) + { + discard; + } +#endif - vec4 color = diffuseLookup(vary_texcoord0.xy)*vertex_color; + color.rgb *= vertex_color.rgb; + color.rgb = srgb_to_linear(color.rgb); + color.rgb = fullbrightAtmosTransportDeferred(color.rgb); + color.rgb = fullbrightScaleSoftClipDeferred(color.rgb); - color.rgb = fullbrightAtmosTransport(color.rgb); + color.rgb = linear_to_srgb(color.rgb); - color.rgb = fullbrightScaleSoftClip(color.rgb); +#ifdef WATER_FOG + vec3 pos = vary_position; + vec4 fogged = applyWaterFogDeferred(pos, vec4(color.rgb, final_alpha)); + color.rgb = fogged.rgb; +#ifndef HAS_ALPHA_MASK + color.a = fogged.a; +#endif +#else +#ifndef HAS_ALPHA_MASK + color.a = final_alpha; +#endif +#endif +#ifdef HAS_ALPHA_MASK + color.a = 0.0; +#endif - frag_color = color; + frag_color.rgb = color.rgb; + frag_color.a = color.a; } diff --git a/indra/newview/app_settings/shaders/class1/deferred/fullbrightShinyF.glsl b/indra/newview/app_settings/shaders/class1/deferred/fullbrightShinyF.glsl new file mode 100644 index 0000000000..f351ec276e --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/fullbrightShinyF.glsl @@ -0,0 +1,70 @@ +/** + * @file fullbrightShinyF.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2007, 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$ + */ + +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_color; +#else +#define frag_color gl_FragColor +#endif + +#ifndef diffuseLookup +uniform sampler2D diffuseMap; +#endif + +VARYING vec4 vertex_color; +VARYING vec2 vary_texcoord0; +VARYING vec3 vary_texcoord1; + +uniform samplerCube environmentMap; + +vec3 fullbrightShinyAtmosTransport(vec3 light); +vec3 fullbrightScaleSoftClip(vec3 light); + +void main() +{ +#if HAS_DIFFUSE_LOOKUP + vec4 color = diffuseLookup(vary_texcoord0.xy); +#else + vec4 color = texture2D(diffuseMap, vary_texcoord0.xy); +#endif + + + color.rgb *= vertex_color.rgb; + + vec3 envColor = textureCube(environmentMap, vary_texcoord1.xyz).rgb; + color.rgb = mix(color.rgb, envColor.rgb, vertex_color.a); + + color.rgb = pow(color.rgb,vec3(2.2f,2.2f,2.2f)); + + color.rgb = fullbrightShinyAtmosTransport(color.rgb); + color.rgb = fullbrightScaleSoftClip(color.rgb); + + color.a = 0.0; + + color.rgb = pow(color.rgb, vec3(1.0/2.2)); + + frag_color = color; +} + diff --git a/indra/newview/app_settings/shaders/class1/deferred/fullbrightShinyV.glsl b/indra/newview/app_settings/shaders/class1/deferred/fullbrightShinyV.glsl new file mode 100644 index 0000000000..34bd8d445a --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/fullbrightShinyV.glsl @@ -0,0 +1,67 @@ +/** + * @file fullbrightShinyV.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2007, 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$ + */ + +uniform mat3 normal_matrix; +uniform mat4 texture_matrix0; +uniform mat4 texture_matrix1; +uniform mat4 modelview_matrix; +uniform mat4 modelview_projection_matrix; + + +void calcAtmospherics(vec3 inPositionEye); + +uniform vec4 origin; + + + +ATTRIBUTE vec3 position; +void passTextureIndex(); +ATTRIBUTE vec3 normal; +ATTRIBUTE vec4 diffuse_color; +ATTRIBUTE vec2 texcoord0; + +VARYING vec4 vertex_color; +VARYING vec2 vary_texcoord0; +VARYING vec3 vary_texcoord1; + + +void main() +{ + //transform vertex + vec4 vert = vec4(position.xyz,1.0); + passTextureIndex(); + vec4 pos = (modelview_matrix * vert); + gl_Position = modelview_projection_matrix*vec4(position.xyz, 1.0); + + vec3 norm = normalize(normal_matrix * normal); + vec3 ref = reflect(pos.xyz, -norm); + + vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; + vary_texcoord1 = (texture_matrix1*vec4(ref,1.0)).xyz; + + calcAtmospherics(pos.xyz); + + vertex_color = diffuse_color; +} diff --git a/indra/newview/app_settings/shaders/class1/deferred/fullbrightV.glsl b/indra/newview/app_settings/shaders/class1/deferred/fullbrightV.glsl index 2e6982d101..0e623aa4fb 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/fullbrightV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/fullbrightV.glsl @@ -40,6 +40,9 @@ vec3 atmosAffectDirectionalLight(float lightIntensity); vec3 scaleDownLight(vec3 light); vec3 scaleUpLight(vec3 light); +#ifdef WATER_FOG +VARYING vec3 vary_position; +#endif VARYING vec4 vertex_color; VARYING vec2 vary_texcoord0; @@ -53,11 +56,15 @@ void main() passTextureIndex(); gl_Position = modelview_projection_matrix*vec4(position.xyz, 1.0); - + +#ifdef WATER_FOG + vary_position = pos.xyz; +#endif + vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; calcAtmospherics(pos.xyz); - + vertex_color = diffuse_color; diff --git a/indra/newview/app_settings/shaders/class1/deferred/fxaaF.glsl b/indra/newview/app_settings/shaders/class1/deferred/fxaaF.glsl index e02a7b405b..aa914aa030 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/fxaaF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/fxaaF.glsl @@ -22,8 +22,6 @@ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ - -#extension GL_ARB_texture_rectangle : enable #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_color; @@ -33,7 +31,9 @@ out vec4 frag_color; #define FXAA_PC 1 //#define FXAA_GLSL_130 1 -#define FXAA_QUALITY__PRESET 12 +#ifndef FXAA_QUALITY_M_PRESET +#define FXAA_QUALITY_M_PRESET 12 +#endif /*============================================================================ @@ -66,7 +66,7 @@ Example, #define FXAA_PC 1 #define FXAA_HLSL_5 1 - #define FXAA_QUALITY__PRESET 12 + #define FXAA_QUALITY_M_PRESET 12 Or, @@ -257,6 +257,10 @@ A. Or use FXAA_GREEN_AS_LUMA. #define FXAA_GLSL_130 0 #endif /*--------------------------------------------------------------------------*/ +#ifndef FXAA_GLSL_400 + #define FXAA_GLSL_400 0 +#endif +/*--------------------------------------------------------------------------*/ #ifndef FXAA_HLSL_3 #define FXAA_HLSL_3 0 #endif @@ -343,8 +347,8 @@ A. Or use FXAA_GREEN_AS_LUMA. // 1 = API supports gather4 on alpha channel. // 0 = API does not support gather4 on alpha channel. // - #if (FXAA_GLSL_130 == 0) - #define FXAA_GATHER4_ALPHA 0 + #if (FXAA_GLSL_400 == 1) + #define FXAA_GATHER4_ALPHA 1 #endif #if (FXAA_HLSL_5 == 1) #define FXAA_GATHER4_ALPHA 1 @@ -365,7 +369,7 @@ A. Or use FXAA_GREEN_AS_LUMA. /*============================================================================ FXAA CONSOLE PS3 - TUNING KNOBS ============================================================================*/ -#ifndef FXAA_CONSOLE__PS3_EDGE_SHARPNESS +#ifndef FXAA_CONSOLE_M_PS3_EDGE_SHARPNESS // // Consoles the sharpness of edges on PS3 only. // Non-PS3 tuning is done with shader input. @@ -379,17 +383,17 @@ A. Or use FXAA_GREEN_AS_LUMA. // 2.0 is really soft (good for vector graphics inputs) // #if 1 - #define FXAA_CONSOLE__PS3_EDGE_SHARPNESS 8.0 + #define FXAA_CONSOLE_M_PS3_EDGE_SHARPNESS 8.0 #endif #if 0 - #define FXAA_CONSOLE__PS3_EDGE_SHARPNESS 4.0 + #define FXAA_CONSOLE_M_PS3_EDGE_SHARPNESS 4.0 #endif #if 0 - #define FXAA_CONSOLE__PS3_EDGE_SHARPNESS 2.0 + #define FXAA_CONSOLE_M_PS3_EDGE_SHARPNESS 2.0 #endif #endif /*--------------------------------------------------------------------------*/ -#ifndef FXAA_CONSOLE__PS3_EDGE_THRESHOLD +#ifndef FXAA_CONSOLE_M_PS3_EDGE_THRESHOLD // // Only effects PS3. // Non-PS3 tuning is done with shader input. @@ -407,9 +411,9 @@ A. Or use FXAA_GREEN_AS_LUMA. // 0.25 leaves more aliasing, and is sharper // #if 1 - #define FXAA_CONSOLE__PS3_EDGE_THRESHOLD 0.125 + #define FXAA_CONSOLE_M_PS3_EDGE_THRESHOLD 0.125 #else - #define FXAA_CONSOLE__PS3_EDGE_THRESHOLD 0.25 + #define FXAA_CONSOLE_M_PS3_EDGE_THRESHOLD 0.25 #endif #endif @@ -418,7 +422,7 @@ A. Or use FXAA_GREEN_AS_LUMA. ------------------------------------------------------------------------------ NOTE the other tuning knobs are now in the shader function inputs! ============================================================================*/ -#ifndef FXAA_QUALITY__PRESET +#ifndef FXAA_QUALITY_M_PRESET // // Choose the quality preset. // This needs to be compiled into the shader as it effects code. @@ -439,7 +443,7 @@ NOTE the other tuning knobs are now in the shader function inputs! // _ = the lowest digit is directly related to performance // _ = the highest digit is directly related to style // - #define FXAA_QUALITY__PRESET 12 + #define FXAA_QUALITY_M_PRESET 12 #endif @@ -452,198 +456,198 @@ NOTE the other tuning knobs are now in the shader function inputs! /*============================================================================ FXAA QUALITY - MEDIUM DITHER PRESETS ============================================================================*/ -#if (FXAA_QUALITY__PRESET == 10) - #define FXAA_QUALITY__PS 3 - #define FXAA_QUALITY__P0 1.5 - #define FXAA_QUALITY__P1 3.0 - #define FXAA_QUALITY__P2 12.0 +#if (FXAA_QUALITY_M_PRESET == 10) + #define FXAA_QUALITY_M_PS 3 + #define FXAA_QUALITY_M_P0 1.5 + #define FXAA_QUALITY_M_P1 3.0 + #define FXAA_QUALITY_M_P2 12.0 #endif /*--------------------------------------------------------------------------*/ -#if (FXAA_QUALITY__PRESET == 11) - #define FXAA_QUALITY__PS 4 - #define FXAA_QUALITY__P0 1.0 - #define FXAA_QUALITY__P1 1.5 - #define FXAA_QUALITY__P2 3.0 - #define FXAA_QUALITY__P3 12.0 +#if (FXAA_QUALITY_M_PRESET == 11) + #define FXAA_QUALITY_M_PS 4 + #define FXAA_QUALITY_M_P0 1.0 + #define FXAA_QUALITY_M_P1 1.5 + #define FXAA_QUALITY_M_P2 3.0 + #define FXAA_QUALITY_M_P3 12.0 #endif /*--------------------------------------------------------------------------*/ -#if (FXAA_QUALITY__PRESET == 12) - #define FXAA_QUALITY__PS 5 - #define FXAA_QUALITY__P0 1.0 - #define FXAA_QUALITY__P1 1.5 - #define FXAA_QUALITY__P2 2.0 - #define FXAA_QUALITY__P3 4.0 - #define FXAA_QUALITY__P4 12.0 +#if (FXAA_QUALITY_M_PRESET == 12) + #define FXAA_QUALITY_M_PS 5 + #define FXAA_QUALITY_M_P0 1.0 + #define FXAA_QUALITY_M_P1 1.5 + #define FXAA_QUALITY_M_P2 2.0 + #define FXAA_QUALITY_M_P3 4.0 + #define FXAA_QUALITY_M_P4 12.0 #endif /*--------------------------------------------------------------------------*/ -#if (FXAA_QUALITY__PRESET == 13) - #define FXAA_QUALITY__PS 6 - #define FXAA_QUALITY__P0 1.0 - #define FXAA_QUALITY__P1 1.5 - #define FXAA_QUALITY__P2 2.0 - #define FXAA_QUALITY__P3 2.0 - #define FXAA_QUALITY__P4 4.0 - #define FXAA_QUALITY__P5 12.0 +#if (FXAA_QUALITY_M_PRESET == 13) + #define FXAA_QUALITY_M_PS 6 + #define FXAA_QUALITY_M_P0 1.0 + #define FXAA_QUALITY_M_P1 1.5 + #define FXAA_QUALITY_M_P2 2.0 + #define FXAA_QUALITY_M_P3 2.0 + #define FXAA_QUALITY_M_P4 4.0 + #define FXAA_QUALITY_M_P5 12.0 #endif /*--------------------------------------------------------------------------*/ -#if (FXAA_QUALITY__PRESET == 14) - #define FXAA_QUALITY__PS 7 - #define FXAA_QUALITY__P0 1.0 - #define FXAA_QUALITY__P1 1.5 - #define FXAA_QUALITY__P2 2.0 - #define FXAA_QUALITY__P3 2.0 - #define FXAA_QUALITY__P4 2.0 - #define FXAA_QUALITY__P5 4.0 - #define FXAA_QUALITY__P6 12.0 +#if (FXAA_QUALITY_M_PRESET == 14) + #define FXAA_QUALITY_M_PS 7 + #define FXAA_QUALITY_M_P0 1.0 + #define FXAA_QUALITY_M_P1 1.5 + #define FXAA_QUALITY_M_P2 2.0 + #define FXAA_QUALITY_M_P3 2.0 + #define FXAA_QUALITY_M_P4 2.0 + #define FXAA_QUALITY_M_P5 4.0 + #define FXAA_QUALITY_M_P6 12.0 #endif /*--------------------------------------------------------------------------*/ -#if (FXAA_QUALITY__PRESET == 15) - #define FXAA_QUALITY__PS 8 - #define FXAA_QUALITY__P0 1.0 - #define FXAA_QUALITY__P1 1.5 - #define FXAA_QUALITY__P2 2.0 - #define FXAA_QUALITY__P3 2.0 - #define FXAA_QUALITY__P4 2.0 - #define FXAA_QUALITY__P5 2.0 - #define FXAA_QUALITY__P6 4.0 - #define FXAA_QUALITY__P7 12.0 +#if (FXAA_QUALITY_M_PRESET == 15) + #define FXAA_QUALITY_M_PS 8 + #define FXAA_QUALITY_M_P0 1.0 + #define FXAA_QUALITY_M_P1 1.5 + #define FXAA_QUALITY_M_P2 2.0 + #define FXAA_QUALITY_M_P3 2.0 + #define FXAA_QUALITY_M_P4 2.0 + #define FXAA_QUALITY_M_P5 2.0 + #define FXAA_QUALITY_M_P6 4.0 + #define FXAA_QUALITY_M_P7 12.0 #endif /*============================================================================ FXAA QUALITY - LOW DITHER PRESETS ============================================================================*/ -#if (FXAA_QUALITY__PRESET == 20) - #define FXAA_QUALITY__PS 3 - #define FXAA_QUALITY__P0 1.5 - #define FXAA_QUALITY__P1 2.0 - #define FXAA_QUALITY__P2 8.0 +#if (FXAA_QUALITY_M_PRESET == 20) + #define FXAA_QUALITY_M_PS 3 + #define FXAA_QUALITY_M_P0 1.5 + #define FXAA_QUALITY_M_P1 2.0 + #define FXAA_QUALITY_M_P2 8.0 #endif /*--------------------------------------------------------------------------*/ -#if (FXAA_QUALITY__PRESET == 21) - #define FXAA_QUALITY__PS 4 - #define FXAA_QUALITY__P0 1.0 - #define FXAA_QUALITY__P1 1.5 - #define FXAA_QUALITY__P2 2.0 - #define FXAA_QUALITY__P3 8.0 +#if (FXAA_QUALITY_M_PRESET == 21) + #define FXAA_QUALITY_M_PS 4 + #define FXAA_QUALITY_M_P0 1.0 + #define FXAA_QUALITY_M_P1 1.5 + #define FXAA_QUALITY_M_P2 2.0 + #define FXAA_QUALITY_M_P3 8.0 #endif /*--------------------------------------------------------------------------*/ -#if (FXAA_QUALITY__PRESET == 22) - #define FXAA_QUALITY__PS 5 - #define FXAA_QUALITY__P0 1.0 - #define FXAA_QUALITY__P1 1.5 - #define FXAA_QUALITY__P2 2.0 - #define FXAA_QUALITY__P3 2.0 - #define FXAA_QUALITY__P4 8.0 +#if (FXAA_QUALITY_M_PRESET == 22) + #define FXAA_QUALITY_M_PS 5 + #define FXAA_QUALITY_M_P0 1.0 + #define FXAA_QUALITY_M_P1 1.5 + #define FXAA_QUALITY_M_P2 2.0 + #define FXAA_QUALITY_M_P3 2.0 + #define FXAA_QUALITY_M_P4 8.0 #endif /*--------------------------------------------------------------------------*/ -#if (FXAA_QUALITY__PRESET == 23) - #define FXAA_QUALITY__PS 6 - #define FXAA_QUALITY__P0 1.0 - #define FXAA_QUALITY__P1 1.5 - #define FXAA_QUALITY__P2 2.0 - #define FXAA_QUALITY__P3 2.0 - #define FXAA_QUALITY__P4 2.0 - #define FXAA_QUALITY__P5 8.0 +#if (FXAA_QUALITY_M_PRESET == 23) + #define FXAA_QUALITY_M_PS 6 + #define FXAA_QUALITY_M_P0 1.0 + #define FXAA_QUALITY_M_P1 1.5 + #define FXAA_QUALITY_M_P2 2.0 + #define FXAA_QUALITY_M_P3 2.0 + #define FXAA_QUALITY_M_P4 2.0 + #define FXAA_QUALITY_M_P5 8.0 #endif /*--------------------------------------------------------------------------*/ -#if (FXAA_QUALITY__PRESET == 24) - #define FXAA_QUALITY__PS 7 - #define FXAA_QUALITY__P0 1.0 - #define FXAA_QUALITY__P1 1.5 - #define FXAA_QUALITY__P2 2.0 - #define FXAA_QUALITY__P3 2.0 - #define FXAA_QUALITY__P4 2.0 - #define FXAA_QUALITY__P5 3.0 - #define FXAA_QUALITY__P6 8.0 +#if (FXAA_QUALITY_M_PRESET == 24) + #define FXAA_QUALITY_M_PS 7 + #define FXAA_QUALITY_M_P0 1.0 + #define FXAA_QUALITY_M_P1 1.5 + #define FXAA_QUALITY_M_P2 2.0 + #define FXAA_QUALITY_M_P3 2.0 + #define FXAA_QUALITY_M_P4 2.0 + #define FXAA_QUALITY_M_P5 3.0 + #define FXAA_QUALITY_M_P6 8.0 #endif /*--------------------------------------------------------------------------*/ -#if (FXAA_QUALITY__PRESET == 25) - #define FXAA_QUALITY__PS 8 - #define FXAA_QUALITY__P0 1.0 - #define FXAA_QUALITY__P1 1.5 - #define FXAA_QUALITY__P2 2.0 - #define FXAA_QUALITY__P3 2.0 - #define FXAA_QUALITY__P4 2.0 - #define FXAA_QUALITY__P5 2.0 - #define FXAA_QUALITY__P6 4.0 - #define FXAA_QUALITY__P7 8.0 +#if (FXAA_QUALITY_M_PRESET == 25) + #define FXAA_QUALITY_M_PS 8 + #define FXAA_QUALITY_M_P0 1.0 + #define FXAA_QUALITY_M_P1 1.5 + #define FXAA_QUALITY_M_P2 2.0 + #define FXAA_QUALITY_M_P3 2.0 + #define FXAA_QUALITY_M_P4 2.0 + #define FXAA_QUALITY_M_P5 2.0 + #define FXAA_QUALITY_M_P6 4.0 + #define FXAA_QUALITY_M_P7 8.0 #endif /*--------------------------------------------------------------------------*/ -#if (FXAA_QUALITY__PRESET == 26) - #define FXAA_QUALITY__PS 9 - #define FXAA_QUALITY__P0 1.0 - #define FXAA_QUALITY__P1 1.5 - #define FXAA_QUALITY__P2 2.0 - #define FXAA_QUALITY__P3 2.0 - #define FXAA_QUALITY__P4 2.0 - #define FXAA_QUALITY__P5 2.0 - #define FXAA_QUALITY__P6 2.0 - #define FXAA_QUALITY__P7 4.0 - #define FXAA_QUALITY__P8 8.0 +#if (FXAA_QUALITY_M_PRESET == 26) + #define FXAA_QUALITY_M_PS 9 + #define FXAA_QUALITY_M_P0 1.0 + #define FXAA_QUALITY_M_P1 1.5 + #define FXAA_QUALITY_M_P2 2.0 + #define FXAA_QUALITY_M_P3 2.0 + #define FXAA_QUALITY_M_P4 2.0 + #define FXAA_QUALITY_M_P5 2.0 + #define FXAA_QUALITY_M_P6 2.0 + #define FXAA_QUALITY_M_P7 4.0 + #define FXAA_QUALITY_M_P8 8.0 #endif /*--------------------------------------------------------------------------*/ -#if (FXAA_QUALITY__PRESET == 27) - #define FXAA_QUALITY__PS 10 - #define FXAA_QUALITY__P0 1.0 - #define FXAA_QUALITY__P1 1.5 - #define FXAA_QUALITY__P2 2.0 - #define FXAA_QUALITY__P3 2.0 - #define FXAA_QUALITY__P4 2.0 - #define FXAA_QUALITY__P5 2.0 - #define FXAA_QUALITY__P6 2.0 - #define FXAA_QUALITY__P7 2.0 - #define FXAA_QUALITY__P8 4.0 - #define FXAA_QUALITY__P9 8.0 +#if (FXAA_QUALITY_M_PRESET == 27) + #define FXAA_QUALITY_M_PS 10 + #define FXAA_QUALITY_M_P0 1.0 + #define FXAA_QUALITY_M_P1 1.5 + #define FXAA_QUALITY_M_P2 2.0 + #define FXAA_QUALITY_M_P3 2.0 + #define FXAA_QUALITY_M_P4 2.0 + #define FXAA_QUALITY_M_P5 2.0 + #define FXAA_QUALITY_M_P6 2.0 + #define FXAA_QUALITY_M_P7 2.0 + #define FXAA_QUALITY_M_P8 4.0 + #define FXAA_QUALITY_M_P9 8.0 #endif /*--------------------------------------------------------------------------*/ -#if (FXAA_QUALITY__PRESET == 28) - #define FXAA_QUALITY__PS 11 - #define FXAA_QUALITY__P0 1.0 - #define FXAA_QUALITY__P1 1.5 - #define FXAA_QUALITY__P2 2.0 - #define FXAA_QUALITY__P3 2.0 - #define FXAA_QUALITY__P4 2.0 - #define FXAA_QUALITY__P5 2.0 - #define FXAA_QUALITY__P6 2.0 - #define FXAA_QUALITY__P7 2.0 - #define FXAA_QUALITY__P8 2.0 - #define FXAA_QUALITY__P9 4.0 - #define FXAA_QUALITY__P10 8.0 +#if (FXAA_QUALITY_M_PRESET == 28) + #define FXAA_QUALITY_M_PS 11 + #define FXAA_QUALITY_M_P0 1.0 + #define FXAA_QUALITY_M_P1 1.5 + #define FXAA_QUALITY_M_P2 2.0 + #define FXAA_QUALITY_M_P3 2.0 + #define FXAA_QUALITY_M_P4 2.0 + #define FXAA_QUALITY_M_P5 2.0 + #define FXAA_QUALITY_M_P6 2.0 + #define FXAA_QUALITY_M_P7 2.0 + #define FXAA_QUALITY_M_P8 2.0 + #define FXAA_QUALITY_M_P9 4.0 + #define FXAA_QUALITY_M_P10 8.0 #endif /*--------------------------------------------------------------------------*/ -#if (FXAA_QUALITY__PRESET == 29) - #define FXAA_QUALITY__PS 12 - #define FXAA_QUALITY__P0 1.0 - #define FXAA_QUALITY__P1 1.5 - #define FXAA_QUALITY__P2 2.0 - #define FXAA_QUALITY__P3 2.0 - #define FXAA_QUALITY__P4 2.0 - #define FXAA_QUALITY__P5 2.0 - #define FXAA_QUALITY__P6 2.0 - #define FXAA_QUALITY__P7 2.0 - #define FXAA_QUALITY__P8 2.0 - #define FXAA_QUALITY__P9 2.0 - #define FXAA_QUALITY__P10 4.0 - #define FXAA_QUALITY__P11 8.0 +#if (FXAA_QUALITY_M_PRESET == 29) + #define FXAA_QUALITY_M_PS 12 + #define FXAA_QUALITY_M_P0 1.0 + #define FXAA_QUALITY_M_P1 1.5 + #define FXAA_QUALITY_M_P2 2.0 + #define FXAA_QUALITY_M_P3 2.0 + #define FXAA_QUALITY_M_P4 2.0 + #define FXAA_QUALITY_M_P5 2.0 + #define FXAA_QUALITY_M_P6 2.0 + #define FXAA_QUALITY_M_P7 2.0 + #define FXAA_QUALITY_M_P8 2.0 + #define FXAA_QUALITY_M_P9 2.0 + #define FXAA_QUALITY_M_P10 4.0 + #define FXAA_QUALITY_M_P11 8.0 #endif /*============================================================================ FXAA QUALITY - EXTREME QUALITY ============================================================================*/ -#if (FXAA_QUALITY__PRESET == 39) - #define FXAA_QUALITY__PS 12 - #define FXAA_QUALITY__P0 1.0 - #define FXAA_QUALITY__P1 1.0 - #define FXAA_QUALITY__P2 1.0 - #define FXAA_QUALITY__P3 1.0 - #define FXAA_QUALITY__P4 1.0 - #define FXAA_QUALITY__P5 1.5 - #define FXAA_QUALITY__P6 2.0 - #define FXAA_QUALITY__P7 2.0 - #define FXAA_QUALITY__P8 2.0 - #define FXAA_QUALITY__P9 2.0 - #define FXAA_QUALITY__P10 4.0 - #define FXAA_QUALITY__P11 8.0 +#if (FXAA_QUALITY_M_PRESET == 39) + #define FXAA_QUALITY_M_PS 12 + #define FXAA_QUALITY_M_P0 1.0 + #define FXAA_QUALITY_M_P1 1.0 + #define FXAA_QUALITY_M_P2 1.0 + #define FXAA_QUALITY_M_P3 1.0 + #define FXAA_QUALITY_M_P4 1.0 + #define FXAA_QUALITY_M_P5 1.5 + #define FXAA_QUALITY_M_P6 2.0 + #define FXAA_QUALITY_M_P7 2.0 + #define FXAA_QUALITY_M_P8 2.0 + #define FXAA_QUALITY_M_P9 2.0 + #define FXAA_QUALITY_M_P10 4.0 + #define FXAA_QUALITY_M_P11 8.0 #endif @@ -653,7 +657,7 @@ NOTE the other tuning knobs are now in the shader function inputs! API PORTING ============================================================================*/ -#if (FXAA_GLSL_120 == 1) || (FXAA_GLSL_130 == 1) +#if (FXAA_GLSL_120 == 1) || (FXAA_GLSL_130 == 1) || (FXAA_GLSL_400 == 1) #define FxaaBool bool #define FxaaDiscard discard #define FxaaFloat float @@ -715,6 +719,16 @@ NOTE the other tuning knobs are now in the shader function inputs! #endif #endif /*--------------------------------------------------------------------------*/ +#if (FXAA_GLSL_400 == 1) + // Requires "#version 400" or better + #define FxaaTexTop(t, p) textureLod(t, p, 0.0) + #define FxaaTexOff(t, p, o, r) textureLodOffset(t, p, 0.0, o) + #define FxaaTexAlpha4(t, p) textureGather(t, p, 3) + #define FxaaTexOffAlpha4(t, p, o) textureGatherOffset(t, p, o, 3) + #define FxaaTexGreen4(t, p) textureGather(t, p, 1) + #define FxaaTexOffGreen4(t, p, o) textureGatherOffset(t, p, o, 1) +#endif +/*--------------------------------------------------------------------------*/ #if (FXAA_HLSL_3 == 1) || (FXAA_360 == 1) || (FXAA_PS3 == 1) #define FxaaInt2 float2 #define FxaaTex sampler2D @@ -868,7 +882,7 @@ FxaaFloat4 FxaaPixelShader( // This used to be the FXAA_CONSOLE__EDGE_SHARPNESS define. // It is here now to allow easier tuning. // This does not effect PS3, as this needs to be compiled in. - // Use FXAA_CONSOLE__PS3_EDGE_SHARPNESS for PS3. + // Use FXAA_CONSOLE_M_PS3_EDGE_SHARPNESS for PS3. // Due to the PS3 being ALU bound, // there are only three safe values here: 2 and 4 and 8. // These options use the shaders ability to a free *|/ by 2|4|8. @@ -882,7 +896,7 @@ FxaaFloat4 FxaaPixelShader( // This used to be the FXAA_CONSOLE__EDGE_THRESHOLD define. // It is here now to allow easier tuning. // This does not effect PS3, as this needs to be compiled in. - // Use FXAA_CONSOLE__PS3_EDGE_THRESHOLD for PS3. + // Use FXAA_CONSOLE_M_PS3_EDGE_THRESHOLD for PS3. // Due to the PS3 being ALU bound, // there are only two safe values here: 1/4 and 1/8. // These options use the shaders ability to a free *|/ by 2|4|8. @@ -1040,11 +1054,11 @@ FxaaFloat4 FxaaPixelShader( if( horzSpan) posB.y += lengthSign * 0.5; /*--------------------------------------------------------------------------*/ FxaaFloat2 posN; - posN.x = posB.x - offNP.x * FXAA_QUALITY__P0; - posN.y = posB.y - offNP.y * FXAA_QUALITY__P0; + posN.x = posB.x - offNP.x * FXAA_QUALITY_M_P0; + posN.y = posB.y - offNP.y * FXAA_QUALITY_M_P0; FxaaFloat2 posP; - posP.x = posB.x + offNP.x * FXAA_QUALITY__P0; - posP.y = posB.y + offNP.y * FXAA_QUALITY__P0; + posP.x = posB.x + offNP.x * FXAA_QUALITY_M_P0; + posP.y = posB.y + offNP.y * FXAA_QUALITY_M_P0; FxaaFloat subpixD = ((-2.0)*subpixC) + 3.0; FxaaFloat lumaEndN = FxaaLuma(FxaaTexTop(tex, posN)); FxaaFloat subpixE = subpixC * subpixC; @@ -1060,11 +1074,11 @@ FxaaFloat4 FxaaPixelShader( lumaEndP -= lumaNN * 0.5; FxaaBool doneN = abs(lumaEndN) >= gradientScaled; FxaaBool doneP = abs(lumaEndP) >= gradientScaled; - if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P1; - if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P1; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_M_P1; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_M_P1; FxaaBool doneNP = (!doneN) || (!doneP); - if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P1; - if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P1; + if(!doneP) posP.x += offNP.x * FXAA_QUALITY_M_P1; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY_M_P1; /*--------------------------------------------------------------------------*/ if(doneNP) { if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); @@ -1073,13 +1087,13 @@ FxaaFloat4 FxaaPixelShader( if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; doneN = abs(lumaEndN) >= gradientScaled; doneP = abs(lumaEndP) >= gradientScaled; - if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P2; - if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P2; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_M_P2; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_M_P2; doneNP = (!doneN) || (!doneP); - if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P2; - if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P2; + if(!doneP) posP.x += offNP.x * FXAA_QUALITY_M_P2; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY_M_P2; /*--------------------------------------------------------------------------*/ - #if (FXAA_QUALITY__PS > 3) + #if (FXAA_QUALITY_M_PS > 3) if(doneNP) { if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); @@ -1087,13 +1101,13 @@ FxaaFloat4 FxaaPixelShader( if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; doneN = abs(lumaEndN) >= gradientScaled; doneP = abs(lumaEndP) >= gradientScaled; - if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P3; - if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P3; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_M_P3; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_M_P3; doneNP = (!doneN) || (!doneP); - if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P3; - if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P3; + if(!doneP) posP.x += offNP.x * FXAA_QUALITY_M_P3; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY_M_P3; /*--------------------------------------------------------------------------*/ - #if (FXAA_QUALITY__PS > 4) + #if (FXAA_QUALITY_M_PS > 4) if(doneNP) { if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); @@ -1101,13 +1115,13 @@ FxaaFloat4 FxaaPixelShader( if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; doneN = abs(lumaEndN) >= gradientScaled; doneP = abs(lumaEndP) >= gradientScaled; - if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P4; - if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P4; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_M_P4; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_M_P4; doneNP = (!doneN) || (!doneP); - if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P4; - if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P4; + if(!doneP) posP.x += offNP.x * FXAA_QUALITY_M_P4; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY_M_P4; /*--------------------------------------------------------------------------*/ - #if (FXAA_QUALITY__PS > 5) + #if (FXAA_QUALITY_M_PS > 5) if(doneNP) { if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); @@ -1115,13 +1129,13 @@ FxaaFloat4 FxaaPixelShader( if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; doneN = abs(lumaEndN) >= gradientScaled; doneP = abs(lumaEndP) >= gradientScaled; - if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P5; - if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P5; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_M_P5; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_M_P5; doneNP = (!doneN) || (!doneP); - if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P5; - if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P5; + if(!doneP) posP.x += offNP.x * FXAA_QUALITY_M_P5; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY_M_P5; /*--------------------------------------------------------------------------*/ - #if (FXAA_QUALITY__PS > 6) + #if (FXAA_QUALITY_M_PS > 6) if(doneNP) { if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); @@ -1129,13 +1143,13 @@ FxaaFloat4 FxaaPixelShader( if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; doneN = abs(lumaEndN) >= gradientScaled; doneP = abs(lumaEndP) >= gradientScaled; - if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P6; - if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P6; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_M_P6; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_M_P6; doneNP = (!doneN) || (!doneP); - if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P6; - if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P6; + if(!doneP) posP.x += offNP.x * FXAA_QUALITY_M_P6; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY_M_P6; /*--------------------------------------------------------------------------*/ - #if (FXAA_QUALITY__PS > 7) + #if (FXAA_QUALITY_M_PS > 7) if(doneNP) { if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); @@ -1143,13 +1157,13 @@ FxaaFloat4 FxaaPixelShader( if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; doneN = abs(lumaEndN) >= gradientScaled; doneP = abs(lumaEndP) >= gradientScaled; - if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P7; - if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P7; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_M_P7; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_M_P7; doneNP = (!doneN) || (!doneP); - if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P7; - if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P7; + if(!doneP) posP.x += offNP.x * FXAA_QUALITY_M_P7; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY_M_P7; /*--------------------------------------------------------------------------*/ - #if (FXAA_QUALITY__PS > 8) + #if (FXAA_QUALITY_M_PS > 8) if(doneNP) { if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); @@ -1157,13 +1171,13 @@ FxaaFloat4 FxaaPixelShader( if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; doneN = abs(lumaEndN) >= gradientScaled; doneP = abs(lumaEndP) >= gradientScaled; - if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P8; - if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P8; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_M_P8; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_M_P8; doneNP = (!doneN) || (!doneP); - if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P8; - if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P8; + if(!doneP) posP.x += offNP.x * FXAA_QUALITY_M_P8; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY_M_P8; /*--------------------------------------------------------------------------*/ - #if (FXAA_QUALITY__PS > 9) + #if (FXAA_QUALITY_M_PS > 9) if(doneNP) { if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); @@ -1171,13 +1185,13 @@ FxaaFloat4 FxaaPixelShader( if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; doneN = abs(lumaEndN) >= gradientScaled; doneP = abs(lumaEndP) >= gradientScaled; - if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P9; - if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P9; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_M_P9; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_M_P9; doneNP = (!doneN) || (!doneP); - if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P9; - if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P9; + if(!doneP) posP.x += offNP.x * FXAA_QUALITY_M_P9; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY_M_P9; /*--------------------------------------------------------------------------*/ - #if (FXAA_QUALITY__PS > 10) + #if (FXAA_QUALITY_M_PS > 10) if(doneNP) { if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); @@ -1185,13 +1199,13 @@ FxaaFloat4 FxaaPixelShader( if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; doneN = abs(lumaEndN) >= gradientScaled; doneP = abs(lumaEndP) >= gradientScaled; - if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P10; - if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P10; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_M_P10; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_M_P10; doneNP = (!doneN) || (!doneP); - if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P10; - if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P10; + if(!doneP) posP.x += offNP.x * FXAA_QUALITY_M_P10; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY_M_P10; /*--------------------------------------------------------------------------*/ - #if (FXAA_QUALITY__PS > 11) + #if (FXAA_QUALITY_M_PS > 11) if(doneNP) { if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); @@ -1199,13 +1213,13 @@ FxaaFloat4 FxaaPixelShader( if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; doneN = abs(lumaEndN) >= gradientScaled; doneP = abs(lumaEndP) >= gradientScaled; - if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P11; - if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P11; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_M_P11; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_M_P11; doneNP = (!doneN) || (!doneP); - if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P11; - if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P11; + if(!doneP) posP.x += offNP.x * FXAA_QUALITY_M_P11; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY_M_P11; /*--------------------------------------------------------------------------*/ - #if (FXAA_QUALITY__PS > 12) + #if (FXAA_QUALITY_M_PS > 12) if(doneNP) { if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); @@ -1213,11 +1227,11 @@ FxaaFloat4 FxaaPixelShader( if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; doneN = abs(lumaEndN) >= gradientScaled; doneP = abs(lumaEndP) >= gradientScaled; - if(!doneN) posN.x -= offNP.x * FXAA_QUALITY__P12; - if(!doneN) posN.y -= offNP.y * FXAA_QUALITY__P12; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_M_P12; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_M_P12; doneNP = (!doneN) || (!doneP); - if(!doneP) posP.x += offNP.x * FXAA_QUALITY__P12; - if(!doneP) posP.y += offNP.y * FXAA_QUALITY__P12; + if(!doneP) posP.x += offNP.x * FXAA_QUALITY_M_P12; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY_M_P12; /*--------------------------------------------------------------------------*/ } #endif @@ -1290,9 +1304,9 @@ FxaaFloat4 FxaaPixelShader( ------------------------------------------------------------------------------ Instead of using this on PC, I'd suggest just using FXAA Quality with - #define FXAA_QUALITY__PRESET 10 + #define FXAA_QUALITY_M_PRESET 10 Or - #define FXAA_QUALITY__PRESET 20 + #define FXAA_QUALITY_M_PRESET 20 Either are higher qualilty and almost as fast as this on modern PC GPUs. ============================================================================*/ #if (FXAA_PC_CONSOLE == 1) @@ -1703,7 +1717,7 @@ half4 FxaaPixelShader( // (5) half4 dir1_pos; dir1_pos.xy = normalize(dir.xyz).xz; - half dirAbsMinTimesC = min(abs(dir1_pos.x), abs(dir1_pos.y)) * half(FXAA_CONSOLE__PS3_EDGE_SHARPNESS); + half dirAbsMinTimesC = min(abs(dir1_pos.x), abs(dir1_pos.y)) * half(FXAA_CONSOLE_M_PS3_EDGE_SHARPNESS); /*--------------------------------------------------------------------------*/ // (6) half4 dir2_pos; @@ -2018,7 +2032,7 @@ half4 FxaaPixelShader( // (6) half4 dir1_pos; dir1_pos.xy = normalize(dir).xz; - half dirAbsMinTimes8 = min(abs(dir1_pos.x), abs(dir1_pos.y)) * half(FXAA_CONSOLE__PS3_EDGE_SHARPNESS); + half dirAbsMinTimes8 = min(abs(dir1_pos.x), abs(dir1_pos.y)) * half(FXAA_CONSOLE_M_PS3_EDGE_SHARPNESS); /*--------------------------------------------------------------------------*/ // (7) half4 dir2_pos; @@ -2060,7 +2074,7 @@ half4 FxaaPixelShader( temp2N = h4tex2Dlod(tex, half4(temp2N.xy, 0.0, 0.0)); half4 rgby2; rgby2.xy = dir2_pos.zw + dir2_pos.xy * fxaaConsoleRcpFrameOpt2.zw; - half lumaRangeM = (lumaMaxM - lumaMinM) / FXAA_CONSOLE__PS3_EDGE_THRESHOLD; + half lumaRangeM = (lumaMaxM - lumaMinM) / FXAA_CONSOLE_M_PS3_EDGE_THRESHOLD; /*--------------------------------------------------------------------------*/ // (12) rgby2 = h4tex2Dlod(tex, half4(rgby2.xy, 0.0, 0.0)); @@ -2093,13 +2107,11 @@ uniform sampler2D diffuseMap; uniform vec2 rcp_screen_res; uniform vec4 rcp_frame_opt; uniform vec4 rcp_frame_opt2; -uniform vec2 screen_res; VARYING vec2 vary_fragcoord; -VARYING vec2 vary_tc; void main() { - vec4 diff = FxaaPixelShader(vary_tc, //pos + vec4 diff = FxaaPixelShader(vary_fragcoord, //pos vec4(vary_fragcoord.xy, 0, 0), //fxaaConsolePosPos diffuseMap, //tex diffuseMap, diff --git a/indra/newview/app_settings/shaders/class1/deferred/giF.glsl b/indra/newview/app_settings/shaders/class1/deferred/giF.glsl deleted file mode 100644 index da1b234240..0000000000 --- a/indra/newview/app_settings/shaders/class1/deferred/giF.glsl +++ /dev/null @@ -1,190 +0,0 @@ -/** - * @file giF.glsl - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2007, 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$ - */ - -#extension GL_ARB_texture_rectangle : enable - -#ifdef DEFINE_GL_FRAGCOLOR -out vec4 frag_color; -#else -#define frag_color gl_FragColor -#endif - -uniform sampler2DRect depthMap; -uniform sampler2DRect normalMap; -uniform sampler2D noiseMap; - -uniform sampler2D diffuseGIMap; -uniform sampler2D normalGIMap; -uniform sampler2D depthGIMap; - -uniform sampler2D lightFunc; - -// Inputs -VARYING vec2 vary_fragcoord; - -uniform vec2 screen_res; - -uniform mat4 inv_proj; -uniform mat4 gi_mat; //gPipeline.mGIMatrix - eye space to sun space -uniform mat4 gi_mat_proj; //gPipeline.mGIMatrixProj - eye space to projected sun space -uniform mat4 gi_norm_mat; //gPipeline.mGINormalMatrix - eye space normal to sun space normal matrix -uniform mat4 gi_inv_proj; //gPipeline.mGIInvProj - projected sun space to sun space -uniform float gi_radius; -uniform float gi_intensity; -uniform int gi_samples; -uniform vec2 gi_kern[25]; -uniform vec2 gi_scale; -uniform vec3 gi_quad; -uniform vec3 gi_spec; -uniform float gi_direction_weight; -uniform float gi_light_offset; - -vec4 getPosition(vec2 pos_screen) -{ - float depth = texture2DRect(depthMap, pos_screen.xy).a; - vec2 sc = pos_screen.xy*2.0; - sc /= screen_res; - sc -= vec2(1.0,1.0); - vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0); - vec4 pos = inv_proj * ndc; - pos /= pos.w; - pos.w = 1.0; - return pos; -} - -vec4 getGIPosition(vec2 gi_tc) -{ - float depth = texture2D(depthGIMap, gi_tc).a; - vec2 sc = gi_tc*2.0; - sc -= vec2(1.0, 1.0); - vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0); - vec4 pos = gi_inv_proj*ndc; - pos.xyz /= pos.w; - pos.w = 1.0; - return pos; -} - -vec3 giAmbient(vec3 pos, vec3 norm) -{ - vec4 gi_c = gi_mat_proj * vec4(pos, 1.0); - gi_c.xyz /= gi_c.w; - - vec4 gi_pos = gi_mat*vec4(pos,1.0); - vec3 gi_norm = (gi_norm_mat*vec4(norm,1.0)).xyz; - gi_norm = normalize(gi_norm); - - vec2 tcx = gi_norm.xy; - vec2 tcy = gi_norm.yx; - - vec4 eye_pos = gi_mat*vec4(0,0,0,1.0); - - vec3 eye_dir = normalize(gi_pos.xyz-eye_pos.xyz/eye_pos.w); - - //vec3 eye_dir = vec3(0,0,-1); - //eye_dir = (gi_norm_mat*vec4(eye_dir, 1.0)).xyz; - //eye_dir = normalize(eye_dir); - - //float round_x = gi_scale.x; - //float round_y = gi_scale.y; - - vec3 debug = texture2D(normalGIMap, gi_c.xy).rgb*0.5+0.5; - debug.xz = vec2(0.0,0.0); - //debug = fract(debug); - - float round_x = 1.0/64.0; - float round_y = 1.0/64.0; - - //gi_c.x = floor(gi_c.x/round_x+0.5)*round_x; - //gi_c.y = floor(gi_c.y/round_y+0.5)*round_y; - - float fda = 0.0; - vec3 fdiff = vec3(0,0,0); - - vec3 rcol = vec3(0,0,0); - - float fsa = 0.0; - - for (int i = -1; i < 2; i+=2 ) - { - for (int j = -1; j < 2; j+=2) - { - vec2 tc = vec2(i, j)*0.75; - vec3 nz = texture2D(noiseMap, vary_fragcoord.xy/128.0+tc*0.5).xyz; - //tc += gi_norm.xy*nz.z; - tc += nz.xy*2.0; - tc /= gi_samples; - tc += gi_c.xy; - - vec3 lnorm = -normalize(texture2D(normalGIMap, tc.xy).xyz*2.0-1.0); - vec3 lpos = getGIPosition(tc.xy).xyz; - - vec3 at = lpos-gi_pos.xyz; - float dist = dot(at,at); - float da = clamp(1.0/(gi_spec.x*dist), 0.0, 1.0); - - if (da > 0.0) - { - //add angular attenuation - vec3 ldir = at; - float ang_atten = clamp(dot(ldir, gi_norm), 0.0, 1.0); - - float ld = -dot(ldir, lnorm); - - if (ang_atten > 0.0 && ld < 0.0) - { - vec3 diff = texture2D(diffuseGIMap, tc.xy).xyz; - da = da*ang_atten; - fda += da; - fdiff += diff*da; - } - } - } - } - - fdiff /= max(gi_spec.y*fda, gi_quad.z); - fdiff = clamp(fdiff, vec3(0), vec3(1)); - - vec3 ret = fda*fdiff; - //ret = ret*ret*gi_quad.x+ret*gi_quad.y+gi_quad.z; - - //fda *= nz.z; - - //rcol.rgb *= gi_intensity; - //return rcol.rgb+vary_AmblitColor.rgb*0.25; - //return vec4(debug, 0.0); - //return vec4(fda*fdiff, 0.0); - return clamp(ret,vec3(0.0), vec3(1.0)); - //return debug.xyz; -} - -void main() -{ - vec2 pos_screen = vary_fragcoord.xy; - vec4 pos = getPosition(pos_screen); - vec3 norm = texture2DRect(normalMap, pos_screen).xyz; - norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm - - frag_color.xyz = giAmbient(pos, norm); -} diff --git a/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl b/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl index bc0719cb82..5062858496 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl @@ -38,6 +38,8 @@ uniform sampler2D specularMap; VARYING vec2 vary_texcoord0; +vec3 linear_to_srgb(vec3 cs); + void main() { vec4 col = texture2D(diffuseMap, vary_texcoord0.xy); @@ -47,7 +49,12 @@ void main() discard; } - frag_data[0] = vec4(col.rgb, col.a * 0.005); - frag_data[1] = texture2D(specularMap, vary_texcoord0.xy); - frag_data[2] = vec4(texture2D(normalMap, vary_texcoord0.xy).xyz, 0.0); + vec4 norm = texture2D(normalMap, vary_texcoord0.xy); + vec4 spec = texture2D(specularMap, vary_texcoord0.xy); + + col.rgb = linear_to_srgb(col.rgb); + + frag_data[0] = vec4(col.rgb, 0.0); + frag_data[1] = spec; + frag_data[2] = vec4(norm.xy,0,0); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/luminanceF.glsl b/indra/newview/app_settings/shaders/class1/deferred/luminanceF.glsl deleted file mode 100644 index dcf474824d..0000000000 --- a/indra/newview/app_settings/shaders/class1/deferred/luminanceF.glsl +++ /dev/null @@ -1,39 +0,0 @@ -/** - * @file luminanceF.glsl - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2007, 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$ - */ - -uniform sampler2DRect diffuseMap; - -#ifdef DEFINE_GL_FRAGCOLOR -out vec4 frag_color; -#else -#define frag_color gl_FragColor -#endif - -VARYING vec2 vary_fragcoord; - -void main() -{ - frag_color = texture2DRect(diffuseMap, vary_fragcoord.xy); -} diff --git a/indra/newview/app_settings/shaders/class1/deferred/luminanceV.glsl b/indra/newview/app_settings/shaders/class1/deferred/luminanceV.glsl deleted file mode 100644 index f2dc60aa5d..0000000000 --- a/indra/newview/app_settings/shaders/class1/deferred/luminanceV.glsl +++ /dev/null @@ -1,45 +0,0 @@ -/** - * @file giV.glsl - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2007, 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$ - */ - -uniform mat4 modelview_projection_matrix; - -ATTRIBUTE vec3 position; -ATTRIBUTE vec4 diffuse_color; - -VARYING vec2 vary_fragcoord; -VARYING vec4 vertex_color; - -uniform vec2 screen_res; - -void main() -{ - //transform vertex - vec4 pos = modelview_projection_matrix * vec4(position.xyz, 1.0); - gl_Position = pos; - - vary_fragcoord = (pos.xy * 0.5 + 0.5)*screen_res; - - vertex_color = diffuse_color; -} diff --git a/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl b/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl new file mode 100644 index 0000000000..2484c9cd4e --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl @@ -0,0 +1,724 @@ +/** + * @file materialF.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2007, 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$ + */ + +#define DIFFUSE_ALPHA_MODE_IGNORE 0 +#define DIFFUSE_ALPHA_MODE_BLEND 1 +#define DIFFUSE_ALPHA_MODE_MASK 2 +#define DIFFUSE_ALPHA_MODE_EMISSIVE 3 + +uniform float emissive_brightness; + +vec2 encode_normal(vec3 n); +vec3 decode_normal(vec2 enc); +vec3 srgb_to_linear(vec3 cs); +vec3 linear_to_srgb(vec3 cl); + +#if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND) + +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_color; +#else +#define frag_color gl_FragColor +#endif + +#if HAS_SUN_SHADOW + +uniform sampler2DShadow shadowMap0; +uniform sampler2DShadow shadowMap1; +uniform sampler2DShadow shadowMap2; +uniform sampler2DShadow shadowMap3; +//uniform sampler2D noiseMap; //Random dither. +VARYING vec2 vary_fragcoord; + +uniform mat4 shadow_matrix[6]; +uniform vec4 shadow_clip; +uniform vec2 shadow_res; +uniform float shadow_bias; + +float pcfShadow(sampler2DShadow shadowMap, vec4 stc, vec2 pos_screen) +{ + stc.xyz /= stc.w; + stc.z += shadow_bias; + + //stc.x += (((texture2D(noiseMap, pos_screen/128.0).x)-.5)/shadow_res.x); //Random dither. + stc.x = floor(stc.x*shadow_res.x + fract(pos_screen.y*0.666666666))/shadow_res.x; // add some chaotic jitter to X sample pos according to Y to disguise the snapping going on here + + float cs = shadow2D(shadowMap, stc.xyz).x; + + float shadow = cs; + + shadow += shadow2D(shadowMap, stc.xyz+vec3(2.0/shadow_res.x, 1.5/shadow_res.y, 0.0)).x; + shadow += shadow2D(shadowMap, stc.xyz+vec3(1.0/shadow_res.x, -1.5/shadow_res.y, 0.0)).x; + shadow += shadow2D(shadowMap, stc.xyz+vec3(-1.0/shadow_res.x, 1.5/shadow_res.y, 0.0)).x; + shadow += shadow2D(shadowMap, stc.xyz+vec3(-2.0/shadow_res.x, -1.5/shadow_res.y, 0.0)).x; + + return shadow*0.2; +} + +#endif + +uniform samplerCube environmentMap; +uniform sampler2D lightFunc; + +// Inputs +uniform vec4 morphFactor; +uniform vec3 camPosLocal; +//uniform vec4 camPosWorld; +uniform vec4 gamma; +uniform vec4 lightnorm; +uniform vec4 sunlight_color; +uniform vec4 ambient; +uniform vec4 blue_horizon; +uniform vec4 blue_density; +uniform float haze_horizon; +uniform float haze_density; +uniform float cloud_shadow; +uniform float density_multiplier; +uniform float distance_multiplier; +uniform float max_y; +uniform vec4 glow; +uniform float scene_light_strength; +uniform mat3 env_mat; + +uniform vec3 sun_dir; + +VARYING vec3 vary_position; + +vec3 vary_PositionEye; + +vec3 vary_SunlitColor; +vec3 vary_AmblitColor; +vec3 vary_AdditiveColor; +vec3 vary_AtmosAttenuation; + +uniform mat4 inv_proj; + +uniform vec4 light_position[8]; +uniform vec3 light_direction[8]; +uniform vec3 light_attenuation[8]; +uniform vec3 light_diffuse[8]; + +#ifdef WATER_FOG +uniform vec4 waterPlane; +uniform vec4 waterFogColor; +uniform float waterFogDensity; +uniform float waterFogKS; + +vec4 applyWaterFogDeferred(vec3 pos, vec4 color) +{ + //normalize view vector + vec3 view = normalize(pos); + float es = -(dot(view, waterPlane.xyz)); + + //find intersection point with water plane and eye vector + + //get eye depth + float e0 = max(-waterPlane.w, 0.0); + + vec3 int_v = waterPlane.w > 0.0 ? view * waterPlane.w/es : vec3(0.0, 0.0, 0.0); + + //get object depth + float depth = length(pos - int_v); + + //get "thickness" of water + float l = max(depth, 0.1); + + float kd = waterFogDensity; + float ks = waterFogKS; + vec4 kc = waterFogColor; + + float F = 0.98; + + float t1 = -kd * pow(F, ks * e0); + float t2 = kd + ks * es; + float t3 = pow(F, t2*l) - 1.0; + + float L = min(t1/t2*t3, 1.0); + + float D = pow(0.98, l*kd); + + color.rgb = color.rgb * D + kc.rgb * L; + color.a = kc.a + color.a; + + return color; +} +#endif + +vec3 calcDirectionalLight(vec3 n, vec3 l) +{ + float a = max(dot(n,l),0.0); + return vec3(a,a,a); +} + + +vec3 calcPointLightOrSpotLight(vec3 light_col, vec3 npos, vec3 diffuse, vec4 spec, vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float fa, float is_pointlight, inout float glare) +{ + //get light vector + vec3 lv = lp.xyz-v; + + //get distance + float d = length(lv); + + float da = 1.0; + + vec3 col = vec3(0,0,0); + + if (d > 0.0 && la > 0.0 && fa > 0.0) + { + //normalize light vector + lv = normalize(lv); + + //distance attenuation + float dist = d/la; + float dist_atten = clamp(1.0-(dist-1.0*(1.0-fa))/fa, 0.0, 1.0); + dist_atten *= dist_atten; + dist_atten *= 2.0; + + // spotlight coefficient. + float spot = max(dot(-ln, lv), is_pointlight); + da *= spot*spot; // GL_SPOT_EXPONENT=2 + + //angular attenuation + da *= max(dot(n, lv), 0.0); + + float lit = max(da * dist_atten, 0.0); + + col = light_col*lit*diffuse; + + if (spec.a > 0.0) + { + //vec3 ref = dot(pos+lv, norm); + vec3 h = normalize(lv+npos); + float nh = dot(n, h); + float nv = dot(n, npos); + float vh = dot(npos, h); + float sa = nh; + float fres = pow(1 - dot(h, npos), 5)*0.4+0.5; + + float gtdenom = 2 * nh; + float gt = max(0, min(gtdenom * nv / vh, gtdenom * da / vh)); + + if (nh > 0.0) + { + float scol = fres*texture2D(lightFunc, vec2(nh, spec.a)).r*gt/(nh*da); + vec3 speccol = lit*scol*light_col.rgb*spec.rgb; + col += speccol; + + float cur_glare = max(speccol.r, speccol.g); + cur_glare = max(cur_glare, speccol.b); + glare = max(glare, speccol.r); + glare += max(cur_glare, 0.0); + //col += spec.rgb; + } + } + } + + return max(col, vec3(0.0,0.0,0.0)); + +} + +#ifndef WATER_FOG +vec3 getPositionEye() +{ + return vary_PositionEye; +} +#endif + +vec3 getSunlitColor() +{ + return vary_SunlitColor; +} +vec3 getAmblitColor() +{ + return vary_AmblitColor; +} +vec3 getAdditiveColor() +{ + return vary_AdditiveColor; +} +vec3 getAtmosAttenuation() +{ + return vary_AtmosAttenuation; +} + +void setPositionEye(vec3 v) +{ + vary_PositionEye = v; +} + +void setSunlitColor(vec3 v) +{ + vary_SunlitColor = v; +} + +void setAmblitColor(vec3 v) +{ + vary_AmblitColor = v; +} + +void setAdditiveColor(vec3 v) +{ + vary_AdditiveColor = v; +} + +void setAtmosAttenuation(vec3 v) +{ + vary_AtmosAttenuation = v; +} + +void calcAtmospherics(vec3 inPositionEye) { + + vec3 P = inPositionEye; + setPositionEye(P); + + vec3 tmpLightnorm = lightnorm.xyz; + + vec3 Pn = normalize(P); + float Plen = length(P); + + vec4 temp1 = vec4(0); + vec3 temp2 = vec3(0); + vec4 blue_weight; + vec4 haze_weight; + vec4 sunlight = sunlight_color; + vec4 light_atten; + + //sunlight attenuation effect (hue and brightness) due to atmosphere + //this is used later for sunlight modulation at various altitudes + light_atten = (blue_density + vec4(haze_density * 0.25)) * (density_multiplier * max_y); + //I had thought blue_density and haze_density should have equal weighting, + //but attenuation due to haze_density tends to seem too strong + + temp1 = blue_density + vec4(haze_density); + blue_weight = blue_density / temp1; + haze_weight = vec4(haze_density) / temp1; + + //(TERRAIN) compute sunlight from lightnorm only (for short rays like terrain) + temp2.y = max(0.0, tmpLightnorm.y); + temp2.y = 1. / temp2.y; + sunlight *= exp( - light_atten * temp2.y); + + // main atmospheric scattering line integral + temp2.z = Plen * density_multiplier; + + // Transparency (-> temp1) + // ATI Bugfix -- can't store temp1*temp2.z*distance_multiplier in a variable because the ati + // compiler gets confused. + temp1 = exp(-temp1 * temp2.z * distance_multiplier); + + //final atmosphere attenuation factor + setAtmosAttenuation(temp1.rgb); + + //compute haze glow + //(can use temp2.x as temp because we haven't used it yet) + temp2.x = dot(Pn, tmpLightnorm.xyz); + temp2.x = 1. - temp2.x; + //temp2.x is 0 at the sun and increases away from sun + temp2.x = max(temp2.x, .03); //was glow.y + //set a minimum "angle" (smaller glow.y allows tighter, brighter hotspot) + temp2.x *= glow.x; + //higher glow.x gives dimmer glow (because next step is 1 / "angle") + temp2.x = pow(temp2.x, glow.z); + //glow.z should be negative, so we're doing a sort of (1 / "angle") function + + //add "minimum anti-solar illumination" + temp2.x += .25; + + //increase ambient when there are more clouds + vec4 tmpAmbient = ambient + (vec4(1.) - ambient) * cloud_shadow * 0.5; + + //haze color + setAdditiveColor( + vec3(blue_horizon * blue_weight * (sunlight*(1.-cloud_shadow) + tmpAmbient) + + (haze_horizon * haze_weight) * (sunlight*(1.-cloud_shadow) * temp2.x + + tmpAmbient))); + + //brightness of surface both sunlight and ambient + setSunlitColor(vec3(sunlight * .5)); + setAmblitColor(vec3(tmpAmbient * .25)); + setAdditiveColor(getAdditiveColor() * vec3(1.0 - temp1)); +} + +vec3 atmosLighting(vec3 light) +{ + light *= getAtmosAttenuation().r; + light += getAdditiveColor(); + return (2.0 * light); +} + +vec3 atmosTransport(vec3 light) { + light *= getAtmosAttenuation().r; + light += getAdditiveColor() * 2.0; + return light; +} +vec3 atmosGetDiffuseSunlightColor() +{ + return getSunlitColor(); +} + +vec3 scaleDownLight(vec3 light) +{ + return (light / vec3(scene_light_strength, scene_light_strength, scene_light_strength)); +} + +vec3 scaleUpLight(vec3 light) +{ + return (light * vec3(scene_light_strength, scene_light_strength, scene_light_strength)); +} + +vec3 atmosAmbient(vec3 light) +{ + return getAmblitColor() + (light * vec3(0.5f, 0.5f, 0.5f)); +} + +vec3 atmosAffectDirectionalLight(float lightIntensity) +{ + return getSunlitColor() * vec3(lightIntensity, lightIntensity, lightIntensity); +} + +vec3 scaleSoftClip(vec3 light) +{ + //soft clip effect: + vec3 zeroes = vec3(0.0f, 0.0f, 0.0f); + vec3 ones = vec3(1.0f, 1.0f, 1.0f); + + light = ones - clamp(light, zeroes, ones); + light = ones - pow(light, gamma.xxx); + + return light; +} + +vec3 fullbrightAtmosTransport(vec3 light) { + float brightness = dot(light.rgb, vec3(0.33333)); + + return mix(atmosTransport(light.rgb), light.rgb + getAdditiveColor().rgb, brightness * brightness); +} + +vec3 fullbrightScaleSoftClip(vec3 light) +{ + //soft clip effect: + return light; +} + +#else +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_data[3]; +#else +#define frag_data gl_FragData +#endif +#endif + +uniform sampler2D diffuseMap; + +#if HAS_NORMAL_MAP +uniform sampler2D bumpMap; +#endif + +#if HAS_SPECULAR_MAP +uniform sampler2D specularMap; + +VARYING vec2 vary_texcoord2; +#endif + +uniform float env_intensity; +uniform vec4 specular_color; // specular color RGB and specular exponent (glossiness) in alpha + +#if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_MASK) +uniform float minimum_alpha; +#endif + +#if HAS_NORMAL_MAP +VARYING vec3 vary_mat0; +VARYING vec3 vary_mat1; +VARYING vec3 vary_mat2; +VARYING vec2 vary_texcoord1; +#else +VARYING vec3 vary_normal; +#endif + +VARYING vec4 vertex_color; +VARYING vec2 vary_texcoord0; + +void main() +{ + vec4 diffcol = texture2D(diffuseMap, vary_texcoord0.xy); + diffcol.rgb *= vertex_color.rgb; + +#if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_MASK) + if (diffcol.a < minimum_alpha) + { + discard; + } +#endif + +#if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND) + #if (HAS_SPECULAR_MAP == 0) + if(diffcol.a < .01) + { + discard; + } + #endif + vec3 gamma_diff = diffcol.rgb; + diffcol.rgb = srgb_to_linear(diffcol.rgb); +#endif + +#if HAS_SPECULAR_MAP + vec4 spec = texture2D(specularMap, vary_texcoord2.xy); + spec.rgb *= specular_color.rgb; +#else + vec4 spec = vec4(specular_color.rgb, 1.0); +#endif + +#if HAS_NORMAL_MAP + vec4 norm = texture2D(bumpMap, vary_texcoord1.xy); + + norm.xyz = norm.xyz * 2 - 1; + + vec3 tnorm = vec3(dot(norm.xyz,vary_mat0), + dot(norm.xyz,vary_mat1), + dot(norm.xyz,vary_mat2)); +#else + vec4 norm = vec4(0,0,0,1.0); + vec3 tnorm = vary_normal; +#endif + + norm.xyz = tnorm; + norm.xyz = normalize(norm.xyz); + + vec2 abnormal = encode_normal(norm.xyz); + norm.xyz = decode_normal(abnormal.xy); + + vec4 final_color = diffcol; + +#if (DIFFUSE_ALPHA_MODE != DIFFUSE_ALPHA_MODE_EMISSIVE) + final_color.a = emissive_brightness; +#else + final_color.a = max(final_color.a, emissive_brightness); +#endif + + vec4 final_specular = spec; +#if HAS_SPECULAR_MAP + vec4 final_normal = vec4(encode_normal(normalize(tnorm)), env_intensity * spec.a, 0.0); + final_specular.a = specular_color.a * norm.a; +#else + vec4 final_normal = vec4(encode_normal(normalize(tnorm)), env_intensity, 0.0); + final_specular.a = specular_color.a; +#endif + + +#if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND) + //forward rendering, output just lit RGBA + vec3 pos = vary_position; + +#if HAS_SUN_SHADOW + vec2 frag = vary_fragcoord.xy; + float shadow = 0.0; + + vec4 spos = vec4(pos,1.0); + + if (spos.z > -shadow_clip.w) + { + vec4 lpos; + + vec4 near_split = shadow_clip*-0.75; + vec4 far_split = shadow_clip*-1.25; + vec4 transition_domain = near_split-far_split; + float weight = 0.0; + + if (spos.z < near_split.z) + { + lpos = shadow_matrix[3]*spos; + + float w = 1.0; + w -= max(spos.z-far_split.z, 0.0)/transition_domain.z; + shadow += pcfShadow(shadowMap3, lpos,frag.xy)*w; + weight += w; + shadow += max((pos.z+shadow_clip.z)/(shadow_clip.z-shadow_clip.w)*2.0-1.0, 0.0); + } + + if (spos.z < near_split.y && spos.z > far_split.z) + { + lpos = shadow_matrix[2]*spos; + + float w = 1.0; + w -= max(spos.z-far_split.y, 0.0)/transition_domain.y; + w -= max(near_split.z-spos.z, 0.0)/transition_domain.z; + shadow += pcfShadow(shadowMap2, lpos,frag.xy)*w; + weight += w; + } + + if (spos.z < near_split.x && spos.z > far_split.y) + { + lpos = shadow_matrix[1]*spos; + + float w = 1.0; + w -= max(spos.z-far_split.x, 0.0)/transition_domain.x; + w -= max(near_split.y-spos.z, 0.0)/transition_domain.y; + shadow += pcfShadow(shadowMap1, lpos,frag.xy)*w; + weight += w; + } + + if (spos.z > far_split.x) + { + lpos = shadow_matrix[0]*spos; + + float w = 1.0; + w -= max(near_split.x-spos.z, 0.0)/transition_domain.x; + + shadow += pcfShadow(shadowMap0, lpos,frag.xy)*w; + weight += w; + } + + + shadow /= weight; + } + else + { + shadow = 1.0; + } +#else + float shadow = 1.0; +#endif + + spec = final_specular; + vec4 diffuse = final_color; + float envIntensity = final_normal.z; + + vec3 col = vec3(0.0f,0.0f,0.0f); + + float bloom = 0.0; + calcAtmospherics(pos.xyz); + + vec3 refnormpersp = normalize(reflect(pos.xyz, norm.xyz)); + + float da =dot(norm.xyz, sun_dir.xyz); + + float final_da = da; + final_da = min(final_da, shadow); + //final_da = max(final_da, diffuse.a); + final_da = max(final_da, 0.0f); + final_da = min(final_da, 1.0f); + final_da = pow(final_da, 1.0/1.3); + + col.rgb = atmosAmbient(col); + + float ambient = min(abs(da), 1.0); + ambient *= 0.5; + ambient *= ambient; + ambient = (1.0-ambient); + + col.rgb *= ambient; + + col.rgb = col.rgb + atmosAffectDirectionalLight(final_da); + + col.rgb *= gamma_diff.rgb; + + + float glare = 0.0; + + if (spec.a > 0.0) // specular reflection + { + // the old infinite-sky shiny reflection + // + + float sa = dot(refnormpersp, sun_dir.xyz); + vec3 dumbshiny = vary_SunlitColor*shadow*(texture2D(lightFunc, vec2(sa, spec.a)).r); + + // add the two types of shiny together + vec3 spec_contrib = dumbshiny * spec.rgb; + bloom = dot(spec_contrib, spec_contrib) / 6; + + glare = max(spec_contrib.r, spec_contrib.g); + glare = max(glare, spec_contrib.b); + + col += spec_contrib; + } + + + col = mix(col.rgb, diffcol.rgb, diffuse.a); + + if (envIntensity > 0.0) + { + //add environmentmap + vec3 env_vec = env_mat * refnormpersp; + + vec3 refcol = textureCube(environmentMap, env_vec).rgb; + + col = mix(col.rgb, refcol, + envIntensity); + + float cur_glare = max(refcol.r, refcol.g); + cur_glare = max(cur_glare, refcol.b); + cur_glare *= envIntensity*4.0; + glare += cur_glare; + } + + //col = mix(atmosLighting(col), fullbrightAtmosTransport(col), diffuse.a); + //col = mix(scaleSoftClip(col), fullbrightScaleSoftClip(col), diffuse.a); + + col = atmosLighting(col); + col = scaleSoftClip(col); + + //convert to linear space before adding local lights + col = srgb_to_linear(col); + + vec3 npos = normalize(-pos.xyz); + + vec3 light = vec3(0,0,0); + + #define LIGHT_LOOP(i) light.rgb += calcPointLightOrSpotLight(light_diffuse[i].rgb, npos, diffuse.rgb, final_specular, pos.xyz, norm.xyz, light_position[i], light_direction[i].xyz, light_attenuation[i].x, light_attenuation[i].y, light_attenuation[i].z, glare); + + LIGHT_LOOP(1) + LIGHT_LOOP(2) + LIGHT_LOOP(3) + LIGHT_LOOP(4) + LIGHT_LOOP(5) + LIGHT_LOOP(6) + LIGHT_LOOP(7) + + col.rgb += light.rgb; + + glare = min(glare, 1.0)/* * diffcol.a*/; + float al = max(diffcol.a,glare)*vertex_color.a; + + //convert to gamma space for display on screen + col.rgb = linear_to_srgb(col.rgb); + +#ifdef WATER_FOG + vec4 temp = applyWaterFogDeferred(pos, vec4(col.rgb, al)); + col.rgb = temp.rgb; + al = temp.a; +#endif + + frag_color.rgb = col.rgb; + frag_color.a = al; + +#else + frag_data[0] = final_color; + frag_data[1] = final_specular; // XYZ = Specular color. W = Specular exponent. + frag_data[2] = final_normal; // XY = Normal. Z = Env. intensity. +#endif +} + diff --git a/indra/newview/app_settings/shaders/class1/deferred/materialV.glsl b/indra/newview/app_settings/shaders/class1/deferred/materialV.glsl new file mode 100644 index 0000000000..e4d3994f50 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/materialV.glsl @@ -0,0 +1,149 @@ +/** + * @file bumpV.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2007, 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$ + */ + +#define DIFFUSE_ALPHA_MODE_IGNORE 0 +#define DIFFUSE_ALPHA_MODE_BLEND 1 +#define DIFFUSE_ALPHA_MODE_MASK 2 +#define DIFFUSE_ALPHA_MODE_EMISSIVE 3 + +#if HAS_SKIN +uniform mat4 modelview_matrix; +uniform mat4 projection_matrix; +mat4 getObjectSkinnedTransform(); +#else +uniform mat3 normal_matrix; +uniform mat4 modelview_projection_matrix; +#endif + +#if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND) + +#if !HAS_SKIN +uniform mat4 modelview_matrix; +#endif + +VARYING vec3 vary_position; +#if HAS_SUN_SHADOW +VARYING vec2 vary_fragcoord; +#endif + +#endif + +uniform mat4 texture_matrix0; + +ATTRIBUTE vec3 position; +ATTRIBUTE vec4 diffuse_color; +ATTRIBUTE vec3 normal; +ATTRIBUTE vec2 texcoord0; + + +#if HAS_NORMAL_MAP +ATTRIBUTE vec4 tangent; +ATTRIBUTE vec2 texcoord1; + +VARYING vec3 vary_mat0; +VARYING vec3 vary_mat1; +VARYING vec3 vary_mat2; + +VARYING vec2 vary_texcoord1; +#else +VARYING vec3 vary_normal; +#endif + +#if HAS_SPECULAR_MAP +ATTRIBUTE vec2 texcoord2; +VARYING vec2 vary_texcoord2; +#endif + +VARYING vec4 vertex_color; +VARYING vec2 vary_texcoord0; + +void main() +{ +#if HAS_SKIN + mat4 mat = modelview_matrix * getObjectSkinnedTransform(); + + vec3 pos = (mat*vec4(position.xyz,1.0)).xyz; + +#if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND) + vary_position = pos; +#endif + + gl_Position = projection_matrix*vec4(pos,1.0); + +#else + //transform vertex + gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0); + +#endif + + vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; + +#if HAS_NORMAL_MAP + vary_texcoord1 = (texture_matrix0 * vec4(texcoord1,0,1)).xy; +#endif + +#if HAS_SPECULAR_MAP + vary_texcoord2 = (texture_matrix0 * vec4(texcoord2,0,1)).xy; +#endif + +#if HAS_SKIN + vec3 n = normalize((mat*vec4(normal.xyz+position.xyz,1.0)).xyz-pos.xyz); +#if HAS_NORMAL_MAP + vec3 t = normalize((mat*vec4(tangent.xyz+position.xyz,1.0)).xyz-pos.xyz); + vec3 b = cross(n, t)*tangent.w; + + vary_mat0 = vec3(t.x, b.x, n.x); + vary_mat1 = vec3(t.y, b.y, n.y); + vary_mat2 = vec3(t.z, b.z, n.z); +#else //HAS_NORMAL_MAP +vary_normal = n; +#endif //HAS_NORMAL_MAP +#else //HAS_SKIN + vec3 n = normalize(normal_matrix * normal); +#if HAS_NORMAL_MAP + vec3 t = normalize(normal_matrix * tangent.xyz); + vec3 b = cross(n,t)*tangent.w; + + vary_mat0 = vec3(t.x, b.x, n.x); + vary_mat1 = vec3(t.y, b.y, n.y); + vary_mat2 = vec3(t.z, b.z, n.z); +#else //HAS_NORMAL_MAP + vary_normal = n; +#endif //HAS_NORMAL_MAP +#endif //HAS_SKIN + + vertex_color = diffuse_color; + +#if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND) +#if !HAS_SKIN + vec3 pos = (modelview_matrix*vec4(position.xyz, 1.0)).xyz; + vary_position = pos; +#endif +#if HAS_SUN_SHADOW + vary_fragcoord = (pos.xy*0.5+0.5); +#endif +#endif +} + diff --git a/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl index 26aa34107d..4e84d38b7d 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl @@ -23,7 +23,7 @@ * $/LicenseInfo$ */ -#extension GL_ARB_texture_rectangle : enable + #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_color; @@ -31,10 +31,10 @@ out vec4 frag_color; #define frag_color gl_FragColor #endif -uniform sampler2DRect depthMap; -uniform sampler2DRect diffuseRect; -uniform sampler2DRect specularRect; -uniform sampler2DRect normalMap; +uniform sampler2D depthMap; +uniform sampler2D diffuseRect; +uniform sampler2D specularRect; +uniform sampler2D normalMap; uniform samplerCube environmentMap; uniform sampler2D noiseMap; uniform sampler2D lightFunc; @@ -45,117 +45,93 @@ uniform float sun_wash; uniform int light_count; -#define MAX_LIGHT_COUNT 16 -uniform vec4 light[MAX_LIGHT_COUNT]; -uniform vec4 light_col[MAX_LIGHT_COUNT]; +uniform vec4 light[LIGHT_COUNT]; +uniform vec4 light_col[LIGHT_COUNT]; VARYING vec4 vary_fragcoord; -uniform vec2 screen_res; uniform float far_z; uniform mat4 inv_proj; +uniform vec2 noise_scale; -vec4 getPosition(vec2 pos_screen) -{ - float depth = texture2DRect(depthMap, pos_screen.xy).r; - vec2 sc = pos_screen.xy*2.0; - sc /= screen_res; - sc -= vec2(1.0,1.0); - vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0); - vec4 pos = inv_proj * ndc; - pos /= pos.w; - pos.w = 1.0; - return pos; -} - -vec3 unpack(vec2 tc) -{ -//#define PACK_NORMALS -#ifdef PACK_NORMALS - vec2 enc = texture2DRect(normalMap, tc).xy; - enc = enc*4.0-2.0; - float prod = dot(enc,enc); - return vec3(enc*sqrt(1.0-prod*.25),1.0-prod*.5); -#else - vec3 norm = texture2DRect(normalMap, tc).xyz; - return norm*2.0-1.0; -#endif -} +vec3 decode_normal(vec2 enc); +vec4 getPosition(vec2 pos_screen); void main() { - vec2 frag = (vary_fragcoord.xy*0.5+0.5)*screen_res; + vec2 frag = (vary_fragcoord.xy*0.5+0.5); vec3 pos = getPosition(frag.xy).xyz; if (pos.z < far_z) { discard; } - vec3 norm = unpack(frag.xy); // unpack norm - //norm = normalize(norm); // may be superfluous - vec4 spec = texture2DRect(specularRect, frag.xy); - vec3 diff = texture2DRect(diffuseRect, frag.xy).rgb; - float noise = texture2D(noiseMap, frag.xy/128.0).b; + vec3 norm = texture2D(normalMap, frag.xy).xyz; + norm = decode_normal(norm.xy); // unpack norm + norm = normalize(norm); + vec4 spec = texture2D(specularRect, frag.xy); + vec3 diff = texture2D(diffuseRect, frag.xy).rgb; + + float noise = texture2D(noiseMap, frag.xy*noise_scale).b; vec3 out_col = vec3(0,0,0); vec3 npos = normalize(-pos); // As of OSX 10.6.7 ATI Apple's crash when using a variable size loop - for (int i = 0; i < MAX_LIGHT_COUNT; ++i) + for (int i = 0; i < LIGHT_COUNT; ++i) { - bool light_contrib = (i < light_count); - vec3 lv = light[i].xyz-pos; - float dist2 = dot(lv,lv); - dist2 /= light[i].w; - if (dist2 > 1.0) + float dist = length(lv); + dist /= light[i].w; + if (dist <= 1.0) { - light_contrib = false; - } - float da = dot(norm, lv); - if (da < 0.0) - { - light_contrib = false; - } - - if (light_contrib) + if (da > 0.0) { lv = normalize(lv); da = dot(norm, lv); - + float fa = light_col[i].a+1.0; - float dist_atten = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0); + float dist_atten = clamp(1.0-(dist-1.0*(1.0-fa))/fa, 0.0, 1.0); + dist_atten *= dist_atten; + dist_atten *= 2.0; + dist_atten *= noise; float lit = da * dist_atten; - + vec3 col = light_col[i].rgb*lit*diff; + //vec3 col = vec3(dist2, light_col[i].a, lit); if (spec.a > 0.0) { + lit = min(da*6.0, 1.0) * dist_atten; //vec3 ref = dot(pos+lv, norm); - - float sa = dot(normalize(lv+npos),norm); - - if (sa > 0.0) + vec3 h = normalize(lv+npos); + float nh = dot(norm, h); + float nv = dot(norm, npos); + float vh = dot(npos, h); + float sa = nh; + float fres = pow(1 - dot(h, npos), 5)*0.4+0.5; + + float gtdenom = 2 * nh; + float gt = max(0, min(gtdenom * nv / vh, gtdenom * da / vh)); + + if (nh > 0.0) { - sa = 6 * texture2D(lightFunc, vec2(sa, spec.a)).r * min(dist_atten*4.0, 1.0); - sa *= noise; - col += da*sa*light_col[i].rgb*spec.rgb; + float scol = fres*texture2D(lightFunc, vec2(nh, spec.a)).r*gt/(nh*da); + col += lit*scol*light_col[i].rgb*spec.rgb; + //col += spec.rgb; } } out_col += col; } } - - if (dot(out_col, out_col) <= 0.0) - { - discard; } + frag_color.rgb = out_col; frag_color.a = 0.0; } diff --git a/indra/newview/app_settings/shaders/class1/deferred/multiSpotLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/multiSpotLightF.glsl index a82ba899ab..65d6e1a802 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/multiSpotLightF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/multiSpotLightF.glsl @@ -31,15 +31,14 @@ out vec4 frag_color; //class 1 -- no shadows -#extension GL_ARB_texture_rectangle : enable - -uniform sampler2DRect diffuseRect; -uniform sampler2DRect specularRect; -uniform sampler2DRect depthMap; -uniform sampler2DRect normalMap; +uniform sampler2D diffuseRect; +uniform sampler2D specularRect; +uniform sampler2D depthMap; +uniform sampler2D normalMap; uniform samplerCube environmentMap; uniform sampler2D noiseMap; uniform sampler2D projectionMap; +uniform sampler2D lightFunc; uniform mat4 proj_mat; //screen space to light space uniform float proj_near; //near clip for projection @@ -62,29 +61,34 @@ uniform float falloff; uniform float size; VARYING vec4 vary_fragcoord; -uniform vec2 screen_res; uniform mat4 inv_proj; +uniform vec2 noise_scale; + +vec3 decode_normal(vec2 enc); +vec4 getPosition(vec2 pos_screen); +vec4 srgb_to_linear(vec4 cs); vec4 texture2DLodSpecular(sampler2D projectionMap, vec2 tc, float lod) { vec4 ret = texture2DLod(projectionMap, tc, lod); - - vec2 dist = tc-vec2(0.5); - - float det = max(1.0-lod/(proj_lod*0.5), 0.0); - - float d = dot(dist,dist); - - ret *= min(clamp((0.25-d)/0.25, 0.0, 1.0)+det, 1.0); - + + ret = srgb_to_linear(ret); + vec2 dist = vec2(0.5) - abs(tc-vec2(0.5)); + float det = min(lod/(proj_lod*0.5), 1.0); + float d = min(dist.x, dist.y); + d *= min(1, d * (proj_lod - lod)); + float edge = 0.25*det; + ret *= clamp(d/edge, 0.0, 1.0); + return ret; } vec4 texture2DLodDiffuse(sampler2D projectionMap, vec2 tc, float lod) { vec4 ret = texture2DLod(projectionMap, tc, lod); - + ret = srgb_to_linear(ret); + vec2 dist = vec2(0.5) - abs(tc-vec2(0.5)); float det = min(lod/(proj_lod*0.5), 1.0); @@ -101,6 +105,7 @@ vec4 texture2DLodDiffuse(sampler2D projectionMap, vec2 tc, float lod) vec4 texture2DLodAmbient(sampler2D projectionMap, vec2 tc, float lod) { vec4 ret = texture2DLod(projectionMap, tc, lod); + ret = srgb_to_linear(ret); vec2 dist = tc-vec2(0.5); @@ -111,53 +116,28 @@ vec4 texture2DLodAmbient(sampler2D projectionMap, vec2 tc, float lod) return ret; } - -vec4 getPosition(vec2 pos_screen) -{ - float depth = texture2DRect(depthMap, pos_screen.xy).r; - vec2 sc = pos_screen.xy*2.0; - sc /= screen_res; - sc -= vec2(1.0,1.0); - vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0); - vec4 pos = inv_proj * ndc; - pos /= pos.w; - pos.w = 1.0; - return pos; -} - -vec3 unpack(vec2 tc) -{ -//#define PACK_NORMALS -#ifdef PACK_NORMALS - vec2 enc = texture2DRect(normalMap, tc).xy; - enc = enc*4.0-2.0; - float prod = dot(enc,enc); - return vec3(enc*sqrt(1.0-prod*.25),1.0-prod*.5); -#else - vec3 norm = texture2DRect(normalMap, tc).xyz; - return norm*2.0-1.0; -#endif -} - void main() { vec4 frag = vary_fragcoord; frag.xyz /= frag.w; frag.xyz = frag.xyz*0.5+0.5; - frag.xy *= screen_res; vec3 pos = getPosition(frag.xy).xyz; vec3 lv = center.xyz-pos.xyz; - float dist2 = dot(lv,lv); - dist2 /= size; - if (dist2 > 1.0) + float dist = length(lv); + dist /= size; + if (dist > 1.0) { discard; } - - vec3 norm = unpack(frag.xy); // unpack norm + + vec3 norm = texture2D(normalMap, frag.xy).xyz; + + float envIntensity = norm.z; + + norm = decode_normal(norm.xy); - //norm = normalize(norm); // may be superfluous + norm = normalize(norm); float l_dist = -dot(lv, proj_n); vec4 proj_tc = (proj_mat * vec4(pos.xyz, 1.0)); @@ -169,7 +149,10 @@ void main() proj_tc.xyz /= proj_tc.w; float fa = falloff+1.0; - float dist_atten = min(1.0-(dist2-1.0*(1.0-fa))/fa, 1.0); + float dist_atten = min(1.0-(dist-1.0*(1.0-fa))/fa, 1.0); + dist_atten *= dist_atten; + dist_atten *= 2.0; + if (dist_atten <= 0.0) { discard; @@ -178,12 +161,13 @@ void main() lv = proj_origin-pos.xyz; lv = normalize(lv); float da = dot(norm, lv); - + vec3 col = vec3(0,0,0); - - vec3 diff_tex = texture2DRect(diffuseRect, frag.xy).rgb; - - float noise = texture2D(noiseMap, frag.xy/128.0).b; + + vec3 diff_tex = texture2D(diffuseRect, frag.xy).rgb; + vec3 dlit = vec3(0, 0, 0); + + float noise = texture2D(noiseMap, frag.xy*noise_scale).b; if (proj_tc.z > 0.0 && proj_tc.x < 1.0 && proj_tc.y < 1.0 && @@ -195,34 +179,60 @@ void main() if (da > 0.0) { + lit = da * dist_atten * noise; + float diff = clamp((l_dist-proj_focus)/proj_range, 0.0, 1.0); float lod = diff * proj_lod; - + vec4 plcol = texture2DLodDiffuse(projectionMap, proj_tc.xy, lod); - - vec3 lcol = color.rgb * plcol.rgb * plcol.a; - - lit = da * dist_atten * noise; - - col = lcol*lit*diff_tex; + + dlit = color.rgb * plcol.rgb * plcol.a; + + col = dlit*lit*diff_tex; amb_da += (da*0.5)*proj_ambiance; } - + //float diff = clamp((proj_range-proj_focus)/proj_range, 0.0, 1.0); vec4 amb_plcol = texture2DLodAmbient(projectionMap, proj_tc.xy, proj_lod); - + amb_da += (da*da*0.5+0.5)*proj_ambiance; - + amb_da *= dist_atten * noise; - + amb_da = min(amb_da, 1.0-lit); - - col += amb_da*color.rgb*diff_tex.rgb*amb_plcol.rgb*amb_plcol.a; + + col += amb_da*color*diff_tex*amb_plcol.rgb*amb_plcol.a; } - - - vec4 spec = texture2DRect(specularRect, frag.xy); + + + vec4 spec = texture2D(specularRect, frag.xy); + if (spec.a > 0.0) + { + dlit *= min(da*6.0, 1.0) * dist_atten; + + vec3 npos = -normalize(pos); + + //vec3 ref = dot(pos+lv, norm); + vec3 h = normalize(lv+npos); + float nh = dot(norm, h); + float nv = dot(norm, npos); + float vh = dot(npos, h); + float sa = nh; + float fres = pow(1 - dot(h, npos), 5)*0.4+0.5; + + float gtdenom = 2 * nh; + float gt = max(0, min(gtdenom * nv / vh, gtdenom * da / vh)); + + if (nh > 0.0) + { + float scol = fres*texture2D(lightFunc, vec2(nh, spec.a)).r*gt/(nh*da); + col += dlit*scol*spec.rgb; + //col += spec.rgb; + } + } + + if (envIntensity > 0.0) { vec3 ref = reflect(normalize(pos), norm); @@ -233,29 +243,27 @@ void main() if (ds < 0.0) { vec3 pfinal = pos + ref * dot(pdelta, proj_n)/ds; - + vec4 stc = (proj_mat * vec4(pfinal.xyz, 1.0)); if (stc.z > 0.0) { - stc.xy /= stc.w; + stc /= stc.w; - float fatten = clamp(spec.a*spec.a+spec.a*0.5, 0.25, 1.0); - - stc.xy = (stc.xy - vec2(0.5)) * fatten + vec2(0.5); - if (stc.x < 1.0 && stc.y < 1.0 && stc.x > 0.0 && stc.y > 0.0) { - vec4 scol = texture2DLodSpecular(projectionMap, stc.xy, proj_lod-spec.a*proj_lod); - col += dist_atten*scol.rgb*color.rgb*scol.a*spec.rgb; + col += color.rgb * texture2DLodSpecular(projectionMap, stc.xy, (1 - spec.a) * (proj_lod * 0.6)).rgb * envIntensity; } } } } - + + //not sure why, but this line prevents MATBUG-194 + col = max(col, vec3(0.0)); + frag_color.rgb = col; frag_color.a = 0.0; } diff --git a/indra/newview/app_settings/shaders/class1/deferred/normgenF.glsl b/indra/newview/app_settings/shaders/class1/deferred/normgenF.glsl index 62cfa5c316..4152ad0246 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/normgenF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/normgenF.glsl @@ -23,7 +23,7 @@ * $/LicenseInfo$ */ -#extension GL_ARB_texture_rectangle : enable + #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_color; diff --git a/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl index 6c1ff1660b..664595a92d 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl @@ -23,7 +23,7 @@ * $/LicenseInfo$ */ -#extension GL_ARB_texture_rectangle : enable + #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_color; @@ -31,13 +31,13 @@ out vec4 frag_color; #define frag_color gl_FragColor #endif -uniform sampler2DRect diffuseRect; -uniform sampler2DRect specularRect; -uniform sampler2DRect normalMap; +uniform sampler2D diffuseRect; +uniform sampler2D specularRect; +uniform sampler2D normalMap; uniform samplerCube environmentMap; uniform sampler2D noiseMap; uniform sampler2D lightFunc; -uniform sampler2DRect depthMap; +uniform sampler2D depthMap; uniform vec3 env_mat[3]; uniform float sun_wash; @@ -49,83 +49,71 @@ uniform float size; VARYING vec4 vary_fragcoord; VARYING vec3 trans_center; -uniform vec2 screen_res; - uniform mat4 inv_proj; uniform vec4 viewport; +uniform vec2 noise_scale; -vec4 getPosition(vec2 pos_screen) -{ - float depth = texture2DRect(depthMap, pos_screen.xy).r; - vec2 sc = (pos_screen.xy-viewport.xy)*2.0; - sc /= viewport.zw; - sc -= vec2(1.0,1.0); - vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0); - vec4 pos = inv_proj * ndc; - pos /= pos.w; - pos.w = 1.0; - return pos; -} - -vec3 unpack(vec2 tc) -{ -//#define PACK_NORMALS -#ifdef PACK_NORMALS - vec2 enc = texture2DRect(normalMap, tc).xy; - enc = enc*4.0-2.0; - float prod = dot(enc,enc); - return vec3(enc*sqrt(1.0-prod*.25),1.0-prod*.5); -#else - vec3 norm = texture2DRect(normalMap, tc).xyz; - return norm*2.0-1.0; -#endif -} +vec3 decode_normal(vec2 enc); +vec4 getPosition(vec2 pos_screen); void main() { vec4 frag = vary_fragcoord; frag.xyz /= frag.w; frag.xyz = frag.xyz*0.5+0.5; - frag.xy *= screen_res; vec3 pos = getPosition(frag.xy).xyz; vec3 lv = trans_center.xyz-pos; - float dist2 = dot(lv,lv); - dist2 /= size; - if (dist2 > 1.0) + float dist = length(lv); + dist /= size; + if (dist > 1.0) { discard; } - vec3 norm = unpack(frag.xy); // unpack norm + vec3 norm = texture2D(normalMap, frag.xy).xyz; + norm = decode_normal(norm.xy); // unpack norm float da = dot(norm, lv); if (da < 0.0) { discard; } - //norm = normalize(norm); // may be superfluous + norm = normalize(norm); lv = normalize(lv); da = dot(norm, lv); - float noise = texture2D(noiseMap, frag.xy/128.0).b; + float noise = texture2D(noiseMap, frag.xy*noise_scale).b; - vec3 col = texture2DRect(diffuseRect, frag.xy).rgb; + vec3 col = texture2D(diffuseRect, frag.xy).rgb; float fa = falloff+1.0; - float dist_atten = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0); - float lit = da * dist_atten * noise; + float dist_atten = clamp(1.0-(dist-1.0*(1.0-fa))/fa, 0.0, 1.0); + dist_atten *= dist_atten; + dist_atten *= 2.0; + float lit = da * dist_atten * noise; + col = color.rgb*lit*col; - vec4 spec = texture2DRect(specularRect, frag.xy); + vec4 spec = texture2D(specularRect, frag.xy); if (spec.a > 0.0) { - float sa = dot(normalize(lv-normalize(pos)),norm); - if (sa > 0.0) + lit = min(da*6.0, 1.0) * dist_atten; + + vec3 npos = -normalize(pos); + vec3 h = normalize(lv+npos); + float nh = dot(norm, h); + float nv = dot(norm, npos); + float vh = dot(npos, h); + float sa = nh; + float fres = pow(1 - dot(h, npos), 5) * 0.4+0.5; + float gtdenom = 2 * nh; + float gt = max(0,(min(gtdenom * nv / vh, gtdenom * da / vh))); + + if (nh > 0.0) { - sa = 6 * texture2D(lightFunc, vec2(sa, spec.a)).r * min(dist_atten*4.0, 1.0); - sa *= noise; - col += da*sa*color.rgb*spec.rgb; + float scol = fres*texture2D(lightFunc, vec2(nh, spec.a)).r*gt/(nh*da); + col += lit*scol*color.rgb*spec.rgb; } } diff --git a/indra/newview/app_settings/shaders/class1/deferred/pointLightV.glsl b/indra/newview/app_settings/shaders/class1/deferred/pointLightV.glsl index 9491421236..a5625fbc16 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/pointLightV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/pointLightV.glsl @@ -37,7 +37,7 @@ VARYING vec3 trans_center; void main() { //transform vertex - vec3 p = position*sqrt(size)+center; + vec3 p = position*size+center; vec4 pos = modelview_projection_matrix * vec4(p.xyz, 1.0); vary_fragcoord = pos; trans_center = (modelview_matrix*vec4(center.xyz, 1.0)).xyz; diff --git a/indra/newview/app_settings/shaders/class1/deferred/postDeferredF.glsl b/indra/newview/app_settings/shaders/class1/deferred/postDeferredF.glsl index bf362e21a4..0a89597b35 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/postDeferredF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/postDeferredF.glsl @@ -23,7 +23,7 @@ * $/LicenseInfo$ */ -#extension GL_ARB_texture_rectangle : enable + #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_color; @@ -31,18 +31,18 @@ out vec4 frag_color; #define frag_color gl_FragColor #endif -uniform sampler2DRect diffuseRect; +uniform sampler2D diffuseRect; uniform mat4 inv_proj; -uniform vec2 screen_res; uniform float max_cof; uniform float res_scale; +uniform vec2 kern_scale; VARYING vec2 vary_fragcoord; void dofSample(inout vec4 diff, inout float w, float min_sc, vec2 tc) { - vec4 s = texture2DRect(diffuseRect, tc); + vec4 s = texture2D(diffuseRect, tc); float sc = abs(s.a*2.0-1.0)*max_cof; @@ -61,7 +61,7 @@ void dofSample(inout vec4 diff, inout float w, float min_sc, vec2 tc) void dofSampleNear(inout vec4 diff, inout float w, float min_sc, vec2 tc) { - vec4 s = texture2DRect(diffuseRect, tc); + vec4 s = texture2D(diffuseRect, tc); float wg = 0.25; @@ -77,7 +77,7 @@ void main() { vec2 tc = vary_fragcoord.xy; - vec4 diff = texture2DRect(diffuseRect, vary_fragcoord.xy); + vec4 diff = texture2D(diffuseRect, tc); { float w = 1.0; @@ -98,7 +98,7 @@ void main() float samp_x = sc*sin(ang); float samp_y = sc*cos(ang); // you could test sample coords against an interesting non-circular aperture shape here, if desired. - dofSampleNear(diff, w, sc, vary_fragcoord.xy + vec2(samp_x,samp_y)); + dofSampleNear(diff, w, sc, tc + vec2(samp_x,samp_y) * kern_scale); } sc -= 1.0; } @@ -115,7 +115,7 @@ void main() float samp_x = sc*sin(ang); float samp_y = sc*cos(ang); // you could test sample coords against an interesting non-circular aperture shape here, if desired. - dofSample(diff, w, sc, vary_fragcoord.xy + vec2(samp_x,samp_y)); + dofSample(diff, w, sc, tc + vec2(samp_x,samp_y) * kern_scale); } sc -= 1.0; } diff --git a/indra/newview/app_settings/shaders/class1/deferred/postDeferredGammaCorrectF.glsl b/indra/newview/app_settings/shaders/class1/deferred/postDeferredGammaCorrectF.glsl new file mode 100644 index 0000000000..db80130546 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/postDeferredGammaCorrectF.glsl @@ -0,0 +1,48 @@ +/** + * @file postDeferredGammaCorrect.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2007, 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$ + */ + + + +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_color; +#else +#define frag_color gl_FragColor +#endif + +uniform sampler2D diffuseRect; + +VARYING vec2 vary_fragcoord; + +//uniform float display_gamma; + +vec3 linear_to_srgb(vec3 cl); + +void main() +{ + vec4 diff = texture2D(diffuseRect, vary_fragcoord); + diff.rgb = linear_to_srgb(diff.rgb); + frag_color = diff; +} + diff --git a/indra/newview/app_settings/shaders/class1/deferred/postDeferredNoDoFF.glsl b/indra/newview/app_settings/shaders/class1/deferred/postDeferredNoDoFF.glsl index eb5beeef39..47b6774f90 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/postDeferredNoDoFF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/postDeferredNoDoFF.glsl @@ -23,7 +23,7 @@ * $/LicenseInfo$ */ -#extension GL_ARB_texture_rectangle : enable + #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_color; @@ -31,17 +31,16 @@ out vec4 frag_color; #define frag_color gl_FragColor #endif -uniform sampler2DRect diffuseRect; +uniform sampler2D diffuseRect; uniform sampler2D bloomMap; -uniform vec2 screen_res; VARYING vec2 vary_fragcoord; void main() { - vec4 diff = texture2DRect(diffuseRect, vary_fragcoord.xy); + vec4 diff = texture2D(diffuseRect, vary_fragcoord.xy); - vec4 bloom = texture2D(bloomMap, vary_fragcoord.xy/screen_res); + vec4 bloom = texture2D(bloomMap, vary_fragcoord.xy); frag_color = diff + bloom; } diff --git a/indra/newview/app_settings/shaders/class1/deferred/postDeferredNoTCV.glsl b/indra/newview/app_settings/shaders/class1/deferred/postDeferredNoTCV.glsl index bd0cb50464..a8465d61bb 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/postDeferredNoTCV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/postDeferredNoTCV.glsl @@ -29,12 +29,10 @@ ATTRIBUTE vec3 position; VARYING vec2 vary_fragcoord; -uniform vec2 screen_res; - void main() { //transform vertex vec4 pos = modelview_projection_matrix * vec4(position.xyz, 1.0); gl_Position = pos; - vary_fragcoord = (pos.xy*0.5+0.5)*screen_res; + vary_fragcoord = (pos.xy*0.5+0.5); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/postDeferredV.glsl b/indra/newview/app_settings/shaders/class1/deferred/postDeferredV.glsl deleted file mode 100644 index 8edf5b2723..0000000000 --- a/indra/newview/app_settings/shaders/class1/deferred/postDeferredV.glsl +++ /dev/null @@ -1,44 +0,0 @@ -/** - * @file postDeferredV.glsl - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2007, 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$ - */ - -uniform mat4 modelview_projection_matrix; - -ATTRIBUTE vec3 position; - -VARYING vec2 vary_fragcoord; -VARYING vec2 vary_tc; - -uniform vec2 tc_scale; - -uniform vec2 screen_res; - -void main() -{ - //transform vertex - vec4 pos = modelview_projection_matrix * vec4(position.xyz, 1.0); - gl_Position = pos; - vary_tc = (pos.xy*0.5+0.5)*tc_scale; - vary_fragcoord = (pos.xy*0.5+0.5)*screen_res; -} diff --git a/indra/newview/app_settings/shaders/class1/deferred/postgiF.glsl b/indra/newview/app_settings/shaders/class1/deferred/postgiF.glsl index 96f9628424..3c035ef7bf 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/postgiF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/postgiF.glsl @@ -47,18 +47,7 @@ VARYING vec2 vary_fragcoord; uniform mat4 inv_proj; uniform vec2 screen_res; -vec4 getPosition(vec2 pos_screen) -{ - float depth = texture2DRect(depthMap, pos_screen.xy).a; - vec2 sc = pos_screen.xy*2.0; - sc /= screen_res; - sc -= vec2(1.0,1.0); - vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0); - vec4 pos = inv_proj * ndc; - pos /= pos.w; - pos.w = 1.0; - return pos; -} +vec4 getPosition(vec2 pos_screen); void main() { diff --git a/indra/newview/app_settings/shaders/class1/deferred/skyF.glsl b/indra/newview/app_settings/shaders/class1/deferred/skyF.glsl index 4eefdd8b65..3e861a0439 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/skyF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/skyF.glsl @@ -61,11 +61,7 @@ void main() /// Gamma correct for WL (soft clip effect). frag_data[0] = vec4(scaleSoftClip(color.rgb), 1.0); frag_data[1] = vec4(vary_HazeColor.a,0.0,0.0,0.0); -//#define PACK_NORMALS -#ifdef PACK_NORMALS - frag_data[2] = vec4(0.5,0.5,0.0,0.0); -#else - frag_data[2] = vec4(0.0,0.0,1.0,0.0); -#endif + frag_data[2] = vec4(0.5,0.5,0.0,1.0); + } diff --git a/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl index 066cdd3480..06c5097084 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl @@ -23,7 +23,6 @@ * $/LicenseInfo$ */ -#extension GL_ARB_texture_rectangle : enable #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_color; @@ -31,12 +30,11 @@ out vec4 frag_color; #define frag_color gl_FragColor #endif -uniform sampler2DRect diffuseRect; -uniform sampler2DRect specularRect; -uniform sampler2DRect positionMap; -uniform sampler2DRect normalMap; -uniform sampler2DRect lightMap; -uniform sampler2DRect depthMap; +uniform sampler2D diffuseRect; +uniform sampler2D specularRect; +uniform sampler2D normalMap; +uniform sampler2D lightMap; +uniform sampler2D depthMap; uniform samplerCube environmentMap; uniform sampler2D lightFunc; @@ -60,9 +58,9 @@ uniform float density_multiplier; uniform float distance_multiplier; uniform float max_y; uniform vec4 glow; +uniform float global_gamma; uniform float scene_light_strength; uniform mat3 env_mat; -uniform float ssao_effect; uniform vec3 sun_dir; VARYING vec2 vary_fragcoord; @@ -75,12 +73,14 @@ vec3 vary_AdditiveColor; vec3 vary_AtmosAttenuation; uniform mat4 inv_proj; -uniform vec2 screen_res; + +vec3 decode_normal(vec2 enc); +vec3 srgb_to_linear(vec3 cs); +vec3 linear_to_srgb(vec3 cl); vec4 getPosition_d(vec2 pos_screen, float depth) { vec2 sc = pos_screen.xy*2.0; - sc /= screen_res; sc -= vec2(1.0,1.0); vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0); vec4 pos = inv_proj * ndc; @@ -89,12 +89,6 @@ vec4 getPosition_d(vec2 pos_screen, float depth) return pos; } -vec4 getPosition(vec2 pos_screen) -{ //get position in screen space (world units) given window coordinate and depth map - float depth = texture2DRect(depthMap, pos_screen.xy).a; - return getPosition_d(pos_screen, depth); -} - vec3 getPositionEye() { return vary_PositionEye; @@ -142,7 +136,53 @@ void setAtmosAttenuation(vec3 v) vary_AtmosAttenuation = v; } -void calcAtmospherics(vec3 inPositionEye, float ambFactor) { +#ifdef WATER_FOG +uniform vec4 waterPlane; +uniform vec4 waterFogColor; +uniform float waterFogDensity; +uniform float waterFogKS; + +vec4 applyWaterFogDeferred(vec3 pos, vec4 color) +{ + //normalize view vector + vec3 view = normalize(pos); + float es = -(dot(view, waterPlane.xyz)); + + //find intersection point with water plane and eye vector + + //get eye depth + float e0 = max(-waterPlane.w, 0.0); + + vec3 int_v = waterPlane.w > 0.0 ? view * waterPlane.w/es : vec3(0.0, 0.0, 0.0); + + //get object depth + float depth = length(pos - int_v); + + //get "thickness" of water + float l = max(depth, 0.1); + + float kd = waterFogDensity; + float ks = waterFogKS; + vec4 kc = waterFogColor; + + float F = 0.98; + + float t1 = -kd * pow(F, ks * e0); + float t2 = kd + ks * es; + float t3 = pow(F, t2*l) - 1.0; + + float L = min(t1/t2*t3, 1.0); + + float D = pow(0.98, l*kd); + + color.rgb = color.rgb * D + kc.rgb * L; + color.a = kc.a + color.a; + + return color; +} +#endif + +void calcAtmospherics(vec3 inPositionEye) { vec3 P = inPositionEye; setPositionEye(P); @@ -209,9 +249,6 @@ void calcAtmospherics(vec3 inPositionEye, float ambFactor) { + (haze_horizon * haze_weight) * (sunlight*(1.-cloud_shadow) * temp2.x + tmpAmbient))); - // decrease value for occluded areas - tmpAmbient = vec4(mix(ssao_effect * tmpAmbient.rgb, tmpAmbient.rgb, ambFactor), tmpAmbient.a); - //brightness of surface both sunlight and ambient setSunlitColor(vec3(sunlight * .5)); setAmblitColor(vec3(tmpAmbient * .25)); @@ -230,6 +267,15 @@ vec3 atmosTransport(vec3 light) { light += getAdditiveColor() * 2.0; return light; } + +vec3 fullbrightAtmosTransport(vec3 light) { + float brightness = dot(light.rgb, vec3(0.33333)); + + return mix(atmosTransport(light.rgb), light.rgb + getAdditiveColor().rgb, brightness * brightness); +} + + + vec3 atmosGetDiffuseSunlightColor() { return getSunlitColor(); @@ -264,18 +310,10 @@ vec3 scaleSoftClip(vec3 light) return light; } -vec3 unpack(vec2 tc) +vec3 fullbrightScaleSoftClip(vec3 light) { -//#define PACK_NORMALS -#ifdef PACK_NORMALS - vec2 enc = texture2DRect(normalMap, tc).xy; - enc = enc*4.0-2.0; - float prod = dot(enc,enc); - return vec3(enc*sqrt(1.0-prod*.25),1.0-prod*.5); -#else - vec3 norm = texture2DRect(normalMap, tc).xyz; - return norm*2.0-1.0; -#endif + //soft clip effect: + return light; } float luminance(vec3 color) @@ -288,56 +326,93 @@ float luminance(vec3 color) void main() { vec2 tc = vary_fragcoord.xy; - float depth = texture2DRect(depthMap, tc.xy).r; + float depth = texture2D(depthMap, tc.xy).r; vec3 pos = getPosition_d(tc, depth).xyz; - vec3 norm = unpack(tc); // unpack norm + vec4 norm = texture2D(normalMap, tc); + float envIntensity = norm.z; + norm.xyz = decode_normal(norm.xy); // unpack norm - float da = max(dot(norm.xyz, sun_dir.xyz), 0.0); - - vec4 diffuse = texture2DRect(diffuseRect, tc); - vec4 spec = texture2DRect(specularRect, vary_fragcoord.xy); - + vec4 diffuse = texture2D(diffuseRect, tc); + + //convert to gamma space + diffuse.rgb = linear_to_srgb(diffuse.rgb); + vec3 col; float bloom = 0.0; - if (diffuse.a < 0.9) { - calcAtmospherics(pos.xyz, 1.0); + vec4 spec = texture2D(specularRect, vary_fragcoord.xy); + bloom = spec.r*norm.w; + if (norm.w < 0.5) + { + float da = dot(norm.xyz, sun_dir.xyz); + + float final_da = max(0.0,da); + final_da = min(final_da, 1.0f); + final_da = pow(final_da, 1.0/1.3); + calcAtmospherics(pos.xyz); col = atmosAmbient(vec3(0)); - col += atmosAffectDirectionalLight(max(min(da, 1.0), diffuse.a)); + float ambient = min(abs(dot(norm.xyz, sun_dir.xyz)), 1.0); + ambient *= 0.5; + ambient *= ambient; + ambient = (1.0-ambient); + + col.rgb *= ambient; + + col += atmosAffectDirectionalLight(final_da); col *= diffuse.rgb; + vec3 refnormpersp = normalize(reflect(pos.xyz, norm.xyz)); + if (spec.a > 0.0) // specular reflection { // the old infinite-sky shiny reflection // - vec3 refnormpersp = normalize(reflect(pos.xyz, norm.xyz)); + float sa = dot(refnormpersp, sun_dir.xyz); - vec3 dumbshiny = vary_SunlitColor*(6 * texture2D(lightFunc, vec2(sa, spec.a)).r); + vec3 dumbshiny = vary_SunlitColor*(texture2D(lightFunc, vec2(sa, spec.a)).r); // add the two types of shiny together vec3 spec_contrib = dumbshiny * spec.rgb; - bloom = dot(spec_contrib, spec_contrib) / 4; + bloom = dot(spec_contrib, spec_contrib) / 6; col += spec_contrib; - - //add environmentmap + } + + + col = mix(col.rgb, diffuse.rgb, diffuse.a); + + if (envIntensity > 0.0) + { //add environmentmap vec3 env_vec = env_mat * refnormpersp; - vec3 env = textureCube(environmentMap, env_vec).rgb; - bloom = (luminance(env) - .45)*.25; - col = mix(col.rgb, env, - max(spec.a-diffuse.a*2.0, 0.0)); + vec3 refcol = textureCube(environmentMap, env_vec).rgb; + bloom = (luminance(refcol) - .45)*.25; + col = mix(col.rgb, refcol, + envIntensity); + } + + //if (norm.w < 0.5) + { + col = mix(atmosLighting(col), fullbrightAtmosTransport(col), diffuse.a); + col = mix(scaleSoftClip(col), fullbrightScaleSoftClip(col), diffuse.a); + //bloom += (luminance(col))*.075; //This looks nice, but requires a larger glow rendertarget. } - - col = atmosLighting(col); - col = scaleSoftClip(col); - col = mix(col, diffuse.rgb, diffuse.a); - } - else - { - bloom = spec.r; - col = diffuse.rgb; + #ifdef WATER_FOG + vec4 fogged = applyWaterFogDeferred(pos,vec4(col, bloom)); + col = fogged.rgb; + bloom = fogged.a; + #endif + } + else + { + col = diffuse.rgb; + } + + col = srgb_to_linear(col); + + //col = vec3(1,0,1); + //col.g = envIntensity; } frag_color.rgb = col; diff --git a/indra/newview/app_settings/shaders/class1/deferred/softenLightV.glsl b/indra/newview/app_settings/shaders/class1/deferred/softenLightV.glsl deleted file mode 100644 index c6031fc45a..0000000000 --- a/indra/newview/app_settings/shaders/class1/deferred/softenLightV.glsl +++ /dev/null @@ -1,40 +0,0 @@ -/** - * @file softenLightF.glsl - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2007, 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$ - */ - -uniform mat4 modelview_projection_matrix; - -ATTRIBUTE vec3 position; - -uniform vec2 screen_res; - -VARYING vec2 vary_fragcoord; -void main() -{ - //transform vertex - vec4 pos = modelview_projection_matrix * vec4(position.xyz, 1.0); - gl_Position = pos; - - vary_fragcoord = (pos.xy*0.5+0.5)*screen_res; -} diff --git a/indra/newview/app_settings/shaders/class1/deferred/spotLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/spotLightF.glsl index ae64d89371..1cecb30e69 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/spotLightF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/spotLightF.glsl @@ -23,7 +23,6 @@ * $/LicenseInfo$ */ - #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_color; #else @@ -32,15 +31,14 @@ out vec4 frag_color; //class 1 -- no shadows -#extension GL_ARB_texture_rectangle : enable - -uniform sampler2DRect diffuseRect; -uniform sampler2DRect specularRect; -uniform sampler2DRect depthMap; -uniform sampler2DRect normalMap; +uniform sampler2D diffuseRect; +uniform sampler2D specularRect; +uniform sampler2D depthMap; +uniform sampler2D normalMap; uniform samplerCube environmentMap; uniform sampler2D noiseMap; uniform sampler2D projectionMap; +uniform sampler2D lightFunc; uniform mat4 proj_mat; //screen space to light space uniform float proj_near; //near clip for projection @@ -57,36 +55,41 @@ uniform float far_clip; uniform vec3 proj_origin; //origin of projection to be used for angular attenuation uniform float sun_wash; + uniform vec3 color; uniform float falloff; uniform float size; -VARYING vec4 vary_fragcoord; VARYING vec3 trans_center; - -uniform vec2 screen_res; +VARYING vec4 vary_fragcoord; uniform mat4 inv_proj; +uniform vec2 noise_scale; + +vec3 decode_normal(vec2 enc); +vec4 getPosition(vec2 pos_screen); +vec4 srgb_to_linear(vec4 cs); vec4 texture2DLodSpecular(sampler2D projectionMap, vec2 tc, float lod) { vec4 ret = texture2DLod(projectionMap, tc, lod); - - vec2 dist = tc-vec2(0.5); - - float det = max(1.0-lod/(proj_lod*0.5), 0.0); - - float d = dot(dist,dist); - - ret *= min(clamp((0.25-d)/0.25, 0.0, 1.0)+det, 1.0); - + + ret = srgb_to_linear(ret); + vec2 dist = vec2(0.5) - abs(tc-vec2(0.5)); + float det = min(lod/(proj_lod*0.5), 1.0); + float d = min(dist.x, dist.y); + d *= min(1, d * (proj_lod - lod)); + float edge = 0.25*det; + ret *= clamp(d/edge, 0.0, 1.0); + return ret; } vec4 texture2DLodDiffuse(sampler2D projectionMap, vec2 tc, float lod) { vec4 ret = texture2DLod(projectionMap, tc, lod); - + ret = srgb_to_linear(ret); + vec2 dist = vec2(0.5) - abs(tc-vec2(0.5)); float det = min(lod/(proj_lod*0.5), 1.0); @@ -103,6 +106,7 @@ vec4 texture2DLodDiffuse(sampler2D projectionMap, vec2 tc, float lod) vec4 texture2DLodAmbient(sampler2D projectionMap, vec2 tc, float lod) { vec4 ret = texture2DLod(projectionMap, tc, lod); + ret = srgb_to_linear(ret); vec2 dist = tc-vec2(0.5); @@ -113,53 +117,28 @@ vec4 texture2DLodAmbient(sampler2D projectionMap, vec2 tc, float lod) return ret; } - -vec4 getPosition(vec2 pos_screen) -{ - float depth = texture2DRect(depthMap, pos_screen.xy).r; - vec2 sc = pos_screen.xy*2.0; - sc /= screen_res; - sc -= vec2(1.0,1.0); - vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0); - vec4 pos = inv_proj * ndc; - pos /= pos.w; - pos.w = 1.0; - return pos; -} - -vec3 unpack(vec2 tc) -{ -//#define PACK_NORMALS -#ifdef PACK_NORMALS - vec2 enc = texture2DRect(normalMap, tc).xy; - enc = enc*4.0-2.0; - float prod = dot(enc,enc); - return vec3(enc*sqrt(1.0-prod*.25),1.0-prod*.5); -#else - vec3 norm = texture2DRect(normalMap, tc).xyz; - return norm*2.0-1.0; -#endif -} - void main() { vec4 frag = vary_fragcoord; frag.xyz /= frag.w; frag.xyz = frag.xyz*0.5+0.5; - frag.xy *= screen_res; vec3 pos = getPosition(frag.xy).xyz; vec3 lv = trans_center.xyz-pos.xyz; - float dist2 = dot(lv,lv); - dist2 /= size; - if (dist2 > 1.0) + float dist = length(lv); + dist /= size; + if (dist > 1.0) { discard; } - - vec3 norm = unpack(frag.xy); // unpack norm + + vec3 norm = texture2D(normalMap, frag.xy).xyz; + + float envIntensity = norm.z; + + norm = decode_normal(norm.xy); - //norm = normalize(norm); // may be superfluous + norm = normalize(norm); float l_dist = -dot(lv, proj_n); vec4 proj_tc = (proj_mat * vec4(pos.xyz, 1.0)); @@ -171,7 +150,10 @@ void main() proj_tc.xyz /= proj_tc.w; float fa = falloff+1.0; - float dist_atten = min(1.0-(dist2-1.0*(1.0-fa))/fa, 1.0); + float dist_atten = min(1.0-(dist-1.0*(1.0-fa))/fa, 1.0); + dist_atten *= dist_atten; + dist_atten *= 2.0; + if (dist_atten <= 0.0) { discard; @@ -180,12 +162,13 @@ void main() lv = proj_origin-pos.xyz; lv = normalize(lv); float da = dot(norm, lv); - + vec3 col = vec3(0,0,0); - - vec3 diff_tex = texture2DRect(diffuseRect, frag.xy).rgb; - - float noise = texture2D(noiseMap, frag.xy/128.0).b; + + vec3 diff_tex = texture2D(diffuseRect, frag.xy).rgb; + vec3 dlit = vec3(0, 0, 0); + + float noise = texture2D(noiseMap, frag.xy*noise_scale).b; if (proj_tc.z > 0.0 && proj_tc.x < 1.0 && proj_tc.y < 1.0 && @@ -197,34 +180,60 @@ void main() if (da > 0.0) { + lit = da * dist_atten * noise; + float diff = clamp((l_dist-proj_focus)/proj_range, 0.0, 1.0); float lod = diff * proj_lod; - + vec4 plcol = texture2DLodDiffuse(projectionMap, proj_tc.xy, lod); - - vec3 lcol = color.rgb * plcol.rgb * plcol.a; - - lit = da * dist_atten * noise; - - col = lcol*lit*diff_tex; + + dlit = color.rgb * plcol.rgb * plcol.a; + + col = dlit*lit*diff_tex; amb_da += (da*0.5)*proj_ambiance; } - + //float diff = clamp((proj_range-proj_focus)/proj_range, 0.0, 1.0); vec4 amb_plcol = texture2DLodAmbient(projectionMap, proj_tc.xy, proj_lod); - + amb_da += (da*da*0.5+0.5)*proj_ambiance; - + amb_da *= dist_atten * noise; - + amb_da = min(amb_da, 1.0-lit); - - col += amb_da*color.rgb*diff_tex.rgb*amb_plcol.rgb*amb_plcol.a; + + col += amb_da*color*diff_tex*amb_plcol.rgb*amb_plcol.a; } - - - vec4 spec = texture2DRect(specularRect, frag.xy); + + + vec4 spec = texture2D(specularRect, frag.xy); + if (spec.a > 0.0) + { + dlit *= min(da*6.0, 1.0) * dist_atten; + + vec3 npos = -normalize(pos); + + //vec3 ref = dot(pos+lv, norm); + vec3 h = normalize(lv+npos); + float nh = dot(norm, h); + float nv = dot(norm, npos); + float vh = dot(npos, h); + float sa = nh; + float fres = pow(1 - dot(h, npos), 5)*0.4+0.5; + + float gtdenom = 2 * nh; + float gt = max(0, min(gtdenom * nv / vh, gtdenom * da / vh)); + + if (nh > 0.0) + { + float scol = fres*texture2D(lightFunc, vec2(nh, spec.a)).r*gt/(nh*da); + col += dlit*scol*spec.rgb; + //col += spec.rgb; + } + } + + if (envIntensity > 0.0) { vec3 ref = reflect(normalize(pos), norm); @@ -235,29 +244,27 @@ void main() if (ds < 0.0) { vec3 pfinal = pos + ref * dot(pdelta, proj_n)/ds; - + vec4 stc = (proj_mat * vec4(pfinal.xyz, 1.0)); if (stc.z > 0.0) { - stc.xy /= stc.w; + stc /= stc.w; - float fatten = clamp(spec.a*spec.a+spec.a*0.5, 0.25, 1.0); - - stc.xy = (stc.xy - vec2(0.5)) * fatten + vec2(0.5); - if (stc.x < 1.0 && stc.y < 1.0 && stc.x > 0.0 && stc.y > 0.0) { - vec4 scol = texture2DLodSpecular(projectionMap, stc.xy, proj_lod-spec.a*proj_lod); - col += dist_atten*scol.rgb*color.rgb*scol.a*spec.rgb; + col += color.rgb * texture2DLodSpecular(projectionMap, stc.xy, (1 - spec.a) * (proj_lod * 0.6)).rgb * envIntensity; } } } } - + + //not sure why, but this line prevents MATBUG-194 + col = max(col, vec3(0.0)); + frag_color.rgb = col; frag_color.a = 0.0; } diff --git a/indra/newview/app_settings/shaders/class1/deferred/srgb.glsl b/indra/newview/app_settings/shaders/class1/deferred/srgb.glsl new file mode 100644 index 0000000000..587f3d5a94 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/srgb.glsl @@ -0,0 +1,46 @@ +/** + * @file srgb.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2007, 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$ + */ + +vec3 srgb_to_linear(vec3 cs) +{ + vec3 low_range = cs / vec3(12.92); + vec3 high_range = pow((cs+vec3(0.055))/vec3(1.055), vec3(2.4)); + + bvec3 lte = lessThanEqual(cs,vec3(0.04045)); + return mix(high_range, low_range, lte); + +} + +vec3 linear_to_srgb(vec3 cl) +{ + cl = clamp(cl, vec3(0), vec3(1)); + vec3 low_range = cl * 12.92; + vec3 high_range = 1.055 * pow(cl, vec3(0.41666)) - 0.055; + + bvec3 lt = lessThan(cl,vec3(0.0031308)); + return mix(high_range, low_range, lt); + +} + diff --git a/indra/newview/app_settings/shaders/class1/deferred/srgb_mac.glsl b/indra/newview/app_settings/shaders/class1/deferred/srgb_mac.glsl new file mode 100644 index 0000000000..6cc1e6e798 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/srgb_mac.glsl @@ -0,0 +1,54 @@ +/** + * @file srgb.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2007, 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$ + */ + +vec3 srgb_to_linear(vec3 cs) +{ + vec3 low_range = cs / vec3(12.92); + vec3 high_range = pow((cs+vec3(0.055))/vec3(1.055), vec3(2.4)); + + bvec3 lte = lessThanEqual(cs,vec3(0.04045)); + + vec3 result; + result.r = lte.r ? low_range.r : high_range.r; + result.g = lte.g ? low_range.g : high_range.g; + result.b = lte.b ? low_range.b : high_range.b; + return result; +} + +vec3 linear_to_srgb(vec3 cl) +{ + cl = clamp(cl, vec3(0), vec3(1)); + vec3 low_range = cl * 12.92; + vec3 high_range = 1.055 * pow(cl, vec3(0.41666)) - 0.055; + + bvec3 lt = lessThan(cl,vec3(0.0031308)); + + vec3 result; + result.r = lt.r ? low_range.r : high_range.r; + result.g = lt.g ? low_range.g : high_range.g; + result.b = lt.b ? low_range.b : high_range.b; + return result; +} + diff --git a/indra/newview/app_settings/shaders/class1/deferred/starsF.glsl b/indra/newview/app_settings/shaders/class1/deferred/starsF.glsl index 2e4b416c42..99e371cf87 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/starsF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/starsF.glsl @@ -42,10 +42,5 @@ void main() frag_data[0] = vec4(col.rgb,col.a*custom_alpha); frag_data[1] = vec4(0,0,0,0); -//#define PACK_NORMALS -#ifdef PACK_NORMALS - frag_data[2] = vec4(0.5,0.5,0.0,0.0); -#else - frag_data[2] = vec4(0.0,0.0,1.0,0.0); -#endif + frag_data[2] = vec4(0.5,0.5,0.0,1.0); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/sunLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/sunLightF.glsl index 5ca817aff6..5177d71a08 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/sunLightF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/sunLightF.glsl @@ -25,7 +25,7 @@ //class 1, no shadow, no SSAO, should never be called -#extension GL_ARB_texture_rectangle : enable + #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_color; diff --git a/indra/newview/app_settings/shaders/class1/deferred/sunLightNoFragCoordV.glsl b/indra/newview/app_settings/shaders/class1/deferred/sunLightNoFragCoordV.glsl index 47e9d15fbc..e872dbf50d 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/sunLightNoFragCoordV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/sunLightNoFragCoordV.glsl @@ -27,8 +27,6 @@ uniform mat4 modelview_projection_matrix; ATTRIBUTE vec3 position; -uniform vec2 screen_res; - void main() { //transform vertex diff --git a/indra/newview/app_settings/shaders/class1/deferred/sunLightSSAOF.glsl b/indra/newview/app_settings/shaders/class1/deferred/sunLightSSAOF.glsl index 24a827e910..cca0fa80f9 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/sunLightSSAOF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/sunLightSSAOF.glsl @@ -23,7 +23,7 @@ */ -#extension GL_ARB_texture_rectangle : enable + #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_color; @@ -31,115 +31,18 @@ out vec4 frag_color; #define frag_color gl_FragColor #endif -//class 1 -- no shadow, SSAO only - -uniform sampler2DRect depthMap; -uniform sampler2DRect normalMap; -uniform sampler2D noiseMap; - - -// Inputs -uniform float ssao_radius; -uniform float ssao_max_radius; -uniform float ssao_factor; -uniform float ssao_factor_inv; - VARYING vec2 vary_fragcoord; -uniform mat4 inv_proj; -uniform vec2 screen_res; - -vec4 getPosition(vec2 pos_screen) -{ - float depth = texture2DRect(depthMap, pos_screen.xy).r; - vec2 sc = pos_screen.xy*2.0; - sc /= screen_res; - sc -= vec2(1.0,1.0); - vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0); - vec4 pos = inv_proj * ndc; - pos /= pos.w; - pos.w = 1.0; - return pos; -} +uniform sampler2D depthMap; -//calculate decreases in ambient lighting when crowded out (SSAO) -float calcAmbientOcclusion(vec4 pos, vec3 norm) -{ - vec2 kern[8]; - // exponentially (^2) distant occlusion samples spread around origin - kern[0] = vec2(-1.0, 0.0) * 0.125*0.125; - kern[1] = vec2(1.0, 0.0) * 0.250*0.250; - kern[2] = vec2(0.0, 1.0) * 0.375*0.375; - kern[3] = vec2(0.0, -1.0) * 0.500*0.500; - kern[4] = vec2(0.7071, 0.7071) * 0.625*0.625; - kern[5] = vec2(-0.7071, -0.7071) * 0.750*0.750; - kern[6] = vec2(-0.7071, 0.7071) * 0.875*0.875; - kern[7] = vec2(0.7071, -0.7071) * 1.000*1.000; +uniform sampler2D diffuseRect; - vec2 pos_screen = vary_fragcoord.xy; - vec3 pos_world = pos.xyz; - vec2 noise_reflect = texture2D(noiseMap, vary_fragcoord.xy/128.0).xy; - - // We treat the first sample as the origin, which definitely doesn't obscure itself thanks to being visible for sampling in the first place. - float points = 1.0; - float angle_hidden = 0.0; - - // use a kernel scale that diminishes with distance. - // a scale of less than 32 is just wasting good samples, though. - float scale = max(32.0, min(ssao_radius / -pos.z, ssao_max_radius)); - - // it was found that keeping # of samples a constant was the fastest, probably due to compiler optimizations (unrolling?) - for (int i = 0; i < 8; i++) - { - vec2 samppos_screen = pos_screen + scale * reflect(kern[i], noise_reflect); - vec3 samppos_world = getPosition(samppos_screen).xyz; - - vec3 diff = samppos_world - pos.xyz; - - if (diff.z < ssao_factor && diff.z != 0.0) - { - float dist = length(diff); - float angrel = max(0.0, dot(norm.xyz, diff/dist)); - float distrel = 1.0/(1.0+dist*dist); - float samplehidden = min(angrel, distrel); - - angle_hidden += (samplehidden); - points += 1.0; - } - } - - angle_hidden /= points; +uniform vec2 ssao_scale; - float rtn = (1.0 - angle_hidden); - - return (rtn * rtn); -} - -vec3 unpack(vec2 tc) -{ -//#define PACK_NORMALS -#ifdef PACK_NORMALS - vec2 enc = texture2DRect(normalMap, tc).xy; - enc = enc*4.0-2.0; - float prod = dot(enc,enc); - return vec3(enc*sqrt(1.0-prod*.25),1.0-prod*.5); -#else - vec3 norm = texture2DRect(normalMap, tc).xyz; - return norm*2.0-1.0; -#endif -} void main() -{ - vec2 pos_screen = vary_fragcoord.xy; - - //try doing an unproject here - - vec4 pos = getPosition(pos_screen); - - vec3 norm = unpack(pos_screen); // unpack norm - +{ frag_color[0] = 1.0; - frag_color[1] = calcAmbientOcclusion(pos, norm); - frag_color[2] = 1.0; + frag_color[1] = texture2D(diffuseRect,vary_fragcoord.xy * ssao_scale).r; // Scales to handle lower-res ssao. + frag_color[2] = 1.0; frag_color[3] = 1.0; } diff --git a/indra/newview/app_settings/shaders/class1/deferred/sunLightV.glsl b/indra/newview/app_settings/shaders/class1/deferred/sunLightV.glsl deleted file mode 100644 index 473d6df8fa..0000000000 --- a/indra/newview/app_settings/shaders/class1/deferred/sunLightV.glsl +++ /dev/null @@ -1,41 +0,0 @@ -/** - * @file sunLightF.glsl - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2007, 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$ - */ - -uniform mat4 modelview_projection_matrix; - -ATTRIBUTE vec3 position; - -VARYING vec2 vary_fragcoord; - -uniform vec2 screen_res; - -void main() -{ - //transform vertex - vec4 pos = modelview_projection_matrix * vec4(position.xyz, 1.0); - gl_Position = pos; - - vary_fragcoord = (pos.xy * 0.5 + 0.5)*screen_res; -} diff --git a/indra/newview/app_settings/shaders/class1/deferred/terrainF.glsl b/indra/newview/app_settings/shaders/class1/deferred/terrainF.glsl index 3e4c5fc9c5..0474086bd1 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/terrainF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/terrainF.glsl @@ -39,16 +39,7 @@ VARYING vec3 vary_normal; VARYING vec4 vary_texcoord0; VARYING vec4 vary_texcoord1; -vec3 pack(vec3 norm) -{ -//#define PACK_NORMALS -#ifdef PACK_NORMALS - float p = sqrt(8.0*norm.z+8.0); - return vec3(norm.xy/p + 0.5, 0.0); -#else - return norm.xyz*0.5+0.5; -#endif -} +vec2 encode_normal(vec3 n); void main() { @@ -67,6 +58,6 @@ void main() frag_data[0] = vec4(outColor.rgb, 0.0); frag_data[1] = vec4(0,0,0,0); vec3 nvn = normalize(vary_normal); - frag_data[2] = vec4(pack(nvn),0.0); + frag_data[2] = vec4(encode_normal(nvn.xyz), 0.0, 0.0); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/treeF.glsl b/indra/newview/app_settings/shaders/class1/deferred/treeF.glsl index 6cd309fdb6..c5bb8ddc88 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/treeF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/treeF.glsl @@ -37,16 +37,7 @@ VARYING vec2 vary_texcoord0; uniform float minimum_alpha; -vec3 pack(vec3 norm) -{ -//#define PACK_NORMALS -#ifdef PACK_NORMALS - float p = sqrt(8.0*norm.z+8.0); - return vec3(norm.xy/p + 0.5, 0.0); -#else - return norm.xyz*0.5+0.5; -#endif -} +vec2 encode_normal(vec3 n); void main() { @@ -59,5 +50,5 @@ void main() frag_data[0] = vec4(vertex_color.rgb*col.rgb, 0.0); frag_data[1] = vec4(0,0,0,0); vec3 nvn = normalize(vary_normal); - frag_data[2] = vec4(pack(nvn),0.0); + frag_data[2] = vec4(encode_normal(nvn.xyz), 0.0, 0.0); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/underWaterF.glsl b/indra/newview/app_settings/shaders/class1/deferred/underWaterF.glsl new file mode 100644 index 0000000000..77126bd0d6 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/underWaterF.glsl @@ -0,0 +1,117 @@ +/** + * @file underWaterF.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2007, 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$ + */ + +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_data[3]; +#else +#define frag_data gl_FragData +#endif + +uniform sampler2D diffuseMap; +uniform sampler2D bumpMap; +uniform sampler2D screenTex; +uniform sampler2D refTex; +uniform sampler2D screenDepth; + +uniform vec4 fogCol; +uniform vec3 lightDir; +uniform vec3 specular; +uniform float lightExp; +uniform vec2 fbScale; +uniform float refScale; +uniform float znear; +uniform float zfar; +uniform float kd; +uniform vec4 waterPlane; +uniform vec3 eyeVec; +uniform vec4 waterFogColor; +uniform float waterFogDensity; +uniform float waterFogKS; +uniform vec2 screenRes; + +//bigWave is (refCoord.w, view.w); +VARYING vec4 refCoord; +VARYING vec4 littleWave; +VARYING vec4 view; + +vec2 encode_normal(vec3 n); +vec3 encode_diffuse(vec3 color); + +vec4 applyWaterFog(vec4 color, vec3 viewVec) +{ + //normalize view vector + vec3 view = normalize(viewVec); + float es = -view.z; + + //find intersection point with water plane and eye vector + + //get eye depth + float e0 = max(-waterPlane.w, 0.0); + + //get object depth + float depth = length(viewVec); + + //get "thickness" of water + float l = max(depth, 0.1); + + float kd = waterFogDensity; + float ks = waterFogKS; + vec4 kc = waterFogColor; + + float F = 0.98; + + float t1 = -kd * pow(F, ks * e0); + float t2 = kd + ks * es; + float t3 = pow(F, t2*l) - 1.0; + + float L = min(t1/t2*t3, 1.0); + + float D = pow(0.98, l*kd); + //return vec4(1.0, 0.0, 1.0, 1.0); + return color * D + kc * L; + //depth /= 10.0; + //return vec4(depth,depth,depth,0.0); +} + +void main() +{ + vec4 color; + + //get detail normals + vec3 wave1 = texture2D(bumpMap, vec2(refCoord.w, view.w)).xyz*2.0-1.0; + vec3 wave2 = texture2D(bumpMap, littleWave.xy).xyz*2.0-1.0; + vec3 wave3 = texture2D(bumpMap, littleWave.zw).xyz*2.0-1.0; + vec3 wavef = normalize(wave1+wave2+wave3); + + //figure out distortion vector (ripply) + vec2 distort = (refCoord.xy/refCoord.z) * 0.5 + 0.5; + distort = distort+wavef.xy*refScale; + + vec4 fb = texture2D(screenTex, distort); + + frag_data[0] = vec4(fb.rgb, 1.0); // diffuse + frag_data[1] = vec4(0.5,0.5,0.5, 0.95); // speccolor*spec, spec + frag_data[2] = vec4(encode_normal(wavef), 0.0, 0.0); // normalxyz, displace +} diff --git a/indra/newview/app_settings/shaders/class1/deferred/waterF.glsl b/indra/newview/app_settings/shaders/class1/deferred/waterF.glsl index b27822814d..6a24c1bd43 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/waterF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/waterF.glsl @@ -23,7 +23,7 @@ * $/LicenseInfo$ */ -#extension GL_ARB_texture_rectangle : enable + #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_data[3]; @@ -37,10 +37,6 @@ vec3 atmosTransport(vec3 inColor); uniform sampler2D bumpMap; uniform sampler2D screenTex; uniform sampler2D refTex; -uniform sampler2DRectShadow shadowMap0; -uniform sampler2DRectShadow shadowMap1; -uniform sampler2DRectShadow shadowMap2; -uniform sampler2DRectShadow shadowMap3; uniform sampler2D noiseMap; uniform mat4 shadow_matrix[6]; @@ -58,7 +54,6 @@ uniform vec3 normScale; uniform float fresnelScale; uniform float fresnelOffset; uniform float blurMultiplier; -uniform vec2 screen_res; uniform mat4 norm_mat; //region space to screen space //bigWave is (refCoord.w, view.w); @@ -67,16 +62,7 @@ VARYING vec4 littleWave; VARYING vec4 view; VARYING vec4 vary_position; -vec3 pack(vec3 norm) -{ -//#define PACK_NORMALS -#ifdef PACK_NORMALS - float p = sqrt(8.0*norm.z+8.0); - return vec3(norm.xy/p + 0.5, 0.0); -#else - return norm.xyz*0.5+0.5; -#endif -} +vec2 encode_normal(vec3 n); void main() { @@ -126,7 +112,7 @@ void main() refcol *= df1 * 0.333; vec3 wavef = (wave1 + wave2 * 0.4 + wave3 * 0.6) * 0.5; - //wavef.z *= max(-viewVec.z, 0.1); + wavef.z *= max(-viewVec.z, 0.1); wavef = normalize(wavef); float df2 = dot(viewVec, wavef) * fresnelScale+fresnelOffset; @@ -136,13 +122,14 @@ void main() vec2 refvec4 = distort+refdistort4/dmod; float dweight = min(dist2*blurMultiplier, 1.0); vec4 baseCol = texture2D(refTex, refvec4); + refcol = mix(baseCol*df2, refcol, dweight); //get specular component - //float spec = clamp(dot(lightDir, (reflect(viewVec,wavef))),0.0,1.0); + float spec = clamp(dot(lightDir, (reflect(viewVec,wavef))),0.0,1.0); //harden specular - //spec = pow(spec, 128.0); + spec = pow(spec, 128.0); //figure out distortion vector (ripply) vec2 distort2 = distort+wavef.xy*refScale/max(dmod*df1, 1.0); @@ -153,25 +140,17 @@ void main() // Note we actually want to use just df1, but multiplying by 0.999999 gets around an nvidia compiler bug color.rgb = mix(fb.rgb, refcol.rgb, df1 * 0.99999); - float shadow = 1.0; vec4 pos = vary_position; - //vec3 nz = texture2D(noiseMap, gl_FragCoord.xy/128.0).xyz; - vec4 spos = pos; - - //spec *= shadow; - //color.rgb += spec * specular; + color.rgb += spec * specular; color.rgb = atmosTransport(color.rgb); color.rgb = scaleSoftClip(color.rgb); + color.a = spec * sunAngle2; - //color.a = spec * sunAngle2; - - //wavef.z *= 0.1f; - //wavef = normalize(wavef); - vec3 screenspacewavef = (norm_mat*vec4(wavef, 1.0)).xyz; + vec3 screenspacewavef = normalize((norm_mat*vec4(wavef, 1.0)).xyz); - frag_data[0] = vec4(color.rgb, 0.5); // diffuse - frag_data[1] = vec4(0.5,0.5,0.5, 0.95); // speccolor*spec, spec - frag_data[2] = vec4(pack(screenspacewavef), 0.5); + frag_data[0] = vec4(color.rgb, color.a); // diffuse + frag_data[1] = vec4(0); // speccolor, spec + frag_data[2] = vec4(encode_normal(screenspacewavef.xyz), 0.05, 0);// normalxy, 0, 0 } diff --git a/indra/newview/app_settings/shaders/class1/deferred/waterV.glsl b/indra/newview/app_settings/shaders/class1/deferred/waterV.glsl index ece34dcc4e..9734acf005 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/waterV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/waterV.glsl @@ -85,7 +85,7 @@ void main() pos.w = 1.0; pos = modelview_matrix*pos; - calcAtmospherics(view.xyz); + calcAtmospherics(pos.xyz); //pass wave parameters to pixel shader vec2 bigWave = (v.xy) * vec2(0.04,0.04) + d1 * time * 0.055; diff --git a/indra/newview/app_settings/shaders/class1/effects/MotionBlurF.glsl b/indra/newview/app_settings/shaders/class1/effects/MotionBlurF.glsl index efa1265a19..6e523a8d5e 100644 --- a/indra/newview/app_settings/shaders/class1/effects/MotionBlurF.glsl +++ b/indra/newview/app_settings/shaders/class1/effects/MotionBlurF.glsl @@ -5,7 +5,7 @@ * $License$ */ -#extension GL_ARB_texture_rectangle : enable + #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_color; @@ -13,11 +13,10 @@ out vec4 frag_color; #define frag_color gl_FragColor #endif -uniform sampler2DRect tex0; -uniform sampler2DRect tex1; +uniform sampler2D tex0; +uniform sampler2D tex1; uniform mat4 inv_proj; uniform mat4 prev_proj; -uniform vec2 screen_res; uniform int blur_strength; VARYING vec2 vary_texcoord0; @@ -26,9 +25,8 @@ VARYING vec2 vary_texcoord0; vec4 getPosition(vec2 pos_screen, out vec4 ndc) { - float depth = texture2DRect(tex1, pos_screen.xy).r; + float depth = texture2D(tex1, pos_screen.xy).r; vec2 sc = pos_screen.xy*2.0; - sc /= screen_res; sc -= vec2(1.0,1.0); ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0); vec4 pos = inv_proj * ndc; @@ -44,14 +42,14 @@ void main(void) vec4 prev_pos = prev_proj * pos; prev_pos/=prev_pos.w; prev_pos.w = 1.0; - vec2 vel = ((ndc.xy-prev_pos.xy) * .5) * screen_res * .01 * blur_strength * 1.0/SAMPLE_COUNT; + vec2 vel = ((ndc.xy-prev_pos.xy) * .5) * .01 * blur_strength * 1.0/SAMPLE_COUNT; float len = length(vel); vel = normalize(vel) * min(len, 50); - vec3 color = texture2DRect(tex0, vary_texcoord0.st).rgb; + vec3 color = texture2D(tex0, vary_texcoord0.st).rgb; vec2 texcoord = vary_texcoord0 + vel; for(int i = 1; i < SAMPLE_COUNT; ++i, texcoord += vel) { - color += texture2DRect(tex0, texcoord.st).rgb; + color += texture2D(tex0, texcoord.st).rgb; } frag_color = vec4(color / SAMPLE_COUNT, 1.0); } diff --git a/indra/newview/app_settings/shaders/class1/effects/PosterizeF.glsl b/indra/newview/app_settings/shaders/class1/effects/PosterizeF.glsl index 0f8b2f8f2c..3da995dc0e 100644 --- a/indra/newview/app_settings/shaders/class1/effects/PosterizeF.glsl +++ b/indra/newview/app_settings/shaders/class1/effects/PosterizeF.glsl @@ -5,7 +5,7 @@ * $License$ */ -#extension GL_ARB_texture_rectangle : enable + #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_color; @@ -13,13 +13,13 @@ out vec4 frag_color; #define frag_color gl_FragColor #endif -uniform sampler2DRect tex0; +uniform sampler2D tex0; uniform int layerCount; VARYING vec2 vary_texcoord0; void main(void) { - vec3 color = pow(floor(pow(vec3(texture2DRect(tex0, vary_texcoord0.st)),vec3(.6)) * layerCount)/layerCount,vec3(1.66666)); + vec3 color = pow(floor(pow(vec3(texture2D(tex0, vary_texcoord0.st)),vec3(.6)) * layerCount)/layerCount,vec3(1.66666)); frag_color = vec4(color, 1.0); } diff --git a/indra/newview/app_settings/shaders/class1/effects/VignetteF.glsl b/indra/newview/app_settings/shaders/class1/effects/VignetteF.glsl index ad989e1a0f..8a1e58a1cc 100644 --- a/indra/newview/app_settings/shaders/class1/effects/VignetteF.glsl +++ b/indra/newview/app_settings/shaders/class1/effects/VignetteF.glsl @@ -5,7 +5,7 @@ * $License$ */ -#extension GL_ARB_texture_rectangle : enable + #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_color; @@ -13,13 +13,12 @@ out vec4 frag_color; #define frag_color gl_FragColor #endif -uniform sampler2DRect tex0; +uniform sampler2D tex0; uniform float vignette_strength; //0 - 1 uniform float vignette_radius; //0 - 8 uniform float vignette_darkness; //0 - 1 uniform float vignette_desaturation; //0 - 10 uniform float vignette_chromatic_aberration; //0 - .1 -uniform vec2 screen_res; VARYING vec2 vary_texcoord0; @@ -32,16 +31,15 @@ float luminance(vec3 color) void main(void) { - vec3 color = texture2DRect(tex0, vary_texcoord0).rgb; - vec2 norm_texcood = (vary_texcoord0/screen_res); - vec2 offset = norm_texcood-vec2(.5); + vec3 color = texture2D(tex0, vary_texcoord0).rgb; + vec2 offset = vary_texcoord0-vec2(.5); float vignette = clamp(pow(1 - dot(offset,offset),vignette_radius) + 1-vignette_strength, 0.0, 1.0); float inv_vignette = 1-vignette; //vignette chromatic aberration (g - vec2 shift = screen_res * offset * vignette_chromatic_aberration * inv_vignette; - float g = texture2DRect(tex0,vary_texcoord0-shift).g; - float b = texture2DRect(tex0,vary_texcoord0-2*shift).b; + vec2 shift = offset * vignette_chromatic_aberration * inv_vignette; + float g = texture2D(tex0,vary_texcoord0-shift).g; + float b = texture2D(tex0,vary_texcoord0-2*shift).b; color.gb = vec2(g,b); //vignette 'black' overlay. diff --git a/indra/newview/app_settings/shaders/class1/effects/colorFilterF.glsl b/indra/newview/app_settings/shaders/class1/effects/colorFilterF.glsl index 6acd277bbc..29485bf98f 100644 --- a/indra/newview/app_settings/shaders/class1/effects/colorFilterF.glsl +++ b/indra/newview/app_settings/shaders/class1/effects/colorFilterF.glsl @@ -5,7 +5,7 @@ * $License$ */ -#extension GL_ARB_texture_rectangle : enable + #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_color; @@ -14,7 +14,7 @@ out vec4 frag_color; #endif -uniform sampler2DRect tex0; +uniform sampler2D tex0; uniform float brightness; uniform float contrast; uniform vec3 contrastBase; @@ -34,7 +34,7 @@ float luminance(vec3 color) void main(void) { - vec3 color = vec3(texture2DRect(tex0, vary_texcoord0.st)); + vec3 color = vec3(texture2D(tex0, vary_texcoord0.st)); /// Apply gamma color = pow(color, vec3(1.0/gamma)); diff --git a/indra/newview/app_settings/shaders/class1/effects/gaussBlurF.glsl b/indra/newview/app_settings/shaders/class1/effects/gaussBlurF.glsl index 6c56e21084..012b5c83c0 100644 --- a/indra/newview/app_settings/shaders/class1/effects/gaussBlurF.glsl +++ b/indra/newview/app_settings/shaders/class1/effects/gaussBlurF.glsl @@ -1,4 +1,4 @@ -#extension GL_ARB_texture_rectangle : enable + #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_color; @@ -6,32 +6,22 @@ out vec4 frag_color; #define frag_color gl_FragColor #endif -uniform sampler2DRect tex0; +uniform sampler2D tex0; uniform int horizontalPass; VARYING vec2 vary_texcoord0; -vec2 offset = vec2( 1.3846153846, 3.2307692308 ); +uniform vec4 kern[2]; vec3 weight = vec3( 0.2270270270, 0.3162162162, 0.0702702703 ); - + void main(void) { - vec3 color = vec3(texture2DRect(tex0, vary_texcoord0))*weight.x; + vec3 color = vec3(texture2D(tex0, vary_texcoord0))*weight.x; - if(horizontalPass == 1) - { - color += weight.y * vec3(texture2DRect(tex0, vec2(vary_texcoord0.s+offset.s,vary_texcoord0.t))); - color += weight.y * vec3(texture2DRect(tex0, vec2(vary_texcoord0.s-offset.s,vary_texcoord0.t))); - color += weight.z * vec3(texture2DRect(tex0, vec2(vary_texcoord0.s+offset.t,vary_texcoord0.t))); - color += weight.z * vec3(texture2DRect(tex0, vec2(vary_texcoord0.s-offset.t,vary_texcoord0.t))); - - } - else - { - color += weight.y * vec3(texture2DRect(tex0, vec2(vary_texcoord0.s,vary_texcoord0.t+offset.s))); - color += weight.y * vec3(texture2DRect(tex0, vec2(vary_texcoord0.s,vary_texcoord0.t-offset.s))); - color += weight.z * vec3(texture2DRect(tex0, vec2(vary_texcoord0.s,vary_texcoord0.t+offset.t))); - color += weight.z * vec3(texture2DRect(tex0, vec2(vary_texcoord0.s,vary_texcoord0.t-offset.t))); - } + color += weight.y * vec3(texture2D(tex0, vec2(vary_texcoord0.s+kern[horizontalPass].s,vary_texcoord0.t+kern[horizontalPass].s))); + color += weight.y * vec3(texture2D(tex0, vec2(vary_texcoord0.s-kern[horizontalPass].s,vary_texcoord0.t-kern[horizontalPass].s))); + color += weight.z * vec3(texture2D(tex0, vec2(vary_texcoord0.s+kern[horizontalPass].t,vary_texcoord0.t+kern[horizontalPass].t))); + color += weight.z * vec3(texture2D(tex0, vec2(vary_texcoord0.s-kern[horizontalPass].t,vary_texcoord0.t-kern[horizontalPass].t))); + frag_color = vec4(color.xyz,1.0); } diff --git a/indra/newview/app_settings/shaders/class1/effects/glowExtractF.glsl b/indra/newview/app_settings/shaders/class1/effects/glowExtractF.glsl index 0f5eb288fd..48886d40da 100644 --- a/indra/newview/app_settings/shaders/class1/effects/glowExtractF.glsl +++ b/indra/newview/app_settings/shaders/class1/effects/glowExtractF.glsl @@ -23,7 +23,7 @@ * $/LicenseInfo$ */ -#extension GL_ARB_texture_rectangle : enable + #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_color; @@ -31,7 +31,7 @@ out vec4 frag_color; #define frag_color gl_FragColor #endif -uniform sampler2DRect diffuseMap; +uniform sampler2D diffuseMap; uniform float minLuminance; uniform float maxExtractAlpha; uniform vec3 lumWeights; @@ -42,7 +42,7 @@ VARYING vec2 vary_texcoord0; void main() { - vec4 col = texture2DRect(diffuseMap, vary_texcoord0.xy); + vec4 col = texture2D(diffuseMap, vary_texcoord0.xy); /// CALCULATING LUMINANCE (Using NTSC lum weights) /// http://en.wikipedia.org/wiki/Luma_%28video%29 float lum = smoothstep(minLuminance, minLuminance+1.0, dot(col.rgb, lumWeights ) ); diff --git a/indra/newview/app_settings/shaders/class1/effects/glowExtractV.glsl b/indra/newview/app_settings/shaders/class1/effects/glowExtractV.glsl index 1396dc6973..3e6a469226 100644 --- a/indra/newview/app_settings/shaders/class1/effects/glowExtractV.glsl +++ b/indra/newview/app_settings/shaders/class1/effects/glowExtractV.glsl @@ -26,13 +26,12 @@ uniform mat4 modelview_projection_matrix; ATTRIBUTE vec3 position; -ATTRIBUTE vec2 texcoord0; VARYING vec2 vary_texcoord0; void main() { - gl_Position = modelview_projection_matrix * vec4(position, 1.0); - - vary_texcoord0.xy = texcoord0; + vec4 pos = modelview_projection_matrix * vec4(position.xyz, 1.0); + gl_Position = pos; + vary_texcoord0 = (pos.xy*0.5+0.5); } diff --git a/indra/newview/app_settings/shaders/class1/effects/glowV.glsl b/indra/newview/app_settings/shaders/class1/effects/glowV.glsl index cdb2281578..b83c1c0074 100644 --- a/indra/newview/app_settings/shaders/class1/effects/glowV.glsl +++ b/indra/newview/app_settings/shaders/class1/effects/glowV.glsl @@ -26,7 +26,6 @@ uniform mat4 modelview_projection_matrix; ATTRIBUTE vec3 position; -ATTRIBUTE vec2 texcoord0; uniform vec2 glowDelta; @@ -37,14 +36,16 @@ VARYING vec4 vary_texcoord3; void main() { - gl_Position = modelview_projection_matrix * vec4(position, 1.0); + vec4 pos = modelview_projection_matrix * vec4(position.xyz, 1.0); + gl_Position = pos; + vec2 texcoord = (pos.xy*0.5+0.5); - vary_texcoord0.xy = texcoord0 + glowDelta*(-3.5); - vary_texcoord1.xy = texcoord0 + glowDelta*(-2.5); - vary_texcoord2.xy = texcoord0 + glowDelta*(-1.5); - vary_texcoord3.xy = texcoord0 + glowDelta*(-0.5); - vary_texcoord0.zw = texcoord0 + glowDelta*(0.5); - vary_texcoord1.zw = texcoord0 + glowDelta*(1.5); - vary_texcoord2.zw = texcoord0 + glowDelta*(2.5); - vary_texcoord3.zw = texcoord0 + glowDelta*(3.5); + vary_texcoord0.xy = texcoord + glowDelta*(-3.5); + vary_texcoord1.xy = texcoord + glowDelta*(-2.5); + vary_texcoord2.xy = texcoord + glowDelta*(-1.5); + vary_texcoord3.xy = texcoord + glowDelta*(-0.5); + vary_texcoord0.zw = texcoord + glowDelta*(0.5); + vary_texcoord1.zw = texcoord + glowDelta*(1.5); + vary_texcoord2.zw = texcoord + glowDelta*(2.5); + vary_texcoord3.zw = texcoord + glowDelta*(3.5); } diff --git a/indra/newview/app_settings/shaders/class1/effects/nightVisionF.glsl b/indra/newview/app_settings/shaders/class1/effects/nightVisionF.glsl index 6257c4e9b4..8987e8e7cd 100644 --- a/indra/newview/app_settings/shaders/class1/effects/nightVisionF.glsl +++ b/indra/newview/app_settings/shaders/class1/effects/nightVisionF.glsl @@ -5,7 +5,7 @@ * $License$ */ -#extension GL_ARB_texture_rectangle : enable + #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_color; @@ -13,7 +13,7 @@ out vec4 frag_color; #define frag_color gl_FragColor #endif -uniform sampler2DRect tex0; +uniform sampler2D tex0; uniform sampler2D tex1; uniform float brightMult; uniform float noiseStrength; @@ -32,7 +32,7 @@ float luminance(vec3 color) void main(void) { /// Get scene color - vec3 color = vec3(texture2DRect(tex0, vary_texcoord0)); + vec3 color = vec3(texture2D(tex0, vary_texcoord0)); /// Extract luminance and scale up by night vision brightness float lum = luminance(color) * brightMult; diff --git a/indra/newview/app_settings/shaders/class1/environment/waterV.glsl b/indra/newview/app_settings/shaders/class1/environment/waterV.glsl index f77edde70f..df65cb9536 100644 --- a/indra/newview/app_settings/shaders/class1/environment/waterV.glsl +++ b/indra/newview/app_settings/shaders/class1/environment/waterV.glsl @@ -48,40 +48,40 @@ float wave(vec2 v, float t, float f, vec2 d, float s) void main() { //transform vertex + vec4 pos = vec4(position.xyz, 1.0); mat4 modelViewProj = modelview_projection_matrix; vec4 oPosition; //get view vector vec3 oEyeVec; - oEyeVec.xyz = position.xyz-eyeVec; + oEyeVec.xyz = pos.xyz-eyeVec; float d = length(oEyeVec.xy); float ld = min(d, 2560.0); - vec3 lpos = position; - lpos.xy = eyeVec.xy + oEyeVec.xy/d*ld; + pos.xy = eyeVec.xy + oEyeVec.xy/d*ld; view.xyz = oEyeVec; d = clamp(ld/1536.0-0.5, 0.0, 1.0); d *= d; - oPosition = vec4(lpos, 1.0); + oPosition = vec4(position, 1.0); oPosition.z = mix(oPosition.z, max(eyeVec.z*0.75, 0.0), d); oPosition = modelViewProj * oPosition; + refCoord.xyz = oPosition.xyz + vec3(0,0,0.2); //get wave position parameter (create sweeping horizontal waves) - vec3 v = lpos; + vec3 v = pos.xyz; v.x += (cos(v.x*0.08/*+time*0.01*/)+sin(v.y*0.02))*6.0; //push position for further horizon effect. - vec4 pos; pos.xyz = oEyeVec.xyz*(waterHeight/oEyeVec.z); pos.w = 1.0; pos = modelview_matrix*pos; - calcAtmospherics(view.xyz); + calcAtmospherics(pos.xyz); //pass wave parameters to pixel shader diff --git a/indra/newview/app_settings/shaders/class1/interface/downsampleDepthF.glsl b/indra/newview/app_settings/shaders/class1/interface/downsampleDepthF.glsl new file mode 100644 index 0000000000..f8efd7cb4a --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/interface/downsampleDepthF.glsl @@ -0,0 +1,65 @@ +/** + * @file debugF.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2011, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_color; +#else +#define frag_color gl_FragColor +#endif + +uniform sampler2D depthMap; + +VARYING vec2 tc0; +VARYING vec2 tc1; +VARYING vec2 tc2; +VARYING vec2 tc3; +VARYING vec2 tc4; +VARYING vec2 tc5; +VARYING vec2 tc6; +VARYING vec2 tc7; +VARYING vec2 tc8; + +void main() +{ + vec4 depth1 = + vec4(texture2D(depthMap, tc0).r, + texture2D(depthMap, tc1).r, + texture2D(depthMap, tc2).r, + texture2D(depthMap, tc3).r); + + vec4 depth2 = + vec4(texture2D(depthMap, tc4).r, + texture2D(depthMap, tc5).r, + texture2D(depthMap, tc6).r, + texture2D(depthMap, tc7).r); + + depth1 = min(depth1, depth2); + float depth = min(depth1.x, depth1.y); + depth = min(depth, depth1.z); + depth = min(depth, depth1.w); + depth = min(depth, texture2D(depthMap, tc8).r); + + gl_FragDepth = depth; +} diff --git a/indra/newview/app_settings/shaders/class1/interface/downsampleDepthV.glsl b/indra/newview/app_settings/shaders/class1/interface/downsampleDepthV.glsl new file mode 100644 index 0000000000..44b6c3c855 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/interface/downsampleDepthV.glsl @@ -0,0 +1,57 @@ +/** + * @file debugV.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2011, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +uniform mat4 modelview_projection_matrix; + +ATTRIBUTE vec3 position; + +uniform vec2 delta; + +VARYING vec2 tc0; +VARYING vec2 tc1; +VARYING vec2 tc2; +VARYING vec2 tc3; +VARYING vec2 tc4; +VARYING vec2 tc5; +VARYING vec2 tc6; +VARYING vec2 tc7; +VARYING vec2 tc8; + +void main() +{ + gl_Position = vec4(position, 1.0); + + vec2 tc = (position.xy*0.5+0.5); + tc0 = tc+vec2(-delta.x,-delta.y); + tc1 = tc+vec2(0,-delta.y); + tc2 = tc+vec2(delta.x,-delta.y); + tc3 = tc+vec2(-delta.x,0); + tc4 = tc+vec2(0,0); + tc5 = tc+vec2(delta.x,0); + tc6 = tc+vec2(-delta.x,delta.y); + tc7 = tc+vec2(0,delta.y); + tc8 = tc+vec2(delta.x,delta.y); +} + diff --git a/indra/newview/app_settings/shaders/class1/interface/glowcombineF.glsl b/indra/newview/app_settings/shaders/class1/interface/glowcombineF.glsl index ed803de277..7765b30ca7 100644 --- a/indra/newview/app_settings/shaders/class1/interface/glowcombineF.glsl +++ b/indra/newview/app_settings/shaders/class1/interface/glowcombineF.glsl @@ -29,16 +29,15 @@ out vec4 frag_color; #define frag_color gl_FragColor #endif -#extension GL_ARB_texture_rectangle : enable + uniform sampler2D glowMap; -uniform sampler2DRect screenMap; +uniform sampler2D screenMap; VARYING vec2 vary_texcoord0; -VARYING vec2 vary_texcoord1; void main() { frag_color = texture2D(glowMap, vary_texcoord0.xy) + - texture2DRect(screenMap, vary_texcoord1.xy); + texture2D(screenMap, vary_texcoord0.xy); } diff --git a/indra/newview/app_settings/shaders/class1/interface/glowcombineFXAAF.glsl b/indra/newview/app_settings/shaders/class1/interface/glowcombineFXAAF.glsl index 59520bb99f..98b2a3bf0f 100644 --- a/indra/newview/app_settings/shaders/class1/interface/glowcombineFXAAF.glsl +++ b/indra/newview/app_settings/shaders/class1/interface/glowcombineFXAAF.glsl @@ -23,7 +23,7 @@ * $/LicenseInfo$ */ -#extension GL_ARB_texture_rectangle : enable + #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_color; @@ -31,14 +31,13 @@ out vec4 frag_color; #define frag_color gl_FragColor #endif -uniform sampler2DRect diffuseRect; +uniform sampler2D diffuseRect; -uniform vec2 screen_res; -VARYING vec2 vary_tc; +VARYING vec2 vary_texcoord0; void main() { - vec3 col = texture2DRect(diffuseRect, vary_tc*screen_res).rgb; + vec3 col = texture2D(diffuseRect, vary_texcoord0).rgb; frag_color = vec4(col.rgb, dot(col.rgb, vec3(0.299, 0.587, 0.144))); } diff --git a/indra/newview/app_settings/shaders/class1/interface/glowcombineFXAAV.glsl b/indra/newview/app_settings/shaders/class1/interface/glowcombineFXAAV.glsl index 058f3b1b82..867a2d4407 100644 --- a/indra/newview/app_settings/shaders/class1/interface/glowcombineFXAAV.glsl +++ b/indra/newview/app_settings/shaders/class1/interface/glowcombineFXAAV.glsl @@ -27,13 +27,13 @@ uniform mat4 modelview_projection_matrix; ATTRIBUTE vec3 position; -VARYING vec2 vary_tc; +VARYING vec2 vary_texcoord0; void main() { vec4 pos = modelview_projection_matrix*vec4(position.xyz, 1.0); gl_Position = pos; - vary_tc = pos.xy*0.5+0.5; + vary_texcoord0 = pos.xy*0.5+0.5; } diff --git a/indra/newview/app_settings/shaders/class1/interface/glowcombineV.glsl b/indra/newview/app_settings/shaders/class1/interface/glowcombineV.glsl index f7970b7f78..83e728ce3b 100644 --- a/indra/newview/app_settings/shaders/class1/interface/glowcombineV.glsl +++ b/indra/newview/app_settings/shaders/class1/interface/glowcombineV.glsl @@ -26,16 +26,13 @@ uniform mat4 modelview_projection_matrix; ATTRIBUTE vec3 position; -ATTRIBUTE vec2 texcoord0; -ATTRIBUTE vec2 texcoord1; VARYING vec2 vary_texcoord0; -VARYING vec2 vary_texcoord1; void main() { - gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0); - vary_texcoord0 = texcoord0; - vary_texcoord1 = texcoord1; + vec4 pos = modelview_projection_matrix * vec4(position.xyz, 1.0); + gl_Position = pos; + vary_texcoord0 = (pos.xy*0.5+0.5); } diff --git a/indra/newview/app_settings/shaders/class1/interface/highlightNormV.glsl b/indra/newview/app_settings/shaders/class1/interface/highlightNormV.glsl new file mode 100644 index 0000000000..947c2b0065 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/interface/highlightNormV.glsl @@ -0,0 +1,42 @@ +/** + * @file highlightV.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2007, 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$ + */ + +uniform mat4 texture_matrix0; +uniform mat4 modelview_projection_matrix; + +ATTRIBUTE vec3 position; +ATTRIBUTE vec2 texcoord0; +ATTRIBUTE vec2 texcoord1; +ATTRIBUTE vec2 texcoord2; + +VARYING vec2 vary_texcoord0; + +void main() +{ + //transform vertex + gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0); + vary_texcoord0 = (texture_matrix0 * vec4(texcoord1,0,1)).xy; +} + diff --git a/indra/newview/app_settings/shaders/class1/interface/highlightSpecV.glsl b/indra/newview/app_settings/shaders/class1/interface/highlightSpecV.glsl new file mode 100644 index 0000000000..c5d102b739 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/interface/highlightSpecV.glsl @@ -0,0 +1,42 @@ +/** + * @file highlightV.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2007, 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$ + */ + +uniform mat4 texture_matrix0; +uniform mat4 modelview_projection_matrix; + +ATTRIBUTE vec3 position; +ATTRIBUTE vec2 texcoord0; +ATTRIBUTE vec2 texcoord1; +ATTRIBUTE vec2 texcoord2; + +VARYING vec2 vary_texcoord0; + +void main() +{ + //transform vertex + gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0); + vary_texcoord0 = (texture_matrix0 * vec4(texcoord2,0,1)).xy; +} + diff --git a/indra/newview/app_settings/shaders/class1/interface/splattexturerectF.glsl b/indra/newview/app_settings/shaders/class1/interface/splattexturerectF.glsl index 772bb374e8..468cf480dd 100644 --- a/indra/newview/app_settings/shaders/class1/interface/splattexturerectF.glsl +++ b/indra/newview/app_settings/shaders/class1/interface/splattexturerectF.glsl @@ -23,7 +23,7 @@ * $/LicenseInfo$ */ -#extension GL_ARB_texture_rectangle : enable + #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_color; @@ -31,12 +31,12 @@ out vec4 frag_color; #define frag_color gl_FragColor #endif -uniform sampler2DRect screenMap; +uniform sampler2D screenMap; VARYING vec4 vertex_color; VARYING vec2 vary_texcoord0; void main() { - frag_color = texture2DRect(screenMap, vary_texcoord0.xy) * vertex_color; + frag_color = texture2D(screenMap, vary_texcoord0.xy) * vertex_color; } diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightAlphaMaskF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightAlphaMaskF.glsl index cf29939cb2..0eb11afe8a 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightAlphaMaskF.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightAlphaMaskF.glsl @@ -39,7 +39,7 @@ VARYING vec2 vary_texcoord0; void default_lighting() { - vec4 color = diffuseLookup(vary_texcoord0.xy) * vertex_color; + vec4 color = diffuseLookup(vary_texcoord0.xy) * vertex_color; //Shader is used on alpha faces too. Need alpha component. if (color.a < minimum_alpha) { diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightAlphaMaskF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightAlphaMaskF.glsl index 6c34643aab..49fccda5b2 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightAlphaMaskF.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightAlphaMaskF.glsl @@ -30,6 +30,7 @@ out vec4 frag_color; #endif uniform float minimum_alpha; +uniform float texture_gamma; vec3 fullbrightAtmosTransport(vec3 light); vec3 fullbrightScaleSoftClip(vec3 light); @@ -39,13 +40,14 @@ VARYING vec2 vary_texcoord0; void fullbright_lighting() { - vec4 color = diffuseLookup(vary_texcoord0.xy) * vertex_color; + vec4 color = diffuseLookup(vary_texcoord0.xy) * vertex_color; //Shader is used on alpha faces too. Need alpha component. if (color.a < minimum_alpha) { discard; } + color.rgb = pow(color.rgb, vec3(texture_gamma)); color.rgb = fullbrightAtmosTransport(color.rgb); color.rgb = fullbrightScaleSoftClip(color.rgb); diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightF.glsl index 2ff7f795b0..c8771a3f1e 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightF.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightF.glsl @@ -32,6 +32,8 @@ out vec4 frag_color; VARYING vec4 vertex_color; VARYING vec2 vary_texcoord0; +uniform float texture_gamma; + vec3 fullbrightAtmosTransport(vec3 light); vec3 fullbrightScaleSoftClip(vec3 light); @@ -39,10 +41,14 @@ void fullbright_lighting() { vec4 color = diffuseLookup(vary_texcoord0.xy) * vertex_color; + color.rgb = pow(color.rgb, vec3(texture_gamma)); + color.rgb = fullbrightAtmosTransport(color.rgb); color.rgb = fullbrightScaleSoftClip(color.rgb); + color.rgb = pow(color.rgb, vec3(1.0/texture_gamma)); + frag_color = color; } diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightNonIndexedAlphaMaskF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightNonIndexedAlphaMaskF.glsl index f4477bd29a..c6850467e1 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightNonIndexedAlphaMaskF.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightNonIndexedAlphaMaskF.glsl @@ -30,6 +30,7 @@ out vec4 frag_color; #endif uniform float minimum_alpha; +uniform float texture_gamma; vec3 fullbrightAtmosTransport(vec3 light); vec3 fullbrightScaleSoftClip(vec3 light); @@ -47,11 +48,14 @@ void fullbright_lighting() { discard; } - + + color.rgb = pow(color.rgb, vec3(texture_gamma)); color.rgb = fullbrightAtmosTransport(color.rgb); color.rgb = fullbrightScaleSoftClip(color.rgb); + color.rgb = pow(color.rgb, vec3(1.0/texture_gamma)); + frag_color = color; } diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyF.glsl index 777c8b45bb..ff96409e80 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyF.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyF.glsl @@ -50,7 +50,7 @@ void fullbright_shiny_lighting() color.rgb = fullbrightScaleSoftClip(color.rgb); - color.a = max(color.a, vertex_color.a); + color.a = 0.0; frag_color = color; } diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyNonIndexedF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyNonIndexedF.glsl index 4fa3b1d939..9311b786aa 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyNonIndexedF.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyNonIndexedF.glsl @@ -51,7 +51,7 @@ void fullbright_shiny_lighting() color.rgb = fullbrightScaleSoftClip(color.rgb); - color.a = max(color.a, vertex_color.a); + color.a = 0.0; frag_color = color; } diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyWaterF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyWaterF.glsl index 58984a4263..5886fc65be 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyWaterF.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyWaterF.glsl @@ -48,7 +48,7 @@ void fullbright_shiny_lighting_water() color.rgb = fullbrightShinyAtmosTransport(color.rgb); color.rgb = fullbrightScaleSoftClip(color.rgb); - color.a = max(color.a, vertex_color.a); + color.a = 1.0; frag_color = applyWaterFog(color); } diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyWaterNonIndexedF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyWaterNonIndexedF.glsl index a39b7205d7..e44865d4ef 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyWaterNonIndexedF.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyWaterNonIndexedF.glsl @@ -49,7 +49,7 @@ void fullbright_shiny_lighting_water() color.rgb = fullbrightShinyAtmosTransport(color.rgb); color.rgb = fullbrightScaleSoftClip(color.rgb); - color.a = max(color.a, vertex_color.a); + color.a = 0.0; frag_color = applyWaterFog(color); } diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterAlphaMaskF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterAlphaMaskF.glsl index 99a6fe85fe..ab2d05a3ca 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterAlphaMaskF.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterAlphaMaskF.glsl @@ -31,7 +31,7 @@ out vec4 frag_color; uniform float minimum_alpha; -vec4 diffuseLookup(vec2 texcoord); +/* vec4 diffuseLookup(vec2 texcoord); */ vec3 fullbrightAtmosTransport(vec3 light); vec4 applyWaterFog(vec4 color); @@ -41,7 +41,7 @@ VARYING vec2 vary_texcoord0; void fullbright_lighting_water() { - vec4 color = diffuseLookup(vary_texcoord0.xy) * vertex_color; + vec4 color = diffuseLookup(vary_texcoord0.xy) * vertex_color; //Shader is used on alpha faces too. Need alpha component. if (color.a < minimum_alpha) { diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterF.glsl index df182168f3..d3dacf9bc4 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterF.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterF.glsl @@ -32,7 +32,7 @@ out vec4 frag_color; VARYING vec4 vertex_color; VARYING vec2 vary_texcoord0; -vec4 diffuseLookup(vec2 texcoord); +/* vec4 diffuseLookup(vec2 texcoord); */ vec3 fullbrightAtmosTransport(vec3 light); vec4 applyWaterFog(vec4 color); diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightFuncV.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightFuncV.glsl index a9288b3df6..7d493d74cc 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightFuncV.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightFuncV.glsl @@ -43,16 +43,17 @@ float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, floa //normalize light vector lv *= 1.0/d; + //lv = normalize(lv); //distance attenuation float da = clamp(1.0/(la * d), 0.0, 1.0); // spotlight coefficient. - float spot = max(dot(-ln, lv), is_pointlight); + float spot = max(dot(normalize(-ln), lv), is_pointlight); da *= spot*spot; // GL_SPOT_EXPONENT=2 //angular attenuation - da *= calcDirectionalLight(n, lv); + da = max(lp.w * da * calcDirectionalLight(n, lv), (1.0 - lp.w) * calcDirectionalLight(n, lp.xyz)); return da; } diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightNonIndexedF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightNonIndexedF.glsl index 0aca768021..b045a55cf5 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightNonIndexedF.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightNonIndexedF.glsl @@ -41,6 +41,11 @@ void default_lighting() { vec4 color = texture2D(diffuseMap,vary_texcoord0.xy) * vertex_color; + if(color.a < .004) + { + discard; + } + color.rgb = atmosLighting(color.rgb); color.rgb = scaleSoftClip(color.rgb); diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightShinyF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightShinyF.glsl index 52e3b2ad02..9208c148ef 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightShinyF.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightShinyF.glsl @@ -50,7 +50,7 @@ void shiny_lighting() color.rgb = atmosLighting(color.rgb); color.rgb = scaleSoftClip(color.rgb); - color.a = max(color.a, vertex_color.a); + color.a = 1.0; frag_color = color; } diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightShinyNonIndexedF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightShinyNonIndexedF.glsl index 474d5ea496..92628faa68 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightShinyNonIndexedF.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightShinyNonIndexedF.glsl @@ -51,7 +51,7 @@ void shiny_lighting() color.rgb = atmosLighting(color.rgb); color.rgb = scaleSoftClip(color.rgb); - color.a = max(color.a, vertex_color.a); + color.a = 1.0; frag_color = color; } diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightShinyWaterF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightShinyWaterF.glsl index d2a4c47aac..61841674e2 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightShinyWaterF.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightShinyWaterF.glsl @@ -47,7 +47,7 @@ void shiny_lighting_water() color.rgb = mix(color.rgb, envColor.rgb, vertex_color.a); color.rgb = atmosLighting(color.rgb); - color.a = max(color.a, vertex_color.a); + color.a = 1.0; frag_color = applyWaterFog(color); } diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightShinyWaterNonIndexedF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightShinyWaterNonIndexedF.glsl index f3bd662364..0b6e835fd0 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightShinyWaterNonIndexedF.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightShinyWaterNonIndexedF.glsl @@ -48,7 +48,7 @@ void shiny_lighting_water() color.rgb = mix(color.rgb, envColor.rgb, vertex_color.a); color.rgb = atmosLighting(color.rgb); - color.a = max(color.a, vertex_color.a); + color.a = 1.0; frag_color = applyWaterFog(color); } diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightWaterAlphaMaskF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightWaterAlphaMaskF.glsl index b68240ba0d..d449a1b324 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightWaterAlphaMaskF.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightWaterAlphaMaskF.glsl @@ -39,7 +39,7 @@ VARYING vec2 vary_texcoord0; void default_lighting_water() { - vec4 color = diffuseLookup(vary_texcoord0.xy) * vertex_color; + vec4 color = diffuseLookup(vary_texcoord0.xy) * vertex_color; //Shader is used on alpha faces too. Need alpha component. if (color.a < minimum_alpha) { diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightWaterF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightWaterF.glsl index 00609e93cd..248bff55f4 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightWaterF.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightWaterF.glsl @@ -39,6 +39,11 @@ void default_lighting_water() { vec4 color = diffuseLookup(vary_texcoord0.xy) * vertex_color; + /*if(color.a < .004) + { + discard; + }*/ + color.rgb = atmosLighting(color.rgb); frag_color = applyWaterFog(color); diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightWaterNonIndexedF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightWaterNonIndexedF.glsl index 13ecb7a636..32494b81fe 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightWaterNonIndexedF.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightWaterNonIndexedF.glsl @@ -41,6 +41,11 @@ void default_lighting_water() { vec4 color = texture2D(diffuseMap,vary_texcoord0.xy) * vertex_color; + if(color.a < .004) + { + discard; + } + color.rgb = atmosLighting(color.rgb); frag_color = applyWaterFog(color); diff --git a/indra/newview/app_settings/shaders/class1/lighting/sumLightsSpecularV.glsl b/indra/newview/app_settings/shaders/class1/lighting/sumLightsSpecularV.glsl index 7059ff31ae..4e86aa1799 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/sumLightsSpecularV.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/sumLightsSpecularV.glsl @@ -22,35 +22,40 @@ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ - - + float calcDirectionalLightSpecular(inout vec4 specular, vec3 view, vec3 n, vec3 l, vec3 lightCol, float da); +vec3 calcPointLightSpecular(inout vec4 specular, vec3 view, vec3 v, vec3 n, vec3 l, float r, float pw, vec3 lightCol); + vec3 atmosAmbient(vec3 light); vec3 atmosAffectDirectionalLight(float lightIntensity); vec3 atmosGetDiffuseSunlightColor(); vec3 scaleDownLight(vec3 light); uniform vec4 light_position[8]; +uniform vec3 light_attenuation[8]; uniform vec3 light_diffuse[8]; vec4 sumLightsSpecular(vec3 pos, vec3 norm, vec4 color, inout vec4 specularColor, vec4 baseCol) { - vec4 col = vec4(0,0,0, color.a); + vec4 col = vec4(0.0, 0.0, 0.0, color.a); vec3 view = normalize(pos); /// collect all the specular values from each calcXXXLightSpecular() function vec4 specularSum = vec4(0.0); - col.rgb += light_diffuse[1].rgb * calcDirectionalLightSpecular(specularColor, view, norm, light_position[1].xyz,light_diffuse[1].rgb, 1.0); + // Collect normal lights (need to be divided by two, as we later multiply by 2) + col.rgb += calcPointLightSpecular(specularSum, view, pos, norm, light_position[1].xyz, light_attenuation[1].x, light_attenuation[1].y, light_diffuse[1].rgb); col.rgb = scaleDownLight(col.rgb); + + // Add windlight lights col.rgb += atmosAmbient(baseCol.rgb); col.rgb += atmosAffectDirectionalLight(calcDirectionalLightSpecular(specularSum, view, norm, light_position[0].xyz,atmosGetDiffuseSunlightColor()*baseCol.a, 1.0)); col.rgb = min(col.rgb * color.rgb, 1.0); specularColor.rgb = min(specularColor.rgb * specularSum.rgb, 1.0); - + col.rgb += specularColor.rgb; return col; diff --git a/indra/newview/app_settings/shaders/class1/lighting/sumLightsV.glsl b/indra/newview/app_settings/shaders/class1/lighting/sumLightsV.glsl index 41288c21c1..752becf788 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/sumLightsV.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/sumLightsV.glsl @@ -23,28 +23,36 @@ * $/LicenseInfo$ */ -uniform vec4 light_position[8]; -uniform vec3 light_diffuse[8]; float calcDirectionalLight(vec3 n, vec3 l); +float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float is_pointlight); vec3 atmosAmbient(vec3 light); vec3 atmosAffectDirectionalLight(float lightIntensity); vec3 scaleDownLight(vec3 light); + +uniform vec4 light_position[8]; +uniform vec3 light_direction[8]; +uniform vec3 light_attenuation[8]; +uniform vec3 light_diffuse[8]; + vec4 sumLights(vec3 pos, vec3 norm, vec4 color, vec4 baseLight) { - vec4 col; - col.a = color.a; - - col.rgb = light_diffuse[1].rgb * calcDirectionalLight(norm, light_position[1].xyz); + vec4 col = vec4(0.0, 0.0, 0.0, color.a); + + // Collect normal lights (need to be divided by two, as we later multiply by 2) + + // Collect normal lights + col.rgb += light_diffuse[1].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[1], light_direction[1], light_attenuation[1].x, light_attenuation[1].z); col.rgb = scaleDownLight(col.rgb); + + // Add windlight lights col.rgb += atmosAmbient(baseLight.rgb); col.rgb += atmosAffectDirectionalLight(calcDirectionalLight(norm, light_position[0].xyz)); - + col.rgb = min(col.rgb*color.rgb, 1.0); - - return col; -} + return col; +} diff --git a/indra/newview/app_settings/shaders/class1/objects/emissiveSkinnedV.glsl b/indra/newview/app_settings/shaders/class1/objects/emissiveSkinnedV.glsl index 8494ffba52..91aba0ed27 100644 --- a/indra/newview/app_settings/shaders/class1/objects/emissiveSkinnedV.glsl +++ b/indra/newview/app_settings/shaders/class1/objects/emissiveSkinnedV.glsl @@ -43,16 +43,13 @@ void main() //transform vertex vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; - mat4 mat = getObjectSkinnedTransform(); + mat4 mat = modelview_matrix * getObjectSkinnedTransform(); - mat = modelview_matrix * mat; vec3 pos = (mat*vec4(position.xyz, 1.0)).xyz; + vertex_color = emissive; + calcAtmospherics(pos.xyz); - vertex_color = emissive; - gl_Position = projection_matrix*vec4(pos, 1.0); - - } diff --git a/indra/newview/app_settings/shaders/class1/objects/fullbrightShinySkinnedV.glsl b/indra/newview/app_settings/shaders/class1/objects/fullbrightShinySkinnedV.glsl index 79b552ee1a..14054c2b61 100644 --- a/indra/newview/app_settings/shaders/class1/objects/fullbrightShinySkinnedV.glsl +++ b/indra/newview/app_settings/shaders/class1/objects/fullbrightShinySkinnedV.glsl @@ -42,9 +42,8 @@ mat4 getObjectSkinnedTransform(); void main() { - mat4 mat = getObjectSkinnedTransform(); + mat4 mat = modelview_matrix * getObjectSkinnedTransform(); - mat = modelview_matrix * mat; vec3 pos = (mat*vec4(position.xyz, 1.0)).xyz; vec4 norm = vec4(position.xyz, 1.0); diff --git a/indra/newview/app_settings/shaders/class1/objects/fullbrightSkinnedV.glsl b/indra/newview/app_settings/shaders/class1/objects/fullbrightSkinnedV.glsl index eff75435a9..6946df2ab3 100644 --- a/indra/newview/app_settings/shaders/class1/objects/fullbrightSkinnedV.glsl +++ b/indra/newview/app_settings/shaders/class1/objects/fullbrightSkinnedV.glsl @@ -42,9 +42,8 @@ void main() //transform vertex vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; - mat4 mat = getObjectSkinnedTransform(); + mat4 mat = modelview_matrix * getObjectSkinnedTransform(); - mat = modelview_matrix * mat; vec3 pos = (mat*vec4(position.xyz, 1.0)).xyz; calcAtmospherics(pos.xyz); diff --git a/indra/newview/app_settings/shaders/class1/objects/previewV.glsl b/indra/newview/app_settings/shaders/class1/objects/previewV.glsl index 7f3f84398b..3ad9d61f70 100644 --- a/indra/newview/app_settings/shaders/class1/objects/previewV.glsl +++ b/indra/newview/app_settings/shaders/class1/objects/previewV.glsl @@ -90,7 +90,7 @@ void main() vec4 col = vec4(0,0,0,1); // Collect normal lights (need to be divided by two, as we later multiply by 2) - col.rgb += light_diffuse[1].rgb * calcDirectionalLight(norm, light_position[1].xyz); + col.rgb += light_diffuse[1].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[1], light_direction[1], light_attenuation[1].x, light_attenuation[1].z); col.rgb += light_diffuse[2].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[2], light_direction[2], light_attenuation[2].x, light_attenuation[2].z); col.rgb += light_diffuse[3].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[3], light_direction[3], light_attenuation[3].x, light_attenuation[3].z); diff --git a/indra/newview/app_settings/shaders/class1/objects/shinySimpleSkinnedV.glsl b/indra/newview/app_settings/shaders/class1/objects/shinySimpleSkinnedV.glsl index 591d6fc5c9..1c8f0bea56 100644 --- a/indra/newview/app_settings/shaders/class1/objects/shinySimpleSkinnedV.glsl +++ b/indra/newview/app_settings/shaders/class1/objects/shinySimpleSkinnedV.glsl @@ -42,9 +42,8 @@ mat4 getObjectSkinnedTransform(); void main() { - mat4 mat = getObjectSkinnedTransform(); - - mat = modelview_matrix * mat; + mat4 mat = modelview_matrix * getObjectSkinnedTransform(); + vec3 pos = (mat*vec4(position.xyz, 1.0)).xyz; vec4 norm = vec4(position.xyz, 1.0); diff --git a/indra/newview/app_settings/shaders/class1/objects/simpleSkinnedV.glsl b/indra/newview/app_settings/shaders/class1/objects/simpleSkinnedV.glsl index 1c6e53b187..d67dad0057 100644 --- a/indra/newview/app_settings/shaders/class1/objects/simpleSkinnedV.glsl +++ b/indra/newview/app_settings/shaders/class1/objects/simpleSkinnedV.glsl @@ -44,9 +44,8 @@ void main() //transform vertex vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; - mat4 mat = getObjectSkinnedTransform(); + mat4 mat = modelview_matrix * getObjectSkinnedTransform(); - mat = modelview_matrix * mat; vec3 pos = (mat*vec4(position.xyz, 1.0)).xyz; vec4 norm = vec4(position.xyz, 1.0); diff --git a/indra/newview/app_settings/shaders/class1/transform/binormalV.glsl b/indra/newview/app_settings/shaders/class1/transform/binormalV.glsl index 44f1aa34a0..67bce87220 100644 --- a/indra/newview/app_settings/shaders/class1/transform/binormalV.glsl +++ b/indra/newview/app_settings/shaders/class1/transform/binormalV.glsl @@ -25,12 +25,12 @@ uniform mat3 normal_matrix; -ATTRIBUTE vec3 binormal; +ATTRIBUTE vec4 tangent; -VARYING vec4 binormal_out; +VARYING vec4 tangent_out; void main() { - binormal_out = vec4(normal_matrix * binormal, 0.0); + tangent_out = vec4(normal_matrix * tangent.xyz, tangent.w); } diff --git a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsHelpersV.glsl b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsHelpersV.glsl index 6ff860362c..1e5ede6c08 100644 --- a/indra/newview/app_settings/shaders/class1/windlight/atmosphericsHelpersV.glsl +++ b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsHelpersV.glsl @@ -23,7 +23,7 @@ * $/LicenseInfo$ */ -uniform vec4 sunlight_color_copy; +uniform vec3 sunlight_color_copy; uniform vec4 light_ambient; vec3 atmosAmbient(vec3 light) diff --git a/indra/newview/app_settings/shaders/class2/avatar/eyeballV.glsl b/indra/newview/app_settings/shaders/class2/avatar/eyeballV.glsl deleted file mode 100644 index 5af9f5c902..0000000000 --- a/indra/newview/app_settings/shaders/class2/avatar/eyeballV.glsl +++ /dev/null @@ -1,62 +0,0 @@ -/** - * @file eyeballV.glsl - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2007, 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$ - */ - -uniform mat3 normal_matrix; -uniform mat4 texture_matrix0; -uniform mat4 modelview_matrix; -uniform mat4 modelview_projection_matrix; - -ATTRIBUTE vec3 position; -ATTRIBUTE vec4 diffuse_color; -ATTRIBUTE vec3 normal; -ATTRIBUTE vec2 texcoord0; - -VARYING vec4 vertex_color; -VARYING vec2 vary_texcoord0; - - -vec4 calcLightingSpecular(vec3 pos, vec3 norm, vec4 color, inout vec4 specularColor, vec4 baseCol); -void calcAtmospherics(vec3 inPositionEye); - -void main() -{ - //transform vertex - vec3 pos = (modelview_matrix * vec4(position.xyz, 1.0)).xyz; - gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0); - vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; - - vec3 norm = normalize(normal_matrix * normal); - - calcAtmospherics(pos.xyz); - - // vec4 specular = specularColor; - vec4 specular = vec4(1.0); - vec4 color = calcLightingSpecular(pos, norm, diffuse_color, specular, vec4(0.0)); - - vertex_color = color; - - -} - diff --git a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl deleted file mode 100644 index 8db4cb58cf..0000000000 --- a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl +++ /dev/null @@ -1,168 +0,0 @@ -/** - * @file alphaF.glsl - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2007, 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$ - */ - -#extension GL_ARB_texture_rectangle : enable - -#ifdef DEFINE_GL_FRAGCOLOR -out vec4 frag_color; -#else -#define frag_color gl_FragColor -#endif - -VARYING vec4 vertex_color; -VARYING vec2 vary_texcoord0; - -uniform sampler2DRectShadow shadowMap0; -uniform sampler2DRectShadow shadowMap1; -uniform sampler2DRectShadow shadowMap2; -uniform sampler2DRectShadow shadowMap3; -uniform sampler2DRect depthMap; - -uniform mat4 shadow_matrix[6]; -uniform vec4 shadow_clip; -uniform vec2 screen_res; -uniform vec2 shadow_res; - -vec3 atmosLighting(vec3 light); -vec3 scaleSoftClip(vec3 light); - -VARYING vec3 vary_ambient; -VARYING vec3 vary_directional; -VARYING vec3 vary_fragcoord; -VARYING vec3 vary_position; -VARYING vec3 vary_pointlight_col; - -uniform float shadow_bias; - -uniform mat4 inv_proj; - -float pcfShadow(sampler2DRectShadow shadowMap, vec4 stc) -{ - stc.xyz /= stc.w; - stc.z += shadow_bias; - - stc.x = floor(stc.x + fract(stc.y*12345)); // add some chaotic jitter to X sample pos according to Y to disguise the snapping going on here - - float cs = shadow2DRect(shadowMap, stc.xyz).x; - float shadow = cs; - - shadow += shadow2DRect(shadowMap, stc.xyz+vec3(2.0, 1.5, 0.0)).x; - shadow += shadow2DRect(shadowMap, stc.xyz+vec3(1.0, -1.5, 0.0)).x; - shadow += shadow2DRect(shadowMap, stc.xyz+vec3(-1.0, 1.5, 0.0)).x; - shadow += shadow2DRect(shadowMap, stc.xyz+vec3(-2.0, -1.5, 0.0)).x; - - return shadow*0.2; -} - - -void main() -{ - vec2 frag = vary_fragcoord.xy/vary_fragcoord.z*0.5+0.5; - frag *= screen_res; - - float shadow = 0.0; - vec4 pos = vec4(vary_position, 1.0); - - vec4 spos = pos; - - if (spos.z > -shadow_clip.w) - { - vec4 lpos; - - vec4 near_split = shadow_clip*-0.75; - vec4 far_split = shadow_clip*-1.25; - vec4 transition_domain = near_split-far_split; - float weight = 0.0; - - if (spos.z < near_split.z) - { - lpos = shadow_matrix[3]*spos; - lpos.xy *= shadow_res; - - float w = 1.0; - w -= max(spos.z-far_split.z, 0.0)/transition_domain.z; - shadow += pcfShadow(shadowMap3, lpos)*w; - weight += w; - shadow += max((pos.z+shadow_clip.z)/(shadow_clip.z-shadow_clip.w)*2.0-1.0, 0.0); - } - - if (spos.z < near_split.y && spos.z > far_split.z) - { - lpos = shadow_matrix[2]*spos; - lpos.xy *= shadow_res; - - float w = 1.0; - w -= max(spos.z-far_split.y, 0.0)/transition_domain.y; - w -= max(near_split.z-spos.z, 0.0)/transition_domain.z; - shadow += pcfShadow(shadowMap2, lpos)*w; - weight += w; - } - - if (spos.z < near_split.x && spos.z > far_split.y) - { - lpos = shadow_matrix[1]*spos; - lpos.xy *= shadow_res; - - float w = 1.0; - w -= max(spos.z-far_split.x, 0.0)/transition_domain.x; - w -= max(near_split.y-spos.z, 0.0)/transition_domain.y; - shadow += pcfShadow(shadowMap1, lpos)*w; - weight += w; - } - - if (spos.z > far_split.x) - { - lpos = shadow_matrix[0]*spos; - lpos.xy *= shadow_res; - - float w = 1.0; - w -= max(near_split.x-spos.z, 0.0)/transition_domain.x; - - shadow += pcfShadow(shadowMap0, lpos)*w; - weight += w; - } - - - shadow /= weight; - } - else - { - shadow = 1.0; - } - - vec4 diff = diffuseLookup(vary_texcoord0.xy); - - vec4 col = vec4(vary_ambient + vary_directional.rgb*shadow, vertex_color.a); - vec4 color = diff * col; - - color.rgb = atmosLighting(color.rgb); - - color.rgb = scaleSoftClip(color.rgb); - - color.rgb += diff.rgb * vary_pointlight_col.rgb; - - frag_color = color; -} - diff --git a/indra/newview/app_settings/shaders/class2/deferred/alphaNonIndexedF.glsl b/indra/newview/app_settings/shaders/class2/deferred/alphaNonIndexedF.glsl deleted file mode 100644 index 33958a5010..0000000000 --- a/indra/newview/app_settings/shaders/class2/deferred/alphaNonIndexedF.glsl +++ /dev/null @@ -1,182 +0,0 @@ -/** - * @file alphaF.glsl - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2007, 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$ - */ - -#extension GL_ARB_texture_rectangle : enable - -#ifdef DEFINE_GL_FRAGCOLOR -out vec4 frag_color; -#else -#define frag_color gl_FragColor -#endif - -uniform sampler2DRectShadow shadowMap0; -uniform sampler2DRectShadow shadowMap1; -uniform sampler2DRectShadow shadowMap2; -uniform sampler2DRectShadow shadowMap3; -uniform sampler2DRect depthMap; -uniform sampler2D diffuseMap; - -uniform mat4 shadow_matrix[6]; -uniform vec4 shadow_clip; -uniform vec2 screen_res; -uniform vec2 shadow_res; - -vec3 atmosLighting(vec3 light); -vec3 scaleSoftClip(vec3 light); - -VARYING vec3 vary_ambient; -VARYING vec3 vary_directional; -VARYING vec3 vary_fragcoord; -VARYING vec3 vary_position; -VARYING vec3 vary_pointlight_col; -VARYING vec2 vary_texcoord0; -VARYING vec4 vertex_color; - -uniform float shadow_bias; - -uniform mat4 inv_proj; - -vec4 getPosition(vec2 pos_screen) -{ - float depth = texture2DRect(depthMap, pos_screen.xy).a; - vec2 sc = pos_screen.xy*2.0; - sc /= screen_res; - sc -= vec2(1.0,1.0); - vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0); - vec4 pos = inv_proj * ndc; - pos.xyz /= pos.w; - pos.w = 1.0; - return pos; -} - -float pcfShadow(sampler2DRectShadow shadowMap, vec4 stc) -{ - stc.xyz /= stc.w; - stc.z += shadow_bias; - - stc.x = floor(stc.x + fract(stc.y*12345)); // add some chaotic jitter to X sample pos according to Y to disguise the snapping going on here - - float cs = shadow2DRect(shadowMap, stc.xyz).x; - float shadow = cs; - - shadow += shadow2DRect(shadowMap, stc.xyz+vec3(2.0, 1.5, 0.0)).x; - shadow += shadow2DRect(shadowMap, stc.xyz+vec3(1.0, -1.5, 0.0)).x; - shadow += shadow2DRect(shadowMap, stc.xyz+vec3(-1.0, 1.5, 0.0)).x; - shadow += shadow2DRect(shadowMap, stc.xyz+vec3(-2.0, -1.5, 0.0)).x; - - return shadow*0.2; -} - - -void main() -{ - vec2 frag = vary_fragcoord.xy/vary_fragcoord.z*0.5+0.5; - frag *= screen_res; - - float shadow = 0.0; - vec4 pos = vec4(vary_position, 1.0); - - vec4 spos = pos; - - if (spos.z > -shadow_clip.w) - { - vec4 lpos; - - vec4 near_split = shadow_clip*-0.75; - vec4 far_split = shadow_clip*-1.25; - vec4 transition_domain = near_split-far_split; - float weight = 0.0; - - if (spos.z < near_split.z) - { - lpos = shadow_matrix[3]*spos; - lpos.xy *= shadow_res; - - float w = 1.0; - w -= max(spos.z-far_split.z, 0.0)/transition_domain.z; - shadow += pcfShadow(shadowMap3, lpos)*w; - weight += w; - shadow += max((pos.z+shadow_clip.z)/(shadow_clip.z-shadow_clip.w)*2.0-1.0, 0.0); - } - - if (spos.z < near_split.y && spos.z > far_split.z) - { - lpos = shadow_matrix[2]*spos; - lpos.xy *= shadow_res; - - float w = 1.0; - w -= max(spos.z-far_split.y, 0.0)/transition_domain.y; - w -= max(near_split.z-spos.z, 0.0)/transition_domain.z; - shadow += pcfShadow(shadowMap2, lpos)*w; - weight += w; - } - - if (spos.z < near_split.x && spos.z > far_split.y) - { - lpos = shadow_matrix[1]*spos; - lpos.xy *= shadow_res; - - float w = 1.0; - w -= max(spos.z-far_split.x, 0.0)/transition_domain.x; - w -= max(near_split.y-spos.z, 0.0)/transition_domain.y; - shadow += pcfShadow(shadowMap1, lpos)*w; - weight += w; - } - - if (spos.z > far_split.x) - { - lpos = shadow_matrix[0]*spos; - lpos.xy *= shadow_res; - - float w = 1.0; - w -= max(near_split.x-spos.z, 0.0)/transition_domain.x; - - shadow += pcfShadow(shadowMap0, lpos)*w; - weight += w; - } - - - shadow /= weight; - - } - else - { - shadow = 1.0; - } - - vec4 diff = texture2D(diffuseMap,vary_texcoord0.xy); - - vec4 col = vec4(vary_ambient + vary_directional.rgb*shadow, vertex_color.a); - vec4 color = diff * col; - - color.rgb = atmosLighting(color.rgb); - - color.rgb = scaleSoftClip(color.rgb); - - color.rgb += diff.rgb * vary_pointlight_col.rgb; - - frag_color = color; -} - diff --git a/indra/newview/app_settings/shaders/class2/deferred/alphaNonIndexedNoColorF.glsl b/indra/newview/app_settings/shaders/class2/deferred/alphaNonIndexedNoColorF.glsl deleted file mode 100644 index 2093fc37dc..0000000000 --- a/indra/newview/app_settings/shaders/class2/deferred/alphaNonIndexedNoColorF.glsl +++ /dev/null @@ -1,187 +0,0 @@ -/** - * @file alphaNonIndexedNoColorF.glsl - * - * $LicenseInfo:firstyear=2005&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2005, 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$ - */ - -#extension GL_ARB_texture_rectangle : enable - -#ifdef DEFINE_GL_FRAGCOLOR -out vec4 frag_color; -#else -#define frag_color gl_FragColor -#endif - -uniform float minimum_alpha; - -uniform sampler2DRectShadow shadowMap0; -uniform sampler2DRectShadow shadowMap1; -uniform sampler2DRectShadow shadowMap2; -uniform sampler2DRectShadow shadowMap3; -uniform sampler2DRect depthMap; -uniform sampler2D diffuseMap; - -uniform mat4 shadow_matrix[6]; -uniform vec4 shadow_clip; -uniform vec2 screen_res; -uniform vec2 shadow_res; - -vec3 atmosLighting(vec3 light); -vec3 scaleSoftClip(vec3 light); - -VARYING vec3 vary_ambient; -VARYING vec3 vary_directional; -VARYING vec3 vary_fragcoord; -VARYING vec3 vary_position; -VARYING vec3 vary_pointlight_col; -VARYING vec2 vary_texcoord0; - -uniform float shadow_bias; - -uniform mat4 inv_proj; - -vec4 getPosition(vec2 pos_screen) -{ - float depth = texture2DRect(depthMap, pos_screen.xy).a; - vec2 sc = pos_screen.xy*2.0; - sc /= screen_res; - sc -= vec2(1.0,1.0); - vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0); - vec4 pos = inv_proj * ndc; - pos.xyz /= pos.w; - pos.w = 1.0; - return pos; -} - -float pcfShadow(sampler2DRectShadow shadowMap, vec4 stc) -{ - stc.xyz /= stc.w; - stc.z += shadow_bias; - - stc.x = floor(stc.x + fract(stc.y*12345)); // add some chaotic jitter to X sample pos according to Y to disguise the snapping going on here - - float cs = shadow2DRect(shadowMap, stc.xyz).x; - float shadow = cs; - - shadow += shadow2DRect(shadowMap, stc.xyz+vec3(2.0, 1.5, 0.0)).x; - shadow += shadow2DRect(shadowMap, stc.xyz+vec3(1.0, -1.5, 0.0)).x; - shadow += shadow2DRect(shadowMap, stc.xyz+vec3(-1.0, 1.5, 0.0)).x; - shadow += shadow2DRect(shadowMap, stc.xyz+vec3(-2.0, -1.5, 0.0)).x; - - return shadow*0.2; -} - - -void main() -{ - vec2 frag = vary_fragcoord.xy/vary_fragcoord.z*0.5+0.5; - frag *= screen_res; - - float shadow = 0.0; - vec4 pos = vec4(vary_position, 1.0); - - vec4 diff = texture2D(diffuseMap,vary_texcoord0.xy); - - if (diff.a < minimum_alpha) - { - discard; - } - - vec4 spos = pos; - - if (spos.z > -shadow_clip.w) - { - vec4 lpos; - - vec4 near_split = shadow_clip*-0.75; - vec4 far_split = shadow_clip*-1.25; - vec4 transition_domain = near_split-far_split; - float weight = 0.0; - - if (spos.z < near_split.z) - { - lpos = shadow_matrix[3]*spos; - lpos.xy *= shadow_res; - - float w = 1.0; - w -= max(spos.z-far_split.z, 0.0)/transition_domain.z; - shadow += pcfShadow(shadowMap3, lpos)*w; - weight += w; - shadow += max((pos.z+shadow_clip.z)/(shadow_clip.z-shadow_clip.w)*2.0-1.0, 0.0); - } - - if (spos.z < near_split.y && spos.z > far_split.z) - { - lpos = shadow_matrix[2]*spos; - lpos.xy *= shadow_res; - - float w = 1.0; - w -= max(spos.z-far_split.y, 0.0)/transition_domain.y; - w -= max(near_split.z-spos.z, 0.0)/transition_domain.z; - shadow += pcfShadow(shadowMap2, lpos)*w; - weight += w; - } - - if (spos.z < near_split.x && spos.z > far_split.y) - { - lpos = shadow_matrix[1]*spos; - lpos.xy *= shadow_res; - - float w = 1.0; - w -= max(spos.z-far_split.x, 0.0)/transition_domain.x; - w -= max(near_split.y-spos.z, 0.0)/transition_domain.y; - shadow += pcfShadow(shadowMap1, lpos)*w; - weight += w; - } - - if (spos.z > far_split.x) - { - lpos = shadow_matrix[0]*spos; - lpos.xy *= shadow_res; - - float w = 1.0; - w -= max(near_split.x-spos.z, 0.0)/transition_domain.x; - - shadow += pcfShadow(shadowMap0, lpos)*w; - weight += w; - } - - - shadow /= weight; - } - else - { - shadow = 1.0; - } - - vec4 col = vec4(vary_ambient + vary_directional.rgb*shadow, 1.0); - vec4 color = diff * col; - - color.rgb = atmosLighting(color.rgb); - - color.rgb = scaleSoftClip(color.rgb); - - color.rgb += diff.rgb * vary_pointlight_col.rgb; - - frag_color = color; -} - diff --git a/indra/newview/app_settings/shaders/class2/deferred/alphaSkinnedV.glsl b/indra/newview/app_settings/shaders/class2/deferred/alphaSkinnedV.glsl deleted file mode 100644 index 9629cfe824..0000000000 --- a/indra/newview/app_settings/shaders/class2/deferred/alphaSkinnedV.glsl +++ /dev/null @@ -1,155 +0,0 @@ -/** - * @file alphaSkinnedV.glsl - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2007, 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$ - */ - -uniform mat4 projection_matrix; -uniform mat4 texture_matrix0; -uniform mat4 modelview_matrix; -uniform mat4 modelview_projection_matrix; - -ATTRIBUTE vec3 position; -ATTRIBUTE vec3 normal; -ATTRIBUTE vec4 diffuse_color; -ATTRIBUTE vec2 texcoord0; - -vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol); -void calcAtmospherics(vec3 inPositionEye); - -float calcDirectionalLight(vec3 n, vec3 l); -mat4 getObjectSkinnedTransform(); -vec3 atmosAmbient(vec3 light); -vec3 atmosAffectDirectionalLight(float lightIntensity); -vec3 scaleDownLight(vec3 light); -vec3 scaleUpLight(vec3 light); - -VARYING vec3 vary_ambient; -VARYING vec3 vary_directional; -VARYING vec3 vary_fragcoord; -VARYING vec3 vary_position; -VARYING vec3 vary_pointlight_col; - -VARYING vec4 vertex_color; -VARYING vec2 vary_texcoord0; - - -uniform float near_clip; -uniform float shadow_offset; -uniform float shadow_bias; - -uniform vec4 light_position[8]; -uniform vec3 light_direction[8]; -uniform vec3 light_attenuation[8]; -uniform vec3 light_diffuse[8]; - -float calcDirectionalLight(vec3 n, vec3 l) -{ - float a = max(dot(n,l),0.0); - return a; -} - -float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float fa, float is_pointlight) -{ -//get light vector - vec3 lv = lp.xyz-v; - - //get distance - float d = dot(lv,lv); - - float da = 0.0; - - if (d > 0.0 && la > 0.0 && fa > 0.0) - { - //normalize light vector - lv = normalize(lv); - - //distance attenuation - float dist2 = d/la; - da = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0); - - // spotlight coefficient. - float spot = max(dot(-ln, lv), is_pointlight); - da *= spot*spot; // GL_SPOT_EXPONENT=2 - - //angular attenuation - da *= max(dot(n, lv), 0.0); - } - - return da; -} - -void main() -{ - vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; - - mat4 mat = getObjectSkinnedTransform(); - - mat = modelview_matrix * mat; - - vec3 pos = (mat*vec4(position, 1.0)).xyz; - - gl_Position = projection_matrix * vec4(pos, 1.0); - - vec4 n = vec4(position, 1.0); - n.xyz += normal.xyz; - n.xyz = (mat*n).xyz; - n.xyz = normalize(n.xyz-pos.xyz); - - vec3 norm = n.xyz; - - float dp_directional_light = max(0.0, dot(norm, light_position[0].xyz)); - vary_position = pos.xyz + light_position[0].xyz * (1.0-dp_directional_light)*shadow_offset; - - calcAtmospherics(pos.xyz); - - //vec4 color = calcLighting(pos.xyz, norm, diffuse_color, vec4(0.)); - vec4 col = vec4(0.0, 0.0, 0.0, diffuse_color.a); - - // Collect normal lights - col.rgb += light_diffuse[2].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[2], light_direction[2], light_attenuation[2].x, light_attenuation[2].y, light_attenuation[2].z); - col.rgb += light_diffuse[3].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[3], light_direction[3], light_attenuation[3].x, light_attenuation[3].y, light_attenuation[3].z); - col.rgb += light_diffuse[4].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[4], light_direction[4], light_attenuation[4].x, light_attenuation[4].y, light_attenuation[4].z); - col.rgb += light_diffuse[5].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[5], light_direction[5], light_attenuation[5].x, light_attenuation[5].y, light_attenuation[5].z); - col.rgb += light_diffuse[6].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[6], light_direction[6], light_attenuation[6].x, light_attenuation[6].y, light_attenuation[6].z); - col.rgb += light_diffuse[7].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[7], light_direction[7], light_attenuation[7].x, light_attenuation[7].y, light_attenuation[7].z); - - vary_pointlight_col = col.rgb*diffuse_color.rgb; - - col.rgb = vec3(0,0,0); - - // Add windlight lights - col.rgb = atmosAmbient(vec3(0.)); - - vary_ambient = col.rgb*diffuse_color.rgb; - vary_directional.rgb = diffuse_color.rgb*atmosAffectDirectionalLight(max(calcDirectionalLight(norm, light_position[0].xyz), (1.0-diffuse_color.a)*(1.0-diffuse_color.a))); - - col.rgb = min(col.rgb*diffuse_color.rgb, 1.0); - - vertex_color = col; - - - - pos.xyz = (modelview_projection_matrix * vec4(position.xyz, 1.0)).xyz; - vary_fragcoord.xyz = pos.xyz + vec3(0,0,near_clip); - -} - diff --git a/indra/newview/app_settings/shaders/class2/deferred/alphaV.glsl b/indra/newview/app_settings/shaders/class2/deferred/alphaV.glsl deleted file mode 100644 index 1586aab0f2..0000000000 --- a/indra/newview/app_settings/shaders/class2/deferred/alphaV.glsl +++ /dev/null @@ -1,150 +0,0 @@ -/** - * @file alphaV.glsl - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2007, 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$ - */ - -uniform mat3 normal_matrix; -uniform mat4 texture_matrix0; -uniform mat4 modelview_matrix; -uniform mat4 modelview_projection_matrix; - -ATTRIBUTE vec3 position; -void passTextureIndex(); -ATTRIBUTE vec3 normal; -ATTRIBUTE vec4 diffuse_color; -ATTRIBUTE vec2 texcoord0; - -vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol); -void calcAtmospherics(vec3 inPositionEye); - -float calcDirectionalLight(vec3 n, vec3 l); - -vec3 atmosAmbient(vec3 light); -vec3 atmosAffectDirectionalLight(float lightIntensity); -vec3 scaleDownLight(vec3 light); -vec3 scaleUpLight(vec3 light); - -VARYING vec3 vary_ambient; -VARYING vec3 vary_directional; -VARYING vec3 vary_fragcoord; -VARYING vec3 vary_position; -VARYING vec3 vary_pointlight_col; - -VARYING vec4 vertex_color; -VARYING vec2 vary_texcoord0; - - -uniform float near_clip; -uniform float shadow_offset; -uniform float shadow_bias; - -uniform vec4 light_position[8]; -uniform vec3 light_direction[8]; -uniform vec3 light_attenuation[8]; -uniform vec3 light_diffuse[8]; - -float calcDirectionalLight(vec3 n, vec3 l) -{ - float a = max(dot(n,l),0.0); - return a; -} - -float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float fa, float is_pointlight) -{ - //get light vector - vec3 lv = lp.xyz-v; - - //get distance - float d = dot(lv,lv); - - float da = 0.0; - - if (d > 0.0 && la > 0.0 && fa > 0.0) - { - //normalize light vector - lv = normalize(lv); - - //distance attenuation - float dist2 = d/la; - da = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0); - - // spotlight coefficient. - float spot = max(dot(-ln, lv), is_pointlight); - da *= spot*spot; // GL_SPOT_EXPONENT=2 - - //angular attenuation - da *= max(dot(n, lv), 0.0); - } - - return da; -} - -void main() -{ - //transform vertex - vec4 vert = vec4(position.xyz, 1.0); - passTextureIndex(); - vec4 pos = (modelview_matrix * vert); - gl_Position = modelview_projection_matrix*vec4(position.xyz, 1.0); - - vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; - - vec3 norm = normalize(normal_matrix * normal); - - float dp_directional_light = max(0.0, dot(norm, light_position[0].xyz)); - vary_position = pos.xyz + light_position[0].xyz * (1.0-dp_directional_light)*shadow_offset; - - calcAtmospherics(pos.xyz); - - //vec4 color = calcLighting(pos.xyz, norm, diffuse_color, vec4(0.)); - vec4 col = vec4(0.0, 0.0, 0.0, diffuse_color.a); - - - // Collect normal lights - col.rgb += light_diffuse[2].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[2], light_direction[2], light_attenuation[2].x, light_attenuation[2].y, light_attenuation[2].z); - col.rgb += light_diffuse[3].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[3], light_direction[3], light_attenuation[3].x, light_attenuation[3].y, light_attenuation[3].z); - col.rgb += light_diffuse[4].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[4], light_direction[4], light_attenuation[4].x, light_attenuation[4].y, light_attenuation[4].z); - col.rgb += light_diffuse[5].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[5], light_direction[5], light_attenuation[5].x, light_attenuation[5].y, light_attenuation[5].z); - col.rgb += light_diffuse[6].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[6], light_direction[6], light_attenuation[6].x, light_attenuation[6].y, light_attenuation[6].z); - col.rgb += light_diffuse[7].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[7], light_direction[7], light_attenuation[7].x, light_attenuation[7].y, light_attenuation[7].z); - - vary_pointlight_col = col.rgb*diffuse_color.rgb; - - col.rgb = vec3(0,0,0); - - // Add windlight lights - col.rgb = atmosAmbient(vec3(0.)); - - vary_ambient = col.rgb*diffuse_color.rgb; - vary_directional.rgb = diffuse_color.rgb*atmosAffectDirectionalLight(max(calcDirectionalLight(norm, light_position[0].xyz), (1.0-diffuse_color.a)*(1.0-diffuse_color.a))); - - col.rgb = col.rgb*diffuse_color.rgb; - - vertex_color = col; - - - - pos = modelview_projection_matrix * vert; - vary_fragcoord.xyz = pos.xyz + vec3(0,0,near_clip); - -} diff --git a/indra/newview/app_settings/shaders/class2/deferred/avatarAlphaV.glsl b/indra/newview/app_settings/shaders/class2/deferred/avatarAlphaV.glsl deleted file mode 100644 index 44aaa98b97..0000000000 --- a/indra/newview/app_settings/shaders/class2/deferred/avatarAlphaV.glsl +++ /dev/null @@ -1,153 +0,0 @@ -/** - * @file avatarAlphaV.glsl - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2007, 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$ - */ - -uniform mat4 projection_matrix; - -ATTRIBUTE vec3 position; -ATTRIBUTE vec3 normal; -ATTRIBUTE vec2 texcoord0; - -vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol); -mat4 getSkinnedTransform(); -void calcAtmospherics(vec3 inPositionEye); - -float calcDirectionalLight(vec3 n, vec3 l); -float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float is_pointlight); - -vec3 atmosAmbient(vec3 light); -vec3 atmosAffectDirectionalLight(float lightIntensity); -vec3 scaleDownLight(vec3 light); -vec3 scaleUpLight(vec3 light); - -VARYING vec3 vary_position; -VARYING vec3 vary_ambient; -VARYING vec3 vary_directional; -VARYING vec3 vary_fragcoord; -VARYING vec3 vary_pointlight_col; -VARYING vec4 vertex_color; -VARYING vec2 vary_texcoord0; - -uniform vec4 color; - -uniform float near_clip; -uniform float shadow_offset; -uniform float shadow_bias; - -uniform vec4 light_position[8]; -uniform vec3 light_direction[8]; -uniform vec3 light_attenuation[8]; -uniform vec3 light_diffuse[8]; - -float calcDirectionalLight(vec3 n, vec3 l) -{ - float a = max(dot(n,l),0.0); - return a; -} - -float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float fa, float is_pointlight) -{ - //get light vector - vec3 lv = lp.xyz-v; - - //get distance - float d = dot(lv,lv); - - float da = 0.0; - - if (d > 0.0 && la > 0.0 && fa > 0.0) - { - //normalize light vector - lv = normalize(lv); - - //distance attenuation - float dist2 = d/la; - da = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0); - - // spotlight coefficient. - float spot = max(dot(-ln, lv), is_pointlight); - da *= spot*spot; // GL_SPOT_EXPONENT=2 - - //angular attenuation - da *= max(dot(n, lv), 0.0); - } - - return da; -} - -void main() -{ - vary_texcoord0 = texcoord0; - - vec4 pos; - vec3 norm; - - mat4 trans = getSkinnedTransform(); - vec4 pos_in = vec4(position.xyz, 1.0); - pos.x = dot(trans[0], pos_in); - pos.y = dot(trans[1], pos_in); - pos.z = dot(trans[2], pos_in); - pos.w = 1.0; - - norm.x = dot(trans[0].xyz, normal); - norm.y = dot(trans[1].xyz, normal); - norm.z = dot(trans[2].xyz, normal); - norm = normalize(norm); - - gl_Position = projection_matrix * pos; - - float dp_directional_light = max(0.0, dot(norm, light_position[0].xyz)); - vary_position = pos.xyz + light_position[0].xyz * (1.0-dp_directional_light)*shadow_offset; - - calcAtmospherics(pos.xyz); - - vec4 col = vec4(0.0, 0.0, 0.0, 1.0); - - // Collect normal lights - col.rgb += light_diffuse[2].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[2], light_direction[2], light_attenuation[2].x, light_attenuation[2].y, light_attenuation[2].z); - col.rgb += light_diffuse[3].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[3], light_direction[3], light_attenuation[3].x, light_attenuation[3].y, light_attenuation[3].z); - col.rgb += light_diffuse[4].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[4], light_direction[4], light_attenuation[4].x, light_attenuation[4].y, light_attenuation[4].z); - col.rgb += light_diffuse[5].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[5], light_direction[5], light_attenuation[5].x, light_attenuation[5].y, light_attenuation[5].z); - col.rgb += light_diffuse[6].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[6], light_direction[6], light_attenuation[6].x, light_attenuation[6].y, light_attenuation[6].z); - col.rgb += light_diffuse[7].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[7], light_direction[7], light_attenuation[7].x, light_attenuation[7].y, light_attenuation[7].z); - - vary_pointlight_col = col.rgb*color.rgb; - - col.rgb = vec3(0,0,0); - - // Add windlight lights - col.rgb = atmosAmbient(vec3(0.)); - - vary_ambient = col.rgb*color.rgb; - vary_directional = atmosAffectDirectionalLight(max(calcDirectionalLight(norm, light_position[0].xyz), 0.0)); - - col.rgb = col.rgb*color.rgb; - - vertex_color = col; - - - vary_fragcoord.xyz = pos.xyz + vec3(0,0,near_clip); -} - - diff --git a/indra/newview/app_settings/shaders/class2/deferred/multiSpotLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/multiSpotLightF.glsl index 7f6a31ef7d..ed1065cd3c 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/multiSpotLightF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/multiSpotLightF.glsl @@ -22,8 +22,6 @@ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ - -#extension GL_ARB_texture_rectangle : enable #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_color; @@ -31,14 +29,14 @@ out vec4 frag_color; #define frag_color gl_FragColor #endif -uniform sampler2DRect diffuseRect; -uniform sampler2DRect specularRect; -uniform sampler2DRect depthMap; -uniform sampler2DRect normalMap; +uniform sampler2D diffuseRect; +uniform sampler2D specularRect; +uniform sampler2D depthMap; +uniform sampler2D normalMap; uniform samplerCube environmentMap; -uniform sampler2DRect lightMap; uniform sampler2D noiseMap; uniform sampler2D projectionMap; +uniform sampler2D lightFunc; uniform mat4 proj_mat; //screen space to light space uniform float proj_near; //near clip for projection @@ -54,30 +52,37 @@ uniform float far_clip; uniform vec3 proj_origin; //origin of projection to be used for angular attenuation uniform float sun_wash; + +// Shadows +uniform sampler2D lightMap; uniform int proj_shadow_idx; uniform float shadow_fade; uniform vec3 center; -uniform float size; uniform vec3 color; uniform float falloff; +uniform float size; VARYING vec4 vary_fragcoord; -uniform vec2 screen_res; uniform mat4 inv_proj; +uniform vec2 noise_scale; + +vec3 decode_normal(vec2 enc); +vec4 getPosition(vec2 pos_screen); +vec4 srgb_to_linear(vec4 cs); vec4 texture2DLodSpecular(sampler2D projectionMap, vec2 tc, float lod) { vec4 ret = texture2DLod(projectionMap, tc, lod); - vec2 dist = tc-vec2(0.5); - - float det = max(1.0-lod/(proj_lod*0.5), 0.0); - - float d = dot(dist,dist); - - ret *= min(clamp((0.25-d)/0.25, 0.0, 1.0)+det, 1.0); + ret = srgb_to_linear(ret); + vec2 dist = vec2(0.5) - abs(tc-vec2(0.5)); + float det = min(lod/(proj_lod*0.5), 1.0); + float d = min(dist.x, dist.y); + d *= min(1, d * (proj_lod - lod)); + float edge = 0.25*det; + ret *= clamp(d/edge, 0.0, 1.0); return ret; } @@ -85,7 +90,8 @@ vec4 texture2DLodSpecular(sampler2D projectionMap, vec2 tc, float lod) vec4 texture2DLodDiffuse(sampler2D projectionMap, vec2 tc, float lod) { vec4 ret = texture2DLod(projectionMap, tc, lod); - + ret = srgb_to_linear(ret); + vec2 dist = vec2(0.5) - abs(tc-vec2(0.5)); float det = min(lod/(proj_lod*0.5), 1.0); @@ -102,6 +108,7 @@ vec4 texture2DLodDiffuse(sampler2D projectionMap, vec2 tc, float lod) vec4 texture2DLodAmbient(sampler2D projectionMap, vec2 tc, float lod) { vec4 ret = texture2DLod(projectionMap, tc, lod); + ret = srgb_to_linear(ret); vec2 dist = tc-vec2(0.5); @@ -112,64 +119,39 @@ vec4 texture2DLodAmbient(sampler2D projectionMap, vec2 tc, float lod) return ret; } - -vec4 getPosition(vec2 pos_screen) -{ - float depth = texture2DRect(depthMap, pos_screen.xy).r; - vec2 sc = pos_screen.xy*2.0; - sc /= screen_res; - sc -= vec2(1.0,1.0); - vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0); - vec4 pos = inv_proj * ndc; - pos /= pos.w; - pos.w = 1.0; - return pos; -} - -vec3 unpack(vec2 tc) -{ -//#define PACK_NORMALS -#ifdef PACK_NORMALS - vec2 enc = texture2DRect(normalMap, tc).xy; - enc = enc*4.0-2.0; - float prod = dot(enc,enc); - return vec3(enc*sqrt(1.0-prod*.25),1.0-prod*.5); -#else - vec3 norm = texture2DRect(normalMap, tc).xyz; - return norm*2.0-1.0; -#endif -} - void main() { vec4 frag = vary_fragcoord; frag.xyz /= frag.w; frag.xyz = frag.xyz*0.5+0.5; - frag.xy *= screen_res; vec3 pos = getPosition(frag.xy).xyz; vec3 lv = center.xyz-pos.xyz; - float dist2 = dot(lv,lv); - dist2 /= size; - if (dist2 > 1.0) + float dist = length(lv); + dist /= size; + if (dist > 1.0) { discard; } - + float shadow = 1.0; - + if (proj_shadow_idx >= 0) { - vec4 shd = texture2DRect(lightMap, frag.xy); + vec4 shd = texture2D(lightMap, frag.xy); float sh[2]; sh[0] = shd.b; sh[1] = shd.a; shadow = min(sh[proj_shadow_idx]+shadow_fade, 1.0); } + + vec3 norm = texture2D(normalMap, frag.xy).xyz; + + float envIntensity = norm.z; + + norm = decode_normal(norm.xy); - vec3 norm = unpack(frag.xy); // unpack norm - - //norm = normalize(norm); // may be superfluous + norm = normalize(norm); float l_dist = -dot(lv, proj_n); vec4 proj_tc = (proj_mat * vec4(pos.xyz, 1.0)); @@ -181,7 +163,10 @@ void main() proj_tc.xyz /= proj_tc.w; float fa = falloff+1.0; - float dist_atten = min(1.0-(dist2-1.0*(1.0-fa))/fa, 1.0); + float dist_atten = min(1.0-(dist-1.0*(1.0-fa))/fa, 1.0); + dist_atten *= dist_atten; + dist_atten *= 2.0; + if (dist_atten <= 0.0) { discard; @@ -190,12 +175,13 @@ void main() lv = proj_origin-pos.xyz; lv = normalize(lv); float da = dot(norm, lv); - + vec3 col = vec3(0,0,0); - - vec3 diff_tex = texture2DRect(diffuseRect, frag.xy).rgb; - - float noise = texture2D(noiseMap, frag.xy/128.0).b; + + vec3 diff_tex = texture2D(diffuseRect, frag.xy).rgb; + vec3 dlit = vec3(0, 0, 0); + + float noise = texture2D(noiseMap, frag.xy*noise_scale).b; if (proj_tc.z > 0.0 && proj_tc.x < 1.0 && proj_tc.y < 1.0 && @@ -207,34 +193,60 @@ void main() if (da > 0.0) { + lit = da * dist_atten * noise; + float diff = clamp((l_dist-proj_focus)/proj_range, 0.0, 1.0); float lod = diff * proj_lod; - + vec4 plcol = texture2DLodDiffuse(projectionMap, proj_tc.xy, lod); - - vec3 lcol = color.rgb * plcol.rgb * plcol.a; - - lit = da * dist_atten * noise; - - col = lcol*lit*diff_tex*shadow; + + dlit = color.rgb * plcol.rgb * plcol.a; + + col = dlit*lit*diff_tex*shadow; amb_da += (da*0.5)*(1.0-shadow)*proj_ambiance; } - + //float diff = clamp((proj_range-proj_focus)/proj_range, 0.0, 1.0); vec4 amb_plcol = texture2DLodAmbient(projectionMap, proj_tc.xy, proj_lod); - + amb_da += (da*da*0.5+0.5)*proj_ambiance; - + amb_da *= dist_atten * noise; - + amb_da = min(amb_da, 1.0-lit); - - col += amb_da*color.rgb*diff_tex.rgb*amb_plcol.rgb*amb_plcol.a; + + col += amb_da*color*diff_tex*amb_plcol.rgb*amb_plcol.a; } - - - vec4 spec = texture2DRect(specularRect, frag.xy); + + + vec4 spec = texture2D(specularRect, frag.xy); + if (spec.a > 0.0) + { + dlit *= min(da*6.0, 1.0) * dist_atten; + + vec3 npos = -normalize(pos); + + //vec3 ref = dot(pos+lv, norm); + vec3 h = normalize(lv+npos); + float nh = dot(norm, h); + float nv = dot(norm, npos); + float vh = dot(npos, h); + float sa = nh; + float fres = pow(1 - dot(h, npos), 5)*0.4+0.5; + + float gtdenom = 2 * nh; + float gt = max(0, min(gtdenom * nv / vh, gtdenom * da / vh)); + + if (nh > 0.0) + { + float scol = fres*texture2D(lightFunc, vec2(nh, spec.a)).r*gt/(nh*da); + col += dlit*scol*spec.rgb*shadow; + //col += spec.rgb; + } + } + + if (envIntensity > 0.0) { vec3 ref = reflect(normalize(pos), norm); @@ -245,29 +257,27 @@ void main() if (ds < 0.0) { vec3 pfinal = pos + ref * dot(pdelta, proj_n)/ds; - + vec4 stc = (proj_mat * vec4(pfinal.xyz, 1.0)); if (stc.z > 0.0) { - stc.xy /= stc.w; + stc /= stc.w; - float fatten = clamp(spec.a*spec.a+spec.a*0.5, 0.25, 1.0); - - stc.xy = (stc.xy - vec2(0.5)) * fatten + vec2(0.5); - if (stc.x < 1.0 && stc.y < 1.0 && stc.x > 0.0 && stc.y > 0.0) { - vec4 scol = texture2DLodSpecular(projectionMap, stc.xy, proj_lod-spec.a*proj_lod); - col += dist_atten*scol.rgb*color.rgb*scol.a*spec.rgb*shadow; + col += color.rgb * texture2DLodSpecular(projectionMap, stc.xy, (1 - spec.a) * (proj_lod * 0.6)).rgb * shadow * envIntensity; } } } } - + + //not sure why, but this line prevents MATBUG-194 + col = max(col, vec3(0.0)); + frag_color.rgb = col; frag_color.a = 0.0; } diff --git a/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl index d490b5d468..b9184655fc 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl @@ -23,7 +23,7 @@ * $/LicenseInfo$ */ -#extension GL_ARB_texture_rectangle : enable + #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_color; @@ -31,14 +31,13 @@ out vec4 frag_color; #define frag_color gl_FragColor #endif -uniform sampler2DRect diffuseRect; -uniform sampler2DRect specularRect; -uniform sampler2DRect normalMap; -uniform sampler2DRect lightMap; -uniform sampler2DRect depthMap; +uniform sampler2D diffuseRect; +uniform sampler2D specularRect; +uniform sampler2D normalMap; +uniform sampler2D lightMap; +uniform sampler2D depthMap; uniform samplerCube environmentMap; uniform sampler2D lightFunc; -uniform vec3 gi_quad; uniform float blur_size; uniform float blur_fidelity; @@ -60,16 +59,13 @@ uniform float density_multiplier; uniform float distance_multiplier; uniform float max_y; uniform vec4 glow; +uniform float global_gamma; uniform float scene_light_strength; uniform mat3 env_mat; uniform vec4 shadow_clip; uniform float ssao_effect; -uniform mat4 inv_proj; -uniform vec2 screen_res; - uniform vec3 sun_dir; - VARYING vec2 vary_fragcoord; vec3 vary_PositionEye; @@ -79,17 +75,15 @@ vec3 vary_AmblitColor; vec3 vary_AdditiveColor; vec3 vary_AtmosAttenuation; -float luminance(vec3 color) -{ - /// CALCULATING LUMINANCE (Using NTSC lum weights) - /// http://en.wikipedia.org/wiki/Luma_%28video%29 - return dot(color, vec3(0.299, 0.587, 0.114)); -} +uniform mat4 inv_proj; + +vec3 decode_normal(vec2 enc); +vec3 srgb_to_linear(vec3 cs); +vec3 linear_to_srgb(vec3 cl); vec4 getPosition_d(vec2 pos_screen, float depth) { vec2 sc = pos_screen.xy*2.0; - sc /= screen_res; sc -= vec2(1.0,1.0); vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0); vec4 pos = inv_proj * ndc; @@ -98,12 +92,6 @@ vec4 getPosition_d(vec2 pos_screen, float depth) return pos; } -vec4 getPosition(vec2 pos_screen) -{ //get position in screen space (world units) given window coordinate and depth map - float depth = texture2DRect(depthMap, pos_screen.xy).r; - return getPosition_d(pos_screen, depth); -} - vec3 getPositionEye() { return vary_PositionEye; @@ -125,7 +113,6 @@ vec3 getAtmosAttenuation() return vary_AtmosAttenuation; } - void setPositionEye(vec3 v) { vary_PositionEye = v; @@ -151,6 +138,52 @@ void setAtmosAttenuation(vec3 v) vary_AtmosAttenuation = v; } +#ifdef WATER_FOG +uniform vec4 waterPlane; +uniform vec4 waterFogColor; +uniform float waterFogDensity; +uniform float waterFogKS; + +vec4 applyWaterFogDeferred(vec3 pos, vec4 color) +{ + //normalize view vector + vec3 view = normalize(pos); + float es = -(dot(view, waterPlane.xyz)); + + //find intersection point with water plane and eye vector + + //get eye depth + float e0 = max(-waterPlane.w, 0.0); + + vec3 int_v = waterPlane.w > 0.0 ? view * waterPlane.w/es : vec3(0.0, 0.0, 0.0); + + //get object depth + float depth = length(pos - int_v); + + //get "thickness" of water + float l = max(depth, 0.1); + + float kd = waterFogDensity; + float ks = waterFogKS; + vec4 kc = waterFogColor; + + float F = 0.98; + + float t1 = -kd * pow(F, ks * e0); + float t2 = kd + ks * es; + float t3 = pow(F, t2*l) - 1.0; + + float L = min(t1/t2*t3, 1.0); + + float D = pow(0.98, l*kd); + + color.rgb = color.rgb * D + kc.rgb * L; + color.a = kc.a + color.a; + + return color; +} +#endif + void calcAtmospherics(vec3 inPositionEye, float ambFactor) { vec3 P = inPositionEye; @@ -211,7 +244,7 @@ void calcAtmospherics(vec3 inPositionEye, float ambFactor) { //increase ambient when there are more clouds vec4 tmpAmbient = ambient + (vec4(1.) - ambient) * cloud_shadow * 0.5; - + //haze color setAdditiveColor( vec3(blue_horizon * blue_weight * (sunlight*(1.-cloud_shadow) + tmpAmbient) @@ -220,8 +253,12 @@ void calcAtmospherics(vec3 inPositionEye, float ambFactor) { // decrease ambient value for occluded areas tmpAmbient *= mix(ssao_effect, 1.0, ambFactor); - + //brightness of surface both sunlight and ambient + /*setSunlitColor(pow(vec3(sunlight * .5), vec3(global_gamma)) * global_gamma); + setAmblitColor(pow(vec3(tmpAmbient * .25), vec3(global_gamma)) * global_gamma); + setAdditiveColor(pow(getAdditiveColor() * vec3(1.0 - temp1), vec3(global_gamma)) * global_gamma);*/ + setSunlitColor(vec3(sunlight * .5)); setAmblitColor(vec3(tmpAmbient * .25)); setAdditiveColor(getAdditiveColor() * vec3(1.0 - temp1)); @@ -239,6 +276,15 @@ vec3 atmosTransport(vec3 light) { light += getAdditiveColor() * 2.0; return light; } + +vec3 fullbrightAtmosTransport(vec3 light) { + float brightness = dot(light.rgb, vec3(0.33333)); + + return mix(atmosTransport(light.rgb), light.rgb + getAdditiveColor().rgb, brightness * brightness); +} + + + vec3 atmosGetDiffuseSunlightColor() { return getSunlitColor(); @@ -273,80 +319,126 @@ vec3 scaleSoftClip(vec3 light) return light; } -vec3 unpack(vec2 tc) + +vec3 fullbrightScaleSoftClip(vec3 light) { -//#define PACK_NORMALS -#ifdef PACK_NORMALS - vec2 enc = texture2DRect(normalMap, tc).xy; - enc = enc*4.0-2.0; - float prod = dot(enc,enc); - return vec3(enc*sqrt(1.0-prod*.25),1.0-prod*.5); -#else - vec3 norm = texture2DRect(normalMap, tc).xyz; - return norm*2.0-1.0; -#endif + //soft clip effect: + return light; +} + +float luminance(vec3 color) +{ + /// CALCULATING LUMINANCE (Using NTSC lum weights) + /// http://en.wikipedia.org/wiki/Luma_%28video%29 + return dot(color, vec3(0.299, 0.587, 0.114)); } void main() { vec2 tc = vary_fragcoord.xy; - float depth = texture2DRect(depthMap, tc.xy).r; + float depth = texture2D(depthMap, tc.xy).r; vec3 pos = getPosition_d(tc, depth).xyz; - vec3 norm = unpack(tc); // unpack norm + vec4 norm = texture2D(normalMap, tc); + float envIntensity = norm.z; + norm.xyz = decode_normal(norm.xy); // unpack norm - float da = max(dot(norm.xyz, sun_dir.xyz), 0.0); - - vec4 diffuse = texture2DRect(diffuseRect, tc); - vec4 spec = texture2DRect(specularRect, vary_fragcoord.xy); + vec4 diffuse = texture2D(diffuseRect, tc); + //convert to gamma space + diffuse.rgb = linear_to_srgb(diffuse.rgb); + vec3 col; float bloom = 0.0; - - if (diffuse.a < 0.9) { - vec2 scol_ambocc = texture2DRect(lightMap, vary_fragcoord.xy).rg; + vec4 spec = texture2D(specularRect, vary_fragcoord.xy); + bloom = spec.r*norm.w; + + if (norm.w < 0.5) + { + + float da = max(dot(norm.xyz, sun_dir.xyz), 0.0); + + float light_gamma = 1.0/1.3; + da = pow(da, light_gamma); + + vec2 scol_ambocc = texture2D(lightMap, vary_fragcoord.xy).rg; + scol_ambocc = pow(scol_ambocc, vec2(light_gamma)); + float scol = max(scol_ambocc.r, diffuse.a); + + + float ambocc = scol_ambocc.g; calcAtmospherics(pos.xyz, ambocc); col = atmosAmbient(vec3(0)); - col += atmosAffectDirectionalLight(max(min(da, scol), diffuse.a)); + float ambient = min(abs(dot(norm.xyz, sun_dir.xyz)), 1.0); + ambient *= 0.5; + ambient *= ambient; + ambient = (1.0-ambient); + + col.rgb *= ambient; + + col += atmosAffectDirectionalLight(max(min(da, scol), 0.0)); col *= diffuse.rgb; + vec3 refnormpersp = normalize(reflect(pos.xyz, norm.xyz)); + if (spec.a > 0.0) // specular reflection { // the old infinite-sky shiny reflection // - vec3 refnormpersp = normalize(reflect(pos.xyz, norm.xyz)); + float sa = dot(refnormpersp, sun_dir.xyz); - vec3 dumbshiny = vary_SunlitColor*scol_ambocc.r*(6 * texture2D(lightFunc, vec2(sa, spec.a)).r); - + vec3 dumbshiny = vary_SunlitColor*scol_ambocc.r*(texture2D(lightFunc, vec2(sa, spec.a)).r); + // add the two types of shiny together vec3 spec_contrib = dumbshiny * spec.rgb; - bloom = dot(spec_contrib, spec_contrib) / 4; + bloom = dot(spec_contrib, spec_contrib) / 6; col += spec_contrib; + + } + + + col = mix(col, diffuse.rgb, diffuse.a); - //add environmentmap + if (envIntensity > 0.0) + { //add environmentmap vec3 env_vec = env_mat * refnormpersp; - vec3 env = textureCube(environmentMap, env_vec).rgb; - bloom = (luminance(env) - .45)*.25; - col = mix(col.rgb, env, - max(spec.a-diffuse.a*2.0, 0.0)); - } - col = atmosLighting(col); - col = scaleSoftClip(col); + vec3 refcol = textureCube(environmentMap, env_vec).rgb; //Perhaps mix with a cubemap without sun, in the future. + bloom = (luminance(refcol) - .45)*.25*scol_ambocc.r; + col = mix(col.rgb, refcol, + envIntensity); - col = mix(col, diffuse.rgb, diffuse.a); - } - else - { - bloom = spec.r; - col = diffuse.rgb; + } + + //if (norm.w < 0.5) + { + col = mix(atmosLighting(col), fullbrightAtmosTransport(col), diffuse.a); + col = mix(scaleSoftClip(col), fullbrightScaleSoftClip(col), diffuse.a); + //bloom += (luminance(col))*.075; //This looks nice, but requires a larger glow rendertarget. + } + + #ifdef WATER_FOG + vec4 fogged = applyWaterFogDeferred(pos,vec4(col, bloom)); + col = fogged.rgb; + bloom = fogged.a; + #endif + } + else + { + col = diffuse.rgb; + } + + col = srgb_to_linear(col); + + //col = vec3(1,0,1); + //col.g = envIntensity; } - + frag_color.rgb = col; frag_color.a = bloom; } diff --git a/indra/newview/app_settings/shaders/class2/deferred/softenLightV.glsl b/indra/newview/app_settings/shaders/class2/deferred/softenLightV.glsl deleted file mode 100644 index c840d72784..0000000000 --- a/indra/newview/app_settings/shaders/class2/deferred/softenLightV.glsl +++ /dev/null @@ -1,42 +0,0 @@ -/** - * @file softenLightF.glsl - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2007, 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$ - */ - -uniform mat4 modelview_projection_matrix; - -ATTRIBUTE vec3 position; - -uniform vec2 screen_res; - -VARYING vec2 vary_fragcoord; - -void main() -{ - //transform vertex - vec4 pos = modelview_projection_matrix * vec4(position.xyz, 1.0); - gl_Position = pos; - - - vary_fragcoord = (pos.xy*0.5+0.5)*screen_res; -} diff --git a/indra/newview/app_settings/shaders/class2/deferred/spotLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/spotLightF.glsl index 3a556e9131..add148bd02 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/spotLightF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/spotLightF.glsl @@ -22,8 +22,6 @@ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ - -#extension GL_ARB_texture_rectangle : enable #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_color; @@ -31,14 +29,14 @@ out vec4 frag_color; #define frag_color gl_FragColor #endif -uniform sampler2DRect diffuseRect; -uniform sampler2DRect specularRect; -uniform sampler2DRect depthMap; -uniform sampler2DRect normalMap; +uniform sampler2D diffuseRect; +uniform sampler2D specularRect; +uniform sampler2D depthMap; +uniform sampler2D normalMap; uniform samplerCube environmentMap; -uniform sampler2DRect lightMap; uniform sampler2D noiseMap; uniform sampler2D projectionMap; +uniform sampler2D lightFunc; uniform mat4 proj_mat; //screen space to light space uniform float proj_near; //near clip for projection @@ -54,30 +52,37 @@ uniform float far_clip; uniform vec3 proj_origin; //origin of projection to be used for angular attenuation uniform float sun_wash; + +// Shadow +uniform sampler2D lightMap; uniform int proj_shadow_idx; uniform float shadow_fade; -uniform float size; uniform vec3 color; uniform float falloff; +uniform float size; VARYING vec3 trans_center; VARYING vec4 vary_fragcoord; -uniform vec2 screen_res; uniform mat4 inv_proj; +uniform vec2 noise_scale; + +vec3 decode_normal(vec2 enc); +vec4 getPosition(vec2 pos_screen); +vec4 srgb_to_linear(vec4 cs); vec4 texture2DLodSpecular(sampler2D projectionMap, vec2 tc, float lod) { vec4 ret = texture2DLod(projectionMap, tc, lod); - vec2 dist = tc-vec2(0.5); - - float det = max(1.0-lod/(proj_lod*0.5), 0.0); - - float d = dot(dist,dist); - - ret *= min(clamp((0.25-d)/0.25, 0.0, 1.0)+det, 1.0); + ret = srgb_to_linear(ret); + vec2 dist = vec2(0.5) - abs(tc-vec2(0.5)); + float det = min(lod/(proj_lod*0.5), 1.0); + float d = min(dist.x, dist.y); + d *= min(1, d * (proj_lod - lod)); + float edge = 0.25*det; + ret *= clamp(d/edge, 0.0, 1.0); return ret; } @@ -85,7 +90,8 @@ vec4 texture2DLodSpecular(sampler2D projectionMap, vec2 tc, float lod) vec4 texture2DLodDiffuse(sampler2D projectionMap, vec2 tc, float lod) { vec4 ret = texture2DLod(projectionMap, tc, lod); - + ret = srgb_to_linear(ret); + vec2 dist = vec2(0.5) - abs(tc-vec2(0.5)); float det = min(lod/(proj_lod*0.5), 1.0); @@ -102,6 +108,7 @@ vec4 texture2DLodDiffuse(sampler2D projectionMap, vec2 tc, float lod) vec4 texture2DLodAmbient(sampler2D projectionMap, vec2 tc, float lod) { vec4 ret = texture2DLod(projectionMap, tc, lod); + ret = srgb_to_linear(ret); vec2 dist = tc-vec2(0.5); @@ -112,64 +119,39 @@ vec4 texture2DLodAmbient(sampler2D projectionMap, vec2 tc, float lod) return ret; } - -vec4 getPosition(vec2 pos_screen) -{ - float depth = texture2DRect(depthMap, pos_screen.xy).r; - vec2 sc = pos_screen.xy*2.0; - sc /= screen_res; - sc -= vec2(1.0,1.0); - vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0); - vec4 pos = inv_proj * ndc; - pos /= pos.w; - pos.w = 1.0; - return pos; -} - -vec3 unpack(vec2 tc) -{ -//#define PACK_NORMALS -#ifdef PACK_NORMALS - vec2 enc = texture2DRect(normalMap, tc).xy; - enc = enc*4.0-2.0; - float prod = dot(enc,enc); - return vec3(enc*sqrt(1.0-prod*.25),1.0-prod*.5); -#else - vec3 norm = texture2DRect(normalMap, tc).xyz; - return norm*2.0-1.0; -#endif -} - void main() { vec4 frag = vary_fragcoord; frag.xyz /= frag.w; frag.xyz = frag.xyz*0.5+0.5; - frag.xy *= screen_res; vec3 pos = getPosition(frag.xy).xyz; vec3 lv = trans_center.xyz-pos.xyz; - float dist2 = dot(lv,lv); - dist2 /= size; - if (dist2 > 1.0) + float dist = length(lv); + dist /= size; + if (dist > 1.0) { discard; } - + float shadow = 1.0; if (proj_shadow_idx >= 0) { - vec4 shd = texture2DRect(lightMap, frag.xy); + vec4 shd = texture2D(lightMap, frag.xy); float sh[2]; sh[0] = shd.b; sh[1] = shd.a; shadow = min(sh[proj_shadow_idx]+shadow_fade, 1.0); } + + vec3 norm = texture2D(normalMap, frag.xy).xyz; + + float envIntensity = norm.z; + + norm = decode_normal(norm.xy); - vec3 norm = unpack(frag.xy); // unpack norm - - //norm = normalize(norm); // may be superfluous + norm = normalize(norm); float l_dist = -dot(lv, proj_n); vec4 proj_tc = (proj_mat * vec4(pos.xyz, 1.0)); @@ -181,7 +163,10 @@ void main() proj_tc.xyz /= proj_tc.w; float fa = falloff+1.0; - float dist_atten = min(1.0-(dist2-1.0*(1.0-fa))/fa, 1.0); + float dist_atten = min(1.0-(dist-1.0*(1.0-fa))/fa, 1.0); + dist_atten *= dist_atten; + dist_atten *= 2.0; + if (dist_atten <= 0.0) { discard; @@ -190,12 +175,13 @@ void main() lv = proj_origin-pos.xyz; lv = normalize(lv); float da = dot(norm, lv); - + vec3 col = vec3(0,0,0); - - vec3 diff_tex = texture2DRect(diffuseRect, frag.xy).rgb; - - float noise = texture2D(noiseMap, frag.xy/128.0).b; + + vec3 diff_tex = texture2D(diffuseRect, frag.xy).rgb; + vec3 dlit = vec3(0, 0, 0); + + float noise = texture2D(noiseMap, frag.xy*noise_scale).b; if (proj_tc.z > 0.0 && proj_tc.x < 1.0 && proj_tc.y < 1.0 && @@ -207,34 +193,60 @@ void main() if (da > 0.0) { + lit = da * dist_atten * noise; + float diff = clamp((l_dist-proj_focus)/proj_range, 0.0, 1.0); float lod = diff * proj_lod; - + vec4 plcol = texture2DLodDiffuse(projectionMap, proj_tc.xy, lod); - - vec3 lcol = color.rgb * plcol.rgb * plcol.a; - - lit = da * dist_atten * noise; - - col = lcol*lit*diff_tex*shadow; + + dlit = color.rgb * plcol.rgb * plcol.a; + + col = dlit*lit*diff_tex*shadow; amb_da += (da*0.5)*(1.0-shadow)*proj_ambiance; } - + //float diff = clamp((proj_range-proj_focus)/proj_range, 0.0, 1.0); vec4 amb_plcol = texture2DLodAmbient(projectionMap, proj_tc.xy, proj_lod); - + amb_da += (da*da*0.5+0.5)*proj_ambiance; - + amb_da *= dist_atten * noise; - + amb_da = min(amb_da, 1.0-lit); - - col += amb_da*color.rgb*diff_tex.rgb*amb_plcol.rgb*amb_plcol.a; + + col += amb_da*color*diff_tex*amb_plcol.rgb*amb_plcol.a; } - - - vec4 spec = texture2DRect(specularRect, frag.xy); + + + vec4 spec = texture2D(specularRect, frag.xy); + if (spec.a > 0.0) + { + dlit *= min(da*6.0, 1.0) * dist_atten; + + vec3 npos = -normalize(pos); + + //vec3 ref = dot(pos+lv, norm); + vec3 h = normalize(lv+npos); + float nh = dot(norm, h); + float nv = dot(norm, npos); + float vh = dot(npos, h); + float sa = nh; + float fres = pow(1 - dot(h, npos), 5)*0.4+0.5; + + float gtdenom = 2 * nh; + float gt = max(0, min(gtdenom * nv / vh, gtdenom * da / vh)); + + if (nh > 0.0) + { + float scol = fres*texture2D(lightFunc, vec2(nh, spec.a)).r*gt/(nh*da); + col += dlit*scol*spec.rgb*shadow; + //col += spec.rgb; + } + } + + if (envIntensity > 0.0) { vec3 ref = reflect(normalize(pos), norm); @@ -245,29 +257,27 @@ void main() if (ds < 0.0) { vec3 pfinal = pos + ref * dot(pdelta, proj_n)/ds; - + vec4 stc = (proj_mat * vec4(pfinal.xyz, 1.0)); if (stc.z > 0.0) { - stc.xy /= stc.w; + stc /= stc.w; - float fatten = clamp(spec.a*spec.a+spec.a*0.5, 0.25, 1.0); - - stc.xy = (stc.xy - vec2(0.5)) * fatten + vec2(0.5); - if (stc.x < 1.0 && stc.y < 1.0 && stc.x > 0.0 && stc.y > 0.0) { - vec4 scol = texture2DLodSpecular(projectionMap, stc.xy, proj_lod-spec.a*proj_lod); - col += dist_atten*scol.rgb*color.rgb*scol.a*spec.rgb*shadow; + col += color.rgb * texture2DLodSpecular(projectionMap, stc.xy, (1 - spec.a) * (proj_lod * 0.6)).rgb * shadow * envIntensity; } } } } - + + //not sure why, but this line prevents MATBUG-194 + col = max(col, vec3(0.0)); + frag_color.rgb = col; frag_color.a = 0.0; } diff --git a/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl index f8f57e5e71..becff8506a 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl @@ -23,7 +23,7 @@ * $/LicenseInfo$ */ -#extension GL_ARB_texture_rectangle : enable + #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_color; @@ -33,15 +33,15 @@ out vec4 frag_color; //class 2, shadows, no SSAO -uniform sampler2DRect depthMap; -uniform sampler2DRect normalMap; -uniform sampler2DRectShadow shadowMap0; -uniform sampler2DRectShadow shadowMap1; -uniform sampler2DRectShadow shadowMap2; -uniform sampler2DRectShadow shadowMap3; +uniform sampler2D depthMap; +uniform sampler2D normalMap; +uniform sampler2DShadow shadowMap0; +uniform sampler2DShadow shadowMap1; +uniform sampler2DShadow shadowMap2; +uniform sampler2DShadow shadowMap3; uniform sampler2DShadow shadowMap4; uniform sampler2DShadow shadowMap5; - +//uniform sampler2D noiseMap; //Random dither. // Inputs uniform mat4 shadow_matrix[6]; @@ -52,84 +52,53 @@ uniform float ssao_factor; uniform float ssao_factor_inv; VARYING vec2 vary_fragcoord; +uniform vec2 kern_scale; uniform mat4 inv_proj; -uniform vec2 screen_res; -uniform vec2 shadow_res; uniform vec2 proj_shadow_res; uniform vec3 sun_dir; +uniform vec2 shadow_res; uniform float shadow_bias; uniform float shadow_offset; uniform float spot_shadow_bias; uniform float spot_shadow_offset; -vec4 getPosition(vec2 pos_screen) -{ - float depth = texture2DRect(depthMap, pos_screen.xy).r; - vec2 sc = pos_screen.xy*2.0; - sc /= screen_res; - sc -= vec2(1.0,1.0); - vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0); - vec4 pos = inv_proj * ndc; - pos /= pos.w; - pos.w = 1.0; - return pos; -} +vec3 decode_normal(vec2 enc); +vec4 getPosition(vec2 pos_screen); -float pcfShadow(sampler2DRectShadow shadowMap, vec4 stc, float scl, vec2 pos_screen) +float calcShadow( sampler2DShadow shadowMap, vec4 stc, vec2 res, vec2 pos_screen ) { - stc.xyz /= stc.w; - stc.z += shadow_bias*scl; + //stc.x += (((texture2D(noiseMap, pos_screen/128.0).x)-.5)/shadow_res.x); //Random dither. - stc.x = floor(stc.x + fract(pos_screen.y*0.666666666)); // add some jitter to X sample pos according to Y to disguise the snapping going on here + vec2 off = vec2(1,1.5)/res; + stc.x = floor(stc.x*res.x + fract(pos_screen.y*(1.0/kern_scale.y)*0.5))*off.x; - float cs = shadow2DRect(shadowMap, stc.xyz).x; - float shadow = cs; - shadow += shadow2DRect(shadowMap, stc.xyz+vec3(2.0, 1.5, 0.0)).x; - shadow += shadow2DRect(shadowMap, stc.xyz+vec3(1.0, -1.5, 0.0)).x; - shadow += shadow2DRect(shadowMap, stc.xyz+vec3(-2.0, 1.5, 0.0)).x; - shadow += shadow2DRect(shadowMap, stc.xyz+vec3(-1.0, -1.5, 0.0)).x; - - return shadow*0.2; + float shadow = shadow2D(shadowMap, stc.xyz).x; // cs + shadow += shadow2D(shadowMap, stc.xyz+vec3(off.x*2.0, off.y, 0.0)).x; + shadow += shadow2D(shadowMap, stc.xyz+vec3(off.x, -off.y, 0.0)).x; + shadow += shadow2D(shadowMap, stc.xyz+vec3(-off.x*2.0, off.y, 0.0)).x; + shadow += shadow2D(shadowMap, stc.xyz+vec3(-off.x, -off.y, 0.0)).x; + + return shadow; } float pcfShadow(sampler2DShadow shadowMap, vec4 stc, float scl, vec2 pos_screen) { stc.xyz /= stc.w; - stc.z += spot_shadow_bias*scl; - stc.x = floor(proj_shadow_res.x * stc.x + fract(pos_screen.y*0.666666666)) / proj_shadow_res.x; // snap - - float cs = shadow2D(shadowMap, stc.xyz).x; - float shadow = cs; - - vec2 off = 1.0/proj_shadow_res; - off.y *= 1.5; - - shadow += shadow2D(shadowMap, stc.xyz+vec3(off.x*2.0, off.y, 0.0)).x; - shadow += shadow2D(shadowMap, stc.xyz+vec3(off.x, -off.y, 0.0)).x; - shadow += shadow2D(shadowMap, stc.xyz+vec3(-off.x, off.y, 0.0)).x; - shadow += shadow2D(shadowMap, stc.xyz+vec3(-off.x*2.0, -off.y, 0.0)).x; + stc.z += shadow_bias; - return shadow*0.2; + return calcShadow(shadowMap, stc, shadow_res, pos_screen)*0.2; } -vec4 unpack(vec2 tc) +float pcfSpotShadow(sampler2DShadow shadowMap, vec4 stc, float scl, vec2 pos_screen) { - vec4 norm = texture2DRect(normalMap, tc).xyzw; -//#define PACK_NORMALS -#ifdef PACK_NORMALS - norm.xy = (norm.xy*4.0)-2.0; - float prod = dot(norm.xy,norm.xy); - norm.xy *= sqrt(1.0-prod*.25); - norm.z = 1.0-prod*.5; -#else - norm.xyz = norm.xyz*2.0-1.0; -#endif - norm.w *= norm.z; - return norm; + stc.xyz /= stc.w; + stc.z += spot_shadow_bias*scl; + + return calcShadow(shadowMap, stc, proj_shadow_res, pos_screen)*0.2; } void main() @@ -140,10 +109,9 @@ void main() vec4 pos = getPosition(pos_screen); - vec4 nmap4 = unpack(pos_screen); // unpack norm - float displace = nmap4.w; - vec3 norm = nmap4.xyz; - + vec3 norm = texture2D(normalMap, pos_screen).xyz; + norm = decode_normal(norm.xy); // unpack norm + /*if (pos.z == 0.0) // do nothing for sky *FIX: REMOVE THIS IF/WHEN THE POSITION MAP IS BEING USED AS A STENCIL { frag_color = vec4(0.0); // doesn't matter @@ -153,7 +121,7 @@ void main() float shadow = 0.0; float dp_directional_light = max(0.0, dot(norm, sun_dir.xyz)); - vec3 shadow_pos = pos.xyz + displace*norm; + vec3 shadow_pos = pos.xyz; vec3 offset = sun_dir.xyz * (1.0-dp_directional_light); vec4 spos = vec4(shadow_pos+offset*shadow_offset, 1.0); @@ -177,8 +145,7 @@ void main() if (spos.z < near_split.z) { lpos = shadow_matrix[3]*spos; - lpos.xy *= shadow_res; - + float w = 1.0; w -= max(spos.z-far_split.z, 0.0)/transition_domain.z; shadow += pcfShadow(shadowMap3, lpos, 0.25, pos_screen)*w; @@ -189,8 +156,7 @@ void main() if (spos.z < near_split.y && spos.z > far_split.z) { lpos = shadow_matrix[2]*spos; - lpos.xy *= shadow_res; - + float w = 1.0; w -= max(spos.z-far_split.y, 0.0)/transition_domain.y; w -= max(near_split.z-spos.z, 0.0)/transition_domain.z; @@ -201,7 +167,6 @@ void main() if (spos.z < near_split.x && spos.z > far_split.y) { lpos = shadow_matrix[1]*spos; - lpos.xy *= shadow_res; float w = 1.0; w -= max(spos.z-far_split.x, 0.0)/transition_domain.x; @@ -213,7 +178,6 @@ void main() if (spos.z > far_split.x) { lpos = shadow_matrix[0]*spos; - lpos.xy *= shadow_res; float w = 1.0; w -= max(near_split.x-spos.z, 0.0)/transition_domain.x; @@ -252,11 +216,11 @@ void main() //spotlight shadow 1 vec4 lpos = shadow_matrix[4]*spos; - frag_color[2] = pcfShadow(shadowMap4, lpos, 0.8, pos_screen); + frag_color[2] = pcfSpotShadow(shadowMap4, lpos, 0.8, pos_screen); //spotlight shadow 2 lpos = shadow_matrix[5]*spos; - frag_color[3] = pcfShadow(shadowMap5, lpos, 0.8, pos_screen); + frag_color[3] = pcfSpotShadow(shadowMap5, lpos, 0.8, pos_screen); //frag_color.rgb = pos.xyz; //frag_color.b = shadow; diff --git a/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl b/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl index ddcb024a9e..61519639fe 100644 --- a/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl +++ b/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl @@ -22,7 +22,7 @@ * $/LicenseInfo$ */ -#extension GL_ARB_texture_rectangle : enable + #ifdef DEFINE_GL_FRAGCOLOR out vec4 frag_color; @@ -32,160 +32,76 @@ out vec4 frag_color; //class 2 -- shadows and SSAO -uniform sampler2DRect depthMap; -uniform sampler2DRect normalMap; -uniform sampler2DRectShadow shadowMap0; -uniform sampler2DRectShadow shadowMap1; -uniform sampler2DRectShadow shadowMap2; -uniform sampler2DRectShadow shadowMap3; +uniform sampler2D diffuseRect; +uniform sampler2D depthMap; +uniform sampler2D normalMap; +uniform sampler2DShadow shadowMap0; +uniform sampler2DShadow shadowMap1; +uniform sampler2DShadow shadowMap2; +uniform sampler2DShadow shadowMap3; uniform sampler2DShadow shadowMap4; uniform sampler2DShadow shadowMap5; -uniform sampler2D noiseMap; +//uniform sampler2D noiseMap; // Inputs uniform mat4 shadow_matrix[6]; uniform vec4 shadow_clip; -uniform float ssao_radius; -uniform float ssao_max_radius; -uniform float ssao_factor; -uniform float ssao_factor_inv; VARYING vec2 vary_fragcoord; +uniform vec2 ssao_scale; +uniform vec2 kern_scale; + uniform mat4 inv_proj; -uniform vec2 screen_res; -uniform vec2 shadow_res; uniform vec2 proj_shadow_res; uniform vec3 sun_dir; +uniform vec2 shadow_res; + uniform float shadow_bias; uniform float shadow_offset; uniform float spot_shadow_bias; uniform float spot_shadow_offset; -vec4 getPosition(vec2 pos_screen) -{ - float depth = texture2DRect(depthMap, pos_screen.xy).r; - vec2 sc = pos_screen.xy*2.0; - sc /= screen_res; - sc -= vec2(1.0,1.0); - vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0); - vec4 pos = inv_proj * ndc; - pos /= pos.w; - pos.w = 1.0; - return pos; -} +vec3 decode_normal(vec2 enc); +vec4 getPosition(vec2 pos_screen); -vec2 getKern(int i) -{ - vec2 kern[8]; - // exponentially (^2) distant occlusion samples spread around origin - kern[0] = vec2(-1.0, 0.0) * 0.125*0.125; - kern[1] = vec2(1.0, 0.0) * 0.250*0.250; - kern[2] = vec2(0.0, 1.0) * 0.375*0.375; - kern[3] = vec2(0.0, -1.0) * 0.500*0.500; - kern[4] = vec2(0.7071, 0.7071) * 0.625*0.625; - kern[5] = vec2(-0.7071, -0.7071) * 0.750*0.750; - kern[6] = vec2(-0.7071, 0.7071) * 0.875*0.875; - kern[7] = vec2(0.7071, -0.7071) * 1.000*1.000; - - return kern[i]; -} -//calculate decreases in ambient lighting when crowded out (SSAO) -float calcAmbientOcclusion(vec4 pos, vec3 norm) +float calcShadow( sampler2DShadow shadowMap, vec4 stc, vec2 res, vec2 pos_screen ) { - vec2 pos_screen = vary_fragcoord.xy; - vec2 noise_reflect = texture2D(noiseMap, vary_fragcoord.xy/128.0).xy; - - // We treat the first sample as the origin, which definitely doesn't obscure itself thanks to being visible for sampling in the first place. - float points = 1.0; - float angle_hidden = 0.0; - - // use a kernel scale that diminishes with distance. - // a scale of less than 32 is just wasting good samples, though. - float scale = max(32.0, min(ssao_radius / -pos.z, ssao_max_radius)); - - // it was found that keeping # of samples a constant was the fastest, probably due to compiler optimizations (unrolling?) - for (int i = 0; i < 8; i++) - { - vec2 samppos_screen = pos_screen + scale * reflect(getKern(i), noise_reflect); - vec3 samppos_world = getPosition(samppos_screen).xyz; + //stc.x += (((texture2D(noiseMap, pos_screen/128.0).x)-.5)/shadow_res.x); //Random dither. - vec3 diff = samppos_world - pos.xyz; + vec2 off = vec2(1,1.5)/res; + stc.x = floor(stc.x*res.x + fract(pos_screen.y*(1.0/kern_scale.y)*0.5))*off.x; - if (diff.z < ssao_factor && diff.z != 0.0) - { - float dist = length(diff); - float angrel = max(0.0, dot(norm.xyz, diff/dist)); - float distrel = 1.0/(1.0+dist*dist); - float samplehidden = min(angrel, distrel); - - angle_hidden += (samplehidden); - points += 1.0; - } - } - - angle_hidden /= points; - float rtn = (1.0 - angle_hidden); - return (rtn * rtn); + + float shadow = shadow2D(shadowMap, stc.xyz).x; // cs + shadow += shadow2D(shadowMap, stc.xyz+vec3(off.x*2.0, off.y, 0.0)).x; + shadow += shadow2D(shadowMap, stc.xyz+vec3(off.x, -off.y, 0.0)).x; + shadow += shadow2D(shadowMap, stc.xyz+vec3(-off.x*2.0, off.y, 0.0)).x; + shadow += shadow2D(shadowMap, stc.xyz+vec3(-off.x, -off.y, 0.0)).x; + + return shadow; } -float pcfShadow(sampler2DRectShadow shadowMap, vec4 stc, float scl, vec2 pos_screen) +float pcfShadow(sampler2DShadow shadowMap, vec4 stc, float scl, vec2 pos_screen) { stc.xyz /= stc.w; - stc.z += shadow_bias*scl; + stc.z += shadow_bias; - stc.x = floor(stc.x + fract(pos_screen.y*0.666666666)); - - float cs = shadow2DRect(shadowMap, stc.xyz).x; - float shadow = cs; - - shadow += shadow2DRect(shadowMap, stc.xyz+vec3(2.0, 1.5, 0.0)).x; - shadow += shadow2DRect(shadowMap, stc.xyz+vec3(1.0, -1.5, 0.0)).x; - shadow += shadow2DRect(shadowMap, stc.xyz+vec3(-1.0, 1.5, 0.0)).x; - shadow += shadow2DRect(shadowMap, stc.xyz+vec3(-2.0, -1.5, 0.0)).x; - - return shadow*0.2; + return calcShadow(shadowMap, stc, shadow_res, pos_screen)*0.2; } -float pcfShadow(sampler2DShadow shadowMap, vec4 stc, float scl, vec2 pos_screen) +float pcfSpotShadow(sampler2DShadow shadowMap, vec4 stc, float scl, vec2 pos_screen) { stc.xyz /= stc.w; stc.z += spot_shadow_bias*scl; - stc.x = floor(proj_shadow_res.x * stc.x + fract(pos_screen.y*0.666666666)) / proj_shadow_res.x; // snap - - float cs = shadow2D(shadowMap, stc.xyz).x; - float shadow = cs; - - vec2 off = 1.0/proj_shadow_res; - off.y *= 1.5; - - shadow += shadow2D(shadowMap, stc.xyz+vec3(off.x*2.0, off.y, 0.0)).x; - shadow += shadow2D(shadowMap, stc.xyz+vec3(off.x, -off.y, 0.0)).x; - shadow += shadow2D(shadowMap, stc.xyz+vec3(-off.x, off.y, 0.0)).x; - shadow += shadow2D(shadowMap, stc.xyz+vec3(-off.x*2.0, -off.y, 0.0)).x; - return shadow*0.2; + return calcShadow(shadowMap, stc, proj_shadow_res, pos_screen)*0.2; } -vec4 unpack(vec2 tc) -{ - vec4 norm = texture2DRect(normalMap, tc).xyzw; -//#define PACK_NORMALS -#ifdef PACK_NORMALS - norm.xy = (norm.xy*4.0)-2.0; - float prod = dot(norm.xy,norm.xy); - norm.xy *= sqrt(1.0-prod*.25); - norm.z = 1.0-prod*.5; -#else - norm.xyz = norm.xyz*2.0-1.0; -#endif - norm.w *= norm.z; - return norm; -} void main() { @@ -195,10 +111,9 @@ void main() vec4 pos = getPosition(pos_screen); - vec4 nmap4 = unpack(pos_screen); // unpack norm - float displace = nmap4.w; - vec3 norm = nmap4.xyz; - + vec3 norm = texture2D(normalMap, pos_screen).xyz; + norm = decode_normal(norm.xy); // unpack norm + /*if (pos.z == 0.0) // do nothing for sky *FIX: REMOVE THIS IF/WHEN THE POSITION MAP IS BEING USED AS A STENCIL { frag_color = vec4(0.0); // doesn't matter @@ -207,8 +122,8 @@ void main() float shadow = 0.0; float dp_directional_light = max(0.0, dot(norm, sun_dir.xyz)); - - vec3 shadow_pos = pos.xyz + displace*norm; + + vec3 shadow_pos = pos.xyz; vec3 offset = sun_dir.xyz * (1.0-dp_directional_light); vec4 spos = vec4(shadow_pos+offset*shadow_offset, 1.0); @@ -232,8 +147,7 @@ void main() if (spos.z < near_split.z) { lpos = shadow_matrix[3]*spos; - lpos.xy *= shadow_res; - + float w = 1.0; w -= max(spos.z-far_split.z, 0.0)/transition_domain.z; shadow += pcfShadow(shadowMap3, lpos, 0.25, pos_screen)*w; @@ -244,8 +158,7 @@ void main() if (spos.z < near_split.y && spos.z > far_split.z) { lpos = shadow_matrix[2]*spos; - lpos.xy *= shadow_res; - + float w = 1.0; w -= max(spos.z-far_split.y, 0.0)/transition_domain.y; w -= max(near_split.z-spos.z, 0.0)/transition_domain.z; @@ -256,8 +169,7 @@ void main() if (spos.z < near_split.x && spos.z > far_split.y) { lpos = shadow_matrix[1]*spos; - lpos.xy *= shadow_res; - + float w = 1.0; w -= max(spos.z-far_split.x, 0.0)/transition_domain.x; w -= max(near_split.y-spos.z, 0.0)/transition_domain.y; @@ -268,8 +180,7 @@ void main() if (spos.z > far_split.x) { lpos = shadow_matrix[0]*spos; - lpos.xy *= shadow_res; - + float w = 1.0; w -= max(near_split.x-spos.z, 0.0)/transition_domain.x; @@ -301,17 +212,17 @@ void main() } frag_color[0] = shadow; - frag_color[1] = calcAmbientOcclusion(pos, norm); + frag_color[1] = texture2D(diffuseRect,vary_fragcoord.xy * ssao_scale).r; spos = vec4(shadow_pos+norm*spot_shadow_offset, 1.0); //spotlight shadow 1 vec4 lpos = shadow_matrix[4]*spos; - frag_color[2] = pcfShadow(shadowMap4, lpos, 0.8, pos_screen); + frag_color[2] = pcfSpotShadow(shadowMap4, lpos, 0.8, pos_screen); //spotlight shadow 2 lpos = shadow_matrix[5]*spos; - frag_color[3] = pcfShadow(shadowMap5, lpos, 0.8, pos_screen); + frag_color[3] = pcfSpotShadow(shadowMap5, lpos, 0.8, pos_screen); //frag_color.rgb = pos.xyz; //frag_color.b = shadow; diff --git a/indra/newview/app_settings/shaders/class2/deferred/sunLightV.glsl b/indra/newview/app_settings/shaders/class2/deferred/sunLightV.glsl deleted file mode 100644 index bc5eb5181d..0000000000 --- a/indra/newview/app_settings/shaders/class2/deferred/sunLightV.glsl +++ /dev/null @@ -1,41 +0,0 @@ -/** - * @file sunLightV.glsl - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2007, 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$ - */ - -uniform mat4 modelview_projection_matrix; - -ATTRIBUTE vec3 position; - -VARYING vec2 vary_fragcoord; - -uniform vec2 screen_res; - -void main() -{ - //transform vertex - vec4 pos = modelview_projection_matrix * vec4(position.xyz, 1.0); - gl_Position = pos; - - vary_fragcoord = (pos.xy * 0.5 + 0.5)*screen_res; -} diff --git a/indra/newview/app_settings/shaders/class2/lighting/sumLightsSpecularV.glsl b/indra/newview/app_settings/shaders/class2/lighting/sumLightsSpecularV.glsl index 3acf9fe883..d956a18f73 100644 --- a/indra/newview/app_settings/shaders/class2/lighting/sumLightsSpecularV.glsl +++ b/indra/newview/app_settings/shaders/class2/lighting/sumLightsSpecularV.glsl @@ -1,5 +1,5 @@ /** - * @file sumLightsV.glsl + * @file sumLightsSpecularV.glsl * * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code @@ -24,7 +24,6 @@ */ - float calcDirectionalLightSpecular(inout vec4 specular, vec3 view, vec3 n, vec3 l, vec3 lightCol, float da); vec3 calcPointLightSpecular(inout vec4 specular, vec3 view, vec3 v, vec3 n, vec3 l, float r, float pw, vec3 lightCol); @@ -47,9 +46,9 @@ vec4 sumLightsSpecular(vec3 pos, vec3 norm, vec4 color, inout vec4 specularColor vec4 specularSum = vec4(0.0); // Collect normal lights (need to be divided by two, as we later multiply by 2) - col.rgb += light_diffuse[1].rgb * calcDirectionalLightSpecular(specularColor, view, norm, light_position[1].xyz,light_diffuse[1].rgb, 1.0); + col.rgb += calcPointLightSpecular(specularSum, view, pos, norm, light_position[1].xyz, light_attenuation[1].x, light_attenuation[1].y, light_diffuse[1].rgb); col.rgb += calcPointLightSpecular(specularSum, view, pos, norm, light_position[2].xyz, light_attenuation[2].x, light_attenuation[2].y, light_diffuse[2].rgb); - col.rgb += calcPointLightSpecular(specularSum, view, pos, norm, light_position[3].xyz, light_attenuation[3].x, light_attenuation[3].y, light_diffuse[3].rgb); + col.rgb += calcPointLightSpecular(specularSum, view, pos, norm, light_position[3].xyz, light_attenuation[3].x, light_attenuation[3].y, light_diffuse[3].rgb); col.rgb = scaleDownLight(col.rgb); // Add windlight lights @@ -58,6 +57,7 @@ vec4 sumLightsSpecular(vec3 pos, vec3 norm, vec4 color, inout vec4 specularColor col.rgb = min(col.rgb*color.rgb, 1.0); specularColor.rgb = min(specularColor.rgb*specularSum.rgb, 1.0); + col.rgb += specularColor.rgb; return col; diff --git a/indra/newview/app_settings/shaders/class2/lighting/sumLightsV.glsl b/indra/newview/app_settings/shaders/class2/lighting/sumLightsV.glsl index c9987ef3b9..13af09c25a 100644 --- a/indra/newview/app_settings/shaders/class2/lighting/sumLightsV.glsl +++ b/indra/newview/app_settings/shaders/class2/lighting/sumLightsV.glsl @@ -23,6 +23,7 @@ * $/LicenseInfo$ */ + float calcDirectionalLight(vec3 n, vec3 l); float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float is_pointlight); @@ -30,29 +31,30 @@ vec3 atmosAmbient(vec3 light); vec3 atmosAffectDirectionalLight(float lightIntensity); vec3 scaleDownLight(vec3 light); + uniform vec4 light_position[8]; uniform vec3 light_direction[8]; -uniform vec3 light_attenuation[8]; +uniform vec3 light_attenuation[8]; uniform vec3 light_diffuse[8]; vec4 sumLights(vec3 pos, vec3 norm, vec4 color, vec4 baseLight) { vec4 col = vec4(0.0, 0.0, 0.0, color.a); - + // Collect normal lights (need to be divided by two, as we later multiply by 2) - col.rgb += light_diffuse[1].rgb * calcDirectionalLight(norm, light_position[1].xyz); + // Collect normal lights + col.rgb += light_diffuse[1].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[1], light_direction[1], light_attenuation[1].x, light_attenuation[1].z); col.rgb += light_diffuse[2].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[2], light_direction[2], light_attenuation[2].x, light_attenuation[2].z); col.rgb += light_diffuse[3].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[3], light_direction[3], light_attenuation[3].x, light_attenuation[3].z); - col.rgb = scaleDownLight(col.rgb); // Add windlight lights col.rgb += atmosAmbient(baseLight.rgb); col.rgb += atmosAffectDirectionalLight(calcDirectionalLight(norm, light_position[0].xyz)); - + col.rgb = min(col.rgb*color.rgb, 1.0); - - return col; + + return col; } diff --git a/indra/newview/app_settings/shaders/class3/lighting/sumLightsSpecularV.glsl b/indra/newview/app_settings/shaders/class3/lighting/sumLightsSpecularV.glsl index e043ac873e..66a127a59e 100644 --- a/indra/newview/app_settings/shaders/class3/lighting/sumLightsSpecularV.glsl +++ b/indra/newview/app_settings/shaders/class3/lighting/sumLightsSpecularV.glsl @@ -1,5 +1,5 @@ /** - * @file sumLightsV.glsl + * @file sumLightsSpecularV.glsl * * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code @@ -23,6 +23,7 @@ * $/LicenseInfo$ */ + float calcDirectionalLightSpecular(inout vec4 specular, vec3 view, vec3 n, vec3 l, vec3 lightCol, float da); vec3 calcPointLightSpecular(inout vec4 specular, vec3 view, vec3 v, vec3 n, vec3 l, float r, float pw, vec3 lightCol); @@ -45,7 +46,7 @@ vec4 sumLightsSpecular(vec3 pos, vec3 norm, vec4 color, inout vec4 specularColor vec4 specularSum = vec4(0.0); // Collect normal lights (need to be divided by two, as we later multiply by 2) - col.rgb += light_diffuse[1].rgb * calcDirectionalLightSpecular(specularColor, view, norm, light_position[1].xyz,light_diffuse[1].rgb, 1.0); + col.rgb += calcPointLightSpecular(specularSum, view, pos, norm, light_position[1].xyz, light_attenuation[1].x, light_attenuation[1].y, light_diffuse[1].rgb); col.rgb += calcPointLightSpecular(specularSum, view, pos, norm, light_position[2].xyz, light_attenuation[2].x, light_attenuation[2].y, light_diffuse[2].rgb); col.rgb += calcPointLightSpecular(specularSum, view, pos, norm, light_position[3].xyz, light_attenuation[3].x, light_attenuation[3].y, light_diffuse[3].rgb); col.rgb += calcPointLightSpecular(specularSum, view, pos, norm, light_position[4].xyz, light_attenuation[4].x, light_attenuation[4].y, light_diffuse[4].rgb); @@ -62,5 +63,6 @@ vec4 sumLightsSpecular(vec3 pos, vec3 norm, vec4 color, inout vec4 specularColor specularColor.rgb = min(specularColor.rgb*specularSum.rgb, 1.0); col.rgb += specularColor.rgb; + return col; } diff --git a/indra/newview/app_settings/shaders/class3/lighting/sumLightsV.glsl b/indra/newview/app_settings/shaders/class3/lighting/sumLightsV.glsl index dadff40933..f6f2ad574b 100644 --- a/indra/newview/app_settings/shaders/class3/lighting/sumLightsV.glsl +++ b/indra/newview/app_settings/shaders/class3/lighting/sumLightsV.glsl @@ -30,35 +30,35 @@ float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, floa vec3 atmosAmbient(vec3 light); vec3 atmosAffectDirectionalLight(float lightIntensity); vec3 scaleDownLight(vec3 light); -vec3 scaleUpLight(vec3 light); + uniform vec4 light_position[8]; uniform vec3 light_direction[8]; -uniform vec3 light_attenuation[8]; +uniform vec3 light_attenuation[8]; uniform vec3 light_diffuse[8]; vec4 sumLights(vec3 pos, vec3 norm, vec4 color, vec4 baseLight) { vec4 col = vec4(0.0, 0.0, 0.0, color.a); - + // Collect normal lights (need to be divided by two, as we later multiply by 2) - + // Collect normal lights + col.rgb += light_diffuse[1].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[1], light_direction[1], light_attenuation[1].x, light_attenuation[1].z); col.rgb += light_diffuse[2].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[2], light_direction[2], light_attenuation[2].x, light_attenuation[2].z); col.rgb += light_diffuse[3].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[3], light_direction[3], light_attenuation[3].x, light_attenuation[3].z); col.rgb += light_diffuse[4].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[4], light_direction[4], light_attenuation[4].x, light_attenuation[4].z); col.rgb += light_diffuse[5].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[5], light_direction[5], light_attenuation[5].x, light_attenuation[5].z); col.rgb += light_diffuse[6].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[6], light_direction[6], light_attenuation[6].x, light_attenuation[6].z); col.rgb += light_diffuse[7].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[7], light_direction[7], light_attenuation[7].x, light_attenuation[7].z); - col.rgb += light_diffuse[1].rgb*calcDirectionalLight(norm, light_position[1].xyz); col.rgb = scaleDownLight(col.rgb); // Add windlight lights - col.rgb += atmosAffectDirectionalLight(calcDirectionalLight(norm, light_position[0].xyz)); col.rgb += atmosAmbient(baseLight.rgb); + col.rgb += atmosAffectDirectionalLight(calcDirectionalLight(norm, light_position[0].xyz)); col.rgb = min(col.rgb*color.rgb, 1.0); - - return col; + + return col; } diff --git a/indra/newview/app_settings/ultra_graphics.xml b/indra/newview/app_settings/ultra_graphics.xml index 6181cbdc04..6734c6db0a 100644 --- a/indra/newview/app_settings/ultra_graphics.xml +++ b/indra/newview/app_settings/ultra_graphics.xml @@ -25,7 +25,7 @@ - + diff --git a/indra/newview/app_settings/windlight/clouds/Altocumulus.tga b/indra/newview/app_settings/windlight/clouds/Altocumulus.tga new file mode 100644 index 0000000000..675cb16091 Binary files /dev/null and b/indra/newview/app_settings/windlight/clouds/Altocumulus.tga differ diff --git a/indra/newview/app_settings/windlight/clouds/Cumulo-Nimbus.tga b/indra/newview/app_settings/windlight/clouds/Cumulo-Nimbus.tga new file mode 100644 index 0000000000..88d5582ebf Binary files /dev/null and b/indra/newview/app_settings/windlight/clouds/Cumulo-Nimbus.tga differ diff --git a/indra/newview/app_settings/windlight/clouds2.tga b/indra/newview/app_settings/windlight/clouds/Default.tga similarity index 100% rename from indra/newview/app_settings/windlight/clouds2.tga rename to indra/newview/app_settings/windlight/clouds/Default.tga diff --git a/indra/newview/app_settings/windlight/clouds/Layered.tga b/indra/newview/app_settings/windlight/clouds/Layered.tga new file mode 100644 index 0000000000..1321d23781 Binary files /dev/null and b/indra/newview/app_settings/windlight/clouds/Layered.tga differ diff --git a/indra/newview/app_settings/windlight/postprocesseffects.xml b/indra/newview/app_settings/windlight/postprocesseffects.xml index 5a498009cd..afabea4aa0 100644 --- a/indra/newview/app_settings/windlight/postprocesseffects.xml +++ b/indra/newview/app_settings/windlight/postprocesseffects.xml @@ -1,12 +1,13 @@ - - + Asi Weird bloom_strength 4.5799999237060547 bloom_width 12.539999961853027 + gamma + 1.0 brightness 0.89999997615814209 brightness_multiplier @@ -43,6 +44,8 @@ 1.5 bloom_width 2.25 + gamma + 1.0 brightness 1 brightness_multiplier @@ -145,7 +148,7 @@ saturation 1 - default + Default bloom_strength 1.5 @@ -174,12 +177,12 @@ 0 enable_gauss_blur 0 - enable_posterize - 0 - enable_motionblur - 0 - enable_vignette - 0 + enable_posterize + 0 + enable_motionblur + 0 + enable_vignette + 0 gauss_blur_passes 2 extract_high @@ -192,20 +195,1632 @@ 0.40000000000000002 saturation 1 - posterize_layers - 10 - blur_strength - 10 - vignette_strength - 0.85 - vignette_radius - 0.7 - vignette_darkness - 1.0 - vignette_desaturation - 1.0 - vignette_chromatic_aberration - 0.01 + posterize_layers + 10 + blur_strength + 10 + vignette_strength + 0.85 + vignette_radius + 0.7 + vignette_darkness + 1.0 + vignette_desaturation + 1.0 + vignette_chromatic_aberration + 0.01 + + PyFX CatVision v1 + + bloom_strength + 1.5 + bloom_width + 2.25 + blur_strength + 30 + brightness + 4 + brightness_multiplier + 3 + contrast + 3 + contrast_base + + 1 + 0 + 0.25 + 1 + + enable_bloom + 0 + enable_color_filter + 1 + enable_gauss_blur + 1 + enable_motionblur + 1 + enable_night_vision + 0 + enable_posterize + 0 + enable_vignette + 1 + extract_high + 1 + extract_low + 0.949999999999999955591079 + gamma + 2 + gauss_blur_passes + 1 + noise_size + 25 + noise_strength + 0.4000000000000000222044605 + posterize_layers + 10 + saturation + 0.0499999523162841796875 + vignette_chromatic_aberration + 0.1000000014901161193847656 + vignette_darkness + 1 + vignette_desaturation + 1 + vignette_radius + 3.9999997615814208984375 + vignette_strength + 1 + + PyFX CatVision v1 Dark + + bloom_strength + 1.5 + bloom_width + 2.25 + blur_strength + 30 + brightness + 2 + brightness_multiplier + 3 + contrast + 3 + contrast_base + + 1 + 0 + 0.25 + 1 + + enable_bloom + 0 + enable_color_filter + 1 + enable_gauss_blur + 1 + enable_motionblur + 1 + enable_night_vision + 0 + enable_posterize + 0 + enable_vignette + 1 + extract_high + 1 + extract_low + 0.949999999999999955591079 + gamma + 2.5 + gauss_blur_passes + 1 + noise_size + 25 + noise_strength + 0.4000000000000000222044605 + posterize_layers + 10 + saturation + 0.0499999523162841796875 + vignette_chromatic_aberration + 0.1000000014901161193847656 + vignette_darkness + 1 + vignette_desaturation + 1 + vignette_radius + 3.9999997615814208984375 + vignette_strength + 1 + + PyFX GrimDark v1 + + bloom_strength + 1.5 + bloom_width + 2.25 + blur_strength + 15 + brightness + 4 + brightness_multiplier + 1 + contrast + 1.25 + contrast_base + + 0.699999988079071044921875 + 0.7999999523162841796875 + 1 + 1 + + enable_bloom + 0 + enable_color_filter + 1 + enable_gauss_blur + 0 + enable_motionblur + 1 + enable_night_vision + 0 + enable_posterize + 0 + enable_vignette + 1 + extract_high + 1 + extract_low + 0.949999999999999955591079 + gamma + 1.25 + gauss_blur_passes + 2 + noise_size + 52.5 + noise_strength + 0.4000000000000000222044605 + posterize_layers + 10 + saturation + 0.5 + vignette_chromatic_aberration + 0.009500000625848770141601563 + vignette_darkness + 1 + vignette_desaturation + 0 + vignette_radius + 2 + vignette_strength + 1 + + PyFX GrimDark v2 + + bloom_strength + 1.5 + bloom_width + 2.25 + blur_strength + 30 + brightness + 4 + brightness_multiplier + 3 + contrast + 1 + contrast_base + + 1 + 1 + 1 + 1 + + enable_bloom + 0 + enable_color_filter + 1 + enable_gauss_blur + 0 + enable_motionblur + 1 + enable_night_vision + 0 + enable_posterize + 0 + enable_vignette + 1 + extract_high + 1 + extract_low + 0.949999999999999955591079 + gamma + 1 + gauss_blur_passes + 2 + noise_size + 25 + noise_strength + 0.4000000000000000222044605 + posterize_layers + 10 + saturation + 0.599999904632568359375 + vignette_chromatic_aberration + 0.009500000625848770141601563 + vignette_darkness + 1 + vignette_desaturation + 0.4000000059604644775390625 + vignette_radius + 2.9999997615814208984375 + vignette_strength + 1 + + PyFX Last Summer + + bloom_strength + 1.5 + bloom_width + 2.25 + blur_strength + 20 + brightness + 1.19999992847442626953125 + brightness_multiplier + 3 + contrast + 1.19999992847442626953125 + contrast_base + + 0.5 + 1 + 1 + 1 + + enable_bloom + 0 + enable_color_filter + 1 + enable_gauss_blur + 0 + enable_motionblur + 1 + enable_night_vision + 0 + enable_posterize + 0 + enable_vignette + 1 + extract_high + 1 + extract_low + 0.949999999999999955591079 + gamma + 2 + gauss_blur_passes + 2 + noise_size + 25 + noise_strength + 0.4000000000000000222044605 + posterize_layers + 10 + saturation + 1.6699998378753662109375 + vignette_chromatic_aberration + 0.001500000013038516044616699 + vignette_darkness + 0.25 + vignette_desaturation + 0 + vignette_radius + 7.999999523162841796875 + vignette_strength + 1 + + PyFX Last Winter + + bloom_strength + 1.5 + bloom_width + 2.25 + blur_strength + 20 + brightness + 1.19999992847442626953125 + brightness_multiplier + 3 + contrast + 1.19999992847442626953125 + contrast_base + + 1 + 0.75 + 0.5 + 1 + + enable_bloom + 0 + enable_color_filter + 1 + enable_gauss_blur + 0 + enable_motionblur + 1 + enable_night_vision + 0 + enable_posterize + 0 + enable_vignette + 1 + extract_high + 1 + extract_low + 0.949999999999999955591079 + gamma + 2 + gauss_blur_passes + 2 + noise_size + 25 + noise_strength + 0.4000000000000000222044605 + posterize_layers + 10 + saturation + 0.7999999523162841796875 + vignette_chromatic_aberration + 0.001500000013038516044616699 + vignette_darkness + 0.25 + vignette_desaturation + 0 + vignette_radius + 7.999999523162841796875 + vignette_strength + 1 + + PyFX Memory v1 + + bloom_strength + 1.5 + bloom_width + 2.25 + blur_strength + 30 + brightness + 1.5 + brightness_multiplier + 3 + contrast + 1.25 + contrast_base + + 0 + 0.66999995708465576171875 + 1 + 1 + + enable_bloom + 0 + enable_color_filter + 1 + enable_gauss_blur + 0 + enable_motionblur + 1 + enable_night_vision + 0 + enable_posterize + 0 + enable_vignette + 1 + extract_high + 1 + extract_low + 0.949999999999999955591079 + gamma + 1.5 + gauss_blur_passes + 2 + noise_size + 25 + noise_strength + 0.4000000000000000222044605 + posterize_layers + 10 + saturation + 0.5 + vignette_chromatic_aberration + 0.005000000353902578353881836 + vignette_darkness + 1 + vignette_desaturation + 0.4000000059604644775390625 + vignette_radius + 5 + vignette_strength + 1 + + PyFX Memory v1 Cold + + bloom_strength + 1.5 + bloom_width + 2.25 + blur_strength + 30 + brightness + 1.5 + brightness_multiplier + 3 + contrast + 1.25 + contrast_base + + 1 + 0.329999983310699462890625 + 0 + 1 + + enable_bloom + 0 + enable_color_filter + 1 + enable_gauss_blur + 0 + enable_motionblur + 1 + enable_night_vision + 0 + enable_posterize + 0 + enable_vignette + 1 + extract_high + 1 + extract_low + 0.949999999999999955591079 + gamma + 1.5 + gauss_blur_passes + 2 + noise_size + 25 + noise_strength + 0.4000000000000000222044605 + posterize_layers + 10 + saturation + 0.5 + vignette_chromatic_aberration + 0.005000000353902578353881836 + vignette_darkness + 1 + vignette_desaturation + 0.4000000059604644775390625 + vignette_radius + 5 + vignette_strength + 1 + + PyFX Memory v2 + + bloom_strength + 1.5 + bloom_width + 2.25 + blur_strength + 20 + brightness + 1 + brightness_multiplier + 3 + contrast + 1.2400000095367431640625 + contrast_base + + 0 + 0.62000000476837158203125 + 1 + 1 + + enable_bloom + 0 + enable_color_filter + 1 + enable_gauss_blur + 0 + enable_motionblur + 1 + enable_night_vision + 0 + enable_posterize + 0 + enable_vignette + 1 + extract_high + 1 + extract_low + 0.949999999999999955591079 + gamma + 2 + gauss_blur_passes + 2 + noise_size + 25 + noise_strength + 0.4000000000000000222044605 + posterize_layers + 10 + saturation + 1.3299999237060546875 + vignette_chromatic_aberration + 0.003000000026077032089233398 + vignette_darkness + 0.5 + vignette_desaturation + 0.5 + vignette_radius + 7.999999523162841796875 + vignette_strength + 1 + + PyFX Memory v2 Cold + + bloom_strength + 1.5 + bloom_width + 2.25 + blur_strength + 20 + brightness + 1 + brightness_multiplier + 3 + contrast + 1.2400000095367431640625 + contrast_base + + 1 + 0.319999992847442626953125 + 0 + 1 + + enable_bloom + 0 + enable_color_filter + 1 + enable_gauss_blur + 0 + enable_motionblur + 1 + enable_night_vision + 0 + enable_posterize + 0 + enable_vignette + 1 + extract_high + 1 + extract_low + 0.949999999999999955591079 + gamma + 2 + gauss_blur_passes + 2 + noise_size + 25 + noise_strength + 0.4000000000000000222044605 + posterize_layers + 10 + saturation + 1.3299999237060546875 + vignette_chromatic_aberration + 0.003000000026077032089233398 + vignette_darkness + 0.5 + vignette_desaturation + 0.5 + vignette_radius + 7.999999523162841796875 + vignette_strength + 1 + + PyFX Mono v1 + + bloom_strength + 1.5 + bloom_width + 2.25 + blur_strength + 30 + brightness + 1 + brightness_multiplier + 3 + contrast + 4 + contrast_base + + 1 + 1 + 1 + 0 + + enable_bloom + 0 + enable_color_filter + 1 + enable_gauss_blur + 0 + enable_motionblur + 1 + enable_night_vision + 0 + enable_posterize + 1 + enable_vignette + 1 + extract_high + 1 + extract_low + 0.949999999999999955591079 + gamma + 1 + gauss_blur_passes + 1 + noise_size + 25 + noise_strength + 0.4000000000000000222044605 + posterize_layers + 3 + saturation + 0 + vignette_chromatic_aberration + 0 + vignette_darkness + 1 + vignette_desaturation + 1 + vignette_radius + 1 + vignette_strength + 1 + + PyFX Neo v1 + + bloom_strength + 1.5 + bloom_width + 2.25 + blur_strength + 15 + brightness + 1.5 + brightness_multiplier + 1 + contrast + 1.25 + contrast_base + + 1 + 1 + 0.75 + 1 + + enable_bloom + 0 + enable_color_filter + 1 + enable_gauss_blur + 0 + enable_motionblur + 1 + enable_night_vision + 0 + enable_posterize + 0 + enable_vignette + 1 + extract_high + 1 + extract_low + 0.949999999999999955591079 + gamma + 1.25 + gauss_blur_passes + 2 + noise_size + 52.5 + noise_strength + 0.4000000000000000222044605 + posterize_layers + 10 + saturation + 0.849999904632568359375 + vignette_chromatic_aberration + 0.009500000625848770141601563 + vignette_darkness + 1 + vignette_desaturation + 0 + vignette_radius + 2 + vignette_strength + 1 + + PyFX Neo v1 Bright + + bloom_strength + 1.5 + bloom_width + 2.25 + blur_strength + 15 + brightness + 2.5 + brightness_multiplier + 1 + contrast + 1.25 + contrast_base + + 1 + 1 + 0.75 + 1 + + enable_bloom + 0 + enable_color_filter + 1 + enable_gauss_blur + 0 + enable_motionblur + 1 + enable_night_vision + 0 + enable_posterize + 0 + enable_vignette + 1 + extract_high + 1 + extract_low + 0.949999999999999955591079 + gamma + 1.25 + gauss_blur_passes + 2 + noise_size + 52.5 + noise_strength + 0.4000000000000000222044605 + posterize_layers + 10 + saturation + 0.849999904632568359375 + vignette_chromatic_aberration + 0.009500000625848770141601563 + vignette_darkness + 1 + vignette_desaturation + 0 + vignette_radius + 2 + vignette_strength + 1 + + PyFX Retrowave + + bloom_strength + 1.5 + bloom_width + 2.25 + blur_strength + 20 + brightness + 1 + brightness_multiplier + 3 + contrast + 1.2400000095367431640625 + contrast_base + + 0.2999999821186065673828125 + 1 + 0 + 1 + + enable_bloom + 0 + enable_color_filter + 1 + enable_gauss_blur + 0 + enable_motionblur + 1 + enable_night_vision + 0 + enable_posterize + 0 + enable_vignette + 1 + extract_high + 1 + extract_low + 0.949999999999999955591079 + gamma + 1.5 + gauss_blur_passes + 2 + noise_size + 25 + noise_strength + 0.4000000000000000222044605 + posterize_layers + 10 + saturation + 1.5 + vignette_chromatic_aberration + 0.003000000026077032089233398 + vignette_darkness + 0.5 + vignette_desaturation + 0 + vignette_radius + 7.999999523162841796875 + vignette_strength + 1 + + PyFX Twilight v1 Cold + + bloom_strength + 1.5 + bloom_width + 2.25 + blur_strength + 30 + brightness + 1.25 + brightness_multiplier + 3 + contrast + 1.0299999713897705078125 + contrast_base + + 1 + 0.329999983310699462890625 + 0 + 1 + + enable_bloom + 0 + enable_color_filter + 1 + enable_gauss_blur + 0 + enable_motionblur + 1 + enable_night_vision + 0 + enable_posterize + 0 + enable_vignette + 1 + extract_high + 1 + extract_low + 0.949999999999999955591079 + gamma + 1.5 + gauss_blur_passes + 2 + noise_size + 25 + noise_strength + 0.4000000000000000222044605 + posterize_layers + 10 + saturation + 0.5 + vignette_chromatic_aberration + 0.005000000353902578353881836 + vignette_darkness + 1 + vignette_desaturation + 0.4000000059604644775390625 + vignette_radius + 5 + vignette_strength + 1 + + PyFX Twilight v1 Warm + + bloom_strength + 1.5 + bloom_width + 2.25 + blur_strength + 30 + brightness + 1.25 + brightness_multiplier + 3 + contrast + 1.0299999713897705078125 + contrast_base + + 0 + 0.66999995708465576171875 + 1 + 1 + + enable_bloom + 0 + enable_color_filter + 1 + enable_gauss_blur + 0 + enable_motionblur + 1 + enable_night_vision + 0 + enable_posterize + 0 + enable_vignette + 1 + extract_high + 1 + extract_low + 0.949999999999999955591079 + gamma + 1.5 + gauss_blur_passes + 2 + noise_size + 25 + noise_strength + 0.4000000000000000222044605 + posterize_layers + 10 + saturation + 0.5 + vignette_chromatic_aberration + 0.005000000353902578353881836 + vignette_darkness + 1 + vignette_desaturation + 0.4000000059604644775390625 + vignette_radius + 5 + vignette_strength + 1 + + PyFX Underwater + + bloom_strength + 1.5 + bloom_width + 2.25 + blur_strength + 30 + brightness + 1.14999997615814208984375 + brightness_multiplier + 3 + contrast + 0.89999997615814208984375 + contrast_base + + 0 + 0.5 + 1 + 1 + + enable_bloom + 0 + enable_color_filter + 1 + enable_gauss_blur + 1 + enable_motionblur + 1 + enable_night_vision + 0 + enable_posterize + 0 + enable_vignette + 1 + extract_high + 1 + extract_low + 0.949999999999999955591079 + gamma + 0.75 + gauss_blur_passes + 1 + noise_size + 25 + noise_strength + 0.4000000000000000222044605 + posterize_layers + 10 + saturation + 0.75 + vignette_chromatic_aberration + 0.01000000070780515670776367 + vignette_darkness + 0.5 + vignette_desaturation + 0 + vignette_radius + 7.999999523162841796875 + vignette_strength + 1 + + PyFX Underwater Murky + + bloom_strength + 1.5 + bloom_width + 2.25 + blur_strength + 30 + brightness + 0.829999983310699462890625 + brightness_multiplier + 3 + contrast + 0.89999997615814208984375 + contrast_base + + 0.64999997615814208984375 + 1 + 0 + 1 + + enable_bloom + 0 + enable_color_filter + 1 + enable_gauss_blur + 1 + enable_motionblur + 1 + enable_night_vision + 0 + enable_posterize + 0 + enable_vignette + 1 + extract_high + 1 + extract_low + 0.949999999999999955591079 + gamma + 0.7999999523162841796875 + gauss_blur_passes + 2 + noise_size + 25 + noise_strength + 0.4000000000000000222044605 + posterize_layers + 10 + saturation + 0.3999998569488525390625 + vignette_chromatic_aberration + 0.01000000070780515670776367 + vignette_darkness + 0.5 + vignette_desaturation + 0 + vignette_radius + 7.999999523162841796875 + vignette_strength + 1 + + PyFX Vivid v1 + + bloom_strength + 1.5 + bloom_width + 2.25 + blur_strength + 30 + brightness + 1.19999992847442626953125 + brightness_multiplier + 3 + contrast + 1.25 + contrast_base + + 0.7999999523162841796875 + 0.89999997615814208984375 + 1 + 1 + + enable_bloom + 0 + enable_color_filter + 1 + enable_gauss_blur + 0 + enable_motionblur + 1 + enable_night_vision + 0 + enable_posterize + 0 + enable_vignette + 1 + extract_high + 1 + extract_low + 0.949999999999999955591079 + gamma + 2 + gauss_blur_passes + 2 + noise_size + 25 + noise_strength + 0.4000000000000000222044605 + posterize_layers + 10 + saturation + 1.19999980926513671875 + vignette_chromatic_aberration + 0.004500000271946191787719727 + vignette_darkness + 1 + vignette_desaturation + 0 + vignette_radius + 2.9999997615814208984375 + vignette_strength + 1 + + PyFX Vivid v1 Cold + + bloom_strength + 1.5 + bloom_width + 2.25 + blur_strength + 30 + brightness + 1.19999992847442626953125 + brightness_multiplier + 3 + contrast + 1.25 + contrast_base + + 1 + 0.89999997615814208984375 + 0.7999999523162841796875 + 1 + + enable_bloom + 0 + enable_color_filter + 1 + enable_gauss_blur + 0 + enable_motionblur + 1 + enable_night_vision + 0 + enable_posterize + 0 + enable_vignette + 1 + extract_high + 1 + extract_low + 0.949999999999999955591079 + gamma + 2 + gauss_blur_passes + 2 + noise_size + 25 + noise_strength + 0.4000000000000000222044605 + posterize_layers + 10 + saturation + 1.19999980926513671875 + vignette_chromatic_aberration + 0.004500000271946191787719727 + vignette_darkness + 1 + vignette_desaturation + 0 + vignette_radius + 2.9999997615814208984375 + vignette_strength + 1 + + PyFX Vivid v2 + + bloom_strength + 1.5 + bloom_width + 2.25 + blur_strength + 20 + brightness + 1 + brightness_multiplier + 3 + contrast + 1.5 + contrast_base + + 1 + 1 + 1 + 1 + + enable_bloom + 0 + enable_color_filter + 1 + enable_gauss_blur + 0 + enable_motionblur + 1 + enable_night_vision + 0 + enable_posterize + 0 + enable_vignette + 1 + extract_high + 1 + extract_low + 0.949999999999999955591079 + gamma + 3 + gauss_blur_passes + 2 + noise_size + 25 + noise_strength + 0.4000000000000000222044605 + posterize_layers + 10 + saturation + 1.5 + vignette_chromatic_aberration + 0.002000000094994902610778809 + vignette_darkness + 0.2999999821186065673828125 + vignette_desaturation + 0 + vignette_radius + 7.999999523162841796875 + vignette_strength + 1 + + PyFX Vivid v2 Bright + + bloom_strength + 1.5 + bloom_width + 2.25 + blur_strength + 15 + brightness + 1.25 + brightness_multiplier + 3 + contrast + 1.5 + contrast_base + + 1 + 1 + 1 + 1 + + enable_bloom + 0 + enable_color_filter + 1 + enable_gauss_blur + 0 + enable_motionblur + 1 + enable_night_vision + 0 + enable_posterize + 0 + enable_vignette + 1 + extract_high + 1 + extract_low + 0.949999999999999955591079 + gamma + 3 + gauss_blur_passes + 2 + noise_size + 25 + noise_strength + 0.4000000000000000222044605 + posterize_layers + 10 + saturation + 1.5 + vignette_chromatic_aberration + 0.01000000000000000020816682 + vignette_darkness + 1 + vignette_desaturation + 1 + vignette_radius + 1 + vignette_strength + 1 + + PyFX Vivid v2 Dark + + bloom_strength + 1.5 + bloom_width + 2.25 + blur_strength + 15 + brightness + 1 + brightness_multiplier + 3 + contrast + 1.5 + contrast_base + + 1 + 1 + 1 + 1 + + enable_bloom + 0 + enable_color_filter + 1 + enable_gauss_blur + 0 + enable_motionblur + 1 + enable_night_vision + 0 + enable_posterize + 0 + enable_vignette + 1 + extract_high + 1 + extract_low + 0.949999999999999955591079 + gamma + 3 + gauss_blur_passes + 2 + noise_size + 25 + noise_strength + 0.4000000000000000222044605 + posterize_layers + 10 + saturation + 1.5 + vignette_chromatic_aberration + 0.01000000000000000020816682 + vignette_darkness + 1 + vignette_desaturation + 1 + vignette_radius + 1 + vignette_strength + 1 + + PyFX v1 + + bloom_strength + 1.5 + bloom_width + 2.25 + blur_strength + 30 + brightness + 1.19999992847442626953125 + brightness_multiplier + 3 + contrast + 1.25 + contrast_base + + 0.7999999523162841796875 + 0.89999997615814208984375 + 1 + 1 + + enable_bloom + 0 + enable_color_filter + 1 + enable_gauss_blur + 0 + enable_motionblur + 1 + enable_night_vision + 0 + enable_posterize + 0 + enable_vignette + 1 + extract_high + 1 + extract_low + 0.949999999999999955591079 + gamma + 2 + gauss_blur_passes + 2 + noise_size + 25 + noise_strength + 0.4000000000000000222044605 + posterize_layers + 10 + saturation + 0.7999999523162841796875 + vignette_chromatic_aberration + 0.004500000271946191787719727 + vignette_darkness + 1 + vignette_desaturation + 0 + vignette_radius + 1.5 + vignette_strength + 1 + + PyFX v2 + + bloom_strength + 1.5 + bloom_width + 2.25 + blur_strength + 30 + brightness + 1 + brightness_multiplier + 3 + contrast + 2 + contrast_base + + 0.949999988079071044921875 + 0.969999969005584716796875 + 1 + 1 + + enable_bloom + 1 + enable_color_filter + 1 + enable_gauss_blur + 0 + enable_motionblur + 1 + enable_night_vision + 0 + enable_posterize + 0 + enable_vignette + 1 + extract_high + 1 + extract_low + 0.949999999999999955591079 + gamma + 5 + gauss_blur_passes + 2 + noise_size + 25 + noise_strength + 0.4000000000000000222044605 + posterize_layers + 10 + saturation + 1 + vignette_chromatic_aberration + 0.004500000271946191787719727 + vignette_darkness + 1 + vignette_desaturation + 0 + vignette_radius + 1.5 + vignette_strength + 1 + + PyFX v3 + + bloom_strength + 1.5 + bloom_width + 2.25 + blur_strength + 30 + brightness + 1 + brightness_multiplier + 3 + contrast + 1.75 + contrast_base + + 0.949999988079071044921875 + 0.969999969005584716796875 + 1 + 1 + + enable_bloom + 1 + enable_color_filter + 1 + enable_gauss_blur + 0 + enable_motionblur + 1 + enable_night_vision + 0 + enable_posterize + 0 + enable_vignette + 1 + extract_high + 1 + extract_low + 0.949999999999999955591079 + gamma + 4 + gauss_blur_passes + 2 + noise_size + 25 + noise_strength + 0.4000000000000000222044605 + posterize_layers + 10 + saturation + 1.099999904632568359375 + vignette_chromatic_aberration + 0.004500000271946191787719727 + vignette_darkness + 0.66999995708465576171875 + vignette_desaturation + 0 + vignette_radius + 2.9999997615814208984375 + vignette_strength + 1 + - - \ No newline at end of file + diff --git a/indra/newview/app_settings/windlight/skies/%252ACanimod.xml b/indra/newview/app_settings/windlight/skies/%252ACanimod.xml deleted file mode 100644 index d4e69e6226..0000000000 --- a/indra/newview/app_settings/windlight/skies/%252ACanimod.xml +++ /dev/null @@ -1,141 +0,0 @@ - - - ambient - - 1.4699999094009399 - 1.4699999094009399 - 1.4699999094009399 - 0.48999997973442078 - - blue_density - - 0.099999994039535522 - 0.037499997764825821 - 0.067499987781047821 - 0.049999997019767761 - - blue_horizon - - 0.15130999684333801 - 0.30000001192092896 - 0.35131001472473145 - 1 - - cloud_color - - 0.22999998927116394 - 0.22999998927116394 - 0.22999998927116394 - 0.22999998927116394 - - cloud_pos_density1 - - 0.88419097661972046 - 0.53047597408294678 - 0.52999997138977051 - 1 - - cloud_pos_density2 - - 0.2800000011920929 - 0.19999998807907104 - 0.31999999284744263 - 1 - - cloud_scale - - 0.0099999997764825821 - 0 - 0 - 1 - - cloud_scroll_rate - - 0 - 15.329999446868896 - - cloud_shadow - - 0 - 0 - 0 - 1 - - density_multiplier - - 0.00022000000171829015 - 0 - 0 - 1 - - distance_multiplier - - 16.200000762939453 - 0 - 0 - 1 - - east_angle - 6.2831854820251465 - enable_cloud_scroll - - 1 - 1 - - gamma - - 1.4199999570846558 - 0 - 0 - 1 - - glow - - 18.599998474121094 - 0.0012815999798476696 - 0 - 1 - - haze_density - - 0 - 0 - 0 - 1 - - haze_horizon - - 1 - 0.21744099259376526 - 0.21744099259376526 - 1 - - lightnorm - - -1.7484555314695172e-007 - 0 - 1 - 0 - - max_y - - 403 - 0 - 0 - 1 - - preset_num - 2 - star_brightness - 0 - sun_angle - 0 - sunlight_color - - 0 - 0 - 0 - 0 - - - diff --git a/indra/newview/app_settings/windlight/skies/%252AStarley%252A%20Settings%202.xml b/indra/newview/app_settings/windlight/skies/%252AStarley%252A%20Settings%202.xml deleted file mode 100644 index 6d1c09d30a..0000000000 --- a/indra/newview/app_settings/windlight/skies/%252AStarley%252A%20Settings%202.xml +++ /dev/null @@ -1,141 +0,0 @@ - - - ambient - - 1.4699999094009399 - 1.4699999094009399 - 1.4699999094009399 - 0.48999997973442078 - - blue_density - - 0.14000000059604645 - 0.14000000059604645 - 0.14000000059604645 - 0.070000000298023224 - - blue_horizon - - 0.83809572458267212 - 1.0735483169555664 - 1.2799999713897705 - 0.63999998569488525 - - cloud_color - - 0.12862999737262726 - 0.12862999737262726 - 0.12862999737262726 - 1 - - cloud_pos_density1 - - 0.70999997854232788 - 0.53047597408294678 - 0.4270470142364502 - 1 - - cloud_pos_density2 - - 0.38419300317764282 - 0.5 - 0.125 - 1 - - cloud_scale - - 0.72999995946884155 - 0 - 0 - 1 - - cloud_scroll_rate - - 10 - 10 - - cloud_shadow - - 0.2199999988079071 - 0 - 0 - 1 - - density_multiplier - - 0.00017999998817685992 - 0 - 0 - 1 - - distance_multiplier - - 11.40000057220459 - 0 - 0 - 1 - - east_angle - 0 - enable_cloud_scroll - - 1 - 1 - - gamma - - 1.6899999380111694 - 0 - 0 - 1 - - glow - - 6.4079799652099609 - 0.0012815999798476696 - -0.39999997615814209 - 1 - - haze_density - - 1.4900000095367432 - 0 - 0 - 1 - - haze_horizon - - 0 - 0.21744099259376526 - 0.21744099259376526 - 1 - - lightnorm - - 0 - 0 - 1 - 0 - - max_y - - 805 - 0 - 0 - 1 - - preset_num - 2 - star_brightness - 1.5699999332427979 - sun_angle - 0 - sunlight_color - - 3 - 3 - 3 - 1 - - - diff --git a/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Ambient%20%2BFog%20Black.xml b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Ambient%20%2BFog%20Black.xml new file mode 100644 index 0000000000..cea6b11522 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Ambient%20%2BFog%20Black.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0 + 0 + 0 + + blue_density + + 0 + 0 + 0 + 0 + + blue_horizon + + 0.23999999567946317 + 0.23999999579784967 + 0.23999999583870221 + 1 + + cloud_color + + 0.22615400241575034 + 0.22615400241575034 + 0.22615400241575034 + 1 + + cloud_pos_density1 + + 0 + 0 + 0 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.125 + 1 + + cloud_scale + + 0.41999998688697815 + 0 + 0 + 1 + + cloud_scroll_rate + + 10 + 10 + + cloud_shadow + + 0.36000001430511475 + 0 + 0 + 1 + + density_multiplier + + 0.0010000000474974513 + 0 + 0 + 1 + + distance_multiplier + + 10 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1 + 0 + 0 + 1 + + glow + + 5 + 0.0010000000474974513 + -0 + 1 + + haze_density + + 4 + 0 + 0 + 1 + + haze_horizon + + 0 + 0.19915600437467304 + 0.19915600437467304 + 1 + + lightnorm + + -0 + 1 + 1.1483815569590661e-006 + 0 + + max_y + + 4000 + 0 + 0 + 1 + + preset_num + 26 + star_brightness + 0 + sun_angle + 1.5707951784133911 + sunlight_color + + 0 + 0 + 0 + 0 + + + diff --git a/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Ambient%20%2BFog%20Dark%20Blue.xml b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Ambient%20%2BFog%20Dark%20Blue.xml new file mode 100644 index 0000000000..340ffe6e3c --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Ambient%20%2BFog%20Dark%20Blue.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0.1499999910593032836914063 + 0.2999999821186065673828125 + 0.0999999940395355224609375 + + blue_density + + 0.89999997615814208984375 + 0.89999997615814208984375 + 0.89999997615814208984375 + 0.449999988079071044921875 + + blue_horizon + + 0.2999999821186065673828125 + 0.5 + 0.599999964237213134765625 + 0.2999999821186065673828125 + + cloud_color + + 0.2261540024157503436796901 + 0.2261540024157503436796901 + 0.2261540024157503436796901 + 1 + + cloud_pos_density1 + + 0 + 0 + 0 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.125 + 1 + + cloud_scale + + 0.4199999868869781494140625 + 0 + 0 + 1 + + cloud_scroll_rate + + 10 + 10 + + cloud_shadow + + 0.36000001430511474609375 + 0 + 0 + 1 + + density_multiplier + + 0.0008999999845400452613830566 + 0 + 0 + 1 + + distance_multiplier + + 15 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1 + 0 + 0 + 1 + + glow + + 5 + 0.001000000047497451305389404 + -0 + 1 + + haze_density + + 4 + 0 + 0 + 1 + + haze_horizon + + 0 + 0.1991560043746730401803546 + 0.1991560043746730401803546 + 1 + + lightnorm + + 0 + 1 + -4.371138828673792886547744e-08 + 0 + + max_y + + 4000 + 0 + 0 + 1 + + preset_num + 26 + star_brightness + 1 + sun_angle + 1.57079637050628662109375 + sunlight_color + + 0 + 0 + 0 + 0 + + + diff --git a/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Ambient%20%2BFog%20Dark.xml b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Ambient%20%2BFog%20Dark.xml new file mode 100644 index 0000000000..36023d958f --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Ambient%20%2BFog%20Dark.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0 + 0 + 0 + + blue_density + + 0 + 0 + 0 + 0 + + blue_horizon + + 0.23999999567946317 + 0.23999999579784967 + 0.23999999583870221 + 1 + + cloud_color + + 0.22615400241575034 + 0.22615400241575034 + 0.22615400241575034 + 1 + + cloud_pos_density1 + + 0 + 0 + 0 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.125 + 1 + + cloud_scale + + 0.41999998688697815 + 0 + 0 + 1 + + cloud_scroll_rate + + 10 + 10 + + cloud_shadow + + 0.36000001430511475 + 0 + 0 + 1 + + density_multiplier + + 0.0010000000474974513 + 0 + 0 + 1 + + distance_multiplier + + 10 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 5 + 0 + 0 + 1 + + glow + + 5 + 0.0010000000474974513 + -0 + 1 + + haze_density + + 4 + 0 + 0 + 1 + + haze_horizon + + 0 + 0.19915600437467304 + 0.19915600437467304 + 1 + + lightnorm + + -0 + 1 + 1.1483815569590661e-006 + 0 + + max_y + + 4000 + 0 + 0 + 1 + + preset_num + 26 + star_brightness + 0 + sun_angle + 1.5707951784133911 + sunlight_color + + 0 + 0 + 0 + 0 + + + diff --git a/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Ambient%20%2BFog%20Gray%20Blue.xml b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Ambient%20%2BFog%20Gray%20Blue.xml new file mode 100644 index 0000000000..329f0e11ca --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Ambient%20%2BFog%20Gray%20Blue.xml @@ -0,0 +1,141 @@ + + + ambient + + 1.5 + 1.5 + 1.5 + 0.5 + + blue_density + + 1 + 1.5058819055557251 + 2 + 1 + + blue_horizon + + 0.23999999567946317 + 0.23999999579784967 + 0.23999999583870221 + 1 + + cloud_color + + 0.22615400241575034 + 0.22615400241575034 + 0.22615400241575034 + 1 + + cloud_pos_density1 + + 0 + 0 + 0 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.125 + 1 + + cloud_scale + + 0.41999998688697815 + 0 + 0 + 1 + + cloud_scroll_rate + + 10 + 10 + + cloud_shadow + + 0.36000001430511475 + 0 + 0 + 1 + + density_multiplier + + 0.00089999998454004526 + 0 + 0 + 1 + + distance_multiplier + + 4 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1 + 0 + 0 + 1 + + glow + + 5 + 0.0010000000474974513 + -0 + 1 + + haze_density + + 4 + 0 + 0 + 1 + + haze_horizon + + 0 + 0.19915600437467304 + 0.19915600437467304 + 1 + + lightnorm + + -0 + 1 + 1.1483815569590661e-006 + 0 + + max_y + + 4000 + 0 + 0 + 1 + + preset_num + 26 + star_brightness + 0 + sun_angle + 1.5707951784133911 + sunlight_color + + 0 + 0 + 0 + 0 + + + diff --git a/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Ambient%20%2BFog%20Gray.xml b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Ambient%20%2BFog%20Gray.xml new file mode 100644 index 0000000000..ff2099f9fb --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Ambient%20%2BFog%20Gray.xml @@ -0,0 +1,141 @@ + + + ambient + + 2.2499997615814209 + 2.2499997615814209 + 2.2499997615814209 + 0.75 + + blue_density + + 0 + 0 + 0 + 0 + + blue_horizon + + 0.23999999567946317 + 0.23999999579784967 + 0.23999999583870221 + 1 + + cloud_color + + 0.22615400241575034 + 0.22615400241575034 + 0.22615400241575034 + 1 + + cloud_pos_density1 + + 0 + 0 + 0 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.125 + 1 + + cloud_scale + + 0.41999998688697815 + 0 + 0 + 1 + + cloud_scroll_rate + + 10 + 10 + + cloud_shadow + + 0.36000001430511475 + 0 + 0 + 1 + + density_multiplier + + 0.00089999998454004526 + 0 + 0 + 1 + + distance_multiplier + + 12.5 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1 + 0 + 0 + 1 + + glow + + 5 + 0.0010000000474974513 + -0 + 1 + + haze_density + + 4 + 0 + 0 + 1 + + haze_horizon + + 0 + 0.19915600437467304 + 0.19915600437467304 + 1 + + lightnorm + + -0 + 1 + 1.1483815569590661e-006 + 0 + + max_y + + 4000 + 0 + 0 + 1 + + preset_num + 26 + star_brightness + 0 + sun_angle + 1.5707951784133911 + sunlight_color + + 0 + 0 + 0 + 0 + + + diff --git a/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Ambient%20%2BFog%20Underwater.xml b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Ambient%20%2BFog%20Underwater.xml new file mode 100644 index 0000000000..8203071d1b --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Ambient%20%2BFog%20Underwater.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0.2100000083446502685546875 + 0.08999999612569808959960938 + 0.2100000083446502685546875 + + blue_density + + 0.89999997615814208984375 + 0.89999997615814208984375 + 0.89999997615814208984375 + 0.449999988079071044921875 + + blue_horizon + + 0.2999999821186065673828125 + 0.5 + 0.599999964237213134765625 + 0.2999999821186065673828125 + + cloud_color + + 0.2261540024157503436796901 + 0.2261540024157503436796901 + 0.2261540024157503436796901 + 1 + + cloud_pos_density1 + + 0 + 0 + 0 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.125 + 1 + + cloud_scale + + 0.4199999868869781494140625 + 0 + 0 + 1 + + cloud_scroll_rate + + 10 + 10 + + cloud_shadow + + 0.36000001430511474609375 + 0 + 0 + 1 + + density_multiplier + + 0.0008999999845400452613830566 + 0 + 0 + 1 + + distance_multiplier + + 15 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1 + 0 + 0 + 1 + + glow + + 5 + 0.001000000047497451305389404 + -0 + 1 + + haze_density + + 4 + 0 + 0 + 1 + + haze_horizon + + 0 + 0.1991560043746730401803546 + 0.1991560043746730401803546 + 1 + + lightnorm + + 0 + 1 + -4.371138828673792886547744e-08 + 0 + + max_y + + 4000 + 0 + 0 + 1 + + preset_num + 26 + star_brightness + 1 + sun_angle + 1.57079637050628662109375 + sunlight_color + + 0 + 0 + 0 + 0 + + + diff --git a/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Ambient%20%2BFog%20White%20Wash.xml b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Ambient%20%2BFog%20White%20Wash.xml new file mode 100644 index 0000000000..351c83361e --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Ambient%20%2BFog%20White%20Wash.xml @@ -0,0 +1,141 @@ + + + ambient + + 3 + 3 + 3 + 1 + + blue_density + + 2 + 2 + 2 + 1 + + blue_horizon + + 0.39999997615814208984375 + 0.39999997615814208984375 + 0.39999997615814208984375 + 0.199999988079071044921875 + + cloud_color + + 0.2261540024157503436796901 + 0.2261540024157503436796901 + 0.2261540024157503436796901 + 1 + + cloud_pos_density1 + + 0 + 0 + 0 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.125 + 1 + + cloud_scale + + 0.4199999868869781494140625 + 0 + 0 + 1 + + cloud_scroll_rate + + 10 + 10 + + cloud_shadow + + 0.36000001430511474609375 + 0 + 0 + 1 + + density_multiplier + + 0.0008999999845400452613830566 + 0 + 0 + 1 + + distance_multiplier + + 100 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1 + 0 + 0 + 1 + + glow + + 5 + 0.001000000047497451305389404 + -0 + 1 + + haze_density + + 0 + 0 + 0 + 1 + + haze_horizon + + 0 + 0.1991560043746730401803546 + 0.1991560043746730401803546 + 1 + + lightnorm + + -0 + 1 + 1.148381556959066074341536e-06 + 0 + + max_y + + 4000 + 0 + 0 + 1 + + preset_num + 26 + star_brightness + 0 + sun_angle + 1.57079517841339111328125 + sunlight_color + + 0 + 0 + 0 + 0 + + + diff --git a/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Ambient%20%2BFog%20White.xml b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Ambient%20%2BFog%20White.xml new file mode 100644 index 0000000000..c915884666 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Ambient%20%2BFog%20White.xml @@ -0,0 +1,141 @@ + + + ambient + + 1.5 + 1.5 + 1.5 + 0.5 + + blue_density + + 2 + 2 + 2 + 1 + + blue_horizon + + 0.39999997615814208984375 + 0.39999997615814208984375 + 0.39999997615814208984375 + 0.199999988079071044921875 + + cloud_color + + 0.2261540024157503436796901 + 0.2261540024157503436796901 + 0.2261540024157503436796901 + 1 + + cloud_pos_density1 + + 0 + 0 + 0 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.125 + 1 + + cloud_scale + + 0.4199999868869781494140625 + 0 + 0 + 1 + + cloud_scroll_rate + + 10 + 10 + + cloud_shadow + + 0.36000001430511474609375 + 0 + 0 + 1 + + density_multiplier + + 0.0008999999845400452613830566 + 0 + 0 + 1 + + distance_multiplier + + 1 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1 + 0 + 0 + 1 + + glow + + 5 + 0.001000000047497451305389404 + -0 + 1 + + haze_density + + 0 + 0 + 0 + 1 + + haze_horizon + + 0 + 0.1991560043746730401803546 + 0.1991560043746730401803546 + 1 + + lightnorm + + -0 + 1 + 1.148381556959066074341536e-06 + 0 + + max_y + + 4000 + 0 + 0 + 1 + + preset_num + 26 + star_brightness + 0 + sun_angle + 1.57079517841339111328125 + sunlight_color + + 0 + 0 + 0 + 0 + + + diff --git a/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Ambient%20Black.xml b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Ambient%20Black.xml new file mode 100644 index 0000000000..04c9713ed3 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Ambient%20Black.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0 + 0 + 0 + + blue_density + + 0.44999999369830818 + 0.44999999398335949 + 0.4499999944309046 + 1 + + blue_horizon + + 0.23999999567946317 + 0.23999999579784967 + 0.23999999583870221 + 1 + + cloud_color + + 0.22615400241575034 + 0.22615400241575034 + 0.22615400241575034 + 1 + + cloud_pos_density1 + + 0 + 0 + 0 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.125 + 1 + + cloud_scale + + 0.41999998688697815 + 0 + 0 + 1 + + cloud_scroll_rate + + 10 + 10 + + cloud_shadow + + 0.36000001430511475 + 0 + 0 + 1 + + density_multiplier + + 0 + 0 + 0 + 1 + + distance_multiplier + + 3.0208916693946743e-009 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1 + 0 + 0 + 1 + + glow + + 5 + 0.0010000000474974513 + -0 + 1 + + haze_density + + 0 + 0 + 0 + 1 + + haze_horizon + + 0 + 0.19915600437467304 + 0.19915600437467304 + 1 + + lightnorm + + -0 + 1 + 1.1483815569590661e-006 + 0 + + max_y + + 0 + 0 + 0 + 1 + + preset_num + 26 + star_brightness + 2 + sun_angle + 1.5707951784133911 + sunlight_color + + 0 + 0 + 0 + 0 + + + diff --git a/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Ambient%20Dark%20H%2DBomb.xml b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Ambient%20Dark%20H%2DBomb.xml new file mode 100644 index 0000000000..c2ceef4d01 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Ambient%20Dark%20H%2DBomb.xml @@ -0,0 +1,141 @@ + + + ambient + + 1.5 + 0 + 0 + 1.5 + + blue_density + + 0.449999993698308176082179 + 0.4499999939833594919669224 + 0.4499999944309046040480382 + 1 + + blue_horizon + + 0.2399999956794631739143142 + 0.2399999957978496689658954 + 0.2399999958387022125361199 + 1 + + cloud_color + + 0.2261540024157503436796901 + 0.2261540024157503436796901 + 0.2261540024157503436796901 + 1 + + cloud_pos_density1 + + 0 + 0 + 0 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.125 + 1 + + cloud_scale + + 0.4199999868869781494140625 + 0 + 0 + 1 + + cloud_scroll_rate + + 10 + 10 + + cloud_shadow + + 0.36000001430511474609375 + 0 + 0 + 1 + + density_multiplier + + 0 + 0 + 0 + 1 + + distance_multiplier + + 3.02089166939467428676299e-09 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 0.39999997615814208984375 + 0 + 0 + 1 + + glow + + 5 + 0.001000000047497451305389404 + -0 + 1 + + haze_density + + 0 + 0 + 0 + 1 + + haze_horizon + + 0 + 0.1991560043746730401803546 + 0.1991560043746730401803546 + 1 + + lightnorm + + -0 + 1 + 1.148381556959066074341536e-06 + 0 + + max_y + + 0 + 0 + 0 + 1 + + preset_num + 26 + star_brightness + 2 + sun_angle + 1.57079517841339111328125 + sunlight_color + + 0 + 0 + 0 + 0 + + + diff --git a/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Ambient%20Dark.xml b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Ambient%20Dark.xml new file mode 100644 index 0000000000..83bd660b64 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Ambient%20Dark.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0 + 0 + 0 + + blue_density + + 2 + 2 + 2 + 1 + + blue_horizon + + 2 + 2 + 2 + 1 + + cloud_color + + 0.22615400241575034 + 0.22615400241575034 + 0.22615400241575034 + 1 + + cloud_pos_density1 + + 0 + 0 + 0 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.125 + 1 + + cloud_scale + + 0.41999998688697815 + 0 + 0 + 1 + + cloud_scroll_rate + + 10 + 10 + + cloud_shadow + + 0.36000001430511475 + 0 + 0 + 1 + + density_multiplier + + 0 + 0 + 0 + 1 + + distance_multiplier + + 3.0208916693946743e-009 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 4 + 0 + 0 + 1 + + glow + + 5 + 0.0010000000474974513 + -0 + 1 + + haze_density + + 0 + 0 + 0 + 1 + + haze_horizon + + 0 + 0.19915600437467304 + 0.19915600437467304 + 1 + + lightnorm + + -0 + 1 + 1.1483815569590661e-006 + 0 + + max_y + + 0 + 0 + 0 + 1 + + preset_num + 26 + star_brightness + 2 + sun_angle + 1.5707951784133911 + sunlight_color + + 0 + 0 + 0 + 0 + + + diff --git a/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Ambient%20Gray%20Background.xml b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Ambient%20Gray%20Background.xml new file mode 100644 index 0000000000..fe1c9f8c0a --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Ambient%20Gray%20Background.xml @@ -0,0 +1,141 @@ + + + ambient + + 1.5 + 1.5 + 1.5 + 0.5 + + blue_density + + 0.449999993698308176082179 + 0.4499999939833594919669224 + 0.4499999944309046040480382 + 1 + + blue_horizon + + 0.89999997615814208984375 + 0.89999997615814208984375 + 0.89999997615814208984375 + 0.449999988079071044921875 + + cloud_color + + 0.2261540024157503436796901 + 0.2261540024157503436796901 + 0.2261540024157503436796901 + 1 + + cloud_pos_density1 + + 0 + 0 + 0 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.125 + 1 + + cloud_scale + + 0.4199999868869781494140625 + 0 + 0 + 1 + + cloud_scroll_rate + + 10 + 10 + + cloud_shadow + + 0.36000001430511474609375 + 0 + 0 + 1 + + density_multiplier + + 0.0004499999922700226306915283 + 0 + 0 + 1 + + distance_multiplier + + 0 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1 + 0 + 0 + 1 + + glow + + 5 + 0.001000000047497451305389404 + -0 + 1 + + haze_density + + 4 + 0 + 0 + 1 + + haze_horizon + + 0 + 0.1991560043746730401803546 + 0.1991560043746730401803546 + 1 + + lightnorm + + -0 + 1 + 1.148381556959066074341536e-06 + 0 + + max_y + + 4000 + 0 + 0 + 1 + + preset_num + 26 + star_brightness + 0 + sun_angle + 1.57079517841339111328125 + sunlight_color + + 0 + 0 + 0 + 0 + + + diff --git a/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Ambient%20Gray.xml b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Ambient%20Gray.xml new file mode 100644 index 0000000000..2ab736ee46 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Ambient%20Gray.xml @@ -0,0 +1,141 @@ + + + ambient + + 1.5 + 1.5 + 1.5 + 0.5 + + blue_density + + 0.44999999369830818 + 0.44999999398335949 + 0.4499999944309046 + 1 + + blue_horizon + + 0.23999999567946317 + 0.23999999579784967 + 0.23999999583870221 + 1 + + cloud_color + + 0.22615400241575034 + 0.22615400241575034 + 0.22615400241575034 + 1 + + cloud_pos_density1 + + 0 + 0 + 0 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.125 + 1 + + cloud_scale + + 0.41999998688697815 + 0 + 0 + 1 + + cloud_scroll_rate + + 10 + 10 + + cloud_shadow + + 0.36000001430511475 + 0 + 0 + 1 + + density_multiplier + + 0 + 0 + 0 + 1 + + distance_multiplier + + 3.0208916693946743e-009 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1 + 0 + 0 + 1 + + glow + + 5 + 0.0010000000474974513 + -0 + 1 + + haze_density + + 0 + 0 + 0 + 1 + + haze_horizon + + 0 + 0.19915600437467304 + 0.19915600437467304 + 1 + + lightnorm + + -0 + 1 + 1.1483815569590661e-006 + 0 + + max_y + + 0 + 0 + 0 + 1 + + preset_num + 26 + star_brightness + 2 + sun_angle + 1.5707951784133911 + sunlight_color + + 0 + 0 + 0 + 0 + + + diff --git a/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Ambient%20White.xml b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Ambient%20White.xml new file mode 100644 index 0000000000..6321311a4c --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Ambient%20White.xml @@ -0,0 +1,141 @@ + + + ambient + + 3 + 3 + 2.9999997615814209 + 1 + + blue_density + + 0.44999999369830818 + 0.44999999398335949 + 0.4499999944309046 + 1 + + blue_horizon + + 0.23999999567946317 + 0.23999999579784967 + 0.23999999583870221 + 1 + + cloud_color + + 0.22615400241575034 + 0.22615400241575034 + 0.22615400241575034 + 1 + + cloud_pos_density1 + + 0 + 0 + 0 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.125 + 1 + + cloud_scale + + 0.41999998688697815 + 0 + 0 + 1 + + cloud_scroll_rate + + 10 + 10 + + cloud_shadow + + 0.36000001430511475 + 0 + 0 + 1 + + density_multiplier + + 0 + 0 + 0 + 1 + + distance_multiplier + + 3.0208916693946743e-009 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1 + 0 + 0 + 1 + + glow + + 5 + 0.0010000000474974513 + -0 + 1 + + haze_density + + 0 + 0 + 0 + 1 + + haze_horizon + + 0 + 0.19915600437467304 + 0.19915600437467304 + 1 + + lightnorm + + -0 + 1 + 1.1483815569590661e-006 + 0 + + max_y + + 0 + 0 + 0 + 1 + + preset_num + 26 + star_brightness + 2 + sun_angle + 1.5707951784133911 + sunlight_color + + 0 + 0 + 0 + 0 + + + diff --git a/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Cloudy%20Afternoon.xml b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Cloudy%20Afternoon.xml new file mode 100644 index 0000000000..233a3b354f --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Cloudy%20Afternoon.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.449999988079071044921875 + 0.89999997615814208984375 + 1.0499999523162841796875 + 0.3499999940395355224609375 + + blue_density + + 2 + 2 + 2 + 1 + + blue_horizon + + 0.5 + 0.5 + 0.5 + 0.25 + + cloud_color + + 0.2999999821186065673828125 + 0.2999999821186065673828125 + 0.2999999821186065673828125 + 0.2999999821186065673828125 + + cloud_pos_density1 + + 1 + 1 + 0.2999999821186065673828125 + 1 + + cloud_pos_density2 + + 1 + 1 + 0 + 1 + + cloud_scale + + 0.2000000029802322387695313 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.3999996185302734375 + 10 + + cloud_shadow + + 0.75 + 0 + 0 + 1 + + density_multiplier + + 4.999999873689375817775726e-05 + 0 + 0 + 1 + + distance_multiplier + + 7 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 0.599999964237213134765625 + 0 + 0 + 1 + + glow + + 0.200002193450927734375 + 0.001000000047497451305389404 + -0.199999988079071044921875 + 1 + + haze_density + + 4 + 0 + 0 + 1 + + haze_horizon + + 0.1499999910593032836914063 + 0.1991560012102127075195313 + 0.1991560012102127075195313 + 1 + + lightnorm + + 0 + 0.876306593418121337890625 + -0.4817537963390350341796875 + 0 + + max_y + + 1 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0 + sun_angle + 2.0734512805938720703125 + sunlight_color + + 1.0499999523162841796875 + 1.0499999523162841796875 + 1.0499999523162841796875 + 0.3499999940395355224609375 + + + diff --git a/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Cloudy%20Dusk.xml b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Cloudy%20Dusk.xml new file mode 100644 index 0000000000..8fe71abd14 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Cloudy%20Dusk.xml @@ -0,0 +1,106 @@ + + + ambient + + 0 + 0.05999999865889549255371094 + 0.1499999910593032836914063 + 0.04999999701976776123046875 + + blue_density + + 1.99999988079071044921875 + 1.99999988079071044921875 + 1.99999988079071044921875 + 1 + + blue_horizon + + 0.680000007152557373046875 + 0.680000007152557373046875 + 0.680000007152557373046875 + 0.3400000035762786865234375 + + cloud_color + + 0.2999999821186065673828125 + 0.2999999821186065673828125 + 0.2999999821186065673828125 + 0.2999999821186065673828125 + + cloud_pos_density1 + + 1 + 1 + 0.0999999940395355224609375 + 1 + + cloud_pos_density2 + + 1.6884100437164306640625 + 1 + 0.0999999940395355224609375 + 1 + + cloud_scale + 0.2000000029802322387695313 + cloud_scroll_rate + + 10.1499996185302734375 + 10 + + cloud_shadow + 0.5 + density_multiplier + 5.999999848427250981330872e-05 + distance_multiplier + 3 + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1.75 + 0 + 0 + 1 + + glow + + 10 + 0.001000000047497451305389404 + -0.449999988079071044921875 + 1 + + haze_density + 4 + haze_horizon + 0 + lightnorm + + 0 + 0 + -1 + 0 + + max_y + 500 + preset_num + 22 + star_brightness + 0 + sun_angle + 3.1415927410125732421875 + sunlight_color + + 0.2999999821186065673828125 + 0.38999998569488525390625 + 0.4500000178813934326171875 + 0.1499999910593032836914063 + + + diff --git a/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Cloudy%20Evening.xml b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Cloudy%20Evening.xml new file mode 100644 index 0000000000..4039d2ee5b --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Cloudy%20Evening.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.2999999821186065673828125 + 0.449999988079071044921875 + 0.599999964237213134765625 + 0.199999988079071044921875 + + blue_density + + 2 + 2 + 2 + 1 + + blue_horizon + + 0.5 + 0.5 + 0.5 + 0.25 + + cloud_color + + 0.2999999821186065673828125 + 0.2999999821186065673828125 + 0.2999999821186065673828125 + 0.2999999821186065673828125 + + cloud_pos_density1 + + 1 + 1 + 0.25 + 1 + + cloud_pos_density2 + + 1.6884100437164306640625 + 1 + 0 + 1 + + cloud_scale + + 0.2000000029802322387695313 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.3999996185302734375 + 10 + + cloud_shadow + + 0.75 + 0 + 0 + 1 + + density_multiplier + + 4.999999873689375817775726e-05 + 0 + 0 + 1 + + distance_multiplier + + 7 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 0.89999997615814208984375 + 0 + 0 + 1 + + glow + + 10 + 0.001000000047497451305389404 + -0.449999988079071044921875 + 1 + + haze_density + + 4 + 0 + 0 + 1 + + haze_horizon + + 0 + 0.1991560012102127075195313 + 0.1991560012102127075195313 + 1 + + lightnorm + + 0 + 0.1873810738325119018554688 + -0.98228728771209716796875 + 0 + + max_y + + 1 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0 + sun_angle + 2.95309734344482421875 + sunlight_color + + 1.0499999523162841796875 + 0.75 + 0.599999964237213134765625 + 1.0499999523162841796875 + + + diff --git a/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Cloudy%20Noon.xml b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Cloudy%20Noon.xml new file mode 100644 index 0000000000..60882441d9 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Cloudy%20Noon.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.2999999821186065673828125 + 0.44999992847442626953125 + 0.599999964237213134765625 + 0.199999988079071044921875 + + blue_density + + 2 + 2 + 2 + 1 + + blue_horizon + + 0.599999964237213134765625 + 0.599999964237213134765625 + 0.599999964237213134765625 + 0.2999999821186065673828125 + + cloud_color + + 0.329999983310699462890625 + 0.329999983310699462890625 + 0.329999983310699462890625 + 0.329999983310699462890625 + + cloud_pos_density1 + + 1 + 1 + 0.25 + 1 + + cloud_pos_density2 + + 1.6884100437164306640625 + 1 + 0 + 1 + + cloud_scale + + 0.2000000029802322387695313 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.3999996185302734375 + 10 + + cloud_shadow + + 0.75 + 0 + 0 + 1 + + density_multiplier + + 9.999999747378751635551453e-05 + 0 + 0 + 1 + + distance_multiplier + + 5 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 0.89999997615814208984375 + 0 + 0 + 1 + + glow + + 0.200002193450927734375 + 0.001000000047497451305389404 + -0.199999988079071044921875 + 1 + + haze_density + + 4 + 0 + 0 + 1 + + haze_horizon + + 0.2099999934434890747070313 + 0.1991560012102127075195313 + 0.1991560012102127075195313 + 1 + + lightnorm + + 0 + 1 + -4.371138828673792886547744e-08 + 0 + + max_y + + 1 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0 + sun_angle + 1.57079637050628662109375 + sunlight_color + + 1.0499999523162841796875 + 1.0499999523162841796875 + 1.0499999523162841796875 + 0.3499999940395355224609375 + + + diff --git a/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Cloudy%20Rainy%20Bright.xml b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Cloudy%20Rainy%20Bright.xml new file mode 100644 index 0000000000..409cea7e39 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Cloudy%20Rainy%20Bright.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0 + 0 + 0 + + blue_density + + 2 + 2 + 2 + 2 + + blue_horizon + + 0.39999997615814208984375 + 0.39999997615814208984375 + 0.39999997615814208984375 + 0.199999988079071044921875 + + cloud_color + + 0.2999999821186065673828125 + 0.2999999821186065673828125 + 0.2999999821186065673828125 + 0.2999999821186065673828125 + + cloud_pos_density1 + + 0.5 + 0.5 + 0.1700000017881393432617188 + 1 + + cloud_pos_density2 + + 1.6884100437164306640625 + 1 + 0 + 1 + + cloud_scale + + 0.2000000029802322387695313 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.3999996185302734375 + 10 + + cloud_shadow + + 0.75 + 0 + 0 + 1 + + density_multiplier + + 0.0005999999702908098697662354 + 0 + 0 + 1 + + distance_multiplier + + 3.5 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1.599999904632568359375 + 0 + 0 + 1 + + glow + + 0.200002193450927734375 + 0.001000000047497451305389404 + -0.1499999910593032836914063 + 1 + + haze_density + + 4 + 0 + 0 + 1 + + haze_horizon + + 0.04999999701976776123046875 + 0.1991560012102127075195313 + 0.1991560012102127075195313 + 1 + + lightnorm + + 0 + 0.876306593418121337890625 + -0.4817537963390350341796875 + 0 + + max_y + + 26 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0 + sun_angle + 2.0734512805938720703125 + sunlight_color + + 0.599999964237213134765625 + 0.75 + 0.749999940395355224609375 + 0.75 + + + diff --git a/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Cloudy%20Rainy%20HalfBright.xml b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Cloudy%20Rainy%20HalfBright.xml new file mode 100644 index 0000000000..eee6373888 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Cloudy%20Rainy%20HalfBright.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0 + 0 + 0 + + blue_density + + 2 + 2 + 2 + 2 + + blue_horizon + + 0.39999997615814208984375 + 0.39999997615814208984375 + 0.39999997615814208984375 + 0.199999988079071044921875 + + cloud_color + + 0.2999999821186065673828125 + 0.2999999821186065673828125 + 0.2999999821186065673828125 + 0.2999999821186065673828125 + + cloud_pos_density1 + + 0.5 + 0.5 + 0.1700000017881393432617188 + 1 + + cloud_pos_density2 + + 1.6884100437164306640625 + 1 + 0 + 1 + + cloud_scale + + 0.2000000029802322387695313 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.3999996185302734375 + 10 + + cloud_shadow + + 0.75 + 0 + 0 + 1 + + density_multiplier + + 0.0005999999702908098697662354 + 0 + 0 + 1 + + distance_multiplier + + 3.5 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1.19999992847442626953125 + 0 + 0 + 1 + + glow + + 0.200002193450927734375 + 0.001000000047497451305389404 + -0.1499999910593032836914063 + 1 + + haze_density + + 4 + 0 + 0 + 1 + + haze_horizon + + 0.04999999701976776123046875 + 0.1991560012102127075195313 + 0.1991560012102127075195313 + 1 + + lightnorm + + 0 + 0.876306593418121337890625 + -0.4817537963390350341796875 + 0 + + max_y + + 100 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0 + sun_angle + 2.0734512805938720703125 + sunlight_color + + 0.599999964237213134765625 + 0.75 + 0.749999940395355224609375 + 0.75 + + + diff --git a/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Cloudy%20Rainy.xml b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Cloudy%20Rainy.xml new file mode 100644 index 0000000000..1b1fd7488f --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Cloudy%20Rainy.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0 + 0 + 0 + + blue_density + + 2 + 2 + 2 + 2 + + blue_horizon + + 0.39999997615814208984375 + 0.39999997615814208984375 + 0.39999997615814208984375 + 0.199999988079071044921875 + + cloud_color + + 0.2999999821186065673828125 + 0.2999999821186065673828125 + 0.2999999821186065673828125 + 0.2999999821186065673828125 + + cloud_pos_density1 + + 0.5 + 0.5 + 0.1700000017881393432617188 + 1 + + cloud_pos_density2 + + 1.6884100437164306640625 + 1 + 0 + 1 + + cloud_scale + + 0.2000000029802322387695313 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.3999996185302734375 + 10 + + cloud_shadow + + 0.75 + 0 + 0 + 1 + + density_multiplier + + 0.0005999999702908098697662354 + 0 + 0 + 1 + + distance_multiplier + + 3.5 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 0.599999964237213134765625 + 0 + 0 + 1 + + glow + + 0.200002193450927734375 + 0.001000000047497451305389404 + -0.1499999910593032836914063 + 1 + + haze_density + + 4 + 0 + 0 + 1 + + haze_horizon + + 0.04999999701976776123046875 + 0.1991560012102127075195313 + 0.1991560012102127075195313 + 1 + + lightnorm + + 0 + 0.876306593418121337890625 + -0.4817537963390350341796875 + 0 + + max_y + + 100 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0 + sun_angle + 2.0734512805938720703125 + sunlight_color + + 0.599999964237213134765625 + 0.75 + 0.749999940395355224609375 + 0.75 + + + diff --git a/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Default%20.xml b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Default%20.xml new file mode 100644 index 0000000000..b26c41ae13 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Default%20.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.2880000174045562744140625 + 0.449999988079071044921875 + 0.599999964237213134765625 + 0.599999964237213134765625 + + blue_density + + 0.199999988079071044921875 + 0.2999999821186065673828125 + 0.599999964237213134765625 + 0.2999999821186065673828125 + + blue_horizon + + 0 + 0.199999988079071044921875 + 0.2999999821186065673828125 + 0.2999999821186065673828125 + + cloud_color + + 1 + 1 + 1 + 1 + + cloud_pos_density1 + + 1 + 1 + 0.08999999612569808959960938 + 1 + + cloud_pos_density2 + + 1.6884100437164306640625 + 0 + 0.75 + 1 + + cloud_scale + + 0.4999999701976776123046875 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.19999980926513671875 + 10.0109996795654296875 + + cloud_shadow + + 0.5 + 0 + 0 + 1 + + density_multiplier + + 0.0002500000118743628263473511 + 0 + 0 + 1 + + distance_multiplier + + 1 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 0.75 + 0 + 0 + 1 + + glow + + 10 + 0.001000000047497451305389404 + -0.4999999701976776123046875 + 1 + + haze_density + + 0.199999988079071044921875 + 0 + 0 + 1 + + haze_horizon + + 0.4699999988079071044921875 + 0.1991560012102127075195313 + 0.1991560012102127075195313 + 1 + + lightnorm + + 0 + 0.867070615291595458984375 + -0.49818527698516845703125 + 0 + + max_y + + 2000 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0 + sun_angle + 2.092300891876220703125 + sunlight_color + + 1.5 + 1.5 + 1.5 + 0.5 + + + diff --git a/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Fine%20Afternoon.xml b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Fine%20Afternoon.xml new file mode 100644 index 0000000000..438cfe90b7 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Fine%20Afternoon.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.599999964237213134765625 + 1.049999237060546875 + 1.19999992847442626953125 + 0.39999997615814208984375 + + blue_density + + 0.0999999940395355224609375 + 0.2999999821186065673828125 + 0.39999997615814208984375 + 0.560000002384185791015625 + + blue_horizon + + 0.39999997615814208984375 + 0.39999997615814208984375 + 0.7999999523162841796875 + 0.39999997615814208984375 + + cloud_color + + 0.39999997615814208984375 + 0.2800000011920928955078125 + 0.1999999433755874633789063 + 0.39999997615814208984375 + + cloud_pos_density1 + + 1 + 1 + 0.0999999940395355224609375 + 1 + + cloud_pos_density2 + + 1.6884100437164306640625 + 0 + 0.0999999940395355224609375 + 1 + + cloud_scale + + 0.05999999493360519409179688 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.5 + 10.0109996795654296875 + + cloud_shadow + + 0.5 + 0 + 0 + 1 + + density_multiplier + + 9.999999747378751635551453e-05 + 0 + 0 + 1 + + distance_multiplier + + 6 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 0.599999964237213134765625 + 0 + 0 + 1 + + glow + + 20 + 0.001000000047497451305389404 + -1.25 + 1 + + haze_density + + 0.5 + 0 + 0 + 1 + + haze_horizon + + 0.2999999821186065673828125 + 0.1991560012102127075195313 + 0.1991560012102127075195313 + 1 + + lightnorm + + 0 + 0.587785184383392333984375 + -0.80901706218719482421875 + 0 + + max_y + + 4000 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0 + sun_angle + 2.51327419281005859375 + sunlight_color + + 1.5 + 1.19999992847442626953125 + 0.89999997615814208984375 + 1.5 + + + diff --git a/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Flamesight.xml b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Flamesight.xml new file mode 100644 index 0000000000..aafbc189f9 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Flamesight.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0 + 0 + 0 + + blue_density + + 0 + 0 + 1.5 + 1.5 + + blue_horizon + + 0 + 0 + 2 + 2 + + cloud_color + + 0.5 + 0.5 + 0.5 + 0.5 + + cloud_pos_density1 + + 1.6884100437164306640625 + 0 + 0.5 + 1 + + cloud_pos_density2 + + 1.6884100437164306640625 + 0.526096999645233154296875 + 0 + 1 + + cloud_scale + + 0.0999999940395355224609375 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.19999980926513671875 + 10.0109996795654296875 + + cloud_shadow + + 0.5 + 0 + 0 + 1 + + density_multiplier + + 0.0003299999807495623826980591 + 0 + 0 + 1 + + distance_multiplier + + 50 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 0.329999983310699462890625 + 0 + 0 + 1 + + glow + + 30 + 0.001000000047497451305389404 + -0.4999999701976776123046875 + 1 + + haze_density + + 1 + 0 + 0 + 1 + + haze_horizon + + 0.5 + 0.1991560012102127075195313 + 0.1991560012102127075195313 + 1 + + lightnorm + + 0 + 0.867070615291595458984375 + -0.49818527698516845703125 + 0 + + max_y + + 2000 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0 + sun_angle + 2.092300891876220703125 + sunlight_color + + 3 + 0.990000188350677490234375 + 0 + 1 + + + diff --git a/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Indoors%20Bright.xml b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Indoors%20Bright.xml new file mode 100644 index 0000000000..16ce75e17b --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Indoors%20Bright.xml @@ -0,0 +1,141 @@ + + + ambient + + 2.25 + 2.25 + 2.25 + 0.75 + + blue_density + + 2 + 2 + 2 + 2 + + blue_horizon + + 0.1999999731779098510742188 + 0.1999999731779098510742188 + 0.1999999731779098510742188 + 0.0999999940395355224609375 + + cloud_color + + 1 + 1 + 1 + 1 + + cloud_pos_density1 + + 1 + 1 + 0.08999999612569808959960938 + 1 + + cloud_pos_density2 + + 1.6884100437164306640625 + 0 + 0.75 + 1 + + cloud_scale + + 0.4999999701976776123046875 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.19999980926513671875 + 10.0109996795654296875 + + cloud_shadow + + 1 + 0 + 0 + 1 + + density_multiplier + + 9.999999747378751635551453e-06 + 0 + 0 + 1 + + distance_multiplier + + 100 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 0.66999995708465576171875 + 0 + 0 + 1 + + glow + + 10 + 0.001000000047497451305389404 + -0.4999999701976776123046875 + 1 + + haze_density + + 1 + 0 + 0 + 1 + + haze_horizon + + 1 + 0.1991560012102127075195313 + 0.1991560012102127075195313 + 1 + + lightnorm + + 0 + 0.867070615291595458984375 + -0.49818527698516845703125 + 0 + + max_y + + 4000 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0 + sun_angle + 2.092300891876220703125 + sunlight_color + + 3 + 2.4000003337860107421875 + 2.099999904632568359375 + 1 + + + diff --git a/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Indoors%20Cloudy.xml b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Indoors%20Cloudy.xml new file mode 100644 index 0000000000..40bbf3b88e --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Indoors%20Cloudy.xml @@ -0,0 +1,141 @@ + + + ambient + + 1.5 + 1.7999999523162841796875 + 2.099999904632568359375 + 2.099999904632568359375 + + blue_density + + 2 + 2 + 2 + 2 + + blue_horizon + + 0.1999999731779098510742188 + 0.1999999731779098510742188 + 0.1999999731779098510742188 + 0.0999999940395355224609375 + + cloud_color + + 1 + 1 + 1 + 1 + + cloud_pos_density1 + + 1 + 1 + 0.08999999612569808959960938 + 1 + + cloud_pos_density2 + + 1.6884100437164306640625 + 0 + 0.75 + 1 + + cloud_scale + + 0.4999999701976776123046875 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.19999980926513671875 + 10.0109996795654296875 + + cloud_shadow + + 1 + 0 + 0 + 1 + + density_multiplier + + 1.999999949475750327110291e-05 + 0 + 0 + 1 + + distance_multiplier + + 100 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 0.66999995708465576171875 + 0 + 0 + 1 + + glow + + 10 + 0.001000000047497451305389404 + -0.4999999701976776123046875 + 1 + + haze_density + + 1 + 0 + 0 + 1 + + haze_horizon + + 1 + 0.1991560012102127075195313 + 0.1991560012102127075195313 + 1 + + lightnorm + + 0 + 0.867070615291595458984375 + -0.49818527698516845703125 + 0 + + max_y + + 4000 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0 + sun_angle + 2.092300891876220703125 + sunlight_color + + 1.230000019073486328125 + 1.230000019073486328125 + 1.230000019073486328125 + 0.4099999964237213134765625 + + + diff --git a/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Indoors%20Evening.xml b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Indoors%20Evening.xml new file mode 100644 index 0000000000..c10d7dc873 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Indoors%20Evening.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.2999999821186065673828125 + 0.599999964237213134765625 + 0.89999997615814208984375 + 0.89999997615814208984375 + + blue_density + + 2 + 2 + 2 + 2 + + blue_horizon + + 0.1999999731779098510742188 + 0.1999999731779098510742188 + 0.1999999731779098510742188 + 0.0999999940395355224609375 + + cloud_color + + 0.5 + 0.5 + 0.5 + 0.5 + + cloud_pos_density1 + + 1 + 1 + 0.08999999612569808959960938 + 1 + + cloud_pos_density2 + + 1.6884100437164306640625 + 0 + 0.75 + 1 + + cloud_scale + + 0.4999999701976776123046875 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.19999980926513671875 + 10.0109996795654296875 + + cloud_shadow + + 1 + 0 + 0 + 1 + + density_multiplier + + 1.999999949475750327110291e-05 + 0 + 0 + 1 + + distance_multiplier + + 100 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 0.66999995708465576171875 + 0 + 0 + 1 + + glow + + 10 + 0.001000000047497451305389404 + -0.4999999701976776123046875 + 1 + + haze_density + + 1 + 0 + 0 + 1 + + haze_horizon + + 1 + 0.1991560012102127075195313 + 0.1991560012102127075195313 + 1 + + lightnorm + + 0 + 0 + -1 + 0 + + max_y + + 4000 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0 + sun_angle + 3.1415927410125732421875 + sunlight_color + + 0 + 0 + 0 + 0 + + + diff --git a/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Indoors%20Night.xml b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Indoors%20Night.xml new file mode 100644 index 0000000000..2958cad7e9 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Indoors%20Night.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.599999964237213134765625 + 0.75 + 1.19999992847442626953125 + 0.39999997615814208984375 + + blue_density + + 1.99999988079071044921875 + 1.99999988079071044921875 + 1.99999988079071044921875 + 1 + + blue_horizon + + 0 + 0 + 0 + 0 + + cloud_color + + 0.5 + 0.5 + 0.5 + 0.5 + + cloud_pos_density1 + + 1 + 1 + 0.08999999612569808959960938 + 1 + + cloud_pos_density2 + + 1.6884100437164306640625 + 0 + 0.75 + 1 + + cloud_scale + + 0.4999999701976776123046875 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.19999980926513671875 + 10.0109996795654296875 + + cloud_shadow + + 0 + 0 + 0 + 1 + + density_multiplier + + 0.0002500000118743628263473511 + 0 + 0 + 1 + + distance_multiplier + + 100 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 0.66999995708465576171875 + 0 + 0 + 1 + + glow + + 10 + 0.001000000047497451305389404 + -0.4999999701976776123046875 + 1 + + haze_density + + 1 + 0 + 0 + 1 + + haze_horizon + + 0 + 0.1991560012102127075195313 + 0.1991560012102127075195313 + 1 + + lightnorm + + 0 + 0 + -1 + 0 + + max_y + + 4000 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0 + sun_angle + 3.1415927410125732421875 + sunlight_color + + 0 + 0 + 0 + 0 + + + diff --git a/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Night%20Bright.xml b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Night%20Bright.xml new file mode 100644 index 0000000000..7b4cebdb97 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Night%20Bright.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0.1499999910593032836914063 + 0.4500000178813934326171875 + 0.1499999910593032836914063 + + blue_density + + 0.39999997615814208984375 + 0.39999997615814208984375 + 0.39999997615814208984375 + 0.199999988079071044921875 + + blue_horizon + + 0.4000000059604644775390625 + 0.599999725818634033203125 + 0.800000011920928955078125 + 0.39999997615814208984375 + + cloud_color + + 0.329999983310699462890625 + 0.329999983310699462890625 + 0.329999983310699462890625 + 0.329999983310699462890625 + + cloud_pos_density1 + + 0.5 + 0.5 + 0.0999999940395355224609375 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0 + 1 + + cloud_scale + + 0.07000000029802322387695313 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.1399993896484375 + 10.0109996795654296875 + + cloud_shadow + + 0.39999997615814208984375 + 0 + 0 + 1 + + density_multiplier + + 4.999999873689375817775726e-05 + 0 + 0 + 1 + + distance_multiplier + + 10 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 2 + 0 + 0 + 1 + + glow + + 20 + 0.001000000047497451305389404 + -1.25 + 1 + + haze_density + + 2 + 0 + 0 + 1 + + haze_horizon + + 0.04999999701976776123046875 + 0.1991560012102127075195313 + 0.1991560012102127075195313 + 1 + + lightnorm + + -0 + 0.3090172111988067626953125 + 0.951056420803070068359375 + 1 + + max_y + + 4000 + 0 + 0 + 1 + + preset_num + 10 + star_brightness + 0.5 + sun_angle + 3.4557521343231201171875 + sunlight_color + + 0.08999999612569808959960938 + 0.1799999922513961791992188 + 0.2999999821186065673828125 + 0.0999999940395355224609375 + + + diff --git a/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Night%20City%20Bright.xml b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Night%20City%20Bright.xml new file mode 100644 index 0000000000..19951bad6b --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Night%20City%20Bright.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0.1499999910593032836914063 + 0.449999988079071044921875 + 0.449999988079071044921875 + + blue_density + + 0.39999997615814208984375 + 0.39999997615814208984375 + 0.39999997615814208984375 + 0.199999988079071044921875 + + blue_horizon + + 0.7999999523162841796875 + 0.599999964237213134765625 + 0.39999997615814208984375 + 0.39999997615814208984375 + + cloud_color + + 0.699999988079071044921875 + 0.39999997615814208984375 + 0.2999999821186065673828125 + 0.699999988079071044921875 + + cloud_pos_density1 + + 0.5 + 0.5 + 0.04999999701976776123046875 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0 + 1 + + cloud_scale + + 0.07000000029802322387695313 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.1399993896484375 + 10.0109996795654296875 + + cloud_shadow + + 0.5 + 0 + 0 + 1 + + density_multiplier + + 4.999999873689375817775726e-05 + 0 + 0 + 1 + + distance_multiplier + + 10 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 2 + 0 + 0 + 1 + + glow + + 20 + 0.001000000047497451305389404 + -1.25 + 1 + + haze_density + + 2 + 0 + 0 + 1 + + haze_horizon + + 0.04999999701976776123046875 + 0.1991560012102127075195313 + 0.1991560012102127075195313 + 1 + + lightnorm + + -0 + 0.3090172111988067626953125 + 0.951056420803070068359375 + 1 + + max_y + + 4000 + 0 + 0 + 1 + + preset_num + 10 + star_brightness + 0.5 + sun_angle + 3.4557521343231201171875 + sunlight_color + + 0.1799999922513961791992188 + 0.1799999922513961791992188 + 0.1799999922513961791992188 + 0.1799999922513961791992188 + + + diff --git a/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Night%20City.xml b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Night%20City.xml new file mode 100644 index 0000000000..8fa2e039f5 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Night%20City.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0.1499999910593032836914063 + 0.449999988079071044921875 + 0.449999988079071044921875 + + blue_density + + 0.39999997615814208984375 + 0.39999997615814208984375 + 0.39999997615814208984375 + 0.199999988079071044921875 + + blue_horizon + + 0.7999999523162841796875 + 0.599999964237213134765625 + 0.39999997615814208984375 + 0.39999997615814208984375 + + cloud_color + + 0.699999988079071044921875 + 0.39999997615814208984375 + 0.2999999821186065673828125 + 0.699999988079071044921875 + + cloud_pos_density1 + + 0.5 + 0.5 + 0.04999999701976776123046875 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0 + 1 + + cloud_scale + + 0.07000000029802322387695313 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.1399993896484375 + 10.0109996795654296875 + + cloud_shadow + + 0.5 + 0 + 0 + 1 + + density_multiplier + + 4.999999873689375817775726e-05 + 0 + 0 + 1 + + distance_multiplier + + 10 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1 + 0 + 0 + 1 + + glow + + 20 + 0.001000000047497451305389404 + -1.25 + 1 + + haze_density + + 2 + 0 + 0 + 1 + + haze_horizon + + 0.04999999701976776123046875 + 0.1991560012102127075195313 + 0.1991560012102127075195313 + 1 + + lightnorm + + -0 + 0.3090172111988067626953125 + 0.951056420803070068359375 + 1 + + max_y + + 4000 + 0 + 0 + 1 + + preset_num + 10 + star_brightness + 0.5 + sun_angle + 3.4557521343231201171875 + sunlight_color + + 0.1799999922513961791992188 + 0.1799999922513961791992188 + 0.1799999922513961791992188 + 0.1799999922513961791992188 + + + diff --git a/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Night%20Cloudy.xml b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Night%20Cloudy.xml new file mode 100644 index 0000000000..92c786b825 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Night%20Cloudy.xml @@ -0,0 +1,106 @@ + + + ambient + + 0.04499999806284904479980469 + 0.06749998778104782104492188 + 0.08999999612569808959960938 + 0.02999999932944774627685547 + + blue_density + + 2 + 2 + 2 + 1 + + blue_horizon + + 0.5 + 0.5 + 0.5 + 0.25 + + cloud_color + + 0.1400000005960464477539063 + 0.1400000005960464477539063 + 0.1400000005960464477539063 + 0.1400000005960464477539063 + + cloud_pos_density1 + + 1 + 1 + 0.25 + 1 + + cloud_pos_density2 + + 1.6884100437164306640625 + 1 + 0 + 1 + + cloud_scale + 0.2000000029802322387695313 + cloud_scroll_rate + + 10.3999996185302734375 + 10 + + cloud_shadow + 0.599999964237213134765625 + density_multiplier + 4.999999873689375817775726e-05 + distance_multiplier + 7 + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 0.75 + 0 + 0 + 1 + + glow + + 10 + 0.001000000047497451305389404 + -0.449999988079071044921875 + 1 + + haze_density + 4 + haze_horizon + 0 + lightnorm + + 0 + 0 + -1 + 0 + + max_y + 1 + preset_num + 22 + star_brightness + 0 + sun_angle + 3.1415927410125732421875 + sunlight_color + + 0 + 0 + 0 + 0 + + + diff --git a/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Night%20Rainy.xml b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Night%20Rainy.xml new file mode 100644 index 0000000000..522c661095 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Night%20Rainy.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0 + 0 + 0 + + blue_density + + 2 + 2 + 2 + 1 + + blue_horizon + + 0.1999999731779098510742188 + 0.1999999731779098510742188 + 0.1999999731779098510742188 + 0.0999999940395355224609375 + + cloud_color + + 0.2999999821186065673828125 + 0.2999999821186065673828125 + 0.2999999821186065673828125 + 0.2999999821186065673828125 + + cloud_pos_density1 + + 1 + 1 + 0.2999999821186065673828125 + 1 + + cloud_pos_density2 + + 1.6884100437164306640625 + 1 + 0 + 1 + + cloud_scale + + 0.07000000029802322387695313 + 0 + 0 + 1 + + cloud_scroll_rate + + 11 + 10 + + cloud_shadow + + 0.66999995708465576171875 + 0 + 0 + 1 + + density_multiplier + + 0.0008999999845400452613830566 + 0 + 0 + 1 + + distance_multiplier + + 32.200000762939453125 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 0.39999997615814208984375 + 0 + 0 + 1 + + glow + + 0.200002193450927734375 + 0.001000000047497451305389404 + -0.2499999850988388061523438 + 1 + + haze_density + + 0 + 0 + 0 + 1 + + haze_horizon + + 0.0999999940395355224609375 + 0.1991560012102127075195313 + 0.1991560012102127075195313 + 1 + + lightnorm + + 0 + 0.876306593418121337890625 + -0.4817537963390350341796875 + 0 + + max_y + + 314 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0 + sun_angle + 2.0734512805938720703125 + sunlight_color + + 0.08999998867511749267578125 + 0.1799999773502349853515625 + 0.269999980926513671875 + 0.08999999612569808959960938 + + + diff --git a/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Night.xml b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Night.xml new file mode 100644 index 0000000000..a1be61d2f9 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Night.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0.1499999910593032836914063 + 0.4500000178813934326171875 + 0.1499999910593032836914063 + + blue_density + + 0.39999997615814208984375 + 0.39999997615814208984375 + 0.39999997615814208984375 + 0.199999988079071044921875 + + blue_horizon + + 0.4000000059604644775390625 + 0.599999725818634033203125 + 0.800000011920928955078125 + 0.39999997615814208984375 + + cloud_color + + 0.329999983310699462890625 + 0.329999983310699462890625 + 0.329999983310699462890625 + 0.329999983310699462890625 + + cloud_pos_density1 + + 0.5 + 0.5 + 0.0999999940395355224609375 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0 + 1 + + cloud_scale + + 0.07000000029802322387695313 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.1399993896484375 + 10.0109996795654296875 + + cloud_shadow + + 0.39999997615814208984375 + 0 + 0 + 1 + + density_multiplier + + 4.999999873689375817775726e-05 + 0 + 0 + 1 + + distance_multiplier + + 10 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1 + 0 + 0 + 1 + + glow + + 20 + 0.001000000047497451305389404 + -1.25 + 1 + + haze_density + + 2 + 0 + 0 + 1 + + haze_horizon + + 0.04999999701976776123046875 + 0.1991560012102127075195313 + 0.1991560012102127075195313 + 1 + + lightnorm + + -0 + 0.3090172111988067626953125 + 0.951056420803070068359375 + 1 + + max_y + + 4000 + 0 + 0 + 1 + + preset_num + 10 + star_brightness + 0.5 + sun_angle + 3.4557521343231201171875 + sunlight_color + + 0.08999999612569808959960938 + 0.1799999922513961791992188 + 0.2999999821186065673828125 + 0.0999999940395355224609375 + + + diff --git a/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Studio%201.xml b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Studio%201.xml new file mode 100644 index 0000000000..b299d5c02b --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Studio%201.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.599999964237213134765625 + 0.599999964237213134765625 + 0.599999964237213134765625 + 0.199999988079071044921875 + + blue_density + + 2 + 2 + 2 + 1 + + blue_horizon + + 0.599999964237213134765625 + 0.599999964237213134765625 + 0.599999964237213134765625 + 0.2999999821186065673828125 + + cloud_color + + 0.2999999821186065673828125 + 0.2999999821186065673828125 + 0.2999999821186065673828125 + 0.2999999821186065673828125 + + cloud_pos_density1 + + 1 + 1 + 0.25 + 1 + + cloud_pos_density2 + + 1.6884100437164306640625 + 1 + 0 + 1 + + cloud_scale + + 0.07000000029802322387695313 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.3999996185302734375 + 10 + + cloud_shadow + + 0.61000001430511474609375 + 0 + 0 + 1 + + density_multiplier + + 9.999999747378751635551453e-05 + 0 + 0 + 1 + + distance_multiplier + + 5 + 0 + 0 + 1 + + east_angle + 1.06814157962799072265625 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1 + 0 + 0 + 1 + + glow + + 0.200002193450927734375 + 0.001000000047497451305389404 + -0.199999988079071044921875 + 1 + + haze_density + + 4 + 0 + 0 + 1 + + haze_horizon + + 0.2099999934434890747070313 + 0.1991560012102127075195313 + 0.1991560012102127075195313 + 1 + + lightnorm + + 0.38304769992828369140625 + 0.89940512180328369140625 + -0.2105822265148162841796875 + 0 + + max_y + + 0 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0 + sun_angle + 2.0231859683990478515625 + sunlight_color + + 1.5 + 1.5 + 1.5 + 0.5 + + + diff --git a/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Studio%20Spotlight.xml b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Studio%20Spotlight.xml new file mode 100644 index 0000000000..7e919afff1 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Studio%20Spotlight.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0 + 0 + 0 + + blue_density + + 0 + 0 + 0 + 0 + + blue_horizon + + 0 + 0 + 0 + 0 + + cloud_color + + 0.2999999821186065673828125 + 0.2999999821186065673828125 + 0.2999999821186065673828125 + 0.2999999821186065673828125 + + cloud_pos_density1 + + 1 + 1 + 0.25 + 1 + + cloud_pos_density2 + + 1.6884100437164306640625 + 1 + 0 + 1 + + cloud_scale + + 0.07000000029802322387695313 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.3999996185302734375 + 10 + + cloud_shadow + + 0 + 0 + 0 + 1 + + density_multiplier + + 0 + 0 + 0 + 1 + + distance_multiplier + + 100 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1 + 0 + 0 + 1 + + glow + + 0.200002193450927734375 + 0.001000000047497451305389404 + -0.199999988079071044921875 + 1 + + haze_density + + 1 + 0 + 0 + 1 + + haze_horizon + + 0.2099999934434890747070313 + 0.1991560012102127075195313 + 0.1991560012102127075195313 + 1 + + lightnorm + + 0 + 0.587785184383392333984375 + -0.80901706218719482421875 + 0 + + max_y + + 0 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0 + sun_angle + 2.51327419281005859375 + sunlight_color + + 2.009999752044677734375 + 2.009999752044677734375 + 2.009999752044677734375 + 0.66999995708465576171875 + + + diff --git a/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Sunrise.xml b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Sunrise.xml new file mode 100644 index 0000000000..1145640848 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Sunrise.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0.449999988079071044921875 + 0.89999997615814208984375 + 0.2999999821186065673828125 + + blue_density + + 0 + 0.2999999821186065673828125 + 0.39999997615814208984375 + 0.39999997615814208984375 + + blue_horizon + + 0 + 0.39999997615814208984375 + 0.7999999523162841796875 + 0.7999999523162841796875 + + cloud_color + + 0.25 + 0.25 + 0.25 + 0.25 + + cloud_pos_density1 + + 1 + 1 + 0.189999997615814208984375 + 1 + + cloud_pos_density2 + + 1.6884100437164306640625 + 0 + 0.04999999701976776123046875 + 1 + + cloud_scale + + 0.07000000029802322387695313 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.19999980926513671875 + 10.0109996795654296875 + + cloud_shadow + + 0.5 + 0 + 0 + 1 + + density_multiplier + + 9.999999747378751635551453e-05 + 0 + 0 + 1 + + distance_multiplier + + 6 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 0.5 + 0 + 0 + 1 + + glow + + 38 + 0.001000000047497451305389404 + -0.2499999850988388061523438 + 1 + + haze_density + + 0.199999988079071044921875 + 0 + 0 + 1 + + haze_horizon + + 0.5 + 0.1991560012102127075195313 + 0.1991560012102127075195313 + 1 + + lightnorm + + -0 + 0.309017002582550048828125 + 0.951056540012359619140625 + 0 + + max_y + + 4000 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0 + sun_angle + 0.31415927410125732421875 + sunlight_color + + 2.9999997615814208984375 + 1.19999992847442626953125 + 0.449999988079071044921875 + 1 + + + diff --git a/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Sunset.xml b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Sunset.xml new file mode 100644 index 0000000000..3fe84a5050 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/%5BPyFX%5D%20Sunset.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0.269999980926513671875 + 0.4500000178813934326171875 + 0.1499999910593032836914063 + + blue_density + + 0.0999999940395355224609375 + 0.0999999940395355224609375 + 0.0999999940395355224609375 + 0.04999999701976776123046875 + + blue_horizon + + 0 + 0.199999988079071044921875 + 0.5 + 0.5 + + cloud_color + + 0 + 0.02999999932944774627685547 + 0.05999999865889549255371094 + 0.05999999865889549255371094 + + cloud_pos_density1 + + 1 + 1 + 0.1199999973177909851074219 + 1 + + cloud_pos_density2 + + 1.6884100437164306640625 + 0 + 0.04999999701976776123046875 + 1 + + cloud_scale + + 0.07000000029802322387695313 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.19999980926513671875 + 10.0109996795654296875 + + cloud_shadow + + 0.5 + 0 + 0 + 1 + + density_multiplier + + 9.999999747378751635551453e-05 + 0 + 0 + 1 + + distance_multiplier + + 6 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1 + 0 + 0 + 1 + + glow + + 10 + 0.001000000047497451305389404 + -0.4999999701976776123046875 + 1 + + haze_density + + 0.75 + 0 + 0 + 1 + + haze_horizon + + 0.199999988079071044921875 + 0.1991560012102127075195313 + 0.1991560012102127075195313 + 1 + + lightnorm + + 0 + 0.1253329664468765258789063 + -0.992114722728729248046875 + 0 + + max_y + + 4000 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0.66999995708465576171875 + sun_angle + 3.01592922210693359375 + sunlight_color + + 3 + 1.19999992847442626953125 + 0.2999999821186065673828125 + 3 + + + diff --git a/indra/newview/app_settings/windlight/skies/AnaLu%20%252Astudio%252A%205.xml b/indra/newview/app_settings/windlight/skies/AnaLu%20%252Astudio%252A%205.xml deleted file mode 100644 index b7c6d047f6..0000000000 --- a/indra/newview/app_settings/windlight/skies/AnaLu%20%252Astudio%252A%205.xml +++ /dev/null @@ -1,141 +0,0 @@ - - - ambient - - 2.0099997520446777 - 1.9199999570846558 - 1.8899999856948853 - 2.0099997520446777 - - blue_density - - 0.63999998569488525 - 1.1799999475479126 - 2 - 2 - - blue_horizon - - 0.23999999463558197 - 0.23999999463558197 - 0.31999999284744263 - 0.31999999284744263 - - cloud_color - - 0.39050509865536398 - 0.39050509865536398 - 0.39050509865536398 - 0.39050509865536398 - - cloud_pos_density1 - - 1.6884100437164307 - 0.52609699964523315 - 1 - 1 - - cloud_pos_density2 - - 1.6884100437164307 - 0.52609699964523315 - 0.125 - 1 - - cloud_scale - - 0.41999998254906856 - 0 - 0 - 1 - - cloud_scroll_rate - - 10.199999735331062 - 10.010999579794088 - - cloud_shadow - - 0.12999999523162842 - 0 - 0 - 1 - - density_multiplier - - 0.00017999998391111764 - 0 - 0 - 1 - - distance_multiplier - - 2 - 0 - 0 - 1 - - east_angle - 0 - enable_cloud_scroll - - 1 - 1 - - gamma - - 1.1499999761581421 - 0 - 0 - 1 - - glow - - 4.9999998807907104 - 0.0010000000478643939 - -0.47999998436731417 - 1 - - haze_density - - 0.64999997615814209 - 0 - 0 - 1 - - haze_horizon - - 0.08999999612569809 - 0.19915600121021271 - 0.19915600121021271 - 1 - - lightnorm - - 0 - 0 - 1 - 0 - - max_y - - 188 - 0 - 0 - 1 - - preset_num - 22 - star_brightness - 0 - sun_angle - 0 - sunlight_color - - 2.5799999237060547 - 2.5799999237060547 - 2.5799999237060547 - 2.5799999237060547 - - - diff --git a/indra/newview/app_settings/windlight/skies/Nacon%27s%20Afternoon.xml b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Afternoon.xml new file mode 100644 index 0000000000..f454c065ed --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Afternoon.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.77999997138977051 + 0.77999997138977051 + 0.77999997138977051 + 0.25999999046325684 + + blue_density + + 0 + 2 + 2 + 2 + + blue_horizon + + 0.2800000011920929 + 0.44679245352745056 + 0.56000000238418579 + 0.56000000238418579 + + cloud_color + + 0.14424242079257965 + 0.14424242079257965 + 0.17000000178813934 + 0.17000000178813934 + + cloud_pos_density1 + + 1 + 1 + 0.76999998092651367 + 1 + + cloud_pos_density2 + + 1 + 1 + 0.08999999612569809 + 1 + + cloud_scale + + 0.14000000059604645 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.949999809265137 + 10.659999847412109 + + cloud_shadow + + 0.25 + 0 + 0 + 1 + + density_multiplier + + 2.9999999242136255e-005 + 0 + 0 + 1 + + distance_multiplier + + 2 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 2.5 + 0 + 0 + 1 + + glow + + 0.19999980926513672 + 0.0010000000474974513 + -0.59999996423721313 + 1 + + haze_density + + 2 + 0 + 0 + 1 + + haze_horizon + + 0.23999999463558197 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0 + 1 + -4.3711388286737929e-008 + 0 + + max_y + + 4000 + 0 + 0 + 1 + + preset_num + 21 + star_brightness + 0.22999998927116394 + sun_angle + 1.5707963705062866 + sunlight_color + + 0.29999998211860657 + 0.29999998211860657 + 0.14999999105930328 + 0.099999994039535522 + + + diff --git a/indra/newview/app_settings/windlight/skies/Nacon%27s%20Dawn.xml b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Dawn.xml new file mode 100644 index 0000000000..e04ce021c0 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Dawn.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.44999998807907104 + 0.44999998807907104 + 0.44999998807907104 + 0.14999999105930328 + + blue_density + + 0.19999998807907104 + 1 + 2 + 2 + + blue_horizon + + 1.8600000143051147 + 0.44679245352745056 + 0.3139621913433075 + 1.8600000143051147 + + cloud_color + + 0.14000000059604645 + 0.070000000298023224 + 0 + 0.14000000059604645 + + cloud_pos_density1 + + 1 + 1 + 1 + 1 + + cloud_pos_density2 + + 1 + 1 + 0.08999999612569809 + 1 + + cloud_scale + + 0.14000000059604645 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.949999809265137 + 10.659999847412109 + + cloud_shadow + + 0.19999998807907104 + 0 + 0 + 1 + + density_multiplier + + 7.9999997979030013e-005 + 0 + 0 + 1 + + distance_multiplier + + 100 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 2.5 + 0 + 0 + 1 + + glow + + 0.19999980926513672 + 0.0010000000474974513 + -0.59999996423721313 + 1 + + haze_density + + 1.5699999332427979 + 0 + 0 + 1 + + haze_horizon + + 0.23999999463558197 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0 + 0.32094338536262512 + -0.94709837436676025 + 0 + + max_y + + 4000 + 0 + 0 + 1 + + preset_num + 21 + star_brightness + 0.22999998927116394 + sun_angle + 2.8148672580718994 + sunlight_color + + 0.08999999612569809 + 0.08999999612569809 + 0.044999998062849045 + 0.029999999329447746 + + + diff --git a/indra/newview/app_settings/windlight/skies/Nacon%27s%20Day%20Mood.xml b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Day%20Mood.xml new file mode 100644 index 0000000000..6aee8d6143 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Day%20Mood.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.44999998807907104 + 0.44999998807907104 + 0.44999998807907104 + 0.14999999105930328 + + blue_density + + 0.23999999463558197 + 1 + 2 + 2 + + blue_horizon + + 0.63999998569488525 + 0.44679245352745056 + 0.3139621913433075 + 0.31999999284744263 + + cloud_color + + 0.14000000059604645 + 0.070000000298023224 + 0 + 0.14000000059604645 + + cloud_pos_density1 + + 1 + 1 + 1 + 1 + + cloud_pos_density2 + + 1 + 1 + 0.08999999612569809 + 1 + + cloud_scale + + 0.14000000059604645 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.949999809265137 + 10.659999847412109 + + cloud_shadow + + 0.17999999225139618 + 0 + 0 + 1 + + density_multiplier + + 2.9999999242136255e-005 + 0 + 0 + 1 + + distance_multiplier + + 2 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 2.5 + 0 + 0 + 1 + + glow + + 0.19999980926513672 + 0.0010000000474974513 + -0.59999996423721313 + 1 + + haze_density + + 2 + 0 + 0 + 1 + + haze_horizon + + 0.23999999463558197 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + -0 + 0.62769138813018799 + 0.77846229076385498 + 0 + + max_y + + 4000 + 0 + 0 + 1 + + preset_num + 21 + star_brightness + 0.22999998927116394 + sun_angle + 0.67858403921127319 + sunlight_color + + 0.08999999612569809 + 0.08999999612569809 + 0.044999998062849045 + 0.029999999329447746 + + + diff --git a/indra/newview/app_settings/windlight/skies/Nacon%27s%20Day%20Mood2.xml b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Day%20Mood2.xml new file mode 100644 index 0000000000..89ab499a32 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Day%20Mood2.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.44999998807907104 + 0.44999998807907104 + 0.44999998807907104 + 0.14999999105930328 + + blue_density + + 0.23999999463558197 + 1 + 2 + 2 + + blue_horizon + + 0.63999998569488525 + 0.44679245352745056 + 0.3139621913433075 + 0.31999999284744263 + + cloud_color + + 0.14000000059604645 + 0.070000000298023224 + 0 + 0.14000000059604645 + + cloud_pos_density1 + + 1 + 1 + 0.45999997854232788 + 1 + + cloud_pos_density2 + + 1 + 1 + 0.08999999612569809 + 1 + + cloud_scale + + 0.14000000059604645 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.949999809265137 + 10.659999847412109 + + cloud_shadow + + 0.25 + 0 + 0 + 1 + + density_multiplier + + 2.9999999242136255e-005 + 0 + 0 + 1 + + distance_multiplier + + 2 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 2.5 + 0 + 0 + 1 + + glow + + 0.19999980926513672 + 0.0010000000474974513 + -0.59999996423721313 + 1 + + haze_density + + 2 + 0 + 0 + 1 + + haze_horizon + + 0.23999999463558197 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0 + 0.53051102161407471 + -0.84767806529998779 + 0 + + max_y + + 4000 + 0 + 0 + 1 + + preset_num + 21 + star_brightness + 0.22999998927116394 + sun_angle + 2.5823893547058105 + sunlight_color + + 0.08999999612569809 + 0.08999999612569809 + 0.044999998062849045 + 0.029999999329447746 + + + diff --git a/indra/newview/app_settings/windlight/skies/Nacon%27s%20Fog.xml b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Fog.xml new file mode 100644 index 0000000000..8036eaf893 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Fog.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.17999999225139618 + 0.23999999463558197 + 0.31000000238418579 + 0.31000000238418579 + + blue_density + + 1 + 0.81000000238418579 + 0.62000000476837158 + 1 + + blue_horizon + + 0 + 0.2199999988079071 + 0.45999997854232788 + 0.45999997854232788 + + cloud_color + + 0.69999998807907104 + 0.69999998807907104 + 0.69999998807907104 + 0.69999998807907104 + + cloud_pos_density1 + + 0.5 + 0.5 + 0.53999996185302734 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.125 + 1 + + cloud_scale + + 0.29999998211860657 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.49940013885498 + 10.01099967956543 + + cloud_shadow + + 0.39999997615814209 + 0 + 0 + 1 + + density_multiplier + + 0.00075000000651925802 + 0 + 0 + 1 + + distance_multiplier + + 30.200000762939453 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 2.1800000667572021 + 0 + 0 + 1 + + glow + + 3.7999999523162842 + 0.0010000000474974513 + -0.5 + 1 + + haze_density + + 2.7200000286102295 + 0 + 0 + 1 + + haze_horizon + + 0.63999998569488525 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0 + 0.99361127614974976 + -0.11285652220249176 + 0 + + max_y + + 3447 + 0 + 0 + 1 + + preset_num + 18 + star_brightness + 0 + sun_angle + 1.6838937997817993 + sunlight_color + + 1.1399999856948853 + 1.1399999856948853 + 1.1399999856948853 + 0.37999999523162842 + + + diff --git a/indra/newview/app_settings/windlight/skies/Nacon%27s%20Ghost.xml b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Ghost.xml new file mode 100644 index 0000000000..ea3ce7f4e3 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Ghost.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.32999998331069946 + 0.32999998331069946 + 0.32999998331069946 + 0.10999999940395355 + + blue_density + + 0.079873383045196533 + 0.21999761462211609 + 0.43999999761581421 + 0.2199999988079071 + + blue_horizon + + 0.21535232663154602 + 0.42697387933731079 + 0.5 + 0.25 + + cloud_color + + 0.2199999988079071 + 0.2199999988079071 + 0.2199999988079071 + 0.2199999988079071 + + cloud_pos_density1 + + 1 + 1 + 0.070000000298023224 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.125 + 1 + + cloud_scale + + 0.14000000059604645 + 0 + 0 + 1 + + cloud_scroll_rate + + 11.539999961853027 + 10.01099967956543 + + cloud_shadow + + 0.44999998807907104 + 0 + 0 + 1 + + density_multiplier + + 0.00042999998549930751 + 0 + 0 + 1 + + distance_multiplier + + 8.1000003814697266 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1 + 0 + 0 + 1 + + glow + + 5 + 0.0010000000474974513 + -0.51999998092651367 + 1 + + haze_density + + 0.75 + 0 + 0 + 1 + + haze_horizon + + 0.18000000715255737 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0 + 0.99992102384567261 + -0.012566247954964638 + 1 + + max_y + + 718.70001220703125 + 0 + 0 + 1 + + preset_num + 23 + star_brightness + 2 + sun_angle + 4.7249555587768555 + sunlight_color + + 0 + 0 + 0 + 0 + + + diff --git a/indra/newview/app_settings/windlight/skies/Nacon%27s%20Morning.xml b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Morning.xml new file mode 100644 index 0000000000..a7f4e06cf5 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Morning.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.69999998807907104 + 0.57749998569488525 + 0.4987500011920929 + 0.69999998807907104 + + blue_density + + 0.45999997854232788 + 0.77999997138977051 + 1 + 1 + + blue_horizon + + 0.08999999612569809 + 0.039999999105930328 + 0 + 0.099999994039535522 + + cloud_color + + 0.50999999046325684 + 0.50999999046325684 + 0.50999999046325684 + 1 + + cloud_pos_density1 + + 0.5 + 0.5 + 1 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.125 + 1 + + cloud_scale + + 0.41999998688697815 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.49940013885498 + 10.01099967956543 + + cloud_shadow + + 0.37000000476837158 + 0 + 0 + 1 + + density_multiplier + + 7.0000001869630069e-005 + 0 + 0 + 1 + + distance_multiplier + + 15.5 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1.6100000143051147 + 0 + 0 + 1 + + glow + + 5 + 0.0010000000474974513 + -0.33000001311302185 + 1 + + haze_density + + 3.5099999904632568 + 0 + 0 + 1 + + haze_horizon + + 0.26999998092651367 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0 + 0.062790460884571075 + -0.99802672863006592 + 0 + + max_y + + 2842 + 0 + 0 + 1 + + preset_num + 21 + star_brightness + 0 + sun_angle + 3.0787608623504639 + sunlight_color + + 3 + 3 + 3 + 1 + + + diff --git a/indra/newview/app_settings/windlight/skies/Nacon%27s%20Morning2.xml b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Morning2.xml new file mode 100644 index 0000000000..6d92b7628f --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Morning2.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.69999997394426039 + 0.57749997886164373 + 0.49874999905271622 + 0.69999995555196648 + + blue_density + + 0.45999996583802716 + 0.77999998620579447 + 1.0000000630106456 + 1.0000000630106456 + + blue_horizon + + 0.09000002999817136 + 0.040000024113538313 + 1.9248282967510022e-008 + 0.10000000769751693 + + cloud_color + + 0.50999996864795882 + 0.5099999643564237 + 0.50999996006488857 + 0.99999994897842548 + + cloud_pos_density1 + + 0.5 + 0.5 + 1.0000000017030004 + 1.0000000017030004 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.12499999806710704 + 1.0000000017030004 + + cloud_scale + + 0.41999997043609838 + 0 + 0 + 1.0000000017030004 + + cloud_scroll_rate + + 10.499400184360695 + 10.010999736402823 + + cloud_shadow + + 0.37000000476837158 + 0 + 0 + 1.0000000017030004 + + density_multiplier + + 6.9999999536534113e-005 + 0 + 0 + 1.0000000017030004 + + distance_multiplier + + 15.499999198743296 + 0 + 0 + 1.0000000017030004 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1.6100000716107488 + 0 + 0 + 1.0000000017030004 + + glow + + 4.9999997142382933 + 0.0010000000492004502 + -0.33000003022807256 + 1.0000000017030004 + + haze_density + + 3.5099999038662446 + 0 + 0 + 1.0000000017030004 + + haze_horizon + + 0.26999997954709531 + 0.19915600154937518 + 0.19915600154937518 + 1.0000000017030004 + + lightnorm + + 0 + 0.069060027599334717 + 0.99761247634887695 + 0 + + max_y + + 2842.0000758341921 + 0 + 0 + 1.0000000017030004 + + preset_num + 21 + star_brightness + 1.4100757894652816e-008 + sun_angle + 0.069115042686462402 + sunlight_color + + 2.9999998267037533 + 2.9999998267037533 + 2.9999998239449095 + 0.99999994223458455 + + + diff --git a/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%2010am.xml b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%2010am.xml new file mode 100644 index 0000000000..48f1ef09a1 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%2010am.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.77999997138977051 + 0.77999997138977051 + 0.77999997138977051 + 0.25999999046325684 + + blue_density + + 0 + 2 + 2 + 2 + + blue_horizon + + 0.2800000011920929 + 0.44679245352745056 + 0.56000000238418579 + 0.56000000238418579 + + cloud_color + + 0.12999999523162842 + 0.14424242079257965 + 0.11999999731779099 + 0.14999999105930328 + + cloud_pos_density1 + + 0.53999996185302734 + 0.50999999046325684 + 0.099999994039535522 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.50999999046325684 + 1 + + cloud_scale + + 0.62000000476837158 + 0 + 0 + 1 + + cloud_scroll_rate + + 10 + 10 + + cloud_shadow + + 0.70999997854232788 + 0 + 0 + 1 + + density_multiplier + + 2.9999999242136255e-005 + 0 + 0 + 1 + + distance_multiplier + + 2 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 0 + 0 + + gamma + + 2.5 + 0 + 0 + 1 + + glow + + 1.1999988555908203 + 0.0010000000474974513 + -0.59999996423721313 + 1 + + haze_density + + 2 + 0 + 0 + 1 + + haze_horizon + + 0.23999999463558197 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + -0 + 0.49818512797355652 + 0.86707067489624023 + 0 + + max_y + + 1400 + 0 + 0 + 1 + + preset_num + 21 + star_brightness + 0.22999998927116394 + sun_angle + 0.52150440216064453 + sunlight_color + + 0.29999998211860657 + 0.29999998211860657 + 0.14999999105930328 + 0.099999994039535522 + + + diff --git a/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%204%3A30am.xml b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%204%3A30am.xml new file mode 100644 index 0000000000..9746250a36 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%204%3A30am.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.84000003337860107 + 0.84000003337860107 + 0.84000003337860107 + 0.2800000011920929 + + blue_density + + 1.2600002288818359 + 2 + 2 + 1 + + blue_horizon + + 0 + 0.022568579763174057 + 0.039999999105930328 + 0.019999999552965164 + + cloud_color + + 0 + 0 + 0 + 0 + + cloud_pos_density1 + + 0.53999996185302734 + 0.50999999046325684 + 0.099999994039535522 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.50999999046325684 + 1 + + cloud_scale + + 0.62000000476837158 + 0 + 0 + 1 + + cloud_scroll_rate + + 20 + 20 + + cloud_shadow + + 0.62000000476837158 + 0 + 0 + 1 + + density_multiplier + + 0.00032999998074956238 + 0 + 0 + 1 + + distance_multiplier + + 8.1000003814697266 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 0 + 0 + + gamma + + 0.29999998211860657 + 0 + 0 + 1 + + glow + + 20 + 0.0010000000474974513 + -1.1000000238418579 + 1 + + haze_density + + 0.31999999284744263 + 0 + 0 + 1 + + haze_horizon + + 0.41999998688697815 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0 + 0.36227512359619141 + -0.93207120895385742 + 0 + + max_y + + 1369 + 0 + 0 + 1 + + preset_num + 18 + star_brightness + 0.63999998569488525 + sun_angle + 2.7708849906921387 + sunlight_color + + 0.32999998331069946 + 0.83719938993453979 + 0.84000003337860107 + 0.2800000011920929 + + + diff --git a/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%205am%20END.xml b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%205am%20END.xml new file mode 100644 index 0000000000..3cfff6d793 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%205am%20END.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.84000003337860107 + 0.84000003337860107 + 0.84000003337860107 + 0.2800000011920929 + + blue_density + + 1.2600002288818359 + 2 + 2 + 1 + + blue_horizon + + 0 + 0.022568579763174057 + 0.039999999105930328 + 0.019999999552965164 + + cloud_color + + 0 + 0 + 0 + 0 + + cloud_pos_density1 + + 0.53999996185302734 + 0.50999999046325684 + 0.099999994039535522 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.50999999046325684 + 1 + + cloud_scale + + 0.62000000476837158 + 0 + 0 + 1 + + cloud_scroll_rate + + 20 + 20 + + cloud_shadow + + 0.62000000476837158 + 0 + 0 + 1 + + density_multiplier + + 0.00032999998074956238 + 0 + 0 + 1 + + distance_multiplier + + 8.1000003814697266 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 0 + 0 + + gamma + + 0.29999998211860657 + 0 + 0 + 1 + + glow + + 20 + 0.0010000000474974513 + -1.1000000238418579 + 1 + + haze_density + + 0.31999999284744263 + 0 + 0 + 1 + + haze_horizon + + 0.41999998688697815 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + -0 + 1.7484555314695172e-007 + 1 + 0 + + max_y + + 1369 + 0 + 0 + 1 + + preset_num + 18 + star_brightness + 0.63999998569488525 + sun_angle + 6.2831854820251465 + sunlight_color + + 0.029999999329447746 + 0.83719938993453979 + 0.84000003337860107 + 0.2800000011920929 + + + diff --git a/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%205am%20START.xml b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%205am%20START.xml new file mode 100644 index 0000000000..44eb1a54a1 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%205am%20START.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.42000001668930054 + 0.42000001668930054 + 0.42000001668930054 + 0.14000000059604645 + + blue_density + + 1.2600002288818359 + 2 + 2 + 1 + + blue_horizon + + 0 + 0.022568579763174057 + 0.039999999105930328 + 0.019999999552965164 + + cloud_color + + 0 + 0 + 0 + 0 + + cloud_pos_density1 + + 0.53999996185302734 + 0.50999999046325684 + 0.099999994039535522 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.50999999046325684 + 1 + + cloud_scale + + 0.62000000476837158 + 0 + 0 + 1 + + cloud_scroll_rate + + 20 + 20 + + cloud_shadow + + 0.62000000476837158 + 0 + 0 + 1 + + density_multiplier + + 0.00032999998074956238 + 0 + 0 + 1 + + distance_multiplier + + 8.1000003814697266 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 0 + 0 + + gamma + + 0.29999998211860657 + 0 + 0 + 1 + + glow + + 20 + 0.0010000000474974513 + -1.1000000238418579 + 1 + + haze_density + + 0.31999999284744263 + 0 + 0 + 1 + + haze_horizon + + 0.41999998688697815 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + -0 + 0 + 1 + 0 + + max_y + + 1369 + 0 + 0 + 1 + + preset_num + 18 + star_brightness + 0.63999998569488525 + sun_angle + 0 + sunlight_color + + 0 + 0 + 0 + 0 + + + diff --git a/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%205am.xml b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%205am.xml new file mode 100644 index 0000000000..7a312df503 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%205am.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.84000003337860107 + 0.84000003337860107 + 0.84000003337860107 + 0.2800000011920929 + + blue_density + + 1.2600002288818359 + 2 + 2 + 1 + + blue_horizon + + 0 + 0.022568579763174057 + 0.039999999105930328 + 0.019999999552965164 + + cloud_color + + 0 + 0 + 0 + 0 + + cloud_pos_density1 + + 0.53999996185302734 + 0.50999999046325684 + 0.099999994039535522 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.50999999046325684 + 1 + + cloud_scale + + 0.62000000476837158 + 0 + 0 + 1 + + cloud_scroll_rate + + 20 + 20 + + cloud_shadow + + 0.62000000476837158 + 0 + 0 + 1 + + density_multiplier + + 0.00032999998074956238 + 0 + 0 + 1 + + distance_multiplier + + 8.1000003814697266 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 0 + 0 + + gamma + + 0.29999998211860657 + 0 + 0 + 1 + + glow + + 20 + 0.0010000000474974513 + -1.1000000238418579 + 1 + + haze_density + + 0.31999999284744263 + 0 + 0 + 1 + + haze_horizon + + 0.41999998688697815 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0 + 0 + -1 + 0 + + max_y + + 1369 + 0 + 0 + 1 + + preset_num + 18 + star_brightness + 0.63999998569488525 + sun_angle + 3.1415927410125732 + sunlight_color + + 0 + 0 + 0 + 0 + + + diff --git a/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%207%3A30pm.xml b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%207%3A30pm.xml new file mode 100644 index 0000000000..1d46458322 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%207%3A30pm.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.84000003337860107 + 0.84000003337860107 + 0.84000003337860107 + 0.2800000011920929 + + blue_density + + 1.2600002288818359 + 2 + 2 + 1 + + blue_horizon + + 0 + 0.022568579763174057 + 0.039999999105930328 + 0.019999999552965164 + + cloud_color + + 0 + 0 + 0 + 0 + + cloud_pos_density1 + + 0.53999996185302734 + 0.50999999046325684 + 0.099999994039535522 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.50999999046325684 + 1 + + cloud_scale + + 0.62000000476837158 + 0 + 0 + 1 + + cloud_scroll_rate + + 20 + 20 + + cloud_shadow + + 0.62000000476837158 + 0 + 0 + 1 + + density_multiplier + + 0.00032999998074956238 + 0 + 0 + 1 + + distance_multiplier + + 8.1000003814697266 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 0 + 0 + + gamma + + 0.29999998211860657 + 0 + 0 + 1 + + glow + + 20 + 0.0010000000474974513 + -1.1000000238418579 + 1 + + haze_density + + 0.31999999284744263 + 0 + 0 + 1 + + haze_horizon + + 0.41999998688697815 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + -0 + 0.33873793482780457 + 0.94088077545166016 + 0 + + max_y + + 1369 + 0 + 0 + 1 + + preset_num + 18 + star_brightness + 0.63999998569488525 + sun_angle + 0.34557521343231201 + sunlight_color + + 0.32999998331069946 + 0.83719938993453979 + 0.84000003337860107 + 0.2800000011920929 + + + diff --git a/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%208%3A30am.xml b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%208%3A30am.xml new file mode 100644 index 0000000000..87d406bc0a --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%208%3A30am.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.22411763608017388 + 0.25058822535416658 + 0.19764705338022287 + 0.18941175678197075 + + blue_density + + 0.21314870774677197 + 1.011764702165828 + 1.0647058807138134 + 1.0647058807138134 + + blue_horizon + + 0.032941176733549904 + 0.61014069170411545 + 1.0541176513012718 + 1.0541176513012718 + + cloud_color + + 0.12999999523162842 + 0.14000000059604645 + 0.11999999731779099 + 0.14000000059604645 + + cloud_pos_density1 + + 0.53999996185302734 + 0.50999999046325684 + 0.13529411745422026 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.50999999046325684 + 1 + + cloud_scale + + 0.62000000476837158 + 0 + 0 + 1 + + cloud_scroll_rate + + 20 + 20 + + cloud_shadow + + 0.70999997854232788 + 0 + 0 + 1 + + density_multiplier + + 2.9999999242136255e-005 + 0 + 0 + 1 + + distance_multiplier + + 1.1176470592617989 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 0 + 0 + + gamma + + 1.661764664224842 + 0 + 0 + 1 + + glow + + 0.31764675632995676 + 0.0010000000474974513 + -0.37941175534882965 + 1 + + haze_density + + 1.8764706009188119 + 0 + 0 + 1 + + haze_horizon + + 0.41647058541283888 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + -0 + 0.53738623857498169 + 0.84333628416061401 + 0 + + max_y + + 1678.5294129177928 + 0 + 0 + 1 + + preset_num + 18 + star_brightness + 0.02705882303416729 + sun_angle + 0.56733471155166626 + sunlight_color + + 0.4588235177625628 + 0.67058820565833765 + 0.38823530767332104 + 0.64705879520844012 + + + diff --git a/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%208am.xml b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%208am.xml new file mode 100644 index 0000000000..f30eb0d2d5 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%208am.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.77999997138977051 + 0.77999997138977051 + 0.77999997138977051 + 0.25999999046325684 + + blue_density + + 0 + 2 + 2 + 2 + + blue_horizon + + 0.2800000011920929 + 0.44679245352745056 + 0.56000000238418579 + 0.56000000238418579 + + cloud_color + + 0.12999999523162842 + 0.14424242079257965 + 0.11999999731779099 + 0.14999999105930328 + + cloud_pos_density1 + + 0.53999996185302734 + 0.50999999046325684 + 0.099999994039535522 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.50999999046325684 + 1 + + cloud_scale + + 0.62000000476837158 + 0 + 0 + 1 + + cloud_scroll_rate + + 10 + 10 + + cloud_shadow + + 0.70999997854232788 + 0 + 0 + 1 + + density_multiplier + + 2.9999999242136255e-005 + 0 + 0 + 1 + + distance_multiplier + + 2 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 0 + 0 + + gamma + + 2.5 + 0 + 0 + 1 + + glow + + 1.1999988555908203 + 0.0010000000474974513 + -0.59999996423721313 + 1 + + haze_density + + 2 + 0 + 0 + 1 + + haze_horizon + + 0.23999999463558197 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + -0 + 0.49818512797355652 + 0.86707067489624023 + 0 + + max_y + + 4000 + 0 + 0 + 1 + + preset_num + 21 + star_brightness + 0.22999998927116394 + sun_angle + 0.52150440216064453 + sunlight_color + + 0.29999998211860657 + 0.29999998211860657 + 0.14999999105930328 + 0.099999994039535522 + + + diff --git a/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%20Dark%20START.xml b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%20Dark%20START.xml new file mode 100644 index 0000000000..310d08424e --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%20Dark%20START.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0 + 0 + 0 + + blue_density + + 1.2600002288818359 + 2 + 2 + 1 + + blue_horizon + + 0 + 0.022568579763174057 + 0.039999999105930328 + 0.019999999552965164 + + cloud_color + + 0 + 0 + 0 + 0 + + cloud_pos_density1 + + 0.53999996185302734 + 0.50999999046325684 + 0.099999994039535522 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.50999999046325684 + 1 + + cloud_scale + + 0.62000000476837158 + 0 + 0 + 1 + + cloud_scroll_rate + + 20 + 20 + + cloud_shadow + + 0.62000000476837158 + 0 + 0 + 1 + + density_multiplier + + 0.00032999998074956238 + 0 + 0 + 1 + + distance_multiplier + + 8.1000003814697266 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 0 + 0 + + gamma + + 0.61000001430511475 + 0 + 0 + 1 + + glow + + 20 + 0.0010000000474974513 + -1.1000000238418579 + 1 + + haze_density + + 0.31999999284744263 + 0 + 0 + 1 + + haze_horizon + + 0.41999998688697815 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + -0 + 0 + 1 + 0 + + max_y + + 1369 + 0 + 0 + 1 + + preset_num + 18 + star_brightness + 2 + sun_angle + 0 + sunlight_color + + 0.029999999329447746 + 0.83719938993453979 + 0.84000003337860107 + 0.2800000011920929 + + + diff --git a/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%20Midnight.xml b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%20Midnight.xml new file mode 100644 index 0000000000..7802c595c7 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%20Midnight.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.84000003337860107 + 0.84000003337860107 + 0.84000003337860107 + 0.2800000011920929 + + blue_density + + 1.2600002288818359 + 2 + 2 + 1 + + blue_horizon + + 0 + 0.022568579763174057 + 0.039999999105930328 + 0.019999999552965164 + + cloud_color + + 0 + 0 + 0 + 0 + + cloud_pos_density1 + + 0.53999996185302734 + 0.50999999046325684 + 0.099999994039535522 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.50999999046325684 + 1 + + cloud_scale + + 0.62000000476837158 + 0 + 0 + 1 + + cloud_scroll_rate + + 20 + 20 + + cloud_shadow + + 0.62000000476837158 + 0 + 0 + 1 + + density_multiplier + + 0.00032999998074956238 + 0 + 0 + 1 + + distance_multiplier + + 8.1000003814697266 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 0 + 0 + + gamma + + 0.29999998211860657 + 0 + 0 + 1 + + glow + + 20 + 0.0010000000474974513 + -0.85000002384185791 + 1 + + haze_density + + 0.31999999284744263 + 0 + 0 + 1 + + haze_horizon + + 0.41999998688697815 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0 + 1 + -4.3711388286737929e-008 + 0 + + max_y + + 1369 + 0 + 0 + 1 + + preset_num + 18 + star_brightness + 0.63999998569488525 + sun_angle + 1.5707963705062866 + sunlight_color + + 0.59999996423721313 + 0.83719938993453979 + 0.84000003337860107 + 0.2800000011920929 + + + diff --git a/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%20Night.xml b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%20Night.xml new file mode 100644 index 0000000000..60f35bad3d --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%20Night.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.84000003337860107 + 0.84000003337860107 + 0.84000003337860107 + 0.2800000011920929 + + blue_density + + 1.2600002288818359 + 2 + 2 + 1 + + blue_horizon + + 0 + 0.022568579763174057 + 0.039999999105930328 + 0.019999999552965164 + + cloud_color + + 0 + 0 + 0 + 0 + + cloud_pos_density1 + + 0.53999996185302734 + 0.50999999046325684 + 0.099999994039535522 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.50999999046325684 + 1 + + cloud_scale + + 0.62000000476837158 + 0 + 0 + 1 + + cloud_scroll_rate + + 20 + 20 + + cloud_shadow + + 0.62000000476837158 + 0 + 0 + 1 + + density_multiplier + + 0.00032999998074956238 + 0 + 0 + 1 + + distance_multiplier + + 8.1000003814697266 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 0 + 0 + + gamma + + 0.29999998211860657 + 0 + 0 + 1 + + glow + + 20 + 0.0010000000474974513 + -0.99999994039535522 + 1 + + haze_density + + 0.31999999284744263 + 0 + 0 + 1 + + haze_horizon + + 0.41999998688697815 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0 + 0.43711560964584351 + -0.89940536022186279 + 0 + + max_y + + 1369 + 0 + 0 + 1 + + preset_num + 18 + star_brightness + 0.63999998569488525 + sun_angle + 2.6892035007476807 + sunlight_color + + 0.35999998450279236 + 0.83719938993453979 + 0.84000003337860107 + 0.2800000011920929 + + + diff --git a/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%20Noon.xml b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%20Noon.xml new file mode 100644 index 0000000000..8c3d29e3f4 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%20Noon.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.77999997138977051 + 0.77999997138977051 + 0.77999997138977051 + 0.25999999046325684 + + blue_density + + 0 + 2 + 2 + 2 + + blue_horizon + + 0.2800000011920929 + 0.44679245352745056 + 0.56000000238418579 + 0.56000000238418579 + + cloud_color + + 0.12999999523162842 + 0.14424242079257965 + 0.11999999731779099 + 0.14999999105930328 + + cloud_pos_density1 + + 0.53999996185302734 + 0.50999999046325684 + 0.14000000059604645 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.50999999046325684 + 1 + + cloud_scale + + 0.62000000476837158 + 0 + 0 + 1 + + cloud_scroll_rate + + 20 + 20 + + cloud_shadow + + 0.70999997854232788 + 0 + 0 + 1 + + density_multiplier + + 2.9999999242136255e-005 + 0 + 0 + 1 + + distance_multiplier + + 1.2000000476837158 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 0 + 0 + + gamma + + 2.5 + 0 + 0 + 1 + + glow + + 1.1999988555908203 + 0.0010000000474974513 + -0.59999996423721313 + 1 + + haze_density + + 2 + 0 + 0 + 1 + + haze_horizon + + 0.23999999463558197 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0 + 1 + -4.3711388286737929e-008 + 0 + + max_y + + 4000 + 0 + 0 + 1 + + preset_num + 21 + star_brightness + 0.22999998927116394 + sun_angle + 1.5707963705062866 + sunlight_color + + 0.29999998211860657 + 0.29999998211860657 + 0.14999999105930328 + 0.099999994039535522 + + + diff --git a/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%20Sunrise%3A%20%2DA.xml b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%20Sunrise%3A%20%2DA.xml new file mode 100644 index 0000000000..2cceb65df7 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%20Sunrise%3A%20%2DA.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.14999997615814209 + 0.17999999225139618 + 0 + 0.059999998658895493 + + blue_density + + 0.37999999523162842 + 0.45999997854232788 + 0.2199999988079071 + 0.45999997854232788 + + blue_horizon + + 0.14000000059604645 + 0 + 0 + 0.17999999225139618 + + cloud_color + + 1 + 0 + 0 + 1 + + cloud_pos_density1 + + 0.53999996185302734 + 0.50999999046325684 + 0.14000000059604645 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.50999999046325684 + 1 + + cloud_scale + + 0.62000000476837158 + 0 + 0 + 1 + + cloud_scroll_rate + + 20 + 20 + + cloud_shadow + + 0.70999997854232788 + 0 + 0 + 1 + + density_multiplier + + 0.00032999998074956238 + 0 + 0 + 1 + + distance_multiplier + + 8.1000003814697266 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 0 + 0 + + gamma + + 0.12999999523162842 + 0 + 0 + 1 + + glow + + 20 + 0.0010000000474974513 + -0.74999994039535522 + 1 + + haze_density + + 4 + 0 + 0 + 1 + + haze_horizon + + 0.43999999761581421 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + -0 + 0.031410761177539825 + 0.99950653314590454 + 0 + + max_y + + 1826 + 0 + 0 + 1 + + preset_num + 18 + star_brightness + 1.5 + sun_angle + 0.031415928155183792 + sunlight_color + + 2.1299998760223389 + 2.0448005199432373 + 1.0735198259353638 + 0.70999997854232788 + + + diff --git a/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%20Sunrise%3A%20A.xml b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%20Sunrise%3A%20A.xml new file mode 100644 index 0000000000..e4a260f7d7 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%20Sunrise%3A%20A.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.14999997615814209 + 0.17999999225139618 + 0 + 0.059999998658895493 + + blue_density + + 0.2199999988079071 + 0.71999996900558472 + 0.93999999761581421 + 1 + + blue_horizon + + 0 + 0.6319204568862915 + 2 + 2 + + cloud_color + + 1 + 0 + 0 + 1 + + cloud_pos_density1 + + 0.53999996185302734 + 0.50999999046325684 + 0.14000000059604645 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.50999999046325684 + 1 + + cloud_scale + + 0.62000000476837158 + 0 + 0 + 1 + + cloud_scroll_rate + + 20 + 20 + + cloud_shadow + + 0.70999997854232788 + 0 + 0 + 1 + + density_multiplier + + 0.00032999998074956238 + 0 + 0 + 1 + + distance_multiplier + + 8.1000003814697266 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 0 + 0 + + gamma + + 0.12999999523162842 + 0 + 0 + 1 + + glow + + 20 + 0.0010000000474974513 + -0.74999994039535522 + 1 + + haze_density + + 4 + 0 + 0 + 1 + + haze_horizon + + 0.43999999761581421 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + -0 + 0.062790520489215851 + 0.99802672863006592 + 0 + + max_y + + 1369 + 0 + 0 + 1 + + preset_num + 18 + star_brightness + 1 + sun_angle + 0.062831856310367584 + sunlight_color + + 2.1299998760223389 + 2.0448005199432373 + 1.0735198259353638 + 0.70999997854232788 + + + diff --git a/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%20Sunrise%3A%20B.xml b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%20Sunrise%3A%20B.xml new file mode 100644 index 0000000000..8cf2190c43 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%20Sunrise%3A%20B.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.074999995529651642 + 0.08999999612569809 + 0 + 0.029999999329447746 + + blue_density + + 0.19191493093967438 + 0.62808448076248169 + 0.81999999284744263 + 0.40999999642372131 + + blue_horizon + + 2 + 0 + 2 + 2 + + cloud_color + + 0 + 0.021999998018145561 + 0.039999999105930328 + 0.039999999105930328 + + cloud_pos_density1 + + 0.53999996185302734 + 0.50999999046325684 + 0.14999999105930328 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.50999999046325684 + 1 + + cloud_scale + + 0.62000000476837158 + 0 + 0 + 1 + + cloud_scroll_rate + + 20 + 20 + + cloud_shadow + + 0.70999997854232788 + 0 + 0 + 1 + + density_multiplier + + 0.00032999998074956238 + 0 + 0 + 1 + + distance_multiplier + + 8.1000003814697266 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 0 + 0 + + gamma + + 0.53999996185302734 + 0 + 0 + 1 + + glow + + 20 + 0.0010000000474974513 + -0.69999998807907104 + 1 + + haze_density + + 4 + 0 + 0 + 1 + + haze_horizon + + 0.48999997973442078 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + -0 + 0.069060027599334717 + 0.99761247634887695 + 0 + + max_y + + 1101 + 0 + 0 + 1 + + preset_num + 18 + star_brightness + 0.5 + sun_angle + 0.069115042686462402 + sunlight_color + + 1.619999885559082 + 1.5551999807357788 + 0.81647992134094238 + 0.53999996185302734 + + + diff --git a/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%20Sunrise%3A%20C.xml b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%20Sunrise%3A%20C.xml new file mode 100644 index 0000000000..bde09ec69f --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%20Sunrise%3A%20C.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.26999998092651367 + 0.14999999105930328 + 0 + 0.26999998092651367 + + blue_density + + 0.24156853556632996 + 0.71999996900558472 + 0.93999999761581421 + 0.93999999761581421 + + blue_horizon + + 0 + 0.6319204568862915 + 1.1200000047683716 + 1.1200000047683716 + + cloud_color + + 0.17999999225139618 + 0 + 0 + 0.17999999225139618 + + cloud_pos_density1 + + 0.53999996185302734 + 0.50999999046325684 + 0.14000000059604645 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.50999999046325684 + 1 + + cloud_scale + + 0.62000000476837158 + 0 + 0 + 1 + + cloud_scroll_rate + + 11.679999351501465 + 10 + + cloud_shadow + + 0.70999997854232788 + 0 + 0 + 1 + + density_multiplier + + 0.00032999998074956238 + 0 + 0 + 1 + + distance_multiplier + + 8.1000003814697266 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 0 + 0 + + gamma + + 0.81000000238418579 + 0 + 0 + 1 + + glow + + 5 + 0.0010000000474974513 + -0.59999996423721313 + 1 + + haze_density + + 1.8600000143051147 + 0 + 0 + 1 + + haze_horizon + + 0.43999999761581421 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + -0 + 0.075326807796955109 + 0.99715888500213623 + 0 + + max_y + + 1074 + 0 + 0 + 1 + + preset_num + 18 + star_brightness + 0 + sun_angle + 0.07539822906255722 + sunlight_color + + 0.75 + 0.62999999523162842 + 0.84000003337860107 + 0.84000003337860107 + + + diff --git a/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%20Sunrise%3A%20D.xml b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%20Sunrise%3A%20D.xml new file mode 100644 index 0000000000..9f990c4da7 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%20Sunrise%3A%20D.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.26999998092651367 + 0.14999999105930328 + 0 + 0.26999998092651367 + + blue_density + + 0.24156853556632996 + 0.71999996900558472 + 0.93999999761581421 + 0.93999999761581421 + + blue_horizon + + 0 + 0.6319204568862915 + 1.1200000047683716 + 1.1200000047683716 + + cloud_color + + 0.18999999761581421 + 0 + 0 + 0.18999999761581421 + + cloud_pos_density1 + + 0.53999996185302734 + 0.50999999046325684 + 0.14000000059604645 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.50999999046325684 + 1 + + cloud_scale + + 0.62000000476837158 + 0 + 0 + 1 + + cloud_scroll_rate + + 11.679999351501465 + 10 + + cloud_shadow + + 0.70999997854232788 + 0 + 0 + 1 + + density_multiplier + + 0.00032999998074956238 + 0 + 0 + 1 + + distance_multiplier + + 8.1000003814697266 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 0 + 0 + + gamma + + 1.3500000238418579 + 0 + 0 + 1 + + glow + + 5 + 0.0010000000474974513 + -0.59999996423721313 + 1 + + haze_density + + 1.8600000143051147 + 0 + 0 + 1 + + haze_horizon + + 0.43999999761581421 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + -0 + 0.081590615212917328 + 0.99666595458984375 + 0 + + max_y + + 859 + 0 + 0 + 1 + + preset_num + 18 + star_brightness + 0 + sun_angle + 0.081681415438652039 + sunlight_color + + 0.75 + 0.62999999523162842 + 0.71999996900558472 + 0.75 + + + diff --git a/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%20Sunrise%3A%20E.xml b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%20Sunrise%3A%20E.xml new file mode 100644 index 0000000000..651d9e79f4 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%20Sunrise%3A%20E.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.14999999105930328 + 0.17999999225139618 + 0 + 0.17999999225139618 + + blue_density + + 0.24156853556632996 + 0.71999996900558472 + 0.93999999761581421 + 0.93999999761581421 + + blue_horizon + + 0 + 0.6319204568862915 + 1.1200000047683716 + 1.1200000047683716 + + cloud_color + + 0.4699999988079071 + 0 + 0 + 0.4699999988079071 + + cloud_pos_density1 + + 0.53999996185302734 + 0.50999999046325684 + 0.14000000059604645 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.50999999046325684 + 1 + + cloud_scale + + 0.62000000476837158 + 0 + 0 + 1 + + cloud_scroll_rate + + 20 + 20 + + cloud_shadow + + 0.70999997854232788 + 0 + 0 + 1 + + density_multiplier + + 0.00032999998074956238 + 0 + 0 + 1 + + distance_multiplier + + 8.1000003814697266 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 0 + 0 + + gamma + + 1.5399999618530273 + 0 + 0 + 1 + + glow + + 0.39999961853027344 + 0.0010000000474974513 + -0.49999997019767761 + 1 + + haze_density + + 1.8600000143051147 + 0 + 0 + 1 + + haze_horizon + + 0.43999999761581421 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + -0 + 0.087851203978061676 + 0.99613362550735474 + 0 + + max_y + + 1369 + 0 + 0 + 1 + + preset_num + 18 + star_brightness + 0 + sun_angle + 0.087964601814746857 + sunlight_color + + 0.75 + 0.71999996900558472 + 0.37800011038780212 + 0.80999994277954102 + + + diff --git a/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%20Sunrise%3A%20F.xml b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%20Sunrise%3A%20F.xml new file mode 100644 index 0000000000..3efde332e8 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%20Sunrise%3A%20F.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.14999999105930328 + 0.17999999225139618 + 0.11999999731779099 + 0.17999999225139618 + + blue_density + + 0.24156853556632996 + 0.87999999523162842 + 0.93999999761581421 + 0.93999999761581421 + + blue_horizon + + 0 + 0.6319204568862915 + 1.1200000047683716 + 1.1200000047683716 + + cloud_color + + 0.28999999165534973 + 0.14000000059604645 + 0.11999999731779099 + 0.28999999165534973 + + cloud_pos_density1 + + 0.53999996185302734 + 0.50999999046325684 + 0.14000000059604645 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.50999999046325684 + 1 + + cloud_scale + + 0.62000000476837158 + 0 + 0 + 1 + + cloud_scroll_rate + + 20 + 20 + + cloud_shadow + + 0.70999997854232788 + 0 + 0 + 1 + + density_multiplier + + 0.00032999998074956238 + 0 + 0 + 1 + + distance_multiplier + + 1 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 0 + 0 + + gamma + + 2 + 0 + 0 + 1 + + glow + + 0.19999980926513672 + 0.0010000000474974513 + -0.34999999403953552 + 1 + + haze_density + + 1.8600000143051147 + 0 + 0 + 1 + + haze_horizon + + 0.43999999761581421 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + -0 + 0.42008578777313232 + 0.90748441219329834 + 0 + + max_y + + 1369 + 0 + 0 + 1 + + preset_num + 18 + star_brightness + 0 + sun_angle + 0.43353983759880066 + sunlight_color + + 0.47999998927116394 + 0.71999996900558472 + 0.42000001668930054 + 0.71999996900558472 + + + diff --git a/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%20Sunset%3A%20A.xml b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%20Sunset%3A%20A.xml new file mode 100644 index 0000000000..6c14c1b947 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%20Sunset%3A%20A.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.14999999105930328 + 0.17999999225139618 + 0.11999999731779099 + 0.17999999225139618 + + blue_density + + 0.24156853556632996 + 0.87999999523162842 + 0.93999999761581421 + 0.93999999761581421 + + blue_horizon + + 0 + 0.6319204568862915 + 1.1200000047683716 + 1.1200000047683716 + + cloud_color + + 0.28999999165534973 + 0.14000000059604645 + 0.11999999731779099 + 0.28999999165534973 + + cloud_pos_density1 + + 0.53999996185302734 + 0.50999999046325684 + 0.14000000059604645 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.50999999046325684 + 1 + + cloud_scale + + 0.62000000476837158 + 0 + 0 + 1 + + cloud_scroll_rate + + 20 + 20 + + cloud_shadow + + 0.70999997854232788 + 0 + 0 + 1 + + density_multiplier + + 0.00032999998074956238 + 0 + 0 + 1 + + distance_multiplier + + 1 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 0 + 0 + + gamma + + 2 + 0 + 0 + 1 + + glow + + 0.19999980926513672 + 0.0010000000474974513 + -0.34999999403953552 + 1 + + haze_density + + 1.8600000143051147 + 0 + 0 + 1 + + haze_horizon + + 0.43999999761581421 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0 + 0.36227512359619141 + -0.93207120895385742 + 0 + + max_y + + 3007 + 0 + 0 + 1 + + preset_num + 18 + star_brightness + 0 + sun_angle + 2.7708849906921387 + sunlight_color + + 0.47999998927116394 + 0.71999996900558472 + 0.42000001668930054 + 0.71999996900558472 + + + diff --git a/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%20Sunset%3A%20B.xml b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%20Sunset%3A%20B.xml new file mode 100644 index 0000000000..b3d7cbc364 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%20Sunset%3A%20B.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.29999998211860657 + 0.17999999225139618 + 0 + 0.099999994039535522 + + blue_density + + 0.14000000059604645 + 0.56000000238418579 + 0 + 0.56000000238418579 + + blue_horizon + + 0.47999998927116394 + 0.27082312107086182 + 0 + 0.23999999463558197 + + cloud_color + + 0.41999998688697815 + 0.20999999344348907 + 0 + 0.41999998688697815 + + cloud_pos_density1 + + 0.53999996185302734 + 0.50999999046325684 + 0.14000000059604645 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.50999999046325684 + 1 + + cloud_scale + + 0.62000000476837158 + 0 + 0 + 1 + + cloud_scroll_rate + + 20 + 20 + + cloud_shadow + + 0.70999997854232788 + 0 + 0 + 1 + + density_multiplier + + 0.00045999998110346496 + 0 + 0 + 1 + + distance_multiplier + + 1.3999999761581421 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 0 + 0 + + gamma + + 1.1499999761581421 + 0 + 0 + 1 + + glow + + 0.39999961853027344 + 0.0010000000474974513 + -0.39999997615814209 + 1 + + haze_density + + 4 + 0 + 0 + 1 + + haze_horizon + + 0.17999999225139618 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0 + 0.14401055872440338 + -0.98957616090774536 + 0 + + max_y + + 805 + 0 + 0 + 1 + + preset_num + 18 + star_brightness + 0 + sun_angle + 2.997079610824585 + sunlight_color + + 3 + 2.7300000190734863 + 0.41666662693023682 + 3 + + + diff --git a/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%20Sunset%3A%20C.xml b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%20Sunset%3A%20C.xml new file mode 100644 index 0000000000..dbd79a4cb2 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%20Sunset%3A%20C.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.14999997615814209 + 0.17999999225139618 + 0 + 0.059999998658895493 + + blue_density + + 0.2199999988079071 + 0.71999996900558472 + 0.93999999761581421 + 1 + + blue_horizon + + 0 + 0.42970588803291321 + 1.3600000143051147 + 0.68000000715255737 + + cloud_color + + 1 + 0 + 0 + 1 + + cloud_pos_density1 + + 0.53999996185302734 + 0.50999999046325684 + 0.14000000059604645 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.50999999046325684 + 1 + + cloud_scale + + 0.62000000476837158 + 0 + 0 + 1 + + cloud_scroll_rate + + 20 + 20 + + cloud_shadow + + 0.70999997854232788 + 0 + 0 + 1 + + density_multiplier + + 0.00032999998074956238 + 0 + 0 + 1 + + distance_multiplier + + 8.1000003814697266 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 0 + 0 + + gamma + + 0.34000000357627869 + 0 + 0 + 1 + + glow + + 10.199999809265137 + 0.0010000000474974513 + -0.74999994039535522 + 1 + + haze_density + + 4 + 0 + 0 + 1 + + haze_horizon + + 0.43999999761581421 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0 + 0.062790460884571075 + -0.99802672863006592 + 0 + + max_y + + 1369 + 0 + 0 + 1 + + preset_num + 18 + star_brightness + 1 + sun_angle + 3.0787608623504639 + sunlight_color + + 2.1299998760223389 + 2.0448005199432373 + 1.0735198259353638 + 0.70999997854232788 + + + diff --git a/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%20Sunset%3A%20D.xml b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%20Sunset%3A%20D.xml new file mode 100644 index 0000000000..061c1c0a17 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Natural%20Sunset%3A%20D.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.14999997615814209 + 0.17999999225139618 + 0 + 0.059999998658895493 + + blue_density + + 0.37999999523162842 + 0.45999997854232788 + 0.2199999988079071 + 0.45999997854232788 + + blue_horizon + + 0.14000000059604645 + 0 + 0 + 0.17999999225139618 + + cloud_color + + 1 + 0 + 0 + 1 + + cloud_pos_density1 + + 0.53999996185302734 + 0.50999999046325684 + 0.14000000059604645 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.50999999046325684 + 1 + + cloud_scale + + 0.62000000476837158 + 0 + 0 + 1 + + cloud_scroll_rate + + 20 + 20 + + cloud_shadow + + 0.70999997854232788 + 0 + 0 + 1 + + density_multiplier + + 0.00032999998074956238 + 0 + 0 + 1 + + distance_multiplier + + 8.1000003814697266 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 0 + 0 + + gamma + + 0.12999999523162842 + 0 + 0 + 1 + + glow + + 20 + 0.0010000000474974513 + -0.74999994039535522 + 1 + + haze_density + + 4 + 0 + 0 + 1 + + haze_horizon + + 0.43999999761581421 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0 + 0.031410444527864456 + -0.99950659275054932 + 0 + + max_y + + 1826 + 0 + 0 + 1 + + preset_num + 18 + star_brightness + 1.5 + sun_angle + 3.1101770401000977 + sunlight_color + + 2.1299998760223389 + 2.0448005199432373 + 1.0735198259353638 + 0.70999997854232788 + + + diff --git a/indra/newview/app_settings/windlight/skies/Nacon%27s%20Nighty%20Fog.xml b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Nighty%20Fog.xml new file mode 100644 index 0000000000..a197c83ead --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Nighty%20Fog.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.079999998211860657 + 0.079999998211860657 + 0.079999998211860657 + 0.079999998211860657 + + blue_density + + 1 + 0.81000000238418579 + 0.62000000476837158 + 1 + + blue_horizon + + 0 + 0.2199999988079071 + 0.45999997854232788 + 0.45999997854232788 + + cloud_color + + 0.69999998807907104 + 0.69999998807907104 + 0.69999998807907104 + 0.69999998807907104 + + cloud_pos_density1 + + 0.5 + 0.5 + 0.53999996185302734 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.125 + 1 + + cloud_scale + + 0.29999998211860657 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.49940013885498 + 10.01099967956543 + + cloud_shadow + + 0.39999997615814209 + 0 + 0 + 1 + + density_multiplier + + 0.00075000000651925802 + 0 + 0 + 1 + + distance_multiplier + + 30.200000762939453 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 2.1800000667572021 + 0 + 0 + 1 + + glow + + 4.2000007629394531 + 0.0010000000474974513 + -0.64999997615814209 + 1 + + haze_density + + 2.7200000286102295 + 0 + 0 + 1 + + haze_horizon + + 0.19999998807907104 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0 + 0.99361127614974976 + -0.11285652220249176 + 0 + + max_y + + 3447 + 0 + 0 + 1 + + preset_num + 18 + star_brightness + 0 + sun_angle + 1.6838937997817993 + sunlight_color + + 0 + 0 + 0 + 0 + + + diff --git a/indra/newview/app_settings/windlight/skies/Nacon%27s%20O%2D6am.xml b/indra/newview/app_settings/windlight/skies/Nacon%27s%20O%2D6am.xml new file mode 100644 index 0000000000..59c4852168 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Nacon%27s%20O%2D6am.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.33054998638431243 + 0.33054998638431243 + 0.33054998638431243 + 0.11018333371629296 + + blue_density + + 0.080423966373246003 + 0.2235726453915845 + 0.44715003729959335 + 0.22815837741444511 + + blue_horizon + + 0.22289033702560346 + 0.427064714973028 + 0.49914732197913736 + 0.25737920767664946 + + cloud_color + + 0.21963333011493091 + 0.21931249500003958 + 0.21899165988514824 + 0.21963333011493091 + + cloud_pos_density1 + + 1.6884100437164307 + 0.52609699964523315 + 1 + 1 + + cloud_pos_density2 + + 1.6884100437164307 + 0.52609699964523315 + 0.12483958242547999 + 1 + + cloud_scale + + 0.14000000059604645 + 0 + 0 + 1 + + cloud_scroll_rate + + 11.53729577948252 + 10.013974280172988 + + cloud_shadow + + 0.26999998092651367 + 0 + 0 + 1 + + density_multiplier + + 0.00042839580998887961 + 0 + 0 + 1 + + distance_multiplier + + 8.5212110501925054 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1.0068750381469727 + 0 + 0 + 1 + + glow + + 4.9779998770554812 + 0.0010000000474974513 + -0.52036664955119249 + 1 + + haze_density + + 0.75375835388103951 + 0 + 0 + 1 + + haze_horizon + + 0.18027500862106649 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0 + 0.9999927282333374 + -0.0038118390366435051 + 1 + + max_y + + 733.73938726552296 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 1.9918874502182007 + sun_angle + 4.7162008285522461 + sunlight_color + + 0.00041250227106104376 + 0.00041250227106104376 + 0.00020625113553052188 + 0.00013750075986607158 + + + diff --git a/indra/newview/app_settings/windlight/skies/Nacon%27s%20Rise.xml b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Rise.xml new file mode 100644 index 0000000000..105ab5d5cf --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Rise.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.38999998569488525 + 0.19687503576278687 + 0.11999999731779099 + 0.38999998569488525 + + blue_density + + 0.0072000003419816494 + 0.029999999329447746 + 0.059999998658895493 + 0.029999999329447746 + + blue_horizon + + 0 + 0 + 0 + 0 + + cloud_color + + 0.14000000059604645 + 0.070000000298023224 + 0 + 0.14000000059604645 + + cloud_pos_density1 + + 1 + 1 + 0.2800000011920929 + 1 + + cloud_pos_density2 + + 1 + 1 + 0.08999999612569809 + 1 + + cloud_scale + + 0.14000000059604645 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.949999809265137 + 10.659999847412109 + + cloud_shadow + + 0.22999998927116394 + 0 + 0 + 1 + + density_multiplier + + 0.00025000001187436283 + 0 + 0 + 1 + + distance_multiplier + + 57.400001525878906 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 2.5 + 0 + 0 + 1 + + glow + + 0.19999980926513672 + 0.0010000000474974513 + -0.59999996423721313 + 1 + + haze_density + + 0.34999999403953552 + 0 + 0 + 1 + + haze_horizon + + 0.28999999165534973 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + -0 + 0.29704159498214722 + 0.95486456155776978 + 0 + + max_y + + 4000 + 0 + 0 + 1 + + preset_num + 21 + star_brightness + 0.22999998927116394 + sun_angle + 0.30159291625022888 + sunlight_color + + 0.059999998658895493 + 0.029999999329447746 + 0.011249998584389687 + 0.059999998658895493 + + + diff --git a/indra/newview/app_settings/windlight/skies/Nacon%27s%20Rosy%20Morning.xml b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Rosy%20Morning.xml new file mode 100644 index 0000000000..651d9e79f4 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Rosy%20Morning.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.14999999105930328 + 0.17999999225139618 + 0 + 0.17999999225139618 + + blue_density + + 0.24156853556632996 + 0.71999996900558472 + 0.93999999761581421 + 0.93999999761581421 + + blue_horizon + + 0 + 0.6319204568862915 + 1.1200000047683716 + 1.1200000047683716 + + cloud_color + + 0.4699999988079071 + 0 + 0 + 0.4699999988079071 + + cloud_pos_density1 + + 0.53999996185302734 + 0.50999999046325684 + 0.14000000059604645 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.50999999046325684 + 1 + + cloud_scale + + 0.62000000476837158 + 0 + 0 + 1 + + cloud_scroll_rate + + 20 + 20 + + cloud_shadow + + 0.70999997854232788 + 0 + 0 + 1 + + density_multiplier + + 0.00032999998074956238 + 0 + 0 + 1 + + distance_multiplier + + 8.1000003814697266 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 0 + 0 + + gamma + + 1.5399999618530273 + 0 + 0 + 1 + + glow + + 0.39999961853027344 + 0.0010000000474974513 + -0.49999997019767761 + 1 + + haze_density + + 1.8600000143051147 + 0 + 0 + 1 + + haze_horizon + + 0.43999999761581421 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + -0 + 0.087851203978061676 + 0.99613362550735474 + 0 + + max_y + + 1369 + 0 + 0 + 1 + + preset_num + 18 + star_brightness + 0 + sun_angle + 0.087964601814746857 + sunlight_color + + 0.75 + 0.71999996900558472 + 0.37800011038780212 + 0.80999994277954102 + + + diff --git a/indra/newview/app_settings/windlight/skies/Nacon%27s%20Sweet%20Dawn.xml b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Sweet%20Dawn.xml new file mode 100644 index 0000000000..db8af4aac8 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Sweet%20Dawn.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.19999998807907104 + 0.17128434777259827 + 0.11999999731779099 + 0.19999998807907104 + + blue_density + + 0.35999998450279236 + 0.0099999997764825821 + 1 + 1 + + blue_horizon + + 0.37000000476837158 + 0.31000000238418579 + 0 + 0.37000000476837158 + + cloud_color + + 0.37000000476837158 + 0.2800000011920929 + 0.17999999225139618 + 0.43999999761581421 + + cloud_pos_density1 + + 0.90999996662139893 + 0.81000000238418579 + 0.059999998658895493 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.125 + 1 + + cloud_scale + + 0.38999998569488525 + 0 + 0 + 1 + + cloud_scroll_rate + + 11.170000076293945 + 8.4099998474121094 + + cloud_shadow + + 0.68999999761581421 + 0 + 0 + 1 + + density_multiplier + + 0.00014000000373926014 + 0 + 0 + 1 + + distance_multiplier + + 7.4000000953674316 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 4.0999999046325684 + 0 + 0 + 1 + + glow + + 0.19999980926513672 + 0.0010000000474974513 + -0.94999998807907104 + 1 + + haze_density + + 0.68999999761581421 + 0 + 0 + 1 + + haze_horizon + + 0.099999994039535522 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0 + 0.7459409236907959 + -0.66601210832595825 + 0 + + max_y + + 3158 + 0 + 0 + 1 + + preset_num + 18 + star_brightness + 0 + sun_angle + 2.2996461391448975 + sunlight_color + + 0.17999999225139618 + 0.14000000059604645 + 0.11999999731779099 + 0.17999999225139618 + + + diff --git a/indra/newview/app_settings/windlight/skies/Nacon%27s%20Sweet%20Morning.xml b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Sweet%20Morning.xml new file mode 100644 index 0000000000..42761fe052 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Sweet%20Morning.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.14117646217346191 + 0.17128434777259827 + 0.19999998807907104 + 0.19999998807907104 + + blue_density + + 0.17000000178813934 + 0.35999998450279236 + 1 + 1 + + blue_horizon + + 0 + 0.37000000476837158 + 0.29089650511741638 + 0.37000000476837158 + + cloud_color + + 0.12210001051425934 + 0.27379998564720154 + 0.37000000476837158 + 0.37000000476837158 + + cloud_pos_density1 + + 0.90999996662139893 + 0.81000000238418579 + 0.059999998658895493 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.125 + 1 + + cloud_scale + + 0.38999998569488525 + 0 + 0 + 1 + + cloud_scroll_rate + + 11.170000076293945 + 8.4099998474121094 + + cloud_shadow + + 0.68999999761581421 + 0 + 0 + 1 + + density_multiplier + + 0.00014000000373926014 + 0 + 0 + 1 + + distance_multiplier + + 7.4000000953674316 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 4.0999999046325684 + 0 + 0 + 1 + + glow + + 0.19999980926513672 + 0.0010000000474974513 + -0.94999998807907104 + 1 + + haze_density + + 0.68999999761581421 + 0 + 0 + 1 + + haze_horizon + + 0.099999994039535522 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0 + 0.7459409236907959 + -0.66601210832595825 + 0 + + max_y + + 3158 + 0 + 0 + 1 + + preset_num + 18 + star_brightness + 0 + sun_angle + 2.2996461391448975 + sunlight_color + + 0.17999999225139618 + 0.14000000059604645 + 0.12000000476837158 + 0.059999998658895493 + + + diff --git a/indra/newview/app_settings/windlight/skies/Nacon%27s%20Test.xml b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Test.xml new file mode 100644 index 0000000000..c5a355777c --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Nacon%27s%20Test.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.14117646217346191 + 0.17128434777259827 + 0.19999998807907104 + 0.19999998807907104 + + blue_density + + 0.17000000178813934 + 0.35999998450279236 + 1 + 1 + + blue_horizon + + 0 + 0.37000000476837158 + 0.29089650511741638 + 0.37000000476837158 + + cloud_color + + 0.12210001051425934 + 0.27379998564720154 + 0.37000000476837158 + 0.37000000476837158 + + cloud_pos_density1 + + 0.90999996662139893 + 0.81000000238418579 + 0.059999998658895493 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.125 + 1 + + cloud_scale + + 0.38999998569488525 + 0 + 0 + 1 + + cloud_scroll_rate + + 11.170000076293945 + 8.4099998474121094 + + cloud_shadow + + 0.68999999761581421 + 0 + 0 + 1 + + density_multiplier + + 0.00014000000373926014 + 0 + 0 + 1 + + distance_multiplier + + 7.4000000953674316 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 4.0999999046325684 + 0 + 0 + 1 + + glow + + 0.59999942779541016 + 0.0010000000474974513 + -0.94999998807907104 + 1 + + haze_density + + 0.68999999761581421 + 0 + 0 + 1 + + haze_horizon + + 0.099999994039535522 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0 + 0.22427062690258026 + -0.97452688217163086 + 0 + + max_y + + 3158 + 0 + 0 + 1 + + preset_num + 18 + star_brightness + 0 + sun_angle + 2.915398120880127 + sunlight_color + + 0.17999999225139618 + 0.14000000059604645 + 0.12000000476837158 + 0.059999998658895493 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Absinthe%20Light%20.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Absinthe%20Light%20.xml new file mode 100644 index 0000000000..31eb39ac29 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Absinthe%20Light%20.xml @@ -0,0 +1,141 @@ + + + ambient + + 1.0799999237060547 + 0.98999994993209839 + 0.77999997138977051 + 1.0799999237060547 + + blue_density + + 0.64736837148666382 + 0.48414888978004456 + 0.81999999284744263 + 0.40999999642372131 + + blue_horizon + + 0.5 + 0.49548381567001343 + 0.45999997854232788 + 0.51999998092651367 + + cloud_color + + 0.4100000062111997 + 0.4100000062111997 + 0.4100000062111997 + 0.4100000062111997 + + cloud_pos_density1 + + 0.14000000059604645 + 0.62000000476837158 + 1 + 1 + + cloud_pos_density2 + + 0.35999998450279236 + 0.56999999284744263 + 0.12999999523162842 + 1 + + cloud_scale + + 0.35999998450279236 + 0 + 0 + 1.0000000149011612 + + cloud_scroll_rate + + 10.199999791580112 + 10.010999679880427 + + cloud_shadow + + 0.29999998211860657 + 0 + 0 + 1.0000000149011612 + + density_multiplier + + 7.9999997979030013e-005 + 0 + 0 + 1.0000000149011612 + + distance_multiplier + + 5.4000000953674316 + 0 + 0 + 1.0000000149011612 + + east_angle + 1.0932743549346924 + enable_cloud_scroll + + 1 + 1 + + gamma + + 2.1699998378753662 + 0 + 0 + 1.0000000149011612 + + glow + + 0.19999980926513672 + 0.0010000000474974513 + -0.55000001192092896 + 1 + + haze_density + + 0.31999999284744263 + 0 + 0 + 1 + + haze_horizon + + 0.17999999225139618 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0.39627334475517273 + 0.89494067430496216 + -0.20505768060684204 + 0 + + max_y + + 805 + 0 + 0 + 1.0000000149011612 + + preset_num + 28 + star_brightness + 0.25999999046325684 + sun_angle + 2.0332944393157959 + sunlight_color + + 0.69882339239120483 + 0.8258824348449707 + 1.0799999237060547 + 0.35999998450279236 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Andi%20Light%20.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Andi%20Light%20.xml new file mode 100644 index 0000000000..654652b52a --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Andi%20Light%20.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0 + 0 + 0 + + blue_density + + 1 + 2 + 2 + 1 + + blue_horizon + + 0 + 0 + 0 + 0 + + cloud_color + + 0 + 0 + 0 + 0 + + cloud_pos_density1 + + 0.57999998331069946 + 0.87000000476837158 + 0.75 + 1 + + cloud_pos_density2 + + 1.6884100437164307 + 0.52609699964523315 + 0.073541670078411725 + 1 + + cloud_scale + + 0.99999994039535522 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.088005410620646 + 10.010458310484864 + + cloud_shadow + + 0 + 0 + 0 + 1 + + density_multiplier + + 5.1599996368167922e-005 + 0 + 0 + 1 + + distance_multiplier + + 0.80000001192092896 + 0 + 0 + 1 + + east_angle + 3.091327428817749 + enable_cloud_scroll + + 1 + 1 + + gamma + + 0.69569998979568481 + 0 + 0 + 1 + + glow + + 0.19999980926513672 + 0.0010000000474974513 + -2.5 + 1 + + haze_density + + 3 + 0 + 0 + 1 + + haze_horizon + + 0.59999996423721313 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0.0098020657896995544 + 0.9807855486869812 + 0.1948426365852356 + 0 + + max_y + + 4000 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0 + sun_angle + 1.7671445608139038 + sunlight_color + + 1.5 + 1.5 + 3 + 1 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Angles%20Light%2001.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Angles%20Light%2001.xml new file mode 100644 index 0000000000..fbb2272ff6 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Angles%20Light%2001.xml @@ -0,0 +1,141 @@ + + + ambient + + 1.8235294818878174 + 1.2352941036224365 + 1.5411765575408936 + 0.60784316062927246 + + blue_density + + 1.2000000476837158 + 1.4039216041564941 + 1.6392157077789307 + 0.81960785388946533 + + blue_horizon + + 1.2000000476837158 + 1.4039216041564941 + 1.6392157077789307 + 0.81960785388946533 + + cloud_color + + 0 + 0 + 0 + 0 + + cloud_pos_density1 + + 0.57999998331069946 + 0.87000000476837158 + 1 + 1 + + cloud_pos_density2 + + 1.6884100437164307 + 0.52609699964523315 + 0.073541670078411725 + 1 + + cloud_scale + + 0.96579998731613159 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.088005410620646 + 10.010458310484864 + + cloud_shadow + + 1 + 0 + 0 + 1 + + density_multiplier + + 0.00020660000154748559 + 0 + 0 + 1 + + distance_multiplier + + 6.2000002861022949 + 0 + 0 + 1 + + east_angle + 0.29530972242355347 + enable_cloud_scroll + + 1 + 1 + + gamma + + 0.95649999380111694 + 0 + 0 + 1 + + glow + + 9.4000005722045898 + 0.0010000000474974513 + -0.44999998807907104 + 1 + + haze_density + + 2.059999942779541 + 0 + 0 + 1 + + haze_horizon + + 0.5 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0.268882155418396 + 0.38268527388572693 + -0.88388597965240479 + 0 + + max_y + + 788 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0.1029166579246521 + sun_angle + 2.7488915920257568 + sunlight_color + + 1.5 + 1.5 + 1.5 + 0.5 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20B%2FW%20Light%20%2008.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20B%2FW%20Light%20%2008.xml new file mode 100644 index 0000000000..268ea125f5 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20B%2FW%20Light%20%2008.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0 + 0 + 0 + + blue_density + + 1 + 1 + 1 + 0.5 + + blue_horizon + + 1 + 1 + 1 + 0.5 + + cloud_color + + 0.5 + 0.5 + 0.5 + 0.5 + + cloud_pos_density1 + + 0.5 + 0.5 + 0.76829999685287476 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.125 + 1 + + cloud_scale + + 0.059000000357627869 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.49940033104544 + 10.011000058908452 + + cloud_shadow + + 0.26999998092651367 + 0 + 0 + 1 + + density_multiplier + + 0.00025079998886212707 + 0 + 0 + 1 + + distance_multiplier + + 14 + 0 + 0 + 1 + + east_angle + 0.19477875530719757 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1 + 0 + 0 + 1 + + glow + + 16.80000114440918 + 0.0010000000474974513 + -0.59999996423721313 + 1 + + haze_density + + 1.1499999761581421 + 0 + 0 + 1 + + haze_horizon + + 0.17000000178813934 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + -0.14745019376277924 + 0.64778679609298706 + 0.74741601943969727 + 0 + + max_y + + 4000 + 0 + 0 + 1 + + preset_num + 21 + star_brightness + 1.7856996059417725 + sun_angle + 0.70467567443847656 + sunlight_color + + 3 + 3 + 3 + 1 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20B%2FW%20Light%2001.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20B%2FW%20Light%2001.xml new file mode 100644 index 0000000000..268ea125f5 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20B%2FW%20Light%2001.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0 + 0 + 0 + + blue_density + + 1 + 1 + 1 + 0.5 + + blue_horizon + + 1 + 1 + 1 + 0.5 + + cloud_color + + 0.5 + 0.5 + 0.5 + 0.5 + + cloud_pos_density1 + + 0.5 + 0.5 + 0.76829999685287476 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.125 + 1 + + cloud_scale + + 0.059000000357627869 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.49940033104544 + 10.011000058908452 + + cloud_shadow + + 0.26999998092651367 + 0 + 0 + 1 + + density_multiplier + + 0.00025079998886212707 + 0 + 0 + 1 + + distance_multiplier + + 14 + 0 + 0 + 1 + + east_angle + 0.19477875530719757 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1 + 0 + 0 + 1 + + glow + + 16.80000114440918 + 0.0010000000474974513 + -0.59999996423721313 + 1 + + haze_density + + 1.1499999761581421 + 0 + 0 + 1 + + haze_horizon + + 0.17000000178813934 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + -0.14745019376277924 + 0.64778679609298706 + 0.74741601943969727 + 0 + + max_y + + 4000 + 0 + 0 + 1 + + preset_num + 21 + star_brightness + 1.7856996059417725 + sun_angle + 0.70467567443847656 + sunlight_color + + 3 + 3 + 3 + 1 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20B%2FW%20Light%2002.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20B%2FW%20Light%2002.xml new file mode 100644 index 0000000000..130571e2a0 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20B%2FW%20Light%2002.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0 + 0 + 0 + + blue_density + + 1 + 1 + 1 + 0.5 + + blue_horizon + + 1 + 1 + 1 + 0.5 + + cloud_color + + 0.5 + 0.5 + 0.5 + 0.5 + + cloud_pos_density1 + + 0.5 + 0.5 + 0.76829999685287476 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.125 + 1 + + cloud_scale + + 0.059000000357627869 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.49940033104544 + 10.011000058908452 + + cloud_shadow + + 0.26999998092651367 + 0 + 0 + 1 + + density_multiplier + + 0.00025079998886212707 + 0 + 0 + 1 + + distance_multiplier + + 14 + 0 + 0 + 1 + + east_angle + 0.19477875530719757 + enable_cloud_scroll + + 1 + 1 + + gamma + + 3.3912999629974365 + 0 + 0 + 1 + + glow + + 16.80000114440918 + 0.0010000000474974513 + -0.59999996423721313 + 1 + + haze_density + + 1.1499999761581421 + 0 + 0 + 1 + + haze_horizon + + 0.17000000178813934 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + -0.14745019376277924 + 0.64778679609298706 + 0.74741601943969727 + 0 + + max_y + + 4000 + 0 + 0 + 1 + + preset_num + 21 + star_brightness + 1.7856996059417725 + sun_angle + 0.70467567443847656 + sunlight_color + + 3 + 3 + 3 + 1 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20B%2FW%20Light%2003.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20B%2FW%20Light%2003.xml new file mode 100644 index 0000000000..676f1a7802 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20B%2FW%20Light%2003.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.15000000596046448 + 0.15000000596046448 + 0.15000000596046448 + 0.05000000074505806 + + blue_density + + 1 + 1 + 1 + 0.5 + + blue_horizon + + 1.7999999523162842 + 1.7999999523162842 + 1.7999999523162842 + 0.89999997615814209 + + cloud_color + + 0 + 0 + 0 + 0 + + cloud_pos_density1 + + 0.93999999761581421 + 0.22999998927116394 + 0.38409999012947083 + 1 + + cloud_pos_density2 + + 1 + 0.50999999046325684 + 1 + 1 + + cloud_scale + + 0.31279999017715454 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.199999809265137 + 10.01099967956543 + + cloud_shadow + + 0.43999999761581421 + 0 + 0 + 1 + + density_multiplier + + 7.3799994424916804e-005 + 0 + 0 + 1 + + distance_multiplier + + 13.199999809265137 + 0 + 0 + 1 + + east_angle + 1.9477875232696533 + enable_cloud_scroll + + 0 + 0 + + gamma + + 1.3999999761581421 + 0 + 0 + 1 + + glow + + 5 + 0.0010000000474974513 + -0.47999998927116394 + 1 + + haze_density + + 0.69999998807907104 + 0 + 0 + 1 + + haze_horizon + + 0.26999998092651367 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + -0.51655691862106323 + 0.83146905899047852 + -0.20451940596103668 + 0 + + max_y + + 242 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0 + sun_angle + 0.98174667358398438 + sunlight_color + + 2.6999998092651367 + 2.6999998092651367 + 2.6999998092651367 + 0.89999997615814209 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20B%2FW%20Light%2004.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20B%2FW%20Light%2004.xml new file mode 100644 index 0000000000..fa71d78f4a --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20B%2FW%20Light%2004.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0 + 0 + 0 + + blue_density + + 1.7999999523162842 + 1.7999999523162842 + 1.7999999523162842 + 0.89999997615814209 + + blue_horizon + + 2 + 2 + 2 + 1 + + cloud_color + + 0.22615529217625469 + 0.22615529217625469 + 0.22615529217625469 + 0.99999702096404042 + + cloud_pos_density1 + + 0.5 + 0.5 + 0.88000003558816353 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.125 + 1 + + cloud_scale + + 0.41999998688697815 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.49940033104544 + 10.011000058908452 + + cloud_shadow + + 0.26999998092651367 + 0 + 0 + 1 + + density_multiplier + + 0.0003761999832931906 + 0 + 0 + 1 + + distance_multiplier + + 31.80000114440918 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1 + 0 + 0 + 1 + + glow + + 5.3999996185302734 + 0.0010000000474974513 + -0.74999994039535522 + 1 + + haze_density + + 3.6292644654378239 + 0 + 0 + 1 + + haze_horizon + + 0.017144030545153739 + 0.19915600403562983 + 0.19915600403562983 + 1 + + lightnorm + + 0 + 0.29445916414260864 + -0.95566403865814209 + 0 + + max_y + + 869.42607640502217 + 0 + 0 + 1 + + preset_num + 21 + star_brightness + 1.7856996059417725 + sun_angle + 2.842703104019165 + sunlight_color + + 3 + 3 + 3 + 1 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20B%2FW%20Light%2005.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20B%2FW%20Light%2005.xml new file mode 100644 index 0000000000..df9427703a --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20B%2FW%20Light%2005.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.1875 + 0.1875 + 0.1875 + 0.0625 + + blue_density + + 1.7999999523162842 + 1.7999999523162842 + 1.7999999523162842 + 0.89999997615814209 + + blue_horizon + + 1.7999999523162842 + 1.7999999523162842 + 1.7999999523162842 + 0.89999997615814209 + + cloud_color + + 0.40999999642372131 + 0.40999999642372131 + 0.40999999642372131 + 0.40999999642372131 + + cloud_pos_density1 + + 1.6884100437164307 + 0.52609699964523315 + 1 + 1 + + cloud_pos_density2 + + 1.6884100437164307 + 0.52609699964523315 + 0.125 + 1 + + cloud_scale + + 0.41999998688697815 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.199999809265137 + 10.01099967956543 + + cloud_shadow + + 0.44999998807907104 + 0 + 0 + 1 + + density_multiplier + + 0.00013000000035390258 + 0 + 0 + 1 + + distance_multiplier + + 21.700000762939453 + 0 + 0 + 1 + + east_angle + 1.9477875232696533 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1.3999999761581421 + 0 + 0 + 1 + + glow + + 5 + 0.0010000000474974513 + -0.47999998927116394 + 1 + + haze_density + + 0.69999998807907104 + 0 + 0 + 1 + + haze_horizon + + 0.20999999344348907 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + -0.51655691862106323 + 0.83146905899047852 + -0.20451940596103668 + 0 + + max_y + + 242 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0 + sun_angle + 0.98174667358398438 + sunlight_color + + 2.6999998092651367 + 2.6999998092651367 + 2.6999998092651367 + 0.89999997615814209 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20B%2FW%20Light%2006.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20B%2FW%20Light%2006.xml new file mode 100644 index 0000000000..d0ba4bb023 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20B%2FW%20Light%2006.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.1875 + 0.1875 + 0.1875 + 0.0625 + + blue_density + + 1.7999999523162842 + 1.7999999523162842 + 1.7999999523162842 + 0.89999997615814209 + + blue_horizon + + 1.7999999523162842 + 1.7999999523162842 + 1.7999999523162842 + 0.89999997615814209 + + cloud_color + + 0.5 + 0.5 + 0.5 + 0.5 + + cloud_pos_density1 + + 1.6884100437164307 + 0.52609699964523315 + 0.99409997463226318 + 1 + + cloud_pos_density2 + + 1.6884100437164307 + 0.52609699964523315 + 0.125 + 1 + + cloud_scale + + 0.49579998850822449 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.70001220703125 + 10.01099967956543 + + cloud_shadow + + 0.29999998211860657 + 0 + 0 + 1 + + density_multiplier + + 0.00015750000602565706 + 0 + 0 + 1 + + distance_multiplier + + 4.5999999046325684 + 0 + 0 + 1 + + east_angle + 1.9477875232696533 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1.3999999761581421 + 0 + 0 + 1 + + glow + + 5 + 0.0010000000474974513 + -0.47999998927116394 + 1 + + haze_density + + 1.7400000095367432 + 0 + 0 + 1 + + haze_horizon + + 0.070000000298023224 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + -0.51655691862106323 + 0.83146905899047852 + -0.20451940596103668 + 0 + + max_y + + 11 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0 + sun_angle + 0.98174667358398438 + sunlight_color + + 2.6999998092651367 + 2.6999998092651367 + 2.6999998092651367 + 0.89999997615814209 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20B%2FW%20Light%2007.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20B%2FW%20Light%2007.xml new file mode 100644 index 0000000000..f62fe8cd04 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20B%2FW%20Light%2007.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0 + 0 + 0 + + blue_density + + 0 + 0 + 0 + 0 + + blue_horizon + + 0 + 0 + 0 + 0 + + cloud_color + + 0.5 + 0.5 + 0.5 + 0.5 + + cloud_pos_density1 + + 0.5 + 0.5 + 0.76829999685287476 + 1 + + cloud_pos_density2 + + 1 + 1 + 0 + 1 + + cloud_scale + + 0.00039999998989515007 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.49940033104544 + 10.011000058908452 + + cloud_shadow + + 0.19999998807907104 + 0 + 0 + 1 + + density_multiplier + + 0.0010865998920053244 + 0 + 0 + 1 + + distance_multiplier + + 1000 + 0 + 0 + 1 + + east_angle + 1.5016813278198242 + enable_cloud_scroll + + 1 + 1 + + gamma + + 0.17999999225139618 + 0 + 0 + 1 + + glow + + 40 + 0.0010000000474974513 + -10 + 1 + + haze_density + + 5 + 0 + 0 + 1 + + haze_horizon + + 5 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0.97396135330200195 + 0.21645671129226685 + -0.067422725260257721 + 0 + + max_y + + 2077 + 0 + 0 + 1 + + preset_num + 21 + star_brightness + 0 + sun_angle + 2.9234089851379395 + sunlight_color + + 3 + 3 + 3 + 1 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20B%2FW%20Light%2008.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20B%2FW%20Light%2008.xml new file mode 100644 index 0000000000..4ecf8c2a69 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20B%2FW%20Light%2008.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0 + 0 + 0 + + blue_density + + 0.39999997615814209 + 0.39999997615814209 + 0.39999997615814209 + 0.19999998807907104 + + blue_horizon + + 1 + 1 + 1 + 0.5 + + cloud_color + + 0.22617273092134837 + 0.2261830306064212 + 0.22618354559006093 + 1 + + cloud_pos_density1 + + 0.5 + 0.5 + 1 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.12499716758729562 + 1 + + cloud_scale + + 0.22999998927116394 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.499370784775238 + 10.011009025563908 + + cloud_shadow + + 0.26999998092651367 + 0 + 0 + 1 + + density_multiplier + + 0.00089999998454004526 + 0 + 0 + 1 + + distance_multiplier + + 100 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 0 + 0 + + gamma + + 1 + 0 + 0 + 1 + + glow + + 0.19999980926513672 + 0.0010000000474974513 + 0 + 1 + + haze_density + + 0.5 + 0 + 0 + 1 + + haze_horizon + + 0.32999998331069946 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0 + 1 + -4.3711388286737929e-008 + 0 + + max_y + + 4000 + 0 + 0 + 1 + + preset_num + 18 + star_brightness + 0 + sun_angle + 1.5707963705062866 + sunlight_color + + 3 + 3 + 3 + 1 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20B%2FW%20Light%2009.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20B%2FW%20Light%2009.xml new file mode 100644 index 0000000000..1a9ebda49b --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20B%2FW%20Light%2009.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0 + 0 + 0 + + blue_density + + 1.5 + 1.5 + 1.5 + 0.75 + + blue_horizon + + 1.5 + 1.5 + 1.5 + 0.75 + + cloud_color + + 1 + 1 + 1 + 1 + + cloud_pos_density1 + + 0.95999997854232788 + 0.31000000238418579 + 0.34149998426437378 + 1 + + cloud_pos_density2 + + 1 + 1 + 0 + 1 + + cloud_scale + + 0.026399999856948853 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.49940033104544 + 10.011000058908452 + + cloud_shadow + + 0.29999998211860657 + 0 + 0 + 1 + + density_multiplier + + 0.00018439999257680029 + 0 + 0 + 1 + + distance_multiplier + + 9.3000001907348633 + 0 + 0 + 1 + + east_angle + 0.78539818525314331 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1 + 0 + 0 + 1 + + glow + + 15.799999237060547 + 0.0010000000474974513 + -0.74999994039535522 + 1 + + haze_density + + 1.5299999713897705 + 0 + 0 + 1 + + haze_horizon + + 0.12999999523162842 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + -0.64968371391296387 + 0.39474311470985413 + 0.64968371391296387 + 0 + + max_y + + 4000 + 0 + 0 + 1 + + preset_num + 21 + star_brightness + 2 + sun_angle + 0.40578824281692505 + sunlight_color + + 3 + 3 + 3 + 1 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20B%2FW%20Light%2010.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20B%2FW%20Light%2010.xml new file mode 100644 index 0000000000..0dac493550 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20B%2FW%20Light%2010.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0 + 0 + 0 + + blue_density + + 0 + 0 + 0 + 0 + + blue_horizon + + 0 + 0 + 0 + 0 + + cloud_color + + 0.5 + 0.5 + 0.5 + 0.5 + + cloud_pos_density1 + + 0.5 + 0.5 + 0.76829999685287476 + 1 + + cloud_pos_density2 + + 1 + 1 + 0 + 1 + + cloud_scale + + 0.00039999998989515007 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.49940033104544 + 10.011000058908452 + + cloud_shadow + + 0.18999999761581421 + 0 + 0 + 1 + + density_multiplier + + 0.001574800000526011 + 0 + 0 + 1 + + distance_multiplier + + 1083.300048828125 + 0 + 0 + 1 + + east_angle + 1.5016813278198242 + enable_cloud_scroll + + 1 + 1 + + gamma + + 0.20999999344348907 + 0 + 0 + 1 + + glow + + 100 + 0.0010000000474974513 + -25 + 1 + + haze_density + + 1.0070000886917114 + 0 + 0 + 1 + + haze_horizon + + 5.0410003662109375 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0.97396135330200195 + 0.21645671129226685 + -0.067422725260257721 + 0 + + max_y + + 100000 + 0 + 0 + 1 + + preset_num + 21 + star_brightness + 0 + sun_angle + 2.9234089851379395 + sunlight_color + + 3 + 3 + 3 + 1 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20B%2FW%20Light%2011.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20B%2FW%20Light%2011.xml new file mode 100644 index 0000000000..491a9eeb64 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20B%2FW%20Light%2011.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0 + 0 + 0 + + blue_density + + 0 + 0 + 0 + 0 + + blue_horizon + + 0 + 0 + 0 + 0 + + cloud_color + + 0.40999999642372131 + 0.40999999642372131 + 0.40999999642372131 + 0.40999999642372131 + + cloud_pos_density1 + + 1.6884100437164307 + 0.52609699964523315 + 1 + 1 + + cloud_pos_density2 + + 1.6884100437164307 + 0.52609699964523315 + 0.125 + 1 + + cloud_scale + + 0.41999998688697815 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.199999809265137 + 10.01099967956543 + + cloud_shadow + + 0 + 0 + 0 + 1 + + density_multiplier + + 0.00036219999310560524 + 0 + 0 + 1 + + distance_multiplier + + 9.3000001907348633 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 2.1599998474121094 + 0 + 0 + 1 + + glow + + 5 + 0.0010000000474974513 + -0.47999998927116394 + 1 + + haze_density + + 1.3799999952316284 + 0 + 0 + 1 + + haze_horizon + + 0.11999999731779099 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0 + 1 + -4.3711388286737929e-008 + 0 + + max_y + + 45 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0 + sun_angle + 1.5707963705062866 + sunlight_color + + 3 + 3 + 3 + 1 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20B%2FW%20Light%2012.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20B%2FW%20Light%2012.xml new file mode 100644 index 0000000000..4e10ae8a97 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20B%2FW%20Light%2012.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0 + 0 + 0 + + blue_density + + 2 + 2 + 2 + 1 + + blue_horizon + + 0 + 0 + 0 + 0 + + cloud_color + + 0.40999999642372131 + 0.40999999642372131 + 0.40999999642372131 + 0.40999999642372131 + + cloud_pos_density1 + + 1.6884100437164307 + 0.52609699964523315 + 1 + 1 + + cloud_pos_density2 + + 1.6884100437164307 + 0.52609699964523315 + 0.125 + 1 + + cloud_scale + + 0.41999998688697815 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.199999809265137 + 10.01099967956543 + + cloud_shadow + + 0 + 0 + 0 + 1 + + density_multiplier + + 0.00074019999010488391 + 0 + 0 + 1 + + distance_multiplier + + 10.199999809265137 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 10 + 0 + 0 + 1 + + glow + + 0.19999980926513672 + 0.0010000000474974513 + -0.64999938011169434 + 1 + + haze_density + + 1.4499999284744263 + 0 + 0 + 1 + + haze_horizon + + 0.11999999731779099 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0 + 0.81158280372619629 + -0.58423745632171631 + 0 + + max_y + + 1846 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0 + sun_angle + 2.1947364807128906 + sunlight_color + + 3 + 3 + 3 + 1 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20B%2FW%20Light%2013.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20B%2FW%20Light%2013.xml new file mode 100644 index 0000000000..6555024384 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20B%2FW%20Light%2013.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0 + 0 + 0 + + blue_density + + 0 + 0 + 0 + 0 + + blue_horizon + + 0 + 0 + 0 + 0 + + cloud_color + + 0.5 + 0.5 + 0.5 + 0.5 + + cloud_pos_density1 + + 0.5 + 0.5 + 0 + 1 + + cloud_pos_density2 + + 1 + 1 + 0 + 1 + + cloud_scale + + 0 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.49940033104544 + 10.011000058908452 + + cloud_shadow + + 0.1983799934387207 + 0 + 0 + 1 + + density_multiplier + + 0.00074799999129027128 + 0 + 0 + 1 + + distance_multiplier + + 163.80000305175781 + 0 + 0 + 1 + + east_angle + 1.5016813278198242 + enable_cloud_scroll + + 1 + 1 + + gamma + + 0.17999999225139618 + 0 + 0 + 1 + + glow + + 100 + 0.0010000000474974513 + -25 + 1 + + haze_density + + 0.33600002527236938 + 0 + 0 + 1 + + haze_horizon + + 5.0370001792907715 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0.97396135330200195 + 0.21645671129226685 + -0.067422725260257721 + 0 + + max_y + + 100000 + 0 + 0 + 1 + + preset_num + 21 + star_brightness + 0 + sun_angle + 2.9234089851379395 + sunlight_color + + 3 + 3 + 3 + 1 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Boken%20Lines%20Light%2001.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Boken%20Lines%20Light%2001.xml new file mode 100644 index 0000000000..8b1a001b18 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Boken%20Lines%20Light%2001.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0 + 0 + 0 + + blue_density + + 2 + 2 + 2 + 1 + + blue_horizon + + 2 + 2 + 2 + 1 + + cloud_color + + 0 + 0 + 0 + 0 + + cloud_pos_density1 + + 0.5 + 0.5 + 0 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.34000000357627869 + 1 + + cloud_scale + + 0 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.49940033104544 + 10.011000058908452 + + cloud_shadow + + -0.485443115234375 + 0 + 0 + 1 + + density_multiplier + + 3.9400001696776599e-005 + 0 + 0 + 1 + + distance_multiplier + + 10000 + 0 + 0 + 1 + + east_angle + 0.19477875530719757 + enable_cloud_scroll + + 0 + 0 + + gamma + + 9.25 + 0 + 0 + 1 + + glow + + 16.80000114440918 + 0.0010000000474974513 + -0.59999996423721313 + 1 + + haze_density + + 0 + 0 + 0 + 1 + + haze_horizon + + 0 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + -0.14745019376277924 + 0.64778679609298706 + 0.74741601943969727 + 0 + + max_y + + 4 + 0 + 0 + 1 + + preset_num + 21 + star_brightness + 0 + sun_angle + 0.70467567443847656 + sunlight_color + + 3 + 3 + 3 + 1 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Breakwave%20Building%20Light.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Breakwave%20Building%20Light.xml new file mode 100644 index 0000000000..0fadd9c759 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Breakwave%20Building%20Light.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0 + 0 + 0 + + blue_density + + 1 + 1 + 1 + 0.5 + + blue_horizon + + 0 + 0 + 0 + 0 + + cloud_color + + 1 + 1 + 1 + 1 + + cloud_pos_density1 + + 0.37000000476837158 + 0.79999995231628418 + 0.12429999560117722 + 1 + + cloud_pos_density2 + + 0.97999995946884155 + 0.70999997854232788 + 0.049999997019767761 + 1 + + cloud_scale + + 0.17359998822212219 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.088005410620646 + 10.010458310484864 + + cloud_shadow + + 0.47300004959106445 + 0 + 0 + 1 + + density_multiplier + + 9.4499999249819666e-005 + 0 + 0 + 1 + + distance_multiplier + + 39.400001525878906 + 0 + 0 + 1 + + east_angle + 5.4852209091186523 + enable_cloud_scroll + + 0 + 1 + + gamma + + 1 + 0 + 0 + 1 + + glow + + 9.4000005722045898 + 0.0010000000474974513 + -0.44999998807907104 + 1 + + haze_density + + 0.070000000298023224 + 0 + 0 + 1 + + haze_horizon + + 0.17999999225139618 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0.47905999422073364 + 0.74313849210739136 + 0.46716883778572083 + 0 + + max_y + + 3615 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0.1029166579246521 + sun_angle + 0.83774858713150024 + sunlight_color + + 3 + 3 + 3 + 1 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Build%20002%20Light.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Build%20002%20Light.xml new file mode 100644 index 0000000000..de207f503f --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Build%20002%20Light.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.15000000596046448 + 0.15000000596046448 + 0.15000000596046448 + 0.05000000074505806 + + blue_density + + 0 + 0 + 0 + 0 + + blue_horizon + + 0 + 0 + 0 + 0 + + cloud_color + + 0.75 + 0.75 + 0.75 + 0.75 + + cloud_pos_density1 + + 0.57999998331069946 + 0.87000000476837158 + 0.75 + 1 + + cloud_pos_density2 + + 1.6884100437164307 + 0.52609699964523315 + 0.073541670078411725 + 1 + + cloud_scale + + 0 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.088005410620646 + 10.010458310484864 + + cloud_shadow + + 0 + 0 + 0 + 1 + + density_multiplier + + 0 + 0 + 0 + 1 + + distance_multiplier + + 0 + 0 + 0 + 1 + + east_angle + 3.0473451614379883 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1.4199999570846558 + 0 + 0 + 1 + + glow + + 9.4000005722045898 + 0.0010000000474974513 + 2.4000000953674316 + 1 + + haze_density + + 5 + 0 + 0 + 1 + + haze_horizon + + 5 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0.083091713488101959 + 0.46948650479316711 + 0.87902116775512695 + 0 + + max_y + + 6538 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 500 + sun_angle + 2.6528835296630859 + sunlight_color + + 3 + 3 + 3 + 1 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Build%20003%20Light.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Build%20003%20Light.xml new file mode 100644 index 0000000000..5f4bc38dd3 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Build%20003%20Light.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0 + 0 + 0 + + blue_density + + 1 + 1 + 1 + 0.5 + + blue_horizon + + 0.45819997787475586 + 0.51910001039505005 + 0.70179998874664307 + 0.35089999437332153 + + cloud_color + + 1 + 1 + 1 + 1 + + cloud_pos_density1 + + 0.78999996185302734 + 0.85999995470046997 + 0.76330000162124634 + 1 + + cloud_pos_density2 + + 0.97999995946884155 + 0.70999997854232788 + 0 + 1 + + cloud_scale + + 0.39659997820854187 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.088005410620646 + 10.010458310484864 + + cloud_shadow + + 0.43999999761581421 + 0 + 0 + 1 + + density_multiplier + + 9.4499999249819666e-005 + 0 + 0 + 1 + + distance_multiplier + + 39.400001525878906 + 0 + 0 + 1 + + east_angle + 2.670353889465332 + enable_cloud_scroll + + 0 + 1 + + gamma + + 1 + 0 + 0 + 1 + + glow + + 9.4000005722045898 + 0.0010000000474974513 + -0.44999998807907104 + 1 + + haze_density + + 0.070000000298023224 + 0 + 0 + 1 + + haze_horizon + + 0.17999999225139618 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + -0.30378204584121704 + 0.74313849210739136 + -0.59620606899261475 + 0 + + max_y + + 3615 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0.1029166579246521 + sun_angle + 0.83774858713150024 + sunlight_color + + 3 + 3 + 3 + 1 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Build%20005%20Light.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Build%20005%20Light.xml new file mode 100644 index 0000000000..7d11023464 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Build%20005%20Light.xml @@ -0,0 +1,141 @@ + + + ambient + + 1.2899999618530273 + 1.2899999618530273 + 1.2899999618530273 + 0.43000000715255737 + + blue_density + + 0 + 0 + 0 + 0 + + blue_horizon + + 0 + 0 + 0 + 0 + + cloud_color + + 0.75 + 0.75 + 0.75 + 0.75 + + cloud_pos_density1 + + 0.57999998331069946 + 0.87000000476837158 + 0.75 + 1 + + cloud_pos_density2 + + 1.6884100437164307 + 0.52609699964523315 + 0.073541670078411725 + 1 + + cloud_scale + + 0 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.088005410620646 + 10.010458310484864 + + cloud_shadow + + 0 + 0 + 0 + 1 + + density_multiplier + + 0 + 0 + 0 + 1 + + distance_multiplier + + 0 + 0 + 0 + 1 + + east_angle + 0.60946899652481079 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1 + 0 + 0 + 1 + + glow + + 9.4000005722045898 + 0.0010000000474974513 + 2.4000000953674316 + 1 + + haze_density + + 5 + 0 + 0 + 1 + + haze_horizon + + 5 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0.36985558271408081 + 0.76324218511581421 + -0.5297812819480896 + 0 + + max_y + + 6538 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 500 + sun_angle + 2.2732763290405273 + sunlight_color + + 3 + 3 + 3 + 1 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Build%20007%20Light.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Build%20007%20Light.xml new file mode 100644 index 0000000000..06034997f9 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Build%20007%20Light.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.17999999225139618 + 0.17999999225139618 + 0.17999999225139618 + 0.059999998658895493 + + blue_density + + 1.5 + 1.5 + 1.5 + 0.75 + + blue_horizon + + 0 + 0 + 0 + 0 + + cloud_color + + 0 + 0 + 0 + 0 + + cloud_pos_density1 + + 0.93999999761581421 + 0.22999998927116394 + 0.38409999012947083 + 1 + + cloud_pos_density2 + + 1 + 0.50999999046325684 + 1 + 1 + + cloud_scale + + 0.31279999017715454 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.199999809265137 + 10.01099967956543 + + cloud_shadow + + 0 + 0 + 0 + 1 + + density_multiplier + + 0 + 0 + 0 + 1 + + distance_multiplier + + 0 + 0 + 0 + 1 + + east_angle + 4.3416814804077148 + enable_cloud_scroll + + 0 + 0 + + gamma + + 2.6099998950958252 + 0 + 0 + 1 + + glow + + 5 + 0.0010000000474974513 + -0.47999998927116394 + 1 + + haze_density + + 0 + 0 + 0 + 1 + + haze_horizon + + 0 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + -0.6760907769203186 + 0.68836575746536255 + 0.26278114318847656 + 0 + + max_y + + 242 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0 + sun_angle + 2.3823590278625488 + sunlight_color + + 3 + 3 + 3 + 1 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Cafe%20Light%2001.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Cafe%20Light%2001.xml new file mode 100644 index 0000000000..7c10c0df46 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Cafe%20Light%2001.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0 + 0 + 0 + + blue_density + + 0.12089811412885521 + 0.33770671695460663 + 0.67541757891583387 + 0.76708334654569654 + + blue_horizon + + 0.13497034943045882 + 0.26690842067701936 + 0.4016666400432598 + 0.74541666984558219 + + cloud_color + + 0.625 + 0.625 + 0.875 + 0.875 + + cloud_pos_density1 + + 0.47999998927116394 + 0.97999995946884155 + 0.14630000293254852 + 1 + + cloud_pos_density2 + + 1 + 1 + 0.070000000298023224 + 1 + + cloud_scale + + 0.22280000150203705 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.088005410620646 + 10.010458310484864 + + cloud_shadow + + 0.5 + 0 + 0 + 1 + + density_multiplier + + 0.00028125001798306321 + 0 + 0 + 1 + + distance_multiplier + + 6.3874998847643383 + 0 + 0 + 1 + + east_angle + 3.5185837745666504 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1.0900000333786011 + 0 + 0 + 1 + + glow + + 9.4000005722045898 + 0.0010000000474974513 + -0.44999998807907104 + 1 + + haze_density + + 0.51583333298563971 + 0 + 0 + 1 + + haze_horizon + + 0.13833333183079954 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0.28709480166435242 + 0.6259227991104126 + -0.72511875629425049 + 0 + + max_y + + 685.18749099969864 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 2 + sun_angle + 0.67631423473358154 + sunlight_color + + 0 + 0 + 0 + 0 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Calima%20Light%2001.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Calima%20Light%2001.xml new file mode 100644 index 0000000000..8cdc45ec0a --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Calima%20Light%2001.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.21000000834465027 + 0.21000000834465027 + 0.21000000834465027 + 0.070000000298023224 + + blue_density + + 2 + 2 + 2 + 1 + + blue_horizon + + 2 + 2 + 2 + 1 + + cloud_color + + 0.28666070103645325 + 0.28666070103645325 + 0.28666070103645325 + 0.28666070103645325 + + cloud_pos_density1 + + 0.17999999225139618 + 0.50999999046325684 + 0.91949393667753065 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.125 + 1 + + cloud_scale + + 1.437999963760376 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.400862650389627 + 10.01099967956543 + + cloud_shadow + + -0.27299976348876953 + 0 + 0 + 1 + + density_multiplier + + 0.011666699312627316 + 0 + 0 + 1 + + distance_multiplier + + 0.10000000149011612 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 10 + 0 + 0 + 1 + + glow + + 22.000003814697266 + 0.0010000000474974513 + -7.5 + 1 + + haze_density + + 0.33600002527236938 + 0 + 0 + 1 + + haze_horizon + + 11.530000686645508 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0 + 0.35022372007369995 + -0.93666607141494751 + 0 + + max_y + + 0 + 0 + 0 + 1 + + preset_num + 18 + star_brightness + 0 + sun_angle + 2.7837827205657959 + sunlight_color + + 0.32999998331069946 + 0.32999998331069946 + 0.32999998331069946 + 0.10999999940395355 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Charolotte%20Light.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Charolotte%20Light.xml new file mode 100644 index 0000000000..623c258f50 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Charolotte%20Light.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0 + 0 + 0 + + blue_density + + 2 + 2 + 2 + 1 + + blue_horizon + + 2 + 2 + 2 + 1 + + cloud_color + + 0.40999999642372131 + 0.40999999642372131 + 0.40999999642372131 + 0.40999999642372131 + + cloud_pos_density1 + + 1.6884100437164307 + 0.52609699964523315 + 1 + 1 + + cloud_pos_density2 + + 1.6884100437164307 + 0.52609699964523315 + 0.125 + 1 + + cloud_scale + + 0.41999998688697815 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.199999809265137 + 10.01099967956543 + + cloud_shadow + + 0 + 0 + 0 + 1 + + density_multiplier + + 0.0006399999838322401 + 0 + 0 + 1 + + distance_multiplier + + 100 + 0 + 0 + 1 + + east_angle + 2.6515045166015625 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1.3042999505996704 + 0 + 0 + 1 + + glow + + 0.19999980926513672 + 0.0010000000474974513 + -2.5 + 1 + + haze_density + + 4 + 0 + 0 + 1 + + haze_horizon + + 1 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + -0.063475340604782104 + 0.99086576700210571 + -0.11897877603769302 + 0 + + max_y + + 4000 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0 + sun_angle + 1.4355322122573853 + sunlight_color + + 3 + 0 + 3 + 1 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Cloud%20Credit%20Light.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Cloud%20Credit%20Light.xml new file mode 100644 index 0000000000..baab0d39e7 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Cloud%20Credit%20Light.xml @@ -0,0 +1,141 @@ + + + ambient + + 3 + 3 + 3 + 1 + + blue_density + + 2 + 2 + 2 + 1 + + blue_horizon + + 0 + 0 + 0 + 0 + + cloud_color + + 1 + 1 + 1 + 1 + + cloud_pos_density1 + + 0.95999997854232788 + 0.17999999225139618 + 0.12429999560117722 + 1 + + cloud_pos_density2 + + 1 + 0.5899999737739563 + 0 + 1 + + cloud_scale + + 0.074400000274181366 + 0 + 0 + 1 + + cloud_scroll_rate + + 76.100006103515625 + 10.70001220703125 + + cloud_shadow + + 0.29999998211860657 + 0 + 0 + 1 + + density_multiplier + + 0 + 0 + 0 + 1 + + distance_multiplier + + 0 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 0 + 0 + + gamma + + 7.8399996757507324 + 0 + 0 + 1 + + glow + + 0.19999980926513672 + 0.0010000000474974513 + 0.64999997615814209 + 1 + + haze_density + + 0 + 0 + 0 + 1 + + haze_horizon + + 0 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0 + 0.8508676290512085 + -0.52538013458251953 + 0 + + max_y + + 0 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0 + sun_angle + 2.1239581108093262 + sunlight_color + + 0 + 0 + 0 + 0 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Cloud%20Light%2001.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Cloud%20Light%2001.xml new file mode 100644 index 0000000000..d0456f444a --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Cloud%20Light%2001.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0 + 0 + 0 + + blue_density + + 2 + 2 + 2 + 1 + + blue_horizon + + 0 + 0 + 0 + 0 + + cloud_color + + 0.5 + 0.5 + 1 + 1 + + cloud_pos_density1 + + 0.95999997854232788 + 0.31000000238418579 + 3 + 1 + + cloud_pos_density2 + + 1 + 1 + 0.71999996900558472 + 1 + + cloud_scale + + 0.2231999933719635 + 0 + 0 + 1 + + cloud_scroll_rate + + 18.5 + -3 + + cloud_shadow + + 0.15999999642372131 + 0 + 0 + 1 + + density_multiplier + + 3.299999889350147e-006 + 0 + 0 + 1 + + distance_multiplier + + 0 + 0 + 0 + 1 + + east_angle + 3.1855752468109131 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1 + 0 + 0 + 1 + + glow + + 15.799999237060547 + 0.0010000000474974513 + -0.74999994039535522 + 1 + + haze_density + + 0 + 0 + 0 + 1 + + haze_horizon + + 4.8899998664855957 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0.040397927165031433 + 0.39473667740821838 + -0.91790574789047241 + 0 + + max_y + + 385 + 0 + 0 + 1 + + preset_num + 21 + star_brightness + 500 + sun_angle + 0.40578123927116394 + sunlight_color + + 0 + 0 + 0 + 0 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Dead%20End%20Sky%2001.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Dead%20End%20Sky%2001.xml new file mode 100644 index 0000000000..53a9cad037 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Dead%20End%20Sky%2001.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.83636385202407837 + 1.0036364793777466 + 1.3799998760223389 + 0.45999997854232788 + + blue_density + + 0 + 0 + 0 + 0 + + blue_horizon + + 2 + 0 + 0 + 1 + + cloud_color + + 0 + 0 + 0 + 0 + + cloud_pos_density1 + + 1.6884100437164307 + 0.52609699964523315 + 0.87999999523162842 + 1 + + cloud_pos_density2 + + 1.6884100437164307 + 0.52609699964523315 + 0.125 + 1 + + cloud_scale + + 0.0099999997764825821 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.510000228881836 + 10.01099967956543 + + cloud_shadow + + 0 + 0 + 0 + 1 + + density_multiplier + + 0.00018999999156221747 + 0 + 0 + 1 + + distance_multiplier + + 56.700000762939453 + 0 + 0 + 1 + + east_angle + 4.7123889923095703 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1.1499999761581421 + 0 + 0 + 1 + + glow + + 5 + 0.0010000000474974513 + -0.47999998927116394 + 1 + + haze_density + + 0.11999999731779099 + 0 + 0 + 1 + + haze_horizon + + 0.25 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0.98078560829162598 + 0.19508861005306244 + 1.1695751034324076e-008 + 1 + + max_y + + 906 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 2 + sun_angle + 3.3379404544830322 + sunlight_color + + 0.59999996423721313 + 0.59999996423721313 + 1.1399999856948853 + 1.1399999856948853 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Dorm%20Light%2001.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Dorm%20Light%2001.xml new file mode 100644 index 0000000000..f4a22b8a2f --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Dorm%20Light%2001.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.26250001788139343 + 0.3031250536441803 + 0.75 + 0.25 + + blue_density + + 1 + 0.5 + 0 + 0.5 + + blue_horizon + + 0 + 0 + 0 + 0 + + cloud_color + + 0.23999999463558197 + 0.4699999988079071 + 0.31999999284744263 + 0.4699999988079071 + + cloud_pos_density1 + + 0.48999997973442078 + 0.50999999046325684 + 0.74000000953674316 + 1 + + cloud_pos_density2 + + 0.44999998807907104 + 0.5 + 0.14000000059604645 + 1 + + cloud_scale + + 0.32999998331069946 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.49940013885498 + 10.01099967956543 + + cloud_shadow + + 0.37999999523162842 + 0 + 0 + 1 + + density_multiplier + + 7.3799994424916804e-005 + 0 + 0 + 1 + + distance_multiplier + + 41.100002288818359 + 0 + 0 + 1 + + east_angle + 2.4064600467681885 + enable_cloud_scroll + + 0 + 0 + + gamma + + 3.2173998355865479 + 0 + 0 + 1 + + glow + + 12 + 0.0010000000474974513 + -0.59999996423721313 + 1 + + haze_density + + 1.3500000238418579 + 0 + 0 + 1 + + haze_horizon + + 0.15999999642372131 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0.67022424936294556 + 0.037081710994243622 + 0.74123167991638184 + 0 + + max_y + + 0 + 0 + 0 + 1 + + preset_num + 18 + star_brightness + 1.0099999904632568 + sun_angle + 3.1045024394989014 + sunlight_color + + 2.5799999237060547 + 2.4411697387695313 + 2.4411697387695313 + 0.86000001430511475 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Dream%20Book%20Light%2001.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Dream%20Book%20Light%2001.xml new file mode 100644 index 0000000000..278ce095da --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Dream%20Book%20Light%2001.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.031499996781349182 + 0.15789999067783356 + 0.26850000023841858 + 0.089500002562999725 + + blue_density + + 0 + 1.3200000524520874 + 1.3199996948242188 + 0.6600000262260437 + + blue_horizon + + 0 + 0.79687511920928955 + 0.79687494039535522 + 0.39843755960464478 + + cloud_color + + 0.2481999397277832 + 0.60211998224258423 + 0.91180002689361572 + 0.91180002689361572 + + cloud_pos_density1 + + 0.69999998807907104 + 0.19999998807907104 + 1.2249000072479248 + 1 + + cloud_pos_density2 + + 0.70999997854232788 + 0.84999996423721313 + 0.35999998450279236 + 1 + + cloud_scale + + 0.29760000109672546 + 0 + 0 + 1 + + cloud_scroll_rate + + 11.70001220703125 + 10.01099967956543 + + cloud_shadow + + 0.26999998092651367 + 0 + 0 + 1 + + density_multiplier + + 0.00014170000213198364 + 0 + 0 + 1 + + distance_multiplier + + 6.5 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 0 + 1 + + gamma + + 1 + 0 + 0 + 1 + + glow + + 32.599998474121094 + 0.0010000000474974513 + -5.0500001907348633 + 1 + + haze_density + + 1.5999999046325684 + 0 + 0 + 1 + + haze_horizon + + 0.38999998569488525 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0 + 1 + -4.8876205482883961e-007 + 1 + + max_y + + 2769 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 500 + sun_angle + 4.7123894691467285 + sunlight_color + + 0.34876692295074463 + 0.35574248433113098 + 0.65999996662139893 + 0.2199999988079071 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Dream%20Book%20Light%2002.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Dream%20Book%20Light%2002.xml new file mode 100644 index 0000000000..d0ef3494cb --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Dream%20Book%20Light%2002.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.99101096746882478 + 0.90569759047448506 + 0.94676920768410944 + 0.33033699762952112 + + blue_density + + 0.15949166061381881 + 0.44534921175553777 + 0.78703662568265287 + 0.78703662568265287 + + blue_horizon + + 0.45808683258190275 + 0.46276614028103857 + 0.64592672496531911 + 0.38195237578970165 + + cloud_color + + 0.33464740594394182 + 0.33464740594394182 + 0.33464740594394182 + 0.52483933184657472 + + cloud_pos_density1 + + 0.17999999225139618 + 0.50999999046325684 + 0.97050554401449818 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.125 + 1 + + cloud_scale + + 0.41999997879515621 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.273588712934393 + 10.010999679568112 + + cloud_shadow + + 0.34000000357627869 + 0 + 0 + 1 + + density_multiplier + + 0.00028814651401716849 + 0 + 0 + 1 + + distance_multiplier + + 16.30000114440918 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1 + 0 + 0 + 1 + + glow + + 5.0002455048624084 + 0.001 + -0.4800002433233434 + 1 + + haze_density + + 0.6606740078475033 + 0 + 0 + 1 + + haze_horizon + + 0.18262636689842734 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0 + 0.99904829263687134 + -0.043617993593215942 + 0 + + max_y + + 1348.8893615007401 + 0 + 0 + 1 + + preset_num + 18 + star_brightness + 0 + sun_angle + 1.6144281625747681 + sunlight_color + + 1.1362672142439687 + 1.1719930547447106 + 1.2613076522878659 + 0.42043587660352916 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Dream%20Book%20Light%2003.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Dream%20Book%20Light%2003.xml new file mode 100644 index 0000000000..d484dbf8f3 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Dream%20Book%20Light%2003.xml @@ -0,0 +1,141 @@ + + + ambient + + 1.0298734564795637 + 0.88898782567135015 + 0.88898782567135015 + 0.79949215426478126 + + blue_density + + 0.17798297054824247 + 0.41603360580930904 + 0.78683667783050026 + 0.79594799064391797 + + blue_horizon + + 0.23530982264376704 + 0.30629670960041322 + 0.37835530224478614 + 0.77620100618916932 + + cloud_color + + 0.2866606875510479 + 0.2866606875510479 + 0.2866606875510479 + 0.80582145952723883 + + cloud_pos_density1 + + 0.17999999225139618 + 0.50999999046325684 + 0.91949393667753065 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.125 + 1 + + cloud_scale + + 0.41999998688697698 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.400862650389627 + 10.01099967956543 + + cloud_shadow + + 0.34000000357627869 + 0 + 0 + 1 + + density_multiplier + + 0.00036784747657809082 + 0 + 0 + 1 + + distance_multiplier + + 0.93417677079577877 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1 + 0 + 0 + 1 + + glow + + 5 + 0.0010000000474974513 + -0.47999998927116394 + 1 + + haze_density + + 0.69999998807907104 + 0 + 0 + 1 + + haze_horizon + + 0.16987348178519687 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0 + 0.30417308211326599 + -0.95261681079864502 + 0 + + max_y + + 905.60360267758369 + 0 + 0 + 1 + + preset_num + 18 + star_brightness + 0 + sun_angle + 2.8325223922729492 + sunlight_color + + 2.1459913660813905 + 2.1615810746477075 + 2.2005553460635001 + 0.76961867816836427 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Dream%20Book%20Light%2004.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Dream%20Book%20Light%2004.xml new file mode 100644 index 0000000000..2de71161f1 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Dream%20Book%20Light%2004.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.99101096746882478 + 0.90569759047448506 + 0.94676920768410944 + 0.33033699762952112 + + blue_density + + 0.15949166061381881 + 0.44534921175553777 + 0.78703662568265287 + 0.78703662568265287 + + blue_horizon + + 0.45808683258190275 + 0.46276614028103857 + 0.64592672496531911 + 0.38195237578970165 + + cloud_color + + 1 + 1 + 1 + 1 + + cloud_pos_density1 + + 0.17999999225139618 + 0.50999999046325684 + 0.97050554401449818 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.125 + 1 + + cloud_scale + + 0.41999997879515621 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.273588712934393 + 10.010999679568112 + + cloud_shadow + + 0 + 0 + 0 + 1 + + density_multiplier + + 0.00033999999868683517 + 0 + 0 + 1 + + distance_multiplier + + 31 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1 + 0 + 0 + 1 + + glow + + 5.0002455711364746 + 0.0010000000474974513 + -0.74999994039535522 + 1 + + haze_density + + 1.059999942779541 + 0 + 0 + 1 + + haze_horizon + + 0.42999997735023499 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0 + 0.99904829263687134 + -0.043617993593215942 + 0 + + max_y + + 4000 + 0 + 0 + 1 + + preset_num + 18 + star_brightness + 0 + sun_angle + 1.6144281625747681 + sunlight_color + + 1.1362672142439687 + 1.1719930547447106 + 1.2613076522878659 + 0.42043587660352916 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Epi%20Vintage%20Light.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Epi%20Vintage%20Light.xml new file mode 100644 index 0000000000..1bb93ec236 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Epi%20Vintage%20Light.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.29999998211860657 + 0.17999999225139618 + 0 + 0.099999994039535522 + + blue_density + + 0.97999995946884155 + 0.97999995946884155 + 0.97999995946884155 + 0.48999997973442078 + + blue_horizon + + 0.31999999284744263 + 0.31999999284744263 + 0.31999999284744263 + 0.15999999642372131 + + cloud_color + + 0.50999999046325684 + 0.50999999046325684 + 0.50999999046325684 + 1 + + cloud_pos_density1 + + 0.5 + 0.5 + 1 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.125 + 1 + + cloud_scale + + 0.079999998211860657 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.49940013885498 + 10.01099967956543 + + cloud_shadow + + 0.25999999046325684 + 0 + 0 + 1 + + density_multiplier + + 0.00031000000308267772 + 0 + 0 + 1 + + distance_multiplier + + 40.299999237060547 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1 + 0 + 0 + 1 + + glow + + 5 + 0.0010000000474974513 + -0.33000001311302185 + 1 + + haze_density + + 2.2100000381469727 + 0 + 0 + 1 + + haze_horizon + + 0.56999999284744263 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0 + 0.36227512359619141 + -0.93207120895385742 + 0 + + max_y + + 752 + 0 + 0 + 1 + + preset_num + 21 + star_brightness + 0 + sun_angle + 2.7708849906921387 + sunlight_color + + 1.3799998760223389 + 1.3799998760223389 + 1.3799998760223389 + 0.45999997854232788 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Fashion%20Path%20Light%2001.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Fashion%20Path%20Light%2001.xml new file mode 100644 index 0000000000..14d6ab9b3d --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Fashion%20Path%20Light%2001.xml @@ -0,0 +1,141 @@ + + + ambient + + 1.5 + 1.5 + 3 + 1 + + blue_density + + 2 + 2 + 1 + 1 + + blue_horizon + + 0 + 0 + 0 + 0 + + cloud_color + + 0.43948723673439005 + 0.49764935046544778 + 0.50246442938400904 + 1 + + cloud_pos_density1 + + 0.57999998331069946 + 0.87000000476837158 + 0.75 + 1 + + cloud_pos_density2 + + 1.6884100437164307 + 0.52609699964523315 + 0.073541670078411725 + 1 + + cloud_scale + + 0.18000000715255737 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.088005410620646 + 10.010458310484864 + + cloud_shadow + + 0 + 0 + 0 + 1 + + density_multiplier + + 0.00028125001798306321 + 0 + 0 + 1 + + distance_multiplier + + 62.700000762939453 + 0 + 0 + 1 + + east_angle + 3.5185837745666504 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1.0900000333786011 + 0 + 0 + 1 + + glow + + 9.4000005722045898 + 0.0010000000474974513 + -0.44999998807907104 + 1 + + haze_density + + 0.42999997735023499 + 0 + 0 + 1 + + haze_horizon + + 0 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0.28709480166435242 + 0.6259227991104126 + -0.72511875629425049 + 0 + + max_y + + 0 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0.1029166579246521 + sun_angle + 0.67631423473358154 + sunlight_color + + 0 + 0 + 0 + 0 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Got%20It%20Light%20.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Got%20It%20Light%20.xml new file mode 100644 index 0000000000..718bd1ab5f --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Got%20It%20Light%20.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.56099998950958252 + 0.37620007991790771 + 0.099000021815299988 + 0.18699999153614044 + + blue_density + + 0.97999995946884155 + 0.97999995946884155 + 0.97999995946884155 + 0.48999997973442078 + + blue_horizon + + 0.31999999284744263 + 0.31999999284744263 + 0.31999999284744263 + 0.15999999642372131 + + cloud_color + + 0.5 + 0.5 + 0.5 + 0.5 + + cloud_pos_density1 + + 0.5 + 0.5 + 1 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.125 + 1 + + cloud_scale + + 0.12459999322891235 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.49940013885498 + 10.01099967956543 + + cloud_shadow + + 0 + 0 + 0 + 1 + + density_multiplier + + 0.0004881999921053648 + 0 + 0 + 1 + + distance_multiplier + + 3.9000000953674316 + 0 + 0 + 1 + + east_angle + 2.2870795726776123 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1.3042999505996704 + 0 + 0 + 1 + + glow + + 0.19999980926513672 + 0.0010000000474974513 + -0.04999995231628418 + 1 + + haze_density + + 3.4800000190734863 + 0 + 0 + 1 + + haze_horizon + + 0.37000000476837158 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0.70532232522964478 + 0.35430732369422913 + 0.61399251222610474 + 0 + + max_y + + 385 + 0 + 0 + 1 + + preset_num + 21 + star_brightness + 0 + sun_angle + 2.7794194221496582 + sunlight_color + + 3 + 3 + 3 + 1 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Horizon%20Building%20Light%2001.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Horizon%20Building%20Light%2001.xml new file mode 100644 index 0000000000..8b6adaae25 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Horizon%20Building%20Light%2001.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0 + 0 + 0 + + blue_density + + 1.7200000286102295 + 1.3424379825592041 + 0.83542799949645996 + 0.86000001430511475 + + blue_horizon + + 1.4582855701446533 + 1.3041387796401978 + 1.0971424579620361 + 0.72914278507232666 + + cloud_color + + 0 + 0.39843800663948059 + 0.39843699336051941 + 0.39843800663948059 + + cloud_pos_density1 + + 0.47999998927116394 + 0.87000000476837158 + 1.4378999471664429 + 1 + + cloud_pos_density2 + + 1.6884100437164307 + 0.52609699964523315 + 0.87000000476837158 + 1 + + cloud_scale + + 0.37199997901916504 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.088005410620646 + 10.010458310484864 + + cloud_shadow + + 0.55000001192092896 + 0 + 0 + 1 + + density_multiplier + + 0.00058270001318305731 + 0 + 0 + 1 + + distance_multiplier + + 63 + 0 + 0 + 1 + + east_angle + 3.5185837745666504 + enable_cloud_scroll + + 0 + 0 + + gamma + + 1.0900000333786011 + 0 + 0 + 1 + + glow + + 0.19999980926513672 + 0.0010000000474974513 + -10 + 1 + + haze_density + + 0.039999999105930328 + 0 + 0 + 1 + + haze_horizon + + 0.52999997138977051 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0.28709480166435242 + 0.6259227991104126 + -0.72511875629425049 + 0 + + max_y + + 5615 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0 + sun_angle + 0.67631423473358154 + sunlight_color + + 0 + 0 + 0 + 0 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Horizon%20Building%20Light%2002.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Horizon%20Building%20Light%2002.xml new file mode 100644 index 0000000000..0fadd9c759 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Horizon%20Building%20Light%2002.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0 + 0 + 0 + + blue_density + + 1 + 1 + 1 + 0.5 + + blue_horizon + + 0 + 0 + 0 + 0 + + cloud_color + + 1 + 1 + 1 + 1 + + cloud_pos_density1 + + 0.37000000476837158 + 0.79999995231628418 + 0.12429999560117722 + 1 + + cloud_pos_density2 + + 0.97999995946884155 + 0.70999997854232788 + 0.049999997019767761 + 1 + + cloud_scale + + 0.17359998822212219 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.088005410620646 + 10.010458310484864 + + cloud_shadow + + 0.47300004959106445 + 0 + 0 + 1 + + density_multiplier + + 9.4499999249819666e-005 + 0 + 0 + 1 + + distance_multiplier + + 39.400001525878906 + 0 + 0 + 1 + + east_angle + 5.4852209091186523 + enable_cloud_scroll + + 0 + 1 + + gamma + + 1 + 0 + 0 + 1 + + glow + + 9.4000005722045898 + 0.0010000000474974513 + -0.44999998807907104 + 1 + + haze_density + + 0.070000000298023224 + 0 + 0 + 1 + + haze_horizon + + 0.17999999225139618 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0.47905999422073364 + 0.74313849210739136 + 0.46716883778572083 + 0 + + max_y + + 3615 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0.1029166579246521 + sun_angle + 0.83774858713150024 + sunlight_color + + 3 + 3 + 3 + 1 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Horizon%20Building%20Light.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Horizon%20Building%20Light.xml new file mode 100644 index 0000000000..0fadd9c759 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Horizon%20Building%20Light.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0 + 0 + 0 + + blue_density + + 1 + 1 + 1 + 0.5 + + blue_horizon + + 0 + 0 + 0 + 0 + + cloud_color + + 1 + 1 + 1 + 1 + + cloud_pos_density1 + + 0.37000000476837158 + 0.79999995231628418 + 0.12429999560117722 + 1 + + cloud_pos_density2 + + 0.97999995946884155 + 0.70999997854232788 + 0.049999997019767761 + 1 + + cloud_scale + + 0.17359998822212219 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.088005410620646 + 10.010458310484864 + + cloud_shadow + + 0.47300004959106445 + 0 + 0 + 1 + + density_multiplier + + 9.4499999249819666e-005 + 0 + 0 + 1 + + distance_multiplier + + 39.400001525878906 + 0 + 0 + 1 + + east_angle + 5.4852209091186523 + enable_cloud_scroll + + 0 + 1 + + gamma + + 1 + 0 + 0 + 1 + + glow + + 9.4000005722045898 + 0.0010000000474974513 + -0.44999998807907104 + 1 + + haze_density + + 0.070000000298023224 + 0 + 0 + 1 + + haze_horizon + + 0.17999999225139618 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0.47905999422073364 + 0.74313849210739136 + 0.46716883778572083 + 0 + + max_y + + 3615 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0.1029166579246521 + sun_angle + 0.83774858713150024 + sunlight_color + + 3 + 3 + 3 + 1 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Hospital%20Light%2001.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Hospital%20Light%2001.xml new file mode 100644 index 0000000000..e615890c93 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Hospital%20Light%2001.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.84000003337860107 + 0.84000003337860107 + 0.84000003337860107 + 0.2800000011920929 + + blue_density + + 0 + 0 + 0 + 0 + + blue_horizon + + 2 + 2 + 2 + 1 + + cloud_color + + 1 + 1 + 1 + 1 + + cloud_pos_density1 + + 0.17999999225139618 + 0.50999999046325684 + 0.97050554401449818 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.125 + 1 + + cloud_scale + + 0.41999997879515621 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.273588712934393 + 10.010999679568112 + + cloud_shadow + + 0 + 0 + 0 + 1 + + density_multiplier + + 0.00017699999443721026 + 0 + 0 + 1 + + distance_multiplier + + 26.399999618530273 + 0 + 0 + 1 + + east_angle + 1.9163715839385986 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1 + 0 + 0 + 1 + + glow + + 5.0002455711364746 + 0.0010000000474974513 + -0.94999998807907104 + 1 + + haze_density + + 0.96999996900558472 + 0 + 0 + 1 + + haze_horizon + + 0.37999999523162842 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0.88343405723571777 + 0.34407094120979309 + 0.3180558979511261 + 0 + + max_y + + 4000 + 0 + 0 + 1 + + preset_num + 18 + star_brightness + 0 + sun_angle + 2.7903435230255127 + sunlight_color + + 3 + 3 + 3 + 1 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Hufflepuff%20Light%2001.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Hufflepuff%20Light%2001.xml new file mode 100644 index 0000000000..c5b090d137 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Hufflepuff%20Light%2001.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.56250005960464478 + 0.26250001788139343 + 0.75 + 0.25 + + blue_density + + 0 + 0.40999585390090942 + 0.81999999284744263 + 0.85999995470046997 + + blue_horizon + + 0.43999999761581421 + 0.22910800576210022 + 0.26829266548156738 + 0.2199999988079071 + + cloud_color + + 0.23999999463558197 + 0.4699999988079071 + 0.31999999284744263 + 0.4699999988079071 + + cloud_pos_density1 + + 0.48999997973442078 + 0.50999999046325684 + 0.74000000953674316 + 1 + + cloud_pos_density2 + + 0.44999998807907104 + 0.5 + 0.14000000059604645 + 1 + + cloud_scale + + 0.32999998331069946 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.49940013885498 + 10.01099967956543 + + cloud_shadow + + 0.37999999523162842 + 0 + 0 + 1 + + density_multiplier + + 0.00035999997635371983 + 0 + 0 + 1 + + distance_multiplier + + 2 + 0 + 0 + 1 + + east_angle + 0.12566371262073517 + enable_cloud_scroll + + 0 + 0 + + gamma + + 2.0299999713897705 + 0 + 0 + 1 + + glow + + 12 + 0.0010000000474974513 + -0.59999996423721313 + 1 + + haze_density + + 0.77999997138977051 + 0 + 0 + 1 + + haze_horizon + + 0.15999999642372131 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0.12524418532848358 + 0.037689968943595886 + -0.9914097785949707 + 0 + + max_y + + 591 + 0 + 0 + 1 + + preset_num + 18 + star_brightness + 1.0099999904632568 + sun_angle + 3.1038937568664551 + sunlight_color + + 2.5799999237060547 + 2.4411697387695313 + 2.4411697387695313 + 0.85999995470046997 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Hufflepuff%20Light%2002.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Hufflepuff%20Light%2002.xml new file mode 100644 index 0000000000..aaff835ebe --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Hufflepuff%20Light%2002.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.26250001788139343 + 0.3031250536441803 + 0.75 + 0.25 + + blue_density + + 1 + 0.5 + 0 + 0.5 + + blue_horizon + + 0 + 0 + 0 + 0 + + cloud_color + + 0.23999999463558197 + 0.4699999988079071 + 0.31999999284744263 + 0.4699999988079071 + + cloud_pos_density1 + + 0.48999997973442078 + 0.50999999046325684 + 0.74000000953674316 + 1 + + cloud_pos_density2 + + 0.44999998807907104 + 0.5 + 0.14000000059604645 + 1 + + cloud_scale + + 0.32999998331069946 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.49940013885498 + 10.01099967956543 + + cloud_shadow + + 0.37999999523162842 + 0 + 0 + 1 + + density_multiplier + + 0.00031719999969936907 + 0 + 0 + 1 + + distance_multiplier + + 39.5 + 0 + 0 + 1 + + east_angle + 2.4064600467681885 + enable_cloud_scroll + + 0 + 0 + + gamma + + 2.4347999095916748 + 0 + 0 + 1 + + glow + + 12 + 0.0010000000474974513 + -0.59999996423721313 + 1 + + haze_density + + 1.559999942779541 + 0 + 0 + 1 + + haze_horizon + + 0.15999999642372131 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0.67022424936294556 + 0.037081710994243622 + 0.74123167991638184 + 0 + + max_y + + 0 + 0 + 0 + 1 + + preset_num + 18 + star_brightness + 1.0099999904632568 + sun_angle + 3.1045024394989014 + sunlight_color + + 2.5799999237060547 + 2.4411697387695313 + 2.4411697387695313 + 0.86000001430511475 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Hufflepuff%20Light%2003.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Hufflepuff%20Light%2003.xml new file mode 100644 index 0000000000..82c8766966 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Hufflepuff%20Light%2003.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.56250005960464478 + 0.26250001788139343 + 0.75 + 0.25 + + blue_density + + 0 + 0.40999585390090942 + 0.81999999284744263 + 0.85999995470046997 + + blue_horizon + + 0.43999999761581421 + 0.22910800576210022 + 0.26829266548156738 + 0.2199999988079071 + + cloud_color + + 0.23999999463558197 + 0.4699999988079071 + 0.31999999284744263 + 0.4699999988079071 + + cloud_pos_density1 + + 0.48999997973442078 + 0.50999999046325684 + 0.74000000953674316 + 1 + + cloud_pos_density2 + + 0.44999998807907104 + 0.5 + 0.14000000059604645 + 1 + + cloud_scale + + 0.32999998331069946 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.49940013885498 + 10.01099967956543 + + cloud_shadow + + 0.37999999523162842 + 0 + 0 + 1 + + density_multiplier + + 0.00049000000581145287 + 0 + 0 + 1 + + distance_multiplier + + 35.700000762939453 + 0 + 0 + 1 + + east_angle + 0.12566371262073517 + enable_cloud_scroll + + 0 + 0 + + gamma + + 2.0299999713897705 + 0 + 0 + 1 + + glow + + 12 + 0.0010000000474974513 + -0.59999996423721313 + 1 + + haze_density + + 1.5899999141693115 + 0 + 0 + 1 + + haze_horizon + + 0.15999999642372131 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0.12524418532848358 + 0.037689968943595886 + -0.9914097785949707 + 0 + + max_y + + 591 + 0 + 0 + 1 + + preset_num + 18 + star_brightness + 1.0099999904632568 + sun_angle + 3.1038937568664551 + sunlight_color + + 2.5799999237060547 + 2.4411697387695313 + 2.4411697387695313 + 0.85999995470046997 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Jessica%20Light%2001.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Jessica%20Light%2001.xml new file mode 100644 index 0000000000..768f4f7a8c --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Jessica%20Light%2001.xml @@ -0,0 +1,141 @@ + + + ambient + + 1.0499999523162842 + 1.0499999523162842 + 1.0499999523162842 + 0.34999999403953552 + + blue_density + + 2 + 2 + 2 + 1 + + blue_horizon + + 0.6171875 + 0.6171875 + 0.6171875 + 0.30859375 + + cloud_color + + 0.40999999642372131 + 0.40999999642372131 + 0.40999999642372131 + 0.40999999642372131 + + cloud_pos_density1 + + 1.6884100437164307 + 0.52609699964523315 + 1 + 1 + + cloud_pos_density2 + + 1.6884100437164307 + 0.52609699964523315 + 0.125 + 1 + + cloud_scale + + 0.41999998688697815 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.199999809265137 + 10.01099967956543 + + cloud_shadow + + 0.26999998092651367 + 0 + 0 + 1 + + density_multiplier + + 0.00017999998817685992 + 0 + 0 + 1 + + distance_multiplier + + 70.900001525878906 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1 + 0 + 0 + 1 + + glow + + 5.1999998092651367 + 0.0010000000474974513 + -0.47999998927116394 + 1 + + haze_density + + 0.69999998807907104 + 0 + 0 + 1 + + haze_horizon + + 0.18999999761581421 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0 + 1 + -4.3711388286737929e-008 + 0 + + max_y + + 1605 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0 + sun_angle + 1.5707963705062866 + sunlight_color + + 0.7342105507850647 + 0.78157901763916016 + 0.90000003576278687 + 0.30000001192092896 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Jessica%20Light%2002.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Jessica%20Light%2002.xml new file mode 100644 index 0000000000..c75320eeaa --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Jessica%20Light%2002.xml @@ -0,0 +1,141 @@ + + + ambient + + 1.0499999523162842 + 1.0499999523162842 + 1.0499999523162842 + 0.34999999403953552 + + blue_density + + 2 + 2 + 2 + 1 + + blue_horizon + + 0.6171875 + 0.6171875 + 0.6171875 + 0.30859375 + + cloud_color + + 0.40999999642372131 + 0.40999999642372131 + 0.40999999642372131 + 0.40999999642372131 + + cloud_pos_density1 + + 1.6884100437164307 + 0.52609699964523315 + 1 + 1 + + cloud_pos_density2 + + 1.6884100437164307 + 0.52609699964523315 + 0.125 + 1 + + cloud_scale + + 0.41999998688697815 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.199999809265137 + 10.01099967956543 + + cloud_shadow + + 0.26999998092651367 + 0 + 0 + 1 + + density_multiplier + + 0.00017999998817685992 + 0 + 0 + 1 + + distance_multiplier + + 70.599998474121094 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1 + 0 + 0 + 1 + + glow + + 5.1999998092651367 + 0.0010000000474974513 + -0.47999998927116394 + 1 + + haze_density + + 0.69999998807907104 + 0 + 0 + 1 + + haze_horizon + + 0.18999999761581421 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0 + 1 + -4.3711388286737929e-008 + 0 + + max_y + + 2923 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0 + sun_angle + 1.5707963705062866 + sunlight_color + + 0.7342105507850647 + 0.78157901763916016 + 0.90000003576278687 + 0.30000001192092896 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Jessica%20Light%2003.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Jessica%20Light%2003.xml new file mode 100644 index 0000000000..6384398370 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Jessica%20Light%2003.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.62999999523162842 + 0.62999999523162842 + 0.62999999523162842 + 0.20999999344348907 + + blue_density + + 1.5 + 1.5 + 1.5 + 0.75 + + blue_horizon + + 0.6171875 + 0.6171875 + 0.6171875 + 0.30859375 + + cloud_color + + 0.40999999642372131 + 0.40999999642372131 + 0.40999999642372131 + 0.40999999642372131 + + cloud_pos_density1 + + 1.6884100437164307 + 0.52609699964523315 + 1 + 1 + + cloud_pos_density2 + + 1.6884100437164307 + 0.52609699964523315 + 0.125 + 1 + + cloud_scale + + 0.41999998688697815 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.199999809265137 + 10.01099967956543 + + cloud_shadow + + 0.26999998092651367 + 0 + 0 + 1 + + density_multiplier + + 0.00012599999899975955 + 0 + 0 + 1 + + distance_multiplier + + 70.599998474121094 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1 + 0 + 0 + 1 + + glow + + 5.1999998092651367 + 0.0010000000474974513 + -0.47999998927116394 + 1 + + haze_density + + 0.98999994993209839 + 0 + 0 + 1 + + haze_horizon + + 0 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0 + 1 + -4.3711388286737929e-008 + 0 + + max_y + + 2923 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0 + sun_angle + 1.5707963705062866 + sunlight_color + + 3 + 3 + 3 + 1 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Jessica%20Light%2004.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Jessica%20Light%2004.xml new file mode 100644 index 0000000000..fcec7085f9 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Jessica%20Light%2004.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.62999999523162842 + 0.62999999523162842 + 0.62999999523162842 + 0.20999999344348907 + + blue_density + + 1.5 + 1.5 + 1.5 + 0.75 + + blue_horizon + + 0.6171875 + 0.6171875 + 0.6171875 + 0.30859375 + + cloud_color + + 0.40999999642372131 + 0.40999999642372131 + 0.40999999642372131 + 0.40999999642372131 + + cloud_pos_density1 + + 1.6884100437164307 + 0.52609699964523315 + 1 + 1 + + cloud_pos_density2 + + 1.6884100437164307 + 0.52609699964523315 + 0.125 + 1 + + cloud_scale + + 0.41999998688697815 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.199999809265137 + 10.01099967956543 + + cloud_shadow + + 0.26999998092651367 + 0 + 0 + 1 + + density_multiplier + + 4.7199999244185165e-005 + 0 + 0 + 1 + + distance_multiplier + + 70.900001525878906 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1 + 0 + 0 + 1 + + glow + + 27.200000762939453 + 0.0010000000474974513 + -7.3500003814697266 + 1 + + haze_density + + 1.1699999570846558 + 0 + 0 + 1 + + haze_horizon + + 0.81999999284744263 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0 + 1 + -4.3711388286737929e-008 + 0 + + max_y + + 10000 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0 + sun_angle + 1.5707963705062866 + sunlight_color + + 3 + 3 + 3 + 1 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Jim%20Light%2001.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Jim%20Light%2001.xml new file mode 100644 index 0000000000..57538798bb --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Jim%20Light%2001.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0 + 0 + 0 + + blue_density + + 0 + 0 + 0 + 0 + + blue_horizon + + 0 + 0 + 0 + 0 + + cloud_color + + 0.43948723673439005 + 0.49764935046544778 + 0.50246442938400904 + 1 + + cloud_pos_density1 + + 0.57999998331069946 + 0.87000000476837158 + 0.75 + 1 + + cloud_pos_density2 + + 1.6884100437164307 + 0.52609699964523315 + 0.073541670078411725 + 1 + + cloud_scale + + 0.18000000715255737 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.088005410620646 + 10.010458310484864 + + cloud_shadow + + 0 + 0 + 0 + 1 + + density_multiplier + + 0.00028125001798306321 + 0 + 0 + 1 + + distance_multiplier + + 6.3874998847643383 + 0 + 0 + 1 + + east_angle + 2.8274335861206055 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1.0900000333786011 + 0 + 0 + 1 + + glow + + 9.4000005722045898 + 0.0010000000474974513 + -0.44999998807907104 + 1 + + haze_density + + 0.51583333298563971 + 0 + 0 + 1 + + haze_horizon + + 0.13833333183079954 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + -0.30801057815551758 + 0.080633237957954407 + -0.94795984029769897 + 0 + + max_y + + 685.18749099969864 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0.1029166579246521 + sun_angle + 0.080720871686935425 + sunlight_color + + 0 + 3 + 1.5 + 1 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Jim%20Light%2002.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Jim%20Light%2002.xml new file mode 100644 index 0000000000..11772b4f05 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Jim%20Light%2002.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0 + 0 + 0 + + blue_density + + 0 + 0 + 0 + 0 + + blue_horizon + + 0 + 0 + 0 + 0 + + cloud_color + + 0.43948723673439005 + 0.49764935046544778 + 0.50246442938400904 + 1 + + cloud_pos_density1 + + 0.57999998331069946 + 0.87000000476837158 + 0.75 + 1 + + cloud_pos_density2 + + 1.6884100437164307 + 0.52609699964523315 + 0.073541670078411725 + 1 + + cloud_scale + + 0.18000000715255737 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.088005410620646 + 10.010458310484864 + + cloud_shadow + + 0 + 0 + 0 + 1 + + density_multiplier + + 0.00028125001798306321 + 0 + 0 + 1 + + distance_multiplier + + 6.3874998847643383 + 0 + 0 + 1 + + east_angle + 2.6515045166015625 + enable_cloud_scroll + + 1 + 1 + + gamma + + 2.4347999095916748 + 0 + 0 + 1 + + glow + + 20 + 0.0010000000474974513 + -0 + 1 + + haze_density + + 0.51583333298563971 + 0 + 0 + 1 + + haze_horizon + + 0.13833333183079954 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + -0.46225041151046753 + 0.18866632878780365 + -0.86644649505615234 + 0 + + max_y + + 685.18749099969864 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0.1029166579246521 + sun_angle + 0.18980391323566437 + sunlight_color + + 0 + 3 + 1.5 + 1 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20July%20Light%2001.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20July%20Light%2001.xml new file mode 100644 index 0000000000..88205d15c6 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20July%20Light%2001.xml @@ -0,0 +1,141 @@ + + + ambient + + 1.0448951721191406 + 1.0375124216079712 + 1.0410666465759277 + 0.34829840064048767 + + blue_density + + 0.15995600819587708 + 0.44843131303787231 + 0.76233971118927002 + 0.38116985559463501 + + blue_horizon + + 0.53291136026382446 + 0.47850862145423889 + 0.69532060623168945 + 0.34766030311584473 + + cloud_color + + 0.36694067716598511 + 0.36694067716598511 + 0.36694067716598511 + 0.36694067716598511 + + cloud_pos_density1 + + 0.59999996423721313 + 0.4699999988079071 + 0.99744760127569754 + 1 + + cloud_pos_density2 + + 1.6884100437164307 + 0.52609699964523315 + 0.125 + 1 + + cloud_scale + + 0.41999997638634312 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.206368064503224 + 10.010999679565662 + + cloud_shadow + + 0.48999997973442078 + 0 + 0 + 1 + + density_multiplier + + 0.00018935874525381486 + 0 + 0 + 1 + + distance_multiplier + + 0.84041139239945806 + 0 + 0 + 1 + + east_angle + 0.32672566175460815 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1 + 0 + 0 + 1 + + glow + + 5.0000211801171162 + 0.0010000000474974277 + -0.48000001234523038 + 1 + + haze_density + + 0.69659684739417083 + 0 + 0 + 1 + + haze_horizon + + 0.1893618953990921 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + -0.27510377764701843 + 0.51503080129623413 + 0.81182581186294556 + 0 + + max_y + + 1582.8367459774017 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0 + sun_angle + 0.54104357957839966 + sunlight_color + + 0.76900362968444824 + 0.8153645396232605 + 0.93126672506332397 + 0.31042224168777466 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20July%20Light%2002.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20July%20Light%2002.xml new file mode 100644 index 0000000000..d385af5666 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20July%20Light%2002.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.45899999141693115 + 0.3078000545501709 + 0.081000030040740967 + 0.15299999713897705 + + blue_density + + 0.97999995946884155 + 0.97999995946884155 + 0.97999995946884155 + 0.48999997973442078 + + blue_horizon + + 0.31999999284744263 + 0.31999999284744263 + 0.31999999284744263 + 0.15999999642372131 + + cloud_color + + 0.5 + 0.5 + 0.5 + 0.5 + + cloud_pos_density1 + + 0.5 + 0.5 + 1 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.125 + 1 + + cloud_scale + + 0.12459999322891235 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.49940013885498 + 10.01099967956543 + + cloud_shadow + + 0 + 0 + 0 + 1 + + density_multiplier + + 0.00040939997415989637 + 0 + 0 + 1 + + distance_multiplier + + 3.9000000953674316 + 0 + 0 + 1 + + east_angle + 2.2870795726776123 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1.3042999505996704 + 0 + 0 + 1 + + glow + + 0.19999980926513672 + 0.0010000000474974513 + -0.04999995231628418 + 1 + + haze_density + + 2.869999885559082 + 0 + 0 + 1 + + haze_horizon + + 0.5 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0.71421909332275391 + 0.32145592570304871 + 0.62173730134963989 + 0 + + max_y + + 385 + 0 + 0 + 1 + + preset_num + 21 + star_brightness + 0 + sun_angle + 2.8143260478973389 + sunlight_color + + 2.0099999904632568 + 2.0099999904632568 + 2.0099999904632568 + 0.67000001668930054 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20July%20Light%2003.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20July%20Light%2003.xml new file mode 100644 index 0000000000..40ffdc4cdc --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20July%20Light%2003.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.56099998950958252 + 0.37620007991790771 + 0.099000021815299988 + 0.18699999153614044 + + blue_density + + 0.97999995946884155 + 0.97999995946884155 + 0.97999995946884155 + 0.48999997973442078 + + blue_horizon + + 0.31999999284744263 + 0.31999999284744263 + 0.31999999284744263 + 0.15999999642372131 + + cloud_color + + 0.5 + 0.5 + 0.5 + 0.5 + + cloud_pos_density1 + + 0.5 + 0.5 + 1 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.125 + 1 + + cloud_scale + + 0.12459999322891235 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.49940013885498 + 10.01099967956543 + + cloud_shadow + + 0 + 0 + 0 + 1 + + density_multiplier + + 0.0004881999921053648 + 0 + 0 + 1 + + distance_multiplier + + 3.9000000953674316 + 0 + 0 + 1 + + east_angle + 2.2556638717651367 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1.3042999505996704 + 0 + 0 + 1 + + glow + + 0.19999980926513672 + 0.0010000000474974513 + -0.04999995231628418 + 1 + + haze_density + + 3.4800000190734863 + 0 + 0 + 1 + + haze_horizon + + 0.37000000476837158 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0.72426009178161621 + 0.35430732369422913 + 0.59153497219085693 + 0 + + max_y + + 385 + 0 + 0 + 1 + + preset_num + 21 + star_brightness + 0 + sun_angle + 2.7794194221496582 + sunlight_color + + 3 + 3 + 3 + 1 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Landar%20Light%2001.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Landar%20Light%2001.xml new file mode 100644 index 0000000000..30cdcd0a59 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Landar%20Light%2001.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0 + 0 + 0 + + blue_density + + 1.5 + 1.5 + 1.5 + 0.75 + + blue_horizon + + 1 + 1 + 1 + 0.5 + + cloud_color + + 1 + 1 + 1 + 1 + + cloud_pos_density1 + + 0.95999997854232788 + 0.31000000238418579 + 0.34149998426437378 + 1 + + cloud_pos_density2 + + 1 + 1 + 0 + 1 + + cloud_scale + + 0.049599997699260712 + 0 + 0 + 1 + + cloud_scroll_rate + + 93.100006103515625 + -25.899993896484375 + + cloud_shadow + + 0.25999999046325684 + 0 + 0 + 1 + + density_multiplier + + 0.00018439999257680029 + 0 + 0 + 1 + + distance_multiplier + + 2.2000000476837158 + 0 + 0 + 1 + + east_angle + 3.1855752468109131 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1 + 0 + 0 + 1 + + glow + + 15.799999237060547 + 0.0010000000474974513 + -0.74999994039535522 + 1 + + haze_density + + 0.66999995708465576 + 0 + 0 + 1 + + haze_horizon + + 0.12999999523162842 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0.040397927165031433 + 0.39473667740821838 + -0.91790574789047241 + 0 + + max_y + + 2231 + 0 + 0 + 1 + + preset_num + 21 + star_brightness + 500 + sun_angle + 0.40578123927116394 + sunlight_color + + 0 + 0 + 0 + 0 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Lo%20%20Gun%20Light.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Lo%20%20Gun%20Light.xml new file mode 100644 index 0000000000..add7359675 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Lo%20%20Gun%20Light.xml @@ -0,0 +1,141 @@ + + + ambient + + 1.5 + 1.8999999761581421 + 3 + 1 + + blue_density + + 1.4579999446868896 + 0 + 0.82620006799697876 + 0.72899997234344482 + + blue_horizon + + 1.4579999446868896 + 0 + 0.7047005295753479 + 0.72899997234344482 + + cloud_color + + 0.37840613487830987 + 0.37840613487830987 + 0.37840613487830987 + 0.37840613487830987 + + cloud_pos_density1 + + 1.6884100437164307 + 0.52609699964523315 + 0.99999998870089368 + 1 + + cloud_pos_density2 + + 1.6884100437164307 + 0.52609699964523315 + 0.125 + 1 + + cloud_scale + + 0.41999997841284203 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.199999837455794 + 10.01099967956543 + + cloud_shadow + + 0.48999997973442078 + 0 + 0 + 1 + + density_multiplier + + 3.6899997212458402e-005 + 0 + 0 + 1 + + distance_multiplier + + 75.200004577636719 + 0 + 0 + 1 + + east_angle + 6.2266373634338379 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1.0434999465942383 + 0 + 0 + 1 + + glow + + 4.9999999435054558 + 0.0010000000474974513 + -0.4799999902127477 + 1 + + haze_density + + 0.34999999403953552 + 0 + 0 + 1 + + haze_horizon + + 1 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0.045796267688274384 + 0.58601820468902588 + 0.80900269746780396 + 0 + + max_y + + 4000 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0 + sun_angle + 0.62613606452941895 + sunlight_color + + 1.4099999666213989 + 1.4099999666213989 + 1.4099999666213989 + 0.4699999988079071 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Lo%20Light%2001.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Lo%20Light%2001.xml new file mode 100644 index 0000000000..2a395d8bb0 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Lo%20Light%2001.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0 + 0 + 0 + + blue_density + + 2 + 2 + 2 + 1 + + blue_horizon + + 2 + 2 + 2 + 1 + + cloud_color + + 0.40999999642372131 + 0.40999999642372131 + 0.40999999642372131 + 0.40999999642372131 + + cloud_pos_density1 + + 1.6884100437164307 + 0.52609699964523315 + 1 + 1 + + cloud_pos_density2 + + 1.6884100437164307 + 0.52609699964523315 + 0.125 + 1 + + cloud_scale + + 0.41999998688697815 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.199999809265137 + 10.01099967956543 + + cloud_shadow + + 0 + 0 + 0 + 1 + + density_multiplier + + 0.0006399999838322401 + 0 + 0 + 1 + + distance_multiplier + + 100 + 0 + 0 + 1 + + east_angle + 3.1415927410125732 + enable_cloud_scroll + + 1 + 1 + + gamma + + 2.0199999809265137 + 0 + 0 + 1 + + glow + + 0.19999980926513672 + 0.0010000000474974513 + -2.5 + 1 + + haze_density + + 4 + 0 + 0 + 1 + + haze_horizon + + 1 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 4.8569567923095747e-008 + 0.83146905899047852 + -0.55557107925415039 + 0 + + max_y + + 4000 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0 + sun_angle + 0.98174667358398438 + sunlight_color + + 1.5 + 1.5 + 3 + 1 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Lo%20Light%2002.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Lo%20Light%2002.xml new file mode 100644 index 0000000000..dbb8405061 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Lo%20Light%2002.xml @@ -0,0 +1,141 @@ + + + ambient + + 3 + 3 + 3 + 1 + + blue_density + + 0 + 0 + 0 + 0 + + blue_horizon + + 0 + 0 + 0 + 0 + + cloud_color + + 0.5 + 0.5 + 1 + 1 + + cloud_pos_density1 + + 0.29999998211860657 + 0.93999999761581421 + 0.75 + 1 + + cloud_pos_density2 + + 0.44999998807907104 + 0.35999998450279236 + 0.019999999552965164 + 1 + + cloud_scale + + 0.45999997854232788 + 0 + 0 + 1 + + cloud_scroll_rate + + 20 + 20 + + cloud_shadow + + 0 + 0 + 0 + 1 + + density_multiplier + + 0.00089999998454004526 + 0 + 0 + 1 + + distance_multiplier + + 0 + 0 + 0 + 1 + + east_angle + 6.2831854820251465 + enable_cloud_scroll + + 0 + 0 + + gamma + + 1.0099999904632568 + 0 + 0 + 1 + + glow + + 0.19999980926513672 + 0.0010000000474974513 + -2.5 + 1 + + haze_density + + 4 + 0 + 0 + 1 + + haze_horizon + + 1 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 6.3370464431500295e-008 + 0.93200832605361938 + -0.36243680119514465 + 0 + + max_y + + 4000 + 0 + 0 + 1 + + preset_num + 24 + star_brightness + 2 + sun_angle + 1.941677451133728 + sunlight_color + + 3 + 3 + 3 + 1 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Lo%20Light%2003.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Lo%20Light%2003.xml new file mode 100644 index 0000000000..3b32f8dcf2 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Lo%20Light%2003.xml @@ -0,0 +1,141 @@ + + + ambient + + 1.41796875 + 1.41796875 + 1.41796875 + 0.47265625 + + blue_density + + 0.12089811412885521 + 0.33770671695460663 + 0.67541757891583387 + 0.76708334654569654 + + blue_horizon + + 0.13497034943045882 + 0.26690842067701936 + 0.4016666400432598 + 0.74541666984558219 + + cloud_color + + 0.43948723673439005 + 0.49764935046544778 + 0.50246442938400904 + 1 + + cloud_pos_density1 + + 0.57999998331069946 + 0.87000000476837158 + 0.75 + 1 + + cloud_pos_density2 + + 1.6884100437164307 + 0.52609699964523315 + 0.073541670078411725 + 1 + + cloud_scale + + 0.15000000596046448 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.088005410620646 + 10.010458310484864 + + cloud_shadow + + 0.12999999523162842 + 0 + 0 + 1 + + density_multiplier + + 0.00028125001798306321 + 0 + 0 + 1 + + distance_multiplier + + 6.3874998847643383 + 0 + 0 + 1 + + east_angle + 3.5185837745666504 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1.0900000333786011 + 0 + 0 + 1 + + glow + + 9.4000005722045898 + 0.0010000000474974513 + -0.44999998807907104 + 1 + + haze_density + + 0.51583333298563971 + 0 + 0 + 1 + + haze_horizon + + 0.13833333183079954 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0.28709480166435242 + 0.6259227991104126 + -0.72511875629425049 + 0 + + max_y + + 685.18749099969864 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0.1029166579246521 + sun_angle + 0.67631423473358154 + sunlight_color + + 2.44921875 + 2.44921875 + 2.44921875 + 0.81640625 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Lo%20Light%2004.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Lo%20Light%2004.xml new file mode 100644 index 0000000000..21cf058bf2 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Lo%20Light%2004.xml @@ -0,0 +1,141 @@ + + + ambient + + 1.41796875 + 1.41796875 + 1.41796875 + 0.47265625 + + blue_density + + 0.12089811412885521 + 0.33770671695460663 + 0.67541757891583387 + 0.76708334654569654 + + blue_horizon + + 0.13497034943045882 + 0.26690842067701936 + 0.4016666400432598 + 0.74541666984558219 + + cloud_color + + 0.43948723673439005 + 0.49764935046544778 + 0.50246442938400904 + 1 + + cloud_pos_density1 + + 0.57999998331069946 + 0.87000000476837158 + 0.75 + 1 + + cloud_pos_density2 + + 1.6884100437164307 + 0.52609699964523315 + 0.073541670078411725 + 1 + + cloud_scale + + 0.15000000596046448 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.088005410620646 + 10.010458310484864 + + cloud_shadow + + 0.12999999523162842 + 0 + 0 + 1 + + density_multiplier + + 0.00028125001798306321 + 0 + 0 + 1 + + distance_multiplier + + 6.3874998847643383 + 0 + 0 + 1 + + east_angle + 3.5185837745666504 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1.0900000333786011 + 0 + 0 + 1 + + glow + + 9.4000005722045898 + 0.0010000000474974513 + -0.44999998807907104 + 1 + + haze_density + + 0.51583333298563971 + 0 + 0 + 1 + + haze_horizon + + 0.13833333183079954 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0.28709480166435242 + 0.6259227991104126 + -0.72511875629425049 + 0 + + max_y + + 685.18749099969864 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0.1029166579246521 + sun_angle + 0.67631423473358154 + sunlight_color + + 1.078125 + 1.078125 + 1.078125 + 0.359375 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Lo%20Light%2005.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Lo%20Light%2005.xml new file mode 100644 index 0000000000..bb863523a0 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Lo%20Light%2005.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0 + 0 + 0 + + blue_density + + 2 + 2 + 2 + 1 + + blue_horizon + + 2 + 2 + 2 + 1 + + cloud_color + + 0.40999999642372131 + 0.40999999642372131 + 0.40999999642372131 + 0.40999999642372131 + + cloud_pos_density1 + + 1.6884100437164307 + 0.52609699964523315 + 1 + 1 + + cloud_pos_density2 + + 1.6884100437164307 + 0.52609699964523315 + 0.125 + 1 + + cloud_scale + + 0.41999998688697815 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.199999809265137 + 10.01099967956543 + + cloud_shadow + + 0 + 0 + 0 + 1 + + density_multiplier + + 0.00089999998454004526 + 0 + 0 + 1 + + distance_multiplier + + 22.5 + 0 + 0 + 1 + + east_angle + 3.1415927410125732 + enable_cloud_scroll + + 1 + 1 + + gamma + + 2.0199999809265137 + 0 + 0 + 1 + + glow + + 0.19999980926513672 + 0.0010000000474974513 + -2.5 + 1 + + haze_density + + 1.8199999332427979 + 0 + 0 + 1 + + haze_horizon + + 1 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 4.8569567923095747e-008 + 0.83146905899047852 + -0.55557107925415039 + 0 + + max_y + + 3533 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0 + sun_angle + 0.98174667358398438 + sunlight_color + + 1.5 + 1.5 + 3 + 1 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Lo%20Moves%20Light.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Lo%20Moves%20Light.xml new file mode 100644 index 0000000000..38ca17aa60 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Lo%20Moves%20Light.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0 + 0 + 0 + + blue_density + + 0.39999997615814209 + 0.39999997615814209 + 0.39999997615814209 + 0.19999998807907104 + + blue_horizon + + 1 + 1 + 1 + 0.5 + + cloud_color + + 1 + 0.5 + 0 + 1 + + cloud_pos_density1 + + 1 + 0.65999996662139893 + 0.31099998950958252 + 1 + + cloud_pos_density2 + + 1 + 1 + 0 + 1 + + cloud_scale + + 0.042800001800060272 + 0 + 0 + 1 + + cloud_scroll_rate + + 15.309999465942383 + 14.079999923706055 + + cloud_shadow + + 0.40999999642372131 + 0 + 0 + 1 + + density_multiplier + + 0 + 0 + 0 + 1 + + distance_multiplier + + 100 + 0 + 0 + 1 + + east_angle + 3.7824780941009521 + enable_cloud_scroll + + 1 + 1 + + gamma + + 0.26089999079704285 + 0 + 0 + 1 + + glow + + 0.59999942779541016 + 0.0010000000474974513 + -1.75 + 1 + + haze_density + + 4 + 0 + 0 + 1 + + haze_horizon + + 1 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0.065092690289020538 + 0.99405622482299805 + -0.087264858186244965 + 0 + + max_y + + 4000 + 0 + 0 + 1 + + preset_num + 18 + star_brightness + 2 + sun_angle + 1.4617122411727905 + sunlight_color + + 0 + 0 + 0 + 0 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Lo%20Music%20Light%2001.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Lo%20Music%20Light%2001.xml new file mode 100644 index 0000000000..db2ba2d168 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Lo%20Music%20Light%2001.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.15000000596046448 + 0.15000000596046448 + 0.15000000596046448 + 0.05000000074505806 + + blue_density + + 1 + 1 + 1 + 0.5 + + blue_horizon + + 1.7999999523162842 + 1.7999999523162842 + 1.7999999523162842 + 0.89999997615814209 + + cloud_color + + 0.5 + 0.5 + 1 + 1 + + cloud_pos_density1 + + 0.15999999642372131 + 0.50999999046325684 + 1 + 1 + + cloud_pos_density2 + + 1 + 0.50999999046325684 + 1 + 1 + + cloud_scale + + 0.059000000357627869 + 0 + 0 + 1 + + cloud_scroll_rate + + 14.409999847412109 + 4.7999997138977051 + + cloud_shadow + + 0.18999999761581421 + 0 + 0 + 1 + + density_multiplier + + 0 + 0 + 0 + 1 + + distance_multiplier + + 51.200000762939453 + 0 + 0 + 1 + + east_angle + 1.9477875232696533 + enable_cloud_scroll + + 1 + 1 + + gamma + + 0.69569998979568481 + 0 + 0 + 1 + + glow + + 5 + 0.0010000000474974513 + -2.5 + 1 + + haze_density + + 0.69999998807907104 + 0 + 0 + 1 + + haze_horizon + + 0.26999998092651367 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + -0.62063354253768921 + 0.74460232257843018 + -0.24572627246379852 + 0 + + max_y + + 4000 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 2 + sun_angle + 0.83993887901306152 + sunlight_color + + 1.5 + 1.5 + 3 + 1 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Mavi%20Light%2001.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Mavi%20Light%2001.xml new file mode 100644 index 0000000000..ecae129257 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Mavi%20Light%2001.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.1875 + 0.1875 + 0.1875 + 0.0625 + + blue_density + + 1.7999999523162842 + 1.7999999523162842 + 1.7999999523162842 + 0.89999997615814209 + + blue_horizon + + 1.7999999523162842 + 1.7999999523162842 + 1.7999999523162842 + 0.89999997615814209 + + cloud_color + + 0.40999999642372131 + 0.40999999642372131 + 0.40999999642372131 + 0.40999999642372131 + + cloud_pos_density1 + + 1.6884100437164307 + 0.52609699964523315 + 1 + 1 + + cloud_pos_density2 + + 1.6884100437164307 + 0.52609699964523315 + 0.125 + 1 + + cloud_scale + + 0.41999998688697815 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.70001220703125 + 10.01099967956543 + + cloud_shadow + + 0.44999998807907104 + 0 + 0 + 1 + + density_multiplier + + 0.00014170000213198364 + 0 + 0 + 1 + + distance_multiplier + + 7.9000000953674316 + 0 + 0 + 1 + + east_angle + 1.9477875232696533 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1.3999999761581421 + 0 + 0 + 1 + + glow + + 5 + 0.0010000000474974513 + -0.47999998927116394 + 1 + + haze_density + + 0.66999995708465576 + 0 + 0 + 1 + + haze_horizon + + 0 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + -0.51655691862106323 + 0.83146905899047852 + -0.20451940596103668 + 0 + + max_y + + 21 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0 + sun_angle + 0.98174667358398438 + sunlight_color + + 2.6999998092651367 + 2.6999998092651367 + 2.6999998092651367 + 0.89999997615814209 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Mavi%20Light%2002.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Mavi%20Light%2002.xml new file mode 100644 index 0000000000..d0ba4bb023 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Mavi%20Light%2002.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.1875 + 0.1875 + 0.1875 + 0.0625 + + blue_density + + 1.7999999523162842 + 1.7999999523162842 + 1.7999999523162842 + 0.89999997615814209 + + blue_horizon + + 1.7999999523162842 + 1.7999999523162842 + 1.7999999523162842 + 0.89999997615814209 + + cloud_color + + 0.5 + 0.5 + 0.5 + 0.5 + + cloud_pos_density1 + + 1.6884100437164307 + 0.52609699964523315 + 0.99409997463226318 + 1 + + cloud_pos_density2 + + 1.6884100437164307 + 0.52609699964523315 + 0.125 + 1 + + cloud_scale + + 0.49579998850822449 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.70001220703125 + 10.01099967956543 + + cloud_shadow + + 0.29999998211860657 + 0 + 0 + 1 + + density_multiplier + + 0.00015750000602565706 + 0 + 0 + 1 + + distance_multiplier + + 4.5999999046325684 + 0 + 0 + 1 + + east_angle + 1.9477875232696533 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1.3999999761581421 + 0 + 0 + 1 + + glow + + 5 + 0.0010000000474974513 + -0.47999998927116394 + 1 + + haze_density + + 1.7400000095367432 + 0 + 0 + 1 + + haze_horizon + + 0.070000000298023224 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + -0.51655691862106323 + 0.83146905899047852 + -0.20451940596103668 + 0 + + max_y + + 11 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0 + sun_angle + 0.98174667358398438 + sunlight_color + + 2.6999998092651367 + 2.6999998092651367 + 2.6999998092651367 + 0.89999997615814209 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Mavi%20Light%2003.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Mavi%20Light%2003.xml new file mode 100644 index 0000000000..ecae129257 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Mavi%20Light%2003.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.1875 + 0.1875 + 0.1875 + 0.0625 + + blue_density + + 1.7999999523162842 + 1.7999999523162842 + 1.7999999523162842 + 0.89999997615814209 + + blue_horizon + + 1.7999999523162842 + 1.7999999523162842 + 1.7999999523162842 + 0.89999997615814209 + + cloud_color + + 0.40999999642372131 + 0.40999999642372131 + 0.40999999642372131 + 0.40999999642372131 + + cloud_pos_density1 + + 1.6884100437164307 + 0.52609699964523315 + 1 + 1 + + cloud_pos_density2 + + 1.6884100437164307 + 0.52609699964523315 + 0.125 + 1 + + cloud_scale + + 0.41999998688697815 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.70001220703125 + 10.01099967956543 + + cloud_shadow + + 0.44999998807907104 + 0 + 0 + 1 + + density_multiplier + + 0.00014170000213198364 + 0 + 0 + 1 + + distance_multiplier + + 7.9000000953674316 + 0 + 0 + 1 + + east_angle + 1.9477875232696533 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1.3999999761581421 + 0 + 0 + 1 + + glow + + 5 + 0.0010000000474974513 + -0.47999998927116394 + 1 + + haze_density + + 0.66999995708465576 + 0 + 0 + 1 + + haze_horizon + + 0 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + -0.51655691862106323 + 0.83146905899047852 + -0.20451940596103668 + 0 + + max_y + + 21 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0 + sun_angle + 0.98174667358398438 + sunlight_color + + 2.6999998092651367 + 2.6999998092651367 + 2.6999998092651367 + 0.89999997615814209 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Me%20Love%20Light.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Me%20Love%20Light.xml new file mode 100644 index 0000000000..838e394cbe --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Me%20Love%20Light.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0 + 0 + 0 + + blue_density + + 0.39999997615814209 + 0.39999997615814209 + 0.39999997615814209 + 0.19999998807907104 + + blue_horizon + + 1 + 1 + 1 + 0.5 + + cloud_color + + 1 + 0.5 + 0 + 1 + + cloud_pos_density1 + + 0.2800000011920929 + 0.31999999284744263 + 0.14019998908042908 + 1 + + cloud_pos_density2 + + 0.019999999552965164 + 0.45999997854232788 + 0 + 1 + + cloud_scale + + 0.018199998885393143 + 0 + 0 + 1 + + cloud_scroll_rate + + 15.309999465942383 + 14.079999923706055 + + cloud_shadow + + 1 + 0 + 0 + 1 + + density_multiplier + + 0 + 0 + 0 + 1 + + distance_multiplier + + 100 + 0 + 0 + 1 + + east_angle + 3.7824780941009521 + enable_cloud_scroll + + 1 + 1 + + gamma + + 2.69569993019104 + 0 + 0 + 1 + + glow + + 0.59999942779541016 + 0.0010000000474974513 + -1.75 + 1 + + haze_density + + 4 + 0 + 0 + 1 + + haze_horizon + + 1 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0.032595228403806686 + 0.99851292371749878 + -0.043697964400053024 + 0 + + max_y + + 4000 + 0 + 0 + 1 + + preset_num + 18 + star_brightness + 2 + sun_angle + 1.5162535905838013 + sunlight_color + + 0 + 0 + 0 + 0 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Me%20Mine%20Light.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Me%20Mine%20Light.xml new file mode 100644 index 0000000000..155a8b9e47 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Me%20Mine%20Light.xml @@ -0,0 +1,141 @@ + + + ambient + + 1.0799999237060547 + 0.98999994993209839 + 0.77999997138977051 + 1.0799999237060547 + + blue_density + + 0.64736837148666382 + 0.48414888978004456 + 0.81999999284744263 + 0.40999999642372131 + + blue_horizon + + 0.5 + 0.49548381567001343 + 0.45999997854232788 + 0.51999998092651367 + + cloud_color + + 0.4100000062111997 + 0.4100000062111997 + 0.4100000062111997 + 0.4100000062111997 + + cloud_pos_density1 + + 0.14000000059604645 + 0.62000000476837158 + 1 + 1 + + cloud_pos_density2 + + 0.35999998450279236 + 0.56999999284744263 + 0.12999999523162842 + 1 + + cloud_scale + + 0.35999998450279236 + 0 + 0 + 1.0000000149011612 + + cloud_scroll_rate + + 10.199999791580112 + 10.010999679880427 + + cloud_shadow + + 0.29999998211860657 + 0 + 0 + 1.0000000149011612 + + density_multiplier + + 7.9999997979030013e-005 + 0 + 0 + 1.0000000149011612 + + distance_multiplier + + 5.4000000953674316 + 0 + 0 + 1.0000000149011612 + + east_angle + 1.0932743549346924 + enable_cloud_scroll + + 1 + 1 + + gamma + + 2.1699998378753662 + 0 + 0 + 1.0000000149011612 + + glow + + 0.19999980926513672 + 0.0010000000474974513 + -0.55000001192092896 + 1 + + haze_density + + 0.31999999284744263 + 0 + 0 + 1 + + haze_horizon + + 0.17999999225139618 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0.39627334475517273 + 0.89494067430496216 + -0.20505768060684204 + 0 + + max_y + + 805 + 0 + 0 + 1.0000000149011612 + + preset_num + 28 + star_brightness + 0.25999999046325684 + sun_angle + 2.0332944393157959 + sunlight_color + + 3 + 0 + 0 + 1 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Meni%20Light%2001.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Meni%20Light%2001.xml new file mode 100644 index 0000000000..f308d292e8 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Meni%20Light%2001.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.28464806749374816 + 0.45923502031814678 + 0.7409173846244812 + 0.7409173846244812 + + blue_density + + 0.25613615825332658 + 0.41819368084009056 + 0.6726322016895665 + 1 + + blue_horizon + + 2 + 1 + 0 + 1 + + cloud_color + + 0.52756190160579308 + 0.52756190160579308 + 0.52756190160579308 + 1 + + cloud_pos_density1 + + 0.72999995946884155 + 0.34000000357627869 + 0.32999998331069946 + 1 + + cloud_pos_density2 + + 0.28999999165534973 + 0.84999996423721313 + 0.019999999552965164 + 1 + + cloud_scale + + 0.32999998058761548 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.499399946934318 + 10.010999746491507 + + cloud_shadow + + 0.37000000476837158 + 0 + 0 + 1 + + density_multiplier + + 2.9999999242136255e-005 + 0 + 0 + 1 + + distance_multiplier + + 100 + 0 + 0 + 1 + + east_angle + 2.9530971050262451 + enable_cloud_scroll + + 0 + 0 + + gamma + + 3.0199999809265137 + 0 + 0 + 1 + + glow + + 0.79999923706054688 + 0.0010000000474974513 + -1.1999999284744263 + 1 + + haze_density + + 2.1499998569488525 + 0 + 0 + 1 + + haze_horizon + + 0.23999999463558197 + 0.19915598630905151 + 0.19915598630905151 + 1 + + lightnorm + + 0.12659277021884918 + 0.7372782826423645 + 0.66362255811691284 + 0 + + max_y + + 711.42973550362512 + 0 + 0 + 1 + + preset_num + 18 + star_brightness + 0 + sun_angle + 2.3125598430633545 + sunlight_color + + 0.62994743245872087 + 0.69737775977682759 + 0.86806544391379248 + 0.28935515608276319 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Miaa%20light%2001.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Miaa%20light%2001.xml new file mode 100644 index 0000000000..eedc74c889 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Miaa%20light%2001.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0 + 0 + 0 + + blue_density + + 1 + 1 + 1 + 0.5 + + blue_horizon + + 1 + 1 + 1 + 0.5 + + cloud_color + + 0.5 + 0.5 + 0.5 + 0.5 + + cloud_pos_density1 + + 0.5 + 0.5 + 0.76829999685287476 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.125 + 1 + + cloud_scale + + 0.059000000357627869 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.49940033104544 + 10.011000058908452 + + cloud_shadow + + 0.26999998092651367 + 0 + 0 + 1 + + density_multiplier + + 0.00025079998886212707 + 0 + 0 + 1 + + distance_multiplier + + 77.400001525878906 + 0 + 0 + 1 + + east_angle + 0.19477875530719757 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1.5699999332427979 + 0 + 0 + 1 + + glow + + 16.80000114440918 + 0.0010000000474974513 + -0.59999996423721313 + 1 + + haze_density + + 1.1190000772476196 + 0 + 0 + 1 + + haze_horizon + + 0.17000000178813934 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + -0.14745019376277924 + 0.64778679609298706 + 0.74741601943969727 + 0 + + max_y + + 2353 + 0 + 0 + 1 + + preset_num + 21 + star_brightness + 1.7856996059417725 + sun_angle + 0.70467567443847656 + sunlight_color + + 3 + 3 + 3 + 1 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Moon%20Light%2001.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Moon%20Light%2001.xml new file mode 100644 index 0000000000..e7fa44c7ee --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Moon%20Light%2001.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.20632287859916687 + 0.24516719579696655 + 0.33367714285850525 + 0.11122571676969528 + + blue_density + + 0.44999827251961821 + 0.44999970758411817 + 0.45000196070835302 + 1 + + blue_horizon + + 0.23999924952063895 + 0.23999984552653461 + 0.24000005119478959 + 1 + + cloud_color + + 0.22615400012094211 + 0.22615400012094211 + 0.22615400012094211 + 1 + + cloud_pos_density1 + + 1.6884100437164307 + 0.52609699964523315 + 0.87999999801324269 + 1 + + cloud_pos_density2 + + 1.6884100437164307 + 0.52609699964523315 + 0.125 + 1 + + cloud_scale + + 0.0099999997764825821 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.499400180710069 + 10.01099976217745 + + cloud_shadow + + 0 + 0 + 0 + 1 + + density_multiplier + + 8.9999994088429958e-005 + 0 + 0 + 1 + + distance_multiplier + + 41.100002288818359 + 0 + 0 + 1 + + east_angle + 1.5707963705062866 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1 + 0 + 0 + 1 + + glow + + 5.0000000000004476 + 0.0010000000424271499 + -0.47999998973471036 + 1 + + haze_density + + 0.20999999344348907 + 0 + 0 + 1 + + haze_horizon + + 0.20999999344348907 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + -0.83147060871124268 + 0.55556869506835938 + -3.6344733445048405e-008 + 1 + + max_y + + 4000 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 1.9999886751174927 + sun_angle + 3.7306394577026367 + sunlight_color + + 0.45637205243110657 + 0.46549969911575317 + 0.86362791061401367 + 0.28787598013877869 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Moon%20Light%2002.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Moon%20Light%2002.xml new file mode 100644 index 0000000000..99d59e5108 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Moon%20Light%2002.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.20405027270317078 + 0.24246673285961151 + 0.32999998331069946 + 0.10999999940395355 + + blue_density + + 0 + 0 + 0 + 0 + + blue_horizon + + 0 + 0 + 0 + 0 + + cloud_color + + 0.5 + 0.5 + 1 + 1 + + cloud_pos_density1 + + 0.12999999523162842 + 0.31999999284744263 + 1 + 1 + + cloud_pos_density2 + + 1.6884100437164307 + 0.74000000953674316 + 0.17999999225139618 + 1 + + cloud_scale + + 0.99999994039535522 + 0 + 0 + 1 + + cloud_scroll_rate + + 16.869998931884766 + 16.760000228881836 + + cloud_shadow + + 0.2199999988079071 + 0 + 0 + 1 + + density_multiplier + + 0.00032459996873512864 + 0 + 0 + 1 + + distance_multiplier + + 85.300003051757813 + 0 + 0 + 1 + + east_angle + 1.0807079076766968 + enable_cloud_scroll + + 0 + 0 + + gamma + + 1 + 0 + 0 + 1 + + glow + + 5.1999998092651367 + 0.0010000000474974513 + -0.39999997615814209 + 1 + + haze_density + + 4 + 0 + 0 + 1 + + haze_horizon + + 0.019999999552965164 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0.79044967889785767 + 0.44424447417259216 + -0.42170625925064087 + 1 + + max_y + + 303 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 2 + sun_angle + 5.8228545188903809 + sunlight_color + + 1.390916109085083 + 1.4052181243896484 + 2.0290837287902832 + 0.67636126279830933 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Moon%20Light%2003.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Moon%20Light%2003.xml new file mode 100644 index 0000000000..f6b4ddab89 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Moon%20Light%2003.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.38972097635269165 + 0.46309363842010498 + 0.63027900457382202 + 0.21009300649166107 + + blue_density + + 0.44999827251961821 + 0.44999970758411817 + 0.45000196070835302 + 1 + + blue_horizon + + 0.23999924952063895 + 0.23999984552653461 + 0.24000005119478959 + 1 + + cloud_color + + 0.22615400012094211 + 0.22615400012094211 + 0.22615400012094211 + 1 + + cloud_pos_density1 + + 1.6884100437164307 + 0.52609699964523315 + 0.87999999801324269 + 1 + + cloud_pos_density2 + + 1.6884100437164307 + 0.52609699964523315 + 0.125 + 1 + + cloud_scale + + 3 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.499400180710069 + 10.01099976217745 + + cloud_shadow + + 0.22999998927116394 + 0 + 0 + 1 + + density_multiplier + + 8.9999994088429958e-005 + 0 + 0 + 1 + + distance_multiplier + + 41.100002288818359 + 0 + 0 + 1 + + east_angle + 2.8588495254516602 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1 + 0 + 0 + 1 + + glow + + 5.0000000000004476 + 0.0010000000424271499 + -0.47999998973471036 + 1 + + haze_density + + 0.20999999344348907 + 0 + 0 + 1 + + haze_horizon + + 0.20999999344348907 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0.23529607057571411 + 0.53731352090835571 + 0.80989503860473633 + 0 + + max_y + + 4000 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 500 + sun_angle + 2.5743441581726074 + sunlight_color + + 0.5808371901512146 + 0.59245419502258301 + 1.0991628170013428 + 0.36638760566711426 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Moon%20Light%2004.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Moon%20Light%2004.xml new file mode 100644 index 0000000000..76c2aed13d --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Moon%20Light%2004.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.20405027270317078 + 0.24246673285961151 + 0.32999998331069946 + 0.10999999940395355 + + blue_density + + 0.23251199722290039 + 0.23716199398040771 + 0.43999999761581421 + 0.2199999988079071 + + blue_horizon + + 0.23999999463558197 + 0.23999999463558197 + 0.23999999463558197 + 1 + + cloud_color + + 0.625 + 0.625 + 0.875 + 0.875 + + cloud_pos_density1 + + 1.6884100437164307 + 0.52609699964523315 + 0.87999999523162842 + 1 + + cloud_pos_density2 + + 1.6884100437164307 + 0.52609699964523315 + 0.125 + 1 + + cloud_scale + + 0.17359998822212219 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.49940013885498 + 10.01099967956543 + + cloud_shadow + + 0.11999999731779099 + 0 + 0 + 1 + + density_multiplier + + 0.00033069998607970774 + 0 + 0 + 1 + + distance_multiplier + + 70.900001525878906 + 0 + 0 + 1 + + east_angle + 1.9666372537612915 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1 + 0 + 0 + 1 + + glow + + 5 + 0.0010000000474974513 + -0.47999998927116394 + 1 + + haze_density + + 1.5999999046325684 + 0 + 0 + 1 + + haze_horizon + + 0.019999999552965164 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0.41169273853302002 + 0.89493530988693237 + 0.17204611003398895 + 1 + + max_y + + 308 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 2 + sun_angle + 5.1748991012573242 + sunlight_color + + 0.93348866701126099 + 0.95215761661529541 + 1.7665112018585205 + 0.58883708715438843 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Moon%20Light%2005.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Moon%20Light%2005.xml new file mode 100644 index 0000000000..496ab40eba --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Moon%20Light%2005.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.20405027270317078 + 0.24246673285961151 + 0.32999998331069946 + 0.10999999940395355 + + blue_density + + 0.23251199722290039 + 0.23716199398040771 + 0.43999999761581421 + 0.2199999988079071 + + blue_horizon + + 0.23999999463558197 + 0.23999999463558197 + 0.23999999463558197 + 1 + + cloud_color + + 0.625 + 0.625 + 0.875 + 0.875 + + cloud_pos_density1 + + 1.6884100437164307 + 0.52609699964523315 + 0.87999999523162842 + 1 + + cloud_pos_density2 + + 1.6884100437164307 + 0.52609699964523315 + 0.125 + 1 + + cloud_scale + + 0.17359998822212219 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.49940013885498 + 10.01099967956543 + + cloud_shadow + + 0.11999999731779099 + 0 + 0 + 1 + + density_multiplier + + 0.00033069998607970774 + 0 + 0 + 1 + + distance_multiplier + + 70.900001525878906 + 0 + 0 + 1 + + east_angle + 2.3499114513397217 + enable_cloud_scroll + + 1 + 1 + + gamma + + 2.0899999141693115 + 0 + 0 + 1 + + glow + + 5 + 0.0010000000474974513 + -0.47999998927116394 + 1 + + haze_density + + 1.5999999046325684 + 0 + 0 + 1 + + haze_horizon + + 0.019999999552965164 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0.37705510854721069 + 0.84804928302764893 + 0.37234652042388916 + 1 + + max_y + + 308 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 2 + sun_angle + 5.2708921432495117 + sunlight_color + + 0.34876799583435059 + 0.50438410043716431 + 0.65999996662139893 + 0.2199999988079071 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Moon%20Light%2006.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Moon%20Light%2006.xml new file mode 100644 index 0000000000..7152527870 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Moon%20Light%2006.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.20632287859916687 + 0.24516719579696655 + 0.33367714285850525 + 0.11122571676969528 + + blue_density + + 0 + 0 + 1 + 0.5 + + blue_horizon + + 1 + 0.5 + 0 + 0.5 + + cloud_color + + 0.22615400012094211 + 0.22615400012094211 + 0.22615400012094211 + 1 + + cloud_pos_density1 + + 1.6884100437164307 + 0.52609699964523315 + 0.87999999801324269 + 1 + + cloud_pos_density2 + + 1.6884100437164307 + 0.52609699964523315 + 0.125 + 1 + + cloud_scale + + 0.0099999997764825821 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.499400180710069 + 10.01099976217745 + + cloud_shadow + + 0 + 0 + 0 + 1 + + density_multiplier + + 0.00013000000035390258 + 0 + 0 + 1 + + distance_multiplier + + 20.200000762939453 + 0 + 0 + 1 + + east_angle + 1.5707963705062866 + enable_cloud_scroll + + 1 + 1 + + gamma + + 2.0199999809265137 + 0 + 0 + 1 + + glow + + 6.8000006675720215 + 0.0010000000474974513 + -0.69999998807907104 + 1 + + haze_density + + 1 + 0 + 0 + 1 + + haze_horizon + + 0.48999997973442078 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + -0.85491305589675903 + 0.51877129077911377 + -3.7369435545997476e-008 + 1 + + max_y + + 1333 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0 + sun_angle + 3.6870057582855225 + sunlight_color + + 0.45637205243110657 + 0.46549969911575317 + 0.86362791061401367 + 0.28787598013877869 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Moon%20Light%2007.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Moon%20Light%2007.xml new file mode 100644 index 0000000000..739c63c993 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Moon%20Light%2007.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.32094669342041016 + 0.38137125968933105 + 0.51905333995819092 + 0.17301777005195618 + + blue_density + + 0.44999827251961821 + 0.44999970758411817 + 0.45000196070835302 + 1 + + blue_horizon + + 0.23999924952063895 + 0.23999984552653461 + 0.24000005119478959 + 1 + + cloud_color + + 0.22615400012094211 + 0.22615400012094211 + 0.22615400012094211 + 1 + + cloud_pos_density1 + + 1.6884100437164307 + 0.52609699964523315 + 0.87999999801324269 + 1 + + cloud_pos_density2 + + 1.6884100437164307 + 0.52609699964523315 + 0.125 + 1 + + cloud_scale + + 3 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.20001220703125 + 10.01099976217745 + + cloud_shadow + + 0.15999999642372131 + 0 + 0 + 1 + + density_multiplier + + 8.9999994088429958e-005 + 0 + 0 + 1 + + distance_multiplier + + 41.100002288818359 + 0 + 0 + 1 + + east_angle + 2.7646017074584961 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1 + 0 + 0 + 1 + + glow + + 5.0000000000004476 + 0.0010000000424271499 + -0.47999998973471036 + 1 + + haze_density + + 0.20999999344348907 + 0 + 0 + 1 + + haze_horizon + + 0.20999999344348907 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0.31046971678733826 + 0.53731352090835571 + 0.78415733575820923 + 0 + + max_y + + 4000 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 500 + sun_angle + 2.5743441581726074 + sunlight_color + + 0.6015813946723938 + 0.61361336708068848 + 1.1384185552597046 + 0.37947285175323486 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Moon%20Light%2008.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Moon%20Light%2008.xml new file mode 100644 index 0000000000..b0fad0999f --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Moon%20Light%2008.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.32094669342041016 + 0.38137125968933105 + 0.51905333995819092 + 0.17301777005195618 + + blue_density + + 0.44999827251961821 + 0.44999970758411817 + 0.45000196070835302 + 1 + + blue_horizon + + 0.23999924952063895 + 0.23999984552653461 + 0.24000005119478959 + 1 + + cloud_color + + 0.22615400012094211 + 0.22615400012094211 + 0.22615400012094211 + 1 + + cloud_pos_density1 + + 1.6884100437164307 + 0.52609699964523315 + 0.87999999801324269 + 1 + + cloud_pos_density2 + + 1.6884100437164307 + 0.52609699964523315 + 0.125 + 1 + + cloud_scale + + 3 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.20001220703125 + 10.01099976217745 + + cloud_shadow + + 0.15999999642372131 + 0 + 0 + 1 + + density_multiplier + + 8.9999994088429958e-005 + 0 + 0 + 1 + + distance_multiplier + + 41.100002288818359 + 0 + 0 + 1 + + east_angle + 2.8588495254516602 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1 + 0 + 0 + 1 + + glow + + 5.0000000000004476 + 0.0010000000424271499 + -0.47999998973471036 + 1 + + haze_density + + 0.20999999344348907 + 0 + 0 + 1 + + haze_horizon + + 0.20999999344348907 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0.23529607057571411 + 0.53731352090835571 + 0.80989503860473633 + 0 + + max_y + + 4000 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 500 + sun_angle + 2.5743441581726074 + sunlight_color + + 0.6015813946723938 + 0.6136133074760437 + 1.1384185552597046 + 0.37947285175323486 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Never%20Night%20Light.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Never%20Night%20Light.xml new file mode 100644 index 0000000000..cc3e252454 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Never%20Night%20Light.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0 + 0.30000001192092896 + 0.10000000149011612 + + blue_density + + 0.12089811412885521 + 0.33770671695460663 + 0.67541757891583387 + 0.76708334654569654 + + blue_horizon + + 0.13497034943045882 + 0.26690842067701936 + 0.4016666400432598 + 0.74541666984558219 + + cloud_color + + 0.43948723673439005 + 0.49764935046544778 + 0.50246442938400904 + 1 + + cloud_pos_density1 + + 0.57999998331069946 + 0.87000000476837158 + 0.75 + 1 + + cloud_pos_density2 + + 1.6884100437164307 + 0.52609699964523315 + 0.073541670078411725 + 1 + + cloud_scale + + 0.18000000715255737 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.088005410620646 + 10.010458310484864 + + cloud_shadow + + 1 + 0 + 0 + 1 + + density_multiplier + + 0.00028125001798306321 + 0 + 0 + 1 + + distance_multiplier + + 6.3874998847643383 + 0 + 0 + 1 + + east_angle + 3.5185837745666504 + enable_cloud_scroll + + 1 + 1 + + gamma + + 0.12999999523162842 + 0 + 0 + 1 + + glow + + 9.4000005722045898 + 0.0010000000474974513 + -0.44999998807907104 + 1 + + haze_density + + 0.51583333298563971 + 0 + 0 + 1 + + haze_horizon + + 0.13833333183079954 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0.28709480166435242 + 0.6259227991104126 + -0.72511875629425049 + 0 + + max_y + + 685.18749099969864 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0.1029166579246521 + sun_angle + 0.67631423473358154 + sunlight_color + + 0 + 0 + 0 + 0 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20No%20Light.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20No%20Light.xml new file mode 100644 index 0000000000..2ca2ef77b0 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20No%20Light.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0 + 0 + 0 + + blue_density + + 0.12089811412885521 + 0.33770671695460663 + 0.67541757891583387 + 0.76708334654569654 + + blue_horizon + + 0.13497034943045882 + 0.26690842067701936 + 0.4016666400432598 + 0.74541666984558219 + + cloud_color + + 0.43948723673439005 + 0.49764935046544778 + 0.50246442938400904 + 1 + + cloud_pos_density1 + + 0.57999998331069946 + 0.87000000476837158 + 0.75 + 1 + + cloud_pos_density2 + + 1.6884100437164307 + 0.52609699964523315 + 0.073541670078411725 + 1 + + cloud_scale + + 0.18000000715255737 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.088005410620646 + 10.010458310484864 + + cloud_shadow + + 0 + 0 + 0 + 1 + + density_multiplier + + 0.00028125001798306321 + 0 + 0 + 1 + + distance_multiplier + + 6.3874998847643383 + 0 + 0 + 1 + + east_angle + 3.5185837745666504 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1.0900000333786011 + 0 + 0 + 1 + + glow + + 9.4000005722045898 + 0.0010000000474974513 + -0.44999998807907104 + 1 + + haze_density + + 0.51583333298563971 + 0 + 0 + 1 + + haze_horizon + + 0.13833333183079954 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0.28709480166435242 + 0.6259227991104126 + -0.72511875629425049 + 0 + + max_y + + 685.18749099969864 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0.1029166579246521 + sun_angle + 0.67631423473358154 + sunlight_color + + 0 + 0 + 0 + 0 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Owlery%20Light.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Owlery%20Light.xml new file mode 100644 index 0000000000..dca43b27f0 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Owlery%20Light.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.56250005960464478 + 0.26250001788139343 + 0.75 + 0.25 + + blue_density + + 0 + 0.40999585390090942 + 0.81999999284744263 + 0.85999995470046997 + + blue_horizon + + 0.43999999761581421 + 0.22910800576210022 + 0.26829266548156738 + 0.2199999988079071 + + cloud_color + + 0.23999999463558197 + 0.4699999988079071 + 0.31999999284744263 + 0.4699999988079071 + + cloud_pos_density1 + + 0.48999997973442078 + 0.50999999046325684 + 0.74000000953674316 + 1 + + cloud_pos_density2 + + 0.44999998807907104 + 0.5 + 0.14000000059604645 + 1 + + cloud_scale + + 0.0835999995470047 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.49940013885498 + 10.01099967956543 + + cloud_shadow + + 0.26999998092651367 + 0 + 0 + 1 + + density_multiplier + + 0.00035999997635371983 + 0 + 0 + 1 + + distance_multiplier + + 2 + 0 + 0 + 1 + + east_angle + 1.3257522583007813 + enable_cloud_scroll + + 0 + 0 + + gamma + + 2.0299999713897705 + 0 + 0 + 1 + + glow + + 0.39999961853027344 + 0.0010000000474974513 + -0.59999996423721313 + 1 + + haze_density + + 0.77999997138977051 + 0 + 0 + 1 + + haze_horizon + + 0.15999999642372131 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0.9694594144821167 + 0.037081710994243622 + -0.24243222177028656 + 0 + + max_y + + 591 + 0 + 0 + 1 + + preset_num + 18 + star_brightness + 1.0099999904632568 + sun_angle + 3.1045024394989014 + sunlight_color + + 2.5799999237060547 + 2.4411697387695313 + 2.4411697387695313 + 0.85999995470046997 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Puppy%20Light.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Puppy%20Light.xml new file mode 100644 index 0000000000..19151d34b5 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Puppy%20Light.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0.75 + 1.5 + 0.5 + + blue_density + + 0 + 0 + 0 + 0 + + blue_horizon + + 0 + 0.79687601327896118 + 0.79687398672103882 + 0.39843800663948059 + + cloud_color + + 0.43948723673439005 + 0.49764935046544778 + 0.50246442938400904 + 1 + + cloud_pos_density1 + + 0.57999998331069946 + 0.87000000476837158 + 0.75 + 1 + + cloud_pos_density2 + + 1.6884100437164307 + 0.52609699964523315 + 0.073541670078411725 + 1 + + cloud_scale + + 0 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.088005410620646 + 10.010458310484864 + + cloud_shadow + + 0 + 0 + 0 + 1 + + density_multiplier + + 0 + 0 + 0 + 1 + + distance_multiplier + + 31.5 + 0 + 0 + 1 + + east_angle + 6.0507078170776367 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1.4900000095367432 + 0 + 0 + 1 + + glow + + 4.8000001907348633 + 0.0010000000474974513 + -4.1499996185302734 + 1 + + haze_density + + 0.42999997735023499 + 0 + 0 + 1 + + haze_horizon + + 0.70999997854232788 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + -0.15858890116214752 + 0.72537636756896973 + -0.66983485221862793 + 1 + + max_y + + 0 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 500 + sun_angle + 5.4716043472290039 + sunlight_color + + 0 + 1.5058825016021729 + 1.5058825016021729 + 0.50196081399917603 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Queen%20Light%2001.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Queen%20Light%2001.xml new file mode 100644 index 0000000000..6db5852e70 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Queen%20Light%2001.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.1875 + 0.1875 + 0.1875 + 0.0625 + + blue_density + + 1.7999999523162842 + 1.7999999523162842 + 1.7999999523162842 + 0.89999997615814209 + + blue_horizon + + 1.7999999523162842 + 1.7999999523162842 + 1.7999999523162842 + 0.89999997615814209 + + cloud_color + + 0.40999999642372131 + 0.40999999642372131 + 0.40999999642372131 + 0.40999999642372131 + + cloud_pos_density1 + + 1.6884100437164307 + 0.52609699964523315 + 1 + 1 + + cloud_pos_density2 + + 1.6884100437164307 + 0.52609699964523315 + 0.125 + 1 + + cloud_scale + + 0.41999998688697815 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.70001220703125 + 10.01099967956543 + + cloud_shadow + + 0.44999998807907104 + 0 + 0 + 1 + + density_multiplier + + 0.00014170000213198364 + 0 + 0 + 1 + + distance_multiplier + + 7.9000000953674316 + 0 + 0 + 1 + + east_angle + 1.9477875232696533 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1.3999999761581421 + 0 + 0 + 1 + + glow + + 5 + 0.0010000000474974513 + -0.47999998927116394 + 1 + + haze_density + + 0.69999998807907104 + 0 + 0 + 1 + + haze_horizon + + 0.20999999344348907 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + -0.51655691862106323 + 0.83146905899047852 + -0.20451940596103668 + 0 + + max_y + + 77 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0 + sun_angle + 0.98174667358398438 + sunlight_color + + 2.6999998092651367 + 2.6999998092651367 + 2.6999998092651367 + 0.89999997615814209 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Quidditch%20Light.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Quidditch%20Light.xml new file mode 100644 index 0000000000..1e756c8f5e --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Quidditch%20Light.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.35999998450279236 + 0.21600005030632019 + 0 + 0.11999999731779099 + + blue_density + + 0.97999995946884155 + 0.97999995946884155 + 0.97999995946884155 + 0.48999997973442078 + + blue_horizon + + 0.31999999284744263 + 0.31999999284744263 + 0.31999999284744263 + 0.15999999642372131 + + cloud_color + + 0.5 + 0.5 + 0.5 + 0.5 + + cloud_pos_density1 + + 0.5 + 0.5 + 1 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.125 + 1 + + cloud_scale + + 0.12459999322891235 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.49940013885498 + 10.01099967956543 + + cloud_shadow + + 0.23999999463558197 + 0 + 0 + 1 + + density_multiplier + + 0.00031000000308267772 + 0 + 0 + 1 + + distance_multiplier + + 6.8000001907348633 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1.3042999505996704 + 0 + 0 + 1 + + glow + + 5 + 0.0010000000474974513 + -0.33000001311302185 + 1 + + haze_density + + 1.8899999856948853 + 0 + 0 + 1 + + haze_horizon + + 0.23999999463558197 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0 + 0.36227512359619141 + -0.93207120895385742 + 0 + + max_y + + 752 + 0 + 0 + 1 + + preset_num + 21 + star_brightness + 0 + sun_angle + 2.7708849906921387 + sunlight_color + + 1.3499999046325684 + 1.3499999046325684 + 1.3499999046325684 + 0.44999998807907104 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Save%20Me%20Light%20.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Save%20Me%20Light%20.xml new file mode 100644 index 0000000000..50fd94c0c0 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Save%20Me%20Light%20.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0 + 0 + 0 + + blue_density + + 2 + 2 + 2 + 1 + + blue_horizon + + 0 + 0 + 0 + 0 + + cloud_color + + 0.5 + 0.5 + 1 + 1 + + cloud_pos_density1 + + 0.95999997854232788 + 0.31000000238418579 + 3 + 1 + + cloud_pos_density2 + + 1 + 1 + 0.5 + 1 + + cloud_scale + + 0.79339998960494995 + 0 + 0 + 1 + + cloud_scroll_rate + + 18.5 + -3 + + cloud_shadow + + 0.15999999642372131 + 0 + 0 + 1 + + density_multiplier + + 3.299999889350147e-006 + 0 + 0 + 1 + + distance_multiplier + + 0 + 0 + 0 + 1 + + east_angle + 3.1855752468109131 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1 + 0 + 0 + 1 + + glow + + 15.799999237060547 + 0.0010000000474974513 + -0.74999994039535522 + 1 + + haze_density + + 0 + 0 + 0 + 1 + + haze_horizon + + 4.8899998664855957 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0.040397927165031433 + 0.39473667740821838 + -0.91790574789047241 + 0 + + max_y + + 385 + 0 + 0 + 1 + + preset_num + 21 + star_brightness + 500 + sun_angle + 0.40578123927116394 + sunlight_color + + 0 + 0 + 0 + 0 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Shadow%20Testing%20Light.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Shadow%20Testing%20Light.xml new file mode 100644 index 0000000000..5b10b3dbea --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Shadow%20Testing%20Light.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0 + 0 + 0 + + blue_density + + 0.24475815892219543 + 0.44872328639030457 + 0.75999999046325684 + 0.37999999523162842 + + blue_horizon + + 0.49548381567001343 + 0.49548381567001343 + 0.63999998569488525 + 0.31999999284744263 + + cloud_color + + 0.40999999642372131 + 0.40999999642372131 + 0.40999999642372131 + 0.40999999642372131 + + cloud_pos_density1 + + 1.6884100437164307 + 0.52609699964523315 + 1 + 1 + + cloud_pos_density2 + + 1.6884100437164307 + 0.52609699964523315 + 0.125 + 1 + + cloud_scale + + 0.41999998688697815 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.199999809265137 + 10.01099967956543 + + cloud_shadow + + 0.26999998092651367 + 0 + 0 + 1 + + density_multiplier + + 0.00017999998817685992 + 0 + 0 + 1 + + distance_multiplier + + 0.80000001192092896 + 0 + 0 + 1 + + east_angle + 3.1415927410125732 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1.3912999629974365 + 0 + 0 + 1 + + glow + + 5 + 0.0010000000474974513 + -0.47999998927116394 + 1 + + haze_density + + 0.69999998807907104 + 0 + 0 + 1 + + haze_horizon + + 0.18999999761581421 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 7.923197387071923e-008 + 0.42261755466461182 + -0.90630811452865601 + 0 + + max_y + + 1605 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0 + sun_angle + 0.43633154034614563 + sunlight_color + + 0 + 3 + 3 + 1 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Still%20Life.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Still%20Life.xml new file mode 100644 index 0000000000..f6d948d242 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Still%20Life.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.21000000834465027 + 0.21000000834465027 + 0.21000000834465027 + 0.070000000298023224 + + blue_density + + 0.97999995946884155 + 0.97999995946884155 + 0.97999995946884155 + 0.48999997973442078 + + blue_horizon + + 0.31999999284744263 + 0.31999999284744263 + 0.31999999284744263 + 0.15999999642372131 + + cloud_color + + 0.13600000739097595 + 0.17000001668930054 + 0.20399999618530273 + 0.20399999618530273 + + cloud_pos_density1 + + 0.42999997735023499 + 0.55000001192092896 + 0.83429998159408569 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.14000000059604645 + 1 + + cloud_scale + + 0.052799999713897705 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.49940013885498 + 10.01099967956543 + + cloud_shadow + + 0.21725988388061523 + 0 + 0 + 1 + + density_multiplier + + 0.00011869999434566125 + 0 + 0 + 1 + + distance_multiplier + + 25.700000762939453 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 0 + 0 + + gamma + + 2.2999999523162842 + 0 + 0 + 1 + + glow + + 5 + 0.0010000000474974513 + 0.39999961853027344 + 1 + + haze_density + + 0.1120000034570694 + 0 + 0 + 1 + + haze_horizon + + 0.44800001382827759 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0 + 0.54830676317214966 + -0.8362773060798645 + 0 + + max_y + + 813 + 0 + 0 + 1 + + preset_num + 21 + star_brightness + 0 + sun_angle + 2.5612545013427734 + sunlight_color + + 3 + 3 + 3 + 1 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Thalia%20Light%2001.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Thalia%20Light%2001.xml new file mode 100644 index 0000000000..099c6d4a1c --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Thalia%20Light%2001.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0 + 0 + 0 + + blue_density + + 1 + 1 + 1 + 0.5 + + blue_horizon + + 2 + 2 + 2 + 1 + + cloud_color + + 0.5 + 0.5 + 0.5 + 0.5 + + cloud_pos_density1 + + 0.5 + 0.5 + 0.76829999685287476 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.125 + 1 + + cloud_scale + + 0.059000000357627869 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.49940033104544 + 10.011000058908452 + + cloud_shadow + + 0.26999998092651367 + 0 + 0 + 1 + + density_multiplier + + 0.00020469998707994819 + 0 + 0 + 1 + + distance_multiplier + + 2.5 + 0 + 0 + 1 + + east_angle + 2.060884952545166 + enable_cloud_scroll + + 1 + 1 + + gamma + + 4.4000000953674316 + 0 + 0 + 1 + + glow + + 16.80000114440918 + 0.0010000000474974513 + -0.59999996423721313 + 1 + + haze_density + + 0 + 0 + 0 + 1 + + haze_horizon + + 0.81999999284744263 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0.77900981903076172 + 0.46948650479316711 + 0.41560328006744385 + 0 + + max_y + + 2538 + 0 + 0 + 1 + + preset_num + 21 + star_brightness + 1.7856996059417725 + sun_angle + 2.6528835296630859 + sunlight_color + + 3 + 3 + 3 + 1 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Thalia%20Light%2002.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Thalia%20Light%2002.xml new file mode 100644 index 0000000000..9e05253dd1 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Thalia%20Light%2002.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.54000002145767212 + 0.54000002145767212 + 0.54000002145767212 + 0.18000000715255737 + + blue_density + + 0.24475815892219543 + 0.44872328639030457 + 0.75999999046325684 + 0.37999999523162842 + + blue_horizon + + 0.49548381567001343 + 0.49548381567001343 + 0.63999998569488525 + 0.31999999284744263 + + cloud_color + + 0.40999999642372131 + 0.40999999642372131 + 0.40999999642372131 + 0.40999999642372131 + + cloud_pos_density1 + + 1.6884100437164307 + 0.52609699964523315 + 1 + 1 + + cloud_pos_density2 + + 1.6884100437164307 + 0.52609699964523315 + 0.125 + 1 + + cloud_scale + + 0.41999998688697815 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.199999809265137 + 10.01099967956543 + + cloud_shadow + + 0.26999998092651367 + 0 + 0 + 1 + + density_multiplier + + 0.00014999999257270247 + 0 + 0 + 1 + + distance_multiplier + + 0 + 0 + 0 + 1 + + east_angle + 0.9424777626991272 + enable_cloud_scroll + + 1 + 1 + + gamma + + 5.6700000762939453 + 0 + 0 + 1 + + glow + + 5 + 0.0010000000474974513 + -0.47999998927116394 + 1 + + haze_density + + 0.28999999165534973 + 0 + 0 + 1 + + haze_horizon + + 0.20999999344348907 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0.67267239093780518 + 0.55557155609130859 + -0.48872512578964233 + 0 + + max_y + + 1605 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0 + sun_angle + 2.5525424480438232 + sunlight_color + + 0.81000006198883057 + 0.81000006198883057 + 0.81000006198883057 + 0.27000001072883606 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Trilogy%20Rain%2001.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Trilogy%20Rain%2001.xml new file mode 100644 index 0000000000..cd69112074 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Trilogy%20Rain%2001.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0 + 0 + 0 + + blue_density + + 2 + 2 + 2 + 1 + + blue_horizon + + 0.13497035205364227 + 0.26690840721130371 + 0.40166664123535156 + 0.20083332061767578 + + cloud_color + + 0 + 0 + 0 + 0 + + cloud_pos_density1 + + 0.57999998331069946 + 0.87000000476837158 + 0.75 + 1 + + cloud_pos_density2 + + 1.6884100437164307 + 0.52609699964523315 + 0.073541670078411725 + 1 + + cloud_scale + + 0.99999994039535522 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.088005410620646 + 10.010458310484864 + + cloud_shadow + + 0.59999996423721313 + 0 + 0 + 1 + + density_multiplier + + 0.00011999999696854502 + 0 + 0 + 1 + + distance_multiplier + + 20.899999618530273 + 0 + 0 + 1 + + east_angle + 3.5185837745666504 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1.2400000095367432 + 0 + 0 + 1 + + glow + + 1.399998664855957 + 0.0010000000474974513 + -0.44999998807907104 + 1 + + haze_density + + 0.84999996423721313 + 0 + 0 + 1 + + haze_horizon + + 0.40999999642372131 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + -0.071817018091678619 + 0.9807855486869812 + 0.18138909339904785 + 0 + + max_y + + 4000 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0 + sun_angle + 1.7671444416046143 + sunlight_color + + 0.014999985694885254 + 1.0545001029968262 + 2.9850001335144043 + 0.99500000476837158 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Trilogy%20Rain%2002.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Trilogy%20Rain%2002.xml new file mode 100644 index 0000000000..9b3f6d522d --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Trilogy%20Rain%2002.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0 + 0 + 0 + + blue_density + + 0 + 0 + 0 + 0 + + blue_horizon + + 0.13497035205364227 + 0.26690840721130371 + 0.40166664123535156 + 0.20083332061767578 + + cloud_color + + 0 + 0 + 0 + 0 + + cloud_pos_density1 + + 0.57999998331069946 + 0.87000000476837158 + 0.75 + 1 + + cloud_pos_density2 + + 1.6884100437164307 + 0.52609699964523315 + 0.073541670078411725 + 1 + + cloud_scale + + 0.99999994039535522 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.088005410620646 + 10.010458310484864 + + cloud_shadow + + 0 + 0 + 0 + 1 + + density_multiplier + + 0.00014999999257270247 + 0 + 0 + 1 + + distance_multiplier + + 14 + 0 + 0 + 1 + + east_angle + 3.5185837745666504 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1.2400000095367432 + 0 + 0 + 1 + + glow + + 1.399998664855957 + 0.0010000000474974513 + -2.2999999523162842 + 1 + + haze_density + + 3.6499998569488525 + 0 + 0 + 1 + + haze_horizon + + 0.75999999046325684 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + -0.071817018091678619 + 0.9807855486869812 + 0.18138909339904785 + 0 + + max_y + + 4000 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 0 + sun_angle + 1.7671444416046143 + sunlight_color + + 0.014999985694885254 + 1.0545001029968262 + 2.9850001335144043 + 0.99500000476837158 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20White%20Fire%20Sky%2001.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20White%20Fire%20Sky%2001.xml new file mode 100644 index 0000000000..df2feee226 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20White%20Fire%20Sky%2001.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.38999998569488525 + 0.38999998569488525 + 0.38999998569488525 + 0.12999999523162842 + + blue_density + + 2 + 2 + 2 + 1 + + blue_horizon + + 0 + 0 + 0 + 0 + + cloud_color + + 1 + 1 + 1 + 1 + + cloud_pos_density1 + + 0.78999996185302734 + 0.90999996662139893 + 0.11589999496936798 + 1 + + cloud_pos_density2 + + 1 + 1 + 0 + 1 + + cloud_scale + + 0.026499999687075615 + 0 + 0 + 1 + + cloud_scroll_rate + + 17.770000457763672 + 4.4699997901916504 + + cloud_shadow + + 1 + 0 + 0 + 1 + + density_multiplier + + 0.00033199999597854912 + 0 + 0 + 1 + + distance_multiplier + + 0 + 0 + 0 + 1 + + east_angle + 2.7457520961761475 + enable_cloud_scroll + + 1 + 1 + + gamma + + 0.057900000363588333 + 0 + 0 + 1 + + glow + + 0.19999980926513672 + 0.0010000000474974513 + -0.14999999105930328 + 1 + + haze_density + + 0 + 0 + 0 + 1 + + haze_horizon + + 0 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + -0.18987095355987549 + 0.87035512924194336 + -0.45434671640396118 + 0 + + max_y + + 2758 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 2 + sun_angle + 1.0559231042861938 + sunlight_color + + 2.6999998092651367 + 2.6999998092651367 + 2.6999998092651367 + 0.89999997615814209 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20White%20Fire%20Sky%2002.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20White%20Fire%20Sky%2002.xml new file mode 100644 index 0000000000..85dd157571 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20White%20Fire%20Sky%2002.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.38999998569488525 + 0.38999998569488525 + 0.38999998569488525 + 0.12999999523162842 + + blue_density + + 2 + 2 + 2 + 1 + + blue_horizon + + 0 + 0 + 0 + 0 + + cloud_color + + 1 + 1 + 1 + 1 + + cloud_pos_density1 + + 0.78999996185302734 + 0.90999996662139893 + 0.23999999463558197 + 1 + + cloud_pos_density2 + + 1 + 1 + 0 + 1 + + cloud_scale + + 0.4681999683380127 + 0 + 0 + 1 + + cloud_scroll_rate + + 17.770000457763672 + 4.4699997901916504 + + cloud_shadow + + 0.75 + 0 + 0 + 1 + + density_multiplier + + 0.00033199999597854912 + 0 + 0 + 1 + + distance_multiplier + + 0 + 0 + 0 + 1 + + east_angle + 2.7457520961761475 + enable_cloud_scroll + + 1 + 1 + + gamma + + 0.057900000363588333 + 0 + 0 + 1 + + glow + + 0.19999980926513672 + 0.0010000000474974513 + -0.14999999105930328 + 1 + + haze_density + + 0 + 0 + 0 + 1 + + haze_horizon + + 0 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + -0.18987095355987549 + 0.87035512924194336 + -0.45434671640396118 + 0 + + max_y + + 2758 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 2 + sun_angle + 1.0559231042861938 + sunlight_color + + 2.6999998092651367 + 2.6999998092651367 + 2.6999998092651367 + 0.89999997615814209 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20White%20Fire%20Sky%2003.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20White%20Fire%20Sky%2003.xml new file mode 100644 index 0000000000..9dbfd2a7d3 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20White%20Fire%20Sky%2003.xml @@ -0,0 +1,141 @@ + + + ambient + + 1.4399999380111694 + 1.4399999380111694 + 1.4399999380111694 + 0.47999998927116394 + + blue_density + + 2 + 2 + 2 + 1 + + blue_horizon + + 0 + 0 + 0 + 0 + + cloud_color + + 1 + 1 + 1 + 1 + + cloud_pos_density1 + + 0.78999996185302734 + 0.90999996662139893 + 0.11589999496936798 + 1 + + cloud_pos_density2 + + 1 + 1 + 0 + 1 + + cloud_scale + + 0.024799998849630356 + 0 + 0 + 1 + + cloud_scroll_rate + + 17.770000457763672 + 4.4699997901916504 + + cloud_shadow + + 1 + 0 + 0 + 1 + + density_multiplier + + 0.00033069998607970774 + 0 + 0 + 1 + + distance_multiplier + + 31.5 + 0 + 0 + 1 + + east_angle + 2.7457520961761475 + enable_cloud_scroll + + 1 + 1 + + gamma + + 0.18999999761581421 + 0 + 0 + 1 + + glow + + 0.19999980926513672 + 0.0010000000474974513 + -0.14999999105930328 + 1 + + haze_density + + 0 + 0 + 0 + 1 + + haze_horizon + + 0 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + -0.18987095355987549 + 0.87035512924194336 + -0.45434671640396118 + 0 + + max_y + + 3000 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 500 + sun_angle + 1.0559231042861938 + sunlight_color + + 2.6999998092651367 + 2.6999998092651367 + 2.6999998092651367 + 0.89999997615814209 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20Yellow%20Stars%2001.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Yellow%20Stars%2001.xml new file mode 100644 index 0000000000..778c1c58b1 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20Yellow%20Stars%2001.xml @@ -0,0 +1,141 @@ + + + ambient + + 0 + 0 + 0 + 0 + + blue_density + + 1 + 1 + 2 + 1 + + blue_horizon + + 1.2800000905990601 + 1.2799999713897705 + 0 + 0.64000004529953003 + + cloud_color + + 0.43948723673439005 + 0.49764935046544778 + 0.50246442938400904 + 1 + + cloud_pos_density1 + + 0.57999998331069946 + 0.87000000476837158 + 0.75 + 1 + + cloud_pos_density2 + + 1.6884100437164307 + 0.52609699964523315 + 0.073541670078411725 + 1 + + cloud_scale + + 0.18000000715255737 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.088005410620646 + 10.010458310484864 + + cloud_shadow + + 0 + 0 + 0 + 1 + + density_multiplier + + 0.00033069998607970774 + 0 + 0 + 1 + + distance_multiplier + + -13761.5 + 0 + 0 + 1 + + east_angle + 3.5185837745666504 + enable_cloud_scroll + + 1 + 1 + + gamma + + 1.0900000333786011 + 0 + 0 + 1 + + glow + + 3.0000019073486328 + 0.0010000000474974513 + 10 + 1 + + haze_density + + 4.7799997329711914 + 0 + 0 + 1 + + haze_horizon + + 0.34999999403953552 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0.26703047752380371 + 0.68834781646728516 + -0.67444199323654175 + 0 + + max_y + + 5691 + 0 + 0 + 1 + + preset_num + 22 + star_brightness + 500 + sun_angle + 0.75920891761779785 + sunlight_color + + 3 + 3 + 1.5 + 1 + + + diff --git a/indra/newview/app_settings/windlight/skies/Phototools%2D%20rara%20Fall%20Home%20Light.xml b/indra/newview/app_settings/windlight/skies/Phototools%2D%20rara%20Fall%20Home%20Light.xml new file mode 100644 index 0000000000..466de5aae8 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/Phototools%2D%20rara%20Fall%20Home%20Light.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.42000001668930054 + 0.42000001668930054 + 0.42000001668930054 + 0.14000000059604645 + + blue_density + + 0.97999995946884155 + 0.97999995946884155 + 0.97999995946884155 + 0.48999997973442078 + + blue_horizon + + 0.31999999284744263 + 0.31999999284744263 + 0.31999999284744263 + 0.15999999642372131 + + cloud_color + + 0.50999999046325684 + 0.50999999046325684 + 0.50999999046325684 + 1 + + cloud_pos_density1 + + 0.5 + 0.5 + 1 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.125 + 1 + + cloud_scale + + 0.079999998211860657 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.49940013885498 + 10.01099967956543 + + cloud_shadow + + 0.25999999046325684 + 0 + 0 + 1 + + density_multiplier + + 7.8699995356146246e-005 + 0 + 0 + 1 + + distance_multiplier + + 79.5 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 3.809999942779541 + 0 + 0 + 1 + + glow + + 5 + 0.0010000000474974513 + 0.39999961853027344 + 1 + + haze_density + + 0.22400000691413879 + 0 + 0 + 1 + + haze_horizon + + 0.67200005054473877 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0 + 0.17796146869659424 + -0.98403745889663696 + 0 + + max_y + + 813 + 0 + 0 + 1 + + preset_num + 21 + star_brightness + 0 + sun_angle + 2.9626781940460205 + sunlight_color + + 1.3799998760223389 + 1.3799998760223389 + 1.3799998760223389 + 0.45999997854232788 + + + diff --git a/indra/newview/app_settings/windlight/skies/wastelands%20bright.xml b/indra/newview/app_settings/windlight/skies/wastelands%20bright.xml new file mode 100644 index 0000000000..b9cfd7dfb9 --- /dev/null +++ b/indra/newview/app_settings/windlight/skies/wastelands%20bright.xml @@ -0,0 +1,141 @@ + + + ambient + + 0.29999998211860657 + 0.17999999225139618 + 0 + 0.29999998211860657 + + blue_density + + 0.97999995946884155 + 0.97999995946884155 + 0.97999995946884155 + 0.48999997973442078 + + blue_horizon + + 0.31999999284744263 + 0.31999999284744263 + 0.31999999284744263 + 0.15999999642372131 + + cloud_color + + 0.50999999046325684 + 0.50999999046325684 + 0.50999999046325684 + 1 + + cloud_pos_density1 + + 0.5 + 0.5 + 1 + 1 + + cloud_pos_density2 + + 0.5 + 0.5 + 0.125 + 1 + + cloud_scale + + 0.079999998211860657 + 0 + 0 + 1 + + cloud_scroll_rate + + 10.49940013885498 + 10.01099967956543 + + cloud_shadow + + 0.25999999046325684 + 0 + 0 + 1 + + density_multiplier + + 0.00031000000308267772 + 0 + 0 + 1 + + distance_multiplier + + 6.8000001907348633 + 0 + 0 + 1 + + east_angle + 0 + enable_cloud_scroll + + 1 + 1 + + gamma + + 3 + 0 + 0 + 1 + + glow + + 5 + 0.0010000000474974513 + -0.33000001311302185 + 1 + + haze_density + + 1.8899999856948853 + 0 + 0 + 1 + + haze_horizon + + 0.23999999463558197 + 0.19915600121021271 + 0.19915600121021271 + 1 + + lightnorm + + 0 + 0.36227512359619141 + -0.93207120895385742 + 0 + + max_y + + 752 + 0 + 0 + 1 + + preset_num + 21 + star_brightness + 0 + sun_angle + 2.7708849906921387 + sunlight_color + + 1.3799998760223389 + 1.3799998760223389 + 1.3799998760223389 + 0.45999997854232788 + + + diff --git a/indra/newview/app_settings/windlight/water/%5BPyFX%5D%20Default%20%2B%20Texture.xml b/indra/newview/app_settings/windlight/water/%5BPyFX%5D%20Default%20%2B%20Texture.xml new file mode 100644 index 0000000000..b945a41d83 --- /dev/null +++ b/indra/newview/app_settings/windlight/water/%5BPyFX%5D%20Default%20%2B%20Texture.xml @@ -0,0 +1,43 @@ + + + blurMultiplier + 0.01000000070780515670776367 + fresnelOffset + 0.5 + fresnelScale + 0.5 + normScale + + 4 + 4 + 1 + + normalMap + 7f132b94-6c9c-5af3-5a17-3412ad653da0 + scaleAbove + 0.02999999932944774627685547 + scaleBelow + 0.2000000029802322387695313 + underWaterFogMod + 0.66999995708465576171875 + waterFogColor + + 0.1960784494876861572265625 + 0.2196078598499298095703125 + 0.1764705926179885864257813 + 1 + + waterFogDensity + 103.96833038330078125 + wave1Dir + + -0.25 + 0 + + wave2Dir + + -1 + 0 + + + diff --git a/indra/newview/app_settings/windlight/water/%5BPyFX%5D%20Default.xml b/indra/newview/app_settings/windlight/water/%5BPyFX%5D%20Default.xml new file mode 100644 index 0000000000..1c443156c8 --- /dev/null +++ b/indra/newview/app_settings/windlight/water/%5BPyFX%5D%20Default.xml @@ -0,0 +1,43 @@ + + + blurMultiplier + 0.04500000178813934326171875 + fresnelOffset + 0.5 + fresnelScale + 0.5 + normScale + + 1.10000002384185791015625 + 1 + 1 + + normalMap + 822ded49-9a6c-f61c-cb89-6df54f42cdf4 + scaleAbove + 0.02999999932944774627685547 + scaleBelow + 0.2000000029802322387695313 + underWaterFogMod + 0.66999995708465576171875 + waterFogColor + + 0.199999988079071044921875 + 0.2199999988079071044921875 + 0.1799999773502349853515625 + 1 + + waterFogDensity + 103.96833038330078125 + wave1Dir + + -1 + 0 + + wave2Dir + + -1 + 0 + + + diff --git a/indra/newview/app_settings/windlight/water/%5BPyFX%5D%20Ice.xml b/indra/newview/app_settings/windlight/water/%5BPyFX%5D%20Ice.xml new file mode 100644 index 0000000000..a5cdf76ae2 --- /dev/null +++ b/indra/newview/app_settings/windlight/water/%5BPyFX%5D%20Ice.xml @@ -0,0 +1,43 @@ + + + blurMultiplier + 0.1600000113248825073242188 + fresnelOffset + 0.5 + fresnelScale + 1 + normScale + + 5 + 5 + 5 + + normalMap + f92da839-f302-c813-668d-601ab1957af1 + scaleAbove + 0.199999988079071044921875 + scaleBelow + 0.2000000029802322387695313 + underWaterFogMod + 1 + waterFogColor + + 0.02851562201976776123046875 + 0.07148437201976776123046875 + 0.06242064759135246276855469 + 1 + + waterFogDensity + 2 + wave1Dir + + 0 + 0 + + wave2Dir + + 0 + 0 + + + diff --git a/indra/newview/app_settings/windlight/water/%5BPyFX%5D%20Ocean%20%2B%20Texture.xml b/indra/newview/app_settings/windlight/water/%5BPyFX%5D%20Ocean%20%2B%20Texture.xml new file mode 100644 index 0000000000..edd3e9a97a --- /dev/null +++ b/indra/newview/app_settings/windlight/water/%5BPyFX%5D%20Ocean%20%2B%20Texture.xml @@ -0,0 +1,43 @@ + + + blurMultiplier + 0.05000000074505805969238281 + fresnelOffset + 0.5 + fresnelScale + 0.5 + normScale + + 5 + 5 + 5 + + normalMap + 7f132b94-6c9c-5af3-5a17-3412ad653da0 + scaleAbove + 0.04999999701976776123046875 + scaleBelow + 0.2000000029802322387695313 + underWaterFogMod + 1 + waterFogColor + + 0.194549560546875 + 0.602325439453125 + 0.50675296783447265625 + 1 + + waterFogDensity + 8 + wave1Dir + + -0.1000001430511474609375 + -0.1000001430511474609375 + + wave2Dir + + -0.5 + -0.5 + + + diff --git a/indra/newview/app_settings/windlight/water/%5BPyFX%5D%20Ocean%202%20%2B%20Texture.xml b/indra/newview/app_settings/windlight/water/%5BPyFX%5D%20Ocean%202%20%2B%20Texture.xml new file mode 100644 index 0000000000..5eaa008459 --- /dev/null +++ b/indra/newview/app_settings/windlight/water/%5BPyFX%5D%20Ocean%202%20%2B%20Texture.xml @@ -0,0 +1,43 @@ + + + blurMultiplier + 0.005000000353902578353881836 + fresnelOffset + 0.599999964237213134765625 + fresnelScale + 0.2999999821186065673828125 + normScale + + 1 + 1 + 1 + + normalMap + 7f132b94-6c9c-5af3-5a17-3412ad653da0 + scaleAbove + 0.02999999932944774627685547 + scaleBelow + 0.2000000029802322387695313 + underWaterFogMod + 0.5 + waterFogColor + + 0.1882353127002716064453125 + 0.2509804069995880126953125 + 0.3137255012989044189453125 + 1 + + waterFogDensity + 32 + wave1Dir + + -0.5 + 0 + + wave2Dir + + -2 + 0 + + + diff --git a/indra/newview/app_settings/windlight/water/%5BPyFX%5D%20Ocean%202.xml b/indra/newview/app_settings/windlight/water/%5BPyFX%5D%20Ocean%202.xml new file mode 100644 index 0000000000..6866eacad7 --- /dev/null +++ b/indra/newview/app_settings/windlight/water/%5BPyFX%5D%20Ocean%202.xml @@ -0,0 +1,43 @@ + + + blurMultiplier + 0.04500000178813934326171875 + fresnelOffset + 0.599999964237213134765625 + fresnelScale + 0.2999999821186065673828125 + normScale + + 1 + 1 + 1 + + normalMap + 822ded49-9a6c-f61c-cb89-6df54f42cdf4 + scaleAbove + 0.02999999932944774627685547 + scaleBelow + 0.2000000029802322387695313 + underWaterFogMod + 0.5 + waterFogColor + + 0.1882353127002716064453125 + 0.2509804069995880126953125 + 0.3137255012989044189453125 + 1 + + waterFogDensity + 32 + wave1Dir + + -2 + 0 + + wave2Dir + + -4 + 0 + + + diff --git a/indra/newview/app_settings/windlight/water/Phototools%2D%20Black%20Default%20.xml b/indra/newview/app_settings/windlight/water/Phototools%2D%20Black%20Default%20.xml new file mode 100644 index 0000000000..31cc985809 --- /dev/null +++ b/indra/newview/app_settings/windlight/water/Phototools%2D%20Black%20Default%20.xml @@ -0,0 +1,43 @@ + + + blurMultiplier + 0.060000002384185791 + fresnelOffset + 0.56000000238418579 + fresnelScale + 1 + normScale + + 10 + 10 + 10 + + normalMap + 822ded49-9a6c-f61c-cb89-6df54f42cdf4 + scaleAbove + 0.029999999329447746 + scaleBelow + 0.20000000298023224 + underWaterFogMod + 0.25 + waterFogColor + + 0 + 0 + 0 + 1 + + waterFogDensity + 16 + wave1Dir + + 1.0499997138977051 + -0.42000007629394531 + + wave2Dir + + 1.1099996566772461 + -1.1600000858306885 + + + diff --git a/indra/newview/app_settings/windlight/water/Phototools%2D%20Breakwave%20Building%20Water.xml b/indra/newview/app_settings/windlight/water/Phototools%2D%20Breakwave%20Building%20Water.xml new file mode 100644 index 0000000000..2c5596edb1 --- /dev/null +++ b/indra/newview/app_settings/windlight/water/Phototools%2D%20Breakwave%20Building%20Water.xml @@ -0,0 +1,43 @@ + + + blurMultiplier + 0.040000002831220627 + fresnelOffset + 0.5 + fresnelScale + 0.39999997615814209 + normScale + + 2 + 2 + 2 + + normalMap + 822ded49-9a6c-f61c-cb89-6df54f42cdf4 + scaleAbove + 0.029999999329447746 + scaleBelow + 0.20000000298023224 + underWaterFogMod + 0.25 + waterFogColor + + 0 + 0 + 0 + 1 + + waterFogDensity + 16 + wave1Dir + + 1.0499997138977051 + -0.42000007629394531 + + wave2Dir + + 1.1099996566772461 + -1.1600000858306885 + + + diff --git a/indra/newview/app_settings/windlight/water/Phototools%2D%20Chandra%20Sea.xml b/indra/newview/app_settings/windlight/water/Phototools%2D%20Chandra%20Sea.xml new file mode 100644 index 0000000000..93989f25b4 --- /dev/null +++ b/indra/newview/app_settings/windlight/water/Phototools%2D%20Chandra%20Sea.xml @@ -0,0 +1,43 @@ + + + blurMultiplier + 0.040000002831220627 + fresnelOffset + 0.55000001192092896 + fresnelScale + 0.62999999523162842 + normScale + + 0 + 0.60000002384185791 + 4.7000002861022949 + + normalMap + 822ded49-9a6c-f61c-cb89-6df54f42cdf4 + scaleAbove + 0 + scaleBelow + 0 + underWaterFogMod + 0.5 + waterFogColor + + 0.19140625 + 0.19140625 + 0.19140625 + 1 + + waterFogDensity + 6.9644041061401367 + wave1Dir + + -0.34000015258789063 + -0.19000005722045898 + + wave2Dir + + -1.4000000953674316 + -0.98000001907348633 + + + diff --git a/indra/newview/app_settings/windlight/water/Phototools%2D%20Gallery%20Water%2001.xml b/indra/newview/app_settings/windlight/water/Phototools%2D%20Gallery%20Water%2001.xml new file mode 100644 index 0000000000..d3cf6f6d8f --- /dev/null +++ b/indra/newview/app_settings/windlight/water/Phototools%2D%20Gallery%20Water%2001.xml @@ -0,0 +1,43 @@ + + + blurMultiplier + 0.040000002831220627 + fresnelOffset + 0.5 + fresnelScale + 0.39999997615814209 + normScale + + 2 + 2 + 2 + + normalMap + 822ded49-9a6c-f61c-cb89-6df54f42cdf4 + scaleAbove + 0.029999999329447746 + scaleBelow + 0.20000000298023224 + underWaterFogMod + 0.25 + waterFogColor + + 0 + 0 + 0 + 1 + + waterFogDensity + 16 + wave1Dir + + 0.529998779296875 + -0.21000099182128906 + + wave2Dir + + 0.55999946594238281 + -0.57999992370605469 + + + diff --git a/indra/newview/app_settings/windlight/water/Phototools%2D%20Ship%20Light.xml b/indra/newview/app_settings/windlight/water/Phototools%2D%20Ship%20Light.xml new file mode 100644 index 0000000000..6a4708dac9 --- /dev/null +++ b/indra/newview/app_settings/windlight/water/Phototools%2D%20Ship%20Light.xml @@ -0,0 +1,43 @@ + + + blurMultiplier + 0.040000002831220627 + fresnelOffset + 0.5899999737739563 + fresnelScale + 0.22999998927116394 + normScale + + 1.3000000715255737 + 5.0999999046325684 + 2.2999999523162842 + + normalMap + 822ded49-9a6c-f61c-cb89-6df54f42cdf4 + scaleAbove + 0 + scaleBelow + 0 + underWaterFogMod + 0.5 + waterFogColor + + 0 + 0 + 0 + 1 + + waterFogDensity + 6.9644041061401367 + wave1Dir + + -0.34000015258789063 + -0.19000005722045898 + + wave2Dir + + -1.4000000953674316 + -0.98000001907348633 + + + diff --git a/indra/newview/ascentfloatercontactgroups.cpp b/indra/newview/ascentfloatercontactgroups.cpp index f1d867fca9..d4032a6e8d 100644 --- a/indra/newview/ascentfloatercontactgroups.cpp +++ b/indra/newview/ascentfloatercontactgroups.cpp @@ -24,7 +24,6 @@ #include "llviewercontrol.h" #include "llviewerwindow.h" #include "llsdserialize.h" -#include "lldarray.h" #include "llfile.h" #include "llchat.h" #include "llfloaterchat.h" @@ -74,7 +73,7 @@ void ASFloaterContactGroups::onBtnDelete(void* userdata) void ASFloaterContactGroups::onBtnAdd(void* userdata) { ASFloaterContactGroups* self = (ASFloaterContactGroups*)userdata; - llinfos << "Button Add Begin" << llendl; + LL_INFOS() << "Button Add Begin" << LL_ENDL; if(self) { LLComboBox* combo = self->getChild("buddy_group_combobox"); @@ -187,17 +186,17 @@ void ASFloaterContactGroups::populateActiveGroupList(LLUUID user_key) LLScrollListCtrl* scroller = getChild("group_scroll_list"); if(scroller != NULL) { - llinfos << "Cleaning and rebuilding group list" << llendl; + LL_INFOS() << "Cleaning and rebuilding group list" << LL_ENDL; scroller->deleteAllItems(); S32 count = ASFloaterContactGroups::mContactGroupData["ASC_MASTER_GROUP_LIST"].size(); for (S32 index = 0; index < count; index++) { - llinfos << "Entries for " << ASFloaterContactGroups::mContactGroupData["ASC_MASTER_GROUP_LIST"][index].asString() << llendl; + LL_INFOS() << "Entries for " << ASFloaterContactGroups::mContactGroupData["ASC_MASTER_GROUP_LIST"][index].asString() << LL_ENDL; S32 entrycount = ASFloaterContactGroups::mContactGroupData["ASC_MASTER_GROUP_LIST"][index].size(); for(S32 i = 0; i < entrycount; i++) { - llinfos << "Subentries for " << ASFloaterContactGroups::mContactGroupData["ASC_MASTER_GROUP_LIST"][index][i].asString() << llendl; + LL_INFOS() << "Subentries for " << ASFloaterContactGroups::mContactGroupData["ASC_MASTER_GROUP_LIST"][index][i].asString() << LL_ENDL; if (ASFloaterContactGroups::mContactGroupData["ASC_MASTER_GROUP_LIST"][index][i].asString() == user_key.asString()) { @@ -236,7 +235,7 @@ void ASFloaterContactGroups::populateGroupList() std::string group = ASFloaterContactGroups::mContactGroupData["ASC_MASTER_GROUP_LIST"][index].asString(); if (group != "") { - llinfos << "Adding " << group << llendl; + LL_INFOS() << "Adding " << group << LL_ENDL; combo->add(ASFloaterContactGroups::mContactGroupData["ASC_MASTER_GROUP_LIST"][index].asString(), ADD_BOTTOM); } } diff --git a/indra/newview/ascentfloatercontactgroups.h b/indra/newview/ascentfloatercontactgroups.h index e20a67d380..25422cbd9b 100644 --- a/indra/newview/ascentfloatercontactgroups.h +++ b/indra/newview/ascentfloatercontactgroups.h @@ -16,7 +16,6 @@ #define ASCENT_CONTACT_GROUPS #include "llfloater.h" -#include "lldarray.h" #include "llsdserialize.h" class LLScrollListCtrl; diff --git a/indra/newview/ascentprefschat.cpp b/indra/newview/ascentprefschat.cpp index 07eb9f7f94..25d1964352 100644 --- a/indra/newview/ascentprefschat.cpp +++ b/indra/newview/ascentprefschat.cpp @@ -37,6 +37,7 @@ #include "llagent.h" #include "llcolorswatch.h" #include "llcombobox.h" +#include "llfloaterautoreplacesettings.h" #include "llradiogroup.h" #include "lluictrlfactory.h" #include "llviewercontrol.h" @@ -68,30 +69,13 @@ LLPrefsAscentChat::LLPrefsAscentChat() autoresponse->setToolTip(LLTrans::getString("NotLoggedIn")); } - // Saved per account settings aren't detected by control_name, therefore autoresponse controls get their values here and have them saved during apply. - childSetValue("AscentInstantMessageResponseRepeat", gSavedPerAccountSettings.getBOOL("AscentInstantMessageResponseRepeat")); - childSetValue("AutoresponseAnyone", gSavedPerAccountSettings.getBOOL("AutoresponseAnyone")); - childSetValue("AutoresponseAnyoneFriendsOnly", gSavedPerAccountSettings.getBOOL("AutoresponseAnyoneFriendsOnly")); - childSetValue("AutoresponseAnyoneItem", gSavedPerAccountSettings.getBOOL("AutoresponseAnyoneItem")); - childSetValue("AutoresponseAnyoneMessage", gSavedPerAccountSettings.getString("AutoresponseAnyoneMessage")); - childSetValue("AutoresponseAnyoneShow", gSavedPerAccountSettings.getBOOL("AutoresponseAnyoneShow")); - childSetValue("AutoresponseNonFriends", gSavedPerAccountSettings.getBOOL("AutoresponseNonFriends")); - childSetValue("AutoresponseNonFriendsItem", gSavedPerAccountSettings.getBOOL("AutoresponseNonFriendsItem")); - childSetValue("AutoresponseNonFriendsMessage", gSavedPerAccountSettings.getString("AutoresponseNonFriendsMessage")); - childSetValue("AutoresponseNonFriendsShow", gSavedPerAccountSettings.getBOOL("AutoresponseNonFriendsShow")); - childSetValue("AutoresponseMuted", gSavedPerAccountSettings.getBOOL("AutoresponseMuted")); - childSetValue("AutoresponseMutedItem", gSavedPerAccountSettings.getBOOL("AutoresponseMutedItem")); - childSetValue("AutoresponseMutedMessage", gSavedPerAccountSettings.getString("AutoresponseMutedMessage")); - childSetValue("BusyModeResponse", gSavedPerAccountSettings.getString("BusyModeResponse")); - childSetValue("BusyModeResponseItem", gSavedPerAccountSettings.getBOOL("BusyModeResponseItem")); - childSetValue("BusyModeResponseShow", gSavedPerAccountSettings.getBOOL("BusyModeResponseShow")); - childSetEnabled("reset_antispam", started); - getChild("reset_antispam")->setCommitCallback(boost::bind(NACLAntiSpamRegistry::purgeAllQueues)); - getChild("enable_as")->setCommitCallback(boost::bind(&LLPrefsAscentChat::onCommitEnableAS, this, _2)); - getChild("antispam_checkbox")->setCommitCallback(boost::bind(&LLPrefsAscentChat::onCommitDialogBlock, this, _1, _2)); - getChild("Group Invites")->setCommitCallback(boost::bind(&LLPrefsAscentChat::onCommitDialogBlock, this, _1, _2)); + getChild("reset_antispam")->setCommitCallback([](LLUICtrl* ctrl, const LLSD& param) { + if (auto inst = NACLAntiSpamRegistry::getIfExists()) + inst->resetQueues(); + }); + getChild("autoreplace")->setCommitCallback(boost::bind(LLFloaterAutoReplaceSettings::showInstance, LLSD())); getChild("KeywordsOn")->setCommitCallback(boost::bind(&LLPrefsAscentChat::onCommitKeywords, this, _1)); getChild("KeywordsList")->setCommitCallback(boost::bind(&LLPrefsAscentChat::onCommitKeywords, this, _1)); getChild("KeywordsSound")->setCommitCallback(boost::bind(&LLPrefsAscentChat::onCommitKeywords, this, _1)); @@ -131,90 +115,75 @@ void LLPrefsAscentChat::onSpellBaseComboBoxCommit(const LLSD& value) glggHunSpell->newDictSelection(value.asString()); } -void LLPrefsAscentChat::onCommitTimeDate(LLUICtrl* ctrl) +void setTimeDateFormats(const S8& tempTimeFormat, const S8& tempDateFormat) { - LLComboBox* combo = static_cast(ctrl); - if (ctrl->getName() == "time_format_combobox") - { - tempTimeFormat = combo->getCurrentIndex(); - } - else if (ctrl->getName() == "date_format_combobox") - { - tempDateFormat = combo->getCurrentIndex(); - } - - std::string short_date, long_date, short_time, long_time, timestamp; + std::string short_date, long_date, short_time, long_time, timestamp; - if (tempTimeFormat == 0) - { - short_time = "%H:%M"; - long_time = "%H:%M:%S"; - timestamp = " %H:%M:%S"; - } - else - { - short_time = "%I:%M %p"; - long_time = "%I:%M:%S %p"; - timestamp = " %I:%M %p"; - } - - if (tempDateFormat == 0) - { - short_date = "%Y-%m-%d"; - long_date = "%A %d %B %Y"; - timestamp = "%a %d %b %Y" + timestamp; - } - else if (tempDateFormat == 1) - { - short_date = "%d/%m/%Y"; - long_date = "%A %d %B %Y"; - timestamp = "%a %d %b %Y" + timestamp; - } - else - { - short_date = "%m/%d/%Y"; - long_date = "%A, %B %d %Y"; - timestamp = "%a %b %d %Y" + timestamp; - } + if (tempDateFormat != -1) + { + if (tempDateFormat < 3) + { + short_date = !tempDateFormat ? "%F" : + tempDateFormat == 1 ? "%Y/%m/%d" : + "%d/%m/%Y"; + long_date = "%A, %d %B %Y"; + timestamp = "%a %d %b %Y"; + } + else + { + short_date = "%m/%d/%Y"; + long_date = "%A, %B %d %Y"; + timestamp = "%a %b %d %Y"; + } + } - gSavedSettings.setString("ShortDateFormat", short_date); - gSavedSettings.setString("LongDateFormat", long_date); - gSavedSettings.setString("ShortTimeFormat", short_time); - gSavedSettings.setString("LongTimeFormat", long_time); - gSavedSettings.setString("TimestampFormat", timestamp); -} + if (tempTimeFormat != -1) + { + if (tempTimeFormat == 0) + { + short_time = "%R"; + long_time = "%T"; + if (!timestamp.empty()) timestamp += " %T"; + } + else + { + short_time = "%I:%M %p"; + long_time = "%I:%M:%S %p"; + if (!timestamp.empty()) timestamp += " %I:%M %p"; + } + } + else if (!timestamp.empty()) + { + timestamp += ' ' + gSavedSettings.getString("ShortTimeFormat"); + } -void LLPrefsAscentChat::onCommitEnableAS(const LLSD& value) -{ - bool enabled = value.asBoolean(); - childSetEnabled("spammsg_checkbox", enabled); - childSetEnabled("antispamtime", enabled); - childSetEnabled("antispamamount", enabled); - childSetEnabled("antispamsoundmulti", enabled); - childSetEnabled("antispamsoundpreloadmulti", enabled); - childSetEnabled("antispamnewlines", enabled); - childSetEnabled("Notify On Spam", enabled); + if (!short_date.empty()) + { + gSavedSettings.setString("ShortDateFormat", short_date); + gSavedSettings.setString("LongDateFormat", long_date); + } + if (!short_time.empty()) + { + gSavedSettings.setString("ShortTimeFormat", short_time); + gSavedSettings.setString("LongTimeFormat", long_time); + } + if (!timestamp.empty()) + gSavedSettings.setString("TimestampFormat", timestamp); } -void LLPrefsAscentChat::onCommitDialogBlock(LLUICtrl* ctrl, const LLSD& value) +void LLPrefsAscentChat::onCommitTimeDate(LLUICtrl* ctrl) { - childSetEnabled("Group Fee Invites", !childGetValue("antispam_checkbox").asBoolean() && !childGetValue("Group Invites").asBoolean()); - bool enabled = value.asBoolean(); - if (ctrl->getName() == "antispam_checkbox") + LLComboBox* combo = static_cast(ctrl); + if (ctrl->getName() == "time_format_combobox") { - childSetEnabled("Block All Dialogs From", !enabled); - childSetEnabled("Alerts", !enabled); - childSetEnabled("Friendship Offers", !enabled); - childSetEnabled("Group Invites", !enabled); - childSetEnabled("Group Notices", !enabled); - childSetEnabled("Item Offers", !enabled); - childSetEnabled("Scripts", !enabled); - childSetEnabled("Teleport Offers", !enabled); - childSetEnabled("Teleport Requests", !enabled); - childSetEnabled("Except those from:", !enabled); - childSetEnabled("My objects", !enabled); - childSetEnabled("My friends", !enabled); + tempTimeFormat = combo->getCurrentIndex(); + } + else if (ctrl->getName() == "date_format_combobox") + { + tempDateFormat = combo->getCurrentIndex(); } + + setTimeDateFormats(tempTimeFormat, tempDateFormat); } void LLPrefsAscentChat::onCommitKeywords(LLUICtrl* ctrl) @@ -260,28 +229,16 @@ void LLPrefsAscentChat::refreshValues() mSecondsInLog = gSavedSettings.getBOOL("SecondsInLog"); std::string format = gSavedSettings.getString("ShortTimeFormat"); - if (format.find("%p") == -1) - { - mTimeFormat = 0; - } - else - { - mTimeFormat = 1; - } + mTimeFormat = format == "%R" ? 0 + : format == "%I:%M %p" ? 1 + : -1; format = gSavedSettings.getString("ShortDateFormat"); - if (format.find("%m/%d/%") != -1) - { - mDateFormat = 2; - } - else if (format.find("%d/%m/%") != -1) - { - mDateFormat = 1; - } - else - { - mDateFormat = 0; - } + mDateFormat = format == "%F" ? 0 : + format == "%Y/%m/%d" ? 1 : + format == "%d/%m/%Y" ? 2 : + format == "%m/%d/%Y" ? 3 : + -1; tempTimeFormat = mTimeFormat; tempDateFormat = mDateFormat; @@ -296,31 +253,40 @@ void LLPrefsAscentChat::refreshValues() mOneLineGroupButt = gSavedSettings.getBOOL("UseConciseGroupChatButtons"); mOneLineConfButt = gSavedSettings.getBOOL("UseConciseConferenceButtons"); mOnlyComm = gSavedSettings.getBOOL("CommunicateSpecificShortcut"); + mLegacyEndScroll = gSavedSettings.getBOOL("LiruLegacyScrollToEnd"); mItalicizeActions = gSavedSettings.getBOOL("LiruItalicizeActions"); - mLegacySpeakerNames = gSavedSettings.getBOOL("LiruILegacySpeakerNames"); + mLegacyLogLaunch = gSavedSettings.getBOOL("LiruLegacyLogLaunch"); + mChatTabNames = gSavedSettings.getS32("IMNameSystem"); + mFriendNames = gSavedSettings.getS32("FriendNameSystem"); + mGroupMembersNames = gSavedSettings.getS32("GroupMembersNameSystem"); + mLandManagementNames = gSavedSettings.getS32("LandManagementNameSystem"); + mProfileNames = gSavedSettings.getS32("ProfileNameSystem"); + mRadarNames = gSavedSettings.getS32("RadarNameSystem"); + mSpeakerNames = gSavedSettings.getS32("SpeakerNameSystem"); //Autoresponse ------------------------------------------------------------------------ - mIMResponseAnyoneItemID = gSavedPerAccountSettings.getString("AutoresponseAnyoneItemID"); - mIMResponseNonFriendsItemID = gSavedPerAccountSettings.getString("AutoresponseNonFriendsItemID"); - mIMResponseMutedItemID = gSavedPerAccountSettings.getString("AutoresponseMutedItemID"); - mIMResponseBusyItemID = gSavedPerAccountSettings.getString("BusyModeResponseItemID"); - - gSavedPerAccountSettings.setBOOL("AscentInstantMessageResponseRepeat", childGetValue("AscentInstantMessageResponseRepeat")); - gSavedPerAccountSettings.setBOOL("AutoresponseAnyone", childGetValue("AutoresponseAnyone")); - gSavedPerAccountSettings.setBOOL("AutoresponseAnyoneFriendsOnly", childGetValue("AutoresponseAnyoneFriendsOnly")); - gSavedPerAccountSettings.setBOOL("AutoresponseAnyoneItem", childGetValue("AutoresponseAnyoneItem")); - gSavedPerAccountSettings.setString("AutoresponseAnyoneMessage", childGetValue("AutoresponseAnyoneMessage")); - gSavedPerAccountSettings.setBOOL("AutoresponseAnyoneShow", childGetValue("AutoresponseAnyoneShow")); - gSavedPerAccountSettings.setBOOL("AutoresponseNonFriends", childGetValue("AutoresponseNonFriends")); - gSavedPerAccountSettings.setBOOL("AutoresponseNonFriendsItem", childGetValue("AutoresponseNonFriendsItem")); - gSavedPerAccountSettings.setString("AutoresponseNonFriendsMessage", childGetValue("AutoresponseNonFriendsMessage")); - gSavedPerAccountSettings.setBOOL("AutoresponseNonFriendsShow", childGetValue("AutoresponseNonFriendsShow")); - gSavedPerAccountSettings.setBOOL("AutoresponseMuted", childGetValue("AutoresponseMuted")); - gSavedPerAccountSettings.setBOOL("AutoresponseMutedItem", childGetValue("AutoresponseMutedItem")); - gSavedPerAccountSettings.setString("AutoresponseMutedMessage", childGetValue("AutoresponseMutedMessage")); - gSavedPerAccountSettings.setString("BusyModeResponse", childGetValue("BusyModeResponse")); - gSavedPerAccountSettings.setBOOL("BusyModeResponseItem", childGetValue("BusyModeResponseItem")); - gSavedPerAccountSettings.setBOOL("BusyModeResponseShow", childGetValue("BusyModeResponseShow")); + mIMResponseRepeat = gSavedPerAccountSettings.getBOOL("AscentInstantMessageResponseRepeat"); + mIMResponseAway = gSavedPerAccountSettings.getBOOL("AutoresponseOnlyIfAway"); + mIMResponseAnyone = gSavedPerAccountSettings.getBOOL("AutoresponseAnyone"); + mIMResponseAnyoneFriends = gSavedPerAccountSettings.getBOOL("AutoresponseAnyoneFriendsOnly"); + mIMResponseAnyoneItem = gSavedPerAccountSettings.getBOOL("AutoresponseAnyoneItem"); + mIMResponseAnyoneItemID = gSavedPerAccountSettings.getString("AutoresponseAnyoneItemID"); + mIMResponseAnyoneMessage = gSavedPerAccountSettings.getString("AutoresponseAnyoneMessage"); + mIMResponseAnyoneShow = gSavedPerAccountSettings.getBOOL("AutoresponseAnyoneShow"); + mIMResponseNonFriends = gSavedPerAccountSettings.getBOOL("AutoresponseNonFriends"); + mIMResponseNonFriendsItem = gSavedPerAccountSettings.getBOOL("AutoresponseNonFriendsItem"); + mIMResponseNonFriendsItemID = gSavedPerAccountSettings.getString("AutoresponseNonFriendsItemID"); + mIMResponseNonFriendsMessage = gSavedPerAccountSettings.getString("AutoresponseNonFriendsMessage"); + mIMResponseNonFriendsShow = gSavedPerAccountSettings.getBOOL("AutoresponseNonFriendsShow"); + mIMResponseMuted = gSavedPerAccountSettings.getBOOL("AutoresponseMuted"); + mIMResponseMutedItem = gSavedPerAccountSettings.getBOOL("AutoresponseMutedItem"); + mIMResponseMutedItemID = gSavedPerAccountSettings.getString("AutoresponseMutedItemID"); + mIMResponseMutedMessage = gSavedPerAccountSettings.getString("AutoresponseMutedMessage"); + mIMResponseMutedShow = gSavedPerAccountSettings.getBOOL("AutoresponseMutedShow"); + mIMResponseBusyItem = gSavedPerAccountSettings.getBOOL("BusyModeResponseItem"); + mIMResponseBusyItemID = gSavedPerAccountSettings.getString("BusyModeResponseItemID"); + mIMResponseBusyMessage = gSavedPerAccountSettings.getString("BusyModeResponse"); + mIMResponseBusyShow = gSavedPerAccountSettings.getBOOL("BusyModeResponseShow"); //Spam -------------------------------------------------------------------------------- mEnableAS = gSavedSettings.getBOOL("AntiSpamEnabled"); @@ -360,89 +326,78 @@ void LLPrefsAscentChat::refreshValues() // Update controls based on current settings void LLPrefsAscentChat::refresh() { - //Chat -------------------------------------------------------------------------------- - // time format combobox - LLComboBox* combo = getChild("time_format_combobox"); - if (combo) - { - combo->setCurrentByIndex(mTimeFormat); - } + //Chat -------------------------------------------------------------------------------- + // time format combobox + if (mTimeFormat != -1) + { + if (auto combo = getChild("time_format_combobox")) + { + combo->setCurrentByIndex(mTimeFormat); + } + } - // date format combobox - combo = getChild("date_format_combobox"); - if (combo) - { - combo->setCurrentByIndex(mDateFormat); - } + // date format combobox + if (mDateFormat != -1) + { + if (auto combo = getChild("date_format_combobox")) + { + combo->setCurrentByIndex(mDateFormat); + } + } - //Antispam ------------------------------------------------------------------------ - // sensitivity tuners - childSetEnabled("spammsg_checkbox", mEnableAS); - childSetEnabled("antispamtime", mEnableAS); - childSetEnabled("antispamamount", mEnableAS); - childSetEnabled("antispamsoundmulti", mEnableAS); - childSetEnabled("antispamsoundpreloadmulti", mEnableAS); - childSetEnabled("antispamnewlines", mEnableAS); - childSetEnabled("Notify On Spam", mEnableAS); - // dialog blocking tuners - childSetEnabled("Block All Dialogs From", !mBlockDialogSpam); - childSetEnabled("Alerts", !mBlockDialogSpam); - childSetEnabled("Friendship Offers", !mBlockDialogSpam); - childSetEnabled("Group Invites", !mBlockDialogSpam); - childSetEnabled("Group Fee Invites", !mBlockDialogSpam && !mBlockGroupInviteSpam); - childSetEnabled("Group Notices", !mBlockDialogSpam); - childSetEnabled("Item Offers", !mBlockDialogSpam); - childSetEnabled("Scripts", !mBlockDialogSpam); - childSetEnabled("Teleport Offers", !mBlockDialogSpam); + //Chat UI ----------------------------------------------------------------------------- + if (auto combo = getChild("chat_tabs_namesystem_combobox")) + combo->setCurrentByIndex(mChatTabNames); + if (auto combo = getChild("friends_namesystem_combobox")) + combo->setCurrentByIndex(mFriendNames); + if (auto combo = getChild("group_members_namesystem_combobox")) + combo->setCurrentByIndex(mGroupMembersNames); + if (auto combo = getChild("land_management_namesystem_combobox")) + combo->setCurrentByIndex(mLandManagementNames); + if (auto combo = getChild("radar_namesystem_combobox")) + combo->setCurrentByIndex(mRadarNames); + if (auto combo = getChild("speaker_namesystem_combobox")) + combo->setCurrentByIndex(mSpeakerNames); //Text Options ------------------------------------------------------------------------ - combo = getChild("SpellBase"); - - if (combo != NULL) + if (auto combo = getChild("SpellBase")) { combo->removeall(); - std::vector names = glggHunSpell->getDicts(); - for (int i = 0; i < (int)names.size(); i++) + for (const auto& name : glggHunSpell->getDicts()) { - combo->add(names[i]); + combo->add(name); } combo->setSimple(gSavedSettings.getString("SpellBase")); } - combo = getChild("EmSpell_Avail"); - - if (combo != NULL) + if (auto combo = getChild("EmSpell_Avail")) { combo->removeall(); - combo->add(""); - std::vector names = glggHunSpell->getAvailDicts(); + combo->add(LLStringUtil::null); - for (int i = 0; i < (int)names.size(); i++) + for (const auto& name : glggHunSpell->getAvailDicts()) { - combo->add(names[i]); + combo->add(name); } - combo->setSimple(std::string("")); + combo->setSimple(LLStringUtil::null); } - combo = getChild("EmSpell_Installed"); - - if (combo != NULL) + if (auto combo = getChild("EmSpell_Installed")) { combo->removeall(); - combo->add(""); - std::vector names = glggHunSpell->getInstalledDicts(); + combo->add(LLStringUtil::null); - for (int i = 0; i < (int)names.size(); i++) + for (const auto& name : glggHunSpell->getInstalledDicts()) { - combo->add(names[i]); + combo->add(name); } - combo->setSimple(std::string("")); + combo->setSimple(LLStringUtil::null); } childSetEnabled("KeywordsList", mKeywordsOn); @@ -484,45 +439,7 @@ void LLPrefsAscentChat::cancel() gSavedSettings.setBOOL("SecondsInChatAndIMs", mSecondsInChatAndIMs); gSavedSettings.setBOOL("SecondsInLog", mSecondsInLog); - std::string short_date, long_date, short_time, long_time, timestamp; - - if (mTimeFormat == 0) - { - short_time = "%H:%M"; - long_time = "%H:%M:%S"; - timestamp = " %H:%M:%S"; - } - else - { - short_time = "%I:%M %p"; - long_time = "%I:%M:%S %p"; - timestamp = " %I:%M %p"; - } - - if (mDateFormat == 0) - { - short_date = "%Y-%m-%d"; - long_date = "%A %d %B %Y"; - timestamp = "%a %d %b %Y" + timestamp; - } - else if (mDateFormat == 1) - { - short_date = "%d/%m/%Y"; - long_date = "%A %d %B %Y"; - timestamp = "%a %d %b %Y" + timestamp; - } - else - { - short_date = "%m/%d/%Y"; - long_date = "%A, %B %d %Y"; - timestamp = "%a %b %d %Y" + timestamp; - } - - gSavedSettings.setString("ShortDateFormat", short_date); - gSavedSettings.setString("LongDateFormat", long_date); - gSavedSettings.setString("ShortTimeFormat", short_time); - gSavedSettings.setString("LongTimeFormat", long_time); - gSavedSettings.setString("TimestampFormat", timestamp); + setTimeDateFormats(mTimeFormat, mDateFormat); //Chat UI ----------------------------------------------------------------------------- gSavedSettings.setBOOL("WoLfVerticalIMTabs", mWoLfVerticalIMTabs); @@ -534,16 +451,42 @@ void LLPrefsAscentChat::cancel() gSavedSettings.setBOOL("UseConciseGroupChatButtons", mOneLineGroupButt); gSavedSettings.setBOOL("UseConciseConferenceButtons", mOneLineConfButt); gSavedSettings.setBOOL("CommunicateSpecificShortcut", mOnlyComm); + gSavedSettings.setBOOL("LiruLegacyScrollToEnd", mLegacyEndScroll); gSavedSettings.setBOOL("LiruItalicizeActions", mItalicizeActions); - gSavedSettings.setBOOL("LiruILegacySpeakerNames", mLegacySpeakerNames); + gSavedSettings.setBOOL("LiruLegacyLogLaunch", mLegacyLogLaunch); + gSavedSettings.setS32("IMNameSystem", mChatTabNames); + gSavedSettings.setS32("FriendNameSystem", mFriendNames); + gSavedSettings.setS32("GroupMembersNameSystem", mGroupMembersNames); + gSavedSettings.setS32("LandManagementNameSystem", mLandManagementNames); + gSavedSettings.setS32("ProfileNameSystem", mProfileNames); + gSavedSettings.setS32("RadarNameSystem", mRadarNames); + gSavedSettings.setS32("SpeakerNameSystem", mSpeakerNames); //Autoresponse ------------------------------------------------------------------------ - gSavedPerAccountSettings.setString("AutoresponseAnyoneItemID", mIMResponseAnyoneItemID); - gSavedPerAccountSettings.setString("AutoresponseNonFriendsItemID", mIMResponseNonFriendsItemID); - gSavedPerAccountSettings.setString("AutoresponseMutedItemID", mIMResponseMutedItemID); - gSavedPerAccountSettings.setString("BusyModeResponseItemID", mIMResponseBusyItemID); - - //Spam -------------------------------------------------------------------------------- + gSavedPerAccountSettings.setBOOL("AscentInstantMessageResponseRepeat", mIMResponseRepeat); + gSavedPerAccountSettings.setBOOL("AutoresponseOnlyIfAway", mIMResponseAway); + gSavedPerAccountSettings.setBOOL("AutoresponseAnyone", mIMResponseAnyone); + gSavedPerAccountSettings.setBOOL("AutoresponseAnyoneFriendsOnly", mIMResponseAnyoneFriends); + gSavedPerAccountSettings.setBOOL("AutoresponseAnyoneItem", mIMResponseAnyoneItem); + gSavedPerAccountSettings.setString("AutoresponseAnyoneItemID", mIMResponseAnyoneItemID); + gSavedPerAccountSettings.setString("AutoresponseAnyoneMessage", mIMResponseAnyoneMessage); + gSavedPerAccountSettings.setBOOL("AutoresponseAnyoneShow", mIMResponseAnyoneShow); + gSavedPerAccountSettings.setBOOL("AutoresponseNonFriends", mIMResponseNonFriends); + gSavedPerAccountSettings.setBOOL("AutoresponseNonFriendsItem", mIMResponseNonFriendsItem); + gSavedPerAccountSettings.setString("AutoresponseNonFriendsItemID", mIMResponseNonFriendsItemID); + gSavedPerAccountSettings.setString("AutoresponseNonFriendsMessage", mIMResponseNonFriendsMessage); + gSavedPerAccountSettings.setBOOL("AutoresponseNonFriendsShow", mIMResponseNonFriendsShow); + gSavedPerAccountSettings.setBOOL("AutoresponseMuted", mIMResponseMuted); + gSavedPerAccountSettings.setBOOL("AutoresponseMutedItem", mIMResponseMutedItem); + gSavedPerAccountSettings.setString("AutoresponseMutedItemID", mIMResponseMutedItemID); + gSavedPerAccountSettings.setString("AutoresponseMutedMessage", mIMResponseMutedMessage); + gSavedPerAccountSettings.setBOOL("AutoresponseMutedShow", mIMResponseMutedShow); + gSavedPerAccountSettings.setBOOL("BusyModeResponseItem", mIMResponseBusyItem); + gSavedPerAccountSettings.setString("BusyModeResponseItemID", mIMResponseBusyItemID); + gSavedPerAccountSettings.setString("BusyModeResponse", mIMResponseBusyMessage); + gSavedPerAccountSettings.setBOOL("BusyModeResponseShow", mIMResponseBusyShow); + + //Spam -------------------------------------------------------------------------------- gSavedSettings.setBOOL("AntiSpamEnabled", mEnableAS); gSavedSettings.setBOOL("_NACL_AntiSpamGlobalQueue", mGlobalQueue); gSavedSettings.setU32("_NACL_AntiSpamAmount", mChatSpamCount); diff --git a/indra/newview/ascentprefschat.h b/indra/newview/ascentprefschat.h index 5e0ecd707a..0f0dc9baaa 100644 --- a/indra/newview/ascentprefschat.h +++ b/indra/newview/ascentprefschat.h @@ -38,13 +38,13 @@ class LLPrefsAscentChat : public LLPanel { public: - LLPrefsAscentChat(); - ~LLPrefsAscentChat(); + LLPrefsAscentChat(); + ~LLPrefsAscentChat(); - void apply(); - void cancel(); - void refresh(); - void refreshValues(); + void apply(); + void cancel(); + void refresh(); + void refreshValues(); protected: void onSpellAdd(); @@ -52,30 +52,29 @@ class LLPrefsAscentChat : public LLPanel void onSpellEditCustom(); void onSpellBaseComboBoxCommit(const LLSD& value); void onCommitTimeDate(LLUICtrl* ctrl); - void onCommitEnableAS(const LLSD& value); - void onCommitDialogBlock(LLUICtrl* ctrl, const LLSD& value); void onCommitKeywords(LLUICtrl* ctrl); - //Chat/IM ----------------------------------------------------------------------------- - BOOL mIMAnnounceIncoming; - BOOL mHideTypingNotification; - bool mInstantMessagesFriendsOnly; - BOOL mShowGroupNameInChatIM; - bool mShowDisplayNameChanges; - bool mUseTypingBubbles; - BOOL mPlayTypingSound; - BOOL mHideNotificationsInChat; - BOOL mEnableMUPose; - BOOL mEnableOOCAutoClose; - U32 mLinksForChattingObjects; - U32 mTimeFormat; - U32 mDateFormat; - U32 tempTimeFormat; - U32 tempDateFormat; - BOOL mSecondsInChatAndIMs; - BOOL mSecondsInLog; +private: + //Chat/IM ----------------------------------------------------------------------------- + bool mIMAnnounceIncoming; + bool mHideTypingNotification; + bool mInstantMessagesFriendsOnly; + bool mShowGroupNameInChatIM; + bool mShowDisplayNameChanges; + bool mUseTypingBubbles; + bool mPlayTypingSound; + bool mHideNotificationsInChat; + bool mEnableMUPose; + bool mEnableOOCAutoClose; + U32 mLinksForChattingObjects; + S8 mTimeFormat; + S8 mDateFormat; + S8 tempTimeFormat; + S8 tempDateFormat; + bool mSecondsInChatAndIMs; + bool mSecondsInLog; - //Chat UI ----------------------------------------------------------------------------- + //Chat UI ----------------------------------------------------------------------------- bool mWoLfVerticalIMTabs; bool mOtherChatsTornOff; bool mIMAnnounceStealFocus; @@ -85,48 +84,74 @@ class LLPrefsAscentChat : public LLPanel bool mOneLineGroupButt; bool mOneLineConfButt; bool mOnlyComm; + bool mLegacyEndScroll; bool mItalicizeActions; - bool mLegacySpeakerNames; + bool mLegacyLogLaunch; + S32 mChatTabNames; + S32 mFriendNames; + S32 mGroupMembersNames; + S32 mLandManagementNames; + S32 mProfileNames; + S32 mRadarNames; + S32 mSpeakerNames; //Autoresponse ------------------------------------------------------------------------ + bool mIMResponseRepeat; + bool mIMResponseAway; + bool mIMResponseAnyone; + bool mIMResponseAnyoneFriends; + bool mIMResponseAnyoneItem; std::string mIMResponseAnyoneItemID; + std::string mIMResponseAnyoneMessage; + bool mIMResponseAnyoneShow; + bool mIMResponseNonFriends; + bool mIMResponseNonFriendsItem; std::string mIMResponseNonFriendsItemID; + std::string mIMResponseNonFriendsMessage; + bool mIMResponseNonFriendsShow; + bool mIMResponseMuted; + bool mIMResponseMutedItem; std::string mIMResponseMutedItemID; + std::string mIMResponseMutedMessage; + bool mIMResponseMutedShow; + bool mIMResponseBusyItem; std::string mIMResponseBusyItemID; + std::string mIMResponseBusyMessage; + bool mIMResponseBusyShow; - //Spam -------------------------------------------------------------------------------- - BOOL mEnableAS; - BOOL mGlobalQueue; - U32 mChatSpamCount; - U32 mChatSpamTime; - BOOL mBlockDialogSpam; - BOOL mBlockAlertSpam; - BOOL mBlockFriendSpam; - BOOL mBlockGroupNoticeSpam; - BOOL mBlockGroupInviteSpam; - BOOL mBlockGroupFeeInviteSpam; - BOOL mBlockItemOfferSpam; + //Spam -------------------------------------------------------------------------------- + bool mEnableAS; + bool mGlobalQueue; + U32 mChatSpamCount; + U32 mChatSpamTime; + bool mBlockDialogSpam; + bool mBlockAlertSpam; + bool mBlockFriendSpam; + bool mBlockGroupNoticeSpam; + bool mBlockGroupInviteSpam; + bool mBlockGroupFeeInviteSpam; + bool mBlockItemOfferSpam; bool mBlockNotMineSpam; bool mBlockNotFriendSpam; - BOOL mBlockScriptSpam; - BOOL mBlockTeleportSpam; + bool mBlockScriptSpam; + bool mBlockTeleportSpam; bool mBlockTeleportRequestSpam; - BOOL mNotifyOnSpam; - BOOL mSoundMulti; - U32 mNewLines; - U32 mPreloadMulti; + bool mNotifyOnSpam; + bool mSoundMulti; + U32 mNewLines; + U32 mPreloadMulti; bool mEnableGestureSounds; - //Text Options ------------------------------------------------------------------------ - BOOL mSpellDisplay; - BOOL mKeywordsOn; - std::string mKeywordsList; - BOOL mKeywordsInChat; - BOOL mKeywordsInIM; - BOOL mKeywordsChangeColor; - LLColor4 mKeywordsColor; - BOOL mKeywordsPlaySound; - LLUUID mKeywordsSound; + //Text Options ------------------------------------------------------------------------ + bool mSpellDisplay; + bool mKeywordsOn; + std::string mKeywordsList; + bool mKeywordsInChat; + bool mKeywordsInIM; + bool mKeywordsChangeColor; + LLColor4 mKeywordsColor; + bool mKeywordsPlaySound; + LLUUID mKeywordsSound; }; #endif diff --git a/indra/newview/ascentprefssys.cpp b/indra/newview/ascentprefssys.cpp index d4d25fcbcd..2b530ad727 100644 --- a/indra/newview/ascentprefssys.cpp +++ b/indra/newview/ascentprefssys.cpp @@ -51,37 +51,36 @@ LLPrefsAscentSys::LLPrefsAscentSys() LLUICtrlFactory::getInstance()->buildPanel(this, "panel_preferences_ascent_system.xml"); //General ----------------------------------------------------------------------------- - getChild("speed_rez_check")->setCommitCallback(boost::bind(&LLPrefsAscentSys::onCommitCheckBox, this, _1, _2)); - getChild("double_click_teleport_check")->setCommitCallback(boost::bind(&LLPrefsAscentSys::onCommitCheckBox, this, _1, _2)); getChild("show_look_at_check")->setCommitCallback(boost::bind(&LLPrefsAscentSys::onCommitCheckBox, this, _1, _2)); - getChild("enable_clouds")->setCommitCallback(boost::bind(&LLPrefsAscentSys::onCommitCheckBox, this, _1, _2)); getChild("power_user_check")->setCommitCallback(boost::bind(&LLPrefsAscentSys::onCommitCheckBox, this, _1, _2)); getChild("power_user_confirm_check")->setCommitCallback(boost::bind(&LLPrefsAscentSys::onCommitCheckBox, this, _1, _2)); //Command Line ------------------------------------------------------------------------ - getChild("chat_cmd_toggle")->setCommitCallback(boost::bind(&LLPrefsAscentSys::onCommitCmdLine, this, _1, _2)); - getChild("AscentCmdLinePos")->setCommitCallback(boost::bind(&LLPrefsAscentSys::onCommitCmdLine, this, _1, _2)); - getChild("AscentCmdLineGround")->setCommitCallback(boost::bind(&LLPrefsAscentSys::onCommitCmdLine, this, _1, _2)); - getChild("AscentCmdLineHeight")->setCommitCallback(boost::bind(&LLPrefsAscentSys::onCommitCmdLine, this, _1, _2)); - getChild("AscentCmdLineTeleportHome")->setCommitCallback(boost::bind(&LLPrefsAscentSys::onCommitCmdLine, this, _1, _2)); - getChild("AscentCmdLineRezPlatform")->setCommitCallback(boost::bind(&LLPrefsAscentSys::onCommitCmdLine, this, _1, _2)); - getChild("AscentCmdLineCalc")->setCommitCallback(boost::bind(&LLPrefsAscentSys::onCommitCmdLine, this, _1, _2)); - getChild("AscentCmdLineClearChat")->setCommitCallback(boost::bind(&LLPrefsAscentSys::onCommitCmdLine, this, _1, _2)); - getChild("AscentCmdLineDrawDistance")->setCommitCallback(boost::bind(&LLPrefsAscentSys::onCommitCmdLine, this, _1, _2)); - getChild("AscentCmdTeleportToCam")->setCommitCallback(boost::bind(&LLPrefsAscentSys::onCommitCmdLine, this, _1, _2)); - getChild("AscentCmdLineKeyToName")->setCommitCallback(boost::bind(&LLPrefsAscentSys::onCommitCmdLine, this, _1, _2)); - getChild("AscentCmdLineOfferTp")->setCommitCallback(boost::bind(&LLPrefsAscentSys::onCommitCmdLine, this, _1, _2)); - getChild("AscentCmdLineMapTo")->setCommitCallback(boost::bind(&LLPrefsAscentSys::onCommitCmdLine, this, _1, _2)); - getChild("AscentCmdLineTP2")->setCommitCallback(boost::bind(&LLPrefsAscentSys::onCommitCmdLine, this, _1, _2)); - getChild("SinguCmdLineAway")->setCommitCallback(boost::bind(&LLPrefsAscentSys::onCommitCmdLine, this, _1, _2)); - getChild("SinguCmdLineURL")->setCommitCallback(boost::bind(&LLPrefsAscentSys::onCommitCmdLine, this, _1, _2)); + commit_callback_t lineEditorControl(boost::bind(&LLControlGroup::setString, boost::ref(gSavedSettings), boost::bind(&LLUICtrl::getName, _1), _2)); + getChild("AscentCmdLinePos")->setCommitCallback(lineEditorControl); + getChild("AscentCmdLineGround")->setCommitCallback(lineEditorControl); + getChild("AscentCmdLineHeight")->setCommitCallback(lineEditorControl); + getChild("AscentCmdLineTeleportHome")->setCommitCallback(lineEditorControl); + getChild("AscentCmdLineRezPlatform")->setCommitCallback(lineEditorControl); + getChild("AscentCmdLineCalc")->setCommitCallback(lineEditorControl); + getChild("AscentCmdLineClearChat")->setCommitCallback(lineEditorControl); + getChild("AscentCmdLineDrawDistance")->setCommitCallback(lineEditorControl); + getChild("AscentCmdTeleportToCam")->setCommitCallback(lineEditorControl); + getChild("AscentCmdLineKeyToName")->setCommitCallback(lineEditorControl); + getChild("AscentCmdLineOfferTp")->setCommitCallback(lineEditorControl); + getChild("AscentCmdLineMapTo")->setCommitCallback(lineEditorControl); + getChild("AscentCmdLineTP2")->setCommitCallback(lineEditorControl); + getChild("SinguCmdLineAway")->setCommitCallback(lineEditorControl); + getChild("SinguCmdLineRegionSay")->setCommitCallback(lineEditorControl); + getChild("SinguCmdLineURL")->setCommitCallback(lineEditorControl); + getChild("AlchemyChatCommandResyncAnim")->setCommitCallback(lineEditorControl); + getChild("AlchemyChatCommandHoverHeight")->setCommitCallback(lineEditorControl); //Security ---------------------------------------------------------------------------- - getChild("disable_click_sit_check")->setCommitCallback(boost::bind(&LLPrefsAscentSys::onCommitCheckBox, this, _1, _2)); //Build ------------------------------------------------------------------------------- getChild("next_owner_copy")->setCommitCallback(boost::bind(&LLPrefsAscentSys::onCommitCheckBox, this, _1, _2)); - childSetEnabled("next_owner_transfer", gSavedSettings.getBOOL("NextOwnerCopy")); + getChild("script_next_owner_copy")->setCommitCallback(boost::bind(&LLPrefsAscentSys::onCommitCheckBox, this, _1, _2)); getChild("material")->setCommitCallback(boost::bind(&LLPrefsAscentSys::onCommitComboBox, this, _1, _2)); getChild("combobox shininess")->setCommitCallback(boost::bind(&LLPrefsAscentSys::onCommitComboBox, this, _1, _2)); getChild("texture control")->setDefaultImageAssetID(LLUUID(gSavedSettings.getString("EmeraldBuildPrefs_Texture"))); @@ -97,25 +96,11 @@ LLPrefsAscentSys::~LLPrefsAscentSys() void LLPrefsAscentSys::onCommitCheckBox(LLUICtrl* ctrl, const LLSD& value) { -// llinfos << "Change to " << ctrl->getControlName() << " aka " << ctrl->getName() << llendl; +// LL_INFOS() << "Change to " << ctrl->getControlName() << " aka " << ctrl->getName() << LL_ENDL; const std::string name = ctrl->getName(); bool enabled = value.asBoolean(); - if (name == "speed_rez_check") - { - childSetEnabled("speed_rez_interval", enabled); - childSetEnabled("speed_rez_seconds", enabled); - } - else if (name == "double_click_teleport_check") - { - childSetEnabled("center_after_teleport_check", enabled); - childSetEnabled("offset_teleport_check", enabled); - } - else if (name == "enable_clouds") - { - childSetEnabled("enable_classic_clouds", enabled); - } - else if (name == "power_user_check") + if (name == "power_user_check") { childSetEnabled("power_user_confirm_check", enabled); childSetValue("power_user_confirm_check", false); @@ -127,64 +112,19 @@ void LLPrefsAscentSys::onCommitCheckBox(LLUICtrl* ctrl, const LLSD& value) if (enabled) { LLVector3d lpos_global = gAgent.getPositionGlobal(); - gAudiop->triggerSound(LLUUID("58a38e89-44c6-c52b-deb8-9f1ddc527319"), gAgent.getID(), 1.0f, LLAudioEngine::AUDIO_TYPE_UI, lpos_global); - LLChat chat; - chat.mSourceType = CHAT_SOURCE_SYSTEM; - chat.mText = LLTrans::getString("PowerUser1") + "\n" + LLTrans::getString("PowerUser2") + "\n" + LLTrans::getString("Unlocked:") + "\n" + LLTrans::getString("PowerUser3") + "\n- " + LLTrans::getString("RightClick") + " > " + LLTrans::getString("PowerUser4") + "\n- " + LLTrans::getString("RightClick") + " > " + LLTrans::getString("PowerUser5"); - LLFloaterChat::addChat(chat); + if(gAudiop) + gAudiop->triggerSound(LLUUID("58a38e89-44c6-c52b-deb8-9f1ddc527319"), gAgent.getID(), 1.0f, LLAudioEngine::AUDIO_TYPE_UI, lpos_global); + void cmdline_printchat(const std::string& message); + cmdline_printchat(LLTrans::getString("PowerUser1") + '\n' + LLTrans::getString("PowerUser2") + '\n' + LLTrans::getString("Unlocked:") + '\n' + LLTrans::getString("PowerUser3") + "\n- " + LLTrans::getString("RightClick") + " > " + LLTrans::getString("PowerUser4") + "\n- " + LLTrans::getString("RightClick") + " > " + LLTrans::getString("PowerUser5")); } } - else if (name == "disable_click_sit_check") - { - childSetEnabled("disable_click_sit_own_check", !enabled); - } else if (name == "next_owner_copy") { - if (!enabled) gSavedSettings.setBOOL("NextOwnerTransfer", true); - childSetEnabled("next_owner_transfer", enabled); + if (!enabled) gSavedSettings.setBOOL("ObjectsNextOwnerTransfer", true); } -} - -void LLPrefsAscentSys::onCommitCmdLine(LLUICtrl* ctrl, const LLSD& value) -{ - const std::string& name = ctrl->getName(); - if (name == "chat_cmd_toggle") - { - bool enabled = value.asBoolean(); - childSetEnabled("cmd_line_text_2", enabled); - childSetEnabled("cmd_line_text_3", enabled); - childSetEnabled("cmd_line_text_4", enabled); - childSetEnabled("cmd_line_text_5", enabled); - childSetEnabled("cmd_line_text_6", enabled); - childSetEnabled("cmd_line_text_7", enabled); - childSetEnabled("cmd_line_text_8", enabled); - childSetEnabled("cmd_line_text_9", enabled); - childSetEnabled("cmd_line_text_10", enabled); - childSetEnabled("cmd_line_text_11", enabled); - childSetEnabled("cmd_line_text_12", enabled); - childSetEnabled("cmd_line_text_13", enabled); - childSetEnabled("cmd_line_text_15", enabled); - childSetEnabled("AscentCmdLinePos", enabled); - childSetEnabled("AscentCmdLineGround", enabled); - childSetEnabled("AscentCmdLineHeight", enabled); - childSetEnabled("AscentCmdLineTeleportHome", enabled); - childSetEnabled("AscentCmdLineRezPlatform", enabled); - childSetEnabled("AscentPlatformSize", enabled); - childSetEnabled("AscentCmdLineCalc", enabled); - childSetEnabled("AscentCmdLineClearChat", enabled); - childSetEnabled("AscentCmdLineDrawDistance", enabled); - childSetEnabled("AscentCmdTeleportToCam", enabled); - childSetEnabled("AscentCmdLineKeyToName", enabled); - childSetEnabled("AscentCmdLineOfferTp", enabled); - childSetEnabled("AscentCmdLineMapTo", enabled); - childSetEnabled("map_to_keep_pos", enabled); - childSetEnabled("AscentCmdLineTP2", enabled); - childSetEnabled("SinguCmdLineAway", enabled); - childSetEnabled("SinguCmdLineURL", enabled); - } - else + else if (name == "script_next_owner_copy") { - gSavedSettings.setString(name, value); // Singu Note: Keep commandline settings using the same name as their settings + if (!enabled) gSavedSettings.setBOOL("ScriptsNextOwnerTransfer", true); } } @@ -203,6 +143,7 @@ void LLPrefsAscentSys::refreshValues() { //General ----------------------------------------------------------------------------- mDoubleClickTeleport = gSavedSettings.getBOOL("DoubleClickTeleport"); + mDoubleClickAutoPilot = gSavedSettings.getBOOL("DoubleClickAutoPilot"); mResetCameraAfterTP = gSavedSettings.getBOOL("OptionRotateCamAfterLocalTP"); mOffsetTPByUserHeight = gSavedSettings.getBOOL("OptionOffsetTPByAgentHeight"); mClearBeaconAfterTeleport = gSavedSettings.getBOOL("ClearBeaconAfterTeleport"); @@ -221,6 +162,7 @@ void LLPrefsAscentSys::refreshValues() mEnableClassicClouds = gSavedSettings.getBOOL("SkyUseClassicClouds"); mSpeedRez = gSavedSettings.getBOOL("SpeedRez"); mSpeedRezInterval = gSavedSettings.getU32("SpeedRezInterval"); + mUseContextMenus = gSavedSettings.getBOOL("LiruUseContextMenus"); mUseWebProfiles = gSavedSettings.getBOOL("UseWebProfiles"); mUseWebSearch = gSavedSettings.getBOOL("UseWebSearch"); @@ -242,20 +184,32 @@ void LLPrefsAscentSys::refreshValues() mCmdMapToKeepPos = gSavedSettings.getBOOL("AscentMapToKeepPos"); mCmdLineTP2 = gSavedSettings.getString("AscentCmdLineTP2"); mCmdLineAway = gSavedSettings.getString("SinguCmdLineAway"); + mCmdLineRegionSay = gSavedSettings.getString("SinguCmdLineRegionSay"); mCmdLineURL = gSavedSettings.getString("SinguCmdLineURL"); + mCmdLineResync = gSavedSettings.getString("AlchemyChatCommandResyncAnim"); + mCmdLineHover = gSavedSettings.getString("AlchemyChatCommandHoverHeight"); //Security ---------------------------------------------------------------------------- mBroadcastViewerEffects = gSavedSettings.getBOOL("BroadcastViewerEffects"); mDisablePointAtAndBeam = gSavedSettings.getBOOL("DisablePointAtAndBeam"); mPrivateLookAt = gSavedSettings.getBOOL("PrivateLookAt"); + mHideOwnLookAt = gSavedSettings.getBOOL("AlchemyLookAtHideSelf"); mShowLookAt = gSavedSettings.getBOOL("AscentShowLookAt"); + mLookAtNames = gSavedSettings.getS32("LookAtNameSystem"); + mLookAtLines = gSavedSettings.getBOOL("AlchemyLookAtLines"); mQuietSnapshotsToDisk = gSavedSettings.getBOOL("QuietSnapshotsToDisk"); + mAnnounceBumps = gSavedSettings.getBOOL("AnnounceBumps"); + mSitOnAway = gSavedSettings.getBOOL("AlchemySitOnAway"); mDetachBridge = gSavedSettings.getBOOL("SGDetachBridge"); mRevokePermsOnStandUp = gSavedSettings.getBOOL("RevokePermsOnStandUp"); mDisableClickSit = gSavedSettings.getBOOL("DisableClickSit"); mDisableClickSitOtherOwner = gSavedSettings.getBOOL("DisableClickSitOtherOwner"); mDisplayScriptJumps = gSavedSettings.getBOOL("AscentDisplayTotalScriptJumps"); mNumScriptDiff = gSavedSettings.getF32("Ascentnumscriptdiff"); + mReplaceLinks = gSavedSettings.getBOOL("SinguReplaceLinks"); + mEmergencySeconds = gSavedPerAccountSettings.getU32("EmergencyTeleportSeconds"); + mLandmark = gSavedPerAccountSettings.getString("EmergencyTeleportLandmark"); + mLandmarkBackup = gSavedPerAccountSettings.getString("EmergencyTeleportLandmarkBackup"); //Build ------------------------------------------------------------------------------- mAlpha = gSavedSettings.getF32("EmeraldBuildPrefs_Alpha"); @@ -264,9 +218,12 @@ void LLPrefsAscentSys::refreshValues() mGlow = gSavedSettings.getF32("EmeraldBuildPrefs_Glow"); mItem = gSavedPerAccountSettings.getString("EmeraldBuildPrefs_Item"); mMaterial = gSavedSettings.getString("BuildPrefs_Material"); - mNextCopy = gSavedSettings.getBOOL("NextOwnerCopy"); - mNextMod = gSavedSettings.getBOOL("NextOwnerModify"); - mNextTrans = gSavedSettings.getBOOL("NextOwnerTransfer"); + mNextCopy = gSavedSettings.getBOOL("ObjectsNextOwnerCopy"); + mNextMod = gSavedSettings.getBOOL("ObjectsNextOwnerModify"); + mNextTrans = gSavedSettings.getBOOL("ObjectsNextOwnerTransfer"); + mScriptNextCopy = gSavedSettings.getBOOL("ScriptsNextOwnerCopy"); + mScriptNextMod = gSavedSettings.getBOOL("ScriptsNextOwnerModify"); + mScriptNextTrans = gSavedSettings.getBOOL("ScriptsNextOwnerTransfer"); mShiny = gSavedSettings.getString("EmeraldBuildPrefs_Shiny"); mTemporary = gSavedSettings.getBOOL("EmeraldBuildPrefs_Temporary"); mTexture = gSavedSettings.getString("EmeraldBuildPrefs_Texture"); @@ -280,46 +237,14 @@ void LLPrefsAscentSys::refreshValues() void LLPrefsAscentSys::refresh() { //General ----------------------------------------------------------------------------- - childSetEnabled("center_after_teleport_check", mDoubleClickTeleport); - childSetEnabled("offset_teleport_check", mDoubleClickTeleport); childSetValue("power_user_check", mPowerUser); - childSetValue("power_user_confirm_check", mPowerUser); - childSetEnabled("speed_rez_interval", mSpeedRez); - childSetEnabled("speed_rez_seconds", mSpeedRez); - - //Command Line ------------------------------------------------------------------------ - childSetEnabled("cmd_line_text_2", mCmdLine); - childSetEnabled("cmd_line_text_3", mCmdLine); - childSetEnabled("cmd_line_text_4", mCmdLine); - childSetEnabled("cmd_line_text_5", mCmdLine); - childSetEnabled("cmd_line_text_6", mCmdLine); - childSetEnabled("cmd_line_text_7", mCmdLine); - childSetEnabled("cmd_line_text_8", mCmdLine); - childSetEnabled("cmd_line_text_9", mCmdLine); - childSetEnabled("cmd_line_text_10", mCmdLine); - childSetEnabled("cmd_line_text_11", mCmdLine); - childSetEnabled("cmd_line_text_12", mCmdLine); - childSetEnabled("cmd_line_text_13", mCmdLine); - childSetEnabled("cmd_line_text_15", mCmdLine); - childSetEnabled("AscentCmdLinePos", mCmdLine); - childSetEnabled("AscentCmdLineGround", mCmdLine); - childSetEnabled("AscentCmdLineHeight", mCmdLine); - childSetEnabled("AscentCmdLineTeleportHome", mCmdLine); - childSetEnabled("AscentCmdLineRezPlatform", mCmdLine); - childSetEnabled("AscentPlatformSize", mCmdLine); - childSetEnabled("AscentCmdLineCalc", mCmdLine); - childSetEnabled("AscentCmdLineClearChat", mCmdLine); - childSetEnabled("AscentCmdLineDrawDistance", mCmdLine); - childSetEnabled("AscentCmdTeleportToCam", mCmdLine); - childSetEnabled("AscentCmdLineKeyToName", mCmdLine); - childSetEnabled("AscentCmdLineOfferTp", mCmdLine); - childSetEnabled("AscentCmdLineMapTo", mCmdLine); - childSetEnabled("map_to_keep_pos", mCmdLine); - childSetEnabled("AscentCmdLineTP2", mCmdLine); - childSetEnabled("SinguCmdLineAway", mCmdLine); - childSetEnabled("SinguCmdLineURL", mCmdLine); + if (LLUICtrl* ctrl = getChild("power_user_confirm_check")) + { + ctrl->setEnabled(mPowerUser); + ctrl->setValue(mPowerUser); + } - //Security ---------------------------------------------------------------------------- + //Command Line ---------------------------------------------------------------------------- childSetValue("AscentCmdLinePos", mCmdLinePos); childSetValue("AscentCmdLineGround", mCmdLineGround); childSetValue("AscentCmdLineHeight", mCmdLineHeight); @@ -334,7 +259,14 @@ void LLPrefsAscentSys::refresh() childSetValue("AscentCmdLineMapTo", mCmdLineMapTo); childSetValue("AscentCmdLineTP2", mCmdLineTP2); childSetValue("SinguCmdLineAway", mCmdLineAway); + childSetValue("SinguCmdLineRegionSay", mCmdLineRegionSay); childSetValue("SinguCmdLineURL", mCmdLineURL); + childSetValue("AlchemyChatCommandResyncAnim", mCmdLineResync); + childSetValue("AlchemyChatCommandHoverHeight", mCmdLineHover); + + //Security ---------------------------------------------------------------------------- + if (LLComboBox* combo = getChild("lookat_namesystem_combobox")) + combo->setValue(mLookAtNames); //Build ------------------------------------------------------------------------------- childSetValue("alpha", mAlpha); @@ -359,6 +291,7 @@ void LLPrefsAscentSys::cancel() { //General ----------------------------------------------------------------------------- gSavedSettings.setBOOL("DoubleClickTeleport", mDoubleClickTeleport); + gSavedSettings.setBOOL("DoubleClickAutoPilot", mDoubleClickAutoPilot); gSavedSettings.setBOOL("OptionRotateCamAfterLocalTP", mResetCameraAfterTP); gSavedSettings.setBOOL("OptionOffsetTPByAgentHeight", mOffsetTPByUserHeight); gSavedSettings.setBOOL("ClearBeaconAfterTeleport", mClearBeaconAfterTeleport); @@ -376,6 +309,7 @@ void LLPrefsAscentSys::cancel() gSavedSettings.setBOOL("SkyUseClassicClouds", mEnableClassicClouds); gSavedSettings.setBOOL("SpeedRez", mSpeedRez); gSavedSettings.setU32("SpeedRezInterval", mSpeedRezInterval); + gSavedSettings.setBOOL("LiruUseContextMenus", mUseContextMenus); gSavedSettings.setBOOL("UseWebProfiles", mUseWebProfiles); gSavedSettings.setBOOL("UseWebSearch", mUseWebSearch); @@ -397,20 +331,32 @@ void LLPrefsAscentSys::cancel() gSavedSettings.setBOOL("AscentMapToKeepPos", mCmdMapToKeepPos); gSavedSettings.setString("AscentCmdLineTP2", mCmdLineTP2); gSavedSettings.setString("SinguCmdLineAway", mCmdLineAway); + gSavedSettings.setString("SinguCmdLineRegionSay", mCmdLineRegionSay); gSavedSettings.setString("SinguCmdLineURL", mCmdLineURL); + gSavedSettings.setString("AlchemyChatCommandResyncAnim", mCmdLineResync); + gSavedSettings.setString("AlchemyChatCommandHoverHeight", mCmdLineHover); //Security ---------------------------------------------------------------------------- gSavedSettings.setBOOL("BroadcastViewerEffects", mBroadcastViewerEffects); gSavedSettings.setBOOL("DisablePointAtAndBeam", mDisablePointAtAndBeam); gSavedSettings.setBOOL("PrivateLookAt", mPrivateLookAt); + gSavedSettings.setBOOL("AlchemyLookAtHideSelf", mHideOwnLookAt); gSavedSettings.setBOOL("AscentShowLookAt", mShowLookAt); + gSavedSettings.setS32("LookAtNameSystem", mLookAtNames); + gSavedSettings.setBOOL("AlchemyLookAtLines", mLookAtLines); gSavedSettings.setBOOL("QuietSnapshotsToDisk", mQuietSnapshotsToDisk); + gSavedSettings.setBOOL("AnnounceBumps", mAnnounceBumps); + gSavedSettings.setBOOL("AlchemySitOnAway", mSitOnAway); gSavedSettings.setBOOL("SGDetachBridge", mDetachBridge); gSavedSettings.setBOOL("RevokePermsOnStandUp", mRevokePermsOnStandUp); gSavedSettings.setBOOL("DisableClickSit", mDisableClickSit); gSavedSettings.setBOOL("DisableClickSitOtherOwner", mDisableClickSitOtherOwner); gSavedSettings.setBOOL("AscentDisplayTotalScriptJumps", mDisplayScriptJumps); gSavedSettings.setF32("Ascentnumscriptdiff", mNumScriptDiff); + gSavedSettings.setBOOL("SinguReplaceLinks", mReplaceLinks); + gSavedPerAccountSettings.setU32("EmergencyTeleportSeconds", mEmergencySeconds); + gSavedPerAccountSettings.setString("EmergencyTeleportLandmark", mLandmark); + gSavedPerAccountSettings.setString("EmergencyTeleportLandmarkBackup", mLandmarkBackup); //Build ------------------------------------------------------------------------------- gSavedSettings.setF32("EmeraldBuildPrefs_Alpha", mAlpha); @@ -419,9 +365,12 @@ void LLPrefsAscentSys::cancel() gSavedSettings.setF32("EmeraldBuildPrefs_Glow", mGlow); gSavedPerAccountSettings.setString("EmeraldBuildPrefs_Item", mItem); gSavedSettings.setString("BuildPrefs_Material", mMaterial); - gSavedSettings.setBOOL("NextOwnerCopy", mNextCopy); - gSavedSettings.setBOOL("NextOwnerModify", mNextMod); - gSavedSettings.setBOOL("NextOwnerTransfer", mNextTrans); + gSavedSettings.setBOOL("ObjectsNextOwnerCopy", mNextCopy); + gSavedSettings.setBOOL("ObjectsNextOwnerModify", mNextMod); + gSavedSettings.setBOOL("ObjectsNextOwnerTransfer", mNextTrans); + gSavedSettings.setBOOL("ScriptsNextOwnerCopy", mScriptNextCopy); + gSavedSettings.setBOOL("ScriptsNextOwnerModify", mScriptNextMod); + gSavedSettings.setBOOL("ScriptsNextOwnerTransfer", mScriptNextTrans); gSavedSettings.setBOOL("EmeraldBuildPrefs_Phantom", mPhantom); gSavedSettings.setBOOL("EmeraldBuildPrefs_Physical", mPhysical); gSavedSettings.setString("EmeraldBuildPrefs_Shiny", mShiny); diff --git a/indra/newview/ascentprefssys.h b/indra/newview/ascentprefssys.h index 701a8e5820..1c357750e5 100644 --- a/indra/newview/ascentprefssys.h +++ b/indra/newview/ascentprefssys.h @@ -38,75 +38,89 @@ class LLPrefsAscentSys : public LLPanel { public: - LLPrefsAscentSys(); - ~LLPrefsAscentSys(); + LLPrefsAscentSys(); + ~LLPrefsAscentSys(); - void apply(); - void cancel(); - void refresh(); - void refreshValues(); + void apply(); + void cancel(); + void refresh(); + void refreshValues(); protected: void onCommitCheckBox(LLUICtrl* ctrl, const LLSD& value); - void onCommitCmdLine(LLUICtrl* ctrl, const LLSD& value); void onCommitComboBox(LLUICtrl* ctrl, const LLSD& value); void onCommitTexturePicker(LLUICtrl* ctrl); - //General ----------------------------------------------------------------------------- - BOOL mDoubleClickTeleport; - BOOL mResetCameraAfterTP; - BOOL mOffsetTPByUserHeight; - bool mClearBeaconAfterTeleport; - bool mLiruFlyAfterTeleport; - bool mLiruContinueFlying; - BOOL mPreviewAnimInWorld; - BOOL mSaveScriptsAsMono; - BOOL mAlwaysRezInGroup; - BOOL mBuildAlwaysEnabled; - BOOL mAlwaysShowFly; - BOOL mDisableMinZoom; - BOOL mPowerUser; - BOOL mFetchInventoryOnLogin; - BOOL mEnableLLWind; - BOOL mEnableClouds; - BOOL mEnableClassicClouds; - BOOL mSpeedRez; - U32 mSpeedRezInterval; +private: + //General ----------------------------------------------------------------------------- + bool mDoubleClickTeleport; + bool mDoubleClickAutoPilot; + bool mResetCameraAfterTP; + bool mOffsetTPByUserHeight; + bool mClearBeaconAfterTeleport; + bool mLiruFlyAfterTeleport; + bool mLiruContinueFlying; + bool mPreviewAnimInWorld; + bool mSaveScriptsAsMono; + bool mAlwaysRezInGroup; + bool mBuildAlwaysEnabled; + bool mAlwaysShowFly; + bool mDisableMinZoom; + bool mPowerUser; + bool mFetchInventoryOnLogin; + bool mEnableLLWind; + bool mEnableClouds; + bool mEnableClassicClouds; + bool mSpeedRez; + U32 mSpeedRezInterval; + bool mUseContextMenus; bool mUseWebProfiles; bool mUseWebSearch; - //Command Line ------------------------------------------------------------------------ - BOOL mCmdLine; - std::string mCmdLinePos; - std::string mCmdLineGround; - std::string mCmdLineHeight; - std::string mCmdLineTeleportHome; - std::string mCmdLineRezPlatform; - F32 mCmdPlatformSize; - std::string mCmdLineCalc; - std::string mCmdLineClearChat; - std::string mCmdLineDrawDistance; - std::string mCmdTeleportToCam; - std::string mCmdLineKeyToName; - std::string mCmdLineOfferTp; - std::string mCmdLineMapTo; - BOOL mCmdMapToKeepPos; - std::string mCmdLineTP2; - std::string mCmdLineAway; + //Command Line ------------------------------------------------------------------------ + bool mCmdLine; + std::string mCmdLinePos; + std::string mCmdLineGround; + std::string mCmdLineHeight; + std::string mCmdLineTeleportHome; + std::string mCmdLineRezPlatform; + F32 mCmdPlatformSize; + std::string mCmdLineCalc; + std::string mCmdLineClearChat; + std::string mCmdLineDrawDistance; + std::string mCmdTeleportToCam; + std::string mCmdLineKeyToName; + std::string mCmdLineOfferTp; + std::string mCmdLineMapTo; + bool mCmdMapToKeepPos; + std::string mCmdLineTP2; + std::string mCmdLineAway; + std::string mCmdLineRegionSay; std::string mCmdLineURL; + std::string mCmdLineResync; + std::string mCmdLineHover; - //Security ---------------------------------------------------------------------------- - BOOL mBroadcastViewerEffects; - BOOL mDisablePointAtAndBeam; - BOOL mPrivateLookAt; - BOOL mShowLookAt; - BOOL mQuietSnapshotsToDisk; - BOOL mDetachBridge; - BOOL mRevokePermsOnStandUp; - BOOL mDisableClickSit; + //Security ---------------------------------------------------------------------------- + bool mBroadcastViewerEffects; + bool mDisablePointAtAndBeam; + bool mPrivateLookAt; + bool mHideOwnLookAt; + bool mShowLookAt; + S32 mLookAtNames; + bool mLookAtLines; + bool mQuietSnapshotsToDisk; + bool mAnnounceBumps; + bool mSitOnAway; + bool mDetachBridge; + bool mRevokePermsOnStandUp; + bool mDisableClickSit; bool mDisableClickSitOtherOwner; - BOOL mDisplayScriptJumps; - F32 mNumScriptDiff; + bool mDisplayScriptJumps; + bool mReplaceLinks; + F32 mNumScriptDiff; + U32 mEmergencySeconds; + std::string mLandmark; + std::string mLandmarkBackup; //Build ------------------------------------------------------------------------------- F32 mAlpha; @@ -115,14 +129,17 @@ class LLPrefsAscentSys : public LLPanel F32 mGlow; std::string mItem; std::string mMaterial; - BOOL mNextCopy; - BOOL mNextMod; - BOOL mNextTrans; + bool mNextCopy; + bool mNextMod; + bool mNextTrans; + bool mScriptNextCopy; + bool mScriptNextMod; + bool mScriptNextTrans; std::string mShiny; - BOOL mTemporary; + bool mTemporary; std::string mTexture; - BOOL mPhantom; - BOOL mPhysical; + bool mPhantom; + bool mPhysical; F32 mXsize; F32 mYsize; F32 mZsize; diff --git a/indra/newview/ascentprefsvan.cpp b/indra/newview/ascentprefsvan.cpp index 869b4026ab..0bb200636d 100644 --- a/indra/newview/ascentprefsvan.cpp +++ b/indra/newview/ascentprefsvan.cpp @@ -61,14 +61,9 @@ LLPrefsAscentVan::LLPrefsAscentVan() getChild("tag_spoofing_combobox")->setCommitCallback(boost::bind(&LLPrefsAscentVan::onCommitClientTag, this, _1)); - getChild("show_my_tag_check")->setCommitCallback(boost::bind(&LLPrefsAscentVan::onCommitCheckBox, this, _1, _2)); - getChild("show_self_tag_check")->setCommitCallback(boost::bind(&LLPrefsAscentVan::onCommitCheckBox, this, _1, _2)); - getChild("show_self_tag_color_check")->setCommitCallback(boost::bind(&LLPrefsAscentVan::onCommitCheckBox, this, _1, _2)); - getChild("customize_own_tag_check")->setCommitCallback(boost::bind(&LLPrefsAscentVan::onCommitCheckBox, this, _1, _2)); - getChild("show_friend_tag_check")->setCommitCallback(boost::bind(&LLPrefsAscentVan::onCommitCheckBox, this, _1, _2)); - getChild("use_status_check")->setCommitCallback(boost::bind(&LLPrefsAscentVan::onCommitCheckBox, this, _1, _2)); - - getChild("custom_tag_label_box")->setCommitCallback(boost::bind(&LLPrefsAscentVan::onCommitTextModified, this, _1, _2)); + getChild("custom_tag_label_box")->setCommitCallback(boost::bind(&LLControlGroup::setString, boost::ref(gSavedSettings), "AscentCustomTagLabel", _2)); + commit_callback_t lineEditorControl(boost::bind(&LLControlGroup::setString, boost::ref(gSavedSettings), boost::bind(&LLUICtrl::getName, _1), _2)); + getChild("UISndRestart")->setCommitCallback(lineEditorControl); getChild("update_clientdefs")->setCommitCallback(boost::bind(LLPrefsAscentVan::onManualClientUpdate)); @@ -104,14 +99,6 @@ void LLPrefsAscentVan::onCommitClientTag(LLUICtrl* ctrl) } } -void LLPrefsAscentVan::onCommitTextModified(LLUICtrl* ctrl, const LLSD& value) -{ - if (ctrl->getName() == "custom_tag_label_box") - { - gSavedSettings.setString("AscentCustomTagLabel", value); - } -} - //static void LLPrefsAscentVan::onManualClientUpdate() { @@ -127,29 +114,6 @@ void LLPrefsAscentVan::onManualClientUpdate() LLFloaterChat::addChat(chat); } -void LLPrefsAscentVan::onCommitCheckBox(LLUICtrl* ctrl, const LLSD& value) -{ -// llinfos << "Control named " << ctrl->getControlName() << llendl; - - if (ctrl->getName() == "use_status_check") - { - bool showCustomColors = value.asBoolean(); - childSetEnabled("friends_color_textbox", showCustomColors); - childSetEnabled("friend_color_swatch", showCustomColors || gSavedSettings.getBOOL("ColorFriendChat")); - childSetEnabled("estate_owner_color_swatch", showCustomColors || gSavedSettings.getBOOL("ColorEstateOwnerChat")); - childSetEnabled("linden_color_swatch", showCustomColors || gSavedSettings.getBOOL("ColorLindenChat")); - childSetEnabled("muted_color_swatch", showCustomColors || gSavedSettings.getBOOL("ColorMutedChat")); - } - else if (ctrl->getName() == "customize_own_tag_check") - { - bool showCustomOptions = value.asBoolean(); - childSetEnabled("custom_tag_label_text", showCustomOptions); - childSetEnabled("custom_tag_label_box", showCustomOptions); - childSetEnabled("custom_tag_color_text", showCustomOptions); - childSetEnabled("custom_tag_color_swatch", showCustomOptions); - } -} - // Store current settings for cancel void LLPrefsAscentVan::refreshValues() { @@ -161,11 +125,15 @@ void LLPrefsAscentVan::refreshValues() mDisableChatAnimation = gSavedSettings.getBOOL("SGDisableChatAnimation"); mAddNotReplace = gSavedSettings.getBOOL("LiruAddNotReplace"); mTurnAround = gSavedSettings.getBOOL("TurnAroundWhenWalkingBackwards"); + mCustomizeAnim = gSavedSettings.getBOOL("LiruCustomizeAnim"); mAnnounceSnapshots = gSavedSettings.getBOOL("AnnounceSnapshots"); mAnnounceStreamMetadata = gSavedSettings.getBOOL("AnnounceStreamMetadata"); - mUnfocusedFloatersOpaque = gSavedSettings.getBOOL("FloaterUnfocusedBackgroundOpaque"); - mCompleteNameProfiles = gSavedSettings.getBOOL("SinguCompleteNameProfiles"); + mInactiveFloaterTransparency = gSavedSettings.getF32("InactiveFloaterTransparency"); + mActiveFloaterTransparency = gSavedSettings.getF32("ActiveFloaterTransparency"); mScriptErrorsStealFocus = gSavedSettings.getBOOL("LiruScriptErrorsStealFocus"); + mConnectToNeighbors = gSavedSettings.getBOOL("AlchemyConnectToNeighbors"); + mRestartMinimized = gSavedSettings.getBOOL("LiruRegionRestartMinimized"); + mRestartSound = gSavedSettings.getString("UISndRestart"); //Tags\Colors ---------------------------------------------------------------------------- mAscentBroadcastTag = gSavedSettings.getBOOL("AscentBroadcastTag"); @@ -174,6 +142,7 @@ void LLPrefsAscentVan::refreshValues() mShowSelfClientTag = gSavedSettings.getBOOL("AscentShowSelfTag"); mShowSelfClientTagColor = gSavedSettings.getBOOL("AscentShowSelfTagColor"); mShowFriendsTag = gSavedSettings.getBOOL("AscentShowFriendsTag"); + mDisplayClientTagOnNewLine = gSavedSettings.getBOOL("SLBDisplayClientTagOnNewLine"); mCustomTagOn = gSavedSettings.getBOOL("AscentUseCustomTag"); mCustomTagLabel = gSavedSettings.getString("AscentCustomTagLabel"); mCustomTagColor = gSavedSettings.getColor4("AscentCustomTagColor"); @@ -187,6 +156,7 @@ void LLPrefsAscentVan::refreshValues() mEstateOwnerColor = gSavedSettings.getColor4("AscentEstateOwnerColor"); mLindenColor = gSavedSettings.getColor4("AscentLindenColor"); mMutedColor = gSavedSettings.getColor4("AscentMutedColor"); + mMapAvatarColor = gSavedSettings.getColor4("MapAvatar"); mCustomColor = gSavedSettings.getColor4("MoyMiniMapCustomColor"); mColorFriendChat = gSavedSettings.getBOOL("ColorFriendChat"); mColorEOChat = gSavedSettings.getBOOL("ColorEstateOwnerChat"); @@ -203,16 +173,13 @@ void LLPrefsAscentVan::refreshValues() void LLPrefsAscentVan::refresh() { //Main ----------------------------------------------------------------------------------- + getChildView("UISndRestart")->setValue(mRestartSound); //Tags\Colors ---------------------------------------------------------------------------- LLComboBox* combo = getChild("tag_spoofing_combobox"); combo->setCurrentByIndex(mSelectedClient); childSetEnabled("friends_color_textbox", mUseStatusColors); - childSetEnabled("friend_color_swatch", mUseStatusColors || mColorFriendChat); - childSetEnabled("estate_owner_color_swatch", mUseStatusColors || mColorEOChat); - childSetEnabled("linden_color_swatch", mUseStatusColors || mColorLindenChat); - childSetEnabled("muted_color_swatch", mUseStatusColors || mColorMutedChat); childSetEnabled("custom_tag_label_text", mCustomTagOn); childSetEnabled("custom_tag_label_box", mCustomTagOn); @@ -232,11 +199,15 @@ void LLPrefsAscentVan::cancel() gSavedSettings.setBOOL("SGDisableChatAnimation", mDisableChatAnimation); gSavedSettings.setBOOL("LiruAddNotReplace", mAddNotReplace); gSavedSettings.setBOOL("TurnAroundWhenWalkingBackwards", mTurnAround); + gSavedSettings.setBOOL("LiruCustomizeAnim", mCustomizeAnim); gSavedSettings.setBOOL("AnnounceSnapshots", mAnnounceSnapshots); gSavedSettings.setBOOL("AnnounceStreamMetadata", mAnnounceStreamMetadata); - gSavedSettings.setBOOL("FloaterUnfocusedBackgroundOpaque", mUnfocusedFloatersOpaque); - gSavedSettings.setBOOL("SinguCompleteNameProfiles", mCompleteNameProfiles); + gSavedSettings.setF32("InactiveFloaterTransparency", mInactiveFloaterTransparency); + gSavedSettings.setF32("ActiveFloaterTransparency", mActiveFloaterTransparency); gSavedSettings.setBOOL("LiruScriptErrorsStealFocus", mScriptErrorsStealFocus); + gSavedSettings.setBOOL("AlchemyConnectToNeighbors", mConnectToNeighbors); + gSavedSettings.setBOOL("LiruRegionRestartMinimized", mRestartMinimized); + gSavedSettings.setString("UISndRestart", mRestartSound); //Tags\Colors ---------------------------------------------------------------------------- gSavedSettings.setBOOL("AscentBroadcastTag", mAscentBroadcastTag); @@ -245,6 +216,7 @@ void LLPrefsAscentVan::cancel() gSavedSettings.setBOOL("AscentShowSelfTag", mShowSelfClientTag); gSavedSettings.setBOOL("AscentShowSelfTagColor", mShowSelfClientTagColor); gSavedSettings.setBOOL("AscentShowFriendsTag", mShowFriendsTag); + gSavedSettings.setBOOL("SLBDisplayClientTagOnNewLine", mDisplayClientTagOnNewLine); gSavedSettings.setBOOL("AscentUseCustomTag", mCustomTagOn); gSavedSettings.setString("AscentCustomTagLabel", mCustomTagLabel); gSavedSettings.setColor4("AscentCustomTagColor", mCustomTagColor); @@ -258,6 +230,7 @@ void LLPrefsAscentVan::cancel() gSavedSettings.setColor4("AscentEstateOwnerColor", mEstateOwnerColor); gSavedSettings.setColor4("AscentLindenColor", mLindenColor); gSavedSettings.setColor4("AscentMutedColor", mMutedColor); + gSavedSettings.setColor4("MapAvatar", mMapAvatarColor); gSavedSettings.setColor4("MoyMiniMapCustomColor", mCustomColor); gSavedSettings.setBOOL("ColorFriendChat", mColorFriendChat); gSavedSettings.setBOOL("ColorEstateOwnerChat", mColorEOChat); diff --git a/indra/newview/ascentprefsvan.h b/indra/newview/ascentprefsvan.h index 5ec08c6054..b29f5147d9 100644 --- a/indra/newview/ascentprefsvan.h +++ b/indra/newview/ascentprefsvan.h @@ -38,65 +38,67 @@ class LLPrefsAscentVan : public LLPanel { public: - LLPrefsAscentVan(); - ~LLPrefsAscentVan(); + LLPrefsAscentVan(); + ~LLPrefsAscentVan(); - void apply(); - void cancel(); - void refresh(); - void refreshValues(); + void apply(); + void cancel(); + void refresh(); + void refreshValues(); protected: void onCommitClientTag(LLUICtrl* ctrl); - void onCommitCheckBox(LLUICtrl* ctrl, const LLSD& value); - void onCommitTextModified(LLUICtrl* ctrl, const LLSD& value); static void onManualClientUpdate(); - //Main - BOOL mUseAccountSettings; - BOOL mShowTPScreen; - BOOL mPlayTPSound; - BOOL mShowLogScreens; + +private: + //Main + bool mUseAccountSettings; + bool mShowTPScreen; + bool mPlayTPSound; + bool mShowLogScreens; bool mDisableChatAnimation; bool mAddNotReplace; bool mTurnAround; + bool mCustomizeAnim; bool mAnnounceSnapshots; bool mAnnounceStreamMetadata; - bool mUnfocusedFloatersOpaque; - bool mCompleteNameProfiles; + F32 mInactiveFloaterTransparency, mActiveFloaterTransparency; bool mScriptErrorsStealFocus; - //Tags\Colors - BOOL mAscentBroadcastTag; - std::string mReportClientUUID; - U32 mSelectedClient; - BOOL mShowSelfClientTag; - BOOL mShowSelfClientTagColor; - BOOL mShowFriendsTag; - BOOL mCustomTagOn; - std::string mCustomTagLabel; - LLColor4 mCustomTagColor; - BOOL mShowOthersTag; - BOOL mShowOthersTagColor; - BOOL mShowIdleTime; - BOOL mUseStatusColors; - BOOL mUpdateTagsOnLoad; - LLColor4 mEffectColor; - LLColor4 mFriendColor; - LLColor4 mEstateOwnerColor; - LLColor4 mLindenColor; - LLColor4 mMutedColor; + bool mConnectToNeighbors; + bool mRestartMinimized; + std::string mRestartSound; + //Tags\Colors + bool mAscentBroadcastTag; + std::string mReportClientUUID; + U32 mSelectedClient; + bool mShowSelfClientTag; + bool mShowSelfClientTagColor; + bool mShowFriendsTag; + bool mDisplayClientTagOnNewLine; + bool mCustomTagOn; + std::string mCustomTagLabel; + LLColor4 mCustomTagColor; + bool mShowOthersTag; + bool mShowOthersTagColor; + bool mShowIdleTime; + bool mUseStatusColors; + bool mUpdateTagsOnLoad; + LLColor4 mEffectColor; + LLColor4 mFriendColor; + LLColor4 mEstateOwnerColor; + LLColor4 mLindenColor; + LLColor4 mMutedColor; + LLColor4 mMapAvatarColor; LLColor4 mCustomColor; bool mColorFriendChat; bool mColorEOChat; bool mColorLindenChat; bool mColorMutedChat; -// bool mColorCustomChat; - - F32 mAvatarXModifier; - F32 mAvatarYModifier; - F32 mAvatarZModifier; - -private: + // bool mColorCustomChat; + F32 mAvatarXModifier; + F32 mAvatarYModifier; + F32 mAvatarZModifier; }; #endif diff --git a/indra/newview/awavefront.cpp b/indra/newview/awavefront.cpp index 4af106c124..5e94a43e41 100644 --- a/indra/newview/awavefront.cpp +++ b/indra/newview/awavefront.cpp @@ -64,14 +64,14 @@ namespace if (LLFILE* fp = LLFile::fopen(selected_filename, "wb")) { wfsaver->saveFile(fp); - llinfos << "OBJ file saved to " << selected_filename << llendl; + LL_INFOS() << "OBJ file saved to " << selected_filename << LL_ENDL; if (gSavedSettings.getBOOL("OBJExportNotifySuccess")) LLNotificationsUtil::add("WavefrontExportSuccess", LLSD().with("FILENAME", selected_filename)); fclose(fp); } - else llerrs << "can't open: " << selected_filename << llendl; + else LL_ERRS() << "can't open: " << selected_filename << LL_ENDL; } - else llwarns << "No file; bailing" << llendl; + else LL_WARNS() << "No file; bailing" << LL_ENDL; delete wfsaver; } @@ -163,10 +163,11 @@ Wavefront::Wavefront(LLFace* face, LLPolyMesh* mesh, const LLXform* transform, c if (transform_normals) Transform(normals, transform_normals); const U32 pcount = mesh ? mesh->getNumFaces() : (vb->getNumIndices()/3); //indices - const U16 offset = face->getIndicesStart(); //indices + const U32 offset = face->getIndicesStart(); //indices for (U32 i = 0; i < pcount; ++i) { - triangles.push_back(tri(getIndices[i * 3 + offset] + start, getIndices[i * 3 + 1 + offset] + start, getIndices[i * 3 + 2 + offset] + start)); + const auto off = i * 3 + offset; + triangles.push_back(tri(getIndices[off] + start, getIndices[off + 1] + start, getIndices[off + 2] + start)); } } @@ -174,9 +175,9 @@ void Wavefront::Transform(vert_t& v, const LLXform* x) //recursive { LLMatrix4 m; x->getLocalMat4(m); - for (vert_t::iterator iterv = v.begin(); iterv != v.end(); ++iterv) + for (auto& i : v) { - iterv->first = iterv->first * m; + i.first = i.first * m; } if (const LLXform* xp = x->getParent()) Transform(v, xp); @@ -186,9 +187,9 @@ void Wavefront::Transform(vec3_t& v, const LLXform* x) //recursive { LLMatrix4 m; x->getLocalMat4(m); - for (vec3_t::iterator iterv = v.begin(); iterv != v.end(); ++iterv) + for (auto& i : v) { - *iterv = *iterv * m; + i = i * m; } if (const LLXform* xp = x->getParent()) Transform(v, xp); @@ -238,7 +239,7 @@ namespace LLViewerObject* obj = node->getObject(); if (obj->isSculpted() && !obj->isMesh()) { - LLSculptParams *sculpt_params = (LLSculptParams *)obj->getParameterEntry(LLNetworkData::PARAMS_SCULPT); + const LLSculptParams *sculpt_params = obj->getSculptParams(); LLUUID sculpt_id = sculpt_params->getSculptTexture(); // Find inventory items with asset id of the sculpt map @@ -252,9 +253,9 @@ namespace asset_id_matches); // See if any of the inventory items matching this sculpt id are exportable - for (S32 i = 0; i < items.count(); i++) + for (const auto& item : items) { - const LLPermissions item_permissions = items[i]->getPermissions(); + const LLPermissions item_permissions = item->getPermissions(); if (item_permissions.allowExportBy(gAgentID, LFSimFeatureHandler::instance().exportPolicy())) { return true; @@ -269,22 +270,29 @@ namespace } } - class LFSaveSelectedObjects : public view_listener_t + class LFSaveSelectedObjects final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { if (LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection()) { + if (!selection->getFirstRootObject()) + { + if (gSavedSettings.getBOOL("OBJExportNotifyFailed")) + LLNotificationsUtil::add("ExportFailed"); + return true; + } + WavefrontSaver* wfsaver = new WavefrontSaver; // deleted in callback wfsaver->offset = -selection->getFirstRootObject()->getRenderPosition(); S32 total = 0; S32 included = 0; for (LLObjectSelection::iterator iter = selection->begin(); iter != selection->end(); ++iter) { - total++; + ++total; LLSelectNode* node = *iter; if (!can_export_node(node)) continue; - included++; + ++included; wfsaver->Add(node->getObject()); } if (wfsaver->obj_v.empty()) @@ -315,12 +323,12 @@ void WavefrontSaver::Add(const LLVOAvatar* av_vo) //adds attachments, too! { offset = -av_vo->getRenderPosition(); avatar_joint_list_t vjv = av_vo->mMeshLOD; - for (avatar_joint_list_t::const_iterator itervj = vjv.begin(); itervj != vjv.end(); ++itervj) + for (const auto& itervj : vjv) { - const LLViewerJoint* vj = dynamic_cast(*itervj); + const auto* vj = dynamic_cast(itervj); if (!vj || vj->mMeshParts.empty()) continue; - LLViewerJointMesh* vjm = dynamic_cast(vj->mMeshParts[0]); //highest LOD + auto* vjm = dynamic_cast(vj->mMeshParts[0]); //highest LOD if (!vjm) continue; vjm->updateJointGeometry(); @@ -348,21 +356,19 @@ void WavefrontSaver::Add(const LLVOAvatar* av_vo) //adds attachments, too! Add(Wavefront(face, pm, NULL, &normfix)); } - for (LLVOAvatar::attachment_map_t::const_iterator iter = av_vo->mAttachmentPoints.begin(); iter != av_vo->mAttachmentPoints.end(); ++iter) + for (const auto& ap : av_vo->mAttachmentPoints) { - LLViewerJointAttachment* ja = iter->second; + LLViewerJointAttachment* ja = ap.second; if (!ja) continue; - for (LLViewerJointAttachment::attachedobjs_vec_t::iterator itero = ja->mAttachedObjects.begin(); itero != ja->mAttachedObjects.end(); ++itero) + for (const auto& o : ja->mAttachedObjects) { - LLViewerObject* o = *itero; if (!o) continue; - LLDynamicArray prims = LLDynamicArray(); + std::vector prims; o->addThisAndAllChildren(prims); - for (LLDynamicArray::iterator iterc = prims.begin(); iterc != prims.end(); ++iterc) + for (const auto& c : prims) { - const LLViewerObject* c = *iterc; if (!c) continue; if (LLSelectNode* n = LLSelectMgr::getInstance()->getSelection()->findNode(const_cast(c))) { @@ -393,9 +399,9 @@ void WavefrontSaver::Add(const LLVOAvatar* av_vo) //adds attachments, too! } namespace { - class LFSaveSelectedAvatar : public view_listener_t + class LFSaveSelectedAvatar final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { if (const LLVOAvatar* avatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject())) { @@ -429,7 +435,7 @@ namespace { const size_t size = outstring.length(); if (fwrite(outstring.c_str(), 1, size, fp) != size) - llwarns << "Short write" << llendl; + LL_WARNS() << "Short write" << LL_ENDL; } } @@ -439,49 +445,48 @@ bool WavefrontSaver::saveFile(LLFILE* fp) int num = 0; int index = 0; - for (std::vector::iterator w_iter = obj_v.begin(); w_iter != obj_v.end(); ++w_iter) + for (const auto& obj : obj_v) { int count = 0; - std::string name = (*w_iter).name; + std::string name = obj.name; if (name.empty()) name = llformat("%d", num++); - vert_t vertices = (*w_iter).vertices; - vec3_t normals = (*w_iter).normals; - tri_t triangles = (*w_iter).triangles; + auto& vertices = obj.vertices; + auto& normals = obj.normals; + auto& triangles = obj.triangles; //Write Object - write_or_bust(fp, "o " + name + "\n"); + write_or_bust(fp, "o " + name + '\n'); //Write vertices; swap axes if necessary static const LLCachedControl swapYZ("OBJExportSwapYZ", false); const double xm = swapYZ ? -1.0 : 1.0; const int y = swapYZ ? 2 : 1; const int z = swapYZ ? 1 : 2; - for (vert_t::iterator v_iter = vertices.begin(); v_iter != vertices.end(); ++v_iter) + for (const auto& vert : vertices) { ++count; - const LLVector3 v = v_iter->first + offset; + const LLVector3 v = vert.first + offset; write_or_bust(fp, llformat("v %f %f %f\n",v[0] * xm, v[y], v[z])); } - for (vec3_t::iterator n_iter = normals.begin(); n_iter != normals.end(); ++n_iter) + for (const auto& n : normals) { - const LLVector3 n = *n_iter; write_or_bust(fp, llformat("vn %f %f %f\n",n[0] * xm, n[y], n[z])); } - for (vert_t::iterator v_iter = vertices.begin(); v_iter != vertices.end(); ++v_iter) + for (const auto& vert : vertices) { - write_or_bust(fp, llformat("vt %f %f\n", v_iter->second[0], v_iter->second[1])); + write_or_bust(fp, llformat("vt %f %f\n", vert.second[0], vert.second[1])); } //Write triangles - for (tri_t::iterator t_iter = triangles.begin(); t_iter != triangles.end(); ++t_iter) + for (const auto& triangle : triangles) { - const int f1 = t_iter->v0 + index + 1; - const int f2 = t_iter->v1 + index + 1; - const int f3 = t_iter->v2 + index + 1; + const int f1 = triangle.v0 + index + 1; + const int f2 = triangle.v1 + index + 1; + const int f3 = triangle.v2 + index + 1; write_or_bust(fp, llformat("f %d/%d/%d %d/%d/%d %d/%d/%d\n", f1,f1,f1,f2,f2,f2,f3,f3,f3)); } diff --git a/indra/newview/awavefront.h b/indra/newview/awavefront.h index 3f58ee4a0f..09f0dc3b91 100644 --- a/indra/newview/awavefront.h +++ b/indra/newview/awavefront.h @@ -28,6 +28,9 @@ class LLFace; class LLPolyMesh; class LLViewerObject; class LLVOAvatar; +class LLVolume; +class LLVolumeFace; +class LLXform; typedef std::vector > vert_t; typedef std::vector vec3_t; diff --git a/indra/newview/character/aux_base.tga b/indra/newview/character/aux_base.tga new file mode 100644 index 0000000000..dbcaaaf2b1 Binary files /dev/null and b/indra/newview/character/aux_base.tga differ diff --git a/indra/newview/character/avatar_lad.xml b/indra/newview/character/avatar_lad.xml index 48e6205bc1..47422d0382 100644 --- a/indra/newview/character/avatar_lad.xml +++ b/indra/newview/character/avatar_lad.xml @@ -1,6 +1,6 @@ @@ -12,6 +12,7 @@ pie_slice="2" name="Chest" joint="mChest" + location="ATTACH_CHEST" position="0.15 0 -0.1" rotation="0 90 90" visible_in_first_person="true" /> @@ -22,6 +23,7 @@ pie_slice="2" name="Skull" joint="mHead" + location="ATTACH_HEAD" position="0 0 0.15" rotation="0 0 90" visible_in_first_person="false" /> @@ -32,6 +34,7 @@ pie_slice="3" name="Left Shoulder" joint="mCollarLeft" + location="ATTACH_LSHOULDER" position="0 0 0.08" rotation="0 0 0" visible_in_first_person="true" /> @@ -42,6 +45,7 @@ pie_slice="1" name="Right Shoulder" joint="mCollarRight" + location="ATTACH_RSHOULDER" position="0 0 0.08" rotation="0 0 0" visible_in_first_person="true"/> @@ -51,6 +55,7 @@ group="4" name="Left Hand" joint="mWristLeft" + location="ATTACH_LHAND" position="0 0.08 -0.02" rotation="0 0 0" visible_in_first_person="true" @@ -61,6 +66,7 @@ group="0" name="Right Hand" joint="mWristRight" + location="ATTACH_RHAND" position="0 -0.08 -0.02" rotation="0 0 0" visible_in_first_person="true" @@ -72,6 +78,7 @@ pie_slice="6" name="Left Foot" joint="mFootLeft" + location="ATTACH_LFOOT" position="0 0.0 0.0" rotation="0 0 0" visible_in_first_person="true"/> @@ -82,6 +89,7 @@ pie_slice="6" name="Right Foot" joint="mFootRight" + location="ATTACH_RFOOT" position="0 0.0 0.0" rotation="0 0 0" visible_in_first_person="true"/> @@ -92,6 +100,7 @@ pie_slice="7" name="Spine" joint="mChest" + location="ATTACH_BACK" position="-0.15 0 -0.1" rotation="0 -90 90" visible_in_first_person="true" /> @@ -102,6 +111,7 @@ pie_slice="6" name="Pelvis" joint="mPelvis" + location="ATTACH_PELVIS" position="0 0 -0.15" rotation="0 0 0" visible_in_first_person="true" /> @@ -112,6 +122,7 @@ pie_slice="6" name="Mouth" joint="mHead" + location="ATTACH_MOUTH" position="0.12 0 0.001" rotation="0 0 0" visible_in_first_person="false"/> @@ -122,6 +133,7 @@ pie_slice="7" name="Chin" joint="mHead" + location="ATTACH_CHIN" position="0.12 0 -0.04" rotation="0 0 0" visible_in_first_person="false" /> @@ -132,6 +144,7 @@ pie_slice="4" name="Left Ear" joint="mHead" + location="ATTACH_LEAR" position="0.015 0.08 0.017" rotation="0 0 0" visible_in_first_person="false" /> @@ -142,6 +155,7 @@ pie_slice="0" name="Right Ear" joint="mHead" + location="ATTACH_REAR" position="0.015 -0.08 0.017" rotation="0 0 0" visible_in_first_person="false" /> @@ -152,6 +166,7 @@ pie_slice="3" name="Left Eyeball" joint="mEyeLeft" + location="ATTACH_LEYE" position="0 0 0" rotation="0 0 0" visible_in_first_person="false"/> @@ -162,6 +177,7 @@ pie_slice="1" name="Right Eyeball" joint="mEyeRight" + location="ATTACH_REYE" position="0 0 0" rotation="0 0 0" visible_in_first_person="false" /> @@ -172,6 +188,7 @@ pie_slice="5" name="Nose" joint="mHead" + location="ATTACH_NOSE" position="0.1 0 0.05" rotation="0 0 0" visible_in_first_person="false"/> @@ -182,6 +199,7 @@ pie_slice="0" name="R Upper Arm" joint="mShoulderRight" + location="ATTACH_RUARM" position="0.01 -0.13 0.01" rotation="0 0 0" visible_in_first_person="true" /> @@ -192,6 +210,7 @@ pie_slice="7" name="R Forearm" joint="mElbowRight" + location="ATTACH_RLARM" position="0 -0.12 0" rotation="0 0 0" visible_in_first_person="true"/> @@ -202,6 +221,7 @@ pie_slice="4" name="L Upper Arm" joint="mShoulderLeft" + location="ATTACH_LUARM" position="0.01 0.15 -0.01" rotation="0 0 0" visible_in_first_person="true" /> @@ -212,6 +232,7 @@ pie_slice="5" name="L Forearm" joint="mElbowLeft" + location="ATTACH_LLARM" position="0 0.113 0" rotation="0 0 0" visible_in_first_person="true" /> @@ -222,6 +243,7 @@ pie_slice="1" name="Right Hip" joint="mHipRight" + location="ATTACH_RHIP" position="0 0 0" rotation="0 0 0" visible_in_first_person="true" /> @@ -232,6 +254,7 @@ pie_slice="0" name="R Upper Leg" joint="mHipRight" + location="ATTACH_RULEG" position="-0.017 0.041 -0.310" rotation="0 0 0" visible_in_first_person="true" /> @@ -242,6 +265,7 @@ pie_slice="7" name="R Lower Leg" joint="mKneeRight" + location="ATTACH_RLLEG" position="-0.044 -0.007 -0.262" rotation="0 0 0" visible_in_first_person="true" /> @@ -252,6 +276,7 @@ pie_slice="3" name="Left Hip" joint="mHipLeft" + location="ATTACH_LHIP" position="0 0 0" rotation="0 0 0" visible_in_first_person="true" /> @@ -262,6 +287,7 @@ pie_slice="4" name="L Upper Leg" joint="mHipLeft" + location="ATTACH_LULEG" position="-0.019 -0.034 -0.310" rotation="0 0 0" visible_in_first_person="true"/> @@ -272,6 +298,7 @@ pie_slice="5" name="L Lower Leg" joint="mKneeLeft" + location="ATTACH_LLLEG" position="-0.044 -0.007 -0.261" rotation="0 0 0" visible_in_first_person="true" /> @@ -282,6 +309,7 @@ pie_slice="5" name="Stomach" joint="mPelvis" + location="ATTACH_BELLY" position="0.092 0.0 0.088" rotation="0 0 0" visible_in_first_person="true" /> @@ -292,6 +320,7 @@ pie_slice="3" name="Left Pec" joint="mTorso" + location="ATTACH_LEFT_PEC" position="0.104 0.082 0.247" rotation="0 0 0" visible_in_first_person="true" /> @@ -302,15 +331,17 @@ pie_slice="1" name="Right Pec" joint="mTorso" + location="ATTACH_RIGHT_PEC" position="0.104 -0.082 0.247" rotation="0 0 0" visible_in_first_person="true" /> @@ -408,12 +447,181 @@ id="40" group="6" pie_slice="4" - name="Root" + name="Avatar Center" joint="mRoot" + location="ATTACH_AVATAR_CENTER" position="0 0 0" rotation="0 0 0" visible_in_first_person="true" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - + camera_distance="2.2"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + + + + + + + + + - - - - - + + + + + + + + + + + + + + + + + + + + + + - - - - + camera_distance="1.8"> + + + + + + + + + + - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + value_max="1"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -633,12 +1496,20 @@ label_max="Eyes Long Head" value_min="-1" value_max="1"> - - - - - - + + + + + + + + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - + value_max=".10"> + - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - + + + + + + + + + + + + - - - - - - + + + + + + + + + + + + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - + + + + + - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - + + + + + + + + + + + + + + + + + + + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - + + + + + + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + + + + + + + + + + + + + + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1038,16 +4474,17 @@ @@ -1055,28 +4492,197 @@ + camera_angle="90"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + ############# + --> + + + - - - + + + - - - + + + - - - + + + + + + + - - + id="20004" + group="1" + name="Broad_Nostrils" + value_min="-.5" + value_max="1"> + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - - - - - - + + + - - + - - - - - - - - - - - + + + - - - + + + - - + + + + + + - - - - - - - - - - - - - - - - - - - + + + - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - + value_max="1.2"> + + - - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - - + + - @@ -3563,7 +6828,11 @@ + pos="0.07 0 -0.07"/> + @@ -3582,7 +6851,16 @@ camera_elevation=".1" camera_distance="1" camera_angle="15"> - + + + + - + + + + - + + + + - + + + + + + + + + + + + @@ -3732,6 +7076,10 @@ scale="-0.01 -0.01 0.0" pos="0.01 0.0 0"/> + @@ -3780,6 +7128,32 @@ scale="0.02 0.03 0.03" pos="0 0 -0.03"/> + + + + + + + @@ -3832,7 +7206,16 @@ value_max="2" camera_elevation=".3" camera_distance=".8"> - + + + + + + + @@ -3901,7 +7293,16 @@ value_max="1.3" camera_elevation=".3" camera_distance=".8"> - + + + + - + + + + @@ -6514,31 +10028,123 @@ - - - - - - - + + + + - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - + @@ -6652,34 +10258,127 @@ skip_if_zero="true" domain="0.6" /> - + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - + name="lower_tattoo"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + - - - + + + + + + + + + + + + + + + + + + + + + + + + @@ -8775,96 +12624,1358 @@ multiply_blend="true" /> - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + + + + - - - + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + + + + + + + + + + + + + + + + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + max2="1" + min2="1" /> + + + + + + + + + + + @@ -9345,9 +14485,13 @@ id="29" /> - - + id="30" /> + + + + + - - + max2="1" + min2="1" /> + + + + + - - - + + + + + + + - - + id="186" /> + + - + + + - - + id="187" /> + + - + + + - - + min2="1" /> - + + + + + + + - - + id="772" /> + + + + + + + + + - - - - + - + + + + + - + - + + + + + + + + - - - + + + - + + + - - - + + + + - - - - - - + + + + + + + - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/indra/newview/character/avatar_skeleton.xml b/indra/newview/character/avatar_skeleton.xml index 5e73804f2d..2241a12545 100644 --- a/indra/newview/character/avatar_skeleton.xml +++ b/indra/newview/character/avatar_skeleton.xml @@ -1,74 +1,232 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/indra/newview/character/checkerboard.tga b/indra/newview/character/checkerboard.tga new file mode 100644 index 0000000000..1950d7403d Binary files /dev/null and b/indra/newview/character/checkerboard.tga differ diff --git a/indra/newview/character/invisible_head.tga b/indra/newview/character/invisible_head.tga new file mode 100644 index 0000000000..2673a237d5 Binary files /dev/null and b/indra/newview/character/invisible_head.tga differ diff --git a/indra/newview/chatbar_as_cmdline.cpp b/indra/newview/chatbar_as_cmdline.cpp index 83b1f37094..2f5da6a334 100644 --- a/indra/newview/chatbar_as_cmdline.cpp +++ b/indra/newview/chatbar_as_cmdline.cpp @@ -16,7 +16,7 @@ * may be used to endorse or promote products derived from this * software without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY MODULAR SYSTEMS AND CONTRIBUTORS AS IS + * THIS SOFTWARE IS PROVIDED BY MODULAR SYSTEMS AND CONTRIBUTORS AS IS * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MODULAR SYSTEMS OR CONTRIBUTORS @@ -33,47 +33,44 @@ #include "chatbar_as_cmdline.h" +#include "llavatarnamecache.h" #include "llcalc.h" #include "llchatbar.h" #include "llagent.h" #include "llagentcamera.h" -#include "stdtypes.h" +#include "llagentui.h" +#include "llavataractions.h" +#include "llnotificationsutil.h" +#include "llsdserialize.h" #include "llviewerregion.h" #include "llworld.h" -#include "lluuid.h" #include "lleventtimer.h" -#include "llviewercontrol.h" -#include "material_codes.h" #include "llvolume.h" -#include "object_flags.h" #include "llvolumemessage.h" #include "llurldispatcher.h" #include "llworld.h" #include "llworldmap.h" #include "llfloateravatarlist.h" +#include "llfloaterregioninfo.h" #include "llviewerobjectlist.h" #include "llviewertexteditor.h" #include "llviewermenu.h" -#include "llvoavatar.h" +#include "llvoavatarself.h" #include "lltooldraganddrop.h" #include "llinventorymodel.h" +#include "llregioninfomodel.h" #include "llselectmgr.h" #include "llslurl.h" #include "llurlaction.h" -#include - -#include - #include "llchat.h" #include "llfloaterchat.h" +#include "rlvhandler.h" - -void cmdline_printchat(std::string message); -void cmdline_rezplat(bool use_saved_value = true, F32 visual_radius = 30.0); +void cmdline_printchat(const std::string& message); void cmdline_tp2name(std::string target); LLUUID cmdline_partial_name2key(std::string name); @@ -109,7 +106,7 @@ class JCZface : public LLEventTimer LLViewerInventoryItem* subj = instack.top(); instack.pop(); LLViewerObject *objectp = gObjectList.findObject(indest); - if(objectp) + if (objectp) { cmdline_printchat(std::string("dropping ")+subj->getName()); LLToolDragAndDrop::dropInventory(objectp,subj,LLToolDragAndDrop::SOURCE_AGENT,gAgent.getID()); @@ -151,7 +148,7 @@ class JCZtake : public LLEventTimer LLSelectNode* node = (*itr); LLViewerObject* object = node->getObject(); U32 localid=object->getLocalID(); - if(done_prims.find(localid) == done_prims.end()) + if (done_prims.find(localid) == done_prims.end()) { done_prims.insert(localid); std::string name = llformat("%fx%fx%f",object->getScale().mV[VX],object->getScale().mV[VY],object->getScale().mV[VZ]); @@ -202,6 +199,22 @@ void invrepair() gInventory.collectDescendents(gInventory.getRootFolderID(),cats,items,FALSE);//,objectnamematches); } +void resync_anims() +{ + for (auto* character : LLCharacter::sInstances) + { + LLVOAvatar& avatar = *static_cast(character); + if (!avatar.isDead()) + { + for (const auto& playpair : avatar.mPlayingAnimations) + { + avatar.stopMotion(playpair.first, TRUE); + avatar.startMotion(playpair.first); + } + } + } +} + #ifdef PROF_CTRL_CALLS bool sort_calls(const std::pair& left, const std::pair& right) { @@ -221,267 +234,412 @@ struct ProfCtrlListAccum : public LLControlGroup::ApplyFunctor std::vector > mVariableList; }; #endif //PROF_CTRL_CALLS -bool cmd_line_chat(std::string revised_text, EChatType type) +void spew_key_to_name(const LLUUID& targetKey, const LLAvatarName& av_name) { - static LLCachedControl sAscentCmdLine(gSavedSettings, "AscentCmdLine"); - static LLCachedControl sAscentCmdLinePos(gSavedSettings, "AscentCmdLinePos"); - static LLCachedControl sAscentCmdLineDrawDistance(gSavedSettings, "AscentCmdLineDrawDistance"); - static LLCachedControl sAscentCmdTeleportToCam(gSavedSettings, "AscentCmdTeleportToCam"); - static LLCachedControl sAscentCmdLineKeyToName(gSavedSettings, "AscentCmdLineKeyToName"); - static LLCachedControl sAscentCmdLineOfferTp(gSavedSettings, "AscentCmdLineOfferTp"); - static LLCachedControl sAscentCmdLineGround(gSavedSettings, "AscentCmdLineGround"); - static LLCachedControl sAscentCmdLineHeight(gSavedSettings, "AscentCmdLineHeight"); - static LLCachedControl sAscentCmdLineTeleportHome(gSavedSettings, "AscentCmdLineTeleportHome"); - static LLCachedControl sAscentCmdLineRezPlatform(gSavedSettings, "AscentCmdLineRezPlatform"); - static LLCachedControl sAscentCmdLineMapTo(gSavedSettings, "AscentCmdLineMapTo"); - static LLCachedControl sAscentCmdLineMapToKeepPos(gSavedSettings, "AscentMapToKeepPos"); - static LLCachedControl sAscentCmdLineCalc(gSavedSettings, "AscentCmdLineCalc"); - static LLCachedControl sAscentCmdLineTP2(gSavedSettings, "AscentCmdLineTP2"); - static LLCachedControl sAscentCmdLineClearChat(gSavedSettings, "AscentCmdLineClearChat"); - static LLCachedControl sSinguCmdLineAway(gSavedSettings, "SinguCmdLineAway"); - static LLCachedControl sSinguCmdLineURL(gSavedSettings, "SinguCmdLineURL"); - - if(sAscentCmdLine) + static const LLCachedControl ns(gSavedSettings, "AscentCmdLineKeyToNameNameSystem"); + cmdline_printchat(llformat("%s: %s", targetKey.asString().c_str(), av_name.getNSName().c_str())); +} +bool cmd_line_chat(std::string data, EChatType type) +{ + static LLCachedControl enableChatCmd(gSavedSettings, "AscentCmdLine", true); + if (enableChatCmd) { - std::istringstream i(revised_text); - std::string command; - i >> command; - command = utf8str_tolower(command); - if(command != "") + std::istringstream input(data); + std::string cmd; + + if (!(input >> cmd)) return true; + cmd = utf8str_tolower(cmd); + + static LLCachedControl sDrawDistanceCommand(gSavedSettings, "AscentCmdLineDrawDistance"); + static LLCachedControl sHeightCommand(gSavedSettings, "AscentCmdLineHeight"); + static LLCachedControl sGroundCommand(gSavedSettings, "AscentCmdLineGround"); + static LLCachedControl sPosCommand(gSavedSettings, "AscentCmdLinePos"); + static LLCachedControl sRezPlatCommand(gSavedSettings, "AscentCmdLineRezPlatform"); + static LLCachedControl sHomeCommand(gSavedSettings, "AscentCmdLineTeleportHome"); + static LLCachedControl sSetHomeCommand(gSavedSettings, "AlchemyChatCommandSetHome", "/sethome"); + static LLCachedControl sCalcCommand(gSavedSettings, "AscentCmdLineCalc"); + static LLCachedControl sMapToCommand(gSavedSettings, "AscentCmdLineMapTo"); + static LLCachedControl sClearCommand(gSavedSettings, "AscentCmdLineClearChat"); + static LLCachedControl sRegionMsgCommand(gSavedSettings, "SinguCmdLineRegionSay"); + static LLCachedControl sTeleportToCam(gSavedSettings, "AscentCmdTeleportToCam"); + static LLCachedControl sHoverHeight(gSavedSettings, "AlchemyChatCommandHoverHeight", "/hover"); + static LLCachedControl sSetNearbyChatChannelCmd(gSavedSettings, "AlchemyChatCommandSetChatChannel", "/setchannel"); + static LLCachedControl sResyncAnimCommand(gSavedSettings, "AlchemyChatCommandResyncAnim", "/resync"); + static LLCachedControl sKeyToName(gSavedSettings, "AscentCmdLineKeyToName"); + static LLCachedControl sOfferTp(gSavedSettings, "AscentCmdLineOfferTp"); + static LLCachedControl sTP2Command(gSavedSettings, "AscentCmdLineTP2"); + static LLCachedControl sAwayCommand(gSavedSettings, "SinguCmdLineAway"); + static LLCachedControl sURLCommand(gSavedSettings, "SinguCmdLineURL"); + static LLCachedControl sSettingCommand(gSavedSettings, "SinguCmdLineSetting"); + + if (cmd == utf8str_tolower(sDrawDistanceCommand)) // dd { - if(command == utf8str_tolower(sAscentCmdLinePos)) + int drawDist; + if (input >> drawDist) { - F32 x,y,z; - if (i >> x) - { - if (i >> y) - { - if (i >> z) - { - LLViewerRegion* agentRegionp = gAgent.getRegion(); - if(agentRegionp) - { - LLVector3 targetPos(x,y,z); - LLVector3d pos_global = from_region_handle(agentRegionp->getHandle()); - pos_global += LLVector3d((F64)targetPos.mV[0],(F64)targetPos.mV[1],(F64)targetPos.mV[2]); - gAgent.teleportViaLocation(pos_global); - return false; - } - } - } - } + gSavedSettings.setF32("RenderFarClip", drawDist); + gAgentCamera.mDrawDistance=drawDist; + char buffer[DB_IM_MSG_BUF_SIZE * 2]; /* Flawfinder: ignore */ + snprintf(buffer,sizeof(buffer),"Draw distance set to: %dm",drawDist); + cmdline_printchat(std::string(buffer)); + return false; } - else if(command == utf8str_tolower(sAscentCmdLineDrawDistance)) + } + else if (cmd == utf8str_tolower(sHeightCommand)) // gth + { + F64 z; + if (input >> z) + { + LLVector3d pos_global = gAgent.getPositionGlobal(); + pos_global.mdV[VZ] = z; + gAgent.teleportViaLocationLookAt(pos_global); + return false; + } + } + else if (cmd == utf8str_tolower(sGroundCommand)) // flr + { + LLVector3d pos_global = gAgent.getPositionGlobal(); + pos_global.mdV[VZ] = 0.0; + gAgent.teleportViaLocationLookAt(pos_global); + return false; + } + else if (cmd == utf8str_tolower(sPosCommand)) // pos + { + F32 x,y,z; + if ((input >> x) && (input >> y)) { - int drawDist; - if(i >> drawDist) + if (!(input >> z)) + z = gAgent.getPositionAgent().mV[VZ]; + + if (LLViewerRegion* regionp = gAgent.getRegion()) { - gSavedSettings.setF32("RenderFarClip", drawDist); - gAgentCamera.mDrawDistance=drawDist; - char buffer[DB_IM_MSG_BUF_SIZE * 2]; /* Flawfinder: ignore */ - snprintf(buffer,sizeof(buffer),"Draw distance set to: %dm",drawDist); - cmdline_printchat(std::string(buffer)); + LLVector3d target_pos = regionp->getPosGlobalFromRegion(LLVector3((F32) x, (F32) y, (F32) z)); + gAgent.teleportViaLocationLookAt(target_pos); return false; } } - else if(command == utf8str_tolower(sAscentCmdTeleportToCam)) - { - gAgent.teleportViaLocation(gAgentCamera.getCameraPositionGlobal()); - return false; - } - else if(command == utf8str_tolower(sAscentCmdLineKeyToName)) + } + else if (cmd == utf8str_tolower(sRezPlatCommand)) // plat + { + F32 size; + static LLCachedControl platSize(gSavedSettings, "AscentPlatformSize"); + if (!(input >> size)) + size = static_cast(platSize); + + const LLVector3& agent_pos = gAgent.getPositionAgent(); + const LLVector3 rez_pos(agent_pos.mV[VX], agent_pos.mV[VY], agent_pos.mV[VZ] - ((gAgentAvatarp->getScale().mV[VZ] / 2.f) + 0.25f + (gAgent.getVelocity().magVec() * 0.333))); + + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_ObjectAdd); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID()); + msg->nextBlockFast(_PREHASH_ObjectData); + msg->addU8Fast(_PREHASH_PCode, LL_PCODE_VOLUME); + msg->addU8Fast(_PREHASH_Material, LL_MCODE_METAL); + msg->addU32Fast(_PREHASH_AddFlags, agent_pos.mV[VZ] > 4096.f ? FLAGS_CREATE_SELECTED : 0U); + + LLVolumeParams volume_params; + volume_params.setType(LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_CIRCLE_33); + volume_params.setRatio(2, 2); + volume_params.setShear(0, 0); + volume_params.setTaper(2.0f,2.0f); + volume_params.setTaperX(0.f); + volume_params.setTaperY(0.f); + LLVolumeMessage::packVolumeParams(&volume_params, msg); + + size /= 3; + msg->addVector3Fast(_PREHASH_Scale, LLVector3(0.01f, size, size)); + msg->addQuatFast(_PREHASH_Rotation, LLQuaternion(90.f * DEG_TO_RAD, LLVector3::y_axis)); + msg->addVector3Fast(_PREHASH_RayStart, rez_pos); + msg->addVector3Fast(_PREHASH_RayEnd, rez_pos); + msg->addUUIDFast(_PREHASH_RayTargetID, LLUUID::null); + msg->addU8Fast(_PREHASH_BypassRaycast, TRUE); + msg->addU8Fast(_PREHASH_RayEndIsIntersection, FALSE); + msg->addU8Fast(_PREHASH_State, FALSE); + msg->sendReliable(gAgent.getRegionHost()); + + return false; + } + else if (cmd == utf8str_tolower(sHomeCommand)) // home + { + gAgent.teleportHome(); + return false; + } + else if (cmd == utf8str_tolower(sSetHomeCommand)) // sethome + { + gAgent.setStartPosition(START_LOCATION_ID_HOME); + return false; + } + else if (cmd == utf8str_tolower(sCalcCommand))//Cryogenic Blitz + { + if (data.length() > cmd.length() + 1) { - LLUUID targetKey; - if(i >> targetKey) + F32 result = 0.f; + std::string expr = data.substr(cmd.length() + 1); + LLStringUtil::toUpper(expr); + if (LLCalc::getInstance()->evalString(expr, result)) { - std::string object_name; - gCacheName->getFullName(targetKey, object_name); - char buffer[DB_IM_MSG_BUF_SIZE * 2]; /* Flawfinder: ignore */ - snprintf(buffer,sizeof(buffer),"%s: (%s)",targetKey.asString().c_str(), object_name.c_str()); - cmdline_printchat(std::string(buffer)); + // Replace the expression with the result + LLSD args; + args["EXPRESSION"] = expr; + args["RESULT"] = result; + LLNotificationsUtil::add("ChatCommandCalc", args); + return false; } + LLNotificationsUtil::add("ChatCommandCalcFailed"); return false; } - else if(command == utf8str_tolower(sAscentCmdLineOfferTp)) + } + else if (cmd == utf8str_tolower(sMapToCommand)) + { + const std::string::size_type length = cmd.length() + 1; + if (data.length() > length) { - std::string avatarKey; -// llinfos << "CMD DEBUG 0 " << command << " " << avatarName << llendl; - if(i >> avatarKey) + LLSLURL slurl(LLWeb::escapeURL(data.substr(length))); + // The user wants to keep their position between MapTos and they have not passed a position (position is defaulted) + static LLCachedControl sMapToKeepPos(gSavedSettings, "AscentMapToKeepPos"); + if (sMapToKeepPos && slurl.getPosition() == LLVector3(REGION_WIDTH_METERS/2, REGION_WIDTH_METERS/2, 0)) { -// llinfos << "CMD DEBUG 0 afterif " << command << " " << avatarName << llendl; - LLUUID tempUUID; - if(LLUUID::parseUUID(avatarKey, &tempUUID)) - { - char buffer[DB_IM_MSG_BUF_SIZE * 2]; /* Flawfinder: ignore */ - std::string tpMsg="Join me!"; - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_StartLure); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_Info); - msg->addU8Fast(_PREHASH_LureType, (U8)0); - - msg->addStringFast(_PREHASH_Message, tpMsg); - msg->nextBlockFast(_PREHASH_TargetData); - msg->addUUIDFast(_PREHASH_TargetID, tempUUID); - gAgent.sendReliableMessage(); - snprintf(buffer,sizeof(buffer),"Offered TP to key %s",tempUUID.asString().c_str()); - cmdline_printchat(std::string(buffer)); - return false; - } + LLVector3d agentPos = gAgent.getPositionGlobal(); + slurl = LLSLURL(slurl.getRegion(), LLVector3(fmod(agentPos.mdV[VX], (F64)REGION_WIDTH_METERS), fmod(agentPos.mdV[VY], (F64)REGION_WIDTH_METERS), agentPos.mdV[VZ])); } + + LLUrlAction::teleportToLocation(LLWeb::escapeURL("secondlife:///app/teleport/"+slurl.getLocationString())); } - else if(command == utf8str_tolower(sAscentCmdLineGround)) + return false; + } + else if (cmd == utf8str_tolower(sClearCommand)) + { + LLFloaterChat* nearby_chat = LLFloaterChat::getInstance(); + if (nearby_chat) { - LLVector3 agentPos = gAgent.getPositionAgent(); - U64 agentRegion = gAgent.getRegion()->getHandle(); - LLVector3 targetPos(agentPos.mV[0],agentPos.mV[1],LLWorld::getInstance()->resolveLandHeightAgent(agentPos)); - LLVector3d pos_global = from_region_handle(agentRegion); - pos_global += LLVector3d((F64)targetPos.mV[0],(F64)targetPos.mV[1],(F64)targetPos.mV[2]); - gAgent.teleportViaLocation(pos_global); + if (LLViewerTextEditor* editor = nearby_chat->getChild("Chat History Editor")) + editor->clear(); + if (LLViewerTextEditor* editor = nearby_chat->getChild("Chat History Editor with mute")) + editor->clear(); return false; } - else if(command == utf8str_tolower(sAscentCmdLineHeight)) + } + else if (cmd == "/droll") + { + S32 dice_sides; + if (!(input >> dice_sides)) + dice_sides = 6; + LLSD args; + args["RESULT"] = ((ll_rand() % dice_sides) + 1); + LLNotificationsUtil::add("ChatCommandDiceRoll", args); + return false; + } + else if (cmd == utf8str_tolower(sRegionMsgCommand)) // Region Message / Dialog + { + if (data.length() > cmd.length() + 1) { - F32 z; - if(i >> z) + std::string notification_message = data.substr(cmd.length() + 1); + if (!gAgent.getRegion()->isEstateManager()) { - LLVector3 agentPos = gAgent.getPositionAgent(); - U64 agentRegion = gAgent.getRegion()->getHandle(); - LLVector3 targetPos(agentPos.mV[0],agentPos.mV[1],z); - LLVector3d pos_global = from_region_handle(agentRegion); - pos_global += LLVector3d((F64)targetPos.mV[0],(F64)targetPos.mV[1],(F64)targetPos.mV[2]); - gAgent.teleportViaLocation(pos_global); + gChatBar->sendChatFromViewer(notification_message, CHAT_TYPE_REGION, false); return false; } + std::vector strings(5, "-1"); + // [0] grid_x, unused here + // [1] grid_y, unused here + strings[2] = gAgentID.asString(); // [2] agent_id of sender + // [3] sender name + std::string name; + LLAgentUI::buildFullname(name); + strings[3] = name; + strings[4] = notification_message; // [4] message + LLRegionInfoModel::sendEstateOwnerMessage(gMessageSystem, "simulatormessage", LLFloaterRegionInfo::getLastInvoice(), strings); } - else if(command == utf8str_tolower(sAscentCmdLineTeleportHome)) - { - gAgent.teleportHome(); - return false; - } - else if(command == utf8str_tolower(sAscentCmdLineRezPlatform)) + return false; + } + else if (cmd == utf8str_tolower(sSetNearbyChatChannelCmd)) // Set nearby chat channel + { + S32 chan; + if (input >> chan) { - F32 width; - if (i >> width) cmdline_rezplat(false, width); - else cmdline_rezplat(); + gSavedSettings.setS32("AlchemyNearbyChatChannel", chan); return false; } - else if(command == utf8str_tolower(sAscentCmdLineMapTo)) + } + else if (cmd == utf8str_tolower(sTeleportToCam)) + { + gAgent.teleportViaLocation(gAgentCamera.getCameraPositionGlobal()); + return false; + } + else if (cmd == utf8str_tolower(sHoverHeight)) // Hover height + { + F32 height; + if (input >> height) { - if (revised_text.length() > command.length() + 1) //Typing this command with no argument was causing a crash. -Madgeek - { - LLSLURL slurl(LLWeb::escapeURL(revised_text.substr(command.length()+1))); - - // The user wants to keep their position between MapTos and they have not passed a position (position is defaulted) - if (sAscentCmdLineMapToKeepPos && slurl.getPosition() == LLVector3(REGION_WIDTH_METERS/2, REGION_WIDTH_METERS/2, 0)) - { - LLVector3d agentPos = gAgent.getPositionGlobal(); - slurl = LLSLURL(slurl.getRegion(), LLVector3(fmod(agentPos.mdV[VX], (F64)REGION_WIDTH_METERS), fmod(agentPos.mdV[VY], (F64)REGION_WIDTH_METERS), agentPos.mdV[VZ])); - } - - LLUrlAction::teleportToLocation(LLWeb::escapeURL(std::string("secondlife:///app/teleport/")+slurl.getLocationString())); - } + gSavedPerAccountSettings.set("AvatarHoverOffsetZ", + llclamp(height, MIN_HOVER_Z, MAX_HOVER_Z)); return false; } - else if(command == utf8str_tolower(sAscentCmdLineCalc))//Cryogenic Blitz + } + else if (cmd == utf8str_tolower(sResyncAnimCommand)) // Resync Animations + { + resync_anims(); + return false; + } + else if (cmd == utf8str_tolower(sKeyToName)) + { + LLUUID targetKey; + if (input >> targetKey) { - bool success; - F32 result = 0.f; - if(revised_text.length() > command.length() + 1) + LLAvatarName av_name; + if (!LLAvatarNameCache::get(targetKey, &av_name)) { - - std::string expr = revised_text.substr(command.length()+1); - LLStringUtil::toUpper(expr); - success = LLCalc::getInstance()->evalString(expr, result); - - std::string out; - - if (!success) - { - out = "Calculation Failed"; - } - else - { - // Replace the expression with the result - std::ostringstream result_str; - result_str << expr; - result_str << " = "; - result_str << result; - out = result_str.str(); - } - cmdline_printchat(out); + LLAvatarNameCache::get(targetKey, boost::bind(spew_key_to_name, _1, _2)); return false; } + spew_key_to_name(targetKey, av_name); } - else if(command == utf8str_tolower(sAscentCmdLineTP2)) + return false; + } + else if (cmd == utf8str_tolower(sOfferTp)) + { + std::string avatarKey; +// LL_INFOS() << "CMD DEBUG 0 " << cmd << " " << avatarName << LL_ENDL; + if (input >> avatarKey) { - if (revised_text.length() > command.length() + 1) //Typing this command with no argument was causing a crash. -Madgeek +// LL_INFOS() << "CMD DEBUG 0 afterif " << cmd << " " << avatarName << LL_ENDL; + LLUUID tempUUID; + if (LLUUID::parseUUID(avatarKey, &tempUUID)) { - std::string name = revised_text.substr(command.length()+1); - cmdline_tp2name(name); + char buffer[DB_IM_MSG_BUF_SIZE * 2]; /* Flawfinder: ignore */ + std::string tpMsg="Join me!"; + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_StartLure); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_Info); + msg->addU8Fast(_PREHASH_LureType, (U8)0); + + msg->addStringFast(_PREHASH_Message, tpMsg); + msg->nextBlockFast(_PREHASH_TargetData); + msg->addUUIDFast(_PREHASH_TargetID, tempUUID); + gAgent.sendReliableMessage(); + snprintf(buffer,sizeof(buffer),"Offered TP to key %s",tempUUID.asString().c_str()); + cmdline_printchat(std::string(buffer)); + return false; } - return false; } - else if(command == utf8str_tolower(sSinguCmdLineAway)) + } + else if (cmd == utf8str_tolower(sTP2Command)) + { + if (data.length() > cmd.length() + 1) //Typing this cmd with no argument was causing a crash. -Madgeek { - handle_fake_away_status(NULL); - return false; + std::string name = data.substr(cmd.length()+1); + cmdline_tp2name(name); } - else if(command == utf8str_tolower(sSinguCmdLineURL)) - { - if (revised_text.length() > command.length() + 1) - { - LLUrlAction::clickAction(revised_text.substr(command.length()+1)); - } - return false; - } - else if(command == "typingstop") + return false; + } + else if (cmd == utf8str_tolower(sAwayCommand)) + { + handle_fake_away_status(NULL); + return false; + } + else if (cmd == utf8str_tolower(sURLCommand)) + { + if (data.length() > cmd.length() + 1) { - std::string text; - if(i >> text) + const std::string sub(data.substr(cmd.length()+1)); + LLUUID id; + if (id.parseUUID(sub, &id)) { - gChatBar->sendChatFromViewer(text, CHAT_TYPE_STOP, FALSE); + LLAvatarActions::showProfile(id); + return false; } + LLUrlAction::clickAction(sub, true); } - else if(command == utf8str_tolower(sAscentCmdLineClearChat)) + return false; + } + else if (cmd == utf8str_tolower(sSettingCommand)) + { + std::string control_name; + if (input >> control_name) { - LLFloaterChat* chat = LLFloaterChat::getInstance(LLSD()); - if(chat) + // Find out if this control even exists. + auto control = gSavedSettings.getControl(control_name); + if (!control) gSavedPerAccountSettings.getControl(control_name); + if (!control) return false; + + LLSD val; + // Toggle if we weren't given a value, + if (input.eof()) val = !control->get(); + else // otherwise use what we were given. { - LLViewerTextEditor* history_editor = chat->getChild("Chat History Editor"); - LLViewerTextEditor* history_editor_with_mute = chat->getChild("Chat History Editor with mute"); - history_editor->clear(); - history_editor_with_mute->clear(); - return false; + switch (control->type()) // Convert to the right type, we can't be a string forever. + { + case TYPE_U32: // Integer is Integer, sucks but whatever + case TYPE_S32: + { + LLSD::Integer i; + input >> i; + val = i; + break; + } + case TYPE_F32: + { + LLSD::Float f; + input >> f; + val = f; + break; + } + case TYPE_STRING: + { + LLSD::String str; + std::getline(input, str, '\0'); // Read the entire rest of the stream into str + LLStringUtil::trim(str); // There's no setting where a space would be necessary here. + val = str; + break; + } + default: // Just parse it like JSON (or accept one of the many boolean value options! + LLSDSerialize::fromNotation(val, input, LLSDSerialize::SIZE_UNLIMITED); + } } + control->set(val); } - else if(command == "invrepair") + return false; + } + else if (cmd == "typingstop") + { + std::string text; + if (input >> text) { - invrepair(); + gChatBar->sendChatFromViewer(text, CHAT_TYPE_STOP, FALSE); } + return false; + } + else if (cmd == "invrepair") + { + invrepair(); + return false; + } #ifdef PROF_CTRL_CALLS - else if(command == "dumpcalls") + else if (cmd == "dumpcalls") + { + LLControlGroup::key_iter it = LLControlGroup::beginKeys(); + LLControlGroup::key_iter end = LLControlGroup::endKeys(); + for(;it!=end;++it) { - LLControlGroup::key_iter it = LLControlGroup::beginKeys(); - LLControlGroup::key_iter end = LLControlGroup::endKeys(); - for(;it!=end;++it) + ProfCtrlListAccum list; + LLControlGroup::getInstance(*it)->applyToAll(&list); + std::sort(list.mVariableList.begin(),list.mVariableList.end(),sort_calls); + LL_INFOS() << *it << ": lookup count (" << gFrameCount << "frames)" << LL_ENDL; + for(U32 i = 0;iapplyToAll(&list); - std::sort(list.mVariableList.begin(),list.mVariableList.end(),sort_calls); - LL_INFOS("") << *it << ": lookup count (" << gFrameCount << "frames)" << LL_ENDL; - for(U32 i = 0;i avatars; + uuid_vec_t avatars; std::string av_name; LLStringUtil::toLower(partial_name); LLWorld::getInstance()->getAvatars(&avatars); - typedef std::vector::const_iterator av_iter; - bool has_avatarlist = LLFloaterAvatarList::instanceExists(); - if(has_avatarlist) - LLFloaterAvatarList::getInstance()->updateAvatarList(); - for(av_iter i = avatars.begin(); i != avatars.end(); ++i) + auto radar = (LLFloaterAvatarList::instanceExists() ? LLFloaterAvatarList::getInstance() : nullptr); + for(const auto& id : avatars) { - if(has_avatarlist) - { - LLAvatarListEntry* entry = LLFloaterAvatarList::getInstance()->getAvatarEntry(*i); - if(entry) - { - av_name = entry->getName(); - } - } - if (av_name.empty() && !gCacheName->getFullName(*i, av_name)) - { - LLVOAvatar *avatarp = gObjectList.findAvatar(*i); - if(avatarp) - { - av_name = avatarp->getFullname(); - } - } + if (LLAvatarListEntry* entry = radar ? radar->getAvatarEntry(id) : nullptr) + av_name = entry->getName(); + else if (gCacheName->getFullName(id, av_name)); + else if (LLVOAvatar* avatarp = gObjectList.findAvatar(id)) + av_name = avatarp->getFullname(); + else + continue; LLStringUtil::toLower(av_name); - if(strstr(av_name.c_str(), partial_name.c_str())) - { - return *i; - } + if (av_name.find(partial_name) != std::string::npos) + return id; } return LLUUID::null; } - void cmdline_tp2name(std::string target) { LLUUID avkey = cmdline_partial_name2key(target); - if(avkey.isNull()) + if (avkey.isNull()) { cmdline_printchat("Avatar not found."); return; } LLFloaterAvatarList* avlist = LLFloaterAvatarList::instanceExists() ? LLFloaterAvatarList::getInstance() : NULL; LLVOAvatar* avatarp = gObjectList.findAvatar(avkey); - if(avatarp) + if (avatarp) { LLVector3d pos = avatarp->getPositionGlobal(); pos.mdV[VZ] += 2.0; gAgent.teleportViaLocation(pos); } - else if(avlist) + else if (avlist) { LLAvatarListEntry* entry = avlist->getAvatarEntry(avkey); - if(entry) + if (entry) { LLVector3d pos = entry->getPosition(); pos.mdV[VZ] += 2.0; @@ -556,63 +699,38 @@ void cmdline_tp2name(std::string target) } } -void cmdline_rezplat(bool use_saved_value, F32 visual_radius) //cmdline_rezplat() will still work... just will use the saved value +void cmdline_printchat(const std::string& message) { - LLVector3 agentPos = gAgent.getPositionAgent()+(gAgent.getVelocity()*(F32)0.333); - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_ObjectAdd); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID()); - msg->nextBlockFast(_PREHASH_ObjectData); - msg->addU8Fast(_PREHASH_PCode, LL_PCODE_VOLUME); - msg->addU8Fast(_PREHASH_Material, LL_MCODE_METAL); - - if(agentPos.mV[2] > 4096.0) - msg->addU32Fast(_PREHASH_AddFlags, FLAGS_CREATE_SELECTED); - else - msg->addU32Fast(_PREHASH_AddFlags, 0); - - LLVolumeParams volume_params; - - volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_CIRCLE_33 ); - volume_params.setRatio( 2, 2 ); - volume_params.setShear( 0, 0 ); - volume_params.setTaper(2.0f,2.0f); - volume_params.setTaperX(0.f); - volume_params.setTaperY(0.f); - - LLVolumeMessage::packVolumeParams(&volume_params, msg); - LLVector3 rezpos = agentPos - LLVector3(0.0f,0.0f,2.5f); - LLQuaternion rotation; - rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis); - - if (use_saved_value) - { - visual_radius = gSavedSettings.getF32("AscentPlatformSize"); - } - - F32 realsize = visual_radius / 3.0f; - if (realsize < 0.01f) realsize = 0.01f; - else if (realsize > 10.0f) realsize = 10.0f; - - msg->addVector3Fast(_PREHASH_Scale, LLVector3(0.01f,realsize,realsize) ); - msg->addQuatFast(_PREHASH_Rotation, rotation ); - msg->addVector3Fast(_PREHASH_RayStart, rezpos ); - msg->addVector3Fast(_PREHASH_RayEnd, rezpos ); - msg->addU8Fast(_PREHASH_BypassRaycast, (U8)1 ); - msg->addU8Fast(_PREHASH_RayEndIsIntersection, (U8)FALSE ); - msg->addU8Fast(_PREHASH_State, 0); - msg->addUUIDFast(_PREHASH_RayTargetID, LLUUID::null ); - msg->sendReliable(gAgent.getRegionHost()); + LLChat chat(message); + chat.mSourceType = CHAT_SOURCE_SYSTEM; + if (rlv_handler_t::isEnabled()) chat.mRlvLocFiltered = chat.mRlvNamesFiltered = true; + LLFloaterChat::addChat(chat); } -void cmdline_printchat(std::string message) +static void fake_local_chat(LLChat chat, const std::string& name) +{ + chat.mFromName = name; + chat.mText = name + chat.mText; + LLFloaterChat::addChat(chat); +} +void fake_local_chat(std::string msg) { - LLChat chat; - chat.mText = message; + bool action(LLStringUtil::startsWith(msg, "/me") && (msg[3] == ' ' || msg[3] == '\'')); + if (action) msg.erase(0, 4); + LLChat chat((action ? " " : ": ") + msg); + chat.mFromID = gAgentID; chat.mSourceType = CHAT_SOURCE_SYSTEM; - LLFloaterChat::addChat(chat, FALSE, FALSE); + if (rlv_handler_t::isEnabled()) chat.mRlvLocFiltered = chat.mRlvNamesFiltered = true; + chat.mPosAgent = gAgent.getPositionAgent(); + chat.mURL = LLAvatarActions::getSLURL(gAgentID); + if (action) chat.mChatStyle = CHAT_STYLE_IRC; + if (!LLAvatarNameCache::getNSName(gAgentID, chat.mFromName)) + { + LLAvatarNameCache::get(gAgentID, boost::bind(fake_local_chat, chat, boost::bind(&LLAvatarName::getNSName, _2, main_name_system()))); + } + else + { + chat.mText = chat.mFromName + chat.mText; + LLFloaterChat::addChat(chat); + } } - diff --git a/indra/newview/chatbar_as_cmdline.h b/indra/newview/chatbar_as_cmdline.h index 3e1d37532c..3a7de8140d 100644 --- a/indra/newview/chatbar_as_cmdline.h +++ b/indra/newview/chatbar_as_cmdline.h @@ -29,8 +29,11 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#include "llviewerprecompiledheaders.h" +#ifndef MS_CHATBARCMDLINE_H +#define MS_CHATBARCMDLINE_H #include "llchatbar.h" bool cmd_line_chat(std::string revised_text, EChatType type); + +#endif \ No newline at end of file diff --git a/indra/newview/daeexport.cpp b/indra/newview/daeexport.cpp index d56d446aff..9f7ad6d7fc 100644 --- a/indra/newview/daeexport.cpp +++ b/indra/newview/daeexport.cpp @@ -1,84 +1,73 @@ /** - * @file daeexport.cpp - * @brief A system which allows saving in-world objects to Collada .DAE files for offline texturizing/shading. - * @authors Latif Khalifa - * - * $LicenseInfo:firstyear=2013&license=LGPLV2.1$ - * Copyright (C) 2013 Latif Khalifa - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * 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 - */ +* @file daeexport.cpp +* @brief A system which allows saving in-world objects to Collada .DAE files for offline texturizing/shading. +* @authors Latif Khalifa +* +* $LicenseInfo:firstyear=2013&license=LGPLV2.1$ +* Copyright (C) 2013 Latif Khalifa +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* 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 +*/ #include "llviewerprecompiledheaders.h" #include "daeexport.h" //colladadom includes -#if LL_MSVC -#pragma warning (disable : 4018) -#pragma warning (push) -#pragma warning (disable : 4068) -#pragma warning (disable : 4263) -#pragma warning (disable : 4264) -#endif -#pragma GCC diagnostic ignored "-Woverloaded-virtual" #include "dae.h" -//#include "dom.h" -#include "dom/domAsset.h" -#include "dom/domBind_material.h" #include "dom/domCOLLADA.h" -#include "dom/domConstants.h" -#include "dom/domController.h" -#include "dom/domEffect.h" -#include "dom/domGeometry.h" -#include "dom/domInstance_geometry.h" -#include "dom/domInstance_material.h" -#include "dom/domInstance_node.h" -#include "dom/domInstance_effect.h" -#include "dom/domMaterial.h" #include "dom/domMatrix.h" -#include "dom/domNode.h" -#include "dom/domProfile_COMMON.h" -#include "dom/domRotate.h" -#include "dom/domScale.h" -#include "dom/domTranslate.h" -#include "dom/domVisual_scene.h" -#if LL_MSVC -#pragma warning (pop) -#endif // library includes #include "aifilepicker.h" +#include "llavatarnamecache.h" #include "llnotificationsutil.h" -#include "boost/date_time/posix_time/posix_time.hpp" // newview includes #include "lfsimfeaturehandler.h" -#include "llface.h" -#include "llvovolume.h" -#include "llviewerinventory.h" #include "llinventorymodel.h" #include "llinventoryfunctions.h" +#include "llface.h" +#include "llversioninfo.h" +#include "llviewerinventory.h" +#include "llviewertexturelist.h" +#include "llvovolume.h" // menu includes #include "llevent.h" #include "llmemberlistener.h" -#include "llview.h" #include "llselectmgr.h" -#define ANY_FACE -1 +// Floater and UI +#include "llfloater.h" +#include "lluictrlfactory.h" +#include "llscrollcontainer.h" +#include "lltexturectrl.h" + +// Files and cache +#include "llcallbacklist.h" +#include "lldir.h" +#include "lltexturecache.h" +#include "llimage.h" +#include "llimagej2c.h" +#include "llimagepng.h" +#include "llimagetga.h" +#include "llimagebmp.h" +#include "llimagejpeg.h" + +#define TEXTURE_DOWNLOAD_TIMEOUT 60.0f extern LLUUID gAgentID; @@ -87,41 +76,53 @@ typedef LLMemberListener view_listener_t; namespace DAEExportUtil { - void saveImpl(DAESaver* daesaver, AIFilePicker* filepicker) - { - if (filepicker->hasFilename()) - { - const std::string selected_filename = filepicker->getFilename(); + const auto LL_TEXTURE_PLYWOOD = LLUUID("89556747-24cb-43ed-920b-47caed15465f"); + const auto LL_TEXTURE_BLANK = LLUUID("5748decc-f629-461c-9a36-a35a221fe21f"); + const auto LL_TEXTURE_INVISIBLE = LLUUID("38b86f85-2575-52a9-a531-23108d8da837"); + const auto LL_TEXTURE_TRANSPARENT = LLUUID("8dcd4a48-2d37-4909-9f78-f7a9eb4ef903"); + const auto LL_TEXTURE_MEDIA = LLUUID("8b5fec65-8d8d-9dc5-cda8-8fdf2716e361"); - daesaver->saveDAE(selected_filename); - LLNotificationsUtil::add("WavefrontExportSuccess", LLSD().with("FILENAME", selected_filename)); - } - else llwarns << "No file; bailing" << llendl; - - delete daesaver; - } - - void filePicker(DAESaver* daesaver, std::string name) + enum image_format_type { - AIFilePicker* filepicker = AIFilePicker::create(); - filepicker->open(name); - filepicker->run(boost::bind(&saveImpl, daesaver, filepicker)); - } + ft_tga, + ft_png, + ft_j2c, + ft_bmp, + ft_jpg + }; + + static const std::string image_format_ext[] = { "tga", "png", "j2c", "bmp", "jpg" }; - void onPartialExportConfirm(const LLSD& notification, const LLSD& response, DAESaver* daesaver, std::string name) + static bool canExportTexture(const LLUUID& id, std::string* name = NULL) { - if (LLNotificationsUtil::getSelectedOption(notification, response) == 0) // 0 - Proceed, first choice + // Find inventory items with asset id of the sculpt map + LLViewerInventoryCategory::cat_array_t cats; + LLViewerInventoryItem::item_array_t items; + LLAssetIDMatches asset_id_matches(id); + gInventory.collectDescendentsIf(LLUUID::null, + cats, + items, + LLInventoryModel::INCLUDE_TRASH, + asset_id_matches); + + // See if any of the inventory items matching this texture id are exportable + ExportPolicy policy = LFSimFeatureHandler::instance().exportPolicy(); + for (const auto& item : items) { - filePicker(daesaver, name); - } - else - { - delete daesaver; + const LLPermissions item_permissions = item->getPermissions(); + if (item_permissions.allowExportBy(gAgentID, policy)) + { + if (name) *name = item->getName(); + return true; + } } + + if (name) *name = id.getString(); + + return (policy & ep_full_perm) == ep_full_perm; } - // Identical to the one in awavefront.cpp - bool can_export_node(LLSelectNode* node) + static bool canExportNode(LLSelectNode* node) { LLPermissions* perms = node->mPermissions; // Is perms ever NULL? // This tests the PERM_EXPORT bit too, which is not really necessary (just checking if it's set @@ -135,94 +136,425 @@ namespace DAEExportUtil LLViewerObject* obj = node->getObject(); if (obj->isSculpted() && !obj->isMesh()) { - LLSculptParams *sculpt_params = (LLSculptParams *)obj->getParameterEntry(LLNetworkData::PARAMS_SCULPT); + const LLSculptParams *sculpt_params = obj->getSculptParams(); LLUUID sculpt_id = sculpt_params->getSculptTexture(); - - // Find inventory items with asset id of the sculpt map - LLViewerInventoryCategory::cat_array_t cats; - LLViewerInventoryItem::item_array_t items; - LLAssetIDMatches asset_id_matches(sculpt_id); - gInventory.collectDescendentsIf(LLUUID::null, - cats, - items, - LLInventoryModel::INCLUDE_TRASH, - asset_id_matches); - - // See if any of the inventory items matching this sculpt id are exportable - for (S32 i = 0; i < items.count(); i++) - { - const LLPermissions item_permissions = items[i]->getPermissions(); - if (item_permissions.allowExportBy(gAgentID, LFSimFeatureHandler::instance().exportPolicy())) - { - return true; - } - } - - return false; + return canExportTexture(sculpt_id); } else // not sculpt, we already checked generic permissions { return true; } } +} + - void saveSelectedObject() +class ColladaExportFloater + : public LLFloater +{ +private: + typedef std::map texture_list_t; + LLView* mExportBtn; + LLView* mFileName; + LLView* mTextureTypeCombo; + + DAESaver mSaver; + texture_list_t mTexturesToSave; + S32 mTotal; + S32 mNumTextures; + S32 mNumExportableTextures; + std::string mObjectName; + LLTimer mTimer; + LLUIString mTitleProgress; + +public: + ColladaExportFloater() + : LLFloater(std::string("Collada Export"), std::string("ColladaExportFloaterRect"), LLStringUtil::null) + { + mCommitCallbackRegistrar.add("ColladaExport.FilePicker", boost::bind(&ColladaExportFloater::onClickBrowse, this)); + mCommitCallbackRegistrar.add("ColladaExport.Export", boost::bind(&ColladaExportFloater::onClickExport, this)); + mCommitCallbackRegistrar.add("ColladaExport.TextureTypeCombo", boost::bind(&ColladaExportFloater::onTextureTypeCombo, this, boost::bind(&LLUICtrl::getControlName, _1), _2)); + mCommitCallbackRegistrar.add("ColladaExport.TextureExport", boost::bind(&ColladaExportFloater::onTextureExportCheck, this, _2)); + LLUICtrlFactory::getInstance()->buildFloater(this, "floater_dae_export.xml"); + + addSelectedObjects(); + if (LLUICtrl* ctrl = findChild("Object Name")) + { + ctrl->setTextArg("[NAME]", mObjectName); + } + if (LLUICtrl* ctrl = findChild("Exportable Prims")) + { + ctrl->setTextArg("[COUNT]", llformat("%d", mSaver.mObjects.size())); + ctrl->setTextArg("[TOTAL]", llformat("%d", mTotal)); + } + if (LLUICtrl* ctrl = findChild("Exportable Textures")) + { + ctrl->setTextArg("[COUNT]", llformat("%d", mNumExportableTextures)); + ctrl->setTextArg("[TOTAL]", llformat("%d", mNumTextures)); + } + addTexturePreview(); + } + + virtual ~ColladaExportFloater() + { + if (gIdleCallbacks.containsFunction(saveTexturesWorker, this)) + { + gIdleCallbacks.deleteFunction(saveTexturesWorker, this); + } + } + + BOOL postBuild() override + { + mFileName = getChildView("file name editor"); + mExportBtn = getChildView("export button"); + mTextureTypeCombo = getChildView("texture type combo"); + mTitleProgress = getString("texture_progress"); + + mTextureTypeCombo->setValue(gSavedSettings.getS32(mTextureTypeCombo->getControlName())); + onTextureExportCheck(getChildView("texture export check")->getValue()); + return TRUE; + } + + void updateTitleProgress() + { + mTitleProgress.setArg("COUNT", llformat("%d", mTexturesToSave.size())); + setTitle(mTitleProgress); + } + + void onTextureExportCheck(const LLSD& value) + { + mTextureTypeCombo->setEnabled(value); + } + + void onTextureTypeCombo(const std::string& control_name, const LLSD& value) + { + gSavedSettings.setS32(control_name, value); + } + + void onClickBrowse() { static const std::string file_ext = ".dae"; + AIFilePicker* filepicker = AIFilePicker::create(); + filepicker->open(mObjectName + file_ext); + filepicker->run(boost::bind(&ColladaExportFloater::onFilePicker, this, filepicker)); + } - if (LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection()) + void onFilePicker(AIFilePicker* filepicker) + { + if (filepicker->hasFilename()) { - DAESaver* daesaver = new DAESaver; // deleted in callback - daesaver->mOffset = -selection->getFirstRootObject()->getRenderPosition(); - S32 total = 0; - S32 included = 0; + mFileName->setValue(filepicker->getFilename()); + mExportBtn->setEnabled(TRUE); + } + } + + void onClickExport() + { + if (gSavedSettings.getBOOL("DAEExportTextures")) + { + saveTextures(); + } + else + { + onTexturesSaved(); + } + } + + void onTexturesSaved() + { + std::string selected_filename = mFileName->getValue(); + mSaver.saveDAE(selected_filename); + LLNotificationsUtil::add("WavefrontExportSuccess", LLSD().with("FILENAME", selected_filename)); + close(); + } + + void addSelectedObjects() + { + LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); + + if (selection && selection->getFirstRootObject()) + { + mSaver.mOffset = -selection->getFirstRootObject()->getRenderPosition(); + mObjectName = selection->getFirstRootNode()->mName; + mTotal = 0; for (LLObjectSelection::iterator iter = selection->begin(); iter != selection->end(); ++iter) { - total++; + mTotal++; LLSelectNode* node = *iter; - if (!node->getObject()->getVolume() || !can_export_node(node)) continue; - included++; - daesaver->Add(node->getObject(), node->mName); + if (!node->getObject()->getVolume() || !DAEExportUtil::canExportNode(node)) continue; + mSaver.add(node->getObject(), node->mName); } + } + + if (mSaver.mObjects.empty()) + { + LLNotificationsUtil::add("ExportFailed"); + close(); + } + else + { + mSaver.updateTextureInfo(); + mNumTextures = mSaver.mTextures.size(); + mNumExportableTextures = getNumExportableTextures(); + } + } + + S32 getNumExportableTextures() + { + S32 res = 0; + for (const auto& name : mSaver.mTextureNames) + { + if (!name.empty()) ++res; + } + + return res; + } + + void addTexturePreview() + { + S32 num_text = mNumExportableTextures; + if (num_text == 0) return; + + S32 img_width = 100; + S32 img_height = img_width + 15; + S32 panel_height = (num_text / 3 + 1) * (img_height) + 10; + LLScrollContainer* scroll_container = getChild("textures container"); + LLPanel* panel = new LLPanel(std::string(), LLRect(0, panel_height, 350, 0), false); + scroll_container->setScrolledView(panel); + scroll_container->addChild(panel); + panel->setEnabled(FALSE); + S32 img_nr = 0; + for (U32 i=0; i < mSaver.mTextures.size(); i++) + { + if (mSaver.mTextureNames[i].empty()) continue; + + S32 left = 16 + (img_nr % 3) * (img_width + 13); + S32 bottom = panel_height - (10 + (img_nr / 3 + 1) * (img_height)); + + LLRect rect(left, bottom + img_height, left + img_width, bottom); + LLTextureCtrl* img = new LLTextureCtrl(std::string(), rect, std::string(), mSaver.mTextures[i], LLUUID(), std::string()); + panel->addChild(img); + img_nr++; + } + } + + void saveTextures() + { + mTexturesToSave.clear(); + for (U32 i=0; i < mSaver.mTextures.size(); i++) + { + if (mSaver.mTextureNames[i].empty()) continue; + mTexturesToSave[mSaver.mTextures[i]] = mSaver.mTextureNames[i]; + } - if (daesaver->mObjects.empty()) + mSaver.mImageFormat = DAEExportUtil::image_format_ext[(S32)mTextureTypeCombo->getValue()]; + + LL_INFOS("ColladaExport") << "Starting to save textures" << LL_ENDL; + mTimer.setTimerExpirySec(TEXTURE_DOWNLOAD_TIMEOUT); + mTimer.start(); + updateTitleProgress(); + gIdleCallbacks.addFunction(saveTexturesWorker, this); + } + + class CacheReadResponder final : public LLTextureCache::ReadResponder + { + private: + LLPointer mFormattedImage; + LLUUID mID; + std::string mName; + S32 mImageType; + + public: + CacheReadResponder(const LLUUID& id, LLImageFormatted* image, std::string name, S32 img_type) + : mFormattedImage(image), mID(id), mName(name), mImageType(img_type) + { + setImage(image); + } + + void setData(U8* data, S32 datasize, S32 imagesize, S32 imageformat, BOOL imagelocal) + { + if (imageformat == IMG_CODEC_TGA && mFormattedImage->getCodec() == IMG_CODEC_J2C) { - LLNotificationsUtil::add("ExportFailed"); - delete daesaver; + LL_WARNS("ColladaExport") << "FAILED: texture " << mID << " is formatted as TGA. Not saving." << LL_ENDL; + mFormattedImage = NULL; + mImageSize = 0; return; } - if (total != included) + if (mFormattedImage.notNull()) + { + if (mFormattedImage->getCodec() == imageformat) + { + mFormattedImage->appendData(data, datasize); + } + else + { + LL_WARNS("ColladaExport") << "FAILED: texture " << mID << " in wrong format." << LL_ENDL; + mFormattedImage = NULL; + mImageSize = 0; + return; + } + } + else { - LLSD args; - args["TOTAL"] = total; - args["FAILED"] = total - included; - LLNotificationsUtil::add("WavefrontExportPartial", args, LLSD(), boost::bind(&onPartialExportConfirm, _1, _2, daesaver, selection->getFirstNode()->mName.c_str() + file_ext)); - return; + mFormattedImage = LLImageFormatted::createFromType(imageformat); + mFormattedImage->setData(data, datasize); } + mImageSize = imagesize; + mImageLocal = imagelocal; + } + + void completed(bool success) override + { + if (success && mFormattedImage.notNull() && mImageSize > 0) + { + bool ok = false; - filePicker(daesaver, selection->getFirstNode()->mName.c_str() + file_ext); + // If we are saving jpeg2000, no need to do anything, just write to disk + if (mImageType == DAEExportUtil::ft_j2c) + { + mName += "." + mFormattedImage->getExtension(); + ok = mFormattedImage->save(mName); + } + else + { + // For other formats we need to decode first + if (mFormattedImage->updateData() && (mFormattedImage->getWidth() * mFormattedImage->getHeight() * mFormattedImage->getComponents())) + { + LLPointer raw = new LLImageRaw; + raw->resize(mFormattedImage->getWidth(), mFormattedImage->getHeight(), mFormattedImage->getComponents()); + + if (mFormattedImage->decode(raw, 0)) + { + LLPointer img = NULL; + switch (mImageType) + { + case DAEExportUtil::ft_tga: + img = new LLImageTGA; + break; + case DAEExportUtil::ft_png: + img = new LLImagePNG; + break; + case DAEExportUtil::ft_bmp: + img = new LLImageBMP; + break; + case DAEExportUtil::ft_jpg: + img = new LLImageJPEG; + break; + } + + if (!img.isNull()) + { + if (img->encode(raw, 0)) + { + mName += "." + img->getExtension(); + ok = img->save(mName); + } + } + } + } + } + + if (ok) + { + LL_INFOS("ColladaExport") << "Saved texture to " << mName << LL_ENDL; + } + else + { + LL_WARNS("ColladaExport") << "FAILED to save texture " << mID << LL_ENDL; + } + } + else + { + LL_WARNS("ColladaExport") << "FAILED to save texture " << mID << LL_ENDL; + } } - return; - } + }; - class DAESaveSelectedObjects : public view_listener_t + static void saveTexturesWorker(void* data) { - bool handleEvent(LLPointer event, const LLSD& userdata) + ColladaExportFloater* me = (ColladaExportFloater *)data; + if (me->mTexturesToSave.size() == 0) { - saveSelectedObject(); - return true; + LL_INFOS("ColladaExport") << "Done saving textures" << LL_ENDL; + me->updateTitleProgress(); + gIdleCallbacks.deleteFunction(saveTexturesWorker, me); + me->mTimer.stop(); + me->onTexturesSaved(); + return; } - }; -} + LLUUID id = me->mTexturesToSave.begin()->first; + LLViewerTexture* imagep = LLViewerTextureManager::findFetchedTexture(id, TEX_LIST_STANDARD); + if (!imagep) + { + me->mTexturesToSave.erase(id); + me->updateTitleProgress(); + me->mTimer.reset(); + } + else + { + if (imagep->getDiscardLevel() == 0) // image download is complete + { + LL_INFOS("ColladaExport") << "Saving texture " << id << LL_ENDL; + LLImageFormatted* img = new LLImageJ2C; + S32 img_type = me->mTextureTypeCombo->getValue(); + std::string name = gDirUtilp->getDirName(me->mFileName->getValue()); + name += gDirUtilp->getDirDelimiter() + me->mTexturesToSave[id]; + CacheReadResponder* responder = new CacheReadResponder(id, img, name, img_type); + LLAppViewer::getTextureCache()->readFromCache(id, LLWorkerThread::PRIORITY_HIGH, 0, 999999, responder); + me->mTexturesToSave.erase(id); + me->updateTitleProgress(); + me->mTimer.reset(); + } + else if (me->mTimer.hasExpired()) + { + LL_WARNS("ColladaExport") << "Timed out downloading texture " << id << LL_ENDL; + me->mTexturesToSave.erase(id); + me->updateTitleProgress(); + me->mTimer.reset(); + } + } + } + +}; -void DAESaver::Add(const LLViewerObject* prim, const std::string name) +void DAESaver::add(const LLViewerObject* prim, const std::string name) { mObjects.push_back(std::pair((LLViewerObject*)prim, name)); } +void DAESaver::updateTextureInfo() +{ + mTextures.clear(); + mTextureNames.clear(); + + for (obj_info_t::iterator obj_iter = mObjects.begin(); obj_iter != mObjects.end(); ++obj_iter) + { + LLViewerObject* obj = obj_iter->first; + S32 num_faces = obj->getVolume()->getNumVolumeFaces(); + for (S32 face_num = 0; face_num < num_faces; ++face_num) + { + LLTextureEntry* te = obj->getTE(face_num); + const LLUUID id = te->getID(); + if (std::find(mTextures.begin(), mTextures.end(), id) != mTextures.end()) continue; + + mTextures.push_back(id); + std::string name; + if (id != DAEExportUtil::LL_TEXTURE_BLANK && DAEExportUtil::canExportTexture(id, &name)) + { + std::string safe_name = gDirUtilp->getScrubbedFileName(name); + std::replace(safe_name.begin(), safe_name.end(), ' ', '_'); + mTextureNames.push_back(safe_name); + } + else + { + mTextureNames.push_back(std::string()); + } + } + } +} + class v4adapt { private: @@ -235,7 +567,7 @@ class v4adapt } }; -void DAESaver::addSource(daeElement* mesh, const char* src_id, std::string params, const std::vector &vals) +void DAESaver::addSource(daeElement* mesh, const char* src_id, const std::string& params, const std::vector &vals) { daeElement* source = mesh->add("source"); source->setAttribute("id", src_id); @@ -244,9 +576,9 @@ void DAESaver::addSource(daeElement* mesh, const char* src_id, std::string param src_array->setAttribute("id", llformat("%s-%s", src_id, "array").c_str()); src_array->setAttribute("count", llformat("%d", vals.size()).c_str()); - for (S32 i = 0; i < vals.size(); i++) + for (const auto& val : vals) { - ((domFloat_array*)src_array)->getValue().append(vals[i]); + static_cast(src_array)->getValue().append(val); } domAccessor* acc = daeSafeCast(source->add("technique_common accessor")); @@ -254,15 +586,15 @@ void DAESaver::addSource(daeElement* mesh, const char* src_id, std::string param acc->setCount(vals.size() / params.size()); acc->setStride(params.size()); - for (std::string::iterator p_iter = params.begin(); p_iter != params.end(); ++p_iter) + for (const auto& param : params) { domElement* pX = acc->add("param"); - pX->setAttribute("name", llformat("%c", *p_iter).c_str()); + pX->setAttribute("name", (LLStringUtil::null + param).c_str()); pX->setAttribute("type", "float"); } } -void DAESaver::addPolygons(daeElement* mesh, const char* geomID, const char* materialID, LLViewerObject* obj, int face_to_include) +void DAESaver::addPolygons(daeElement* mesh, const char* geomID, const char* materialID, LLViewerObject* obj, int_list_t* faces_to_include) { domPolylist* polylist = daeSafeCast(mesh->add("polylist")); polylist->setMaterial(materialID); @@ -298,13 +630,15 @@ void DAESaver::addPolygons(daeElement* mesh, const char* geomID, const char* mat S32 num_tris = 0; for (S32 face_num = 0; face_num < obj->getVolume()->getNumVolumeFaces(); face_num++) { + if (skipFace(obj->getTE(face_num))) continue; + const LLVolumeFace* face = (LLVolumeFace*)&obj->getVolume()->getVolumeFace(face_num); - if (face_to_include == ANY_FACE || face_to_include == face_num) + if (faces_to_include == NULL || (std::find(faces_to_include->begin(), faces_to_include->end(), face_num) != faces_to_include->end())) { for (S32 i = 0; i < face->mNumIndices; i++) { - U16 index = index_offset + face->mIndices[i]; + U32 index = index_offset + face->mIndices[i]; (p->getValue()).append(index); if (i % 3 == 0) { @@ -318,16 +652,75 @@ void DAESaver::addPolygons(daeElement* mesh, const char* geomID, const char* mat polylist->setCount(num_tris); } +void DAESaver::transformTexCoord(S32 num_vert, LLVector2* coord, LLVector3* positions, LLVector3* normals, LLTextureEntry* te, LLVector3 scale) +{ + F32 cosineAngle = cos(te->getRotation()); + F32 sinAngle = sin(te->getRotation()); + + for (S32 ii=0; iigetTexGen()) + { + LLVector3 normal = normals[ii]; + LLVector3 pos = positions[ii]; + LLVector3 binormal; + F32 d = normal * LLVector3::x_axis; + if (d >= 0.5f || d <= -0.5f) + { + binormal = LLVector3::y_axis; + if (normal.mV[0] < 0) binormal *= -1.0f; + } + else + { + binormal = LLVector3::x_axis; + if (normal.mV[1] > 0) binormal *= -1.0f; + } + LLVector3 tangent = binormal % normal; + LLVector3 scaledPos = pos.scaledVec(scale); + coord[ii].mV[0] = 1.f + ((binormal * scaledPos) * 2.f - 0.5f); + coord[ii].mV[1] = -((tangent * scaledPos) * 2.f - 0.5f); + } + + F32 repeatU; + F32 repeatV; + te->getScale(&repeatU, &repeatV); + F32 tX = coord[ii].mV[0] - 0.5f; + F32 tY = coord[ii].mV[1] - 0.5f; + + F32 offsetU; + F32 offsetV; + te->getOffset(&offsetU, &offsetV); + + coord[ii].mV[0] = (tX * cosineAngle + tY * sinAngle) * repeatU + offsetU + 0.5f; + coord[ii].mV[1] = (-tX * sinAngle + tY * cosineAngle) * repeatV + offsetV + 0.5f; + } +} + bool DAESaver::saveDAE(std::string filename) { + // Collada expects file and folder names to be escaped + // Note: cdom::nativePathToUri() + // Same as in LLDAELoader::OpenFile() + const char* allowed = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789" + "%-._~:\"|\\/"; + std::string uri_filename = LLURI::escape(filename, allowed); + + mAllMaterials.clear(); + mTotalNumMaterials = 0; DAE dae; // First set the filename to save - daeElement* root = dae.add(filename); + daeElement* root = dae.add(uri_filename); // Obligatory elements in header daeElement* asset = root->add("asset"); // Get ISO format time - std::string date = boost::posix_time::to_iso_extended_string(boost::posix_time::second_clock::local_time()); + time_t rawtime; + time(&rawtime); + struct tm* utc_time = gmtime(&rawtime); + std::string date = llformat("%04d-%02d-%02dT%02d:%02d:%02d", utc_time->tm_year + 1900, utc_time->tm_mon + 1, utc_time->tm_mday, utc_time->tm_hour, utc_time->tm_min, utc_time->tm_sec); daeElement* created = asset->add("created"); created->setCharData(date); daeElement* modified = asset->add("modified"); @@ -339,10 +732,15 @@ bool DAESaver::saveDAE(std::string filename) up_axis->setCharData("Z_UP"); // File creator + std::string author; + if (!LLAvatarNameCache::getNSName(gAgentID, author)) + author = "Unknown"; + daeElement* contributor = asset->add("contributor"); - contributor->add("author")->setCharData("Singularity User"); - contributor->add("authoring_tool")->setCharData("Singularity Viewer Collada Export"); + contributor->add("author")->setCharData(author); + contributor->add("authoring_tool")->setCharData(LLVersionInfo::getChannelAndVersion() + " Collada Export"); + daeElement* images = root->add("library_images"); daeElement* geomLib = root->add("library_geometries"); daeElement* effects = root->add("library_effects"); daeElement* materials = root->add("library_materials"); @@ -350,6 +748,11 @@ bool DAESaver::saveDAE(std::string filename) scene->setAttribute("id", "Scene"); scene->setAttribute("name", "Scene"); + if (gSavedSettings.getBOOL("DAEExportTextures")) + { + generateImagesSection(images); + } + S32 prim_nr = 0; for (obj_info_t::iterator obj_iter = mObjects.begin(); obj_iter != mObjects.end(); ++obj_iter) @@ -369,16 +772,37 @@ bool DAESaver::saveDAE(std::string filename) std::vector position_data; std::vector normal_data; std::vector uv_data; + bool applyTexCoord = gSavedSettings.getBOOL("DAEExportTextureParams"); S32 num_faces = obj->getVolume()->getNumVolumeFaces(); - for (S32 face_num = 0; face_num < num_faces; face_num++) { + if (skipFace(obj->getTE(face_num))) continue; + const LLVolumeFace* face = (LLVolumeFace*)&obj->getVolume()->getVolumeFace(face_num); total_num_vertices += face->mNumVertices; v4adapt verts(face->mPositions); v4adapt norms(face->mNormals); + + LLVector2* newCoord = NULL; + + if (applyTexCoord) + { + newCoord = new LLVector2[face->mNumVertices]; + LLVector3* newPos = new LLVector3[face->mNumVertices]; + LLVector3* newNormal = new LLVector3[face->mNumVertices]; + for (S32 i = 0; i < face->mNumVertices; i++) + { + newPos[i] = verts[i]; + newNormal[i] = norms[i]; + newCoord[i] = face->mTexCoords[i]; + } + transformTexCoord(face->mNumVertices, newCoord, newPos, newNormal, obj->getTE(face_num), obj->getScale()); + delete[] newPos; + delete[] newNormal; + } + for (S32 i=0; i < face->mNumVertices; i++) { const LLVector3 v = verts[i]; @@ -391,13 +815,18 @@ bool DAESaver::saveDAE(std::string filename) normal_data.push_back(n.mV[VY]); normal_data.push_back(n.mV[VZ]); - const LLVector2 uv = face->mTexCoords[i]; + const LLVector2 uv = applyTexCoord ? newCoord[i] : face->mTexCoords[i]; + uv_data.push_back(uv.mV[VX]); uv_data.push_back(uv.mV[VY]); } + + if (applyTexCoord) + { + delete[] newCoord; + } } - - + addSource(mesh, llformat("%s-%s", geomID, "positions").c_str(), "XYZ", position_data); addSource(mesh, llformat("%s-%s", geomID, "normals").c_str(), "XYZ", normal_data); addSource(mesh, llformat("%s-%s", geomID, "map0").c_str(), "ST", uv_data); @@ -411,33 +840,30 @@ bool DAESaver::saveDAE(std::string filename) verticesInput->setAttribute("source", llformat("#%s-%s", geomID, "positions").c_str()); } - // Add triangles - for (S32 face_num = 0; face_num < num_faces; face_num++) - { - addPolygons(mesh, geomID, llformat("%s-f%d-%s", geomID, face_num, "material").c_str(), obj, face_num); - } + material_list_t objMaterials; + getMaterials(obj, &objMaterials); - // Effects (face color, alpha) - for (S32 face_num = 0; face_num < num_faces; face_num++) + // Add triangles + if (gSavedSettings.getBOOL("DAEExportConsolidateMaterials")) { - LLTextureEntry* te = obj->getTE(face_num); - LLColor4 color = te->getColor(); - domEffect* effect = (domEffect*)effects->add("effect"); - effect->setId(llformat("%s-f%d-%s", geomID, face_num, "fx").c_str()); - daeElement* t = effect->add("profile_COMMON technique"); - t->setAttribute("sid", "common"); - domElement* phong = t->add("phong"); - phong->add("diffuse color")->setCharData(llformat("%f %f %f %f", color.mV[0], color.mV[1], color.mV[2], color.mV[3]).c_str()); - phong->add("transparency float")->setCharData(llformat("%f", color.mV[3]).c_str()); + for (const auto& objMaterial : objMaterials) + { + int_list_t faces; + getFacesWithMaterial(obj, objMaterial, &faces); + addPolygons(mesh, geomID, (objMaterial.name + "-material").c_str(), obj, &faces); + } } - - // Materials - for (S32 face_num = 0; face_num < num_faces; face_num++) + else { - domMaterial* mat = (domMaterial*)materials->add("material"); - mat->setId(llformat("%s-f%d-%s", geomID, face_num, "material").c_str()); - domElement* matEffect = mat->add("instance_effect"); - matEffect->setAttribute("url", llformat("#%s-f%d-%s", geomID, face_num, "fx").c_str()); + S32 mat_nr = 0; + for (S32 face_num = 0; face_num < num_faces; face_num++) + { + if (skipFace(obj->getTE(face_num))) continue; + int_list_t faces; + faces.push_back(face_num); + std::string matName = objMaterials[mat_nr++].name; + addPolygons(mesh, geomID, (matName + "-material").c_str(), obj, &faces); + } } daeElement* node = scene->add("node"); @@ -462,16 +888,30 @@ bool DAESaver::saveDAE(std::string filename) // Bind materials daeElement* tq = nodeGeometry->add("bind_material technique_common"); - for (S32 face_num = 0; face_num < num_faces; face_num++) + for (const auto& objMaterial : objMaterials) { daeElement* instanceMaterial = tq->add("instance_material"); - instanceMaterial->setAttribute("symbol", llformat("%s-f%d-%s", geomID, face_num, "material").c_str()); - instanceMaterial->setAttribute("target", llformat("#%s-f%d-%s", geomID, face_num, "material").c_str()); + std::string matName = objMaterial.name + "-material"; + instanceMaterial->setAttribute("symbol", matName.c_str()); + instanceMaterial->setAttribute("target", ('#' + matName).c_str()); } nodeGeometry->setAttribute("url", llformat("#%s-%s", geomID, "mesh").c_str()); } + + // Effects (face texture, color, alpha) + generateEffects(effects); + + // Materials + for (const auto& objMaterial : mAllMaterials) + { + daeElement* mat = materials->add("material"); + mat->setAttribute("id", (objMaterial.name + "-material").c_str()); + daeElement* matEffect = mat->add("instance_effect"); + matEffect->setAttribute("url", ('#' + objMaterial.name + "-fx").c_str()); + } + root->add("scene instance_visual_scene")->setAttribute("url", "#Scene"); return dae.writeAll(); @@ -480,8 +920,148 @@ bool DAESaver::saveDAE(std::string filename) DAESaver::DAESaver() {} +bool DAESaver::skipFace(LLTextureEntry *te) +{ + return (gSavedSettings.getBOOL("DAEExportSkipTransparent") + && (te->getColor().mV[3] < 0.01f || te->getID() == DAEExportUtil::LL_TEXTURE_TRANSPARENT)); +} + +DAESaver::MaterialInfo DAESaver::getMaterial(LLTextureEntry* te) +{ + if (gSavedSettings.getBOOL("DAEExportConsolidateMaterials")) + { + for (const auto& mat : mAllMaterials) + { + if (mat.matches(te)) + { + return mat; + } + } + } + + MaterialInfo ret; + ret.textureID = te->getID(); + ret.color = te->getColor(); + ret.name = llformat("Material%d", mAllMaterials.size()); + mAllMaterials.push_back(ret); + return ret; +} + +void DAESaver::getMaterials(LLViewerObject* obj, material_list_t* ret) +{ + S32 num_faces = obj->getVolume()->getNumVolumeFaces(); + for (S32 face_num = 0; face_num < num_faces; ++face_num) + { + LLTextureEntry* te = obj->getTE(face_num); + + if (skipFace(te)) continue; + + MaterialInfo mat = getMaterial(te); + + if (!gSavedSettings.getBOOL("DAEExportConsolidateMaterials") || std::find(ret->begin(), ret->end(), mat) == ret->end()) + { + ret->push_back(mat); + } + } +} + +void DAESaver::getFacesWithMaterial(LLViewerObject* obj, const MaterialInfo& mat, int_list_t* ret) +{ + S32 num_faces = obj->getVolume()->getNumVolumeFaces(); + for (S32 face_num = 0; face_num < num_faces; ++face_num) + { + if (mat == getMaterial(obj->getTE(face_num))) + { + ret->push_back(face_num); + } + } +} + +void DAESaver::generateEffects(daeElement *effects) +{ + // Effects (face color, alpha) + bool export_textures = gSavedSettings.getBOOL("DAEExportTextures"); + + for (const auto& mat : mAllMaterials) + { + LLColor4 color = mat.color; + domEffect* effect = (domEffect*)effects->add("effect"); + effect->setId((mat.name + "-fx").c_str()); + daeElement* profile = effect->add("profile_COMMON"); + std::string colladaName; + + if (export_textures) + { + LLUUID textID; + U32 i = 0; + for (; i < mTextures.size(); i++) + { + if (mat.textureID == mTextures[i]) + { + textID = mTextures[i]; + break; + } + } + + if (!textID.isNull() && !mTextureNames[i].empty()) + { + colladaName = mTextureNames[i] + "_" + mImageFormat; + daeElement* newparam = profile->add("newparam"); + newparam->setAttribute("sid", (colladaName + "-surface").c_str()); + daeElement* surface = newparam->add("surface"); + surface->setAttribute("type", "2D"); + surface->add("init_from")->setCharData(colladaName.c_str()); + newparam = profile->add("newparam"); + newparam->setAttribute("sid", (colladaName + "-sampler").c_str()); + newparam->add("sampler2D source")->setCharData((colladaName + "-surface").c_str()); + } + } + + daeElement* t = profile->add("technique"); + t->setAttribute("sid", "common"); + domElement* phong = t->add("phong"); + domElement* diffuse = phong->add("diffuse"); + // Only one or can appear inside diffuse element + if (!colladaName.empty()) + { + daeElement* txtr = diffuse->add("texture"); + txtr->setAttribute("texture", (colladaName + "-sampler").c_str()); + txtr->setAttribute("texcoord", colladaName.c_str()); + } + else + { + daeElement* diffuseColor = diffuse->add("color"); + diffuseColor->setAttribute("sid", "diffuse"); + diffuseColor->setCharData(llformat("%f %f %f %f", color.mV[0], color.mV[1], color.mV[2], color.mV[3]).c_str()); + phong->add("transparency float")->setCharData(llformat("%f", color.mV[3]).c_str()); + } + } +} + +void DAESaver::generateImagesSection(daeElement* images) +{ + for (const auto& name : mTextureNames) + { + if (name.empty()) continue; + std::string colladaName = name + '_' + mImageFormat; + daeElement* image = images->add("image"); + image->setAttribute("id", colladaName.c_str()); + image->setAttribute("name", colladaName.c_str()); + image->add("init_from")->setCharData(LLURI::escape(name + '.' + mImageFormat)); + } +} + +class DAESaveSelectedObjects final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) + { + (new ColladaExportFloater())->open(); + return true; + } +}; + void addMenu(view_listener_t* menu, const std::string& name); void add_dae_listeners() // Called in llviewermenu with other addMenu calls, function linked against { - addMenu(new DAEExportUtil::DAESaveSelectedObjects(), "Object.SaveAsDAE"); + addMenu(new DAESaveSelectedObjects(), "Object.SaveAsDAE"); } diff --git a/indra/newview/daeexport.h b/indra/newview/daeexport.h index 3bfcf2ec60..1f79aa17af 100644 --- a/indra/newview/daeexport.h +++ b/indra/newview/daeexport.h @@ -1,48 +1,89 @@ /** - * @file daeexport.h - * @brief A system which allows saving in-world objects to Collada .DAE files for offline texturizing/shading. - * @authors Latif Khalifa - * - * $LicenseInfo:firstyear=2013&license=LGPLV2.1$ - * Copyright (C) 2013 Latif Khalifa - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * 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 - */ +* @file daeexport.h +* @brief A system which allows saving in-world objects to Collada .DAE files for offline texturizing/shading. +* @authors Latif Khalifa +* +* $LicenseInfo:firstyear=2013&license=LGPLV2.1$ +* Copyright (C) 2013 Latif Khalifa +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* 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 +*/ #ifndef DAEEXPORT_H_ #define DAEEXPORT_H_ #include +#include "lltextureentry.h" class LLViewerObject; class DAESaver { - typedef std::vector > obj_info_t; - public: + struct MaterialInfo + { + LLUUID textureID; + LLColor4 color; + std::string name; + + bool matches(LLTextureEntry* te) const + { + return (textureID == te->getID()) && (color == te->getColor()); + } + + bool operator== (const MaterialInfo& rhs) const + { + return (textureID == rhs.textureID) && (color == rhs.color) && (name == rhs.name); + } + + bool operator!= (const MaterialInfo& rhs) const + { + return !(*this == rhs); + } + }; + + typedef std::vector> obj_info_t; + typedef uuid_vec_t id_list_t; + typedef std::vector string_list_t; + typedef std::vector int_list_t; + typedef std::vector material_list_t; + + material_list_t mAllMaterials; + id_list_t mTextures; + string_list_t mTextureNames; obj_info_t mObjects; LLVector3 mOffset; + std::string mImageFormat; + S32 mTotalNumMaterials; + DAESaver(); - void Add(const LLViewerObject* prim, const std::string name); + void updateTextureInfo(); + void add(const LLViewerObject* prim, const std::string name); bool saveDAE(std::string filename); private: - void addSource(daeElement* mesh, const char* src_id, std::string params, const std::vector &vals); - void addPolygons(daeElement* mesh, const char* geomID, const char* materialID, LLViewerObject* obj, int face_to_include); + void transformTexCoord(S32 num_vert, LLVector2* coord, LLVector3* positions, LLVector3* normals, LLTextureEntry* te, LLVector3 scale); + void addSource(daeElement* mesh, const char* src_id, const std::string& params, const std::vector &vals); + void addPolygons(daeElement* mesh, const char* geomID, const char* materialID, LLViewerObject* obj, int_list_t* faces_to_include); + bool skipFace(LLTextureEntry *te); + MaterialInfo getMaterial(LLTextureEntry* te); + void getMaterials(LLViewerObject* obj, material_list_t* ret); + void getFacesWithMaterial(LLViewerObject* obj, const MaterialInfo& mat, int_list_t* ret); + void generateEffects(daeElement *effects); + void generateImagesSection(daeElement* images); }; #endif // DAEEXPORT_H_ diff --git a/indra/newview/featuretable.txt b/indra/newview/featuretable.txt index fc9a175d92..90dd093875 100644 --- a/indra/newview/featuretable.txt +++ b/indra/newview/featuretable.txt @@ -90,7 +90,7 @@ RenderTerrainDetail 1 0 RenderTerrainScale 1 12.0 RenderTerrainLODFactor 1 1 RenderTransparentWater 1 0 -RenderTreeLODFactor 1 0 +RenderTreeLODFactor 1 0.125 RenderUseImpostors 1 1 RenderVolumeLODFactor 1 1.125 VertexShaderEnable 1 0 @@ -155,7 +155,7 @@ RenderTerrainDetail 1 1 RenderTerrainScale 1 7.0 RenderTerrainLODFactor 1 2.0 RenderTransparentWater 1 1 -RenderTreeLODFactor 1 0.5 +RenderTreeLODFactor 1 1.0 RenderUseImpostors 1 1 RenderVolumeLODFactor 1 1.125 VertexShaderEnable 1 1 @@ -186,7 +186,7 @@ RenderTerrainDetail 1 1 RenderTerrainScale 1 5.0 RenderTerrainLODFactor 1 2.0 RenderTransparentWater 1 1 -RenderTreeLODFactor 1 1.0 +RenderTreeLODFactor 1 2.0 RenderUseImpostors 1 1 RenderVolumeLODFactor 1 2.0 VertexShaderEnable 1 1 @@ -301,6 +301,10 @@ RenderObjectBump 0 0 list OpenGLPre15 RenderVBOEnable 1 0 +list OpenGLPre21 +RenderAvatarVP 0 0 +RenderAvatarCloth 0 0 + list OpenGLPre30 RenderDeferred 0 0 RenderMaxTextureIndex 1 1 @@ -486,6 +490,7 @@ Disregard128DefaultDrawDistance 1 0 list ATIOldDriver RenderAvatarVP 0 0 RenderAvatarCloth 0 0 +RenderDeferred 0 0 // ATI cards generally perform better when not using VBOs for streaming data @@ -596,3 +601,7 @@ RenderShaderLightingMaxLevel 1 2 list NVIDIA_GeForce_Go_7900 RenderShaderLightingMaxLevel 1 2 +list VertexUniformsLT1024 +RenderAvatarVP 0 0 +RenderAvatarCloth 0 0 +RenderDeferred 0 0 diff --git a/indra/newview/featuretable_linux.txt b/indra/newview/featuretable_linux.txt index bc464b0fd2..043d448665 100644 --- a/indra/newview/featuretable_linux.txt +++ b/indra/newview/featuretable_linux.txt @@ -1,4 +1,4 @@ -version 27 +version 28 // NOTE: This is mostly identical to featuretable_mac.txt with a few differences // Should be combined into one table @@ -87,7 +87,7 @@ RenderTerrainDetail 1 0 RenderTerrainScale 1 12.0 RenderTerrainLODFactor 1 1 RenderTransparentWater 1 0 -RenderTreeLODFactor 1 0 +RenderTreeLODFactor 1 0.125 RenderUseImpostors 1 1 RenderVolumeLODFactor 1 0.5 VertexShaderEnable 1 0 @@ -151,7 +151,7 @@ RenderTerrainDetail 1 1 RenderTerrainScale 1 7.0 RenderTerrainLODFactor 1 2.0 RenderTransparentWater 1 1 -RenderTreeLODFactor 1 0.5 +RenderTreeLODFactor 1 1.0 RenderUseImpostors 1 1 RenderVolumeLODFactor 1 1.125 VertexShaderEnable 1 1 @@ -184,7 +184,7 @@ RenderTerrainDetail 1 1 RenderTerrainScale 1 5.0 RenderTerrainLODFactor 1 2.0 RenderTransparentWater 1 1 -RenderTreeLODFactor 1 1.0 +RenderTreeLODFactor 1 2.0 RenderUseImpostors 1 1 RenderVolumeLODFactor 1 2.0 VertexShaderEnable 1 1 @@ -301,7 +301,12 @@ RenderObjectBump 0 0 list OpenGLPre15 RenderVBOEnable 1 0 -list Intel +list OpenGLPre21 +RenderAvatarVP 0 0 +RenderAvatarCloth 0 0 +RenderDeferred 0 0 + +list IntelPre30 RenderAnisotropic 1 0 // Avoid some Intel crashes on Linux RenderCubeMap 0 0 @@ -458,6 +463,7 @@ Disregard128DefaultDrawDistance 1 0 list ATIOldDriver RenderAvatarVP 0 0 RenderAvatarCloth 0 0 +RenderDeferred 0 0 // Avoid driver crashes with some features on Linux with old ATI drivers UseOcclusion 0 0 WindLightUseAtmosShaders 0 0 @@ -563,3 +569,7 @@ RenderShaderLightingMaxLevel 1 2 list NVIDIA_GeForce_Go_7900 RenderShaderLightingMaxLevel 1 2 +list VertexUniformsLT1024 +RenderAvatarVP 0 0 +RenderAvatarCloth 0 0 +RenderDeferred 0 0 \ No newline at end of file diff --git a/indra/newview/featuretable_mac.txt b/indra/newview/featuretable_mac.txt index 16e50377e1..c097b42fd2 100644 --- a/indra/newview/featuretable_mac.txt +++ b/indra/newview/featuretable_mac.txt @@ -57,7 +57,7 @@ WindLightUseAtmosShaders 1 1 WLSkyDetail 1 128 Disregard128DefaultDrawDistance 1 1 Disregard96DefaultDrawDistance 1 1 -RenderTextureMemoryMultiple 1 0.5 +RenderTextureMemoryMultiple 1 1.0 RenderShaderLightingMaxLevel 1 3 RenderDeferred 1 1 RenderDeferredSSAO 1 1 @@ -90,7 +90,7 @@ RenderTerrainDetail 1 0 RenderTerrainScale 1 12.0 RenderTerrainLODFactor 1 1 RenderTransparentWater 1 0 -RenderTreeLODFactor 1 0 +RenderTreeLODFactor 1 0.125 RenderUseImpostors 1 1 RenderVolumeLODFactor 1 0.5 VertexShaderEnable 1 0 @@ -155,7 +155,7 @@ RenderTerrainDetail 1 1 RenderTerrainScale 1 7.0 RenderTerrainLODFactor 1 2.0 RenderTransparentWater 1 1 -RenderTreeLODFactor 1 0.5 +RenderTreeLODFactor 1 1.0 RenderUseImpostors 1 1 RenderVolumeLODFactor 1 1.125 VertexShaderEnable 1 1 @@ -188,7 +188,7 @@ RenderTerrainDetail 1 1 RenderTerrainScale 1 5.0 RenderTerrainLODFactor 1 2.0 RenderTransparentWater 1 1 -RenderTreeLODFactor 1 1.0 +RenderTreeLODFactor 1 2.0 RenderUseImpostors 1 1 RenderVolumeLODFactor 1 2.0 VertexShaderEnable 1 1 @@ -296,6 +296,11 @@ RenderObjectBump 0 0 list OpenGLPre15 RenderVBOEnable 1 0 +list OpenGLPre21 +RenderAvatarVP 0 0 +RenderAvatarCloth 0 0 +RenderDeferred 0 0 + list TexUnit8orLess RenderDeferredSSAO 0 0 @@ -390,7 +395,7 @@ list ATI_Mobility_Radeon_9600 Disregard96DefaultDrawDistance 1 0 list NVIDIA_GeForce_8600 -RenderTextureMemoryMultiple 1 0.375 +RenderTextureMemoryMultiple 1 1 RenderUseImpostors 0 0 UseOcclusion 0 0 @@ -521,3 +526,7 @@ Disregard128DefaultDrawDistance 1 0 list NVIDIA_GeForce_Go_7400 Disregard128DefaultDrawDistance 1 0 +list VertexUniformsLT1024 +RenderAvatarVP 0 0 +RenderAvatarCloth 0 0 +RenderDeferred 0 0 \ No newline at end of file diff --git a/indra/newview/floaterao.cpp b/indra/newview/floaterao.cpp index c9386d95a7..973c4e233e 100644 --- a/indra/newview/floaterao.cpp +++ b/indra/newview/floaterao.cpp @@ -1,79 +1,61 @@ -/** +/** * @file llfloaterao.cpp - * @brief clientside animation overrider - * by Skills Hak + * @brief clientside animation overrider floater + * by Skills Hak & Liru Frs */ #include "llviewerprecompiledheaders.h" #include "floaterao.h" +#include "aosystem.h" #include "llagent.h" -#include "llagentcamera.h" -#include "llvoavatarself.h" -#include "llanimationstates.h" -#include "lluictrlfactory.h" -#include "llstartup.h" -#include "llpreviewnotecard.h" -#include "llviewertexteditor.h" -#include "llcheckboxctrl.h" #include "llcombobox.h" -#include "llspinctrl.h" -#include "chatbar_as_cmdline.h" -//#include "llfloaterchat.h" #include "llfirstuse.h" -#include "lltrans.h" - -#include "llinventory.h" -#include "llinventoryfunctions.h" #include "llinventorypanel.h" -#include "llinventorymodelbackgroundfetch.h" +#include "llmemorystream.h" +#include "llpreviewnotecard.h" +#include "lltexteditor.h" +#include "lluictrlfactory.h" #include "roles_constants.h" -#include "llviewerregion.h" - -#include "llpanelobjectinventory.h" -#include "llinventorybridge.h" - -#include "llboost.h" -#include // Uncomment and use instead if we ever add the chatbar as a command line - MC -void cmdline_printchat(std::string message); +void cmdline_printchat(const std::string& message); -class AONotecardCallback : public LLInventoryCallback +class AONotecardCallback final : public LLInventoryCallback { public: - AONotecardCallback(std::string &filename) - { - mFileName = filename; - } + AONotecardCallback(const std::string& filename) : mFileName(filename) {} - void fire(const LLUUID &inv_item) + void fire(const LLUUID &inv_item) override { if (!mFileName.empty()) { - LLPreviewNotecard* nc; - nc = (LLPreviewNotecard*)LLPreview::find(inv_item); - if(nc) + auto nc = (LLPreviewNotecard*)LLPreview::show(inv_item); + if (!nc) + { + auto item = gInventory.getItem(inv_item); + open_notecard(item, "Note: " + item->getName(), LLUUID::null, false); + nc = (LLPreviewNotecard*)LLPreview::find(inv_item); + } + + if (nc) { - nc->open(); - LLTextEditor *text = nc->getEditor(); - if (text) + if (LLTextEditor *text = nc->getEditor()) { text->clear(); text->makePristine(); std::ifstream file(mFileName.c_str()); - + std::string line; while (!file.eof()) - { + { getline(file, line); - line = line + "\n"; - text->insertText(line); + text->insertText(line + '\n'); } file.close(); - + nc->saveIfNeeded(); } } @@ -84,1245 +66,169 @@ class AONotecardCallback : public LLInventoryCallback std::string mFileName; }; -AOInvTimer* gAOInvTimer = NULL; - - -// ------------------------------------------------------- - -AOStandTimer* mAOStandTimer; - -AOStandTimer::AOStandTimer() : LLEventTimer( gSavedSettings.getF32("AOStandInterval") ) -{ - AOStandTimer::tick(); -} -AOStandTimer::~AOStandTimer() -{ -// llinfos << "dead" << llendl; -} -void AOStandTimer::reset() -{ - mPeriod = gSavedSettings.getF32("AOStandInterval"); - mEventTimer.reset(); -// llinfos << "reset" << llendl; -} -BOOL AOStandTimer::tick() -{ - LLFloaterAO::stand_iterator++; -// llinfos << "tick" << llendl; - LLFloaterAO::ChangeStand(); - return FALSE; -// return LLFloaterAO::ChangeStand(); //timer is always active now .. -} - -// ------------------------------------------------------- - -AOInvTimer::AOInvTimer() : LLEventTimer( (F32)1.0 ) -{ -} -AOInvTimer::~AOInvTimer() -{ -} -BOOL AOInvTimer::tick() -{ - if (!(gSavedSettings.getBOOL("AOEnabled"))) return TRUE; - if(LLStartUp::getStartupState() >= STATE_INVENTORY_SEND) - { - if(LLInventoryModelBackgroundFetch::instance().isEverythingFetched()) - { -// cmdline_printchat("Inventory fetched, loading AO."); - LLFloaterAO::init(); - return TRUE; - } - } - return FALSE; -} - -// STUFF ------------------------------------------------------- - -int LLFloaterAO::mAnimationState = 0; -int LLFloaterAO::stand_iterator = 0; - -LLUUID LLFloaterAO::invfolderid = LLUUID::null; -LLUUID LLFloaterAO::mCurrentStandId = LLUUID::null; - -LLComboBox* mcomboBox_stands; -LLComboBox* mcomboBox_walks; -LLComboBox* mcomboBox_runs; -LLComboBox* mcomboBox_jumps; -LLComboBox* mcomboBox_sits; -LLComboBox* mcomboBox_gsits; -LLComboBox* mcomboBox_crouchs; -LLComboBox* mcomboBox_cwalks; -LLComboBox* mcomboBox_falls; -LLComboBox* mcomboBox_hovers; -LLComboBox* mcomboBox_flys; -LLComboBox* mcomboBox_flyslows; -LLComboBox* mcomboBox_flyups; -LLComboBox* mcomboBox_flydowns; -LLComboBox* mcomboBox_lands; -LLComboBox* mcomboBox_standups; -LLComboBox* mcomboBox_prejumps; - -struct struct_overrides -{ - LLUUID orig_id; - LLUUID ao_id; - int state; -}; -std::vector mAOOverrides; - -struct struct_stands -{ - LLUUID ao_id; - std::string anim_name; -}; -std::vector mAOStands; - -struct struct_tokens -{ - std::string token; - int state; -}; -std::vector mAOTokens; - -LLFloaterAO* LLFloaterAO::sInstance = NULL; - -LLFloaterAO::LLFloaterAO() -:LLFloater(std::string("floater_ao")) -{ -// init(); - llassert_always(sInstance == NULL); - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_ao.xml"); - sInstance = this; -} -LLFloaterAO::~LLFloaterAO() +LLFloaterAO::LLFloaterAO(const LLSD&) : LLFloater("floater_ao") +, mCombos({}) { - sInstance=NULL; - mcomboBox_stands = 0; - mcomboBox_walks = 0; - mcomboBox_runs = 0; - mcomboBox_jumps = 0; - mcomboBox_sits = 0; - mcomboBox_gsits = 0; - mcomboBox_crouchs = 0; - mcomboBox_cwalks = 0; - mcomboBox_falls = 0; - mcomboBox_hovers = 0; - mcomboBox_flys = 0; - mcomboBox_flyslows = 0; - mcomboBox_flyups = 0; - mcomboBox_flydowns = 0; - mcomboBox_lands = 0; - mcomboBox_standups = 0; - mcomboBox_prejumps = 0; -// llinfos << "floater destroyed" << llendl; + LLUICtrlFactory::getInstance()->buildFloater(this, "floater_ao.xml", nullptr, false); } -void LLFloaterAO::show(void*) +void LLFloaterAO::onOpen() { - if (!sInstance) - { - sInstance = new LLFloaterAO(); - updateLayout(sInstance); - init(); - - sInstance->open(); - } - else - { - sInstance->close(); - } LLFirstUse::useAO(); } -bool LLFloaterAO::getInstance() +LLFloaterAO::~LLFloaterAO() { - if (sInstance) - return true; - else - return false; +// LL_INFOS() << "floater destroyed" << LL_ENDL; } BOOL LLFloaterAO::postBuild() { - childSetAction("more_btn", onClickMore, this); - childSetAction("less_btn", onClickLess, this); - - childSetAction("reloadcard",onClickReloadCard,this); - childSetAction("opencard",onClickOpenCard,this); - childSetAction("newcard",onClickNewCard,this); - childSetAction("prevstand",onClickPrevStand,this); - childSetAction("nextstand",onClickNextStand,this); - getChild("AOEnabled")->setCommitCallback(boost::bind(&LLFloaterAO::onClickToggleAO)); - getChild("AOSitsEnabled")->setCommitCallback(boost::bind(&LLFloaterAO::onClickToggleSits)); - getChild("standtime")->setCommitCallback(boost::bind(&LLFloaterAO::onSpinnerCommit,_1)); - mcomboBox_stands = getChild("stands"); - mcomboBox_walks = getChild("walks"); - mcomboBox_runs = getChild("runs"); - mcomboBox_jumps = getChild("jumps"); - mcomboBox_sits = getChild("sits"); - mcomboBox_gsits = getChild("gsits"); - mcomboBox_crouchs = getChild("crouchs"); - mcomboBox_cwalks = getChild("cwalks"); - mcomboBox_falls = getChild("falls"); - mcomboBox_hovers = getChild("hovers"); - mcomboBox_flys = getChild("flys"); - mcomboBox_flyslows = getChild("flyslows"); - mcomboBox_flyups = getChild("flyups"); - mcomboBox_flydowns = getChild("flydowns"); - mcomboBox_lands = getChild("lands"); - mcomboBox_standups = getChild("standups"); - mcomboBox_prejumps = getChild("prejumps"); - getChild("stands")->setCommitCallback(boost::bind(&LLFloaterAO::onComboBoxCommit,_1)); - getChild("walks")->setCommitCallback(boost::bind(&LLFloaterAO::onComboBoxCommit,_1)); - getChild("runs")->setCommitCallback(boost::bind(&LLFloaterAO::onComboBoxCommit,_1)); - getChild("jumps")->setCommitCallback(boost::bind(&LLFloaterAO::onComboBoxCommit,_1)); - getChild("sits")->setCommitCallback(boost::bind(&LLFloaterAO::onComboBoxCommit,_1)); - getChild("gsits")->setCommitCallback(boost::bind(&LLFloaterAO::onComboBoxCommit,_1)); - getChild("crouchs")->setCommitCallback(boost::bind(&LLFloaterAO::onComboBoxCommit,_1)); - getChild("cwalks")->setCommitCallback(boost::bind(&LLFloaterAO::onComboBoxCommit,_1)); - getChild("falls")->setCommitCallback(boost::bind(&LLFloaterAO::onComboBoxCommit,_1)); - getChild("hovers")->setCommitCallback(boost::bind(&LLFloaterAO::onComboBoxCommit,_1)); - getChild("flys")->setCommitCallback(boost::bind(&LLFloaterAO::onComboBoxCommit,_1)); - getChild("flyslows")->setCommitCallback(boost::bind(&LLFloaterAO::onComboBoxCommit,_1)); - getChild("flyups")->setCommitCallback(boost::bind(&LLFloaterAO::onComboBoxCommit,_1)); - getChild("flydowns")->setCommitCallback(boost::bind(&LLFloaterAO::onComboBoxCommit,_1)); - getChild("lands")->setCommitCallback(boost::bind(&LLFloaterAO::onComboBoxCommit,_1)); - getChild("standups")->setCommitCallback(boost::bind(&LLFloaterAO::onComboBoxCommit,_1)); - getChild("prejumps")->setCommitCallback(boost::bind(&LLFloaterAO::onComboBoxCommit,_1)); - - return TRUE; -} - -void LLFloaterAO::onSpinnerCommit(LLUICtrl* ctrl) -{ - LLSpinCtrl* spin = (LLSpinCtrl*) ctrl; - if(spin) - { - if (spin->getName() == "standtime") - { - if (mAOStandTimer) mAOStandTimer->reset(); - } - } -} - -void LLFloaterAO::onComboBoxCommit(LLUICtrl* ctrl) -{ - LLComboBox* box = (LLComboBox*)ctrl; - if(box) - { - if (box->getName() == "stands") - { - stand_iterator = box->getCurrentIndex(); - cmdline_printchat(llformat("Changing stand to %s.",mAOStands[stand_iterator].anim_name.c_str())); - ChangeStand(); - } - else - { - int state = STATE_AGENT_IDLE; - std::string stranim = box->getValue().asString(); -// llinfos << "state " << (gAgentAvatarp->isSitting()) << " - " << getAnimationState() << llendl; - if (box->getName() == "walks") - { - gAgent.sendAnimationRequest(GetAnimID(ANIM_AGENT_WALK), ANIM_REQUEST_STOP); - gSavedPerAccountSettings.setString("AODefaultWalk",stranim); - state = STATE_AGENT_WALK; - } - else if (box->getName() == "runs") - { - gAgent.sendAnimationRequest(GetAnimID(ANIM_AGENT_RUN), ANIM_REQUEST_STOP); - gSavedPerAccountSettings.setString("AODefaultRun",stranim); - state = STATE_AGENT_RUN; - } - else if (box->getName() == "jumps") - { - gAgent.sendAnimationRequest(GetAnimID(ANIM_AGENT_JUMP), ANIM_REQUEST_STOP); - gSavedPerAccountSettings.setString("AODefaultJump",stranim); - state = STATE_AGENT_JUMP; - } - else if (box->getName() == "sits") - { - if (gAgentAvatarp && (gSavedSettings.getBOOL("AOEnabled")) && (gSavedSettings.getBOOL("AOSitsEnabled"))) - { - if ((gAgentAvatarp->isSitting()) && (getAnimationState() == STATE_AGENT_SIT)) - { -// llinfos << "sitting " << GetAnimID(ANIM_AGENT_SIT) << " " << getAssetIDByName(stranim) << llendl; - gAgent.sendAnimationRequest(GetAnimID(ANIM_AGENT_SIT), ANIM_REQUEST_STOP); - gAgent.sendAnimationRequest(getAssetIDByName(stranim), ANIM_REQUEST_START); - } - } - gSavedPerAccountSettings.setString("AODefaultSit",stranim); - state = STATE_AGENT_SIT; - } - else if (box->getName() == "gsits") - { -// llinfos << "gsitting " << GetAnimID(ANIM_AGENT_SIT_GROUND) << " " << getAssetIDByName(stranim) << llendl; - if (gAgentAvatarp) - { - if ((gAgentAvatarp->isSitting()) && (getAnimationState() == STATE_AGENT_GROUNDSIT)) - { -// llinfos << "gsitting " << GetAnimID(ANIM_AGENT_SIT_GROUND) << " " << getAssetIDByName(stranim) << llendl; - gAgent.sendAnimationRequest(GetAnimID(ANIM_AGENT_SIT_GROUND), ANIM_REQUEST_STOP); - gAgent.sendAnimationRequest(getAssetIDByName(stranim), ANIM_REQUEST_START); - } - } - gSavedPerAccountSettings.setString("AODefaultGroundSit",stranim); - state = STATE_AGENT_GROUNDSIT; - } - else if (box->getName() == "crouchs") - { - gAgent.sendAnimationRequest(GetAnimID(ANIM_AGENT_CROUCH), ANIM_REQUEST_STOP); - gSavedPerAccountSettings.setString("AODefaultCrouch",stranim); - state = STATE_AGENT_CROUCH; - } - else if (box->getName() == "cwalks") - { - gAgent.sendAnimationRequest(GetAnimID(ANIM_AGENT_CROUCHWALK), ANIM_REQUEST_STOP); - gSavedPerAccountSettings.setString("AODefaultCrouchWalk",stranim); - state = STATE_AGENT_CROUCHWALK; - } - else if (box->getName() == "falls") - { - gAgent.sendAnimationRequest(GetAnimID(ANIM_AGENT_FALLDOWN), ANIM_REQUEST_STOP); - gSavedPerAccountSettings.setString("AODefaultFall",stranim); - state = STATE_AGENT_FALLDOWN; - } - else if (box->getName() == "hovers") - { - gAgent.sendAnimationRequest(GetAnimID(ANIM_AGENT_HOVER), ANIM_REQUEST_STOP); - gSavedPerAccountSettings.setString("AODefaultHover",stranim); - state = STATE_AGENT_HOVER; - } - else if (box->getName() == "flys") - { - gAgent.sendAnimationRequest(GetAnimID(ANIM_AGENT_FLY), ANIM_REQUEST_STOP); - gSavedPerAccountSettings.setString("AODefaultFly",stranim); - state = STATE_AGENT_FLY; - } - else if (box->getName() == "flyslows") - { - gAgent.sendAnimationRequest(GetAnimID(ANIM_AGENT_FLYSLOW), ANIM_REQUEST_STOP); - gSavedPerAccountSettings.setString("AODefaultFlySlow",stranim); - state = STATE_AGENT_FLYSLOW; + gSavedSettings.getControl("AOAdvanced")->getSignal()->connect(boost::bind(&LLFloaterAO::updateLayout, this, _2)); + + getChild("reloadcard")->setCommitCallback(boost::bind(&LLFloaterAO::onClickReloadCard, this)); + getChild("opencard")->setCommitCallback(boost::bind(&LLFloaterAO::onClickOpenCard, this)); + getChild("newcard")->setCommitCallback(boost::bind(&LLFloaterAO::onClickNewCard, this)); + getChild("prevstand")->setCommitCallback(boost::bind(&LLFloaterAO::onClickCycleStand, this, false)); + getChild("nextstand")->setCommitCallback(boost::bind(&LLFloaterAO::onClickCycleStand, this, true)); + getChild("standtime")->setCommitCallback(boost::bind(&LLFloaterAO::onSpinnerCommit, this)); + + auto ao = AOSystem::getIfExists(); + const auto& cb = boost::bind(&LLFloaterAO::onComboBoxCommit, this, _1); + const auto& setup_combo = [&](const std::string& name, const AOState& state) { + if (auto combo = findChild(name)) + { + combo->setCommitCallback(cb); + LLControlVariablePtr setting = nullptr; + if (auto aop = ao ? ao->mAOOverrides[state] : nullptr) + setting = aop->setting; + else // AO is down or missing override struct(why?), try getting from UI + setting = combo->getControl(combo->getControlName()); + if (setting) combo->add(setting->get().asStringRef(), ADD_BOTTOM, true); + mCombos[state] = combo; + } + }; + setup_combo("stands", STATE_AGENT_IDLE); + setup_combo("walks", STATE_AGENT_WALK); + setup_combo("runs", STATE_AGENT_RUN); + setup_combo("prejumps", STATE_AGENT_PRE_JUMP); + setup_combo("jumps", STATE_AGENT_JUMP); + setup_combo("turnlefts", STATE_AGENT_TURNLEFT); + setup_combo("turnrights", STATE_AGENT_TURNRIGHT); + setup_combo("sits", STATE_AGENT_SIT); + setup_combo("gsits", STATE_AGENT_SIT_GROUND); + setup_combo("hovers", STATE_AGENT_HOVER); + setup_combo("flydowns", STATE_AGENT_HOVER_DOWN); + setup_combo("flyups", STATE_AGENT_HOVER_UP); + setup_combo("crouchs", STATE_AGENT_CROUCH); + setup_combo("cwalks", STATE_AGENT_CROUCHWALK); + setup_combo("falls", STATE_AGENT_FALLDOWN); + setup_combo("standups", STATE_AGENT_STANDUP); + setup_combo("lands", STATE_AGENT_LAND); + setup_combo("flys", STATE_AGENT_FLY); + setup_combo("flyslows", STATE_AGENT_FLYSLOW); + setup_combo("typings", STATE_AGENT_TYPE); + setup_combo("swimdowns", STATE_AGENT_SWIM_DOWN); + setup_combo("swimups", STATE_AGENT_SWIM_UP); + setup_combo("swims", STATE_AGENT_SWIM); + setup_combo("floats", STATE_AGENT_FLOAT); + + updateLayout(gSavedSettings.getBOOL("AOAdvanced")); + AOSystem::requestConfigNotecard(false); + + return true; +} + +void LLFloaterAO::updateLayout(bool advanced) +{ + reshape(advanced ? 800 : 200, getRect().getHeight()); + childSetVisible("tabcontainer", advanced); +} + +void LLFloaterAO::onSpinnerCommit() const +{ + if (auto ao = AOSystem::getIfExists()) + ao->mAOStandTimer.reset(); +} + +void LLFloaterAO::onComboBoxCommit(LLUICtrl* ctrl) const +{ + if (LLComboBox* box = (LLComboBox*)ctrl) + { + std::string stranim = box->getValue().asString(); + if (auto ao = AOSystem::getIfExists()) + { + if (box == mCombos[STATE_AGENT_IDLE]) + { + ao->stand_iterator = box->getCurrentIndex(); + llassert(ao->stand_iterator < ao->mAOStands.size()); + const auto& name = ao->mAOStands[ao->stand_iterator].anim_name; + llassert(name == box->getValue().asStringRef()); + cmdline_printchat("Changing stand to " + name + '.'); + ao->updateStand(); + ao->mAOStandTimer.reset(); } - else if (box->getName() == "flyups") - { - gAgent.sendAnimationRequest(GetAnimID(ANIM_AGENT_HOVER_UP), ANIM_REQUEST_STOP); - gSavedPerAccountSettings.setString("AODefaultFlyUp",stranim); - state = STATE_AGENT_HOVER_UP; - } - else if (box->getName() == "flydowns") - { - gAgent.sendAnimationRequest(GetAnimID(ANIM_AGENT_HOVER_DOWN), ANIM_REQUEST_STOP); - gSavedPerAccountSettings.setString("AODefaultFlyDown",stranim); - state = STATE_AGENT_HOVER_DOWN; - } - else if (box->getName() == "lands") - { - gAgent.sendAnimationRequest(GetAnimID(ANIM_AGENT_LAND), ANIM_REQUEST_STOP); - gSavedPerAccountSettings.setString("AODefaultLand",stranim); - state = STATE_AGENT_LAND; - } - else if (box->getName() == "standups") - { - gAgent.sendAnimationRequest(GetAnimID(ANIM_AGENT_STAND), ANIM_REQUEST_STOP); - gSavedPerAccountSettings.setString("AODefaultStandUp",stranim); - state = STATE_AGENT_STAND; - } - else if (box->getName() == "prejumps") - { - gAgent.sendAnimationRequest(GetAnimID(ANIM_AGENT_PRE_JUMP), ANIM_REQUEST_STOP); - gSavedPerAccountSettings.setString("AODefaultPreJump",stranim); - state = STATE_AGENT_PRE_JUMP; - } - for (std::vector::iterator iter = mAOOverrides.begin(); iter != mAOOverrides.end(); ++iter) - { - if (state == iter->state) - { - iter->ao_id = getAssetIDByName(stranim); - } - } - } - } -} - -void LLFloaterAO::updateLayout(LLFloaterAO* floater) -{ - if (floater) - { - BOOL advanced = gSavedSettings.getBOOL( "AOAdvanced"); - if (advanced) - { - floater->reshape(610,380); //view->getRect().getWidth(), view->getUIWinHeightLong()); - } - else - { - floater->reshape(200,380); //view->getRect().getWidth(), view->getUIWinHeightShort()); - } - - floater->childSetVisible("more_btn", !advanced); - floater->childSetVisible("less_btn", advanced); - - floater->childSetVisible("tabcontainer", advanced); - floater->childSetVisible("tabdefaultanims", advanced); - - floater->childSetVisible("textdefaultwalk", advanced); - floater->childSetVisible("textdefaultrun", advanced); - floater->childSetVisible("textdefaultjump", advanced); - floater->childSetVisible("textdefaultsit", advanced); - floater->childSetVisible("textdefaultgsit", advanced); - floater->childSetVisible("textdefaultcrouch", advanced); - floater->childSetVisible("textdefaultcrouchwalk", advanced); - floater->childSetVisible("textdefaultfall", advanced); - floater->childSetVisible("textdefaulthover", advanced); - floater->childSetVisible("textdefaultfly", advanced); - floater->childSetVisible("textdefaultflyslow", advanced); - floater->childSetVisible("textdefaultflyup", advanced); - floater->childSetVisible("textdefaultflydown", advanced); - floater->childSetVisible("textdefaultland", advanced); - floater->childSetVisible("textdefaultstandup", advanced); - floater->childSetVisible("textdefaultprejump", advanced); - - - floater->childSetVisible("walks", advanced); - floater->childSetVisible("runs", advanced); - floater->childSetVisible("jumps", advanced); - floater->childSetVisible("sits", advanced); - floater->childSetVisible("gsits", advanced); - floater->childSetVisible("crouchs", advanced); - floater->childSetVisible("falls", advanced); - floater->childSetVisible("hovers", advanced); - floater->childSetVisible("flys", advanced); - floater->childSetVisible("flyslows", advanced); - floater->childSetVisible("flyups", advanced); - floater->childSetVisible("flydowns", advanced); - floater->childSetVisible("lands", advanced); - floater->childSetVisible("standups", advanced); - floater->childSetVisible("prejumps", advanced); - } -} - -void LLFloaterAO::init() -{ - mAOStands.clear(); - mAOTokens.clear(); - mAOOverrides.clear(); - - struct_tokens tokenloader; - tokenloader.token = - tokenloader.token = "[ Sitting On Ground ]"; tokenloader.state = STATE_AGENT_GROUNDSIT; mAOTokens.push_back(tokenloader); // 0 - tokenloader.token = "[ Sitting ]"; tokenloader.state = STATE_AGENT_SIT; mAOTokens.push_back(tokenloader); // 1 - tokenloader.token = "[ Crouching ]"; tokenloader.state = STATE_AGENT_CROUCH; mAOTokens.push_back(tokenloader); // 3 - tokenloader.token = "[ Crouch Walking ]"; tokenloader.state = STATE_AGENT_CROUCHWALK; mAOTokens.push_back(tokenloader); // 4 - tokenloader.token = "[ Standing Up ]"; tokenloader.state = STATE_AGENT_STANDUP; mAOTokens.push_back(tokenloader); // 6 - tokenloader.token = "[ Falling ]"; tokenloader.state = STATE_AGENT_FALLDOWN; mAOTokens.push_back(tokenloader); // 7 - tokenloader.token = "[ Flying Down ]"; tokenloader.state = STATE_AGENT_HOVER_DOWN; mAOTokens.push_back(tokenloader); // 8 - tokenloader.token = "[ Flying Up ]"; tokenloader.state = STATE_AGENT_HOVER_UP; mAOTokens.push_back(tokenloader); // 9 - tokenloader.token = "[ Flying Slow ]"; tokenloader.state = STATE_AGENT_FLYSLOW; mAOTokens.push_back(tokenloader); // 10 - tokenloader.token = "[ Flying ]"; tokenloader.state = STATE_AGENT_FLY; mAOTokens.push_back(tokenloader); // 11 - tokenloader.token = "[ Hovering ]"; tokenloader.state = STATE_AGENT_HOVER; mAOTokens.push_back(tokenloader); // 12 - tokenloader.token = "[ Jumping ]"; tokenloader.state = STATE_AGENT_JUMP; mAOTokens.push_back(tokenloader); // 13 - tokenloader.token = "[ Pre Jumping ]"; tokenloader.state = STATE_AGENT_PRE_JUMP; mAOTokens.push_back(tokenloader); // 14 - tokenloader.token = "[ Running ]"; tokenloader.state = STATE_AGENT_RUN; mAOTokens.push_back(tokenloader); // 15 - tokenloader.token = "[ Turning Right ]"; tokenloader.state = STATE_AGENT_TURNRIGHT; mAOTokens.push_back(tokenloader); // 16 - tokenloader.token = "[ Turning Left ]"; tokenloader.state = STATE_AGENT_TURNLEFT; mAOTokens.push_back(tokenloader); // 17 - tokenloader.token = "[ Walking ]"; tokenloader.state = STATE_AGENT_WALK; mAOTokens.push_back(tokenloader); // 18 - tokenloader.token = "[ Landing ]"; tokenloader.state = STATE_AGENT_LAND; mAOTokens.push_back(tokenloader); // 19 - tokenloader.token = "[ Standing ]"; tokenloader.state = STATE_AGENT_STAND; mAOTokens.push_back(tokenloader); // 20 - tokenloader.token = "[ Swimming Down ]"; tokenloader.state = 999; mAOTokens.push_back(tokenloader); // 21 - tokenloader.token = "[ Swimming Up ]"; tokenloader.state = 999; mAOTokens.push_back(tokenloader); // 22 - tokenloader.token = "[ Swimming Forward ]"; tokenloader.state = 999; mAOTokens.push_back(tokenloader); // 23 - tokenloader.token = "[ Floating ]"; tokenloader.state = 999; mAOTokens.push_back(tokenloader); // 24 - - struct_overrides overrideloader; - overrideloader.orig_id = ANIM_AGENT_WALK; overrideloader.ao_id = LLUUID::null; overrideloader.state = STATE_AGENT_WALK; mAOOverrides.push_back(overrideloader); - overrideloader.orig_id = ANIM_AGENT_RUN; overrideloader.ao_id = LLUUID::null; overrideloader.state = STATE_AGENT_RUN; mAOOverrides.push_back(overrideloader); - overrideloader.orig_id = ANIM_AGENT_PRE_JUMP; overrideloader.ao_id = LLUUID::null; overrideloader.state = STATE_AGENT_PRE_JUMP; mAOOverrides.push_back(overrideloader); - overrideloader.orig_id = ANIM_AGENT_JUMP; overrideloader.ao_id = LLUUID::null; overrideloader.state = STATE_AGENT_JUMP; mAOOverrides.push_back(overrideloader); - overrideloader.orig_id = ANIM_AGENT_TURNLEFT; overrideloader.ao_id = LLUUID::null; overrideloader.state = STATE_AGENT_TURNLEFT; mAOOverrides.push_back(overrideloader); - overrideloader.orig_id = ANIM_AGENT_TURNRIGHT; overrideloader.ao_id = LLUUID::null; overrideloader.state = STATE_AGENT_TURNRIGHT; mAOOverrides.push_back(overrideloader); - - overrideloader.orig_id = ANIM_AGENT_SIT; overrideloader.ao_id = LLUUID::null; overrideloader.state = STATE_AGENT_SIT; mAOOverrides.push_back(overrideloader); - overrideloader.orig_id = ANIM_AGENT_SIT_FEMALE; overrideloader.ao_id = LLUUID::null; overrideloader.state = STATE_AGENT_SIT; mAOOverrides.push_back(overrideloader); - overrideloader.orig_id = ANIM_AGENT_SIT_GENERIC; overrideloader.ao_id = LLUUID::null; overrideloader.state = STATE_AGENT_SIT; mAOOverrides.push_back(overrideloader); - overrideloader.orig_id = ANIM_AGENT_SIT_GROUND; overrideloader.ao_id = LLUUID::null; overrideloader.state = STATE_AGENT_GROUNDSIT; mAOOverrides.push_back(overrideloader); - overrideloader.orig_id = ANIM_AGENT_SIT_GROUND_CONSTRAINED; overrideloader.ao_id = LLUUID::null; overrideloader.state = STATE_AGENT_GROUNDSIT; mAOOverrides.push_back(overrideloader); - - overrideloader.orig_id = ANIM_AGENT_HOVER; overrideloader.ao_id = LLUUID::null; overrideloader.state = STATE_AGENT_HOVER; mAOOverrides.push_back(overrideloader); - overrideloader.orig_id = ANIM_AGENT_HOVER_DOWN; overrideloader.ao_id = LLUUID::null; overrideloader.state = STATE_AGENT_HOVER_DOWN; mAOOverrides.push_back(overrideloader); - overrideloader.orig_id = ANIM_AGENT_HOVER_UP; overrideloader.ao_id = LLUUID::null; overrideloader.state = STATE_AGENT_HOVER_UP; mAOOverrides.push_back(overrideloader); - - overrideloader.orig_id = ANIM_AGENT_CROUCH; overrideloader.ao_id = LLUUID::null; overrideloader.state = STATE_AGENT_CROUCH; mAOOverrides.push_back(overrideloader); - overrideloader.orig_id = ANIM_AGENT_CROUCHWALK; overrideloader.ao_id = LLUUID::null; overrideloader.state = STATE_AGENT_CROUCHWALK; mAOOverrides.push_back(overrideloader); - - overrideloader.orig_id = ANIM_AGENT_FALLDOWN; overrideloader.ao_id = LLUUID::null; overrideloader.state = STATE_AGENT_FALLDOWN; mAOOverrides.push_back(overrideloader); - overrideloader.orig_id = ANIM_AGENT_STANDUP; overrideloader.ao_id = LLUUID::null; overrideloader.state = STATE_AGENT_STANDUP; mAOOverrides.push_back(overrideloader); - overrideloader.orig_id = ANIM_AGENT_LAND; overrideloader.ao_id = LLUUID::null; overrideloader.state = STATE_AGENT_LAND; mAOOverrides.push_back(overrideloader); - - overrideloader.orig_id = ANIM_AGENT_FLY; overrideloader.ao_id = LLUUID::null; overrideloader.state = STATE_AGENT_FLY; mAOOverrides.push_back(overrideloader); - overrideloader.orig_id = ANIM_AGENT_FLYSLOW; overrideloader.ao_id = LLUUID::null; overrideloader.state = STATE_AGENT_FLYSLOW; mAOOverrides.push_back(overrideloader); - - BOOL success = TRUE; - - if(LLStartUp::getStartupState() >= STATE_INVENTORY_SEND) - { - if(LLInventoryModelBackgroundFetch::instance().isEverythingFetched()) - { - LLUUID configncitem = (LLUUID)gSavedPerAccountSettings.getString("AOConfigNotecardID"); - if (configncitem.notNull()) + else { - success = FALSE; - const LLInventoryItem* item = gInventory.getItem(configncitem); - if(item) + auto end = mCombos.end(); + auto it = std::find(mCombos.begin(), end, box); + llassert(it != end); + const auto state = std::distance(mCombos.begin(), it); + if (auto aop = ao->mAOOverrides[state]) { - if (gAgent.allowOperation(PERM_COPY, item->getPermissions(),GP_OBJECT_MANIPULATE) || gAgent.isGodlike()) - { - if(!item->getAssetUUID().isNull()) - { - LLUUID* new_uuid = new LLUUID(configncitem); - LLHost source_sim = LLHost::invalid; - invfolderid = item->getParentUUID(); - gAssetStorage->getInvItemAsset(source_sim, - gAgent.getID(), - gAgent.getSessionID(), - item->getPermissions().getOwner(), - LLUUID::null, - item->getUUID(), - item->getAssetUUID(), - item->getType(), - &onNotecardLoadComplete, - (void*)new_uuid, - TRUE); - success = TRUE; - } - } + LLUUID getAssetIDByName(const std::string & name); +// LL_INFOS() << "state " << state << " - " << aop->playing() << LL_ENDL; + bool was_playing = aop->playing; + if (was_playing) aop->play(false); + aop->ao_id = getAssetIDByName(stranim); + if (was_playing) aop->play(); } } } + gSavedPerAccountSettings.setString(ctrl->getControlName(), stranim); } - - if (!success) - { - cmdline_printchat("Could not read the specified Config Notecard"); - } - -// mAnimationState = 0; -// mCurrentStandId = LLUUID::null; -// setAnimationState(STATE_AGENT_IDLE); - -} - -void LLFloaterAO::onClickMore(void* data) -{ - gSavedSettings.setBOOL( "AOAdvanced", TRUE ); - updateLayout(sInstance); -} -void LLFloaterAO::onClickLess(void* data) -{ - gSavedSettings.setBOOL( "AOAdvanced", FALSE ); - updateLayout(sInstance); -} - -void LLFloaterAO::onClickToggleAO() -{ - run(); -} - -void LLFloaterAO::onClickToggleSits() -{ - run(); -} - - -void LLFloaterAO::run() -{ - setAnimationState(STATE_AGENT_IDLE); // reset state - int state = getAnimationState(); // check if sitting or hovering - if ((state == STATE_AGENT_IDLE) || (state == STATE_AGENT_STAND)) - { - if (gSavedSettings.getBOOL("AOEnabled")) - { - if (mAOStandTimer) - { - mAOStandTimer->reset(); - ChangeStand(); - } - else - { - mAOStandTimer = new AOStandTimer(); - } - } - else - { - stopMotion(getCurrentStandId(), FALSE, TRUE); //stop stand first then set state - setAnimationState(STATE_AGENT_IDLE); - } - } - else - { - if (state == STATE_AGENT_SIT) gAgent.sendAnimationRequest(GetAnimIDFromState(state), (gSavedSettings.getBOOL("AOEnabled") && gSavedSettings.getBOOL("AOSitsEnabled")) ? ANIM_REQUEST_START : ANIM_REQUEST_STOP); - else gAgent.sendAnimationRequest(GetAnimIDFromState(state), gSavedSettings.getBOOL("AOEnabled") ? ANIM_REQUEST_START : ANIM_REQUEST_STOP); - } -} - -int LLFloaterAO::getAnimationState() -{ - if (gAgentAvatarp) - { - if (gAgentAvatarp->isSitting()) setAnimationState(STATE_AGENT_SIT); - else if (gAgent.getFlying()) setAnimationState(STATE_AGENT_HOVER); - } - return mAnimationState; -} - -void LLFloaterAO::setAnimationState(const int state) -{ - mAnimationState = state; -} - -LLUUID LLFloaterAO::getCurrentStandId() -{ - return mCurrentStandId; -} - -void LLFloaterAO::setCurrentStandId(const LLUUID& id) -{ - mCurrentStandId = id; -} - -LLUUID LLFloaterAO::GetAnimID(const LLUUID& id) -{ - for (std::vector::iterator iter = mAOOverrides.begin(); iter != mAOOverrides.end(); ++iter) - { - if (iter->orig_id == id) return iter->ao_id; - } - return LLUUID::null; -} - -int LLFloaterAO::GetStateFromAnimID(const LLUUID& id) -{ - for (std::vector::iterator iter = mAOOverrides.begin(); iter != mAOOverrides.end(); ++iter) - { - if (iter->orig_id == id) return iter->state; - } - return STATE_AGENT_IDLE; -} - -LLUUID LLFloaterAO::GetAnimIDFromState(const int state) -{ - for (std::vector::iterator iter = mAOOverrides.begin(); iter != mAOOverrides.end(); ++iter) - { - if (iter->state == state) return iter->ao_id; - } - return LLUUID::null; -} - -int LLFloaterAO::GetStateFromToken(std::string strtoken) -{ - for (std::vector::iterator iter = mAOTokens.begin(); iter != mAOTokens.end(); ++iter) - { - if (iter->token == strtoken) return iter->state; - } - return STATE_AGENT_IDLE; -} - -void LLFloaterAO::onClickPrevStand(void* user_data) -{ - if (!(mAOStands.size() > 0)) return; - stand_iterator=stand_iterator-1; - if (stand_iterator < 0) stand_iterator = int( mAOStands.size()-stand_iterator); - if (stand_iterator > int( mAOStands.size()-1)) stand_iterator = 0; - cmdline_printchat(llformat("Changing stand to %s.",mAOStands[stand_iterator].anim_name.c_str())); - ChangeStand(); -} - -void LLFloaterAO::onClickNextStand(void* user_data) -{ - if (!(mAOStands.size() > 0)) return; - stand_iterator=stand_iterator+1; - if (stand_iterator < 0) stand_iterator = int( mAOStands.size()-stand_iterator); - if (stand_iterator > int( mAOStands.size()-1)) stand_iterator = 0; - cmdline_printchat(llformat("Changing stand to %s.",mAOStands[stand_iterator].anim_name.c_str())); - ChangeStand(); -} - -BOOL LLFloaterAO::ChangeStand() -{ - if (gSavedSettings.getBOOL("AOEnabled")) - { - if (gAgentAvatarp) - { - if (gSavedSettings.getBOOL("AONoStandsInMouselook") && gAgentCamera.cameraMouselook()) return FALSE; - - if (gAgentAvatarp->isSitting()) - { -// stopMotion(getCurrentStandId(), FALSE, TRUE); //stop stand first then set state -// if (getAnimationState() != STATE_AGENT_GROUNDSIT) setAnimationState(STATE_AGENT_SIT); -// setCurrentStandId(LLUUID::null); - return FALSE; - } - } - if ((getAnimationState() == STATE_AGENT_IDLE) || (getAnimationState() == STATE_AGENT_STAND))// stands have lowest priority - { - if (!(mAOStands.size() > 0)) return TRUE; - if (gSavedSettings.getBOOL("AOStandRandomize")) - { - stand_iterator = ll_rand(mAOStands.size()-1); - } - if (stand_iterator < 0) stand_iterator = int( mAOStands.size()-stand_iterator); - if (stand_iterator > int( mAOStands.size()-1)) stand_iterator = 0; - - int stand_iterator_previous = stand_iterator -1; - - if (stand_iterator_previous < 0) stand_iterator_previous = int( mAOStands.size()-1); - - if (mAOStands[stand_iterator].ao_id.notNull()) - { - stopMotion(getCurrentStandId(), FALSE, TRUE); //stop stand first then set state - startMotion(mAOStands[stand_iterator].ao_id, 0, TRUE); - - setAnimationState(STATE_AGENT_STAND); - setCurrentStandId(mAOStands[stand_iterator].ao_id); - if ((sInstance)&&(mcomboBox_stands)) mcomboBox_stands->selectNthItem(stand_iterator); -// llinfos << "changing stand to " << mAOStands[stand_iterator].anim_name << llendl; - return FALSE; - } - } - } - else - { - stopMotion(getCurrentStandId(), FALSE, TRUE); - return TRUE; //stop if ao is off - } - return TRUE; } - -BOOL LLFloaterAO::startMotion(const LLUUID& id, F32 time_offset, BOOL stand) +void LLFloaterAO::onClickCycleStand(bool next) const { - if (stand) - { - if (id.notNull()) - { - BOOL sitting = FALSE; - if (gAgentAvatarp) - { - sitting = gAgentAvatarp->isSitting(); - } - if (sitting) return FALSE; - gAgent.sendAnimationRequest(id, ANIM_REQUEST_START); - return TRUE; - } - } - else - { - if (GetAnimID(id).notNull() && gSavedSettings.getBOOL("AOEnabled")) - { - stopMotion(getCurrentStandId(), FALSE, TRUE); //stop stand first then set state - setAnimationState(GetStateFromAnimID(id)); - -// llinfos << " state " << getAnimationState() << " start anim " << id << " overriding with " << GetAnimID(id) << llendl; - if ((GetStateFromAnimID(id) == STATE_AGENT_SIT) && !(gSavedSettings.getBOOL("AOSitsEnabled"))) return TRUE; - gAgent.sendAnimationRequest(GetAnimID(id), ANIM_REQUEST_START); - return TRUE; - } - } - return FALSE; + auto ao = AOSystem::getIfExists(); + if (!ao) return; + auto stand = ao->cycleStand(next, false); + ao->mAOStandTimer.reset(); + if (stand < 0) return; + cmdline_printchat("Changed stand to " + ao->mAOStands[stand].anim_name + '.'); } -BOOL LLFloaterAO::stopMotion(const LLUUID& id, BOOL stop_immediate, BOOL stand) -{ - if (stand) - { - setAnimationState(STATE_AGENT_IDLE); - gAgent.sendAnimationRequest(id, ANIM_REQUEST_STOP); - return TRUE; - } - else - { - if (GetAnimID(id).notNull() && gSavedSettings.getBOOL("AOEnabled")) - { -// llinfos << " state " << getAnimationState() << "/" << GetStateFromAnimID(id) << "(now 0) stop anim " << id << " overriding with " << GetAnimID(id) << llendl; - if (getAnimationState() == GetStateFromAnimID(id)) - { - setAnimationState(STATE_AGENT_IDLE); - } - ChangeStand(); // startMotion(getCurrentStandId(), 0, TRUE); - gAgent.sendAnimationRequest(GetAnimID(id), ANIM_REQUEST_STOP); - return TRUE; - } - } - return FALSE; -} - -void LLFloaterAO::onClickReloadCard(void* user_data) +void LLFloaterAO::onClickReloadCard() const { - if(LLInventoryModelBackgroundFetch::instance().isEverythingFetched()) - { - LLFloaterAO::init(); - } + AOSystem::instance().initSingleton(); } -void LLFloaterAO::onClickOpenCard(void* user_data) +void LLFloaterAO::onClickOpenCard() const { - if(LLInventoryModelBackgroundFetch::instance().isEverythingFetched()) - { - LLUUID configncitem = (LLUUID)gSavedPerAccountSettings.getString("AOConfigNotecardID"); - if (configncitem.notNull()) - { - const LLInventoryItem* item = gInventory.getItem(configncitem); - if(item) - { - if (gAgent.allowOperation(PERM_COPY, item->getPermissions(),GP_OBJECT_MANIPULATE) || gAgent.isGodlike()) - { - if(!item->getAssetUUID().isNull()) - open_notecard((LLViewerInventoryItem*)item, std::string("Note: ") + item->getName(), LLUUID::null, FALSE); - // open_notecard((LLViewerInventoryItem*)item, std::string("Note: ") + item->getName(), LLUUID::null, FALSE, LLUUID::null, FALSE); - } - } - } - } + auto config_nc_id = (LLUUID)gSavedPerAccountSettings.getString("AOConfigNotecardID"); + if (config_nc_id.notNull()) + if (LLViewerInventoryItem* item = gInventory.getItem(config_nc_id)) + if (gAgent.allowOperation(PERM_COPY, item->getPermissions(), GP_OBJECT_MANIPULATE) || gAgent.isGodlike()) + if(!item->getAssetUUID().isNull()) + open_notecard(item, "Note: " + item->getName(), LLUUID::null, false); } -void LLFloaterAO::onClickNewCard(void* user_data) +void LLFloaterAO::onClickNewCard() const { // load the template file from app_settings/ao_template.ini then // create a new properly-formatted notecard in the user's inventory std::string ao_template = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "ao_template.ini"); - if (!ao_template.empty()) - { - LLPointer cb = new AONotecardCallback(ao_template); - create_inventory_item(gAgent.getID(), gAgent.getSessionID(), - LLUUID::null, LLTransactionID::tnull, "New AO Notecard", - "Drop this notecard in your AO window to use", LLAssetType::AT_NOTECARD, - LLInventoryType::IT_NOTECARD, NOT_WEARABLE, PERM_ALL, cb); - } - else - { - llwarns << "Can't find ao_template.ini in app_settings!" << llendl; - } -} - -struct AOAssetInfo -{ - std::string path; - std::string name; -}; - -void LLFloaterAO::onNotecardLoadComplete(LLVFS *vfs,const LLUUID& asset_uuid,LLAssetType::EType type,void* user_data, S32 status, LLExtStat ext_status) -{ - if(status == LL_ERR_NOERR) - { - S32 size = vfs->getSize(asset_uuid, type); - U8* buffer = new U8[size]; - vfs->getData(asset_uuid, type, buffer, 0, size); - - if(type == LLAssetType::AT_NOTECARD) - { - LLViewerTextEditor* edit = new LLViewerTextEditor("",LLRect(0,0,0,0),S32_MAX,""); - if(edit->importBuffer((char*)buffer, (S32)size)) - { - llinfos << "ao nc decode success" << llendl; - std::string card = edit->getText(); - edit->die(); - - if (mcomboBox_stands) - { - mcomboBox_stands->clear(); - mcomboBox_stands->removeall(); - } - if (mcomboBox_walks) mcomboBox_walks->clear(); - if (mcomboBox_runs) mcomboBox_runs->clear(); - if (mcomboBox_jumps) mcomboBox_jumps->clear(); - if (mcomboBox_sits) mcomboBox_sits->clear(); - if (mcomboBox_gsits) mcomboBox_gsits->clear(); - if (mcomboBox_crouchs) mcomboBox_cwalks->clear(); - if (mcomboBox_cwalks) mcomboBox_cwalks->clear(); - if (mcomboBox_falls) mcomboBox_falls->clear(); - if (mcomboBox_hovers) mcomboBox_hovers->clear(); - if (mcomboBox_flys) mcomboBox_flys->clear(); - if (mcomboBox_flyslows) mcomboBox_flyslows->clear(); - if (mcomboBox_flyups) mcomboBox_flyups->clear(); - if (mcomboBox_flydowns) mcomboBox_flydowns->clear(); - if (mcomboBox_lands) mcomboBox_lands->clear(); - if (mcomboBox_standups) mcomboBox_standups->clear(); - if (mcomboBox_prejumps) mcomboBox_prejumps->clear(); - - - struct_stands loader; - - typedef boost::tokenizer > tokenizer; - boost::char_separator sep("\n"); - tokenizer tokline(card, sep); - - for (tokenizer::iterator line = tokline.begin(); line != tokline.end(); ++line) - { -// llinfos << *line << llendl; - std::string strline(*line); -// llinfos << "uncommented line: " << strline << llendl; - - boost::regex type("^(\\s*)(\\[ )(.*)( \\])"); - boost::smatch what; - if (boost::regex_search(strline, what, type)) - { -// llinfos << "type: " << what[0] << llendl; -// llinfos << "anims in type: " << boost::regex_replace(strline, type, "") << llendl; - - boost::char_separator sep("|,"); - std::string stranimnames(boost::regex_replace(strline, type, "")); - tokenizer tokanimnames(stranimnames, sep); - for (tokenizer::iterator anim = tokanimnames.begin(); anim != tokanimnames.end(); ++anim) - { - std::string strtoken(what[0]); - std::string stranim(*anim); - LLUUID animid(getAssetIDByName(stranim)); - -// llinfos << invfolderid.asString().c_str() << llendl; -// llinfos << "anim: " << stranim.c_str() << " assetid: " << animid << llendl; - if (!(animid.notNull())) - { - cmdline_printchat(llformat("Warning: animation '%s' could not be found (Section: %s).",stranim.c_str(),strtoken.c_str())); - } - else - { - switch(GetStateFromToken(strtoken.c_str())) - { - case STATE_AGENT_STAND: - loader.ao_id = animid; loader.anim_name = stranim.c_str(); mAOStands.push_back(loader); - if(mcomboBox_stands != NULL) mcomboBox_stands->add(stranim.c_str(), ADD_BOTTOM, TRUE); - break; - case STATE_AGENT_WALK: - { - if (sInstance && (mcomboBox_walks != NULL)) - { - //llinfos << "1 anim: " << stranim.c_str() << " assetid: " << animid << llendl; - if (!(mcomboBox_walks->selectByValue(stranim.c_str()))) mcomboBox_walks->add(stranim.c_str(), ADD_BOTTOM, TRUE); //check if exist - } - } - break; - case STATE_AGENT_RUN: - { - if (sInstance && (mcomboBox_runs != NULL)) - { - if (!(mcomboBox_runs->selectByValue(stranim.c_str()))) mcomboBox_runs->add(stranim.c_str(), ADD_BOTTOM, TRUE); //check if exist - } - } - break; - case STATE_AGENT_JUMP: - { - if (sInstance && (mcomboBox_jumps != NULL)) - { - if (!(mcomboBox_jumps->selectByValue(stranim.c_str()))) mcomboBox_jumps->add(stranim.c_str(), ADD_BOTTOM, TRUE); //check if exist - } - } - break; - case STATE_AGENT_SIT: - { - if (sInstance && (mcomboBox_sits != NULL)) - { - if (!(mcomboBox_sits->selectByValue(stranim.c_str()))) mcomboBox_sits->add(stranim.c_str(), ADD_BOTTOM, TRUE); //check if exist - } - } - break; - case STATE_AGENT_GROUNDSIT: - { - if (sInstance && (mcomboBox_gsits != NULL)) - { - if (!(mcomboBox_gsits->selectByValue(stranim.c_str()))) mcomboBox_gsits->add(stranim.c_str(), ADD_BOTTOM, TRUE); //check if exist - } - } - break; - case STATE_AGENT_CROUCH: - { - if (sInstance && (mcomboBox_crouchs != NULL)) - { - if (!(mcomboBox_crouchs->selectByValue(stranim.c_str()))) mcomboBox_crouchs->add(stranim.c_str(), ADD_BOTTOM, TRUE); //check if exist - } - } - break; - case STATE_AGENT_CROUCHWALK: - { - if (sInstance && (mcomboBox_cwalks != NULL)) - { - if (!(mcomboBox_cwalks->selectByValue(stranim.c_str()))) mcomboBox_cwalks->add(stranim.c_str(), ADD_BOTTOM, TRUE); //check if exist - } - } - break; - case STATE_AGENT_FALLDOWN: - { - if (sInstance && (mcomboBox_falls != NULL)) - { - if (!(mcomboBox_falls->selectByValue(stranim.c_str()))) mcomboBox_falls->add(stranim.c_str(), ADD_BOTTOM, TRUE); //check if exist - } - } - break; - case STATE_AGENT_HOVER: - { - if (sInstance && (mcomboBox_hovers != NULL)) - { - if (!(mcomboBox_hovers->selectByValue(stranim.c_str()))) mcomboBox_hovers->add(stranim.c_str(), ADD_BOTTOM, TRUE); //check if exist - } - } - break; - case STATE_AGENT_FLY: - { - if (sInstance && (mcomboBox_flys != NULL)) - { - if (!(mcomboBox_flys->selectByValue(stranim.c_str()))) mcomboBox_flys->add(stranim.c_str(), ADD_BOTTOM, TRUE); //check if exist - } - } - break; - case STATE_AGENT_FLYSLOW: - { - if (sInstance && (mcomboBox_flyslows != NULL)) - { - if (!(mcomboBox_flyslows->selectByValue(stranim.c_str()))) mcomboBox_flyslows->add(stranim.c_str(), ADD_BOTTOM, TRUE); //check if exist - } - } - break; - case STATE_AGENT_HOVER_UP: - { - if (sInstance && (mcomboBox_flyups != NULL)) - { - if (!(mcomboBox_flyups->selectByValue(stranim.c_str()))) mcomboBox_flyups->add(stranim.c_str(), ADD_BOTTOM, TRUE); //check if exist - } - } - break; - case STATE_AGENT_HOVER_DOWN: - { - if (sInstance && (mcomboBox_flydowns != NULL)) - { - if (!(mcomboBox_flydowns->selectByValue(stranim.c_str()))) mcomboBox_flydowns->add(stranim.c_str(), ADD_BOTTOM, TRUE); //check if exist - } - } - break; - case STATE_AGENT_LAND: - { - if (sInstance && (mcomboBox_lands != NULL)) - { - if (!(mcomboBox_lands->selectByValue(stranim.c_str()))) mcomboBox_lands->add(stranim.c_str(), ADD_BOTTOM, TRUE); //check if exist - } - } - break; - case STATE_AGENT_STANDUP: - { - if (sInstance && (mcomboBox_standups != NULL)) - { - if (!(mcomboBox_standups->selectByValue(stranim.c_str()))) mcomboBox_standups->add(stranim.c_str(), ADD_BOTTOM, TRUE); //check if exist - } - } - break; - case STATE_AGENT_PRE_JUMP: - { - if (sInstance && (mcomboBox_prejumps != NULL)) - { - if (!(mcomboBox_prejumps->selectByValue(stranim.c_str()))) mcomboBox_prejumps->add(stranim.c_str(), ADD_BOTTOM, TRUE); //check if exist - } - } - break; - } - for (std::vector::iterator iter = mAOOverrides.begin(); iter != mAOOverrides.end(); ++iter) - { - if (GetStateFromToken(strtoken.c_str()) == iter->state) - { - iter->ao_id = animid; - } - } - } - } - } - } - llinfos << "ao nc read sucess" << llendl; - - for (std::vector::iterator iter = mAOOverrides.begin(); iter != mAOOverrides.end(); ++iter) - { - switch(iter->state) - { - - case STATE_AGENT_WALK: - { - std::string defaultanim = gSavedPerAccountSettings.getString("AODefaultWalk"); - SetDefault(mcomboBox_walks,iter->ao_id,defaultanim); - if (getAssetIDByName(defaultanim) != LLUUID::null) iter->ao_id = getAssetIDByName(defaultanim); - } - break; - case STATE_AGENT_RUN: - { - std::string defaultanim = gSavedPerAccountSettings.getString("AODefaultRun"); - SetDefault(mcomboBox_runs,iter->ao_id,defaultanim); - if (getAssetIDByName(defaultanim) != LLUUID::null) iter->ao_id = getAssetIDByName(defaultanim); - } - break; - case STATE_AGENT_JUMP: - { - std::string defaultanim = gSavedPerAccountSettings.getString("AODefaultJump"); - SetDefault(mcomboBox_jumps,iter->ao_id,defaultanim); - if (getAssetIDByName(defaultanim) != LLUUID::null) iter->ao_id = getAssetIDByName(defaultanim); - } - break; - case STATE_AGENT_SIT: - { - std::string defaultanim = gSavedPerAccountSettings.getString("AODefaultSit"); - SetDefault(mcomboBox_sits,iter->ao_id,defaultanim); - if (getAssetIDByName(defaultanim) != LLUUID::null) iter->ao_id = getAssetIDByName(defaultanim); - } - break; - case STATE_AGENT_CROUCH: - { - std::string defaultanim = gSavedPerAccountSettings.getString("AODefaultCrouch"); - SetDefault(mcomboBox_crouchs,iter->ao_id,defaultanim); - if (getAssetIDByName(defaultanim) != LLUUID::null) iter->ao_id = getAssetIDByName(defaultanim); - } - break; - case STATE_AGENT_GROUNDSIT: - { - std::string defaultanim = gSavedPerAccountSettings.getString("AODefaultGroundSit"); - SetDefault(mcomboBox_gsits,iter->ao_id,defaultanim); - if (getAssetIDByName(defaultanim) != LLUUID::null) iter->ao_id = getAssetIDByName(defaultanim); - } - break; - case STATE_AGENT_CROUCHWALK: - { - std::string defaultanim = gSavedPerAccountSettings.getString("AODefaultCrouchWalk"); - SetDefault(mcomboBox_cwalks,iter->ao_id,defaultanim); - if (getAssetIDByName(defaultanim) != LLUUID::null) iter->ao_id = getAssetIDByName(defaultanim); - } - break; - case STATE_AGENT_FALLDOWN: - { - std::string defaultanim = gSavedPerAccountSettings.getString("AODefaultFall"); - SetDefault(mcomboBox_falls,iter->ao_id,defaultanim); - if (getAssetIDByName(defaultanim) != LLUUID::null) iter->ao_id = getAssetIDByName(defaultanim); - } - break; - case STATE_AGENT_HOVER: - { - std::string defaultanim = gSavedPerAccountSettings.getString("AODefaultHover"); - SetDefault(mcomboBox_hovers,iter->ao_id,defaultanim); - if (getAssetIDByName(defaultanim) != LLUUID::null) iter->ao_id = getAssetIDByName(defaultanim); - } - break; - case STATE_AGENT_FLY: - { - std::string defaultanim = gSavedPerAccountSettings.getString("AODefaultFly"); - SetDefault(mcomboBox_flys,iter->ao_id,defaultanim); - if (getAssetIDByName(defaultanim) != LLUUID::null) iter->ao_id = getAssetIDByName(defaultanim); - } - break; - case STATE_AGENT_HOVER_UP: - { - std::string defaultanim = gSavedPerAccountSettings.getString("AODefaultFlyUp"); - SetDefault(mcomboBox_flyups,iter->ao_id,defaultanim); - if (getAssetIDByName(defaultanim) != LLUUID::null) iter->ao_id = getAssetIDByName(defaultanim); - } - break; - case STATE_AGENT_FLYSLOW: - { - std::string defaultanim = gSavedPerAccountSettings.getString("AODefaultFlySlow"); - SetDefault(mcomboBox_flyslows,iter->ao_id,defaultanim); - if (getAssetIDByName(defaultanim) != LLUUID::null) iter->ao_id = getAssetIDByName(defaultanim); - } - break; - case STATE_AGENT_HOVER_DOWN: - { - std::string defaultanim = gSavedPerAccountSettings.getString("AODefaultFlyDown"); - SetDefault(mcomboBox_flydowns,iter->ao_id,defaultanim); - if (getAssetIDByName(defaultanim) != LLUUID::null) iter->ao_id = getAssetIDByName(defaultanim); - } - break; - case STATE_AGENT_LAND: - { - std::string defaultanim = gSavedPerAccountSettings.getString("AODefaultLand"); - SetDefault(mcomboBox_lands,iter->ao_id,defaultanim); - if (getAssetIDByName(defaultanim) != LLUUID::null) iter->ao_id = getAssetIDByName(defaultanim); - } - break; - case STATE_AGENT_STANDUP: - { - std::string defaultanim = gSavedPerAccountSettings.getString("AODefaultStandUp"); - SetDefault(mcomboBox_standups,iter->ao_id,defaultanim); - if (getAssetIDByName(defaultanim) != LLUUID::null) iter->ao_id = getAssetIDByName(defaultanim); - } - break; - case STATE_AGENT_PRE_JUMP: - { - std::string defaultanim = gSavedPerAccountSettings.getString("AODefaultPreJump"); - SetDefault(mcomboBox_prejumps,iter->ao_id,defaultanim); - if (getAssetIDByName(defaultanim) != LLUUID::null) iter->ao_id = getAssetIDByName(defaultanim); - } - break; - } - } - run(); - } - else - { - llinfos << "ao nc decode error" << llendl; - } - } - } - else + if (ao_template.empty()) { - llinfos << "ao nc read error" << llendl; + ao_template = "#Can't find ao_template.ini in app_settings!"; + LL_WARNS() << ao_template << LL_ENDL; + ao_template += "\n#ZHAO II Style Notecards are supported."; } -} -BOOL LLFloaterAO::SetDefault(void* userdata, LLUUID ao_id, std::string defaultanim) -{ - if (sInstance && (userdata)) - { - LLComboBox *box = (LLComboBox *) userdata; - if (ao_id.isNull()) - { - box->clear(); - box->removeall(); - } - else - { - box->selectByValue(defaultanim); - } - } - return TRUE; + create_inventory_item(gAgentID, gAgentSessionID, + LLUUID::null, LLTransactionID::tnull, "New AO Notecard", + "Drop this notecard in your AO window to use", LLAssetType::AT_NOTECARD, + LLInventoryType::IT_NOTECARD, NOT_WEARABLE, PERM_ALL, new AONotecardCallback(ao_template)); } - -class ObjectNameMatches : public LLInventoryCollectFunctor -{ -public: - ObjectNameMatches(std::string name) - { - sName = name; - } - virtual ~ObjectNameMatches() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item) - { - if(item) - { - if (item->getParentUUID() == LLFloaterAO::invfolderid) - { - return (item->getName() == sName); - } - return false; - } - return false; - } -private: - std::string sName; -}; - -const LLUUID& LLFloaterAO::getAssetIDByName(const std::string& name) -{ - if (name.empty() || !(LLInventoryModelBackgroundFetch::instance().isEverythingFetched())) return LLUUID::null; - - LLViewerInventoryCategory::cat_array_t cats; - LLViewerInventoryItem::item_array_t items; - ObjectNameMatches objectnamematches(name); - gInventory.collectDescendentsIf(LLUUID::null,cats,items,FALSE,objectnamematches); - - if (items.count()) - { - return items[0]->getAssetUUID(); - } - return LLUUID::null; -}; diff --git a/indra/newview/floaterao.h b/indra/newview/floaterao.h index b8a63f0da2..187493e340 100644 --- a/indra/newview/floaterao.h +++ b/indra/newview/floaterao.h @@ -1,128 +1,30 @@ +#pragma once -#ifndef LL_LLFLOATERAO_H -#define LL_LLFLOATERAO_H - +#include "aostate.h" #include "llfloater.h" -#include "llviewercontrol.h" -#include "llagent.h" -#include "lleventtimer.h" - - -const int STATE_AGENT_IDLE = 0; -const int STATE_AGENT_WALK = 1; -const int STATE_AGENT_RUN = 2; -const int STATE_AGENT_STAND = 3; - -const int STATE_AGENT_PRE_JUMP = 4; -const int STATE_AGENT_JUMP = 5; -const int STATE_AGENT_TURNLEFT = 6; -const int STATE_AGENT_TURNRIGHT = 7; - -const int STATE_AGENT_SIT = 8; -const int STATE_AGENT_GROUNDSIT = 9; - -const int STATE_AGENT_HOVER = 10; -const int STATE_AGENT_HOVER_DOWN = 11; -const int STATE_AGENT_HOVER_UP = 12; - -const int STATE_AGENT_CROUCH = 13; -const int STATE_AGENT_CROUCHWALK = 14; -const int STATE_AGENT_FALLDOWN = 15; -const int STATE_AGENT_STANDUP = 16; -const int STATE_AGENT_LAND = 17; - -const int STATE_AGENT_FLY = 18; -const int STATE_AGENT_FLYSLOW = 19; - - - - - -class AOStandTimer : public LLEventTimer -{ -public: - AOStandTimer(); - ~AOStandTimer(); - virtual BOOL tick(); - virtual void reset(); -}; - -class AOInvTimer : public LLEventTimer -{ -public: - AOInvTimer(); - ~AOInvTimer(); - BOOL tick(); -}; -class LLFloaterAO : public LLFloater +class LLFloaterAO final : public LLFloater, public LLFloaterSingleton { + friend class AOSystem; public: - LLFloaterAO(); - virtual BOOL postBuild(); - virtual ~LLFloaterAO(); - - static void show(void*); - static void init(); - - static void onClickToggleAO(); - static void onClickToggleSits(); - static void run(); - static void updateLayout(LLFloaterAO* floater); - - static BOOL loadAnims(); - - static int getAnimationState(); - static void setAnimationState(int state); - static void setStates(const LLUUID& id, BOOL start); - - static LLUUID getCurrentStandId(); - static void setCurrentStandId(const LLUUID& id); - static int stand_iterator; - static BOOL ChangeStand(); - - static BOOL startMotion(const LLUUID& id, F32 time_offset = 0.f, BOOL stand = FALSE); - static BOOL stopMotion(const LLUUID& id, BOOL stop_immediate, BOOL stand = FALSE); - - static LLUUID GetAnimID(const LLUUID& id); + LLFloaterAO(const LLSD&); + BOOL postBuild() override; + void onOpen() override; + virtual ~LLFloaterAO(); + void updateLayout(bool advanced); - static int GetStateFromAnimID(const LLUUID& id); - static LLUUID GetAnimIDFromState(const int state); - static int GetStateFromToken(std::string strtoken); + void onClickCycleStand(bool next) const; + void onClickReloadCard() const; + void onClickOpenCard() const; + void onClickNewCard() const; - static void onClickLess(void* data) ; - static void onClickMore(void* data) ; - - static void onClickPrevStand(void* userdata); - static void onClickNextStand(void* userdata); - static void onClickReloadCard(void* userdata); - static void onClickOpenCard(void* userdata); - static void onClickNewCard(void* userdata); - - static LLUUID invfolderid; - static const LLUUID& getAssetIDByName(const std::string& name); - - static bool getInstance(); - private: - - static LLFloaterAO* sInstance; - static int mAnimationState; - static LLUUID mCurrentStandId; - - static void onSpinnerCommit(LLUICtrl* ctrl); - static void onComboBoxCommit(LLUICtrl* ctrl); - static BOOL SetDefault(void *userdata, LLUUID ao_id, std::string defaultanim); - - BOOL mDirty; + void onSpinnerCommit() const; + void onComboBoxCommit(LLUICtrl* ctrl) const; + std::array mCombos; protected: - static void onNotecardLoadComplete(LLVFS *vfs,const LLUUID& asset_uuid,LLAssetType::EType type,void* user_data, S32 status, LLExtStat ext_status); - + LLComboBox* getComboFromState(const U8& state) const { return mCombos[state]; } }; - -extern AOInvTimer* gAOInvTimer; - -#endif diff --git a/indra/newview/floaterlocalassetbrowse.cpp b/indra/newview/floaterlocalassetbrowse.cpp index abcb19c983..8a700593a3 100644 --- a/indra/newview/floaterlocalassetbrowse.cpp +++ b/indra/newview/floaterlocalassetbrowse.cpp @@ -64,6 +64,8 @@ this feature is still a work in progress. #include "llviewermenufile.h" #include "llfloaterimagepreview.h" #include "llfile.h" +#include "llsdparam.h" +#include "llsdserialize.h" /* including to force rebakes when needed */ #include "llvoavatarself.h" @@ -72,6 +74,8 @@ this feature is still a work in progress. #include "llvovolume.h" #include "llface.h" +/* static pointer to self, wai? oh well. */ +static FloaterLocalAssetBrowser* sLFInstance = NULL; /*=======================================*/ /* Instantiating manager class */ @@ -79,7 +83,7 @@ this feature is still a work in progress. /*=======================================*/ LocalAssetBrowser* gLocalBrowser; LocalAssetBrowserTimer* gLocalBrowserTimer; -std::vector LocalAssetBrowser::loaded_bitmaps; +std::vector LocalAssetBrowser::loaded_bitmaps; bool LocalAssetBrowser::mLayerUpdated; bool LocalAssetBrowser::mSculptUpdated; @@ -91,56 +95,65 @@ bool LocalAssetBrowser::mSculptUpdated; containing one loaded local texture. */ -LocalBitmap::LocalBitmap(std::string fullpath) +LocalBitmap::Params::Params(const std::string& path) +: fullpath("path", path) +, keep_updating("update", gSavedSettings.getBOOL("LocalBitmapUpdate")) +, type("type", TYPE_TEXTURE) +, id("id", LLUUID::generateNewID()) { - this->valid = false; - if ( gDirUtilp->fileExists(fullpath) ) +} + +LocalBitmap::LocalBitmap(const Params& p) +{ + llassert(!p.fullpath().empty()); + valid = false; + if ( gDirUtilp->fileExists(p.fullpath) ) { /* taking care of basic properties */ - this->id.generate(); - this->filename = fullpath; - this->linkstatus = LINK_OFF; - this->keep_updating = false; - this->shortname = gDirUtilp->getBaseFileName(this->filename, true); - this->bitmap_type = TYPE_TEXTURE; - this->sculpt_dirty = false; - this->volume_dirty = false; - this->valid = false; + id = p.id; + filename = p.fullpath; + keep_updating = p.keep_updating; + linkstatus = keep_updating ? LINK_ON : LINK_OFF; + shortname = gDirUtilp->getBaseFileName(filename, true); + bitmap_type = p.type; + sculpt_dirty = false; + volume_dirty = false; /* taking care of extension type now to avoid switch madness */ - std::string temp_exten = gDirUtilp->getExtension(this->filename); + std::string temp_exten = gDirUtilp->getExtension(filename); - if (temp_exten == "bmp") { this->extension = IMG_EXTEN_BMP; } - else if (temp_exten == "tga") { this->extension = IMG_EXTEN_TGA; } - else if (temp_exten == "jpg" || temp_exten == "jpeg") { this->extension = IMG_EXTEN_JPG; } - else if (temp_exten == "png") { this->extension = IMG_EXTEN_PNG; } - else { return; } // no valid extension. + if (temp_exten == "bmp") extension = IMG_EXTEN_BMP; + else if (temp_exten == "tga") extension = IMG_EXTEN_TGA; + else if (temp_exten == "jpg" || temp_exten == "jpeg") extension = IMG_EXTEN_JPG; + else if (temp_exten == "png") extension = IMG_EXTEN_PNG; + else return; // no valid extension. /* getting file's last modified */ llstat temp_stat; - LLFile::stat(this->filename, &temp_stat); + LLFile::stat(filename, &temp_stat); std::time_t time = temp_stat.st_mtime; - this->last_modified = asctime( localtime(&time) ); + last_modified = asctime( localtime(&time) ); /* checking if the bitmap is valid && decoding if it is */ - LLImageRaw* raw_image = new LLImageRaw(); - if ( this->decodeSelf(raw_image) ) + LLPointer raw_image = new LLImageRaw; + if (decodeSelf(raw_image)) { /* creating a shell LLViewerTexture and fusing raw image into it */ - LLViewerFetchedTexture* viewer_image = new LLViewerFetchedTexture( "file://"+this->filename, this->id, LOCAL_USE_MIPMAPS ); + LLViewerFetchedTexture* viewer_image = new LLViewerFetchedTexture( "file://"+filename, FTT_LOCAL_FILE, id, LOCAL_USE_MIPMAPS ); viewer_image->createGLTexture( LOCAL_DISCARD_LEVEL, raw_image ); viewer_image->setCachedRawImage(-1,raw_image); /* making damn sure gTextureList will not delete it prematurely */ - viewer_image->ref(); + viewer_image->ref(); /* finalizing by adding LLViewerTexture instance into gTextureList */ - gTextureList.addImage(viewer_image); + gTextureList.addImage(viewer_image, TEX_LIST_STANDARD); /* filename is valid, bitmap is decoded and valid, i can haz liftoff! */ - this->valid = true; + valid = true; + LocalAssetBrowser::add(*this); } } } @@ -152,60 +165,64 @@ LocalBitmap::~LocalBitmap() /* [maintenence functions] */ void LocalBitmap::updateSelf() { - if ( this->linkstatus == LINK_ON || this->linkstatus == LINK_UPDATING ) + if (linkstatus == LINK_ON || linkstatus == LINK_UPDATING) { /* making sure file still exists */ - if ( !gDirUtilp->fileExists(this->filename) ) { this->linkstatus = LINK_BROKEN; return; } + if (!gDirUtilp->fileExists(filename)) + { + linkstatus = LINK_BROKEN; + return; + } /* exists, let's check if it's lastmod has changed */ llstat temp_stat; - LLFile::stat(this->filename, &temp_stat); + LLFile::stat(filename, &temp_stat); std::time_t temp_time = temp_stat.st_mtime; LLSD new_last_modified = asctime( localtime(&temp_time) ); - if ( this->last_modified.asString() == new_last_modified.asString() ) { return; } + if (last_modified.asString() == new_last_modified.asString()) return; /* here we update the image */ - LLImageRaw* new_imgraw = new LLImageRaw(); - - if ( !decodeSelf(new_imgraw) ) { this->linkstatus = LINK_UPDATING; return; } - else { this->linkstatus = LINK_ON; } - - LLViewerFetchedTexture* image = gTextureList.findImage(this->id); - - if (!image->forSculpt()) - { image->createGLTexture( LOCAL_DISCARD_LEVEL, new_imgraw ); } + LLPointer new_imgraw = new LLImageRaw; + if (!decodeSelf(new_imgraw)) + { + linkstatus = LINK_UPDATING; + return; + } else - { image->setCachedRawImage(-1,new_imgraw); } + { + linkstatus = LINK_ON; + } + + LLViewerFetchedTexture* image = gTextureList.findImage(id, TEX_LIST_STANDARD); + if (!image->forSculpt()) + image->createGLTexture(LOCAL_DISCARD_LEVEL, new_imgraw); + else + image->setCachedRawImage(-1,new_imgraw); /* finalizing by updating lastmod to current */ - this->last_modified = new_last_modified; + last_modified = new_last_modified; /* setting unit property to reflect that it has been changed */ - switch (this->bitmap_type) + switch (bitmap_type) { - case TYPE_TEXTURE: - { break; } - case TYPE_SCULPT: - { - /* sets a bool to run through all visible sculpts in one go, and update the ones necessary. */ - this->sculpt_dirty = true; - this->volume_dirty = true; - gLocalBrowser->setSculptUpdated( true ); - break; - } - + { + /* sets a bool to run through all visible sculpts in one go, and update the ones necessary. */ + sculpt_dirty = true; + volume_dirty = true; + gLocalBrowser->setSculptUpdated( true ); + break; + } case TYPE_LAYER: - { - /* sets a bool to rebake layers after the iteration is done with */ - gLocalBrowser->setLayerUpdated( true ); - break; - } - + { + /* sets a bool to rebake layers after the iteration is done with */ + gLocalBrowser->setLayerUpdated( true ); + break; + } + case TYPE_TEXTURE: default: - { break; } - + break; } } @@ -213,51 +230,47 @@ void LocalBitmap::updateSelf() bool LocalBitmap::decodeSelf(LLImageRaw* rawimg) { - switch (this->extension) + switch (extension) { case IMG_EXTEN_BMP: - { - LLPointer bmp_image = new LLImageBMP; - if ( !bmp_image->load(filename) ) { break; } - if ( !bmp_image->decode(rawimg, 0.0f) ) { break; } - - rawimg->biasedScaleToPowerOfTwo( LLViewerTexture::MAX_IMAGE_SIZE_DEFAULT ); - return true; - } + { + LLPointer bmp_image = new LLImageBMP; + if (!bmp_image->load(filename)) break; + if (!bmp_image->decode(rawimg, 0.0f)) break; + rawimg->biasedScaleToPowerOfTwo(LLViewerTexture::MAX_IMAGE_SIZE_DEFAULT); + return true; + } case IMG_EXTEN_TGA: - { - LLPointer tga_image = new LLImageTGA; - if ( !tga_image->load(filename) ) { break; } - if ( !tga_image->decode(rawimg) ) { break; } - - if( ( tga_image->getComponents() != 3) && - ( tga_image->getComponents() != 4) ) { break; } - - rawimg->biasedScaleToPowerOfTwo( LLViewerTexture::MAX_IMAGE_SIZE_DEFAULT ); - return true; - } - + { + LLPointer tga_image = new LLImageTGA; + if (!tga_image->load(filename)) break; + if (!tga_image->decode(rawimg)) break; + if (( tga_image->getComponents() != 3) && + ( tga_image->getComponents() != 4) ) + break; + + rawimg->biasedScaleToPowerOfTwo(LLViewerTexture::MAX_IMAGE_SIZE_DEFAULT); + return true; + } case IMG_EXTEN_JPG: - { - LLPointer jpeg_image = new LLImageJPEG; - if ( !jpeg_image->load(filename) ) { break; } - if ( !jpeg_image->decode(rawimg, 0.0f) ) { break; } - - rawimg->biasedScaleToPowerOfTwo( LLViewerTexture::MAX_IMAGE_SIZE_DEFAULT ); - return true; - } + { + LLPointer jpeg_image = new LLImageJPEG; + if (!jpeg_image->load(filename)) break; + if (!jpeg_image->decode(rawimg, 0.0f)) break; + rawimg->biasedScaleToPowerOfTwo(LLViewerTexture::MAX_IMAGE_SIZE_DEFAULT); + return true; + } case IMG_EXTEN_PNG: - { - LLPointer png_image = new LLImagePNG; - if ( !png_image->load(filename) ) { break; } - if ( !png_image->decode(rawimg, 0.0f) ) { break; } - - rawimg->biasedScaleToPowerOfTwo( LLViewerTexture::MAX_IMAGE_SIZE_DEFAULT ); - return true; - } + { + LLPointer png_image = new LLImagePNG; + if ( !png_image->load(filename) ) break; + if ( !png_image->decode(rawimg, 0.0f) ) break; + rawimg->biasedScaleToPowerOfTwo(LLViewerTexture::MAX_IMAGE_SIZE_DEFAULT); + return true; + } default: break; } @@ -266,93 +279,89 @@ bool LocalBitmap::decodeSelf(LLImageRaw* rawimg) void LocalBitmap::setUpdateBool() { - if ( this->linkstatus != LINK_BROKEN ) + if (linkstatus != LINK_BROKEN) { - if ( !this->keep_updating ) + if (!keep_updating) { - this->linkstatus = LINK_ON; - this->keep_updating = true; + linkstatus = LINK_ON; + keep_updating = true; } else { - this->linkstatus = LINK_OFF; - this->keep_updating = false; + linkstatus = LINK_OFF; + keep_updating = false; } } else { - this->keep_updating = false; + keep_updating = false; } + gSavedSettings.setBOOL("LocalBitmapUpdate", keep_updating); } void LocalBitmap::setType( S32 type ) { - this->bitmap_type = type; + bitmap_type = type; } -/* [information query functions] */ -std::string LocalBitmap::getShortName() +void LocalBitmap::setID(const LLUUID& uuid) { - return this->shortname; + LLViewerFetchedTexture* image = gTextureList.findImage(id, TEX_LIST_STANDARD); + gTextureList.deleteImage(image); + id = uuid; + image->setID(id); + gTextureList.addImage(image, TEX_LIST_STANDARD); } -std::string LocalBitmap::getFileName() +/* [information query functions] */ +std::string LocalBitmap::getShortName() const { - return this->filename; + return shortname; } -LLUUID LocalBitmap::getID() +std::string LocalBitmap::getFileName() const { - return this->id; + return filename; } -LLSD LocalBitmap::getLastModified() +LLUUID LocalBitmap::getID() const { - return this->last_modified; + return id; } -std::string LocalBitmap::getLinkStatus() +LLSD LocalBitmap::getLastModified() const { - switch(this->linkstatus) - { - case LINK_ON: - return "On"; - - case LINK_OFF: - return "Off"; - - case LINK_BROKEN: - return "Broken"; - - case LINK_UPDATING: - return "Updating"; - - default: - return "Unknown"; - } + return last_modified; } -bool LocalBitmap::getUpdateBool() +std::string LocalBitmap::getLinkStatus() const { - return this->keep_updating; + switch(linkstatus) + { + case LINK_ON: return "On"; + case LINK_OFF: return "Off"; + case LINK_BROKEN: return "Broken"; + case LINK_UPDATING: return "Updating"; + default: return "Unknown"; + } } -bool LocalBitmap::getIfValidBool() +bool LocalBitmap::getUpdateBool() const { - return this->valid; + return keep_updating; } -LocalBitmap* LocalBitmap::getThis() +bool LocalBitmap::getIfValidBool() const { - return this; + return valid; } -S32 LocalBitmap::getType() +S32 LocalBitmap::getType() const { - return this->bitmap_type; + return bitmap_type; } -std::vector LocalBitmap::getFaceUsesThis(LLDrawable* drawable) +std::vector LocalBitmap::getFaceUsesThis(LLDrawable* drawable) const { std::vector matching_faces; @@ -360,18 +369,18 @@ std::vector LocalBitmap::getFaceUsesThis(LLDrawable* drawable) { LLFace* newface = drawable->getFace(face_iter); - if ( this->id == newface->getTexture()->getID() ) - { matching_faces.push_back(newface); } + if (id == newface->getTexture()->getID()) + matching_faces.push_back(newface); } return matching_faces; } -std::vector LocalBitmap::getUsingObjects(bool seek_by_type, bool seek_textures, bool seek_sculptmaps) +std::vector LocalBitmap::getUsingObjects(bool seek_by_type, bool seek_textures, bool seek_sculptmaps) const { std::vector affected_vector; - for( LLDynamicArrayPtr< LLPointer, 256 >::iterator iter = gObjectList.mObjects.begin(); + for (std::vector< LLPointer >::iterator iter = gObjectList.mObjects.begin(); iter != gObjectList.mObjects.end(); iter++ ) { LLViewerObject* obj = *iter; @@ -389,10 +398,10 @@ std::vector LocalBitmap::getUsingObjects(bool seek_by_type, boo if ( obj && obj->mDrawable ) { /* looking for textures */ - if ( seek_textures || ( seek_by_type && this->bitmap_type == TYPE_TEXTURE ) ) + if (seek_textures || (seek_by_type && bitmap_type == TYPE_TEXTURE)) { - std::vector affected_faces = this->getFaceUsesThis( obj->mDrawable ); - if ( !affected_faces.empty() ) + std::vector affected_faces = getFaceUsesThis(obj->mDrawable); + if (!affected_faces.empty()) { shell.face_list = affected_faces; obj_relevant = true; @@ -400,40 +409,44 @@ std::vector LocalBitmap::getUsingObjects(bool seek_by_type, boo } /* looking for sculptmaps */ - if ( ( seek_sculptmaps || ( seek_by_type && this->bitmap_type == TYPE_SCULPT ) ) - && obj->isSculpted() && obj->getVolume() - && this->id == obj->getVolume()->getParams().getSculptID() - ) + if ((seek_sculptmaps || (seek_by_type && bitmap_type == TYPE_SCULPT)) + && obj->isSculpted() && obj->getVolume() + && id == obj->getVolume()->getParams().getSculptID()) { shell.local_sculptmap = true; obj_relevant = true; } } - if (obj_relevant) - { affected_vector.push_back(shell); } + if (obj_relevant) affected_vector.push_back(shell); } - - return affected_vector; } -void LocalBitmap::getDebugInfo() +void LocalBitmap::getDebugInfo() const { /* debug function: dumps everything human readable into llinfos */ - llinfos << "===[local bitmap debug]===" << "\n" - << "path: " << this->filename << "\n" - << "name: " << this->shortname << "\n" - << "extension: " << this->extension << "\n" - << "uuid: " << this->id << "\n" - << "last modified: " << this->last_modified << "\n" - << "link status: " << this->getLinkStatus() << "\n" - << "keep updated: " << this->keep_updating << "\n" - << "type: " << this->bitmap_type << "\n" - << "is valid: " << this->valid << "\n" - << "==========================" << llendl; - + LL_INFOS() << "===[local bitmap debug]===" << '\n' + << "path: " << filename << '\n' + << "name: " << shortname << '\n' + << "extension: " << extension << '\n' + << "uuid: " << id << '\n' + << "last modified: " << last_modified << '\n' + << "link status: " << getLinkStatus() << '\n' + << "keep updated: " << keep_updating << '\n' + << "type: " << bitmap_type << '\n' + << "is valid: " << valid << '\n' + << "==========================" << LL_ENDL; +} + +LLSD LocalBitmap::asLLSD() const +{ + return LLSD() + .with("path", filename) + .with("id", id) + .with("update", keep_updating) + .with("type", bitmap_type); } /*=======================================*/ @@ -445,15 +458,47 @@ void LocalBitmap::getDebugInfo() Sits in memory until the viewer is closed. */ +const std::string LocalAssetBrowser::getFileName() const +{ + return gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "local_assets.xml"); +} + LocalAssetBrowser::LocalAssetBrowser() { - this->mLayerUpdated = false; - this->mSculptUpdated = false; + gLocalBrowser = this; + mLayerUpdated = false; + mSculptUpdated = false; + + // Load bitmaps + llifstream file(getFileName()); + if (!file) return; + LLSD saved_assets; + LLSDSerialize::fromXML(saved_assets, file); + file.close(); + for (auto it = saved_assets.beginArray(), end = saved_assets.endArray(); it < end; ++it) + { + const auto&& p = LLSDParamAdapter(*it); + LocalBitmap bm(p); // Creating one adds it to the list + } + + if (!loaded_bitmaps.empty()) PingTimer(); } LocalAssetBrowser::~LocalAssetBrowser() { - + // Save bitmaps + llofstream file(getFileName()); + if (!file) + { + LL_WARNS() << "Could not open file " << getFileName() << " for saving." << LL_ENDL; + return; + } + LLSD saved_assets(LLSD::emptyArray()); + for (const auto& bitmap : loaded_bitmaps) + saved_assets.append(bitmap.asLLSD()); + LLSDSerialize::toPrettyXML(saved_assets, file); + file.close(); + gLocalBrowser = nullptr; } void LocalAssetBrowser::AddBitmap() @@ -469,22 +514,13 @@ void LocalAssetBrowser::AddBitmap_continued(AIFilePicker* filepicker) return; bool change_happened = false; - std::vector const& filenames(filepicker->getFilenames()); - for(std::vector::const_iterator filename = filenames.begin(); filename != filenames.end(); ++filename) - { - LocalBitmap* unit = new LocalBitmap(*filename); - if ( unit->getIfValidBool() ) - { - loaded_bitmaps.push_back( unit ); + for(const auto& filename : filepicker->getFilenames()) + if (LocalBitmap(filename).getIfValidBool()) change_happened = true; - } - } - if ( change_happened ) - { onChangeHappened(); } + if (change_happened) onChangeHappened(); } - void LocalAssetBrowser::DelBitmap( std::vector delete_vector, S32 column ) { bool change_happened = false; @@ -498,34 +534,26 @@ void LocalAssetBrowser::DelBitmap( std::vector delete_vector, for (local_list_iter iter = loaded_bitmaps.begin(); iter != loaded_bitmaps.end();) { - LocalBitmap* unit = (*iter)->getThis(); - - if ( unit->getID() == id ) + if ((*iter).getID() == id) { - LLViewerFetchedTexture* image = gTextureList.findImage(id); + LLViewerFetchedTexture* image = gTextureList.findImage(id, TEX_LIST_STANDARD); gTextureList.deleteImage( image ); image->unref(); - iter = loaded_bitmaps.erase(iter); - delete unit; - unit = NULL; - change_happened = true; } else - { iter++; } + ++iter; } } } - if ( change_happened ) - { onChangeHappened(); } + if (change_happened) onChangeHappened(); } void LocalAssetBrowser::onUpdateBool(LLUUID id) { - LocalBitmap* unit = GetBitmapUnit( id ); - if ( unit ) + if (LocalBitmap* unit = GetBitmapUnit(id)) { unit->setUpdateBool(); PingTimer(); @@ -534,32 +562,22 @@ void LocalAssetBrowser::onUpdateBool(LLUUID id) void LocalAssetBrowser::onSetType(LLUUID id, S32 type) { - LocalBitmap* unit = GetBitmapUnit( id ); - if ( unit ) - { unit->setType(type); } + if (LocalBitmap* unit = GetBitmapUnit(id)) unit->setType(type); } LocalBitmap* LocalAssetBrowser::GetBitmapUnit(LLUUID id) { - local_list_iter iter = loaded_bitmaps.begin(); - for (; iter != loaded_bitmaps.end(); iter++) - { - if ( (*iter)->getID() == id ) - { - return (*iter)->getThis(); - } - } - + for (local_list_iter iter = loaded_bitmaps.begin(); iter != loaded_bitmaps.end(); ++iter) + if ((*iter).getID() == id) + return &(*iter); return NULL; } bool LocalAssetBrowser::IsDoingUpdates() { - local_list_iter iter = loaded_bitmaps.begin(); - for (; iter != loaded_bitmaps.end(); iter++) + for (local_list_iter iter = loaded_bitmaps.begin(); iter != loaded_bitmaps.end(); iter++) { - if ( (*iter)->getUpdateBool() ) - { return true; } /* if at least one unit in the list needs updates - we need a timer. */ + if ((*iter).getUpdateBool()) return true; /* if at least one unit in the list needs updates - we need a timer. */ } return false; @@ -572,7 +590,7 @@ bool LocalAssetBrowser::IsDoingUpdates() void LocalAssetBrowser::onChangeHappened() { /* own floater update */ - FloaterLocalAssetBrowser::UpdateBitmapScrollList(); + if (sLFInstance) sLFInstance->UpdateBitmapScrollList(); /* texturepicker related */ const LLView::child_list_t* child_list = gFloaterView->getChildList(); @@ -599,118 +617,96 @@ void LocalAssetBrowser::onChangeHappened() void LocalAssetBrowser::PingTimer() { - if ( !loaded_bitmaps.empty() && IsDoingUpdates() ) + if (!loaded_bitmaps.empty() && IsDoingUpdates()) { - if (!gLocalBrowserTimer) - { gLocalBrowserTimer = new LocalAssetBrowserTimer(); } - - if ( !gLocalBrowserTimer->isRunning() ) - { gLocalBrowserTimer->start(); } + if (!gLocalBrowserTimer) + gLocalBrowserTimer = new LocalAssetBrowserTimer(); + if (!gLocalBrowserTimer->isRunning()) + gLocalBrowserTimer->start(); } - - else + else if (gLocalBrowserTimer && gLocalBrowserTimer->isRunning()) { - if (gLocalBrowserTimer) - { - if ( gLocalBrowserTimer->isRunning() ) - { gLocalBrowserTimer->stop(); } - } + gLocalBrowserTimer->stop(); } } /* This function refills the texture picker floater's scrolllist with the updated contents of bitmaplist */ void LocalAssetBrowser::UpdateTextureCtrlList(LLScrollListCtrl* ctrl) { - if ( ctrl ) // checking again in case called externally for some silly reason. + if (ctrl) // checking again in case called externally for some silly reason. { ctrl->clearRows(); - if ( !loaded_bitmaps.empty() ) + for (const auto& bitmap : loaded_bitmaps) { - local_list_iter iter = loaded_bitmaps.begin(); - for ( ; iter != loaded_bitmaps.end(); iter++ ) - { - LLSD element; - element["columns"][0]["column"] = "unit_name"; - element["columns"][0]["type"] = "text"; - element["columns"][0]["value"] = (*iter)->shortname; - - element["columns"][1]["column"] = "unit_id_HIDDEN"; - element["columns"][1]["type"] = "text"; - element["columns"][1]["value"] = (*iter)->id; - - ctrl->addElement(element); - } + auto row = LLScrollListItem::Params(); + row.value(bitmap.id); + row.columns.add(LLScrollListCell::Params() + .column("unit_name") + .type("text") + .value(bitmap.shortname)); + + row.columns.add(LLScrollListCell::Params() + .column("unit_id_HIDDEN") + .type("text") + .value(bitmap.id)); + + ctrl->addRow(row); } } } -void LocalAssetBrowser::PerformTimedActions(void) +void LocalAssetBrowser::PerformTimedActions() { // perform checking if updates are needed && update if so. - local_list_iter iter; - for (iter = loaded_bitmaps.begin(); iter != loaded_bitmaps.end(); iter++) - { (*iter)->updateSelf(); } - - // one or more sculpts have been updated, refreshing them. - if ( mSculptUpdated ) + for (local_list_iter iter = loaded_bitmaps.begin(); iter != loaded_bitmaps.end(); ++iter) { - LocalAssetBrowser::local_list_iter iter; - for(iter = loaded_bitmaps.begin(); iter != loaded_bitmaps.end(); iter++) + (*iter).updateSelf(); + // one or more sculpts have been updated, refreshing them. + if (mSculptUpdated && (*iter).sculpt_dirty) { - if ( (*iter)->sculpt_dirty ) - { - PerformSculptUpdates( (*iter)->getThis() ); - (*iter)->sculpt_dirty = false; - } + PerformSculptUpdates(*iter); + (*iter).sculpt_dirty = false; } - mSculptUpdated = false; } + mSculptUpdated = false; // one of the layer bitmaps has been updated, we need to rebake. - if ( mLayerUpdated ) + if (mLayerUpdated) { - if (isAgentAvatarValid()) - { + if (isAgentAvatarValid()) gAgentAvatarp->forceBakeAllTextures(SLAM_FOR_DEBUG); - } - mLayerUpdated = false; } } -void LocalAssetBrowser::PerformSculptUpdates(LocalBitmap* unit) +void LocalAssetBrowser::PerformSculptUpdates(LocalBitmap& unit) { - /* looking for sculptmap using objects only */ - std::vector object_list = unit->getUsingObjects(false, false, true); + std::vector object_list = unit.getUsingObjects(false, false, true); if (object_list.empty()) { return; } for( std::vector::iterator iter = object_list.begin(); iter != object_list.end(); iter++ ) { affected_object aobj = *iter; - if ( aobj.object ) + if (aobj.object) { - if ( !aobj.local_sculptmap ) { continue; } // should never get here. only in case of misuse. - + if (!aobj.local_sculptmap) continue; // should never get here. only in case of misuse. // update code [begin] - if ( unit->volume_dirty ) + if (unit.volume_dirty) { - LLImageRaw* rawimage = gTextureList.findImage( unit->getID() )->getCachedRawImage(); + LLImageRaw* rawimage = gTextureList.findImage(unit.getID(), TEX_LIST_STANDARD)->getCachedRawImage(); - aobj.object->getVolume()->sculpt(rawimage->getWidth(), rawimage->getHeight(), - rawimage->getComponents(), rawimage->getData(), 0); - unit->volume_dirty = false; + aobj.object->getVolume()->sculpt(rawimage->getWidth(), rawimage->getHeight(), rawimage->getComponents(), rawimage->getData(), 0, true); + unit.volume_dirty = false; } - // tell affected drawable it's got updated - aobj.object->mDrawable->getVOVolume()->setSculptChanged( true ); - aobj.object->mDrawable->getVOVolume()->markForUpdate( true ); + // tell affected drawable it's got updated + aobj.object->mDrawable->getVOVolume()->setSculptChanged(true); + aobj.object->mDrawable->getVOVolume()->markForUpdate(true); // update code [end] } - } - } /*==================================================*/ @@ -722,36 +718,6 @@ void LocalAssetBrowser::PerformSculptUpdates(LocalBitmap* unit) Destroyed when the floater is closed. */ - -// Floater Globals -FloaterLocalAssetBrowser* FloaterLocalAssetBrowser::sLFInstance = NULL; - -// widgets: - LLButton* mAddBtn; - LLButton* mDelBtn; - LLButton* mMoreBtn; - LLButton* mLessBtn; - LLButton* mUploadBtn; - - - LLScrollListCtrl* mBitmapList; - LLTextureCtrl* mTextureView; - LLCheckBoxCtrl* mUpdateChkBox; - - LLLineEditor* mPathTxt; - LLLineEditor* mUUIDTxt; - LLLineEditor* mNameTxt; - - LLTextBox* mLinkTxt; - LLTextBox* mTimeTxt; - LLComboBox* mTypeComboBox; - - LLTextBox* mCaptionPathTxt; - LLTextBox* mCaptionUUIDTxt; - LLTextBox* mCaptionLinkTxt; - LLTextBox* mCaptionNameTxt; - LLTextBox* mCaptionTimeTxt; - FloaterLocalAssetBrowser::FloaterLocalAssetBrowser() : LLFloater(std::string("local_bitmap_browser_floater")) { @@ -791,12 +757,15 @@ FloaterLocalAssetBrowser::FloaterLocalAssetBrowser() mDelBtn->setEnabled( false ); mUploadBtn->setEnabled( false ); + // Initialize visibility + FloaterResize(true); + // setting button callbacks: - mAddBtn->setClickedCallback( onClickAdd, this); - mDelBtn->setClickedCallback( onClickDel, this); - mMoreBtn->setClickedCallback( onClickMore, this); - mLessBtn->setClickedCallback( onClickLess, this); - mUploadBtn->setClickedCallback( onClickUpload, this); + mAddBtn->setClickedCallback(boost::bind(&FloaterLocalAssetBrowser::onClickAdd, this)); + mDelBtn->setClickedCallback(boost::bind(&FloaterLocalAssetBrowser::onClickDel, this)); + mMoreBtn->setClickedCallback(boost::bind(&FloaterLocalAssetBrowser::FloaterResize, this, true)); + mLessBtn->setClickedCallback(boost::bind(&FloaterLocalAssetBrowser::FloaterResize, this, false)); + mUploadBtn->setClickedCallback(boost::bind(&FloaterLocalAssetBrowser::onClickUpload, this)); // combo callback mTypeComboBox->setCommitCallback(boost::bind(&FloaterLocalAssetBrowser::onCommitTypeCombo,this)); @@ -807,47 +776,39 @@ FloaterLocalAssetBrowser::FloaterLocalAssetBrowser() // checkbox callbacks mUpdateChkBox->setCommitCallback(boost::bind(&FloaterLocalAssetBrowser::onClickUpdateChkbox,this)); + // Allow changing the ID! + mUUIDTxt->setCommitCallback(boost::bind(&FloaterLocalAssetBrowser::onUpdateID, this, _2)); + mUUIDTxt->setCommitOnReturn(true); + mUUIDTxt->setCommitOnFocusLost(true); } void FloaterLocalAssetBrowser::show(void*) { - if (!sLFInstance) - sLFInstance = new FloaterLocalAssetBrowser(); - sLFInstance->open(); + if (!sLFInstance) + sLFInstance = new FloaterLocalAssetBrowser(); + sLFInstance->open(); sLFInstance->UpdateBitmapScrollList(); } FloaterLocalAssetBrowser::~FloaterLocalAssetBrowser() { - sLFInstance=NULL; + sLFInstance = NULL; } -void FloaterLocalAssetBrowser::onClickAdd(void* userdata) +void FloaterLocalAssetBrowser::onClickAdd() { gLocalBrowser->AddBitmap(); } -void FloaterLocalAssetBrowser::onClickDel(void* userdata) -{ - gLocalBrowser->DelBitmap( sLFInstance->mBitmapList->getAllSelected() ); -} - -/* what stopped me from using a single button and simply changing it's label - is the fact that i'd need to hardcode the button labels here, and that is griff. */ -void FloaterLocalAssetBrowser::onClickMore(void* userdata) -{ - FloaterResize(true); -} - -void FloaterLocalAssetBrowser::onClickLess(void* userdata) +void FloaterLocalAssetBrowser::onClickDel() { - FloaterResize(false); + gLocalBrowser->DelBitmap(mBitmapList->getAllSelected()); } -void FloaterLocalAssetBrowser::onClickUpload(void* userdata) +void FloaterLocalAssetBrowser::onClickUpload() { std::string filename = gLocalBrowser->GetBitmapUnit( - (LLUUID)sLFInstance->mBitmapList->getSelectedItemLabel(BITMAPLIST_COL_ID) )->getFileName(); + (LLUUID)mBitmapList->getSelectedItemLabel(BITMAPLIST_COL_ID) )->getFileName(); if ( !filename.empty() ) { @@ -858,9 +819,9 @@ void FloaterLocalAssetBrowser::onClickUpload(void* userdata) void FloaterLocalAssetBrowser::onChooseBitmapList() { - bool button_status = mBitmapList->isEmpty(); - mDelBtn->setEnabled(!button_status); - mUploadBtn->setEnabled(!button_status); + bool button_status = !mBitmapList->isEmpty() && mBitmapList->getFirstSelected(); + mDelBtn->setEnabled(button_status); + mUploadBtn->setEnabled(button_status); UpdateRightSide(); } @@ -879,71 +840,74 @@ void FloaterLocalAssetBrowser::onCommitTypeCombo() { std::string temp_str = mBitmapList->getSelectedItemLabel(BITMAPLIST_COL_ID); - if ( !temp_str.empty() ) + if (!temp_str.empty()) { - S32 selection = sLFInstance->mTypeComboBox->getCurrentIndex(); - gLocalBrowser->onSetType( (LLUUID)temp_str, selection ); + S32 selection = mTypeComboBox->getCurrentIndex(); + gLocalBrowser->onSetType((LLUUID)temp_str, selection); } } -void FloaterLocalAssetBrowser::FloaterResize(bool expand) +void FloaterLocalAssetBrowser::onUpdateID(const LLSD& val) { - sLFInstance->mMoreBtn->setVisible(!expand); - sLFInstance->mLessBtn->setVisible(expand); - sLFInstance->mTextureView->setVisible(expand); - sLFInstance->mUpdateChkBox->setVisible(expand); - sLFInstance->mCaptionPathTxt->setVisible(expand); - sLFInstance->mCaptionUUIDTxt->setVisible(expand); - sLFInstance->mCaptionLinkTxt->setVisible(expand); - sLFInstance->mCaptionNameTxt->setVisible(expand); - sLFInstance->mCaptionTimeTxt->setVisible(expand); - sLFInstance->mTypeComboBox->setVisible(expand); - - sLFInstance->mTimeTxt->setVisible(expand); - sLFInstance->mPathTxt->setVisible(expand); - sLFInstance->mUUIDTxt->setVisible(expand); - sLFInstance->mLinkTxt->setVisible(expand); - sLFInstance->mNameTxt->setVisible(expand); - - if(expand) - { - sLFInstance->reshape(LF_FLOATER_EXPAND_WIDTH, LF_FLOATER_HEIGHT); - sLFInstance->setResizeLimits(LF_FLOATER_EXPAND_WIDTH, LF_FLOATER_HEIGHT); - sLFInstance->UpdateRightSide(); - } + const auto& id = val.asUUID(); + const auto& col = mBitmapList->getFirstSelected()->getColumn(BITMAPLIST_COL_ID); + const auto& old_id = col->getValue().asString(); + if (id.isNull() && id.asString() != old_id) // Just reset if invalid or unchanged + mUUIDTxt->setValue(old_id); else - { - sLFInstance->reshape(LF_FLOATER_CONTRACT_WIDTH, LF_FLOATER_HEIGHT); - sLFInstance->setResizeLimits(LF_FLOATER_CONTRACT_WIDTH, LF_FLOATER_HEIGHT); + { + gLocalBrowser->GetBitmapUnit(LLUUID(old_id))->setID(id); + mTextureView->setImageAssetID(id); + col->setValue(id); } +} + +void FloaterLocalAssetBrowser::FloaterResize(bool expand) +{ + mMoreBtn->setVisible(!expand); + mLessBtn->setVisible(expand); + mTextureView->setVisible(expand); + mUpdateChkBox->setVisible(expand); + mCaptionPathTxt->setVisible(expand); + mCaptionUUIDTxt->setVisible(expand); + mCaptionLinkTxt->setVisible(expand); + mCaptionNameTxt->setVisible(expand); + mCaptionTimeTxt->setVisible(expand); + mTypeComboBox->setVisible(expand); + mTimeTxt->setVisible(expand); + mPathTxt->setVisible(expand); + mUUIDTxt->setVisible(expand); + mLinkTxt->setVisible(expand); + mNameTxt->setVisible(expand); + + reshape(expand ? LF_FLOATER_EXPAND_WIDTH : LF_FLOATER_CONTRACT_WIDTH, LF_FLOATER_HEIGHT); + setResizeLimits(expand ? LF_FLOATER_EXPAND_WIDTH : LF_FLOATER_CONTRACT_WIDTH, LF_FLOATER_HEIGHT); + if (expand) UpdateRightSide(); } void FloaterLocalAssetBrowser::UpdateBitmapScrollList() { - if ( !sLFInstance ) { return; } - - sLFInstance->mBitmapList->clearRows(); + mBitmapList->clearRows(); if (!gLocalBrowser->loaded_bitmaps.empty()) { - LocalAssetBrowser::local_list_iter iter; for(iter = gLocalBrowser->loaded_bitmaps.begin(); iter != gLocalBrowser->loaded_bitmaps.end(); iter++) { LLSD element; element["columns"][BITMAPLIST_COL_NAME]["column"] = "bitmap_name"; element["columns"][BITMAPLIST_COL_NAME]["type"] = "text"; - element["columns"][BITMAPLIST_COL_NAME]["value"] = (*iter)->getShortName(); + element["columns"][BITMAPLIST_COL_NAME]["value"] = (*iter).getShortName(); element["columns"][BITMAPLIST_COL_ID]["column"] = "bitmap_uuid"; element["columns"][BITMAPLIST_COL_ID]["type"] = "text"; - element["columns"][BITMAPLIST_COL_ID]["value"] = (*iter)->getID(); + element["columns"][BITMAPLIST_COL_ID]["value"] = (*iter).getID(); - sLFInstance->mBitmapList->addElement(element); + mBitmapList->addElement(element); } } - sLFInstance->UpdateRightSide(); + onChooseBitmapList(); } void FloaterLocalAssetBrowser::UpdateRightSide() @@ -951,47 +915,47 @@ void FloaterLocalAssetBrowser::UpdateRightSide() /* Since i'm not keeping a bool on if the floater is expanded or not, i'll just check if one of the widgets that shows when the floater is expanded is visible. - Also obviously before updating - checking if something IS actually selected :o */ + if (!mTextureView->getVisible()) return; - if ( !sLFInstance->mTextureView->getVisible() ) { return; } - - if ( !sLFInstance->mBitmapList->getAllSelected().empty() ) - { - LocalBitmap* unit = gLocalBrowser->GetBitmapUnit( LLUUID(sLFInstance->mBitmapList->getSelectedItemLabel(BITMAPLIST_COL_ID)) ); - + if (const auto& selected = mBitmapList->getFirstSelected()) + { + LocalBitmap* unit = gLocalBrowser->GetBitmapUnit(LLUUID(selected->getColumn(BITMAPLIST_COL_ID)->getValue().asString())); if ( unit ) { - sLFInstance->mTextureView->setImageAssetID( unit->getID() ); - sLFInstance->mUpdateChkBox->set( unit->getUpdateBool() ); - sLFInstance->mPathTxt->setText( unit->getFileName() ); - sLFInstance->mUUIDTxt->setText( unit->getID().asString() ); - sLFInstance->mNameTxt->setText( unit->getShortName() ); - sLFInstance->mTimeTxt->setText( unit->getLastModified().asString() ); - sLFInstance->mLinkTxt->setText( unit->getLinkStatus() ); - sLFInstance->mTypeComboBox->selectNthItem( unit->getType() ); - - sLFInstance->mTextureView->setEnabled(true); - sLFInstance->mUpdateChkBox->setEnabled(true); - sLFInstance->mTypeComboBox->setEnabled(true); + mTextureView->setImageAssetID(unit->getID()); + mUpdateChkBox->set(unit->getUpdateBool()); + mPathTxt->setText(unit->getFileName()); + mUUIDTxt->setText(unit->getID().asString()); + mNameTxt->setText(unit->getShortName()); + mTimeTxt->setText(unit->getLastModified().asString()); + mLinkTxt->setText(unit->getLinkStatus()); + mTypeComboBox->selectNthItem(unit->getType()); + + mTextureView->setEnabled(true); + mUpdateChkBox->setEnabled(true); + mTypeComboBox->setEnabled(true); + mUUIDTxt->setEnabled(true); } } else { - sLFInstance->mTextureView->setImageAssetID( NO_IMAGE ); - sLFInstance->mTextureView->setEnabled( false ); - sLFInstance->mUpdateChkBox->set( false ); - sLFInstance->mUpdateChkBox->setEnabled( false ); - - sLFInstance->mTypeComboBox->selectFirstItem(); - sLFInstance->mTypeComboBox->setEnabled( false ); - - sLFInstance->mPathTxt->setText( LLStringExplicit("None") ); - sLFInstance->mUUIDTxt->setText( LLStringExplicit("None") ); - sLFInstance->mNameTxt->setText( LLStringExplicit("None") ); - sLFInstance->mLinkTxt->setText( LLStringExplicit("None") ); - sLFInstance->mTimeTxt->setText( LLStringExplicit("None") ); + mTextureView->setImageAssetID(NO_IMAGE); + mTextureView->setEnabled(false); + mUpdateChkBox->set(false); + mUpdateChkBox->setEnabled(false); + + mTypeComboBox->selectFirstItem(); + mTypeComboBox->setEnabled(false); + mUUIDTxt->setEnabled(false); + + const auto none = LLStringExplicit("None"); + mPathTxt->setText(none); + mUUIDTxt->setText(none); + mNameTxt->setText(none); + mLinkTxt->setText(none); + mTimeTxt->setText(none); } } @@ -1033,7 +997,7 @@ void LocalAssetBrowserTimer::stop() mEventTimer.stop(); } -bool LocalAssetBrowserTimer::isRunning() +bool LocalAssetBrowserTimer::isRunning() const { return mEventTimer.getStarted(); } diff --git a/indra/newview/floaterlocalassetbrowse.h b/indra/newview/floaterlocalassetbrowse.h index b4cbc149f4..290fbe4e35 100644 --- a/indra/newview/floaterlocalassetbrowse.h +++ b/indra/newview/floaterlocalassetbrowse.h @@ -97,8 +97,16 @@ struct affected_object class LocalBitmap { public: - LocalBitmap(std::string filename); - virtual ~LocalBitmap(void); + struct Params : public LLInitParam::Block + { + Mandatory fullpath; + Optional keep_updating; + Optional type; + Optional id; + Params(const std::string& path = LLStringUtil::null); + }; + LocalBitmap(const Params& p); + virtual ~LocalBitmap(); friend class LocalAssetBrowser; public: /* [enums, typedefs, etc] */ @@ -127,26 +135,28 @@ class LocalBitmap }; public: /* [information query functions] */ - std::string getShortName(void); - std::string getFileName(void); - LLUUID getID(void); - LLSD getLastModified(void); - std::string getLinkStatus(void); - bool getUpdateBool(void); + std::string getShortName() const; + std::string getFileName() const; + LLUUID getID() const; + void setID(const LLUUID&); + LLSD getLastModified() const; + std::string getLinkStatus() const; + bool getUpdateBool() const; void setType( S32 ); - bool getIfValidBool(void); - S32 getType(void); - void getDebugInfo(void); + bool getIfValidBool() const; + S32 getType() const; + void getDebugInfo() const; + LLSD asLLSD() const; + private: /* [maintenence functions] */ - void updateSelf(void); + void updateSelf(); bool decodeSelf(LLImageRaw* rawimg); - void setUpdateBool(void); + void setUpdateBool(); - LocalBitmap* getThis(void); - std::vector getFaceUsesThis(LLDrawable*); + std::vector getFaceUsesThis(LLDrawable*) const; std::vector getUsingObjects(bool seek_by_type = true, - bool seek_textures = false, bool seek_sculptmaps = false); + bool seek_textures = false, bool seek_sculptmaps = false) const; protected: /* [basic properties] */ std::string shortname; @@ -174,9 +184,10 @@ class LocalBitmap class AIFilePicker; -class LocalAssetBrowser +class LocalAssetBrowser : public LLSingleton { public: + const std::string getFileName() const; LocalAssetBrowser(); virtual ~LocalAssetBrowser(); friend class FloaterLocalAssetBrowser; @@ -184,7 +195,8 @@ class LocalAssetBrowser static void UpdateTextureCtrlList(LLScrollListCtrl*); static void setLayerUpdated(bool toggle) { mLayerUpdated = toggle; } static void setSculptUpdated(bool toggle) { mSculptUpdated = toggle; } - static void AddBitmap(void); + static void add(const LocalBitmap& unit) { loaded_bitmaps.push_back(unit); } + static void AddBitmap(); static void AddBitmap_continued(AIFilePicker* filepicker); static void DelBitmap( std::vector, S32 column = BITMAPLIST_COL_ID ); @@ -194,18 +206,18 @@ class LocalAssetBrowser the latter - each time the button's pressed. */ private: - static void onChangeHappened(void); + static void onChangeHappened(); static void onUpdateBool(LLUUID); static void onSetType(LLUUID, S32); static LocalBitmap* GetBitmapUnit(LLUUID); - static bool IsDoingUpdates(void); - static void PingTimer(void); - static void PerformTimedActions(void); - static void PerformSculptUpdates(LocalBitmap*); + static bool IsDoingUpdates(); + static void PingTimer(); + static void PerformTimedActions(); + static void PerformSculptUpdates(LocalBitmap&); protected: - static std::vector loaded_bitmaps; - typedef std::vector::iterator local_list_iter; + static std::vector loaded_bitmaps; + typedef std::vector::iterator local_list_iter; static bool mLayerUpdated; static bool mSculptUpdated; }; @@ -225,17 +237,13 @@ class FloaterLocalAssetBrowser : public LLFloater FloaterLocalAssetBrowser(); virtual ~FloaterLocalAssetBrowser(); static void show(void*); - - private: /* Widget related callbacks */ - // Button callback declarations - static void onClickAdd(void* userdata); - static void onClickDel(void* userdata); - static void onClickMore(void* userdata); - static void onClickLess(void* userdata); - static void onClickUpload(void* userdata); + // Button callback declarations + void onClickAdd(); + void onClickDel(); + void onClickUpload(); // ScrollList callback declarations void onChooseBitmapList(); @@ -246,6 +254,8 @@ class FloaterLocalAssetBrowser : public LLFloater // Combobox type select void onCommitTypeCombo(); + void onUpdateID(const LLSD& val); + // Widgets LLButton* mAddBtn; LLButton* mDelBtn; @@ -271,17 +281,12 @@ class FloaterLocalAssetBrowser : public LLFloater LLTextBox* mCaptionNameTxt; LLTextBox* mCaptionTimeTxt; - /* static pointer to self, wai? oh well. */ - static FloaterLocalAssetBrowser* sLFInstance; - // non-widget functions - static void FloaterResize(bool expand); - static void UpdateRightSide(void); + void FloaterResize(bool expand); + void UpdateRightSide(); public: - static void UpdateBitmapScrollList(void); - - + void UpdateBitmapScrollList(); }; /*==================================================*/ @@ -299,10 +304,10 @@ class LocalAssetBrowserTimer : public LLEventTimer public: LocalAssetBrowserTimer(); ~LocalAssetBrowserTimer(); - virtual BOOL tick(); + BOOL tick() override; void start(); void stop(); - bool isRunning(); + bool isRunning() const; }; #endif diff --git a/indra/newview/floatervoicelicense.cpp b/indra/newview/floatervoicelicense.cpp deleted file mode 100644 index 1013980066..0000000000 --- a/indra/newview/floatervoicelicense.cpp +++ /dev/null @@ -1,244 +0,0 @@ -/** -* @file floatervoicelicense.cpp -* @brief prompts user to agree to the Vivox license in order to enable voice -* -* $LicenseInfo:firstyear=2009&license=viewergpl$ -* -* Copyright (c) 2010, McCabe Maxsted -* -* Imprudence Viewer Source Code -* The source code in this file ("Source Code") is provided to you -* under the terms of the GNU General Public License, version 2.0 -* ("GPL"). Terms of the GPL can be found in doc/GPL-license.txt in -* this distribution, or online at -* http://secondlifegrid.net/programs/open_source/licensing/gplv2 -* -* There are special exceptions to the terms and conditions of the GPL as -* it is applied to this Source Code. View the full text of the exception -* in the file doc/FLOSS-exception.txt in this software distribution, or -* online at http://secondlifegrid.net/programs/open_source/licensing/flossexception -* -* By copying, modifying or distributing this software, you acknowledge -* that you have read and understood your obligations described above, -* and agree to abide by those obligations. -* -* ALL SOURCE CODE IS PROVIDED "AS IS." THE AUTHOR MAKES NO -* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, -* COMPLETENESS OR PERFORMANCE. -* $/LicenseInfo$ -*/ - -#include "llviewerprecompiledheaders.h" - -#include "floatervoicelicense.h" - -// viewer includes -#include "llagent.h" -#include "llappviewer.h" -#include "llstartup.h" -#include "llviewercontrol.h" -#include "llviewerstats.h" -#include "llviewertexteditor.h" -#include "llviewerwindow.h" - -// linden library includes -#include "llbutton.h" -#include "llhttpclient.h" -#include "llhttpstatuscodes.h" // for HTTP_FOUND -#include "llradiogroup.h" -#include "lltextbox.h" -#include "llui.h" -#include "lluictrlfactory.h" -#include "llvfile.h" -#include "message.h" - -class AIHTTPTimeoutPolicy; -extern AIHTTPTimeoutPolicy iamHereVoice_timeout; - -FloaterVoiceLicense::FloaterVoiceLicense(const LLSD& key) -: LLModalDialog( std::string(" "), 100, 100 ), - mLoadCompleteCount( 0 ) -{ - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_voice_license.xml"); -} - -// helper class that trys to download a URL from a web site and calls a method -// on parent class indicating if the web server is working or not -class LLIamHereVoice : public LLHTTPClient::ResponderWithResult -{ - private: - LLIamHereVoice( FloaterVoiceLicense* parent ) : - mParent( parent ) - {} - - FloaterVoiceLicense* mParent; - - public: - static boost::intrusive_ptr< LLIamHereVoice > build( FloaterVoiceLicense* parent ) - { - return boost::intrusive_ptr< LLIamHereVoice >( new LLIamHereVoice( parent ) ); - }; - - virtual void setParent( FloaterVoiceLicense* parentIn ) - { - mParent = parentIn; - }; - - /*virtual*/ void result( const LLSD& content ) - { - if ( mParent ) - mParent->setSiteIsAlive( true ); - }; - - /*virtual*/ void error( U32 status, const std::string& reason ) - { - if ( mParent ) - { - // *HACK: For purposes of this alive check, 302 Found - // (aka Moved Temporarily) is considered alive. The web site - // redirects this link to a "cache busting" temporary URL. JC - bool alive = (status == HTTP_FOUND); - mParent->setSiteIsAlive( alive ); - } - }; - - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return iamHereVoice_timeout; } - /*virtual*/ bool redirect_status_ok(void) const { return true; } - /*virtual*/ char const* getName(void) const { return "LLIamHereVoice"; } -}; - -// this is global and not a class member to keep crud out of the header file -namespace { - boost::intrusive_ptr< LLIamHereVoice > gResponsePtr = 0; -}; - -BOOL FloaterVoiceLicense::postBuild() -{ - childSetAction("Continue", onContinue, this); - childSetAction("Cancel", onCancel, this); - childSetCommitCallback("agree_chk", updateAgree, this); - - // disable Agree to License radio button until the page has fully loaded - LLCheckBoxCtrl* license_agreement = getChild("agree_chk"); - license_agreement->setEnabled( false ); - - // hide the SL text widget if we're displaying license with using a browser widget. - LLTextEditor *editor = getChild("license_text"); - editor->setVisible( FALSE ); - - LLMediaCtrl* web_browser = getChild("license_html"); - if ( web_browser ) - { - // start to observe it so we see navigate complete events - web_browser->addObserver( this ); - std::string url = getString( "real_url" ); - if(url.substr(0,4) == "http") { - gResponsePtr = LLIamHereVoice::build( this ); - LLHTTPClient::get( url, gResponsePtr ); - } else { - setSiteIsAlive(false); - } - } - - return TRUE; -} - -void FloaterVoiceLicense::setSiteIsAlive( bool alive ) -{ - LLMediaCtrl* web_browser = getChild("license_html"); - // if the contents of the site was retrieved - if ( alive ) - { - if ( web_browser ) - { - // navigate to the "real" page - std::string real_url = getString( "real_url" ); - web_browser->navigateTo(real_url); - } - } - else - { - web_browser->navigateToLocalPage("license", getString("fallback_html")); - // normally this is set when navigation to license page completes (so you can't accept before it loads) - // but if the page is unavailable, we need to do this now - LLCheckBoxCtrl* license_agreement = getChild("agree_chk"); - license_agreement->setEnabled( true ); - } -} - -FloaterVoiceLicense::~FloaterVoiceLicense() -{ - - // tell the responder we're not here anymore - if ( gResponsePtr ) - { - gResponsePtr->setParent( 0 ); - } -} - -// virtual -void FloaterVoiceLicense::draw() -{ - // draw children - LLModalDialog::draw(); -} - -// static -void FloaterVoiceLicense::updateAgree(LLUICtrl*, void* userdata ) -{ - FloaterVoiceLicense* self = (FloaterVoiceLicense*) userdata; - bool agree = self->childGetValue("agree_chk").asBoolean(); - self->childSetEnabled("Continue", agree); -} - -// static -void FloaterVoiceLicense::onContinue( void* userdata ) -{ - FloaterVoiceLicense* self = (FloaterVoiceLicense*) userdata; - llinfos << "User agreed to the Vivox personal license" << llendl; - - // enabling voice by default here seems like the best behavior - gSavedSettings.setBOOL("EnableVoiceChat", TRUE); - gSavedSettings.setBOOL("VivoxLicenseAccepted", TRUE); - - // save these settings in case something bad happens later - gSavedSettings.saveToFile(gSavedSettings.getString("ClientSettingsFile"), TRUE); - - if (LLStartUp::getStartupState() == STATE_LOGIN_VOICE_LICENSE) - { - LLStartUp::setStartupState( STATE_LOGIN_AUTH_INIT ); // Go back and finish authentication - } - self->close(); // destroys this object -} - -// static -void FloaterVoiceLicense::onCancel( void* userdata ) -{ - FloaterVoiceLicense* self = (FloaterVoiceLicense*) userdata; - llinfos << "User disagreed with the vivox personal license" << llendl; - gSavedSettings.setBOOL("EnableVoiceChat", FALSE); - gSavedSettings.setBOOL("VivoxLicenseAccepted", FALSE); - - if (LLStartUp::getStartupState() == STATE_LOGIN_VOICE_LICENSE) - { - LLStartUp::setStartupState( STATE_LOGIN_AUTH_INIT ); // Go back and finish authentication - } - self->mLoadCompleteCount = 0; // reset counter for next time we come here - self->close(); // destroys this object -} - -//virtual -void FloaterVoiceLicense::handleMediaEvent(LLPluginClassMedia* /*self*/, EMediaEvent event) -{ - if(event == MEDIA_EVENT_NAVIGATE_COMPLETE) - { - // skip past the loading screen navigate complete - if ( ++mLoadCompleteCount == 2 ) - { - llinfos << "NAVIGATE COMPLETE" << llendl; - // enable Agree to License radio button now that page has loaded - LLCheckBoxCtrl * license_agreement = getChild("agree_chk"); - license_agreement->setEnabled( true ); - } - } -} diff --git a/indra/newview/floatervoicelicense.h b/indra/newview/floatervoicelicense.h deleted file mode 100644 index 10aaa1979d..0000000000 --- a/indra/newview/floatervoicelicense.h +++ /dev/null @@ -1,72 +0,0 @@ -/** -* @file floatervoicelicense.h -* @brief prompts user to agree to the Vivox license in order to enable voice -* -* $LicenseInfo:firstyear=2009&license=viewergpl$ -* -* Copyright (c) 2010, McCabe Maxsted -* -* Imprudence Viewer Source Code -* The source code in this file ("Source Code") is provided to you -* under the terms of the GNU General Public License, version 2.0 -* ("GPL"). Terms of the GPL can be found in doc/GPL-license.txt in -* this distribution, or online at -* http://secondlifegrid.net/programs/open_source/licensing/gplv2 -* -* There are special exceptions to the terms and conditions of the GPL as -* it is applied to this Source Code. View the full text of the exception -* in the file doc/FLOSS-exception.txt in this software distribution, or -* online at http://secondlifegrid.net/programs/open_source/licensing/flossexception -* -* By copying, modifying or distributing this software, you acknowledge -* that you have read and understood your obligations described above, -* and agree to abide by those obligations. -* -* ALL SOURCE CODE IS PROVIDED "AS IS." THE AUTHOR MAKES NO -* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, -* COMPLETENESS OR PERFORMANCE. -* $/LicenseInfo$ -*/ - -#ifndef FLOATERVOICELICENSE_H -#define FLOATERVOICELICENSE_H - -#include "llfloater.h" - -#include "llmodaldialog.h" -#include "llassetstorage.h" -#include "llmediactrl.h" - -class LLButton; -class LLRadioGroup; -class LLVFS; -class LLTextEditor; -class LLUUID; - -class FloaterVoiceLicense : - public LLModalDialog, - public LLViewerMediaObserver, - public LLFloaterSingleton -{ -public: - FloaterVoiceLicense(const LLSD& key); - virtual ~FloaterVoiceLicense(); - - BOOL postBuild(); - - virtual void draw(); - - static void updateAgree( LLUICtrl *, void* userdata ); - static void onContinue( void* userdata ); - static void onCancel( void* userdata ); - - void setSiteIsAlive( bool alive ); - - // inherited from LLViewerMediaObserver - /*virtual*/ void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event); - -private: - int mLoadCompleteCount; -}; - -#endif // FLOATERVOICELICENSE_H diff --git a/indra/newview/fonts/DejaVuSansCondensed-Bold.ttf b/indra/newview/fonts/DejaVuSansCondensed-Bold.ttf deleted file mode 100644 index 9edd89c3dc..0000000000 Binary files a/indra/newview/fonts/DejaVuSansCondensed-Bold.ttf and /dev/null differ diff --git a/indra/newview/fonts/DejaVuSansCondensed.ttf b/indra/newview/fonts/DejaVuSansCondensed.ttf deleted file mode 100644 index 826e619b78..0000000000 Binary files a/indra/newview/fonts/DejaVuSansCondensed.ttf and /dev/null differ diff --git a/indra/newview/fonts/DejaVuSansMono.ttf b/indra/newview/fonts/DejaVuSansMono.ttf deleted file mode 100644 index 19d188832b..0000000000 Binary files a/indra/newview/fonts/DejaVuSansMono.ttf and /dev/null differ diff --git a/indra/newview/fonts/DroidSans-Bold.ttf b/indra/newview/fonts/DroidSans-Bold.ttf deleted file mode 100644 index d065b64eb1..0000000000 Binary files a/indra/newview/fonts/DroidSans-Bold.ttf and /dev/null differ diff --git a/indra/newview/fonts/DroidSans.ttf b/indra/newview/fonts/DroidSans.ttf deleted file mode 100644 index ad1efca88a..0000000000 Binary files a/indra/newview/fonts/DroidSans.ttf and /dev/null differ diff --git a/indra/newview/generate_breakpad_symbols.py b/indra/newview/generate_breakpad_symbols.py new file mode 100644 index 0000000000..2fc5abe8ba --- /dev/null +++ b/indra/newview/generate_breakpad_symbols.py @@ -0,0 +1,166 @@ +#!/usr/bin/env python2 +"""\ +@file generate_breakpad_symbols.py +@author Brad Kittenbrink +@brief Simple tool for generating google_breakpad symbol information + for the crash reporter. + +$LicenseInfo:firstyear=2010&license=viewerlgpl$ +Second Life Viewer Source Code +Copyright (C) 2010-2011, Linden Research, Inc. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; +version 2.1 of the License only. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +$/LicenseInfo$ +""" + + +import collections +import fnmatch +import itertools +import os +import re +import sys +import shlex +import subprocess +import tarfile +import StringIO +import pprint + +DEBUG=False + +def usage(): + print >>sys.stderr, "usage: %s search_dirs viewer_exes libs_suffix dump_syms_tool viewer_symbol_file" % sys.argv[0] + +class MissingModuleError(Exception): + def __init__(self, modules): + Exception.__init__(self, "Failed to find required modules: %r" % modules) + self.modules = modules + +def main(configuration, search_dirs, viewer_exes, libs_suffix, dump_syms_tool, viewer_symbol_file): + print "generate_breakpad_symbols run with args: %s" % str((configuration, search_dirs, viewer_exes, libs_suffix, dump_syms_tool, viewer_symbol_file)) + + if not re.match("release", configuration, re.IGNORECASE): + print "skipping breakpad symbol generation for non-release build." + return 0 + + # split up list of viewer_exes + # "'Second Life' SLPlugin" becomes ['Second Life', 'SLPlugin'] + viewer_exes = shlex.split(viewer_exes) + + found_required = dict([(module, False) for module in viewer_exes]) + + def matches(f): + if f in viewer_exes: + found_required[f] = True + return True + return fnmatch.fnmatch(f, libs_suffix) + + search_dirs = search_dirs.split(";") + + def list_files(): + for search_dir in search_dirs: + for (dirname, subdirs, filenames) in os.walk(search_dir): + if DEBUG: + print "scanning '%s' for modules..." % dirname + for f in itertools.ifilter(matches, filenames): + yield os.path.join(dirname, f) + + def dump_module(m): + print "dumping module '%s' with '%s'..." % (m, dump_syms_tool) + dsym_full_path = m + child = subprocess.Popen([dump_syms_tool, dsym_full_path] , stdout=subprocess.PIPE) + out, err = child.communicate() + return (m,child.returncode, out, err) + + + modules = {} + + for m in list_files(): + if DEBUG: + print "examining module '%s' ... " % m, + filename=os.path.basename(m) + if -1 != m.find("DWARF"): + # Just use this module; it has the symbols we want. + modules[filename] = m + if DEBUG: + print "found dSYM entry" + elif filename not in modules: + # Only use this if we don't already have a (possibly better) entry. + modules[filename] = m + if DEBUG: + print "found new entry" + elif DEBUG: + print "ignoring entry" + + + print "Found these following modules:" + pprint.pprint( modules ) + + out = tarfile.open(viewer_symbol_file, 'w:bz2') + for (filename,status,symbols,err) in itertools.imap(dump_module, modules.values()): + if status == 0: + module_line = symbols[:symbols.index('\n')] + module_line = module_line.split() + hash_id = module_line[3] + module = ' '.join(module_line[4:]) + if sys.platform in ['win32', 'cygwin']: + mod_name = module[:module.rindex('.pdb')] + else: + mod_name = module + symbolfile = StringIO.StringIO(symbols) + info = tarfile.TarInfo("%(module)s/%(hash_id)s/%(mod_name)s.sym" % dict(module=module, hash_id=hash_id, mod_name=mod_name)) + info.size = symbolfile.len + out.addfile(info, symbolfile) + else: + print >>sys.stderr, "warning: failed to dump symbols for '%s': %s" % (filename, err) + + out.close() + + missing_modules = [m for (m,_) in + itertools.ifilter(lambda (k,v): not v, found_required.iteritems()) + ] + if missing_modules: + print >> sys.stderr, "failed to generate %s" % viewer_symbol_file + os.remove(viewer_symbol_file) + raise MissingModuleError(missing_modules) + + symbols = tarfile.open(viewer_symbol_file, 'r:bz2') + tarfile_members = symbols.getnames() + symbols.close() + + for required_module in viewer_exes: + def match_module_basename(m): + return os.path.splitext(required_module)[0].lower() \ + == os.path.splitext(os.path.basename(m))[0].lower() + # there must be at least one .sym file in tarfile_members that matches + # each required module (ignoring file extensions) + if not any(itertools.imap(match_module_basename, tarfile_members)): + print >> sys.stderr, "failed to find required %s in generated %s" \ + % (required_module, viewer_symbol_file) + os.remove(viewer_symbol_file) + raise MissingModuleError([required_module]) + + print "successfully generated %s including required modules '%s'" % (viewer_symbol_file, viewer_exes) + + return 0 + +if __name__ == "__main__": + if len(sys.argv) != 7: + usage() + sys.exit(1) + sys.exit(main(*sys.argv[1:])) + diff --git a/indra/newview/generichandlers.h b/indra/newview/generichandlers.h index 2a1210b57d..456d9aa535 100644 --- a/indra/newview/generichandlers.h +++ b/indra/newview/generichandlers.h @@ -22,6 +22,9 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#ifndef SG_GENERICHANDLERS_H +#define SG_GENERICHANDLERS_H + class GenericHandlers { public: @@ -29,3 +32,5 @@ class GenericHandlers }; extern GenericHandlers *gGenericHandlers; + +#endif // SG_GENERIC_HANDLERS \ No newline at end of file diff --git a/indra/newview/gpu_table.txt b/indra/newview/gpu_table.txt index ce8e013f0d..af5aa6a125 100644 --- a/indra/newview/gpu_table.txt +++ b/indra/newview/gpu_table.txt @@ -53,6 +53,9 @@ ATI ASUS EAH38xx .*ATI.*ASUS.*EAH38.* 3 1 ATI ASUS EAH43xx .*ATI.*ASUS.*EAH43.* 1 1 ATI ASUS EAH45xx .*ATI.*ASUS.*EAH45.* 1 1 ATI ASUS EAH48xx .*ATI.*ASUS.*EAH48.* 3 1 +ATI ASUS EAH54xx .*ATI.*ASUS.*EAH54.* 3 1 +ATI ASUS EAH55xx .*ATI.*ASUS.*EAH55.* 3 1 +ATI ASUS EAH56xx .*ATI.*ASUS.*EAH56.* 3 1 ATI ASUS EAH57xx .*ATI.*ASUS.*EAH57.* 3 1 ATI ASUS EAH58xx .*ATI.*ASUS.*EAH58.* 3 1 ATI ASUS EAH6xxx .*ATI.*ASUS.*EAH6.* 3 1 @@ -76,9 +79,6 @@ ATI FirePro M5800 .*ATI.*FirePro.*M58.* 3 1 ATI FirePro M7740 .*ATI.*FirePro.*M77.* 3 1 ATI FirePro M7820 .*ATI.*FirePro.*M78.* 3 1 ATI FireMV .*ATI.*FireMV.* 0 1 -ATI Geforce 9500 GT .*ATI.*Geforce 9500 *GT.* 2 1 -ATI Geforce 9600 GT .*ATI.*Geforce 9600 *GT.* 2 1 -ATI Geforce 9800 GT .*ATI.*Geforce 9800 *GT.* 2 1 ATI Generic .*ATI.*Generic.* 0 0 ATI Hercules 9800 .*ATI.*Hercules.*9800.* 1 1 ATI IGP 340M .*ATI.*IGP.*340M.* 0 0 @@ -189,6 +189,14 @@ ATI Radeon HD 7600 .*ATI.*Radeon HD *76.. 3 1 ATI Radeon HD 7700 .*ATI.*Radeon HD *77.. 3 1 ATI Radeon HD 7800 .*ATI.*Radeon HD *78.. 3 1 ATI Radeon HD 7900 .*ATI.*Radeon HD *79.. 3 1 +ATI Radeon HD 8200 .*ATI.*AMD Radeon.* HD 82.* 3 1 +ATI Radeon HD 8300 .*ATI.*AMD Radeon.* HD 83.* 3 1 +ATI Radeon HD 8400 .*ATI.*AMD Radeon.* HD 84.* 3 1 +ATI Radeon HD 8500 .*ATI.*AMD Radeon.* HD 85.* 3 1 +ATI Radeon HD 8600 .*ATI.*AMD Radeon.* HD 86.* 3 1 +ATI Radeon HD 8700 .*ATI.*AMD Radeon.* HD 87.* 3 1 +ATI Radeon HD 8800 .*ATI.*AMD Radeon.* HD 88.* 3 1 +ATI Radeon HD 8900 .*ATI.*AMD Radeon.* HD 89.* 3 1 ATI Radeon OpenGL .*ATI.*Radeon OpenGL.* 0 0 ATI Radeon 2100 .*ATI.*Radeon 21.. 0 1 ATI Radeon 3000 .*ATI.*Radeon 30.. 0 1 @@ -209,7 +217,6 @@ ATI Radeon RX700 .*ATI.*RX70.* 1 1 ATI Radeon RX800 .*ATI.*Radeon *RX80.* 2 1 ATI RS880M .*ATI.*RS880M 1 1 ATI Radeon RX9550 .*ATI.*RX9550.* 1 1 -ATI Radeon VE .*ATI.*Radeon.*VE.* 0 0 ATI Radeon X1000 .*ATI.*Radeon *X10.* 0 1 ATI Radeon X1200 .*ATI.*Radeon *X12.* 0 1 ATI Radeon X1300 .*ATI.*Radeon *X13.* 1 1 @@ -268,6 +275,9 @@ AMD RV730 (HD 4600) .*RV730.* 3 1 AMD RV740 (HD 4700) .*RV740.* 3 1 AMD RV770 (HD 4800) .*RV770.* 3 1 AMD RV790 (HD 4800) .*RV790.* 3 1 +AMD Vega .*(AMD|ATI).*Vega.* 3 1 +AMD Radeon VII .*AMD.*Radeon ?VII.* 3 1 +AMD Radeon RX Series .*ATI.*(Radeon|ASUS).* RX.* 3 1 ATI 760G/Radeon 3000 .*ATI.*AMD 760G.* 1 1 ATI 780L/Radeon 3000 .*ATI.*AMD 780L.* 1 1 ATI Radeon DDR .*ATI.*Radeon ?DDR.* 0 1 @@ -278,6 +288,7 @@ ATI FirePro 5000 .*ATI.*FirePro V5.* 3 1 ATI FirePro 7000 .*ATI.*FirePro V7.* 3 1 ATI FirePro M .*ATI.*FirePro M.* 3 1 ATI Technologies .*ATI *Technologies.* 0 1 +ATI Radeon VE .*ATI.*Radeon.*VE.* 0 0 // This entry is last to work around the "R300" driver problem. ATI R300 (9700) .*R300.* 1 1 ATI Radeon .*ATI.*(Diamond|Radeon).* 0 1 @@ -304,7 +315,15 @@ Intel Eaglelake .*Intel.*Eaglelake.* 0 1 Intel Graphics Media HD .*Intel.*Graphics Media.*HD.* 0 1 Intel HD Graphics 2000 .*Intel.*HD Graphics 2000.* 1 1 Intel HD Graphics 3000 .*Intel.*HD Graphics 3000.* 2 1 +Intel HD Graphics 3000 .*Intel.*Sandybridge.* 2 1 Intel HD Graphics 4000 .*Intel.*HD Graphics 4000.* 2 1 +Intel HD Graphics 4000 .*Intel.*Ivybridge.* 2 1 +Intel Intel Iris Pro Graphics 5200 .*Intel.*Iris Pro Graphics 52.* 2 1 +Intel Intel Iris Graphics 5100 .*Intel.*Iris Graphics 51.* 2 1 +Intel Intel Iris OpenGL Engine .*Intel.*Iris OpenGL.* 2 1 +Intel Intel Iris Pro OpenGL Engine .*Intel.*Iris Pro OpenGL.* 3 1 +Intel HD Graphics 5000 .*Intel.*HD Graphics 5.* 2 1 +Intel HD Graphics 5000 .*Intel.*Haswell.* 2 1 Intel HD Graphics .*Intel.*HD Graphics.* 2 1 Intel Mobile 4 Series .*Intel.*Mobile.* 4 Series.* 0 1 Intel Media Graphics HD .*Intel.*Media Graphics HD.* 0 1 @@ -314,7 +333,10 @@ Intel Springdale .*Intel.*Springdale.* 0 0 Intel HD Graphics 2000 .*Intel.*HD2000.* 1 1 Intel HD Graphics 3000 .*Intel.*HD3000.* 2 1 Matrox .*Matrox.* 0 0 +Intel Mesa (Ivybridge) .*Mesa DRI.*Ivybridge.* 2 1 +Intel Mesa (Haswell) .*Mesa DRI.*Haswell.* 2 1 Mesa .*Mesa.* 0 0 +Gallium .*Gallium.* 1 1 NVIDIA 205 .*NVIDIA .*GeForce 205.* 2 1 NVIDIA 210 .*NVIDIA .*GeForce 210.* 2 1 NVIDIA 310M .*NVIDIA .*GeForce 310M.* 1 1 @@ -410,6 +432,22 @@ NVIDIA GTX 670 .*NVIDIA .*GTX *67.* 3 1 NVIDIA GTX 680M .*NVIDIA .*GTX *680M.* 3 1 NVIDIA GTX 680 .*NVIDIA .*GTX *68.* 3 1 NVIDIA GTX 690 .*NVIDIA .*GTX *69.* 3 1 +NVIDIA GTX 750 .*NVIDIA .*GTX *75.* 3 1 +NVIDIA GTX 760 .*NVIDIA .*GTX *76.* 3 1 +NVIDIA GTX 770 .*NVIDIA .*GTX *77.* 3 1 +NVIDIA GTX 780 .*NVIDIA .*GTX *78.* 3 1 +NVIDIA GTX 970 .*NVIDIA .*GTX *97.* 3 1 +NVIDIA GTX 980 .*NVIDIA .*GTX *98.* 3 1 +NVIDIA GTX 1050 .*NVIDIA.*GTX 105.* 3 1 +NVIDIA GTX 1060 .*NVIDIA.*GTX 106.* 3 1 +NVIDIA GTX 1070 .*NVIDIA.*GTX 107.* 3 1 +NVIDIA GTX 1080 .*NVIDIA.*GTX 108.* 3 1 +NVIDIA GTX 1650 .*NVIDIA.*GTX 165.* 3 1 +NVIDIA GTX 1660 .*NVIDIA.*GTX 166.* 3 1 +NVIDIA GTX TITAN .*NVIDIA .*GTX *TITAN.* 3 1 +NVIDIA GeForce/Quadro RTX .*(GeForce|Quadro) .*RTX.* 3 1 +NVIDIA RTX TITAN .*NVIDIA .*RTX.*TITAN.* 3 1 +NVIDIA GT 7xxM .*NVIDIA .*GT *7.* 3 1 NVIDIA C51 .*NVIDIA .*C51.* 0 1 NVIDIA G72 .*NVIDIA .*G72.* 1 1 NVIDIA G73 .*NVIDIA .*G73.* 1 1 @@ -532,6 +570,7 @@ NVIDIA MCP78 .*NVIDIA .*MCP78.* 1 1 NVIDIA MCP79 .*NVIDIA .*MCP79.* 1 1 NVIDIA MCP7A .*NVIDIA .*MCP7A.* 1 1 NVIDIA Quadro2 .*Quadro2.* 0 1 +NVIDIA Quadro K1000 .*Quadro.* (K1|1)00[0-9].* 2 1 NVIDIA Quadro 1000M .*Quadro.*1000M.* 2 1 NVIDIA Quadro 2000 M/D .*Quadro.*2000.* 3 1 NVIDIA Quadro 3000M .*Quadro.*3000M.* 3 1 @@ -540,6 +579,7 @@ NVIDIA Quadro 4000 .*Quadro *4000.* 3 1 NVIDIA Quadro 50x0 M .*Quadro.*50.0.* 3 1 NVIDIA Quadro 6000 .*Quadro.*6000.* 3 1 NVIDIA Quadro 400 .*Quadro.*400.* 2 1 +NVIDIA Quadro K600 .*Quadro.* (K6|6)0[0-9][^0].* 2 1 NVIDIA Quadro 600 .*Quadro.*600.* 2 1 NVIDIA Quadro4 .*Quadro4.* 0 1 NVIDIA Quadro DCC .*Quadro DCC.* 0 1 @@ -594,6 +634,8 @@ NVIDIA Quadro 6000 .*Quadro.*6000.* 2 1 NVIDIA Quadro 600 .*Quadro.*600.* 2 1 NVIDIA Quadro NVS .*(Quadro|NVIDIA) NVS.* 0 1 NVIDIA RIVA TNT .*RIVA TNT.* 0 0 +NVIDIA GRID .*NVIDIA .*GRID.* 0 0 +NVIDIA ION .*NVIDIA.* *ION.* 2 1 NVIDIA PCI .*NVIDIA.*/PCI/SSE2 0 0 S3 .*S3 Graphics.* 0 0 SiS SiS.* 0 0 diff --git a/indra/newview/hbfloatergrouptitles.cpp b/indra/newview/hbfloatergrouptitles.cpp index c96189de1d..5efb691186 100644 --- a/indra/newview/hbfloatergrouptitles.cpp +++ b/indra/newview/hbfloatergrouptitles.cpp @@ -162,7 +162,7 @@ void HBFloaterGroupTitles::onActivate(void* userdata) void update_titles_list(HBFloaterGroupTitles* self) { S32 i; - S32 count = gAgent.mGroups.count(); + S32 count = gAgent.mGroups.size(); LLUUID id; LLUUID highlight_id = LLUUID::null; LLUUID current_group_id = gAgent.getGroupID(); @@ -178,7 +178,7 @@ void update_titles_list(HBFloaterGroupTitles* self) for (i = 0; i < count; ++i) { - group_datap = &gAgent.mGroups.get(i); + group_datap = &gAgent.mGroups[i]; id = group_datap->mID; if (self->mFirstUse) { diff --git a/indra/newview/hippogridmanager.cpp b/indra/newview/hippogridmanager.cpp index 9febd1777e..f6cff71b96 100644 --- a/indra/newview/hippogridmanager.cpp +++ b/indra/newview/hippogridmanager.cpp @@ -8,7 +8,6 @@ #include #include -#include #include #include #include @@ -16,6 +15,7 @@ #include "lltrans.h" #include "llviewercontrol.h" #include "llweb.h" +#include "aialert.h" // ******************************************************************** // Global Variables @@ -32,6 +32,7 @@ HippoGridInfo HippoGridInfo::FALLBACK_GRIDINFO(""); // ******************************************************************** // ******************************************************************** +const S32 MINIMUM_PRICE_FOR_LISTING = 50; // L$ // ******************************************************************** // Initialize @@ -46,6 +47,7 @@ HippoGridInfo::HippoGridInfo(const std::string& gridName) : mWebSite(LLStringUtil::null), mSupportUrl(LLStringUtil::null), mRegisterUrl(LLStringUtil::null), + mPartnerUrl(LLStringUtil::null), mPasswordUrl(LLStringUtil::null), mSearchUrl(LLStringUtil::null), mGridMessage(""), @@ -54,12 +56,12 @@ HippoGridInfo::HippoGridInfo(const std::string& gridName) : mIsInProductionGrid(false), mIsInAvination(false), mRenderCompat(true), - mInvLinks(false), mAutoUpdate(false), - mMaxAgentGroups(-1), + mLocked(false), mCurrencySymbol("OS$"), mCurrencyText("OS Dollars"), mRealCurrencySymbol("US$"), + mClassifiedFee(MINIMUM_PRICE_FOR_LISTING), mDirectoryFee(30), mUPCSupported(false) { @@ -78,7 +80,7 @@ const std::string& HippoGridInfo::getGridOwner() const } else { - return this->getGridName(); + return getGridName(); } } @@ -99,14 +101,13 @@ void HippoGridInfo::setPlatform(Platform platform) void HippoGridInfo::setPlatform(const std::string& platform) { std::string tmp = platform; - for (unsigned i=0; imXmlState = XML_SUPPORT; else if ((strcasecmp(name, "register") == 0) || (strcasecmp(name, "account") == 0)) self->mXmlState = XML_REGISTER; + else if (strcasecmp(name, "partner") == 0) + self->mXmlState = XML_PARTNER; else if (strcasecmp(name, "password") == 0) self->mXmlState = XML_PASSWORD; else if (strcasecmp(name, "search") == 0) @@ -398,15 +323,13 @@ void HippoGridInfo::onXmlCharacterData(void* userData, const XML_Char* s, int le case XML_LOGINURI: { - std::string loginuri(s, len); - self->mLoginUri = sanitizeUri( loginuri ); + self->setLoginUri(std::string(s, len)); break; } case XML_HELPERURI: { - std::string helperuri(s, len); - self->mHelperUri = sanitizeUri( helperuri ); + self->setHelperUri(std::string(s, len)); break; } @@ -419,7 +342,7 @@ void HippoGridInfo::onXmlCharacterData(void* userData, const XML_Char* s, int le case XML_GRIDNAME: { - if (self->mGridName == "") + if (self->mGridName.empty()) { self->mGridName.assign(s, len); } @@ -430,6 +353,7 @@ void HippoGridInfo::onXmlCharacterData(void* userData, const XML_Char* s, int le case XML_WEBSITE: self->mWebSite.assign(s, len); break; case XML_SUPPORT: self->mSupportUrl.assign(s, len); break; case XML_REGISTER: self->mRegisterUrl.assign(s, len); break; + case XML_PARTNER: self->mPartnerUrl.assign(s, len); break; case XML_PASSWORD: self->mPasswordUrl.assign(s, len); break; case XML_MESSAGE: self->mGridMessage.assign(s, len); break; @@ -437,24 +361,45 @@ void HippoGridInfo::onXmlCharacterData(void* userData, const XML_Char* s, int le } } - -bool HippoGridInfo::retrieveGridInfo() +// Throws AIAlert::ErrorCode with the http status as 'code' (HTTP_OK on XML parse error). +void HippoGridInfo::getGridInfo() { - if (mLoginUri == "") return false; + if (mLoginUri.empty()) + { + // By passing 0 we automatically get GridInfoErrorInstruction appended. + THROW_ALERTC(0, "GridInfoErrorNoLoginURI"); + } - // If last character in uri is not "/" + // Make sure the uri ends on a '/'. std::string uri = mLoginUri; - if (uri.compare(uri.length()-1, 1, "/") != 0) + if (uri.back() != '/') { - uri += '/'; + uri += '/'; } + std::string reply; int result = LLHTTPClient::blockingGetRaw(uri + "get_grid_info", reply); - if (result != 200) return false; + if (result != HTTP_OK) + { + char const* xml_desc; + switch (result) + { + case HTTP_NOT_FOUND: + xml_desc = "GridInfoErrorNotFound"; + break; + case HTTP_METHOD_NOT_ALLOWED: + xml_desc = "GridInfoErrorNotAllowed"; + break; + default: + xml_desc = "AIError"; + break; + } + // LLHTTPClient::blockingGetRaw puts any error message in the reply. + THROW_ALERTC(result, xml_desc, AIArgs("[ERROR]", reply)); + } - llinfos << "Received: " << reply << llendl; + LL_INFOS() << "Received: " << reply << LL_ENDL; - bool success = true; XML_Parser parser = XML_ParserCreate(0); XML_SetUserData(parser, this); XML_SetElementHandler(parser, onXmlElementStart, onXmlElementEnd); @@ -462,46 +407,27 @@ bool HippoGridInfo::retrieveGridInfo() mXmlState = XML_VOID; if (!XML_Parse(parser, reply.data(), reply.size(), TRUE)) { - llwarns << "XML Parse Error: " << XML_ErrorString(XML_GetErrorCode(parser)) << llendl; - success = false; + THROW_ALERTC(HTTP_OK, "GridInfoParseError", AIArgs("[XML_ERROR]", XML_ErrorString(XML_GetErrorCode(parser)))); } XML_ParserFree(parser); - - return success; -} - - -std::string HippoGridInfo::getUploadFee() const -{ - std::string fee; - formatFee(fee, LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(), true); - return fee; -} - -std::string HippoGridInfo::getGroupCreationFee() const -{ - std::string fee; - formatFee(fee, LLGlobalEconomy::Singleton::getInstance()->getPriceGroupCreate(), false); - return fee; } std::string HippoGridInfo::getDirectoryFee() const { - std::string fee; - formatFee(fee, mDirectoryFee, true); + std::string fee = formatFee(mDirectoryFee, true); if (mDirectoryFee != 0) fee += "/" + LLTrans::getString("hippo_label_week"); return fee; } -void HippoGridInfo::formatFee(std::string &fee, int cost, bool showFree) const +std::string HippoGridInfo::formatFee(int cost, bool showFree) const { - if (showFree && (cost == 0)) + if (showFree && (cost < 0)) { - fee = LLTrans::getString("hippo_label_free"); + return LLTrans::getString("hippo_label_free"); } else { - fee = llformat("%s%d", getCurrencySymbol().c_str(), cost); + return llformat("%s%d", getCurrencySymbol().c_str(), cost); } } @@ -547,9 +473,9 @@ std::string HippoGridInfo::getGridNick() const // static const char* HippoGridInfo::getPlatformString(Platform platform) { - static const char* platformStrings[PLATFORM_LAST] = + constexpr const char* platformStrings[PLATFORM_LAST] = { - "Other", "Aurora", "OpenSim", "SecondLife" + "Other", "WhiteCore", "OpenSim", "SecondLife" }; if ((platform < PLATFORM_OTHER) || (platform >= PLATFORM_LAST)) @@ -558,22 +484,40 @@ const char* HippoGridInfo::getPlatformString(Platform platform) } // static -std::string HippoGridInfo::sanitizeUri(std::string &uri) +std::string HippoGridInfo::sanitizeUri(std::string const& uri_in) { - // if (uri.empty()) { - // return ""; - // } + std::string uri = uri_in; - // // If last character in uri is not "/" - // // NOTE: This wrongly assumes that all URIs should end with "/"! - // if (uri.compare(uri.length()-1, 1, "/") != 0) { - // return uri + '/'; - // } + // Strip any leading and trailing spaces. + LLStringUtil::trim(uri); + + // Only use https when it was entered. + bool use_https = uri.substr(0, 6) == "https:"; + + // Strip off attempts to use some prefix that is just wrong. + // We accept the following: + // "" (nothing) + // "http:" or "https:", optionally followed by one or more '/'. + std::string::size_type pos = uri.find_first_not_of("htps"); + if (pos != std::string::npos && pos < 6 && uri[pos] == ':') + { + do { ++pos; } while(uri[pos] == '/'); + uri = uri.substr(pos); + } + + // Add (back) the prefix. + if (use_https) + { + uri = "https://" + uri; + } + else + { + uri = "http://" + uri; + } return uri; } - void HippoGridInfo::initFallback() { FALLBACK_GRIDINFO.setPlatform(PLATFORM_OPENSIM); @@ -582,23 +526,6 @@ void HippoGridInfo::initFallback() FALLBACK_GRIDINFO.setHelperUri("http://127.0.0.1:9000/"); } -bool HippoGridInfo::supportsInvLinks() -{ - if(isSecondLife()) - return true; - else - return mInvLinks; -} - -void HippoGridInfo::setSupportsInvLinks(bool b) -{ - if (b == true && mInvLinks == false) - { - llinfos << "Inventory Link support detected" << llendl; - } - mInvLinks = b; -} - bool HippoGridInfo::getAutoUpdate() { if(isSecondLife()) @@ -607,11 +534,6 @@ bool HippoGridInfo::getAutoUpdate() return mAutoUpdate; } -void HippoGridInfo::setAutoUpdate(bool b) -{ - mAutoUpdate = b; -} - bool HippoGridInfo::getUPCSupported() { if(isSecondLife()) @@ -753,13 +675,13 @@ void HippoGridManager::addGrid(HippoGridInfo* grid) const std::string& nick = grid->getGridName(); if (nick == "") { - llwarns << "Ignoring to try adding grid with empty nick." << llendl; + LL_WARNS() << "Ignoring to try adding grid with empty nick." << LL_ENDL; delete grid; return; } if (mGridInfo.find(nick) != mGridInfo.end()) { - llwarns << "Ignoring to try adding existing grid " << nick << '.' << llendl; + LL_WARNS() << "Ignoring to try adding existing grid " << nick << '.' << LL_ENDL; delete grid; return; } @@ -771,12 +693,12 @@ void HippoGridManager::deleteGrid(const std::string& grid) { GridIterator it = mGridInfo.find(grid); if (it == mGridInfo.end()) { - llwarns << "Trying to delete non-existing grid " << grid << '.' << llendl; + LL_WARNS() << "Trying to delete non-existing grid " << grid << '.' << LL_ENDL; return; } mGridInfo.erase(it); - llinfos << "Number of grids now: " << mGridInfo.size() << llendl; - if (mGridInfo.empty()) llinfos << "Grid info map is empty." << llendl; + LL_INFOS() << "Number of grids now: " << mGridInfo.size() << LL_ENDL; + if (mGridInfo.empty()) LL_INFOS() << "Grid info map is empty." << LL_ENDL; if (grid == mDefaultGrid) setDefaultGrid(LLStringUtil::null); // sets first grid, if map not empty if (grid == mCurrentGrid) @@ -816,7 +738,7 @@ void HippoGridManager::setCurrentGrid(const std::string& grid) } else if (!mGridInfo.empty()) { - llwarns << "Unknown grid '" << grid << "'. Setting to default grid." << llendl; + LL_WARNS() << "Unknown grid '" << grid << "'. Setting to default grid." << LL_ENDL; mCurrentGrid = mDefaultGrid; } if(mCurrentGridChangeSignal) @@ -834,9 +756,6 @@ void HippoGridManager::loadFromFile() parseFile(gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "grids_sg1.xml"), false); // merge default grid info, if newer. Force load, if list of grids is empty. parseFile(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "default_grids.xml"), !mGridInfo.empty()); - // merge grid info from web site, if newer. Force load, if list of grids is empty. - if (gSavedSettings.getBOOL("CheckForGridUpdates")) - parseUrl(gSavedSettings.getString("GridUpdateList"), !mGridInfo.empty()); std::string last_grid = gSavedSettings.getString("LastSelectedGrid"); if (last_grid.empty()) last_grid = gSavedSettings.getString("DefaultGrid"); @@ -844,9 +763,12 @@ void HippoGridManager::loadFromFile() setCurrentGrid(last_grid); } -void HippoGridManager::parseUrl(const std::string url, bool mergeIfNewer) +void HippoGridManager::parseUrl() { - llinfos << "Loading grid info from '" << url << "'." << llendl; + const std::string& url(gSavedSettings.getString("GridUpdateList")); + if (url.empty()) return; + + LL_INFOS() << "Loading grid info from '" << url << "'." << LL_ENDL; // query update server std::string escaped_url = LLWeb::escapeURL(url); @@ -856,14 +778,14 @@ void HippoGridManager::parseUrl(const std::string url, bool mergeIfNewer) S32 status = response["status"].asInteger(); if ((status != 200) || !response["body"].isArray()) { - llinfos << "GridInfo Update failed (" << status << "): " + LL_INFOS() << "GridInfo Update failed (" << status << "): " << (response["body"].isString()? response["body"].asString(): "") - << llendl; + << LL_ENDL; return; } - LLSD gridInfo = response["body"]; - parseData(gridInfo, mergeIfNewer); + // Force load, if list of grids is empty. + parseData(response["body"], !mGridInfo.empty()); } void HippoGridManager::parseFile(const std::string& fileName, bool mergeIfNewer) @@ -872,18 +794,18 @@ void HippoGridManager::parseFile(const std::string& fileName, bool mergeIfNewer) infile.open(fileName.c_str()); if (!infile.is_open()) { - llwarns << "Cannot find grid info file " << fileName << " to load." << llendl; + LL_WARNS() << "Cannot find grid info file " << fileName << " to load." << LL_ENDL; return; } LLSD gridInfo; if (LLSDSerialize::fromXML(gridInfo, infile) <= 0) { - llwarns << "Unable to parse grid info file " << fileName << '.' << llendl; + LL_WARNS() << "Unable to parse grid info file " << fileName << '.' << LL_ENDL; return; } - llinfos << "Loading grid info file " << fileName << '.' << llendl; + LL_INFOS() << "Loading grid info file " << fileName << '.' << LL_ENDL; parseData(gridInfo, mergeIfNewer); } @@ -905,12 +827,12 @@ void HippoGridManager::parseData(LLSD &gridInfo, bool mergeIfNewer) } if (it == end) { - llwarns << "Grid data has no version number." << llendl; + LL_WARNS() << "Grid data has no version number." << LL_ENDL; return; } } - llinfos << "Loading grid data." << llendl; + LL_INFOS() << "Loading grid data." << LL_ENDL; LLSD::array_const_iterator it, end = gridInfo.endArray(); for (it = gridInfo.beginArray(); it != end; ++it) @@ -963,11 +885,12 @@ void HippoGridManager::parseData(LLSD &gridInfo, bool mergeIfNewer) if (gridMap.has("website")) grid->setWebSite(gridMap["website"]); if (gridMap.has("support")) grid->setSupportUrl(gridMap["support"]); if (gridMap.has("register")) grid->setRegisterUrl(gridMap["register"]); + if (gridMap.has("partner")) grid->setPartnerUrl(gridMap["partner"]); if (gridMap.has("password")) grid->setPasswordUrl(gridMap["password"]); if (gridMap.has("search")) grid->setSearchUrl(gridMap["search"]); if (gridMap.has("render_compat")) grid->setRenderCompat(gridMap["render_compat"]); - if (gridMap.has("inventory_links")) grid->setSupportsInvLinks(gridMap["inventory_links"]); - if (gridMap.has("auto_update")) grid->setAutoUpdate(gridMap["auto_update"]); + if (gridMap.has("auto_update")) grid->mAutoUpdate = gridMap["auto_update"]; + if (gridMap.has("locked")) grid->mLocked = gridMap["locked"]; if (newGrid) addGrid(grid); } } @@ -998,12 +921,13 @@ void HippoGridManager::saveFile() gridInfo[i]["website"] = grid->getWebSite(); gridInfo[i]["support"] = grid->getSupportUrl(); gridInfo[i]["register"] = grid->getRegisterUrl(); + gridInfo[i]["partner"] = grid->getPartnerUrl(); gridInfo[i]["password"] = grid->getPasswordUrl(); gridInfo[i]["search"] = grid->getSearchUrl(); gridInfo[i]["render_compat"] = grid->isRenderCompat(); - gridInfo[i]["inventory_links"] = grid->supportsInvLinks(); gridInfo[i]["auto_update"] = grid->getAutoUpdate(); + gridInfo[i]["locked"] = grid->getLocked(); } // write client grid info file @@ -1014,10 +938,10 @@ void HippoGridManager::saveFile() { LLSDSerialize::toPrettyXML(gridInfo, file); file.close(); - llinfos << "Saved grids to " << fileName << llendl; + LL_INFOS() << "Saved grids to " << fileName << LL_ENDL; } else { - llwarns << "Unable to open grid info file for save: " << fileName << llendl; + LL_WARNS() << "Unable to open grid info file for save: " << fileName << LL_ENDL; } } diff --git a/indra/newview/hippogridmanager.h b/indra/newview/hippogridmanager.h index 605a02e0d3..f7bbdfe870 100644 --- a/indra/newview/hippogridmanager.h +++ b/indra/newview/hippogridmanager.h @@ -22,25 +22,21 @@ class LLSD; class HippoGridInfo { + friend class HippoGridManager; public: enum Platform { PLATFORM_OTHER = 0, - PLATFORM_AURORA, + PLATFORM_WHITECORE, PLATFORM_OPENSIM, PLATFORM_SECONDLIFE, PLATFORM_LAST }; - enum SearchType { - SEARCH_ALL_EMPTY, - SEARCH_ALL_QUERY, - SEARCH_ALL_TEMPLATE - }; explicit HippoGridInfo(const std::string& gridName); Platform getPlatform() { return mPlatform; } - bool isOpenSimulator() const { return (mPlatform == PLATFORM_OPENSIM || mPlatform == PLATFORM_AURORA); } - bool isAurora() const { return (mPlatform == PLATFORM_AURORA); } + bool isOpenSimulator() const { return (mPlatform == PLATFORM_OPENSIM || mPlatform == PLATFORM_WHITECORE); } + bool isWhiteCore() const { return (mPlatform == PLATFORM_WHITECORE); } bool isSecondLife() const { return (mPlatform == PLATFORM_SECONDLIFE); } bool isAvination() const { return mIsInAvination; } bool isInProductionGrid() const { llassert(mPlatform == PLATFORM_SECONDLIFE); return mIsInProductionGrid; } // Should only be called if isSecondLife() returns true. @@ -52,22 +48,21 @@ class HippoGridInfo const std::string& getWebSite() const { return mWebSite; } const std::string& getSupportUrl() const { return mSupportUrl; } const std::string& getRegisterUrl() const { return mRegisterUrl; } + const std::string& getPartnerUrl() const { return mPartnerUrl; } const std::string& getPasswordUrl() const { return mPasswordUrl; } // Returns the url base used for the Web Search tab const std::string& getSearchUrl() const { return mSearchUrl; } const std::string& getGridMessage() const { return mGridMessage; } const std::string& getVoiceConnector() const { return mVoiceConnector; } - std::string getSearchUrl(SearchType ty, bool is_web) const; bool isRenderCompat() const { return mRenderCompat; } std::string getGridNick() const; - int getMaxAgentGroups() const { return mMaxAgentGroups; } const std::string& getCurrencySymbol() const { return mCurrencySymbol; } const std::string& getCurrencyText() const { return mCurrencyText; } const std::string& getRealCurrencySymbol() const { return mRealCurrencySymbol; } - std::string getUploadFee() const; - std::string getGroupCreationFee() const; + const int& getClassifiedFee() const { return mClassifiedFee; } std::string getDirectoryFee() const; + std::string formatFee(S32 cost, bool showFree = true) const; void setPlatform (const std::string& platform); void setPlatform (Platform platform); @@ -79,12 +74,12 @@ class HippoGridInfo void setWebSite (const std::string& website); void setSupportUrl(const std::string& url); void setRegisterUrl(const std::string& url); + void setPartnerUrl(const std::string& url); void setPasswordUrl(const std::string& url); // sets the url base used for the Web Search tab void setSearchUrl(const std::string& url); void setGridMessage(const std::string& message); void setRenderCompat(bool compat); - void setMaxAgentGroups(int max) { mMaxAgentGroups = max; } void setVoiceConnector(const std::string& vc) { mVoiceConnector = vc; } void setUPCSupported(bool on); bool getUPCSupported(); @@ -92,13 +87,12 @@ class HippoGridInfo void setCurrencySymbol(const std::string& sym); void setCurrencyText(const std::string& text); void setRealCurrencySymbol(const std::string& sym); - void setDirectoryFee(int fee); - bool supportsInvLinks(); - void setSupportsInvLinks(bool b); + void setClassifiedFee(int fee) { mClassifiedFee = fee; } + void setDirectoryFee(int fee) { mDirectoryFee = fee; } bool getAutoUpdate(); - void setAutoUpdate(bool b); + bool getLocked() { return mLocked; } - bool retrieveGridInfo(); + void getGridInfo(); static const char* getPlatformString(Platform platform); static std::string sanitizeGridNick(const std::string &gridnick); @@ -116,20 +110,21 @@ class HippoGridInfo std::string mWebSite; std::string mSupportUrl; std::string mRegisterUrl; + std::string mPartnerUrl; std::string mPasswordUrl; std::string mSearchUrl; std::string mVoiceConnector; bool mIsInProductionGrid; bool mIsInAvination; bool mRenderCompat; - bool mInvLinks; bool mAutoUpdate; + bool mLocked; bool mUPCSupported; - int mMaxAgentGroups; std::string mCurrencySymbol; std::string mCurrencyText; std::string mRealCurrencySymbol; + int mClassifiedFee; int mDirectoryFee; std::string mGridMessage; @@ -138,12 +133,12 @@ class HippoGridInfo { XML_VOID, XML_PLATFORM, XML_GRIDNAME, XML_GRIDNICK, XML_LOGINURI, XML_LOGINPAGE, XML_HELPERURI, - XML_WEBSITE, XML_SUPPORT, XML_REGISTER, XML_PASSWORD, XML_SEARCH, XML_MESSAGE + XML_WEBSITE, XML_SUPPORT, XML_REGISTER, XML_PARTNER, XML_PASSWORD, XML_SEARCH, XML_MESSAGE }; XmlState mXmlState; - static std::string sanitizeUri(std::string &uri); - void formatFee(std::string &fee, int cost, bool showFree) const; + static std::string sanitizeUri(std::string const& uri_in); + void useHttps(void); static void onXmlElementStart(void* userData, const XML_Char* name, const XML_Char** atts); static void onXmlElementEnd(void* userData, const XML_Char* name); @@ -190,6 +185,8 @@ class HippoGridManager return mCurrentGridChangeSignal->connect(cb); } + void parseUrl(); + private: friend class HippoGridInfo; std::map mGridInfo; @@ -203,7 +200,6 @@ class HippoGridManager void cleanup(); void loadFromFile(); void parseFile(const std::string& fileName, bool mergeIfNewer); - void parseUrl(const std::string url, bool mergeIfNewer); void parseData(LLSD &gridInfo, bool mergeIfNewer); }; diff --git a/indra/newview/hippolimits.cpp b/indra/newview/hippolimits.cpp index 2ee9a7344e..346e72267f 100644 --- a/indra/newview/hippolimits.cpp +++ b/indra/newview/hippolimits.cpp @@ -21,37 +21,31 @@ void HippoLimits::setLimits() { if (gHippoGridManager->getConnectedGrid()->getPlatform() == HippoGridInfo::PLATFORM_SECONDLIFE) { setSecondLifeLimits(); - } else if (gHippoGridManager->getConnectedGrid()->getPlatform() == HippoGridInfo::PLATFORM_AURORA) { - setAuroraLimits(); + } else if (gHippoGridManager->getConnectedGrid()->getPlatform() == HippoGridInfo::PLATFORM_WHITECORE) { + setWhiteCoreLimits(); } else { setOpenSimLimits(); } } - void HippoLimits::setOpenSimLimits() { - mMaxAgentGroups = gHippoGridManager->getConnectedGrid()->getMaxAgentGroups(); - if (mMaxAgentGroups < 0) mMaxAgentGroups = 50; - mMaxPrimScale = 256.0f; + mMaxPrimScale = 8192.0f; mMaxHeight = 10000.0f; + mMinPrimScale = 0.001f; if (gHippoGridManager->getConnectedGrid()->isRenderCompat()) { - llinfos << "Using rendering compatible OpenSim limits." << llendl; - mMinPrimScale = 0.01f; + LL_INFOS() << "Using rendering compatible OpenSim limits." << LL_ENDL; mMinHoleSize = 0.05f; mMaxHollow = 0.95f; } else { - llinfos << "Using Hippo OpenSim limits." << llendl; - mMinPrimScale = 0.001f; + LL_INFOS() << "Using Hippo OpenSim limits." << LL_ENDL; mMinHoleSize = 0.01f; mMaxHollow = 0.99f; } } -void HippoLimits::setAuroraLimits() +void HippoLimits::setWhiteCoreLimits() { - mMaxAgentGroups = gHippoGridManager->getConnectedGrid()->getMaxAgentGroups(); - if (mMaxAgentGroups < 0) mMaxAgentGroups = 50; mMaxPrimScale = 8192.0f; mMinPrimScale = 0.001f; mMaxHeight = 10000.0f; @@ -61,17 +55,8 @@ void HippoLimits::setAuroraLimits() void HippoLimits::setSecondLifeLimits() { - llinfos << "Using Second Life limits." << llendl; - - if (gHippoGridManager->getConnectedGrid()) - - //KC: new server defined max groups - mMaxAgentGroups = gHippoGridManager->getConnectedGrid()->getMaxAgentGroups(); - if (mMaxAgentGroups <= 0) - { - mMaxAgentGroups = DEFAULT_MAX_AGENT_GROUPS; - } - + LL_INFOS() << "Using Second Life limits." << LL_ENDL; + mMinPrimScale = 0.01f; mMaxHeight = 4096.0f; mMinHoleSize = 0.05f; diff --git a/indra/newview/hippolimits.h b/indra/newview/hippolimits.h index 91625276b0..3ddfec165f 100644 --- a/indra/newview/hippolimits.h +++ b/indra/newview/hippolimits.h @@ -8,7 +8,6 @@ class HippoLimits public: HippoLimits(); - int getMaxAgentGroups() const { return mMaxAgentGroups; } float getMaxHeight() const { return mMaxHeight; } float getMinHoleSize() const { return mMinHoleSize; } float getMaxHollow() const { return mMaxHollow; } @@ -18,7 +17,6 @@ class HippoLimits void setLimits(); private: - int mMaxAgentGroups; float mMaxHeight; float mMinHoleSize; float mMaxHollow; @@ -26,7 +24,7 @@ class HippoLimits float mMinPrimScale; void setOpenSimLimits(); - void setAuroraLimits(); + void setWhiteCoreLimits(); void setSecondLifeLimits(); }; diff --git a/indra/newview/hippopanelgrids.cpp b/indra/newview/hippopanelgrids.cpp index b0239feadd..53446f17c6 100644 --- a/indra/newview/hippopanelgrids.cpp +++ b/indra/newview/hippopanelgrids.cpp @@ -42,7 +42,7 @@ #include "lluictrlfactory.h" #include "llviewerwindow.h" #include "llnotificationsutil.h" - +#include "llhttpstatuscodes.h" // ******************************************************************** @@ -61,6 +61,7 @@ class HippoPanelGridsImpl : public HippoPanelGrids enum State { NORMAL, ADD_NEW, ADD_COPY }; State mState; std::string mCurGrid; + bool mIsEditable; void loadCurGrid(); bool saveCurGrid(); @@ -78,6 +79,8 @@ class HippoPanelGridsImpl : public HippoPanelGrids static void onClickGridInfo(void *data); static void onClickHelpRenderCompat(void *data); static void onClickAdvanced(void *data); + + void enableEditing(bool); }; @@ -103,7 +106,7 @@ HippoPanelGrids *HippoPanelGrids::create() HippoPanelGridsImpl::HippoPanelGridsImpl() : - mState(NORMAL) + mState(NORMAL), mIsEditable(true) { LLUICtrlFactory::getInstance()->buildPanel(this, "panel_preferences_grids.xml"); } @@ -127,6 +130,7 @@ BOOL HippoPanelGridsImpl::postBuild() requires("website"); requires("support"); requires("register"); + requires("partner"); requires("password"); requires("search"); requires("btn_delete"); @@ -152,7 +156,7 @@ BOOL HippoPanelGridsImpl::postBuild() childSetCommitCallback("grid_selector", onSelectGrid, this); childSetCommitCallback("platform", onSelectPlatform, this); - + // !!!### server_choice_combo->setFocusLostCallback(onServerComboLostFocus); reset(); @@ -169,7 +173,7 @@ void HippoPanelGridsImpl::refresh() LLComboBox *grids = getChild("grid_selector"); S32 selectIndex = -1, i = 0; grids->removeall(); - if (defaultGrid != "") { + if (!defaultGrid.empty()) { grids->add(defaultGrid); selectIndex = i++; } @@ -189,32 +193,15 @@ void HippoPanelGridsImpl::refresh() if (selectIndex >= 0) { grids->setCurrentByIndex(selectIndex); } else { - grids->setLabel(LLStringExplicit("")); // LLComboBox::removeall() does not clear the label + grids->setLabel(LLStringUtil::null); // LLComboBox::removeall() does not clear the label } - childSetTextArg("default_grid", "[DEFAULT]", (defaultGrid != "")? defaultGrid: " "); + childSetTextArg("default_grid", "[DEFAULT]", !defaultGrid.empty() ? defaultGrid : " "); - childSetEnabled("btn_delete", (selectIndex >= 0)); + childSetEnabled("btn_delete", (selectIndex >= 0) && mIsEditable ); childSetEnabled("btn_copy", (mState == NORMAL) && (selectIndex >= 0)); childSetEnabled("btn_default", (mState == NORMAL) && (selectIndex > 0)); - childSetEnabled("gridname", (mState == ADD_NEW) || (mState == ADD_COPY)); - - if (childGetValue("platform").asString() == "SecondLife") { - // disable platform selector, if logged into the grid edited and it is SL - // so object export restrictions cannot be circumvented by changing the platform - bool enablePlatform = (LLStartUp::getStartupState() < STATE_LOGIN_CLEANUP) || - (mCurGrid != gHippoGridManager->getConnectedGrid()->getGridName()); - childSetEnabled("platform", enablePlatform); - childSetEnabled("search", false); - childSetText("search", LLStringExplicit("")); - childSetEnabled("render_compat", false); - childSetValue("render_compat", false); - } else { - childSetEnabled("platform", true); - childSetEnabled("search", true); - childSetText("search", gHippoGridManager->getConnectedGrid()->getSearchUrl()); - childSetEnabled("render_compat", true); - } + childSetEnabled("gridname", (mState == ADD_NEW) || (mState == ADD_COPY)); } @@ -256,11 +243,14 @@ void HippoPanelGridsImpl::loadCurGrid() childSetText("helperuri", gridInfo->getHelperUri()); childSetText("website", gridInfo->getWebSite()); childSetText("support", gridInfo->getSupportUrl()); + childSetText("search", gridInfo->getSearchUrl()); childSetText("register", gridInfo->getRegisterUrl()); + childSetText("partner", gridInfo->getPartnerUrl()); childSetText("password", gridInfo->getPasswordUrl()); childSetValue("render_compat", gridInfo->isRenderCompat()); + enableEditing(!gridInfo->getLocked()); } else { - std::string empty = ""; + const std::string& empty = LLStringUtil::null; LLComboBox *platform = getChild("platform"); if (platform) platform->setCurrentByIndex(HippoGridInfo::PLATFORM_OTHER); childSetText("gridname", empty); @@ -269,10 +259,12 @@ void HippoPanelGridsImpl::loadCurGrid() childSetText("helperuri", empty); childSetText("website", empty); childSetText("support", empty); + childSetText("search", empty); childSetText("register", empty); + childSetText("partner", empty); childSetText("password", empty); - childSetEnabled("render_compat", true); childSetValue("render_compat", true); + enableEditing(true); } if (mState == ADD_NEW) { @@ -281,8 +273,9 @@ void HippoPanelGridsImpl::loadCurGrid() childSetText("loginuri", required); } else if (mState == ADD_COPY) { childSetText("gridname", std::string("")); + enableEditing(true); } else if (mState != NORMAL) { - llwarns << "Illegal state " << mState << '.' << llendl; + LL_WARNS() << "Illegal state " << mState << '.' << LL_ENDL; } refresh(); @@ -294,13 +287,13 @@ bool HippoPanelGridsImpl::saveCurGrid() HippoGridInfo *gridInfo = 0; gridInfo = gHippoGridManager->getGrid(mCurGrid); - //gridInfo->retrieveGridInfo(); + //gridInfo->getGridInfo(); refresh(); std::string gridname = childGetValue("gridname"); - if (gridname == "") gridname = ""; + if (gridname == "") gridname.clear(); std::string loginuri = childGetValue("loginuri"); - if (loginuri == "") loginuri = ""; + if (loginuri == "") loginuri.clear(); if (gridname.empty() && !loginuri.empty()) this->retrieveGridInfo(); @@ -309,8 +302,8 @@ bool HippoPanelGridsImpl::saveCurGrid() // check nickname std::string gridname = childGetValue("gridname"); - childSetValue("gridname", (gridname != "")? gridname: ""); - if (gridname == "") { + childSetValue("gridname", !gridname.empty() ? gridname : ""); + if (gridname.empty()) { LLNotificationsUtil::add("GridsNoNick"); return false; } @@ -322,7 +315,7 @@ bool HippoPanelGridsImpl::saveCurGrid() } // check login URI - if (loginuri == "") { + if (loginuri.empty()) { LLSD args; args["NAME"] = gridname; LLNotificationsUtil::add("GridsNoLoginUri", args); @@ -332,12 +325,34 @@ bool HippoPanelGridsImpl::saveCurGrid() mState = NORMAL; mCurGrid = gridname; gridInfo = new HippoGridInfo(gridname); + gridInfo->setLoginUri(loginuri); gHippoGridManager->addGrid(gridInfo); - gridInfo->retrieveGridInfo(); + try + { + gridInfo->getGridInfo(); + } + catch (AIAlert::ErrorCode const& error) + { + if (error.getCode() == HTTP_NOT_FOUND || error.getCode() == HTTP_METHOD_NOT_ALLOWED) + { + // Ignore this error; it might be a user entered entry for a grid that has no get_grid_info support. + LL_WARNS() << AIAlert::text(error) << LL_ENDL; + } + else if (error.getCode() == HTTP_OK) + { + // XML parse error. + AIAlert::add("GridInfoError", error); + } + else + { + // Append GridInfoErrorInstruction to error message. + AIAlert::add("GridInfoError", AIAlert::Error(AIAlert::Prefix(), AIAlert::not_modal, error, "GridInfoErrorInstruction")); + } + } } - + if (!gridInfo) { - llwarns << "Grid not found, ignoring changes." << llendl; + LL_WARNS() << "Grid not found, ignoring changes." << LL_ENDL; return true; } @@ -349,6 +364,7 @@ bool HippoPanelGridsImpl::saveCurGrid() gridInfo->setWebSite(childGetValue("website")); gridInfo->setSupportUrl(childGetValue("support")); gridInfo->setRegisterUrl(childGetValue("register")); + gridInfo->setPartnerUrl(childGetValue("partner")); gridInfo->setPasswordUrl(childGetValue("password")); gridInfo->setSearchUrl(childGetValue("search")); gridInfo->setRenderCompat(childGetValue("render_compat")); @@ -372,7 +388,7 @@ void HippoPanelGridsImpl::reset() void HippoPanelGridsImpl::retrieveGridInfo() { std::string loginuri = childGetValue("loginuri"); - if ((loginuri == "") || (loginuri == "")) { + if ((loginuri.empty()) || (loginuri == "")) { LLNotificationsUtil::add("GridInfoNoLoginUri"); return; } @@ -382,35 +398,49 @@ void HippoPanelGridsImpl::retrieveGridInfo() if (mState == NORMAL) { grid = gHippoGridManager->getGrid(mCurGrid); } else if ((mState == ADD_NEW) || (mState == ADD_COPY)) { - grid = new HippoGridInfo(""); + grid = new HippoGridInfo(LLStringUtil::null); cleanupGrid = true; } else { - llerrs << "Illegal state " << mState << '.' << llendl; + LL_ERRS() << "Illegal state " << mState << '.' << LL_ENDL; return; } if (!grid) { - llerrs << "Internal error retrieving grid info." << llendl; + LL_ERRS() << "Internal error retrieving grid info." << LL_ENDL; return; } grid->setLoginUri(loginuri); - if (grid->retrieveGridInfo()) { + try + { + grid->getGridInfo(); + if (grid->getPlatform() != HippoGridInfo::PLATFORM_OTHER) getChild("platform")->setCurrentByIndex(grid->getPlatform()); - if (grid->getGridName() != "") childSetText("gridname", grid->getGridName()); - if (grid->getLoginUri() != "") childSetText("loginuri", grid->getLoginUri()); - if (grid->getLoginPage() != "") childSetText("loginpage", grid->getLoginPage()); - if (grid->getHelperUri() != "") childSetText("helperuri", grid->getHelperUri()); - if (grid->getWebSite() != "") childSetText("website", grid->getWebSite()); - if (grid->getSupportUrl() != "") childSetText("support", grid->getSupportUrl()); - if (grid->getRegisterUrl() != "") childSetText("register", grid->getRegisterUrl()); - if (grid->getPasswordUrl() != "") childSetText("password", grid->getPasswordUrl()); - if (grid->getSearchUrl() != "") childSetText("search", grid->getSearchUrl()); - if (grid->getGridMessage() != "") childSetText("gridmessage", grid->getGridMessage()); - } else { - LLNotificationsUtil::add("GridInfoError"); + if (!grid->getGridName().empty()) childSetText("gridname", grid->getGridName()); + if (!grid->getLoginUri().empty()) childSetText("loginuri", grid->getLoginUri()); + if (!grid->getLoginPage().empty()) childSetText("loginpage", grid->getLoginPage()); + if (!grid->getHelperUri().empty()) childSetText("helperuri", grid->getHelperUri()); + if (!grid->getWebSite().empty()) childSetText("website", grid->getWebSite()); + if (!grid->getSupportUrl().empty()) childSetText("support", grid->getSupportUrl()); + if (!grid->getRegisterUrl().empty()) childSetText("register", grid->getRegisterUrl()); + if (!grid->getPartnerUrl().empty()) childSetText("partner", grid->getPartnerUrl()); + if (!grid->getPasswordUrl().empty()) childSetText("password", grid->getPasswordUrl()); + if (!grid->getSearchUrl().empty()) childSetText("search", grid->getSearchUrl()); + if (!grid->getGridMessage().empty()) childSetText("gridmessage", grid->getGridMessage()); } - + catch(AIAlert::ErrorCode const& error) + { + if (error.getCode() == HTTP_METHOD_NOT_ALLOWED || error.getCode() == HTTP_OK) + { + AIAlert::add("GridInfoError", error); + } + else + { + // Append GridInfoErrorInstruction to error message. + AIAlert::add("GridInfoError", AIAlert::Error(AIAlert::Prefix(), AIAlert::not_modal, error, "GridInfoErrorInstruction")); + } + } + if (cleanupGrid) delete grid; } @@ -472,8 +502,10 @@ void HippoPanelGridsImpl::onClickDefault(void *data) { HippoPanelGridsImpl *self = (HippoPanelGridsImpl*)data; if (self->mState == NORMAL) { - self->saveCurGrid(); - gHippoGridManager->setDefaultGrid(self->mCurGrid); + if (self->saveCurGrid()) + { + gHippoGridManager->setDefaultGrid(self->mCurGrid); + } self->refresh(); } } @@ -505,6 +537,8 @@ void HippoPanelGridsImpl::onClickAdvanced(void *data) self->childSetVisible("support", false); self->childSetVisible("register_label", false); self->childSetVisible("register", false); + self->childSetVisible("partner_label", false); + self->childSetVisible("partner", false); self->childSetVisible("password_label", false); self->childSetVisible("password", false); self->childSetVisible("search_label", false); @@ -524,6 +558,8 @@ void HippoPanelGridsImpl::onClickAdvanced(void *data) self->childSetVisible("support", true); self->childSetVisible("register_label", true); self->childSetVisible("register", true); + self->childSetVisible("partner_label", true); + self->childSetVisible("partner", true); self->childSetVisible("password_label", true); self->childSetVisible("password", true); self->childSetVisible("search_label", true); @@ -538,3 +574,32 @@ void HippoPanelGridsImpl::onClickHelpRenderCompat(void *data) { LLNotificationsUtil::add("HelpRenderCompat"); } + + +void HippoPanelGridsImpl::enableEditing(bool b) +{ + static const char * elements [] = { + "platform", + "gridname", + "loginuri", + "loginpage", + "helperuri", + "website", + "support", + "register", + "partner", + "password", + "search", + "btn_delete", + "btn_gridinfo", + "render_compat", + "gridmessage", + 0 + }; + + for(int i = 0; elements[i]; ++i ) { + this->childSetEnabled(elements[i], b); + } + + mIsEditable = b; +} diff --git a/indra/newview/icons/alpha/viewer.icns b/indra/newview/icons/alpha/viewer.icns new file mode 100644 index 0000000000..0b5d5c626a Binary files /dev/null and b/indra/newview/icons/alpha/viewer.icns differ diff --git a/indra/newview/icons/alpha/viewer.ico b/indra/newview/icons/alpha/viewer.ico new file mode 100644 index 0000000000..e15813d24c Binary files /dev/null and b/indra/newview/icons/alpha/viewer.ico differ diff --git a/indra/newview/icons/alpha/viewer.png b/indra/newview/icons/alpha/viewer.png new file mode 100644 index 0000000000..8d7619f958 Binary files /dev/null and b/indra/newview/icons/alpha/viewer.png differ diff --git a/indra/newview/icons/alpha/viewer_256.BMP b/indra/newview/icons/alpha/viewer_256.BMP new file mode 100644 index 0000000000..b42ed064fd Binary files /dev/null and b/indra/newview/icons/alpha/viewer_256.BMP differ diff --git a/indra/newview/res/singularity.icns b/indra/newview/icons/default/viewer.icns similarity index 100% rename from indra/newview/res/singularity.icns rename to indra/newview/icons/default/viewer.icns diff --git a/indra/newview/installers/windows/install_icon_singularity.ico b/indra/newview/icons/default/viewer.ico similarity index 100% rename from indra/newview/installers/windows/install_icon_singularity.ico rename to indra/newview/icons/default/viewer.ico diff --git a/indra/newview/icons/default/viewer.png b/indra/newview/icons/default/viewer.png new file mode 100644 index 0000000000..ae3d64aa33 Binary files /dev/null and b/indra/newview/icons/default/viewer.png differ diff --git a/indra/newview/icons/default/viewer_256.BMP b/indra/newview/icons/default/viewer_256.BMP new file mode 100644 index 0000000000..32bf37e5cb Binary files /dev/null and b/indra/newview/icons/default/viewer_256.BMP differ diff --git a/indra/newview/importtracker.cpp b/indra/newview/importtracker.cpp index e880819694..284327d170 100644 --- a/indra/newview/importtracker.cpp +++ b/indra/newview/importtracker.cpp @@ -17,7 +17,7 @@ //#include "llsdserialize.h" #include "lltooldraganddrop.h" //#include "llassetuploadresponders.h" -//#include "lleconomy.h" +//#include "llagentbenefits.h" //#include "llfloaterperms.h" @@ -46,7 +46,7 @@ extern LLAgent gAgent; asset_dir = filepath.substr(0,filepath.find_last_of(".")) + "_assets"; linksetgroups=file_data; - //llinfos << "LOADED LINKSETS, PREPARING.." << llendl; + //LL_INFOS() << "LOADED LINKSETS, PREPARING.." << LL_ENDL; groupcounter=0; LLSD ls_llsd; ls_llsd=linksetgroups[groupcounter]["Object"]; @@ -68,7 +68,7 @@ void ImportTracker::import(LLSD& ls_data) rootrot.mQ[VZ] = (F32)(rot[2].asReal()); rootrot.mQ[VW] = (F32)(rot[3].asReal()); state = BUILDING; - //llinfos << "IMPORTED, BUILDING.." << llendl; + //LL_INFOS() << "IMPORTED, BUILDING.." << LL_ENDL; plywood_above_head(); }*/ @@ -76,7 +76,7 @@ void ImportTracker::expectRez() { numberExpected++; state = WAND; - //llinfos << "EXPECTING CUBE..." << llendl; + //LL_INFOS() << "EXPECTING CUBE..." << LL_ENDL; } /*void ImportTracker::clear() @@ -87,7 +87,7 @@ void ImportTracker::expectRez() state = IDLE; finish(); } -void cmdline_printchat(std::string message);*/ +void cmdline_printchat(const std::string& message);*/ LLViewerObject* find(U32 local) { S32 i; @@ -226,7 +226,9 @@ void ImportTracker::get_update(S32 newid, BOOL justCreated, BOOL createSelected) } } } - + + // Anything below here must be permissions!!! + if (gAgent.getRegion()->getCapability("AgentPreferences").empty()) break; // This cap automates perm setting on the server msg->newMessageFast(_PREHASH_ObjectPermissions); msg->nextBlockFast(_PREHASH_AgentData); msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); @@ -238,21 +240,37 @@ void ImportTracker::get_update(S32 newid, BOOL justCreated, BOOL createSelected) msg->addU8Fast(_PREHASH_Field, PERM_NEXT_OWNER); msg->addU8Fast(_PREHASH_Set, PERM_SET_TRUE); U32 flags = 0; - if ( gSavedSettings.getBOOL("NextOwnerCopy") ) + if ( gSavedSettings.getBOOL("ObjectsNextOwnerCopy") ) { flags |= PERM_COPY; } - if ( gSavedSettings.getBOOL("NextOwnerModify") ) + if ( gSavedSettings.getBOOL("ObjectsNextOwnerModify") ) { flags |= PERM_MODIFY; } - if ( gSavedSettings.getBOOL("NextOwnerTransfer") ) + bool next_owner_trans; + if ( next_owner_trans = gSavedSettings.getBOOL("ObjectsNextOwnerTransfer") ) { flags |= PERM_TRANSFER; } msg->addU32Fast(_PREHASH_Mask, flags); msg->sendReliable(gAgent.getRegion()->getHost()); - //llinfos << "LGG SENDING CUBE TEXTURE.." << llendl; + if (!next_owner_trans) // Workaround transfer being true by default. + { + msg->newMessageFast(_PREHASH_ObjectPermissions); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgentID); + msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID); + msg->nextBlockFast(_PREHASH_HeaderData); + msg->addBOOLFast(_PREHASH_Override, false); + msg->nextBlockFast(_PREHASH_ObjectData); + msg->addU32Fast(_PREHASH_ObjectLocalID, (U32)newid); + msg->addU8Fast(_PREHASH_Field, PERM_NEXT_OWNER); + msg->addU8Fast(_PREHASH_Set, PERM_SET_FALSE); + msg->addU32Fast(_PREHASH_Mask, PERM_TRANSFER); + msg->sendReliable(gAgent.getRegion()->getHost()); + } + //LL_INFOS() << "LGG SENDING CUBE TEXTURE.." << LL_ENDL; } break; /* case BUILDING: @@ -289,7 +307,7 @@ void ImportTracker::get_update(S32 newid, BOOL justCreated, BOOL createSelected) if (updated >= linkset.size()) { updated=0; - llinfos << "FINISHED BUILDING, LINKING.." << llendl; + LL_INFOS() << "FINISHED BUILDING, LINKING.." << LL_ENDL; state = LINKING; link(); } @@ -383,7 +401,7 @@ class JCImportInventoryResponder : public LLAssetUploadResponder create_inventory_item(gAgent.getID(), gAgent.getSessionID(), gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH), data->tid, data->name, data->description, data->type, LLInventoryType::defaultForAssetType(data->type), data->wear_type, - LLFloaterPerms::getNextOwnerPerms(), + LLFloaterPerms::getNextOwnerPerms("Uploads"), cb); } @@ -489,10 +507,10 @@ class JCPostInvCallback : public LLInventoryCallback gVFS->getData(data->assetid, data->type, buffer, 0, size); std::string script((char*)buffer); BOOL domono = FALSE;//Phox- this needs to be fixed when the preproc is added = JCLSLPreprocessor::mono_directive(script); - *//*if(script.find("//mono\n") != -1) + *//*if(script.find("//mono\n") != std::string::npos) { domono = TRUE; - }else if(script.find("//lsl2\n") != -1) + }else if(script.find("//lsl2\n") != std::string::npos) { domono = FALSE; }*//* @@ -526,7 +544,7 @@ void JCImportInventorycallback(const LLUUID& uuid, void* user_data, S32 result, create_inventory_item(gAgent.getID(), gAgent.getSessionID(), gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH), data->tid, data->name, data->description, data->type, LLInventoryType::defaultForAssetType(data->type), data->wear_type, - LLFloaterPerms::getNextOwnerPerms(), + LLFloaterPerms::getNextOwnerPerms("Uploads"), cb); }else cmdline_printchat("err: "+std::string(LLAssetStorage::getErrorString(result))); } @@ -617,7 +635,7 @@ void ImportTracker::send_inventory(LLSD& prim) body["next_owner_mask"] = LLSD::Integer(U32_MAX); body["group_mask"] = LLSD::Integer(U32_MAX); body["everyone_mask"] = LLSD::Integer(U32_MAX); - body["expected_upload_cost"] = LLSD::Integer(LLGlobalEconomy::Singleton::getInstance()->getPriceUpload()); + body["expected_upload_cost"] = LLAgentBenefits::current().getTextureUploadCost(); //cmdline_printchat("posting "+ data->assetid.asString()); LLHTTPClient::post(url, body, new JCImportInventoryResponder(body, data->assetid, data->type,data)); //error = TRUE; @@ -674,7 +692,7 @@ void ImportTracker::send_inventory(LLSD& prim) create_inventory_item(gAgent.getID(), gAgent.getSessionID(), gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH), data->tid, data->name, data->description, data->type, LLInventoryType::defaultForAssetType(data->type), data->wear_type, - LLFloaterPerms::getNextOwnerPerms(), + LLFloaterPerms::getNextOwnerPerms("Notecards"), cb); } break; @@ -686,7 +704,7 @@ void ImportTracker::send_inventory(LLSD& prim) create_inventory_item(gAgent.getID(), gAgent.getSessionID(), gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH), data->tid, data->name, data->description, data->type, LLInventoryType::defaultForAssetType(data->type), data->wear_type, - LLFloaterPerms::getNextOwnerPerms(), + LLFloaterPerms::getNextOwnerPerms("Scripts"), cb); } break; @@ -1027,11 +1045,11 @@ void ImportTracker::link() msg->sendReliable(gAgent.getRegion()->getHost()); } - llinfos << "FINISHED IMPORT" << llendl; + LL_INFOS() << "FINISHED IMPORT" << LL_ENDL; if (linkset[0].has("Attachment")) { - llinfos << "OBJECT IS ATTACHMENT, WAITING FOR POSITION PACKETS.." << llendl; + LL_INFOS() << "OBJECT IS ATTACHMENT, WAITING FOR POSITION PACKETS.." << LL_ENDL; state = POSITIONING; wear(linkset[0]); } @@ -1084,7 +1102,7 @@ void ImportTracker::wear(LLSD &prim) msg2->addBinaryDataFast(_PREHASH_Data, data, 12); msg2->sendReliable(gAgent.getRegion()->getHost()); - llinfos << "POSITIONED, IMPORT COMPLETED" << llendl; + LL_INFOS() << "POSITIONED, IMPORT COMPLETED" << LL_ENDL; cleanUp(); } diff --git a/indra/newview/installers/darwin/firstlook-dmg/background.jpg b/indra/newview/installers/darwin/firstlook-dmg/background.jpg index 55294dcc9a..3962e2fb31 100644 Binary files a/indra/newview/installers/darwin/firstlook-dmg/background.jpg and b/indra/newview/installers/darwin/firstlook-dmg/background.jpg differ diff --git a/indra/newview/installers/darwin/publicnightly-dmg/background.jpg b/indra/newview/installers/darwin/publicnightly-dmg/background.jpg index 55294dcc9a..3962e2fb31 100644 Binary files a/indra/newview/installers/darwin/publicnightly-dmg/background.jpg and b/indra/newview/installers/darwin/publicnightly-dmg/background.jpg differ diff --git a/indra/newview/installers/darwin/release-dmg/background.jpg b/indra/newview/installers/darwin/release-dmg/background.jpg index 55294dcc9a..3962e2fb31 100644 Binary files a/indra/newview/installers/darwin/release-dmg/background.jpg and b/indra/newview/installers/darwin/release-dmg/background.jpg differ diff --git a/indra/newview/installers/darwin/releasecandidate-dmg/background.jpg b/indra/newview/installers/darwin/releasecandidate-dmg/background.jpg index 55294dcc9a..3962e2fb31 100644 Binary files a/indra/newview/installers/darwin/releasecandidate-dmg/background.jpg and b/indra/newview/installers/darwin/releasecandidate-dmg/background.jpg differ diff --git a/indra/newview/installers/windows/FILES_ARE_UNICODE_UTF-16LE.txt b/indra/newview/installers/windows/FILES_ARE_UNICODE_UTF-16LE.txt deleted file mode 100644 index 30f9349111..0000000000 --- a/indra/newview/installers/windows/FILES_ARE_UNICODE_UTF-16LE.txt +++ /dev/null @@ -1,6 +0,0 @@ -The language files in this directory are Unicode (Little-Endian) format, also known as UTF-16 LE. - -This is the format required for NSIS Unicode. See http://www.scratchpaper.com/ for details. - -James Cook -September 2008 diff --git a/indra/newview/installers/windows/install_icon.ico b/indra/newview/installers/windows/install_icon.ico index 1e00530c90..84a455a226 100644 Binary files a/indra/newview/installers/windows/install_icon.ico and b/indra/newview/installers/windows/install_icon.ico differ diff --git a/indra/newview/installers/windows/install_icon_singularity.BMP b/indra/newview/installers/windows/install_icon_singularity.BMP deleted file mode 100644 index 09df573870..0000000000 Binary files a/indra/newview/installers/windows/install_icon_singularity.BMP and /dev/null differ diff --git a/indra/newview/installers/windows/install_icon_snowglobe.BMP b/indra/newview/installers/windows/install_icon_snowglobe.BMP deleted file mode 100644 index 86817c5411..0000000000 Binary files a/indra/newview/installers/windows/install_icon_snowglobe.BMP and /dev/null differ diff --git a/indra/newview/installers/windows/install_icon_snowglobe.ico b/indra/newview/installers/windows/install_icon_snowglobe.ico deleted file mode 100644 index e866e91a29..0000000000 Binary files a/indra/newview/installers/windows/install_icon_snowglobe.ico and /dev/null differ diff --git a/indra/newview/installers/windows/install_welcome.bmp b/indra/newview/installers/windows/install_welcome.bmp new file mode 100644 index 0000000000..196a5b7a7e Binary files /dev/null and b/indra/newview/installers/windows/install_welcome.bmp differ diff --git a/indra/newview/installers/windows/installer_template.nsi b/indra/newview/installers/windows/installer_template.nsi index 8fa0a943c2..e44ff819b5 100644 --- a/indra/newview/installers/windows/installer_template.nsi +++ b/indra/newview/installers/windows/installer_template.nsi @@ -1,198 +1,335 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; secondlife setup.nsi -;; Copyright 2004-2008, Linden Research, Inc. +;; Copyright 2004-2011, Linden Research, Inc. +;; Copyright 2013-2015 Alchemy Viewer Project ;; -;; NSIS Unicode 2.38.1 or higher required -;; http://www.scratchpaper.com/ +;; 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. ;; -;; Author: James Cook, Don Kjer, Callum Prentice -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Compiler flags -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -SetOverwrite on ; overwrite files -SetCompress auto ; compress iff saves space -SetCompressor /solid /final lzma ; compress whole installer as one block -SetDatablockOptimize off ; only saves us 0.1%, not worth it -XPStyle on ; add an XP manifest to the installer -RequestExecutionLevel admin ; on Vista we must be admin because we write to Program Files +;; This library is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;; Lesser General Public License for more details. +;; +;; You should have received a copy of the GNU Lesser General Public +;; License along with this library; if not, write to the Free Software +;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +;; +;; Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +;; +;; NSIS 3 or higher required for Unicode support +;; +;; Author: James Cook, Don Kjer, Callum Prentice, Drake Arconis +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;-------------------------------- +;Unicode + Unicode true + +;-------------------------------- +;Include Modern UI + + !include "LogicLib.nsh" + !include "StdUtils.nsh" + !include "FileFunc.nsh" + !insertmacro GetParameters + !insertmacro GetOptions + !include "x64.nsh" + !include "WinVer.nsh" + !include "MUI2.nsh" + +;------------------------------- +;Global Variables + ; These will be replaced by manifest scripts + %%INST_VARS%% + %%WIN64_BIN_BUILD%% + + Var INSTEXE + Var INSTPROG + Var INSTSHORTCUT + Var AUTOSTART + Var COMMANDLINE ; command line passed to this installer, set in .onInit + Var SHORTCUT_LANG_PARAM ; "--set InstallLanguage de", passes language to viewer + Var SKIP_DIALOGS ; set from command line in .onInit. autoinstall + ; GUI and the defaults. + Var SKIP_AUTORUN ; skip automatic launch of viewer after install + Var STARTMENUFOLDER + +;-------------------------------- +;Registry Keys + !define ALCHEMY_KEY "SOFTWARE\${VENDORSTR}" + !define INSTNAME_KEY "${ALCHEMY_KEY}\${APPNAMEONEWORD}" + !define MSCURRVER_KEY "SOFTWARE\Microsoft\Windows\CurrentVersion" + !define MSNTCURRVER_KEY "SOFTWARE\Microsoft\Windows NT\CurrentVersion" + !define MSUNINSTALL_KEY "${MSCURRVER_KEY}\Uninstall\${APPNAMEONEWORD}" + +;-------------------------------- +;General + + ;Name and file + Name "${APPNAME}" + OutFile "${INSTOUTFILE}" + Caption "${CAPTIONSTR}" + BrandingText "${VENDORSTR}" + + ;Default installation folder +!ifdef WIN64_BIN_BUILD + InstallDir "$PROGRAMFILES64\${APPNAMEONEWORD}" +!else + InstallDir "$PROGRAMFILES\${APPNAMEONEWORD}" +!endif -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; Project flags -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + ;Get installation folder from registry if available and 32bit otherwise do it in init +!ifndef WIN64_BIN_BUILD + InstallDirRegKey HKLM "${INSTNAME_KEY}" "" +!endif -%%VERSION%% + ;Request application privileges for Windows UAC + RequestExecutionLevel admin + + ;Compression + SetCompress auto ; compress to saves space + SetCompressor /solid /final lzma ; compress whole installer as one block + + ;File Handling + SetOverwrite on + + ;Verify CRC + CRCCheck on + +;-------------------------------- +;Interface Settings + + ;Show Details + ShowInstDetails hide + ShowUninstDetails hide + + !define MUI_ICON "%%SOURCE%%\installers\windows\install_icon.ico" + !define MUI_UNICON "%%SOURCE%%\installers\windows\uninstall_icon.ico" + !define MUI_WELCOMEFINISHPAGE_BITMAP "%%SOURCE%%\installers\windows\install_welcome.bmp" + !define MUI_UNWELCOMEFINISHPAGE_BITMAP "%%SOURCE%%\installers\windows\uninstall_welcome.bmp" + !define MUI_ABORTWARNING + +;-------------------------------- +;Language Selection Dialog Settings + + ;Show all languages, despite user's codepage + !define MUI_LANGDLL_ALLLANGUAGES + + ;Remember the installer language + !define MUI_LANGDLL_REGISTRY_ROOT "HKLM" + !define MUI_LANGDLL_REGISTRY_KEY "${INSTNAME_KEY}" + !define MUI_LANGDLL_REGISTRY_VALUENAME "InstallerLanguage" + + ;Always show the dialog + !define MUI_LANGDLL_ALWAYSSHOW + +;-------------------------------- +;Install Pages + + !define MUI_PAGE_CUSTOMFUNCTION_PRE check_skip + !insertmacro MUI_PAGE_WELCOME + + ;License Page + !define MUI_PAGE_CUSTOMFUNCTION_PRE check_skip + !insertmacro MUI_PAGE_LICENSE "%%SOURCE%%\..\..\doc\GPL-license.txt" + + ;Directory Page + !define MUI_PAGE_CUSTOMFUNCTION_PRE check_skip + !insertmacro MUI_PAGE_DIRECTORY + + ;Start Menu Folder Page + !define MUI_STARTMENUPAGE_REGISTRY_ROOT "HKLM" + !define MUI_STARTMENUPAGE_REGISTRY_KEY "${INSTNAME_KEY}" + !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder" + !define MUI_PAGE_CUSTOMFUNCTION_PRE check_skip +!ifdef WIN64_BIN_BUILD + !define MUI_STARTMENUPAGE_DEFAULTFOLDER "${APPNAME} (64 bit) Viewer" +!else + !define MUI_STARTMENUPAGE_DEFAULTFOLDER "${APPNAME} Viewer" +!endif + !insertmacro MUI_PAGE_STARTMENU Application $STARTMENUFOLDER + + ;Install Progress Page + !define MUI_PAGE_CUSTOMFUNCTION_LEAVE CheckWindowsServPack + !insertmacro MUI_PAGE_INSTFILES + + ; Finish Page + !define MUI_PAGE_CUSTOMFUNCTION_PRE check_skip_finish + !define MUI_FINISHPAGE_RUN + !define MUI_FINISHPAGE_RUN_FUNCTION launch_viewer + !define MUI_FINISHPAGE_SHOWREADME + !define MUI_FINISHPAGE_SHOWREADME_TEXT "Create Desktop Shortcut" + !define MUI_FINISHPAGE_SHOWREADME_NOTCHECKED + !define MUI_FINISHPAGE_SHOWREADME_FUNCTION create_desktop_shortcut + !define MUI_FINISHPAGE_NOREBOOTSUPPORT + !insertmacro MUI_PAGE_FINISH + +;-------------------------------- +;Uninstall Pages + + !insertmacro MUI_UNPAGE_WELCOME + !insertmacro MUI_UNPAGE_CONFIRM + !insertmacro MUI_UNPAGE_INSTFILES + !insertmacro MUI_UNPAGE_FINISH + +;-------------------------------- +;Languages + + !include "%%SOURCE%%\installers\windows\lang_en-us.nsi" + !include "%%SOURCE%%\installers\windows\lang_de.nsi" + !include "%%SOURCE%%\installers\windows\lang_es.nsi" + !include "%%SOURCE%%\installers\windows\lang_fr.nsi" + !include "%%SOURCE%%\installers\windows\lang_ja.nsi" + !include "%%SOURCE%%\installers\windows\lang_pl.nsi" + !include "%%SOURCE%%\installers\windows\lang_it.nsi" + !include "%%SOURCE%%\installers\windows\lang_pt-br.nsi" + !include "%%SOURCE%%\installers\windows\lang_da.nsi" + !include "%%SOURCE%%\installers\windows\lang_ru.nsi" + !include "%%SOURCE%%\installers\windows\lang_tr.nsi" + !include "%%SOURCE%%\installers\windows\lang_zh.nsi" + +;-------------------------------- +;Version Information + + VIProductVersion "${VERSION_LONG}" + VIAddVersionKey /LANG=${LANG_ENGLISH} "ProductName" "Singularity Viewer Installer" + VIAddVersionKey /LANG=${LANG_ENGLISH} "Comments" "A viewer for the meta-verse!" + VIAddVersionKey /LANG=${LANG_ENGLISH} "CompanyName" "${VENDORSTR}" + VIAddVersionKey /LANG=${LANG_ENGLISH} "LegalCopyright" "Copyright © 2010-2020, ${VENDORSTR}" + VIAddVersionKey /LANG=${LANG_ENGLISH} "FileDescription" "${APPNAME} Installer" + VIAddVersionKey /LANG=${LANG_ENGLISH} "ProductVersion" "${VERSION_LONG}" + VIAddVersionKey /LANG=${LANG_ENGLISH} "FileVersion" "${VERSION_LONG}" + +;-------------------------------- +;Reserve Files + + ;If you are using solid compression, files that are required before + ;the actual installation should be stored first in the data block, + ;because this will make your installer start faster. + + !insertmacro MUI_RESERVEFILE_LANGDLL + ReserveFile "${NSISDIR}\Plugins\x86-unicode\INetC.dll" + ReserveFile "${NSISDIR}\Plugins\x86-unicode\nsDialogs.dll" + ReserveFile "${NSISDIR}\Plugins\x86-unicode\nsis7z.dll" + ReserveFile "${NSISDIR}\Plugins\x86-unicode\StartMenu.dll" + ReserveFile "${NSISDIR}\Plugins\x86-unicode\StdUtils.dll" + ReserveFile "${NSISDIR}\Plugins\x86-unicode\System.dll" + ReserveFile "${NSISDIR}\Plugins\x86-unicode\UserInfo.dll" + +;-------------------------------- +; Local Functions + +;Page pre-checks for skip conditions +Function check_skip + StrCmp $SKIP_DIALOGS "true" 0 +2 + Abort +FunctionEnd -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Tweak for different servers/builds (this placeholder is replaced by viewer_manifest.py) -;; For example: -;; !define INSTFLAGS "%(flags)s" -;; !define INSTNAME "SecondLife%(grid_caps)s" -;; !define SHORTCUT "Second Life (%(grid_caps)s)" -;; !define URLNAME "secondlife%(grid)s" -;; !define UNINSTALL_SETTINGS 1 +Function check_skip_finish + StrCmp $SKIP_DIALOGS "true" 0 +4 + StrCmp $AUTOSTART "true" 0 +3 + Call launch_viewer + Abort +FunctionEnd -%%GRID_VARS%% +Function launch_viewer + ${StdUtils.ExecShellAsUser} $0 "$INSTDIR\$INSTEXE" "open" "$SHORTCUT_LANG_PARAM" +FunctionEnd -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; - language files - one for each language (or flavor thereof) -;; (these files are in the same place as the nsi template but the python script generates a new nsi file in the -;; application directory so we have to add a path to these include files) -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -!include "%%SOURCE%%\installers\windows\lang_de.nsi" -!include "%%SOURCE%%\installers\windows\lang_en-us.nsi" -!include "%%SOURCE%%\installers\windows\lang_es.nsi" -!include "%%SOURCE%%\installers\windows\lang_fr.nsi" -!include "%%SOURCE%%\installers\windows\lang_ja.nsi" -!include "%%SOURCE%%\installers\windows\lang_it.nsi" -!include "%%SOURCE%%\installers\windows\lang_ko.nsi" -!include "%%SOURCE%%\installers\windows\lang_nl.nsi" -!include "%%SOURCE%%\installers\windows\lang_pt-br.nsi" -!include "%%SOURCE%%\installers\windows\lang_zh.nsi" - -# *TODO: Move these into the language files themselves -LangString LanguageCode ${LANG_GERMAN} "de" -LangString LanguageCode ${LANG_ENGLISH} "en" -LangString LanguageCode ${LANG_SPANISH} "es" -LangString LanguageCode ${LANG_FRENCH} "fr" -LangString LanguageCode ${LANG_JAPANESE} "ja" -LangString LanguageCode ${LANG_ITALIAN} "it" -LangString LanguageCode ${LANG_KOREAN} "ko" -LangString LanguageCode ${LANG_DUTCH} "nl" -LangString LanguageCode ${LANG_PORTUGUESEBR} "pt" -LangString LanguageCode ${LANG_SIMPCHINESE} "zh" - -Name ${VIEWERNAME} - -SubCaption 0 $(LicenseSubTitleSetup) ; override "license agreement" text - -BrandingText "Prepare to Implode!" ; bottom of window text -Icon %%SOURCE%%\installers\windows\install_icon_singularity.ico -UninstallIcon %%SOURCE%%\installers\windows\uninstall_icon_singularity.ico -WindowIcon off ; show our icon in left corner -BGGradient 9090b0 000000 notext -CRCCheck on ; make sure CRC is OK -#InstProgressFlags smooth colored ; new colored smooth look -InstProgressFlags -InstallColors /windows -ShowInstDetails show ; no details, no "show" button -SetOverwrite on ; stomp files by default -AutoCloseWindow true ; after all files install, close window - -InstallDir "$PROGRAMFILES\${INSTNAME}" -InstallDirRegKey HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\${INSTNAME}" "" -DirText $(DirectoryChooseTitle) $(DirectoryChooseSetup) +Function create_desktop_shortcut +!ifdef WIN64_BIN_BUILD + CreateShortCut "$DESKTOP\$INSTSHORTCUT x64.lnk" "$INSTDIR\$INSTEXE" "$SHORTCUT_LANG_PARAM" "$INSTDIR\$INSTEXE" +!else + CreateShortCut "$DESKTOP\$INSTSHORTCUT.lnk" "$INSTDIR\$INSTEXE" "$SHORTCUT_LANG_PARAM" "$INSTDIR\$INSTEXE" +!endif +FunctionEnd -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; Variables -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -Var INSTPROG -Var INSTEXE -Var INSTFLAGS -Var INSTSHORTCUT -Var COMMANDLINE ; command line passed to this installer, set in .onInit -Var SHORTCUT_LANG_PARAM ; "--set InstallLanguage de", passes language to viewer - -;;; Function definitions should go before file includes, because calls to -;;; DLLs like LangDLL trigger an implicit file include, so if that call is at -;;; the end of this script NSIS has to decompress the whole installer before -;;; it can call the DLL function. JC - -!include "FileFunc.nsh" ; For GetParameters, GetOptions -!insertmacro GetParameters -!insertmacro GetOptions +;Check version compatibility +Function CheckWindowsVersion +!ifdef WIN64_BIN_BUILD + ${IfNot} ${RunningX64} + MessageBox MB_OK|MB_ICONSTOP "This version requires a 64 bit operating system." + Quit + ${EndIf} +!endif -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; After install completes, launch app -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -Function .onInstSuccess - Push $R0 # Option value, unused - ${GetOptions} $COMMANDLINE "/AUTOSTART" $R0 - # If parameter was there (no error) just launch - # Otherwise ask - IfErrors label_ask_launch label_launch - -label_ask_launch: - # Don't launch by default when silent - IfSilent label_no_launch - MessageBox MB_YESNO $(InstSuccesssQuestion) \ - IDYES label_launch IDNO label_no_launch - -label_launch: - # Assumes SetOutPath $INSTDIR - Exec '"$INSTDIR\$INSTEXE" $INSTFLAGS $SHORTCUT_LANG_PARAM' -label_no_launch: - Pop $R0 + ${If} ${AtMostWinVista} + MessageBox MB_OK $(CheckWindowsVersionMB) + Quit + ${EndIf} FunctionEnd +;Check service pack compatibility and suggest upgrade +Function CheckWindowsServPack + ${If} ${IsWin7} + ${AndIfNot} ${IsServicePack} 1 + MessageBox MB_OK $(CheckWindowsServPackMB) + DetailPrint $(UseLatestServPackDP) + Return + ${EndIf} -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; Make sure we're not on Windows 98 / ME -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -Function CheckWindowsVersion - DetailPrint "Checking Windows version..." - Call GetWindowsVersion - Pop $R0 - ; Just get first two characters, ignore 4.0 part of "NT 4.0" - StrCpy $R0 $R0 2 - ; Blacklist certain OS versions - StrCmp $R0 "95" win_ver_bad - StrCmp $R0 "98" win_ver_bad - StrCmp $R0 "ME" win_ver_bad - StrCmp $R0 "NT" win_ver_bad - Return -win_ver_bad: - MessageBox MB_YESNO $(CheckWindowsVersionMB) IDNO win_ver_abort - Return -win_ver_abort: - Quit + ${If} ${IsWin2008R2} + ${AndIfNot} ${IsServicePack} 1 + MessageBox MB_OK $(CheckWindowsServPackMB) + DetailPrint $(UseLatestServPackDP) + Return + ${EndIf} FunctionEnd -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; Make sure the user can install/uninstall -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;Make sure the user can install/uninstall Function CheckIfAdministrator - DetailPrint $(CheckAdministratorInstDP) - UserInfo::GetAccountType - Pop $R0 - StrCmp $R0 "Admin" lbl_is_admin - MessageBox MB_OK $(CheckAdministratorInstMB) - Quit + DetailPrint $(CheckAdministratorInstDP) + UserInfo::GetAccountType + Pop $R0 + StrCmp $R0 "Admin" lbl_is_admin + MessageBox MB_OK $(CheckAdministratorInstMB) + Quit lbl_is_admin: - Return + Return FunctionEnd -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Function un.CheckIfAdministrator - DetailPrint $(CheckAdministratorUnInstDP) - UserInfo::GetAccountType - Pop $R0 - StrCmp $R0 "Admin" lbl_is_admin - MessageBox MB_OK $(CheckAdministratorUnInstMB) - Quit + DetailPrint $(CheckAdministratorUnInstDP) + UserInfo::GetAccountType + Pop $R0 + StrCmp $R0 "Admin" lbl_is_admin + MessageBox MB_OK $(CheckAdministratorUnInstMB) + Quit lbl_is_admin: - Return + Return FunctionEnd -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; Checks to see if the current version has already been installed (according to the registry). -; If it has, allow user to bail out of install process. -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;Checks for CPU compatibility +Function CheckCPUFlags + Push $1 + System::Call 'kernel32::IsProcessorFeaturePresent(i) i(10) .r1' + IntCmp $1 1 OK_SSE2 + MessageBox MB_OKCANCEL $(MissingSSE2) /SD IDOK IDOK OK_SSE2 + Quit + + OK_SSE2: + Pop $1 + Return +FunctionEnd + +;Checks if installed version is same as installer and offers to cancel Function CheckIfAlreadyCurrent +!ifdef WIN64_BIN_BUILD + SetRegView 64 +!endif Push $0 - ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Version" - StrCmp $0 ${VERSION_LONG} 0 DONE - MessageBox MB_OKCANCEL $(CheckIfCurrentMB) /SD IDOK IDOK DONE - Quit - - DONE: - Pop $0 - Return + ReadRegStr $0 HKLM "SOFTWARE\${VENDORSTR}\$INSTPROG" "Version" + StrCmp $0 ${VERSION_LONG} 0 continue_install + StrCmp $SKIP_DIALOGS "true" continue_install + MessageBox MB_OKCANCEL $(CheckIfCurrentMB) /SD IDOK IDOK continue_install + Quit +continue_install: + Pop $0 + Return FunctionEnd - + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Close the program, if running. Modifies no variables. ; Allows user to bail out of install process. @@ -201,224 +338,28 @@ Function CloseSecondLife Push $0 FindWindow $0 "Second Life" "" IntCmp $0 0 DONE - MessageBox MB_OKCANCEL $(CloseSecondLifeInstMB) IDOK CLOSE IDCANCEL CANCEL_INSTALL + + StrCmp $SKIP_DIALOGS "true" CLOSE + MessageBox MB_YESNOCANCEL $(CloseSecondLifeInstMB) IDYES CLOSE IDNO DONE - CANCEL_INSTALL: - Quit +; CANCEL_INSTALL: + Quit CLOSE: DetailPrint $(CloseSecondLifeInstDP) SendMessage $0 16 0 0 LOOP: - FindWindow $0 "Second Life" "" - IntCmp $0 0 DONE - Sleep 500 - Goto LOOP + FindWindow $0 "Second Life" "" + IntCmp $0 0 DONE + Sleep 500 + Goto LOOP DONE: Pop $0 Return FunctionEnd -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; Test our connection to secondlife.com -; Also allows us to count attempted installs by examining web logs. -; *TODO: Return current SL version info and have installer check -; if it is up to date. -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -Function CheckNetworkConnection - Push $0 - Push $1 - Push $2 # Option value for GetOptions - DetailPrint $(CheckNetworkConnectionDP) - ; Look for a tag value from the stub installer, used for statistics - ; to correlate installs. Default to "" if not found on command line. - StrCpy $2 "" - ${GetOptions} $COMMANDLINE "/STUBTAG=" $2 - GetTempFileName $0 - !define HTTP_TIMEOUT 5000 ; milliseconds - ; Don't show secondary progress bar, this will be quick. - NSISdl::download_quiet \ - /TIMEOUT=${HTTP_TIMEOUT} \ - "http://install.secondlife.com/check/?stubtag=$2&version=${VERSION_LONG}" \ - $0 - Pop $1 ; Return value, either "success", "cancel" or an error message - ; MessageBox MB_OK "Download result: $1" - ; Result ignored for now - ; StrCmp $1 "success" +2 - ; DetailPrint "Connection failed: $1" - Delete $0 ; temporary file - Pop $2 - Pop $1 - Pop $0 - Return -FunctionEnd - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; Delete files in Documents and Settings\\SecondLife\cache -; Delete files in Documents and Settings\All Users\SecondLife\cache -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;Function RemoveCacheFiles -; -;; Delete files in Documents and Settings\\SecondLife -;Push $0 -;Push $1 -;Push $2 -; DetailPrint $(RemoveCacheFilesDP) -; -; StrCpy $0 0 ; Index number used to iterate via EnumRegKey -; -; LOOP: -; EnumRegKey $1 HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList" $0 -; StrCmp $1 "" DONE ; no more users -; -; ReadRegStr $2 HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\$1" "ProfileImagePath" -; StrCmp $2 "" CONTINUE 0 ; "ProfileImagePath" value is missing -; -; ; Required since ProfileImagePath is of type REG_EXPAND_SZ -; ExpandEnvStrings $2 $2 -; -; ; When explicitly uninstalling, everything goes away -; RMDir /r "$2\Application Data\SecondLife\cache" -; -; CONTINUE: -; IntOp $0 $0 + 1 -; Goto LOOP -; DONE: -;Pop $2 -;Pop $1 -;Pop $0 -; -;; Delete files in Documents and Settings\All Users\SecondLife -;Push $0 -; ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders" "Common AppData" -; StrCmp $0 "" +2 -; RMDir /r "$0\SecondLife\cache" -;Pop $0 -; -;; Delete filse in C:\Windows\Application Data\SecondLife -;; If the user is running on a pre-NT system, Application Data lives here instead of -;; in Documents and Settings. -;RMDir /r "$WINDIR\Application Data\SecondLife\cache" -; -;FunctionEnd - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; Delete the installed shader files -;;; Since shaders are in active development, we'll likely need to shuffle them -;;; around a bit from build to build. This ensures that shaders that we move -;;; or rename in the dev tree don't get left behind in the install. -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -Function RemoveOldShaders - -;; Remove old shader files first so fallbacks will work. see DEV-5663 -RMDir /r "$INSTDIR\app_settings\shaders\*" - -FunctionEnd - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; Delete the installed XUI files -;;; We've changed the directory hierarchy for skins, putting all XUI and texture -;;; files under a specific skin directory, i.e. skins/default/xui/en-us as opposed -;;; to skins/xui/en-us. Need to clean up the old path when upgrading -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -Function RemoveOldXUI - -;; remove old XUI and texture files -RmDir /r "$INSTDIR\skins\html" -RmDir /r "$INSTDIR\skins\xui" -RmDir /r "$INSTDIR\skins\textures" -Delete "$INSTDIR\skins\*.txt" - -FunctionEnd - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; Remove any releasenotes files. -;;; We are no longer including release notes with the viewer. This will delete -;;; any that were left behind by an older installer. Delete will not fail if -;;; the files do not exist -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -Function RemoveOldReleaseNotes - -;; remove releasenotes.txt file from application directory, and the shortcut -;; from the start menu. -Delete "$SMPROGRAMS\$INSTSHORTCUT\SL Release Notes.lnk" -Delete "$INSTDIR\releasenotes.txt" - -FunctionEnd - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; Delete a xui file that causes crash in Silver skin in cases where it was -;;; left behind by an older installer. -;;; See SNOW-348 -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -Function RemoveOldAboutLandSilver - -Delete "$INSTDIR\skins\silver\xui\en-us\floater_about_land.xml" - -FunctionEnd - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; Delete files in Documents and Settings\\SecondLife -; Delete files in Documents and Settings\All Users\SecondLife -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -Function un.DocumentsAndSettingsFolder - -; Delete files in Documents and Settings\\SecondLife -Push $0 -Push $1 -Push $2 - - DetailPrint "Deleting files in Documents and Settings folder" - - StrCpy $0 0 ; Index number used to iterate via EnumRegKey - - LOOP: - EnumRegKey $1 HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList" $0 - StrCmp $1 "" DONE ; no more users - - ReadRegStr $2 HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\$1" "ProfileImagePath" - StrCmp $2 "" CONTINUE 0 ; "ProfileImagePath" value is missing - - ; Required since ProfileImagePath is of type REG_EXPAND_SZ - ExpandEnvStrings $2 $2 - - ; If uninstalling a normal install remove everything - ; Otherwise (preview/dmz etc) just remove cache - StrCmp $INSTFLAGS "" RM_ALL RM_CACHE - RM_ALL: - RMDir /r "$2\Application Data\SecondLife" - RM_CACHE: - # Local Settings directory is the cache, there is no "cache" subdir - RMDir /r "$2\Local Settings\Application Data\SecondLife" - # Vista version of the same - RMDir /r "$2\AppData\Local\SecondLife" - Delete "$2\Application Data\SecondLife\user_settings\settings_windlight.xml" - - CONTINUE: - IntOp $0 $0 + 1 - Goto LOOP - DONE: - -Pop $2 -Pop $1 -Pop $0 - -; Delete files in Documents and Settings\All Users\SecondLife -Push $0 - ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders" "Common AppData" - StrCmp $0 "" +2 - RMDir /r "$0\SecondLife" -Pop $0 - -; Delete filse in C:\Windows\Application Data\SecondLife -; If the user is running on a pre-NT system, Application Data lives here instead of -; in Documents and Settings. -RMDir /r "$WINDIR\Application Data\SecondLife" - -FunctionEnd - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Close the program, if running. Modifies no variables. ; Allows user to bail out of uninstall process. @@ -430,17 +371,17 @@ Function un.CloseSecondLife MessageBox MB_OKCANCEL $(CloseSecondLifeUnInstMB) IDOK CLOSE IDCANCEL CANCEL_UNINSTALL CANCEL_UNINSTALL: - Quit + Quit CLOSE: DetailPrint $(CloseSecondLifeUnInstDP) SendMessage $0 16 0 0 LOOP: - FindWindow $0 "Second Life" "" - IntCmp $0 0 DONE - Sleep 500 - Goto LOOP + FindWindow $0 "Second Life" "" + IntCmp $0 0 DONE + Sleep 500 + Goto LOOP DONE: Pop $0 @@ -448,375 +389,301 @@ Function un.CloseSecondLife FunctionEnd -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; -; Delete the stored password for the current Windows user -; DEV-10821 -- Unauthorised user can gain access to an SL account after a real user has uninstalled -; -Function un.RemovePassword - -DetailPrint "Removing Second Life password" -SetShellVarContext current -Delete "$APPDATA\SecondLife\user_settings\password.dat" -SetShellVarContext all +;-------------------------------- +;Installer Sections -FunctionEnd - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; Delete the installed files -;;; This deletes the uninstall executable, but it works -;;; because it is copied to temp directory before running -;;; -;;; Note: You must list all files here, because we only -;;; want to delete our files, not things users left in the -;;; application directories. -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -Function un.ProgramFiles - -;; Remove mozilla file first so recursive directory deletion doesn't get hung up -Delete "$INSTDIR\app_settings\mozilla\components" - -;; This placeholder is replaced by the complete list of files to uninstall by viewer_manifest.py -%%DELETE_FILES%% - -;; Optional/obsolete files. Delete won't fail if they don't exist. -Delete "$INSTDIR\dronesettings.ini" -Delete "$INSTDIR\message_template.msg" -Delete "$INSTDIR\newview.pdb" -Delete "$INSTDIR\newview.map" -Delete "$INSTDIR\SecondLife.pdb" -Delete "$INSTDIR\SecondLife.map" -Delete "$INSTDIR\comm.dat" -Delete "$INSTDIR\*.glsl" -Delete "$INSTDIR\motions\*.lla" -Delete "$INSTDIR\trial\*.html" -Delete "$INSTDIR\newview.exe" -;; Remove entire help directory -Delete "$INSTDIR\help\Advanced\*" -RMDir "$INSTDIR\help\Advanced" -Delete "$INSTDIR\help\basics\*" -RMDir "$INSTDIR\help\basics" -Delete "$INSTDIR\help\Concepts\*" -RMDir "$INSTDIR\help\Concepts" -Delete "$INSTDIR\help\welcome\*" -RMDir "$INSTDIR\help\welcome" -Delete "$INSTDIR\help\*" -RMDir "$INSTDIR\help" - -Delete "$INSTDIR\uninst.exe" -RMDir "$INSTDIR" - -IfFileExists "$INSTDIR" FOLDERFOUND NOFOLDER - -FOLDERFOUND: - MessageBox MB_YESNO $(DeleteProgramFilesMB) IDNO NOFOLDER - RMDir /r "$INSTDIR" - -NOFOLDER: - -FunctionEnd - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; Uninstall settings -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -UninstallText $(UninstallTextMsg) -ShowUninstDetails show - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; Uninstall section -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -Section Uninstall - -; Start with some default values. -StrCpy $INSTFLAGS "" -StrCpy $INSTPROG "${INSTNAME}" -StrCpy $INSTEXE "${INSTEXE}" -StrCpy $INSTSHORTCUT "${SHORTCUT}" -Call un.CheckIfAdministrator ; Make sure the user can install/uninstall - -; uninstall for all users (if you change this, change it in the install as well) -SetShellVarContext all - -; Make sure we're not running -Call un.CloseSecondLife - -; Clean up registry keys and subkeys (these should all be !defines somewhere) -DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" -DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" - -; Clean up shortcuts -Delete "$SMPROGRAMS\$INSTSHORTCUT\*.*" -RMDir "$SMPROGRAMS\$INSTSHORTCUT" - -Delete "$DESKTOP\$INSTSHORTCUT.lnk" -Delete "$INSTDIR\$INSTSHORTCUT.lnk" -Delete "$INSTDIR\Uninstall $INSTSHORTCUT.lnk" - -; Clean up cache and log files. -; Leave them in-place for non AGNI installs. - -!ifdef UNINSTALL_SETTINGS -Call un.DocumentsAndSettingsFolder +Section "Viewer" + SectionIn RO + SetShellVarContext all +!ifdef WIN64_BIN_BUILD + SetRegView 64 +!endif + ;Start with some default values. + StrCpy $INSTPROG "${APPNAMEONEWORD}" + StrCpy $INSTEXE "${INSTEXE}" + StrCpy $INSTSHORTCUT "${APPNAME}" + + Call CheckIfAlreadyCurrent + Call CloseSecondLife ; Make sure we're not running + + SetOutPath "$INSTDIR" + ;Remove old shader files first so fallbacks will work. + RMDir /r "$INSTDIR\app_settings\shaders\*" + ;Remove old Microsoft DLLs, reboot if needed + Delete /REBOOTOK "$INSTDIR\api-ms-win-*.dll" + Delete /REBOOTOK "$INSTDIR\concrt*.dll" + Delete /REBOOTOK "$INSTDIR\msvcp*.dll" + Delete /REBOOTOK "$INSTDIR\ucrtbase.dll" + Delete /REBOOTOK "$INSTDIR\vccorlib*.dll" + Delete /REBOOTOK "$INSTDIR\vcruntime*.dll" + + ;This placeholder is replaced by the complete list of all the files in the installer, by viewer_manifest.py + %%INSTALL_FILES%% + + ;Create temp dir and set out dir to it + CreateDirectory "$TEMP\AlchemyInst" + SetOutPath "$TEMP\AlchemyInst" + + ;Download LibVLC +!ifdef WIN64_BIN_BUILD + inetc::get /RESUME "Failed to download VLC media package. Retry?" "https://download.videolan.org/pub/videolan/vlc/3.0.8/win64/vlc-3.0.8-win64.7z" "$TEMP\AlchemyInst\libvlc.7z" /END +!else + inetc::get /RESUME "Failed to download VLC media package. Retry?" "https://download.videolan.org/pub/videolan/vlc/3.0.8/win32/vlc-3.0.8-win32.7z" "$TEMP\AlchemyInst\libvlc.7z" /END +!endif + Nsis7z::ExtractWithDetails "$TEMP\AlchemyInst\libvlc.7z" "Unpacking media plugins %s..." + Rename "$TEMP\AlchemyInst\vlc-3.0.8\libvlc.dll" "$INSTDIR\llplugin\libvlc.dll" + Rename "$TEMP\AlchemyInst\vlc-3.0.8\libvlccore.dll" "$INSTDIR\llplugin\libvlccore.dll" + Rename "$TEMP\AlchemyInst\vlc-3.0.8\plugins" "$INSTDIR\llplugin\plugins" + + ;Download and install VC redist +!ifdef WIN64_BIN_BUILD + inetc::get /RESUME "Failed to download VS2019 redistributable package. Retry?" "https://aka.ms/vs/16/release/vc_redist.x64.exe" "$TEMP\AlchemyInst\vc_redist_16.x64.exe" /END + ExecWait "$TEMP\AlchemyInst\vc_redist_16.x64.exe /install /passive /norestart" + + inetc::get /RESUME "Failed to download VS2013 redistributable package. Retry?" "https://aka.ms/highdpimfc2013x64enu" "$TEMP\AlchemyInst\vc_redist_12.x64.exe" /END + ExecWait "$TEMP\AlchemyInst\vc_redist_12.x64.exe /install /passive /norestart" +!else + inetc::get /RESUME "Failed to download VS2019 redistributable package. Retry?" "https://aka.ms/vs/16/release/vc_redist.x86.exe" "$TEMP\AlchemyInst\vc_redist_16.x86.exe" /END + ExecWait "$TEMP\AlchemyInst\vc_redist_16.x86.exe /install /passive /norestart" + + inetc::get /RESUME "Failed to download VS2013 redistributable package. Retry?" "https://aka.ms/highdpimfc2013x86enu" "$TEMP\AlchemyInst\vc_redist_12.x86.exe" /END + ExecWait "$TEMP\AlchemyInst\vc_redist_12.x86.exe /install /passive /norestart" !endif -; remove stored password on uninstall -Call un.RemovePassword + ;Remove temp dir and reset out to inst dir + RMDir /r "$TEMP\AlchemyInst\" + SetOutPath "$INSTDIR" + + ;Pass the installer's language to the client to use as a default + StrCpy $SHORTCUT_LANG_PARAM "--set InstallLanguage $(LanguageCode)" + + ;Create startmenu shortcuts + !insertmacro MUI_STARTMENU_WRITE_BEGIN Application + CreateDirectory "$SMPROGRAMS\$STARTMENUFOLDER" +!ifdef WIN64_BIN_BUILD + CreateShortCut "$SMPROGRAMS\$STARTMENUFOLDER\$INSTSHORTCUT (64 bit) Viewer.lnk" "$\"$INSTDIR\$INSTEXE$\"" "$SHORTCUT_LANG_PARAM" + CreateShortCut "$SMPROGRAMS\$STARTMENUFOLDER\Uninstall $INSTSHORTCUT (64 bit) Viewer.lnk" "$\"$INSTDIR\uninst.exe$\"" "" +!else + CreateShortCut "$SMPROGRAMS\$STARTMENUFOLDER\$INSTSHORTCUT.lnk" "$\"$INSTDIR\$INSTEXE$\"" "$SHORTCUT_LANG_PARAM" + CreateShortCut "$SMPROGRAMS\$STARTMENUFOLDER\Uninstall $INSTSHORTCUT.lnk" "$\"$INSTDIR\uninst.exe$\"" "" +!endif + WriteINIStr "$SMPROGRAMS\$STARTMENUFOLDER\SL Create Account.url" "InternetShortcut" "URL" "https://join.secondlife.com/" + WriteINIStr "$SMPROGRAMS\$STARTMENUFOLDER\SL Your Account.url" "InternetShortcut" "URL" "https://www.secondlife.com/account/" + WriteINIStr "$SMPROGRAMS\$STARTMENUFOLDER\SL Scripting Language Help.url" "InternetShortcut" "URL" "https://wiki.secondlife.com/wiki/LSL_Portal" + + !insertmacro MUI_STARTMENU_WRITE_END + + ;Other shortcuts + SetOutPath "$INSTDIR" +!ifdef WIN64_BIN_BUILD + ;CreateShortCut "$DESKTOP\$INSTSHORTCUT.lnk" "$INSTDIR\$INSTEXE" "$SHORTCUT_LANG_PARAM" + CreateShortCut "$INSTDIR\$INSTSHORTCUT (64 bit) Viewer.lnk" "$INSTDIR\$INSTEXE" "$SHORTCUT_LANG_PARAM" + CreateShortCut "$INSTDIR\$INSTSHORTCUT (64 bit) Viewer Portable.lnk" "$INSTDIR\$INSTEXE" "$SHORTCUT_LANG_PARAM --portable" + CreateShortCut "$INSTDIR\Uninstall $INSTSHORTCUT (64 bit) Viewer.lnk" "$INSTDIR\uninst.exe" "" +!else + ;CreateShortCut "$DESKTOP\$INSTSHORTCUT.lnk" "$INSTDIR\$INSTEXE" "$SHORTCUT_LANG_PARAM" + CreateShortCut "$INSTDIR\$INSTSHORTCUT Viewer.lnk" "$INSTDIR\$INSTEXE" "$SHORTCUT_LANG_PARAM" + CreateShortCut "$INSTDIR\$INSTSHORTCUT Viewer Portable.lnk" "$INSTDIR\$INSTEXE" "$SHORTCUT_LANG_PARAM --portable" + CreateShortCut "$INSTDIR\Uninstall $INSTSHORTCUT Viewer.lnk" "$INSTDIR\uninst.exe" "" +!endif + + ;Write registry + WriteRegStr HKLM "${INSTNAME_KEY}" "" "$INSTDIR" + WriteRegStr HKLM "${INSTNAME_KEY}" "Version" "${VERSION_LONG}" + WriteRegStr HKLM "${INSTNAME_KEY}" "Shortcut" "$INSTSHORTCUT" + WriteRegStr HKLM "${INSTNAME_KEY}" "Exe" "$INSTEXE" + WriteRegStr HKLM "${MSUNINSTALL_KEY}" "Comments" "A viewer for the meta-verse!" +!ifdef WIN64_BIN_BUILD + WriteRegStr HKLM "${MSUNINSTALL_KEY}" "DisplayName" "$INSTSHORTCUT (64 bit) Viewer" +!else + WriteRegStr HKLM "${MSUNINSTALL_KEY}" "DisplayName" "$INSTSHORTCUT Viewer" +!endif + WriteRegStr HKLM "${MSUNINSTALL_KEY}" "DisplayIcon" "$INSTDIR\$INSTEXE" + WriteRegStr HKLM "${MSUNINSTALL_KEY}" "DisplayVersion" "${VERSION_LONG}" + WriteRegStr HKLM "${MSUNINSTALL_KEY}" "InstallLocation" "$INSTDIR" + WriteRegStr HKLM "${MSUNINSTALL_KEY}" "InstallSource" "$EXEDIR\" + WriteRegStr HKLM "${MSUNINSTALL_KEY}" "HelpLink" "http://www.singularityviewer.org" + WriteRegDWORD HKLM "${MSUNINSTALL_KEY}" "NoModify" 1 + WriteRegDWORD HKLM "${MSUNINSTALL_KEY}" "NoRepair" 1 + WriteRegStr HKLM "${MSUNINSTALL_KEY}" "Publisher" "${VENDORSTR}" + WriteRegStr HKLM "${MSUNINSTALL_KEY}" "URLInfoAbout" "http://www.singularityviewer.org" + WriteRegStr HKLM "${MSUNINSTALL_KEY}" "URLUpdateInfo" "http://www.singularityviewer.org/downloads" + WriteRegStr HKLM "${MSUNINSTALL_KEY}" "UninstallString" "$\"$INSTDIR\uninst.exe$\"" + WriteRegStr HKLM "${MSUNINSTALL_KEY}" "QuietUninstallString" "$\"$INSTDIR\uninst.exe$\" /S" + ${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2 + IntFmt $0 "0x%08X" $0 + WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "EstimatedSize" "$0" + + + ;Write URL registry info + DeleteRegKey HKEY_CLASSES_ROOT "${URLNAME}" + WriteRegStr HKEY_CLASSES_ROOT "${URLNAME}" "" "URL:Second Life" + WriteRegStr HKEY_CLASSES_ROOT "${URLNAME}" "URL Protocol" "" + WriteRegStr HKEY_CLASSES_ROOT "${URLNAME}\DefaultIcon" "" "$INSTDIR\$INSTEXE" + ;; URL param must be last item passed to viewer, it ignores subsequent params + ;; to avoid parameter injection attacks. + WriteRegStr HKEY_CLASSES_ROOT "${URLNAME}\shell" "" "open" +!ifdef WIN64_BIN_BUILD + WriteRegStr HKEY_CLASSES_ROOT "${URLNAME}\shell\open" "FriendlyAppName" "$INSTSHORTCUT (64 bit) Viewer" +!else + WriteRegStr HKEY_CLASSES_ROOT "${URLNAME}\shell\open" "FriendlyAppName" "$INSTSHORTCUT Viewer" +!endif + WriteRegExpandStr HKEY_CLASSES_ROOT "${URLNAME}\shell\open\command" "" "$\"$INSTDIR\$INSTEXE$\" -url $\"%1$\"" + + DeleteRegKey HKEY_CLASSES_ROOT "x-grid-info" + WriteRegStr HKEY_CLASSES_ROOT "x-grid-info" "" "URL:Hypergrid" + WriteRegStr HKEY_CLASSES_ROOT "x-grid-info" "URL Protocol" "" + WriteRegStr HKEY_CLASSES_ROOT "x-grid-info\DefaultIcon" "" "$INSTDIR\$INSTEXE" + ;; URL param must be last item passed to viewer, it ignores subsequent params + ;; to avoid parameter injection attacks. + WriteRegStr HKEY_CLASSES_ROOT "x-grid-info\shell" "" "open" +!ifdef WIN64_BIN_BUILD + WriteRegStr HKEY_CLASSES_ROOT "x-grid-info\shell\open" "FriendlyAppName" "$INSTSHORTCUT (64 bit) Viewer" +!else + WriteRegStr HKEY_CLASSES_ROOT "x-grid-info\shell\open" "FriendlyAppName" "$INSTSHORTCUT Viewer" +!endif + WriteRegExpandStr HKEY_CLASSES_ROOT "x-grid-info\shell\open\command" "" "$\"$INSTDIR\$INSTEXE$\" -url $\"%1$\"" + + DeleteRegKey HKEY_CLASSES_ROOT "x-grid-location-info" + WriteRegStr HKEY_CLASSES_ROOT "x-grid-location-info" "" "URL:Hypergrid legacy" + WriteRegStr HKEY_CLASSES_ROOT "x-grid-location-info" "URL Protocol" "" + WriteRegStr HKEY_CLASSES_ROOT "x-grid-location-info\DefaultIcon" "" "$\"$INSTDIR\$INSTEXE$\"" + + ;; URL param must be last item passed to viewer, it ignores subsequent params + ;; to avoid parameter injection attacks. + WriteRegStr HKEY_CLASSES_ROOT "x-grid-location-info\shell" "" "open" +!ifdef WIN64_BIN_BUILD + WriteRegStr HKEY_CLASSES_ROOT "x-grid-location-info\shell\open" "FriendlyAppName" "$INSTSHORTCUT (64 bit) Viewer" +!else + WriteRegStr HKEY_CLASSES_ROOT "x-grid-location-info\shell\open" "FriendlyAppName" "$INSTSHORTCUT Viewer" +!endif + WriteRegExpandStr HKEY_CLASSES_ROOT "x-grid-location-info\shell\open\command" "" "$\"$INSTDIR\$INSTEXE$\" -url $\"%1$\"" + + ;Create uninstaller + SetOutPath "$INSTDIR" + WriteUninstaller "$INSTDIR\uninst.exe" + +SectionEnd -Call un.ProgramFiles +;-------------------------------- +;Installer Functions +Function .onInit +!ifdef WIN64_BIN_BUILD + SetRegView 64 +!endif + ;Don't install on unsupported operating systems + Call CheckWindowsVersion + ;Don't install if not administator + Call CheckIfAdministrator + ;Don't install if we lack required cpu support + Call CheckCPUFlags -SectionEnd ; end of uninstall section + Push $0 + ;Get installation folder from registry if available for 64bit +!ifdef WIN64_BIN_BUILD + ReadRegStr $0 HKLM "SOFTWARE\${VENDORSTR}\${APPNAMEONEWORD}" "" + IfErrors +2 0 ; If error jump past setting SKIP_AUTORUN + StrCpy $INSTDIR $0 +!endif -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; (From the NSIS documentation, JC) -; GetWindowsVersion -; -; Based on Yazno's function, http://yazno.tripod.com/powerpimpit/ -; Updated by Joost Verburg -; -; Returns on top of stack -; -; Windows Version (95, 98, ME, NT x.x, 2000, XP, 2003) -; or -; '' (Unknown Windows Version) -; -; Usage: -; Call GetWindowsVersion -; Pop $R0 -; ; at this point $R0 is "NT 4.0" or whatnot -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -Function GetWindowsVersion - - Push $R0 - Push $R1 - - ReadRegStr $R0 HKLM \ - "SOFTWARE\Microsoft\Windows NT\CurrentVersion" CurrentVersion - - IfErrors 0 lbl_winnt - - ; we are not NT - ReadRegStr $R0 HKLM \ - "SOFTWARE\Microsoft\Windows\CurrentVersion" VersionNumber - - StrCpy $R1 $R0 1 - StrCmp $R1 '4' 0 lbl_error - - StrCpy $R1 $R0 3 - - StrCmp $R1 '4.0' lbl_win32_95 - StrCmp $R1 '4.9' lbl_win32_ME lbl_win32_98 - - lbl_win32_95: - StrCpy $R0 '95' - Goto lbl_done - - lbl_win32_98: - StrCpy $R0 '98' - Goto lbl_done - - lbl_win32_ME: - StrCpy $R0 'ME' - Goto lbl_done - - lbl_winnt: - - StrCpy $R1 $R0 1 - - StrCmp $R1 '3' lbl_winnt_x - StrCmp $R1 '4' lbl_winnt_x - - StrCpy $R1 $R0 3 - - StrCmp $R1 '5.0' lbl_winnt_2000 - StrCmp $R1 '5.1' lbl_winnt_XP - StrCmp $R1 '5.2' lbl_winnt_2003 lbl_error + ${GetParameters} $COMMANDLINE ; get our command line + + ${GetOptions} $COMMANDLINE "/SKIP_DIALOGS" $0 + IfErrors +2 0 ; If error jump past setting SKIP_DIALOGS + StrCpy $SKIP_DIALOGS "true" + + ${GetOptions} $COMMANDLINE "/SKIP_AUTORUN" $0 + IfErrors +2 0 ; If error jump past setting SKIP_AUTORUN + StrCpy $SKIP_AUTORUN "true" + + ${GetOptions} $COMMANDLINE "/AUTOSTART" $0 + IfErrors +2 0 ; If error jump past setting AUTOSTART + StrCpy $AUTOSTART "true" + + + ${GetOptions} $COMMANDLINE "/LANGID=" $0 ; /LANGID=1033 implies US English + ; If no language (error), then proceed + IfErrors lbl_configure_default_lang + ; No error means we got a language, so use it + StrCpy $LANGUAGE $0 + Goto lbl_return + +lbl_configure_default_lang: + ;For silent installs, no language prompt, use default + IfSilent lbl_return + StrCmp $SKIP_DIALOGS "true" lbl_return - lbl_winnt_x: - StrCpy $R0 "NT $R0" 6 - Goto lbl_done - - lbl_winnt_2000: - Strcpy $R0 '2000' - Goto lbl_done - - lbl_winnt_XP: - Strcpy $R0 'XP' - Goto lbl_done - - lbl_winnt_2003: - Strcpy $R0 '2003' - Goto lbl_done - - lbl_error: - Strcpy $R0 '' - lbl_done: - - Pop $R1 - Exch $R0 - -FunctionEnd + !insertmacro MUI_LANGDLL_DISPLAY -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Note: to add new languages, add a language file include to the list -;; at the top of this file, add an entry to the menu and then add an -;; entry to the language ID selector below -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -Function .onInit - Push $0 - ${GetParameters} $COMMANDLINE ; get our command line - ${GetOptions} $COMMANDLINE "/LANGID=" $0 ; /LANGID=1033 implies US English - ; If no language (error), then proceed - IfErrors lbl_check_silent - ; No error means we got a language, so use it - StrCpy $LANGUAGE $0 - Goto lbl_return - -lbl_check_silent: - ; For silent installs, no language prompt, use default - IfSilent lbl_return - - ; If we currently have a version of SL installed, default to the language of that install - ; Otherwise don't change $LANGUAGE and it will default to the OS UI language. - ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\${INSTNAME}" "InstallerLanguage" - IfErrors lbl_build_menu - StrCpy $LANGUAGE $0 - -lbl_build_menu: - Push "" - # Use separate file so labels can be UTF-16 but we can still merge changes - # into this ASCII file. JC - !include "%%SOURCE%%\installers\windows\language_menu.nsi" - - Push A ; A means auto count languages for the auto count to work the first empty push (Push "") must remain - LangDLL::LangDialog $(InstallerLanguageTitle) $(SelectInstallerLanguage) - Pop $0 - StrCmp $0 "cancel" 0 +2 - Abort - StrCpy $LANGUAGE $0 - - ; save language in registry - WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\${INSTNAME}" "InstallerLanguage" $LANGUAGE lbl_return: - Pop $0 - Return + Pop $0 + Return FunctionEnd -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -Function un.onInit - ; read language from registry and set for uninstaller - ; Key will be removed on successful uninstall - ReadRegStr $0 HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\${INSTNAME}" "InstallerLanguage" - IfErrors lbl_end - StrCpy $LANGUAGE $0 -lbl_end: - Return -FunctionEnd - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; MAIN SECTION -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -Section "" ; (default section) +;-------------------------------- +;Uninstaller Section -SetShellVarContext all ; install for all users (if you change this, change it in the uninstall as well) - -; Start with some default values. -StrCpy $INSTFLAGS "${INSTFLAGS}" -StrCpy $INSTPROG "${INSTNAME}" -StrCpy $INSTEXE "${INSTEXE}" -StrCpy $INSTSHORTCUT "${SHORTCUT}" - -Call CheckWindowsVersion ; warn if on Windows 98/ME -Call CheckIfAdministrator ; Make sure the user can install/uninstall -Call CheckIfAlreadyCurrent ; Make sure that we haven't already installed this version -Call CloseSecondLife ; Make sure we're not running -#Call CheckNetworkConnection ; ping secondlife.com - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; Don't remove cache files during a regular install, removing the inventory cache on upgrades results in lots of damage to the servers. -;Call RemoveCacheFiles ; Installing over removes potentially corrupted - ; VFS and cache files. - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; Need to clean out shader files from previous installs to fix DEV-5663 -Call RemoveOldShaders - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; Need to clean out old XUI files that predate skinning -Call RemoveOldXUI - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; Clear out old releasenotes.txt files. These are now on the public wiki. -Call RemoveOldReleaseNotes - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; Remove an old xui file that should not be in Silver skin -Call RemoveOldAboutLandSilver - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; Files -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; This placeholder is replaced by the complete list of all the files in the installer, by viewer_manifest.py -%%INSTALL_FILES%% - -# Pass the installer's language to the client to use as a default -StrCpy $SHORTCUT_LANG_PARAM "--set InstallLanguage $(LanguageCode)" - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; Shortcuts in start menu -CreateDirectory "$SMPROGRAMS\$INSTSHORTCUT" -SetOutPath "$INSTDIR" -CreateShortCut "$SMPROGRAMS\$INSTSHORTCUT\$INSTSHORTCUT.lnk" \ - "$INSTDIR\$INSTEXE" "$INSTFLAGS $SHORTCUT_LANG_PARAM" - - -WriteINIStr "$SMPROGRAMS\$INSTSHORTCUT\SL Create Account.url" \ - "InternetShortcut" "URL" \ - "http://www.secondlife.com/registration/" -WriteINIStr "$SMPROGRAMS\$INSTSHORTCUT\SL Your Account.url" \ - "InternetShortcut" "URL" \ - "http://www.secondlife.com/account/" -WriteINIStr "$SMPROGRAMS\$INSTSHORTCUT\SL Scripting Language Help.url" \ - "InternetShortcut" "URL" \ - "http://wiki.secondlife.com/wiki/LSL_Portal" -CreateShortCut "$SMPROGRAMS\$INSTSHORTCUT\Uninstall $INSTSHORTCUT.lnk" \ - '"$INSTDIR\uninst.exe"' '' +Section "Uninstall" + SectionIn RO + SetShellVarContext all +!ifdef WIN64_BIN_BUILD + SetRegView 64 +!endif + + StrCpy $INSTPROG "${APPNAMEONEWORD}" + StrCpy $INSTSHORTCUT "${APPNAME}" + + Call un.CloseSecondLife + + !insertmacro MUI_STARTMENU_GETFOLDER Application $STARTMENUFOLDER + RMDir /r "$SMPROGRAMS\$STARTMENUFOLDER" + + ;This placeholder is replaced by the complete list of all the files in the installer, by viewer_manifest.py + %%DELETE_FILES%% + + ;Optional/obsolete files. Delete won't fail if they don't exist. + Delete "$INSTDIR\message_template.msg" + Delete "$INSTDIR\VivoxVoiceService-*.log" + + ;Shortcuts in install directory +!ifdef WIN64_BIN_BUILD + Delete "$INSTDIR\$INSTSHORTCUT (64 bit) Viewer.lnk" + Delete "$INSTDIR\$INSTSHORTCUT (64 bit) Viewer Portable.lnk" + Delete "$INSTDIR\Uninstall $INSTSHORTCUT (64 bit) Viewer.lnk" +!else + Delete "$INSTDIR\$INSTSHORTCUT Viewer.lnk" + Delete "$INSTDIR\$INSTSHORTCUT Viewer Portable.lnk" + Delete "$INSTDIR\Uninstall $INSTSHORTCUT Viewer.lnk" +!endif + + Delete "$INSTDIR\uninst.exe" + RMDir "$INSTDIR" + + IfFileExists "$INSTDIR" FOLDERFOUND NOFOLDER -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; Other shortcuts -SetOutPath "$INSTDIR" -CreateShortCut "$DESKTOP\$INSTSHORTCUT.lnk" \ - "$INSTDIR\$INSTEXE" "$INSTFLAGS $SHORTCUT_LANG_PARAM" -CreateShortCut "$INSTDIR\$INSTSHORTCUT.lnk" \ - "$INSTDIR\$INSTEXE" "$INSTFLAGS $SHORTCUT_LANG_PARAM" -CreateShortCut "$INSTDIR\Uninstall $INSTSHORTCUT.lnk" \ - '"$INSTDIR\uninst.exe"' '' +FOLDERFOUND: + ;Silent uninstall always removes all files (/SD IDYES) + MessageBox MB_YESNO $(DeleteProgramFilesMB) /SD IDYES IDNO NOFOLDER + RMDir /r "$INSTDIR" +NOFOLDER: + DeleteRegKey HKLM "SOFTWARE\${VENDORSTR}\$INSTPROG" + DeleteRegKey /ifempty HKLM "SOFTWARE\${VENDORSTR}" + DeleteRegKey HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" + +SectionEnd -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; Write registry -WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "" "$INSTDIR" -WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Version" "${VERSION_LONG}" -WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Flags" "$INSTFLAGS" -WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Shortcut" "$INSTSHORTCUT" -WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Linden Research, Inc.\$INSTPROG" "Exe" "$INSTEXE" -WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "DisplayName" "$INSTPROG (remove only)" -WriteRegStr HKEY_LOCAL_MACHINE "Software\Microsoft\Windows\CurrentVersion\Uninstall\$INSTPROG" "UninstallString" '"$INSTDIR\uninst.exe"' +;-------------------------------- +;Uninstaller Functions -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; Write URL registry info -WriteRegStr HKEY_CLASSES_ROOT "${URLNAME}" "(default)" "URL:Second Life" -WriteRegStr HKEY_CLASSES_ROOT "${URLNAME}" "URL Protocol" "" -WriteRegStr HKEY_CLASSES_ROOT "${URLNAME}\DefaultIcon" "" '"$INSTDIR\$INSTEXE"' -;; URL param must be last item passed to viewer, it ignores subsequent params -;; to avoid parameter injection attacks. -WriteRegExpandStr HKEY_CLASSES_ROOT "${URLNAME}\shell\open\command" "" '"$INSTDIR\$INSTEXE" $INSTFLAGS -url "%1"' - -; write out uninstaller -WriteUninstaller "$INSTDIR\uninst.exe" - -; end of default section -SectionEnd +Function un.onInit +!ifdef WIN64_BIN_BUILD + SetRegView 64 +!endif + Call un.CheckIfAdministrator -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; EOF ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + !insertmacro MUI_UNGETLANGUAGE + +FunctionEnd diff --git a/indra/newview/installers/windows/lang_da.nsi b/indra/newview/installers/windows/lang_da.nsi new file mode 100644 index 0000000000..87e88492e8 --- /dev/null +++ b/indra/newview/installers/windows/lang_da.nsi @@ -0,0 +1,56 @@ +; First is default +!insertmacro MUI_LANGUAGE "Danish" + +; Language string +LangString LanguageCode ${LANG_DANISH} "da" + +; Language selection dialog +LangString SelectInstallerLanguage ${LANG_DANISH} "Vælg venligst sprog til installation" + +; installation directory text +LangString DirectoryChooseTitle ${LANG_DANISH} "Installationsmappe" +LangString DirectoryChooseUpdate ${LANG_DANISH} "Vælg ${APPNAME} mappe til opdatering til version ${VERSION_LONG}.(XXX):" +LangString DirectoryChooseSetup ${LANG_DANISH} "Vælg mappe hvor ${APPNAME} skal installeres:" + +; CheckStartupParams message box +LangString CheckStartupParamsMB ${LANG_DANISH} "Kunne ikke finde programmet '$INSTPROG'. Baggrundsopdatering fejlede." + +; check windows version +LangString CheckWindowsVersionDP ${LANG_DANISH} "Checker Windows version..." +LangString CheckWindowsVersionMB ${LANG_DANISH} '${APPNAME} supporterer kun Windows XP.$\n$\nForsøg på installation på Windows $R0 kan resultere i nedbrud og datatab.$\n$\n' +LangString CheckWindowsServPackMB ${LANG_DANISH} "It is recomended to run ${APPNAME} on the latest service pack for your operating system.$\nThis will help with performance and stability of the program." +LangString UseLatestServPackDP ${LANG_DANISH} "Please use Windows Update to install the latest Service Pack." + +; checkifadministrator function (install) +LangString CheckAdministratorInstDP ${LANG_DANISH} "Checker rettigheder til installation..." +LangString CheckAdministratorInstMB ${LANG_DANISH} 'Det ser ud til at du benytter en konto med begrænsninger.$\nDu skal have "administrator" rettigheder for at installere ${APPNAME}.' + +; checkifadministrator function (uninstall) +LangString CheckAdministratorUnInstDP ${LANG_DANISH} "Checker rettigheder til at afinstallere..." +LangString CheckAdministratorUnInstMB ${LANG_DANISH} 'Det ser ud til at du benytter en konto med begrænsninger.$\nDu skal have "administrator" rettigheder for at afinstallere ${APPNAME}.' + +; checkifalreadycurrent +LangString CheckIfCurrentMB ${LANG_DANISH} "Det ser ud til at ${APPNAME} ${VERSION_LONG} allerede er installeret.$\n$\nØnsker du at installere igen?" + +; checkcpuflags +LangString MissingSSE2 ${LANG_DANISH} "This machine may not have a CPU with SSE2 support, which is required to run ${APPNAME} ${VERSION_LONG}. Do you want to continue?" + +; closesecondlife function (install) +LangString CloseSecondLifeInstDP ${LANG_DANISH} "Venter på at ${APPNAME} skal lukke ned..." +LangString CloseSecondLifeInstMB ${LANG_DANISH} "${APPNAME} kan ikke installeres mens programmet kører.$\n$\nAfslut programmet for at fortsætte.$\nVælg ANNULÉR for at afbryde installation." + +; closesecondlife function (uninstall) +LangString CloseSecondLifeUnInstDP ${LANG_DANISH} "Venter på at ${APPNAME} skal lukke ned..." +LangString CloseSecondLifeUnInstMB ${LANG_DANISH} "${APPNAME} kan ikke afinstalleres mens programmet kører.$\n$\nAfslut programmet for at fortsætte.$\nVælg ANNULÉR for at afbryde installation." + +; CheckNetworkConnection +LangString CheckNetworkConnectionDP ${LANG_DANISH} "Checker netværksforbindelse..." + +; removecachefiles +LangString RemoveCacheFilesDP ${LANG_DANISH} "Sletter cache filer i dokument mappen" + +; delete program files +LangString DeleteProgramFilesMB ${LANG_DANISH} "Der er stadig filer i ${APPNAME} program mappen.$\n$\nDette er sandsynligvis filer du har oprettet eller flyttet til :$\n$INSTDIR$\n$\nØnsker du at fjerne disse filer?" + +; uninstall text +LangString UninstallTextMsg ${LANG_DANISH} "Dette vil afinstallere ${APPNAME} ${VERSION_LONG} fra dit system." diff --git a/indra/newview/installers/windows/lang_de.nsi b/indra/newview/installers/windows/lang_de.nsi index b717a4d3a5..a9d99fb749 100644 Binary files a/indra/newview/installers/windows/lang_de.nsi and b/indra/newview/installers/windows/lang_de.nsi differ diff --git a/indra/newview/installers/windows/lang_en-us.nsi b/indra/newview/installers/windows/lang_en-us.nsi index 331c4a3a38..9b0b64a7a5 100644 Binary files a/indra/newview/installers/windows/lang_en-us.nsi and b/indra/newview/installers/windows/lang_en-us.nsi differ diff --git a/indra/newview/installers/windows/lang_es.nsi b/indra/newview/installers/windows/lang_es.nsi index c6a7f38f3f..f4dd51a595 100644 Binary files a/indra/newview/installers/windows/lang_es.nsi and b/indra/newview/installers/windows/lang_es.nsi differ diff --git a/indra/newview/installers/windows/lang_fr.nsi b/indra/newview/installers/windows/lang_fr.nsi index 008c240ed7..6e11ffa6d8 100644 Binary files a/indra/newview/installers/windows/lang_fr.nsi and b/indra/newview/installers/windows/lang_fr.nsi differ diff --git a/indra/newview/installers/windows/lang_it.nsi b/indra/newview/installers/windows/lang_it.nsi index 1208ec4eb8..465b137099 100644 Binary files a/indra/newview/installers/windows/lang_it.nsi and b/indra/newview/installers/windows/lang_it.nsi differ diff --git a/indra/newview/installers/windows/lang_ja.nsi b/indra/newview/installers/windows/lang_ja.nsi index f564291f7d..f4cf3c75cf 100644 Binary files a/indra/newview/installers/windows/lang_ja.nsi and b/indra/newview/installers/windows/lang_ja.nsi differ diff --git a/indra/newview/installers/windows/lang_pl.nsi b/indra/newview/installers/windows/lang_pl.nsi new file mode 100644 index 0000000000..5e6c183b1f --- /dev/null +++ b/indra/newview/installers/windows/lang_pl.nsi @@ -0,0 +1,56 @@ +; First is default +!insertmacro MUI_LANGUAGE "Polish" + +; Language string +LangString LanguageCode ${LANG_POLISH} "pl" + +; Language selection dialog +LangString SelectInstallerLanguage ${LANG_POLISH} "Proszę wybrać język instalatora" + +; installation directory text +LangString DirectoryChooseTitle ${LANG_POLISH} "Katalog instalacji" +LangString DirectoryChooseUpdate ${LANG_POLISH} "Wybierz katalog instalacji ${APPNAME} w celu aktualizacji wersji ${VERSION_LONG}.(XXX):" +LangString DirectoryChooseSetup ${LANG_POLISH} "Wybierz katalog instalacji ${APPNAME} w:" + +; CheckStartupParams message box +LangString CheckStartupParamsMB ${LANG_POLISH} "Nie można odnaleźć programu '$INSTPROG'. Cicha aktualizacja zakończyła się niepowodzeniem." + +; check windows version +LangString CheckWindowsVersionDP ${LANG_POLISH} "Sprawdzanie wersji Windows..." +LangString CheckWindowsVersionMB ${LANG_POLISH} '${APPNAME} obsługuje tylko Windows XP.$\n$\nPróba zainstalowania na Windows $R0 może spowodować awarie i utratę danych.$\n$\n' +LangString CheckWindowsServPackMB ${LANG_POLISH} "Zalecane jest uruchamianie ${APPNAME} z najnowszym dostępnym Service Packiem zainstalowanym w systemie.$\nPomaga on w podniesieniu wydajności i stabilności programu." +LangString UseLatestServPackDP ${LANG_POLISH} "Użyj usługi Windows Update, aby zainstalować najnowszy Service Pack." + +; checkifadministrator function (install) +LangString CheckAdministratorInstDP ${LANG_POLISH} "Sprawdzanie zezwolenia na instalację..." +LangString CheckAdministratorInstMB ${LANG_POLISH} 'Używasz "ograniczonego" konta.$\nMusisz być zalogowany jako "administrator" aby zainstalować ${APPNAME}.' + +; checkifadministrator function (uninstall) +LangString CheckAdministratorUnInstDP ${LANG_POLISH} "Sprawdzanie zezwolenia na odinstalowanie..." +LangString CheckAdministratorUnInstMB ${LANG_POLISH} 'Używasz "ograniczonego" konta.$\nMusisz być być zalogowany jako "administrator" aby zainstalować ${APPNAME}.' + +; checkifalreadycurrent +LangString CheckIfCurrentMB ${LANG_POLISH} "${APPNAME} ${VERSION_LONG} jest już zainstalowane.$\n$\nCzy chcesz zainstalować ${APPNAME} ponownie?" + +; checkcpuflags +LangString MissingSSE2 ${LANG_POLISH} "Ten komputer może nie mieć procesora z obsługą SSE2, który jest wymagany aby uruchomić ${APPNAME} w wersji ${VERSION_LONG}. Chcesz kontynuować?" + +; closesecondlife function (install) +LangString CloseSecondLifeInstDP ${LANG_POLISH} "Oczekiwanie na zamknięcie ${APPNAME}..." +LangString CloseSecondLifeInstMB ${LANG_POLISH} "${APPNAME} nie może zostać zainstalowane, ponieważ jest już włączone.$\n$\nZakończ swoje działania i wybierz OK aby zamknąć ${APPNAME} i kontynuować.$\nWybierz CANCEL aby anulować instalację." + +; closesecondlife function (uninstall) +LangString CloseSecondLifeUnInstDP ${LANG_POLISH} "Oczekiwanie na zamknięcie ${APPNAME}..." +LangString CloseSecondLifeUnInstMB ${LANG_POLISH} "${APPNAME} nie może zostać zainstalowane, ponieważ jest już włączone.$\n$\nZakończ swoje działania i wybierz OK aby zamknąć ${APPNAME} i kontynuować.$\nWybierz CANCEL aby anulować." + +; CheckNetworkConnection +LangString CheckNetworkConnectionDP ${LANG_POLISH} "Sprawdzanie połączenia sieciowego..." + +; removecachefiles +LangString RemoveCacheFilesDP ${LANG_POLISH} "Kasowanie plików pamięci podręcznej (cache) w folderze Documents and Settings" + +; delete program files +LangString DeleteProgramFilesMB ${LANG_POLISH} "Nadal istnieją pliki w katalogu instalacyjnym ${APPNAME}.$\n$\nMożliwe, że są to pliki, które stworzyłeś/stworzyłaś lub przeniosłeś/przeniosłaś do:$\n$INSTDIR$\n$\nCzy chcesz je usunąć?" + +; uninstall text +LangString UninstallTextMsg ${LANG_POLISH} "To spowoduje odinstalowanie ${APPNAME} ${VERSION_LONG} z Twojego systemu." diff --git a/indra/newview/installers/windows/lang_pt-br.nsi b/indra/newview/installers/windows/lang_pt-br.nsi index da56a3c336..6ddbadab59 100644 Binary files a/indra/newview/installers/windows/lang_pt-br.nsi and b/indra/newview/installers/windows/lang_pt-br.nsi differ diff --git a/indra/newview/installers/windows/lang_ru.nsi b/indra/newview/installers/windows/lang_ru.nsi new file mode 100644 index 0000000000..ed4cd47c68 --- /dev/null +++ b/indra/newview/installers/windows/lang_ru.nsi @@ -0,0 +1,56 @@ +; First is default +!insertmacro MUI_LANGUAGE "Russian" + +; Language string +LangString LanguageCode ${LANG_RUSSIAN} "ru" + +; Language selection dialog +LangString SelectInstallerLanguage ${LANG_RUSSIAN} "Выберите язык программы установки" + +; installation directory text +LangString DirectoryChooseTitle ${LANG_RUSSIAN} "Каталог установки" +LangString DirectoryChooseUpdate ${LANG_RUSSIAN} "Выберите каталог ${APPNAME} для обновления до версии ${VERSION_LONG}.(XXX):" +LangString DirectoryChooseSetup ${LANG_RUSSIAN} "Выберите каталог для установки ${APPNAME}:" + +; CheckStartupParams message box +LangString CheckStartupParamsMB ${LANG_RUSSIAN} "Не удалось найти программу «$INSTPROG». Автоматическое обновление не выполнено." + +; check windows version +LangString CheckWindowsVersionDP ${LANG_RUSSIAN} "Проверка версии Windows..." +LangString CheckWindowsVersionMB ${LANG_RUSSIAN} '${APPNAME} может работать только в Windows XP.$\n$\nПопытка установки в Windows $R0 может привести к сбою и потере данных.$\n$\n' +LangString CheckWindowsServPackMB ${LANG_RUSSIAN} "It is recomended to run ${APPNAME} on the latest service pack for your operating system.$\nThis will help with performance and stability of the program." +LangString UseLatestServPackDP ${LANG_RUSSIAN} "Please use Windows Update to install the latest Service Pack." + +; checkifadministrator function (install) +LangString CheckAdministratorInstDP ${LANG_RUSSIAN} "Проверка разрешений на установку..." +LangString CheckAdministratorInstMB ${LANG_RUSSIAN} 'Вероятно, у вас ограниченный аккаунт.$\nДля установки ${APPNAME} необходимы права администратора.' + +; checkifadministrator function (uninstall) +LangString CheckAdministratorUnInstDP ${LANG_RUSSIAN} "Проверка разрешений на удаление..." +LangString CheckAdministratorUnInstMB ${LANG_RUSSIAN} 'Вероятно, у вас ограниченный аккаунт.$\nДля удаления ${APPNAME} необходимы права администратора.' + +; checkifalreadycurrent +LangString CheckIfCurrentMB ${LANG_RUSSIAN} "Вероятно, версия ${APPNAME} ${VERSION_LONG} уже установлена.$\n$\nУстановить ее снова?" + +; checkcpuflags +LangString MissingSSE2 ${LANG_RUSSIAN} "Возможно, на этом компьютере нет ЦП с поддержкой SSE2, которая необходима для работы ${APPNAME} ${VERSION_LONG}. Продолжить?" + +; closesecondlife function (install) +LangString CloseSecondLifeInstDP ${LANG_RUSSIAN} "Ожидаю завершения работы ${APPNAME}..." +LangString CloseSecondLifeInstMB ${LANG_RUSSIAN} "${APPNAME} уже работает, выполнить установку невозможно.$\n$\nЗавершите текущую операцию и нажмите кнопку «OK», чтобы закрыть ${APPNAME} и продолжить установку.$\nНажмите кнопку «ОТМЕНА» для отказа от установки." + +; closesecondlife function (uninstall) +LangString CloseSecondLifeUnInstDP ${LANG_RUSSIAN} "Ожидаю завершения работы ${APPNAME}..." +LangString CloseSecondLifeUnInstMB ${LANG_RUSSIAN} "${APPNAME} уже работает, выполнить удаление невозможно.$\n$\nЗавершите текущую операцию и нажмите кнопку «OK», чтобы закрыть ${APPNAME} и продолжить удаление.$\nНажмите кнопку «ОТМЕНА» для отказа от удаления." + +; CheckNetworkConnection +LangString CheckNetworkConnectionDP ${LANG_RUSSIAN} "Проверка подключения к сети..." + +; removecachefiles +LangString RemoveCacheFilesDP ${LANG_RUSSIAN} "Удаление файлов кэша из папки «Documents and Settings»" + +; delete program files +LangString DeleteProgramFilesMB ${LANG_RUSSIAN} "В каталоге программы ${APPNAME} остались файлы.$\n$\nВероятно, это файлы, созданные или перемещенные вами в $\n$INSTDIR$\n$\nУдалить их?" + +; uninstall text +LangString UninstallTextMsg ${LANG_RUSSIAN} "Программа ${APPNAME} ${VERSION_LONG} будет удалена из вашей системы." diff --git a/indra/newview/installers/windows/lang_tr.nsi b/indra/newview/installers/windows/lang_tr.nsi new file mode 100644 index 0000000000..262c327487 --- /dev/null +++ b/indra/newview/installers/windows/lang_tr.nsi @@ -0,0 +1,56 @@ +; First is default +!insertmacro MUI_LANGUAGE "Turkish" + +; Language string +LangString LanguageCode ${LANG_TURKISH} "tr" + +; Language selection dialog +LangString SelectInstallerLanguage ${LANG_TURKISH} "Lütfen yükleyicinin dilini seçin" + +; installation directory text +LangString DirectoryChooseTitle ${LANG_TURKISH} "Yükleme Dizini" +LangString DirectoryChooseUpdate ${LANG_TURKISH} "${VERSION_LONG}.(XXX) sürümüne güncelleştirme yapmak için ${APPNAME} dizinini seçin:" +LangString DirectoryChooseSetup ${LANG_TURKISH} "${APPNAME}'ın yükleneceği dizini seçin:" + +; CheckStartupParams message box +LangString CheckStartupParamsMB ${LANG_TURKISH} "'$INSTPROG' programı bulunamadı. Sessiz güncelleştirme başarılamadı." + +; check windows version +LangString CheckWindowsVersionDP ${LANG_TURKISH} "Windows sürümü kontrol ediliyor..." +LangString CheckWindowsVersionMB ${LANG_TURKISH} "${APPNAME} sadece Windows XP'i destekler.$\n$\nWindows $R0 üzerine yüklemeye çalışmak sistem çökmelerine ve veri kaybına neden olabilir.$\n$\n" +LangString CheckWindowsServPackMB ${LANG_TURKISH} "It is recomended to run ${APPNAME} on the latest service pack for your operating system.$\nThis will help with performance and stability of the program." +LangString UseLatestServPackDP ${LANG_TURKISH} "Please use Windows Update to install the latest Service Pack." + +; checkifadministrator function (install) +LangString CheckAdministratorInstDP ${LANG_TURKISH} "Yükleme izni kontrol ediliyor..." +LangString CheckAdministratorInstMB ${LANG_TURKISH} "'Sınırlı' bir hesap kullanıyor görünüyorsunuz.$\n${APPNAME}'ı yüklemek için bir 'yönetici' olmalısınız." + +; checkifadministrator function (uninstall) +LangString CheckAdministratorUnInstDP ${LANG_TURKISH} "Kaldırma izni kontrol ediliyor..." +LangString CheckAdministratorUnInstMB ${LANG_TURKISH} "'Sınırlı' bir hesap kullanıyor görünüyorsunuz.$\n${APPNAME}'ı kaldırmak için bir 'yönetici' olmalısınız." + +; checkifalreadycurrent +LangString CheckIfCurrentMB ${LANG_TURKISH} "${APPNAME} ${VERSION_LONG} zaten yüklü.$\n$\nTekrar yüklemek ister misiniz?" + +; checkcpuflags +LangString MissingSSE2 ${LANG_TURKISH} "Bu makinede SSE2 desteğine sahip bir CPU bulunmayabilir, ${APPNAME} ${VERSION_LONG} çalıştırmak için bu gereklidir. Devam etmek istiyor musunuz?" + +; closesecondlife function (install) +LangString CloseSecondLifeInstDP ${LANG_TURKISH} "${APPNAME}'ın kapatılması bekleniyor..." +LangString CloseSecondLifeInstMB ${LANG_TURKISH} "${APPNAME} zaten çalışırken kapatılamaz.$\n$\nYaptığınız işi bitirdikten sonra ${APPNAME}'ı kapatmak ve devam etmek için Tamam seçimini yapın.$\nYüklemeyi iptal etmek için İPTAL seçimini yapın." + +; closesecondlife function (uninstall) +LangString CloseSecondLifeUnInstDP ${LANG_TURKISH} "${APPNAME}'ın kapatılması bekleniyor..." +LangString CloseSecondLifeUnInstMB ${LANG_TURKISH} "${APPNAME} zaten çalışırken kaldırılamaz.$\n$\nYaptığınız işi bitirdikten sonra ${APPNAME}'ı kapatmak ve devam etmek için Tamam seçimini yapın.$\nİptal etmek için İPTAL seçimini yapın." + +; CheckNetworkConnection +LangString CheckNetworkConnectionDP ${LANG_TURKISH} "Ağ bağlantısı kontrol ediliyor..." + +; removecachefiles +LangString RemoveCacheFilesDP ${LANG_TURKISH} "Belgeler ve Ayarlar klasöründeki önbellek dosyaları siliniyor" + +; delete program files +LangString DeleteProgramFilesMB ${LANG_TURKISH} "${APPNAME} program dizininizde hala dosyalar var.$\n$\nBunlar muhtemelen sizin oluşturduğunuz veya şuraya taşıdığınız dosyalar:$\n$INSTDIR$\n$\nBunları kaldırmak istiyor musunuz?" + +; uninstall text +LangString UninstallTextMsg ${LANG_TURKISH} "Bu adımla ${APPNAME} ${VERSION_LONG} sisteminizden kaldırılacaktır." diff --git a/indra/newview/installers/windows/lang_zh.nsi b/indra/newview/installers/windows/lang_zh.nsi index d17e860df9..10b9303c6a 100644 Binary files a/indra/newview/installers/windows/lang_zh.nsi and b/indra/newview/installers/windows/lang_zh.nsi differ diff --git a/indra/newview/installers/windows/uninstall_icon.BMP b/indra/newview/installers/windows/uninstall_icon.BMP index 562b56676a..e7291fcc35 100644 Binary files a/indra/newview/installers/windows/uninstall_icon.BMP and b/indra/newview/installers/windows/uninstall_icon.BMP differ diff --git a/indra/newview/installers/windows/uninstall_icon.ico b/indra/newview/installers/windows/uninstall_icon.ico index c4ec6c70bd..290b1dc2b8 100644 Binary files a/indra/newview/installers/windows/uninstall_icon.ico and b/indra/newview/installers/windows/uninstall_icon.ico differ diff --git a/indra/newview/installers/windows/uninstall_icon_singularity.BMP b/indra/newview/installers/windows/uninstall_icon_singularity.BMP deleted file mode 100644 index e7291fcc35..0000000000 Binary files a/indra/newview/installers/windows/uninstall_icon_singularity.BMP and /dev/null differ diff --git a/indra/newview/installers/windows/uninstall_icon_singularity.ico b/indra/newview/installers/windows/uninstall_icon_singularity.ico deleted file mode 100644 index 290b1dc2b8..0000000000 Binary files a/indra/newview/installers/windows/uninstall_icon_singularity.ico and /dev/null differ diff --git a/indra/newview/installers/windows/uninstall_icon_snowglobe.BMP b/indra/newview/installers/windows/uninstall_icon_snowglobe.BMP deleted file mode 100644 index e7291fcc35..0000000000 Binary files a/indra/newview/installers/windows/uninstall_icon_snowglobe.BMP and /dev/null differ diff --git a/indra/newview/installers/windows/uninstall_icon_snowglobe.ico b/indra/newview/installers/windows/uninstall_icon_snowglobe.ico deleted file mode 100644 index 290b1dc2b8..0000000000 Binary files a/indra/newview/installers/windows/uninstall_icon_snowglobe.ico and /dev/null differ diff --git a/indra/newview/installers/windows/uninstall_welcome.bmp b/indra/newview/installers/windows/uninstall_welcome.bmp new file mode 100644 index 0000000000..097d094292 Binary files /dev/null and b/indra/newview/installers/windows/uninstall_welcome.bmp differ diff --git a/indra/newview/jcfloaterareasearch.cpp b/indra/newview/jcfloaterareasearch.cpp index 8b1ac9d770..ae970ebc33 100644 --- a/indra/newview/jcfloaterareasearch.cpp +++ b/indra/newview/jcfloaterareasearch.cpp @@ -41,6 +41,7 @@ #include "lluictrlfactory.h" #include "llagent.h" +#include "llagentcamera.h" #include "lltracker.h" #include "llviewerobjectlist.h" @@ -79,11 +80,21 @@ BOOL JCFloaterAreaSearch::postBuild() mResultList = getChild("result_list"); mResultList->setDoubleClickCallback(boost::bind(&JCFloaterAreaSearch::onDoubleClick,this)); mResultList->sortByColumn("Name", TRUE); + auto tp = getChild("TP"); + auto look = getChild("Look"); + mResultList->setCommitOnSelectionChange(true); + mResultList->setCommitCallback([=](LLUICtrl* ctrl, const LLSD& param){ + bool enabled = mResultList->getNumSelected() == 1; + tp->setEnabled(enabled); + look->setEnabled(enabled); + }); mCounterText = getChild("counter"); getChild("Refresh")->setClickedCallback(boost::bind(&JCFloaterAreaSearch::onRefresh,this)); getChild("Stop")->setClickedCallback(boost::bind(&JCFloaterAreaSearch::onStop,this)); + tp->setClickedCallback(boost::bind(&JCFloaterAreaSearch::teleportToSelected, this)); + look->setClickedCallback(boost::bind(&JCFloaterAreaSearch::lookAtSelected, this)); getChild("Name query chunk")->setCommitCallback(boost::bind(&JCFloaterAreaSearch::onCommitLine,this,_1,_2,LIST_OBJECT_NAME)); getChild("Description query chunk")->setCommitCallback(boost::bind(&JCFloaterAreaSearch::onCommitLine,this,_1,_2,LIST_OBJECT_DESC)); @@ -113,22 +124,32 @@ void JCFloaterAreaSearch::checkRegion(bool force_clear) } } +LLViewerObject* JCFloaterAreaSearch::getSelectedObject() +{ + if (LLScrollListItem* item = mResultList->getFirstSelected()) + return gObjectList.findObject(item->getUUID()); + return NULL; +} + void JCFloaterAreaSearch::onDoubleClick() { - LLScrollListItem *item = mResultList->getFirstSelected(); - if (!item) return; - LLUUID object_id = item->getUUID(); - std::map::iterator it = mCachedObjects.find(object_id); - if(it != mCachedObjects.end()) - { - LLViewerObject* objectp = gObjectList.findObject(object_id); - if (objectp) - { - LLTracker::trackLocation(objectp->getPositionGlobal(), it->second.name, "", LLTracker::LOCATION_ITEM); - } - } + if (LLViewerObject* objectp = getSelectedObject()) + LLTracker::trackLocation(objectp->getPositionGlobal(), mCachedObjects[objectp->getID()].name, "", LLTracker::LOCATION_ITEM); } +void JCFloaterAreaSearch::teleportToSelected() +{ + if (LLViewerObject* objectp = getSelectedObject()) + gAgent.teleportViaLocation(objectp->getPositionGlobal()); +} + +void JCFloaterAreaSearch::lookAtSelected() +{ + if (LLScrollListItem* item = mResultList->getFirstSelected()) + gAgentCamera.lookAtObject(item->getUUID(), false); +} + + void JCFloaterAreaSearch::onStop() { mStopped = true; @@ -138,7 +159,7 @@ void JCFloaterAreaSearch::onStop() void JCFloaterAreaSearch::onRefresh() { - //llinfos << "Clicked search" << llendl; + //LL_INFOS() << "Clicked search" << LL_ENDL; mStopped = false; checkRegion(true); results(); @@ -150,7 +171,7 @@ void JCFloaterAreaSearch::onCommitLine(LLUICtrl* caller, const LLSD& value, OBJE LLStringUtil::toLower(text); caller->setValue(text); mFilterStrings[type] = text; - //llinfos << "loaded " << name << " with "<< text << llendl; + //LL_INFOS() << "loaded " << name << " with "<< text << LL_ENDL; checkRegion(); results(); } @@ -162,7 +183,7 @@ bool JCFloaterAreaSearch::requestIfNeeded(LLUUID object_id) if(mStopped) return true; - //llinfos << "not in list" << llendl; + //LL_INFOS() << "not in list" << LL_ENDL; mPendingObjects.insert(object_id); LLMessageSystem* msg = gMessageSystem; @@ -174,7 +195,7 @@ bool JCFloaterAreaSearch::requestIfNeeded(LLUUID object_id) msg->addU32Fast(_PREHASH_RequestFlags, 0 ); msg->addUUIDFast(_PREHASH_ObjectID, object_id); gAgent.sendReliableMessage(); - //llinfos << "Sent data request for object " << object_id << llendl; + //LL_INFOS() << "Sent data request for object " << object_id << LL_ENDL; return true; } return false; @@ -185,7 +206,7 @@ void JCFloaterAreaSearch::results() if (!getVisible()) return; if (mPendingObjects.size() > 0 && mLastUpdateTimer.getElapsedTimeF32() < min_refresh_interval) return; - //llinfos << "results()" << llendl; + //LL_INFOS() << "results()" << LL_ENDL; uuid_vec_t selected = mResultList->getSelectedIDs(); S32 scrollpos = mResultList->getScrollPos(); mResultList->deleteAllItems(); @@ -204,29 +225,29 @@ void JCFloaterAreaSearch::results() LLUUID object_id = objectp->getID(); if(!requestIfNeeded(object_id)) { - std::map::iterator it = mCachedObjects.find(object_id); + auto it = mCachedObjects.find(object_id); if(it != mCachedObjects.end()) { - //llinfos << "all entries are \"\" or we have data" << llendl; + //LL_INFOS() << "all entries are \"\" or we have data" << LL_ENDL; std::string object_name = it->second.name; std::string object_desc = it->second.desc; std::string object_owner; std::string object_group; gCacheName->getFullName(it->second.owner_id, object_owner); gCacheName->getGroupName(it->second.group_id, object_group); - //llinfos << "both names are loaded or aren't needed" << llendl; + //LL_INFOS() << "both names are loaded or aren't needed" << LL_ENDL; std::string onU = object_owner; std::string cnU = object_group; LLStringUtil::toLower(object_name); LLStringUtil::toLower(object_desc); LLStringUtil::toLower(object_owner); LLStringUtil::toLower(object_group); - if ((mFilterStrings[LIST_OBJECT_NAME].empty() || object_name.find(mFilterStrings[LIST_OBJECT_NAME]) != -1) && - (mFilterStrings[LIST_OBJECT_DESC].empty() || object_desc.find(mFilterStrings[LIST_OBJECT_DESC]) != -1) && - (mFilterStrings[LIST_OBJECT_OWNER].empty() || object_owner.find(mFilterStrings[LIST_OBJECT_OWNER]) != -1) && - (mFilterStrings[LIST_OBJECT_GROUP].empty() || object_group.find(mFilterStrings[LIST_OBJECT_GROUP]) != -1)) + if ((mFilterStrings[LIST_OBJECT_NAME].empty() || object_name.find(mFilterStrings[LIST_OBJECT_NAME]) != std::string::npos) && + (mFilterStrings[LIST_OBJECT_DESC].empty() || object_desc.find(mFilterStrings[LIST_OBJECT_DESC]) != std::string::npos) && + (mFilterStrings[LIST_OBJECT_OWNER].empty() || object_owner.find(mFilterStrings[LIST_OBJECT_OWNER]) != std::string::npos) && + (mFilterStrings[LIST_OBJECT_GROUP].empty() || object_group.find(mFilterStrings[LIST_OBJECT_GROUP]) != std::string::npos)) { - //llinfos << "pass" << llendl; + //LL_INFOS() << "pass" << LL_ENDL; LLSD element; element["id"] = object_id; element["columns"][LIST_OBJECT_NAME]["column"] = "Name"; @@ -268,7 +289,7 @@ void JCFloaterAreaSearch::processObjectPropertiesFamily(LLMessageSystem* msg, vo LLUUID object_id; msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_ObjectID, object_id); - std::set::iterator it = floater->mPendingObjects.find(object_id); + auto it = floater->mPendingObjects.find(object_id); if(it != floater->mPendingObjects.end()) floater->mPendingObjects.erase(it); //else if(floater->mCachedObjects.count(object_id)) //Let entries update. @@ -278,10 +299,11 @@ void JCFloaterAreaSearch::processObjectPropertiesFamily(LLMessageSystem* msg, vo // We cache unknown objects (to avoid having to request them later) // and requested objects. msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_OwnerID, data->owner_id); + if (auto obj = gObjectList.findObject(object_id)) obj->mOwnerID = data->owner_id; // Singu Note: Try to get Owner whenever possible msg->getUUIDFast(_PREHASH_ObjectData, _PREHASH_GroupID, data->group_id); msg->getStringFast(_PREHASH_ObjectData, _PREHASH_Name, data->name); msg->getStringFast(_PREHASH_ObjectData, _PREHASH_Description, data->desc); gCacheName->get(data->owner_id, false, boost::bind(&JCFloaterAreaSearch::results,floater)); gCacheName->get(data->group_id, true, boost::bind(&JCFloaterAreaSearch::results,floater)); - //llinfos << "Got info for " << (exists ? "requested" : "unknown") << " object " << object_id << llendl; + //LL_INFOS() << "Got info for " << (exists ? "requested" : "unknown") << " object " << object_id << LL_ENDL; } diff --git a/indra/newview/jcfloaterareasearch.h b/indra/newview/jcfloaterareasearch.h index abf2bd592f..033dc22ad4 100644 --- a/indra/newview/jcfloaterareasearch.h +++ b/indra/newview/jcfloaterareasearch.h @@ -31,10 +31,14 @@ * Modified, debugged, optimized and improved by Henri Beauchamp Feb 2010. */ +#ifndef JC_FLOATERAREASEARCH_H +#define JC_FLOATERAREASEARCH_H + #include "llfloater.h" #include "lluuid.h" #include "llstring.h" #include "llframetimer.h" +#include class LLTextBox; class LLScrollListCtrl; @@ -52,6 +56,20 @@ class JCFloaterAreaSearch : public LLFloater, public LLFloaterSingletonsecond : nullptr; + } private: @@ -69,7 +87,10 @@ class JCFloaterAreaSearch : public LLFloater, public LLFloaterSingleton mPendingObjects; - std::map mCachedObjects; + uuid_set_t mPendingObjects; + boost::unordered_map mCachedObjects; std::string mFilterStrings[LIST_OBJECT_COUNT]; }; + +#endif diff --git a/indra/newview/lffloaterinvpanel.cpp b/indra/newview/lffloaterinvpanel.cpp index 0132579d20..b687100a0e 100644 --- a/indra/newview/lffloaterinvpanel.cpp +++ b/indra/newview/lffloaterinvpanel.cpp @@ -22,60 +22,87 @@ #include "lffloaterinvpanel.h" +#include + #include "llinventorypanel.h" #include "lluictrlfactory.h" -LFFloaterInvPanel::LFFloaterInvPanel(const LLUUID& cat_id, LLInventoryModel* model, const std::string& name) -: LLInstanceTracker(cat_id) +LFFloaterInvPanel::LFFloaterInvPanel(const LLSD& cat, const std::string& name, LLInventoryModel* model) +: LLInstanceTracker(cat) { - mCommitCallbackRegistrar.add("InvPanel.Search", boost::bind(&LFFloaterInvPanel::onSearch, this, _2)); + // Setup the floater first + auto mPanel = new LLInventoryPanel("inv_panel", LLInventoryPanel::DEFAULT_SORT_ORDER, cat, LLRect(), model ? model : &gInventory, true); + + // Load from XUI + mCommitCallbackRegistrar.add("InvPanel.Search", boost::bind(&LLInventoryPanel::setFilterSubString, mPanel, _2)); LLUICtrlFactory::getInstance()->buildFloater(this, "floater_inv_panel.xml"); + + // Now set the title + const auto& title = name.empty() ? gInventory.getCategory(mPanel->getRootFolderID())->getName() : name; + setTitle(title); + + // Figure out a unique name for our rect control + const auto rect_control = llformat("FloaterInv%sRect", boost::algorithm::erase_all_copy(title, " ").data()); + if (!gSavedSettings.controlExists(rect_control)) // If we haven't existed before, create it + { + S32 left, top; + gFloaterView->getNewFloaterPosition(&left, &top); + LLRect rect = getRect(); + rect.translate(left - rect.mLeft, top - rect.mTop); + gSavedSettings.declareRect(rect_control, rect, "Rectangle for " + title + " window"); + } + setRectControl(rect_control); + applyRectControl(); // Set our initial rect to the stored (or just created) control + + // Now take care of the children LLPanel* panel = getChild("placeholder_panel"); - mPanel = new LLInventoryPanel("inv_panel", LLInventoryPanel::DEFAULT_SORT_ORDER, cat_id.asString(), panel->getRect(), model, true); + mPanel->setRect(panel->getRect()); + mPanel->setOrigin(0, 0); mPanel->postBuild(); mPanel->setFollows(FOLLOWS_ALL); mPanel->setEnabled(true); - addChild(mPanel); - removeChild(panel); - setTitle(name); -} - -LFFloaterInvPanel::~LFFloaterInvPanel() -{ - delete mPanel; + mPanel->removeBorder(); + panel->addChild(mPanel); } // static -void LFFloaterInvPanel::show(const LLUUID& cat_id, LLInventoryModel* model, const std::string& name) +void LFFloaterInvPanel::show(const LLSD& cat, const std::string& name, LLInventoryModel* model) { - LFFloaterInvPanel* floater = LFFloaterInvPanel::getInstance(cat_id); - if (!floater) floater = new LFFloaterInvPanel(cat_id, model, name); + LFFloaterInvPanel* floater = LFFloaterInvPanel::getInstance(cat); + if (!floater) floater = new LFFloaterInvPanel(cat, name, model); floater->open(); } // static void LFFloaterInvPanel::closeAll() { - for (instance_iter i = endInstances(); i >= beginInstances(); --i) - i->close(); + // We must make a copy first, because LLInstanceTracker doesn't allow destruction while having iterators to it. + std::vector cache; + for (instance_iter i = beginInstances(), end(endInstances()); i != end; ++i) + { + cache.push_back(&*i); + } + // Now close all, without using instance_iter iterators. + for (auto& floater : cache) + { + floater->close(); + } } -// virtual BOOL LFFloaterInvPanel::handleKeyHere(KEY key, MASK mask) { - if (!mPanel->hasFocus() && mask == MASK_NONE && (key == KEY_RETURN || key == KEY_DOWN)) + if (mask == MASK_NONE && (key == KEY_RETURN || key == KEY_DOWN)) { - mPanel->setFocus(true); - if (LLFolderView* root = mPanel->getRootFolder()) - root->scrollToShowSelection(); - return true; + auto& mPanel = *getChild("inv_panel"); + if (!mPanel.hasFocus()) + { + mPanel.setFocus(true); + if (LLFolderView* root = mPanel.getRootFolder()) + root->scrollToShowSelection(); + return true; + } } return LLFloater::handleKeyHere(key, mask); } - -void LFFloaterInvPanel::onSearch(const LLSD& val) -{ - mPanel->setFilterSubString(val.asString()); -} diff --git a/indra/newview/lffloaterinvpanel.h b/indra/newview/lffloaterinvpanel.h index 24ae089fd6..c65763cdd2 100644 --- a/indra/newview/lffloaterinvpanel.h +++ b/indra/newview/lffloaterinvpanel.h @@ -18,27 +18,27 @@ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA */ -#ifndef LFFLOATERINVPANEL_H -#define LFFLOATERINVPANEL_H +#pragma once #include "llfloater.h" #include "llinstancetracker.h" +#include "llsdutil.h" -class LFFloaterInvPanel : public LLFloater, public LLInstanceTracker +class LFFloaterInvPanel final : public LLFloater, public LLInstanceTracker { - LFFloaterInvPanel(const LLUUID& cat_id, class LLInventoryModel* model, const std::string& name); - ~LFFloaterInvPanel(); + LFFloaterInvPanel(const LLSD& cat, const std::string& name = LLStringUtil::null, class LLInventoryModel* model = nullptr); public: - static void show(const LLUUID& cat_id, LLInventoryModel* model, const std::string& name); // Show the floater for cat_id (create with other params if necessary) + static void show(const LLSD& cat, const std::string& name = LLStringUtil::null, LLInventoryModel* model = nullptr); // Show the floater for cat (create with other params if necessary) + static void toggle(const LLSD& cat) + { + if (auto instance = getInstance(cat)) + instance->close(); + else + show(cat); + } static void closeAll(); // Called when not allowed to have inventory open - /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask); - void onSearch(const LLSD& val); - -private: - class LLInventoryPanel* mPanel; + BOOL handleKeyHere(KEY key, MASK mask) override; }; - -#endif //LFFLOATERINVPANEL_H diff --git a/indra/newview/lfsimfeaturehandler.cpp b/indra/newview/lfsimfeaturehandler.cpp index 481856e95d..e9fa957b0d 100644 --- a/indra/newview/lfsimfeaturehandler.cpp +++ b/indra/newview/lfsimfeaturehandler.cpp @@ -20,15 +20,21 @@ #include "lfsimfeaturehandler.h" #include "llagent.h" -#include "llenvmanager.h" #include "llviewerregion.h" +#include "llmutelist.h" #include "hippogridmanager.h" LFSimFeatureHandler::LFSimFeatureHandler() : mSupportsExport(false) +, mDestinationGuideURL(gSavedSettings.getString("DestinationGuideURL")) +, mSearchURL(gSavedSettings.getString("SearchURL")) +, mSayRange(20) +, mShoutRange(100) +, mWhisperRange(10) { if (!gHippoGridManager->getCurrentGrid()->isSecondLife()) // Remove this line if we ever handle SecondLife sim features - LLEnvManagerNew::instance().setRegionChangeCallback(boost::bind(&LFSimFeatureHandler::handleRegionChange, this)); + gAgent.addRegionChangedCallback(boost::bind(&LFSimFeatureHandler::handleRegionChange, this)); + LLMuteList::instance().mGodLastNames = { "Linden", "ProductEngine" }; } ExportPolicy LFSimFeatureHandler::exportPolicy() const @@ -40,47 +46,99 @@ void LFSimFeatureHandler::handleRegionChange() { if (LLViewerRegion* region = gAgent.getRegion()) { - if (region->getFeaturesReceived()) + if (region->simulatorFeaturesReceived()) { setSupportedFeatures(); } else { - region->setFeaturesReceivedCallback(boost::bind(&LFSimFeatureHandler::setSupportedFeatures, this)); + region->setSimulatorFeaturesReceivedCallback(boost::bind(&LFSimFeatureHandler::setSupportedFeatures, this)); } } } +template +void has_feature_or_default(SignaledType& type, const LLSD& features, const std::string& feature) +{ + type = (features.has(feature)) ? static_cast(features[feature]) : type.getDefault(); +} +template<> +void has_feature_or_default(SignaledType& type, const LLSD& features, const std::string& feature) +{ + type = (features.has(feature)) ? features[feature].asInteger() : type.getDefault(); +} + void LFSimFeatureHandler::setSupportedFeatures() { if (LLViewerRegion* region = gAgent.getRegion()) { LLSD info; region->getSimulatorFeatures(info); + //bool hg(); // Singu Note: There should probably be a flag for this some day. if (info.has("OpenSimExtras")) // OpenSim specific sim features { // For definition of OpenSimExtras please see // http://opensimulator.org/wiki/SimulatorFeatures_Extras - mSupportsExport = info["OpenSimExtras"].has("ExportSupported") ? info["OpenSimExtras"]["ExportSupported"].asBoolean() : false; - mMapServerURL = info["OpenSimExtras"].has("map-server-url") ? info["OpenSimExtras"]["map-server-url"].asString() : ""; - mSearchURL = info["OpenSimExtras"].has("search-server-url") ? info["OpenSimExtras"]["search-server-url"].asString() : ""; + const LLSD& extras(info["OpenSimExtras"]); + has_feature_or_default(mSupportsExport, extras, "ExportSupported"); + //if (hg) + { + has_feature_or_default(mDestinationGuideURL, extras, "destination-guide-url"); + mMapServerURL = extras.has("map-server-url") ? extras["map-server-url"].asString() : LLStringUtil::null; + has_feature_or_default(mSearchURL, extras, "search-server-url"); + if (extras.has("GridName")) + { + const std::string& grid_name(extras["GridName"]); + mGridName = gHippoGridManager->getConnectedGrid()->getGridName() != grid_name ? grid_name : LLStringUtil::null; + } + } + has_feature_or_default(mEventsURL, extras, "EventsURL"); + has_feature_or_default(mSayRange, extras, "say-range"); + has_feature_or_default(mShoutRange, extras, "shout-range"); + has_feature_or_default(mWhisperRange, extras, "whisper-range"); } else // OpenSim specifics are unsupported reset all to default { - mSupportsExport = false; - mMapServerURL = ""; - mSearchURL = ""; + mSupportsExport.reset(); + //if (hg) + { + mDestinationGuideURL.reset(); + mMapServerURL = LLStringUtil::null; + mSearchURL.reset(); + mGridName.reset(); + mEventsURL.reset(); + } + mSayRange.reset(); + mShoutRange.reset(); + mWhisperRange.reset(); } - } -} -boost::signals2::connection LFSimFeatureHandler::setSupportsExportCallback(const boost::signals2::signal::slot_type& slot) -{ - return mSupportsExport.connect(slot); -} + LLMuteList& mute_list(LLMuteList::instance()); + mute_list.mGodLastNames.clear(); + mute_list.mGodFullNames.clear(); -boost::signals2::connection LFSimFeatureHandler::setSearchURLCallback(const boost::signals2::signal::slot_type& slot) -{ - return mSearchURL.connect(slot); -} + if (info.has("god_names")) + { + const LLSD& god_names(info["god_names"]); + if (god_names.has("last_names")) + { + const LLSD& last_names(god_names["last_names"]); + + for (LLSD::array_const_iterator it = last_names.beginArray(); it != last_names.endArray(); ++it) + mute_list.mGodLastNames.insert((*it).asString()); + } + if (god_names.has("full_names")) + { + const LLSD& full_names(god_names["full_names"]); + + for (LLSD::array_const_iterator it = full_names.beginArray(); it != full_names.endArray(); ++it) + mute_list.mGodFullNames.insert((*it).asString()); + } + } + else + { + mute_list.mGodLastNames = { "Linden", "ProductEngine" }; + } + } +} diff --git a/indra/newview/lfsimfeaturehandler.h b/indra/newview/lfsimfeaturehandler.h index 8a8c496405..9b7554e32f 100644 --- a/indra/newview/lfsimfeaturehandler.h +++ b/indra/newview/lfsimfeaturehandler.h @@ -21,29 +21,34 @@ #include "llsingleton.h" #include "llpermissions.h" // ExportPolicy -template > +template > class SignaledType { public: - SignaledType() : mValue() {} - SignaledType(Type b) : mValue(b) {} + SignaledType() : mValue(), mDefaultValue() {} + SignaledType(Type b) : mValue(b), mDefaultValue(b) {} - boost::signals2::connection connect(const typename Signal::slot_type& slot) { return mSignal.connect(slot); } + typedef typename Signal::slot_type slot_t; + boost::signals2::connection connect(const slot_t& slot) { return mSignal.connect(slot); } SignaledType& operator =(Type val) { if (val != mValue) { mValue = val; - mSignal(); + mSignal(val); } return *this; } operator Type() const { return mValue; } + const Type& ref() const { return mValue; } + void reset() { *this = mDefaultValue; } + const Type& getDefault() const { return mDefaultValue; } private: Signal mSignal; Type mValue; + const Type mDefaultValue; }; class LFSimFeatureHandler : public LLSingleton @@ -57,20 +62,37 @@ class LFSimFeatureHandler : public LLSingleton void setSupportedFeatures(); // Connection setters - boost::signals2::connection setSupportsExportCallback(const boost::signals2::signal::slot_type& slot); - boost::signals2::connection setSearchURLCallback(const boost::signals2::signal::slot_type& slot); + boost::signals2::connection setSupportsExportCallback(const SignaledType::slot_t& slot) { return mSupportsExport.connect(slot); } + boost::signals2::connection setDestinationGuideURLCallback(const SignaledType::slot_t& slot) { return mDestinationGuideURL.connect(slot); } + boost::signals2::connection setSearchURLCallback(const SignaledType::slot_t& slot) { return mSearchURL.connect(slot); } + boost::signals2::connection setEventsURLCallback(const SignaledType::slot_t& slot) { return mEventsURL.connect(slot); } + boost::signals2::connection setSayRangeCallback(const SignaledType::slot_t& slot) { return mSayRange.connect(slot); } + boost::signals2::connection setShoutRangeCallback(const SignaledType::slot_t& slot) { return mShoutRange.connect(slot); } + boost::signals2::connection setWhisperRangeCallback(const SignaledType::slot_t& slot) { return mWhisperRange.connect(slot); } // Accessors bool simSupportsExport() const { return mSupportsExport; } + std::string destinationGuideURL() const { return mDestinationGuideURL; } std::string mapServerURL() const { return mMapServerURL; } std::string searchURL() const { return mSearchURL; } + const std::string& getEventsURL() const { return mEventsURL.ref(); } + const std::string& gridName() const { return mGridName.ref(); } + U32 sayRange() const { return mSayRange; } + U32 shoutRange() const { return mShoutRange; } + U32 whisperRange() const { return mWhisperRange; } ExportPolicy exportPolicy() const; private: // SignaledTypes SignaledType mSupportsExport; + SignaledType mDestinationGuideURL; std::string mMapServerURL; SignaledType mSearchURL; + SignaledType mGridName; + SignaledType mEventsURL; + SignaledType mSayRange; + SignaledType mShoutRange; + SignaledType mWhisperRange; }; #endif //LFSIMFEATUREHANDLER_H diff --git a/indra/newview/lggdicdownload.cpp b/indra/newview/lggdicdownload.cpp index 8207ed0bc9..0028861bab 100644 --- a/indra/newview/lggdicdownload.cpp +++ b/indra/newview/lggdicdownload.cpp @@ -58,8 +58,6 @@ class EmeraldDicDownloader : public LLHTTPClient::ResponderWithCompleted EmeraldDicDownloader(lggDicDownloadFloater* spanel, std::string sname); ~EmeraldDicDownloader() { } /*virtual*/ void completedRaw( - U32 status, - const std::string& reason, const LLChannelDescriptors& channels, const buffer_ptr_t& buffer); /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return emeraldDicDownloader_timeout; } @@ -167,9 +165,9 @@ EmeraldDicDownloader::EmeraldDicDownloader(lggDicDownloadFloater* spanel, std::s } -void EmeraldDicDownloader::completedRaw(U32 status, const std::string& reason, const LLChannelDescriptors& channels, const buffer_ptr_t& buffer) +void EmeraldDicDownloader::completedRaw(LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) { - if (status < 200 || status >= 300) + if (!isGoodStatus(mStatus)) { return; } @@ -191,7 +189,7 @@ void EmeraldDicDownloader::completedRaw(U32 status, const std::string& reason, c } else { - llinfos << "completedRaw(): No empanel to refresh()!" << llendl; + LL_INFOS() << "completedRaw(): No empanel to refresh()!" << LL_ENDL; } panel->close(); diff --git a/indra/newview/lggdicdownload.h b/indra/newview/lggdicdownload.h index 75f3053e95..d9edb8deb8 100644 --- a/indra/newview/lggdicdownload.h +++ b/indra/newview/lggdicdownload.h @@ -28,6 +28,8 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ +#ifndef LGG_DICDOWNLOAD_H +#define LGG_DICDOWNLOAD_H class LggDicDownload { @@ -35,3 +37,4 @@ class LggDicDownload static void show( BOOL showw , std::vector shortNames, std::vector longNames, void * data); }; +#endif \ No newline at end of file diff --git a/indra/newview/lgghunspell_wrapper.cpp b/indra/newview/lgghunspell_wrapper.cpp index 8c4f3c8022..d19e91485a 100644 --- a/indra/newview/lgghunspell_wrapper.cpp +++ b/indra/newview/lgghunspell_wrapper.cpp @@ -502,7 +502,7 @@ std::string lggHunSpell_Wrapper::getCorrectPath(std::string file) void lggHunSpell_Wrapper::setNewDictionary(std::string newDict) { - llinfos << "Setting new base dictionary long name is-> " << newDict.c_str() << llendl; + LL_INFOS() << "Setting new base dictionary long name is-> " << newDict.c_str() << LL_ENDL; currentBaseDic = newDict; @@ -517,10 +517,10 @@ void lggHunSpell_Wrapper::setNewDictionary(std::string newDict) std::string dicaffpath = getCorrectPath(newDict+".aff"); std::string dicdicpath = getCorrectPath(newDict+".dic"); - llinfos << "Setting new base dictionary -> " << dicaffpath.c_str() << llendl; + LL_INFOS() << "Setting new base dictionary -> " << dicaffpath.c_str() << LL_ENDL; myHunspell = new Hunspell(dicaffpath.c_str(), dicdicpath.c_str()); - llinfos << "Adding custom dictionary " << llendl; + LL_INFOS() << "Adding custom dictionary " << LL_ENDL; createCustomDic(); addDictionary("custom"); std::vector toInstall = getInstalledDicts(); @@ -614,23 +614,23 @@ std::vector lggHunSpell_Wrapper::getSuggestionList(std::string badW void lggHunSpell_Wrapper::debugTest(std::string testWord) { - llinfos << "Testing to see if " << testWord.c_str() << " is spelled correct" << llendl; + LL_INFOS() << "Testing to see if " << testWord.c_str() << " is spelled correct" << LL_ENDL; if (isSpelledRight(testWord)) { - llinfos << testWord.c_str() << " is spelled correctly" << llendl; + LL_INFOS() << testWord.c_str() << " is spelled correctly" << LL_ENDL; } else { - llinfos << testWord.c_str() << " is not spelled correctly, getting suggestions" << llendl; + LL_INFOS() << testWord.c_str() << " is not spelled correctly, getting suggestions" << LL_ENDL; std::vector suggList; suggList.clear(); suggList = getSuggestionList(testWord); - llinfos << "Got suggestions.. " << llendl; + LL_INFOS() << "Got suggestions.. " << LL_ENDL; for (int i = 0; i < (int)suggList.size(); i++) { - llinfos << "Suggestion for " << testWord.c_str() << ":" << suggList[i].c_str() << llendl; + LL_INFOS() << "Suggestion for " << testWord.c_str() << ":" << suggList[i].c_str() << LL_ENDL; } } } @@ -659,7 +659,7 @@ void lggHunSpell_Wrapper::addDictionary(std::string additionalDictionary) std::string dicpath = getCorrectPath(fullName2DictName(additionalDictionary)+".dic"); if (gDirUtilp->fileExists(dicpath)) { - llinfos << "Adding additional dictionary -> " << dicpath.c_str() << llendl; + LL_INFOS() << "Adding additional dictionary -> " << dicpath.c_str() << LL_ENDL; myHunspell->add_dic(dicpath.c_str()); } } @@ -709,7 +709,7 @@ std::string lggHunSpell_Wrapper::dictName2FullName(std::string dictName) { for (int i =0; iaddWordToCustomDictionary("temp"); } - gViewerWindow->getWindow()->ShellEx(dicdicpath); + LLWindow::ShellEx(dicdicpath); } void lggHunSpell_Wrapper::setSpellCheckHighlight(BOOL highlight) diff --git a/indra/newview/lgghunspell_wrapper.h b/indra/newview/lgghunspell_wrapper.h index 51c1f37a71..df55ece365 100644 --- a/indra/newview/lgghunspell_wrapper.h +++ b/indra/newview/lgghunspell_wrapper.h @@ -19,9 +19,14 @@ #define ASPELL_WRAPPER 1 #if LL_WINDOWS -#include "hunspell/hunspelldll.h" +#pragma push_macro("near") +#ifdef near +#undef near +#endif +#include +#pragma pop_macro("near") #else -#include "hunspell/hunspell.hxx" +#include #endif class lggHunSpell_Wrapper diff --git a/indra/newview/linux_tools/client-readme-joystick.txt b/indra/newview/linux_tools/client-readme-joystick.txt index 997a8b08eb..4f89a73ccb 100644 --- a/indra/newview/linux_tools/client-readme-joystick.txt +++ b/indra/newview/linux_tools/client-readme-joystick.txt @@ -41,7 +41,7 @@ applications such as the Second Life Viewer, as follows: * Ubuntu or Gentoo Linux Configuration: For a quick start, you can simply paste the following line into a terminal before plugging in your SpaceNavigator - this only needs to be done once: - sudo bash -c 'echo KERNEL==\"event[0-9]*\", SYSFS{idVendor}==\"046d\", SYSFS{idProduct}==\"c626\", SYMLINK+=\"input/spacenavigator\", GROUP=\"plugdev\", MODE=\"664\" >> /etc/udev/rules.d/91-spacenavigator.rules' + sudo bash -c 'echo KERNEL==\"event[0-9]*\", SYSFS{idVendor}==\"046d\", SYSFS{idProduct}==\"c626\", SYMLINK+=\"input/spacenavigator\", GROUP=\"plugdev\", MODE=\"664\" > /etc/udev/rules.d/91-spacenavigator-LL.rules ; echo "" > /etc/hal/fdi/policy/3Dconnexion_SpaceNavigator_LL.fdi' For more comprehensive Linux SpaceNavigator configuration information please see the section 'Installing SpaceNavigator without the official driver' here: diff --git a/indra/newview/linux_tools/client-readme-voice.txt b/indra/newview/linux_tools/client-readme-voice.txt index aa04a57045..53f1ac5b5d 100644 --- a/indra/newview/linux_tools/client-readme-voice.txt +++ b/indra/newview/linux_tools/client-readme-voice.txt @@ -11,9 +11,9 @@ groups inside Second Life, with an appropriate headset/microphone. Linux Voice Support is currently EXPERIMENTAL and is known to still have some compatibility issues. -SINGULARITY MULTI-VOICE +MULTI-VOICE -=-=-=-=-=-=-=-=-=-=-=- -Singularity multi-voice is an experimental feature that allows you to run multiple +Multi-voice is an experimental feature that allows you to run multiple SLVoice daemons at the same time, in order to do this, the debug setting VoiceMultiInstance must be TRUE, this allows multiple instances of the viewer to run concurrently and each connect to voice. @@ -22,18 +22,10 @@ REQUIREMENTS -=-=-=-=-=-= * A headset/microphone supported by your chosen version of Linux -* The ALSA sound system (you probably already have this - - i.e. the alsa-base and alsa-utils packages on Ubuntu) - -Success with Linux Voice support has been reported on the following -systems: -* Ubuntu 6.06 (Dapper) with Intel ICH5/CMI9761A+ audio chipset -* Ubuntu 6.06 (Dapper) with SigmaTel STAC2997 audio chipset -* Ubuntu 6.06 (Dapper) with Creative EMU10K1 audio chipset -* Ubuntu 7.04 (Feisty) with USB Plantronics headset -* Ubuntu 7.04 (Feisty) with Intel HDA audio chipset -* Fedora Core 6 with (unknown) audio chipset -* Ubuntu 8.04 (Hardy) with (unknown) audio chipset +* At this time, the PulseAudio audio system is recommended; this software + is already part of most modern (2009+) Linux desktop systems. Alternatively, + the ALSA audio system may be used on systems installed from around + 2007 onwards (again this is likely already installed on your system). TESTING YOUR SETTINGS -=-=-=-=-=-=-=-=-=-=- @@ -45,8 +37,8 @@ when you speak. KNOWN PROBLEMS -=-=-=-=-=-=-= -* The 'Input Level' meter in the Voice Chat Device Settings dialog - does not respond to audio input. +* Compatibility with old ALSA-based audio systems (such as Ubuntu Dapper + from 2006) is poor. TROUBLESHOOTING -=-=-=-=-=-=-=- diff --git a/indra/newview/linux_tools/client-readme.txt b/indra/newview/linux_tools/client-readme.txt index f9f60c8338..656c7dc97c 100644 --- a/indra/newview/linux_tools/client-readme.txt +++ b/indra/newview/linux_tools/client-readme.txt @@ -55,10 +55,13 @@ Minimum requirements: is required. If you are running a 64-bit Linux distribution then you will need its 32-bit compatibility environment installed, but this configuration is not currently supported. + * PulseAudio or ALSA Linux system sound software. A recent PulseAudio + is the recommended configuration; see README-linux-voice.txt for more + information. * Video/Graphics Card: o nVidia GeForce 2, GeForce 4mx, or better (recommend one of the following: 6700, 6800, 7600, 7800, 7900, 8400, 8500, 8600, - 8800, Go 7400, Go 7600, Go 7800, Go 7900) + 8800, Go 7400, Go 7600, Go 7800, Go 7900, +) o OR ATI Radeon 8500, 9250, or better (nVidia cards are recommended for the Linux client) @@ -97,10 +100,7 @@ you wish. 4. KNOWN ISSUES -=-=-=-=-=-=-=- -* UPDATING - when the client detects that a new version of Second Life - is available, it will ask you if you wish to download the new version. - This option is not implemented; to upgrade, you should manually download a - new version from the Second Life web site, . +* No significant known issues at this time. 5. TROUBLESHOOTING diff --git a/indra/newview/linux_tools/handle_secondlifeprotocol.sh b/indra/newview/linux_tools/handle_secondlifeprotocol.sh deleted file mode 100755 index 4ff3e26370..0000000000 --- a/indra/newview/linux_tools/handle_secondlifeprotocol.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash - -# Send a URL of the form secondlife://... to Second Life. -# - -URL="$1" - -if [ -z "$URL" ]; then - echo Usage: $0 secondlife://... - exit -fi - -RUN_PATH=`dirname "$0" || echo .` -cd "${RUN_PATH}" - -exec ./singularity -url \'"${URL}"\' - diff --git a/indra/newview/linux_tools/handle_secondlifeprotocol.sh.in b/indra/newview/linux_tools/handle_secondlifeprotocol.sh.in new file mode 100755 index 0000000000..078cee2ed3 --- /dev/null +++ b/indra/newview/linux_tools/handle_secondlifeprotocol.sh.in @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +# Send a URL of the form secondlife://... to Second Life. +# + +URL="$1" + +if [ -z "$URL" ]; then + echo Usage: $0 secondlife://... + exit +fi + +RUN_PATH=`dirname "$0" || echo .` +cd "${RUN_PATH}/.." + +exec ./@VIEWER_BRANDING_ID@ -url \'"${URL}"\' + diff --git a/indra/newview/linux_tools/install.sh b/indra/newview/linux_tools/install.sh deleted file mode 100644 index 86d0206713..0000000000 --- a/indra/newview/linux_tools/install.sh +++ /dev/null @@ -1,106 +0,0 @@ -#!/bin/bash - -# Install Singularity Viewer. This script can install the viewer both -# system-wide and for an individual user. - -VT102_STYLE_NORMAL='\E[0m' -VT102_COLOR_RED='\E[31m' - -SCRIPTSRC=`readlink -f "$0" || echo "$0"` -RUN_PATH=`dirname "${SCRIPTSRC}" || echo .` -tarball_path=${RUN_PATH} - -function prompt() -{ - local prompt=$1 - local input - - echo -n "$prompt" - - while read input; do - case $input in - [Yy]* ) - return 1 - ;; - [Nn]* ) - return 0 - ;; - * ) - echo "Please enter yes or no." - echo -n "$prompt" - esac - done -} - -function die() -{ - warn $1 - exit 1 -} - -function warn() -{ - echo -n -e $VT102_COLOR_RED - echo $1 - echo -n -e $VT102_STYLE_NORMAL -} - -function homedir_install() -{ - warn "You are not running as a privileged user, so you will only be able" - warn "to install Singularity Viewer in your home directory. If you" - warn "would like to install Singularity Viewer system-wide, please run" - warn "this script as the root user, or with the 'sudo' command." - echo - - prompt "Proceed with the installation? [Y/N]: " - if [[ $? == 0 ]]; then - exit 0 - fi - - install_to_prefix "$HOME/.singularity-install" - $HOME/.singularity-install/refresh_desktop_app_entry.sh -} - -function root_install() -{ - local default_prefix="/opt/singularity-install" - - echo -n "Enter the desired installation directory [${default_prefix}]: "; - read - if [[ "$REPLY" = "" ]] ; then - local install_prefix=$default_prefix - else - local install_prefix=$REPLY - fi - - install_to_prefix "$install_prefix" - - mkdir -p /usr/local/share/applications - ${install_prefix}/refresh_desktop_app_entry.sh -} - -function install_to_prefix() -{ - test -e "$1" && backup_previous_installation "$1" - mkdir -p "$1" || die "Failed to create installation directory!" - - echo " - Installing to $1" - - cp -a "${tarball_path}"/* "$1/" || die "Failed to complete the installation!" -} - -function backup_previous_installation() -{ - local backup_dir="$1".backup-$(date -I) - echo " - Backing up previous installation to $backup_dir" - - mv "$1" "$backup_dir" || die "Failed to create backup of existing installation!" -} - - -if [ "$UID" == "0" ]; then - root_install -else - homedir_install -fi diff --git a/indra/newview/linux_tools/install.sh.in b/indra/newview/linux_tools/install.sh.in new file mode 100755 index 0000000000..2136c38083 --- /dev/null +++ b/indra/newview/linux_tools/install.sh.in @@ -0,0 +1,106 @@ +#!/usr/bin/env bash + +# Install @VIEWER_CHANNEL@. This script can install the viewer both +# system-wide and for an individual user. + +VT102_STYLE_NORMAL='\E[0m' +VT102_COLOR_RED='\E[31m' + +SCRIPTSRC=`readlink -f "$0" || echo "$0"` +RUN_PATH=`dirname "${SCRIPTSRC}" || echo .` +tarball_path=${RUN_PATH} + +function prompt() +{ + local prompt=$1 + local input + + echo -n "$prompt" + + while read input; do + case $input in + [Yy]* ) + return 1 + ;; + [Nn]* ) + return 0 + ;; + * ) + echo "Please enter yes or no." + echo -n "$prompt" + esac + done +} + +function die() +{ + warn $1 + exit 1 +} + +function warn() +{ + echo -n -e $VT102_COLOR_RED + echo $1 + echo -n -e $VT102_STYLE_NORMAL +} + +function homedir_install() +{ + warn "You are not running as a privileged user, so you will only be able" + warn "to install @VIEWER_CHANNEL@ in your home directory. If you" + warn "would like to install @VIEWER_CHANNEL@ system-wide, please run" + warn "this script as the root user, or with the 'sudo' command." + echo + + prompt "Proceed with the installation? [Y/N]: " + if [[ $? == 0 ]]; then + exit 0 + fi + + install_to_prefix "$HOME/.@VIEWER_BRANDING_ID@-install" + $HOME/.@VIEWER_BRANDING_ID@-install/etc/refresh_desktop_app_entry.sh +} + +function root_install() +{ + local default_prefix="/opt/@VIEWER_BRANDING_ID@-install" + + echo -n "Enter the desired installation directory [${default_prefix}]: "; + read + if [[ "$REPLY" = "" ]] ; then + local install_prefix=$default_prefix + else + local install_prefix=$REPLY + fi + + install_to_prefix "$install_prefix" + + mkdir -p /usr/local/share/applications + ${install_prefix}/etc/refresh_desktop_app_entry.sh +} + +function install_to_prefix() +{ + test -e "$1" && backup_previous_installation "$1" + mkdir -p "$1" || die "Failed to create installation directory!" + + echo " - Installing to $1" + + cp -a "${tarball_path}"/* "$1/" || die "Failed to complete the installation!" +} + +function backup_previous_installation() +{ + local backup_dir="$1".backup-$(date -I) + echo " - Backing up previous installation to $backup_dir" + + mv "$1" "$backup_dir" || die "Failed to create backup of existing installation!" +} + + +if [ "$UID" == "0" ]; then + root_install +else + homedir_install +fi diff --git a/indra/newview/linux_tools/launch_url.sh b/indra/newview/linux_tools/launch_url.sh index c528ee762c..c1effc1883 100755 --- a/indra/newview/linux_tools/launch_url.sh +++ b/indra/newview/linux_tools/launch_url.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # This script loads a web page in the 'default' graphical web browser. # It MUST return immediately (or soon), so the browser should be diff --git a/indra/newview/linux_tools/refresh_desktop_app_entry.sh b/indra/newview/linux_tools/refresh_desktop_app_entry.sh deleted file mode 100755 index 9412c840cf..0000000000 --- a/indra/newview/linux_tools/refresh_desktop_app_entry.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/bash - -SCRIPTSRC=`readlink -f "$0" || echo "$0"` -RUN_PATH=`dirname "${SCRIPTSRC}" || echo .` - -install_prefix=${RUN_PATH} - -function install_desktop_entry() -{ - local installation_prefix="$1" - local desktop_entries_dir="$2" - - local desktop_entry="\ -[Desktop Entry]\n\ -Name=Singularity\n\ -Comment=Client for Online Virtual Worlds, such as Second Life\n\ -Exec=${installation_prefix}/singularity\n\ -Icon=${installation_prefix}/singularity_icon.png\n\ -Terminal=false\n\ -Type=Application\n\ -Categories=Application;Network;\n\ -StartupNotify=true\n\ -X-Desktop-File-Install-Version=3.0" - - echo " - Installing menu entries in ${desktop_entries_dir}" - mkdir -vp "${desktop_entries_dir}" - echo -e $desktop_entry > "${desktop_entries_dir}/singularity-viewer.desktop" || "Failed to install application menu!" -} - -if [ "$UID" == "0" ]; then - # system-wide - install_desktop_entry "$install_prefix" /usr/local/share/applications -else - # user-specific - install_desktop_entry "$install_prefix" "$HOME/.local/share/applications" -fi diff --git a/indra/newview/linux_tools/refresh_desktop_app_entry.sh.in b/indra/newview/linux_tools/refresh_desktop_app_entry.sh.in new file mode 100755 index 0000000000..109dfe38ff --- /dev/null +++ b/indra/newview/linux_tools/refresh_desktop_app_entry.sh.in @@ -0,0 +1,36 @@ +#!/usr/bin/env bash + +SCRIPTSRC=`readlink -f "$0" || echo "$0"` +RUN_PATH=`dirname "${SCRIPTSRC}" || echo .` + +install_prefix=${RUN_PATH}/.. + +function install_desktop_entry() +{ + local installation_prefix="$1" + local desktop_entries_dir="$2" + + local desktop_entry="\ +[Desktop Entry]\n\ +Name=@VIEWER_BRANDING_ID@\n\ +Comment=Client for Online Virtual Worlds, such as Second Life\n\ +Exec=${installation_prefix}/@VIEWER_BRANDING_ID@\n\ +Icon=${installation_prefix}/viewer_icon.png\n\ +Terminal=false\n\ +Type=Application\n\ +Categories=Application;Network;\n\ +StartupNotify=true\n\ +X-Desktop-File-Install-Version=3.0" + + echo " - Installing menu entries in ${desktop_entries_dir}" + mkdir -vp "${desktop_entries_dir}" + echo -e $desktop_entry > "${desktop_entries_dir}/@VIEWER_BRANDING_ID@-viewer.desktop" || "Failed to install application menu!" +} + +if [ "$UID" == "0" ]; then + # system-wide + install_desktop_entry "$install_prefix" /usr/local/share/applications +else + # user-specific + install_desktop_entry "$install_prefix" "$HOME/.local/share/applications" +fi diff --git a/indra/newview/linux_tools/register_secondlifeprotocol.sh b/indra/newview/linux_tools/register_secondlifeprotocol.sh index f4af742fa4..d7ce56c49b 100755 --- a/indra/newview/linux_tools/register_secondlifeprotocol.sh +++ b/indra/newview/linux_tools/register_secondlifeprotocol.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # Register a protocol handler (default: handle_secondlifeprotocol.sh) for # URLs of the form secondlife://... @@ -7,10 +7,10 @@ HANDLER="$1" RUN_PATH=`dirname "$0" || echo .` -cd "${RUN_PATH}" +cd "${RUN_PATH}/.." if [ -z "$HANDLER" ]; then - HANDLER=`pwd`/handle_secondlifeprotocol.sh + HANDLER=`pwd`/etc/handle_secondlifeprotocol.sh fi # Register handler for GNOME-aware apps diff --git a/indra/newview/linux_tools/wrapper.sh b/indra/newview/linux_tools/wrapper.sh deleted file mode 100755 index d6a2662403..0000000000 --- a/indra/newview/linux_tools/wrapper.sh +++ /dev/null @@ -1,160 +0,0 @@ -#!/bin/bash - -## Here are some configuration options for Linux Client Testers. -## These options are for self-assisted troubleshooting during this beta -## testing phase; you should not usually need to touch them. - -## - Avoids using any FMOD Ex audio driver. -#export LL_BAD_FMODEX_DRIVER=x -## - Avoids using any OpenAL audio driver. -#export LL_BAD_OPENAL_DRIVER=x -## - Avoids using any FMOD audio driver. -#export LL_BAD_FMOD_DRIVER=x - -## - Avoids using the FMOD Ex PulseAudio audio driver. -#export LL_BAD_FMOD_PULSEAUDIO=x -## - Avoids using the FMOD or FMOD Ex ALSA audio driver. -#export LL_BAD_FMOD_ALSA=x -## - Avoids using the FMOD or FMOD Ex OSS audio driver. -#export LL_BAD_FMOD_OSS=x -## - Avoids using the FMOD or FMOD Ex ESD audio driver. -#export LL_BAD_FMOD_ESD=x - -## - Avoids the optional OpenGL extensions which have proven most problematic -## on some hardware. Disabling this option may cause BETTER PERFORMANCE but -## may also cause CRASHES and hangs on some unstable combinations of drivers -## and hardware. -## NOTE: This is now disabled by default. -#export LL_GL_BASICEXT=x - -## - Avoids *all* optional OpenGL extensions. This is the safest and least- -## exciting option. Enable this if you experience stability issues, and -## report whether it helps in the Linux Client Testers forum. -#export LL_GL_NOEXT=x - -## - For advanced troubleshooters, this lets you disable specific GL -## extensions, each of which is represented by a letter a-o. If you can -## narrow down a stability problem on your system to just one or two -## extensions then please post details of your hardware (and drivers) to -## the Linux Client Testers forum along with the minimal -## LL_GL_BLACKLIST which solves your problems. -#export LL_GL_BLACKLIST=abcdefghijklmno - -## - Some ATI/Radeon users report random X server crashes when the mouse -## cursor changes shape. If you suspect that you are a victim of this -## driver bug, try enabling this option and report whether it helps: -#export LL_ATI_MOUSE_CURSOR_BUG=x - -## - If you experience crashes with streaming video and music, you can -## disable these by enabling this option: -#export LL_DISABLE_GSTREAMER=x - - -## Everything below this line is just for advanced troubleshooters. -##------------------------------------------------------------------- - -## - For advanced debugging cases, you can run the viewer under the -## control of another program, such as strace, gdb, or valgrind. If -## you're building your own viewer, bear in mind that the executable -## in the bin directory will be stripped: you should replace it with -## an unstripped binary before you run. -if [ -n "$ASCENDED_DEVELOPER" ]; then - if [ "$ASCENDED_DEVELOPER" = "1" ]; then - export LL_WRAPPER='gdb --args' - elif [ "$ASCENDED_DEVELOPER" = "2" ]; then - export LL_WRAPPER='valgrind --smc-check=all --error-limit=no --log-file=secondlife.vg --leak-check=full --suppressions=/usr/lib/valgrind/glibc-2.5.supp --suppressions=secondlife-i686.supp' - elif [ "$ASCENDED_DEVELOPER" = "3" ]; then - export LL_WRAPPER='strace -f -ff -o singularity.strace' - fi -fi - -## - This allows one to set an arbitrary value for LD_PRELOAD. -## It won't work if LL_TCMALLOC is set because that uses it's -## own value of LD_PRELOAD. -#export AI_PRELOAD='/path/to/libmemleak.so' - -## - Avoids an often-buggy X feature that doesn't really benefit us anyway. -export SDL_VIDEO_X11_DGAMOUSE=0 - -## - Works around a problem with misconfigured 64-bit systems not finding GL -export LIBGL_DRIVERS_PATH="${LIBGL_DRIVERS_PATH}":/usr/lib64/dri:/usr/lib32/dri:/usr/lib/dri - -## - The 'scim' GTK IM module widely crashes the viewer. Avoid it. -if [ "$GTK_IM_MODULE" = "scim" ]; then - export GTK_IM_MODULE=xim -fi - -# Work around for a crash bug when restarting OpenGL after a change in the -# graphic settings (anti-aliasing, VBO, FSAA, full screen mode, UI scale). -# When you enable this work around, you can change the settings without -# crashing, but you will have to restart the viewer after changing them -# because the display still gets corrupted. -export LL_OPENGL_RESTART_CRASH_BUG=x - -## - Automatically work around the ATI mouse cursor crash bug: -## (this workaround is disabled as most fglrx users do not see the bug) -#if lsmod | grep fglrx &>/dev/null ; then -# export LL_ATI_MOUSE_CURSOR_BUG=x -#fi - - -## Nothing worth editing below this line. -##------------------------------------------------------------------- - -SCRIPTSRC=`readlink -f "$0" || echo "$0"` -RUN_PATH=`dirname "${SCRIPTSRC}" || echo .` -echo "Running from ${RUN_PATH}" -cd "${RUN_PATH}" - -# Re-register the secondlife:// protocol handler every launch, for now. -./register_secondlifeprotocol.sh - -# Re-register the application with the desktop system every launch, for now. -./refresh_desktop_app_entry.sh - -## Before we mess with LD_LIBRARY_PATH, save the old one to restore for -## subprocesses that care. -export SAVED_LD_LIBRARY_PATH="${LD_LIBRARY_PATH}" - -SL_ENV= - -if [ -n "$AI_PRELOAD" ]; then - SL_ENV='LD_PRELOAD="$AI_PRELOAD" ' -fi - -if [ -n "$LL_TCMALLOC" ]; then - tcmalloc_libs='/usr/lib/libtcmalloc.so.0 /usr/lib/libstacktrace.so.0 /lib/libpthread.so.0' - all=1 - for f in $tcmalloc_libs; do - if [ ! -f $f ]; then - all=0 - fi - done - if [ $all != 1 ]; then - echo 'Cannot use tcmalloc libraries: components missing' 1>&2 - else - SL_ENV='LD_PRELOAD="$(echo $tcmalloc_libs | tr '"' '"' :)" ' - if [ -z "$HEAPCHECK" -a -z "$HEAPPROFILE" ]; then - export HEAPCHECK=${HEAPCHECK:-normal} - fi - fi -fi - -export VIEWER_BINARY='singularity-do-not-run-directly' -BINARY_TYPE=$(expr match "$(file -b bin/$VIEWER_BINARY)" '\(.*executable\)' | sed -e 's/ / /g') -if [ "${BINARY_TYPE}" == "ELF 64-bit LSB executable" ]; then - SL_ENV+='LD_LIBRARY_PATH="`pwd`/lib64:`pwd`/lib32:$LD_LIBRARY_PATH"' -else - SL_ENV+='LD_LIBRARY_PATH="`pwd`/lib:$LD_LIBRARY_PATH"' -fi -export SL_CMD='$LL_WRAPPER bin/$VIEWER_BINARY' -export SL_OPT="`cat gridargs.dat` $@" - -# Run the program. -eval ${SL_ENV} ${SL_CMD} ${SL_OPT} || LL_RUN_ERR=runerr - -# Handle any resulting errors -if [ "$LL_RUN_ERR" = "runerr" ]; then - # generic error running the binary - echo '*** Bad shutdown. ***' -fi diff --git a/indra/newview/linux_tools/wrapper.sh.in b/indra/newview/linux_tools/wrapper.sh.in new file mode 100755 index 0000000000..7ccee7eaba --- /dev/null +++ b/indra/newview/linux_tools/wrapper.sh.in @@ -0,0 +1,161 @@ +#!/usr/bin/env bash + +## Here are some configuration options for Linux Client Testers. +## These options are for self-assisted troubleshooting during this beta +## testing phase; you should not usually need to touch them. + +## - Avoids using any FMOD Ex audio driver. +#export LL_BAD_FMODEX_DRIVER=x +## - Avoids using any OpenAL audio driver. +#export LL_BAD_OPENAL_DRIVER=x +## - Avoids using any FMOD audio driver. +#export LL_BAD_FMOD_DRIVER=x + +## - Avoids using the FMOD Ex PulseAudio audio driver. +#export LL_BAD_FMOD_PULSEAUDIO=x +## - Avoids using the FMOD or FMOD Ex ALSA audio driver. +#export LL_BAD_FMOD_ALSA=x +## - Avoids using the FMOD or FMOD Ex OSS audio driver. +#export LL_BAD_FMOD_OSS=x +## - Avoids using the FMOD or FMOD Ex ESD audio driver. +#export LL_BAD_FMOD_ESD=x + +## - Avoids the optional OpenGL extensions which have proven most problematic +## on some hardware. Disabling this option may cause BETTER PERFORMANCE but +## may also cause CRASHES and hangs on some unstable combinations of drivers +## and hardware. +## NOTE: This is now disabled by default. +#export LL_GL_BASICEXT=x + +## - Avoids *all* optional OpenGL extensions. This is the safest and least- +## exciting option. Enable this if you experience stability issues, and +## report whether it helps in the Linux Client Testers forum. +#export LL_GL_NOEXT=x + +## - For advanced troubleshooters, this lets you disable specific GL +## extensions, each of which is represented by a letter a-o. If you can +## narrow down a stability problem on your system to just one or two +## extensions then please post details of your hardware (and drivers) to +## the Linux Client Testers forum along with the minimal +## LL_GL_BLACKLIST which solves your problems. +#export LL_GL_BLACKLIST=abcdefghijklmno + +## - Some ATI/Radeon users report random X server crashes when the mouse +## cursor changes shape. If you suspect that you are a victim of this +## driver bug, try enabling this option and report whether it helps: +#export LL_ATI_MOUSE_CURSOR_BUG=x + +## - If you experience crashes with streaming video and music, you can +## disable these by enabling this option: +#export LL_DISABLE_GSTREAMER=x + + +## Everything below this line is just for advanced troubleshooters. +##------------------------------------------------------------------- + +## - For advanced debugging cases, you can run the viewer under the +## control of another program, such as strace, gdb, or valgrind. If +## you're building your own viewer, run the configure step with +## -DPACKAGE:BOOL=OFF to produce an unstripped binary for debugging. +if [ -n "$ASCENDED_DEVELOPER" ]; then + if [ "$ASCENDED_DEVELOPER" = "1" ]; then + export LL_WRAPPER='gdb --args' + elif [ "$ASCENDED_DEVELOPER" = "2" ]; then + export LL_WRAPPER='valgrind --smc-check=all --error-limit=no --log-file=secondlife.vg --leak-check=full --suppressions=/usr/lib/valgrind/glibc-2.5.supp --suppressions=secondlife-i686.supp' + elif [ "$ASCENDED_DEVELOPER" = "3" ]; then + export LL_WRAPPER='strace -f -ff -o @VIEWER_BRANDING_ID@.strace' + fi +fi + +## - This allows one to set an arbitrary value for LD_PRELOAD. +## It won't work if LL_TCMALLOC is set because that uses it's +## own value of LD_PRELOAD. +#export AI_PRELOAD='/path/to/libmemleak.so' + +## - Avoids an often-buggy X feature that doesn't really benefit us anyway. +export SDL_VIDEO_X11_DGAMOUSE=0 + +## - Works around a problem with misconfigured 64-bit systems not finding GL +# This is less needed nowadays; don't uncomment this unless LibGL can't find your +# drivers automatically. +#export LIBGL_DRIVERS_PATH="${LIBGL_DRIVERS_PATH}":/usr/lib64/dri:/usr/lib32/dri:/usr/lib/dri + +## - The 'scim' GTK IM module widely crashes the viewer. Avoid it. +if [ "$GTK_IM_MODULE" = "scim" ]; then + export GTK_IM_MODULE=xim +fi + +# Work around for a crash bug when restarting OpenGL after a change in the +# graphic settings (anti-aliasing, VBO, FSAA, full screen mode, UI scale). +# When you enable this work around, you can change the settings without +# crashing, but you will have to restart the viewer after changing them +# because the display still gets corrupted. +export LL_OPENGL_RESTART_CRASH_BUG=x + +## - Automatically work around the ATI mouse cursor crash bug: +## (this workaround is disabled as most fglrx users do not see the bug) +#if lsmod | grep fglrx &>/dev/null ; then +# export LL_ATI_MOUSE_CURSOR_BUG=x +#fi + + +## Nothing worth editing below this line. +##------------------------------------------------------------------- + +SCRIPTSRC=`readlink -f "$0" || echo "$0"` +RUN_PATH=`dirname "${SCRIPTSRC}" || echo .` +echo "Running from ${RUN_PATH}" +cd "${RUN_PATH}" + +# Re-register the secondlife:// protocol handler every launch, for now. +./etc/register_secondlifeprotocol.sh + +# Re-register the application with the desktop system every launch, for now. +./etc/refresh_desktop_app_entry.sh + +## Before we mess with LD_LIBRARY_PATH, save the old one to restore for +## subprocesses that care. +export SAVED_LD_LIBRARY_PATH="${LD_LIBRARY_PATH}" + +SL_ENV= + +if [ -n "$AI_PRELOAD" ]; then + SL_ENV='LD_PRELOAD="$AI_PRELOAD" ' +fi + +if [ -n "$LL_TCMALLOC" ]; then + tcmalloc_libs='/usr/lib/libtcmalloc.so.0 /usr/lib/libstacktrace.so.0 /lib/libpthread.so.0' + all=1 + for f in $tcmalloc_libs; do + if [ ! -f $f ]; then + all=0 + fi + done + if [ $all != 1 ]; then + echo 'Cannot use tcmalloc libraries: components missing' 1>&2 + else + SL_ENV='LD_PRELOAD="$(echo $tcmalloc_libs | tr '"' '"' :)" ' + if [ -z "$HEAPCHECK" -a -z "$HEAPPROFILE" ]; then + export HEAPCHECK=${HEAPCHECK:-normal} + fi + fi +fi + +export VIEWER_BINARY='do-not-directly-run-@VIEWER_BRANDING_ID@-bin' +BINARY_TYPE=$(expr match "$(file -b bin/$VIEWER_BINARY)" '\(.*executable\)' | sed -e 's/ / /g') +if [ "${BINARY_TYPE}" == "ELF 32-bit LSB executable" ]; then + SL_ENV+='LD_LIBRARY_PATH="`pwd`/lib:$LD_LIBRARY_PATH"' +else + SL_ENV+='LD_LIBRARY_PATH="`pwd`/lib64:`pwd`/lib32:$LD_LIBRARY_PATH"' +fi +export SL_CMD='$LL_WRAPPER bin/$VIEWER_BINARY' + + +# Run the program. +eval ${SL_ENV} ${SL_CMD} || LL_RUN_ERR=runerr + +# Handle any resulting errors +if [ "$LL_RUN_ERR" = "runerr" ]; then + # generic error running the binary + echo '*** Bad shutdown. ***' +fi diff --git a/indra/newview/llaccountingcostmanager.cpp b/indra/newview/llaccountingcostmanager.cpp index d4a5108c50..165d354b6b 100644 --- a/indra/newview/llaccountingcostmanager.cpp +++ b/indra/newview/llaccountingcostmanager.cpp @@ -30,9 +30,6 @@ #include "llcurl.h" #include "llhttpclient.h" -class AIHTTPTimeoutPolicy; -extern AIHTTPTimeoutPolicy accountingCostResponder_timeout; - //=============================================================================== LLAccountingCostManager::LLAccountingCostManager() { @@ -41,9 +38,15 @@ LLAccountingCostManager::LLAccountingCostManager() class LLAccountingCostResponder : public LLHTTPClient::ResponderWithResult { public: - LLAccountingCostResponder( const LLSD& objectIDs ) - : mObjectIDs( objectIDs ) + LLAccountingCostResponder( const LLSD& objectIDs, const LLHandle& observer_handle ) + : mObjectIDs( objectIDs ), + mObserverHandle( observer_handle ) { + LLAccountingCostObserver* observer = mObserverHandle.get(); + if (observer) + { + mTransactionID = observer->getTransactionID(); + } } void clearPendingRequests ( void ) @@ -54,50 +57,63 @@ class LLAccountingCostResponder : public LLHTTPClient::ResponderWithResult } } - /*virtual*/ void error( U32 statusNum, const std::string& reason ) + void httpFailure(void) { - llwarns << "Transport error "<getTransactionID() == mTransactionID) + { + observer->setErrorStatus(mStatus, mReason); + } } - /*virtual*/ void result( const LLSD& content ) + void httpSuccess(void) { //Check for error - if ( !content.isMap() || content.has("error") ) + if ( !mContent.isMap() || mContent.has("error") ) { - llwarns << "Error on fetched data"<< llendl; - clearPendingRequests(); + LL_WARNS() << "Error on fetched data" << LL_ENDL; } - else if (content.has("selected")) + else if (mContent.has("selected")) { F32 physicsCost = 0.0f; F32 networkCost = 0.0f; F32 simulationCost = 0.0f; - //LLTransactionID transactionID; - - //transactionID = content["selected"][i]["local_id"].asUUID(); - physicsCost = content["selected"]["physics"].asReal(); - networkCost = content["selected"]["streaming"].asReal(); - simulationCost = content["selected"]["simulation"].asReal(); + physicsCost = mContent["selected"]["physics"].asReal(); + networkCost = mContent["selected"]["streaming"].asReal(); + simulationCost = mContent["selected"]["simulation"].asReal(); SelectionCost selectionCost( /*transactionID,*/ physicsCost, networkCost, simulationCost ); - + + LLAccountingCostObserver* observer = mObserverHandle.get(); + if (observer && observer->getTransactionID() == mTransactionID) + { + observer->onWeightsUpdate(selectionCost); + } } clearPendingRequests(); } - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return accountingCostResponder_timeout; } /*virtual*/ char const* getName(void) const { return "LLAccountingCostResponder"; } private: //List of posted objects LLSD mObjectIDs; -}; + // Current request ID + LLUUID mTransactionID; + + // Cost update observer handle + LLHandle mObserverHandle; +}; //=============================================================================== -void LLAccountingCostManager::fetchCosts( eSelectionType selectionType, const std::string& url ) +void LLAccountingCostManager::fetchCosts( eSelectionType selectionType, + const std::string& url, + const LLHandle& observer_handle ) { // Invoking system must have already determined capability availability if ( !url.empty() ) @@ -135,7 +151,7 @@ void LLAccountingCostManager::fetchCosts( eSelectionType selectionType, const st } else { - llinfos<<"Invalid selection type "<& getObserverHandle() const { return mObserverHandle; } + const LLUUID& getTransactionID() { return mTransactionID; } + +protected: + virtual void generateTransactionID() = 0; + + LLRootHandle mObserverHandle; + LLUUID mTransactionID; +}; +//=============================================================================== class LLAccountingCostManager : public LLSingleton { public: @@ -37,17 +57,18 @@ class LLAccountingCostManager : public LLSingleton //Store an object that will be eventually fetched void addObject( const LLUUID& objectID ); //Request quotas for object list - void fetchCosts( eSelectionType selectionType, const std::string& url ); + void fetchCosts( eSelectionType selectionType, const std::string& url, + const LLHandle& observer_handle ); //Delete a specific object from the pending list void removePendingObject( const LLUUID& objectID ); private: //Set of objects that will be used to generate a cost - std::set mObjectList; + uuid_set_t mObjectList; //During fetchCosts we move object into a the pending set to signify that //a fetch has been instigated. - std::set mPendingObjectQuota; - typedef std::set::iterator IDIt; + uuid_set_t mPendingObjectQuota; + typedef uuid_set_t::iterator IDIt; }; //=============================================================================== diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index f42739b20c..ac8b94b9f1 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -31,6 +31,7 @@ #include "pipeline.h" #include "llagentaccess.h" +#include "llagentbenefits.h" #include "llagentcamera.h" #include "llagentwearables.h" #include "llagentui.h" @@ -38,11 +39,14 @@ #include "llanimationstates.h" #include "llcallingcard.h" #include "llcapabilitylistener.h" +#include "llcororesponder.h" #include "llconsole.h" #include "llenvmanager.h" #include "llfirstuse.h" #include "llfloatercamera.h" #include "llfloatertools.h" +#include "llfloaterpostcard.h" +#include "llfloaterpreference.h" #include "llgroupactions.h" #include "llgroupmgr.h" #include "llhomelocationresponder.h" @@ -52,6 +56,7 @@ #include "llmoveview.h" #include "llchatbar.h" #include "llnotificationsutil.h" +#include "llnotify.h" // For hiding notices(gNotifyBoxView) in mouselook #include "llparcel.h" #include "llrendersphere.h" #include "llsdmessage.h" @@ -84,6 +89,7 @@ #include "llworld.h" #include "llworldmap.h" #include "llworldmapmessage.h" +#include "../lscript/lscript_byteformat.h" //Misc non-standard includes #include "llurldispatcher.h" @@ -101,10 +107,13 @@ #include "lluictrlfactory.h" //For LLUICtrlFactory::getLayeredXMLNode -// [RLVa:KB] - Checked: 2010-09-27 (RLVa-1.1.3b) +#include "aosystem.h" // for Typing override +#include "hippolimits.h" // for getMaxAgentGroups +// [RLVa:KB] - Checked: 2011-11-04 (RLVa-1.4.4a) +#include "rlvactions.h" #include "rlvhandler.h" -#include "rlvinventory.h" -#include "llattachmentsmgr.h" +#include "rlvhelper.h" +#include "rlvui.h" // [/RLVa:KB] #include "NACLantispam.h" // for NaCl Antispam Registry @@ -179,10 +188,10 @@ class LLTeleportRequestViaLandmark : public LLTeleportRequest LLTeleportRequestViaLandmark(const LLUUID &pLandmarkId); virtual ~LLTeleportRequestViaLandmark(); - virtual bool canRestartTeleport(); + bool canRestartTeleport() override; - virtual void startTeleport(); - virtual void restartTeleport(); + void startTeleport() override; + void restartTeleport() override; protected: inline const LLUUID &getLandmarkId() const {return mLandmarkId;}; @@ -191,15 +200,15 @@ class LLTeleportRequestViaLandmark : public LLTeleportRequest LLUUID mLandmarkId; }; -class LLTeleportRequestViaLure : public LLTeleportRequestViaLandmark +class LLTeleportRequestViaLure final : public LLTeleportRequestViaLandmark { public: LLTeleportRequestViaLure(const LLUUID &pLureId, BOOL pIsLureGodLike); virtual ~LLTeleportRequestViaLure(); - virtual bool canRestartTeleport(); + bool canRestartTeleport() override; - virtual void startTeleport(); + void startTeleport() override; protected: inline BOOL isLureGodLike() const {return mIsLureGodLike;}; @@ -214,10 +223,10 @@ class LLTeleportRequestViaLocation : public LLTeleportRequest LLTeleportRequestViaLocation(const LLVector3d &pPosGlobal); virtual ~LLTeleportRequestViaLocation(); - virtual bool canRestartTeleport(); + bool canRestartTeleport() override; - virtual void startTeleport(); - virtual void restartTeleport(); + void startTeleport() override; + void restartTeleport() override; protected: inline const LLVector3d &getPosGlobal() const {return mPosGlobal;}; @@ -227,22 +236,23 @@ class LLTeleportRequestViaLocation : public LLTeleportRequest }; -class LLTeleportRequestViaLocationLookAt : public LLTeleportRequestViaLocation +class LLTeleportRequestViaLocationLookAt final : public LLTeleportRequestViaLocation { public: LLTeleportRequestViaLocationLookAt(const LLVector3d &pPosGlobal); virtual ~LLTeleportRequestViaLocationLookAt(); - virtual bool canRestartTeleport(); + bool canRestartTeleport() override; - virtual void startTeleport(); - virtual void restartTeleport(); + void startTeleport() override; + void restartTeleport() override; protected: private: }; + //-------------------------------------------------------------------- // Statics // @@ -252,12 +262,12 @@ const F32 LLAgent::TYPING_TIMEOUT_SECS = 5.f; std::map LLAgent::sTeleportErrorMessages; std::map LLAgent::sTeleportProgressMessages; -class LLAgentFriendObserver : public LLFriendObserver +class LLAgentFriendObserver final : public LLFriendObserver { public: - LLAgentFriendObserver() {} - virtual ~LLAgentFriendObserver() {} - virtual void changed(U32 mask); + LLAgentFriendObserver() = default; + virtual ~LLAgentFriendObserver() = default; + void changed(U32 mask) override; }; void LLAgentFriendObserver::changed(U32 mask) @@ -269,11 +279,10 @@ void LLAgentFriendObserver::changed(U32 mask) } } -// static -void LLAgent::parcelChangedCallback() + +void LLAgent::setCanEditParcel() // called via mParcelChangedSignal { bool can_edit = LLToolMgr::getInstance()->canEdit(); - gAgent.mCanEditParcel = can_edit; } @@ -286,9 +295,24 @@ bool LLAgent::isActionAllowed(const LLSD& sdname) if (param == "speak") { - if ( gAgent.isVoiceConnected() && - LLViewerParcelMgr::getInstance()->allowAgentVoice() && - ! LLVoiceClient::getInstance()->inTuningMode() ) + bool allow_agent_voice = false; + LLVoiceChannel* channel = LLVoiceChannel::getCurrentVoiceChannel(); + if (channel != nullptr) + { + if (channel->getSessionName().empty() && channel->getSessionID().isNull()) + { + // default channel + allow_agent_voice = LLViewerParcelMgr::getInstance()->allowAgentVoice(); + } + else + { + allow_agent_voice = channel->isActive() && channel->callStarted(); + } + } + + if (gAgent.isVoiceConnected() && + allow_agent_voice && + !LLVoiceClient::getInstance()->inTuningMode()) { retval = true; } @@ -361,6 +385,7 @@ LLAgent::LLAgent() : mAgentAccess(new LLAgentAccess(gSavedSettings)), mGodLevelChangeSignal(), + mIsCrossingRegion(false), mCanEditParcel(false), mTeleportSourceSLURL(new LLSLURL), mTeleportRequest(), @@ -392,7 +417,8 @@ LLAgent::LLAgent() : mShowAvatar(TRUE), mFrameAgent(), - mIsBusy(FALSE), + mIsAwaySitting(false), + mIsDoNotDisturb(false), mControlFlags(0x00000000), mbFlagsDirty(FALSE), @@ -400,6 +426,7 @@ LLAgent::LLAgent() : mAutoPilot(FALSE), mAutoPilotFlyOnStop(FALSE), + mAutoPilotAllowFlying(TRUE), mAutoPilotTargetGlobal(), mAutoPilotStopDistance(1.f), mAutoPilotUseRotation(FALSE), @@ -410,6 +437,8 @@ LLAgent::LLAgent() : mAutoPilotFinishedCallback(NULL), mAutoPilotCallbackData(NULL), + mMovementKeysLocked(FALSE), + mEffectColor(new LLColor4(0.f, 1.f, 1.f, 1.f)), mHaveHomePosition(FALSE), @@ -418,19 +447,24 @@ LLAgent::LLAgent() : mNextFidgetTime(0.f), mCurrentFidget(0), + mCrouch(false), mFirstLogin(FALSE), - mGenderChosen(FALSE), + mOutfitChosen(FALSE), + mAppearanceSerialNum(0), mMouselookModeInSignal(NULL), mMouselookModeOutSignal(NULL), - mPendingLure(NULL) + mPendingLure(NULL), + mFriendObserver(nullptr) { for (U32 i = 0; i < TOTAL_CONTROLS; i++) { mControlsTakenCount[i] = 0; mControlsTakenPassedOnCount[i] = 0; } + + addParcelChangedCallback(&setCanEditParcel); } // Requires gSavedSettings to be initialized. @@ -440,9 +474,9 @@ LLAgent::LLAgent() : void LLAgent::init() { - setFlying( gSavedSettings.getBOOL("FlyingAtExit") ); - + // *Note: this is where LLViewerCamera::getInstance() used to be constructed. + setFlying( gSavedSettings.getBOOL("FlyingAtExit") ); // LLDebugVarMessageBox::show("Camera Lag", &CAMERA_FOCUS_HALF_LIFE, 0.5f, 0.01f); @@ -454,8 +488,6 @@ void LLAgent::init() mLastKnownRequestMaturity = mLastKnownResponseMaturity; mIsDoSendMaturityPreferenceToServer = true; - LLViewerParcelMgr::getInstance()->addAgentParcelChangedCallback(boost::bind(&LLAgent::parcelChangedCallback)); - if (!mTeleportFinishedSlot.connected()) { mTeleportFinishedSlot = LLViewerParcelMgr::getInstance()->setTeleportFinishedCallback(boost::bind(&LLAgent::handleTeleportFinished, this)); @@ -514,11 +546,11 @@ LLAgent::~LLAgent() //----------------------------------------------------------------------------- void LLAgent::onAppFocusGained() { - if (CAMERA_MODE_MOUSELOOK == gAgentCamera.getCameraMode()) + /*if (CAMERA_MODE_MOUSELOOK == gAgentCamera.getCameraMode()) // Singu Note: Issue 97 requested that we don't do this. { gAgentCamera.changeCameraToDefault(); LLToolMgr::getInstance()->clearSavedTool(); - } + }*/ } @@ -637,13 +669,15 @@ void LLAgent::moveUp(S32 direction) if (direction > 0) { setControlFlags(AGENT_CONTROL_UP_POS | AGENT_CONTROL_FAST_UP); + mCrouch = false; } else if (direction < 0) { setControlFlags(AGENT_CONTROL_UP_NEG | AGENT_CONTROL_FAST_UP); } - if (!isCrouch) camera_reset_on_motion(); + if (!mCrouch) + camera_reset_on_motion(); } //----------------------------------------------------------------------------- @@ -685,6 +719,11 @@ void LLAgent::movePitch(F32 mag) } } +bool LLAgent::isCrouching() const +{ + return mCrouch && !getFlying(); +} + // Does this parcel allow you to fly? BOOL LLAgent::canFly() @@ -696,8 +735,7 @@ BOOL LLAgent::canFly() // static const LLCachedControl ascent_fly_always_enabled("AscentFlyAlwaysEnabled",false); - if(ascent_fly_always_enabled) - return TRUE; + if(ascent_fly_always_enabled) return TRUE; // LLViewerRegion* regionp = getRegion(); @@ -749,10 +787,7 @@ void LLAgent::setFlying(BOOL fly) if (fly) { // [RLVa:KB] - Checked: 2010-03-02 (RLVa-1.2.0d) | Modified: RLVa-1.0.0c - if (gRlvHandler.hasBehaviour(RLV_BHVR_FLY)) - { - return; - } + if (gRlvHandler.hasBehaviour(RLV_BHVR_FLY)) return; // [/RLVa:KB] BOOL was_flying = getFlying(); @@ -768,6 +803,7 @@ void LLAgent::setFlying(BOOL fly) { LLViewerStats::getInstance()->incStat(LLViewerStats::ST_FLY_COUNT); } + mCrouch = false; setControlFlags(AGENT_CONTROL_FLY); } else @@ -804,6 +840,8 @@ void LLAgent::toggleFlying() bool LLAgent::enableFlying() { BOOL sitting = FALSE; + static LLCachedControl continue_flying_on_unsit(gSavedSettings, "LiruContinueFlyingOnUnsit", false); + if (!continue_flying_on_unsit) if (isAgentAvatarValid()) { sitting = gAgentAvatarp->isSitting(); @@ -816,22 +854,25 @@ void LLAgent::standUp() // setControlFlags(AGENT_CONTROL_STAND_UP); // [RLVa:KB] - Checked: 2010-03-07 (RLVa-1.2.0c) | Added: RLVa-1.2.0a // RELEASE-RLVa: [SL-2.0.0] Check this function's callers since usually they require explicit blocking - if ( (!rlv_handler_t::isEnabled()) || (gRlvHandler.canStand()) ) + if ( (!rlv_handler_t::isEnabled()) || (RlvActions::canStand()) ) { setControlFlags(AGENT_CONTROL_STAND_UP); } // [/RLVa:KB] } + void LLAgent::handleServerBakeRegionTransition(const LLUUID& region_id) { - llinfos << "called" << llendl; + LL_INFOS() << "called" << LL_ENDL; + + // Old-style appearance entering a server-bake region. if (isAgentAvatarValid() && !gAgentAvatarp->isUsingServerBakes() && (mRegionp->getCentralBakeVersion()>0)) { - llinfos << "update requested due to region transition" << llendl; + LL_INFOS() << "update requested due to region transition" << LL_ENDL; LLAppearanceMgr::instance().requestServerAppearanceUpdate(); } // new-style appearance entering a non-bake region, @@ -844,26 +885,34 @@ void LLAgent::handleServerBakeRegionTransition(const LLUUID& region_id) } } +void LLAgent::changeParcels() +{ + LL_DEBUGS("AgentLocation") << "Calling ParcelChanged callbacks" << LL_ENDL; + // Notify anything that wants to know about parcel changes + mParcelChangedSignal(); +} + +boost::signals2::connection LLAgent::addParcelChangedCallback(parcel_changed_callback_t cb) +{ + return mParcelChangedSignal.connect(cb); +} + //----------------------------------------------------------------------------- // setRegion() //----------------------------------------------------------------------------- void LLAgent::setRegion(LLViewerRegion *regionp) { - bool teleport = true; - llassert(regionp); if (mRegionp != regionp) { - // std::string host_name; - // host_name = regionp->getHost().getHostName(); std::string ip = regionp->getHost().getString(); - llinfos << "Moving agent into region: " << regionp->getName() - << " located at " << ip << llendl; + LL_INFOS("AgentLocation") << "Moving agent into region: " << regionp->getName() + << " located at " << ip << LL_ENDL; if (mRegionp) { // NaCl - Antispam Registry - NACLAntiSpamRegistry::purgeAllQueues(); + if (auto antispam = NACLAntiSpamRegistry::getIfExists()) antispam->resetQueues(); // NaCl End // We've changed regions, we're now going to change our agent coordinate frame. @@ -892,8 +941,15 @@ void LLAgent::setRegion(LLViewerRegion *regionp) gSky.mVOGroundp->setRegion(regionp); } - // Notify windlight managers - teleport = (gAgent.getTeleportState() != LLAgent::TELEPORT_NONE); + if (regionp->capabilitiesReceived()) + { + regionp->requestSimulatorFeatures(); + } + else + { + regionp->setCapabilitiesReceivedCallback(boost::bind(&LLViewerRegion::requestSimulatorFeatures, regionp)); + } + } else { @@ -915,6 +971,7 @@ void LLAgent::setRegion(LLViewerRegion *regionp) // Pass new region along to metrics components that care about this level of detail. LLAppViewer::metricsUpdateRegion(regionp->getHandle()); } + mRegionp = regionp; // Must shift hole-covering water object locations because local @@ -929,33 +986,18 @@ void LLAgent::setRegion(LLViewerRegion *regionp) LLSelectMgr::getInstance()->updateSelectionCenter(); - if (teleport) - { - LLEnvManagerNew::instance().onTeleport(); - } - else - { - LLEnvManagerNew::instance().onRegionCrossing(); - } - - // If the newly entered region is using server bakes, and our - // current appearance is non-baked, request appearance update from - // server. - if (mRegionp->capabilitiesReceived()) - { - handleServerBakeRegionTransition(mRegionp->getRegionID()); - } - else - { - // Need to handle via callback after caps arrive. - mRegionp->setCapabilitiesReceivedCallback(boost::bind(&LLAgent::handleServerBakeRegionTransition,this,_1)); - } + LL_DEBUGS("AgentLocation") << "Calling RegionChanged callbacks" << LL_ENDL; + mRegionChangedSignal(); } //----------------------------------------------------------------------------- // getRegion() //----------------------------------------------------------------------------- +LLViewerRegion *LLAgent::getRegion() const +{ + return mRegionp; +} const LLHost& LLAgent::getRegionHost() const { @@ -969,6 +1011,15 @@ const LLHost& LLAgent::getRegionHost() const } } +boost::signals2::connection LLAgent::addRegionChangedCallback(const region_changed_signal_t::slot_type& cb) +{ + return mRegionChangedSignal.connect(cb); +} + +void LLAgent::removeRegionChangedCallback(boost::signals2::connection callback) +{ + mRegionChangedSignal.disconnect(callback); +} //----------------------------------------------------------------------------- // inPrelude() @@ -979,6 +1030,15 @@ BOOL LLAgent::inPrelude() } +std::string LLAgent::getRegionCapability(const std::string &name) +{ + if (!mRegionp) + return std::string(); + + return mRegionp->getCapability(name); +} + + //----------------------------------------------------------------------------- // canManageEstate() //----------------------------------------------------------------------------- @@ -995,12 +1055,12 @@ void LLAgent::sendMessage() { if (gDisconnected) { - llwarns << "Trying to send message when disconnected!" << llendl; + LL_WARNS() << "Trying to send message when disconnected!" << LL_ENDL; return; } if (!mRegionp) { - llerrs << "No region for agent yet!" << llendl; + LL_ERRS() << "No region for agent yet!" << LL_ENDL; return; } gMessageSystem->sendMessage(mRegionp->getHost()); @@ -1014,12 +1074,12 @@ void LLAgent::sendReliableMessage() { if (gDisconnected) { - lldebugs << "Trying to send message when disconnected!" << llendl; + LL_DEBUGS() << "Trying to send message when disconnected!" << LL_ENDL; return; } if (!mRegionp) { - lldebugs << "LLAgent::sendReliableMessage No region for agent yet, not sending message!" << llendl; + LL_DEBUGS() << "LLAgent::sendReliableMessage No region for agent yet, not sending message!" << LL_ENDL; return; } gMessageSystem->sendReliable(mRegionp->getHost()); @@ -1048,7 +1108,7 @@ void LLAgent::setPositionAgent(const LLVector3 &pos_agent) { if (!pos_agent.isFinite()) { - llerrs << "setPositionAgent is not a number" << llendl; + LL_ERRS() << "setPositionAgent is not a number" << LL_ENDL; } if (isAgentAvatarValid() && gAgentAvatarp->getParent()) @@ -1146,7 +1206,7 @@ void LLAgent::sitDown() // setControlFlags(AGENT_CONTROL_SIT_ON_GROUND); // [RLVa:KB] - Checked: 2010-08-28 (RLVa-1.2.1a) | Added: RLVa-1.2.1a // RELEASE-RLVa: [SL-2.0.0] Check this function's callers since usually they require explicit blocking - if ( (!rlv_handler_t::isEnabled()) || ((gRlvHandler.canStand()) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SIT))) ) + if ( (!rlv_handler_t::isEnabled()) || ((RlvActions::canStand()) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SIT))) ) { setControlFlags(AGENT_CONTROL_SIT_ON_GROUND); } @@ -1179,7 +1239,7 @@ void LLAgent::resetAxes(const LLVector3 &look_at) LLVector3 cross(look_at % skyward); if (cross.isNull()) { - llinfos << "LLAgent::resetAxes cross-product is zero" << llendl; + LL_INFOS() << "LLAgent::resetAxes cross-product is zero" << LL_ENDL; return; } @@ -1280,20 +1340,12 @@ F32 LLAgent::clampPitchToLimits(F32 angle) LLVector3 skyward = getReferenceUpVector(); - F32 look_down_limit; - F32 look_up_limit = 10.f * DEG_TO_RAD; + static const LLCachedControl useRealisticMouselook(gSavedSettings, "UseRealisticMouselook", false); + const F32 look_down_limit = (useRealisticMouselook ? 160.f : (isAgentAvatarValid() && gAgentAvatarp->isSitting() ? 130.f : 179.f)) * DEG_TO_RAD; + const F32 look_up_limit = (useRealisticMouselook ? 20.f : 1.f) * DEG_TO_RAD;; F32 angle_from_skyward = acos( mFrameAgent.getAtAxis() * skyward ); - if (isAgentAvatarValid() && gAgentAvatarp->isSitting()) - { - look_down_limit = 130.f * DEG_TO_RAD; - } - else - { - look_down_limit = 170.f * DEG_TO_RAD; - } - // clamp pitch to limits if ((angle >= 0.f) && (angle_from_skyward + angle > look_down_limit)) { @@ -1422,12 +1474,13 @@ void LLAgent::setAFK() { sendAnimationRequest(ANIM_AGENT_AWAY, ANIM_REQUEST_START); setControlFlags(AGENT_CONTROL_AWAY | AGENT_CONTROL_STOP); - LL_INFOS("AFK") << "Setting Away" << LL_ENDL; gAwayTimer.start(); + + if (isAgentAvatarValid() && !gAgentAvatarp->isSitting() && gSavedSettings.getBOOL("AlchemySitOnAway")) + gAgent.setSitDownAway(true); + if (gAFKMenu) - { gAFKMenu->setLabel(LLTrans::getString("AvatarSetNotAway")); - } } } @@ -1447,56 +1500,55 @@ void LLAgent::clearAFK() { sendAnimationRequest(ANIM_AGENT_AWAY, ANIM_REQUEST_STOP); clearControlFlags(AGENT_CONTROL_AWAY); - LL_INFOS("AFK") << "Clearing Away" << LL_ENDL; + + if (isAgentAvatarValid() && gAgentAvatarp->isSitting() && gAgent.isAwaySitting()) + gAgent.setSitDownAway(false); + if (gAFKMenu) - { gAFKMenu->setLabel(LLTrans::getString("AvatarSetAway")); - } } } //----------------------------------------------------------------------------- -// getAFK() +// setSitDownAway(bool) //----------------------------------------------------------------------------- -BOOL LLAgent::getAFK() const +void LLAgent::setSitDownAway(bool go_away) { - return (mControlFlags & AGENT_CONTROL_AWAY) != 0; + if (go_away) + gAgent.sitDown(); + else + gAgent.standUp(); + mIsAwaySitting = go_away; } //----------------------------------------------------------------------------- -// setBusy() +// getAFK() //----------------------------------------------------------------------------- -void LLAgent::setBusy() +BOOL LLAgent::getAFK() const { - sendAnimationRequest(ANIM_AGENT_BUSY, ANIM_REQUEST_START); - mIsBusy = TRUE; - if (gBusyMenu) - { - gBusyMenu->setLabel(LLTrans::getString("AvatarSetNotBusy")); - } - LLFloaterMute::getInstance()->updateButtons(); + return (mControlFlags & AGENT_CONTROL_AWAY) != 0; } //----------------------------------------------------------------------------- -// clearBusy() +// setDoNotDisturb() //----------------------------------------------------------------------------- -void LLAgent::clearBusy() +void LLAgent::setDoNotDisturb(bool pIsDoNotDisturb) { - mIsBusy = FALSE; - sendAnimationRequest(ANIM_AGENT_BUSY, ANIM_REQUEST_STOP); + sendAnimationRequest(ANIM_AGENT_DO_NOT_DISTURB, pIsDoNotDisturb ? ANIM_REQUEST_START : ANIM_REQUEST_STOP); + mIsDoNotDisturb = pIsDoNotDisturb; if (gBusyMenu) { - gBusyMenu->setLabel(LLTrans::getString("AvatarSetBusy")); + gBusyMenu->setLabel(LLTrans::getString(pIsDoNotDisturb ? "AvatarSetNotBusy" : "AvatarSetBusy")); } LLFloaterMute::getInstance()->updateButtons(); } //----------------------------------------------------------------------------- -// getBusy() +// isDoNotDisturb() //----------------------------------------------------------------------------- -BOOL LLAgent::getBusy() const +bool LLAgent::isDoNotDisturb() const { - return mIsBusy; + return mIsDoNotDisturb; } @@ -1510,17 +1562,25 @@ void LLAgent::startAutoPilotGlobal( void (*finish_callback)(BOOL, void *), void *callback_data, F32 stop_distance, - F32 rot_threshold) + F32 rot_threshold, + BOOL allow_flying) { if (!isAgentAvatarValid()) { return; } + // Are there any pending callbacks from previous auto pilot requests? + if (mAutoPilotFinishedCallback) + { + mAutoPilotFinishedCallback(dist_vec(gAgent.getPositionGlobal(), mAutoPilotTargetGlobal) < mAutoPilotStopDistance, mAutoPilotCallbackData); + } + mAutoPilotFinishedCallback = finish_callback; mAutoPilotCallbackData = callback_data; mAutoPilotRotationThreshold = rot_threshold; mAutoPilotBehaviorName = behavior_name; + mAutoPilotAllowFlying = allow_flying; LLVector3d delta_pos( target_global ); delta_pos -= getPositionGlobal(); @@ -1548,14 +1608,25 @@ void LLAgent::startAutoPilotGlobal( } } - mAutoPilotFlyOnStop = getFlying(); + if (mAutoPilotAllowFlying) + { + mAutoPilotFlyOnStop = getFlying(); + } + else + { + mAutoPilotFlyOnStop = FALSE; + } + + bool follow = mAutoPilotBehaviorName == "Follow"; - if (distance > 30.0) + if (!follow && distance > 30.0 && mAutoPilotAllowFlying) { setFlying(TRUE); } - if ( distance > 1.f && heightDelta > (sqrtf(mAutoPilotStopDistance) + 1.f)) + if (!follow && distance > 1.f && + mAutoPilotAllowFlying && + heightDelta > (sqrtf(mAutoPilotStopDistance) + 1.f)) { setFlying(TRUE); // Do not force flying for "Sit" behavior to prevent flying after pressing "Stand" @@ -1612,10 +1683,8 @@ void LLAgent::setAutoPilotTargetGlobal(const LLVector3d &target_global) //----------------------------------------------------------------------------- // startFollowPilot() //----------------------------------------------------------------------------- -void LLAgent::startFollowPilot(const LLUUID &leader_id) +void LLAgent::startFollowPilot(const LLUUID &leader_id, BOOL allow_flying, F32 stop_distance) { - if (!mAutoPilot) return; - mLeaderID = leader_id; if ( mLeaderID.isNull() ) return; @@ -1626,7 +1695,14 @@ void LLAgent::startFollowPilot(const LLUUID &leader_id) return; } - startAutoPilotGlobal(object->getPositionGlobal()); + startAutoPilotGlobal(object->getPositionGlobal(), + "Follow", // behavior_name + NULL, // target_rotation + NULL, // finish_callback + NULL, // callback_data + stop_distance, + 0.03f, // rotation_threshold + allow_flying); } @@ -1637,6 +1713,9 @@ void LLAgent::stopAutoPilot(BOOL user_cancel) { if (mAutoPilot) { + if (!user_cancel && mAutoPilotBehaviorName == "Follow") + return; // Follow means actually follow + mAutoPilot = FALSE; if (mAutoPilotUseRotation && !user_cancel) { @@ -1655,7 +1734,16 @@ void LLAgent::stopAutoPilot(BOOL user_cancel) mAutoPilotFinishedCallback(!user_cancel && dist_vec_squared(gAgent.getPositionGlobal(), mAutoPilotTargetGlobal) < (mAutoPilotStopDistance * mAutoPilotStopDistance), mAutoPilotCallbackData); mAutoPilotFinishedCallback = NULL; } + + // Sit response during follow pilot, now complete, resume follow + if (!user_cancel && mAutoPilotBehaviorName == "Sit" && mLeaderID.notNull()) + { + startFollowPilot(mLeaderID, true, gSavedSettings.getF32("SinguFollowDistance")); + return; + } + mLeaderID = LLUUID::null; + mAutoPilotNoProgressFrameCount = 0; setControlFlags(AGENT_CONTROL_STOP); @@ -1665,6 +1753,8 @@ void LLAgent::stopAutoPilot(BOOL user_cancel) LLNotificationsUtil::add("CancelledSit"); else if (mAutoPilotBehaviorName == "Attach") LLNotificationsUtil::add("CancelledAttach"); + else if (mAutoPilotBehaviorName == "Follow") + LLNotificationsUtil::add("CancelledFollow"); else LLNotificationsUtil::add("Cancelled"); } @@ -1672,28 +1762,105 @@ void LLAgent::stopAutoPilot(BOOL user_cancel) } +bool LLAgent::getAutoPilotNoProgress() const +{ + return mAutoPilotNoProgressFrameCount > AUTOPILOT_MAX_TIME_NO_PROGRESS * gFPSClamped; +} + // Returns necessary agent pitch and yaw changes, radians. //----------------------------------------------------------------------------- // autoPilot() //----------------------------------------------------------------------------- void LLAgent::autoPilot(F32 *delta_yaw) { - if (mAutoPilot) + if (mAutoPilot && isAgentAvatarValid()) { - if (!mLeaderID.isNull()) + U8 follow = mAutoPilotBehaviorName == "Follow"; + if (follow) { - LLViewerObject* object = gObjectList.findObject(mLeaderID); - if (!object) + llassert(mLeaderID.notNull()); + const auto old_pos = mAutoPilotTargetGlobal; + if (auto object = gObjectList.findObject(mLeaderID)) { - stopAutoPilot(); - return; + mAutoPilotTargetGlobal = object->getPositionGlobal(); + if (const auto& av = object->asAvatar()) // Fly/sit if avatar target is flying + { + const auto& our_pos_global = getPositionGlobal(); + setFlying(av->mInAir && (getFlying() || mAutoPilotTargetGlobal[VZ] > our_pos_global[VZ])); // If they're in air, fly if they're higher or we were already (follow) flying + if (av->isSitting() && (!rlv_handler_t::isEnabled() || !gRlvHandler.hasBehaviour(RLV_BHVR_SIT))) + { + if (auto seat = av->getParent()) + { + if (gAgentAvatarp->getParent() == seat) + { + mAutoPilotNoProgressFrameCount = 0; // We may have incremented this before making it here, reset it + return; // We're seated with them, nothing more to do + } + else if (!getAutoPilotNoProgress()) + { + void handle_object_sit(LLViewerObject*, const LLVector3&); + handle_object_sit(static_cast(seat), LLVector3::zero); + follow = 2; // Indicate ground sitting is okay if we can't make it + } + else return; // If the server just wouldn't let us sit there, we won't be moving, exit here + } + else // Ground sit, but only if near enough + { + if (dist_vec(mAutoPilotTargetGlobal, our_pos_global) <= mAutoPilotStopDistance) // We're close enough, sit. + { + if (!gAgentAvatarp->isSittingAvatarOnGround()) + setControlFlags(AGENT_CONTROL_SIT_ON_GROUND); + mAutoPilotNoProgressFrameCount = 0; // Ground Sit may have incremented this, reset it now + return; // We're already sitting on the ground, we have nothing to do + } + else // We're not close enough yet + { + if (/*!gAgentAvatarp->isSitting() && */ // RLV takes care of sitting check for us inside standUp + getAutoPilotNoProgress()) // Only stand up if we haven't exhausted our no progress frames + standUp(); // Unsit if need be, so we can move + follow = 2; // Indicate we want to groundsit + } + } + } + else + { + if (dist_vec(mAutoPilotTargetGlobal, our_pos_global) <= mAutoPilotStopDistance) + { + follow = 3; // We're close enough, indicate no walking + } + + if (gAgentAvatarp->isSitting()) // Leader isn't sitting, standUp if needed + { + standUp(); + mAutoPilotNoProgressFrameCount = 0; // Ground Sit may have incremented this, reset it + } + } + } } - mAutoPilotTargetGlobal = object->getPositionGlobal(); + else // We might still have a valid avatar pos + { + const LLVector3d& get_av_pos(const LLUUID & id); + auto pos = get_av_pos(mLeaderID); + if (pos.isExactlyZero()) // Default constructed or invalid from server + { + // Wait for them for more follow pilot + return; + } + standUp(); // Leader not rendered, we mustn't be sitting + mAutoPilotNoProgressFrameCount = 0; // Ground Sit may have incremented this, reset it + mAutoPilotTargetGlobal = pos; + setFlying(true); // Should we fly here? Altitude is often invalid... + + if (dist_vec(mAutoPilotTargetGlobal, getPositionGlobal()) <= mAutoPilotStopDistance) + { + follow = 3; // We're close enough, indicate no walking + } + } + if (old_pos != mAutoPilotTargetGlobal) // Reset if position changes + mAutoPilotNoProgressFrameCount = 0; } - - if (!isAgentAvatarValid()) return; - if (gAgentAvatarp->mInAir) + if (follow % 2 == 0 && gAgentAvatarp->mInAir && mAutoPilotAllowFlying) { setFlying(TRUE); } @@ -1705,12 +1872,15 @@ void LLAgent::autoPilot(F32 *delta_yaw) F32 target_dist = direction.magVec(); - if (target_dist >= mAutoPilotTargetDist) + if (follow % 2 == 0 && target_dist >= mAutoPilotTargetDist) { mAutoPilotNoProgressFrameCount++; - if (mAutoPilotNoProgressFrameCount > AUTOPILOT_MAX_TIME_NO_PROGRESS * gFPSClamped) + if (getAutoPilotNoProgress()) { - stopAutoPilot(); + if (follow) // Well, we tried to reach them, let's just ground sit for now. + setControlFlags(AGENT_CONTROL_SIT_ON_GROUND); + else + stopAutoPilot(); return; } } @@ -1752,8 +1922,9 @@ void LLAgent::autoPilot(F32 *delta_yaw) } *delta_yaw = yaw; + if (follow == 3) return; // We're close enough, all we need to do is turn - // Compute when to start slowing down and when to stop + // Compute when to start slowing down F32 slow_distance; if (getFlying()) { @@ -1901,12 +2072,6 @@ std::ostream& operator<<(std::ostream &s, const LLAgent &agent) return s; } - -// ------------------- Beginning of legacy LLCamera hack ---------------------- -// This section is included for legacy LLCamera support until -// it is no longer needed. Some legacy code must exist in -// non-legacy functions, and is labeled with "// legacy" comments. - // TRUE if your own avatar needs to be rendered. Usually only // in third person and build. //----------------------------------------------------------------------------- @@ -1919,7 +2084,7 @@ BOOL LLAgent::needsRenderAvatar() return FALSE; } - return mShowAvatar && mGenderChosen; + return mShowAvatar && mOutfitChosen; } // TRUE if we need to render your own avatar's head. @@ -1945,18 +2110,16 @@ void LLAgent::startTyping() if (mChatTimer.getElapsedTimeF32() < 2.f) { - LLVOAvatar* chatter = gObjectList.findAvatar(mLastChatterID); - if (chatter) + LLViewerObject* chatter = gObjectList.findObject(mLastChatterID); + if (chatter && chatter->isAvatar()) { gAgentCamera.setLookAt(LOOKAT_TARGET_RESPOND, chatter, LLVector3::zero); } } - if (gSavedSettings.getBOOL("PlayTypingAnim")) - { - sendAnimationRequest(ANIM_AGENT_TYPE, ANIM_REQUEST_START); - } - gChatBar->sendChatFromViewer("", CHAT_TYPE_START, FALSE); + AOSystem::typing(true); // Singu Note: Typing anims handled by AO/settings. + gChatBar-> + sendChatFromViewer("", CHAT_TYPE_START, FALSE); } //----------------------------------------------------------------------------- @@ -1967,8 +2130,9 @@ void LLAgent::stopTyping() if (mRenderState & AGENT_STATE_TYPING) { clearRenderState(AGENT_STATE_TYPING); - sendAnimationRequest(ANIM_AGENT_TYPE, ANIM_REQUEST_STOP); - gChatBar->sendChatFromViewer("", CHAT_TYPE_STOP, FALSE); + AOSystem::typing(false); // Singu Note: Typing anims handled by AO/settings. + gChatBar-> + sendChatFromViewer("", CHAT_TYPE_STOP, FALSE); } } @@ -2042,6 +2206,8 @@ void LLAgent::endAnimationUpdateUI() gMenuBarView->setVisible(TRUE); gStatusBar->setVisibleForMouselook(true); + // Show notices + gNotifyBoxView->setVisible(true); LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset); @@ -2052,7 +2218,7 @@ void LLAgent::endAnimationUpdateUI() } // Only pop if we have pushed... - if (TRUE == mViewsPushed) + if (mViewsPushed) { LLFloaterView::skip_list_t skip_list; skip_list.insert(LLFloaterMap::getInstance()); @@ -2061,6 +2227,7 @@ void LLAgent::endAnimationUpdateUI() mViewsPushed = FALSE; } + gAgentCamera.setLookAt(LOOKAT_TARGET_CLEAR); if( gMorphView ) { @@ -2133,9 +2300,11 @@ void LLAgent::endAnimationUpdateUI() if (gAgentCamera.getCameraMode() == CAMERA_MODE_MOUSELOOK) { // hide menus - gMenuBarView->setVisible(FALSE); + gMenuBarView->setVisible(!gSavedSettings.getBOOL("LiruMouselookHidesMenubar")); gStatusBar->setVisibleForMouselook(false); + if (gSavedSettings.getBOOL("LiruMouselookHidesNotices")) + gNotifyBoxView->setVisible(false); // clear out camera lag effect gAgentCamera.clearCameraLag(); @@ -2145,7 +2314,7 @@ void LLAgent::endAnimationUpdateUI() LLToolMgr::getInstance()->setCurrentToolset(gMouselookToolset); - mViewsPushed = TRUE; + mViewsPushed = gSavedSettings.getBOOL("LiruMouselookHidesFloaters"); if (mMouselookModeInSignal) { @@ -2154,9 +2323,12 @@ void LLAgent::endAnimationUpdateUI() // hide all floaters except the mini map - LLFloaterView::skip_list_t skip_list; - skip_list.insert(LLFloaterMap::getInstance()); - gFloaterView->pushVisibleAll(FALSE, skip_list); + if (mViewsPushed) // Singu Note: Only hide if the setting is true. + { + LLFloaterView::skip_list_t skip_list; + skip_list.insert(LLFloaterMap::getInstance()); + gFloaterView->pushVisibleAll(FALSE, skip_list); + } if( gMorphView ) { @@ -2211,13 +2383,6 @@ void LLAgent::endAnimationUpdateUI() LLToolMgr::getInstance()->setCurrentToolset(gFaceEditToolset); LLFloaterMap::getInstance()->pushVisible(FALSE); - /* - LLView *view; - for (view = gFloaterView->getFirstChild(); view; view = gFloaterView->getNextChild()) - { - view->pushVisible(FALSE); - } - */ if( gMorphView ) { @@ -2311,7 +2476,7 @@ void LLAgent::setStartPosition( U32 location_id ) object = gObjectList.findObject(gAgentID); if (! object) { - llinfos << "setStartPosition - Can't find agent viewerobject id " << gAgentID << llendl; + LL_INFOS() << "setStartPosition - Can't find agent viewerobject id " << gAgentID << LL_ENDL; return; } // we've got the viewer object @@ -2319,7 +2484,10 @@ void LLAgent::setStartPosition( U32 location_id ) // this simulator. Clamp it to the region the agent is // in, a little bit in on each side. const F32 INSET = 0.5f; //meters - const F32 REGION_WIDTH = LLWorld::getInstance()->getRegionWidthInMeters(); +// Aurora Sim + //const F32 REGION_WIDTH = LLWorld::getInstance()->getRegionWidthInMeters(); + const F32 REGION_WIDTH = getRegion()->getWidth(); +// Aurora Sim LLVector3 agent_pos = getPositionAgent(); @@ -2413,7 +2581,7 @@ void LLAgent::requestStopMotion( LLMotion* motion ) // if motion is not looping, it could have stopped by running out of time // so we need to tell the server this -// llinfos << "Sending stop for motion " << motion->getName() << llendl; +// LL_INFOS() << "Sending stop for motion " << motion->getName() << LL_ENDL; sendAnimationRequest( anim_state, ANIM_REQUEST_STOP ); } @@ -2426,15 +2594,11 @@ void LLAgent::onAnimStop(const LLUUID& id) } else if (id == ANIM_AGENT_AWAY) { -// clearAFK(); // [RLVa:KB] - Checked: 2010-05-03 (RLVa-1.2.0g) | Added: RLVa-1.1.0g -#ifdef RLV_EXTENSION_CMD_ALLOWIDLE if (!gRlvHandler.hasBehaviour(RLV_BHVR_ALLOWIDLE)) clearAFK(); -#else - clearAFK(); -#endif // RLV_EXTENSION_CMD_ALLOWIDLE // [/RLVa:KB] +// clearAFK(); } else if (id == ANIM_AGENT_STANDUP) { @@ -2505,7 +2669,7 @@ bool LLAgent::canAccessMaturityInRegion( U64 region_handle ) const return true; } -bool LLAgent::canAccessMaturityAtGlobal( LLVector3d pos_global ) const +bool LLAgent::canAccessMaturityAtGlobal(const LLVector3d& pos_global ) const { U64 region_handle = to_region_handle_global( pos_global.mdV[0], pos_global.mdV[1] ); return canAccessMaturityInRegion( region_handle ); @@ -2552,28 +2716,28 @@ int LLAgent::convertTextToMaturity(char text) return LLAgentAccess::convertTextToMaturity(text); } -extern AIHTTPTimeoutPolicy maturityPreferences_timeout; -class LLMaturityPreferencesResponder : public LLHTTPClient::ResponderWithResult +class LLMaturityPreferencesResponder final : public LLHTTPClient::ResponderWithResult { + LOG_CLASS(LLMaturityPreferencesResponder); public: LLMaturityPreferencesResponder(LLAgent *pAgent, U8 pPreferredMaturity, U8 pPreviousMaturity); virtual ~LLMaturityPreferencesResponder(); - /*virtual*/ void result(const LLSD &pContent); - /*virtual*/ void error(U32 pStatus, const std::string& pReason); - - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return maturityPreferences_timeout; } - /*virtual*/ char const* getName(void) const { return "LLMaturityPreferencesResponder"; } +protected: + void httpSuccess() override; + void httpFailure() override; + char const* getName() const override { return "LLMaturityPreferencesResponder"; } private: - U8 parseMaturityFromServerResponse(const LLSD &pContent); + U8 parseMaturityFromServerResponse(const LLSD &pContent) const; LLAgent *mAgent; U8 mPreferredMaturity; U8 mPreviousMaturity; }; -LLMaturityPreferencesResponder::LLMaturityPreferencesResponder(LLAgent *pAgent, U8 pPreferredMaturity, U8 pPreviousMaturity) : +LLMaturityPreferencesResponder::LLMaturityPreferencesResponder(LLAgent *pAgent, U8 pPreferredMaturity, U8 pPreviousMaturity) + : mAgent(pAgent), mPreferredMaturity(pPreferredMaturity), mPreviousMaturity(pPreviousMaturity) @@ -2584,75 +2748,49 @@ LLMaturityPreferencesResponder::~LLMaturityPreferencesResponder() { } -void LLMaturityPreferencesResponder::result(const LLSD &pContent) +void LLMaturityPreferencesResponder::httpSuccess() { - U8 actualMaturity = parseMaturityFromServerResponse(pContent); + U8 actualMaturity = parseMaturityFromServerResponse(getContent()); if (actualMaturity != mPreferredMaturity) { - llwarns << "while attempting to change maturity preference from '" << LLViewerRegion::accessToString(mPreviousMaturity) - << "' to '" << LLViewerRegion::accessToString(mPreferredMaturity) << "', the server responded with '" - << LLViewerRegion::accessToString(actualMaturity) << "' [value:" << static_cast(actualMaturity) << ", llsd:" - << pContent << "]" << llendl; + LL_WARNS() << "while attempting to change maturity preference from '" + << LLViewerRegion::accessToString(mPreviousMaturity) + << "' to '" << LLViewerRegion::accessToString(mPreferredMaturity) + << "', the server responded with '" + << LLViewerRegion::accessToString(actualMaturity) + << "' [value:" << static_cast(actualMaturity) + << "], " << dumpResponse() << LL_ENDL; } mAgent->handlePreferredMaturityResult(actualMaturity); } -void LLMaturityPreferencesResponder::error(U32 pStatus, const std::string& pReason) +void LLMaturityPreferencesResponder::httpFailure() { - llwarns << "while attempting to change maturity preference from '" << LLViewerRegion::accessToString(mPreviousMaturity) - << "' to '" << LLViewerRegion::accessToString(mPreferredMaturity) << "', we got an error because '" - << pReason << "' [status:" << pStatus << "]" << llendl; + LL_WARNS() << "while attempting to change maturity preference from '" + << LLViewerRegion::accessToString(mPreviousMaturity) + << "' to '" << LLViewerRegion::accessToString(mPreferredMaturity) + << "', " << dumpResponse() << LL_ENDL; mAgent->handlePreferredMaturityError(); } -U8 LLMaturityPreferencesResponder::parseMaturityFromServerResponse(const LLSD &pContent) +U8 LLMaturityPreferencesResponder::parseMaturityFromServerResponse(const LLSD &pContent) const { - // stinson 05/24/2012 Pathfinding regions have re-defined the response behavior. In the old server code, - // if you attempted to change the preferred maturity to the same value, the response content would be an - // undefined LLSD block. In the new server code with pathfinding, the response content should always be - // defined. Thus, the check for isUndefined() can be replaced with an assert after pathfinding is merged - // into server trunk and fully deployed. U8 maturity = SIM_ACCESS_MIN; - if (pContent.isUndefined()) + + llassert(pContent.isDefined()); + llassert(pContent.isMap()); + llassert(pContent.has("access_prefs")); + llassert(pContent.get("access_prefs").isMap()); + llassert(pContent.get("access_prefs").has("max")); + llassert(pContent.get("access_prefs").get("max").isString()); + if (pContent.isDefined() && pContent.isMap() && pContent.has("access_prefs") + && pContent.get("access_prefs").isMap() && pContent.get("access_prefs").has("max") + && pContent.get("access_prefs").get("max").isString()) { - maturity = mPreferredMaturity; - } - else - { - llassert(!pContent.isUndefined()); - llassert(pContent.isMap()); - - if (!pContent.isUndefined() && pContent.isMap()) - { - // stinson 05/24/2012 Pathfinding regions have re-defined the response syntax. The if statement catches - // the new syntax, and the else statement catches the old syntax. After pathfinding is merged into - // server trunk and fully deployed, we can remove the else statement. - if (pContent.has("access_prefs")) - { - llassert(pContent.has("access_prefs")); - llassert(pContent.get("access_prefs").isMap()); - llassert(pContent.get("access_prefs").has("max")); - llassert(pContent.get("access_prefs").get("max").isString()); - if (pContent.get("access_prefs").isMap() && pContent.get("access_prefs").has("max") && - pContent.get("access_prefs").get("max").isString()) - { - LLSD::String actualPreference = pContent.get("access_prefs").get("max").asString(); - LLStringUtil::trim(actualPreference); - maturity = LLViewerRegion::shortStringToAccess(actualPreference); - } - } - else if (pContent.has("max")) - { - llassert(pContent.get("max").isString()); - if (pContent.get("max").isString()) - { - LLSD::String actualPreference = pContent.get("max").asString(); - LLStringUtil::trim(actualPreference); - maturity = LLViewerRegion::shortStringToAccess(actualPreference); - } - } - } + LLSD::String actualPreference = pContent.get("access_prefs").get("max").asString(); + LLStringUtil::trim(actualPreference); + maturity = LLViewerRegion::shortStringToAccess(actualPreference); } return maturity; @@ -2681,8 +2819,8 @@ void LLAgent::handlePreferredMaturityResult(U8 pServerMaturity) // server by re-sending our last known request. Cap the re-tries at 3 just to be safe. else if (++mMaturityPreferenceNumRetries <= 3) { - llinfos << "Retrying attempt #" << mMaturityPreferenceNumRetries << " to set viewer preferred maturity to '" - << LLViewerRegion::accessToString(mLastKnownRequestMaturity) << "'" << llendl; + LL_INFOS() << "Retrying attempt #" << mMaturityPreferenceNumRetries << " to set viewer preferred maturity to '" + << LLViewerRegion::accessToString(mLastKnownRequestMaturity) << "'" << LL_ENDL; sendMaturityPreferenceToServer(mLastKnownRequestMaturity); } // Else, the viewer is style out of sync with the server after 3 retries, so inform the user @@ -2709,8 +2847,8 @@ void LLAgent::handlePreferredMaturityError() // the server, but not quite sure why we are if (mLastKnownRequestMaturity == mLastKnownResponseMaturity) { - llwarns << "Got an error but maturity preference '" << LLViewerRegion::accessToString(mLastKnownRequestMaturity) - << "' seems to be in sync with the server" << llendl; + LL_WARNS() << "Got an error but maturity preference '" << LLViewerRegion::accessToString(mLastKnownRequestMaturity) + << "' seems to be in sync with the server" << LL_ENDL; reportPreferredMaturitySuccess(); } // Else, the more likely case is that the last request does not match the last response, @@ -2764,7 +2902,7 @@ void LLAgent::reportPreferredMaturityError() { bool tmpIsDoSendMaturityPreferenceToServer = mIsDoSendMaturityPreferenceToServer; mIsDoSendMaturityPreferenceToServer = false; - llinfos << "Setting viewer preferred maturity to '" << LLViewerRegion::accessToString(mLastKnownResponseMaturity) << "'" << llendl; + LL_INFOS() << "Setting viewer preferred maturity to '" << LLViewerRegion::accessToString(mLastKnownResponseMaturity) << "'" << LL_ENDL; gSavedSettings.setU32("PreferredMaturity", static_cast(mLastKnownResponseMaturity)); mIsDoSendMaturityPreferenceToServer = tmpIsDoSendMaturityPreferenceToServer; } @@ -2787,12 +2925,12 @@ void LLAgent::sendMaturityPreferenceToServer(U8 pPreferredMaturity) mLastKnownRequestMaturity = pPreferredMaturity; // Create a response handler - boost::intrusive_ptr responderPtr = new LLMaturityPreferencesResponder(this, pPreferredMaturity, mLastKnownResponseMaturity); + boost::intrusive_ptr responderPtr = boost::intrusive_ptr(new LLMaturityPreferencesResponder(this, pPreferredMaturity, mLastKnownResponseMaturity)); // If we don't have a region, report it as an error - if (getRegion() == NULL) + if (getRegion() == nullptr) { - responderPtr->error(0U, "region is not defined"); + responderPtr->failureResult(0U, "region is not defined", LLSD()); } else { @@ -2802,7 +2940,8 @@ void LLAgent::sendMaturityPreferenceToServer(U8 pPreferredMaturity) // If the capability is not defined, report it as an error if (url.empty()) { - responderPtr->error(0U, "capability 'UpdateAgentInformation' is not defined for region"); + responderPtr->failureResult(0U, + "capability 'UpdateAgentInformation' is not defined for region", LLSD()); } else { @@ -2812,8 +2951,8 @@ void LLAgent::sendMaturityPreferenceToServer(U8 pPreferredMaturity) LLSD body = LLSD::emptyMap(); body["access_prefs"] = access_prefs; - llinfos << "Sending viewer preferred maturity to '" << LLViewerRegion::accessToString(pPreferredMaturity) - << "' via capability to: " << url << llendl; + LL_INFOS() << "Sending viewer preferred maturity to '" << LLViewerRegion::accessToString(pPreferredMaturity) + << "' via capability to: " << url << LL_ENDL; LLHTTPClient::post(url, body, responderPtr); } } @@ -2846,11 +2985,6 @@ LLAgent::god_level_change_slot_t LLAgent::registerGodLevelChanageListener(god_le return mGodLevelChangeSignal.connect(pGodLevelChangeCallback); } -void LLAgent::setAOTransition() -{ - mAgentAccess->setTransition(); -} - const LLAgentAccess& LLAgent::getAgentAccess() { return *mAgentAccess; @@ -2866,14 +3000,9 @@ void LLAgent::handleMaturity(const LLSD &pNewValue) sendMaturityPreferenceToServer(static_cast(pNewValue.asInteger())); } -void LLAgent::buildFullname(std::string& name) const -{ - if (isAgentAvatarValid()) - { - name = gAgentAvatarp->getFullname(); - } -} +//---------------------------------------------------------------------------- +//*TODO remove, is not used anywhere as of August 20, 2009 void LLAgent::buildFullnameAndTitle(std::string& name) const { if (isGroupMember()) @@ -2897,10 +3026,10 @@ BOOL LLAgent::isInGroup(const LLUUID& group_id, BOOL ignore_god_mode /* FALSE */ if (!ignore_god_mode && isGodlike()) return true; - S32 count = mGroups.count(); - for(S32 i = 0; i < count; ++i) + U32 count = mGroups.size(); + for(U32 i = 0; i < count; ++i) { - if(mGroups.get(i).mID == group_id) + if(mGroups[i].mID == group_id) { return TRUE; } @@ -2917,12 +3046,12 @@ BOOL LLAgent::hasPowerInGroup(const LLUUID& group_id, U64 power) const // GP_NO_POWERS can also mean no power is enough to grant an ability. if (GP_NO_POWERS == power) return FALSE; - S32 count = mGroups.count(); - for(S32 i = 0; i < count; ++i) + U32 count = mGroups.size(); + for(U32 i = 0; i < count; ++i) { - if(mGroups.get(i).mID == group_id) + if(mGroups[i].mID == group_id) { - return (BOOL)((mGroups.get(i).mPowers & power) > 0); + return (BOOL)((mGroups[i].mPowers & power) > 0); } } return FALSE; @@ -2938,12 +3067,12 @@ U64 LLAgent::getPowerInGroup(const LLUUID& group_id) const if (isGodlike()) return GP_ALL_POWERS; - S32 count = mGroups.count(); - for(S32 i = 0; i < count; ++i) + U32 count = mGroups.size(); + for(U32 i = 0; i < count; ++i) { - if(mGroups.get(i).mID == group_id) + if(mGroups[i].mID == group_id) { - return (mGroups.get(i).mPowers); + return (mGroups[i].mPowers); } } @@ -2952,12 +3081,12 @@ U64 LLAgent::getPowerInGroup(const LLUUID& group_id) const BOOL LLAgent::getGroupData(const LLUUID& group_id, LLGroupData& data) const { - S32 count = mGroups.count(); + S32 count = mGroups.size(); for(S32 i = 0; i < count; ++i) { - if(mGroups.get(i).mID == group_id) + if(mGroups[i].mID == group_id) { - data = mGroups.get(i); + data = mGroups[i]; return TRUE; } } @@ -2966,12 +3095,12 @@ BOOL LLAgent::getGroupData(const LLUUID& group_id, LLGroupData& data) const S32 LLAgent::getGroupContribution(const LLUUID& group_id) const { - S32 count = mGroups.count(); + S32 count = mGroups.size(); for(S32 i = 0; i < count; ++i) { - if(mGroups.get(i).mID == group_id) + if(mGroups[i].mID == group_id) { - S32 contribution = mGroups.get(i).mContribution; + S32 contribution = mGroups[i].mContribution; return contribution; } } @@ -2980,12 +3109,12 @@ S32 LLAgent::getGroupContribution(const LLUUID& group_id) const BOOL LLAgent::setGroupContribution(const LLUUID& group_id, S32 contribution) { - S32 count = mGroups.count(); + S32 count = mGroups.size(); for(S32 i = 0; i < count; ++i) { - if(mGroups.get(i).mID == group_id) + if(mGroups[i].mID == group_id) { - mGroups.get(i).mContribution = contribution; + mGroups[i].mContribution = contribution; LLMessageSystem* msg = gMessageSystem; msg->newMessage("SetGroupContribution"); msg->nextBlock("AgentData"); @@ -3003,14 +3132,13 @@ BOOL LLAgent::setGroupContribution(const LLUUID& group_id, S32 contribution) BOOL LLAgent::setUserGroupFlags(const LLUUID& group_id, BOOL accept_notices, BOOL list_in_profile) { - S32 count = mGroups.count(); + S32 count = mGroups.size(); for(S32 i = 0; i < count; ++i) { - LLGroupData &group = mGroups.get(i); - if(group.mID == group_id) + if(mGroups[i].mID == group_id) { - group.mAcceptNotices = accept_notices; - group.mListInProfile = list_in_profile; + mGroups[i].mAcceptNotices = accept_notices; + mGroups[i].mListInProfile = list_in_profile; LLMessageSystem* msg = gMessageSystem; msg->newMessage("SetGroupAcceptNotices"); msg->nextBlock("AgentData"); @@ -3023,7 +3151,7 @@ BOOL LLAgent::setUserGroupFlags(const LLUUID& group_id, BOOL accept_notices, BOO msg->addBOOL("ListInProfile", list_in_profile); sendReliableMessage(); - update_group_floaters(group.mID); + update_group_floaters(mGroups[i].mID); return TRUE; } @@ -3031,6 +3159,10 @@ BOOL LLAgent::setUserGroupFlags(const LLUUID& group_id, BOOL accept_notices, BOO return FALSE; } +BOOL LLAgent::canJoinGroups() const +{ + return (S32)mGroups.size() < LLAgentBenefitsMgr::current().getGroupMembershipLimit(); +} LLQuaternion LLAgent::getHeadRotation() { @@ -3058,7 +3190,7 @@ LLQuaternion LLAgent::getHeadRotation() return rot; } -void LLAgent::sendAnimationRequests(LLDynamicArray &anim_ids, EAnimRequest request) +void LLAgent::sendAnimationRequests(const uuid_vec_t &anim_ids, EAnimRequest request) { if (gAgentID.isNull()) { @@ -3073,24 +3205,27 @@ void LLAgent::sendAnimationRequests(LLDynamicArray &anim_ids, EAnimReque msg->addUUIDFast(_PREHASH_AgentID, getID()); msg->addUUIDFast(_PREHASH_SessionID, getSessionID()); - for (S32 i = 0; i < anim_ids.count(); i++) + for (auto anim_id : anim_ids) { - if (anim_ids[i].isNull()) + if (anim_id.isNull()) { continue; } msg->nextBlockFast(_PREHASH_AnimationList); - msg->addUUIDFast(_PREHASH_AnimID, (anim_ids[i]) ); + msg->addUUIDFast(_PREHASH_AnimID, anim_id); msg->addBOOLFast(_PREHASH_StartAnim, (request == ANIM_REQUEST_START) ? TRUE : FALSE); num_valid_anims++; } - - msg->nextBlockFast(_PREHASH_PhysicalAvatarEventList); - msg->addBinaryDataFast(_PREHASH_TypeData, NULL, 0); - if (num_valid_anims) + if (!num_valid_anims) { - sendReliableMessage(); + msg->clearMessage(); + return; } + + msg->nextBlockFast(_PREHASH_PhysicalAvatarEventList); + msg->addBinaryDataFast(_PREHASH_TypeData, nullptr, 0); + + sendReliableMessage(); } void LLAgent::sendAnimationRequest(const LLUUID &anim_id, EAnimRequest request) @@ -3111,10 +3246,59 @@ void LLAgent::sendAnimationRequest(const LLUUID &anim_id, EAnimRequest request) msg->addBOOLFast(_PREHASH_StartAnim, (request == ANIM_REQUEST_START) ? TRUE : FALSE); msg->nextBlockFast(_PREHASH_PhysicalAvatarEventList); - msg->addBinaryDataFast(_PREHASH_TypeData, NULL, 0); + msg->addBinaryDataFast(_PREHASH_TypeData, nullptr, 0); + sendReliableMessage(); +} + +// Send a message to the region to stop the NULL animation state +// This will reset animation state overrides for the agent. +void LLAgent::sendAnimationStateReset() +{ + if (gAgentID.isNull() || !mRegionp) + { + return; + } + + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_AgentAnimation); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, getID()); + msg->addUUIDFast(_PREHASH_SessionID, getSessionID()); + + msg->nextBlockFast(_PREHASH_AnimationList); + msg->addUUIDFast(_PREHASH_AnimID, LLUUID::null ); + msg->addBOOLFast(_PREHASH_StartAnim, FALSE); + + msg->nextBlockFast(_PREHASH_PhysicalAvatarEventList); + msg->addBinaryDataFast(_PREHASH_TypeData, nullptr, 0); sendReliableMessage(); } + +// Send a message to the region to revoke sepecified permissions on ALL scripts in the region +// If the target is an object in the region, permissions in scripts on that object are cleared. +// If it is the region ID, all scripts clear the permissions for this agent +void LLAgent::sendRevokePermissions(const LLUUID & target, U32 permissions) +{ + // Currently only the bits for SCRIPT_PERMISSION_TRIGGER_ANIMATION and SCRIPT_PERMISSION_OVERRIDE_ANIMATIONS + // are supported by the server. Sending any other bits will cause the message to be dropped without changing permissions + + if (gAgentID.notNull() && gMessageSystem) + { + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_RevokePermissions); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, getID()); // Must be our ID + msg->addUUIDFast(_PREHASH_SessionID, getSessionID()); + + msg->nextBlockFast(_PREHASH_Data); + msg->addUUIDFast(_PREHASH_ObjectID, target); // Must be in the region + msg->addS32Fast(_PREHASH_ObjectPermissions, (S32) permissions); + + sendReliableMessage(); + } +} + // [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i void LLAgent::setAlwaysRun() { @@ -3225,32 +3409,19 @@ BOOL LLAgent::allowOperation(PermissionBit op, return perm.allowOperationBy(op, agent_proxy, group_proxy); } -void LLAgent::getName(std::string& name) +const LLColor4 LLAgent::getEffectColor() { - name.clear(); + LLColor4 effect_color = *mEffectColor; - if (gAgentAvatarp) - { - LLNameValue *first_nv = gAgentAvatarp->getNVPair("FirstName"); - LLNameValue *last_nv = gAgentAvatarp->getNVPair("LastName"); - if (first_nv && last_nv) - { - name = first_nv->printData() + " " + last_nv->printData(); - } - else - { - llwarns << "Agent is missing FirstName and/or LastName nv pair." << llendl; - } - } - else + // Rainbow Particle Effects + static LLCachedControl AlchemyRainbowEffects(gSavedSettings, "AlchemyRainbowEffects"); + if(AlchemyRainbowEffects) { - name = gSavedSettings.getString("FirstName") + " " + gSavedSettings.getString("LastName"); + LLColor3 rainbow; + rainbow.setHSL(fmodf((F32)LLFrameTimer::getElapsedSeconds()/4.f, 1.f), 1.f, 0.5f); + effect_color.set(rainbow, 1.0f); } -} - -const LLColor4 &LLAgent::getEffectColor() -{ - return *mEffectColor; + return effect_color; } void LLAgent::setEffectColor(const LLColor4 &color) @@ -3272,6 +3443,13 @@ BOOL LLAgent::leftButtonGrabbed() const || (camera_mouse_look && mControlsTakenPassedOnCount[CONTROL_ML_LBUTTON_DOWN_INDEX] > 0); } +BOOL LLAgent::leftButtonBlocked() const +{ + const BOOL camera_mouse_look = gAgentCamera.cameraMouselook(); + return (!camera_mouse_look && mControlsTakenCount[CONTROL_LBUTTON_DOWN_INDEX] > 0) + || (camera_mouse_look && mControlsTakenCount[CONTROL_ML_LBUTTON_DOWN_INDEX] > 0); +} + BOOL LLAgent::rotateGrabbed() const { return (mControlsTakenCount[CONTROL_YAW_POS_INDEX] > 0) @@ -3300,6 +3478,7 @@ BOOL LLAgent::downGrabbed() const void update_group_floaters(const LLUUID& group_id) { + LLGroupActions::refresh(group_id); // update avatar info @@ -3309,12 +3488,6 @@ void update_group_floaters(const LLUUID& group_id) fa->resetGroupList(); } - if (gIMMgr) - { - // update the talk view - gIMMgr->refresh(); - } - gAgent.fireEvent(new LLOldEvents::LLEvent(&gAgent, "new group"), ""); } @@ -3326,7 +3499,7 @@ void LLAgent::processAgentDropGroup(LLMessageSystem *msg, void **) if (agent_id != gAgentID) { - llwarns << "processAgentDropGroup for agent other than me" << llendl; + LL_WARNS() << "processAgentDropGroup for agent other than me" << LL_ENDL; return; } @@ -3336,10 +3509,10 @@ void LLAgent::processAgentDropGroup(LLMessageSystem *msg, void **) // Remove the group if it already exists remove it and add the new data to pick up changes. LLGroupData gd; gd.mID = group_id; - S32 index = gAgent.mGroups.find(gd); - if (index != -1) + auto found_it = std::find(gAgent.mGroups.cbegin(), gAgent.mGroups.cend(), gd); + if (found_it != gAgent.mGroups.cend()) { - gAgent.mGroups.remove(index); + gAgent.mGroups.erase(found_it); if (gAgent.getGroupID() == group_id) { gAgent.mGroupID.setNull(); @@ -3359,16 +3532,16 @@ void LLAgent::processAgentDropGroup(LLMessageSystem *msg, void **) } else { - llwarns << "processAgentDropGroup, agent is not part of group " << group_id << llendl; + LL_WARNS() << "processAgentDropGroup, agent is not part of group " << group_id << LL_ENDL; } } -class LLAgentDropGroupViewerNode : public LLHTTPNode +class LLAgentDropGroupViewerNode final : public LLHTTPNode { - virtual void post( + void post( LLHTTPNode::ResponsePtr response, const LLSD& context, - const LLSD& input) const + const LLSD& input) const override { if ( @@ -3376,8 +3549,7 @@ class LLAgentDropGroupViewerNode : public LLHTTPNode !input.has("body") ) { //what to do with badly formed message? - response->statusUnknownError(400); - response->result(LLSD("Invalid message parameters")); + response->extendedResult(HTTP_BAD_REQUEST, "", LLSD("Invalid message parameters")); } LLSD body = input["body"]; @@ -3392,20 +3564,17 @@ class LLAgentDropGroupViewerNode : public LLHTTPNode body["AgentData"].isArray() && body["AgentData"][0].isMap() ) { - llinfos << "VALID DROP GROUP" << llendl; + LL_INFOS() << "VALID DROP GROUP" << LL_ENDL; //there is only one set of data in the AgentData block LLSD agent_data = body["AgentData"][0]; - LLUUID agent_id; - LLUUID group_id; - - agent_id = agent_data["AgentID"].asUUID(); - group_id = agent_data["GroupID"].asUUID(); + LLUUID agent_id = agent_data["AgentID"].asUUID(); + LLUUID group_id = agent_data["GroupID"].asUUID(); if (agent_id != gAgentID) { - llwarns - << "AgentDropGroup for agent other than me" << llendl; + LL_WARNS() + << "AgentDropGroup for agent other than me" << LL_ENDL; response->notFound(); return; @@ -3415,10 +3584,10 @@ class LLAgentDropGroupViewerNode : public LLHTTPNode // and add the new data to pick up changes. LLGroupData gd; gd.mID = group_id; - S32 index = gAgent.mGroups.find(gd); - if (index != -1) + auto found_it = std::find(gAgent.mGroups.cbegin(), gAgent.mGroups.cend(), gd); + if (found_it != gAgent.mGroups.cend()) { - gAgent.mGroups.remove(index); + gAgent.mGroups.erase(found_it); if (gAgent.getGroupID() == group_id) { gAgent.mGroupID.setNull(); @@ -3439,9 +3608,9 @@ class LLAgentDropGroupViewerNode : public LLHTTPNode } else { - llwarns + LL_WARNS() << "AgentDropGroup, agent is not part of group " - << group_id << llendl; + << group_id << LL_ENDL; } response->result(LLSD()); @@ -3449,8 +3618,7 @@ class LLAgentDropGroupViewerNode : public LLHTTPNode else { //what to do with badly formed message? - response->statusUnknownError(400); - response->result(LLSD("Invalid message parameters")); + response->extendedResult(HTTP_BAD_REQUEST, "", LLSD("Invalid message parameters")); } } }; @@ -3468,13 +3636,12 @@ void LLAgent::processAgentGroupDataUpdate(LLMessageSystem *msg, void **) if (agent_id != gAgentID) { - llwarns << "processAgentGroupDataUpdate for agent other than me" << llendl; + LL_WARNS() << "processAgentGroupDataUpdate for agent other than me" << LL_ENDL; return; } S32 count = msg->getNumberOfBlocksFast(_PREHASH_GroupData); LLGroupData group; - S32 index = -1; bool need_floater_update = false; for(S32 i = 0; i < count; ++i) { @@ -3489,12 +3656,12 @@ void LLAgent::processAgentGroupDataUpdate(LLMessageSystem *msg, void **) { need_floater_update = true; // Remove the group if it already exists remove it and add the new data to pick up changes. - index = gAgent.mGroups.find(group); - if (index != -1) + auto found_it = std::find(gAgent.mGroups.cbegin(), gAgent.mGroups.cend(), group); + if (found_it != gAgent.mGroups.cend()) { - gAgent.mGroups.remove(index); + gAgent.mGroups.erase(found_it); } - gAgent.mGroups.put(group); + gAgent.mGroups.push_back(group); } if (need_floater_update) { @@ -3504,12 +3671,12 @@ void LLAgent::processAgentGroupDataUpdate(LLMessageSystem *msg, void **) } -class LLAgentGroupDataUpdateViewerNode : public LLHTTPNode +class LLAgentGroupDataUpdateViewerNode final : public LLHTTPNode { - virtual void post( + void post( LLHTTPNode::ResponsePtr response, const LLSD& context, - const LLSD& input) const + const LLSD& input) const override { LLSD body = input["body"]; if(body.has("body")) @@ -3518,7 +3685,7 @@ class LLAgentGroupDataUpdateViewerNode : public LLHTTPNode if (agent_id != gAgentID) { - llwarns << "processAgentGroupDataUpdate for agent other than me" << llendl; + LL_WARNS() << "processAgentGroupDataUpdate for agent other than me" << LL_ENDL; return; } @@ -3533,7 +3700,6 @@ class LLAgentGroupDataUpdateViewerNode : public LLHTTPNode { LLGroupData group; - S32 index = -1; bool need_floater_update = false; group.mID = (*iter_group)["GroupID"].asUUID(); @@ -3550,12 +3716,12 @@ class LLAgentGroupDataUpdateViewerNode : public LLHTTPNode { need_floater_update = true; // Remove the group if it already exists remove it and add the new data to pick up changes. - index = gAgent.mGroups.find(group); - if (index != -1) + auto found_it = std::find(gAgent.mGroups.cbegin(), gAgent.mGroups.cend(), group); + if (found_it != gAgent.mGroups.cend()) { - gAgent.mGroups.remove(index); + gAgent.mGroups.erase(found_it); } - gAgent.mGroups.put(group); + gAgent.mGroups.push_back(group); } if (need_floater_update) { @@ -3577,7 +3743,7 @@ void LLAgent::processAgentDataUpdate(LLMessageSystem *msg, void **) if (agent_id != gAgentID) { - llwarns << "processAgentDataUpdate for agent other than me" << llendl; + LL_WARNS() << "processAgentDataUpdate for agent other than me" << LL_ENDL; return; } @@ -3634,12 +3800,9 @@ void LLAgent::processScriptControlChange(LLMessageSystem *msg, void **) total_count++; } } - + // Any control taken? If so, might be first time. - if (total_count > 0) - { - LLFirstUse::useOverrideKeys(); - } + if (total_count > 0) LLFirstUse::useOverrideKeys(); } else { @@ -3751,7 +3914,7 @@ void LLAgent::processAgentCachedTextureResponse(LLMessageSystem *mesgsys, void * if (!isAgentAvatarValid() || gAgentAvatarp->isDead()) { - llwarns << "No avatar for user in cached texture update!" << llendl; + LL_WARNS() << "No avatar for user in cached texture update!" << LL_ENDL; return; } @@ -3788,7 +3951,7 @@ void LLAgent::processAgentCachedTextureResponse(LLMessageSystem *mesgsys, void * { if (texture_id.notNull()) { - //llinfos << "Received cached texture " << (U32)texture_index << ": " << texture_id << llendl; + //LL_INFOS() << "Received cached texture " << (U32)texture_index << ": " << texture_id << LL_ENDL; gAgentAvatarp->setCachedBakedTexture((ETextureIndex)texture_index, texture_id); //gAgentAvatarp->setTETexture( LLVOAvatar::sBakedTextureIndices[texture_index], texture_id ); gAgentQueryManager.mActiveCacheQueries[baked_index] = 0; @@ -3803,7 +3966,7 @@ void LLAgent::processAgentCachedTextureResponse(LLMessageSystem *mesgsys, void * } } } - llinfos << "Received cached texture response for " << num_results << " textures." << llendl; + LL_INFOS() << "Received cached texture response for " << num_results << " textures." << LL_ENDL; gAgentAvatarp->outputRezTiming("Fetched agent wearables textures from cache. Will now load them"); gAgentAvatarp->updateMeshTextures(); @@ -3829,6 +3992,13 @@ BOOL LLAgent::anyControlGrabbed() const } BOOL LLAgent::isControlGrabbed(S32 control_index) const +{ + if (gAgent.mControlsTakenCount[control_index] > 0) + return TRUE; + return gAgent.mControlsTakenPassedOnCount[control_index] > 0; +} + +BOOL LLAgent::isControlBlocked(S32 control_index) const { return mControlsTakenCount[control_index] > 0; } @@ -3879,9 +4049,10 @@ void LLAgent::clearVisualParams(void *data) // protected bool LLAgent::teleportCore(bool is_local) { + LL_INFOS("Teleport") << "In teleport core!" << LL_ENDL; if ((TELEPORT_NONE != mTeleportState) && (mTeleportState != TELEPORT_PENDING)) { - llwarns << "Attempt to teleport when already teleporting." << llendl; + LL_WARNS() << "Attempt to teleport when already teleporting." << LL_ENDL; // //return false; teleportCancel(); @@ -3896,7 +4067,7 @@ bool LLAgent::teleportCore(bool is_local) // Stop all animation before actual teleporting if (isAgentAvatarValid()) { - for ( LLVOAvatar::AnimIterator anim_it= gAgentAvatarp->mPlayingAnimations.begin(); + for ( auto anim_it= gAgentAvatarp->mPlayingAnimations.begin(); anim_it != gAgentAvatarp->mPlayingAnimations.end(); ++anim_it) { @@ -3915,7 +4086,7 @@ bool LLAgent::teleportCore(bool is_local) LLFloaterWorldMap::hide(); // hide land floater too - it'll be out of date - LLFloaterLand::hideInstance(); + if (LLFloaterLand::findInstance()) LLFloaterLand::hideInstance(); LLViewerParcelMgr::getInstance()->deselectLand(); LLViewerMediaFocus::getInstance()->clearFocus(); @@ -3938,12 +4109,16 @@ bool LLAgent::teleportCore(bool is_local) gTeleportDisplay = TRUE; gAgent.setTeleportState( LLAgent::TELEPORT_START ); - /*static const LLCachedControl hide_tp_screen("AscentDisableTeleportScreens",false); - if(!hide_tp_screen) + static const LLCachedControl hide_tp_screen("AscentDisableTeleportScreens",false); + static const LLCachedControl skip_reset_objects_on_teleport("SHSkipResetVBOsOnTeleport", false); + if(!hide_tp_screen && !skip_reset_objects_on_teleport) { + // AscentDisableTeleportScreens TRUE might be broken..*/ + //release geometry from old location gPipeline.resetVertexBuffers(); - }*/ + LLSpatialPartition::sTeleportRequested = TRUE; + } if (gSavedSettings.getBOOL("SpeedRez")) { @@ -4042,6 +4217,12 @@ void LLAgent::handleTeleportFinished() LLNotificationsUtil::add("PreferredMaturityChanged", args); mIsMaturityRatingChangingDuringTeleport = false; } + + // Init SLM Marketplace connection so we know which UI should be used for the user as a merchant + // Note: Eventually, all merchant will be migrated to the new SLM system and there will be no reason to show the old UI at all. + // Note: Some regions will not support the SLM cap for a while so we need to do that check for each teleport. + // *TODO : Suppress that line from here once the whole grid migrated to SLM and move it to idle_startup() (llstartup.cpp) + check_merchant_status(); } void LLAgent::handleTeleportFailed() @@ -4180,11 +4361,24 @@ void LLAgent::teleportCancel() msg->addUUIDFast(_PREHASH_SessionID, getSessionID()); sendReliableMessage(); } + mTeleportCanceled = mTeleportRequest; } clearTeleportRequest(); gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); + gPipeline.resetVertexBuffers(); } +void LLAgent::restoreCanceledTeleportRequest() +{ + if (mTeleportCanceled != NULL) + { + gAgent.setTeleportState( LLAgent::TELEPORT_REQUESTED ); + mTeleportRequest = mTeleportCanceled; + mTeleportCanceled.reset(); + gTeleportDisplay = TRUE; + gTeleportDisplayTimer.reset(); + } +} void LLAgent::teleportViaLocation(const LLVector3d& pos_global) { @@ -4233,13 +4427,15 @@ void LLAgent::doTeleportViaLocation(const LLVector3d& pos_global) (F32)(pos_global.mdV[VX] - region_origin.mdV[VX]), (F32)(pos_global.mdV[VY] - region_origin.mdV[VY]), (F32)(pos_global.mdV[VZ])); - pos_local += offset; - teleportRequest(handle, pos_local); +// Aurora-sim var region teleports + //teleportRequest(handle, pos_local); + teleportRequest(info->getHandle(), pos_local); +// } else if(regionp && teleportCore(regionp->getHandle() == to_region_handle_global((F32)pos_global.mdV[VX], (F32)pos_global.mdV[VY]))) { - llwarns << "Using deprecated teleportlocationrequest." << llendl; + LL_WARNS() << "Using deprecated teleportlocationrequest." << LL_ENDL; // send the message LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_TeleportLocationRequest); @@ -4273,7 +4469,7 @@ void LLAgent::teleportViaLocationLookAt(const LLVector3d& pos_global) // [RLVa:KB] - Checked: 2010-10-07 (RLVa-1.2.1f) | Added: RLVa-1.2.1f // RELEASE-RLVa: [SL-2.2.0] Make sure this isn't used for anything except double-click teleporting if ( (rlv_handler_t::isEnabled()) && (!RlvUtil::isForceTp()) && - ((gRlvHandler.hasBehaviour(RLV_BHVR_SITTP)) || (!gRlvHandler.canStand())) ) + ((gRlvHandler.hasBehaviour(RLV_BHVR_SITTP)) || (!RlvActions::canStand())) ) { RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_TELEPORT); return; @@ -4287,14 +4483,39 @@ void LLAgent::teleportViaLocationLookAt(const LLVector3d& pos_global) void LLAgent::doTeleportViaLocationLookAt(const LLVector3d& pos_global) { mbTeleportKeepsLookAt = true; - gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE); // detach camera form avatar, so it keeps direction + + if(!gAgentCamera.isfollowCamLocked()) + { + gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE); // detach camera form avatar, so it keeps direction + } U64 region_handle = to_region_handle(pos_global); +// Aurora-sim var region teleports + LLSimInfo* simInfo = LLWorldMap::instance().simInfoFromHandle(region_handle); + if (simInfo) + { + region_handle = simInfo->getHandle(); + } +// LLVector3 pos_local = (LLVector3)(pos_global - from_region_handle(region_handle)); teleportRequest(region_handle, pos_local, getTeleportKeepsLookAt()); } +LLAgent::ETeleportState LLAgent::getTeleportState() const +{ + return (mTeleportRequest && (mTeleportRequest->getStatus() == LLTeleportRequest::kFailed)) ? + TELEPORT_NONE : mTeleportState; +} + + void LLAgent::setTeleportState(ETeleportState state) { + if (mTeleportRequest && (state != TELEPORT_NONE) && (mTeleportRequest->getStatus() == LLTeleportRequest::kFailed)) + { // A late message has come in regarding a failed teleport. + // We have already decided that it failed so should not reinitiate the teleport sequence in the viewer. + LL_WARNS("Teleport") << "Attempt to set teleport state to " << state << + " for previously failed teleport. Ignore!" << LL_ENDL; + return; + } mTeleportState = state; static const LLCachedControl freeze_time("FreezeTime",false); if (mTeleportState > TELEPORT_NONE && freeze_time) @@ -4306,6 +4527,7 @@ void LLAgent::setTeleportState(ETeleportState state) { case TELEPORT_NONE: mbTeleportKeepsLookAt = false; + mIsCrossingRegion = false; // Attachments getting lost on TP; finished TP break; case TELEPORT_MOVING: @@ -4332,6 +4554,8 @@ void LLAgent::stopCurrentAnimations() // avatar, propagating this change back to the server. if (isAgentAvatarValid()) { + uuid_vec_t anim_ids; + for ( LLVOAvatar::AnimIterator anim_it = gAgentAvatarp->mPlayingAnimations.begin(); anim_it != gAgentAvatarp->mPlayingAnimations.end(); @@ -4349,14 +4573,30 @@ void LLAgent::stopCurrentAnimations() // stop this animation locally gAgentAvatarp->stopMotion(anim_it->first, TRUE); // ...and tell the server to tell everyone. - sendAnimationRequest(anim_it->first, ANIM_REQUEST_STOP); + anim_ids.push_back(anim_it->first); + } + } + + sendAnimationRequests(anim_ids, ANIM_REQUEST_STOP); + + // Tell the region to clear any animation state overrides + sendAnimationStateReset(); + + // Revoke all animation permissions + if (mRegionp && + gSavedSettings.getBOOL("RevokePermsOnStopAnimation")) + { + U32 permissions = LSCRIPTRunTimePermissionBits[SCRIPT_PERMISSION_TRIGGER_ANIMATION] | LSCRIPTRunTimePermissionBits[SCRIPT_PERMISSION_OVERRIDE_ANIMATIONS]; + sendRevokePermissions(mRegionp->getRegionID(), permissions); + if (gAgentAvatarp->isSitting()) + { // Also stand up, since auto-granted sit animation permission has been revoked + gAgent.standUp(); } } // re-assert at least the default standing animation, because // viewers get confused by avs with no associated anims. - sendAnimationRequest(ANIM_AGENT_STAND, - ANIM_REQUEST_START); + sendAnimationRequest(ANIM_AGENT_STAND, ANIM_REQUEST_START); } } @@ -4413,11 +4653,12 @@ void LLAgent::fidget() void LLAgent::stopFidget() { - LLDynamicArray anims; - anims.put(ANIM_AGENT_STAND_1); - anims.put(ANIM_AGENT_STAND_2); - anims.put(ANIM_AGENT_STAND_3); - anims.put(ANIM_AGENT_STAND_4); + const uuid_vec_t anims { + ANIM_AGENT_STAND_1, + ANIM_AGENT_STAND_2, + ANIM_AGENT_STAND_3, + ANIM_AGENT_STAND_4, + }; gAgent.sendAnimationRequests(anims, ANIM_REQUEST_STOP); } @@ -4453,7 +4694,7 @@ void LLAgent::requestLeaveGodMode() sendReliableMessage(); } -extern void dump_visual_param(LLAPRFile& file, LLVisualParam const* viewer_param, F32 value); +extern void dump_visual_param(apr_file_t* file, LLVisualParam const* viewer_param, F32 value); extern std::string get_sequential_numbered_file_name(const std::string& prefix, const std::string& suffix); @@ -4472,14 +4713,14 @@ void LLAgent::dumpSentAppearance(const std::string& dump_prefix) } else { - LL_DEBUGS("Avatar") << "dumping sent appearance message to " << fullpath << llendl; + LL_DEBUGS("Avatar") << "dumping sent appearance message to " << fullpath << LL_ENDL; } LLVisualParam* appearance_version_param = gAgentAvatarp->getVisualParam(11000); if (appearance_version_param) { F32 value = appearance_version_param->getWeight(); - dump_visual_param(outfile, appearance_version_param, value); + dump_visual_param(file, appearance_version_param, value); } for (LLAvatarAppearanceDictionary::Textures::const_iterator iter = LLAvatarAppearanceDictionary::getInstance()->getTextures().begin(); iter != LLAvatarAppearanceDictionary::getInstance()->getTextures().end(); @@ -4515,7 +4756,7 @@ void LLAgent::sendAgentSetAppearance() gAgentAvatarp->bakedTextureOriginCounts(sb_count, host_count, both_count, neither_count); if (both_count != 0 || neither_count != 0) { - llwarns << "bad bake texture state " << sb_count << "," << host_count << "," << both_count << "," << neither_count << llendl; + LL_WARNS() << "bad bake texture state " << sb_count << "," << host_count << "," << both_count << "," << neither_count << LL_ENDL; } if (sb_count != 0 && host_count == 0) { @@ -4527,7 +4768,7 @@ void LLAgent::sendAgentSetAppearance() } else if (sb_count + host_count > 0) { - llwarns << "unclear baked texture state, not sending appearance" << llendl; + LL_WARNS() << "unclear baked texture state, not sending appearance" << LL_ENDL; return; } @@ -4572,7 +4813,7 @@ void LLAgent::sendAgentSetAppearance() // IMG_DEFAULT_AVATAR means not baked. 0 index should be ignored for baked textures if (!gAgentAvatarp->isTextureDefined(texture_index, 0)) { - LL_DEBUGS("Avatar") << "texture not current for baked " << (S32)baked_index << " local " << (S32)texture_index << llendl; + LL_DEBUGS("Avatar") << "texture not current for baked " << (S32)baked_index << " local " << (S32)texture_index << LL_ENDL; textures_current = FALSE; break; } @@ -4619,24 +4860,18 @@ void LLAgent::sendAgentSetAppearance() // This means the baked texture IDs on the server will be untouched. // Once all textures are baked, another AvatarAppearance message will be sent to update the TEs msg->nextBlockFast(_PREHASH_ObjectData); - gMessageSystem->addBinaryDataFast(_PREHASH_TextureEntry, NULL, 0); + gMessageSystem->addBinaryDataFast(_PREHASH_TextureEntry, nullptr, 0); } - static bool send_physics_params = false; - send_physics_params |= !!gAgentWearables.selfHasWearable(LLWearableType::WT_PHYSICS); S32 transmitted_params = 0; for (LLViewerVisualParam* param = (LLViewerVisualParam*)gAgentAvatarp->getFirstVisualParam(); param; param = (LLViewerVisualParam*)gAgentAvatarp->getNextVisualParam()) { - if (param->getGroup() == VISUAL_PARAM_GROUP_TWEAKABLE) // do not transmit params of group VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT + if (param->getGroup() == VISUAL_PARAM_GROUP_TWEAKABLE || + param->getGroup() == VISUAL_PARAM_GROUP_TRANSMIT_NOT_TWEAKABLE) // do not transmit params of group VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT { - //A hack to prevent ruthing on older viewers when phys wearables aren't being worn. - if(!send_physics_params && param->getID() >= 10000) - { - break; - } msg->nextBlockFast(_PREHASH_VisualParam ); // We don't send the param ids. Instead, we assume that the receiver has the same params in the same sequence. @@ -4647,10 +4882,8 @@ void LLAgent::sendAgentSetAppearance() } } - llinfos << "Avatar XML num VisualParams transmitted = " << transmitted_params << llendl; - if(transmitted_params < 218) { - LLNotificationsUtil::add("SGIncompleteAppearance"); - } + LL_INFOS() << "Avatar XML num VisualParams transmitted = " << transmitted_params << LL_ENDL; + if (transmitted_params < 218) LLNotificationsUtil::add("SGIncompleteAppearance"); sendReliableMessage(); } @@ -4665,8 +4898,96 @@ void LLAgent::sendAgentDataUpdateRequest() void LLAgent::sendAgentUserInfoRequest() { - if(getID().isNull()) + std::string cap; + + if (getID().isNull()) return; // not logged in + + if (mRegionp) + cap = mRegionp->getCapability("UserInfo"); + + if (!cap.empty()) + { + LLHTTPClient::get(cap, new LLCoroResponder( + boost::bind(&LLAgent::requestAgentUserInfoCoro, this, _1))); + } + else + { + sendAgentUserInfoRequestMessage(); + } +} + +void LLAgent::requestAgentUserInfoCoro(const LLCoroResponder& responder) +{ + const auto& result = responder.getContent(); + const auto& status = responder.getStatus(); + + if (!responder.isGoodStatus(status)) + { + LL_WARNS("UserInfo") << "Failed to get user information: " << result["message"] << "Status " << status << " Reason: " << responder.getReason() << LL_ENDL; + return; + } + + bool im_via_email; + bool is_verified_email; + std::string email; + std::string dir_visibility; + + im_via_email = result["im_via_email"].asBoolean(); + is_verified_email = result["is_verified"].asBoolean(); + email = result["email"].asString(); + dir_visibility = result["directory_visibility"].asString(); + + // TODO: This should probably be changed. I'm not entirely comfortable + // having LLAgent interact directly with the UI in this way. + LLFloaterPreference::updateUserInfo(dir_visibility, im_via_email, email, is_verified_email); + LLFloaterPostcard::updateUserInfo(email); +} + +void LLAgent::sendAgentUpdateUserInfo(bool im_via_email, const std::string& directory_visibility) +{ + std::string cap; + + if (getID().isNull()) + return; // not logged in + + if (mRegionp) + cap = mRegionp->getCapability("UserInfo"); + + if (!cap.empty()) + { + LLSD body(LLSDMap + ("dir_visibility", LLSD::String(directory_visibility)) + ("im_via_email", LLSD::Boolean(im_via_email))); + LLHTTPClient::post(cap, body, new LLCoroResponder( + boost::bind(&LLAgent::updateAgentUserInfoCoro, this, _1))); + } + else + { + sendAgentUpdateUserInfoMessage(im_via_email, directory_visibility); + } +} + + +void LLAgent::updateAgentUserInfoCoro(const LLCoroResponder& responder) +{ + const auto& result = responder.getContent(); + const auto& status = responder.getStatus(); + + if (!responder.isGoodStatus(status)) + { + LL_WARNS("UserInfo") << "Failed to set user information." << LL_ENDL; + } + else if (!result["success"].asBoolean()) + { + LL_WARNS("UserInfo") << "Failed to set user information: " << result["message"] << LL_ENDL; + } +} + +// deprecated: +// May be removed when UserInfo cap propagates to all simhosts in grid +void LLAgent::sendAgentUserInfoRequestMessage() +{ gMessageSystem->newMessageFast(_PREHASH_UserInfoRequest); gMessageSystem->nextBlockFast(_PREHASH_AgentData); gMessageSystem->addUUIDFast(_PREHASH_AgentID, getID()); @@ -4674,6 +4995,21 @@ void LLAgent::sendAgentUserInfoRequest() sendReliableMessage(); } +void LLAgent::sendAgentUpdateUserInfoMessage(bool im_via_email, const std::string& directory_visibility) +{ + gMessageSystem->newMessageFast(_PREHASH_UpdateUserInfo); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, getID()); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, getSessionID()); + gMessageSystem->nextBlockFast(_PREHASH_UserData); + gMessageSystem->addBOOLFast(_PREHASH_IMViaEMail, im_via_email); + gMessageSystem->addString("DirectoryVisibility", directory_visibility); + gAgent.sendReliableMessage(); + +} +// end deprecated +//------ + void LLAgent::observeFriends() { if(!mFriendObserver) @@ -4691,8 +5027,8 @@ void LLAgent::parseTeleportMessages(const std::string& xml_filename) if (!success || !root || !root->hasName( "teleport_messages" )) { - llerrs << "Problem reading teleport string XML file: " - << xml_filename << llendl; + LL_ERRS() << "Problem reading teleport string XML file: " + << xml_filename << LL_ENDL; return; } @@ -4741,25 +5077,13 @@ const void LLAgent::getTeleportSourceSLURL(LLSLURL& slurl) const slurl = *mTeleportSourceSLURL; } -void LLAgent::sendAgentUpdateUserInfo(bool im_via_email, const std::string& directory_visibility ) -{ - gMessageSystem->newMessageFast(_PREHASH_UpdateUserInfo); - gMessageSystem->nextBlockFast(_PREHASH_AgentData); - gMessageSystem->addUUIDFast(_PREHASH_AgentID, getID()); - gMessageSystem->addUUIDFast(_PREHASH_SessionID, getSessionID()); - gMessageSystem->nextBlockFast(_PREHASH_UserData); - gMessageSystem->addBOOLFast(_PREHASH_IMViaEMail, im_via_email); - gMessageSystem->addString("DirectoryVisibility", directory_visibility); - gAgent.sendReliableMessage(); -} - void LLAgent::dumpGroupInfo() { - llinfos << "group " << mGroupName << llendl; - llinfos << "ID " << mGroupID << llendl; - llinfos << "powers " << mGroupPowers << llendl; - llinfos << "title " << mGroupTitle << llendl; - //llinfos << "insig " << mGroupInsigniaID << llendl; + LL_INFOS() << "group " << mGroupName << LL_ENDL; + LL_INFOS() << "ID " << mGroupID << LL_ENDL; + LL_INFOS() << "powers " << mGroupPowers << LL_ENDL; + LL_INFOS() << "title " << mGroupTitle << LL_ENDL; + //LL_INFOS() << "insig " << mGroupInsigniaID << LL_ENDL; } // Draw a representation of current autopilot target @@ -4825,7 +5149,7 @@ void LLAgent::onFoundLureDestination(LLSimInfo *siminfo) const std::string sim_name = siminfo->getName(); const std::string maturity = siminfo->getAccessString(); - llinfos << mPendingLure->mAvatarName << "'s teleport lure is to " << sim_name << " (" << maturity << ")" << llendl; + LL_INFOS() << mPendingLure->mAvatarName << "'s teleport lure is to " << sim_name << " (" << maturity << ")" << LL_ENDL; LLStringUtil::format_map_t args; args["[NAME]"] = mPendingLure->mAvatarName; args["[DESTINATION]"] = LLSLURL(sim_name,mPendingLure->mPosLocal).getSLURLString(); @@ -4835,10 +5159,11 @@ void LLAgent::onFoundLureDestination(LLSimInfo *siminfo) msg.append(llformat(" (%s)", maturity.c_str())); } LLChat chat(msg); + chat.mSourceType = CHAT_SOURCE_SYSTEM; LLFloaterChat::addChat(chat); } else - llwarns << "Grand scheme failed" << llendl; + LL_WARNS() << "Grand scheme failed" << LL_ENDL; delete mPendingLure; mPendingLure = NULL; } diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h index 8a01093bf8..6fd97b679c 100644 --- a/indra/newview/llagent.h +++ b/indra/newview/llagent.h @@ -33,10 +33,7 @@ #ifndef LL_LLAGENT_H #define LL_LLAGENT_H -#include - #include "indra_constants.h" - #include "llevent.h" // LLObservable base class #include "llagentconstants.h" #include "llagentdata.h" // gAgentID, gAgentSessionID @@ -47,7 +44,6 @@ #include "llinventorymodel.h" #include "v3dmath.h" -#include #include #include @@ -71,10 +67,14 @@ class LLAgentAccess; class LLSLURL; class LLSimInfo; class LLTeleportRequest; +struct LLCoroResponder; -typedef std::vector llvo_vec_t; typedef boost::shared_ptr LLTeleportRequestPtr; +//-------------------------------------------------------------------- +// Types +//-------------------------------------------------------------------- + enum EAnimRequest { ANIM_REQUEST_START, @@ -98,7 +98,7 @@ struct LLGroupData //------------------------------------------------------------------------ // LLAgent //------------------------------------------------------------------------ -class LLAgent : public LLOldEvents::LLObservable +class LLAgent final : public LLOldEvents::LLObservable { LOG_CLASS(LLAgent); @@ -119,6 +119,8 @@ class LLAgent : public LLOldEvents::LLObservable void init(); void cleanup(); +private: + //-------------------------------------------------------------------- // Login //-------------------------------------------------------------------- @@ -160,8 +162,6 @@ class LLAgent : public LLOldEvents::LLObservable // Name //-------------------------------------------------------------------- public: - void getName(std::string& name); //Legacy - void buildFullname(std::string &name) const; //Legacy //*TODO remove, is not used as of August 20, 2009 void buildFullnameAndTitle(std::string &name) const; @@ -169,12 +169,13 @@ class LLAgent : public LLOldEvents::LLObservable // Gender //-------------------------------------------------------------------- public: - // On the very first login, gender isn't chosen until the user clicks - // in a dialog. We don't render the avatar until they choose. - BOOL isGenderChosen() const { return mGenderChosen; } - void setGenderChosen(BOOL b) { mGenderChosen = b; } + // On the very first login, outfit needs to be chosen by some + // mechanism, usually by loading the requested initial outfit. We + // don't render the avatar until the choice is made. + BOOL isOutfitChosen() const { return mOutfitChosen; } + void setOutfitChosen(BOOL b) { mOutfitChosen = b; } private: - BOOL mGenderChosen; + BOOL mOutfitChosen; /** Identity ** ** @@ -213,7 +214,7 @@ class LLAgent : public LLOldEvents::LLObservable //-------------------------------------------------------------------- public: const LLCoordFrame& getFrameAgent() const { return mFrameAgent; } - void initOriginGlobal(const LLVector3d &origin_global); // Only to be used in ONE place! - djs 08/07/02 + void initOriginGlobal(const LLVector3d &origin_global); // Only to be used in ONE place void resetAxes(); void resetAxes(const LLVector3 &look_at); // Makes reasonable left and up // The following three get*Axis functions return direction avatar is looking, not camera. @@ -238,15 +239,55 @@ class LLAgent : public LLOldEvents::LLObservable U64 mHomeRegionHandle; LLVector3 mHomePosRegion; + //-------------------------------------------------------------------- + // Parcel + //-------------------------------------------------------------------- +public: + void changeParcels(); // called by LLViewerParcelMgr when we cross a parcel boundary + + // Register a boost callback to be called when the agent changes parcels + typedef std::function parcel_changed_callback_t; + boost::signals2::connection addParcelChangedCallback(parcel_changed_callback_t); + +private: + typedef boost::signals2::signal parcel_changed_signal_t; + parcel_changed_signal_t mParcelChangedSignal; + //-------------------------------------------------------------------- // Region //-------------------------------------------------------------------- public: void setRegion(LLViewerRegion *regionp); - LLViewerRegion *getRegion() const { return mRegionp; } + LLViewerRegion *getRegion() const; const LLHost& getRegionHost() const; BOOL inPrelude(); + // Capability + std::string getRegionCapability(const std::string &name); // short hand for if (getRegion()) { getRegion()->getCapability(name) } + + /** + * Register a boost callback to be called when the agent changes regions + * Note that if you need to access a capability for the region, you may need to wait + * for the capabilities to be received, since in some cases your region changed + * callback will be called before the capabilities have been received. Your callback + * may need to look something like: + * + * LLViewerRegion* region = gAgent.getRegion(); + * if (region->capabilitiesReceived()) + * { + * useCapability(region); + * } + * else // Need to handle via callback after caps arrive. + * { + * region->setCapabilitiesReceivedCallback(boost::bind(&useCapability,region,_1)); + * // you may or may not want to remove that callback + * } + */ + typedef boost::signals2::signal region_changed_signal_t; + + boost::signals2::connection addRegionChangedCallback(const region_changed_signal_t::slot_type& cb); + void removeRegionChangedCallback(boost::signals2::connection callback); + // struct SHLureRequest { @@ -260,9 +301,10 @@ class LLAgent : public LLOldEvents::LLObservable void showLureDestination(const std::string fromname, U64& handle, U32 x, U32 y, U32 z); void onFoundLureDestination(LLSimInfo *siminfo = NULL); // - + private: LLViewerRegion *mRegionp; + region_changed_signal_t mRegionChangedSignal; //-------------------------------------------------------------------- // History @@ -274,6 +316,7 @@ class LLAgent : public LLOldEvents::LLObservable const LLVector3d &getLastPositionGlobal() const { return mLastPositionGlobal; } void setLastPositionGlobal(const LLVector3d &pos) { mLastPositionGlobal = pos; } + private: std::set mRegionsVisited; // Stat - what distinct regions has the avatar been to? F64 mDistanceTraveled; // Stat - how far has the avatar moved? @@ -302,6 +345,15 @@ class LLAgent : public LLOldEvents::LLObservable F32 mNextFidgetTime; S32 mCurrentFidget; + //-------------------------------------------------------------------- + // Crouch + //-------------------------------------------------------------------- +public: + bool isCrouching() const; + void toggleCrouch() { mCrouch = !mCrouch; } +private: + bool mCrouch; + //-------------------------------------------------------------------- // Fly //-------------------------------------------------------------------- @@ -412,21 +464,27 @@ class LLAgent : public LLOldEvents::LLObservable /// @brief ground-sit at agent's current position void sitDown(); + void setSitDownAway(bool away); + bool isAwaySitting() const { return mIsAwaySitting; } + +private: + bool mIsAwaySitting; + //-------------------------------------------------------------------- - // Busy + // Do Not Disturb //-------------------------------------------------------------------- public: - void setBusy(); - void clearBusy(); - BOOL getBusy() const; + void setDoNotDisturb(bool pIsDoNotDisturb); + bool isDoNotDisturb() const; private: - BOOL mIsBusy; + bool mIsDoNotDisturb; //-------------------------------------------------------------------- // Grab //-------------------------------------------------------------------- public: BOOL leftButtonGrabbed() const; + BOOL leftButtonBlocked() const; BOOL rotateGrabbed() const; BOOL forwardGrabbed() const; BOOL backwardGrabbed() const; @@ -438,13 +496,14 @@ class LLAgent : public LLOldEvents::LLObservable //-------------------------------------------------------------------- public: U32 getControlFlags(); - void setControlFlags(U32 mask); // performs bitwise mControlFlags |= mask - void clearControlFlags(U32 mask); // performs bitwise mControlFlags &= ~mask + void setControlFlags(U32 mask); // Performs bitwise mControlFlags |= mask + void clearControlFlags(U32 mask); // Performs bitwise mControlFlags &= ~mask BOOL controlFlagsDirty() const; void enableControlFlagReset(); void resetControlFlags(); - BOOL anyControlGrabbed() const; // True iff a script has taken over a control - BOOL isControlGrabbed(S32 control_index) const; + BOOL anyControlGrabbed() const; // True if a script has taken over any control + BOOL isControlGrabbed(S32 control_index) const; // True if a script has taken over a control + BOOL isControlBlocked(S32 control_index) const; // Control should be ignored or won't be passed // Send message to simulator to force grabbed controls to be // released, in case of a poorly written script. void forceReleaseControls(); @@ -464,8 +523,11 @@ class LLAgent : public LLOldEvents::LLObservable void stopCurrentAnimations(); void requestStopMotion(LLMotion* motion); void onAnimStop(const LLUUID& id); - void sendAnimationRequests(LLDynamicArray &anim_ids, EAnimRequest request); + void sendAnimationRequests(const uuid_vec_t &anim_ids, EAnimRequest request); void sendAnimationRequest(const LLUUID &anim_id, EAnimRequest request); + void sendAnimationStateReset(); + void sendRevokePermissions(const LLUUID & target, U32 permissions); + void endAnimationUpdateUI(); void unpauseAnimation() { mPauseRequest = NULL; } BOOL getCustomAnim() const { return mCustomAnim; } @@ -506,6 +568,9 @@ class LLAgent : public LLOldEvents::LLObservable void moveYaw(F32 mag, bool reset_view = true); void movePitch(F32 mag); + BOOL isMovementLocked() const { return mMovementKeysLocked; } + void setMovementLocked(BOOL set_locked) { mMovementKeysLocked = set_locked; } + //-------------------------------------------------------------------- // Move the avatar's frame //-------------------------------------------------------------------- @@ -526,20 +591,22 @@ class LLAgent : public LLOldEvents::LLObservable public: BOOL getAutoPilot() const { return mAutoPilot; } LLVector3d getAutoPilotTargetGlobal() const { return mAutoPilotTargetGlobal; } - LLUUID getAutoPilotLeaderID() const { return mLeaderID; } + const LLUUID& getAutoPilotLeaderID() const { return mLeaderID; } F32 getAutoPilotStopDistance() const { return mAutoPilotStopDistance; } F32 getAutoPilotTargetDist() const { return mAutoPilotTargetDist; } BOOL getAutoPilotUseRotation() const { return mAutoPilotUseRotation; } LLVector3 getAutoPilotTargetFacing() const { return mAutoPilotTargetFacing; } F32 getAutoPilotRotationThreshold() const { return mAutoPilotRotationThreshold; } - std::string getAutoPilotBehaviorName() const { return mAutoPilotBehaviorName; } + const std::string& getAutoPilotBehaviorName() const { return mAutoPilotBehaviorName; } + bool getAutoPilotNoProgress() const; void startAutoPilotGlobal(const LLVector3d &pos_global, const std::string& behavior_name = std::string(), const LLQuaternion *target_rotation = NULL, void (*finish_callback)(BOOL, void *) = NULL, void *callback_data = NULL, - F32 stop_distance = 0.f, F32 rotation_threshold = 0.03f); - void startFollowPilot(const LLUUID &leader_id); + F32 stop_distance = 0.f, F32 rotation_threshold = 0.03f, + BOOL allow_flying = TRUE); + void startFollowPilot(const LLUUID &leader_id, BOOL allow_flying = TRUE, F32 stop_distance = 0.5f); void stopAutoPilot(BOOL user_cancel = FALSE); void setAutoPilotTargetGlobal(const LLVector3d &target_global); void autoPilot(F32 *delta_yaw); // Autopilot walking action, angles in radians @@ -547,17 +614,19 @@ class LLAgent : public LLOldEvents::LLObservable private: BOOL mAutoPilot; BOOL mAutoPilotFlyOnStop; + BOOL mAutoPilotAllowFlying; LLVector3d mAutoPilotTargetGlobal; F32 mAutoPilotStopDistance; BOOL mAutoPilotUseRotation; LLVector3 mAutoPilotTargetFacing; F32 mAutoPilotTargetDist; - S32 mAutoPilotNoProgressFrameCount; + U64 mAutoPilotNoProgressFrameCount; F32 mAutoPilotRotationThreshold; std::string mAutoPilotBehaviorName; void (*mAutoPilotFinishedCallback)(BOOL, void *); void* mAutoPilotCallbackData; LLUUID mLeaderID; + BOOL mMovementKeysLocked; /** Movement ** ** @@ -601,6 +670,7 @@ class LLAgent : public LLOldEvents::LLObservable void teleportViaLocation(const LLVector3d& pos_global); // To a global location - this will probably need to be deprecated void teleportViaLocationLookAt(const LLVector3d& pos_global);// To a global location, preserving camera rotation void teleportCancel(); // May or may not be allowed by server + void restoreCanceledTeleportRequest(); bool getTeleportKeepsLookAt() { return mbTeleportKeepsLookAt; } // Whether look-at reset after teleport protected: bool teleportCore(bool is_local = false); // Stuff for all teleports; returns true if the teleport can proceed @@ -623,6 +693,7 @@ class LLAgent : public LLOldEvents::LLObservable friend class LLTeleportRequestViaLocationLookAt; LLTeleportRequestPtr mTeleportRequest; + LLTeleportRequestPtr mTeleportCanceled; boost::signals2::connection mTeleportFinishedSlot; boost::signals2::connection mTeleportFailedSlot; @@ -642,13 +713,14 @@ class LLAgent : public LLOldEvents::LLObservable void handleTeleportFinished(); void handleTeleportFailed(); +public: void handleServerBakeRegionTransition(const LLUUID& region_id); //-------------------------------------------------------------------- // Teleport State //-------------------------------------------------------------------- public: - ETeleportState getTeleportState() const { return mTeleportState; } + ETeleportState getTeleportState() const; void setTeleportState(ETeleportState state); private: ETeleportState mTeleportState; @@ -666,13 +738,21 @@ class LLAgent : public LLOldEvents::LLObservable ** ** *******************************************************************************/ + // Attachments getting lost on TP +public: + void setIsCrossingRegion(bool is_crossing) { mIsCrossingRegion = is_crossing; } + bool isCrossingRegion() const { return mIsCrossingRegion; } +private: + bool mIsCrossingRegion; + // Build public: bool canEditParcel() const { return mCanEditParcel; } private: + static void setCanEditParcel(); bool mCanEditParcel; - static void parcelChangedCallback(); + /******************************************************************************** ** ** @@ -689,8 +769,6 @@ class LLAgent : public LLOldEvents::LLObservable const LLAgentAccess& getAgentAccess(); BOOL canManageEstate() const; BOOL getAdminOverride() const; - // ! BACKWARDS COMPATIBILITY ! This function can go away after the AO transition (see llstartup.cpp). - void setAOTransition(); private: LLAgentAccess * mAgentAccess; @@ -706,7 +784,7 @@ class LLAgent : public LLOldEvents::LLObservable void requestEnterGodMode(); void requestLeaveGodMode(); - typedef boost::function god_level_change_callback_t; + typedef std::function god_level_change_callback_t; typedef boost::signals2::signal god_level_change_signal_t; typedef boost::signals2::connection god_level_change_slot_t; @@ -728,7 +806,7 @@ class LLAgent : public LLOldEvents::LLObservable bool canAccessMature() const; bool canAccessAdult() const; bool canAccessMaturityInRegion( U64 region_handle ) const; - bool canAccessMaturityAtGlobal( LLVector3d pos_global ) const; + bool canAccessMaturityAtGlobal( const LLVector3d& pos_global ) const; bool prefersPG() const; bool prefersMature() const; bool prefersAdult() const; @@ -795,7 +873,7 @@ class LLAgent : public LLOldEvents::LLObservable // HUD //-------------------------------------------------------------------- public: - const LLColor4 &getEffectColor(); + const LLColor4 getEffectColor(); void setEffectColor(const LLColor4 &color); private: LLColor4 *mEffectColor; @@ -819,6 +897,7 @@ class LLAgent : public LLOldEvents::LLObservable BOOL setGroupContribution(const LLUUID& group_id, S32 contribution); BOOL setUserGroupFlags(const LLUUID& group_id, BOOL accept_notices, BOOL list_in_profile); const std::string &getGroupName() const { return mGroupName; } + BOOL canJoinGroups() const; private: std::string mGroupName; LLUUID mGroupID; @@ -833,7 +912,7 @@ class LLAgent : public LLOldEvents::LLObservable // Only used for building titles. BOOL isGroupMember() const { return !mGroupID.isNull(); } public: - LLDynamicArray mGroups; + std::vector mGroups; //-------------------------------------------------------------------- // Group Title @@ -863,7 +942,7 @@ class LLAgent : public LLOldEvents::LLObservable void friendsChanged(); private: LLFriendObserver* mFriendObserver; - std::set mProxyForAgents; + uuid_set_t mProxyForAgents; /** Groups ** ** @@ -884,9 +963,17 @@ class LLAgent : public LLOldEvents::LLObservable void sendAgentSetAppearance(); void sendAgentDataUpdateRequest(); void sendAgentUserInfoRequest(); - // IM to Email and Online visibility + +// IM to Email and Online visibility void sendAgentUpdateUserInfo(bool im_to_email, const std::string& directory_visibility); +private: + void requestAgentUserInfoCoro(const LLCoroResponder& responder); + void updateAgentUserInfoCoro(const LLCoroResponder& responder); + // DEPRECATED: may be removed when User Info cap propagates + void sendAgentUserInfoRequestMessage(); + void sendAgentUpdateUserInfoMessage(bool im_via_email, const std::string& directory_visibility); + //-------------------------------------------------------------------- // Receive //-------------------------------------------------------------------- diff --git a/indra/newview/llagentaccess.cpp b/indra/newview/llagentaccess.cpp index 8e93c06fc5..f1ea2423ca 100644 --- a/indra/newview/llagentaccess.cpp +++ b/indra/newview/llagentaccess.cpp @@ -172,7 +172,7 @@ int LLAgentAccess::convertTextToMaturity(char text) void LLAgentAccess::setMaturity(char text) { mAccess = LLAgentAccess::convertTextToMaturity(text); - llinfos << "Setting agent maturity to " << text << " " << (int)mAccess << llendl; + LL_INFOS() << "Setting agent maturity to " << text << " " << (int)mAccess << LL_ENDL; U32 preferred_access = mSavedSettings.getU32("PreferredMaturity"); while (!canSetMaturity(preferred_access)) { diff --git a/indra/newview/llagentbenefits.cpp b/indra/newview/llagentbenefits.cpp new file mode 100644 index 0000000000..7a92dff359 --- /dev/null +++ b/indra/newview/llagentbenefits.cpp @@ -0,0 +1,260 @@ +/** +* @file llagentbenefits.cpp +* +* $LicenseInfo:firstyear=2019&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2019, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#include "llviewerprecompiledheaders.h" +#include "llagentbenefits.h" + +LLAgentBenefits::LLAgentBenefits(): + m_initalized(false), + m_animated_object_limit(-1), + m_animation_upload_cost(-1), + m_attachment_limit(-1), + m_group_membership_limit(-1), + m_picks_limit(-1), + m_sound_upload_cost(-1), + m_texture_upload_cost(-1) +{ +} + +LLAgentBenefits::~LLAgentBenefits() +{ +} + +// This could be extended to a template scheme or otherwise modified +// to support other types, if and when needed. Currently all fields +// the viewer cares about are integer. +bool get_required_S32(const LLSD& sd, const LLSD::String& key, S32& value) +{ + value = -1; + if (sd.has(key)) + { + value = sd[key].asInteger(); + return true; + } + + LL_WARNS("Benefits") << "Missing required benefit field " << key << LL_ENDL; + return false; +} + +bool LLAgentBenefits::init(const LLSD& benefits_sd) +{ + LL_DEBUGS("Benefits") << "initializing benefits from " << benefits_sd << LL_ENDL; + + if (!get_required_S32(benefits_sd, "animated_object_limit", m_animated_object_limit)) + { + return false; + } + if (!get_required_S32(benefits_sd, "animation_upload_cost", m_animation_upload_cost)) + { + return false; + } + if (!get_required_S32(benefits_sd, "attachment_limit", m_attachment_limit)) + { + return false; + } + if (!get_required_S32(benefits_sd, "create_group_cost", m_create_group_cost)) + { + return false; + } + if (!get_required_S32(benefits_sd, "group_membership_limit", m_group_membership_limit)) + { + return false; + } + if (!get_required_S32(benefits_sd, "picks_limit", m_picks_limit)) + { + return false; + } + if (!get_required_S32(benefits_sd, "sound_upload_cost", m_sound_upload_cost)) + { + return false; + } + if (!get_required_S32(benefits_sd, "texture_upload_cost", m_texture_upload_cost)) + { + return false; + } + + // FIXME PREMIUM - either use this field or get rid of it + m_initalized = true; + return true; +} + +void LLAgentBenefits::initNonSL(const LLSD& benefits_sd) +{ + if (!get_required_S32(benefits_sd, "max_groups", m_group_membership_limit) + && !get_required_S32(benefits_sd, "max-agent-groups", m_group_membership_limit)) + m_group_membership_limit = S32_MAX; + m_picks_limit = m_animated_object_limit = m_attachment_limit = S32_MAX; + m_texture_upload_cost = m_sound_upload_cost = m_create_group_cost = m_animation_upload_cost = 0; +} + +void LLAgentBenefits::processEconomyData(LLMessageSystem* msg) +{ + msg->getS32Fast(_PREHASH_Info, _PREHASH_PriceUpload, m_texture_upload_cost); + m_sound_upload_cost = m_animation_upload_cost = m_texture_upload_cost; + msg->getS32Fast(_PREHASH_Info, _PREHASH_PriceGroupCreate, m_create_group_cost); + + LL_INFOS_ONCE("Messaging") << "EconomyData message arrived; upload cost is L$" << m_texture_upload_cost << " group cost is " << m_create_group_cost << LL_ENDL; +} + +S32 LLAgentBenefits::getAnimatedObjectLimit() const +{ + return m_animated_object_limit; +} + +S32 LLAgentBenefits::getAnimationUploadCost() const +{ + return m_animation_upload_cost; +} + +S32 LLAgentBenefits::getAttachmentLimit() const +{ + return m_attachment_limit; +} + +S32 LLAgentBenefits::getCreateGroupCost() const +{ + return m_create_group_cost; +} + +S32 LLAgentBenefits::getGroupMembershipLimit() const +{ + return m_group_membership_limit; +} + +S32 LLAgentBenefits::getPicksLimit() const +{ + return m_picks_limit; +} + +S32 LLAgentBenefits::getSoundUploadCost() const +{ + return m_sound_upload_cost; +} + +S32 LLAgentBenefits::getTextureUploadCost() const +{ + return m_texture_upload_cost; +} + +bool LLAgentBenefits::findUploadCost(LLAssetType::EType& asset_type, S32& cost) const +{ + bool succ = false; + if (asset_type == LLAssetType::AT_TEXTURE) + { + cost = getTextureUploadCost(); + succ = true; + } + else if (asset_type == LLAssetType::AT_SOUND) + { + cost = getSoundUploadCost(); + succ = true; + } + else if (asset_type == LLAssetType::AT_ANIMATION) + { + cost = getAnimationUploadCost(); + succ = true; + } + return succ; +} + +LLAgentBenefitsMgr::LLAgentBenefitsMgr() +{ +} + +LLAgentBenefitsMgr::~LLAgentBenefitsMgr() +{ +} + +// static +LLAgentBenefits& LLAgentBenefitsMgr::current() +{ + return instance().mCurrent; +} + +// static +const LLAgentBenefits& LLAgentBenefitsMgr::get(const std::string& package) +{ + if (instance().mPackageMap.find(package) != instance().mPackageMap.end()) + { + return instance().mPackageMap[package]; + } + else + { + return instance().mDefault; + } +} + +// static +bool LLAgentBenefitsMgr::init(const std::string& package, const LLSD& benefits_sd) +{ + LLAgentBenefits benefits; + if (!benefits.init(benefits_sd)) + { + LL_WARNS("Benefits") << "Unable to initialize package " << package << " from sd " << benefits_sd << LL_ENDL; + return false; + } + else + { + instance().mPackageMap[package] = benefits; + } + return true; + +} + +// static +bool LLAgentBenefitsMgr::initCurrent(const std::string& package, const LLSD& benefits_sd) +{ + LLAgentBenefits benefits; + if (!benefits.init(benefits_sd)) + { + LL_WARNS("Benefits") << "Unable to initialize package " << package << " from sd " << benefits_sd << LL_ENDL; + return false; + } + else + { + instance().mCurrent = benefits; + instance().mCurrentName = package; + } + return true; + +} + +void LLAgentBenefitsMgr::initNonSL(const LLSD& benefits_sd) +{ + mCurrent.initNonSL(benefits_sd); + mCurrentName = "NonSL"; +} + +// static +bool LLAgentBenefitsMgr::has(const std::string& package) +{ + return instance().mPackageMap.find(package) != instance().mPackageMap.end(); +} + +//static +bool LLAgentBenefitsMgr::isCurrent(const std::string& package) +{ + return instance().mCurrentName == package; +} diff --git a/indra/newview/llagentbenefits.h b/indra/newview/llagentbenefits.h new file mode 100644 index 0000000000..b121e33893 --- /dev/null +++ b/indra/newview/llagentbenefits.h @@ -0,0 +1,92 @@ +/** +* @file llagentbenefits.h +* +* $LicenseInfo:firstyear=2019&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2019, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#ifndef LL_AGENTBENEFITS_H +#define LL_AGENTBENEFITS_H + +#include "llsingleton.h" +#include "llsd.h" +#include "llassettype.h" + +class LLAgentBenefits +{ +public: + LLAgentBenefits(); + ~LLAgentBenefits(); + LOG_CLASS(LLAgentBenefits); + + bool init(const LLSD& benefits_sd); + void initNonSL(const LLSD& benefits_sd); + void processEconomyData(LLMessageSystem*); + + S32 getAnimatedObjectLimit() const; + S32 getAnimationUploadCost() const; + S32 getAttachmentLimit() const; + S32 getCreateGroupCost() const; + S32 getGroupMembershipLimit() const; + S32 getPicksLimit() const; + S32 getSoundUploadCost() const; + S32 getTextureUploadCost() const; + + bool findUploadCost(LLAssetType::EType& asset_type, S32& cost) const; + +private: + S32 m_animated_object_limit; + S32 m_animation_upload_cost; + S32 m_attachment_limit; + S32 m_create_group_cost; + S32 m_group_membership_limit; + S32 m_picks_limit; + S32 m_sound_upload_cost; + S32 m_texture_upload_cost; + + bool m_initalized; +}; + +class LLAgentBenefitsMgr : public LLSingleton +{ + friend class LLSingleton; + LLAgentBenefitsMgr(); + ~LLAgentBenefitsMgr(); + LOG_CLASS(LLAgentBenefitsMgr); + +public: + static LLAgentBenefits& current(); + static const LLAgentBenefits& get(const std::string& package); + static bool init(const std::string& package, const LLSD& benefits_sd); + static bool initCurrent(const std::string& package, const LLSD& benefits_sd); + void initNonSL(const LLSD& benefits_sd); + static bool has(const std::string& package); + static bool isCurrent(const std::string& package); + +private: + std::string mCurrentName; + LLAgentBenefits mCurrent; + LLAgentBenefits mDefault; + std::map mPackageMap; +}; + + +#endif diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp index 9d41796218..c08751edac 100644 --- a/indra/newview/llagentcamera.cpp +++ b/indra/newview/llagentcamera.cpp @@ -29,6 +29,7 @@ #include "pipeline.h" +#include "aosystem.h" //For AOSystem #include "llagent.h" #include "llanimationstates.h" #include "llfloatercamera.h" @@ -49,7 +50,6 @@ #include "llwindow.h" #include "llworld.h" #include "llfloatertools.h" //For gFloaterTools -#include "floaterao.h" //For LLFloaterAO #include "llfloatercustomize.h" //For gFloaterCustomize // [RLVa:KB] - Checked: 2010-05-10 (RLVa-1.2.0g) #include "rlvhandler.h" @@ -155,12 +155,14 @@ LLAgentCamera::LLAgentCamera() : mCameraUpVector(LLVector3::z_axis), // default is straight up mFocusOnAvatar(TRUE), + mAllowChangeToFollow(FALSE), mFocusGlobal(), mFocusTargetGlobal(), mFocusObject(NULL), mFocusObjectDist(0.f), mFocusObjectOffset(), mFocusDotRadius( 0.1f ), // meters + mTrackFocusObject(TRUE), mUIOffset(0.f), mAtKey(0), // Either 1, 0, or -1... indicates that movement-key is pressed @@ -224,6 +226,7 @@ void LLAgentCamera::init() mCurrentCameraDistance = getCameraOffsetInitial().magVec() * gSavedSettings.getF32("CameraOffsetScale"); mTargetCameraDistance = mCurrentCameraDistance; mCameraZoomFraction = 1.f; + mTrackFocusObject = gSavedSettings.getBOOL("TrackFocusObject"); mInitialized = true; } @@ -286,30 +289,22 @@ LLAgentCamera::~LLAgentCamera() //----------------------------------------------------------------------------- void LLAgentCamera::resetView(BOOL reset_camera, BOOL change_camera) { - if (gAgent.getAutoPilot()) + LLSelectMgr::getInstance()->unhighlightAll(); + + // By popular request, keep land selection while walking around. JC + // LLViewerParcelMgr::getInstance()->deselectLand(); + + // force deselect when walking and attachment is selected + // this is so people don't wig out when their avatar moves without animating + if (LLSelectMgr::getInstance()->getSelection()->isAttachment()) { - gAgent.stopAutoPilot(TRUE); + LLSelectMgr::getInstance()->deselectAll(); } - if (!gNoRender) + if (gMenuHolder != NULL) { - LLSelectMgr::getInstance()->unhighlightAll(); - - // By popular request, keep land selection while walking around. JC - // LLViewerParcelMgr::getInstance()->deselectLand(); - - // force deselect when walking and attachment is selected - // this is so people don't wig out when their avatar moves without animating - if (LLSelectMgr::getInstance()->getSelection()->isAttachment()) - { - LLSelectMgr::getInstance()->deselectAll(); - } - - if (gMenuHolder != NULL) - { - // Hide all popup menus - gMenuHolder->hideMenus(); - } + // Hide all popup menus + gMenuHolder->hideMenus(); } static const LLCachedControl freeze_time("FreezeTime",false); @@ -352,7 +347,7 @@ void LLAgentCamera::resetView(BOOL reset_camera, BOOL change_camera) LLVector3 agent_at_axis = gAgent.getAtAxis(); agent_at_axis -= projected_vec(agent_at_axis, gAgent.getReferenceUpVector()); agent_at_axis.normalize(); - gAgent.resetAxes(lerp(gAgent.getAtAxis(), agent_at_axis, LLCriticalDamp::getInterpolant(0.3f))); + gAgent.resetAxes(lerp(gAgent.getAtAxis(), agent_at_axis, LLSmoothInterpolation::getInterpolant(0.3f))); } setFocusOnAvatar(TRUE, ANIMATE); @@ -369,6 +364,8 @@ void LLAgentCamera::resetView(BOOL reset_camera, BOOL change_camera) //----------------------------------------------------------------------------- void LLAgentCamera::unlockView() { + if (gRlvHandler.hasBehaviour(RLV_BHVR_CAMUNLOCK)) return; // [RLVa:LF] - camunlock + if (getFocusOnAvatar()) { if (isAgentAvatarValid()) @@ -395,7 +392,7 @@ void LLAgentCamera::slamLookAt(const LLVector3 &look_at) //----------------------------------------------------------------------------- LLVector3 LLAgentCamera::calcFocusOffset(LLViewerObject *object, LLVector3 original_focus_point, S32 x, S32 y) { - LLMatrix4 obj_matrix = object->getRenderMatrix(); + const LLMatrix4a& obj_matrix = object->getRenderMatrix(); LLQuaternion obj_rot = object->getRenderRotation(); LLVector3 obj_pos = object->getRenderPosition(); @@ -427,24 +424,24 @@ LLVector3 LLAgentCamera::calcFocusOffset(LLViewerObject *object, LLVector3 origi // find the largest ratio stored in obj_to_cam_ray_proportions // this corresponds to the object's local axial plane (XY, YZ, XZ) that is *most* facing the camera - LLVector3 longest_object_axis; + LLVector4a focus_plane_normal; // is x-axis longest? if (obj_to_cam_ray_proportions.mV[VX] > obj_to_cam_ray_proportions.mV[VY] && obj_to_cam_ray_proportions.mV[VX] > obj_to_cam_ray_proportions.mV[VZ]) { // then grab it - longest_object_axis.setVec(obj_matrix.getFwdRow4()); + focus_plane_normal = obj_matrix.getRow(); } // is y-axis longest? else if (obj_to_cam_ray_proportions.mV[VY] > obj_to_cam_ray_proportions.mV[VZ]) { // then grab it - longest_object_axis.setVec(obj_matrix.getLeftRow4()); + focus_plane_normal = obj_matrix.getRow(); } // otherwise, use z axis else { - longest_object_axis.setVec(obj_matrix.getUpRow4()); + focus_plane_normal = obj_matrix.getRow(); } // Use this axis as the normal to project mouse click on to plane with that normal, at the object center. @@ -453,11 +450,10 @@ LLVector3 LLAgentCamera::calcFocusOffset(LLViewerObject *object, LLVector3 origi // We do this to allow the camera rotation tool to "tumble" the object by rotating the camera. // If the focus point were the object surface under the mouse, camera rotation would introduce an undesirable // eccentricity to the object orientation - LLVector3 focus_plane_normal(longest_object_axis); - focus_plane_normal.normalize(); + focus_plane_normal.normalize3fast(); LLVector3d focus_pt_global; - gViewerWindow->mousePointOnPlaneGlobal(focus_pt_global, x, y, gAgent.getPosGlobalFromAgent(obj_pos), focus_plane_normal); + gViewerWindow->mousePointOnPlaneGlobal(focus_pt_global, x, y, gAgent.getPosGlobalFromAgent(obj_pos), LLVector3(focus_plane_normal.getF32ptr())); LLVector3 focus_pt = gAgent.getPosAgentFromGlobal(focus_pt_global); // find vector from camera to focus point in object space @@ -579,10 +575,10 @@ BOOL LLAgentCamera::calcCameraMinDistance(F32 &obj_min_distance) if (mFocusObject->mDrawable.isNull()) { #ifdef LL_RELEASE_FOR_DOWNLOAD - llwarns << "Focus object with no drawable!" << llendl; + LL_WARNS() << "Focus object with no drawable!" << LL_ENDL; #else mFocusObject->dump(); - llerrs << "Focus object with no drawable!" << llendl; + LL_ERRS() << "Focus object with no drawable!" << LL_ENDL; #endif obj_min_distance = 0.f; return TRUE; @@ -789,6 +785,7 @@ void LLAgentCamera::setCameraZoomFraction(F32 fraction) // 0.f -> camera zoomed all the way out // 1.f -> camera zoomed all the way in LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); + if (selection->getObjectCount() && selection->getSelectType() == SELECT_TYPE_HUD) { mHUDTargetZoom = fraction; @@ -829,6 +826,7 @@ void LLAgentCamera::setCameraZoomFraction(F32 fraction) { min_zoom = 0.f; } + LLVector3d camera_offset_dir = mCameraFocusOffsetTarget; camera_offset_dir.normalize(); //mCameraFocusOffsetTarget = camera_offset_dir * rescale(fraction, 0.f, 1.f, max_zoom, min_zoom); @@ -911,7 +909,8 @@ void LLAgentCamera::cameraZoomIn(const F32 fraction) LLVector3d camera_offset_unit(mCameraFocusOffsetTarget); - F32 min_zoom = 0.f;//LAND_MIN_ZOOM; + // Still limit min zoom to something sane, otherwise the camera normal starts flaking out. + F32 min_zoom = 0.02f;//LAND_MIN_ZOOM; F32 current_distance = (F32)camera_offset_unit.normalize(); F32 new_distance = current_distance * fraction; @@ -932,15 +931,16 @@ void LLAgentCamera::cameraZoomIn(const F32 fraction) min_zoom = OBJECT_MIN_ZOOM; } } - - new_distance = llmax(new_distance, min_zoom); } + new_distance = llmax(new_distance, min_zoom); // Don't zoom too far back const F32 DIST_FUDGE = 16.f; // meters F32 max_distance = /*llmin(mDrawDistance*/ INT_MAX - DIST_FUDGE//, /*LLWorld::getInstance()->getRegionWidthInMeters() - DIST_FUDGE )*/; + max_distance = llmin(max_distance, current_distance * 4.f); //Scaled max relative to current distance. MAINT-3154 + if (new_distance > max_distance) { // screw cam constraints @@ -969,6 +969,26 @@ void LLAgentCamera::cameraZoomIn(const F32 fraction) //----------------------------------------------------------------------------- void LLAgentCamera::cameraOrbitIn(const F32 meters) { +// [RLVa:LF] - @camdistmax, @camdistmin + if (gRlvHandler.hasBehaviour(RLV_BHVR_CAMDISTMAX)) + { + F32 dist_max(gRlvHandler.camPole(RLV_BHVR_CAMDISTMAX)); + if (0 >= dist_max) + { + if (!cameraMouselook()) + changeCameraToMouselook(); + return; // There's no getting out of mouselook + } + } + + if (gRlvHandler.hasBehaviour(RLV_BHVR_CAMDISTMIN)) + { + F32 dist_min(gRlvHandler.camPole(RLV_BHVR_CAMDISTMIN)); + if (cameraMouselook() && dist_min > 0) + changeCameraToDefault(); // Just to be sure we're not in mouselook + } +// [/RLVa:LF] + if (mFocusOnAvatar && mCameraMode == CAMERA_MODE_THIRD_PERSON) { static const LLCachedControl camera_offset_scale("CameraOffsetScale"); @@ -1167,8 +1187,8 @@ void LLAgentCamera::updateLookAt(const S32 mouse_x, const S32 mouse_y) //----------------------------------------------------------------------------- void LLAgentCamera::updateCamera() { - //static LLFastTimer::DeclareTimer ftm("Camera"); - //LLFastTimer t(ftm); + //static LLTrace::BlockTimerStatHandle ftm("Camera"); + //LL_RECORD_BLOCK_TIME(ftm); // - changed camera_skyward to the new global "mCameraUpVector" mCameraUpVector = LLVector3::z_axis; @@ -1178,7 +1198,9 @@ void LLAgentCamera::updateCamera() validateFocusObject(); - if (isAgentAvatarValid() && + static const LLCachedControl realistic_ml("UseRealisticMouselook"); + if (isAgentAvatarValid() && + !realistic_ml && gAgentAvatarp->isSitting() && camera_mode == CAMERA_MODE_MOUSELOOK) { @@ -1186,8 +1208,10 @@ void LLAgentCamera::updateCamera() mCameraUpVector = mCameraUpVector * gAgentAvatarp->getRenderRotation(); } - if (cameraThirdPerson() && mFocusOnAvatar && LLFollowCamMgr::getActiveFollowCamParams()) + if (cameraThirdPerson() && (mFocusOnAvatar || mAllowChangeToFollow) && LLFollowCamMgr::getActiveFollowCamParams()) { + mAllowChangeToFollow = FALSE; + mFocusOnAvatar = TRUE; changeCameraToFollow(); } @@ -1270,7 +1294,7 @@ void LLAgentCamera::updateCamera() gAgentCamera.clearPanKeys(); // lerp camera focus offset - mCameraFocusOffset = lerp(mCameraFocusOffset, mCameraFocusOffsetTarget, LLCriticalDamp::getInterpolant(CAMERA_FOCUS_HALF_LIFE)); + mCameraFocusOffset = lerp(mCameraFocusOffset, mCameraFocusOffsetTarget, LLSmoothInterpolation::getInterpolant(CAMERA_FOCUS_HALF_LIFE)); if ( mCameraMode == CAMERA_MODE_FOLLOW ) { @@ -1389,7 +1413,7 @@ void LLAgentCamera::updateCamera() const F32 SMOOTHING_HALF_LIFE = 0.02f; static const LLCachedControl camera_position_smoothing("CameraPositionSmoothing"); - F32 smoothing = LLCriticalDamp::getInterpolant(camera_position_smoothing * SMOOTHING_HALF_LIFE, FALSE); + F32 smoothing = LLSmoothInterpolation::getInterpolant(camera_position_smoothing * SMOOTHING_HALF_LIFE, FALSE); if (!mFocusObject) // we differentiate on avatar mode { @@ -1419,9 +1443,9 @@ void LLAgentCamera::updateCamera() } - mCameraCurrentFOVZoomFactor = lerp(mCameraCurrentFOVZoomFactor, mCameraFOVZoomFactor, LLCriticalDamp::getInterpolant(FOV_ZOOM_HALF_LIFE)); + mCameraCurrentFOVZoomFactor = lerp(mCameraCurrentFOVZoomFactor, mCameraFOVZoomFactor, LLSmoothInterpolation::getInterpolant(FOV_ZOOM_HALF_LIFE)); -// llinfos << "Current FOV Zoom: " << mCameraCurrentFOVZoomFactor << " Target FOV Zoom: " << mCameraFOVZoomFactor << " Object penetration: " << mFocusObjectDist << llendl; +// LL_INFOS() << "Current FOV Zoom: " << mCameraCurrentFOVZoomFactor << " Target FOV Zoom: " << mCameraFOVZoomFactor << " Object penetration: " << mFocusObjectDist << LL_ENDL; F32 ui_offset = 0.f; if( CAMERA_MODE_CUSTOMIZE_AVATAR == mCameraMode ) @@ -1461,20 +1485,18 @@ void LLAgentCamera::updateCamera() } gAgent.setLastPositionGlobal(global_pos); - if (LLVOAvatar::sVisibleInFirstPerson && isAgentAvatarValid() && !gAgentAvatarp->isSitting() && cameraMouselook()) + if (LLVOAvatar::sVisibleInFirstPerson && isAgentAvatarValid() && (realistic_ml || !gAgentAvatarp->isSitting()) && cameraMouselook()) { LLVector3 head_pos = gAgentAvatarp->mHeadp->getWorldPosition() + LLVector3(0.08f, 0.f, 0.05f) * gAgentAvatarp->mHeadp->getWorldRotation() + LLVector3(0.1f, 0.f, 0.f) * gAgentAvatarp->mPelvisp->getWorldRotation(); - LLVector3 diff = mCameraPositionAgent - head_pos; - diff = diff * ~gAgentAvatarp->mRoot->getWorldRotation(); LLJoint* torso_joint = gAgentAvatarp->mTorsop; LLJoint* chest_joint = gAgentAvatarp->mChestp; LLVector3 torso_scale = torso_joint->getScale(); LLVector3 chest_scale = chest_joint->getScale(); - // shorten avatar skeleton to avoid foot interpenetration + /*// shorten avatar skeleton to avoid foot interpenetration if (!gAgentAvatarp->mInAir) { LLVector3 chest_offset = LLVector3(0.f, 0.f, chest_joint->getPosition().mV[VZ]) * torso_joint->getWorldRotation(); @@ -1487,9 +1509,21 @@ void LLAgentCamera::updateCamera() scale_factor = llclamp(1.f - ((z_compensate * 0.5f) / neck_offset.mV[VZ]), 0.5f, 1.2f); chest_joint->setScale(LLVector3(1.f, 1.f, scale_factor)); diff.mV[VZ] = 0.f; - } + }*/ - gAgentAvatarp->mPelvisp->setPosition(gAgentAvatarp->mPelvisp->getPosition() + diff); + if (realistic_ml) + { + LLQuaternion agent_rot(gAgent.getFrameAgent().getQuaternion()); + if (LLViewerObject* parent = static_cast(gAgentAvatarp->getParent())) + if (static_cast(gAgentAvatarp->getRoot())->flagCameraDecoupled()) + agent_rot *= parent->getRenderRotation(); + LLViewerCamera::getInstance()->updateCameraLocation(head_pos, mCameraUpVector, gAgentAvatarp->mHeadp->getWorldPosition() + LLVector3(1.0, 0.0, 0.0) * agent_rot); + } + else + { + const LLVector3 diff((mCameraPositionAgent - head_pos) * ~gAgentAvatarp->mRoot->getWorldRotation()); + gAgentAvatarp->mPelvisp->setPosition(gAgentAvatarp->mPelvisp->getPosition() + diff); + } gAgentAvatarp->mRoot->updateWorldMatrixChildren(); @@ -1576,7 +1610,7 @@ F32 LLAgentCamera::calcCustomizeAvatarUIOffset( const LLVector3d& camera_pos_glo } } F32 range = (F32)dist_vec(camera_pos_global, gAgentCamera.getFocusGlobal()); - mUIOffset = lerp(mUIOffset, ui_offset, LLCriticalDamp::getInterpolant(0.05f)); + mUIOffset = lerp(mUIOffset, ui_offset, LLSmoothInterpolation::getInterpolant(0.05f)); return mUIOffset * range; } @@ -1621,10 +1655,11 @@ LLVector3d LLAgentCamera::calcFocusPositionTargetGlobal() { LLDrawable* drawablep = mFocusObject->mDrawable; - static const LLCachedControl track_focus_object("TrackFocusObject"); - if (track_focus_object && drawablep) + if (mTrackFocusObject && + drawablep && + drawablep->isActive()) { - if (drawablep->isActive() && !mFocusObject->isAvatar()) + if (!mFocusObject->isAvatar()) { if (mFocusObject->isSelected()) { @@ -1771,7 +1806,7 @@ LLVector3d LLAgentCamera::calcCameraPositionTargetGlobal(BOOL *hit_limit) { if (!isAgentAvatarValid() || gAgentAvatarp->mDrawable.isNull()) { - llwarns << "Null avatar drawable!" << llendl; + LL_WARNS() << "Null avatar drawable!" << LL_ENDL; return LLVector3d::zero; } head_offset.clearVec(); @@ -1781,7 +1816,7 @@ LLVector3d LLAgentCamera::calcCameraPositionTargetGlobal(BOOL *hit_limit) head_offset.mdV[VX] = gAgentAvatarp->mHeadOffset.mV[VX]; head_offset.mdV[VY] = gAgentAvatarp->mHeadOffset.mV[VY]; head_offset.mdV[VZ] = gAgentAvatarp->mHeadOffset.mV[VZ] + 0.1f; - const LLMatrix4& mat = ((LLViewerObject*) gAgentAvatarp->getParent())->getRenderMatrix(); + const LLMatrix4 mat(((LLViewerObject*) gAgentAvatarp->getParent())->getRenderMatrix().getF32ptr()); camera_position_global = gAgent.getPosGlobalFromAgent ((gAgentAvatarp->getPosition()+ LLVector3(head_offset)*gAgentAvatarp->getRotation()) * mat); @@ -1840,7 +1875,7 @@ LLVector3d LLAgentCamera::calcCameraPositionTargetGlobal(BOOL *hit_limit) static const LLCachedControl sg_ignore_sim_cam_consts("SGIgnoreSimulatorCameraConstraints",false); if ( !mCameraCollidePlane.isExactlyZero() - && !sg_ignore_sim_cam_consts + && (!sg_ignore_sim_cam_consts || gRlvHandler.hasBehaviour(RLV_BHVR_CAMUNLOCK)) && isAgentAvatarValid() && !gAgentAvatarp->isSitting()) { @@ -1884,7 +1919,7 @@ LLVector3d LLAgentCamera::calcCameraPositionTargetGlobal(BOOL *hit_limit) if (mTargetCameraDistance != mCurrentCameraDistance) { - F32 camera_lerp_amt = LLCriticalDamp::getInterpolant(CAMERA_ZOOM_HALF_LIFE); + F32 camera_lerp_amt = LLSmoothInterpolation::getInterpolant(CAMERA_ZOOM_HALF_LIFE); mCurrentCameraDistance = lerp(mCurrentCameraDistance, mTargetCameraDistance, camera_lerp_amt); } @@ -1901,7 +1936,7 @@ LLVector3d LLAgentCamera::calcCameraPositionTargetGlobal(BOOL *hit_limit) if (isAgentAvatarValid()) { LLVector3d camera_lag_d; - F32 lag_interp = LLCriticalDamp::getInterpolant(CAMERA_LAG_HALF_LIFE); + F32 lag_interp = LLSmoothInterpolation::getInterpolant(CAMERA_LAG_HALF_LIFE); LLVector3 target_lag; LLVector3 vel = gAgent.getVelocity(); @@ -1947,7 +1982,7 @@ LLVector3d LLAgentCamera::calcCameraPositionTargetGlobal(BOOL *hit_limit) } else { - mCameraLag = lerp(mCameraLag, LLVector3::zero, LLCriticalDamp::getInterpolant(0.15f)); + mCameraLag = lerp(mCameraLag, LLVector3::zero, LLSmoothInterpolation::getInterpolant(0.15f)); } camera_lag_d.setVec(mCameraLag); @@ -1996,6 +2031,35 @@ LLVector3d LLAgentCamera::calcCameraPositionTargetGlobal(BOOL *hit_limit) // } } +// [RLVa:LF] - @camdistmax, @camdistmin + if (rlv_handler_t::isEnabled() && !cameraMouselook()) + { + // Constrainy stuffs ish based off above code + const LLVector3d agent_pos(gAgent.getPositionGlobal()); + const LLVector3d offset(camera_position_global - agent_pos); + const F32 total_dist(offset.magVec()); + bool rlvConstrained = false; // You Only Constrain Once + if (gRlvHandler.hasBehaviour(RLV_BHVR_CAMDISTMAX)) + { + F32 max_dist(gRlvHandler.camPole(RLV_BHVR_CAMDISTMAX)); + if (total_dist > max_dist) + { + camera_position_global = agent_pos + (max_dist/total_dist)*offset; + rlvConstrained = isConstrained = true; + } + } + if (!rlvConstrained && gRlvHandler.hasBehaviour(RLV_BHVR_CAMDISTMIN)) + { + F32 min_dist(gRlvHandler.camPole(RLV_BHVR_CAMDISTMIN)); + if (total_dist < min_dist) + { + camera_position_global = agent_pos + (min_dist/total_dist)*offset; + rlvConstrained = isConstrained = true; + } + } + } +// [/RLVa:LF] + // Don't let camera go underground F32 camera_min_off_ground = getCameraMinOffGround(); @@ -2022,6 +2086,22 @@ LLVector3 LLAgentCamera::getCameraOffsetInitial() return convert_from_llsd(mCameraOffsetInitial[mCameraPreset]->get(), TYPE_VEC3, ""); } +// Adds change to vector CachedControl, vec, at idx +template +void change_vec(const T& change, LLCachedControl& vec, const U32& idx = VZ) +{ + Vec changed(vec); + changed[idx] += change; + vec = changed; +} +// Same as above, but for ControlVariables +template +void change_vec(const T& change, LLPointer& vec, const U32& idx = VZ) +{ + Vec changed(vec->get()); + changed[idx] += change; + vec->set(changed.getValue()); +} //----------------------------------------------------------------------------- // handleScrollWheel() @@ -2057,6 +2137,23 @@ void LLAgentCamera::handleScrollWheel(S32 clicks) } else if (mFocusOnAvatar && (mCameraMode == CAMERA_MODE_THIRD_PERSON)) { + if (MASK mask = gKeyboard->currentMask(true)) // Singu Note: Conveniently set view offsets while modifier keys are held during scroll + { + static const LLCachedControl enableCameraOffsetScroll("SinguOffsetScrollKeys"); + if (mask & (MASK_CONTROL|MASK_SHIFT) && enableCameraOffsetScroll) + { + const F32 change(static_cast(clicks) * 0.1f); + if (mask & MASK_SHIFT) + { + change_vec(change, mFocusOffsetInitial[mCameraPreset]); + } + if (mask & MASK_CONTROL) + { + change_vec(change, mCameraOffsetInitial[mCameraPreset]); + } + return; + } + } F32 camera_offset_initial_mag = getCameraOffsetInitial().magVec(); static const LLCachedControl camera_offset_scale("CameraOffsetScale"); @@ -2073,6 +2170,15 @@ void LLAgentCamera::handleScrollWheel(S32 clicks) } } +//----------------------------------------------------------------------------- +// resetPresetOffsets() - Sets the current preset back to its default state +//----------------------------------------------------------------------------- +void LLAgentCamera::resetPresetOffsets() +{ + mFocusOffsetInitial[mCameraPreset]->resetToDefault(); + mCameraOffsetInitial[mCameraPreset]->resetToDefault(); +} + //----------------------------------------------------------------------------- // getCameraMinOffGround() @@ -2119,6 +2225,8 @@ void LLAgentCamera::resetCamera() //----------------------------------------------------------------------------- void LLAgentCamera::changeCameraToMouselook(BOOL animate) { + if (gRlvHandler.hasBehaviour(RLV_BHVR_CAMDISTMIN) && gRlvHandler.camPole(RLV_BHVR_CAMDISTMIN) > 0) return; // [RLVa:LF] - @camdistmin + if (!gSavedSettings.getBOOL("EnableMouselook") || LLViewerJoystick::getInstance()->getOverrideCamera()) { @@ -2149,15 +2257,16 @@ void LLAgentCamera::changeCameraToMouselook(BOOL animate) //gViewerWindow->stopGrab(); LLSelectMgr::getInstance()->deselectAll(); - gViewerWindow->hideCursor(); - gViewerWindow->moveCursorToCenter(); +// gViewerWindow->hideCursor(); +// gViewerWindow->moveCursorToCenter(); if (mCameraMode != CAMERA_MODE_MOUSELOOK) { mMouselookTimer.reset(); - gFocusMgr.setKeyboardFocus( NULL ); - if (gSavedSettings.getBOOL("AONoStandsInMouselook")) LLFloaterAO::stopMotion(LLFloaterAO::getCurrentStandId(), FALSE,TRUE); + gFocusMgr.setKeyboardFocus(NULL); + auto ao = AOSystem::getIfExists(); + if (ao && gSavedSettings.getBOOL("AONoStandsInMouselook")) ao->stopCurrentStand(); updateLastCamera(); mCameraMode = CAMERA_MODE_MOUSELOOK; @@ -2207,6 +2316,8 @@ void LLAgentCamera::changeCameraToDefault() //----------------------------------------------------------------------------- void LLAgentCamera::changeCameraToFollow(BOOL animate) { + if (gRlvHandler.hasBehaviour(RLV_BHVR_CAMDISTMAX) && 0 >= gRlvHandler.camPole(RLV_BHVR_CAMDISTMAX)) return; // [RLVa:LF] - @camdistmax + if (LLViewerJoystick::getInstance()->getOverrideCamera()) { return; @@ -2217,6 +2328,7 @@ void LLAgentCamera::changeCameraToFollow(BOOL animate) if (mCameraMode == CAMERA_MODE_MOUSELOOK) { animate = FALSE; + if (gViewerWindow->getRightMouseDown()) LLViewerCamera::instance().loadDefaultFOV(); // We could be zoomed in } startCameraAnimation(); @@ -2264,6 +2376,8 @@ void LLAgentCamera::changeCameraToFollow(BOOL animate) //----------------------------------------------------------------------------- void LLAgentCamera::changeCameraToThirdPerson(BOOL animate) { + if (gRlvHandler.hasBehaviour(RLV_BHVR_CAMDISTMAX) && 0 >= gRlvHandler.camPole(RLV_BHVR_CAMDISTMAX)) return; // [RLVa:LF] - @camdistmax + if (LLViewerJoystick::getInstance()->getOverrideCamera()) { return; @@ -2306,6 +2420,7 @@ void LLAgentCamera::changeCameraToThirdPerson(BOOL animate) mCurrentCameraDistance = MIN_CAMERA_DISTANCE; mTargetCameraDistance = MIN_CAMERA_DISTANCE; animate = FALSE; + if (gViewerWindow->getRightMouseDown()) LLViewerCamera::instance().loadDefaultFOV(); // We could be zoomed in } updateLastCamera(); mCameraMode = CAMERA_MODE_THIRD_PERSON; @@ -2346,6 +2461,8 @@ void LLAgentCamera::changeCameraToThirdPerson(BOOL animate) //----------------------------------------------------------------------------- void LLAgentCamera::changeCameraToCustomizeAvatar() { + if (gRlvHandler.hasBehaviour(RLV_BHVR_CAMDISTMAX) && 0 >= gRlvHandler.camPole(RLV_BHVR_CAMDISTMAX)) return; // [RLVa:LF] - @camdistmax + if (LLViewerJoystick::getInstance()->getOverrideCamera() || !isAgentAvatarValid()) { return; @@ -2391,15 +2508,18 @@ void LLAgentCamera::changeCameraToCustomizeAvatar() at.normalize(); gAgent.resetAxes(at); - gAgent.sendAnimationRequest(ANIM_AGENT_CUSTOMIZE, ANIM_REQUEST_START); - gAgent.setCustomAnim(TRUE); - gAgentAvatarp->startMotion(ANIM_AGENT_CUSTOMIZE); - LLMotion* turn_motion = gAgentAvatarp->findMotion(ANIM_AGENT_CUSTOMIZE); - - if (turn_motion) + if (gSavedSettings.getBOOL("LiruCustomizeAnim")) { - // delay camera animation long enough to play through turn animation - setAnimationDuration(turn_motion->getDuration() + CUSTOMIZE_AVATAR_CAMERA_ANIM_SLOP); + gAgent.sendAnimationRequest(ANIM_AGENT_CUSTOMIZE, ANIM_REQUEST_START); + gAgent.setCustomAnim(TRUE); + gAgentAvatarp->startMotion(ANIM_AGENT_CUSTOMIZE); + LLMotion* turn_motion = gAgentAvatarp->findMotion(ANIM_AGENT_CUSTOMIZE); + + if (turn_motion) + { + // delay camera animation long enough to play through turn animation + setAnimationDuration(turn_motion->getDuration() + CUSTOMIZE_AVATAR_CAMERA_ANIM_SLOP); + } } } // @@ -2428,8 +2548,6 @@ void LLAgentCamera::changeCameraToCustomizeAvatar() LLVector3d focus_target_global = gAgent.getPosGlobalFromAgent(focus_target); setAnimationDuration(gSavedSettings.getF32("ZoomTime")); setCameraPosAndFocusGlobal(focus_target_global + camera_offset, focus_target_global, gAgent.getID()); - - } @@ -2741,6 +2859,7 @@ void LLAgentCamera::setFocusOnAvatar(BOOL focus_on_avatar, BOOL animate) { // keep camera focus point consistent, even though it is now unlocked setFocusGlobal(gAgent.getPositionGlobal() + calcThirdPersonFocusOffset(), gAgent.getID()); + mAllowChangeToFollow = FALSE; } mFocusOnAvatar = focus_on_avatar; @@ -2878,6 +2997,10 @@ bool LLAgentCamera::lookAtObject(const LLUUID &object_id, bool self) return true; } +bool LLAgentCamera::isfollowCamLocked() +{ + return mFollowCam.getPositionLocked(); +} BOOL LLAgentCamera::setPointAt(EPointAtType target_type, LLViewerObject *object, LLVector3 position) { @@ -2952,3 +3075,4 @@ S32 LLAgentCamera::directionToKey(S32 direction) // EOF + diff --git a/indra/newview/llagentcamera.h b/indra/newview/llagentcamera.h index 3a2ced0582..6d580fd450 100644 --- a/indra/newview/llagentcamera.h +++ b/indra/newview/llagentcamera.h @@ -88,11 +88,9 @@ class LLAgentCamera void changeCameraToDefault(); void changeCameraToMouselook(BOOL animate = TRUE); void changeCameraToThirdPerson(BOOL animate = TRUE); - void changeCameraToCustomizeAvatar(); // trigger transition animation + void changeCameraToCustomizeAvatar(); // Trigger transition animation F32 calcCustomizeAvatarUIOffset( const LLVector3d& camera_pos_global ); - // Ventrella - void changeCameraToFollow(BOOL animate = TRUE); - //end Ventrella + void changeCameraToFollow(BOOL animate = TRUE); // Ventrella BOOL cameraThirdPerson() const { return (mCameraMode == CAMERA_MODE_THIRD_PERSON && mLastCameraMode == CAMERA_MODE_THIRD_PERSON); } BOOL cameraMouselook() const { return (mCameraMode == CAMERA_MODE_MOUSELOOK && mLastCameraMode == CAMERA_MODE_MOUSELOOK); } BOOL cameraCustomizeAvatar() const { return (mCameraMode == CAMERA_MODE_CUSTOMIZE_AVATAR /*&& !mCameraAnimating*/); } @@ -113,6 +111,9 @@ class LLAgentCamera //-------------------------------------------------------------------- public: void switchCameraPreset(ECameraPreset preset); + + /** Sets the current preset back to its default state */ + void resetPresetOffsets(); private: /** Determines default camera offset depending on the current camera preset */ LLVector3 getCameraOffsetInitial(); @@ -159,6 +160,7 @@ class LLAgentCamera //-------------------------------------------------------------------- public: void setUsingFollowCam(bool using_follow_cam); + bool isfollowCamLocked(); private: LLFollowCam mFollowCam; // Ventrella @@ -211,18 +213,22 @@ class LLAgentCamera void setCameraPosAndFocusGlobal(const LLVector3d& pos, const LLVector3d& focus, const LLUUID &object_id); void clearFocusObject(); void setFocusObject(LLViewerObject* object); + void setAllowChangeToFollow(BOOL focus) { mAllowChangeToFollow = focus; } + void setObjectTracking(BOOL track) { mTrackFocusObject = track; } const LLVector3d &getFocusGlobal() const { return mFocusGlobal; } const LLVector3d &getFocusTargetGlobal() const { return mFocusTargetGlobal; } private: LLVector3d mCameraFocusOffset; // Offset from focus point in build mode LLVector3d mCameraFocusOffsetTarget; // Target towards which we are lerping the camera's focus offset BOOL mFocusOnAvatar; + BOOL mAllowChangeToFollow; LLVector3d mFocusGlobal; LLVector3d mFocusTargetGlobal; LLPointer mFocusObject; F32 mFocusObjectDist; LLVector3 mFocusObjectOffset; F32 mFocusDotRadius; // Meters + BOOL mTrackFocusObject; //-------------------------------------------------------------------- // Lookat / Pointat diff --git a/indra/newview/llagentpilot.cpp b/indra/newview/llagentpilot.cpp index 035c9426a1..576aea61b9 100644 --- a/indra/newview/llagentpilot.cpp +++ b/indra/newview/llagentpilot.cpp @@ -72,13 +72,13 @@ void LLAgentPilot::load(const std::string& filename) if (!file) { - lldebugs << "Couldn't open " << filename - << ", aborting agentpilot load!" << llendl; + LL_DEBUGS() << "Couldn't open " << filename + << ", aborting agentpilot load!" << LL_ENDL; return; } else { - llinfos << "Opening pilot file " << filename << llendl; + LL_INFOS() << "Opening pilot file " << filename << LL_ENDL; } S32 num_actions; @@ -92,7 +92,7 @@ void LLAgentPilot::load(const std::string& filename) file >> new_action.mTime >> action_type; file >> new_action.mTarget.mdV[VX] >> new_action.mTarget.mdV[VY] >> new_action.mTarget.mdV[VZ]; new_action.mType = (EActionType)action_type; - mActions.put(new_action); + mActions.push_back(new_action); } file.close(); @@ -105,16 +105,17 @@ void LLAgentPilot::save(const std::string& filename) if (!file) { - llinfos << "Couldn't open " << filename << ", aborting agentpilot save!" << llendl; + LL_INFOS() << "Couldn't open " << filename << ", aborting agentpilot save!" << LL_ENDL; } - file << mActions.count() << '\n'; + file << mActions.size() << '\n'; - S32 i; - for (i = 0; i < mActions.count(); i++) + U32 i; + for (i = 0; i < mActions.size(); i++) { file << mActions[i].mTime << "\t" << mActions[i].mType << "\t"; - file << std::setprecision(32) << mActions[i].mTarget.mdV[VX] << "\t" << mActions[i].mTarget.mdV[VY] << "\t" << mActions[i].mTarget.mdV[VZ] << '\n'; + file << std::setprecision(32) << mActions[i].mTarget.mdV[VX] << "\t" << mActions[i].mTarget.mdV[VY] << "\t" << mActions[i].mTarget.mdV[VZ]; + file << '\n'; } file.close(); @@ -122,7 +123,7 @@ void LLAgentPilot::save(const std::string& filename) void LLAgentPilot::startRecord() { - mActions.reset(); + mActions.clear(); mTimer.reset(); addAction(STRAIGHT); mRecording = TRUE; @@ -137,13 +138,13 @@ void LLAgentPilot::stopRecord() void LLAgentPilot::addAction(enum EActionType action_type) { - llinfos << "Adding waypoint: " << gAgent.getPositionGlobal() << llendl; + LL_INFOS() << "Adding waypoint: " << gAgent.getPositionGlobal() << LL_ENDL; Action action; action.mType = action_type; action.mTarget = gAgent.getPositionGlobal(); action.mTime = mTimer.getElapsedTimeF32(); mLastRecordTime = (F32)action.mTime; - mActions.put(action); + mActions.push_back(action); } void LLAgentPilot::startPlayback() @@ -154,15 +155,15 @@ void LLAgentPilot::startPlayback() mCurrentAction = 0; mTimer.reset(); - if (mActions.count()) + if (mActions.size()) { - llinfos << "Starting playback, moving to waypoint 0" << llendl; + LL_INFOS() << "Starting playback, moving to waypoint 0" << LL_ENDL; gAgent.startAutoPilotGlobal(mActions[0].mTarget); mStarted = FALSE; } else { - llinfos << "No autopilot data, cancelling!" << llendl; + LL_INFOS() << "No autopilot data, cancelling!" << LL_ENDL; mPlaying = FALSE; } } @@ -183,7 +184,7 @@ void LLAgentPilot::updateTarget() { if (mPlaying) { - if (mCurrentAction < mActions.count()) + if (mCurrentAction < (S32)mActions.size()) { if (0 == mCurrentAction) { @@ -196,7 +197,7 @@ void LLAgentPilot::updateTarget() { if (!mStarted) { - llinfos << "At start, beginning playback" << llendl; + LL_INFOS() << "At start, beginning playback" << LL_ENDL; mTimer.reset(); LLFrameStats::startLogging(NULL); mStarted = TRUE; @@ -208,7 +209,7 @@ void LLAgentPilot::updateTarget() //gAgent.stopAutoPilot(); mCurrentAction++; - if (mCurrentAction < mActions.count()) + if (mCurrentAction < (S32)mActions.size()) { gAgent.startAutoPilotGlobal(mActions[mCurrentAction].mTarget); } @@ -221,17 +222,17 @@ void LLAgentPilot::updateTarget() { if ((mNumRuns < 0) || (mNumRuns > 0)) { - llinfos << "Looping, restarting playback" << llendl; + LL_INFOS() << "Looping, restarting playback" << LL_ENDL; startPlayback(); } else if (mQuitAfterRuns) { - llinfos << "Done with all runs, quitting viewer!" << llendl; + LL_INFOS() << "Done with all runs, quitting viewer!" << LL_ENDL; LLAppViewer::instance()->forceQuit(); } else { - llinfos << "Done with all runs, disabling pilot" << llendl; + LL_INFOS() << "Done with all runs, disabling pilot" << LL_ENDL; stopPlayback(); } } diff --git a/indra/newview/llagentpilot.h b/indra/newview/llagentpilot.h index 0ad4772f68..96f39eead4 100644 --- a/indra/newview/llagentpilot.h +++ b/indra/newview/llagentpilot.h @@ -36,7 +36,6 @@ #include "stdtypes.h" #include "lltimer.h" #include "v3dmath.h" -#include "lldarray.h" // Class that drives the agent around according to a "script". @@ -92,7 +91,7 @@ class LLAgentPilot F64 mTime; }; - LLDynamicArray mActions; + std::vector mActions; LLTimer mTimer; }; diff --git a/indra/newview/llagentui.cpp b/indra/newview/llagentui.cpp index 0fcc5fb2b2..d8ab02436b 100644 --- a/indra/newview/llagentui.cpp +++ b/indra/newview/llagentui.cpp @@ -56,7 +56,8 @@ void LLAgentUI::buildSLURL(LLSLURL& slurl, const bool escaped /*= true*/) LLViewerRegion *regionp = gAgent.getRegion(); if (regionp) { - return_slurl = LLSLURL(regionp->getName(), gAgent.getPositionGlobal()); + // Singu Note: Not Global, get correct SLURL for Variable Regions + return_slurl = LLSLURL(regionp->getName(), gAgent.getPositionAgent()); } slurl = return_slurl; } diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp index 9bb2301240..30a86d723a 100644 --- a/indra/newview/llagentwearables.cpp +++ b/indra/newview/llagentwearables.cpp @@ -27,17 +27,21 @@ #include "llviewerprecompiledheaders.h" #include "llagentwearables.h" +#include "llattachmentsmgr.h" #include "llagent.h" #include "llagentcamera.h" #include "llagentwearablesfetch.h" #include "llappearancemgr.h" +#include "llattachmentsmgr.h" #include "llcallbacklist.h" +#include "llfloatercustomize.h" #include "llfolderview.h" #include "llgesturemgr.h" #include "llinventorybridge.h" #include "llinventoryfunctions.h" #include "llinventoryobserver.h" #include "llinventorypanel.h" +#include "lllocaltextureobject.h" #include "llpanelmaininventory.h" #include "llmd5.h" #include "llnotificationsutil.h" @@ -46,16 +50,16 @@ #include "lltooldraganddrop.h" #include "llviewerregion.h" #include "llvoavatarself.h" -#include "llwearable.h" +#include "llviewerwearable.h" #include "llwearablelist.h" +#include "lllocaltextureobject.h" -#include "llfloatercustomize.h" +#include "llfloaterperms.h" -// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a) +// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1) #include "rlvhandler.h" -#include "rlvinventory.h" -#include "llattachmentsmgr.h" +#include "rlvlocks.h" // [/RLVa:KB] #include "hippogridmanager.h" @@ -65,24 +69,69 @@ LLAgentWearables gAgentWearables; BOOL LLAgentWearables::mInitialWearablesUpdateReceived = FALSE; -// [SL:KB] - Patch: Appearance-InitialWearablesLoadedCallback | Checked: 2010-08-14 (Catznip-3.0.0a) | Added: Catznip-2.1.1d +// [SL:KB] - Patch: Appearance-InitialWearablesLoadedCallback | Checked: 2010-08-14 (Catznip-2.1) bool LLAgentWearables::mInitialWearablesLoaded = false; // [/SL:KB] +// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1) +bool LLAgentWearables::mInitialAttachmentsRequested = false; +// [/RLVa:KB] using namespace LLAvatarAppearanceDefines; /////////////////////////////////////////////////////////////////////////////// +void set_default_permissions(LLViewerInventoryItem* item) +{ + llassert(item); + LLPermissions perm = item->getPermissions(); + if (perm.getMaskNextOwner() != LLFloaterPerms::getNextOwnerPerms("Wearables") + || perm.getMaskEveryone() != LLFloaterPerms::getEveryonePerms("Wearables") + || perm.getMaskGroup() != LLFloaterPerms::getGroupPerms("Wearables")) + { + perm.setMaskNext(LLFloaterPerms::getNextOwnerPerms("Wearables")); + perm.setMaskEveryone(LLFloaterPerms::getEveryonePerms("Wearables")); + perm.setMaskGroup(LLFloaterPerms::getGroupPerms("Wearables")); + + item->setPermissions(perm); + + item->updateServer(FALSE); + } +} + // Callback to wear and start editing an item that has just been created. void wear_and_edit_cb(const LLUUID& inv_item) { if (inv_item.isNull()) return; - + + LLViewerInventoryItem* item = gInventory.getItem(inv_item); + if (!item) return; + + set_default_permissions(item); + + // item was just created, update even if permissions did not changed + gInventory.updateItem(item); + gInventory.notifyObservers(); + // Request editing the item after it gets worn. gAgentWearables.requestEditingWearable(inv_item); // Wear it. - LLAppearanceMgr::instance().wearItemOnAvatar(inv_item); + LLAppearanceMgr::instance().wearItemOnAvatar(inv_item,true); +} + +void wear_cb(const LLUUID& inv_item) +{ + if (!inv_item.isNull()) + { + LLViewerInventoryItem* item = gInventory.getItem(inv_item); + if (item) + { + set_default_permissions(item); + + gInventory.updateItem(item); + gInventory.notifyObservers(); + } + } } /////////////////////////////////////////////////////////////////////////////// @@ -103,65 +152,58 @@ void checkWearableAgainstInventory(LLViewerWearable *wearable) { if (!item->isWearableType()) { - llwarns << "wearable associated with non-wearable item" << llendl; + LL_WARNS() << "wearable associated with non-wearable item" << LL_ENDL; } if (item->getWearableType() != wearable->getType()) { - llwarns << "type mismatch: wearable " << wearable->getName() + LL_WARNS() << "type mismatch: wearable " << wearable->getName() << " has type " << wearable->getType() << " but inventory item " << item->getName() - << " has type " << item->getWearableType() << llendl; + << " has type " << item->getWearableType() << LL_ENDL; } } else { - llwarns << "wearable inventory item not found" << wearable->getName() - << " itemID " << wearable->getItemID().asString() << llendl; + LL_WARNS() << "wearable inventory item not found" << wearable->getName() + << " itemID " << wearable->getItemID().asString() << LL_ENDL; } } void LLAgentWearables::dump() { - llinfos << "LLAgentWearablesDump" << llendl; + LL_INFOS() << "LLAgentWearablesDump" << LL_ENDL; for (S32 i = 0; i < LLWearableType::WT_COUNT; i++) { U32 count = getWearableCount((LLWearableType::EType)i); - llinfos << "Type: " << i << " count " << count << llendl; + LL_INFOS() << "Type: " << i << " count " << count << LL_ENDL; for (U32 j=0; jgetName() - << " description " << wearable->getDescription() << llendl; + LL_INFOS() << " " << j << " Name " << wearable->getName() + << " description " << wearable->getDescription() << LL_ENDL; } } - llinfos << "Total items awaiting wearable update " << mItemsAwaitingWearableUpdate.size() << llendl; - for (std::set::iterator it = mItemsAwaitingWearableUpdate.begin(); - it != mItemsAwaitingWearableUpdate.end(); - ++it) - { - llinfos << (*it).asString() << llendl; - } } struct LLAgentDumper { LLAgentDumper(std::string name): - mName(name) + mName(std::move(name)) { - llinfos << llendl; - llinfos << "LLAgentDumper " << mName << llendl; + LL_INFOS() << LL_ENDL; + LL_INFOS() << "LLAgentDumper " << mName << LL_ENDL; gAgentWearables.dump(); } ~LLAgentDumper() { - llinfos << llendl; - llinfos << "~LLAgentDumper " << mName << llendl; + LL_INFOS() << LL_ENDL; + LL_INFOS() << "~LLAgentDumper " << mName << LL_ENDL; gAgentWearables.dump(); } @@ -197,82 +239,59 @@ void LLAgentWearables::setAvatarObject(LLVOAvatarSelf *avatar) llassert(avatar); if (avatar) { - avatar->outputRezTiming("Sending wearables request"); - sendAgentWearablesRequest(); + if(!gHippoGridManager->getConnectedGrid()->isSecondLife()) + { + avatar->outputRezTiming("Sending wearables request"); + gMessageSystem->newMessageFast(_PREHASH_AgentWearablesRequest); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() ); + gAgent.sendReliableMessage(); + } setAvatarAppearance(avatar); } } -// wearables -LLAgentWearables::createStandardWearablesAllDoneCallback::~createStandardWearablesAllDoneCallback() -{ - llinfos << "destructor - all done?" << llendl; - gAgentWearables.createStandardWearablesAllDone(); -} - -LLAgentWearables::sendAgentWearablesUpdateCallback::~sendAgentWearablesUpdateCallback() -{ - gAgentWearables.sendAgentWearablesUpdate(); -} - /** * @brief Construct a callback for dealing with the wearables. * * Would like to pass the agent in here, but we can't safely * count on it being around later. Just use gAgent directly. - * @param cb callback to execute on completion (??? unused ???) + * @param cb callback to execute on completion (? unused ?) * @param type Type for the wearable in the agent * @param wearable The wearable data. * @param todo Bitmask of actions to take on completion. */ -LLAgentWearables::addWearableToAgentInventoryCallback::addWearableToAgentInventoryCallback( +LLAgentWearables::AddWearableToAgentInventoryCallback::AddWearableToAgentInventoryCallback( LLPointer cb, LLWearableType::EType type, U32 index, LLViewerWearable* wearable, U32 todo, const std::string description) : mType(type), mIndex(index), mWearable(wearable), mTodo(todo), - mCB(cb), + mCB(std::move(cb)), mDescription(description) { - llinfos << "constructor" << llendl; + LL_INFOS() << "constructor" << LL_ENDL; } -void LLAgentWearables::addWearableToAgentInventoryCallback::fire(const LLUUID& inv_item) +void LLAgentWearables::AddWearableToAgentInventoryCallback::fire(const LLUUID& inv_item) { - if (mTodo & CALL_CREATESTANDARDDONE) - { - llinfos << "callback fired, inv_item " << inv_item.asString() << llendl; - } - if (inv_item.isNull()) return; gAgentWearables.addWearabletoAgentInventoryDone(mType, mIndex, inv_item, mWearable); - if (mTodo & CALL_UPDATE) - { - gAgentWearables.sendAgentWearablesUpdate(); - } - if (mTodo & CALL_RECOVERDONE) - { - LLAppearanceMgr::instance().addCOFItemLink(inv_item,false); - gAgentWearables.recoverMissingWearableDone(); - } /* * Do this for every one in the loop */ - if (mTodo & CALL_CREATESTANDARDDONE) - { - LLAppearanceMgr::instance().addCOFItemLink(inv_item,false); - gAgentWearables.createStandardWearablesDone(mType, mIndex); - } if (mTodo & CALL_MAKENEWOUTFITDONE) { gAgentWearables.makeNewOutfitDone(mType, mIndex); } if (mTodo & CALL_WEARITEM) { - LLAppearanceMgr::instance().addCOFItemLink(inv_item, true, NULL, mDescription); + LLAppearanceMgr::instance().addCOFItemLink(inv_item, + new LLUpdateAppearanceOnDestroy(true, true, boost::bind(&edit_wearable_and_customize_avatar, inv_item)), mDescription); } } @@ -281,11 +300,11 @@ void LLAgentWearables::addWearabletoAgentInventoryDone(const LLWearableType::ETy const LLUUID& item_id, LLViewerWearable* wearable) { - llinfos << "type " << type << " index " << index << " item " << item_id.asString() << llendl; + LL_INFOS() << "type " << type << " index " << index << " item " << item_id.asString() << LL_ENDL; if (item_id.isNull()) return; - + LLUUID old_item_id = getWearableItemID(type,index); if (wearable) @@ -293,7 +312,7 @@ void LLAgentWearables::addWearabletoAgentInventoryDone(const LLWearableType::ETy wearable->setItemID(item_id); if (old_item_id.notNull()) - { + { gInventory.addChangedMask(LLInventoryObserver::LABEL, old_item_id); setWearable(type,index,wearable); } @@ -306,7 +325,7 @@ void LLAgentWearables::addWearabletoAgentInventoryDone(const LLWearableType::ETy gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); LLViewerInventoryItem* item = gInventory.getItem(item_id); - if(item && wearable) + if (item && wearable) { // We're changing the asset id, so we both need to set it // locally via setAssetUUID() and via setTransactionID() which @@ -319,84 +338,9 @@ void LLAgentWearables::addWearabletoAgentInventoryDone(const LLWearableType::ETy gInventory.notifyObservers(); } -void LLAgentWearables::sendAgentWearablesUpdate() -{ - // First make sure that we have inventory items for each wearable - for (S32 type=0; type < LLWearableType::WT_COUNT; ++type) - { - for (U32 index=0; index < getWearableCount((LLWearableType::EType)type); ++index) - { - LLViewerWearable* wearable = getViewerWearable((LLWearableType::EType)type,index); - if (wearable) - { - if (wearable->getItemID().isNull()) - { - LLPointer cb = - new addWearableToAgentInventoryCallback( - LLPointer(NULL), - (LLWearableType::EType)type, - index, - wearable, - addWearableToAgentInventoryCallback::CALL_NONE); - addWearableToAgentInventory(cb, wearable); - } - else - { - gInventory.addChangedMask( LLInventoryObserver::LABEL, - wearable->getItemID()); - } - } - } - } - - // Then make sure the inventory is in sync with the avatar. - gInventory.notifyObservers(); - - // Send the AgentIsNowWearing - gMessageSystem->newMessageFast(_PREHASH_AgentIsNowWearing); - - gMessageSystem->nextBlockFast(_PREHASH_AgentData); - gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - - lldebugs << "sendAgentWearablesUpdate()" << llendl; - // MULTI-WEARABLE: DEPRECATED: HACK: index to 0- server database tables don't support concept of multiwearables. - for (S32 type=0; type < LLWearableType::WT_COUNT; ++type) - { - gMessageSystem->nextBlockFast(_PREHASH_WearableData); - - U8 type_u8 = (U8)type; - gMessageSystem->addU8Fast(_PREHASH_WearableType, type_u8 ); - - LLViewerWearable* wearable = getViewerWearable((LLWearableType::EType)type, 0); - if( wearable ) - { - //llinfos << "Sending wearable " << wearable->getName() << llendl; - LLUUID item_id = wearable->getItemID(); - const LLViewerInventoryItem *item = gInventory.getItem(item_id); - if (item && item->getIsLinkType()) - { - // Get the itemID that this item points to. i.e. make sure - // we are storing baseitems, not their links, in the database. - item_id = item->getLinkedUUID(); - } - gMessageSystem->addUUIDFast(_PREHASH_ItemID, item_id); - } - else - { - //llinfos << "Not wearing wearable type " << LLWearableType::getTypeName((LLWearableType::EType)i) << llendl; - gMessageSystem->addUUIDFast(_PREHASH_ItemID, LLUUID::null); - } - - lldebugs << " " << LLWearableType::getTypeLabel((LLWearableType::EType)type) << ": " << (wearable ? wearable->getAssetID() : LLUUID::null) << llendl; - } - gAgent.sendReliableMessage(); -} - -void LLAgentWearables::saveWearable(const LLWearableType::EType type, const U32 index, BOOL send_update, +void LLAgentWearables::saveWearable(const LLWearableType::EType type, const U32 index, const std::string new_name) { - //llassert_always(index == 0); LLViewerWearable* old_wearable = getViewerWearable(type, index); if(!old_wearable) return; bool name_changed = !new_name.empty() && (new_name != old_wearable->getName()); @@ -418,7 +362,7 @@ void LLAgentWearables::saveWearable(const LLWearableType::EType type, const U32 std::string item_name = item->getName(); if (name_changed) { - llinfos << "saveWearable changing name from " << item->getName() << " to " << new_name << llendl; + LL_INFOS() << "saveWearable changing name from " << item->getName() << " to " << new_name << LL_ENDL; item_name = new_name; } // Update existing inventory item @@ -435,23 +379,14 @@ void LLAgentWearables::saveWearable(const LLWearableType::EType type, const U32 item->getFlags(), item->getCreationDate()); template_item->setTransactionID(new_wearable->getTransactionID()); - template_item->updateServer(FALSE); - gInventory.updateItem(template_item); - if (name_changed) - { - gInventory.notifyObservers(); - } + update_inventory_item(template_item, gAgentAvatarp->mEndCustomizeCallback); } else { // Add a new inventory item (shouldn't ever happen here) - U32 todo = addWearableToAgentInventoryCallback::CALL_NONE; - if (send_update) - { - todo |= addWearableToAgentInventoryCallback::CALL_UPDATE; - } + U32 todo = AddWearableToAgentInventoryCallback::CALL_NONE; LLPointer cb = - new addWearableToAgentInventoryCallback( + new AddWearableToAgentInventoryCallback( LLPointer(NULL), type, index, @@ -462,11 +397,6 @@ void LLAgentWearables::saveWearable(const LLWearableType::EType type, const U32 } gAgentAvatarp->wearableUpdated( type, TRUE ); - - if( send_update ) - { - sendAgentWearablesUpdate(); - } } } @@ -478,21 +408,21 @@ LLViewerWearable* LLAgentWearables::saveWearableAs(const LLWearableType::EType t { if (!isWearableCopyable(type, index)) { - llwarns << "LLAgent::saveWearableAs() not copyable." << llendl; - return NULL; + LL_WARNS() << "LLAgent::saveWearableAs() not copyable." << LL_ENDL; + return nullptr; } LLViewerWearable* old_wearable = getViewerWearable(type, index); if (!old_wearable) { - llwarns << "LLAgent::saveWearableAs() no old wearable." << llendl; - return NULL; + LL_WARNS() << "LLAgent::saveWearableAs() no old wearable." << LL_ENDL; + return nullptr; } LLInventoryItem* item = gInventory.getItem(getWearableItemID(type,index)); if (!item) { - llwarns << "LLAgent::saveWearableAs() no inventory item." << llendl; - return NULL; + LL_WARNS() << "LLAgent::saveWearableAs() no inventory item." << LL_ENDL; + return nullptr; } std::string trunc_name(new_name); LLStringUtil::truncate(trunc_name, DB_INV_ITEM_NAME_STR_LEN); @@ -502,13 +432,14 @@ LLViewerWearable* LLAgentWearables::saveWearableAs(const LLWearableType::EType t old_wearable, trunc_name, trunc_description); + LLPointer cb = - new addWearableToAgentInventoryCallback( + new AddWearableToAgentInventoryCallback( LLPointer(NULL), type, index, new_wearable, - addWearableToAgentInventoryCallback::CALL_WEARITEM, + AddWearableToAgentInventoryCallback::CALL_WEARITEM, trunc_description ); LLUUID category_id; @@ -560,9 +491,8 @@ void LLAgentWearables::saveAllWearables() for (S32 i=0; i < LLWearableType::WT_COUNT; i++) { for (U32 j=0; j < getWearableCount((LLWearableType::EType)i); j++) - saveWearable((LLWearableType::EType)i, j, FALSE); + saveWearable((LLWearableType::EType)i, j); } - sendAgentWearablesUpdate(); } // Called when the user changes the name of a wearable inventory item that is currently being worn. @@ -591,7 +521,6 @@ void LLAgentWearables::setWearableName(const LLUUID& item_id, const std::string& old_wearable->setName(old_name); setWearable((LLWearableType::EType)i,j,new_wearable); - sendAgentWearablesUpdate(); break; } } @@ -628,7 +557,6 @@ void LLAgentWearables::nameOrDescriptionChanged(LLUUID const& item_id) BOOL LLAgentWearables::isWearableModifiable(LLWearableType::EType type, U32 index) const { - //llassert_always(index == 0); LLUUID item_id = getWearableItemID(type, index); return item_id.notNull() ? isWearableModifiable(item_id) : FALSE; } @@ -639,7 +567,7 @@ BOOL LLAgentWearables::isWearableModifiable(const LLUUID& item_id) const if (linked_id.notNull()) { LLInventoryItem* item = gInventory.getItem(linked_id); - if(item && item->getPermissions().allowModifyBy(gAgent.getID(), + if (item && item->getPermissions().allowModifyBy(gAgent.getID(), gAgent.getGroupID())) { return TRUE; @@ -650,12 +578,11 @@ BOOL LLAgentWearables::isWearableModifiable(const LLUUID& item_id) const BOOL LLAgentWearables::isWearableCopyable(LLWearableType::EType type, U32 index) const { - //llassert_always(index == 0); LLUUID item_id = getWearableItemID(type, index); if (!item_id.isNull()) { LLInventoryItem* item = gInventory.getItem(item_id); - if(item && item->getPermissions().allowCopyBy(gAgent.getID(), + if (item && item->getPermissions().allowCopyBy(gAgent.getID(), gAgent.getGroupID())) { return TRUE; @@ -668,24 +595,23 @@ BOOL LLAgentWearables::isWearableCopyable(LLWearableType::EType type, U32 index) U32 LLAgentWearables::getWearablePermMask(LLWearableType::EType type) { LLUUID item_id = getWearableItemID(type); - if(!item_id.isNull()) + if (!item_id.isNull()) { LLInventoryItem* item = gInventory.getItem(item_id); - if(item) + if (item) { return item->getPermissions().getMaskOwner(); } } return PERM_NONE; -} + } */ LLInventoryItem* LLAgentWearables::getWearableInventoryItem(LLWearableType::EType type, U32 index) { - //llassert_always(index == 0); LLUUID item_id = getWearableItemID(type,index); LLInventoryItem* item = NULL; - if(item_id.notNull()) + if (item_id.notNull()) { item = gInventory.getItem(item_id); } @@ -742,15 +668,6 @@ LLViewerWearable* LLAgentWearables::getWearableFromAssetID(const LLUUID& asset_i return NULL; } -void LLAgentWearables::sendAgentWearablesRequest() -{ - gMessageSystem->newMessageFast(_PREHASH_AgentWearablesRequest); - gMessageSystem->nextBlockFast(_PREHASH_AgentData); - gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); - gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() ); - gAgent.sendReliableMessage(); -} - LLViewerWearable* LLAgentWearables::getViewerWearable(const LLWearableType::EType type, U32 index /*= 0*/) { return dynamic_cast (getWearable(type, index)); @@ -772,8 +689,7 @@ void LLAgentWearables::wearableUpdated(LLWearable *wearable, BOOL removed) { if (isAgentAvatarValid()) { - const BOOL upload_result = removed; - gAgentAvatarp->wearableUpdated(wearable->getType(), upload_result); + gAgentAvatarp->wearableUpdated(wearable->getType(), removed); } LLWearableData::wearableUpdated(wearable, removed); @@ -790,10 +706,13 @@ void LLAgentWearables::wearableUpdated(LLWearable *wearable, BOOL removed) // the versions themselves are compatible. This code can be removed before release. if( wearable->getDefinitionVersion() == 24 ) { - wearable->setDefinitionVersion(22); - U32 index = getWearableIndex(wearable); - llinfos << "forcing wearable type " << wearable->getType() << " to version 22 from 24" << llendl; - saveWearable(wearable->getType(),index,TRUE); + U32 index; + if (getWearableIndex(wearable,index)) + { + LL_INFOS() << "forcing wearable type " << wearable->getType() << " to version 22 from 24" << LL_ENDL; + wearable->setDefinitionVersion(22); + saveWearable(wearable->getType(),index); + } } //Needed as wearable 'save' process is a mess and fires superfluous updateScrollingPanelList calls @@ -805,19 +724,6 @@ void LLAgentWearables::wearableUpdated(LLWearable *wearable, BOOL removed) checkWearableAgainstInventory(viewer_wearable); } - -} - - - -BOOL LLAgentWearables::itemUpdatePending(const LLUUID& item_id) const -{ - return mItemsAwaitingWearableUpdate.find(item_id) != mItemsAwaitingWearableUpdate.end(); -} - -U32 LLAgentWearables::itemUpdatePendingCount() const -{ - return mItemsAwaitingWearableUpdate.size(); } const LLUUID LLAgentWearables::getWearableItemID(LLWearableType::EType type, U32 index) const @@ -829,7 +735,7 @@ const LLUUID LLAgentWearables::getWearableItemID(LLWearableType::EType type, U32 return LLUUID(); } -// [RLVa:KB] - Checked: 2011-03-31 (RLVa-1.3.0f) | Added: RLVa-1.3.0f +// [RLVa:KB] - Checked: 2011-03-31 (RLVa-1.3.0) void LLAgentWearables::getWearableItemIDs(uuid_vec_t& idItems) const { for (wearableentry_map_t::const_iterator itWearableType = mWearableDatas.begin(); @@ -844,12 +750,14 @@ void LLAgentWearables::getWearableItemIDs(LLWearableType::EType eType, uuid_vec_ wearableentry_map_t::const_iterator itWearableType = mWearableDatas.find(eType); if (mWearableDatas.end() != itWearableType) { - for (wearableentry_vec_t::const_iterator itWearable = itWearableType->second.begin(), endWearable = itWearableType->second.end(); - itWearable != endWearable; ++itWearable) + for (wearableentry_vec_t::const_iterator itWearable = itWearableType->second.begin(); + itWearable != itWearableType->second.end(); ++itWearable) { - LLViewerWearable* wearable = dynamic_cast(*itWearable); - if(wearable) - idItems.push_back(wearable->getItemID()); + const LLViewerWearable* pWearable = dynamic_cast(*itWearable); + if (pWearable) + { + idItems.push_back(pWearable->getItemID()); + } } } } @@ -869,165 +777,12 @@ BOOL LLAgentWearables::isWearingItem(const LLUUID& item_id) const return getWearableFromItemID(item_id) != NULL; } -// MULTI-WEARABLE: DEPRECATED (see backwards compatibility) -// static -// ! BACKWARDS COMPATIBILITY ! When we stop supporting viewer1.23, we can assume -// that viewers have a Current Outfit Folder and won't need this message, and thus -// we can remove/ignore this whole function. EXCEPT gAgentWearables.notifyLoadingStarted -void LLAgentWearables::processAgentInitialWearablesUpdate(LLMessageSystem* mesgsys, void** user_data) -{ - // We should only receive this message a single time. Ignore subsequent AgentWearablesUpdates - // that may result from AgentWearablesRequest having been sent more than once. - if (mInitialWearablesUpdateReceived) - return; - - if (isAgentAvatarValid()) - { - //gAgentAvatarp->clearPhases(); // reset phase timers for outfit loading. - gAgentAvatarp->startPhase("process_initial_wearables_update"); - gAgentAvatarp->outputRezTiming("Received initial wearables update"); - } - - // notify subscribers that wearables started loading. See EXT-7777 - // *TODO: find more proper place to not be called from deprecated method. - // Seems such place is found: LLInitialWearablesFetch::processContents() - gAgentWearables.notifyLoadingStarted(); - - mInitialWearablesUpdateReceived = true; - - LLUUID agent_id; - gMessageSystem->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); - - if (isAgentAvatarValid() && (agent_id == gAgentAvatarp->getID())) - { - gMessageSystem->getU32Fast(_PREHASH_AgentData, _PREHASH_SerialNum, gAgentQueryManager.mUpdateSerialNum); - - const S32 NUM_BODY_PARTS = 4; - S32 num_wearables = gMessageSystem->getNumberOfBlocksFast(_PREHASH_WearableData); - if (num_wearables < NUM_BODY_PARTS) - { - // Transitional state. Avatars should always have at least their body parts (hair, eyes, shape and skin). - // The fact that they don't have any here (only a dummy is sent) implies that either: - // 1. This account existed before we had wearables - // 2. The database has gotten messed up - // 3. This is the account's first login (i.e. the wearables haven't been generated yet). - return; - } - - // Get the UUID of the current outfit folder (will be created if it doesn't exist) - const LLUUID current_outfit_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); - LLInitialWearablesFetch* outfit = new LLInitialWearablesFetch(current_outfit_id); - - //lldebugs << "processAgentInitialWearablesUpdate()" << llendl; - // Add wearables - // MULTI-WEARABLE: DEPRECATED: Message only supports one wearable per type, will be ignored in future. - gAgentWearables.mItemsAwaitingWearableUpdate.clear(); - for (S32 i=0; i < num_wearables; i++) - { - // Parse initial wearables data from message system - U8 type_u8 = 0; - gMessageSystem->getU8Fast(_PREHASH_WearableData, _PREHASH_WearableType, type_u8, i); - if (type_u8 >= LLWearableType::WT_COUNT) - { - continue; - } - LLWearableType::EType type = (LLWearableType::EType) type_u8; - - LLUUID item_id; - gMessageSystem->getUUIDFast(_PREHASH_WearableData, _PREHASH_ItemID, item_id, i ); - - LLUUID asset_id; - gMessageSystem->getUUIDFast(_PREHASH_WearableData, _PREHASH_AssetID, asset_id, i ); - if( asset_id.isNull() ) - { - LLViewerWearable::removeFromAvatar( type, FALSE ); - } - else - { - LLAssetType::EType asset_type = LLWearableType::getAssetType( type ); - if (asset_type == LLAssetType::AT_NONE) - { - continue; - } - - // MULTI-WEARABLE: DEPRECATED: this message only supports one wearable per type. Should be ignored in future versions - - // Store initial wearables data until we know whether we have the current outfit folder or need to use the data. - LLInitialWearablesFetch::InitialWearableData wearable_data(type, item_id, asset_id); - outfit->add(wearable_data); - } - - lldebugs << " " << LLWearableType::getTypeLabel(type) << llendl; - } - - // Get the complete information on the items in the inventory and set up an observer - // that will trigger when the complete information is fetched. - outfit->startFetch(); - if(outfit->isFinished()) - { - // everything is already here - call done. - outfit->done(); - } - else - { - // it's all on it's way - add an observer, and the inventory - // will call done for us when everything is here. - gInventory.addObserver(outfit); - } - - } -} - -// Normally, all wearables referred to "AgentWearablesUpdate" will correspond to actual assets in the -// database. If for some reason, we can't load one of those assets, we can try to reconstruct it so that -// the user isn't left without a shape, for example. (We can do that only after the inventory has loaded.) -void LLAgentWearables::recoverMissingWearable(const LLWearableType::EType type, U32 index) -{ - //llassert_always(index == 0); - // Try to recover by replacing missing wearable with a new one. - LLNotificationsUtil::add("ReplacedMissingWearable"); - lldebugs << "Wearable " << LLWearableType::getTypeLabel( type ) << " could not be downloaded. Replaced inventory item with default wearable." << llendl; - LLViewerWearable* new_wearable = LLWearableList::instance().createNewWearable(type, gAgentAvatarp); - - setWearable(type,index,new_wearable); - //new_wearable->writeToAvatar( TRUE ); - - // Add a new one in the lost and found folder. - // (We used to overwrite the "not found" one, but that could potentially - // destory content.) JC - const LLUUID lost_and_found_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); - LLPointer cb = - new addWearableToAgentInventoryCallback( - LLPointer(NULL), - type, - index, - new_wearable, - addWearableToAgentInventoryCallback::CALL_RECOVERDONE); - addWearableToAgentInventory( cb, new_wearable, lost_and_found_id, TRUE); -} - -void LLAgentWearables::recoverMissingWearableDone() -{ - // Have all the wearables that the avatar was wearing at log-in arrived or been fabricated? - updateWearablesLoaded(); - if (areWearablesLoaded()) - { - // Make sure that the server's idea of the avatar's wearables actually match the wearables. - gAgent.sendAgentSetAppearance(); - } - else - { - gInventory.addChangedMask( LLInventoryObserver::LABEL, LLUUID::null ); - gInventory.notifyObservers(); - } -} - void LLAgentWearables::addLocalTextureObject(const LLWearableType::EType wearable_type, const LLAvatarAppearanceDefines::ETextureIndex texture_type, U32 wearable_index) { LLViewerWearable* wearable = getViewerWearable((LLWearableType::EType)wearable_type, wearable_index); if (!wearable) { - llerrs << "Tried to add local texture object to invalid wearable with type " << wearable_type << " and index " << wearable_index << llendl; + LL_ERRS() << "Tried to add local texture object to invalid wearable with type " << wearable_type << " and index " << wearable_index << LL_ENDL; return; } LLLocalTextureObject lto; @@ -1040,28 +795,28 @@ class OnWearableItemCreatedCB: public LLInventoryCallback OnWearableItemCreatedCB(): mWearablesAwaitingItems(LLWearableType::WT_COUNT,NULL) { - llinfos << "created callback" << llendl; + LL_INFOS() << "created callback" << LL_ENDL; } /* virtual */ void fire(const LLUUID& inv_item) { - llinfos << "One item created " << inv_item.asString() << llendl; - LLViewerInventoryItem *item = gInventory.getItem(inv_item); - mItemsToLink.put(item); + LL_INFOS() << "One item created " << inv_item.asString() << LL_ENDL; + LLConstPointer item = gInventory.getItem(inv_item); + mItemsToLink.push_back(item); updatePendingWearable(inv_item); } ~OnWearableItemCreatedCB() { - llinfos << "All items created" << llendl; + LL_INFOS() << "All items created" << LL_ENDL; LLPointer link_waiter = new LLUpdateAppearanceOnDestroy; - LLAppearanceMgr::instance().linkAll(LLAppearanceMgr::instance().getCOF(), - mItemsToLink, - link_waiter); + link_inventory_array(LLAppearanceMgr::instance().getCOF(), + mItemsToLink, + link_waiter); } void addPendingWearable(LLViewerWearable *wearable) { if (!wearable) { - llwarns << "no wearable" << llendl; + LL_WARNS() << "no wearable" << LL_ENDL; return; } LLWearableType::EType type = wearable->getType(); @@ -1071,7 +826,7 @@ class OnWearableItemCreatedCB: public LLInventoryCallback } else { - llwarns << "invalid type " << type << llendl; + LL_WARNS() << "invalid type " << type << LL_ENDL; } } void updatePendingWearable(const LLUUID& inv_item) @@ -1079,12 +834,12 @@ class OnWearableItemCreatedCB: public LLInventoryCallback LLViewerInventoryItem *item = gInventory.getItem(inv_item); if (!item) { - llwarns << "no item found" << llendl; + LL_WARNS() << "no item found" << LL_ENDL; return; } if (!item->isWearableType()) { - llwarns << "non-wearable item found" << llendl; + LL_WARNS() << "non-wearable item found" << LL_ENDL; return; } if (item && item->isWearableType()) @@ -1098,19 +853,19 @@ class OnWearableItemCreatedCB: public LLInventoryCallback } else { - llwarns << "invalid wearable type " << type << llendl; + LL_WARNS() << "invalid wearable type " << type << LL_ENDL; } } } private: - LLInventoryModel::item_array_t mItemsToLink; + LLInventoryObject::const_object_list_t mItemsToLink; std::vector mWearablesAwaitingItems; }; void LLAgentWearables::createStandardWearables() { - llwarns << "Creating standard wearables" << llendl; + LL_WARNS() << "Creating standard wearables" << LL_ENDL; if (!isAgentAvatarValid()) return; @@ -1159,28 +914,38 @@ void LLAgentWearables::createStandardWearables() } } -void LLAgentWearables::createStandardWearablesDone(S32 type, U32 index) +// We no longer need this message in the current viewer, but send +// it for now to maintain compatibility with release viewers. Can +// remove this function once the SH-3455 changesets are universally deployed. +void LLAgentWearables::sendDummyAgentWearablesUpdate() { - llinfos << "type " << type << " index " << index << llendl; + LL_DEBUGS("Avatar") << "sendAgentWearablesUpdate()" << LL_ENDL; - if (!isAgentAvatarValid()) return; - gAgentAvatarp->updateVisualParams(); -} + // Send the AgentIsNowWearing + gMessageSystem->newMessageFast(_PREHASH_AgentIsNowWearing); + + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); -void LLAgentWearables::createStandardWearablesAllDone() -{ - // ... because sendAgentWearablesUpdate will notify inventory - // observers. - llinfos << "all done?" << llendl; + // Send 4 standardized nonsense item ids (same as returned by the modified sim, not that it especially matters). + gMessageSystem->nextBlockFast(_PREHASH_WearableData); + gMessageSystem->addU8Fast(_PREHASH_WearableType, U8(1)); + gMessageSystem->addUUIDFast(_PREHASH_ItemID, LLUUID("db5a4e5f-9da3-44c8-992d-1181c5795498")); - mWearablesLoaded = TRUE; - checkWearablesLoaded(); - notifyLoadingFinished(); - - updateServer(); + gMessageSystem->nextBlockFast(_PREHASH_WearableData); + gMessageSystem->addU8Fast(_PREHASH_WearableType, U8(2)); + gMessageSystem->addUUIDFast(_PREHASH_ItemID, LLUUID("6969c7cc-f72f-4a76-a19b-c293cce8ce4f")); + + gMessageSystem->nextBlockFast(_PREHASH_WearableData); + gMessageSystem->addU8Fast(_PREHASH_WearableType, U8(3)); + gMessageSystem->addUUIDFast(_PREHASH_ItemID, LLUUID("7999702b-b291-48f9-8903-c91dfb828408")); - // Treat this as the first texture entry message, if none received yet - gAgentAvatarp->onFirstTEMessageReceived(); + gMessageSystem->nextBlockFast(_PREHASH_WearableData); + gMessageSystem->addU8Fast(_PREHASH_WearableType, U8(4)); + gMessageSystem->addUUIDFast(_PREHASH_ItemID, LLUUID("566cb59e-ef60-41d7-bfa6-e0f293fbea40")); + + gAgent.sendReliableMessage(); } void LLAgentWearables::makeNewOutfitDone(S32 type, U32 index) @@ -1289,17 +1054,16 @@ bool LLAgentWearables::onRemoveWearableDialog(const LLSD& notification, const LL // Called by removeWearable() and onRemoveWearableDialog() to actually do the removal. void LLAgentWearables::removeWearableFinal( LLWearableType::EType type, bool do_remove_all, U32 index) { - //llassert_always(index == 0); + //LLAgentDumper dumper("removeWearable"); if (do_remove_all) { S32 max_entry = getWearableCount(type)-1; for (S32 i=max_entry; i>=0; i--) { LLViewerWearable* old_wearable = getViewerWearable(type,i); - //queryWearableCache(); // moved below if (old_wearable) { - popWearable(old_wearable); + eraseWearable(old_wearable); old_wearable->removeFromAvatar(TRUE); } } @@ -1312,48 +1076,105 @@ void LLAgentWearables::removeWearableFinal( LLWearableType::EType type, bool do_ else { LLViewerWearable* old_wearable = getViewerWearable(type, index); - //queryWearableCache(); // moved below if (old_wearable) { - popWearable(old_wearable); + eraseWearable(old_wearable); old_wearable->removeFromAvatar(TRUE); } } - queryWearableCache(); - - // Update the server - updateServer(); gInventory.notifyObservers(); } // Assumes existing wearables are not dirty. void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& items, - const LLDynamicArray< LLViewerWearable* >& wearables, - BOOL remove) + const std::vector< LLViewerWearable* >& wearables) { - llinfos << "setWearableOutfit() start" << llendl; + LL_INFOS() << "setWearableOutfit() start" << LL_ENDL; + + S32 count = wearables.size(); + llassert(items.size() == count); + + // Check for whether outfit already matches the one requested + S32 matched = 0, mismatched = 0; + const S32 arr_size = LLWearableType::WT_COUNT; + S32 type_counts[arr_size]; + BOOL update_inventory = FALSE; + std::fill(type_counts,type_counts+arr_size,0); + for (S32 i = 0; i < count; i++) + { + LLViewerWearable* new_wearable = wearables[i]; + LLPointer new_item = items[i]; + const LLWearableType::EType type = new_wearable->getType(); + if (type < 0 || type>=LLWearableType::WT_COUNT) + { + LL_WARNS() << "invalid type " << type << LL_ENDL; + mismatched++; + continue; + } + S32 index = type_counts[type]; + type_counts[type]++; + + LLViewerWearable *curr_wearable = dynamic_cast(getWearable(type,index)); + if (!new_wearable || !curr_wearable || + new_wearable->getAssetID() != curr_wearable->getAssetID()) + { + LL_DEBUGS("Avatar") << "mismatch, type " << type << " index " << index + << " names " << (curr_wearable ? curr_wearable->getName() : "NONE") << "," + << " names " << (new_wearable ? new_wearable->getName() : "NONE") << LL_ENDL; + mismatched++; + continue; + } + + // Update only inventory in this case - ordering of wearables with the same asset id has no effect. + // Updating wearables in this case causes the two-alphas error in MAINT-4158. + // We should actually disallow wearing two wearables with the same asset id. + if (curr_wearable->getName() != new_item->getName() || + curr_wearable->getItemID() != new_item->getUUID()) + { + LL_DEBUGS("Avatar") << "mismatch on name or inventory id, names " + << curr_wearable->getName() << " vs " << new_item->getName() + << " item ids " << curr_wearable->getItemID() << " vs " << new_item->getUUID() + << LL_ENDL; + update_inventory = TRUE; + continue; + } + // If we got here, everything matches. + matched++; + } + LL_DEBUGS("Avatar") << "matched " << matched << " mismatched " << mismatched << LL_ENDL; + for (S32 j=0; j new_item = items[i]; @@ -1362,20 +1183,27 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it if (new_wearable) { const LLWearableType::EType type = new_wearable->getType(); - + + LLUUID old_wearable_id = new_wearable->getItemID(); new_wearable->setName(new_item->getName()); - new_wearable->setDescription(new_item->getDescription()); new_wearable->setItemID(new_item->getUUID()); if (LLWearableType::getAssetType(type) == LLAssetType::AT_BODYPART) { // exactly one wearable per body part setWearable(type,0,new_wearable); + if (old_wearable_id.notNull()) + { + // we changed id before setting wearable, update old item manually + // to complete the swap. + gInventory.addChangedMask(LLInventoryObserver::LABEL, old_wearable_id); + } } else { pushWearable(type,new_wearable); } + const BOOL removed = FALSE; wearableUpdated(new_wearable, removed); } @@ -1383,10 +1211,18 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it gInventory.notifyObservers(); + if (mismatched == 0) + { + LL_DEBUGS("Avatar") << "inventory updated, wearable assets not changed, bailing out" << LL_ENDL; + notifyLoadingFinished(); + return; + } + + // updating agent avatar + if (isAgentAvatarValid()) { gAgentAvatarp->setCompositeUpdatesEnabled(TRUE); - gAgentAvatarp->updateVisualParams(); // If we have not yet declouded, we may want to use // baked texture UUIDs sent from the first objectUpdate message @@ -1401,8 +1237,8 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it // Start rendering & update the server mWearablesLoaded = TRUE; - checkWearablesLoaded(); -// [SL:KB] - Patch: Appearance-InitialWearablesLoadedCallback | Checked: 2010-09-22 (Catznip-3.0.0a) | Modified: Catznip-2.2.0a + +// [SL:KB] - Patch: Appearance-InitialWearablesLoadedCallback | Checked: 2010-09-22 (Catznip-2.2) if (!mInitialWearablesLoaded) { mInitialWearablesLoaded = true; @@ -1410,212 +1246,133 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it } // [/SL:KB] notifyLoadingFinished(); - queryWearableCache(); - updateServer(); + + // Copy wearable params to avatar. + gAgentAvatarp->writeWearablesToAvatar(); + + // Then update the avatar based on the copied params. + gAgentAvatarp->updateVisualParams(); gAgentAvatarp->dumpAvatarTEs("setWearableOutfit"); - lldebugs << "setWearableOutfit() end" << llendl; + LL_DEBUGS("Avatar") << "setWearableOutfit() end" << LL_ENDL; } // User has picked "wear on avatar" from a menu. -/*void LLAgentWearables::setWearableItem(LLInventoryItem* new_item, LLViewerWearable* new_wearable, bool do_append) -{ - //LLAgentDumper dumper("setWearableItem"); - if (isWearingItem(new_item->getUUID())) - { - llwarns << "wearable " << new_item->getUUID() << " is already worn" << llendl; - return; - } - - const LLWearableType::EType type = new_wearable->getType(); - -// [RLVa:KB] - Checked: 2010-03-19 (RLVa-1.2.0a) | Modified: RLVa-1.2.0g - // TODO-RLVa: [RLVa-1.2.1] This looks like dead code in SL-2.0.2 so we can't really check to see if it works :| - if (rlv_handler_t::isEnabled()) - { - ERlvWearMask eWear = gRlvWearableLocks.canWear(type); - if ( (RLV_WEAR_LOCKED == eWear) || ((!do_append) && (!(eWear & RLV_WEAR_REPLACE))) ) - return; - } -// [/RLVa:KB] - - if (!do_append) - { - // Remove old wearable, if any - // MULTI_WEARABLE: hardwired to 0 - LLViewerWearable* old_wearable = getViewerWearable(type,0); - if( old_wearable ) - { - const LLUUID& old_item_id = old_wearable->getItemID(); - if( (old_wearable->getAssetID() == new_wearable->getAssetID()) && - (old_item_id == new_item->getUUID()) ) - { - lldebugs << "No change to wearable asset and item: " << LLWearableType::getTypeName( type ) << llendl; - return; - } - - if( old_wearable->isDirty() ) - { - // Bring up modal dialog: Save changes? Yes, No, Cancel - LLSD payload; - payload["item_id"] = new_item->getUUID(); - LLNotificationsUtil::add( "WearableSave", LLSD(), payload, boost::bind(onSetWearableDialog, _1, _2, new_wearable)); - return; - } - } - } - - setWearableFinal(new_item, new_wearable, do_append); -}*/ +//void LLAgentWearables::setWearableItem(LLInventoryItem* new_item, LLViewerWearable* new_wearable, bool do_append) +//{ +// //LLAgentDumper dumper("setWearableItem"); +// if (isWearingItem(new_item->getUUID())) +// { +// LL_WARNS() << "wearable " << new_item->getUUID() << " is already worn" << LL_ENDL; +// return; +// } +// +// const LLWearableType::EType type = new_wearable->getType(); +// +// if (!do_append) +// { +// // Remove old wearable, if any +// // MULTI_WEARABLE: hardwired to 0 +// LLViewerWearable* old_wearable = getViewerWearable(type,0); +// if (old_wearable) +// { +// const LLUUID& old_item_id = old_wearable->getItemID(); +// if ((old_wearable->getAssetID() == new_wearable->getAssetID()) && +// (old_item_id == new_item->getUUID())) +// { +// LL_DEBUGS() << "No change to wearable asset and item: " << LLWearableType::getTypeName(type) << LL_ENDL; +// return; +// } +// +// if (old_wearable->isDirty()) +// { +// // Bring up modal dialog: Save changes? Yes, No, Cancel +// LLSD payload; +// payload["item_id"] = new_item->getUUID(); +// LLNotificationsUtil::add("WearableSave", LLSD(), payload, boost::bind(onSetWearableDialog, _1, _2, new_wearable)); +// return; +// } +// } +// } +// +// setWearableFinal(new_item, new_wearable, do_append); +//} // static -bool LLAgentWearables::onSetWearableDialog(const LLSD& notification, const LLSD& response, LLViewerWearable* wearable) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - LLInventoryItem* new_item = gInventory.getItem( notification["payload"]["item_id"].asUUID()); - U32 index = gAgentWearables.getWearableIndex(wearable); - if( !new_item ) - { - delete wearable; - return false; - } - - switch( option ) - { - case 0: // "Save" - gAgentWearables.saveWearable(wearable->getType(),index); - gAgentWearables.setWearableFinal( new_item, wearable ); - break; - - case 1: // "Don't Save" - gAgentWearables.setWearableFinal( new_item, wearable ); - break; - - case 2: // "Cancel" - break; - - default: - llassert(0); - break; - } - - delete wearable; - return false; -} +//bool LLAgentWearables::onSetWearableDialog(const LLSD& notification, const LLSD& response, LLViewerWearable* wearable) +//{ +// S32 option = LLNotificationsUtil::getSelectedOption(notification, response); +// LLInventoryItem* new_item = gInventory.getItem(notification["payload"]["item_id"].asUUID()); +// U32 index; +// if (!gAgentWearables.getWearableIndex(wearable,index)) +// { +// LL_WARNS() << "Wearable not found" << LL_ENDL; +// delete wearable; +// return false; +// } +// switch(option) +// { +// case 0: // "Save" +// gAgentWearables.saveWearable(wearable->getType(),index); +// gAgentWearables.setWearableFinal(new_item, wearable); +// break; +// +// case 1: // "Don't Save" +// gAgentWearables.setWearableFinal(new_item, wearable); +// break; +// +// case 2: // "Cancel" +// break; +// +// default: +// llassert(0); +// break; +// } +// +// delete wearable; +// return false; +//} // Called from setWearableItem() and onSetWearableDialog() to actually set the wearable. // MULTI_WEARABLE: unify code after null objects are gone. -void LLAgentWearables::setWearableFinal(LLInventoryItem* new_item, LLViewerWearable* new_wearable, bool do_append) -{ - const LLWearableType::EType type = new_wearable->getType(); - - if (do_append && getWearableItemID(type,0).notNull()) - { - new_wearable->setItemID(new_item->getUUID()); - /*mWearableDatas[type].push_back(new_wearable); - llinfos << "Added additional wearable for type " << type - << " size is now " << mWearableDatas[type].size() << llendl; - checkWearableAgainstInventory(new_wearable);*/ - pushWearable(type,new_wearable); //To call LLAgentWearables::wearableUpdated - } - else - { - // Replace the old wearable with a new one. - llassert(new_item->getAssetUUID() == new_wearable->getAssetID()); - - LLViewerWearable *old_wearable = getViewerWearable(type,0); - LLUUID old_item_id; - if (old_wearable) - { - old_item_id = old_wearable->getItemID(); - } - new_wearable->setItemID(new_item->getUUID()); - setWearable(type,0,new_wearable); - - if (old_item_id.notNull()) - { - gInventory.addChangedMask(LLInventoryObserver::LABEL, old_item_id); - gInventory.notifyObservers(); - } - llinfos << "Replaced current element 0 for type " << type - << " size is now " << getWearableCount(type) << llendl; - } - - //llinfos << "LLVOAvatar::setWearableItem()" << llendl; - queryWearableCache(); - //new_wearable->writeToAvatar(TRUE); - - updateServer(); -} - -void LLAgentWearables::queryWearableCache() -{ - if (!areWearablesLoaded() || (gAgent.getRegion() && gAgent.getRegion()->getCentralBakeVersion())) - { - return; - } - - // Look up affected baked textures. - // If they exist: - // disallow updates for affected layersets (until dataserver responds with cache request.) - // If cache miss, turn updates back on and invalidate composite. - // If cache hit, modify baked texture entries. - // - // Cache requests contain list of hashes for each baked texture entry. - // Response is list of valid baked texture assets. (same message) - - gMessageSystem->newMessageFast(_PREHASH_AgentCachedTexture); - gMessageSystem->nextBlockFast(_PREHASH_AgentData); - gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - gMessageSystem->addS32Fast(_PREHASH_SerialNum, gAgentQueryManager.mWearablesCacheQueryID); - - S32 num_queries = 0; - for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++ ) - { - LLUUID hash_id = computeBakedTextureHash((EBakedTextureIndex) baked_index); - if (hash_id.notNull()) - { - num_queries++; - // *NOTE: make sure at least one request gets packed - - ETextureIndex te_index = LLAvatarAppearanceDictionary::bakedToLocalTextureIndex((EBakedTextureIndex)baked_index); - - //llinfos << "Requesting texture for hash " << hash << " in baked texture slot " << baked_index << llendl; - gMessageSystem->nextBlockFast(_PREHASH_WearableData); - gMessageSystem->addUUIDFast(_PREHASH_ID, hash_id); - gMessageSystem->addU8Fast(_PREHASH_TextureIndex, (U8)te_index); - } - - gAgentQueryManager.mActiveCacheQueries[ baked_index ] = gAgentQueryManager.mWearablesCacheQueryID; - } - //VWR-22113: gAgent.getRegion() can return null if invalid, seen here on logout - if(gAgent.getRegion()) - { - if (isAgentAvatarValid()) - { - selfStartPhase("fetch_texture_cache_entries"); - gAgentAvatarp->outputRezTiming("Fetching textures from cache"); - } - - LL_INFOS("Avatar") << gAgentAvatarp->avString() << "Requesting texture cache entry for " << num_queries << " baked textures" << LL_ENDL; - gMessageSystem->sendReliable(gAgent.getRegion()->getHost()); - gAgentQueryManager.mNumPendingQueries++; - gAgentQueryManager.mWearablesCacheQueryID++; - } -} - -// virtual -void LLAgentWearables::invalidateBakedTextureHash(LLMD5& hash) const -{ - // Add some garbage into the hash so that it becomes invalid. - if (isAgentAvatarValid()) - { - hash.update((const unsigned char*)gAgentAvatarp->getID().mData, UUID_BYTES); - } -} +//void LLAgentWearables::setWearableFinal(LLInventoryItem* new_item, LLViewerWearable* new_wearable, bool do_append) +//{ +// const LLWearableType::EType type = new_wearable->getType(); +// +// if (do_append && getWearableItemID(type,0).notNull()) +// { +// new_wearable->setItemID(new_item->getUUID()); +// const bool trigger_updated = false; +// pushWearable(type, new_wearable, trigger_updated); +// LL_INFOS() << "Added additional wearable for type " << type +// << " size is now " << getWearableCount(type) << LL_ENDL; +// checkWearableAgainstInventory(new_wearable); +// } +// else +// { +// // Replace the old wearable with a new one. +// llassert(new_item->getAssetUUID() == new_wearable->getAssetID()); +// +// LLViewerWearable *old_wearable = getViewerWearable(type,0); +// LLUUID old_item_id; +// if (old_wearable) +// { +// old_item_id = old_wearable->getItemID(); +// } +// new_wearable->setItemID(new_item->getUUID()); +// setWearable(type,0,new_wearable); +// +// if (old_item_id.notNull()) +// { +// gInventory.addChangedMask(LLInventoryObserver::LABEL, old_item_id); +// gInventory.notifyObservers(); +// } +// LL_INFOS() << "Replaced current element 0 for type " << type +// << " size is now " << getWearableCount(type) << LL_ENDL; +// } +//} // User has picked "remove from avatar" from a menu. // static @@ -1638,12 +1395,12 @@ void LLAgentWearables::invalidateBakedTextureHash(LLMD5& hash) const // } //} -// Combines userRemoveAllAttachments() and userAttachMultipleAttachments() logic to -// get attachments into desired state with minimal number of adds/removes. -//void LLAgentWearables::userUpdateAttachments(LLInventoryModel::item_array_t& obj_item_array) -// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2010-09-22 (Catznip-2.2) -void LLAgentWearables::userUpdateAttachments(LLInventoryModel::item_array_t& obj_item_array, bool attach_only) -// [/SL:KB] +// Given a desired set of attachments, find what objects need to be +// removed, and what additional inventory items need to be added. +void LLAgentWearables::findAttachmentsAddRemoveInfo(LLInventoryModel::item_array_t& obj_item_array, + llvo_vec_t& objects_to_remove, + llvo_vec_t& objects_to_retain, + LLInventoryModel::item_array_t& items_to_add) { // Possible cases: // already wearing but not in request set -> take off. @@ -1652,13 +1409,15 @@ void LLAgentWearables::userUpdateAttachments(LLInventoryModel::item_array_t& obj if (!isAgentAvatarValid()) return; - std::set requested_item_ids; - std::set current_item_ids; - for (S32 i=0; igetLinkedUUID()); - + uuid_set_t requested_item_ids; + uuid_set_t current_item_ids; + for (U32 i=0; igetLinkedUUID(); + //LL_INFOS() << "Requested attachment id " << requested_id << LL_ENDL; + requested_item_ids.insert(requested_id); + } // Build up list of objects to be removed and items currently attached. - llvo_vec_t objects_to_remove; for (LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin(); iter != gAgentAvatarp->mAttachmentPoints.end();) { @@ -1672,22 +1431,33 @@ void LLAgentWearables::userUpdateAttachments(LLInventoryModel::item_array_t& obj if (objectp) { LLUUID object_item_id = objectp->getAttachmentItemID(); + + bool remove_attachment = true; if (requested_item_ids.find(object_item_id) != requested_item_ids.end()) - { - // Object currently worn, was requested. + { // Object currently worn, was requested to keep it // Flag as currently worn so we won't have to add it again. - current_item_ids.insert(object_item_id); + remove_attachment = false; } - else + else if (objectp->isTempAttachment()) + { // Check if we should keep this temp attachment + remove_attachment = LLAppearanceMgr::instance().shouldRemoveTempAttachment(objectp->getID()); + } + + if (remove_attachment) { - // object currently worn, not requested. + // LL_INFOS() << "found object to remove, id " << objectp->getID() << ", item " << objectp->getAttachmentItemID() << LL_ENDL; objects_to_remove.push_back(objectp); } + else + { + // LL_INFOS() << "found object to keep, id " << objectp->getID() << ", item " << objectp->getAttachmentItemID() << LL_ENDL; + current_item_ids.insert(object_item_id); + objects_to_retain.push_back(objectp); + } } } } - LLInventoryModel::item_array_t items_to_add; for (LLInventoryModel::item_array_t::iterator it = obj_item_array.begin(); it != obj_item_array.end(); ++it) @@ -1705,19 +1475,7 @@ void LLAgentWearables::userUpdateAttachments(LLInventoryModel::item_array_t& obj } // S32 remove_count = objects_to_remove.size(); // S32 add_count = items_to_add.size(); - // llinfos << "remove " << remove_count << " add " << add_count << llendl; - - // Remove everything in objects_to_remove -// userRemoveMultipleAttachments(objects_to_remove); -// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2010-09-22 (Catznip-2.2) - if (!attach_only) - { - userRemoveMultipleAttachments(objects_to_remove); - } -// [/SL:KB] - - // Add everything in items_to_add - userAttachMultipleAttachments(items_to_add); + // LL_INFOS() << "remove " << remove_count << " add " << add_count << LL_ENDL; } void LLAgentWearables::userRemoveMultipleAttachments(llvo_vec_t& objects_to_remove) @@ -1737,7 +1495,7 @@ void LLAgentWearables::userRemoveMultipleAttachments(llvo_vec_t& objects_to_remo itObj = objects_to_remove.erase(itObj); // Fall-back code: re-add the attachment if it got removed from COF somehow (compensates for possible bugs elsewhere) - bool fInCOF = LLAppearanceMgr::isLinkInCOF(pAttachObj->getAttachmentItemID()); + bool fInCOF = LLAppearanceMgr::instance().isLinkedInCOF(pAttachObj->getAttachmentItemID()); RLV_ASSERT(fInCOF); if (!fInCOF) { @@ -1755,6 +1513,7 @@ void LLAgentWearables::userRemoveMultipleAttachments(llvo_vec_t& objects_to_remo if (objects_to_remove.empty()) return; + LL_DEBUGS("Avatar") << "ATT [ObjectDetach] removing " << objects_to_remove.size() << " objects" << LL_ENDL; gMessageSystem->newMessage("ObjectDetach"); gMessageSystem->nextBlockFast(_PREHASH_AgentData); gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); @@ -1765,104 +1524,39 @@ void LLAgentWearables::userRemoveMultipleAttachments(llvo_vec_t& objects_to_remo ++it) { LLViewerObject *objectp = *it; + //gAgentAvatarp->resetJointPositionsOnDetach(objectp); gMessageSystem->nextBlockFast(_PREHASH_ObjectData); gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, objectp->getLocalID()); + const LLUUID& item_id = objectp->getAttachmentItemID(); + LLViewerInventoryItem *item = gInventory.getItem(item_id); + LL_DEBUGS("Avatar") << "ATT removing object, item is " << (item ? item->getName() : "UNKNOWN") << " " << item_id << LL_ENDL; + LLAttachmentsMgr::instance().onDetachRequested(item_id); } gMessageSystem->sendReliable(gAgent.getRegionHost()); } void LLAgentWearables::userAttachMultipleAttachments(LLInventoryModel::item_array_t& obj_item_array) { -// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1) - static bool sInitialAttachmentsRequested = false; - - // RELEASE-RLVa: [SL-3.4] Check our callers and verify that erasing elements from the passed vector won't break random things - if ( (rlv_handler_t::isEnabled()) && (sInitialAttachmentsRequested) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) ) - { - // Fall-back code: everything should really already have been pruned before we get this far - for (S32 idxItem = obj_item_array.count() - 1; idxItem >= 0; idxItem--) - { - const LLInventoryItem* pItem = obj_item_array.get(idxItem).get(); - if (!gRlvAttachmentLocks.canAttach(pItem)) - { - obj_item_array.remove(idxItem); - RLV_ASSERT(false); - } - } - } -// [/RLVa:KB] - // Build a compound message to send all the objects that need to be rezzed. - S32 obj_count = obj_item_array.count(); - - // Limit number of packets to send - const S32 MAX_PACKETS_TO_SEND = 10; - const S32 OBJECTS_PER_PACKET = 4; - const S32 MAX_OBJECTS_TO_SEND = MAX_PACKETS_TO_SEND * OBJECTS_PER_PACKET; - if( obj_count > MAX_OBJECTS_TO_SEND ) + S32 obj_count = obj_item_array.size(); + if (obj_count > 0) { - obj_count = MAX_OBJECTS_TO_SEND; + LL_DEBUGS("Avatar") << "ATT attaching multiple, total obj_count " << obj_count << LL_ENDL; } - - // Create an id to keep the parts of the compound message together - LLUUID compound_msg_id; - compound_msg_id.generate(); - LLMessageSystem* msg = gMessageSystem; - for(S32 i = 0; i < obj_count; ++i) - { - if( 0 == (i % OBJECTS_PER_PACKET) ) - { - // Start a new message chunk - msg->newMessageFast(_PREHASH_RezMultipleAttachmentsFromInv); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_HeaderData); - msg->addUUIDFast(_PREHASH_CompoundMsgID, compound_msg_id ); - msg->addU8Fast(_PREHASH_TotalObjects, obj_count ); - msg->addBOOLFast(_PREHASH_FirstDetachAll, false ); - } + for(LLInventoryModel::item_array_t::const_iterator it = obj_item_array.begin(); + it != obj_item_array.end(); + ++it) + { + const LLInventoryItem* item = *it; + LLAttachmentsMgr::instance().addAttachmentRequest(item->getLinkedUUID(), 0, TRUE); + } - const LLInventoryItem* item = obj_item_array.get(i).get(); - bool replace = !gHippoGridManager->getConnectedGrid()->supportsInvLinks(); - msg->nextBlockFast(_PREHASH_ObjectData ); - msg->addUUIDFast(_PREHASH_ItemID, item->getLinkedUUID()); - msg->addUUIDFast(_PREHASH_OwnerID, item->getPermissions().getOwner()); - msg->addU8Fast(_PREHASH_AttachmentPt, replace? 0 : ATTACHMENT_ADD); // Wear at the previous or default attachment point -// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1b) | Added: RLVa-1.3.1b - if ( (rlv_handler_t::isEnabled()) && (sInitialAttachmentsRequested) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) ) - { - RlvAttachmentLockWatchdog::instance().onWearAttachment(item, RLV_WEAR_ADD); - } -// [/RLVa:KB] - pack_permissions_slam(msg, item->getFlags(), item->getPermissions()); - msg->addStringFast(_PREHASH_Name, item->getName()); - msg->addStringFast(_PREHASH_Description, item->getDescription()); - - if( (i+1 == obj_count) || ((OBJECTS_PER_PACKET-1) == (i % OBJECTS_PER_PACKET)) ) - { - // End of message chunk - msg->sendReliable( gAgent.getRegion()->getHost() ); - } - } - -// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1b) | Added: RLVa-1.3.1b - sInitialAttachmentsRequested = true; +// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1) + mInitialAttachmentsRequested = true; // [/RLVa:KB] } -void LLAgentWearables::checkWearablesLoaded() const -{ -#ifdef SHOW_ASSERT - U32 item_pend_count = itemUpdatePendingCount(); - if (mWearablesLoaded) - { - llassert(item_pend_count==0); - } -#endif -} - // Returns false if the given wearable is already topmost/bottommost // (depending on closer_to_body parameter). bool LLAgentWearables::canMoveWearable(const LLUUID& item_id, bool closer_to_body) const @@ -1879,20 +1573,9 @@ bool LLAgentWearables::canMoveWearable(const LLUUID& item_id, bool closer_to_bod BOOL LLAgentWearables::areWearablesLoaded() const { - checkWearablesLoaded(); return mWearablesLoaded; } -// MULTI-WEARABLE: DEPRECATED: item pending count relies on old messages that don't support multi-wearables. do not trust to be accurate -void LLAgentWearables::updateWearablesLoaded() -{ - mWearablesLoaded = (itemUpdatePendingCount()==0); - if (mWearablesLoaded) - { - notifyLoadingFinished(); - } -} - bool LLAgentWearables::canWearableBeRemoved(const LLViewerWearable* wearable) const { if (!wearable) return false; @@ -1902,7 +1585,7 @@ bool LLAgentWearables::canWearableBeRemoved(const LLViewerWearable* wearable) co return !(((type == LLWearableType::WT_SHAPE) || (type == LLWearableType::WT_SKIN) || (type == LLWearableType::WT_HAIR) || (type == LLWearableType::WT_EYES)) && (getWearableCount(type) <= 1) ); } -void LLAgentWearables::animateAllWearableParams(F32 delta, BOOL upload_bake) +void LLAgentWearables::animateAllWearableParams(F32 delta, bool upload_bake) { for( S32 type = 0; type < LLWearableType::WT_COUNT; ++type ) { @@ -1973,10 +1656,25 @@ void LLAgentWearables::createWearable(LLWearableType::EType type, bool wear, con { if (type == LLWearableType::WT_INVALID || type == LLWearableType::WT_NONE) return; + if (type == LLWearableType::WT_UNIVERSAL && !gAgent.getRegion()->bakesOnMeshEnabled()) + { + LL_WARNS("Inventory") << "Can't create WT_UNIVERSAL type " << LL_ENDL; + return; + } + LLViewerWearable* wearable = LLWearableList::instance().createNewWearable(type, gAgentAvatarp); LLAssetType::EType asset_type = wearable->getAssetType(); LLInventoryType::EType inv_type = LLInventoryType::IT_WEARABLE; - LLPointer cb = wear ? new LLBoostFuncInventoryCallback(wear_and_edit_cb) : NULL; + LLPointer cb; + if(wear) + { + cb = new LLBoostFuncInventoryCallback(wear_and_edit_cb); + } + else + { + cb = new LLBoostFuncInventoryCallback(wear_cb); + } + LLUUID folder_id; if (parent_id.notNull()) @@ -1989,10 +1687,15 @@ void LLAgentWearables::createWearable(LLWearableType::EType type, bool wear, con folder_id = gInventory.findCategoryUUIDForType(folder_type); } - create_inventory_item(gAgent.getID(), gAgent.getSessionID(), - folder_id, wearable->getTransactionID(), wearable->getName(), - wearable->getDescription(), asset_type, inv_type, wearable->getType(), - wearable->getPermissions().getMaskNextOwner(), + create_inventory_item(gAgent.getID(), + gAgent.getSessionID(), + folder_id, + wearable->getTransactionID(), + wearable->getName(), + wearable->getDescription(), + asset_type, inv_type, + wearable->getType(), + LLFloaterPerms::getNextOwnerPerms("Wearables"), cb); } @@ -2002,20 +1705,20 @@ void LLAgentWearables::editWearable(const LLUUID& item_id) LLViewerInventoryItem* item = gInventory.getLinkedItem(item_id); if (!item) { - llwarns << "Failed to get linked item" << llendl; + LL_WARNS() << "Failed to get linked item" << LL_ENDL; return; } LLViewerWearable* wearable = gAgentWearables.getWearableFromItemID(item_id); if (!wearable) { - llwarns << "Cannot get wearable" << llendl; + LL_WARNS() << "Cannot get wearable" << LL_ENDL; return; } if (!gAgentWearables.isWearableModifiable(item->getUUID())) { - llwarns << "Cannot modify wearable" << llendl; + LL_WARNS() << "Cannot modify wearable" << LL_ENDL; return; } @@ -2042,30 +1745,6 @@ void LLAgentWearables::editWearableIfRequested(const LLUUID& item_id) } } -void LLAgentWearables::updateServer() -{ - sendAgentWearablesUpdate(); - gAgent.sendAgentSetAppearance(); -} - -void LLAgentWearables::populateMyOutfitsFolder(void) -{ - llinfos << "starting outfit population" << llendl; - - const LLUUID& my_outfits_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); - LLLibraryOutfitsFetch* outfits = new LLLibraryOutfitsFetch(my_outfits_id); - outfits->mMyOutfitsID = my_outfits_id; - - // Get the complete information on the items in the inventory and - // setup an observer that will wait for that to happen. - gInventory.addObserver(outfits); - outfits->startFetch(); - if (outfits->isFinished()) - { - outfits->done(); - } -} - boost::signals2::connection LLAgentWearables::addLoadingStartedCallback(loading_started_callback_t cb) { return mLoadingStartedSignal.connect(cb); @@ -2076,21 +1755,22 @@ boost::signals2::connection LLAgentWearables::addLoadedCallback(loaded_callback_ return mLoadedSignal.connect(cb); } -// [SL:KB] - Patch: Appearance-InitialWearablesLoadedCallback | Checked: 2010-08-14 (Catznip-3.0.0a) | Added: Catznip-2.1.1d -boost::signals2::connection LLAgentWearables::addInitialWearablesLoadedCallback(loaded_callback_t cb) +bool LLAgentWearables::changeInProgress() const { - return mInitialWearablesLoadedSignal.connect(cb); + return mCOFChangeInProgress; } -// [/SL:KB] -bool LLAgentWearables::changeInProgress() const +// [SL:KB] - Patch: Appearance-InitialWearablesLoadedCallback | Checked: 2010-08-14 (Catznip-2.1) +boost::signals2::connection LLAgentWearables::addInitialWearablesLoadedCallback(const loaded_callback_t& cb) { - return mCOFChangeInProgress; + return mInitialWearablesLoadedSignal.connect(cb); } +// [/SL:KB] void LLAgentWearables::notifyLoadingStarted() { mCOFChangeInProgress = true; + mCOFChangeTimer.reset(); mLoadingStartedSignal(); } diff --git a/indra/newview/llagentwearables.h b/indra/newview/llagentwearables.h index 5f8ece16eb..51825b9a29 100644 --- a/indra/newview/llagentwearables.h +++ b/indra/newview/llagentwearables.h @@ -42,7 +42,6 @@ class LLInventoryItem; class LLVOAvatarSelf; class LLViewerWearable; -class LLInitialWearablesFetch; class LLViewerObject; class LLAgentWearables : public LLInitClass, public LLWearableData @@ -62,9 +61,6 @@ class LLAgentWearables : public LLInitClass, public LLWearable // LLInitClass interface static void initClass(); -protected: - void createStandardWearablesDone(S32 type, U32 index/* = 0*/); - void createStandardWearablesAllDone(); //-------------------------------------------------------------------- // Queries @@ -76,10 +72,14 @@ class LLAgentWearables : public LLInitClass, public LLWearable BOOL isWearableCopyable(LLWearableType::EType type, U32 index /*= 0*/) const; BOOL areWearablesLoaded() const; -// [SL:KB] - Patch: Appearance-InitialWearablesLoadedCallback | Checked: 2010-08-14 (Catznip-3.0.0a) | Added: Catznip-2.1.1d +// [SL:KB] - Patch: Appearance-InitialWearablesLoadedCallback | Checked: 2010-08-14 (Catznip-2.1) bool areInitalWearablesLoaded() const { return mInitialWearablesLoaded; } // [/SL:KB] +// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1) + bool areInitialAttachmentsRequested() const { return mInitialAttachmentsRequested; } +// [/RLVa:KB] bool isCOFChangeInProgress() const { return mCOFChangeInProgress; } + F32 getCOFChangeTime() const { return mCOFChangeTimer.getElapsedTimeF32(); } void updateWearablesLoaded(); void checkWearablesLoaded() const; bool canMoveWearable(const LLUUID& item_id, bool closer_to_body) const; @@ -87,13 +87,13 @@ class LLAgentWearables : public LLInitClass, public LLWearable // Note: False for shape, skin, eyes, and hair, unless you have MORE than 1. bool canWearableBeRemoved(const LLViewerWearable* wearable) const; - void animateAllWearableParams(F32 delta, BOOL upload_bake); + void animateAllWearableParams(F32 delta, bool upload_bake = false); //-------------------------------------------------------------------- // Accessors //-------------------------------------------------------------------- public: -// [RLVa:KB] - Checked: 2011-03-31 (RLVa-1.3.0f) | Added: RLVa-1.3.0f +// [RLVa:KB] - Checked: 2011-03-31 (RLVa-1.3.0) void getWearableItemIDs(uuid_vec_t& idItems) const; void getWearableItemIDs(LLWearableType::EType eType, uuid_vec_t& idItems) const; // [/RLVa:KB] @@ -114,15 +114,15 @@ class LLAgentWearables : public LLInitClass, public LLWearable /*virtual*/void wearableUpdated(LLWearable *wearable, BOOL removed); public: // void setWearableItem(LLInventoryItem* new_item, LLViewerWearable* wearable, bool do_append = false); - void setWearableOutfit(const LLInventoryItem::item_array_t& items, const LLDynamicArray< LLViewerWearable* >& wearables, BOOL remove); + void setWearableOutfit(const LLInventoryItem::item_array_t& items, const std::vector< LLViewerWearable* >& wearables); void setWearableName(const LLUUID& item_id, const std::string& new_name); void nameOrDescriptionChanged(LLUUID const& item_id); // *TODO: Move this into llappearance/LLWearableData ? void addLocalTextureObject(const LLWearableType::EType wearable_type, const LLAvatarAppearanceDefines::ETextureIndex texture_type, U32 wearable_index); protected: - void setWearableFinal(LLInventoryItem* new_item, LLViewerWearable* new_wearable, bool do_append = false); - static bool onSetWearableDialog(const LLSD& notification, const LLSD& response, LLViewerWearable* wearable); +// void setWearableFinal(LLInventoryItem* new_item, LLViewerWearable* new_wearable, bool do_append = false); +// static bool onSetWearableDialog(const LLSD& notification, const LLSD& response, LLViewerWearable* wearable); void addWearableToAgentInventory(LLPointer cb, LLViewerWearable* wearable, @@ -154,37 +154,18 @@ class LLAgentWearables : public LLInitClass, public LLWearable // Removing wearables //-------------------------------------------------------------------- public: - void removeWearable(const LLWearableType::EType type, bool do_remove_all /*= false*/, U32 index /*= 0*/); +// void removeWearable(const LLWearableType::EType type, bool do_remove_all /*= false*/, U32 index /*= 0*/); private: +// [RLVa:KB] - Checked: 2010-05-11 (RLVa-1.2.0) + void removeWearable(const LLWearableType::EType type, bool do_remove_all /*= false*/, U32 index /*= 0*/); +// [/RLVa:KB] void removeWearableFinal(const LLWearableType::EType type, bool do_remove_all /*= false*/, U32 index /*= 0*/); protected: static bool onRemoveWearableDialog(const LLSD& notification, const LLSD& response); - //-------------------------------------------------------------------- - // Server Communication - //-------------------------------------------------------------------- -public: - // Processes the initial wearables update message (if necessary, since the outfit folder makes it redundant) - static void processAgentInitialWearablesUpdate(LLMessageSystem* mesgsys, void** user_data); - -protected: - - /*virtual*/ void invalidateBakedTextureHash(LLMD5& hash) const; - void sendAgentWearablesUpdate(); - void sendAgentWearablesRequest(); - void queryWearableCache(); - void updateServer(); - static void onInitialWearableAssetArrived(LLViewerWearable* wearable, void* userdata); - //-------------------------------------------------------------------- // Outfits //-------------------------------------------------------------------- -public: - - // Should only be called if we *know* we've never done so before, since users may - // not want the Library outfits to stay in their quick outfit selector and can delete them. - void populateMyOutfitsFolder(); - private: void makeNewOutfitDone(S32 type, U32 index); @@ -193,11 +174,16 @@ class LLAgentWearables : public LLInitClass, public LLWearable //-------------------------------------------------------------------- public: LLViewerWearable* saveWearableAs(const LLWearableType::EType type, const U32 index, const std::string& new_name, const std::string& description, BOOL save_in_lost_and_found); - void saveWearable(const LLWearableType::EType type, const U32 index, BOOL send_update = TRUE, + void saveWearable(const LLWearableType::EType type, const U32 index, const std::string new_name = ""); void saveAllWearables(); void revertWearable(const LLWearableType::EType type, const U32 index); + // We no longer need this message in the current viewer, but send + // it for now to maintain compatibility with release viewers. Can + // remove this function once the SH-3455 changesets are universally deployed. + void sendDummyAgentWearablesUpdate(); + //-------------------------------------------------------------------- // Static UI hooks //-------------------------------------------------------------------- @@ -207,17 +193,13 @@ class LLAgentWearables : public LLInitClass, public LLWearable typedef std::vector llvo_vec_t; -// static void userUpdateAttachments(LLInventoryModel::item_array_t& obj_item_array); -// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2010-09-22 (Catznip-3.0.0a) | Added: Catznip-2.2.0a - // Not the best way to go about this but other attempts changed far too much LL code to be a viable solution - static void userUpdateAttachments(LLInventoryModel::item_array_t& obj_item_array, bool fAttachOnly = false); -// [/SL:KB] + static void findAttachmentsAddRemoveInfo(LLInventoryModel::item_array_t& obj_item_array, + llvo_vec_t& objects_to_remove, + llvo_vec_t& objects_to_retain, + LLInventoryModel::item_array_t& items_to_add); static void userRemoveMultipleAttachments(llvo_vec_t& llvo_array); static void userAttachMultipleAttachments(LLInventoryModel::item_array_t& obj_item_array); - BOOL itemUpdatePending(const LLUUID& item_id) const; - U32 itemUpdatePendingCount() const; - //-------------------------------------------------------------------- // Signals //-------------------------------------------------------------------- @@ -229,8 +211,8 @@ class LLAgentWearables : public LLInitClass, public LLWearable typedef boost::function loaded_callback_t; typedef boost::signals2::signal loaded_signal_t; boost::signals2::connection addLoadedCallback(loaded_callback_t cb); -// [SL:KB] - Patch: Appearance-InitialWearablesLoadedCallback | Checked: 2010-08-14 (Catznip-3.0.0a) | Added: Catznip-2.1.1d - boost::signals2::connection addInitialWearablesLoadedCallback(loaded_callback_t cb); +// [SL:KB] - Patch: Appearance-InitialWearablesLoadedCallback | Checked: 2010-08-14 (Catznip-2.1) + boost::signals2::connection addInitialWearablesLoadedCallback(const loaded_callback_t& cb); // [/SL:KB] bool changeInProgress() const; @@ -240,7 +222,7 @@ class LLAgentWearables : public LLInitClass, public LLWearable private: loading_started_signal_t mLoadingStartedSignal; // should be called before wearables are changed loaded_signal_t mLoadedSignal; // emitted when all agent wearables get loaded -// [SL:KB] - Patch: Appearance-InitialWearablesLoadedCallback | Checked: 2010-08-14 (Catznip-3.0.0a) | Added: Catznip-2.1.1d +// [SL:KB] - Patch: Appearance-InitialWearablesLoadedCallback | Checked: 2010-08-14 (Catznip-2.1) loaded_signal_t mInitialWearablesLoadedSignal; // emitted once when the initial wearables are loaded // [/SL:KB] @@ -249,33 +231,25 @@ class LLAgentWearables : public LLInitClass, public LLWearable //-------------------------------------------------------------------- private: static BOOL mInitialWearablesUpdateReceived; -// [SL:KB] - Patch: Appearance-InitialWearablesLoadedCallback | Checked: 2010-08-14 (Catznip-3.0.0a) | Added: Catznip-2.2.0a +// [SL:KB] - Patch: Appearance-InitialWearablesLoadedCallback | Checked: 2010-08-14 (Catznip-2.2) static bool mInitialWearablesLoaded; // [/SL:KB] +// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1) + static bool mInitialAttachmentsRequested; +// [/RLVa:KB] BOOL mWearablesLoaded; - std::set mItemsAwaitingWearableUpdate; /** * True if agent's outfit is being changed now. */ BOOL mCOFChangeInProgress; + LLTimer mCOFChangeTimer; //-------------------------------------------------------------------------------- // Support classes //-------------------------------------------------------------------------------- private: - class createStandardWearablesAllDoneCallback : public LLRefCount - { - protected: - ~createStandardWearablesAllDoneCallback(); - }; - class sendAgentWearablesUpdateCallback : public LLRefCount - { - protected: - ~sendAgentWearablesUpdateCallback(); - }; - - class addWearableToAgentInventoryCallback : public LLInventoryCallback + class AddWearableToAgentInventoryCallback : public LLInventoryCallback { public: enum ETodo @@ -288,7 +262,7 @@ class LLAgentWearables : public LLInitClass, public LLWearable CALL_WEARITEM = 16 }; - addWearableToAgentInventoryCallback(LLPointer cb, + AddWearableToAgentInventoryCallback(LLPointer cb, LLWearableType::EType type, U32 index, LLViewerWearable* wearable, diff --git a/indra/newview/llagentwearablesfetch.cpp b/indra/newview/llagentwearablesfetch.cpp index 3b48606a51..dce3d22f61 100644 --- a/indra/newview/llagentwearablesfetch.cpp +++ b/indra/newview/llagentwearablesfetch.cpp @@ -45,7 +45,7 @@ void order_my_outfits_cb() { if (!LLApp::isRunning()) { - llwarns << "called during shutdown, skipping" << llendl; + LL_WARNS() << "called during shutdown, skipping" << LL_ENDL; return; } @@ -60,11 +60,11 @@ void order_my_outfits_cb() //My Outfits should at least contain saved initial outfit and one another outfit if (cats->size() < 2) { - llwarning("My Outfits category was not populated properly", 0); + LL_WARNS() << "My Outfits category was not populated properly" << LL_ENDL; return; } - llinfos << "Starting updating My Outfits with wearables ordering information" << llendl; + LL_INFOS() << "Starting updating My Outfits with wearables ordering information" << LL_ENDL; for (LLInventoryModel::cat_array_t::iterator outfit_iter = cats->begin(); outfit_iter != cats->end(); ++outfit_iter) @@ -78,7 +78,7 @@ void order_my_outfits_cb() LLAppearanceMgr::getInstance()->updateClothingOrderingInfo(cat_id); } - llinfos << "Finished updating My Outfits with wearables ordering information" << llendl; + LL_INFOS() << "Finished updating My Outfits with wearables ordering information" << LL_ENDL; } LLInitialWearablesFetch::LLInitialWearablesFetch(const LLUUID& cof_id) : @@ -135,7 +135,15 @@ void LLInitialWearablesFetch::processContents() LLInventoryModel::cat_array_t cat_array; LLInventoryModel::item_array_t wearable_array; LLFindWearables is_wearable; - llassert(mComplete.size() != 0); + // + llassert(!mComplete.empty()); + if (mComplete.empty()) + { + // We can't call mComplete.front() in this case. + LL_WARNS() << "mComplete is empty." << LL_ENDL; + } + else + // gInventory.collectDescendentsIf(mComplete.front(), cat_array, wearable_array, LLInventoryModel::EXCLUDE_TRASH, is_wearable); @@ -155,7 +163,7 @@ void LLInitialWearablesFetch::processContents() const LLUUID& idItem = itWearableData->mItemID; bool fFound = false; for (S32 idxItem = 0, cntItem = items_by_type[itWearableData->mType].size(); idxItem < cntItem; idxItem++) { - const LLViewerInventoryItem* pCOFItem = items_by_type[itWearableData->mType].get(idxItem); + const LLViewerInventoryItem* pCOFItem = items_by_type[itWearableData->mType].at(idxItem); if (idItem == pCOFItem->getLinkedUUID()) { fFound = true; @@ -169,7 +177,7 @@ void LLInitialWearablesFetch::processContents() // [/SL:KB] LLAppearanceMgr::instance().setAttachmentInvLinkEnable(true); -// if (wearable_array.count() > 0) +// if (wearable_array.size() > 0) // [SL:KB] - Patch: Appearance-MixedViewers | Checked: 2010-04-28 (Catznip-3.0.0a) | Modified: Catznip-2.0.0e if (fUpdateFromCOF) // [/SL:KB] @@ -210,7 +218,7 @@ class LLFetchAndLinkObserver: public LLInventoryFetchItemsObserver // LLViewerInventoryItem *item = gInventory.getItem(*it); // if (!item) // { -// llwarns << "fetch failed!" << llendl; +// LL_WARNS() << "fetch failed!" << LL_ENDL; // continue; // } // @@ -231,13 +239,13 @@ class LLFetchAndLinkObserver: public LLInventoryFetchItemsObserver void doneIdle() { // NOTE: the code above makes the assumption that COF is empty which won't be the case the way it's used now - LLInventoryModel::item_array_t initial_items; + LLInventoryObject::const_object_list_t initial_items; for (uuid_vec_t::iterator itItem = mIDs.begin(); itItem != mIDs.end(); ++itItem) { LLViewerInventoryItem* pItem = gInventory.getItem(*itItem); if (!pItem) { - llwarns << "fetch failed!" << llendl; + LL_WARNS() << "fetch failed!" << LL_ENDL; continue; } initial_items.push_back(pItem); @@ -259,21 +267,16 @@ void LLInitialWearablesFetch::processWearablesMessage() for (U8 i = 0; i < mAgentInitialWearables.size(); ++i) { // Populate the current outfit folder with links to the wearables passed in the message -// InitialWearableData *wearable_data = new InitialWearableData(mAgentInitialWearables[i]); // This will be deleted in the callback. -// [SL:KB] - Patch: Appearance-MixedViewers | Checked: 2010-05-02 (Catznip-3.0.0a) | Added: Catznip-2.0.0f - // Fixes minor leak: since COF is used onInitialWearableAssetArrived() will never get called and "wearable_data" leaks - InitialWearableData* wearable_data = &mAgentInitialWearables[i]; -// [/SL:KB] + const InitialWearableData& wearable_data = mAgentInitialWearables[i]; - if (wearable_data->mAssetID.notNull()) + if (wearable_data.mAssetID.notNull()) { - ids.push_back(wearable_data->mItemID); + ids.push_back(wearable_data.mItemID); } else { - llinfos << "Invalid wearable, type " << wearable_data->mType << " itemID " - << wearable_data->mItemID << " assetID " << wearable_data->mAssetID << llendl; -// delete wearable_data; + LL_INFOS() << "Invalid wearable, type " << wearable_data.mType << " itemID " + << wearable_data.mItemID << " assetID " << wearable_data.mAssetID << LL_ENDL; } } @@ -323,7 +326,7 @@ LLLibraryOutfitsFetch::LLLibraryOutfitsFetch(const LLUUID& my_outfits_id) : mCurrFetchStep(LOFS_FOLDER), mOutfitsPopulated(false) { - llinfos << "created" << llendl; + LL_INFOS() << "created" << LL_ENDL; mMyOutfitsID = LLUUID::null; mClothingID = LLUUID::null; @@ -334,12 +337,12 @@ LLLibraryOutfitsFetch::LLLibraryOutfitsFetch(const LLUUID& my_outfits_id) : LLLibraryOutfitsFetch::~LLLibraryOutfitsFetch() { - llinfos << "destroyed" << llendl; + LL_INFOS() << "destroyed" << LL_ENDL; } void LLLibraryOutfitsFetch::done() { - llinfos << "start" << llendl; + LL_INFOS() << "start" << LL_ENDL; // Delay this until idle() routine, since it's a heavy operation and // we also can't have it run within notifyObservers. @@ -349,7 +352,7 @@ void LLLibraryOutfitsFetch::done() void LLLibraryOutfitsFetch::doneIdle() { - llinfos << "start" << llendl; + LL_INFOS() << "start" << LL_ENDL; gInventory.addObserver(this); // Add this back in since it was taken out during ::done() @@ -375,7 +378,7 @@ void LLLibraryOutfitsFetch::doneIdle() contentsDone(); break; default: - llwarns << "Got invalid state for outfit fetch: " << mCurrFetchStep << llendl; + LL_WARNS() << "Got invalid state for outfit fetch: " << mCurrFetchStep << LL_ENDL; mOutfitsPopulated = TRUE; break; } @@ -391,7 +394,7 @@ void LLLibraryOutfitsFetch::doneIdle() void LLLibraryOutfitsFetch::folderDone() { - llinfos << "start" << llendl; + LL_INFOS() << "start" << LL_ENDL; LLInventoryModel::cat_array_t cat_array; LLInventoryModel::item_array_t wearable_array; @@ -400,14 +403,14 @@ void LLLibraryOutfitsFetch::folderDone() // Early out if we already have items in My Outfits // except the case when My Outfits contains just initial outfit - if (cat_array.count() > 1) + if (cat_array.size() > 1) { mOutfitsPopulated = true; return; } mClothingID = gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING); - mLibraryClothingID = gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING, false, true); + mLibraryClothingID = gInventory.findLibraryCategoryUUIDForType(LLFolderType::FT_CLOTHING, false); // If Library->Clothing->Initial Outfits exists, use that. LLNameCategoryCollector matchFolderFunctor("Initial Outfits"); @@ -416,9 +419,9 @@ void LLLibraryOutfitsFetch::folderDone() cat_array, wearable_array, LLInventoryModel::EXCLUDE_TRASH, matchFolderFunctor); - if (cat_array.count() > 0) + if (cat_array.size() > 0) { - const LLViewerInventoryCategory *cat = cat_array.get(0); + const LLViewerInventoryCategory *cat = cat_array.at(0); mLibraryClothingID = cat->getUUID(); } @@ -438,7 +441,7 @@ void LLLibraryOutfitsFetch::folderDone() void LLLibraryOutfitsFetch::outfitsDone() { - llinfos << "start" << llendl; + LL_INFOS() << "start" << LL_ENDL; LLInventoryModel::cat_array_t cat_array; LLInventoryModel::item_array_t wearable_array; @@ -448,7 +451,7 @@ void LLLibraryOutfitsFetch::outfitsDone() gInventory.collectDescendents(mLibraryClothingID, cat_array, wearable_array, LLInventoryModel::EXCLUDE_TRASH); - llassert(cat_array.count() > 0); + llassert(cat_array.size() > 0); for (LLInventoryModel::cat_array_t::const_iterator iter = cat_array.begin(); iter != cat_array.end(); ++iter) @@ -475,7 +478,7 @@ void LLLibraryOutfitsFetch::outfitsDone() matchFolderFunctor); if (cat_array.size() > 0) { - const LLViewerInventoryCategory *cat = cat_array.get(0); + const LLViewerInventoryCategory *cat = cat_array.at(0); mImportedClothingID = cat->getUUID(); } @@ -517,7 +520,7 @@ class LLLibraryOutfitsCopyDone: public LLInventoryCallback // Copy the clothing folders from the library into the imported clothing folder void LLLibraryOutfitsFetch::libraryDone() { - llinfos << "start" << llendl; + LL_INFOS() << "start" << LL_ENDL; if (mImportedClothingID != LLUUID::null) { @@ -542,13 +545,13 @@ void LLLibraryOutfitsFetch::libraryDone() const LLViewerInventoryCategory *cat = gInventory.getCategory(src_folder_id); if (!cat) { - llwarns << "Library folder import for uuid:" << src_folder_id << " failed to find folder." << llendl; + LL_WARNS() << "Library folder import for uuid:" << src_folder_id << " failed to find folder." << LL_ENDL; continue; } if (!LLAppearanceMgr::getInstance()->getCanMakeFolderIntoOutfit(src_folder_id)) { - llinfos << "Skipping non-outfit folder name:" << cat->getName() << llendl; + LL_INFOS() << "Skipping non-outfit folder name:" << cat->getName() << LL_ENDL; continue; } @@ -574,7 +577,7 @@ void LLLibraryOutfitsFetch::libraryDone() void LLLibraryOutfitsFetch::importedFolderFetch() { - llinfos << "start" << llendl; + LL_INFOS() << "start" << LL_ENDL; // Fetch the contents of the Imported Clothing Folder uuid_vec_t folders; @@ -591,7 +594,7 @@ void LLLibraryOutfitsFetch::importedFolderFetch() void LLLibraryOutfitsFetch::importedFolderDone() { - llinfos << "start" << llendl; + LL_INFOS() << "start" << LL_ENDL; LLInventoryModel::cat_array_t cat_array; LLInventoryModel::item_array_t wearable_array; @@ -623,7 +626,7 @@ void LLLibraryOutfitsFetch::importedFolderDone() void LLLibraryOutfitsFetch::contentsDone() { - llinfos << "start" << llendl; + LL_INFOS() << "start" << LL_ENDL; LLInventoryModel::cat_array_t cat_array; LLInventoryModel::item_array_t wearable_array; @@ -638,7 +641,7 @@ void LLLibraryOutfitsFetch::contentsDone() const LLViewerInventoryCategory *cat = gInventory.getCategory(folder_id); if (!cat) { - llwarns << "Library folder import for uuid:" << folder_id << " failed to find folder." << llendl; + LL_WARNS() << "Library folder import for uuid:" << folder_id << " failed to find folder." << LL_ENDL; continue; } @@ -658,13 +661,9 @@ void LLLibraryOutfitsFetch::contentsDone() wearable_iter != wearable_array.end(); ++wearable_iter) { - const LLViewerInventoryItem *item = wearable_iter->get(); - link_inventory_item(gAgent.getID(), - item->getLinkedUUID(), - new_outfit_folder_id, - item->getName(), - item->getDescription(), - LLAssetType::AT_LINK, + LLConstPointer item = wearable_iter->get(); + link_inventory_object(new_outfit_folder_id, + item, order_myoutfits_on_destroy); } } diff --git a/indra/newview/llaisapi.cpp b/indra/newview/llaisapi.cpp new file mode 100644 index 0000000000..c786308bed --- /dev/null +++ b/indra/newview/llaisapi.cpp @@ -0,0 +1,1027 @@ +/** + * @file llaisapi.cpp + * @brief classes and functions for interfacing with the v3+ ais inventory service. + * + * $LicenseInfo:firstyear=2013&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2013, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + * + */ + +#include "llviewerprecompiledheaders.h" +#include "llaisapi.h" + +#include "llagent.h" +#include "llcallbacklist.h" +#include "llinventorymodel.h" +#include "llsdutil.h" +#include "llviewerregion.h" +#include "llinventoryobserver.h" +#include "llviewercontrol.h" + +///---------------------------------------------------------------------------- +/// Classes for AISv3 support. +///---------------------------------------------------------------------------- + +extern AIHTTPTimeoutPolicy AISAPIResponder_timeout; + +class AISCommand final : public LLHTTPClient::ResponderWithCompleted +{ +public: + typedef boost::function command_func_type; + // AISCommand - base class for retry-able HTTP requests using the AISv3 cap. + + // Limit max in flight requests to 2. Server was aggressively throttling otherwise. + constexpr static U8 sMaxActiveAISCommands = 4; + static U8 sActiveAISCommands; + static std::queue< boost::intrusive_ptr< AISCommand > > sPendingAISCommands; + + virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return AISAPIResponder_timeout; } + + AISCommand(AISAPI::COMMAND_TYPE type, const char* name, const LLUUID& targetId, AISAPI::completion_t callback) : + mCommandFunc(NULL), + mRetryPolicy(new LLAdaptiveRetryPolicy(1.0, 32.0, 2.0, 10)), + mCompletionFunc(callback), + mTargetId(targetId), + mName(name), + mType(type) + {} + virtual ~AISCommand() + { + if (mActive) + { + --sActiveAISCommands; + while (sActiveAISCommands < sMaxActiveAISCommands && !sPendingAISCommands.empty()) + { + sPendingAISCommands.front()->dispatch(); + sPendingAISCommands.pop(); + } + } + } + + void run( command_func_type func ) + { + mCommandFunc = func; + if (sActiveAISCommands >= sMaxActiveAISCommands) + { + sPendingAISCommands.push(this); + } + else + { + dispatch(); + } + } + + char const* getName(void) const override + { + return mName; + } + +private: + void dispatch() + { + if (LLApp::isQuitting()) + { + return; + } + ++sActiveAISCommands; + mActive = true; + (mCommandFunc)(); + } + void markComplete() + { + // Command func holds a reference to self, need to release it + // after a success or final failure. + mCommandFunc = no_op; + mRetryPolicy->onSuccess(); + } + + bool onFailure() + { + mRetryPolicy->onFailure(mStatus, getResponseHeaders()); + F32 seconds_to_wait; + if (mRetryPolicy->shouldRetry(seconds_to_wait)) + { + if (mStatus == 503) + { + // Pad delay a bit more since we're getting throttled. + seconds_to_wait += 10.f + ll_frand(4.f); + } + LL_WARNS("Inventory") << "Retrying in " << seconds_to_wait << "seconds due to inventory error for " << getName() <<": " << dumpResponse() << LL_ENDL; + doAfterInterval(mCommandFunc,seconds_to_wait); + return true; + } + else + { + // Command func holds a reference to self, need to release it + // after a success or final failure. + // *TODO: Notify user? This seems bad. + LL_WARNS("Inventory") << "Abort due to inventory error for " << getName() <<": " << dumpResponse() << LL_ENDL; + mCommandFunc = no_op; + return false; + } + } + +protected: + void httpCompleted() override + { + // Continue through if successful or longer retrying, + if (isGoodStatus(mStatus) || !onFailure()) + { + markComplete(); + AISAPI::InvokeAISCommandCoro(this, getURL(), mTargetId, getContent(), mCompletionFunc, (AISAPI::COMMAND_TYPE)mType); + } + } + +private: + command_func_type mCommandFunc; + LLPointer mRetryPolicy; + AISAPI::completion_t mCompletionFunc; + const LLUUID mTargetId; + const char* mName; + bool mActive = false; + AISAPI::COMMAND_TYPE mType; +}; + +U8 AISCommand::sActiveAISCommands = 0; +std::queue< boost::intrusive_ptr< AISCommand > > AISCommand::sPendingAISCommands; + +//========================================================================= +const std::string AISAPI::INVENTORY_CAP_NAME("InventoryAPIv3"); +const std::string AISAPI::LIBRARY_CAP_NAME("LibraryAPIv3"); + +//------------------------------------------------------------------------- +/*static*/ +bool AISAPI::isAvailable() +{ + if (gAgent.getRegion()) + { + return gAgent.getRegion()->isCapabilityAvailable(INVENTORY_CAP_NAME); + } + return false; +} + +/*static*/ +void AISAPI::getCapNames(LLSD& capNames) +{ + capNames.append(INVENTORY_CAP_NAME); + capNames.append(LIBRARY_CAP_NAME); +} + +/*static*/ +std::string AISAPI::getInvCap() +{ + if (gAgent.getRegion()) + { + return gAgent.getRegion()->getCapability(INVENTORY_CAP_NAME); + } + return std::string(); +} + +/*static*/ +std::string AISAPI::getLibCap() +{ + if (gAgent.getRegion()) + { + return gAgent.getRegion()->getCapability(LIBRARY_CAP_NAME); + } + return std::string(); +} + +/*static*/ +void AISAPI::CreateInventory(const LLUUID& parentId, const LLSD& newInventory, completion_t callback) +{ + std::string cap = getInvCap(); + if (cap.empty()) + { + LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL; + return; + } + + LLUUID tid; + tid.generate(); + + std::string url = cap + std::string("/category/") + parentId.asString() + "?tid=" + tid.asString(); + LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL; + + boost::intrusive_ptr< AISCommand > responder = new AISCommand(COPYINVENTORY, "CreateInventory",parentId, callback); + responder->run(boost::bind(&LLHTTPClient::post, url, newInventory, responder/*,*/ DEBUG_CURLIO_PARAM(debug_off), keep_alive, (AIStateMachine*)NULL, 0)); +} + +/*static*/ +void AISAPI::SlamFolder(const LLUUID& folderId, const LLSD& newInventory, completion_t callback) +{ + std::string cap = getInvCap(); + if (cap.empty()) + { + LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL; + return; + } + + LLUUID tid; + tid.generate(); + + std::string url = cap + std::string("/category/") + folderId.asString() + "/links?tid=" + tid.asString(); + + AIHTTPHeaders headers; + headers.addHeader("Content-Type", "application/llsd+xml"); + boost::intrusive_ptr< AISCommand > responder = new AISCommand(SLAMFOLDER, "SlamFolder", folderId, callback); + responder->run(boost::bind(&LLHTTPClient::put, url, newInventory, responder, headers/*,*/ DEBUG_CURLIO_PARAM(debug_off))); + +} + +void AISAPI::RemoveCategory(const LLUUID &categoryId, completion_t callback) +{ + std::string cap; + + cap = getInvCap(); + if (cap.empty()) + { + LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL; + return; + } + + std::string url = cap + std::string("/category/") + categoryId.asString(); + LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL; + + boost::intrusive_ptr< AISCommand > responder = new AISCommand(REMOVECATEGORY, "RemoveCategory",categoryId, callback); + responder->run(boost::bind(&LLHTTPClient::del, url, responder/*,*/ DEBUG_CURLIO_PARAM(debug_off))); +} + +/*static*/ +void AISAPI::RemoveItem(const LLUUID &itemId, completion_t callback) +{ + std::string cap; + + cap = getInvCap(); + if (cap.empty()) + { + LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL; + return; + } + + std::string url = cap + std::string("/item/") + itemId.asString(); + LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL; + + boost::intrusive_ptr< AISCommand > responder = new AISCommand(REMOVEITEM,"RemoveItem",itemId, callback); + responder->run(boost::bind(&LLHTTPClient::del, url, responder/*,*/ DEBUG_CURLIO_PARAM(debug_off))); +} + +void AISAPI::CopyLibraryCategory(const LLUUID& sourceId, const LLUUID& destId, bool copySubfolders, completion_t callback) +{ + std::string cap; + + cap = getLibCap(); + if (cap.empty()) + { + LL_WARNS("Inventory") << "Library cap not found!" << LL_ENDL; + return; + } + + LL_DEBUGS("Inventory") << "Copying library category: " << sourceId << " => " << destId << LL_ENDL; + + LLUUID tid; + tid.generate(); + + std::string url = cap + std::string("/category/") + sourceId.asString() + "?tid=" + tid.asString(); + if (!copySubfolders) + { + url += ",depth=0"; + } + LL_INFOS() << url << LL_ENDL; + + std::string destination = destId.asString(); + + boost::intrusive_ptr< AISCommand > responder = new AISCommand(COPYLIBRARYCATEGORY, "CopyLibraryCategory",destId, callback); + responder->run(boost::bind(&LLHTTPClient::copy, url, destination, responder/*,*/ DEBUG_CURLIO_PARAM(debug_off))); + +} + +/*static*/ +void AISAPI::PurgeDescendents(const LLUUID &categoryId, completion_t callback) +{ + std::string cap; + + cap = getInvCap(); + if (cap.empty()) + { + LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL; + return; + } + + std::string url = cap + std::string("/category/") + categoryId.asString() + "/children"; + LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL; + + boost::intrusive_ptr< AISCommand > responder = new AISCommand(PURGEDESCENDENTS, "PurgeDescendents",categoryId, callback); + responder->run(boost::bind(&LLHTTPClient::del, url, responder/*,*/ DEBUG_CURLIO_PARAM(debug_off))); +} + +/*static*/ +void AISAPI::UpdateCategory(const LLUUID &categoryId, const LLSD &updates, completion_t callback) +{ + std::string cap; + + cap = getInvCap(); + if (cap.empty()) + { + LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL; + return; + } + std::string url = cap + std::string("/category/") + categoryId.asString(); + + boost::intrusive_ptr< AISCommand > responder = new AISCommand(UPDATECATEGORY, "UpdateCategory",categoryId, callback); + responder->run(boost::bind(&LLHTTPClient::patch, url, updates, responder/*,*/ DEBUG_CURLIO_PARAM(debug_off), keep_alive, (AIStateMachine*)NULL, 0)); +} + +/*static*/ +void AISAPI::UpdateItem(const LLUUID &itemId, const LLSD &updates, completion_t callback) +{ + + std::string cap; + + cap = getInvCap(); + if (cap.empty()) + { + LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL; + return; + } + std::string url = cap + std::string("/item/") + itemId.asString(); + + boost::intrusive_ptr< AISCommand > responder = new AISCommand(UPDATEITEM, "UpdateItem",itemId, callback); + responder->run(boost::bind(&LLHTTPClient::patch, url, updates, responder/*,*/ DEBUG_CURLIO_PARAM(debug_off), keep_alive, (AIStateMachine*)NULL, 0)); +} +void AISAPI::InvokeAISCommandCoro(LLHTTPClient::ResponderWithCompleted* responder, + std::string url, + LLUUID targetId, LLSD result, completion_t callback, COMMAND_TYPE type) +{ + LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL; + + auto status = responder->getStatus(); + + if (!responder->isGoodStatus(status) || !result.isMap()) + { + LL_WARNS("Inventory") << "Inventory error: " << status << ": " << responder->getReason() << LL_ENDL; + if (status == 410) //GONE + { + // Item does not exist or was already deleted from server. + // parent folder is out of sync + if (type == REMOVECATEGORY) + { + LLViewerInventoryCategory *cat = gInventory.getCategory(targetId); + if (cat) + { + LL_WARNS("Inventory") << "Purge failed for '" << cat->getName() + << "' local version:" << cat->getVersion() + << " since folder no longer exists at server. Descendent count: server == " << cat->getDescendentCount() + << ", viewer == " << cat->getViewerDescendentCount() + << LL_ENDL; + gInventory.fetchDescendentsOf(cat->getParentUUID()); + // Note: don't delete folder here - contained items will be deparented (or deleted) + // and since we are clearly out of sync we can't be sure we won't get rid of something we need. + // For example folder could have been moved or renamed with items intact, let it fetch first. + } + } + else if (type == REMOVEITEM) + { + LLViewerInventoryItem *item = gInventory.getItem(targetId); + if (item) + { + LL_WARNS("Inventory") << "Purge failed for '" << item->getName() + << "' since item no longer exists at server." << LL_ENDL; + gInventory.fetchDescendentsOf(item->getParentUUID()); + // since item not on the server and exists at viewer, so it needs an update at the least, + // so delete it, in worst case item will be refetched with new params. + gInventory.onObjectDeletedFromServer(targetId); + } + } + } + if (!result.isMap()) + { + LL_WARNS("Inventory") << "Inventory error: Malformed response contents" << LL_ENDL; + } + LL_WARNS("Inventory") << ll_pretty_print_sd(result) << LL_ENDL; + } + + gInventory.onAISUpdateReceived("AISCommand", result); + + if (callback && callback != nullptr) + { +// [SL:KB] - Patch: Appearance-SyncAttach | Checked: Catznip-3.7 + uuid_list_t ids; + switch (type) + { + case COPYLIBRARYCATEGORY: + if (result.has("category_id")) + { + ids.insert(result["category_id"]); + } + break; + case COPYINVENTORY: + { + AISUpdate::parseUUIDArray(result, "_created_items", ids); + AISUpdate::parseUUIDArray(result, "_created_categories", ids); + } + break; + default: + break; + } + + // If we were feeling daring we'd call LLInventoryCallback::fire for every item but it would take additional work to investigate whether all LLInventoryCallback derived classes + // were designed to handle multiple fire calls (with legacy link creation only one would ever fire per link creation) so we'll be cautious and only call for the first one for now + // (note that the LL code as written below will always call fire once with the NULL UUID for anything but CopyLibraryCategoryCommand so even the above is an improvement) + callback( (!ids.empty()) ? *ids.begin() : LLUUID::null); +// [/SL:KB] +// LLUUID id(LLUUID::null); +// +// if (result.has("category_id") && (type == COPYLIBRARYCATEGORY)) +// { +// id = result["category_id"]; +// } +// +// callback(id); + } + +} + +//------------------------------------------------------------------------- +AISUpdate::AISUpdate(const LLSD& update) +{ + parseUpdate(update); +} + +void AISUpdate::clearParseResults() +{ + mCatDescendentDeltas.clear(); + mCatDescendentsKnown.clear(); + mCatVersionsUpdated.clear(); + mItemsCreated.clear(); + mItemsUpdated.clear(); + mCategoriesCreated.clear(); + mCategoriesUpdated.clear(); + mObjectsDeletedIds.clear(); + mItemIds.clear(); + mCategoryIds.clear(); +} + +void AISUpdate::parseUpdate(const LLSD& update) +{ + clearParseResults(); + parseMeta(update); + parseContent(update); +} + +void AISUpdate::parseMeta(const LLSD& update) +{ + // parse _categories_removed -> mObjectsDeletedIds + uuid_list_t cat_ids; + parseUUIDArray(update,"_categories_removed",cat_ids); + for (auto cat_id : cat_ids) + { + LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id); + if(cat) + { + mCatDescendentDeltas[cat->getParentUUID()]--; + mObjectsDeletedIds.insert(cat_id); + } + else + { + LL_WARNS("Inventory") << "removed category not found " << cat_id << LL_ENDL; + } + } + + // parse _categories_items_removed -> mObjectsDeletedIds + uuid_list_t item_ids; + parseUUIDArray(update,"_category_items_removed",item_ids); + parseUUIDArray(update,"_removed_items",item_ids); + for (auto item_id : item_ids) + { + LLViewerInventoryItem *item = gInventory.getItem(item_id); + if(item) + { + mCatDescendentDeltas[item->getParentUUID()]--; + mObjectsDeletedIds.insert(item_id); + } + else + { + LL_WARNS("Inventory") << "removed item not found " << item_id << LL_ENDL; + } + } + + // parse _broken_links_removed -> mObjectsDeletedIds + uuid_list_t broken_link_ids; + parseUUIDArray(update,"_broken_links_removed",broken_link_ids); + for (auto broken_link_id : broken_link_ids) + { + LLViewerInventoryItem *item = gInventory.getItem(broken_link_id); + if(item) + { + mCatDescendentDeltas[item->getParentUUID()]--; + mObjectsDeletedIds.insert(broken_link_id); + } + else + { + LL_WARNS("Inventory") << "broken link not found " << broken_link_id << LL_ENDL; + } + } + + // parse _created_items + parseUUIDArray(update,"_created_items",mItemIds); + + // parse _created_categories + parseUUIDArray(update,"_created_categories",mCategoryIds); + + // Parse updated category versions. + const std::string& ucv = "_updated_category_versions"; + if (update.has(ucv)) + { + for(LLSD::map_const_iterator it = update[ucv].beginMap(), + end = update[ucv].endMap(); + it != end; ++it) + { + const LLUUID id((*it).first); + S32 version = (*it).second.asInteger(); + mCatVersionsUpdated[id] = version; + } + } +} + +void AISUpdate::parseContent(const LLSD& update) +{ + if (update.has("linked_id")) + { + parseLink(update); + } + else if (update.has("item_id")) + { + parseItem(update); + } + + if (update.has("category_id")) + { + parseCategory(update); + } + else + { + if (update.has("_embedded")) + { + parseEmbedded(update["_embedded"]); + } + } +} + +void AISUpdate::parseItem(const LLSD& item_map) +{ + LLUUID item_id = item_map["item_id"].asUUID(); + LLPointer new_item(new LLViewerInventoryItem); + LLViewerInventoryItem *curr_item = gInventory.getItem(item_id); + if (curr_item) + { + // Default to current values where not provided. + new_item->copyViewerItem(curr_item); + } + BOOL rv = new_item->unpackMessage(item_map); + if (rv) + { + if (curr_item) + { + mItemsUpdated[item_id] = new_item; + // This statement is here to cause a new entry with 0 + // delta to be created if it does not already exist; + // otherwise has no effect. + mCatDescendentDeltas[new_item->getParentUUID()]; + } + else + { + mItemsCreated[item_id] = new_item; + mCatDescendentDeltas[new_item->getParentUUID()]++; + } + } + else + { + // *TODO: Wow, harsh. Should we just complain and get out? + LL_ERRS() << "unpack failed" << LL_ENDL; + } +} + +void AISUpdate::parseLink(const LLSD& link_map) +{ + LLUUID item_id = link_map["item_id"].asUUID(); + LLPointer new_link(new LLViewerInventoryItem); + LLViewerInventoryItem *curr_link = gInventory.getItem(item_id); + if (curr_link) + { + // Default to current values where not provided. + new_link->copyViewerItem(curr_link); + } + BOOL rv = new_link->unpackMessage(link_map); + if (rv) + { + const LLUUID& parent_id = new_link->getParentUUID(); + if (curr_link) + { + mItemsUpdated[item_id] = new_link; + // This statement is here to cause a new entry with 0 + // delta to be created if it does not already exist; + // otherwise has no effect. + mCatDescendentDeltas[parent_id]; + } + else + { + LLPermissions default_perms; + default_perms.init(gAgent.getID(),gAgent.getID(),LLUUID::null,LLUUID::null); + default_perms.initMasks(PERM_NONE,PERM_NONE,PERM_NONE,PERM_NONE,PERM_NONE); + new_link->setPermissions(default_perms); + LLSaleInfo default_sale_info; + new_link->setSaleInfo(default_sale_info); + //LL_DEBUGS("Inventory") << "creating link from llsd: " << ll_pretty_print_sd(link_map) << LL_ENDL; + mItemsCreated[item_id] = new_link; + mCatDescendentDeltas[parent_id]++; + } + } + else + { + // *TODO: Wow, harsh. Should we just complain and get out? + LL_ERRS() << "unpack failed" << LL_ENDL; + } +} + + +void AISUpdate::parseCategory(const LLSD& category_map) +{ + LLUUID category_id = category_map["category_id"].asUUID(); + + // Check descendent count first, as it may be needed + // to populate newly created categories + if (category_map.has("_embedded")) + { + parseDescendentCount(category_id, category_map["_embedded"]); + } + + LLPointer new_cat; + LLViewerInventoryCategory *curr_cat = gInventory.getCategory(category_id); + if (curr_cat) + { + // Default to current values where not provided. + new_cat = new LLViewerInventoryCategory(curr_cat); + } + else + { + if (category_map.has("agent_id")) + { + new_cat = new LLViewerInventoryCategory(category_map["agent_id"].asUUID()); + } + else + { + LL_DEBUGS() << "No owner provided, folder might be assigned wrong owner" << LL_ENDL; + new_cat = new LLViewerInventoryCategory(LLUUID::null); + } + } + BOOL rv = new_cat->unpackMessage(category_map); + // *NOTE: unpackMessage does not unpack version or descendent count. + //if (category_map.has("version")) + //{ + // mCatVersionsUpdated[category_id] = category_map["version"].asInteger(); + //} + if (rv) + { + if (curr_cat) + { + mCategoriesUpdated[category_id] = new_cat; + // This statement is here to cause a new entry with 0 + // delta to be created if it does not already exist; + // otherwise has no effect. + mCatDescendentDeltas[new_cat->getParentUUID()]; + // Capture update for the category itself as well. + mCatDescendentDeltas[category_id]; + } + else + { + // Set version/descendents for newly created categories. + if (category_map.has("version")) + { + S32 version = category_map["version"].asInteger(); + LL_DEBUGS("Inventory") << "Setting version to " << version + << " for new category " << category_id << LL_ENDL; + new_cat->setVersion(version); + } + uuid_int_map_t::const_iterator lookup_it = mCatDescendentsKnown.find(category_id); + if (mCatDescendentsKnown.end() != lookup_it) + { + S32 descendent_count = lookup_it->second; + LL_DEBUGS("Inventory") << "Setting descendents count to " << descendent_count + << " for new category " << category_id << LL_ENDL; + new_cat->setDescendentCount(descendent_count); + } + mCategoriesCreated[category_id] = new_cat; + mCatDescendentDeltas[new_cat->getParentUUID()]++; + } + } + else + { + // *TODO: Wow, harsh. Should we just complain and get out? + LL_ERRS() << "unpack failed" << LL_ENDL; + } + + // Check for more embedded content. + if (category_map.has("_embedded")) + { + parseEmbedded(category_map["_embedded"]); + } +} + +void AISUpdate::parseDescendentCount(const LLUUID& category_id, const LLSD& embedded) +{ + // We can only determine true descendent count if this contains all descendent types. + if (embedded.has("categories") && + embedded.has("links") && + embedded.has("items")) + { + mCatDescendentsKnown[category_id] = embedded["categories"].size(); + mCatDescendentsKnown[category_id] += embedded["links"].size(); + mCatDescendentsKnown[category_id] += embedded["items"].size(); + } +} + +void AISUpdate::parseEmbedded(const LLSD& embedded) +{ + if (embedded.has("links")) // _embedded in a category + { + parseEmbeddedLinks(embedded["links"]); + } + if (embedded.has("items")) // _embedded in a category + { + parseEmbeddedItems(embedded["items"]); + } + if (embedded.has("item")) // _embedded in a link + { + parseEmbeddedItem(embedded["item"]); + } + if (embedded.has("categories")) // _embedded in a category + { + parseEmbeddedCategories(embedded["categories"]); + } + if (embedded.has("category")) // _embedded in a link + { + parseEmbeddedCategory(embedded["category"]); + } +} + +void AISUpdate::parseUUIDArray(const LLSD& content, const std::string& name, uuid_list_t& ids) +{ + if (content.has(name)) + { + for (auto& id : content[name].array()) + { + ids.insert(id.asUUID()); + } + } +} + +void AISUpdate::parseEmbeddedLinks(const LLSD& links) +{ + for(LLSD::map_const_iterator linkit = links.beginMap(), + linkend = links.endMap(); + linkit != linkend; ++linkit) + { + const LLUUID link_id((*linkit).first); + const LLSD& link_map = (*linkit).second; + if (mItemIds.end() == mItemIds.find(link_id)) + { + LL_DEBUGS("Inventory") << "Ignoring link not in items list " << link_id << LL_ENDL; + } + else + { + parseLink(link_map); + } + } +} + +void AISUpdate::parseEmbeddedItem(const LLSD& item) +{ + // a single item (_embedded in a link) + if (item.has("item_id")) + { + if (mItemIds.end() != mItemIds.find(item["item_id"].asUUID())) + { + parseItem(item); + } + } +} + +void AISUpdate::parseEmbeddedItems(const LLSD& items) +{ + // a map of items (_embedded in a category) + for(LLSD::map_const_iterator itemit = items.beginMap(), + itemend = items.endMap(); + itemit != itemend; ++itemit) + { + const LLUUID item_id((*itemit).first); + const LLSD& item_map = (*itemit).second; + if (mItemIds.end() == mItemIds.find(item_id)) + { + LL_DEBUGS("Inventory") << "Ignoring item not in items list " << item_id << LL_ENDL; + } + else + { + parseItem(item_map); + } + } +} + +void AISUpdate::parseEmbeddedCategory(const LLSD& category) +{ + // a single category (_embedded in a link) + if (category.has("category_id")) + { + if (mCategoryIds.end() != mCategoryIds.find(category["category_id"].asUUID())) + { + parseCategory(category); + } + } +} + +void AISUpdate::parseEmbeddedCategories(const LLSD& categories) +{ + // a map of categories (_embedded in a category) + for(LLSD::map_const_iterator categoryit = categories.beginMap(), + categoryend = categories.endMap(); + categoryit != categoryend; ++categoryit) + { + const LLUUID category_id((*categoryit).first); + const LLSD& category_map = (*categoryit).second; + if (mCategoryIds.end() == mCategoryIds.find(category_id)) + { + LL_DEBUGS("Inventory") << "Ignoring category not in categories list " << category_id << LL_ENDL; + } + else + { + parseCategory(category_map); + } + } +} + +void AISUpdate::doUpdate() +{ + // Do version/descendant accounting. + for (std::map::const_iterator catit = mCatDescendentDeltas.begin(); + catit != mCatDescendentDeltas.end(); ++catit) + { + LL_DEBUGS("Inventory") << "descendant accounting for " << catit->first << LL_ENDL; + + const LLUUID cat_id(catit->first); + // Don't account for update if we just created this category. + if (mCategoriesCreated.find(cat_id) != mCategoriesCreated.end()) + { + LL_DEBUGS("Inventory") << "Skipping version increment for new category " << cat_id << LL_ENDL; + continue; + } + + // Don't account for update unless AIS told us it updated that category. + if (mCatVersionsUpdated.find(cat_id) == mCatVersionsUpdated.end()) + { + LL_DEBUGS("Inventory") << "Skipping version increment for non-updated category " << cat_id << LL_ENDL; + continue; + } + + // If we have a known descendant count, set that now. + LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id); + if (cat) + { + S32 descendent_delta = catit->second; + S32 old_count = cat->getDescendentCount(); + LL_DEBUGS("Inventory") << "Updating descendant count for " + << cat->getName() << " " << cat_id + << " with delta " << descendent_delta << " from " + << old_count << " to " << (old_count+descendent_delta) << LL_ENDL; + LLInventoryModel::LLCategoryUpdate up(cat_id, descendent_delta); + gInventory.accountForUpdate(up); + } + else + { + LL_DEBUGS("Inventory") << "Skipping version accounting for unknown category " << cat_id << LL_ENDL; + } + } + + // CREATE CATEGORIES + for (deferred_category_map_t::const_iterator create_it = mCategoriesCreated.begin(); + create_it != mCategoriesCreated.end(); ++create_it) + { + LLUUID category_id(create_it->first); + LLPointer new_category = create_it->second; + + gInventory.updateCategory(new_category, LLInventoryObserver::CREATE); + LL_DEBUGS("Inventory") << "created category " << category_id << LL_ENDL; + } + + // UPDATE CATEGORIES + for (deferred_category_map_t::const_iterator update_it = mCategoriesUpdated.begin(); + update_it != mCategoriesUpdated.end(); ++update_it) + { + LLUUID category_id(update_it->first); + LLPointer new_category = update_it->second; + // Since this is a copy of the category *before* the accounting update, above, + // we need to transfer back the updated version/descendant count. + LLViewerInventoryCategory* curr_cat = gInventory.getCategory(new_category->getUUID()); + if (!curr_cat) + { + LL_WARNS("Inventory") << "Failed to update unknown category " << new_category->getUUID() << LL_ENDL; + } + else + { + new_category->setVersion(curr_cat->getVersion()); + new_category->setDescendentCount(curr_cat->getDescendentCount()); + gInventory.updateCategory(new_category); + LL_DEBUGS("Inventory") << "updated category " << new_category->getName() << " " << category_id << LL_ENDL; + } + } + + // CREATE ITEMS + for (deferred_item_map_t::const_iterator create_it = mItemsCreated.begin(); + create_it != mItemsCreated.end(); ++create_it) + { + LLUUID item_id(create_it->first); + LLPointer new_item = create_it->second; + + // FIXME risky function since it calls updateServer() in some + // cases. Maybe break out the update/create cases, in which + // case this is create. + LL_DEBUGS("Inventory") << "created item " << item_id << LL_ENDL; + gInventory.updateItem(new_item, LLInventoryObserver::CREATE); + } + + // UPDATE ITEMS + for (deferred_item_map_t::const_iterator update_it = mItemsUpdated.begin(); + update_it != mItemsUpdated.end(); ++update_it) + { + LLUUID item_id(update_it->first); + LLPointer new_item = update_it->second; + // FIXME risky function since it calls updateServer() in some + // cases. Maybe break out the update/create cases, in which + // case this is update. + LL_DEBUGS("Inventory") << "updated item " << item_id << LL_ENDL; + //LL_DEBUGS("Inventory") << ll_pretty_print_sd(new_item->asLLSD()) << LL_ENDL; + gInventory.updateItem(new_item); + } + + // DELETE OBJECTS + for (auto deleted_id : mObjectsDeletedIds) + { + LL_DEBUGS("Inventory") << "deleted item " << deleted_id << LL_ENDL; + gInventory.onObjectDeletedFromServer(deleted_id, false, false, false); + } + + // TODO - how can we use this version info? Need to be sure all + // changes are going through AIS first, or at least through + // something with a reliable responder. + for (auto& ucv_it : mCatVersionsUpdated) + { + const LLUUID id = ucv_it.first; + S32 version = ucv_it.second; + LLViewerInventoryCategory *cat = gInventory.getCategory(id); + LL_DEBUGS("Inventory") << "cat version update " << cat->getName() << " to version " << cat->getVersion() << LL_ENDL; + if (cat->getVersion() != version) + { + LL_WARNS() << "Possible version mismatch for category " << cat->getName() + << ", viewer version " << cat->getVersion() + << " AIS version " << version << " !!!Adjusting local version!!!" << LL_ENDL; + + // the AIS version should be considered the true version. Adjust + // our local category model to reflect this version number. Otherwise + // it becomes possible to get stuck with the viewer being out of + // sync with the inventory system. Under normal circumstances + // inventory COF is maintained on the viewer through calls to + // LLInventoryModel::accountForUpdate when a changing operation + // is performed. This occasionally gets out of sync however. + if (version != LLViewerInventoryCategory::VERSION_UNKNOWN) + { + cat->setVersion(version); + } + else + { + // We do not account for update if version is UNKNOWN, so we shouldn't rise version + // either or viewer will get stuck on descendants count -1, try to refetch folder instead + cat->fetch(); + } + } + } + + gInventory.notifyObservers(); +} + diff --git a/indra/newview/llaisapi.h b/indra/newview/llaisapi.h new file mode 100644 index 0000000000..7fc247779a --- /dev/null +++ b/indra/newview/llaisapi.h @@ -0,0 +1,124 @@ +/** + * @file llaisapi.h + * @brief classes and functions for interfacing with the v3+ ais inventory service. + * + * $LicenseInfo:firstyear=2013&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2013, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLAISAPI_H +#define LL_LLAISAPI_H + +#include "lluuid.h" +#include +#include +#include +#include "llcurl.h" +#include "llhttpclient.h" +#include "llhttpretrypolicy.h" +#include "llviewerinventory.h" + +class AISAPI +{ + friend class AISCommand; +public: + typedef std::function completion_t; + + static bool isAvailable(); + static void getCapNames(LLSD& capNames); + + static void CreateInventory(const LLUUID& parentId, const LLSD& newInventory, completion_t callback = completion_t()); + static void SlamFolder(const LLUUID& folderId, const LLSD& newInventory, completion_t callback = completion_t()); + static void RemoveCategory(const LLUUID &categoryId, completion_t callback = completion_t()); + static void RemoveItem(const LLUUID &itemId, completion_t callback = completion_t()); + static void PurgeDescendents(const LLUUID &categoryId, completion_t callback = completion_t()); + static void UpdateCategory(const LLUUID &categoryId, const LLSD &updates, completion_t callback = completion_t()); + static void UpdateItem(const LLUUID &itemId, const LLSD &updates, completion_t callback = completion_t()); + static void CopyLibraryCategory(const LLUUID& sourceId, const LLUUID& destId, bool copySubfolders, completion_t callback = completion_t()); + +private: + typedef enum { + COPYINVENTORY, + SLAMFOLDER, + REMOVECATEGORY, + REMOVEITEM, + PURGEDESCENDENTS, + UPDATECATEGORY, + UPDATEITEM, + COPYLIBRARYCATEGORY + } COMMAND_TYPE; + + static const std::string INVENTORY_CAP_NAME; + static const std::string LIBRARY_CAP_NAME; + + static std::string getInvCap(); + static std::string getLibCap(); + + static void InvokeAISCommandCoro(LLHTTPClient::ResponderWithCompleted* responder, + std::string url, LLUUID targetId, LLSD body, + completion_t callback, COMMAND_TYPE type); +}; + +class AISUpdate +{ +public: + AISUpdate(const LLSD& update); + void parseUpdate(const LLSD& update); + void parseMeta(const LLSD& update); + void parseContent(const LLSD& update); +// [SL:KB] - Patch: Appearance-SyncAttach | Checked: Catznip-3.7 + static void parseUUIDArray(const LLSD& content, const std::string& name, uuid_list_t& ids); +// [/SL:KB] +// void parseUUIDArray(const LLSD& content, const std::string& name, uuid_list_t& ids); + void parseLink(const LLSD& link_map); + void parseItem(const LLSD& link_map); + void parseCategory(const LLSD& link_map); + void parseDescendentCount(const LLUUID& category_id, const LLSD& embedded); + void parseEmbedded(const LLSD& embedded); + void parseEmbeddedLinks(const LLSD& links); + void parseEmbeddedItems(const LLSD& items); + void parseEmbeddedCategories(const LLSD& categories); + void parseEmbeddedItem(const LLSD& item); + void parseEmbeddedCategory(const LLSD& category); + void doUpdate(); +private: + void clearParseResults(); + + typedef std::map uuid_int_map_t; + uuid_int_map_t mCatDescendentDeltas; + uuid_int_map_t mCatDescendentsKnown; + uuid_int_map_t mCatVersionsUpdated; + + typedef std::map > deferred_item_map_t; + deferred_item_map_t mItemsCreated; + deferred_item_map_t mItemsUpdated; + typedef std::map > deferred_category_map_t; + deferred_category_map_t mCategoriesCreated; + deferred_category_map_t mCategoriesUpdated; + + // These keep track of uuid's mentioned in meta values. + // Useful for filtering out which content we are interested in. + uuid_list_t mObjectsDeletedIds; + uuid_list_t mItemIds; + uuid_list_t mCategoryIds; +}; + +#endif diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index b840c63fcd..ebda2b1202 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -33,6 +33,7 @@ #include "llattachmentsmgr.h" #include "llcommandhandler.h" #include "lleventtimer.h" +#include "llfloatercustomize.h" #include "llgesturemgr.h" #include "llinventorybridge.h" #include "llinventoryfunctions.h" @@ -49,14 +50,21 @@ #include "llviewerstats.h" #include "llwearablelist.h" #include "llsdutil.h" +#include "llhttpretrypolicy.h" +#include "llaisapi.h" #include "llinventorypanel.h" -#include "llfloatercustomize.h" -// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a) +// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1) #include "rlvhandler.h" #include "rlvhelper.h" #include "rlvlocks.h" // [/RLVa:KB] +void doAppearanceCb(LLPointer cb, LLUUID id) +{ + if (cb.notNull()) + cb->fire(id); +} + std::string self_av_string() { // On logout gAgentAvatarp can already be invalid @@ -113,7 +121,7 @@ class LLOutfitUnLockTimer: public LLEventTimer }; // support for secondlife:///app/appearance SLapps -/*class LLAppearanceHandler : public LLCommandHandler +class LLAppearanceHandler : public LLCommandHandler { public: // requests will be throttled from a non-trusted browser @@ -121,6 +129,7 @@ class LLOutfitUnLockTimer: public LLEventTimer bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web) { + /* Singu Note: Nopenopenope. // support secondlife:///app/appearance/show, but for now we just // make all secondlife:///app/appearance SLapps behave this way if (!LLUI::sSettingGroups["config"]->getBOOL("EnableAppearance")) @@ -128,13 +137,14 @@ class LLOutfitUnLockTimer: public LLEventTimer LLNotificationsUtil::add("NoAppearance", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit")); return true; } + */ - LLFloaterSidePanelContainer::showPanel("appearance", LLSD()); + LLFloaterCustomize::getInstance()->open(); return true; } }; -LLAppearanceHandler gAppearanceHandler;*/ +LLAppearanceHandler gAppearanceHandler; LLUUID findDescendentCategoryIDByName(const LLUUID& parent_id, const std::string& name) @@ -147,16 +157,16 @@ LLUUID findDescendentCategoryIDByName(const LLUUID& parent_id, const std::string item_array, LLInventoryModel::EXCLUDE_TRASH, has_name); - if (0 == cat_array.count()) + if (0 == cat_array.size()) return LLUUID(); else { - LLViewerInventoryCategory *cat = cat_array.get(0); + LLViewerInventoryCategory *cat = cat_array.at(0); if (cat) return cat->getUUID(); else { - llwarns << "null cat" << llendl; + LL_WARNS() << "null cat" << LL_ENDL; return LLUUID(); } } @@ -215,11 +225,10 @@ class LLCallAfterInventoryBatchMgr: public LLEventTimer // Request or re-request operation for specified item. void addItem(const LLUUID& item_id) { - LL_DEBUGS("Avatar") << "item_id " << item_id << llendl; - + LL_DEBUGS("Avatar") << "item_id " << item_id << LL_ENDL; if (!requestOperation(item_id)) { - LL_DEBUGS("Avatar") << "item_id " << item_id << " requestOperation false, skipping" << llendl; + LL_DEBUGS("Avatar") << "item_id " << item_id << " requestOperation false, skipping" << LL_ENDL; return; } @@ -242,20 +251,20 @@ class LLCallAfterInventoryBatchMgr: public LLEventTimer { if (ll_frand() < gSavedSettings.getF32("InventoryDebugSimulateLateOpRate")) { - llwarns << "Simulating late operation by punting handling to later" << llendl; + LL_WARNS() << "Simulating late operation by punting handling to later" << LL_ENDL; doAfterInterval(boost::bind(&LLCallAfterInventoryBatchMgr::onOp,this,src_id,dst_id,timestamp), mRetryAfter); return; } mPendingRequests--; F32 elapsed = timestamp.getElapsedTimeF32(); - LL_DEBUGS("Avatar") << "op done, src_id " << src_id << " dst_id " << dst_id << " after " << elapsed << " seconds" << llendl; + LL_DEBUGS("Avatar") << "op done, src_id " << src_id << " dst_id " << dst_id << " after " << elapsed << " seconds" << LL_ENDL; if (mWaitTimes.find(src_id) == mWaitTimes.end()) { // No longer waiting for this item - either serviced // already or gave up after too many retries. - llwarns << "duplicate or late operation, src_id " << src_id << "dst_id " << dst_id - << " elapsed " << elapsed << " after end " << (S32) mCompletionOrFailureCalled << llendl; + LL_WARNS() << "duplicate or late operation, src_id " << src_id << "dst_id " << dst_id + << " elapsed " << elapsed << " after end " << (S32) mCompletionOrFailureCalled << LL_ENDL; } mTimeStats.push(elapsed); mWaitTimes.erase(src_id); @@ -290,13 +299,13 @@ class LLCallAfterInventoryBatchMgr: public LLEventTimer void onFailure() { - llinfos << "failed" << llendl; + LL_INFOS() << "failed" << LL_ENDL; mOnFailureFunc(); } void onCompletion() { - llinfos << "done" << llendl; + LL_INFOS() << "done" << LL_ENDL; mOnCompletionFunc(); } @@ -315,7 +324,7 @@ class LLCallAfterInventoryBatchMgr: public LLEventTimer if (!mWaitTimes.empty()) { - llwarns << "still waiting on " << mWaitTimes.size() << " items" << llendl; + LL_WARNS() << "still waiting on " << mWaitTimes.size() << " items" << LL_ENDL; for (std::map::iterator it = mWaitTimes.begin(); it != mWaitTimes.end();) { @@ -330,13 +339,13 @@ class LLCallAfterInventoryBatchMgr: public LLEventTimer if (retries < mMaxRetries) { LL_DEBUGS("Avatar") << "Waited " << time_waited << - " for " << curr_it->first << ", retrying" << llendl; + " for " << curr_it->first << ", retrying" << LL_ENDL; mRetryCount++; addItem(curr_it->first); } else { - llwarns << "Giving up on " << curr_it->first << " after too many retries" << llendl; + LL_WARNS() << "Giving up on " << curr_it->first << " after too many retries" << LL_ENDL; mWaitTimes.erase(curr_it); mFailCount++; } @@ -353,16 +362,16 @@ class LLCallAfterInventoryBatchMgr: public LLEventTimer void reportStats() { - LL_DEBUGS("Avatar") << "Phase: " << mTrackingPhase << llendl; - LL_DEBUGS("Avatar") << "mFailCount: " << mFailCount << llendl; - LL_DEBUGS("Avatar") << "mRetryCount: " << mRetryCount << llendl; - LL_DEBUGS("Avatar") << "Times: n " << mTimeStats.getCount() << " min " << mTimeStats.getMinValue() << " max " << mTimeStats.getMaxValue() << llendl; - LL_DEBUGS("Avatar") << "Mean " << mTimeStats.getMean() << " stddev " << mTimeStats.getStdDev() << llendl; + LL_DEBUGS("Avatar") << "Phase: " << mTrackingPhase << LL_ENDL; + LL_DEBUGS("Avatar") << "mFailCount: " << mFailCount << LL_ENDL; + LL_DEBUGS("Avatar") << "mRetryCount: " << mRetryCount << LL_ENDL; + LL_DEBUGS("Avatar") << "Times: n " << mTimeStats.getCount() << " min " << mTimeStats.getMinValue() << " max " << mTimeStats.getMaxValue() << LL_ENDL; + LL_DEBUGS("Avatar") << "Mean " << mTimeStats.getMean() << " stddev " << mTimeStats.getStdDev() << LL_ENDL; } virtual ~LLCallAfterInventoryBatchMgr() { - LL_DEBUGS("Avatar") << "deleting" << llendl; + LL_DEBUGS("Avatar") << "deleting" << LL_ENDL; } protected: @@ -395,16 +404,22 @@ class LLCallAfterInventoryCopyMgr: public LLCallAfterInventoryBatchMgr LLCallAfterInventoryBatchMgr(dst_cat_id, phase_name, on_completion_func, on_failure_func, retry_after, max_retries) { addItems(src_items); + sInstanceCount++; + } + + ~LLCallAfterInventoryCopyMgr() + { + sInstanceCount--; } virtual bool requestOperation(const LLUUID& item_id) { LLViewerInventoryItem *item = gInventory.getItem(item_id); llassert(item); - LL_DEBUGS("Avatar") << "copying item " << item_id << llendl; + LL_DEBUGS("Avatar") << "copying item " << item_id << LL_ENDL; if (ll_frand() < gSavedSettings.getF32("InventoryDebugSimulateOpFailureRate")) { - LL_DEBUGS("Avatar") << "simulating failure by not sending request for item " << item_id << llendl; + LL_DEBUGS("Avatar") << "simulating failure by not sending request for item " << item_id << LL_ENDL; return true; } copy_inventory_item( @@ -417,97 +432,90 @@ class LLCallAfterInventoryCopyMgr: public LLCallAfterInventoryBatchMgr ); return true; } + + static S32 getInstanceCount() { return sInstanceCount; } + +private: + static S32 sInstanceCount; }; -class LLCallAfterInventoryLinkMgr: public LLCallAfterInventoryBatchMgr +S32 LLCallAfterInventoryCopyMgr::sInstanceCount = 0; + +class LLWearCategoryAfterCopy: public LLInventoryCallback { public: - LLCallAfterInventoryLinkMgr(LLInventoryModel::item_array_t& src_items, - const LLUUID& dst_cat_id, - const std::string& phase_name, - nullary_func_t on_completion_func, - nullary_func_t on_failure_func = no_op, - F32 retry_after = DEFAULT_RETRY_AFTER_INTERVAL, - S32 max_retries = DEFAULT_MAX_RETRIES - ): - LLCallAfterInventoryBatchMgr(dst_cat_id, phase_name, on_completion_func, on_failure_func, retry_after, max_retries) + LLWearCategoryAfterCopy(bool append): + mAppend(append) + {} + + // virtual + void fire(const LLUUID& id) { - addItems(src_items); + // Wear the inventory category. + LLInventoryCategory* cat = gInventory.getCategory(id); + LLAppearanceMgr::instance().wearInventoryCategoryOnAvatar(cat, mAppend); } - - virtual bool requestOperation(const LLUUID& item_id) + +private: + bool mAppend; +}; + +class LLTrackPhaseWrapper : public LLInventoryCallback +{ +public: + LLTrackPhaseWrapper(const std::string& phase_name, LLPointer cb = nullptr): + mTrackingPhase(phase_name), + mCB(cb) { - bool request_sent = false; - LLViewerInventoryItem *item = gInventory.getItem(item_id); - if (item) + selfStartPhase(mTrackingPhase); + } + + // virtual + void fire(const LLUUID& id) + { + if (mCB) { - if (item->getParentUUID() == mDstCatID) - { - LL_DEBUGS("Avatar") << "item " << item_id << " name " << item->getName() << " is already a child of " << mDstCatID << llendl; - return false; - } - LL_DEBUGS("Avatar") << "linking item " << item_id << " name " << item->getName() << " to " << mDstCatID << llendl; - // create an inventory item link. - if (ll_frand() < gSavedSettings.getF32("InventoryDebugSimulateOpFailureRate")) - { - LL_DEBUGS("Avatar") << "simulating failure by not sending request for item " << item_id << llendl; - return true; - } - link_inventory_item(gAgent.getID(), - item->getLinkedUUID(), - mDstCatID, - item->getName(), - item->getActualDescription(), - LLAssetType::AT_LINK, - new LLBoostFuncInventoryCallback( - boost::bind(&LLCallAfterInventoryBatchMgr::onOp,this,item_id,_1,LLTimer()))); - return true; + mCB->fire(id); } - else - { - // create a base outfit link if appropriate. - LLViewerInventoryCategory *catp = gInventory.getCategory(item_id); - if (!catp) - { - llwarns << "link request failed, id not found as inventory item or category " << item_id << llendl; - return false; - } - const LLUUID cof = LLAppearanceMgr::instance().getCOF(); - std::string new_outfit_name = ""; - - LLAppearanceMgr::instance().purgeBaseOutfitLink(cof); + } - if (catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT) - { - if (ll_frand() < gSavedSettings.getF32("InventoryDebugSimulateOpFailureRate")) - { - LL_DEBUGS("Avatar") << "simulating failure by not sending request for item " << item_id << llendl; - return true; - } - LL_DEBUGS("Avatar") << "linking folder " << item_id << " name " << catp->getName() << " to cof " << cof << llendl; - link_inventory_item(gAgent.getID(), item_id, cof, catp->getName(), "", - LLAssetType::AT_LINK_FOLDER, - new LLBoostFuncInventoryCallback( - boost::bind(&LLCallAfterInventoryBatchMgr::onOp,this,item_id,_1,LLTimer()))); - new_outfit_name = catp->getName(); - request_sent = true; - } - - LLAppearanceMgr::instance().updatePanelOutfitName(new_outfit_name); - } - return request_sent; + // virtual + ~LLTrackPhaseWrapper() + { + selfStopPhase(mTrackingPhase); } + +protected: + std::string mTrackingPhase; + LLPointer mCB; }; -LLUpdateAppearanceOnDestroy::LLUpdateAppearanceOnDestroy(bool update_base_outfit_ordering): +LLUpdateAppearanceOnDestroy::LLUpdateAppearanceOnDestroy(bool enforce_item_restrictions, + bool enforce_ordering, + nullary_func_t post_update_func + ): mFireCount(0), - mUpdateBaseOrder(update_base_outfit_ordering) + mEnforceItemRestrictions(enforce_item_restrictions), + mEnforceOrdering(enforce_ordering), + mPostUpdateFunc(post_update_func) { + sActiveCallbacks++; selfStartPhase("update_appearance_on_destroy"); } +void LLUpdateAppearanceOnDestroy::fire(const LLUUID& inv_item) +{ + LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(inv_item); + const std::string item_name = item ? item->getName() : "ITEM NOT FOUND"; +#ifndef LL_RELEASE_FOR_DOWNLOAD + LL_DEBUGS("Avatar") << self_av_string() << "callback fired [ name:" << item_name << " UUID:" << inv_item << " count:" << mFireCount << " ] " << LL_ENDL; +#endif + mFireCount++; +} + LLUpdateAppearanceOnDestroy::~LLUpdateAppearanceOnDestroy() { + --sActiveCallbacks; if (!LLApp::isExiting()) { // speculative fix for MAINT-1150 @@ -515,20 +523,52 @@ LLUpdateAppearanceOnDestroy::~LLUpdateAppearanceOnDestroy() selfStopPhase("update_appearance_on_destroy"); - LLAppearanceMgr::instance().updateAppearanceFromCOF(mUpdateBaseOrder); + LLAppearanceMgr::instance().updateAppearanceFromCOF(mEnforceItemRestrictions, + mEnforceOrdering, + mPostUpdateFunc); } } -void LLUpdateAppearanceOnDestroy::fire(const LLUUID& inv_item) +U32 LLUpdateAppearanceOnDestroy::sActiveCallbacks = 0; + +LLUpdateAppearanceAndEditWearableOnDestroy::LLUpdateAppearanceAndEditWearableOnDestroy(const LLUUID& item_id): + mItemID(item_id) { - LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(inv_item); - const std::string item_name = item ? item->getName() : "ITEM NOT FOUND"; -#ifndef LL_RELEASE_FOR_DOWNLOAD - LL_DEBUGS("Avatar") << self_av_string() << "callback fired [ name:" << item_name << " UUID:" << inv_item << " count:" << mFireCount << " ] " << LL_ENDL; -#endif - mFireCount++; } +LLRequestServerAppearanceUpdateOnDestroy::~LLRequestServerAppearanceUpdateOnDestroy() +{ + LL_DEBUGS("Avatar") << "ATT requesting server appearance update" << LL_ENDL; + if (!LLApp::isExiting()) + { + LLAppearanceMgr::instance().requestServerAppearanceUpdate(); + } +} + +void edit_wearable_and_customize_avatar(LLUUID item_id) +{ + // Start editing the item if previously requested. + gAgentWearables.editWearableIfRequested(item_id); + + // TODO: camera mode may not be changed if a debug setting is tweaked + if( LLFloaterCustomize::instanceExists() ) + { + // If we're in appearance editing mode, the current tab may need to be refreshed + LLFloaterCustomize::getInstance()->switchToDefaultSubpart(); + } +} + +LLUpdateAppearanceAndEditWearableOnDestroy::~LLUpdateAppearanceAndEditWearableOnDestroy() +{ + if (!LLApp::isExiting()) + { + LLAppearanceMgr::instance().updateAppearanceFromCOF( + true,true, + boost::bind(edit_wearable_and_customize_avatar, mItemID)); + } +} + + struct LLFoundData { LLFoundData() : @@ -578,12 +618,12 @@ class LLWearableHoldingPattern bool pollMissingWearables(); bool isMissingCompleted(); void recoverMissingWearable(LLWearableType::EType type); - void clearCOFLinksForMissingWearables(); +// void clearCOFLinksForMissingWearables(); void onWearableAssetFetch(LLViewerWearable *wearable); void onAllComplete(); -// [SL:KB] - Patch: Appearance-COFCorruption | Checked: 2010-04-14 (Catznip-3.0.0a) | Added: Catznip-2.0.0a +// [SL:KB] - Patch: Appearance-COFCorruption | Checked: 2010-04-14 (Catznip-2.0) bool pollStopped(); // [/SL:KB] @@ -596,6 +636,8 @@ class LLWearableHoldingPattern bool isMostRecent(); void handleLateArrivals(); void resetTime(F32 timeout); + static S32 countActive() { return sActiveHoldingPatterns.size(); } + S32 index() { return mIndex; } private: found_list_t mFoundList; @@ -609,12 +651,15 @@ class LLWearableHoldingPattern bool mFired; typedef std::set type_set_hp; static type_set_hp sActiveHoldingPatterns; + static S32 sNextIndex; + S32 mIndex; bool mIsMostRecent; std::set mLateArrivals; bool mIsAllComplete; }; LLWearableHoldingPattern::type_set_hp LLWearableHoldingPattern::sActiveHoldingPatterns; +S32 LLWearableHoldingPattern::sNextIndex = 0; LLWearableHoldingPattern::LLWearableHoldingPattern(): mResolved(0), @@ -622,13 +667,13 @@ LLWearableHoldingPattern::LLWearableHoldingPattern(): mIsMostRecent(true), mIsAllComplete(false) { - if (sActiveHoldingPatterns.size()>0) + if (countActive()>0) { - llinfos << "Creating LLWearableHoldingPattern when " - << sActiveHoldingPatterns.size() - << " other attempts are active." - << " Flagging others as invalid." - << llendl; + LL_INFOS() << "Creating LLWearableHoldingPattern when " + << countActive() + << " other attempts are active." + << " Flagging others as invalid." + << LL_ENDL; for (type_set_hp::iterator it = sActiveHoldingPatterns.begin(); it != sActiveHoldingPatterns.end(); ++it) @@ -637,8 +682,10 @@ LLWearableHoldingPattern::LLWearableHoldingPattern(): } } + mIndex = sNextIndex++; sActiveHoldingPatterns.insert(this); - //selfStartPhase("holding_pattern"); + LL_DEBUGS("Avatar") << "HP " << index() << " created" << LL_ENDL; + selfStartPhase("holding_pattern"); } LLWearableHoldingPattern::~LLWearableHoldingPattern() @@ -648,6 +695,7 @@ LLWearableHoldingPattern::~LLWearableHoldingPattern() { selfStopPhase("holding_pattern"); } + LL_DEBUGS("Avatar") << "HP " << index() << " deleted" << LL_ENDL; } bool LLWearableHoldingPattern::isMostRecent() @@ -670,7 +718,7 @@ void LLWearableHoldingPattern::eraseTypeToRecover(LLWearableType::EType type) mTypesToRecover.erase(type); } -// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2010-06-19 (Catznip-3.0.0a) | Added: Catznip-2.1.2a +// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2010-06-19 (Catznip-2.1) //void LLWearableHoldingPattern::setObjItems(const LLInventoryModel::item_array_t& items) //{ // mObjItems = items; @@ -696,7 +744,7 @@ void LLWearableHoldingPattern::checkMissingWearables() if (!isMostRecent()) { // runway why don't we actually skip here? - llwarns << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; + LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; } std::vector found_by_type(LLWearableType::WT_COUNT,0); @@ -714,7 +762,7 @@ void LLWearableHoldingPattern::checkMissingWearables() { if (requested_by_type[type] > found_by_type[type]) { - llwarns << self_av_string() << "got fewer wearables than requested, type " << type << ": requested " << requested_by_type[type] << ", found " << found_by_type[type] << llendl; + LL_WARNS() << self_av_string() << "got fewer wearables than requested, type " << type << ": requested " << requested_by_type[type] << ", found " << found_by_type[type] << LL_ENDL; } if (found_by_type[type] > 0) continue; @@ -731,13 +779,16 @@ void LLWearableHoldingPattern::checkMissingWearables() mTypesToRecover.insert(type); mTypesToLink.insert(type); recoverMissingWearable((LLWearableType::EType)type); - llwarns << self_av_string() << "need to replace " << type << llendl; + LL_WARNS() << self_av_string() << "need to replace " << type << LL_ENDL; } } resetTime(60.0F); - selfStartPhase("get_missing_wearables"); + if (isMostRecent()) + { + selfStartPhase("get_missing_wearables_2"); + } if (!pollMissingWearables()) { doOnIdleRepeating(boost::bind(&LLWearableHoldingPattern::pollMissingWearables,this)); @@ -754,13 +805,13 @@ void LLWearableHoldingPattern::onAllComplete() if (!isMostRecent()) { // runway need to skip here? - llwarns << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; + LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; } // Activate all gestures in this folder - if (mGestItems.count() > 0) + if (mGestItems.size() > 0) { - LL_DEBUGS("Avatar") << self_av_string() << "Activating " << mGestItems.count() << " gestures" << LL_ENDL; + LL_DEBUGS("Avatar") << self_av_string() << "Activating " << mGestItems.size() << " gestures" << LL_ENDL; LLGestureMgr::instance().activateGestures(mGestItems); @@ -776,17 +827,55 @@ void LLWearableHoldingPattern::onAllComplete() } } - // Update wearables. - LL_INFOS("Avatar") << self_av_string() << "Updating agent wearables with " << mResolved << " wearable items " << LL_ENDL; - LLAppearanceMgr::instance().updateAgentWearables(this, false); - -// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2010-03-22 (Catznip-3.0.0a) | Added: Catznip-2.1.2a -// // Update attachments to match those requested. -// if (isAgentAvatarValid()) -// { -// llinfos << "Updating " << mObjItems.count() << " attachments" << llendl; -// LLAgentWearables::userUpdateAttachments(mObjItems); -// } + if (isAgentAvatarValid()) + { +// LL_DEBUGS("Avatar") << self_av_string() << "Updating " << mObjItems.size() << " attachments" << LL_ENDL; +// LLAgentWearables::llvo_vec_t objects_to_remove; +// LLAgentWearables::llvo_vec_t objects_to_retain; +// LLInventoryModel::item_array_t items_to_add; +// +// LLAgentWearables::findAttachmentsAddRemoveInfo(mObjItems, +// objects_to_remove, +// objects_to_retain, +// items_to_add); +// +// LL_DEBUGS("Avatar") << self_av_string() << "Removing " << objects_to_remove.size() +// << " attachments" << LL_ENDL; +// +// // Here we remove the attachment pos overrides for *all* +// // attachments, even those that are not being removed. This is +// // needed to get joint positions all slammed down to their +// // pre-attachment states. +// gAgentAvatarp->clearAttachmentPosOverrides(); +// +// if (objects_to_remove.size() || items_to_add.size()) +// { +// LL_DEBUGS("Avatar") << "ATT will remove " << objects_to_remove.size() +// << " and add " << items_to_add.size() << " items" << LL_ENDL; +// } +// +// // Take off the attachments that will no longer be in the outfit. +// LLAgentWearables::userRemoveMultipleAttachments(objects_to_remove); + + // Update wearables. + LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " updating agent wearables with " + << mResolved << " wearable items " << LL_ENDL; + LLAppearanceMgr::instance().updateAgentWearables(this); + + // Restore attachment pos overrides for the attachments that + // are remaining in the outfit. +// for (LLAgentWearables::llvo_vec_t::iterator it = objects_to_retain.begin(); +// it != objects_to_retain.end(); +// ++it) +// { +// LLViewerObject *objectp = *it; +// gAgentAvatarp->addAttachmentPosOverridesForObject(objectp); +// } + +// // Add new attachments to match those requested. +// LL_DEBUGS("Avatar") << self_av_string() << "Adding " << items_to_add.size() << " attachments" << LL_ENDL; +// LLAgentWearables::userAttachMultipleAttachments(items_to_add); + } if (isFetchCompleted() && isMissingCompleted()) { @@ -802,12 +891,15 @@ void LLWearableHoldingPattern::onAllComplete() void LLWearableHoldingPattern::onFetchCompletion() { - selfStopPhase("get_wearables"); + if (isMostRecent()) + { + selfStopPhase("get_wearables_2"); + } if (!isMostRecent()) { // runway skip here? - llwarns << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; + LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; } checkMissingWearables(); @@ -819,9 +911,9 @@ bool LLWearableHoldingPattern::pollFetchCompletion() if (!isMostRecent()) { // runway skip here? - llwarns << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; + LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; -// [SL:KB] - Patch: Appearance-COFCorruption | Checked: 2010-04-14 (Catznip-3.0.0a) | Added: Catznip-2.0.0a +// [SL:KB] - Patch: Appearance-COFCorruption | Checked: 2010-04-14 (Catznip-2.0) // If we were signalled to stop then we shouldn't do anything else except poll for when it's safe to delete ourselves doOnIdleRepeating(boost::bind(&LLWearableHoldingPattern::pollStopped, this)); return true; @@ -834,14 +926,14 @@ bool LLWearableHoldingPattern::pollFetchCompletion() if (done) { - LL_INFOS("Avatar") << self_av_string() << "polling, done status: " << completed << " timed out " << timed_out + LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " polling, done status: " << completed << " timed out " << timed_out << " elapsed " << mWaitTime.getElapsedTimeF32() << LL_ENDL; mFired = true; if (timed_out) { - llwarns << self_av_string() << "Exceeded max wait time for wearables, updating appearance based on what has arrived" << llendl; + LL_WARNS() << self_av_string() << "Exceeded max wait time for wearables, updating appearance based on what has arrived" << LL_ENDL; } onFetchCompletion(); @@ -853,11 +945,11 @@ void recovered_item_link_cb(const LLUUID& item_id, LLWearableType::EType type, L { if (!holder->isMostRecent()) { - llwarns << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; + LL_WARNS() << "HP " << holder->index() << " skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; // runway skip here? } - llinfos << "Recovered item link for type " << type << llendl; + LL_INFOS() << "HP " << holder->index() << " recovered item link for type " << type << LL_ENDL; holder->eraseTypeToLink(type); // Add wearable to FoundData for actual wearing LLViewerInventoryItem *item = gInventory.getItem(item_id); @@ -881,12 +973,12 @@ void recovered_item_link_cb(const LLUUID& item_id, LLWearableType::EType type, L } else { - llwarns << self_av_string() << "inventory item not found for recovered wearable" << llendl; + LL_WARNS() << self_av_string() << "inventory link not found for recovered wearable" << LL_ENDL; } } else { - llwarns << self_av_string() << "inventory link not found for recovered wearable" << llendl; + LL_WARNS() << self_av_string() << "HP " << holder->index() << " inventory link not found for recovered wearable" << LL_ENDL; } } @@ -895,29 +987,24 @@ void recovered_item_cb(const LLUUID& item_id, LLWearableType::EType type, LLView if (!holder->isMostRecent()) { // runway skip here? - llwarns << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; + LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; -// [SL:KB] - Patch: Appearance-COFCorruption | Checked: 2010-04-14 (Catznip-3.0.0a) | Added: Catznip-2.0.0a +// [SL:KB] - Patch: Appearance-COFCorruption | Checked: 2010-04-14 (Catznip-2.0) // If we were signalled to stop then we shouldn't do anything else except poll for when it's safe to delete ourselves return; // [/SL:KB] } LL_DEBUGS("Avatar") << self_av_string() << "Recovered item for type " << type << LL_ENDL; - LLViewerInventoryItem *itemp = gInventory.getItem(item_id); + LLConstPointer itemp = gInventory.getItem(item_id); wearable->setItemID(item_id); - LLPointer cb = new LLBoostFuncInventoryCallback(boost::bind(recovered_item_link_cb,_1,type,wearable,holder)); holder->eraseTypeToRecover(type); llassert(itemp); if (itemp) { - link_inventory_item( gAgent.getID(), - item_id, - LLAppearanceMgr::instance().getCOF(), - itemp->getName(), - itemp->getDescription(), - LLAssetType::AT_LINK, - cb); + LLPointer cb = new LLBoostFuncInventoryCallback(boost::bind(recovered_item_link_cb,_1,type,wearable,holder)); + + link_inventory_object(LLAppearanceMgr::instance().getCOF(), itemp, cb); } } @@ -926,13 +1013,13 @@ void LLWearableHoldingPattern::recoverMissingWearable(LLWearableType::EType type if (!isMostRecent()) { // runway skip here? - llwarns << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; + LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; } // Try to recover by replacing missing wearable with a new one. LLNotificationsUtil::add("ReplacedMissingWearable"); - lldebugs << "Wearable " << LLWearableType::getTypeLabel(type) - << " could not be downloaded. Replaced inventory item with default wearable." << llendl; + LL_DEBUGS() << "Wearable " << LLWearableType::getTypeLabel(type) + << " could not be downloaded. Replaced inventory item with default wearable." << LL_ENDL; LLViewerWearable* wearable = LLWearableList::instance().createNewWearable(type, gAgentAvatarp); // Add a new one in the lost and found folder. @@ -957,21 +1044,21 @@ bool LLWearableHoldingPattern::isMissingCompleted() return mTypesToLink.size()==0 && mTypesToRecover.size()==0; } -void LLWearableHoldingPattern::clearCOFLinksForMissingWearables() -{ - for (found_list_t::iterator it = getFoundList().begin(); it != getFoundList().end(); ++it) - { - LLFoundData &data = *it; - if ((data.mWearableType < LLWearableType::WT_COUNT) && (!data.mWearable)) - { - // Wearable link that was never resolved; remove links to it from COF - LL_INFOS("Avatar") << self_av_string() << "removing link for unresolved item " << data.mItemID.asString() << LL_ENDL; - LLAppearanceMgr::instance().removeCOFItemLinks(data.mItemID); - } - } -} +//void LLWearableHoldingPattern::clearCOFLinksForMissingWearables() +//{ +// for (found_list_t::iterator it = getFoundList().begin(); it != getFoundList().end(); ++it) +// { +// LLFoundData &data = *it; +// if ((data.mWearableType < LLWearableType::WT_COUNT) && (!data.mWearable)) +// { +// // Wearable link that was never resolved; remove links to it from COF +// LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " removing link for unresolved item " << data.mItemID.asString() << LL_ENDL; +// LLAppearanceMgr::instance().removeCOFItemLinks(data.mItemID); +// } +// } +//} -// [SL:KB] - Patch: Appearance-COFCorruption | Checked: 2010-04-14 (Catznip-3.0.0a) | Added: Catznip-2.0.0a +// [SL:KB] - Patch: Appearance-COFCorruption | Checked: 2010-04-14 (Catznip-2.0) bool LLWearableHoldingPattern::pollStopped() { // We have to keep on polling until we're sure that all callbacks have completed or they'll cause a crash @@ -989,9 +1076,9 @@ bool LLWearableHoldingPattern::pollMissingWearables() if (!isMostRecent()) { // runway skip here? - llwarns << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; + LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; -// [SL:KB] - Patch: Appearance-COFCorruption | Checked: 2010-04-14 (Catznip-3.0.0a) | Added: Catznip-2.0.0a +// [SL:KB] - Patch: Appearance-COFCorruption | Checked: 2010-04-14 (Catznip-2.0) // If we were signalled to stop then we shouldn't do anything else except poll for when it's safe to delete ourselves doOnIdleRepeating(boost::bind(&LLWearableHoldingPattern::pollStopped, this)); return true; @@ -1004,7 +1091,7 @@ bool LLWearableHoldingPattern::pollMissingWearables() if (!done) { - LL_INFOS("Avatar") << self_av_string() << "polling missing wearables, waiting for items " << mTypesToRecover.size() + LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " polling missing wearables, waiting for items " << mTypesToRecover.size() << " links " << mTypesToLink.size() << " wearables, timed out " << timed_out << " elapsed " << mWaitTime.getElapsedTimeF32() @@ -1013,7 +1100,10 @@ bool LLWearableHoldingPattern::pollMissingWearables() if (done) { - selfStopPhase("get_missing_wearables"); + if (isMostRecent()) + { + selfStopPhase("get_missing_wearables_2"); + } gAgentAvatarp->debugWearablesLoaded(); @@ -1044,14 +1134,14 @@ void LLWearableHoldingPattern::handleLateArrivals() } if (!isMostRecent()) { - llwarns << self_av_string() << "Late arrivals not handled - outfit change no longer valid" << llendl; + LL_WARNS() << self_av_string() << "Late arrivals not handled - outfit change no longer valid" << LL_ENDL; } if (!mIsAllComplete) { - llwarns << self_av_string() << "Late arrivals not handled - in middle of missing wearables processing" << llendl; + LL_WARNS() << self_av_string() << "Late arrivals not handled - in middle of missing wearables processing" << LL_ENDL; } - LL_INFOS("Avatar") << self_av_string() << "Need to handle " << mLateArrivals.size() << " late arriving wearables" << LL_ENDL; + LL_INFOS("Avatar") << self_av_string() << "HP " << index() << " need to handle " << mLateArrivals.size() << " late arriving wearables" << LL_ENDL; // Update mFoundList using late-arriving wearables. std::set replaced_types; @@ -1114,7 +1204,7 @@ void LLWearableHoldingPattern::handleLateArrivals() mLateArrivals.clear(); // Update appearance based on mFoundList - LLAppearanceMgr::instance().updateAgentWearables(this, false); + LLAppearanceMgr::instance().updateAgentWearables(this); } void LLWearableHoldingPattern::resetTime(F32 timeout) @@ -1127,19 +1217,19 @@ void LLWearableHoldingPattern::onWearableAssetFetch(LLViewerWearable *wearable) { if (!isMostRecent()) { - llwarns << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; + LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; } mResolved += 1; // just counting callbacks, not successes. - LL_DEBUGS("Avatar") << self_av_string() << "resolved " << mResolved << "/" << getFoundList().size() << LL_ENDL; + LL_DEBUGS("Avatar") << self_av_string() << "HP " << index() << " resolved " << mResolved << "/" << getFoundList().size() << LL_ENDL; if (!wearable) { - llwarns << self_av_string() << "no wearable found" << llendl; + LL_WARNS() << self_av_string() << "no wearable found" << LL_ENDL; } if (mFired) { - llwarns << self_av_string() << "called after holder fired" << llendl; + LL_WARNS() << self_av_string() << "called after holder fired" << LL_ENDL; if (wearable) { mLateArrivals.insert(wearable); @@ -1163,13 +1253,14 @@ void LLWearableHoldingPattern::onWearableAssetFetch(LLViewerWearable *wearable) if(wearable->getAssetID() == data.mAssetID) { // Failing this means inventory or asset server are corrupted in a way we don't handle. + // Singu Note: This code conflict exists because we correct corrupted clothing items to their correct wearable type. if (data.mWearableType >= LLWearableType::WT_COUNT || wearable->getType() >= LLWearableType::WT_UNKNOWN || (data.mWearableType != wearable->getType() && data.mWearableType != LLWearableType::WT_UNKNOWN && data.mWearableType != LLWearableType::WT_SHAPE)) { - llwarns << self_av_string() << "recovered wearable but type invalid. inventory wearable type: " << data.mWearableType << " asset wearable type: " << wearable->getType() << llendl; + LL_WARNS() << self_av_string() << "recovered wearable but type invalid. inventory wearable type: " << data.mWearableType << " asset wearable type: " << wearable->getType() << LL_ENDL; break; } else if (data.mWearableType == LLWearableType::WT_UNKNOWN || @@ -1178,25 +1269,26 @@ void LLWearableHoldingPattern::onWearableAssetFetch(LLViewerWearable *wearable) { if (data.mWearableType == LLWearableType::WT_UNKNOWN) { - llinfos << "Wearing wearable '" << wearable->getName() << "' with an unknown inventory wearable type. Fixing inventory to have type " << wearable->getType() << llendl; + LL_INFOS() << "Wearing wearable '" << wearable->getName() << "' with an unknown inventory wearable type. Fixing inventory to have type " << wearable->getType() << LL_ENDL; } else { // This probably means that the inventory contains an item without wearable type information. // We can still fix the type here, but we also have to fix that in the mean time we took off our real shape because of this! - llwarns << "Wearing wearable '" << wearable->getName() << "' with incorrect wearable type 'shape'! Trying to recover from this..." << llendl; + LL_WARNS() << "Wearing wearable '" << wearable->getName() << "' with incorrect wearable type 'shape'! Trying to recover from this..." << LL_ENDL; } // Fix it! data.mWearableType = wearable->getType(); LLViewerInventoryItem* item = gInventory.getItem(data.mItemID); if (!item) { - llwarns << "Can't find the broken item in the inventory?!" << llendl; + LL_WARNS() << "Can't find the broken item in the inventory?!" << LL_ENDL; break; } llassert(item->getUUID() == data.mItemID); item->setWearableType(wearable->getType()); gInventory.updateItem(item); + gInventory.notifyObservers(); } data.mWearable = wearable; @@ -1214,15 +1306,15 @@ static void onWearableAssetFetch(LLViewerWearable* wearable, void* data) static void removeDuplicateItems(LLInventoryModel::item_array_t& items) { LLInventoryModel::item_array_t new_items; - std::set items_seen; + uuid_set_t items_seen; std::deque tmp_list; // Traverse from the front and keep the first of each item // encountered, so we actually keep the *last* of each duplicate // item. This is needed to give the right priority when adding // duplicate items to an existing outfit. - for (S32 i=items.count()-1; i>=0; i--) + for (S32 i=items.size()-1; i>=0; i--) { - LLViewerInventoryItem *item = items.get(i); + LLViewerInventoryItem *item = items.at(i); LLUUID item_id = item->getLinkedUUID(); if (items_seen.find(item_id)!=items_seen.end()) continue; @@ -1233,25 +1325,29 @@ static void removeDuplicateItems(LLInventoryModel::item_array_t& items) it != tmp_list.end(); ++it) { - new_items.put(*it); + new_items.push_back(*it); } items = new_items; } -// [SL:KB] - Patch: Appearance-WearableDuplicateAssets | Checked: 2011-07-24 (Catznip-2.6.0e) | Added: Catznip-2.6.0e +//========================================================================= + +// [SL:KB] - Patch: Appearance-WearableDuplicateAssets | Checked: 2015-06-30 (Catznip-3.7) static void removeDuplicateWearableItemsByAssetID(LLInventoryModel::item_array_t& items) { - std::set idsAsset; - for (S32 idxItem = items.count() - 1; idxItem >= 0; idxItem--) - { - const LLViewerInventoryItem* pItem = items.get(idxItem); - if (!pItem->isWearableType()) - continue; - if (idsAsset.end() == idsAsset.find(pItem->getAssetUUID())) - idsAsset.insert(pItem->getAssetUUID()); - else - items.remove(idxItem); - } + uuid_set_t idsAsset; + items.erase(std::remove_if(items.begin(), items.end(), + [&idsAsset](const LLViewerInventoryItem* pItem) + { + if (pItem->isWearableType()) + { + const LLUUID& idAsset = pItem->getAssetUUID(); + if ( (idAsset.notNull()) && (idsAsset.end() != idsAsset.find(idAsset)) ) + return true; + idsAsset.insert(idAsset); + } + return false; + }), items.end()); } // [/SL:KB] @@ -1273,21 +1369,6 @@ S32 LLAppearanceMgr::getCOFVersion() const } } -S32 LLAppearanceMgr::getLastUpdateRequestCOFVersion() const -{ - return mLastUpdateRequestCOFVersion; -} - -S32 LLAppearanceMgr::getLastAppearanceUpdateCOFVersion() const -{ - return mLastAppearanceUpdateCOFVersion; -} - -void LLAppearanceMgr::setLastAppearanceUpdateCOFVersion(S32 new_val) -{ - mLastAppearanceUpdateCOFVersion = new_val; -} - const LLViewerInventoryItem* LLAppearanceMgr::getBaseOutfitLink() { const LLUUID& current_outfit_cat = getCOF(); @@ -1300,8 +1381,7 @@ const LLViewerInventoryItem* LLAppearanceMgr::getBaseOutfitLink() cat_array, item_array, false, - is_category, - false); + is_category); for (LLInventoryModel::item_array_t::const_iterator iter = item_array.begin(); iter != item_array.end(); iter++) @@ -1348,14 +1428,14 @@ const LLUUID LLAppearanceMgr::getBaseOutfitUUID() if (outfit_cat->getPreferredType() != LLFolderType::FT_OUTFIT) { - llwarns << "Expected outfit type:" << LLFolderType::FT_OUTFIT << " but got type:" << outfit_cat->getType() << " for folder name:" << outfit_cat->getName() << llendl; + LL_WARNS() << "Expected outfit type:" << LLFolderType::FT_OUTFIT << " but got type:" << outfit_cat->getType() << " for folder name:" << outfit_cat->getName() << LL_ENDL; return LLUUID::null; } return outfit_cat->getUUID(); } -void wear_on_avatar_cb(const LLUUID& inv_item, bool do_replace/*= false*/) +void wear_on_avatar_cb(const LLUUID& inv_item, bool do_replace /*= false*/) { if (inv_item.isNull()) return; @@ -1367,81 +1447,152 @@ void wear_on_avatar_cb(const LLUUID& inv_item, bool do_replace/*= false*/) } } -bool LLAppearanceMgr::wearItemOnAvatar(const LLUUID& item_id_to_wear, bool do_update, bool replace, LLPointer cb) -{ - if (item_id_to_wear.isNull()) return false; - - // *TODO: issue with multi-wearable should be fixed: - // in this case this method will be called N times - loading started for each item - // and than N times will be called - loading completed for each item. - // That means subscribers will be notified that loading is done after first item in a batch is worn. - // (loading indicator disappears for example before all selected items are worn) - // Have not fix this issue for 2.1 because of stability reason. EXT-7777. - - // Disabled for now because it is *not* acceptable to call updateAppearanceFromCOF() multiple times -// gAgentWearables.notifyLoadingStarted(); - - LLViewerInventoryItem* item_to_wear = gInventory.getItem(item_id_to_wear); - if (!item_to_wear) return false; - - if (gInventory.isObjectDescendentOf(item_to_wear->getUUID(), gInventory.getLibraryRootFolderID())) - { - LLPointer cb = new LLBoostFuncInventoryCallback(boost::bind(&wear_on_avatar_cb,_1,replace)); - copy_inventory_item(gAgent.getID(), item_to_wear->getPermissions().getOwner(), item_to_wear->getUUID(), LLUUID::null, std::string(), cb); - return false; - } - else if (!gInventory.isObjectDescendentOf(item_to_wear->getUUID(), gInventory.getRootFolderID())) - { - return false; // not in library and not in agent's inventory - } - else if (gInventory.isObjectDescendentOf(item_to_wear->getUUID(), gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH))) - { - LLNotificationsUtil::add("CannotWearTrash"); - return false; - } - else if (gInventory.isObjectDescendentOf(item_to_wear->getUUID(), LLAppearanceMgr::instance().getCOF())) // EXT-84911 - { - return false; - } +void LLAppearanceMgr::wearItemsOnAvatar(const uuid_vec_t& item_ids_to_wear, + bool do_update, + bool replace, + LLPointer cb) +{ + bool first = true; + + LLInventoryObject::const_object_list_t items_to_link; + + for (uuid_vec_t::const_iterator it = item_ids_to_wear.begin(); + it != item_ids_to_wear.end(); + ++it) + { + replace = first && replace; + first = false; + + const LLUUID& item_id_to_wear = *it; + + if (item_id_to_wear.isNull()) + { + LL_DEBUGS("Avatar") << "null id " << item_id_to_wear << LL_ENDL; + continue; + } + + LLViewerInventoryItem* item_to_wear = gInventory.getItem(item_id_to_wear); + if (!item_to_wear) + { + LL_DEBUGS("Avatar") << "inventory item not found for id " << item_id_to_wear << LL_ENDL; + continue; + } + + if (gInventory.isObjectDescendentOf(item_to_wear->getUUID(), gInventory.getLibraryRootFolderID())) + { + LL_DEBUGS("Avatar") << "inventory item in library, will copy and wear " + << item_to_wear->getName() << " id " << item_id_to_wear << LL_ENDL; + LLPointer cb = new LLBoostFuncInventoryCallback(boost::bind(wear_on_avatar_cb,_1,replace)); + copy_inventory_item(gAgent.getID(), item_to_wear->getPermissions().getOwner(), + item_to_wear->getUUID(), LLUUID::null, std::string(), cb); + continue; + } + else if (!gInventory.isObjectDescendentOf(item_to_wear->getUUID(), gInventory.getRootFolderID())) + { + // not in library and not in agent's inventory + LL_DEBUGS("Avatar") << "inventory item not in user inventory or library, skipping " + << item_to_wear->getName() << " id " << item_id_to_wear << LL_ENDL; + continue; + } + else if (gInventory.isObjectDescendentOf(item_to_wear->getUUID(), gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH))) + { + LLNotificationsUtil::add("CannotWearTrash"); + LL_DEBUGS("Avatar") << "inventory item is in trash, skipping " + << item_to_wear->getName() << " id " << item_id_to_wear << LL_ENDL; + continue; + } + else if (isLinkedInCOF(item_to_wear->getUUID())) // EXT-84911 + { + LL_DEBUGS("Avatar") << "inventory item is already in COF, skipping " + << item_to_wear->getName() << " id " << item_id_to_wear << LL_ENDL; + continue; + } + /* Singu TODO: Find out why this was here, it wasn't in any upstream so I've commented it out. ~Liru + else if (item_to_wear->isWearableType()) + { + LLViewerWearable* wearable = gAgentWearables.getWearableFromAssetID(item_to_wear->getAssetUUID()); + if (wearable && (!replace || wearable != gAgentWearables.getTopWearable(item_to_wear->getWearableType()))) + continue; + } + */ // [RLVa:KB] - Checked: 2013-02-12 (RLVa-1.4.8) - replace |= (LLAssetType::AT_BODYPART == item_to_wear->getType()); // Body parts should always replace - if ( (rlv_handler_t::isEnabled()) && (!rlvPredCanWearItem(item_to_wear, (replace) ? RLV_WEAR_REPLACE : RLV_WEAR_ADD)) ) - { - return false; - } -// [/RLVa:KB] - - switch (item_to_wear->getType()) - { - case LLAssetType::AT_CLOTHING: - if (gAgentWearables.areWearablesLoaded()) + replace |= (LLAssetType::AT_BODYPART == item_to_wear->getType()); // Body parts should always replace + if ( (rlv_handler_t::isEnabled()) && (!rlvPredCanWearItem(item_to_wear, (replace) ? RLV_WEAR_REPLACE : RLV_WEAR_ADD)) ) { - S32 wearable_count = gAgentWearables.getWearableCount(item_to_wear->getWearableType()); - if ((replace && wearable_count != 0) || - (wearable_count >= LLAgentWearables::MAX_CLOTHING_PER_TYPE) ) - { - removeCOFItemLinks(gAgentWearables.getWearableItemID(item_to_wear->getWearableType(), wearable_count-1)); - } - addCOFItemLink(item_to_wear, do_update, cb); - } - break; - case LLAssetType::AT_BODYPART: - // TODO: investigate wearables may not be loaded at this point EXT-8231 - - // Remove the existing wearables of the same type. - // Remove existing body parts anyway because we must not be able to wear e.g. two skins. - removeCOFLinksOfType(item_to_wear->getWearableType()); + continue; + } +// [/RLVa:KB] - addCOFItemLink(item_to_wear, do_update, cb); - break; - case LLAssetType::AT_OBJECT: - rez_attachment(item_to_wear, NULL, replace); - break; - default: return false;; - } + switch (item_to_wear->getType()) + { + case LLAssetType::AT_CLOTHING: + { + if (gAgentWearables.areWearablesLoaded()) + { + if (!cb && do_update) + { + cb = new LLUpdateAppearanceAndEditWearableOnDestroy(item_id_to_wear); + } + LLWearableType::EType type = item_to_wear->getWearableType(); + S32 wearable_count = gAgentWearables.getWearableCount(type); + if ((replace && wearable_count != 0) || !gAgentWearables.canAddWearable(type)) + { + LLUUID item_id = gAgentWearables.getWearableItemID(item_to_wear->getWearableType(), + wearable_count-1); +// [SL:KB] - Patch: Appearance-AISFilter | Checked: 2015-05-02 (Catznip-3.7) + removeCOFItemLinks(item_id, NULL, true); +// [/SL:KB] +// removeCOFItemLinks(item_id, cb); + } + + items_to_link.push_back(item_to_wear); + } + } + break; + + case LLAssetType::AT_BODYPART: + { + // TODO: investigate wearables may not be loaded at this point EXT-8231 + + // Remove the existing wearables of the same type. + // Remove existing body parts anyway because we must not be able to wear e.g. two skins. + removeCOFLinksOfType(item_to_wear->getWearableType()); + if (!cb && do_update) + { + cb = new LLUpdateAppearanceAndEditWearableOnDestroy(item_id_to_wear); + } + items_to_link.push_back(item_to_wear); + } + break; + + case LLAssetType::AT_OBJECT: + { + LL_DEBUGS("Avatar") << "ATT wearing object. calling rez_attachment, item " << item_to_wear->getName() + << " id " << item_to_wear->getLinkedUUID() << LL_ENDL; + rez_attachment(item_to_wear, NULL, replace); + } + break; + + default: continue; + } + } + + // Batch up COF link creation - more efficient if using AIS. + if (items_to_link.size()) + { + link_inventory_array(getCOF(), items_to_link, cb); + } +} - return true; +void LLAppearanceMgr::wearItemOnAvatar(const LLUUID& item_id_to_wear, + bool do_update, + bool replace, + LLPointer cb) +{ + uuid_vec_t ids; + ids.push_back(item_id_to_wear); + wearItemsOnAvatar(ids, do_update, replace, cb); } // Update appearance from outfit folder. @@ -1525,7 +1676,7 @@ void LLAppearanceMgr::takeOffOutfit(const LLUUID& cat_id) LLInventoryModel::item_array_t items; LLFindWearablesEx collector(/*is_worn=*/ true, /*include_body_parts=*/ false); - gInventory.collectDescendentsIf(cat_id, cats, items, FALSE, collector); + gInventory.collectDescendentsIf(cat_id, cats, items, FALSE, collector, true); LLInventoryModel::item_array_t::const_iterator it = items.begin(); const LLInventoryModel::item_array_t::const_iterator it_end = items.end(); @@ -1536,6 +1687,18 @@ void LLAppearanceMgr::takeOffOutfit(const LLUUID& cat_id) uuids_to_remove.push_back(item->getUUID()); } removeItemsFromAvatar(uuids_to_remove); + + // deactivate all gestures in the outfit folder + LLInventoryModel::item_array_t gest_items; + getDescendentsOfAssetType(cat_id, gest_items, LLAssetType::AT_GESTURE, true); + for(U32 i = 0; i < gest_items.size(); ++i) + { + LLViewerInventoryItem *gest_item = gest_items[i]; + if ( LLGestureMgr::instance().isGestureActive( gest_item->getLinkedUUID()) ) + { + LLGestureMgr::instance().deactivateGesture( gest_item->getLinkedUUID() ); + } + } } // Create a copy of src_id + contents as a subfolder of dst_id. @@ -1545,10 +1708,10 @@ void LLAppearanceMgr::shallowCopyCategory(const LLUUID& src_id, const LLUUID& ds LLInventoryCategory *src_cat = gInventory.getCategory(src_id); if (!src_cat) { - llwarns << "folder not found for src " << src_id.asString() << llendl; + LL_WARNS() << "folder not found for src " << src_id.asString() << LL_ENDL; return; } - llinfos << "starting, src_id " << src_id << " name " << src_cat->getName() << " dst_id " << dst_id << llendl; + LL_INFOS() << "starting, src_id " << src_id << " name " << src_cat->getName() << " dst_id " << dst_id << LL_ENDL; LLUUID parent_id = dst_id; if(parent_id.isNull()) { @@ -1562,6 +1725,58 @@ void LLAppearanceMgr::shallowCopyCategory(const LLUUID& src_id, const LLUUID& ds gInventory.notifyObservers(); } +void LLAppearanceMgr::slamCategoryLinks(const LLUUID& src_id, const LLUUID& dst_id, + bool include_folder_links, LLPointer cb) +{ + LLInventoryModel::cat_array_t* cats; + LLInventoryModel::item_array_t* items; + LLSD contents = LLSD::emptyArray(); + gInventory.getDirectDescendentsOf(src_id, cats, items); + LL_INFOS() << "copying " << items->size() << " items" << LL_ENDL; + for (LLInventoryModel::item_array_t::const_iterator iter = items->begin(); + iter != items->end(); + ++iter) + { + const LLViewerInventoryItem* item = (*iter); + switch (item->getActualType()) + { + case LLAssetType::AT_LINK: + { + LL_DEBUGS("Avatar") << "linking inventory item " << item->getName() << LL_ENDL; + //getActualDescription() is used for a new description + //to propagate ordering information saved in descriptions of links + LLSD item_contents; + item_contents["name"] = item->getName(); + item_contents["desc"] = item->getActualDescription(); + item_contents["linked_id"] = item->getLinkedUUID(); + item_contents["type"] = LLAssetType::AT_LINK; + contents.append(item_contents); + break; + } + case LLAssetType::AT_LINK_FOLDER: + { + LLViewerInventoryCategory *catp = item->getLinkedCategory(); + if (catp && include_folder_links) + { + LL_DEBUGS("Avatar") << "linking inventory folder " << item->getName() << LL_ENDL; + LLSD base_contents; + base_contents["name"] = catp->getName(); + base_contents["desc"] = ""; // categories don't have descriptions. + base_contents["linked_id"] = catp->getLinkedUUID(); + base_contents["type"] = LLAssetType::AT_LINK_FOLDER; + contents.append(base_contents); + } + break; + } + default: + { + // Linux refuses to compile unless all possible enums are handled. Really, Linux? + break; + } + } + } + slam_inventory_folder(dst_id, contents, cb); +} // Copy contents of src_id to dst_id. void LLAppearanceMgr::shallowCopyCategoryContents(const LLUUID& src_id, const LLUUID& dst_id, LLPointer cb) @@ -1569,12 +1784,8 @@ void LLAppearanceMgr::shallowCopyCategoryContents(const LLUUID& src_id, const LL LLInventoryModel::cat_array_t* cats; LLInventoryModel::item_array_t* items; gInventory.getDirectDescendentsOf(src_id, cats, items); - llinfos << "copying " << items->count() << " items" << llendl; - copyItems(dst_id, items, cb); -} - -void LLAppearanceMgr::copyItems(const LLUUID& dst_id, LLInventoryModel::item_array_t* items, LLPointer cb) -{ + LL_INFOS() << "copying " << items->size() << " items" << LL_ENDL; + LLInventoryObject::const_object_list_t link_array; for (LLInventoryModel::item_array_t::const_iterator iter = items->begin(); iter != items->end(); ++iter) @@ -1584,14 +1795,8 @@ void LLAppearanceMgr::copyItems(const LLUUID& dst_id, LLInventoryModel::item_arr { case LLAssetType::AT_LINK: { - //LLInventoryItem::getDescription() is used for a new description - //to propagate ordering information saved in descriptions of links - link_inventory_item(gAgent.getID(), - item->getLinkedUUID(), - dst_id, - item->getName(), - item->getActualDescription(), - LLAssetType::AT_LINK, cb); + LL_DEBUGS("Avatar") << "linking inventory item " << item->getName() << LL_ENDL; + link_array.push_back(LLConstPointer(item)); break; } case LLAssetType::AT_LINK_FOLDER: @@ -1600,12 +1805,8 @@ void LLAppearanceMgr::copyItems(const LLUUID& dst_id, LLInventoryModel::item_arr // Skip copying outfit links. if (catp && catp->getPreferredType() != LLFolderType::FT_OUTFIT) { - link_inventory_item(gAgent.getID(), - item->getLinkedUUID(), - dst_id, - item->getName(), - item->getDescription(), - LLAssetType::AT_LINK_FOLDER, cb); + LL_DEBUGS("Avatar") << "linking inventory folder " << item->getName() << LL_ENDL; + link_array.push_back(LLConstPointer(item)); } break; } @@ -1615,17 +1816,10 @@ void LLAppearanceMgr::copyItems(const LLUUID& dst_id, LLInventoryModel::item_arr case LLAssetType::AT_GESTURE: { if(!item->getPermissions().allowCopyBy(gAgent.getID())) - { - link_inventory_item(gAgent.getID(), - item->getUUID(), - dst_id, - item->getName(), - item->getDescription(), - LLAssetType::AT_LINK, cb); - } + link_array.push_back(LLConstPointer(item)); else { - llinfos << "copying inventory item " << item->getName() << llendl; + LL_DEBUGS("Avatar") << "copying inventory item " << item->getName() << LL_ENDL; copy_inventory_item(gAgent.getID(), item->getPermissions().getOwner(), item->getUUID(), @@ -1640,6 +1834,10 @@ void LLAppearanceMgr::copyItems(const LLUUID& dst_id, LLInventoryModel::item_arr break; } } + if (!link_array.empty()) + { + link_inventory_array(dst_id, link_array, cb); + } } BOOL LLAppearanceMgr::getCanMakeFolderIntoOutfit(const LLUUID& folder_id) @@ -1704,6 +1902,10 @@ bool LLAppearanceMgr::getCanRemoveOutfit(const LLUUID& outfit_cat_id) // static bool LLAppearanceMgr::getCanRemoveFromCOF(const LLUUID& outfit_cat_id) { + if (gAgentWearables.isCOFChangeInProgress()) + { + return false; + } LLInventoryModel::cat_array_t cats; LLInventoryModel::item_array_t items; LLFindWearablesEx is_worn(/*is_worn=*/ true, /*include_body_parts=*/ false); @@ -1711,7 +1913,8 @@ bool LLAppearanceMgr::getCanRemoveFromCOF(const LLUUID& outfit_cat_id) cats, items, LLInventoryModel::EXCLUDE_TRASH, - is_worn); + is_worn, + /*follow_folder_links=*/ true); return items.size() > 0; } @@ -1731,6 +1934,7 @@ bool LLAppearanceMgr::getCanAddToCOF(const LLUUID& outfit_cat_id) items, LLInventoryModel::EXCLUDE_TRASH, not_worn); + return items.size() > 0; } @@ -1744,7 +1948,7 @@ bool LLAppearanceMgr::getCanReplaceCOF(const LLUUID& outfit_cat_id) // Check whether it's the base outfit. // if (outfit_cat_id.isNull() || outfit_cat_id == getBaseOutfitUUID()) -// [SL:KB] - Patch: Appearance-Misc | Checked: 2010-09-21 (Catznip-3.0.0a) | Added: Catznip-2.1.2d +// [SL:KB] - Patch: Appearance-Misc | Checked: 2010-09-21 (Catznip-2.1) if ( (outfit_cat_id.isNull()) || ((outfit_cat_id == getBaseOutfitUUID()) && (!isOutfitDirty())) ) // [/SL:KB] { @@ -1760,183 +1964,140 @@ bool LLAppearanceMgr::getCanReplaceCOF(const LLUUID& outfit_cat_id) items, LLInventoryModel::EXCLUDE_TRASH, is_worn); + return items.size() > 0; } -void LLAppearanceMgr::purgeBaseOutfitLink(const LLUUID& category) +// Moved from LLWearableList::ContextMenu for wider utility. +bool LLAppearanceMgr::canAddWearables(const uuid_vec_t& item_ids) { - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - gInventory.collectDescendents(category, cats, items, - LLInventoryModel::EXCLUDE_TRASH); - for (S32 i = 0; i < items.count(); ++i) - { - LLViewerInventoryItem *item = items.get(i); - if (item->getActualType() != LLAssetType::AT_LINK_FOLDER) - continue; - if (item->getIsLinkType()) - { - LLViewerInventoryCategory* catp = item->getLinkedCategory(); - if(catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT) - { - gInventory.purgeObject(item->getUUID()); - } - } - } -} + // TODO: investigate wearables may not be loaded at this point EXT-8231 -void LLAppearanceMgr::purgeCategory(const LLUUID& category, bool keep_outfit_links) -{ - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - gInventory.collectDescendents(category, cats, items, - LLInventoryModel::EXCLUDE_TRASH); - for (S32 i = 0; i < items.count(); ++i) + U32 n_objects = 0; + U32 n_clothes = 0; + + // Count given clothes (by wearable type) and objects. + for (uuid_vec_t::const_iterator it = item_ids.begin(); it != item_ids.end(); ++it) { - LLViewerInventoryItem *item = items.get(i); - if (keep_outfit_links && (item->getActualType() == LLAssetType::AT_LINK_FOLDER)) - continue; - if (item->getIsLinkType()) + LLViewerInventoryItem* item = gInventory.getItem(*it); + if (!item) { - gInventory.purgeObject(item->getUUID()); + return false; } - } -} -// [SL:KB] - Checked: 2010-04-24 (RLVa-1.2.0f) | Added: RLVa-1.2.0f -void LLAppearanceMgr::purgeItems(const LLInventoryModel::item_array_t& items) -{ - for (LLInventoryModel::item_array_t::const_iterator itItem = items.begin(); itItem != items.end(); ++itItem) - { - const LLViewerInventoryItem* pItem = *itItem; - if (pItem->getIsLinkType()) + if (item->getType() == LLAssetType::AT_OBJECT) { - gInventory.purgeObject(pItem->getUUID()); + ++n_objects; } - } -} - -void LLAppearanceMgr::purgeItemsOfType(LLAssetType::EType asset_type) -{ - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - gInventory.collectDescendents(getCOF(), cats, items, LLInventoryModel::EXCLUDE_TRASH); - for (LLInventoryModel::item_array_t::const_iterator itItem = items.begin(); itItem != items.end(); ++itItem) - { - const LLInventoryItem* pItem = *itItem; - if ( (pItem->getIsLinkType()) && (asset_type == pItem->getType()) ) + else if (item->getType() == LLAssetType::AT_CLOTHING) { - gInventory.purgeObject(pItem->getUUID()); + ++n_clothes; } - } -} - -void LLAppearanceMgr::syncCOF(const LLInventoryModel::item_array_t& items, - LLInventoryModel::item_array_t& items_to_add, LLInventoryModel::item_array_t& items_to_remove) -{ - const LLUUID idCOF = getCOF(); - LLInventoryModel::item_array_t cur_cof_items, new_cof_items = items; - - // Grab the current COF contents - LLInventoryModel::cat_array_t cats; - gInventory.collectDescendents(getCOF(), cats, cur_cof_items, LLInventoryModel::EXCLUDE_TRASH); - - // Purge everything in cur_cof_items that isn't part of new_cof_items - for (S32 idxCurItem = 0, cntCurItem = cur_cof_items.count(); idxCurItem < cntCurItem; idxCurItem++) - { - LLViewerInventoryItem* pItem = cur_cof_items.get(idxCurItem); - if (std::find_if(new_cof_items.begin(), new_cof_items.end(), RlvPredIsEqualOrLinkedItem(pItem)) == new_cof_items.end()) + else if (item->getType() == LLAssetType::AT_BODYPART || item->getType() == LLAssetType::AT_GESTURE) { - // Item doesn't exist in new_cof_items => purge (if it's a link) - if ( (pItem->getIsLinkType()) && - (LLAssetType::AT_LINK_FOLDER != pItem->getActualType()) && - (items_to_remove.end() == std::find(items_to_remove.begin(), items_to_remove.end(), pItem)) ) - { - items_to_remove.push_back(pItem); - } + return isAgentAvatarValid(); } else { - // Item exists in new_cof_items => remove *all* occurances in new_cof_items (removes duplicate COF links to this item as well) - new_cof_items.erase( - std::remove_if(new_cof_items.begin(), new_cof_items.end(), RlvPredIsEqualOrLinkedItem(pItem)), new_cof_items.end()); + LL_WARNS() << "Unexpected wearable type" << LL_ENDL; + return false; } } - // Whatever remains in new_cof_items will need to have a link created - for (S32 idxNewItem = 0, cntNewItem = new_cof_items.count(); idxNewItem < cntNewItem; idxNewItem++) + // Check whether we can add all the objects. + if (!isAgentAvatarValid() || !gAgentAvatarp->canAttachMoreObjects(n_objects)) { - LLViewerInventoryItem* pItem = new_cof_items.get(idxNewItem); - if (items_to_add.end() == std::find(items_to_add.begin(), items_to_add.end(), pItem)) - { - items_to_add.push_back(pItem); - } + return false; } + + // Check whether we can add all the clothes. + U32 sum_clothes = n_clothes + gAgentWearables.getClothingLayerCount(); + return sum_clothes <= LLAgentWearables::MAX_CLOTHING_LAYERS; } -// [/SL:KB] -// Keep the last N wearables of each type. For viewer 2.0, N is 1 for -// both body parts and clothing items. -void LLAppearanceMgr::filterWearableItems( - LLInventoryModel::item_array_t& items, S32 max_per_type) +void LLAppearanceMgr::purgeBaseOutfitLink(const LLUUID& category, LLPointer cb) { - // Divvy items into arrays by wearable type. - std::vector items_by_type(LLWearableType::WT_COUNT); - divvyWearablesByType(items, items_by_type); - - // rebuild items list, retaining the last max_per_type of each array - items.clear(); - for (S32 i=0; igetActualType() != LLAssetType::AT_LINK_FOLDER) continue; -// S32 start_index = llmax(0,size-max_per_type); -// [SL:KB] - Patch: Appearance-Misc | Checked: 2010-05-11 (Catznip-3.0.0a) | Added: Catznip-2.0.0h - S32 start_index = - llmax(0, size - ((LLAssetType::AT_BODYPART == LLWearableType::getAssetType((LLWearableType::EType)i)) ? 1 : max_per_type)); -// [/SL:KB[ - for (S32 j = start_index; jgetIsLinkType()) { - items.push_back(items_by_type[i][j]); + LLViewerInventoryCategory* catp = item->getLinkedCategory(); + if(catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT) + { + remove_inventory_item(item->getUUID(), cb); + } } } } -// Create links to all listed items. -void LLAppearanceMgr::linkAll(const LLUUID& cat_uuid, - LLInventoryModel::item_array_t& items, - LLPointer cb) -{ - for (S32 i=0; igetLinkedUUID(), - cat_uuid, - item->getName(), - item->getActualDescription(), - LLAssetType::AT_LINK, - cb); - - const LLViewerInventoryCategory *cat = gInventory.getCategory(cat_uuid); - const std::string cat_name = cat ? cat->getName() : "CAT NOT FOUND"; -#ifndef LL_RELEASE_FOR_DOWNLOAD - LL_DEBUGS("Avatar") << self_av_string() << "Linking Item [ name:" << item->getName() << " UUID:" << item->getUUID() << " ] to Category [ name:" << cat_name << " UUID:" << cat_uuid << " ] " << LL_ENDL; -#endif - } +// Keep the last N wearables of each type. For viewer 2.0, N is 1 for +// both body parts and clothing items. +void LLAppearanceMgr::filterWearableItems( + LLInventoryModel::item_array_t& items, S32 max_per_type, S32 max_total) +{ + // Restrict by max total items first. + if ((max_total > 0) && ((S32)items.size() > max_total)) + { + LLInventoryModel::item_array_t items_to_keep; + for (S32 i=0; i 0) + { + // Divvy items into arrays by wearable type. + std::vector items_by_type(LLWearableType::WT_COUNT); + divvyWearablesByType(items, items_by_type); + + // rebuild items list, retaining the last max_per_type of each array + items.clear(); + for (S32 i=0; igetName() : "[UNKNOWN]") << "'" << LL_ENDL; +// [RLVa:KB] - Checked: 2010-03-26 (RLVa-1.2.0) + LL_INFOS("Avatar") << "starting" << LL_ENDL; +// [/RLVa:KB] + LLInventoryModel::item_array_t body_items_new, wear_items_new, obj_items_new, gest_items_new; - getDescendentsOfAssetType(category, body_items_new, LLAssetType::AT_BODYPART, false); - getDescendentsOfAssetType(category, wear_items_new, LLAssetType::AT_CLOTHING, false); - getDescendentsOfAssetType(category, obj_items_new, LLAssetType::AT_OBJECT, false); - getDescendentsOfAssetType(category, gest_items_new, LLAssetType::AT_GESTURE, false); + getDescendentsOfAssetType(category, body_items_new, LLAssetType::AT_BODYPART); + getDescendentsOfAssetType(category, wear_items_new, LLAssetType::AT_CLOTHING); + getDescendentsOfAssetType(category, obj_items_new, LLAssetType::AT_OBJECT); + getDescendentsOfAssetType(category, gest_items_new, LLAssetType::AT_GESTURE); updateCOF(body_items_new, wear_items_new, obj_items_new, gest_items_new, append, category); } @@ -1944,26 +2105,19 @@ void LLAppearanceMgr::updateCOF(LLInventoryModel::item_array_t& body_items_new, LLInventoryModel::item_array_t& wear_items_new, LLInventoryModel::item_array_t& obj_items_new, LLInventoryModel::item_array_t& gest_items_new, - bool append /*=false*/, const LLUUID& idOutfit /*=LLUUID::null*/) + bool append /*=false*/, const LLUUID& idOutfit /*=LLUUID::null*/, LLPointer link_waiter /*= NULL*/) // [/RLVa:KB] { -// LLViewerInventoryCategory *pcat = gInventory.getCategory(category); -// llinfos << "starting, cat " << (pcat ? pcat->getName() : "[UNKNOWN]") << llendl; -// [RLVa:KB] - Checked: 2010-03-26 (RLVa-1.2.0b) | Added: RLVa-1.2.0b - // RELEASE-RLVa: [SL-2.0.0] If pcat ever gets used for anything further down the beta we'll know about it - llinfos << "starting" << llendl; -// [/RLVa:KB] - const LLUUID cof = getCOF(); // Deactivate currently active gestures in the COF, if replacing outfit if (!append) { LLInventoryModel::item_array_t gest_items; - getDescendentsOfAssetType(cof, gest_items, LLAssetType::AT_GESTURE, false); - for(S32 i = 0; i < gest_items.count(); ++i) + getDescendentsOfAssetType(cof, gest_items, LLAssetType::AT_GESTURE); + for(U32 i = 0; i < gest_items.size(); ++i) { - LLViewerInventoryItem *gest_item = gest_items.get(i); + LLViewerInventoryItem *gest_item = gest_items.at(i); if ( LLGestureMgr::instance().isGestureActive( gest_item->getLinkedUUID()) ) { LLGestureMgr::instance().deactivateGesture( gest_item->getLinkedUUID() ); @@ -1973,13 +2127,14 @@ void LLAppearanceMgr::updateCOF(LLInventoryModel::item_array_t& body_items_new, // Collect and filter descendents to determine new COF contents. - // - Body parts: always include COF contents as a fallback in case any - // required parts are missing. + // + // - Body parts: always include COF contents as a fallback in case any required parts are missing. + // // Preserve body parts from COF if appending. LLInventoryModel::item_array_t body_items; - getDescendentsOfAssetType(cof, body_items, LLAssetType::AT_BODYPART, false); -// getDescendentsOfAssetType(category, body_items, LLAssetType::AT_BODYPART, false); -// [RLVa:KB] - Checked: 2010-03-19 (RLVa-1.2.0c) | Modified: RLVa-1.2.0b + getDescendentsOfAssetType(cof, body_items, LLAssetType::AT_BODYPART); +// getDescendentsOfAssetType(category, body_items, LLAssetType::AT_BODYPART); +// [RLVa:KB] - Checked: 2010-03-19 (RLVa-1.2.0) // Filter out any new body parts that can't be worn before adding them if ( (rlv_handler_t::isEnabled()) && (gRlvWearableLocks.hasLockedWearableType(RLV_LOCK_ANY)) ) body_items_new.erase(std::remove_if(body_items_new.begin(), body_items_new.end(), RlvPredCanNotWearItem(RLV_WEAR_REPLACE)), body_items_new.end()); @@ -1990,22 +2145,24 @@ void LLAppearanceMgr::updateCOF(LLInventoryModel::item_array_t& body_items_new, // reverse(body_items.begin(), body_items.end()); // Reduce body items to max of one per type. removeDuplicateItems(body_items); - filterWearableItems(body_items, 1); + filterWearableItems(body_items, 1, 0); + // // - Wearables: include COF contents only if appending. + // LLInventoryModel::item_array_t wear_items; if (append) - getDescendentsOfAssetType(cof, wear_items, LLAssetType::AT_CLOTHING, false); -// [RLVa:KB] - Checked: 2010-03-19 (RLVa-1.2.0c) | Modified: RLVa-1.2.0b + getDescendentsOfAssetType(cof, wear_items, LLAssetType::AT_CLOTHING); +// [RLVa:KB] - Checked: 2010-03-19 (RLVa-1.2.0) else if ( (rlv_handler_t::isEnabled()) && (gRlvWearableLocks.hasLockedWearableType(RLV_LOCK_ANY)) ) { // Make sure that all currently locked clothing layers remain in COF when replacing - getDescendentsOfAssetType(cof, wear_items, LLAssetType::AT_CLOTHING, false); - wear_items.erase(std::remove_if(wear_items.begin(), wear_items.end(), rlvPredCanRemoveItem), wear_items.end()); + getDescendentsOfAssetType(cof, wear_items, LLAssetType::AT_CLOTHING); + wear_items.erase(std::remove_if(wear_items.begin(), wear_items.end(), RlvPredCanRemoveItem()), wear_items.end()); } // [/RLVa:KB] -// getDescendentsOfAssetType(category, wear_items, LLAssetType::AT_CLOTHING, false); -// [RLVa:KB] - Checked: 2010-03-19 (RLVa-1.2.0c) | Modified: RLVa-1.2.0b +// getDescendentsOfAssetType(category, wear_items, LLAssetType::AT_CLOTHING); +// [RLVa:KB] - Checked: 2010-03-19 (RLVa-1.2.0) // Filter out any new wearables that can't be worn before adding them if ( (rlv_handler_t::isEnabled()) && (gRlvWearableLocks.hasLockedWearableType(RLV_LOCK_ANY)) ) wear_items_new.erase(std::remove_if(wear_items_new.begin(), wear_items_new.end(), RlvPredCanNotWearItem(RLV_WEAR)), wear_items_new.end()); @@ -2016,24 +2173,24 @@ void LLAppearanceMgr::updateCOF(LLInventoryModel::item_array_t& body_items_new, // [SL:KB] - Patch: Appearance-WearableDuplicateAssets | Checked: 2011-07-24 (Catznip-2.6.0e) | Added: Catznip-2.6.0e removeDuplicateWearableItemsByAssetID(wear_items); // [/SL:KB] - filterWearableItems(wear_items, LLAgentWearables::MAX_CLOTHING_PER_TYPE); + filterWearableItems(wear_items, 0, LLAgentWearables::MAX_CLOTHING_LAYERS); // // - Attachments: include COF contents only if appending. // LLInventoryModel::item_array_t obj_items; if (append) - getDescendentsOfAssetType(cof, obj_items, LLAssetType::AT_OBJECT, false); + getDescendentsOfAssetType(cof, obj_items, LLAssetType::AT_OBJECT); // [RLVa:KB] - Checked: 2010-03-05 (RLVa-1.2.0z) | Modified: RLVa-1.2.0b else if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) ) { // Make sure that all currently locked attachments remain in COF when replacing - getDescendentsOfAssetType(cof, obj_items, LLAssetType::AT_OBJECT, false); - obj_items.erase(std::remove_if(obj_items.begin(), obj_items.end(), rlvPredCanRemoveItem), obj_items.end()); + getDescendentsOfAssetType(cof, obj_items, LLAssetType::AT_OBJECT); + obj_items.erase(std::remove_if(obj_items.begin(), obj_items.end(), RlvPredCanRemoveItem()), obj_items.end()); } // [/RLVa:KB] -// getDescendentsOfAssetType(category, obj_items, LLAssetType::AT_OBJECT, false); -// [RLVa:KB] - Checked: 2010-03-05 (RLVa-1.2.0z) | Modified: RLVa-1.2.0b +// getDescendentsOfAssetType(category, obj_items, LLAssetType::AT_OBJECT); +// [RLVa:KB] - Checked: 2010-03-05 (RLVa-1.2.0) // Filter out any new attachments that can't be worn before adding them if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) ) obj_items_new.erase(std::remove_if(obj_items_new.begin(), obj_items_new.end(), RlvPredCanNotWearItem(RLV_WEAR)), obj_items_new.end()); @@ -2046,71 +2203,90 @@ void LLAppearanceMgr::updateCOF(LLInventoryModel::item_array_t& body_items_new, // LLInventoryModel::item_array_t gest_items; if (append) - getDescendentsOfAssetType(cof, gest_items, LLAssetType::AT_GESTURE, false); -// getDescendentsOfAssetType(category, gest_items, LLAssetType::AT_GESTURE, false); -// [RLVa:KB] - Checked: 2010-03-05 (RLVa-1.2.0z) | Added: RLVa-1.2.0b + getDescendentsOfAssetType(cof, gest_items, LLAssetType::AT_GESTURE); +// getDescendentsOfAssetType(category, gest_items, LLAssetType::AT_GESTURE); +// [RLVa:KB] - Checked: 2010-03-05 (RLVa-1.2.0) gest_items.insert(gest_items.end(), gest_items_new.begin(), gest_items_new.end()); // [/RLVa:KB] removeDuplicateItems(gest_items); // Create links to new COF contents. LLInventoryModel::item_array_t all_items; - all_items += body_items; - all_items += wear_items; - all_items += obj_items; - all_items += gest_items; - -// [SL:KB] - // Synchronize COF - // -> it's possible that we don't link to any new items in which case 'link_waiter' fires when it goes out of scope below - LLInventoryModel::item_array_t items_add, items_remove; - syncCOF(all_items, items_add, items_remove); -// [/SL:KB] + std::copy(body_items.begin(), body_items.end(), std::back_inserter(all_items)); + std::copy(wear_items.begin(), wear_items.end(), std::back_inserter(all_items)); + std::copy(obj_items.begin(), obj_items.end(), std::back_inserter(all_items)); + std::copy(gest_items.begin(), gest_items.end(), std::back_inserter(all_items)); + + // Find any wearables that need description set to enforce ordering. + desc_map_t desc_map; + getWearableOrderingDescUpdates(wear_items, desc_map); // Will link all the above items. - LLPointer link_waiter = new LLUpdateAppearanceOnDestroy; -// [SL:KB] - Checked: 2013-03-05 (RLVa-1.4.8) - linkAll(cof, items_add, link_waiter); -// [/SL:KB] -// linkAll(cof,all_items,link_waiter); + // link_waiter enforce flags are false because we've already fixed everything up in updateCOF(). +// LLPointer link_waiter = new LLUpdateAppearanceOnDestroy(false,false); +// [RLVa:KB] Checked: 2015-05-05 (RLVa-1.4.12) + if (!link_waiter) + link_waiter = new LLUpdateAppearanceOnDestroy(false, false); +// [/RLVa:KB] + LLSD contents = LLSD::emptyArray(); - // Add link to outfit if category is an outfit. -// [SL:KB] - Checked: 2010-04-24 (RLVa-1.2.0f) | Added: RLVa-1.2.0f - if ( (!append) && (idOutfit.notNull()) ) + for (LLInventoryModel::item_array_t::const_iterator it = all_items.begin(); + it != all_items.end(); ++it) { - createBaseOutfitLink(idOutfit, link_waiter); - } -// [/SL:KB] -// if (!append) -// { -// createBaseOutfitLink(category, link_waiter); -// } -// - // Remove current COF contents. Have to do this after creating - // the link_waiter so links can be followed for any items that get - // carried over (e.g. keeping old shape if the new outfit does not - // contain one) -// [SL:KB] - purgeItems(items_remove); + LLSD item_contents; + LLInventoryItem *item = *it; - bool keep_outfit_links = append; - if (!keep_outfit_links) - { - purgeItemsOfType(LLAssetType::AT_LINK_FOLDER); - } + std::string desc; + desc_map_t::const_iterator desc_iter = desc_map.find(item->getUUID()); + if (desc_iter != desc_map.end()) + { + desc = desc_iter->second; + LL_DEBUGS("Avatar") << item->getName() << " overriding desc to: " << desc + << " (was: " << item->getActualDescription() << ")" << LL_ENDL; + } + else + { + desc = item->getActualDescription(); + } - gInventory.notifyObservers(); + item_contents["name"] = item->getName(); + item_contents["desc"] = desc; + item_contents["linked_id"] = item->getLinkedUUID(); + item_contents["type"] = LLAssetType::AT_LINK; + contents.append(item_contents); + } +// const LLUUID& base_id = append ? getBaseOutfitUUID() : category; +// LLViewerInventoryCategory *base_cat = gInventory.getCategory(base_id); +// [RLVa:KB] - Checked: 2014-11-02 (RLVa-1.4.11) + const LLUUID& base_id = (append) ? getBaseOutfitUUID() : idOutfit; + LLViewerInventoryCategory* base_cat = (base_id.notNull()) ? gInventory.getCategory(base_id) : NULL; +// [/RLVa:KB] +// if (base_cat) +// [SL:KB] - Patch: Appearance-Misc | Checked: 2015-06-27 (Catznip-3.7) + if ((base_cat) && (base_cat->getPreferredType() == LLFolderType::FT_OUTFIT)) // [/SL:KB] -// bool keep_outfit_links = append; -// purgeCategory(cof, keep_outfit_links, &all_items); -// gInventory.notifyObservers(); + { + LLSD base_contents; + base_contents["name"] = base_cat->getName(); + base_contents["desc"] = ""; + base_contents["linked_id"] = base_cat->getLinkedUUID(); + base_contents["type"] = LLAssetType::AT_LINK_FOLDER; + contents.append(base_contents); + } + static LLCachedControl debug_ava_appr_msg(gSavedSettings, "DebugAvatarAppearanceMessage"); + if (debug_ava_appr_msg) + { + dump_sequential_xml(gAgentAvatarp->getFullname() + "_slam_request", contents); + } + slam_inventory_folder(getCOF(), contents, link_waiter); LL_DEBUGS("Avatar") << self_av_string() << "waiting for LLUpdateAppearanceOnDestroy" << LL_ENDL; } void LLAppearanceMgr::updatePanelOutfitName(const std::string& name) { - LLFloaterCustomize* panel_appearance = LLFloaterCustomize::instanceExists() ? LLFloaterCustomize::getInstance() : NULL; + LLFloaterCustomize* panel_appearance = + LLFloaterCustomize::instanceExists() ? LLFloaterCustomize::getInstance() : nullptr; if (panel_appearance) { panel_appearance->refreshCurrentOutfitName(name); @@ -2123,24 +2299,24 @@ void LLAppearanceMgr::createBaseOutfitLink(const LLUUID& category, LLPointergetPreferredType() == LLFolderType::FT_OUTFIT) { - link_inventory_item(gAgent.getID(), category, cof, catp->getName(), "", - LLAssetType::AT_LINK_FOLDER, link_waiter); + link_inventory_object(cof, catp, link_waiter); new_outfit_name = catp->getName(); } updatePanelOutfitName(new_outfit_name); } -void LLAppearanceMgr::updateAgentWearables(LLWearableHoldingPattern* holder, bool append) +void LLAppearanceMgr::updateAgentWearables(LLWearableHoldingPattern* holder) { - lldebugs << "updateAgentWearables()" << llendl; + LL_DEBUGS("Avatar") << "updateAgentWearables()" << LL_ENDL; LLInventoryItem::item_array_t items; - LLDynamicArray< LLViewerWearable* > wearables; -// [RLVa:KB] - Checked: 2011-03-31 (RLVa-1.3.0f) | Added: RLVa-1.3.0f + std::vector< LLViewerWearable* > wearables; + wearables.reserve(32); +// [RLVa:KB] - Checked: 2011-03-31 (RLVa-1.3.0) uuid_vec_t idsCurrent; LLInventoryModel::item_array_t itemsNew; if (rlv_handler_t::isEnabled()) { @@ -2162,7 +2338,7 @@ void LLAppearanceMgr::updateAgentWearables(LLWearableHoldingPattern* holder, boo LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(data.mItemID); if( item && (item->getAssetUUID() == wearable->getAssetID()) ) { -// [RLVa:KB] - Checked: 2010-03-19 (RLVa-1.2.0g) | Modified: RLVa-1.2.0g +// [RLVa:KB] - Checked: 2010-03-19 (RLVa-1.2.0) // TODO-RLVa: [RLVa-1.2.1] This is fall-back code so if we don't ever trigger this code it can just be removed // -> one way to trigger the assertion: // 1) "Replace Outfit" on a folder with clothing and an attachment that goes @addoutfit=n @@ -2181,9 +2357,9 @@ void LLAppearanceMgr::updateAgentWearables(LLWearableHoldingPattern* holder, boo } #endif // RLV_DEBUG // [/RLVa:KB] - items.put(item); - wearables.put(wearable); -// [RLVa:KB] - Checked: 2011-03-31 (RLVa-1.3.0f) | Added: RLVa-1.3.0f + items.push_back(item); + wearables.push_back(wearable); +// [RLVa:KB] - Checked: 2011-03-31 (RLVa-1.3.0) if ( (rlv_handler_t::isEnabled()) && (gAgentWearables.areInitalWearablesLoaded()) ) { // Remove the wearable from current item UUIDs if currently worn and requested, otherwise mark it as a new item @@ -2199,7 +2375,7 @@ void LLAppearanceMgr::updateAgentWearables(LLWearableHoldingPattern* holder, boo } } -// [RLVa:KB] - Checked: 2011-03-31 (RLVa-1.3.0f) | Added: RLVa-1.3.0f +// [RLVa:KB] - Checked: 2011-03-31 (RLVa-1.3.0) if ( (rlv_handler_t::isEnabled()) && (gAgentWearables.areInitalWearablesLoaded()) ) { // We need to report removals before additions or scripts will get confused @@ -2209,19 +2385,22 @@ void LLAppearanceMgr::updateAgentWearables(LLWearableHoldingPattern* holder, boo if (pWearable) RlvBehaviourNotifyHandler::onTakeOff(pWearable->getType(), true); } - for (S32 idxItem = 0, cntItem = itemsNew.count(); idxItem < cntItem; idxItem++) + for (S32 idxItem = 0, cntItem = itemsNew.size(); idxItem < cntItem; idxItem++) { - RlvBehaviourNotifyHandler::onWear(itemsNew.get(idxItem)->getWearableType(), true); + RlvBehaviourNotifyHandler::onWear(itemsNew.at(idxItem)->getWearableType(), true); } } // [/RLVa:KB] - if(wearables.count() > 0) + if(wearables.size() > 0) { - gAgentWearables.setWearableOutfit(items, wearables, !append); + gAgentWearables.setWearableOutfit(items, wearables); } +} -// dec_busy_count(); +S32 LLAppearanceMgr::countActiveHoldingPatterns() +{ + return LLWearableHoldingPattern::countActive(); } static void remove_non_link_items(LLInventoryModel::item_array_t &items) @@ -2245,7 +2424,7 @@ bool sort_by_actual_description(const LLInventoryItem* item1, const LLInventoryI { if (!item1 || !item2) { - llwarning("either item1 or item2 is NULL", 0); + LL_WARNS() << "either item1 or item2 is NULL" << LL_ENDL; return true; } @@ -2262,7 +2441,7 @@ void item_array_diff(LLInventoryModel::item_array_t& full_list, ++it) { LLViewerInventoryItem *item = *it; - if (keep_list.find(item) < 0) // Why on earth does LLDynamicArray need to redefine find()? + if (std::find(keep_list.begin(), keep_list.end(), item) == keep_list.end()) { kill_list.push_back(item); } @@ -2271,18 +2450,19 @@ void item_array_diff(LLInventoryModel::item_array_t& full_list, S32 LLAppearanceMgr::findExcessOrDuplicateItems(const LLUUID& cat_id, LLAssetType::EType type, - S32 max_items, - LLInventoryModel::item_array_t& items_to_kill) + S32 max_items_per_type, + S32 max_items_total, + LLInventoryObject::object_list_t& items_to_kill) { S32 to_kill_count = 0; LLInventoryModel::item_array_t items; - getDescendentsOfAssetType(cat_id, items, type, false); + getDescendentsOfAssetType(cat_id, items, type); LLInventoryModel::item_array_t curr_items = items; removeDuplicateItems(items); - if (max_items > 0) + if (max_items_per_type > 0 || max_items_total > 0) { - filterWearableItems(items, max_items); + filterWearableItems(items, max_items_per_type, max_items_total); } LLInventoryModel::item_array_t kill_items; item_array_diff(curr_items,items,kill_items); @@ -2290,60 +2470,87 @@ S32 LLAppearanceMgr::findExcessOrDuplicateItems(const LLUUID& cat_id, it != kill_items.end(); ++it) { - items_to_kill.push_back(*it); + items_to_kill.push_back(LLPointer(*it)); to_kill_count++; } return to_kill_count; } - -void LLAppearanceMgr::enforceItemRestrictions() -{ - S32 purge_count = 0; - LLInventoryModel::item_array_t items_to_kill; - purge_count += findExcessOrDuplicateItems(getCOF(),LLAssetType::AT_BODYPART, - 1, items_to_kill); - purge_count += findExcessOrDuplicateItems(getCOF(),LLAssetType::AT_CLOTHING, - LLAgentWearables::MAX_CLOTHING_PER_TYPE, items_to_kill); - purge_count += findExcessOrDuplicateItems(getCOF(),LLAssetType::AT_OBJECT, - -1, items_to_kill); +void LLAppearanceMgr::findAllExcessOrDuplicateItems(const LLUUID& cat_id, + LLInventoryObject::object_list_t& items_to_kill) +{ + findExcessOrDuplicateItems(cat_id,LLAssetType::AT_BODYPART, + 1, 0, items_to_kill); + findExcessOrDuplicateItems(cat_id,LLAssetType::AT_CLOTHING, + 0, LLAgentWearables::MAX_CLOTHING_LAYERS, items_to_kill); + findExcessOrDuplicateItems(cat_id,LLAssetType::AT_OBJECT, + 0, 0, items_to_kill); +} +void LLAppearanceMgr::enforceCOFItemRestrictions(LLPointer cb) +{ + LLInventoryObject::object_list_t items_to_kill; + findAllExcessOrDuplicateItems(getCOF(), items_to_kill); if (items_to_kill.size()>0) { - for (LLInventoryModel::item_array_t::iterator it = items_to_kill.begin(); - it != items_to_kill.end(); - ++it) - { - LLViewerInventoryItem *item = *it; - LL_DEBUGS("Avatar") << self_av_string() << "purging duplicate or excess item " << item->getName() << LL_ENDL; - gInventory.purgeObject(item->getUUID()); - } - gInventory.notifyObservers(); + // Remove duplicate or excess wearables. Should normally be enforced at the UI level, but + // this should catch anything that gets through. + remove_inventory_items(items_to_kill, cb); } } -void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering) +void LLAppearanceMgr::updateAppearanceFromCOF(bool enforce_item_restrictions, + bool enforce_ordering, + nullary_func_t post_update_func) { if (mIsInUpdateAppearanceFromCOF) { - llwarns << "Called updateAppearanceFromCOF inside updateAppearanceFromCOF, skipping" << llendl; + LL_WARNS() << "Called updateAppearanceFromCOF inside updateAppearanceFromCOF, skipping" << LL_ENDL; return; } - BoolSetter setIsInUpdateAppearanceFromCOF(mIsInUpdateAppearanceFromCOF); - selfStartPhase("update_appearance_from_cof"); + LL_DEBUGS("Avatar") << self_av_string() << "starting" << LL_ENDL; - LL_INFOS("Avatar") << self_av_string() << "starting" << LL_ENDL; + if (enforce_item_restrictions) + { + // The point here is just to call + // updateAppearanceFromCOF() again after excess items + // have been removed. That time we will set + // enforce_item_restrictions to false so we don't get + // caught in a perpetual loop. + LLPointer cb( + new LLUpdateAppearanceOnDestroy(false, enforce_ordering, post_update_func)); + enforceCOFItemRestrictions(cb); + return; + } - //checking integrity of the COF in terms of ordering of wearables, - //checking and updating links' descriptions of wearables in the COF (before analyzed for "dirty" state) - updateClothingOrderingInfo(LLUUID::null, update_base_outfit_ordering); + if (enforce_ordering) + { + //checking integrity of the COF in terms of ordering of wearables, + //checking and updating links' descriptions of wearables in the COF (before analyzed for "dirty" state) +// [SL:KB] - Patch: Appearance-AISFilter | Checked: 2015-03-01 (Catznip-3.7) + // Ordering information is pre-applied locally so no reason to reason to wait on the inventory backend + updateClothingOrderingInfo(LLUUID::null); +// [/SL:KB] + +// // As with enforce_item_restrictions handling above, we want +// // to wait for the update callbacks, then (finally!) call +// // updateAppearanceFromCOF() with no additional COF munging needed. +// LLPointer cb( +// new LLUpdateAppearanceOnDestroy(false, false, post_update_func)); +// updateClothingOrderingInfo(LLUUID::null, cb); +// return; + } + + if (!validateClothingOrderingInfo()) + { + LL_WARNS() << "Clothing ordering error" << LL_ENDL; + } + + BoolSetter setIsInUpdateAppearanceFromCOF(mIsInUpdateAppearanceFromCOF); + selfStartPhase("update_appearance_from_cof"); - // Remove duplicate or excess wearables. Should normally be enforced at the UI level, but - // this should catch anything that gets through. - enforceItemRestrictions(); - // update dirty flag to see if the state of the COF matches // the saved outfit stored as a folder link updateIsDirty(); @@ -2353,31 +2560,25 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering) { requestServerAppearanceUpdate(); } - // DRANO really should wait for the appearance message to set this. - // verify that deleting this line doesn't break anything. - //gAgentAvatarp->setIsUsingServerBakes(gAgent.getRegion() && gAgent.getRegion()->getCentralBakeVersion()); - - //dumpCat(getCOF(),"COF, start"); - bool follow_folder_links = false; LLUUID current_outfit_id = getCOF(); // Find all the wearables that are in the COF's subtree. - lldebugs << "LLAppearanceMgr::updateFromCOF()" << llendl; + LL_DEBUGS() << "LLAppearanceMgr::updateFromCOF()" << LL_ENDL; LLInventoryModel::item_array_t wear_items; LLInventoryModel::item_array_t obj_items; LLInventoryModel::item_array_t gest_items; - getUserDescendents(current_outfit_id, wear_items, obj_items, gest_items, follow_folder_links); + getUserDescendents(current_outfit_id, wear_items, obj_items, gest_items); // Get rid of non-links in case somehow the COF was corrupted. remove_non_link_items(wear_items); remove_non_link_items(obj_items); remove_non_link_items(gest_items); -// [SL:KB] - Patch: Apperance-Misc | Checked: 2010-11-24 (Catznip-3.0.0a) | Added: Catzip-2.4.0f - // Since we're following folder links we might have picked up new duplicates, or exceeded MAX_CLOTHING_PER_TYPE +// [SL:KB] - Patch: Apperance-Misc | Checked: 2010-11-24 (Catznip-2.4) + // Since we're following folder links we might have picked up new duplicates, or exceeded MAX_CLOTHING_LAYERS removeDuplicateItems(wear_items); removeDuplicateItems(obj_items); removeDuplicateItems(gest_items); - filterWearableItems(wear_items, LLAgentWearables::MAX_CLOTHING_PER_TYPE); + filterWearableItems(wear_items, LLAgentWearables::MAX_CLOTHING_LAYERS, LLAgentWearables::MAX_CLOTHING_LAYERS); // [/SL:KB] // [SL:KB] - Patch: Appearance-WearableDuplicateAssets | Checked: 2011-07-24 (Catznip-2.6.0e) | Added: Catznip-2.6.0e // Wearing two wearables that share the same asset causes some issues @@ -2387,37 +2588,73 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering) dumpItemArray(wear_items,"asset_dump: wear_item"); dumpItemArray(obj_items,"asset_dump: obj_item"); -// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2010-09-22 (Catznip-3.0.0a) | Added: Catznip-2.2.0a + LLViewerInventoryCategory *cof = gInventory.getCategory(current_outfit_id); + if (!gInventory.isCategoryComplete(current_outfit_id)) + { + LL_WARNS() << "COF info is not complete. Version " << cof->getVersion() + << " descendent_count " << cof->getDescendentCount() + << " viewer desc count " << cof->getViewerDescendentCount() << LL_ENDL; + } + +// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2010-09-22 (Catznip-2.2) // Update attachments to match those requested. if (isAgentAvatarValid()) { // Include attachments which should be in COF but don't have their link created yet - uuid_vec_t::iterator itPendingAttachLink = mPendingAttachLinks.begin(); - while (itPendingAttachLink != mPendingAttachLinks.end()) + uuid_set_t pendingAttachments; + if (LLAttachmentsMgr::instance().getPendingAttachments(pendingAttachments)) { - const LLUUID& idItem = *itPendingAttachLink; - if ( (!gAgentAvatarp->isWearingAttachment(idItem)) || (isLinkInCOF(idItem)) ) + for (const LLUUID& idAttachItem : pendingAttachments) { - itPendingAttachLink = mPendingAttachLinks.erase(itPendingAttachLink); - continue; - } + if ( (!gAgentAvatarp->isWearingAttachment(idAttachItem)) || (isLinkedInCOF(idAttachItem)) ) + { + LLAttachmentsMgr::instance().clearPendingAttachmentLink(idAttachItem); + continue; + } - LLViewerInventoryItem* pItem = gInventory.getItem(idItem); - if (pItem) - { - obj_items.push_back(pItem); + LLViewerInventoryItem* pAttachItem = gInventory.getItem(idAttachItem); + if (pAttachItem) + { + obj_items.push_back(pAttachItem); + } } - - ++itPendingAttachLink; } - // Don't remove attachments until avatar is fully loaded (should reduce random attaching/detaching/reattaching at log-on) - LL_DEBUGS("Avatar") << self_av_string() << "Updating " << obj_items.count() << " attachments" << LL_ENDL; - LLAgentWearables::userUpdateAttachments(obj_items, !gAgentAvatarp->isFullyLoaded()); + LL_DEBUGS("Avatar") << self_av_string() << "Updating " << obj_items.size() << " attachments" << LL_ENDL; + + LLAgentWearables::llvo_vec_t objects_to_remove; + LLAgentWearables::llvo_vec_t objects_to_retain; + LLInventoryModel::item_array_t items_to_add; + LLAgentWearables::findAttachmentsAddRemoveInfo(obj_items, objects_to_remove, objects_to_retain, items_to_add); + + // Here we remove the attachment pos overrides for *all* + // attachments, even those that are not being removed. This is + // needed to get joint positions all slammed down to their + // pre-attachment states. + gAgentAvatarp->clearAttachmentOverrides(); + + // Take off the attachments that will no longer be in the outfit. + // (but don't remove attachments until avatar is fully loaded - should reduce random attaching/detaching/reattaching at log-on) + if (gAgentAvatarp->isFullyLoaded()) + { + LL_DEBUGS("Avatar") << self_av_string() << "Removing " << objects_to_remove.size() << " attachments" << LL_ENDL; + LLAgentWearables::userRemoveMultipleAttachments(objects_to_remove); + } + + // Restore attachment pos overrides for the attachments that are remaining in the outfit. + for (LLAgentWearables::llvo_vec_t::iterator it = objects_to_retain.begin(); it != objects_to_retain.end(); ++it) + { + LLViewerObject *objectp = *it; + gAgentAvatarp->addAttachmentOverridesForObject(objectp); + } + + // Add new attachments to match those requested. + LL_DEBUGS("Avatar") << self_av_string() << "Adding " << items_to_add.size() << " attachments" << LL_ENDL; + LLAgentWearables::userAttachMultipleAttachments(items_to_add); } // [/SL:KB] - if(!wear_items.count()) + if(!wear_items.size()) { LLNotificationsUtil::add("CouldNotPutOnOutfit"); return; @@ -2427,6 +2664,8 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering) sortItemsByActualDescription(wear_items); + LL_DEBUGS("Avatar") << "HP block starts" << LL_ENDL; + LLTimer hp_block_timer; LLWearableHoldingPattern* holder = new LLWearableHoldingPattern; // holder->setObjItems(obj_items); @@ -2437,19 +2676,19 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering) // callback will be called (and this object deleted) // before the final getNextData(). - for(S32 i = 0; i < wear_items.count(); ++i) + // Fault injection: use debug setting to test asset + // fetch failures (should be replaced by new defaults in + // lost&found). + U32 skip_type = gSavedSettings.getU32("ForceAssetFail"); +// [RLVa:KB] - Checked: 2010-12-11 (RLVa-1.2.2) + U32 missing_type = gSavedSettings.getU32("ForceMissingType"); +// [/RLVa:KB] + + for(U32 i = 0; i < wear_items.size(); ++i) { - LLViewerInventoryItem *item = wear_items.get(i); + LLViewerInventoryItem *item = wear_items.at(i); LLViewerInventoryItem *linked_item = item ? item->getLinkedItem() : NULL; - // Fault injection: use debug setting to test asset - // fetch failures (should be replaced by new defaults in - // lost&found). - U32 skip_type = gSavedSettings.getU32("ForceAssetFail"); -// [RLVa:KB] - Checked: 2010-12-11 (RLVa-1.2.2c) | Added: RLVa-1.2.2c - U32 missing_type = gSavedSettings.getU32("ForceMissingType"); -// [/RLVa:KB] - if (item && item->getIsLinkType() && linked_item) { LLFoundData found(linked_item->getUUID(), @@ -2459,7 +2698,7 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering) linked_item->isWearableType() ? linked_item->getWearableType() : LLWearableType::WT_INVALID ); -// [RLVa:KB] - Checked: 2010-12-15 (RLVa-1.2.2c) | Modified: RLVa-1.2.2c +// [RLVa:KB] - Checked: 2010-12-15 (RLVa-1.2.2) #ifdef LL_RELEASE_FOR_DOWNLOAD // Don't allow forcing an invalid wearable if the initial wearables aren't set yet, or if any wearable type is currently locked if ( (!rlv_handler_t::isEnabled()) || @@ -2471,11 +2710,11 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering) continue; } // [/RLVa:KB] - if (skip_type != LLWearableType::WT_INVALID && skip_type == found.mWearableType) - { - found.mAssetID.generate(); // Replace with new UUID, guaranteed not to exist in DB - } -// [RLVa:KB] - Checked: 2010-12-15 (RLVa-1.2.2c) | Modified: RLVa-1.2.2c + if (skip_type != LLWearableType::WT_INVALID && skip_type == found.mWearableType) + { + found.mAssetID.generate(); // Replace with new UUID, guaranteed not to exist in DB + } +// [RLVa:KB] - Checked: 2010-12-15 (RLVa-1.2.2) } // [/RLVa:KB] //pushing back, not front, to preserve order of wearables for LLAgentWearables @@ -2485,23 +2724,23 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering) { if (!item) { - llwarns << "Attempt to wear a null item " << llendl; + LL_WARNS() << "Attempt to wear a null item " << LL_ENDL; } else if (!linked_item) { - llwarns << "Attempt to wear a broken link [ name:" << item->getName() << " ] " << llendl; + LL_WARNS() << "Attempt to wear a broken link [ name:" << item->getName() << " ] " << LL_ENDL; } } } - selfStartPhase("get_wearables"); + selfStartPhase("get_wearables_2"); for (LLWearableHoldingPattern::found_list_t::iterator it = holder->getFoundList().begin(); it != holder->getFoundList().end(); ++it) { LLFoundData& found = *it; - lldebugs << self_av_string() << "waiting for onWearableAssetFetch callback, asset " << found.mAssetID.asString() << llendl; + LL_DEBUGS() << self_av_string() << "waiting for onWearableAssetFetch callback, asset " << found.mAssetID.asString() << LL_ENDL; // Fetch the wearables about to be worn. LLWearableList::instance().getAsset(found.mAssetID, @@ -2518,20 +2757,32 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering) { doOnIdleRepeating(boost::bind(&LLWearableHoldingPattern::pollFetchCompletion,holder)); } + post_update_func(); + + LL_DEBUGS("Avatar") << "HP block ends, elapsed " << hp_block_timer.getElapsedTimeF32() << LL_ENDL; } // [SL:KB] - Patch: Appearance-MixedViewers | Checked: 2010-04-02 (Catznip-3.0.0a) | Added: Catznip-2.0.0a -void LLAppearanceMgr::updateAppearanceFromInitialWearables(LLInventoryModel::item_array_t& initial_items) +void LLAppearanceMgr::updateAppearanceFromInitialWearables(LLInventoryObject::const_object_list_t& initial_items) { const LLUUID& idCOF = getCOF(); // Remove current COF contents - purgeCategory(idCOF, false); - gInventory.notifyObservers(); - + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + gInventory.collectDescendents(idCOF, cats, items, + LLInventoryModel::EXCLUDE_TRASH); + for (U32 i = 0; i < items.size(); ++i) + { + LLViewerInventoryItem *item = items.at(i); + if (item->getIsLinkType()) + { + remove_inventory_item(item->getUUID(), NULL); + } + } // Create links to new COF contents LLPointer link_waiter = new LLUpdateAppearanceOnDestroy(); - linkAll(idCOF, initial_items, link_waiter); + link_inventory_array(idCOF, initial_items, link_waiter); } // [/SL:KB] @@ -2589,6 +2840,12 @@ void LLAppearanceMgr::wearInventoryCategory(LLInventoryCategory* category, bool { if(!category) return; + // Attachments getting lost on TP: + // We'll be sending the outfit change request to our current region, + // so we'll learn them if they've been sending bad kills. + // We don't take kindly to that sorta behaviour round these parts. + gAgent.setIsCrossingRegion(false); + selfClearPhases(); selfStartPhase("wear_inventory_category"); @@ -2597,10 +2854,35 @@ void LLAppearanceMgr::wearInventoryCategory(LLInventoryCategory* category, bool LL_INFOS("Avatar") << self_av_string() << "wearInventoryCategory( " << category->getName() << " )" << LL_ENDL; - selfStartPhase("wear_inventory_category_fetch"); - callAfterCategoryFetch(category->getUUID(),boost::bind(&LLAppearanceMgr::wearCategoryFinal, - &LLAppearanceMgr::instance(), - category->getUUID(), copy, append)); + // If we are copying from library, attempt to use AIS to copy the category. + if (copy && AISAPI::isAvailable()) + { + LLUUID parent_id; + parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING); + if (parent_id.isNull()) + { + parent_id = gInventory.getRootFolderID(); + } + + LLPointer copy_cb = new LLWearCategoryAfterCopy(append); + LLPointer track_cb = new LLTrackPhaseWrapper( + std::string("wear_inventory_category_callback"), copy_cb); + + AISAPI::completion_t cr = boost::bind(&doAppearanceCb, track_cb, _1); + AISAPI::CopyLibraryCategory(category->getUUID(), parent_id, false, cr); + } + else + { + selfStartPhase("wear_inventory_category_fetch"); + callAfterCategoryFetch(category->getUUID(),boost::bind(&LLAppearanceMgr::wearCategoryFinal, + &LLAppearanceMgr::instance(), + category->getUUID(), copy, append)); + } +} + +S32 LLAppearanceMgr::getActiveCopyOperations() const +{ + return LLCallAfterInventoryCopyMgr::getInstanceCount(); } void LLAppearanceMgr::wearCategoryFinal(LLUUID& cat_id, bool copy_items, bool append) @@ -2701,10 +2983,10 @@ void LLAppearanceMgr::wearInventoryCategoryOnAvatar( LLInventoryCategory* catego LLAppearanceMgr::changeOutfit(TRUE, category->getUUID(), append); } +// FIXME do we really want to search entire inventory for matching name? void LLAppearanceMgr::wearOutfitByName(const std::string& name) { LL_INFOS("Avatar") << self_av_string() << "Wearing category " << name << LL_ENDL; - //inc_busy_count(); LLInventoryModel::cat_array_t cat_array; LLInventoryModel::item_array_t item_array; @@ -2716,10 +2998,10 @@ void LLAppearanceMgr::wearOutfitByName(const std::string& name) has_name); bool copy_items = false; LLInventoryCategory* cat = NULL; - if (cat_array.count() > 0) + if (cat_array.size() > 0) { // Just wear the first one that matches - cat = cat_array.get(0); + cat = cat_array.at(0); } else { @@ -2728,9 +3010,9 @@ void LLAppearanceMgr::wearOutfitByName(const std::string& name) item_array, LLInventoryModel::EXCLUDE_TRASH, has_name); - if(cat_array.count() > 0) + if(cat_array.size() > 0) { - cat = cat_array.get(0); + cat = cat_array.at(0); copy_items = true; } } @@ -2741,11 +3023,9 @@ void LLAppearanceMgr::wearOutfitByName(const std::string& name) } else { - llwarns << "Couldn't find outfit " < cb = NULL, std::string description = ""): + LLDeferredCOFLinkObserver(const LLUUID& item_id, LLPointer cb, const std::string& description): mItemID(item_id), - mDoUpdate(do_update), mCallback(cb), mDescription(description) { @@ -2775,14 +3054,13 @@ class LLDeferredCOFLinkObserver: public LLInventoryObserver if (item) { gInventory.removeObserver(this); - LLAppearanceMgr::instance().addCOFItemLink(item,mDoUpdate,mCallback); + LLAppearanceMgr::instance().addCOFItemLink(item, mCallback, mDescription); delete this; } } private: const LLUUID mItemID; - bool mDoUpdate; std::string mDescription; LLPointer mCallback; }; @@ -2790,47 +3068,30 @@ class LLDeferredCOFLinkObserver: public LLInventoryObserver // BAP - note that this runs asynchronously if the item is not already loaded from inventory. // Dangerous if caller assumes link will exist after calling the function. -void LLAppearanceMgr::addCOFItemLink(const LLUUID &item_id, bool do_update, LLPointer cb, const std::string description) +void LLAppearanceMgr::addCOFItemLink(const LLUUID &item_id, + LLPointer cb, + const std::string description) { const LLInventoryItem *item = gInventory.getItem(item_id); if (!item) { - LLDeferredCOFLinkObserver *observer = new LLDeferredCOFLinkObserver(item_id, do_update, cb, description); + LLDeferredCOFLinkObserver *observer = new LLDeferredCOFLinkObserver(item_id, cb, description); gInventory.addObserver(observer); } else { - addCOFItemLink(item, do_update, cb, description); + addCOFItemLink(item, cb, description); } } -void modified_cof_cb(const LLUUID& inv_item) +void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item, + LLPointer cb, + const std::string description) { - LLAppearanceMgr::instance().updateAppearanceFromCOF(); - - // Start editing the item if previously requested. - gAgentWearables.editWearableIfRequested(inv_item); - - // TODO: camera mode may not be changed if a debug setting is tweaked - if( LLFloaterCustomize::instanceExists() ) - { - // If we're in appearance editing mode, the current tab may need to be refreshed - /*LLSidepanelAppearance *panel = dynamic_cast(LLFloaterSidePanelContainer::getPanel("appearance")); - if (panel) - { - panel->showDefaultSubpart(); - }*/ - LLFloaterCustomize::getInstance()->switchToDefaultSubpart(); - } -} - -void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item, bool do_update, LLPointer cb, const std::string description) -{ - std::string link_description = description; const LLViewerInventoryItem *vitem = dynamic_cast(item); if (!vitem) { - llwarns << "not an llviewerinventoryitem, failed" << llendl; + LL_WARNS() << "not an llviewerinventoryitem, failed" << LL_ENDL; return; } @@ -2843,11 +3104,10 @@ void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item, bool do_update item_array, LLInventoryModel::EXCLUDE_TRASH); bool linked_already = false; - U32 count = 0; - for (S32 i=0; igetWearableType(); const bool is_body_part = (wearable_type == LLWearableType::WT_SHAPE) @@ -2863,15 +3123,14 @@ void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item, bool do_update // type? If so, new item will replace old. else if ((vitem->isWearableType()) && (vitem->getWearableType() == wearable_type)) { - ++count; - if (is_body_part && inv_item->getIsLinkType() && (vitem->getWearableType() == wearable_type)) + if (is_body_part && inv_item->getIsLinkType()) { - gInventory.purgeObject(inv_item->getUUID()); + remove_inventory_item(inv_item->getUUID(), cb); } - else if (count >= LLAgentWearables::MAX_CLOTHING_PER_TYPE) + else if (!gAgentWearables.canAddWearable(wearable_type)) { - // MULTI-WEARABLES: make sure we don't go over MAX_CLOTHING_PER_TYPE - gInventory.purgeObject(inv_item->getUUID()); + // MULTI-WEARABLES: make sure we don't go over clothing limits + remove_inventory_item(inv_item->getUUID(), cb); } // [SL:KB] - Patch: Appearance-WearableDuplicateAssets | Checked: 2011-07-24 (Catznip-2.6.0e) | Added: Catznip-2.6.0e else if ( (vitem->getWearableType() == wearable_type) && (vitem->getAssetUUID() == inv_item->getAssetUUID()) ) @@ -2883,62 +3142,43 @@ void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item, bool do_update } } - if (linked_already) - { - if (do_update) - { - LLAppearanceMgr::updateAppearanceFromCOF(); - } - return; - } - else + if (!linked_already) { - if(do_update && cb.isNull()) - { - cb = new LLBoostFuncInventoryCallback(modified_cof_cb); - } - if (vitem->getIsLinkType()) - { - link_description = vitem->getActualDescription(); - } - link_inventory_item( gAgent.getID(), - vitem->getLinkedUUID(), - getCOF(), - vitem->getName(), - link_description, - LLAssetType::AT_LINK, - cb); + LLViewerInventoryItem *copy_item = new LLViewerInventoryItem; + copy_item->copyViewerItem(vitem); + copy_item->setDescription(description); + link_inventory_object(getCOF(), copy_item, cb); } - return; } LLInventoryModel::item_array_t LLAppearanceMgr::findCOFItemLinks(const LLUUID& item_id) { - LLInventoryModel::item_array_t result; - const LLViewerInventoryItem *vitem = - dynamic_cast(gInventory.getItem(item_id)); - if (vitem) + LLUUID linked_id = gInventory.getLinkedItemID(item_id); + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + gInventory.collectDescendents(LLAppearanceMgr::getCOF(), + cat_array, + item_array, + LLInventoryModel::EXCLUDE_TRASH); + for (U32 i=0; igetLinkedUUID() == linked_id) { - const LLViewerInventoryItem* inv_item = item_array.get(i).get(); - if (inv_item->getLinkedUUID() == vitem->getLinkedUUID()) - { - result.put(item_array.get(i)); - } + result.push_back(item_array.at(i)); } } return result; } +bool LLAppearanceMgr::isLinkedInCOF(const LLUUID& item_id) +{ + LLInventoryModel::item_array_t links = LLAppearanceMgr::instance().findCOFItemLinks(item_id); + return links.size() > 0; +} + void LLAppearanceMgr::removeAllClothesFromAvatar() { // Fetch worn clothes (i.e. the ones in COF). @@ -2949,8 +3189,7 @@ void LLAppearanceMgr::removeAllClothesFromAvatar() dummy, clothing_items, LLInventoryModel::EXCLUDE_TRASH, - is_clothing, - false); + is_clothing); uuid_vec_t item_ids; for (LLInventoryModel::item_array_t::iterator it = clothing_items.begin(); it != clothing_items.end(); ++it) @@ -2994,7 +3233,10 @@ void LLAppearanceMgr::removeAllAttachmentsFromAvatar() removeItemsFromAvatar(ids_to_remove); } -void LLAppearanceMgr::removeCOFItemLinks(const LLUUID& item_id) +//void LLAppearanceMgr::removeCOFItemLinks(const LLUUID& item_id, LLPointer cb) +// [SL:KB] - Patch: Appearance-AISFilter | Checked: 2015-05-02 (Catznip-3.7) +void LLAppearanceMgr::removeCOFItemLinks(const LLUUID& item_id, LLPointer cb, bool immediate_delete) +// [/SL:KB] { gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); @@ -3004,27 +3246,28 @@ void LLAppearanceMgr::removeCOFItemLinks(const LLUUID& item_id) cat_array, item_array, LLInventoryModel::EXCLUDE_TRASH); - for (S32 i=0; igetIsLinkType() && item->getLinkedUUID() == item_id) { // [RLVa:KB] - Checked: 2013-02-12 (RLVa-1.4.8) -#if LL_RELEASE_WITH_DEBUG_INFO || LL_DEBUG - // NOTE-RLVa: debug-only, can be removed down the line if (rlv_handler_t::isEnabled()) { RLV_ASSERT(rlvPredCanRemoveItem(item)); } -#endif // LL_RELEASE_WITH_DEBUG_INFO || LL_DEBUG // [/RLVa:KB] - - gInventory.purgeObject(item->getUUID()); +// bool immediate_delete = false; +// if (item->getType() == LLAssetType::AT_OBJECT) +// { +// immediate_delete = true; +// } + remove_inventory_item(item->getUUID(), cb, immediate_delete); } } } -void LLAppearanceMgr::removeCOFLinksOfType(LLWearableType::EType type) +void LLAppearanceMgr::removeCOFLinksOfType(LLWearableType::EType type, LLPointer cb, bool immediate_delete) { LLFindWearablesOfType filter_wearables_of_type(type); LLInventoryModel::cat_array_t cats; @@ -3038,16 +3281,12 @@ void LLAppearanceMgr::removeCOFLinksOfType(LLWearableType::EType type) if (item->getIsLinkType()) // we must operate on links only { // [RLVa:KB] - Checked: 2013-02-12 (RLVa-1.4.8) -#if LL_RELEASE_WITH_DEBUG_INFO || LL_DEBUG - // NOTE-RLVa: debug-only, can be removed down the line if (rlv_handler_t::isEnabled()) { RLV_ASSERT(rlvPredCanRemoveItem(item)); } -#endif // LL_RELEASE_WITH_DEBUG_INFO || LL_DEBUG // [/RLVa:KB] - - gInventory.purgeObject(item->getUUID()); + remove_inventory_item(item->getUUID(), cb, immediate_delete); } } } @@ -3056,7 +3295,7 @@ bool sort_by_linked_uuid(const LLViewerInventoryItem* item1, const LLViewerInven { if (!item1 || !item2) { - llwarning("item1, item2 cannot be null, something is very wrong", 0); + LL_WARNS() << "item1, item2 cannot be null, something is very wrong" << LL_ENDL; return true; } @@ -3086,7 +3325,7 @@ void LLAppearanceMgr::updateIsDirty() if (base_outfit.notNull()) { - LLIsOfAssetType collector = LLIsOfAssetType(LLAssetType::AT_LINK); + LLIsValidItemLink collector; LLInventoryModel::cat_array_t cof_cats; LLInventoryModel::item_array_t cof_items; @@ -3098,8 +3337,9 @@ void LLAppearanceMgr::updateIsDirty() gInventory.collectDescendentsIf(base_outfit, outfit_cats, outfit_items, LLInventoryModel::EXCLUDE_TRASH, collector); - if(outfit_items.count() != cof_items.count()) + if(outfit_items.size() != cof_items.size()) { + LL_DEBUGS("Avatar") << "item count different - base " << outfit_items.size() << " cof " << cof_items.size() << LL_ENDL; // Current outfit folder should have one more item than the outfit folder. // this one item is the link back to the outfit folder itself. mOutfitIsDirty = true; @@ -3112,18 +3352,37 @@ void LLAppearanceMgr::updateIsDirty() for (U32 i = 0; i < cof_items.size(); ++i) { - LLViewerInventoryItem *item1 = cof_items.get(i); - LLViewerInventoryItem *item2 = outfit_items.get(i); + LLViewerInventoryItem *item1 = cof_items.at(i); + LLViewerInventoryItem *item2 = outfit_items.at(i); if (item1->getLinkedUUID() != item2->getLinkedUUID() || item1->getName() != item2->getName() || item1->getActualDescription() != item2->getActualDescription()) { + if (item1->getLinkedUUID() != item2->getLinkedUUID()) + { + LL_DEBUGS("Avatar") << "link id different " << LL_ENDL; + } + else + { + if (item1->getName() != item2->getName()) + { + LL_DEBUGS("Avatar") << "name different " << item1->getName() << " " << item2->getName() << LL_ENDL; + } + if (item1->getActualDescription() != item2->getActualDescription()) + { + LL_DEBUGS("Avatar") << "desc different " << item1->getActualDescription() + << " " << item2->getActualDescription() + << " names " << item1->getName() << " " << item2->getName() << LL_ENDL; + } + } mOutfitIsDirty = true; return; } } } + llassert(!mOutfitIsDirty); + LL_DEBUGS("Avatar") << "clean" << LL_ENDL; } // *HACK: Must match name in Library or agent inventory @@ -3140,10 +3399,10 @@ void LLAppearanceMgr::copyLibraryGestures() // Copy gestures LLUUID lib_gesture_cat_id = - gInventory.findCategoryUUIDForType(LLFolderType::FT_GESTURE,false,true); + gInventory.findLibraryCategoryUUIDForType(LLFolderType::FT_GESTURE,false); if (lib_gesture_cat_id.isNull()) { - llwarns << "Unable to copy gestures, source category not found" << llendl; + LL_WARNS() << "Unable to copy gestures, source category not found" << LL_ENDL; } LLUUID dst_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_GESTURE); @@ -3192,7 +3451,7 @@ void LLAppearanceMgr::copyLibraryGestures() LLUUID cat_id = findDescendentCategoryIDByName(lib_gesture_cat_id,folder_name); if (cat_id.isNull()) { - llwarns << self_av_string() << "failed to find gesture folder for " << folder_name << llendl; + LL_WARNS() << self_av_string() << "failed to find gesture folder for " << folder_name << LL_ENDL; } else { @@ -3205,23 +3464,6 @@ void LLAppearanceMgr::copyLibraryGestures() } } -void LLAppearanceMgr::autopopulateOutfits() -{ - // If this is the very first time the user has logged into viewer2+ (from a legacy viewer, or new account) - // then auto-populate outfits from the library into the My Outfits folder. - - LL_INFOS("Avatar") << self_av_string() << "avatar fully visible" << LL_ENDL; - - static bool check_populate_my_outfits = true; - if (check_populate_my_outfits && - (LLInventoryModel::getIsFirstTimeInViewer2() - || gSavedSettings.getBOOL("MyOutfitsAutofill"))) - { - gAgentWearables.populateMyOutfitsFolder(); - } - check_populate_my_outfits = false; -} - // Handler for anything that's deferred until avatar de-clouds. void LLAppearanceMgr::onFirstFullyVisible() { @@ -3229,10 +3471,6 @@ void LLAppearanceMgr::onFirstFullyVisible() gAgentAvatarp->reportAvatarRezTime(); gAgentAvatarp->debugAvatarVisible(); - // The auto-populate is failing at the point of generating outfits - // folders, so don't do the library copy until that is resolved. - // autopopulateOutfits(); - // If this is the first time we've ever logged in, // then copy default gestures from the library. if (gAgent.isFirstLogin()) { @@ -3247,34 +3485,49 @@ void appearance_mgr_update_dirty_state() if (LLAppearanceMgr::instanceExists()) { LLAppearanceMgr::getInstance()->updateIsDirty(); + LLAppearanceMgr::getInstance()->setOutfitLocked(false); + gAgentWearables.notifyLoadingFinished(); } } -bool LLAppearanceMgr::updateBaseOutfit() +void update_base_outfit_after_ordering() { - if (isOutfitLocked()) - { - // don't allow modify locked outfit - llassert(!isOutfitLocked()); + LLAppearanceMgr& app_mgr = LLAppearanceMgr::instance(); + + LLPointer dirty_state_updater = + new LLBoostFuncInventoryCallback(no_op_inventory_func, appearance_mgr_update_dirty_state); + + //COF contains only links so we copy to the Base Outfit only links + const LLUUID base_outfit_id = app_mgr.getBaseOutfitUUID(); + bool copy_folder_links = false; + app_mgr.slamCategoryLinks(app_mgr.getCOF(), base_outfit_id, copy_folder_links, dirty_state_updater); + +} + +// Save COF changes - update the contents of the current base outfit +// to match the current COF. Fails if no current base outfit is set. +bool LLAppearanceMgr::updateBaseOutfit() +{ + if (isOutfitLocked()) + { + // don't allow modify locked outfit + llassert(!isOutfitLocked()); return false; } + setOutfitLocked(true); gAgentWearables.notifyLoadingStarted(); const LLUUID base_outfit_id = getBaseOutfitUUID(); if (base_outfit_id.isNull()) return false; + LL_DEBUGS("Avatar") << "saving cof to base outfit " << base_outfit_id << LL_ENDL; - updateClothingOrderingInfo(); - - // in a Base Outfit we do not remove items, only links - purgeCategory(base_outfit_id, false); - - LLPointer dirty_state_updater = - new LLBoostFuncInventoryCallback(no_op_inventory_func, appearance_mgr_update_dirty_state); - - //COF contains only links so we copy to the Base Outfit only links - shallowCopyCategoryContents(getCOF(), base_outfit_id, dirty_state_updater); + LLPointer cb = + new LLBoostFuncInventoryCallback(no_op_inventory_func, update_base_outfit_after_ordering); + // Really shouldn't be needed unless there's a race condition - + // updateAppearanceFromCOF() already calls updateClothingOrderingInfo. + updateClothingOrderingInfo(LLUUID::null, cb); return true; } @@ -3284,12 +3537,12 @@ void LLAppearanceMgr::divvyWearablesByType(const LLInventoryModel::item_array_t& items_by_type.resize(LLWearableType::WT_COUNT); if (items.empty()) return; - for (S32 i=0; igetActualDescription(); const std::string& desc2 = item2->getActualDescription(); @@ -3341,180 +3588,190 @@ struct WearablesOrderComparator //items with ordering information but not for the associated wearables type if (!item1_valid && item2_valid) return false; + else if (item1_valid && !item2_valid) + return true; - return true; + return item1->getName() < item2->getName(); } U32 mControlSize; }; -void LLAppearanceMgr::updateClothingOrderingInfo(LLUUID cat_id, bool update_base_outfit_ordering) +void LLAppearanceMgr::getWearableOrderingDescUpdates(LLInventoryModel::item_array_t& wear_items, + desc_map_t& desc_map) { - if (cat_id.isNull()) - { - cat_id = getCOF(); - if (update_base_outfit_ordering) - { - const LLUUID base_outfit_id = getBaseOutfitUUID(); - if (base_outfit_id.notNull()) - { - updateClothingOrderingInfo(base_outfit_id,false); - } - } - } - - // COF is processed if cat_id is not specified - LLInventoryModel::item_array_t wear_items; - getDescendentsOfAssetType(cat_id, wear_items, LLAssetType::AT_CLOTHING, false); - wearables_by_type_t items_by_type(LLWearableType::WT_COUNT); divvyWearablesByType(wear_items, items_by_type); - bool inventory_changed = false; for (U32 type = LLWearableType::WT_SHIRT; type < LLWearableType::WT_COUNT; type++) { - U32 size = items_by_type[type].size(); if (!size) continue; - + //sinking down invalid items which need reordering std::sort(items_by_type[type].begin(), items_by_type[type].end(), WearablesOrderComparator((LLWearableType::EType) type)); - + //requesting updates only for those links which don't have "valid" descriptions for (U32 i = 0; i < size; i++) { LLViewerInventoryItem* item = items_by_type[type][i]; if (!item) continue; - + std::string new_order_str = build_order_string((LLWearableType::EType)type, i); if (new_order_str == item->getActualDescription()) continue; - - item->setDescription(new_order_str); - item->setComplete(TRUE); - item->updateServer(FALSE); - gInventory.updateItem(item); - inventory_changed = true; + desc_map[item->getUUID()] = new_order_str; } } - - //*TODO do we really need to notify observers? - if (inventory_changed) gInventory.notifyObservers(); } -// This is intended for use with HTTP Clients/Responders, but is not -// specifically coupled with those classes. -class LLHTTPRetryPolicy: public LLThreadSafeRefCount +bool LLAppearanceMgr::validateClothingOrderingInfo(LLUUID cat_id) { -public: - LLHTTPRetryPolicy() {} - virtual ~LLHTTPRetryPolicy() {} - virtual bool shouldRetry(U32 status, F32& seconds_to_wait) = 0; -}; + // COF is processed if cat_id is not specified + if (cat_id.isNull()) + { + cat_id = getCOF(); + } -// Example of simplest possible policy, not necessarily recommended. -class LLAlwaysRetryImmediatelyPolicy: public LLHTTPRetryPolicy -{ -public: - LLAlwaysRetryImmediatelyPolicy() {} - bool shouldRetry(U32 status, F32& seconds_to_wait) + LLInventoryModel::item_array_t wear_items; + getDescendentsOfAssetType(cat_id, wear_items, LLAssetType::AT_CLOTHING); + + // Identify items for which desc needs to change. + desc_map_t desc_map; + getWearableOrderingDescUpdates(wear_items, desc_map); + + for (desc_map_t::const_iterator it = desc_map.begin(); + it != desc_map.end(); ++it) { - seconds_to_wait = 0.0; - return true; + const LLUUID& item_id = it->first; + const std::string& new_order_str = it->second; + LLViewerInventoryItem *item = gInventory.getItem(item_id); + LL_WARNS() << "Order validation fails: " << item->getName() + << " needs to update desc to: " << new_order_str + << " (from: " << item->getActualDescription() << ")" << LL_ENDL; } -}; + + return desc_map.size() == 0; +} -// Very general policy with geometric back-off after failures, -// up to a maximum delay, and maximum number of retries. -class LLAdaptiveRetryPolicy: public LLHTTPRetryPolicy +void LLAppearanceMgr::updateClothingOrderingInfo(LLUUID cat_id, + LLPointer cb) { -public: - LLAdaptiveRetryPolicy(F32 min_delay, F32 max_delay, F32 backoff_factor, U32 max_retries): - mMinDelay(min_delay), - mMaxDelay(max_delay), - mBackoffFactor(backoff_factor), - mMaxRetries(max_retries), - mDelay(min_delay), - mRetryCount(0) + // COF is processed if cat_id is not specified + if (cat_id.isNull()) { + cat_id = getCOF(); } - bool shouldRetry(U32 status, F32& seconds_to_wait) + LLInventoryModel::item_array_t wear_items; + getDescendentsOfAssetType(cat_id, wear_items, LLAssetType::AT_CLOTHING); + + // Identify items for which desc needs to change. + desc_map_t desc_map; + getWearableOrderingDescUpdates(wear_items, desc_map); + + for (desc_map_t::const_iterator it = desc_map.begin(); + it != desc_map.end(); ++it) { - seconds_to_wait = mDelay; - mDelay = llclamp(mDelay*mBackoffFactor,mMinDelay,mMaxDelay); - mRetryCount++; - return (mRetryCount<=mMaxRetries); + LLSD updates; + const LLUUID& item_id = it->first; + const std::string& new_order_str = it->second; + LLViewerInventoryItem *item = gInventory.getItem(item_id); + LL_DEBUGS("Avatar") << item->getName() << " updating desc to: " << new_order_str + << " (was: " << item->getActualDescription() << ")" << LL_ENDL; + updates["desc"] = new_order_str; + update_inventory_item(item_id,updates,cb); } - -private: - F32 mMinDelay; // delay never less than this value - F32 mMaxDelay; // delay never exceeds this value - F32 mBackoffFactor; // delay increases by this factor after each retry, up to mMaxDelay. - U32 mMaxRetries; // maximum number of times shouldRetry will return true. - F32 mDelay; // current delay. - U32 mRetryCount; // number of times shouldRetry has been called. -}; + +} extern AIHTTPTimeoutPolicy requestAgentUpdateAppearance_timeout; class RequestAgentUpdateAppearanceResponder: public LLHTTPClient::ResponderWithResult { + LOG_CLASS(RequestAgentUpdateAppearanceResponder); + + friend class LLAppearanceMgr; + public: virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return requestAgentUpdateAppearance_timeout; } - RequestAgentUpdateAppearanceResponder() - { - mRetryPolicy = new LLAdaptiveRetryPolicy(1.0, 32.0, 2.0, 10); - } + RequestAgentUpdateAppearanceResponder(); - virtual ~RequestAgentUpdateAppearanceResponder() - { - } + virtual ~RequestAgentUpdateAppearanceResponder(); + +private: + // Called when sendServerAppearanceUpdate called. May or may not + // trigger a request depending on various bits of state. + void onRequestRequested(); + + // Post the actual appearance request to cap. + void sendRequest(); + void debugCOF(const LLSD& content); + +protected: // Successful completion. - /* virtual */ void result(const LLSD& content) - { - LL_DEBUGS("Avatar") << "content: " << ll_pretty_print_sd(content) << LL_ENDL; - if (content["success"].asBoolean()) - { - LL_DEBUGS("Avatar") << "OK" << LL_ENDL; - } - else - { - onFailure(200); - } - } + /* virtual */ void httpSuccess(); // Error - /*virtual*/ void errorWithContent(U32 status, const std::string& reason, const LLSD& content) - { - llwarns << "appearance update request failed, status: " << status << " reason: " << reason << llendl; - LL_DEBUGS("Avatar") << "content: " << ll_pretty_print_sd(content) << LL_ENDL; - onFailure(status); - } + /*virtual*/ void httpFailure(); - void onFailure(U32 status) - { - F32 seconds_to_wait; - if (mRetryPolicy->shouldRetry(status,seconds_to_wait)) - { - llinfos << "retrying" << llendl; - doAfterInterval(boost::bind(&LLAppearanceMgr::requestServerAppearanceUpdate, - LLAppearanceMgr::getInstance(), - LLHTTPClient::ResponderPtr(this)), - seconds_to_wait); - } - else - { - llwarns << "giving up after too many retries" << llendl; - } - } + void onFailure(); + void onSuccess(); + S32 mInFlightCounter; + LLTimer mInFlightTimer; LLPointer mRetryPolicy; /*virtual*/ char const* getName(void) const { return "RequestAgentUpdateAppearanceResponder"; } + /*virtual*/ bool needsHeaders() const { return true; } }; -void LLAppearanceMgr::requestServerAppearanceUpdate(LLHTTPClient::ResponderPtr responder_ptr) +RequestAgentUpdateAppearanceResponder::RequestAgentUpdateAppearanceResponder() +{ + bool retry_on_4xx = true; + mRetryPolicy = new LLAdaptiveRetryPolicy(1.0, 32.0, 2.0, 10, retry_on_4xx); + mInFlightCounter = 0; +} + +RequestAgentUpdateAppearanceResponder::~RequestAgentUpdateAppearanceResponder() +{ +} + +void RequestAgentUpdateAppearanceResponder::onRequestRequested() +{ + // If we have already received an update for this or higher cof version, ignore. + S32 cof_version = LLAppearanceMgr::instance().getCOFVersion(); + S32 last_rcv = gAgentAvatarp->mLastUpdateReceivedCOFVersion; + S32 last_req = gAgentAvatarp->mLastUpdateRequestCOFVersion; + LL_DEBUGS("Avatar") << "cof_version " << cof_version + << " last_rcv " << last_rcv + << " last_req " << last_req + << " in flight " << mInFlightCounter << LL_ENDL; + if ((mInFlightCounter>0) && (mInFlightTimer.hasExpired())) + { + LL_WARNS("Avatar") << "in flight timer expired, resetting " << LL_ENDL; + mInFlightCounter = 0; + } + if (cof_version < last_rcv) + { + LL_DEBUGS("Avatar") << "Have already received update for cof version " << last_rcv + << " will not request for " << cof_version << LL_ENDL; + return; + } + if (mInFlightCounter>0 && last_req >= cof_version) + { + LL_DEBUGS("Avatar") << "Request already in flight for cof version " << last_req + << " will not request for " << cof_version << LL_ENDL; + return; + } + + // Actually send the request. + LL_DEBUGS("Avatar") << "ATT sending bake request for cof_version " << cof_version << LL_ENDL; + mRetryPolicy->reset(); + sendRequest(); +} + +void RequestAgentUpdateAppearanceResponder::sendRequest() { if (gAgentAvatarp->isEditingAppearance()) { @@ -3524,51 +3781,270 @@ void LLAppearanceMgr::requestServerAppearanceUpdate(LLHTTPClient::ResponderPtr r if (!gAgent.getRegion()) { - llwarns << "Region not set, cannot request server appearance update" << llendl; - return; //Avoid a crash here. RequestAgentUpdateAppearanceResponder crams requestServerAppearanceUpdate into an event... - //which results in gAgent.getRegion() legitimately returning NULL under some scenarios. + LL_WARNS() << "Region not set, cannot request server appearance update" << LL_ENDL; + return; } if (gAgent.getRegion()->getCentralBakeVersion()==0) { - llwarns << "Region does not support baking" << llendl; + LL_WARNS() << "Region does not support baking" << LL_ENDL; } std::string url = gAgent.getRegion()->getCapability("UpdateAvatarAppearance"); if (url.empty()) { - llwarns << "No cap for UpdateAvatarAppearance." << llendl; + LL_WARNS() << "No cap for UpdateAvatarAppearance." << LL_ENDL; return; } LLSD body; - S32 cof_version = getCOFVersion(); + S32 cof_version = LLAppearanceMgr::instance().getCOFVersion(); body["cof_version"] = cof_version; - LL_DEBUGS("Avatar") << "my_cof_version " << cof_version << llendl; + LL_DEBUGS("Avatar") << "request url " << url << " my_cof_version " << cof_version << LL_ENDL; + + mInFlightCounter++; + mInFlightTimer.setTimerExpirySec(60.0); + LLHTTPClient::post(url, body, this); + llassert(cof_version >= gAgentAvatarp->mLastUpdateRequestCOFVersion); + gAgentAvatarp->mLastUpdateRequestCOFVersion = cof_version; +} + +void RequestAgentUpdateAppearanceResponder::debugCOF(const LLSD& content) +{ + LL_INFOS("Avatar") << "AIS COF, version received: " << content["expected"].asInteger() + << " ================================= " << LL_ENDL; + uuid_set_t ais_items, local_items; + const LLSD& cof_raw = content["cof_raw"]; + for (LLSD::array_const_iterator it = cof_raw.beginArray(); + it != cof_raw.endArray(); ++it) + { + const LLSD& item = *it; + if (item["parent_id"].asUUID() == LLAppearanceMgr::instance().getCOF()) + { + ais_items.insert(item["item_id"].asUUID()); + if (item["type"].asInteger() == 24) // link + { + LL_INFOS("Avatar") << "AIS Link: item_id: " << item["item_id"].asUUID() + << " linked_item_id: " << item["asset_id"].asUUID() + << " name: " << item["name"].asString() + << LL_ENDL; + } + else if (item["type"].asInteger() == 25) // folder link + { + LL_INFOS("Avatar") << "AIS Folder link: item_id: " << item["item_id"].asUUID() + << " linked_item_id: " << item["asset_id"].asUUID() + << " name: " << item["name"].asString() + << LL_ENDL; + } + else + { + LL_INFOS("Avatar") << "AIS Other: item_id: " << item["item_id"].asUUID() + << " linked_item_id: " << item["asset_id"].asUUID() + << " name: " << item["name"].asString() + << " type: " << item["type"].asInteger() + << LL_ENDL; + } + } + } + LL_INFOS("Avatar") << LL_ENDL; + LL_INFOS("Avatar") << "Local COF, version requested: " << content["observed"].asInteger() + << " ================================= " << LL_ENDL; + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + gInventory.collectDescendents(LLAppearanceMgr::instance().getCOF(), + cat_array, item_array, LLInventoryModel::EXCLUDE_TRASH); + for (U32 i = 0; i < item_array.size(); i++) + { + const LLViewerInventoryItem* inv_item = item_array.at(i).get(); + local_items.insert(inv_item->getUUID()); + LL_INFOS("Avatar") << "LOCAL: item_id: " << inv_item->getUUID() + << " linked_item_id: " << inv_item->getLinkedUUID() + << " name: " << inv_item->getName() + << " parent: " << inv_item->getParentUUID() + << LL_ENDL; + } + LL_INFOS("Avatar") << " ================================= " << LL_ENDL; + S32 local_only = 0, ais_only = 0; + for (auto it = local_items.begin(); it != local_items.end(); ++it) + { + if (ais_items.find(*it) == ais_items.end()) + { + LL_INFOS("Avatar") << "LOCAL ONLY: " << *it << LL_ENDL; + local_only++; + } + } + for (auto it = ais_items.begin(); it != ais_items.end(); ++it) + { + if (local_items.find(*it) == local_items.end()) + { + LL_INFOS("Avatar") << "AIS ONLY: " << *it << LL_ENDL; + ais_only++; + } + } + if (local_only == 0 && ais_only == 0) + { + LL_INFOS("Avatar") << "COF contents identical, only version numbers differ (req " + << content["observed"].asInteger() + << " rcv " << content["expected"].asInteger() + << ")" << LL_ENDL; + } +} + +/* virtual */ void RequestAgentUpdateAppearanceResponder::httpSuccess() +{ + const LLSD& content = getContent(); + if (!content.isMap()) + { + failureResult(400, "Malformed response contents", content); + return; + } + if (content["success"].asBoolean()) + { + LL_DEBUGS("Avatar") << "succeeded" << LL_ENDL; + static LLCachedControl debug_ava_appr_msg(gSavedSettings, "DebugAvatarAppearanceMessage"); + if (debug_ava_appr_msg) + { + dump_sequential_xml(gAgentAvatarp->getFullname() + "_appearance_request_ok", content); + } + + onSuccess(); + } + else + { + failureResult(400, "Non-success response", content); + } +} + +void RequestAgentUpdateAppearanceResponder::onSuccess() +{ + mInFlightCounter = llmax(mInFlightCounter-1,0); +} + +/*virtual*/ void RequestAgentUpdateAppearanceResponder::httpFailure() +{ + LL_WARNS("Avatar") << "appearance update request failed, status " + << getStatus() << " reason " << getReason() << LL_ENDL; + + if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage")) + { + const LLSD& content = getContent(); + dump_sequential_xml(gAgentAvatarp->getFullname() + "_appearance_request_error", content); + debugCOF(content); + } + onFailure(); +} + +void RequestAgentUpdateAppearanceResponder::onFailure() +{ + mInFlightCounter = llmax(mInFlightCounter-1,0); + + F32 seconds_to_wait; + mRetryPolicy->onFailure(getStatus(), getResponseHeaders()); + if (mRetryPolicy->shouldRetry(seconds_to_wait)) + { + LL_INFOS() << "retrying" << LL_ENDL; + doAfterInterval(boost::bind(&RequestAgentUpdateAppearanceResponder::sendRequest,this), + seconds_to_wait); + } + else + { + LL_WARNS() << "giving up after too many retries" << LL_ENDL; + } +} + + +LLSD LLAppearanceMgr::dumpCOF() const +{ + LLSD links = LLSD::emptyArray(); + LLMD5 md5; - //LLHTTPClient::ResponderPtr responder_ptr; - if (!responder_ptr.get()) + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + gInventory.collectDescendents(getCOF(),cat_array,item_array,LLInventoryModel::EXCLUDE_TRASH); + for (U32 i=0; igetUUID()); + md5.update((unsigned char*)item_id.mData, 16); + item["description"] = inv_item->getActualDescription(); + md5.update(inv_item->getActualDescription()); + item["asset_type"] = inv_item->getActualType(); + LLUUID linked_id(inv_item->getLinkedUUID()); + item["linked_id"] = linked_id; + md5.update((unsigned char*)linked_id.mData, 16); + + if (LLAssetType::AT_LINK == inv_item->getActualType()) + { + const LLViewerInventoryItem* linked_item = inv_item->getLinkedItem(); + if (NULL == linked_item) + { + LL_WARNS() << "Broken link for item '" << inv_item->getName() + << "' (" << inv_item->getUUID() + << ") during requestServerAppearanceUpdate" << LL_ENDL; + continue; + } + // Some assets may be 'hidden' and show up as null in the viewer. + //if (linked_item->getAssetUUID().isNull()) + //{ + // LL_WARNS() << "Broken link (null asset) for item '" << inv_item->getName() + // << "' (" << inv_item->getUUID() + // << ") during requestServerAppearanceUpdate" << LL_ENDL; + // continue; + //} + LLUUID linked_asset_id(linked_item->getAssetUUID()); + md5.update((unsigned char*)linked_asset_id.mData, 16); + U32 flags = linked_item->getFlags(); + md5.update(fmt::to_string(flags)); + } + else if (LLAssetType::AT_LINK_FOLDER != inv_item->getActualType()) + { + LL_WARNS() << "Non-link item '" << inv_item->getName() + << "' (" << inv_item->getUUID() + << ") type " << (S32) inv_item->getActualType() + << " during requestServerAppearanceUpdate" << LL_ENDL; + continue; + } + links.append(item); + } + LLSD result = LLSD::emptyMap(); + result["cof_contents"] = links; + char cof_md5sum[MD5HEX_STR_SIZE]; + md5.finalize(); + md5.hex_digest(cof_md5sum); + result["cof_md5sum"] = std::string(cof_md5sum); + return result; +} + +void LLAppearanceMgr::requestServerAppearanceUpdate() +{ + mAppearanceResponder->onRequestRequested(); +} + +std::string LLAppearanceMgr::getAppearanceServiceURL() const +{ + if (gSavedSettings.getString("AgentAppearanceServiceURL").empty()) { - responder_ptr = new RequestAgentUpdateAppearanceResponder; + return mAppearanceServiceURL; } - LLHTTPClient::post(url, body, responder_ptr); - llassert(cof_version >= mLastUpdateRequestCOFVersion); - mLastUpdateRequestCOFVersion = cof_version; + return gSavedSettings.getString("AgentAppearanceServiceURL"); // Singu TODO: Use "DebugAvatarAppearanceServiceURLOverride" } void show_created_outfit(const LLUUID& folder_id, bool show_panel = true) { if (!LLApp::isRunning()) { - llwarns << "called during shutdown, skipping" << llendl; + LL_WARNS() << "called during shutdown, skipping" << LL_ENDL; return; } + LL_DEBUGS("Avatar") << "called" << LL_ENDL; LLSD key; - //EXT-7727. For new accounts LLShowCreatedOutfit is created during login process - // add may be processed after login process is finished + //EXT-7727. For new accounts inventory callback is created during login process + // and may be processed after login process is finished // MULTI-WEARABLES TODO - /*if (mShowPanel) + /*if (show_panel) { + LL_DEBUGS("Avatar") << "showing panel" << LL_ENDL; LLFloaterSidePanelContainer::showPanel("appearance", "panel_outfits_inventory", key); } @@ -3576,12 +4052,20 @@ void show_created_outfit(const LLUUID& folder_id, bool show_panel = true) dynamic_cast(LLFloaterSidePanelContainer::getPanel("appearance", "outfitslist_tab")); if (outfits_list) { - outfits_list->setSelectedOutfitByUUID(mFolderID); + outfits_list->setSelectedOutfitByUUID(folder_id); }*/ LLAppearanceMgr::getInstance()->updateIsDirty(); gAgentWearables.notifyLoadingFinished(); // New outfit is saved. LLAppearanceMgr::getInstance()->updatePanelOutfitName(""); + + // For SSB, need to update appearance after we add a base outfit + // link, since, the COF version has changed. There is a race + // condition in initial outfit setup which can lead to rez + // failures - SH-3860. + LL_DEBUGS("Avatar") << "requesting appearance update after createBaseOutfitLink" << LL_ENDL; + LLPointer cb = new LLUpdateAppearanceOnDestroy; + LLAppearanceMgr::getInstance()->createBaseOutfitLink(folder_id, cb); } void scroll_to_folder(const LLUUID& folder_id) @@ -3621,38 +4105,58 @@ class LLBoostFuncInventoryCallbackFireOnce : public LLBoostFuncInventoryCallback bool mFired; }; -LLUUID LLAppearanceMgr::makeNewOutfitCore(const std::string& new_folder_name, bool show_panel, LLInventoryModel::item_array_t* items /*=NULL*/) +void LLAppearanceMgr::onOutfitFolderCreated(const LLUUID& folder_id, bool show_panel) { - if (!isAgentAvatarValid()) return LLUUID::null; - - gAgentWearables.notifyLoadingStarted(); - - // First, make a folder in the My Outfits directory. - const LLUUID parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); - LLUUID folder_id = gInventory.createNewCategory( - parent_id, - LLFolderType::FT_OUTFIT, - new_folder_name); - - updateClothingOrderingInfo(); - inventory_func_type fire_fn = no_op_inventory_func; if(show_panel) fire_fn = boost::bind(&scroll_to_folder,folder_id); + LLPointer cb = + new LLBoostFuncInventoryCallback(fire_fn, + boost::bind(&LLAppearanceMgr::onOutfitFolderCreatedAndClothingOrdered,this,folder_id,show_panel)); + updateClothingOrderingInfo(LLUUID::null, cb); +} - LLPointer cb = new LLBoostFuncInventoryCallbackFireOnce( fire_fn, - boost::bind(&show_created_outfit,folder_id,show_panel)); +void LLAppearanceMgr::onOutfitFolderCreatedAndClothingOrdered(const LLUUID& folder_id, bool show_panel) +{ + LLPointer cb = + new LLBoostFuncInventoryCallback(no_op_inventory_func, + boost::bind(show_created_outfit,folder_id,show_panel)); + bool copy_folder_links = false; + slamCategoryLinks(getCOF(), folder_id, copy_folder_links, cb); +} - if(items) - copyItems(folder_id,items,cb); - else - shallowCopyCategoryContents(getCOF(),folder_id,cb); +LLUUID LLAppearanceMgr::makeNewOutfitCore(const std::string& new_folder_name, bool show_panel, LLInventoryModel::item_array_t* items /*=NULL*/) +{ + if (!isAgentAvatarValid()) return LLUUID::null; - createBaseOutfitLink(folder_id, cb); + LL_DEBUGS("Avatar") << "creating new outfit" << LL_ENDL; - dumpCat(folder_id,"COF, new outfit"); + gAgentWearables.notifyLoadingStarted(); - return folder_id; + // First, make a folder in the My Outfits directory. + const LLUUID parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); + if (AISAPI::isAvailable()) + { + // cap-based category creation was buggy until recently. use + // existence of AIS as an indicator the fix is present. Does + // not actually use AIS to create the category. + inventory_func_type func = boost::bind(&LLAppearanceMgr::onOutfitFolderCreated,this,_1,show_panel); + LLUUID folder_id = gInventory.createNewCategory( + parent_id, + LLFolderType::FT_OUTFIT, + new_folder_name, + func); + return folder_id; + } + else + { + LLUUID folder_id = gInventory.createNewCategory( + parent_id, + LLFolderType::FT_OUTFIT, + new_folder_name); + onOutfitFolderCreated(folder_id, show_panel); + return folder_id; + } } LLUUID LLAppearanceMgr::makeNewOutfitLinks(const std::string& new_folder_name, bool show_panel/*=true*/) { @@ -3679,7 +4183,7 @@ LLUUID LLAppearanceMgr::makeNewOutfitLinks(const std::string& new_folder_name, L // 2) Stuff with requests via makeLink and makeCopy // 3) Call dispatch() // 4) Let the LLPointer go out of scope. -class LLCreateLegacyOutfit : public LLBoostFuncInventoryCallbackFireOnce +class LLCreateLegacyOutfit final : public LLBoostFuncInventoryCallbackFireOnce { public: LLCreateLegacyOutfit(const LLUUID& folder_id, inventory_func_type fire_func, nullary_func_type destroy_func = no_op) : @@ -3692,38 +4196,11 @@ class LLCreateLegacyOutfit : public LLBoostFuncInventoryCallbackFireOnce if (!LLApp::isRunning() || mFailed) return; - /* Singu Note: This wasn't working when we detached copyable attachments early, changeOutfit instead - LLInventoryModel::item_array_t body_items, wear_items, obj_items, gest_items; - for(std::set::const_iterator it = mWearItems.begin(); it != mWearItems.end(); ++it) - { - LLViewerInventoryItem* item = gInventory.getItem(*it); - if(item) - { - switch(item->getType()) - { - case LLAssetType::AT_BODYPART: - body_items.push_back(item); - break; - case LLAssetType::AT_CLOTHING: - wear_items.push_back(item); - break; - case LLAssetType::AT_OBJECT: - obj_items.push_back(item); - break; - case LLAssetType::AT_GESTURE: - gest_items.push_back(item); - break; - default: - break; - } - } - } - - if(!body_items.empty() || !wear_items.empty() || !obj_items.empty() || !gest_items.empty()) - LLAppearanceMgr::instance().updateCOF(body_items, wear_items, obj_items, gest_items, false); - */ LLAppearanceMgr::instance().changeOutfit(true, mFolderID, false); } + + void setFailed() { mFailed = true; } // Singu Note: Lies and hacks + private: class LLCreateBase : public LLInventoryCallback { @@ -3783,13 +4260,7 @@ class LLCreateLegacyOutfit : public LLBoostFuncInventoryCallbackFireOnce {} virtual void dispatch() { - link_inventory_item(gAgent.getID(), - mItem->getLinkedUUID(), - mFolderID, - mItem->getName(), - mDesc, - LLAssetType::AT_LINK, - this); + link_inventory_object(mFolderID,mItem.get(),this); } private: const std::string mDesc; @@ -3885,7 +4356,7 @@ class LLCreateLegacyOutfit : public LLBoostFuncInventoryCallbackFireOnce bool mFailed; std::vector > mPendingCopies; std::vector > mPendingLinks; - std::set mWearItems; + uuid_set_t mWearItems; std::vector mActiveRequests; }; @@ -3912,12 +4383,18 @@ LLUUID LLAppearanceMgr::makeNewOutfitLegacy(const std::string& new_folder_name, LLPointer cb = new LLCreateLegacyOutfit(folder_id,boost::bind(&scroll_to_folder,folder_id),boost::bind(&show_created_outfit,folder_id,true)); uuid_vec_t obj_ids; // Collect the uuids of copyable objects, in order to keep any changes made in the copies + bool use_all_links(gSavedSettings.getBOOL("LiruLegacyOutfitAllLinks")); for (LLInventoryModel::item_array_t::const_iterator iter = items.begin(); iter != items.end(); ++iter) { LLViewerInventoryItem* item = (*iter); + if (use_all_links) + { + cb->makeLink(item, item->LLInventoryItem::getDescription()); + continue; + } LLViewerInventoryItem* base_item = item->getLinkedItem() ? item->getLinkedItem() : item; bool is_copy = base_item->getPermissions().allowCopyBy(gAgent.getID()); bool is_obj = base_item->getInventoryType() == LLInventoryType::IT_OBJECT; @@ -3936,10 +4413,12 @@ LLUUID LLAppearanceMgr::makeNewOutfitLegacy(const std::string& new_folder_name, cb->makeCopy(item,is_multi && use_links); } } - if (gSavedSettings.getBOOL("LiruLegacyOutfitStoreObjChanges")) // As a last resort, someone may create a legacy outfit to undo attachment changes + if (!use_all_links && gSavedSettings.getBOOL("LiruLegacyOutfitStoreObjChanges")) // As a last resort, someone may create a legacy outfit to undo attachment changes LLAppearanceMgr::instance().removeItemsFromAvatar(obj_ids); // The avatar will have to go without these for now cb->dispatch(); + if (use_all_links) cb->setFailed(); // Cause an early return to avoid rewearing + return folder_id; } @@ -3951,49 +4430,106 @@ void LLAppearanceMgr::wearBaseOutfit() updateCOF(base_outfit_id); } -void LLAppearanceMgr::removeItemsFromAvatar(const uuid_vec_t& ids_to_remove) +//void LLAppearanceMgr::removeItemsFromAvatar(const uuid_vec_t& ids_to_remove) +// [SL:KB] - Patch: Appearance-Misc | Checked: 2015-05-05 (Catznip-3.7) +void LLAppearanceMgr::removeItemsFromAvatar(const uuid_vec_t& ids_to_remove, LLPointer cb /*= NULL*/, bool immediate_delete /*= false*/) +// [/SL:KB] { + if (ids_to_remove.empty()) + { + LL_WARNS() << "called with empty list, nothing to do" << LL_ENDL; + return; + } // [RLVa:KB] - Checked: 2013-02-12 (RLVa-1.4.8) - bool fUpdateAppearance = false; +// LLPointer cb = NULL; for (uuid_vec_t::const_iterator it = ids_to_remove.begin(); it != ids_to_remove.end(); ++it) { - const LLUUID& linked_item_id = gInventory.getLinkedItemID(*it); - if ( (rlv_handler_t::isEnabled()) && (!rlvPredCanRemoveItem(gInventory.getItem(linked_item_id))) ) + const LLUUID& id_to_remove = *it; + const LLUUID& linked_item_id = gInventory.getLinkedItemID(id_to_remove); + + if ( (rlv_handler_t::isEnabled()) && (!rlvPredCanRemoveItem(linked_item_id)) ) { continue; } - fUpdateAppearance = true; - removeCOFItemLinks(linked_item_id); - } + LLViewerInventoryItem *item = gInventory.getItem(linked_item_id); + if (item && item->getType() == LLAssetType::AT_OBJECT) + { + LL_DEBUGS("Avatar") << "ATT removing attachment " << item->getName() << " id " << item->getUUID() << LL_ENDL; + } + if (item && item->getType() == LLAssetType::AT_BODYPART) + { + continue; + } - if (fUpdateAppearance) - { - updateAppearanceFromCOF(); + if (!cb) + cb = new LLUpdateAppearanceOnDestroy(); + removeCOFItemLinks(linked_item_id, cb, immediate_delete); +// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2015-03-01 (Catznip-3.7) + LLAttachmentsMgr::instance().clearPendingAttachmentLink(linked_item_id); +// [/SL:KB] + addDoomedTempAttachment(linked_item_id); } // [/RLVa:KB] +//// LLPointer cb = new LLUpdateAppearanceOnDestroy; +//// [SL:KB] - Patch: Appearance-Misc | Checked: 2015-05-05 (Catznip-3.7) +// if (!cb) +// { +// cb = new LLUpdateAppearanceOnDestroy; +// } +//// [/SL:KB] // for (uuid_vec_t::const_iterator it = ids_to_remove.begin(); it != ids_to_remove.end(); ++it) // { // const LLUUID& id_to_remove = *it; // const LLUUID& linked_item_id = gInventory.getLinkedItemID(id_to_remove); -// removeCOFItemLinks(linked_item_id); +//// [SL:KB] - Patch: Appearance-Misc | Checked: 2015-05-05 (Catznip-3.7) +// removeCOFItemLinks(linked_item_id, cb, immediate_delete); +//// [/SL:KB] +//// removeCOFItemLinks(linked_item_id, cb); +// addDoomedTempAttachment(linked_item_id); // } -// updateAppearanceFromCOF(); } -void LLAppearanceMgr::removeItemFromAvatar(const LLUUID& id_to_remove) +//void LLAppearanceMgr::removeItemFromAvatar(const LLUUID& id_to_remove) +// [SL:KB] - Patch: Appearance-Misc | Checked: 2015-05-05 (Catznip-3.7) +void LLAppearanceMgr::removeItemFromAvatar(const LLUUID& id_to_remove, LLPointer cb /*= NULL*/, bool immediate_delete /*= false*/) +// [/SL:KB] { -// [RLVa:KB] - Checked: 2013-02-12 (RLVa-1.4.8) - LLUUID linked_item_id = gInventory.getLinkedItemID(id_to_remove); - if ( (rlv_handler_t::isEnabled()) && (!rlvPredCanRemoveItem(gInventory.getItem(linked_item_id))) ) + uuid_vec_t ids_to_remove; + ids_to_remove.push_back(id_to_remove); +// [SL:KB] - Patch: Appearance-Misc | Checked: 2015-05-05 (Catznip-3.7) + removeItemsFromAvatar(ids_to_remove, cb, immediate_delete); +// [/SL:KB] +// removeItemsFromAvatar(ids_to_remove); +} + + +// Adds the given item ID to mDoomedTempAttachmentIDs iff it's a temp attachment +void LLAppearanceMgr::addDoomedTempAttachment(const LLUUID& id_to_remove) +{ + LLViewerObject * attachmentp = gAgentAvatarp->findAttachmentByID(id_to_remove); + if (attachmentp && + attachmentp->isTempAttachment()) + { // If this is a temp attachment and we want to remove it, record the ID + // so it will be deleted when attachments are synced up with COF + mDoomedTempAttachmentIDs.insert(id_to_remove); + //LL_INFOS() << "Will remove temp attachment id " << id_to_remove << LL_ENDL; + } +} + +// Find AND REMOVES the given UUID from mDoomedTempAttachmentIDs +bool LLAppearanceMgr::shouldRemoveTempAttachment(const LLUUID& item_id) +{ + doomed_temp_attachments_t::iterator iter = mDoomedTempAttachmentIDs.find(item_id); + if (iter != mDoomedTempAttachmentIDs.end()) { - return; + mDoomedTempAttachmentIDs.erase(iter); + return true; } -// [/RLVA:KB] - removeCOFItemLinks(linked_item_id); - updateAppearanceFromCOF(); + return false; } + bool LLAppearanceMgr::moveWearable(LLViewerInventoryItem* item, bool closer_to_body) { if (!item || !item->isWearableType()) return false; @@ -4024,7 +4560,12 @@ bool LLAppearanceMgr::moveWearable(LLViewerInventoryItem* item, bool closer_to_b swap_item->setDescription(item->getActualDescription()); item->setDescription(tmp); + // LL_DEBUGS("Inventory") << "swap, item " + // << ll_pretty_print_sd(item->asLLSD()) + // << " swap_item " + // << ll_pretty_print_sd(swap_item->asLLSD()) << LL_ENDL; + // FIXME switch to use AISv3 where supported. //items need to be updated on a dataserver item->setComplete(TRUE); item->updateServer(FALSE); @@ -4066,26 +4607,26 @@ void LLAppearanceMgr::dumpCat(const LLUUID& cat_id, const std::string& msg) gInventory.collectDescendents(cat_id, cats, items, LLInventoryModel::EXCLUDE_TRASH); #ifdef DUMP_CAT_VERBOSE - llinfos << llendl; - llinfos << str << llendl; + LL_INFOS() << LL_ENDL; + LL_INFOS() << str << LL_ENDL; S32 hitcount = 0; - for(S32 i=0; igetName() <getName() <getLinkedItem() : NULL; LLUUID asset_id; if (linked_item) @@ -4101,8 +4642,7 @@ LLAppearanceMgr::LLAppearanceMgr(): mOutfitIsDirty(false), mOutfitLocked(false), mIsInUpdateAppearanceFromCOF(false), - mLastUpdateRequestCOFVersion(LLViewerInventoryCategory::VERSION_UNKNOWN), - mLastAppearanceUpdateCOFVersion(LLViewerInventoryCategory::VERSION_UNKNOWN) + mAppearanceResponder(new RequestAgentUpdateAppearanceResponder) { LLOutfitObserver& outfit_observer = LLOutfitObserver::instance(); @@ -4122,132 +4662,66 @@ LLAppearanceMgr::~LLAppearanceMgr() void LLAppearanceMgr::setAttachmentInvLinkEnable(bool val) { - llinfos << "setAttachmentInvLinkEnable => " << (int) val << llendl; + LL_DEBUGS("Avatar") << "setAttachmentInvLinkEnable => " << (int) val << LL_ENDL; mAttachmentInvLinkEnabled = val; -// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2010-10-05 (Catznip-3.0.0a) | Added: Catznip-2.2.0a - if (mAttachmentInvLinkEnabled) - { - linkPendingAttachments(); - } -// [/SL:KB] } -void dumpAttachmentSet(const std::set& atts, const std::string& msg) +void dumpAttachmentSet(const uuid_set_t& atts, const std::string& msg) { - llinfos << msg << llendl; - for (std::set::const_iterator it = atts.begin(); + LL_INFOS() << msg << LL_ENDL; + for (auto it = atts.begin(); it != atts.end(); ++it) { LLUUID item_id = *it; LLViewerInventoryItem *item = gInventory.getItem(item_id); if (item) - llinfos << "atts " << item->getName() << llendl; + LL_INFOS() << "atts " << item->getName() << LL_ENDL; else - llinfos << "atts " << "UNKNOWN[" << item_id.asString() << "]" << llendl; + LL_INFOS() << "atts " << "UNKNOWN[" << item_id.asString() << "]" << LL_ENDL; } - llinfos << llendl; + LL_INFOS() << LL_ENDL; } void LLAppearanceMgr::registerAttachment(const LLUUID& item_id) { + LLViewerInventoryItem *item = gInventory.getItem(item_id); + LL_DEBUGS("Avatar") << "ATT registering attachment " + << (item ? item->getName() : "UNKNOWN") << " " << item_id << LL_ENDL; gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); -// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2010-10-05 (Catznip-3.0.0a) | Added: Catznip-2.2.0a - if (isLinkInCOF(item_id)) - { - return; - } - mPendingAttachLinks.push_back(item_id); -// [/SL:KB] - if (mAttachmentInvLinkEnabled) - { - // we have to pass do_update = true to call LLAppearanceMgr::updateAppearanceFromCOF. - // it will trigger gAgentWariables.notifyLoadingFinished() - // But it is not acceptable solution. See EXT-7777 -// LLAppearanceMgr::addCOFItemLink(item_id, false); // Add COF link for item. -// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2010-10-05 (Catznip-3.0.0a) | Modified: Catznip-2.2.0a - LLPointer cb = new LLRegisterAttachmentCallback(); - LLAppearanceMgr::addCOFItemLink(item_id, false, cb); // Add COF link for item. -// [/SL:KB] - } - else - { - //llinfos << "no link changes, inv link not enabled" << llendl; - } + LLAttachmentsMgr::instance().onAttachmentArrived(item_id); } void LLAppearanceMgr::unregisterAttachment(const LLUUID& item_id) { - gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); -// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2010-10-05 (Catznip-3.0.0a) | Added: Catznip-2.2.0a - uuid_vec_t::iterator itPendingAttachLink = std::find(mPendingAttachLinks.begin(), mPendingAttachLinks.end(), item_id); - if (itPendingAttachLink != mPendingAttachLinks.end()) - { - mPendingAttachLinks.erase(itPendingAttachLink); - } -// [/SL:KB] - - if (mAttachmentInvLinkEnabled) - { - LLAppearanceMgr::removeCOFItemLinks(item_id); - } - else - { - //llinfos << "no link changes, inv link not enabled" << llendl; - } -} + LLViewerInventoryItem *item = gInventory.getItem(item_id); + LL_DEBUGS("Avatar") << "ATT unregistering attachment " + << (item ? item->getName() : "UNKNOWN") << " " << item_id << LL_ENDL; + gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); -// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2010-09-18 (Catznip-3.0.0a) | Modified: Catznip-2.2.0a -void LLAppearanceMgr::linkPendingAttachments() -{ - LLPointer cb = NULL; - for (uuid_vec_t::const_iterator itPendingAttachLink = mPendingAttachLinks.begin(); - itPendingAttachLink != mPendingAttachLinks.end(); ++itPendingAttachLink) + LLAttachmentsMgr::instance().onDetachCompleted(item_id); + if (mAttachmentInvLinkEnabled && isLinkedInCOF(item_id)) { - const LLUUID& idAttachItem = *itPendingAttachLink; - if ( (gAgentAvatarp->isWearingAttachment(idAttachItem)) && (!isLinkInCOF(idAttachItem)) ) - { - if (!cb) - cb = new LLRegisterAttachmentCallback(); - LLAppearanceMgr::addCOFItemLink(idAttachItem, false, cb); - } + LL_DEBUGS("Avatar") << "ATT removing COF link for attachment " + << (item ? item->getName() : "UNKNOWN") << " " << item_id << LL_ENDL; + LLAppearanceMgr::removeCOFItemLinks(item_id); + } + else + { + //LL_INFOS() << "no link changes, inv link not enabled" << LL_ENDL; } } -void LLAppearanceMgr::onRegisterAttachmentComplete(const LLUUID& idItem) -{ - const LLUUID& idItemBase = gInventory.getLinkedItemID(idItem); - - // Remove the attachment from the pending list - uuid_vec_t::iterator itPendingAttachLink = std::find(mPendingAttachLinks.begin(), mPendingAttachLinks.end(), idItemBase); - if (itPendingAttachLink != mPendingAttachLinks.end()) - mPendingAttachLinks.erase(itPendingAttachLink); - - // It may have been detached already in which case we should remove the COF link - if ( (isAgentAvatarValid()) && (!gAgentAvatarp->isWearingAttachment(idItemBase)) ) - removeCOFItemLinks(idItemBase); -} -// [/SL:KB] - BOOL LLAppearanceMgr::getIsInCOF(const LLUUID& obj_id) const { - return gInventory.isObjectDescendentOf(obj_id, getCOF()); -} - -// static -bool LLAppearanceMgr::isLinkInCOF(const LLUUID& obj_id) -{ - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - LLLinkedItemIDMatches find_links(gInventory.getLinkedItemID(obj_id)); - gInventory.collectDescendentsIf(LLAppearanceMgr::instance().getCOF(), - cats, - items, - LLInventoryModel::EXCLUDE_TRASH, - find_links); - - return !items.empty(); + const LLUUID& cof = getCOF(); + if (obj_id == cof) + return TRUE; + const LLInventoryObject* obj = gInventory.getObject(obj_id); + if (obj && obj->getParentUUID() == cof) + return TRUE; + return FALSE; } BOOL LLAppearanceMgr::getIsProtectedCOFItem(const LLUUID& obj_id) const @@ -4264,18 +4738,6 @@ BOOL LLAppearanceMgr::getIsProtectedCOFItem(const LLUUID& obj_id) const // For now, don't allow direct deletion from the COF. Instead, force users // to choose "Detach" or "Take Off". return TRUE; - /* - const LLInventoryObject *obj = gInventory.getObject(obj_id); - if (!obj) return FALSE; - - // Can't delete bodyparts, since this would be equivalent to removing the item. - if (obj->getType() == LLAssetType::AT_BODYPART) return TRUE; - - // Can't delete the folder link, since this is saved for bookkeeping. - if (obj->getActualType() == LLAssetType::AT_LINK_FOLDER) return TRUE; - - return FALSE; - */ } class CallAfterCategoryFetchStage2: public LLInventoryFetchItemsObserver @@ -4292,8 +4754,8 @@ class CallAfterCategoryFetchStage2: public LLInventoryFetchItemsObserver } virtual void done() { - llinfos << this << " done with incomplete " << mIncomplete.size() - << " complete " << mComplete.size() << " calling callable" << llendl; + LL_INFOS() << this << " done with incomplete " << mIncomplete.size() + << " complete " << mComplete.size() << " calling callable" << LL_ENDL; gInventory.removeObserver(this); doOnIdleOneTime(mCallable); @@ -4316,34 +4778,32 @@ class CallAfterCategoryFetchStage1: public LLInventoryFetchDescendentsObserver } virtual void done() { - // What we do here is get the complete information on the items in - // the library, and set up an observer that will wait for that to - // happen. + // What we do here is get the complete information on the + // items in the requested category, and set up an observer + // that will wait for that to happen. LLInventoryModel::cat_array_t cat_array; LLInventoryModel::item_array_t item_array; gInventory.collectDescendents(mComplete.front(), cat_array, item_array, LLInventoryModel::EXCLUDE_TRASH); - S32 count = item_array.count(); + S32 count = item_array.size(); if(!count) { - llwarns << "Nothing fetched in category " << mComplete.front() - << llendl; - //dec_busy_count(); + LL_WARNS() << "Nothing fetched in category " << mComplete.front() + << LL_ENDL; gInventory.removeObserver(this); + doOnIdleOneTime(mCallable); - // lets notify observers that loading is finished. - gAgentWearables.notifyLoadingFinished(); delete this; return; } - llinfos << "stage1 got " << item_array.count() << " items, passing to stage2 " << llendl; + LL_INFOS() << "stage1 got " << item_array.size() << " items, passing to stage2 " << LL_ENDL; uuid_vec_t ids; for(S32 i = 0; i < count; ++i) { - ids.push_back(item_array.get(i)->getUUID()); + ids.push_back(item_array.at(i)->getUUID()); } gInventory.removeObserver(this); @@ -4382,24 +4842,60 @@ void callAfterCategoryFetch(const LLUUID& cat_id, nullary_func_t cb) } } +void add_wearable_type_counts(const uuid_vec_t& ids, + S32& clothing_count, + S32& bodypart_count, + S32& object_count, + S32& other_count) +{ + for (uuid_vec_t::const_iterator it = ids.begin(); it != ids.end(); ++it) + { + const LLUUID& item_id_to_wear = *it; + LLViewerInventoryItem* item_to_wear = gInventory.getItem(item_id_to_wear); + if (item_to_wear) + { + if (item_to_wear->getType() == LLAssetType::AT_CLOTHING) + { + clothing_count++; + } + else if (item_to_wear->getType() == LLAssetType::AT_BODYPART) + { + bodypart_count++; + } + else if (item_to_wear->getType() == LLAssetType::AT_OBJECT) + { + object_count++; + } + else + { + other_count++; + } + } + else + { + other_count++; + } + } +} + void wear_multiple(const uuid_vec_t& ids, bool replace) { - LLPointer cb = new LLUpdateAppearanceOnDestroy; - - bool first = true; - uuid_vec_t::const_iterator it; - for (it = ids.begin(); it != ids.end(); ++it) - { - // if replace is requested, the first item worn will replace the current top - // item, and others will be added. - LLAppearanceMgr::instance().wearItemOnAvatar(*it,false,first && replace,cb); - first = false; + S32 clothing_count = 0; + S32 bodypart_count = 0; + S32 object_count = 0; + S32 other_count = 0; + add_wearable_type_counts(ids, clothing_count, bodypart_count, object_count, other_count); + + LLPointer cb = NULL; + if (clothing_count > 0 || bodypart_count > 0) + { + cb = new LLUpdateAppearanceOnDestroy; } + LLAppearanceMgr::instance().wearItemsOnAvatar(ids, true, replace, cb); } // SLapp for easy-wearing of a stock (library) avatar // -/* class LLWearFolderHandler : public LLCommandHandler { public: @@ -4409,17 +4905,33 @@ class LLWearFolderHandler : public LLCommandHandler bool handle(const LLSD& tokens, const LLSD& query_map, LLMediaCtrl* web) { - LLPointer category = new LLInventoryCategory(query_map["folder_id"], - LLUUID::null, - LLFolderType::FT_CLOTHING, - "Quick Appearance"); - LLSD::UUID folder_uuid = query_map["folder_id"].asUUID(); - if ( gInventory.getCategory( folder_uuid ) != NULL ) - { - LLAppearanceMgr::getInstance()->wearInventoryCategory(category, true, false); + LLSD::UUID folder_uuid; - // *TODOw: This may not be necessary if initial outfit is chosen already -- josh - gAgent.setGenderChosen(TRUE); + if (folder_uuid.isNull() && query_map.has("folder_name")) + { + std::string outfit_folder_name = query_map["folder_name"]; + folder_uuid = findDescendentCategoryIDByName( + gInventory.getLibraryRootFolderID(), + outfit_folder_name); + } + if (folder_uuid.isNull() && query_map.has("folder_id")) + { + folder_uuid = query_map["folder_id"].asUUID(); + } + + if (folder_uuid.notNull()) + { + LLPointer category = new LLInventoryCategory(folder_uuid, + LLUUID::null, + LLFolderType::FT_CLOTHING, + "Quick Appearance"); + if ( gInventory.getCategory( folder_uuid ) != NULL ) + { + LLAppearanceMgr::getInstance()->wearInventoryCategory(category, true, false); + + // *TODOw: This may not be necessary if initial outfit is chosen already -- josh + gAgent.setOutfitChosen(TRUE); + } } // release avatar picker keyboard focus @@ -4429,4 +4941,4 @@ class LLWearFolderHandler : public LLCommandHandler } }; -LLWearFolderHandler gWearFolderHandler;*/ +LLWearFolderHandler gWearFolderHandler; diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h index b3539de669..46edd4a99f 100644 --- a/indra/newview/llappearancemgr.h +++ b/indra/newview/llappearancemgr.h @@ -40,7 +40,7 @@ class LLWearable; class LLWearableHoldingPattern; class LLInventoryCallback; class LLOutfitUnLockTimer; -class LLCallAfterInventoryLinkMgr; +class RequestAgentUpdateAppearanceResponder; class LLAppearanceMgr: public LLSingleton { @@ -52,16 +52,17 @@ class LLAppearanceMgr: public LLSingleton public: typedef std::vector wearables_by_type_t; - void updateAppearanceFromCOF(bool update_base_outfit_ordering = false); + void updateAppearanceFromCOF(bool enforce_item_restrictions = true, + bool enforce_ordering = true, + nullary_func_t post_update_func = no_op); // [SL:KB] - Patch: Appearance-MixedViewers | Checked: 2010-04-02 (Catznip-3.0.0a) | Added: Catznip-2.0.0a - void updateAppearanceFromInitialWearables(LLInventoryModel::item_array_t& initial_items); + void updateAppearanceFromInitialWearables(LLInventoryObject::const_object_list_t& initial_items); // [/SL:KB] - bool needToSaveCOF(); void updateCOF(const LLUUID& category, bool append = false); // [RLVa:KB] - Checked: 2010-03-05 (RLVa-1.2.0a) | Added: RLVa-1.2.0a void updateCOF(LLInventoryModel::item_array_t& body_items_new, LLInventoryModel::item_array_t& wear_items_new, LLInventoryModel::item_array_t& obj_items_new, LLInventoryModel::item_array_t& gest_items_new, - bool append = false, const LLUUID& idOutfit = LLUUID::null); + bool append = false, const LLUUID& idOutfit = LLUUID::null, LLPointer link_waiter = NULL); // [/RLVa:KB] void wearInventoryCategory(LLInventoryCategory* category, bool copy, bool append); void wearInventoryCategoryOnAvatar(LLInventoryCategory* category, bool append); @@ -74,16 +75,24 @@ class LLAppearanceMgr: public LLSingleton void addCategoryToCurrentOutfit(const LLUUID& cat_id); S32 findExcessOrDuplicateItems(const LLUUID& cat_id, LLAssetType::EType type, - S32 max_items, - LLInventoryModel::item_array_t& items_to_kill); - void enforceItemRestrictions(); - + S32 max_items_per_type, + S32 max_items_total, + LLInventoryObject::object_list_t& items_to_kill); + void findAllExcessOrDuplicateItems(const LLUUID& cat_id, + LLInventoryObject::object_list_t& items_to_kill); + void enforceCOFItemRestrictions(LLPointer cb); + + S32 getActiveCopyOperations() const; + + // Replace category contents with copied links via the slam_inventory_folder + // command (single inventory operation where supported) + void slamCategoryLinks(const LLUUID& src_id, const LLUUID& dst_id, + bool include_folder_links, LLPointer cb); + // Copy all items and the src category itself. void shallowCopyCategory(const LLUUID& src_id, const LLUUID& dst_id, LLPointer cb); - void copyItems(const LLUUID& dst_id, LLInventoryModel::item_array_t* items, LLPointer cb); - // Return whether this folder contains minimal contents suitable for making a full outfit. BOOL getCanMakeFolderIntoOutfit(const LLUUID& folder_id); @@ -99,6 +108,9 @@ class LLAppearanceMgr: public LLSingleton // Determine whether we can replace current outfit with the given one. bool getCanReplaceCOF(const LLUUID& outfit_cat_id); + // Can we add all referenced items to the avatar? + bool canAddWearables(const uuid_vec_t& item_ids); + // Copy all items in a category. void shallowCopyCategoryContents(const LLUUID& src_id, const LLUUID& dst_id, LLPointer cb); @@ -107,13 +119,8 @@ class LLAppearanceMgr: public LLSingleton const LLUUID getCOF() const; S32 getCOFVersion() const; - S32 mLastUpdateRequestCOFVersion; - S32 getLastUpdateRequestCOFVersion() const; - - // COF version of last appearance message received for self av. - S32 mLastAppearanceUpdateCOFVersion; - S32 getLastAppearanceUpdateCOFVersion() const; - void setLastAppearanceUpdateCOFVersion(S32 new_val); + // Debugging - get truncated LLSD summary of COF contents. + LLSD dumpCOF() const; // Finds the folder link to the currently worn outfit const LLViewerInventoryItem *getBaseOutfitLink(); @@ -122,17 +129,24 @@ class LLAppearanceMgr: public LLSingleton // find the UUID of the currently worn outfit (Base Outfit) const LLUUID getBaseOutfitUUID(); + void wearItemsOnAvatar(const uuid_vec_t& item_ids_to_wear, + bool do_update, + bool replace, + LLPointer cb = NULL); + // Wear/attach an item (from a user's inventory) on the agent - bool wearItemOnAvatar(const LLUUID& item_to_wear, bool do_update = true, bool replace = false, LLPointer cb = NULL); + void wearItemOnAvatar(const LLUUID& item_to_wear, bool do_update, bool replace = false, + LLPointer cb = NULL); // Update the displayed outfit name in UI. void updatePanelOutfitName(const std::string& name); - void purgeBaseOutfitLink(const LLUUID& category); + void purgeBaseOutfitLink(const LLUUID& category, LLPointer cb = NULL); void createBaseOutfitLink(const LLUUID& category, LLPointer link_waiter); - void updateAgentWearables(LLWearableHoldingPattern* holder, bool append); + void updateAgentWearables(LLWearableHoldingPattern* holder); + S32 countActiveHoldingPatterns(); // For debugging - could be moved elsewhere. void dumpCat(const LLUUID& cat_id, const std::string& msg); void dumpItemArray(const LLInventoryModel::item_array_t& items, const std::string& msg); @@ -140,26 +154,31 @@ class LLAppearanceMgr: public LLSingleton // Attachment link management void unregisterAttachment(const LLUUID& item_id); void registerAttachment(const LLUUID& item_id); +// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2015-06-24 (Catznip-3.7) + bool getAttachmentInvLinkEnable() { return mAttachmentInvLinkEnabled; } +// [/SL:KB] void setAttachmentInvLinkEnable(bool val); - // utility function for bulk linking. - void linkAll(const LLUUID& category, - LLInventoryModel::item_array_t& items, - LLPointer cb); - // Add COF link to individual item. - void addCOFItemLink(const LLUUID& item_id, bool do_update = true, LLPointer cb = NULL, const std::string description = ""); - void addCOFItemLink(const LLInventoryItem *item, bool do_update = true, LLPointer cb = NULL, const std::string description = ""); + void addCOFItemLink(const LLUUID& item_id, LLPointer cb = NULL, const std::string description = ""); + void addCOFItemLink(const LLInventoryItem *item, LLPointer cb = NULL, const std::string description = ""); // Find COF entries referencing the given item. LLInventoryModel::item_array_t findCOFItemLinks(const LLUUID& item_id); - + bool isLinkedInCOF(const LLUUID& item_id); + // Remove COF entries - void removeCOFItemLinks(const LLUUID& item_id); - void removeCOFLinksOfType(LLWearableType::EType type); +// void removeCOFItemLinks(const LLUUID& item_id, LLPointer cb = NULL); +// [SL:KB] - Patch: Appearance-AISFilter | Checked: 2015-05-02 (Catznip-3.7) + void removeCOFItemLinks(const LLUUID& item_id, LLPointer cb = NULL, bool immediate_delete = false); +// [/SL:KB] + void removeCOFLinksOfType(LLWearableType::EType type, LLPointer cb = NULL, bool immediate_delete = false); void removeAllClothesFromAvatar(); void removeAllAttachmentsFromAvatar(); + // Special handling of temp attachments, which are not in the COF + bool shouldRemoveTempAttachment(const LLUUID& item_id); + //has the current outfit changed since it was loaded? bool isOutfitDirty() { return mOutfitIsDirty; } @@ -170,12 +189,11 @@ class LLAppearanceMgr: public LLSingleton // should only be necessary to do on initial login. void updateIsDirty(); + void setOutfitLocked(bool locked); + // Called when self avatar is first fully visible. void onFirstFullyVisible(); - // Create initial outfits from library. - void autopopulateOutfits(); - // Copy initial gestures from library. void copyLibraryGestures(); @@ -186,9 +204,18 @@ class LLAppearanceMgr: public LLSingleton bool updateBaseOutfit(); //Remove clothing or detach an object from the agent (a bodypart cannot be removed) - void removeItemsFromAvatar(const uuid_vec_t& item_ids); - void removeItemFromAvatar(const LLUUID& item_id); +// [SL:KB] - Patch: Appearance-Misc | Checked: 2015-05-05 (Catznip-3.7) + void removeItemFromAvatar(const LLUUID& id_to_remove, LLPointer cb = NULL, bool immediate_delete = false); + + void removeItemsFromAvatar(const uuid_vec_t& ids_to_remove, LLPointer cb = NULL, bool immediate_delete = false); +// [/SL:KB] +// void removeItemsFromAvatar(const uuid_vec_t& item_ids); +// void removeItemFromAvatar(const LLUUID& item_id); + + void onOutfitFolderCreated(const LLUUID& folder_id, bool show_panel); + void onOutfitFolderCreatedAndClothingOrdered(const LLUUID& folder_id, bool show_panel); + private: LLUUID makeNewOutfitCore(const std::string& new_folder_name, bool show_panel/*=true*/, LLInventoryModel::item_array_t* items = NULL); public: @@ -203,15 +230,29 @@ class LLAppearanceMgr: public LLSingleton //Divvy items into arrays by wearable type static void divvyWearablesByType(const LLInventoryModel::item_array_t& items, wearables_by_type_t& items_by_type); + typedef std::map desc_map_t; + + void getWearableOrderingDescUpdates(LLInventoryModel::item_array_t& wear_items, desc_map_t& desc_map); + //Check ordering information on wearables stored in links' descriptions and update if it is invalid // COF is processed if cat_id is not specified - void updateClothingOrderingInfo(LLUUID cat_id = LLUUID::null, bool update_base_outfit_ordering = false); + bool validateClothingOrderingInfo(LLUUID cat_id = LLUUID::null); + + void updateClothingOrderingInfo(LLUUID cat_id = LLUUID::null, + LLPointer cb = NULL); bool isOutfitLocked() { return mOutfitLocked; } bool isInUpdateAppearanceFromCOF() { return mIsInUpdateAppearanceFromCOF; } - void requestServerAppearanceUpdate(LLHTTPClient::ResponderPtr responder_ptr = NULL); + void requestServerAppearanceUpdate(); + + void setAppearanceServiceURL(const std::string& url) { mAppearanceServiceURL = url; } + std::string getAppearanceServiceURL() const; + +private: + std::string mAppearanceServiceURL; + protected: LLAppearanceMgr(); @@ -219,36 +260,27 @@ class LLAppearanceMgr: public LLSingleton private: - void filterWearableItems(LLInventoryModel::item_array_t& items, S32 max_per_type); + void filterWearableItems(LLInventoryModel::item_array_t& items, S32 max_per_type, S32 max_total); void getDescendentsOfAssetType(const LLUUID& category, LLInventoryModel::item_array_t& items, LLAssetType::EType type, - bool follow_folder_links); + bool follow_folder_links = false); void getUserDescendents(const LLUUID& category, LLInventoryModel::item_array_t& wear_items, LLInventoryModel::item_array_t& obj_items, LLInventoryModel::item_array_t& gest_items, - bool follow_folder_links); - - void purgeCategory(const LLUUID& category, bool keep_outfit_links); + bool follow_folder_links = false); static void onOutfitRename(const LLSD& notification, const LLSD& response); - void setOutfitLocked(bool locked); - -// [SL:KB] - Checked: 2010-04-24 (RLVa-1.2.0f) | Added: RLVa-1.2.0f - void purgeItems(const LLInventoryModel::item_array_t& items); - void purgeItemsOfType(LLAssetType::EType asset_type); - void syncCOF(const LLInventoryModel::item_array_t& items, - LLInventoryModel::item_array_t& items_to_add, LLInventoryModel::item_array_t& items_to_remove); -// [/SL:KB] - bool mAttachmentInvLinkEnabled; bool mOutfitIsDirty; bool mIsInUpdateAppearanceFromCOF; // to detect recursive calls. + boost::intrusive_ptr mAppearanceResponder; + /** * Lock for blocking operations on outfit until server reply or timeout exceed * to avoid unsynchronized outfit state or performing duplicate operations. @@ -257,13 +289,11 @@ class LLAppearanceMgr: public LLSingleton std::auto_ptr mUnlockOutfitTimer; -// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2010-09-18 (Catznip-3.0.0a) | Modified: Catznip-2.1.2e -public: - void linkPendingAttachments(); - void onRegisterAttachmentComplete(const LLUUID& idItem); -private: - uuid_vec_t mPendingAttachLinks; -// [/SL:KB] + // Set of temp attachment UUIDs that should be removed + typedef uuid_set_t doomed_temp_attachments_t; + doomed_temp_attachments_t mDoomedTempAttachmentIDs; + + void addDoomedTempAttachment(const LLUUID& id_to_remove); ////////////////////////////////////////////////////////////////////////////////// // Item-specific convenience functions @@ -272,37 +302,49 @@ class LLAppearanceMgr: public LLSingleton BOOL getIsInCOF(const LLUUID& obj_id) const; // Is this in the COF and can the user delete it from the COF? BOOL getIsProtectedCOFItem(const LLUUID& obj_id) const; - - /** - * Checks if COF contains link to specified object. - */ - static bool isLinkInCOF(const LLUUID& obj_id); }; class LLUpdateAppearanceOnDestroy: public LLInventoryCallback { public: - LLUpdateAppearanceOnDestroy(bool update_base_outfit_ordering = false); + LLUpdateAppearanceOnDestroy(bool enforce_item_restrictions = true, + bool enforce_ordering = true, + nullary_func_t post_update_func = no_op); virtual ~LLUpdateAppearanceOnDestroy(); /* virtual */ void fire(const LLUUID& inv_item); + static U32 sActiveCallbacks; private: U32 mFireCount; - bool mUpdateBaseOrder; + bool mEnforceItemRestrictions; + bool mEnforceOrdering; + nullary_func_t mPostUpdateFunc; }; -// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2010-08-31 (Catznip-3.0.0a) | Added: Catznip-2.1.2a -class LLRegisterAttachmentCallback : public LLInventoryCallback +// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2010-08-31 (Catznip-2.1) +class LLUpdateAppearanceAndEditWearableOnDestroy: public LLInventoryCallback { public: - /*virtual*/ void fire(const LLUUID& idItem) - { - LLAppearanceMgr::instance().onRegisterAttachmentComplete(idItem); - } + LLUpdateAppearanceAndEditWearableOnDestroy(const LLUUID& item_id); + + /* virtual */ void fire(const LLUUID& item_id) {} + + ~LLUpdateAppearanceAndEditWearableOnDestroy(); + +private: + LLUUID mItemID; +}; + +class LLRequestServerAppearanceUpdateOnDestroy: public LLInventoryCallback +{ +public: + LLRequestServerAppearanceUpdateOnDestroy() {} + ~LLRequestServerAppearanceUpdateOnDestroy(); + + /* virtual */ void fire(const LLUUID& item_id) {} }; -// [/SL:KB] -#define SUPPORT_ENSEMBLES 0 +void edit_wearable_and_customize_avatar(LLUUID item_id); LLUUID findDescendentCategoryIDByName(const LLUUID& parent_id,const std::string& name); diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 575be42104..b058d76098 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -36,7 +36,7 @@ #include "hippogridmanager.h" #include "hippolimits.h" -#include "sgversion.h" +#include "llversioninfo.h" #include "llfeaturemanager.h" #include "lluictrlfactory.h" #include "lltexteditor.h" @@ -47,11 +47,11 @@ #include "llagent.h" #include "llagentcamera.h" #include "llagentwearables.h" +#include "llimprocessing.h" #include "llwindow.h" #include "llviewerstats.h" #include "llmarketplacefunctions.h" #include "llmarketplacenotifications.h" -#include "llmd5.h" #include "llmeshrepository.h" #include "llmodaldialog.h" #include "llpumpio.h" @@ -63,7 +63,6 @@ #include "llares.h" #include "llcurl.h" #include "llcalc.h" -#include "lltexturestats.h" #include "llviewerwindow.h" #include "llviewerdisplay.h" #include "llviewermedia.h" @@ -85,19 +84,25 @@ #include "llprogressview.h" #include "llvocache.h" #include "llvopartgroup.h" +// [SL:KB] - Patch: Appearance-Misc | Checked: 2013-02-12 (Catznip-3.4) +#include "llappearancemgr.h" +// [/SL:KB] #include "llfloaterteleporthistory.h" - #include "llweb.h" #include "llsecondlifeurls.h" +#include "llavatarrenderinfoaccountant.h" +#include "llskinningutil.h" // Linden library includes #include "llavatarnamecache.h" #include "lldiriterator.h" +#include "llexperiencecache.h" #include "llimagej2c.h" #include "llmemory.h" #include "llprimitive.h" #include "llurlaction.h" #include "llurlentry.h" +#include "llvolumemgr.h" #include "llnotifications.h" #include "llnotificationsutil.h" #include @@ -132,8 +137,6 @@ #include "llassetstorage.h" #include "llpolymesh.h" #include "llaudioengine.h" -#include "llstreamingaudio.h" -#include "llviewermenu.h" #include "llselectmgr.h" #include "lltrans.h" #include "lltracker.h" @@ -141,7 +144,6 @@ #include "llworldmapview.h" #include "llpostprocess.h" #include "llwlparammanager.h" -#include "llwaterparammanager.h" #include "lldebugview.h" #include "llconsole.h" @@ -157,11 +159,11 @@ // Included so that constants/settings might be initialized // in save_settings_to_globals() +#include "aosystem.h" #include "llbutton.h" #include "llcombobox.h" -#include "llstatusbar.h" +#include "floaterlocalassetbrowse.h" #include "llsurface.h" -#include "llvosky.h" #include "llvotree.h" #include "llfolderview.h" #include "lltoolbar.h" @@ -190,15 +192,13 @@ #include "llviewerthrottle.h" #include "llparcel.h" #include "llviewerassetstats.h" +#include "NACLantispam.h" #include "llmainlooprepeater.h" // [RLVa:KB] #include "rlvhandler.h" // [/RLVa:KB] -// [SL:KB] - Patch: Appearance-Misc | Checked: 2013-02-12 (Catznip-3.4) -#include "llappearancemgr.h" -// [/SL:KB] // *FIX: These extern globals should be cleaned up. // The globals either represent state/config/resource-storage of either @@ -212,6 +212,58 @@ // llviewernetwork.h #include "llviewernetwork.h" +#include + +#ifdef USE_CRASHPAD +#pragma warning(disable:4265) + +#include +#include +#include +#include +#include + +#include + +#include "llnotificationsutil.h" +#include "llversioninfo.h" + + +template +struct crashpad_annotation : public crashpad::Annotation { + std::array buffer; + crashpad_annotation(const char* name) : crashpad::Annotation(T, name, buffer.data()) + {} + void set(const std::string& src) { + //LL_INFOS() << name() << ": " << src.c_str() << LL_ENDL; + const size_t min_size = llmin(SIZE, src.size()); + memcpy(buffer.data(), src.data(), min_size); + buffer.data()[SIZE - 1] = '\0'; + SetSize(min_size); + } +}; +#define DEFINE_CRASHPAD_ANNOTATION(name, len) \ +static crashpad_annotation g_crashpad_annotation_##name##_buffer("sentry[tags]["#name"]"); +#define DEFINE_CRASHPAD_ANNOTATION_EXTRA(name, len) \ +static crashpad_annotation g_crashpad_annotation_##name##_buffer("sentry[extra]["#name"]"); +#define SET_CRASHPAD_ANNOTATION_VALUE(name, value) \ +g_crashpad_annotation_##name##_buffer.set(value); +#else +#define SET_CRASHPAD_ANNOTATION_VALUE(name, value) +#define DEFINE_CRASHPAD_ANNOTATION_EXTRA(name, len) +#define DEFINE_CRASHPAD_ANNOTATION(name, len) +#endif + +DEFINE_CRASHPAD_ANNOTATION_EXTRA(fatal_message, 512); +DEFINE_CRASHPAD_ANNOTATION(grid_name, 64); +DEFINE_CRASHPAD_ANNOTATION(region_name, 64); +DEFINE_CRASHPAD_ANNOTATION_EXTRA(cpu_string, 128); +DEFINE_CRASHPAD_ANNOTATION_EXTRA(gpu_string, 128); +DEFINE_CRASHPAD_ANNOTATION_EXTRA(gl_version, 128); +DEFINE_CRASHPAD_ANNOTATION_EXTRA(session_duration, 32); +DEFINE_CRASHPAD_ANNOTATION_EXTRA(startup_state, 32); +DEFINE_CRASHPAD_ANNOTATION_EXTRA(memory_sys, 32); +DEFINE_CRASHPAD_ANNOTATION_EXTRA(memory_alloc, 32); ////// Windows-specific includes to the bottom - nasty defines in these pollute the preprocessor // @@ -237,7 +289,8 @@ F32 gSimLastTime; // Used in LLAppViewer::init and send_stats() F32 gSimFrames; BOOL gShowObjectUpdates = FALSE; -BOOL gUseQuickTime = TRUE; + +S32 gLastExecDuration = -1; // (<0 indicates unknown) BOOL gAcceptTOS = FALSE; BOOL gAcceptCriticalMessage = FALSE; @@ -252,12 +305,12 @@ LLPumpIO* gServicePump = NULL; BOOL gPacificDaylightTime = FALSE; -U64 gFrameTime = 0; -F32 gFrameTimeSeconds = 0.f; -F32 gFrameIntervalSeconds = 0.f; +U64MicrosecondsImplicit gFrameTime = 0; +F32SecondsImplicit gFrameTimeSeconds = 0.f; +F32SecondsImplicit gFrameIntervalSeconds = 0.f; F32 gFPSClamped = 10.f; // Pretend we start at target rate. F32 gFrameDTClamped = 0.f; // Time between adjacent checks to network for packets -U64 gStartTime = 0; // gStartTime is "private", used only to calculate gFrameTimeSeconds +U64MicrosecondsImplicit gStartTime = 0; // gStartTime is "private", used only to calculate gFrameTimeSeconds U32 gFrameStalls = 0; const F64 FRAME_STALL_THRESHOLD = 1.0; @@ -278,7 +331,7 @@ BOOL gUseWireframe = FALSE; LLVFS* gStaticVFS = NULL; LLMemoryInfo gSysMemory; -U64 gMemoryAllocated = 0; // updated in display_stats() in llviewerdisplay.cpp +U64Bytes gMemoryAllocated(0); // updated in display_stats() in llviewerdisplay.cpp std::string gLastVersionChannel; @@ -299,11 +352,14 @@ BOOL gLogoutInProgress = FALSE; //////////////////////////////////////////////////////////// // Internal globals... that should be removed. static std::string gArgs; - +const int MAX_MARKER_LENGTH = 1024; const std::string MARKER_FILE_NAME("Singularity.exec_marker"); +const std::string START_MARKER_FILE_NAME("Singularity.start_marker");; const std::string ERROR_MARKER_FILE_NAME("Singularity.error_marker"); const std::string LLERROR_MARKER_FILE_NAME("Singularity.llerror_marker"); const std::string LOGOUT_MARKER_FILE_NAME("Singularity.logout_marker"); +const std::string LOG_FILE("Singularity.log"); +extern const std::string OLD_LOG_FILE("Singularity.old"); static BOOL gDoDisconnect = FALSE; static std::string gLaunchFileOnQuit; @@ -353,7 +409,9 @@ void init_default_trans_args() { default_trans_args.insert("SECOND_LIFE"); // World default_trans_args.insert("APP_NAME"); + default_trans_args.insert("SHORT_APP_NAME"); default_trans_args.insert("CAPITALIZED_APP_NAME"); + default_trans_args.insert("APP_SITE"); default_trans_args.insert("SECOND_LIFE_GRID"); default_trans_args.insert("SUPPORT_SITE"); default_trans_args.insert("CURRENCY"); @@ -365,7 +423,6 @@ void init_default_trans_args() const char *VFS_DATA_FILE_BASE = "data.db2.x."; const char *VFS_INDEX_FILE_BASE = "index.db2.x."; -static std::string gSecondLife; std::string gWindowTitle; std::string gLoginPage; @@ -411,45 +468,6 @@ static void ui_audio_callback(const LLUUID& uuid) } } -void request_initial_instant_messages() -{ - static BOOL requested = FALSE; - if (!requested - && gMessageSystem - && LLMuteList::getInstance()->isLoaded() - && isAgentAvatarValid()) - { - // Auto-accepted inventory items may require the avatar object - // to build a correct name. Likewise, inventory offers from - // muted avatars require the mute list to properly mute. - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_RetrieveInstantMessages); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - gAgent.sendReliableMessage(); - requested = TRUE; - } -} - -// A settings system callback for CrashSubmitBehavior -bool handleCrashSubmitBehaviorChanged(const LLSD& newvalue) -{ - S32 cb = newvalue.asInteger(); - const S32 NEVER_SUBMIT_REPORT = 2; - if(cb == NEVER_SUBMIT_REPORT) - { -// LLWatchdog::getInstance()->cleanup(); // SJB: cleaning up a running watchdog thread is unsafe - LLAppViewer::instance()->destroyMainloopTimeout(); - } - else if(gSavedSettings.getBOOL("WatchdogEnabled") == TRUE) - { - // Don't re-enable the watchdog when we change the setting; this may get called before it's started -// LLWatchdog::getInstance()->init(); - } - return true; -} - // Use these strictly for things that are constructed at startup, // or for things that are performance critical. JC static void settings_to_globals() @@ -459,8 +477,9 @@ static void settings_to_globals() BTN_HEIGHT_SMALL = gSavedSettings.getS32("ButtonHeightSmall"); BTN_HEIGHT = gSavedSettings.getS32("ButtonHeight"); + extern S32 MENU_BAR_HEIGHT; MENU_BAR_HEIGHT = gSavedSettings.getS32("MenuBarHeight"); - MENU_BAR_WIDTH = gSavedSettings.getS32("MenuBarWidth"); + extern S32 STATUS_BAR_HEIGHT; STATUS_BAR_HEIGHT = gSavedSettings.getS32("StatusBarHeight"); LLCOMBOBOX_HEIGHT = BTN_HEIGHT - 2; @@ -468,7 +487,7 @@ static void settings_to_globals() LLSurface::setTextureSize(gSavedSettings.getU32("RegionTextureSize")); - LLRender::sGLCoreProfile = gSavedSettings.getBOOL("RenderGLCoreProfile"); + LLRender::sGLCoreProfile = LLGLSLShader::sNoFixedFunction = gSavedSettings.getBOOL("RenderGLCoreProfile"); LLImageGL::sGlobalUseAnisotropic = gSavedSettings.getBOOL("RenderAnisotropic"); LLImageGL::sCompressTextures = gSavedSettings.getBOOL("RenderCompressTextures"); @@ -533,7 +552,6 @@ LLAppViewer* LLAppViewer::sInstance = NULL; const std::string LLAppViewer::sGlobalSettingsName = "Global"; const std::string LLAppViewer::sPerAccountSettingsName = "PerAccount"; -const std::string LLAppViewer::sCrashSettingsName = "CrashSettings"; LLTextureCache* LLAppViewer::sTextureCache = NULL; LLImageDecodeThread* LLAppViewer::sImageDecodeThread = NULL; @@ -541,7 +559,7 @@ LLTextureFetch* LLAppViewer::sTextureFetch = NULL; LLAppViewer::LLAppViewer() : mMarkerFile(), - mLogoutMarkerFile(NULL), + mLogoutMarkerFile(), mReportedCrash(false), mNumSessions(0), mPurgeCache(false), @@ -553,12 +571,48 @@ LLAppViewer::LLAppViewer() : mMainloopTimeout(NULL), mAgentRegionLastAlive(false) { - if(NULL != sInstance) + if(nullptr != sInstance) { - llerrs << "Oh no! An instance of LLAppViewer already exists! LLAppViewer is sort of like a singleton." << llendl; + LL_ERRS() << "Oh no! An instance of LLAppViewer already exists! LLAppViewer is sort of like a singleton." << LL_ENDL; } + // Need to do this initialization before we do anything else, since anything + // that touches files should really go through the lldir API + { + std::string newview_path; + const auto& exe_dir = gDirUtilp->getExecutableDir(); + auto build_dir_pos = exe_dir.rfind("build-"); + if (build_dir_pos != std::string::npos) + { + // ...we're in a dev checkout + newview_path = gDirUtilp->add(gDirUtilp->add(exe_dir.substr(0, build_dir_pos), "indra"), "newview"); + if (LLFile::isdir(newview_path)) + LL_INFOS() << "Running in dev checkout with newview " << newview_path << LL_ENDL; + else newview_path.clear(); + } + + gDirUtilp->initAppDirs("SecondLife", newview_path); + } + // + // IMPORTANT! Do NOT put anything that will write + // into the log files during normal startup until AFTER + // we run the "program crashed last time" error handler below. + // sInstance = this; + + + initLoggingAndGetLastDuration(); + + processMarkerFiles(); + // + // OK to write stuff to logs now, we've now crash reported if necessary + // +#if !defined(USE_CRASHPAD) + // write dump files to a per-run dump directory to avoid multiple viewer issues. + std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_DUMP, ""); + + setDebugFileNames(logdir); +#endif } @@ -567,32 +621,213 @@ LLAppViewer::~LLAppViewer() destroyMainloopTimeout(); // If we got to this destructor somehow, the app didn't hang. - removeMarkerFile(); + removeMarkerFiles(); } class LLUITranslationBridge : public LLTranslationBridge { public: - virtual std::string getString(const std::string &xml_desc) + std::string getString(const std::string &xml_desc) override { return LLTrans::getString(xml_desc); } }; +void load_default_bindings(bool zqsd) +{ + gViewerKeyboard.unloadBindings(); + const std::string key_bindings_file(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, zqsd ? "keysZQSD.xml" : "keys.xml")); + if (!gDirUtilp->fileExists(key_bindings_file) || !gViewerKeyboard.loadBindingsXML(key_bindings_file)) + { + const std::string key_bindings_file(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, zqsd ? "keysZQSD.ini" : "keys.ini")); + if (!gViewerKeyboard.loadBindings(key_bindings_file)) + { + LL_ERRS("InitInfo") << "Unable to open " << key_bindings_file << LL_ENDL; + } + } + // Load Custom bindings (override defaults) + std::string custom_keys(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "custom_keys.xml")); + if (!gDirUtilp->fileExists(custom_keys) || !gViewerKeyboard.loadBindingsXML(custom_keys)) + { + custom_keys = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "custom_keys.ini"); + if (gDirUtilp->fileExists(custom_keys)) + gViewerKeyboard.loadBindings(custom_keys); + } +} + +/* Singu unused +namespace { +// With Xcode 6, _exit() is too magical to use with boost::bind(), so provide +// this little helper function. +void fast_exit(int rc) +{ + _exit(rc); +} +} +*/ + +#ifdef USE_CRASHPAD +base::FilePath databasePath() +{ + // Cache directory that will store crashpad information and minidumps + std::string crashpad_path = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "crashpad"); + return base::FilePath(ll_convert_string_to_wide(crashpad_path)); +} + +static void handleCrashSubmitBehaviorChanged(LLControlVariable*, const LLSD& val) +{ + if (auto db = crashpad::CrashReportDatabase::Initialize(databasePath())) + { + if (auto settings = db->GetSettings()) + { + settings->SetUploadsEnabled(val.asBoolean()); + } + } +} + +static void configureCrashUploads() +{ + auto database = databasePath(); + auto db = crashpad::CrashReportDatabase::InitializeWithoutCreating(database); + if (!db) return; + auto settings = db->GetSettings(); + if (!settings) return; + auto control = gSavedSettings.getControl("CrashSubmitBehavior"); + control->getSignal()->connect(handleCrashSubmitBehaviorChanged); + if (control->get().asInteger() == -1) + { + LLNotificationsUtil::add("SubmitCrashReports", LLSD(), LLSD(), [control](const LLSD& p, const LLSD& f) { + control->set(!LLNotificationsUtil::getSelectedOption(p, f)); + }); + } + + if (!settings->SetUploadsEnabled(control->get().asInteger() == 1)) + { + LL_WARNS() << "Failed to set enable upload of crash database." << LL_ENDL; + } +} +#endif + +void LLAppViewer::initCrashReporting() +{ +#ifdef USE_CRASHPAD + // Path to the out-of-process handler executable + std::string handler_path = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "crashpad_handler.exe"); + if (!gDirUtilp->fileExists(handler_path)) + { + LL_ERRS() << "Failed to initialize crashpad due to missing handler executable." << LL_ENDL; + return; + } + base::FilePath handler(ll_convert_string_to_wide(handler_path)); + + auto database = databasePath(); + + // URL used to submit minidumps to + std::string url(CRASHPAD_URL); + + // Optional annotations passed via --annotations to the handler + std::map annotations; + +#if 0 + unsigned char node_id[6]; + if (LLUUID::getNodeID(node_id) > 0) + { + char md5str[MD5HEX_STR_SIZE] = { 0 }; + LLMD5 hashed_unique_id; + hashed_unique_id.update(node_id, 6); + hashed_unique_id.finalize(); + hashed_unique_id.hex_digest((char*)md5str); + annotations.emplace("sentry[contexts][app][device_app_hash]", std::string(md5str)); + } +#endif + + annotations.emplace("sentry[contexts][app][app_name]", LLVersionInfo::getChannel()); + annotations.emplace("sentry[contexts][app][app_version]", LLVersionInfo::getVersion()); + annotations.emplace("sentry[contexts][app][app_build]", LLVersionInfo::getChannelAndVersion()); + + annotations.emplace("sentry[release]", LLVersionInfo::getChannelAndVersion()); + + annotations.emplace("sentry[tags][second_instance]", fmt::to_string(isSecondInstance())); + //annotations.emplace("sentry[tags][bitness]", fmt::to_string(ADDRESS_SIZE)); + annotations.emplace("sentry[tags][bitness]", +#if defined(_WIN64) || defined(__x86_64__) + "64" +#else + "32" +#endif + ); + + // Optional arguments to pass to the handler + std::vector arguments; + arguments.push_back("--no-rate-limit"); + arguments.push_back("--monitor-self"); + + if (isSecondInstance()) + { + arguments.push_back("--no-periodic-tasks"); + } + else + { + auto db = crashpad::CrashReportDatabase::Initialize(database); + if (db == nullptr) + { + LL_WARNS() << "Failed to initialize crashpad database at path: " << wstring_to_utf8str(database.value()) << LL_ENDL; + return; + } + + auto prune_condition = crashpad::PruneCondition::GetDefault(); + if (prune_condition != nullptr) + { + auto ret = crashpad::PruneCrashReportDatabase(db.get(), prune_condition.get()); + LL_INFOS() << "Pruned " << ret << " reports from the crashpad database." << LL_ENDL; + } + } + + crashpad::CrashpadClient client; + bool success = client.StartHandler( + handler, + database, + database, + url, + annotations, + arguments, + /* restartable */ true, + /* asynchronous_start */ false + ); + if (success) + LL_INFOS() << "Crashpad init success" << LL_ENDL; + else + LL_WARNS() << "FAILED TO INITIALIZE CRASHPAD" << LL_ENDL; +#endif +} + bool LLAppViewer::init() { +#ifdef USE_CRASHPAD + initCrashReporting(); +#endif + + writeDebugInfo(); + + setupErrorHandling(); + + { + auto fn = boost::bind([](const LLSD& stateInfo) -> bool { + SET_CRASHPAD_ANNOTATION_VALUE(startup_state, stateInfo["str"].asString()); + return false; + }, _1); + LLStartUp::getStateEventPump().listen<::LLEventListener>("LLAppViewer", fn); + } + // // Start of the application // - // IMPORTANT! Do NOT put anything that will write - // into the log files during normal startup until AFTER - // we run the "program crashed last time" error handler below. - // LLFastTimer::reset(); // initialize LLWearableType translation bridge. // Memory will be cleaned up in ::cleanupClass() - LLWearableType::initClass(new LLUITranslationBridge()); + LLTranslationBridge::ptr_t trans = std::make_shared(); + LLWearableType::initClass(trans); // // We can call this early. @@ -605,26 +840,19 @@ bool LLAppViewer::init() //initialize particle index pool LLVOPartGroup::initClass(); - // Need to do this initialization before we do anything else, since anything - // that touches files should really go through the lldir API - gDirUtilp->initAppDirs("SecondLife"); // set skin search path to default, will be overridden later // this allows simple skinned file lookups to work - gDirUtilp->setSkinFolder("default"); + gDirUtilp->setSkinFolder("default", "en-us"); - initLogging(); +// initLoggingAndGetLastDuration(); // // Curl must be initialized before any thread is running. AICurlInterface::initCurl(); - // Logging is initialized. Now it's safe to start the error thread. - startErrorThread(); - // // OK to write stuff to logs now, we've now crash reported if necessary // - init_default_trans_args(); if (!initConfiguration()) @@ -632,13 +860,14 @@ bool LLAppViewer::init() LL_INFOS("InitInfo") << "Configuration initialized." << LL_ENDL ; + // initialize skinning util + LLSkinningUtil::initClass(); + //set the max heap size. initMaxHeapSize() ; LLPrivateMemoryPoolManager::initClass((BOOL)gSavedSettings.getBOOL("MemoryPrivatePoolEnabled"), (U32)gSavedSettings.getU32("MemoryPrivatePoolSize")) ; - mAlloc.setProfilingEnabled(gSavedSettings.getBOOL("MemProfiling")); - AIEngine::setMaxCount(gSavedSettings.getU32("StateMachineMaxTime")); { @@ -654,13 +883,10 @@ bool LLAppViewer::init() ); AIHTTPTimeoutPolicy::setDefaultCurlTimeout(policy_tmp); } - { - // Viewer metrics initialization - //static LLCachedControl metrics_submode(gSavedSettings, - // "QAModeMetrics", - // false, - // "Enables QA features (logging, faster cycling) for metrics collector"); + mAlloc.setProfilingEnabled(gSavedSettings.getBOOL("MemProfiling")); + + { if (gSavedSettings.getBOOL("QAModeMetrics")) { app_metrics_qa_mode = true; @@ -669,20 +895,24 @@ bool LLAppViewer::init() LLViewerAssetStatsFF::init(); } - initThreads(); + initThreads(); LL_INFOS("InitInfo") << "Threads initialized." << LL_ENDL ; // Load art UUID information, don't require these strings to be declared in code. - std::string colors_base_filename = gDirUtilp->findSkinnedFilename("colors_base.xml"); - LL_DEBUGS("InitInfo") << "Loading base colors from " << colors_base_filename << LL_ENDL; - gColors.loadFromFileLegacy(colors_base_filename, FALSE, TYPE_COL4U); - + for(auto& colors_base_filename : gDirUtilp->findSkinnedFilenames(LLDir::SKINBASE, "colors_base.xml", LLDir::ALL_SKINS)) + { + LL_DEBUGS("InitInfo") << "Loading colors from " << colors_base_filename << LL_ENDL; + gColors.loadFromFileLegacy(colors_base_filename, FALSE, TYPE_COL4U); + } // Load overrides from user colors file - std::string user_colors_filename = gDirUtilp->findSkinnedFilename("colors.xml"); - LL_DEBUGS("InitInfo") << "Loading user colors from " << user_colors_filename << LL_ENDL; - if (gColors.loadFromFileLegacy(user_colors_filename, FALSE, TYPE_COL4U) == 0) + for (auto& colors_base_filename : gDirUtilp->findSkinnedFilenames(LLDir::SKINBASE, "colors.xml", LLDir::ALL_SKINS)) { - LL_DEBUGS("InitInfo") << "Cannot load user colors from " << user_colors_filename << LL_ENDL; + gColors.loadFromFileLegacy(colors_base_filename, FALSE, TYPE_COL4U); + LL_DEBUGS("InitInfo") << "Loading user colors from " << colors_base_filename << LL_ENDL; + if (gColors.loadFromFileLegacy(colors_base_filename, FALSE, TYPE_COL4U) == 0) + { + LL_DEBUGS("InitInfo") << "Cannot load user colors from " << colors_base_filename << LL_ENDL; + } } // Widget construction depends on LLUI being initialized @@ -695,6 +925,11 @@ bool LLAppViewer::init() &LLUI::getScaleFactor()); LL_INFOS("InitInfo") << "UI initialized." << LL_ENDL ; + // NOW LLUI::getLanguage() should work. gDirUtilp must know the language + // for this session ASAP so all the file-loading commands that follow, + // that use findSkinnedFilenames(), will include the localized files. + gDirUtilp->setSkinFolder(gDirUtilp->getSkinFolder(), LLUI::getLanguage()); + LLUICtrlFactory::getInstance()->setupPaths(); // update paths with correct language set // Setup LLTrans after LLUI::initClass has been called. @@ -703,16 +938,13 @@ bool LLAppViewer::init() // Setup notifications after LLUI::initClass() has been called. LLNotifications::instance().createDefaultChannels(); LL_INFOS("InitInfo") << "Notifications initialized." << LL_ENDL ; - - writeSystemInfo(); - // Build a string representing the current version number. - gCurrentVersion = llformat("%s %d.%d.%d.%d", - gVersionChannel, - gVersionMajor, - gVersionMinor, - gVersionPatch, - gVersionBuild ); +#ifdef USE_CRASHPAD + // Now that we have Settings and Notifications, we can configure crash uploads + configureCrashUploads(); +#endif + + writeSystemInfo(); ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// @@ -722,15 +954,11 @@ bool LLAppViewer::init() // // Various introspection concerning the libs we're using - particularly - // the libs involved in getting to a full login screen. + // the libs involved in getting to a full login screen. // LL_INFOS("InitInfo") << "J2C Engine is: " << LLImageJ2C::getEngineInfo() << LL_ENDL; LL_INFOS("InitInfo") << "libcurl version is: " << LLCurl::getVersionString() << LL_ENDL; - // Get the single value from the crash settings file, if it exists - std::string crash_settings_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, CRASH_SETTINGS_FILE); - gCrashSettings.loadFromFile(crash_settings_filename); - ///////////////////////////////////////////////// // OS-specific login dialogs ///////////////////////////////////////////////// @@ -758,7 +986,14 @@ bool LLAppViewer::init() LLUrlAction::setOpenURLInternalCallback(boost::bind(&LLWeb::loadURLInternal, _1, LLStringUtil::null, LLStringUtil::null)); LLUrlAction::setOpenURLExternalCallback(boost::bind(&LLWeb::loadURLExternal, _1, true, LLStringUtil::null)); LLUrlAction::setExecuteSLURLCallback(&LLURLDispatcher::dispatchFromTextEditor); - + + LL_INFOS("InitInfo") << "UI initialization is done." << LL_ENDL ; + + // Load translations for tooltips + LLFloater::initClass(); + + ///////////////////////////////////////////////// + LLToolMgr::getInstance(); // Initialize tool manager if not already instantiated ///////////////////////////////////////////////// @@ -781,7 +1016,7 @@ bool LLAppViewer::init() #endif LLMIMETypes::parseMIMETypes( mime_types_name ); - // Copy settings to globals. *TODO: Remove or move to appropriage class initializers + // Copy settings to globals. *TODO: Remove or move to appropriate class initializers settings_to_globals(); // Setup settings listeners settings_setup_listeners(); @@ -821,10 +1056,11 @@ bool LLAppViewer::init() if (!initCache()) { + LL_WARNS("InitInfo") << "Failed to init cache" << LL_ENDL; std::ostringstream msg; msg << LLTrans::getString("MBUnableToAccessFile"); OSMessageBox(msg.str(),LLStringUtil::null,OSMB_OK); - return 1; + return true; } LL_INFOS("InitInfo") << "Cache initialization is done." << LL_ENDL ; @@ -849,19 +1085,13 @@ bool LLAppViewer::init() gGLManager.getGLInfo(gDebugInfo); gGLManager.printGLInfoString(); - //load key settings - bind_keyboard_functions(); + writeDebugInfo(); // Load Default bindings - if (!gViewerKeyboard.loadBindings(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"keys.ini"))) - { - LL_ERRS("InitInfo") << "Unable to open keys.ini" << LL_ENDL; - } - // Load Custom bindings (override defaults) - gViewerKeyboard.loadBindings(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"custom_keys.ini")); + load_default_bindings(gSavedSettings.getBOOL("LiruUseZQSDKeys")); // If we don't have the right GL requirements, exit. - if (!gGLManager.mHasRequirements && !gNoRender) + if (!gGLManager.mHasRequirements) { // can't use an alert here since we're exiting and // all hell breaks lose. @@ -871,10 +1101,9 @@ bool LLAppViewer::init() msg, LLStringUtil::null, OSMB_OK); - return 0; + return false; } -#if (_M_IX86_FP > 1 || defined(__SSE2__)) // Without SSE2 support we will crash almost immediately, warn here. if (!gSysCPU.hasSSE2()) { @@ -886,23 +1115,8 @@ bool LLAppViewer::init() msg, LLStringUtil::null, OSMB_OK); - return 0; - } -#elif (_M_IX86_FP == 1 || defined(__SSE__)) - // Without SSE support we will crash almost immediately, warn here. - if (!gSysCPU.hasSSE()) - { - // can't use an alert here since we're exiting and - // all hell breaks lose. - std::string msg = LNotificationTemplates::instance().getGlobalString("UnsupportedCPUSSE2"); - LLStringUtil::format(msg,LLTrans::getDefaultArgs()); - OSMessageBox( - msg, - LLStringUtil::null, - OSMB_OK); - return 0; + return false; } -#endif // alert the user if they are using unsupported hardware if(!gSavedSettings.getBOOL("AlertedUnsupportedHardware")) @@ -918,9 +1132,8 @@ bool LLAppViewer::init() // get RAM data from XML std::stringstream minRAMString(LLNotificationTemplates::instance().getGlobalString("UnsupportedRAMAmount")); - U64 minRAM = 0; + U64Bytes minRAM; minRAMString >> minRAM; - minRAM = minRAM * 1024 * 1024; if(!LLFeatureManager::getInstance()->isGPUSupported() && LLFeatureManager::getInstance()->getGPUClass() != GPU_CLASS_UNKNOWN) { @@ -934,7 +1147,7 @@ bool LLAppViewer::init() minSpecs += "\n"; unsupported = true; } - if(gSysMemory.getPhysicalMemoryClamped() < minRAM) + if(gSysMemory.getPhysicalMemoryKB() < minRAM) { minSpecs += LLNotificationTemplates::instance().getGlobalString("UnsupportedRAM"); minSpecs += "\n"; @@ -961,8 +1174,11 @@ bool LLAppViewer::init() // save the graphics card gDebugInfo["GraphicsCard"] = LLFeatureManager::getInstance()->getGPUString(); + writeDebugInfo(); + // Save the current version to the prefs file - gSavedSettings.setString("LastRunVersion", gCurrentVersion); + gSavedSettings.setString("LastRunVersion", + LLVersionInfo::getChannelAndVersion()); gSimLastTime = gRenderStartTime.getElapsedTimeF32(); gSimFrames = (F32)gFrameCount; @@ -977,6 +1193,8 @@ bool LLAppViewer::init() gGLActive = FALSE; LLViewerMedia::initClass(); LL_INFOS("InitInfo") << "Viewer media initialized." << LL_ENDL ; + + writeDebugInfo(); return true; } @@ -998,9 +1216,8 @@ void LLAppViewer::initMaxHeapSize() //currently SL is built under 32-bit setting, we set its max heap size no more than 1.6 GB. //F32 max_heap_size_gb = llmin(1.6f, (F32)gSavedSettings.getF32("MaxHeapSize")) ; - - F32 max_heap_size_gb = gSavedSettings.getF32("MaxHeapSize") ; - + F32Gigabytes max_heap_size_gb = (F32Gigabytes)gSavedSettings.getF32("MaxHeapSize") ; + //This is all a bunch of CRAP. We run LAA on windows. 64bit windows supports LAA out of the box. 32bit does not, unless PAE is on. #if LL_WINDOWS //http://msdn.microsoft.com/en-us/library/windows/desktop/ms684139%28v=vs.85%29.aspx @@ -1011,24 +1228,24 @@ void LLAppViewer::initMaxHeapSize() HKEY hKey; - if(fnIsWow64Process && fnIsWow64Process(GetCurrentProcess(), &bWow64Process) && bWow64Process) + if(fnIsWow64Process && fnIsWow64Process(GetCurrentProcess(), &bWow64Process) && bWow64Process) { - max_heap_size_gb = 3.7f; + max_heap_size_gb = F32Gigabytes(3.7f); } else if(ERROR_SUCCESS == RegOpenKey(HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Memory Management"), &hKey)) { - DWORD dwSize = sizeof(DWORD); + DWORD dwSize = sizeof(DWORD); DWORD dwResult = 0; - if(ERROR_SUCCESS == RegQueryValueEx(hKey, TEXT("PhysicalAddressExtension"), NULL, NULL, (LPBYTE)&dwResult, &dwSize)) - { + if(ERROR_SUCCESS == RegQueryValueEx(hKey, TEXT("PhysicalAddressExtension"), NULL, NULL, (LPBYTE)&dwResult, &dwSize)) + { if(dwResult) - max_heap_size_gb = 3.7f; + max_heap_size_gb = F32Gigabytes(3.7f); } RegCloseKey(hKey); } #endif - BOOL enable_mem_failure_prevention = (BOOL)gSavedSettings.getBOOL("MemoryFailurePreventionEnabled") ; + BOOL enable_mem_failure_prevention = gSavedSettings.getBOOL("MemoryFailurePreventionEnabled") ; LLMemory::initMaxHeapSizeGB(max_heap_size_gb, enable_mem_failure_prevention) ; } @@ -1063,23 +1280,23 @@ void LLAppViewer::checkMemory() } } -static LLFastTimer::DeclareTimer FTM_MESSAGES("System Messages"); -static LLFastTimer::DeclareTimer FTM_SLEEP("Sleep"); -static LLFastTimer::DeclareTimer FTM_YIELD("Yield"); - -static LLFastTimer::DeclareTimer FTM_TEXTURE_CACHE("Texture Cache"); -static LLFastTimer::DeclareTimer FTM_DECODE("Image Decode"); -static LLFastTimer::DeclareTimer FTM_VFS("VFS Thread"); -static LLFastTimer::DeclareTimer FTM_LFS("LFS Thread"); -static LLFastTimer::DeclareTimer FTM_PAUSE_THREADS("Pause Threads"); -static LLFastTimer::DeclareTimer FTM_IDLE("Idle"); -static LLFastTimer::DeclareTimer FTM_PUMP("Pump"); -static LLFastTimer::DeclareTimer FTM_PUMP_ARES("Ares"); -static LLFastTimer::DeclareTimer FTM_PUMP_SERVICE("Service"); -static LLFastTimer::DeclareTimer FTM_SERVICE_CALLBACK("Callback"); -static LLFastTimer::DeclareTimer FTM_AGENT_AUTOPILOT("Autopilot"); -static LLFastTimer::DeclareTimer FTM_AGENT_UPDATE("Update"); -static LLFastTimer::DeclareTimer FTM_STATEMACHINE("State Machine"); +static LLTrace::BlockTimerStatHandle FTM_MESSAGES("System Messages"); +static LLTrace::BlockTimerStatHandle FTM_SLEEP("Sleep"); +static LLTrace::BlockTimerStatHandle FTM_YIELD("Yield"); + +static LLTrace::BlockTimerStatHandle FTM_TEXTURE_CACHE("Texture Cache"); +static LLTrace::BlockTimerStatHandle FTM_DECODE("Image Decode"); +static LLTrace::BlockTimerStatHandle FTM_VFS("VFS Thread"); +static LLTrace::BlockTimerStatHandle FTM_LFS("LFS Thread"); +static LLTrace::BlockTimerStatHandle FTM_PAUSE_THREADS("Pause Threads"); +static LLTrace::BlockTimerStatHandle FTM_IDLE("Idle"); +static LLTrace::BlockTimerStatHandle FTM_PUMP("Pump"); +static LLTrace::BlockTimerStatHandle FTM_PUMP_ARES("Ares"); +static LLTrace::BlockTimerStatHandle FTM_PUMP_SERVICE("Service"); +static LLTrace::BlockTimerStatHandle FTM_SERVICE_CALLBACK("Callback"); +static LLTrace::BlockTimerStatHandle FTM_AGENT_AUTOPILOT("Autopilot"); +static LLTrace::BlockTimerStatHandle FTM_AGENT_UPDATE("Update"); +static LLTrace::BlockTimerStatHandle FTM_STATEMACHINE("State Machine"); bool LLAppViewer::mainLoop() { @@ -1105,28 +1322,39 @@ bool LLAppViewer::mainLoop() LLViewerJoystick* joystick(LLViewerJoystick::getInstance()); joystick->setNeedsReset(true); - LLEventPump& mainloop(LLEventPumps::instance().obtain("mainloop")); - // As we do not (yet) send data on the mainloop LLEventPump that varies - // with each frame, no need to instantiate a new LLSD event object each - // time. Obviously, if that changes, just instantiate the LLSD at the - // point of posting. - LLSD newFrame; + LLEventPump& mainloop(LLEventPumps::instance().obtain("mainloop")); + + // merge grid info from web site, if newer. + if (gSavedSettings.getBOOL("CheckForGridUpdates")) + gHippoGridManager->parseUrl(); + + // As we do not (yet) send data on the mainloop LLEventPump that varies + // with each frame, no need to instantiate a new LLSD event object each + // time. Obviously, if that changes, just instantiate the LLSD at the + // point of posting. + LLSD newFrame; BOOL restore_rendering_masks = FALSE; // Handle messages - while (!LLApp::isExiting()) + try { - LLFastTimer::nextFrame(); // Should be outside of any timer instances + while (!LLApp::isExiting()) + { + LLFastTimer::nextFrame(); // Should be outside of any timer instances - //clear call stack records - llclearcallstacks; + //clear call stack records + LL_CLEAR_CALLSTACKS(); - //check memory availability information - checkMemory() ; +#ifdef USE_CRASHPAD + // Not event based. Update per frame + SET_CRASHPAD_ANNOTATION_VALUE(session_duration, fmt::to_string(LLFrameTimer::getElapsedSeconds())); + SET_CRASHPAD_ANNOTATION_VALUE(memory_alloc, fmt::to_string((LLMemory::getCurrentRSS() >> 10)/1000.f)); +#endif + + //check memory availability information + checkMemory() ; - try - { // Check if we need to restore rendering masks. if (restore_rendering_masks) { @@ -1153,7 +1381,7 @@ bool LLAppViewer::mainLoop() if (gViewerWindow) { - LLFastTimer t2(FTM_MESSAGES); + LL_RECORD_BLOCK_TIME(FTM_MESSAGES); gViewerWindow->getWindow()->processMiscNativeEvents(); } @@ -1161,10 +1389,10 @@ bool LLAppViewer::mainLoop() if (gViewerWindow) { - LLFastTimer t2(FTM_MESSAGES); + LL_RECORD_BLOCK_TIME(FTM_MESSAGES); if (!restoreErrorTrap()) { - llwarns << " Someone took over my signal/exception handler (post messagehandling)!" << llendl; + LL_WARNS() << " Someone took over my signal/exception handler (post messagehandling)!" << LL_ENDL; } gViewerWindow->getWindow()->gatherInput(); @@ -1179,15 +1407,13 @@ bool LLAppViewer::mainLoop() #endif //memory leaking simulation - LLFloaterMemLeak* mem_leak_instance = - LLFloaterMemLeak::getInstance(); - if(mem_leak_instance) + if (auto mem_leak_instance = LLFloaterMemLeak::getInstance()) { - mem_leak_instance->idle() ; - } + mem_leak_instance->idle(); + } - // canonical per-frame event - mainloop.post(newFrame); + // canonical per-frame event + mainloop.post(newFrame); if (!LLApp::isExiting()) { @@ -1205,36 +1431,33 @@ bool LLAppViewer::mainLoop() { joystick->scanJoystick(); gKeyboard->scanKeyboard(); - if(isCrouch) - { + if (gAgent.isCrouching()) gAgent.moveUp(-1); - } - } // Update state based on messages, user input, object idle. { pauseMainloopTimeout(); // *TODO: Remove. Messages shouldn't be stalling for 20+ seconds! - LLFastTimer t3(FTM_IDLE); + LL_RECORD_BLOCK_TIME(FTM_IDLE); // bad_alloc!! idle(); if (gAres != NULL && gAres->isInitialized()) { pingMainloopTimeout("Main:ServicePump"); - LLFastTimer t4(FTM_PUMP); + LL_RECORD_BLOCK_TIME(FTM_PUMP); { - LLFastTimer t(FTM_PUMP_ARES); + LL_RECORD_BLOCK_TIME(FTM_PUMP_ARES); gAres->process(); } { - LLFastTimer t(FTM_PUMP_SERVICE); + LL_RECORD_BLOCK_TIME(FTM_PUMP_SERVICE); // this pump is necessary to make the login screen show up gServicePump->pump(); { - LLFastTimer t(FTM_SERVICE_CALLBACK); + LL_RECORD_BLOCK_TIME(FTM_SERVICE_CALLBACK); gServicePump->callback(); } } @@ -1257,11 +1480,11 @@ bool LLAppViewer::mainLoop() pingMainloopTimeout("Main:Display"); gGLActive = TRUE; display(); + pingMainloopTimeout("Main:Snapshot"); LLFloaterSnapshot::update(); // take snapshots gGLActive = FALSE; } - } pingMainloopTimeout("Main:Sleep"); @@ -1270,23 +1493,24 @@ bool LLAppViewer::mainLoop() // Sleep and run background threads { - LLFastTimer t2(FTM_SLEEP); + LL_RECORD_BLOCK_TIME(FTM_SLEEP); static const LLCachedControl run_multiple_threads("RunMultipleThreads",false); static const LLCachedControl yield_time("YieldTime", -1); // yield some time to the os based on command line option if(yield_time >= 0) { - LLFastTimer t(FTM_YIELD); + LL_RECORD_BLOCK_TIME(FTM_YIELD); ms_sleep(yield_time); } // yield cooperatively when not running as foreground window if ( gNoRender || (gViewerWindow && !gViewerWindow->getWindow()->getVisible()) - || !gFocusMgr.getAppHasFocus()) + || (!gFocusMgr.getAppHasFocus() && !AIFilePicker::activePicker) ) { // Sleep if we're not rendering, or the window is minimized. - S32 milliseconds_to_sleep = llclamp(gSavedSettings.getS32("BackgroundYieldTime"), 0, 1000); + static LLCachedControl s_bacground_yeild_time(gSavedSettings, "BackgroundYieldTime", 40); + S32 milliseconds_to_sleep = llclamp((S32)s_bacground_yeild_time, 0, 1000); // don't sleep when BackgroundYieldTime set to 0, since this will still yield to other threads // of equal priority on Windows if (milliseconds_to_sleep > 0) @@ -1309,36 +1533,36 @@ bool LLAppViewer::mainLoop() if (gPeriodicSlowFrame && (gFrameCount % 10 == 0)) { - llinfos << "Periodic slow frame - sleeping 500 ms" << llendl; + LL_INFOS() << "Periodic slow frame - sleeping 500 ms" << LL_ENDL; ms_sleep(500); } - const F64 max_idle_time = run_multiple_threads ? 0.0 : llmin(.005*10.0*gFrameIntervalSeconds, 0.005); // 50ms/second, no more than 5ms/frame + const F64 max_idle_time = run_multiple_threads ? 0.0 : llmin(.005*10.0*gFrameIntervalSeconds.value(), 0.005); // 50ms/second, no more than 5ms/frame idleTimer.reset(); while(1) { S32 work_pending = 0; S32 io_pending = 0; { - LLFastTimer ftm(FTM_TEXTURE_CACHE); - work_pending += LLAppViewer::getTextureCache()->update(1); // unpauses the texture cache thread + LL_RECORD_BLOCK_TIME(FTM_TEXTURE_CACHE); + work_pending += LLAppViewer::getTextureCache()->update(1); // unpauses the texture cache thread } { - LLFastTimer ftm(FTM_DECODE); - work_pending += LLAppViewer::getImageDecodeThread()->update(1); // unpauses the image thread + LL_RECORD_BLOCK_TIME(FTM_DECODE); + work_pending += LLAppViewer::getImageDecodeThread()->update(1); // unpauses the image thread } { - LLFastTimer ftm(FTM_DECODE); - work_pending += LLAppViewer::getTextureFetch()->update(1); // unpauses the texture fetch thread + LL_RECORD_BLOCK_TIME(FTM_DECODE); + work_pending += LLAppViewer::getTextureFetch()->update(1); // unpauses the texture fetch thread } { - LLFastTimer ftm(FTM_VFS); - io_pending += LLVFSThread::updateClass(1); + LL_RECORD_BLOCK_TIME(FTM_VFS); + io_pending += LLVFSThread::updateClass(1); } { - LLFastTimer ftm(FTM_LFS); - io_pending += LLLFSThread::updateClass(1); + LL_RECORD_BLOCK_TIME(FTM_LFS); + io_pending += LLLFSThread::updateClass(1); } if (io_pending > 1000) @@ -1368,68 +1592,43 @@ bool LLAppViewer::mainLoop() // LLAppViewer::getTextureFetch()->pause(); // Don't pause the fetch (IO) thread } //LLVFSThread::sLocal->pause(); // Prevent the VFS thread from running while rendering. - //LLLFSThread::sLocal->pause(); // Prevent the LFS thread from running while rendering. resumeMainloopTimeout(); pingMainloopTimeout("Main:End"); } } - catch(std::bad_alloc) - { - LLMemory::logMemoryInfo(TRUE) ; - - //stop memory leaking simulation - LLFloaterMemLeak* mem_leak_instance = - LLFloaterMemLeak::getInstance(); - if(mem_leak_instance) - { - mem_leak_instance->stop() ; - llwarns << "Bad memory allocation in LLAppViewer::mainLoop()!" << llendl ; - } - else - { - //output possible call stacks to log file. - LLError::LLCallStacks::print() ; - llerrs << "Bad memory allocation in LLAppViewer::mainLoop()!" << llendl ; - } - } + // Save snapshot for next time, if we made it through initialization + if (STATE_STARTED == LLStartUp::getStartupState()) + saveFinalSnapshot(); } - - // Save snapshot for next time, if we made it through initialization - if (STATE_STARTED == LLStartUp::getStartupState()) + catch(std::bad_alloc) { - try - { - saveFinalSnapshot(); - } - catch(std::bad_alloc) - { - llwarns << "Bad memory allocation when saveFinalSnapshot() is called!" << llendl ; + LLMemory::logMemoryInfo(TRUE); - //stop memory leaking simulation - LLFloaterMemLeak* mem_leak_instance = - LLFloaterMemLeak::getInstance(); - if(mem_leak_instance) - { - mem_leak_instance->stop() ; - } - } + //stop memory leaking simulation + if (auto mem_leak_instance = LLFloaterMemLeak::getInstance()) + mem_leak_instance->stop(); + + //output possible call stacks to log file. + LLError::LLCallStacks::print(); + + LL_ERRS() << "Bad memory allocation in LLAppViewer::mainLoop()!" << LL_ENDL; } delete gServicePump; destroyMainloopTimeout(); - llinfos << "Exiting main_loop" << llendflush; + LL_INFOS() << "Exiting main_loop" << LL_ENDL; return true; } void LLAppViewer::flushVFSIO() { - while (1) + while (true) { S32 pending = LLVFSThread::updateClass(0); pending += LLLFSThread::updateClass(0); @@ -1437,7 +1636,7 @@ void LLAppViewer::flushVFSIO() { break; } - llinfos << "Waiting for pending IO to finish: " << pending << llendflush; + LL_INFOS() << "Waiting for pending IO to finish: " << pending << LL_ENDL; ms_sleep(100); } } @@ -1447,7 +1646,16 @@ extern void cleanup_pose_stand(void); bool LLAppViewer::cleanup() { //ditch LLVOAvatarSelf instance - gAgentAvatarp = NULL; + gAgentAvatarp = nullptr; + + + // remove any old breakpad minidump files from the log directory + if (! isError()) + { + std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ""); + gDirUtilp->deleteFilesInDir(logdir, "*-*-*-*-*.dmp"); + } + cleanup_pose_stand(); //flag all elements as needing to be destroyed immediately @@ -1458,15 +1666,15 @@ bool LLAppViewer::cleanup() disconnectViewer(); - llinfos << "Viewer disconnected" << llendflush; + LL_INFOS() << "Viewer disconnected" << LL_ENDL; display_cleanup(); release_start_screen(); // just in case - LLError::logToFixedBuffer(NULL); + LLError::logToFixedBuffer(nullptr); // stop the fixed buffer recorder - llinfos << "Cleaning Up" << llendflush; + LL_INFOS() << "Cleaning Up" << LL_ENDL; // shut down mesh streamer gMeshRepo.shutdown(); @@ -1478,12 +1686,10 @@ bool LLAppViewer::cleanup() LLHUDObject::updateAll(); LLHUDManager::getInstance()->cleanupEffects(); LLHUDObject::cleanupHUDObjects(); - llinfos << "HUD Objects cleaned up" << llendflush; + LL_INFOS() << "HUD Objects cleaned up" << LL_ENDL; } - LLKeyframeDataCache::clear(); - - // End TransferManager before deleting systems it depends on (Audio, VFS, AssetStorage) + // End TransferManager before deleting systems it depends on (Audio, VFS, AssetStorage) #if 0 // this seems to get us stuck in an infinite loop... gTransferManager.cleanup(); #endif @@ -1497,7 +1703,7 @@ bool LLAppViewer::cleanup() } delete gAssetStorage; - gAssetStorage = NULL; + gAssetStorage = nullptr; LLPolyMesh::freeAllMeshes(); @@ -1505,38 +1711,16 @@ bool LLAppViewer::cleanup() // Note: this is where gLocalSpeakerMgr and gActiveSpeakerMgr used to be deleted. - LLWorldMap::getInstance()->reset(); // release any images - - LLCalc::cleanUp(); - - llinfos << "Global stuff deleted" << llendflush; - - if (gAudiop) + if (LLWorldMap::instanceExists()) { - // shut down the streaming audio sub-subsystem first, in case it relies on not outliving the general audio subsystem. - - LLStreamingAudioInterface *sai = gAudiop->getStreamingAudioImpl(); - delete sai; - gAudiop->setStreamingAudioImpl(NULL); + LLWorldMap::getInstance()->reset(); // release any images + } - // shut down the audio subsystem + LLCalc::cleanUp(); - bool want_longname = false; - if (gAudiop->getDriverName(want_longname) == "FMOD") - { - // This hack exists because fmod likes to occasionally - // crash or hang forever when shutting down, for no - // apparent reason. - llwarns << "Hack, skipping FMOD audio engine cleanup" << llendflush; - } - else - { - gAudiop->shutdown(); - } + AOSystem::deleteSingleton(); - delete gAudiop; - gAudiop = NULL; - } + LL_INFOS() << "Global stuff deleted" << LL_ENDL; // Note: this is where LLFeatureManager::getInstance()-> used to be deleted. @@ -1545,7 +1729,7 @@ bool LLAppViewer::cleanup() // such that we can suck rectangle information out of // it. cleanupSavedSettings(); - llinfos << "Settings patched up" << llendflush; + LL_INFOS() << "Settings patched up" << LL_ENDL; // moving this to below. /* @@ -1560,34 +1744,37 @@ bool LLAppViewer::cleanup() removeCacheFiles("*.clothing"); // - llinfos << "Cache files removed" << llendflush; + LL_INFOS() << "Cache files removed" << LL_ENDL; */ // - + void cleanup_menus(); cleanup_menus(); // Wait for any pending VFS IO flushVFSIO(); - llinfos << "Shutting down Views" << llendflush; + LL_INFOS() << "Shutting down Views" << LL_ENDL; // Destroy the UI if( gViewerWindow) gViewerWindow->shutdownViews(); - llinfos << "Cleaning up Inventory" << llendflush; + LL_INFOS() << "Cleaning up Inventory" << LL_ENDL; // Cleanup Inventory after the UI since it will delete any remaining observers // (Deleted observers should have already removed themselves) gInventory.cleanupInventory(); - llinfos << "Cleaning up Selections" << llendflush; + LL_INFOS() << "Cleaning up Selections" << LL_ENDL; // Clean up selection managers after UI is destroyed, as UI may be observing them. // Clean up before GL is shut down because we might be holding on to objects with texture references LLSelectMgr::cleanupGlobals(); - llinfos << "Shutting down OpenGL" << llendflush; + // Clean up before shutdownGL. + LLPostProcess::cleanupClass(); + + LL_INFOS() << "Shutting down OpenGL" << LL_ENDL; // Shut down OpenGL if( gViewerWindow) @@ -1598,24 +1785,22 @@ bool LLAppViewer::cleanup() // This may generate window reshape and activation events. // Therefore must do this before destroying the message system. delete gViewerWindow; - gViewerWindow = NULL; - llinfos << "ViewerWindow deleted" << llendflush; + gViewerWindow = nullptr; + LL_INFOS() << "ViewerWindow deleted" << LL_ENDL; } - llinfos << "Cleaning up Keyboard & Joystick" << llendflush; + LL_INFOS() << "Cleaning up Keyboard & Joystick" << LL_ENDL; // viewer UI relies on keyboard so keep it aound until viewer UI isa gone delete gKeyboard; - gKeyboard = NULL; + gKeyboard = nullptr; - llinfos << "Cleaning up Objects" << llendflush; + LL_INFOS() << "Cleaning up Objects" << LL_ENDL; LLViewerObject::cleanupVOClasses(); LLAvatarAppearance::cleanupClass(); - - LLPostProcess::cleanupClass(); LLTracker::cleanupInstance(); @@ -1629,17 +1814,17 @@ bool LLAppViewer::cleanup() LLVolumeMgr* volume_manager = LLPrimitive::getVolumeManager(); if (!volume_manager->cleanup()) { - llwarns << "Remaining references in the volume manager!" << llendflush; + LL_WARNS() << "Remaining references in the volume manager!" << LL_ENDL; } LLPrimitive::cleanupVolumeManager(); - llinfos << "Additional Cleanup..." << llendflush; + LL_INFOS() << "Additional Cleanup..." << LL_ENDL; LLViewerParcelMgr::cleanupGlobals(); // *Note: this is where gViewerStats used to be deleted. - //end_messaging_system(); + //end_messaging_system(); LLFollowCamMgr::cleanupClass(); //LLVolumeMgr::cleanupClass(); @@ -1654,10 +1839,10 @@ bool LLAppViewer::cleanup() // Also after shutting down the messaging system since it has VFS dependencies // - llinfos << "Cleaning up VFS" << llendflush; + LL_INFOS() << "Cleaning up VFS" << LL_ENDL; LLVFile::cleanupClass(); - llinfos << "Saving Data" << llendflush; + LL_INFOS() << "Saving Data" << LL_ENDL; // Quitting with "Remember Password" turned off should always stomp your // saved password, whether or not you successfully logged in. JC @@ -1677,18 +1862,14 @@ bool LLAppViewer::cleanup() // *FIX:Mani This should get really saved in a "logoff" mode. if (gSavedSettings.getString("PerAccountSettingsFile").empty()) { - llinfos << "Not saving per-account settings; don't know the account name yet." << llendl; + LL_INFOS() << "Not saving per-account settings; don't know the account name yet." << LL_ENDL; } else { gSavedPerAccountSettings.saveToFile(gSavedSettings.getString("PerAccountSettingsFile"), TRUE); - llinfos << "Saved settings" << llendflush; + LL_INFOS() << "Saved settings" << LL_ENDL; } - std::string crash_settings_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, CRASH_SETTINGS_FILE); - // save all settings, even if equals defaults - gCrashSettings.saveToFile(crash_settings_filename, FALSE); - // Save URL history file LLURLHistory::saveFile("url_history.xml"); @@ -1697,18 +1878,20 @@ bool LLAppViewer::cleanup() LLFloaterTeleportHistory::saveFile("teleport_history.xml"); + LocalAssetBrowser::deleteSingleton(); // + // save mute list. gMuteList used to also be deleted here too. LLMuteList::getInstance()->cache(gAgent.getID()); + if (mPurgeOnExit) { - llinfos << "Purging all cache files on exit" << llendflush; + LL_INFOS() << "Purging all cache files on exit" << LL_ENDL; gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""),"*.*"); } - removeMarkerFile(); // Any crashes from here on we'll just have to ignore // moved this stuff from above to make it conditional here... - if(!anotherInstanceRunning()) + if(!mSecondInstance) { removeCacheFiles("*.wav"); removeCacheFiles("*.tmp"); @@ -1717,31 +1900,28 @@ bool LLAppViewer::cleanup() removeCacheFiles("*.dsf"); removeCacheFiles("*.bodypart"); removeCacheFiles("*.clothing"); - llinfos << "Cache files removed" << llendflush; + LL_INFOS() << "Cache files removed" << LL_ENDL; } else { - llinfos << "Not removing cache files. Other viewer instance detected." << llendflush; + LL_INFOS() << "Not removing cache files. Other viewer instance detected." << LL_ENDL; } // - - writeDebugInfo(); - if(!gDirUtilp->getLindenUserDir(true).empty()) - LLViewerMedia::saveCookieFile(); + writeDebugInfo(); // Stop the plugin read thread if it's running. LLPluginProcessParent::setUseReadThread(false); // Stop curl responder call backs. AICurlInterface::shutdownCurl(); - llinfos << "Shutting down Threads" << llendflush; + LL_INFOS() << "Shutting down Threads" << LL_ENDL; // Let threads finish LLTimer idleTimer; idleTimer.reset(); const F64 max_idle_time = 5.f; // 5 seconds - while(1) + while(true) { S32 pending = 0; pending += LLAppViewer::getTextureCache()->update(1); // unpauses the worker thread @@ -1751,11 +1931,11 @@ bool LLAppViewer::cleanup() pending += LLLFSThread::updateClass(0); if (!pending) { - break; + break ; //done } else if (idleTimer.getElapsedTimeF64() >= max_idle_time) { - llwarns << "Quitting with pending background tasks." << llendl; + LL_WARNS() << "Quitting with pending background tasks." << LL_ENDL; break; } } @@ -1765,17 +1945,19 @@ bool LLAppViewer::cleanup() sTextureFetch->shutdown(); sTextureCache->shutdown(); sImageDecodeThread->shutdown(); + sTextureFetch->shutDownTextureCacheThread(); sTextureFetch->shutDownImageDecodeThread(); delete sTextureCache; - sTextureCache = NULL; + sTextureCache = nullptr; delete sTextureFetch; - sTextureFetch = NULL; + sTextureFetch = nullptr; delete sImageDecodeThread; - sImageDecodeThread = NULL; + sImageDecodeThread = nullptr; - llinfos << "Cleaning up Media and Textures" << llendflush; + + LL_INFOS() << "Cleaning up Media and Textures" << LL_ENDL; //Note: //LLViewerMedia::cleanupClass() has to be put before gTextureList.shutdown() @@ -1790,30 +1972,30 @@ bool LLAppViewer::cleanup() LLVFSThread::cleanupClass(); LLLFSThread::cleanupClass(); - llinfos << "VFS Thread finished" << llendflush; + LL_INFOS() << "VFS Thread finished" << LL_ENDL; #ifndef LL_RELEASE_FOR_DOWNLOAD - llinfos << "Auditing VFS" << llendl; + LL_INFOS() << "Auditing VFS" << LL_ENDL; if(gVFS) { gVFS->audit(); } #endif - llinfos << "Misc Cleanup" << llendflush; + LL_INFOS() << "Misc Cleanup" << LL_ENDL; // For safety, the LLVFS has to be deleted *after* LLVFSThread. This should be cleaned up. // (LLVFS doesn't know about LLVFSThread so can't kill pending requests) -Steve delete gStaticVFS; - gStaticVFS = NULL; + gStaticVFS = nullptr; delete gVFS; - gVFS = NULL; + gVFS = nullptr; LLWatchdog::getInstance()->cleanup(); - llinfos << "Shutting down message system" << llendflush; + LL_INFOS() << "Shutting down message system" << LL_ENDL; end_messaging_system(); - llinfos << "Message system deleted." << llendflush; + LL_INFOS() << "Message system deleted." << LL_ENDL; LLApp::stopErrorThread(); // The following call is not thread-safe. Have to stop all threads. stopEngineThread(); @@ -1822,24 +2004,23 @@ bool LLAppViewer::cleanup() // Cleanup settings last in case other classes reference them. gSavedSettings.cleanup(); gColors.cleanup(); - gCrashSettings.cleanup(); LLViewerAssetStatsFF::cleanup(); // If we're exiting to launch an URL, do that here so the screen // is at the right resolution before we launch IE. if (!gLaunchFileOnQuit.empty()) { - llinfos << "Launch file on quit." << llendflush; + LL_INFOS() << "Launch file on quit." << LL_ENDL; #if LL_WINDOWS // Indicate an application is starting. - SetCursor(LoadCursor(NULL, IDC_WAIT)); + SetCursor(LoadCursor(nullptr, IDC_WAIT)); #endif // HACK: Attempt to wait until the screen res. switch is complete. ms_sleep(1000); LLWeb::loadURLExternal( gLaunchFileOnQuit ); - llinfos << "File launched." << llendflush; + LL_INFOS() << "File launched." << LL_ENDL; } LLWearableType::cleanupClass(); @@ -1851,21 +2032,25 @@ bool LLAppViewer::cleanup() ll_close_fail_log(); - MEM_TRACK_RELEASE + LLError::LLCallStacks::cleanup(); - llinfos << "Goodbye!" << llendflush; + removeMarkerFiles(); + + MEM_TRACK_RELEASE + + LL_INFOS() << "Goodbye!" << LL_ENDL; // return 0; return true; } -// A callback for llerrs to call during the watchdog error. +// A callback for LL_ERRS() to call during the watchdog error. void watchdog_llerrs_callback(const std::string &error_string) { gLLErrorActivated = true; #ifdef LL_WINDOWS - RaiseException(0,0,0,0); + RaiseException(0,0,0,nullptr); #else raise(SIGQUIT); #endif @@ -1875,7 +2060,7 @@ void watchdog_llerrs_callback(const std::string &error_string) void watchdog_killer_callback() { LLError::setFatalFunction(watchdog_llerrs_callback); - llerrs << "Watchdog killer event" << llendl; + LL_ERRS() << "Watchdog killer event" << LL_ENDL; } bool LLAppViewer::initThreads() @@ -1886,9 +2071,8 @@ bool LLAppViewer::initThreads() static const bool enable_threads = true; #endif - const S32 NEVER_SUBMIT_REPORT = 2; bool use_watchdog = gSavedSettings.getBOOL("WatchdogEnabled"); - bool send_reports = gCrashSettings.getS32(CRASH_BEHAVIOR_SETTING) != NEVER_SUBMIT_REPORT; + bool send_reports = gSavedSettings.getS32("CrashSubmitBehavior") == 1; if(use_watchdog && send_reports) { LLWatchdog::getInstance()->init(watchdog_killer_callback); @@ -1925,8 +2109,8 @@ void errorCallback(const std::string &error_string) static std::string last_message; if(last_message != error_string) { - U32 response = OSMessageBox(error_string, "Crash Loop?", OSMB_YESNO); - if(response) + U32 response = OSMessageBox(error_string, LLTrans::getString("MBFatalError"), OSMB_YESNO); + if (response == OSBTN_NO) { last_message = error_string; return; @@ -1935,45 +2119,101 @@ void errorCallback(const std::string &error_string) //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 + // static info file. + LLAppViewer::instance()->writeDebugInfo(); + LLError::crashAndLoop(error_string); } } -bool LLAppViewer::initLogging() +void LLAppViewer::initLoggingAndGetLastDuration() { // // Set up logging defaults for the viewer // LLError::initForApplication( - gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "")); + gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "") + ); LLError::setFatalFunction(errorCallback); + //LLError::setTimeFunction(getRuntime); + initLoggingInternal(); +} +void LLAppViewer::initLoggingInternal() +{ // Remove the last ".old" log file. std::string old_log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, - "Singularity.old"); + OLD_LOG_FILE); LLFile::remove(old_log_file); - // Rename current log file to ".old" + // Get name of the log file std::string log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, - "Singularity.log"); - LLFile::rename(log_file, old_log_file); + LOG_FILE); + /* + * Before touching any log files, compute the duration of the last run + * by comparing the ctime of the previous start marker file with the ctime + * of the last log file. + */ + std::string start_marker_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, START_MARKER_FILE_NAME); + llstat start_marker_stat; + llstat log_file_stat; + std::ostringstream duration_log_stream; // can't log yet, so save any message for when we can below + int start_stat_result = LLFile::stat(start_marker_file_name, &start_marker_stat); + int log_stat_result = LLFile::stat(log_file, &log_file_stat); + if ( 0 == start_stat_result && 0 == log_stat_result ) + { + int elapsed_seconds = log_file_stat.st_ctime - start_marker_stat.st_ctime; + // only report a last run time if the last viewer was the same version + // because this stat will be counted against this version + if ( markerIsSameVersion(start_marker_file_name) ) + { + gLastExecDuration = elapsed_seconds; + } + else + { + duration_log_stream << "start marker from some other version; duration is not reported"; + gLastExecDuration = -1; + } + } + else + { + // at least one of the LLFile::stat calls failed, so we can't compute the run time + duration_log_stream << "duration stat failure; start: "<< start_stat_result << " log: " << log_stat_result; + gLastExecDuration = -1; // unknown + } + std::string duration_log_msg(duration_log_stream.str()); - // Set the log file to Singularity.log + // Create a new start marker file for comparison with log file time for the next run + LLAPRFile start_marker_file ; + start_marker_file.open(start_marker_file_name, LL_APR_WB); + if (start_marker_file.getFileHandle()) + { + recordMarkerVersion(start_marker_file); + start_marker_file.close(); + } - LLError::logToFile(log_file); + // Rename current log file to ".old" + LLFile::rename(log_file, old_log_file); - // *FIX:Mani no error handling here! - return true; + // Set the log file to SecondLife.log + LLError::logToFile(log_file); + if (!duration_log_msg.empty()) + { + LL_WARNS("MarkerFile") << duration_log_msg << LL_ENDL; + } } bool LLAppViewer::loadSettingsFromDirectory(AIReadAccess const& settings_r, - std::string const& location_key, - bool set_defaults) + std::string const& location_key, + bool set_defaults) { // Find and vet the location key. if(!mSettingsLocationList.has(location_key)) { - llerrs << "Requested unknown location: " << location_key << llendl; + LL_ERRS() << "Requested unknown location: " << location_key << LL_ENDL; return false; } @@ -1981,13 +2221,13 @@ bool LLAppViewer::loadSettingsFromDirectory(AIReadAccess cons if(!location.has("PathIndex")) { - llerrs << "Settings location is missing PathIndex value. Settings cannot be loaded." << llendl; + LL_ERRS() << "Settings location is missing PathIndex value. Settings cannot be loaded." << LL_ENDL; return false; } ELLPath path_index = (ELLPath)(location.get("PathIndex").asInteger()); if(path_index <= LL_PATH_NONE || path_index >= LL_PATH_LAST) { - llerrs << "Out of range path index in app_settings/settings_files.xml" << llendl; + LL_ERRS() << "Out of range path index in app_settings/settings_files.xml" << LL_ENDL; return false; } @@ -1998,12 +2238,12 @@ bool LLAppViewer::loadSettingsFromDirectory(AIReadAccess cons std::string const settings_group = (*itr).first; settings_map_type::const_iterator const settings_group_iter = settings_r->find(settings_group); - llinfos << "Attempting to load settings for the group " << settings_group - << " - from location " << location_key << llendl; + LL_INFOS() << "Attempting to load settings for the group " << settings_group + << " - from location " << location_key << LL_ENDL; if(settings_group_iter == settings_r->end()) { - llwarns << "No matching settings group for name " << settings_group << llendl; + LL_WARNS() << "No matching settings group for name " << settings_group << LL_ENDL; continue; } @@ -2038,18 +2278,18 @@ bool LLAppViewer::loadSettingsFromDirectory(AIReadAccess cons { if(requirement == 1) { - llwarns << "Error: Cannot load required settings file from: " - << full_settings_path << llendl; + LL_WARNS() << "Error: Cannot load required settings file from: " + << full_settings_path << LL_ENDL; return false; } else { - llwarns << "Cannot load " << full_settings_path << " - No settings found." << llendl; + LL_WARNS() << "Cannot load " << full_settings_path << " - No settings found." << LL_ENDL; } } else { - llinfos << "Loaded settings file " << full_settings_path << llendl; + LL_INFOS() << "Loaded settings file " << full_settings_path << LL_ENDL; } } @@ -2083,15 +2323,16 @@ bool LLAppViewer::initConfiguration() //Set up internal pointers settings[sGlobalSettingsName] = &gSavedSettings; settings[sPerAccountSettingsName] = &gSavedPerAccountSettings; - settings[sCrashSettingsName] = &gCrashSettings; //Load settings files list std::string settings_file_list = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "settings_files.xml"); LLControlGroup settings_control("groups"); - llinfos << "Loading settings file list" << settings_file_list << llendl; + LL_INFOS() << "Loading settings file list" << settings_file_list << LL_ENDL; if (0 == settings_control.loadFromFile(settings_file_list)) { - llerrs << "Cannot load default configuration file " << settings_file_list << llendl; + OSMessageBox("Cannot load default configuration file " + settings_file_list + " The installation may be corrupted.", + LLStringUtil::null,OSMB_OK); + return false; } mSettingsLocationList = settings_control.getLLSD("Locations"); @@ -2102,7 +2343,7 @@ bool LLAppViewer::initConfiguration() // - set procedural settings values // - read command line settings // - selectively apply settings needed to load user settings. - // - load overrides from user_settings + // - load overrides from user_settings // - apply command line settings (to override the overrides) // - load per account settings (happens in llstartup @@ -2110,9 +2351,9 @@ bool LLAppViewer::initConfiguration() bool set_defaults = true; if(!loadSettingsFromDirectory(settings_w, "Default", set_defaults)) { - std::ostringstream msg; - msg << "Unable to load default settings file. The installation may be corrupted."; - OSMessageBox(msg.str(),LLStringUtil::null,OSMB_OK); + OSMessageBox( + "Unable to load default settings file. The installation may be corrupted.", + LLStringUtil::null,OSMB_OK); return false; } @@ -2124,10 +2365,11 @@ bool LLAppViewer::initConfiguration() gSavedSettings.connectCOAVars(gSavedPerAccountSettings); // - set procedural settings + // Note: can't use LL_PATH_PER_SL_ACCOUNT for any of these since we haven't logged in yet gSavedSettings.setString("ClientSettingsFile", - gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, getSettingsFilename("Default", "Global"))); + gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, getSettingsFilename("Default", "Global"))); - gSavedSettings.setString("VersionChannelName", gVersionChannel); + gSavedSettings.setString("VersionChannelName", LLVersionInfo::getChannel()); #if 0 //#ifndef LL_RELEASE_FOR_DOWNLOAD // provide developer build only overrides for these control variables that are not @@ -2156,8 +2398,6 @@ bool LLAppViewer::initConfiguration() gSavedSettings.setBOOL("WatchdogEnabled", FALSE); #endif - gCrashSettings.getControl(CRASH_BEHAVIOR_SETTING)->getSignal()->connect(boost::bind(&handleCrashSubmitBehaviorChanged, _2)); - // These are warnings that appear on the first experience of that condition. // They are already set in the settings_default.xml file, but still need to be added to LLFirstUse // for disable/reset ability @@ -2198,9 +2438,9 @@ bool LLAppViewer::initConfiguration() if(!initParseCommandLine(clp)) { - llwarns << "Error parsing command line options. Command Line options ignored." << llendl; + LL_WARNS() << "Error parsing command line options. Command Line options ignored." << LL_ENDL; - llinfos << "Command line usage:\n" << clp << llendl; + LL_INFOS() << "Command line usage:\n" << clp << LL_ENDL; std::ostringstream msg; msg << LLTrans::getString("MBCmdLineError") << clp.getErrorMessage(); @@ -2210,6 +2450,19 @@ bool LLAppViewer::initConfiguration() // - selectively apply settings + // Portability Mode! + if (clp.hasOption("portable")) + { + const std::string log = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, LOG_FILE); + LL_INFOS() << "Attempting to use portable settings and cache!" << LL_ENDL; + gDirUtilp->makePortable(); + initLoggingInternal(); // Switch to portable log file + LL_INFOS() << "Portable viewer configuration initialized!" << LL_ENDL; + LLFile::remove(log); + LL_INFOS() << "Cleaned up local log file to keep this computer untouched." << LL_ENDL; + } + // + // If the user has specified a alternate settings file name. // Load it now before loading the user_settings/settings.xml if(clp.hasOption("settings")) @@ -2218,8 +2471,35 @@ bool LLAppViewer::initConfiguration() gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, clp.getOption("settings")[0]); gSavedSettings.setString("ClientSettingsFile", user_settings_filename); - llinfos << "Using command line specified settings filename: " - << user_settings_filename << llendl; + LL_INFOS("Settings") << "Using command line specified settings filename: " + << user_settings_filename << LL_ENDL; + } + else + { + std::string channel(LLVersionInfo::getChannel()); + LLStringUtil::toLower(channel); + switch (LLVersionInfo::getViewerMaturity()) + { + default: + case LLVersionInfo::TEST_VIEWER: + case LLVersionInfo::PROJECT_VIEWER: + case LLVersionInfo::ALPHA_VIEWER: + case LLVersionInfo::BETA_VIEWER: + { + channel.erase(std::remove_if(channel.begin(), channel.end(), isspace), channel.end()); + break; + } + case LLVersionInfo::RELEASE_VIEWER: + size_t pos = channel.find(' '); + if (pos != channel.npos) + channel.erase(pos, channel.npos); + break; + } + std::string settings_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, + llformat("settings_%s.xml", channel.c_str())); + gSavedSettings.setString("ClientSettingsFile", settings_filename); + LL_INFOS() << "Using default settings filename from channel: " + << settings_filename << LL_ENDL; } // - load overrides from user_settings @@ -2233,8 +2513,8 @@ bool LLAppViewer::initConfiguration() // ASAP or we might miss init issue etc. if(clp.hasOption("disablecrashlogger")) { - llwarns << "Crashes will be handled by system, stack trace logs and crash logger are both disabled" <disableCrashlogger(); + LL_WARNS() << "Crashes will be handled by system, stack trace logs and crash logger are both disabled" <getControl(name); - if(c) - { - c->setValue(value, false); - } - else - { - llwarns << "'--set' specified with unknown setting: '" - << name << "'." << llendl; - } - } - } - } + if(clp.hasOption("set")) + { + const LLCommandLineParser::token_vector_t& set_values = clp.getOption("set"); + if(0x1 & set_values.size()) + { + LL_WARNS() << "Invalid '--set' parameter count." << LL_ENDL; + } + else + { + LLCommandLineParser::token_vector_t::const_iterator itr = set_values.begin(); + for(; itr != set_values.end(); ++itr) + { + const std::string& name = *itr; + const std::string& value = *(++itr); + LLControlVariable* c = settings[sGlobalSettingsName]->getControl(name); + if(c) + { + c->setValue(value, false); + } + else + { + LL_WARNS() << "'--set' specified with unknown setting: '" + << name << "'." << LL_ENDL; + } + } + } + } if (!gHippoGridManager) { @@ -2312,77 +2592,48 @@ bool LLAppViewer::initConfiguration() // Handle slurl use. NOTE: Don't let SL-55321 reappear. - // *FIX: This init code should be made more robust to prevent - // the issue SL-55321 from returning. One thought is to allow - // only select options to be set from command line when a slurl - // is specified. More work on the settings system is needed to - // achieve this. For now... - - // *NOTE:Mani The command line parser parses tokens and is - // setup to bail after parsing the '--url' option or the - // first option specified without a '--option' flag (or - // any other option that uses the 'last_option' setting - - // see LLControlGroupCLP::configure()) - - // What can happen is that someone can use IE (or potentially - // other browsers) and do the rough equivalent of command - // injection and steal passwords. Phoenix. SL-55321 - if(clp.hasOption("url")) - { + // *FIX: This init code should be made more robust to prevent + // the issue SL-55321 from returning. One thought is to allow + // only select options to be set from command line when a slurl + // is specified. More work on the settings system is needed to + // achieve this. For now... + + // *NOTE:Mani The command line parser parses tokens and is + // setup to bail after parsing the '--url' option or the + // first option specified without a '--option' flag (or + // any other option that uses the 'last_option' setting - + // see LLControlGroupCLP::configure()) + + // What can happen is that someone can use IE (or potentially + // other browsers) and do the rough equivalent of command + // injection and steal passwords. Phoenix. SL-55321 + if(clp.hasOption("url")) + { LLStartUp::setStartSLURL(LLSLURL(clp.getOption("url")[0])); if(LLStartUp::getStartSLURL().getType() == LLSLURL::LOCATION) { gHippoGridManager->setCurrentGrid(LLStartUp::getStartSLURL().getGrid()); } - } - else if(clp.hasOption("slurl")) - { + } + else if(clp.hasOption("slurl")) + { LLSLURL start_slurl(clp.getOption("slurl")[0]); LLStartUp::setStartSLURL(start_slurl); - } - - const LLControlVariable* skinfolder = gSavedSettings.getControl("SkinCurrent"); - if(skinfolder && LLStringUtil::null != skinfolder->getValue().asString()) - { - gDirUtilp->setSkinFolder(skinfolder->getValue().asString()); - } - - // XUI:translate - gSecondLife = "Singularity Viewer"; - - // Read skin/branding settings if specified. - //if (! gDirUtilp->getSkinDir().empty() ) - //{ - // std::string skin_def_file = gDirUtilp->findSkinnedFilename("skin.xml"); - // LLXmlTree skin_def_tree; - - // if (!skin_def_tree.parseFile(skin_def_file)) - // { - // llerrs << "Failed to parse skin definition." << llendl; - // } + } - //} + const LLControlVariable* skinfolder = gSavedSettings.getControl("SkinCurrent"); + if(skinfolder && LLStringUtil::null != skinfolder->getValue().asString()) + { + // Examining "Language" may not suffice -- see LLUI::getLanguage() + // logic. Unfortunately LLUI::getLanguage() doesn't yet do us much + // good because we haven't yet called LLUI::initClass(). + gDirUtilp->setSkinFolder(skinfolder->getValue().asString(), + gSavedSettings.getString("Language")); + } #if LL_DARWIN // Initialize apple menubar and various callbacks init_apple_menu(LLTrans::getString("APP_NAME").c_str()); - -#if __ppc__ - // If the CPU doesn't have Altivec (i.e. it's not at least a G4), don't go any further. - // Only test PowerPC - all Intel Macs have SSE. - if(!gSysCPU.hasAltivec()) - { - std::ostringstream msg; - msg << LLTrans::getString("MBRequiresAltiVec"); - OSMessageBox( - msg.str(), - LLStringUtil::null, - OSMB_OK); - removeMarkerFile(); - return false; - } -#endif - #endif // LL_DARWIN // Display splash screen. Must be after above check for previous @@ -2405,12 +2656,11 @@ bool LLAppViewer::initConfiguration() // // Set the name of the window // - gWindowTitle = LLTrans::getString("APP_NAME"); + gWindowTitle = LLTrans::getString("APP_NAME") + llformat(" (%d) ", LLVersionInfo::getBuild()) #if LL_DEBUG - gWindowTitle += std::string(" [DEBUG] ") + gArgs; -#else - gWindowTitle += std::string(" ") + gArgs; + + "[DEBUG] " #endif + + gArgs; LLStringUtil::truncate(gWindowTitle, 255); //RN: if we received a URL, hand it off to the existing instance. @@ -2428,54 +2678,32 @@ bool LLAppViewer::initConfiguration() } } - if (!gSavedSettings.getBOOL("AllowMultipleViewers")) + + // + // Check for another instance of the app running + // + if (mSecondInstance && !gSavedSettings.getBOOL("AllowMultipleViewers")) { - // - // Check for another instance of the app running - // - - mSecondInstance = anotherInstanceRunning(); - - if (mSecondInstance) - { - std::ostringstream msg; - msg << LLTrans::getString("MBAlreadyRunning"); - OSMessageBox( - msg.str(), - LLStringUtil::null, - OSMB_OK); - return false; - } + OSMessageBox( + LLTrans::getString("MBAlreadyRunning"), + LLStringUtil::null, + OSMB_OK); + return false; + } - initMarkerFile(); - - checkForCrash(); - } - else + if (mSecondInstance) { - mSecondInstance = anotherInstanceRunning(); - - 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"); + if(disable_voice && !gSavedSettings.getBOOL("VoiceMultiInstance")) { - // 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"); - if(disable_voice && !gSavedSettings.getBOOL("VoiceMultiInstance")) - { - const BOOL DO_NOT_PERSIST = FALSE; - disable_voice->setValue(LLSD(TRUE), DO_NOT_PERSIST); - } + const BOOL DO_NOT_PERSIST = FALSE; + disable_voice->setValue(LLSD(TRUE), DO_NOT_PERSIST); } - - initMarkerFile(); - - if(!mSecondInstance) - { - checkForCrash(); - } } - // need to do this here - need to have initialized global settings first + // need to do this here - need to have initialized global settings first std::string nextLoginLocation = gSavedSettings.getString( "NextLoginLocation" ); if ( !nextLoginLocation.empty() ) { @@ -2488,62 +2716,6 @@ bool LLAppViewer::initConfiguration() return true; // Config was successful. } - -void LLAppViewer::checkForCrash(void) -{ -#if LL_SEND_CRASH_REPORTS - // *NOTE:Mani The current state of the crash handler has the MacOSX - // sending all crash reports as freezes, in order to let - // the MacOSX CrashRepoter generate stacks before spawning the - // SL crash logger. - // The Linux and Windows clients generate their own stacks and - // spawn the SL crash logger immediately. This may change in the future. -#if LL_DARWIN - if(gLastExecEvent != LAST_EXEC_NORMAL) -#else - if (gLastExecEvent == LAST_EXEC_FROZE) -#endif - { - llinfos << "Last execution froze, requesting to send crash report." << llendl; - // - // Pop up a freeze or crash warning dialog - // - S32 choice; - const S32 cb = gCrashSettings.getS32(CRASH_BEHAVIOR_SETTING); - if(cb == CRASH_BEHAVIOR_ASK) - { - std::ostringstream msg; - msg << LLTrans::getString("MBFrozenCrashed"); - std::string alert = LLTrans::getString("APP_NAME") + " " + LLTrans::getString("MBAlert"); - choice = OSMessageBox(msg.str(), - alert, - OSMB_YESNO); - } - else if(cb == CRASH_BEHAVIOR_NEVER_SEND) - { - choice = OSBTN_NO; - } - else - { - choice = OSBTN_YES; - } - - if (OSBTN_YES == choice) - { - llinfos << "Sending crash report." << llendl; - - bool report_freeze = true; - handleCrashReporting(report_freeze); - } - else - { - llinfos << "Not sending crash report." << llendl; - } - } -#endif // LL_SEND_CRASH_REPORTS - -} - bool LLAppViewer::initWindow() { LL_INFOS("AppInit") << "Initializing window..." << LL_ENDL; @@ -2586,6 +2758,8 @@ bool LLAppViewer::initWindow() gPipeline.init(); LL_INFOS("AppInit") << "gPipeline Initialized" << LL_ENDL; stop_glerror(); + + gGL.restoreVertexBuffers(); gViewerWindow->initGLDefaults(); gSavedSettings.setBOOL("RenderInitError", FALSE); @@ -2610,16 +2784,35 @@ bool LLAppViewer::initWindow() //gViewerWindow->getWindow()->show(); LL_INFOS("AppInit") << "Window initialization done." << LL_ENDL; + return true; } -void LLAppViewer::writeDebugInfo() +void LLAppViewer::writeDebugInfo(bool isStatic) { - std::string debug_filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"debug_info.log"); - llinfos << "Opening debug file " << debug_filename << llendl; - llofstream out_file(debug_filename); - LLSDSerialize::toPrettyXML(gDebugInfo, out_file); - out_file.close(); +#if !defined(USE_CRASHPAD) + //Try to do the minimum when writing data during a crash. + std::string* debug_filename; + debug_filename = ( isStatic + ? getStaticDebugFile() + : getDynamicDebugFile() ); + + LL_INFOS() << "Writing debug file " << *debug_filename << LL_ENDL; + llofstream out_file(debug_filename->c_str()); + + isStatic ? LLSDSerialize::toPrettyXML(gDebugInfo, out_file) + : LLSDSerialize::toPrettyXML(gDebugInfo["Dynamic"], out_file); +#else + SET_CRASHPAD_ANNOTATION_VALUE(fatal_message, gDebugInfo["FatalMessage"].asString()); + SET_CRASHPAD_ANNOTATION_VALUE(grid_name, gDebugInfo["GridName"].asString()); + SET_CRASHPAD_ANNOTATION_VALUE(region_name, gDebugInfo["CurrentRegion"].asString()); + SET_CRASHPAD_ANNOTATION_VALUE(cpu_string, gDebugInfo["CPUInfo"]["CPUString"].asString()); + SET_CRASHPAD_ANNOTATION_VALUE(gpu_string, gDebugInfo["GraphicsCard"].asString()); + SET_CRASHPAD_ANNOTATION_VALUE(gl_version, gDebugInfo["GLInfo"]["GLVersion"].asString()); + SET_CRASHPAD_ANNOTATION_VALUE(session_duration, fmt::to_string(LLFrameTimer::getElapsedSeconds())); + SET_CRASHPAD_ANNOTATION_VALUE(memory_alloc, fmt::to_string((LLMemory::getCurrentRSS() >> 10) / 1000.f)); + SET_CRASHPAD_ANNOTATION_VALUE(memory_sys, fmt::to_string(gDebugInfo["RAMInfo"]["Physical"].asInteger() * 0.001f)); +#endif } void LLAppViewer::cleanupSavedSettings() @@ -2660,6 +2853,8 @@ void LLAppViewer::cleanupSavedSettings() { gSavedSettings.setF32("RenderFarClip", gAgentCamera.mDrawDistance); } + + LLSpeakerVolumeStorage::deleteSingleton(); } void LLAppViewer::removeCacheFiles(const std::string& file_mask) @@ -2669,13 +2864,23 @@ void LLAppViewer::removeCacheFiles(const std::string& file_mask) void LLAppViewer::writeSystemInfo() { + + if (! gDebugInfo.has("Dynamic") ) + gDebugInfo["Dynamic"] = LLSD::emptyMap(); + gDebugInfo["SLLog"] = LLError::logFileName(); - gDebugInfo["ClientInfo"]["Name"] = gVersionChannel; - gDebugInfo["ClientInfo"]["MajorVersion"] = gVersionMajor; - gDebugInfo["ClientInfo"]["MinorVersion"] = gVersionMinor; - gDebugInfo["ClientInfo"]["PatchVersion"] = gVersionPatch; - gDebugInfo["ClientInfo"]["BuildVersion"] = gVersionBuild; + gDebugInfo["ClientInfo"]["Name"] = LLVersionInfo::getChannel(); + gDebugInfo["ClientInfo"]["MajorVersion"] = LLVersionInfo::getMajor(); + gDebugInfo["ClientInfo"]["MinorVersion"] = LLVersionInfo::getMinor(); + gDebugInfo["ClientInfo"]["PatchVersion"] = LLVersionInfo::getPatch(); + gDebugInfo["ClientInfo"]["BuildVersion"] = LLVersionInfo::getBuild(); + gDebugInfo["ClientInfo"]["AddressSize"] = +#if defined(_WIN64) || defined(__x86_64__) + "64"; +#else + "32"; +#endif gDebugInfo["CAFilename"] = gDirUtilp->getCAFile(); @@ -2686,8 +2891,8 @@ void LLAppViewer::writeSystemInfo() gDebugInfo["CPUInfo"]["CPUSSE"] = gSysCPU.hasSSE(); gDebugInfo["CPUInfo"]["CPUSSE2"] = gSysCPU.hasSSE2(); - gDebugInfo["RAMInfo"]["Physical"] = (LLSD::Integer)(gSysMemory.getPhysicalMemoryKB()); - gDebugInfo["RAMInfo"]["Allocated"] = (LLSD::Integer)(gMemoryAllocated>>10); // MB -> KB + gDebugInfo["RAMInfo"]["Physical"] = LLSD::Integer(gSysMemory.getPhysicalMemoryKB().value()); + gDebugInfo["RAMInfo"]["Allocated"] = LLSD::Integer(gMemoryAllocated.valueInUnits()); gDebugInfo["OSInfo"] = getOSInfo().getOSStringSimple(); // The user is not logged on yet, but record the current grid choice login url @@ -2706,11 +2911,19 @@ void LLAppViewer::writeSystemInfo() // If the crash is handled by LLAppViewer::handleViewerCrash, ie not a freeze, // then the value of "CrashNotHandled" will be set to true. gDebugInfo["CrashNotHandled"] = (LLSD::Boolean)true; + + // Insert crash host url (url to post crash log to) if configured. This insures + // that the crash report will go to the proper location in the case of a + // prior freeze. + std::string crashHostUrl = gSavedSettings.get("CrashHostUrl"); + if (!crashHostUrl.empty()) + { + gDebugInfo["CrashHostUrl"] = crashHostUrl; + } // Dump some debugging info - LL_INFOS("SystemInfo") << LLTrans::getString("APP_NAME") - << " version " << gVersionMajor << "." << gVersionMinor << "." << gVersionPatch - << LL_ENDL; + LL_INFOS("SystemInfo") << "Application: " << LLTrans::getString("APP_NAME") << LL_ENDL; + LL_INFOS("SystemInfo") << "Version: " << LLVersionInfo::getChannelAndVersion() << LL_ENDL; // Dump the local time and time zone time_t now; @@ -2730,18 +2943,11 @@ void LLAppViewer::writeSystemInfo() writeDebugInfo(); // Save out debug_info.log early, in case of crash. } -void LLAppViewer::handleSyncViewerCrash() -{ - LLAppViewer* pApp = LLAppViewer::instance(); - // Call to pure virtual, handled by platform specific llappviewer instance. - pApp->handleSyncCrashTrace(); -} - void LLAppViewer::handleViewerCrash() { - llinfos << "Handle viewer crash entry." << llendl; + LL_INFOS("CRASHREPORT") << "Handle viewer crash entry." << LL_ENDL; - llinfos << "Last render pool type: " << LLPipeline::sCurRenderPoolType << llendl ; + LL_INFOS("CRASHREPORT") << "Last render pool type: " << LLPipeline::sCurRenderPoolType << LL_ENDL ; LLMemory::logMemoryInfo(true) ; @@ -2768,100 +2974,106 @@ void LLAppViewer::handleViewerCrash() } pApp->mReportedCrash = TRUE; - // Make sure the watchdog gets turned off... -// pApp->destroyMainloopTimeout(); // SJB: Bah. This causes the crash handler to hang, not sure why. + // Insert crash host url (url to post crash log to) if configured. + std::string crashHostUrl = gSavedSettings.get("CrashHostUrl"); + if (!crashHostUrl.empty()) + { + gDebugInfo["Dynamic"]["CrashHostUrl"] = crashHostUrl; + } - //We already do this in writeSystemInfo(), but we do it again here to make /sure/ we have a version - //to check against no matter what - gDebugInfo["ClientInfo"]["Name"] = gVersionChannel; - - gDebugInfo["ClientInfo"]["MajorVersion"] = gVersionMajor; - gDebugInfo["ClientInfo"]["MinorVersion"] = gVersionMinor; - gDebugInfo["ClientInfo"]["PatchVersion"] = gVersionPatch; - gDebugInfo["ClientInfo"]["BuildVersion"] = gVersionBuild; - LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); if ( parcel && parcel->getMusicURL()[0]) { - gDebugInfo["ParcelMusicURL"] = parcel->getMusicURL(); + gDebugInfo["Dynamic"]["ParcelMusicURL"] = parcel->getMusicURL(); } if ( parcel && parcel->getMediaURL()[0]) { - gDebugInfo["ParcelMediaURL"] = parcel->getMediaURL(); + gDebugInfo["Dynamic"]["ParcelMediaURL"] = parcel->getMediaURL(); } - - + gDebugInfo["SettingsFilename"] = gSavedSettings.getString("ClientSettingsFile"); gDebugInfo["CAFilename"] = gDirUtilp->getCAFile(); gDebugInfo["ViewerExePath"] = gDirUtilp->getExecutablePathAndName(); gDebugInfo["CurrentPath"] = gDirUtilp->getCurPath(); - gDebugInfo["SessionLength"] = F32(LLFrameTimer::getElapsedSeconds()); + gDebugInfo["Dynamic"]["SessionLength"] = F32(LLFrameTimer::getElapsedSeconds()); + gDebugInfo["Dynamic"]["RAMInfo"]["Allocated"] = (LLSD::Integer) LLMemory::getCurrentRSS() >> 10; gDebugInfo["StartupState"] = LLStartUp::getStartupStateString(); - gDebugInfo["RAMInfo"]["Allocated"] = (LLSD::Integer) LLMemory::getCurrentRSS() >> 10; gDebugInfo["FirstLogin"] = (LLSD::Boolean) gAgent.isFirstLogin(); gDebugInfo["FirstRunThisInstall"] = gSavedSettings.getBOOL("FirstRunThisInstall"); if(gLogoutInProgress) { - gDebugInfo["LastExecEvent"] = LAST_EXEC_LOGOUT_CRASH; + gDebugInfo["Dynamic"]["LastExecEvent"] = LAST_EXEC_LOGOUT_CRASH; } else { - gDebugInfo["LastExecEvent"] = gLLErrorActivated ? LAST_EXEC_LLERROR_CRASH : LAST_EXEC_OTHER_CRASH; + gDebugInfo["Dynamic"]["LastExecEvent"] = gLLErrorActivated ? LAST_EXEC_LLERROR_CRASH : LAST_EXEC_OTHER_CRASH; } if(gAgent.getRegion()) { - gDebugInfo["CurrentSimHost"] = gAgent.getRegionHost().getHostName(); - gDebugInfo["CurrentRegion"] = gAgent.getRegion()->getName(); + gDebugInfo["Dynamic"]["CurrentSimHost"] = gAgent.getRegionHost().getHostName(); + gDebugInfo["Dynamic"]["CurrentRegion"] = gAgent.getRegion()->getName(); const LLVector3& loc = gAgent.getPositionAgent(); - gDebugInfo["CurrentLocationX"] = loc.mV[0]; - gDebugInfo["CurrentLocationY"] = loc.mV[1]; - gDebugInfo["CurrentLocationZ"] = loc.mV[2]; + gDebugInfo["Dynamic"]["CurrentLocationX"] = loc.mV[0]; + gDebugInfo["Dynamic"]["CurrentLocationY"] = loc.mV[1]; + gDebugInfo["Dynamic"]["CurrentLocationZ"] = loc.mV[2]; } if(LLAppViewer::instance()->mMainloopTimeout) { - gDebugInfo["MainloopTimeoutState"] = LLAppViewer::instance()->mMainloopTimeout->getState(); + gDebugInfo["Dynamic"]["MainloopTimeoutState"] = LLAppViewer::instance()->mMainloopTimeout->getState(); } // The crash is being handled here so set this value to false. // Otherwise the crash logger will think this crash was a freeze. - gDebugInfo["CrashNotHandled"] = (LLSD::Boolean)false; - + gDebugInfo["Dynamic"]["CrashNotHandled"] = (LLSD::Boolean)false; + //Write out the crash status file //Use marker file style setup, as that's the simplest, especially since //we're already in a crash situation if (gDirUtilp) { - std::string crash_file_name; - if(gLLErrorActivated) crash_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,LLERROR_MARKER_FILE_NAME); - else crash_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,ERROR_MARKER_FILE_NAME); - llinfos << "Creating crash marker file " << crash_file_name << llendl; - - LLAPRFile crash_file(crash_file_name, LL_APR_W); - if (crash_file.getFileHandle()) + std::string crash_marker_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, + gLLErrorActivated + ? LLERROR_MARKER_FILE_NAME + : ERROR_MARKER_FILE_NAME); + LLAPRFile crash_marker_file ; + crash_marker_file.open(crash_marker_file_name, LL_APR_WB); + if (crash_marker_file.getFileHandle()) { - LL_INFOS("MarkerFile") << "Created crash marker file " << crash_file_name << LL_ENDL; + LL_INFOS("MarkerFile") << "Created crash marker file " << crash_marker_file_name << LL_ENDL; + recordMarkerVersion(crash_marker_file); } else { - LL_WARNS("MarkerFile") << "Cannot create error marker file " << crash_file_name << LL_ENDL; + LL_WARNS("MarkerFile") << "Cannot create error marker file " << crash_marker_file_name << LL_ENDL; } } + else + { + LL_WARNS("MarkerFile") << "No gDirUtilp with which to create error marker file name" << LL_ENDL; + } + LL_WARNS("CRASHREPORT") << "no minidump file? ah yeah, boi!" << LL_ENDL; + + gDebugInfo["Dynamic"]["CrashType"]="crash"; if (gMessageSystem && gDirUtilp) { std::string filename; - filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "stats.log"); - llofstream file(filename, llofstream::binary); + filename = gDirUtilp->getExpandedFilename(LL_PATH_DUMP, "stats.log"); + LL_DEBUGS("CRASHREPORT") << "recording stats " << filename << LL_ENDL; + llofstream file(filename.c_str(), std::ios_base::binary); if(file.good()) { - llinfos << "Handle viewer crash generating stats log." << llendl; gMessageSystem->summarizeLogs(file); file.close(); } + else + { + LL_WARNS("CRASHREPORT") << "problem recording stats" << LL_ENDL; + } } if (gMessageSystem) @@ -2870,156 +3082,245 @@ void LLAppViewer::handleViewerCrash() gMessageSystem->stopLogging(); } - if (LLWorld::instanceExists()) LLWorld::getInstance()->getInfo(gDebugInfo); + if (LLWorld::instanceExists()) LLWorld::getInstance()->getInfo(gDebugInfo["Dynamic"]); // Close the debug file - pApp->writeDebugInfo(); - - LLError::logToFile(""); - -// On Mac, we send the report on the next run, since we need macs crash report -// for a stack trace, so we have to let it the app fail. -#if !LL_DARWIN + pApp->writeDebugInfo(false); //false answers the isStatic question with the least overhead. +} - // Remove the marker file, since otherwise we'll spawn a process that'll keep it locked - if(gDebugInfo["LastExecEvent"].asInteger() == LAST_EXEC_LOGOUT_CRASH) - { - pApp->removeMarkerFile(true); - } - else +// static +void LLAppViewer::recordMarkerVersion(LLAPRFile& marker_file) +{ + std::string marker_version(LLVersionInfo::getChannelAndVersion()); + if ( marker_version.length() > MAX_MARKER_LENGTH ) { - pApp->removeMarkerFile(false); + LL_WARNS_ONCE("MarkerFile") << "Version length ("<< marker_version.length()<< ")" + << " greater than maximum (" << MAX_MARKER_LENGTH << ")" + << ": marker matching may be incorrect" + << LL_ENDL; } - - // Call to pure virtual, handled by platform specific llappviewer instance. - pApp->handleCrashReporting(); -#endif //!LL_DARWIN - - return; + // record the viewer version in the marker file + marker_file.write(marker_version.data(), marker_version.length()); } -bool LLAppViewer::anotherInstanceRunning() +bool LLAppViewer::markerIsSameVersion(const std::string& marker_name) const { - // We create a marker file when the program starts and remove the file when it finishes. - // If the file is currently locked, that means another process is already running. + bool sameVersion = false; - std::string marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, MARKER_FILE_NAME); - LL_DEBUGS("MarkerFile") << "Checking marker file for lock..." << LL_ENDL; + std::string my_version(LLVersionInfo::getChannelAndVersion()); + char marker_version[MAX_MARKER_LENGTH]; - //Freeze case checks - if (LLAPRFile::isExist(marker_file, LL_APR_RB)) + LLAPRFile marker_file; + marker_file.open(marker_name, LL_APR_RB); + if (marker_file.getFileHandle()) { - // File exists, try opening with write permissions - LLAPRFile outfile(marker_file, LL_APR_WB); - apr_file_t* fMarker = outfile.getFileHandle() ; - if (!fMarker) - { - // Another instance is running. Skip the rest of these operations. - LL_INFOS("MarkerFile") << "Marker file is locked." << LL_ENDL; - return true; - } - if (apr_file_lock(fMarker, APR_FLOCK_NONBLOCK | APR_FLOCK_EXCLUSIVE) != APR_SUCCESS) //flock(fileno(fMarker), LOCK_EX | LOCK_NB) == -1) + S32 marker_version_length = marker_file.read(marker_version, sizeof(marker_version)); + std::string marker_string(marker_version, marker_version_length); + if ( 0 == my_version.compare( 0, my_version.length(), marker_version, 0, marker_version_length ) ) { - LL_INFOS("MarkerFile") << "Marker file is locked." << LL_ENDL; - return true; + sameVersion = true; } - // No other instances; we'll lock this file now & delete on quit. - } - LL_DEBUGS("MarkerFile") << "Marker file isn't locked." << LL_ENDL; - return false; + LL_DEBUGS("MarkerFile") << "Compare markers for '" << marker_name << "': " + << "\n mine '" << my_version << "'" + << "\n marker '" << marker_string << "'" + << "\n " << ( sameVersion ? "same" : "different" ) << " version" + << LL_ENDL; + marker_file.close(); + } + return sameVersion; } -void LLAppViewer::initMarkerFile() +void LLAppViewer::processMarkerFiles() { - //First, check for the existence of other files. - //There are marker files for two different types of crashes - - mMarkerFileName = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,MARKER_FILE_NAME); - LL_DEBUGS("MarkerFile") << "Checking marker file for lock..." << LL_ENDL; - //We've got 4 things to test for here - // - Other Process Running (Singularity.exec_marker present, locked) - // - Freeze (Singularity.exec_marker present, not locked) - // - LLError Crash (Singularity.llerror_marker present) - // - Other Crash (Singularity.error_marker present) + // - Other Process Running (SecondLife.exec_marker present, locked) + // - Freeze (SecondLife.exec_marker present, not locked) + // - LLError Crash (SecondLife.llerror_marker present) + // - Other Crash (SecondLife.error_marker present) // These checks should also remove these files for the last 2 cases if they currently exist - //LLError/Error checks. Only one of these should ever happen at a time. - std::string logout_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, LOGOUT_MARKER_FILE_NAME); - std::string llerror_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, LLERROR_MARKER_FILE_NAME); - std::string error_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ERROR_MARKER_FILE_NAME); + bool marker_is_same_version = true; + // first, look for the marker created at startup and deleted on a clean exit + mMarkerFileName = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,MARKER_FILE_NAME); + if (LLAPRFile::isExist(mMarkerFileName, LL_APR_RB)) + { + // File exists... + // first, read it to see if it was created by the same version (we need this later) + marker_is_same_version = markerIsSameVersion(mMarkerFileName); - if (LLAPRFile::isExist(mMarkerFileName, LL_APR_RB) && !anotherInstanceRunning()) + // now test to see if this file is locked by a running process (try to open for write) + LL_DEBUGS("MarkerFile") << "Checking exec marker file for lock..." << LL_ENDL; + mMarkerFile.open(mMarkerFileName, LL_APR_WB); + apr_file_t* fMarker = mMarkerFile.getFileHandle() ; + if (!fMarker) + { + LL_INFOS("MarkerFile") << "Exec marker file open failed - assume it is locked." << LL_ENDL; + mSecondInstance = true; // lock means that instance is running. + } + else + { + // We were able to open it, now try to lock it ourselves... + if (apr_file_lock(fMarker, APR_FLOCK_NONBLOCK | APR_FLOCK_EXCLUSIVE) != APR_SUCCESS) + { + LL_WARNS_ONCE("MarkerFile") << "Locking exec marker failed." << LL_ENDL; + mSecondInstance = true; // lost a race? be conservative + } + else + { + // No other instances; we've locked this file now, so record our version; delete on quit. + recordMarkerVersion(mMarkerFile); + LL_DEBUGS("MarkerFile") << "Exec marker file existed but was not locked; rewritten." << LL_ENDL; + } + } + + if (mSecondInstance) + { + LL_INFOS("MarkerFile") << "Exec marker '"<< mMarkerFileName << "' owned by another instance" << LL_ENDL; + } + else if (marker_is_same_version) + { + // the file existed, is ours, and matched our version, so we can report on what it says + LL_INFOS("MarkerFile") << "Exec marker '"<< mMarkerFileName << "' found; last exec FROZE" << LL_ENDL; + gLastExecEvent = LAST_EXEC_FROZE; + + } + else + { + LL_INFOS("MarkerFile") << "Exec marker '"<< mMarkerFileName << "' found, but versions did not match" << LL_ENDL; + } + } + else // marker did not exist... last exec (if any) did not freeze { - gLastExecEvent = LAST_EXEC_FROZE; - LL_INFOS("MarkerFile") << "Exec marker found: program froze on previous execution" << LL_ENDL; - } + // Create the marker file for this execution & lock it; it will be deleted on a clean exit + apr_status_t s; + s = mMarkerFile.open(mMarkerFileName, LL_APR_WB, TRUE); + + if (s == APR_SUCCESS && mMarkerFile.getFileHandle()) + { + LL_DEBUGS("MarkerFile") << "Exec marker file '"<< mMarkerFileName << "' created." << LL_ENDL; + if (APR_SUCCESS == apr_file_lock(mMarkerFile.getFileHandle(), APR_FLOCK_NONBLOCK | APR_FLOCK_EXCLUSIVE)) + { + recordMarkerVersion(mMarkerFile); + LL_DEBUGS("MarkerFile") << "Exec marker file locked." << LL_ENDL; + } + else + { + LL_WARNS("MarkerFile") << "Exec marker file cannot be locked." << LL_ENDL; + } + } + else + { + LL_WARNS("MarkerFile") << "Failed to create exec marker file '"<< mMarkerFileName << "'." << LL_ENDL; + } + } + + // now check for cases in which the exec marker may have been cleaned up by crash handlers + + // check for any last exec event report based on whether or not it happened during logout + // (the logout marker is created when logout begins) + std::string logout_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, LOGOUT_MARKER_FILE_NAME); if(LLAPRFile::isExist(logout_marker_file, LL_APR_RB)) { - gLastExecEvent = LAST_EXEC_LOGOUT_FROZE; - LL_INFOS("MarkerFile") << "Last exec LLError crashed, setting LastExecEvent to " << gLastExecEvent << LL_ENDL; + if (markerIsSameVersion(logout_marker_file)) + { + gLastExecEvent = LAST_EXEC_LOGOUT_FROZE; + LL_INFOS("MarkerFile") << "Logout crash marker '"<< logout_marker_file << "', changing LastExecEvent to LOGOUT_FROZE" << LL_ENDL; + } + else + { + LL_INFOS("MarkerFile") << "Logout crash marker '"<< logout_marker_file << "' found, but versions did not match" << LL_ENDL; + } LLAPRFile::remove(logout_marker_file); } + // further refine based on whether or not a marker created during an llerr crash is found + std::string llerror_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, LLERROR_MARKER_FILE_NAME); if(LLAPRFile::isExist(llerror_marker_file, LL_APR_RB)) { - llinfos << "Last exec LLError crashed, setting LastExecEvent to " << LAST_EXEC_LLERROR_CRASH << llendl; - if(gLastExecEvent == LAST_EXEC_LOGOUT_FROZE) gLastExecEvent = LAST_EXEC_LOGOUT_CRASH; - else gLastExecEvent = LAST_EXEC_LLERROR_CRASH; - LL_INFOS("MarkerFile") << "Last exec LLError crashed, setting LastExecEvent to " << gLastExecEvent << LL_ENDL; + if (markerIsSameVersion(llerror_marker_file)) + { + if ( gLastExecEvent == LAST_EXEC_LOGOUT_FROZE ) + { + gLastExecEvent = LAST_EXEC_LOGOUT_CRASH; + LL_INFOS("MarkerFile") << "LLError marker '"<< llerror_marker_file << "' crashed, setting LastExecEvent to LOGOUT_CRASH" << LL_ENDL; + } + else + { + gLastExecEvent = LAST_EXEC_LLERROR_CRASH; + LL_INFOS("MarkerFile") << "LLError marker '"<< llerror_marker_file << "' crashed, setting LastExecEvent to LLERROR_CRASH" << LL_ENDL; + } + } + else + { + LL_INFOS("MarkerFile") << "LLError marker '"<< llerror_marker_file << "' found, but versions did not match" << LL_ENDL; + } LLAPRFile::remove(llerror_marker_file); } + // and last refine based on whether or not a marker created during a non-llerr crash is found + std::string error_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ERROR_MARKER_FILE_NAME); if(LLAPRFile::isExist(error_marker_file, LL_APR_RB)) { - LL_INFOS("MarkerFile") << "Last exec crashed, setting LastExecEvent to " << LAST_EXEC_OTHER_CRASH << LL_ENDL; - if(gLastExecEvent == LAST_EXEC_LOGOUT_FROZE) gLastExecEvent = LAST_EXEC_LOGOUT_CRASH; - else gLastExecEvent = LAST_EXEC_OTHER_CRASH; - LL_INFOS("MarkerFile") << "Last exec crashed, setting LastExecEvent to " << gLastExecEvent << LL_ENDL; + if (markerIsSameVersion(error_marker_file)) + { + if (gLastExecEvent == LAST_EXEC_LOGOUT_FROZE) + { + gLastExecEvent = LAST_EXEC_LOGOUT_CRASH; + LL_INFOS("MarkerFile") << "Error marker '"<< error_marker_file << "' crashed, setting LastExecEvent to LOGOUT_CRASH" << LL_ENDL; + } + else + { + gLastExecEvent = LAST_EXEC_OTHER_CRASH; + LL_INFOS("MarkerFile") << "Error marker '"<< error_marker_file << "' crashed, setting LastExecEvent to " << gLastExecEvent << LL_ENDL; + } + } + else + { + LL_INFOS("MarkerFile") << "Error marker '"<< error_marker_file << "' marker found, but versions did not match" << LL_ENDL; + } LLAPRFile::remove(error_marker_file); } - - // No new markers if another instance is running. - if(anotherInstanceRunning()) - { - return; - } - - // Create the marker file for this execution & lock it - apr_status_t s; - s = mMarkerFile.open(mMarkerFileName, LL_APR_W, LLAPRFile::long_lived); +} - if (s == APR_SUCCESS && mMarkerFile.getFileHandle()) +void LLAppViewer::removeMarkerFiles() +{ + if (!mSecondInstance) { - LL_DEBUGS("MarkerFile") << "Marker file created." << LL_ENDL; + if (mMarkerFile.getFileHandle()) + { + mMarkerFile.close() ; + LLAPRFile::remove( mMarkerFileName ); + LL_DEBUGS("MarkerFile") << "removed exec marker '"<getExpandedFilename(LL_PATH_DUMP, ""); + gDirUtilp->deleteDirAndContents(dump_dir); +#endif } void LLAppViewer::forceQuit() @@ -3039,14 +3340,14 @@ void LLAppViewer::fastQuit(S32 error_code) // figure out the error code S32 final_error_code = error_code ? error_code : (S32)isError(); // this isn't a crash - removeMarkerFile(); + removeMarkerFiles(); // get outta here _exit(final_error_code); } void LLAppViewer::requestQuit() { - llinfos << "requestQuit" << llendl; + LL_INFOS() << "requestQuit" << LL_ENDL; LLViewerRegion* region = gAgent.getRegion(); @@ -3125,7 +3426,7 @@ static bool finish_early_exit(const LLSD& notification, const LLSD& response) void LLAppViewer::earlyExit(const std::string& name, const LLSD& substitutions) { - llwarns << "app_early_exit: " << name << llendl; + LL_WARNS() << "app_early_exit: " << name << LL_ENDL; gDoDisconnect = TRUE; LLNotificationsUtil::add(name, substitutions, LLSD(), finish_early_exit); } @@ -3133,7 +3434,7 @@ void LLAppViewer::earlyExit(const std::string& name, const LLSD& substitutions) void LLAppViewer::abortQuit() { - llinfos << "abortQuit()" << llendl; + LL_INFOS() << "abortQuit()" << LL_ENDL; mQuitRequested = false; } @@ -3160,13 +3461,12 @@ void LLAppViewer::migrateCacheDirectory() { gSavedSettings.setBOOL("MigrateCacheDirectory", FALSE); - std::string delimiter = gDirUtilp->getDirDelimiter(); - std::string old_cache_dir = gDirUtilp->getOSUserAppDir() + delimiter + "cache"; + std::string old_cache_dir = gDirUtilp->add(gDirUtilp->getOSUserAppDir(), "cache"); std::string new_cache_dir = gDirUtilp->getCacheDir(true); if (gDirUtilp->fileExists(old_cache_dir)) { - llinfos << "Migrating cache from " << old_cache_dir << " to " << new_cache_dir << llendl; + LL_INFOS() << "Migrating cache from " << old_cache_dir << " to " << new_cache_dir << LL_ENDL; // Migrate inventory cache to avoid pain to inventory database after mass update S32 file_count = 0; @@ -3177,14 +3477,14 @@ void LLAppViewer::migrateCacheDirectory() while (iter.next(file_name)) { if (file_name == "." || file_name == "..") continue; - std::string source_path = old_cache_dir + delimiter + file_name; - std::string dest_path = new_cache_dir + delimiter + file_name; + std::string source_path = gDirUtilp->add(old_cache_dir, file_name); + std::string dest_path = gDirUtilp->add(new_cache_dir, file_name); if (!LLFile::rename(source_path, dest_path)) { file_count++; } } - llinfos << "Moved " << file_count << " files" << llendl; + LL_INFOS() << "Moved " << file_count << " files" << LL_ENDL; // Nuke the old cache gDirUtilp->setCacheDir(old_cache_dir); @@ -3201,7 +3501,7 @@ void LLAppViewer::migrateCacheDirectory() #endif if (LLFile::rmdir(old_cache_dir) != 0) { - llwarns << "could not delete old cache directory " << old_cache_dir << llendl; + LL_WARNS() << "could not delete old cache directory " << old_cache_dir << LL_ENDL; } } } @@ -3210,39 +3510,40 @@ void LLAppViewer::migrateCacheDirectory() void dumpVFSCaches() { - llinfos << "======= Static VFS ========" << llendl; - gStaticVFS->listFiles(); + LL_INFOS() << "======= Static VFS ========" << LL_ENDL; + gStaticVFS->listFiles(); #if LL_WINDOWS - llinfos << "======= Dumping static VFS to StaticVFSDump ========" << llendl; - WCHAR w_str[MAX_PATH]; - GetCurrentDirectory(MAX_PATH, w_str); - S32 res = LLFile::mkdir("StaticVFSDump"); - if (res == -1) - { - if (errno != EEXIST) - { - llwarns << "Couldn't create dir StaticVFSDump" << llendl; - } - } - SetCurrentDirectory(utf8str_to_utf16str("StaticVFSDump").c_str()); - gStaticVFS->dumpFiles(); - SetCurrentDirectory(w_str); + LL_INFOS() << "======= Dumping static VFS to StaticVFSDump ========" << LL_ENDL; + WCHAR w_str[MAX_PATH]; + GetCurrentDirectory(MAX_PATH, w_str); + S32 res = LLFile::mkdir("StaticVFSDump"); + if (res == -1) + { + if (errno != EEXIST) + { + LL_WARNS() << "Couldn't create dir StaticVFSDump" << LL_ENDL; + } + } + SetCurrentDirectory(utf8str_to_utf16str("StaticVFSDump").c_str()); + gStaticVFS->dumpFiles(); + SetCurrentDirectory(w_str); #endif - llinfos << "========= Dynamic VFS ====" << llendl; - gVFS->listFiles(); + + LL_INFOS() << "========= Dynamic VFS ====" << LL_ENDL; + gVFS->listFiles(); #if LL_WINDOWS - llinfos << "========= Dumping dynamic VFS to VFSDump ====" << llendl; - res = LLFile::mkdir("VFSDump"); - if (res == -1) - { - if (errno != EEXIST) - { - llwarns << "Couldn't create dir VFSDump" << llendl; - } - } - SetCurrentDirectory(utf8str_to_utf16str("VFSDump").c_str()); - gVFS->dumpFiles(); - SetCurrentDirectory(w_str); + LL_INFOS() << "========= Dumping dynamic VFS to VFSDump ====" << LL_ENDL; + res = LLFile::mkdir("VFSDump"); + if (res == -1) + { + if (errno != EEXIST) + { + LL_WARNS() << "Couldn't create dir VFSDump" << LL_ENDL; + } + } + SetCurrentDirectory(utf8str_to_utf16str("VFSDump").c_str()); + gVFS->dumpFiles(); + SetCurrentDirectory(w_str); #endif } @@ -3288,6 +3589,7 @@ bool LLAppViewer::initCache() if (gSavedSettings.getBOOL("PurgeCacheOnStartup") || gSavedSettings.getBOOL("PurgeCacheOnNextStartup")) { + LL_INFOS("AppCache") << "Startup cache purge requested: " << (gSavedSettings.getBOOL("PurgeCacheOnStartup") ? "ALWAYS" : "ONCE") << LL_ENDL; gSavedSettings.setBOOL("PurgeCacheOnNextStartup", false); mPurgeCache = true; // STORM-1141 force purgeAllTextures to get called to prevent a crash here. -brad @@ -3303,6 +3605,7 @@ bool LLAppViewer::initCache() std::string new_cache_location = gSavedSettings.getString("NewCacheLocation"); if (new_cache_location != cache_location) { + LL_INFOS("AppCache") << "Cache location changed, cache needs purging" << LL_ENDL; gDirUtilp->setCacheDir(gSavedSettings.getString("CacheLocation")); purgeCache(); // purge old cache gSavedSettings.setString("CacheLocation", new_cache_location); @@ -3313,6 +3616,8 @@ bool LLAppViewer::initCache() { LL_WARNS("AppCache") << "Unable to set cache location" << LL_ENDL; gSavedSettings.setString("CacheLocation", ""); + // Keep NewCacheLocation equal to CacheLocation so we won't try to erase the cache the next time the viewer is run. + gSavedSettings.setString("NewCacheLocation", ""); } if (mPurgeCache && !read_only) @@ -3324,20 +3629,26 @@ bool LLAppViewer::initCache() // } - LLSplashScreen::update(LLTrans::getString("StartupInitializingTextureCache")); - + { + std::random_device rnddev; + std::mt19937 rng(rnddev()); + std::uniform_int_distribution<> dist(0, 4); + + LLSplashScreen::update(LLTrans::getString( + llformat("StartupInitializingTextureCache%d", dist(rng)))); + } + // Init the texture cache // Allocate 80% of the cache size for textures - const S32 MB = 1024 * 1024; - const S64 MIN_CACHE_SIZE = 64 * MB; - const S64 MAX_CACHE_SIZE = 9984ll * MB; - const S64 MAX_VFS_SIZE = 1024 * MB; // 1 GB + const U64Bytes MIN_CACHE_SIZE = U32Megabytes(64); + const U64Bytes MAX_CACHE_SIZE = U32Megabytes(9984); + const U64Bytes MAX_VFS_SIZE = U32Gigabytes(1); - S64 cache_size = (S64)(gSavedSettings.getU32("CacheSize")) * MB; + U64Bytes cache_size = U32Megabytes(gSavedSettings.getU32("CacheSize")); cache_size = llclamp(cache_size, MIN_CACHE_SIZE, MAX_CACHE_SIZE); - S64 texture_cache_size = ((cache_size * 8) / 10); - S64 vfs_size = cache_size - texture_cache_size; + U64Bytes texture_cache_size = ((cache_size * 8) / 10); + U64Bytes vfs_size = U64Bytes(cache_size) - U64Bytes(texture_cache_size); if (vfs_size > MAX_VFS_SIZE) { @@ -3347,7 +3658,7 @@ bool LLAppViewer::initCache() texture_cache_size = cache_size - MAX_VFS_SIZE; } - S64 extra = LLAppViewer::getTextureCache()->initCache(LL_PATH_CACHE, texture_cache_size, texture_cache_mismatch); + U64Bytes extra(LLAppViewer::getTextureCache()->initCache(LL_PATH_CACHE, texture_cache_size, texture_cache_mismatch)); texture_cache_size -= extra; LLVOCache::getInstance()->initCache(LL_PATH_CACHE, gSavedSettings.getU32("CacheNumberOfRegionsForObjects"), getObjectCacheVersion()) ; @@ -3356,19 +3667,18 @@ bool LLAppViewer::initCache() // Init the VFS vfs_size = llmin(vfs_size + extra, MAX_VFS_SIZE); - vfs_size = (vfs_size / MB) * MB; // make sure it is MB aligned - U32 vfs_size_u32 = (U32)vfs_size; - U32 old_vfs_size = gSavedSettings.getU32("VFSOldSize") * MB; - bool resize_vfs = (vfs_size_u32 != old_vfs_size); + vfs_size = U32Megabytes(vfs_size + U32Bytes(1048575)); // make sure it is MB aligned + U32Megabytes old_vfs_size(gSavedSettings.getU32("VFSOldSize")); + bool resize_vfs = (vfs_size != old_vfs_size); if (resize_vfs) { - gSavedSettings.setU32("VFSOldSize", vfs_size_u32 / MB); + gSavedSettings.setU32("VFSOldSize", U32Megabytes(vfs_size)); } - LL_INFOS("AppCache") << "VFS CACHE SIZE: " << vfs_size / (1024*1024) << " MB" << LL_ENDL; + LL_INFOS("AppCache") << "VFS CACHE SIZE: " << U32Megabytes(vfs_size) << LL_ENDL; // This has to happen BEFORE starting the vfs // time_t ltime; - srand(time(NULL)); // Flawfinder: ignore + srand(time(nullptr)); // Flawfinder: ignore U32 old_salt = gSavedSettings.getU32("VFSSalt"); U32 new_salt; std::string old_vfs_data_file; @@ -3410,14 +3720,14 @@ bool LLAppViewer::initCache() LLDirIterator iter(dir, mask); if (iter.next(found_file)) { - old_vfs_data_file = dir + gDirUtilp->getDirDelimiter() + found_file; + old_vfs_data_file = gDirUtilp->add(dir, found_file); - S32 start_pos = found_file.find_last_of('.'); - if (start_pos > 0) + size_t start_pos = found_file.find_last_of('.'); + if (start_pos != std::string::npos && start_pos != 0) { sscanf(found_file.substr(start_pos+1).c_str(), "%d", &old_salt); } - LL_DEBUGS("AppCache") << "Default vfs data file not present, found: " << old_vfs_data_file << " Old salt: " << old_salt << llendl; + LL_DEBUGS("AppCache") << "Default vfs data file not present, found: " << old_vfs_data_file << " Old salt: " << old_salt << LL_ENDL; } } @@ -3474,7 +3784,7 @@ bool LLAppViewer::initCache() gSavedSettings.setU32("VFSSalt", new_salt); // Don't remove VFS after viewer crashes. If user has corrupt data, they can reinstall. JC - gVFS = LLVFS::createLLVFS(new_vfs_index_file, new_vfs_data_file, false, vfs_size_u32, false); + gVFS = LLVFS::createLLVFS(new_vfs_index_file, new_vfs_data_file, false, U32Bytes(vfs_size), false); if (!gVFS) { return false; @@ -3520,9 +3830,9 @@ void LLAppViewer::purgeCache() gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ""), mask); } -const std::string& LLAppViewer::getSecondLifeTitle() const +std::string LLAppViewer::getSecondLifeTitle() const { - return gSecondLife; + return LLTrans::getString("APP_NAME"); } const std::string& LLAppViewer::getWindowTitle() const @@ -3537,7 +3847,7 @@ bool finish_disconnect(const LLSD& notification, const LLSD& response) if (1 == option) { - LLAppViewer::instance()->forceQuit(); + LLAppViewer::instance()->forceQuit(); } return false; } @@ -3553,15 +3863,15 @@ bool finish_forced_disconnect(const LLSD& notification, const LLSD& response) void LLAppViewer::forceDisconnect(const std::string& mesg) { if (gDoDisconnect) - { + { // Already popped up one of these dialogs, don't // do this again. return; - } + } - // Translate the message if possible + // *TODO: Translate the message if possible std::string big_reason = LLAgent::sTeleportErrorMessages[mesg]; - if ( big_reason.size() == 0 ) + if (big_reason.empty()) { big_reason = mesg; } @@ -3592,30 +3902,24 @@ void LLAppViewer::badNetworkHandler() mPurgeOnExit = TRUE; -#if LL_WINDOWS - // Generates the minidump. - LLWinDebug::generateCrashStacks(NULL); -#endif - LLAppViewer::handleSyncViewerCrash(); - LLAppViewer::handleViewerCrash(); - - std::string grid_support_msg = ""; - if (!gHippoGridManager->getCurrentGrid()->getSupportUrl().empty()) - { - grid_support_msg = "\n\nOr visit the grid support page at: \n " - + gHippoGridManager->getCurrentGrid()->getSupportUrl(); - } std::ostringstream message; message << "The viewer has detected mangled network data indicative\n" "of a bad upstream network connection or an incomplete\n" - "local installation of " << gSecondLife << ". \n" + "local installation of " << LLAppViewer::instance()->getSecondLifeTitle() << ". \n" " \n" "Try uninstalling and reinstalling to see if this resolves \n" "the issue. \n" " \n" "If the problem continues, please report the issue at: \n" - "http://www.singularityviewer.org" << grid_support_msg; + "http://www.singularityviewer.org"; + + if (!gHippoGridManager->getCurrentGrid()->getSupportUrl().empty()) + { + message << "\n\nOr visit the grid support page at: \n" + << gHippoGridManager->getCurrentGrid()->getSupportUrl(); + } + forceDisconnect(message.str()); } @@ -3647,11 +3951,11 @@ void LLAppViewer::saveFinalSnapshot() void LLAppViewer::loadNameCache() { - // Phoenix: Wolfspirit: Loads the Display Name Cache. And set if we are using Display Names. + // display names cache std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "avatar_name_cache.xml"); LL_INFOS("AvNameCache") << filename << LL_ENDL; - llifstream name_cache_stream(filename); + llifstream name_cache_stream(filename.c_str()); if(name_cache_stream.is_open()) { LLAvatarNameCache::importFile(name_cache_stream); @@ -3661,7 +3965,7 @@ void LLAppViewer::loadNameCache() std::string name_cache; name_cache = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "name.cache"); - llifstream cache_file(name_cache); + llifstream cache_file(name_cache.c_str()); if(cache_file.is_open()) { if(gCacheName->importFile(cache_file)) return; @@ -3670,26 +3974,29 @@ void LLAppViewer::loadNameCache() void LLAppViewer::saveNameCache() { - // Phoenix: Wolfspirit: Saves the Display Name Cache. + // display names cache std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "avatar_name_cache.xml"); - llofstream name_cache_stream(filename); + llofstream name_cache_stream(filename.c_str()); if(name_cache_stream.is_open()) { LLAvatarNameCache::exportFile(name_cache_stream); } - if (!gCacheName) return; - - std::string name_cache; - name_cache = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "name.cache"); - llofstream cache_file(name_cache); - if(cache_file.is_open()) - { - gCacheName->exportFile(cache_file); + // real names cache + if (gCacheName) + { + std::string name_cache; + name_cache = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "name.cache"); + llofstream cache_file(name_cache.c_str()); + if(cache_file.is_open()) + { + gCacheName->exportFile(cache_file); + } } } + /*! @brief This class is an LLFrameTimer that can be created with an elapsed time that starts counting up from the given value rather than 0.0. @@ -3706,18 +4013,18 @@ class LLFrameStatsTimer : public LLFrameTimer } }; -static LLFastTimer::DeclareTimer FTM_AUDIO_UPDATE("Update Audio"); -static LLFastTimer::DeclareTimer FTM_CLEANUP("Cleanup"); -static LLFastTimer::DeclareTimer FTM_CLEANUP_DRAWABLES("Drawables"); -static LLFastTimer::DeclareTimer FTM_CLEANUP_OBJECTS("Objects"); -static LLFastTimer::DeclareTimer FTM_IDLE_CB("Idle Callbacks"); -static LLFastTimer::DeclareTimer FTM_LOD_UPDATE("Update LOD"); -static LLFastTimer::DeclareTimer FTM_OBJECTLIST_UPDATE("Update Objectlist"); -static LLFastTimer::DeclareTimer FTM_REGION_UPDATE("Update Region"); -static LLFastTimer::DeclareTimer FTM_WORLD_UPDATE("Update World"); -static LLFastTimer::DeclareTimer FTM_NETWORK("Network"); -static LLFastTimer::DeclareTimer FTM_AGENT_NETWORK("Agent Network"); -static LLFastTimer::DeclareTimer FTM_VLMANAGER("VL Manager"); +static LLTrace::BlockTimerStatHandle FTM_AUDIO_UPDATE("Update Audio"); +static LLTrace::BlockTimerStatHandle FTM_CLEANUP("Cleanup"); +static LLTrace::BlockTimerStatHandle FTM_CLEANUP_DRAWABLES("Drawables"); +static LLTrace::BlockTimerStatHandle FTM_CLEANUP_OBJECTS("Objects"); +static LLTrace::BlockTimerStatHandle FTM_IDLE_CB("Idle Callbacks"); +static LLTrace::BlockTimerStatHandle FTM_LOD_UPDATE("Update LOD"); +static LLTrace::BlockTimerStatHandle FTM_OBJECTLIST_UPDATE("Update Objectlist"); +static LLTrace::BlockTimerStatHandle FTM_REGION_UPDATE("Update Region"); +static LLTrace::BlockTimerStatHandle FTM_WORLD_UPDATE("Update World"); +static LLTrace::BlockTimerStatHandle FTM_NETWORK("Network"); +static LLTrace::BlockTimerStatHandle FTM_AGENT_NETWORK("Agent Network"); +static LLTrace::BlockTimerStatHandle FTM_VLMANAGER("VL Manager"); /////////////////////////////////////////////////////// // idle() @@ -3727,37 +4034,56 @@ static LLFastTimer::DeclareTimer FTM_VLMANAGER("VL Manager"); /////////////////////////////////////////////////////// void LLAppViewer::idle() { +//LAZY_FT is just temporary. +#define LAZY_FT(str) static LLTrace::BlockTimerStatHandle ftm(str); LL_RECORD_BLOCK_TIME(ftm) pingMainloopTimeout("Main:Idle"); - + // Update frame timers static LLTimer idle_timer; - LLFrameTimer::updateFrameTimeAndCount(); - LLEventTimer::updateClass(); - LLCriticalDamp::updateInterpolants(); - LLMortician::updateClass(); - F32 dt_raw = idle_timer.getElapsedTimeAndResetF32(); + { + LAZY_FT("updateFrameTimeAndCount"); + LLFrameTimer::updateFrameTimeAndCount(); + } + { + LAZY_FT("LLEventTimer::updateClass"); + LLEventTimer::updateClass(); + } + { + LAZY_FT("LLSmoothInterpolation::updateInterpolants"); + LLSmoothInterpolation::updateInterpolants(); + } + { + LAZY_FT("LLMortician::updateClass"); + LLMortician::updateClass(); + } + F32 dt_raw; + { + LAZY_FT("UpdateGlobalTimers"); + dt_raw = idle_timer.getElapsedTimeAndResetF32(); - // Cap out-of-control frame times - // Too low because in menus, swapping, debugger, etc. - // Too high because idle called with no objects in view, etc. - const F32 MIN_FRAME_RATE = 1.f; - const F32 MAX_FRAME_RATE = 200.f; + // Cap out-of-control frame times + // Too low because in menus, swapping, debugger, etc. + // Too high because idle called with no objects in view, etc. + const F32 MIN_FRAME_RATE = 1.f; + const F32 MAX_FRAME_RATE = 200.f; - F32 frame_rate_clamped = 1.f / dt_raw; - frame_rate_clamped = llclamp(frame_rate_clamped, MIN_FRAME_RATE, MAX_FRAME_RATE); - gFrameDTClamped = 1.f / frame_rate_clamped; + F32 frame_rate_clamped = 1.f / dt_raw; + frame_rate_clamped = llclamp(frame_rate_clamped, MIN_FRAME_RATE, MAX_FRAME_RATE); + gFrameDTClamped = 1.f / frame_rate_clamped; - // Global frame timer - // Smoothly weight toward current frame - gFPSClamped = (frame_rate_clamped + (4.f * gFPSClamped)) / 5.f; + // Global frame timer + // Smoothly weight toward current frame + gFPSClamped = (frame_rate_clamped + (4.f * gFPSClamped)) / 5.f; - F32 qas = gSavedSettings.getF32("QuitAfterSeconds"); - if (qas > 0.f) - { - if (gRenderStartTime.getElapsedTimeF32() > qas) + static LLCachedControl qas(gSavedSettings, "QuitAfterSeconds"); + if (qas > 0.f) { - LLAppViewer::instance()->forceQuit(); + if (gRenderStartTime.getElapsedTimeF32() > qas) + { + LL_INFOS() << "Quitting after " << qas << " seconds. See setting \"QuitAfterSeconds\"." << LL_ENDL; + LLAppViewer::instance()->forceQuit(); + } } } @@ -3767,72 +4093,80 @@ void LLAppViewer::idle() // { - LLFastTimer t(FTM_STATEMACHINE); + LL_RECORD_BLOCK_TIME(FTM_STATEMACHINE); gMainThreadEngine.mainloop(); } // Must wait until both have avatar object and mute list, so poll // here. - request_initial_instant_messages(); + { + LAZY_FT("request_initial_instant_messages"); + LLIMProcessing::requestOfflineMessages(); + } /////////////////////////////////// // // Special case idle if still starting up // - if (LLStartUp::getStartupState() < STATE_STARTED) { - // Skip rest if idle startup returns false (essentially, no world yet) - gGLActive = TRUE; - if (!idle_startup()) + LAZY_FT("idle_startup"); + if (LLStartUp::getStartupState() < STATE_STARTED) { + // Skip rest if idle startup returns false (essentially, no world yet) + gGLActive = TRUE; + if (!idle_startup()) + { + gGLActive = FALSE; + return; + } gGLActive = FALSE; - return; } - gGLActive = FALSE; } - - F32 yaw = 0.f; // radians + + F32 yaw = 0.f; // radians if (!gDisconnected) { - LLFastTimer t(FTM_NETWORK); + LL_RECORD_BLOCK_TIME(FTM_NETWORK); // Update spaceserver timeinfo - LLWorld::getInstance()->setSpaceTimeUSec(LLWorld::getInstance()->getSpaceTimeUSec() + (U32)(dt_raw * SEC_TO_MICROSEC)); - - - ////////////////////////////////////// - // - // Update simulator agent state - // - - if (gSavedSettings.getBOOL("RotateRight")) + LLWorld::getInstance()->setSpaceTimeUSec(LLWorld::getInstance()->getSpaceTimeUSec() + (U32)(dt_raw * SEC_TO_MICROSEC)); + + + ////////////////////////////////////// + // + // Update simulator agent state + // + + static LLCachedControl rotateRight(gSavedSettings, "RotateRight"); + if (rotateRight) { gAgent.moveYaw(-1.f); } { - LLFastTimer t(FTM_AGENT_AUTOPILOT); + LL_RECORD_BLOCK_TIME(FTM_AGENT_AUTOPILOT); // Handle automatic walking towards points gAgentPilot.updateTarget(); gAgent.autoPilot(&yaw); } - - static LLFrameTimer agent_update_timer; - static U32 last_control_flags; - - // When appropriate, update agent location to the simulator. - F32 agent_update_time = agent_update_timer.getElapsedTimeF32(); - BOOL flags_changed = gAgent.controlFlagsDirty() || (last_control_flags != gAgent.getControlFlags()); - - if (flags_changed || (agent_update_time > (1.0f / (F32) AGENT_UPDATES_PER_SECOND))) - { - LLFastTimer t(FTM_AGENT_UPDATE); - // Send avatar and camera info - last_control_flags = gAgent.getControlFlags(); + + static LLFrameTimer agent_update_timer; + static U32 last_control_flags; + + // When appropriate, update agent location to the simulator. + F32 agent_update_time = agent_update_timer.getElapsedTimeF32(); + BOOL flags_changed = gAgent.controlFlagsDirty() + || (last_control_flags != gAgent.getControlFlags()); + + if (flags_changed || (agent_update_time > (1.0f / (F32)AGENT_UPDATES_PER_SECOND))) + { + LL_RECORD_BLOCK_TIME(FTM_AGENT_UPDATE); + // Send avatar and camera info + last_control_flags = gAgent.getControlFlags(); send_agent_update(TRUE); - agent_update_timer.reset(); - } + agent_update_timer.reset(); + } } ////////////////////////////////////// @@ -3841,6 +4175,7 @@ void LLAppViewer::idle() // // { + LAZY_FT("Frame Stats"); // Initialize the viewer_stats_timer with an already elapsed time // of SEND_STATS_PERIOD so that the initial stats report will // be sent immediately. @@ -3848,10 +4183,10 @@ void LLAppViewer::idle() reset_statistics(); // Update session stats every large chunk of time - // *FIX: (???) SAMANTHA + // *FIX: (?) SAMANTHA if (viewer_stats_timer.getElapsedTimeF32() >= SEND_STATS_PERIOD && !gDisconnected) { - llinfos << "Transmitting sessions stats" << llendl; + LL_INFOS() << "Transmitting sessions stats" << LL_ENDL; send_stats(); viewer_stats_timer.reset(); } @@ -3863,17 +4198,17 @@ void LLAppViewer::idle() object_debug_timer.reset(); if (gObjectList.mNumDeadObjectUpdates) { - llinfos << "Dead object updates: " << gObjectList.mNumDeadObjectUpdates << llendl; + LL_INFOS() << "Dead object updates: " << gObjectList.mNumDeadObjectUpdates << LL_ENDL; gObjectList.mNumDeadObjectUpdates = 0; } if (gObjectList.mNumUnknownKills) { - llinfos << "Kills on unknown objects: " << gObjectList.mNumUnknownKills << llendl; + LL_INFOS() << "Kills on unknown objects: " << gObjectList.mNumUnknownKills << LL_ENDL; gObjectList.mNumUnknownKills = 0; } if (gObjectList.mNumUnknownUpdates) { - llinfos << "Unknown object updates: " << gObjectList.mNumUnknownUpdates << llendl; + LL_INFOS() << "Unknown object updates: " << gObjectList.mNumUnknownUpdates << LL_ENDL; gObjectList.mNumUnknownUpdates = 0; } @@ -3884,26 +4219,27 @@ void LLAppViewer::idle() } gFrameStats.addFrameData(); } - + if (!gDisconnected) { - LLFastTimer t(FTM_NETWORK); - - //////////////////////////////////////////////// - // - // Network processing - // - // NOTE: Starting at this point, we may still have pointers to "dead" objects - // floating throughout the various object lists. - // + LL_RECORD_BLOCK_TIME(FTM_NETWORK); + + //////////////////////////////////////////////// + // + // Network processing + // + // NOTE: Starting at this point, we may still have pointers to "dead" objects + // floating throughout the various object lists. + // idleNameCache(); - - gFrameStats.start(LLFrameStats::IDLE_NETWORK); + if (gAgent.getRegion()) LLExperienceCache::instance().idleCoro(); + + gFrameStats.start(LLFrameStats::IDLE_NETWORK); stop_glerror(); idleNetwork(); - stop_glerror(); - - gFrameStats.start(LLFrameStats::AGENT_MISC); + stop_glerror(); + + gFrameStats.start(LLFrameStats::AGENT_MISC); // Check for away from keyboard, kick idle agents. idle_afk_check(); @@ -3917,17 +4253,17 @@ void LLAppViewer::idle() // Handle the regular UI idle callbacks as well as // hover callbacks // - { -// LLFastTimer t(FTM_IDLE_CB); + LL_RECORD_BLOCK_TIME(FTM_IDLE_CB); // Do event notifications if necessary. Yes, we may want to move this elsewhere. gEventNotifier.update(); - + gIdleCallbacks.callFunctions(); gInventory.idleNotifyObservers(); + if (auto antispam = NACLAntiSpamRegistry::getIfExists()) antispam->idle(); } - + // Metrics logging (LLViewerAssetStats, etc.) { static LLTimer report_interval; @@ -3936,56 +4272,61 @@ void LLAppViewer::idle() F32 seconds = report_interval.getElapsedTimeF32(); if (seconds >= app_metrics_interval) { - metricsSend(! gDisconnected); + LAZY_FT("metricsSend"); + metricsSend(!gDisconnected); report_interval.reset(); } } if (gDisconnected) - { + { return; - } + } - static const LLCachedControl hide_tp_screen("AscentDisableTeleportScreens",false); + static const LLCachedControl hide_tp_screen("AscentDisableTeleportScreens", false); LLAgent::ETeleportState tp_state = gAgent.getTeleportState(); if (!hide_tp_screen && tp_state != LLAgent::TELEPORT_NONE && tp_state != LLAgent::TELEPORT_LOCAL && tp_state != LLAgent::TELEPORT_PENDING) - { + { return; - } + } gViewerWindow->updateUI(); + //updateUI may have created sounds (clicks, etc). Call idleAudio to dispatch asap. + idleAudio(); + /////////////////////////////////////// // Agent and camera movement // - LLCoordGL current_mouse = gViewerWindow->getCurrentMouse(); + LLCoordGL current_mouse = gViewerWindow->getCurrentMouse(); { // After agent and camera moved, figure out if we need to // deselect objects. + LAZY_FT("deselectAllIfTooFar"); LLSelectMgr::getInstance()->deselectAllIfTooFar(); } { // Handle pending gesture processing - static LLFastTimer::DeclareTimer ftm("Agent Position"); - LLFastTimer t(ftm); + static LLTrace::BlockTimerStatHandle ftm("Agent Position"); + LL_RECORD_BLOCK_TIME(ftm); LLGestureMgr::instance().update(); gAgent.updateAgentPosition(gFrameDTClamped, yaw, current_mouse.mX, current_mouse.mY); } { - LLFastTimer t(FTM_OBJECTLIST_UPDATE); + LL_RECORD_BLOCK_TIME(FTM_OBJECTLIST_UPDATE); gFrameStats.start(LLFrameStats::OBJECT_UPDATE); - - if (!(logoutRequestSent() && hasSavedFinalSnapshot())) + + if (!(logoutRequestSent() && hasSavedFinalSnapshot())) { gObjectList.update(gAgent, *LLWorld::getInstance()); } } - + ////////////////////////////////////// // // Deletes objects... @@ -3994,17 +4335,17 @@ void LLAppViewer::idle() { gFrameStats.start(LLFrameStats::CLEAN_DEAD); - LLFastTimer t(FTM_CLEANUP); + LL_RECORD_BLOCK_TIME(FTM_CLEANUP); { - LLFastTimer t(FTM_CLEANUP_OBJECTS); + LL_RECORD_BLOCK_TIME(FTM_CLEANUP_OBJECTS); gObjectList.cleanDeadObjects(); } { - LLFastTimer t(FTM_CLEANUP_DRAWABLES); + LL_RECORD_BLOCK_TIME(FTM_CLEANUP_DRAWABLES); LLDrawable::cleanupDeadDrawables(); } } - + // // After this point, in theory we should never see a dead object // in the various object/drawable lists. @@ -4020,8 +4361,8 @@ void LLAppViewer::idle() { gFrameStats.start(LLFrameStats::UPDATE_EFFECTS); - static LLFastTimer::DeclareTimer ftm("HUD Effects"); - LLFastTimer t(ftm); + static LLTrace::BlockTimerStatHandle ftm("HUD Effects"); + LL_RECORD_BLOCK_TIME(ftm); LLSelectMgr::getInstance()->updateEffects(); LLHUDManager::getInstance()->cleanupEffects(); LLHUDManager::getInstance()->sendEffects(); @@ -4035,28 +4376,32 @@ void LLAppViewer::idle() // { - LLFastTimer t(FTM_NETWORK); + LL_RECORD_BLOCK_TIME(FTM_NETWORK); gVLManager.unpackData(); } - + ///////////////////////// // // Update surfaces, and surface textures as well. // - LLWorld::getInstance()->updateVisibilities(); + { + LAZY_FT("updateVisibilities"); + LLWorld::getInstance()->updateVisibilities(); + } { const F32 max_region_update_time = .001f; // 1ms - LLFastTimer t(FTM_REGION_UPDATE); + LL_RECORD_BLOCK_TIME(FTM_REGION_UPDATE); LLWorld::getInstance()->updateRegions(max_region_update_time); } - + ///////////////////////// // // Update weather effects // if (!gNoRender) { + LAZY_FT("Weather"); #if ENABLE_CLASSIC_CLOUDS LLWorld::getInstance()->updateClouds(gFrameDTClamped); #endif @@ -4073,7 +4418,7 @@ void LLAppViewer::idle() gWindVec = regionp->mWind.getVelocity(wind_position_region); // Compute average wind and use to drive motion of water - + average_wind = regionp->mWind.getAverage(); #if ENABLE_CLASSIC_CLOUDS F32 cloud_density = regionp->mCloudLayer.getDensityRegion(wind_position_region); @@ -4088,16 +4433,16 @@ void LLAppViewer::idle() } } stop_glerror(); - + ////////////////////////////////////// // // Sort and cull in the new renderer are moved to pipeline.cpp // Here, particles are updated and drawables are moved. // - + if (!gNoRender) { - LLFastTimer t(FTM_WORLD_UPDATE); + LL_RECORD_BLOCK_TIME(FTM_WORLD_UPDATE); gFrameStats.start(LLFrameStats::UPDATE_MOVE); gPipeline.updateMove(); @@ -4106,51 +4451,53 @@ void LLAppViewer::idle() } stop_glerror(); - if (LLViewerJoystick::getInstance()->getOverrideCamera()) { - LLViewerJoystick::getInstance()->moveFlycam(); - } - else - { - if (LLToolMgr::getInstance()->inBuildMode()) + LAZY_FT("Move*"); + if (LLViewerJoystick::getInstance()->getOverrideCamera()) { - LLViewerJoystick::getInstance()->moveObjects(); + LLViewerJoystick::getInstance()->moveFlycam(); } + else + { + if (LLToolMgr::getInstance()->inBuildMode()) + { + LLViewerJoystick::getInstance()->moveObjects(); + } - gAgentCamera.updateCamera(); + gAgentCamera.updateCamera(); + } } // update media focus - LLViewerMediaFocus::getInstance()->update(); - + { + LAZY_FT("Media Focus"); + LLViewerMediaFocus::getInstance()->update(); + } + // Update marketplace - LLMarketplaceInventoryImporter::update(); - LLMarketplaceInventoryNotifications::update(); + { + LAZY_FT("MPII::update"); + LLMarketplaceInventoryImporter::update(); + } + { + LAZY_FT("MPIN::update"); + LLMarketplaceInventoryNotifications::update(); + } // objects and camera should be in sync, do LOD calculations now { - LLFastTimer t(FTM_LOD_UPDATE); + LL_RECORD_BLOCK_TIME(FTM_LOD_UPDATE); gObjectList.updateApparentAngles(gAgent); } - { - gFrameStats.start(LLFrameStats::AUDIO); - LLFastTimer t(FTM_AUDIO_UPDATE); - - if (gAudiop) - { - audio_update_volume(false); - audio_update_listener(); - audio_update_wind(false); - - // this line actually commits the changes we've made to source positions, etc. - const F32 max_audio_decode_time = 0.002f; // 2 ms decode time - gAudiop->idle(max_audio_decode_time); - } - } + // Update AV render info + LLAvatarRenderInfoAccountant::idle(); // Execute deferred tasks. - LLDeferredTaskList::instance().run(); + { + LAZY_FT("DeferredTaskRun"); + LLDeferredTaskList::instance().run(); + } // Handle shutdown process, for example, // wait for floaters to close, send quit message, @@ -4257,17 +4604,15 @@ void LLAppViewer::sendLogoutRequest() //Set internal status variables and marker files gLogoutInProgress = TRUE; mLogoutMarkerFileName = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,LOGOUT_MARKER_FILE_NAME); - - LLAPRFile outfile(mLogoutMarkerFileName, LL_APR_W); - mLogoutMarkerFile = outfile.getFileHandle() ; - if (mLogoutMarkerFile) + + if (mLogoutMarkerFile.open(mLogoutMarkerFileName, LL_APR_W) == APR_SUCCESS) { - llinfos << "Created logout marker file " << mLogoutMarkerFileName << llendl; - apr_file_close(mLogoutMarkerFile); + LL_INFOS() << "Created logout marker file " << mLogoutMarkerFileName << LL_ENDL; + mLogoutMarkerFile.close(); } else { - llwarns << "Cannot create logout marker file " << mLogoutMarkerFileName << llendl; + LL_WARNS() << "Cannot create logout marker file " << mLogoutMarkerFileName << LL_ENDL; } } } @@ -4299,15 +4644,15 @@ void LLAppViewer::idleNameCache() if (have_capability) { // we have support for display names, use it - U32 url_size = name_lookup_url.size(); - // capabilities require URLs with slashes before query params: - // https://:/cap//?ids= - // but the caps are granted like: - // https://:/cap/ - if (url_size > 0 && name_lookup_url[url_size-1] != '/') - { - name_lookup_url += '/'; - } + U32 url_size = name_lookup_url.size(); + // capabilities require URLs with slashes before query params: + // https://:/cap//?ids= + // but the caps are granted like: + // https://:/cap/ + if (url_size > 0 && name_lookup_url[url_size-1] != '/') + { + name_lookup_url += '/'; + } LLAvatarNameCache::setNameLookupURL(name_lookup_url); } else @@ -4337,12 +4682,12 @@ void LLAppViewer::idleNameCache() static F32 CheckMessagesMaxTime = CHECK_MESSAGES_DEFAULT_MAX_TIME; #endif -static LLFastTimer::DeclareTimer FTM_IDLE_NETWORK("Idle Network"); -static LLFastTimer::DeclareTimer FTM_MESSAGE_ACKS("Message Acks"); -static LLFastTimer::DeclareTimer FTM_RETRANSMIT("Retransmit"); -static LLFastTimer::DeclareTimer FTM_TIMEOUT_CHECK("Timeout Check"); -static LLFastTimer::DeclareTimer FTM_DYNAMIC_THROTTLE("Dynamic Throttle"); -static LLFastTimer::DeclareTimer FTM_CHECK_REGION_CIRCUIT("Check Region Circuit"); +static LLTrace::BlockTimerStatHandle FTM_IDLE_NETWORK("Idle Network"); +static LLTrace::BlockTimerStatHandle FTM_MESSAGE_ACKS("Message Acks"); +static LLTrace::BlockTimerStatHandle FTM_RETRANSMIT("Retransmit"); +static LLTrace::BlockTimerStatHandle FTM_TIMEOUT_CHECK("Timeout Check"); +static LLTrace::BlockTimerStatHandle FTM_DYNAMIC_THROTTLE("Dynamic Throttle"); +static LLTrace::BlockTimerStatHandle FTM_CHECK_REGION_CIRCUIT("Check Region Circuit"); void LLAppViewer::idleNetwork() { @@ -4354,9 +4699,9 @@ void LLAppViewer::idleNetwork() static const LLCachedControl speedTest(gSavedSettings, "SpeedTest"); if (!speedTest) { - LLFastTimer t(FTM_IDLE_NETWORK); // decode + LL_RECORD_BLOCK_TIME(FTM_IDLE_NETWORK); // decode - llpushcallstacks ; + LL_PUSH_CALLSTACKS(); LLTimer check_message_timer; // Read all available packets from network const S64 frame_count = gFrameCount; // U32->S64 @@ -4417,25 +4762,23 @@ void LLAppViewer::idleNetwork() if( remaining_possible_decodes <= 0 ) { - llinfos << "Maxed out number of messages per frame at " << MESSAGE_MAX_PER_FRAME << llendl; + LL_INFOS() << "Maxed out number of messages per frame at " << MESSAGE_MAX_PER_FRAME << LL_ENDL; } if (gPrintMessagesThisFrame) { - llinfos << "Decoded " << total_decoded << " msgs this frame!" << llendl; + LL_INFOS() << "Decoded " << total_decoded << " msgs this frame!" << LL_ENDL; gPrintMessagesThisFrame = FALSE; } } - llpushcallstacks ; + LLViewerStats::getInstance()->mNumNewObjectsStat.addValue(gObjectList.mNumNewObjects); // Retransmit unacknowledged packets. gXferManager->retransmitUnackedPackets(); gAssetStorage->checkForTimeouts(); - llpushcallstacks ; gViewerThrottle.updateDynamicThrottle(); - llpushcallstacks ; // Check that the circuit between the viewer and the agent's current // region is still alive LLViewerRegion *agent_region = gAgent.getRegion(); @@ -4444,7 +4787,7 @@ void LLAppViewer::idleNetwork() LLUUID this_region_id = agent_region->getRegionID(); bool this_region_alive = agent_region->isAlive(); if ((mAgentRegionLastAlive && !this_region_alive) // newly dead - && (mAgentRegionLastID == this_region_id)) // same region + && (mAgentRegionLastID == this_region_id)) // same region { forceDisconnect(LLTrans::getString("AgentLostConnection")); } @@ -4453,6 +4796,33 @@ void LLAppViewer::idleNetwork() } } +void LLAppViewer::idleAudio() +{ + gFrameStats.start(LLFrameStats::AUDIO); + LL_RECORD_BLOCK_TIME(FTM_AUDIO_UPDATE); + + if (gAudiop) + { + audio_update_volume(); + audio_update_listener(); + + // this line actually commits the changes we've made to source positions, etc. + const F32 max_audio_decode_time = 0.002f; // 2 ms decode time + gAudiop->idle(max_audio_decode_time); + } +} +void LLAppViewer::shutdownAudio() +{ + if (gAudiop) + { + // shut down the audio subsystem + gAudiop->shutdown(); + + delete gAudiop; + gAudiop = NULL; + } +} + void LLAppViewer::disconnectViewer() { if (gDisconnected) @@ -4464,7 +4834,7 @@ void LLAppViewer::disconnectViewer() // // Save snapshot for next time, if we made it through initialization - llinfos << "Disconnecting viewer!" << llendl; + LL_INFOS() << "Disconnecting viewer!" << LL_ENDL; // Dump our frame statistics gFrameStats.dump(); @@ -4478,36 +4848,38 @@ void LLAppViewer::disconnectViewer() if (gFloaterView) { gFloaterView->restoreAll(); - } + std::list floaters_to_close; + for (LLView::child_list_const_iter_t it = gFloaterView->getChildList()->begin(); + it != gFloaterView->getChildList()->end(); + ++it) + { + // The following names are defined in the + // floater_image_preview.xml + // floater_sound_preview.xml + // floater_animation_preview.xml + // files. + + // A more generic mechanism would be nice.. + LLFloater* fl = static_cast(*it); + if (fl + && (fl->getName() == "Image Preview" + || fl->getName() == "Sound Preview" + || fl->getName() == "Animation Preview" + || fl->getName() == "perm prefs" + )) + { + floaters_to_close.push_back(fl); + } + } - std::list floaters_to_close; - for(LLView::child_list_const_iter_t it = gFloaterView->getChildList()->begin(); - it != gFloaterView->getChildList()->end(); - ++it) - { - // The following names are defined in the - // floater_image_preview.xml - // floater_sound_preview.xml - // floater_animation_preview.xml - // files. - LLFloater* fl = static_cast(*it); - if(fl - && (fl->getName() == "Image Preview" - || fl->getName() == "Sound Preview" - || fl->getName() == "Animation Preview" - )) + while (!floaters_to_close.empty()) { - floaters_to_close.push_back(fl); + LLFloater* fl = floaters_to_close.front(); + floaters_to_close.pop_front(); + fl->close(); } } - - while(!floaters_to_close.empty()) - { - LLFloater* fl = floaters_to_close.front(); - floaters_to_close.pop_front(); - fl->close(); - } } if (LLSelectMgr::getInstance()) @@ -4529,9 +4901,15 @@ void LLAppViewer::disconnectViewer() } saveNameCache(); + if (LLExperienceCache::instanceExists()) + { + // TODO: LLExperienceCache::cleanup() logic should be moved to + // cleanupSingleton(). + LLExperienceCache::instance().cleanup(); + } // close inventory interface, close all windows - LLInventoryView::cleanup(); + LLPanelMainInventory::cleanup(); // [SL:KB] - Patch: Appearance-Misc | Checked: 2013-02-12 (Catznip-3.4) // Destroying all objects below will trigger attachment detaching code and attempt to remove the COF links for them LLAppearanceMgr::instance().setAttachmentInvLinkEnable(false); @@ -4553,47 +4931,57 @@ void LLAppViewer::disconnectViewer() LLDestroyClassList::instance().fireCallbacks(); cleanup_xfer_manager(); + + shutdownAudio(); + gDisconnected = TRUE; } void LLAppViewer::forceErrorLLError() { - llerrs << "This is an llerror" << llendl; + LL_ERRS() << "This is a deliberate llerror" << LL_ENDL; } void LLAppViewer::forceErrorBreakpoint() { + LL_WARNS() << "Forcing a deliberate breakpoint" << LL_ENDL; #ifdef LL_WINDOWS - DebugBreak(); + DebugBreak(); +#else + asm ("int $3"); #endif - return; + return; } void LLAppViewer::forceErrorBadMemoryAccess() { - S32* crash = NULL; - *crash = 0xDEADBEEF; - return; + LL_WARNS() << "Forcing a deliberate bad memory access" << LL_ENDL; + S32* crash = nullptr; + *crash = 0xDEADBEEF; + return; } void LLAppViewer::forceErrorInfiniteLoop() { - while(true) - { - ; - } - return; + LL_WARNS() << "Forcing a deliberate infinite loop" << LL_ENDL; + while(true) + { + ; + } + return; } void LLAppViewer::forceErrorSoftwareException() { - // *FIX: Any way to insure it won't be handled? - throw; + LL_WARNS() << "Forcing a deliberate exception" << LL_ENDL; + // *FIX: Any way to insure it won't be handled? + throw; } void LLAppViewer::forceErrorDriverCrash() { - glDeleteTextures(1, NULL); + LL_WARNS() << "Forcing a deliberate driver crash" << LL_ENDL; + glDeleteTextures(1, nullptr); } void LLAppViewer::initMainloopTimeout(const std::string& state, F32 secs) @@ -4610,7 +4998,7 @@ void LLAppViewer::destroyMainloopTimeout() if(mMainloopTimeout) { delete mMainloopTimeout; - mMainloopTimeout = NULL; + mMainloopTimeout = nullptr; } } @@ -4641,7 +5029,7 @@ void LLAppViewer::pingMainloopTimeout(const std::string& state, F32 secs) { // if(!restoreErrorTrap()) // { -// llwarns << "!!!!!!!!!!!!! Its an error trap!!!!" << state << llendl; +// LL_WARNS() << "!!!!!!!!!!!!! Its an error trap!!!!" << state << LL_ENDL; // } if(mMainloopTimeout) @@ -4662,12 +5050,12 @@ void LLAppViewer::handleLoginComplete() initMainloopTimeout("Mainloop Init"); // Store some data to DebugInfo in case of a freeze. - gDebugInfo["ClientInfo"]["Name"] = gVersionChannel; + gDebugInfo["ClientInfo"]["Name"] = LLVersionInfo::getChannel(); - gDebugInfo["ClientInfo"]["MajorVersion"] = gVersionMajor; - gDebugInfo["ClientInfo"]["MinorVersion"] = gVersionMinor; - gDebugInfo["ClientInfo"]["PatchVersion"] = gVersionPatch; - gDebugInfo["ClientInfo"]["BuildVersion"] = gVersionBuild; + gDebugInfo["ClientInfo"]["MajorVersion"] = LLVersionInfo::getMajor(); + gDebugInfo["ClientInfo"]["MinorVersion"] = LLVersionInfo::getMinor(); + gDebugInfo["ClientInfo"]["PatchVersion"] = LLVersionInfo::getPatch(); + gDebugInfo["ClientInfo"]["BuildVersion"] = LLVersionInfo::getBuild(); LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); if ( parcel && parcel->getMusicURL()[0]) @@ -4696,6 +5084,16 @@ void LLAppViewer::handleLoginComplete() } mOnLoginCompleted(); + + // Singu Note: This would usually be registered via mOnLoginCompleted, but that would require code in newview regardless so.. just call directly here. + LLNotifications::instance().onLoginCompleted(); + + // Singu Note: Due to MAINT-4001, we must do this here, it lives in LLSidepanelInventory::updateInbox upstream. + // Consolidate Received items + // We shouldn't have to do that but with a client/server system relying on a "well known folder" convention, + // things can get messy and conventions broken. This call puts everything back together in its right place. + LLUUID id(gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX, true)); + if (id.notNull()) gInventory.consolidateForType(id, LLFolderType::FT_INBOX); writeDebugInfo(); } diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index 1f9b5025c1..9644fbe08b 100644 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -76,8 +76,9 @@ class LLAppViewer : public LLApp bool quitRequested() { return mQuitRequested; } bool logoutRequestSent() { return mLogoutRequestSent; } + bool isSecondInstance() { return mSecondInstance; } - void writeDebugInfo(); + void writeDebugInfo(bool isStatic=true); const LLOSInfo& getOSInfo() const { return mSysOSInfo; } @@ -86,11 +87,8 @@ class LLAppViewer : public LLApp virtual bool restoreErrorTrap() = 0; // Require platform specific override to reset error handling mechanism. // return false if the error trap needed restoration. - virtual void handleCrashReporting(bool reportFreeze = false) = 0; // What to do with crash report? - virtual void handleSyncCrashTrace() = 0; // any low-level crash-prep that has to happen in the context of the crashing thread before the crash report is delivered. + void initCrashReporting(); // What to do with crash report? static void handleViewerCrash(); // Hey! The viewer crashed. Do this, soon. - static void handleSyncViewerCrash(); // Hey! The viewer crashed. Do this right NOW in the context of the crashing thread. - void checkForCrash(); // Thread accessors static LLTextureCache* getTextureCache() { return sTextureCache; } @@ -104,7 +102,7 @@ class LLAppViewer : public LLApp bool getPurgeCache() const { return mPurgeCache; } - const std::string& getSecondLifeTitle() const; // The Second Life title. + std::string getSecondLifeTitle() const; // The Second Life title. const std::string& getWindowTitle() const; // The window display name. void forceDisconnect(const std::string& msg); // Force disconnection, with a message to the user. @@ -116,8 +114,9 @@ class LLAppViewer : public LLApp void loadNameCache(); void saveNameCache(); - void removeMarkerFile(bool leave_logout_marker = false); + void removeMarkerFiles(); + void removeDumpDir(); // LLAppViewer testing helpers. // *NOTE: These will potentially crash the viewer. Only for debugging. virtual void forceErrorLLError(); @@ -127,14 +126,13 @@ class LLAppViewer : public LLApp virtual void forceErrorSoftwareException(); virtual void forceErrorDriverCrash(); - // *NOTE: There are currently 3 settings files: - // "Global", "PerAccount" and "CrashSettings" + // *NOTE: There are currently 2 settings files: + // "Global", and "PerAccount" // The list is found in app_settings/settings_files.xml // but since they are used explicitly in code, // the follow consts should also do the trick. static const std::string sGlobalSettingsName; static const std::string sPerAccountSettingsName; - static const std::string sCrashSettingsName; // Load settings from the location specified by loction_key. // Key availale and rules for loading, are specified in @@ -160,6 +158,7 @@ class LLAppViewer : public LLApp void handleLoginComplete(); LLAllocator & getAllocator() { return mAlloc; } + // On LoginCompleted callback typedef boost::signals2::signal login_completed_signal_t; login_completed_signal_t mOnLoginCompleted; @@ -174,7 +173,8 @@ class LLAppViewer : public LLApp static void metricsSend(bool enable_reporting); protected: virtual bool initWindow(); // Initialize the viewer's window. - virtual bool initLogging(); // Initialize log files, logging system, return false on failure. + virtual void initLoggingAndGetLastDuration(); // Initialize log files, logging system + void initLoggingInternal(); virtual void initConsole() {}; // Initialize OS level debugging console. virtual bool initHardwareTest() { return true; } // A false result indicates the app should quit. virtual bool initSLURLHandler(); @@ -191,7 +191,6 @@ class LLAppViewer : public LLApp void initMaxHeapSize(); bool initThreads(); // Initialize viewer threads, return false on failure. bool initConfiguration(); // Initialize settings from the command line/config file. - bool initCache(); // Initialize local client cache. void checkMemory() ; @@ -204,14 +203,17 @@ class LLAppViewer : public LLApp void writeSystemInfo(); // Write system info to "debug_info.log" - bool anotherInstanceRunning(); - void initMarkerFile(); + void processMarkerFiles(); + static void recordMarkerVersion(LLAPRFile& marker_file); + bool markerIsSameVersion(const std::string& marker_name) const; void idle(); void idleShutdown(); // update avatar SLID and display name caches void idleNameCache(); void idleNetwork(); + void idleAudio(); + void shutdownAudio(); void sendLogoutRequest(); void disconnectViewer(); @@ -226,8 +228,7 @@ class LLAppViewer : public LLApp LLAPRFile mMarkerFile; // A file created to indicate the app is running. std::string mLogoutMarkerFileName; - apr_file_t* mLogoutMarkerFile; // A file created to indicate the app is running. - + LLAPRFile mLogoutMarkerFile; // A file created to indicate the app is running. LLOSInfo mSysOSInfo; bool mReportedCrash; @@ -271,6 +272,7 @@ class LLAppViewer : public LLApp // consts from viewer.h const S32 AGENT_UPDATES_PER_SECOND = 10; +const S32 AGENT_FORCE_UPDATES_PER_SECOND = 1; // Globals with external linkage. From viewer.h // *NOTE:Mani - These will be removed as the Viewer App Cleanup project continues. @@ -303,13 +305,13 @@ extern LLPumpIO* gServicePump; // Is the Pacific time zone (aka server time zone) // currently in daylight savings time? extern BOOL gPacificDaylightTime; - -extern U64 gFrameTime; // The timestamp of the most-recently-processed frame -extern F32 gFrameTimeSeconds; // Loses msec precision after ~4.5 hours... -extern F32 gFrameIntervalSeconds; // Elapsed time between current and previous gFrameTimeSeconds +extern U64MicrosecondsImplicit gStartTime; +extern U64MicrosecondsImplicit gFrameTime; // The timestamp of the most-recently-processed frame +extern F32SecondsImplicit gFrameTimeSeconds; // Loses msec precision after ~4.5 hours... +extern F32SecondsImplicit gFrameIntervalSeconds; // Elapsed time between current and previous gFrameTimeSeconds extern F32 gFPSClamped; // Frames per second, smoothed, weighted toward last frame extern F32 gFrameDTClamped; -extern U64 gStartTime; + extern U32 gFrameStalls; extern LLTimer gRenderStartTime; @@ -333,7 +335,7 @@ extern BOOL gUseWireframe; extern LLVFS *gStaticVFS; extern LLMemoryInfo gSysMemory; -extern U64 gMemoryAllocated; +extern U64Bytes gMemoryAllocated; extern std::string gLastVersionChannel; diff --git a/indra/newview/llappviewerlinux.cpp b/indra/newview/llappviewerlinux.cpp index ce64710fab..0f2957bc92 100644 --- a/indra/newview/llappviewerlinux.cpp +++ b/indra/newview/llappviewerlinux.cpp @@ -46,27 +46,6 @@ #include -#if LL_LINUX -# include // RTLD_LAZY -# include // backtrace - glibc only -# include -# include -# include -# include -#elif LL_SOLARIS -# include -# include -# include -# include -#endif - -#ifdef LL_ELFBIN -# ifdef __GNUC__ -# include // for symbol demangling -# endif -# include "ELFIO/ELFIO.h" // for better backtraces -#endif - #if LL_DBUS_ENABLED # include "llappviewerlinux_api_dbus.h" @@ -90,8 +69,9 @@ static void exceptionTerminateHandler() // reinstall default terminate() handler in case we re-terminate. if (gOldTerminateHandler) std::set_terminate(gOldTerminateHandler); // treat this like a regular viewer crash, with nice stacktrace etc. - LLAppViewer::handleSyncViewerCrash(); - LLAppViewer::handleViewerCrash(); + long *null_ptr; + null_ptr = 0; + *null_ptr = 0xDEADBEEF; //Force an exception that will trigger breakpad. // we've probably been killed-off before now, but... gOldTerminateHandler(); // call old terminate() handler } @@ -114,12 +94,11 @@ int main( int argc, char **argv ) gOldTerminateHandler = std::set_terminate(exceptionTerminateHandler); // install crash handlers viewer_app_ptr->setErrorHandler(LLAppViewer::handleViewerCrash); - viewer_app_ptr->setSyncErrorHandler(LLAppViewer::handleSyncViewerCrash); bool ok = viewer_app_ptr->init(); if(!ok) { - llwarns << "Application init failed." << llendl; + LL_WARNS() << "Application init failed." << LL_ENDL; return -1; } @@ -140,205 +119,9 @@ int main( int argc, char **argv ) } delete viewer_app_ptr; viewer_app_ptr = NULL; - return 0; } -#ifdef LL_SOLARIS -static inline BOOL do_basic_glibc_backtrace() -{ - BOOL success = FALSE; - - std::string strace_filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log"); - llinfos << "Opening stack trace file " << strace_filename << llendl; - LLFILE* StraceFile = LLFile::fopen(strace_filename, "w"); - if (!StraceFile) - { - llinfos << "Opening stack trace file " << strace_filename << " failed. Using stderr." << llendl; - StraceFile = stderr; - } - - printstack(fileno(StraceFile)); - - if (StraceFile != stderr) - fclose(StraceFile); - - return success; -} -#else -#define MAX_STACK_TRACE_DEPTH 40 -// This uses glibc's basic built-in stack-trace functions for a not very -// amazing backtrace. -static inline BOOL do_basic_glibc_backtrace() -{ - void *stackarray[MAX_STACK_TRACE_DEPTH]; - size_t size; - char **strings; - size_t i; - BOOL success = FALSE; - - size = backtrace(stackarray, MAX_STACK_TRACE_DEPTH); - strings = backtrace_symbols(stackarray, size); - - std::string strace_filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log"); - llinfos << "Opening stack trace file " << strace_filename << llendl; - LLFILE* StraceFile = LLFile::fopen(strace_filename, "w"); // Flawfinder: ignore - if (!StraceFile) - { - llinfos << "Opening stack trace file " << strace_filename << " failed. Using stderr." << llendl; - StraceFile = stderr; - } - - if (size) - { - for (i = 0; i < size; i++) - { - // the format of the StraceFile is very specific, to allow (kludgy) machine-parsing - fprintf(StraceFile, "%-3lu ", (unsigned long)i); - fprintf(StraceFile, "%-32s\t", "unknown"); - fprintf(StraceFile, "%p ", stackarray[i]); - fprintf(StraceFile, "%s\n", strings[i]); - } - - success = TRUE; - } - - if (StraceFile != stderr) - fclose(StraceFile); - - free (strings); - return success; -} - -#if LL_ELFBIN -// This uses glibc's basic built-in stack-trace functions together with -// ELFIO's ability to parse the .symtab ELF section for better symbol -// extraction without exporting symbols (which'd cause subtle, fatal bugs). -static inline BOOL do_elfio_glibc_backtrace() -{ - void *stackarray[MAX_STACK_TRACE_DEPTH]; - size_t btsize; - char **strings; - BOOL success = FALSE; - - std::string appfilename = gDirUtilp->getExecutablePathAndName(); - - std::string strace_filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log"); - llinfos << "Opening stack trace file " << strace_filename << llendl; - LLFILE* StraceFile = LLFile::fopen(strace_filename, "w"); // Flawfinder: ignore - if (!StraceFile) - { - llinfos << "Opening stack trace file " << strace_filename << " failed. Using stderr." << llendl; - StraceFile = stderr; - } - - // get backtrace address list and basic symbol info - btsize = backtrace(stackarray, MAX_STACK_TRACE_DEPTH); - strings = backtrace_symbols(stackarray, btsize); - - // create ELF reader for our app binary - IELFI* pReader; - const IELFISection* pSec = NULL; - IELFISymbolTable* pSymTbl = 0; - if (ERR_ELFIO_NO_ERROR != ELFIO::GetInstance()->CreateELFI(&pReader) || - ERR_ELFIO_NO_ERROR != pReader->Load(appfilename.c_str()) || - // find symbol table, create reader-object - NULL == (pSec = pReader->GetSection( ".symtab" )) || - ERR_ELFIO_NO_ERROR != pReader->CreateSectionReader(IELFI::ELFI_SYMBOL, pSec, (void**)&pSymTbl) ) - { - // Failed to open our binary and read its symbol table somehow - llinfos << "Could not initialize ELF symbol reading - doing basic backtrace." << llendl; - if (StraceFile != stderr) - fclose(StraceFile); - // note that we may be leaking some of the above ELFIO - // objects now, but it's expected that we'll be dead soon - // and we want to tread delicately until we get *some* kind - // of useful backtrace. - return do_basic_glibc_backtrace(); - } - - // iterate over trace and symtab, looking for plausible symbols - std::string name; - Elf32_Addr value; - Elf32_Word ssize; - unsigned char bind; - unsigned char type; - Elf32_Half section; - int nSymNo = pSymTbl->GetSymbolNum(); - size_t btpos; - for (btpos = 0; btpos < btsize; ++btpos) - { - // the format of the StraceFile is very specific, to allow (kludgy) machine-parsing - fprintf(StraceFile, "%-3ld ", (long)btpos); - int symidx; - for (symidx = 0; symidx < nSymNo; ++symidx) - { - if (ERR_ELFIO_NO_ERROR == - pSymTbl->GetSymbol(symidx, name, value, ssize, - bind, type, section)) - { - // check if trace address within symbol range - if (uintptr_t(stackarray[btpos]) >= value && - uintptr_t(stackarray[btpos]) < value+ssize) - { - // symbol is inside viewer - fprintf(StraceFile, "%-32s\t", "com.secondlife.indra.viewer"); - fprintf(StraceFile, "%p ", stackarray[btpos]); - - char *demangled_str = NULL; - int demangle_result = 1; - demangled_str = - abi::__cxa_demangle - (name.c_str(), NULL, NULL, - &demangle_result); - if (0 == demangle_result && - NULL != demangled_str) { - fprintf(StraceFile, - "%s", demangled_str); - free(demangled_str); - } - else // failed demangle; print it raw - { - fprintf(StraceFile, - "%s", name.c_str()); - } - // print offset from symbol start - fprintf(StraceFile, - " + %lu\n", - uintptr_t(stackarray[btpos]) - - value); - goto got_sym; // early escape - } - } - } - // Fallback: - // Didn't find a suitable symbol in the binary - it's probably - // a symbol in a DSO; use glibc's idea of what it should be. - fprintf(StraceFile, "%-32s\t", "unknown"); - fprintf(StraceFile, "%p ", stackarray[btpos]); - fprintf(StraceFile, "%s\n", strings[btpos]); - got_sym:; - } - - if (StraceFile != stderr) - fclose(StraceFile); - - pSymTbl->Release(); - pSec->Release(); - pReader->Release(); - - free(strings); - - llinfos << "Finished generating stack trace." << llendl; - - success = TRUE; - return success; -} -#endif // LL_ELFBIN - -#endif // LL_SOLARIS - - LLAppViewerLinux::LLAppViewerLinux() { } @@ -349,18 +132,22 @@ LLAppViewerLinux::~LLAppViewerLinux() bool LLAppViewerLinux::init() { +#if !GLIB_CHECK_VERSION(2, 32, 0) // g_thread_init() must be called before *any* use of glib, *and* // before any mutexes are held, *and* some of our third-party // libraries likes to use glib functions; in short, do this here // really early in app startup! if (!g_thread_supported ()) g_thread_init (NULL); +#endif - return LLAppViewer::init(); + bool success = LLAppViewer::init(); + + return success; } bool LLAppViewerLinux::restoreErrorTrap() { - // *NOTE:Mani there is a case for implementing this or the mac. + // *NOTE:Mani there is a case for implementing this on the mac. // Linux doesn't need it to my knowledge. return true; } @@ -435,7 +222,7 @@ void viewerappapi_init(ViewerAppAPI *server) } else { - llwarns << "Unable to register service name: " << error->message << llendl; + LL_WARNS() << "Unable to register service name: " << error->message << LL_ENDL; } g_object_unref(serverproxy); @@ -454,7 +241,7 @@ gboolean viewer_app_api_GoSLURL(ViewerAppAPI *obj, gchar *slurl, gboolean **succ { bool success = false; - llinfos << "Was asked to go to slurl: " << slurl << llendl; + LL_INFOS() << "Was asked to go to slurl: " << slurl << LL_ENDL; std::string url = slurl; LLMediaCtrl* web = NULL; @@ -483,7 +270,9 @@ bool LLAppViewerLinux::initSLURLHandler() return false; // failed } +#if !GLIB_CHECK_VERSION(2, 36, 0) g_type_init(); +#endif //ViewerAppAPI *api_server = (ViewerAppAPI*) g_object_new(viewerappapi_get_type(), NULL); @@ -503,7 +292,9 @@ bool LLAppViewerLinux::sendURLToOtherInstance(const std::string& url) DBusGConnection *bus; GError *error = NULL; +#if !GLIB_CHECK_VERSION(2, 36, 0) g_type_init(); +#endif bus = lldbus_g_bus_get (DBUS_BUS_SESSION, &error); if (bus) @@ -520,14 +311,14 @@ bool LLAppViewerLinux::sendURLToOtherInstance(const std::string& url) } else { - llinfos << "Call-out to other instance failed (perhaps not running): " << error->message << llendl; + LL_INFOS() << "Call-out to other instance failed (perhaps not running): " << error->message << LL_ENDL; } g_object_unref(G_OBJECT(remote_object)); } else { - llwarns << "Couldn't connect to session bus: " << error->message << llendl; + LL_WARNS() << "Couldn't connect to session bus: " << error->message << LL_ENDL; } if (error) @@ -547,104 +338,6 @@ bool LLAppViewerLinux::sendURLToOtherInstance(const std::string& url) } #endif // LL_DBUS_ENABLED -void LLAppViewerLinux::handleSyncCrashTrace() -{ - // This backtrace writes into stack_trace.log -# if LL_ELFBIN - do_elfio_glibc_backtrace(); // more useful backtrace -# else - do_basic_glibc_backtrace(); // only slightly useful backtrace -# endif // LL_ELFBIN -} - -void LLAppViewerLinux::handleCrashReporting(bool reportFreeze) -{ - std::string cmd =gDirUtilp->getAppRODataDir(); - cmd += gDirUtilp->getDirDelimiter(); -#if LL_LINUX - cmd += "linux-crash-logger.bin"; -#elif LL_SOLARIS - cmd += "solaris-crash-logger"; -#else -# error Unknown platform -#endif - - if(reportFreeze) - { - char* const cmdargv[] = - {(char*)cmd.c_str(), - (char*)"-previous", - NULL}; - - fflush(NULL); // flush all buffers before the child inherits them - pid_t pid = fork(); - if (pid == 0) - { // child - execv(cmd.c_str(), cmdargv); /* Flawfinder: Ignore */ - llwarns << "execv failure when trying to start " << cmd << llendl; - _exit(1); // avoid atexit() - } else { - if (pid > 0) - { - // wait for child proc to die - int childExitStatus; - waitpid(pid, &childExitStatus, 0); - } else { - llwarns << "fork failure." << llendl; - } - } - } - else - { - const S32 cb = gCrashSettings.getS32(CRASH_BEHAVIOR_SETTING); - - // Always generate the report, have the logger do the asking, and - // don't wait for the logger before exiting (-> total cleanup). - if (CRASH_BEHAVIOR_NEVER_SEND != cb) - { - // launch the actual crash logger - const char* ask_dialog = "-dialog"; - if (CRASH_BEHAVIOR_ASK != cb) - ask_dialog = ""; // omit '-dialog' option - const char * cmdargv[] = - {cmd.c_str(), - ask_dialog, - "-user", - (char*)LLViewerLogin::getInstance()->getGridLabel().c_str(), - "-name", - LLAppViewer::instance()->getSecondLifeTitle().c_str(), - NULL}; - fflush(NULL); - pid_t pid = fork(); - if (pid == 0) - { // child - execv(cmd.c_str(), (char* const*) cmdargv); /* Flawfinder: ignore */ - llwarns << "execv failure when trying to start " << cmd << llendl; - _exit(1); // avoid atexit() - } - else - { - if (pid > 0) - { - // DO NOT wait for child proc to die; we want - // the logger to outlive us while we quit to - // free up the screen/keyboard/etc. - ////int childExitStatus; - ////waitpid(pid, &childExitStatus, 0); - } - else - { - llwarns << "fork failure." << llendl; - } - } - } - // Sometimes signals don't seem to quit the viewer. Also, we may - // have been called explicitly instead of from a signal handler. - // Make sure we exit so as to not totally confuse the user. - _exit(1); // avoid atexit(), else we may re-crash in dtors. - } -} - bool LLAppViewerLinux::beingDebugged() { static enum {unknown, no, yes} debugged = unknown; @@ -676,7 +369,6 @@ bool LLAppViewerLinux::beingDebugged() base += 1; } - //should valgrind be added here? if (strcmp(base, "gdb") == 0) { debugged = yes; @@ -690,14 +382,16 @@ bool LLAppViewerLinux::beingDebugged() #endif } -bool LLAppViewerLinux::initLogging() +void LLAppViewerLinux::initLoggingAndGetLastDuration() { // Remove the last stack trace, if any + // This file is no longer created, since the move to Google Breakpad + // The code is left here to clean out any old state in the log dir std::string old_stack_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log"); LLFile::remove(old_stack_file); - return LLAppViewer::initLogging(); + LLAppViewer::initLoggingAndGetLastDuration(); } bool LLAppViewerLinux::initParseCommandLine(LLCommandLineParser& clp) @@ -739,6 +433,7 @@ std::string LLAppViewerLinux::generateSerialNumber() // trawl /dev/disk/by-uuid looking for a good-looking UUID to grab std::string this_name; + LLDirIterator iter(uuiddir, "*"); while (iter.next(this_name)) { diff --git a/indra/newview/llappviewerlinux.h b/indra/newview/llappviewerlinux.h index 365fcfeb6b..6c4020c4ce 100644 --- a/indra/newview/llappviewerlinux.h +++ b/indra/newview/llappviewerlinux.h @@ -64,10 +64,8 @@ class LLAppViewerLinux : public LLAppViewer virtual bool beingDebugged(); virtual bool restoreErrorTrap(); - virtual void handleCrashReporting(bool reportFreeze); - virtual void handleSyncCrashTrace(); - virtual bool initLogging(); + virtual void initLoggingAndGetLastDuration(); virtual bool initParseCommandLine(LLCommandLineParser& clp); virtual bool initSLURLHandler(); diff --git a/indra/newview/llappviewerlinux_api_dbus.cpp b/indra/newview/llappviewerlinux_api_dbus.cpp index 656a7444ad..f56a75c59d 100644 --- a/indra/newview/llappviewerlinux_api_dbus.cpp +++ b/indra/newview/llappviewerlinux_api_dbus.cpp @@ -47,9 +47,9 @@ extern "C" { #include "apr_dso.h" } -#define DEBUGMSG(...) lldebugs << llformat(__VA_ARGS__) << llendl -#define INFOMSG(...) llinfos << llformat(__VA_ARGS__) << llendl -#define WARNMSG(...) llwarns << llformat(__VA_ARGS__) << llendl +#define DEBUGMSG(...) LL_DEBUGS() << llformat(__VA_ARGS__) << LL_ENDL +#define INFOMSG(...) LL_INFOS() << llformat(__VA_ARGS__) << LL_ENDL +#define WARNMSG(...) LL_WARNS() << llformat(__VA_ARGS__) << LL_ENDL #define LL_DBUS_SYM(REQUIRED, DBUSSYM, RTN, ...) RTN (*ll##DBUSSYM)(__VA_ARGS__) = NULL #include "llappviewerlinux_api_dbus_syms_raw.inc" diff --git a/indra/newview/llappviewermacosx.cpp b/indra/newview/llappviewermacosx.cpp index 029b0953ec..d4eef2b2b4 100644 --- a/indra/newview/llappviewermacosx.cpp +++ b/indra/newview/llappviewermacosx.cpp @@ -57,8 +57,6 @@ namespace int gArgC; char** gArgV; - bool sCrashReporterIsRunning = false; - OSErr AEQuitHandler(const AppleEvent *messagein, AppleEvent *reply, long refIn) { OSErr result = noErr; @@ -78,9 +76,9 @@ int main( int argc, char **argv ) // Set the working dir to /Contents/Resources if (chdir(gDirUtilp->getAppRODataDir().c_str()) == -1) { - llwarns << "Could not change directory to " + LL_WARNS() << "Could not change directory to " << gDirUtilp->getAppRODataDir() << ": " << strerror(errno) - << llendl; + << LL_ENDL; } LLAppViewerMacOSX* viewer_app_ptr = new LLAppViewerMacOSX(); @@ -94,7 +92,7 @@ int main( int argc, char **argv ) bool ok = viewer_app_ptr->init(); if(!ok) { - llwarns << "Application init failed." << llendl; + LL_WARNS() << "Application init failed." << LL_ENDL; return -1; } @@ -169,7 +167,7 @@ bool LLAppViewerMacOSX::initParseCommandLine(LLCommandLineParser& clp) llifstream ifs(filename, llifstream::binary); if (!ifs.is_open()) { - llwarns << "Unable to open file" << filename << llendl; + LL_WARNS() << "Unable to open file" << filename << LL_ENDL; return false; } @@ -262,156 +260,6 @@ bool LLAppViewerMacOSX::restoreErrorTrap() return reset_count == 0; } -void LLAppViewerMacOSX::handleSyncCrashTrace() -{ - // do nothing -} - -static OSStatus CarbonEventHandler(EventHandlerCallRef inHandlerCallRef, - EventRef inEvent, - void* inUserData) -{ - ProcessSerialNumber psn; - - GetEventParameter(inEvent, - kEventParamProcessID, - typeProcessSerialNumber, - NULL, - sizeof(psn), - NULL, - &psn); - - if( GetEventKind(inEvent) == kEventAppTerminated ) - { - Boolean matching_psn = FALSE; - OSErr os_result = SameProcess(&psn, (ProcessSerialNumber*)inUserData, &matching_psn); - if(os_result >= 0 && matching_psn) - { - sCrashReporterIsRunning = false; - QuitApplicationEventLoop(); - } - } - return noErr; -} - -void LLAppViewerMacOSX::handleCrashReporting(bool reportFreeze) -{ - // This used to use fork&exec, but is switched to LSOpenApplication to - // Make sure the crash reporter launches in front of the SL window. - - std::string command_str; - //command_str = "open Second Life.app/Contents/Resources/mac-crash-logger.app"; - command_str = "mac-crash-logger.app/Contents/MacOS/mac-crash-logger"; - - FSRef appRef; - Boolean isDir = 0; - OSStatus os_result = FSPathMakeRef((UInt8*)command_str.c_str(), - &appRef, - &isDir); - if(os_result >= 0) - { - LSApplicationParameters appParams; - memset(&appParams, 0, sizeof(appParams)); - appParams.version = 0; - appParams.flags = kLSLaunchNoParams | kLSLaunchStartClassic; - appParams.application = &appRef; - - if(reportFreeze) - { - // Make sure freeze reporting launches the crash logger synchronously, lest - // Log files get changed by SL while the logger is running. - - // *NOTE:Mani A better way - make a copy of the data that the crash reporter will send - // and let SL go about its business. This way makes the mac work like windows and linux - // and is the smallest patch for the issue. - sCrashReporterIsRunning = false; - ProcessSerialNumber o_psn; - - static EventHandlerRef sCarbonEventsRef = NULL; - static const EventTypeSpec kEvents[] = - { - { kEventClassApplication, kEventAppTerminated } - }; - - // Install the handler to detect crash logger termination - InstallEventHandler(GetApplicationEventTarget(), - (EventHandlerUPP) CarbonEventHandler, - GetEventTypeCount(kEvents), - kEvents, - &o_psn, - &sCarbonEventsRef - ); - - // Remove, temporarily the quit handler - which has *crash* behavior before - // the mainloop gets running! - AERemoveEventHandler(kCoreEventClass, - kAEQuitApplication, - NewAEEventHandlerUPP(AEQuitHandler), - false); - - // Launch the crash reporter. - os_result = LSOpenApplication(&appParams, &o_psn); - - if(os_result >= 0) - { - sCrashReporterIsRunning = true; - } - - while(sCrashReporterIsRunning) - { - RunApplicationEventLoop(); - } - - // Re-install the apps quit handler. - AEInstallEventHandler(kCoreEventClass, - kAEQuitApplication, - NewAEEventHandlerUPP(AEQuitHandler), - 0, - false); - - // Remove the crash reporter quit handler. - RemoveEventHandler(sCarbonEventsRef); - } - else - { - appParams.flags |= kLSLaunchAsync; - clear_signals(); - - ProcessSerialNumber o_psn; - os_result = LSOpenApplication(&appParams, &o_psn); - } - - } - - if(!reportFreeze) - { - _exit(1); - } - - // TODO:palmer REMOVE THIS VERY SOON. THIS WILL NOT BE IN VIEWER 2.0 - // Remove the crash stack log from previous executions. - // Since we've started logging a new instance of the app, we can assume - // The old crash stack is invalid for the next crash report. - char path[MAX_PATH]; - FSRef folder; - if(FSFindFolder(kUserDomain, kLogsFolderType, false, &folder) == noErr) - { - // folder is an FSRef to ~/Library/Logs/ - if(FSRefMakePath(&folder, (UInt8*)&path, sizeof(path)) == noErr) - { - std::string pathname = std::string(path) + std::string("/CrashReporter/"); - std::string mask = "Second Life*"; - std::string file_name; - LLDirIterator iter(pathname, mask); - while(iter.next(file_name)) - { - LLFile::remove(pathname + file_name); - } - } - } - -} - std::string LLAppViewerMacOSX::generateSerialNumber() { char serial_md5[MD5HEX_STR_SIZE]; // Flawfinder: ignore @@ -540,13 +388,13 @@ void init_apple_menu(const char* product) if(AEInstallEventHandler('GURL', 'GURL', NewAEEventHandlerUPP(AEGURLHandler),0, false) != noErr) { // Couldn't install AppleEvent handler. This error shouldn't be fatal. - llinfos << "Couldn't install 'GURL' AppleEvent handler. Continuing..." << llendl; + LL_INFOS() << "Couldn't install 'GURL' AppleEvent handler. Continuing..." << LL_ENDL; } // Install a handler for 'quit' AppleEvents. This makes quitting the application from the dock work. if(AEInstallEventHandler(kCoreEventClass, kAEQuitApplication, NewAEEventHandlerUPP(AEQuitHandler),0, false) != noErr) { // Couldn't install AppleEvent handler. This error shouldn't be fatal. - llinfos << "Couldn't install Quit AppleEvent handler. Continuing..." << llendl; + LL_INFOS() << "Couldn't install Quit AppleEvent handler. Continuing..." << LL_ENDL; } } diff --git a/indra/newview/llappviewermacosx.h b/indra/newview/llappviewermacosx.h index bc841fc3a7..69d069d013 100644 --- a/indra/newview/llappviewermacosx.h +++ b/indra/newview/llappviewermacosx.h @@ -51,8 +51,6 @@ class LLAppViewerMacOSX : public LLAppViewer protected: virtual bool restoreErrorTrap(); - virtual void handleCrashReporting(bool reportFreeze); - virtual void handleSyncCrashTrace(); std::string generateSerialNumber(); virtual bool initParseCommandLine(LLCommandLineParser& clp); diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index 5ccb1f7e6f..3dc530a576 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -32,26 +32,29 @@ #include "llviewerprecompiledheaders.h" -#if defined(_DEBUG) -# if _MSC_VER >= 1400 // Visual C++ 2005 or later -# define WINDOWS_CRT_MEM_CHECKS 1 -# endif -#endif +#include "llwindowwin32.h" // *FIX: for setting gIconResource. #include "llappviewerwin32.h" -#include "llwindowwin32.cpp" // *FIX: for setting gIconResource. +#include "llgl.h" #include "res/resource.h" // *FIX: for setting gIconResource. #include //_O_APPEND #include //_open_osfhandle() -#include // for AddERExcludedApplicationA() #include // _spawnl() #include // For TCHAR support +#include #include "llviewercontrol.h" #include "lldxhardware.h" +#ifdef USE_NVAPI +#include "nvapi/nvapi.h" +#include "nvapi/NvApiDriverSettings.h" +#endif + +#include + #include "llweb.h" #include "llsecondlifeurls.h" @@ -64,66 +67,8 @@ #include "llcommandlineparser.h" #include "lltrans.h" -// *FIX:Mani - This hack is to fix a linker issue with libndofdev.lib -// The lib was compiled under VS2005 - in VS2003 we need to remap assert -#ifdef LL_DEBUG -#ifdef LL_MSVC7 -extern "C" { - void _wassert(const wchar_t * _Message, const wchar_t *_File, unsigned _Line) - { - llerrs << _Message << llendl; - } -} -#endif -#endif - const std::string LLAppViewerWin32::sWindowClass = "Second Life"; -LONG WINAPI viewer_windows_exception_handler(struct _EXCEPTION_POINTERS *exception_infop) -{ - // *NOTE:Mani - this code is stolen from LLApp, where its never actually used. - //OSMessageBox("Attach Debugger Now", "Error", OSMB_OK); - // Translate the signals/exceptions into cross-platform stuff - // Windows implementation - _tprintf( _T("Entering Windows Exception Handler...\n") ); - llinfos << "Entering Windows Exception Handler..." << llendl; - - // Make sure the user sees something to indicate that the app crashed. - LONG retval; - - if (LLApp::isError()) - { - _tprintf( _T("Got another fatal signal while in the error handler, die now!\n") ); - llwarns << "Got another fatal signal while in the error handler, die now!" << llendl; - - retval = EXCEPTION_EXECUTE_HANDLER; - return retval; - } - - // Generate a minidump if we can. - // Before we wake the error thread... - // Which will start the crash reporting. - LLWinDebug::generateCrashStacks(exception_infop); - - // Flag status to error, so thread_error starts its work - LLApp::setError(); - - // Block in the exception handler until the app has stopped - // This is pretty sketchy, but appears to work just fine - while (!LLApp::isStopped()) - { - ms_sleep(10); - } - - // - // At this point, we always want to exit the app. There's no graceful - // recovery for an unhandled exception. - // - // Just kill the process. - retval = EXCEPTION_EXECUTE_HANDLER; - return retval; -} - // Create app mutex creates a unique global windows object. // If the object can be created it returns true, otherwise // it returns false. The false result can be used to determine @@ -137,7 +82,7 @@ bool create_app_mutex() bool result = true; LPCWSTR unique_mutex_name = L"SecondLifeAppMutex"; HANDLE hMutex; - hMutex = CreateMutex(NULL, TRUE, unique_mutex_name); + hMutex = CreateMutex(nullptr, TRUE, unique_mutex_name); if(GetLastError() == ERROR_ALREADY_EXISTS) { result = false; @@ -145,6 +90,94 @@ bool create_app_mutex() return result; } +#ifdef USE_NVAPI +#define NVAPI_APPNAME L"Second Life" + +/* +This function is used to print to the command line a text message +describing the nvapi error and quits +*/ +void nvapi_error(NvAPI_Status status) +{ + NvAPI_ShortString szDesc = { 0 }; + NvAPI_GetErrorMessage(status, szDesc); + LL_WARNS() << szDesc << LL_ENDL; + + //should always trigger when asserts are enabled + //llassert(status == NVAPI_OK); +} + +void ll_nvapi_init(NvDRSSessionHandle hSession) +{ + // (2) load all the system settings into the session + NvAPI_Status status = NvAPI_DRS_LoadSettings(hSession); + if (status != NVAPI_OK) + { + nvapi_error(status); + return; + } + + NvAPI_UnicodeString wsz = { 0 }; + memcpy_s(wsz, sizeof(wsz), NVAPI_APPNAME, sizeof(NVAPI_APPNAME)); + status = NvAPI_DRS_SetCurrentGlobalProfile(hSession, wsz); + if (status != NVAPI_OK) + { + nvapi_error(status); + return; + } + + // (3) Obtain the current profile. + NvDRSProfileHandle hProfile = 0; + status = NvAPI_DRS_GetCurrentGlobalProfile(hSession, &hProfile); + if (status != NVAPI_OK) + { + nvapi_error(status); + return; + } + + // load settings for querying + status = NvAPI_DRS_LoadSettings(hSession); + if (status != NVAPI_OK) + { + nvapi_error(status); + return; + } + + //get the preferred power management mode for Second Life + NVDRS_SETTING drsSetting = {0}; + drsSetting.version = NVDRS_SETTING_VER; + status = NvAPI_DRS_GetSetting(hSession, hProfile, PREFERRED_PSTATE_ID, &drsSetting); + if (status == NVAPI_SETTING_NOT_FOUND) + { //only override if the user hasn't specifically set this setting + // (4) Specify that we want the VSYNC disabled setting + // first we fill the NVDRS_SETTING struct, then we call the function + drsSetting.version = NVDRS_SETTING_VER; + drsSetting.settingId = PREFERRED_PSTATE_ID; + drsSetting.settingType = NVDRS_DWORD_TYPE; + drsSetting.u32CurrentValue = PREFERRED_PSTATE_PREFER_MAX; + status = NvAPI_DRS_SetSetting(hSession, hProfile, &drsSetting); + if (status != NVAPI_OK) + { + nvapi_error(status); + return; + } + + // (5) Now we apply (or save) our changes to the system + status = NvAPI_DRS_SaveSettings(hSession); + if (status != NVAPI_OK) + { + nvapi_error(status); + return; + } + } + else if (status != NVAPI_OK) + { + nvapi_error(status); + return; + } +} +#endif + //#define DEBUGGING_SEH_FILTER 1 #if DEBUGGING_SEH_FILTER # define WINMAIN DebuggingWinMain @@ -187,10 +220,10 @@ int APIENTRY WINMAIN(HINSTANCE hInstance, gIconResource = MAKEINTRESOURCE(IDI_LL_ICON); LLAppViewerWin32* viewer_app_ptr = new LLAppViewerWin32(lpCmdLine); - - LLWinDebug::initExceptionHandler(viewer_windows_exception_handler); +#if !defined(USE_CRASHPAD) viewer_app_ptr->setErrorHandler(LLAppViewer::handleViewerCrash); +#endif // Set a debug info flag to indicate if multiple instances are running. bool found_other_instance = !create_app_mutex(); @@ -199,19 +232,42 @@ int APIENTRY WINMAIN(HINSTANCE hInstance, bool ok = viewer_app_ptr->init(); if(!ok) { - llwarns << "Application init failed." << llendl; + LL_WARNS() << "Application init failed." << LL_ENDL; return -1; } +#ifdef USE_NVAPI + NvAPI_Status status; + + // Initialize NVAPI + status = NvAPI_Initialize(); + NvDRSSessionHandle hSession = 0; + + if (status == NVAPI_OK) + { + // Create the session handle to access driver settings + status = NvAPI_DRS_CreateSession(&hSession); + if (status != NVAPI_OK) + { + nvapi_error(status); + } + else + { + //override driver setting as needed + ll_nvapi_init(hSession); + } + } +#endif + // Have to wait until after logging is initialized to display LFH info if (num_heaps > 0) { - llinfos << "Attempted to enable LFH for " << num_heaps << " heaps." << llendl; + LL_INFOS() << "Attempted to enable LFH for " << num_heaps << " heaps." << LL_ENDL; for(S32 i = 0; i < num_heaps; i++) { if (heap_enable_lfh_error[i]) { - llinfos << " Failed to enable LFH for heap: " << i << " Error: " << heap_enable_lfh_error[i] << llendl; + LL_INFOS() << " Failed to enable LFH for heap: " << i << " Error: " << heap_enable_lfh_error[i] << LL_ENDL; } } } @@ -230,14 +286,14 @@ int APIENTRY WINMAIN(HINSTANCE hInstance, // app cleanup if there was a problem. // #if WINDOWS_CRT_MEM_CHECKS - llinfos << "CRT Checking memory:" << llendflush; + LL_INFOS() << "CRT Checking memory:" << LL_ENDL; if (!_CrtCheckMemory()) { - llwarns << "_CrtCheckMemory() failed at prior to cleanup!" << llendflush; + LL_WARNS() << "_CrtCheckMemory() failed at prior to cleanup!" << LL_ENDL; } else { - llinfos << " No corruption detected." << llendflush; + LL_INFOS() << " No corruption detected." << LL_ENDL; } #endif @@ -246,20 +302,20 @@ int APIENTRY WINMAIN(HINSTANCE hInstance, viewer_app_ptr->cleanup(); #if WINDOWS_CRT_MEM_CHECKS - llinfos << "CRT Checking memory:" << llendflush; + LL_INFOS() << "CRT Checking memory:" << LL_ENDL; if (!_CrtCheckMemory()) { - llwarns << "_CrtCheckMemory() failed after cleanup!" << llendflush; + LL_WARNS() << "_CrtCheckMemory() failed after cleanup!" << LL_ENDL; } else { - llinfos << " No corruption detected." << llendflush; + LL_INFOS() << " No corruption detected." << LL_ENDL; } #endif } delete viewer_app_ptr; - viewer_app_ptr = NULL; + viewer_app_ptr = nullptr; //start updater if(LLAppViewer::sUpdaterInfo) @@ -270,6 +326,15 @@ int APIENTRY WINMAIN(HINSTANCE hInstance, LLAppViewer::sUpdaterInfo = NULL ; } +#ifdef USE_NVAPI + // (NVAPI) (6) We clean up. This is analogous to doing a free() + if (hSession) + { + NvAPI_DRS_DestroySession(hSession); + hSession = 0; + } +#endif + return 0; } @@ -296,102 +361,48 @@ int APIENTRY WinMain(HINSTANCE hInstance, void LLAppViewerWin32::disableWinErrorReporting() { - const char win_xp_string[] = "Microsoft Windows XP"; - BOOL is_win_xp = ( getOSInfo().getOSString().substr(0, strlen(win_xp_string) ) == win_xp_string ); /* Flawfinder: ignore*/ - if( is_win_xp ) - { - // Note: we need to use run-time dynamic linking, because load-time dynamic linking will fail - // on systems that don't have the library installed (all non-Windows XP systems) - HINSTANCE fault_rep_dll_handle = LoadLibrary(L"faultrep.dll"); /* Flawfinder: ignore */ - if( fault_rep_dll_handle ) - { - pfn_ADDEREXCLUDEDAPPLICATIONA pAddERExcludedApplicationA = (pfn_ADDEREXCLUDEDAPPLICATIONA) GetProcAddress(fault_rep_dll_handle, "AddERExcludedApplicationA"); - if( pAddERExcludedApplicationA ) - { + std::string const& executable_name = gDirUtilp->getExecutableFilename(); - // Strip the path off the name - const char* executable_name = gDirUtilp->getExecutableFilename().c_str(); - - if( 0 == pAddERExcludedApplicationA( executable_name ) ) - { - U32 error_code = GetLastError(); - llinfos << "AddERExcludedApplication() failed with error code " << error_code << llendl; - } - else - { - llinfos << "AddERExcludedApplication() success for " << executable_name << llendl; - } - } - FreeLibrary( fault_rep_dll_handle ); - } + if( S_OK == WerAddExcludedApplication( utf8str_to_utf16str(executable_name).c_str(), FALSE ) ) + { + LL_INFOS() << "WerAddExcludedApplication() succeeded for " << executable_name << LL_ENDL; + } + else + { + LL_INFOS() << "WerAddExcludedApplication() failed for " << executable_name << LL_ENDL; } } const S32 MAX_CONSOLE_LINES = 500; -void create_console() +static bool create_console() { - int h_con_handle; - long l_std_handle; CONSOLE_SCREEN_BUFFER_INFO coninfo; - FILE *fp; // allocate a console for this app - AllocConsole(); + const bool isConsoleAllocated = AllocConsole(); // set the screen buffer to be big enough to let us scroll text GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo); coninfo.dwSize.Y = MAX_CONSOLE_LINES; SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coninfo.dwSize); - // redirect unbuffered STDOUT to the console - l_std_handle = (long)GetStdHandle(STD_OUTPUT_HANDLE); - h_con_handle = _open_osfhandle(l_std_handle, _O_TEXT); - if (h_con_handle == -1) - { - llwarns << "create_console() failed to open stdout handle" << llendl; - } - else - { - fp = _fdopen( h_con_handle, "w" ); - *stdout = *fp; - setvbuf( stdout, NULL, _IONBF, 0 ); - } + // Redirect the CRT standard input, output, and error handles to the console + freopen("CONIN$", "r", stdin); + freopen("CONOUT$", "w", stdout); + freopen("CONOUT$", "w", stderr); - // redirect unbuffered STDIN to the console - l_std_handle = (long)GetStdHandle(STD_INPUT_HANDLE); - h_con_handle = _open_osfhandle(l_std_handle, _O_TEXT); - if (h_con_handle == -1) - { - llwarns << "create_console() failed to open stdin handle" << llendl; - } - else - { - fp = _fdopen( h_con_handle, "r" ); - *stdin = *fp; - setvbuf( stdin, NULL, _IONBF, 0 ); - } + setvbuf( stdin, nullptr, _IONBF, 0 ); + setvbuf( stdout, nullptr, _IONBF, 0 ); + setvbuf( stderr, nullptr, _IONBF, 0 ); - // redirect unbuffered STDERR to the console - l_std_handle = (long)GetStdHandle(STD_ERROR_HANDLE); - h_con_handle = _open_osfhandle(l_std_handle, _O_TEXT); - if (h_con_handle == -1) - { - llwarns << "create_console() failed to open stderr handle" << llendl; - } - else - { - fp = _fdopen( h_con_handle, "w" ); - *stderr = *fp; - setvbuf( stderr, NULL, _IOFBF, 1024 ); //Assigning a buffer improves speed a LOT, esp on vista/win7 - //_IOLBF is borked. - } + return isConsoleAllocated; } - LLAppViewerWin32::LLAppViewerWin32(const char* cmd_line) : - mCmdLine(cmd_line) + mCmdLine(cmd_line), + mIsConsoleAllocated(false) { } @@ -403,14 +414,20 @@ bool LLAppViewerWin32::init() { // Platform specific initialization. - // Turn off Windows XP Error Reporting + // Turn off Windows Error Reporting // (Don't send our data to Microsoft--at least until we are Logo approved and have a way // of getting the data back from them.) // - llinfos << "Turning off Windows error reporting." << llendl; + // LL_INFOS() << "Turning off Windows error reporting." << LL_ENDL; disableWinErrorReporting(); - return LLAppViewer::init(); +#ifndef LL_RELEASE_FOR_DOWNLOAD + LLWinDebug::instance().init(); +#endif + + bool success = LLAppViewer::init(); + + return success; } bool LLAppViewerWin32::cleanup() @@ -419,24 +436,24 @@ bool LLAppViewerWin32::cleanup() gDXHardware.cleanup(); + if (mIsConsoleAllocated) + { + FreeConsole(); + mIsConsoleAllocated = false; + } + return result; } -bool LLAppViewerWin32::initLogging() +void LLAppViewerWin32::initLoggingAndGetLastDuration() { - // Remove the crash stack log from previous executions. - // Since we've started logging a new instance of the app, we can assume - // *NOTE: This should happen before the we send a 'previous instance froze' - // crash report, but it must happen after we initialize the DirUtil. - LLWinDebug::clearCrashStacks(); - - return LLAppViewer::initLogging(); + LLAppViewer::initLoggingAndGetLastDuration(); } void LLAppViewerWin32::initConsole() { // pop up debug console - create_console(); + mIsConsoleAllocated = create_console(); return LLAppViewer::initConsole(); } @@ -470,7 +487,10 @@ bool LLAppViewerWin32::initHardwareTest() LL_DEBUGS("AppInit") << "Attempting to poll DirectX for hardware info" << LL_ENDL; gDXHardware.setWriteDebugFunc(write_debug_dx); - BOOL probe_ok = gDXHardware.getInfo(vram_only); + + S32Megabytes system_ram = gSysMemory.getPhysicalMemoryKB(); + + BOOL probe_ok = gDXHardware.getInfo(vram_only, system_ram); if (!probe_ok && gSavedSettings.getWarning("AboutDirectX9")) @@ -515,6 +535,7 @@ bool LLAppViewerWin32::initHardwareTest() if (gGLManager.mVRAM == 0) { gGLManager.mVRAM = gDXHardware.getVRAM(); + LL_WARNS("AppInit") << "gGLManager.mVRAM: " << gGLManager.mVRAM << LL_ENDL; } LL_INFOS("AppInit") << "Detected VRAM: " << gGLManager.mVRAM << LL_ENDL; @@ -530,7 +551,7 @@ bool LLAppViewerWin32::initParseCommandLine(LLCommandLineParser& clp) } // Find the system language. - FL_Locale *locale = NULL; + FL_Locale *locale = nullptr; FL_Success success = FL_FindLocale(&locale, FL_MESSAGES); if (success != 0) { @@ -552,39 +573,8 @@ bool LLAppViewerWin32::initParseCommandLine(LLCommandLineParser& clp) } bool LLAppViewerWin32::restoreErrorTrap() -{ - return LLWinDebug::checkExceptionHandler(); -} - -void LLAppViewerWin32::handleSyncCrashTrace() -{ - // do nothing -} - -void LLAppViewerWin32::handleCrashReporting(bool reportFreeze) -{ - const char* logger_name = "win_crash_logger.exe"; - std::string exe_path = gDirUtilp->getExecutableDir(); - exe_path += gDirUtilp->getDirDelimiter(); - exe_path += logger_name; - - const char* arg_str = logger_name; - - // *NOTE:Mani - win_crash_logger.exe no longer parses command line options. - if(reportFreeze) - { - // Spawn crash logger. - // NEEDS to wait until completion, otherwise log files will get smashed. - _spawnl(_P_WAIT, exe_path.c_str(), arg_str, NULL); - } - else - { - S32 cb = gCrashSettings.getS32(CRASH_BEHAVIOR_SETTING); - if(cb != CRASH_BEHAVIOR_NEVER_SEND) - { - _spawnl(_P_NOWAIT, exe_path.c_str(), arg_str, NULL); - } - } +{ + return true; } //virtual @@ -594,11 +584,11 @@ bool LLAppViewerWin32::sendURLToOtherInstance(const std::string& url) mbstowcs(window_class, sWindowClass.c_str(), 255); window_class[255] = 0; // Use the class instead of the window name. - HWND other_window = FindWindow(window_class, NULL); + HWND other_window = FindWindow(window_class, nullptr); - if (other_window != NULL) + if (other_window != nullptr) { - lldebugs << "Found other window with the name '" << getWindowTitle() << "'" << llendl; + LL_DEBUGS() << "Found other window with the name '" << getWindowTitle() << "'" << LL_ENDL; COPYDATASTRUCT cds; const S32 SLURL_MESSAGE_TYPE = 0; cds.dwData = SLURL_MESSAGE_TYPE; @@ -606,8 +596,8 @@ bool LLAppViewerWin32::sendURLToOtherInstance(const std::string& url) cds.lpData = (void*)url.c_str(); LRESULT msg_result = SendMessage(other_window, WM_COPYDATA, NULL, (LPARAM)&cds); - lldebugs << "SendMessage(WM_COPYDATA) to other window '" - << getWindowTitle() << "' returned " << msg_result << llendl; + LL_DEBUGS() << "SendMessage(WM_COPYDATA) to other window '" + << getWindowTitle() << "' returned " << msg_result << LL_ENDL; return true; } return false; @@ -622,13 +612,13 @@ std::string LLAppViewerWin32::generateSerialNumber() DWORD serial = 0; DWORD flags = 0; BOOL success = GetVolumeInformation( - L"C:\\", - NULL, // volume name buffer + TEXT("C:\\"), + nullptr, // volume name buffer 0, // volume name buffer size &serial, // volume serial - NULL, // max component length + nullptr, // max component length &flags, // file system flags - NULL, // file system name buffer + nullptr, // file system name buffer 0); // file system name buffer size if (success) { @@ -639,7 +629,7 @@ std::string LLAppViewerWin32::generateSerialNumber() } else { - llwarns << "GetVolumeInformation failed" << llendl; + LL_WARNS() << "GetVolumeInformation failed" << LL_ENDL; } return serial_md5; } diff --git a/indra/newview/llappviewerwin32.h b/indra/newview/llappviewerwin32.h index 13454edeec..96f8347988 100644 --- a/indra/newview/llappviewerwin32.h +++ b/indra/newview/llappviewerwin32.h @@ -46,22 +46,20 @@ class LLAppViewerWin32 : public LLAppViewer // // Main application logic // - virtual bool init(); // Override to do application initialization - virtual bool cleanup(); + bool init() override; // Override to do application initialization + bool cleanup() override; protected: - virtual bool initLogging(); // Override to clean stack_trace info. - virtual void initConsole(); // Initialize OS level debugging console. - virtual bool initHardwareTest(); // Win32 uses DX9 to test hardware. - virtual bool initParseCommandLine(LLCommandLineParser& clp); + void initLoggingAndGetLastDuration() override; // Override to clean stack_trace info. + void initConsole() override; // Initialize OS level debugging console. + bool initHardwareTest() override; // Win32 uses DX9 to test hardware. + bool initParseCommandLine(LLCommandLineParser& clp) override; - virtual bool restoreErrorTrap(); - virtual void handleCrashReporting(bool reportFreeze); - virtual void handleSyncCrashTrace(); + bool restoreErrorTrap() override; - virtual bool sendURLToOtherInstance(const std::string& url); + bool sendURLToOtherInstance(const std::string& url) override; - std::string generateSerialNumber(); + std::string generateSerialNumber() override; static const std::string sWindowClass; @@ -69,6 +67,7 @@ class LLAppViewerWin32 : public LLAppViewer void disableWinErrorReporting(); std::string mCmdLine; + bool mIsConsoleAllocated; }; #endif // LL_LLAPPVIEWERWIN32_H diff --git a/indra/newview/llassetuploadqueue.cpp b/indra/newview/llassetuploadqueue.cpp index f0d0fa761a..67c7fa55c0 100644 --- a/indra/newview/llassetuploadqueue.cpp +++ b/indra/newview/llassetuploadqueue.cpp @@ -47,7 +47,7 @@ class LLAssetUploadChainResponder : public LLUpdateTaskInventoryResponder LLAssetUploadChainResponder(const LLSD& post_data, const std::string& file_name, const LLUUID& queue_id, - char* data, + U8* data, U32 data_size, std::string script_name, LLAssetUploadQueueSupplier *supplier) : @@ -75,10 +75,10 @@ class LLAssetUploadChainResponder : public LLUpdateTaskInventoryResponder delete mData; } - /*virtual*/ void error(U32 statusNum, const std::string& reason) + /*virtual*/ void httpFailure(void) { - llwarns << "Error: " << reason << llendl; - LLUpdateTaskInventoryResponder::error(statusNum, reason); + LL_WARNS() << "Error: " << mReason << LL_ENDL; + LLUpdateTaskInventoryResponder::httpFailure(); LLAssetUploadQueue *queue = mSupplier->get(); if (queue) { @@ -86,15 +86,15 @@ class LLAssetUploadChainResponder : public LLUpdateTaskInventoryResponder } } - /*virtual*/ void result(const LLSD& content) + /*virtual*/ void httpSuccess(void) { - LLUpdateTaskInventoryResponder::result(content); + LLUpdateTaskInventoryResponder::httpSuccess(); LLAssetUploadQueue *queue = mSupplier->get(); if (queue) { // Responder is reused across 2 phase upload, // so only start next upload after 2nd phase complete. - std::string state = content["state"]; + std::string state = mContent["state"]; if(state == "complete") { queue->request(&mSupplier); @@ -107,7 +107,7 @@ class LLAssetUploadChainResponder : public LLUpdateTaskInventoryResponder std::string uploader = content["uploader"]; mSupplier->log(std::string("Compiling " + mScriptName).c_str()); - llinfos << "Compiling " << llendl; + LL_INFOS() << "Compiling " << LL_ENDL; // postRaw takes ownership of mData and will delete it. LLHTTPClient::postRaw(uploader, mData, mDataSize, this); @@ -121,7 +121,7 @@ class LLAssetUploadChainResponder : public LLUpdateTaskInventoryResponder if (content["compiled"]) { mSupplier->log("Compilation succeeded"); - llinfos << "Compiled!" << llendl; + LL_INFOS() << "Compiled!" << LL_ENDL; } else { @@ -129,8 +129,10 @@ class LLAssetUploadChainResponder : public LLUpdateTaskInventoryResponder for(LLSD::array_const_iterator line = compile_errors.beginArray(); line < compile_errors.endArray(); line++) { - mSupplier->log(line->asString()); - llinfos << content["errors"] << llendl; + std::string str = line->asString(); + str.erase(std::remove(str.begin(), str.end(), '\n'), str.end()); + mSupplier->log(str); + LL_INFOS() << content["errors"] << LL_ENDL; } } LLUpdateTaskInventoryResponder::uploadComplete(content); @@ -139,7 +141,7 @@ class LLAssetUploadChainResponder : public LLUpdateTaskInventoryResponder /*virtual*/ char const* getName(void) const { return "LLAssetUploadChainResponder"; } LLAssetUploadQueueSupplier *mSupplier; - char* mData; + U8* mData; U32 mDataSize; std::string mScriptName; }; @@ -169,6 +171,7 @@ void LLAssetUploadQueue::request(LLAssetUploadQueueSupplier** supplier) body["item_id"] = data.mItemId; body["is_script_running"] = data.mIsRunning; body["target"] = data.mIsTargetMono? "mono" : "lsl2"; + body["experience"] = data.mExperienceId; std::string url = ""; LLViewerObject* object = gObjectList.findObject(data.mTaskId); @@ -190,9 +193,10 @@ void LLAssetUploadQueue::queue(const std::string& filename, BOOL is_running, BOOL is_target_mono, const LLUUID& queue_id, - char* script_data, + U8* script_data, U32 data_size, - std::string script_name) + std::string script_name, + const LLUUID& experience_id) { UploadData data; data.mTaskId = task_id; @@ -204,6 +208,7 @@ void LLAssetUploadQueue::queue(const std::string& filename, data.mData = script_data; data.mDataSize = data_size; data.mScriptName = script_name; + data.mExperienceId = experience_id; mQueue.push_back(data); diff --git a/indra/newview/llassetuploadqueue.h b/indra/newview/llassetuploadqueue.h index eaee9f424e..bc6c11cdab 100644 --- a/indra/newview/llassetuploadqueue.h +++ b/indra/newview/llassetuploadqueue.h @@ -54,9 +54,10 @@ class LLAssetUploadQueue BOOL is_running, BOOL is_target_mono, const LLUUID& queue_id, - char* data, + U8* data, U32 data_size, - std::string script_name); + std::string script_name, + const LLUUID& experience_id); bool isEmpty() const {return mQueue.empty();} @@ -72,9 +73,10 @@ class LLAssetUploadQueue BOOL mIsRunning; BOOL mIsTargetMono; LLUUID mQueueId; - char* mData; + U8* mData; U32 mDataSize; std::string mScriptName; + LLUUID mExperienceId; }; // Ownership of mSupplier passed to currently waiting responder diff --git a/indra/newview/llassetuploadresponders.cpp b/indra/newview/llassetuploadresponders.cpp index 004152f463..b50d0202dc 100644 --- a/indra/newview/llassetuploadresponders.cpp +++ b/indra/newview/llassetuploadresponders.cpp @@ -35,8 +35,10 @@ // viewer includes #include "llagent.h" +#include "llagentbenefits.h" #include "llcompilequeue.h" #include "llfloaterbuycurrency.h" +#include "statemachine/aifilepicker.h" #include "llinventorydefines.h" #include "llinventoryobserver.h" #include "llinventorypanel.h" @@ -58,7 +60,6 @@ // library includes #include "lldir.h" -#include "lleconomy.h" #include "llfocusmgr.h" #include "llnotificationsutil.h" #include "llscrolllistctrl.h" @@ -66,8 +67,6 @@ #include "llsdutil.h" #include "llvfs.h" -#include "statemachine/aifilepicker.h" - // When uploading multiple files, don't display any of them when uploading more than this number. static const S32 FILE_COUNT_DISPLAY_THRESHOLD = 5; @@ -138,7 +137,7 @@ void on_new_single_inventory_upload_complete( inventory_item_flags = (U32) server_response["inventory_flags"].asInteger(); if (inventory_item_flags != 0) { - llinfos << "inventory_item_flags " << inventory_item_flags << llendl; + LL_INFOS() << "inventory_item_flags " << inventory_item_flags << LL_ENDL; } } S32 creation_date_now = time_corrected(); @@ -180,7 +179,7 @@ void on_new_single_inventory_upload_complete( } else { - llwarns << "Can't find a folder to put it in" << llendl; + LL_WARNS() << "Can't find a folder to put it in" << LL_ENDL; } // remove the "Uploading..." message @@ -190,13 +189,14 @@ void on_new_single_inventory_upload_complete( LLAssetUploadResponder::LLAssetUploadResponder(const LLSD &post_data, const LLUUID& vfile_id, LLAssetType::EType asset_type) -: mPostData(post_data), - mVFileID(vfile_id), - mAssetType(asset_type) +: + mPostData(post_data), + mVFileID(vfile_id), + mAssetType(asset_type) { if (!gVFS->getExists(vfile_id, asset_type)) { - llwarns << "LLAssetUploadResponder called with nonexistant vfile_id" << llendl; + LL_WARNS() << "LLAssetUploadResponder called with nonexistant vfile_id" << LL_ENDL; mVFileID.setNull(); mAssetType = LLAssetType::AT_NONE; return; @@ -207,9 +207,10 @@ LLAssetUploadResponder::LLAssetUploadResponder( const LLSD &post_data, const std::string& file_name, LLAssetType::EType asset_type) -: mPostData(post_data), - mFileName(file_name), - mAssetType(asset_type) +: + mPostData(post_data), + mFileName(file_name), + mAssetType(asset_type) { } @@ -222,13 +223,34 @@ LLAssetUploadResponder::~LLAssetUploadResponder() } } +void on_failure(const LLAssetType::EType& mAssetType, const LLSD& mPostData, const LLSD& args) +{ + switch (mAssetType) + { + case LLAssetType::AT_NOTECARD: + { + if (LLPreviewNotecard* nc = (LLPreviewNotecard*)LLPreview::find(mPostData["item_id"])) + nc->setEnabled(true); + break; + } + case LLAssetType::AT_SCRIPT: + case LLAssetType::AT_LSL_TEXT: + case LLAssetType::AT_LSL_BYTECODE: + { + if (LLPreviewLSL* lsl = (LLPreviewLSL*)LLPreview::find(mPostData["item_id"])) + lsl->callbackLSLCompileFailed(LLSD().with(0, "Upload Failure:").with(1, args["REASON"])); + break; + } + default: break; + } +} // virtual -void LLAssetUploadResponder::error(U32 statusNum, const std::string& reason) +void LLAssetUploadResponder::httpFailure() { - llinfos << "LLAssetUploadResponder::error " << statusNum - << " reason: " << reason << llendl; + LL_INFOS() << "LLAssetUploadResponder::error " << mStatus + << " reason: " << mReason << LL_ENDL; LLSD args; - switch(statusNum) + switch(mStatus) { case 400: args["FILE"] = (mFileName.empty() ? mVFileID.asString() : mFileName); @@ -244,15 +266,22 @@ void LLAssetUploadResponder::error(U32 statusNum, const std::string& reason) LLNotificationsUtil::add("CannotUploadReason", args); break; } + on_failure(mAssetType, mPostData, args); LLUploadDialog::modalUploadFinished(); } //virtual -void LLAssetUploadResponder::result(const LLSD& content) +void LLAssetUploadResponder::httpSuccess() { - lldebugs << "LLAssetUploadResponder::result from capabilities" << llendl; + const LLSD& content = getContent(); + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR_OTHER, "Malformed response contents", content); + return; + } + LL_DEBUGS() << "LLAssetUploadResponder::result from capabilities" << LL_ENDL; - std::string state = content["state"]; + const std::string& state = content["state"].asString(); if (state == "upload") { @@ -264,7 +293,7 @@ void LLAssetUploadResponder::result(const LLSD& content) if (mFileName.empty()) { // rename the file in the VFS to the actual asset id - // llinfos << "Changing uploaded asset UUID to " << content["new_asset"].asUUID() << llendl; + // LL_INFOS() << "Changing uploaded asset UUID to " << content["new_asset"].asUUID() << LL_ENDL; gVFS->renameFile(mVFileID, mAssetType, content["new_asset"].asUUID(), mAssetType); } uploadComplete(content); @@ -277,7 +306,7 @@ void LLAssetUploadResponder::result(const LLSD& content) void LLAssetUploadResponder::uploadUpload(const LLSD& content) { - std::string uploader = content["uploader"]; + const std::string& uploader = content["uploader"].asString(); if (mFileName.empty()) { LLHTTPClient::postFile(uploader, mVFileID, mAssetType, this); @@ -293,11 +322,15 @@ void LLAssetUploadResponder::uploadFailure(const LLSD& content) // remove the "Uploading..." message LLUploadDialog::modalUploadFinished(); - std::string reason = content["state"]; + const std::string& reason = content["state"].asString(); // deal with L$ errors if (reason == "insufficient funds") { - S32 price = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(); + S32 price; + if (content.has("upload_price")) + price = content["upload_price"]; + else + LLAgentBenefitsMgr::current().findUploadCost(mAssetType, price); LLFloaterBuyCurrency::buyCurrency("Uploading costs", price); } else @@ -306,6 +339,7 @@ void LLAssetUploadResponder::uploadFailure(const LLSD& content) args["FILE"] = (mFileName.empty() ? mVFileID.asString() : mFileName); args["REASON"] = content["message"].asString(); LLNotificationsUtil::add("CannotUploadReason", args); + on_failure(mAssetType, mPostData, args); } } @@ -316,10 +350,8 @@ void LLAssetUploadResponder::uploadComplete(const LLSD& content) LLNewAgentInventoryResponder::LLNewAgentInventoryResponder( const LLSD& post_data, const LLUUID& vfile_id, - LLAssetType::EType asset_type, - void (*callback)(bool, void*), - void* user_data) - : LLAssetUploadResponder(post_data, vfile_id, asset_type), mCallBack(callback), mUserData(user_data) + LLAssetType::EType asset_type) + : LLAssetUploadResponder(post_data, vfile_id, asset_type) { } @@ -327,18 +359,14 @@ LLNewAgentInventoryResponder::LLNewAgentInventoryResponder( const LLSD& post_data, const std::string& file_name, LLAssetType::EType asset_type) - : LLAssetUploadResponder(post_data, file_name, asset_type), mCallBack(NULL), mUserData(NULL) + : LLAssetUploadResponder(post_data, file_name, asset_type) { } // virtual -void LLNewAgentInventoryResponder::error(U32 statusNum, const std::string& reason) +void LLNewAgentInventoryResponder::httpFailure() { - if (mCallBack) - { - (*mCallBack)(false, mUserData); - } - LLAssetUploadResponder::error(statusNum, reason); + LLAssetUploadResponder::httpFailure(); //LLImportColladaAssetCache::getInstance()->assetUploaded(mVFileID, LLUUID(), FALSE); } @@ -346,10 +374,6 @@ void LLNewAgentInventoryResponder::error(U32 statusNum, const std::string& reaso //virtual void LLNewAgentInventoryResponder::uploadFailure(const LLSD& content) { - if (mCallBack) - { - (*mCallBack)(false, mUserData); - } LLAssetUploadResponder::uploadFailure(content); //LLImportColladaAssetCache::getInstance()->assetUploaded(mVFileID, content["new_asset"], FALSE); @@ -358,16 +382,11 @@ void LLNewAgentInventoryResponder::uploadFailure(const LLSD& content) //virtual void LLNewAgentInventoryResponder::uploadComplete(const LLSD& content) { - lldebugs << "LLNewAgentInventoryResponder::result from capabilities" << llendl; - - if (mCallBack) - { - (*mCallBack)(true, mUserData); - } + LL_DEBUGS() << "LLNewAgentInventoryResponder::result from capabilities" << LL_ENDL; //std::ostringstream llsdxml; //LLSDSerialize::toXML(content, llsdxml); - //llinfos << "upload complete content:\n " << llsdxml.str() << llendl; + //LL_INFOS() << "upload complete content:\n " << llsdxml.str() << LL_ENDL; LLAssetType::EType asset_type = LLAssetType::lookup(mPostData["asset_type"].asString()); LLInventoryType::EType inventory_type = LLInventoryType::lookup(mPostData["inventory_type"].asString()); @@ -375,17 +394,18 @@ void LLNewAgentInventoryResponder::uploadComplete(const LLSD& content) // Update L$ and ownership credit information // since it probably changed on the server - if (asset_type == LLAssetType::AT_TEXTURE || + if (content.has("upload_price")) + expected_upload_cost = content["upload_price"]; + else if (asset_type == LLAssetType::AT_TEXTURE || asset_type == LLAssetType::AT_SOUND || asset_type == LLAssetType::AT_ANIMATION || asset_type == LLAssetType::AT_MESH) { - expected_upload_cost = - LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(); + LLAgentBenefitsMgr::current().findUploadCost(asset_type, expected_upload_cost); } - llinfos << "Adding " << content["new_inventory_item"].asUUID() << " " - << content["new_asset"].asUUID() << " to inventory." << llendl; + LL_INFOS() << "Adding " << content["new_inventory_item"].asUUID() << " " + << content["new_asset"].asUUID() << " to inventory." << LL_ENDL; on_new_single_inventory_upload_complete( asset_type, inventory_type, @@ -456,57 +476,6 @@ void LLNewAgentInventoryResponder::uploadComplete(const LLSD& content) */ } -LLSendTexLayerResponder::LLSendTexLayerResponder(const LLSD& post_data, - const LLUUID& vfile_id, - LLAssetType::EType asset_type, - LLBakedUploadData * baked_upload_data) : - LLAssetUploadResponder(post_data, vfile_id, asset_type), - mBakedUploadData(baked_upload_data) -{ -} - -LLSendTexLayerResponder::~LLSendTexLayerResponder() -{ - // mBakedUploadData is normally deleted by calls to LLViewerTexLayerSetBuffer::onTextureUploadComplete() below - if (mBakedUploadData) - { // ...but delete it in the case where uploadComplete() is never called - delete mBakedUploadData; - mBakedUploadData = NULL; - } -} - - -// Baked texture upload completed -void LLSendTexLayerResponder::uploadComplete(const LLSD& content) -{ - LLUUID item_id = mPostData["item_id"]; - - std::string result = content["state"]; - LLUUID new_id = content["new_asset"]; - - llinfos << "result: " << result << " new_id: " << new_id << llendl; - if (result == "complete" - && mBakedUploadData != NULL) - { // Invoke - LLViewerTexLayerSetBuffer::onTextureUploadComplete(new_id, (void*) mBakedUploadData, 0, LL_EXSTAT_NONE); - mBakedUploadData = NULL; // deleted in onTextureUploadComplete() - } - else - { // Invoke the original callback with an error result - LLViewerTexLayerSetBuffer::onTextureUploadComplete(new_id, (void*) mBakedUploadData, -1, LL_EXSTAT_NONE); - mBakedUploadData = NULL; // deleted in onTextureUploadComplete() - } -} - -void LLSendTexLayerResponder::error(U32 statusNum, const std::string& reason) -{ - llinfos << "status: " << statusNum << " reason: " << reason << llendl; - - // Invoke the original callback with an error result - LLViewerTexLayerSetBuffer::onTextureUploadComplete(LLUUID(), (void*) mBakedUploadData, -1, LL_EXSTAT_NONE); - mBakedUploadData = NULL; // deleted in onTextureUploadComplete() -} - LLUpdateAgentInventoryResponder::LLUpdateAgentInventoryResponder( const LLSD& post_data, const LLUUID& vfile_id, @@ -526,14 +495,14 @@ LLUpdateAgentInventoryResponder::LLUpdateAgentInventoryResponder( //virtual void LLUpdateAgentInventoryResponder::uploadComplete(const LLSD& content) { - llinfos << "LLUpdateAgentInventoryResponder::result from capabilities" << llendl; + LL_INFOS() << "LLUpdateAgentInventoryResponder::result from capabilities" << LL_ENDL; LLUUID item_id = mPostData["item_id"]; LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(item_id); if(!item) { - llwarns << "Inventory item for " << mVFileID - << " is no longer in agent inventory." << llendl; + LL_WARNS() << "Inventory item for " << mVFileID + << " is no longer in agent inventory." << LL_ENDL; return; } @@ -543,8 +512,8 @@ void LLUpdateAgentInventoryResponder::uploadComplete(const LLSD& content) gInventory.updateItem(new_item); gInventory.notifyObservers(); - llinfos << "Inventory item " << item->getName() << " saved into " - << content["new_asset"].asString() << llendl; + LL_INFOS() << "Inventory item " << item->getName() << " saved into " + << content["new_asset"].asString() << LL_ENDL; LLInventoryType::EType inventory_type = new_item->getInventoryType(); switch(inventory_type) @@ -605,6 +574,7 @@ void LLUpdateAgentInventoryResponder::uploadComplete(const LLSD& content) { previewp->onUpdateSucceeded(); } + break; } case LLInventoryType::IT_WEARABLE: @@ -639,7 +609,7 @@ LLUpdateTaskInventoryResponder::LLUpdateTaskInventoryResponder(const LLSD& post_ //virtual void LLUpdateTaskInventoryResponder::uploadComplete(const LLSD& content) { - llinfos << "LLUpdateTaskInventoryResponder::result from capabilities" << llendl; + LL_INFOS() << "LLUpdateTaskInventoryResponder::result from capabilities" << LL_ENDL; LLUUID item_id = mPostData["item_id"]; LLUUID task_id = mPostData["task_id"]; @@ -650,8 +620,7 @@ void LLUpdateTaskInventoryResponder::uploadComplete(const LLSD& content) case LLAssetType::AT_NOTECARD: { // Update the UI with the new asset. - LLPreviewNotecard* nc; - nc = (LLPreviewNotecard*)LLPreview::find(item_id); + LLPreviewNotecard* nc = (LLPreviewNotecard*)LLPreview::find(item_id); if (nc) { // *HACK: we have to delete the asset in the VFS so @@ -674,8 +643,7 @@ void LLUpdateTaskInventoryResponder::uploadComplete(const LLSD& content) { if (mQueueId.notNull()) { - LLFloaterCompileQueue* queue = - (LLFloaterCompileQueue*) LLFloaterScriptQueue::findInstance(mQueueId); + LLFloaterCompileQueue* queue = (LLFloaterCompileQueue*) LLFloaterScriptQueue::findInstance(mQueueId); if (NULL != queue) { queue->removeItemByItemID(item_id); @@ -722,9 +690,9 @@ class LLNewAgentInventoryVariablePriceResponder::Impl { if (!gVFS->getExists(vfile_id, asset_type)) { - llwarns + LL_WARNS() << "LLAssetUploadResponder called with nonexistant " - << "vfile_id " << vfile_id << llendl; + << "vfile_id " << vfile_id << LL_ENDL; mVFileID.setNull(); mAssetType = LLAssetType::AT_NONE; } @@ -1020,19 +988,14 @@ LLNewAgentInventoryVariablePriceResponder::~LLNewAgentInventoryVariablePriceResp delete mImpl; } -void LLNewAgentInventoryVariablePriceResponder::errorWithContent( - U32 statusNum, - const std::string& reason, - const LLSD& content) +void LLNewAgentInventoryVariablePriceResponder::httpFailure() { - lldebugs - << "LLNewAgentInventoryVariablePrice::error " << statusNum - << " reason: " << reason << llendl; + const LLSD& content = getContent(); + LL_WARNS("Upload") << dumpResponse() << LL_ENDL; - if ( content.has("error") ) - { static const std::string _ERROR = "error"; - + if ( content.has(_ERROR) ) + { mImpl->onTransportError(content[_ERROR]); } else @@ -1041,8 +1004,14 @@ void LLNewAgentInventoryVariablePriceResponder::errorWithContent( } } -void LLNewAgentInventoryVariablePriceResponder::result(const LLSD& content) +void LLNewAgentInventoryVariablePriceResponder::httpSuccess() { + const LLSD& content = getContent(); + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR_OTHER, "Malformed response contents", content); + return; + } // Parse out application level errors and the appropriate // responses for them static const std::string _ERROR = "error"; @@ -1056,8 +1025,9 @@ void LLNewAgentInventoryVariablePriceResponder::result(const LLSD& content) static const std::string _RSVP = "rsvp"; // Check for application level errors - if (content.has(_ERROR)) + if ( content.has(_ERROR) ) { + LL_WARNS("Upload") << dumpResponse() << LL_ENDL; onApplicationLevelError(content[_ERROR]); return; } @@ -1071,7 +1041,7 @@ void LLNewAgentInventoryVariablePriceResponder::result(const LLSD& content) if (mImpl->getFilename().empty()) { // rename the file in the VFS to the actual asset id - // llinfos << "Changing uploaded asset UUID to " << content["new_asset"].asUUID() << llendl; + // LL_INFOS() << "Changing uploaded asset UUID to " << content["new_asset"].asUUID() << LL_ENDL; gVFS->renameFile( mImpl->getVFileID(), asset_type, @@ -1101,6 +1071,7 @@ void LLNewAgentInventoryVariablePriceResponder::result(const LLSD& content) } else { + LL_WARNS("Upload") << dumpResponse() << LL_ENDL; onApplicationLevelError(""); } } @@ -1173,3 +1144,4 @@ void LLNewAgentInventoryVariablePriceResponder::showConfirmationDialog( } } + diff --git a/indra/newview/llassetuploadresponders.h b/indra/newview/llassetuploadresponders.h index bdcf413904..21787786fe 100644 --- a/indra/newview/llassetuploadresponders.h +++ b/indra/newview/llassetuploadresponders.h @@ -36,10 +36,6 @@ #include "llhttpclient.h" #include "llinventory.h" -class AIHTTPTimeoutPolicy; -extern AIHTTPTimeoutPolicy assetUploadResponder_timeout; -extern AIHTTPTimeoutPolicy newAgentInventoryVariablePriceResponder_timeout; - void on_new_single_inventory_upload_complete(LLAssetType::EType asset_type, LLInventoryType::EType inventory_type, const std::string inventory_type_string, @@ -53,6 +49,8 @@ void on_new_single_inventory_upload_complete(LLAssetType::EType asset_type, // via capabilities class LLAssetUploadResponder : public LLHTTPClient::ResponderWithResult { +protected: + LOG_CLASS(LLAssetUploadResponder); public: LLAssetUploadResponder(const LLSD& post_data, const LLUUID& vfile_id, @@ -61,10 +59,12 @@ class LLAssetUploadResponder : public LLHTTPClient::ResponderWithResult const std::string& file_name, LLAssetType::EType asset_type); ~LLAssetUploadResponder(); - /*virtual*/ void error(U32 statusNum, const std::string& reason); - /*virtual*/ void result(const LLSD& content); - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return assetUploadResponder_timeout; } +protected: + virtual void httpFailure(); + virtual void httpSuccess(); + +public: virtual void uploadUpload(const LLSD& content); virtual void uploadComplete(const LLSD& content); virtual void uploadFailure(const LLSD& content); @@ -76,25 +76,24 @@ class LLAssetUploadResponder : public LLHTTPClient::ResponderWithResult std::string mFileName; }; +// TODO*: Remove this once deprecated class LLNewAgentInventoryResponder : public LLAssetUploadResponder { - void (*mCallBack)(bool, void*); - void* mUserData; + LOG_CLASS(LLNewAgentInventoryResponder); public: LLNewAgentInventoryResponder( const LLSD& post_data, const LLUUID& vfile_id, - LLAssetType::EType asset_type, - void (*callback)(bool, void*) = NULL, - void* user_data = NULL); + LLAssetType::EType asset_type); LLNewAgentInventoryResponder( const LLSD& post_data, const std::string& file_name, LLAssetType::EType asset_type); - /*virtual*/ void error(U32 statusNum, const std::string& reason); virtual void uploadComplete(const LLSD& content); virtual void uploadFailure(const LLSD& content); - /*virtual*/ char const* getName(void) const { return "LLNewAgentInventoryResponder"; } + /*virtual*/ char const* getName() const { return "LLNewAgentInventoryResponder"; } +protected: + virtual void httpFailure(); }; // A base class which goes through and performs some default @@ -104,6 +103,7 @@ class LLNewAgentInventoryResponder : public LLAssetUploadResponder class LLNewAgentInventoryVariablePriceResponder : public LLHTTPClient::ResponderWithResult { + LOG_CLASS(LLNewAgentInventoryVariablePriceResponder); public: LLNewAgentInventoryVariablePriceResponder( const LLUUID& vfile_id, @@ -116,13 +116,11 @@ class LLNewAgentInventoryVariablePriceResponder : const LLSD& inventory_info); virtual ~LLNewAgentInventoryVariablePriceResponder(); - /*virtual*/ void errorWithContent( - U32 statusNum, - const std::string& reason, - const LLSD& content); - /*virtual*/ void result(const LLSD& content); - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return newAgentInventoryVariablePriceResponder_timeout; } +private: + /* virtual */ void httpFailure(); + /* virtual */ void httpSuccess(); +public: virtual void onApplicationLevelError( const LLSD& error); virtual void showConfirmationDialog( @@ -135,25 +133,6 @@ class LLNewAgentInventoryVariablePriceResponder : Impl* mImpl; }; -struct LLBakedUploadData; -class LLSendTexLayerResponder : public LLAssetUploadResponder -{ - LOG_CLASS(LLSendTexLayerResponder); -public: - LLSendTexLayerResponder(const LLSD& post_data, - const LLUUID& vfile_id, - LLAssetType::EType asset_type, - LLBakedUploadData * baked_upload_data); - - ~LLSendTexLayerResponder(); - - /*virtual*/ void uploadComplete(const LLSD& content); - /*virtual*/ void error(U32 statusNum, const std::string& reason); - /*virtual*/ char const* getName(void) const { return "LLSendTexLayerResponder"; } - - LLBakedUploadData * mBakedUploadData; -}; - class LLUpdateAgentInventoryResponder : public LLAssetUploadResponder { public: @@ -164,7 +143,7 @@ class LLUpdateAgentInventoryResponder : public LLAssetUploadResponder const std::string& file_name, LLAssetType::EType asset_type); virtual void uploadComplete(const LLSD& content); - /*virtual*/ char const* getName(void) const { return "LLUpdateAgentInventoryResponder"; } + /*virtual*/ char const* getName() const { return "LLUpdateAgentInventoryResponder"; } }; class LLUpdateTaskInventoryResponder : public LLAssetUploadResponder @@ -182,7 +161,7 @@ class LLUpdateTaskInventoryResponder : public LLAssetUploadResponder LLAssetType::EType asset_type); virtual void uploadComplete(const LLSD& content); - /*virtual*/ char const* getName(void) const { return "LLUpdateTaskInventoryResponder"; } + /*virtual*/ char const* getName() const { return "LLUpdateTaskInventoryResponder"; } private: LLUUID mQueueId; diff --git a/indra/newview/llattachmentsmgr.cpp b/indra/newview/llattachmentsmgr.cpp index c064fa5f4b..ef533de19d 100644 --- a/indra/newview/llattachmentsmgr.cpp +++ b/indra/newview/llattachmentsmgr.cpp @@ -27,18 +27,49 @@ #include "llviewerprecompiledheaders.h" #include "llattachmentsmgr.h" +#include "llvoavatarself.h" #include "llagent.h" +#include "llappearancemgr.h" #include "llinventorymodel.h" #include "lltooldraganddrop.h" // pack_permissions_slam #include "llviewerinventory.h" #include "llviewerregion.h" #include "message.h" -// [RLVa:KB] - Checked: 2010-09-13 (RLVa-1.2.1c) +// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a) #include "rlvhandler.h" #include "rlvlocks.h" // [/RLVa:KB] +#include -LLAttachmentsMgr::LLAttachmentsMgr() +const F32 COF_LINK_BATCH_TIME = 5.0F; +const F32 MAX_ATTACHMENT_REQUEST_LIFETIME = 30.0F; +const F32 MIN_RETRY_REQUEST_TIME = 5.0F; +const F32 MAX_BAD_COF_TIME = 30.0F; + +// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2015-06-24 (Catznip-3.7) +class LLRegisterAttachmentCallback : public LLRequestServerAppearanceUpdateOnDestroy +{ +public: + LLRegisterAttachmentCallback() + : LLRequestServerAppearanceUpdateOnDestroy() + { + } + + /*virtual*/ ~LLRegisterAttachmentCallback() + { + } + + /*virtual*/ void fire(const LLUUID& idItem) + { + LLAttachmentsMgr::instance().onRegisterAttachmentComplete(idItem); + } +}; +// [/SL:KB] + +LLAttachmentsMgr::LLAttachmentsMgr(): + mAttachmentRequests("attach",MIN_RETRY_REQUEST_TIME), + mDetachRequests("detach",MIN_RETRY_REQUEST_TIME) +// , mQuestionableCOFLinks("badcof",MAX_BAD_COF_TIME) { } @@ -46,20 +77,34 @@ LLAttachmentsMgr::~LLAttachmentsMgr() { } -void LLAttachmentsMgr::addAttachment(const LLUUID& item_id, - const U8 attachment_pt, +//void LLAttachmentsMgr::addAttachmentRequest(const LLUUID& item_id, +// const U8 attachment_pt, // const BOOL add) -// [RLVa:KB] - Checked: 2010-09-13 (RLVa-1.2.1c) | Added: RLVa-1.2.1c +// [RLVa:KB] - Checked: 2010-09-13 (RLVa-1.2.1) +void LLAttachmentsMgr::addAttachmentRequest(const LLUUID& item_id, + const U8 attachment_pt, const BOOL add, const BOOL fRlvForce /*=FALSE*/) // [/RLVa:KB] { + LLViewerInventoryItem *item = gInventory.getItem(item_id); + + if (mAttachmentRequests.wasRequestedRecently(item_id)) + { + LL_DEBUGS("Avatar") << "ATT not adding attachment to mPendingAttachments, recent request is already pending: " + << (item ? item->getName() : "UNKNOWN") << " id " << item_id << LL_ENDL; + return; + } + + LL_DEBUGS("Avatar") << "ATT adding attachment to mPendingAttachments " + << (item ? item->getName() : "UNKNOWN") << " id " << item_id << LL_ENDL; + AttachmentsInfo attachment; attachment.mItemID = item_id; attachment.mAttachmentPt = attachment_pt; attachment.mAdd = add; -// [RLVa:KB] - Checked: 2010-09-23 (RLVa-1.2.1d) | Modified: RLVa-1.2.1d - if ( (rlv_handler_t::isEnabled()) && (!fRlvForce) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) ) +// [RLVa:KB] - Checked: 2010-09-23 (RLVa-1.2.1) + if ( (rlv_handler_t::isEnabled()) && (!fRlvForce) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) && (gAgentWearables.areInitialAttachmentsRequested()) ) { const LLInventoryItem* pItem = gInventory.getItem(item_id); if (!pItem) @@ -78,6 +123,21 @@ void LLAttachmentsMgr::addAttachment(const LLUUID& item_id, // [/RLVa:KB] mPendingAttachments.push_back(attachment); + + mAttachmentRequests.addTime(item_id); +} + +void LLAttachmentsMgr::onAttachmentRequested(const LLUUID& item_id) +{ +// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2015-06-24 (Catznip-3.7) + if (item_id.isNull()) + return; +// [/SL:KB] + + LLViewerInventoryItem *item = gInventory.getItem(item_id); + LL_DEBUGS("Avatar") << "ATT attachment was requested " + << (item ? item->getName() : "UNKNOWN") << " id " << item_id << LL_ENDL; + mAttachmentRequests.addTime(item_id); } // static @@ -88,10 +148,55 @@ void LLAttachmentsMgr::onIdle(void *) void LLAttachmentsMgr::onIdle() { - if(!gAgent.getRegion()) + // Make sure we got a region before trying anything else + if( !gAgent.getRegion() ) + { + return; + } + + if (LLApp::isExiting()) + { + return; + } + + requestPendingAttachments(); + + linkRecentlyArrivedAttachments(); + + expireOldAttachmentRequests(); + + expireOldDetachRequests(); + +// checkInvalidCOFLinks(); + + spamStatusInfo(); +} + +void LLAttachmentsMgr::requestPendingAttachments() +{ + if (mPendingAttachments.size()) + { + requestAttachments(mPendingAttachments); + } +} + +// Send request(s) for a group of attachments. As coded, this can +// request at most 40 attachments and the rest will be +// ignored. Currently the max attachments per avatar is 38, so the 40 +// limit should not be hit in practice. +void LLAttachmentsMgr::requestAttachments(attachments_vec_t& attachment_requests) +{ + // Make sure we got a region before trying anything else + if( !gAgent.getRegion() ) + { return; + } - S32 obj_count = mPendingAttachments.size(); + // For unknown reasons, requesting many attachments at once causes + // frequent server-side failures. Here we're limiting the number + // of attachments requested per idle loop. + const S32 max_objects_per_request = 5; + S32 obj_count = llmin((S32)attachment_requests.size(),max_objects_per_request); if (obj_count == 0) { return; @@ -103,18 +208,24 @@ void LLAttachmentsMgr::onIdle() const S32 MAX_OBJECTS_TO_SEND = MAX_PACKETS_TO_SEND * OBJECTS_PER_PACKET; if( obj_count > MAX_OBJECTS_TO_SEND ) { + LL_WARNS() << "ATT Too many attachments requested: " << obj_count + << " exceeds limit of " << MAX_OBJECTS_TO_SEND << LL_ENDL; + obj_count = MAX_OBJECTS_TO_SEND; } + LL_DEBUGS("Avatar") << "ATT [RezMultipleAttachmentsFromInv] attaching multiple from attachment_requests," + " total obj_count " << obj_count << LL_ENDL; + LLUUID compound_msg_id; compound_msg_id.generate(); LLMessageSystem* msg = gMessageSystem; + // by construction above, obj_count <= attachment_requests.size(), so no + // check against attachment_requests.empty() is needed. + llassert(obj_count <= attachment_requests.size()); - S32 i = 0; - for (attachments_vec_t::const_iterator iter = mPendingAttachments.begin(); - iter != mPendingAttachments.end(); - ++iter) + for (S32 i=0; iaddBOOLFast(_PREHASH_FirstDetachAll, false ); } - const AttachmentsInfo &attachment = (*iter); + const AttachmentsInfo& attachment = attachment_requests.front(); LLViewerInventoryItem* item = gInventory.getItem(attachment.mItemID); - if (!item) + if (item) + { + LL_DEBUGS("Avatar") << "ATT requesting from attachment_requests " << item->getName() + << " " << item->getLinkedUUID() << LL_ENDL; + S32 attachment_pt = attachment.mAttachmentPt; + if (attachment.mAdd) + attachment_pt |= ATTACHMENT_ADD; + + msg->nextBlockFast(_PREHASH_ObjectData ); + msg->addUUIDFast(_PREHASH_ItemID, item->getLinkedUUID()); + msg->addUUIDFast(_PREHASH_OwnerID, item->getPermissions().getOwner()); + msg->addU8Fast(_PREHASH_AttachmentPt, attachment_pt); + pack_permissions_slam(msg, item->getFlags(), item->getPermissions()); + msg->addStringFast(_PREHASH_Name, item->getName()); + msg->addStringFast(_PREHASH_Description, item->getDescription()); + } + else { - llinfos << "Attempted to add non-existant item ID:" << attachment.mItemID << llendl; - continue; + LL_WARNS("Avatar") << "ATT Attempted to add non-existent item ID:" << attachment.mItemID << LL_ENDL; } - S32 attachment_pt = attachment.mAttachmentPt; - if (attachment.mAdd) - attachment_pt |= ATTACHMENT_ADD; - - msg->nextBlockFast(_PREHASH_ObjectData ); - msg->addUUIDFast(_PREHASH_ItemID, item->getLinkedUUID()); - msg->addUUIDFast(_PREHASH_OwnerID, item->getPermissions().getOwner()); - msg->addU8Fast(_PREHASH_AttachmentPt, attachment_pt); - pack_permissions_slam(msg, item->getFlags(), item->getPermissions()); - msg->addStringFast(_PREHASH_Name, item->getName()); - msg->addStringFast(_PREHASH_Description, item->getDescription()); if( (i+1 == obj_count) || ((OBJECTS_PER_PACKET-1) == (i % OBJECTS_PER_PACKET)) ) { // End of message chunk msg->sendReliable( gAgent.getRegion()->getHost() ); } - i++; + attachment_requests.pop_front(); } +} + +void LLAttachmentsMgr::linkRecentlyArrivedAttachments() +{ + if (mRecentlyArrivedAttachments.size()) + { + // [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2015-06-24 (Catznip-3.7) + if (!LLAppearanceMgr::instance().getAttachmentInvLinkEnable()) + { + return; + } +// [/SL:KB] + + // One or more attachments have arrived but have not yet been + // processed for COF links + if (mAttachmentRequests.empty()) + { + // Not waiting for any more. + LL_DEBUGS("Avatar") << "ATT all pending attachments have arrived after " + << mCOFLinkBatchTimer.getElapsedTimeF32() << " seconds" << LL_ENDL; + } + else if (mCOFLinkBatchTimer.getElapsedTimeF32() > COF_LINK_BATCH_TIME) + { + LL_DEBUGS("Avatar") << "ATT " << mAttachmentRequests.size() + << " pending attachments have not arrived, but wait time exceeded" << LL_ENDL; + } + else + { + return; + } + + LL_DEBUGS("Avatar") << "ATT checking COF linkability for " << mRecentlyArrivedAttachments.size() + << " recently arrived items" << LL_ENDL; + + uuid_vec_t ids_to_link; + for (auto it = mRecentlyArrivedAttachments.begin(); + it != mRecentlyArrivedAttachments.end(); ++it) + { + if (isAgentAvatarValid() && + gAgentAvatarp->isWearingAttachment(*it) && + !LLAppearanceMgr::instance().isLinkedInCOF(*it)) + { + LLUUID item_id = *it; + LLViewerInventoryItem *item = gInventory.getItem(item_id); + LL_DEBUGS("Avatar") << "ATT adding COF link for attachment " + << (item ? item->getName() : "UNKNOWN") << " " << item_id << LL_ENDL; + ids_to_link.push_back(item_id); + } + } + if (ids_to_link.size()) + { +// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2015-06-24 (Catznip-3.7) + LLPointer cb = new LLRegisterAttachmentCallback(); + for (const LLUUID& idAttach : ids_to_link) + { + if (std::find(mPendingAttachLinks.begin(), mPendingAttachLinks.end(), idAttach) == mPendingAttachLinks.end()) + { + LLAppearanceMgr::instance().addCOFItemLink(idAttach, cb); + mPendingAttachLinks.insert(idAttach); + } + } +// [/SL:KB] +// LLPointer cb = new LLRequestServerAppearanceUpdateOnDestroy(); +// for (uuid_vec_t::const_iterator uuid_it = ids_to_link.begin(); +// uuid_it != ids_to_link.end(); ++uuid_it) +// { +// LLAppearanceMgr::instance().addCOFItemLink(*uuid_it, cb); +// } + } + mRecentlyArrivedAttachments.clear(); + } +} + +// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2010-09-18 (Catznip-2.2) +bool LLAttachmentsMgr::getPendingAttachments(uuid_set_t& ids) const +{ + ids.clear(); + + // Returns the union of the LL maintained list of attachments that are waiting for link creation and our maintained list of attachments that are pending link creation + ids.insert(mRecentlyArrivedAttachments.begin(), mRecentlyArrivedAttachments.end()); + ids.insert(mPendingAttachLinks.begin(), mPendingAttachLinks.end()); + // Singu Note: "Expression: Sequence not ordered" using std::set_union + //set_union(mRecentlyArrivedAttachments.begin(), mRecentlyArrivedAttachments.end(), mPendingAttachLinks.begin(), mPendingAttachLinks.end(), std::inserter(ids, ids.begin())); + + return !ids.empty(); +} + +void LLAttachmentsMgr::clearPendingAttachmentLink(const LLUUID& idItem) +{ + mPendingAttachLinks.erase(idItem); +} + +void LLAttachmentsMgr::onRegisterAttachmentComplete(const LLUUID& idAttachLink) +{ + const LLViewerInventoryItem* pAttachLink = gInventory.getItem(idAttachLink); + if (!pAttachLink) + return; + + const LLUUID& idAttachBase = pAttachLink->getLinkedUUID(); + + // Remove the attachment from the pending list + clearPendingAttachmentLink(idAttachBase); + + // It may have been detached already in which case we should remove the COF link + if ( (isAgentAvatarValid()) && (!gAgentAvatarp->isWearingAttachment(idAttachBase)) ) + { + LLAppearanceMgr::instance().removeCOFItemLinks(idAttachBase, NULL, true); + } +} +// [/SL:KB] + +LLAttachmentsMgr::LLItemRequestTimes::LLItemRequestTimes(const std::string& op_name, F32 timeout): + mOpName(op_name), + mTimeout(timeout) +{ +} + +void LLAttachmentsMgr::LLItemRequestTimes::addTime(const LLUUID& inv_item_id) +{ + LLInventoryItem *item = gInventory.getItem(inv_item_id); + LL_DEBUGS("Avatar") << "ATT " << mOpName << " adding request time " << (item ? item->getName() : "UNKNOWN") << " " << inv_item_id << LL_ENDL; + LLTimer current_time; + (*this)[inv_item_id] = current_time; +} + +void LLAttachmentsMgr::LLItemRequestTimes::removeTime(const LLUUID& inv_item_id) +{ + LLInventoryItem *item = gInventory.getItem(inv_item_id); + S32 remove_count = (*this).erase(inv_item_id); + if (remove_count) + { + LL_DEBUGS("Avatar") << "ATT " << mOpName << " removing request time " + << (item ? item->getName() : "UNKNOWN") << " " << inv_item_id << LL_ENDL; + } +} + +BOOL LLAttachmentsMgr::LLItemRequestTimes::getTime(const LLUUID& inv_item_id, LLTimer& timer) const +{ + std::map::const_iterator it = (*this).find(inv_item_id); + if (it != (*this).end()) + { + timer = it->second; + return TRUE; + } + return FALSE; +} + +BOOL LLAttachmentsMgr::LLItemRequestTimes::wasRequestedRecently(const LLUUID& inv_item_id) const +{ + LLTimer request_time; + if (getTime(inv_item_id, request_time)) + { + F32 request_time_elapsed = request_time.getElapsedTimeF32(); + return request_time_elapsed < mTimeout; + } + else + { + return FALSE; + } +} + +// If we've been waiting for an attachment a long time, we want to +// forget the request, because if the request is invalid (say the +// object does not exist), the existence of a request that never goes +// away will gum up the COF batch logic, causing it to always wait for +// the timeout. Expiring a request means if the item does show up +// late, the COF link request may not get properly batched up, but +// behavior will be no worse than before we had the batching mechanism +// in place; the COF link will still be created, but extra +// requestServerAppearanceUpdate() calls may occur. +void LLAttachmentsMgr::expireOldAttachmentRequests() +{ + for (std::map::iterator it = mAttachmentRequests.begin(); + it != mAttachmentRequests.end(); ) + { + std::map::iterator curr_it = it; + ++it; + if (curr_it->second.getElapsedTimeF32() > MAX_ATTACHMENT_REQUEST_LIFETIME) + { + LLInventoryItem *item = gInventory.getItem(curr_it->first); + LL_WARNS("Avatar") << "ATT expiring request for attachment " + << (item ? item->getName() : "UNKNOWN") << " item_id " << curr_it->first + << " after " << MAX_ATTACHMENT_REQUEST_LIFETIME << " seconds" << LL_ENDL; + mAttachmentRequests.erase(curr_it); + } + } +} + +void LLAttachmentsMgr::expireOldDetachRequests() +{ + for (std::map::iterator it = mDetachRequests.begin(); + it != mDetachRequests.end(); ) + { + std::map::iterator curr_it = it; + ++it; + if (curr_it->second.getElapsedTimeF32() > MAX_ATTACHMENT_REQUEST_LIFETIME) + { + LLInventoryItem *item = gInventory.getItem(curr_it->first); + LL_WARNS("Avatar") << "ATT expiring request for detach " + << (item ? item->getName() : "UNKNOWN") << " item_id " << curr_it->first + << " after " << MAX_ATTACHMENT_REQUEST_LIFETIME << " seconds" << LL_ENDL; + mDetachRequests.erase(curr_it); + } + } +} + +// When an attachment arrives, we want to stop waiting for it, and add +// it to the set of recently arrived items. +void LLAttachmentsMgr::onAttachmentArrived(const LLUUID& inv_item_id) +{ + LLTimer timer; + bool expected = mAttachmentRequests.getTime(inv_item_id, timer); + LLInventoryItem *item = gInventory.getItem(inv_item_id); + + if (!expected) + { + LL_WARNS() << "ATT Attachment was unexpected or arrived after " << MAX_ATTACHMENT_REQUEST_LIFETIME << " seconds: " + << (item ? item->getName() : "UNKNOWN") << " id " << inv_item_id << LL_ENDL; + } + mAttachmentRequests.removeTime(inv_item_id); + if (expected && mAttachmentRequests.empty()) + { + // mAttachmentRequests just emptied out + LL_DEBUGS("Avatar") << "ATT all active attachment requests have completed" << LL_ENDL; + } + if (mRecentlyArrivedAttachments.empty()) + { + // Start the timer for sending off a COF link batch. + mCOFLinkBatchTimer.reset(); + } + mRecentlyArrivedAttachments.insert(inv_item_id); + + static const LLCachedControl detach_bridge("SGDetachBridge"); + if (detach_bridge && item && boost::algorithm::contains(item->getName(), " Bridge v")) + { + LL_INFOS() << "Bridge detected! detaching" << LL_ENDL; + LLVOAvatarSelf::detachAttachmentIntoInventory(item->getUUID()); + } +} + +void LLAttachmentsMgr::onDetachRequested(const LLUUID& inv_item_id) +{ + mDetachRequests.addTime(inv_item_id); +} + +void LLAttachmentsMgr::onDetachCompleted(const LLUUID& inv_item_id) +{ +// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2010-10-05 (Catznip-2.2) + // (mRecentlyArrivedAttachments doesn't need pruning since it'll check the attachment is actually worn before linking) + clearPendingAttachmentLink(inv_item_id); +// [/SL:KB] + + LLTimer timer; + LLInventoryItem *item = gInventory.getItem(inv_item_id); + if (mDetachRequests.getTime(inv_item_id, timer)) + { + LL_DEBUGS("Avatar") << "ATT detach completed after " << timer.getElapsedTimeF32() + << " seconds for " << (item ? item->getName() : "UNKNOWN") << " " << inv_item_id << LL_ENDL; + mDetachRequests.removeTime(inv_item_id); + if (mDetachRequests.empty()) + { + LL_DEBUGS("Avatar") << "ATT all detach requests have completed" << LL_ENDL; + } + } + else + { + LL_WARNS() << "ATT unexpected detach for " + << (item ? item->getName() : "UNKNOWN") << " id " << inv_item_id << LL_ENDL; + } + +// LL_DEBUGS("Avatar") << "ATT detached item flagging as questionable for COF link checking " +// << (item ? item->getName() : "UNKNOWN") << " id " << inv_item_id << LL_ENDL; +// mQuestionableCOFLinks.addTime(inv_item_id); +} + +// Check for attachments that are (a) linked in COF and (b) not +// attached to the avatar. This is a rotten function to have to +// include, because it runs the risk of either repeatedly spamming out +// COF link removals if they're failing for some reason, or getting +// into a tug of war with some other sequence of events that's in the +// process of adding the attachment in question. However, it's needed +// because we have no definitive source of authority for what things +// are actually supposed to be attached. Scripts, run on the server +// side, can remove an attachment without our expecting it. If this +// happens to an attachment that's just been added, then the COF link +// creation may still be in flight, and we will have to delete the +// link after it shows up. +// +// Note that we only flag items for possible link removal if they have +// been previously detached. This means that an attachment failure +// will leave the link in the COF, where it will hopefully resolve +// correctly on relog. +// +// See related: MAINT-5070, MAINT-4409 +// +//void LLAttachmentsMgr::checkInvalidCOFLinks() +//{ +// LLInventoryModel::cat_array_t cat_array; +// LLInventoryModel::item_array_t item_array; +// gInventory.collectDescendents(LLAppearanceMgr::instance().getCOF(), +// cat_array,item_array,LLInventoryModel::EXCLUDE_TRASH); +// for (S32 i=0; igetLinkedUUID(); +// if (inv_item->getType() == LLAssetType::AT_OBJECT) +// { +// LLTimer timer; +// bool is_flagged_questionable = mQuestionableCOFLinks.getTime(item_id,timer); +// bool is_wearing_attachment = isAgentAvatarValid() && gAgentAvatarp->isWearingAttachment(item_id); +// if (is_wearing_attachment && is_flagged_questionable) +// { +// LL_DEBUGS("Avatar") << "ATT was flagged questionable but is now " +// << (is_wearing_attachment ? "attached " : "") +// <<"removing flag after " +// << timer.getElapsedTimeF32() << " item " +// << inv_item->getName() << " id " << item_id << LL_ENDL; +// mQuestionableCOFLinks.removeTime(item_id); +// } +// } +// } +// +// for(LLItemRequestTimes::iterator it = mQuestionableCOFLinks.begin(); +// it != mQuestionableCOFLinks.end(); ) +// { +// LLItemRequestTimes::iterator curr_it = it; +// ++it; +// const LLUUID& item_id = curr_it->first; +// LLViewerInventoryItem *inv_item = gInventory.getItem(item_id); +// if (curr_it->second.getElapsedTimeF32() > MAX_BAD_COF_TIME) +// { +// if (LLAppearanceMgr::instance().isLinkedInCOF(item_id)) +// { +// LL_DEBUGS("Avatar") << "ATT Linked in COF but not attached or requested, deleting link after " +// << curr_it->second.getElapsedTimeF32() << " seconds for " +// << (inv_item ? inv_item->getName() : "UNKNOWN") << " id " << item_id << LL_ENDL; +// LLAppearanceMgr::instance().removeCOFItemLinks(item_id); +// } +// mQuestionableCOFLinks.erase(curr_it); +// continue; +// } +// } +//} + +void LLAttachmentsMgr::spamStatusInfo() +{ +#if 0 + static LLTimer spam_timer; + const F32 spam_frequency = 100.0F; + + if (spam_timer.getElapsedTimeF32() > spam_frequency) + { + spam_timer.reset(); - mPendingAttachments.clear(); + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + gInventory.collectDescendents(LLAppearanceMgr::instance().getCOF(), + cat_array,item_array,LLInventoryModel::EXCLUDE_TRASH); + for (S32 i=0; igetType() == LLAssetType::AT_OBJECT) + { + LL_DEBUGS("Avatar") << "item_id: " << inv_item->getUUID() + << " linked_item_id: " << inv_item->getLinkedUUID() + << " name: " << inv_item->getName() + << " parent: " << inv_item->getParentUUID() + << LL_ENDL; + } + } + } +#endif } diff --git a/indra/newview/llattachmentsmgr.h b/indra/newview/llattachmentsmgr.h index 997db59d22..84fb76bbea 100644 --- a/indra/newview/llattachmentsmgr.h +++ b/indra/newview/llattachmentsmgr.h @@ -32,45 +32,120 @@ class LLViewerInventoryItem; -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +//-------------------------------------------------------------------------------- // LLAttachmentsMgr // -// The sole purpose of this class is to take attachment -// requests, queue them up, and send them all at once. -// This handles situations where the viewer may request -// a bunch of attachments at once in a short period of -// time, where each of the requests would normally be -// sent as a separate message versus being batched into -// one single message. +// This class manages batching up of requests at two stages of +// attachment rezzing. // -// The intent of this batching is to reduce viewer->server -// traffic. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// First, attachments requested to rez get saved in +// mPendingAttachments and sent as a single +// RezMultipleAttachmentsFromInv request. This batching is needed +// mainly because of weaknessing the UI element->inventory item +// handling, such that we don't always know when we are requesting +// multiple items. Now they just pile up and get swept into a single +// request during the idle loop. +// +// Second, after attachments arrive, we need to generate COF links for +// them. There are both efficiency and UI correctness reasons why it +// is better to request all the COF links at once and run a single +// callback after they all complete. Given the vagaries of the +// attachment system, there is no guarantee that we will get all the +// attachments we ask for, but we frequently do. So in the common case +// that all the desired attachments arrive fairly quickly, we generate +// a single batched request for COF links. If attachments arrive late +// or not at all, we will still issue COF link requests once a timeout +// value has been exceeded. +// +// To handle attachments that never arrive, we forget about requests +// that exceed a timeout value. +//-------------------------------------------------------------------------------- class LLAttachmentsMgr: public LLSingleton { public: + // Stores info for attachments that will be requested during idle. + struct AttachmentsInfo + { + LLUUID mItemID; + U8 mAttachmentPt; + BOOL mAdd; + }; + typedef std::deque attachments_vec_t; + LLAttachmentsMgr(); virtual ~LLAttachmentsMgr(); - void addAttachment(const LLUUID& item_id, +// [RLVa:KB] - Checked: 2010-09-13 (RLVa-1.2.1) + void addAttachmentRequest(const LLUUID& item_id, const U8 attachment_pt, -// const BOOL add); -// [RLVa:KB] - Checked: 2010-09-13 (RLVa-1.2.1c) | Added: RLVa-1.2.1c const BOOL add, const BOOL fRlvForce = FALSE); // [/RLVa:KB] +// void addAttachmentRequest(const LLUUID& item_id, +// const U8 attachment_pt, +// const BOOL add); + void onAttachmentRequested(const LLUUID& item_id); + void requestAttachments(attachments_vec_t& attachment_requests); static void onIdle(void *); + + void onAttachmentArrived(const LLUUID& inv_item_id); + + void onDetachRequested(const LLUUID& inv_item_id); + void onDetachCompleted(const LLUUID& inv_item_id); + +// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2010-09-18 (Catznip-2.1) +public: + void clearPendingAttachmentLink(const LLUUID& idItem); + bool getPendingAttachments(uuid_set_t& ids) const; protected: - void onIdle(); + void onRegisterAttachmentComplete(const LLUUID& idAttachLink); + friend class LLRegisterAttachmentCallback; +// [/SL:KB] + private: - struct AttachmentsInfo + + class LLItemRequestTimes: public std::map { - LLUUID mItemID; - U8 mAttachmentPt; - BOOL mAdd; + public: + LLItemRequestTimes(const std::string& op_name, F32 timeout); + void addTime(const LLUUID& inv_item_id); + void removeTime(const LLUUID& inv_item_id); + BOOL wasRequestedRecently(const LLUUID& item_id) const; + BOOL getTime(const LLUUID& inv_item_id, LLTimer& timer) const; + + private: + F32 mTimeout; + std::string mOpName; }; - typedef std::vector attachments_vec_t; + void removeAttachmentRequestTime(const LLUUID& inv_item_id); + void onIdle(); + void requestPendingAttachments(); + void linkRecentlyArrivedAttachments(); + void expireOldAttachmentRequests(); + void expireOldDetachRequests(); +// void checkInvalidCOFLinks(); + void spamStatusInfo(); + + // Attachments that we are planning to rez but haven't requested from the server yet. attachments_vec_t mPendingAttachments; + + // Attachments that have been requested from server but have not arrived yet. + LLItemRequestTimes mAttachmentRequests; + + // Attachments that have been requested to detach but have not gone away yet. + LLItemRequestTimes mDetachRequests; + + // Attachments that have arrived but have not been linked in the COF yet. + uuid_set_t mRecentlyArrivedAttachments; + LLTimer mCOFLinkBatchTimer; + +// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2010-09-18 (Catznip-2.1) + // Attachments that have pending link creation + uuid_set_t mPendingAttachLinks; +// [/SL:KB] + +// // Attachments that are linked in the COF but may be invalid. +// LLItemRequestTimes mQuestionableCOFLinks; }; #endif diff --git a/indra/newview/llautoreplace.cpp b/indra/newview/llautoreplace.cpp new file mode 100644 index 0000000000..2e8926f45b --- /dev/null +++ b/indra/newview/llautoreplace.cpp @@ -0,0 +1,802 @@ +/** + * @file llautoreplace.cpp + * @brief Auto Replace Manager + * + * $LicenseInfo:firstyear=2012&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llautoreplace.h" +#include "llsdserialize.h" +#include "llboost.h" +#include "llcontrol.h" +#include "llviewercontrol.h" +#include "llnotificationsutil.h" + +const char* LLAutoReplace::SETTINGS_FILE_NAME = "autoreplace.xml"; + +void LLAutoReplace::autoreplaceCallback(S32& replacement_start, S32& replacement_length, LLWString& replacement_string, S32& cursor_pos, const LLWString& input_text) +{ + // make sure these returned values are cleared in case there is no replacement + replacement_start = 0; + replacement_length = 0; + replacement_string.clear(); + + static LLCachedControl perform_autoreplace(gSavedSettings, "AutoReplace", 0); + if (perform_autoreplace) + { + S32 word_end = cursor_pos - 1; + + bool at_space = (input_text[word_end] == ' '); + bool have_word = (LLWStringUtil::isPartOfWord(input_text[word_end])); + + if (at_space || have_word) + { + if (at_space && word_end > 0) + { + // find out if this space immediately follows a word + word_end--; + have_word = (LLWStringUtil::isPartOfWord(input_text[word_end])); + } + if (have_word) + { + // word_end points to the end of a word, now find the start of the word + std::string word; + S32 word_start = word_end; + for (S32 back_one = word_start - 1; + back_one >= 0 && LLWStringUtil::isPartOfWord(input_text[back_one]); + back_one-- + ) + { + word_start--; // walk word_start back to the beginning of the word + } + LL_DEBUGS("AutoReplace") << "word_start: " << word_start << " word_end: " << word_end << LL_ENDL; + std::string str_text = std::string(input_text.begin(), input_text.end()); + std::string last_word = str_text.substr(word_start, word_end - word_start + 1); + std::string replacement_word(mSettings.replaceWord(last_word)); + + if (replacement_word != last_word) + { + // The last word is one for which we have a replacement + if (at_space) + { + // return the replacement string + replacement_start = word_start; + replacement_length = last_word.length(); + replacement_string = utf8str_to_wstring(replacement_word); + LLWString old_string = utf8str_to_wstring(last_word); + S32 size_change = replacement_string.size() - old_string.size(); + cursor_pos += size_change; + } + } + } + } + } +} + +std::string LLAutoReplace::getUserSettingsFileName() +{ + std::string path=gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""); + + if (!path.empty()) + { + path = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, SETTINGS_FILE_NAME); + } + return path; +} + +std::string LLAutoReplace::getAppSettingsFileName() +{ + std::string path=gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, ""); + + if (!path.empty()) + { + path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, SETTINGS_FILE_NAME); + } + else + { + LL_ERRS("AutoReplace") << "Failed to get app settings directory name" << LL_ENDL; + } + return path; +} + +LLAutoReplaceSettings LLAutoReplace::getSettings() +{ + return mSettings; +} + +void LLAutoReplace::setSettings(const LLAutoReplaceSettings& newSettings) +{ + mSettings.set(newSettings); + /// Make the newSettings active and write them to user storage + saveToUserSettings(); +} + +LLAutoReplace::LLAutoReplace() +{ +} + +void LLAutoReplace::initSingleton() +{ + loadFromSettings(); +} + +void LLAutoReplace::loadFromSettings() +{ + std::string filename=getUserSettingsFileName(); + if (filename.empty()) + { + LL_INFOS("AutoReplace") << "no valid user settings directory." << LL_ENDL; + } + if(gDirUtilp->fileExists(filename)) + { + LLSD userSettings; + llifstream file; + file.open(filename.c_str()); + if (file.is_open()) + { + LLSDSerialize::fromXML(userSettings, file); + } + file.close(); + if ( mSettings.setFromLLSD(userSettings) ) + { + LL_INFOS("AutoReplace") << "settings loaded from '" << filename << "'" << LL_ENDL; + } + else + { + LL_WARNS("AutoReplace") << "invalid settings found in '" << filename << "'" << LL_ENDL; + } + } + else // no user settings found, try application settings + { + std::string defaultName = getAppSettingsFileName(); + LL_INFOS("AutoReplace") << " user settings file '" << filename << "' not found"<< LL_ENDL; + + bool gotSettings = false; + if(gDirUtilp->fileExists(defaultName)) + { + LLSD appDefault; + llifstream file; + file.open(defaultName.c_str()); + if (file.is_open()) + { + LLSDSerialize::fromXMLDocument(appDefault, file); + } + file.close(); + + if ( mSettings.setFromLLSD(appDefault) ) + { + LL_INFOS("AutoReplace") << "settings loaded from '" << defaultName.c_str() << "'" << LL_ENDL; + gotSettings = true; + } + else + { + LL_WARNS("AutoReplace") << "invalid settings found in '" << defaultName.c_str() << "'" << LL_ENDL; + } + } + + if ( ! gotSettings ) + { + if (mSettings.setFromLLSD(mSettings.getExampleLLSD())) + { + LL_WARNS("AutoReplace") << "no settings found; loaded example." << LL_ENDL; + } + else + { + LL_WARNS("AutoReplace") << "no settings found and example invalid!" << LL_ENDL; + } + } + } +} + +void LLAutoReplace::saveToUserSettings() +{ + std::string filename=getUserSettingsFileName(); + llofstream file; + file.open(filename.c_str()); + LLSDSerialize::toPrettyXML(mSettings.asLLSD(), file); + file.close(); + LL_INFOS("AutoReplace") << "settings saved to '" << filename << "'" << LL_ENDL; +} + +// ================================================================ +// LLAutoReplaceSettings +// ================================================================ + +const std::string LLAutoReplaceSettings::AUTOREPLACE_LIST_NAME = "name"; ///< key for looking up list names +const std::string LLAutoReplaceSettings::AUTOREPLACE_LIST_REPLACEMENTS = "replacements"; ///< key for looking up replacement map + +LLAutoReplaceSettings::LLAutoReplaceSettings() +{ +} + +LLAutoReplaceSettings::LLAutoReplaceSettings(const LLAutoReplaceSettings& settings) +{ + // copy all values through fundamental type intermediates for thread safety + mLists = LLSD::emptyArray(); + + for ( LLSD::array_const_iterator list = settings.mLists.beginArray(), listEnd = settings.mLists.endArray(); + list != listEnd; + list++ + ) + { + if ( (*list).isMap() ) // can fail due to LLSD-30: ignore it + { + LLSD listMap = LLSD::emptyMap(); + std::string listName = (*list)[AUTOREPLACE_LIST_NAME]; + listMap[AUTOREPLACE_LIST_NAME] = listName; + listMap[AUTOREPLACE_LIST_REPLACEMENTS] = LLSD::emptyMap(); + + for ( LLSD::map_const_iterator + entry = (*list)[AUTOREPLACE_LIST_REPLACEMENTS].beginMap(), + entriesEnd = (*list)[AUTOREPLACE_LIST_REPLACEMENTS].endMap(); + entry != entriesEnd; + entry++ + ) + { + std::string keyword = entry->first; + std::string replacement = entry->second.asString(); + listMap[AUTOREPLACE_LIST_REPLACEMENTS].insert(keyword, LLSD(replacement)); + } + + mLists.append(listMap); + } + } +} + +void LLAutoReplaceSettings::set(const LLAutoReplaceSettings& newSettings) +{ + mLists = newSettings.mLists; +} + +bool LLAutoReplaceSettings::setFromLLSD(const LLSD& settingsFromLLSD) +{ + bool settingsValid = true; + + if ( settingsFromLLSD.isArray() ) + { + for ( LLSD::array_const_iterator + list = settingsFromLLSD.beginArray(), + listEnd = settingsFromLLSD.endArray(); + settingsValid && list != listEnd; + list++ + ) + { + if ( (*list).isDefined() ) // can be undef due to LLSD-30: ignore it + { + settingsValid = listIsValid(*list); + } + } + } + else + { + settingsValid = false; + LL_WARNS("AutoReplace") << "settings are not an array" << LL_ENDL; + } + + if ( settingsValid ) + { + mLists = settingsFromLLSD; + } + else + { + LL_WARNS("AutoReplace") << "invalid settings discarded; using hard coded example" << LL_ENDL; + } + + return settingsValid; +} + +bool LLAutoReplaceSettings::listNameMatches( const LLSD& list, const std::string name ) +{ + return list.isMap() + && list.has(AUTOREPLACE_LIST_NAME) + && list[AUTOREPLACE_LIST_NAME].asString() == name; +} + +const LLSD* LLAutoReplaceSettings::getListEntries(std::string listName) +{ + const LLSD* returnedEntries = NULL; + for( LLSD::array_const_iterator list = mLists.beginArray(), endList = mLists.endArray(); + returnedEntries == NULL && list != endList; + list++ + ) + { + const LLSD& thisList = *list; + if ( listNameMatches(thisList, listName) ) + { + returnedEntries = &thisList[AUTOREPLACE_LIST_REPLACEMENTS]; + } + } + return returnedEntries; +} + +std::string LLAutoReplaceSettings::replacementFor(std::string keyword, std::string listName) +{ + std::string replacement; + bool foundList = false; + for( LLSD::array_const_iterator list = mLists.beginArray(), endList = mLists.endArray(); + ! foundList && list != endList; + list++ + ) + { + const LLSD& thisList = *list; + if ( listNameMatches(thisList, listName) ) + { + foundList = true; // whether there is a replacement or not, we're done + if ( thisList.isMap() + && thisList.has(AUTOREPLACE_LIST_REPLACEMENTS) + && thisList[AUTOREPLACE_LIST_REPLACEMENTS].has(keyword) + ) + { + replacement = thisList[AUTOREPLACE_LIST_REPLACEMENTS][keyword].asString(); + LL_DEBUGS("AutoReplace")<<"'"< '"<second.isString() ) + { + listValid = false; + LL_WARNS("AutoReplace") + << "non-string replacement value found in list '" + << list[AUTOREPLACE_LIST_NAME].asString() << "'" + << LL_ENDL; + } + } + } + + return listValid; +} + +const LLSD* LLAutoReplaceSettings::exportList(std::string listName) +{ + const LLSD* exportedList = NULL; + for ( LLSD::array_const_iterator list = mLists.beginArray(), listEnd = mLists.endArray(); + exportedList == NULL && list != listEnd; + list++ + ) + { + if ( listNameMatches(*list, listName) ) + { + const LLSD& namedList = (*list); + exportedList = &namedList; + } + } + return exportedList; +} + +bool LLAutoReplaceSettings::listNameIsUnique(const LLSD& newList) +{ + bool nameIsUnique = true; + // this must always be called with a valid list, so it is safe to assume it has a name + std::string newListName = newList[AUTOREPLACE_LIST_NAME].asString(); + for ( LLSD::array_const_iterator list = mLists.beginArray(), listEnd = mLists.endArray(); + nameIsUnique && list != listEnd; + list++ + ) + { + if ( listNameMatches(*list, newListName) ) + { + LL_WARNS("AutoReplace")<<"duplicate list name '"<= 0) + { + LL_DEBUGS("AutoReplace") << "erase "< autoreplace_enabled(gSavedSettings, "AutoReplace", false); + if ( autoreplace_enabled ) + { + LL_DEBUGS("AutoReplace")<<"checking '"< '" << replacements[currentWord].asString() << "'" + << LL_ENDL; + returnedWord = replacements[currentWord].asString(); + } + } + } + return returnedWord; +} + +bool LLAutoReplaceSettings::addEntryToList(LLWString keyword, LLWString replacement, std::string listName) +{ + bool added = false; + + if ( ! keyword.empty() && ! replacement.empty() ) + { + bool isOneWord = true; + for (size_t character = 0; isOneWord && character < keyword.size(); character++ ) + { + if ( ! LLWStringUtil::isPartOfWord(keyword[character]) ) + { + LL_WARNS("AutoReplace") << "keyword '" << wstring_to_utf8str(keyword) << "' not a single word (len "< replacement test pairs + + /// Get the replacement for the keyword from the specified list + std::string replacementFor(std::string keyword, std::string listName); + + /// Adds a keywword/replacement pair to the named list + bool addEntryToList(LLWString keyword, LLWString replacement, std::string listName); + + /// Removes the keywword and its replacement from the named list + bool removeEntryFromList(std::string keyword, std::string listName); + + /** + * Look for currentWord in the lists in order, returning any substitution found + * If no configured substitution is found, returns currentWord + */ + std::string replaceWord(const std::string currentWord /**< word to search for */ ); + + /// Provides a hard-coded example of settings + LLSD getExampleLLSD(); + + /// Get the actual settings as LLSD + const LLSD& asLLSD(); + ///< @note for use only in AutoReplace::saveToUserSettings + + private: + /// Efficiently and safely compare list names + bool listNameMatches( const LLSD& list, const std::string name ); + + /// The actual llsd data structure + LLSD mLists; + + static const std::string AUTOREPLACE_LIST_NAME; ///< key for looking up list names + static const std::string AUTOREPLACE_LIST_REPLACEMENTS; ///< key for looking up replacement map + + /**< + * LLSD structure of the lists + * - The configuration is an array (mLists), + * - Each entry in the array is a replacement list + * - Each replacement list is a map with three keys: + * @verbatim + * "name" String the name of the list + * "replacements" Map keyword -> replacement pairs + * + * + * + * + * name List 1 + * data + * + * keyword1 replacement1 + * keyword2 replacement2 + * + * + * + * name List 2 + * data + * + * keyword1 replacement1 + * keyword2 replacement2 + * + * + * + * + * @endverbatim + */ +}; + +/** Provides a facility to auto-replace text dynamically as it is entered. + * + * When the end of a word is detected (defined as any punctuation character, + * or any whitespace except newline or return), the preceding word is used + * as a lookup key in an ordered list of maps. If a match is found in any + * map, the replacement start index and length are returned along with the + * new replacement string. + * + * See the autoreplaceCallback method for how to add autoreplace functionality + * to a text entry tool. + */ +class LLAutoReplace : public LLSingleton +{ +public: + /// Callback that provides the hook for use in text entry methods + void autoreplaceCallback(S32& replacement_start, S32& replacement_length, LLWString& replacement_string, S32& cursor_pos, const LLWString& input_text); + + /// Get a copy of the current settings + LLAutoReplaceSettings getSettings(); + + /// Commit new settings after making changes + void setSettings(const LLAutoReplaceSettings& settings); + +private: + friend class LLSingleton; + LLAutoReplace(); + /*virtual*/ void initSingleton(); + + LLAutoReplaceSettings mSettings; ///< configuration information + + /// Read settings from persistent storage + void loadFromSettings(); + + /// Make the newSettings active and write them to user storage + void saveToUserSettings(); + + /// Compute the user settings file name + std::string getUserSettingsFileName(); + + /// Compute the (read-ony) application settings file name + std::string getAppSettingsFileName(); + + /// basename for the settings files + static const char* SETTINGS_FILE_NAME; +}; + +#endif /* LLAUTOREPLACE_H */ diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp index 42f2e73d8e..3685ce21b9 100644 --- a/indra/newview/llavataractions.cpp +++ b/indra/newview/llavataractions.cpp @@ -37,23 +37,31 @@ #include "llagent.h" #include "llcallingcard.h" // for LLAvatarTracker #include "llfloateravatarinfo.h" +#include "llfloateravatarpicker.h" // for LLFloaterAvatarPicker +#include "llfloaterchatterbox.h" +#include "llfloatergroupbulkban.h" #include "llfloatergroupinvite.h" #include "llfloatergroups.h" #include "llfloaterwebprofile.h" #include "llfloaterworldmap.h" +#include "llgiveinventory.h" #include "llgivemoney.h" +#include "llinventorybridge.h" +#include "llinventoryfunctions.h" +#include "llinventorypanel.h" #include "llimview.h" // for gIMMgr -#include "llinventoryobserver.h" #include "llmutelist.h" #include "llpanelprofile.h" #include "lltrans.h" #include "llvoiceclient.h" #include "llweb.h" #include "llslurl.h" // IDEVO +#include "llpanelmaininventory.h" #include "llavatarname.h" #include "llagentui.h" -// [RLVa:KB] - Checked: 2011-04-11 (RLVa-1.3.0h) | Added: RLVa-1.3.0h -#include "rlvhandler.h" +// [RLVa:KB] - Checked: 2011-04-11 (RLVa-1.3.0) +#include "rlvactions.h" +#include "rlvcommon.h" // [/RLVa:KB] #include "llviewerwindow.h" @@ -123,10 +131,10 @@ void LLAvatarActions::removeFriendsDialog(const uuid_vec_t& ids) if(ids.size() == 1) { LLUUID agent_id = ids[0]; - std::string av_name; - if(LLAvatarNameCache::getPNSName(agent_id, av_name)) + LLAvatarName av_name; + if(LLAvatarNameCache::get(agent_id, &av_name)) { - args["NAME"] = av_name; + args["NAME"] = av_name.getNSName(); } msgType = "RemoveFromFriends"; @@ -154,9 +162,7 @@ void LLAvatarActions::offerTeleport(const LLUUID& invitee) if (invitee.isNull()) return; - LLDynamicArray ids; - ids.push_back(invitee); - offerTeleport(ids); + offerTeleport(uuid_vec_t{invitee}); } // static @@ -182,16 +188,12 @@ void LLAvatarActions::startIM(const LLUUID& id) if (id.isNull() || gAgentID == id) return; -// [RLVa:KB] - Checked: 2011-04-11 (RLVa-1.3.0h) | Added: RLVa-1.3.0h - if ( (rlv_handler_t::isEnabled()) && (!gRlvHandler.canStartIM(id)) ) +// [RLVa:KB] - Checked: 2013-05-09 (RLVa-1.4.9) + if ( (!RlvActions::canStartIM(id)) && (!RlvActions::hasOpenP2PSession(id)) ) { - LLUUID idSession = gIMMgr->computeSessionID(IM_NOTHING_SPECIAL, id); - if ( (idSession.notNull()) && (!gIMMgr->hasSession(idSession)) ) - { - make_ui_sound("UISndInvalidOp"); - RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTIM, LLSD().with("RECIPIENT", LLSLURL("agent", id, "completename").getSLURLString())); - return; - } + make_ui_sound("UISndInvalidOp"); + RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTIM, LLSD().with("RECIPIENT", LLSLURL("agent", id, "completename").getSLURLString())); + return; } // [/RLVa:KB] @@ -234,16 +236,12 @@ void LLAvatarActions::startCall(const LLUUID& id) return; } -// [RLVa:KB] - Checked: 2011-04-11 (RLVa-1.3.0h) | Added: RLVa-1.3.0h - if ( (rlv_handler_t::isEnabled()) && (!gRlvHandler.canStartIM(id)) ) +// [RLVa:KB] - Checked: 2013-05-09 (RLVa-1.4.9) + if ( (!RlvActions::canStartIM(id)) && (!RlvActions::hasOpenP2PSession(id)) ) { - LLUUID idSession = gIMMgr->computeSessionID(IM_NOTHING_SPECIAL, id); - if ( (idSession.notNull()) && (!gIMMgr->hasSession(idSession)) ) - { - make_ui_sound("UISndInvalidOp"); - RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTIM, LLSD().with("RECIPIENT", LLSLURL("agent", id, "completename").getSLURLString())); - return; - } + make_ui_sound("UISndInvalidOp"); + RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTIM, LLSD().with("RECIPIENT", LLSLURL("agent", id, "completename").getSLURLString())); + return; } // [/RLVa:KB] @@ -258,19 +256,16 @@ void LLAvatarActions::startAdhocCall(const uuid_vec_t& ids) return; } - // convert vector into LLDynamicArray for addSession - LLDynamicArray id_array; for (uuid_vec_t::const_iterator it = ids.begin(); it != ids.end(); ++it) { -// [RLVa:KB] - Checked: 2011-04-11 (RLVa-1.3.0h) | Added: RLVa-1.3.0h +// [RLVa:KB] - Checked: 2011-04-11 (RLVa-1.3.0) const LLUUID& idAgent = *it; - if ( (rlv_handler_t::isEnabled()) && (!gRlvHandler.canStartIM(idAgent)) ) + if (!RlvActions::canStartIM(idAgent)) { make_ui_sound("UISndInvalidOp"); - RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTCONF, LLSD().with("RECIPIENT", LLSLURL("agent", idAgent, "completename").getSLURLString())); + RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTCONF); return; } - id_array.push_back(idAgent); // [/RLVa:KB] // id_array.push_back(*it); } @@ -278,7 +273,7 @@ void LLAvatarActions::startAdhocCall(const uuid_vec_t& ids) // create the new ad hoc voice session const std::string title = LLTrans::getString("conference-title"); LLUUID session_id = gIMMgr->addSession(title, IM_SESSION_CONFERENCE_START, - ids[0], id_array); + ids[0], ids); if (session_id.isNull()) { return; @@ -315,12 +310,12 @@ void LLAvatarActions::startConference(const uuid_vec_t& ids) { for (uuid_vec_t::const_iterator it = ids.begin(); it != ids.end(); ++it) { -// [RLVa:KB] - Checked: 2011-04-11 (RLVa-1.3.0h) | Added: RLVa-1.3.0h +// [RLVa:KB] - Checked: 2011-04-11 (RLVa-1.3.0) const LLUUID& idAgent = *it; - if ( (rlv_handler_t::isEnabled()) && (!gRlvHandler.canStartIM(idAgent)) ) + if (!RlvActions::canStartIM(idAgent)) { make_ui_sound("UISndInvalidOp"); - RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTCONF, LLSD().with("RECIPIENT", LLSLURL("agent", idAgent, "completename").getSLURLString())); + RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTCONF); return; } // [/RLVa:KB] @@ -354,19 +349,11 @@ static void on_avatar_name_show_profile(const LLUUID& agent_id, const LLAvatarNa } else { - std::string username = av_name.mUsername; - if (username.empty()) - { - username = LLCacheName::buildUsername(av_name.mDisplayName); - } - - llinfos << "opening web profile for " << username << llendl; - std::string url = getProfileURL(username); + std::string url = getProfileURL(av_name.getAccountName()); // PROFILES: open in webkit window LLFloaterWebContent::Params p; - p.url(url). - id(agent_id.asString()); + p.url(url).id(agent_id.asString()); LLFloaterWebProfile::showInstance(get_profile_floater_name(agent_id), p); } } @@ -387,8 +374,8 @@ void LLAvatarActions::showProfile(const LLUUID& id, bool web) // static void LLAvatarActions::showProfiles(const uuid_vec_t& ids, bool web) { - for (uuid_vec_t::const_iterator it = ids.begin(); it != ids.end(); ++it) - showProfile(*it, web); + for (const auto& id : ids) + showProfile(id, web); } //static @@ -423,14 +410,14 @@ void LLAvatarActions::hideProfile(const LLUUID& id) // static void LLAvatarActions::showOnMap(const LLUUID& id) { - std::string av_name; - if (!LLAvatarNameCache::getPNSName(id, av_name)) + LLAvatarName av_name; + if (!LLAvatarNameCache::get(id, &av_name)) { LLAvatarNameCache::get(id, boost::bind(&LLAvatarActions::showOnMap, id)); return; } - gFloaterWorldMap->trackAvatar(id, av_name); + gFloaterWorldMap->trackAvatar(id, av_name.getNSName()); LLFloaterWorldMap::show(true); } @@ -440,7 +427,7 @@ void LLAvatarActions::pay(const LLUUID& id) LLNotification::Params params("BusyModePay"); params.functor(boost::bind(&LLAvatarActions::handlePay, _1, _2, id)); - if (gAgent.getBusy()) + if (gAgent.isDoNotDisturb()) { // warn users of being in busy mode during a transaction LLNotifications::instance().add(params); @@ -513,9 +500,13 @@ void LLAvatarActions::on_avatar_name_cache_teleport_request(const LLUUID& id, co { LLSD notification; notification["uuid"] = id; - //notification["NAME_SLURL"] = LLSLURL("agent", id, "about").getSLURLString(); std::string name; - LLAvatarNameCache::getPNSName(av_name, name); +// [RLVa:KB] - Checked: 2014-03-31 (Catznip-3.6) + if (!RlvActions::canShowName(RlvActions::SNC_TELEPORTREQUEST)) + name = RlvStrings::getAnonym(av_name.getLegacyName()); + else +// [RLVa:KB] + name = av_name.getNSName(); notification["NAME"] = name; LLSD payload; @@ -553,25 +544,256 @@ void LLAvatarActions::csr(const LLUUID& id) if (!gCacheName->getFullName(id, name)) return; std::string url = "http://csr.lindenlab.com/agent/"; + if (char* output = curl_easy_escape(nullptr, name.c_str(), name.length())) + { + name = output; + curl_free(output); + } + url += name; + + LLWeb::loadURL(url); +} - // slow and stupid, but it's late - S32 len = name.length(); - for (S32 i = 0; i < len; i++) +//static +void LLAvatarActions::share(const LLUUID& id) +{ + /* + LLSD key; + LLFloaterSidePanelContainer::showPanel("inventory", key); + LLFloaterReg::showInstance("im_container"); + */ + LLPanelMainInventory::getActiveInventory()->setVisible(true); + + LLUUID session_id = gIMMgr->computeSessionID(IM_NOTHING_SPECIAL, id); + + if (!gIMMgr->hasSession(session_id)) + { + startIM(id); + } + + if (gIMMgr->hasSession(session_id)) { - if (name[i] == ' ') + // we should always get here, but check to verify anyways + LLIMMgr::getInstance()->addMessage(session_id, LLUUID::null, SYSTEM_FROM, LLTrans::getString("share_alert")); + LLFloaterChatterBox::showInstance(session_id); + } +} + +namespace action_give_inventory +{ + /** + * Returns a pointer to 'Add More' inventory panel of Edit Outfit SP. + * + static LLInventoryPanel* get_outfit_editor_inventory_panel() + { + LLPanelOutfitEdit* panel_outfit_edit = dynamic_cast(LLFloaterSidePanelContainer::getPanel("appearance", "panel_outfit_edit")); + if (NULL == panel_outfit_edit) return NULL; + + LLInventoryPanel* inventory_panel = panel_outfit_edit->findChild("folder_view"); + return inventory_panel; + }*/ + + /** + * @return active inventory panel, or NULL if there's no such panel + */ + static LLInventoryPanel* get_active_inventory_panel() + { + LLInventoryPanel* active_panel = LLInventoryPanel::getActiveInventoryPanel(FALSE); + /*if (!active_panel) { - url += "%20"; + active_panel = get_outfit_editor_inventory_panel(); + }*/ + + return active_panel; + } + + /** + * Checks My Inventory visibility. + */ + + static bool is_give_inventory_acceptable() + { + // check selection in the panel + const auto inventory_selected_uuids = LLAvatarActions::getInventorySelectedUUIDs(); + if (inventory_selected_uuids.empty()) return false; // nothing selected + + bool acceptable = false; + for (const auto& id : inventory_selected_uuids) + { + // any category can be offered. + if (gInventory.getCategory(id)) + { + acceptable = true; + continue; + } + + // check if inventory item can be given + if (LLGiveInventory::isInventoryGiveAcceptable(gInventory.getItem(id))) + { + acceptable = true; + continue; + } + + // there are neither item nor category in inventory + acceptable = false; + break; } - else + return acceptable; + } + + static void build_items_string(const uuid_set_t& inventory_selected_uuids, std::string& items_string) + { + llassert(inventory_selected_uuids.size() > 0); + + const std::string& separator = LLTrans::getString("words_separator"); + for (const auto& id : inventory_selected_uuids) { - url += name[i]; + if (!items_string.empty()) items_string.append(separator); + if (LLViewerInventoryCategory* inv_cat = gInventory.getCategory(id)) + { + items_string = inv_cat->getName(); + break; + } + else if (LLViewerInventoryItem* inv_item = gInventory.getItem(id)) + { + items_string.append(inv_item->getName()); + } } } - LLWeb::loadURL(url); -} + struct LLShareInfo : public LLSingleton + { + std::vector mAvatarNames; + uuid_vec_t mAvatarUuids; + }; + + static void give_inventory_cb(const LLSD& notification, const LLSD& response) + { + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + // if Cancel pressed + if (option == 1) + { + return; + } + + const auto inventory_selected_uuids = LLAvatarActions::getInventorySelectedUUIDs(); + if (inventory_selected_uuids.empty()) + { + return; + } + + S32 count = LLShareInfo::instance().mAvatarNames.size(); + bool shared = count; + + // iterate through avatars + for(S32 i = 0; i < count; ++i) + { + const LLUUID& avatar_uuid = LLShareInfo::instance().mAvatarUuids[i]; + + // We souldn't open IM session, just calculate session ID for logging purpose. See EXT-6710 + const LLUUID session_id = gIMMgr->computeSessionID(IM_NOTHING_SPECIAL, avatar_uuid); + + const std::string& separator = LLTrans::getString("words_separator"); + std::string noncopy_item_names; + LLSD noncopy_items = LLSD::emptyArray(); + // iterate through selected inventory objects + for (const auto& id : inventory_selected_uuids) + { + if (LLViewerInventoryCategory* inv_cat = gInventory.getCategory(id)) + { + if (!LLGiveInventory::doGiveInventoryCategory(avatar_uuid, inv_cat, session_id, "ItemsShared")) + { + shared = false; + } + break; + } + LLViewerInventoryItem* inv_item = gInventory.getItem(id); + if (!inv_item->getPermissions().allowCopyBy(gAgentID)) + { + if (!noncopy_item_names.empty()) + { + noncopy_item_names.append(separator); + } + noncopy_item_names.append(inv_item->getName()); + noncopy_items.append(id); + } + else + { + if (!LLGiveInventory::doGiveInventoryItem(avatar_uuid, inv_item, session_id)) + { + shared = false; + } + } + } + if (noncopy_items.beginArray() != noncopy_items.endArray()) + { + LLSD substitutions; + substitutions["ITEMS"] = noncopy_item_names; + LLSD payload; + payload["agent_id"] = avatar_uuid; + payload["items"] = noncopy_items; + payload["success_notification"] = "ItemsShared"; + LLNotificationsUtil::add("CannotCopyWarning", substitutions, payload, + &LLGiveInventory::handleCopyProtectedItem); + shared = false; + break; + } + } + if (shared) + { + if (LLFloaterAvatarPicker::instanceExists()) LLFloaterAvatarPicker::instance().close(); + LLNotificationsUtil::add("ItemsShared"); + } + } + + /** + * Performs "give inventory" operations for provided avatars. + * + * Sends one requests to give all selected inventory items for each passed avatar. + * Avatars are represent by two vectors: names and UUIDs which must be sychronized with each other. + * + * @param avatar_names - avatar names request to be sent. + * @param avatar_uuids - avatar names request to be sent. + */ + static void give_inventory(const uuid_vec_t& avatar_uuids, const std::vector avatar_names) + { + llassert(avatar_names.size() == avatar_uuids.size()); + + const auto inventory_selected_uuids = LLAvatarActions::getInventorySelectedUUIDs(); + if (inventory_selected_uuids.empty()) + { + return; + } + + std::string residents; + LLAvatarActions::buildResidentsString(avatar_names, residents); + + std::string items; + build_items_string(inventory_selected_uuids, items); + + auto folders_count = 0; + //traverse through selected inventory items and count folders among them + for (const auto& id : inventory_selected_uuids) + { + if (gInventory.getCategory(id)) + { + if (++folders_count == 2) + break; + } + } -// Singu TODO: Share inventory code block should live here + // EXP-1599 + // In case of sharing multiple folders, make the confirmation + // dialog contain a warning that only one folder can be shared at a time. + std::string notification = folders_count == 2 ? "ShareFolderConfirmation" : "ShareItemsConfirmation"; + LLSD substitutions; + substitutions["RESIDENTS"] = residents; + substitutions["ITEMS"] = items; + LLShareInfo::instance().mAvatarNames = avatar_names; + LLShareInfo::instance().mAvatarUuids = avatar_uuids; + LLNotificationsUtil::add(notification, substitutions, LLSD(), &give_inventory_cb); + } +} // static void LLAvatarActions::buildResidentsString(std::vector avatar_names, std::string& residents_string) @@ -582,7 +804,7 @@ void LLAvatarActions::buildResidentsString(std::vector avatar_name const std::string& separator = LLTrans::getString("words_separator"); for (std::vector::const_iterator it = avatar_names.begin(); ; ) { - residents_string.append((*it).getCompleteName()); + residents_string.append((*it).getNSName()); if (++it == avatar_names.end()) { break; @@ -613,7 +835,115 @@ void LLAvatarActions::buildResidentsString(const uuid_vec_t& avatar_uuids, std:: } } -// Singu TODO: Share inventory code block should live here, too +//static +uuid_set_t LLAvatarActions::getInventorySelectedUUIDs() +{ + LLInventoryPanel* active_panel = action_give_inventory::get_active_inventory_panel(); + return active_panel ? active_panel->getRootFolder()->getSelectionList() : uuid_set_t(); + /*std::set inventory_selected; + + LLInventoryPanel* active_panel = action_give_inventory::get_active_inventory_panel(); + if (active_panel) + { + inventory_selected= active_panel->getRootFolder()->getSelectionList(); + } + + if (inventory_selected.empty()) + { + LLSidepanelInventory *sidepanel_inventory = LLFloaterSidePanelContainer::getPanel("inventory"); + if (sidepanel_inventory) + { + inventory_selected= sidepanel_inventory->getInboxSelectionList(); + } + } + + uuid_set_t inventory_selected_uuids; + for (auto it = inventory_selected.begin(), end_it = inventory_selected.end(); + it != end_it; + ++it) + { + inventory_selected_uuids.insert(static_cast((*it)->getViewModelItem())->getUUID()); + } + return inventory_selected_uuids;*/ +} + +//static +void LLAvatarActions::shareWithAvatars(LLView * panel) +{ + using namespace action_give_inventory; + + LLFloater* root_floater = gFloaterView->getParentFloater(panel); + LLFloaterAvatarPicker* picker = + LLFloaterAvatarPicker::show(boost::bind(give_inventory, _1, _2), TRUE, FALSE, FALSE, root_floater->getName()); + if (!picker) + { + return; + } + + picker->setOkBtnEnableCb(boost::bind(is_give_inventory_acceptable)); + picker->openFriendsTab(); + + if (root_floater) + { + root_floater->addDependentFloater(picker); + } + LLNotificationsUtil::add("ShareNotification"); +} + + +// static +bool LLAvatarActions::canShareSelectedItems(LLInventoryPanel* inv_panel /* = NULL*/) +{ + using namespace action_give_inventory; + + if (!inv_panel) + { + LLInventoryPanel* active_panel = get_active_inventory_panel(); + if (!active_panel) return false; + inv_panel = active_panel; + } + + // check selection in the panel + LLFolderView* root_folder = inv_panel->getRootFolder(); + if (!root_folder) + { + return false; + } + const auto inventory_selected = root_folder->getSelectionList(); + if (inventory_selected.empty()) return false; // nothing selected + + bool can_share = true; + const LLUUID& trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); // + for (const auto& id : inventory_selected) + { + LLViewerInventoryCategory* inv_cat = gInventory.getCategory(id); + // any category can be offered. + if (inv_cat && !gInventory.isObjectDescendentOf(inv_cat->getUUID(), trash_id)) // + { + continue; + } + + // check if inventory item can be given + else if (!inv_cat && gInventory.isObjectDescendentOf(id, gInventory.getRootFolderID())) // Singu Note: These three ifs comprise the item half of LLInvFVBridge::canShare, which LL calls here. + if (LLViewerInventoryItem* item = gInventory.getItem(id)) + if (LLInventoryCollectFunctor::itemTransferCommonlyAllowed(item) && LLGiveInventory::isInventoryGiveAcceptable(item)) + /* + LLFolderViewItem* item = *it; + if (!item) return false; + LLInvFVBridge* bridge = dynamic_cast(item->getViewModelItem()); + if (bridge && bridge->canShare()) + */ + { + continue; + } + + // there are neither item nor category in inventory + can_share = false; + break; + } + + return can_share; +} // static void LLAvatarActions::toggleBlock(const LLUUID& id) @@ -689,13 +1019,18 @@ bool LLAvatarActions::canOfferTeleport(const uuid_vec_t& ids) void LLAvatarActions::inviteToGroup(const LLUUID& id) { - LLFloaterGroupPicker* widget = LLFloaterGroupPicker::showInstance(LLSD(id)); + inviteToGroup(uuid_vec_t(1, id)); +} + +void LLAvatarActions::inviteToGroup(const uuid_vec_t& ids) +{ + LLFloaterGroupPicker* widget = LLFloaterGroupPicker::showInstance(LLSD(ids.front())); if (widget) { widget->center(); widget->setPowersMask(GP_MEMBER_INVITE); widget->removeNoneOption(); - widget->setSelectGroupCallback(boost::bind(callback_invite_to_group, _1, id)); + widget->setSelectGroupCallback(boost::bind(callback_invite_to_group, _1, ids)); } } @@ -729,7 +1064,7 @@ bool LLAvatarActions::handleRemove(const LLSD& notification, const LLSD& respons case 1: // NO default: - llinfos << "No removal performed." << llendl; + LL_INFOS() << "No removal performed." << LL_ENDL; break; } } @@ -743,19 +1078,34 @@ bool LLAvatarActions::handlePay(const LLSD& notification, const LLSD& response, S32 option = LLNotificationsUtil::getSelectedOption(notification, response); if (option == 0) { - gAgent.clearBusy(); + gAgent.setDoNotDisturb(false); } LLFloaterPay::payDirectly(&give_money, avatar_id, /*is_group=*/false); return false; } -// static -void LLAvatarActions::callback_invite_to_group(LLUUID group_id, LLUUID id) +// Ban from group functions +void callback_ban_from_group(const LLUUID& group, uuid_vec_t& ids) { - uuid_vec_t agent_ids; - agent_ids.push_back(id); + LLFloaterGroupBulkBan::showForGroup(group, &ids); +} + +void ban_from_group(const uuid_vec_t& ids) +{ + if (LLFloaterGroupPicker* widget = LLFloaterGroupPicker::showInstance(ids.front())) // It'd be cool if LLSD could be formed from uuid_vec_t + { + widget->center(); + widget->setPowersMask(GP_GROUP_BAN_ACCESS); + widget->removeNoneOption(); + widget->setSelectGroupCallback(boost::bind(callback_ban_from_group, _1, ids)); + } +} +// +// static +void LLAvatarActions::callback_invite_to_group(LLUUID group_id, uuid_vec_t& agent_ids) +{ LLFloaterGroupInvite::showForGroup(group_id, &agent_ids); } @@ -847,7 +1197,7 @@ void LLAvatarActions::requestFriendship(const LLUUID& target_id, const std::stri calling_card_folder_id); LLSD args; - args["TO_NAME"] = target_name; + args["TO_NAME"] = getSLURL(target_id); LLSD payload; payload["from_id"] = target_id; @@ -880,23 +1230,47 @@ bool LLAvatarActions::canBlock(const LLUUID& id) return !is_self && !is_linden; } -// static -void LLAvatarActions::copyUUIDs(const uuid_vec_t& ids) +//static +bool LLAvatarActions::isAgentMappable(const LLUUID& agent_id) +{ + const LLRelationship* buddy_info = NULL; + bool is_friend = LLAvatarActions::isFriend(agent_id); + + if (is_friend) + buddy_info = LLAvatarTracker::instance().getBuddyInfo(agent_id); + + return (buddy_info && + buddy_info->isOnline() && + buddy_info->isRightGrantedFrom(LLRelationship::GRANT_MAP_LOCATION) + ); +} + +void copy_from_ids(const uuid_vec_t& ids, std::function func) { std::string ids_string; const std::string& separator = LLTrans::getString("words_separator"); - for (uuid_vec_t::const_iterator it = ids.begin(); it != ids.end(); ++it) + for (const auto& id : ids) { - const LLUUID& id = *it; if (id.isNull()) continue; if (!ids_string.empty()) ids_string.append(separator); - ids_string.append(id.asString()); + ids_string.append(func(id)); } if (!ids_string.empty()) gViewerWindow->getWindow()->copyTextToClipboard(utf8str_to_wstring(ids_string)); } + +// static +void LLAvatarActions::copyUUIDs(const uuid_vec_t& ids) +{ + copy_from_ids(ids, [](const LLUUID& id) { return id.asString(); }); +} + +std::string LLAvatarActions::getSLURL(const LLUUID& id) +{ + return llformat("secondlife:///app/agent/%s/about", id.asString().c_str()); +} diff --git a/indra/newview/llavataractions.h b/indra/newview/llavataractions.h index 3bb6131854..9f75e793ff 100644 --- a/indra/newview/llavataractions.h +++ b/indra/newview/llavataractions.h @@ -27,8 +27,12 @@ #ifndef LL_LLAVATARACTIONS_H #define LL_LLAVATARACTIONS_H +#include + class LLAvatarName; +class LLInventoryPanel; class LLFloater; +class LLView; /** * Friend-related actions (add, remove, offer teleport, etc) @@ -108,6 +112,16 @@ class LLAvatarActions static void teleportRequest(const LLUUID& id); static void teleport_request_callback(const LLSD& notification, const LLSD& response); + /** + * Share items with the avatar. + */ + static void share(const LLUUID& id); + + /** + * Share items with the picked avatars. + */ + static void shareWithAvatars(LLView * panel); + /** * Block/unblock the avatar. */ @@ -155,6 +169,7 @@ class LLAvatarActions * Invite avatar to a group. */ static void inviteToGroup(const LLUUID& id); + static void inviteToGroup(const uuid_vec_t& ids); /** * Kick avatar off grid @@ -189,6 +204,20 @@ class LLAvatarActions */ static bool canOfferTeleport(const uuid_vec_t& ids); + /** + * Checks whether all items selected in the given inventory panel can be shared + * + * @param inv_panel Inventory panel to get selection from. If NULL, the active inventory panel is used. + * + * @return false if the selected items cannot be shared or the active inventory panel cannot be obtained + */ + static bool canShareSelectedItems(LLInventoryPanel* inv_panel = NULL); + + /** + * Checks whether agent is mappable + */ + static bool isAgentMappable(const LLUUID& agent_id); + /** * Builds a string of residents' display names separated by "words_separator" string. * @@ -205,11 +234,18 @@ class LLAvatarActions */ static void buildResidentsString(const uuid_vec_t& avatar_uuids, std::string& residents_string); + static uuid_set_t getInventorySelectedUUIDs(); + /** * Copy the selected avatar's UUID to clipboard */ static void copyUUIDs(const uuid_vec_t& id); + /** + * @return slurl string from agent ID + */ + static std::string getSLURL(const LLUUID& id); + private: static bool callbackAddFriendWithMessage(const LLSD& notification, const LLSD& response); static bool handleRemove(const LLSD& notification, const LLSD& response); @@ -217,7 +253,7 @@ class LLAvatarActions static bool handleKick(const LLSD& notification, const LLSD& response); static bool handleFreeze(const LLSD& notification, const LLSD& response); static bool handleUnfreeze(const LLSD& notification, const LLSD& response); - static void callback_invite_to_group(LLUUID group_id, LLUUID id); + static void callback_invite_to_group(LLUUID group_id, uuid_vec_t& ids); static void on_avatar_name_cache_teleport_request(const LLUUID& id, const LLAvatarName& av_name); public: diff --git a/indra/newview/llavatarpropertiesprocessor.cpp b/indra/newview/llavatarpropertiesprocessor.cpp index 9ec769f9f9..cf0b282838 100644 --- a/indra/newview/llavatarpropertiesprocessor.cpp +++ b/indra/newview/llavatarpropertiesprocessor.cpp @@ -169,11 +169,11 @@ void LLAvatarPropertiesProcessor::sendAvatarPropertiesUpdate(const LLAvatarData* { if (!gAgent.isInitialized() || (gAgent.getID() == LLUUID::null)) { - llwarns << "Sending avatarinfo update DENIED - invalid agent" << llendl; + LL_WARNS() << "Sending avatarinfo update DENIED - invalid agent" << LL_ENDL; return; } - llinfos << "Sending avatarinfo update" << llendl; + LL_INFOS() << "Sending avatarinfo update" << LL_ENDL; // This value is required by sendAvatarPropertiesUpdate method. //A profile should never be mature. (From the original code) @@ -203,7 +203,7 @@ void LLAvatarPropertiesProcessor::sendAvatarInterestsUpdate(const LLAvatarIntere { if (!gAgent.isInitialized() || (gAgent.getID() == LLUUID::null)) { - llwarns << "Sending avatarinfo update DENIED - invalid agent" << llendl; + LL_WARNS() << "Sending avatarinfo update DENIED - invalid agent" << LL_ENDL; return; } diff --git a/indra/newview/llavatarpropertiesprocessor.h b/indra/newview/llavatarpropertiesprocessor.h index 162fd05c45..64846dcd05 100644 --- a/indra/newview/llavatarpropertiesprocessor.h +++ b/indra/newview/llavatarpropertiesprocessor.h @@ -33,6 +33,14 @@ #include #include +// For Flags in AvatarPropertiesReply +constexpr U32 AVATAR_ALLOW_PUBLISH = 0x1 << 0; // whether profile is externally visible or not +constexpr U32 AVATAR_MATURE_PUBLISH = 0x1 << 1; // profile is "mature" +constexpr U32 AVATAR_IDENTIFIED = 0x1 << 2; // whether avatar has provided payment info +constexpr U32 AVATAR_TRANSACTED = 0x1 << 3; // whether avatar has actively used payment info +constexpr U32 AVATAR_ONLINE = 0x1 << 4; // the online status of this avatar, if known. +constexpr U32 AVATAR_AGEVERIFIED = 0x1 << 5; // whether avatar has been age-verified + /* *TODO Vadim: This needs some refactoring: - Remove EAvatarProcessorType in favor of separate observers, derived from a common parent (to get rid of void*). diff --git a/indra/newview/llavatarrenderinfoaccountant.cpp b/indra/newview/llavatarrenderinfoaccountant.cpp new file mode 100644 index 0000000000..dd83d68abd --- /dev/null +++ b/indra/newview/llavatarrenderinfoaccountant.cpp @@ -0,0 +1,459 @@ +/** + * @file llavatarrenderinfoaccountant.cpp + * @author Dave Simmons + * @date 2013-02-28 + * @brief + * + * $LicenseInfo:firstyear=2013&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2013, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +// Precompiled header +#include "llviewerprecompiledheaders.h" +// associated header +#include "llavatarrenderinfoaccountant.h" +// STL headers +// std headers +// external library headers +// other Linden headers +#include "llcharacter.h" +#include "llhttpclient.h" +#include "lltimer.h" +#include "llviewercontrol.h" +#include "llviewermenu.h" +#include "llviewerobjectlist.h" +#include "llviewerregion.h" +#include "llvoavatar.h" +#include "llworld.h" + + +static const std::string KEY_AGENTS = "agents"; // map +static const std::string KEY_WEIGHT = "weight"; // integer +static const std::string KEY_TOO_COMPLEX = "tooComplex"; // bool +static const std::string KEY_OVER_COMPLEXITY_LIMIT = "overlimit"; // integer +static const std::string KEY_REPORTING_COMPLEXITY_LIMIT = "reportinglimit"; // integer + +static const std::string KEY_IDENTIFIER = "identifier"; +static const std::string KEY_MESSAGE = "message"; +static const std::string KEY_ERROR = "error"; + + +static const F32 SECS_BETWEEN_REGION_SCANS = 5.f; // Scan the region list every 5 seconds +static const F32 SECS_BETWEEN_REGION_REQUEST = 15.0; // Look for new avs every 15 seconds +static const F32 SECS_BETWEEN_REGION_REPORTS = 60.0; // Update each region every 60 seconds + +// Send data updates about once per minute, only need per-frame resolution +LLFrameTimer LLAvatarRenderInfoAccountant::sRenderInfoReportTimer; + + +// HTTP responder class for GET request for avatar render weight information +class LLAvatarRenderInfoGetResponder : public LLHTTPClient::ResponderWithResult +{ +public: + LLAvatarRenderInfoGetResponder(U64 region_handle) : mRegionHandle(region_handle) + { + } + + virtual void httpFailure(); + + virtual void httpSuccess(); + /*virtual*/ char const* getName() const { return "This is dumb."; } + +private: + U64 mRegionHandle; +}; + + +void LLAvatarRenderInfoGetResponder::httpFailure() +{ + const S32 statusNum = getStatus(); + const std::string& reason = getReason(); + LLViewerRegion * regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); + if (regionp) + { + LL_WARNS() << "HTTP error result for avatar weight GET: " << statusNum + << ", " << reason + << " returned by region " << regionp->getName() + << LL_ENDL; + } + else + { + LL_WARNS() << "Avatar render weight GET error recieved but region not found for " + << mRegionHandle + << ", error " << statusNum + << ", " << reason + << LL_ENDL; + } +} + + +void LLAvatarRenderInfoGetResponder::httpSuccess() +{ + LLViewerRegion * regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); + if (!regionp) + { + LL_WARNS("AvatarRenderInfoAccountant") << "Avatar render weight info received but region not found for " + << mRegionHandle << LL_ENDL; + return; + } + + if (LLAvatarRenderInfoAccountant::logRenderInfo()) + { + LL_INFOS() << "LRI: Result for avatar weights request for region " << regionp->getName() << ":" << LL_ENDL; + } + + const LLSD& result = getContent(); + if (result.isMap()) + { + if (result.has(KEY_AGENTS)) + { + const LLSD & agents = result[KEY_AGENTS]; + if (agents.isMap()) + { + for (LLSD::map_const_iterator agent_iter = agents.beginMap(); + agent_iter != agents.endMap(); + agent_iter++ + ) + { + LLUUID target_agent_id = LLUUID(agent_iter->first); + LLVOAvatar* avatarp = gObjectList.findAvatar(target_agent_id); + if (avatarp && + !avatarp->isControlAvatar() && + avatarp->isAvatar()) + + { + const LLSD & agent_info_map = agent_iter->second; + if (agent_info_map.isMap()) + { + // Extract the data for this avatar + if (LLAvatarRenderInfoAccountant::logRenderInfo()) + { + LL_INFOS() << "LRI: Agent " << target_agent_id + << ": " << agent_info_map << LL_ENDL; + } + if (agent_info_map.has(KEY_WEIGHT)) + { + avatarp->setReportedVisualComplexity(agent_info_map[KEY_WEIGHT].asInteger()); + } + } + else + { + LL_WARNS("AvatarRenderInfo") << "agent entry invalid" + << " agent " << target_agent_id + << " map " << agent_info_map + << LL_ENDL; + } + } + else + { + LL_DEBUGS("AvatarRenderInfo") << "Unknown agent " << target_agent_id << LL_ENDL; + } + } + } + else + { + LL_WARNS("AvatarRenderInfo") << "malformed get response '" << KEY_AGENTS << "' is not map" << LL_ENDL; + } + } + else + { + LL_INFOS("AvatarRenderInfo") << "no '" << KEY_AGENTS << "' key in get response" << LL_ENDL; + } + + if (result.has(KEY_REPORTING_COMPLEXITY_LIMIT) + && result.has(KEY_OVER_COMPLEXITY_LIMIT)) + { + U32 reporting = result[KEY_REPORTING_COMPLEXITY_LIMIT].asInteger(); + U32 overlimit = result[KEY_OVER_COMPLEXITY_LIMIT].asInteger(); + + LL_DEBUGS("AvatarRenderInfo") << "complexity limit: " << reporting << " reporting, " << overlimit << " over limit" << LL_ENDL; + } + if (result.has(KEY_ERROR)) + { + const LLSD & error = result[KEY_ERROR]; + LL_WARNS() << "Avatar render info GET error: " + << error[KEY_IDENTIFIER] + << ": " << error[KEY_MESSAGE] + << " from region " << regionp->getName() + << LL_ENDL; + } + } +} + + +// HTTP responder class for POST request for avatar render weight information +class LLAvatarRenderInfoPostResponder : public LLHTTPClient::ResponderWithResult +{ +public: + LLAvatarRenderInfoPostResponder(U64 region_handle) : mRegionHandle(region_handle) + { + } + + virtual void httpFailure(); + + virtual void httpSuccess(); + /*virtual*/ char const* getName() const { return "This is also dumb."; } + +private: + U64 mRegionHandle; +}; + + +// static +// Send request for one region, no timer checks +void LLAvatarRenderInfoAccountant::sendRenderInfoToRegion(LLViewerRegion * regionp) +{ + std::string url = regionp->getCapability("AvatarRenderInfo"); + if (!url.empty()) + { + if (logRenderInfo()) + { + LL_INFOS() << "LRI: Sending avatar render info to region " + << regionp->getName() + << " from " << url + << LL_ENDL; + } + + U32 num_avs = 0; + // Build the render info to POST to the region + LLSD agents = LLSD::emptyMap(); + + std::vector::iterator iter = LLCharacter::sInstances.begin(); + while( iter != LLCharacter::sInstances.end() ) + { + LLVOAvatar* avatar = dynamic_cast(*iter); + if (avatar && + avatar->getRezzedStatus() >= 2 && // Mostly rezzed (maybe without baked textures downloaded) + !avatar->isDead() && // Not dead yet + !avatar->isControlAvatar() && // Not part of an animated object + avatar->getObjectHost() == regionp->getHost()) // Ensure it's on the same region + { + avatar->calculateUpdateRenderComplexity(); // Make sure the numbers are up-to-date + + LLSD info = LLSD::emptyMap(); + U32 avatar_complexity = avatar->getVisualComplexity(); + if (avatar_complexity > 0) + { + // the weight/complexity is unsigned, but LLSD only stores signed integers, + // so if it's over that (which would be ridiculously high), just store the maximum signed int value + info[KEY_WEIGHT] = (S32)(avatar_complexity < S32_MAX ? avatar_complexity : S32_MAX); + info[KEY_TOO_COMPLEX] = LLSD::Boolean(avatar->isTooComplex()); + agents[avatar->getID().asString()] = info; + + if (logRenderInfo()) + { + LL_INFOS("AvatarRenderInfo") << "Sending avatar render info for " << avatar->getID() + << ": " << info << LL_ENDL; + } + num_avs++; + } + } + iter++; + } + + if (num_avs == 0) + return; // nothing to report + + LLSD report = LLSD::emptyMap(); + report[KEY_AGENTS] = agents; + if (agents.size() > 0) + { + LLHTTPClient::post(url, report, new LLAvatarRenderInfoPostResponder(regionp->getHandle())); + } + } +} + +void LLAvatarRenderInfoPostResponder::httpSuccess() +{ + LLViewerRegion * regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); + if (!regionp) + { + LL_INFOS("AvatarRenderInfoAccountant") << "Avatar render weight POST result received but region not found for " + << mRegionHandle << LL_ENDL; + return; + } + const LLSD& result = getContent(); + if (result.isMap()) + { + if (result.has(KEY_ERROR)) + { + const LLSD & error = result[KEY_ERROR]; + LL_WARNS("AvatarRenderInfoAccountant") << "POST error: " + << error[KEY_IDENTIFIER] + << ": " << error[KEY_MESSAGE] + << " from region " << regionp->getName() + << LL_ENDL; + } + else + { + LL_DEBUGS("AvatarRenderInfoAccountant") + << "POST result for region " << regionp->getName() + << ": " << result + << LL_ENDL; + } + } + else + { + LL_WARNS("AvatarRenderInfoAccountant") << "Malformed POST response from region '" << regionp->getName() + << LL_ENDL; + } +} + +void LLAvatarRenderInfoPostResponder::httpFailure() +{ + const S32 statusNum = getStatus(); + const std::string& reason = getReason(); + LLViewerRegion * regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); + if (regionp) + { + LL_WARNS() << "HTTP error result for avatar weight POST: " << statusNum + << ", " << reason + << " returned by region " << regionp->getName() + << LL_ENDL; + } + else + { + LL_WARNS() << "Avatar render weight POST error recieved but region not found for " + << mRegionHandle + << ", error " << statusNum + << ", " << reason + << LL_ENDL; + } +} + +// static +// Send request for one region, no timer checks +void LLAvatarRenderInfoAccountant::getRenderInfoFromRegion(LLViewerRegion * regionp) +{ + std::string url = regionp->getCapability("AvatarRenderInfo"); + if (!url.empty()) + { + if (logRenderInfo()) + { + LL_INFOS() << "LRI: Requesting avatar render info for region " + << regionp->getName() + << " from " << url + << LL_ENDL; + } + + // First send a request to get the latest data + LLHTTPClient::get(url, new LLAvatarRenderInfoGetResponder(regionp->getHandle())); + } +} + + +// static +// Called every frame - send render weight requests to every region +void LLAvatarRenderInfoAccountant::idle() +{ + if (sRenderInfoReportTimer.hasExpired()) + { + S32 num_avs = LLCharacter::sInstances.size(); + + if (logRenderInfo()) + { + LL_INFOS() << "LRI: Scanning all regions and checking for render info updates" + << LL_ENDL; + } + + // Check all regions and see if it's time to fetch/send data + for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); + iter != LLWorld::getInstance()->getRegionList().end(); ++iter) + { + LLViewerRegion* regionp = *iter; + if (regionp && + regionp->isAlive() && + regionp->capabilitiesReceived() && // Region has capability URLs available + regionp->getRenderInfoRequestTimer().hasExpired()) // Time to make request + { + sendRenderInfoToRegion(regionp); + getRenderInfoFromRegion(regionp); + + // Reset this regions timer, moving to longer intervals if there are lots of avatars around + regionp->getRenderInfoRequestTimer().resetWithExpiry(SECS_BETWEEN_REGION_REQUEST + (2.f * num_avs)); + } + } + + // We scanned all the regions, reset the request timer. + sRenderInfoReportTimer.resetWithExpiry(SECS_BETWEEN_REGION_SCANS); + } + + /* Singu TODO: RenderAutoMuteFunctions + static LLCachedControl render_auto_mute_functions(gSavedSettings, "RenderAutoMuteFunctions", 0); + static U32 prev_render_auto_mute_functions = (U32) -1; + if (prev_render_auto_mute_functions != render_auto_mute_functions) + { + prev_render_auto_mute_functions = render_auto_mute_functions; + + // Adjust menus + BOOL show_items = (BOOL)(render_auto_mute_functions & 0x04); + gMenuAvatarOther->setItemVisible( std::string("Normal"), show_items); + gMenuAvatarOther->setItemVisible( std::string("Always use impostor"), show_items); + gMenuAvatarOther->setItemVisible( std::string("Never use impostor"), show_items); + gMenuAvatarOther->setItemVisible( std::string("Impostor seperator"), show_items); + + gMenuAttachmentOther->setItemVisible( std::string("Normal"), show_items); + gMenuAttachmentOther->setItemVisible( std::string("Always use impostor"), show_items); + gMenuAttachmentOther->setItemVisible( std::string("Never use impostor"), show_items); + gMenuAttachmentOther->setItemVisible( std::string("Impostor seperator"), show_items); + + if (!show_items) + { // Turning off visual muting + for (std::vector::iterator iter = LLCharacter::sInstances.begin(); + iter != LLCharacter::sInstances.end(); ++iter) + { // Make sure all AVs have the setting cleared + LLVOAvatar* inst = (LLVOAvatar*) *iter; + inst->setCachedVisualMute(false); + } + } + }*/ +} + + +// static +// Make sRenderInfoReportTimer expire so the next call to idle() will scan and query a new region +// called via LLViewerRegion::setCapabilitiesReceived() boost signals when the capabilities +// are returned for a new LLViewerRegion, and is the earliest time to get render info +void LLAvatarRenderInfoAccountant::expireRenderInfoReportTimer(const LLUUID& region_id) +{ + if (logRenderInfo()) + { + LL_INFOS() << "LRI: Viewer has new region capabilities, clearing global render info timer" + << " and timer for region " << region_id + << LL_ENDL; + } + + // Reset the global timer so it will scan regions immediately + sRenderInfoReportTimer.reset(); + + LLViewerRegion* regionp = LLWorld::instance().getRegionFromID(region_id); + if (regionp) + { // Reset the region's timer so it will request data immediately + regionp->getRenderInfoRequestTimer().reset(); + } +} + +// static +bool LLAvatarRenderInfoAccountant::logRenderInfo() +{ + static LLCachedControl render_mute_logging_enabled(gSavedSettings, "RenderAutoMuteLogging", false); + return render_mute_logging_enabled; +} diff --git a/indra/newview/llavatarrenderinfoaccountant.h b/indra/newview/llavatarrenderinfoaccountant.h new file mode 100644 index 0000000000..d68f2dccfb --- /dev/null +++ b/indra/newview/llavatarrenderinfoaccountant.h @@ -0,0 +1,56 @@ +/** + * @file llavatarrenderinfoaccountant.h + * @author Dave Simmons + * @date 2013-02-28 + * @brief + * + * $LicenseInfo:firstyear=2013&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2013, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#if ! defined(LL_llavatarrenderinfoaccountant_H) +#define LL_llavatarrenderinfoaccountant_H + +class LLViewerRegion; + +// Class to gather avatar rendering information +// that is sent to or fetched from regions. +class LLAvatarRenderInfoAccountant +{ +public: + LLAvatarRenderInfoAccountant() {}; + ~LLAvatarRenderInfoAccountant() {}; + + static void sendRenderInfoToRegion(LLViewerRegion * regionp); + static void getRenderInfoFromRegion(LLViewerRegion * regionp); + + static void expireRenderInfoReportTimer(const LLUUID& region_id); + + static void idle(); + + static bool logRenderInfo(); + +private: + // Send data updates about once per minute, only need per-frame resolution + static LLFrameTimer sRenderInfoReportTimer; +}; + +#endif /* ! defined(LL_llavatarrenderinfoaccountant_H) */ diff --git a/indra/newview/llbox.cpp b/indra/newview/llbox.cpp index f8c0afdfda..a72c966c75 100644 --- a/indra/newview/llbox.cpp +++ b/indra/newview/llbox.cpp @@ -82,16 +82,16 @@ void LLBox::renderface(S32 which_face) {7, 4, 0, 3} }; - gGL.begin(LLRender::QUADS); + gGL.begin(LLRender::TRIANGLE_STRIP); //gGL.normal3fv(&normals[which_face][0]); - gGL.texCoord2f(1,0); - gGL.vertex3fv(&mVertex[ faces[which_face][0] ][0]); - gGL.texCoord2f(1,1); - gGL.vertex3fv(&mVertex[ faces[which_face][1] ][0]); gGL.texCoord2f(0,1); - gGL.vertex3fv(&mVertex[ faces[which_face][2] ][0]); + gGL.vertex3fv(&mVertex[ faces[which_face][2]][0]); gGL.texCoord2f(0,0); - gGL.vertex3fv(&mVertex[ faces[which_face][3] ][0]); + gGL.vertex3fv(&mVertex[ faces[which_face][3]][0]); + gGL.texCoord2f(1, 1); + gGL.vertex3fv(&mVertex[faces[which_face][1]][0]); + gGL.texCoord2f(1, 0); + gGL.vertex3fv(&mVertex[faces[which_face][0]][0]); gGL.end(); } diff --git a/indra/newview/llcallbacklist.cpp b/indra/newview/llcallbacklist.cpp index 79ec43dfe9..cdc664381d 100644 --- a/indra/newview/llcallbacklist.cpp +++ b/indra/newview/llcallbacklist.cpp @@ -56,7 +56,7 @@ void LLCallbackList::addFunction( callback_t func, void *data) { if (!func) { - llerrs << "LLCallbackList::addFunction - function is NULL" << llendl; + LL_ERRS() << "LLCallbackList::addFunction - function is NULL" << LL_ENDL; return; } @@ -70,7 +70,7 @@ void LLCallbackList::addFunction( callback_t func, void *data) } -BOOL LLCallbackList::containsFunction( callback_t func, void *data) +bool LLCallbackList::containsFunction( callback_t func, void *data) { callback_pair_t t(func, data); callback_list_t::iterator iter = std::find(mCallbackList.begin(), mCallbackList.end(), t); @@ -85,7 +85,7 @@ BOOL LLCallbackList::containsFunction( callback_t func, void *data) } -BOOL LLCallbackList::deleteFunction( callback_t func, void *data) +bool LLCallbackList::deleteFunction( callback_t func, void *data) { callback_pair_t t(func, data); callback_list_t::iterator iter = std::find(mCallbackList.begin(), mCallbackList.end(), t); @@ -234,14 +234,14 @@ void doPeriodically(bool_func_t callable, F32 seconds) void test1(void *data) { S32 *s32_data = (S32 *)data; - llinfos << "testfunc1 " << *s32_data << llendl; + LL_INFOS() << "testfunc1 " << *s32_data << LL_ENDL; } void test2(void *data) { S32 *s32_data = (S32 *)data; - llinfos << "testfunc2 " << *s32_data << llendl; + LL_INFOS() << "testfunc2 " << *s32_data << LL_ENDL; } @@ -252,54 +252,54 @@ LLCallbackList::test() S32 b = 2; LLCallbackList *list = new LLCallbackList; - llinfos << "Testing LLCallbackList" << llendl; + LL_INFOS() << "Testing LLCallbackList" << LL_ENDL; if (!list->deleteFunction(NULL)) { - llinfos << "passed 1" << llendl; + LL_INFOS() << "passed 1" << LL_ENDL; } else { - llinfos << "error, removed function from empty list" << llendl; + LL_INFOS() << "error, removed function from empty list" << LL_ENDL; } - // llinfos << "This should crash" << llendl; + // LL_INFOS() << "This should crash" << LL_ENDL; // list->addFunction(NULL); list->addFunction(&test1, &a); list->addFunction(&test1, &a); - llinfos << "Expect: test1 1, test1 1" << llendl; + LL_INFOS() << "Expect: test1 1, test1 1" << LL_ENDL; list->callFunctions(); list->addFunction(&test1, &b); list->addFunction(&test2, &b); - llinfos << "Expect: test1 1, test1 1, test1 2, test2 2" << llendl; + LL_INFOS() << "Expect: test1 1, test1 1, test1 2, test2 2" << LL_ENDL; list->callFunctions(); if (list->deleteFunction(&test1, &b)) { - llinfos << "passed 3" << llendl; + LL_INFOS() << "passed 3" << LL_ENDL; } else { - llinfos << "error removing function" << llendl; + LL_INFOS() << "error removing function" << LL_ENDL; } - llinfos << "Expect: test1 1, test1 1, test2 2" << llendl; + LL_INFOS() << "Expect: test1 1, test1 1, test2 2" << LL_ENDL; list->callFunctions(); list->deleteAllFunctions(); - llinfos << "Expect nothing" << llendl; + LL_INFOS() << "Expect nothing" << LL_ENDL; list->callFunctions(); - llinfos << "nothing :-)" << llendl; + LL_INFOS() << "nothing :-)" << LL_ENDL; delete list; - llinfos << "test complete" << llendl; + LL_INFOS() << "test complete" << LL_ENDL; } #endif // _DEBUG diff --git a/indra/newview/llcallingcard.cpp b/indra/newview/llcallingcard.cpp index 1481f49b47..cfe688689d 100644 --- a/indra/newview/llcallingcard.cpp +++ b/indra/newview/llcallingcard.cpp @@ -38,39 +38,34 @@ #include "llcallingcard.h" -#include #include -//#include #include "indra_constants.h" -#include "llcachename.h" +//#include "llcachename.h" #include "llstl.h" #include "lltimer.h" #include "lluuid.h" #include "message.h" #include "llagent.h" -#include "llbutton.h" -//#include "llinventory.h" -#include "llinventorymodel.h" +#include "llavatarnamecache.h" #include "llinventoryobserver.h" +#include "llinventorymodel.h" #include "llnotifications.h" -#include "llnotificationsutil.h" #include "llresmgr.h" #include "llimview.h" +#include "lltrans.h" #include "llviewercontrol.h" -#include "llviewernetwork.h" #include "llviewerobjectlist.h" -#include "llviewerwindow.h" #include "llvoavatar.h" +#include "llavataractions.h" #include "llimview.h" #include "llimpanel.h" -#include "llavatarname.h" -#include "llavatarnamecache.h" ///---------------------------------------------------------------------------- /// Local function declarations, constants, enums, and typedefs ///---------------------------------------------------------------------------- +const S32& friend_name_system(); class LLTrackingData { @@ -111,8 +106,6 @@ static void on_avatar_name_cache_notify(const LLUUID& agent_id, LLAvatarTracker::LLAvatarTracker() : mTrackingData(NULL), mTrackedAgentValid(false), - //mInventory(NULL), - //mInventoryObserver(NULL), mModifyMask(0x0) { } @@ -121,7 +114,9 @@ LLAvatarTracker::~LLAvatarTracker() { deleteTrackingData(); std::for_each(mObservers.begin(), mObservers.end(), DeletePointer()); + mObservers.clear(); std::for_each(mBuddyInfo.begin(), mBuddyInfo.end(), DeletePairedPointer()); + mBuddyInfo.clear(); } void LLAvatarTracker::track(const LLUUID& avatar_id, const std::string& name) @@ -184,13 +179,13 @@ LLVector3d LLAvatarTracker::getGlobalPos() if(!mTrackedAgentValid || !mTrackingData) return LLVector3d(); LLVector3d global_pos; - LLVOAvatar* avatarp = gObjectList.findAvatar(mTrackingData->mAvatarID); - if(avatarp && !avatarp->isDead()) + LLVOAvatar* av = gObjectList.findAvatar(mTrackingData->mAvatarID); + if(av && !av->isDead()) { - global_pos = avatarp->getPositionGlobal(); + global_pos = av->getPositionGlobal(); // HACK - for making the tracker point above the avatar's head // rather than its groin - global_pos.mdV[VZ] += 0.7f * (avatarp->mBodySize.mV[VZ] + avatarp->mAvatarOffset.mV[VZ]); + global_pos.mdV[VZ] += 0.7f * (av->mBodySize.mV[VZ] + av->mAvatarOffset.mV[VZ]); mTrackingData->mGlobalPositionEstimate = global_pos; } @@ -210,10 +205,10 @@ void LLAvatarTracker::getDegreesAndDist(F32& rot, LLVector3d global_pos; - LLVOAvatar* avatarp = gObjectList.findAvatar(mTrackingData->mAvatarID); - if(avatarp && !avatarp->isDead()) + LLViewerObject* object = gObjectList.findObject(mTrackingData->mAvatarID); + if(object && !object->isDead()) { - global_pos = avatarp->getPositionGlobal(); + global_pos = object->getPositionGlobal(); mTrackingData->mGlobalPositionEstimate = global_pos; } else @@ -268,21 +263,21 @@ S32 LLAvatarTracker::addBuddyList(const LLAvatarTracker::buddy_map_t& buds) // IDEVO: is this necessary? name is unused? gCacheName->getFullName(agent_id, full_name); addChangedMask(LLFriendObserver::ADD, agent_id); - lldebugs << "Added buddy " << agent_id + LL_DEBUGS() << "Added buddy " << agent_id << ", " << (mBuddyInfo[agent_id]->isOnline() ? "Online" : "Offline") << ", TO: " << mBuddyInfo[agent_id]->getRightsGrantedTo() << ", FROM: " << mBuddyInfo[agent_id]->getRightsGrantedFrom() - << llendl; + << LL_ENDL; } else { LLRelationship* e_r = (*existing_buddy).second; LLRelationship* n_r = (*itr).second; - llwarns << "!! Add buddy for existing buddy: " << agent_id + LL_WARNS() << "!! Add buddy for existing buddy: " << agent_id << " [" << (e_r->isOnline() ? "Online" : "Offline") << "->" << (n_r->isOnline() ? "Online" : "Offline") << ", " << e_r->getRightsGrantedTo() << "->" << n_r->getRightsGrantedTo() << ", " << e_r->getRightsGrantedTo() << "->" << n_r->getRightsGrantedTo() - << "]" << llendl; + << "]" << LL_ENDL; } } notifyObservers(); @@ -303,7 +298,7 @@ void LLAvatarTracker::copyBuddyList(buddy_map_t& buddies) const void LLAvatarTracker::terminateBuddy(const LLUUID& id) { - lldebugs << "LLAvatarTracker::terminateBuddy()" << llendl; + LL_DEBUGS() << "LLAvatarTracker::terminateBuddy()" << LL_ENDL; LLRelationship* buddy = get_ptr_in_map(mBuddyInfo, id); if(!buddy) return; mBuddyInfo.erase(id); @@ -315,6 +310,7 @@ void LLAvatarTracker::terminateBuddy(const LLUUID& id) msg->nextBlock("ExBlock"); msg->addUUID("OtherID", id); gAgent.sendReliableMessage(); + addChangedMask(LLFriendObserver::REMOVE, id); delete buddy; } @@ -340,12 +336,12 @@ void LLAvatarTracker::setBuddyOnline(const LLUUID& id, bool is_online) { info->online(is_online); addChangedMask(LLFriendObserver::ONLINE, id); - lldebugs << "Set buddy " << id << (is_online ? " Online" : " Offline") << llendl; + LL_DEBUGS() << "Set buddy " << id << (is_online ? " Online" : " Offline") << LL_ENDL; } else { - llwarns << "!! No buddy info found for " << id - << ", setting to " << (is_online ? "Online" : "Offline") << llendl; + LL_WARNS() << "!! No buddy info found for " << id + << ", setting to " << (is_online ? "Online" : "Offline") << LL_ENDL; } } @@ -392,7 +388,7 @@ void LLAvatarTracker::empower(const LLUUID& id, bool grant) void LLAvatarTracker::empowerList(const buddy_map_t& list, bool grant) { - llwarns << "LLAvatarTracker::empowerList() not implemented." << llendl; + LL_WARNS() << "LLAvatarTracker::empowerList() not implemented." << LL_ENDL; /* LLMessageSystem* msg = gMessageSystem; const char* message_name; @@ -462,7 +458,7 @@ void LLAvatarTracker::findAgent() msg->nextBlockFast(_PREHASH_AgentBlock); msg->addUUIDFast(_PREHASH_Hunter, gAgentID); msg->addUUIDFast(_PREHASH_Prey, mTrackingData->mAvatarID); - msg->addU32Fast(_PREHASH_SpaceIP, 0); // will get filled in by simulator + msg->addIPAddrFast(_PREHASH_SpaceIP, 0); // will get filled in by simulator // msg->nextBlockFast(_PREHASH_LocationBlock); const F64 NO_LOCATION = 0.0; msg->addF64Fast(_PREHASH_GlobalX, NO_LOCATION); @@ -604,14 +600,14 @@ void LLAvatarTracker::agentFound(const LLUUID& prey, // static void LLAvatarTracker::processOnlineNotification(LLMessageSystem* msg, void**) { - lldebugs << "LLAvatarTracker::processOnlineNotification()" << llendl; + LL_DEBUGS() << "LLAvatarTracker::processOnlineNotification()" << LL_ENDL; instance().processNotify(msg, true); } // static void LLAvatarTracker::processOfflineNotification(LLMessageSystem* msg, void**) { - lldebugs << "LLAvatarTracker::processOfflineNotification()" << llendl; + LL_DEBUGS() << "LLAvatarTracker::processOfflineNotification()" << LL_ENDL; instance().processNotify(msg, false); } @@ -640,20 +636,40 @@ void LLAvatarTracker::processChange(LLMessageSystem* msg) { std::string fullname; LLSD args; - if (LLAvatarNameCache::getPNSName(agent_id, fullname)) + if (LLAvatarNameCache::getNSName(agent_id, fullname, friend_name_system())) args["NAME"] = fullname; LLSD payload; payload["from_id"] = agent_id; if(LLRelationship::GRANT_MODIFY_OBJECTS & new_rights) { - LLNotificationsUtil::add("GrantedModifyRights",args, payload); + LLNotifications::instance().add("GrantedModifyRights",args, payload); + } + else + { + LLNotifications::instance().add("RevokedModifyRights",args, payload); + } + } + // + if ((mBuddyInfo[agent_id]->getRightsGrantedFrom() ^ new_rights) & LLRelationship::GRANT_MAP_LOCATION) + { + std::string fullname; + LLSD args; + if (LLAvatarNameCache::getNSName(agent_id, fullname, friend_name_system())) + args["NAME"] = fullname; + + LLSD payload; + payload["from_id"] = agent_id; + if (LLRelationship::GRANT_MAP_LOCATION & new_rights) + { + LLNotifications::instance().add("GrantedMapRights", args, payload); } else { - LLNotificationsUtil::add("RevokedModifyRights",args, payload); + LLNotifications::instance().add("RevokedMapRights", args, payload); } } + // (mBuddyInfo[agent_id])->setRightsFrom(new_rights); } } @@ -665,7 +681,7 @@ void LLAvatarTracker::processChange(LLMessageSystem* msg) void LLAvatarTracker::processChangeUserRights(LLMessageSystem* msg, void**) { - lldebugs << "LLAvatarTracker::processChangeUserRights()" << llendl; + LL_DEBUGS() << "LLAvatarTracker::processChangeUserRights()" << LL_ENDL; instance().processChange(msg); } @@ -674,7 +690,7 @@ void LLAvatarTracker::processNotify(LLMessageSystem* msg, bool online) S32 count = msg->getNumberOfBlocksFast(_PREHASH_AgentBlock); BOOL chat_notify = gSavedSettings.getBOOL("ChatOnlineNotification"); - lldebugs << "Received " << count << " online notifications **** " << llendl; + LL_DEBUGS() << "Received " << count << " online notifications **** " << LL_ENDL; if(count > 0) { LLUUID agent_id; @@ -696,8 +712,8 @@ void LLAvatarTracker::processNotify(LLMessageSystem* msg, bool online) } else { - llwarns << "Received online notification for unknown buddy: " - << agent_id << " is " << (online ? "ONLINE" : "OFFLINE") << llendl; + LL_WARNS() << "Received online notification for unknown buddy: " + << agent_id << " is " << (online ? "ONLINE" : "OFFLINE") << LL_ENDL; } if(tracking_id == agent_id) @@ -711,9 +727,7 @@ void LLAvatarTracker::processNotify(LLMessageSystem* msg, bool online) if(chat_notify) { // Look up the name of this agent for the notification - LLAvatarNameCache::get(agent_id, - boost::bind(&on_avatar_name_cache_notify, - _1, _2, online, payload)); + LLAvatarNameCache::get(agent_id,boost::bind(&on_avatar_name_cache_notify,_1, _2, online, payload)); } mModifyMask |= LLFriendObserver::ONLINE; @@ -729,22 +743,35 @@ static void on_avatar_name_cache_notify(const LLUUID& agent_id, { // Popup a notify box with online status of this agent // Use display name only because this user is your friend - std::string name; - LLAvatarNameCache::getPNSName(av_name, name); LLSD args; - args["NAME"] = name; + args["NAME"] = av_name.getNSName(friend_name_system()); + args["ID"] = agent_id; + args["STATUS"] = online ? LLTrans::getString("OnlineStatus") : LLTrans::getString("OfflineStatus"); // Popup a notify box with online status of this agent - LLNotificationPtr notification = LLNotificationsUtil::add(online ? "FriendOnline" : "FriendOffline", args, payload); + LLNotificationPtr notification; + static const LLCachedControl behavior(gSavedSettings, "LiruOnlineNotificationBehavior", 1); + if (online && behavior) + { + notification = + LLNotifications::instance().add("FriendOnlineOffline", + args, + payload, + behavior == 1 ? boost::bind(&LLAvatarActions::startIM, agent_id) : (LLNotificationResponder)boost::bind(LLAvatarActions::showProfile, agent_id, false)); + } + else + { + notification = + LLNotifications::instance().add("FriendOnlineOffline", args, payload); + } // If there's an open IM session with this agent, send a notification there too. LLUUID session_id = LLIMMgr::computeSessionID(IM_NOTHING_SPECIAL, agent_id); - LLFloaterIMPanel *floater = gIMMgr->findFloaterBySession(session_id); - if (floater) + if (LLFloaterIMPanel* floater = gIMMgr->findFloaterBySession(session_id)) { - std::string notifyMsg = notification->getMessage(); - if (!notifyMsg.empty()) - floater->addHistoryLine(notifyMsg,gSavedSettings.getColor4("SystemChatColor")); + std::string notify_msg = notification->getMessage(); + if (!notify_msg.empty()) + floater->addHistoryLine(notify_msg, gSavedSettings.getColor4("SystemChatColor")); } } @@ -811,8 +838,8 @@ void LLTrackingData::agentFound(const LLUUID& prey, { if(prey != mAvatarID) { - llwarns << "LLTrackingData::agentFound() - found " << prey - << " but looking for " << mAvatarID << llendl; + LL_WARNS() << "LLTrackingData::agentFound() - found " << prey + << " but looking for " << mAvatarID << LL_ENDL; } mHaveInfo = true; mAgentGone.setTimerExpirySec(OFFLINE_SECONDS); @@ -821,8 +848,8 @@ void LLTrackingData::agentFound(const LLUUID& prey, bool LLTrackingData::haveTrackingInfo() { - LLVOAvatar* avatarp = gObjectList.findAvatar(mAvatarID); - if(avatarp && !avatarp->isDead()) + LLViewerObject* object = gObjectList.findObject(mAvatarID); + if(object && !object->isDead()) { mCoarseLocationTimer.checkExpirationAndReset(COARSE_FREQUENCY); mUpdateTimer.setTimerExpirySec(FIND_FREQUENCY); @@ -876,7 +903,7 @@ bool LLCollectMappableBuddies::operator()(const LLUUID& buddy_id, LLRelationship { LLAvatarName av_name; LLAvatarNameCache::get( buddy_id, &av_name); - buddy_map_t::value_type value(av_name.mDisplayName, buddy_id); + buddy_map_t::value_type value(av_name.getNSName(friend_name_system()), buddy_id); if(buddy->isOnline() && buddy->isRightGrantedFrom(LLRelationship::GRANT_MAP_LOCATION)) { mMappable.insert(value); @@ -899,7 +926,7 @@ bool LLCollectAllBuddies::operator()(const LLUUID& buddy_id, LLRelationship* bud { LLAvatarName av_name; LLAvatarNameCache::get(buddy_id, &av_name); - mFullName = av_name.mDisplayName; + mFullName = av_name.getNSName(friend_name_system()); buddy_map_t::value_type value(mFullName, buddy_id); if(buddy->isOnline()) { @@ -911,5 +938,3 @@ bool LLCollectAllBuddies::operator()(const LLUUID& buddy_id, LLRelationship* bud } return true; } - - diff --git a/indra/newview/llcallingcard.h b/indra/newview/llcallingcard.h index 104b5122ca..9d4948783a 100644 --- a/indra/newview/llcallingcard.h +++ b/indra/newview/llcallingcard.h @@ -165,7 +165,7 @@ class LLAvatarTracker */ void addChangedMask(U32 mask, const LLUUID& referent); - const std::set& getChangedIDs() { return mChangedBuddyIDs; } + const uuid_set_t& getChangedIDs() { return mChangedBuddyIDs; } // Apply the functor to every buddy. Do not actually modify the // buddy list in the functor or bad things will happen. @@ -201,7 +201,7 @@ class LLAvatarTracker buddy_map_t mBuddyInfo; - typedef std::set changed_buddy_t; + typedef uuid_set_t changed_buddy_t; changed_buddy_t mChangedBuddyIDs; typedef std::vector observer_list_t; @@ -229,7 +229,7 @@ class LLCollectProxyBuddies : public LLRelationshipFunctor LLCollectProxyBuddies() {} virtual ~LLCollectProxyBuddies() {} virtual bool operator()(const LLUUID& buddy_id, LLRelationship* buddy); - typedef std::set buddy_list_t; + typedef uuid_set_t buddy_list_t; buddy_list_t mProxy; }; diff --git a/indra/newview/llcaphttpsender.cpp b/indra/newview/llcaphttpsender.cpp index 1127f43424..3f224f2189 100644 --- a/indra/newview/llcaphttpsender.cpp +++ b/indra/newview/llcaphttpsender.cpp @@ -45,8 +45,8 @@ void LLCapHTTPSender::send(const LLHost& host, const std::string& message, const LLSD& body, LLHTTPClient::ResponderPtr response) const { - llinfos << "LLCapHTTPSender::send: message " << message - << " to host " << host << llendl; + LL_INFOS() << "LLCapHTTPSender::send: message " << message + << " to host " << host << LL_ENDL; LLSD llsd; llsd["message"] = message; llsd["body"] = body; diff --git a/indra/newview/llchatbar.cpp b/indra/newview/llchatbar.cpp index 95e39ee89b..7949571078 100644 --- a/indra/newview/llchatbar.cpp +++ b/indra/newview/llchatbar.cpp @@ -44,6 +44,7 @@ #include "llfocusmgr.h" #include "llagent.h" +#include "llautoreplace.h" #include "llbutton.h" #include "llcombobox.h" #include "llcommandhandler.h" // secondlife:///app/chat/ support @@ -71,6 +72,8 @@ #include "chatbar_as_cmdline.h" // [RLVa:KB] +#include "rlvcommon.h" +#include "rlvactions.h" #include "rlvhandler.h" // [/RLVa:KB] @@ -99,25 +102,24 @@ class LLChatBarGestureObserver : public LLGestureManagerObserver { public: LLChatBarGestureObserver(LLChatBar* chat_barp) : mChatBar(chat_barp){} - virtual ~LLChatBarGestureObserver() {} - virtual void changed() { mChatBar->refreshGestures(); } + virtual ~LLChatBarGestureObserver() = default; + void changed() override { mChatBar->refreshGestures(); } private: LLChatBar* mChatBar; }; - // // Functions // LLChatBar::LLChatBar() : LLPanel(), - mInputEditor(NULL), + mInputEditor(nullptr), mGestureLabelTimer(), mLastSpecialChatChannel(0), mIsBuilt(FALSE), - mGestureCombo(NULL), - mObserver(NULL) + mGestureCombo(nullptr), + mObserver(nullptr) { setIsChrome(TRUE); @@ -131,10 +133,14 @@ LLChatBar::~LLChatBar() { LLGestureMgr::instance().removeObserver(mObserver); delete mObserver; - mObserver = NULL; + mObserver = nullptr; // LLView destructor cleans up children } +//----------------------------------------------------------------------- +// Overrides +//----------------------------------------------------------------------- + BOOL LLChatBar::postBuild() { if (LLUICtrl* history_ctrl = findChild("History")) @@ -149,6 +155,7 @@ BOOL LLChatBar::postBuild() mInputEditor = findChild("Chat Editor"); if (mInputEditor) { + mInputEditor->setAutoreplaceCallback(boost::bind(&LLAutoReplace::autoreplaceCallback, LLAutoReplace::getInstance(), _1, _2, _3, _4, _5)); mInputEditor->setKeystrokeCallback(boost::bind(&LLChatBar::onInputEditorKeystroke,this)); mInputEditor->setFocusLostCallback(boost::bind(&LLChatBar::onInputEditorFocusLost)); mInputEditor->setFocusReceivedCallback(boost::bind(&LLChatBar::onInputEditorGainFocus)); @@ -187,7 +194,7 @@ BOOL LLChatBar::handleKeyHere( KEY key, MASK mask ) else if (mask == MASK_SHIFT) { // whisper - sendChat( CHAT_TYPE_WHISPER ); + sendChat(CHAT_TYPE_WHISPER); handled = TRUE; } else if (mask == MASK_NONE) @@ -208,6 +215,11 @@ BOOL LLChatBar::handleKeyHere( KEY key, MASK mask ) return handled; } +void LLChatBar::onFocusLost() +{ + //stopChat(); +} + void LLChatBar::refresh() { // HACK: Leave the name of the gesture in place for a few seconds. @@ -240,17 +252,16 @@ void LLChatBar::refreshGestures() //store current selection so we can maintain it std::string cur_gesture = mGestureCombo->getValue().asString(); mGestureCombo->selectFirstItem(); - std::string label = mGestureCombo->getValue().asString();; + // clear mGestureCombo->clearRows(); // collect list of unique gestures std::map unique; - LLGestureMgr::item_map_t::const_iterator it; const LLGestureMgr::item_map_t& active_gestures = LLGestureMgr::instance().getActiveGestures(); - for (it = active_gestures.begin(); it != active_gestures.end(); ++it) + for (const auto& active_gesture : active_gestures) { - LLMultiGesture* gesture = (*it).second; + LLMultiGesture* gesture = active_gesture.second; if (gesture) { if (!gesture->mTrigger.empty()) @@ -260,11 +271,9 @@ void LLChatBar::refreshGestures() } } - // add unique gestures - std::map ::iterator it2; - for (it2 = unique.begin(); it2 != unique.end(); ++it2) + for (auto& it2 : unique) { - mGestureCombo->addSimpleElement((*it2).first); + mGestureCombo->addSimpleElement(it2.first); } mGestureCombo->sortByName(); @@ -314,12 +323,12 @@ void LLChatBar::setIgnoreArrowKeys(BOOL b) } } -BOOL LLChatBar::inputEditorHasFocus() +BOOL LLChatBar::inputEditorHasFocus() const { return mInputEditor && mInputEditor->hasFocus(); } -std::string LLChatBar::getCurrentChat() +std::string LLChatBar::getCurrentChat() const { return mInputEditor ? mInputEditor->getText() : LLStringUtil::null; } @@ -388,7 +397,7 @@ LLWString LLChatBar::stripChannelNumber(const LLWString &mesg, S32* channel) pos++; } - mLastSpecialChatChannel = strtol(wstring_to_utf8str(channel_string).c_str(), NULL, 10); + mLastSpecialChatChannel = strtol(wstring_to_utf8str(channel_string).c_str(), nullptr, 10); // if(mesg[1] == '-') mLastSpecialChatChannel = -mLastSpecialChatChannel; @@ -404,6 +413,63 @@ LLWString LLChatBar::stripChannelNumber(const LLWString &mesg, S32* channel) } } +// Returns whether or not this is an action +bool convert_roleplay_text(std::string& utf8text) +{ + bool action(true); // Using /me with autoclose /me ((does something ooc)) + // Allow CAPSlock /me here + if (utf8text.find("/ME'") == 0 || utf8text.find("/ME ") == 0) + { + utf8text.replace(1, 2, "me"); + } + // Convert MU*s style poses into IRC emotes here. + else if (gSavedSettings.getBOOL("AscentAllowMUpose") && utf8text.length() > 3 && utf8text.find(":") == 0) + { + if (utf8text[1] == '\'') + utf8text.replace(0, 1, "/me"); + else if (isalpha(utf8text[1])) // Do not prevent smileys and such. + utf8text.replace(0, 1, "/me "); + else + action = false; + } + else if (utf8text.find("/me'") != 0 && utf8text.find("/me ") != 0) + { + action = false; + } + + if (gSavedSettings.getBOOL("AscentAutoCloseOOC") && (utf8text.length() > 3)) + { + const U32 pos(action ? 4 : 0); + //Check if it needs the end-of-chat brackets -HgB + if (utf8text.find("((") == pos && utf8text.find("))") == std::string::npos) + { + if (*utf8text.rbegin() == ')') + utf8text += " "; + utf8text += "))"; + } + else if (utf8text.find("[[") == pos && utf8text.find("]]") == std::string::npos) + { + if (*utf8text.rbegin() == ']') + utf8text += " "; + utf8text += "]]"; + } + // Check if it needs start-of-chat brackets + else if (utf8text.find("((") == std::string::npos && utf8text.find("))") == (utf8text.length() - 2)) + { + if (utf8text.at(pos) == '(') + utf8text.insert(pos, " "); + utf8text.insert(pos, "(("); + } + else if (utf8text.find("[[") == std::string::npos && utf8text.find("]]") == (utf8text.length() - 2)) + { + if (utf8text.at(pos) == '[') + utf8text.insert(pos, " "); + utf8text.insert(pos, "[["); + } + } + return action; +} + // void LLChatBar::sendChat( EChatType type ) { @@ -423,47 +489,7 @@ void LLChatBar::sendChat( EChatType type ) std::string utf8_revised_text; if (0 == channel) { - if (gSavedSettings.getBOOL("AscentAutoCloseOOC") && (utf8text.length() > 1)) - { - //Check if it needs the end-of-chat brackets -HgB - if (utf8text.find("((") == 0 && utf8text.find("))") == -1) - { - if(utf8text.at(utf8text.length() - 1) == ')') - utf8text+=" "; - utf8text+="))"; - } - else if(utf8text.find("[[") == 0 && utf8text.find("]]") == -1) - { - if(utf8text.at(utf8text.length() - 1) == ']') - utf8text+=" "; - utf8text+="]]"; - } - - if (utf8text.find("((") == -1 && utf8text.find("))") == (utf8text.length() - 2)) - { - if(utf8text.at(0) == '(') - utf8text.insert(0," "); - utf8text.insert(0,"(("); - } - else if (utf8text.find("[[") == -1 && utf8text.find("]]") == (utf8text.length() - 2)) - { - if(utf8text.at(0) == '[') - utf8text.insert(0," "); - utf8text.insert(0,"[["); - } - } - // Convert MU*s style poses into IRC emotes here. - if (gSavedSettings.getBOOL("AscentAllowMUpose") && utf8text.find(":") == 0 && utf8text.length() > 3) - { - if (utf8text.find(":'") == 0) - { - utf8text.replace(0, 1, "/me"); - } - else if (isalpha(utf8text.at(1))) // Do not prevent smileys and such. - { - utf8text.replace(0, 1, "/me "); - } - } + convert_roleplay_text(utf8text); // discard returned "found" boolean LLGestureMgr::instance().triggerAndReviseString(utf8text, &utf8_revised_text); } @@ -473,11 +499,7 @@ void LLChatBar::sendChat( EChatType type ) } utf8_revised_text = utf8str_trim(utf8_revised_text); - EChatType nType; - if(type == CHAT_TYPE_OOC) - nType=CHAT_TYPE_NORMAL; - else - nType=type; + EChatType nType(type == CHAT_TYPE_OOC ? CHAT_TYPE_NORMAL : type); if (!utf8_revised_text.empty() && cmd_line_chat(utf8_revised_text, nType)) { // Chat with animation @@ -509,17 +531,24 @@ void LLChatBar::sendChat( EChatType type ) // static void LLChatBar::startChat(const char* line) { + if (!gChatBar || !gChatBar->getParent()) + { + return; + } gChatBar->getParent()->setVisible(TRUE); gChatBar->setKeyboardFocus(TRUE); gSavedSettings.setBOOL("ChatVisible", TRUE); - if (line && gChatBar->mInputEditor) + if (gChatBar->mInputEditor) { - std::string line_string(line); - gChatBar->mInputEditor->setText(line_string); + if (line) + { + std::string line_string(line); + gChatBar->mInputEditor->setText(line_string); + } + // always move cursor to end so users don't obliterate chat when accidentally hitting WASD + gChatBar->mInputEditor->setCursorToEnd(); } - // always move cursor to end so users don't obliterate chat when accidentally hitting WASD - gChatBar->mInputEditor->setCursorToEnd(); } @@ -528,7 +557,8 @@ void LLChatBar::startChat(const char* line) void LLChatBar::stopChat() { // In simple UI mode, we never release focus from the chat bar - gChatBar->setKeyboardFocus(FALSE); + if (gChatBar) + gChatBar->setKeyboardFocus(FALSE); // If we typed a movement key and pressed return during the // same frame, the keyboard handlers will see the key as having @@ -540,7 +570,8 @@ void LLChatBar::stopChat() gAgent.stopTyping(); // hide chat bar so it doesn't grab focus back - gChatBar->getParent()->setVisible(FALSE); + if (gChatBar && gChatBar->getParent()) + gChatBar->getParent()->setVisible(FALSE); gSavedSettings.setBOOL("ChatVisible", FALSE); } @@ -555,9 +586,12 @@ void LLChatBar::onInputEditorKeystroke() S32 length = raw_text.length(); - //if( (length > 0) && (raw_text[0] != '/') ) // forward slash is used for escape (eg. emote) sequences -// [RLVa:KB] - Checked: 2009-07-07 (RLVa-1.0.0d) - if ( (length > 0) && (raw_text[0] != '/') && (!gRlvHandler.hasBehaviour(RLV_BHVR_REDIRCHAT)) ) +// if( (length > 0) +// && (raw_text[0] != '/') // forward slash is used for escape (eg. emote) sequences +// && (raw_text[0] != ':') // colon is used in for MUD poses +// ) +// [RLVa:KB] - Checked: 2010-03-26 (RLVa-1.2.0b) | Modified: RLVa-1.0.0d + if ( (length > 0) && (raw_text[0] != '/') && (raw_text[0] != ':') && (!RlvActions::hasBehaviour(RLV_BHVR_REDIRCHAT)) ) // [/RLVa:KB] { gAgent.startTyping(); @@ -567,21 +601,6 @@ void LLChatBar::onInputEditorKeystroke() gAgent.stopTyping(); } - /* Doesn't work -- can't tell the difference between a backspace - that killed the selection vs. backspace at the end of line. - if (length > 1 - && text[0] == '/' - && key == KEY_BACKSPACE) - { - // the selection will already be deleted, but we need to trim - // off the character before - std::string new_text = raw_text.substr(0, length-1); - mInputEditor->setText( new_text ); - mInputEditor->setCursorToEnd(); - length = length - 1; - } - */ - KEY key = gKeyboard->currentKey(); // Ignore "special" keys, like backspace, arrows, etc. @@ -607,11 +626,6 @@ void LLChatBar::onInputEditorKeystroke() mInputEditor->setSelection(length, outlength); } } - - //llinfos << "GESTUREDEBUG " << trigger - // << " len " << length - // << " outlen " << out_str.getLength() - // << llendl; } } @@ -625,7 +639,8 @@ void LLChatBar::onInputEditorFocusLost() // static void LLChatBar::onInputEditorGainFocus() { - LLFloaterChat::setHistoryCursorAndScrollToEnd(); + if (gSavedSettings.getBOOL("LiruLegacyScrollToEnd")) + LLFloaterChat::setHistoryCursorAndScrollToEnd(); } // static @@ -652,11 +667,11 @@ void LLChatBar::sendChatFromViewer(const std::string &utf8text, EChatType type, void LLChatBar::sendChatFromViewer(const LLWString &wtext, EChatType type, BOOL animate) { // Look for "/20 foo" channel chats. - S32 channel = 0; + S32 channel = gSavedSettings.getS32("AlchemyNearbyChatChannel"); LLWString out_text = stripChannelNumber(wtext, &channel); std::string utf8_out_text = wstring_to_utf8str(out_text); - std::string utf8_text = wstring_to_utf8str(wtext); + utf8_text = utf8str_trim(utf8_text); if (!utf8_text.empty()) { @@ -664,17 +679,12 @@ void LLChatBar::sendChatFromViewer(const LLWString &wtext, EChatType type, BOOL } // [RLVa:KB] - Checked: 2010-03-27 (RLVa-1.2.0b) | Modified: RLVa-1.2.0b - if ( (0 == channel) && (rlv_handler_t::isEnabled()) ) + // RELEASE-RLVa: [SL-2.0.0] This entire class appears to be dead/non-functional? + if ( (0 == channel) && (RlvActions::isRlvEnabled()) ) { // Adjust the (public) chat "volume" on chat and gestures (also takes care of playing the proper animation) - if ( ((CHAT_TYPE_SHOUT == type) || (CHAT_TYPE_NORMAL == type)) && (gRlvHandler.hasBehaviour(RLV_BHVR_CHATNORMAL)) ) - type = CHAT_TYPE_WHISPER; - else if ( (CHAT_TYPE_SHOUT == type) && (gRlvHandler.hasBehaviour(RLV_BHVR_CHATSHOUT)) ) - type = CHAT_TYPE_NORMAL; - else if ( (CHAT_TYPE_WHISPER == type) && (gRlvHandler.hasBehaviour(RLV_BHVR_CHATWHISPER)) ) - type = CHAT_TYPE_NORMAL; - - animate &= !gRlvHandler.hasBehaviour( (!RlvUtil::isEmote(utf8_text)) ? RLV_BHVR_REDIRCHAT : RLV_BHVR_REDIREMOTE ); + type = RlvActions::checkChatVolume(type); + animate &= !RlvActions::hasBehaviour( (!RlvUtil::isEmote(utf8_text)) ? RLV_BHVR_REDIRCHAT : RLV_BHVR_REDIREMOTE ); } // [/RLVa:KB] @@ -685,22 +695,22 @@ void LLChatBar::sendChatFromViewer(const LLWString &wtext, EChatType type, BOOL { if (type == CHAT_TYPE_WHISPER) { - lldebugs << "You whisper " << utf8_text << llendl; + LL_DEBUGS() << "You whisper " << utf8_text << LL_ENDL; gAgent.sendAnimationRequest(ANIM_AGENT_WHISPER, ANIM_REQUEST_START); } else if (type == CHAT_TYPE_NORMAL) { - lldebugs << "You say " << utf8_text << llendl; + LL_DEBUGS() << "You say " << utf8_text << LL_ENDL; gAgent.sendAnimationRequest(ANIM_AGENT_TALK, ANIM_REQUEST_START); } else if (type == CHAT_TYPE_SHOUT) { - lldebugs << "You shout " << utf8_text << llendl; + LL_DEBUGS() << "You shout " << utf8_text << LL_ENDL; gAgent.sendAnimationRequest(ANIM_AGENT_SHOUT, ANIM_REQUEST_START); } else { - llinfos << "send_chat_from_viewer() - invalid volume" << llendl; + LL_INFOS() << "send_chat_from_viewer() - invalid volume" << LL_ENDL; return; } } @@ -708,30 +718,26 @@ void LLChatBar::sendChatFromViewer(const LLWString &wtext, EChatType type, BOOL { if (type != CHAT_TYPE_START && type != CHAT_TYPE_STOP) { - lldebugs << "Channel chat: " << utf8_text << llendl; + LL_DEBUGS() << "Channel chat: " << utf8_text << LL_ENDL; } } send_chat_from_viewer(utf8_out_text, type, channel); } -// [RLVa:KB] - Checked: 2009-07-07 (RLVa-1.0.0d) | Modified: RLVa-0.2.2a +//void send_chat_from_viewer(const std::string& utf8_out_text, EChatType type, S32 channel) +// [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0b) | Modified: RLVa-0.2.2a void send_chat_from_viewer(std::string utf8_out_text, EChatType type, S32 channel) // [/RLVa:KB] { // [RLVa:KB] - Checked: 2010-02-27 (RLVa-1.2.0b) | Modified: RLVa-1.2.0a // Only process chat messages (ie not CHAT_TYPE_START, CHAT_TYPE_STOP, etc) - if ( (rlv_handler_t::isEnabled()) && ( (CHAT_TYPE_WHISPER == type) || (CHAT_TYPE_NORMAL == type) || (CHAT_TYPE_SHOUT == type) ) ) + if ( (RlvActions::isRlvEnabled()) && ( (CHAT_TYPE_WHISPER == type) || (CHAT_TYPE_NORMAL == type) || (CHAT_TYPE_SHOUT == type) ) ) { if (0 == channel) { - // (We already did this before, but LLChatHandler::handle() calls this directly) - if ( ((CHAT_TYPE_SHOUT == type) || (CHAT_TYPE_NORMAL == type)) && (gRlvHandler.hasBehaviour(RLV_BHVR_CHATNORMAL)) ) - type = CHAT_TYPE_WHISPER; - else if ( (CHAT_TYPE_SHOUT == type) && (gRlvHandler.hasBehaviour(RLV_BHVR_CHATSHOUT)) ) - type = CHAT_TYPE_NORMAL; - else if ( (CHAT_TYPE_WHISPER == type) && (gRlvHandler.hasBehaviour(RLV_BHVR_CHATWHISPER)) ) - type = CHAT_TYPE_NORMAL; + // Clamp the volume of the chat if needed + type = RlvActions::checkChatVolume(type); // Redirect chat if needed if ( ( (gRlvHandler.hasBehaviour(RLV_BHVR_REDIRCHAT) || (gRlvHandler.hasBehaviour(RLV_BHVR_REDIREMOTE)) ) && @@ -747,7 +753,7 @@ void send_chat_from_viewer(std::string utf8_out_text, EChatType type, S32 channe else { // Don't allow chat on a non-public channel if sendchannel restricted (unless the channel is an exception) - if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SENDCHANNEL)) && (!gRlvHandler.isException(RLV_BHVR_SENDCHANNEL, channel)) ) + if (!RlvActions::canSendChannel(channel)) return; // Don't allow chat on debug channel if @sendchat, @redirchat or @rediremote restricted (shows as public chat on viewers) @@ -820,33 +826,29 @@ void send_chat_from_viewer(std::string utf8_out_text, EChatType type, S32 channe void really_send_chat_from_viewer(const std::string& utf8_out_text, EChatType type, S32 channel) { LLMessageSystem* msg = gMessageSystem; - // - if(channel >= 0) - { - // - msg->newMessageFast(_PREHASH_ChatFromViewer); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_ChatData); - msg->addStringFast(_PREHASH_Message, utf8_out_text); - msg->addU8Fast(_PREHASH_Type, type); - msg->addS32("Channel", channel); - // + if (channel >= 0) + { + msg->newMessageFast(_PREHASH_ChatFromViewer); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_ChatData); + msg->addStringFast(_PREHASH_Message, utf8_out_text); + msg->addU8Fast(_PREHASH_Type, type); + msg->addS32("Channel", channel); } else { - msg->newMessage("ScriptDialogReply"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID()); - msg->addUUID("SessionID", gAgent.getSessionID()); - msg->nextBlock("Data"); - msg->addUUID("ObjectID", gAgent.getID()); + msg->newMessageFast(_PREHASH_ScriptDialogReply); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_Data); + msg->addUUIDFast(_PREHASH_ObjectID, gAgent.getID()); msg->addS32("ChatChannel", channel); - msg->addS32("ButtonIndex", 0); - msg->addString("ButtonLabel", utf8_out_text); + msg->addS32Fast(_PREHASH_ButtonIndex, 0); + msg->addStringFast(_PREHASH_ButtonLabel, utf8_out_text); } - // gAgent.sendReliableMessage(); LLViewerStats::getInstance()->incStat(LLViewerStats::ST_CHAT_COUNT); @@ -879,7 +881,7 @@ void LLChatBar::onCommitGesture(LLUICtrl* ctrl) } } mGestureLabelTimer.start(); - if (mGestureCombo != NULL) + if (mGestureCombo != nullptr) { // free focus back to chat bar mGestureCombo->setFocus(FALSE); @@ -891,24 +893,39 @@ void toggleChatHistory() LLFloaterChat::toggleInstance(LLSD()); } +// +// LLChatCommandHandler +// -class LLChatHandler : public LLCommandHandler +class LLChatCommandHandler final : public LLCommandHandler { public: // not allowed from outside the app - LLChatHandler() : LLCommandHandler("chat", UNTRUSTED_BLOCK) { } + LLChatCommandHandler() : LLCommandHandler("chat", UNTRUSTED_BLOCK) { } // Your code here bool handle(const LLSD& tokens, const LLSD& query_map, - LLMediaCtrl* web) + LLMediaCtrl* web) override { - if (tokens.size() < 2) return false; - S32 channel = tokens[0].asInteger(); - std::string mesg = tokens[1].asString(); - send_chat_from_viewer(mesg, CHAT_TYPE_NORMAL, channel); - return true; + bool retval = false; + // Need at least 2 tokens to have a valid message. + if (tokens.size() < 2) + { + retval = false; + } + else + { + S32 channel = tokens[0].asInteger(); + { + retval = true; + // Send unescaped message, see EXT-6353. + std::string unescaped_mesg (LLURI::unescape(tokens[1].asString())); + send_chat_from_viewer(unescaped_mesg, CHAT_TYPE_NORMAL, channel); + } + } + return retval; } }; // Creating the object registers with the dispatcher. -LLChatHandler gChatHandler; +LLChatCommandHandler gChatHandler; diff --git a/indra/newview/llchatbar.h b/indra/newview/llchatbar.h index b031e312a1..656da51324 100644 --- a/indra/newview/llchatbar.h +++ b/indra/newview/llchatbar.h @@ -33,10 +33,9 @@ #ifndef LL_LLCHATBAR_H #define LL_LLCHATBAR_H -#include "llpanel.h" #include "llframetimer.h" #include "llchat.h" -#include "lllayoutstack.h" +#include "llpanel.h" class LLLineEditor; class LLMessageSystem; @@ -46,17 +45,19 @@ class LLFrameTimer; class LLChatBarGestureObserver; class LLComboBox; -class LLChatBar : public LLPanel + +class LLChatBar final +: public LLPanel { public: // constructor for inline chat-bars (e.g. hosted in chat history window) LLChatBar(); - ~LLChatBar(); - virtual BOOL postBuild(); - virtual BOOL handleKeyHere(KEY key, MASK mask); + BOOL postBuild() override; + BOOL handleKeyHere(KEY key, MASK mask) override; + void onFocusLost() override; - void refresh(); + void refresh() override; void refreshGestures(); // Move cursor into chat input field. @@ -65,8 +66,8 @@ class LLChatBar : public LLPanel // Ignore arrow keys for chat bar void setIgnoreArrowKeys(BOOL b); - BOOL inputEditorHasFocus(); - std::string getCurrentChat(); + BOOL inputEditorHasFocus() const; + std::string getCurrentChat() const; // since chat bar logic is reused for chat history // gesture combo box might not be a direct child @@ -84,7 +85,6 @@ class LLChatBar : public LLPanel // callbacks void onClickSay(LLUICtrl* ctrl); - static void onTabClick( void* userdata ); void onInputEditorKeystroke(); static void onInputEditorFocusLost(); static void onInputEditorGainFocus(); @@ -95,10 +95,11 @@ class LLChatBar : public LLPanel static void stopChat(); protected: + ~LLChatBar(); + void sendChat(EChatType type); void updateChat(); -protected: LLLineEditor* mInputEditor; LLFrameTimer mGestureLabelTimer; diff --git a/indra/newview/llclassifiedstatsresponder.cpp b/indra/newview/llclassifiedstatsresponder.cpp index a218e2b4e5..aa137605ee 100644 --- a/indra/newview/llclassifiedstatsresponder.cpp +++ b/indra/newview/llclassifiedstatsresponder.cpp @@ -50,16 +50,16 @@ mClassifiedID(classified_id) { } /*virtual*/ -void LLClassifiedStatsResponder::result(const LLSD& content) +void LLClassifiedStatsResponder::httpSuccess(void) { - S32 teleport = content["teleport_clicks"].asInteger(); - S32 map = content["map_clicks"].asInteger(); - S32 profile = content["profile_clicks"].asInteger(); - S32 search_teleport = content["search_teleport_clicks"].asInteger(); - S32 search_map = content["search_map_clicks"].asInteger(); - S32 search_profile = content["search_profile_clicks"].asInteger(); + S32 teleport = mContent["teleport_clicks"].asInteger(); + S32 map = mContent["map_clicks"].asInteger(); + S32 profile = mContent["profile_clicks"].asInteger(); + S32 search_teleport = mContent["search_teleport_clicks"].asInteger(); + S32 search_map = mContent["search_map_clicks"].asInteger(); + S32 search_profile = mContent["search_profile_clicks"].asInteger(); - LLPanelClassified* classified_panelp = (LLPanelClassified*)mClassifiedPanelHandle.get(); + LLPanelClassifiedInfo* classified_panelp = (LLPanelClassifiedInfo*)mClassifiedPanelHandle.get(); if(classified_panelp) { @@ -73,10 +73,9 @@ void LLClassifiedStatsResponder::result(const LLSD& content) } /*virtual*/ -void LLClassifiedStatsResponder::error(U32 status, const std::string& reason) +void LLClassifiedStatsResponder::httpFailure(void) { - llinfos << "LLClassifiedStatsResponder::error(" - << status << ": " << reason << ")" << llendl; + LL_INFOS() << "httpFailure: " << dumpResponse() << LL_ENDL; } diff --git a/indra/newview/llclassifiedstatsresponder.h b/indra/newview/llclassifiedstatsresponder.h index d44d43f78f..4eacd3b615 100644 --- a/indra/newview/llclassifiedstatsresponder.h +++ b/indra/newview/llclassifiedstatsresponder.h @@ -45,9 +45,9 @@ class LLClassifiedStatsResponder : public LLHTTPClient::ResponderWithResult public: LLClassifiedStatsResponder(LLHandle classified_panel_handle, LLUUID classified_id); //If we get back a normal response, handle it here - /*virtual*/ void result(const LLSD& content); + /*virtual*/ void httpSuccess(void); //If we get back an error (not found, etc...), handle it here - /*virtual*/ void error(U32 status, const std::string& reason); + /*virtual*/ void httpFailure(void); /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return classifiedStatsResponder_timeout; } /*virtual*/ char const* getName(void) const { return "LLClassifiedStatsResponder"; } diff --git a/indra/newview/llcloud.cpp b/indra/newview/llcloud.cpp index fcdfbecd4b..0d38ecbb65 100644 --- a/indra/newview/llcloud.cpp +++ b/indra/newview/llcloud.cpp @@ -161,17 +161,17 @@ void LLCloudGroup::updatePuffOwnership() continue; } - //llinfos << "Cloud moving to new group" << llendl; + //LL_INFOS() << "Cloud moving to new group" << LL_ENDL; LLCloudGroup *new_cgp = LLWorld::getInstance()->findCloudGroup(mCloudPuffs[i]); if (!new_cgp) { - //llinfos << "Killing puff not in group" << llendl; + //LL_INFOS() << "Killing puff not in group" << LL_ENDL; mCloudPuffs[i].setLifeState(LL_PUFF_DYING); mCloudPuffs[i].mRate = CLOUD_DECAY_RATE*CLOUD_UPDATE_RATE; i++; continue; } - //llinfos << "Puff handed off!" << llendl; + //LL_INFOS() << "Puff handed off!" << LL_ENDL; LLCloudPuff puff; puff.mPositionGlobal = mCloudPuffs[i].mPositionGlobal; puff.mAlpha = mCloudPuffs[i].mAlpha; @@ -179,7 +179,7 @@ void LLCloudGroup::updatePuffOwnership() new_cgp->mCloudPuffs.push_back(puff); } - //llinfos << "Puff count: " << LLCloudPuff::sPuffCount << llendl; + //LL_INFOS() << "Puff count: " << LLCloudPuff::sPuffCount << LL_ENDL; } void LLCloudGroup::updatePuffCount() @@ -189,7 +189,7 @@ void LLCloudGroup::updatePuffCount() return; } S32 i; - S32 target_puff_count = llround(CLOUD_DENSITY * mDensity); + S32 target_puff_count = ll_round(CLOUD_DENSITY * mDensity); target_puff_count = llmax(0, target_puff_count); target_puff_count = llmin(CLOUD_COUNT_MAX, target_puff_count); S32 current_puff_count = (S32) mCloudPuffs.size(); @@ -229,7 +229,7 @@ void LLCloudGroup::updatePuffCount() { if (mCloudPuffs[i].getLifeState() != LL_PUFF_DYING) { - //llinfos << "Killing extra live cloud" << llendl; + //LL_INFOS() << "Killing extra live cloud" << LL_ENDL; mCloudPuffs[i].setLifeState(LL_PUFF_DYING); mCloudPuffs[i].mRate = CLOUD_DECAY_RATE*CLOUD_UPDATE_RATE; new_dying_count--; @@ -243,7 +243,7 @@ void LLCloudGroup::updatePuffCount() { if (mCloudPuffs[i].isDead()) { - //llinfos << "Removing dead puff!" << llendl; + //LL_INFOS() << "Removing dead puff!" << LL_ENDL; mCloudPuffs.erase(mCloudPuffs.begin() + i); LLCloudPuff::sPuffCount--; } @@ -515,6 +515,10 @@ void LLCloudLayer::connectNeighbor(LLCloudLayer *cloudp, U32 direction) return; } + if (mNeighbors[direction]) + { + mNeighbors[direction]->mNeighbors[gDirOpposite[direction]] = NULL; + } mNeighbors[direction] = cloudp; if (cloudp) mNeighbors[direction]->mNeighbors[gDirOpposite[direction]] = this; diff --git a/indra/newview/llcloud.h b/indra/newview/llcloud.h index b3fd6f6818..d7863c27f3 100644 --- a/indra/newview/llcloud.h +++ b/indra/newview/llcloud.h @@ -73,7 +73,6 @@ #include "v4math.h" #include "v4color.h" #include "llmemory.h" -#include "lldarray.h" #include "llframetimer.h" diff --git a/indra/newview/llcolorswatch.cpp b/indra/newview/llcolorswatch.cpp index 61fcd5d7be..3efba0c998 100644 --- a/indra/newview/llcolorswatch.cpp +++ b/indra/newview/llcolorswatch.cpp @@ -213,7 +213,7 @@ void LLColorSwatchCtrl::draw() { if (!mFallbackImageName.empty()) { - LLPointer fallback_image = LLViewerTextureManager::getFetchedTextureFromFile(mFallbackImageName, TRUE, + LLPointer fallback_image = LLViewerTextureManager::getFetchedTextureFromFile(mFallbackImageName, FTT_LOCAL_FILE, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); if( fallback_image->getComponents() == 4 ) { diff --git a/indra/newview/llcommandlineparser.cpp b/indra/newview/llcommandlineparser.cpp index 38dcc8aab7..17a869e873 100644 --- a/indra/newview/llcommandlineparser.cpp +++ b/indra/newview/llcommandlineparser.cpp @@ -181,12 +181,18 @@ class LLCLPValue : public po::value_semantic_codecvt_helper { mNotifyCallback(*value); } + } + virtual bool is_required(void) const + { + return mIsRequired; } - virtual bool is_required(void) const - { - return mIsRequired; - } + + virtual bool adjacent_tokens_only() const + { + return false; + } + protected: void xparse(boost::any& value_store, const std::vector& new_tokens) const @@ -287,19 +293,19 @@ bool LLCommandLineParser::parseAndStoreResults(po::command_line_parser& clp) po::basic_parsed_options opts = clp.run(); po::store(opts, gVariableMap); } - catch(po::error& e) + catch (const po::error& e) { - llwarns << "Caught Error:" << e.what() << llendl; + LL_WARNS() << "Caught Error:" << e.what() << LL_ENDL; mErrorMsg = e.what(); return false; } - catch(LLCLPError& e) + catch (const LLCLPError& e) { - llwarns << "Caught Error:" << e.what() << llendl; + LL_WARNS() << "Caught Error:" << e.what() << LL_ENDL; mErrorMsg = e.what(); return false; } - catch(LLCLPLastOption&) + catch (const LLCLPLastOption&) { // This exception means a token was read after an option // that must be the last option was reached (see url and slurl options) @@ -335,7 +341,7 @@ bool LLCommandLineParser::parseAndStoreResults(po::command_line_parser& clp) << last_option << " " << last_value; - llwarns << msg.str() << llendl; + LL_WARNS() << msg.str() << LL_ENDL; mErrorMsg = msg.str(); return false; } @@ -348,18 +354,58 @@ bool LLCommandLineParser::parseCommandLine(int argc, char **argv) return parseAndStoreResults(clp); } +// TODO: +// - Break out this funky parsing logic into separate method +// - Unit-test it with tests like LLStringUtil::getTokens() (the command-line +// overload that supports quoted tokens) +// - Unless this logic offers significant semantic benefits, replace it with +// LLStringUtil::getTokens(). This would fix a known bug: you cannot --set a +// string-valued variable to the empty string, because empty strings are +// eliminated below. + bool LLCommandLineParser::parseCommandLineString(const std::string& str) { + std::string cmd_line_string(""); + if (!str.empty()) + { + bool add_last_c = true; + S32 last_c_pos = str.size() - 1; //don't get out of bounds on pos+1, last char will be processed separately + for (S32 pos = 0; pos < last_c_pos; ++pos) + { + cmd_line_string.append(&str[pos], 1); + if (str[pos] == '\\') + { + cmd_line_string.append("\\", 1); + if (str[pos + 1] == '\\') + { + ++pos; + add_last_c = (pos != last_c_pos); + } + } + } + if (add_last_c) + { + cmd_line_string.append(&str[last_c_pos], 1); + if (str[last_c_pos] == '\\') + { + cmd_line_string.append("\\", 1); + } + } + } + // Split the string content into tokens - boost::escaped_list_separator sep("\\", "\r\n ", "\"'"); - boost::tokenizer< boost::escaped_list_separator > tok(str, sep); + const char* escape_chars = "\\"; + const char* separator_chars = "\r\n "; + const char* quote_chars = "\"'"; + boost::escaped_list_separator sep(escape_chars, separator_chars, quote_chars); + boost::tokenizer< boost::escaped_list_separator > tok(cmd_line_string, sep); std::vector tokens; // std::copy(tok.begin(), tok.end(), std::back_inserter(tokens)); for(boost::tokenizer< boost::escaped_list_separator >::iterator i = tok.begin(); i != tok.end(); ++i) { - if(0 != i->size()) + if(!i->empty()) { tokens.push_back(*i); } @@ -380,22 +426,30 @@ bool LLCommandLineParser::parseCommandLineFile(const std::basic_istream < char > void LLCommandLineParser::notify() { - po::notify(gVariableMap); + try + { + po::notify(gVariableMap); + } + catch (const LLCLPError& e) + { + LL_WARNS() << "Caught Error: " << e.what() << LL_ENDL; + mErrorMsg = e.what(); + } } void LLCommandLineParser::printOptions() const { - for(po::variables_map::iterator i = gVariableMap.begin(); i != gVariableMap.end(); ++i) + for (auto& i : gVariableMap) { - std::string name = i->first; - token_vector_t values = i->second.as(); + std::string name = i.first; + token_vector_t values = i.second.as(); std::ostringstream oss; oss << name << ": "; - for(token_vector_t::iterator t_itr = values.begin(); t_itr != values.end(); ++t_itr) + for (auto& value : values) { - oss << t_itr->c_str() << " "; + oss << value.c_str() << " "; } - llinfos << oss.str() << llendl; + LL_INFOS() << oss.str() << LL_ENDL; } } @@ -440,7 +494,7 @@ void setControlValueCB(const LLCommandLineParser::token_vector_t& value, case TYPE_BOOLEAN: if(value.size() > 1) { - llwarns << "Ignoring extra tokens." << llendl; + LL_WARNS() << "Ignoring extra tokens." << LL_ENDL; } if(value.size() > 0) @@ -479,7 +533,7 @@ void setControlValueCB(const LLCommandLineParser::token_vector_t& value, { if(value.size() > 1) { - llwarns << "Ignoring extra tokens mapped to the setting: " << opt_name << "." << llendl; + LL_WARNS() << "Ignoring extra tokens mapped to the setting: " << opt_name << "." << LL_ENDL; } LLSD llsdValue; @@ -492,10 +546,10 @@ void setControlValueCB(const LLCommandLineParser::token_vector_t& value, } else { - llwarns << "Command Line option mapping '" + LL_WARNS() << "Command Line option mapping '" << opt_name << "' not found! Ignoring." - << llendl; + << LL_ENDL; } } diff --git a/indra/newview/llcompilequeue.cpp b/indra/newview/llcompilequeue.cpp index dd260711ad..0e4a0168fd 100644 --- a/indra/newview/llcompilequeue.cpp +++ b/indra/newview/llcompilequeue.cpp @@ -50,13 +50,13 @@ #include "llviewerobject.h" #include "llviewerobjectlist.h" #include "llviewerregion.h" -//#include "lscript_rt_interface.h" #include "llviewercontrol.h" #include "llviewerobject.h" #include "llviewerregion.h" #include "llresmgr.h" #include "llbutton.h" +#include "llscrolllistctrl.h" #include "lldir.h" #include "llnotificationsutil.h" #include "llfloaterchat.h" @@ -65,6 +65,10 @@ #include "lltrans.h" #include "llselectmgr.h" +#include "llexperiencecache.h" + +// *TODO: This should be separated into the script queue, and the floater views of that queue. +// There should only be one floater class that can view any queue type ///---------------------------------------------------------------------------- /// Local function declarations, constants, enums, and typedefs @@ -73,12 +77,12 @@ struct LLScriptQueueData { LLUUID mQueueID; - std::string mScriptName; + LLPointer mItemp; LLUUID mTaskId; - LLUUID mItemId; - LLScriptQueueData(const LLUUID& q_id, const std::string& name, const LLUUID& task_id, const LLUUID& item_id) : - mQueueID(q_id), mScriptName(name), mTaskId(task_id), mItemId(item_id) {} - + LLUUID mExperienceId; + LLHost mHost; + LLScriptQueueData(const LLUUID& q_id, const LLUUID& task_id, LLInventoryItem* item, const LLHost& host) : + mQueueID(q_id), mTaskId(task_id), mItemp(item), mHost(host) {} }; ///---------------------------------------------------------------------------- @@ -96,22 +100,20 @@ LLFloaterScriptQueue::LLFloaterScriptQueue(const std::string& name, const std::string& start_string) : LLFloater(name, rect, title, RESIZE_YES, DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT, - DRAG_ON_TOP, MINIMIZE_YES, CLOSE_YES) + DRAG_ON_TOP, MINIMIZE_YES, CLOSE_YES), + mMessages(nullptr), + mCloseBtn(nullptr), + mDone(false), + mMono(false) { mID.generate(); LLUICtrlFactory::getInstance()->buildFloater(this,"floater_script_queue.xml"); - - childSetAction("close",onCloseBtn,this); - childSetEnabled("close",FALSE); - setTitle(title); LLRect curRect = getRect(); translate(rect.mLeft - curRect.mLeft, rect.mTop - curRect.mTop); - mStartString = start_string; - mDone = FALSE; sInstances.addData(mID, this); } @@ -121,18 +123,20 @@ LLFloaterScriptQueue::~LLFloaterScriptQueue() sInstances.removeData(mID); } +BOOL LLFloaterScriptQueue::postBuild() +{ + childSetAction("close",onCloseBtn,this); + getChildView("close")->setEnabled(FALSE); + return TRUE; +} + // find an instance by ID. Return NULL if it does not exist. // static LLFloaterScriptQueue* LLFloaterScriptQueue::findInstance(const LLUUID& id) { - if(sInstances.checkData(id)) - { - return sInstances.getData(id); - } - return NULL; + return sInstances.checkData(id) ? sInstances.getData(id) : NULL; } - // This is the callback method for the viewer object currently being // worked on. // NOT static, virtual! @@ -141,8 +145,8 @@ void LLFloaterScriptQueue::inventoryChanged(LLViewerObject* viewer_object, S32, void* q_id) { - llinfos << "LLFloaterScriptQueue::inventoryChanged() for object " - << viewer_object->getID() << llendl; + LL_INFOS() << "LLFloaterScriptQueue::inventoryChanged() for object " + << viewer_object->getID() << LL_ENDL; //Remove this listener from the object since its //listener callback is now being executed. @@ -167,8 +171,8 @@ void LLFloaterScriptQueue::inventoryChanged(LLViewerObject* viewer_object, // something went wrong... // note that we're not working on this one, and move onto the // next object in the list. - llwarns << "No inventory for " << mCurrentObjectID - << llendl; + LL_WARNS() << "No inventory for " << mCurrentObjectID + << LL_ENDL; nextObject(); } } @@ -183,50 +187,49 @@ void LLFloaterScriptQueue::onCloseBtn(void* user_data) void LLFloaterScriptQueue::addObject(const LLUUID& id) { - mObjectIDs.put(id); + mObjectIDs.push_back(id); } BOOL LLFloaterScriptQueue::start() { - //llinfos << "LLFloaterCompileQueue::start()" << llendl; std::string buffer; LLStringUtil::format_map_t args; args["[START]"] = mStartString; - args["[COUNT]"] = llformat ("%d", mObjectIDs.count()); + args["[COUNT]"] = llformat ("%d", mObjectIDs.size()); buffer = getString ("Starting", args); getChild("queue output")->addSimpleElement(buffer, ADD_BOTTOM); - return nextObject(); + return startQueue(); } BOOL LLFloaterScriptQueue::isDone() const { - return (mCurrentObjectID.isNull() && (mObjectIDs.count() == 0)); + return (mCurrentObjectID.isNull() && (mObjectIDs.size() == 0)); } // go to the next object. If no objects left, it falls out silently // and waits to be killed by the window being closed. BOOL LLFloaterScriptQueue::nextObject() { - S32 count; + U32 count; BOOL successful_start = FALSE; do { - count = mObjectIDs.count(); - llinfos << "LLFloaterScriptQueue::nextObject() - " << count - << " objects left to process." << llendl; + count = mObjectIDs.size(); + LL_INFOS() << "LLFloaterScriptQueue::nextObject() - " << count + << " objects left to process." << LL_ENDL; mCurrentObjectID.setNull(); - if(count > 0) + if (count > 0) { successful_start = popNext(); } - llinfos << "LLFloaterScriptQueue::nextObject() " + LL_INFOS() << "LLFloaterScriptQueue::nextObject() " << (successful_start ? "successful" : "unsuccessful") - << llendl; - } while((mObjectIDs.count() > 0) && !successful_start); - if(isDone() && !mDone) + << LL_ENDL; + } while((mObjectIDs.size() > 0) && !successful_start); + if (isDone() && !mDone) { mDone = true; getChild("queue output")->addSimpleElement(getString("Done"), ADD_BOTTOM); @@ -242,18 +245,18 @@ BOOL LLFloaterScriptQueue::popNext() // get the first element off of the container, and attempt to get // the inventory. BOOL rv = FALSE; - S32 count = mObjectIDs.count(); - if(mCurrentObjectID.isNull() && (count > 0)) + S32 count = mObjectIDs.size(); + if (mCurrentObjectID.isNull() && (count > 0)) { - mCurrentObjectID = mObjectIDs.get(0); - llinfos << "LLFloaterScriptQueue::popNext() - mCurrentID: " - << mCurrentObjectID << llendl; - mObjectIDs.remove(0); + mCurrentObjectID = mObjectIDs.at(0); + LL_INFOS() << "LLFloaterScriptQueue::popNext() - mCurrentID: " + << mCurrentObjectID << LL_ENDL; + mObjectIDs.erase(mObjectIDs.begin()); LLViewerObject* obj = gObjectList.findObject(mCurrentObjectID); - if(obj) + if (obj) { - llinfos << "LLFloaterScriptQueue::popNext() requesting inv for " - << mCurrentObjectID << llendl; + LL_INFOS() << "LLFloaterScriptQueue::popNext() requesting inv for " + << mCurrentObjectID << LL_ENDL; LLUUID* id = new LLUUID(mID); registerVOInventoryListener(obj,id); requestVOInventory(); @@ -263,6 +266,28 @@ BOOL LLFloaterScriptQueue::popNext() return rv; } +BOOL LLFloaterScriptQueue::startQueue() +{ + return nextObject(); +} + +class CompileQueueExperienceResponder final : public LLHTTPClient::ResponderWithResult +{ + const LLUUID mParent; +public: + CompileQueueExperienceResponder(const LLUUID& parent): mParent(parent) {} + + void httpSuccess() override { sendResult(getContent()); } + void httpFailure() override { sendResult(LLSD()); } + void sendResult(const LLSD& content) + { + if (auto queue = static_cast(LLFloaterCompileQueue::findInstance(mParent))) + queue->experienceIdsReceived(content["experience_ids"]); + } + char const* getName() const override { return "CompileQueueExperienceResponder"; } +}; + + ///---------------------------------------------------------------------------- /// Class LLFloaterCompileQueue @@ -280,7 +305,7 @@ class LLCompileFloaterUploadQueueSupplier : public LLAssetUploadQueueSupplier virtual LLAssetUploadQueue* get() const { LLFloaterCompileQueue* queue = (LLFloaterCompileQueue*) LLFloaterScriptQueue::findInstance(mQueueId); - if(NULL == queue) + if (NULL == queue) { return NULL; } @@ -290,7 +315,7 @@ class LLCompileFloaterUploadQueueSupplier : public LLAssetUploadQueueSupplier virtual void log(std::string message) const { LLFloaterCompileQueue* queue = (LLFloaterCompileQueue*) LLFloaterScriptQueue::findInstance(mQueueId); - if(NULL == queue) + if (NULL == queue) { return; } @@ -303,7 +328,7 @@ class LLCompileFloaterUploadQueueSupplier : public LLAssetUploadQueueSupplier }; // static -LLFloaterCompileQueue* LLFloaterCompileQueue::create(BOOL mono) +LLFloaterCompileQueue* LLFloaterCompileQueue::create(bool mono) { S32 left, top; gFloaterView->getNewFloaterPosition(&left, &top); @@ -312,7 +337,7 @@ LLFloaterCompileQueue* LLFloaterCompileQueue::create(BOOL mono) LLFloaterCompileQueue* new_queue = new LLFloaterCompileQueue("queue", rect); new_queue->mUploadQueue = new LLAssetUploadQueue(new LLCompileFloaterUploadQueueSupplier(new_queue->getID())); - new_queue->mMono = mono; + new_queue->setMono(mono); new_queue->open(); return new_queue; } @@ -325,6 +350,21 @@ LLFloaterCompileQueue::~LLFloaterCompileQueue() { } +void LLFloaterCompileQueue::experienceIdsReceived(const LLSD& content) +{ + for(LLSD::array_const_iterator it = content.beginArray(); it != content.endArray(); ++it) + { + mExperienceIds.insert(it->asUUID()); + } + nextObject(); +} + +BOOL LLFloaterCompileQueue::hasExperience(const LLUUID& id) const +{ + return mExperienceIds.find(id) != mExperienceIds.end(); +} + + void LLFloaterCompileQueue::handleInventory(LLViewerObject *viewer_object, LLInventoryObject::object_list_t* inv) { @@ -338,7 +378,7 @@ void LLFloaterCompileQueue::handleInventory(LLViewerObject *viewer_object, LLInventoryObject::object_list_t::const_iterator end = inv->end(); for ( ; it != end; ++it) { - if((*it)->getType() == LLAssetType::AT_LSL_TEXT) + if ((*it)->getType() == LLAssetType::AT_LSL_TEXT) { LLInventoryItem* item = (LLInventoryItem*)((LLInventoryObject*)(*it)); // Check permissions before allowing the user to retrieve data. @@ -346,7 +386,7 @@ void LLFloaterCompileQueue::handleInventory(LLViewerObject *viewer_object, item->getPermissions().allowCopyBy(gAgent.getID(), gAgent.getGroupID()) ) { LLPointer script = new LLViewerInventoryItem(item); - mCurrentScripts.put(script); + mCurrentScripts.push_back(script); asset_item_map.insert(std::make_pair(item->getAssetUUID(), item)); } } @@ -359,46 +399,87 @@ void LLFloaterCompileQueue::handleInventory(LLViewerObject *viewer_object, } else { + LLViewerRegion* region = viewer_object->getRegion(); + std::string url = std::string(); + if (region) + { + url = region->getCapability("GetMetadata"); + } + + const auto& host = region->getHost(); + const auto& obj_id = viewer_object->getID(); // request all of the assets. - uuid_item_map::iterator iter; - for(iter = asset_item_map.begin(); iter != asset_item_map.end(); iter++) + for(const auto& pair : asset_item_map) { - LLInventoryItem *itemp = iter->second; + LLInventoryItem *itemp = pair.second; LLScriptQueueData* datap = new LLScriptQueueData(getID(), - itemp->getName(), - viewer_object->getID(), - itemp->getUUID()); - - //llinfos << "ITEM NAME 2: " << names.get(i) << llendl; - gAssetStorage->getInvItemAsset(viewer_object->getRegion()->getHost(), - gAgent.getID(), - gAgent.getSessionID(), - itemp->getPermissions().getOwner(), - viewer_object->getID(), - itemp->getUUID(), - itemp->getAssetUUID(), - itemp->getType(), - LLFloaterCompileQueue::scriptArrived, - (void*)datap); + obj_id, + itemp, + host); + + LLExperienceCache::instance().fetchAssociatedExperience(itemp->getParentUUID(), itemp->getUUID(), + boost::bind(LLFloaterCompileQueue::requestAsset, datap, _1)); } } } +void LLFloaterCompileQueue::requestAsset(LLScriptQueueData* datap, const LLSD& experience) +{ + LLFloaterCompileQueue* queue = static_cast(findInstance(datap->mQueueID)); + if (!queue) + { + delete datap; + return; + } + + if (experience.has(LLExperienceCache::EXPERIENCE_ID)) + { + datap->mExperienceId = experience[LLExperienceCache::EXPERIENCE_ID].asUUID(); + if (!queue->hasExperience(datap->mExperienceId)) + { + std::string buffer = LLTrans::getString("CompileNoExperiencePerm", LLSD::emptyMap() + .with("SCRIPT", datap->mItemp->getName()) + .with("EXPERIENCE", experience[LLExperienceCache::NAME].asString())); + + queue->getChild("queue output")->addSimpleElement(buffer, ADD_BOTTOM); + queue->removeItemByItemID(datap->mItemp->getUUID()); + delete datap; + return; + } + } + + //LL_INFOS() << "ITEM NAME 2: " << names.get(i) << LL_ENDL; + gAssetStorage->getInvItemAsset(datap->mHost, + gAgent.getID(), + gAgent.getSessionID(), + datap->mItemp->getPermissions().getOwner(), + datap->mTaskId, + datap->mItemp->getUUID(), + datap->mItemp->getAssetUUID(), + datap->mItemp->getType(), + LLFloaterCompileQueue::scriptArrived, + (void*)datap); +} + + // This is the callback for when each script arrives // static void LLFloaterCompileQueue::scriptArrived(LLVFS *vfs, const LLUUID& asset_id, LLAssetType::EType type, void* user_data, S32 status, LLExtStat ext_status) { - llinfos << "LLFloaterCompileQueue::scriptArrived()" << llendl; + LL_INFOS() << "LLFloaterCompileQueue::scriptArrived()" << LL_ENDL; LLScriptQueueData* data = (LLScriptQueueData*)user_data; - if(!data) return; + if(!data) + { + return; + } LLFloaterCompileQueue* queue = static_cast (LLFloaterScriptQueue::findInstance(data->mQueueID)); std::string buffer; - if(queue && (0 == status)) + if (queue && (0 == status)) { - //llinfos << "ITEM NAME 3: " << data->mScriptName << llendl; + //LL_INFOS() << "ITEM NAME 3: " << data->mItemp->getName() << LL_ENDL; // Dump this into a file on the local disk so we can compile it. std::string filename; @@ -412,204 +493,71 @@ void LLFloaterCompileQueue::scriptArrived(LLVFS *vfs, const LLUUID& asset_id, if (object) { std::string url = object->getRegion()->getCapability("UpdateScriptTask"); - if(!url.empty()) + if (!url.empty()) { // Read script source in to buffer. U32 script_size = file.getSize(); - char* script_data = new char[script_size]; - file.read(reinterpret_cast(script_data), script_size); + U8* script_data = new U8[script_size]; + file.read(script_data, script_size); queue->mUploadQueue->queue(filename, data->mTaskId, - data->mItemId, is_running, queue->mMono, queue->getID(), - script_data, script_size, data->mScriptName); + data->mItemp->getUUID(), is_running, queue->mMono, queue->getID(), + script_data, script_size, data->mItemp->getName(), data->mExperienceId); } else { std::string text = LLTrans::getString("CompileQueueProblemUploading"); LLChat chat(text); LLFloaterChat::addChat(chat); - buffer = text + LLTrans::getString(":") + " " + data->mScriptName; - llwarns << "Problem uploading script asset." << llendl; - if(queue) queue->removeItemByItemID(data->mItemId); + buffer = text + LLTrans::getString(":") + ' ' + data->mItemp->getName(); + LL_WARNS() << "Problem uploading script asset." << LL_ENDL; + if(queue) queue->removeItemByItemID(data->mItemp->getUUID()); } -#if 0 //Client side compiling disabled. - else - { - // It's now in the file, now compile it. - buffer = LLTrans::getString("CompileQueueDownloadedCompiling") + (": ") + data->mScriptName; - - // Write script to local file for compilation. - LLFILE *fp = LLFile::fopen(filename, "wb"); /*Flawfinder: ignore*/ - if (fp) - { - const S32 buf_size = 65536; - U8 copy_buf[buf_size]; - - while (file.read(copy_buf, buf_size)) /*Flawfinder: ignore*/ - { - if (fwrite(copy_buf, file.getLastBytesRead(), 1, fp) < 1) - { - // return a bad file error if we can't write the whole thing - status = LL_ERR_CANNOT_OPEN_FILE; - } - } - - fclose(fp); - } - else - { - llerrs << "Unable to find object to compile" << llendl; - } - - // TODO: babbage: No compile if no cap. - queue->compile(filename, data->mItemId); - - // Delete it after we're done compiling? - LLFile::remove(filename); - } -#endif } } else { LLViewerStats::getInstance()->incStat( LLViewerStats::ST_DOWNLOAD_FAILED ); - if( LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status ) + if ( LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status ) { LLChat chat(LLTrans::getString("CompileQueueScriptNotFound")); LLFloaterChat::addChat(chat); - buffer = LLTrans::getString("CompileQueueProblemDownloading") + LLTrans::getString(":") + " " + data->mScriptName; + buffer = LLTrans::getString("CompileQueueProblemDownloading") + LLTrans::getString(":") + ' ' + data->mItemp->getName(); } else if (LL_ERR_INSUFFICIENT_PERMISSIONS == status) { LLChat chat(LLTrans::getString("CompileQueueInsufficientPermDownload")); LLFloaterChat::addChat(chat); - buffer = LLTrans::getString("CompileQueueInsufficientPermFor") + LLTrans::getString(":") + " " + data->mScriptName; + buffer = LLTrans::getString("CompileQueueInsufficientPermFor") + LLTrans::getString(":") + ' ' + data->mItemp->getName(); } else { - buffer = LLTrans::getString("CompileQueueUnknownFailure") + (" ") + data->mScriptName; + buffer = LLTrans::getString("CompileQueueUnknownFailure") + ' ' + data->mItemp->getName(); } - llwarns << "Problem downloading script asset." << llendl; - if(queue) queue->removeItemByItemID(data->mItemId); + LL_WARNS() << "Problem downloading script asset." << LL_ENDL; + if(queue) queue->removeItemByItemID(data->mItemp->getUUID()); } - if(queue && (buffer.size() > 0)) + if (queue && (buffer.size() > 0)) { queue->getChild("queue output")->addSimpleElement(buffer, ADD_BOTTOM); } delete data; } -#if 0 //Client side compiling disabled. -// static -void LLFloaterCompileQueue::onSaveTextComplete(const LLUUID& asset_id, void* user_data, S32 status, LLExtStat ext_status) // StoreAssetData callback (fixed) -{ - llinfos << "LLFloaterCompileQueue::onSaveTextComplete()" << llendl; - if (status) - { - llwarns << "Unable to save text for script." << llendl; - LLSD args; - args["REASON"] = std::string(LLAssetStorage::getErrorString(status)); - LLNotificationsUtil::add("CompileQueueSaveText", args); - } -} - -// static -void LLFloaterCompileQueue::onSaveBytecodeComplete(const LLUUID& asset_id, void* user_data, S32 status, LLExtStat ext_status) // StoreAssetData callback (fixed) -{ - llinfos << "LLFloaterCompileQueue::onSaveBytecodeComplete()" << llendl; - LLCompileQueueData* data = (LLCompileQueueData*)user_data; - LLFloaterCompileQueue* queue = static_cast (LLFloaterScriptQueue::findInstance(data->mQueueID)); - if(queue && (0 == status) && data) - { - queue->saveItemByItemID(data->mItemId); - queue->removeItemByItemID(data->mItemId); - } - else - { - llwarns << "Unable to save bytecode for script." << llendl; - LLSD args; - args["REASON"] = std::string(LLAssetStorage::getErrorString(status)); - LLNotificationsUtil::add("CompileQueueSaveBytecode", args); - } - delete data; - data = NULL; -} - -// compile the file given and save it out. -void LLFloaterCompileQueue::compile(const std::string& filename, - const LLUUID& item_id) -{ - LLUUID new_asset_id; - LLTransactionID tid; - tid.generate(); - new_asset_id = tid.makeAssetID(gAgent.getSecureSessionID()); - - std::string uuid_string; - new_asset_id.toString(uuid_string); - std::string dst_filename; - dst_filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_string) + ".lso"; - std::string err_filename; - err_filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_string) + ".out"; - - gAssetStorage->storeAssetData(filename, tid, - LLAssetType::AT_LSL_TEXT, - &onSaveTextComplete, NULL, FALSE); - - const BOOL compile_to_mono = FALSE; - if(!lscript_compile(filename.c_str(), dst_filename.c_str(), - err_filename.c_str(), compile_to_mono, - uuid_string.c_str(), gAgent.isGodlike())) - { - llwarns << "compile failed" << llendl; - removeItemByItemID(item_id); - } - else - { - llinfos << "compile successful." << llendl; - - // Save LSL bytecode - LLCompileQueueData* data = new LLCompileQueueData(mID, item_id); - gAssetStorage->storeAssetData(dst_filename, new_asset_id, - LLAssetType::AT_LSL_BYTECODE, - &LLFloaterCompileQueue::onSaveBytecodeComplete, - (void*)data, FALSE); - } -} -#endif - -void LLFloaterCompileQueue::removeItemByItemID(const LLUUID& asset_id) -{ - llinfos << "LLFloaterCompileQueue::removeItemByAssetID()" << llendl; - for(S32 i = 0; i < mCurrentScripts.count(); ) - { - if(asset_id == mCurrentScripts.get(i)->getUUID()) - { - mCurrentScripts.remove(i); - } - else - { - ++i; - } - } - if(mCurrentScripts.count() == 0) - { - nextObject(); - } -} const LLInventoryItem* LLFloaterCompileQueue::findItemByItemID(const LLUUID& asset_id) const { LLInventoryItem* result = NULL; - S32 count = mCurrentScripts.count(); + S32 count = mCurrentScripts.size(); for(S32 i = 0; i < count; ++i) { - if(asset_id == mCurrentScripts.get(i)->getUUID()) + if(asset_id == mCurrentScripts.at(i)->getUUID()) { - result = mCurrentScripts.get(i); + result = mCurrentScripts.at(i); } } return result; @@ -617,24 +565,24 @@ const LLInventoryItem* LLFloaterCompileQueue::findItemByItemID(const LLUUID& ass void LLFloaterCompileQueue::saveItemByItemID(const LLUUID& asset_id) { - llinfos << "LLFloaterCompileQueue::saveItemByAssetID()" << llendl; + LL_INFOS() << "LLFloaterCompileQueue::saveItemByAssetID()" << LL_ENDL; LLViewerObject* viewer_object = gObjectList.findObject(mCurrentObjectID); - if(viewer_object) + if (viewer_object) { - S32 count = mCurrentScripts.count(); + S32 count = mCurrentScripts.size(); for(S32 i = 0; i < count; ++i) { - if(asset_id == mCurrentScripts.get(i)->getUUID()) + if(asset_id == mCurrentScripts.at(i)->getUUID()) { // *FIX: this auto-resets active to TRUE. That might // be a bad idea. - viewer_object->saveScript(mCurrentScripts.get(i), TRUE, false); + viewer_object->saveScript(mCurrentScripts.at(i), TRUE, false); } } } else { - llwarns << "Unable to finish save!" << llendl; + LL_WARNS() << "Unable to finish save!" << LL_ENDL; } } @@ -668,13 +616,12 @@ void LLFloaterResetQueue::handleInventory(LLViewerObject* viewer_obj, { // find all of the lsl, leaving off duplicates. We'll remove // all matching asset uuids on compilation success. - LLDynamicArray names; LLInventoryObject::object_list_t::const_iterator it = inv->begin(); LLInventoryObject::object_list_t::const_iterator end = inv->end(); for ( ; it != end; ++it) { - if((*it)->getType() == LLAssetType::AT_LSL_TEXT) + if ((*it)->getType() == LLAssetType::AT_LSL_TEXT) { LLViewerObject* object = gObjectList.findObject(viewer_obj->getID()); @@ -682,7 +629,7 @@ void LLFloaterResetQueue::handleInventory(LLViewerObject* viewer_obj, { LLInventoryItem* item = (LLInventoryItem*)((LLInventoryObject*)(*it)); std::string buffer; - buffer = getString("Resetting") + LLTrans::getString(":") + " " + item->getName(); + buffer = getString("Resetting") + LLTrans::getString(":") + ' ' + item->getName(); getChild("queue output")->addSimpleElement(buffer, ADD_BOTTOM); LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_ScriptReset); @@ -729,13 +676,11 @@ void LLFloaterRunQueue::handleInventory(LLViewerObject* viewer_obj, { // find all of the lsl, leaving off duplicates. We'll remove // all matching asset uuids on compilation success. - LLDynamicArray names; - LLInventoryObject::object_list_t::const_iterator it = inv->begin(); LLInventoryObject::object_list_t::const_iterator end = inv->end(); for ( ; it != end; ++it) { - if((*it)->getType() == LLAssetType::AT_LSL_TEXT) + if ((*it)->getType() == LLAssetType::AT_LSL_TEXT) { LLViewerObject* object = gObjectList.findObject(viewer_obj->getID()); @@ -744,7 +689,7 @@ void LLFloaterRunQueue::handleInventory(LLViewerObject* viewer_obj, LLInventoryItem* item = (LLInventoryItem*)((LLInventoryObject*)(*it)); LLScrollListCtrl* list = getChild("queue output"); std::string buffer; - buffer = getString("Running") + LLTrans::getString(":") + " " + item->getName(); + buffer = getString("Running") + LLTrans::getString(":") + ' ' + item->getName(); list->addSimpleElement(buffer, ADD_BOTTOM); LLMessageSystem* msg = gMessageSystem; @@ -788,18 +733,53 @@ LLFloaterNotRunQueue::~LLFloaterNotRunQueue() { } +void LLFloaterCompileQueue::removeItemByItemID(const LLUUID& asset_id) +{ + LL_INFOS() << "LLFloaterCompileQueue::removeItemByAssetID()" << LL_ENDL; + for(size_t i = 0; i < mCurrentScripts.size(); ) + { + if(asset_id == mCurrentScripts[i]->getUUID()) + { + vector_replace_with_last(mCurrentScripts, mCurrentScripts.begin() + i); + } + else + { + ++i; + } + } + if(mCurrentScripts.empty()) + { + nextObject(); + } +} + +BOOL LLFloaterCompileQueue::startQueue() +{ + LLViewerRegion* region = gAgent.getRegion(); + if (region) + { + std::string lookup_url = region->getCapability("GetCreatorExperiences"); + if (!lookup_url.empty()) + { + LLHTTPClient::get(lookup_url, new CompileQueueExperienceResponder(mID)); + return TRUE; + } + } + return nextObject(); +} + + + void LLFloaterNotRunQueue::handleInventory(LLViewerObject* viewer_obj, LLInventoryObject::object_list_t* inv) { // find all of the lsl, leaving off duplicates. We'll remove // all matching asset uuids on compilation success. - LLDynamicArray names; - LLInventoryObject::object_list_t::const_iterator it = inv->begin(); LLInventoryObject::object_list_t::const_iterator end = inv->end(); for ( ; it != end; ++it) { - if((*it)->getType() == LLAssetType::AT_LSL_TEXT) + if ((*it)->getType() == LLAssetType::AT_LSL_TEXT) { LLViewerObject* object = gObjectList.findObject(viewer_obj->getID()); @@ -808,7 +788,7 @@ void LLFloaterNotRunQueue::handleInventory(LLViewerObject* viewer_obj, LLInventoryItem* item = (LLInventoryItem*)((LLInventoryObject*)(*it)); LLScrollListCtrl* list = getChild("queue output"); std::string buffer; - buffer = getString("NotRunning") + LLTrans::getString(":") + " " + item->getName(); + buffer = getString("NotRunning") + LLTrans::getString(":") + ' ' + item->getName(); list->addSimpleElement(buffer, ADD_BOTTOM); LLMessageSystem* msg = gMessageSystem; diff --git a/indra/newview/llcompilequeue.h b/indra/newview/llcompilequeue.h index 9114ce484c..fba5d295a7 100644 --- a/indra/newview/llcompilequeue.h +++ b/indra/newview/llcompilequeue.h @@ -33,7 +33,6 @@ #ifndef LL_LLCOMPILEQUEUE_H #define LL_LLCOMPILEQUEUE_H -#include "lldarray.h" #include "llinventory.h" #include "llviewerobject.h" #include "llvoinventorylistener.h" @@ -41,10 +40,11 @@ #include "lluuid.h" #include "llfloater.h" -#include "llscrolllistctrl.h" #include "llviewerinventory.h" +class LLScrollListCtrl; + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLFloaterScriptQueue // @@ -59,20 +59,23 @@ class LLFloaterScriptQueue : public LLFloater, public LLVOInventoryListener { public: + // find an instance by ID. Return NULL if it does not exist. + static LLFloaterScriptQueue* findInstance(const LLUUID& id); + LLFloaterScriptQueue(const std::string& name, const LLRect& rect, + const std::string& title, const std::string& start_string); + virtual ~LLFloaterScriptQueue(); + + /*virtual*/ BOOL postBuild(); + + void setMono(bool mono) { mMono = mono; } + // addObject() accepts an object id. void addObject(const LLUUID& id); // start() returns TRUE if the queue has started, otherwise FALSE. BOOL start(); - // find an instance by ID. Return NULL if it does not exist. - static LLFloaterScriptQueue* findInstance(const LLUUID& id); - protected: - LLFloaterScriptQueue(const std::string& name, const LLRect& rect, - const std::string& title, const std::string& start_string); - virtual ~LLFloaterScriptQueue(); - // This is the callback method for the viewer object currently // being worked on. /*virtual*/ void inventoryChanged(LLViewerObject* obj, @@ -89,21 +92,25 @@ class LLFloaterScriptQueue : public LLFloater, public LLVOInventoryListener // returns true if this is done BOOL isDone() const; + virtual BOOL startQueue(); + // go to the next object. If no objects left, it falls out // silently and waits to be killed by the deleteIfDone() callback. BOOL nextObject(); BOOL popNext(); - // Get this instances ID. + void setStartString(const std::string& s) { mStartString = s; } + + // Get this instance's ID. const LLUUID& getID() const { return mID; } - + protected: // UI LLScrollListCtrl* mMessages; LLButton* mCloseBtn; // Object Queue - LLDynamicArray mObjectIDs; + uuid_vec_t mObjectIDs; LLUUID mCurrentObjectID; bool mDone; @@ -111,6 +118,7 @@ class LLFloaterScriptQueue : public LLFloater, public LLVOInventoryListener static LLMap sInstances; std::string mStartString; + bool mMono; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -134,13 +142,16 @@ class LLFloaterCompileQueue : public LLFloaterScriptQueue public: // Use this method to create a compile queue. Once created, it // will be responsible for it's own destruction. - static LLFloaterCompileQueue* create(BOOL mono); + static LLFloaterCompileQueue* create(bool mono); // remove any object in mScriptScripts with the matching uuid. void removeItemByItemID(const LLUUID& item_id); LLAssetUploadQueue* getUploadQueue() { return mUploadQueue; } + void experienceIdsReceived(const LLSD& content); + BOOL hasExperience(const LLUUID& id) const; + protected: LLFloaterCompileQueue(const std::string& name, const LLRect& rect); virtual ~LLFloaterCompileQueue(); @@ -149,21 +160,13 @@ class LLFloaterCompileQueue : public LLFloaterScriptQueue virtual void handleInventory(LLViewerObject* viewer_obj, LLInventoryObject::object_list_t* inv); + static void requestAsset(struct LLScriptQueueData* datap, const LLSD& experience); + + // This is the callback for when each script arrives static void scriptArrived(LLVFS *vfs, const LLUUID& asset_id, LLAssetType::EType type, void* user_data, S32 status, LLExtStat ext_status); - -#if 0 //Client side compiling disabled. - static void onSaveTextComplete(const LLUUID& asset_id, void* user_data, S32 status, LLExtStat ext_status); - - static void onSaveBytecodeComplete(const LLUUID& asset_id, - void* user_data, - S32 status, LLExtStat ext_status); - - // compile the file given and save it out. - void compile(const std::string& filename, const LLUUID& asset_id); -#endif // remove any object in mScriptScripts with the matching uuid. void removeItemByAssetID(const LLUUID& asset_id); @@ -174,12 +177,13 @@ class LLFloaterCompileQueue : public LLFloaterScriptQueue // find InventoryItem given item id. const LLInventoryItem* findItemByItemID(const LLUUID& item_id) const; + virtual BOOL startQueue(); protected: LLViewerInventoryItem::item_array_t mCurrentScripts; private: - BOOL mMono; // Compile to mono. LLAssetUploadQueue* mUploadQueue; + uuid_list_t mExperienceIds; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/indra/newview/llconsole.cpp b/indra/newview/llconsole.cpp index dc72314fef..e4e365cefb 100644 --- a/indra/newview/llconsole.cpp +++ b/indra/newview/llconsole.cpp @@ -194,7 +194,7 @@ void LLConsole::draw() // draw remaining lines F32 y_pos = 0.f; - LLUIImagePtr imagep = LLUI::getUIImage("rounded_square.tga"); + LLUIImagePtr imagep = LLUI::getUIImage("Rounded_Square"); static const LLCachedControl console_background_opacity("ConsoleBackgroundOpacity"); F32 console_opacity = llclamp(console_background_opacity.get(), 0.f, 1.f); diff --git a/indra/newview/llcontrolavatar.cpp b/indra/newview/llcontrolavatar.cpp new file mode 100644 index 0000000000..31d027926a --- /dev/null +++ b/indra/newview/llcontrolavatar.cpp @@ -0,0 +1,671 @@ +/** + * @file llcontrolavatar.cpp + * @brief Implementation for special dummy avatar used to drive rigged meshes. + * + * $LicenseInfo:firstyear=2017&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2017, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llcontrolavatar.h" +#include "llagent.h" // Get state values from here +#include "llviewerobjectlist.h" +#include "pipeline.h" +#include "llanimationstates.h" +#include "llviewercontrol.h" +#include "llmeshrepository.h" +#include "llviewerregion.h" +#include "llskinningutil.h" + +//#pragma optimize("", off) + +const F32 LLControlAvatar::MAX_LEGAL_OFFSET = 3.0f; +const F32 LLControlAvatar::MAX_LEGAL_SIZE = 64.0f; + +//static +boost::signals2::connection LLControlAvatar::sRegionChangedSlot; + +LLControlAvatar::LLControlAvatar(const LLUUID& id, const LLPCode pcode, LLViewerRegion* regionp) : + LLVOAvatar(id, pcode, regionp), + mPlaying(false), + mGlobalScale(1.0f), + mRootVolp(NULL), + mMarkedForDeath(false), + mScaleConstraintFixup(1.0), + mRegionChanged(false) +{ + mIsDummy = TRUE; + mIsControlAvatar = true; + mEnableDefaultMotions = false; +} + +// virtual +LLControlAvatar::~LLControlAvatar() +{ + // Should already have been unlinked before destruction + llassert(!mRootVolp); +} + +// virtual +void LLControlAvatar::initInstance() +{ + // Potential optimizations here: avoid creating system + // avatar mesh content since it's not used. For now we just clean some + // things up after the fact in releaseMeshData(). + LLVOAvatar::initInstance(); + + createDrawable(&gPipeline); + updateJointLODs(); + updateGeometry(mDrawable); + hideSkirt(); + + mInitFlags |= 1<<4; +} + +void LLControlAvatar::getNewConstraintFixups(LLVector3& new_pos_fixup, F32& new_scale_fixup) const +{ + + F32 max_legal_offset = MAX_LEGAL_OFFSET; + static LLCachedControl animated_object_max_legal_offset(gSavedSettings, "AnimatedObjectsMaxLegalOffset"); + max_legal_offset = llmax(animated_object_max_legal_offset(),0.f); + + F32 max_legal_size = MAX_LEGAL_SIZE; + static LLCachedControl animated_object_max_legal_size(gSavedSettings, "AnimatedObjectsMaxLegalSize"); + max_legal_size = llmax(animated_object_max_legal_size(), 1.f); + + new_pos_fixup = LLVector3(); + new_scale_fixup = 1.0f; + LLVector3 vol_pos = mRootVolp->getRenderPosition(); + + // Fix up position if needed to prevent visual encroachment + if (box_valid_and_non_zero(getLastAnimExtents())) // wait for state to settle down + { + // The goal here is to ensure that the extent of the avatar's + // bounding box does not wander too far from the + // official position of the corresponding volume. We + // do this by tracking the distance and applying a + // correction to the control avatar position if + // needed. + const LLVector3 *extents = getLastAnimExtents(); + LLVector3 unshift_extents[2]; + unshift_extents[0] = extents[0] - mPositionConstraintFixup; + unshift_extents[1] = extents[1] - mPositionConstraintFixup; + LLVector3 box_dims = extents[1]-extents[0]; + F32 box_size = llmax(box_dims[0],box_dims[1],box_dims[2]); + + if (!mRootVolp->isAttachment()) + { + LLVector3 pos_box_offset = point_to_box_offset(vol_pos, unshift_extents); + F32 offset_dist = pos_box_offset.length(); + if (offset_dist > max_legal_offset && offset_dist > 0.f) + { + F32 target_dist = (offset_dist - max_legal_offset); + new_pos_fixup = (target_dist/offset_dist)*pos_box_offset; + } + //if (new_pos_fixup != mPositionConstraintFixup) + //{ + // LL_DEBUGS("ConstraintFix") << getFullname() << " pos fix, offset_dist " << offset_dist << " pos fixup " + // << new_pos_fixup << " was " << mPositionConstraintFixup << LL_ENDL; + // LL_DEBUGS("ConstraintFix") << "vol_pos " << vol_pos << LL_ENDL; + // LL_DEBUGS("ConstraintFix") << "extents " << extents[0] << " " << extents[1] << LL_ENDL; + // LL_DEBUGS("ConstraintFix") << "unshift_extents " << unshift_extents[0] << " " << unshift_extents[1] << LL_ENDL; + // + //} + } + if (box_size/mScaleConstraintFixup > max_legal_size) + { + new_scale_fixup = mScaleConstraintFixup*max_legal_size/box_size; + //LL_DEBUGS("ConstraintFix") << getFullname() << " scale fix, box_size " << box_size << " fixup " + // << mScaleConstraintFixup << " max legal " << max_legal_size + // << " -> new scale " << new_scale_fixup << LL_ENDL; + } + } +} + +void LLControlAvatar::matchVolumeTransform() +{ + if (mRootVolp) + { + LLVector3 new_pos_fixup; + F32 new_scale_fixup; + if (mRegionChanged) + { + new_scale_fixup = mScaleConstraintFixup; + new_pos_fixup = mPositionConstraintFixup; + mRegionChanged = false; + } + else + { + getNewConstraintFixups(new_pos_fixup, new_scale_fixup); + } + mPositionConstraintFixup = new_pos_fixup; + mScaleConstraintFixup = new_scale_fixup; + + static LLCachedControl global_scale(gSavedSettings, "AnimatedObjectsGlobalScale", 1.f); + + if (mRootVolp->isAttachment()) + { + LLVOAvatar *attached_av = mRootVolp->getAvatarAncestor(); + if (attached_av) + { + LLViewerJointAttachment *attach = attached_av->getTargetAttachmentPoint(mRootVolp); + setPositionAgent(mRootVolp->getRenderPosition()); + attach->updateWorldPRSParent(); + LLVector3 joint_pos = attach->getWorldPosition(); + LLQuaternion joint_rot = attach->getWorldRotation(); + LLVector3 obj_pos = mRootVolp->mDrawable->getPosition(); + const LLQuaternion& obj_rot = mRootVolp->mDrawable->getRotation(); + obj_pos.rotVec(joint_rot); + mRoot->setWorldPosition(obj_pos + joint_pos); + mRoot->setWorldRotation(obj_rot * joint_rot); + setRotation(mRoot->getRotation()); + + setGlobalScale(global_scale * mScaleConstraintFixup); + } + else + { + LL_WARNS_ONCE() << "can't find attached av!" << LL_ENDL; + } + } + else + { + LLVector3 vol_pos = mRootVolp->getRenderPosition(); + + // FIXME: Currently if you're doing something like playing an + // animation that moves the pelvis (on an avatar or + // animated object), the name tag and debug text will be + // left behind. Ideally setPosition() would follow the + // skeleton around in a smarter way, so name tags, + // complexity info and such line up better. Should defer + // this until avatars also get fixed. + + const LLQuaternion& obj_rot = mRootVolp->mDrawable ? mRootVolp->mDrawable->getRotation() : mRootVolp->getRotation(); + + LLQuaternion bind_rot; +#define MATCH_BIND_SHAPE +#ifdef MATCH_BIND_SHAPE + // MAINT-8671 - based on a patch from Beq Janus + const LLMeshSkinInfo* skin_info = mRootVolp->getSkinInfo(); + if (skin_info) + { + //LL_DEBUGS("BindShape") << getFullname() << " bind shape " << skin_info->mBindShapeMatrix << LL_ENDL; + bind_rot = LLSkinningUtil::getUnscaledQuaternion(skin_info->mBindShapeMatrix); + } +#endif + setRotation(bind_rot*obj_rot); + mRoot->setWorldRotation(bind_rot*obj_rot); + setPositionAgent(vol_pos); + mRoot->setPosition(vol_pos + mPositionConstraintFixup); + + setGlobalScale(global_scale * mScaleConstraintFixup); + } + } +} + +void LLControlAvatar::setGlobalScale(F32 scale) +{ + if (scale <= 0.0f) + { + LL_WARNS() << "invalid global scale " << scale << LL_ENDL; + return; + } + if (scale != mGlobalScale) + { + F32 adjust_scale = scale/mGlobalScale; + LL_INFOS() << "scale " << scale << " adjustment " << adjust_scale << LL_ENDL; + // should we be scaling from the pelvis or the root? + recursiveScaleJoint(mPelvisp,adjust_scale); + mGlobalScale = scale; + } +} + +void LLControlAvatar::recursiveScaleJoint(LLJoint* joint, F32 factor) +{ + joint->setScale(factor * joint->getScale()); + + for (auto child : joint->mChildren) + { + recursiveScaleJoint(child, factor); + } +} + +// Based on LLViewerJointAttachment::setupDrawable(), without the attaching part. +void LLControlAvatar::updateVolumeGeom() +{ + if (!mRootVolp->mDrawable) + return; + if (mRootVolp->mDrawable->isActive()) + { + mRootVolp->mDrawable->makeStatic(FALSE); + } + mRootVolp->mDrawable->makeActive(); + gPipeline.markMoved(mRootVolp->mDrawable); + gPipeline.markTextured(mRootVolp->mDrawable); // face may need to change draw pool to/from POOL_HUD + mRootVolp->mDrawable->setState(LLDrawable::USE_BACKLIGHT); + + LLViewerObject::const_child_list_t& child_list = mRootVolp->getChildren(); + for (const auto& iter : child_list) + { + LLViewerObject* childp = iter; + if (childp && childp->mDrawable.notNull()) + { + childp->mDrawable->setState(LLDrawable::USE_BACKLIGHT); + gPipeline.markTextured(childp->mDrawable); // face may need to change draw pool to/from POOL_HUD + gPipeline.markMoved(childp->mDrawable); + } + } + + gPipeline.markRebuild(mRootVolp->mDrawable, LLDrawable::REBUILD_ALL, TRUE); + mRootVolp->markForUpdate(TRUE); + + // Note that attachment overrides aren't needed here, have already + // been applied at the time the mControlAvatar was created, in + // llvovolume.cpp. + + matchVolumeTransform(); + + // Initial exploration of allowing scaling skeleton to match root + // prim bounding box. If enabled, would probably be controlled by + // an additional checkbox and default to off. Not enabled for + // initial release. + + // What should the scale be? What we really want is the ratio + // between the scale at which the object was originally designed + // and rigged, and the scale to which it has been subsequently + // modified - for example, if the object has been scaled down by a + // factor of 2 then we should use 0.5 as the global scale. But we + // don't have the original scale stored anywhere, just the current + // scale. Possibilities - 1) remember the original scale + // somewhere, 2) add another field to let the user specify the + // global scale, 3) approximate the original scale by looking at + // the proportions of the skeleton after joint positions have + // been applied + + //LLVector3 obj_scale = obj->getScale(); + //F32 obj_scale_z = llmax(obj_scale[2],0.1f); + //setGlobalScale(obj_scale_z/2.0f); // roughly fit avatar height range (2m) into object height +} + +LLControlAvatar *LLControlAvatar::createControlAvatar(LLVOVolume *obj) +{ + LLControlAvatar *cav = (LLControlAvatar*)gObjectList.createObjectViewer(LL_PCODE_LEGACY_AVATAR, gAgent.getRegion(), CO_FLAG_CONTROL_AVATAR); + + if (cav) + { + cav->mRootVolp = obj; + + // Sync up position/rotation with object + cav->matchVolumeTransform(); + } + + return cav; +} + +void LLControlAvatar::markForDeath() +{ + mMarkedForDeath = true; + mRootVolp = NULL; +} + +void LLControlAvatar::markDead() +{ + // NOTE: this can happen when the control avatar and root volume are on different regions and we're + // being called from the LLViewerRegion destructor due the region being dropped + // (due to being used as a vehicle and the move not yet being processed?) + if (mRootVolp) + { + mRootVolp->unlinkControlAvatar(); + mRootVolp = nullptr; + } + + LLVOAvatar::markDead(); +} + +void LLControlAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) +{ + if (mMarkedForDeath) + { + markDead(); + mMarkedForDeath = false; + } + else + { + LLVOAvatar::idleUpdate(agent, world,time); + } +} + +BOOL LLControlAvatar::updateCharacter(LLAgent &agent) +{ + return LLVOAvatar::updateCharacter(agent); +} + +//virtual +void LLControlAvatar::updateDebugText() +{ + /*static LLCachedControl debug_animated_objects(gSavedSettings, "DebugAnimatedObjects"); + if (debug_animated_objects) + { + S32 total_linkset_count = 0; + if (mRootVolp) + { + total_linkset_count = 1 + mRootVolp->getChildren().size(); + } + std::vector volumes; + getAnimatedVolumes(volumes); + S32 animated_volume_count = volumes.size(); + std::string active_string; + std::string type_string; + std::string lod_string; + std::string animated_object_flag_string; + S32 total_tris = 0; + S32 total_verts = 0; + F32 est_tris = 0.f; + F32 est_streaming_tris = 0.f; + F32 streaming_cost = 0.f; + std::string cam_dist_string = ""; + S32 cam_dist_count = 0; + F32 lod_radius = mRootVolp->mLODRadius; + + for (auto volp : volumes) + { + if (volp) + { + S32 verts = 0; + total_tris += volp->getTriangleCount(&verts); + total_verts += verts; + est_tris += volp->getEstTrianglesMax(); + est_streaming_tris += volp->getEstTrianglesStreamingCost(); + streaming_cost += volp->getStreamingCost(); + lod_string += llformat("%d", volp->getLOD()); + if (volp->mDrawable) + { + bool is_animated_flag = volp->getExtendedMeshFlags() & LLExtendedMeshParams::ANIMATED_MESH_ENABLED_FLAG; + if (is_animated_flag) + { + animated_object_flag_string += "1"; + } + else + { + animated_object_flag_string += "0"; + } + if (volp->mDrawable->isActive()) + { + active_string += "A"; + } + else + { + active_string += "S"; + } + if (volp->isRiggedMesh()) + { + // Rigged/animatable mesh + type_string += "R"; + lod_radius = volp->mLODRadius; + } + else if (volp->isMesh()) + { + // Static mesh + type_string += "M"; + } + else + { + // Any other prim + type_string += "P"; + } + if (cam_dist_count < 4) + { + cam_dist_string += LLStringOps::getReadableNumber(volp->mLODDistance) + "/" + + LLStringOps::getReadableNumber(volp->mLODAdjustedDistance) + " "; + cam_dist_count++; + } + } + else + { + active_string += "-"; + type_string += "-"; + } + } + } + addDebugText(llformat("CAV obj %d anim %d active %s impost %d upprd %d strcst %f", + total_linkset_count, animated_volume_count, + active_string.c_str(), (S32) isImpostor(), getUpdatePeriod(), streaming_cost)); + addDebugText(llformat("types %s lods %s", type_string.c_str(), lod_string.c_str())); + addDebugText(llformat("flags %s", animated_object_flag_string.c_str())); + addDebugText(llformat("tris %d (est %.1f, streaming %.1f), verts %d", total_tris, est_tris, est_streaming_tris, total_verts)); + addDebugText(llformat("pxarea %s rank %d", LLStringOps::getReadableNumber(getPixelArea()).c_str(), getVisibilityRank())); + addDebugText(llformat("lod_radius %s dists %s", LLStringOps::getReadableNumber(lod_radius).c_str(),cam_dist_string.c_str())); + if (mPositionConstraintFixup.length() > 0.0f || mScaleConstraintFixup != 1.0f) + { + addDebugText(llformat("pos fix (%.1f %.1f %.1f) scale %f", + mPositionConstraintFixup[0], + mPositionConstraintFixup[1], + mPositionConstraintFixup[2], + mScaleConstraintFixup)); + } + +#if 0 + std::string region_name = "no region"; + if (mRootVolp->getRegion()) + { + region_name = mRootVolp->getRegion()->getName(); + } + std::string skel_region_name = "skel no region"; + if (getRegion()) + { + skel_region_name = getRegion()->getName(); + } + addDebugText(llformat("region %x %s skel %x %s", + mRootVolp->getRegion(), region_name.c_str(), + getRegion(), skel_region_name.c_str())); +#endif + + }*/ + LLVOAvatar::updateDebugText(); +} + +void LLControlAvatar::getAnimatedVolumes(std::vector& volumes) +{ + if (!mRootVolp) + { + return; + } + + volumes.push_back(mRootVolp); + + LLViewerObject::const_child_list_t& child_list = mRootVolp->getChildren(); + for (const auto& iter : child_list) + { + LLViewerObject* childp = iter; + LLVOVolume *child_volp = childp ? childp->asVolume() : nullptr; + if (child_volp && child_volp->isAnimatedObject()) + { + volumes.push_back(child_volp); + } + } +} + +// This is called after an associated object receives an animation +// message. Combine the signaled animations for all associated objects +// and process any resulting state changes. +void LLControlAvatar::updateAnimations() +{ + if (!mRootVolp) + { + LL_WARNS_ONCE("AnimatedObjectsNotify") << "No root vol" << LL_ENDL; + return; + } + + std::vector volumes; + getAnimatedVolumes(volumes); + + // Rebuild mSignaledAnimations from the associated volumes. + std::map anims; + for (auto vol_it = volumes.begin(); vol_it != volumes.end(); ++vol_it) + { + LLVOVolume *volp = *vol_it; + //LL_INFOS("AnimatedObjects") << "updating anim for vol " << volp->getID() << " root " << mRootVolp->getID() << LL_ENDL; + auto& signaled_anim_map = LLObjectSignaledAnimationMap::instance().getMap(); + signaled_animation_map_t& signaled_animations = signaled_anim_map[volp->getID()]; + for (auto anim_it = signaled_animations.begin(), anim_it_end = signaled_animations.end(); + anim_it != anim_it_end; + ++anim_it) + { + auto found_anim_it = anims.find(anim_it->first); + if (found_anim_it != anims.end()) + { + // Animation already present, use the larger sequence id + anims[anim_it->first] = llmax(found_anim_it->second, anim_it->second); + } + else + { + // Animation not already present, use this sequence id. + anims[anim_it->first] = anim_it->second; + } +#if LL_DEBUG + LL_DEBUGS("AnimatedObjectsNotify") << "found anim for vol " << volp->getID() << " anim " << anim_it->first << " root " << mRootVolp->getID() << LL_ENDL; +#endif + } + } + if (!mPlaying) + { + mPlaying = true; + //if (!mRootVolp->isAnySelected()) + { + updateVolumeGeom(); + mRootVolp->recursiveMarkForUpdate(TRUE); + } + } + + mSignaledAnimations = anims; + processAnimationStateChanges(); +} + +// virtual +LLViewerObject* LLControlAvatar::lineSegmentIntersectRiggedAttachments(const LLVector4a& start, const LLVector4a& end, + S32 face, + BOOL pick_transparent, + BOOL pick_rigged, + S32* face_hit, + LLVector4a* intersection, + LLVector2* tex_coord, + LLVector4a* normal, + LLVector4a* tangent) +{ + if (!mRootVolp) + { + return NULL; + } + + LLViewerObject* hit = NULL; + + if (lineSegmentBoundingBox(start, end)) + { + LLVector4a local_end = end; + LLVector4a local_intersection; + if (mRootVolp->lineSegmentIntersect(start, local_end, face, pick_transparent, pick_rigged, face_hit, &local_intersection, tex_coord, normal, tangent)) + { + local_end = local_intersection; + if (intersection) + { + *intersection = local_intersection; + } + hit = mRootVolp; + } + else + { + std::vector volumes; + getAnimatedVolumes(volumes); + + for (auto volp : volumes) + { + if (mRootVolp != volp && volp->lineSegmentIntersect(start, local_end, face, pick_transparent, pick_rigged, face_hit, &local_intersection, tex_coord, normal, tangent)) + { + local_end = local_intersection; + if (intersection) + { + *intersection = local_intersection; + } + hit = volp; + break; + } + } + } + } + + return hit; +} + +// virtual +std::string LLControlAvatar::getFullname() const +{ + if (mRootVolp) + { + return "AO_" + mRootVolp->getID().getString(); + } + else + { + return "AO_no_root_vol"; + } +} + +// virtual +bool LLControlAvatar::shouldRenderRigged() const +{ + if (mRootVolp && mRootVolp->isAttachment()) + { + LLVOAvatar *attached_av = mRootVolp->getAvatarAncestor(); + if (attached_av) + { + return attached_av->shouldRenderRigged(); + } + } + return true; +} + +// virtual +BOOL LLControlAvatar::isImpostor() const +{ + if (mRootVolp && mRootVolp->isAttachment()) + { + // Attached animated objects should match state of their attached av. + LLVOAvatar *attached_av = mRootVolp->getAvatarAncestor(); + if (attached_av) + { + return attached_av->isImpostor(); + } + } + return LLVOAvatar::isImpostor(); +} + +//static +void LLControlAvatar::onRegionChanged() +{ + std::vector::iterator it = LLCharacter::sInstances.begin(); + for ( ; it != LLCharacter::sInstances.end(); ++it) + { + auto avatar = static_cast(*it); + if (!avatar->isDead() && avatar->isControlAvatar()) + { + LLControlAvatar* cav = static_cast(avatar); + cav->mRegionChanged = true; + } + } +} diff --git a/indra/newview/llcontrolavatar.h b/indra/newview/llcontrolavatar.h new file mode 100644 index 0000000000..c01c5c0a95 --- /dev/null +++ b/indra/newview/llcontrolavatar.h @@ -0,0 +1,115 @@ +/** + * @file llcontrolavatar.h + * @brief Special dummy avatar used to drive rigged meshes. + * + * $LicenseInfo:firstyear=2017&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2017, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_CONTROLAVATAR_H +#define LL_CONTROLAVATAR_H + +#include "llvoavatar.h" +#include "llvovolume.h" + +class LLControlAvatar final: + public LLVOAvatar +{ + LOG_CLASS(LLControlAvatar); + +public: + LLControlAvatar(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp); + void initInstance() override; // Called after construction to initialize the class. + virtual ~LLControlAvatar(); + LLControlAvatar* asControlAvatar() override { return this; } + + void getNewConstraintFixups(LLVector3& new_pos_constraint, F32& new_scale_constraint) const; + void matchVolumeTransform(); + void updateVolumeGeom(); + + void setGlobalScale(F32 scale); + void recursiveScaleJoint(LLJoint *joint, F32 factor); + static LLControlAvatar *createControlAvatar(LLVOVolume *obj); + + // Delayed kill so we don't make graphics pipeline unhappy calling + // markDead() inside other graphics pipeline operations. + void markForDeath(); + void markDead() override; + + void idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) override; + BOOL updateCharacter(LLAgent &agent) override; + + void getAnimatedVolumes(std::vector& volumes); + void updateAnimations(); + + LLViewerObject* lineSegmentIntersectRiggedAttachments( + const LLVector4a& start, const LLVector4a& end, + S32 face = -1, // which face to check, -1 = ALL_SIDES + BOOL pick_transparent = FALSE, + BOOL pick_rigged = FALSE, + S32* face_hit = NULL, // which face was hit + LLVector4a* intersection = NULL, // return the intersection point + LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point + LLVector4a* normal = NULL, // return the surface normal at the intersection point + LLVector4a* tangent = NULL) override; // return the surface tangent at the intersection point + + void updateDebugText() override; + + std::string getFullname() const override; + + bool shouldRenderRigged() const override; + + BOOL isImpostor() const override; + + bool mPlaying; + + F32 mGlobalScale; + + LLVOVolume *mRootVolp; + + bool mMarkedForDeath; + + LLVector3 mPositionConstraintFixup; + F32 mScaleConstraintFixup; + + static const F32 MAX_LEGAL_OFFSET; + static const F32 MAX_LEGAL_SIZE; + + static void onRegionChanged(); + bool mRegionChanged; + static boost::signals2::connection sRegionChangedSlot; +}; + +typedef std::map signaled_animation_map_t; +typedef std::map object_signaled_animation_map_t; + +// Stores information about previously requested animations, by object id. +class LLObjectSignaledAnimationMap final : public LLSingleton +{ +public: + LLObjectSignaledAnimationMap() {} + + object_signaled_animation_map_t mMap; + + object_signaled_animation_map_t& getMap() { return mMap; } +}; + +#endif //LL_CONTROLAVATAR_H diff --git a/indra/newview/llcurrencyuimanager.cpp b/indra/newview/llcurrencyuimanager.cpp index e2cc5a1538..3320e609b9 100644 --- a/indra/newview/llcurrencyuimanager.cpp +++ b/indra/newview/llcurrencyuimanager.cpp @@ -265,9 +265,9 @@ bool LLCurrencyUIManager::Impl::checkTransaction() return false; } - if (mResponder->result_code() != CURLE_OK || mResponder->http_status() < 200 || mResponder->http_status() >= 400) + if (mResponder->result_code() != CURLE_OK || mResponder->getStatus() < 200 || mResponder->getStatus() >= 400) { - setError(mResponder->reason(), mResponder->getURL()); + setError(mResponder->getReason(), mResponder->getURL()); } else { switch (mTransactionType) @@ -387,6 +387,7 @@ void LLCurrencyUIManager::Impl::updateUI() } mPanel.childSetTextArg("currency_est", "[USD]", llformat("%#.2f", mSiteCurrencyEstimatedCost / 100.0)); + mPanel.childSetTextArg("currency_est", "[REALCURRENCY]", gHippoGridManager->getConnectedGrid()->getRealCurrencySymbol()); mPanel.childSetVisible("currency_est", mSiteCurrencyEstimated && mUserCurrencyBuy > 0); if (mPanel.childIsEnabled("buy_btn") diff --git a/indra/newview/llcylinder.cpp b/indra/newview/llcylinder.cpp index e382643285..2fa94fecad 100644 --- a/indra/newview/llcylinder.cpp +++ b/indra/newview/llcylinder.cpp @@ -37,7 +37,6 @@ #include "llerror.h" #include "math.h" #include "llmath.h" -#include "noise.h" #include "v3math.h" #include "llvertexbuffer.h" #include "llgl.h" diff --git a/indra/newview/lldaycyclemanager.cpp b/indra/newview/lldaycyclemanager.cpp index b5ed0facc7..6dcbb4a10a 100644 --- a/indra/newview/lldaycyclemanager.cpp +++ b/indra/newview/lldaycyclemanager.cpp @@ -211,7 +211,7 @@ bool LLDayCycleManager::loadPreset(const std::string& path) LLSD data = LLWLDayCycle::loadDayCycleFromPath(path); if (data.isUndefined()) { - llwarns << "Error loading day cycle from " << path << llendl; + LL_WARNS() << "Error loading day cycle from " << path << LL_ENDL; return false; } diff --git a/indra/newview/lldebugmessagebox.cpp b/indra/newview/lldebugmessagebox.cpp index 527344bf48..7073d9b057 100644 --- a/indra/newview/lldebugmessagebox.cpp +++ b/indra/newview/lldebugmessagebox.cpp @@ -56,32 +56,32 @@ LLDebugVarMessageBox::LLDebugVarMessageBox(const std::string& title, EDebugVarTy switch(var_type) { case VAR_TYPE_F32: - mSlider1 = new LLSliderCtrl(std::string("slider 1"), LLRect(20,130,190,110), title, NULL, 70, 130, TRUE, TRUE, FALSE, NULL, *((F32*)var), -100.f, 100.f, 0.1f, LLStringUtil::null); + mSlider1 = new LLSliderCtrl(std::string("slider 1"), LLRect(20,130,190,110), title, NULL, 70, 130, TRUE, TRUE, NULL, *((F32*)var), -100.f, 100.f, 0.1f, LLStringUtil::null); mSlider1->setPrecision(3); addChild(mSlider1); mSlider2 = NULL; mSlider3 = NULL; break; case VAR_TYPE_S32: - mSlider1 = new LLSliderCtrl(std::string("slider 1"), LLRect(20,100,190,80), title, NULL, 70, 130, TRUE, TRUE, FALSE, NULL, (F32)*((S32*)var), -255.f, 255.f, 1.f, LLStringUtil::null); + mSlider1 = new LLSliderCtrl(std::string("slider 1"), LLRect(20,100,190,80), title, NULL, 70, 130, TRUE, TRUE, NULL, (F32)*((S32*)var), -255.f, 255.f, 1.f, LLStringUtil::null); mSlider1->setPrecision(0); addChild(mSlider1); mSlider2 = NULL; mSlider3 = NULL; break; case VAR_TYPE_VEC3: - mSlider1 = new LLSliderCtrl(std::string("slider 1"), LLRect(20,130,190,110), std::string("x: "), NULL, 70, 130, TRUE, TRUE, FALSE, NULL, ((LLVector3*)var)->mV[VX], -100.f, 100.f, 0.1f, LLStringUtil::null); + mSlider1 = new LLSliderCtrl(std::string("slider 1"), LLRect(20,130,190,110), std::string("x: "), NULL, 70, 130, TRUE, TRUE, NULL, ((LLVector3*)var)->mV[VX], -100.f, 100.f, 0.1f, LLStringUtil::null); mSlider1->setPrecision(3); - mSlider2 = new LLSliderCtrl(std::string("slider 2"), LLRect(20,100,190,80), std::string("y: "), NULL, 70, 130, TRUE, TRUE, FALSE, NULL, ((LLVector3*)var)->mV[VY], -100.f, 100.f, 0.1f, LLStringUtil::null); + mSlider2 = new LLSliderCtrl(std::string("slider 2"), LLRect(20,100,190,80), std::string("y: "), NULL, 70, 130, TRUE, TRUE, NULL, ((LLVector3*)var)->mV[VY], -100.f, 100.f, 0.1f, LLStringUtil::null); mSlider2->setPrecision(3); - mSlider3 = new LLSliderCtrl(std::string("slider 3"), LLRect(20,70,190,50), std::string("z: "), NULL, 70, 130, TRUE, TRUE, FALSE, NULL, ((LLVector3*)var)->mV[VZ], -100.f, 100.f, 0.1f, LLStringUtil::null); + mSlider3 = new LLSliderCtrl(std::string("slider 3"), LLRect(20,70,190,50), std::string("z: "), NULL, 70, 130, TRUE, TRUE, NULL, ((LLVector3*)var)->mV[VZ], -100.f, 100.f, 0.1f, LLStringUtil::null); mSlider3->setPrecision(3); addChild(mSlider1); addChild(mSlider2); addChild(mSlider3); break; default: - llwarns << "Unhandled var type " << var_type << llendl; + LL_WARNS() << "Unhandled var type " << var_type << LL_ENDL; break; } @@ -194,7 +194,7 @@ void LLDebugVarMessageBox::slider_changed(LLUICtrl* ctrl, void* user_data) break; } default: - llwarns << "Unhandled var type " << msg_box->mVarType << llendl; + LL_WARNS() << "Unhandled var type " << msg_box->mVarType << LL_ENDL; break; } } @@ -228,7 +228,7 @@ void LLDebugVarMessageBox::draw() break; } default: - llwarns << "Unhandled var type " << mVarType << llendl; + LL_WARNS() << "Unhandled var type " << mVarType << LL_ENDL; break; } mText->setText(text); diff --git a/indra/newview/lldebugmessagebox.h b/indra/newview/lldebugmessagebox.h index 6da5b6b1ce..1f38e39c67 100644 --- a/indra/newview/lldebugmessagebox.h +++ b/indra/newview/lldebugmessagebox.h @@ -34,7 +34,6 @@ #ifndef LL_LLDEBUGMESSAGEBOX_H #define LL_LLDEBUGMESSAGEBOX_H -#include "lldarray.h" #include "llfloater.h" #include "v3math.h" #include "lltextbox.h" diff --git a/indra/newview/lldebugview.cpp b/indra/newview/lldebugview.cpp index e1451a4118..cf991376ba 100644 --- a/indra/newview/lldebugview.cpp +++ b/indra/newview/lldebugview.cpp @@ -85,7 +85,7 @@ LLDebugView::LLDebugView(const std::string& name, const LLRect &rect) mFastTimerView->setVisible(FALSE); // start invisible addChild(mFastTimerView); - r.set(150, rect.getHeight() - 50, 870, 100); + r.set(150, rect.getHeight() - 50, 970, 100); LLTextureView::Params tvp; tvp.name("gTextureView"); tvp.rect(r); diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp index 8d0f3e9713..becf850ab4 100644 --- a/indra/newview/lldrawable.cpp +++ b/indra/newview/lldrawable.cpp @@ -32,6 +32,7 @@ #include "material_codes.h" // viewer includes +#include "llagent.h" #include "llcriticaldamp.h" #include "llface.h" #include "lllightconstants.h" @@ -49,13 +50,15 @@ #include "llspatialpartition.h" #include "llviewerobjectlist.h" #include "llviewerwindow.h" +#include "llcontrolavatar.h" +#include "lldrawpoolavatar.h" const F32 MIN_INTERPOLATE_DISTANCE_SQUARED = 0.001f * 0.001f; const F32 MAX_INTERPOLATE_DISTANCE_SQUARED = 10.f * 10.f; const F32 OBJECT_DAMPING_TIME_CONSTANT = 0.06f; const F32 MIN_SHADOW_CASTER_RADIUS = 2.0f; -static LLFastTimer::DeclareTimer FTM_CULL_REBOUND("Cull Rebound"); +static LLTrace::BlockTimerStatHandle FTM_CULL_REBOUND("Cull Rebound"); extern bool gShiftFrame; @@ -75,19 +78,25 @@ extern bool gShiftFrame; // // static -U32 LLDrawable::sCurVisible = 0; U32 LLDrawable::sNumZombieDrawables = 0; F32 LLDrawable::sCurPixelAngle = 0; -LLDynamicArrayPtr > LLDrawable::sDeadList; +std::vector > LLDrawable::sDeadList; #define FORCE_INVISIBLE_AREA 16.f // static void LLDrawable::incrementVisible() { - sCurVisible++; + LLViewerOctreeEntryData::incrementVisible(); sCurPixelAngle = (F32) gViewerWindow->getWindowHeightRaw()/LLViewerCamera::getInstance()->getView(); } + +LLDrawable::LLDrawable(LLViewerObject *vobj) +: LLViewerOctreeEntryData(LLViewerOctreeEntry::LLDRAWABLE), + mVObjp(vobj) +{ + init(); +} void LLDrawable::init() { // mXform @@ -95,21 +104,38 @@ void LLDrawable::init() mRenderType = 0; mCurrentScale = LLVector3(1,1,1); mDistanceWRTCamera = 0.0f; - mPositionGroup.clear(); - mExtents[0].clear(); - mExtents[1].clear(); - mState = 0; - mVObjp = NULL; + // mFaces - mSpatialGroupp = NULL; - mVisible = sCurVisible - 2;//invisible for the current frame and the last frame. mRadius = 0.f; - mGeneration = -1; - mBinRadius = 1.f; - mBinIndex = -1; mSpatialBridge = NULL; + + LLViewerOctreeEntry* entry = NULL; + setOctreeEntry(entry); + initVisible(sCurVisible - 2);//invisible for the current frame and the last frame. +} + +void LLDrawable::unload() +{ + LLVOVolume *pVVol = getVOVolume(); + pVVol->setNoLOD(); + + for (S32 i = 0; i < getNumFaces(); i++) + { + LLFace* facep = getFace(i); + if (facep->isState(LLFace::RIGGED)) + { + LLDrawPoolAvatar* pool = (LLDrawPoolAvatar*)facep->getPool(); + if (pool) { + pool->removeRiggedFace(facep); + } + facep->setVertexBuffer(NULL); + } + facep->clearState(LLFace::RIGGED); + } + + pVVol->markForUpdate(TRUE); } // static @@ -131,7 +157,7 @@ void LLDrawable::destroy() if (LLSpatialGroup::sNoDelete) { - llerrs << "Illegal deletion of LLDrawable!" << llendl; + LL_ERRS() << "Illegal deletion of LLDrawable!" << LL_ENDL; } std::for_each(mFaces.begin(), mFaces.end(), DeletePointer()); @@ -140,17 +166,19 @@ void LLDrawable::destroy() /*if (!(sNumZombieDrawables % 10)) { - llinfos << "- Zombie drawables: " << sNumZombieDrawables << llendl; + LL_INFOS() << "- Zombie drawables: " << sNumZombieDrawables << LL_ENDL; }*/ + } void LLDrawable::markDead() { if (isDead()) { - llwarns << "Warning! Marking dead multiple times!" << llendl; + LL_WARNS() << "Warning! Marking dead multiple times!" << LL_ENDL; return; } + setState(DEAD); if (mSpatialBridge) { @@ -161,9 +189,8 @@ void LLDrawable::markDead() sNumZombieDrawables++; // We're dead. Free up all of our references to other objects - setState(DEAD); cleanupReferences(); -// sDeadList.put(this); +// sDeadList.push_back(this); } LLVOVolume* LLDrawable::getVOVolume() const @@ -179,7 +206,7 @@ LLVOVolume* LLDrawable::getVOVolume() const } } -const LLMatrix4& LLDrawable::getRenderMatrix() const +const LLMatrix4a& LLDrawable::getRenderMatrix() const { return isRoot() ? getWorldMatrix() : getParent()->getWorldMatrix(); } @@ -197,16 +224,16 @@ BOOL LLDrawable::isLight() const } } -static LLFastTimer::DeclareTimer FTM_CLEANUP_DRAWABLE("Cleanup Drawable"); -static LLFastTimer::DeclareTimer FTM_DEREF_DRAWABLE("Deref"); -static LLFastTimer::DeclareTimer FTM_DELETE_FACES("Faces"); +static LLTrace::BlockTimerStatHandle FTM_CLEANUP_DRAWABLE("Cleanup Drawable"); +static LLTrace::BlockTimerStatHandle FTM_DEREF_DRAWABLE("Deref"); +static LLTrace::BlockTimerStatHandle FTM_DELETE_FACES("Faces"); void LLDrawable::cleanupReferences() { - LLFastTimer t(FTM_CLEANUP_DRAWABLE); + LL_RECORD_BLOCK_TIME(FTM_CLEANUP_DRAWABLE); { - LLFastTimer t(FTM_DELETE_FACES); + LL_RECORD_BLOCK_TIME(FTM_DELETE_FACES); std::for_each(mFaces.begin(), mFaces.end(), DeletePointer()); mFaces.clear(); } @@ -215,14 +242,27 @@ void LLDrawable::cleanupReferences() gPipeline.unlinkDrawable(this); + removeFromOctree(); + { - LLFastTimer t(FTM_DEREF_DRAWABLE); + LL_RECORD_BLOCK_TIME(FTM_DEREF_DRAWABLE); // Cleanup references to other objects mVObjp = NULL; mParent = NULL; } } +void LLDrawable::removeFromOctree() +{ + if(!mEntry) + { + return; + } + + mEntry->removeData(this); + mEntry = NULL; +} + void LLDrawable::cleanupDeadDrawables() { /* @@ -231,12 +271,12 @@ void LLDrawable::cleanupDeadDrawables() { if (sDeadList[i]->getNumRefs() > 1) { - llwarns << "Dead drawable has " << sDeadList[i]->getNumRefs() << " remaining refs" << llendl; + LL_WARNS() << "Dead drawable has " << sDeadList[i]->getNumRefs() << " remaining refs" << LL_ENDL; gPipeline.findReferences(sDeadList[i]); } } */ - sDeadList.reset(); + sDeadList.clear(); } S32 LLDrawable::findReferences(LLDrawable *drawablep) @@ -244,24 +284,24 @@ S32 LLDrawable::findReferences(LLDrawable *drawablep) S32 count = 0; if (mParent == drawablep) { - llinfos << this << ": parent reference" << llendl; + LL_INFOS() << this << ": parent reference" << LL_ENDL; count++; } return count; } -static LLFastTimer::DeclareTimer FTM_ALLOCATE_FACE("Allocate Face", true); +static LLTrace::BlockTimerStatHandle FTM_ALLOCATE_FACE("Allocate Face", true); LLFace* LLDrawable::addFace(LLFacePool *poolp, LLViewerTexture *texturep) { LLFace *face; { - LLFastTimer t(FTM_ALLOCATE_FACE); + LL_RECORD_BLOCK_TIME(FTM_ALLOCATE_FACE); face = new LLFace(this, mVObjp); } - if (!face) llerrs << "Allocating new Face: " << mFaces.size() << llendl; + if (!face) LL_ERRS() << "Allocating new Face: " << mFaces.size() << LL_ENDL; if (face) { @@ -285,7 +325,7 @@ LLFace* LLDrawable::addFace(const LLTextureEntry *te, LLViewerTexture *texturep) LLFace *face; { - LLFastTimer t(FTM_ALLOCATE_FACE); + LL_RECORD_BLOCK_TIME(FTM_ALLOCATE_FACE); face = new LLFace(this, mVObjp); } @@ -304,6 +344,49 @@ LLFace* LLDrawable::addFace(const LLTextureEntry *te, LLViewerTexture *texturep) } +LLFace* LLDrawable::addFace(const LLTextureEntry *te, LLViewerTexture *texturep, LLViewerTexture *normalp) +{ + LLFace *face; + face = new LLFace(this, mVObjp); + + face->setTEOffset(mFaces.size()); + face->setTexture(texturep); + face->setNormalMap(normalp); + face->setPoolType(gPipeline.getPoolTypeFromTE(te, texturep)); + + mFaces.push_back(face); + + if (isState(UNLIT)) + { + face->setState(LLFace::FULLBRIGHT); + } + + return face; + +} + +LLFace* LLDrawable::addFace(const LLTextureEntry *te, LLViewerTexture *texturep, LLViewerTexture *normalp, LLViewerTexture *specularp) +{ + LLFace *face; + face = new LLFace(this, mVObjp); + + face->setTEOffset(mFaces.size()); + face->setTexture(texturep); + face->setNormalMap(normalp); + face->setSpecularMap(specularp); + face->setPoolType(gPipeline.getPoolTypeFromTE(te, texturep)); + + mFaces.push_back(face); + + if (isState(UNLIT)) + { + face->setState(LLFace::FULLBRIGHT); + } + + return face; + +} + void LLDrawable::setNumFaces(const S32 newFaces, LLFacePool *poolp, LLViewerTexture *texturep) { if (newFaces == (S32)mFaces.size()) @@ -375,7 +458,7 @@ void LLDrawable::deleteFaces(S32 offset, S32 count) void LLDrawable::update() { - llerrs << "Shouldn't be called!" << llendl; + LL_ERRS() << "Shouldn't be called!" << LL_ENDL; } @@ -400,7 +483,7 @@ void LLDrawable::makeActive() pcode == LLViewerObject::LL_VO_GROUND || pcode == LLViewerObject::LL_VO_SKY) { - llerrs << "Static viewer object has active drawable!" << llendl; + LL_ERRS() << "Static viewer object has active drawable!" << LL_ENDL; } } #endif @@ -438,6 +521,12 @@ void LLDrawable::makeActive() } updatePartition(); } + else if (!isRoot() && !mParent->isActive()) //this should not happen, but occasionally it does... + { + mParent->makeActive(); + //NOTE: linked set will now NEVER become static + mParent->setState(LLDrawable::ACTIVE_CHILD); + } llassert(isAvatar() || isRoot() || mParent->isActive()); } @@ -448,7 +537,8 @@ void LLDrawable::makeStatic(BOOL warning_enabled) if (isState(ACTIVE) && !isState(ACTIVE_CHILD) && !mVObjp->isAttachment() && - !mVObjp->isFlexible()) + !mVObjp->isFlexible() && + !mVObjp->isAnimatedObject()) { clearState(ACTIVE | ANIMATED_CHILD); @@ -465,7 +555,7 @@ void LLDrawable::makeStatic(BOOL warning_enabled) { if (child_drawable->getParent() != this) { - llwarns << "Child drawable has unknown parent." << llendl; + LL_WARNS() << "Child drawable has unknown parent." << LL_ENDL; } child_drawable->makeStatic(warning_enabled); } @@ -517,11 +607,12 @@ F32 LLDrawable::updateXform(BOOL undamped) if (damped && isVisible()) { - F32 lerp_amt = llclamp(LLCriticalDamp::getInterpolant(OBJECT_DAMPING_TIME_CONSTANT), 0.f, 1.f); + F32 lerp_amt = llclamp(LLSmoothInterpolation::getInterpolant(OBJECT_DAMPING_TIME_CONSTANT), 0.f, 1.f); LLVector3 new_pos = lerp(old_pos, target_pos, lerp_amt); dist_squared = dist_vec_squared(new_pos, target_pos); LLQuaternion new_rot = nlerp(lerp_amt, old_rot, target_rot); + // FIXME: This can be negative! It is be possible for some rots to 'cancel out' pos or size changes. dist_squared += (1.f - dot(new_rot, target_rot)) * 10.f; LLVector3 new_scale = lerp(old_scale, target_scale, lerp_amt); @@ -539,18 +630,36 @@ F32 LLDrawable::updateXform(BOOL undamped) { // snap to final position (only if no target omega is applied) dist_squared = 0.0f; + //set target scale here, because of dist_squared = 0.0f remove object from move list + mCurrentScale = target_scale; // Animesh+ + if (getVOVolume() && !isRoot()) { //child prim snapping to some position, needs a rebuild gPipeline.markRebuild(this, LLDrawable::REBUILD_POSITION, TRUE); } } } + else + { + // The following fixes MAINT-1742 but breaks vehicles similar to MAINT-2275 + // dist_squared = dist_vec_squared(old_pos, target_pos); + + // The following fixes MAINT-2247 but causes MAINT-2275 + //dist_squared += (1.f - dot(old_rot, target_rot)) * 10.f; + //dist_squared += dist_vec_squared(old_scale, target_scale); + } LLVector3 vec = mCurrentScale-target_scale; + //It's a very important on each cycle on Drawable::update form(), when object remained in move + //, list update the CurrentScale member, because if do not do that, it remained in this list forever + //or when the delta time between two frames a become a sufficiently large (due to interpolation) + //for overcome the MIN_INTERPOLATE_DISTANCE_SQUARED. + mCurrentScale = target_scale; // Animesh+ + if (vec*vec > MIN_INTERPOLATE_DISTANCE_SQUARED) { //scale change requires immediate rebuild - mCurrentScale = target_scale; + //mCurrentScale = target_scale; // Animesh- gPipeline.markRebuild(this, LLDrawable::REBUILD_POSITION, TRUE); } else if (!isRoot() && @@ -565,10 +674,10 @@ F32 LLDrawable::updateXform(BOOL undamped) mVObjp->dirtySpatialGroup(); } } - else if (!isRoot() && ( - dist_vec_squared(old_pos, target_pos) > 0.f - || old_rot != target_rot )) - { //fix for BUG-860, MAINT-2275, MAINT-1742, MAINT-2247 + else if (!isRoot() && + ((dist_vec_squared(old_pos, target_pos) > 0.f) + || (1.f - dot(old_rot, target_rot)) > 0.f)) + { //fix for BUG-840, MAINT-2275, MAINT-1742, MAINT-2247 gPipeline.markRebuild(this, LLDrawable::REBUILD_POSITION, TRUE); } else if (!getVOVolume() && !isAvatar()) @@ -581,6 +690,10 @@ F32 LLDrawable::updateXform(BOOL undamped) mXform.setRotation(target_rot); mXform.setScale(LLVector3(1,1,1)); //no scale in drawable transforms (IT'S A RULE!) mXform.updateMatrix(); + if (isRoot() && mVObjp->isAnimatedObject() && mVObjp->getControlAvatar()) + { + mVObjp->getControlAvatar()->matchVolumeTransform(); + } if (mSpatialBridge) { @@ -628,7 +741,7 @@ BOOL LLDrawable::updateMove() { if (isDead()) { - llwarns << "Update move on dead drawable!" << llendl; + LL_WARNS() << "Update move on dead drawable!" << LL_ENDL; return TRUE; } @@ -639,17 +752,7 @@ BOOL LLDrawable::updateMove() makeActive(); - BOOL done; - - if (isState(MOVE_UNDAMPED)) - { - done = updateMoveUndamped(); - } - else - { - done = updateMoveDamped(); - } - return done; + return isState(MOVE_UNDAMPED) ? updateMoveUndamped() : updateMoveDamped(); } BOOL LLDrawable::updateMoveUndamped() @@ -660,13 +763,12 @@ BOOL LLDrawable::updateMoveUndamped() if (!isState(LLDrawable::INVISIBLE)) { - BOOL moved = (dist_squared > 0.001f); + BOOL moved = (dist_squared > 0.001f && dist_squared < 255.99f); // Animesh added 255.99f cap moveUpdatePipeline(moved); mVObjp->updateText(); } mVObjp->clearChanged(LLXform::MOVED); - return TRUE; } @@ -695,7 +797,7 @@ BOOL LLDrawable::updateMoveDamped() if (!isState(LLDrawable::INVISIBLE)) { - BOOL moved = (dist_squared > 0.001f); + BOOL moved = (dist_squared > 0.001f && dist_squared < 128.0f); // Animesh added 128.0f cap moveUpdatePipeline(moved); mVObjp->updateText(); } @@ -714,7 +816,7 @@ void LLDrawable::updateDistance(LLCamera& camera, bool force_update) { if (LLViewerCamera::sCurCameraID != LLViewerCamera::CAMERA_WORLD) { - llwarns << "Attempted to update distance for non-world camera." << llendl; + LL_WARNS() << "Attempted to update distance for non-world camera." << LL_ENDL; return; } @@ -733,7 +835,7 @@ void LLDrawable::updateDistance(LLCamera& camera, bool force_update) LLVOVolume* volume = getVOVolume(); if (volume) { - if (getSpatialGroup()) + if (getGroup()) { pos.set(getPositionGroup().getF32ptr()); } @@ -763,6 +865,28 @@ void LLDrawable::updateDistance(LLCamera& camera, bool force_update) } } } + + // MAINT-7926 Handle volumes in an animated object as a special case + // SL-937: add dynamic box handling for rigged mesh on regular avatars. + //if (volume->getAvatar() && volume->getAvatar()->isControlAvatar()) + if (volume->getAvatar()) + { + const LLVector3* av_box = volume->getAvatar()->getLastAnimExtents(); + LLVector3d cam_pos = gAgent.getPosGlobalFromAgent(LLViewerCamera::getInstance()->getOrigin()); + LLVector3 cam_region_pos = LLVector3(cam_pos - volume->getRegion()->getOriginGlobal()); + + LLVector3 cam_to_box_offset = point_to_box_offset(cam_region_pos, av_box); + mDistanceWRTCamera = llmax(0.01f, ll_round(cam_to_box_offset.magVec(), 0.01f)); + LL_DEBUGS("DynamicBox") << volume->getAvatar()->getFullname() + << " pos (ignored) " << pos + << " cam pos " << cam_pos + << " cam region pos " << cam_region_pos + << " box " << av_box[0] << "," << av_box[1] + << " -> dist " << mDistanceWRTCamera + << LL_ENDL; + mVObjp->updateLOD(); + return; + } } else { @@ -770,7 +894,7 @@ void LLDrawable::updateDistance(LLCamera& camera, bool force_update) } pos -= camera.getOrigin(); - mDistanceWRTCamera = llround(pos.magVec(), 0.01f); + mDistanceWRTCamera = ll_round(pos.magVec(), 0.01f); mVObjp->updateLOD(); } } @@ -779,7 +903,7 @@ void LLDrawable::updateTexture() { if (isDead()) { - llwarns << "Dead drawable updating texture!" << llendl; + LL_WARNS() << "Dead drawable updating texture!" << LL_ENDL; return; } @@ -790,7 +914,6 @@ void LLDrawable::updateTexture() if (getVOVolume()) { - //getVOVolume()->mFaceMappingChanged = TRUE; gPipeline.markRebuild(this, LLDrawable::REBUILD_MATERIAL, TRUE); } } @@ -806,7 +929,7 @@ void LLDrawable::shiftPos(const LLVector4a &shift_vector) { if (isDead()) { - llwarns << "Shifting dead drawable" << llendl; + LL_WARNS() << "Shifting dead drawable" << LL_ENDL; return; } @@ -852,9 +975,7 @@ void LLDrawable::shiftPos(const LLVector4a &shift_vector) } } - mExtents[0].add(shift_vector); - mExtents[1].add(shift_vector); - mPositionGroup.add(shift_vector); + shift(shift_vector); } else if (mSpatialBridge) { @@ -862,9 +983,7 @@ void LLDrawable::shiftPos(const LLVector4a &shift_vector) } else if (isAvatar()) { - mExtents[0].add(shift_vector); - mExtents[1].add(shift_vector); - mPositionGroup.add(shift_vector); + shift(shift_vector); } mVObjp->onShift(shift_vector); @@ -876,40 +995,22 @@ const LLVector3& LLDrawable::getBounds(LLVector3& min, LLVector3& max) const return mXform.getPositionW(); } -const LLVector4a* LLDrawable::getSpatialExtents() const -{ - return mExtents; -} - -void LLDrawable::setSpatialExtents(const LLVector3& min, const LLVector3& max) -{ - mExtents[0].load3(min.mV); - mExtents[1].load3(max.mV); -} - -void LLDrawable::setSpatialExtents(const LLVector4a& min, const LLVector4a& max) -{ - mExtents[0] = min; - mExtents[1] = max; -} - -void LLDrawable::setPositionGroup(const LLVector4a& pos) -{ - mPositionGroup = pos; -} - void LLDrawable::updateSpatialExtents() { if (mVObjp) { - mVObjp->updateSpatialExtents(mExtents[0], mExtents[1]); + const LLVector4a* exts = getSpatialExtents(); + LLVector4a extents[2] = { exts[0], exts[1] }; + + mVObjp->updateSpatialExtents(extents[0], extents[1]); + setSpatialExtents(extents[0], extents[1]); } updateBinRadius(); if (mSpatialBridge.notNull()) { - mPositionGroup.splat(0.f); + getGroupPosition().splat(0.f); } } @@ -918,11 +1019,11 @@ void LLDrawable::updateBinRadius() { if (mVObjp.notNull()) { - mBinRadius = llmin(mVObjp->getBinRadius(), 256.f); + setBinRadius(llmin(mVObjp->getBinRadius(), 256.f)); } else { - mBinRadius = llmin(getRadius()*4.f, 256.f); + setBinRadius(llmin(getRadius()*4.f, 256.f)); } } @@ -956,26 +1057,56 @@ void LLDrawable::updateUVMinMax() { } -LLSpatialGroup* LLDrawable::getSpatialGroup() const +//virtual +bool LLDrawable::isVisible() const +{ + if (LLViewerOctreeEntryData::isVisible()) { - llassert((mSpatialGroupp == NULL) ? getBinIndex() == -1 : getBinIndex() != -1); - return mSpatialGroupp; + return true; } -void LLDrawable::setSpatialGroup(LLSpatialGroup *groupp) { - //precondition: mSpatialGroupp MUST be null or DEAD or mSpatialGroupp MUST NOT contain this - llassert(!mSpatialGroupp || mSpatialGroupp->isDead() || !mSpatialGroupp->hasElement(this)); + LLViewerOctreeGroup* group = mEntry->getGroup(); + if (group && group->isVisible()) + { + LLViewerOctreeEntryData::setVisible(); + return true; + } + } + + return false; +} + +//virtual +bool LLDrawable::isRecentlyVisible() const +{ + //currently visible or visible in the previous frame. + bool vis = LLViewerOctreeEntryData::isRecentlyVisible(); + + if(!vis) + { + const U32 MIN_VIS_FRAME_RANGE = 2 ; //two frames:the current one and the last one. + vis = (sCurVisible - getVisible() < MIN_VIS_FRAME_RANGE); + } + + return vis ; +} +void LLDrawable::setGroup(LLViewerOctreeGroup *groupp) +{ + LLSpatialGroup* cur_groupp = (LLSpatialGroup*)getGroup(); + + //precondition: mGroupp MUST be null or DEAD or mGroupp MUST NOT contain this + //llassert(!cur_groupp || cur_groupp->isDead() || !cur_groupp->hasElement(this)); //precondition: groupp MUST be null or groupp MUST contain this - llassert(!groupp || groupp->hasElement(this)); + llassert(!groupp || (LLSpatialGroup*)groupp->hasElement(this)); -/*if (mSpatialGroupp && (groupp != mSpatialGroupp)) + /*if (mSpatialGroupp && (groupp != mSpatialGroupp)) { mSpatialGroupp->setState(LLSpatialGroup::GEOM_DIRTY); }*/ - if (mSpatialGroupp != groupp && getVOVolume()) + if (cur_groupp != groupp && getVOVolume()) { //NULL out vertex buffer references for volumes on spatial group change to maintain //requirement that every face vertex buffer is either NULL or points to a vertex buffer //contained by its drawable's spatial group @@ -991,10 +1122,10 @@ void LLDrawable::setSpatialGroup(LLSpatialGroup *groupp) //postcondition: if next group is NULL, previous group must be dead OR NULL OR binIndex must be -1 //postcondition: if next group is NOT NULL, binIndex must not be -1 - llassert(groupp == NULL ? (mSpatialGroupp == NULL || mSpatialGroupp->isDead()) || getBinIndex() == -1 : - getBinIndex() != -1); + //llassert(groupp == NULL ? (mSpatialGroupp == NULL || mSpatialGroupp->isDead()) || getBinIndex() == -1 : + // getBinIndex() != -1); - mSpatialGroupp = groupp; + LLViewerOctreeEntryData::setGroup(groupp); } LLSpatialPartition* LLDrawable::getSpatialPartition() @@ -1008,16 +1139,28 @@ LLSpatialPartition* LLDrawable::getSpatialPartition() retval = gPipeline.getSpatialPartition((LLViewerObject*) mVObjp); } else if (isRoot()) - { //must be an active volume + { + if (mSpatialBridge && (mSpatialBridge->asPartition()->mPartitionType == LLViewerRegion::PARTITION_HUD) != mVObjp->isHUDAttachment()) + { + // remove obsolete bridge + mSpatialBridge->markDead(); + setSpatialBridge(NULL); + } + //must be an active volume if (!mSpatialBridge) { + // Spatial bridge ctors self-register... if (mVObjp->isHUDAttachment()) { - setSpatialBridge(new LLHUDBridge(this)); + setSpatialBridge(new LLHUDBridge(this, getRegion())); + } + else if (mVObjp->isAttachment()) + { + setSpatialBridge(new LLAttachmentBridge(this, getRegion())); } else { - setSpatialBridge(new LLVolumeBridge(this)); + setSpatialBridge(new LLVolumeBridge(this, getRegion())); } } return mSpatialBridge->asPartition(); @@ -1036,89 +1179,18 @@ LLSpatialPartition* LLDrawable::getSpatialPartition() return retval; } -const S32 MIN_VIS_FRAME_RANGE = 2 ; //two frames:the current one and the last one. -//static -S32 LLDrawable::getMinVisFrameRange() -{ - return MIN_VIS_FRAME_RANGE ; -} - -BOOL LLDrawable::isRecentlyVisible() const -{ - //currently visible or visible in the previous frame. - BOOL vis = isVisible() || (sCurVisible - mVisible < MIN_VIS_FRAME_RANGE) ; - - if(!vis) - { - LLSpatialGroup* group = getSpatialGroup(); - if (group && group->isRecentlyVisible()) - { - mVisible = sCurVisible; - vis = TRUE ; - } - } - - return vis ; -} - -BOOL LLDrawable::isVisible() const -{ - if (mVisible == sCurVisible) - { - return TRUE; - } - -#if 0 - //disabling this code fixes DEV-20105. Leaving in place in case some other bug pops up as a a result. - //should be safe to just always ask the spatial group for visibility. - if (isActive()) - { - if (isRoot()) - { - LLSpatialGroup* group = mSpatialBridge.notNull() ? mSpatialBridge->getSpatialGroup() : - getSpatialGroup(); - if (group && group->isVisible()) - { - mVisible = sCurVisible; - return TRUE; - } - } - else - { - if (getParent()->isVisible()) - { - mVisible = sCurVisible; - return TRUE; - } - } - } - else -#endif - { - LLSpatialGroup* group = getSpatialGroup(); - if (group && group->isVisible()) - { - mVisible = sCurVisible; - return TRUE; - } - } - - return FALSE; -} - //======================================= // Spatial Partition Bridging Drawable //======================================= -LLSpatialBridge::LLSpatialBridge(LLDrawable* root, BOOL render_by_group, U32 data_mask) -: LLSpatialPartition(data_mask, render_by_group, GL_STREAM_DRAW_ARB) +LLSpatialBridge::LLSpatialBridge(LLDrawable* root, BOOL render_by_group, U32 data_mask, LLViewerRegion* regionp) : + LLDrawable(root->getVObj()), + LLSpatialPartition(data_mask, render_by_group, GL_STREAM_DRAW_ARB, regionp) { mBridge = this; mDrawable = root; root->setSpatialBridge(this); - mBinIndex = -1; - mRenderType = mDrawable->mRenderType; mDrawableType = mDrawable->mRenderType; @@ -1139,10 +1211,13 @@ LLSpatialBridge::LLSpatialBridge(LLDrawable* root, BOOL render_by_group, U32 dat LLSpatialBridge::~LLSpatialBridge() { + if(mEntry) + { LLSpatialGroup* group = getSpatialGroup(); if (group) { - group->mSpatialPartition->remove(this, group); + group->getSpatialPartition()->remove(this, group); + } } //delete octree here so listeners will still be able to access bridge specific state @@ -1160,16 +1235,15 @@ void LLSpatialBridge::updateSpatialExtents() LLSpatialGroup* root = (LLSpatialGroup*) mOctree->getListener(0); { - LLFastTimer ftm(FTM_CULL_REBOUND); + LL_RECORD_BLOCK_TIME(FTM_CULL_REBOUND); root->rebound(); } + const LLVector4a* root_bounds = root->getBounds(); LLVector4a offset; - LLVector4a size = root->mBounds[1]; + LLVector4a size = root_bounds[1]; - //VECTORIZE THIS - LLMatrix4a mat; - mat.loadu(mDrawable->getXform()->getWorldMatrix()); + const LLMatrix4a& mat = mDrawable->getXform()->getWorldMatrix(); LLVector4a t; t.splat(0.f); @@ -1177,7 +1251,7 @@ void LLSpatialBridge::updateSpatialExtents() LLVector4a center; mat.affineTransform(t, center); - mat.rotate(root->mBounds[0], offset); + mat.rotate(root_bounds[0], offset); center.add(offset); LLVector4a v[4]; @@ -1199,12 +1273,9 @@ void LLSpatialBridge::updateSpatialExtents() scale.mul(size); mat.rotate(scale, v[3]); - - LLVector4a& newMin = mExtents[0]; - LLVector4a& newMax = mExtents[1]; - + LLVector4a newMin; + LLVector4a newMax; newMin = newMax = center; - for (U32 i = 0; i < 4; i++) { LLVector4a delta; @@ -1217,53 +1288,63 @@ void LLSpatialBridge::updateSpatialExtents() newMin.setMin(newMin, min); newMax.setMax(newMax, max); } + setSpatialExtents(newMin, newMax); LLVector4a diagonal; diagonal.setSub(newMax, newMin); mRadius = diagonal.getLength3().getF32() * 0.5f; - mPositionGroup.setAdd(newMin,newMax); - mPositionGroup.mul(0.5f); + LLVector4a& pos = getGroupPosition(); + pos.setAdd(newMin,newMax); + pos.mul(0.5f); updateBinRadius(); } void LLSpatialBridge::updateBinRadius() { - mBinRadius = llmin( mOctree->getSize()[0]*0.5f, 256.f); + setBinRadius(llmin( mOctree->getSize()[0]*0.5f, 256.f)); } LLCamera LLSpatialBridge::transformCamera(LLCamera& camera) { LLCamera ret = camera; LLXformMatrix* mat = mDrawable->getXform(); - LLVector3 center = LLVector3(0,0,0) * mat->getWorldMatrix(); + const LLVector4a& center = mat->getWorldMatrix().getRow<3>(); - LLVector3 delta = ret.getOrigin() - center; - LLQuaternion rot = ~mat->getRotation(); + LLQuaternion2 invRot; + invRot.setConjugate( LLQuaternion2(mat->getRotation()) ); - delta *= rot; - LLVector3 lookAt = ret.getAtAxis(); - LLVector3 up_axis = ret.getUpAxis(); - LLVector3 left_axis = ret.getLeftAxis(); + LLVector4a delta; + delta.load3(ret.getOrigin().mV); + delta.sub(center); - lookAt *= rot; - up_axis *= rot; - left_axis *= rot; + LLVector4a lookAt; + lookAt.load3(ret.getAtAxis().mV); + LLVector4a up_axis; - if (!delta.isFinite()) + up_axis.load3(ret.getUpAxis().mV); + LLVector4a left_axis; + left_axis.load3(ret.getLeftAxis().mV); + + delta.setRotated(invRot, delta); + lookAt.setRotated(invRot, lookAt); + up_axis.setRotated(invRot, up_axis); + left_axis.setRotated(invRot, left_axis); + + if (!delta.isFinite3()) { - delta.clearVec(); + delta.clear(); } - ret.setOrigin(delta); - ret.setAxes(lookAt, left_axis, up_axis); + ret.setOrigin(LLVector3(delta.getF32ptr())); + ret.setAxes(LLVector3(lookAt.getF32ptr()), LLVector3(left_axis.getF32ptr()), LLVector3(up_axis.getF32ptr())); return ret; } void LLDrawable::setVisible(LLCamera& camera, std::vector* results, BOOL for_select) { - mVisible = sCurVisible; + LLViewerOctreeEntryData::setVisible(); #if 0 && !LL_RELEASE_FOR_DOWNLOAD //crazy paranoid rules checking @@ -1273,46 +1354,46 @@ void LLDrawable::setVisible(LLCamera& camera, std::vector* results, { if (isActive() && !mParent->isActive()) { - llerrs << "Active drawable has static parent!" << llendl; + LL_ERRS() << "Active drawable has static parent!" << LL_ENDL; } if (isStatic() && !mParent->isStatic()) { - llerrs << "Static drawable has active parent!" << llendl; + LL_ERRS() << "Static drawable has active parent!" << LL_ENDL; } if (mSpatialBridge) { - llerrs << "Child drawable has spatial bridge!" << llendl; + LL_ERRS() << "Child drawable has spatial bridge!" << LL_ENDL; } } else if (isActive() && !mSpatialBridge) { - llerrs << "Active root drawable has no spatial bridge!" << llendl; + LL_ERRS() << "Active root drawable has no spatial bridge!" << LL_ENDL; } else if (isStatic() && mSpatialBridge.notNull()) { - llerrs << "Static drawable has spatial bridge!" << llendl; + LL_ERRS() << "Static drawable has spatial bridge!" << LL_ENDL; } } #endif } -class LLOctreeMarkNotCulled: public LLOctreeTraveler +class LLOctreeMarkNotCulled: public OctreeTraveler { public: LLCamera* mCamera; LLOctreeMarkNotCulled(LLCamera* camera_in) : mCamera(camera_in) { } - virtual void traverse(const LLOctreeNode* node) + virtual void traverse(const OctreeNode* node) { LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0); group->setVisible(); - LLOctreeTraveler::traverse(node); + OctreeTraveler::traverse(node); } - void visit(const LLOctreeNode* branch) + void visit(const OctreeNode* branch) { gPipeline.markNotCulled((LLSpatialGroup*) branch->getListener(0), *mCamera); } @@ -1356,7 +1437,7 @@ void LLSpatialBridge::setVisible(LLCamera& camera_in, std::vector* } if (!group || - LLDrawable::getCurrentFrame() - av->mVisible > 1 || + LLDrawable::getCurrentFrame() - av->getVisible() > 1 || impostor || !loaded) { @@ -1376,16 +1457,17 @@ void LLSpatialBridge::setVisible(LLCamera& camera_in, std::vector* group->rebound(); LLVector4a center; - center.setAdd(mExtents[0], mExtents[1]); + const LLVector4a* exts = getSpatialExtents(); + center.setAdd(exts[0], exts[1]); center.mul(0.5f); LLVector4a size; - size.setSub(mExtents[1], mExtents[0]); + size.setSub(exts[1], exts[0]); size.mul(0.5f); if ((LLPipeline::sShadowRender && camera_in.AABBInFrustum(center, size)) || LLPipeline::sImpostorRender || (camera_in.AABBInFrustumNoFarClip(center, size) && - AABBSphereIntersect(mExtents[0], mExtents[1], camera_in.getOrigin(), camera_in.mFrustumCornerDist))) + AABBSphereIntersect(exts[0], exts[1], camera_in.getOrigin(), camera_in.mFrustumCornerDist))) { if (!LLPipeline::sImpostorRender && !LLPipeline::sShadowRender && @@ -1479,7 +1561,7 @@ void LLSpatialBridge::updateDistance(LLCamera& camera_in, bool force_update) void LLSpatialBridge::makeActive() { //it is an error to make a spatial bridge active (it's already active) - llerrs << "makeActive called on spatial bridge" << llendl; + LL_ERRS() << "makeActive called on spatial bridge" << LL_ENDL; } void LLSpatialBridge::move(LLDrawable *drawablep, LLSpatialGroup *curp, BOOL immediate) @@ -1506,9 +1588,7 @@ BOOL LLSpatialBridge::updateMove() void LLSpatialBridge::shiftPos(const LLVector4a& vec) { - mExtents[0].add(vec); - mExtents[1].add(vec); - mPositionGroup.add(vec); + LLDrawable::shift(vec); } void LLSpatialBridge::cleanupReferences() @@ -1516,11 +1596,7 @@ void LLSpatialBridge::cleanupReferences() LLDrawable::cleanupReferences(); if (mDrawable) { - /* - - DON'T DO THIS -- this should happen through octree destruction - - mDrawable->setSpatialGroup(NULL); + mDrawable->setGroup(NULL); if (mDrawable->getVObj()) { LLViewerObject::const_child_list_t& child_list = mDrawable->getVObj()->getChildren(); @@ -1528,17 +1604,18 @@ void LLSpatialBridge::cleanupReferences() iter != child_list.end(); iter++) { LLViewerObject* child = *iter; - LLDrawable* drawable = child->mDrawable; + LLDrawable* drawable = child->mDrawable; if (drawable) { - drawable->setSpatialGroup(NULL); + drawable->setGroup(NULL); } } - }*/ + } - LLDrawable* drawablep = mDrawable; - mDrawable = NULL; - drawablep->setSpatialBridge(NULL); + LLPointer bridgep = mDrawable->getSpatialBridge(); + mDrawable->setSpatialBridge(nullptr); + mDrawable = nullptr; + bridgep = nullptr; } } @@ -1548,12 +1625,17 @@ const LLVector3 LLDrawable::getPositionAgent() const { if (isActive()) { - LLVector3 pos(0,0,0); if (!isRoot()) { - pos = mVObjp->getPosition(); + LLVector4a pos; + pos.load3(mVObjp->getPosition().mV); + getRenderMatrix().affineTransform(pos,pos); + return LLVector3(pos.getF32ptr()); + } + else + { + return LLVector3(getRenderMatrix().getRow<3>().getF32ptr()); } - return pos * getRenderMatrix(); } else { @@ -1609,17 +1691,23 @@ void LLDrawable::updateFaceSize(S32 idx) } } -LLBridgePartition::LLBridgePartition() -: LLSpatialPartition(0, FALSE, 0) +LLBridgePartition::LLBridgePartition(LLViewerRegion* regionp) +: LLSpatialPartition(0, FALSE, 0, regionp) { - mDrawableType = LLPipeline::RENDER_TYPE_AVATAR; + mDrawableType = LLPipeline::RENDER_TYPE_VOLUME; mPartitionType = LLViewerRegion::PARTITION_BRIDGE; mLODPeriod = 16; mSlopRatio = 0.25f; } -LLHUDBridge::LLHUDBridge(LLDrawable* drawablep) -: LLVolumeBridge(drawablep) +LLAttachmentPartition::LLAttachmentPartition(LLViewerRegion* regionp) +: LLBridgePartition(regionp) +{ + mDrawableType = LLPipeline::RENDER_TYPE_AVATAR; +} + +LLHUDBridge::LLHUDBridge(LLDrawable* drawablep, LLViewerRegion* regionp) +: LLVolumeBridge(drawablep, regionp) { mDrawableType = LLPipeline::RENDER_TYPE_HUD; mPartitionType = LLViewerRegion::PARTITION_HUD; diff --git a/indra/newview/lldrawable.h b/indra/newview/lldrawable.h index ba4665a992..1da98e3150 100644 --- a/indra/newview/lldrawable.h +++ b/indra/newview/lldrawable.h @@ -44,10 +44,10 @@ #include "llvector4a.h" #include "llquaternion.h" #include "xform.h" -#include "lldarray.h" #include "llviewerobject.h" #include "llrect.h" #include "llappviewer.h" // for gFrameTimeSeconds +#include "llvieweroctree.h" class LLCamera; class LLDrawPool; @@ -61,21 +61,23 @@ class LLVOVolume; class LLViewerTexture; // Can have multiple silhouettes for each object -const U32 SILHOUETTE_HIGHLIGHT = 0; +constexpr U32 SILHOUETTE_HIGHLIGHT = 0; // All data for new renderer goes into this class. LL_ALIGN_PREFIX(16) -class LLDrawable : public LLRefCount +class LLDrawable +: public LLViewerOctreeEntryData { public: LLDrawable(const LLDrawable& rhs) + : LLViewerOctreeEntryData(rhs) { *this = rhs; } const LLDrawable& operator=(const LLDrawable& rhs) { - llerrs << "Illegal operation!" << llendl; + LL_ERRS() << "Illegal operation!" << LL_ENDL; return *this; } @@ -91,41 +93,35 @@ class LLDrawable : public LLRefCount ll_aligned_free_16(ptr); } - LLDrawable() { init(); } + LLDrawable(LLViewerObject *vobj); void markDead(); // Mark this drawable as dead BOOL isDead() const { return isState(DEAD); } BOOL isNew() const { return !isState(BUILT); } - + BOOL isUnload() const { return isState(FOR_UNLOAD); } BOOL isLight() const; - BOOL isVisible() const; - BOOL isRecentlyVisible() const; virtual void setVisible(LLCamera& camera_in, std::vector* results = NULL, BOOL for_select = FALSE); - + LLSpatialGroup* getSpatialGroup()const {return (LLSpatialGroup*)getGroup();} LLViewerRegion* getRegion() const { return mVObjp->getRegion(); } const LLTextureEntry* getTextureEntry(U8 which) const { return mVObjp->getTE(which); } LLPointer& getVObj() { return mVObjp; } const LLViewerObject *getVObj() const { return mVObjp; } LLVOVolume* getVOVolume() const; // cast mVObjp tp LLVOVolume if OK - const LLMatrix4& getWorldMatrix() const { return mXform.getWorldMatrix(); } - const LLMatrix4& getRenderMatrix() const; + const LLMatrix4a& getWorldMatrix() const { return mXform.getWorldMatrix(); } + const LLMatrix4a& getRenderMatrix() const; void setPosition(LLVector3 v) const { } const LLVector3& getPosition() const { return mXform.getPosition(); } const LLVector3& getWorldPosition() const { return mXform.getPositionW(); } const LLVector3 getPositionAgent() const; - const LLVector4a& getPositionGroup() const { return mPositionGroup; } const LLVector3& getScale() const { return mCurrentScale; } void setScale(const LLVector3& scale) { mCurrentScale = scale; } const LLQuaternion& getWorldRotation() const { return mXform.getWorldRotation(); } const LLQuaternion& getRotation() const { return mXform.getRotation(); } F32 getIntensity() const { return llmin(mXform.getScale().mV[0], 4.f); } S32 getLOD() const { return mVObjp ? mVObjp->getLOD() : 1; } - F32 getBinRadius() const { return mBinRadius; } - S32 getBinIndex() const { return mBinIndex; } - void setBinIndex(S32 index) const { mBinIndex = index; } void getMinMax(LLVector3& min,LLVector3& max) const { mXform.getMinMax(min,max); } LLXformMatrix* getXform() { return &mXform; } @@ -151,12 +147,15 @@ class LLDrawable : public LLRefCount //void removeFace(const S32 i); // SJB: Avoid using this, it's slow LLFace* addFace(LLFacePool *poolp, LLViewerTexture *texturep); LLFace* addFace(const LLTextureEntry *te, LLViewerTexture *texturep); + LLFace* addFace(const LLTextureEntry *te, LLViewerTexture *texturep, LLViewerTexture *normalp); + LLFace* addFace(const LLTextureEntry *te, LLViewerTexture *texturep, LLViewerTexture *normalp, LLViewerTexture *specularp); void deleteFaces(S32 offset, S32 count); void setNumFaces(const S32 numFaces, LLFacePool *poolp, LLViewerTexture *texturep); void setNumFacesFast(const S32 numFaces, LLFacePool *poolp, LLViewerTexture *texturep); void mergeFaces(LLDrawable* src); void init(); + void unload(); void destroy(); void update(); @@ -187,8 +186,12 @@ class LLDrawable : public LLRefCount BOOL getLit() const { return isState(UNLIT) ? FALSE : TRUE; } void setLit(BOOL lit) { lit ? clearState(UNLIT) : setState(UNLIT); } + bool isVisible() const; + bool isRecentlyVisible() const; + virtual void cleanupReferences(); + void setGroup(LLViewerOctreeGroup* group); void setRadius(const F32 radius); F32 getRadius() const { return mRadius; } F32 getVisibilityRadius() const; @@ -198,11 +201,6 @@ class LLDrawable : public LLRefCount const LLVector3& getBounds(LLVector3& min, LLVector3& max) const; virtual void updateSpatialExtents(); virtual void updateBinRadius(); - const LLVector4a* getSpatialExtents() const; - void setSpatialExtents(const LLVector3& min, const LLVector3& max); - void setSpatialExtents(const LLVector4a& min, const LLVector4a& max); - - void setPositionGroup(const LLVector4a& pos); void setRenderType(S32 type) { mRenderType = type; } BOOL isRenderType(S32 type) { return mRenderType == type; } @@ -211,10 +209,13 @@ class LLDrawable : public LLRefCount // Debugging methods S32 findReferences(LLDrawable *drawablep); // Not const because of @#$! iterators... - void setSpatialGroup(LLSpatialGroup *groupp); - LLSpatialGroup *getSpatialGroup() const; LLSpatialPartition* getSpatialPartition(); + void removeFromOctree(); + + void setSpatialBridge(LLSpatialBridge* bridge) { mSpatialBridge = (LLDrawable*) bridge; } + LLSpatialBridge* getSpatialBridge() { return (LLSpatialBridge*) (LLDrawable*) mSpatialBridge; } + // Statics static void incrementVisible(); static void cleanupDeadDrawables(); @@ -296,26 +297,17 @@ class LLDrawable : public LLRefCount PARTITION_MOVE = 0x10000000, ANIMATED_CHILD = 0x20000000, ACTIVE_CHILD = 0x40000000, + FOR_UNLOAD = 0x80000000, //should be unload from memory } EDrawableFlags; - -private: //aligned members - LL_ALIGN_16(LLVector4a mExtents[2]); - LL_ALIGN_16(LLVector4a mPositionGroup); public: - LLXformMatrix mXform; + LL_ALIGN_16(LLXformMatrix mXform); // vis data LLPointer mParent; F32 mDistanceWRTCamera; - static S32 getCurrentFrame() { return sCurVisible; } - static S32 getMinVisFrameRange(); - - void setSpatialBridge(LLSpatialBridge* bridge) { mSpatialBridge = (LLDrawable*) bridge; } - LLSpatialBridge* getSpatialBridge() { return (LLSpatialBridge*) (LLDrawable*) mSpatialBridge; } - static F32 sCurPixelAngle; //current pixels per radian private: @@ -325,21 +317,15 @@ class LLDrawable : public LLRefCount S32 mRenderType; LLPointer mVObjp; face_list_t mFaces; - LLSpatialGroup* mSpatialGroupp; LLPointer mSpatialBridge; - mutable U32 mVisible; F32 mRadius; - F32 mBinRadius; - mutable S32 mBinIndex; S32 mGeneration; LLVector3 mCurrentScale; - static U32 sCurVisible; // Counter for what value of mVisible means currently visible - static U32 sNumZombieDrawables; - static LLDynamicArrayPtr > sDeadList; + static std::vector > sDeadList; } LL_ALIGN_POSTFIX(16); @@ -351,13 +337,13 @@ inline LLFace* LLDrawable::getFace(const S32 i) const if ((U32) i >= mFaces.size()) { - llwarns << "Invalid face index." << llendl; + LL_WARNS() << "Invalid face index." << LL_ENDL; return NULL; } if (!mFaces[i]) { - llwarns << "Null face found." << llendl; + LL_WARNS() << "Null face found." << LL_ENDL; return NULL; } diff --git a/indra/newview/lldrawpool.cpp b/indra/newview/lldrawpool.cpp index 909cec540c..b1d393e9bb 100644 --- a/indra/newview/lldrawpool.cpp +++ b/indra/newview/lldrawpool.cpp @@ -35,6 +35,7 @@ #include "lldrawpoolalpha.h" #include "lldrawpoolavatar.h" #include "lldrawpoolbump.h" +#include "lldrawpoolmaterials.h" #include "lldrawpoolground.h" #include "lldrawpoolsimple.h" #include "lldrawpoolsky.h" @@ -47,6 +48,7 @@ #include "llspatialpartition.h" #include "llviewercamera.h" #include "lldrawpoolwlsky.h" +#include "llglslshader.h" S32 LLDrawPool::sNumDrawPools = 0; @@ -64,12 +66,15 @@ LLDrawPool *LLDrawPool::createPool(const U32 type, LLViewerTexture *tex0) case POOL_GRASS: poolp = new LLDrawPoolGrass(); break; + case POOL_ALPHA_MASK: + poolp = new LLDrawPoolAlphaMask(); + break; + case POOL_FULLBRIGHT_ALPHA_MASK: + poolp = new LLDrawPoolFullbrightAlphaMask(); + break; case POOL_FULLBRIGHT: poolp = new LLDrawPoolFullbright(); break; - case POOL_INVISIBLE: - poolp = new LLDrawPoolInvisible(); - break; case POOL_GLOW: poolp = new LLDrawPoolGlow(); break; @@ -98,11 +103,14 @@ LLDrawPool *LLDrawPool::createPool(const U32 type, LLViewerTexture *tex0) case POOL_BUMP: poolp = new LLDrawPoolBump(); break; + case POOL_MATERIALS: + poolp = new LLDrawPoolMaterials(); + break; case POOL_WL_SKY: poolp = new LLDrawPoolWLSky(); break; default: - llerrs << "Unknown draw pool type!" << llendl; + LL_ERRS() << "Unknown draw pool type!" << LL_ENDL; return NULL; } @@ -243,7 +251,7 @@ void LLFacePool::destroy() { if (!mReferences.empty()) { - llinfos << mReferences.size() << " references left on deletion of draw pool!" << llendl; + LL_INFOS() << mReferences.size() << " references left on deletion of draw pool!" << LL_ENDL; } } @@ -286,17 +294,15 @@ LLViewerTexture *LLFacePool::getTexture() void LLFacePool::removeFaceReference(LLFace *facep) { - if (facep->getReferenceIndex() != -1) + S32 idx = facep->getReferenceIndex(); + if (idx != -1) { - if (facep->getReferenceIndex() != (S32)mReferences.size()) - { - LLFace *back = mReferences.back(); - mReferences[facep->getReferenceIndex()] = back; - back->setReferenceIndex(facep->getReferenceIndex()); - } - mReferences.pop_back(); + facep->setReferenceIndex(-1); + std::vector::iterator face_it(mReferences.begin() + idx); + std::vector::iterator iter = vector_replace_with_last(mReferences, face_it); + if(iter != mReferences.end()) + (*iter)->setReferenceIndex(idx); } - facep->setReferenceIndex(-1); } void LLFacePool::addFaceReference(LLFace *facep) @@ -318,7 +324,7 @@ BOOL LLFacePool::verify() const const LLFace* facep = *iter; if (facep->getPool() != this) { - llinfos << "Face in wrong pool!" << llendl; + LL_INFOS() << "Face in wrong pool!" << LL_ENDL; facep->printDebugInfo(); ok = FALSE; } @@ -333,7 +339,7 @@ BOOL LLFacePool::verify() const void LLFacePool::printDebugInfo() const { - llinfos << "Pool " << this << " Type: " << getType() << llendl; + LL_INFOS() << "Pool " << this << " Type: " << getType() << LL_ENDL; } BOOL LLFacePool::LLOverrideFaceColor::sOverrideFaceColor = FALSE; @@ -345,7 +351,7 @@ void LLFacePool::LLOverrideFaceColor::setColor(const LLColor4& color) void LLFacePool::LLOverrideFaceColor::setColor(const LLColor4U& color) { - glColor4ubv(color.mV); + gGL.diffuseColor4ubv(color.mV); } void LLFacePool::LLOverrideFaceColor::setColor(F32 r, F32 g, F32 b, F32 a) @@ -371,9 +377,9 @@ LLRenderPass::~LLRenderPass() LLDrawPool* LLRenderPass::instancePool() { #if LL_RELEASE_FOR_DOWNLOAD - llwarns << "Attempting to instance a render pass. Invalid operation." << llendl; + LL_WARNS() << "Attempting to instance a render pass. Invalid operation." << LL_ENDL; #else - llerrs << "Attempting to instance a render pass. Invalid operation." << llendl; + LL_ERRS() << "Attempting to instance a render pass. Invalid operation." << LL_ENDL; #endif return NULL; } @@ -408,6 +414,27 @@ void LLRenderPass::pushBatches(U32 type, U32 mask, BOOL texture, BOOL batch_text } } +void LLRenderPass::pushMaskBatches(U32 type, U32 mask, BOOL texture, BOOL batch_textures) +{ + for (LLCullResult::drawinfo_iterator i = gPipeline.beginRenderMap(type); i != gPipeline.endRenderMap(type); ++i) + { + LLDrawInfo* pparams = *i; + if (pparams) + { + if (LLGLSLShader::sCurBoundShaderPtr) + { + LLGLSLShader::sCurBoundShaderPtr->setMinimumAlpha(pparams->mAlphaMaskCutoff); + } + else + { + gGL.setAlphaRejectSettings(LLRender::CF_GREATER, pparams->mAlphaMaskCutoff); + } + + pushBatch(*pparams, mask, texture, batch_textures); + } + } +} + void LLRenderPass::applyModelMatrix(LLDrawInfo& params) { if (params.mModelMatrix != gGLLastMatrix) @@ -417,7 +444,7 @@ void LLRenderPass::applyModelMatrix(LLDrawInfo& params) if (params.mModelMatrix) { llassert(gGL.getMatrixMode() == LLRender::MM_MODELVIEW); - gGL.multMatrix((GLfloat*) params.mModelMatrix->mMatrix); + gGL.multMatrix(*params.mModelMatrix); } gPipeline.mMatrixOpCount++; } @@ -452,7 +479,7 @@ void LLRenderPass::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL ba tex_setup = true; gGL.getTexUnit(0)->activate(); gGL.matrixMode(LLRender::MM_TEXTURE); - gGL.loadMatrix((GLfloat*) params.mTextureMatrix->mMatrix); + gGL.loadMatrix(*params.mTextureMatrix); gPipeline.mTextureMatrixOps++; } } diff --git a/indra/newview/lldrawpool.h b/indra/newview/lldrawpool.h index 384e398372..1e4070f244 100644 --- a/indra/newview/lldrawpool.h +++ b/indra/newview/lldrawpool.h @@ -46,27 +46,24 @@ class LLDrawPool enum { // Correspond to LLPipeline render type - POOL_SIMPLE = 1, - POOL_GROUND, + POOL_GROUND = 1, + POOL_TERRAIN, + POOL_SIMPLE, POOL_FULLBRIGHT, POOL_BUMP, - POOL_TERRAIN, + POOL_MATERIALS, POOL_TREE, // Singu Note: Before sky for zcull. + POOL_ALPHA_MASK, + POOL_FULLBRIGHT_ALPHA_MASK, POOL_SKY, POOL_WL_SKY, POOL_GRASS, - POOL_INVISIBLE, // see below * POOL_AVATAR, POOL_VOIDWATER, POOL_WATER, POOL_GLOW, POOL_ALPHA, NUM_POOL_TYPES, - // * invisiprims work by rendering to the depth buffer but not the color buffer, occluding anything rendered after them - // - and the LLDrawPool types enum controls what order things are rendered in - // - so, it has absolute control over what invisprims block - // ...invisiprims being rendered in pool_invisible - // ...shiny/bump mapped objects in rendered in POOL_BUMP }; LLDrawPool(const U32 type); @@ -123,12 +120,26 @@ class LLRenderPass : public LLDrawPool PASS_SIMPLE = NUM_POOL_TYPES, PASS_GRASS, PASS_FULLBRIGHT, - PASS_INVISIBLE, - PASS_INVISI_SHINY, PASS_FULLBRIGHT_SHINY, PASS_SHINY, PASS_BUMP, PASS_POST_BUMP, + PASS_MATERIAL, + PASS_MATERIAL_ALPHA, + PASS_MATERIAL_ALPHA_MASK, + PASS_MATERIAL_ALPHA_EMISSIVE, + PASS_SPECMAP, + PASS_SPECMAP_BLEND, + PASS_SPECMAP_MASK, + PASS_SPECMAP_EMISSIVE, + PASS_NORMMAP, + PASS_NORMMAP_BLEND, + PASS_NORMMAP_MASK, + PASS_NORMMAP_EMISSIVE, + PASS_NORMSPEC, + PASS_NORMSPEC_BLEND, + PASS_NORMSPEC_MASK, + PASS_NORMSPEC_EMISSIVE, PASS_GLOW, PASS_ALPHA, PASS_ALPHA_MASK, @@ -147,6 +158,7 @@ class LLRenderPass : public LLDrawPool static void applyModelMatrix(LLDrawInfo& params); virtual void pushBatches(U32 type, U32 mask, BOOL texture = TRUE, BOOL batch_textures = FALSE); + virtual void pushMaskBatches(U32 type, U32 mask, BOOL texture = TRUE, BOOL batch_textures = FALSE); virtual void pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures = FALSE); virtual void renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture = TRUE); virtual void renderGroups(U32 type, U32 mask, BOOL texture = TRUE); diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp index 7d65bd359a..328d514d0d 100644 --- a/indra/newview/lldrawpoolalpha.cpp +++ b/indra/newview/lldrawpoolalpha.cpp @@ -77,33 +77,6 @@ void LLDrawPoolAlpha::prerender() mVertexShaderLevel = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT); } -S32 LLDrawPoolAlpha::getNumDeferredPasses() -{ - return 1; -} - -void LLDrawPoolAlpha::beginDeferredPass(S32 pass) -{ - -} - -void LLDrawPoolAlpha::endDeferredPass(S32 pass) -{ - -} - -void LLDrawPoolAlpha::renderDeferred(S32 pass) -{ - LLFastTimer t(FTM_RENDER_GRASS); - gDeferredDiffuseAlphaMaskProgram.bind(); - gDeferredDiffuseAlphaMaskProgram.setMinimumAlpha(0.33f); - - //render alpha masked objects - LLRenderPass::pushBatches(LLRenderPass::PASS_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); - gDeferredDiffuseAlphaMaskProgram.unbind(); -} - - S32 LLDrawPoolAlpha::getNumPostDeferredPasses() { static const LLCachedControl render_depth_of_field("RenderDepthOfField"); @@ -123,46 +96,73 @@ S32 LLDrawPoolAlpha::getNumPostDeferredPasses() void LLDrawPoolAlpha::beginPostDeferredPass(S32 pass) { - LLFastTimer t(FTM_RENDER_ALPHA); + LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA); if (pass == 0) { - simple_shader = &gDeferredAlphaProgram; - fullbright_shader = &gObjectFullbrightAlphaMaskProgram; + if (LLPipeline::sImpostorRender) + { + simple_shader = &gDeferredAlphaImpostorProgram; + fullbright_shader = &gDeferredFullbrightProgram; + } + else if (LLPipeline::sUnderWaterRender) + { + simple_shader = &gDeferredAlphaWaterProgram; + fullbright_shader = &gDeferredFullbrightWaterProgram; + } + else + { + simple_shader = &gDeferredAlphaProgram; + fullbright_shader = &gDeferredFullbrightProgram; + } + + //F32 gamma = gSavedSettings.getF32("RenderDeferredDisplayGamma"); + + fullbright_shader->bind(); + fullbright_shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f); + //fullbright_shader->uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f/2.2f)); + fullbright_shader->unbind(); //prime simple shader (loads shadow relevant uniforms) gPipeline.bindDeferredShader(*simple_shader); + gPipeline.unbindDeferredShader(*simple_shader); + + //simple_shader->uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f/2.2f)); } - else + else if (!LLPipeline::sImpostorRender) { //update depth buffer sampler gPipeline.mScreen.flush(); gPipeline.mDeferredDepth.copyContents(gPipeline.mDeferredScreen, 0, 0, gPipeline.mDeferredScreen.getWidth(), gPipeline.mDeferredScreen.getHeight(), 0, 0, gPipeline.mDeferredDepth.getWidth(), gPipeline.mDeferredDepth.getHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST); gPipeline.mDeferredDepth.bindTarget(); - simple_shader = NULL; - fullbright_shader = NULL; - gObjectFullbrightAlphaMaskProgram.bind(); - gObjectFullbrightAlphaMaskProgram.setMinimumAlpha(0.33f); + simple_shader = fullbright_shader = &gObjectFullbrightProgram[1<bind(); + fullbright_shader->setMinimumAlpha(0.33f); } + llassert_always(LLPipeline::sRenderDeferred); + emissive_shader = &gDeferredEmissiveProgram; + deferred_render = TRUE; - if (mVertexShaderLevel > 0) - { - // Start out with no shaders. - current_shader = target_shader = NULL; - } - gPipeline.enableLightsDynamic(); + + // Start out with no shaders. + current_shader = target_shader = NULL; + + LLGLSLShader::bindNoShader(); } void LLDrawPoolAlpha::endPostDeferredPass(S32 pass) -{ - - if (pass == 1) +{ + if (current_shader) + { + gPipeline.unbindDeferredShader(*current_shader); + } + if (pass == 1 && !LLPipeline::sImpostorRender) { gPipeline.mDeferredDepth.flush(); gPipeline.mScreen.bindTarget(); - gObjectFullbrightAlphaMaskProgram.unbind(); + gObjectFullbrightProgram[1< 0) { - // Start out with no shaders. - current_shader = target_shader = NULL; LLGLSLShader::bindNoShader(); } - gPipeline.enableLightsDynamic(); } void LLDrawPoolAlpha::endRenderPass( S32 pass ) { - LLFastTimer t(FTM_RENDER_ALPHA); + LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA); LLRenderPass::endRenderPass(pass); - if(mVertexShaderLevel > 0) + if(mVertexShaderLevel > 0) //Singu Note: Unbind if shaders are enabled at all, not just windlight atmospherics.. { LLGLSLShader::bindNoShader(); } @@ -213,9 +204,11 @@ void LLDrawPoolAlpha::endRenderPass( S32 pass ) void LLDrawPoolAlpha::render(S32 pass) { - LLFastTimer t(FTM_RENDER_ALPHA); + LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA); LLGLSPipelineAlpha gls_pipeline_alpha; + LLGLState light_state; + gPipeline.enableLightsDynamic(light_state); if (deferred_render && pass == 1) { //depth only @@ -225,45 +218,13 @@ void LLDrawPoolAlpha::render(S32 pass) { gGL.setColorMask(true, true); } + + bool write_depth = (deferred_render && pass == 1) + // we want depth written so that rendered alpha will + // contribute to the alpha mask used for impostors + || LLPipeline::sImpostorRenderAlphaDepthPass; - if (LLPipeline::sAutoMaskAlphaNonDeferred) - { - mColorSFactor = LLRender::BF_ONE; // } - mColorDFactor = LLRender::BF_ZERO; // } these are like disabling blend on the color channels, but we're still blending on the alpha channel so that we can suppress glow - mAlphaSFactor = LLRender::BF_ZERO; - mAlphaDFactor = LLRender::BF_ZERO; // block (zero-out) glow where the alpha test succeeds - gGL.blendFunc(mColorSFactor, mColorDFactor, mAlphaSFactor, mAlphaDFactor); - - if (mVertexShaderLevel > 0) - { - if (!LLPipeline::sRenderDeferred || !deferred_render) - { - simple_shader->bind(); - simple_shader->setMinimumAlpha(0.33f); - - pushBatches(LLRenderPass::PASS_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); - } - if (fullbright_shader) - { - fullbright_shader->bind(); - fullbright_shader->setMinimumAlpha(0.33f); - } - pushBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); - //LLGLSLShader::bindNoShader(); - } - else - { - gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.33f); //OK - gPipeline.enableLightsFullbright(LLColor4(1,1,1,1)); - pushBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, getVertexDataMask()); - gPipeline.enableLightsDynamic(); - pushBatches(LLRenderPass::PASS_ALPHA_MASK, getVertexDataMask()); - gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); //OK - } - } - - LLGLDepthTest depth(GL_TRUE, (LLDrawPoolWater::sSkipScreenCopy || - (deferred_render && pass == 1)) ? GL_TRUE : GL_FALSE); + LLGLDepthTest depth(GL_TRUE, write_depth ? GL_TRUE : GL_FALSE); if (deferred_render && pass == 1) { @@ -279,20 +240,14 @@ void LLDrawPoolAlpha::render(S32 pass) if (mVertexShaderLevel > 0) { - if (LLPipeline::sImpostorRender) - { - fullbright_shader->bind(); - fullbright_shader->setMinimumAlpha(0.5f); - simple_shader->bind(); - simple_shader->setMinimumAlpha(0.5f); - } - else - { - fullbright_shader->bind(); - fullbright_shader->setMinimumAlpha(0.f); - simple_shader->bind(); - simple_shader->setMinimumAlpha(0.f); - } + float min_alpha = LLPipeline::sImpostorRender ? 0.5f : 0.004f; + + fullbright_shader->bind(); + fullbright_shader->setMinimumAlpha(min_alpha); + simple_shader->bind(); + simple_shader->setMinimumAlpha(min_alpha); + emissive_shader->bind(); + emissive_shader->setMinimumAlpha(min_alpha); } else { @@ -307,14 +262,7 @@ void LLDrawPoolAlpha::render(S32 pass) } } - if (mVertexShaderLevel > 0) - { - renderAlpha(getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX); - } - else - { - renderAlpha(getVertexDataMask()); - } + renderAlpha(getVertexDataMask(), pass); //getVertexDataMask base mask if fixed-function. gGL.setColorMask(true, false); @@ -325,17 +273,17 @@ void LLDrawPoolAlpha::render(S32 pass) if (sShowDebugAlpha) { - BOOL shaders = gPipeline.canUseVertexShaders(); - if(shaders) + LLGLState light_state; + if (LLGLSLShader::sNoFixedFunction) { gHighlightProgram.bind(); } else { - gPipeline.enableLightsFullbright(LLColor4(1,1,1,1)); + gPipeline.enableLightsFullbright(light_state); } - gGL.diffuseColor4f(1,0,0,1); + gGL.diffuseColor4f(0.9f,0.f,0.f,0.4f); LLViewerFetchedTexture::sSmokeImagep->addTextureStats(1024.f*1024.f); gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sSmokeImagep, TRUE) ; @@ -346,10 +294,14 @@ void LLDrawPoolAlpha::render(S32 pass) pushBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, FALSE); pushBatches(LLRenderPass::PASS_ALPHA_INVISIBLE, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, FALSE); - if(shaders) + if (LLGLSLShader::sNoFixedFunction) { gHighlightProgram.unbind(); } + else + { + gPipeline.enableLightsDynamic(light_state); + } } gGL.setSceneBlendType(LLRender::BT_ALPHA); } @@ -359,7 +311,7 @@ void LLDrawPoolAlpha::renderAlphaHighlight(U32 mask) for (LLCullResult::sg_iterator i = gPipeline.beginAlphaGroups(); i != gPipeline.endAlphaGroups(); ++i) { LLSpatialGroup* group = *i; - if (group->mSpatialPartition->mRenderByGroup && + if (group->getSpatialPartition()->mRenderByGroup && !group->isDead()) { LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[LLRenderPass::PASS_ALPHA]; @@ -386,29 +338,33 @@ void LLDrawPoolAlpha::renderAlphaHighlight(U32 mask) } } -void LLDrawPoolAlpha::renderAlpha(U32 mask) +void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass) { - BOOL initialized_lighting = FALSE; - BOOL light_enabled = TRUE; - - BOOL use_shaders = gPipeline.canUseVertexShaders(); + LLGLState light_state; + bool light_enabled = TRUE; + bool use_shaders = LLGLSLShader::sNoFixedFunction; + bool depth_only = (pass == 1 && !LLPipeline::sImpostorRender); for (LLCullResult::sg_iterator i = gPipeline.beginAlphaGroups(); i != gPipeline.endAlphaGroups(); ++i) { LLSpatialGroup* group = *i; llassert(group); - llassert(group->mSpatialPartition); + llassert(group->getSpatialPartition()); - if (group->mSpatialPartition->mRenderByGroup && + if (group->getSpatialPartition()->mRenderByGroup && !group->isDead()) { - bool draw_glow_for_this_partition = mVertexShaderLevel > 0 && // no shaders = no glow. - // All particle systems seem to come off the wire with texture entries which claim that they glow. This is probably a bug in the data. Suppress. - group->mSpatialPartition->mPartitionType != LLViewerRegion::PARTITION_PARTICLE && -#if ENABLE_CLASSIC_CLOUDS - group->mSpatialPartition->mPartitionType != LLViewerRegion::PARTITION_CLOUD && -#endif - group->mSpatialPartition->mPartitionType != LLViewerRegion::PARTITION_HUD_PARTICLE; + bool is_particle_or_hud_particle = group->getSpatialPartition()->mPartitionType == LLViewerRegion::PARTITION_PARTICLE + || group->getSpatialPartition()->mPartitionType == LLViewerRegion::PARTITION_CLOUD + || group->getSpatialPartition()->mPartitionType == LLViewerRegion::PARTITION_HUD_PARTICLE; + + bool draw_glow_for_this_partition = !depth_only && mVertexShaderLevel > 0; // no shaders = no glow. + + static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_GROUP_LOOP("Alpha Group"); + LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_GROUP_LOOP); + + bool disable_cull = is_particle_or_hud_particle; + LLGLDisable cull(disable_cull); LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[LLRenderPass::PASS_ALPHA]; @@ -416,90 +372,156 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask) { LLDrawInfo& params = **k; - if ((params.mVertexBuffer->getTypeMask() & mask) != mask) + /*if ((params.mVertexBuffer->getTypeMask() & mask) != mask) { //FIXME! - llwarns << "Missing required components, skipping render batch." << llendl; + LL_WARNS() << "Missing required components, skipping render batch." << LL_ENDL; continue; + }*/ + + // Fix for bug - NORSPEC-271 + // If the face is more than 90% transparent, then don't update the Depth buffer for Dof + // We don't want the nearly invisible objects to cause of DoF effects + if(depth_only) + { + LLFace* face = params.mFace; + if(face) + { + const LLTextureEntry* tep = face->getTextureEntry(); + if(tep) + { + if(tep->getColor().mV[3] < 0.1f) + continue; + } + } } LLRenderPass::applyModelMatrix(params); + // Singu Note: Logic reordered here. Removed a fair bit of unneeded condition checks (mostly related to deferred mode), and made + // shader selection more explicit. - if (params.mFullbright) + if (params.mGroup) { - // Turn off lighting if it hasn't already been so. - if (light_enabled || !initialized_lighting) - { - initialized_lighting = TRUE; - if (use_shaders) - { - target_shader = fullbright_shader; - } - else - { - gPipeline.enableLightsFullbright(LLColor4(1,1,1,1)); - } - light_enabled = FALSE; - } - } - // Turn on lighting if it isn't already. - else if (!light_enabled || !initialized_lighting) + params.mGroup->rebuildMesh(); + } + + LLMaterial* mat = deferred_render ? params.mMaterial.get() : NULL; + if (!use_shaders) + { + llassert_always(!target_shader); + llassert_always(!current_shader); + llassert_always(!LLGLSLShader::sNoFixedFunction); + llassert_always(!LLGLSLShader::sCurBoundShaderPtr); + + bool fullbright = depth_only || params.mFullbright; + if(light_enabled == fullbright) { - initialized_lighting = TRUE; - if (use_shaders) + light_enabled = !fullbright; + + if (light_enabled) // Set local lights { - target_shader = simple_shader; + gPipeline.enableLightsDynamic(light_state); } - else + else // Set fullbright { - gPipeline.enableLightsDynamic(); + gPipeline.enableLightsFullbright(light_state); } - light_enabled = TRUE; } - - // If we need shaders, and we're not ALREADY using the proper shader, then bind it - // (this way we won't rebind shaders unnecessarily). - if(use_shaders && (current_shader != target_shader)) - { - llassert(target_shader != NULL); - current_shader = target_shader; - current_shader->bind(); } - else if (!use_shaders && current_shader != NULL) + else { - LLGLSLShader::bindNoShader(); - current_shader = NULL; - } + if (mat) + { + U32 mask = params.mShaderMask; + + llassert(mask < LLMaterial::SHADER_COUNT); + target_shader = LLPipeline::sUnderWaterRender ? &(gDeferredMaterialWaterProgram[mask]) : &(gDeferredMaterialProgram[mask]); - if (params.mGroup) + // If we need shaders, and we're not ALREADY using the proper shader, then bind it + // (this way we won't rebind shaders unnecessarily). + if (current_shader != target_shader) + { + if(current_shader) + gPipeline.unbindDeferredShader(*current_shader); + gPipeline.bindDeferredShader(*target_shader); + } + } + else { - params.mGroup->rebuildMesh(); + target_shader = params.mFullbright ? fullbright_shader : simple_shader; + + // If we need shaders, and we're not ALREADY using the proper shader, then bind it + // (this way we won't rebind shaders unnecessarily). + if(current_shader != target_shader) + { + if(current_shader) + gPipeline.unbindDeferredShader(*current_shader); + gPipeline.bindDeferredShader(*target_shader); + } } + current_shader = target_shader; - bool tex_setup = false; + if(mat) + { + current_shader->uniform4f(LLShaderMgr::SPECULAR_COLOR, params.mSpecColor.mV[0], params.mSpecColor.mV[1], params.mSpecColor.mV[2], params.mSpecColor.mV[3]); + current_shader->uniform1f(LLShaderMgr::ENVIRONMENT_INTENSITY, params.mEnvIntensity); + current_shader->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, params.mFullbright ? 1.f : 0.f); - if (use_shaders && params.mTextureList.size() > 1) - { - for (U32 i = 0; i < params.mTextureList.size(); ++i) + if (params.mNormalMap) + { + params.mNormalMap->addTextureStats(params.mVSize); + current_shader->bindTexture(LLShaderMgr::BUMP_MAP, params.mNormalMap); + } + + if (params.mSpecularMap) + { + params.mSpecularMap->addTextureStats(params.mVSize); + current_shader->bindTexture(LLShaderMgr::SPECULAR_MAP, params.mSpecularMap); + } + } + /*else if(deferred_render && current_shader == simple_shader) { - if (params.mTextureList[i].notNull()) + current_shader->uniform4f(LLShaderMgr::SPECULAR_COLOR, 1.0f, 1.0f, 1.0f, 1.0f); + current_shader->uniform1f(LLShaderMgr::ENVIRONMENT_INTENSITY, 0.0f); + LLViewerFetchedTexture::sFlatNormalImagep->addTextureStats(params.mVSize); + current_shader->bindTexture(LLShaderMgr::BUMP_MAP, LLViewerFetchedTexture::sFlatNormalImagep); + LLViewerFetchedTexture::sWhiteImagep->addTextureStats(params.mVSize); + current_shader->bindTexture(LLShaderMgr::SPECULAR_MAP, LLViewerFetchedTexture::sWhiteImagep); + }*/ + + if (params.mTextureList.size() > 1) + { + for (U32 i = 0; i < params.mTextureList.size(); ++i) { - gGL.getTexUnit(i)->bind(params.mTextureList[i], TRUE); + if (params.mTextureList[i].notNull()) + { + gGL.getTexUnit(i)->bind(params.mTextureList[i], TRUE); + } } } } - else + + bool tex_setup = false; + if(!use_shaders || params.mTextureList.size() <= 1) { //not batching textures or batch has only 1 texture -- might need a texture matrix if (params.mTexture.notNull()) { params.mTexture->addTextureStats(params.mVSize); - gGL.getTexUnit(0)->bind(params.mTexture, TRUE) ; + if (use_shaders && mat && current_shader) + { + current_shader->bindTexture(LLShaderMgr::DIFFUSE_MAP, params.mTexture); + } + else + { + gGL.getTexUnit(0)->bind(params.mTexture, TRUE); + } + if (params.mTextureMatrix) { tex_setup = true; gGL.getTexUnit(0)->activate(); gGL.matrixMode(LLRender::MM_TEXTURE); - gGL.loadMatrix((GLfloat*) params.mTextureMatrix->mMatrix); + gGL.loadMatrix(*params.mTextureMatrix); gPipeline.mTextureMatrixOps++; } } @@ -509,32 +531,43 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask) } } - params.mVertexBuffer->setBuffer(mask); - params.mVertexBuffer->drawRange(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset); - gPipeline.addTrianglesDrawn(params.mCount, params.mDrawMode); + static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_PUSH("Alpha Push Verts"); + { + LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_PUSH); + + gGL.blendFunc((LLRender::eBlendFactor) params.mBlendFuncSrc, (LLRender::eBlendFactor) params.mBlendFuncDst, mAlphaSFactor, mAlphaDFactor); + // Singu Note: If using shaders, pull the attribute mask from it, else used passed base mask. + params.mVertexBuffer->setBuffer(current_shader ? current_shader->mAttributeMask : mask); + + params.mVertexBuffer->drawRange(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset); + gPipeline.addTrianglesDrawn(params.mCount, params.mDrawMode); + } // If this alpha mesh has glow, then draw it a second time to add the destination-alpha (=glow). Interleaving these state-changing calls could be expensive, but glow must be drawn Z-sorted with alpha. if (current_shader && draw_glow_for_this_partition && + (!is_particle_or_hud_particle || params.mHasGlow) && //only do this second pass for batches that actually have glow params.mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_EMISSIVE)) { // install glow-accumulating blend mode gGL.blendFunc(LLRender::BF_ZERO, LLRender::BF_ONE, // don't touch color LLRender::BF_ONE, LLRender::BF_ONE); // add to alpha (glow) - emissive_shader->bind(); - + //emissive_shader->bind(); + // glow doesn't use vertex colors from the mesh data - params.mVertexBuffer->setBuffer((mask & ~LLVertexBuffer::MAP_COLOR) | LLVertexBuffer::MAP_EMISSIVE); - + // Singu Note: Pull attribs from shader, since we always have one here. + // Singu Note: To avoid ridiculous shader bind cost, simply re-use prior shader, but let llvertexbuffer replace the color attrib ptr with the emissive one. + params.mVertexBuffer->setBuffer(current_shader->mAttributeMask | LLVertexBuffer::MAP_EMISSIVE); + // do the actual drawing, again params.mVertexBuffer->drawRange(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset); gPipeline.addTrianglesDrawn(params.mCount, params.mDrawMode); + //current_shader->bind(); + // restore our alpha blend mode gGL.blendFunc(mColorSFactor, mColorDFactor, mAlphaSFactor, mAlphaDFactor); - - current_shader->bind(); } if (tex_setup) @@ -546,11 +579,12 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask) } } } - - LLVertexBuffer::unbind(); - if (!light_enabled) { - gPipeline.enableLightsDynamic(); + gPipeline.enableLightsDynamic(light_state); } + + gGL.setSceneBlendType(LLRender::BT_ALPHA); + + LLVertexBuffer::unbind(); } diff --git a/indra/newview/lldrawpoolalpha.h b/indra/newview/lldrawpoolalpha.h index 570ed62e24..08e5068d40 100644 --- a/indra/newview/lldrawpoolalpha.h +++ b/indra/newview/lldrawpoolalpha.h @@ -56,11 +56,6 @@ class LLDrawPoolAlpha: public LLRenderPass LLDrawPoolAlpha(U32 type = LLDrawPool::POOL_ALPHA); /*virtual*/ ~LLDrawPoolAlpha(); - /*virtual*/ S32 getNumDeferredPasses(); - /*virtual*/ void beginDeferredPass(S32 pass); - /*virtual*/ void endDeferredPass(S32 pass); - /*virtual*/ void renderDeferred(S32 pass); - /*virtual*/ S32 getNumPostDeferredPasses(); /*virtual*/ void beginPostDeferredPass(S32 pass); /*virtual*/ void endPostDeferredPass(S32 pass); @@ -74,9 +69,9 @@ class LLDrawPoolAlpha: public LLRenderPass /*virtual*/ void prerender(); void renderGroupAlpha(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture = TRUE); - void renderAlpha(U32 mask); + void renderAlpha(U32 mask, S32 pass); void renderAlphaHighlight(U32 mask); - + static BOOL sShowDebugAlpha; private: diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp index 61762272d8..47f55ef690 100644 --- a/indra/newview/lldrawpoolavatar.cpp +++ b/indra/newview/lldrawpoolavatar.cpp @@ -33,6 +33,7 @@ #include "llviewerprecompiledheaders.h" #include "lldrawpoolavatar.h" +#include "llskinningutil.h" #include "llrender.h" #include "llvoavatar.h" @@ -47,7 +48,7 @@ #include "llsky.h" #include "llviewercamera.h" #include "llviewerregion.h" -#include "noise.h" +#include "llperlin.h" #include "pipeline.h" #include "llviewershadermgr.h" #include "llvovolume.h" @@ -55,19 +56,22 @@ #include "llappviewer.h" #include "llrendersphere.h" #include "llviewerpartsim.h" +#include "llviewercontrol.h" // for gSavedSettings static U32 sDataMask = LLDrawPoolAvatar::VERTEX_DATA_MASK; static U32 sBufferUsage = GL_STREAM_DRAW_ARB; static U32 sShaderLevel = 0; - LLGLSLShader* LLDrawPoolAvatar::sVertexProgram = NULL; BOOL LLDrawPoolAvatar::sSkipOpaque = FALSE; BOOL LLDrawPoolAvatar::sSkipTransparent = FALSE; S32 LLDrawPoolAvatar::sDiffuseChannel = 0; +F32 LLDrawPoolAvatar::sMinimumAlpha = 0.2f; static bool is_deferred_render = false; +static bool is_post_deferred_render = false; +static bool is_mats_render = false; extern BOOL gUseGLPick; @@ -105,13 +109,39 @@ S32 normal_channel = -1; S32 specular_channel = -1; S32 cube_channel = -1; -static LLFastTimer::DeclareTimer FTM_SHADOW_AVATAR("Avatar Shadow"); +static LLTrace::BlockTimerStatHandle FTM_SHADOW_AVATAR("Avatar Shadow"); LLDrawPoolAvatar::LLDrawPoolAvatar() : LLFacePool(POOL_AVATAR) { } +LLDrawPoolAvatar::~LLDrawPoolAvatar() +{ + if (!isDead()) + { + LL_WARNS() << "Destroying avatar drawpool that still contains faces" << LL_ENDL; + } +} + +// virtual +BOOL LLDrawPoolAvatar::isDead() +{ + if (!LLFacePool::isDead()) + { + return FALSE; + } + + for (U32 i = 0; i < NUM_RIGGED_PASSES; ++i) + { + if (mRiggedFace[i].size() > 0) + { + return FALSE; + } + } + return TRUE; +} + //----------------------------------------------------------------------------- // instancePool() //----------------------------------------------------------------------------- @@ -153,16 +183,9 @@ void LLDrawPoolAvatar::prerender() } } -LLMatrix4& LLDrawPoolAvatar::getModelView() +const LLMatrix4a& LLDrawPoolAvatar::getModelView() { - static LLMatrix4 ret; - - ret.initRows(LLVector4(gGLModelView+0), - LLVector4(gGLModelView+4), - LLVector4(gGLModelView+8), - LLVector4(gGLModelView+12)); - - return ret; + return gGLModelView; } //----------------------------------------------------------------------------- @@ -170,7 +193,7 @@ LLMatrix4& LLDrawPoolAvatar::getModelView() //----------------------------------------------------------------------------- void LLDrawPoolAvatar::beginDeferredPass(S32 pass) { - LLFastTimer t(FTM_RENDER_CHARACTERS); + LL_RECORD_BLOCK_TIME(FTM_RENDER_CHARACTERS); sSkipTransparent = TRUE; is_deferred_render = true; @@ -197,12 +220,15 @@ void LLDrawPoolAvatar::beginDeferredPass(S32 pass) case 4: beginDeferredRiggedBump(); break; + default: + beginDeferredRiggedMaterial(pass-5); + break; } } void LLDrawPoolAvatar::endDeferredPass(S32 pass) { - LLFastTimer t(FTM_RENDER_CHARACTERS); + LL_RECORD_BLOCK_TIME(FTM_RENDER_CHARACTERS); sSkipTransparent = FALSE; is_deferred_render = false; @@ -229,6 +255,9 @@ void LLDrawPoolAvatar::endDeferredPass(S32 pass) case 4: endDeferredRiggedBump(); break; + default: + endDeferredRiggedMaterial(pass-5); + break; } } @@ -239,7 +268,7 @@ void LLDrawPoolAvatar::renderDeferred(S32 pass) S32 LLDrawPoolAvatar::getNumPostDeferredPasses() { - return 6; + return 10; } void LLDrawPoolAvatar::beginPostDeferredPass(S32 pass) @@ -261,9 +290,12 @@ void LLDrawPoolAvatar::beginPostDeferredPass(S32 pass) case 4: beginRiggedFullbrightAlpha(); break; - case 5: + case 9: beginRiggedGlow(); break; + default: + beginDeferredRiggedMaterialAlpha(pass-5); + break; } } @@ -276,7 +308,7 @@ void LLDrawPoolAvatar::beginPostDeferredAlpha() gPipeline.bindDeferredShader(*sVertexProgram); - sVertexProgram->setMinimumAlpha(0.2f); + sVertexProgram->setMinimumAlpha(LLDrawPoolAvatar::sMinimumAlpha); sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); } @@ -286,14 +318,37 @@ void LLDrawPoolAvatar::beginDeferredRiggedAlpha() sVertexProgram = &gDeferredSkinnedAlphaProgram; gPipeline.bindDeferredShader(*sVertexProgram); sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); - gPipeline.enableLightsDynamic(); + gPipeline.enableLightsDynamic(*(LLGLState*)gPipeline.pushRenderPassState()); } +void LLDrawPoolAvatar::beginDeferredRiggedMaterialAlpha(S32 pass) +{ + switch (pass) + { + case 0: pass = 1; break; + case 1: pass = 5; break; + case 2: pass = 9; break; + default: pass = 13; break; + } + pass += LLMaterial::SHADER_COUNT; + sVertexProgram = &gDeferredMaterialProgram[pass]; + if (LLPipeline::sUnderWaterRender) + { + sVertexProgram = &(gDeferredMaterialWaterProgram[pass]); + } + gPipeline.bindDeferredShader(*sVertexProgram); + sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); + normal_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::BUMP_MAP); + specular_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::SPECULAR_MAP); + gPipeline.enableLightsDynamic(*(LLGLState*)gPipeline.pushRenderPassState()); +} void LLDrawPoolAvatar::endDeferredRiggedAlpha() { LLVertexBuffer::unbind(); gPipeline.unbindDeferredShader(*sVertexProgram); sDiffuseChannel = 0; + normal_channel = -1; + specular_channel = -1; sVertexProgram = NULL; } @@ -319,6 +374,9 @@ void LLDrawPoolAvatar::endPostDeferredPass(S32 pass) case 5: endRiggedGlow(); break; + default: + endDeferredRiggedAlpha(); + break; } } @@ -335,7 +393,7 @@ void LLDrawPoolAvatar::endPostDeferredAlpha() void LLDrawPoolAvatar::renderPostDeferred(S32 pass) { - const S32 actual_pass[] = + static const S32 actual_pass[] = { //map post deferred pass numbers to what render() expects 2, //skinned 4, // rigged fullbright @@ -343,16 +401,22 @@ void LLDrawPoolAvatar::renderPostDeferred(S32 pass) 7, //rigged alpha 8, //rigged fullbright alpha 9, //rigged glow + 10,//rigged material alpha 2 + 11,//rigged material alpha 3 + 12,//rigged material alpha 4 + 13, //rigged glow }; - pass = actual_pass[pass]; + S32 p = actual_pass[pass]; if (LLPipeline::sImpostorRender) { //HACK for impostors so actual pass ends up being proper pass - pass -= 2; + p -= 2; } - render(pass); + is_post_deferred_render = true; + render(p); + is_post_deferred_render = false; } @@ -363,7 +427,7 @@ S32 LLDrawPoolAvatar::getNumShadowPasses() void LLDrawPoolAvatar::beginShadowPass(S32 pass) { - LLFastTimer t(FTM_SHADOW_AVATAR); + LL_RECORD_BLOCK_TIME(FTM_SHADOW_AVATAR); if (pass == 0) { @@ -389,7 +453,7 @@ void LLDrawPoolAvatar::beginShadowPass(S32 pass) void LLDrawPoolAvatar::endShadowPass(S32 pass) { - LLFastTimer t(FTM_SHADOW_AVATAR); + LL_RECORD_BLOCK_TIME(FTM_SHADOW_AVATAR); if (pass == 0) { if (sShaderLevel > 0) @@ -408,7 +472,7 @@ void LLDrawPoolAvatar::endShadowPass(S32 pass) void LLDrawPoolAvatar::renderShadow(S32 pass) { - LLFastTimer t(FTM_SHADOW_AVATAR); + LL_RECORD_BLOCK_TIME(FTM_SHADOW_AVATAR); if (mDrawFace.empty()) { @@ -422,7 +486,7 @@ void LLDrawPoolAvatar::renderShadow(S32 pass) } LLVOAvatar *avatarp = (LLVOAvatar *)facep->getDrawable()->getVObj().get(); - if (avatarp->isDead() || avatarp->mIsDummy || avatarp->mDrawable.isNull()) + if (avatarp->isDead() || avatarp->isUIAvatar() || avatarp->mDrawable.isNull()) { return; } @@ -439,12 +503,10 @@ void LLDrawPoolAvatar::renderShadow(S32 pass) } else { - renderRigged(avatarp, RIGGED_SIMPLE); - renderRigged(avatarp, RIGGED_ALPHA); - renderRigged(avatarp, RIGGED_FULLBRIGHT); - renderRigged(avatarp, RIGGED_FULLBRIGHT_SHINY); - renderRigged(avatarp, RIGGED_SHINY); - renderRigged(avatarp, RIGGED_FULLBRIGHT_ALPHA); + for (U32 i = 0; i < NUM_RIGGED_PASSES; ++i) + { + renderRigged(avatarp, i); + } } } @@ -465,18 +527,18 @@ S32 LLDrawPoolAvatar::getNumDeferredPasses() { if (LLPipeline::sImpostorRender) { - return 3; + return 19; } else { - return 5; + return 21; } } void LLDrawPoolAvatar::render(S32 pass) { - LLFastTimer t(FTM_RENDER_CHARACTERS); + LL_RECORD_BLOCK_TIME(FTM_RENDER_CHARACTERS); if (LLPipeline::sImpostorRender) { renderAvatars(NULL, pass+2); @@ -488,7 +550,7 @@ void LLDrawPoolAvatar::render(S32 pass) void LLDrawPoolAvatar::beginRenderPass(S32 pass) { - LLFastTimer t(FTM_RENDER_CHARACTERS); + LL_RECORD_BLOCK_TIME(FTM_RENDER_CHARACTERS); //reset vertex buffer mappings LLVertexBuffer::unbind(); @@ -539,7 +601,7 @@ void LLDrawPoolAvatar::beginRenderPass(S32 pass) void LLDrawPoolAvatar::endRenderPass(S32 pass) { - LLFastTimer t(FTM_RENDER_CHARACTERS); + LL_RECORD_BLOCK_TIME(FTM_RENDER_CHARACTERS); if (LLPipeline::sImpostorRender) { @@ -595,7 +657,7 @@ void LLDrawPoolAvatar::beginImpostor() gImpostorProgram.setMinimumAlpha(0.01f); } - gPipeline.enableLightsFullbright(LLColor4(1,1,1,1)); + gPipeline.enableLightsFullbright(*(LLGLState*)gPipeline.pushRenderPassState()); sDiffuseChannel = 0; } @@ -605,12 +667,11 @@ void LLDrawPoolAvatar::endImpostor() { gImpostorProgram.unbind(); } - gPipeline.enableLightsDynamic(); } void LLDrawPoolAvatar::beginRigid() { - if (gPipeline.canUseVertexShaders()) + if (LLGLSLShader::sNoFixedFunction) { if (LLPipeline::sUnderWaterRender) { @@ -624,7 +685,7 @@ void LLDrawPoolAvatar::beginRigid() if (sVertexProgram != NULL) { //eyeballs render with the specular shader sVertexProgram->bind(); - sVertexProgram->setMinimumAlpha(0.2f); + sVertexProgram->setMinimumAlpha(LLDrawPoolAvatar::sMinimumAlpha); } } else @@ -666,8 +727,9 @@ void LLDrawPoolAvatar::endDeferredImpostor() sVertexProgram->disableTexture(LLViewerShaderMgr::DEFERRED_NORMAL); sVertexProgram->disableTexture(LLViewerShaderMgr::SPECULAR_MAP); sVertexProgram->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP); - sVertexProgram->unbind(); - gGL.getTexUnit(0)->activate(); + gPipeline.unbindDeferredShader(*sVertexProgram); + sVertexProgram = NULL; + sDiffuseChannel = 0; } void LLDrawPoolAvatar::beginDeferredRigid() @@ -675,7 +737,7 @@ void LLDrawPoolAvatar::beginDeferredRigid() sVertexProgram = &gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram; sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); sVertexProgram->bind(); - sVertexProgram->setMinimumAlpha(0.2f); + sVertexProgram->setMinimumAlpha(LLDrawPoolAvatar::sMinimumAlpha); } void LLDrawPoolAvatar::endDeferredRigid() @@ -689,12 +751,18 @@ void LLDrawPoolAvatar::endDeferredRigid() void LLDrawPoolAvatar::beginSkinned() { - if (sShaderLevel > 0) + if (!LLGLSLShader::sNoFixedFunction) + { + sVertexProgram = NULL; + return; + } + + if (sShaderLevel > 0) // for hardware blending { if (LLPipeline::sUnderWaterRender) { sVertexProgram = &gAvatarWaterProgram; - sShaderLevel = llmin((U32) 1, sShaderLevel); + sShaderLevel = 1; } else { @@ -723,17 +791,14 @@ void LLDrawPoolAvatar::beginSkinned() } else { - if(gPipeline.canUseVertexShaders()) - { - // software skinning, use a basic shader for windlight. - // TODO: find a better fallback method for software skinning. - sVertexProgram->bind(); - } + // software skinning, use a basic shader for windlight. + // TODO: find a better fallback method for software skinning. + sVertexProgram->bind(); } if (LLGLSLShader::sNoFixedFunction) { - sVertexProgram->setMinimumAlpha(0.2f); + sVertexProgram->setMinimumAlpha(LLDrawPoolAvatar::sMinimumAlpha); } } @@ -745,17 +810,12 @@ void LLDrawPoolAvatar::endSkinned() sRenderingSkinned = FALSE; sVertexProgram->disableTexture(LLViewerShaderMgr::BUMP_MAP); gGL.getTexUnit(0)->activate(); - sVertexProgram->unbind(); sShaderLevel = mVertexShaderLevel; } - else + + if(sVertexProgram) { - if(gPipeline.canUseVertexShaders()) - { - // software skinning, use a basic shader for windlight. - // TODO: find a better fallback method for software skinning. - sVertexProgram->unbind(); - } + sVertexProgram->unbind(); } gGL.getTexUnit(0)->activate(); @@ -763,44 +823,29 @@ void LLDrawPoolAvatar::endSkinned() void LLDrawPoolAvatar::beginRiggedSimple() { - if (sShaderLevel > 0) - { - if (LLPipeline::sUnderWaterRender) - { - sVertexProgram = &gSkinnedObjectSimpleWaterProgram; - } - else - { - sVertexProgram = &gSkinnedObjectSimpleProgram; - } - } - else + sDiffuseChannel = 0; + if (!LLGLSLShader::sNoFixedFunction) { - if (LLPipeline::sUnderWaterRender) - { - sVertexProgram = &gObjectSimpleNonIndexedWaterProgram; - } - else - { - sVertexProgram = &gObjectSimpleNonIndexedProgram; - } + sVertexProgram = NULL; + return; } - if (sShaderLevel > 0 || gPipeline.canUseVertexShaders()) - { - sDiffuseChannel = 0; - sVertexProgram->bind(); - } + sVertexProgram = &gObjectSimpleProgram[1<0)<mProgramObject > 0); + + sDiffuseChannel = 0; + sVertexProgram->bind(); } void LLDrawPoolAvatar::endRiggedSimple() { LLVertexBuffer::unbind(); - if (sShaderLevel > 0 || gPipeline.canUseVertexShaders()) - { - sVertexProgram->unbind(); - sVertexProgram = NULL; - } + + if(!sVertexProgram) + return; + + sVertexProgram->unbind(); + sVertexProgram = NULL; } void LLDrawPoolAvatar::beginRiggedAlpha() @@ -826,36 +871,21 @@ void LLDrawPoolAvatar::endRiggedFullbrightAlpha() void LLDrawPoolAvatar::beginRiggedGlow() { - if (sShaderLevel > 0) - { - if (LLPipeline::sUnderWaterRender) - { - sVertexProgram = &gSkinnedObjectEmissiveWaterProgram; - } - else - { - sVertexProgram = &gSkinnedObjectEmissiveProgram; - } - } - else + sDiffuseChannel = 0; + if (!LLGLSLShader::sNoFixedFunction) { - if (LLPipeline::sUnderWaterRender) - { - sVertexProgram = &gObjectEmissiveNonIndexedWaterProgram; - } - else - { - sVertexProgram = &gObjectEmissiveNonIndexedProgram; - } + sVertexProgram = NULL; + return; } - if (sShaderLevel > 0 || gPipeline.canUseVertexShaders()) - { - sDiffuseChannel = 0; - sVertexProgram->bind(); - } -} + sVertexProgram = &gObjectEmissiveProgram[1<0)<mProgramObject > 0); + sVertexProgram->bind(); + sVertexProgram->uniform1f(LLShaderMgr::TEXTURE_GAMMA, LLPipeline::sRenderDeferred ? 2.2f : 1.1f); + //F32 gamma = gSavedSettings.getF32("RenderDeferredDisplayGamma"); + //sVertexProgram->uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f/2.2f)); +} void LLDrawPoolAvatar::endRiggedGlow() { endRiggedFullbright(); @@ -863,131 +893,114 @@ void LLDrawPoolAvatar::endRiggedGlow() void LLDrawPoolAvatar::beginRiggedFullbright() { - if (sShaderLevel > 0) + sDiffuseChannel = 0; + if (!LLGLSLShader::sNoFixedFunction) { - if (LLPipeline::sUnderWaterRender) - { - sVertexProgram = &gSkinnedObjectFullbrightWaterProgram; - } - else - { - sVertexProgram = &gSkinnedObjectFullbrightProgram; - } + sVertexProgram = NULL; + return; + } + if (sShaderLevel > 0 && !LLPipeline::sUnderWaterRender && LLPipeline::sRenderDeferred) + { + sVertexProgram = &gDeferredSkinnedFullbrightProgram; } else { - if (LLPipeline::sUnderWaterRender) - { - sVertexProgram = &gObjectFullbrightNonIndexedWaterProgram; - } - else - { - sVertexProgram = &gObjectFullbrightNonIndexedProgram; - } + sVertexProgram = &gObjectFullbrightProgram[1<0)<mProgramObject > 0); - if (sShaderLevel > 0 || gPipeline.canUseVertexShaders()) + sVertexProgram->bind(); + if (LLPipeline::sRenderingHUDs || !LLPipeline::sRenderDeferred) { - sDiffuseChannel = 0; - sVertexProgram->bind(); + sVertexProgram->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.0f); + } + else + { + sVertexProgram->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f); + //F32 gamma = gSavedSettings.getF32("RenderDeferredDisplayGamma"); + //sVertexProgram->uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f/2.2f)); } } void LLDrawPoolAvatar::endRiggedFullbright() { LLVertexBuffer::unbind(); - if (sShaderLevel > 0 || gPipeline.canUseVertexShaders()) - { - sVertexProgram->unbind(); - sVertexProgram = NULL; - } + + if(!sVertexProgram) + return; + + sVertexProgram->unbind(); + sVertexProgram = NULL; } void LLDrawPoolAvatar::beginRiggedShinySimple() { - if (sShaderLevel > 0) - { - if (LLPipeline::sUnderWaterRender) - { - sVertexProgram = &gSkinnedObjectShinySimpleWaterProgram; - } - else - { - sVertexProgram = &gSkinnedObjectShinySimpleProgram; - } - } - else + if (!LLGLSLShader::sNoFixedFunction) { - if (LLPipeline::sUnderWaterRender) - { - sVertexProgram = &gObjectShinyNonIndexedWaterProgram; - } - else - { - sVertexProgram = &gObjectShinyNonIndexedProgram; - } + sVertexProgram = NULL; + return; } - if (sShaderLevel > 0 || gPipeline.canUseVertexShaders()) - { - sVertexProgram->bind(); - LLDrawPoolBump::bindCubeMap(sVertexProgram, 2, sDiffuseChannel, cube_channel, false); - } + sVertexProgram = &gObjectSimpleProgram[1<0)<mProgramObject > 0); + + sVertexProgram->bind(); + LLDrawPoolBump::bindCubeMap(sVertexProgram, 2, sDiffuseChannel, cube_channel); } void LLDrawPoolAvatar::endRiggedShinySimple() { LLVertexBuffer::unbind(); - if (sShaderLevel > 0 || gPipeline.canUseVertexShaders()) - { - LLDrawPoolBump::unbindCubeMap(sVertexProgram, 2, sDiffuseChannel, cube_channel, false); - sVertexProgram->unbind(); - sVertexProgram = NULL; - } + + if(!sVertexProgram) + return; + + LLDrawPoolBump::unbindCubeMap(sVertexProgram, 2, sDiffuseChannel, cube_channel); + sVertexProgram->unbind(); + sVertexProgram = NULL; } void LLDrawPoolAvatar::beginRiggedFullbrightShiny() { - if (sShaderLevel > 0) + if (!LLGLSLShader::sNoFixedFunction) { - if (LLPipeline::sUnderWaterRender) - { - sVertexProgram = &gSkinnedObjectFullbrightShinyWaterProgram; - } - else - { - sVertexProgram = &gSkinnedObjectFullbrightShinyProgram; - } + sVertexProgram = NULL; + return; + } + if (sShaderLevel > 0 && !LLPipeline::sUnderWaterRender && LLPipeline::sRenderDeferred) + { + sVertexProgram = &gDeferredSkinnedFullbrightShinyProgram; } else { - if (LLPipeline::sUnderWaterRender) - { - sVertexProgram = &gObjectFullbrightShinyNonIndexedWaterProgram; - } - else - { - sVertexProgram = &gObjectFullbrightShinyNonIndexedProgram; - } + sVertexProgram = &gObjectFullbrightProgram[1<0)<mProgramObject > 0); - - if (sShaderLevel > 0 || gPipeline.canUseVertexShaders()) + sVertexProgram->bind(); + LLDrawPoolBump::bindCubeMap(sVertexProgram, 2, sDiffuseChannel, cube_channel); + if (LLPipeline::sRenderingHUDs || !LLPipeline::sRenderDeferred) { - sVertexProgram->bind(); - LLDrawPoolBump::bindCubeMap(sVertexProgram, 2, sDiffuseChannel, cube_channel, false); + sVertexProgram->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.0f); + } + else + { + sVertexProgram->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f); + //F32 gamma = gSavedSettings.getF32("RenderDeferredDisplayGamma"); + //sVertexProgram->uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f/2.2f)); } } void LLDrawPoolAvatar::endRiggedFullbrightShiny() { LLVertexBuffer::unbind(); - if (sShaderLevel > 0 || gPipeline.canUseVertexShaders()) - { - LLDrawPoolBump::unbindCubeMap(sVertexProgram, 2, sDiffuseChannel, cube_channel, false); - sVertexProgram->unbind(); - sVertexProgram = NULL; - } + + if(!sVertexProgram) + return; + + LLDrawPoolBump::unbindCubeMap(sVertexProgram, 2, sDiffuseChannel, cube_channel); + sVertexProgram->unbind(); + sVertexProgram = NULL; } @@ -1024,6 +1037,43 @@ void LLDrawPoolAvatar::endDeferredRiggedBump() sVertexProgram = NULL; } +void LLDrawPoolAvatar::beginDeferredRiggedMaterial(S32 pass) +{ + if (pass == 1 || + pass == 5 || + pass == 9 || + pass == 13) + { //skip alpha passes + return; + } + sVertexProgram = &gDeferredMaterialProgram[pass+LLMaterial::SHADER_COUNT]; + if (LLPipeline::sUnderWaterRender) + { + sVertexProgram = &(gDeferredMaterialWaterProgram[pass+LLMaterial::SHADER_COUNT]); + } + sVertexProgram->bind(); + normal_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::BUMP_MAP); + specular_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::SPECULAR_MAP); + sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); +} +void LLDrawPoolAvatar::endDeferredRiggedMaterial(S32 pass) +{ + if (pass == 1 || + pass == 5 || + pass == 9 || + pass == 13) + { + return; + } + LLVertexBuffer::unbind(); + sVertexProgram->disableTexture(LLViewerShaderMgr::BUMP_MAP); + sVertexProgram->disableTexture(LLViewerShaderMgr::SPECULAR_MAP); + sVertexProgram->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP); + sVertexProgram->unbind(); + normal_channel = -1; + sDiffuseChannel = 0; + sVertexProgram = NULL; +} void LLDrawPoolAvatar::beginDeferredSkinned() { sShaderLevel = mVertexShaderLevel; @@ -1031,7 +1081,7 @@ void LLDrawPoolAvatar::beginDeferredSkinned() sRenderingSkinned = TRUE; sVertexProgram->bind(); - sVertexProgram->setMinimumAlpha(0.2f); + sVertexProgram->setMinimumAlpha(LLDrawPoolAvatar::sMinimumAlpha); sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); gGL.getTexUnit(0)->activate(); @@ -1050,11 +1100,11 @@ void LLDrawPoolAvatar::endDeferredSkinned() gGL.getTexUnit(0)->activate(); } -static LLFastTimer::DeclareTimer FTM_RENDER_AVATARS("renderAvatars"); +static LLTrace::BlockTimerStatHandle FTM_RENDER_AVATARS("renderAvatars"); void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) { - LLFastTimer t(FTM_RENDER_AVATARS); + LL_RECORD_BLOCK_TIME(FTM_RENDER_AVATARS); if (pass == -1) { @@ -1184,6 +1234,21 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) else { renderRiggedSimple(avatarp); + if (LLPipeline::sRenderDeferred) + { //render "simple" materials + renderRigged(avatarp, RIGGED_MATERIAL); + renderRigged(avatarp, RIGGED_MATERIAL_ALPHA_MASK); + renderRigged(avatarp, RIGGED_MATERIAL_ALPHA_EMISSIVE); + renderRigged(avatarp, RIGGED_NORMMAP); + renderRigged(avatarp, RIGGED_NORMMAP_MASK); + renderRigged(avatarp, RIGGED_NORMMAP_EMISSIVE); + renderRigged(avatarp, RIGGED_SPECMAP); + renderRigged(avatarp, RIGGED_SPECMAP_MASK); + renderRigged(avatarp, RIGGED_SPECMAP_EMISSIVE); + renderRigged(avatarp, RIGGED_NORMSPEC); + renderRigged(avatarp, RIGGED_NORMSPEC_MASK); + renderRigged(avatarp, RIGGED_NORMSPEC_EMISSIVE); + } } return; } @@ -1202,6 +1267,18 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) return; } + if (is_deferred_render && pass >= 5 && pass <= 21) + { + S32 p = pass-5; + if (p != 1 && + p != 5 && + p != 9 && + p != 13) + { + renderDeferredRiggedMaterial(avatarp, p); + } + return; + } if (pass == 5) { renderRiggedShinySimple(avatarp); @@ -1214,11 +1291,26 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) return; } - if (pass >= 7 && pass < 9) + if (pass >= 7 && pass < 13) { if (pass == 7) { renderRiggedAlpha(avatarp); + if (LLPipeline::sRenderDeferred && !is_post_deferred_render) + { //render transparent materials under water + LLGLEnable blend; + gGL.setColorMask(true, true); + gGL.blendFunc(LLRender::BF_SOURCE_ALPHA, + LLRender::BF_ONE_MINUS_SOURCE_ALPHA, + LLRender::BF_ZERO, + LLRender::BF_ONE_MINUS_SOURCE_ALPHA); + renderRigged(avatarp, RIGGED_MATERIAL_ALPHA); + renderRigged(avatarp, RIGGED_SPECMAP_BLEND); + renderRigged(avatarp, RIGGED_NORMMAP_BLEND); + renderRigged(avatarp, RIGGED_NORMSPEC_BLEND); + gGL.setSceneBlendType(LLRender::BT_ALPHA); + gGL.setColorMask(true, false); + } return; } @@ -1227,20 +1319,41 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) renderRiggedFullbrightAlpha(avatarp); return; } + if (LLPipeline::sRenderDeferred && is_post_deferred_render) + { + S32 p = 0; + switch (pass) + { + case 9: p = 1; break; + case 10: p = 5; break; + case 11: p = 9; break; + case 12: p = 13; break; + } + { + LLGLEnable blend; + renderDeferredRiggedMaterial(avatarp, p); + } + return; + } + else if (pass == 9) + { + renderRiggedGlow(avatarp); + return; + } } - if (pass == 9) + if (pass == 13) { renderRiggedGlow(avatarp); return; } - if ((sShaderLevel >= SHADER_LEVEL_CLOTH)) + if (sShaderLevel >= SHADER_LEVEL_CLOTH) { LLMatrix4 rot_mat; LLViewerCamera::getInstance()->getMatrixToLocal(rot_mat); - LLMatrix4 cfr(OGL_TO_CFR_ROTATION); + LLMatrix4 cfr(OGL_TO_CFR_ROTATION.getF32ptr()); rot_mat *= cfr; LLVector4 wind; @@ -1252,7 +1365,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) sVertexProgram->uniform4fv(LLViewerShaderMgr::AVATAR_WIND, 1, wind.mV); F32 phase = -1.f * (avatarp->mRipplePhase); - F32 freq = 7.f + (noise1(avatarp->mRipplePhase) * 2.f); + F32 freq = 7.f + (LLPerlinNoise::noise(avatarp->mRipplePhase) * 2.f); LLVector4 sin_params(freq, freq, freq, phase); sVertexProgram->uniform4fv(LLViewerShaderMgr::AVATAR_SINWAVE, 1, sin_params.mV); @@ -1267,27 +1380,10 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) } } -void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace* face, const LLMeshSkinInfo* skin, LLVolume* volume, const LLVolumeFace& vol_face) +void LLDrawPoolAvatar::getRiggedGeometry(LLFace* face, LLPointer& buffer, U32 data_mask, const LLMeshSkinInfo* skin, LLVolume* volume, const LLVolumeFace& vol_face) { - LLVector4a* weight = vol_face.mWeights; - if (!weight) - { - return; - } - - LLPointer buffer = face->getVertexBuffer(); - LLDrawable* drawable = face->getDrawable(); - - U32 data_mask = face->getRiggedVertexBufferDataMask(); - - if (buffer.isNull() || - buffer->getTypeMask() != data_mask || - buffer->getNumVerts() != vol_face.mNumVertices || - buffer->getNumIndices() != vol_face.mNumIndices || - (drawable && drawable->isState(LLDrawable::REBUILD_ALL))) - { - face->setGeomIndex(0); - face->setIndicesIndex(0); + face->setGeomIndex(0); + face->setIndicesIndex(0); //rigged faces do not batch textures face->setTextureIndex(255); @@ -1314,16 +1410,11 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace* U16 offset = 0; - LLMatrix4 mat_vert = skin->mBindShapeMatrix; - glh::matrix4f m((F32*) mat_vert.mMatrix); - m = m.inverse().transpose(); - - F32 mat3[] = - { m.m[0], m.m[1], m.m[2], - m.m[4], m.m[5], m.m[6], - m.m[8], m.m[9], m.m[10] }; - - LLMatrix3 mat_normal(mat3); + LLMatrix4a mat_vert; + mat_vert.loadu(skin->mBindShapeMatrix); + LLMatrix4a mat_inv_trans = mat_vert; + mat_inv_trans.invert(); + mat_inv_trans.transpose(); //let getGeometryVolume know if alpha should override shiny U32 type = gPipeline.getPoolTypeFromTE(face->getTextureEntry(), face->getTexture()); @@ -1334,108 +1425,92 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace* } else { - face->setPoolType(LLDrawPool::POOL_AVATAR); - } - - face->getGeometryVolume(*volume, face->getTEOffset(), mat_vert, mat_normal, offset, true); - - buffer->flush(); + face->setPoolType(LLDrawPool::POOL_AVATAR); } - if (sShaderLevel <= 0 && face->mLastSkinTime < avatar->getLastSkinTime()) - { //perform software vertex skinning for this face - LLStrider position; - LLStrider normal; - - bool has_normal = buffer->hasDataType(LLVertexBuffer::TYPE_NORMAL); - buffer->getVertexStrider(position); - - if (has_normal) - { - buffer->getNormalStrider(normal); - } - - LLVector4a* pos = (LLVector4a*) position.get(); - - LLVector4a* norm = has_normal ? (LLVector4a*) normal.get() : NULL; - - //build matrix palette - static const size_t kMaxJoints = 64; - LLMatrix4a mp[kMaxJoints]; - LLMatrix4* mat = (LLMatrix4*) mp; - - U32 maxJoints = llmin(skin->mJointNames.size(), kMaxJoints); - for (U32 j = 0; j < maxJoints; ++j) - { - LLJoint* joint = avatar->getJoint(skin->mJointNames[j]); - if (joint) - { - mat[j] = skin->mInvBindMatrix[j]; - mat[j] *= joint->getWorldMatrix(); - } - } - - LLMatrix4a bind_shape_matrix; - bind_shape_matrix.loadu(skin->mBindShapeMatrix); + //LL_INFOS() << "Rebuilt face " << face->getTEOffset() << " of " << face->getDrawable() << " at " << gFrameTimeSeconds << LL_ENDL; - for (U32 j = 0; j < (U32)buffer->getNumVerts(); ++j) - { - LLMatrix4a final_mat; - final_mat.clear(); + // Let getGeometryVolume know if a texture matrix is in play + if (face->mTextureMatrix) + { + face->setState(LLFace::TEXTURE_ANIM); + } + else + { + face->clearState(LLFace::TEXTURE_ANIM); + } + face->getGeometryVolume(*volume, face->getTEOffset(), mat_vert, mat_inv_trans, offset, true); - S32 idx[4]; + buffer->flush(); +} - LLVector4 wght; +void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace* face, const LLMeshSkinInfo* skin, LLVolume* volume, const LLVolumeFace& vol_face) +{ + LLVector4a* weights = vol_face.mWeights; + if (!weights) + { + return; + } + // FIXME ugly const cast + LLSkinningUtil::scrubInvalidJoints(avatar, const_cast(skin)); - F32 scale = 0.f; - for (U32 k = 0; k < 4; k++) - { - F32 w = weight[j][k]; + LLPointer buffer = face->getVertexBuffer(); + LLDrawable* drawable = face->getDrawable(); - idx[k] = llclamp((S32) floorf(w), 0, 63); - wght[k] = w - floorf(w); - scale += wght[k]; - } + if (drawable->getVOVolume() && drawable->getVOVolume()->isNoLOD()) + { + return; + } - wght *= 1.f/scale; + U32 data_mask = face->getRiggedVertexBufferDataMask(); - for (U32 k = 0; k < 4; k++) + if (!vol_face.mWeightsScrubbed) + { + LLSkinningUtil::scrubSkinWeights(weights, vol_face.mNumVertices, skin); + vol_face.mWeightsScrubbed = TRUE; + } + + if (buffer.isNull() || + buffer->getTypeMask() != data_mask || + buffer->getNumVerts() != vol_face.mNumVertices || + buffer->getNumIndices() != vol_face.mNumIndices || + (drawable && drawable->isState(LLDrawable::REBUILD_ALL))) + { + if (drawable && drawable->isState(LLDrawable::REBUILD_ALL)) + { //rebuild EVERY face in the drawable, not just this one, to avoid missing drawable wide rebuild issues + for (S32 i = 0; i < drawable->getNumFaces(); ++i) { - F32 w = wght[k]; - - LLMatrix4a src; - src.setMul(mp[idx[k]], w); - - final_mat.add(src); + LLFace* facep = drawable->getFace(i); + U32 face_data_mask = facep->getRiggedVertexBufferDataMask(); + if (face_data_mask) + { + LLPointer cur_buffer = facep->getVertexBuffer(); + const LLVolumeFace& cur_vol_face = volume->getVolumeFace(i); + getRiggedGeometry(facep, cur_buffer, face_data_mask, skin, volume, cur_vol_face); + } } + drawable->clearState(LLDrawable::REBUILD_ALL); - - LLVector4a& v = vol_face.mPositions[j]; - LLVector4a t; - LLVector4a dst; - bind_shape_matrix.affineTransform(v, t); - final_mat.affineTransform(t, dst); - pos[j] = dst; - - if (norm) - { - LLVector4a& n = vol_face.mNormals[j]; - bind_shape_matrix.rotate(n, t); - final_mat.rotate(t, dst); - norm[j] = dst; - } + buffer = face->getVertexBuffer(); + } + else + { //just rebuild this face + getRiggedGeometry(face, buffer, data_mask, skin, volume, vol_face); } } - if (drawable && (face->getTEOffset() == drawable->getNumFaces()-1)) + if (sShaderLevel <= 0 && face->mLastSkinTime < avatar->getLastSkinTime()) { - drawable->clearState(LLDrawable::REBUILD_ALL); + avatar->updateSoftwareSkinnedVertices(skin, weights, vol_face, buffer); } } +extern int sMaxCacheHit; +extern int sCurCacheHit; + void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow) { - if ((avatar->isSelf() && !gAgent.needsRenderAvatar()) || !gMeshRepo.meshRezEnabled()) + if (!avatar->shouldRenderRigged() || !gMeshRepo.meshRezEnabled()) { return; } @@ -1466,13 +1541,7 @@ void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow) continue; } - LLUUID mesh_id = volume->getParams().getSculptID(); - if (mesh_id.isNull()) - { - continue; - } - - const LLMeshSkinInfo* skin = gMeshRepo.getSkinInfo(mesh_id, vobj); + const LLMeshSkinInfo* skin = vobj->getSkinInfo(); if (!skin) { continue; @@ -1492,29 +1561,64 @@ void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow) if (buff) { if (sShaderLevel > 0) - { //upload matrix palette to shader - static const size_t kMaxJoints = 64; - LLMatrix4 mat[kMaxJoints]; - - U32 maxJoints = llmin(skin->mJointNames.size(), kMaxJoints); - for (U32 i = 0; i < maxJoints; ++i) + { + static LLCachedControl sh_use_rigging_cache("SHUseRiggedMatrixCache", true); + auto& mesh_cache = avatar->getRiggedMatrixCache();; + auto rigged_matrix_data_iter = mesh_cache.cend(); + if (sh_use_rigging_cache) + { + auto& mesh_id = skin->mMeshID; + rigged_matrix_data_iter = find_if(mesh_cache.begin(), mesh_cache.end(), [&mesh_id](decltype(mesh_cache[0]) & entry) { return entry.first == mesh_id; }); + + } + if (rigged_matrix_data_iter != avatar->getRiggedMatrixCache().cend()) + { + LLDrawPoolAvatar::sVertexProgram->uniformMatrix3x4fv(LLViewerShaderMgr::AVATAR_MATRIX, + rigged_matrix_data_iter->second.first, + FALSE, + (GLfloat*)rigged_matrix_data_iter->second.second.data()); + LLDrawPoolAvatar::sVertexProgram->uniform1f(LLShaderMgr::AVATAR_MAX_WEIGHT, F32(rigged_matrix_data_iter->second.first - 1)); + } + else { - LLJoint* joint = avatar->getJoint(skin->mJointNames[i]); - if (joint) + // upload matrix palette to shader + LLMatrix4a mat[LL_MAX_JOINTS_PER_MESH_OBJECT]; + U32 count = LLSkinningUtil::getMeshJointCount(skin); + LLSkinningUtil::initSkinningMatrixPalette(mat, count, skin, avatar); + + std::array mp; + + for (U32 i = 0; i < count; ++i) { - mat[i] = skin->mInvBindMatrix[i]; - mat[i] *= joint->getWorldMatrix(); + F32* m = (F32*)mat[i].getF32ptr(); + + U32 idx = i * 12; + + mp[idx + 0] = m[0]; + mp[idx + 1] = m[1]; + mp[idx + 2] = m[2]; + mp[idx + 3] = m[12]; + + mp[idx + 4] = m[4]; + mp[idx + 5] = m[5]; + mp[idx + 6] = m[6]; + mp[idx + 7] = m[13]; + + mp[idx + 8] = m[8]; + mp[idx + 9] = m[9]; + mp[idx + 10] = m[10]; + mp[idx + 11] = m[14]; } + if (sh_use_rigging_cache) + mesh_cache.emplace_back(std::make_pair( skin->mMeshID, std::make_pair(count, mp) ) ); + LLDrawPoolAvatar::sVertexProgram->uniformMatrix3x4fv(LLViewerShaderMgr::AVATAR_MATRIX, + count, + FALSE, + (GLfloat*)mp.data()); + LLDrawPoolAvatar::sVertexProgram->uniform1f(LLShaderMgr::AVATAR_MAX_WEIGHT, F32(count - 1)); } stop_glerror(); - - LLDrawPoolAvatar::sVertexProgram->uniformMatrix4fv("matrixPalette", - maxJoints, - FALSE, - (GLfloat*) mat[0].mMatrix); - - stop_glerror(); } else { @@ -1531,16 +1635,85 @@ void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow) gGL.diffuseColor4f(0,0,0,face->getTextureEntry()->getGlow()); }*/ - gGL.getTexUnit(sDiffuseChannel)->bind(face->getTexture()); - if (normal_channel > -1) + const LLTextureEntry* te = face->getTextureEntry(); + LLMaterial* mat = te->getMaterialParams().get(); + + if (mat && is_mats_render) { - LLDrawPoolBump::bindBumpMap(face, normal_channel); + gGL.getTexUnit(sDiffuseChannel)->bind(face->getTexture(LLRender::DIFFUSE_MAP)); + gGL.getTexUnit(normal_channel)->bind(face->getTexture(LLRender::NORMAL_MAP)); + gGL.getTexUnit(specular_channel)->bind(face->getTexture(LLRender::SPECULAR_MAP)); + + LLColor4 col = mat->getSpecularLightColor(); + F32 spec = llmax(0.0000f, mat->getSpecularLightExponent() / 255.f); + + F32 env = mat->getEnvironmentIntensity()/255.f; + + if (mat->getSpecularID().isNull()) + { + env = te->getShiny()*0.25f; + col.set(env,env,env,0); + spec = env; + } + + BOOL fullbright = te->getFullbright(); + + sVertexProgram->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, fullbright ? 1.f : 0.f); + sVertexProgram->uniform4f(LLShaderMgr::SPECULAR_COLOR, col.mV[0], col.mV[1], col.mV[2], spec); + sVertexProgram->uniform1f(LLShaderMgr::ENVIRONMENT_INTENSITY, env); + + if (mat->getDiffuseAlphaMode() == LLMaterial::DIFFUSE_ALPHA_MODE_MASK) + { + sVertexProgram->setMinimumAlpha(mat->getAlphaMaskCutoff()/255.f); + } + else if (mat->getDiffuseAlphaMode() == LLMaterial::DIFFUSE_ALPHA_MODE_NONE || mat->getDiffuseAlphaMode() == LLMaterial::DIFFUSE_ALPHA_MODE_EMISSIVE) + { + sVertexProgram->setMinimumAlpha(0.f); + } + else + { + sVertexProgram->setMinimumAlpha(0.004f); + } + + for (U32 i = 0; i < LLRender::NUM_TEXTURE_CHANNELS; ++i) + { + LLViewerTexture* tex = face->getTexture(i); + if (tex) + { + tex->addTextureStats(avatar->getPixelArea()); + } + } + } + else + { + gGL.getTexUnit(sDiffuseChannel)->bind(face->getTexture()); + + if(sVertexProgram) + { + if (mat && mat->getDiffuseAlphaMode() == LLMaterial::DIFFUSE_ALPHA_MODE_MASK) + { + sVertexProgram->setMinimumAlpha(mat->getAlphaMaskCutoff()/255.f); + } + else if (mat && (mat->getDiffuseAlphaMode() == LLMaterial::DIFFUSE_ALPHA_MODE_NONE || mat->getDiffuseAlphaMode() == LLMaterial::DIFFUSE_ALPHA_MODE_EMISSIVE)) + { + sVertexProgram->setMinimumAlpha(0.f); + } + else + { + sVertexProgram->setMinimumAlpha(0.004f); + } + } + + if (normal_channel > -1) + { + LLDrawPoolBump::bindBumpMap(face, normal_channel); + } } - if (face->mTextureMatrix) + if (face->mTextureMatrix && vobj->mTexAnimMode) { - gGL.matrixMode(LLRender::MM_TEXTURE); - gGL.loadMatrix((F32*) face->mTextureMatrix->mMatrix); + gGL.matrixMode(LLRender::MM_TEXTURE0 + sDiffuseChannel); + gGL.loadMatrix(*face->mTextureMatrix); buff->setBuffer(data_mask); buff->drawRange(LLRender::TRIANGLES, start, end, count, offset); gGL.loadIdentity(); @@ -1551,6 +1724,8 @@ void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow) buff->setBuffer(data_mask); buff->drawRange(LLRender::TRIANGLES, start, end, count, offset); } + + gPipeline.addTrianglesDrawn(count, LLRender::TRIANGLES); } } } @@ -1565,11 +1740,18 @@ void LLDrawPoolAvatar::renderDeferredRiggedBump(LLVOAvatar* avatar) renderRigged(avatar, RIGGED_DEFERRED_BUMP); } -static LLFastTimer::DeclareTimer FTM_RIGGED_VBO("Rigged VBO"); +void LLDrawPoolAvatar::renderDeferredRiggedMaterial(LLVOAvatar* avatar, S32 pass) +{ + is_mats_render = true; + renderRigged(avatar, pass); + is_mats_render = false; +} + +static LLTrace::BlockTimerStatHandle FTM_RIGGED_VBO("Rigged VBO"); void LLDrawPoolAvatar::updateRiggedVertexBuffers(LLVOAvatar* avatar) { - LLFastTimer t(FTM_RIGGED_VBO); + LL_RECORD_BLOCK_TIME(FTM_RIGGED_VBO); //update rigged vertex buffers for (U32 type = 0; type < NUM_RIGGED_PASSES; ++type) @@ -1585,7 +1767,7 @@ void LLDrawPoolAvatar::updateRiggedVertexBuffers(LLVOAvatar* avatar) LLVOVolume* vobj = drawable->getVOVolume(); - if (!vobj) + if (!vobj || vobj->isNoLOD()) { continue; } @@ -1598,13 +1780,7 @@ void LLDrawPoolAvatar::updateRiggedVertexBuffers(LLVOAvatar* avatar) continue; } - LLUUID mesh_id = volume->getParams().getSculptID(); - if (mesh_id.isNull()) - { - continue; - } - - const LLMeshSkinInfo* skin = gMeshRepo.getSkinInfo(mesh_id, vobj); + const LLMeshSkinInfo* skin = vobj->getSkinInfo(); if (!skin) { continue; @@ -1643,7 +1819,7 @@ void LLDrawPoolAvatar::renderRiggedAlpha(LLVOAvatar* avatar) { if (!mRiggedFace[RIGGED_ALPHA].empty()) { - LLGLEnable blend(GL_BLEND); + LLGLEnable blend; gGL.setColorMask(true, true); gGL.blendFunc(LLRender::BF_SOURCE_ALPHA, @@ -1661,7 +1837,7 @@ void LLDrawPoolAvatar::renderRiggedFullbrightAlpha(LLVOAvatar* avatar) { if (!mRiggedFace[RIGGED_FULLBRIGHT_ALPHA].empty()) { - LLGLEnable blend(GL_BLEND); + LLGLEnable blend; gGL.setColorMask(true, true); gGL.blendFunc(LLRender::BF_SOURCE_ALPHA, @@ -1679,12 +1855,12 @@ void LLDrawPoolAvatar::renderRiggedGlow(LLVOAvatar* avatar) { if (!mRiggedFace[RIGGED_GLOW].empty()) { - LLGLEnable blend(GL_BLEND); - LLGLDisable test(GL_ALPHA_TEST); + LLGLEnable blend; + LLGLDisable test; gGL.flush(); - LLGLEnable polyOffset(GL_POLYGON_OFFSET_FILL); - glPolygonOffset(-1.0f, -1.0f); + LLGLEnable polyOffset; + gGL.setPolygonOffset(-1.0f, -1.0f); gGL.setSceneBlendType(LLRender::BT_ADD); LLGLDepthTest depth(GL_TRUE, GL_FALSE); @@ -1729,17 +1905,19 @@ void LLDrawPoolAvatar::addRiggedFace(LLFace* facep, U32 type) { if (type >= NUM_RIGGED_PASSES) { - llerrs << "Invalid rigged face type." << llendl; + LL_ERRS() << "Invalid rigged face type." << LL_ENDL; } if (facep->getRiggedIndex(type) != -1) { - llerrs << "Tried to add a rigged face that's referenced elsewhere." << llendl; + LL_ERRS() << "Tried to add a rigged face that's referenced elsewhere." << LL_ENDL; } facep->setRiggedIndex(type, mRiggedFace[type].size()); facep->setPool(this); mRiggedFace[type].push_back(facep); + + facep->mShinyInAlpha = type == RIGGED_DEFERRED_SIMPLE || type == RIGGED_DEFERRED_BUMP || type == RIGGED_FULLBRIGHT_SHINY || type == RIGGED_SHINY; } void LLDrawPoolAvatar::removeRiggedFace(LLFace* facep) @@ -1763,7 +1941,7 @@ void LLDrawPoolAvatar::removeRiggedFace(LLFace* facep) } else { - llerrs << "Face reference data corrupt for rigged type " << i << llendl; + LL_ERRS() << "Face reference data corrupt for rigged type " << i << LL_ENDL; } } } diff --git a/indra/newview/lldrawpoolavatar.h b/indra/newview/lldrawpoolavatar.h index 880378f851..acc11a95ee 100644 --- a/indra/newview/lldrawpoolavatar.h +++ b/indra/newview/lldrawpoolavatar.h @@ -42,6 +42,7 @@ class LLMeshSkinInfo; class LLVolume; class LLVolumeFace; +constexpr U32 JOINT_COUNT = 52; class LLDrawPoolAvatar : public LLFacePool { @@ -66,8 +67,10 @@ class LLDrawPoolAvatar : public LLFacePool virtual S32 getVertexShaderLevel() const; LLDrawPoolAvatar(); + ~LLDrawPoolAvatar(); + /*virtual*/ BOOL isDead(); - static LLMatrix4& getModelView(); + static const LLMatrix4a& getModelView(); /*virtual*/ LLDrawPool *instancePool(); @@ -119,6 +122,8 @@ class LLDrawPoolAvatar : public LLFacePool void beginRiggedFullbrightAlpha(); void beginRiggedGlow(); void beginDeferredRiggedAlpha(); + void beginDeferredRiggedMaterial(S32 pass); + void beginDeferredRiggedMaterialAlpha(S32 pass); void endRiggedSimple(); void endRiggedFullbright(); @@ -128,6 +133,8 @@ class LLDrawPoolAvatar : public LLFacePool void endRiggedFullbrightAlpha(); void endRiggedGlow(); void endDeferredRiggedAlpha(); + void endDeferredRiggedMaterial(S32 pass); + void endDeferredRiggedMaterialAlpha(S32 pass); void beginDeferredRiggedSimple(); void beginDeferredRiggedBump(); @@ -135,6 +142,7 @@ class LLDrawPoolAvatar : public LLFacePool void endDeferredRiggedSimple(); void endDeferredRiggedBump(); + void getRiggedGeometry(LLFace* face, LLPointer& buffer, U32 data_mask, const LLMeshSkinInfo* skin, LLVolume* volume, const LLVolumeFace& vol_face); void updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace* facep, const LLMeshSkinInfo* skin, @@ -152,10 +160,27 @@ class LLDrawPoolAvatar : public LLFacePool void renderRiggedGlow(LLVOAvatar* avatar); void renderDeferredRiggedSimple(LLVOAvatar* avatar); void renderDeferredRiggedBump(LLVOAvatar* avatar); - + void renderDeferredRiggedMaterial(LLVOAvatar* avatar, S32 pass); + typedef enum { - RIGGED_SIMPLE = 0, + RIGGED_MATERIAL=0, + RIGGED_MATERIAL_ALPHA, + RIGGED_MATERIAL_ALPHA_MASK, + RIGGED_MATERIAL_ALPHA_EMISSIVE, + RIGGED_SPECMAP, + RIGGED_SPECMAP_BLEND, + RIGGED_SPECMAP_MASK, + RIGGED_SPECMAP_EMISSIVE, + RIGGED_NORMMAP, + RIGGED_NORMMAP_BLEND, + RIGGED_NORMMAP_MASK, + RIGGED_NORMMAP_EMISSIVE, + RIGGED_NORMSPEC, + RIGGED_NORMSPEC_BLEND, + RIGGED_NORMSPEC_MASK, + RIGGED_NORMSPEC_EMISSIVE, + RIGGED_SIMPLE, RIGGED_FULLBRIGHT, RIGGED_SHINY, RIGGED_FULLBRIGHT_SHINY, @@ -170,6 +195,48 @@ class LLDrawPoolAvatar : public LLFacePool typedef enum { + RIGGED_MATERIAL_MASK = + LLVertexBuffer::MAP_VERTEX | + LLVertexBuffer::MAP_NORMAL | + LLVertexBuffer::MAP_TEXCOORD0 | + LLVertexBuffer::MAP_COLOR | + LLVertexBuffer::MAP_WEIGHT4, + RIGGED_MATERIAL_ALPHA_VMASK = RIGGED_MATERIAL_MASK, + RIGGED_MATERIAL_ALPHA_MASK_MASK = RIGGED_MATERIAL_MASK, + RIGGED_MATERIAL_ALPHA_EMISSIVE_MASK = RIGGED_MATERIAL_MASK, + RIGGED_SPECMAP_VMASK = + LLVertexBuffer::MAP_VERTEX | + LLVertexBuffer::MAP_NORMAL | + LLVertexBuffer::MAP_TEXCOORD0 | + LLVertexBuffer::MAP_TEXCOORD2 | + LLVertexBuffer::MAP_COLOR | + LLVertexBuffer::MAP_WEIGHT4, + RIGGED_SPECMAP_BLEND_MASK = RIGGED_SPECMAP_VMASK, + RIGGED_SPECMAP_MASK_MASK = RIGGED_SPECMAP_VMASK, + RIGGED_SPECMAP_EMISSIVE_MASK = RIGGED_SPECMAP_VMASK, + RIGGED_NORMMAP_VMASK = + LLVertexBuffer::MAP_VERTEX | + LLVertexBuffer::MAP_NORMAL | + LLVertexBuffer::MAP_TANGENT | + LLVertexBuffer::MAP_TEXCOORD0 | + LLVertexBuffer::MAP_TEXCOORD1 | + LLVertexBuffer::MAP_COLOR | + LLVertexBuffer::MAP_WEIGHT4, + RIGGED_NORMMAP_BLEND_MASK = RIGGED_NORMMAP_VMASK, + RIGGED_NORMMAP_MASK_MASK = RIGGED_NORMMAP_VMASK, + RIGGED_NORMMAP_EMISSIVE_MASK = RIGGED_NORMMAP_VMASK, + RIGGED_NORMSPEC_VMASK = + LLVertexBuffer::MAP_VERTEX | + LLVertexBuffer::MAP_NORMAL | + LLVertexBuffer::MAP_TANGENT | + LLVertexBuffer::MAP_TEXCOORD0 | + LLVertexBuffer::MAP_TEXCOORD1 | + LLVertexBuffer::MAP_TEXCOORD2 | + LLVertexBuffer::MAP_COLOR | + LLVertexBuffer::MAP_WEIGHT4, + RIGGED_NORMSPEC_BLEND_MASK = RIGGED_NORMSPEC_VMASK, + RIGGED_NORMSPEC_MASK_MASK = RIGGED_NORMSPEC_VMASK, + RIGGED_NORMSPEC_EMISSIVE_MASK = RIGGED_NORMSPEC_VMASK, RIGGED_SIMPLE_MASK = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0 | @@ -190,7 +257,7 @@ class LLDrawPoolAvatar : public LLFacePool RIGGED_DEFERRED_BUMP_MASK = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0 | - LLVertexBuffer::MAP_BINORMAL | + LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_WEIGHT4, RIGGED_DEFERRED_SIMPLE_MASK = LLVertexBuffer::MAP_VERTEX | @@ -214,6 +281,7 @@ class LLDrawPoolAvatar : public LLFacePool static BOOL sSkipOpaque; static BOOL sSkipTransparent; static S32 sDiffuseChannel; + static F32 sMinimumAlpha; static LLGLSLShader* sVertexProgram; }; diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp index 1debd4209b..d9a9365cf0 100644 --- a/indra/newview/lldrawpoolbump.cpp +++ b/indra/newview/lldrawpoolbump.cpp @@ -109,7 +109,7 @@ void LLStandardBumpmap::addstandard() // can't assert; we destroyGL and restoreGL a lot during *first* startup, which populates this list already, THEN we explicitly init the list as part of *normal* startup. Sigh. So clear the list every time before we (re-)add the standard bumpmaps. //llassert( LLStandardBumpmap::sStandardBumpmapCount == 0 ); clear(); - llinfos << "Adding standard bumpmaps." << llendl; + LL_INFOS() << "Adding standard bumpmaps." << LL_ENDL; gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount++] = LLStandardBumpmap("None"); // BE_NO_BUMP gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount++] = LLStandardBumpmap("Brightness"); // BE_BRIGHTNESS gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount++] = LLStandardBumpmap("Darkness"); // BE_DARKNESS @@ -118,7 +118,7 @@ void LLStandardBumpmap::addstandard() LLFILE* file = LLFile::fopen( file_name, "rt" ); /*Flawfinder: ignore*/ if( !file ) { - llwarns << "Could not open std_bump <" << file_name << ">" << llendl; + LL_WARNS() << "Could not open std_bump <" << file_name << ">" << LL_ENDL; return; } @@ -127,13 +127,13 @@ void LLStandardBumpmap::addstandard() S32 fields_read = fscanf( file, "LLStandardBumpmap version %d", &file_version ); if( fields_read != 1 ) { - llwarns << "Bad LLStandardBumpmap header" << llendl; + LL_WARNS() << "Bad LLStandardBumpmap header" << LL_ENDL; return; } if( file_version > STD_BUMP_LATEST_FILE_VERSION ) { - llwarns << "LLStandardBumpmap has newer version (" << file_version << ") than viewer (" << STD_BUMP_LATEST_FILE_VERSION << ")" << llendl; + LL_WARNS() << "LLStandardBumpmap has newer version (" << file_version << ") than viewer (" << STD_BUMP_LATEST_FILE_VERSION << ")" << LL_ENDL; return; } @@ -150,12 +150,12 @@ void LLStandardBumpmap::addstandard() } if( fields_read != 2 ) { - llwarns << "Bad LLStandardBumpmap entry" << llendl; + LL_WARNS() << "Bad LLStandardBumpmap entry" << LL_ENDL; return; } if(strlen(bump_image_id) == (UUID_STR_LENGTH - 1) + 4 && !stricmp(&(bump_image_id[UUID_STR_LENGTH-1]),".j2c")) bump_image_id[UUID_STR_LENGTH-1] = 0; // truncate to a valid uuid (hopefully) -// llinfos << "Loading bumpmap: " << bump_file << " from viewerart" << llendl; +// LL_INFOS() << "Loading bumpmap: " << bump_file << " from viewerart" << LL_ENDL; gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount].mLabel = label; gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount].mImage = LLViewerTextureManager::getFetchedTexture(LLUUID(bump_image_id)); @@ -171,7 +171,7 @@ void LLStandardBumpmap::addstandard() // static void LLStandardBumpmap::clear() { - llinfos << "Clearing standard bumpmaps." << llendl; + LL_INFOS() << "Clearing standard bumpmaps." << LL_ENDL; for( U32 i = 0; i < LLStandardBumpmap::sStandardBumpmapCount; i++ ) { gStandardBumpmapList[i].mLabel.assign(""); @@ -241,7 +241,7 @@ S32 LLDrawPoolBump::getNumPasses() void LLDrawPoolBump::beginRenderPass(S32 pass) { - LLFastTimer t(FTM_RENDER_BUMP); + LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP); switch( pass ) { case 0: @@ -268,9 +268,9 @@ void LLDrawPoolBump::beginRenderPass(S32 pass) void LLDrawPoolBump::render(S32 pass) { - LLFastTimer t(FTM_RENDER_BUMP); + LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP); - if (!gPipeline.hasRenderType(LLDrawPool::POOL_SIMPLE)) + if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_SIMPLE)) { return; } @@ -301,7 +301,7 @@ void LLDrawPoolBump::render(S32 pass) void LLDrawPoolBump::endRenderPass(S32 pass) { - LLFastTimer t(FTM_RENDER_BUMP); + LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP); switch( pass ) { case 0: @@ -330,11 +330,10 @@ void LLDrawPoolBump::endRenderPass(S32 pass) } //static -void LLDrawPoolBump::beginShiny(bool invisible) +void LLDrawPoolBump::beginShiny() { - LLFastTimer t(FTM_RENDER_SHINY); - if ((!invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_SHINY))|| - (invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_INVISI_SHINY))) + LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY); + if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_SHINY)) { return; } @@ -342,21 +341,14 @@ void LLDrawPoolBump::beginShiny(bool invisible) mShiny = TRUE; sVertexMask = VERTEX_MASK_SHINY; // Second pass: environment map - if (!invisible && mVertexShaderLevel > 1) + if (mVertexShaderLevel > 1) { sVertexMask = VERTEX_MASK_SHINY | LLVertexBuffer::MAP_TEXCOORD0; } if (getVertexShaderLevel() > 0) { - if (LLPipeline::sUnderWaterRender) - { - shader = &gObjectShinyWaterProgram; - } - else - { - shader = &gObjectShinyProgram; - } + shader = &gObjectSimpleProgram[LLPipeline::sUnderWaterRender<bind(); } else @@ -364,7 +356,7 @@ void LLDrawPoolBump::beginShiny(bool invisible) shader = NULL; } - bindCubeMap(shader, mVertexShaderLevel, diffuse_channel, cube_channel, invisible); + bindCubeMap(shader, mVertexShaderLevel, diffuse_channel, cube_channel); if (mVertexShaderLevel > 1) { //indexed texture rendering, channel 0 is always diffuse @@ -373,18 +365,14 @@ void LLDrawPoolBump::beginShiny(bool invisible) } //static -void LLDrawPoolBump::bindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel, bool invisible) +void LLDrawPoolBump::bindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel) { LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL; if( cube_map ) { - if (!invisible && shader ) + if (shader) { - LLMatrix4 mat; - mat.initRows(LLVector4(gGLModelView+0), - LLVector4(gGLModelView+4), - LLVector4(gGLModelView+8), - LLVector4(gGLModelView+12)); + LLMatrix4 mat(gGLModelView.getF32ptr()); LLVector3 vec = LLVector3(gShinyOrigin) * mat; LLVector4 vec4(vec, gShinyOrigin.mV[3]); shader->uniform4fv(LLViewerShaderMgr::SHINY_ORIGIN, 1, vec4.mV); @@ -423,43 +411,35 @@ void LLDrawPoolBump::bindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& di } } -void LLDrawPoolBump::renderShiny(bool invisible) +void LLDrawPoolBump::renderShiny() { - LLFastTimer t(FTM_RENDER_SHINY); - if ((!invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_SHINY))|| - (invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_INVISI_SHINY))) + LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY); + if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_SHINY)) { return; } if( gSky.mVOSkyp->getCubeMap() ) { - LLGLEnable blend_enable(GL_BLEND); - if (!invisible && mVertexShaderLevel > 1) + LLGLEnable blend_enable; + if (mVertexShaderLevel > 1) { LLRenderPass::pushBatches(LLRenderPass::PASS_SHINY, sVertexMask | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); } - else if (!invisible) + else { renderGroups(LLRenderPass::PASS_SHINY, sVertexMask); } - //else // invisible (deprecated) - //{ - //renderGroups(LLRenderPass::PASS_INVISI_SHINY, sVertexMask); - //} } } //static -void LLDrawPoolBump::unbindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel, bool invisible) +void LLDrawPoolBump::unbindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel) { LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL; if( cube_map ) { - cube_map->disable(); - cube_map->restoreMatrix(); - - if (!invisible && shader_level > 1) + if (shader_level > 1) { shader->disableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP); @@ -471,6 +451,10 @@ void LLDrawPoolBump::unbindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& } } } + // Moved below shader->disableTexture call to avoid false alarms from auto-re-enable of textures on stage 0 + // MAINT-755 + cube_map->disable(); + cube_map->restoreMatrix(); } if (!LLGLSLShader::sNoFixedFunction) @@ -483,16 +467,15 @@ void LLDrawPoolBump::unbindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& } } -void LLDrawPoolBump::endShiny(bool invisible) +void LLDrawPoolBump::endShiny() { - LLFastTimer t(FTM_RENDER_SHINY); - if ((!invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_SHINY))|| - (invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_INVISI_SHINY))) + LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY); + if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_SHINY)) { return; } - unbindCubeMap(shader, mVertexShaderLevel, diffuse_channel, cube_channel, invisible); + unbindCubeMap(shader, mVertexShaderLevel, diffuse_channel, cube_channel); if (shader) { shader->unbind(); @@ -505,7 +488,7 @@ void LLDrawPoolBump::endShiny(bool invisible) void LLDrawPoolBump::beginFullbrightShiny() { - LLFastTimer t(FTM_RENDER_SHINY); + LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY); if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY)) { return; @@ -515,23 +498,19 @@ void LLDrawPoolBump::beginFullbrightShiny() // Second pass: environment map - if (LLPipeline::sUnderWaterRender) + if(!LLPipeline::sUnderWaterRender && LLPipeline::sRenderDeferred) { - shader = &gObjectFullbrightShinyWaterProgram; + shader = &gDeferredFullbrightShinyProgram; } else { - shader = &gObjectFullbrightShinyProgram; + shader = &gObjectFullbrightProgram[LLPipeline::sUnderWaterRender<getCubeMap() : NULL; if( cube_map ) { - LLMatrix4 mat; - mat.initRows(LLVector4(gGLModelView+0), - LLVector4(gGLModelView+4), - LLVector4(gGLModelView+8), - LLVector4(gGLModelView+12)); + LLMatrix4 mat(gGLModelView.getF32ptr()); shader->bind(); LLVector3 vec = LLVector3(gShinyOrigin) * mat; LLVector4 vec4(vec, gShinyOrigin.mV[3]); @@ -560,7 +539,7 @@ void LLDrawPoolBump::beginFullbrightShiny() void LLDrawPoolBump::renderFullbrightShiny() { - LLFastTimer t(FTM_RENDER_SHINY); + LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY); if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY)) { return; @@ -568,8 +547,9 @@ void LLDrawPoolBump::renderFullbrightShiny() if( gSky.mVOSkyp->getCubeMap() ) { - LLGLEnable blend_enable(GL_BLEND); + LLGLEnable blend_enable; + gGL.setSceneBlendType(LLRender::BT_REPLACE); if (mVertexShaderLevel > 1) { LLRenderPass::pushBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY, sVertexMask | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); @@ -578,12 +558,13 @@ void LLDrawPoolBump::renderFullbrightShiny() { LLRenderPass::renderTexture(LLRenderPass::PASS_FULLBRIGHT_SHINY, sVertexMask); } + gGL.setSceneBlendType(LLRender::BT_ALPHA); } } void LLDrawPoolBump::endFullbrightShiny() { - LLFastTimer t(FTM_RENDER_SHINY); + LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY); if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY)) { return; @@ -714,7 +695,7 @@ void LLDrawPoolBump::beginBump(U32 pass) } sVertexMask = VERTEX_MASK_BUMP; - LLFastTimer t(FTM_RENDER_BUMP); + LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP); // Optional second pass: emboss bump map stop_glerror(); @@ -766,14 +747,14 @@ void LLDrawPoolBump::renderBump(U32 pass) return; } - LLFastTimer ftm(FTM_RENDER_BUMP); - LLGLDisable fog(GL_FOG); + LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP); + LLGLDisable fog; LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE, GL_LEQUAL); - LLGLEnable blend(GL_BLEND); + LLGLEnable blend; gGL.diffuseColor4f(1,1,1,1); /// Get rid of z-fighting with non-bump pass. - LLGLEnable polyOffset(GL_POLYGON_OFFSET_FILL); - glPolygonOffset(-1.0f, -1.0f); + LLGLEnable polyOffset; + gGL.setPolygonOffset(-1.0f, -1.0f); renderBump(pass, sVertexMask); } @@ -816,7 +797,7 @@ void LLDrawPoolBump::beginDeferredPass(S32 pass) { return; } - LLFastTimer ftm(FTM_RENDER_BUMP); + LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP); mShiny = TRUE; gDeferredBumpProgram.bind(); diffuse_channel = gDeferredBumpProgram.enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); @@ -831,7 +812,7 @@ void LLDrawPoolBump::endDeferredPass(S32 pass) { return; } - LLFastTimer ftm(FTM_RENDER_BUMP); + LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP); mShiny = FALSE; gDeferredBumpProgram.disableTexture(LLViewerShaderMgr::DIFFUSE_MAP); gDeferredBumpProgram.disableTexture(LLViewerShaderMgr::BUMP_MAP); @@ -845,13 +826,13 @@ void LLDrawPoolBump::renderDeferred(S32 pass) { return; } - LLFastTimer ftm(FTM_RENDER_BUMP); + LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP); U32 type = LLRenderPass::PASS_BUMP; LLCullResult::drawinfo_iterator begin = gPipeline.beginRenderMap(type); LLCullResult::drawinfo_iterator end = gPipeline.endRenderMap(type); - U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_BINORMAL | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_COLOR; + U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_COLOR; for (LLCullResult::drawinfo_iterator i = begin; i != end; ++i) { @@ -896,7 +877,9 @@ void LLDrawPoolBump::renderPostDeferred(S32 pass) switch (pass) { case 0: + gGL.setColorMask(true, true); renderFullbrightShiny(); + gGL.setColorMask(true, false); break; case 1: renderBump(LLRenderPass::PASS_POST_BUMP); @@ -920,7 +903,7 @@ void LLBumpImageList::init() void LLBumpImageList::clear() { - llinfos << "Clearing dynamic bumpmaps." << llendl; + LL_INFOS() << "Clearing dynamic bumpmaps." << LL_ENDL; // these will be re-populated on-demand mBrightnessEntries.clear(); mDarknessEntries.clear(); @@ -995,7 +978,7 @@ void LLBumpImageList::updateImages() if( destroy ) { - //llinfos << "*** Destroying bright " << (void*)image << llendl; + //LL_INFOS() << "*** Destroying bright " << (void*)image << LL_ENDL; mBrightnessEntries.erase(curiter); // deletes the image thanks to reference counting } } @@ -1022,7 +1005,7 @@ void LLBumpImageList::updateImages() if( destroy ) { - //llinfos << "*** Destroying dark " << (void*)image << llendl;; + //LL_INFOS() << "*** Destroying dark " << (void*)image << LL_ENDL;; mDarknessEntries.erase(curiter); // deletes the image thanks to reference counting } } @@ -1085,7 +1068,7 @@ LLViewerTexture* LLBumpImageList::getBrightnessDarknessImage(LLViewerFetchedText } -static LLFastTimer::DeclareTimer FTM_BUMP_SOURCE_STANDARD_LOADED("Bump Standard Callback"); +static LLTrace::BlockTimerStatHandle FTM_BUMP_SOURCE_STANDARD_LOADED("Bump Standard Callback"); // static void LLBumpImageList::onSourceBrightnessLoaded( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata ) @@ -1109,22 +1092,22 @@ void LLBumpImageList::onSourceDarknessLoaded( BOOL success, LLViewerFetchedTextu } } -static LLFastTimer::DeclareTimer FTM_BUMP_GEN_NORMAL("Generate Normal Map"); -static LLFastTimer::DeclareTimer FTM_BUMP_CREATE_TEXTURE("Create GL Normal Map"); +static LLTrace::BlockTimerStatHandle FTM_BUMP_GEN_NORMAL("Generate Normal Map"); +static LLTrace::BlockTimerStatHandle FTM_BUMP_CREATE_TEXTURE("Create GL Normal Map"); void LLBumpImageList::onSourceStandardLoaded( BOOL success, LLViewerFetchedTexture* src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata) { if (success && LLPipeline::sRenderDeferred) { - LLFastTimer t(FTM_BUMP_SOURCE_STANDARD_LOADED); + LL_RECORD_BLOCK_TIME(FTM_BUMP_SOURCE_STANDARD_LOADED); LLPointer nrm_image = new LLImageRaw(src->getWidth(), src->getHeight(), 4); { - LLFastTimer t(FTM_BUMP_GEN_NORMAL); + LL_RECORD_BLOCK_TIME(FTM_BUMP_GEN_NORMAL); generateNormalMapFromAlpha(src, nrm_image); } src_vi->setExplicitFormat(GL_RGBA, GL_RGBA); { - LLFastTimer t(FTM_BUMP_CREATE_TEXTURE); + LL_RECORD_BLOCK_TIME(FTM_BUMP_CREATE_TEXTURE); src_vi->createGLTexture(src_vi->getDiscardLevel(), nrm_image); } } @@ -1186,27 +1169,27 @@ void LLBumpImageList::generateNormalMapFromAlpha(LLImageRaw* src, LLImageRaw* nr } -static LLFastTimer::DeclareTimer FTM_BUMP_SOURCE_LOADED("Bump Source Loaded"); -static LLFastTimer::DeclareTimer FTM_BUMP_SOURCE_ENTRIES_UPDATE("Entries Update"); -static LLFastTimer::DeclareTimer FTM_BUMP_SOURCE_MIN_MAX("Min/Max"); -static LLFastTimer::DeclareTimer FTM_BUMP_SOURCE_RGB2LUM("RGB to Luminance"); -static LLFastTimer::DeclareTimer FTM_BUMP_SOURCE_RESCALE("Rescale"); -static LLFastTimer::DeclareTimer FTM_BUMP_SOURCE_GEN_NORMAL("Generate Normal"); -static LLFastTimer::DeclareTimer FTM_BUMP_SOURCE_CREATE("Bump Source Create"); +static LLTrace::BlockTimerStatHandle FTM_BUMP_SOURCE_LOADED("Bump Source Loaded"); +static LLTrace::BlockTimerStatHandle FTM_BUMP_SOURCE_ENTRIES_UPDATE("Entries Update"); +static LLTrace::BlockTimerStatHandle FTM_BUMP_SOURCE_MIN_MAX("Min/Max"); +static LLTrace::BlockTimerStatHandle FTM_BUMP_SOURCE_RGB2LUM("RGB to Luminance"); +static LLTrace::BlockTimerStatHandle FTM_BUMP_SOURCE_RESCALE("Rescale"); +static LLTrace::BlockTimerStatHandle FTM_BUMP_SOURCE_GEN_NORMAL("Generate Normal"); +static LLTrace::BlockTimerStatHandle FTM_BUMP_SOURCE_CREATE("Bump Source Create"); // static void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLImageRaw* src, LLUUID& source_asset_id, EBumpEffect bump_code ) { if( success ) { - LLFastTimer t(FTM_BUMP_SOURCE_LOADED); + LL_RECORD_BLOCK_TIME(FTM_BUMP_SOURCE_LOADED); bump_image_map_t& entries_list(bump_code == BE_BRIGHTNESS ? gBumpImageList.mBrightnessEntries : gBumpImageList.mDarknessEntries ); bump_image_map_t::iterator iter = entries_list.find(source_asset_id); { - LLFastTimer t(FTM_BUMP_SOURCE_ENTRIES_UPDATE); + LL_RECORD_BLOCK_TIME(FTM_BUMP_SOURCE_ENTRIES_UPDATE); if (iter == entries_list.end() || iter->second.isNull() || iter->second->getWidth() != src->getWidth() || @@ -1249,7 +1232,7 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI case 1: case 2: { - LLFastTimer t(FTM_BUMP_SOURCE_MIN_MAX); + LL_RECORD_BLOCK_TIME(FTM_BUMP_SOURCE_MIN_MAX); if( src_data_size == dst_data_size * src_components ) { for( S32 i = 0, j=0; i < dst_data_size; i++, j+= src_components ) @@ -1275,7 +1258,7 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI case 3: case 4: { - LLFastTimer t(FTM_BUMP_SOURCE_RGB2LUM); + LL_RECORD_BLOCK_TIME(FTM_BUMP_SOURCE_RGB2LUM); if( src_data_size == dst_data_size * src_components ) { for( S32 i = 0, j=0; i < dst_data_size; i++, j+= src_components ) @@ -1308,7 +1291,7 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI if( maximum > minimum ) { - LLFastTimer t(FTM_BUMP_SOURCE_RESCALE); + LL_RECORD_BLOCK_TIME(FTM_BUMP_SOURCE_RESCALE); U8 bias_and_scale_lut[256]; F32 twice_one_over_range = 2.f / (maximum - minimum); S32 i; @@ -1319,7 +1302,7 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI for( i = minimum; i <= maximum; i++ ) { F32 minus_one_to_one = F32(maximum - i) * twice_one_over_range - 1.f; - bias_and_scale_lut[i] = llclampb(llround(127 * minus_one_to_one * ARTIFICIAL_SCALE + 128)); + bias_and_scale_lut[i] = llclampb(ll_round(127 * minus_one_to_one * ARTIFICIAL_SCALE + 128)); } } else @@ -1328,7 +1311,7 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI for( i = minimum; i <= maximum; i++ ) { F32 minus_one_to_one = F32(i - minimum) * twice_one_over_range - 1.f; - bias_and_scale_lut[i] = llclampb(llround(127 * minus_one_to_one * ARTIFICIAL_SCALE + 128)); + bias_and_scale_lut[i] = llclampb(ll_round(127 * minus_one_to_one * ARTIFICIAL_SCALE + 128)); } } @@ -1345,7 +1328,7 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI if (!LLPipeline::sRenderDeferred) { - LLFastTimer t(FTM_BUMP_SOURCE_CREATE); + LL_RECORD_BLOCK_TIME(FTM_BUMP_SOURCE_CREATE); bump->setExplicitFormat(GL_ALPHA8, GL_ALPHA); bump->createGLTexture(0, dst_image); } @@ -1356,23 +1339,28 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI bump->getGLTexture()->setAllowCompression(false); { - LLFastTimer t(FTM_BUMP_SOURCE_CREATE); + LL_RECORD_BLOCK_TIME(FTM_BUMP_SOURCE_CREATE); bump->setExplicitFormat(GL_RGBA8, GL_ALPHA); bump->createGLTexture(0, dst_image); } { - LLFastTimer t(FTM_BUMP_SOURCE_GEN_NORMAL); + LL_RECORD_BLOCK_TIME(FTM_BUMP_SOURCE_GEN_NORMAL); gPipeline.mScreen.bindTarget(); LLGLDepthTest depth(GL_FALSE); - LLGLDisable cull(GL_CULL_FACE); - LLGLDisable blend(GL_BLEND); + LLGLDisable cull; + LLGLDisable blend; gGL.setColorMask(TRUE, TRUE); gNormalMapGenProgram.bind(); - gNormalMapGenProgram.uniform1f("norm_scale", gSavedSettings.getF32("RenderNormalMapScale")); - gNormalMapGenProgram.uniform1f("stepX", 1.f/bump->getWidth()); - gNormalMapGenProgram.uniform1f("stepY", 1.f/bump->getHeight()); + + static LLStaticHashedString sNormScale("norm_scale"); + static LLStaticHashedString sStepX("stepX"); + static LLStaticHashedString sStepY("stepY"); + + gNormalMapGenProgram.uniform1f(sNormScale, gSavedSettings.getF32("RenderNormalMapScale")); + gNormalMapGenProgram.uniform1f(sStepX, 1.f/bump->getWidth()); + gNormalMapGenProgram.uniform1f(sStepY, 1.f/bump->getHeight()); LLVector2 v((F32) bump->getWidth()/gPipeline.mScreen.getWidth(), (F32) bump->getHeight()/gPipeline.mScreen.getHeight()); @@ -1385,7 +1373,7 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI S32 screen_width = gPipeline.mScreen.getWidth(); S32 screen_height = gPipeline.mScreen.getHeight(); - glViewport(0, 0, screen_width, screen_height); + gGL.setViewport(0, 0, screen_width, screen_height); for (S32 left = 0; left < width; left += screen_width) { @@ -1494,16 +1482,16 @@ void LLDrawPoolBump::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL { gGL.getTexUnit(1)->activate(); gGL.matrixMode(LLRender::MM_TEXTURE); - gGL.loadMatrix((GLfloat*) params.mTextureMatrix->mMatrix); + gGL.loadMatrix(*params.mTextureMatrix); } gGL.getTexUnit(0)->activate(); gGL.matrixMode(LLRender::MM_TEXTURE); - gGL.loadMatrix((GLfloat*) params.mTextureMatrix->mMatrix); + gGL.loadMatrix(*params.mTextureMatrix); gPipeline.mTextureMatrixOps++; } - gGL.loadMatrix((GLfloat*) params.mTextureMatrix->mMatrix); + gGL.loadMatrix(*params.mTextureMatrix); gPipeline.mTextureMatrixOps++; tex_setup = true; @@ -1550,76 +1538,3 @@ void LLDrawPoolBump::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL gGL.matrixMode(LLRender::MM_MODELVIEW); } } - -void LLDrawPoolInvisible::render(S32 pass) -{ //render invisiprims - LLFastTimer t(FTM_RENDER_INVISIBLE); - - if (gPipeline.canUseVertexShaders()) - { - gOcclusionProgram.bind(); - } - - U32 invisi_mask = LLVertexBuffer::MAP_VERTEX; - glStencilMask(0); - gGL.setColorMask(false, false); - pushBatches(LLRenderPass::PASS_INVISIBLE, invisi_mask, FALSE); - gGL.setColorMask(true, false); - glStencilMask(0xFFFFFFFF); - - if (gPipeline.canUseVertexShaders()) - { - gOcclusionProgram.unbind(); - } - - /*if (gPipeline.hasRenderBatches(LLRenderPass::PASS_INVISI_SHINY)) // invisible (deprecated) - { - beginShiny(true); - renderShiny(true); - endShiny(true); - }*/ -} - -void LLDrawPoolInvisible::beginDeferredPass(S32 pass) -{ - static const LLCachedControl enable("SianaRenderDeferredInvisiprim"); - if (!enable) - { - return; - } - beginRenderPass(pass); -} - -void LLDrawPoolInvisible::endDeferredPass( S32 pass ) -{ - endRenderPass(pass); -} - -void LLDrawPoolInvisible::renderDeferred( S32 pass ) -{ //render invisiprims; this doesn't work becaue it also blocks all the post-deferred stuff - static const LLCachedControl enable("SianaRenderDeferredInvisiprim"); - if (!enable) - { - return; - } - - LLFastTimer t(FTM_RENDER_INVISIBLE); - - gOcclusionProgram.bind(); - - U32 invisi_mask = LLVertexBuffer::MAP_VERTEX; - glStencilMask(0); - gGL.setColorMask(false, false); - pushBatches(LLRenderPass::PASS_INVISIBLE, invisi_mask, FALSE); - gGL.setColorMask(true, true); - glStencilMask(0xFFFFFFFF); - - gOcclusionProgram.unbind(); - - /*if (gPipeline.hasRenderBatches(LLRenderPass::PASS_INVISI_SHINY)) // invisible (deprecated) - { - beginShiny(true); - renderShiny(true); - endShiny(true); - }*/ -} diff --git a/indra/newview/lldrawpoolbump.h b/indra/newview/lldrawpoolbump.h index 2611730ee9..e51e566276 100644 --- a/indra/newview/lldrawpoolbump.h +++ b/indra/newview/lldrawpoolbump.h @@ -68,9 +68,9 @@ protected : S32 numBumpPasses(); - void beginShiny(bool invisible = false); - void renderShiny(bool invisible = false); - void endShiny(bool invisible = false); + void beginShiny(); + void renderShiny(); + void endShiny(); void beginFullbrightShiny(); void renderFullbrightShiny(); @@ -80,8 +80,8 @@ protected : void renderBump(U32 pass = LLRenderPass::PASS_BUMP); void endBump(U32 pass = LLRenderPass::PASS_BUMP); - static void bindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel, bool invisible); - static void unbindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel, bool invisible); + static void bindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel); + static void unbindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel); virtual S32 getNumDeferredPasses(); /*virtual*/ void beginDeferredPass(S32 pass); @@ -173,30 +173,4 @@ class LLBumpImageList extern LLBumpImageList gBumpImageList; -class LLDrawPoolInvisible : public LLDrawPoolBump -{ -public: - LLDrawPoolInvisible() : LLDrawPoolBump(LLDrawPool::POOL_INVISIBLE) { } - - enum - { - VERTEX_DATA_MASK = LLVertexBuffer::MAP_VERTEX - }; - - virtual U32 getVertexDataMask() { return VERTEX_DATA_MASK; } - - virtual void prerender() { } - - virtual void render(S32 pass = 0); - virtual void beginRenderPass( S32 pass ) { } - virtual void endRenderPass( S32 pass ) { } - virtual S32 getNumPasses() {return 1;} - - virtual S32 getNumDeferredPasses() { return 1; } - /*virtual*/ void beginDeferredPass(S32 pass); - /*virtual*/ void endDeferredPass(S32 pass); - /*virtual*/ void renderDeferred(S32 pass); -}; - - #endif // LL_LLDRAWPOOLBUMP_H diff --git a/indra/newview/lldrawpoolground.cpp b/indra/newview/lldrawpoolground.cpp index 2f5849bb07..d3d63a7922 100644 --- a/indra/newview/lldrawpoolground.cpp +++ b/indra/newview/lldrawpoolground.cpp @@ -83,8 +83,6 @@ void LLDrawPoolGround::render(S32 pass) LLFace *facep = mDrawFace[0]; - gPipeline.disableLights(); - LLOverrideFaceColor col(this, gSky.mVOSkyp->getGLFogColor()); facep->renderIndexed(); diff --git a/indra/newview/lldrawpoolmaterials.cpp b/indra/newview/lldrawpoolmaterials.cpp new file mode 100644 index 0000000000..5b15f78af0 --- /dev/null +++ b/indra/newview/lldrawpoolmaterials.cpp @@ -0,0 +1,224 @@ +/** + * @file lldrawpool.cpp + * @brief LLDrawPoolMaterials class implementation + * @author Jonathan "Geenz" Goodman + * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2013, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "lldrawpoolmaterials.h" +#include "llviewershadermgr.h" +#include "pipeline.h" + +S32 diffuse_channel = -1; + +LLDrawPoolMaterials::LLDrawPoolMaterials() +: LLRenderPass(LLDrawPool::POOL_MATERIALS) +{ + +} + +void LLDrawPoolMaterials::prerender() +{ + mVertexShaderLevel = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT); +} + +S32 LLDrawPoolMaterials::getNumDeferredPasses() +{ + return 12; +} + +void LLDrawPoolMaterials::beginDeferredPass(S32 pass) +{ + U32 shader_idx[] = + { + 0, //LLRenderPass::PASS_MATERIAL, + //1, //LLRenderPass::PASS_MATERIAL_ALPHA, + 2, //LLRenderPass::PASS_MATERIAL_ALPHA_MASK, + 3, //LLRenderPass::PASS_MATERIAL_ALPHA_GLOW, + 4, //LLRenderPass::PASS_SPECMAP, + //5, //LLRenderPass::PASS_SPECMAP_BLEND, + 6, //LLRenderPass::PASS_SPECMAP_MASK, + 7, //LLRenderPass::PASS_SPECMAP_GLOW, + 8, //LLRenderPass::PASS_NORMMAP, + //9, //LLRenderPass::PASS_NORMMAP_BLEND, + 10, //LLRenderPass::PASS_NORMMAP_MASK, + 11, //LLRenderPass::PASS_NORMMAP_GLOW, + 12, //LLRenderPass::PASS_NORMSPEC, + //13, //LLRenderPass::PASS_NORMSPEC_BLEND, + 14, //LLRenderPass::PASS_NORMSPEC_MASK, + 15, //LLRenderPass::PASS_NORMSPEC_GLOW, + }; + + mShader = &(gDeferredMaterialProgram[shader_idx[pass]]); + + if (LLPipeline::sUnderWaterRender) + { + mShader = &(gDeferredMaterialWaterProgram[shader_idx[pass]]); + } + + mShader->bind(); + + diffuse_channel = mShader->enableTexture(LLShaderMgr::DIFFUSE_MAP); + + LL_RECORD_BLOCK_TIME(FTM_RENDER_MATERIALS); +} + +void LLDrawPoolMaterials::endDeferredPass(S32 pass) +{ + LL_RECORD_BLOCK_TIME(FTM_RENDER_MATERIALS); + + mShader->unbind(); + + LLRenderPass::endRenderPass(pass); +} + +void LLDrawPoolMaterials::renderDeferred(S32 pass) +{ + U32 type_list[] = + { + LLRenderPass::PASS_MATERIAL, + //LLRenderPass::PASS_MATERIAL_ALPHA, + LLRenderPass::PASS_MATERIAL_ALPHA_MASK, + LLRenderPass::PASS_MATERIAL_ALPHA_EMISSIVE, + LLRenderPass::PASS_SPECMAP, + //LLRenderPass::PASS_SPECMAP_BLEND, + LLRenderPass::PASS_SPECMAP_MASK, + LLRenderPass::PASS_SPECMAP_EMISSIVE, + LLRenderPass::PASS_NORMMAP, + //LLRenderPass::PASS_NORMMAP_BLEND, + LLRenderPass::PASS_NORMMAP_MASK, + LLRenderPass::PASS_NORMMAP_EMISSIVE, + LLRenderPass::PASS_NORMSPEC, + //LLRenderPass::PASS_NORMSPEC_BLEND, + LLRenderPass::PASS_NORMSPEC_MASK, + LLRenderPass::PASS_NORMSPEC_EMISSIVE, + }; + + llassert(pass < sizeof(type_list)/sizeof(U32)); + + U32 type = type_list[pass]; + + U32 mask = mShader->mAttributeMask; + + LLCullResult::drawinfo_iterator begin = gPipeline.beginRenderMap(type); + LLCullResult::drawinfo_iterator end = gPipeline.endRenderMap(type); + + for (LLCullResult::drawinfo_iterator i = begin; i != end; ++i) + { + LLDrawInfo& params = **i; + + mShader->uniform4f(LLShaderMgr::SPECULAR_COLOR, params.mSpecColor.mV[0], params.mSpecColor.mV[1], params.mSpecColor.mV[2], params.mSpecColor.mV[3]); + mShader->uniform1f(LLShaderMgr::ENVIRONMENT_INTENSITY, params.mEnvIntensity); + + if (params.mNormalMap) + { + params.mNormalMap->addTextureStats(params.mVSize); + bindNormalMap(params.mNormalMap); + } + + if (params.mSpecularMap) + { + params.mSpecularMap->addTextureStats(params.mVSize); + bindSpecularMap(params.mSpecularMap); + } + + mShader->setMinimumAlpha(params.mAlphaMaskCutoff); + mShader->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, params.mFullbright ? 1.f : 0.f); + + pushBatch(params, mask, TRUE); + } +} + +void LLDrawPoolMaterials::bindSpecularMap(LLViewerTexture* tex) +{ + mShader->bindTexture(LLShaderMgr::SPECULAR_MAP, tex); +} + +void LLDrawPoolMaterials::bindNormalMap(LLViewerTexture* tex) +{ + mShader->bindTexture(LLShaderMgr::BUMP_MAP, tex); +} + +void LLDrawPoolMaterials::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures) +{ + applyModelMatrix(params); + + bool tex_setup = false; + + if (batch_textures && params.mTextureList.size() > 1) + { + for (U32 i = 0; i < params.mTextureList.size(); ++i) + { + if (params.mTextureList[i].notNull()) + { + gGL.getTexUnit(i)->bind(params.mTextureList[i], TRUE); + } + } + } + else + { //not batching textures or batch has only 1 texture -- might need a texture matrix + if (params.mTextureMatrix) + { + //if (mShiny) + { + gGL.getTexUnit(0)->activate(); + gGL.matrixMode(LLRender::MM_TEXTURE); + } + + gGL.loadMatrix(*params.mTextureMatrix); + gPipeline.mTextureMatrixOps++; + + tex_setup = true; + } + + if (mVertexShaderLevel > 1 && texture) + { + if (params.mTexture.notNull()) + { + gGL.getTexUnit(diffuse_channel)->bind(params.mTexture); + params.mTexture->addTextureStats(params.mVSize); + } + else + { + gGL.getTexUnit(diffuse_channel)->unbind(LLTexUnit::TT_TEXTURE); + } + } + } + + if (params.mGroup) + { + params.mGroup->rebuildMesh(); + } + params.mVertexBuffer->setBuffer(mask); + params.mVertexBuffer->drawRange(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset); + gPipeline.addTrianglesDrawn(params.mCount, params.mDrawMode); + if (tex_setup) + { + gGL.getTexUnit(0)->activate(); + gGL.loadIdentity(); + gGL.matrixMode(LLRender::MM_MODELVIEW); + } +} + diff --git a/indra/newview/lldrawpoolmaterials.h b/indra/newview/lldrawpoolmaterials.h new file mode 100644 index 0000000000..eae1aba87c --- /dev/null +++ b/indra/newview/lldrawpoolmaterials.h @@ -0,0 +1,75 @@ +/** + * @file lldrawpoolmaterials.h + * @brief LLDrawPoolMaterials class definition + * @author Jonathan "Geenz" Goodman + * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2013, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLDRAWPOOLMATERIALS_H +#define LL_LLDRAWPOOLMATERIALS_H + +#include "v4coloru.h" +#include "v2math.h" +#include "v3math.h" +#include "llvertexbuffer.h" +#include "lldrawpool.h" + +class LLViewerTexture; +class LLDrawInfo; +class LLGLSLShader; + +class LLDrawPoolMaterials : public LLRenderPass +{ + LLGLSLShader *mShader; +public: + LLDrawPoolMaterials(); + + enum + { + VERTEX_DATA_MASK = LLVertexBuffer::MAP_VERTEX | + LLVertexBuffer::MAP_NORMAL | + LLVertexBuffer::MAP_TEXCOORD0 | + LLVertexBuffer::MAP_TEXCOORD1 | + LLVertexBuffer::MAP_TEXCOORD2 | + LLVertexBuffer::MAP_COLOR | + LLVertexBuffer::MAP_TANGENT + }; + + /*virtual*/ U32 getVertexDataMask() { return VERTEX_DATA_MASK; } + + /*virtual*/ void render(S32 pass = 0) { } + /*virtual*/ S32 getNumPasses() {return 0;} + /*virtual*/ void prerender(); + + /*virtual*/ S32 getNumDeferredPasses(); + /*virtual*/ void beginDeferredPass(S32 pass); + /*virtual*/ void endDeferredPass(S32 pass); + /*virtual*/ void renderDeferred(S32 pass); + + void bindSpecularMap(LLViewerTexture* tex); + void bindNormalMap(LLViewerTexture* tex); + + /*virtual*/ void pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures = FALSE); +}; + +#endif //LL_LLDRAWPOOLMATERIALS_H diff --git a/indra/newview/lldrawpoolsimple.cpp b/indra/newview/lldrawpoolsimple.cpp index 4bc06580f6..ff864fb852 100644 --- a/indra/newview/lldrawpoolsimple.cpp +++ b/indra/newview/lldrawpoolsimple.cpp @@ -37,36 +37,36 @@ #include "llviewershadermgr.h" #include "llrender.h" - static LLGLSLShader* simple_shader = NULL; static LLGLSLShader* fullbright_shader = NULL; -static LLFastTimer::DeclareTimer FTM_RENDER_SIMPLE_DEFERRED("Deferred Simple"); -static LLFastTimer::DeclareTimer FTM_RENDER_GRASS_DEFERRED("Deferred Grass"); +static LLTrace::BlockTimerStatHandle FTM_RENDER_SIMPLE_DEFERRED("Deferred Simple"); +static LLTrace::BlockTimerStatHandle FTM_RENDER_GRASS_DEFERRED("Deferred Grass"); void LLDrawPoolGlow::beginPostDeferredPass(S32 pass) { gDeferredEmissiveProgram.bind(); + gDeferredEmissiveProgram.uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f); } -static LLFastTimer::DeclareTimer FTM_RENDER_GLOW_PUSH("Glow Push"); +static LLTrace::BlockTimerStatHandle FTM_RENDER_GLOW_PUSH("Glow Push"); void LLDrawPoolGlow::renderPostDeferred(S32 pass) { - LLFastTimer t(FTM_RENDER_GLOW); - LLGLEnable blend(GL_BLEND); - LLGLDisable test(GL_ALPHA_TEST); + LL_RECORD_BLOCK_TIME(FTM_RENDER_GLOW); + LLGLEnable blend; + LLGLDisable test; gGL.flush(); /// Get rid of z-fighting with non-glow pass. - LLGLEnable polyOffset(GL_POLYGON_OFFSET_FILL); - glPolygonOffset(-1.0f, -1.0f); + LLGLEnable polyOffset; + gGL.setPolygonOffset(-1.0f, -1.0f); gGL.setSceneBlendType(LLRender::BT_ADD); LLGLDepthTest depth(GL_TRUE, GL_FALSE); gGL.setColorMask(false, true); { - LLFastTimer t(FTM_RENDER_GLOW_PUSH); + LL_RECORD_BLOCK_TIME(FTM_RENDER_GLOW_PUSH); pushBatches(LLRenderPass::PASS_GLOW, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); } @@ -94,13 +94,13 @@ S32 LLDrawPoolGlow::getNumPasses() void LLDrawPoolGlow::render(S32 pass) { - LLFastTimer t(FTM_RENDER_GLOW); - LLGLEnable blend(GL_BLEND); - LLGLDisable test(GL_ALPHA_TEST); + LL_RECORD_BLOCK_TIME(FTM_RENDER_GLOW); + LLGLEnable blend; + LLGLDisable test; gGL.flush(); /// Get rid of z-fighting with non-glow pass. - LLGLEnable polyOffset(GL_POLYGON_OFFSET_FILL); - glPolygonOffset(-1.0f, -1.0f); + LLGLEnable polyOffset; + gGL.setPolygonOffset(-1.0f, -1.0f); gGL.setSceneBlendType(LLRender::BT_ADD); U32 shader_level = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT); @@ -108,8 +108,16 @@ void LLDrawPoolGlow::render(S32 pass) //should never get here without basic shaders enabled llassert(shader_level > 0); - LLGLSLShader* shader = LLPipeline::sUnderWaterRender ? &gObjectEmissiveWaterProgram : &gObjectEmissiveProgram; + LLGLSLShader* shader = &gObjectEmissiveProgram[LLPipeline::sUnderWaterRender<bind(); + if (LLPipeline::sRenderDeferred) + { + shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f); + } + else + { + shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.f); + } LLGLDepthTest depth(GL_TRUE, GL_FALSE); gGL.setColorMask(false, true); @@ -144,16 +152,9 @@ void LLDrawPoolSimple::prerender() void LLDrawPoolSimple::beginRenderPass(S32 pass) { - LLFastTimer t(FTM_RENDER_SIMPLE); + LL_RECORD_BLOCK_TIME(FTM_RENDER_SIMPLE); - if (LLPipeline::sUnderWaterRender) - { - simple_shader = &gObjectSimpleWaterProgram; - } - else - { - simple_shader = &gObjectSimpleProgram; - } + simple_shader = &gObjectSimpleProgram[LLPipeline::sUnderWaterRender< 0) { @@ -171,7 +172,7 @@ void LLDrawPoolSimple::beginRenderPass(S32 pass) void LLDrawPoolSimple::endRenderPass(S32 pass) { - LLFastTimer t(FTM_RENDER_SIMPLE); + LL_RECORD_BLOCK_TIME(FTM_RENDER_SIMPLE); stop_glerror(); LLRenderPass::endRenderPass(pass); stop_glerror(); @@ -183,11 +184,12 @@ void LLDrawPoolSimple::endRenderPass(S32 pass) void LLDrawPoolSimple::render(S32 pass) { - LLGLDisable blend(GL_BLEND); + LLGLDisable blend; { //render simple - LLFastTimer t(FTM_RENDER_SIMPLE); - gPipeline.enableLightsDynamic(); + LL_RECORD_BLOCK_TIME(FTM_RENDER_SIMPLE); + LLGLState lighting; + gPipeline.enableLightsDynamic(lighting); if (mVertexShaderLevel > 0) { @@ -198,31 +200,184 @@ void LLDrawPoolSimple::render(S32 pass) if (LLPipeline::sRenderDeferred) { //if deferred rendering is enabled, bump faces aren't registered as simple //render bump faces here as simple so bump faces will appear under water - pushBatches(LLRenderPass::PASS_BUMP, mask, TRUE, TRUE); + pushBatches(LLRenderPass::PASS_BUMP, mask, TRUE, TRUE); + pushBatches(LLRenderPass::PASS_MATERIAL, mask, TRUE, TRUE); + pushBatches(LLRenderPass::PASS_SPECMAP, mask, TRUE, TRUE); + pushBatches(LLRenderPass::PASS_NORMMAP, mask, TRUE, TRUE); + pushBatches(LLRenderPass::PASS_NORMSPEC, mask, TRUE, TRUE); } } else { - LLGLDisable alpha_test(GL_ALPHA_TEST); + LLGLDisable alpha_test; renderTexture(LLRenderPass::PASS_SIMPLE, getVertexDataMask()); } } } + + + + + + + + + +static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_MASK("Alpha Mask"); + +LLDrawPoolAlphaMask::LLDrawPoolAlphaMask() : + LLRenderPass(POOL_ALPHA_MASK) +{ +} + +void LLDrawPoolAlphaMask::prerender() +{ + mVertexShaderLevel = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT); +} + +void LLDrawPoolAlphaMask::beginRenderPass(S32 pass) +{ + LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK); + + simple_shader = &gObjectSimpleProgram[1< 0) + { + simple_shader->bind(); + } + else + { + // don't use shaders! + if (gGLManager.mHasShaderObjects) + { + LLGLSLShader::bindNoShader(); + } + } +} + +void LLDrawPoolAlphaMask::endRenderPass(S32 pass) +{ + LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK); + stop_glerror(); + LLRenderPass::endRenderPass(pass); + stop_glerror(); + if (mVertexShaderLevel > 0) + { + simple_shader->unbind(); + } +} + +void LLDrawPoolAlphaMask::render(S32 pass) +{ + LLGLDisable blend; + LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK); + + if (mVertexShaderLevel > 0) + { + simple_shader->bind(); + simple_shader->setMinimumAlpha(0.33f); + + pushMaskBatches(LLRenderPass::PASS_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); + pushMaskBatches(LLRenderPass::PASS_MATERIAL_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); + pushMaskBatches(LLRenderPass::PASS_SPECMAP_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); + pushMaskBatches(LLRenderPass::PASS_NORMMAP_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); + pushMaskBatches(LLRenderPass::PASS_NORMSPEC_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); + } + else + { + LLGLEnable test; + pushMaskBatches(LLRenderPass::PASS_ALPHA_MASK, getVertexDataMask(), TRUE, FALSE); + gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); //OK + } +} + +LLDrawPoolFullbrightAlphaMask::LLDrawPoolFullbrightAlphaMask() : + LLRenderPass(POOL_FULLBRIGHT_ALPHA_MASK) +{ +} + +void LLDrawPoolFullbrightAlphaMask::prerender() +{ + mVertexShaderLevel = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT); +} + +void LLDrawPoolFullbrightAlphaMask::beginRenderPass(S32 pass) +{ + LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK); + + simple_shader = &gObjectFullbrightProgram[1< 0) + { + simple_shader->bind(); + } + else + { + // don't use shaders! + if (gGLManager.mHasShaderObjects) + { + LLGLSLShader::bindNoShader(); + } + } +} + +void LLDrawPoolFullbrightAlphaMask::endRenderPass(S32 pass) +{ + LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK); + stop_glerror(); + LLRenderPass::endRenderPass(pass); + stop_glerror(); + if (mVertexShaderLevel > 0) + { + simple_shader->unbind(); + } +} + +void LLDrawPoolFullbrightAlphaMask::render(S32 pass) +{ + LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK); + + if (mVertexShaderLevel > 0) + { + if (simple_shader) + { + simple_shader->bind(); + simple_shader->setMinimumAlpha(0.33f); + if (LLPipeline::sRenderingHUDs || !LLPipeline::sRenderDeferred) + { + simple_shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.0f); + } else { + simple_shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f); + } + } + pushMaskBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); + //LLGLSLShader::bindNoShader(); + } + else + { + LLGLEnable test; + LLGLState lighting; + gPipeline.enableLightsFullbright(lighting); + pushMaskBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, getVertexDataMask(), TRUE, FALSE); + gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); //OK + } +} + //=============================== //DEFERRED IMPLEMENTATION //=============================== void LLDrawPoolSimple::beginDeferredPass(S32 pass) { - LLFastTimer t(FTM_RENDER_SIMPLE_DEFERRED); + LL_RECORD_BLOCK_TIME(FTM_RENDER_SIMPLE_DEFERRED); gDeferredDiffuseProgram.bind(); } void LLDrawPoolSimple::endDeferredPass(S32 pass) { - LLFastTimer t(FTM_RENDER_SIMPLE_DEFERRED); + LL_RECORD_BLOCK_TIME(FTM_RENDER_SIMPLE_DEFERRED); LLRenderPass::endRenderPass(pass); gDeferredDiffuseProgram.unbind(); @@ -230,15 +385,37 @@ void LLDrawPoolSimple::endDeferredPass(S32 pass) void LLDrawPoolSimple::renderDeferred(S32 pass) { - LLGLDisable blend(GL_BLEND); - LLGLDisable alpha_test(GL_ALPHA_TEST); + LLGLDisable blend; + LLGLDisable alpha_test; { //render simple - LLFastTimer t(FTM_RENDER_SIMPLE_DEFERRED); + LL_RECORD_BLOCK_TIME(FTM_RENDER_SIMPLE_DEFERRED); pushBatches(LLRenderPass::PASS_SIMPLE, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); } } +static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_MASK_DEFERRED("Deferred Alpha Mask"); + +void LLDrawPoolAlphaMask::beginDeferredPass(S32 pass) +{ + +} + +void LLDrawPoolAlphaMask::endDeferredPass(S32 pass) +{ + +} + +void LLDrawPoolAlphaMask::renderDeferred(S32 pass) +{ + LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK_DEFERRED); + gDeferredDiffuseAlphaMaskProgram.bind(); + gDeferredDiffuseAlphaMaskProgram.setMinimumAlpha(0.33f); + pushMaskBatches(LLRenderPass::PASS_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); + gDeferredDiffuseAlphaMaskProgram.unbind(); +} + + // grass drawpool LLDrawPoolGrass::LLDrawPoolGrass() : LLRenderPass(POOL_GRASS) @@ -254,16 +431,12 @@ void LLDrawPoolGrass::prerender() void LLDrawPoolGrass::beginRenderPass(S32 pass) { - LLFastTimer t(FTM_RENDER_GRASS); + LL_RECORD_BLOCK_TIME(FTM_RENDER_GRASS); stop_glerror(); if (LLPipeline::sUnderWaterRender) { - simple_shader = &gObjectAlphaMaskNonIndexedWaterProgram; - } - else - { - simple_shader = &gObjectAlphaMaskNonIndexedProgram; + simple_shader = &gObjectSimpleProgram[1< 0) @@ -284,7 +457,7 @@ void LLDrawPoolGrass::beginRenderPass(S32 pass) void LLDrawPoolGrass::endRenderPass(S32 pass) { - LLFastTimer t(FTM_RENDER_GRASS); + LL_RECORD_BLOCK_TIME(FTM_RENDER_GRASS); LLRenderPass::endRenderPass(pass); if (mVertexShaderLevel > 0) @@ -299,11 +472,11 @@ void LLDrawPoolGrass::endRenderPass(S32 pass) void LLDrawPoolGrass::render(S32 pass) { - LLGLDisable blend(GL_BLEND); + LLGLDisable blend; { - LLFastTimer t(FTM_RENDER_GRASS); - LLGLEnable test(GL_ALPHA_TEST); + LL_RECORD_BLOCK_TIME(FTM_RENDER_GRASS); + LLGLEnable test; gGL.setSceneBlendType(LLRender::BT_ALPHA); //render grass LLRenderPass::renderTexture(LLRenderPass::PASS_GRASS, getVertexDataMask()); @@ -323,7 +496,7 @@ void LLDrawPoolGrass::endDeferredPass(S32 pass) void LLDrawPoolGrass::renderDeferred(S32 pass) { { - LLFastTimer t(FTM_RENDER_GRASS_DEFERRED); + LL_RECORD_BLOCK_TIME(FTM_RENDER_GRASS_DEFERRED); gDeferredNonIndexedDiffuseAlphaMaskProgram.bind(); gDeferredNonIndexedDiffuseAlphaMaskProgram.setMinimumAlpha(0.5f); //render grass @@ -345,14 +518,28 @@ void LLDrawPoolFullbright::prerender() void LLDrawPoolFullbright::beginPostDeferredPass(S32 pass) { - gDeferredFullbrightProgram.bind(); + if (LLPipeline::sUnderWaterRender) + { + //gDeferredFullbrightWaterProgram.bind(); + //Use alpha-mask version to ignore alpha values while still allowing us to occlude glow. + gDeferredFullbrightAlphaMaskWaterProgram.bind(); + gDeferredFullbrightAlphaMaskWaterProgram.setMinimumAlpha(0.f); + } + else + { + //gDeferredFullbrightProgram.bind(); + //Use alpha-mask version to ignore alpha values while still allowing us to occlude glow. + gDeferredFullbrightAlphaMaskProgram.bind(); + gDeferredFullbrightAlphaMaskProgram.setMinimumAlpha(0.f); + } + } void LLDrawPoolFullbright::renderPostDeferred(S32 pass) { - LLFastTimer t(FTM_RENDER_FULLBRIGHT); + LL_RECORD_BLOCK_TIME(FTM_RENDER_FULLBRIGHT); gGL.setColorMask(true, true); - gGL.setSceneBlendType(LLRender::BT_ALPHA); + LLGLDisable blend; U32 fullbright_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_TEXTURE_INDEX; pushBatches(LLRenderPass::PASS_FULLBRIGHT, fullbright_mask, TRUE, TRUE); @@ -362,28 +549,27 @@ void LLDrawPoolFullbright::renderPostDeferred(S32 pass) void LLDrawPoolFullbright::endPostDeferredPass(S32 pass) { - gDeferredFullbrightProgram.unbind(); - LLRenderPass::endRenderPass(pass); - -} - -void LLDrawPoolFullbright::beginRenderPass(S32 pass) -{ - LLFastTimer t(FTM_RENDER_FULLBRIGHT); - if (LLPipeline::sUnderWaterRender) { - fullbright_shader = &gObjectFullbrightWaterProgram; + gDeferredFullbrightAlphaMaskWaterProgram.unbind(); } else { - fullbright_shader = &gObjectFullbrightProgram; + gDeferredFullbrightAlphaMaskProgram.unbind(); } + LLRenderPass::endRenderPass(pass); +} + +void LLDrawPoolFullbright::beginRenderPass(S32 pass) +{ + LL_RECORD_BLOCK_TIME(FTM_RENDER_FULLBRIGHT); + + fullbright_shader = &gObjectFullbrightProgram[LLPipeline::sUnderWaterRender<bind(); fullbright_shader->uniform1f(LLViewerShaderMgr::FULLBRIGHT, 1.f); + fullbright_shader->uniform1f(LLViewerShaderMgr::TEXTURE_GAMMA, 1.f); + U32 fullbright_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_TEXTURE_INDEX; pushBatches(LLRenderPass::PASS_FULLBRIGHT, fullbright_mask, TRUE, TRUE); + pushBatches(LLRenderPass::PASS_MATERIAL_ALPHA_EMISSIVE, fullbright_mask, TRUE, TRUE); + pushBatches(LLRenderPass::PASS_SPECMAP_EMISSIVE, fullbright_mask, TRUE, TRUE); + pushBatches(LLRenderPass::PASS_NORMMAP_EMISSIVE, fullbright_mask, TRUE, TRUE); + pushBatches(LLRenderPass::PASS_NORMSPEC_EMISSIVE, fullbright_mask, TRUE, TRUE); } else { - gPipeline.enableLightsFullbright(LLColor4(1,1,1,1)); + LLGLState light_state; + gPipeline.enableLightsFullbright(light_state); U32 fullbright_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR; renderTexture(LLRenderPass::PASS_FULLBRIGHT, fullbright_mask); + pushBatches(LLRenderPass::PASS_MATERIAL_ALPHA_EMISSIVE, fullbright_mask); + pushBatches(LLRenderPass::PASS_SPECMAP_EMISSIVE, fullbright_mask); + pushBatches(LLRenderPass::PASS_NORMMAP_EMISSIVE, fullbright_mask); + pushBatches(LLRenderPass::PASS_NORMSPEC_EMISSIVE, fullbright_mask); } stop_glerror(); @@ -425,3 +622,59 @@ S32 LLDrawPoolFullbright::getNumPasses() return 1; } + +void LLDrawPoolFullbrightAlphaMask::beginPostDeferredPass(S32 pass) +{ + + if (LLPipeline::sRenderingHUDs || !LLPipeline::sRenderDeferred) + { + gObjectFullbrightProgram[1< blend; + U32 fullbright_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_TEXTURE_INDEX; + pushMaskBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, fullbright_mask, TRUE, TRUE); + gGL.setColorMask(true, false); +} + +void LLDrawPoolFullbrightAlphaMask::endPostDeferredPass(S32 pass) +{ + if (LLPipeline::sRenderingHUDs || !LLPipeline::sRenderDeferred) + { + gObjectFullbrightProgram[1<cameraUnderWater()) ? GL_FOG : 0); - - gPipeline.disableLights(); + LLGLEnable fog_enable(mVertexShaderLevel < 1 && LLViewerCamera::getInstance()->cameraUnderWater()); - LLGLDisable clip(GL_CLIP_PLANE0); + LLGLDisable clip; gGL.pushMatrix(); LLVector3 origin = LLViewerCamera::getInstance()->getOrigin(); @@ -152,7 +150,7 @@ void LLDrawPoolSky::renderSkyCubeFace(U8 side) if (LLSkyTex::doInterpolate()) { - LLGLEnable blend(GL_BLEND); + LLGLEnable blend; mSkyTex[side].bindTexture(FALSE); gGL.diffuseColor4f(1, 1, 1, LLSkyTex::getInterpVal()); // lighting is disabled face.renderIndexed(); diff --git a/indra/newview/lldrawpoolsky.h b/indra/newview/lldrawpoolsky.h index 3da493cc92..09b77f0c17 100644 --- a/indra/newview/lldrawpoolsky.h +++ b/indra/newview/lldrawpoolsky.h @@ -68,9 +68,6 @@ class LLDrawPoolSky : public LLFacePool void setSkyTex(LLSkyTex* const st) { mSkyTex = st; } void renderSkyCubeFace(U8 side); - void renderHeavenlyBody(U8 hb, LLFace* face); - void renderSunHalo(LLFace* face); - }; #endif // LL_LLDRAWPOOLSKY_H diff --git a/indra/newview/lldrawpoolterrain.cpp b/indra/newview/lldrawpoolterrain.cpp index 8465d34a77..b348bc6aea 100644 --- a/indra/newview/lldrawpoolterrain.cpp +++ b/indra/newview/lldrawpoolterrain.cpp @@ -61,33 +61,25 @@ int DebugDetailMap = 0; S32 LLDrawPoolTerrain::sDetailMode = 1; F32 LLDrawPoolTerrain::sDetailScale = DETAIL_SCALE; static LLGLSLShader* sShader = NULL; -static LLFastTimer::DeclareTimer FTM_SHADOW_TERRAIN("Terrain Shadow"); +static LLTrace::BlockTimerStatHandle FTM_SHADOW_TERRAIN("Terrain Shadow"); LLDrawPoolTerrain::LLDrawPoolTerrain(LLViewerTexture *texturep) : LLFacePool(POOL_TERRAIN), mTexturep(texturep) { - U32 format = GL_ALPHA8; - U32 int_format = GL_ALPHA; + U32 format = GL_ALPHA; + U32 int_format = GL_ALPHA8; // Hack! sDetailScale = 1.f/gSavedSettings.getF32("RenderTerrainScale"); sDetailMode = gSavedSettings.getS32("RenderTerrainDetail"); - mAlphaRampImagep = LLViewerTextureManager::getFetchedTextureFromFile("alpha_gradient.tga", - TRUE, LLGLTexture::BOOST_UI, - LLViewerTexture::FETCHED_TEXTURE, - format, int_format, - LLUUID("e97cf410-8e61-7005-ec06-629eba4cd1fb")); - - //gGL.getTexUnit(0)->bind(mAlphaRampImagep.get()); - mAlphaRampImagep->setAddressMode(LLTexUnit::TAM_CLAMP); m2DAlphaRampImagep = LLViewerTextureManager::getFetchedTextureFromFile("alpha_gradient_2d.j2c", + FTT_LOCAL_FILE, TRUE, LLGLTexture::BOOST_UI, LLViewerTexture::FETCHED_TEXTURE, - format, int_format, - LLUUID("38b86f85-2575-52a9-a531-23108d8da837")); + int_format, format); //gGL.getTexUnit(0)->bind(m2DAlphaRampImagep.get()); m2DAlphaRampImagep->setAddressMode(LLTexUnit::TAM_CLAMP); @@ -134,7 +126,7 @@ void LLDrawPoolTerrain::prerender() void LLDrawPoolTerrain::beginRenderPass( S32 pass ) { - LLFastTimer t(FTM_RENDER_TERRAIN); + LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN); LLFacePool::beginRenderPass(pass); sShader = LLPipeline::sUnderWaterRender ? @@ -149,7 +141,7 @@ void LLDrawPoolTerrain::beginRenderPass( S32 pass ) void LLDrawPoolTerrain::endRenderPass( S32 pass ) { - LLFastTimer t(FTM_RENDER_TERRAIN); + LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN); //LLFacePool::endRenderPass(pass); if (mVertexShaderLevel > 1 && sShader->mShaderLevel > 0) { @@ -165,7 +157,7 @@ S32 LLDrawPoolTerrain::getDetailMode() void LLDrawPoolTerrain::render(S32 pass) { - LLFastTimer t(FTM_RENDER_TERRAIN); + LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN); if (mDrawFace.empty()) { @@ -197,61 +189,45 @@ void LLDrawPoolTerrain::render(S32 pass) } LLGLSPipeline gls; - - if (mVertexShaderLevel > 1 && sShader->mShaderLevel > 0) - { - gPipeline.enableLightsDynamic(); - - renderFullShader(); - } - else { - gPipeline.enableLightsStatic(); + LLGLState light_state; - if (sDetailMode == 0) + if (mVertexShaderLevel > 1 && sShader->mShaderLevel > 0) { - renderSimple(); - } - else if (gGLManager.mNumTextureUnits < 4) - { - renderFull2TU(); - gGL.setSceneBlendType(LLRender::BT_ALPHA); - } - else + gPipeline.enableLightsDynamic(light_state); + + renderFullShader(); + } + else { - renderFull4TU(); - gGL.setSceneBlendType(LLRender::BT_ALPHA); + gPipeline.enableLightsStatic(light_state); + + if (sDetailMode == 0) + { + renderSimple(); + } + else if (gGLManager.mNumTextureUnits < 4) + { + renderFull2TU(); + gGL.setSceneBlendType(LLRender::BT_ALPHA); + } + else + { + renderFull4TU(); + gGL.setSceneBlendType(LLRender::BT_ALPHA); + } } } // Special-case for land ownership feedback - static const LLCachedControl show_parcel_owners("ShowParcelOwners",false); - if (show_parcel_owners) { - if (mVertexShaderLevel > 1) - { //use fullbright shader for highlighting - LLGLSLShader* old_shader = sShader; - sShader->unbind(); - sShader = &gHighlightProgram; - sShader->bind(); - gGL.diffuseColor4f(1,1,1,1); - LLGLEnable polyOffset(GL_POLYGON_OFFSET_FILL); - glPolygonOffset(-1.0f, -1.0f); - renderOwnership(); - sShader = old_shader; - sShader->bind(); - } - else - { - gPipeline.disableLights(); - renderOwnership(); - } + hilightParcelOwners(); } } void LLDrawPoolTerrain::beginDeferredPass(S32 pass) { - LLFastTimer t(FTM_RENDER_TERRAIN); + LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN); LLFacePool::beginRenderPass(pass); sShader = &gDeferredTerrainProgram; @@ -261,24 +237,31 @@ void LLDrawPoolTerrain::beginDeferredPass(S32 pass) void LLDrawPoolTerrain::endDeferredPass(S32 pass) { - LLFastTimer t(FTM_RENDER_TERRAIN); + LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN); LLFacePool::endRenderPass(pass); sShader->unbind(); } void LLDrawPoolTerrain::renderDeferred(S32 pass) { - LLFastTimer t(FTM_RENDER_TERRAIN); + LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN); if (mDrawFace.empty()) { return; } + renderFullShader(); + + // Special-case for land ownership feedback + { + hilightParcelOwners(); + } + } void LLDrawPoolTerrain::beginShadowPass(S32 pass) { - LLFastTimer t(FTM_SHADOW_TERRAIN); + LL_RECORD_BLOCK_TIME(FTM_SHADOW_TERRAIN); LLFacePool::beginRenderPass(pass); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); gDeferredShadowProgram.bind(); @@ -286,14 +269,14 @@ void LLDrawPoolTerrain::beginShadowPass(S32 pass) void LLDrawPoolTerrain::endShadowPass(S32 pass) { - LLFastTimer t(FTM_SHADOW_TERRAIN); + LL_RECORD_BLOCK_TIME(FTM_SHADOW_TERRAIN); LLFacePool::endRenderPass(pass); gDeferredShadowProgram.unbind(); } void LLDrawPoolTerrain::renderShadow(S32 pass) { - LLFastTimer t(FTM_SHADOW_TERRAIN); + LL_RECORD_BLOCK_TIME(FTM_SHADOW_TERRAIN); if (mDrawFace.empty()) { return; @@ -314,8 +297,11 @@ void LLDrawPoolTerrain::drawLoop() { LLFace *facep = *iter; - LLMatrix4* model_matrix = &(facep->getDrawable()->getRegion()->mRenderMatrix); - + LLMatrix4a* model_matrix = &(facep->getDrawable()->getRegion()->mRenderMatrix); + if(model_matrix && model_matrix->isIdentity()) + { + model_matrix = NULL; + } if (model_matrix != gGLLastMatrix) { llassert(gGL.getMatrixMode() == LLRender::MM_MODELVIEW); @@ -323,7 +309,7 @@ void LLDrawPoolTerrain::drawLoop() gGL.loadMatrix(gGLModelView); if (model_matrix) { - gGL.multMatrix((GLfloat*) model_matrix->mMatrix); + gGL.multMatrix(*model_matrix); } gPipeline.mMatrixOpCount++; } @@ -362,8 +348,8 @@ void LLDrawPoolTerrain::renderFullShader() LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; llassert(shader); - shader->uniform4fv("object_plane_s", 1, tp0.mV); - shader->uniform4fv("object_plane_t", 1, tp1.mV); + shader->uniform4fv(LLShaderMgr::OBJECT_PLANE_S, 1, tp0.mV); + shader->uniform4fv(LLShaderMgr::OBJECT_PLANE_T, 1, tp1.mV); gGL.matrixMode(LLRender::MM_TEXTURE); gGL.loadIdentity(); @@ -462,6 +448,29 @@ void LLDrawPoolTerrain::renderFullShader() gGL.matrixMode(LLRender::MM_MODELVIEW); } +void LLDrawPoolTerrain::hilightParcelOwners() +{ + static const LLCachedControl show_parcel_owners("ShowParcelOwners",false); + if (!show_parcel_owners) return; + if (mVertexShaderLevel > 1) + { //use fullbright shader for highlighting + LLGLSLShader* old_shader = sShader; + sShader->unbind(); + sShader = &gHighlightProgram; + sShader->bind(); + gGL.diffuseColor4f(1,1,1,1); + LLGLEnable polyOffset; + gGL.setPolygonOffset(-1.0f, -1.0f); + renderOwnership(); + sShader = old_shader; + sShader->bind(); + } + else + { + renderOwnership(); + } +} + void LLDrawPoolTerrain::renderFull4TU() { // Hack! Get the region that this draw pool is rendering from! @@ -605,7 +614,6 @@ void LLDrawPoolTerrain::renderFull4TU() gGL.matrixMode(LLRender::MM_TEXTURE); gGL.loadIdentity(); gGL.translatef(-1.f, 0.f, 0.f); - gGL.matrixMode(LLRender::MM_MODELVIEW); // Set alpha texture and do lighting modulation @@ -614,7 +622,7 @@ void LLDrawPoolTerrain::renderFull4TU() gGL.getTexUnit(0)->activate(); { - LLGLEnable blend(GL_BLEND); + LLGLEnable blend; drawLoop(); } @@ -740,7 +748,7 @@ void LLDrawPoolTerrain::renderFull2TU() gGL.getTexUnit(0)->activate(); { - LLGLEnable blend(GL_BLEND); + LLGLEnable blend; drawLoop(); } //---------------------------------------------------------------------------- @@ -779,7 +787,7 @@ void LLDrawPoolTerrain::renderFull2TU() gGL.getTexUnit(1)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_ALPHA); { - LLGLEnable blend(GL_BLEND); + LLGLEnable blend; drawLoop(); } @@ -818,7 +826,7 @@ void LLDrawPoolTerrain::renderFull2TU() gGL.getTexUnit(0)->activate(); { - LLGLEnable blend(GL_BLEND); + LLGLEnable blend; drawLoop(); } @@ -873,8 +881,8 @@ void LLDrawPoolTerrain::renderSimple() if (LLGLSLShader::sNoFixedFunction) { - sShader->uniform4fv("object_plane_s", 1, tp0.mV); - sShader->uniform4fv("object_plane_t", 1, tp1.mV); + sShader->uniform4fv(LLShaderMgr::OBJECT_PLANE_S, 1, tp0.mV); + sShader->uniform4fv(LLShaderMgr::OBJECT_PLANE_T, 1, tp1.mV); } else { diff --git a/indra/newview/lldrawpoolterrain.h b/indra/newview/lldrawpoolterrain.h index a9fb48bac6..08ab122769 100644 --- a/indra/newview/lldrawpoolterrain.h +++ b/indra/newview/lldrawpoolterrain.h @@ -76,12 +76,11 @@ class LLDrawPoolTerrain : public LLFacePool /*virtual*/ LLViewerTexture *getDebugTexture(); /*virtual*/ LLColor3 getDebugColor() const; // For AGP debug display - LLPointer mAlphaRampImagep; LLPointer m2DAlphaRampImagep; - LLPointer mAlphaNoiseImagep; static S32 sDetailMode; static F32 sDetailScale; // meters per texture + protected: void renderSimple(); void renderOwnership(); @@ -90,6 +89,9 @@ class LLDrawPoolTerrain : public LLFacePool void renderFull4TU(); void renderFullShader(); void drawLoop(); + +private: + void hilightParcelOwners(); }; #endif // LL_LLDRAWPOOLSIMPLE_H diff --git a/indra/newview/lldrawpooltree.cpp b/indra/newview/lldrawpooltree.cpp index d2faca8357..c02c55d683 100644 --- a/indra/newview/lldrawpooltree.cpp +++ b/indra/newview/lldrawpooltree.cpp @@ -47,7 +47,7 @@ S32 LLDrawPoolTree::sDiffTex = 0; static LLGLSLShader* shader = NULL; -static LLFastTimer::DeclareTimer FTM_SHADOW_TREE("Tree Shadow"); +static LLTrace::BlockTimerStatHandle FTM_SHADOW_TREE("Tree Shadow"); LLDrawPoolTree::LLDrawPoolTree(LLViewerTexture *texturep) : LLFacePool(POOL_TREE), @@ -68,7 +68,7 @@ void LLDrawPoolTree::prerender() void LLDrawPoolTree::beginRenderPass(S32 pass) { - LLFastTimer t(FTM_RENDER_TREES); + LL_RECORD_BLOCK_TIME(FTM_RENDER_TREES); if (LLPipeline::sUnderWaterRender) { @@ -79,7 +79,7 @@ void LLDrawPoolTree::beginRenderPass(S32 pass) shader = &gTreeProgram; } - if (gPipeline.canUseVertexShaders()) + if (LLGLSLShader::sNoFixedFunction) { shader->bind(); shader->setMinimumAlpha(0.5f); @@ -87,41 +87,67 @@ void LLDrawPoolTree::beginRenderPass(S32 pass) } else { - gPipeline.enableLightsDynamic(); gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f); } } void LLDrawPoolTree::render(S32 pass) { - LLFastTimer t(LLPipeline::sShadowRender ? FTM_SHADOW_TREE : FTM_RENDER_TREES); + LL_RECORD_BLOCK_TIME(LLPipeline::sShadowRender ? FTM_SHADOW_TREE : FTM_RENDER_TREES); if (mDrawFace.empty()) { return; } - LLGLState test(GL_ALPHA_TEST, LLGLSLShader::sNoFixedFunction ? 0 : 1); - LLOverrideFaceColor color(this, 1.f, 1.f, 1.f, 1.f); - - /*static const LLCachedControl render_animate_trees("RenderAnimateTrees",false); - if (render_animate_trees) + LLGLState test(LLGLSLShader::sNoFixedFunction ? 0 : 1); + LLGLState light_state; + if (!LLGLSLShader::sNoFixedFunction) { - renderTree(); + gPipeline.enableLightsDynamic(light_state); } - else*/ + LLOverrideFaceColor color(this, 1.f, 1.f, 1.f, 1.f); + gGL.getTexUnit(sDiffTex)->bind(mTexturep); - + for (std::vector::iterator iter = mDrawFace.begin(); iter != mDrawFace.end(); iter++) { LLFace *face = *iter; + if(face->getViewerObject()) + { + LLVOTree* pTree = dynamic_cast(face->getViewerObject()); + if(pTree && !pTree->mDrawList.empty() ) + { + LLMatrix4a* model_matrix = &(face->getDrawable()->getRegion()->mRenderMatrix); + + gGL.loadMatrix(gGLModelView); + gGL.multMatrix(*model_matrix); + gPipeline.mMatrixOpCount++; + + for(std::vector >::iterator iter2 = pTree->mDrawList.begin(); + iter2 != pTree->mDrawList.end(); iter2++) + { + LLDrawInfo& params = *iter2->get(); + gGL.pushMatrix(); + gGL.multMatrix(*params.mModelMatrix); + gPipeline.mMatrixOpCount++; + params.mVertexBuffer->setBuffer(LLDrawPoolTree::VERTEX_DATA_MASK); + params.mVertexBuffer->drawRange(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset); + gGL.popMatrix(); + } + continue; + } + } LLVertexBuffer* buff = face->getVertexBuffer(); if(buff) { - LLMatrix4* model_matrix = &(face->getDrawable()->getRegion()->mRenderMatrix); - + LLMatrix4a* model_matrix = &(face->getDrawable()->getRegion()->mRenderMatrix); + if(model_matrix && model_matrix->isIdentity()) + { + model_matrix = NULL; + } if (model_matrix != gGLLastMatrix) { gGLLastMatrix = model_matrix; @@ -129,7 +155,7 @@ void LLDrawPoolTree::render(S32 pass) if (model_matrix) { llassert(gGL.getMatrixMode() == LLRender::MM_MODELVIEW); - gGL.multMatrix((GLfloat*) model_matrix->mMatrix); + gGL.multMatrix(*model_matrix); } gPipeline.mMatrixOpCount++; } @@ -143,7 +169,7 @@ void LLDrawPoolTree::render(S32 pass) void LLDrawPoolTree::endRenderPass(S32 pass) { - LLFastTimer t(FTM_RENDER_TREES); + LL_RECORD_BLOCK_TIME(FTM_RENDER_TREES); if (gPipeline.canUseWindLightShadersOnObjects()) { @@ -161,7 +187,7 @@ void LLDrawPoolTree::endRenderPass(S32 pass) //============================================ void LLDrawPoolTree::beginDeferredPass(S32 pass) { - LLFastTimer t(FTM_RENDER_TREES); + LL_RECORD_BLOCK_TIME(FTM_RENDER_TREES); shader = &gDeferredTreeProgram; shader->bind(); @@ -175,7 +201,7 @@ void LLDrawPoolTree::renderDeferred(S32 pass) void LLDrawPoolTree::endDeferredPass(S32 pass) { - LLFastTimer t(FTM_RENDER_TREES); + LL_RECORD_BLOCK_TIME(FTM_RENDER_TREES); shader->unbind(); } @@ -185,11 +211,11 @@ void LLDrawPoolTree::endDeferredPass(S32 pass) //============================================ void LLDrawPoolTree::beginShadowPass(S32 pass) { - LLFastTimer t(FTM_SHADOW_TREE); + LL_RECORD_BLOCK_TIME(FTM_SHADOW_TREE); static const LLCachedControl render_deferred_offset("RenderDeferredTreeShadowOffset",1.f); static const LLCachedControl render_deferred_bias("RenderDeferredTreeShadowBias",1.f); - glPolygonOffset(render_deferred_offset,render_deferred_bias); + gGL.setPolygonOffset(render_deferred_offset,render_deferred_bias); gDeferredTreeShadowProgram.bind(); gDeferredTreeShadowProgram.setMinimumAlpha(0.5f); } @@ -201,138 +227,14 @@ void LLDrawPoolTree::renderShadow(S32 pass) void LLDrawPoolTree::endShadowPass(S32 pass) { - LLFastTimer t(FTM_SHADOW_TREE); + LL_RECORD_BLOCK_TIME(FTM_SHADOW_TREE); static const LLCachedControl render_deferred_offset("RenderDeferredSpotShadowOffset",1.f); static const LLCachedControl render_deferred_bias("RenderDeferredSpotShadowBias",1.f); - glPolygonOffset(render_deferred_offset,render_deferred_bias); + gGL.setPolygonOffset(render_deferred_offset,render_deferred_bias); gDeferredTreeShadowProgram.unbind(); } -/* -void LLDrawPoolTree::renderTree(BOOL selecting) -{ - LLGLState normalize(GL_NORMALIZE, TRUE); - - // Bind the texture for this tree. - gGL.getTexUnit(sDiffTex)->bind(mTexturep.get(), TRUE); - - U32 indices_drawn = 0; - - gGL.matrixMode(LLRender::MM_MODELVIEW); - - for (std::vector::iterator iter = mDrawFace.begin(); - iter != mDrawFace.end(); iter++) - { - LLFace *face = *iter; - LLDrawable *drawablep = face->getDrawable(); - - if (drawablep->isDead() || !face->getVertexBuffer()) - { - continue; - } - - face->getVertexBuffer()->setBuffer(LLDrawPoolTree::VERTEX_DATA_MASK); - U16* indicesp = (U16*) face->getVertexBuffer()->getIndicesPointer(); - - // Render each of the trees - LLVOTree *treep = (LLVOTree *)drawablep->getVObj().get(); - - LLColor4U color(255,255,255,255); - - if (!selecting || treep->mGLName != 0) - { - if (selecting) - { - S32 name = treep->mGLName; - - color = LLColor4U((U8)(name >> 16), (U8)(name >> 8), (U8)name, 255); - } - - gGLLastMatrix = NULL; - gGL.loadMatrix(gGLModelView); - //gGL.pushMatrix(); - - LLMatrix4 matrix(gGLModelView); - - // Translate to tree base HACK - adjustment in Z plants tree underground - const LLVector3 &pos_agent = treep->getPositionAgent(); - //gGL.translatef(pos_agent.mV[VX], pos_agent.mV[VY], pos_agent.mV[VZ] - 0.1f); - LLMatrix4 trans_mat; - trans_mat.setTranslation(pos_agent.mV[VX], pos_agent.mV[VY], pos_agent.mV[VZ] - 0.1f); - trans_mat *= matrix; - - // Rotate to tree position and bend for current trunk/wind - // Note that trunk stiffness controls the amount of bend at the trunk as - // opposed to the crown of the tree - // - const F32 TRUNK_STIFF = 22.f; - - LLQuaternion rot = - LLQuaternion(treep->mTrunkBend.magVec()*TRUNK_STIFF*DEG_TO_RAD, LLVector4(treep->mTrunkBend.mV[VX], treep->mTrunkBend.mV[VY], 0)) * - LLQuaternion(90.f*DEG_TO_RAD, LLVector4(0,0,1)) * - treep->getRotation(); - - LLMatrix4 rot_mat(rot); - rot_mat *= trans_mat; - - F32 radius = treep->getScale().magVec()*0.05f; - LLMatrix4 scale_mat; - scale_mat.mMatrix[0][0] = - scale_mat.mMatrix[1][1] = - scale_mat.mMatrix[2][2] = radius; - - scale_mat *= rot_mat; - - //TO-DO: Make these set-able? - const F32 THRESH_ANGLE_FOR_BILLBOARD = 7.5f; //Made LoD now a little less aggressive here -Shyotl - const F32 BLEND_RANGE_FOR_BILLBOARD = 1.5f; - - F32 droop = treep->mDroop + 25.f*(1.f - treep->mTrunkBend.magVec()); - - S32 stop_depth = 0; - F32 app_angle = treep->getAppAngle()*LLVOTree::sTreeFactor; - F32 alpha = 1.0; - S32 trunk_LOD = LLVOTree::sMAX_NUM_TREE_LOD_LEVELS; - - for (S32 j = 0; j < 4; j++) - { - - if (app_angle > LLVOTree::sLODAngles[j]) - { - trunk_LOD = j; - break; - } - } - if(trunk_LOD >= LLVOTree::sMAX_NUM_TREE_LOD_LEVELS) - { - continue ; //do not render. - } - - if (app_angle < (THRESH_ANGLE_FOR_BILLBOARD - BLEND_RANGE_FOR_BILLBOARD)) - { - // - // Draw only the billboard - // - // Only the billboard, can use closer to normal alpha func. - stop_depth = -1; - LLFacePool::LLOverrideFaceColor clr(this, color); - indices_drawn += treep->drawBranchPipeline(scale_mat, indicesp, trunk_LOD, stop_depth, treep->mDepth, treep->mTrunkDepth, 1.0, treep->mTwist, droop, treep->mBranches, alpha); - } - else // if (app_angle > (THRESH_ANGLE_FOR_BILLBOARD + BLEND_RANGE_FOR_BILLBOARD)) - { - // - // Draw only the full geometry tree - // - LLFacePool::LLOverrideFaceColor clr(this, color); - indices_drawn += treep->drawBranchPipeline(scale_mat, indicesp, trunk_LOD, stop_depth, treep->mDepth, treep->mTrunkDepth, 1.0, treep->mTwist, droop, treep->mBranches, alpha); - } - - //gGL.popMatrix(); - } - } -}*/ - BOOL LLDrawPoolTree::verify() const { /* BOOL ok = TRUE; diff --git a/indra/newview/lldrawpooltree.h b/indra/newview/lldrawpooltree.h index 5c63e8f4e3..714dc25e17 100644 --- a/indra/newview/lldrawpooltree.h +++ b/indra/newview/lldrawpooltree.h @@ -75,8 +75,8 @@ class LLDrawPoolTree : public LLFacePool static S32 sDiffTex; -//private: - //void renderTree(BOOL selecting = FALSE); +private: + void renderTree(BOOL selecting = FALSE); }; #endif // LL_LLDRAWPOOLTREE_H diff --git a/indra/newview/lldrawpoolwater.cpp b/indra/newview/lldrawpoolwater.cpp index 91fbf7cbee..1928794f23 100644 --- a/indra/newview/lldrawpoolwater.cpp +++ b/indra/newview/lldrawpoolwater.cpp @@ -63,7 +63,6 @@ static float sTime; BOOL deferred_render = FALSE; -BOOL LLDrawPoolWater::sSkipScreenCopy = FALSE; BOOL LLDrawPoolWater::sNeedsReflectionUpdate = TRUE; BOOL LLDrawPoolWater::sNeedsDistortionUpdate = TRUE; LLColor4 LLDrawPoolWater::sWaterFogColor = LLColor4(0.2f, 0.5f, 0.5f, 0.f); @@ -74,11 +73,11 @@ LLVector3 LLDrawPoolWater::sLightDir; LLDrawPoolWater::LLDrawPoolWater() : LLFacePool(POOL_WATER) { - mHBTex[0] = LLViewerTextureManager::getFetchedTexture(gSunTextureID, TRUE, LLGLTexture::BOOST_UI); + mHBTex[0] = LLViewerTextureManager::getFetchedTexture(gSunTextureID, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_UI); gGL.getTexUnit(0)->bind(mHBTex[0]) ; mHBTex[0]->setAddressMode(LLTexUnit::TAM_CLAMP); - mHBTex[1] = LLViewerTextureManager::getFetchedTexture(gMoonTextureID, TRUE, LLGLTexture::BOOST_UI); + mHBTex[1] = LLViewerTextureManager::getFetchedTexture(gMoonTextureID, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_UI); gGL.getTexUnit(0)->bind(mHBTex[1]); mHBTex[1]->setAddressMode(LLTexUnit::TAM_CLAMP); @@ -106,7 +105,7 @@ void LLDrawPoolWater::restoreGL() LLDrawPool *LLDrawPoolWater::instancePool() { - llerrs << "Should never be calling instancePool on a water pool!" << llendl; + LL_ERRS() << "Should never be calling instancePool on a water pool!" << LL_ENDL; return NULL; } @@ -150,7 +149,7 @@ void LLDrawPoolWater::endPostDeferredPass(S32 pass) //=============================== void LLDrawPoolWater::renderDeferred(S32 pass) { - LLFastTimer t(FTM_RENDER_WATER); + LL_RECORD_BLOCK_TIME(FTM_RENDER_WATER); deferred_render = TRUE; shade(); deferred_render = FALSE; @@ -160,7 +159,7 @@ void LLDrawPoolWater::renderDeferred(S32 pass) void LLDrawPoolWater::render(S32 pass) { - LLFastTimer ftm(FTM_RENDER_WATER); + LL_RECORD_BLOCK_TIME(FTM_RENDER_WATER); if (mDrawFace.empty() || LLDrawable::getCurrentFrame() <= 1) { return; @@ -183,9 +182,9 @@ void LLDrawPoolWater::render(S32 pass) return; } - LLGLEnable blend(GL_BLEND); + LLGLEnable blend; - if ((mVertexShaderLevel > 0) && !sSkipScreenCopy) + if (mVertexShaderLevel > 0) { shade(); return; @@ -203,11 +202,12 @@ void LLDrawPoolWater::render(S32 pass) LLFace* refl_face = voskyp->getReflFace(); - gPipeline.disableLights(); + LLGLState light_state; + gPipeline.disableLights(light_state); LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE); - LLGLDisable cullFace(GL_CULL_FACE); + LLGLDisable cullFace; // Set up second pass first mWaterImagep->addTextureStats(1024.f*1024.f); @@ -253,7 +253,8 @@ void LLDrawPoolWater::render(S32 pass) glClearStencil(1); glClear(GL_STENCIL_BUFFER_BIT); - LLGLEnable gls_stencil(GL_STENCIL_TEST); + glClearStencil(0); + LLGLEnable gls_stencil; glStencilOp(GL_KEEP, GL_REPLACE, GL_KEEP); glStencilFunc(GL_ALWAYS, 0, 0xFFFFFFFF); @@ -292,11 +293,10 @@ void LLDrawPoolWater::render(S32 pass) gGL.matrixMode(LLRender::MM_TEXTURE); gGL.loadIdentity(); - LLMatrix4 camera_mat = LLViewerCamera::getInstance()->getModelview(); - LLMatrix4 camera_rot(camera_mat.getMat3()); + LLMatrix4a camera_rot = LLViewerCamera::getInstance()->getModelview(); + camera_rot.extractRotation_affine(); camera_rot.invert(); - - gGL.loadMatrix((F32 *)camera_rot.mMatrix); + gGL.loadMatrix(camera_rot); gGL.matrixMode(LLRender::MM_MODELVIEW); LLOverrideFaceColor overrid(this, 1.f, 1.f, 1.f, 0.5f*up_dot); @@ -370,10 +370,10 @@ void LLDrawPoolWater::renderOpaqueLegacyWater() // of no transparency. And no face culling so // that the underside of the water is also opaque. LLGLDepthTest gls_depth(GL_TRUE, GL_TRUE); - LLGLDisable no_cull(GL_CULL_FACE); - LLGLDisable no_blend(GL_BLEND); - - gPipeline.disableLights(); + LLGLDisable no_cull; + LLGLDisable no_blend; + LLGLState light_state; + gPipeline.disableLights(light_state); //Singu note: This is a hack around bizarre opensim behavior. The opaque water texture we get is pure white and only has one channel. // This behavior is clearly incorrect, so we try to detect that case, purge it from the cache, and try to re-fetch the texture. @@ -449,8 +449,8 @@ void LLDrawPoolWater::renderOpaqueLegacyWater() } else { - shader->uniform4fv("object_plane_s", 1, tp0); - shader->uniform4fv("object_plane_t", 1, tp1); + shader->uniform4fv(LLShaderMgr::OBJECT_PLANE_S, 1, tp0); + shader->uniform4fv(LLShaderMgr::OBJECT_PLANE_T, 1, tp1); } gGL.diffuseColor3f(1.f, 1.f, 1.f); @@ -523,7 +523,7 @@ void LLDrawPoolWater::shade() return; } - LLGLDisable blend(GL_BLEND); + LLGLDisable blend; LLColor3 light_diffuse(0,0,0); F32 light_exp = 0.0f; @@ -564,14 +564,21 @@ void LLDrawPoolWater::shade() F32 eyedepth = LLViewerCamera::getInstance()->getOrigin().mV[2] - gAgent.getRegion()->getWaterHeight(); + if (eyedepth < 0.f && LLPipeline::sWaterReflections) + { if (deferred_render) { - shader = &gDeferredWaterProgram; + shader = &gDeferredUnderWaterProgram; } - else if (eyedepth < 0.f && LLPipeline::sWaterReflections) + else { shader = &gUnderWaterProgram; } + } + else if (deferred_render) + { + shader = &gDeferredWaterProgram; + } else { shader = &gWaterProgram; @@ -592,7 +599,7 @@ void LLDrawPoolWater::shade() sTime = (F32)LLFrameTimer::getElapsedSeconds()*0.5f; } - S32 reftex = shader->enableTexture(LLViewerShaderMgr::WATER_REFTEX); + S32 reftex = shader->enableTexture(LLShaderMgr::WATER_REFTEX); if (reftex > -1) { @@ -624,12 +631,12 @@ void LLDrawPoolWater::shade() mWaterNormp->setFilteringOption(LLTexUnit::TFO_POINT); } - S32 screentex = shader->enableTexture(LLViewerShaderMgr::WATER_SCREENTEX); + S32 screentex = shader->enableTexture(LLShaderMgr::WATER_SCREENTEX); if (screentex > -1) { - shader->uniform4fv(LLViewerShaderMgr::WATER_FOGCOLOR, 1, sWaterFogColor.mV); - shader->uniform1f(LLViewerShaderMgr::WATER_FOGDENSITY, + shader->uniform4fv(LLShaderMgr::WATER_FOGCOLOR, 1, sWaterFogColor.mV); + shader->uniform1f(LLShaderMgr::WATER_FOGDENSITY, param_mgr->getFogDensity()); gPipeline.mWaterDis.bindTexture(0, screentex); } @@ -641,18 +648,10 @@ void LLDrawPoolWater::shade() if (mVertexShaderLevel == 1) { sWaterFogColor.mV[3] = param_mgr->mDensitySliderValue; - shader->uniform4fv(LLViewerShaderMgr::WATER_FOGCOLOR, 1, sWaterFogColor.mV); + shader->uniform4fv(LLShaderMgr::WATER_FOGCOLOR, 1, sWaterFogColor.mV); } - - F32 screenRes[] = - { - 1.f/gGLViewport[2], - 1.f/gGLViewport[3] - }; - shader->uniform2fv("screenRes", 1, screenRes); - stop_glerror(); - S32 diffTex = shader->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); + S32 diffTex = shader->enableTexture(LLShaderMgr::DIFFUSE_MAP); stop_glerror(); light_dir.normVec(); @@ -661,26 +660,26 @@ void LLDrawPoolWater::shade() light_diffuse *= 6.f; //shader->uniformMatrix4fv("inverse_ref", 1, GL_FALSE, (GLfloat*) gGLObliqueProjectionInverse.mMatrix); - shader->uniform1f(LLViewerShaderMgr::WATER_WATERHEIGHT, eyedepth); - shader->uniform1f(LLViewerShaderMgr::WATER_TIME, sTime); - shader->uniform3fv(LLViewerShaderMgr::WATER_EYEVEC, 1, LLViewerCamera::getInstance()->getOrigin().mV); - shader->uniform3fv(LLViewerShaderMgr::WATER_SPECULAR, 1, light_diffuse.mV); - shader->uniform1f(LLViewerShaderMgr::WATER_SPECULAR_EXP, light_exp); - shader->uniform2fv(LLViewerShaderMgr::WATER_WAVE_DIR1, 1, param_mgr->getWave1Dir().mV); - shader->uniform2fv(LLViewerShaderMgr::WATER_WAVE_DIR2, 1, param_mgr->getWave2Dir().mV); - shader->uniform3fv(LLViewerShaderMgr::WATER_LIGHT_DIR, 1, light_dir.mV); - - shader->uniform3fv("normScale", 1, param_mgr->getNormalScale().mV); - shader->uniform1f("fresnelScale", param_mgr->getFresnelScale()); - shader->uniform1f("fresnelOffset", param_mgr->getFresnelOffset()); - shader->uniform1f("blurMultiplier", param_mgr->getBlurMultiplier()); + shader->uniform1f(LLShaderMgr::WATER_WATERHEIGHT, eyedepth); + shader->uniform1f(LLShaderMgr::WATER_TIME, sTime); + shader->uniform3fv(LLShaderMgr::WATER_EYEVEC, 1, LLViewerCamera::getInstance()->getOrigin().mV); + shader->uniform3fv(LLShaderMgr::WATER_SPECULAR, 1, light_diffuse.mV); + shader->uniform1f(LLShaderMgr::WATER_SPECULAR_EXP, light_exp); + shader->uniform2fv(LLShaderMgr::WATER_WAVE_DIR1, 1, param_mgr->getWave1Dir().mV); + shader->uniform2fv(LLShaderMgr::WATER_WAVE_DIR2, 1, param_mgr->getWave2Dir().mV); + shader->uniform3fv(LLShaderMgr::WATER_LIGHT_DIR, 1, light_dir.mV); + + shader->uniform3fv(LLShaderMgr::WATER_NORM_SCALE, 1, param_mgr->getNormalScale().mV); + shader->uniform1f(LLShaderMgr::WATER_FRESNEL_SCALE, param_mgr->getFresnelScale()); + shader->uniform1f(LLShaderMgr::WATER_FRESNEL_OFFSET, param_mgr->getFresnelOffset()); + shader->uniform1f(LLShaderMgr::WATER_BLUR_MULTIPLIER, param_mgr->getBlurMultiplier()); F32 sunAngle = llmax(0.f, light_dir.mV[2]); F32 scaledAngle = 1.f - sunAngle; - shader->uniform1f("sunAngle", sunAngle); - shader->uniform1f("scaledAngle", scaledAngle); - shader->uniform1f("sunAngle2", 0.1f + 0.2f*sunAngle); + shader->uniform1f(LLShaderMgr::WATER_SUN_ANGLE, sunAngle); + shader->uniform1f(LLShaderMgr::WATER_SCALED_ANGLE, scaledAngle); + shader->uniform1f(LLShaderMgr::WATER_SUN_ANGLE2, 0.1f + 0.2f*sunAngle); LLColor4 water_color; LLVector3 camera_up = LLViewerCamera::getInstance()->getUpAxis(); @@ -688,12 +687,12 @@ void LLDrawPoolWater::shade() if (LLViewerCamera::getInstance()->cameraUnderWater()) { water_color.setVec(1.f, 1.f, 1.f, 0.4f); - shader->uniform1f(LLViewerShaderMgr::WATER_REFSCALE, param_mgr->getScaleBelow()); + shader->uniform1f(LLShaderMgr::WATER_REFSCALE, param_mgr->getScaleBelow()); } else { water_color.setVec(1.f, 1.f, 1.f, 0.5f*(1.f + up_dot)); - shader->uniform1f(LLViewerShaderMgr::WATER_REFSCALE, param_mgr->getScaleAbove()); + shader->uniform1f(LLShaderMgr::WATER_REFSCALE, param_mgr->getScaleAbove()); } if (water_color.mV[3] > 0.9f) @@ -702,8 +701,8 @@ void LLDrawPoolWater::shade() } { - LLGLEnable depth_clamp(gGLManager.mHasDepthClamp ? GL_DEPTH_CLAMP : 0); - LLGLDisable cullface(GL_CULL_FACE); + LLGLEnable depth_clamp(gGLManager.mHasDepthClamp); + LLGLDisable cullface; for (std::vector::iterator iter = mDrawFace.begin(); iter != mDrawFace.end(); iter++) { @@ -719,7 +718,7 @@ void LLDrawPoolWater::shade() gGL.getTexUnit(diffTex)->bind(face->getTexture()); sNeedsReflectionUpdate = TRUE; - + if (water->getUseTexture() || !water->getIsEdgePatch()) { sNeedsDistortionUpdate = TRUE; @@ -739,12 +738,12 @@ void LLDrawPoolWater::shade() } } - shader->disableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP); - shader->disableTexture(LLViewerShaderMgr::WATER_SCREENTEX); - shader->disableTexture(LLViewerShaderMgr::BUMP_MAP); - shader->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP); - shader->disableTexture(LLViewerShaderMgr::WATER_REFTEX); - shader->disableTexture(LLViewerShaderMgr::WATER_SCREENDEPTH); + shader->disableTexture(LLShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP); + shader->disableTexture(LLShaderMgr::WATER_SCREENTEX); + shader->disableTexture(LLShaderMgr::BUMP_MAP); + shader->disableTexture(LLShaderMgr::DIFFUSE_MAP); + shader->disableTexture(LLShaderMgr::WATER_REFTEX); + shader->disableTexture(LLShaderMgr::WATER_SCREENDEPTH); if (deferred_render) { diff --git a/indra/newview/lldrawpoolwater.h b/indra/newview/lldrawpoolwater.h index 4d12605f5b..1e93c27521 100644 --- a/indra/newview/lldrawpoolwater.h +++ b/indra/newview/lldrawpoolwater.h @@ -49,7 +49,6 @@ class LLDrawPoolWater: public LLFacePool LLPointer mWaterNormp; public: - static BOOL sSkipScreenCopy; static BOOL sNeedsReflectionUpdate; static BOOL sNeedsDistortionUpdate; static LLVector3 sLightDir; diff --git a/indra/newview/lldrawpoolwlsky.cpp b/indra/newview/lldrawpoolwlsky.cpp index 104f6cac1c..6257187dca 100644 --- a/indra/newview/lldrawpoolwlsky.cpp +++ b/indra/newview/lldrawpoolwlsky.cpp @@ -47,6 +47,7 @@ #include "llviewerregion.h" #include "llface.h" #include "llrender.h" +#include "llviewercontrol.h" LLPointer LLDrawPoolWLSky::sCloudNoiseTexture = NULL; @@ -59,13 +60,17 @@ static LLGLSLShader* star_shader = NULL; LLDrawPoolWLSky::LLDrawPoolWLSky(void) : LLDrawPool(POOL_WL_SKY) { - const std::string cloudNoiseFilename(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight", "clouds2.tga")); - llinfos << "loading WindLight cloud noise from " << cloudNoiseFilename << llendl; + std::string cloudNoiseFilename(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight/clouds", gSavedSettings.getString("AlchemyWLCloudTexture"))); + if (!gDirUtilp->fileExists(cloudNoiseFilename)) + { + cloudNoiseFilename = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight/clouds", "Default.tga"); + } + LL_INFOS() << "loading WindLight cloud noise from " << cloudNoiseFilename << LL_ENDL; LLPointer cloudNoiseFile(LLImageFormatted::createFromExtension(cloudNoiseFilename)); if(cloudNoiseFile.isNull()) { - llerrs << "Error: Failed to load cloud noise image " << cloudNoiseFilename << llendl; + LL_ERRS() << "Error: Failed to load cloud noise image " << cloudNoiseFilename << LL_ENDL; } if(cloudNoiseFile->load(cloudNoiseFilename)) @@ -75,8 +80,8 @@ LLDrawPoolWLSky::LLDrawPoolWLSky(void) : if(cloudNoiseFile->decode(sCloudNoiseRawImage, 0.0f)) { //debug use - lldebugs << "cloud noise raw image width: " << sCloudNoiseRawImage->getWidth() << " : height: " << sCloudNoiseRawImage->getHeight() << " : components: " << - (S32)sCloudNoiseRawImage->getComponents() << " : data size: " << sCloudNoiseRawImage->getDataSize() << llendl ; + LL_DEBUGS() << "cloud noise raw image width: " << sCloudNoiseRawImage->getWidth() << " : height: " << sCloudNoiseRawImage->getHeight() << " : components: " << + (S32)sCloudNoiseRawImage->getComponents() << " : data size: " << sCloudNoiseRawImage->getDataSize() << LL_ENDL ; llassert_always(sCloudNoiseRawImage->getData()) ; sCloudNoiseTexture = LLViewerTextureManager::getLocalTexture(sCloudNoiseRawImage.get(), TRUE); @@ -92,7 +97,7 @@ LLDrawPoolWLSky::LLDrawPoolWLSky(void) : LLDrawPoolWLSky::~LLDrawPoolWLSky() { - //llinfos << "destructing wlsky draw pool." << llendl; + //LL_INFOS() << "destructing wlsky draw pool." << LL_ENDL; sCloudNoiseTexture = NULL; sCloudNoiseRawImage = NULL; } @@ -154,14 +159,16 @@ void LLDrawPoolWLSky::renderDome(F32 camHeightLocal, LLGLSLShader * shader) cons // the windlight sky dome works most conveniently in a coordinate system // where Y is up, so permute our basis vectors accordingly. - gGL.rotatef(120.f, 1.f / F_SQRT3, 1.f / F_SQRT3, 1.f / F_SQRT3); + static const LLMatrix4a rot = gGL.genRot(120.f, 1.f / F_SQRT3, 1.f / F_SQRT3, 1.f / F_SQRT3); + gGL.rotatef(rot); gGL.scalef(0.333f, 0.333f, 0.333f); gGL.translatef(0.f,-camHeightLocal, 0.f); // Draw WL Sky - shader->uniform3f("camPosLocal", 0.f, camHeightLocal, 0.f); + static LLStaticHashedString sCamPosLocal("camPosLocal"); + shader->uniform3f(sCamPosLocal, 0.f, camHeightLocal, 0.f); gSky.mVOWLSkyp->drawDome(); @@ -172,7 +179,7 @@ void LLDrawPoolWLSky::renderSkyHaze(F32 camHeightLocal) const { if (gPipeline.canUseWindLightShaders() && gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_SKY)) { - LLGLDisable blend(GL_BLEND); + LLGLDisable blend; sky_shader->bind(); @@ -195,15 +202,16 @@ void LLDrawPoolWLSky::renderStars(void) const return; LLGLSPipelineSkyBox gls_sky; - LLGLEnable blend(GL_BLEND); + LLGLEnable blend; gGL.setSceneBlendType(LLRender::BT_ALPHA); // *NOTE: have to have bound the cloud noise texture already since register // combiners blending below requires something to be bound // and we might as well only bind once. gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE); - - gPipeline.disableLights(); + + LLGLState light_state; + gPipeline.disableLights(light_state); /*if (!LLPipeline::sReflectionRender) { @@ -217,9 +225,10 @@ void LLDrawPoolWLSky::renderStars(void) const //New gGL.getTexUnit(0)->bind(gSky.mVOSkyp->getBloomTex()); - if (gPipeline.canUseVertexShaders()) + if (LLGLSLShader::sNoFixedFunction) { - star_shader->uniform1f("custom_alpha", star_alpha.mV[3]); + static LLStaticHashedString sCustomAlpha("custom_alpha"); + star_shader->uniform1f(sCustomAlpha, star_alpha.mV[3]); } else { @@ -232,7 +241,7 @@ void LLDrawPoolWLSky::renderStars(void) const gGL.popMatrix(); - if (!gPipeline.canUseVertexShaders()) + if (!LLGLSLShader::sNoFixedFunction) { // and disable the combiner states gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); @@ -243,7 +252,7 @@ void LLDrawPoolWLSky::renderSkyClouds(F32 camHeightLocal) const { if (gPipeline.canUseWindLightShaders() && gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_WL_CLOUDS) && sCloudNoiseTexture.notNull()) { - LLGLEnable blend(GL_BLEND); + LLGLEnable blend; gGL.setSceneBlendType(LLRender::BT_ALPHA); gGL.getTexUnit(0)->bind(sCloudNoiseTexture); @@ -266,9 +275,9 @@ void LLDrawPoolWLSky::renderHeavenlyBodies() color.mV[VW] = llclamp(color.mV[VW]*color.mV[VW]*4.f,0.f,1.f); LLGLSPipelineSkyBox gls_skybox; - LLGLEnable blend_on(GL_BLEND); + LLGLEnable blend_on; + LLGLDisable lighting; gGL.setSceneBlendType(LLRender::BT_ALPHA); - gPipeline.disableLights(); #if 0 // when we want to re-add a texture sun disc, here's where to do it. LLFace * face = gSky.mVOSkyp->mFace[LLVOSky::FACE_SUN]; @@ -291,10 +300,11 @@ void LLDrawPoolWLSky::renderHeavenlyBodies() // since LLImageGL::bind detects that it's a noop, and optimizes it out. gGL.getTexUnit(0)->bind(face->getTexture()); - if (gPipeline.canUseVertexShaders()) + if (LLGLSLShader::sNoFixedFunction) { // Okay, so the moon isn't a star, but it's close enough. - star_shader->uniform1f("custom_alpha", color.mV[VW]); + static LLStaticHashedString sCustomAlpha("custom_alpha"); + star_shader->uniform1f(sCustomAlpha, color.mV[VW]); } else { @@ -306,7 +316,7 @@ void LLDrawPoolWLSky::renderHeavenlyBodies() face->getVertexBuffer()->setBuffer(LLDrawPoolWLSky::STAR_VERTEX_DATA_MASK); face->getVertexBuffer()->draw(LLRender::TRIANGLES, face->getVertexBuffer()->getNumIndices(), 0); - if (!gPipeline.canUseVertexShaders()) + if (!LLGLSLShader::sNoFixedFunction) { gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); } @@ -319,13 +329,14 @@ void LLDrawPoolWLSky::renderDeferred(S32 pass) { return; } - LLFastTimer ftm(FTM_RENDER_WL_SKY); + LL_RECORD_BLOCK_TIME(FTM_RENDER_WL_SKY); const F32 camHeightLocal = LLWLParamManager::getInstance()->getDomeOffset() * LLWLParamManager::getInstance()->getDomeRadius(); + LLGLDisable stencil; LLGLSNoFog disableFog; LLGLDepthTest depth(GL_TRUE, GL_FALSE); - LLGLDisable clip(GL_CLIP_PLANE0); + LLGLDisable clip; LLGLSquashToFarClip far_clip(glh_get_current_projection()); @@ -363,13 +374,13 @@ void LLDrawPoolWLSky::render(S32 pass) { return; } - LLFastTimer ftm(FTM_RENDER_WL_SKY); + LL_RECORD_BLOCK_TIME(FTM_RENDER_WL_SKY); const F32 camHeightLocal = LLWLParamManager::getInstance()->getDomeOffset() * LLWLParamManager::getInstance()->getDomeRadius(); LLGLSNoFog disableFog; LLGLDepthTest depth(GL_TRUE, GL_FALSE); - LLGLDisable clip(GL_CLIP_PLANE0); + LLGLDisable clip; LLGLSquashToFarClip far_clip(glh_get_current_projection()); @@ -382,7 +393,7 @@ void LLDrawPoolWLSky::render(S32 pass) gGL.translatef(origin.mV[0], origin.mV[1], origin.mV[2]); - if(gPipeline.canUseVertexShaders()) + if (LLGLSLShader::sNoFixedFunction) star_shader->bind(); // *NOTE: have to bind a texture here since register combiners blending in // renderStars() requires something to be bound and we might as well only @@ -393,7 +404,7 @@ void LLDrawPoolWLSky::render(S32 pass) renderStars(); - if(gPipeline.canUseVertexShaders()) + if (LLGLSLShader::sNoFixedFunction) star_shader->unbind(); @@ -406,7 +417,7 @@ void LLDrawPoolWLSky::render(S32 pass) void LLDrawPoolWLSky::prerender() { - //llinfos << "wlsky prerendering pass." << llendl; + //LL_INFOS() << "wlsky prerendering pass." << LL_ENDL; } LLDrawPoolWLSky *LLDrawPoolWLSky::instancePool() diff --git a/indra/newview/lldrawpoolwlsky.h b/indra/newview/lldrawpoolwlsky.h index 1057ef7bdc..89daefa7a2 100644 --- a/indra/newview/lldrawpoolwlsky.h +++ b/indra/newview/lldrawpoolwlsky.h @@ -82,7 +82,7 @@ class LLDrawPoolWLSky : public LLDrawPool { void renderSkyClouds(F32 camHeightLocal) const; void renderHeavenlyBodies(); -private: +public: static LLPointer sCloudNoiseTexture; static LLPointer sCloudNoiseRawImage; }; diff --git a/indra/newview/lldroptarget.cpp b/indra/newview/lldroptarget.cpp index d35cb4c03e..a8625c5718 100644 --- a/indra/newview/lldroptarget.cpp +++ b/indra/newview/lldroptarget.cpp @@ -37,6 +37,9 @@ #include "lldroptarget.h" +#include + +#include "llbutton.h" #include "llinventorymodel.h" #include "llstartup.h" #include "lltextbox.h" @@ -46,8 +49,9 @@ static LLRegisterWidget r("drop_target"); -static std::string currently_set_to(const LLViewerInventoryItem* item) +std::string currently_set_to(const LLInventoryItem* item) { + if (!item) return LLTrans::getString("CurrentlyNotSet"); LLStringUtil::format_map_t args; args["[ITEM]"] = item->getName(); return LLTrans::getString("CurrentlySetTo", args); @@ -55,38 +59,42 @@ static std::string currently_set_to(const LLViewerInventoryItem* item) LLDropTarget::LLDropTarget(const LLDropTarget::Params& p) : LLView(p) +, mReset(NULL) { setToolTip(std::string(p.tool_tip)); - mText = new LLTextBox("drop_text", p.rect, p.label); + mText = new LLTextBox("drop_text", LLRect(), p.label); addChild(mText); setControlName(p.control_name, NULL); - mText->setOrigin(0, 0); mText->setFollows(FOLLOWS_NONE); mText->setMouseOpaque(false); mText->setHAlign(LLFontGL::HCENTER); mText->setVPad(1); - mBorder = new LLViewBorder("drop_border", p.rect, LLViewBorder::BEVEL_IN); + mBorder = new LLViewBorder("drop_border", LLRect(), LLViewBorder::BEVEL_IN); addChild(mBorder); mBorder->setMouseOpaque(false); - - if (p.fill_parent) fillParent(getParent()); if (!p.border_visible) mBorder->setBorderWidth(0); + + if (p.show_reset) + { + addChild(mReset = new LLButton("reset", LLRect(), "icn_clear_lineeditor.tga", "icn_clear_lineeditor.tga", "", boost::bind(&LLDropTarget::setValue, this, _2))); + } + + // Now set the rects of the children + p.fill_parent ? fillParent(getParent()) : setChildRects(p.rect); } LLDropTarget::~LLDropTarget() { - delete mText; - delete mBorder; } // static LLView* LLDropTarget::fromXML(LLXMLNodePtr node, LLView* parent, LLUICtrlFactory* factory) { - LLDropTarget* target = new LLDropTarget(); + LLDropTarget* target = new LLDropTarget; target->initFromXML(node, parent); return target; } @@ -97,9 +105,17 @@ void LLDropTarget::initFromXML(LLXMLNodePtr node, LLView* parent) LLView::initFromXML(node, parent); const LLRect& rect = getRect(); - const LLRect child_rect(0, rect.getHeight(), rect.getWidth(), 0); - mText->setRect(child_rect); - mBorder->setRect(child_rect); + if (node->hasAttribute("show_reset")) + { + bool show; + node->getAttribute_bool("show_reset", show); + if (!show) + { + delete mReset; + mReset = NULL; + } + } + setChildRects(LLRect(0, rect.getHeight(), rect.getWidth(), 0)); if (node->hasAttribute("name")) // Views can't have names, but drop targets can { @@ -136,9 +152,11 @@ void LLDropTarget::setControlName(const std::string& control_name, LLView* conte if (control_name.empty()) // The "empty set" { mControl = NULL; + mConnection.disconnect(); return; // This DropTarget never changes text, it isn't tied to a control } + bool none(true); std::string text; if (LLStartUp::getStartupState() != STATE_STARTED) // Too early for PerAccount { @@ -147,16 +165,46 @@ void LLDropTarget::setControlName(const std::string& control_name, LLView* conte else { mControl = gSavedPerAccountSettings.getControl(control_name); + if (!mControl) + { + LL_ERRS() << "Could not find control \"" << control_name << "\" in gSavedPerAccountSettings" << LL_ENDL; + return; // Though this should never happen. + } const LLUUID id(mControl->getValue().asString()); - if (id.isNull()) + none = id.isNull(); + if (none) text = LLTrans::getString("CurrentlyNotSet"); else if (LLViewerInventoryItem* item = gInventory.getItem(id)) text = currently_set_to(item); else text = LLTrans::getString("CurrentlySetToAnItemNotOnThisAccount"); } + if (mControl) + mConnection = mControl->getSignal()->connect(boost::bind(&LLView::setValue, this, _2)); + else + mConnection.disconnect(); mText->setText(text); + if (mReset) mReset->setVisible(!none); +} + +void LLDropTarget::setChildRects(LLRect rect) +{ + mBorder->setRect(rect); + if (mReset) + { + // Reset button takes rightmost part of the text area. + S32 height(rect.getHeight()); + rect.mRight -= height; + mText->setRect(rect); + rect.mLeft = rect.mRight; + rect.mRight += height; + mReset->setRect(rect); + } + else + { + mText->setRect(rect); + } } void LLDropTarget::fillParent(const LLView* parent) @@ -171,37 +219,48 @@ void LLDropTarget::fillParent(const LLView* parent) } // The following block enlarges the target, but maintains the desired size for the text and border - const LLRect& rect = getRect(); // Children maintain the old rectangle - mText->setRect(rect); - mBorder->setRect(rect); + setChildRects(getRect()); // Children maintain the old rectangle const LLRect& parent_rect = parent->getRect(); setRect(LLRect(0, parent_rect.getHeight(), parent_rect.getWidth(), 0)); } +void LLDropTarget::setControlValue(const std::string& val) +{ + if (mControl) + { + boost::signals2::shared_connection_block block(mConnection); + mControl->setValue(val); + } +} + +void LLDropTarget::setItem(const LLInventoryItem* item) +{ + if (mReset) mReset->setVisible(!!item); + mText->setText(currently_set_to(item)); + setControlValue(item ? item->getUUID().asString() : ""); +} + +void LLDropTarget::setValue(const LLSD& value) +{ + const LLUUID& id(value.asUUID()); + setItem(id.isNull() ? NULL : gInventory.getItem(id)); +} + void LLDropTarget::doDrop(EDragAndDropType cargo_type, void* cargo_data) { - llinfos << "LLDropTarget::doDrop()" << llendl; + LL_INFOS() << "LLDropTarget::doDrop()" << LL_ENDL; } BOOL LLDropTarget::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, void* cargo_data, EAcceptance* accept, std::string& tooltip_msg) { - if (mEntityID.isNull()) + if (mID.notNull()) + return getParent() ? LLToolDragAndDrop::handleGiveDragAndDrop(mID, LLUUID::null, drop, cargo_type, cargo_data, accept) : false; + + if (LLViewerInventoryItem* inv_item = static_cast(cargo_data)) { - if (LLViewerInventoryItem* inv_item = static_cast(cargo_data)) - { - *accept = ACCEPT_YES_COPY_SINGLE; - if (drop) - { - mText->setText(currently_set_to(inv_item)); - if (mControl) mControl->setValue(inv_item->getUUID().asString()); - } - } - else - { - *accept = ACCEPT_NO; - } - return true; + *accept = ACCEPT_YES_COPY_SINGLE; + if (drop) setItem(inv_item); } - return getParent() ? LLToolDragAndDrop::handleGiveDragAndDrop(mEntityID, LLUUID::null, drop, cargo_type, cargo_data, accept) : false; + return true; } diff --git a/indra/newview/lldroptarget.h b/indra/newview/lldroptarget.h index 08026bd2a4..8edc4c6918 100644 --- a/indra/newview/lldroptarget.h +++ b/indra/newview/lldroptarget.h @@ -47,11 +47,13 @@ class LLDropTarget : public LLView Optional border_visible; // Whether or not to display the border Optional control_name; // Control to change on item drop (Per Account only) Optional label; // Label for the LLTextBox, used when label doesn't dynamically change on drop + Optional show_reset; // Whether or not to show the reset button Optional fill_parent; // Whether or not to fill the direct parent, to have a larger drop target. If true, the next sibling must explicitly define its rect without deltas. Params() : border_visible("border_visible", true) , control_name("control_name", "") , label("label", "") + , show_reset("show_reset", true) , fill_parent("fill_parent", false) { changeDefault(mouse_opaque, false); @@ -69,16 +71,23 @@ class LLDropTarget : public LLView virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, void* cargo_data, EAcceptance* accept, std::string& tooltip_msg); static LLView* fromXML(LLXMLNodePtr node, LLView* parent, class LLUICtrlFactory* factory); virtual void initFromXML(LLXMLNodePtr node, LLView* parent); - virtual void setControlName(const std::string& control, LLView* context); + virtual void setControlName(const std::string& control, LLView* context); + virtual void setValue(const LLSD& value); + void setChildRects(LLRect rect); void fillParent(const LLView* parent); - void setEntityID(const LLUUID& id) { mEntityID = id;} + void setEntityID(const LLUUID& id) { mID = id; } + protected: - LLUUID mEntityID; -private: + virtual void setItem(const class LLInventoryItem* item); + void setControlValue(const std::string& val); + + LLUUID mID; class LLViewBorder* mBorder; LLControlVariable* mControl; + boost::signals2::scoped_connection mConnection; class LLTextBox* mText; + class LLButton* mReset; }; #endif // LLDROPTARGET_H diff --git a/indra/newview/lldynamictexture.cpp b/indra/newview/lldynamictexture.cpp index e8f3fafbe6..2daf5b6e97 100644 --- a/indra/newview/lldynamictexture.cpp +++ b/indra/newview/lldynamictexture.cpp @@ -51,7 +51,7 @@ S32 LLViewerDynamicTexture::sNumRenders = 0; // LLViewerDynamicTexture() //----------------------------------------------------------------------------- LLViewerDynamicTexture::LLViewerDynamicTexture(S32 width, S32 height, S32 components, EOrder order, BOOL clamp) : - LLViewerTexture(width, height, components, FALSE), + LLViewerTexture(width, height, components, FALSE, false), mClamp(clamp) { llassert((1 <= components) && (components <= 4)); @@ -99,7 +99,7 @@ void LLViewerDynamicTexture::generateGLTexture(LLGLint internal_format, LLGLenum { if (mComponents < 1 || mComponents > 4) { - llerrs << "Bad number of components in dynamic texture: " << mComponents << llendl; + LL_ERRS() << "Bad number of components in dynamic texture: " << mComponents << LL_ENDL; } LLPointer raw_image = new LLImageRaw(mFullWidth, mFullHeight, mComponents); @@ -109,7 +109,7 @@ void LLViewerDynamicTexture::generateGLTexture(LLGLint internal_format, LLGLenum } if(fill_color) raw_image->fill(*fill_color); - createGLTexture(0, raw_image, 0, TRUE, LLViewerTexture::DYNAMIC_TEX); + createGLTexture(0, raw_image, nullptr, TRUE, LLViewerTexture::DYNAMIC_TEX); setAddressMode((mClamp) ? LLTexUnit::TAM_CLAMP : LLTexUnit::TAM_WRAP); mGLTexturep->setGLTextureCreated(false); } @@ -131,7 +131,7 @@ void LLViewerDynamicTexture::preRender(BOOL clear_depth) llassert(mFullHeight <= 512); llassert(mFullWidth <= 512); - if (gGLManager.mHasFramebufferObject && gPipeline.mWaterDis.isComplete()) + if (gGLManager.mHasFramebufferObject && gPipeline.mWaterDis.isComplete() && !gGLManager.mIsATI) { //using offscreen render target, just use the bottom left corner mOrigin.set(0, 0); } @@ -161,9 +161,10 @@ void LLViewerDynamicTexture::preRender(BOOL clear_depth) mCamera.setView(camera->getView()); mCamera.setNear(camera->getNear()); - glViewport(mOrigin.mX, mOrigin.mY, mFullWidth, mFullHeight); + gGL.setViewport(mOrigin.mX, mOrigin.mY, mFullWidth, mFullHeight); if (clear_depth) { + gGL.syncContextState(); glClear(GL_DEPTH_BUFFER_BIT); } } @@ -218,16 +219,14 @@ BOOL LLViewerDynamicTexture::updateAllInstances() return TRUE; } -#if 0 //THIS CAUSES MAINT-1092 - bool use_fbo = gGLManager.mHasFramebufferObject && gPipeline.mWaterDis.isComplete(); + bool use_fbo = gGLManager.mHasFramebufferObject && gPipeline.mWaterDis.isComplete() && !gGLManager.mIsATI; + if (use_fbo) { gPipeline.mWaterDis.bindTarget(); } -#endif LLGLSLShader::bindNoShader(); - LLVertexBuffer::unbind(); BOOL result = FALSE; BOOL ret = FALSE ; @@ -238,7 +237,8 @@ BOOL LLViewerDynamicTexture::updateAllInstances() { LLViewerDynamicTexture *dynamicTexture = *iter; if (dynamicTexture->needsRender()) - { + { + gGL.syncContextState(); glClear(GL_DEPTH_BUFFER_BIT); gDepthDirty = TRUE; @@ -259,12 +259,10 @@ BOOL LLViewerDynamicTexture::updateAllInstances() } } -#if 0 //THIS CAUSES MAINT-1092 if (use_fbo) { gPipeline.mWaterDis.flush(); } -#endif return ret; } diff --git a/indra/newview/llemote.cpp b/indra/newview/llemote.cpp index c83846215e..47bd579696 100644 --- a/indra/newview/llemote.cpp +++ b/indra/newview/llemote.cpp @@ -48,7 +48,7 @@ // LLEmote() // Class Constructor //----------------------------------------------------------------------------- -LLEmote::LLEmote(const LLUUID &id) : LLMotion(id) +LLEmote::LLEmote(LLUUID const& id, LLMotionController* controller) : LLMotion(id, controller) { mCharacter = NULL; diff --git a/indra/newview/llemote.h b/indra/newview/llemote.h index 99d05b9a2a..173719121a 100644 --- a/indra/newview/llemote.h +++ b/indra/newview/llemote.h @@ -55,7 +55,7 @@ class LLEmote : { public: // Constructor - LLEmote(const LLUUID &id); + LLEmote(LLUUID const& id, LLMotionController* controller); // Destructor virtual ~LLEmote(); @@ -67,7 +67,7 @@ class LLEmote : // static constructor // all subclasses must implement such a function and register it - static LLMotion *create(const LLUUID &id) { return new LLEmote(id); } + static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLEmote(id, controller); } public: //------------------------------------------------------------------------- diff --git a/indra/newview/llenvmanager.cpp b/indra/newview/llenvmanager.cpp index 3033d4e07f..d2fb204cca 100644 --- a/indra/newview/llenvmanager.cpp +++ b/indra/newview/llenvmanager.cpp @@ -53,7 +53,7 @@ std::string LLEnvPrefs::getWaterPresetName() const { if (mWaterPresetName.empty()) { - llwarns << "Water preset name is empty" << llendl; + LL_WARNS() << "Water preset name is empty" << LL_ENDL; } return mWaterPresetName; @@ -63,7 +63,7 @@ std::string LLEnvPrefs::getSkyPresetName() const { if (mSkyPresetName.empty()) { - llwarns << "Sky preset name is empty" << llendl; + LL_WARNS() << "Sky preset name is empty" << LL_ENDL; } return mSkyPresetName; @@ -73,7 +73,7 @@ std::string LLEnvPrefs::getDayCycleName() const { if (mDayCycleName.empty()) { - llwarns << "Day cycle name is empty" << llendl; + LL_WARNS() << "Day cycle name is empty" << LL_ENDL; } return mDayCycleName; @@ -105,9 +105,11 @@ void LLEnvPrefs::setUseDayCycle(const std::string& name) } //============================================================================= -LLEnvManagerNew::LLEnvManagerNew() +LLEnvManagerNew::LLEnvManagerNew(): + mInterpNextChangeMessage(true), + mCurRegionUUID(LLUUID::null), + mLastReceivedID(LLUUID::null) { - mInterpNextChangeMessage = true; // Set default environment settings. mUserPrefs.mUseRegionSettings = true; @@ -115,6 +117,9 @@ LLEnvManagerNew::LLEnvManagerNew() mUserPrefs.mWaterPresetName = "Default"; mUserPrefs.mSkyPresetName = "Default"; mUserPrefs.mDayCycleName = "Default"; + + LL_DEBUGS("Windlight")<getConnectedGrid()->isAurora()) // On Aurora, the region says when to refresh + if (!gHippoGridManager->getConnectedGrid()->isWhiteCore()) // On WhiteCore, the region says when to refresh mInterpNextChangeMessage = false; } @@ -599,7 +593,7 @@ void LLEnvManagerNew::updateWaterFromPrefs(bool interpolate) LLWaterParamSet params; if (!water_mgr.getParamSet(water, params)) { - llwarns << "No water preset named " << water << ", falling back to defaults" << llendl; + LL_WARNS() << "No water preset named " << water << ", falling back to defaults" << LL_ENDL; water_mgr.getParamSet("Default", params); // *TODO: Fix user preferences accordingly. @@ -613,6 +607,7 @@ void LLEnvManagerNew::updateWaterFromPrefs(bool interpolate) void LLEnvManagerNew::updateManagersFromPrefs(bool interpolate) { + LL_DEBUGS("Windlight")<getRegionID() : LLUUID::null; - if (region_uuid == mCurRegionUUID) + if (region_uuid != mCurRegionUUID) { - return; + // Clear locally modified region settings. + mNewRegionPrefs.clear(); + + // *TODO: clear environment settings of the previous region? + + // Request environment settings of the new region. + mCurRegionUUID = region_uuid; + // for region crossings, interpolate the change; for teleports, don't + mInterpNextChangeMessage = (gAgent.getTeleportState() == LLAgent::TELEPORT_NONE); + LL_DEBUGS("Windlight") << (mInterpNextChangeMessage ? "Crossed" : "Teleported") + << " to new region: " << region_uuid + << LL_ENDL; + requestRegionSettings(); + } + else + { + LL_DEBUGS("Windlight") << "disregarding region change; interp: " + << (mInterpNextChangeMessage ? "true" : "false") + << " regionp: " << regionp + << " old: " << mCurRegionUUID + << " new: " << region_uuid + << LL_ENDL; } - - // Clear locally modified region settings. - mNewRegionPrefs.clear(); - - // *TODO: clear environment settings of the previous region? - - // Request environment settings of the new region. - LL_DEBUGS("Windlight") << "New viewer region: " << region_uuid << LL_ENDL; - mCurRegionUUID = region_uuid; - mInterpNextChangeMessage = interpolate; - requestRegionSettings(); - - // Let interested parties know agent region has been changed. - mRegionChangeSignal(); } -// Aurora-sim windlight refresh +// WhiteCore windlight refresh class WindLightRefresh : public LLHTTPNode { /*virtual*/ void post(LLHTTPNode::ResponsePtr response, const LLSD& context, const LLSD& input) const { if (!input || !context || !input.isMap() || !input.has("body")) { - llinfos << "malformed WindLightRefresh!" << llendl; + LL_INFOS() << "malformed WindLightRefresh!" << LL_ENDL; return; } //std::string dump = input["body"].asString(); - //llwarns << dump << llendl; + //LL_WARNS() << dump << LL_ENDL; LLSD body = input["body"]; LLEnvManagerNew *env = &LLEnvManagerNew::instance(); @@ -727,9 +729,9 @@ class WindLightRefresh : public LLHTTPNode env->mInterpNextChangeMessage = !body.has("Interpolate") || body["Interpolate"].asInteger() == 1; - llinfos << "Windlight Refresh, interpolate:" << env->mInterpNextChangeMessage << llendl; + LL_INFOS() << "Windlight Refresh, interpolate:" << env->mInterpNextChangeMessage << LL_ENDL; env->requestRegionSettings(); - env->mRegionChangeSignal(); + env->onRegionChange(); } }; diff --git a/indra/newview/llenvmanager.h b/indra/newview/llenvmanager.h index 8d53179964..6d7efeab6a 100644 --- a/indra/newview/llenvmanager.h +++ b/indra/newview/llenvmanager.h @@ -2,31 +2,25 @@ * @file llenvmanager.h * @brief Declaration of classes managing WindLight and water settings. * - * $LicenseInfo:firstyear=2009&license=viewergpl$ - * - * Copyright (c) 2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2011, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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$ */ @@ -39,7 +33,6 @@ class LLWLParamManager; class LLWaterParamManager; class LLWLAnimator; -class WindLightRefresh; // generic key struct LLEnvKey @@ -173,7 +166,6 @@ class LLEnvManagerNew : public LLSingleton public: typedef boost::signals2::signal prefs_change_signal_t; typedef boost::signals2::signal region_settings_change_signal_t; - typedef boost::signals2::signal region_change_signal_t; typedef boost::signals2::signal region_settings_applied_signal_t; LLEnvManagerNew(); @@ -229,15 +221,12 @@ class LLEnvManagerNew : public LLSingleton bool sendRegionSettings(const LLEnvironmentSettings& new_settings); boost::signals2::connection setPreferencesChangeCallback(const prefs_change_signal_t::slot_type& cb); boost::signals2::connection setRegionSettingsChangeCallback(const region_settings_change_signal_t::slot_type& cb); - boost::signals2::connection setRegionChangeCallback(const region_change_signal_t::slot_type& cb); boost::signals2::connection setRegionSettingsAppliedCallback(const region_settings_applied_signal_t::slot_type& cb); static bool canEditRegionSettings(); /// @return true if we have access to editing region environment static const std::string getScopeString(LLEnvKey::EScope scope); // Public callbacks. - void onRegionCrossing(); - void onTeleport(); void onRegionSettingsResponse(const LLSD& content); void onRegionSettingsApplyResponse(bool ok); @@ -261,7 +250,7 @@ class LLEnvManagerNew : public LLSingleton bool useDefaultSky(); bool useDefaultWater(); - void onRegionChange(bool interpolate); + void onRegionChange(); /// Emitted when user environment preferences change. prefs_change_signal_t mUsePrefsChangeSignal; @@ -269,9 +258,6 @@ class LLEnvManagerNew : public LLSingleton /// Emitted when region environment settings update comes. region_settings_change_signal_t mRegionSettingsChangeSignal; - /// Emitted when agent region changes. Move to LLAgent? - region_change_signal_t mRegionChangeSignal; - /// Emitted when agent region changes. Move to LLAgent? region_settings_applied_signal_t mRegionSettingsAppliedSignal; diff --git a/indra/newview/llestateinfomodel.cpp b/indra/newview/llestateinfomodel.cpp index 2b4494473c..72b9ae34a4 100644 --- a/indra/newview/llestateinfomodel.cpp +++ b/indra/newview/llestateinfomodel.cpp @@ -38,9 +38,6 @@ #include "llfloaterregioninfo.h" // for invoice id #include "llviewerregion.h" -class AIHTTPTimeoutPolicy; -extern AIHTTPTimeoutPolicy estateChangeInfoResponder_timeout; - LLEstateInfoModel::LLEstateInfoModel() : mID(0) , mFlags(0) @@ -68,12 +65,12 @@ void LLEstateInfoModel::sendEstateInfo() } } -bool LLEstateInfoModel::getUseFixedSun() const { return mFlags & REGION_FLAGS_SUN_FIXED; } -bool LLEstateInfoModel::getIsExternallyVisible() const { return mFlags & REGION_FLAGS_EXTERNALLY_VISIBLE; } -bool LLEstateInfoModel::getAllowDirectTeleport() const { return mFlags & REGION_FLAGS_ALLOW_DIRECT_TELEPORT; } -bool LLEstateInfoModel::getDenyAnonymous() const { return mFlags & REGION_FLAGS_DENY_ANONYMOUS; } -bool LLEstateInfoModel::getDenyAgeUnverified() const { return mFlags & REGION_FLAGS_DENY_AGEUNVERIFIED; } -bool LLEstateInfoModel::getAllowVoiceChat() const { return mFlags & REGION_FLAGS_ALLOW_VOICE; } +bool LLEstateInfoModel::getUseFixedSun() const { return getFlag(REGION_FLAGS_SUN_FIXED); } +bool LLEstateInfoModel::getIsExternallyVisible() const { return getFlag(REGION_FLAGS_EXTERNALLY_VISIBLE); } +bool LLEstateInfoModel::getAllowDirectTeleport() const { return getFlag(REGION_FLAGS_ALLOW_DIRECT_TELEPORT); } +bool LLEstateInfoModel::getDenyAnonymous() const { return getFlag(REGION_FLAGS_DENY_ANONYMOUS); } +bool LLEstateInfoModel::getDenyAgeUnverified() const { return getFlag(REGION_FLAGS_DENY_AGEUNVERIFIED); } +bool LLEstateInfoModel::getAllowVoiceChat() const { return getFlag(REGION_FLAGS_ALLOW_VOICE); } void LLEstateInfoModel::setUseFixedSun(bool val) { setFlag(REGION_FLAGS_SUN_FIXED, val); } void LLEstateInfoModel::setIsExternallyVisible(bool val) { setFlag(REGION_FLAGS_EXTERNALLY_VISIBLE, val); } @@ -96,7 +93,7 @@ void LLEstateInfoModel::update(const strings_t& strings) LL_DEBUGS("Windlight Sync") << "Received estate info: " << "is_sun_fixed = " << getUseFixedSun() << ", sun_hour = " << getSunHour() << LL_ENDL; - lldebugs << getInfoDump() << llendl; + LL_DEBUGS() << getInfoDump() << LL_ENDL; // Update region owner. LLViewerRegion* regionp = gAgent.getRegion(); @@ -118,19 +115,18 @@ class LLEstateChangeInfoResponder : public LLHTTPClient::ResponderWithResult public: // if we get a normal response, handle it here - /*virtual*/ void result(const LLSD& content) + virtual void httpSuccess() { - llinfos << "Committed estate info" << llendl; + LL_INFOS() << "Committed estate info" << LL_ENDL; LLEstateInfoModel::instance().notifyCommit(); } // if we get an error response - /*virtual*/ void error(U32 status, const std::string& reason) + virtual void httpFailure() { - llwarns << "Failed to commit estate info (" << status << "): " << reason << llendl; + LL_WARNS() << "Failed to commit estate info [status:" << mStatus << "]: " << mReason << LL_ENDL; } - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return estateChangeInfoResponder_timeout; } /*virtual*/ char const* getName(void) const { return "LLEstateChangeInfoResponder"; } }; @@ -161,7 +157,7 @@ bool LLEstateInfoModel::commitEstateInfoCaps() LL_DEBUGS("Windlight Sync") << "Sending estate caps: " << "is_sun_fixed = " << getUseFixedSun() << ", sun_hour = " << getSunHour() << LL_ENDL; - lldebugs << body << LL_ENDL; + LL_DEBUGS() << body << LL_ENDL; // we use a responder so that we can re-get the data after committing to the database LLHTTPClient::post(url, body, new LLEstateChangeInfoResponder); @@ -180,7 +176,7 @@ void LLEstateInfoModel::commitEstateInfoDataserver() LL_DEBUGS("Windlight Sync") << "Sending estate info: " << "is_sun_fixed = " << getUseFixedSun() << ", sun_hour = " << getSunHour() << LL_ENDL; - lldebugs << getInfoDump() << LL_ENDL; + LL_DEBUGS() << getInfoDump() << LL_ENDL; LLMessageSystem* msg = gMessageSystem; msg->newMessage("EstateOwnerMessage"); @@ -205,18 +201,6 @@ void LLEstateInfoModel::commitEstateInfoDataserver() gAgent.sendMessage(); } -void LLEstateInfoModel::setFlag(U32 flag, bool val) -{ - if (val) - { - mFlags |= flag; - } - else - { - mFlags &= ~flag; - } -} - std::string LLEstateInfoModel::getInfoDump() { LLSD dump; diff --git a/indra/newview/llestateinfomodel.h b/indra/newview/llestateinfomodel.h index 30e83b1409..b83d17f8d5 100644 --- a/indra/newview/llestateinfomodel.h +++ b/indra/newview/llestateinfomodel.h @@ -86,19 +86,38 @@ class LLEstateInfoModel : public LLSingleton private: bool commitEstateInfoCaps(); void commitEstateInfoDataserver(); - U32 getFlags() const { return mFlags; } - void setFlag(U32 flag, bool val); + inline bool getFlag(U64 flag) const; + inline void setFlag(U64 flag, bool val); + U64 getFlags() const { return mFlags; } std::string getInfoDump(); // estate info std::string mName; /// estate name LLUUID mOwnerID; /// estate owner id U32 mID; /// estate id - U32 mFlags; /// estate flags + U64 mFlags; /// estate flags F32 mSunHour; /// estate sun hour update_signal_t mUpdateSignal; /// emitted when we receive update from sim update_signal_t mCommitSignal; /// emitted when our update gets applied to sim }; +inline bool LLEstateInfoModel::getFlag(U64 flag) const +{ + return ((mFlags & flag) != 0); +} + +inline void LLEstateInfoModel::setFlag(U64 flag, bool val) +{ + if (val) + { + mFlags |= flag; + } + else + { + mFlags &= ~flag; + } +} + + #endif // LL_LLESTATEINFOMODEL_H diff --git a/indra/newview/lleventnotifier.cpp b/indra/newview/lleventnotifier.cpp index 4cbbbc4202..f48b994118 100644 --- a/indra/newview/lleventnotifier.cpp +++ b/indra/newview/lleventnotifier.cpp @@ -39,12 +39,58 @@ #include "llnotify.h" #include "lleventinfo.h" -#include "llfloaterdirectory.h" +#include "llfloaterevent.h" #include "llfloaterworldmap.h" #include "llagent.h" #include "llappviewer.h" // for gPacificDaylightTime +#include "llcommandhandler.h" // secondlife:///app/... support #include "llviewercontrol.h" +class LLEventHandler : public LLCommandHandler +{ +public: + // requires trusted browser to trigger + LLEventHandler() : LLCommandHandler("event", UNTRUSTED_THROTTLE) { } + bool handle(const LLSD& params, const LLSD& query_map, + LLMediaCtrl* web) + { + if (params.size() < 2) + { + return false; + } + std::string event_command = params[1].asString(); + S32 event_id = params[0].asInteger(); + if (event_command == "about" || event_command == "details") + { + LLFloaterEventInfo::show(event_id); + return true; + } + else if(event_command == "notify") + { + // we're adding or removing a notification, so grab the date, name and notification bool + if (params.size() < 3) + { + return false; + } + if(params[2].asString() == "enable") + { + gEventNotifier.add(event_id); + // tell the server to modify the database as this was a slurl event notification command + gEventNotifier.serverPushRequest(event_id, true); + } + else + { + gEventNotifier.remove(event_id); + } + return true; + } + + return false; + } +}; +LLEventHandler gEventHandler; + + LLEventNotifier gEventNotifier; LLEventNotifier::LLEventNotifier() @@ -104,8 +150,7 @@ bool LLEventNotifier::handleResponse(U32 eventId, LLVector3d eventPos, const LLS gFloaterWorldMap->trackLocation(eventPos); break; case 1: - gDisplayEventHack = TRUE; - LLFloaterDirectory::showEvents(eventId); + LLFloaterEventInfo::show(eventId); break; case 2: break; @@ -231,7 +276,7 @@ BOOL LLEventNotification::load(const LLSD& response) if (event_name.isDefined()) { mEventName = event_name.asString(); - llinfos << "Event: " << mEventName << llendl; + LL_INFOS() << "Event: " << mEventName << LL_ENDL; } else { @@ -242,7 +287,7 @@ BOOL LLEventNotification::load(const LLSD& response) if (event_date.isDefined()) { mEventDate = event_date.asString(); - llinfos << "EventDate: " << mEventDate << llendl; + LL_INFOS() << "EventDate: " << mEventDate << LL_ENDL; } else { @@ -253,7 +298,7 @@ BOOL LLEventNotification::load(const LLSD& response) if (event_date_ut.isDefined()) { std::string date = event_date_ut.asString(); - llinfos << "EventDate: " << date << llendl; + LL_INFOS() << "EventDate: " << date << LL_ENDL; mEventDate = strtoul(date.c_str(), NULL, 10); // Convert to Pacific, based on server's opinion of whether @@ -283,7 +328,7 @@ BOOL LLEventNotification::load(const LLSD& response) if (grid_x_sd.isDefined()) { grid_x= grid_x_sd.asInteger(); - llinfos << "GridX: " << grid_x << llendl; + LL_INFOS() << "GridX: " << grid_x << LL_ENDL; } else { @@ -294,7 +339,7 @@ BOOL LLEventNotification::load(const LLSD& response) if (grid_y_sd.isDefined()) { grid_y= grid_y_sd.asInteger(); - llinfos << "GridY: " << grid_y << llendl; + LL_INFOS() << "GridY: " << grid_y << LL_ENDL; } else { @@ -305,7 +350,7 @@ BOOL LLEventNotification::load(const LLSD& response) if (x_region_sd.isDefined()) { x_region = x_region_sd.asInteger(); - llinfos << "RegionX: " << x_region << llendl; + LL_INFOS() << "RegionX: " << x_region << LL_ENDL; } else { @@ -316,7 +361,7 @@ BOOL LLEventNotification::load(const LLSD& response) if (y_region_sd.isDefined()) { y_region = y_region_sd.asInteger(); - llinfos << "RegionY: " << y_region << llendl; + LL_INFOS() << "RegionY: " << y_region << LL_ENDL; } else { diff --git a/indra/newview/lleventpoll.cpp b/indra/newview/lleventpoll.cpp index 75d3c4eda8..b1a412b493 100644 --- a/indra/newview/lleventpoll.cpp +++ b/indra/newview/lleventpoll.cpp @@ -73,8 +73,9 @@ namespace void handleMessage(const LLSD& content); - /*virtual*/ void error(U32 status, const std::string& reason); - /*virtual*/ void result(const LLSD& content); + /*virtual*/ void httpFailure(void); + /*virtual*/ void httpSuccess(void); + /*virtual*/ bool is_event_poll(void) const { return true; } /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return eventPollResponder_timeout; } /*virtual*/ char const* getName(void) const { return "LLEventPollResponder"; } @@ -118,15 +119,15 @@ namespace const std::string& pollURL, const LLHost& sender) { LLHTTPClient::ResponderPtr result = new LLEventPollResponder(pollURL, sender); - llinfos << "LLEventPollResponder::start <" << sCount << "> " - << pollURL << llendl; + LL_INFOS() << "LLEventPollResponder::start <" << sCount << "> " + << pollURL << LL_ENDL; return result; } void LLEventPollResponder::stop() { - llinfos << "LLEventPollResponder::stop <" << mCount << "> " - << mPollURL << llendl; + LL_INFOS() << "LLEventPollResponder::stop <" << mCount << "> " + << mPollURL << LL_ENDL; // there should be a way to stop a LLHTTPClient request in progress mDone = true; } @@ -143,18 +144,18 @@ namespace LLViewerRegion *regionp = gAgent.getRegion(); if (!regionp) { - llerrs << "LLEventPoll initialized before region is added." << llendl; + LL_ERRS() << "LLEventPoll initialized before region is added." << LL_ENDL; } mSender = sender.getIPandPort(); - llinfos << "LLEventPoll initialized with sender " << mSender << llendl; + LL_INFOS() << "LLEventPoll initialized with sender " << mSender << LL_ENDL; makeRequest(); } LLEventPollResponder::~LLEventPollResponder() { stop(); - lldebugs << "LLEventPollResponder::~Impl <" << mCount << "> " - << mPollURL << llendl; + LL_DEBUGS() << "LLEventPollResponder::~Impl <" << mCount << "> " + << mPollURL << LL_ENDL; } void LLEventPollResponder::makeRequest() @@ -163,8 +164,8 @@ namespace request["ack"] = mAcknowledge; request["done"] = mDone; - lldebugs << "LLEventPollResponder::makeRequest <" << mCount << "> ack = " - << LLSDXMLStreamer(mAcknowledge) << llendl; + LL_DEBUGS() << "LLEventPollResponder::makeRequest <" << mCount << "> ack = " + << LLSDXMLStreamer(mAcknowledge) << LL_ENDL; LLHTTPClient::post(mPollURL, request, this); } @@ -178,17 +179,36 @@ namespace } //virtual - void LLEventPollResponder::error(U32 status, const std::string& reason) + void LLEventPollResponder::httpFailure(void) { if (mDone) return; - // A HTTP_BAD_GATEWAY (502) error is our standard timeout response - // we get this when there are no events. - if ( status == HTTP_BAD_GATEWAY ) - { + // Timeout + if (is_internal_http_error_that_warrants_a_retry(mStatus)) + { // A standard timeout response we get this when there are no events. mErrorCount = 0; makeRequest(); } + else if ( mStatus == HTTP_BAD_GATEWAY ) + { // LEGACY: A HTTP_BAD_GATEWAY (502) error is our standard timeout response + // we get this when there are no events. + mErrorCount = 0; + makeRequest(); + } + else if (mStatus == HTTP_NOT_FOUND) + { // Event polling for this server has been canceled. In + // some cases the server gets ahead of the viewer and will + // return a 404 error (Not Found) before the cancel event + // comes back in the queue + LL_WARNS("LLEventPollImpl") << "Canceling coroutine" << LL_ENDL; + stop(); + } + else if (mCode != CURLE_OK) + { + /// Some LLCore or LIBCurl error was returned. This is unlikely to be recoverable + LL_WARNS("LLEventPollImpl") << "Critical error from poll request returned from libraries. Canceling coroutine." << LL_ENDL; + stop(); + } else if (mErrorCount < MAX_EVENT_POLL_HTTP_ERRORS) { ++mErrorCount; @@ -198,13 +218,13 @@ namespace + mErrorCount * EVENT_POLL_ERROR_RETRY_SECONDS_INC , this); - llwarns << "Unexpected HTTP error. status: " << status << ", reason: " << reason << llendl; + LL_WARNS() << "Unexpected HTTP error. status: " << mStatus << ", reason: " << mReason << LL_ENDL; } else { - llwarns << "LLEventPollResponder::error: <" << mCount << "> got " - << status << ": " << reason - << (mDone ? " -- done" : "") << llendl; + LL_WARNS() << "LLEventPollResponder::error: <" << mCount << "> got " + << mStatus << ": " << mReason + << (mDone ? " -- done" : "") << LL_ENDL; stop(); // At this point we have given up and the viewer will not receive HTTP messages from the simulator. @@ -212,47 +232,49 @@ namespace // They are essentially disconnected from the region even though some things may still work. // Since things won't get better until they relog we force a disconnect now. + /* Singu Note: There's no reason to disconnect, just because this failed a few too many times // *NOTE:Mani - The following condition check to see if this failing event poll // is attached to the Agent's main region. If so we disconnect the viewer. // Else... its a child region and we just leave the dead event poll stopped and // continue running. if(gAgent.getRegion() && gAgent.getRegion()->getHost().getIPandPort() == mSender) { - llwarns << "Forcing disconnect due to stalled main region event poll." << llendl; + LL_WARNS() << "Forcing disconnect due to stalled main region event poll." << LL_ENDL; LLAppViewer::instance()->forceDisconnect(LLTrans::getString("AgentLostConnection")); } + */ } } //virtual - void LLEventPollResponder::result(const LLSD& content) + void LLEventPollResponder::httpSuccess(void) { - lldebugs << "LLEventPollResponder::result <" << mCount << ">" - << (mDone ? " -- done" : "") << ll_pretty_print_sd(content) << llendl; + LL_DEBUGS() << "LLEventPollResponder::result <" << mCount << ">" + << (mDone ? " -- done" : "") << ll_pretty_print_sd(mContent) << LL_ENDL; if (mDone) return; mErrorCount = 0; - if (!content.get("events") || - !content.get("id")) + if (!mContent.get("events") || + !mContent.get("id")) { - //llwarns << "received event poll with no events or id key" << llendl; + //LL_WARNS() << "received event poll with no events or id key" << LL_ENDL; makeRequest(); return; } - mAcknowledge = content["id"]; - LLSD events = content["events"]; + mAcknowledge = mContent["id"]; + LLSD events = mContent["events"]; if(mAcknowledge.isUndefined()) { - llwarns << "LLEventPollResponder: id undefined" << llendl; + LL_WARNS() << "LLEventPollResponder: id undefined" << LL_ENDL; } // was llinfos but now that CoarseRegionUpdate is TCP @ 1/second, it'd be too verbose for viewer logs. -MG - lldebugs << "LLEventPollResponder::completed <" << mCount << "> " << events.size() << "events (id " - << LLSDXMLStreamer(mAcknowledge) << ")" << llendl; + LL_DEBUGS() << "LLEventPollResponder::completed <" << mCount << "> " << events.size() << "events (id " + << LLSDXMLStreamer(mAcknowledge) << ")" << LL_ENDL; LLSD::array_const_iterator i = events.beginArray(); LLSD::array_const_iterator end = events.endArray(); diff --git a/indra/newview/llexperiencelog.cpp b/indra/newview/llexperiencelog.cpp new file mode 100644 index 0000000000..ea2e57535f --- /dev/null +++ b/indra/newview/llexperiencelog.cpp @@ -0,0 +1,289 @@ +/** + * @file llexperiencelog.cpp + * @brief llexperiencelog implementation + * + * $LicenseInfo:firstyear=2014&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2014, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llexperiencelog.h" + +#include "lldispatcher.h" +#include "llsdserialize.h" +#include "llviewergenericmessage.h" +#include "llnotificationsutil.h" +#include "lltrans.h" +#include "llerror.h" +#include "lldate.h" + + +class LLExperienceLogDispatchHandler final : public LLDispatchHandler +{ +public: + bool operator()( + const LLDispatcher* dispatcher, + const std::string& key, + const LLUUID& invoice, + const sparam_t& strings) override + { + LLSD message; + + sparam_t::const_iterator it = strings.begin(); + if(it != strings.end()){ + const std::string& llsdRaw = *it++; + std::istringstream llsdData(llsdRaw); + if (!LLSDSerialize::deserialize(message, llsdData, llsdRaw.length())) + { + LL_WARNS() << "LLExperienceLogDispatchHandler: Attempted to read parameter data into LLSD but failed:" << llsdRaw << LL_ENDL; + } + } + message["public_id"] = invoice; + + // Object Name + if(it != strings.end()) + { + message["ObjectName"] = *it++; + } + + // parcel Name + if(it != strings.end()) + { + message["ParcelName"] = *it++; + } + message["Count"] = 1; + + LLExperienceLog::instance().handleExperienceMessage(message); + return true; + } +}; + +static LLExperienceLogDispatchHandler experience_log_dispatch_handler; + +void LLExperienceLog::handleExperienceMessage(LLSD& message) +{ + time_t now; + time(&now); + char daybuf[16];/* Flawfinder: ignore */ + char time_of_day[16];/* Flawfinder: ignore */ + strftime(daybuf, 16, "%Y-%m-%d", localtime(&now)); + strftime(time_of_day, 16, " %H:%M:%S", localtime(&now)); + message["Time"] = time_of_day; + + std::string day = daybuf; + + if(!mEvents.has(day)) + { + mEvents[day] = LLSD::emptyArray(); + } + LLSD& dayEvents = mEvents[day]; + if(dayEvents.size() > 0) + { + LLSD& last = *(dayEvents.rbeginArray()); + if( last["public_id"].asUUID() == message["public_id"].asUUID() + && last["ObjectName"].asString() == message["ObjectName"].asString() + && last["OwnerID"].asUUID() == message["OwnerID"].asUUID() + && last["ParcelName"].asString() == message["ParcelName"].asString() + && last["Permission"].asInteger() == message["Permission"].asInteger()) + { + last["Count"] = last["Count"].asInteger() + 1; + last["Time"] = time_of_day; + mSignals(last); + return; + } + } + message["Time"] = time_of_day; + mEvents[day].append(message); + mSignals(message); +} + +LLExperienceLog::LLExperienceLog() + : mMaxDays(7) + , mPageSize(25) + , mNotifyNewEvent(false) +{ +} + +void LLExperienceLog::initialize() +{ + loadEvents(); + if(!gGenericDispatcher.isHandlerPresent("ExperienceEvent")) + { + gGenericDispatcher.addHandler("ExperienceEvent", &experience_log_dispatch_handler); + } +} + +std::string LLExperienceLog::getFilename() +{ + return gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "experience_events.xml"); +} + + +std::string LLExperienceLog::getPermissionString( const LLSD& message, const std::string& base ) +{ + std::ostringstream buf; + if(message.has("Permission")) + { + buf << base << message["Permission"].asInteger(); + std::string entry; + if(LLTrans::findString(entry, buf.str())) + { + buf.str(entry); + } + } + + if(buf.str().empty()) + { + buf << base << "Unknown"; + + buf.str(LLTrans::getString(buf.str(), message)); + } + + return buf.str(); +} + +void LLExperienceLog::notify( LLSD& message ) +{ + message["EventType"] = getPermissionString(message, "ExperiencePermission"); + if(message.has("IsAttachment") && message["IsAttachment"].asBoolean()) + { + LLNotificationsUtil::add("ExperienceEventAttachment", message); + } + else + { + LLNotificationsUtil::add("ExperienceEvent", message); + } + message.erase("EventType"); +} + +void LLExperienceLog::saveEvents() +{ + eraseExpired(); + std::string filename = getFilename(); + LLSD settings = LLSD::emptyMap().with("Events", mEvents); + + settings["MaxDays"] = (int)mMaxDays; + settings["Notify"] = mNotifyNewEvent; + settings["PageSize"] = (int)mPageSize; + + llofstream stream(filename.c_str()); + LLSDSerialize::toPrettyXML(settings, stream); +} + + +void LLExperienceLog::loadEvents() +{ + LLSD settings = LLSD::emptyMap(); + + std::string filename = getFilename(); + llifstream stream(filename.c_str()); + LLSDSerialize::fromXMLDocument(settings, stream); + + if(settings.has("MaxDays")) + { + setMaxDays((U32)settings["MaxDays"].asInteger()); + } + if(settings.has("Notify")) + { + setNotifyNewEvent(settings["Notify"].asBoolean()); + } + if(settings.has("PageSize")) + { + setPageSize((U32)settings["PageSize"].asInteger()); + } + mEvents.clear(); + if(mMaxDays > 0 && settings.has("Events")) + { + mEvents = settings["Events"]; + } + + eraseExpired(); +} + +LLExperienceLog::~LLExperienceLog() +{ + saveEvents(); +} + +void LLExperienceLog::eraseExpired() +{ + std::vector expired; + for (const auto& event_pair : mEvents.map()) + { + const std::string& date = event_pair.first; + if (isExpired(date)) + { + expired.push_back(date); + } + } + + for (const auto& date : expired) + { + mEvents.erase(date); + } +} + +bool LLExperienceLog::isExpired(const std::string& date) const +{ + if (date.empty()) + return true; + + S32 month, day, year = 0; + S32 matched = sscanf(date.c_str(), "%d-%d-%d", &year, &month, &day); + if (matched != 3) return false; + LLDate event_date; + event_date.fromYMDHMS(year, month, day); + + return event_date.secondsSinceEpoch() <= (LLDate::now().secondsSinceEpoch() - F64(getMaxDays() * 86400U)); +} + +const LLSD& LLExperienceLog::getEvents() const +{ + return mEvents; +} + +void LLExperienceLog::clear() +{ + mEvents.clear(); +} + +void LLExperienceLog::setMaxDays( U32 val ) +{ + mMaxDays = val; +} + +LLExperienceLog::callback_connection_t LLExperienceLog::addUpdateSignal( const callback_slot_t& cb ) +{ + return mSignals.connect(cb); +} + +void LLExperienceLog::setNotifyNewEvent( bool val ) +{ + mNotifyNewEvent = val; + if(!val && mNotifyConnection.connected()) + { + mNotifyConnection.disconnect(); + } + else if( val && !mNotifyConnection.connected()) + { + mNotifyConnection = addUpdateSignal(std::function(LLExperienceLog::notify)); + } +} diff --git a/indra/newview/llexperiencelog.h b/indra/newview/llexperiencelog.h new file mode 100644 index 0000000000..27012898c6 --- /dev/null +++ b/indra/newview/llexperiencelog.h @@ -0,0 +1,86 @@ +/** + * @file llexperiencelog.h + * @brief llexperiencelog and related class definitions + * + * $LicenseInfo:firstyear=2014&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2014, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + + + +#ifndef LL_LLEXPERIENCELOG_H +#define LL_LLEXPERIENCELOG_H + +#include "llsingleton.h" + +class LLExperienceLog final : public LLSingleton +{ + friend class LLSingleton; + LLExperienceLog(); +public: + typedef boost::signals2::signal + callback_signal_t; + typedef callback_signal_t::slot_type callback_slot_t; + typedef boost::signals2::connection callback_connection_t; + callback_connection_t addUpdateSignal(const callback_slot_t& cb); + + void initialize(); + + U32 getMaxDays() const { return mMaxDays; } + void setMaxDays(U32 val); + + bool getNotifyNewEvent() const { return mNotifyNewEvent; } + void setNotifyNewEvent(bool val); + + U32 getPageSize() const { return mPageSize; } + void setPageSize(U32 val) { mPageSize = val; } + + const LLSD& getEvents()const; + void clear(); + + virtual ~LLExperienceLog(); + + static void notify(LLSD& message); + static std::string getFilename(); + static std::string getPermissionString(const LLSD& message, const std::string& base); + bool isExpired(const std::string& date) const; +protected: + void handleExperienceMessage(LLSD& message); + + + void loadEvents(); + void saveEvents(); + void eraseExpired(); + + LLSD mEvents; + callback_signal_t mSignals; + callback_connection_t mNotifyConnection; + U32 mMaxDays; + U32 mPageSize; + bool mNotifyNewEvent; + + friend class LLExperienceLogDispatchHandler; +}; + + + + +#endif // LL_LLEXPERIENCELOG_H diff --git a/indra/newview/llexternaleditor.cpp b/indra/newview/llexternaleditor.cpp index c016b8da68..c0c397142d 100644 --- a/indra/newview/llexternaleditor.cpp +++ b/indra/newview/llexternaleditor.cpp @@ -41,21 +41,33 @@ LLExternalEditor::EErrorCode LLExternalEditor::setCommand(const std::string& env std::string cmd = findCommand(env_var, override); if (cmd.empty()) { - llwarns << "Editor command is empty or not set" << llendl; - return EC_NOT_SPECIFIED; +#if LL_WINDOWS + cmd = getenv("COMSPEC") + std::string(" /C START \"%s\""); +#elif LL_DARWIN + cmd = "/usr/bin/open \"%s\""; +#elif LL_LINUX + // xdg-open might not actually be installed on all distros, but it's our best bet. + cmd = "/usr/bin/xdg-open \"%s\""; +#endif + cmd = findCommand(LLStringUtil::null, cmd); + if (cmd.empty()) + { + LL_WARNS() << "Failed to find generic open handler." << LL_ENDL; + return EC_NOT_SPECIFIED; + } } // Add the filename marker if missing. if (cmd.find(sFilenameMarker) == std::string::npos) { cmd += " \"" + sFilenameMarker + "\""; - llinfos << "Adding the filename marker (" << sFilenameMarker << ")" << llendl; + LL_INFOS() << "Adding the filename marker (" << sFilenameMarker << ")" << LL_ENDL; } string_vec_t tokens; if (tokenize(tokens, cmd) < 2) // 2 = bin + at least one arg (%s) { - llwarns << "Error parsing editor command" << llendl; + LL_WARNS() << "Error parsing editor command" << LL_ENDL; return EC_PARSE_ERROR; } @@ -63,7 +75,7 @@ LLExternalEditor::EErrorCode LLExternalEditor::setCommand(const std::string& env std::string bin_path = tokens[0]; if (!LLFile::isfile(bin_path)) { - llwarns << "Editor binary [" << bin_path << "] not found" << llendl; + LL_WARNS() << "Editor binary [" << bin_path << "] not found" << LL_ENDL; return EC_BINARY_NOT_FOUND; } @@ -75,7 +87,7 @@ LLExternalEditor::EErrorCode LLExternalEditor::setCommand(const std::string& env if (i > 1) mArgs += " "; mArgs += "\"" + tokens[i] + "\""; } - llinfos << "Setting command [" << bin_path << " " << mArgs << "]" << llendl; + LL_INFOS() << "Setting command [" << bin_path << " " << mArgs << "]" << LL_ENDL; return EC_SUCCESS; } @@ -85,7 +97,7 @@ LLExternalEditor::EErrorCode LLExternalEditor::run(const std::string& file_path) std::string args = mArgs; if (mProcess.getExecutable().empty() || args.empty()) { - llwarns << "Editor command not set" << llendl; + LL_WARNS() << "Editor command not set" << LL_ENDL; return EC_NOT_SPECIFIED; } @@ -104,7 +116,7 @@ LLExternalEditor::EErrorCode LLExternalEditor::run(const std::string& file_path) } // Run the editor. - llinfos << "Running editor command [" << mProcess.getExecutable() + " " + args << "]" << llendl; + LL_INFOS() << "Running editor command [" << mProcess.getExecutable() + " " + args << "]" << LL_ENDL; int result = mProcess.launch(); if (result == 0) { @@ -186,12 +198,12 @@ std::string LLExternalEditor::findCommand( if (!override.empty()) // try the supplied override first { cmd = override; - llinfos << "Using override" << llendl; + LL_INFOS() << "Using override" << LL_ENDL; } else if (!gSavedSettings.getString(sSetting).empty()) { cmd = gSavedSettings.getString(sSetting); - llinfos << "Using setting" << llendl; + LL_INFOS() << "Using setting" << LL_ENDL; } else // otherwise use the path specified by the environment variable { @@ -199,10 +211,10 @@ std::string LLExternalEditor::findCommand( if (env_var_val) { cmd = env_var_val; - llinfos << "Using env var " << env_var << llendl; + LL_INFOS() << "Using env var " << env_var << LL_ENDL; } } - llinfos << "Found command [" << cmd << "]" << llendl; + LL_INFOS() << "Found command [" << cmd << "]" << LL_ENDL; return cmd; } diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index 7593ad9386..c0271b3066 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -57,14 +57,19 @@ #include "llviewerregion.h" #include "llviewerwindow.h" #include "llviewershadermgr.h" +#include "llviewertexture.h" +#include "llvoavatar.h" +#include "llsculptidsize.h" #define LL_MAX_INDICES_COUNT 1000000 +static LLStaticHashedString sTextureIndexIn("texture_index_in"); +static LLStaticHashedString sColorIn("color_in"); + BOOL LLFace::sSafeRenderSelect = TRUE; // FALSE #define DOTVEC(a,b) (a.mV[0]*b.mV[0] + a.mV[1]*b.mV[1] + a.mV[2]*b.mV[2]) - /* For each vertex, given: B - binormal @@ -137,9 +142,13 @@ void LLFace::init(LLDrawable* drawablep, LLViewerObject* objp) //special value to indicate uninitialized position mIndicesIndex = 0xFFFFFFFF; + + for (U32 i = 0; i < LLRender::NUM_TEXTURE_CHANNELS; ++i) + { + mIndexInTex[i] = 0; + mTexture[i] = NULL; + } - mIndexInTex = 0; - mTexture = NULL; mTEOffset = -1; mTextureIndex = 255; @@ -157,6 +166,8 @@ void LLFace::init(LLDrawable* drawablep, LLViewerObject* objp) mBoundingSphereRadius = 0.0f ; mHasMedia = FALSE ; + + mShinyInAlpha = false; } void LLFace::destroy() @@ -166,9 +177,12 @@ void LLFace::destroy() gPipeline.checkReferences(this); } - if(mTexture.notNull()) + for (U32 i = 0; i < LLRender::NUM_TEXTURE_CHANNELS; ++i) { - mTexture->removeFace(this) ; + if(mTexture[i].notNull()) + { + mTexture[i]->removeFace(i, this) ; + } } if (isState(LLFace::PARTICLE)) @@ -193,7 +207,7 @@ void LLFace::destroy() if (mTextureMatrix) { - delete mTextureMatrix; + ll_aligned_free_16(mTextureMatrix); mTextureMatrix = NULL; if (mDrawablep.notNull()) @@ -221,7 +235,7 @@ void LLFace::initClass() void LLFace::setWorldMatrix(const LLMatrix4 &mat) { - llerrs << "Faces on this drawable are not independently modifiable\n" << llendl; + LL_ERRS() << "Faces on this drawable are not independently modifiable\n" << LL_ENDL; } void LLFace::setPool(LLFacePool* pool) @@ -233,7 +247,7 @@ void LLFace::setPool(LLFacePool* new_pool, LLViewerTexture *texturep) { if (!new_pool) { - llerrs << "Setting pool to null!" << llendl; + LL_ERRS() << "Setting pool to null!" << LL_ENDL; } if (new_pool != mDrawPoolp) @@ -261,60 +275,126 @@ void LLFace::setPool(LLFacePool* new_pool, LLViewerTexture *texturep) setTexture(texturep) ; } -void LLFace::setTexture(LLViewerTexture* tex) +void LLFace::setTexture(U32 ch, LLViewerTexture* tex) { - if(mTexture == tex) + llassert(ch < LLRender::NUM_TEXTURE_CHANNELS); + + if(mTexture[ch] == tex) { return ; } - if(mTexture.notNull()) + if(mTexture[ch].notNull()) { - mTexture->removeFace(this) ; - } + mTexture[ch]->removeFace(ch, this) ; + } if(tex) { - tex->addFace(this) ; + tex->addFace(ch, this) ; } - mTexture = tex ; + mTexture[ch] = tex ; +} + +void LLFace::setTexture(LLViewerTexture* tex) +{ + setDiffuseMap(tex); +} + +void LLFace::setDiffuseMap(LLViewerTexture* tex) +{ + setTexture(LLRender::DIFFUSE_MAP, tex); +} + +void LLFace::setNormalMap(LLViewerTexture* tex) +{ + setTexture(LLRender::NORMAL_MAP, tex); +} + +void LLFace::setSpecularMap(LLViewerTexture* tex) +{ + setTexture(LLRender::SPECULAR_MAP, tex); } void LLFace::dirtyTexture() { LLDrawable* drawablep = getDrawable(); - if (mVObjp.notNull() && mVObjp->getVolume() && - mTexture.notNull() && mTexture->getComponents() == 4) - { //dirty texture on an alpha object should be treated as an LoD update - LLVOVolume* vobj = drawablep->getVOVolume(); - if (vobj) + if (mVObjp.notNull() && mVObjp->getVolume()) + { + for (U32 ch = 0; ch < LLRender::NUM_TEXTURE_CHANNELS; ++ch) { - vobj->mLODChanged = TRUE; + if (mTexture[ch].notNull() && mTexture[ch]->getComponents() == 4) + { //dirty texture on an alpha object should be treated as an LoD update + LLVOVolume* vobj = drawablep->getVOVolume(); + if (vobj) + { + vobj->mLODChanged = TRUE; + + vobj->updateVisualComplexity(); // Animmesh+ + } + gPipeline.markRebuild(drawablep, LLDrawable::REBUILD_VOLUME, FALSE); + } } - gPipeline.markRebuild(drawablep, LLDrawable::REBUILD_VOLUME, FALSE); - } + } gPipeline.markTextured(drawablep); } -void LLFace::switchTexture(LLViewerTexture* new_texture) +void LLFace::notifyAboutCreatingTexture(LLViewerTexture *texture) +{ + LLDrawable* drawablep = getDrawable(); + if(mVObjp.notNull() && mVObjp->getVolume()) + { + LLVOVolume *vobj = drawablep->getVOVolume(); + if(vobj && vobj->notifyAboutCreatingTexture(texture)) + { + gPipeline.markTextured(drawablep); + gPipeline.markRebuild(drawablep, LLDrawable::REBUILD_VOLUME); + } + } +} + +void LLFace::notifyAboutMissingAsset(LLViewerTexture *texture) +{ + LLDrawable* drawablep = getDrawable(); + if(mVObjp.notNull() && mVObjp->getVolume()) + { + LLVOVolume *vobj = drawablep->getVOVolume(); + if(vobj && vobj->notifyAboutMissingAsset(texture)) + { + gPipeline.markTextured(drawablep); + gPipeline.markRebuild(drawablep, LLDrawable::REBUILD_VOLUME); + } + } +} + +void LLFace::switchTexture(U32 ch, LLViewerTexture* new_texture) { - if(mTexture == new_texture) + llassert(ch < LLRender::NUM_TEXTURE_CHANNELS); + + if(mTexture[ch] == new_texture) { return ; } if(!new_texture) { - llerrs << "Can not switch to a null texture." << llendl; + LL_ERRS() << "Can not switch to a null texture." << LL_ENDL; return; } - new_texture->addTextureStats(mTexture->getMaxVirtualSize()) ; - getViewerObject()->changeTEImage(mTEOffset, new_texture) ; - setTexture(new_texture) ; + llassert(mTexture[ch].notNull()); + + new_texture->addTextureStats(mTexture[ch]->getMaxVirtualSize()) ; + + if (ch == LLRender::DIFFUSE_MAP) + { + getViewerObject()->changeTEImage(mTEOffset, new_texture) ; + } + + setTexture(ch, new_texture) ; dirtyTexture(); } @@ -348,6 +428,7 @@ void LLFace::setSize(S32 num_vertices, const S32 num_indices, bool align) //allocate vertices in blocks of 4 for alignment num_vertices = (num_vertices + 0x3) & ~0x3; } + if (mGeomCount != num_vertices || mIndicesCount != num_indices) { @@ -382,7 +463,7 @@ void LLFace::setTextureIndex(U8 index) { if (mDrawInfo && !mDrawInfo->mTextureList.empty()) { - llerrs << "Face with no texture index references indexed texture draw info." << llendl; + LL_ERRS() << "Face with no texture index references indexed texture draw info." << LL_ENDL; } } } @@ -404,7 +485,7 @@ U16 LLFace::getGeometryAvatar( LLStrider &normals, LLStrider &tex_coords, LLStrider &vertex_weights, - LLStrider &clothing_weights) + LLStrider &clothing_weights) { if (mVertexBuffer.notNull()) { @@ -443,7 +524,11 @@ void LLFace::updateCenterAgent() { if (mDrawablep->isActive()) { - mCenterAgent = mCenterLocal * getRenderMatrix(); + LLVector4a local_pos; + local_pos.load3(mCenterLocal.mV); + + getRenderMatrix().affineTransform(local_pos,local_pos); + mCenterAgent.set(local_pos.getF32ptr()); } else { @@ -471,17 +556,21 @@ void LLFace::renderSelected(LLViewerTexture *imagep, const LLColor4& color) gGL.getTexUnit(0)->bind(imagep); gGL.pushMatrix(); + + const LLMatrix4a* model_matrix = NULL; if (mDrawablep->isActive()) { - gGL.multMatrix((GLfloat*)mDrawablep->getRenderMatrix().mMatrix); + model_matrix = &(mDrawablep->getRenderMatrix()); } else { - gGL.multMatrix((GLfloat*)mDrawablep->getRegion()->mRenderMatrix.mMatrix); + model_matrix = &mDrawablep->getRegion()->mRenderMatrix; + } + if(model_matrix && !model_matrix->isIdentity()) + { + gGL.multMatrix(*model_matrix); } - gGL.diffuseColor4fv(color.mV); - if (mDrawablep->isState(LLDrawable::RIGGED)) { LLVOVolume* volume = mDrawablep->getVOVolume(); @@ -490,10 +579,13 @@ void LLFace::renderSelected(LLViewerTexture *imagep, const LLColor4& color) LLRiggedVolume* rigged = volume->getRiggedVolume(); if (rigged) { - LLGLEnable offset(GL_POLYGON_OFFSET_FILL); - glPolygonOffset(-1.f, -1.f); - gGL.multMatrix((F32*) volume->getRelativeXform().mMatrix); + LLGLEnable offset; + gGL.setPolygonOffset(-1.f, -1.f); + gGL.multMatrix(volume->getRelativeXform()); const LLVolumeFace& vol_face = rigged->getVolumeFace(getTEOffset()); + + // Singu Note: Implementation changed to utilize a VBO, avoiding fixed functions unless required +#if 0 LLVertexBuffer::unbind(); glVertexPointer(3, GL_FLOAT, 16, vol_face.mPositions); if (vol_face.mTexCoords) @@ -504,14 +596,37 @@ void LLFace::renderSelected(LLViewerTexture *imagep, const LLColor4& color) gGL.syncMatrices(); glDrawElements(GL_TRIANGLES, vol_face.mNumIndices, GL_UNSIGNED_SHORT, vol_face.mIndices); glDisableClientState(GL_TEXTURE_COORD_ARRAY); +#else + LLGLSLShader* prev_shader = NULL; + + if(LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_INTERFACE)) + { + if(LLGLSLShader::sCurBoundShaderPtr != &gHighlightProgram) + { + prev_shader = LLGLSLShader::sCurBoundShaderPtr; + gHighlightProgram.bind(); + } + } + + gGL.diffuseColor4fv(color.mV); + + LLVertexBuffer::drawElements(LLRender::TRIANGLES, vol_face.mNumVertices, vol_face.mPositions, vol_face.mTexCoords, vol_face.mNumIndices, vol_face.mIndices); + + if(prev_shader) + { + prev_shader->bind(); + } +#endif } } } else { - LLGLEnable poly_offset(GL_POLYGON_OFFSET_FILL); - glPolygonOffset(-1.f,-1.f); - mVertexBuffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0); + gGL.diffuseColor4fv(color.mV); + LLGLEnable poly_offset; + gGL.setPolygonOffset(-1.f,-1.f); + // Singu Note: Disable per-vertex color to prevent fixed-function pipeline from using it. We want glColor color, not vertex color! + mVertexBuffer->setBuffer(mVertexBuffer->getTypeMask() & ~(LLVertexBuffer::MAP_COLOR)); mVertexBuffer->draw(LLRender::TRIANGLES, mIndicesCount, mIndicesIndex); } @@ -574,29 +689,29 @@ void LLFace::setDrawInfo(LLDrawInfo* draw_info) void LLFace::printDebugInfo() const { LLFacePool *poolp = getPool(); - llinfos << "Object: " << getViewerObject()->mID << llendl; + LL_INFOS() << "Object: " << getViewerObject()->mID << LL_ENDL; if (getDrawable()) { - llinfos << "Type: " << LLPrimitive::pCodeToString(getDrawable()->getVObj()->getPCode()) << llendl; + LL_INFOS() << "Type: " << LLPrimitive::pCodeToString(getDrawable()->getVObj()->getPCode()) << LL_ENDL; } if (getTexture()) { - llinfos << "Texture: " << getTexture() << " Comps: " << (U32)getTexture()->getComponents() << llendl; + LL_INFOS() << "Texture: " << getTexture() << " Comps: " << (U32)getTexture()->getComponents() << LL_ENDL; } else { - llinfos << "No texture: " << llendl; + LL_INFOS() << "No texture: " << LL_ENDL; } - llinfos << "Face: " << this << llendl; - llinfos << "State: " << getState() << llendl; - llinfos << "Geom Index Data:" << llendl; - llinfos << "--------------------" << llendl; - llinfos << "GI: " << mGeomIndex << " Count:" << mGeomCount << llendl; - llinfos << "Face Index Data:" << llendl; - llinfos << "--------------------" << llendl; - llinfos << "II: " << mIndicesIndex << " Count:" << mIndicesCount << llendl; - llinfos << llendl; + LL_INFOS() << "Face: " << this << LL_ENDL; + LL_INFOS() << "State: " << getState() << LL_ENDL; + LL_INFOS() << "Geom Index Data:" << LL_ENDL; + LL_INFOS() << "--------------------" << LL_ENDL; + LL_INFOS() << "GI: " << mGeomIndex << " Count:" << mGeomCount << LL_ENDL; + LL_INFOS() << "Face Index Data:" << LL_ENDL; + LL_INFOS() << "--------------------" << LL_ENDL; + LL_INFOS() << "II: " << mIndicesIndex << " Count:" << mIndicesCount << LL_ENDL; + LL_INFOS() << LL_ENDL; if (poolp) { @@ -609,20 +724,20 @@ void LLFace::printDebugInfo() const LLFace *facep = *iter; if (facep == this) { - llinfos << "Pool reference: " << pool_references << llendl; + LL_INFOS() << "Pool reference: " << pool_references << LL_ENDL; pool_references++; } } if (pool_references != 1) { - llinfos << "Incorrect number of pool references!" << llendl; + LL_INFOS() << "Incorrect number of pool references!" << LL_ENDL; } } #if 0 - llinfos << "Indices:" << llendl; - llinfos << "--------------------" << llendl; + LL_INFOS() << "Indices:" << LL_ENDL; + LL_INFOS() << "--------------------" << LL_ENDL; const U32 *indicesp = getRawIndices(); S32 indices_count = getIndicesCount(); @@ -630,17 +745,17 @@ void LLFace::printDebugInfo() const for (S32 i = 0; i < indices_count; i++) { - llinfos << i << ":" << indicesp[i] << ":" << (S32)(indicesp[i] - geom_start) << llendl; + LL_INFOS() << i << ":" << indicesp[i] << ":" << (S32)(indicesp[i] - geom_start) << LL_ENDL; } - llinfos << llendl; + LL_INFOS() << LL_ENDL; - llinfos << "Vertices:" << llendl; - llinfos << "--------------------" << llendl; + LL_INFOS() << "Vertices:" << LL_ENDL; + LL_INFOS() << "--------------------" << LL_ENDL; for (S32 i = 0; i < mGeomCount; i++) { - llinfos << mGeomIndex + i << ":" << poolp->getVertex(mGeomIndex + i) << llendl; + LL_INFOS() << mGeomIndex + i << ":" << poolp->getVertex(mGeomIndex + i) << LL_ENDL; } - llinfos << llendl; + LL_INFOS() << LL_ENDL; #endif } @@ -681,9 +796,6 @@ static void xform4a(LLVector4a &tex_coord, const LLVector4a& trans, const LLVect // Texture transforms are done about the center of the face. st.setAdd(tex_coord, trans); - // Handle rotation - LLVector4a rot_st; - // LLVector4a s0; s0.splat(st, 0); @@ -734,131 +846,53 @@ bool less_than_max_mag(const LLVector4a& vec) } BOOL LLFace::genVolumeBBoxes(const LLVolume &volume, S32 f, - const LLMatrix4& mat_vert_in, const LLMatrix3& mat_normal_in, BOOL global_volume) + const LLMatrix4a& mat_vert_in, BOOL global_volume) { //get bounding box if (mDrawablep->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION | LLDrawable::REBUILD_RIGGED)) { - //VECTORIZE THIS - LLMatrix4a mat_vert; - mat_vert.loadu(mat_vert_in); - - LLMatrix4a mat_normal; - mat_normal.loadu(mat_normal_in); - - //if (mDrawablep->isState(LLDrawable::REBUILD_VOLUME)) - //{ //vertex buffer no longer valid - // mVertexBuffer = NULL; - // mLastVertexBuffer = NULL; - //} - - //VECTORIZE THIS - LLVector4a min,max; - if (f >= volume.getNumVolumeFaces()) { - llwarns << "Generating bounding box for invalid face index!" << llendl; + LL_WARNS() << "Generating bounding box for invalid face index!" << LL_ENDL; f = 0; } const LLVolumeFace &face = volume.getVolumeFace(f); - min = face.mExtents[0]; - max = face.mExtents[1]; - llassert(less_than_max_mag(min)); - llassert(less_than_max_mag(max)); - //min, max are in volume space, convert to drawable render space - LLVector4a center; - LLVector4a t; - t.setAdd(min, max); - t.mul(0.5f); - mat_vert.affineTransform(t, center); - LLVector4a size; - size.setSub(max, min); - size.mul(0.5f); - - llassert(less_than_max_mag(min)); - llassert(less_than_max_mag(max)); - - if (!global_volume) + // MAINT-8264 - stray vertices, especially in low LODs, cause bounding box errors. + if (face.mNumVertices < 3) { - //VECTORIZE THIS - LLVector4a scale; - scale.load3(mDrawablep->getVObj()->getScale().mV); - size.mul(scale); + LL_DEBUGS("RiggedBox") << "skipping face " << f << ", bad num vertices " + << face.mNumVertices << " " << face.mNumIndices << " " << face.mWeights << LL_ENDL; + return FALSE; } - mat_normal.mMatrix[0].normalize3fast(); - mat_normal.mMatrix[1].normalize3fast(); - mat_normal.mMatrix[2].normalize3fast(); - - LLVector4a v[4]; - - //get 4 corners of bounding box - mat_normal.rotate(size,v[0]); - //VECTORIZE THIS - LLVector4a scale; - - scale.set(-1.f, -1.f, 1.f); - scale.mul(size); - mat_normal.rotate(scale, v[1]); - - scale.set(1.f, -1.f, -1.f); - scale.mul(size); - mat_normal.rotate(scale, v[2]); - - scale.set(-1.f, 1.f, -1.f); - scale.mul(size); - mat_normal.rotate(scale, v[3]); + LLMatrix4a mat_vert = mat_vert_in; - LLVector4a& newMin = mExtents[0]; - LLVector4a& newMax = mExtents[1]; - - newMin = newMax = center; - - llassert(less_than_max_mag(center)); - - for (U32 i = 0; i < 4; i++) - { - LLVector4a delta; - delta.setAbs(v[i]); - LLVector4a min; - min.setSub(center, delta); - LLVector4a max; - max.setAdd(center, delta); - - newMin.setMin(newMin,min); - newMax.setMax(newMax,max); - - llassert(less_than_max_mag(newMin)); - llassert(less_than_max_mag(newMax)); - } + llassert(less_than_max_mag(face.mExtents[0])); + llassert(less_than_max_mag(face.mExtents[1])); + + matMulBoundBox(mat_vert, face.mExtents, mExtents); if (!mDrawablep->isActive()) - { + { // Shift position for region LLVector4a offset; offset.load3(mDrawablep->getRegion()->getOriginAgent().mV); - newMin.add(offset); - newMax.add(offset); - - llassert(less_than_max_mag(newMin)); - llassert(less_than_max_mag(newMax)); + mExtents[0].add(offset); + mExtents[1].add(offset); + LL_DEBUGS("RiggedBox") << "updating extents for face " << f + << " not active, added offset " << offset << LL_ENDL; } - t.setAdd(newMin, newMax); + LLVector4a t; + t.setAdd(mExtents[0],mExtents[1]); t.mul(0.5f); - llassert(less_than_max_mag(t)); - - //VECTORIZE THIS mCenterLocal.set(t.getF32ptr()); - - llassert(less_than_max_mag(newMin)); - llassert(less_than_max_mag(newMax)); - t.setSub(newMax,newMin); + t.setSub(mExtents[1],mExtents[0]); mBoundingSphereRadius = t.getLength3().getF32()*0.5f; updateCenterAgent(); @@ -874,7 +908,7 @@ BOOL LLFace::genVolumeBBoxes(const LLVolume &volume, S32 f, // integrated with getGeometryVolume() for its texture coordinate // generation - but i'll leave that to someone more familiar // with the implications. -LLVector2 LLFace::surfaceToTexture(LLVector2 surface_coord, LLVector3 position, LLVector3 normal) +LLVector2 LLFace::surfaceToTexture(LLVector2 surface_coord, const LLVector4a& position, const LLVector4a& normal) { LLVector2 tc = surface_coord; @@ -894,7 +928,9 @@ LLVector2 LLFace::surfaceToTexture(LLVector2 surface_coord, LLVector3 position, LLVector4a& center = *(mDrawablep->getVOVolume()->getVolume()->getVolumeFace(mTEOffset).mCenter); LLVector4a volume_position; - volume_position.load3(mDrawablep->getVOVolume()->agentPositionToVolume(position).mV); + LLVector3 v_position(position.getF32ptr()); + + volume_position.load3(mDrawablep->getVOVolume()->agentPositionToVolume(v_position).mV); if (!mDrawablep->getVOVolume()->isVolumeGlobal()) { @@ -904,7 +940,8 @@ LLVector2 LLFace::surfaceToTexture(LLVector2 surface_coord, LLVector3 position, } LLVector4a volume_normal; - volume_normal.load3(mDrawablep->getVOVolume()->agentDirectionToVolume(normal).mV); + LLVector3 v_normal(normal.getF32ptr()); + volume_normal.load3(mDrawablep->getVOVolume()->agentDirectionToVolume(v_normal).mV); volume_normal.normalize3fast(); if (texgen == LLTextureEntry::TEX_GEN_PLANAR) @@ -915,9 +952,9 @@ LLVector2 LLFace::surfaceToTexture(LLVector2 surface_coord, LLVector3 position, if (mTextureMatrix) // if we have a texture matrix, use it { - LLVector3 tc3(tc); - tc3 = tc3 * *mTextureMatrix; - tc = LLVector2(tc3); + LLVector4a tc4(tc.mV[VX],tc.mV[VY],0.f); + mTextureMatrix->affineTransform(tc4,tc4); + tc.set(tc4.getF32ptr()); } else // otherwise use the texture entry parameters @@ -934,12 +971,21 @@ LLVector2 LLFace::surfaceToTexture(LLVector2 surface_coord, LLVector3 position, // by planarProjection(). This is needed to match planar texgen parameters. void LLFace::getPlanarProjectedParams(LLQuaternion* face_rot, LLVector3* face_pos, F32* scale) const { - const LLMatrix4& vol_mat = getWorldMatrix(); + const LLMatrix4a& vol_mat = getWorldMatrix(); const LLVolumeFace& vf = getViewerObject()->getVolume()->getVolumeFace(mTEOffset); - const LLVector4a& normal4a = vf.mNormals[0]; - const LLVector4a& binormal4a = vf.mBinormals[0]; + if (!vf.mTangents) + { + return; + } + const LLVector4a& normal = vf.mNormals[0]; + const LLVector4a& tangent = vf.mTangents[0]; + + LLVector4a binormal; + binormal.setCross3(normal, tangent); + binormal.mul(tangent.getF32ptr()[3]); + LLVector2 projected_binormal; - planarProjection(projected_binormal, normal4a, *vf.mCenter, binormal4a); + planarProjection(projected_binormal, normal, *vf.mCenter, binormal); projected_binormal -= LLVector2(0.5f, 0.5f); // this normally happens in xform() *scale = projected_binormal.length(); // rotate binormal to match what planarProjection() thinks it is, @@ -948,13 +994,16 @@ void LLFace::getPlanarProjectedParams(LLQuaternion* face_rot, LLVector3* face_po F32 ang = acos(projected_binormal.mV[VY]); ang = (projected_binormal.mV[VX] < 0.f) ? -ang : ang; + gGL.genRot(RAD_TO_DEG * ang, normal).rotate(binormal, binormal); + + LLVector4a x_axis; + x_axis.setCross3(binormal, normal); + //VECTORIZE THIS - LLVector3 binormal(binormal4a.getF32ptr()); - LLVector3 normal(normal4a.getF32ptr()); - binormal.rotVec(ang, normal); - LLQuaternion local_rot( binormal % normal, binormal, normal ); - *face_rot = local_rot * vol_mat.quaternion(); - *face_pos = vol_mat.getTranslation(); + LLQuaternion local_rot(LLVector3(x_axis.getF32ptr()), LLVector3(binormal.getF32ptr()), LLVector3(normal.getF32ptr())); + *face_rot = local_rot * LLMatrix4(vol_mat.getF32ptr()).quaternion(); + + face_pos->set(vol_mat.getRow().getF32ptr()); } // Returns the necessary texture transform to align this face's TE to align_to's TE @@ -1035,9 +1084,10 @@ bool LLFace::canRenderAsMask() static const LLCachedControl use_rmse_auto_mask("SHUseRMSEAutoMask",false); static const LLCachedControl auto_mask_max_rmse("SHAutoMaskMaxRMSE",.09f); + static const LLCachedControl auto_mask_max_mid("SHAutoMaskMaxMid", .25f); if ((te->getColor().mV[3] == 1.0f) && // can't treat as mask if we have face alpha (te->getGlow() == 0.f) && // glowing masks are hard to implement - don't mask - (!getViewerObject()->isAttachment() && getTexture()->getIsAlphaMask(use_rmse_auto_mask ? auto_mask_max_rmse : -1.f))) // texture actually qualifies for masking (lazily recalculated but expensive) + (getTexture()->getIsAlphaMask((!getViewerObject()->isAttachment() && use_rmse_auto_mask) ? auto_mask_max_rmse : -1.f, auto_mask_max_mid))) // texture actually qualifies for masking (lazily recalculated but expensive) { if (LLPipeline::sRenderDeferred) { @@ -1060,14 +1110,14 @@ bool LLFace::canRenderAsMask() } -static LLFastTimer::DeclareTimer FTM_FACE_GEOM_VOLUME("Volume VB Cache"); +static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_VOLUME("Volume VB Cache"); //static void LLFace::cacheFaceInVRAM(const LLVolumeFace& vf) { - LLFastTimer t(FTM_FACE_GEOM_VOLUME); + LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_VOLUME); U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | - LLVertexBuffer::MAP_BINORMAL | LLVertexBuffer::MAP_NORMAL; + LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_NORMAL; if (vf.mWeights) { @@ -1080,11 +1130,11 @@ void LLFace::cacheFaceInVRAM(const LLVolumeFace& vf) buff->allocateBuffer(vf.mNumVertices, 0, true); LLStrider f_vert; - LLStrider f_binorm; + LLStrider f_tangent; LLStrider f_norm; LLStrider f_tc; - buff->getBinormalStrider(f_binorm); + buff->getTangentStrider(f_tangent); buff->getVertexStrider(f_vert); buff->getNormalStrider(f_norm); buff->getTexCoord0Strider(f_tc); @@ -1092,18 +1142,18 @@ void LLFace::cacheFaceInVRAM(const LLVolumeFace& vf) for (U32 i = 0; i < (U32)vf.mNumVertices; ++i) { *f_vert++ = vf.mPositions[i]; - (*f_binorm++).set(vf.mBinormals[i].getF32ptr()); + *f_tangent++ = vf.mTangents[i]; *f_tc++ = vf.mTexCoords[i]; (*f_norm++).set(vf.mNormals[i].getF32ptr()); } if (vf.mWeights) { - LLStrider f_wght; + LLStrider f_wght; buff->getWeight4Strider(f_wght); for (U32 i = 0; i < (U32)vf.mNumVertices; ++i) { - (*f_wght++).set(vf.mWeights[i].getF32ptr()); + (*f_wght++) = vf.mWeights[i]; } } @@ -1126,41 +1176,41 @@ void push_for_transform(LLVertexBuffer* buff, U32 source_count, U32 dest_count) gPipeline.mTransformFeedbackPrimitives += dest_count; } } -static LLFastTimer::DeclareTimer FTM_FACE_GET_GEOM("Face Geom"); -static LLFastTimer::DeclareTimer FTM_FACE_GEOM_POSITION("Position"); -static LLFastTimer::DeclareTimer FTM_FACE_GEOM_NORMAL("Normal"); -static LLFastTimer::DeclareTimer FTM_FACE_GEOM_TEXTURE("Texture"); -static LLFastTimer::DeclareTimer FTM_FACE_GEOM_COLOR("Color"); -static LLFastTimer::DeclareTimer FTM_FACE_GEOM_EMISSIVE("Emissive"); -static LLFastTimer::DeclareTimer FTM_FACE_GEOM_WEIGHTS("Weights"); -static LLFastTimer::DeclareTimer FTM_FACE_GEOM_BINORMAL("Binormal"); - -static LLFastTimer::DeclareTimer FTM_FACE_GEOM_FEEDBACK("Face Feedback"); -static LLFastTimer::DeclareTimer FTM_FACE_GEOM_FEEDBACK_POSITION("Feedback Position"); -static LLFastTimer::DeclareTimer FTM_FACE_GEOM_FEEDBACK_NORMAL("Feedback Normal"); -static LLFastTimer::DeclareTimer FTM_FACE_GEOM_FEEDBACK_TEXTURE("Feedback Texture"); -static LLFastTimer::DeclareTimer FTM_FACE_GEOM_FEEDBACK_COLOR("Feedback Color"); -static LLFastTimer::DeclareTimer FTM_FACE_GEOM_FEEDBACK_EMISSIVE("Feedback Emissive"); -static LLFastTimer::DeclareTimer FTM_FACE_GEOM_FEEDBACK_BINORMAL("Feedback Binormal"); - -static LLFastTimer::DeclareTimer FTM_FACE_GEOM_INDEX("Index"); -static LLFastTimer::DeclareTimer FTM_FACE_GEOM_INDEX_TAIL("Tail"); -static LLFastTimer::DeclareTimer FTM_FACE_POSITION_STORE("Pos"); -static LLFastTimer::DeclareTimer FTM_FACE_TEXTURE_INDEX_STORE("TexIdx"); -static LLFastTimer::DeclareTimer FTM_FACE_POSITION_PAD("Pad"); -static LLFastTimer::DeclareTimer FTM_FACE_TEX_DEFAULT("Default"); -static LLFastTimer::DeclareTimer FTM_FACE_TEX_QUICK("Quick"); -static LLFastTimer::DeclareTimer FTM_FACE_TEX_QUICK_NO_XFORM("No Xform"); -static LLFastTimer::DeclareTimer FTM_FACE_TEX_QUICK_XFORM("Xform"); -static LLFastTimer::DeclareTimer FTM_FACE_TEX_QUICK_PLANAR("Quick Planar"); +static LLTrace::BlockTimerStatHandle FTM_FACE_GET_GEOM("Face Geom"); +static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_POSITION("Position"); +static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_NORMAL("Normal"); +static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_TEXTURE("Texture"); +static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_COLOR("Color"); +static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_EMISSIVE("Emissive"); +static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_WEIGHTS("Weights"); +static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_TANGENT("Binormal"); + +static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_FEEDBACK("Face Feedback"); +static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_FEEDBACK_POSITION("Feedback Position"); +static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_FEEDBACK_NORMAL("Feedback Normal"); +static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_FEEDBACK_TEXTURE("Feedback Texture"); +static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_FEEDBACK_COLOR("Feedback Color"); +static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_FEEDBACK_EMISSIVE("Feedback Emissive"); +static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_FEEDBACK_BINORMAL("Feedback Binormal"); + +static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_INDEX("Index"); +static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_INDEX_TAIL("Tail"); +static LLTrace::BlockTimerStatHandle FTM_FACE_POSITION_STORE("Pos"); +static LLTrace::BlockTimerStatHandle FTM_FACE_TEXTURE_INDEX_STORE("TexIdx"); +static LLTrace::BlockTimerStatHandle FTM_FACE_POSITION_PAD("Pad"); +static LLTrace::BlockTimerStatHandle FTM_FACE_TEX_DEFAULT("Default"); +static LLTrace::BlockTimerStatHandle FTM_FACE_TEX_QUICK("Quick"); +static LLTrace::BlockTimerStatHandle FTM_FACE_TEX_QUICK_NO_XFORM("No Xform"); +static LLTrace::BlockTimerStatHandle FTM_FACE_TEX_QUICK_XFORM("Xform"); +static LLTrace::BlockTimerStatHandle FTM_FACE_TEX_QUICK_PLANAR("Quick Planar"); BOOL LLFace::getGeometryVolume(const LLVolume& volume, const S32 &f, - const LLMatrix4& mat_vert_in, const LLMatrix3& mat_norm_in, + const LLMatrix4a& mat_vert_in, const LLMatrix4a& mat_norm_in, const U16 &index_offset, bool force_rebuild) { - LLFastTimer t(FTM_FACE_GET_GEOM); + LL_RECORD_BLOCK_TIME(FTM_FACE_GET_GEOM); llassert(verify()); const LLVolumeFace &vf = volume.getVolumeFace(f); S32 num_vertices = (S32)vf.mNumVertices; @@ -1181,13 +1231,13 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, { if (gDebugGL) { - llwarns << "Index buffer overflow!" << llendl; - llwarns << "Indices Count: " << mIndicesCount + LL_WARNS() << "Index buffer overflow!" << LL_ENDL; + LL_WARNS() << "Indices Count: " << mIndicesCount << " VF Num Indices: " << num_indices << " Indices Index: " << mIndicesIndex - << " VB Num Indices: " << mVertexBuffer->getNumIndices() << llendl; - llwarns << " Face Index: " << f - << " Pool Type: " << mPoolType << llendl; + << " VB Num Indices: " << mVertexBuffer->getNumIndices() << LL_ENDL; + LL_WARNS() << " Face Index: " << f + << " Pool Type: " << mPoolType << LL_ENDL; } return FALSE; } @@ -1196,7 +1246,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, { if (gDebugGL) { - llwarns << "Vertex buffer overflow!" << llendl; + LL_WARNS() << "Vertex buffer overflow!" << LL_ENDL; } return FALSE; } @@ -1207,9 +1257,9 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, LLStrider tex_coords1; LLStrider norm; LLStrider colors; - LLStrider binorm; + LLStrider tangent; LLStrider indicesp; - LLStrider wght; + LLStrider wght; BOOL full_rebuild = force_rebuild || mDrawablep->isState(LLDrawable::REBUILD_VOLUME); @@ -1229,12 +1279,19 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, bool rebuild_emissive = rebuild_color && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_EMISSIVE); bool rebuild_tcoord = full_rebuild || mDrawablep->isState(LLDrawable::REBUILD_TCOORD); bool rebuild_normal = rebuild_pos && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_NORMAL); - bool rebuild_binormal = rebuild_pos && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_BINORMAL); + bool rebuild_tangent = rebuild_pos && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TANGENT); bool rebuild_weights = rebuild_pos && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_WEIGHT4); const LLTextureEntry *tep = mVObjp->getTE(f); const U8 bump_code = tep ? tep->getBumpmap() : 0; + if ( bump_code && rebuild_tcoord && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TANGENT) ) + { + LLMaterial* mat = tep->getMaterialParams().get(); + if( !mat || mat->getNormalID().isNull() ) + rebuild_tangent = true; + } + BOOL is_static = mDrawablep->isStatic(); BOOL is_global = is_static; @@ -1253,45 +1310,20 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, if (rebuild_color) // FALSE if tep == NULL { //decide if shiny goes in alpha channel of color - if (tep && - getPoolType() != LLDrawPool::POOL_ALPHA) // <--- alpha channel MUST contain transparency, not shiny + + if(mShinyInAlpha) { - bool shiny_in_alpha = false; - - if (LLPipeline::sRenderDeferred) - { //store shiny in alpha if we don't have a specular map - //if (!mat || mat->getSpecularID().isNull()) - { - shiny_in_alpha = true; - } - } - else - { - if(LLPipeline::sRenderBump && tep->getShiny()) - { - shiny_in_alpha = true; - } - } - if(shiny_in_alpha) - { - GLfloat alpha[4] = - { - 0.00f, - 0.25f, - 0.5f, - 0.75f - }; - - llassert(tep->getShiny() <= 3); - color.mV[3] = U8 (alpha[tep->getShiny()] * 255); - } + // Singu Note: Avoid casing. Store as LLColor4U. + static const LLColor4U shine_steps(LLColor4(0.f, .25f, .5f, 7.5f)); + llassert(tep->getShiny() <= 3); + color.mV[3] = shine_steps.mV[tep->getShiny()]; } } // INDICES if (full_rebuild) { - LLFastTimer t(FTM_FACE_GEOM_INDEX); + LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_INDEX); mVertexBuffer->getIndexStrider(indicesp, mIndicesIndex, mIndicesCount, map_range); volatile __m128i* dst = (__m128i*) indicesp.get(); @@ -1307,7 +1339,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, } { - LLFastTimer t(FTM_FACE_GEOM_INDEX_TAIL); + LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_INDEX_TAIL); U16* idx = (U16*) dst; for (S32 i = end*8; i < num_indices; ++i) @@ -1322,8 +1354,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, } } - LLMatrix4a mat_normal; - mat_normal.loadu(mat_norm_in); + const LLMatrix4a& mat_normal = mat_norm_in; F32 r = 0, os = 0, ot = 0, ms = 0, mt = 0, cos_ang = 0, sin_ang = 0; bool do_xform = false; @@ -1360,153 +1391,6 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, } static LLCachedControl use_transform_feedback("RenderUseTransformFeedback", false); - -#ifdef GL_TRANSFORM_FEEDBACK_BUFFER - if (use_transform_feedback && - gTransformPositionProgram.mProgramObject && //transform shaders are loaded - mVertexBuffer->useVBOs() && //target buffer is in VRAM - !rebuild_weights && //TODO: add support for weights - !volume.isUnique()) //source volume is NOT flexi - { //use transform feedback to pack vertex buffer - LLFastTimer t(FTM_FACE_GEOM_FEEDBACK); - LLGLEnable discard(GL_RASTERIZER_DISCARD); - LLVertexBuffer* buff = (LLVertexBuffer*) vf.mVertexBuffer.get(); - - if (vf.mVertexBuffer.isNull() || buff->getNumVerts() != vf.mNumVertices) - { - mVObjp->getVolume()->genBinormals(f); - LLFace::cacheFaceInVRAM(vf); - buff = (LLVertexBuffer*) vf.mVertexBuffer.get(); - } - - LLGLSLShader* cur_shader = LLGLSLShader::sCurBoundShaderPtr; - - gGL.pushMatrix(); - gGL.loadMatrix((GLfloat*) mat_vert_in.mMatrix); - - if (rebuild_pos) - { - LLFastTimer t(FTM_FACE_GEOM_FEEDBACK_POSITION); - gTransformPositionProgram.bind(); - - mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_VERTEX, mGeomIndex, mGeomCount); - - U8 index = mTextureIndex < 255 ? mTextureIndex : 0; - - S32 val = 0; - U8* vp = (U8*) &val; - vp[0] = index; - vp[1] = 0; - vp[2] = 0; - vp[3] = 0; - - gTransformPositionProgram.uniform1i("texture_index_in", val); - glBeginTransformFeedback(GL_POINTS); - buff->setBuffer(LLVertexBuffer::MAP_VERTEX); - - push_for_transform(buff, vf.mNumVertices, mGeomCount); - - glEndTransformFeedback(); - } - - if (rebuild_color) - { - LLFastTimer t(FTM_FACE_GEOM_FEEDBACK_COLOR); - gTransformColorProgram.bind(); - - mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_COLOR, mGeomIndex, mGeomCount); - - S32 val = *((S32*) color.mV); - - gTransformColorProgram.uniform1i("color_in", val); - glBeginTransformFeedback(GL_POINTS); - buff->setBuffer(LLVertexBuffer::MAP_VERTEX); - push_for_transform(buff, vf.mNumVertices, mGeomCount); - glEndTransformFeedback(); - } - - if (rebuild_emissive) - { - LLFastTimer t(FTM_FACE_GEOM_FEEDBACK_EMISSIVE); - gTransformColorProgram.bind(); - - mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_EMISSIVE, mGeomIndex, mGeomCount); - - U8 glow = (U8) llclamp((S32) (getTextureEntry()->getGlow()*255), 0, 255); - - S32 glow32 = glow | - (glow << 8) | - (glow << 16) | - (glow << 24); - - gTransformColorProgram.uniform1i("color_in", glow32); - glBeginTransformFeedback(GL_POINTS); - buff->setBuffer(LLVertexBuffer::MAP_VERTEX); - push_for_transform(buff, vf.mNumVertices, mGeomCount); - glEndTransformFeedback(); - } - - if (rebuild_normal) - { - LLFastTimer t(FTM_FACE_GEOM_FEEDBACK_NORMAL); - gTransformNormalProgram.bind(); - - mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_NORMAL, mGeomIndex, mGeomCount); - - glBeginTransformFeedback(GL_POINTS); - buff->setBuffer(LLVertexBuffer::MAP_NORMAL); - push_for_transform(buff, vf.mNumVertices, mGeomCount); - glEndTransformFeedback(); - } - - if (rebuild_binormal) - { - LLFastTimer t(FTM_FACE_GEOM_FEEDBACK_BINORMAL); - gTransformBinormalProgram.bind(); - - mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_BINORMAL, mGeomIndex, mGeomCount); - - glBeginTransformFeedback(GL_POINTS); - buff->setBuffer(LLVertexBuffer::MAP_BINORMAL); - push_for_transform(buff, vf.mNumVertices, mGeomCount); - glEndTransformFeedback(); - } - - if (rebuild_tcoord) - { - LLFastTimer t(FTM_FACE_GEOM_FEEDBACK_TEXTURE); - gTransformTexCoordProgram.bind(); - - mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_TEXCOORD0, mGeomIndex, mGeomCount); - - glBeginTransformFeedback(GL_POINTS); - buff->setBuffer(LLVertexBuffer::MAP_TEXCOORD0); - push_for_transform(buff, vf.mNumVertices, mGeomCount); - glEndTransformFeedback(); - - bool do_bump = bump_code && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD1); - - if (do_bump) - { - mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_TEXCOORD1, mGeomIndex, mGeomCount); - glBeginTransformFeedback(GL_POINTS); - buff->setBuffer(LLVertexBuffer::MAP_TEXCOORD0); - push_for_transform(buff, vf.mNumVertices, mGeomCount); - glEndTransformFeedback(); - } - } - - glBindBufferARB(GL_TRANSFORM_FEEDBACK_BUFFER, 0); - - gGL.popMatrix(); - - if (cur_shader) - { - cur_shader->bind(); - } - } - else -#endif { //if it's not fullbright and has no normals, bake sunlight based on face normal //bool bake_sunlight = !getTextureEntry()->getFullbright() && @@ -1514,7 +1398,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, if (rebuild_tcoord) { - LLFastTimer t(FTM_FACE_GEOM_TEXTURE); + LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_TEXTURE); //bump setup LLVector4a binormal_dir( -sin_ang, cos_ang, 0.f ); @@ -1522,72 +1406,83 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, LLVector4a bump_t_primary_light_ray(0.f, 0.f, 0.f); LLQuaternion bump_quat; - if (mDrawablep->isActive()) - { - bump_quat = LLQuaternion(mDrawablep->getRenderMatrix()); - } - - if (bump_code) + + if (!LLPipeline::sRenderDeferred) { - mVObjp->getVolume()->genBinormals(f); - F32 offset_multiple; - switch( bump_code ) + if (mDrawablep->isActive()) { + bump_quat = LLQuaternion(LLMatrix4(mDrawablep->getRenderMatrix().getF32ptr())); + } + + if (bump_code) + { + mVObjp->getVolume()->genTangents(f); + F32 offset_multiple; + switch (bump_code) + { case BE_NO_BUMP: - offset_multiple = 0.f; - break; + offset_multiple = 0.f; + break; case BE_BRIGHTNESS: case BE_DARKNESS: - if( mTexture.notNull() && mTexture->hasGLTexture()) - { - // Offset by approximately one texel - S32 cur_discard = mTexture->getDiscardLevel(); - S32 max_size = llmax( mTexture->getWidth(), mTexture->getHeight() ); - max_size <<= cur_discard; - const F32 ARTIFICIAL_OFFSET = 2.f; - offset_multiple = ARTIFICIAL_OFFSET / (F32)max_size; - } - else - { - offset_multiple = 1.f/256; - } - break; + if (mTexture[LLRender::DIFFUSE_MAP].notNull() && mTexture[LLRender::DIFFUSE_MAP]->hasGLTexture()) + { + // Offset by approximately one texel + S32 cur_discard = mTexture[LLRender::DIFFUSE_MAP]->getDiscardLevel(); + S32 max_size = llmax(mTexture[LLRender::DIFFUSE_MAP]->getWidth(), mTexture[LLRender::DIFFUSE_MAP]->getHeight()); + max_size <<= cur_discard; + const F32 ARTIFICIAL_OFFSET = 2.f; + offset_multiple = ARTIFICIAL_OFFSET / (F32)max_size; + } + else + { + offset_multiple = 1.f / 256; + } + break; default: // Standard bumpmap textures. Assumed to be 256x256 - offset_multiple = 1.f / 256; - break; - } + offset_multiple = 1.f / 256; + break; + } - F32 s_scale = 1.f; - F32 t_scale = 1.f; - if( tep ) - { - tep->getScale( &s_scale, &t_scale ); + F32 s_scale = 1.f; + F32 t_scale = 1.f; + if (tep) + { + tep->getScale(&s_scale, &t_scale); + } + // Use the nudged south when coming from above sun angle, such + // that emboss mapping always shows up on the upward faces of cubes when + // it's noon (since a lot of builders build with the sun forced to noon). + LLVector3 sun_ray = gSky.mVOSkyp->mBumpSunDir; + LLVector3 moon_ray = gSky.getMoonDirection(); + LLVector3& primary_light_ray = (sun_ray.mV[VZ] > 0) ? sun_ray : moon_ray; + + bump_s_primary_light_ray.load3((offset_multiple * s_scale * primary_light_ray).mV); + bump_t_primary_light_ray.load3((offset_multiple * t_scale * primary_light_ray).mV); } - // Use the nudged south when coming from above sun angle, such - // that emboss mapping always shows up on the upward faces of cubes when - // it's noon (since a lot of builders build with the sun forced to noon). - LLVector3 sun_ray = gSky.mVOSkyp->mBumpSunDir; - LLVector3 moon_ray = gSky.getMoonDirection(); - LLVector3& primary_light_ray = (sun_ray.mV[VZ] > 0) ? sun_ray : moon_ray; - - bump_s_primary_light_ray.load3((offset_multiple * s_scale * primary_light_ray).mV); - bump_t_primary_light_ray.load3((offset_multiple * t_scale * primary_light_ray).mV); } U8 texgen = getTextureEntry()->getTexGen(); if (rebuild_tcoord && texgen != LLTextureEntry::TEX_GEN_DEFAULT) { //planar texgen needs binormals - mVObjp->getVolume()->genBinormals(f); + mVObjp->getVolume()->genTangents(f); } U8 tex_mode = 0; + bool tex_anim = false; + + LLVOVolume* vobj = (LLVOVolume*) (LLViewerObject*) mVObjp; + tex_mode = vobj->mTexAnimMode; + + if (vobj->mTextureAnimp) + { //texture animation is in play, override specular and normal map tex coords with diffuse texcoords + tex_anim = true; + } + if (isState(TEXTURE_ANIM)) { - LLVOVolume* vobj = (LLVOVolume*) (LLViewerObject*) mVObjp; - tex_mode = vobj->mTexAnimMode; - if (!tex_mode) { clearState(TEXTURE_ANIM); @@ -1603,7 +1498,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, do_xform = false; } - if (getVirtualSize() >= MIN_TEX_ANIM_SIZE) + if (getVirtualSize() >= MIN_TEX_ANIM_SIZE || isState(LLFace::RIGGED)) { //don't override texture transform during tc bake tex_mode = 0; } @@ -1612,7 +1507,16 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, LLVector4a scalea; scalea.load3(scale.mV); + LLMaterial* mat = tep->getMaterialParams().get(); + bool do_bump = bump_code && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD1); + + if (mat && !do_bump) + { + do_bump = mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD1) + || mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD2); + } + bool do_tex_mat = tex_mode && mTextureMatrix; if (!do_bump) @@ -1621,18 +1525,18 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, if (texgen != LLTextureEntry::TEX_GEN_PLANAR) { - LLFastTimer t(FTM_FACE_TEX_QUICK); + LL_RECORD_BLOCK_TIME(FTM_FACE_TEX_QUICK); if (!do_tex_mat) { if (!do_xform) { - LLFastTimer t(FTM_FACE_TEX_QUICK_NO_XFORM); + LL_RECORD_BLOCK_TIME(FTM_FACE_TEX_QUICK_NO_XFORM); S32 tc_size = (num_vertices*2*sizeof(F32)+0xF) & ~0xF; LLVector4a::memcpyNonAliased16((F32*) tex_coords0.get(), (F32*) vf.mTexCoords, tc_size); } else { - LLFastTimer t(FTM_FACE_TEX_QUICK_XFORM); + LL_RECORD_BLOCK_TIME(FTM_FACE_TEX_QUICK_XFORM); F32* dst = (F32*) tex_coords0.get(); LLVector4a* src = (LLVector4a*) vf.mTexCoords; @@ -1670,22 +1574,18 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, else { //do tex mat, no texgen, no atlas, no bump for (S32 i = 0; i < num_vertices; i++) - { - LLVector2 tc(vf.mTexCoords[i]); + { //LLVector4a& norm = vf.mNormals[i]; //LLVector4a& center = *(vf.mCenter); - - LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f); - tmp = tmp * *mTextureMatrix; - tc.mV[0] = tmp.mV[0]; - tc.mV[1] = tmp.mV[1]; - *tex_coords0++ = tc; + LLVector4a tc(vf.mTexCoords[i].mV[VX],vf.mTexCoords[i].mV[VY],0.f); + mTextureMatrix->affineTransform(tc,tc); + (tex_coords0++)->set(tc.getF32ptr()); } } } else { //no bump, no atlas, tex gen planar - LLFastTimer t(FTM_FACE_TEX_QUICK_PLANAR); + LL_RECORD_BLOCK_TIME(FTM_FACE_TEX_QUICK_PLANAR); if (do_tex_mat) { for (S32 i = 0; i < num_vertices; i++) @@ -1697,12 +1597,9 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, vec.mul(scalea); planarProjection(tc, norm, center, vec); - LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f); - tmp = tmp * *mTextureMatrix; - tc.mV[0] = tmp.mV[0]; - tc.mV[1] = tmp.mV[1]; - - *tex_coords0++ = tc; + LLVector4a tmp(tc.mV[VX],tc.mV[VY],0.f); + mTextureMatrix->affineTransform(tmp,tmp); + (tex_coords0++)->set(tmp.getF32ptr()); } } else @@ -1730,51 +1627,102 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, } else { //either bump mapped or in atlas, just do the whole expensive loop - LLFastTimer t(FTM_FACE_TEX_DEFAULT); + LL_RECORD_BLOCK_TIME(FTM_FACE_TEX_DEFAULT); std::vector bump_tc; + if (mat && !mat->getNormalID().isNull()) + { //writing out normal and specular texture coordinates, not bump offsets + do_bump = false; + } + LLStrider dst; - mVertexBuffer->getTexCoord0Strider(dst, mGeomIndex, mGeomCount, map_range); + for (U32 ch = 0; ch < 3; ++ch) + { + switch (ch) + { + case 0: + mVertexBuffer->getTexCoord0Strider(dst, mGeomIndex, mGeomCount, map_range); + break; + case 1: + if (mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD1)) + { + mVertexBuffer->getTexCoord1Strider(dst, mGeomIndex, mGeomCount, map_range); + if (mat && !tex_anim) + { + r = mat->getNormalRotation(); + mat->getNormalOffset(os, ot); + mat->getNormalRepeat(ms, mt); + + cos_ang = cos(r); + sin_ang = sin(r); + + } + } + else + { + continue; + } + break; + case 2: + if (mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD2)) + { + mVertexBuffer->getTexCoord2Strider(dst, mGeomIndex, mGeomCount, map_range); + if (mat && !tex_anim) + { + r = mat->getSpecularRotation(); + mat->getSpecularOffset(os, ot); + mat->getSpecularRepeat(ms, mt); + + cos_ang = cos(r); + sin_ang = sin(r); + } + } + else + { + continue; + } + break; + } + - - for (S32 i = 0; i < num_vertices; i++) - { - LLVector2 tc(vf.mTexCoords[i]); + for (S32 i = 0; i < num_vertices; i++) + { + LLVector2 tc(vf.mTexCoords[i]); - LLVector4a& norm = vf.mNormals[i]; + LLVector4a& norm = vf.mNormals[i]; - LLVector4a& center = *(vf.mCenter); + LLVector4a& center = *(vf.mCenter); - if (texgen != LLTextureEntry::TEX_GEN_DEFAULT) - { - LLVector4a vec = vf.mPositions[i]; + if (texgen != LLTextureEntry::TEX_GEN_DEFAULT) + { + LLVector4a vec = vf.mPositions[i]; - vec.mul(scalea); + vec.mul(scalea); - if (texgen == LLTextureEntry::TEX_GEN_PLANAR) - { - planarProjection(tc, norm, center, vec); + if (texgen == LLTextureEntry::TEX_GEN_PLANAR) + { + planarProjection(tc, norm, center, vec); + } } - } - if (tex_mode && mTextureMatrix) - { - LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f); - tmp = tmp * *mTextureMatrix; - tc.mV[0] = tmp.mV[0]; - tc.mV[1] = tmp.mV[1]; - } - else - { - xform(tc, cos_ang, sin_ang, os, ot, ms, mt); - } + if (tex_mode && mTextureMatrix) + { + LLVector4a tmp(tc.mV[VX],tc.mV[VY],0.f); + mTextureMatrix->affineTransform(tmp,tmp); + tc.set(tmp.getF32ptr()); + } + else + { + xform(tc, cos_ang, sin_ang, os, ot, ms, mt); + } - *dst++ = tc; - if (do_bump) - { - bump_tc.push_back(tc); + *dst++ = tc; + if (do_bump) + { + bump_tc.push_back(tc); + } } } @@ -1783,17 +1731,20 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, mVertexBuffer->flush(); } - if (do_bump) + if ( !LLPipeline::sRenderDeferred && do_bump ) { mVertexBuffer->getTexCoord1Strider(tex_coords1, mGeomIndex, mGeomCount, map_range); for (S32 i = 0; i < num_vertices; i++) { - LLVector4a tangent; - tangent.setCross3(vf.mBinormals[i], vf.mNormals[i]); + LLVector4a tangent = vf.mTangents[i]; + LLVector4a binorm; + binorm.setCross3(vf.mNormals[i], tangent); + binorm.mul(tangent.getF32ptr()[3]); + LLMatrix4a tangent_to_object; - tangent_to_object.setRows(tangent, vf.mBinormals[i], vf.mNormals[i]); + tangent_to_object.setRows(tangent, binorm, vf.mNormals[i]); LLVector4a t; tangent_to_object.rotate(binormal_dir, t); LLVector4a binormal; @@ -1826,32 +1777,39 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, if (rebuild_pos) { - LLFastTimer t(FTM_FACE_GEOM_POSITION); + LLVector4a* src = vf.mPositions; + + //_mm_prefetch((char*)src, _MM_HINT_T0); + + LLVector4a* end = src+num_vertices; + //LLVector4a* end_64 = end-4; + + //LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_POSITION); llassert(num_vertices > 0); mVertexBuffer->getVertexStrider(vert, mGeomIndex, mGeomCount, map_range); + const LLMatrix4a& mat_vert = mat_vert_in; - LLMatrix4a mat_vert; - mat_vert.loadu(mat_vert_in); + F32* dst = (F32*) vert.get(); + F32* end_f32 = dst+mGeomCount*4; + + //_mm_prefetch((char*)dst, _MM_HINT_NTA); + //_mm_prefetch((char*)src, _MM_HINT_NTA); + + //_mm_prefetch((char*)dst, _MM_HINT_NTA); - LLVector4a* src = vf.mPositions; - volatile F32* dst = (volatile F32*) vert.get(); - volatile F32* end = dst+num_vertices*4; - LLVector4a res; + LLVector4a res0; //,res1,res2,res3; LLVector4a texIdx; - U8 index = mTextureIndex < 255 ? mTextureIndex : 0; + S32 index = mTextureIndex < 255 ? mTextureIndex : 0; F32 val = 0.f; - U8* vp = (U8*) &val; - vp[0] = index; - vp[1] = 0; - vp[2] = 0; - vp[3] = 0; - + S32* vp = (S32*) &val; + *vp = index; + llassert(index <= LLGLSLShader::sIndexedTextureChannels-1); LLVector4Logical mask; @@ -1860,29 +1818,53 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, texIdx.set(0,0,0,val); + LLVector4a tmp; + { - LLFastTimer t(FTM_FACE_POSITION_STORE); - LLVector4a tmp; + //LL_RECORD_BLOCK_TIME(FTM_FACE_POSITION_STORE); + + /*if (num_vertices > 4) + { //more than 64 bytes + while (src < end_64) + { + _mm_prefetch((char*)src + 64, _MM_HINT_T0); + _mm_prefetch((char*)dst + 64, _MM_HINT_T0); + + mat_vert.affineTransform(*src, res0); + tmp.setSelectWithMask(mask, texIdx, res0); + tmp.store4a((F32*) dst); + + mat_vert.affineTransform(*(src+1), res1); + tmp.setSelectWithMask(mask, texIdx, res1); + tmp.store4a((F32*) dst+4); + + mat_vert.affineTransform(*(src+2), res2); + tmp.setSelectWithMask(mask, texIdx, res2); + tmp.store4a((F32*) dst+8); + + mat_vert.affineTransform(*(src+3), res3); + tmp.setSelectWithMask(mask, texIdx, res3); + tmp.store4a((F32*) dst+12); - do + dst += 16; + src += 4; + } + }*/ + + while (src < end) { - mat_vert.affineTransform(*src++, res); - tmp.setSelectWithMask(mask, texIdx, res); + mat_vert.affineTransform(*src++, res0); + tmp.setSelectWithMask(mask, texIdx, res0); tmp.store4a((F32*) dst); dst += 4; } - while(dst < end); } { - LLFastTimer t(FTM_FACE_POSITION_PAD); - S32 aligned_pad_vertices = mGeomCount - num_vertices; - res.set(res[0], res[1], res[2], 0.f); - - while (aligned_pad_vertices > 0) + //LL_RECORD_BLOCK_TIME(FTM_FACE_POSITION_PAD); + while (dst < end_f32) { - --aligned_pad_vertices; - res.store4a((F32*) dst); + res0.store4a((F32*) dst); dst += 4; } } @@ -1896,15 +1878,16 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, if (rebuild_normal) { - LLFastTimer t(FTM_FACE_GEOM_NORMAL); + //LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_NORMAL); mVertexBuffer->getNormalStrider(norm, mGeomIndex, mGeomCount, map_range); F32* normals = (F32*) norm.get(); - - for (S32 i = 0; i < num_vertices; i++) + LLVector4a* src = vf.mNormals; + LLVector4a* end = src+num_vertices; + + while (src < end) { LLVector4a normal; - mat_normal.rotate(vf.mNormals[i], normal); - normal.normalize3fast(); + mat_normal.rotate(*src++, normal); normal.store4a(normals); normals += 4; } @@ -1915,19 +1898,37 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, } } - if (rebuild_binormal) + if (rebuild_tangent) { - LLFastTimer t(FTM_FACE_GEOM_BINORMAL); - mVertexBuffer->getBinormalStrider(binorm, mGeomIndex, mGeomCount, map_range); - F32* binormals = (F32*) binorm.get(); - - for (S32 i = 0; i < num_vertices; i++) - { - LLVector4a binormal; - mat_normal.rotate(vf.mBinormals[i], binormal); - binormal.normalize3fast(); - binormal.store4a(binormals); - binormals += 4; + LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_TANGENT); + mVertexBuffer->getTangentStrider(tangent, mGeomIndex, mGeomCount, map_range); + F32* tangents = (F32*) tangent.get(); + + mVObjp->getVolume()->genTangents(f); + + LLVector4a* src = vf.mTangents; + LLVector4a* end = vf.mTangents+num_vertices; + LLVector4a* src2 = vf.mNormals; + LLVector4a* end2 = vf.mNormals+num_vertices; + + LLMaterial* mat = tep->getMaterialParams().get(); + F32 rot = RAD_TO_DEG * ( (mat && mat->getNormalID().notNull()) ? mat->getNormalRotation() : r); + bool rotate_tangent = src2 && !is_approx_equal(rot, 360.f) && !is_approx_zero(rot); + + while (src < end) + { + LLVector4a tangent_out = *src; + if (rotate_tangent && src2 < end2) + { + gGL.genRot(rot, *src2++).rotate(tangent_out, tangent_out); + } + mat_normal.rotate(tangent_out, tangent_out); + tangent_out.normalize3fast(); + tangent_out.copyComponent<3>(*src); + tangent_out.store4a(tangents); + + src++; + tangents += 4; } if (map_range) @@ -1938,10 +1939,12 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, if (rebuild_weights && vf.mWeights) { - LLFastTimer t(FTM_FACE_GEOM_WEIGHTS); + LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_WEIGHTS); mVertexBuffer->getWeight4Strider(wght, mGeomIndex, mGeomCount, map_range); - F32* weights = (F32*) wght.get(); - LLVector4a::memcpyNonAliased16(weights, (F32*) vf.mWeights, num_vertices*4*sizeof(F32)); + for(S32 i=0;iflush(); @@ -1950,7 +1953,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, if (rebuild_color && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_COLOR) ) { - LLFastTimer t(FTM_FACE_GEOM_COLOR); + LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_COLOR); mVertexBuffer->getColorStrider(colors, mGeomIndex, mGeomCount, map_range); LLVector4a src; @@ -1981,7 +1984,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, if (rebuild_emissive) { - LLFastTimer t(FTM_FACE_GEOM_EMISSIVE); + LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_EMISSIVE); LLStrider emissive; mVertexBuffer->getEmissiveStrider(emissive, mGeomIndex, mGeomCount, map_range); @@ -2046,16 +2049,23 @@ BOOL LLFace::hasMedia() const { return TRUE ; } - if(mTexture.notNull()) + if(mTexture[LLRender::DIFFUSE_MAP].notNull()) { - return mTexture->hasParcelMedia() ; //if has a parcel media + return mTexture[LLRender::DIFFUSE_MAP]->hasParcelMedia() ; //if has a parcel media } return FALSE ; //no media. } + const F32 LEAST_IMPORTANCE = 0.05f ; const F32 LEAST_IMPORTANCE_FOR_LARGE_IMAGE = 0.3f ; +void LLFace::resetVirtualSize() +{ + setVirtualSize(0.f); + mImportanceToCamera = 0.f; +} + F32 LLFace::getTextureVirtualSize() { F32 radius; @@ -2091,11 +2101,11 @@ F32 LLFace::getTextureVirtualSize() } face_area = LLFace::adjustPixelArea(mImportanceToCamera, face_area); - if (/*mImportanceToCamera < 1.0f && */face_area > LLViewerTexture::sMinLargeImageSize) //if is large image, shrink face_area by considering the partial overlapping. + if(face_area > LLViewerTexture::sMinLargeImageSize) //if is large image, shrink face_area by considering the partial overlapping. { - if (mImportanceToCamera > LEAST_IMPORTANCE_FOR_LARGE_IMAGE && mTexture.notNull() && mTexture->isLargeImage()) - { - face_area *= adjustPartialOverlapPixelArea(cos_angle_to_view_dir, radius); + if(mImportanceToCamera > LEAST_IMPORTANCE_FOR_LARGE_IMAGE && mTexture[LLRender::DIFFUSE_MAP].notNull() && mTexture[LLRender::DIFFUSE_MAP]->isLargeImage()) + { + face_area *= adjustPartialOverlapPixelArea(cos_angle_to_view_dir, radius ); } } @@ -2121,9 +2131,18 @@ BOOL LLFace::calcPixelArea(F32& cos_angle_to_view_dir, F32& radius) LLVector4a t; t.load3(camera->getOrigin().mV); lookAt.setSub(center, t); + F32 dist = lookAt.getLength3().getF32(); dist = llmax(dist-size.getLength3().getF32(), 0.001f); - lookAt.normalize3fast() ; + //ramp down distance for nearby objects + if (dist < 16.f) + { + dist /= 16.f; + dist *= dist; + dist *= 16.f; + } + + lookAt.normalize3fast(); //get area of circle around node F32 app_angle = atanf((F32) sqrt(size_squared) / dist); @@ -2223,8 +2242,6 @@ F32 LLFace::calcImportanceToCamera(F32 cos_angle_to_view_dir, F32 dist) return 0.f ; } - //F32 camera_relative_speed = camera_moving_speed * (lookAt * LLViewerCamera::getInstance()->getVelocityDir()) ; - S32 i = 0 ; for(i = 0; i < FACE_IMPORTANCE_LEVEL && dist > FACE_IMPORTANCE_TO_CAMERA_OVER_DISTANCE[i][0]; ++i); i = llmin(i, FACE_IMPORTANCE_LEVEL - 1) ; @@ -2265,16 +2282,7 @@ BOOL LLFace::verify(const U32* indices_array) const BOOL ok = TRUE; if( mVertexBuffer.isNull() ) - { - if( mGeomCount ) - { - // This happens before teleports as faces are torn down. - // Stop the crash in DEV-31893 with a null pointer check, - // but present this info. - // To clean up the log, the geometry could be cleared, or the - // face could otherwise be marked for no ::verify. - //AIFIXME: llinfos << "Face with no vertex buffer and " << mGeomCount << " mGeomCount" << llendl; - } + { //no vertex buffer, face is implicitly valid return TRUE; } @@ -2282,7 +2290,7 @@ BOOL LLFace::verify(const U32* indices_array) const if ((mGeomIndex + mGeomCount) > mVertexBuffer->getNumVerts()) { ok = FALSE; - llinfos << "Face references invalid vertices!" << llendl; + LL_INFOS() << "Face references invalid vertices!" << LL_ENDL; } S32 indices_count = (S32)getIndicesCount(); @@ -2295,13 +2303,13 @@ BOOL LLFace::verify(const U32* indices_array) const if (indices_count > LL_MAX_INDICES_COUNT) { ok = FALSE; - llinfos << "Face has bogus indices count" << llendl; + LL_INFOS() << "Face has bogus indices count" << LL_ENDL; } if (mIndicesIndex + mIndicesCount > (U32)mVertexBuffer->getNumIndices()) { ok = FALSE; - llinfos << "Face references invalid indices!" << llendl; + LL_INFOS() << "Face references invalid indices!" << LL_ENDL; } #if 0 @@ -2315,14 +2323,14 @@ BOOL LLFace::verify(const U32* indices_array) const S32 delta = indicesp[i] - geom_start; if (0 > delta) { - llwarns << "Face index too low!" << llendl; - llinfos << "i:" << i << " Index:" << indicesp[i] << " GStart: " << geom_start << llendl; + LL_WARNS() << "Face index too low!" << LL_ENDL; + LL_INFOS() << "i:" << i << " Index:" << indicesp[i] << " GStart: " << geom_start << LL_ENDL; ok = FALSE; } else if (delta >= geom_count) { - llwarns << "Face index too high!" << llendl; - llinfos << "i:" << i << " Index:" << indicesp[i] << " GEnd: " << geom_start + geom_count << llendl; + LL_WARNS() << "Face index too high!" << LL_ENDL; + LL_INFOS() << "i:" << i << " Index:" << indicesp[i] << " GEnd: " << geom_start + geom_count << LL_ENDL; ok = FALSE; } } @@ -2364,7 +2372,7 @@ void LLFace::renderSetColor() const } } -S32 LLFace::pushVertices(const U16* index_array) const +S32 LLFace::pushVertices() const { if (mIndicesCount) { @@ -2380,24 +2388,24 @@ S32 LLFace::pushVertices(const U16* index_array) const return mIndicesCount; } -const LLMatrix4& LLFace::getRenderMatrix() const +const LLMatrix4a& LLFace::getRenderMatrix() const { return mDrawablep->getRenderMatrix(); } -S32 LLFace::renderElements(const U16 *index_array) const +S32 LLFace::renderElements() const { S32 ret = 0; if (isState(GLOBAL)) { - ret = pushVertices(index_array); + ret = pushVertices(); } else { gGL.pushMatrix(); - gGL.multMatrix((float*)getRenderMatrix().mMatrix); - ret = pushVertices(index_array); + gGL.multMatrix(getRenderMatrix()); + ret = pushVertices(); gGL.popMatrix(); } @@ -2422,8 +2430,7 @@ S32 LLFace::renderIndexed(U32 mask) } mVertexBuffer->setBuffer(mask); - U16* index_array = (U16*) mVertexBuffer->getIndicesPointer(); - return renderElements(index_array); + return renderElements(); } //============================================================================ @@ -2456,22 +2463,41 @@ LLVector3 LLFace::getPositionAgent() const } else { - return mCenterLocal * getRenderMatrix(); + LLVector4a center_local; + center_local.load3(mCenterLocal.mV); + getRenderMatrix().affineTransform(center_local,center_local); + return LLVector3(center_local.getF32ptr()); } } -LLViewerTexture* LLFace::getTexture() const + +LLViewerTexture* LLFace::getTexture(U32 ch) const { - return mTexture ; + llassert(ch < LLRender::NUM_TEXTURE_CHANNELS); + + return mTexture[ch] ; } void LLFace::setVertexBuffer(LLVertexBuffer* buffer) { + if (buffer) + { + LLSculptIDSize::instance().inc(mDrawablep, buffer->getSize() + buffer->getIndicesSize()); + } + + if (mVertexBuffer) + { + LLSculptIDSize::instance().dec(mDrawablep); + } mVertexBuffer = buffer; llassert(verify()); } void LLFace::clearVertexBuffer() { + if (mVertexBuffer) + { + LLSculptIDSize::instance().dec(mDrawablep); + } mVertexBuffer = NULL; } @@ -2479,6 +2505,22 @@ void LLFace::clearVertexBuffer() U32 LLFace::getRiggedDataMask(U32 type) { static const U32 rigged_data_mask[] = { + LLDrawPoolAvatar::RIGGED_MATERIAL_MASK, + LLDrawPoolAvatar::RIGGED_MATERIAL_ALPHA_VMASK, + LLDrawPoolAvatar::RIGGED_MATERIAL_ALPHA_MASK_MASK, + LLDrawPoolAvatar::RIGGED_MATERIAL_ALPHA_EMISSIVE_MASK, + LLDrawPoolAvatar::RIGGED_SPECMAP_VMASK, + LLDrawPoolAvatar::RIGGED_SPECMAP_BLEND_MASK, + LLDrawPoolAvatar::RIGGED_SPECMAP_MASK_MASK, + LLDrawPoolAvatar::RIGGED_SPECMAP_EMISSIVE_MASK, + LLDrawPoolAvatar::RIGGED_NORMMAP_VMASK, + LLDrawPoolAvatar::RIGGED_NORMMAP_BLEND_MASK, + LLDrawPoolAvatar::RIGGED_NORMMAP_MASK_MASK, + LLDrawPoolAvatar::RIGGED_NORMMAP_EMISSIVE_MASK, + LLDrawPoolAvatar::RIGGED_NORMSPEC_VMASK, + LLDrawPoolAvatar::RIGGED_NORMSPEC_BLEND_MASK, + LLDrawPoolAvatar::RIGGED_NORMSPEC_MASK_MASK, + LLDrawPoolAvatar::RIGGED_NORMSPEC_EMISSIVE_MASK, LLDrawPoolAvatar::RIGGED_SIMPLE_MASK, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_MASK, LLDrawPoolAvatar::RIGGED_SHINY_MASK, diff --git a/indra/newview/llface.h b/indra/newview/llface.h index 68cdcadde6..e0e478df6e 100644 --- a/indra/newview/llface.h +++ b/indra/newview/llface.h @@ -2,31 +2,25 @@ * @file llface.h * @brief LLFace class definition * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -43,7 +37,6 @@ #include "v4coloru.h" #include "llquaternion.h" #include "xform.h" -#include "lldarrayptr.h" #include "llvertexbuffer.h" #include "llviewertexture.h" #include "llstat.h" @@ -82,7 +75,7 @@ class LLFace const LLFace& operator=(const LLFace& rhs) { - llerrs << "Illegal operation!" << llendl; + LL_ERRS() << "Illegal operation!" << LL_ENDL; return *this; } @@ -106,8 +99,8 @@ class LLFace LLFace(LLDrawable* drawablep, LLViewerObject* objp) { init(drawablep, objp); } ~LLFace() { destroy(); } - const LLMatrix4& getWorldMatrix() const { return mVObjp->getWorldMatrix(mXform); } - const LLMatrix4& getRenderMatrix() const; + const LLMatrix4a& getWorldMatrix() const { return mVObjp->getWorldMatrix(mXform); } + const LLMatrix4a& getRenderMatrix() const; U32 getIndicesCount() const { return mIndicesCount; }; S32 getIndicesStart() const { return mIndicesIndex; }; U16 getGeomCount() const { return mGeomCount; } // vertex count for this face @@ -115,13 +108,17 @@ class LLFace U16 getGeomStart() const { return mGeomIndex; } // index into draw pool void setTextureIndex(U8 index); U8 getTextureIndex() const { return mTextureIndex; } + void setTexture(U32 ch, LLViewerTexture* tex); void setTexture(LLViewerTexture* tex) ; - void switchTexture(LLViewerTexture* new_texture); + void setDiffuseMap(LLViewerTexture* tex); + void setNormalMap(LLViewerTexture* tex); + void setSpecularMap(LLViewerTexture* tex); + void switchTexture(U32 ch, LLViewerTexture* new_texture); void dirtyTexture(); LLXformMatrix* getXform() const { return mXform; } BOOL hasGeometry() const { return mGeomCount > 0; } LLVector3 getPositionAgent() const; - LLVector2 surfaceToTexture(LLVector2 surface_coord, LLVector3 position, LLVector3 normal); + LLVector2 surfaceToTexture(LLVector2 surface_coord, const LLVector4a& position, const LLVector4a& normal); void getPlanarProjectedParams(LLQuaternion* face_rot, LLVector3* face_pos, F32* scale) const; bool calcAlignedPlanarTE(const LLFace* align_to, LLVector2* st_offset, LLVector2* st_scale, F32* st_rot) const; @@ -135,14 +132,14 @@ class LLFace F32 getVirtualSize() const { return mVSize; } F32 getPixelArea() const { return mPixelArea; } - S32 getIndexInTex() const {return mIndexInTex ;} - void setIndexInTex(S32 index) { mIndexInTex = index ;} + S32 getIndexInTex(U32 ch) const {llassert(ch < LLRender::NUM_TEXTURE_CHANNELS); return mIndexInTex[ch];} + void setIndexInTex(U32 ch, S32 index) { llassert(ch < LLRender::NUM_TEXTURE_CHANNELS); mIndexInTex[ch] = index ;} void renderSetColor() const; - S32 renderElements(const U16 *index_array) const; + S32 renderElements() const; S32 renderIndexed (); S32 renderIndexed (U32 mask); - S32 pushVertices(const U16* index_array) const; + S32 pushVertices() const; void setWorldMatrix(const LLMatrix4& mat); const LLTextureEntry* getTextureEntry() const { return mVObjp->getTE(mTEOffset); } @@ -154,7 +151,7 @@ class LLFace S32 getLOD() const { return mVObjp.notNull() ? mVObjp->getLOD() : 0; } void setPoolType(U32 type) { mPoolType = type; } S32 getTEOffset() { return mTEOffset; } - LLViewerTexture* getTexture() const; + LLViewerTexture* getTexture(U32 ch = LLRender::DIFFUSE_MAP) const; void setViewerObject(LLViewerObject* object); void setPool(LLFacePool *pool, LLViewerTexture *texturep); @@ -175,7 +172,7 @@ class LLFace bool canRenderAsMask(); // logic helper BOOL getGeometryVolume(const LLVolume& volume, const S32 &f, - const LLMatrix4& mat_vert, const LLMatrix3& mat_normal, + const LLMatrix4a& mat_vert, const LLMatrix4a& mat_normal, const U16 &index_offset, bool force_rebuild = false); @@ -185,7 +182,7 @@ class LLFace LLStrider &normals, LLStrider &texCoords, LLStrider &vertex_weights, - LLStrider &clothing_weights); + LLStrider &clothing_weights); // For volumes, etc. U16 getGeometry(LLStrider &vertices, @@ -196,10 +193,9 @@ class LLFace S32 getColors(LLStrider &colors); S32 getIndices(LLStrider &indices); - void setSize(S32 numVertices, const S32 num_indices = 0, bool align = false); + void setSize(S32 numVertices, S32 num_indices = 0, bool align = false); - BOOL genVolumeBBoxes(const LLVolume &volume, S32 f, - const LLMatrix4& mat, const LLMatrix3& inv_trans_mat, BOOL global_volume = FALSE); + BOOL genVolumeBBoxes(const LLVolume &volume, S32 f,const LLMatrix4a& mat, BOOL global_volume = FALSE); void init(LLDrawable* drawablep, LLViewerObject* objp); void destroy(); @@ -224,9 +220,13 @@ class LLFace F32 getTextureVirtualSize() ; F32 getImportanceToCamera()const {return mImportanceToCamera ;} + void resetVirtualSize(); void setHasMedia(bool has_media) { mHasMedia = has_media ;} BOOL hasMedia() const ; + + BOOL switchTexture() ; + //vertex buffer tracking void setVertexBuffer(LLVertexBuffer* buffer); void clearVertexBuffer(); //sets mVertexBuffer and mLastVertexBuffer to NULL @@ -237,8 +237,11 @@ class LLFace static U32 getRiggedDataMask(U32 type); + void notifyAboutCreatingTexture(LLViewerTexture *texture); + void notifyAboutMissingAsset(LLViewerTexture *texture); + public: //aligned members - LLVector4a mExtents[2]; + LL_ALIGN_16(LLVector4a mExtents[2]); private: F32 adjustPartialOverlapPixelArea(F32 cos_angle_to_view_dir, F32 radius ); @@ -257,9 +260,11 @@ class LLFace F32 mLastUpdateTime; F32 mLastSkinTime; F32 mLastMoveTime; - LLMatrix4* mTextureMatrix; + LLMatrix4a* mTextureMatrix; LLDrawInfo* mDrawInfo; + bool mShinyInAlpha; + private: LLPointer mVertexBuffer; @@ -273,10 +278,12 @@ class LLFace U8 mTextureIndex; // index of texture channel to use for pseudo-atlasing U32 mIndicesCount; U32 mIndicesIndex; // index into draw pool for indices (yeah, I know!) - S32 mIndexInTex ; + S32 mIndexInTex[LLRender::NUM_TEXTURE_CHANNELS]; LLXformMatrix* mXform; - LLPointer mTexture; + + LLPointer mTexture[LLRender::NUM_TEXTURE_CHANNELS]; + LLPointer mDrawablep; LLPointer mVObjp; S32 mTEOffset; diff --git a/indra/newview/llface.inl b/indra/newview/llface.inl index 176c73e38e..85c35a88f3 100644 --- a/indra/newview/llface.inl +++ b/indra/newview/llface.inl @@ -2,31 +2,25 @@ * @file llface.inl * @brief Inline functions for LLFace * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/newview/llfasttimerview.cpp b/indra/newview/llfasttimerview.cpp index 30864755c6..98bdcf0f63 100644 --- a/indra/newview/llfasttimerview.cpp +++ b/indra/newview/llfasttimerview.cpp @@ -256,7 +256,7 @@ BOOL LLFastTimerView::handleHover(S32 x, S32 y, MASK mask) if (hasMouseCapture()) { F32 lerp = llclamp(1.f - (F32) (x - mGraphRect.mLeft) / (F32) mGraphRect.getWidth(), 0.f, 1.f); - mScrollIndex = llround( lerp * (F32)(LLFastTimer::NamedTimer::HISTORY_NUM - MAX_VISIBLE_HISTORY)); + mScrollIndex = ll_round( lerp * (F32)(LLFastTimer::NamedTimer::HISTORY_NUM - MAX_VISIBLE_HISTORY)); mScrollIndex = llclamp( mScrollIndex, 0, LLFastTimer::getLastFrameIndex()); return TRUE; } @@ -298,9 +298,9 @@ BOOL LLFastTimerView::handleHover(S32 x, S32 y, MASK mask) } mToolTipRect.set(mBarStart[mHoverBarIndex][i], - mBarRect.mBottom + llround(((F32)(MAX_VISIBLE_HISTORY - mHoverBarIndex + 1)) * ((F32)mBarRect.getHeight() / ((F32)MAX_VISIBLE_HISTORY + 2.f))), + mBarRect.mBottom + ll_round(((F32)(MAX_VISIBLE_HISTORY - mHoverBarIndex + 1)) * ((F32)mBarRect.getHeight() / ((F32)MAX_VISIBLE_HISTORY + 2.f))), mBarEnd[mHoverBarIndex][i], - mBarRect.mBottom + llround((F32)(MAX_VISIBLE_HISTORY - mHoverBarIndex) * ((F32)mBarRect.getHeight() / ((F32)MAX_VISIBLE_HISTORY + 2.f)))); + mBarRect.mBottom + ll_round((F32)(MAX_VISIBLE_HISTORY - mHoverBarIndex) * ((F32)mBarRect.getHeight() / ((F32)MAX_VISIBLE_HISTORY + 2.f)))); } if ((*it)->getCollapsed()) @@ -397,13 +397,13 @@ BOOL LLFastTimerView::handleScrollWheel(S32 x, S32 y, S32 clicks) return TRUE; } -static LLFastTimer::DeclareTimer FTM_RENDER_TIMER("Timers", true); +static LLTrace::BlockTimerStatHandle FTM_RENDER_TIMER("Timers", true); static std::map sTimerColors; void LLFastTimerView::draw() { - LLFastTimer t(FTM_RENDER_TIMER); + LL_RECORD_BLOCK_TIME(FTM_RENDER_TIMER); std::string tdesc; @@ -421,7 +421,7 @@ void LLFastTimerView::draw() S32 left, top, right, bottom; S32 x, y, barw, barh, dx, dy; S32 texth; - LLPointer box_imagep = LLUI::getUIImage("rounded_square.tga"); + LLPointer box_imagep = LLUI::getUIImage("Rounded_Square"); // Draw the window background gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); @@ -432,7 +432,7 @@ void LLFastTimerView::draw() mAverageCyclesPerTimer = LLFastTimer::sTimerCalls == 0 ? 0 - : llround(lerp((F32)mAverageCyclesPerTimer, (F32)(LLFastTimer::sTimerCycles / (U64)LLFastTimer::sTimerCalls), 0.1f)); + : ll_round(lerp((F32)mAverageCyclesPerTimer, (F32)(LLFastTimer::sTimerCycles / (U64)LLFastTimer::sTimerCalls), 0.1f)); LLFastTimer::sTimerCycles = 0; LLFastTimer::sTimerCalls = 0; @@ -800,7 +800,7 @@ void LLFastTimerView::draw() ? (F32)idp->getCountAverage() / (F32)totalticks : (F32)idp->getHistoricalCount(tidx) / (F32)totalticks; - dx = llround(frac * (F32)barw); + dx = ll_round(frac * (F32)barw); S32 prev_delta_x = deltax.empty() ? 0 : deltax.back(); deltax.push_back(dx); @@ -884,7 +884,8 @@ void LLFastTimerView::draw() gGL.color4fv(color.mV); F32 start_fragment = llclamp((F32)(left - sublevel_left[level]) / (F32)sublevel_dx[level], 0.f, 1.f); F32 end_fragment = llclamp((F32)(right - sublevel_left[level]) / (F32)sublevel_dx[level], 0.f, 1.f); - gl_segmented_rect_2d_fragment_tex(sublevel_left[level], top - level + scale_offset, sublevel_right[level], bottom + level - scale_offset, box_imagep->getTextureWidth(), box_imagep->getTextureHeight(), 16, start_fragment, end_fragment); + LLRect rect(sublevel_left[level], top - level + scale_offset, sublevel_right[level], bottom + level - scale_offset); + gl_segmented_rect_2d_fragment_tex(rect, box_imagep->getTextureWidth(), box_imagep->getTextureHeight(), 16, start_fragment, end_fragment); } @@ -964,7 +965,7 @@ void LLFastTimerView::draw() if (mHoverID == idp) { gGL.flush(); - glLineWidth(3); + gGL.setLineWidth(3); } const F32 * col = sTimerColors[idp].mV;// ft_display_table[idx].color->mV; @@ -1014,7 +1015,7 @@ void LLFastTimerView::draw() if (mHoverID == idp) { gGL.flush(); - glLineWidth(1); + gGL.setLineWidth(1); } if (idp->getCollapsed()) @@ -1025,7 +1026,7 @@ void LLFastTimerView::draw() } //interpolate towards new maximum - last_max = (U64) lerp((F32)last_max, (F32) cur_max, LLCriticalDamp::getInterpolant(0.1f)); + last_max = (U64) lerp((F32)last_max, (F32) cur_max, LLSmoothInterpolation::getInterpolant(0.1f)); if (last_max - cur_max <= 1 || cur_max - last_max <= 1) { last_max = cur_max; @@ -1033,7 +1034,7 @@ void LLFastTimerView::draw() F32 alpha_target = last_max > cur_max ? llmin((F32) last_max/ (F32) cur_max - 1.f,1.f) : llmin((F32) cur_max/ (F32) last_max - 1.f,1.f); - alpha_interp = lerp(alpha_interp, alpha_target, LLCriticalDamp::getInterpolant(0.1f)); + alpha_interp = lerp(alpha_interp, alpha_target, LLSmoothInterpolation::getInterpolant(0.1f)); if (mHoverID != NULL) { @@ -1073,7 +1074,7 @@ void LLFastTimerView::draw() it.skipDescendants(); } } - llinfos << legend_stat << llendl; + LL_INFOS() << legend_stat << LL_ENDL; std::string timer_stat; first = true; @@ -1107,7 +1108,7 @@ void LLFastTimerView::draw() it.skipDescendants(); } } - llinfos << timer_stat << llendl; + LL_INFOS() << timer_stat << LL_ENDL; mPrintStats = -1; } @@ -1305,7 +1306,7 @@ void LLFastTimerView::exportCharts(const std::string& base, const std::string& t last_p.clear(); - LLGLDisable cull(GL_CULL_FACE); + LLGLDisable cull; LLVector3 base_col(0, 0.7f, 0.f); LLVector3 cur_col(1.f, 0.f, 0.f); @@ -1329,7 +1330,7 @@ void LLFastTimerView::exportCharts(const std::string& base, const std::string& t last_p.clear(); { - LLGLEnable blend(GL_BLEND); + LLGLEnable blend; gGL.color3fv(cur_col.mV); for (U32 i = 0; i < cur_times.size(); ++i) @@ -1370,7 +1371,7 @@ void LLFastTimerView::exportCharts(const std::string& base, const std::string& t gGL.flush(); { - LLGLEnable blend(GL_BLEND); + LLGLEnable blend; gGL.color3fv(cur_col.mV); last_p.clear(); @@ -1418,7 +1419,7 @@ void LLFastTimerView::exportCharts(const std::string& base, const std::string& t last_p.clear(); { - LLGLEnable blend(GL_BLEND); + LLGLEnable blend; gGL.color3fv(cur_col.mV); count = 0; total_count = cur_execution.size(); @@ -1519,7 +1520,7 @@ void LLFastTimerView::doAnalysisDefault(std::string baseline, std::string target std::ifstream target_is(target.c_str()); if (!base_is.is_open() || !target_is.is_open()) { - llwarns << "'-analyzeperformance' error : baseline or current target file inexistent" << llendl; + LL_WARNS() << "'-analyzeperformance' error : baseline or current target file inexistent" << LL_ENDL; base_is.close(); target_is.close(); return; diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp new file mode 100644 index 0000000000..254d750cb7 --- /dev/null +++ b/indra/newview/llfavoritesbar.cpp @@ -0,0 +1,1802 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +/** + * @file llfavoritesbar.cpp + * @brief LLFavoritesBarCtrl class implementation + * + * $LicenseInfo:firstyear=2009&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llfavoritesbar.h" + +//#include "llfloaterreg.h" +#include "llfocusmgr.h" +#include "llinventory.h" +#include "lllandmarkactions.h" +//#include "lltoolbarview.h" +#include "lltrans.h" +#include "llmenugl.h" +//#include "lltooltip.h" +#include "lluictrlfactory.h" + +#include "llagent.h" +#include "llavatarnamecache.h" +#include "llclipboard.h" +#include "llinventorybridge.h" +#include "llinventoryclipboard.h" +#include "llinventoryfunctions.h" +//#include "llfloatersidepanelcontainer.h" +#include "llfloaterworldmap.h" +#include "lllandmarkactions.h" +//#include "lllogininstance.h" +#include "llnotificationsutil.h" +//#include "lltoggleablemenu.h" +#include "llviewerinventory.h" +#include "llviewermenu.h" +#include "hippogridmanager.h" //"llviewernetwork.h" +#include "lltooldraganddrop.h" +#include "llsdserialize.h" + +void open_landmark(LLViewerInventoryItem* inv_item, const std::string& title, BOOL show_keep_discard, const LLUUID& source_id, BOOL take_focus); + +static LLRegisterWidget r("favorites_bar"); + +const S32 DROP_DOWN_MENU_WIDTH = 250; +const S32 DROP_DOWN_MENU_TOP_PAD = 13; + +/** + * Helper for LLFavoriteLandmarkButton and LLFavoriteLandmarkMenuItem. + * Performing requests for SLURL for given Landmark ID + */ +class LLLandmarkInfoGetter +{ +public: + LLLandmarkInfoGetter() + : mLandmarkID(LLUUID::null), + mName("(Loading...)"), + mPosX(0), + mPosY(0), + mPosZ(0), + mLoaded(false) + { + mHandle.bind(this); + } + + void setLandmarkID(const LLUUID& id) { mLandmarkID = id; } + const LLUUID& getLandmarkId() const { return mLandmarkID; } + + const std::string& getName() + { + if(!mLoaded) + requestNameAndPos(); + + return mName; + } + + S32 getPosX() + { + if (!mLoaded) + requestNameAndPos(); + return mPosX; + } + + S32 getPosY() + { + if (!mLoaded) + requestNameAndPos(); + return mPosY; + } + + S32 getPosZ() + { + if (!mLoaded) + requestNameAndPos(); + return mPosZ; + } + +private: + /** + * Requests landmark data from server. + */ + void requestNameAndPos() + { + if (mLandmarkID.isNull()) + return; + + LLVector3d g_pos; + if(LLLandmarkActions::getLandmarkGlobalPos(mLandmarkID, g_pos)) + { + LLLandmarkActions::getRegionNameAndCoordsFromPosGlobal(g_pos, + boost::bind(&LLLandmarkInfoGetter::landmarkNameCallback, static_cast >(mHandle), _1, _2, _3, _4)); + } + } + + static void landmarkNameCallback(LLHandle handle, const std::string& name, S32 x, S32 y, S32 z) + { + LLLandmarkInfoGetter* getter = handle.get(); + if (getter) + { + getter->mPosX = x; + getter->mPosY = y; + getter->mPosZ = z; + getter->mName = name; + getter->mLoaded = true; + } + } + + LLUUID mLandmarkID; + std::string mName; + S32 mPosX; + S32 mPosY; + S32 mPosZ; + bool mLoaded; + LLRootHandle mHandle; +}; + +/** + * This class is needed to override LLButton default handleToolTip function and + * show SLURL as button tooltip. + * *NOTE: dzaporozhan: This is a workaround. We could set tooltips for buttons + * in createButtons function but landmark data is not available when Favorites Bar is + * created. Thats why we are requesting landmark data after + */ +class LLFavoriteLandmarkButton : public LLButton +{ +public: + + BOOL handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_rect) override + { + std::string region_name = mLandmarkInfoGetter.getName(); + + if (!region_name.empty()) + { + std::string extra_message = llformat("%s (%d, %d, %d)", region_name.c_str(), + mLandmarkInfoGetter.getPosX(), mLandmarkInfoGetter.getPosY(), mLandmarkInfoGetter.getPosZ()); + + msg = llformat("%s\n%s", getLabelSelected().c_str(), extra_message.c_str()); + *sticky_rect = calcScreenRect(); + } + return TRUE; + } + + /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask) override + { + LLFavoritesBarCtrl* fb = dynamic_cast(getParent()); + + if (fb) + { + fb->handleHover(x, y, mask); + } + + return LLButton::handleHover(x, y, mask); + } + + void setLandmarkID(const LLUUID& id){ mLandmarkInfoGetter.setLandmarkID(id); } + const LLUUID& getLandmarkId() const { return mLandmarkInfoGetter.getLandmarkId(); } + + void onMouseEnter(S32 x, S32 y, MASK mask) override + { + if (LLToolDragAndDrop::getInstance()->hasMouseCapture()) + { + LLUICtrl::onMouseEnter(x, y, mask); + } + else + { + LLButton::onMouseEnter(x, y, mask); + } + } + +//protected: + LLFavoriteLandmarkButton(const LLButton::Params& p) : LLButton(p) {} + friend class LLUICtrlFactory; + +private: + LLLandmarkInfoGetter mLandmarkInfoGetter; +}; + +/** + * This class is needed to override LLMenuItemCallGL default handleToolTip function and + * show SLURL as button tooltip. + * *NOTE: dzaporozhan: This is a workaround. We could set tooltips for buttons + * in showDropDownMenu function but landmark data is not available when Favorites Bar is + * created. Thats why we are requesting landmark data after + */ +class LLFavoriteLandmarkMenuItem : public LLMenuItemCallGL +{ +public: + BOOL handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_rect) override + { + std::string region_name = mLandmarkInfoGetter.getName(); + if (!region_name.empty()) + { + msg = llformat("%s\n%s (%d, %d)", getLabel().c_str(), region_name.c_str(), mLandmarkInfoGetter.getPosX(), mLandmarkInfoGetter.getPosY()); + *sticky_rect = calcScreenRect(); + } + return TRUE; + } + + void setLandmarkID(const LLUUID& id){ mLandmarkInfoGetter.setLandmarkID(id); } + + BOOL handleMouseDown(S32 x, S32 y, MASK mask) override + { + if (mMouseDownSignal) + (*mMouseDownSignal)(this, x, y, mask); + return LLMenuItemCallGL::handleMouseDown(x, y, mask); + } + + BOOL handleMouseUp(S32 x, S32 y, MASK mask) override + { + if (mMouseUpSignal) + (*mMouseUpSignal)(this, x, y, mask); + return LLMenuItemCallGL::handleMouseUp(x, y, mask); + } + + BOOL handleHover(S32 x, S32 y, MASK mask) override + { + if (fb) + { + fb->handleHover(x, y, mask); + } + + return TRUE; + } + + void initFavoritesBarPointer(LLFavoritesBarCtrl* fb) { this->fb = fb; } + +//protected: + + LLFavoriteLandmarkMenuItem(const LLMenuItemCallGL::Params& p) : LLMenuItemCallGL(p.name(), p.label(), nullptr), fb(nullptr) {} + friend class LLUICtrlFactory; + +private: + LLLandmarkInfoGetter mLandmarkInfoGetter; + LLFavoritesBarCtrl* fb; +}; + +/** + * This class was introduced just for fixing the following issue: + * EXT-836 Nav bar: Favorites overflow menu passes left-mouse click through. + * We must explicitly handle drag and drop event by returning TRUE + * because otherwise LLToolDragAndDrop will initiate drag and drop operation + * with the world. + */ +class LLFavoriteLandmarkToggleableMenu : public LLMenuGL +{ +public: + BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg) override + { + *accept = ACCEPT_NO; + return TRUE; + } + +//protected: + LLFavoriteLandmarkToggleableMenu(): + LLMenuGL("favorites menu") + { + } + + friend class LLUICtrlFactory; +}; + +/** + * This class is needed to update an item being copied to the favorites folder + * with a sort field value (required to save favorites bar's tabs order). + * See method handleNewFavoriteDragAndDrop for more details on how this class is used. + */ +class LLItemCopiedCallback : public LLInventoryCallback +{ +public: + LLItemCopiedCallback(S32 sortField): mSortField(sortField) {} + + void fire(const LLUUID& inv_item) override + { + LLViewerInventoryItem* item = gInventory.getItem(inv_item); + + if (item) + { + LLFavoritesOrderStorage::instance().setSortIndex(item, mSortField); + + item->setComplete(TRUE); + item->updateServer(FALSE); + + gInventory.updateItem(item); + gInventory.notifyObservers(); + LLFavoritesOrderStorage::instance().saveOrder(); + } + + LLView::getWindow()->setCursor(UI_CURSOR_ARROW); + } + +private: + S32 mSortField; +}; + +// updateButtons's helper +struct LLFavoritesSort +{ + // Sorting by creation date and name + // TODO - made it customizible using gSavedSettings + bool operator()(const LLViewerInventoryItem* const& a, const LLViewerInventoryItem* const& b) const + { + S32 sortField1 = LLFavoritesOrderStorage::instance().getSortIndex(a->getUUID()); + S32 sortField2 = LLFavoritesOrderStorage::instance().getSortIndex(b->getUUID()); + + if (!(sortField1 < 0 && sortField2 < 0)) + { + return sortField2 > sortField1; + } + + time_t first_create = a->getCreationDate(); + time_t second_create = b->getCreationDate(); + if (first_create == second_create) + { + return (LLStringUtil::compareDict(a->getName(), b->getName()) < 0); + } + else + { + return (first_create > second_create); + } + } +}; + +LLFavoritesBarCtrl::Params::Params() +: image_drag_indication("image_drag_indication"), + more_button("more_button"), + label("label") +{ +} + +LLFavoritesBarCtrl::LLFavoritesBarCtrl(const LLFavoritesBarCtrl::Params& p) +: LLUICtrl(p), + mOverflowMenuHandle(), + mContextMenuHandle(), + mFont(p.font.isProvided() ? p.font() : LLFontGL::getFontSansSerifSmall()), + mUpdateDropDownItems(true), + mRestoreOverflowMenu(false), + mImageDragIndication(p.image_drag_indication), + mShowDragMarker(FALSE), + mLandingTab(NULL) + , mLastTab(NULL) +, mTabsHighlightEnabled(TRUE) +{ + // Register callback for menus with current registrar (will be parent panel's registrar) + LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Favorites.DoToSelected", + boost::bind(&LLFavoritesBarCtrl::doToSelected, this, _2)); + + // Add this if we need to selectively enable items + LLUICtrl::EnableCallbackRegistry::currentRegistrar().add("Favorites.EnableSelected", + boost::bind(&LLFavoritesBarCtrl::enableSelected, this, _2)); + + gInventory.addObserver(this); + + //make chevron button + mMoreTextBox = new LLTextBox(">>", "\u0032", 50); + mMoreTextBox->setFollows(FOLLOWS_LEFT | FOLLOWS_BOTTOM); + mMoreTextBox->setToolTip(LLStringExplicit("Show more of My Favorites")); + mMoreTextBox->setTabStop(false); + mMoreTextBox->setClickedCallback(boost::bind(&LLFavoritesBarCtrl::showDropDownMenu, this)); + addChild(mMoreTextBox); + + mDropDownItemsCount = 0; + + mBarLabel = new LLTextBox(p.label.name, p.label.label); + addChild(mBarLabel); +} + +LLFavoritesBarCtrl::~LLFavoritesBarCtrl() +{ + gInventory.removeObserver(this); + + if (mOverflowMenuHandle.get()) mOverflowMenuHandle.get()->die(); + if (mContextMenuHandle.get()) mContextMenuHandle.get()->die(); +} + +BOOL LLFavoritesBarCtrl::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg) +{ + *accept = ACCEPT_NO; + + LLToolDragAndDrop::ESource source = LLToolDragAndDrop::getInstance()->getSource(); + if (LLToolDragAndDrop::SOURCE_AGENT != source && LLToolDragAndDrop::SOURCE_LIBRARY != source) return FALSE; + + switch (cargo_type) + { + + case DAD_LANDMARK: + { + /* + * add a callback to the end drag event. + * the callback will disconnet itself immediately after execution + * this is done because LLToolDragAndDrop is a common tool so it shouldn't + * be overloaded with redundant callbacks. + */ + if (!mEndDragConnection.connected()) + { + mEndDragConnection = LLToolDragAndDrop::getInstance()->setEndDragCallback(boost::bind(&LLFavoritesBarCtrl::onEndDrag, this)); + } + + // Copy the item into the favorites folder (if it's not already there). + LLInventoryItem *item = (LLInventoryItem *)cargo_data; + + if (LLFavoriteLandmarkButton* dest = dynamic_cast(findChildByLocalCoords(x, y))) + { + setLandingTab(dest); + } + else if (mLastTab && (x >= mLastTab->getRect().mRight)) + { + /* + * the condition dest == NULL can be satisfied not only in the case + * of dragging to the right from the last tab of the favbar. there is a + * small gap between each tab. if the user drags something exactly there + * then mLandingTab will be set to NULL and the dragged item will be pushed + * to the end of the favorites bar. this is incorrect behavior. that's why + * we need an additional check which excludes the case described previously + * making sure that the mouse pointer is beyond the last tab. + */ + setLandingTab(NULL); + } + + // check if we are dragging an existing item from the favorites bar + if (item && mDragItemId == item->getUUID()) + { + *accept = ACCEPT_YES_SINGLE; + + showDragMarker(TRUE); + + if (drop) + { + handleExistingFavoriteDragAndDrop(x, y); + } + } + else + { + const LLUUID favorites_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE); + if (item && item->getParentUUID() == favorites_id) + { + LL_WARNS("FavoritesBar") << "Attemt to copy a favorite item into the same folder." << LL_ENDL; + break; + } + + *accept = ACCEPT_YES_COPY_MULTI; + + showDragMarker(TRUE); + + if (drop) + { + if (mItems.empty()) + { + setLandingTab(NULL); + } + handleNewFavoriteDragAndDrop(item, favorites_id, x, y); + } + } + } + break; + default: + break; + } + + return TRUE; +} + +void LLFavoritesBarCtrl::handleExistingFavoriteDragAndDrop(S32 x, S32 y) +{ + // Identify the button hovered and the side to drop + LLFavoriteLandmarkButton* dest = dynamic_cast(mLandingTab); + bool insert_before = true; + if (!dest) + { + insert_before = false; + dest = dynamic_cast(mLastTab); + } + + // There is no need to handle if an item was dragged onto itself + if (dest && dest->getLandmarkId() == mDragItemId) + { + return; + } + + // Insert the dragged item in the right place + if (dest) + { + LLInventoryModel::updateItemsOrder(mItems, mDragItemId, dest->getLandmarkId(), insert_before); + } + else + { + // This can happen when the item list is empty + mItems.push_back(gInventory.getItem(mDragItemId)); + } + + LLFavoritesOrderStorage::instance().saveItemsOrder(mItems); + + LLMenuGL* menu = (LLMenuGL*) mOverflowMenuHandle.get(); + + if (menu && menu->getVisible()) + { + menu->setVisible(FALSE); + showDropDownMenu(); + } +} + +void LLFavoritesBarCtrl::handleNewFavoriteDragAndDrop(LLInventoryItem *item, const LLUUID& favorites_id, S32 x, S32 y) +{ + if (!item) return; + // Identify the button hovered and the side to drop + LLFavoriteLandmarkButton* dest = NULL; + bool insert_before = true; + if (!mItems.empty()) + { + // [MAINT-2386] When multiple landmarks are selected and dragged onto an empty favorites bar, + // the viewer would crash when casting mLastTab below, as mLastTab is still null when the + // second landmark is being added. + // To ensure mLastTab is valid, we need to call updateButtons() at the end of this function + dest = dynamic_cast(mLandingTab); + if (!dest) + { + insert_before = false; + dest = dynamic_cast(mLastTab); + } + } + + // There is no need to handle if an item was dragged onto itself + if (dest && dest->getLandmarkId() == mDragItemId) + { + return; + } + + LLPointer viewer_item = new LLViewerInventoryItem(item); + + // Insert the dragged item in the right place + if (dest) + { + insertItem(mItems, dest->getLandmarkId(), viewer_item, insert_before); + } + else + { + // This can happen when the item list is empty + mItems.push_back(viewer_item); + } + + int sortField = 0; + LLPointer cb; + + // 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) + { + LLViewerInventoryItem* currItem = *i; + + if (currItem->getUUID() == item->getUUID()) + { + cb = new LLItemCopiedCallback(++sortField); + } + else + { + LLFavoritesOrderStorage::instance().setSortIndex(currItem, ++sortField); + + currItem->setComplete(TRUE); + currItem->updateServer(FALSE); + + gInventory.updateItem(currItem); + } + } + + LLToolDragAndDrop* tool_dad = LLToolDragAndDrop::getInstance(); + if (tool_dad->getSource() == LLToolDragAndDrop::SOURCE_NOTECARD) + { + viewer_item->setType(LLAssetType::AT_LANDMARK); + copy_inventory_from_notecard(favorites_id, + tool_dad->getObjectID(), + tool_dad->getSourceID(), + viewer_item.get(), + gInventoryCallbacks.registerCB(cb)); + } + else + { + copy_inventory_item( + gAgent.getID(), + item->getPermissions().getOwner(), + item->getUUID(), + favorites_id, + std::string(), + cb); + } + + // [MAINT-2386] Ensure the favorite button has been created and is valid. + // This also ensures that mLastTab will be valid when dropping multiple + // landmarks to an empty favorites bar. + updateButtons(); + + LL_INFOS("FavoritesBar") << "Copied inventory item #" << item->getUUID() << " to favorites." << LL_ENDL; +} + +//virtual +void LLFavoritesBarCtrl::changed(U32 mask) +{ + if (mFavoriteFolderId.isNull()) + { + mFavoriteFolderId = gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE); + + if (mFavoriteFolderId.notNull()) + { + gInventory.fetchDescendentsOf(mFavoriteFolderId); + } + } + else + { + LLInventoryModel::item_array_t items; + LLInventoryModel::cat_array_t cats; + LLIsType is_type(LLAssetType::AT_LANDMARK); + gInventory.collectDescendentsIf(mFavoriteFolderId, cats, items, LLInventoryModel::EXCLUDE_TRASH, is_type); + + for (LLInventoryModel::item_array_t::iterator i = items.begin(); i != items.end(); ++i) + { + LLFavoritesOrderStorage::instance().getSLURL((*i)->getAssetUUID()); + } + + updateButtons(); + } +} + +//virtual +void LLFavoritesBarCtrl::reshape(S32 width, S32 height, BOOL called_from_parent) +{ + LLUICtrl::reshape(width, height, called_from_parent); + updateButtons(); +} + +void LLFavoritesBarCtrl::draw() +{ + LLUICtrl::draw(); + + if (mShowDragMarker) + { + S32 w = mImageDragIndication->getWidth(); + S32 h = mImageDragIndication->getHeight(); + + if (mLandingTab) + { + // mouse pointer hovers over an existing tab + LLRect rect = mLandingTab->getRect(); + mImageDragIndication->draw(rect.mLeft, rect.getHeight(), w, h); + } + else if (mLastTab) + { + // mouse pointer hovers over the favbar empty space (right to the last tab) + LLRect rect = mLastTab->getRect(); + mImageDragIndication->draw(rect.mRight, rect.getHeight(), w, h); + } + // Once drawn, mark this false so we won't draw it again (unless we hit the favorite bar again) + mShowDragMarker = FALSE; + } +} + +const LLButton::Params& LLFavoritesBarCtrl::getButtonParams() +{ + static LLButton::Params button_params; + static bool params_initialized = false; + + if (!params_initialized) + { + button_params.image_overlay(LLUI::getUIImage("Favorite_Link_Over")) + .hover_glow_amount(0.15f) + .use_ellipses(true).tab_stop(false) + .name("favorites_bar_btn") + .follows.flags(FOLLOWS_LEFT|FOLLOWS_BOTTOM); + params_initialized = true; + } + + return button_params; +} + +void LLFavoritesBarCtrl::updateButtons() +{ + mItems.clear(); + + if (!collectFavoriteItems(mItems)) + { + return; + } + + const LLButton::Params& button_params = getButtonParams(); + + if(mItems.empty()) + { + mBarLabel->setVisible(TRUE); + } + else + { + mBarLabel->setVisible(FALSE); + } + const child_list_t* childs = getChildList(); + child_list_const_iter_t child_it = childs->begin(); + size_t first_changed_item_index = 0; + int rightest_point = getRect().mRight - mMoreTextBox->getRect().getWidth(); + //lets find first changed button + while (child_it != childs->end() && first_changed_item_index < mItems.size()) + { + LLFavoriteLandmarkButton* button = dynamic_cast (*child_it); + if (button) + { + const LLViewerInventoryItem *item = mItems[first_changed_item_index].get(); + if (item) + { + // an child's order and mItems should be same + if (button->getLandmarkId() != item->getUUID() // sort order has been changed + || button->getLabelSelected() != item->getName() // favorite's name has been changed + || button->getRect().mRight < rightest_point) // favbar's width has been changed + { + break; + } + } + first_changed_item_index++; + } + child_it++; + } + // now first_changed_item_index should contains a number of button that need to change + + if (first_changed_item_index <= mItems.size()) + { + // Rebuild the buttons only + // child_list_t is a linked list, so safe to erase from the middle if we pre-increment the iterator + + while (child_it != childs->end()) + { + //lets remove other landmarks button and rebuild it + child_list_const_iter_t cur_it = child_it++; + LLFavoriteLandmarkButton* button = + dynamic_cast (*cur_it); + if (button) + { + removeChild(button); + delete button; + } + } + // we have to remove ChevronButton to make sure that the last item will be LandmarkButton to get the right aligning + // keep in mind that we are cutting all buttons in space between the last visible child of favbar and ChevronButton + if (mMoreTextBox->getParent() == this) + { + removeChild(mMoreTextBox); + } + int last_right_edge = 0; + //calculate new buttons offset + if (getChildList()->size() > 0) + { + //find last visible child to get the rightest button offset + child_list_const_reverse_iter_t last_visible_it = std::find_if(childs->rbegin(), childs->rend(), + std::mem_fn(&LLView::getVisible)); + if(last_visible_it != childs->rend()) + { + last_right_edge = (*last_visible_it)->getRect().mRight; + } + } + //last_right_edge is saving coordinates + LLButton* last_new_button = NULL; + size_t j = first_changed_item_index; + for (; j < mItems.size(); j++) + { + last_new_button = createButton(mItems[j], button_params, last_right_edge); + if (!last_new_button) + { + break; + } + sendChildToBack(last_new_button); + last_right_edge = last_new_button->getRect().mRight; + + mLastTab = last_new_button; + } + mFirstDropDownItem = j; + // Chevron button + if (mFirstDropDownItem < mItems.size()) + { + // if updateButton had been called it means: + //or there are some new favorites, or width had been changed + // so if we need to display chevron button, we must update dropdown items too. + mUpdateDropDownItems = true; + S32 buttonHGap = button_params.rect.left; // default value + LLRect rect; + // Chevron button should stay right aligned + rect.setOriginAndSize(getRect().mRight - mMoreTextBox->getRect().getWidth() - buttonHGap, 0, + mMoreTextBox->getRect().getWidth(), + mMoreTextBox->getRect().getHeight()); + + addChild(mMoreTextBox); + mMoreTextBox->setRect(rect); + mMoreTextBox->setVisible(TRUE); + } + // Update overflow menu + LLMenuGL* overflow_menu = static_cast (mOverflowMenuHandle.get()); + if (overflow_menu && overflow_menu->getVisible() && (overflow_menu->getItemCount() != mDropDownItemsCount)) + { + overflow_menu->setVisible(FALSE); + if (mUpdateDropDownItems) + { + showDropDownMenu(); + } + } + } + else + { + mUpdateDropDownItems = false; + } + +} + +LLButton* LLFavoritesBarCtrl::createButton(const LLPointer item, const LLButton::Params& button_params, S32 x_offset) +{ + S32 def_button_width = button_params.rect.width; + S32 button_x_delta = button_params.rect.left; // default value + S32 curr_x = x_offset; + + /** + * WORKAROUND: + * There are some problem with displaying of fonts in buttons. + * Empty space or ellipsis might be displayed instead of last symbols, even though the width of the button is enough. + * The problem disappears if we pad the button with 20 pixels. + */ + int required_width = mFont->getWidth(item->getName()) + 20; + int width = required_width > def_button_width? def_button_width : required_width; + LLFavoriteLandmarkButton* fav_btn = NULL; + + // do we have a place for next button + double buttonHGap + mMoreTextBox ? + if(curr_x + width + 2*button_x_delta + mMoreTextBox->getRect().getWidth() > getRect().mRight ) + { + return NULL; + } + LLButton::Params fav_btn_params(button_params); + fav_btn = new LLFavoriteLandmarkButton(fav_btn_params); + if (NULL == fav_btn) + { + LL_WARNS("FavoritesBar") << "Unable to create LLFavoriteLandmarkButton widget: " << item->getName() << LL_ENDL; + return NULL; + } + + addChild(fav_btn); + + LLRect butt_rect (fav_btn->getRect()); + fav_btn->setLandmarkID(item->getUUID()); + butt_rect.setOriginAndSize(curr_x + button_x_delta, fav_btn->getRect().mBottom, width, fav_btn->getRect().getHeight()); + + fav_btn->setRect(butt_rect); + // change only left and save bottom + fav_btn->setFont(mFont); + fav_btn->setLabel(item->getName()); + fav_btn->setToolTip(item->getName()); + fav_btn->setCommitCallback(boost::bind(&LLFavoritesBarCtrl::onButtonClick, this, item->getUUID())); + fav_btn->setRightMouseDownCallback(boost::bind(&LLFavoritesBarCtrl::onButtonRightClick, this, item->getUUID(), _1, _2, _3,_4 )); + + fav_btn->LLUICtrl::setMouseDownCallback(boost::bind(&LLFavoritesBarCtrl::onButtonMouseDown, this, item->getUUID(), _1, _2, _3, _4)); + fav_btn->LLUICtrl::setMouseUpCallback(boost::bind(&LLFavoritesBarCtrl::onButtonMouseUp, this, item->getUUID(), _1, _2, _3, _4)); + + return fav_btn; +} + + +BOOL LLFavoritesBarCtrl::postBuild() +{ + // make the popup menu available + LLMenuGL* menu = LLUICtrlFactory::getInstance()->buildMenu("menu_favorites.xml", gMenuHolder); + if (!menu) + { + return FALSE; //menu = LLUICtrlFactory::getDefaultWidget("inventory_menu"); + } + menu->setBackgroundColor(gColors.getColor("MenuPopupBgColor")); + mContextMenuHandle = menu->getHandle(); + + return TRUE; +} + +BOOL collectFavoriteItems(LLInventoryModel::item_array_t& items) +{ + + auto mFavoriteFolderId = gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE); + if (mFavoriteFolderId.isNull()) + return FALSE; + + + LLInventoryModel::cat_array_t cats; + + LLIsType is_type(LLAssetType::AT_LANDMARK); + gInventory.collectDescendentsIf(mFavoriteFolderId, cats, items, LLInventoryModel::EXCLUDE_TRASH, is_type); + + std::sort(items.begin(), items.end(), LLFavoritesSort()); + + BOOL needToSaveItemsOrder(const LLInventoryModel::item_array_t& items); + //if (needToSaveItemsOrder(items)) + { + S32 sortField = 0; + for (LLInventoryModel::item_array_t::iterator i = items.begin(); i != items.end(); ++i) + { + LLFavoritesOrderStorage::instance().setSortIndex((*i), ++sortField); + } + } + + return TRUE; +} +BOOL LLFavoritesBarCtrl::collectFavoriteItems(LLInventoryModel::item_array_t& items) { return ::collectFavoriteItems(items); } + +void LLFavoritesBarCtrl::showDropDownMenu() +{ + if (mOverflowMenuHandle.isDead()) + { + createOverflowMenu(); + } + + LLMenuGL* menu = (LLMenuGL*)mOverflowMenuHandle.get(); + if (menu) + { + + if (mUpdateDropDownItems) + { + updateMenuItems(menu); + } + + menu->buildDrawLabels(); + menu->updateParent(LLMenuGL::sMenuContainer); + //menu->setButtonRect(mMoreTextBox->getRect(), this); + positionAndShowMenu(menu); + mDropDownItemsCount = menu->getItemCount(); + } +} + +void LLFavoritesBarCtrl::createOverflowMenu() +{ + LLMenuGL* menu = new LLFavoriteLandmarkToggleableMenu(); + menu->setCanTearOff(false); + menu->setVisible(false); + menu->setScrollable(true); + //menu_p.max_scrollable_items = 10; + //menu_p.preferred_width = DROP_DOWN_MENU_WIDTH; + mOverflowMenuHandle = menu->getHandle(); +} + +void LLFavoritesBarCtrl::updateMenuItems(LLMenuGL* menu) +{ + menu->empty(); + + U32 widest_item = 0; + + for (size_t i = mFirstDropDownItem; i < mItems.size(); i++) + { + LLViewerInventoryItem* item = mItems.at(i); + const std::string& item_name = item->getName(); + + LLFavoriteLandmarkMenuItem::Params item_params; + item_params.name(item_name); + item_params.label(item_name); + + LLFavoriteLandmarkMenuItem *menu_item = new LLFavoriteLandmarkMenuItem(item_params); + menu_item->setMouseUpCallback(std::bind(&LLFavoritesBarCtrl::onButtonClick, this, item->getUUID())); + menu_item->initFavoritesBarPointer(this); + menu_item->setRightMouseDownCallback(boost::bind(&LLFavoritesBarCtrl::onButtonRightClick, this, item->getUUID(), _1, _2, _3, _4)); + menu_item->LLUICtrl::setMouseDownCallback(boost::bind(&LLFavoritesBarCtrl::onButtonMouseDown, this, item->getUUID(), _1, _2, _3, _4)); + menu_item->LLUICtrl::setMouseUpCallback(boost::bind(&LLFavoritesBarCtrl::onButtonMouseUp, this, item->getUUID(), _1, _2, _3, _4)); + menu_item->setLandmarkID(item->getUUID()); + + fitLabelWidth(menu_item); + + widest_item = llmax(widest_item, menu_item->getNominalWidth()); + + menu->addChild(menu_item); + } + + addOpenLandmarksMenuItem(menu); + mUpdateDropDownItems = false; +} + +void LLFavoritesBarCtrl::fitLabelWidth(LLMenuItemCallGL* menu_item) +{ + U32 max_width = llmin(DROP_DOWN_MENU_WIDTH, getRect().getWidth()); + std::string item_name = menu_item->getName(); + + // Check whether item name wider than menu + if (menu_item->getNominalWidth() > max_width) + { + S32 chars_total = item_name.length(); + S32 chars_fitted = 1; + menu_item->setLabel(LLStringExplicit("")); + S32 label_space = max_width - menu_item->getFont()->getWidth("...") - + menu_item->getNominalWidth();// This returns width of menu item with empty label (pad pixels) + + while (chars_fitted < chars_total + && menu_item->getFont()->getWidth(item_name, 0, chars_fitted) < label_space) + { + chars_fitted++; + } + chars_fitted--; // Rolling back one char, that doesn't fit + + menu_item->setLabel(item_name.substr(0, chars_fitted) + "..."); + } +} + +void LLFavoritesBarCtrl::addOpenLandmarksMenuItem(LLMenuGL* menu) +{ + std::string label_untrans = "Open landmarks"; + std::string label_transl; + bool translated = LLTrans::findString(label_transl, label_untrans); + + LLMenuItemCallGL* menu_item = new LLMenuItemCallGL(std::string("open_my_landmarks"), std::string(translated ? label_transl : label_untrans), nullptr); + void show_floater(const std::string& floater_name); + menu_item->setMouseUpCallback(std::bind(show_floater, "floater_inventory_favs.xml")); + + fitLabelWidth(menu_item); + + LLMenuItemSeparatorGL* separator = new LLMenuItemSeparatorGL; + + menu->addChild(separator); + menu->addChild(menu_item); +} + +void LLFavoritesBarCtrl::positionAndShowMenu(LLMenuGL* menu) +{ + U32 max_width = llmin(DROP_DOWN_MENU_WIDTH, getRect().getWidth()); + + S32 menu_x = getRect().getWidth() - max_width; + S32 menu_y = getParent()->getRect().mBottom - DROP_DOWN_MENU_TOP_PAD; + + /* Singu TODO: Side Toolbar? + // the menu should be offset of the right edge of the window + // so it's no covered by buttons in the right-side toolbar. + LLToolBar* right_toolbar = gToolBarView->getChild("toolbar_right"); + if (right_toolbar && right_toolbar->hasButtons()) + { + S32 toolbar_top = 0; + + if (LLView* top_border_panel = right_toolbar->getChild("button_panel")) + { + toolbar_top = top_border_panel->calcScreenRect().mTop; + } + + // Calculating the bottom (in screen coord) of the drop down menu + S32 menu_top = getParent()->getRect().mBottom - DROP_DOWN_MENU_TOP_PAD; + S32 menu_bottom = menu_top - menu->getRect().getHeight(); + S32 menu_bottom_screen = 0; + + localPointToScreen(0, menu_bottom, &menu_top, &menu_bottom_screen); + + if (menu_bottom_screen < toolbar_top) + { + menu_x -= right_toolbar->getRect().getWidth(); + } + } + */ + + LLMenuGL::showPopup(this, menu, menu_x, menu_y); +} + +void LLFavoritesBarCtrl::onButtonClick(LLUUID item_id) +{ + // We only have one Inventory, gInventory. Some day this should be better abstracted. + LLInvFVBridgeAction::doAction(item_id,&gInventory); +} + +void LLFavoritesBarCtrl::onButtonRightClick( LLUUID item_id,LLView* fav_button,S32 x,S32 y,MASK mask) +{ + mSelectedItemID = item_id; + + LLMenuGL* menu = (LLMenuGL*)mContextMenuHandle.get(); + if (!menu) + { + return; + } + + // Remember that the context menu was shown simultaneously with the overflow menu, + // so that we can restore the overflow menu when user clicks a context menu item + // (which hides the overflow menu). + { + LLView* overflow_menu = mOverflowMenuHandle.get(); + mRestoreOverflowMenu = overflow_menu && overflow_menu->getVisible(); + } + + // Release mouse capture so hover events go to the popup menu + // because this is happening during a mouse down. + gFocusMgr.setMouseCapture(NULL); + + menu->updateParent(LLMenuGL::sMenuContainer); + LLMenuGL::showPopup(fav_button, menu, x, y); +} + +BOOL LLFavoritesBarCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask) +{ + BOOL handled = childrenHandleRightMouseDown( x, y, mask) != NULL; + /*if(!handled && !gMenuHolder->hasVisibleMenu()) + { + show_navbar_context_menu(this,x,y); + handled = true; + }*/ + + return handled; +} +void copy_slurl_to_clipboard_cb(std::string& slurl) +{ + LLView::getWindow()->copyTextToClipboard(utf8str_to_wstring(slurl)); + + LLSD args; + args["SLURL"] = slurl; + LLNotificationsUtil::add("CopySLURL", args); +} + + +bool LLFavoritesBarCtrl::enableSelected(const LLSD& userdata) +{ + std::string param = userdata.asString(); + + if (param == std::string("can_paste")) + { + return isClipboardPasteable(); + } + + return false; +} + +void LLFavoritesBarCtrl::doToSelected(const LLSD& userdata) +{ + std::string action = userdata.asString(); + LL_INFOS("FavoritesBar") << "Action = " << action << " Item = " << mSelectedItemID.asString() << LL_ENDL; + + LLViewerInventoryItem* item = gInventory.getItem(mSelectedItemID); + if (!item) + return; + + if (action == "open") + { + onButtonClick(item->getUUID()); + } + else if (action == "about") + { + LLSD key; + key["type"] = "landmark"; + key["id"] = mSelectedItemID; + + open_landmark(item, "Favorite", false, mSelectedItemID, true); + } + else if (action == "copy_slurl") + { + LLVector3d posGlobal; + LLLandmarkActions::getLandmarkGlobalPos(mSelectedItemID, posGlobal); + + if (!posGlobal.isExactlyZero()) + { + LLLandmarkActions::getSLURLfromPosGlobal(posGlobal, copy_slurl_to_clipboard_cb); + } + } + else if (action == "show_on_map") + { + LLFloaterWorldMap* worldmap_instance = gFloaterWorldMap; + + LLVector3d posGlobal; + LLLandmarkActions::getLandmarkGlobalPos(mSelectedItemID, posGlobal); + + if (!posGlobal.isExactlyZero() && worldmap_instance) + { + worldmap_instance->trackLocation(posGlobal); + LLFloaterWorldMap::show(true); + } + } + else if (action == "cut") + { + } + else if (action == "copy") + { + LLInventoryClipboard::instance().add(mSelectedItemID); + } + else if (action == "paste") + { + pasteFromClipboard(); + } + else if (action == "delete") + { + gInventory.removeItem(mSelectedItemID); + } + + // Pop-up the overflow menu again (it gets hidden whenever the user clicks a context menu item). + // See EXT-4217 and STORM-207. + LLMenuGL* menu = (LLMenuGL*) mOverflowMenuHandle.get(); + if (mRestoreOverflowMenu && menu && !menu->getVisible()) + { + menu->resetScrollPositionOnShow(false); + showDropDownMenu(); + menu->resetScrollPositionOnShow(true); + } +} + +BOOL LLFavoritesBarCtrl::isClipboardPasteable() const +{ + if (!LLInventoryClipboard::instance().hasContents()) + { + return FALSE; + } + + uuid_vec_t objects; + LLInventoryClipboard::instance().retrieve(objects); + S32 count = objects.size(); + for(S32 i = 0; i < count; i++) + { + const LLUUID &item_id = objects.at(i); + + // Can't paste folders + const LLInventoryCategory *cat = gInventory.getCategory(item_id); + if (cat) + { + return FALSE; + } + + const LLInventoryItem *item = gInventory.getItem(item_id); + if (item && LLAssetType::AT_LANDMARK != item->getType()) + { + return FALSE; + } + } + return TRUE; +} + +void LLFavoritesBarCtrl::pasteFromClipboard() const +{ + LLInventoryModel* model = &gInventory; + if(model && isClipboardPasteable()) + { + LLInventoryItem* item = NULL; + uuid_vec_t objects; + LLInventoryClipboard::instance().retrieve(objects); + S32 count = objects.size(); + LLUUID parent_id(mFavoriteFolderId); + for(S32 i = 0; i < count; i++) + { + item = model->getItem(objects.at(i)); + if (item) + { + copy_inventory_item( + gAgent.getID(), + item->getPermissions().getOwner(), + item->getUUID(), + parent_id, + std::string(), + LLPointer(NULL)); + } + } + } +} + +void LLFavoritesBarCtrl::onButtonMouseDown(LLUUID id, LLUICtrl* ctrl, S32 x, S32 y, MASK mask) +{ + // EXT-6997 (Fav bar: Pop-up menu for LM in overflow dropdown is kept after LM was dragged away) + // mContextMenuHandle.get() - is a pop-up menu (of items) in already opened dropdown menu. + // We have to check and set visibility of pop-up menu in such a way instead of using + // LLMenuHolderGL::hideMenus() because it will close both menus(dropdown and pop-up), but + // we need to close only pop-up menu while dropdown one should be still opened. + LLMenuGL* menu = (LLMenuGL*)mContextMenuHandle.get(); + if(menu && menu->getVisible()) + { + menu->setVisible(FALSE); + } + + mDragItemId = id; + mStartDrag = TRUE; + + S32 screenX, screenY; + localPointToScreen(x, y, &screenX, &screenY); + + LLToolDragAndDrop::getInstance()->setDragStart(screenX, screenY); +} + +void LLFavoritesBarCtrl::onButtonMouseUp(LLUUID id, LLUICtrl* ctrl, S32 x, S32 y, MASK mask) +{ + mStartDrag = FALSE; + mDragItemId = LLUUID::null; +} + +void LLFavoritesBarCtrl::onEndDrag() +{ + mEndDragConnection.disconnect(); + + showDragMarker(FALSE); + mDragItemId = LLUUID::null; + LLView::getWindow()->setCursor(UI_CURSOR_ARROW); +} + +BOOL LLFavoritesBarCtrl::handleHover(S32 x, S32 y, MASK mask) +{ + if (mDragItemId != LLUUID::null && mStartDrag) + { + S32 screenX, screenY; + localPointToScreen(x, y, &screenX, &screenY); + + if(LLToolDragAndDrop::getInstance()->isOverThreshold(screenX, screenY)) + { + LLToolDragAndDrop::getInstance()->beginDrag( + DAD_LANDMARK, mDragItemId, + LLToolDragAndDrop::SOURCE_LIBRARY); + + mStartDrag = FALSE; + + return LLToolDragAndDrop::getInstance()->handleHover(x, y, mask); + } + } + + return TRUE; +} + +LLUICtrl* LLFavoritesBarCtrl::findChildByLocalCoords(S32 x, S32 y) +{ + LLUICtrl* ctrl = NULL; + const child_list_t* list = getChildList(); + + for (child_list_const_iter_t i = list->begin(); i != list->end(); ++i) + { + // Look only for children that are favorite buttons + if ((*i)->getName() == "favorites_bar_btn") + { + LLRect rect = (*i)->getRect(); + // We consider a button hit if the cursor is left of the right side + // This makes the hit a bit less finicky than hitting directly on the button itself + if (x <= rect.mRight) + { + ctrl = dynamic_cast(*i); + break; + } + } + } + return ctrl; +} + +BOOL needToSaveItemsOrder(const LLInventoryModel::item_array_t& items) +{ + BOOL result = FALSE; + + // if there is an item without sort order field set, we need to save items order + for (LLInventoryModel::item_array_t::const_iterator i = items.begin(); i != items.end(); ++i) + { + if (LLFavoritesOrderStorage::instance().getSortIndex((*i)->getUUID()) < 0) + { + result = TRUE; + break; + } + } + + return result; +} +BOOL LLFavoritesBarCtrl::needToSaveItemsOrder(const LLInventoryModel::item_array_t& items) { return ::needToSaveItemsOrder(items); } + +void LLFavoritesBarCtrl::insertItem(LLInventoryModel::item_array_t& items, const LLUUID& dest_item_id, LLViewerInventoryItem* insertedItem, bool insert_before) +{ + // Get the iterator to the destination item + LLInventoryModel::item_array_t::iterator it_dest = LLInventoryModel::findItemIterByUUID(items, dest_item_id); + if (it_dest == items.end()) + return; + + // Go to the next element if one wishes to insert after the dest element + if (!insert_before) + { + ++it_dest; + } + + // Insert the source item in the right place + if (it_dest != items.end()) + { + items.insert(it_dest, insertedItem); + } + else + { + // Append to the list if it_dest reached the end + items.push_back(insertedItem); + } +} + +const std::string LLFavoritesOrderStorage::SORTING_DATA_FILE_NAME = "landmarks_sorting.xml"; +const S32 LLFavoritesOrderStorage::NO_INDEX = -1; + +void LLFavoritesOrderStorage::setSortIndex(const LLViewerInventoryItem* inv_item, S32 sort_index) +{ + mSortIndexes[inv_item->getUUID()] = sort_index; + mIsDirty = true; + getSLURL(inv_item->getAssetUUID()); +} + +S32 LLFavoritesOrderStorage::getSortIndex(const LLUUID& inv_item_id) +{ + sort_index_map_t::const_iterator it = mSortIndexes.find(inv_item_id); + if (it != mSortIndexes.end()) + { + return it->second; + } + return NO_INDEX; +} + +void LLFavoritesOrderStorage::removeSortIndex(const LLUUID& inv_item_id) +{ + mSortIndexes.erase(inv_item_id); + mIsDirty = true; +} + +void LLFavoritesOrderStorage::getSLURL(const LLUUID& asset_id) +{ + slurls_map_t::iterator slurl_iter = mSLURLs.find(asset_id); + if (slurl_iter != mSLURLs.end()) return; // SLURL for current landmark is already cached + + LLLandmark* lm = gLandmarkList.getAsset(asset_id, + boost::bind(&LLFavoritesOrderStorage::onLandmarkLoaded, this, asset_id, _1)); + if (lm) + { + LL_DEBUGS("FavoritesBar") << "landmark for " << asset_id << " already loaded" << LL_ENDL; + onLandmarkLoaded(asset_id, lm); + } +} + +// static +std::string LLFavoritesOrderStorage::getStoredFavoritesFilename() +{ + std::string user_dir = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""); + + return (user_dir.empty() ? "" + : gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, + "stored_favorites_" + + gHippoGridManager->getCurrentGridName() + + ".xml") + ); +} + +// static +void LLFavoritesOrderStorage::destroyClass() +{ + LLFavoritesOrderStorage::instance().cleanup(); + + + std::string old_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "stored_favorites.xml"); + llifstream file; + file.open(old_filename.c_str()); + if (file.is_open()) + { + file.close(); + std::string new_filename = getStoredFavoritesFilename(); + LL_INFOS("FavoritesBar") << "moving favorites from old name '" << old_filename + << "' to new name '" << new_filename << "'" + << LL_ENDL; + LLFile::rename(old_filename,new_filename); + } + + if (gSavedPerAccountSettings.getBOOL("ShowFavoritesOnLogin")) + { + LLFavoritesOrderStorage::instance().saveFavoritesSLURLs(); + } + else + { + LLFavoritesOrderStorage::instance().removeFavoritesRecordOfUser(); + } +} + +std::string LLFavoritesOrderStorage::getSavedOrderFileName() +{ + // If we quit from the login screen we will not have an SL account + // name. Don't try to save, otherwise we'll dump a file in + // C:\Program Files\SecondLife\ or similar. JC + std::string user_dir = gDirUtilp->getLindenUserDir(); + return (user_dir.empty() ? "" : gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, SORTING_DATA_FILE_NAME)); +} + +void LLFavoritesOrderStorage::load() +{ + // load per-resident sorting information + std::string filename = getSavedOrderFileName(); + LLSD settings_llsd; + llifstream file; + file.open(filename.c_str()); + if (file.is_open()) + { + LLSDSerialize::fromXML(settings_llsd, file); + LL_INFOS("FavoritesBar") << "loaded favorites order from '" << filename << "' " + << (settings_llsd.isMap() ? "" : "un") << "successfully" + << LL_ENDL; + file.close(); + } + else + { + LL_WARNS("FavoritesBar") << "unable to open favorites order file at '" << filename << "'" << LL_ENDL; + } + + for (LLSD::map_const_iterator iter = settings_llsd.beginMap(); + iter != settings_llsd.endMap(); ++iter) + { + mSortIndexes.insert(std::make_pair(LLUUID(iter->first), (S32)iter->second.asInteger())); + } +} + +void LLFavoritesOrderStorage::saveFavoritesSLURLs() +{ + // Do not change the file if we are not logged in yet. + if (gAgentID.isNull()) //LLLoginInstance::getInstance()->authSuccess()) + { + LL_WARNS("FavoritesBar") << "Cannot save favorites: not logged in" << LL_ENDL; + return; + } + + std::string filename = getStoredFavoritesFilename(); + if (!filename.empty()) + { + llifstream in_file; + in_file.open(filename.c_str()); + LLSD fav_llsd; + if (in_file.is_open()) + { + LLSDSerialize::fromXML(fav_llsd, in_file); + LL_INFOS("FavoritesBar") << "loaded favorites from '" << filename << "' " + << (fav_llsd.isMap() ? "" : "un") << "successfully" + << LL_ENDL; + in_file.close(); + } + else + { + LL_WARNS("FavoritesBar") << "unable to open favorites from '" << filename << "'" << LL_ENDL; + } + + const LLUUID fav_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE); + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + gInventory.collectDescendents(fav_id, cats, items, LLInventoryModel::EXCLUDE_TRASH); + + LLSD user_llsd; + for (LLInventoryModel::item_array_t::const_iterator it = items.cbegin(); it != items.cend(); ++it) + { + if (it->get()->getActualType() != LLAssetType::AT_LANDMARK) continue; + LLSD value; + value["name"] = (*it)->getName(); + value["asset_id"] = (*it)->getAssetUUID(); + + slurls_map_t::const_iterator slurl_iter = mSLURLs.find(value["asset_id"]); + if (slurl_iter != mSLURLs.cend()) + { + LL_DEBUGS("FavoritesBar") << "Saving favorite: idx=" << LLFavoritesOrderStorage::instance().getSortIndex((*it)->getUUID()) + << ", SLURL=" << slurl_iter->second + << ", value=" << value << LL_ENDL; + value["slurl"] = slurl_iter->second; + user_llsd[LLFavoritesOrderStorage::instance().getSortIndex((*it)->getUUID())] = value; + } + else + { + LL_WARNS("FavoritesBar") << "Not saving favorite " << value["name"] << ": no matching SLURL" << LL_ENDL; + } + } + + LLAvatarName av_name; + LLAvatarNameCache::get( gAgentID, &av_name ); + // Note : use the "John Doe" and not the "john.doe" version of the name + // as we'll compare it with the stored credentials in the login panel. + fav_llsd[av_name.getUserName()] = user_llsd; + + llofstream file; + file.open(filename.c_str()); + if ( file.is_open() ) + { + LLSDSerialize::toPrettyXML(fav_llsd, file); + LL_INFOS("FavoritesBar") << "saved favorites for '" << av_name.getUserName() + << "' to '" << filename << "' " + << LL_ENDL; + file.close(); + } + else + { + LL_WARNS("FavoritesBar") << "unable to open favorites storage for '" << av_name.getUserName() + << "' at '" << filename << "' " + << LL_ENDL; + } + } +} + +void LLFavoritesOrderStorage::removeFavoritesRecordOfUser() +{ + std::string filename = getStoredFavoritesFilename(); + if (!filename.empty()) + { + LLSD fav_llsd; + llifstream file; + file.open(filename.c_str()); + if (file.is_open()) + { + LLSDSerialize::fromXML(fav_llsd, file); + file.close(); + + LLAvatarName av_name; + LLAvatarNameCache::get( gAgentID, &av_name ); + // Note : use the "John Doe" and not the "john.doe" version of the name. + // See saveFavoritesSLURLs() here above for the reason why. + if (fav_llsd.has(av_name.getUserName())) + { + LL_INFOS("FavoritesBar") << "Removed favorites for " << av_name.getUserName() << LL_ENDL; + fav_llsd.erase(av_name.getUserName()); + } + + llofstream out_file; + out_file.open(filename.c_str()); + if ( out_file.is_open() ) + { + LLSDSerialize::toPrettyXML(fav_llsd, out_file); + LL_INFOS("FavoritesBar") << "saved favorites to '" << filename << "' " + << LL_ENDL; + out_file.close(); + } + } + } +} + +void LLFavoritesOrderStorage::onLandmarkLoaded(const LLUUID& asset_id, LLLandmark* landmark) +{ + if (landmark) + { + LL_DEBUGS("FavoritesBar") << "landmark for " << asset_id << " loaded" << LL_ENDL; + LLVector3d pos_global; + if (!landmark->getGlobalPos(pos_global)) + { + // If global position was unknown on first getGlobalPos() call + // it should be set for the subsequent calls. + landmark->getGlobalPos(pos_global); + } + + if (!pos_global.isExactlyZero()) + { + LL_DEBUGS("FavoritesBar") << "requesting slurl for landmark " << asset_id << LL_ENDL; + LLLandmarkActions::getSLURLfromPosGlobal(pos_global, + boost::bind(&LLFavoritesOrderStorage::storeFavoriteSLURL, this, asset_id, _1)); + } + } +} + +void LLFavoritesOrderStorage::storeFavoriteSLURL(const LLUUID& asset_id, std::string& slurl) +{ + LL_DEBUGS("FavoritesBar") << "Saving landmark SLURL '" << slurl << "' for " << asset_id << LL_ENDL; + mSLURLs[asset_id] = slurl; +} + +void LLFavoritesOrderStorage::save() +{ + if (mIsDirty) + { + // something changed, so save it + std::string filename = LLFavoritesOrderStorage::getInstance()->getSavedOrderFileName(); + if (!filename.empty()) + { + LLSD settings_llsd; + + for(sort_index_map_t::const_iterator iter = mSortIndexes.begin(); iter != mSortIndexes.end(); ++iter) + { + settings_llsd[iter->first.asString()] = iter->second; + } + + llofstream file; + file.open(filename.c_str()); + if ( file.is_open() ) + { + LLSDSerialize::toPrettyXML(settings_llsd, file); + LL_INFOS("FavoritesBar") << "saved favorites order to '" << filename << "' " << LL_ENDL; + } + else + { + LL_WARNS("FavoritesBar") << "failed to open favorites order file '" << filename << "' " << LL_ENDL; + } + } + else + { + LL_DEBUGS("FavoritesBar") << "no user directory available to store favorites order file" << LL_ENDL; + } + } +} + + +void LLFavoritesOrderStorage::cleanup() +{ + // nothing to clean + if (!mIsDirty) return; + + const LLUUID fav_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE); + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + gInventory.collectDescendents(fav_id, cats, items, LLInventoryModel::EXCLUDE_TRASH); + + IsNotInFavorites is_not_in_fav(items); + + sort_index_map_t aTempMap; + //copy unremoved values from mSortIndexes to aTempMap + std::remove_copy_if(mSortIndexes.begin(), mSortIndexes.end(), + inserter(aTempMap, aTempMap.begin()), + is_not_in_fav); + + //Swap the contents of mSortIndexes and aTempMap + mSortIndexes.swap(aTempMap); +} + +// See also LLInventorySort where landmarks in the Favorites folder are sorted. +class LLViewerInventoryItemSort +{ +public: + bool operator()(const LLPointer& a, const LLPointer& b) const + { + return LLFavoritesOrderStorage::instance().getSortIndex(a->getUUID()) + < LLFavoritesOrderStorage::instance().getSortIndex(b->getUUID()); + } +}; + +void LLFavoritesOrderStorage::saveOrder() +{ + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + LLIsType is_type(LLAssetType::AT_LANDMARK); + LLUUID favorites_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE); + gInventory.collectDescendentsIf(favorites_id, cats, items, LLInventoryModel::EXCLUDE_TRASH, is_type); + std::sort(items.begin(), items.end(), LLViewerInventoryItemSort()); + saveItemsOrder(items); +} + +void LLFavoritesOrderStorage::saveItemsOrder( const LLInventoryModel::item_array_t& items ) +{ + + int sortField = 0; + // current order is saved by setting incremental values (1, 2, 3, ...) for the sort field + for (LLInventoryModel::item_array_t::const_iterator i = items.begin(); i != items.end(); ++i) + { + LLViewerInventoryItem* item = *i; + + setSortIndex(item, ++sortField); + + item->setComplete(TRUE); + item->updateServer(FALSE); + + gInventory.updateItem(item); + + // Tell the parent folder to refresh its sort order. + gInventory.addChangedMask(LLInventoryObserver::SORT, item->getParentUUID()); + } + + gInventory.notifyObservers(); +} + + +// * @param source_item_id - LLUUID of the source item to be moved into new position +// * @param target_item_id - LLUUID of the target item before which source item should be placed. +void LLFavoritesOrderStorage::rearrangeFavoriteLandmarks(const LLUUID& source_item_id, const LLUUID& target_item_id) +{ + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + //LLIsType is_type(LLAssetType::AT_LANDMARK); // Singu Note: We can have anything here~ + LLUUID favorites_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE); + gInventory.collectDescendents(favorites_id, cats, items, LLInventoryModel::EXCLUDE_TRASH/*, is_type*/); + + // ensure items are sorted properly before changing order. EXT-3498 + std::sort(items.begin(), items.end(), LLViewerInventoryItemSort()); + + // update order + gInventory.updateItemsOrder(items, source_item_id, target_item_id); + + saveItemsOrder(items); +} + +void AddFavoriteLandmarkCallback::fire(const LLUUID& inv_item_id) +{ + if (mTargetLandmarkId.isNull()) return; + + LLFavoritesOrderStorage::instance().rearrangeFavoriteLandmarks(inv_item_id, mTargetLandmarkId); +} +// EOF diff --git a/indra/newview/llfavoritesbar.h b/indra/newview/llfavoritesbar.h new file mode 100644 index 0000000000..7d6008a027 --- /dev/null +++ b/indra/newview/llfavoritesbar.h @@ -0,0 +1,274 @@ +/** + * @file llfavoritesbar.h + * @brief LLFavoritesBarCtrl base class + * + * $LicenseInfo:firstyear=2009&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLFAVORITESBARCTRL_H +#define LL_LLFAVORITESBARCTRL_H + +#include "llbutton.h" +#include "lluictrl.h" +#include "lltextbox.h" + +#include "llinventoryobserver.h" +#include "llinventorymodel.h" +#include "llviewerinventory.h" +#include "llui.h" //"llinitdestroyclass.h" + +class LLMenuItemCallGL; +class LLMenuGL; + +class LLFavoritesBarCtrl : public LLUICtrl, public LLInventoryObserver +{ +public: + struct Params : public LLInitParam::Block + { + Optional image_drag_indication; + Optional more_button; + Optional label; + Params(); + }; + +protected: + LLFavoritesBarCtrl(const Params&); + friend class LLUICtrlFactory; +public: + virtual ~LLFavoritesBarCtrl(); + + /*virtual*/ BOOL postBuild() override; + + /*virtual*/ BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg) override; + + /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask) override; + /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask) override; + // LLInventoryObserver observer trigger + void changed(U32 mask) override; + void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE) override; + void draw() override; + + void showDragMarker(BOOL show) { mShowDragMarker = show; } + void setLandingTab(LLUICtrl* tab) { mLandingTab = tab; } + +protected: + void updateButtons(); + LLButton* createButton(const LLPointer item, const LLButton::Params& button_params, S32 x_offset ); + const LLButton::Params& getButtonParams(); + BOOL collectFavoriteItems(LLInventoryModel::item_array_t &items); + + void onButtonClick(LLUUID id); + 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(); + + bool enableSelected(const LLSD& userdata); + void doToSelected(const LLSD& userdata); + BOOL isClipboardPasteable() const; + void pasteFromClipboard() const; + + void showDropDownMenu(); + + LLHandle mOverflowMenuHandle; + LLHandle mContextMenuHandle; + + LLUUID mFavoriteFolderId; + const LLFontGL *mFont; + size_t mFirstDropDownItem; + U32 mDropDownItemsCount; + bool mUpdateDropDownItems; + bool mRestoreOverflowMenu; + + LLUUID mSelectedItemID; + + LLUIImage* mImageDragIndication; + +private: + /* + * Helper function to make code more readable. It handles all drag and drop + * operations of the existing favorites items on the favorites bar. + */ + void handleExistingFavoriteDragAndDrop(S32 x, S32 y); + + /* + * Helper function to make code more readable. It handles all drag and drop + * operations of the new landmark to the favorites bar. + */ + void handleNewFavoriteDragAndDrop(LLInventoryItem *item, const LLUUID& favorites_id, S32 x, S32 y); + + // finds a control under the specified LOCAL point + LLUICtrl* findChildByLocalCoords(S32 x, S32 y); + + // checks if the current order of the favorites items must be saved + BOOL needToSaveItemsOrder(const LLInventoryModel::item_array_t& items); + + /** + * inserts an item identified by insertedItemId BEFORE an item identified by beforeItemId. + * this function assumes that an item identified by insertedItemId doesn't exist in items array. + */ + void insertItem(LLInventoryModel::item_array_t& items, const LLUUID& dest_item_id, LLViewerInventoryItem* insertedItem, bool insert_before); + + // finds an item by it's UUID in the items array + LLInventoryModel::item_array_t::iterator findItemByUUID(LLInventoryModel::item_array_t& items, const LLUUID& id); + + void createOverflowMenu(); + + void updateMenuItems(LLMenuGL* menu); + + // Fits menu item label width with favorites menu width + void fitLabelWidth(LLMenuItemCallGL* menu_item); + + void addOpenLandmarksMenuItem(LLMenuGL* menu); + + void positionAndShowMenu(LLMenuGL* menu); + + BOOL mShowDragMarker; + LLUICtrl* mLandingTab; + LLUICtrl* mLastTab; + LLTextBox* mMoreTextBox; + LLTextBox* mBarLabel; + + LLUUID mDragItemId; + BOOL mStartDrag; + LLInventoryModel::item_array_t mItems; + + BOOL mTabsHighlightEnabled; + + boost::signals2::connection mEndDragConnection; +}; + +/** + * Class to store sorting order of favorites landmarks in a local file. EXT-3985. + * It replaced previously implemented solution to store sort index in landmark's name as a "@" prefix. + * Data are stored in user home directory. + */ +class LLFavoritesOrderStorage : public LLSingleton + , public LLDestroyClass +{ + friend class LLSingleton; + LLFavoritesOrderStorage(); //LLSINGLETON(LLFavoritesOrderStorage); + ~LLFavoritesOrderStorage() { save(); } + LOG_CLASS(LLFavoritesOrderStorage); +public: + /** + * Sets sort index for specified with LLUUID favorite landmark + */ + void setSortIndex(const LLViewerInventoryItem* inv_item, S32 sort_index); + + /** + * Gets sort index for specified with LLUUID favorite landmark + */ + S32 getSortIndex(const LLUUID& inv_item_id); + void removeSortIndex(const LLUUID& inv_item_id); + + void getSLURL(const LLUUID& asset_id); + + // Saves current order of the passed items using inventory item sort field. + // Resets 'items' sort fields and saves them on server. + // Is used to save order for Favorites folder. + void saveItemsOrder(const LLInventoryModel::item_array_t& items); + + void saveOrder(); + + void rearrangeFavoriteLandmarks(const LLUUID& source_item_id, const LLUUID& target_item_id); + + /** + * Implementation of LLDestroyClass. Calls cleanup() instance method. + * + * It is important this callback is called before gInventory is cleaned. + * For now it is called from LLAppViewer::cleanup() -> LLAppViewer::disconnectViewer(), + * Inventory is cleaned later from LLAppViewer::cleanup() after LLAppViewer::disconnectViewer() is called. + * @see cleanup() + */ + static void destroyClass(); + + const static S32 NO_INDEX; +private: + /** + * Removes sort indexes for items which are not in Favorites bar for now. + */ + void cleanup(); + + const static std::string SORTING_DATA_FILE_NAME; + std::string getSavedOrderFileName(); + static std::string getStoredFavoritesFilename(); + + void load(); + void save(); + + void saveFavoritesSLURLs(); + + // Remove record of current user's favorites from file on disk. + void removeFavoritesRecordOfUser(); + + void onLandmarkLoaded(const LLUUID& asset_id, class LLLandmark* landmark); + void storeFavoriteSLURL(const LLUUID& asset_id, std::string& slurl); + + typedef std::map sort_index_map_t; + sort_index_map_t mSortIndexes; + + typedef std::map slurls_map_t; + slurls_map_t mSLURLs; + uuid_set_t mMissingSLURLs; + bool mIsDirty; + + struct IsNotInFavorites + { + IsNotInFavorites(const LLInventoryModel::item_array_t& items) + : mFavoriteItems(items) + { + + } + + /** + * Returns true if specified item is not found among inventory items + */ + bool operator()(const sort_index_map_t::value_type& id_index_pair) const + { + LLPointer item = gInventory.getItem(id_index_pair.first); + if (item.isNull()) return true; + + LLInventoryModel::item_array_t::const_iterator found_it = + std::find(mFavoriteItems.begin(), mFavoriteItems.end(), item); + + return found_it == mFavoriteItems.end(); + } + private: + LLInventoryModel::item_array_t mFavoriteItems; + }; + +}; + +inline +LLFavoritesOrderStorage::LLFavoritesOrderStorage() : + mIsDirty(false) +{ load(); } + +#endif // LL_LLFAVORITESBARCTRL_H diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp index 1551744bdf..8ecf9f8c67 100644 --- a/indra/newview/llfeaturemanager.cpp +++ b/indra/newview/llfeaturemanager.cpp @@ -95,20 +95,26 @@ LLFeatureList::~LLFeatureList() void LLFeatureList::addFeature(const std::string& name, const BOOL available, const F32 level) { - if (mFeatures.count(name)) + LLFeatureInfo fi(name, available, level); + + feature_map_t::iterator iter = mFeatures.find(name); + if (iter != mFeatures.end()) { LL_WARNS("RenderInit") << "LLFeatureList::Attempting to add preexisting feature " << name << LL_ENDL; + iter->second = fi; + } + else + { + mFeatures.insert(std::make_pair(name, fi)); } - - LLFeatureInfo fi(name, available, level); - mFeatures[name] = fi; } BOOL LLFeatureList::isFeatureAvailable(const std::string& name) { - if (mFeatures.count(name)) + feature_map_t::iterator iter = mFeatures.find(name); + if (iter != mFeatures.end()) { - return mFeatures[name].mAvailable; + return iter->second.mAvailable; } LL_WARNS_ONCE("RenderInit") << "Feature " << name << " not on feature list!" << LL_ENDL; @@ -118,20 +124,9 @@ BOOL LLFeatureList::isFeatureAvailable(const std::string& name) return TRUE; } -F32 LLFeatureList::getRecommendedValue(const std::string& name) -{ - if (mFeatures.count(name) && isFeatureAvailable(name)) - { - return mFeatures[name].mRecommendedLevel; - } - - LL_WARNS_ONCE("RenderInit") << "Feature " << name << " not on feature list or not available!" << LL_ENDL; - return 0; -} - BOOL LLFeatureList::maskList(LLFeatureList &mask) { - //llinfos << "Masking with " << mask.mName << llendl; + //LL_INFOS() << "Masking with " << mask.mName << LL_ENDL; // // Lookup the specified feature mask, and overlay it on top of the // current feature mask. @@ -146,13 +141,14 @@ BOOL LLFeatureList::maskList(LLFeatureList &mask) // // Look for the corresponding feature // - if (!mFeatures.count(mask_fi.mName)) + feature_map_t::iterator iter = mFeatures.find(mask_fi.mName); + if (iter == mFeatures.end()) { LL_WARNS("RenderInit") << "Feature " << mask_fi.mName << " in mask not in top level!" << LL_ENDL; continue; } - LLFeatureInfo &cur_fi = mFeatures[mask_fi.mName]; + LLFeatureInfo &cur_fi = iter->second; if (mask_fi.mAvailable && !cur_fi.mAvailable) { LL_WARNS("RenderInit") << "Mask attempting to reenabling disabled feature, ignoring " << cur_fi.mName << LL_ENDL; @@ -238,7 +234,7 @@ BOOL LLFeatureManager::loadFeatureTables() BOOL LLFeatureManager::parseFeatureTable(std::string filename) { - llinfos << "Looking for feature table in " << filename << llendl; + LL_INFOS() << "Looking for feature table in " << filename << LL_ENDL; llifstream file; std::string name; @@ -425,6 +421,9 @@ void LLFeatureManager::parseGPUTable(std::string filename) else { LL_WARNS("RenderInit") << "GPU '" << rawRenderer << "' not recognized" << LL_ENDL; + mGPUString = rawRenderer; + mGPUClass = EGPUClass::GPU_CLASS_3; + mGPUSupported = true; } } @@ -452,7 +451,7 @@ void LLFeatureManager::applyRecommendedSettings() // cap the level at 2 (high) S32 level = llmax(GPU_CLASS_0, llmin(mGPUClass, GPU_CLASS_2)); - llinfos << "Applying Recommended Features" << llendl; + LL_INFOS() << "Applying Recommended Features" << LL_ENDL; setGraphicsLevel(level, false); gSavedSettings.setU32("RenderQualityPerformance", level); @@ -499,30 +498,37 @@ void LLFeatureManager::applyFeatures(bool skipFeatures) LLControlVariable* ctrl = gSavedSettings.getControl(mIt->first); if(ctrl == NULL) { - llwarns << "AHHH! Control setting " << mIt->first << " does not exist!" << llendl; + LL_WARNS() << "AHHH! Control setting " << mIt->first << " does not exist!" << LL_ENDL; continue; } + if (!mIt->second.mAvailable) + { + LL_WARNS_ONCE("RenderInit") << "Feature " << mIt->first << " not available!" << LL_ENDL; + } + + F32 val = mIt->second.mAvailable ? mIt->second.mRecommendedLevel : 0.f; + // handle all the different types if(ctrl->isType(TYPE_BOOLEAN)) { - gSavedSettings.setBOOL(mIt->first, (BOOL)getRecommendedValue(mIt->first)); + gSavedSettings.setBOOL(mIt->first, (BOOL)val); } else if (ctrl->isType(TYPE_S32)) { - gSavedSettings.setS32(mIt->first, (S32)getRecommendedValue(mIt->first)); + gSavedSettings.setS32(mIt->first, (S32)val); } else if (ctrl->isType(TYPE_U32)) { - gSavedSettings.setU32(mIt->first, (U32)getRecommendedValue(mIt->first)); + gSavedSettings.setU32(mIt->first, (U32)val); } else if (ctrl->isType(TYPE_F32)) { - gSavedSettings.setF32(mIt->first, (F32)getRecommendedValue(mIt->first)); + gSavedSettings.setF32(mIt->first, (F32)val); } else { - llwarns << "AHHH! Control variable is not a numeric type!" << llendl; + LL_WARNS() << "AHHH! Control variable is not a numeric type!" << LL_ENDL; } } } @@ -556,7 +562,6 @@ void LLFeatureManager::setGraphicsLevel(S32 level, bool skipFeatures) LLViewerShaderMgr::sSkipReload = false; LLViewerShaderMgr::instance()->setShaders(); - gPipeline.refreshCachedSettings(); } void LLFeatureManager::applyBaseMasks() @@ -626,17 +631,25 @@ void LLFeatureManager::applyBaseMasks() { maskFeatures("GeForceFX"); } - if (gGLManager.mIsIntel) + if (gGLManager.mIsIntel && gGLManager.mGLVersion<3.0f) { - maskFeatures("Intel"); + maskFeatures("IntelPre30"); } - if (gGLManager.mGLVersion < 1.5f) + if (gGLManager.mIsIntel) { - maskFeatures("OpenGLPre15"); + maskFeatures("Intel"); } if (gGLManager.mGLVersion < 3.f) { maskFeatures("OpenGLPre30"); + if(gGLManager.mGLVersion < 2.1f || glUniformMatrix3x4fv == NULL) //glUniformMatrix3x4fv is part of glsl 1.20 spec. + { + maskFeatures("OpenGLPre21"); + if (gGLManager.mGLVersion < 1.5f) + { + maskFeatures("OpenGLPre15"); + } + } } if (gGLManager.mNumTextureImageUnits <= 8) { @@ -646,6 +659,10 @@ void LLFeatureManager::applyBaseMasks() { maskFeatures("MapBufferRange"); } + if (gGLManager.mGLMaxVertexUniformComponents < 1024) + { + maskFeatures("VertexUniformsLT1024"); + } // now mask by gpu string // Replaces ' ' with '_' in mGPUString to deal with inability for parser to handle spaces @@ -658,11 +675,11 @@ void LLFeatureManager::applyBaseMasks() } } - //llinfos << "Masking features from gpu table match: " << gpustr << llendl; + //LL_INFOS() << "Masking features from gpu table match: " << gpustr << LL_ENDL; maskFeatures(gpustr); // now mask cpu type ones - if (gSysMemory.getPhysicalMemoryClamped() <= 256*1024*1024) + if (gSysMemory.getPhysicalMemoryKB() <= U32Megabytes(256)) { maskFeatures("RAM256MB"); } diff --git a/indra/newview/llfeaturemanager.h b/indra/newview/llfeaturemanager.h index a9cb33598f..8fc87eb699 100644 --- a/indra/newview/llfeaturemanager.h +++ b/indra/newview/llfeaturemanager.h @@ -72,7 +72,6 @@ class LLFeatureList virtual ~LLFeatureList(); BOOL isFeatureAvailable(const std::string& name); - F32 getRecommendedValue(const std::string& name); void setFeatureAvailable(const std::string& name, const BOOL available); void setRecommendedLevel(const std::string& name, const F32 level); diff --git a/indra/newview/llfirstuse.cpp b/indra/newview/llfirstuse.cpp index b8e8b37dcf..718d82b502 100644 --- a/indra/newview/llfirstuse.cpp +++ b/indra/newview/llfirstuse.cpp @@ -45,8 +45,8 @@ #include "llviewercontrol.h" #include "llui.h" #include "llappviewer.h" +#include "llfloatertos.h" #include "lltracker.h" -#include "floatervoicelicense.h" #include "llstartup.h" #include "hippogridmanager.h" @@ -303,8 +303,9 @@ void LLFirstUse::voiceLicenseAgreement() { gSavedSettings.setWarning("FirstVoiceLicense", FALSE); - FloaterVoiceLicense::getInstance()->open(); - FloaterVoiceLicense::getInstance()->center(); + auto inst = LLFloaterTOS::show(LLFloaterTOS::TOS_VOICE); + inst->open(); + inst->center(); } else // currently in STATE_LOGIN_VOICE_LICENSE when arriving here { diff --git a/indra/newview/llflexibleobject.cpp b/indra/newview/llflexibleobject.cpp index a800039912..21bfb48499 100644 --- a/indra/newview/llflexibleobject.cpp +++ b/indra/newview/llflexibleobject.cpp @@ -47,8 +47,8 @@ std::vector LLVolumeImplFlexible::sInstanceList; std::vector LLVolumeImplFlexible::sUpdateDelay; -static LLFastTimer::DeclareTimer FTM_FLEXIBLE_REBUILD("Rebuild"); -static LLFastTimer::DeclareTimer FTM_DO_FLEXIBLE_UPDATE("Flexible Update"); +static LLTrace::BlockTimerStatHandle FTM_FLEXIBLE_REBUILD("Rebuild"); +static LLTrace::BlockTimerStatHandle FTM_DO_FLEXIBLE_UPDATE("Flexible Update"); // LLFlexibleObjectData::pack/unpack now in llprimitive.cpp @@ -80,17 +80,12 @@ LLVolumeImplFlexible::LLVolumeImplFlexible(LLViewerObject* vo, LLFlexibleObjectD LLVolumeImplFlexible::~LLVolumeImplFlexible() { - S32 end_idx = sInstanceList.size()-1; - - if (end_idx != mInstanceIndex) - { - sInstanceList[mInstanceIndex] = sInstanceList[end_idx]; - sInstanceList[mInstanceIndex]->mInstanceIndex = mInstanceIndex; - sUpdateDelay[mInstanceIndex] = sUpdateDelay[end_idx]; - } - - sInstanceList.pop_back(); - sUpdateDelay.pop_back(); + std::vector::iterator flex_it(sInstanceList.begin() + mInstanceIndex); + std::vector::iterator iter = vector_replace_with_last(sInstanceList, flex_it); + if(iter != sInstanceList.end()) + (*iter)->mInstanceIndex = mInstanceIndex; + std::vector::iterator update_it(sUpdateDelay.begin() + mInstanceIndex); + vector_replace_with_last(sUpdateDelay, update_it); } //static @@ -293,6 +288,9 @@ void LLVolumeImplFlexible::onSetVolume(const LLVolumeParams &volume_params, cons void LLVolumeImplFlexible::updateRenderRes() { + if (!mAttributes) + return; + LLDrawable* drawablep = mVO->mDrawable; S32 new_res = mAttributes->getSimulateLOD(); @@ -304,7 +302,7 @@ void LLVolumeImplFlexible::updateRenderRes() mRenderRes = (S32) (12.f*app_angle); #else //legacy behavior //number of segments only cares about z axis - F32 app_angle = llround((F32) atan2( mVO->getScale().mV[2]*2.f, drawablep->mDistanceWRTCamera) * RAD_TO_DEG, 0.01f); + F32 app_angle = ll_round((F32) atan2( mVO->getScale().mV[2]*2.f, drawablep->mDistanceWRTCamera) * RAD_TO_DEG, 0.01f); // Rendering sections increases with visible angle on the screen mRenderRes = (S32)(FLEXIBLE_OBJECT_MAX_SECTIONS*4*app_angle*DEG_TO_RAD/LLViewerCamera::getInstance()->getView()); @@ -330,14 +328,14 @@ void LLVolumeImplFlexible::updateRenderRes() // updated every time step. In the future, perhaps there could be an // optimization similar to what Havok does for objects that are stationary. //--------------------------------------------------------------------------------- -static LLFastTimer::DeclareTimer FTM_FLEXIBLE_UPDATE("Update Flexies"); +static LLTrace::BlockTimerStatHandle FTM_FLEXIBLE_UPDATE("Update Flexies"); void LLVolumeImplFlexible::doIdleUpdate() { LLDrawable* drawablep = mVO->mDrawable; if (drawablep) { - //LLFastTimer ftm(FTM_FLEXIBLE_UPDATE); + //LL_RECORD_BLOCK_TIME(FTM_FLEXIBLE_UPDATE); //ensure drawable is active drawablep->makeActive(); @@ -409,7 +407,7 @@ inline S32 log2(S32 x) void LLVolumeImplFlexible::doFlexibleUpdate() { - LLFastTimer ftm(FTM_DO_FLEXIBLE_UPDATE); + LL_RECORD_BLOCK_TIME(FTM_DO_FLEXIBLE_UPDATE); LLVolume* volume = mVO->getVolume(); LLPath *path = &volume->getPath(); if ((mSimulateRes == 0 || !mInitialized) && mVO->mDrawable->isVisible()) @@ -424,7 +422,7 @@ void LLVolumeImplFlexible::doFlexibleUpdate() } } - if(!mInitialized) + if(!mInitialized || !mAttributes) { //the object is not visible return ; @@ -682,15 +680,17 @@ void LLVolumeImplFlexible::doFlexibleUpdate() new_point = &path->mPath[i]; LLVector3 pos = newSection[i].mPosition * rel_xform; LLQuaternion rot = mSection[i].mAxisRotation * newSection[i].mRotation * delta_rot; - - if (!mUpdated || (new_point->mPos-pos).magVec()/mVO->mDrawable->mDistanceWRTCamera > 0.001f) + + LLVector3 np(new_point->mPos.getF32ptr()); + + if (!mUpdated || (np-pos).magVec()/mVO->mDrawable->mDistanceWRTCamera > 0.001f) { - new_point->mPos = newSection[i].mPosition * rel_xform; + new_point->mPos.load3((newSection[i].mPosition * rel_xform).mV); mUpdated = FALSE; } - new_point->mRot = rot; - new_point->mScale = newSection[i].mScale; + new_point->mRot.loadu(LLMatrix3(rot)); + new_point->mScale.set(newSection[i].mScale.mV[0], newSection[i].mScale.mV[1], 0,1); new_point->mTexT = ((F32)i)/(num_render_sections); } @@ -759,7 +759,7 @@ BOOL LLVolumeImplFlexible::doUpdateGeometry(LLDrawable *drawable) if (mRenderRes > -1) { - LLFastTimer t(FTM_DO_FLEXIBLE_UPDATE); + LL_RECORD_BLOCK_TIME(FTM_DO_FLEXIBLE_UPDATE); doFlexibleUpdate(); } @@ -779,7 +779,7 @@ BOOL LLVolumeImplFlexible::doUpdateGeometry(LLDrawable *drawable) volume->mDrawable->setState(LLDrawable::REBUILD_VOLUME); volume->dirtySpatialGroup(); { - LLFastTimer t(FTM_FLEXIBLE_REBUILD); + LL_RECORD_BLOCK_TIME(FTM_FLEXIBLE_REBUILD); doFlexibleRebuild(); } volume->genBBoxes(isVolumeGlobal()); @@ -878,35 +878,38 @@ LLQuaternion LLVolumeImplFlexible::getEndRotation() void LLVolumeImplFlexible::updateRelativeXform(bool force_identity) { - LLQuaternion delta_rot; - LLVector3 delta_pos, delta_scale; + LLVOVolume* vo = (LLVOVolume*) mVO; bool use_identity = vo->mDrawable->isSpatialRoot() || force_identity; + vo->mRelativeXform.setIdentity(); + //matrix from local space to parent relative/global space - delta_rot = use_identity ? LLQuaternion() : vo->mDrawable->getRotation(); - delta_pos = use_identity ? LLVector3(0,0,0) : vo->mDrawable->getPosition(); - delta_scale = LLVector3(1,1,1); + LLVector4a delta_pos; + LLQuaternion2 delta_rot; + if(use_identity) + { + delta_pos.set(0,0,0,1.f); + delta_rot.getVector4aRw() = delta_pos; + } + else + { + delta_pos.load3(vo->mDrawable->getPosition().mV,1.f); + delta_rot.getVector4aRw().loadua(vo->mDrawable->getRotation().mQ); + vo->mRelativeXform.getRow<0>().setRotated(delta_rot,vo->mRelativeXform.getRow<0>()); + vo->mRelativeXform.getRow<1>().setRotated(delta_rot,vo->mRelativeXform.getRow<1>()); + vo->mRelativeXform.getRow<2>().setRotated(delta_rot,vo->mRelativeXform.getRow<2>()); + } - // Vertex transform (4x4) - LLVector3 x_axis = LLVector3(delta_scale.mV[VX], 0.f, 0.f) * delta_rot; - LLVector3 y_axis = LLVector3(0.f, delta_scale.mV[VY], 0.f) * delta_rot; - LLVector3 z_axis = LLVector3(0.f, 0.f, delta_scale.mV[VZ]) * delta_rot; + vo->mRelativeXform.setRow<3>(delta_pos); - vo->mRelativeXform.initRows(LLVector4(x_axis, 0.f), - LLVector4(y_axis, 0.f), - LLVector4(z_axis, 0.f), - LLVector4(delta_pos, 1.f)); - - x_axis.normVec(); - y_axis.normVec(); - z_axis.normVec(); - - vo->mRelativeXformInvTrans.setRows(x_axis, y_axis, z_axis); + vo->mRelativeXformInvTrans = vo->mRelativeXform; + vo->mRelativeXformInvTrans.invert(); + vo->mRelativeXformInvTrans.transpose(); } -const LLMatrix4& LLVolumeImplFlexible::getWorldMatrix(LLXformMatrix* xform) const +const LLMatrix4a& LLVolumeImplFlexible::getWorldMatrix(LLXformMatrix* xform) const { return xform->getWorldMatrix(); } diff --git a/indra/newview/llflexibleobject.h b/indra/newview/llflexibleobject.h index d8b3225465..8768a13dc1 100644 --- a/indra/newview/llflexibleobject.h +++ b/indra/newview/llflexibleobject.h @@ -98,7 +98,7 @@ class LLVolumeImplFlexible : public LLVolumeInterface bool isVolumeUnique() const { return true; } bool isVolumeGlobal() const { return true; } bool isActive() const { return true; } - const LLMatrix4& getWorldMatrix(LLXformMatrix* xform) const; + const LLMatrix4a& getWorldMatrix(LLXformMatrix* xform) const; void updateRelativeXform(bool force_identity); void doFlexibleUpdate(); // Called to update the simulation void doFlexibleRebuild(); // Called to rebuild the geometry diff --git a/indra/newview/llfloaterabout.cpp b/indra/newview/llfloaterabout.cpp index 8bf56b58d9..a083627142 100644 --- a/indra/newview/llfloaterabout.cpp +++ b/indra/newview/llfloaterabout.cpp @@ -49,8 +49,7 @@ #include "llagent.h" #include "llviewerstats.h" #include "llviewerregion.h" -#include "sgversion.h" -#include "llviewerbuild.h" +#include "llversioninfo.h" #include "lluictrlfactory.h" #include "lluri.h" #include "llweb.h" @@ -62,18 +61,19 @@ #include "hippogridmanager.h" -// [RLVa:KB] -#include "rlvhandler.h" +// [RLVa:KB] - Checked: 2010-04-18 (RLVa-1.4.0) +#include "rlvactions.h" +#include "rlvhelper.h" // [/RLVa:KB] #if LL_WINDOWS #include "lldxhardware.h" #endif - - - - +#include "cef/dullahan.h" +#if VLCPLUGIN +#include "vlc/libvlc_version.h" +#endif // LL_WINDOWS extern LLMemoryInfo gSysMemory; extern U32 gPacketsIn; @@ -116,6 +116,9 @@ LLFloaterAbout::LLFloaterAbout() LLViewerTextEditor *credits_widget = getChild("credits_editor", true); + + LLViewerTextEditor *licenses_widget = + getChild("licenses_editor", true); childSetAction("copy_btn", onAboutClickCopyToClipboard, this); @@ -136,12 +139,15 @@ LLFloaterAbout::LLFloaterAbout() // Version string std::string version = std::string(LLAppViewer::instance()->getSecondLifeTitle() +#if defined(_WIN64) || defined(__x86_64__) + + " (64 bit)" +#endif + llformat(" %d.%d.%d (%d) %s %s (%s)\n", - gVersionMajor, gVersionMinor, gVersionPatch, LL_VIEWER_BUILD, + LLVersionInfo::getMajor(), LLVersionInfo::getMinor(), LLVersionInfo::getPatch(), LLVersionInfo::getBuild(), __DATE__, __TIME__, - gVersionChannel)); + LLVersionInfo::getChannel().c_str())); support_widget->appendColoredText(version, FALSE, FALSE, gColors.getColor("TextFgReadOnlyColor")); - support_widget->appendStyledText(LLTrans::getString("ReleaseNotes"), false, false, viewer_link_style); + support_widget->appendText(LLTrans::getString("ReleaseNotes"), false, false, viewer_link_style); std::string support; support.append("\n\n"); @@ -155,7 +161,7 @@ LLFloaterAbout::LLFloaterAbout() support.append(llformat("Built with Clang version %d\n\n", CLANG_VERSION)); #endif -#if LL_ICC +#if LL_INTELC support.append(llformat("Built with ICC version %d\n\n", __ICC)); #endif @@ -165,44 +171,49 @@ LLFloaterAbout::LLFloaterAbout() // Position LLViewerRegion* region = gAgent.getRegion(); -// [RLVa:KB] - Version: 1.23.4 | Checked: 2009-07-04 (RLVa-1.0.0a) - if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) + if (region) { - support.append(RlvStrings::getString(RLV_STRING_HIDDEN)); - support.append("\n\n"); - } - else if (region) -// [/RLVa:KB] -// if (region) - { - LLStyleSP server_link_style(new LLStyle); - server_link_style->setVisible(true); - server_link_style->setFontName(LLStringUtil::null); - server_link_style->setLinkHREF(region->getCapability("ServerReleaseNotes")); - server_link_style->setColor(gSavedSettings.getColor4("HTMLLinkColor")); - +// [RLVa:KB] - Checked: 2014-02-24 (RLVa-1.4.10) + if (RlvActions::canShowLocation()) + { const LLVector3d &pos = gAgent.getPositionGlobal(); LLUIString pos_text = getString("you_are_at"); pos_text.setArg("[POSITION]", llformat("%.1f, %.1f, %.1f ", pos.mdV[VX], pos.mdV[VY], pos.mdV[VZ])); support.append(pos_text); - std::string region_text = llformat("in %s located at ", - gAgent.getRegion()->getName().c_str()); - support.append(region_text); - - std::string buffer; - buffer = gAgent.getRegion()->getHost().getHostName(); - support.append(buffer); - support.append(" ("); - buffer = gAgent.getRegion()->getHost().getString(); - support.append(buffer); - support.append(")\n"); + if (const LLViewerRegion* region = gAgent.getRegion()) + { + const LLVector3d& coords(region->getOriginGlobal()); + std::string region_text = llformat("in %s (%.0f, %.0f) located at ", region->getName().c_str(), coords.mdV[VX]/REGION_WIDTH_METERS, coords.mdV[VY]/REGION_WIDTH_METERS); + support.append(region_text); + + std::string buffer; + buffer = region->getHost().getHostName(); + support.append(buffer); + support.append(" ("); + buffer = region->getHost().getString(); + support.append(buffer); + support.append(")"); + } + } + else + support.append(RlvStrings::getString(RLV_STRING_HIDDEN_REGION)); +// [/RLVa:KN] + support += '\n'; + support.append(gLastVersionChannel); - support.append("\n"); + support += '\n'; support_widget->appendColoredText(support, FALSE, FALSE, gColors.getColor("TextFgReadOnlyColor")); - support_widget->appendStyledText(LLTrans::getString("ReleaseNotes"), false, false, server_link_style); + + const std::string url(region->getCapability("ServerReleaseNotes")); + if (!url.empty()) + { + LLStyleSP server_link_style(new LLStyle(*viewer_link_style)); + server_link_style->setLinkHREF(url); + support_widget->appendText(LLTrans::getString("ReleaseNotes"), false, false, server_link_style); + } support = "\n\n"; } @@ -214,7 +225,7 @@ LLFloaterAbout::LLFloaterAbout() // CPU support.append("CPU: "); support.append( gSysCPU.getCPUString() ); - support.append("\n"); + support += '\n'; /* This is confusing and WRONG. support.append("SSE Support:"); @@ -225,7 +236,7 @@ LLFloaterAbout::LLFloaterAbout() else support.append(" None\n"); */ - U32 memory = gSysMemory.getPhysicalMemoryKB() / 1024; + U32Megabytes memory = gSysMemory.getPhysicalMemoryKB(); // Moved hack adjustment to Windows memory size into llsys.cpp std::string mem_text = llformat("Memory: %u MB\n", memory ); @@ -233,15 +244,15 @@ LLFloaterAbout::LLFloaterAbout() support.append("OS Version: "); support.append( LLAppViewer::instance()->getOSInfo().getOSString() ); - support.append("\n"); + support += '\n'; support.append("Graphics Card Vendor: "); support.append( (const char*) glGetString(GL_VENDOR) ); - support.append("\n"); + support += '\n'; support.append("Graphics Card: "); support.append( (const char*) glGetString(GL_RENDERER) ); - support.append("\n"); + support += '\n'; #if LL_WINDOWS getWindow()->incBusyCount(); @@ -252,43 +263,55 @@ LLFloaterAbout::LLFloaterAbout() { support.append(driver_info["DriverVersion"]); } - support.append("\n"); + support += '\n'; getWindow()->decBusyCount(); getWindow()->setCursor(UI_CURSOR_ARROW); #endif support.append("OpenGL Version: "); support.append( (const char*) glGetString(GL_VERSION) ); +// [RLVa:KB] - Checked: 2010-04-18 (RLVa-1.2.0) + support += '\n'; + support.append("RLV Version: " + (RlvActions::isRlvEnabled() ? RlvStrings::getVersionAbout() : "(disabled)")); +// [/RLVa:KB] support.append("\n\n"); - support.append("Viewer SSE Version: "); -#if _M_IX86_FP > 0 //Windows - support.append(llformat("SSE%i\n", _M_IX86_FP )); -#elif defined(__SSE2__) //GCC - support.append("SSE2\n"); -#elif defined(__SSE__) //GCC - support.append("SSE\n"); -#else - support.append("None\n"); -#endif - support.append("libcurl Version: "); support.append( LLCurl::getVersionString() ); - support.append("\n"); + support += '\n'; support.append("J2C Decoder Version: "); support.append( LLImageJ2C::getEngineInfo() ); - support.append("\n"); + support += '\n'; support.append("Audio Driver Version: "); bool want_fullname = true; support.append( gAudiop ? gAudiop->getDriverName(want_fullname) : "(none)" ); - support.append("\n"); - - // TODO: Implement media plugin version query + support += '\n'; + + std::stringstream supportstrm; + supportstrm << "Dullahan: " + << DULLAHAN_VERSION_MAJOR + << '.' + << DULLAHAN_VERSION_MINOR + << '.' + << DULLAHAN_VERSION_BUILD + + << " / CEF: " << CEF_VERSION + << " / Chrome: " << CHROME_VERSION_MAJOR + << '\n'; + +#if VLCPLUGIN + supportstrm << "LibVLC: "; + supportstrm << LIBVLC_VERSION_MAJOR; + supportstrm << '.'; + supportstrm << LIBVLC_VERSION_MINOR; + supportstrm << '.'; + supportstrm << LIBVLC_VERSION_REVISION; + supportstrm << '\n'; +#endif - support.append("Qt Webkit Version: 4.7.1 (version number hard-coded)"); - support.append("\n"); + support += supportstrm.str(); if (gPacketsIn > 0) { @@ -297,7 +320,7 @@ LLFloaterAbout::LLFloaterAbout() F32(gPacketsIn), 100.f*LLViewerStats::getInstance()->mPacketsLostStat.getCurrent() / F32(gPacketsIn) ); support.append(packet_loss); - support.append("\n"); + support += '\n'; } support_widget->appendColoredText(support, FALSE, FALSE, gColors.getColor("TextFgReadOnlyColor")); @@ -313,6 +336,30 @@ LLFloaterAbout::LLFloaterAbout() credits_widget->setTakesFocus(TRUE); credits_widget->setHandleEditKeysDirectly(TRUE); + // Get the Versions and Copyrights, created at build time + std::string licenses_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "packages-info.txt"); + llifstream licenses_file; + licenses_file.open(licenses_path); /* Flawfinder: ignore */ + if (licenses_file.is_open()) + { + std::string license_line; + licenses_widget->clear(); + while (std::getline(licenses_file, license_line)) + { + licenses_widget->appendColoredText(license_line + '\n', FALSE, FALSE, gColors.getColor("TextFgReadOnlyColor")); + } + licenses_file.close(); + } + else + { + // this case will use the (out of date) hard coded value from the XUI + LL_INFOS("AboutInit") << "Could not read licenses file at " << licenses_path << LL_ENDL; + } + licenses_widget->setCursorPos(0); + licenses_widget->setEnabled(FALSE); + licenses_widget->setTakesFocus(TRUE); + licenses_widget->setHandleEditKeysDirectly(TRUE); + center(); sInstance = this; @@ -338,7 +385,7 @@ void LLFloaterAbout::show(void*) static std::string get_viewer_release_notes_url() { - return "http://www.singularityviewer.org"; + return LLTrans::getString("APP_SITE"); /*std::ostringstream version; version << gVersionMajor << "." << gVersionMinor diff --git a/indra/newview/llfloaterauction.cpp b/indra/newview/llfloaterauction.cpp index 37ebd6f16e..cefa86f5c2 100644 --- a/indra/newview/llfloaterauction.cpp +++ b/indra/newview/llfloaterauction.cpp @@ -3,38 +3,31 @@ * @author James Cook, Ian Wilkes * @brief Implementation of the auction floater. * - * $LicenseInfo:firstyear=2004&license=viewergpl$ - * - * Copyright (c) 2004-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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 "llfloaterauction.h" -#include "lldir.h" #include "llgl.h" #include "llimagej2c.h" #include "llimagetga.h" @@ -46,17 +39,21 @@ #include "llagent.h" #include "llcombobox.h" +#include "llmimetypes.h" #include "llnotifications.h" -#include "llnotificationsutil.h" +#include "llnotificationsutil.h" #include "llviewertexturelist.h" #include "llviewerparcelmgr.h" #include "llviewerregion.h" -#include "lluictrlfactory.h" #include "llviewerwindow.h" #include "llviewerdisplay.h" #include "llviewercontrol.h" #include "llui.h" +#include "lluictrlfactory.h" #include "llrender.h" +#include "llsdutil.h" +#include "llsdutil_math.h" +#include "lltrans.h" ///---------------------------------------------------------------------------- /// Local function declarations, constants, enums, and typedefs @@ -74,8 +71,8 @@ void auction_tga_upload_done(const LLUUID& asset_id, LLFloaterAuction* LLFloaterAuction::sInstance = NULL; // Default constructor -LLFloaterAuction::LLFloaterAuction() : - LLFloater(std::string("floater_auction")), +LLFloaterAuction::LLFloaterAuction() + : LLFloater(std::string("floater_auction")), mParcelID(-1) { LLUICtrlFactory::getInstance()->buildFloater(this, "floater_auction.xml"); @@ -86,13 +83,13 @@ LLFloaterAuction::LLFloaterAuction() : onCommitControlSetting(gSavedSettings), (void*)"AuctionShowFence"); childSetAction("snapshot_btn", onClickSnapshot, this); - childSetAction("ok_btn", onClickOK, this); + childSetAction("ok_btn", onClickStartAuction, this); } // Destroys the object LLFloaterAuction::~LLFloaterAuction() { - sInstance = NULL; + sInstance = nullptr; } // static @@ -104,12 +101,23 @@ void LLFloaterAuction::show() sInstance->center(); sInstance->setFocus(TRUE); } - sInstance->initialize(); sInstance->open(); /*Flawfinder: ignore*/ } +BOOL LLFloaterAuction::postBuild() +{ + return TRUE; +} + +void LLFloaterAuction::onOpen() +{ + initialize(); +} + void LLFloaterAuction::initialize() { + mParcelUpdateCapUrl.clear(); + mParcelp = LLViewerParcelMgr::getInstance()->getParcelSelection(); LLViewerRegion* region = LLViewerParcelMgr::getInstance()->getSelectionRegion(); LLParcel* parcelp = mParcelp->getParcel(); @@ -117,28 +125,30 @@ void LLFloaterAuction::initialize() { mParcelHost = region->getHost(); mParcelID = parcelp->getLocalID(); + mParcelUpdateCapUrl = region->getCapability("ParcelPropertiesUpdate"); - childSetText("parcel_text", parcelp->getName()); - childEnable("snapshot_btn"); - childEnable("ok_btn"); + getChild("parcel_text")->setValue(parcelp->getName()); + getChildView("snapshot_btn")->setEnabled(TRUE); + getChildView("ok_btn")->setEnabled(true); } else { mParcelHost.invalidate(); if(parcelp && parcelp->getForSale()) { - childSetText("parcel_text", getString("already for sale")); + getChild("parcel_text")->setValue(getString("already for sale")); } else { - childSetText("parcel_text", LLStringUtil::null); + getChild("parcel_text")->setValue(LLStringUtil::null); } mParcelID = -1; - childSetEnabled("snapshot_btn", false); - childSetEnabled("ok_btn", false); + getChildView("snapshot_btn")->setEnabled(false); + getChildView("ok_btn")->setEnabled(false); } + mImageID.setNull(); - mImage = NULL; + mImage = nullptr; } void LLFloaterAuction::draw() @@ -147,9 +157,10 @@ void LLFloaterAuction::draw() if(!isMinimized() && mImage.notNull()) { - LLRect rect; - if (childGetRect("snapshot_icon", rect)) + LLView* snapshot_icon = findChild("snapshot_icon"); + if (snapshot_icon) { + LLRect rect = snapshot_icon->getRect(); { gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); gl_rect_2d(rect, LLColor4(0.f, 0.f, 0.f, 1.f)); @@ -176,7 +187,7 @@ void LLFloaterAuction::onClickSnapshot(void* data) LLPointer raw = new LLImageRaw; - gForceRenderLandFence = self->childGetValue("fence_check").asBoolean(); + gForceRenderLandFence = self->getChild("fence_check")->getValue().asBoolean(); BOOL success = gViewerWindow->rawSnapshot(raw, gViewerWindow->getWindowWidth(), gViewerWindow->getWindowHeight(), @@ -193,7 +204,7 @@ void LLFloaterAuction::onClickSnapshot(void* data) { gViewerWindow->playSnapshotAnimAndSound(); } - llinfos << "Writing TGA..." << llendl; + LL_INFOS() << "Writing TGA..." << LL_ENDL; LLPointer tga = new LLImageTGA; tga->encode(raw); @@ -201,7 +212,7 @@ void LLFloaterAuction::onClickSnapshot(void* data) raw->biasedScaleToPowerOfTwo(LLViewerTexture::MAX_IMAGE_SIZE_DEFAULT); - llinfos << "Writing J2C..." << llendl; + LL_INFOS() << "Writing J2C..." << LL_ENDL; LLPointer j2c = new LLImageJ2C; j2c->encode(raw, 0.0f); @@ -213,18 +224,18 @@ void LLFloaterAuction::onClickSnapshot(void* data) } else { - llwarns << "Unable to take snapshot" << llendl; + LL_WARNS() << "Unable to take snapshot" << LL_ENDL; } } // static -void LLFloaterAuction::onClickOK(void* data) +void LLFloaterAuction::onClickStartAuction(void* data) { LLFloaterAuction* self = (LLFloaterAuction*)(data); if(self->mImageID.notNull()) { - LLSD parcel_name = self->childGetValue("parcel_text"); + LLSD parcel_name = self->getChild("parcel_text")->getValue(); // create the asset std::string* name = new std::string(parcel_name.asString()); @@ -257,11 +268,243 @@ void LLFloaterAuction::onClickOK(void* data) msg->sendReliable(self->mParcelHost); // clean up floater, and get out - self->mImageID.setNull(); - self->mImage = NULL; - self->mParcelID = -1; - self->mParcelHost.invalidate(); - self->close(); + self->cleanupAndClose(); +} + + +void LLFloaterAuction::cleanupAndClose() +{ + mImageID.setNull(); + mImage = nullptr; + mParcelID = -1; + mParcelHost.invalidate(); + close(); +} + + + +// static glue +void LLFloaterAuction::onClickResetParcel(void* data) +{ + LLFloaterAuction* self = (LLFloaterAuction*)(data); + if (self) + { + self->doResetParcel(); + } +} + + +// Reset all the values for the parcel in preparation for a sale +void LLFloaterAuction::doResetParcel() +{ + LLParcel* parcelp = mParcelp->getParcel(); + LLViewerRegion* region = LLViewerParcelMgr::getInstance()->getSelectionRegion(); + + if (parcelp + && region + && !mParcelUpdateCapUrl.empty()) + { + LLSD body; + std::string empty; + + // request new properties update from simulator + U32 message_flags = 0x01; + body["flags"] = ll_sd_from_U32(message_flags); + + // Set all the default parcel properties for auction + body["local_id"] = parcelp->getLocalID(); + + U32 parcel_flags = PF_ALLOW_LANDMARK | + PF_ALLOW_FLY | + PF_CREATE_GROUP_OBJECTS | + PF_ALLOW_ALL_OBJECT_ENTRY | + PF_ALLOW_GROUP_OBJECT_ENTRY | + PF_ALLOW_GROUP_SCRIPTS | + PF_RESTRICT_PUSHOBJECT | + PF_SOUND_LOCAL | + PF_ALLOW_VOICE_CHAT | + PF_USE_ESTATE_VOICE_CHAN; + + body["parcel_flags"] = ll_sd_from_U32(parcel_flags); + + // Build a parcel name like "Ahern (128,128) PG 4032m" + std::ostringstream parcel_name; + LLVector3 center_point( parcelp->getCenterpoint() ); + center_point.snap(0); // Get rid of fractions + parcel_name << region->getName() + << " (" + << (S32) center_point.mV[VX] + << "," + << (S32) center_point.mV[VY] + << ") " + << region->getSimAccessString() + << " " + << parcelp->getArea() + << "m"; + + std::string new_name(parcel_name.str()); + body["name"] = new_name; + getChild("parcel_text")->setValue(new_name); // Set name in dialog as well, since it won't get updated otherwise + + body["sale_price"] = (S32) 0; + body["description"] = empty; + body["music_url"] = empty; + body["media_url"] = empty; + body["media_desc"] = empty; + body["media_type"] = LLMIMETypes::getDefaultMimeType(); + body["media_width"] = (S32) 0; + body["media_height"] = (S32) 0; + body["auto_scale"] = (S32) 0; + body["media_loop"] = (S32) 0; + body["obscure_media"] = (S32) 0; // OBSOLETE - no longer used + body["obscure_music"] = (S32) 0; // OBSOLETE - no longer used + body["media_id"] = LLUUID::null; + body["group_id"] = MAINTENANCE_GROUP_ID; // Use maintenance group + body["pass_price"] = (S32) 10; // Defaults to $10 + body["pass_hours"] = 0.0f; + body["category"] = (U8) LLParcel::C_NONE; + body["auth_buyer_id"] = LLUUID::null; + body["snapshot_id"] = LLUUID::null; + body["user_location"] = ll_sd_from_vector3( LLVector3::zero ); + body["user_look_at"] = ll_sd_from_vector3( LLVector3::zero ); + body["landing_type"] = (U8) LLParcel::L_DIRECT; + + LL_INFOS() << "Sending parcel update to reset for auction via capability to: " + << mParcelUpdateCapUrl << LL_ENDL; + LLHTTPClient::post(mParcelUpdateCapUrl, body, new LLHTTPClient::ResponderIgnore()); + + // Send a message to clear the object return time + LLMessageSystem *msg = gMessageSystem; + msg->newMessageFast(_PREHASH_ParcelSetOtherCleanTime); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_ParcelData); + msg->addS32Fast(_PREHASH_LocalID, parcelp->getLocalID()); + msg->addS32Fast(_PREHASH_OtherCleanTime, 5); // 5 minute object auto-return + + msg->sendReliable(region->getHost()); + + // Clear the access lists + clearParcelAccessList(parcelp, region, AL_ACCESS); + clearParcelAccessList(parcelp, region, AL_BAN); + clearParcelAccessList(parcelp, region, AL_ALLOW_EXPERIENCE); + clearParcelAccessList(parcelp, region, AL_BLOCK_EXPERIENCE); + } +} + + + +void LLFloaterAuction::clearParcelAccessList(LLParcel* parcel, LLViewerRegion* region, U32 list) +{ + if (!region || !parcel) return; + + LLUUID transactionUUID; + transactionUUID.generate(); + + LLMessageSystem* msg = gMessageSystem; + + msg->newMessageFast(_PREHASH_ParcelAccessListUpdate); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() ); + msg->nextBlockFast(_PREHASH_Data); + msg->addU32Fast(_PREHASH_Flags, list); + msg->addS32(_PREHASH_LocalID, parcel->getLocalID() ); + msg->addUUIDFast(_PREHASH_TransactionID, transactionUUID); + msg->addS32Fast(_PREHASH_SequenceID, 1); // sequence_id + msg->addS32Fast(_PREHASH_Sections, 0); // num_sections + + // pack an empty block since there will be no data + msg->nextBlockFast(_PREHASH_List); + msg->addUUIDFast(_PREHASH_ID, LLUUID::null ); + msg->addS32Fast(_PREHASH_Time, 0 ); + msg->addU32Fast(_PREHASH_Flags, 0 ); + + msg->sendReliable( region->getHost() ); +} + + + +// static - 'Sell to Anyone' clicked, throw up a confirmation dialog +void LLFloaterAuction::onClickSellToAnyone(void* data) +{ + LLFloaterAuction* self = (LLFloaterAuction*)(data); + if (self) + { + LLParcel* parcelp = self->mParcelp->getParcel(); + + // Do a confirmation + S32 sale_price = parcelp->getArea(); // Selling for L$1 per meter + S32 area = parcelp->getArea(); + + LLSD args; + args["LAND_SIZE"] = llformat("%d", area); + args["SALE_PRICE"] = llformat("%d", sale_price); + args["NAME"] = LLTrans::getString("Anyone"); + + LLNotification::Params params("ConfirmLandSaleChange"); // Re-use existing dialog + params.substitutions(args) + .functor/*.function*/(boost::bind(&LLFloaterAuction::onSellToAnyoneConfirmed, self, _1, _2)); + + params.name("ConfirmLandSaleToAnyoneChange"); + + // ask away + LLNotifications::instance().add(params); + } +} + + +// Sell confirmation clicked +bool LLFloaterAuction::onSellToAnyoneConfirmed(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option == 0) + { + doSellToAnyone(); + } + + return false; +} + + + +// Reset all the values for the parcel in preparation for a sale +void LLFloaterAuction::doSellToAnyone() +{ + LLParcel* parcelp = mParcelp->getParcel(); + LLViewerRegion* region = LLViewerParcelMgr::getInstance()->getSelectionRegion(); + + if (parcelp + && region + && !mParcelUpdateCapUrl.empty()) + { + LLSD body; + + // request new properties update from simulator + U32 message_flags = 0x01; + body["flags"] = ll_sd_from_U32(message_flags); + + // Set all the default parcel properties for auction + body["local_id"] = parcelp->getLocalID(); + + // Set 'for sale' flag + U32 parcel_flags = parcelp->getParcelFlags() | PF_FOR_SALE; + // Ensure objects not included + parcel_flags &= ~PF_FOR_SALE_OBJECTS; + body["parcel_flags"] = ll_sd_from_U32(parcel_flags); + + body["sale_price"] = parcelp->getArea(); // Sell for L$1 per square meter + body["auth_buyer_id"] = LLUUID::null; // To anyone + + LL_INFOS() << "Sending parcel update to sell to anyone for L$1 via capability to: " + << mParcelUpdateCapUrl << LL_ENDL; + + LLHTTPClient::post(mParcelUpdateCapUrl, body, new LLHTTPClient::ResponderIgnore()); + + // clean up floater, and get out + cleanupAndClose(); + } } @@ -272,8 +515,8 @@ void LLFloaterAuction::onClickOK(void* data) void auction_tga_upload_done(const LLUUID& asset_id, void* user_data, S32 status, LLExtStat ext_status) // StoreAssetData callback (fixed) { std::string* name = (std::string*)(user_data); - llinfos << "Upload of asset '" << *name << "' " << asset_id - << " returned " << status << llendl; + LL_INFOS() << "Upload of asset '" << *name << "' " << asset_id + << " returned " << status << LL_ENDL; delete name; gViewerWindow->getWindow()->decBusyCount(); @@ -293,8 +536,8 @@ void auction_tga_upload_done(const LLUUID& asset_id, void* user_data, S32 status void auction_j2c_upload_done(const LLUUID& asset_id, void* user_data, S32 status, LLExtStat ext_status) // StoreAssetData callback (fixed) { std::string* name = (std::string*)(user_data); - llinfos << "Upload of asset '" << *name << "' " << asset_id - << " returned " << status << llendl; + LL_INFOS() << "Upload of asset '" << *name << "' " << asset_id + << " returned " << status << LL_ENDL; delete name; gViewerWindow->getWindow()->decBusyCount(); diff --git a/indra/newview/llfloaterauction.h b/indra/newview/llfloaterauction.h index a9f1ea874f..f431a84fc4 100644 --- a/indra/newview/llfloaterauction.h +++ b/indra/newview/llfloaterauction.h @@ -3,31 +3,25 @@ * @author James Cook, Ian Wilkes * @brief llfloaterauction class header file * - * $LicenseInfo:firstyear=2004&license=viewergpl$ - * - * Copyright (c) 2004-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -36,7 +30,7 @@ #include "llfloater.h" #include "lluuid.h" -#include "llmemory.h" +#include "llsafehandle.h" #include "llviewertexture.h" //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -45,34 +39,50 @@ // Class which holds the functionality to start auctions. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class LLParcelSelection; +class LLParcel; +class LLViewerRegion; -class LLFloaterAuction : public LLFloater +class LLFloaterAuction final : public LLFloater { public: // LLFloater interface - /*virtual*/ void onClose(bool app_quitting) { setVisible(FALSE); } - /*virtual*/ void draw(); + /*virtual*/ void onOpen() override; + /*virtual*/ void onClose(bool app_quitting) override { setVisible(FALSE); } + /*virtual*/ void draw() override; // LLFloaterAuction interface static void show(); - private: + LLFloaterAuction(); ~LLFloaterAuction(); + void initialize(); static void onClickSnapshot(void* data); - static void onClickOK(void* data); + static void onClickResetParcel(void* data); + static void onClickSellToAnyone(void* data); // Sell to anyone clicked + bool onSellToAnyoneConfirmed(const LLSD& notification, const LLSD& response); // Sell confirmation clicked + static void onClickStartAuction(void* data); static LLFloaterAuction* sInstance; + /*virtual*/ BOOL postBuild() override; + + void doResetParcel(); + void doSellToAnyone(); + void clearParcelAccessList(LLParcel* parcel, LLViewerRegion* region, U32 list); + void cleanupAndClose(); private: + LLTransactionID mTransactionID; LLAssetID mImageID; LLPointer mImage; LLSafeHandle mParcelp; S32 mParcelID; LLHost mParcelHost; + + std::string mParcelUpdateCapUrl; // "ParcelPropertiesUpdate" capability }; diff --git a/indra/newview/llfloaterautoreplacesettings.cpp b/indra/newview/llfloaterautoreplacesettings.cpp new file mode 100644 index 0000000000..eabd8c13eb --- /dev/null +++ b/indra/newview/llfloaterautoreplacesettings.cpp @@ -0,0 +1,632 @@ +/** + * @file llfloaterautoreplacesettings.cpp + * @brief Auto Replace List floater + * + * $LicenseInfo:firstyear=2012&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llfloaterautoreplacesettings.h" + +#include "statemachine/aifilepicker.h" +#include "llscrolllistctrl.h" +#include "lluictrlfactory.h" + +#include "llautoreplace.h" +#include "llsdserialize.h" +#include "llsdutil.h" + +#include + +#include "llnotificationsutil.h" + + +LLFloaterAutoReplaceSettings::LLFloaterAutoReplaceSettings(const LLSD& key) + : LLFloater(/*key*/) + , mSelectedListName("") + , mListNames(NULL) + , mReplacementsList(NULL) + , mKeyword(NULL) + , mPreviousKeyword("") + , mReplacement(NULL) +{ + LLUICtrlFactory::getInstance()->buildFloater(this, "floater_autoreplace.xml"); +} + +BOOL LLFloaterAutoReplaceSettings::postBuild(void) +{ + // get copies of the current settings that we will operate on + mEnabled = gSavedSettings.getBOOL("AutoReplace"); + LL_DEBUGS("AutoReplace") << ( mEnabled ? "enabled" : "disabled") << LL_ENDL; + + mSettings = LLAutoReplace::getInstance()->getSettings(); + + // global checkbox for whether or not autoreplace is active + LLUICtrl* enabledCheckbox = getChild("autoreplace_enable"); + enabledCheckbox->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::onAutoReplaceToggled, this)); + enabledCheckbox->setValue(LLSD(mEnabled)); + + // top row list creation and deletion + getChild("autoreplace_import_list")->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::onImportList,this)); + getChild("autoreplace_export_list")->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::onExportList,this)); + getChild("autoreplace_new_list")->setCommitCallback( boost::bind(&LLFloaterAutoReplaceSettings::onNewList,this)); + getChild("autoreplace_delete_list")->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::onDeleteList,this)); + + // the list of keyword->replacement lists + mListNames = getChild("autoreplace_list_name"); + mListNames->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::onSelectList, this)); + mListNames->setCommitOnSelectionChange(true); + + // list ordering + getChild("autoreplace_list_up")->setCommitCallback( boost::bind(&LLFloaterAutoReplaceSettings::onListUp,this)); + getChild("autoreplace_list_down")->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::onListDown,this)); + + // keyword->replacement entry add / delete + getChild("autoreplace_add_entry")->setCommitCallback( boost::bind(&LLFloaterAutoReplaceSettings::onAddEntry,this)); + getChild("autoreplace_delete_entry")->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::onDeleteEntry,this)); + + // entry edits + mKeyword = getChild("autoreplace_keyword"); + mReplacement = getChild("autoreplace_replacement"); + getChild("autoreplace_save_entry")->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::onSaveEntry, this)); + + // dialog termination ( Save Changes / Cancel ) + getChild("autoreplace_save_changes")->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::onSaveChanges, this)); + getChild("autoreplace_cancel")->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::close, this, false)); + + // the list of keyword->replacement pairs + mReplacementsList = getChild("autoreplace_list_replacements"); + mReplacementsList->setCommitCallback(boost::bind(&LLFloaterAutoReplaceSettings::onSelectEntry, this)); + mReplacementsList->setCommitOnSelectionChange(true); + + center(); + + mSelectedListName.clear(); + updateListNames(); + updateListNamesControls(); + updateReplacementsList(); + + return true; +} + + +void LLFloaterAutoReplaceSettings::updateListNames() +{ + mListNames->deleteAllItems(); // start from scratch + + LLSD listNames = mSettings.getListNames(); // Array of Strings + + for ( LLSD::array_const_iterator entry = listNames.beginArray(), end = listNames.endArray(); + entry != end; + ++entry + ) + { + const std::string& listName = entry->asString(); + mListNames->addSimpleElement(listName); + } + + if (!mSelectedListName.empty()) + { + mListNames->setSelectedByValue( LLSD(mSelectedListName), true ); + } +} + +void LLFloaterAutoReplaceSettings::updateListNamesControls() +{ + if ( mSelectedListName.empty() ) + { + // There is no selected list + + // Disable all controls that operate on the selected list + getChild("autoreplace_export_list")->setEnabled(false); + getChild("autoreplace_delete_list")->setEnabled(false); + getChild("autoreplace_list_up")->setEnabled(false); + getChild("autoreplace_list_down")->setEnabled(false); + + mReplacementsList->deleteAllItems(); + } + else + { + // Enable the controls that operate on the selected list + getChild("autoreplace_export_list")->setEnabled(true); + getChild("autoreplace_delete_list")->setEnabled(true); + getChild("autoreplace_list_up")->setEnabled(!selectedListIsFirst()); + getChild("autoreplace_list_down")->setEnabled(!selectedListIsLast()); + } +} + +void LLFloaterAutoReplaceSettings::onSelectList() +{ + std::string previousSelectedListName = mSelectedListName; + // only one selection allowed + LLSD selected = mListNames->getSelectedValue(); + if (selected.isDefined()) + { + mSelectedListName = selected.asString(); + LL_DEBUGS("AutoReplace")<<"selected list '"<getSelectedValue(); + if (selectedRow.isDefined()) + { + mPreviousKeyword = selectedRow.asString(); + LL_DEBUGS("AutoReplace")<<"selected entry '"<setValue(selectedRow); + std::string replacement = mSettings.replacementFor(mPreviousKeyword, mSelectedListName ); + mReplacement->setValue(replacement); + enableReplacementEntry(); + mReplacement->setFocus(true); + } + else + { + // no entry selection, so the entry panel should be off + disableReplacementEntry(); + LL_DEBUGS("AutoReplace")<<"no row selected"<deleteAllItems(); + + if ( mSelectedListName.empty() ) + { + mReplacementsList->setEnabled(false); + getChild("autoreplace_add_entry")->setEnabled(false); + disableReplacementEntry(); + } + else + { + // Populate the keyword->replacement list from the selected list + const LLSD* mappings = mSettings.getListEntries(mSelectedListName); + for ( LLSD::map_const_iterator entry = mappings->beginMap(), end = mappings->endMap(); + entry != end; + entry++ + ) + { + LLSD row; + row["id"] = entry->first; + row["columns"][0]["column"] = "Keyword"; + row["columns"][0]["value"] = entry->first; + row["columns"][1]["column"] = "Replacement"; + row["columns"][1]["value"] = entry->second; + + mReplacementsList->addElement(row, ADD_BOTTOM); + } + + mReplacementsList->deselectAllItems(false /* don't call commit */); + mReplacementsList->setEnabled(true); + + getChild("autoreplace_add_entry")->setEnabled(true); + disableReplacementEntry(); + } +} + +void LLFloaterAutoReplaceSettings::enableReplacementEntry() +{ + LL_DEBUGS("AutoReplace")<setEnabled(true); + mReplacement->setEnabled(true); + getChild("autoreplace_save_entry")->setEnabled(true); + getChild("autoreplace_delete_entry")->setEnabled(true); +} + +void LLFloaterAutoReplaceSettings::disableReplacementEntry() +{ + LL_DEBUGS("AutoReplace")<clear(); + mKeyword->setEnabled(false); + mReplacement->clear(); + mReplacement->setEnabled(false); + getChild("autoreplace_save_entry")->setEnabled(false); + getChild("autoreplace_delete_entry")->setEnabled(false); +} + +// called when the global settings checkbox is changed +void LLFloaterAutoReplaceSettings::onAutoReplaceToggled() +{ + // set our local copy of the flag, copied to the global preference in onOk + mEnabled = childGetValue("autoreplace_enable").asBoolean(); + LL_DEBUGS("AutoReplace")<< "autoreplace_enable " << ( mEnabled ? "on" : "off" ) << LL_ENDL; +} + +// called when the List Up button is pressed +void LLFloaterAutoReplaceSettings::onListUp() +{ + S32 selectedRow = mListNames->getFirstSelectedIndex(); + LLSD selectedName = mListNames->getSelectedValue().asString(); + + if ( mSettings.increaseListPriority(selectedName) ) + { + updateListNames(); + updateListNamesControls(); + } + else + { + LL_WARNS("AutoReplace") + << "invalid row ("<getFirstSelectedIndex(); + std::string selectedName = mListNames->getSelectedValue().asString(); + + if ( mSettings.decreaseListPriority(selectedName) ) + { + updateListNames(); + updateListNamesControls(); + } + else + { + LL_WARNS("AutoReplace") + << "invalid row ("<getSelectedValue(); + if (selectedRow.isDefined()) + { + std::string keyword = selectedRow.asString(); + mReplacementsList->deleteSelectedItems(); // delete from the control + mSettings.removeEntryFromList(keyword, mSelectedListName); // delete from the local settings copy + disableReplacementEntry(); // no selection active, so turn off the buttons + } +} + +// called when the Import List button is pressed +void LLFloaterAutoReplaceSettings::onImportList() +{ + AIFilePicker* picker = AIFilePicker::create(); + picker->open(FFLOAD_XML, "", "autoreplace"); + picker->run(boost::bind(&LLFloaterAutoReplaceSettings::onImportList_continued, this, picker)); +} + +void LLFloaterAutoReplaceSettings::onImportList_continued(AIFilePicker* picker) +{ + if (picker->hasFilename()) + { + llifstream file; + file.open(picker->getFilename()); + LLSD newList; + if (file.is_open()) + { + LLSDSerialize::fromXMLDocument(newList, file); + } + file.close(); + + switch ( mSettings.addList(newList) ) + { + case LLAutoReplaceSettings::AddListOk: + mSelectedListName = LLAutoReplaceSettings::getListName(newList); + + updateListNames(); + updateListNamesControls(); + updateReplacementsList(); + break; + + case LLAutoReplaceSettings::AddListDuplicateName: + { + std::string newName = LLAutoReplaceSettings::getListName(newList); + LL_WARNS("AutoReplace")<<"name '"<getSelectedValue().asString(); + if ( ! listName.empty() ) + { + if ( mSettings.removeReplacementList(listName) ) + { + LL_INFOS("AutoReplace")<<"deleted list '"<deleteSelectedItems(); // remove from the scrolling list + mSelectedListName.clear(); + updateListNames(); + updateListNamesControls(); + updateReplacementsList(); + } + else + { + LL_WARNS("AutoReplace")<<"failed to delete list '"<getFirstSelected()->getColumn(0)->getValue().asString(); + std::string listFileName = listName + ".xml"; + AIFilePicker* picker = AIFilePicker::create(); + picker->open(listFileName, FFSAVE_XML, "", "autoreplace"); + picker->run(boost::bind(&LLFloaterAutoReplaceSettings::onExportList_continued, this, picker, mSettings.exportList(listName))); +} +void LLFloaterAutoReplaceSettings::onExportList_continued(AIFilePicker* picker, const LLSD* list) +{ + if (picker->hasFilename()) + { + llofstream file; + file.open(picker->getFilename()); + LLSDSerialize::toPrettyXML(*list, file); + file.close(); + } +} + +void LLFloaterAutoReplaceSettings::onAddEntry() +{ + mPreviousKeyword.clear(); + mReplacementsList->deselectAllItems(false /* don't call commit */); + mKeyword->clear(); + mReplacement->clear(); + enableReplacementEntry(); + mKeyword->setFocus(true); +} + +void LLFloaterAutoReplaceSettings::onSaveEntry() +{ + LL_DEBUGS("AutoReplace")<<"called"<getWText(); + LLWString replacement = mReplacement->getWText(); + if ( mSettings.addEntryToList(keyword, replacement, mSelectedListName) ) + { + // insert the new keyword->replacement pair + LL_INFOS("AutoReplace") + << "list '" << mSelectedListName << "' " + << "added '" << wstring_to_utf8str(keyword) + << "' -> '" << wstring_to_utf8str(replacement) + << "'" << LL_ENDL; + + updateReplacementsList(); + } + else + { + LLNotificationsUtil::add("InvalidAutoReplaceEntry"); + LL_WARNS("AutoReplace")<<"invalid entry " + << "keyword '" << wstring_to_utf8str(keyword) + << "' replacement '" << wstring_to_utf8str(replacement) + << "'" << LL_ENDL; + } +} + +void LLFloaterAutoReplaceSettings::onSaveChanges() +{ + // put our local copy of the settings into the active copy + LLAutoReplace::getInstance()->setSettings( mSettings ); + // save our local copy of the global feature enable/disable value + gSavedSettings.setBOOL("AutoReplace", mEnabled); + close(); +} + +bool LLFloaterAutoReplaceSettings::selectedListIsFirst() +{ + bool isFirst = false; + + if (!mSelectedListName.empty()) + { + LLSD lists = mSettings.getListNames(); // an Array of Strings + LLSD first = lists.get(0); + if ( first.isString() && first.asString() == mSelectedListName ) + { + isFirst = true; + } + } + return isFirst; +} + +bool LLFloaterAutoReplaceSettings::selectedListIsLast() +{ + bool isLast = false; + + if (!mSelectedListName.empty()) + { + LLSD last; + LLSD lists = mSettings.getListNames(); // an Array of Strings + for ( LLSD::array_const_iterator list = lists.beginArray(), listEnd = lists.endArray(); + list != listEnd; + list++ + ) + { + last = *list; + } + if ( last.isString() && last.asString() == mSelectedListName ) + { + isLast = true; + } + } + return isLast; +} + +/* TBD +mOldText = getChild("autoreplace_old_text"); +mNewText = getChild("autoreplace_new_text"); +*/ diff --git a/indra/newview/llfloaterautoreplacesettings.h b/indra/newview/llfloaterautoreplacesettings.h new file mode 100644 index 0000000000..c9cc98d9f7 --- /dev/null +++ b/indra/newview/llfloaterautoreplacesettings.h @@ -0,0 +1,111 @@ +/** + * @file llfloaterautoreplacesettings.h + * @brief Auto Replace List floater + * @copyright Copyright (c) 2011 LordGregGreg Back + * + * $LicenseInfo:firstyear=2012&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * $/LicenseInfo$ + */ + +#ifndef LLFLOATERAUTOREPLACESETTINGS_H +#define LLFLOATERAUTOREPLACESETTINGS_H + +#include "llfloater.h" +#include "llautoreplace.h" + +class AIFilePicker; +class LLLineEditor; +class LLScrollListCtrl; + +class LLFloaterAutoReplaceSettings : public LLFloater, public LLFloaterSingleton +{ +public: + LLFloaterAutoReplaceSettings(const LLSD& key = LLSD()); + + /*virtual*/ BOOL postBuild(); + +private: + + /** @{ @name Local Copies of Settings + * These are populated in the postBuild method with the values + * current when the floater is instantiated, and then either + * discarded when Cancel is pressed, or copied back to the active + * settings if Ok is pressed. + */ + bool mEnabled; ///< the global preference for AutoReplace + LLAutoReplaceSettings mSettings; ///< settings being modified + /** @} */ + + /// convenience variable - the name of the currently selected list (if any) + std::string mSelectedListName; + /// the scrolling list of list names (one column, no headings, order manually controlled) + LLScrollListCtrl* mListNames; + /// the scroling list of keyword->replacement pairs + LLScrollListCtrl* mReplacementsList; + + /// the keyword for the entry editing pane + LLLineEditor* mKeyword; + /// saved keyword value + std::string mPreviousKeyword; + /// the replacement for the entry editing pane + LLLineEditor* mReplacement; + + /// callback for when the feature enable/disable checkbox changes + void onAutoReplaceToggled(); + /// callback for when an entry in the list of list names is selected + void onSelectList(); + + void onImportList(); + void onImportList_continued(AIFilePicker* picker); + void onExportList(); + void onExportList_continued(AIFilePicker* picker, const LLSD* list); + void onNewList(); + void onDeleteList(); + + void onListUp(); + void onListDown(); + + void onSelectEntry(); + void onAddEntry(); + void onDeleteEntry(); + void onSaveEntry(); + + void onSaveChanges(); + + /// updates the contents of the mListNames + void updateListNames(); + /// updates the controls associated with mListNames (depends on whether a name is selected or not) + void updateListNamesControls(); + /// updates the contents of the mReplacementsList + void updateReplacementsList(); + /// enables the components that should only be active when a keyword is selected + void enableReplacementEntry(); + /// disables the components that should only be active when a keyword is selected + void disableReplacementEntry(); + + /// called from the AddAutoReplaceList notification dialog + bool callbackNewListName(const LLSD& notification, const LLSD& response); + /// called from the RenameAutoReplaceList notification dialog + bool callbackListNameConflict(const LLSD& notification, const LLSD& response); + + bool selectedListIsFirst(); + bool selectedListIsLast(); +}; + +#endif // LLFLOATERAUTOREPLACESETTINGS_H diff --git a/indra/newview/llfloateravatar.cpp b/indra/newview/llfloateravatar.cpp new file mode 100644 index 0000000000..15033c997e --- /dev/null +++ b/indra/newview/llfloateravatar.cpp @@ -0,0 +1,65 @@ +/** + * @file llfloateravatar.h + * @author Leyla Farazha + * @brief floater for the avatar changer + * + * $LicenseInfo:firstyear=2011&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2011, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +/** + * Floater that appears when buying an object, giving a preview + * of its contents and their permissions. + */ + +#include "llviewerprecompiledheaders.h" + +#include "llfloateravatar.h" +#include "llmediactrl.h" +#include "lluictrlfactory.h" +#include "llweb.h" + + +LLFloaterAvatar::LLFloaterAvatar(const LLSD& key) + : LLFloater(key) +{ + LLUICtrlFactory::getInstance()->buildFloater(this, "floater_avatar.xml", NULL, false); +} + +LLFloaterAvatar::~LLFloaterAvatar() +{ +} + +BOOL LLFloaterAvatar::postBuild() +{ + enableResizeCtrls(true, true, false); + LLMediaCtrl* avatar_picker = findChild("avatar_picker_contents"); + if (avatar_picker) + { + avatar_picker->setErrorPageURL(gSavedSettings.getString("GenericErrorPageURL")); + std::string url = gSavedSettings.getString("AvatarPickerURL"); + url = LLWeb::expandURLSubstitutions(url, LLSD()); + avatar_picker->navigateTo(url, "text/html"); + } + return TRUE; +} + + diff --git a/indra/newview/llfloateravatar.h b/indra/newview/llfloateravatar.h new file mode 100644 index 0000000000..10327cf1f5 --- /dev/null +++ b/indra/newview/llfloateravatar.h @@ -0,0 +1,44 @@ +/** + * @file llfloateravatar.h + * @author Leyla Farazha + * @brief floater for the avatar changer + * + * $LicenseInfo:firstyear=2011&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2011, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_FLOATER_AVATAR_H +#define LL_FLOATER_AVATAR_H + +#include "llfloater.h" + +class LLFloaterAvatar: + public LLFloater +, public LLFloaterSingleton +{ + friend class LLUISingleton >; +private: + LLFloaterAvatar(const LLSD& key); + /*virtual*/ ~LLFloaterAvatar(); + /*virtual*/ BOOL postBuild(); +}; + +#endif diff --git a/indra/newview/llfloateravatarlist.cpp b/indra/newview/llfloateravatarlist.cpp index 1cef54918f..a778162fa1 100644 --- a/indra/newview/llfloateravatarlist.cpp +++ b/indra/newview/llfloateravatarlist.cpp @@ -16,144 +16,116 @@ #include "llviewerprecompiledheaders.h" +#include "llfloateravatarlist.h" +#include "llaudioengine.h" #include "llavatarconstants.h" #include "llavatarnamecache.h" -#include "llfloateravatarlist.h" #include "llnotificationsutil.h" #include "llradiogroup.h" #include "llscrolllistcolumn.h" #include "llscrolllistctrl.h" #include "llscrolllistitem.h" +#include "llsdutil.h" +#include "lltrans.h" #include "lluictrlfactory.h" -#include "llviewerwindow.h" #include "llwindow.h" -#include "llvoavatar.h" -#include "llimview.h" -#include "llfloaterreporter.h" +#include "hippogridmanager.h" +#include "lfsimfeaturehandler.h" #include "llagent.h" #include "llagentcamera.h" #include "llavataractions.h" +#include "llfloaterchat.h" #include "llfloaterregioninfo.h" -#include "llviewerregion.h" +#include "llfloaterreporter.h" +#include "llmutelist.h" +#include "llspeakers.h" #include "lltracker.h" -#include "llchat.h" -#include "llfloaterchat.h" +#include "llviewermenu.h" #include "llviewermessage.h" -#include "llweb.h" #include "llviewerobjectlist.h" -#include "llmutelist.h" -#include "llcallbacklist.h" - -#include -#include - -#include -#include -#include -#include - +#include "llviewerregion.h" +#include "llviewerwindow.h" +#include "llvoavatar.h" +#include "llvoiceclient.h" #include "llworld.h" -#include "llsdutil.h" -#include "llaudioengine.h" -#include "llstartup.h" -#include "llviewermenu.h" -#include "hippogridmanager.h" +#include // [RLVa:KB] #include "rlvhandler.h" // [/RLVa:KB] -/** - * @brief How long to keep people who are gone in the list and in memory. - */ -const F32 DEAD_KEEP_TIME = 0.5f; +LLVector3d unpackLocalToGlobalPosition(U32 compact_local, const LLVector3d& origin); extern U32 gFrameCount; -namespace +const S32& radar_namesystem() { -void chat_avatar_status(std::string name, LLUUID key, ERadarStatType type, bool entering) -{ - if(gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) return; //RLVa:LF Don't announce people are around when blind, that cheats the system. - static LLCachedControl radar_chat_alerts(gSavedSettings, "RadarChatAlerts"); - if (!radar_chat_alerts) return; - static LLCachedControl radar_alert_sim(gSavedSettings, "RadarAlertSim"); - static LLCachedControl radar_alert_draw(gSavedSettings, "RadarAlertDraw"); - static LLCachedControl radar_alert_shout_range(gSavedSettings, "RadarAlertShoutRange"); - static LLCachedControl radar_alert_chat_range(gSavedSettings, "RadarAlertChatRange"); - static LLCachedControl radar_alert_age(gSavedSettings, "RadarAlertAge"); + static const LLCachedControl namesystem("RadarNameSystem"); + return namesystem; +} - LLFloaterAvatarList* self = LLFloaterAvatarList::getInstance(); - LLStringUtil::format_map_t args; - args["[NAME]"] = name; - switch(type) +namespace +{ + void chat_avatar_status(const std::string& name, const LLUUID& key, ERadarStatType type, bool entering, const F32& dist, bool flood = false) { - case STAT_TYPE_SIM: - if (radar_alert_sim) - { - args["[RANGE]"] = self->getString("the_sim"); - } - break; - - case STAT_TYPE_DRAW: - if (radar_alert_draw) - { - args["[RANGE]"] = self->getString("draw_distance"); - } - break; - - case STAT_TYPE_SHOUTRANGE: - if (radar_alert_shout_range) - { - args["[RANGE]"] = self->getString("shout_range"); - } - break; - - case STAT_TYPE_CHATRANGE: - if (radar_alert_chat_range) - { - args["[RANGE]"] = self->getString("chat_range"); - } - break; + static LLCachedControl radar_chat_alerts(gSavedSettings, "RadarChatAlerts"); + if (!radar_chat_alerts) return; + // + // If we're teleporting, we don't want to see the radar's alerts about EVERY agent leaving. + if (!entering && gAgent.getTeleportState() != LLAgent::TELEPORT_NONE) + { + return; + } + // + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS)) return; // RLVa:LF Don't announce people are around when blind, that cheats the system. + static LLCachedControl radar_alert_flood(gSavedSettings, "RadarAlertFlood"); + if (flood && !radar_alert_flood) return; + static LLCachedControl radar_alert_sim(gSavedSettings, "RadarAlertSim"); + static LLCachedControl radar_alert_draw(gSavedSettings, "RadarAlertDraw"); + static LLCachedControl radar_alert_shout_range(gSavedSettings, "RadarAlertShoutRange"); + static LLCachedControl radar_alert_chat_range(gSavedSettings, "RadarAlertChatRange"); + static LLCachedControl radar_alert_age(gSavedSettings, "RadarAlertAge"); - case STAT_TYPE_AGE: - if (radar_alert_age) - { - LLChat chat; - chat.mFromName = name; - chat.mText = name + " " + self->getString("has_triggered_your_avatar_age_alert") + "."; - chat.mURL = llformat("secondlife:///app/agent/%s/about",key.asString().c_str()); - chat.mSourceType = CHAT_SOURCE_SYSTEM; - LLFloaterChat::addChat(chat); - } - break; - default: - llassert(type); - break; - } - if (args.find("[RANGE]") != args.end()) - { - args["[ACTION]"] = self->getString(entering ? "has_entered" : "has_left"); + LLStringUtil::format_map_t args; LLChat chat; - chat.mText = self->getString("template", args); + switch(type) + { + case STAT_TYPE_SIM: if (radar_alert_sim) args["[RANGE]"] = LLTrans::getString("the_sim"); break; + case STAT_TYPE_DRAW: if (radar_alert_draw) args["[RANGE]"] = LLTrans::getString("draw_distance"); break; + case STAT_TYPE_SHOUTRANGE: if (radar_alert_shout_range) args["[RANGE]"] = LLTrans::getString("shout_range"); break; + case STAT_TYPE_CHATRANGE: if (radar_alert_chat_range) args["[RANGE]"] = LLTrans::getString("chat_range"); break; + case STAT_TYPE_AGE: if (radar_alert_age) chat.mText = name + ' ' + LLTrans::getString("has_triggered_your_avatar_age_alert") + '.'; break; + default: llassert(type); break; + } + args["[NAME]"] = name; + args["[ACTION]"] = LLTrans::getString((entering ? "has_entered" : "has_left") + (flood ? "_flood" : LLStringUtil::null)); + if (args.find("[RANGE]") != args.end()) + chat.mText = LLTrans::getString("radar_alert_template", args); + else if (chat.mText.empty()) return; + if (entering) // Note: If we decide to make this for leaving as well, change this check to dist != F32_MIN + { + static const LLCachedControl radar_show_dist("RadarAlertShowDist"); + if (radar_show_dist) chat.mText += llformat(" (%.2fm)", dist); + } chat.mFromName = name; - chat.mURL = llformat("secondlife:///app/agent/%s/about",key.asString().c_str()); + chat.mFromID = key; + if (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) // RLVa:LF - No way! + chat.mURL = LLAvatarActions::getSLURL(key); chat.mSourceType = CHAT_SOURCE_SYSTEM; LLFloaterChat::addChat(chat); } -} - void send_keys_message(const int transact_num, const int num_ids, const std::string ids) + void send_keys_message(const int transact_num, const int num_ids, const std::string& ids) { gMessageSystem->newMessage("ScriptDialogReply"); gMessageSystem->nextBlock("AgentData"); - gMessageSystem->addUUID("AgentID", gAgent.getID()); - gMessageSystem->addUUID("SessionID", gAgent.getSessionID()); + gMessageSystem->addUUID("AgentID", gAgentID); + gMessageSystem->addUUID("SessionID", gAgentSessionID); gMessageSystem->nextBlock("Data"); - gMessageSystem->addUUID("ObjectID", gAgent.getID()); + gMessageSystem->addUUID("ObjectID", gAgentID); gMessageSystem->addS32("ChatChannel", -777777777); gMessageSystem->addS32("ButtonIndex", 1); gMessageSystem->addString("ButtonLabel", llformat("%d,%d", transact_num, num_ids) + ids); @@ -161,92 +133,108 @@ void chat_avatar_status(std::string name, LLUUID key, ERadarStatType type, bool } } //namespace -LLAvatarListEntry::LLAvatarListEntry(const LLUUID& id, const std::string &name, const LLVector3d &position) : - mID(id), mName(name), mPosition(position), mMarked(false), mFocused(false), - mUpdateTimer(), mFrame(gFrameCount), mStats(), +const LLColor4* mm_getMarkerColor(const LLUUID& id, bool mark_only = true); +LLAvatarListEntry::LLAvatarListEntry(const LLUUID& id, const std::string& name, const LLVector3d& position) : + mID(id), mName(name), mPosition(position), mMarked(mm_getMarkerColor(id)), mFocused(false), + mStats(), mActivityType(ACTIVITY_NEW), mActivityTimer(), mIsInList(false), mAge(-1), mTime(time(NULL)) { - LLAvatarPropertiesProcessor::getInstance()->addObserver(mID, this); - LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesRequest(mID); + LLAvatarPropertiesProcessor& inst(LLAvatarPropertiesProcessor::instance()); + inst.addObserver(mID, this); + inst.sendAvatarPropertiesRequest(mID); + inst.sendAvatarNotesRequest(mID); } LLAvatarListEntry::~LLAvatarListEntry() { - LLAvatarPropertiesProcessor::getInstance()->removeObserver(mID, this); + static LLCachedControl radar_alert_flood_leaving(gSavedSettings, "RadarAlertFloodLeaving"); + bool cleanup = LLFloaterAvatarList::isCleanup(); + if (radar_alert_flood_leaving || !cleanup) + { + setPosition(mPosition, F32_MIN, false, cleanup); // Dead and gone + } + LLAvatarPropertiesProcessor::instance().removeObserver(mID, this); } // virtual void LLAvatarListEntry::processProperties(void* data, EAvatarProcessorType type) { - if(type == APT_PROPERTIES) + // If one wanted more information that gets displayed on profiles to be displayed, here would be the place to do it. + switch(type) { - LLAvatarPropertiesProcessor::getInstance()->removeObserver(mID, this); - const LLAvatarData* pAvatarData = static_cast(data); - if (pAvatarData && (pAvatarData->avatar_id != LLUUID::null)) - { - using namespace boost::gregorian; - int year, month, day; - sscanf(pAvatarData->born_on.c_str(),"%d/%d/%d",&month,&day,&year); - mAge = (day_clock::local_day() - date(year, month, day)).days(); - if (!mStats[STAT_TYPE_AGE] && mAge >= 0) //Only announce age once per entry. + case APT_PROPERTIES: + if (mAge == -1) { - static const LLCachedControl sAvatarAgeAlertDays(gSavedSettings, "AvatarAgeAlertDays"); - if ((U32)mAge < sAvatarAgeAlertDays) + LLAvatarPropertiesProcessor& inst(LLAvatarPropertiesProcessor::instance()); + const LLAvatarData* pAvatarData = static_cast(data); + if (pAvatarData && (pAvatarData->avatar_id.notNull())) { - chat_avatar_status(mName, mID, STAT_TYPE_AGE, mStats[STAT_TYPE_AGE] = true); + using namespace boost::gregorian; + int year, month, day; + const auto born = pAvatarData->born_on; + if (born.empty()) return; // Opensim returns this for NPCs. + if (sscanf(born.c_str(),"%d/%d/%d",&month,&day,&year) == 3) + try + { + mAge = (day_clock::local_day() - date(year, month, day)).days(); + } + catch(const std::out_of_range&) {} // date throws this, so we didn't assign + + if (mAge >= 0) + { + static const LLCachedControl sAvatarAgeAlertDays(gSavedSettings, "AvatarAgeAlertDays"); + if (!mStats[STAT_TYPE_AGE] && (U32)mAge < sAvatarAgeAlertDays) //Only announce age once per entry. + chat_avatar_status(mName, mID, STAT_TYPE_AGE, mStats[STAT_TYPE_AGE] = true, (mPosition - gAgent.getPositionGlobal()).magVec()); + } + else // Something failed, resend request but only on NonSL grids + { + LL_WARNS() << "Failed to extract age from APT_PROPERTIES for " << mID << ", received \"" << born << "\"." << LL_ENDL; + if (!gHippoGridManager->getConnectedGrid()->isSecondLife()) + { + LL_WARNS() << "Requesting properties again." << LL_ENDL; + inst.sendAvatarPropertiesRequest(mID); + } + } } } - // If one wanted more information that gets displayed on profiles to be displayed, here would be the place to do it. - } + break; + case APT_NOTES: + if (const LLAvatarNotes* pAvatarNotes = static_cast(data)) + mNotes = !pAvatarNotes->notes.empty(); + break; + default: break; } } -void LLAvatarListEntry::setPosition(LLVector3d position, bool this_sim, bool drawn, bool chatrange, bool shoutrange) +void LLAvatarListEntry::setPosition(const LLVector3d& position, const F32& dist, bool drawn, bool flood) { mPosition = position; - - mFrame = gFrameCount; - - if (this_sim != mStats[STAT_TYPE_SIM]) - { - chat_avatar_status(mName, mID, STAT_TYPE_SIM, mStats[STAT_TYPE_SIM] = this_sim); - } - if (drawn != mStats[STAT_TYPE_DRAW]) - { - chat_avatar_status(mName, mID, STAT_TYPE_DRAW, mStats[STAT_TYPE_DRAW] = drawn); - } - if (shoutrange != mStats[STAT_TYPE_SHOUTRANGE]) - { - chat_avatar_status(mName, mID, STAT_TYPE_SHOUTRANGE, mStats[STAT_TYPE_SHOUTRANGE] = shoutrange); - } - if (chatrange != mStats[STAT_TYPE_CHATRANGE]) - { - chat_avatar_status(mName, mID, STAT_TYPE_CHATRANGE, mStats[STAT_TYPE_CHATRANGE] = chatrange); - } - - mUpdateTimer.start(); -} - -bool LLAvatarListEntry::getAlive() -{ - U32 current = gFrameCount; - return ((current - mFrame) <= 2); + bool here(dist != F32_MIN); // F32_MIN only if dead + bool this_sim(here && (gAgent.getRegion()->pointInRegionGlobal(position) || !(LLWorld::getInstance()->positionRegionValidGlobal(position)))); + if (this_sim != mStats[STAT_TYPE_SIM]) chat_avatar_status(mName, mID, STAT_TYPE_SIM, mStats[STAT_TYPE_SIM] = this_sim, dist, flood); + if (drawn != mStats[STAT_TYPE_DRAW]) chat_avatar_status(mName, mID, STAT_TYPE_DRAW, mStats[STAT_TYPE_DRAW] = drawn, dist, flood); + bool shoutrange(here && dist < LFSimFeatureHandler::getInstance()->shoutRange()); + if (shoutrange != mStats[STAT_TYPE_SHOUTRANGE]) chat_avatar_status(mName, mID, STAT_TYPE_SHOUTRANGE, mStats[STAT_TYPE_SHOUTRANGE] = shoutrange, dist, flood); + bool chatrange(here && dist < LFSimFeatureHandler::getInstance()->sayRange()); + if (chatrange != mStats[STAT_TYPE_CHATRANGE]) chat_avatar_status(mName, mID, STAT_TYPE_CHATRANGE, mStats[STAT_TYPE_CHATRANGE] = chatrange, dist, flood); } -F32 LLAvatarListEntry::getEntryAgeSeconds() const +void LLAvatarListEntry::resetName(const bool& hide_tags, const bool& anon_names, const std::string& hidden) { - return mUpdateTimer.getElapsedTimeF32(); + if (hide_tags) + mName = hidden; + else + { + LLAvatarNameCache::getNSName(mID, mName, radar_namesystem()); // We wouldn't be alive if this were to fail now. + if (anon_names) mName = RlvStrings::getAnonym(mName); + } } -bool LLAvatarListEntry::isDead() const -{ - return getEntryAgeSeconds() > DEAD_KEEP_TIME; -} const F32 ACTIVITY_TIMEOUT = 1.0f; void LLAvatarListEntry::setActivity(ACTIVITY_TYPE activity) { - if ( activity >= mActivityType || mActivityTimer.getElapsedTimeF32() > ACTIVITY_TIMEOUT ) + if (activity >= mActivityType || mActivityTimer.getElapsedTimeF32() > ACTIVITY_TIMEOUT) { mActivityType = activity; mActivityTimer.start(); @@ -255,11 +243,10 @@ void LLAvatarListEntry::setActivity(ACTIVITY_TYPE activity) const LLAvatarListEntry::ACTIVITY_TYPE LLAvatarListEntry::getActivity() { - if ( mActivityTimer.getElapsedTimeF32() > ACTIVITY_TIMEOUT ) + if (mActivityTimer.getElapsedTimeF32() > ACTIVITY_TIMEOUT) { mActivityType = ACTIVITY_NONE; } - if(isDead())return ACTIVITY_DEAD; return mActivityType; } @@ -268,7 +255,6 @@ LLFloaterAvatarList::LLFloaterAvatarList() : LLFloater(std::string("radar")), mTracking(false), mUpdate("RadarUpdateEnabled"), mDirtyAvatarSorting(false), - mUpdateRate(gSavedSettings.getU32("RadarUpdateRate") * 3 + 3), mAvatarList(NULL) { LLUICtrlFactory::getInstance()->buildFloater(this, "floater_radar.xml"); @@ -276,21 +262,22 @@ LLFloaterAvatarList::LLFloaterAvatarList() : LLFloater(std::string("radar")), LLFloaterAvatarList::~LLFloaterAvatarList() { - gIdleCallbacks.deleteFunction(LLFloaterAvatarList::callbackIdle); + mCleanup = true; + LLSD sort; + for (const auto& col : mAvatarList->getSortOrder()) + { + sort.append(mAvatarList->getColumn(col.first)->mName); + sort.append(col.second); + } + + gSavedSettings.setLLSD("RadarSortOrder", sort); + mAvatars.clear(); } //static -void LLFloaterAvatarList::toggle(void*) +void LLFloaterAvatarList::toggleInstance(const LLSD&) { -// [RLVa:KB] - if(gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) - { - if(instanceExists()) - getInstance()->close(); - } - else -// [/RLVa:KB] - if(!instanceExists() || !getInstance()->getVisible()) + if (!instanceVisible()) { showInstance(); } @@ -303,10 +290,6 @@ void LLFloaterAvatarList::toggle(void*) //static void LLFloaterAvatarList::showInstance() { -// [RLVa:KB] - if(gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) - return; -// [/RLVa:KB] getInstance()->open(); } @@ -317,87 +300,114 @@ void LLFloaterAvatarList::draw() void LLFloaterAvatarList::onOpen() { - gSavedSettings.setBOOL("ShowRadar", TRUE); + refreshAvatarList(); } void LLFloaterAvatarList::onClose(bool app_quitting) { - setVisible(FALSE); - if (!app_quitting) - { - gSavedSettings.setBOOL("ShowRadar", FALSE); - } - if (!gSavedSettings.getBOOL("RadarKeepOpen") || app_quitting) - { + if (app_quitting || !gSavedSettings.getBOOL("RadarKeepOpen")) destroy(); - } + else + setVisible(false); +} + +BOOL LLFloaterAvatarList::handleRightMouseDown(S32 x, S32 y, MASK mask) +{ + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS) || gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) return TRUE; // RLVa:LF - No menu, menus share listeners with others that we may want to work; plus the user has no idea who these people are!! + return LLFloater::handleRightMouseDown(x, y, mask); +} + +bool is_nearby(const LLUUID& id) +{ + if (id.isNull()) return false; + if (const auto inst = LLFloaterAvatarList::getIfExists()) + return inst->getAvatarEntry(id); + uuid_vec_t avatars; + LLWorld::instance().getAvatars(&avatars); + return std::find(avatars.begin(), avatars.end(), id) != avatars.end(); +} + +const LLVector3d& get_av_pos(const LLUUID& id) +{ + if (const auto inst = LLFloaterAvatarList::getIfExists()) + if (const auto av = inst->getAvatarEntry(id)) + return av->getPosition(); + + LLWorld::pos_map_t avatars; + LLWorld::instance().getAvatars(&avatars); + return avatars[id]; +} + +void track_av(const LLUUID& id) +{ + if (auto inst = LLFloaterAvatarList::getIfExists()) + if (inst->getAvatarEntry(id)) + { + inst->trackAvatar(id); + return; + } + + LLWorld::pos_map_t avatars; + LLWorld::instance().getAvatars(&avatars); + LLTracker::trackLocation(avatars[id], LLStringUtil::null, LLStringUtil::null); } static void cmd_profile(const LLAvatarListEntry* entry); -static void cmd_toggle_mark(LLAvatarListEntry* entry); +static void cmd_toggle_mark(LLAvatarListEntry* entry) +{ + bool mark = !entry->isMarked(); + void mm_setcolor(LLUUID key, LLColor4 col); + void mm_clearMark(const LLUUID & id); + mark ? mm_setcolor(entry->getID(), LLColor4::red) : mm_clearMark(entry->getID()); + entry->setMarked(mark); +} static void cmd_ar(const LLAvatarListEntry* entry); static void cmd_teleport(const LLAvatarListEntry* entry); +const LLUUID& active_owner_or_id(const LLSD& userdata); + namespace { typedef LLMemberListener view_listener_t; - class RadarTrack : public view_listener_t + class RadarTrack final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLFloaterAvatarList::instance().onClickTrack(); return true; } }; - class RadarMark : public view_listener_t - { - bool handleEvent(LLPointer event, const LLSD& userdata) - { - LLFloaterAvatarList::instance().doCommand(cmd_toggle_mark); - return true; - } - }; - - class RadarFocus : public view_listener_t + class RadarFocus final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - LLFloaterAvatarList::instance().onClickFocus(); + LLFloaterAvatarList::setFocusAvatar(active_owner_or_id(userdata)); return true; } }; - class RadarFocusPrev : public view_listener_t + class RadarFocusPrev final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLFloaterAvatarList::instance().focusOnPrev(userdata.asInteger()); return true; } }; - class RadarFocusNext : public view_listener_t + class RadarFocusNext final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLFloaterAvatarList::instance().focusOnNext(userdata.asInteger()); return true; } }; - class RadarTeleportTo : public view_listener_t - { - bool handleEvent(LLPointer event, const LLSD& userdata) - { - LLFloaterAvatarList::instance().doCommand(cmd_teleport, true); - return true; - } - }; - - class RadarAnnounceKeys : public view_listener_t + class RadarAnnounceKeys final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLFloaterAvatarList::instance().sendKeys(); return true; @@ -409,13 +419,11 @@ void addMenu(view_listener_t* menu, const std::string& name); void add_radar_listeners() { - addMenu(new RadarTrack(), "Radar.Track"); - addMenu(new RadarMark(), "Radar.Mark"); - addMenu(new RadarFocus(), "Radar.Focus"); - addMenu(new RadarFocusPrev(), "Radar.FocusPrev"); - addMenu(new RadarFocusNext(), "Radar.FocusNext"); - addMenu(new RadarTeleportTo(), "Radar.TeleportTo"); - addMenu(new RadarAnnounceKeys(), "Radar.AnnounceKeys"); + addMenu(new RadarTrack, "Radar.Track"); + addMenu(new RadarFocus, "Radar.Focus"); + addMenu(new RadarFocusPrev, "Radar.FocusPrev"); + addMenu(new RadarFocusNext, "Radar.FocusNext"); + addMenu(new RadarAnnounceKeys, "Radar.AnnounceKeys"); } BOOL LLFloaterAvatarList::postBuild() @@ -427,10 +435,10 @@ BOOL LLFloaterAvatarList::postBuild() childSetAction("track_btn", boost::bind(&LLFloaterAvatarList::onClickTrack, this)); childSetAction("mark_btn", boost::bind(&LLFloaterAvatarList::doCommand, this, &cmd_toggle_mark, false)); childSetAction("focus_btn", boost::bind(&LLFloaterAvatarList::onClickFocus, this)); - childSetAction("prev_in_list_btn", boost::bind(&LLFloaterAvatarList::focusOnPrev, this, FALSE)); - childSetAction("next_in_list_btn", boost::bind(&LLFloaterAvatarList::focusOnNext, this, FALSE)); - childSetAction("prev_marked_btn", boost::bind(&LLFloaterAvatarList::focusOnPrev, this, TRUE)); - childSetAction("next_marked_btn", boost::bind(&LLFloaterAvatarList::focusOnNext, this, TRUE)); + childSetAction("prev_in_list_btn", boost::bind(&LLFloaterAvatarList::focusOnPrev, this, false)); + childSetAction("next_in_list_btn", boost::bind(&LLFloaterAvatarList::focusOnNext, this, false)); + childSetAction("prev_marked_btn", boost::bind(&LLFloaterAvatarList::focusOnPrev, this, true)); + childSetAction("next_marked_btn", boost::bind(&LLFloaterAvatarList::focusOnNext, this, true)); childSetAction("get_key_btn", boost::bind(&LLFloaterAvatarList::onClickGetKey, this)); @@ -444,26 +452,32 @@ BOOL LLFloaterAvatarList::postBuild() childSetAction("send_keys_btn", boost::bind(&LLFloaterAvatarList::sendKeys, this)); - getChild("update_rate")->setSelectedIndex(gSavedSettings.getU32("RadarUpdateRate")); - getChild("update_rate")->setCommitCallback(boost::bind(&LLFloaterAvatarList::onCommitUpdateRate, this)); - gSavedSettings.getControl("RadarColumnMarkHidden")->getSignal()->connect(boost::bind(&LLFloaterAvatarList::assessColumns, this)); gSavedSettings.getControl("RadarColumnPositionHidden")->getSignal()->connect(boost::bind(&LLFloaterAvatarList::assessColumns, this)); gSavedSettings.getControl("RadarColumnAltitudeHidden")->getSignal()->connect(boost::bind(&LLFloaterAvatarList::assessColumns, this)); gSavedSettings.getControl("RadarColumnActivityHidden")->getSignal()->connect(boost::bind(&LLFloaterAvatarList::assessColumns, this)); + gSavedSettings.getControl("RadarColumnVoiceHidden")->getSignal()->connect(boost::bind(&LLFloaterAvatarList::assessColumns, this)); + gSavedSettings.getControl("RadarColumnNotesHidden")->getSignal()->connect(boost::bind(&LLFloaterAvatarList::assessColumns, this)); gSavedSettings.getControl("RadarColumnAgeHidden")->getSignal()->connect(boost::bind(&LLFloaterAvatarList::assessColumns, this)); gSavedSettings.getControl("RadarColumnTimeHidden")->getSignal()->connect(boost::bind(&LLFloaterAvatarList::assessColumns, this)); // Get a pointer to the scroll list from the interface mAvatarList = getChild("avatar_list"); - mAvatarList->sortByColumn("distance", TRUE); - mAvatarList->setCommitOnSelectionChange(TRUE); + const LLSD sort = gSavedSettings.getLLSD("RadarSortOrder"); + for (auto it = sort.beginArray(), end = sort.endArray(); it < end; ++it) + { + const auto& column_name = (*it); + const auto& ascending = (*++it); + mAvatarList->sortByColumn(column_name.asStringRef(), ascending.asBoolean()); + } + mAvatarList->setCommitOnSelectionChange(true); mAvatarList->setCommitCallback(boost::bind(&LLFloaterAvatarList::onSelectName,this)); mAvatarList->setDoubleClickCallback(boost::bind(&LLFloaterAvatarList::onClickFocus,this)); mAvatarList->setSortChangedCallback(boost::bind(&LLFloaterAvatarList::onAvatarSortingChanged,this)); - refreshAvatarList(); - - gIdleCallbacks.addFunction(LLFloaterAvatarList::callbackIdle); + for (LLViewerRegion* region : LLWorld::instance().getRegionList()) + { + updateAvatarList(region, true); + } assessColumns(); @@ -472,7 +486,7 @@ BOOL LLFloaterAvatarList::postBuild() else gSavedSettings.getControl("RadarColumnClientHidden")->getSignal()->connect(boost::bind(&LLFloaterAvatarList::assessColumns, this)); - return TRUE; + return true; } void col_helper(const bool hide, LLCachedControl &setting, LLScrollListColumn* col) @@ -494,6 +508,21 @@ void col_helper(const bool hide, LLCachedControl &setting, LLScrollListColu } } +enum AVATARS_COLUMN_ORDER +{ + LIST_MARK, + LIST_AVATAR_NAME, + LIST_DISTANCE, + LIST_POSITION, + LIST_ALTITUDE, + LIST_ACTIVITY, + LIST_VOICE, + LIST_NOTES, + LIST_AGE, + LIST_TIME, + LIST_CLIENT, +}; + //Macro to reduce redundant lines. Preprocessor concatenation and stringizing avoids bloat that //wrapping in a class would create. #define BIND_COLUMN_TO_SETTINGS(col, name)\ @@ -507,6 +536,8 @@ void LLFloaterAvatarList::assessColumns() BIND_COLUMN_TO_SETTINGS(LIST_POSITION,Position); BIND_COLUMN_TO_SETTINGS(LIST_ALTITUDE,Altitude); BIND_COLUMN_TO_SETTINGS(LIST_ACTIVITY,Activity); + BIND_COLUMN_TO_SETTINGS(LIST_VOICE,Voice); + BIND_COLUMN_TO_SETTINGS(LIST_NOTES,Notes); BIND_COLUMN_TO_SETTINGS(LIST_AGE,Age); BIND_COLUMN_TO_SETTINGS(LIST_TIME,Time); @@ -557,67 +588,59 @@ void updateParticleActivity(LLDrawable *drawablep) } } -void LLFloaterAvatarList::updateAvatarList() +const F32& radar_range_radius() { - //llinfos << "radar refresh: updating map" << llendl; + static const LLCachedControl radius("RadarRangeRadius", 0); + return radius; +} +void LLFloaterAvatarList::updateAvatarList(const LLViewerRegion* region, bool first) +{ // Check whether updates are enabled if (!mUpdate) { refreshTracker(); return; } - //moved to pipeline to prevent a crash - //gPipeline.forAllVisibleDrawables(updateParticleActivity); - - - //todo: make this less of a hacked up copypasta from dales 1.18. { - std::vector avatar_ids; - std::vector sorted_avatar_ids; - std::vector positions; - - LLVector3d mypos = gAgent.getPositionGlobal(); - static const LLCachedControl radar_range_radius("RadarRangeRadius", 0); - LLWorld::instance().getAvatars(&avatar_ids, &positions, mypos, radar_range_radius ? radar_range_radius : F32_MAX); - - size_t i; - size_t count = avatar_ids.size(); + const std::vector& map_avs(region->mMapAvatars); + const uuid_vec_t& map_avids(region->mMapAvatarIDs); + const LLVector3d& mypos(gAgent.getPositionGlobal()); + const LLVector3d& origin(region->getOriginGlobal()); + const F32 max_range(radar_range_radius() * radar_range_radius()); static LLCachedControl announce(gSavedSettings, "RadarChatKeys"); std::queue announce_keys; - for (i = 0; i < count; ++i) + bool no_names(gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS)); + bool anon_names(!no_names && gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)); + const std::string& rlv_hidden(RlvStrings::getString(RLV_STRING_HIDDEN)); + for (size_t i = 0, size = map_avs.size(); i < size; ++i) { - const LLUUID &avid = avatar_ids[i]; + const LLUUID& avid = map_avids[i]; + LLVector3d position(unpackLocalToGlobalPosition(map_avs[i], origin)); - std::string name; - if (!LLAvatarNameCache::getPNSName(avid, name)) - continue; //prevent (Loading...) - - LLAvatarListEntry* entry = getAvatarEntry(avid); + LLVOAvatar* avatarp = gObjectList.findAvatar(avid); + if (avatarp) position = gAgent.getPosGlobalFromAgent(avatarp->getCharacterPosition()); - LLVector3d position = positions[i]; + if (max_range && dist_vec_squared(position, mypos) > max_range) continue; // Out of desired range - LLVOAvatar* avatarp = gObjectList.findAvatar(avid); - if (avatarp) - { - // Get avatar data - position = gAgent.getPosGlobalFromAgent(avatarp->getCharacterPosition()); - } + std::string name; + if (no_names) name = rlv_hidden; + else if (!LLAvatarNameCache::getNSName(avid, name, radar_namesystem())) continue; //prevent (Loading...) + else if (anon_names) name = RlvStrings::getAnonym(name); + LLAvatarListEntry* entry = getAvatarEntry(avid); if (!entry) { // Avatar not there yet, add it - if(announce && gAgent.getRegion()->pointInRegionGlobal(position)) - announce_keys.push(avid); + if (announce && gAgent.getRegion()->pointInRegionGlobal(position)) announce_keys.push(avid); mAvatars.push_back(LLAvatarListEntryPtr(entry = new LLAvatarListEntry(avid, name, position))); } // Announce position - F32 dist = (F32)(position - mypos).magVec(); - entry->setPosition(position, gAgent.getRegion()->pointInRegionGlobal(position), avatarp, dist < 20.0, dist < 96.0); + entry->setPosition(position, (position - mypos).magVec(), avatarp, first); // Mark as typing if they are typing if (avatarp && avatarp->isTyping()) entry->setActivity(LLAvatarListEntry::ACTIVITY_TYPING); @@ -625,106 +648,77 @@ void LLFloaterAvatarList::updateAvatarList() // Set activity for anyone making sounds if (gAudiop) - { - for (LLAudioEngine::source_map::iterator iter = gAudiop->mAllSources.begin(); iter != gAudiop->mAllSources.end(); ++iter) - { - LLAudioSource* sourcep = iter->second; - if (LLAvatarListEntry* entry = getAvatarEntry(sourcep->getOwnerID())) - { + for (LLAudioEngine::source_map::iterator i = gAudiop->mAllSources.begin(); i != gAudiop->mAllSources.end(); ++i) + if (LLAvatarListEntry* entry = getAvatarEntry((i->second)->getOwnerID())) entry->setActivity(LLAvatarListEntry::ACTIVITY_SOUND); - } - } - } //let us send the keys in a more timely fashion if (announce && !announce_keys.empty()) { // NOTE: This fragment is repeated in sendKey std::ostringstream ids; - int transact_num = (int)gFrameCount; - int num_ids = 0; + U32 transact_num = gFrameCount; + U32 num_ids = 0; while(!announce_keys.empty()) { - LLUUID id = announce_keys.front(); - announce_keys.pop(); - - ids << "," << id.asString(); + ids << ',' << announce_keys.front().asString(); ++num_ids; - if (ids.tellp() > 200) { send_keys_message(transact_num, num_ids, ids.str()); - - num_ids = 0; - ids.seekp(0); - ids.str(""); + ids.seekp(num_ids = 0); + ids.str(LLStringUtil::null); } + announce_keys.pop(); } - if (num_ids > 0) - send_keys_message(transact_num, num_ids, ids.str()); + if (num_ids) send_keys_message(transact_num, num_ids, ids.str()); } } - -// llinfos << "radar refresh: done" << llendl; - - expireAvatarList(); - - if (mAvatars.empty()) - setTitle(getString("Title")); - else if (mAvatars.size() == 1) - setTitle(getString("TitleOneAvatar")); - else - { - LLStringUtil::format_map_t args; - args["[COUNT]"] = boost::lexical_cast(mAvatars.size()); - setTitle(getString("TitleWithCount", args)); - } - - refreshAvatarList(); - refreshTracker(); } -void LLFloaterAvatarList::expireAvatarList() +void LLFloaterAvatarList::expireAvatarList(const std::list& ids) { -// llinfos << "radar: expiring" << llendl; - for(av_list_t::iterator it = mAvatars.begin(); it != mAvatars.end();) + if (!ids.empty()) { - LLAvatarListEntry* entry = it->get(); - if(!entry->isDead()) + uuid_vec_t existing_avs; + std::vector neighbors; + gAgent.getRegion()->getNeighboringRegions(neighbors); + for (const LLViewerRegion* region : neighbors) + existing_avs.insert(existing_avs.end(), region->mMapAvatarIDs.begin(), region->mMapAvatarIDs.end()); + for (const LLUUID& id : ids) { - entry->getAlive(); - ++it; - } - else - { - entry->setPosition(entry->getPosition(), false, false, false, false); // Dead and gone - it = mAvatars.erase(it); + if (std::find(existing_avs.begin(), existing_avs.end(), id) != existing_avs.end()) continue; // Now in another region we know. + av_list_t::iterator it(std::find_if(mAvatars.begin(), mAvatars.end(), LLAvatarListEntry::uuidMatch(id))); + if (it != mAvatars.end()) + mAvatars.erase(it); } } + + refreshAvatarList(); + refreshTracker(); } void LLFloaterAvatarList::updateAvatarSorting() { - if(mDirtyAvatarSorting) + if (mDirtyAvatarSorting) { mDirtyAvatarSorting = false; - if(mAvatars.size() <= 1) //Nothing to sort. - return; + if (mAvatars.size() <= 1) return; // Nothing to sort. + const std::vector list = mAvatarList->getAllData(); av_list_t::iterator insert_it = mAvatars.begin(); - for(std::vector::const_iterator it=list.begin();it!=list.end();++it) + for(std::vector::const_iterator it = list.begin(); it != list.end(); ++it) { av_list_t::iterator av_it = std::find_if(mAvatars.begin(),mAvatars.end(),LLAvatarListEntry::uuidMatch((*it)->getUUID())); - if(av_it!=mAvatars.end()) - { - std::iter_swap(insert_it++,av_it); - if(insert_it+1 == mAvatars.end()) //We've ran out of elements to sort - return; - } + if (av_it == mAvatars.end()) continue; + std::iter_swap(insert_it++, av_it); + if (insert_it+1 == mAvatars.end()) return; // We've run out of elements to sort } } } +bool getCustomColorRLV(const LLUUID& id, LLColor4& color, LLViewerRegion* parent_estate, bool name_restricted); + /** * Redraws the avatar list * Only does anything if the avatar list is visible. @@ -732,7 +726,7 @@ void LLFloaterAvatarList::updateAvatarSorting() */ void LLFloaterAvatarList::refreshAvatarList() { - // Don't update list when interface is hidden + // Don't update when interface is hidden if (!getVisible()) return; // We rebuild the list fully each time it's refreshed @@ -747,38 +741,21 @@ void LLFloaterAvatarList::refreshAvatarList() LLVector3d posagent; posagent.setVec(gAgent.getPositionAgent()); LLVector3d simpos = mypos - posagent; + const S32 width(gAgent.getRegion() ? gAgent.getRegion()->getWidth() : 256); + LLSpeakerMgr& speakermgr = LLActiveSpeakerMgr::instance(); + LLRect screen_rect; + localRectToScreen(getLocalRect(), &screen_rect); + speakermgr.update(!(screen_rect.pointInRect(gViewerWindow->getCurrentMouseX(), gViewerWindow->getCurrentMouseY()) && gMouseIdleTimer.getElapsedTimeF32() < 5.f)); - BOOST_FOREACH(av_list_t::value_type& entry, mAvatars) + av_list_t dead_entries; + bool name_restricted(gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS) || gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)); + for (auto& entry : mAvatars) { - LLScrollListItem::Params element; - LLUUID av_id; - std::string av_name; - - // Skip if avatar hasn't been around - if (entry->isDead()) - { - continue; - } - - entry->setInList(); - - av_id = entry->getID(); - av_name = entry->getName().c_str(); - LLVector3d position = entry->getPosition(); - BOOL UnknownAltitude = false; - LLVector3d delta = position - mypos; - F32 distance = (F32)delta.magVec(); - F32 unknownAlt = (gHippoGridManager->getConnectedGrid()->isSecondLife()) ? 1020.f : 0.f; - if (position.mdV[VZ] == unknownAlt) - { - UnknownAltitude = true; - distance = 9000.0; - } + bool UnknownAltitude = position.mdV[VZ] == (gHippoGridManager->getConnectedGrid()->isSecondLife() ? 1020.f : 0.f); + F32 distance = UnknownAltitude ? 9000.0f : (F32)delta.magVec(); delta.mdV[2] = 0.0f; - F32 side_distance = (F32)delta.magVec(); - // HACK: Workaround for an apparent bug: // sometimes avatar entries get stuck, and are registered // by the client as perpetually moving in the same direction. @@ -786,293 +763,315 @@ void LLFloaterAvatarList::refreshAvatarList() //jcool410 -- this fucks up seeing dueds thru minimap data > 1024m away, so, lets just say > 2048m to the side is bad //aka 8 sims - if (side_distance > 2048.0f) + if (delta.magVec() > 2048.0) { + dead_entries.push_back(entry); continue; } + entry->setInList(); + const LLUUID& av_id = entry->getID(); + LLScrollListItem::Params element; element.value = av_id; - LLScrollListCell::Params mark; - mark.column = "marked"; - mark.type = "text"; - if (entry->isMarked()) + static const LLCachedControl hide_mark("RadarColumnMarkHidden"); + if (!hide_mark) { - mark.value = "X"; - mark.color = LLColor4::blue; - mark.font_style = "BOLD"; - } - - LLScrollListCell::Params name; - name.column = "avatar_name"; - name.type = "text"; - name.value = av_name; - if (entry->isFocused()) - { - name.font_style = "BOLD"; - } - - // custom colors for certain types of avatars! - //Changed a bit so people can modify them in settings. And since they're colors, again it's possibly account-based. Starting to think I need a function just to determine that. - HgB - //name.color = gColors.getColor( "MapAvatar" ); - LLViewerRegion* parent_estate = LLWorld::getInstance()->getRegionFromPosGlobal(entry->getPosition()); - LLUUID estate_owner = LLUUID::null; - if(parent_estate && parent_estate->isAlive()) - { - estate_owner = parent_estate->getOwner(); + LLScrollListCell::Params mark; + mark.column = "marked"; + mark.type = "text"; + if (entry->isMarked()) + { + mark.value = "X"; + mark.color = *mm_getMarkerColor(av_id); + mark.font_style = "BOLD"; + } + element.columns.add(mark); } - static const LLCachedControl unselected_color(gColors, "ScrollUnselectedColor",LLColor4(0.f, 0.f, 0.f, 0.8f)); + static const LLCachedControl unselected_color(gColors, "ScrollUnselectedColor", LLColor4(0.f, 0.f, 0.f, 0.8f)); - static LLCachedControl sDefaultListText(gColors, "DefaultListText"); - static LLCachedControl sRadarTextChatRange(gColors, "RadarTextChatRange"); - static LLCachedControl sRadarTextShoutRange(gColors, "RadarTextShoutRange"); - static LLCachedControl sRadarTextDrawDist(gColors, "RadarTextDrawDist"); - static LLCachedControl sRadarTextYoung(gColors, "RadarTextYoung"); - LLColor4 name_color = sDefaultListText; + static const LLCachedControl sDefaultListText(gColors, "DefaultListText"); + static const LLCachedControl ascent_muted_color("AscentMutedColor", LLColor4(0.7f,0.7f,0.7f,1.f)); + LLColor4 color = sDefaultListText; - //Lindens are always more Linden than your friend, make that take precedence - if(LLMuteList::getInstance()->isLinden(av_id)) - { - static const LLCachedControl ascent_linden_color("AscentLindenColor",LLColor4(0.f,0.f,1.f,1.f)); - name_color = ascent_linden_color; - } - //check if they are an estate owner at their current position - else if(estate_owner.notNull() && av_id == estate_owner) + // Name never hidden { - static const LLCachedControl ascent_estate_owner_color("AscentEstateOwnerColor",LLColor4(1.f,0.6f,1.f,1.f)); - name_color = ascent_estate_owner_color; - } - //without these dots, SL would suck. - else if(LLAvatarActions::isFriend(av_id)) - { - static const LLCachedControl ascent_friend_color("AscentFriendColor",LLColor4(1.f,1.f,0.f,1.f)); - name_color = ascent_friend_color; - } - //big fat jerkface who is probably a jerk, display them as such. - else if(LLMuteList::getInstance()->isMuted(av_id)) - { - static const LLCachedControl ascent_muted_color("AscentMutedColor",LLColor4(0.7f,0.7f,0.7f,1.f)); - name_color = ascent_muted_color; - } - - name_color = name_color*0.5f + unselected_color*0.5f; + LLScrollListCell::Params name; + name.column = "avatar_name"; + name.type = "text"; + name.value = entry->getName(); + if (entry->isFocused()) + { + name.font_style = "BOLD"; + } - name.color = name_color; + // custom colors for certain types of avatars! + getCustomColorRLV(av_id, color, LLWorld::getInstance()->getRegionFromPosGlobal(entry->getPosition()), name_restricted); + name.color = color*0.5f + unselected_color*0.5f; + element.columns.add(name); + } char temp[32]; - LLColor4 color = sDefaultListText; - LLScrollListCell::Params dist; - dist.column = "distance"; - dist.type = "text"; - if (UnknownAltitude) + // Distance never hidden { - strcpy(temp, "?"); - if (entry->mStats[STAT_TYPE_DRAW]) + color = sDefaultListText; + LLScrollListCell::Params dist; + dist.column = "distance"; + dist.type = "text"; + static const LLCachedControl sRadarTextDrawDist(gColors, "RadarTextDrawDist"); + if (UnknownAltitude) { - color = sRadarTextDrawDist; + strcpy(temp, "?"); + if (entry->mStats[STAT_TYPE_DRAW]) + { + color = sRadarTextDrawDist; + } } - } - else - { - if (distance <= 96.0) + else { - snprintf(temp, sizeof(temp), "%.1f", distance); - if (distance > 20.0f) + if (distance <= LFSimFeatureHandler::getInstance()->shoutRange()) { - color = sRadarTextShoutRange; + static const LLCachedControl sRadarTextChatRange(gColors, "RadarTextChatRange"); + static const LLCachedControl sRadarTextShoutRange(gColors, "RadarTextShoutRange"); + snprintf(temp, sizeof(temp), "%.1f", distance); + color = (distance > LFSimFeatureHandler::getInstance()->sayRange()) ? sRadarTextShoutRange : sRadarTextChatRange; } else { - color = sRadarTextChatRange; + if (entry->mStats[STAT_TYPE_DRAW]) color = sRadarTextDrawDist; + snprintf(temp, sizeof(temp), "%d", (S32)distance); } } + dist.value = temp; + dist.color = color * 0.7f + unselected_color * 0.3f; // Liru: Blend testing! + //dist.color = color; + element.columns.add(dist); + } + + static const LLCachedControl hide_pos("RadarColumnPositionHidden"); + if (!hide_pos) + { + LLScrollListCell::Params pos; + position -= simpos; + + S32 x(position.mdV[VX]); + S32 y(position.mdV[VY]); + if (x >= 0 && x <= width && y >= 0 && y <= width) + { + snprintf(temp, sizeof(temp), "%d, %d", x, y); + } else { - if (entry->mStats[STAT_TYPE_DRAW]) + temp[0] = '\0'; + if (y < 0) { - color = sRadarTextDrawDist; + strcat(temp, "S"); + } + else if (y > width) + { + strcat(temp, "N"); + } + if (x < 0) + { + strcat(temp, "W"); + } + else if (x > width) + { + strcat(temp, "E"); } - snprintf(temp, sizeof(temp), "%d", (S32)distance); } + pos.column = "position"; + pos.type = "text"; + pos.value = temp; + element.columns.add(pos); } - dist.value = temp; - dist.color = color; - LLScrollListCell::Params pos; - position = position - simpos; - - S32 x = (S32)position.mdV[VX]; - S32 y = (S32)position.mdV[VY]; - if (x >= 0 && x <= 256 && y >= 0 && y <= 256) + static const LLCachedControl hide_alt("RadarColumnAltitudeHidden"); + if (!hide_alt) { - snprintf(temp, sizeof(temp), "%d, %d", x, y); - } - else - { - temp[0] = '\0'; - if (y < 0) + LLScrollListCell::Params alt; + alt.column = "altitude"; + alt.type = "text"; + if (UnknownAltitude) { - strcat(temp, "S"); + strcpy(temp, "?"); } - else if (y > 256) - { - strcat(temp, "N"); - } - if (x < 0) + else { - strcat(temp, "W"); + snprintf(temp, sizeof(temp), "%d", (S32)position.mdV[VZ]); } - else if (x > 256) + alt.value = temp; + element.columns.add(alt); + } + + static const LLCachedControl hide_act("RadarColumnActivityHidden"); + if (!hide_act) + { + LLScrollListCell::Params act; + act.column = "activity"; + act.type = "icon"; + switch(entry->getActivity()) { - strcat(temp, "E"); + case LLAvatarListEntry::ACTIVITY_MOVING: + act.value = "inv_item_animation.tga"; + act.tool_tip = getString("Moving"); + break; + case LLAvatarListEntry::ACTIVITY_GESTURING: + act.value = "inv_item_gesture.tga"; + act.tool_tip = getString("Playing a gesture"); + break; + case LLAvatarListEntry::ACTIVITY_SOUND: + act.value = "inv_item_sound.tga"; + act.tool_tip = getString("Playing a sound"); + break; + case LLAvatarListEntry::ACTIVITY_REZZING: + act.value = "ff_edit_theirs.tga"; + act.tool_tip = getString("Rezzing objects"); + break; + case LLAvatarListEntry::ACTIVITY_PARTICLES: + act.value = "particles_scan.tga"; + act.tool_tip = getString("Creating particles"); + break; + case LLAvatarListEntry::ACTIVITY_NEW: + act.value = "avatar_new.tga"; + act.tool_tip = getString("Just arrived"); + break; + case LLAvatarListEntry::ACTIVITY_TYPING: + act.value = "avatar_typing.tga"; + act.tool_tip = getString("Typing"); + break; + default: + break; } + element.columns.add(act); } - pos.column = "position"; - pos.type = "text"; - pos.value = temp; - - LLScrollListCell::Params alt; - alt.column = "altitude"; - alt.type = "text"; - if (UnknownAltitude) + + static const LLCachedControl hide_voice("RadarColumnVoiceHidden"); + if (!hide_voice) { - strcpy(temp, "?"); + LLScrollListCell::Params voice; + voice.column("voice"); + voice.type("icon"); + // transplant from llparticipantlist.cpp, update accordingly. + if (LLPointer speakerp = speakermgr.findSpeaker(av_id)) + { + if (speakerp->mStatus == LLSpeaker::STATUS_MUTED) + { + voice.value("mute_icon.tga"); + voice.color(speakerp->mModeratorMutedVoice ? ascent_muted_color : LLColor4(1.f, 71.f / 255.f, 71.f / 255.f, 1.f)); + } + else + { + switch(llmin(2, llfloor((speakerp->mSpeechVolume / LLVoiceClient::OVERDRIVEN_POWER_LEVEL) * 3.f))) + { + case 0: + voice.value("icn_active-speakers-dot-lvl0.tga"); + break; + case 1: + voice.value("icn_active-speakers-dot-lvl1.tga"); + break; + case 2: + voice.value("icn_active-speakers-dot-lvl2.tga"); + break; + } + // non voice speakers have hidden icons, render as transparent + voice.color(speakerp->mStatus > LLSpeaker::STATUS_VOICE_ACTIVE ? LLColor4::transparent : speakerp->mDotColor); + } + } + element.columns.add(voice); } - else + + static const LLCachedControl hide_notes("RadarColumnNotesHidden"); + if (!hide_notes) { - snprintf(temp, sizeof(temp), "%d", (S32)position.mdV[VZ]); + element.columns.add(LLScrollListCell::Params().column("notes").type("checkbox").enabled(false).value(entry->mNotes)); } - alt.value = temp; - LLScrollListCell::Params act; - act.column = "activity"; - act.type = "icon"; - - std::string activity_icon = ""; - std::string activity_tip = ""; - switch(entry->getActivity()) + static const LLCachedControl hide_age("RadarColumnAgeHidden"); + if (!hide_age) { - case LLAvatarListEntry::ACTIVITY_MOVING: - { - activity_icon = "inv_item_animation.tga"; - activity_tip = getString("Moving"); - } - break; - case LLAvatarListEntry::ACTIVITY_GESTURING: - { - activity_icon = "inv_item_gesture.tga"; - activity_tip = getString("Playing a gesture"); - } - break; - case LLAvatarListEntry::ACTIVITY_SOUND: + LLScrollListCell::Params agep; + agep.column = "age"; + agep.type = "text"; + color = sDefaultListText; + bool age_set(entry->mAge > -1); + if (age_set) { - activity_icon = "inv_item_sound.tga"; - activity_tip = getString("Playing a sound"); - } - break; - case LLAvatarListEntry::ACTIVITY_REZZING: - { - activity_icon = "ff_edit_theirs.tga"; - activity_tip = getString("Rezzing objects"); - } - break; - case LLAvatarListEntry::ACTIVITY_PARTICLES: - { - activity_icon = "particles_scan.tga"; - activity_tip = getString("Creating particles"); - } - break; - case LLAvatarListEntry::ACTIVITY_NEW: - { - activity_icon = "avatar_new.tga"; - activity_tip = getString("Just arrived"); - } - break; - case LLAvatarListEntry::ACTIVITY_TYPING: - { - activity_icon = "avatar_typing.tga"; - activity_tip = getString("Typing"); + static const LLCachedControl sAvatarAgeAlertDays(gSavedSettings, "AvatarAgeAlertDays"); + if ((U32)entry->mAge < sAvatarAgeAlertDays) + { + static const LLCachedControl sRadarTextYoung(gColors, "RadarTextYoung"); + color = sRadarTextYoung; + } } - break; - default: - break; + agep.value = age_set ? fmt::to_string(entry->mAge) : "?"; + agep.color = color; + element.columns.add(agep); } - act.value = activity_icon;//icon_image_id; //"icn_active-speakers-dot-lvl0.tga"; - //act.color = icon_color; - act.tool_tip = activity_tip; - - LLScrollListCell::Params agep; - agep.column = "age"; - agep.type = "text"; - color = sDefaultListText; - std::string age = boost::lexical_cast(entry->mAge); - if (entry->mAge > -1) + static const LLCachedControl hide_time("RadarColumnTimeHidden"); + if (!hide_time) { - static const LLCachedControl sAvatarAgeAlertDays(gSavedSettings, "AvatarAgeAlertDays"); - if ((U32)entry->mAge < sAvatarAgeAlertDays) - color = sRadarTextYoung; + int dur = difftime(time(NULL), entry->getTime()); + int hours = dur / 3600; + int mins = (dur % 3600) / 60; + int secs = (dur % 3600) % 60; + + LLScrollListCell::Params time; + time.column = "time"; + time.type = "text"; + time.value = llformat("%d:%02d:%02d", hours, mins, secs); + element.columns.add(time); } - else - { - age = "?"; - } - agep.value = age; - agep.color = color; - - int dur = difftime(time(NULL), entry->getTime()); - int hours = dur / 3600; - int mins = (dur % 3600) / 60; - int secs = (dur % 3600) % 60; - - LLScrollListCell::Params time; - time.column = "time"; - time.type = "text"; - time.value = llformat("%d:%02d:%02d", hours, mins, secs); - - LLScrollListCell::Params viewer; - viewer.column = "client"; - viewer.type = "text"; - - static const LLCachedControl avatar_name_color(gColors, "AvatarNameColor",LLColor4(0.98f, 0.69f, 0.36f, 1.f)); - LLColor4 client_color(avatar_name_color); - LLVOAvatar* avatarp = gObjectList.findAvatar(av_id); - if(avatarp) + + static const LLCachedControl hide_client("RadarColumnClientHidden"); + if (!hide_client) { - std::string client = SHClientTagMgr::instance().getClientName(avatarp, false); - SHClientTagMgr::instance().getClientColor(avatarp, false, client_color); - if(client == "") + LLScrollListCell::Params viewer; + viewer.column = "client"; + viewer.type = "text"; + + static const LLCachedControl avatar_name_color(gColors, "AvatarNameColor",LLColor4(0.98f, 0.69f, 0.36f, 1.f)); + color = avatar_name_color; + if (LLVOAvatar* avatarp = gObjectList.findAvatar(av_id)) { - client_color = unselected_color; - client = "?"; + std::string client = SHClientTagMgr::instance().getClientName(avatarp, false); + if (client.empty()) + { + color = unselected_color; + client = "?"; + } + else SHClientTagMgr::instance().getClientColor(avatarp, false, color); + viewer.value = client.c_str(); } - viewer.value = client.c_str(); - } - else - { - viewer.value = getString("Out Of Range"); + else + { + viewer.value = getString("Out Of Range"); + } + //Blend to make the color show up better + viewer.color = color *.5f + unselected_color * .5f; + element.columns.add(viewer); } - //Blend to make the color show up better - client_color = client_color *.5f + unselected_color * .5f; - - viewer.color = client_color; - - // Add individual column cell params to the item param - element.columns.add(mark); - element.columns.add(name); - element.columns.add(dist); - element.columns.add(pos); - element.columns.add(alt); - element.columns.add(act); - element.columns.add(agep); - element.columns.add(time); - element.columns.add(viewer); // Add to list mAvatarList->addRow(element); } + for (auto& dead : dead_entries) + mAvatars.erase(std::remove(mAvatars.begin(), mAvatars.end(), dead), mAvatars.end()); + + if (mAvatars.empty()) + setTitle(getString("Title")); + else if (mAvatars.size() == 1) + setTitle(getString("TitleOneAvatar")); + else + { + LLStringUtil::format_map_t args; + args["[COUNT]"] = fmt::to_string(mAvatars.size()); + setTitle(getString("TitleWithCount", args)); + } + // finish mAvatarList->updateSort(); mAvatarList->selectMultiple(selected); @@ -1080,13 +1079,25 @@ void LLFloaterAvatarList::refreshAvatarList() mDirtyAvatarSorting = true; -// llinfos << "radar refresh: done" << llendl; +// LL_INFOS() << "radar refresh: done" << LL_ENDL; +} +void LLFloaterAvatarList::resetAvatarNames() +{ + bool hide_tags(gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS)); + bool anon_names(gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)); + const std::string& hidden(RlvStrings::getString(RLV_STRING_HIDDEN)); + for (auto& entry : mAvatars) + { + entry->resetName(hide_tags, anon_names, hidden); + } + getChildView("profile_btn")->setEnabled(!hide_tags && !anon_names); + getChildView("im_btn")->setEnabled(!hide_tags && !anon_names); } void LLFloaterAvatarList::onClickIM() { - //llinfos << "LLFloaterFriends::onClickIM()" << llendl; + //LL_INFOS() << "LLFloaterFriends::onClickIM()" << LL_ENDL; const uuid_vec_t ids = mAvatarList->getSelectedIDs(); if (!ids.empty()) { @@ -1117,19 +1128,22 @@ void LLFloaterAvatarList::onClickTrack() LLScrollListItem* item = mAvatarList->getFirstSelected(); if (!item) return; - LLUUID agent_id = item->getUUID(); + trackAvatar(item->getUUID()); +} +void LLFloaterAvatarList::trackAvatar(const LLUUID& agent_id) +{ if (mTracking && mTrackedAvatar == agent_id) { LLTracker::stopTracking(false); - mTracking = FALSE; + mTracking = false; } else { - mTracking = TRUE; + mTracking = true; mTrackedAvatar = agent_id; // trackAvatar only works for friends allowing you to see them on map... -// LLTracker::trackAvatar(agent_id, self->mAvatars[agent_id].getName()); +// LLTracker::trackAvatar(agent_id, mAvatars[agent_id].getName()); trackAvatar(getAvatarEntry(mTrackedAvatar)); } } @@ -1151,70 +1165,64 @@ void LLFloaterAvatarList::refreshTracker() else { // Tracker stopped. LLTracker::stopTracking(false); - mTracking = FALSE; -// llinfos << "Tracking stopped." << llendl; + mTracking = false; +// LL_INFOS() << "Tracking stopped." << LL_ENDL; } } -void LLFloaterAvatarList::trackAvatar(const LLAvatarListEntry* entry) +void LLFloaterAvatarList::trackAvatar(const LLAvatarListEntry* entry) const { - if(!entry) return; + if (!entry) return; std::string name = entry->getName(); - if (!mUpdate) - { - name += "\n(last known position)"; - } + if (!mUpdate) name += "\n(last known position)"; LLTracker::trackLocation(entry->getPosition(), name, name); } -LLAvatarListEntry * LLFloaterAvatarList::getAvatarEntry(LLUUID avatar) +LLAvatarListEntry* LLFloaterAvatarList::getAvatarEntry(const LLUUID& avatar) const { - if (avatar.isNull()) - { - return NULL; - } - - av_list_t::iterator iter = std::find_if(mAvatars.begin(),mAvatars.end(),LLAvatarListEntry::uuidMatch(avatar)); - if(iter != mAvatars.end()) - return iter->get(); - else - return NULL; + av_list_t::const_iterator iter = std::find_if(mAvatars.begin(),mAvatars.end(),LLAvatarListEntry::uuidMatch(avatar)); + return (iter != mAvatars.end()) ? iter->get() : NULL; } BOOL LLFloaterAvatarList::handleKeyHere(KEY key, MASK mask) { - LLScrollListItem* item = mAvatarList->getFirstSelected(); - if(item) + if (const LLScrollListItem* item = mAvatarList->getFirstSelected()) { LLUUID agent_id = item->getUUID(); - if (( KEY_RETURN == key ) && (MASK_NONE == mask)) - { - setFocusAvatar(agent_id); - return TRUE; - } - else if (( KEY_RETURN == key ) && (MASK_CONTROL == mask)) + if (KEY_RETURN == key) { - const LLAvatarListEntry* entry = getAvatarEntry(agent_id); - if (entry) + if (MASK_NONE == mask) { -// llinfos << "Trying to teleport to " << entry->getName() << " at " << entry->getPosition() << llendl; - gAgent.teleportViaLocation(entry->getPosition()); + setFocusAvatar(agent_id); + return true; + } + if (MASK_CONTROL == mask) + { + if (const LLAvatarListEntry* entry = getAvatarEntry(agent_id)) + { +// LL_INFOS() << "Trying to teleport to " << entry->getName() << " at " << entry->getPosition() << LL_ENDL; + gAgent.teleportViaLocation(entry->getPosition()); + } + return true; + } + if (MASK_SHIFT == mask) + { + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS) || gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) // RLVa:LF - Don't you dare! + { + make_ui_sound("UISndInvalidOp"); + return true; + } + onClickIM(); + return true; } - return TRUE; } } - - if (( KEY_RETURN == key ) && (MASK_SHIFT == mask)) - { - onClickIM(); - } return LLPanel::handleKeyHere(key, mask); } void LLFloaterAvatarList::onClickFocus() { - LLScrollListItem* item = mAvatarList->getFirstSelected(); - if (item) + if (LLScrollListItem* item = mAvatarList->getFirstSelected()) { setFocusAvatar(item->getUUID()); } @@ -1222,94 +1230,108 @@ void LLFloaterAvatarList::onClickFocus() void LLFloaterAvatarList::removeFocusFromAll() { - BOOST_FOREACH(av_list_t::value_type& entry, mAvatars) + for (auto& entry : mAvatars) { - entry->setFocus(FALSE); + entry->setFocus(false); } } +// static void LLFloaterAvatarList::setFocusAvatar(const LLUUID& id) +{ + if (/*!gAgentCamera.lookAtObject(id, false) &&*/ !lookAtAvatar(id)) return; + if (auto inst = getIfExists()) + inst->setFocusAvatarInternal(id); +} + +void LLFloaterAvatarList::setFocusAvatarInternal(const LLUUID& id) { av_list_t::iterator iter = std::find_if(mAvatars.begin(),mAvatars.end(),LLAvatarListEntry::uuidMatch(id)); - if(iter != mAvatars.end()) - { - if(!gAgentCamera.lookAtObject(id, false)) - return; - removeFocusFromAll(); - (*iter)->setFocus(TRUE); - } + if (iter == mAvatars.end()) return; + removeFocusFromAll(); + (*iter)->setFocus(true); } +// Simple function to decrement iterators, wrapping back if needed template -void decrement_focus_target(T begin, T end, BOOL marked_only) +T prev_iter(const T& cur, const T& begin, const T& end) { - T iter = begin; - while(iter != end && !(*iter)->isFocused()) ++iter; - if(iter == end) - return; - T prev_iter = iter; - while(prev_iter != begin) + return ((cur == begin) ? end : cur) - 1; +} + +template +void decrement_focus_target(T begin, const T& end, bool marked_only) +{ + for (T iter = begin; iter != end; ++iter) { - const LLAvatarListEntry& entry = *((--prev_iter)->get()); - if(entry.isInList() && (entry.isMarked() || !marked_only) && gAgentCamera.lookAtObject(entry.getID(), false)) + LLAvatarListEntry& old = *(iter->get()); + if (!old.isFocused()) continue; + for (T prev = prev_iter(iter, begin, end); prev != iter; prev = prev_iter(prev, begin, end)) { - (*iter)->setFocus(FALSE); - (*prev_iter)->setFocus(TRUE); - gAgentCamera.lookAtObject((*prev_iter)->getID(), false); - return; + LLAvatarListEntry& entry = *(prev->get()); + if (!entry.isInList()) continue; + if (marked_only && !entry.isMarked()) continue; + if (gAgentCamera.lookAtObject(entry.getID(), false)) + { + old.setFocus(false); + entry.setFocus(true); + return; + } } + // Nothing else to focus + break; } - gAgentCamera.lookAtObject((*iter)->getID(), false); } -void LLFloaterAvatarList::focusOnPrev(BOOL marked_only) +void LLFloaterAvatarList::focusOnPrev(bool marked_only) { updateAvatarSorting(); decrement_focus_target(mAvatars.begin(), mAvatars.end(), marked_only); } -void LLFloaterAvatarList::focusOnNext(BOOL marked_only) +void LLFloaterAvatarList::focusOnNext(bool marked_only) { updateAvatarSorting(); decrement_focus_target(mAvatars.rbegin(), mAvatars.rend(), marked_only); } /*static*/ -void LLFloaterAvatarList::lookAtAvatar(LLUUID &uuid) +bool LLFloaterAvatarList::lookAtAvatar(const LLUUID& uuid) { // twisted laws LLVOAvatar* voavatar = gObjectList.findAvatar(uuid); - if(voavatar && voavatar->isAvatar()) + if (voavatar && voavatar->isAvatar()) { - gAgentCamera.setFocusOnAvatar(FALSE, FALSE); + gAgentCamera.setFocusOnAvatar(false, false); gAgentCamera.changeCameraToThirdPerson(); gAgentCamera.setFocusGlobal(voavatar->getPositionGlobal(),uuid); gAgentCamera.setCameraPosAndFocusGlobal(voavatar->getPositionGlobal() - + LLVector3d(3.5,1.35,0.75) * voavatar->getRotation(), + + LLVector3d(3.5, 1.35, 0.75) * voavatar->getRotation(), voavatar->getPositionGlobal(), - uuid ); + uuid); + return true; } + return false; } void LLFloaterAvatarList::onClickGetKey() { - LLScrollListItem* item = mAvatarList->getFirstSelected(); - - if (NULL == item) return; - - gViewerWindow->getWindow()->copyTextToClipboard(utf8str_to_wstring(item->getUUID().asString())); + if (LLScrollListItem* item = mAvatarList->getFirstSelected()) + { + gViewerWindow->getWindow()->copyTextToClipboard(utf8str_to_wstring(item->getUUID().asString())); + } } -void LLFloaterAvatarList::sendKeys() +void LLFloaterAvatarList::sendKeys() const { // This would break for send_keys_btn callback, check this beforehand, if it matters. //static LLCachedControl radar_chat_keys(gSavedSettings, "RadarChatKeys"); //if (radar_chat_keys) return; LLViewerRegion* regionp = gAgent.getRegion(); - if (!regionp) return;//ALWAYS VALIDATE DATA + if (!regionp) return; - static int last_transact_num = 0; - int transact_num = (int)gFrameCount; + static U32 last_transact_num = 0; + U32 transact_num(gFrameCount); if (transact_num > last_transact_num) { @@ -1323,37 +1345,32 @@ void LLFloaterAvatarList::sendKeys() } std::ostringstream ids; - int num_ids = 0; + U32 num_ids = 0; - for (int i = 0; i < regionp->mMapAvatarIDs.count(); ++i) + for (U32 i = 0; i < regionp->mMapAvatarIDs.size(); ++i) { - const LLUUID &id = regionp->mMapAvatarIDs.get(i); - - ids << "," << id; + ids << ',' << regionp->mMapAvatarIDs.at(i); ++num_ids; - - if (ids.tellp() > 200) { send_keys_message(transact_num, num_ids, ids.str()); - - num_ids = 0; - ids.seekp(0); - ids.str(""); + ids.seekp(num_ids = 0); + ids.str(LLStringUtil::null); } } - if (num_ids > 0) - send_keys_message(transact_num, num_ids, ids.str()); + if (num_ids > 0) send_keys_message(transact_num, num_ids, ids.str()); } //static void LLFloaterAvatarList::sound_trigger_hook(LLMessageSystem* msg,void **) { if (!LLFloaterAvatarList::instanceExists()) return; // Don't bother if we're closed. - LLUUID sound_id,owner_id; - msg->getUUIDFast(_PREHASH_SoundData, _PREHASH_SoundID, sound_id); + LLUUID owner_id; msg->getUUIDFast(_PREHASH_SoundData, _PREHASH_OwnerID, owner_id); - if (owner_id == gAgent.getID() && sound_id == LLUUID("76c78607-93f9-f55a-5238-e19b1a181389")) + if (owner_id != gAgentID) return; + LLUUID sound_id; + msg->getUUIDFast(_PREHASH_SoundData, _PREHASH_SoundID, sound_id); + if (sound_id == LLUUID("76c78607-93f9-f55a-5238-e19b1a181389")) { static LLCachedControl on("RadarChatKeys"); static LLCachedControl do_not_ask("RadarChatKeysStopAsking"); @@ -1364,7 +1381,7 @@ void LLFloaterAvatarList::sound_trigger_hook(LLMessageSystem* msg,void **) } } // static -bool LLFloaterAvatarList::onConfirmRadarChatKeys(const LLSD& notification, const LLSD& response ) +bool LLFloaterAvatarList::onConfirmRadarChatKeys(const LLSD& notification, const LLSD& response) { S32 option = LLNotification::getSelectedOption(notification, response); if (option == 1) // no @@ -1386,90 +1403,56 @@ bool LLFloaterAvatarList::onConfirmRadarChatKeys(const LLSD& notification, const void send_freeze(const LLUUID& avatar_id, bool freeze) { - U32 flags = 0x0; - if (!freeze) - { - // unfreeze - flags |= 0x1; - } - - LLMessageSystem* msg = gMessageSystem; LLVOAvatar* avatarp = gObjectList.findAvatar(avatar_id); - - if (avatarp && avatarp->getRegion()) + if (!avatarp) return; + if (LLViewerRegion* region = avatarp->getRegion()) { + LLMessageSystem* msg = gMessageSystem; msg->newMessage("FreezeUser"); msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID()); - msg->addUUID("SessionID", gAgent.getSessionID()); + msg->addUUID("AgentID", gAgentID); + msg->addUUID("SessionID", gAgentSessionID); msg->nextBlock("Data"); msg->addUUID("TargetID", avatar_id); + U32 flags = 0x0; + if (!freeze) + { + // unfreeze + flags |= 0x1; + } msg->addU32("Flags", flags); - msg->sendReliable( avatarp->getRegion()->getHost()); + msg->sendReliable(region->getHost()); } } void send_eject(const LLUUID& avatar_id, bool ban) -{ - LLMessageSystem* msg = gMessageSystem; +{ LLVOAvatar* avatarp = gObjectList.findAvatar(avatar_id); - - if (avatarp && avatarp->getRegion()) + if (!avatarp) return; + if (LLViewerRegion* region = avatarp->getRegion()) { + LLMessageSystem* msg = gMessageSystem; + msg->newMessage("EjectUser"); + msg->nextBlock("AgentData"); + msg->addUUID("AgentID", gAgentID); + msg->addUUID("SessionID", gAgentSessionID); + msg->nextBlock("Data"); + msg->addUUID("TargetID", avatar_id); U32 flags = 0x0; if (ban) { // eject and add to ban list flags |= 0x1; } - - msg->newMessage("EjectUser"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID()); - msg->addUUID("SessionID", gAgent.getSessionID()); - msg->nextBlock("Data"); - msg->addUUID("TargetID", avatar_id); msg->addU32("Flags", flags); - msg->sendReliable(avatarp->getRegion()->getHost()); + msg->sendReliable(region->getHost()); } } -static void send_estate_message( - const char* request, - const LLUUID& target) -{ - - LLMessageSystem* msg = gMessageSystem; - LLUUID invoice; - - // This seems to provide an ID so that the sim can say which request it's - // replying to. I think this can be ignored for now. - invoice.generate(); - - llinfos << "Sending estate request '" << request << "'" << llendl; - msg->newMessage("EstateOwnerMessage"); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->addUUIDFast(_PREHASH_TransactionID, LLUUID::null); //not used - msg->nextBlock("MethodData"); - msg->addString("Method", request); - msg->addUUID("Invoice", invoice); - - // Agent id - msg->nextBlock("ParamList"); - msg->addString("Parameter", gAgent.getID().asString().c_str()); - - // Target - msg->nextBlock("ParamList"); - msg->addString("Parameter", target.asString().c_str()); - - msg->sendReliable(gAgent.getRegion()->getHost()); -} +void send_estate_message(const std::string request, const std::vector& strings); static void cmd_append_names(const LLAvatarListEntry* entry, std::string &str, std::string &sep) { if(!str.empty())str.append(sep);str.append(entry->getName()); } -static void cmd_toggle_mark(LLAvatarListEntry* entry) { entry->toggleMark(); } static void cmd_ar(const LLAvatarListEntry* entry) { LLFloaterReporter::showFromObject(entry->getID()); } static void cmd_profile(const LLAvatarListEntry* entry) { LLAvatarActions::showProfile(entry->getID()); } static void cmd_teleport(const LLAvatarListEntry* entry) { gAgent.teleportViaLocation(entry->getPosition()); } @@ -1477,172 +1460,120 @@ static void cmd_freeze(const LLAvatarListEntry* entry) { send_freeze(entry->get static void cmd_unfreeze(const LLAvatarListEntry* entry) { send_freeze(entry->getID(), false); } static void cmd_eject(const LLAvatarListEntry* entry) { send_eject(entry->getID(), false); } static void cmd_ban(const LLAvatarListEntry* entry) { send_eject(entry->getID(), true); } -static void cmd_estate_eject(const LLAvatarListEntry* entry){ send_estate_message("teleporthomeuser", entry->getID()); } -static void cmd_estate_ban(const LLAvatarListEntry* entry) { LLPanelEstateInfo::sendEstateAccessDelta(ESTATE_ACCESS_BANNED_AGENT_ADD | ESTATE_ACCESS_ALLOWED_AGENT_REMOVE | ESTATE_ACCESS_NO_REPLY, entry->getID()); } +static void cmd_estate_eject(const LLAvatarListEntry* entry){ send_estate_message("kickestate", {entry->getID().asString()}); } +static void cmd_estate_tp_home(const LLAvatarListEntry* entry){ send_estate_message("teleporthomeuser", {gAgentID.asString(), entry->getID().asString()}); } +static void cmd_estate_ban(const LLAvatarListEntry* entry) { LLPanelEstateAccess::sendEstateAccessDelta(ESTATE_ACCESS_BANNED_AGENT_ADD | ESTATE_ACCESS_ALLOWED_AGENT_REMOVE | ESTATE_ACCESS_NO_REPLY, entry->getID()); } -void LLFloaterAvatarList::doCommand(avlist_command_t func, bool single/*=false*/) +void LLFloaterAvatarList::doCommand(avlist_command_t func, bool single/*=false*/) const { uuid_vec_t ids; - if(!single) + if (!single) ids = mAvatarList->getSelectedIDs(); else ids.push_back(getSelectedID()); - for (uuid_vec_t::iterator itr = ids.begin(); itr != ids.end(); ++itr) + for (uuid_vec_t::const_iterator itr = ids.begin(); itr != ids.end(); ++itr) { - LLUUID& avid = *itr; - if(avid.isNull()) - continue; - LLAvatarListEntry* entry = getAvatarEntry(avid); - if (entry != NULL) + const LLUUID& avid = *itr; + if (avid.isNull()) continue; + if (LLAvatarListEntry* entry = getAvatarEntry(avid)) { - llinfos << "Executing command on " << entry->getName() << llendl; + LL_INFOS() << "Executing command on " << entry->getName() << LL_ENDL; func(entry); } } } -std::string LLFloaterAvatarList::getSelectedNames(const std::string& separator) +std::string LLFloaterAvatarList::getSelectedNames(const std::string& separator) const { std::string ret; doCommand(boost::bind(&cmd_append_names,_1,boost::ref(ret),separator)); return ret; } -std::string LLFloaterAvatarList::getSelectedName() +std::string LLFloaterAvatarList::getSelectedName() const { - LLUUID id = getSelectedID(); - LLAvatarListEntry* entry = getAvatarEntry(id); - if (entry) - { - return entry->getName(); - } - return ""; + LLAvatarListEntry* entry = getAvatarEntry(getSelectedID()); + return entry ? entry->getName() : LLStringUtil::null; } -LLUUID LLFloaterAvatarList::getSelectedID() +LLUUID LLFloaterAvatarList::getSelectedID() const { LLScrollListItem* item = mAvatarList->getFirstSelected(); - if (item) return item->getUUID(); - return LLUUID::null; + return item ? item->getUUID() : LLUUID::null; +} + +uuid_vec_t LLFloaterAvatarList::getSelectedIDs() const +{ + return mAvatarList->getSelectedIDs(); } //static void LLFloaterAvatarList::callbackFreeze(const LLSD& notification, const LLSD& response) { - if(!instanceExists()) - return; - + if (!instanceExists()) return; + LLFloaterAvatarList& inst(instance()); S32 option = LLNotification::getSelectedOption(notification, response); - - if (option == 0) - { - getInstance()->doCommand(cmd_freeze); - } - else if (option == 1) - { - getInstance()->doCommand(cmd_unfreeze); - } + if (option == 0) inst.doCommand(cmd_freeze); + else if (option == 1) inst.doCommand(cmd_unfreeze); } //static void LLFloaterAvatarList::callbackEject(const LLSD& notification, const LLSD& response) { - if(!instanceExists()) - return; - + if (!instanceExists()) return; + LLFloaterAvatarList& inst(instance()); S32 option = LLNotification::getSelectedOption(notification, response); - - if (option == 0) - { - getInstance()->doCommand(cmd_eject); - } - else if (option == 1) - { - getInstance()->doCommand(cmd_ban); - } + if (option == 0) inst.doCommand(cmd_eject); + else if (option == 1) inst.doCommand(cmd_ban); } //static void LLFloaterAvatarList::callbackEjectFromEstate(const LLSD& notification, const LLSD& response) { - if(!instanceExists()) - return; - + if (!instanceExists()) return; + LLFloaterAvatarList& inst(instance()); S32 option = LLNotification::getSelectedOption(notification, response); - - if (option == 0) - { - getInstance()->doCommand(cmd_estate_eject); - } + if (option != 2) + inst.doCommand(option ? cmd_estate_tp_home : cmd_estate_eject); } //static void LLFloaterAvatarList::callbackBanFromEstate(const LLSD& notification, const LLSD& response) { - if(!instanceExists()) - return; - - S32 option = LLNotification::getSelectedOption(notification, response); - - if (option == 0) - { - getInstance()->doCommand(cmd_estate_eject); //Eject first, just in case. - getInstance()->doCommand(cmd_estate_ban); - } -} - -//static -void LLFloaterAvatarList::callbackIdle(void* userdata) -{ - if (instanceExists()) + if (!instanceExists()) return; + LLFloaterAvatarList& inst(instance()); + if (!LLNotification::getSelectedOption(notification, response)) // if == 0 { - // Do not update at every frame: this would be insane! - if (gFrameCount % getInstance()->mUpdateRate == 0) - { - getInstance()->updateAvatarList(); - } + inst.doCommand(cmd_estate_eject); //Eject first, just in case. + inst.doCommand(cmd_estate_ban); } } void LLFloaterAvatarList::onClickFreeze() { LLSD args; - LLSD payload; args["AVATAR_NAME"] = getSelectedNames(); - LLNotificationsUtil::add("FreezeAvatarFullname", args, payload, callbackFreeze); + LLNotificationsUtil::add("FreezeAvatarFullname", args, LLSD(), callbackFreeze); } void LLFloaterAvatarList::onClickEject() { LLSD args; - LLSD payload; args["AVATAR_NAME"] = getSelectedNames(); - LLNotificationsUtil::add("EjectAvatarFullname", args, payload, callbackEject); + LLNotificationsUtil::add("EjectAvatarFullname", args, LLSD(), callbackEject); } void LLFloaterAvatarList::onClickMute() { uuid_vec_t ids = mAvatarList->getSelectedIDs(); - if (ids.size() > 0) + for (uuid_vec_t::const_iterator itr = ids.begin(); itr != ids.end(); ++itr) { - for (uuid_vec_t::iterator itr = ids.begin(); itr != ids.end(); ++itr) + const LLUUID& agent_id = *itr; + std::string agent_name; + if (gCacheName->getFullName(agent_id, agent_name)) { - LLUUID agent_id = *itr; - - std::string agent_name; - if (gCacheName->getFullName(agent_id, agent_name)) - { - if (LLMuteList::getInstance()->isMuted(agent_id)) - { - LLMute mute(agent_id, agent_name, LLMute::AGENT); - LLMuteList::getInstance()->remove(mute); - } - else - { - LLMute mute(agent_id, agent_name, LLMute::AGENT); - LLMuteList::getInstance()->add(mute); - } - } + LLMute mute(agent_id, agent_name, LLMute::AGENT); + LLMuteList::getInstance()->isMuted(agent_id) ? LLMuteList::getInstance()->remove(mute) : LLMuteList::getInstance()->add(mute); } } } @@ -1650,9 +1581,8 @@ void LLFloaterAvatarList::onClickMute() void LLFloaterAvatarList::onClickEjectFromEstate() { LLSD args; - LLSD payload; args["EVIL_USER"] = getSelectedNames(); - LLNotificationsUtil::add("EstateKickUser", args, payload, callbackEjectFromEstate); + LLNotificationsUtil::add("EstateKickUser", args, LLSD(), callbackEjectFromEstate); } void LLFloaterAvatarList::onClickBanFromEstate() @@ -1660,32 +1590,19 @@ void LLFloaterAvatarList::onClickBanFromEstate() LLSD args; LLSD payload; args["EVIL_USER"] = getSelectedNames(); - LLNotificationsUtil::add("EstateBanUser", args, payload, callbackBanFromEstate); -} - -void LLFloaterAvatarList::onAvatarSortingChanged() -{ - mDirtyAvatarSorting = true; + LLNotificationsUtil::add("EstateBanUser", args, LLSD(), callbackBanFromEstate); } void LLFloaterAvatarList::onSelectName() { - LLScrollListItem* item = mAvatarList->getFirstSelected(); - if (item) + if (LLScrollListItem* item = mAvatarList->getFirstSelected()) { - LLUUID agent_id = item->getUUID(); - LLAvatarListEntry* entry = getAvatarEntry(agent_id); - if (entry) + if (LLAvatarListEntry* entry = getAvatarEntry(item->getUUID())) { - BOOL enabled = entry->mStats[STAT_TYPE_DRAW]; + bool enabled = entry->mStats[STAT_TYPE_DRAW]; childSetEnabled("focus_btn", enabled); childSetEnabled("prev_in_list_btn", enabled); childSetEnabled("next_in_list_btn", enabled); } } } - -void LLFloaterAvatarList::onCommitUpdateRate() -{ - mUpdateRate = gSavedSettings.getU32("RadarUpdateRate") * 3 + 3; -} diff --git a/indra/newview/llfloateravatarlist.h b/indra/newview/llfloateravatarlist.h index 33f02ce9bf..5c83219878 100644 --- a/indra/newview/llfloateravatarlist.h +++ b/indra/newview/llfloateravatarlist.h @@ -10,6 +10,10 @@ // Copyright: See COPYING file that comes with this distribution // // + +#ifndef LL_LLFLOATERAVATARLIST_H +#define LL_LLFLOATERAVATARLIST_H + #include "llavatarname.h" #include "llavatarpropertiesprocessor.h" #include "llfloater.h" @@ -58,7 +62,6 @@ enum ACTIVITY_TYPE ACTIVITY_TYPING, /** Typing */ ACTIVITY_NEW, /** Avatar just appeared */ ACTIVITY_SOUND, /** Playing a sound */ - ACTIVITY_DEAD /** Avatar isn't around anymore, and will be removed soon from the list */ }; /** * @brief Initializes a list entry @@ -76,22 +79,14 @@ enum ACTIVITY_TYPE * Update world position. * Affects age. */ - void setPosition(LLVector3d position, bool this_sim, bool drawn, bool chatrange, bool shoutrange); + void setPosition(const LLVector3d& position, const F32& dist, bool drawn, bool flood = false); const LLVector3d& getPosition() const { return mPosition; } - /** - * @brief Returns the age of this entry in frames - * - * This is only used for determining whether the avatar is still around. - * @see getEntryAgeSeconds - */ - bool getAlive(); - - /** - * @brief Returns the age of this entry in seconds + /* + * @brief resets the name accordance with RLVa */ - F32 getEntryAgeSeconds() const; + void resetName(const bool& hide_tags, const bool& anon_names, const std::string& hidden); /** * @brief Returns the name of the avatar @@ -107,14 +102,14 @@ enum ACTIVITY_TYPE void setActivity(ACTIVITY_TYPE activity); /** - * @brief Returns the activity type + * @brief Returns the activity type, updates mActivityType if necessary */ const ACTIVITY_TYPE getActivity(); /** * @brief Sets the 'focus' status on this entry (camera focused on this avatar) */ - void setFocus(BOOL value) { mFocused = value; } + void setFocus(bool value) { mFocused = value; } bool isFocused() const { return mFocused; } @@ -128,13 +123,8 @@ enum ACTIVITY_TYPE void setInList() { mIsInList = true; } bool isInList() const { return mIsInList; } - /** - * @brief Returns whether the item is dead and shouldn't appear in the list - * @returns TRUE if dead - */ - bool isDead() const; - void toggleMark() { mMarked = !mMarked; } + void setMarked(bool marked) { mMarked = marked; } struct uuidMatch { @@ -153,6 +143,7 @@ enum ACTIVITY_TYPE bool mMarked; bool mFocused; bool mIsInList; + bool mNotes = false; int mAge; /** @@ -160,20 +151,9 @@ enum ACTIVITY_TYPE */ std::bitset mStats; - /** - * @brief Timer to keep track of whether avatars are still there - */ - - LLTimer mUpdateTimer; - ACTIVITY_TYPE mActivityType; LLTimer mActivityTimer; - - /** - * @brief Last frame when this avatar was updated - */ - U32 mFrame; }; @@ -207,14 +187,15 @@ class LLFloaterAvatarList : public LLFloater, public LLSingleton LLAvatarListEntryPtr; typedef std::vector< LLAvatarListEntryPtr > av_list_t; @@ -253,19 +240,6 @@ class LLFloaterAvatarList : public LLFloater, public LLSingleton avlist_command_t; @@ -277,22 +251,23 @@ class LLFloaterAvatarList : public LLFloater, public LLSingleton& ids); void updateAvatarSorting(); + static bool isCleanup() + { + const auto& inst = getIfExists(); + return inst && inst->mCleanup; + } private: + void setFocusAvatarInternal(const LLUUID& id); + /** * @brief Pointer to the avatar scroll list */ LLScrollListCtrl* mAvatarList; av_list_t mAvatars; bool mDirtyAvatarSorting; + bool mCleanup = false; /** - * @brief TRUE when Updating + * @brief true when Updating */ const LLCachedControl mUpdate; - /** - * @brief Update rate (if min frames per update) - */ - U32 mUpdateRate; - // tracking data bool mTracking; // Tracking ? LLUUID mTrackedAvatar; // Who we are tracking @@ -371,3 +347,5 @@ class LLFloaterAvatarList : public LLFloater, public LLSingleton sAvatarNameMap; LLFloaterAvatarPicker* LLFloaterAvatarPicker::show(select_callback_t callback, BOOL allow_multiple, - BOOL closeOnSelect) + BOOL closeOnSelect, + BOOL skip_agent, + const std::string& name, + LLView * frustumOrigin) { // *TODO: Use a key to allow this not to be an effective singleton - - LLFloaterAvatarPicker* floater = getInstance(); + LLFloaterAvatarPicker* floater = + getInstance(); floater->open(); floater->mSelectionCallback = callback; floater->setAllowMultiple(allow_multiple); floater->mNearMeListComplete = FALSE; floater->mCloseOnSelect = closeOnSelect; + floater->mExcludeAgentFromSearchResults = skip_agent; if (!closeOnSelect) { @@ -78,6 +85,11 @@ LLFloaterAvatarPicker* LLFloaterAvatarPicker::show(select_callback_t callback, floater->getChild("cancel_btn")->setLabel(close_string); } + if(frustumOrigin) + { + floater->mFrustumOrigin = frustumOrigin->getHandle(); + } + return floater; } @@ -86,10 +98,18 @@ LLFloaterAvatarPicker::LLFloaterAvatarPicker() : LLFloater(), mNumResultsReturned(0), mNearMeListComplete(FALSE), - mCloseOnSelect(FALSE) + mCloseOnSelect(FALSE), + mContextConeOpacity (0.f), + mContextConeInAlpha(0.f), + mContextConeOutAlpha(0.f), + mContextConeFadeTime(0.f) { mCommitCallbackRegistrar.add("Refresh.FriendList", boost::bind(&LLFloaterAvatarPicker::populateFriend, this)); LLUICtrlFactory::getInstance()->buildFloater(this, "floater_avatar_picker.xml", NULL); + + mContextConeInAlpha = gSavedSettings.getF32("ContextConeInAlpha"); + mContextConeOutAlpha = gSavedSettings.getF32("ContextConeOutAlpha"); + mContextConeFadeTime = gSavedSettings.getF32("ContextConeFadeTime"); } BOOL LLFloaterAvatarPicker::postBuild() @@ -187,11 +207,10 @@ static void addAvatarUUID(const LLUUID av_id, uuid_vec_t& avatar_ids, std::vecto static void getSelectedAvatarData(const LLUICtrl* from, uuid_vec_t& avatar_ids, std::vector& avatar_names) { - const LLScrollListCtrl* list = dynamic_cast(from); - if(list) + if(const LLScrollListCtrl* list = dynamic_cast(from)) { - std::vector items = list->getAllSelected(); - for (std::vector::iterator iter = items.begin(); iter != items.end(); ++iter) + const std::vector items = list->getAllSelected(); + for (std::vector::const_iterator iter = items.begin(); iter != items.end(); ++iter) { addAvatarUUID((*iter)->getUUID(), avatar_ids, avatar_names); } @@ -238,16 +257,21 @@ void LLFloaterAvatarPicker::onBtnSelect() uuid_vec_t avatar_ids; std::vector avatar_names; getSelectedAvatarData(list, avatar_ids, avatar_names); + if (mCloseOnSelect) // Singu Note: Close before callback if we get here first, makes potential next dialog floater position correctly + { + mCloseOnSelect = FALSE; + close(); + } mSelectionCallback(avatar_ids, avatar_names); } } getChild("SearchResults")->deselectAllItems(TRUE); getChild("NearMe")->deselectAllItems(TRUE); getChild("Friends")->deselectAllItems(TRUE); - if(mCloseOnSelect) + if (mCloseOnSelect) { mCloseOnSelect = FALSE; - close(); + close(); } } @@ -280,7 +304,7 @@ void LLFloaterAvatarPicker::onList() RLV_ASSERT( (pTabs) && (pNearMePanel) ); if ( (pTabs) && (pNearMePanel) ) { - bool fRlvEnable = !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES); + bool fRlvEnable = !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES) && !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS); pTabs->enableTabButton(pTabs->getIndexForPanel(pNearMePanel), fRlvEnable); if ( (!fRlvEnable) && (pTabs->getCurrentPanel() == pNearMePanel) ) pTabs->selectTabByName("SearchPanel"); @@ -315,9 +339,9 @@ void LLFloaterAvatarPicker::populateNearMe() else { element["columns"][0]["column"] = "name"; - element["columns"][0]["value"] = av_name.mDisplayName; + element["columns"][0]["value"] = av_name.getDisplayName(); element["columns"][1]["column"] = "username"; - element["columns"][1]["value"] = av_name.mUsername; + element["columns"][1]["value"] = av_name.getUserName(); sAvatarNameMap[av] = av_name; } @@ -360,13 +384,65 @@ void LLFloaterAvatarPicker::populateFriend() } for(it = collector.mOffline.begin(); it!=collector.mOffline.end(); it++) { - friends_scroller->addStringUUIDItem(it->first, it->second); + friends_scroller->addStringUUIDItem(it->first, it->second); } friends_scroller->sortByColumnIndex(0, TRUE); } +void LLFloaterAvatarPicker::drawFrustum() +{ + if (mFrustumOrigin.get()) + { + LLView * frustumOrigin = mFrustumOrigin.get(); + LLRect origin_rect; + frustumOrigin->localRectToOtherView(frustumOrigin->getLocalRect(), &origin_rect, this); + // draw context cone connecting color picker with color swatch in parent floater + LLRect local_rect = getLocalRect(); + if (hasFocus() && frustumOrigin->isInVisibleChain() && mContextConeOpacity > 0.001f) + { + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + LLGLEnable clip; + gGL.begin(LLRender::TRIANGLE_STRIP); + { + gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity); + gGL.vertex2i(local_rect.mLeft, local_rect.mTop); + gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity); + gGL.vertex2i(origin_rect.mLeft, origin_rect.mTop); + gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity); + gGL.vertex2i(local_rect.mRight, local_rect.mTop); + gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity); + gGL.vertex2i(origin_rect.mRight, origin_rect.mTop); + gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity); + gGL.vertex2i(local_rect.mRight, local_rect.mBottom); + gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity); + gGL.vertex2i(origin_rect.mRight, origin_rect.mBottom); + gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity); + gGL.vertex2i(local_rect.mLeft, local_rect.mBottom); + gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity); + gGL.vertex2i(origin_rect.mLeft, origin_rect.mBottom); + gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity); + gGL.vertex2i(local_rect.mLeft, local_rect.mTop); + gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity); + gGL.vertex2i(origin_rect.mLeft, origin_rect.mTop); + } + gGL.end(); + } + + if (gFocusMgr.childHasMouseCapture(getDragHandle())) + { + mContextConeOpacity = lerp(mContextConeOpacity, gSavedSettings.getF32("PickerContextOpacity"), LLSmoothInterpolation::getInterpolant(mContextConeFadeTime)); + } + else + { + mContextConeOpacity = lerp(mContextConeOpacity, 0.f, LLSmoothInterpolation::getInterpolant(mContextConeFadeTime)); + } + } +} + void LLFloaterAvatarPicker::draw() { + drawFrustum(); + // sometimes it is hard to determine when Select/Ok button should be disabled (see LLAvatarActions::shareWithAvatars). // lets check this via mOkButtonValidateSignal callback periodically. static LLFrameTimer timer; @@ -410,37 +486,36 @@ BOOL LLFloaterAvatarPicker::visibleItemsSelected() const return FALSE; } -extern AIHTTPTimeoutPolicy avatarPickerResponder_timeout; class LLAvatarPickerResponder : public LLHTTPClient::ResponderWithCompleted { + LOG_CLASS(LLAvatarPickerResponder); public: LLUUID mQueryID; LLAvatarPickerResponder(const LLUUID& id) : mQueryID(id) { } - /*virtual*/ void completed(U32 status, const std::string& reason, const LLSD& content) +protected: + /*virtual*/ void httpCompleted() { //std::ostringstream ss; //LLSDSerialize::toPrettyXML(content, ss); - //llinfos << ss.str() << llendl; + //LL_INFOS() << ss.str() << LL_ENDL; // in case of invalid characters, the avatar picker returns a 400 // just set it to process so it displays 'not found' - if ((200 <= status && status < 300) || status == 400) + if (isGoodStatus(mStatus) || mStatus == 400) { if (LLFloaterAvatarPicker::instanceExists()) { - LLFloaterAvatarPicker::getInstance()->processResponse(mQueryID, content); + LLFloaterAvatarPicker::getInstance()->processResponse(mQueryID, mContent); } } else { - llwarns << "avatar picker failed " << status << " reason " << reason << llendl; - + LL_WARNS() << "avatar picker failed " << dumpResponse() << LL_ENDL; } } - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return avatarPickerResponder_timeout; } /*virtual*/ char const* getName(void) const { return "LLAvatarPickerResponder"; } }; @@ -459,9 +534,7 @@ void LLFloaterAvatarPicker::find() LLViewerRegion* region = gAgent.getRegion(); url = region->getCapability("AvatarPickerSearch"); // Prefer use of capabilities to search on both SLID and display name - // but allow display name search to be manually turned off for test - if (!url.empty() - && LLAvatarNameCache::useDisplayNames()) + if (!url.empty()) { // capability urls don't end in '/', but we need one to parse // query parameters correctly @@ -470,8 +543,9 @@ void LLFloaterAvatarPicker::find() url += "/"; } url += "?page_size=100&names="; + std::replace(text.begin(), text.end(), '.', ' '); url += LLURI::escape(text); - llinfos << "avatar picker " << url << llendl; + LL_INFOS() << "avatar picker " << url << LL_ENDL; LLHTTPClient::get(url, new LLAvatarPickerResponder(mQueryID)); } else @@ -549,8 +623,8 @@ BOOL LLFloaterAvatarPicker::handleDragAndDrop(S32 x, S32 y, MASK mask, if (dest_agent_id.notNull() && dest_agent_id != gAgentID) { // if (drop) -// [RLVa:KB] - Checked: 2011-04-11 (RLVa-1.3.0h) | Added: RLVa-1.3.0h - if ( (drop) && ( (!rlv_handler_t::isEnabled()) || (gRlvHandler.canStartIM(dest_agent_id)) ) ) +// [RLVa:KB] - Checked: 2011-04-11 (RLVa-1.3.0) + if ( (drop) && (RlvActions::canStartIM(dest_agent_id)) ) // [/RLVa:KB] { // Start up IM before give the item @@ -594,9 +668,7 @@ void LLFloaterAvatarPicker::processAvatarPickerReply(LLMessageSystem* msg, void* // Not for us if (agent_id != gAgent.getID()) return; - if(!instanceExists()) - return; - LLFloaterAvatarPicker* floater = getInstance(); + LLFloaterAvatarPicker* floater = instanceExists() ? getInstance() : NULL; // floater is closed or these are not results from our last request if (NULL == floater || query_id != floater->mQueryID) @@ -619,35 +691,36 @@ void LLFloaterAvatarPicker::processAvatarPickerReply(LLMessageSystem* msg, void* msg->getUUIDFast( _PREHASH_Data,_PREHASH_AvatarID, avatar_id, i); msg->getStringFast(_PREHASH_Data,_PREHASH_FirstName, first_name, i); msg->getStringFast(_PREHASH_Data,_PREHASH_LastName, last_name, i); - - std::string avatar_name; - if (avatar_id.isNull()) - { - LLStringUtil::format_map_t map; - map["[TEXT]"] = floater->getChild("Edit")->getValue().asString(); - avatar_name = floater->getString("not_found", map); - search_results->setEnabled(FALSE); - floater->getChildView("ok_btn")->setEnabled(FALSE); - } - else + + if (avatar_id != agent_id || !floater->isExcludeAgentFromSearchResults()) // exclude agent from search results? { - avatar_name = LLCacheName::buildFullName(first_name, last_name); - search_results->setEnabled(TRUE); - found_one = TRUE; + std::string avatar_name; + if (avatar_id.isNull()) + { + LLStringUtil::format_map_t map; + map["[TEXT]"] = floater->getChild("Edit")->getValue().asString(); + avatar_name = floater->getString("not_found", map); + search_results->setEnabled(FALSE); + floater->getChildView("ok_btn")->setEnabled(FALSE); + } + else + { + avatar_name = LLCacheName::buildFullName(first_name, last_name); + search_results->setEnabled(TRUE); + found_one = TRUE; - LLAvatarName av_name; - av_name.mLegacyFirstName = first_name; - av_name.mLegacyLastName = last_name; - av_name.mDisplayName = avatar_name; - const LLUUID& agent_id = avatar_id; - sAvatarNameMap[agent_id] = av_name; + LLAvatarName av_name; + av_name.fromString(avatar_name); + const LLUUID& agent_id = avatar_id; + sAvatarNameMap[agent_id] = av_name; + } + LLSD element; + element["id"] = avatar_id; // value + element["columns"][0]["column"] = "name"; + element["columns"][0]["value"] = avatar_name; + search_results->addElement(element); } - LLSD element; - element["id"] = avatar_id; // value - element["columns"][0]["column"] = "name"; - element["columns"][0]["value"] = avatar_name; - search_results->addElement(element); } if (found_one) @@ -689,18 +762,21 @@ void LLFloaterAvatarPicker::processResponse(const LLUUID& query_id, const LLSD& for ( ; it != agents.endArray(); ++it) { const LLSD& row = *it; - item["id"] = row["id"]; - LLSD& columns = item["columns"]; - columns[0]["column"] = "name"; - columns[0]["value"] = row["display_name"]; - columns[1]["column"] = "username"; - columns[1]["value"] = row["username"]; - search_results->addElement(item); - - // add the avatar name to our list - LLAvatarName avatar_name; - avatar_name.fromLLSD(row); - sAvatarNameMap[row["id"].asUUID()] = avatar_name; + if (row["id"].asUUID() != gAgent.getID() || !mExcludeAgentFromSearchResults) + { + item["id"] = row["id"]; + LLSD& columns = item["columns"]; + columns[0]["column"] = "name"; + columns[0]["value"] = row["display_name"]; + columns[1]["column"] = "username"; + columns[1]["value"] = row["username"]; + search_results->addElement(item); + + // add the avatar name to our list + LLAvatarName avatar_name; + avatar_name.fromLLSD(row); + sAvatarNameMap[row["id"].asUUID()] = avatar_name; + } } getChildView("ok_btn")->setEnabled(true); @@ -712,10 +788,10 @@ void LLFloaterAvatarPicker::processResponse(const LLUUID& query_id, const LLSD& void LLFloaterAvatarPicker::editKeystroke(LLLineEditor* caller) { - if(caller->getName() == "Edit") + if (caller->getName() == "Edit") getChildView("Find")->setEnabled(caller->getText().size() >= 3); else - childSetEnabled("Select", caller->getValue().asUUID().notNull()); + getChildView("Select")->setEnabled(caller->getValue().asUUID().notNull()); } // virtual diff --git a/indra/newview/llfloateravatarpicker.h b/indra/newview/llfloateravatarpicker.h index 799d287901..f4fcc91f4c 100644 --- a/indra/newview/llfloateravatarpicker.h +++ b/indra/newview/llfloateravatarpicker.h @@ -45,11 +45,15 @@ class LLFloaterAvatarPicker : public LLFloater, public LLSingleton mFrustumOrigin; + F32 mContextConeOpacity; + F32 mContextConeInAlpha; + F32 mContextConeOutAlpha; + F32 mContextConeFadeTime; validate_signal_t mOkButtonValidateSignal; select_callback_t mSelectionCallback; diff --git a/indra/newview/llfloateravatartextures.cpp b/indra/newview/llfloateravatartextures.cpp index 4e6312175e..79c6d72b8a 100644 --- a/indra/newview/llfloateravatartextures.cpp +++ b/indra/newview/llfloateravatartextures.cpp @@ -46,6 +46,10 @@ LLFloaterAvatarTextures::LLFloaterAvatarTextures(const LLUUID& id) : LLFloater(std::string("avatar_texture_debug")), mID(id) { + for (U32 i = 0; i < TEX_NUM_INDICES; i++) + { + mTextures[i] = nullptr; + } } LLFloaterAvatarTextures::~LLFloaterAvatarTextures() @@ -175,7 +179,7 @@ void LLFloaterAvatarTextures::onClickDump(void* data) const LLTextureEntry* te = avatarp->getTE(i); if (!te) continue; - llinfos << "Avatar TE " << i << " id " << te->getID() << llendl; + LL_INFOS() << "Avatar TE " << i << " id " << te->getID() << LL_ENDL; } #endif } diff --git a/indra/newview/llfloaterbanduration.cpp b/indra/newview/llfloaterbanduration.cpp new file mode 100644 index 0000000000..3555cd846d --- /dev/null +++ b/indra/newview/llfloaterbanduration.cpp @@ -0,0 +1,92 @@ +/** +* @file llfloaterbanduration.cpp +* +* $LicenseInfo:firstyear=2004&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2018, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#include "llviewerprecompiledheaders.h" +#include "llfloaterbanduration.h" + +#include "llcombobox.h" +#include "llspinctrl.h" +#include "lluictrlfactory.h" + +LLFloaterBanDuration::LLFloaterBanDuration(const LLSD& target) : LLFloater() +{ + LLUICtrlFactory::instance().buildFloater(this, "floater_ban_duration.xml"); +} + +BOOL LLFloaterBanDuration::postBuild() +{ + childSetAction("ok_btn", boost::bind(&LLFloaterBanDuration::onClickBan, this)); + childSetAction("cancel_btn", boost::bind(&LLFloaterBanDuration::close, this, false)); + + auto combo = getChild("ban_duration_combo"); + combo->setCommitCallback(boost::bind(&LLFloaterBanDuration::onClickCombo, this, _2, getChild("ban_duration"))); + combo->onCommit(); + + return TRUE; +} + +LLFloaterBanDuration* LLFloaterBanDuration::show(select_callback_t callback, const uuid_vec_t& ids) +{ + LLFloaterBanDuration* floater = showInstance(); + if (!floater) + { + LL_WARNS() << "Cannot instantiate ban duration floater" << LL_ENDL; + return nullptr; + } + + floater->mSelectionCallback = callback; + floater->mAvatar_ids = ids; + + return floater; +} + +void LLFloaterBanDuration::onClickCombo(const LLSD& val, LLUICtrl* duration) +{ + duration->setEnabled(val.asInteger() != 0); +} + +void LLFloaterBanDuration::onClickBan() +{ + if (mSelectionCallback) + { + S32 time = 0; + if (auto type = getChild("ban_duration_combo")->getValue().asInteger()) + { + LLSpinCtrl* duration_spin = getChild("ban_duration"); + if (duration_spin) + { + time = (duration_spin->getValue().asInteger() * 3600); + if (type > 1) + { + time *= type == 2 ? 24 : type == 3 ? 168 : 730; + } + time += LLDate::now().secondsSinceEpoch(); + } + } + mSelectionCallback(mAvatar_ids, time); + } + close(); +} + diff --git a/indra/newview/llfloaterbanduration.h b/indra/newview/llfloaterbanduration.h new file mode 100644 index 0000000000..75b063ec68 --- /dev/null +++ b/indra/newview/llfloaterbanduration.h @@ -0,0 +1,52 @@ +/** +* @file llfloaterbanduration.h +* +* $LicenseInfo:firstyear=2004&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2018, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + + +#ifndef LL_FLOATERBANDURATION_H +#define LL_FLOATERBANDURATION_H + +#include "llfloater.h" + +class LLFloaterBanDuration : public LLFloater +, public LLFloaterSingleton +{ + typedef std::function select_callback_t; + +public: + LLFloaterBanDuration(const LLSD& target); + BOOL postBuild() override; + static LLFloaterBanDuration* show(select_callback_t callback, const uuid_vec_t& ids); + +private: + ~LLFloaterBanDuration() {}; + void onClickBan(); + void onClickCombo(const LLSD&, LLUICtrl*); + + uuid_vec_t mAvatar_ids; + select_callback_t mSelectionCallback; +}; + +#endif // LL_FLOATERBANDURATION_H + diff --git a/indra/newview/llfloaterblacklist.cpp b/indra/newview/llfloaterblacklist.cpp index 2b9b9dd050..bfbfd0a09a 100644 --- a/indra/newview/llfloaterblacklist.cpp +++ b/indra/newview/llfloaterblacklist.cpp @@ -20,10 +20,10 @@ LLFloaterBlacklist* LLFloaterBlacklist::sInstance; -std::vector LLFloaterBlacklist::blacklist_textures; -std::vector LLFloaterBlacklist::blacklist_objects; +uuid_vec_t LLFloaterBlacklist::blacklist_textures; +uuid_vec_t LLFloaterBlacklist::blacklist_objects; -std::map LLFloaterBlacklist::blacklist_entries; +boost::unordered_map LLFloaterBlacklist::blacklist_entries; LLFloaterBlacklist::LLFloaterBlacklist() : LLFloater() @@ -85,10 +85,10 @@ BOOL LLFloaterBlacklist::postBuild() } void LLFloaterBlacklist::refresh() { - + LLScrollListCtrl* list = getChild("file_list"); list->clearRows(); - for(std::map::iterator iter = blacklist_entries.begin(); iter != blacklist_entries.end(); ++iter) + for(auto iter = blacklist_entries.begin(); iter != blacklist_entries.end(); ++iter) { if(iter->first.isNull()) continue; LLSD element; @@ -174,7 +174,8 @@ void LLFloaterBlacklist::addEntry(LLUUID key, LLSD data) std::string wav_path= gDirUtilp->getExpandedFilename(LL_PATH_CACHE,sound_id.asString()) + ".dsf"; if(LLAPRFile::isExist(wav_path, LL_APR_RPB)) LLAPRFile::remove(wav_path); - gAudiop->removeAudioData(sound_id); + if(gAudiop) + gAudiop->removeAudioData(sound_id); } blacklist_entries.insert(std::pair(key,data)); updateBlacklists(); @@ -206,13 +207,17 @@ void LLFloaterBlacklist::onClickRemove(void* user_data) LLScrollListCtrl* list = floaterp->getChild("file_list"); if(list->getFirstSelected()) { - LLScrollListItem* item = list->getFirstSelected(); - LLUUID selected_id = item->getColumn(0)->getValue().asUUID(); - if(selected_id.isNull()) return; - list->deleteSingleItem(list->getFirstSelectedIndex()); - blacklist_entries.erase(selected_id); + uuid_vec_t selectedIDs = list->getSelectedIDs(); + uuid_vec_t::const_iterator iterator; + for(iterator = selectedIDs.begin(); + iterator != selectedIDs.end(); + ++iterator) + { + LLUUID selectedID = *iterator; + blacklist_entries.erase(selectedID); + } + list->deleteSelectedItems(); updateBlacklists(); - } } // static @@ -241,7 +246,7 @@ void LLFloaterBlacklist::updateBlacklists() blacklist_textures.clear(); blacklist_objects.clear(); gAssetStorage->mBlackListedAsset.clear(); - for(std::map::iterator iter = blacklist_entries.begin(); iter != blacklist_entries.end(); ++iter) + for(auto iter = blacklist_entries.begin(); iter != blacklist_entries.end(); ++iter) { if(blacklist_entries[iter->first]["entry_type"].asString() == "0") { @@ -251,12 +256,12 @@ void LLFloaterBlacklist::updateBlacklists() { gAssetStorage->mBlackListedAsset.push_back(LLUUID(iter->first)); } - + if(blacklist_entries[iter->first]["entry_type"].asString() == "6") { blacklist_objects.push_back(LLUUID(iter->first)); } - + } saveToDisk(); LLFloaterBlacklist* instance = LLFloaterBlacklist::getInstance(); @@ -271,7 +276,7 @@ void LLFloaterBlacklist::saveToDisk() std::string file_name = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "blacklist_sg1.xml"); llofstream export_file(file_name); LLSD data; - for(std::map::iterator iter = blacklist_entries.begin(); iter != blacklist_entries.end(); ++iter) + for(auto iter = blacklist_entries.begin(); iter != blacklist_entries.end(); ++iter) { data[iter->first.asString()] = iter->second; } @@ -295,11 +300,11 @@ void LLFloaterBlacklist::onClickSave_continued(AIFilePicker* filepicker) std::string file_name = filepicker->getFilename(); llofstream export_file(file_name); LLSD data; - for(std::map::iterator iter = blacklist_entries.begin(); iter != blacklist_entries.end(); ++iter) + for(auto iter = blacklist_entries.begin(); iter != blacklist_entries.end(); ++iter) { data[iter->first.asString()] = iter->second; } - LLSDSerialize::toPrettyXML(data, export_file); + LLSDSerialize::toPrettyXML(data, export_file); export_file.close(); } } @@ -335,14 +340,13 @@ void LLFloaterBlacklist::onClickLoad_continued(AIFilePicker* filepicker) void LLFloaterBlacklist::onClickRerender(void* user_data) { - std::map blacklist_new; - for(std::map::iterator itr = blacklist_entries.begin(); itr != blacklist_entries.end(); ++itr) + for(auto itr = blacklist_entries.begin(); itr != blacklist_entries.end();) { - if(blacklist_entries[itr->first]["entry_type"].asString() == "6") continue; - blacklist_new[itr->first] = blacklist_entries[itr->first]; - blacklist_new[itr->second] = blacklist_entries[itr->second]; + if (blacklist_entries[itr->first]["entry_type"].asString() == "6") + itr = blacklist_entries.erase(itr); + else + ++itr; } - blacklist_entries = blacklist_new; saveToDisk(); LLFloaterBlacklist* instance = LLFloaterBlacklist::getInstance(); if(instance) diff --git a/indra/newview/llfloaterblacklist.h b/indra/newview/llfloaterblacklist.h index 9b5c4171fc..c15c99a9cb 100644 --- a/indra/newview/llfloaterblacklist.h +++ b/indra/newview/llfloaterblacklist.h @@ -16,8 +16,7 @@ class LLFloaterBlacklist : LLFloater BOOL postBuild(); void refresh(); static LLFloaterBlacklist* getInstance() { return sInstance; }; - - + /*This is the function to call to add anything to the blacklist, key is the asset ID LLSD data is as follows: LLSD[entry_type] = LLAssetType::Etype, @@ -29,12 +28,9 @@ class LLFloaterBlacklist : LLFloater */ static void addEntry(LLUUID key, LLSD data); - - - - static std::map blacklist_entries; - static std::vector blacklist_textures; - static std::vector blacklist_objects; + static boost::unordered_map blacklist_entries; + static uuid_vec_t blacklist_textures; + static uuid_vec_t blacklist_objects; static void loadFromSave(); diff --git a/indra/newview/llfloaterbulkpermission.cpp b/indra/newview/llfloaterbulkpermission.cpp index bed9fea81e..0fcdc70712 100644 --- a/indra/newview/llfloaterbulkpermission.cpp +++ b/indra/newview/llfloaterbulkpermission.cpp @@ -79,17 +79,17 @@ void LLFloaterBulkPermission::doApply() class ModifiableGatherer : public LLSelectedNodeFunctor { public: - ModifiableGatherer(LLDynamicArray& q) : mQueue(q) {} + ModifiableGatherer(uuid_vec_t& q) : mQueue(q) {} virtual bool apply(LLSelectNode* node) { if( node->allowOperationOnNode(PERM_MODIFY, GP_OBJECT_MANIPULATE) ) { - mQueue.put(node->getObject()->getID()); + mQueue.push_back(node->getObject()->getID()); } return true; } private: - LLDynamicArray& mQueue; + uuid_vec_t& mQueue; }; LLScrollListCtrl* list = getChild("queue output"); list->deleteAllItems(); @@ -104,7 +104,7 @@ void LLFloaterBulkPermission::doApply() mDone = FALSE; if (!start()) { - llwarns << "Unexpected bulk permission change failure." << llendl; + LL_WARNS() << "Unexpected bulk permission change failure." << LL_ENDL; } } } @@ -118,7 +118,7 @@ void LLFloaterBulkPermission::inventoryChanged(LLViewerObject* viewer_object, S32, void* q_id) { - //llinfos << "changed object: " << viewer_object->getID() << llendl; + //LL_INFOS() << "changed object: " << viewer_object->getID() << LL_ENDL; //Remove this listener from the object since its //listener callback is now being executed. @@ -143,7 +143,7 @@ void LLFloaterBulkPermission::inventoryChanged(LLViewerObject* viewer_object, // something went wrong... // note that we're not working on this one, and move onto the // next object in the list. - llwarns << "No inventory for " << mCurrentObjectID << llendl; + LL_WARNS() << "No inventory for " << mCurrentObjectID << LL_ENDL; nextObject(); } } @@ -190,15 +190,15 @@ BOOL LLFloaterBulkPermission::nextObject() BOOL successful_start = FALSE; do { - count = mObjectIDs.count(); - //llinfos << "Objects left to process = " << count << llendl; + count = mObjectIDs.size(); + //LL_INFOS() << "Objects left to process = " << count << LL_ENDL; mCurrentObjectID.setNull(); if(count > 0) { successful_start = popNext(); - //llinfos << (successful_start ? "successful" : "unsuccessful") << llendl; + //LL_INFOS() << (successful_start ? "successful" : "unsuccessful") << LL_ENDL; } - } while((mObjectIDs.count() > 0) && !successful_start); + } while((mObjectIDs.size() > 0) && !successful_start); if(isDone() && !mDone) { @@ -214,16 +214,16 @@ BOOL LLFloaterBulkPermission::popNext() { // get the head element from the container, and attempt to get its inventory. BOOL rv = FALSE; - S32 count = mObjectIDs.count(); + S32 count = mObjectIDs.size(); if(mCurrentObjectID.isNull() && (count > 0)) { - mCurrentObjectID = mObjectIDs.get(0); - //llinfos << "mCurrentID: " << mCurrentObjectID << llendl; - mObjectIDs.remove(0); + mCurrentObjectID = mObjectIDs.at(0); + //LL_INFOS() << "mCurrentID: " << mCurrentObjectID << LL_ENDL; + mObjectIDs.erase(mObjectIDs.begin()); LLViewerObject* obj = gObjectList.findObject(mCurrentObjectID); if(obj) { - //llinfos << "requesting inv for " << mCurrentObjectID << llendl; + //LL_INFOS() << "requesting inv for " << mCurrentObjectID << LL_ENDL; LLUUID* id = new LLUUID(mID); registerVOInventoryListener(obj,id); requestVOInventory(); @@ -231,7 +231,7 @@ BOOL LLFloaterBulkPermission::popNext() } else { - llinfos<<"NULL LLViewerObject" <addSimpleElement(status_text.getString()); //TODO if we are an object inside an object we should check a recuse flag and if set diff --git a/indra/newview/llfloaterbulkpermission.h b/indra/newview/llfloaterbulkpermission.h index cd8c5760f2..ccbeb67414 100644 --- a/indra/newview/llfloaterbulkpermission.h +++ b/indra/newview/llfloaterbulkpermission.h @@ -34,7 +34,6 @@ #ifndef LL_LLBULKPERMISSION_H #define LL_LLBULKPERMISSION_H -#include "lldarray.h" #include "llinventory.h" #include "llviewerobject.h" #include "llvoinventorylistener.h" @@ -82,7 +81,7 @@ class LLFloaterBulkPermission : public LLFloater, public LLVOInventoryListener, void onUncheckAll() { doCheckUncheckAll(FALSE); } // returns true if this is done - BOOL isDone() const { return (mCurrentObjectID.isNull() || (mObjectIDs.count() == 0)); } + BOOL isDone() const { return (mCurrentObjectID.isNull() || (mObjectIDs.size() == 0)); } //Read the settings and Apply the permissions void doApply(); @@ -90,7 +89,7 @@ class LLFloaterBulkPermission : public LLFloater, public LLVOInventoryListener, private: // Object Queue - LLDynamicArray mObjectIDs; + uuid_vec_t mObjectIDs; LLUUID mCurrentObjectID; BOOL mDone; diff --git a/indra/newview/llfloaterbump.cpp b/indra/newview/llfloaterbump.cpp index 29b99c1f92..ee9c4373b6 100644 --- a/indra/newview/llfloaterbump.cpp +++ b/indra/newview/llfloaterbump.cpp @@ -129,8 +129,8 @@ void LLFloaterBump::add(LLScrollListCtrl* list, LLMeanCollisionData* mcd) action = "physical_object_collide"; break; default: - llinfos << "LLFloaterBump::add unknown mean collision type " - << mcd->mType << llendl; + LL_INFOS() << "LLFloaterBump::add unknown mean collision type " + << mcd->mType << LL_ENDL; return; } diff --git a/indra/newview/llfloaterbuy.cpp b/indra/newview/llfloaterbuy.cpp index 0314b7fffd..e7d3531730 100644 --- a/indra/newview/llfloaterbuy.cpp +++ b/indra/newview/llfloaterbuy.cpp @@ -206,14 +206,14 @@ void LLFloaterBuy::inventoryChanged(LLViewerObject* obj, { if (!obj) { - llwarns << "No object in LLFloaterBuy::inventoryChanged" << llendl; + LL_WARNS() << "No object in LLFloaterBuy::inventoryChanged" << LL_ENDL; return; } if (!inv) { - llwarns << "No inventory in LLFloaterBuy::inventoryChanged" - << llendl; + LL_WARNS() << "No inventory in LLFloaterBuy::inventoryChanged" + << LL_ENDL; removeVOInventoryListener(); return; } @@ -297,7 +297,7 @@ void LLFloaterBuy::onClickBuy(void*) { if (!sInstance) { - llinfos << "LLFloaterBuy::onClickBuy no sInstance!" << llendl; + LL_INFOS() << "LLFloaterBuy::onClickBuy no sInstance!" << LL_ENDL; return; } diff --git a/indra/newview/llfloaterbuycontents.cpp b/indra/newview/llfloaterbuycontents.cpp index 56bd7ed1ff..9f4088347b 100644 --- a/indra/newview/llfloaterbuycontents.cpp +++ b/indra/newview/llfloaterbuycontents.cpp @@ -157,7 +157,7 @@ void LLFloaterBuyContents::inventoryChanged(LLViewerObject* obj, { if (!obj) { - llwarns << "No object in LLFloaterBuyContents::inventoryChanged" << llendl; + LL_WARNS() << "No object in LLFloaterBuyContents::inventoryChanged" << LL_ENDL; return; } @@ -172,8 +172,8 @@ void LLFloaterBuyContents::inventoryChanged(LLViewerObject* obj, if (!inv) { - llwarns << "No inventory in LLFloaterBuyContents::inventoryChanged" - << llendl; + LL_WARNS() << "No inventory in LLFloaterBuyContents::inventoryChanged" + << LL_ENDL; return; } @@ -229,7 +229,7 @@ void LLFloaterBuyContents::inventoryChanged(LLViewerObject* obj, BOOL item_is_multi = FALSE; if ((inv_item->getFlags() & LLInventoryItemFlags::II_FLAGS_LANDMARK_VISITED || inv_item->getFlags() & LLInventoryItemFlags::II_FLAGS_OBJECT_HAS_MULTIPLE_ITEMS) - && !(inv_item->getFlags() & LLInventoryItemFlags::II_FLAGS_WEARABLES_MASK)) + && !(inv_item->getFlags() & LLInventoryItemFlags::II_FLAGS_SUBTYPE_MASK)) { item_is_multi = TRUE; } diff --git a/indra/newview/llfloaterbuycurrency.cpp b/indra/newview/llfloaterbuycurrency.cpp index 5a6ea24cb4..14f484e574 100644 --- a/indra/newview/llfloaterbuycurrency.cpp +++ b/indra/newview/llfloaterbuycurrency.cpp @@ -277,19 +277,19 @@ void LLFloaterBuyCurrencyUI::updateUI() S32 balance = gStatusBar->getBalance(); childShow("balance_label"); childShow("balance_amount"); - childSetTextArg("balance_amount", "[AMT]", llformat("%d", balance)); + childSetTextArg("balance_amount", "[AMT]", fmt::to_string(balance)); childSetTextArg("balance_amount", "[CURRENCY]", gHippoGridManager->getConnectedGrid()->getCurrencySymbol()); S32 buying = mManager.getAmount(); childShow("buying_label"); childShow("buying_amount"); - childSetTextArg("buying_amount", "[AMT]", llformat("%d", buying)); + childSetTextArg("buying_amount", "[AMT]", fmt::to_string(buying)); childSetTextArg("buying_amount", "[CURRENCY]", gHippoGridManager->getConnectedGrid()->getCurrencySymbol()); S32 total = balance + buying; childShow("total_label"); childShow("total_amount"); - childSetTextArg("total_amount", "[AMT]", llformat("%d", total)); + childSetTextArg("total_amount", "[AMT]", fmt::to_string(total)); childSetTextArg("total_amount", "[CURRENCY]", gHippoGridManager->getConnectedGrid()->getCurrencySymbol()); childSetVisible("purchase_warning_repurchase", false); diff --git a/indra/newview/llfloaterbuyland.cpp b/indra/newview/llfloaterbuyland.cpp index 02468dd65d..080a74a48f 100644 --- a/indra/newview/llfloaterbuyland.cpp +++ b/indra/newview/llfloaterbuyland.cpp @@ -157,7 +157,8 @@ class LLFloaterBuyLandUI { TransactionPreflight, TransactionCurrency, - TransactionBuy + TransactionBuy, + TransactionNone }; boost::intrusive_ptr mResponder; TransactionType mTransactionType; @@ -175,7 +176,7 @@ class LLFloaterBuyLandUI void updateFloaterCovenantText(const std::string& string, const LLUUID &asset_id); void updateFloaterEstateName(const std::string& name); void updateFloaterLastModified(const std::string& text); - void updateFloaterEstateOwnerName(const std::string& name); + void updateFloaterEstateOwnerID(const LLUUID& id); void updateWebSiteInfo(); void finishWebSiteInfo(); @@ -262,12 +263,12 @@ void LLFloaterBuyLand::updateLastModified(const std::string& text) } // static -void LLFloaterBuyLand::updateEstateOwnerName(const std::string& name) +void LLFloaterBuyLand::updateEstateOwnerID(const LLUUID& id) { - LLFloaterBuyLandUI* floater = LLFloaterBuyLandUI::instanceExists() ? LLFloaterBuyLandUI::getInstance() : NULL; + LLFloaterBuyLandUI* floater = LLFloaterBuyLandUI::instanceExists() ? LLFloaterBuyLandUI::getInstance() : nullptr; if (floater) { - floater->updateFloaterEstateOwnerName(name); + floater->updateFloaterEstateOwnerID(id); } } @@ -281,11 +282,34 @@ void LLFloaterBuyLand::updateEstateOwnerName(const std::string& name) LLFloaterBuyLandUI::LLFloaterBuyLandUI() : LLFloater(std::string("Buy Land")), mParcelSelectionObserver(this), + mRegion(nullptr), mParcel(0), + mIsClaim(false), + mIsForGroup(false), + mCanBuy(false), + mCannotBuyIsError(false), mBought(false), - mParcelValid(false), mSiteValid(false), - mChildren(*this), mCurrency(*this), - mParcelBuyInfo(0) + mAgentCommittedTier(0), + mAgentHasNeverOwnedLand(true), + mParcelValid(false), + mParcelIsForSale(false), + mParcelIsGroupLand(false), + mParcelGroupContribution(0), + mParcelPrice(0), + mParcelActualArea(0), + mParcelBillableArea(0), + mParcelSupportedObjects(0), + mParcelSoldWithObjects(false), + mUserPlanChoice(0), + mSiteValid(false), + mSiteMembershipUpgrade(false), + mSiteLandUseUpgrade(false), + mPreflightAskBillableArea(0), + mPreflightAskCurrencyBuy(0), + mChildren(*this), + mCurrency(*this), + mParcelBuyInfo(nullptr), + mTransactionType(TransactionNone) { LLUICtrlFactory::getInstance()->buildFloater(this, "floater_buy_land.xml"); LLViewerParcelMgr::getInstance()->addObserver(&mParcelSelectionObserver); @@ -347,8 +371,6 @@ void LLFloaterBuyLandUI::updateParcelInfo() mParcelSnapshot.setNull(); mParcelSellerName = ""; - mCanBuy = false; - mCannotBuyIsError = false; if (!mParcelValid) { @@ -386,9 +408,9 @@ void LLFloaterBuyLandUI::updateParcelInfo() } mParcelBillableArea = - llround(mRegion->getBillableFactor() * mParcelActualArea); + ll_round(mRegion->getBillableFactor() * mParcelActualArea); - mParcelSupportedObjects = llround( + mParcelSupportedObjects = ll_round( parcel->getMaxPrimCapacity() * parcel->getParcelPrimBonus()); // Can't have more than region max tasks, regardless of parcel // object bonus factor. @@ -607,10 +629,10 @@ void LLFloaterBuyLandUI::updateFloaterLastModified(const std::string& text) if (editor) editor->setText(text); } -void LLFloaterBuyLandUI::updateFloaterEstateOwnerName(const std::string& name) +void LLFloaterBuyLandUI::updateFloaterEstateOwnerID(const LLUUID& id) { LLTextBox* box = getChild("estate_owner_text"); - if (box) box->setText(name); + if (box) box->setValue(id); } void LLFloaterBuyLandUI::updateWebSiteInfo() @@ -843,7 +865,7 @@ void LLFloaterBuyLandUI::startTransaction(TransactionType type, const LLXMLRPCVa method = "buyLandPrep"; break; default: - llwarns << "LLFloaterBuyLandUI: Unknown transaction type!" << llendl; + LL_WARNS() << "LLFloaterBuyLandUI: Unknown transaction type!" << LL_ENDL; return; } @@ -863,9 +885,9 @@ bool LLFloaterBuyLandUI::checkTransaction() return false; } - if (mResponder->result_code() != CURLE_OK || mResponder->http_status() < 200 || mResponder->http_status() >= 400) + if (mResponder->result_code() != CURLE_OK || mResponder->getStatus() < 200 || mResponder->getStatus() >= 400) { - tellUserError(mResponder->reason(), mResponder->getURL()); + tellUserError(mResponder->getReason(), mResponder->getURL()); } else { switch (mTransactionType) diff --git a/indra/newview/llfloaterbuyland.h b/indra/newview/llfloaterbuyland.h index 0d90130a0b..8bb98e0c28 100644 --- a/indra/newview/llfloaterbuyland.h +++ b/indra/newview/llfloaterbuyland.h @@ -46,7 +46,7 @@ class LLFloaterBuyLand static void updateCovenantText(const std::string& string, const LLUUID& asset_id); static void updateEstateName(const std::string& name); static void updateLastModified(const std::string& text); - static void updateEstateOwnerName(const std::string& name); + static void updateEstateOwnerID(const LLUUID& id); }; #endif diff --git a/indra/newview/llfloaterbvhpreview.cpp b/indra/newview/llfloaterbvhpreview.cpp index 2544f67886..5bf24ddcc3 100644 --- a/indra/newview/llfloaterbvhpreview.cpp +++ b/indra/newview/llfloaterbvhpreview.cpp @@ -36,13 +36,13 @@ #include "llbvhloader.h" #include "lldatapacker.h" #include "lldir.h" -#include "lleconomy.h" #include "llnotificationsutil.h" #include "llvfile.h" #include "llapr.h" #include "llstring.h" #include "llagent.h" +#include "llagentbenefits.h" #include "llanimationstates.h" #include "llbbox.h" #include "llbutton.h" @@ -144,14 +144,13 @@ std::string STATUS[] = // LLFloaterBvhPreview() //----------------------------------------------------------------------------- LLFloaterBvhPreview::LLFloaterBvhPreview(const std::string& filename, void* item) : - LLFloaterNameDesc(filename, item) + LLFloaterNameDesc(filename, item), + mItem(item), // + mLastMouseX(0), + mLastMouseY(0), + mPlayButton(nullptr), + mStopButton(nullptr) { - // - mItem = item; - // - mLastMouseX = 0; - mLastMouseY = 0; - mIDList["Standing"] = ANIM_AGENT_STAND; mIDList["Walking"] = ANIM_AGENT_FEMALE_WALK; mIDList["Sitting"] = ANIM_AGENT_SIT_FEMALE; @@ -230,7 +229,7 @@ BOOL LLFloaterBvhPreview::postBuild() getChild("priority")->setMaxValue(7); } - childSetLabelArg("ok_btn", "[UPLOADFEE]", gHippoGridManager->getConnectedGrid()->getUploadFee()); + childSetLabelArg("ok_btn", "[UPLOADFEE]", gHippoGridManager->getConnectedGrid()->formatFee(LLAgentBenefitsMgr::current().getAnimationUploadCost())); childSetAction("ok_btn", onBtnOK, this); setDefaultBtn(); @@ -297,7 +296,7 @@ BOOL LLFloaterBvhPreview::postBuild() if (!infile.getFileHandle()) { - llwarns << "Can't open BVH file:" << mFilename << llendl; + LL_WARNS() << "Can't open BVH file:" << mFilename << LL_ENDL; } else { @@ -308,7 +307,7 @@ BOOL LLFloaterBvhPreview::postBuild() if (file_size == infile.read(file_buffer, file_size)) { file_buffer[file_size] = '\0'; - llinfos << "Loading BVH file " << mFilename << llendl; + LL_INFOS() << "Loading BVH file " << mFilename << LL_ENDL; ELoadStatus load_status = E_ST_OK; S32 line_number = 0; loaderp = new LLBVHLoader(file_buffer, load_status, line_number); @@ -316,11 +315,11 @@ BOOL LLFloaterBvhPreview::postBuild() if(load_status == E_ST_NO_XLT_FILE) { - llwarns << "NOTE: No translation table found." << llendl; + LL_WARNS() << "NOTE: No translation table found." << LL_ENDL; } else { - llwarns << "ERROR: [line: " << line_number << "] " << status << llendl; + LL_WARNS() << "ERROR: [line: " << line_number << "] " << status << LL_ENDL; } } @@ -353,7 +352,7 @@ BOOL LLFloaterBvhPreview::postBuild() // pass animation data through memory buffer loaderp->serialize(dp); dp.reset(); - success = motionp && motionp->deserialize(dp); + success = motionp && motionp->deserialize(dp, mMotionID); } else { @@ -375,6 +374,10 @@ BOOL LLFloaterBvhPreview::postBuild() } } + if (motionp && mInWorld) + { + gAgentAvatarp->removeMotion(mMotionID); + } //setEnabled(FALSE); mMotionID.setNull(); mAnimPreview = NULL; @@ -390,7 +393,7 @@ BOOL LLFloaterBvhPreview::postBuild() if (!raw_animatn.getFileHandle()) { - llwarns << "Can't open animatn file:" << mFilename << llendl; + LL_WARNS() << "Can't open animatn file:" << mFilename << LL_ENDL; } else { @@ -401,14 +404,14 @@ BOOL LLFloaterBvhPreview::postBuild() if (file_size == raw_animatn.read(file_buffer, file_size)) { file_buffer[file_size] = '\0'; - llinfos << "Loading animatn file " << mFilename << llendl; + LL_INFOS() << "Loading animatn file " << mFilename << LL_ENDL; mTransactionID.generate(); mMotionID = mTransactionID.makeAssetID(gAgent.getSecureSessionID()); mAnimPreview = new LLPreviewAnimation(256, 256); motionp = (LLKeyframeMotion*)mAnimPreview->getDummyAvatar()->createMotion(mMotionID); LLDataPackerBinaryBuffer dp((U8*)file_buffer, file_size); dp.reset(); - success = motionp && motionp->deserialize(dp); + success = motionp && motionp->deserialize(dp, mMotionID); } raw_animatn.close(); @@ -520,16 +523,16 @@ void LLFloaterBvhPreview::draw() gGL.getTexUnit(0)->bind(mAnimPreview); - gGL.begin( LLRender::QUADS ); + gGL.begin( LLRender::TRIANGLE_STRIP ); { gGL.texCoord2f(0.f, 1.f); gGL.vertex2i(PREVIEW_HPAD, PREVIEW_TEXTURE_HEIGHT); gGL.texCoord2f(0.f, 0.f); gGL.vertex2i(PREVIEW_HPAD, PREVIEW_HPAD + PREF_BUTTON_HEIGHT + PREVIEW_HPAD); - gGL.texCoord2f(1.f, 0.f); - gGL.vertex2i(r.getWidth() - PREVIEW_HPAD, PREVIEW_HPAD + PREF_BUTTON_HEIGHT + PREVIEW_HPAD); gGL.texCoord2f(1.f, 1.f); gGL.vertex2i(r.getWidth() - PREVIEW_HPAD, PREVIEW_TEXTURE_HEIGHT); + gGL.texCoord2f(1.f, 0.f); + gGL.vertex2i(r.getWidth() - PREVIEW_HPAD, PREVIEW_HPAD + PREF_BUTTON_HEIGHT + PREVIEW_HPAD); } gGL.end(); @@ -754,8 +757,25 @@ void LLFloaterBvhPreview::onBtnStop() avatarp = mAnimPreview->getDummyAvatar(); else return; +#if 0 // Singu note: See https://jira.secondlife.com/browse/SH-2590 resetMotion(); mPauseRequest = avatarp->requestPause(); +#else + // + // https://jira.secondlife.com/browse/SH-2590?focusedCommentId=286661&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-286661 + // Written by Coaldust Numbers. + // Is the motion looping and have we passed the loop in point? + if (getChild("loop_check")->getValue().asBoolean() && + (F32)getChild("loop_in_point")->getValue().asReal() <= (F32)getChild("playback_slider")->getValue().asReal() * 100.f) + { + avatarp->stopMotion(mMotionID, FALSE); + } + else + { + avatarp->stopMotion(mMotionID, TRUE); + } + // +#endif } } @@ -1218,7 +1238,7 @@ void LLFloaterBvhPreview::onBtnOK(void* userdata) std::string name = floaterp->getChild("name_form")->getValue().asString(); std::string desc = floaterp->getChild("description_form")->getValue().asString(); LLAssetStorage::LLStoreAssetCallback callback = NULL; - S32 expected_upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(); + S32 expected_upload_cost = LLAgentBenefitsMgr::current().getAnimationUploadCost(); void *userdata = NULL; // @@ -1248,14 +1268,16 @@ void LLFloaterBvhPreview::onBtnOK(void* userdata) 0, LLFolderType::FT_NONE, LLInventoryType::IT_ANIMATION, - LLFloaterPerms::getNextOwnerPerms(), LLFloaterPerms::getGroupPerms(), LLFloaterPerms::getEveryonePerms(), + LLFloaterPerms::getNextOwnerPerms("Uploads"), + LLFloaterPerms::getGroupPerms("Uploads"), + LLFloaterPerms::getEveryonePerms("Uploads"), name, callback, expected_upload_cost, userdata); } } else { - llwarns << "Failure writing animation data." << llendl; + LL_WARNS() << "Failure writing animation data." << LL_ENDL; LLNotificationsUtil::add("WriteAnimationFail"); } } @@ -1288,17 +1310,10 @@ LLPreviewAnimation::LLPreviewAnimation(S32 width, S32 height) : LLViewerDynamicT mCameraPitch = 0.f; mCameraZoom = 1.f; - mDummyAvatar = (LLVOAvatar*)gObjectList.createObjectViewer(LL_PCODE_LEGACY_AVATAR, gAgent.getRegion()); - mDummyAvatar->createDrawable(&gPipeline); - mDummyAvatar->mIsDummy = TRUE; + mDummyAvatar = (LLVOAvatar*)gObjectList.createObjectViewer(LL_PCODE_LEGACY_AVATAR, gAgent.getRegion(), LLViewerObject::CO_FLAG_UI_AVATAR); mDummyAvatar->mSpecialRenderMode = 1; - mDummyAvatar->setPositionAgent(LLVector3::zero); - mDummyAvatar->slamPosition(); - mDummyAvatar->updateJointLODs(); - mDummyAvatar->updateGeometry(mDummyAvatar->mDrawable); mDummyAvatar->startMotion(ANIM_AGENT_STAND, BASE_ANIM_TIME_OFFSET); mDummyAvatar->hideSkirt(); - //gPipeline.markVisible(mDummyAvatar->mDrawable, *LLViewerCamera::getInstance()); // stop extraneous animations mDummyAvatar->stopMotion( ANIM_AGENT_HEAD_ROT, TRUE ); diff --git a/indra/newview/llfloaterbvhpreview.h b/indra/newview/llfloaterbvhpreview.h index 7f31054c02..c775f41356 100644 --- a/indra/newview/llfloaterbvhpreview.h +++ b/indra/newview/llfloaterbvhpreview.h @@ -40,13 +40,24 @@ class LLVOAvatar; class LLViewerJointMesh; +LL_ALIGN_PREFIX(16) class LLPreviewAnimation : public LLViewerDynamicTexture { -protected: +public: virtual ~LLPreviewAnimation(); public: - LLPreviewAnimation(S32 width, S32 height); + LLPreviewAnimation(S32 width, S32 height); + + void* operator new(size_t size) + { + return ll_aligned_malloc_16(size); + } + + void operator delete(void* ptr) + { + ll_aligned_free_16(ptr); + } /*virtual*/ S8 getType() const ; @@ -69,7 +80,7 @@ class LLPreviewAnimation : public LLViewerDynamicTexture LLVector3 mCameraOffset; LLVector3 mCameraRelPos; LLPointer mDummyAvatar; -}; +} LL_ALIGN_POSTFIX(16); class LLFloaterBvhPreview : public LLFloaterNameDesc { diff --git a/indra/newview/llfloatercamera.cpp b/indra/newview/llfloatercamera.cpp index 18826f961e..c2bf202830 100644 --- a/indra/newview/llfloatercamera.cpp +++ b/indra/newview/llfloatercamera.cpp @@ -50,7 +50,10 @@ const F32 CAMERA_BUTTON_DELAY = 0.0f; // LLFloaterCamera::LLFloaterCamera(const LLSD& val) -: LLFloater("camera floater") // uses "FloaterCameraRect3" +: LLFloater("camera floater"), // uses "FloaterCameraRect3" + mRotate(nullptr), + mZoom(nullptr), + mTrack(nullptr) { setIsChrome(TRUE); diff --git a/indra/newview/llfloaterchat.cpp b/indra/newview/llfloaterchat.cpp index a8d430ca57..a3e51e234e 100644 --- a/indra/newview/llfloaterchat.cpp +++ b/indra/newview/llfloaterchat.cpp @@ -45,11 +45,13 @@ #include "llcombobox.h" #include "lltextparser.h" #include "lltrans.h" +#include "llurlregistry.h" #include "llwindow.h" // project include #include "ascentkeyword.h" #include "llagent.h" +#include "llavataractions.h" #include "llchatbar.h" #include "llconsole.h" #include "llfloaterchatterbox.h" @@ -70,11 +72,14 @@ #include "rlvhandler.h" // [/RLVa:KB] +#include + // // Global statics // LLColor4 agent_chat_color(const LLUUID& id, const std::string&, bool local_chat = true); LLColor4 get_text_color(const LLChat& chat, bool from_im = false); +void show_log_browser(const std::string&, const LLUUID&); // // Member Functions @@ -89,12 +94,9 @@ LLFloaterChat::LLFloaterChat(const LLSD& seed) // do not automatically open singleton floaters (as result of getInstance()) LLUICtrlFactory::getInstance()->buildFloater(this, "floater_chat_history.xml", &getFactoryMap(), /*no_open =*/false); - childSetCommitCallback("show mutes",onClickToggleShowMute,this); //show mutes - //childSetCommitCallback("translate chat",onClickToggleTranslateChat,this); - //childSetValue("translate chat", gSavedSettings.getBOOL("TranslateChat")); - childSetVisible("Chat History Editor with mute",FALSE); - childSetAction("toggle_active_speakers_btn", onClickToggleActiveSpeakers, this); - childSetAction("chat_history_open", onClickChatHistoryOpen, this); + LLTextEditor* history_editor_with_mute = getChild("Chat History Editor with mute"); + getChild("show mutes")->setCommitCallback(boost::bind(&LLFloaterChat::onClickToggleShowMute, this, _2, getChild("Chat History Editor"), history_editor_with_mute)); + getChild("chat_history_open")->setCommitCallback(boost::bind(show_log_browser, "chat", LLUUID::null)); } LLFloaterChat::~LLFloaterChat() @@ -102,25 +104,9 @@ LLFloaterChat::~LLFloaterChat() // Children all cleaned up by default view destructor. } -void LLFloaterChat::setVisible(BOOL visible) -{ - LLFloater::setVisible( visible ); - - gSavedSettings.setBOOL("ShowChatHistory", visible); -} - void LLFloaterChat::draw() { - // enable say and shout only when text available - - mToggleActiveSpeakersBtn->setValue(mPanel->getVisible()); - - LLChatBar* chat_barp = mChatPanel; - if (chat_barp) - { - chat_barp->refresh(); - } - + mChatPanel->refresh(); mPanel->refreshSpeakers(); LLFloater::draw(); } @@ -129,14 +115,13 @@ BOOL LLFloaterChat::postBuild() { mPanel = getChild("active_speakers_panel"); - LLChatBar* chat_barp = getChild("chat_panel", TRUE); - if (chat_barp) - { - chat_barp->setGestureCombo(getChild( "Gesture")); - } +// [RLVa:KB] - Checked: 2009-07-08 (RLVa-1.0.0e) + getChild("toggle_active_speakers_btn")->setCommitCallback(boost::bind(&LLView::setVisible, mPanel, boost::bind(std::logical_and(), _2, !boost::bind(&RlvHandler::hasBehaviour, boost::ref(gRlvHandler), RLV_BHVR_SHOWNAMES)))); +// [/RLVa:KB] + //getChild("toggle_active_speakers_btn")->setCommitCallback(boost::bind(&LLView::setVisible, mPanel, _2)); - mToggleActiveSpeakersBtn.connect(this,"toggle_active_speakers_btn"); mChatPanel.connect(this,"chat_panel"); + mChatPanel->setGestureCombo(getChild( "Gesture")); return TRUE; } @@ -171,8 +156,7 @@ void LLFloaterChat::onFocusReceived() if (getVisible() && chat_editor->getVisible()) { gFocusMgr.setKeyboardFocus(chat_editor); - - chat_editor->setFocus(TRUE); + chat_editor->setFocus(true); } LLFloater::onFocusReceived(); @@ -212,46 +196,57 @@ void add_timestamped_line(LLViewerTextEditor* edit, LLChat chat, const LLColor4& (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) ) // [/RLVa:KB] { - chat.mURL = llformat("secondlife:///app/agent/%s/about",chat.mFromID.asString().c_str()); + chat.mURL = LLAvatarActions::getSLURL(chat.mFromID); } - if(chat.mSourceType == CHAT_SOURCE_OBJECT && !chat.mFromName.length()) + if (chat.mSourceType == CHAT_SOURCE_OBJECT) { - chat.mFromName = LLTrans::getString("Unnamed"); - line = chat.mFromName + line; + LLStringUtil::trim(chat.mFromName); + if (chat.mFromName.empty()) + { + chat.mFromName = LLTrans::getString("Unnamed"); + line = chat.mFromName + line; + } } static const LLCachedControl italicize("LiruItalicizeActions"); bool is_irc = italicize && chat.mChatStyle == CHAT_STYLE_IRC; // If the chat line has an associated url, link it up to the name. if (!chat.mURL.empty() - && (line.length() > chat.mFromName.length() && line.find(chat.mFromName,0) == 0)) + && boost::algorithm::starts_with(line, chat.mFromName)) { - std::string start_line = line.substr(0, chat.mFromName.length() + 1); - line = line.substr(chat.mFromName.length() + 1); - LLStyleSP sourceStyle = LLStyleMap::instance().lookup(chat.mFromID,chat.mURL); + line = line.substr(chat.mFromName.length()); + LLStyleSP sourceStyle = LLStyleMap::instance().lookup(chat.mFromID, chat.mURL); sourceStyle->mItalic = is_irc; - edit->appendStyledText(start_line, false, prepend_newline, sourceStyle); + edit->appendText(chat.mFromName, false, prepend_newline, sourceStyle, false); prepend_newline = false; } LLStyleSP style(new LLStyle); style->setColor(color); style->mItalic = is_irc; - edit->appendStyledText(line, false, prepend_newline, style); + style->mBold = chat.mChatType == CHAT_TYPE_SHOUT; + edit->appendText(line, false, prepend_newline, style, chat.mSourceType == CHAT_SOURCE_SYSTEM); +} + +void LLFloaterChat::addChatHistory(const std::string& str, bool log_to_file) +{ + LLChat chat(str); + chat.mSourceType = CHAT_SOURCE_SYSTEM; + addChatHistory(chat, log_to_file); } void log_chat_text(const LLChat& chat) { - std::string histstr; - if (gSavedPerAccountSettings.getBOOL("LogChatTimestamp")) - histstr = LLLogChat::timestamp(gSavedPerAccountSettings.getBOOL("LogTimestampDate")) + chat.mText; - else - histstr = chat.mText; + std::string histstr; + if (gSavedPerAccountSettings.getBOOL("LogChatTimestamp")) + histstr = LLLogChat::timestamp(gSavedPerAccountSettings.getBOOL("LogTimestampDate")) + chat.mText; + else + histstr = chat.mText; - LLLogChat::saveHistory(std::string("chat"),histstr); + LLLogChat::saveHistory("chat", LLUUID::null, histstr); } // static -void LLFloaterChat::addChatHistory(const LLChat& chat, bool log_to_file) +void LLFloaterChat::addChatHistory(LLChat& chat, bool log_to_file) { // [RLVa:KB] - Checked: 2009-07-08 (RLVa-1.0.0e) if (rlv_handler_t::isEnabled()) @@ -259,56 +254,53 @@ void LLFloaterChat::addChatHistory(const LLChat& chat, bool log_to_file) // TODO-RLVa: we might cast too broad a net by filtering here, needs testing if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) && (!chat.mRlvLocFiltered) && (CHAT_SOURCE_AGENT != chat.mSourceType) ) { - LLChat& rlvChat = const_cast(chat); - RlvUtil::filterLocation(rlvChat.mText); - rlvChat.mRlvLocFiltered = TRUE; + RlvUtil::filterLocation(chat.mText); + chat.mRlvLocFiltered = TRUE; } if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (!chat.mRlvNamesFiltered) ) { // NOTE: this will also filter inventory accepted/declined text in the chat history - LLChat& rlvChat = const_cast(chat); if (CHAT_SOURCE_AGENT != chat.mSourceType) { // Filter object and system chat (names are filtered elsewhere to save ourselves an gObjectList lookup) - RlvUtil::filterNames(rlvChat.mText); + RlvUtil::filterNames(chat.mText); } - rlvChat.mRlvNamesFiltered = TRUE; + chat.mRlvNamesFiltered = TRUE; } } // [/RLVa:KB] - if ( gSavedPerAccountSettings.getBOOL("LogChat") && log_to_file) + if (gSavedPerAccountSettings.getBOOL("LogChat") && log_to_file) { log_chat_text(chat); } LLColor4 color = get_text_color(chat); - if (!log_to_file) color = LLColor4::grey; //Recap from log file. + if (!log_to_file) color = gSavedSettings.getColor("LogChatColor"); //Recap from log file. if (chat.mChatType == CHAT_TYPE_DEBUG_MSG) { - LLFloaterScriptDebug::addScriptLine(chat.mText, - chat.mFromName, - color, - chat.mFromID); + LLFloaterScriptDebug::addScriptLine(chat, color); if (!gSavedSettings.getBOOL("ScriptErrorsAsChat")) { return; } } + else if (chat.mChatType == CHAT_TYPE_OWNER && gSavedSettings.getBOOL("SinguOwnerSayAsErrors")) + { + LLFloaterScriptDebug::addScriptLine(chat, color); + return; + } // could flash the chat button in the status bar here. JC LLFloaterChat* chat_floater = LLFloaterChat::getInstance(LLSD()); - LLViewerTextEditor* history_editor = chat_floater->getChild("Chat History Editor"); - LLViewerTextEditor* history_editor_with_mute = chat_floater->getChild("Chat History Editor with mute"); + LLViewerTextEditor* history_editor = chat_floater->getChild("Chat History Editor"); + LLViewerTextEditor* history_editor_with_mute = chat_floater->getChild("Chat History Editor with mute"); history_editor->setParseHTML(TRUE); history_editor_with_mute->setParseHTML(TRUE); - - history_editor->setParseHighlights(TRUE); - history_editor_with_mute->setParseHighlights(TRUE); - + if (!chat.mMuted) { add_timestamped_line(history_editor, chat, color); @@ -325,7 +317,7 @@ void LLFloaterChat::addChatHistory(const LLChat& chat, bool log_to_file) // add objects as transient speakers that can be muted if (chat.mSourceType == CHAT_SOURCE_OBJECT) { - LLLocalSpeakerMgr::getInstance()->setSpeaker(chat.mFromID, chat.mFromName, LLSpeaker::STATUS_NOT_IN_CHANNEL, LLSpeaker::SPEAKER_OBJECT); + LLLocalSpeakerMgr::getInstance()->setSpeaker({ chat.mFromID, LLSpeaker::SPEAKER_OBJECT, LLSpeaker::STATUS_NOT_IN_CHANNEL, boost::none, boost::none, chat.mFromName }); } // start tab flashing on incoming text from other users (ignoring system text, etc) @@ -338,90 +330,32 @@ void LLFloaterChat::addChatHistory(const LLChat& chat, bool log_to_file) // static void LLFloaterChat::setHistoryCursorAndScrollToEnd() { - LLViewerTextEditor* history_editor = LLFloaterChat::getInstance(LLSD())->getChild("Chat History Editor"); - LLViewerTextEditor* history_editor_with_mute = LLFloaterChat::getInstance(LLSD())->getChild("Chat History Editor with mute"); - - if (history_editor) + if (LLViewerTextEditor* editor = getInstance()->findChild("Chat History Editor")) { - history_editor->setCursorAndScrollToEnd(); + editor->setCursorAndScrollToEnd(); } - if (history_editor_with_mute) + if (LLViewerTextEditor* editor = getInstance()->findChild("Chat History Editor with mute")) { - history_editor_with_mute->setCursorAndScrollToEnd(); + editor->setCursorAndScrollToEnd(); } } -//static -void LLFloaterChat::onClickMute(void *data) -{ - LLFloaterChat* self = (LLFloaterChat*)data; - - LLComboBox* chatter_combo = self->getChild("chatter combobox"); - - const std::string& name = chatter_combo->getSimple(); - LLUUID id = chatter_combo->getCurrentID(); - - if (name.empty()) return; - - LLMute mute(id); - mute.setFromDisplayName(name); - LLMuteList::getInstance()->add(mute); - - LLFloaterMute::showInstance(); -} - //static -void LLFloaterChat::onClickToggleShowMute(LLUICtrl* caller, void *data) +void LLFloaterChat::onClickToggleShowMute(bool show_mute, LLTextEditor* history_editor, LLTextEditor* history_editor_with_mute) { - LLFloaterChat* floater = (LLFloaterChat*)data; - - - //LLCheckBoxCtrl* - BOOL show_mute = floater->getChild("show mutes")->get(); - LLViewerTextEditor* history_editor = floater->getChild("Chat History Editor"); - LLViewerTextEditor* history_editor_with_mute = floater->getChild("Chat History Editor with mute"); - - if (!history_editor || !history_editor_with_mute) - return; - - //BOOL show_mute = floater->mShowMuteCheckBox->get(); - if (show_mute) - { - history_editor->setVisible(FALSE); - history_editor_with_mute->setVisible(TRUE); - history_editor_with_mute->setCursorAndScrollToEnd(); - } - else - { - history_editor->setVisible(TRUE); - history_editor_with_mute->setVisible(FALSE); - history_editor->setCursorAndScrollToEnd(); - } + (show_mute ? history_editor_with_mute : history_editor)->setCursorAndScrollToEnd(); } -// Update the "TranslateChat" pref after "translate chat" checkbox is toggled in -// the "Local Chat" floater. -//static -void LLFloaterChat::onClickToggleTranslateChat(LLUICtrl* caller, void *data) +void LLFloaterChat::addChat(const std::string& str, BOOL from_im, BOOL local_agent) { - LLFloaterChat* floater = (LLFloaterChat*)data; - - BOOL translate_chat = floater->getChild("translate chat")->get(); - gSavedSettings.setBOOL("TranslateChat", translate_chat); -} - -// Update the "translate chat" checkbox after the "TranslateChat" pref is set in -// some other place (e.g. prefs dialog). -//static -void LLFloaterChat::updateSettings() -{ - BOOL translate_chat = gSavedSettings.getBOOL("TranslateChat"); - LLFloaterChat::getInstance(LLSD())->getChild("translate chat")->set(translate_chat); + LLChat chat(str); + chat.mSourceType = CHAT_SOURCE_SYSTEM; + addChat(chat, from_im, local_agent); } // Put a line of chat in all the right places -void LLFloaterChat::addChat(const LLChat& chat, +void LLFloaterChat::addChat(LLChat& chat, BOOL from_instant_message, BOOL local_agent) { @@ -437,20 +371,18 @@ void LLFloaterChat::addChat(const LLChat& chat, // TODO-RLVa: we might cast too broad a net by filtering here, needs testing if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) && (!chat.mRlvLocFiltered) && (CHAT_SOURCE_AGENT != chat.mSourceType) ) { - LLChat& rlvChat = const_cast(chat); if (!from_instant_message) - RlvUtil::filterLocation(rlvChat.mText); - rlvChat.mRlvLocFiltered = TRUE; + RlvUtil::filterLocation(chat.mText); + chat.mRlvLocFiltered = TRUE; } if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (!chat.mRlvNamesFiltered) ) { - LLChat& rlvChat = const_cast(chat); if ( (!from_instant_message) && (CHAT_SOURCE_AGENT != chat.mSourceType) ) { // Filter object and system chat (names are filtered elsewhere to save ourselves an gObjectList lookup) - RlvUtil::filterNames(rlvChat.mText); + RlvUtil::filterNames(chat.mText); } - rlvChat.mRlvNamesFiltered = TRUE; + chat.mRlvNamesFiltered = TRUE; } } // [/RLVa:KB] @@ -463,7 +395,19 @@ void LLFloaterChat::addChat(const LLChat& chat, // We display anything if it's not an IM. If it's an IM, check pref... if ( !from_instant_message || gSavedSettings.getBOOL("IMInChatConsole") ) { - gConsole->addConsoleLine(chat.mText, text_color); + // Replace registered urls in the console so it looks right. + std::string chit(chat.mText), // Read through this + chat; // Add parts to this + LLUrlMatch match; + while (!chit.empty() && LLUrlRegistry::instance().findUrl(chit, match)) + { + const auto start(match.getStart()), length(match.getEnd()+1-start); + if (start > 0) chat += chit.substr(0, start); // Add up to the start of the match + chat += match.getLabel() + match.getQuery(); // Add the label and the query + chit.erase(0, start+length); // remove the url match and all before it + } + if (!chit.empty()) chat += chit; // Add any leftovers + gConsole->addConsoleLine(chat, text_color); } } @@ -498,6 +442,7 @@ void LLFloaterChat::triggerAlerts(const std::string& text) { if ((std::string)highlight["sound_lluuid"] != LLUUID::null.asString()) { + if(gAudiop) gAudiop->triggerSound(highlight["sound_lluuid"].asUUID(), gAgent.getID(), 1.f, @@ -577,21 +522,11 @@ LLColor4 get_text_color(const LLChat& chat, bool from_im) } } - static const LLCachedControl mKeywordsChangeColor(gSavedPerAccountSettings, "KeywordsChangeColor", false); - static const LLCachedControl mKeywordsColor(gSavedPerAccountSettings, "KeywordsColor", LLColor4(1.f, 1.f, 1.f, 1.f)); - - if ((gAgent.getID() != chat.mFromID) && (chat.mSourceType != CHAT_SOURCE_SYSTEM)) + static const LLCachedControl sKeywordsChangeColor(gSavedPerAccountSettings, "KeywordsChangeColor", false); + if (sKeywordsChangeColor && gAgentID != chat.mFromID && AscentKeyword::hasKeyword((chat.mSourceType != CHAT_SOURCE_SYSTEM && boost::starts_with(chat.mText, chat.mFromName)) ? chat.mText.substr(chat.mFromName.length()) : chat.mText, 1)) { - if (mKeywordsChangeColor) - { - std::string shortmsg(chat.mText); - shortmsg.erase(0, chat.mFromName.length()); - - if (AscentKeyword::hasKeyword(shortmsg, 1)) - { - text_color = mKeywordsColor; - } - } + static const LLCachedControl sKeywordsColor(gSavedPerAccountSettings, "KeywordsColor", LLColor4(1.f, 1.f, 1.f, 1.f)); + text_color = sKeywordsColor; } return text_color; @@ -600,28 +535,19 @@ LLColor4 get_text_color(const LLChat& chat, bool from_im) //static void LLFloaterChat::loadHistory() { - LLLogChat::loadHistory(std::string("chat"), &chatFromLogFile, (void *)LLFloaterChat::getInstance(LLSD())); + LLLogChat::loadHistory("chat", LLUUID::null, boost::bind(&LLFloaterChat::chatFromLogFile, getInstance(), _1, _2)); } -//static -void LLFloaterChat::chatFromLogFile(LLLogChat::ELogLineType type , std::string line, void* userdata) + +void LLFloaterChat::chatFromLogFile(LLLogChat::ELogLineType type, const std::string& line) { - switch (type) + bool log_line = type == LLLogChat::LOG_LINE; + if (log_line || gSavedPerAccountSettings.getBOOL("LogChat")) { - case LLLogChat::LOG_EMPTY: - case LLLogChat::LOG_END: - // *TODO: nice message from XML file here - break; - case LLLogChat::LOG_LINE: - { - LLChat chat; - chat.mText = line; - addChatHistory(chat, FALSE); - } - break; - default: - // nothing - break; + LLStyleSP style(new LLStyle(true, gSavedSettings.getColor4("LogChatColor"), LLStringUtil::null)); + const auto text = log_line ? line : getString(type == LLLogChat::LOG_END ? "IM_end_log_string" : "IM_logging_string"); + for (const auto& ed_name : { "Chat History Editor", "Chat History Editor with mute" }) + getChild(ed_name)->appendText(text, false, true, style, false); } } @@ -634,29 +560,7 @@ void* LLFloaterChat::createSpeakersPanel(void* data) //static void* LLFloaterChat::createChatPanel(void* data) { - LLChatBar* chatp = new LLChatBar(); - return chatp; -} - -// static -void LLFloaterChat::onClickToggleActiveSpeakers(void* userdata) -{ - LLFloaterChat* self = (LLFloaterChat*)userdata; - -// [RLVa:KB] - Checked: 2009-07-08 (RLVa-1.0.0e) - self->childSetVisible("active_speakers_panel", - (!self->childIsVisible("active_speakers_panel")) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) ); -// [/RLVa:KB] - //self->childSetVisible("active_speakers_panel", !self->childIsVisible("active_speakers_panel")); -} - -// static -void LLFloaterChat::onClickChatHistoryOpen(void* userdata) -{ - std::string command("\"" + LLLogChat::makeLogFileName("chat") + "\""); - gViewerWindow->getWindow()->ShellEx(command); - - llinfos << command << llendl; + return new LLChatBar; } //static diff --git a/indra/newview/llfloaterchat.h b/indra/newview/llfloaterchat.h index 7eaab1b163..7a9a7948ee 100644 --- a/indra/newview/llfloaterchat.h +++ b/indra/newview/llfloaterchat.h @@ -40,17 +40,9 @@ #include "llfloater.h" #include "lllogchat.h" -class LLButton; class LLChat; -class LLComboBox; -class LLLineEditor; -class LLViewerTextEditor; -class LLMessageSystem; -class LLUUID; -class LLCheckBoxCtrl; -class LLParticipantList; -class LLLogChat; class LLChatBar; +class LLParticipantList; class LLFloaterChat : public LLFloater, public LLUISingleton @@ -59,7 +51,6 @@ class LLFloaterChat LLFloaterChat(const LLSD& seed); ~LLFloaterChat(); - virtual void setVisible( BOOL b ); virtual void draw(); virtual BOOL postBuild(); virtual void onClose(bool app_quitting); @@ -67,25 +58,22 @@ class LLFloaterChat virtual void handleVisibilityChange(BOOL cur_visibility); virtual void setMinimized(BOOL); void updateConsoleVisibility(); - void updateSettings(); static void setHistoryCursorAndScrollToEnd(); - + // Add chat to console and history list. // Color based on source, type, distance. - static void addChat(const LLChat& chat, BOOL from_im = FALSE, BOOL local_agent = FALSE); + static void addChat(const std::string& str, BOOL from_im = FALSE, BOOL local_agent = FALSE); + static void addChat(LLChat& chat, BOOL from_im = FALSE, BOOL local_agent = FALSE); // Add chat to history alone. - static void addChatHistory(const LLChat& chat, bool log_to_file = true); + static void addChatHistory(const std::string& str, bool log_to_file = true); + static void addChatHistory(LLChat& chat, bool log_to_file = true); static void triggerAlerts(const std::string& text); - static void onClickMute(void *data); - static void onClickToggleShowMute(LLUICtrl* caller, void *data); - static void onClickToggleTranslateChat(LLUICtrl* caller, void *data); - static void onClickToggleActiveSpeakers(void* userdata); - static void onClickChatHistoryOpen(void* userdata); - static void chatFromLogFile(LLLogChat::ELogLineType type,std::string line, void* userdata); + void onClickToggleShowMute(bool show_mute, class LLTextEditor* history_editor, LLTextEditor* history_editor_with_mute); + void chatFromLogFile(LLLogChat::ELogLineType type, const std::string& line); static void loadHistory(); static void* createSpeakersPanel(void* data); static void* createChatPanel(void* data); @@ -100,7 +88,6 @@ class LLFloaterChat BOOL focusFirstItem(BOOL prefer_text_fields = FALSE, BOOL focus_flash = TRUE ); - CachedUICtrl mToggleActiveSpeakersBtn; CachedUICtrl mChatPanel; }; diff --git a/indra/newview/llfloaterchatterbox.cpp b/indra/newview/llfloaterchatterbox.cpp index c491f07fee..2e3598d23b 100644 --- a/indra/newview/llfloaterchatterbox.cpp +++ b/indra/newview/llfloaterchatterbox.cpp @@ -78,9 +78,14 @@ BOOL LLFloaterMyFriends::postBuild() return TRUE; } +void LLFloaterMyFriends::onOpen() +{ + gSavedSettings.setBOOL("ShowContacts", true); +} void LLFloaterMyFriends::onClose(bool app_quitting) { + if (!app_quitting) gSavedSettings.setBOOL("ShowContacts", false); setVisible(FALSE); } @@ -122,6 +127,7 @@ LLFloaterChatterBox::LLFloaterChatterBox(const LLSD& seed) : removeFloater(floater_contacts); // reparent to floater view gFloaterView->addChild(floater_contacts); + if (gSavedSettings.getBOOL("ShowContacts")) floater_contacts->open(); } else { @@ -136,11 +142,13 @@ LLFloaterChatterBox::LLFloaterChatterBox(const LLSD& seed) : removeFloater(floater_chat); // reparent to floater view gFloaterView->addChild(floater_chat); + if (gSavedSettings.getBOOL("ShowChatHistory")) floater_chat->open(); } else { addFloater(floater_chat, FALSE); } + if (gSavedSettings.getBOOL("ShowCommunicate")) open(); // After all floaters have been added, so we may not be hidden anyhow. gSavedSettings.getControl("ShowLocalChatFloaterBar")->getSignal()->connect(boost::bind(handleLocalChatBar, floater_chat, _2)); mTabContainer->lockTabs(); } @@ -228,7 +236,7 @@ void LLFloaterChatterBox::onOpen() void LLFloaterChatterBox::onClose(bool app_quitting) { setVisible(FALSE); - gSavedSettings.setBOOL("ShowCommunicate", FALSE); + if (!app_quitting) gSavedSettings.setBOOL("ShowCommunicate", false); } void LLFloaterChatterBox::setMinimized(BOOL minimized) diff --git a/indra/newview/llfloaterchatterbox.h b/indra/newview/llfloaterchatterbox.h index d3b45576ae..70f6314fe5 100644 --- a/indra/newview/llfloaterchatterbox.h +++ b/indra/newview/llfloaterchatterbox.h @@ -126,7 +126,8 @@ class LLFloaterMyFriends : public LLFloater, public LLUISingletonmClassifiedPanel = new LLPanelClassified(true, true); + self->mClassifiedPanel = new LLPanelClassifiedInfo(true, true); self->mClassifiedPanel->childSetValue("classified_url", self->mClassifiedID); return self->mClassifiedPanel; } diff --git a/indra/newview/llfloaterclassified.h b/indra/newview/llfloaterclassified.h index 732a5584af..d049467b42 100644 --- a/indra/newview/llfloaterclassified.h +++ b/indra/newview/llfloaterclassified.h @@ -2,7 +2,7 @@ * @file llfloaterclassified.h * @brief Classified information as shown in a floating window from * secondlife:// command handler. - * Just a wrapper for LLPanelClassified. + * Just a wrapper for LLPanelClassifiedInfo. * * $LicenseInfo:firstyear=2002&license=viewergpl$ * @@ -37,7 +37,7 @@ #include "llfloater.h" -class LLPanelClassified; +class LLPanelClassifiedInfo; class LLFloaterClassifiedInfo : LLFloater { @@ -53,7 +53,7 @@ class LLFloaterClassifiedInfo : LLFloater private: - LLPanelClassified* mClassifiedPanel; + LLPanelClassifiedInfo* mClassifiedPanel; LLUUID mClassifiedID; }; diff --git a/indra/newview/llfloatercolorpicker.cpp b/indra/newview/llfloatercolorpicker.cpp index fb2ab184cc..487cccc49e 100644 --- a/indra/newview/llfloatercolorpicker.cpp +++ b/indra/newview/llfloatercolorpicker.cpp @@ -78,6 +78,15 @@ const F32 CONTEXT_FADE_TIME = 0.08f; LLFloaterColorPicker::LLFloaterColorPicker (LLColorSwatchCtrl* swatch, BOOL show_apply_immediate ) : LLFloater (std::string("Color Picker Floater")), + origR(1.f), + origG(1.f), + origB(1.f), + curR(1.f), + curG(1.f), + curB(1.f), + curH(0.f), + curS(0.f), + curL(1.f), mComponents ( 3 ), mMouseDownInLumRegion ( FALSE ), mMouseDownInHueRegion ( FALSE ), @@ -108,7 +117,11 @@ LLFloaterColorPicker::LLFloaterColorPicker (LLColorSwatchCtrl* swatch, BOOL show mPaletteRegionHeight ( 40 ), mSwatch ( swatch ), mActive ( TRUE ), + mApplyImmediateCheck(nullptr), mCanApplyImmediately ( show_apply_immediate ), + mSelectBtn(nullptr), + mCancelBtn(nullptr), + mPipetteBtn(nullptr), mContextConeOpacity ( 0.f ) { // build the majority of the gui using the factory builder @@ -490,47 +503,40 @@ void LLFloaterColorPicker::draw() if (hasFocus() && mSwatch->isInVisibleChain() && mContextConeOpacity > 0.001f) { gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - LLGLEnable(GL_CULL_FACE); - gGL.begin(LLRender::QUADS); + LLGLEnable cull; + gGL.begin(LLRender::TRIANGLE_STRIP); { - gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity); - gGL.vertex2i(swatch_rect.mLeft, swatch_rect.mTop); - gGL.vertex2i(swatch_rect.mRight, swatch_rect.mTop); gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity); - gGL.vertex2i(local_rect.mRight, local_rect.mTop); gGL.vertex2i(local_rect.mLeft, local_rect.mTop); - - gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity); - gGL.vertex2i(local_rect.mLeft, local_rect.mTop); - gGL.vertex2i(local_rect.mLeft, local_rect.mBottom); gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity); - gGL.vertex2i(swatch_rect.mLeft, swatch_rect.mBottom); gGL.vertex2i(swatch_rect.mLeft, swatch_rect.mTop); - gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity); - gGL.vertex2i(local_rect.mRight, local_rect.mBottom); gGL.vertex2i(local_rect.mRight, local_rect.mTop); gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity); gGL.vertex2i(swatch_rect.mRight, swatch_rect.mTop); - gGL.vertex2i(swatch_rect.mRight, swatch_rect.mBottom); - gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity); - gGL.vertex2i(local_rect.mLeft, local_rect.mBottom); gGL.vertex2i(local_rect.mRight, local_rect.mBottom); gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity); gGL.vertex2i(swatch_rect.mRight, swatch_rect.mBottom); + gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity); + gGL.vertex2i(local_rect.mLeft, local_rect.mBottom); + gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity); gGL.vertex2i(swatch_rect.mLeft, swatch_rect.mBottom); + gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity); + gGL.vertex2i(local_rect.mLeft, local_rect.mTop); + gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity); + gGL.vertex2i(swatch_rect.mLeft, swatch_rect.mTop); } gGL.end(); } if (gFocusMgr.childHasMouseCapture(getDragHandle())) { - mContextConeOpacity = lerp(mContextConeOpacity, gSavedSettings.getF32("PickerContextOpacity"), LLCriticalDamp::getInterpolant(CONTEXT_FADE_TIME)); + mContextConeOpacity = lerp(mContextConeOpacity, gSavedSettings.getF32("PickerContextOpacity"), LLSmoothInterpolation::getInterpolant(CONTEXT_FADE_TIME)); } else { - mContextConeOpacity = lerp(mContextConeOpacity, 0.f, LLCriticalDamp::getInterpolant(CONTEXT_FADE_TIME)); + mContextConeOpacity = lerp(mContextConeOpacity, 0.f, LLSmoothInterpolation::getInterpolant(CONTEXT_FADE_TIME)); } mPipetteBtn->setToggleState(LLToolMgr::getInstance()->getCurrentTool() == LLToolPipette::getInstance()); diff --git a/indra/newview/llfloatercustomize.cpp b/indra/newview/llfloatercustomize.cpp index 3a9e9f3977..63aa904ddc 100644 --- a/indra/newview/llfloatercustomize.cpp +++ b/indra/newview/llfloatercustomize.cpp @@ -38,6 +38,7 @@ #include "llagentcamera.h" #include "llagentwearables.h" #include "llappearancemgr.h" +#include "llflyoutbutton.h" #include "llmakeoutfitdialog.h" #include "llmorphview.h" #include "llnotificationsutil.h" @@ -53,8 +54,8 @@ #include "llvoavatarself.h" #include "statemachine/aifilepicker.h" -#include "llxmltree.h" #include "hippogridmanager.h" +#include "aixmllindengenepool.h" using namespace LLAvatarAppearanceDefines; @@ -89,20 +90,6 @@ BOOL edit_wearable_for_teens(LLWearableType::EType type) } } -//////////////////////////////////////////////////////////////////////////// - -void updateAvatarHeightDisplay() -{ - if (LLFloaterCustomize::instanceExists() && isAgentAvatarValid()) - { - F32 avatar_size = (gAgentAvatarp->mBodySize.mV[VZ]) + (F32)0.17; //mBodySize is actually quite a bit off. - LLFloaterCustomize::getInstance()->getChild("HeightTextM")->setValue(llformat("%.2f", avatar_size) + "m"); - F32 feet = avatar_size / 0.3048; - F32 inches = (feet - (F32)((U32)feet)) * 12.0; - LLFloaterCustomize::getInstance()->getChild("HeightTextI")->setValue(llformat("%d'%d\"", (U32)feet, (U32)inches)); - } - } - ///////////////////////////////////////////////////////////////////// // LLFloaterCustomize @@ -116,7 +103,7 @@ struct WearablePanelData LLFloaterCustomize::LLFloaterCustomize() : LLFloater(std::string("customize")), - mScrollingPanelList( NULL ), + mScrollingPanelList(new LLScrollingPanelList(std::string("panel_list"), LLRect())), mInventoryObserver(NULL), mCurrentWearableType(LLWearableType::WT_INVALID) { @@ -131,9 +118,9 @@ LLFloaterCustomize::LLFloaterCustomize() gInventory.addObserver(mInventoryObserver); LLOutfitObserver& outfit_observer = LLOutfitObserver::instance(); - outfit_observer.addBOFReplacedCallback(boost::bind(&LLFloaterCustomize::refreshCurrentOutfitName, this, "")); - outfit_observer.addBOFChangedCallback(boost::bind(&LLFloaterCustomize::refreshCurrentOutfitName, this, "")); - outfit_observer.addCOFChangedCallback(boost::bind(&LLFloaterCustomize::refreshCurrentOutfitName, this, "")); + outfit_observer.addBOFReplacedCallback(boost::bind(&LLFloaterCustomize::refreshCurrentOutfitName, this, LLStringUtil::null)); + outfit_observer.addBOFChangedCallback(boost::bind(&LLFloaterCustomize::refreshCurrentOutfitName, this, LLStringUtil::null)); + outfit_observer.addCOFChangedCallback(boost::bind(&LLFloaterCustomize::refreshCurrentOutfitName, this, LLStringUtil::null)); LLCallbackMap::map_t factory_map; const std::string &invalid_name = LLWearableType::getTypeName(LLWearableType::WT_INVALID); @@ -158,7 +145,7 @@ LLFloaterCustomize::LLFloaterCustomize() LLFloaterCustomize::~LLFloaterCustomize() { - llinfos << "Destroying LLFloaterCustomize" << llendl; + LL_INFOS() << "Destroying LLFloaterCustomize" << LL_ENDL; mResetParams = NULL; gInventory.removeObserver(mInventoryObserver); delete mInventoryObserver; @@ -167,9 +154,9 @@ LLFloaterCustomize::~LLFloaterCustomize() // virtual BOOL LLFloaterCustomize::postBuild() { - getChild("Make Outfit")->setCommitCallback(boost::bind(&LLFloaterCustomize::onBtnMakeOutfit, this)); - getChild("Save Outfit")->setCommitCallback(boost::bind(&LLAppearanceMgr::updateBaseOutfit, LLAppearanceMgr::getInstance())); - refreshCurrentOutfitName(); // Initialize tooltip for save outfit button + mMakeOutfitBtn = getChild("Make Outfit"); + mMakeOutfitBtn->setCommitCallback(boost::bind(&LLFloaterCustomize::onBtnMakeOutfit, this, _2)); + refreshCurrentOutfitName(); // Initialize flyout list entry for save outfit getChild("Ok")->setCommitCallback(boost::bind(&LLFloaterCustomize::onBtnOk, this)); getChild("Cancel")->setCommitCallback(boost::bind(&LLFloater::onClickClose, this)); @@ -178,41 +165,46 @@ BOOL LLFloaterCustomize::postBuild() getChild("Export")->setCommitCallback(boost::bind(&LLFloaterCustomize::onBtnExport, this)); // Tab container - LLTabContainer* tab_container = getChild("customize tab container"); - if(tab_container) + if (mTabContainer = getChild("customize tab container")) { - tab_container->setCommitCallback(boost::bind(&LLFloaterCustomize::onTabChanged, this, _2)); - tab_container->setValidateCallback(boost::bind(&LLFloaterCustomize::onTabPrecommit, this, _1, _2)); + mTabContainer->setCommitCallback(boost::bind(&LLFloaterCustomize::onTabChanged, this, _2)); + mTabContainer->setValidateCallback(boost::bind(&LLFloaterCustomize::onTabPrecommit, this, _1, _2)); } // Remove underwear panels for teens if (gAgent.isTeen()) { - if (tab_container) + if (mTabContainer) { - LLPanel* panel = tab_container->getPanelByName("Undershirt"); - if (panel) tab_container->removeTabPanel(panel); - panel = tab_container->getPanelByName("Underpants"); - if (panel) tab_container->removeTabPanel(panel); + LLPanel* panel = mTabContainer->getPanelByName("Undershirt"); + if (panel) mTabContainer->removeTabPanel(panel); + panel = mTabContainer->getPanelByName("Underpants"); + if (panel) mTabContainer->removeTabPanel(panel); } } - + // Scrolling Panel - initScrollingPanelList(); - + if (LLScrollContainer* scroll_container = getChild("panel_container")) + { + scroll_container->setScrolledView(mScrollingPanelList); + scroll_container->addChild(mScrollingPanelList); + } + + mMetricHeight = getChildView("HeightTextM"); + mImperialHeight = getChildView("HeightTextI"); + return TRUE; } void LLFloaterCustomize::refreshCurrentOutfitName(const std::string& name) { - LLUICtrl* save_outfit_btn = getChild("Save Outfit"); // Set current outfit status (wearing/unsaved). - bool dirty = LLAppearanceMgr::getInstance()->isOutfitDirty(); + //bool dirty = LLAppearanceMgr::getInstance()->isOutfitDirty(); //std::string cof_status_str = getString(dirty ? "Unsaved Changes" : "Now Wearing"); //mOutfitStatus->setText(cof_status_str); - save_outfit_btn->setEnabled(dirty); // No use saving unless dirty - if (name == "") + mMakeOutfitBtn->remove(0); + if (name.empty()) { std::string outfit_name; if (LLAppearanceMgr::getInstance()->getBaseOutfitName(outfit_name)) @@ -220,22 +212,21 @@ void LLFloaterCustomize::refreshCurrentOutfitName(const std::string& name) //mCurrentLookName->setText(outfit_name); LLStringUtil::format_map_t args; args["[OUTFIT]"] = outfit_name; - save_outfit_btn->setToolTip(getString("Save changes to", args)); + mMakeOutfitBtn->add(getString("Save changes to", args), LLSD(true)); return; } std::string string_name = gAgentWearables.isCOFChangeInProgress() ? "Changing outfits" : "No Outfit"; //mCurrentLookName->setText(getString(string_name)); - save_outfit_btn->setToolTip(getString(string_name)); + mMakeOutfitBtn->add(getString(string_name), LLSD()); //mOpenOutfitBtn->setEnabled(FALSE); - save_outfit_btn->setEnabled(false); // Can't save right now } else { //mCurrentLookName->setText(name); LLStringUtil::format_map_t args; args["[OUTFIT]"] = name; - save_outfit_btn->setToolTip(getString("Save changes to", args)); + mMakeOutfitBtn->add(getString("Save changes to", args), LLSD(true)); // Can't just call update verbs since the folder link may not have been created yet. //mOpenOutfitBtn->setEnabled(TRUE); } @@ -246,12 +237,18 @@ void LLFloaterCustomize::editWearable(LLViewerWearable* wearable, bool disable_c { if(!wearable) return; - LLFloaterCustomize::getInstance()->setCurrentWearableType(wearable->getType(), disable_camera_switch); + auto& inst = LLFloaterCustomize::instance(); + inst.setCurrentWearableType(wearable->getType(), disable_camera_switch); + U32 index(0); + gAgentWearables.getWearableIndex(wearable, index); + static_cast(inst.mTabContainer->getCurrentPanel())->setWearableIndex(index); } //static void LLFloaterCustomize::show() { + if (!gAgentWearables.areWearablesLoaded()) return; + if(!LLFloaterCustomize::instanceExists()) { const BOOL disable_camera_switch = LLWearableType::getDisableCameraSwitch(LLWearableType::WT_SHAPE); @@ -302,7 +299,7 @@ void LLFloaterCustomize::setCurrentWearableType( LLWearableType::EType type, boo if(mWearablePanelList[type_int]) { std::string panelname = mWearablePanelList[type_int]->getName(); - childShowTab("customize tab container", panelname); + mTabContainer->selectTabByName(panelname); switchToDefaultSubpart(); } @@ -330,215 +327,111 @@ void LLFloaterCustomize::onBtnImport_continued(AIFilePicker* filepicker) LLPanelEditWearable* panel_edit_wearable = getCurrentWearablePanel(); LLViewerWearable* edit_wearable = panel_edit_wearable->getWearable(); + LLWearableType::EType panel_wearable_type = panel_edit_wearable->getType(); + std::string label = utf8str_tolower(panel_edit_wearable->getLabel()); + std::string const filename = filepicker->getFilename(); - LLSD args(LLSD::emptyMap()); - args["FILE"] = gDirUtilp->getBaseFileName(filename); - LLXmlTree xml; - BOOL success = xml.parseFile(filename, FALSE); - if (!success) - { - LLNotificationsUtil::add("AIXMLImportParseError", args); - return; - } - LLXmlTreeNode* root = xml.getRoot(); - if (!root) - { - llwarns << "No root node found in wearable import file: " << filename << llendl; - LLNotificationsUtil::add("AIXMLImportParseError", args); - return; - } + AIArgs args("[FILE]", gDirUtilp->getBaseFileName(filename)); - //------------------------------------------------------------------------- - // (root) - //------------------------------------------------------------------------- - if (!root->hasName("linden_genepool")) - { - llwarns << "Invalid wearable import file (missing linden_genepool header): " << filename << llendl; - LLNotificationsUtil::add("AIXMLImportRootTypeError", args); - return; - } - static LLStdStringHandle const version_string = LLXmlTree::addAttributeString("version"); - std::string version; - if (!root->getFastAttributeString(version_string, version) || (version != "1.0")) - { - llwarns << "Invalid or incompatible linden_genepool version: " << version << " in file: " << filename << llendl; - args["TAG"] = "version"; - args["VERSIONMAJOR"] = "1"; - LLNotificationsUtil::add("AIXMLImportRootVersionError", args); - return; - } - static LLStdStringHandle const metaversion_string = LLXmlTree::addAttributeString("metaversion"); - std::string metaversion; - U32 metaversion_major; - if (!root->getFastAttributeString(metaversion_string, metaversion)) - { - llwarns << "Invalid linden_genepool metaversion: " << metaversion << " in file: " << filename << llendl; - metaversion_major = 0; - } - else if (!LLStringUtil::convertToU32(metaversion, metaversion_major) || metaversion_major > 1) - { - llwarns << "Invalid or incompatible linden_genepool metaversion: " << metaversion << " in file: " << filename << llendl; - args["TAG"] = "metaversion"; - args["VERSIONMAJOR"] = "1"; - LLNotificationsUtil::add("AIXMLImportRootVersionError", args); - return; - } + bool found_param = false; + bool found_texture = false; + bool found_type = false; - //------------------------------------------------------------------------- - // - //------------------------------------------------------------------------- - std::string gridnick; - LLDate date; bool different_grid = false; // By default assume it was exported on the same grid as we're on now. bool mixed_grids = false; // Set to true if two different grids (might) share UUIDs. Currently only "secondlife" and "secondlife_beta". - if (metaversion_major >= 1) - { - static LLStdStringHandle const gridnick_string = LLXmlTree::addAttributeString("gridnick"); - static LLStdStringHandle const date_string = LLXmlTree::addAttributeString("date"); - std::string date_s; - bool invalid = true; - LLXmlTreeNode* meta_node = root->getChildByName("meta"); - if (!meta_node) - { - llwarns << "No meta (1) in wearable import file: " << filename << llendl; - } - else if (!meta_node->getFastAttributeString(gridnick_string, gridnick)) - { - llwarns << "meta tag in file: " << filename << " is missing the 'gridnick' parameter." << llendl; - } - else if (!meta_node->getFastAttributeString(date_string, date_s) || !date.fromString(date_s)) + std::string gridnick; + std::string wearable_types; + + try + { + //------------------------------------------------------------------------- + // (root) + //------------------------------------------------------------------------- + std::string metaversion; + U32 metaversion_major = 0; // No metaversion + + AIXMLParser linden_genepool(filename, "wearable import file", "linden_genepool", 1); + linden_genepool.attribute("version", "1.0"); + + if (linden_genepool.attribute("metaversion", metaversion) && (!LLStringUtil::convertToU32(metaversion, metaversion_major) || metaversion_major > 1)) { - llwarns << "meta tag in file: " << filename << " is missing or invalid 'date' parameter." << llendl; + THROW_MALERT("AIXMLImportRootVersionError", args("[TAG]", "metaversion")("[VERSIONMAJOR]", "1")); } - else + + //------------------------------------------------------------------------- + // + //------------------------------------------------------------------------- + AIXMLLindenGenepool::MetaData meta_data; + + if (metaversion_major >= 1) { - invalid = false; + linden_genepool.child("meta", meta_data); std::string current_gridnick = gHippoGridManager->getConnectedGrid()->getGridNick(); + gridnick = meta_data.mGridNick; different_grid = gridnick != current_gridnick; mixed_grids = (gridnick == "secondlife" && current_gridnick == "secondlife_beta") || - (gridnick == "secondlife_beta" && current_gridnick == "secondlife"); + (gridnick == "secondlife_beta" && current_gridnick == "secondlife"); } - if (invalid) - { - LLNotificationsUtil::add("AIXMLImportInvalidError", args); - return; - } - } - static LLStdStringHandle const name_string = LLXmlTree::addAttributeString("name"); - - //------------------------------------------------------------------------- - // - //------------------------------------------------------------------------- - LLXmlTreeNode* archetype_node = root->getChildByName("archetype"); - if (!archetype_node) - { - llwarns << "No archetype in wearable import file: " << filename << llendl; - LLNotificationsUtil::add("AIXMLImportInvalidError", args); - return; - } - // Legacy that name="" exists. Using it as human (only) readable type label of contents. Don't use it for anything else because it might not be set. - std::string label = "???"; - if (metaversion_major >= 1) - { - if (!archetype_node->getFastAttributeString(name_string, label)) - { - llwarns << "archetype tag in file: " << filename << " is missing the 'name' parameter." << llendl; - } - } + std::vector archetypes; + linden_genepool.setVersion(metaversion_major); + linden_genepool.push_back_children("archetype", archetypes); - //------------------------------------------------------------------------- - // - //------------------------------------------------------------------------- - std::string path; - std::string wearable_name; - std::string wearable_description; - if (metaversion_major >= 1) - { - static LLStdStringHandle const path_string = LLXmlTree::addAttributeString("path"); - static LLStdStringHandle const description_string = LLXmlTree::addAttributeString("description"); - bool invalid = true; - LLXmlTreeNode* meta_node = archetype_node->getChildByName("meta"); - if (!meta_node) - { - llwarns << "No meta (2) in wearable import file: " << filename << llendl; - } - else if (!meta_node->getFastAttributeString(path_string, path)) - { - llwarns << "meta tag in file: " << filename << " is missing the 'path' parameter." << llendl; - } - else if (!meta_node->getFastAttributeString(name_string, wearable_name)) - { - llwarns << "meta tag in file: " << filename << " is missing the 'name' parameter." << llendl; - } - else if (!meta_node->getFastAttributeString(description_string, wearable_description)) - { - llwarns << "meta tag in file: " << filename << " is missing the 'description' parameter." << llendl; - } - else - { - invalid = false; - } - if (invalid) + if (archetypes.empty()) { - LLNotificationsUtil::add("AIXMLImportInvalidError", args); - return; + THROW_ALERT("AIXMLImportNoArchetypeError", AIArgs("[FILE]", filename)); } - } - // Parse the XML content. - static LLStdStringHandle const id_string = LLXmlTree::addAttributeString("id"); - static LLStdStringHandle const value_string = LLXmlTree::addAttributeString("value"); - static LLStdStringHandle const te_string = LLXmlTree::addAttributeString("te"); - static LLStdStringHandle const uuid_string = LLXmlTree::addAttributeString("uuid"); - bool found_param = false; - bool found_texture = false; - for(LLXmlTreeNode* child = archetype_node->getFirstChild(); child; child = archetype_node->getNextChild()) - { - if (child->hasName("param")) + for (std::vector::iterator archetype = archetypes.begin(); archetype != archetypes.end(); ++archetype) { - std::string id_s; - U32 id; - std::string value_s; - F32 value; - if (!child->getFastAttributeString(id_string, id_s) || !LLStringUtil::convertToU32(id_s, id) || - !child->getFastAttributeString(value_string, value_s) || !LLStringUtil::convertToF32(value_s, value)) + LLWearableType::EType type = archetype->getType(); + if (type != LLWearableType::WT_NONE) { - llwarns << "Possible syntax error or corruption for node in " << filename << llendl; - continue; - } - LLVisualParam* visual_param = edit_wearable->getVisualParam(id); - if (visual_param) - { - found_param = true; - visual_param->setWeight(value, FALSE); + if (!wearable_types.empty()) + { + wearable_types += "/"; + } + wearable_types += LLWearableType::getTypeName(type); + if (panel_wearable_type == type) + { + found_type = true; + } } - } - else if (child->hasName("texture")) - { - std::string te_s; - S32 te; - std::string uuid_s; - LLUUID uuid; - if (!child->getFastAttributeString(te_string, te_s) || !LLStringUtil::convertToS32(te_s, te) || te < 0 || te >= TEX_NUM_INDICES || - !child->getFastAttributeString(uuid_string, uuid_s) || !uuid.set(uuid_s, TRUE)) + for (AIArchetype::params_type::const_iterator param = archetype->getParams().begin(); param != archetype->getParams().end(); ++param) { - llwarns << "Possible syntax error or corruption for node in " << filename << llendl; - continue; + LLVisualParam* visual_param = edit_wearable->getVisualParam(param->getID()); + if (visual_param) + { + found_param = true; + visual_param->setWeight(param->getValue(), FALSE); + } } - ETextureIndex te_index = (ETextureIndex)te; - LLWearableType::EType te_wearable_type = LLAvatarAppearanceDictionary::getTEWearableType(te_index); - if (te_wearable_type == edit_wearable->getType()) + for (AIArchetype::textures_type::const_iterator texture = archetype->getTextures().begin(); texture != archetype->getTextures().end(); ++texture) { - found_texture = true; - if (!different_grid || mixed_grids) + U32 te = texture->getID(); + if (te >= TEX_NUM_INDICES) + { + } + ETextureIndex te_index = (ETextureIndex)te; + LLWearableType::EType te_wearable_type = LLAvatarAppearanceDictionary::getTEWearableType(te_index); + if (te_wearable_type == edit_wearable->getType()) { - panel_edit_wearable->setNewImageID(te_index, uuid); + found_texture = true; + if (!different_grid || mixed_grids) + { + panel_edit_wearable->setNewImageID(te_index, texture->getUUID()); + } } } } } + catch (AIAlert::Error const& error) + { + AIAlert::add_modal("AIXMLImportError", AIArgs("[TYPE]", label), error); + return; + } + if (found_param || found_texture) { edit_wearable->writeToAvatar(gAgentAvatarp); @@ -546,23 +439,25 @@ void LLFloaterCustomize::onBtnImport_continued(AIFilePicker* filepicker) panel_edit_wearable->updateScrollingPanelUI(); if (found_texture && different_grid) { - args["EXPORTGRID"] = gridnick; - args["CURRENTGRID"] = gHippoGridManager->getConnectedGrid()->getGridNick(); + args("[EXPORTGRID]", gridnick); + args("[CURRENTGRID]", gHippoGridManager->getConnectedGrid()->getGridNick()); if (mixed_grids) { - LLNotificationsUtil::add("AIXMLImportMixedGrid", args); + AIAlert::add_modal("AIXMLImportMixedGrid", args); } else { - LLNotificationsUtil::add("AIXMLImportDifferentGrid", args); + AIAlert::add_modal("AIXMLImportDifferentGrid", args); } } } - else + else if (found_type) { - args["TYPE"] = panel_edit_wearable->LLPanel::getLabel(); - args["ARCHETYPENAME"] = label; - LLNotificationsUtil::add("AIXMLImportWearableTypeMismatch", args); + AIAlert::add("AIXMLImportEmptyArchetype", args("[TYPE]", label)); + } + else if (!wearable_types.empty()) + { + AIAlert::add("AIXMLImportWearableTypeMismatch", args("[TYPE]", label)("[ARCHETYPENAME]", wearable_types)); } } @@ -593,7 +488,7 @@ void LLFloaterCustomize::onBtnExport() if (!is_modifiable) { // We should never get here, because in that case the Export button is disabled. - llwarns << "Cannot export current wearable \"" << name << "\" of type " << (int)edit_type << "because user lacks modify permissions." << llendl; + LL_WARNS() << "Cannot export current wearable \"" << name << "\" of type " << (int)edit_type << "because user lacks modify permissions." << LL_ENDL; return; } @@ -615,21 +510,24 @@ void LLFloaterCustomize::onBtnExport_continued(LLViewerWearable* edit_wearable, } std::string filename = filepicker->getFilename(); - LLSD args(LLSD::emptyMap()); - args["FILE"] = filename; - LLAPRFile outfile; - outfile.open(filename, LL_APR_WB); - if (!outfile.getFileHandle()) + bool success = false; + try { - llwarns << "Could not open \"" << filename << "\" for writing." << llendl; - LLNotificationsUtil::add("AIXMLExportWriteError", args); - return; + AIXMLLindenGenepool linden_genepool(filename); + linden_genepool.child(edit_wearable->getArchetype()); + + success = true; + } + catch (AIAlert::Error const& error) + { + AIAlert::add_modal("AIXMLExportWriteError", AIArgs("[FILE]", filename), error); } - LLVOAvatar::dumpArchetypeXML_header(outfile, edit_wearable->getTypeName()); - edit_wearable->archetypeExport(outfile); - LLVOAvatar::dumpArchetypeXML_footer(outfile); + if (success) + { + AIAlert::add_modal("AIXMLExportSuccess", AIArgs("[FILE]", filename)); + } } void LLFloaterCustomize::onBtnOk() @@ -639,9 +537,12 @@ void LLFloaterCustomize::onBtnOk() close(false); } -void LLFloaterCustomize::onBtnMakeOutfit() +void LLFloaterCustomize::onBtnMakeOutfit(const LLSD& val) { - new LLMakeOutfitDialog(true); // LLMakeOutfitDialog deletes itself. + if (val && LLAppearanceMgr::instance().isOutfitDirty()) // No use saving unless dirty + LLAppearanceMgr::instance().updateBaseOutfit(); + else + new LLMakeOutfitDialog(true); // LLMakeOutfitDialog deletes itself. } //////////////////////////////////////////////////////////////////////////// @@ -682,7 +583,14 @@ void LLFloaterCustomize::draw() // arrives. Figure out some way to avoid this if possible. updateInventoryUI(); - updateAvatarHeightDisplay(); + if (isAgentAvatarValid()) + { + F32 avatar_size = (gAgentAvatarp->mBodySize.mV[VZ]) + (F32)0.17; //mBodySize is actually quite a bit off. + mMetricHeight->setValue(llformat("%.2f", avatar_size) + "m"); + F32 feet = avatar_size / 0.3048; + F32 inches = (feet - (F32)((U32)feet)) * 12.0; + mImperialHeight->setValue(llformat("%d'%d\"", (U32)feet, (U32)inches)); + } LLScrollingPanelParam::sUpdateDelayFrames = 0; @@ -763,24 +671,11 @@ const S32 LINE_HEIGHT = 16; const S32 HEADER_PAD = 8; const S32 HEADER_HEIGHT = 3 * (LINE_HEIGHT + LLFLOATER_VPAD) + (2 * LLPANEL_BORDER_WIDTH) + HEADER_PAD; -void LLFloaterCustomize::initScrollingPanelList() -{ - LLScrollContainer* scroll_container = - getChild("panel_container"); - // LLScrollingPanelList's do not import correctly -// mScrollingPanelList = LLUICtrlFactory::getScrollingPanelList(this, "panel_list"); - mScrollingPanelList = new LLScrollingPanelList(std::string("panel_list"), LLRect()); - if (scroll_container) - { - scroll_container->setScrolledView(mScrollingPanelList); - scroll_container->addChild(mScrollingPanelList); - } -} - void LLFloaterCustomize::wearablesChanged(LLWearableType::EType type) { llassert( type < LLWearableType::WT_COUNT ); - gSavedSettings.setU32("AvatarSex", (gAgentAvatarp->getSex() == SEX_MALE) ); + if (type == LLWearableType::WT_SHAPE) + gSavedSettings.setU32("AvatarSex", (gAgentAvatarp->getSex() == SEX_MALE)); LLPanelEditWearable* panel = mWearablePanelList[ type ]; if( panel ) @@ -848,7 +743,7 @@ void LLFloaterCustomize::saveCurrentWearables() LLAppearanceMgr::instance().findCOFItemLinks(wearable->getItemID()); if (links.size()>0) { - link_item = links.get(0).get(); + link_item = links.at(0).get(); if (link_item && link_item->getIsLinkType()) { description = link_item->getActualDescription(); @@ -860,15 +755,11 @@ void LLFloaterCustomize::saveCurrentWearables() if (link_item) { // Create new link - link_inventory_item( gAgent.getID(), - link_item->getLinkedUUID(), + link_inventory_object( LLAppearanceMgr::instance().getCOF(), - link_item->getName(), - description, - LLAssetType::AT_LINK, - NULL); + link_item, NULL); // Remove old link - gInventory.purgeObject(link_item->getUUID()); + remove_inventory_object(link_item->getUUID(), NULL); } } gAgentWearables.saveWearable( cur, i ); @@ -971,11 +862,9 @@ void LLFloaterCustomize::updateInventoryUI() { panel->setUIPermissions(perm_mask, is_complete); } - //BOOL is_vis = panel && item && is_complete && (perm_mask & PERM_MODIFY); - //childSetVisible("panel_container", is_vis); } } - childSetEnabled("Make Outfit", all_complete); + mMakeOutfitBtn->setEnabled(all_complete); } diff --git a/indra/newview/llfloatercustomize.h b/indra/newview/llfloatercustomize.h index 3a7d099098..dfe669470f 100644 --- a/indra/newview/llfloatercustomize.h +++ b/indra/newview/llfloatercustomize.h @@ -69,10 +69,6 @@ class LLFloaterCustomize : public LLFloater, public LLSingleton mResetParams; LLInventoryObserver* mInventoryObserver; diff --git a/indra/newview/llfloaterdaycycle.cpp b/indra/newview/llfloaterdaycycle.cpp index 3cf67821f5..33ae1b35fc 100644 --- a/indra/newview/llfloaterdaycycle.cpp +++ b/indra/newview/llfloaterdaycycle.cpp @@ -59,6 +59,7 @@ #include "llwlparammanager.h" #include "llfloaterwindlight.h" +#include "rlvactions.h" LLFloaterDayCycle* LLFloaterDayCycle::sDayCycle = NULL; std::map LLFloaterDayCycle::sSliderToKey; @@ -277,6 +278,7 @@ bool LLFloaterDayCycle::isOpen() void LLFloaterDayCycle::show() { + if (RlvActions::hasBehaviour(RLV_BHVR_SETENV)) return; LLFloaterDayCycle* dayCycle = instance(); dayCycle->syncMenu(); syncSliderTrack(); diff --git a/indra/newview/llfloaterdestinations.cpp b/indra/newview/llfloaterdestinations.cpp new file mode 100644 index 0000000000..219df67ce5 --- /dev/null +++ b/indra/newview/llfloaterdestinations.cpp @@ -0,0 +1,77 @@ +/** + * @file llfloaterdestinations.h + * @author Leyla Farazha + * @brief floater for the destinations guide + * + * $LicenseInfo:firstyear=2011&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2011, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +/** + * Floater that appears when buying an object, giving a preview + * of its contents and their permissions. + */ + +#include "llviewerprecompiledheaders.h" + +#include "lfsimfeaturehandler.h" +#include "llfloaterdestinations.h" +#include "llmediactrl.h" +#include "lluictrlfactory.h" +#include "llweb.h" + + +LLFloaterDestinations::LLFloaterDestinations(const LLSD& key) + : LLFloater(key) +{ + LLUICtrlFactory::getInstance()->buildFloater(this, "floater_destinations.xml", NULL, false); +} + +LLFloaterDestinations::~LLFloaterDestinations() +{ +} + +BOOL LLFloaterDestinations::postBuild() +{ + enableResizeCtrls(true, true, false); + LLMediaCtrl* destinations = getChild("destination_guide_contents"); + if (destinations) + { + destinations->setErrorPageURL(gSavedSettings.getString("GenericErrorPageURL")); + std::string url = gSavedSettings.getString("DestinationGuideURL"); + changeURL(destinations, url); + LFSimFeatureHandler::instance().setDestinationGuideURLCallback(boost::bind(&LLFloaterDestinations::changeURL, this, destinations, _1)); + } + return TRUE; +} + +void LLFloaterDestinations::changeURL(LLMediaCtrl* destinations, const std::string& url) +{ + if (url.empty()) + { + close(); + return; + } + + destinations->navigateTo(LLWeb::expandURLSubstitutions(url, LLSD()), "text/html"); +} + + diff --git a/indra/newview/llfloaterdestinations.h b/indra/newview/llfloaterdestinations.h new file mode 100644 index 0000000000..619960a1c7 --- /dev/null +++ b/indra/newview/llfloaterdestinations.h @@ -0,0 +1,45 @@ +/** + * @file llfloaterdestinations.h + * @author Leyla Farazha + * @brief floater for the destinations guide + * + * $LicenseInfo:firstyear=2011&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2011, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_FLOATER_DESTINATIONS_H +#define LL_FLOATER_DESTINATIONS_H + +#include "llfloater.h" + +class LLFloaterDestinations : + public LLFloater +, public LLFloaterSingleton +{ + friend class LLUISingleton >; +private: + LLFloaterDestinations(const LLSD& key); + /*virtual*/ ~LLFloaterDestinations(); + /*virtual*/ BOOL postBuild(); + void changeURL(class LLMediaCtrl* destinations, const std::string& url); +}; + +#endif diff --git a/indra/newview/llfloaterdirectory.cpp b/indra/newview/llfloaterdirectory.cpp index 92daa4e2b7..a856e4d5f1 100644 --- a/indra/newview/llfloaterdirectory.cpp +++ b/indra/newview/llfloaterdirectory.cpp @@ -53,12 +53,25 @@ #include "lluictrlfactory.h" #include "hippogridmanager.h" -#include "llenvmanager.h" +#include "lfsimfeaturehandler.h" #include "llnotificationsutil.h" #include "llviewerregion.h" const char* market_panel = "market_panel"; +void set_tab_visible(LLTabContainer* container, LLPanel* tab, bool visible, LLPanel* prev_tab) +{ + if (visible) + { + if (prev_tab) + container->lockTabs(container->getIndexForPanel(prev_tab) + 1); + container->addTabPanel(tab, tab->getLabel(), false, 0, false, LLTabContainer::START); + if (prev_tab) + container->unlockTabs(); + } + else container->removeTabPanel(tab); +} + class LLPanelDirMarket : public LLPanelDirFind { public: @@ -93,13 +106,13 @@ class LLPanelDirMarket : public LLPanelDirFind { if (LLViewerRegion* region = gAgent.getRegion()) { - if (region->getFeaturesReceived()) + if (region->simulatorFeaturesReceived()) { setMarketplaceURL(container); } else { - region->setFeaturesReceivedCallback(boost::bind(&LLPanelDirMarket::setMarketplaceURL, this, container)); + region->setSimulatorFeaturesReceivedCallback(boost::bind(&LLPanelDirMarket::setMarketplaceURL, this, container)); } } } @@ -161,7 +174,9 @@ class LLPanelDirMarket : public LLPanelDirFind std::string mMarketplaceURL; }; -static void* createWebPanel(void* data) +namespace { + +void* createWebPanel(void* data) { struct LLPanelDirWeb : public LLPanelDirFind { @@ -175,6 +190,8 @@ static void* createWebPanel(void* data) return new LLPanelDirWeb(static_cast(data)); } +} // namespace + LLFloaterDirectory* LLFloaterDirectory::sInstance = NULL; //static S32 LLFloaterDirectory::sOldSearchCount = 0; // debug @@ -187,7 +204,6 @@ LLFloaterDirectory::LLFloaterDirectory(const std::string& name) { sInstance = this; - mFindAllPanel = NULL; mClassifiedPanel = NULL; mEventsPanel = NULL; mLandPanel = NULL; @@ -201,10 +217,7 @@ LLFloaterDirectory::LLFloaterDirectory(const std::string& name) mPanelClassifiedp = NULL; // Build the floater with our tab panel classes - - bool enableWebSearch = gHippoGridManager->getConnectedGrid()->isSecondLife() || - !gHippoGridManager->getConnectedGrid()->getSearchUrl().empty(); - bool enableClassicAllSearch = !gHippoGridManager->getConnectedGrid()->isSecondLife(); + bool secondlife = gHippoGridManager->getConnectedGrid()->isSecondLife(); LLCallbackMap::map_t factory_map; factory_map["classified_panel"] = LLCallbackMap(createClassified, this); @@ -214,15 +227,13 @@ LLFloaterDirectory::LLFloaterDirectory(const std::string& name) factory_map["people_panel"] = LLCallbackMap(createPeople, this); factory_map["groups_panel"] = LLCallbackMap(createGroups, this); factory_map[market_panel] = LLCallbackMap(LLPanelDirMarket::create, this); - if (enableWebSearch) + factory_map["find_all_panel"] = LLCallbackMap(createFindAll, this); + factory_map["showcase_panel"] = LLCallbackMap(createShowcase, this); + if (secondlife) { - // web search and showcase only for SecondLife - factory_map["find_all_panel"] = LLCallbackMap(createFindAll, this); - factory_map["showcase_panel"] = LLCallbackMap(createShowcase, this); - if (!enableClassicAllSearch) factory_map["web_panel"] = LLCallbackMap(createWebPanel, this); + factory_map["web_panel"] = LLCallbackMap(createWebPanel, this); } - - if (enableClassicAllSearch) + else { factory_map["find_all_old_panel"] = LLCallbackMap(createFindAllOld, this); } @@ -236,32 +247,42 @@ LLFloaterDirectory::LLFloaterDirectory(const std::string& name) factory_map["Panel Avatar"] = LLCallbackMap(createPanelAvatar, this); - if (enableWebSearch) - { - mCommitCallbackRegistrar.add("Search.WebFloater", boost::bind(&LLFloaterSearch::open, boost::bind(LLFloaterSearch::getInstance))); - if (enableClassicAllSearch) - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_directory3.xml", &factory_map); - else - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_directory.xml", &factory_map); - } - else - { - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_directory2.xml", &factory_map); - } + mCommitCallbackRegistrar.add("Search.WebFloater", boost::bind(&LLFloaterSearch::open, boost::bind(&LLFloaterSearch::getInstance))); + LLUICtrlFactory::getInstance()->buildFloater(this, "floater_directory.xml", &factory_map); moveResizeHandlesToFront(); - if(mPanelAvatarp) + if (mPanelAvatarp) { mPanelAvatarp->selectTab(0); } LLTabContainer* container = getChild("Directory Tabs"); - if (enableClassicAllSearch) + if (secondlife) + { + // Remove unused tabs + container->removeTabPanel(getChild("find_all_old_panel")); + LLPanel* p = getChild("find_all_panel"); + container->removeTabPanel(p); // This should be at the end + p->setLabel(p->getString("classic_label")); // Give it a special label + container->addTabPanel(p, p->getLabel()); + } + else { + container->removeTabPanel(getChild("web_panel")); // Not needed + LLPanel* panel(getChild("find_all_panel")); + LLPanel* prev_tab(getChild("find_all_old_panel")); + LFSimFeatureHandler& inst(LFSimFeatureHandler::instance()); + set_tab_visible(container, panel, !inst.searchURL().empty(), prev_tab); + inst.setSearchURLCallback(boost::bind(set_tab_visible, container, panel, !boost::bind(&std::string::empty, _1), prev_tab)); + panel = getChild("showcase_panel"); + prev_tab = getChild("events_panel"); + set_tab_visible(container, panel, !inst.destinationGuideURL().empty(), prev_tab); + inst.setDestinationGuideURLCallback(boost::bind(set_tab_visible, container, panel, !boost::bind(&std::string::empty, _1), prev_tab)); + LLPanelDirMarket* marketp = static_cast(container->getPanelByName(market_panel)); container->removeTabPanel(marketp); // Until we get a MarketPlace URL, tab is removed. marketp->handleRegionChange(container); - LLEnvManagerNew::instance().setRegionChangeCallback(boost::bind(&LLPanelDirMarket::handleRegionChange, marketp, container)); + gAgent.addRegionChangedCallback(boost::bind(&LLPanelDirMarket::handleRegionChange, marketp, container)); } container->setCommitCallback(boost::bind(&LLFloaterDirectory::onTabChanged,_2)); } @@ -288,9 +309,7 @@ LLFloaterDirectory::~LLFloaterDirectory() // static void *LLFloaterDirectory::createFindAll(void* userdata) { - LLFloaterDirectory *self = (LLFloaterDirectory*)userdata; - self->mFindAllPanel = LLPanelDirFindAllInterface::create(self); - return self->mFindAllPanel; + return LLPanelDirFindAllInterface::create(static_cast(userdata)); } // static @@ -357,7 +376,7 @@ void *LLFloaterDirectory::createFindAllOld(void* userdata) void* LLFloaterDirectory::createClassifiedDetail(void* userdata) { LLFloaterDirectory *self = (LLFloaterDirectory*)userdata; - self->mPanelClassifiedp = new LLPanelClassified(true, false); + self->mPanelClassifiedp = new LLPanelClassifiedInfo(true, false); self->mPanelClassifiedp->setVisible(FALSE); return self->mPanelClassifiedp; } @@ -435,13 +454,43 @@ void LLFloaterDirectory::requestClassifieds() } } -void LLFloaterDirectory::showFindAll(const std::string& search_text) +void LLFloaterDirectory::search(const LLFloaterSearch::SearchQuery& search) { - showPanel("find_all_panel"); - LLPanelDirFindAllInterface::search(sInstance->mFindAllPanel, search_text); + start(); + const std::string category(search.category()); + const std::string search_text(search.query); + if (category.empty()) + { + LLPanelDirFindAllInterface::search(sInstance, search); + performQueryOn2("classified_panel", search_text); + performQueryOn2("events_panel", search_text); + performQueryOn2("groups_panel", search_text); + performQueryOn2("people_panel", search_text); + performQueryOn2("places_panel", search_text); + } + else if (category == "all") + LLPanelDirFindAllInterface::search(sInstance, search, true); + else if (category == "people") + showPeople(search.query); + else if (category == "places") + showPlaces(search.query); + else if (category == "events") + showEvents(search.query); + else if (category == "groups") + showGroups(search.query); + /* Singu TODO: Wiki tab in secondlife legacy search floater? + else if (category == "wiki") + LLFloaterDirectory::showWiki(search.query);*/ + else if (category == "destinations") + showDestinations(); + else if (category == "classifieds") + showClassified(search.query); + else if (gHippoGridManager->getConnectedGrid()->isSecondLife()) + LLPanelDirFindAllInterface::search(sInstance, search, true); + else + LLNotificationsUtil::add("UnsupportedCommandSLURL"); // Singu Note: Perhaps we should use a special notification here? } - void LLFloaterDirectory::showClassified(const LLUUID& classified_id) { showPanel("classified_panel"); @@ -520,6 +569,12 @@ void LLFloaterDirectory::showPlaces(const std::string& search_text) void LLFloaterDirectory::performQueryOn(const std::string& name, const std::string& search_text) { showPanel(name); + performQueryOn2(name, search_text); +} + +//static +void LLFloaterDirectory::performQueryOn2(const std::string& name, const std::string& search_text) +{ if (search_text.empty()) return; // We're done here. LLPanelDirBrowser* panel = sInstance->getChild(name); panel->getChild("name")->setValue(search_text); @@ -548,7 +603,7 @@ void LLFloaterDirectory::focusCurrentPanel() } // static -void LLFloaterDirectory::showPanel(const std::string& tabname) +void LLFloaterDirectory::start() { // This function gets called when web browser clicks are processed, // so we don't delete the existing panel, which would delete the @@ -558,7 +613,13 @@ void LLFloaterDirectory::showPanel(const std::string& tabname) sInstance = new LLFloaterDirectory("directory"); } sInstance->open(); /*Flawfinder: ignore*/ - sInstance->childShowTab("Directory Tabs", tabname); +} + +// static +void LLFloaterDirectory::showPanel(const std::string& tabname) +{ + start(); + sInstance->findChild("Directory Tabs")->selectTabByName(tabname); sInstance->focusCurrentPanel(); } @@ -568,12 +629,16 @@ void LLFloaterDirectory::toggleFind(void*) if (!sInstance) { std::string panel = gSavedSettings.getString("LastFindPanel"); - bool hasWebSearch = gHippoGridManager->getConnectedGrid()->isSecondLife() || - !gHippoGridManager->getConnectedGrid()->getSearchUrl().empty(); - if (hasWebSearch && (panel == "find_all_panel" || panel == "showcase_panel")) + if (!gHippoGridManager->getConnectedGrid()->isSecondLife()) { - panel = "find_all_old_panel"; + LFSimFeatureHandler& inst(LFSimFeatureHandler::instance()); + if (panel == "web_panel" + || (inst.searchURL().empty() && panel == "find_all_panel") + || (inst.destinationGuideURL().empty() && panel == "showcase_panel")) + panel = "find_all_old_panel"; } + else if (panel == "find_all_old_panel") panel = "web_panel"; + showPanel(panel); // HACK: force query for today's events diff --git a/indra/newview/llfloaterdirectory.h b/indra/newview/llfloaterdirectory.h index b4cbf1f185..792c578d38 100644 --- a/indra/newview/llfloaterdirectory.h +++ b/indra/newview/llfloaterdirectory.h @@ -33,7 +33,7 @@ #ifndef LL_LLFLOATERDIRECTORY_H #define LL_LLFLOATERDIRECTORY_H -#include "llfloater.h" +#include "llfloatersearch.h" #include "lltabcontainer.h" class LLDirectoryCore; @@ -54,7 +54,7 @@ class LLPanelAvatar; class LLPanelEvent; class LLPanelGroup; class LLPanelPlace; -class LLPanelClassified; +class LLPanelClassifiedInfo; // Floater to find people, places, things class LLFloaterDirectory : public LLFloater @@ -71,7 +71,7 @@ class LLFloaterDirectory : public LLFloater // Outside UI widgets can spawn this floater with various tabs // selected. - static void showFindAll(const std::string& search_text); + static void search(const LLFloaterSearch::SearchQuery& search); static void showClassified(const LLUUID& classified_id); static void showClassified(const std::string& search_text = ""); static void showEvents(S32 event_id); @@ -92,6 +92,8 @@ class LLFloaterDirectory : public LLFloater private: static void performQueryOn(const std::string& name, const std::string& search_text); + static void performQueryOn2(const std::string& name, const std::string& search_text); + static void start(); static void showPanel(const std::string& tabname); /*virtual*/ void onClose(bool app_quitting); void focusCurrentPanel(); @@ -99,7 +101,6 @@ class LLFloaterDirectory : public LLFloater private: // Some special "showByID" functions use these cached pointers. // They could be replaced by getPanelByName(), perhaps. JC - LLPanelDirFindAll* mFindAllPanel; LLPanelDirClassified* mClassifiedPanel; LLPanelDirEvents* mEventsPanel; LLPanelDirLand* mLandPanel; @@ -131,7 +132,7 @@ class LLFloaterDirectory : public LLFloater LLPanel* mPanelGroupHolderp; LLPanelPlace* mPanelPlacep; LLPanelPlace* mPanelPlaceSmallp; - LLPanelClassified* mPanelClassifiedp; + LLPanelClassifiedInfo* mPanelClassifiedp; static S32 sOldSearchCount; // debug static S32 sNewSearchCount; // debug @@ -141,6 +142,4 @@ class LLFloaterDirectory : public LLFloater static LLFloaterDirectory *sInstance; }; -extern BOOL gDisplayEventHack; - #endif // LL_LLDIRECTORYFLOATER_H diff --git a/indra/newview/llfloaterdisplayname.cpp b/indra/newview/llfloaterdisplayname.cpp index a00cfb8bf7..4750f219e7 100644 --- a/indra/newview/llfloaterdisplayname.cpp +++ b/indra/newview/llfloaterdisplayname.cpp @@ -40,53 +40,12 @@ #include "llagent.h" -LLFloaterDisplayName* LLFloaterDisplayName::sInstance = NULL; - -LLFloaterDisplayName::LLFloaterDisplayName() +LLFloaterDisplayName::LLFloaterDisplayName(const LLSD&) : LLFloater(std::string("Display Names Floater")) { - LLFloaterDisplayName::sInstance = this; -} - -// virtual -LLFloaterDisplayName::~LLFloaterDisplayName() -{ - - LLFloaterDisplayName::sInstance = NULL; - -} - -BOOL LLFloaterDisplayName::postBuild() -{ - childSetAction("reset_btn", onReset, this); - childSetAction("cancel_btn", onCancel, this); - childSetAction("save_btn", onSave, this); - - center(); - - return TRUE; -} - -void LLFloaterDisplayName::show() -{ - if (LLFloaterDisplayName::sInstance) - { - LLFloaterDisplayName::sInstance->open(); /*Flawfinder: ignore*/ - return; - } - - - LLFloaterDisplayName *self = new LLFloaterDisplayName(); - - // Builds and adds to gFloaterView - LLUICtrlFactory::getInstance()->buildFloater(self, "floater_display_name.xml"); - - // Fix up rectangle - - self->open(); /*Flawfinder: ignore*/ + LLUICtrlFactory::getInstance()->buildFloater(this, "floater_display_name.xml"); } - void LLFloaterDisplayName::onOpen() { getChild("display_name_editor")->clear(); @@ -112,16 +71,10 @@ void LLFloaterDisplayName::onOpen() std::string hour = next_update_local.asString().substr(11,2); std::string minute = next_update_local.asString().substr(14,2); std::string second = next_update_local.asString().substr(17,2); - std::string next_update_string_date = - llformat("%s/%s/%s",year.c_str(),month.c_str(), - day.c_str()); - std::string next_update_string_time = - llformat("%s:%s:%s",hour.c_str(),minute.c_str(), - second.c_str()); - getChild("lockout_text")->setTextArg("[DATE]", - next_update_string_date); - getChild("lockout_text")->setTextArg("[TIME]", - next_update_string_time); + std::string next_update_string_date = llformat("%s/%s/%s",year.c_str(),month.c_str(), day.c_str()); + std::string next_update_string_time = llformat("%s:%s:%s",hour.c_str(),minute.c_str(), second.c_str()); + getChild("lockout_text")->setTextArg("[DATE]", next_update_string_date); + getChild("lockout_text")->setTextArg("[TIME]", next_update_string_time); getChild("lockout_text")->setVisible(true); getChild("save_btn")->setEnabled(false); getChild("display_name_editor")->setEnabled(false); @@ -139,6 +92,16 @@ void LLFloaterDisplayName::onOpen() } } +BOOL LLFloaterDisplayName::postBuild() +{ + getChild("reset_btn")->setCommitCallback(boost::bind(&LLFloaterDisplayName::onReset, this)); + getChild("cancel_btn")->setCommitCallback(boost::bind(&LLFloaterDisplayName::onCancel, this)); + getChild("save_btn")->setCommitCallback(boost::bind(&LLFloaterDisplayName::onSave, this)); + + center(); + + return TRUE; +} void LLFloaterDisplayName::onCacheSetName(bool success, const std::string& reason, @@ -151,23 +114,19 @@ void LLFloaterDisplayName::onCacheSetName(bool success, LLSD args; args["DISPLAY_NAME"] = content["display_name"]; LLNotificationsUtil::add("SetDisplayNameSuccess", args); - - // Re-fetch my name, as it may have been sanitized by the service - //LLAvatarNameCache::get(getAvatarId(), - // boost::bind(&LLPanelMyProfileEdit::onNameCache, this, _1, _2)); return; } // Request failed, notify the user std::string error_tag = content["error_tag"].asString(); - llinfos << "set name failure error_tag " << error_tag << llendl; + LL_INFOS() << "set name failure error_tag " << error_tag << LL_ENDL; // We might have a localized string for this message // error_args will usually be empty from the server. if (!error_tag.empty() && LLNotificationTemplates::getInstance()->templateExists(error_tag)) { - LLNotifications::instance().add(error_tag); + LLNotificationsUtil::add(error_tag); return; } @@ -186,34 +145,30 @@ void LLFloaterDisplayName::onCacheSetName(bool success, LLNotificationsUtil::add("SetDisplayNameFailedGeneric"); } -void LLFloaterDisplayName::onCancel(void* data) +void LLFloaterDisplayName::onCancel() { - LLFloaterDisplayName* self = (LLFloaterDisplayName*)data; - self->setVisible(false); + setVisible(false); } -void LLFloaterDisplayName::onReset(void* data) +void LLFloaterDisplayName::onReset() { - LLFloaterDisplayName* self = (LLFloaterDisplayName*)data; - if (LLAvatarNameCache::useDisplayNames()) + if (LLAvatarNameCache::hasNameLookupURL()) { - LLViewerDisplayName::set("", - boost::bind(&LLFloaterDisplayName::onCacheSetName, self, _1, _2, _3)); + LLViewerDisplayName::set("", boost::bind(&LLFloaterDisplayName::onCacheSetName, this, _1, _2, _3)); } else { LLNotificationsUtil::add("SetDisplayNameFailedGeneric"); } - self->setVisible(false); + setVisible(false); } -void LLFloaterDisplayName::onSave(void* data) +void LLFloaterDisplayName::onSave() { - LLFloaterDisplayName* self = (LLFloaterDisplayName*)data; - std::string display_name_utf8 = self->getChild("display_name_editor")->getValue().asString(); - std::string display_name_confirm = self->getChild("display_name_confirm")->getValue().asString(); + std::string display_name_utf8 = getChild("display_name_editor")->getValue().asString(); + std::string display_name_confirm = getChild("display_name_confirm")->getValue().asString(); if (display_name_utf8.compare(display_name_confirm)) { @@ -231,17 +186,16 @@ void LLFloaterDisplayName::onSave(void* data) return; } - if (LLAvatarNameCache::useDisplayNames()) + if (LLAvatarNameCache::hasNameLookupURL()) { - LLViewerDisplayName::set(display_name_utf8, - boost::bind(&LLFloaterDisplayName::onCacheSetName, self, _1, _2, _3)); + LLViewerDisplayName::set(display_name_utf8, boost::bind(&LLFloaterDisplayName::onCacheSetName, this, _1, _2, _3)); } else { LLNotificationsUtil::add("SetDisplayNameFailedGeneric"); } - self->setVisible(false); + setVisible(false); } diff --git a/indra/newview/llfloaterdisplayname.h b/indra/newview/llfloaterdisplayname.h index 2d6bbf1980..0e642706b2 100644 --- a/indra/newview/llfloaterdisplayname.h +++ b/indra/newview/llfloaterdisplayname.h @@ -28,24 +28,21 @@ class LLFloaterDisplayName : public LLFloater +, public LLFloaterSingleton { public: - LLFloaterDisplayName(); - virtual ~LLFloaterDisplayName(); + LLFloaterDisplayName(const LLSD&); + virtual ~LLFloaterDisplayName() { } /*virtual*/ BOOL postBuild(); - static void onSave(void* data); - static void onReset(void* data); - static void onCancel(void* data); - static void show(); + void onSave(); + void onReset(); + void onCancel(); /*virtual*/ void onOpen(); private: void onCacheSetName(bool success, const std::string& reason, const LLSD& content); -protected: - static LLFloaterDisplayName* sInstance; - }; diff --git a/indra/newview/llfloatereditui.cpp b/indra/newview/llfloatereditui.cpp index 0bc8fcc15d..2d7b42438f 100644 --- a/indra/newview/llfloatereditui.cpp +++ b/indra/newview/llfloatereditui.cpp @@ -164,7 +164,7 @@ LLFloaterEditUI::LLFloaterEditUI() spin = new LLSpinCtrl(std::string("width_spin"), LLRect(x, y+20, x+100, y), std::string("Width:"), LLFontGL::getFontSansSerifSmall(), - boost::bind(&LLFloaterEditUI::onCommitHeight,_1), + boost::bind(&LLFloaterEditUI::onCommitWidth,_1), 0.f, 2.f, 1000.f, diff --git a/indra/newview/llfloaterenvsettings.cpp b/indra/newview/llfloaterenvsettings.cpp index 57a9522448..3461b24615 100644 --- a/indra/newview/llfloaterenvsettings.cpp +++ b/indra/newview/llfloaterenvsettings.cpp @@ -50,6 +50,7 @@ #include "llviewerwindow.h" #include "pipeline.h" +#include "rlvactions.h" #include @@ -61,6 +62,7 @@ LLFloaterEnvSettings::LLFloaterEnvSettings() : LLFloater(std::string("Environmen // load it up initCallbacks(); + syncMenu(); } LLFloaterEnvSettings::~LLFloaterEnvSettings() @@ -98,14 +100,14 @@ void LLFloaterEnvSettings::initCallbacks(void) void LLFloaterEnvSettings::syncMenu() { LLSliderCtrl* sldr; - sldr = sEnvSettings->getChild("EnvTimeSlider"); + sldr = getChild("EnvTimeSlider"); // sync the clock F32 val = (F32)LLWLParamManager::getInstance()->mAnimator.getDayTime(); std::string timeStr = timeToString(val); LLTextBox* textBox; - textBox = sEnvSettings->getChild("EnvTimeText"); + textBox = getChild("EnvTimeText"); textBox->setValue(timeStr); @@ -124,7 +126,7 @@ void LLFloaterEnvSettings::syncMenu() LLWaterParamManager * param_mgr = LLWaterParamManager::getInstance(); // sync water params LLColor4 col = param_mgr->getFogColor(); - LLColorSwatchCtrl* colCtrl = sEnvSettings->getChild("EnvWaterColor"); + LLColorSwatchCtrl* colCtrl = getChild("EnvWaterColor"); col.mV[3] = 1.0f; colCtrl->set(col); @@ -139,7 +141,7 @@ void LLFloaterEnvSettings::syncMenu() childEnable("EnvUseEstateTimeButton"); } - if(!gPipeline.canUseVertexShaders()) + if (!LLGLSLShader::sNoFixedFunction) { childDisable("EnvWaterColor"); childDisable("EnvWaterColorText"); @@ -175,13 +177,17 @@ LLFloaterEnvSettings* LLFloaterEnvSettings::instance() if (!sEnvSettings) { sEnvSettings = new LLFloaterEnvSettings(); - sEnvSettings->open(); - sEnvSettings->setFocus(TRUE); } return sEnvSettings; } void LLFloaterEnvSettings::show() { + if (RlvActions::hasBehaviour(RLV_BHVR_SETENV)) return; + if (!sEnvSettings) // Liru TODO: Remove this when UI Overhaul merges, it will no longer be an issue. + { + sEnvSettings = new LLFloaterEnvSettings(); + return; // Will now be visible, don't change that. + } LLFloaterEnvSettings* envSettings = instance(); envSettings->syncMenu(); @@ -189,7 +195,10 @@ void LLFloaterEnvSettings::show() //LLUICtrlFactory::getInstance()->buildFloater(envSettings, "floater_env_settings.xml"); //envSettings->initCallbacks(); - envSettings->open(); + if (envSettings->getVisible()) + envSettings->close(); + else + envSettings->open(); } bool LLFloaterEnvSettings::isOpen() @@ -307,7 +316,7 @@ std::string LLFloaterEnvSettings::timeToString(F32 curTime) // get hours and minutes hours = (S32) (24.0 * curTime); curTime -= ((F32) hours / 24.0f); - min = llround(24.0f * 60.0f * curTime); + min = ll_round(24.0f * 60.0f * curTime); // handle case where it's 60 if(min == 60) diff --git a/indra/newview/llfloaterevent.cpp b/indra/newview/llfloaterevent.cpp index b526767f8f..ec863020c3 100644 --- a/indra/newview/llfloaterevent.cpp +++ b/indra/newview/llfloaterevent.cpp @@ -36,7 +36,6 @@ #include "llfloaterevent.h" // viewer project includes -#include "llcommandhandler.h" #include "llpanelevent.h" // linden library includes @@ -52,29 +51,6 @@ LLMap< U32, LLFloaterEventInfo* > gEventInfoInstances; -class LLEventHandler : public LLCommandHandler -{ -public: - // requires trusted browser to trigger - LLEventHandler() : LLCommandHandler("event", UNTRUSTED_THROTTLE) { } - bool handle(const LLSD& tokens, const LLSD& query_map, - LLMediaCtrl* web) - { - if (tokens.size() < 2) - { - return false; - } - U32 event_id = tokens[0].asInteger(); - if (tokens[1].asString() == "about") - { - LLFloaterEventInfo::show(event_id); - return true; - } - return false; - } -}; -LLEventHandler gEventHandler; - LLFloaterEventInfo::LLFloaterEventInfo(const std::string& name, const U32 event_id) : LLFloater(name), mEventID( event_id ) diff --git a/indra/newview/llfloaterexperiencepicker.cpp b/indra/newview/llfloaterexperiencepicker.cpp new file mode 100644 index 0000000000..7613001b33 --- /dev/null +++ b/indra/newview/llfloaterexperiencepicker.cpp @@ -0,0 +1,167 @@ +/** +* @file llfloaterexperiencepicker.cpp +* @brief Implementation of llfloaterexperiencepicker +* @author dolphin@lindenlab.com +* +* $LicenseInfo:firstyear=2014&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2014, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#include "llviewerprecompiledheaders.h" + +#include "llfloaterexperiencepicker.h" + + +#include "lllineeditor.h" +//#include "llfloaterreg.h" +#include "lluictrlfactory.h" +#include "llscrolllistctrl.h" +#include "llviewerregion.h" +#include "llagent.h" +#include "llexperiencecache.h" +#include "llslurl.h" +#include "llavatarnamecache.h" +#include "llfloaterexperienceprofile.h" +#include "llcombobox.h" +#include "llviewercontrol.h" +#include "lldraghandle.h" +#include "llpanelexperiencepicker.h" + +// +LLFloaterExperiencePicker* show_xp_picker(const LLSD& key) +{ + LLFloaterExperiencePicker* floater = + LLFloaterExperiencePicker::getInstance(key); + if (!floater) + { + floater = new LLFloaterExperiencePicker(key); + } + floater->open(); + return floater; +} +// + +LLFloaterExperiencePicker* LLFloaterExperiencePicker::show( select_callback_t callback, const LLUUID& key, BOOL allow_multiple, BOOL close_on_select, filter_list filters, LLView * frustumOrigin ) +{ + LLFloaterExperiencePicker* floater = show_xp_picker(key); + + if (floater->mSearchPanel) + { + floater->mSearchPanel->mSelectionCallback = callback; + floater->mSearchPanel->mCloseOnSelect = close_on_select; + floater->mSearchPanel->setAllowMultiple(allow_multiple); + floater->mSearchPanel->setDefaultFilters(); + floater->mSearchPanel->addFilters(filters.begin(), filters.end()); + floater->mSearchPanel->filterContent(); + } + + if(frustumOrigin) + { + floater->mFrustumOrigin = frustumOrigin->getHandle(); + } + + return floater; +} + +void LLFloaterExperiencePicker::drawFrustum() +{ + if(mFrustumOrigin.get()) + { + LLView * frustumOrigin = mFrustumOrigin.get(); + LLRect origin_rect; + frustumOrigin->localRectToOtherView(frustumOrigin->getLocalRect(), &origin_rect, this); + // draw context cone connecting color picker with color swatch in parent floater + LLRect local_rect = getLocalRect(); + if (hasFocus() && frustumOrigin->isInVisibleChain() && mContextConeOpacity > 0.001f) + { + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + LLGLEnable cull_face; + gGL.begin(LLRender::TRIANGLE_STRIP); + { + gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity); + gGL.vertex2i(local_rect.mLeft, local_rect.mTop); + gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity); + gGL.vertex2i(origin_rect.mLeft, origin_rect.mTop); + gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity); + gGL.vertex2i(local_rect.mRight, local_rect.mTop); + gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity); + gGL.vertex2i(origin_rect.mRight, origin_rect.mTop); + gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity); + gGL.vertex2i(local_rect.mRight, local_rect.mBottom); + gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity); + gGL.vertex2i(origin_rect.mRight, origin_rect.mBottom); + gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity); + gGL.vertex2i(local_rect.mLeft, local_rect.mBottom); + gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity); + gGL.vertex2i(origin_rect.mLeft, origin_rect.mBottom); + gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity); + gGL.vertex2i(local_rect.mLeft, local_rect.mTop); + gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity); + gGL.vertex2i(origin_rect.mLeft, origin_rect.mTop); + } + gGL.end(); + } + + if (gFocusMgr.childHasMouseCapture(getDragHandle())) + { + mContextConeOpacity = lerp(mContextConeOpacity, gSavedSettings.getF32("PickerContextOpacity"), LLCriticalDamp::getInterpolant(mContextConeFadeTime)); + } + else + { + mContextConeOpacity = lerp(mContextConeOpacity, 0.f, LLCriticalDamp::getInterpolant(mContextConeFadeTime)); + } + } +} + +void LLFloaterExperiencePicker::draw() +{ + drawFrustum(); + LLFloater::draw(); +} + +LLFloaterExperiencePicker::LLFloaterExperiencePicker( const LLSD& key ) + :LLFloater() + ,LLInstanceTracker(key.asUUID()) + ,mSearchPanel(nullptr) + ,mContextConeOpacity(0.f) + ,mContextConeInAlpha(0.f) + ,mContextConeOutAlpha(0.f) + ,mContextConeFadeTime(0.f) +{ + mContextConeInAlpha = gSavedSettings.getF32("ContextConeInAlpha"); + mContextConeOutAlpha = gSavedSettings.getF32("ContextConeOutAlpha"); + mContextConeFadeTime = gSavedSettings.getF32("ContextConeFadeTime"); + LLUICtrlFactory::getInstance()->buildFloater(this, "floater_experience_search.xml", NULL, false); + //buildFromFile("floater_experience_search.xml"); +} + +LLFloaterExperiencePicker::~LLFloaterExperiencePicker() +{ + gFocusMgr.releaseFocusIfNeeded( this ); +} + +BOOL LLFloaterExperiencePicker::postBuild() +{ + mSearchPanel = new LLPanelExperiencePicker(); + addChild(mSearchPanel); + mSearchPanel->setOrigin(0, 0); + return LLFloater::postBuild(); +} diff --git a/indra/newview/llfloaterexperiencepicker.h b/indra/newview/llfloaterexperiencepicker.h new file mode 100644 index 0000000000..4aff63169b --- /dev/null +++ b/indra/newview/llfloaterexperiencepicker.h @@ -0,0 +1,69 @@ +/** +* @file llfloaterexperiencepicker.h +* @brief Header file for llfloaterexperiencepicker +* @author dolphin@lindenlab.com +* +* $LicenseInfo:firstyear=2014&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2014, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ +#ifndef LL_LLFLOATEREXPERIENCEPICKER_H +#define LL_LLFLOATEREXPERIENCEPICKER_H + +#include "llfloater.h" +#include "llinstancetracker.h" + +class LLScrollListCtrl; +class LLLineEditor; +class LLPanelExperiencePicker; + + +class LLFloaterExperiencePicker : public LLFloater +, public LLInstanceTracker +{ +public: + + typedef std::function select_callback_t; + // filter function for experiences, return true if the experience should be hidden. + typedef std::function filter_function; + typedef std::vector filter_list; + + static LLFloaterExperiencePicker* show( select_callback_t callback, const LLUUID& key, BOOL allow_multiple, BOOL close_on_select, filter_list filters, LLView * frustumOrigin); + + LLFloaterExperiencePicker(const LLSD& key); + virtual ~LLFloaterExperiencePicker(); + + BOOL postBuild() override; + + void draw() override; +private: + + LLPanelExperiencePicker* mSearchPanel; + + void drawFrustum(); + LLHandle mFrustumOrigin; + F32 mContextConeOpacity; + F32 mContextConeInAlpha; + F32 mContextConeOutAlpha; + F32 mContextConeFadeTime; +}; + +#endif // LL_LLFLOATEREXPERIENCEPICKER_H + diff --git a/indra/newview/llfloaterexperienceprofile.cpp b/indra/newview/llfloaterexperienceprofile.cpp new file mode 100644 index 0000000000..3195a3bda9 --- /dev/null +++ b/indra/newview/llfloaterexperienceprofile.cpp @@ -0,0 +1,934 @@ +/** + * @file llfloaterexperienceprofile.cpp + * @brief llfloaterexperienceprofile and related class definitions + * + * $LicenseInfo:firstyear=2013&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2013, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + + +#include "llviewerprecompiledheaders.h" +#include "llfloaterexperienceprofile.h" + +#include "llagent.h" +#include "llappviewer.h" +#include "llavatarnamecache.h" +#include "llcheckboxctrl.h" +#include "llcombobox.h" +#include "llcommandhandler.h" +//#include "llexpandabletextbox.h" +#include "llexperiencecache.h" +//#include "llfloaterreg.h" +#include "llgroupactions.h" +#include "lluictrlfactory.h" +#include "lllayoutstack.h" +#include "lllineeditor.h" +#include "llnotificationsutil.h" +#include "llsdserialize.h" +#include "llslurl.h" +#include "lltabcontainer.h" +#include "lltextbox.h" +#include "lltexteditor.h" +#include "lltexturectrl.h" +#include "lltrans.h" +#include "llviewerregion.h" +#include "llevents.h" +#include "llfloatergroups.h" +#include "llnotifications.h" +#include "llfloaterreporter.h" +#include "llurlaction.h" + +#define XML_PANEL_EXPERIENCE_PROFILE "floater_experienceprofile.xml" +#define TF_NAME "experience_title" +#define TF_DESC "experience_description" +#define TF_SLURL "LocationTextText" +#define TF_MRKT "marketplace" +#define TF_MATURITY "ContentRatingText" +#define TF_OWNER "OwnerText" +#define TF_GROUP "GroupText" +#define TF_GRID_WIDE "grid_wide" +#define TF_PRIVILEGED "privileged" +#define EDIT "edit_" + +#define IMG_LOGO "logo" + +#define PNL_TOP "top panel" +#define PNL_IMAGE "image_panel" +#define PNL_DESC "description panel" +#define PNL_LOC "location panel" +#define PNL_MRKT "marketplace panel" +#define PNL_GROUP "group_panel" +#define PNL_PERMS "perm panel" + +#define BTN_ALLOW "allow_btn" +#define BTN_BLOCK "block_btn" +#define BTN_CANCEL "cancel_btn" +#define BTN_CLEAR_LOCATION "clear_btn" +#define BTN_EDIT "edit_btn" +#define BTN_ENABLE "enable_btn" +#define BTN_FORGET "forget_btn" +#define BTN_PRIVATE "private_btn" +#define BTN_REPORT "report_btn" +#define BTN_SAVE "save_btn" +#define BTN_SET_GROUP "Group_btn" +#define BTN_SET_LOCATION "location_btn" + + +class LLExperienceHandler : public LLCommandHandler +{ +public: + LLExperienceHandler() : LLCommandHandler("experience", UNTRUSTED_THROTTLE) { } + + bool handle(const LLSD& params, const LLSD& query_map, + LLMediaCtrl* web) override + { + if (params.size() != 2 || params[1].asString() != "profile") + return false; + + LLExperienceCache::instance().get(params[0].asUUID(), boost::bind(&LLExperienceHandler::experienceCallback, this, _1)); + return true; + } + + void experienceCallback(const LLSD& experienceDetails) + { + if (!experienceDetails.has(LLExperienceCache::MISSING)) + { + LLFloaterExperienceProfile::showInstance(experienceDetails[LLExperienceCache::EXPERIENCE_ID].asUUID()); + } + } +}; + +LLExperienceHandler gExperienceHandler; + +void LLFloaterExperienceProfile::showInstance(const LLSD& data) +{ + bool is_map = data.has("experience_id"); + LLFloaterExperienceProfile* floater = getInstance(is_map ? data["experience_id"].asUUID() : data.asUUID()); + if (!floater) floater = new LLFloaterExperienceProfile(data); + else if (is_map && data.has("edit_experience") && data["edit_experience"].asBoolean()) + floater->changeToEdit(); + floater->open(); +} + +LLFloaterExperienceProfile::LLFloaterExperienceProfile(const LLSD& data) + : LLFloater(), LLInstanceTracker(data.asUUID()) + , mSaveCompleteAction(NOTHING) + , mDirty(false) + , mForceClose(false) +{ + if (data.has("experience_id")) +{ + mExperienceId = data["experience_id"].asUUID(); + mPostEdit = data.has("edit_experience") && data["edit_experience"].asBoolean(); +} + else +{ + mExperienceId = data.asUUID(); + mPostEdit = false; + } + LLUICtrlFactory::getInstance()->buildFloater(this, XML_PANEL_EXPERIENCE_PROFILE, NULL, false); + //buildFromFile(XML_PANEL_EXPERIENCE_PROFILE); +} + + +LLFloaterExperienceProfile::~LLFloaterExperienceProfile() +{ + +} + +BOOL LLFloaterExperienceProfile::postBuild() +{ + + if (mExperienceId.notNull()) + { + LLExperienceCache::instance().fetch(mExperienceId, true); + LLExperienceCache::instance().get(mExperienceId, boost::bind(&LLFloaterExperienceProfile::experienceCallback, + getDerivedHandle(), _1)); + + LLViewerRegion* region = gAgent.getRegion(); + if (region) + { + LLExperienceCache::instance().getExperienceAdmin(mExperienceId, boost::bind( + &LLFloaterExperienceProfile::experienceIsAdmin, getDerivedHandle(), _1)); + } + } + + childSetAction(BTN_EDIT, boost::bind(&LLFloaterExperienceProfile::onClickEdit, this)); + childSetAction(BTN_ALLOW, boost::bind(&LLFloaterExperienceProfile::onClickPermission, this, "Allow")); + childSetAction(BTN_FORGET, boost::bind(&LLFloaterExperienceProfile::onClickForget, this)); + childSetAction(BTN_BLOCK, boost::bind(&LLFloaterExperienceProfile::onClickPermission, this, "Block")); + childSetAction(BTN_CANCEL, boost::bind(&LLFloaterExperienceProfile::onClickCancel, this)); + childSetAction(BTN_SAVE, boost::bind(&LLFloaterExperienceProfile::onClickSave, this)); + childSetAction(BTN_SET_LOCATION, boost::bind(&LLFloaterExperienceProfile::onClickLocation, this)); + childSetAction(BTN_CLEAR_LOCATION, boost::bind(&LLFloaterExperienceProfile::onClickClear, this)); + childSetAction(BTN_SET_GROUP, boost::bind(&LLFloaterExperienceProfile::onPickGroup, this)); + childSetAction(BTN_REPORT, boost::bind(&LLFloaterExperienceProfile::onReportExperience, this)); + + getChild(EDIT TF_DESC)->setKeystrokeCallback(boost::bind(&LLFloaterExperienceProfile::onFieldChanged, this)); + getChild(EDIT TF_MATURITY)->setCommitCallback(boost::bind(&LLFloaterExperienceProfile::onFieldChanged, this)); + getChild(EDIT TF_MRKT)->setKeystrokeCallback(boost::bind(&LLFloaterExperienceProfile::onFieldChanged, this)); + getChild(EDIT TF_NAME)->setKeystrokeCallback(boost::bind(&LLFloaterExperienceProfile::onFieldChanged, this)); + + childSetCommitCallback(EDIT BTN_ENABLE, boost::bind(&LLFloaterExperienceProfile::onFieldChanged, this), nullptr); + childSetCommitCallback(EDIT BTN_PRIVATE, boost::bind(&LLFloaterExperienceProfile::onFieldChanged, this), nullptr); + + childSetCommitCallback(EDIT IMG_LOGO, boost::bind(&LLFloaterExperienceProfile::onFieldChanged, this), nullptr); + + if (auto logo = findChild(IMG_LOGO)) + { + void show_picture(const LLUUID& id, const std::string& name); + LLTextBox* name = getChild(TF_NAME); + std::function cb = [logo, name]() { show_picture(logo->getImageAssetID(), "Experience Picture: " + name->getText()); }; + logo->setMouseUpCallback(boost::bind(cb)); + } + + getChild(EDIT TF_DESC)->setCommitOnFocusLost(TRUE); + + LLEventPumps::instance().obtain("experience_permission").listen(mExperienceId.asString()+"-profile", + boost::bind(&LLFloaterExperienceProfile::experiencePermission, getDerivedHandle(this), _1)); + + if (mPostEdit && mExperienceId.notNull()) + { + mPostEdit = false; + changeToEdit(); + } + + return TRUE; +} + +void LLFloaterExperienceProfile::experienceCallback(LLHandle handle, const LLSD& experience ) +{ + LLFloaterExperienceProfile* pllpep = handle.get(); + if (pllpep) + { + pllpep->refreshExperience(experience); + } +} + + +bool LLFloaterExperienceProfile::experiencePermission( LLHandle handle, const LLSD& permission ) +{ + LLFloaterExperienceProfile* pllpep = handle.get(); + if (pllpep) + { + pllpep->updatePermission(permission); + } + return false; +} + + +void LLFloaterExperienceProfile::onClickEdit() +{ + changeToEdit(); +} + + +void LLFloaterExperienceProfile::onClickCancel() +{ + changeToView(); +} + +void LLFloaterExperienceProfile::onClickSave() +{ + doSave(NOTHING); +} + +void LLFloaterExperienceProfile::onClickPermission(const char* perm) +{ + LLViewerRegion* region = gAgent.getRegion(); + if (!region) + return; + LLExperienceCache::instance().setExperiencePermission(mExperienceId, perm, boost::bind( + &LLFloaterExperienceProfile::experiencePermissionResults, mExperienceId, _1)); +} + + +void LLFloaterExperienceProfile::onClickForget() +{ + LLViewerRegion* region = gAgent.getRegion(); + if (!region) + return; + + LLExperienceCache::instance().forgetExperiencePermission(mExperienceId, boost::bind( + &LLFloaterExperienceProfile::experiencePermissionResults, mExperienceId, _1)); +} + +bool LLFloaterExperienceProfile::setMaturityString( U8 maturity, LLTextBox* child, LLComboBox* combo ) +{ + //LLStyle::Params style; // Singu Note: Nope. + std::string access; + if (maturity <= SIM_ACCESS_PG) + { + //style.image(LLUI::getUIImage(getString("maturity_icon_general"))); // Singu Note: Nope. + access = LLTrans::getString("SIM_ACCESS_PG"); + combo->setCurrentByIndex(2); + } + else if (maturity <= SIM_ACCESS_MATURE) + { + //style.image(LLUI::getUIImage(getString("maturity_icon_moderate"))); // Singu Note: Nope. + access = LLTrans::getString("SIM_ACCESS_MATURE"); + combo->setCurrentByIndex(1); + } + else if (maturity <= SIM_ACCESS_ADULT) + { + //style.image(LLUI::getUIImage(getString("maturity_icon_adult"))); // Singu Note: Nope. + access = LLTrans::getString("SIM_ACCESS_ADULT"); + combo->setCurrentByIndex(0); + } + else + { + return false; + } + + /* Singu Note: Nope. + child->setText(LLStringUtil::null); + + child->appendImageSegment(style); + */ + child->setText(access); + + return true; +} + + +void LLFloaterExperienceProfile::refreshExperience( const LLSD& experience ) +{ + mExperienceDetails = experience; + mPackage = experience; + + + LLLayoutPanel* imagePanel = getChild(PNL_IMAGE); + LLLayoutPanel* descriptionPanel = getChild(PNL_DESC); + LLLayoutPanel* locationPanel = getChild(PNL_LOC); + LLLayoutPanel* marketplacePanel = getChild(PNL_MRKT); + LLLayoutPanel* topPanel = getChild(PNL_TOP); + + + imagePanel->setVisible(FALSE); + descriptionPanel->setVisible(FALSE); + locationPanel->setVisible(FALSE); + marketplacePanel->setVisible(FALSE); + topPanel->setVisible(FALSE); + + + LLTextBox* child = getChild(TF_NAME); + //child->setText(experience[LLExperienceCache::NAME].asString()); + child->setValue(experience[LLExperienceCache::EXPERIENCE_ID].asUUID()); + + LLLineEditor* linechild = getChild(EDIT TF_NAME); + linechild->setText(experience[LLExperienceCache::NAME].asString()); + + std::string value = experience[LLExperienceCache::DESCRIPTION].asString(); + LLTextEditor* exchild = getChild(TF_DESC); + exchild->setText(value); + descriptionPanel->setVisible(value.length()>0); + + LLTextEditor* edit_child = getChild(EDIT TF_DESC); + edit_child->setText(value); + + mLocationSLURL = experience[LLExperienceCache::SLURL].asString(); + edit_child = getChild(TF_SLURL); + bool has_slurl = !mLocationSLURL.empty() && mLocationSLURL != "last"; + locationPanel->setVisible(has_slurl); + if (has_slurl) mLocationSLURL = LLSLURL(mLocationSLURL).getSLURLString(); + edit_child->setText(mLocationSLURL); + + + edit_child = getChild(EDIT TF_SLURL); + if (has_slurl) + { + edit_child->setText(mLocationSLURL); + } + else + { + edit_child->setText(getString("empty_slurl")); + } + + setMaturityString((U8)(experience[LLExperienceCache::MATURITY].asInteger()), getChild(TF_MATURITY), getChild(EDIT TF_MATURITY)); + + LLUUID agent_id = experience[LLExperienceCache::AGENT_ID].asUUID(); + getChild(TF_OWNER)->setValue(agent_id); + + LLUUID id = experience[LLExperienceCache::GROUP_ID].asUUID(); + bool id_null = id.isNull(); + if (!id_null) + { + getChild(TF_GROUP)->setValue(id); + } + getChild(PNL_GROUP)->setVisible(!id_null); + + setEditGroup(id); + + getChild(BTN_SET_GROUP)->setEnabled(agent_id == gAgentID); + + LLCheckBoxCtrl* enable = getChild(EDIT BTN_ENABLE); + S32 properties = mExperienceDetails[LLExperienceCache::PROPERTIES].asInteger(); + enable->set(!(properties & LLExperienceCache::PROPERTY_DISABLED)); + + enable = getChild(EDIT BTN_PRIVATE); + enable->set(properties & LLExperienceCache::PROPERTY_PRIVATE); + + topPanel->setVisible(TRUE); + child=getChild(TF_GRID_WIDE); + child->setVisible(TRUE); + + if(properties & LLExperienceCache::PROPERTY_GRID) + { + child->setText(LLTrans::getString("Grid-Scope")); + } + else + { + child->setText(LLTrans::getString("Land-Scope")); + } + + if (getChild(BTN_EDIT)->getVisible()) + { + topPanel->setVisible(TRUE); + } + + if (properties & LLExperienceCache::PROPERTY_PRIVILEGED) + { + child = getChild(TF_PRIVILEGED); + child->setVisible(TRUE); + } + else + { + LLViewerRegion* region = gAgent.getRegion(); + if (region) + { + LLExperienceCache::instance().getExperiencePermission(mExperienceId, boost::bind( + &LLFloaterExperienceProfile::experiencePermissionResults, mExperienceId, _1)); + } + } + + value=experience[LLExperienceCache::METADATA].asString(); + if (value.empty()) + return; + + LLPointer parser = new LLSDXMLParser(); + + LLSD data; + + std::istringstream is(value); + if (LLSDParser::PARSE_FAILURE != parser->parse(is, data, value.size())) + { + value.clear(); + if (data.has(TF_MRKT)) + { + value=data[TF_MRKT].asString(); + + edit_child = getChild(TF_MRKT); + edit_child->setText(value); + if(!value.empty()) + { + marketplacePanel->setVisible(TRUE); + } + else + { + marketplacePanel->setVisible(FALSE); + } + } + else + { + marketplacePanel->setVisible(FALSE); + } + + linechild = getChild(EDIT TF_MRKT); + linechild->setText(value); + + if (data.has(IMG_LOGO)) + { + LLTextureCtrl* logo = getChild(IMG_LOGO); + + LLUUID id = data[IMG_LOGO].asUUID(); + logo->setImageAssetID(id); + imagePanel->setVisible(TRUE); + + logo = getChild(EDIT IMG_LOGO); + logo->setImageAssetID(data[IMG_LOGO].asUUID()); + + imagePanel->setVisible(id.notNull()); + } + } + else + { + marketplacePanel->setVisible(FALSE); + imagePanel->setVisible(FALSE); + } + + mDirty=false; + mForceClose = false; + getChild(BTN_SAVE)->setEnabled(mDirty); +} + +void LLFloaterExperienceProfile::setPreferences( const LLSD& content ) +{ + S32 properties = mExperienceDetails[LLExperienceCache::PROPERTIES].asInteger(); + if (properties & LLExperienceCache::PROPERTY_PRIVILEGED) + { + return; + } + + const LLSD& experiences = content["experiences"]; + const LLSD& blocked = content["blocked"]; + + + for(const auto& exp : experiences.array()) + { + if (exp.asUUID()==mExperienceId) + { + experienceAllowed(); + return; + } + } + + for(const auto& exp : blocked.array()) + { + if (exp.asUUID()==mExperienceId) + { + experienceBlocked(); + return; + } + } + + experienceForgotten(); +} + +void LLFloaterExperienceProfile::onFieldChanged() +{ + updatePackage(); + + if (!getChild(BTN_EDIT)->getVisible()) + { + return; + } + + mDirty = mPackage.size() != mExperienceDetails.size(); + if (!mDirty) + { + LLSD::map_const_iterator st = mExperienceDetails.beginMap(); + LLSD::map_const_iterator dt = mPackage.beginMap(); + LLSD::map_const_iterator ste = mExperienceDetails.endMap(); + LLSD::map_const_iterator dte = mPackage.endMap(); + for (; st != ste && dt != dte; ++st, ++dt) + if (mDirty = st->first != dt->first || st->second.asString() != dt->second.asString()) + break; + } + + getChild(BTN_SAVE)->setEnabled(mDirty); +} + + +BOOL LLFloaterExperienceProfile::canClose() +{ + if (mForceClose || !mDirty) + { + return TRUE; + } + else + { + // Bring up view-modal dialog: Save changes? Yes, No, Cancel + LLNotificationsUtil::add("SaveChanges", LLSD(), LLSD(), boost::bind(&LLFloaterExperienceProfile::handleSaveChangesDialog, this, _1, _2, CLOSE)); + return FALSE; + } +} + +bool LLFloaterExperienceProfile::handleSaveChangesDialog( const LLSD& notification, const LLSD& response, PostSaveAction action ) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + switch( option ) + { + case 0: // "Yes" + // close after saving + doSave( action ); + break; + + case 1: // "No" + if (action != NOTHING) + { + mForceClose = TRUE; + if (action==CLOSE) + { + close(); + } + else + { + changeToView(); + } + } + break; + + case 2: // "Cancel" + default: + // If we were quitting, we didn't really mean it. + LLAppViewer::instance()->abortQuit(); + break; + } + return false; +} + +void LLFloaterExperienceProfile::doSave( int success_action ) +{ + mSaveCompleteAction=success_action; + + LLViewerRegion* region = gAgent.getRegion(); + if (!region) + return; + + LLExperienceCache::instance().updateExperience(mPackage, boost::bind( + &LLFloaterExperienceProfile::experienceUpdateResult, + getDerivedHandle(), _1)); +} + +void LLFloaterExperienceProfile::onSaveComplete( const LLSD& content ) +{ + LLUUID id = getExperienceId(); + + if (content.has("removed")) + { + const LLSD& removed = content["removed"]; + for(const auto& it : removed.map()) + { + const std::string& field = it.first; + if (field == LLExperienceCache::EXPERIENCE_ID) + { + //this message should be removed by the experience api + continue; + } + const LLSD& data = it.second; + std::string error_tag = data["error_tag"].asString()+ "ExperienceProfileMessage"; + LLSD fields; + if (LLNotificationTemplates::instance().templateExists(error_tag)) + { + fields["field"] = field; + fields["extra_info"] = data["extra_info"]; + LLNotificationsUtil::add(error_tag, fields); + } + else + { + fields["MESSAGE"] = data["en"]; + LLNotificationsUtil::add("GenericAlert", fields); + } + } + } + + if (!content.has("experience_keys")) + { + LL_WARNS() << "LLFloaterExperienceProfile::onSaveComplete called with bad content" << LL_ENDL; + return; + } + + const LLSD& experiences = content["experience_keys"]; + + if (experiences.size() == 0) + { + LL_WARNS() << "LLFloaterExperienceProfile::onSaveComplete called with empty content" << LL_ENDL; + return; + } + + const auto& exp = experiences[0]; + if (!exp.has(LLExperienceCache::EXPERIENCE_ID) || (exp[LLExperienceCache::EXPERIENCE_ID].asUUID() != id)) + { + LL_WARNS() << "LLFloaterExperienceProfile::onSaveComplete called with unexpected experience id" << LL_ENDL; + return; + } + + refreshExperience(exp); + LLExperienceCache::instance().insert(exp); + LLExperienceCache::instance().fetch(id, true); + + if (mSaveCompleteAction == VIEW) + { + LLTabContainer* tabs = getChild("tab_container"); + tabs->selectTabByName("panel_experience_info"); + } + else if (mSaveCompleteAction == CLOSE) + { + close(); + } +} + +void LLFloaterExperienceProfile::changeToView() +{ + if (mForceClose || !mDirty) + { + refreshExperience(mExperienceDetails); + LLTabContainer* tabs = getChild("tab_container"); + + tabs->selectTabByName("panel_experience_info"); + } + else + { + // Bring up view-modal dialog: Save changes? Yes, No, Cancel + LLNotificationsUtil::add("SaveChanges", LLSD(), LLSD(), boost::bind(&LLFloaterExperienceProfile::handleSaveChangesDialog, this, _1, _2, VIEW)); + } +} + +void LLFloaterExperienceProfile::changeToEdit() +{ + LLTabContainer* tabs = getChild("tab_container"); + + tabs->selectTabByName("edit_panel_experience_info"); +} + +void LLFloaterExperienceProfile::onClickLocation() +{ + LLViewerRegion* region = gAgent.getRegion(); + if (region) + { + auto child = getChild(EDIT TF_SLURL); + mLocationSLURL = LLSLURL(region->getName(), gAgent.getPositionGlobal()).getSLURLString(); + child->setText(mLocationSLURL); + onFieldChanged(); + } +} + +void LLFloaterExperienceProfile::onClickClear() +{ + auto child = getChild(EDIT TF_SLURL); + mLocationSLURL.clear(); + child->setText(getString("empty_slurl")); + onFieldChanged(); +} + +void LLFloaterExperienceProfile::updatePermission(const LLSD& permission) +{ + if (permission.has("experience")) + { + if (permission["experience"].asUUID() != mExperienceId) + { + return; + } + + std::string str = permission[mExperienceId.asString()]["permission"].asString(); + if (str == "Allow") + { + experienceAllowed(); + } + else if (str == "Block") + { + experienceBlocked(); + } + else if (str == "Forget") + { + experienceForgotten(); + } + } + else + { + setPreferences(permission); + } +} + +void LLFloaterExperienceProfile::experienceAllowed() +{ + LLButton* button=getChild(BTN_ALLOW); + button->setEnabled(FALSE); + + button=getChild(BTN_FORGET); + button->setEnabled(TRUE); + + button=getChild(BTN_BLOCK); + button->setEnabled(TRUE); +} + +void LLFloaterExperienceProfile::experienceForgotten() +{ + LLButton* button=getChild(BTN_ALLOW); + button->setEnabled(TRUE); + + button=getChild(BTN_FORGET); + button->setEnabled(FALSE); + + button=getChild(BTN_BLOCK); + button->setEnabled(TRUE); +} + +void LLFloaterExperienceProfile::experienceBlocked() +{ + LLButton* button=getChild(BTN_ALLOW); + button->setEnabled(TRUE); + + button=getChild(BTN_FORGET); + button->setEnabled(TRUE); + + button=getChild(BTN_BLOCK); + button->setEnabled(FALSE); +} + +void LLFloaterExperienceProfile::onClose( bool app_quitting ) +{ + LLEventPumps::instance().obtain("experience_permission").stopListening(mExperienceId.asString()+"-profile"); + LLFloater::onClose(app_quitting); +} + +void LLFloaterExperienceProfile::updatePackage() +{ + mPackage[LLExperienceCache::NAME] = getChild(EDIT TF_NAME)->getText(); + mPackage[LLExperienceCache::DESCRIPTION] = getChild(EDIT TF_DESC)->getText(); + if (mLocationSLURL.empty()) + { + mPackage[LLExperienceCache::SLURL] = LLStringUtil::null; + } + else + { + mPackage[LLExperienceCache::SLURL] = mLocationSLURL; + } + + mPackage[LLExperienceCache::MATURITY] = getChild(EDIT TF_MATURITY)->getSelectedValue().asInteger(); + + LLSD metadata; + + metadata[TF_MRKT] = getChild(EDIT TF_MRKT)->getText(); + metadata[IMG_LOGO] = getChild(EDIT IMG_LOGO)->getImageAssetID(); + + LLPointer formatter = new LLSDXMLFormatter(); + + std::ostringstream os; + if (formatter->format(metadata, os)) + { + mPackage[LLExperienceCache::METADATA] = os.str(); + } + + int properties = mPackage[LLExperienceCache::PROPERTIES].asInteger(); + LLCheckBoxCtrl* enable = getChild(EDIT BTN_ENABLE); + if (enable->get()) + { + properties &= ~LLExperienceCache::PROPERTY_DISABLED; + } + else + { + properties |= LLExperienceCache::PROPERTY_DISABLED; + } + + enable = getChild(EDIT BTN_PRIVATE); + if (enable->get()) + { + properties |= LLExperienceCache::PROPERTY_PRIVATE; + } + else + { + properties &= ~LLExperienceCache::PROPERTY_PRIVATE; + } + + mPackage[LLExperienceCache::PROPERTIES] = properties; +} + +void LLFloaterExperienceProfile::onPickGroup() +{ + LLFloater* parent_floater = gFloaterView->getParentFloater(this); + + LLFloaterGroupPicker* widget = LLFloaterGroupPicker::showInstance(gAgent.getID()); + if (widget) + { + widget->setSelectGroupCallback(boost::bind(&LLFloaterExperienceProfile::setEditGroup, this, _1)); + if (parent_floater) + { + LLRect new_rect = gFloaterView->findNeighboringPosition(parent_floater, widget); + widget->setOrigin(new_rect.mLeft, new_rect.mBottom); + parent_floater->addDependentFloater(widget); + } + } +} + +void LLFloaterExperienceProfile::setEditGroup( LLUUID group_id ) +{ + LLTextBox* child = getChild(EDIT TF_GROUP); + child->setValue(group_id); + mPackage[LLExperienceCache::GROUP_ID] = group_id; + onFieldChanged(); +} + +void LLFloaterExperienceProfile::onReportExperience() +{ + LLFloaterReporter::showFromExperience(mExperienceId); +} + +/*static*/ +bool LLFloaterExperienceProfile::hasPermission(const LLSD& content, const std::string &name, const LLUUID &test) +{ + if (!content.has(name)) + return false; + + const LLSD& list = content[name]; + for (const auto& it : list.array()) + { + if (it.asUUID() == test) + { + return true; + } + } + return false; +} + +/*static*/ +void LLFloaterExperienceProfile::experiencePermissionResults(const LLUUID& exprienceId, const LLSD& result) +{ + std::string permission("Forget"); + if (hasPermission(result, "experiences", exprienceId)) + permission = "Allow"; + else if (hasPermission(result, "blocked", exprienceId)) + permission = "Block"; + + LLSD experience; + LLSD message; + experience["permission"] = permission; + message["experience"] = exprienceId; + message[exprienceId.asString()] = experience; + + LLEventPumps::instance().obtain("experience_permission").post(message); +} + +/*static*/ +void LLFloaterExperienceProfile::experienceIsAdmin(LLHandle handle, const LLSD &result) +{ + LLFloaterExperienceProfile* parent = handle.get(); + if (!parent) + return; + + bool enabled = true; + LLViewerRegion* region = gAgent.getRegion(); + if (!region) + { + enabled = false; + } + else + { + std::string url = region->getCapability("UpdateExperience"); + if (url.empty()) + enabled = false; + } + if (enabled && result["status"].asBoolean()) + { + parent->getChild(PNL_TOP)->setVisible(TRUE); + parent->getChild(BTN_EDIT)->setVisible(TRUE); + } +} + +/*static*/ +void LLFloaterExperienceProfile::experienceUpdateResult(LLHandle handle, const LLSD &result) +{ + LLFloaterExperienceProfile* parent = handle.get(); + if (parent) + { + parent->onSaveComplete(result); + } +} diff --git a/indra/newview/llfloaterexperienceprofile.h b/indra/newview/llfloaterexperienceprofile.h new file mode 100644 index 0000000000..d9dad7784e --- /dev/null +++ b/indra/newview/llfloaterexperienceprofile.h @@ -0,0 +1,113 @@ +/** + * @file llfloaterexperienceprofile.h + * @brief llfloaterexperienceprofile and related class definitions + * + * $LicenseInfo:firstyear=2013&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2013, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + + + +#ifndef LL_LLFLOATEREXPERIENCEPROFILE_H +#define LL_LLFLOATEREXPERIENCEPROFILE_H + +#include "llfloater.h" +#include "lluuid.h" +#include "llsd.h" + +class LLLayoutPanel; +class LLTextBox; +class LLComboBox; + +class LLFloaterExperienceProfile final : public LLFloater +, public LLInstanceTracker +{ + LOG_CLASS(LLFloaterExperienceProfile); +public: + enum PostSaveAction + { + NOTHING, + CLOSE, + VIEW, + }; + + static void experiencePermissionResults(const LLUUID& exprienceId, const LLSD& result); + + static void showInstance(const LLSD& data); + LLFloaterExperienceProfile(const LLSD& data); + virtual ~LLFloaterExperienceProfile(); + + LLUUID getExperienceId() const { return mExperienceId; } + void setPreferences( const LLSD& content ); + + + void refreshExperience(const LLSD& experience); + void onSaveComplete( const LLSD& content ); + BOOL canClose() override; + + void onClose(bool app_quitting) override; +protected: + void onClickEdit(); + void onClickPermission(const char* permission); + void onClickForget(); + void onClickCancel(); + void onClickSave(); + void onClickLocation(); + void onClickClear(); + void onPickGroup(); + void onFieldChanged(); + void onReportExperience(); + + void setEditGroup(LLUUID group_id); + + void changeToView(); + void changeToEdit(); + + void experienceForgotten(); + void experienceBlocked(); + void experienceAllowed(); + + static void experienceCallback(LLHandle handle, const LLSD& experience); + static bool experiencePermission(LLHandle handle, const LLSD& permission); + + BOOL postBuild() override; + bool setMaturityString(U8 maturity, LLTextBox* child, LLComboBox* combo); + bool handleSaveChangesDialog(const LLSD& notification, const LLSD& response, PostSaveAction action); + void doSave( int success_action ); + + void updatePackage(); + + void updatePermission( const LLSD& permission ); + LLUUID mExperienceId; + LLSD mExperienceDetails; + LLSD mPackage; + std::string mLocationSLURL; + int mSaveCompleteAction; + bool mDirty; + bool mForceClose; + bool mPostEdit; // edit experience after opening and updating it +private: + static bool hasPermission(const LLSD& content, const std::string &name, const LLUUID &test); + static void experienceIsAdmin(LLHandle handle, const LLSD &result); + static void experienceUpdateResult(LLHandle handle, const LLSD &result); +}; + +#endif // LL_LLFLOATEREXPERIENCEPROFILE_H diff --git a/indra/newview/llfloaterexperiences.cpp b/indra/newview/llfloaterexperiences.cpp new file mode 100644 index 0000000000..395b094706 --- /dev/null +++ b/indra/newview/llfloaterexperiences.cpp @@ -0,0 +1,377 @@ +/** + * @file llfloaterexperiences.cpp + * @brief LLFloaterExperiences class implementation + * + * $LicenseInfo:firstyear=2012&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llfloaterexperiences.h" + +#include "llagent.h" +#include "llcororesponder.h" +#include "llevents.h" +#include "llexperiencecache.h" +#include "llfloaterexperienceprofile.h" +#include "llfloaterregioninfo.h" +#include "llnotificationsutil.h" +#include "llpanelexperiencelog.h" +#include "llpanelexperiencepicker.h" +#include "llpanelexperiences.h" +#include "lltabcontainer.h" +#include "lltrans.h" +#include "lluictrlfactory.h" +#include "llviewerregion.h" + + +#define SHOW_RECENT_TAB (0) +LLFloaterExperiences::LLFloaterExperiences(const LLSD& data) + :LLFloater(data) +{ + LLUICtrlFactory::getInstance()->buildFloater(this, "floater_experiences.xml", NULL, false); + //buildFromFile("floater_experiences.xml"); +} + +LLPanelExperiences* LLFloaterExperiences::addTab(const std::string& name, bool select) +{ + LLPanelExperiences* newPanel = LLPanelExperiences::create(name); + getChild("xp_tabs")->addTabPanel( + newPanel, + LLTrans::getString(name), + select); + + return newPanel; +} + +BOOL LLFloaterExperiences::postBuild() +{ + LLPanel* panel = new LLPanelExperiencePicker(); + getChild("xp_tabs")->addTabPanel(panel, panel->getLabel()); + addTab("Allowed_Experiences_Tab", true); + addTab("Blocked_Experiences_Tab", false); + addTab("Admin_Experiences_Tab", false); + addTab("Contrib_Experiences_Tab", false); + LLPanelExperiences* owned = addTab("Owned_Experiences_Tab", false); + owned->setButtonAction("acquire", boost::bind(&LLFloaterExperiences::sendPurchaseRequest, this)); + owned->enableButton(false); +#if SHOW_RECENT_TAB + addTab("Recent_Experiences_Tab", false); +#endif //SHOW_RECENT_TAB + panel = new LLPanelExperienceLog(); + getChild("xp_tabs")->addTabPanel(panel, panel->getLabel()); + resizeToTabs(); + + return TRUE; +} + + +void LLFloaterExperiences::clearFromRecent(const LLSD& ids) +{ +#if SHOW_RECENT_TAB + LLTabContainer* tabs = getChild("xp_tabs"); + + LLPanelExperiences* tab = (LLPanelExperiences*)tabs->getPanelByName("Recent_Experiences_Tab"); + if(!tab) + return; + + tab->removeExperiences(ids); +#endif // SHOW_RECENT_TAB +} + +void LLFloaterExperiences::setupRecentTabs() +{ +#if SHOW_RECENT_TAB + LLTabContainer* tabs = getChild("xp_tabs"); + + LLPanelExperiences* tab = (LLPanelExperiences*)tabs->getPanelByName("Recent_Experiences_Tab"); + if(!tab) + return; + + LLSD recent; + + const LLExperienceCache::cache_t& experiences = LLExperienceCache::getCached(); + + LLExperienceCache::cache_t::const_iterator it = experiences.begin(); + while( it != experiences.end() ) + { + if(!it->second.has(LLExperienceCache::MISSING)) + { + recent.append(it->first); + } + ++it; + } + + tab->setExperienceList(recent); +#endif // SHOW_RECENT_TAB +} + + +void LLFloaterExperiences::resizeToTabs() +{ + const S32 TAB_WIDTH_PADDING = 16; + + LLTabContainer* tabs = getChild("xp_tabs"); + LLRect rect = getRect(); + if(rect.getWidth() < tabs->getTotalTabWidth() + TAB_WIDTH_PADDING) + { + rect.mRight = rect.mLeft + tabs->getTotalTabWidth() + TAB_WIDTH_PADDING; + } + reshape(rect.getWidth(), rect.getHeight(), FALSE); +} + +void LLFloaterExperiences::refreshContents() +{ + setupRecentTabs(); + + LLViewerRegion* region = gAgent.getRegion(); + + if (region) + { + NameMap_t tabMap; + LLHandle handle = getDerivedHandle(); + + tabMap["experiences"]="Allowed_Experiences_Tab"; + tabMap["blocked"]="Blocked_Experiences_Tab"; + tabMap["experience_ids"]="Owned_Experiences_Tab"; + + retrieveExperienceList(region->getCapability("GetExperiences"), handle, tabMap); + + updateInfo("GetAdminExperiences","Admin_Experiences_Tab"); + updateInfo("GetCreatorExperiences","Contrib_Experiences_Tab"); + + retrieveExperienceList(region->getCapability("AgentExperiences"), handle, tabMap, + "ExperienceAcquireFailed", boost::bind(&LLFloaterExperiences::checkPurchaseInfo, this, _1, _2)); + } +} + +void LLFloaterExperiences::onOpen() +{ + LLEventPumps::instance().obtain("experience_permission").stopListening("LLFloaterExperiences"); + LLEventPumps::instance().obtain("experience_permission").listen("LLFloaterExperiences", + boost::bind(&LLFloaterExperiences::updatePermissions, this, _1)); + + LLViewerRegion* region = gAgent.getRegion(); + if(region) + { + if(region->capabilitiesReceived()) + { + refreshContents(); + return; + } + region->setCapabilitiesReceivedCallback(boost::bind(&LLFloaterExperiences::refreshContents, this)); + return; + } +} + +bool LLFloaterExperiences::updatePermissions( const LLSD& permission ) +{ + LLTabContainer* tabs = getChild("xp_tabs"); + LLUUID experience; + std::string permission_string; + if(permission.has("experience")) + { + experience = permission["experience"].asUUID(); + permission_string = permission[experience.asString()]["permission"].asString(); + + } + LLPanelExperiences* tab = (LLPanelExperiences*)tabs->getPanelByName("Allowed_Experiences_Tab"); + if(tab) + { + if(permission.has("experiences")) + { + tab->setExperienceList(permission["experiences"]); + } + else if(experience.notNull()) + { + if(permission_string != "Allow") + { + tab->removeExperience(experience); + } + else + { + tab->addExperience(experience); + } + } + } + + tab = (LLPanelExperiences*)tabs->getPanelByName("Blocked_Experiences_Tab"); + if(tab) + { + if(permission.has("blocked")) + { + tab->setExperienceList(permission["blocked"]); + } + else if(experience.notNull()) + { + if(permission_string != "Block") + { + tab->removeExperience(experience); + } + else + { + tab->addExperience(experience); + } + } + } + return false; +} + +void LLFloaterExperiences::onClose( bool app_quitting ) +{ + LLEventPumps::instance().obtain("experience_permission").stopListening("LLFloaterExperiences"); + LLFloater::onClose(app_quitting); +} + +void LLFloaterExperiences::checkPurchaseInfo(LLPanelExperiences* panel, const LLSD& content) const +{ + panel->enableButton(content.has("purchase")); + + LLFloaterExperiences::findInstance()->updateInfo("GetAdminExperiences","Admin_Experiences_Tab"); + LLFloaterExperiences::findInstance()->updateInfo("GetCreatorExperiences","Contrib_Experiences_Tab"); +} + +void LLFloaterExperiences::checkAndOpen(LLPanelExperiences* panel, const LLSD& content) const +{ + checkPurchaseInfo(panel, content); + + // determine new item + const LLSD& response_ids = content["experience_ids"]; + + if (mPrepurchaseIds.size() + 1 == response_ids.size()) + { + // we have a new element + for (const auto& it : response_ids.array()) + { + LLUUID experience_id = it.asUUID(); + if (std::find(mPrepurchaseIds.begin(), mPrepurchaseIds.end(), experience_id) == mPrepurchaseIds.end()) + { + // new element found, open it + LLSD args; + args["experience_id"] = experience_id; + args["edit_experience"] = true; + LLFloaterExperienceProfile::showInstance(args); + break; + } + } + } +} + +void LLFloaterExperiences::updateInfo(std::string experienceCap, std::string tab) +{ + LLViewerRegion* region = gAgent.getRegion(); + if (region) + { + NameMap_t tabMap; + LLHandle handle = getDerivedHandle(); + + tabMap["experience_ids"] = tab; + + retrieveExperienceList(region->getCapability(experienceCap), handle, tabMap); + } +} + +void LLFloaterExperiences::sendPurchaseRequest() +{ + LLViewerRegion* region = gAgent.getRegion(); + + if (region) + { + NameMap_t tabMap; + const std::string tab_owned_name = "Owned_Experiences_Tab"; + LLHandle handle = getDerivedHandle(); + + tabMap["experience_ids"] = tab_owned_name; + + // extract ids for experiences that we already have + LLTabContainer* tabs = getChild("xp_tabs"); + LLPanelExperiences* tab_owned = (LLPanelExperiences*)tabs->getPanelByName(tab_owned_name); + mPrepurchaseIds.clear(); + if (tab_owned) + { + tab_owned->getExperienceIdsList(mPrepurchaseIds); + } + + requestNewExperience(region->getCapability("AgentExperiences"), handle, tabMap, "ExperienceAcquireFailed", + boost::bind(&LLFloaterExperiences::checkAndOpen, this, _1, _2)); + } +} + + +void LLFloaterExperiences::retrieveExperienceList(const std::string &url, + const LLHandle &hparent, const NameMap_t &tabMapping, + const std::string &errorNotify, Callback_t cback, bool post) +{ + if (url.empty()) + { + LL_WARNS() << "retrieveExperienceListCoro called with empty capability!" << LL_ENDL; + return; + } + + auto responder = new LLCoroResponder( + boost::bind(LLFloaterExperiences::retrieveExperienceListCoro, _1, + hparent, tabMapping, errorNotify, cback)); + + if (post) + LLHTTPClient::post(url, LLSD(), responder); + else + LLHTTPClient::get(url, responder); +} + +void LLFloaterExperiences::retrieveExperienceListCoro(const LLCoroResponder& responder, + LLHandle hparent, NameMap_t tabMapping, + std::string errorNotify, Callback_t cback) +{ + LLSD result = responder.getContent(); + + if (!responder.isGoodStatus(responder.getStatus())) + { + LLSD subs; + subs["ERROR_MESSAGE"] = responder.getReason(); + LLNotificationsUtil::add(errorNotify, subs); + + return; + } + + if (hparent.isDead()) + return; + + LLFloaterExperiences* parent = hparent.get(); + LLTabContainer* tabs = parent->getChild("xp_tabs"); + + for (auto& it : tabMapping) + { + if (result.has(it.first)) + { + LLPanelExperiences* tab = (LLPanelExperiences*)tabs->getPanelByName(it.second); + if (tab) + { + const LLSD& ids = result[it.first]; + tab->setExperienceList(ids); + if (cback != nullptr) + { + cback(tab, result); + } + } + } + } + +} diff --git a/indra/newview/llfloaterexperiences.h b/indra/newview/llfloaterexperiences.h new file mode 100644 index 0000000000..ebe1a00fec --- /dev/null +++ b/indra/newview/llfloaterexperiences.h @@ -0,0 +1,78 @@ +/** + * @file llfloaterexperiences.h + * @brief LLFloaterExperiences class definition + * + * $LicenseInfo:firstyear=2012&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLFLOATEREXPERIENCES_H +#define LL_LLFLOATEREXPERIENCES_H + +#include "llfloater.h" + +class LLPanelExperiences; + +class LLFloaterExperiences final : + public LLFloater +, public LLFloaterSingleton +{ + friend class LLUISingleton >; +public: + LLFloaterExperiences(const LLSD& data); + void onClose(bool app_quitting) override; + + void onOpen(/*const LLSD& key*/) override; + +protected: + typedef std::map NameMap_t; + typedef std::function Callback_t; + + void clearFromRecent(const LLSD& ids); + void resizeToTabs(); + /*virtual*/ BOOL postBuild() override; + void refreshContents(); + void setupRecentTabs(); + LLPanelExperiences* addTab(const std::string& name, bool select); + + bool updatePermissions(const LLSD& permission); + void sendPurchaseRequest(); + void checkPurchaseInfo(LLPanelExperiences* panel, const LLSD& content)const; + void checkAndOpen(LLPanelExperiences* panel, const LLSD& content) const; + void updateInfo(std::string experiences, std::string tab); + + void retrieveExperienceList(const std::string &url, const LLHandle &hparent, const NameMap_t &tabMapping, + const std::string &errorNotify = std::string("ErrorMessage"), Callback_t cback = Callback_t(), bool post = false); + + void requestNewExperience(const std::string &url, const LLHandle &hparent, const NameMap_t &tabMapping, + const std::string &errorNotify, Callback_t cback) + { + retrieveExperienceList(url, hparent, tabMapping, errorNotify, cback, true); + } + +private: + static void retrieveExperienceListCoro(const struct LLCoroResponder& responder, LLHandle hparent, + NameMap_t tabMapping, std::string errorNotify, Callback_t cback); + uuid_vec_t mPrepurchaseIds; +}; + +#endif //LL_LLFLOATEREXPERIENCES_H + diff --git a/indra/newview/llfloaterexploreanimations.cpp b/indra/newview/llfloaterexploreanimations.cpp index 5ffe000b66..6bfa4f52ff 100644 --- a/indra/newview/llfloaterexploreanimations.cpp +++ b/indra/newview/llfloaterexploreanimations.cpp @@ -4,6 +4,7 @@ #include "llfloaterexploreanimations.h" #include "lluictrlfactory.h" #include "llscrolllistctrl.h" +#include "llagentdata.h" #include "llfloaterbvhpreview.h" #include "llvoavatar.h" #include "llviewercamera.h" @@ -14,42 +15,51 @@ #include "llselectmgr.h" // -std::map< LLUUID, std::list< LLAnimHistoryItem* > > LLFloaterExploreAnimations::animHistory; -LLFloaterExploreAnimations* LLFloaterExploreAnimations::sInstance; +std::map< LLUUID, std::list< LLAnimHistoryItem > > LLFloaterExploreAnimations::animHistory; +LLAnimHistoryItem::LLAnimHistoryItem(LLUUID assetid, bool playing) +: mAssetID(assetid) +, mPlaying(playing) +, mTimeStarted(LLTimer::getElapsedSeconds()) +, mTimeStopped(playing ? 0.f : mTimeStarted) +{} +bool LLAnimHistoryItem::setPlaying(bool playing) +{ + if (mPlaying == playing) return false; + mPlaying = playing; + playing ? mTimeStarted : mTimeStopped = LLTimer::getElapsedSeconds(); + return true; +} -LLAnimHistoryItem::LLAnimHistoryItem(LLUUID assetid) +void LLFloaterExploreAnimations::show() { - mAssetID = assetid; + LLViewerObject* avatar = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + const LLUUID& id(avatar ? avatar->getID() : gAgentID); + if (LLFloaterExploreAnimations* f = getInstance(id)) + if (avatar) f->open(); + else f->close(); + else + (new LLFloaterExploreAnimations(id))->open(); } -LLFloaterExploreAnimations::LLFloaterExploreAnimations(LLUUID avatarid) -: LLFloater() +LLFloaterExploreAnimations::LLFloaterExploreAnimations(const LLUUID avatarid) +: LLInstanceTracker(avatarid) +, mAnimPreview(256, 256) { mLastMouseX = 0; mLastMouseY = 0; - LLFloaterExploreAnimations::sInstance = this; - mAvatarID = avatarid; - mAnimPreview = new LLPreviewAnimation(256, 256); - mAnimPreview->setZoom(2.0f); + mAnimPreview.setZoom(2.0f); LLUICtrlFactory::getInstance()->buildFloater(this, "floater_explore_animations.xml"); } -void LLFloaterExploreAnimations::close(bool app_quitting) -{ - LLFloater::close(app_quitting); -} - LLFloaterExploreAnimations::~LLFloaterExploreAnimations() { - mAnimPreview = NULL; - LLFloaterExploreAnimations::sInstance = NULL; } -BOOL LLFloaterExploreAnimations::postBuild(void) +BOOL LLFloaterExploreAnimations::postBuild() { - childSetCommitCallback("anim_list", onSelectAnimation, this); + getChild("anim_list")->setCommitCallback(boost::bind(&LLFloaterExploreAnimations::onSelectAnimation, this)); LLRect r = getRect(); mPreviewRect.set(r.getWidth() - 266, r.getHeight() - 25, r.getWidth() - 10, r.getHeight() - 256); update(); @@ -59,29 +69,28 @@ BOOL LLFloaterExploreAnimations::postBuild(void) void LLFloaterExploreAnimations::update() { LLScrollListCtrl* list = getChild("anim_list"); - LLUUID selection = list->getSelectedValue().asUUID(); + LLUUID selection = list->getCurrentID(); list->clearRows(); // do this differently probably - std::list history = animHistory[mAvatarID]; - std::list::iterator iter = history.begin(); - std::list::iterator end = history.end(); - for( ; iter != end; ++iter) + std::list history = animHistory[getKey()]; + std::list::iterator end = history.end(); + for(std::list::iterator iter = history.begin(); iter != end; ++iter) { - LLAnimHistoryItem* item = (*iter); + LLAnimHistoryItem item = (*iter); LLSD element; - element["id"] = item->mAssetID; + element["id"] = item.mAssetID; LLSD& name_column = element["columns"][0]; name_column["column"] = "name"; - name_column["value"] = item->mAssetID.asString(); + name_column["value"] = item.mAssetID.asString(); LLSD& info_column = element["columns"][1]; info_column["column"] = "info"; - if(item->mPlaying) + if(item.mPlaying) info_column["value"] = "Playing"; else - info_column["value"] = llformat("%.1f min ago", (LLTimer::getElapsedSeconds() - item->mTimeStopped) / 60.f); + info_column["value"] = llformat("%.1f min ago", (LLTimer::getElapsedSeconds() - item.mTimeStopped) / 60.f); list->addElement(element, ADD_BOTTOM); } @@ -98,174 +107,99 @@ void LLFloaterExploreAnimations::draw() gGL.color3f(1.f, 1.f, 1.f); - gGL.getTexUnit(0)->bind(mAnimPreview); + gGL.getTexUnit(0)->bind(&mAnimPreview); - gGL.begin( LLRender::QUADS ); + gGL.begin( LLRender::TRIANGLE_STRIP ); { gGL.texCoord2f(0.f, 1.f); gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mTop); gGL.texCoord2f(0.f, 0.f); gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mBottom); - gGL.texCoord2f(1.f, 0.f); - gGL.vertex2i(mPreviewRect.mRight, mPreviewRect.mBottom); gGL.texCoord2f(1.f, 1.f); gGL.vertex2i(mPreviewRect.mRight, mPreviewRect.mTop); + gGL.texCoord2f(1.f, 0.f); + gGL.vertex2i(mPreviewRect.mRight, mPreviewRect.mBottom); } gGL.end(); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - //LLVOAvatar* avatarp = mAnimPreview->getDummyAvatar(); + //LLVOAvatar* avatarp = mAnimPreview.getDummyAvatar(); //if (!avatarp->areAnimationsPaused()) //{ - // mAnimPreview->requestUpdate(); + // mAnimPreview.requestUpdate(); //} } - - - - // static -void LLFloaterExploreAnimations::startAnim(LLUUID avatarid, LLUUID assetid) +void LLFloaterExploreAnimations::processAnim(LLUUID avatarid, LLUUID assetid, bool playing) { std::string asset_str = assetid.asString(); if(asset_str.find("17132261-c061") != std::string::npos) return; // dog1 else if(asset_str.find("fea558cb-8b9b") != std::string::npos) return; // dog2 else if(asset_str.find("50cb5750-0743") != std::string::npos) return; // dog3 - else if(asset_str.find("-dead-") != std::string::npos) return; // emo - - LLAnimHistoryItem* item = NULL; - std::list history = animHistory[avatarid]; - std::list::iterator iter = history.begin(); - std::list::iterator end = history.end(); - for( ; iter != end; ++iter) - { - if((*iter)->mAssetID == assetid) - { - item = (*iter); - break; - } - } - if(!item) + std::list& history = animHistory[avatarid]; + std::list::iterator end = history.end(); + for(std::list::iterator iter = history.begin(); iter != end; ++iter) { - item = new LLAnimHistoryItem(assetid); - item->mAvatarID = avatarid; - item->mTimeStarted = LLTimer::getElapsedSeconds(); + LLAnimHistoryItem& item = (*iter); + if (item.mAssetID != assetid) continue; + if (item.setPlaying(playing)) + handleHistoryChange(avatarid); + return; } - item->mPlaying = true; - history.push_back(item); - animHistory[avatarid] = history; // is this really necessary? - handleHistoryChange(); -} + // Trim it + if (history.size() > 31) + history.resize(31); -// static -void LLFloaterExploreAnimations::stopAnim(LLUUID avatarid, LLUUID assetid) -{ - std::string asset_str = assetid.asString(); - if(asset_str.find("17132261-c061") != std::string::npos) return; // dog1 - else if(asset_str.find("fea558cb-8b9b") != std::string::npos) return; // dog2 - else if(asset_str.find("50cb5750-0743") != std::string::npos) return; // dog3 - else if(asset_str.find("-dead-") != std::string::npos) return; // emo - - LLAnimHistoryItem* item = NULL; - - std::list history = animHistory[avatarid]; - std::list::iterator iter = history.begin(); - std::list::iterator end = history.end(); - for( ; iter != end; ++iter) - { - if((*iter)->mAssetID == assetid) - { - item = (*iter); - break; - } - } - if(!item) - { - item = new LLAnimHistoryItem(assetid); - item->mAvatarID = avatarid; - item->mTimeStarted = LLTimer::getElapsedSeconds(); - history.push_back(item); - } - item->mPlaying = false; - item->mTimeStopped = LLTimer::getElapsedSeconds(); - handleHistoryChange(); + history.push_back(LLAnimHistoryItem(assetid, playing)); + handleHistoryChange(avatarid); } class LLAnimHistoryItemCompare { public: - bool operator() (LLAnimHistoryItem* first, LLAnimHistoryItem* second) + bool operator() (LLAnimHistoryItem first, LLAnimHistoryItem second) { - if(first->mPlaying) + if (first.mPlaying) { - if(second->mPlaying) + if (second.mPlaying) { - return (first->mTimeStarted > second->mTimeStarted); + return (first.mTimeStarted > second.mTimeStarted); } else { return true; } } - else if(second->mPlaying) + else if (second.mPlaying) { return false; } else { - return (first->mTimeStopped > second->mTimeStopped); + return (first.mTimeStopped > second.mTimeStopped); } } }; // static -void LLFloaterExploreAnimations::handleHistoryChange() +void LLFloaterExploreAnimations::handleHistoryChange(LLUUID avatarid) { - std::map< LLUUID, std::list< LLAnimHistoryItem* > >::iterator av_iter = animHistory.begin(); - std::map< LLUUID, std::list< LLAnimHistoryItem* > >::iterator av_end = animHistory.end(); - for( ; av_iter != av_end; ++av_iter) - { - std::list history = (*av_iter).second; - - // Sort it - LLAnimHistoryItemCompare c; - history.sort(c); - - // Remove dupes - history.unique(); - - // Trim it - if(history.size() > 32) - { - history.resize(32); - } - - animHistory[(*av_iter).first] = history; - } + // Sort it + animHistory[avatarid].sort(LLAnimHistoryItemCompare()); // Update floater - if(LLFloaterExploreAnimations::sInstance) - LLFloaterExploreAnimations::sInstance->update(); + if (LLFloaterExploreAnimations* f = getInstance(avatarid)) + f->update(); } - - - - -// static -void LLFloaterExploreAnimations::onSelectAnimation(LLUICtrl* ctrl, void* user_data) +void LLFloaterExploreAnimations::onSelectAnimation() { - LLFloaterExploreAnimations* floater = (LLFloaterExploreAnimations*)user_data; - LLPreviewAnimation* preview = (LLPreviewAnimation*)floater->mAnimPreview; - LLScrollListCtrl* list = floater->getChild("anim_list"); - LLUUID selection = list->getSelectedValue().asUUID(); - - preview->getDummyAvatar()->deactivateAllMotions(); - preview->getDummyAvatar()->startMotion(selection, 0.f); - preview->setZoom(2.0f); + mAnimPreview.getDummyAvatar()->deactivateAllMotions(); + mAnimPreview.getDummyAvatar()->startMotion(getChild("anim_list")->getCurrentID(), 0.f); + mAnimPreview.setZoom(2.0f); } //----------------------------------------------------------------------------- @@ -275,7 +209,7 @@ BOOL LLFloaterExploreAnimations::handleMouseDown(S32 x, S32 y, MASK mask) { if (mPreviewRect.pointInRect(x, y)) { - //llinfos << "lolwut" << llendl; + //LL_INFOS() << "lolwut" << LL_ENDL; bringToFront( x, y ); gFocusMgr.setMouseCapture(this); gViewerWindow->hideCursor(); @@ -292,7 +226,7 @@ BOOL LLFloaterExploreAnimations::handleMouseDown(S32 x, S32 y, MASK mask) //----------------------------------------------------------------------------- BOOL LLFloaterExploreAnimations::handleMouseUp(S32 x, S32 y, MASK mask) { - //llinfos << "lolwut pear" << llendl; + //LL_INFOS() << "lolwut pear" << LL_ENDL; gFocusMgr.setMouseCapture(FALSE); gViewerWindow->showCursor(); return LLFloater::handleMouseUp(x, y, mask); @@ -305,35 +239,35 @@ BOOL LLFloaterExploreAnimations::handleHover(S32 x, S32 y, MASK mask) { MASK local_mask = mask & ~MASK_ALT; - if (mAnimPreview && hasMouseCapture()) + if (hasMouseCapture()) { if (local_mask == MASK_PAN) { // pan here - mAnimPreview->pan((F32)(x - mLastMouseX) * -0.005f, (F32)(y - mLastMouseY) * -0.005f); + mAnimPreview.pan((F32)(x - mLastMouseX) * -0.005f, (F32)(y - mLastMouseY) * -0.005f); } else if (local_mask == MASK_ORBIT) { F32 yaw_radians = (F32)(x - mLastMouseX) * -0.01f; F32 pitch_radians = (F32)(y - mLastMouseY) * 0.02f; - mAnimPreview->rotate(yaw_radians, pitch_radians); + mAnimPreview.rotate(yaw_radians, pitch_radians); } else { F32 yaw_radians = (F32)(x - mLastMouseX) * -0.01f; F32 zoom_amt = (F32)(y - mLastMouseY) * 0.02f; - mAnimPreview->rotate(yaw_radians, 0.f); - mAnimPreview->zoom(zoom_amt); + mAnimPreview.rotate(yaw_radians, 0.f); + mAnimPreview.zoom(zoom_amt); } - mAnimPreview->requestUpdate(); + mAnimPreview.requestUpdate(); LLUI::setMousePositionLocal(this, mLastMouseX, mLastMouseY); } - if (!mPreviewRect.pointInRect(x, y) || !mAnimPreview) + if (!mPreviewRect.pointInRect(x, y)) { return LLFloater::handleHover(x, y, mask); } @@ -358,8 +292,8 @@ BOOL LLFloaterExploreAnimations::handleHover(S32 x, S32 y, MASK mask) //----------------------------------------------------------------------------- BOOL LLFloaterExploreAnimations::handleScrollWheel(S32 x, S32 y, S32 clicks) { - mAnimPreview->zoom((F32)clicks * -0.2f); - mAnimPreview->requestUpdate(); + mAnimPreview.zoom((F32)clicks * -0.2f); + mAnimPreview.requestUpdate(); return TRUE; } diff --git a/indra/newview/llfloaterexploreanimations.h b/indra/newview/llfloaterexploreanimations.h index 383b16e6d3..b0ec7f8e24 100644 --- a/indra/newview/llfloaterexploreanimations.h +++ b/indra/newview/llfloaterexploreanimations.h @@ -2,16 +2,15 @@ #ifndef LL_LLFLOATEREXPLOREANIMATIONS_H #define LL_LLFLOATEREXPLOREANIMATIONS_H -#include "llfloater.h" #include "llfloaterbvhpreview.h" -#include "llviewerwindow.h" // gViewerWindow +#include "llinstancetracker.h" class LLAnimHistoryItem { public: - LLAnimHistoryItem(LLUUID assetid); + LLAnimHistoryItem(LLUUID assetid = LLUUID(), bool playing = true); + bool setPlaying(bool playing); - LLUUID mAvatarID; LLUUID mAssetID; bool mPlaying; F64 mTimeStarted; @@ -19,25 +18,30 @@ class LLAnimHistoryItem }; class LLFloaterExploreAnimations -: public LLFloater +: public LLFloater, public LLInstanceTracker { public: + static void show(); LLFloaterExploreAnimations(LLUUID avatarid); - BOOL postBuild(void); - void close(bool app_quitting); + BOOL postBuild(); void update(); - LLUUID mAvatarID; - LLPointer mAnimPreview; + void* operator new(size_t size) + { + return ll_aligned_malloc_16(size); + } + + void operator delete(void* ptr) + { + ll_aligned_free_16(ptr); + } private: virtual ~LLFloaterExploreAnimations(); - -// static stuff! public: - static void onSelectAnimation(LLUICtrl* ctrl, void* user_data); + void onSelectAnimation(); BOOL handleMouseDown(S32 x, S32 y, MASK mask); BOOL handleMouseUp(S32 x, S32 y, MASK mask); @@ -45,16 +49,17 @@ class LLFloaterExploreAnimations BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); void onMouseCaptureLost(); - static void startAnim(LLUUID avatarid, LLUUID assetid); - static void stopAnim(LLUUID avatarid, LLUUID assetid); +// static stuff! + static void processAnim(LLUUID avatarid, LLUUID assetid, bool playing); - static std::map< LLUUID, std::list< LLAnimHistoryItem* > > animHistory; - static LLFloaterExploreAnimations* sInstance; + static std::map< LLUUID, std::list< LLAnimHistoryItem > > animHistory; private: - static void handleHistoryChange(); + static void handleHistoryChange(LLUUID avatarid); protected: void draw(); + + LL_ALIGN_16(LLPreviewAnimation mAnimPreview); LLRect mPreviewRect; S32 mLastMouseX; S32 mLastMouseY; diff --git a/indra/newview/llfloaterexploresounds.cpp b/indra/newview/llfloaterexploresounds.cpp index d1dacf4e3f..94400f31f9 100644 --- a/indra/newview/llfloaterexploresounds.cpp +++ b/indra/newview/llfloaterexploresounds.cpp @@ -295,7 +295,7 @@ void LLFloaterExploreSounds::handle_play_locally(void* user_data) std::vector selection = list->getAllSelected(); std::vector::iterator selection_iter = selection.begin(); std::vector::iterator selection_end = selection.end(); - std::vector asset_list; + uuid_vec_t asset_list; for( ; selection_iter != selection_end; ++selection_iter) { LLSoundHistoryItem item = floater->getItem((*selection_iter)->getValue()); @@ -304,6 +304,7 @@ void LLFloaterExploreSounds::handle_play_locally(void* user_data) if(std::find(asset_list.begin(), asset_list.end(), item.mAssetID) == asset_list.end()) { asset_list.push_back(item.mAssetID); + if(gAudiop) gAudiop->triggerSound(item.mAssetID, LLUUID::null, 1.0f, LLAudioEngine::AUDIO_TYPE_UI); } } @@ -352,7 +353,7 @@ void LLFloaterExploreSounds::handle_stop(void* user_data) std::vector selection = list->getAllSelected(); std::vector::iterator selection_iter = selection.begin(); std::vector::iterator selection_end = selection.end(); - std::vector asset_list; + uuid_vec_t asset_list; for( ; selection_iter != selection_end; ++selection_iter) { LLSoundHistoryItem item = floater->getItem((*selection_iter)->getValue()); diff --git a/indra/newview/llfloaterfriends.cpp b/indra/newview/llfloaterfriends.cpp index 45cedfeac5..da43f9696c 100644 --- a/indra/newview/llfloaterfriends.cpp +++ b/indra/newview/llfloaterfriends.cpp @@ -37,7 +37,7 @@ #include "llfloaterfriends.h" - +#include "llsdutil_math.h" #include "llagent.h" #include "llavataractions.h" #include "llavatarnamecache.h" @@ -54,7 +54,6 @@ #include "lltextbox.h" #include "lluictrlfactory.h" #include "llviewerwindow.h" -#include "llvoiceclient.h" #include "statemachine/aifilepicker.h" @@ -65,44 +64,19 @@ //#include "llchat.h" //#include "llfloaterchat.h" -#define DEFAULT_PERIOD 5.0 -#define RIGHTS_CHANGE_TIMEOUT 5.0 -#define OBSERVER_TIMEOUT 0.5 - -#define ONLINE_SIP_ICON_NAME "slim_icon_16_viewer.tga" - // simple class to observe the calling cards. - - -class LLAvatarListUpdater : public LLEventTimer -{ -public: - LLAvatarListUpdater(F32 period) - : LLEventTimer(period) - { - mEventTimer.stop(); - } - - virtual BOOL tick() // from LLEventTimer - { - return FALSE; - } -}; - -class LLLocalFriendsObserver : public LLAvatarListUpdater, public LLFriendObserver +class LLLocalFriendsObserver : public LLFriendObserver, public LLEventTimer { LOG_CLASS(LLLocalFriendsObserver); public: LLLocalFriendsObserver(LLPanelFriends* floater) - : mFloater(floater), LLAvatarListUpdater(OBSERVER_TIMEOUT) + : mFloater(floater), LLEventTimer(0.5) { + mEventTimer.stop(); LLAvatarTracker::instance().addObserver(this); - // For notification when SIP online status changes. - LLVoiceClient::getInstance()->addObserver(this); } /*virtual*/ ~LLLocalFriendsObserver() { - LLVoiceClient::getInstance()->removeObserver(this); LLAvatarTracker::instance().removeObserver(this); } /*virtual*/ void changed(U32 mask) @@ -122,7 +96,7 @@ class LLLocalFriendsObserver : public LLAvatarListUpdater, public LLFriendObserv mEventTimer.stop(); mMask = 0; - return FALSE; + return false; } protected: @@ -131,15 +105,9 @@ class LLLocalFriendsObserver : public LLAvatarListUpdater, public LLFriendObserv }; LLPanelFriends::LLPanelFriends() : - LLPanel(), - LLEventTimer(DEFAULT_PERIOD), mObserver(NULL), - mShowMaxSelectWarning(TRUE), - mAllowRightsChange(TRUE), - mNumRightsChanged(0), mNumOnline(0) { - mEventTimer.stop(); mObserver = new LLLocalFriendsObserver(this); } @@ -148,66 +116,34 @@ LLPanelFriends::~LLPanelFriends() delete mObserver; } -BOOL LLPanelFriends::tick() -{ - mEventTimer.stop(); - mPeriod = DEFAULT_PERIOD; - mAllowRightsChange = TRUE; - updateFriends(LLFriendObserver::ADD); - return FALSE; -} - void LLPanelFriends::updateFriends(U32 changed_mask) { LLUUID selected_id; - LLCtrlListInterface *friends_list = childGetListInterface("friend_list"); - if (!friends_list) return; - LLCtrlScrollInterface *friends_scroll = childGetScrollInterface("friend_list"); - if (!friends_scroll) return; - - // We kill the selection warning, otherwise we'll spam with warning popups - // if the maximum amount of friends are selected - mShowMaxSelectWarning = false; const uuid_vec_t selected_friends = mFriendsList->getSelectedIDs(); - if(changed_mask & (LLFriendObserver::ADD | LLFriendObserver::REMOVE | LLFriendObserver::ONLINE)) + if (changed_mask & (LLFriendObserver::ADD | LLFriendObserver::REMOVE | LLFriendObserver::ONLINE | LLFriendObserver::POWERS)) { refreshNames(changed_mask); } - else if(changed_mask & LLFriendObserver::POWERS) - { - --mNumRightsChanged; - if(mNumRightsChanged > 0) - { - mPeriod = RIGHTS_CHANGE_TIMEOUT; - mEventTimer.start(); - mAllowRightsChange = FALSE; - } - else - { - tick(); - } - } - if(!selected_friends.empty()) + if (!selected_friends.empty()) { // only non-null if friends was already found. This may fail, // but we don't really care here, because refreshUI() will // clean up the interface. - friends_list->setCurrentByID(selected_id); + mFriendsList->setCurrentByID(selected_id); for(uuid_vec_t::const_iterator itr = selected_friends.begin(); itr != selected_friends.end(); ++itr) { - friends_list->setSelectedByValue(*itr, true); + mFriendsList->setSelectedByValue(*itr, true); } } refreshUI(); - mShowMaxSelectWarning = true; } // // Contact search and group system. // 09/05/2010 - Charley Levenque -std::string LLPanelFriends::cleanFileName(std::string filename) +/*std::string LLPanelFriends::cleanFileName(std::string filename) { std::string invalidChars = "\"\'\\/?*:<>|"; S32 position = filename.find_first_of(invalidChars); @@ -217,13 +153,11 @@ std::string LLPanelFriends::cleanFileName(std::string filename) position = filename.find_first_of(invalidChars, position); } return filename; -} +}*/ /*void LLPanelFriends::populateContactGroupSelect() { - LLComboBox* combo = getChild("buddy_group_combobox"); - - if (combo) + if (LLComboBox* combo = findChild("buddy_group_combobox")) { combo->removeall(); combo->add("All", ADD_BOTTOM); @@ -239,15 +173,13 @@ std::string LLPanelFriends::cleanFileName(std::string filename) } else { - LLChat msg("Null combo"); - LLFloaterChat::addChat(msg); + LLFloaterChat::addChat("Null combo"); } }*/ -/*void LLPanelFriends::setContactGroup(std::string contact_grp) +/*void LLPanelFriends::setContactGroup(const std::string& contact_grp) { - LLChat msg("Group set to " + contact_grp); - LLFloaterChat::addChat(msg); + LLFloaterChat::addChat("Group set to " + contact_grp); refreshNames(LLFriendObserver::ADD); refreshUI(); categorizeContacts(); @@ -258,8 +190,7 @@ std::string LLPanelFriends::cleanFileName(std::string filename) LLSD contact_groups = gSavedPerAccountSettings.getLLSD("AscentContactGroups"); std::string group_name = "All"; - LLComboBox* combo = getChild("buddy_group_combobox"); - if (combo) + if (LLComboBox* combo = findChild("buddy_group_combobox")) { group_name = combo->getValue().asString(); @@ -268,11 +199,9 @@ std::string LLPanelFriends::cleanFileName(std::string filename) std::vector vFriends = mFriendsList->getAllData(); // all of it. for (std::vector::iterator itr = vFriends.begin(); itr != vFriends.end(); ++itr) { - BOOL show_entry = false;//contact_groups[group_name].has((*itr)->getUUID().asString()); + bool show_entry = false;//contact_groups[group_name].has((*itr)->getUUID().asString()); - S32 count = contact_groups[group_name].size(); - int i; - for(i = 0; i < count; i++) + for(S32 i = 0, count = contact_groups[group_name].size(); i < count; ++i) { if (contact_groups[group_name][i].asString() == (*itr)->getUUID().asString()) { @@ -283,29 +212,25 @@ std::string LLPanelFriends::cleanFileName(std::string filename) if (!show_entry) { - LLChat msg("False: contact_groups['" + group_name + "'].has('" + (*itr)->getUUID().asString() + "');"); - LLFloaterChat::addChat(msg); + LLFloaterChat::addChat("False: contact_groups['" + group_name + "'].has('" + (*itr)->getUUID().asString() + "');"); mFriendsList->deleteItems((*itr)->getValue()); } else { - LLChat msg("True: contact_groups['" + group_name + "'].has('" + (*itr)->getUUID().asString() + "');"); - LLFloaterChat::addChat(msg); + LLFloaterChat::addChat("True: contact_groups['" + group_name + "'].has('" + (*itr)->getUUID().asString() + "');"); } } } else { - LLChat msg("Group set to all."); - LLFloaterChat::addChat(msg); + LLFloaterChat::addChat("Group set to all."); } refreshUI(); } else { - LLChat msg("Null combo."); - LLFloaterChat::addChat(msg); + LLFloaterChat::addChat("Null combo."); } }*/ @@ -313,21 +238,21 @@ void LLPanelFriends::filterContacts(const std::string& search_name) { std::string friend_name; - if ((search_name != "" /*&& search_name != mLastContactSearch*/)) - { + if (!search_name.empty()) + { if (search_name.find(mLastContactSearch) == std::string::npos) { refreshNames(LLFriendObserver::ADD); } - //llinfos << "search_name = " << search_name <deleteItems((*itr)->getValue()); @@ -337,43 +262,28 @@ void LLPanelFriends::filterContacts(const std::string& search_name) mFriendsList->updateLayout(); refreshUI(); } - else if (search_name == "" && search_name != mLastContactSearch) refreshNames(LLFriendObserver::ADD); + else if (!mLastContactSearch.empty()) refreshNames(LLFriendObserver::ADD); mLastContactSearch = search_name; } - -void LLPanelFriends::onContactFilterEdit(const std::string& search_string) -{ - filterContacts(search_string); -} - -/*void LLPanelFriends::onChangeContactGroup(LLUICtrl* ctrl, void* user_data) -{ - LLPanelFriends* panelp = (LLPanelFriends*)user_data; - - if(panelp) - { - LLComboBox* combo = panelp->getChild("buddy_group_combobox"); - panelp->setContactGroup(combo->getValue().asString()); - } -}*/ // -- // virtual BOOL LLPanelFriends::postBuild() { mFriendsList = getChild("friend_list"); - mFriendsList->setCommitOnSelectionChange(TRUE); - mFriendsList->setCommitCallback(onSelectName, this); - //childSetCommitCallback("buddy_group_combobox", onChangeContactGroup, this); - mFriendsList->setDoubleClickCallback(onClickIM, this); + mFriendsList->setCommitOnSelectionChange(true); + auto single_selection(boost::bind(&LLScrollListCtrl::getCurrentID, mFriendsList)); + auto selection(boost::bind(&LLScrollListCtrl::getSelectedIDs, mFriendsList)); + mFriendsList->setCommitCallback(boost::bind(&LLPanelFriends::onSelectName, this)); + //getChild("buddy_group_combobox")->setCommitCallback(boost::bind(&LLPanelFriends::setContactGroup, this, _2)); + mFriendsList->setDoubleClickCallback(boost::bind(LLAvatarActions::startIM, single_selection)); // // Contact search and group system. // 09/05/2010 - Charley Levenque - LLFilterEditor* contact = getChild("buddy_search_lineedit"); - if (contact) + if (LLFilterEditor* contact = getChild("buddy_search_lineedit")) { - contact->setCommitCallback(boost::bind(&LLPanelFriends::onContactFilterEdit, this, _2)); + contact->setCommitCallback(boost::bind(&LLPanelFriends::filterContacts, this, _2)); } getChild("s_num")->setValue("0"); @@ -382,16 +292,15 @@ BOOL LLPanelFriends::postBuild() U32 changed_mask = LLFriendObserver::ADD | LLFriendObserver::REMOVE | LLFriendObserver::ONLINE; refreshNames(changed_mask); - childSetAction("im_btn", onClickIM, this); - //childSetAction("assign_btn", onClickAssign, this); - childSetAction("expand_collapse_btn", onClickExpand, this); - childSetAction("profile_btn", onClickProfile, this); - getChild("offer_teleport_btn")->setCommitCallback(boost::bind(static_cast(LLAvatarActions::offerTeleport), boost::bind(&LLScrollListCtrl::getSelectedIDs, mFriendsList))); - childSetAction("pay_btn", onClickPay, this); - childSetAction("add_btn", onClickAddFriend, this); - getChild("remove_btn")->setCommitCallback(boost::bind(LLAvatarActions::removeFriendsDialog, boost::bind(&LLScrollListCtrl::getSelectedIDs, mFriendsList))); - //childSetAction("export_btn", onClickExport, this); Making Dummy View -HgB - //childSetAction("import_btn", onClickImport, this); Making Dummy View -HgB + getChild("im_btn")->setCommitCallback(boost::bind(&LLPanelFriends::onClickIM, this, selection)); + //getChild("assign_btn")->setCommitCallback(boost::bind(ASFloaterContactGroups::show, selection)); + getChild("profile_btn")->setCommitCallback(boost::bind(LLAvatarActions::showProfiles, selection, false)); + getChild("offer_teleport_btn")->setCommitCallback(boost::bind(static_cast(LLAvatarActions::offerTeleport), selection)); + getChild("pay_btn")->setCommitCallback(boost::bind(LLAvatarActions::pay, single_selection)); + getChild("add_btn")->setCommitCallback(boost::bind(&LLPanelFriends::onClickAddFriend, this)); + getChild("remove_btn")->setCommitCallback(boost::bind(LLAvatarActions::removeFriendsDialog, selection)); + //getChild("export_btn")->setCommitCallback(boost::bind(&LLPanelFriends::onClickExport, this)); Making Dummy View -HgB + //getChild("import_btn")->setCommitCallback(boost::bind(&LLPanelFriends::onClickImport, this)); Making Dummy View -HgB setDefaultBtn("im_btn"); @@ -399,215 +308,179 @@ BOOL LLPanelFriends::postBuild() refreshUI(); // primary sort = online status, secondary sort = name - mFriendsList->sortByColumn(std::string("friend_name"), TRUE); - mFriendsList->sortByColumn(std::string("icon_online_status"), FALSE); + mFriendsList->sortByColumn(std::string("friend_name"), true); + mFriendsList->sortByColumn(std::string("icon_online_status"), false); + + if (LLControlVariable* ctrl = gSavedSettings.getControl("ContactListCollapsed")) + { + updateColumns(ctrl->getValue()); + ctrl->getSignal()->connect(boost::bind(&LLPanelFriends::updateColumns, this, _2)); + } + + return true; +} - updateColumns(this); +const S32& friend_name_system() +{ + static const LLCachedControl name_system("FriendNameSystem", 0); + return name_system; +} - return TRUE; +static void update_friend_name(LLScrollListCtrl* list, const LLUUID& id, const LLAvatarName& avname) +{ + if (LLScrollListItem* item = list->getItem(id)) + item->getColumn(1)->setValue(avname.getNSName(friend_name_system())); } -BOOL LLPanelFriends::addFriend(const LLUUID& agent_id) +void LLPanelFriends::addFriend(const LLUUID& agent_id) { - LLAvatarTracker& at = LLAvatarTracker::instance(); - const LLRelationship* relationInfo = at.getBuddyInfo(agent_id); - if(!relationInfo) return FALSE; + const LLRelationship* relation_info = LLAvatarTracker::instance().getBuddyInfo(agent_id); + if (!relation_info) return; - bool isOnlineSIP = LLVoiceClient::getInstance()->isOnlineSIP(agent_id); - bool isOnline = relationInfo->isOnline(); + bool isOnline = relation_info->isOnline(); std::string fullname; - BOOL have_name = LLAvatarNameCache::getPNSName(agent_id, fullname); + bool have_name = LLAvatarNameCache::getNSName(agent_id, fullname, friend_name_system()); + if (!have_name) gCacheName->getFullName(agent_id, fullname); - LLSD element; - element["id"] = agent_id; - LLSD& friend_column = element["columns"][LIST_FRIEND_NAME]; - friend_column["column"] = "friend_name"; - friend_column["value"] = fullname; - friend_column["font"] = "SANSSERIF"; - friend_column["font-style"] = "NORMAL"; + LLScrollListItem::Params element; + element.value = agent_id; + LLScrollListCell::Params friend_column; + friend_column.column("friend_name").value(fullname).font("SANSSERIF"); + static const LLCachedControl sDefaultColor(gColors, "DefaultListText"); + static const LLCachedControl sMutedColor("AscentMutedColor"); + friend_column.color(LLAvatarActions::isBlocked(agent_id) ? sMutedColor : sDefaultColor); - LLSD& online_status_column = element["columns"][LIST_ONLINE_STATUS]; - online_status_column["column"] = "icon_online_status"; - online_status_column["type"] = "icon"; + LLScrollListCell::Params cell; + cell.column("icon_online_status").type("icon"); if (isOnline) { - mNumOnline++; - friend_column["font-style"] = "BOLD"; - online_status_column["value"] = "icon_avatar_online.tga"; - } - else if(isOnlineSIP) - { - mNumOnline++; - friend_column["font-style"] = "BOLD"; - online_status_column["value"] = ONLINE_SIP_ICON_NAME; + ++mNumOnline; + friend_column.font_style("BOLD"); + cell.value("icon_avatar_online.tga"); } - LLSD& online_column = element["columns"][LIST_VISIBLE_ONLINE]; - online_column["column"] = "icon_visible_online"; - online_column["type"] = "checkbox"; - online_column["value"] = relationInfo->isRightGrantedTo(LLRelationship::GRANT_ONLINE_STATUS); + // Add the online indicator, then the names + element.columns.add(cell); + element.columns.add(friend_column); - LLSD& visible_map_column = element["columns"][LIST_VISIBLE_MAP]; - visible_map_column["column"] = "icon_visible_map"; - visible_map_column["type"] = "checkbox"; - visible_map_column["value"] = relationInfo->isRightGrantedTo(LLRelationship::GRANT_MAP_LOCATION); + cell.font_style("NORMAL").type("checkbox") // Ready cell for the extended info - LLSD& edit_my_object_column = element["columns"][LIST_EDIT_MINE]; - edit_my_object_column["column"] = "icon_edit_mine"; - edit_my_object_column["type"] = "checkbox"; - edit_my_object_column["value"] = relationInfo->isRightGrantedTo(LLRelationship::GRANT_MODIFY_OBJECTS); - - LLSD& see_online_them_column = element["columns"][LIST_VISIBLE_ONLINE_THEIRS]; - see_online_them_column["column"] = "icon_visible_online_theirs"; - see_online_them_column["type"] = "checkbox"; - see_online_them_column["enabled"] = ""; - see_online_them_column["value"] = relationInfo->isRightGrantedFrom(LLRelationship::GRANT_ONLINE_STATUS); + .column("icon_visible_online") + .value(relation_info->isRightGrantedTo(LLRelationship::GRANT_ONLINE_STATUS)); + element.columns.add(cell); + + cell.column("icon_visible_map") + .value(relation_info->isRightGrantedTo(LLRelationship::GRANT_MAP_LOCATION)); + element.columns.add(cell); + + cell.column("icon_edit_mine") + .value(relation_info->isRightGrantedTo(LLRelationship::GRANT_MODIFY_OBJECTS)); + element.columns.add(cell); + cell.enabled(false) // These next cells are disabled. + .column("icon_visible_online_theirs") + .value(relation_info->isRightGrantedFrom(LLRelationship::GRANT_ONLINE_STATUS)); + element.columns.add(cell); - LLSD& mapstalk_them_column = element["columns"][LIST_VISIBLE_MAP_THEIRS]; - mapstalk_them_column["column"] = "icon_visible_map_theirs"; - mapstalk_them_column["type"] = "checkbox"; - mapstalk_them_column["enabled"] = ""; - mapstalk_them_column["value"] = relationInfo->isRightGrantedFrom(LLRelationship::GRANT_MAP_LOCATION); + cell.column("icon_visible_map_theirs") + .value(relation_info->isRightGrantedFrom(LLRelationship::GRANT_MAP_LOCATION)); + element.columns.add(cell); - LLSD& edit_their_object_column = element["columns"][LIST_EDIT_THEIRS]; - edit_their_object_column["column"] = "icon_edit_theirs"; - edit_their_object_column["type"] = "checkbox"; - edit_their_object_column["enabled"] = ""; - edit_their_object_column["value"] = relationInfo->isRightGrantedFrom(LLRelationship::GRANT_MODIFY_OBJECTS); + cell.column("icon_edit_theirs") + .value(relation_info->isRightGrantedFrom(LLRelationship::GRANT_MODIFY_OBJECTS)); + element.columns.add(cell); - LLSD& update_gen_column = element["columns"][LIST_FRIEND_UPDATE_GEN]; - update_gen_column["column"] = "friend_last_update_generation"; - update_gen_column["value"] = have_name ? relationInfo->getChangeSerialNum() : -1; + cell.type("text") // This is for sort, not display. + .column("friend_last_update_generation") + .value(have_name ? relation_info->getChangeSerialNum() : -1); + element.columns.add(cell); - mFriendsList->addElement(element, ADD_BOTTOM); - return have_name; + mFriendsList->addRow(element); + if (!have_name) LLAvatarNameCache::get(agent_id, boost::bind(update_friend_name, mFriendsList, _1, _2)); } // propagate actual relationship to UI. // Does not resort the UI list because it can be called frequently. JC -BOOL LLPanelFriends::updateFriendItem(const LLUUID& agent_id, const LLRelationship* info) +void LLPanelFriends::updateFriendItem(const LLUUID& agent_id, const LLRelationship* info) { - if (!info) return FALSE; + if (!info) return; LLScrollListItem* itemp = mFriendsList->getItem(agent_id); - if (!itemp) return FALSE; - - bool isOnlineSIP = LLVoiceClient::getInstance()->isOnlineSIP(itemp->getUUID()); + if (!itemp) return; + bool isOnline = info->isOnline(); std::string fullname; - BOOL have_name = LLAvatarNameCache::getPNSName(agent_id, fullname); - - // Name of the status icon to use - std::string statusIcon; - - if(isOnline) + if (LLAvatarNameCache::getNSName(agent_id, fullname, friend_name_system())) { - mNumOnline++; - statusIcon = "icon_avatar_online.tga"; + itemp->getColumn(LIST_FRIEND_UPDATE_GEN)->setValue(info->getChangeSerialNum()); } - else if(isOnlineSIP) + else { - mNumOnline++; - statusIcon = ONLINE_SIP_ICON_NAME; + gCacheName->getFullName(agent_id, fullname); + LLAvatarNameCache::get(agent_id, boost::bind(update_friend_name, mFriendsList, _1, _2)); + itemp->getColumn(LIST_FRIEND_UPDATE_GEN)->setValue(-1); } - else + + if (LLScrollListCell* cell = itemp->getColumn(LIST_ONLINE_STATUS)) { - mNumOnline--; + if (cell->getValue().asString().empty() == isOnline) + { + // Name of the status icon to use + std::string statusIcon; + + if (isOnline) + { + ++mNumOnline; + statusIcon = "icon_avatar_online.tga"; + } + else + { + --mNumOnline; + } + cell->setValue(statusIcon); + } } - itemp->getColumn(LIST_ONLINE_STATUS)->setValue(statusIcon); - itemp->getColumn(LIST_FRIEND_NAME)->setValue(fullname); // render name of online friends in bold text - ((LLScrollListText*)itemp->getColumn(LIST_FRIEND_NAME))->setFontStyle((isOnline || isOnlineSIP) ? LLFontGL::BOLD : LLFontGL::NORMAL); + static_cast(itemp->getColumn(LIST_FRIEND_NAME))->setFontStyle(isOnline ? LLFontGL::BOLD : LLFontGL::NORMAL); itemp->getColumn(LIST_VISIBLE_ONLINE)->setValue(info->isRightGrantedTo(LLRelationship::GRANT_ONLINE_STATUS)); itemp->getColumn(LIST_VISIBLE_MAP)->setValue(info->isRightGrantedTo(LLRelationship::GRANT_MAP_LOCATION)); itemp->getColumn(LIST_EDIT_MINE)->setValue(info->isRightGrantedTo(LLRelationship::GRANT_MODIFY_OBJECTS)); //Notes in the original code imply this may not always work. Good to know. -HgB itemp->getColumn(LIST_VISIBLE_ONLINE_THEIRS)->setValue(info->isRightGrantedFrom(LLRelationship::GRANT_ONLINE_STATUS)); - + itemp->getColumn(LIST_VISIBLE_MAP_THEIRS)->setValue(info->isRightGrantedFrom(LLRelationship::GRANT_MAP_LOCATION)); itemp->getColumn(LIST_EDIT_THEIRS)->setValue(info->isRightGrantedFrom(LLRelationship::GRANT_MODIFY_OBJECTS)); - S32 change_generation = have_name ? info->getChangeSerialNum() : -1; - itemp->getColumn(LIST_FRIEND_UPDATE_GEN)->setValue(change_generation); - - // enable this item, in case it was disabled after user input - itemp->setEnabled(TRUE); - mFriendsList->setNeedsSort(); // Do not resort, this function can be called frequently. - return have_name; } void LLPanelFriends::refreshRightsChangeList() { - - const uuid_vec_t friends = mFriendsList->getSelectedIDs(); - - S32 num_selected = friends.size(); - bool can_offer_teleport = num_selected >= 1; - bool selected_friends_online = true; - - /*LLTextBox* processing_label = getChild("process_rights_label"); - - if(!mAllowRightsChange) - { - if(processing_label) - { - processing_label->setVisible(true); - // ignore selection for now - friends.clear(); - num_selected = 0; - } - } - else if(processing_label) - { - processing_label->setVisible(false); - } Making Dummy View -HgB */ - const LLRelationship* friend_status = NULL; - for(uuid_vec_t::const_iterator itr = friends.begin(); itr != friends.end(); ++itr) - { - friend_status = LLAvatarTracker::instance().getBuddyInfo(*itr); - if (friend_status) - { - if(!friend_status->isOnline()) - { - can_offer_teleport = false; - selected_friends_online = false; - } - } - else // missing buddy info, don't allow any operations - { - can_offer_teleport = false; - } - } + S32 num_selected = mFriendsList->getNumSelected(); //Stuff for the online/total/select counts. - getChild("s_num")->setValue(llformat("%d", num_selected)); getChild("f_num")->setValue(llformat("%d / %d", mNumOnline, mFriendsList->getItemCount())); - - if (num_selected == 0) // nothing selected + + if (!num_selected) // nothing selected { - childSetEnabled("im_btn", FALSE); - //childSetEnabled("assign_btn", FALSE); - childSetEnabled("offer_teleport_btn", FALSE); + getChildView("im_btn")->setEnabled(false); + //getChildView("assign_btn")->setEnabled(false); + getChildView("offer_teleport_btn")->setEnabled(false); } else // we have at least one friend selected... { - // only allow IMs to groups when everyone in the group is online - // to be consistent with context menus in inventory and because otherwise - // offline friends would be silently dropped from the session - childSetEnabled("im_btn", selected_friends_online || num_selected == 1); - //childSetEnabled("assign_btn", num_selected == 1); - childSetEnabled("offer_teleport_btn", can_offer_teleport); + getChildView("im_btn")->setEnabled(true); + //getChildView("assign_btn")->setEnabled(num_selected == 1); + getChildView("offer_teleport_btn")->setEnabled(true); } } @@ -621,29 +494,23 @@ struct SortFriendsByID void LLPanelFriends::refreshNames(U32 changed_mask) { - const uuid_vec_t selected_ids = mFriendsList->getSelectedIDs(); + const uuid_vec_t selected_ids = mFriendsList->getSelectedIDs(); S32 pos = mFriendsList->getScrollPos(); // get all buddies we know about LLAvatarTracker::buddy_map_t all_buddies; LLAvatarTracker::instance().copyBuddyList(all_buddies); - BOOL have_names = TRUE; - - if(changed_mask & (LLFriendObserver::ADD | LLFriendObserver::REMOVE)) + if (changed_mask & (LLFriendObserver::ADD | LLFriendObserver::REMOVE)) { - have_names &= refreshNamesSync(all_buddies); + refreshNamesSync(all_buddies); } - if(changed_mask & LLFriendObserver::ONLINE) + if (changed_mask & LLFriendObserver::ONLINE) { - have_names &= refreshNamesPresence(all_buddies); + refreshNamesPresence(all_buddies); } - if (!have_names) - { - mEventTimer.start(); - } // Changed item in place, need to request sort and update columns // because we might have changed data in a column on which the user // has already sorted. JC @@ -654,41 +521,30 @@ void LLPanelFriends::refreshNames(U32 changed_mask) mFriendsList->setScrollPos(pos); } -BOOL LLPanelFriends::refreshNamesSync(const LLAvatarTracker::buddy_map_t & all_buddies) +void LLPanelFriends::refreshNamesSync(const LLAvatarTracker::buddy_map_t& all_buddies) { mNumOnline = 0; mFriendsList->deleteAllItems(); - BOOL have_names = TRUE; - LLAvatarTracker::buddy_map_t::const_iterator buddy_it = all_buddies.begin(); - - for(; buddy_it != all_buddies.end(); ++buddy_it) + for(LLAvatarTracker::buddy_map_t::const_iterator buddy_it = all_buddies.begin(); buddy_it != all_buddies.end(); ++buddy_it) { - have_names &= addFriend(buddy_it->first); + addFriend(buddy_it->first); } - - return have_names; } -BOOL LLPanelFriends::refreshNamesPresence(const LLAvatarTracker::buddy_map_t & all_buddies) +void LLPanelFriends::refreshNamesPresence(const LLAvatarTracker::buddy_map_t& all_buddies) { std::vector items = mFriendsList->getAllData(); std::sort(items.begin(), items.end(), SortFriendsByID()); LLAvatarTracker::buddy_map_t::const_iterator buddy_it = all_buddies.begin(); std::vector::const_iterator item_it = items.begin(); - BOOL have_names = TRUE; - while(true) + while(item_it != items.end() && buddy_it != all_buddies.end()) { - if(item_it == items.end() || buddy_it == all_buddies.end()) - { - break; - } - - const LLUUID & buddy_uuid = buddy_it->first; - const LLUUID & item_uuid = (*item_it)->getValue().asUUID(); - if(item_uuid == buddy_uuid) + const LLUUID& buddy_uuid = buddy_it->first; + const LLUUID& item_uuid = (*item_it)->getValue().asUUID(); + if (item_uuid == buddy_uuid) { const LLRelationship* info = buddy_it->second; if (!info) @@ -696,18 +552,18 @@ BOOL LLPanelFriends::refreshNamesPresence(const LLAvatarTracker::buddy_map_t & a ++item_it; continue; } - + S32 last_change_generation = (*item_it)->getColumn(LIST_FRIEND_UPDATE_GEN)->getValue().asInteger(); if (last_change_generation < info->getChangeSerialNum()) { // update existing item in UI - have_names &= updateFriendItem(buddy_it->first, info); + updateFriendItem(buddy_it->first, info); } ++buddy_it; ++item_it; } - else if(item_uuid < buddy_uuid) + else if (item_uuid < buddy_uuid) { ++item_it; } @@ -716,199 +572,110 @@ BOOL LLPanelFriends::refreshNamesPresence(const LLAvatarTracker::buddy_map_t & a ++buddy_it; } } - - return have_names; } + // meal disk void LLPanelFriends::refreshUI() -{ - BOOL single_selected = FALSE; - BOOL multiple_selected = FALSE; - int num_selected = mFriendsList->getAllSelected().size(); - if(num_selected > 0) +{ + bool single_selected = false; + bool multiple_selected = false; + size_t num_selected = mFriendsList->getAllSelected().size(); + if (num_selected) { - single_selected = TRUE; - if(num_selected > 1) + single_selected = true; + if (num_selected > 1) { - multiple_selected = TRUE; + multiple_selected = true; } } //Options that can only be performed with one friend selected - childSetEnabled("profile_btn", single_selected && !multiple_selected); - childSetEnabled("pay_btn", single_selected && !multiple_selected); - //childSetEnabled("assign_btn", single_selected && !multiple_selected); + getChildView("pay_btn")->setEnabled(single_selected && !multiple_selected); + //getChildView("assign_btn")->setEnabled(single_selected && !multiple_selected); - //Options that can be performed with up to MAX_FRIEND_SELECT friends selected + //Options that can be performed with multiple friends selected //(single_selected will always be true in this situations) - childSetEnabled("remove_btn", single_selected); - childSetEnabled("im_btn", single_selected); - //childSetEnabled("friend_rights", single_selected); Making Dummy View -HgB + getChildView("profile_btn")->setEnabled(single_selected); + getChildView("remove_btn")->setEnabled(single_selected); + getChildView("im_btn")->setEnabled(single_selected); + //getChildView("friend_rights")->setEnabled(single_selected); Making Dummy View -HgB refreshRightsChangeList(); } -// static -void LLPanelFriends::onSelectName(LLUICtrl* ctrl, void* user_data) -{ - LLPanelFriends* panelp = (LLPanelFriends*)user_data; - - if(panelp) - { - panelp->refreshUI(); - // check to see if rights have changed - panelp->applyRightsToFriends(); - } -} - -// static -void LLPanelFriends::onClickProfile(void* user_data) +void LLPanelFriends::onSelectName() { - LLPanelFriends* panelp = (LLPanelFriends*)user_data; - - //llinfos << "LLPanelFriends::onClickProfile()" << llendl; - const uuid_vec_t ids = panelp->mFriendsList->getSelectedIDs(); - if(!ids.empty()) - { - LLAvatarActions::showProfile(ids[0]); - } + refreshUI(); + // check to see if rights have changed + applyRightsToFriends(); } -// static -/*void LLPanelFriends::onClickAssign(void* user_data) -{ - LLPanelFriends* panelp = (LLPanelFriends*)user_data; - if (panelp) - { - const uuid_vec_t ids = panelp->mFriendsList->getSelectedIDs(); - ASFloaterContactGroups::show(ids); - } -}*/ - -// static -void LLPanelFriends::onClickExpand(void* user_data) +void LLPanelFriends::updateColumns(bool collapsed) { - BOOL collapsed = gSavedSettings.getBOOL("ContactListCollapsed"); - gSavedSettings.setBOOL("ContactListCollapsed", !collapsed); - updateColumns(user_data); + //LL_INFOS() << "Refreshing UI" << LL_ENDL; + S32 width = collapsed ? 0 : 22; + LLScrollListColumn* column = mFriendsList->getColumn(5); + mFriendsList->updateStaticColumnWidth(column, width); + column->setWidth(width); + column = mFriendsList->getColumn(6); + mFriendsList->updateStaticColumnWidth(column, width); + column->setWidth(width); + column = mFriendsList->getColumn(7); + mFriendsList->updateStaticColumnWidth(column, width); + column->setWidth(width); + mFriendsList->updateLayout(); + if (!collapsed) updateFriends(LLFriendObserver::ADD); } -void LLPanelFriends::updateColumns(void* user_data) +void LLPanelFriends::onClickIM(const uuid_vec_t& ids) { - LLPanelFriends* panelp = (LLPanelFriends*)user_data; - if (panelp) - { - LLButton* expand_button = panelp->getChild("expand_collapse_btn"); - LLScrollListCtrl* list = panelp->getChild("friend_list"); - //llinfos << "Refreshing UI" << llendl; - S32 width = 22; - std::string button = ">"; - if (gSavedSettings.getBOOL("ContactListCollapsed")) - { - width = 0; - button = "<"; - } - expand_button->setLabel(button); - LLScrollListColumn* column = list->getColumn(5); - list->updateStaticColumnWidth(column, width); - column->setWidth(width); - column = list->getColumn(6); - list->updateStaticColumnWidth(column, width); - column->setWidth(width); - column = list->getColumn(7); - list->updateStaticColumnWidth(column, width); - column->setWidth(width); - list->updateLayout(); - if (!gSavedSettings.getBOOL("ContactListCollapsed")) - { - panelp->updateFriends(LLFriendObserver::ADD); - } - } -} - -void LLPanelFriends::onClickIM(void* user_data) -{ - LLPanelFriends* panelp = (LLPanelFriends*)user_data; - - //llinfos << "LLPanelFriends::onClickIM()" << llendl; - const uuid_vec_t ids = panelp->mFriendsList->getSelectedIDs(); - if(!ids.empty()) - { - if(ids.size() == 1) - { - LLAvatarActions::startIM(ids[0]); - } - else - { - LLAvatarActions::startConference(ids); - } - } + //LL_INFOS() << "LLPanelFriends::onClickIM()" << LL_ENDL; + if (!ids.empty()) + ids.size() == 1 ? LLAvatarActions::startIM(ids[0]) : LLAvatarActions::startConference(ids); } // static -void LLPanelFriends::onPickAvatar( const uuid_vec_t& ids, - const std::vector& names ) +void LLPanelFriends::onPickAvatar(const uuid_vec_t& ids, const std::vector& names) { - if (names.empty()) return; - if (ids.empty()) return; + if (names.empty() || ids.empty()) return; LLAvatarActions::requestFriendshipDialog(ids[0], names[0].getCompleteName()); } -// static -void LLPanelFriends::onClickAddFriend(void* user_data) +void LLPanelFriends::onClickAddFriend() { - LLPanelFriends* panelp = (LLPanelFriends*)user_data; - LLFloater* root_floater = gFloaterView->getParentFloater(panelp); - LLFloaterAvatarPicker* picker = LLFloaterAvatarPicker::show(boost::bind(&LLPanelFriends::onPickAvatar, _1, _2), FALSE, TRUE); - if (root_floater) - { - root_floater->addDependentFloater(picker); - } + if (LLFloater* root_floater = gFloaterView->getParentFloater(this)) + root_floater->addDependentFloater(LLFloaterAvatarPicker::show(boost::bind(&LLPanelFriends::onPickAvatar, _1, _2), false, true)); } -void LLPanelFriends::onClickExport(void* user_data) +/* Singu Note: We don't currently use these. +void LLPanelFriends::onClickExport() { std::string agn; gAgent.getName(agn); AIFilePicker* filepicker = AIFilePicker::create(); filepicker->open(agn + ".friendlist", FFSAVE_ALL); - filepicker->run(boost::bind(&LLPanelFriends::onClickExport_continued, user_data, filepicker)); + filepicker->run(boost::bind(&LLPanelFriends::onClickExport_continued, this, filepicker)); } -void LLPanelFriends::onClickExport_continued(void* user_data, AIFilePicker* filepicker) +void LLPanelFriends::onClickExport_continued(AIFilePicker* filepicker) { - if(!filepicker->hasFilename()) - { - // User canceled save. - return; - } - std::string const filename = filepicker->getFilename(); - LLPanelFriends* panelp = (LLPanelFriends*)user_data; - std::vector selected = panelp->mFriendsList->getAllData();//->getAllSelected(); + if(!filepicker->hasFilename()) return; + + const std::string filename(filepicker->getFilename()); + std::vector selected = mFriendsList->getAllData(); LLSD llsd; - //U32 count = 0; - //std::string friendlist; - for(std::vector::iterator itr = selected.begin(); itr != selected.end(); ++itr) + for(std::vector::const_iterator itr = selected.begin(); itr != selected.end(); ++itr) { - LLSD fraind; - std::string friend_name = (*itr)->getColumn(LIST_FRIEND_NAME)->getValue().asString(); - std::string friend_uuid = (*itr)->getUUID().asString(); - bool show_online_status = (*itr)->getColumn(LIST_VISIBLE_ONLINE)->getValue().asBoolean(); - bool show_map_location = (*itr)->getColumn(LIST_VISIBLE_MAP)->getValue().asBoolean(); - bool allow_modify_objects = (*itr)->getColumn(LIST_EDIT_MINE)->getValue().asBoolean(); - fraind["name"] = friend_name; - fraind["see_online"] = show_online_status; - fraind["can_map"] = show_map_location; - fraind["can_mod"] = allow_modify_objects; - //friendlist += friend_name+"|"+friend_uuid+"|"+show_online_status+"|"+show_map_location+"|"+allow_modify_objects+"\n"; - llsd[friend_uuid] = fraind; - //count += 1; + const LLScrollListItem* it(*itr); + LLSD& fraind = llsd[it->getUUID().asString()]; + fraind["name"] = it->getColumn(LIST_FRIEND_NAME)->getValue().asString(); + fraind["see_online"] = it->getColumn(LIST_VISIBLE_ONLINE)->getValue().asBoolean(); + fraind["can_map"] = it->getColumn(LIST_VISIBLE_MAP)->getValue().asBoolean(); + fraind["can_mod"] = it->getColumn(LIST_EDIT_MINE)->getValue().asBoolean(); } - std::string grid_uri = gHippoGridManager->getConnectedGrid()->getLoginUri(); - //LLStringUtil::toLower(uris[0]); - llsd["GRID"] = grid_uri; + llsd["GRID"] = gHippoGridManager->getConnectedGrid()->getLoginUri(); llofstream export_file; export_file.open(filename); @@ -940,7 +707,7 @@ void LLPanelFriends::onClickImport_filepicker_continued(AIFilePicker* filepicker if(data.has("GRID")) { std::string grid = gHippoGridManager->getConnectedGrid()->getLoginUri(); - if(grid != data["GRID"])return; + if (grid != data["GRID"])return; data.erase("GRID"); } @@ -951,24 +718,22 @@ void LLPanelFriends::onClickImport_filepicker_continued(AIFilePicker* filepicker #endif std::string importstate = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "friendimportstate.dat"); - + llifstream stateload(importstate); LLSD importstatellsd; LLSDSerialize::fromXMLDocument(importstatellsd, stateload); static bool merging; - //LLMessageSystem* msg = gMessageSystem; LLSD newdata; - LLSD::map_const_iterator iter; - for(iter = data.beginMap(); iter != data.endMap(); ++iter) + for(LLSD::map_const_iterator iter = data.beginMap(); iter != data.endMap(); ++iter) {//first= var second = val LLSD content = iter->second; - if(!content.has("name"))continue; - if(!content.has("see_online"))continue; - if(!content.has("can_map"))continue; - if(!content.has("can_mod"))continue; + if (!content.has("name")) continue; + if (!content.has("see_online")) continue; + if (!content.has("can_map")) continue; + if (!content.has("can_mod")) continue; LLUUID agent_id = LLUUID(iter->first); if(merging && importstatellsd.has(agent_id.asString()))continue;//dont need to request what we've already requested from another list import and have not got a reply yet @@ -979,19 +744,13 @@ void LLPanelFriends::onClickImport_filepicker_continued(AIFilePicker* filepicker if(merging)importstatellsd[agent_id.asString()] = content;//MERGEEEE LLAvatarActions::requestFriendship(agent_id, agent_name, "Imported from "+file); newdata[iter->first] = iter->second; - }else - { - //data.erase(iter->first); - //--iter;//god help us all } } - data = newdata; - newdata = LLSD(); if(!merging) { merging = true;//this hack is to support importing multiple account lists without spamming users but considering LLs fail in forcing silent declines - importstatellsd = data; + importstatellsd = newdata; } llofstream export_file; @@ -1014,14 +773,11 @@ void LLPanelFriends::FriendImportState(LLUUID id, bool accepted) LLSD user = data[id.asString()]; if(accepted) { - BOOL can_map = user["can_map"].asBoolean(); - BOOL can_mod = user["can_mod"].asBoolean(); - BOOL see_online = user["see_online"].asBoolean(); S32 rights = 0; - if(can_map)rights |= LLRelationship::GRANT_MAP_LOCATION; - if(can_mod)rights |= LLRelationship::GRANT_MODIFY_OBJECTS; - if(see_online)rights |= LLRelationship::GRANT_ONLINE_STATUS; - if(LLAvatarActions::isFriend(id))//is this legit shit yo + if (user["can_map"].asBoolean()) rights |= LLRelationship::GRANT_MAP_LOCATION; + if (user["can_mod"].asBoolean()) rights |= LLRelationship::GRANT_MODIFY_OBJECTS; + if (user["see_online"].asBoolean()) rights |= LLRelationship::GRANT_ONLINE_STATUS; + if (LLAvatarActions::isFriend(id)) //is this legit shit yo { const LLRelationship* friend_status = LLAvatarTracker::instance().getBuddyInfo(id); if(friend_status) @@ -1032,8 +788,8 @@ void LLPanelFriends::FriendImportState(LLUUID id, bool accepted) LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_GrantUserRights); msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUID(_PREHASH_AgentID, gAgent.getID()); - msg->addUUID(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addUUID(_PREHASH_AgentID, gAgentID); + msg->addUUID(_PREHASH_SessionID, gAgentSessionID); msg->nextBlockFast(_PREHASH_Rights); msg->addUUID(_PREHASH_AgentRelated, id); msg->addS32(_PREHASH_RelatedRights, rights); @@ -1050,81 +806,43 @@ void LLPanelFriends::FriendImportState(LLUUID id, bool accepted) export_file.close(); } } - -// static -void LLPanelFriends::onClickPay(void* user_data) -{ - LLPanelFriends* panelp = (LLPanelFriends*)user_data; - - const uuid_vec_t ids = panelp->mFriendsList->getSelectedIDs(); - if(!ids.empty()) - { - LLAvatarActions::pay(ids[0]); - } -} +*/ void LLPanelFriends::confirmModifyRights(rights_map_t& rights, EGrantRevoke command) { if (rights.empty()) return; - // Make a copy on the heap: rights is allocated on the stack. - // This copy will be deleted in LLPanelFriends::modifyRightsConfirmation. - rights_map_t* heap_rights = new rights_map_t(rights); - // for single friend, show their name if (rights.size() == 1) { LLSD args; std::string fullname; - if (LLAvatarNameCache::getPNSName(rights.begin()->first, fullname)) + if (LLAvatarNameCache::getNSName(rights.begin()->first, fullname, friend_name_system())) args["NAME"] = fullname; - if (command == GRANT) - { - LLNotificationsUtil::add("GrantModifyRights", - args, - LLSD(), - boost::bind(&LLPanelFriends::modifyRightsConfirmation, this, _1, _2, heap_rights)); - } - else - { - LLNotificationsUtil::add("RevokeModifyRights", - args, - LLSD(), - boost::bind(&LLPanelFriends::modifyRightsConfirmation, this, _1, _2, heap_rights)); - } + LLNotificationsUtil::add(command == GRANT ? "GrantModifyRights" : "RevokeModifyRights", + args, LLSD(), + boost::bind(&LLPanelFriends::modifyRightsConfirmation, this, _1, _2, rights)); } else { - if (command == GRANT) - { - LLNotificationsUtil::add("GrantModifyRightsMultiple", - LLSD(), - LLSD(), - boost::bind(&LLPanelFriends::modifyRightsConfirmation, this, _1, _2, heap_rights)); - } - else - { - LLNotificationsUtil::add("RevokeModifyRightsMultiple", - LLSD(), - LLSD(), - boost::bind(&LLPanelFriends::modifyRightsConfirmation, this, _1, _2, heap_rights)); - } + LLNotificationsUtil::add(command == GRANT ? "GrantModifyRightsMultiple" : "RevokeModifyRightsMultiple", + LLSD(), LLSD(), + boost::bind(&LLPanelFriends::modifyRightsConfirmation, this, _1, _2, rights)); } } -bool LLPanelFriends::modifyRightsConfirmation(const LLSD& notification, const LLSD& response, rights_map_t* rights) +bool LLPanelFriends::modifyRightsConfirmation(const LLSD& notification, const LLSD& response, rights_map_t rights) { S32 option = LLNotificationsUtil::getSelectedOption(notification, response); if(0 == option) { - sendRightsGrant(*rights); + sendRightsGrant(rights); } else { // need to resync view with model, since user cancelled operation - rights_map_t::iterator rights_it; - for (rights_it = rights->begin(); rights_it != rights->end(); ++rights_it) + for (rights_map_t::iterator rights_it = rights.begin(); rights_it != rights.end(); ++rights_it) { const LLRelationship* info = LLAvatarTracker::instance().getBuddyInfo(rights_it->first); updateFriendItem(rights_it->first, info); @@ -1132,18 +850,15 @@ bool LLPanelFriends::modifyRightsConfirmation(const LLSD& notification, const LL } refreshUI(); - delete rights; return false; } void LLPanelFriends::applyRightsToFriends() { - BOOL rights_changed = FALSE; - // store modify rights separately for confirmation rights_map_t rights_updates; - BOOL need_confirmation = FALSE; + bool need_confirmation = false; EGrantRevoke confirmation_type = GRANT; // this assumes that changes only happened to selected items @@ -1152,17 +867,18 @@ void LLPanelFriends::applyRightsToFriends() { LLUUID id = (*itr)->getValue(); const LLRelationship* buddy_relationship = LLAvatarTracker::instance().getBuddyInfo(id); - if (buddy_relationship == NULL) continue; + if (!buddy_relationship) continue; bool show_online_staus = (*itr)->getColumn(LIST_VISIBLE_ONLINE)->getValue().asBoolean(); bool show_map_location = (*itr)->getColumn(LIST_VISIBLE_MAP)->getValue().asBoolean(); bool allow_modify_objects = (*itr)->getColumn(LIST_EDIT_MINE)->getValue().asBoolean(); + bool rights_changed(false); S32 rights = buddy_relationship->getRightsGrantedTo(); - if(buddy_relationship->isRightGrantedTo(LLRelationship::GRANT_ONLINE_STATUS) != show_online_staus) + if (buddy_relationship->isRightGrantedTo(LLRelationship::GRANT_ONLINE_STATUS) != show_online_staus) { - rights_changed = TRUE; - if(show_online_staus) + rights_changed = true; + if (show_online_staus) { rights |= LLRelationship::GRANT_ONLINE_STATUS; } @@ -1172,19 +888,19 @@ void LLPanelFriends::applyRightsToFriends() rights &= ~LLRelationship::GRANT_ONLINE_STATUS; rights &= ~LLRelationship::GRANT_MAP_LOCATION; // propagate rights constraint to UI - (*itr)->getColumn(LIST_VISIBLE_MAP)->setValue(FALSE); + (*itr)->getColumn(LIST_VISIBLE_MAP)->setValue(false); mFriendsList->setNeedsSortColumn(LIST_VISIBLE_MAP); } } - if(buddy_relationship->isRightGrantedTo(LLRelationship::GRANT_MAP_LOCATION) != show_map_location) + if (buddy_relationship->isRightGrantedTo(LLRelationship::GRANT_MAP_LOCATION) != show_map_location) { - rights_changed = TRUE; - if(show_map_location) + rights_changed = true; + if (show_map_location) { // ONLINE_STATUS necessary for MAP_LOCATION rights |= LLRelationship::GRANT_MAP_LOCATION; rights |= LLRelationship::GRANT_ONLINE_STATUS; - (*itr)->getColumn(LIST_VISIBLE_ONLINE)->setValue(TRUE); + (*itr)->getColumn(LIST_VISIBLE_ONLINE)->setValue(true); mFriendsList->setNeedsSortColumn(LIST_VISIBLE_ONLINE); } else @@ -1194,12 +910,12 @@ void LLPanelFriends::applyRightsToFriends() } // now check for change in modify object rights, which requires confirmation - if(buddy_relationship->isRightGrantedTo(LLRelationship::GRANT_MODIFY_OBJECTS) != allow_modify_objects) + if (buddy_relationship->isRightGrantedTo(LLRelationship::GRANT_MODIFY_OBJECTS) != allow_modify_objects) { - rights_changed = TRUE; - need_confirmation = TRUE; + rights_changed = true; + need_confirmation = true; - if(allow_modify_objects) + if (allow_modify_objects) { rights |= LLRelationship::GRANT_MODIFY_OBJECTS; confirmation_type = GRANT; @@ -1212,12 +928,7 @@ void LLPanelFriends::applyRightsToFriends() } if (rights_changed) - { rights_updates.insert(std::make_pair(id, rights)); - // disable these ui elements until response from server - // to avoid race conditions - (*itr)->setEnabled(FALSE); - } } // separately confirm grant and revoke of modify rights @@ -1240,8 +951,8 @@ void LLPanelFriends::sendRightsGrant(rights_map_t& ids) // setup message header msg->newMessageFast(_PREHASH_GrantUserRights); msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUID(_PREHASH_AgentID, gAgent.getID()); - msg->addUUID(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addUUID(_PREHASH_AgentID, gAgentID); + msg->addUUID(_PREHASH_SessionID, gAgentSessionID); rights_map_t::iterator id_it; rights_map_t::iterator end_it = ids.end(); @@ -1252,6 +963,5 @@ void LLPanelFriends::sendRightsGrant(rights_map_t& ids) msg->addS32(_PREHASH_RelatedRights, id_it->second); } - mNumRightsChanged = ids.size(); gAgent.sendReliableMessage(); } diff --git a/indra/newview/llfloaterfriends.h b/indra/newview/llfloaterfriends.h index c82db7886a..2fddc7b636 100644 --- a/indra/newview/llfloaterfriends.h +++ b/indra/newview/llfloaterfriends.h @@ -38,15 +38,14 @@ #include "llpanel.h" #include "llstring.h" #include "lluuid.h" -#include "lleventtimer.h" + #include "llcallingcard.h" class LLAvatarName; class LLFriendObserver; class LLRelationship; -class LLScrollListItem; class LLScrollListCtrl; -class AIFilePicker; +class LLScrollListItem; /** * @class LLPanelFriends @@ -55,19 +54,12 @@ class AIFilePicker; * * @sa LLFloater */ -class LLPanelFriends : public LLPanel, public LLEventTimer +class LLPanelFriends : public LLPanel { public: LLPanelFriends(); virtual ~LLPanelFriends(); - /** - * @brief This method either creates or brings to the front the - * current instantiation of this floater. There is only once since - * you can currently only look at your local friends. - */ - virtual BOOL tick(); - /** * @brief This method is called in response to the LLAvatarTracker * sending out a changed() message. @@ -99,16 +91,16 @@ class LLPanelFriends : public LLPanel, public LLEventTimer // Contacts search and group system void filterContacts(const std::string& search_name); void categorizeContacts(); - void setContactGroup(std::string contact_grp); - std::string cleanFileName(std::string filename); + void setContactGroup(const std::string& contact_grp); + //std::string cleanFileName(std::string filename); // -- - BOOL refreshNamesSync(const LLAvatarTracker::buddy_map_t & all_buddies); - BOOL refreshNamesPresence(const LLAvatarTracker::buddy_map_t & all_buddies); + void refreshNamesSync(const LLAvatarTracker::buddy_map_t & all_buddies); + void refreshNamesPresence(const LLAvatarTracker::buddy_map_t & all_buddies); void refreshUI(); void refreshRightsChangeList(); void applyRightsToFriends(); - BOOL addFriend(const LLUUID& agent_id); - BOOL updateFriendItem(const LLUUID& agent_id, const LLRelationship* relationship); + void addFriend(const LLUUID& agent_id); + void updateFriendItem(const LLUUID& agent_id, const LLRelationship* relationship); typedef enum { @@ -119,27 +111,22 @@ class LLPanelFriends : public LLPanel, public LLEventTimer void sendRightsGrant(rights_map_t& ids); // callback methods - static void onSelectName(LLUICtrl* ctrl, void* user_data); - static void onChangeContactGroup(LLUICtrl* ctrl, void* user_data); - static void onPickAvatar(const uuid_vec_t& ids, const std::vector& names ); - void onContactFilterEdit(const std::string& search_string); - static void onClickIM(void* user_data); - static void onClickAssign(void* user_data); - static void onClickExpand(void* user_data); - static void updateColumns(void* user_data); - static void onClickProfile(void* user_data); - static void onClickAddFriend(void* user_data); - static void onClickExport(void* user_data); - static void onClickExport_continued(void* user_data, AIFilePicker* filepicker); - static void onClickImport(void* user_data); - static void onClickImport_filepicker_continued(AIFilePicker* filepicker); + void onSelectName(); + static void onPickAvatar(const uuid_vec_t& ids, const std::vector& names); + void onClickIM(const uuid_vec_t& ids); + void updateColumns(bool collapsed); + void onClickAddFriend(); +/* + void onClickExport(); + void onClickExport_continued(class AIFilePicker* filepicker); + void onClickImport(); + void onClickImport_filepicker_continued(AIFilePicker* filepicker); +*/ public: static void FriendImportState(LLUUID id, bool accepted); private: - static void onClickPay(void* user_data); - static void onClickModifyStatus(LLUICtrl* ctrl, void* user_data); - bool modifyRightsConfirmation(const LLSD& notification, const LLSD& response, rights_map_t* rights); + bool modifyRightsConfirmation(const LLSD& notification, const LLSD& response, rights_map_t rights); private: // member data @@ -147,13 +134,8 @@ class LLPanelFriends : public LLPanel, public LLEventTimer LLUUID mAddFriendID; std::string mAddFriendName; LLScrollListCtrl* mFriendsList; - std::string mContactFilter; - BOOL mShowMaxSelectWarning; - BOOL mAllowRightsChange; - S32 mNumRightsChanged; S32 mNumOnline; std::string mLastContactSearch; }; - #endif // LL_LLFLOATERFRIENDS_H diff --git a/indra/newview/llfloatergesture.cpp b/indra/newview/llfloatergesture.cpp index 4a146a4e21..e01cb02670 100644 --- a/indra/newview/llfloatergesture.cpp +++ b/indra/newview/llfloatergesture.cpp @@ -34,32 +34,24 @@ #include "llfloatergesture.h" -#include "lldir.h" #include "llinventory.h" #include "llmultigesture.h" #include "llagent.h" -#include "llviewerwindow.h" -#include "llbutton.h" -#include "llcombobox.h" -#include "llgesturemgr.h" #include "llfloaterinventory.h" +#include "llfloaterperms.h" +#include "llgesturemgr.h" #include "llinventorymodel.h" #include "llinventorypanel.h" #include "llkeyboard.h" -#include "lllineeditor.h" #include "llpreviewgesture.h" -#include "llresizehandle.h" -#include "llscrollbar.h" -#include "llscrollcontainer.h" #include "llscrolllistctrl.h" -#include "lltextbox.h" #include "lluictrlfactory.h" #include "llviewergesture.h" -#include "llviewertexturelist.h" #include "llviewerinventory.h" +#include "llviewertexturelist.h" +#include "llviewerwindow.h" #include "llvoavatar.h" -#include "llviewercontrol.h" // static LLFloaterGesture* LLFloaterGesture::sInstance = NULL; @@ -174,9 +166,9 @@ void LLFloaterGesture::show() } // static -void LLFloaterGesture::toggleVisibility() +void LLFloaterGesture::toggleInstance(const LLSD&) { - if(sInstance && sInstance->getVisible()) + if (instanceVisible()) { sInstance->close(); } @@ -187,7 +179,7 @@ void LLFloaterGesture::toggleVisibility() } // static -bool LLFloaterGesture::instanceVisible() +bool LLFloaterGesture::instanceVisible(const LLSD&) { return sInstance && sInstance->getVisible(); } @@ -339,7 +331,7 @@ void LLFloaterGesture::onClickInventory(void* data) if (!list) return; const LLUUID& item_id = list->getCurrentID(); - LLInventoryView* inv = LLInventoryView::showAgentInventory(); + LLPanelMainInventory* inv = LLPanelMainInventory::showAgentInventory(); if (!inv) return; inv->getPanel()->setSelection(item_id, TRUE); } @@ -367,27 +359,38 @@ void LLFloaterGesture::onClickPlay(void* data) class GestureShowCallback : public LLInventoryCallback { public: - GestureShowCallback(std::string &title) - { - mTitle = title; - } void fire(const LLUUID &inv_item) { - LLPreviewGesture::show(mTitle, inv_item, LLUUID::null); + LLPreviewGesture::show("Gesture: New Gesture", inv_item, LLUUID::null); + + LLInventoryItem* item = gInventory.getItem(inv_item); + if (item) + { + LLPermissions perm = item->getPermissions(); + perm.setMaskNext(LLFloaterPerms::getNextOwnerPerms("Gestures")); + perm.setMaskEveryone(LLFloaterPerms::getEveryonePerms("Gestures")); + perm.setMaskGroup(LLFloaterPerms::getGroupPerms("Gestures")); + item->setPermissions(perm); + item->updateServer(FALSE); + } } -private: - std::string mTitle; }; // static void LLFloaterGesture::onClickNew(void* data) { - std::string title("Gesture: "); - title.append("New Gesture"); - LLPointer cb = new GestureShowCallback(title); - create_inventory_item(gAgent.getID(), gAgent.getSessionID(), - LLUUID::null, LLTransactionID::tnull, "New Gesture", "", LLAssetType::AT_GESTURE, - LLInventoryType::IT_GESTURE, NOT_WEARABLE, PERM_MOVE | PERM_TRANSFER, cb); + LLPointer cb = new GestureShowCallback(); + create_inventory_item(gAgent.getID(), + gAgent.getSessionID(), + LLUUID::null, + LLTransactionID::tnull, + "New Gesture", + "", + LLAssetType::AT_GESTURE, + LLInventoryType::IT_GESTURE, + NOT_WEARABLE, + LLFloaterPerms::getNextOwnerPerms("Gestures"), + cb); } diff --git a/indra/newview/llfloatergesture.h b/indra/newview/llfloatergesture.h index 0ded594676..a64495b0af 100644 --- a/indra/newview/llfloatergesture.h +++ b/indra/newview/llfloatergesture.h @@ -39,8 +39,6 @@ #include "llfloater.h" -#include "lldarray.h" - class LLScrollContainer; class LLView; class LLButton; @@ -62,9 +60,9 @@ class LLFloaterGesture virtual BOOL postBuild(); static void show(); - static void toggleVisibility(); + static void toggleInstance(const LLSD& = LLSD()); static void refreshAll(); - static bool instanceVisible(); + static bool instanceVisible(const LLSD& = LLSD()); protected: // Reads from the gesture manager's list of active gestures diff --git a/indra/newview/llfloatergodtools.cpp b/indra/newview/llfloatergodtools.cpp index fc42879825..7e58612762 100644 --- a/indra/newview/llfloatergodtools.cpp +++ b/indra/newview/llfloatergodtools.cpp @@ -118,6 +118,8 @@ void LLFloaterGodTools::refreshAll() LLFloaterGodTools::LLFloaterGodTools() : LLFloater(std::string("godtools floater")), + mPanelRegionTools(nullptr), + mPanelObjectTools(nullptr), mCurrentHost(LLHost::invalid), mUpdateTimer() { @@ -554,7 +556,7 @@ void LLPanelRegionTools::onSaveState(void* userdata) gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); gMessageSystem->nextBlockFast(_PREHASH_DataBlock); - gMessageSystem->addStringFast(_PREHASH_Filename, NULL); + gMessageSystem->addStringFast(_PREHASH_Filename, nullptr); gAgent.sendReliableMessage(); } } @@ -831,7 +833,7 @@ void LLPanelRegionTools::onSwapTerrain() void LLPanelRegionTools::onSelectRegion() { - llinfos << "LLPanelRegionTools::onSelectRegion" << llendl; + LL_INFOS() << "LLPanelRegionTools::onSelectRegion" << LL_ENDL; LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromPosGlobal(gAgent.getPositionGlobal()); if (!regionp) @@ -1330,8 +1332,8 @@ void LLPanelRequestTools::sendRequest(const std::string& request, const std::string& parameter, const LLHost& host) { - llinfos << "Sending request '" << request << "', '" - << parameter << "' to " << host << llendl; + LL_INFOS() << "Sending request '" << request << "', '" + << parameter << "' to " << host << LL_ENDL; LLMessageSystem* msg = gMessageSystem; msg->newMessage("GodlikeMessage"); msg->nextBlockFast(_PREHASH_AgentData); @@ -1352,7 +1354,7 @@ void LLPanelRequestTools::onClickRequest() if(dest == SELECTION) { std::string req =getChild("request")->getValue(); - req = req.substr(0, req.find_first_of(" ")); + req = req.substr(0, req.find_first_of(' ')); std::string param = getChild("parameter")->getValue(); LLSelectMgr::getInstance()->sendGodlikeRequest(req, param); } @@ -1384,7 +1386,7 @@ void terrain_download_done(void** data, S32 status, LLExtStat ext_status) void test_callback(const LLTSCode status) { - llinfos << "Test transfer callback returned!" << llendl; + LL_INFOS() << "Test transfer callback returned!" << LL_ENDL; } @@ -1399,11 +1401,11 @@ void LLPanelRequestTools::sendRequest(const LLHost& host) host, FALSE, terrain_download_done, - NULL); + nullptr); } else { - req = req.substr(0, req.find_first_of(" ")); + req = req.substr(0, req.find_first_of(' ')); sendRequest(req, getChild("parameter")->getValue().asString(), host); } } diff --git a/indra/newview/llfloatergroupbulkban.cpp b/indra/newview/llfloatergroupbulkban.cpp new file mode 100644 index 0000000000..b1aaa993a6 --- /dev/null +++ b/indra/newview/llfloatergroupbulkban.cpp @@ -0,0 +1,131 @@ +/** +* @file llfloatergroupbulkban.cpp +* @brief Floater to ban Residents from a group. +* +* $LicenseInfo:firstyear=2013&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2013, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#include "llviewerprecompiledheaders.h" + +#include "llfloatergroupbulkban.h" +#include "llpanelgroupbulkban.h" +#include "lltrans.h" +#include "lldraghandle.h" + +const LLRect FGB_RECT(0, 320, 210, 0); + +class LLFloaterGroupBulkBan::impl +{ +public: + impl(const LLUUID& group_id) : mGroupID(group_id), mBulkBanPanelp(NULL) {} + ~impl() {} + + static void closeFloater(void* data); + +public: + LLUUID mGroupID; + LLPanelGroupBulkBan* mBulkBanPanelp; + + static std::map sInstances; +}; + +// +// Globals +// +std::map LLFloaterGroupBulkBan::impl::sInstances; + +void LLFloaterGroupBulkBan::impl::closeFloater(void* data) +{ + LLFloaterGroupBulkBan* floaterp = (LLFloaterGroupBulkBan*)data; + if(floaterp) + floaterp->close(); +} + +//----------------------------------------------------------------------------- +// Implementation +//----------------------------------------------------------------------------- +LLFloaterGroupBulkBan::LLFloaterGroupBulkBan(const std::string& name, + const LLRect &rect, + const std::string& title, + const LLUUID& group_id) +: LLFloater(name, rect, title) +{ + S32 floater_header_size = LLFLOATER_HEADER_SIZE; + LLRect contents(getRect()); + contents.mTop -= floater_header_size; + + mImpl = new impl(group_id); + mImpl->mBulkBanPanelp = new LLPanelGroupBulkBan(group_id); + + setTitle(mImpl->mBulkBanPanelp->getString("GroupBulkBan")); + mImpl->mBulkBanPanelp->setCloseCallback(impl::closeFloater, this); + mImpl->mBulkBanPanelp->setRect(contents); + + addChild(mImpl->mBulkBanPanelp); +} + +LLFloaterGroupBulkBan::~LLFloaterGroupBulkBan() +{ + if(mImpl->mGroupID.notNull()) + { + impl::sInstances.erase(mImpl->mGroupID); + } + + delete mImpl->mBulkBanPanelp; + delete mImpl; +} + +void LLFloaterGroupBulkBan::showForGroup(const LLUUID& group_id, uuid_vec_t* agent_ids) +{ + // Make sure group_id isn't null + if (group_id.isNull()) + { + LL_WARNS() << "LLFloaterGroupInvite::showForGroup with null group_id!" << LL_ENDL; + return; + } + + // If we don't have a floater for this group, create one. + LLFloaterGroupBulkBan* fgb = get_if_there(impl::sInstances, + group_id, + (LLFloaterGroupBulkBan*)NULL); + if (!fgb) + { + fgb = new LLFloaterGroupBulkBan("groupban", + FGB_RECT, + "Group Ban", + group_id); + fgb->getDragHandle()->setTitle(fgb->mImpl->mBulkBanPanelp->getString("GroupBulkBan")); + + impl::sInstances[group_id] = fgb; + + fgb->mImpl->mBulkBanPanelp->clear(); + } + + if (agent_ids != NULL) + { + fgb->mImpl->mBulkBanPanelp->addUsers(*agent_ids); + } + + fgb->center(); + fgb->open(); + fgb->mImpl->mBulkBanPanelp->update(); +} diff --git a/indra/newview/llfloatergroupbulkban.h b/indra/newview/llfloatergroupbulkban.h new file mode 100644 index 0000000000..5eb29b1b65 --- /dev/null +++ b/indra/newview/llfloatergroupbulkban.h @@ -0,0 +1,51 @@ + /** +* @file llfloatergroupbulkban.h +* @brief This floater is a wrapper for LLPanelGroupBulkBan, which +* is used to ban Residents from a specific group. +* +* $LicenseInfo:firstyear=2013&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2013, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#ifndef LL_LLFLOATERGROUPBULKBAN_H +#define LL_LLFLOATERGROUPBULKBAN_H + +#include "llfloater.h" +#include "lluuid.h" + +class LLFloaterGroupBulkBan : public LLFloater +{ +public: + virtual ~LLFloaterGroupBulkBan(); + + static void showForGroup(const LLUUID& group_id, uuid_vec_t* agent_ids = NULL); + +protected: + LLFloaterGroupBulkBan(const std::string& name, + const LLRect& rect, + const std::string& title, + const LLUUID& group_id = LLUUID::null); + + class impl; + impl* mImpl; +}; + +#endif // LL_LLFLOATERGROUPBULKBAN_H diff --git a/indra/newview/llfloatergroupinvite.cpp b/indra/newview/llfloatergroupinvite.cpp index 08a6269a04..656854e41e 100644 --- a/indra/newview/llfloatergroupinvite.cpp +++ b/indra/newview/llfloatergroupinvite.cpp @@ -112,12 +112,12 @@ LLFloaterGroupInvite::~LLFloaterGroupInvite() } // static -void LLFloaterGroupInvite::showForGroup(const LLUUID& group_id, std::vector *agent_ids) +void LLFloaterGroupInvite::showForGroup(const LLUUID& group_id, uuid_vec_t *agent_ids) { // Make sure group_id isn't null if (group_id.isNull()) { - llwarns << "LLFloaterGroupInvite::showForGroup with null group_id!" << llendl; + LL_WARNS() << "LLFloaterGroupInvite::showForGroup with null group_id!" << LL_ENDL; return; } diff --git a/indra/newview/llfloatergroupinvite.h b/indra/newview/llfloatergroupinvite.h index d1485ead91..48c15c3aa0 100644 --- a/indra/newview/llfloatergroupinvite.h +++ b/indra/newview/llfloatergroupinvite.h @@ -43,7 +43,7 @@ class LLFloaterGroupInvite public: virtual ~LLFloaterGroupInvite(); - static void showForGroup(const LLUUID &group_id, std::vector *agent_ids = NULL); + static void showForGroup(const LLUUID &group_id, uuid_vec_t *agent_ids = NULL); protected: LLFloaterGroupInvite(const std::string& name, diff --git a/indra/newview/llfloatergroups.cpp b/indra/newview/llfloatergroups.cpp index 00d31dd1cd..f696bcef0a 100644 --- a/indra/newview/llfloatergroups.cpp +++ b/indra/newview/llfloatergroups.cpp @@ -45,6 +45,7 @@ #include "hbfloatergrouptitles.h" #include "llagent.h" +#include "llagentbenefits.h" #include "llbutton.h" #include "llfloatergroupinvite.h" #include "llgroupactions.h" @@ -182,20 +183,27 @@ LLPanelGroups::~LLPanelGroups() gAgent.removeListener(this); } +void LLPanelGroups::setTexts() +{ + LLUICtrl* ctrl(getChild("groupcount")); + size_t count(gAgent.mGroups.size()); + ctrl->setTextArg("[COUNT]", llformat("%d", count)); + int maxgroups(LLAgentBenefitsMgr::current().getGroupMembershipLimit()); + ctrl->setTextArg("[MAX]", llformat("%d", maxgroups)); + ctrl->setTextArg("[LEFT]", llformat("%d", maxgroups - count)); +} + // clear the group list, and get a fresh set of info. void LLPanelGroups::reset() { - getChild("groupcount")->setTextArg("[COUNT]", llformat("%d",gAgent.mGroups.count())); - getChild("groupcount")->setTextArg("[MAX]", llformat("%d", gHippoLimits->getMaxAgentGroups())); - + setTexts(); init_group_list(getChild("group list"), gAgent.getGroupID()); enableButtons(); } BOOL LLPanelGroups::postBuild() { - getChild("groupcount")->setTextArg("[COUNT]", llformat("%d",gAgent.mGroups.count())); - getChild("groupcount")->setTextArg("[MAX]", llformat("%d",gHippoLimits->getMaxAgentGroups())); + setTexts(); LLScrollListCtrl *list = getChild("group list"); if (list) @@ -231,21 +239,20 @@ BOOL LLPanelGroups::postBuild() void LLPanelGroups::enableButtons() { - LLCtrlListInterface *group_list = childGetListInterface("group list"); + getChildView("Create")->setEnabled(gAgent.canJoinGroups()); + LLScrollListCtrl* group_list = getChild("group list"); + if (!group_list) return; LLUUID group_id; - if (group_list) + if (group_list->getNumSelected() == 1) { group_id = group_list->getCurrentID(); - } - - if(group_id != gAgent.getGroupID()) - { - getChildView("Activate")->setEnabled(TRUE); + getChildView("Activate")->setEnabled(group_id != gAgent.getGroupID()); } else { getChildView("Activate")->setEnabled(FALSE); } + if (group_id.notNull()) { getChildView("Info")->setEnabled(TRUE); @@ -258,7 +265,6 @@ void LLPanelGroups::enableButtons() getChildView("IM")->setEnabled(FALSE); getChildView("Leave")->setEnabled(FALSE); } - getChildView("Create")->setEnabled(gAgent.mGroups.count() < gHippoLimits->getMaxAgentGroups()); getChildView("Invite...")->setEnabled(group_id.notNull() && gAgent.hasPowerInGroup(group_id, GP_MEMBER_INVITE)); } @@ -370,7 +376,6 @@ LLSD create_group_element(const LLGroupData *group_datap, const LLUUID &active_g void init_group_list(LLScrollListCtrl* ctrl, const LLUUID& highlight_id, U64 powers_mask) { - S32 count = gAgent.mGroups.count(); LLUUID id; LLCtrlListInterface *group_list = ctrl->getListInterface(); if (!group_list) return; @@ -381,11 +386,16 @@ void init_group_list(LLScrollListCtrl* ctrl, const LLUUID& highlight_id, U64 pow group_list->operateOnAll(LLCtrlListInterface::OP_DELETE); - for(S32 i = 0; i < count; ++i) + for(const auto& group : gAgent.mGroups) { - LLSD element = create_group_element(&gAgent.mGroups.get(i), highlight_id, powers_mask); - if(element.size()) + LLSD element = create_group_element(&group, highlight_id, powers_mask); + if (element.size()) + { group_list->addElement(element, ADD_SORTED); + // Force a name lookup here to get it added to the cache so other UI is prepared + std::string dummy; + gCacheName->getGroupName(group.mID, dummy); + } } // add "none" to list at top diff --git a/indra/newview/llfloatergroups.h b/indra/newview/llfloatergroups.h index 8af8e03c31..36a6844c64 100644 --- a/indra/newview/llfloatergroups.h +++ b/indra/newview/llfloatergroups.h @@ -48,7 +48,10 @@ #include "llfloater.h" #include "llinstancetracker.h" #include +#ifndef BOOST_FUNCTION_HPP_INCLUDED #include +#define BOOST_FUNCTION_HPP_INCLUDED +#endif #include class LLUICtrl; @@ -106,6 +109,9 @@ class LLPanelGroups : public LLPanel, public LLOldEvents::LLSimpleListener // initialize based on the type BOOL postBuild(); + // set the text displays + void setTexts(); + // highlight_id is a group id to highlight void enableButtons(); diff --git a/indra/newview/llfloaterhtml.cpp b/indra/newview/llfloaterhtml.cpp index a5d24f4d82..25e6613c60 100644 --- a/indra/newview/llfloaterhtml.cpp +++ b/indra/newview/llfloaterhtml.cpp @@ -199,7 +199,7 @@ void LLFloaterHtml::onClickHome( void* data ) } else { - llwarns << "Invalid home page specified for HTML floater - navigating to default" << llendl; + LL_WARNS() << "Invalid home page specified for HTML floater - navigating to default" << LL_ENDL; self->mWebBrowser->navigateTo( "http://secondlife.com" ); } }; diff --git a/indra/newview/llfloaterimagepreview.cpp b/indra/newview/llfloaterimagepreview.cpp index 74093f2434..6db06034f5 100644 --- a/indra/newview/llfloaterimagepreview.cpp +++ b/indra/newview/llfloaterimagepreview.cpp @@ -40,6 +40,7 @@ #include "llimagej2c.h" #include "llagent.h" +#include "llagentbenefits.h" #include "llbutton.h" #include "llcombobox.h" #include "lldrawable.h" @@ -96,7 +97,8 @@ BOOL LLFloaterImagePreview::postBuild() return FALSE; } - childSetLabelArg("ok_btn", "[UPLOADFEE]", gHippoGridManager->getConnectedGrid()->getUploadFee()); + auto& grid = *gHippoGridManager->getConnectedGrid(); + childSetLabelArg("ok_btn", "[UPLOADFEE]", grid.formatFee(LLAgentBenefitsMgr::current().getTextureUploadCost())); LLCtrlSelectionInterface* iface = childGetSelectionInterface("clothing_type_combo"); if (iface) @@ -126,7 +128,11 @@ BOOL LLFloaterImagePreview::postBuild() // gSavedSettings.setBOOL("TemporaryUpload",FALSE); - childSetValue("temp_check",FALSE); + auto child = getChildView("temp_check"); + if (grid.isSecondLife()) + child->setVisible(false); + else + child->setValue(false); // } else @@ -252,7 +258,7 @@ void LLFloaterImagePreview::draw() if (selected <= 0) { gl_rect_2d_checkerboard( calcScreenRect(), mPreviewRect); - LLGLDisable gls_alpha(GL_ALPHA_TEST); + LLGLDisable gls_alpha; if(mImagep.notNull()) { @@ -277,16 +283,16 @@ void LLFloaterImagePreview::draw() } gGL.color3f(1.f, 1.f, 1.f); - gGL.begin( LLRender::QUADS ); + gGL.begin( LLRender::TRIANGLE_STRIP ); { gGL.texCoord2f(mPreviewImageRect.mLeft, mPreviewImageRect.mTop); gGL.vertex2i(PREVIEW_HPAD, PREVIEW_TEXTURE_HEIGHT); gGL.texCoord2f(mPreviewImageRect.mLeft, mPreviewImageRect.mBottom); gGL.vertex2i(PREVIEW_HPAD, PREVIEW_HPAD + PREF_BUTTON_HEIGHT + PREVIEW_HPAD); - gGL.texCoord2f(mPreviewImageRect.mRight, mPreviewImageRect.mBottom); - gGL.vertex2i(r.getWidth() - PREVIEW_HPAD, PREVIEW_HPAD + PREF_BUTTON_HEIGHT + PREVIEW_HPAD); gGL.texCoord2f(mPreviewImageRect.mRight, mPreviewImageRect.mTop); gGL.vertex2i(r.getWidth() - PREVIEW_HPAD, PREVIEW_TEXTURE_HEIGHT); + gGL.texCoord2f(mPreviewImageRect.mRight, mPreviewImageRect.mBottom); + gGL.vertex2i(r.getWidth() - PREVIEW_HPAD, PREVIEW_HPAD + PREF_BUTTON_HEIGHT + PREVIEW_HPAD); } gGL.end(); @@ -309,16 +315,16 @@ void LLFloaterImagePreview::draw() gGL.getTexUnit(0)->bind(mAvatarPreview); } - gGL.begin( LLRender::QUADS ); + gGL.begin( LLRender::TRIANGLE_STRIP ); { gGL.texCoord2f(0.f, 1.f); gGL.vertex2i(PREVIEW_HPAD, PREVIEW_TEXTURE_HEIGHT); gGL.texCoord2f(0.f, 0.f); gGL.vertex2i(PREVIEW_HPAD, PREVIEW_HPAD + PREF_BUTTON_HEIGHT + PREVIEW_HPAD); - gGL.texCoord2f(1.f, 0.f); - gGL.vertex2i(r.getWidth() - PREVIEW_HPAD, PREVIEW_HPAD + PREF_BUTTON_HEIGHT + PREVIEW_HPAD); gGL.texCoord2f(1.f, 1.f); gGL.vertex2i(r.getWidth() - PREVIEW_HPAD, PREVIEW_TEXTURE_HEIGHT); + gGL.texCoord2f(1.f, 0.f); + gGL.vertex2i(r.getWidth() - PREVIEW_HPAD, PREVIEW_HPAD + PREF_BUTTON_HEIGHT + PREVIEW_HPAD); } gGL.end(); @@ -621,15 +627,8 @@ LLImagePreviewAvatar::LLImagePreviewAvatar(S32 width, S32 height) : LLViewerDyna mCameraPitch = 0.f; mCameraZoom = 1.f; - mDummyAvatar = (LLVOAvatar*)gObjectList.createObjectViewer(LL_PCODE_LEGACY_AVATAR, gAgent.getRegion()); - mDummyAvatar->createDrawable(&gPipeline); - mDummyAvatar->mIsDummy = TRUE; + mDummyAvatar = (LLVOAvatar*)gObjectList.createObjectViewer(LL_PCODE_LEGACY_AVATAR, gAgent.getRegion(), LLViewerObject::CO_FLAG_UI_AVATAR); mDummyAvatar->mSpecialRenderMode = 2; - mDummyAvatar->setPositionAgent(LLVector3::zero); - mDummyAvatar->slamPosition(); - mDummyAvatar->updateJointLODs(); - mDummyAvatar->updateGeometry(mDummyAvatar->mDrawable); - // gPipeline.markVisible(mDummyAvatar->mDrawable, *LLViewerCamera::getInstance()); mTextureName = 0; } @@ -757,13 +756,14 @@ BOOL LLImagePreviewAvatar::render() { LLGLDepthTest gls_depth(GL_TRUE, GL_TRUE); // make sure alpha=0 shows avatar material color - LLGLDisable no_blend(GL_BLEND); + LLGLDisable no_blend; LLFace* face = avatarp->mDrawable->getFace(0); if (face) { LLDrawPoolAvatar *avatarPoolp = (LLDrawPoolAvatar *)face->getPool(); - gPipeline.enableLightsPreview(); + LLGLState light_state; + gPipeline.enableLightsPreview(light_state); avatarPoolp->renderAvatars(avatarp); // renders only one avatar } } @@ -848,7 +848,7 @@ void LLImagePreviewSculpted::setPreviewTarget(LLImageRaw* imagep, F32 distance) if (imagep) { - mVolume->sculpt(imagep->getWidth(), imagep->getHeight(), imagep->getComponents(), imagep->getData(), 0); + mVolume->sculpt(imagep->getWidth(), imagep->getHeight(), imagep->getComponents(), imagep->getData(), 0, false); } const LLVolumeFace &vf = mVolume->getVolumeFace(0); @@ -900,8 +900,8 @@ BOOL LLImagePreviewSculpted::render() { mNeedsUpdate = FALSE; LLGLSUIDefault def; - LLGLDisable no_blend(GL_BLEND); - LLGLEnable cull(GL_CULL_FACE); + LLGLDisable no_blend; + LLGLEnable cull; LLGLDepthTest depth(GL_TRUE); gGL.matrixMode(LLRender::MM_PROJECTION); @@ -928,6 +928,7 @@ BOOL LLImagePreviewSculpted::render() gGL.matrixMode(LLRender::MM_MODELVIEW); gGL.popMatrix(); + gGL.syncContextState(); glClear(GL_DEPTH_BUFFER_BIT); LLVector3 target_pos(0, 0, 0); @@ -950,13 +951,14 @@ BOOL LLImagePreviewSculpted::render() const LLVolumeFace &vf = mVolume->getVolumeFace(0); U32 num_indices = vf.mNumIndices; - gPipeline.enableLightsAvatar(); + LLGLState light_state; + gPipeline.enableLightsAvatar(light_state); if (LLGLSLShader::sNoFixedFunction) { gObjectPreviewProgram.bind(); } - gPipeline.enableLightsPreview(); + gPipeline.enableLightsPreview(light_state); gGL.pushMatrix(); const F32 SCALE = 1.25f; diff --git a/indra/newview/llfloaterimagepreview.h b/indra/newview/llfloaterimagepreview.h index c2186450a9..0acb80fd89 100644 --- a/indra/newview/llfloaterimagepreview.h +++ b/indra/newview/llfloaterimagepreview.h @@ -52,6 +52,16 @@ class LLImagePreviewSculpted : public LLViewerDynamicTexture public: LLImagePreviewSculpted(S32 width, S32 height); + void* operator new(size_t size) + { + return ll_aligned_malloc_16(size); + } + + void operator delete(void* ptr) + { + ll_aligned_free_16(ptr); + } + /*virtual*/ S8 getType() const ; void setPreviewTarget(LLImageRaw *imagep, F32 distance); @@ -85,6 +95,16 @@ class LLImagePreviewAvatar : public LLViewerDynamicTexture public: LLImagePreviewAvatar(S32 width, S32 height); + void* operator new(size_t size) + { + return ll_aligned_malloc_16(size); + } + + void operator delete(void* ptr) + { + ll_aligned_free_16(ptr); + } + /*virtual*/ S8 getType() const ; void setPreviewTarget(const std::string& joint_name, const std::string& mesh_name, LLImageRaw* imagep, F32 distance, BOOL male); diff --git a/indra/newview/llfloaterinspect.cpp b/indra/newview/llfloaterinspect.cpp index 448e1bb37e..01dd84dc18 100644 --- a/indra/newview/llfloaterinspect.cpp +++ b/indra/newview/llfloaterinspect.cpp @@ -52,11 +52,13 @@ //LLFloaterInspect* LLFloaterInspect::sInstance = NULL; -LLFloaterInspect::LLFloaterInspect() +LLFloaterInspect::LLFloaterInspect(const LLSD&) : LLFloater(std::string("Inspect Object")), + mObjectList(nullptr), mDirty(FALSE) { mCommitCallbackRegistrar.add("Inspect.OwnerProfile", boost::bind(&LLFloaterInspect::onClickOwnerProfile, this)); + mCommitCallbackRegistrar.add("Inspect.LastOwnerProfile", boost::bind(&LLFloaterInspect::onClickLastOwnerProfile, this)); mCommitCallbackRegistrar.add("Inspect.CreatorProfile", boost::bind(&LLFloaterInspect::onClickCreatorProfile, this)); mCommitCallbackRegistrar.add("Inspect.SelectObject", boost::bind(&LLFloaterInspect::onSelectObject, this)); LLUICtrlFactory::getInstance()->buildFloater(this, "floater_inspect.xml"); @@ -89,13 +91,6 @@ LLFloaterInspect::~LLFloaterInspect(void) { gFloaterTools->setFocus(TRUE); } - //sInstance = NULL; -} - -// static -void LLFloaterInspect::showInstance() -{ - getInstance()->open(); } void LLFloaterInspect::onOpen() @@ -131,7 +126,7 @@ void LLFloaterInspect::onClickCreatorProfile() // LLAvatarActions::showProfile(node->mPermissions->getCreator()); // [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.2a) | Modified: RLVa-1.0.0e const LLUUID& idCreator = node->mPermissions->getCreator(); - if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES) || gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS)) && ((node->mPermissions->getOwner() == idCreator) || (RlvUtil::isNearbyAgent(idCreator))) ) { return; @@ -164,7 +159,7 @@ void LLFloaterInspect::onClickOwnerProfile() { const LLUUID& owner_id = node->mPermissions->getOwner(); // [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.2a) | Modified: RLVa-1.0.0e - if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES) || gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS)) return; // [/RLVa:KB] LLAvatarActions::showProfile(owner_id); @@ -172,6 +167,36 @@ void LLFloaterInspect::onClickOwnerProfile() } } +void LLFloaterInspect::onClickLastOwnerProfile() +{ + if(mObjectList->getAllSelected().size() == 0) return; + LLScrollListItem* first_selected =mObjectList->getFirstSelected(); + + if (first_selected) + { + LLUUID selected_id = first_selected->getUUID(); + struct f : public LLSelectedNodeFunctor + { + LLUUID obj_id; + f(const LLUUID& id) : obj_id(id) {} + virtual bool apply(LLSelectNode* node) + { + return (obj_id == node->getObject()->getID()); + } + } func(selected_id); + LLSelectNode* node = mObjectSelection->getFirstNode(&func); + if(node) + { + const LLUUID& last_owner_id = node->mPermissions->getLastOwner(); +// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.2a) | Modified: RLVa-1.0.0e + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES) || gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS)) + if (last_owner_id == node->mPermissions->getOwner()) return; +// [/RLVa:KB] + LLAvatarActions::showProfile(last_owner_id); + } + } +} + void LLFloaterInspect::onSelectObject() { if(LLFloaterInspect::getSelectedUUID() != LLUUID::null) @@ -179,7 +204,7 @@ void LLFloaterInspect::onSelectObject() // getChildView("button owner")->setEnabled(true); // getChildView("button creator")->setEnabled(true); // [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.2a) | Modified: RLVa-1.0.0e - getChildView("button owner")->setEnabled(!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)); + getChildView("button owner")->setEnabled(!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES) && !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS)); // TODO-RLVa: [RLVa-1.2.2] Is it worth checking the selected node just to selectively disable this button? getChildView("button creator")->setEnabled(true); // [/RLVa:KB] @@ -199,15 +224,6 @@ LLUUID LLFloaterInspect::getSelectedUUID() return LLUUID::null; } -void LLFloaterInspect::onGetAvNameCallback(const LLUUID& idCreator, const LLAvatarName& av_name, void* FloaterPtr) -{ - if (FloaterPtr) - { - LLFloaterInspect* floater = (LLFloaterInspect*)FloaterPtr; - floater->dirty(); - } -} - void LLFloaterInspect::refresh() { LLUUID creator_id; @@ -234,15 +250,14 @@ void LLFloaterInspect::refresh() { LLSelectNode* obj = *iter; LLSD row; - std::string owner_name, creator_name, time, last_owner_name; + std::string owner_name, creator_name, last_owner_name; if (obj->mCreationDate == 0) { // Don't have valid information from the server, so skip this one continue; } - time_t timestamp = (time_t) (obj->mCreationDate/1000000); - timeToFormattedString(timestamp, gSavedSettings.getString("TimestampFormat"), time); + // Singu Note: Diverge from LL and handle datetime column in a sortable manner later on const LLUUID& idOwner = obj->mPermissions->getOwner(); const LLUUID& idCreator = obj->mPermissions->getCreator(); @@ -256,54 +271,57 @@ void LLFloaterInspect::refresh() // actual name and set a placeholder. if (LLAvatarNameCache::get(idOwner, &av_name)) { -// owner_name = av_name.getCompleteName(); +// owner_name = av_name.getNSName(); // [RLVa:KB] - Checked: 2010-11-01 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a - bool fRlvFilterOwner = (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (idOwner != gAgent.getID()) && + bool fRlvFilterOwner = (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES) || gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS)) && (idOwner != gAgent.getID()) && (!obj->mPermissions->isGroupOwned()); - owner_name = (!fRlvFilterOwner) ? av_name.getCompleteName() : RlvStrings::getAnonym(av_name); + owner_name = (!fRlvFilterOwner) ? av_name.getNSName() : RlvStrings::getAnonym(av_name); // [/RLVa:KB] } else { owner_name = LLTrans::getString("RetrievingData"); - LLAvatarNameCache::get(idOwner, boost::bind(&LLFloaterInspect::onGetAvNameCallback, _1, _2, this)); - } - - if (LLAvatarNameCache::get(idCreator, &av_name)) - { -// creator_name = av_name.getCompleteName(); -// [RLVa:KB] - Checked: 2010-11-01 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a - const LLUUID& idCreator = obj->mPermissions->getCreator(); - LLAvatarNameCache::get(idCreator, &av_name); - bool fRlvFilterCreator = (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (idCreator != gAgent.getID()) && - ( (obj->mPermissions->getOwner() == idCreator) || (RlvUtil::isNearbyAgent(idCreator)) ); - creator_name = (!fRlvFilterCreator) ? av_name.getCompleteName() : RlvStrings::getAnonym(av_name); -// [/RLVa:KB] - } - else - { - creator_name = LLTrans::getString("RetrievingData"); - LLAvatarNameCache::get(idCreator, boost::bind(&LLFloaterInspect::onGetAvNameCallback, _1, _2, this)); + if (mOwnerNameCacheConnection.find(idOwner) == mOwnerNameCacheConnection.end()) + mOwnerNameCacheConnection.emplace(idOwner, LLAvatarNameCache::get(idOwner, boost::bind(&LLFloaterInspect::onGetOwnerNameCallback, this, _1))); } // if (LLAvatarNameCache::get(idLastOwner, &av_name)) { -// last_owner_name = av_name.getCompleteName(); +// last_owner_name = av_name.getNSName(); // [RLVa:LF] - Copied from the above creator check Checked: 2010-11-01 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a LLAvatarNameCache::get(idLastOwner, &av_name); - bool fRlvFilterLastOwner = (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (idLastOwner != gAgent.getID()) && - ( (obj->mPermissions->getOwner() == idLastOwner) || (RlvUtil::isNearbyAgent(idLastOwner)) ); - last_owner_name = (!fRlvFilterLastOwner) ? av_name.getCompleteName() : RlvStrings::getAnonym(av_name); + bool fRlvFilterLastOwner = (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES) || gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS)) && idLastOwner != gAgent.getID() && + (obj->mPermissions->getOwner() == idLastOwner || RlvUtil::isNearbyAgent(idLastOwner)); + last_owner_name = (!fRlvFilterLastOwner) ? av_name.getNSName() : RlvStrings::getAnonym(av_name); // [/RLVa:LF] } else { last_owner_name = LLTrans::getString("RetrievingData"); - LLAvatarNameCache::get(idLastOwner, boost::bind(&LLFloaterInspect::onGetAvNameCallback, _1, _2, this)); + if (mLastOwnerNameCacheConnection.find(idLastOwner) == mLastOwnerNameCacheConnection.end()) + mLastOwnerNameCacheConnection.emplace(idLastOwner, LLAvatarNameCache::get(idLastOwner, boost::bind(&LLFloaterInspect::onGetLastOwnerNameCallback, this, _1))); } // + if (LLAvatarNameCache::get(idCreator, &av_name)) + { +// creator_name = av_name.getNSName(); +// [RLVa:KB] - Checked: 2010-11-01 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a + const LLUUID& idCreator = obj->mPermissions->getCreator(); + LLAvatarNameCache::get(idCreator, &av_name); + bool fRlvFilterCreator = (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES) || gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS)) && (idCreator != gAgent.getID()) && + ( (obj->mPermissions->getOwner() == idCreator) || (RlvUtil::isNearbyAgent(idCreator)) ); + creator_name = (!fRlvFilterCreator) ? av_name.getNSName() : RlvStrings::getAnonym(av_name); +// [/RLVa:KB] + } + else + { + creator_name = LLTrans::getString("RetrievingData"); + if (mCreatorNameCacheConnection.find(idCreator) == mCreatorNameCacheConnection.end()) + mCreatorNameCacheConnection.emplace(idCreator, LLAvatarNameCache::get(idCreator, boost::bind(&LLFloaterInspect::onGetCreatorNameCallback, this, _1))); + } + row["id"] = obj->getObject()->getID(); row["columns"][0]["column"] = "object_name"; row["columns"][0]["type"] = "text"; @@ -338,8 +356,8 @@ void LLFloaterInspect::refresh() row["columns"][5]["value"] = llformat("%d",obj->getObject()->getNumVertices()); // inventory silliness S32 scripts,total_inv; - std::map >::iterator itr = mInventoryNums.find(obj->getObject()->getID()); - if(itr != mInventoryNums.end()) + std::map >::iterator itr = mInventoryNums.find(obj->getObject()->getID()); + if (itr != mInventoryNums.end()) { scripts = itr->second.first; total_inv = itr->second.second; @@ -348,10 +366,10 @@ void LLFloaterInspect::refresh() { scripts = 0; total_inv = 0; - if(std::find(mQueue.begin(),mQueue.end(),obj->getObject()->getID()) == mQueue.end()) + if (std::find(mQueue.begin(),mQueue.end(),obj->getObject()->getID()) == mQueue.end()) { mQueue.push_back(obj->getObject()->getID()); - registerVOInventoryListener(obj->getObject(),NULL); + registerVOInventoryListener(obj->getObject(), NULL); requestVOInventory(); } } @@ -363,8 +381,10 @@ void LLFloaterInspect::refresh() row["columns"][7]["value"] = llformat("%d",total_inv); // row["columns"][8]["column"] = "creation_date"; - row["columns"][8]["type"] = "text"; - row["columns"][8]["value"] = time; + row["columns"][8]["type"] = "date"; + row["columns"][8]["value"] = LLDate(obj->mCreationDate/1000000); + static const LLCachedControl format("TimestampFormat"); + row["columns"][8]["format"] = format; mObjectList->addElement(row, ADD_TOP); } if(selected_index > -1 && mObjectList->getItemIndex(selected_uuid) == selected_index) @@ -380,23 +400,19 @@ void LLFloaterInspect::refresh() } // -void LLFloaterInspect::inventoryChanged(LLViewerObject* viewer_object, LLInventoryObject::object_list_t* inv, S32, void* q_id) +void LLFloaterInspect::inventoryChanged(LLViewerObject* viewer_object, LLInventoryObject::object_list_t* inv, S32, void*) { - std::vector::iterator iter = std::find(mQueue.begin(),mQueue.end(),viewer_object->getID()); - if (viewer_object && inv && iter != mQueue.end() ) + auto iter = std::find(mQueue.begin(),mQueue.end(),viewer_object->getID()); + if (viewer_object && inv && iter != mQueue.end()) { - S32 scripts = 0; + U32 scripts = 0; LLInventoryObject::object_list_t::const_iterator end = inv->end(); for (LLInventoryObject::object_list_t::const_iterator it = inv->begin(); it != end; ++it) - { - if((*it)->getType() == LLAssetType::AT_LSL_TEXT) - { + if ((*it)->getType() == LLAssetType::AT_LSL_TEXT) ++scripts; - } - } mInventoryNums[viewer_object->getID()] = std::make_pair(scripts,inv->size()); mQueue.erase(iter); - mDirty = TRUE; + setDirty(); } } // @@ -416,6 +432,24 @@ void LLFloaterInspect::dirty() setDirty(); } +void LLFloaterInspect::onGetOwnerNameCallback(const LLUUID& id) +{ + mOwnerNameCacheConnection.erase(id); + setDirty(); +} + +void LLFloaterInspect::onGetLastOwnerNameCallback(const LLUUID& id) +{ + mLastOwnerNameCacheConnection.erase(id); + setDirty(); +} + +void LLFloaterInspect::onGetCreatorNameCallback(const LLUUID& id) +{ + mCreatorNameCacheConnection.erase(id); + setDirty(); +} + void LLFloaterInspect::draw() { if (mDirty) diff --git a/indra/newview/llfloaterinspect.h b/indra/newview/llfloaterinspect.h index 52e6a7f9aa..3769cedf77 100644 --- a/indra/newview/llfloaterinspect.h +++ b/indra/newview/llfloaterinspect.h @@ -44,12 +44,11 @@ class LLObjectSelection; class LLScrollListCtrl; class LLUICtrl; -class LLFloaterInspect : public LLFloater, public LLSingleton, public LLVOInventoryListener +class LLFloaterInspect : public LLFloater, public LLFloaterSingleton, public LLVOInventoryListener { - friend class LLSingleton; + friend class LLUISingleton >; public: - static void showInstance(); // static void show(void* ignored = NULL); void onOpen(); virtual BOOL postBuild(); @@ -61,10 +60,9 @@ class LLFloaterInspect : public LLFloater, public LLSingleton, virtual void onFocusReceived(); void onClickCreatorProfile(); void onClickOwnerProfile(); + void onClickLastOwnerProfile(); void onSelectObject(); - static void onGetAvNameCallback(const LLUUID& idCreator, const LLAvatarName& av_name, void* FloaterPtr); - LLScrollListCtrl* mObjectList; protected: // protected members @@ -75,16 +73,21 @@ class LLFloaterInspect : public LLFloater, public LLSingleton, // private: - LLFloaterInspect(); + void onGetOwnerNameCallback(const LLUUID& id); + void onGetLastOwnerNameCallback(const LLUUID& id); // + void onGetCreatorNameCallback(const LLUUID& id); + + LLFloaterInspect(const LLSD& key); virtual ~LLFloaterInspect(void); - // static data -// static LLFloaterInspect* sInstance; LLSafeHandle mObjectSelection; // - std::map > mInventoryNums; // - std::vector mQueue; + std::map > mInventoryNums; // + uuid_vec_t mQueue; // + std::map mOwnerNameCacheConnection; + std::map mLastOwnerNameCacheConnection; // + std::map mCreatorNameCacheConnection; }; #endif //LL_LLFLOATERINSPECT_H diff --git a/indra/newview/llfloaterjoystick.cpp b/indra/newview/llfloaterjoystick.cpp index c067b78a70..da8385485b 100644 --- a/indra/newview/llfloaterjoystick.cpp +++ b/indra/newview/llfloaterjoystick.cpp @@ -49,6 +49,9 @@ LLFloaterJoystick::LLFloaterJoystick(const LLSD& data) : LLFloater("floater_joystick") + , mCheckJoystickEnabled(nullptr) + , mCheckFlycamEnabled(nullptr) + , mAxisStatsBar({ {nullptr,nullptr,nullptr,nullptr,nullptr,nullptr} }) { LLUICtrlFactory::getInstance()->buildFloater(this, "floater_joystick.xml"); center(); @@ -56,27 +59,21 @@ LLFloaterJoystick::LLFloaterJoystick(const LLSD& data) void LLFloaterJoystick::draw() { + // Singu TODO: Cache these children, or consider not doing this in the draw call bool joystick_inited = LLViewerJoystick::getInstance()->isJoystickInitialized(); childSetEnabled("enable_joystick", joystick_inited); - childSetEnabled("joystick_type", joystick_inited); + auto type(getChild("joystick_type")); + type->setEnabled(joystick_inited); std::string desc = LLViewerJoystick::getInstance()->getDescription(); if (desc.empty()) desc = getString("NoDevice"); - childSetText("joystick_type", desc); + type->setValue(desc); LLViewerJoystick* joystick(LLViewerJoystick::getInstance()); - for (U32 i = 0; i < 6; i++) + for (U32 i = 0; i < 6; ++i) { F32 value = joystick->getJoystickAxis(i); + mAxisStatsBar[i]->fit(value); mAxisStats[i]->addValue(value * gFrameIntervalSeconds); - - if (mAxisStatsBar[i]->mMinBar > value) - { - mAxisStatsBar[i]->mMinBar = value; - } - if (mAxisStatsBar[i]->mMaxBar < value) - { - mAxisStatsBar[i]->mMaxBar = value; - } } LLFloater::draw(); @@ -112,11 +109,12 @@ BOOL LLFloaterJoystick::postBuild() axis.setArg("[NUM]", llformat("%d", i)); std::string stat_name(llformat("Joystick axis %d", i)); mAxisStats[i] = new LLStat(stat_name,4); - mAxisStatsBar[i] = mAxisStatsView->addStat(axis, mAxisStats[i]); - mAxisStatsBar[i]->mMinBar = -range; - mAxisStatsBar[i]->mMaxBar = range; - mAxisStatsBar[i]->mLabelSpacing = range * 0.5f; - mAxisStatsBar[i]->mTickSpacing = range * 0.25f; + LLStatBar::Parameters params; + params.mMinBar = -range; + params.mMaxBar = range; + params.mLabelSpacing = range * 0.5f; + params.mTickSpacing = range * 0.25f; + mAxisStatsBar[i] = mAxisStatsView->addStat(axis, mAxisStats[i], params); } addChild(mAxisStatsView); @@ -126,7 +124,7 @@ BOOL LLFloaterJoystick::postBuild() mCheckFlycamEnabled = getChild("JoystickFlycamEnabled"); childSetCommitCallback("JoystickFlycamEnabled",onCommitJoystickEnabled,this); - childSetAction("SpaceNavigatorDefaults", onClickRestoreSNDefaults, this); + getChild("Default")->setCommitCallback(boost::bind(&LLFloaterJoystick::onClickDefault, this, _2)); childSetAction("cancel_btn", onClickCancel, this); childSetAction("ok_btn", onClickOK, this); @@ -301,9 +299,14 @@ void LLFloaterJoystick::onCommitJoystickEnabled(LLUICtrl*, void *joy_panel) } } -void LLFloaterJoystick::onClickRestoreSNDefaults(void *joy_panel) +S32 get_joystick_type(); +void LLFloaterJoystick::onClickDefault(const LLSD& val) { - setSNDefaults(); + S32 type(val.asInteger()); + if (val.isUndefined()) // If button portion, set to default for device. + if ((type = get_joystick_type()) == -1) // Invalid/No device + return; + LLViewerJoystick::getInstance()->setSNDefaults(type); } void LLFloaterJoystick::onClickCancel(void *joy_panel) @@ -332,8 +335,3 @@ void LLFloaterJoystick::onClickOK(void *joy_panel) } } } - -void LLFloaterJoystick::setSNDefaults() -{ - LLViewerJoystick::getInstance()->setSNDefaults(); -} diff --git a/indra/newview/llfloaterjoystick.h b/indra/newview/llfloaterjoystick.h index 3ce647e5bb..1104b604f0 100644 --- a/indra/newview/llfloaterjoystick.h +++ b/indra/newview/llfloaterjoystick.h @@ -49,11 +49,10 @@ class LLFloaterJoystick : public LLFloater, public LLFloaterSingleton mAxisStatsBar; }; #endif diff --git a/indra/newview/llfloaterlagmeter.cpp b/indra/newview/llfloaterlagmeter.cpp deleted file mode 100644 index d1445cdbb1..0000000000 --- a/indra/newview/llfloaterlagmeter.cpp +++ /dev/null @@ -1,364 +0,0 @@ -/** - * @file llfloaterlagmeter.cpp - * @brief The "Lag-o-Meter" floater used to tell users what is causing lag. - * - * $LicenseInfo:firstyear=2007&license=viewergpl$ - * - * Copyright (c) 2007-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llfloaterlagmeter.h" - -#include "lluictrlfactory.h" -#include "llviewerstats.h" -#include "llviewertexture.h" -#include "llviewercontrol.h" -#include "llappviewer.h" - -#include "lltexturefetch.h" - -#include "llbutton.h" -#include "llfocusmgr.h" -#include "lltextbox.h" - -const std::string LAG_CRITICAL_IMAGE_NAME = "lag_status_critical.tga"; -const std::string LAG_WARNING_IMAGE_NAME = "lag_status_warning.tga"; -const std::string LAG_GOOD_IMAGE_NAME = "lag_status_good.tga"; - -LLFloaterLagMeter::LLFloaterLagMeter(const LLSD& key) - : LLFloater(std::string("floater_lagmeter")) -{ - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_lagmeter.xml"); - - // Don't let this window take keyboard focus -- it's confusing to - // lose arrow-key driving when testing lag. - setIsChrome(TRUE); - - mClientButton = getChild("client_lagmeter"); - mClientText = getChild("client_text"); - mClientCause = getChild("client_lag_cause"); - - mNetworkButton = getChild("network_lagmeter"); - mNetworkText = getChild("network_text"); - mNetworkCause = getChild("network_lag_cause"); - - mServerButton = getChild("server_lagmeter"); - mServerText = getChild("server_text"); - mServerCause = getChild("server_lag_cause"); - - std::string config_string = getString("client_frame_rate_critical_fps", mStringArgs); - mClientFrameTimeCritical = 1.0f / (float)atof( config_string.c_str() ); - config_string = getString("client_frame_rate_warning_fps", mStringArgs); - mClientFrameTimeWarning = 1.0f / (float)atof( config_string.c_str() ); - - config_string = getString("network_packet_loss_critical_pct", mStringArgs); - mNetworkPacketLossCritical = (float)atof( config_string.c_str() ); - config_string = getString("network_packet_loss_warning_pct", mStringArgs); - mNetworkPacketLossWarning = (float)atof( config_string.c_str() ); - - config_string = getString("network_ping_critical_ms", mStringArgs); - mNetworkPingCritical = (float)atof( config_string.c_str() ); - config_string = getString("network_ping_warning_ms", mStringArgs); - mNetworkPingWarning = (float)atof( config_string.c_str() ); - config_string = getString("server_frame_rate_critical_fps", mStringArgs); - - mServerFrameTimeCritical = 1000.0f / (float)atof( config_string.c_str() ); - config_string = getString("server_frame_rate_warning_fps", mStringArgs); - mServerFrameTimeWarning = 1000.0f / (float)atof( config_string.c_str() ); - config_string = getString("server_single_process_max_time_ms", mStringArgs); - mServerSingleProcessMaxTime = (float)atof( config_string.c_str() ); - - mShrunk = false; - config_string = getString("max_width_px", mStringArgs); - mMaxWidth = atoi( config_string.c_str() ); - config_string = getString("min_width_px", mStringArgs); - mMinWidth = atoi( config_string.c_str() ); - - mStringArgs["[CLIENT_FRAME_RATE_CRITICAL]"] = getString("client_frame_rate_critical_fps"); - mStringArgs["[CLIENT_FRAME_RATE_WARNING]"] = getString("client_frame_rate_warning_fps"); - - mStringArgs["[NETWORK_PACKET_LOSS_CRITICAL]"] = getString("network_packet_loss_critical_pct"); - mStringArgs["[NETWORK_PACKET_LOSS_WARNING]"] = getString("network_packet_loss_warning_pct"); - - mStringArgs["[NETWORK_PING_CRITICAL]"] = getString("network_ping_critical_ms"); - mStringArgs["[NETWORK_PING_WARNING]"] = getString("network_ping_warning_ms"); - - mStringArgs["[SERVER_FRAME_RATE_CRITICAL]"] = getString("server_frame_rate_critical_fps"); - mStringArgs["[SERVER_FRAME_RATE_WARNING]"] = getString("server_frame_rate_warning_fps"); - - childSetAction("minimize", onClickShrink, this); - - // were we shrunk last time? - if (gSavedSettings.getBOOL("LagMeterShrunk")) - { - onClickShrink(this); - } -} - -LLFloaterLagMeter::~LLFloaterLagMeter() -{ - // save shrunk status for next time - gSavedSettings.setBOOL("LagMeterShrunk", mShrunk); - // expand so we save the large window rectangle - if (mShrunk) - { - onClickShrink(this); - } -} - -void LLFloaterLagMeter::draw() -{ - determineClient(); - determineNetwork(); - determineServer(); - - LLFloater::draw(); -} - -void LLFloaterLagMeter::determineClient() -{ - F32 client_frame_time = LLViewerStats::getInstance()->mFPSStat.getMeanDuration(); - bool find_cause = false; - - if (!gFocusMgr.getAppHasFocus()) - { - mClientButton->setImageUnselected(LLUI::getUIImage(LAG_GOOD_IMAGE_NAME)); - mClientText->setText( getString("client_frame_time_window_bg_msg", mStringArgs) ); - mClientCause->setText( LLStringUtil::null ); - } - else if(client_frame_time >= mClientFrameTimeCritical) - { - mClientButton->setImageUnselected(LLUI::getUIImage(LAG_CRITICAL_IMAGE_NAME)); - mClientText->setText( getString("client_frame_time_critical_msg", mStringArgs) ); - find_cause = true; - } - else if(client_frame_time >= mClientFrameTimeWarning) - { - mClientButton->setImageUnselected(LLUI::getUIImage(LAG_WARNING_IMAGE_NAME)); - mClientText->setText( getString("client_frame_time_warning_msg", mStringArgs) ); - find_cause = true; - } - else - { - mClientButton->setImageUnselected(LLUI::getUIImage(LAG_GOOD_IMAGE_NAME)); - mClientText->setText( getString("client_frame_time_normal_msg", mStringArgs) ); - mClientCause->setText( LLStringUtil::null ); - } - - if(find_cause) - { - if(gSavedSettings.getF32("RenderFarClip") > 128) - { - mClientCause->setText( getString("client_draw_distance_cause_msg", mStringArgs) ); - } - else if(LLAppViewer::instance()->getTextureFetch()->getNumRequests() > 2) - { - mClientCause->setText( getString("client_texture_loading_cause_msg", mStringArgs) ); - } - else if((BYTES_TO_MEGA_BYTES(LLViewerTexture::sBoundTextureMemoryInBytes)) > LLViewerTexture::sMaxBoundTextureMemInMegaBytes) - { - mClientCause->setText( getString("client_texture_memory_cause_msg", mStringArgs) ); - } - else - { - mClientCause->setText( getString("client_complex_objects_cause_msg", mStringArgs) ); - } - } -} - -void LLFloaterLagMeter::determineNetwork() -{ - F32 packet_loss = LLViewerStats::getInstance()->mPacketsLostPercentStat.getMean(); - F32 ping_time = LLViewerStats::getInstance()->mSimPingStat.getMean(); - bool find_cause_loss = false; - bool find_cause_ping = false; - - // *FIXME: We can't blame a large ping time on anything in - // particular if the frame rate is low, because a low frame - // rate is a sure recipe for crappy ping times right now until - // the network handlers are de-synched from the rendering. - F32 client_frame_time_ms = 1000.0f * LLViewerStats::getInstance()->mFPSStat.getMeanDuration(); - - if(packet_loss >= mNetworkPacketLossCritical) - { - mNetworkButton->setImageUnselected(LLUI::getUIImage(LAG_CRITICAL_IMAGE_NAME)); - mNetworkText->setText( getString("network_packet_loss_critical_msg", mStringArgs) ); - find_cause_loss = true; - } - else if(ping_time >= mNetworkPingCritical) - { - mNetworkButton->setImageUnselected(LLUI::getUIImage(LAG_CRITICAL_IMAGE_NAME)); - if (client_frame_time_ms < mNetworkPingCritical) - { - mNetworkText->setText( getString("network_ping_critical_msg", mStringArgs) ); - find_cause_ping = true; - } - } - else if(packet_loss >= mNetworkPacketLossWarning) - { - mNetworkButton->setImageUnselected(LLUI::getUIImage(LAG_WARNING_IMAGE_NAME)); - mNetworkText->setText( getString("network_packet_loss_warning_msg", mStringArgs) ); - find_cause_loss = true; - } - else if(ping_time >= mNetworkPingWarning) - { - mNetworkButton->setImageUnselected(LLUI::getUIImage(LAG_WARNING_IMAGE_NAME)); - if (client_frame_time_ms < mNetworkPingWarning) - { - mNetworkText->setText( getString("network_ping_warning_msg", mStringArgs) ); - find_cause_ping = true; - } - } - else - { - mNetworkButton->setImageUnselected(LLUI::getUIImage(LAG_GOOD_IMAGE_NAME)); - mNetworkText->setText( getString("network_performance_normal_msg", mStringArgs) ); - } - - if(find_cause_loss) - { - mNetworkCause->setText( getString("network_packet_loss_cause_msg", mStringArgs) ); - } - else if(find_cause_ping) - { - mNetworkCause->setText( getString("network_ping_cause_msg", mStringArgs) ); - } - else - { - mNetworkCause->setText( LLStringUtil::null ); - } -} - -void LLFloaterLagMeter::determineServer() -{ - F32 sim_frame_time = LLViewerStats::getInstance()->mSimFrameMsec.getCurrent(); - bool find_cause = false; - - if(sim_frame_time >= mServerFrameTimeCritical) - { - mServerButton->setImageUnselected(LLUI::getUIImage(LAG_CRITICAL_IMAGE_NAME)); - mServerText->setText( getString("server_frame_time_critical_msg", mStringArgs) ); - find_cause = true; - } - else if(sim_frame_time >= mServerFrameTimeWarning) - { - mServerButton->setImageUnselected(LLUI::getUIImage(LAG_WARNING_IMAGE_NAME)); - mServerText->setText( getString("server_frame_time_warning_msg", mStringArgs) ); - find_cause = true; - } - else - { - mServerButton->setImageUnselected(LLUI::getUIImage(LAG_GOOD_IMAGE_NAME)); - mServerText->setText( getString("server_frame_time_normal_msg", mStringArgs) ); - mServerCause->setText( LLStringUtil::null ); - } - - if(find_cause) - { - if(LLViewerStats::getInstance()->mSimSimPhysicsMsec.getCurrent() > mServerSingleProcessMaxTime) - { - mServerCause->setText( getString("server_physics_cause_msg", mStringArgs) ); - } - else if(LLViewerStats::getInstance()->mSimScriptMsec.getCurrent() > mServerSingleProcessMaxTime) - { - mServerCause->setText( getString("server_scripts_cause_msg", mStringArgs) ); - } - else if(LLViewerStats::getInstance()->mSimNetMsec.getCurrent() > mServerSingleProcessMaxTime) - { - mServerCause->setText( getString("server_net_cause_msg", mStringArgs) ); - } - else if(LLViewerStats::getInstance()->mSimAgentMsec.getCurrent() > mServerSingleProcessMaxTime) - { - mServerCause->setText( getString("server_agent_cause_msg", mStringArgs) ); - } - else if(LLViewerStats::getInstance()->mSimImagesMsec.getCurrent() > mServerSingleProcessMaxTime) - { - mServerCause->setText( getString("server_images_cause_msg", mStringArgs) ); - } - else - { - mServerCause->setText( getString("server_generic_cause_msg", mStringArgs) ); - } - } -} - -//static -void LLFloaterLagMeter::onClickShrink(void * data) -{ - LLFloaterLagMeter * self = (LLFloaterLagMeter*)data; - - LLButton * button = self->getChild("minimize"); - S32 delta_width = self->mMaxWidth - self->mMinWidth; - LLRect r = self->getRect(); - if(self->mShrunk) - { - self->setTitle( self->getString("max_title_msg", self->mStringArgs) ); - // make left edge appear to expand - r.translate(-delta_width, 0); - self->setRect(r); - self->reshape(self->mMaxWidth, self->getRect().getHeight()); - - self->childSetText("client", self->getString("client_text_msg", self->mStringArgs) + ":"); - self->childSetText("network", self->getString("network_text_msg", self->mStringArgs) + ":"); - self->childSetText("server", self->getString("server_text_msg", self->mStringArgs) + ":"); - - // usually "<<" - button->setLabel( self->getString("smaller_label", self->mStringArgs) ); - } - else - { - self->setTitle( self->getString("min_title_msg", self->mStringArgs) ); - // make left edge appear to collapse - r.translate(delta_width, 0); - self->setRect(r); - self->reshape(self->mMinWidth, self->getRect().getHeight()); - - self->childSetText("client", self->getString("client_text_msg", self->mStringArgs) ); - self->childSetText("network", self->getString("network_text_msg", self->mStringArgs) ); - self->childSetText("server", self->getString("server_text_msg", self->mStringArgs) ); - - // usually ">>" - button->setLabel( self->getString("bigger_label", self->mStringArgs) ); - } - // Don't put keyboard focus on the button - button->setFocus(FALSE); - - self->mClientText->setVisible(self->mShrunk); - self->mClientCause->setVisible(self->mShrunk); - self->childSetVisible("client_help", self->mShrunk); - - self->mNetworkText->setVisible(self->mShrunk); - self->mNetworkCause->setVisible(self->mShrunk); - self->childSetVisible("network_help", self->mShrunk); - - self->mServerText->setVisible(self->mShrunk); - self->mServerCause->setVisible(self->mShrunk); - self->childSetVisible("server_help", self->mShrunk); - - self->mShrunk = !self->mShrunk; -} diff --git a/indra/newview/llfloaterlagmeter.h b/indra/newview/llfloaterlagmeter.h deleted file mode 100644 index d9cea18305..0000000000 --- a/indra/newview/llfloaterlagmeter.h +++ /dev/null @@ -1,82 +0,0 @@ -/** - * @file llfloaterlagmeter.h - * @brief The "Lag-o-Meter" floater used to tell users what is causing lag. - * - * $LicenseInfo:firstyear=2007&license=viewergpl$ - * - * Copyright (c) 2007-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifndef LLFLOATERLAGMETER_H -#define LLFLOATERLAGMETER_H - -#include "llfloater.h" - -class LLFloaterLagMeter : public LLFloater, public LLFloaterSingleton -{ - friend class LLUISingleton >; - -public: - /*virtual*/ void draw(); - -private: - LLFloaterLagMeter(const LLSD& key); - /*virtual*/ ~LLFloaterLagMeter(); - - void determineClient(); - void determineNetwork(); - void determineServer(); - - static void onClickShrink(void * data); - - bool mShrunk; - S32 mMaxWidth, mMinWidth; - - F32 mClientFrameTimeCritical; - F32 mClientFrameTimeWarning; - LLButton * mClientButton; - LLTextBox * mClientText; - LLTextBox * mClientCause; - - F32 mNetworkPacketLossCritical; - F32 mNetworkPacketLossWarning; - F32 mNetworkPingCritical; - F32 mNetworkPingWarning; - LLButton * mNetworkButton; - LLTextBox * mNetworkText; - LLTextBox * mNetworkCause; - - F32 mServerFrameTimeCritical; - F32 mServerFrameTimeWarning; - F32 mServerSingleProcessMaxTime; - LLButton * mServerButton; - LLTextBox * mServerText; - LLTextBox * mServerCause; - - LLStringUtil::format_map_t mStringArgs; -}; - -#endif diff --git a/indra/newview/llfloaterland.cpp b/indra/newview/llfloaterland.cpp index 7c58016804..543e56e8f3 100644 --- a/indra/newview/llfloaterland.cpp +++ b/indra/newview/llfloaterland.cpp @@ -46,15 +46,16 @@ #include "llagent.h" #include "llagentaccess.h" -#include "llavataractions.h" #include "llbutton.h" #include "llcheckboxctrl.h" #include "llcombobox.h" -#include "llfloaterauction.h" #include "llfloateravatarpicker.h" +#include "llfloaterauction.h" +#include "llfloaterbanduration.h" #include "llfloatergroups.h" #include "llfloaterscriptlimits.h" -#include "llgroupactions.h" +#include "llavataractions.h" +#include "lllayoutstack.h" #include "lllineeditor.h" #include "llnamelistctrl.h" #include "llpanellandaudio.h" @@ -63,6 +64,7 @@ #include "llscrolllistctrl.h" #include "llscrolllistitem.h" #include "llselectmgr.h" +#include "llslurl.h" #include "llspinctrl.h" #include "lltabcontainer.h" #include "lltextbox.h" @@ -80,15 +82,20 @@ #include "roles_constants.h" #include "llworld.h" #include "lltrans.h" +#include "llpanelexperiencelisteditor.h" +#include "llpanelexperiencepicker.h" +#include "llexperiencecache.h" +#include "llgroupactions.h" #include "hippogridmanager.h" - // [RLVa:KB] #include "rlvhandler.h" // [/RLVa:KB] +const F64 COVENANT_REFRESH_TIME_SEC = 60.0f; + static std::string OWNER_ONLINE = "0"; static std::string OWNER_OFFLINE = "1"; static std::string OWNER_GROUP = "2"; @@ -97,17 +104,37 @@ static std::string OWNER_INSIM = "4"; // constants used in callbacks below - syntactic sugar. static const BOOL BUY_GROUP_LAND = TRUE; static const BOOL BUY_PERSONAL_LAND = FALSE; -LLPointer LLPanelLandGeneral::sSelectionForBuyPass = NULL; // Statics LLParcelSelectionObserver* LLFloaterLand::sObserver = NULL; S32 LLFloaterLand::sLastTab = 0; // Local classes -class LLParcelSelectionObserver : public LLParcelObserver +class LLParcelSelectionObserver final : public LLParcelObserver { public: - virtual void changed() { LLFloaterLand::refreshAll(); } + void changed() override { LLFloaterLand::refreshAll(); } +}; + +class LLPanelLandExperiences final + : public LLPanel +{ +public: + LLPanelLandExperiences(LLSafeHandle& parcelp); + BOOL postBuild() override; + void refresh() override; + + void experienceAdded(const LLUUID& id, U32 xp_type, U32 access_type); + void experienceRemoved(const LLUUID& id, U32 access_type); +protected: + void setupList(LLPanelExperienceListEditor* child, const char* control_name, U32 xp_type, U32 access_type ); + void refreshPanel(LLPanelExperienceListEditor* panel, U32 xp_type); + + LLSafeHandle& mParcel; + + + LLPanelExperienceListEditor* mAllowed; + LLPanelExperienceListEditor* mBlocked; }; //--------------------------------------------------------------------------- @@ -165,24 +192,44 @@ LLParcel* LLFloaterLand::getCurrentSelectedParcel() //static LLPanelLandObjects* LLFloaterLand::getCurrentPanelLandObjects() { - return LLFloaterLand::getInstance()->mPanelObjects; + LLFloaterLand* land_instance = LLFloaterLand::getInstance(); + if (land_instance) + { + return land_instance->mPanelObjects; + } + else + { + return NULL; + } } //static LLPanelLandCovenant* LLFloaterLand::getCurrentPanelLandCovenant() { - return LLFloaterLand::getInstance()->mPanelCovenant; + LLFloaterLand* land_instance = LLFloaterLand::getInstance(); + if (land_instance) + { + return land_instance->mPanelCovenant; + } + else + { + return NULL; + } } // static void LLFloaterLand::refreshAll() { - LLFloaterLand::getInstance()->refresh(); + LLFloaterLand* land_instance = LLFloaterLand::getInstance(); + if (land_instance) + { + land_instance->refresh(); + } } void LLFloaterLand::onOpen() { - // moved from triggering show instance in llviwermenu.cpp + // moved from triggering show instance in llviewermenu.cpp if (LLViewerParcelMgr::getInstance()->selectionEmpty()) { @@ -201,21 +248,16 @@ void LLFloaterLand::onOpen() } -// virtual -void LLFloaterLand::onClose(bool app_quitting) -{ - // Might have been showing owned objects - LLSelectMgr::getInstance()->unhighlightAll(); - - // Save which panel we had open - sLastTab = mTabLand->getCurrentPanelIndex(); - - destroy(); -} - - LLFloaterLand::LLFloaterLand(const LLSD& seed) : LLFloater(std::string("floaterland"), std::string("FloaterLandRect5"), std::string("About Land")) + , mTabLand(nullptr) + , mPanelGeneral(nullptr) + , mPanelObjects(nullptr) + , mPanelOptions(nullptr) + , mPanelMedia(nullptr) + , mPanelAccess(nullptr) + , mPanelCovenant(nullptr) + , mPanelExperiences(nullptr) { mFactoryMap["land_general_panel"] = LLCallbackMap(createPanelLandGeneral, this); mFactoryMap["land_covenant_panel"] = LLCallbackMap(createPanelLandCovenant, this); @@ -224,6 +266,7 @@ LLFloaterLand::LLFloaterLand(const LLSD& seed) mFactoryMap["land_audio_panel"] = LLCallbackMap(createPanelLandAudio, this); mFactoryMap["land_media_panel"] = LLCallbackMap(createPanelLandMedia, this); mFactoryMap["land_access_panel"] = LLCallbackMap(createPanelLandAccess, this); + //mFactoryMap["land_experiences_panel"] = LLCallbackMap(createPanelLandExperiences, this); // We need to buildPanel this, so we call this in postBuild LLUICtrlFactory::getInstance()->buildFloater(this, "floater_about_land.xml", &getFactoryMap(), false); @@ -239,6 +282,8 @@ BOOL LLFloaterLand::postBuild() if (tab) { + if (!gAgent.getRegion()->getCapability("RegionExperiences").empty()) + createPanelLandExperiences(this); // We need to buildPanel this, so call it here instead of during floater building tab->selectTab(sLastTab); } @@ -257,6 +302,10 @@ LLFloaterLand::~LLFloaterLand() // public void LLFloaterLand::refresh() { + if (!instanceVisible()) + return; + if (LLViewerParcelMgr::getInstance()->selectionEmpty() && mParcel->getParcel() == NULL) + LLViewerParcelMgr::getInstance()->selectParcelAt(gAgent.getPositionGlobal()); mPanelGeneral->refresh(); mPanelObjects->refresh(); mPanelOptions->refresh(); @@ -264,10 +313,9 @@ void LLFloaterLand::refresh() mPanelMedia->refresh(); mPanelAccess->refresh(); mPanelCovenant->refresh(); + if (mPanelExperiences) mPanelExperiences->refresh(); } - - void* LLFloaterLand::createPanelLandGeneral(void* data) { LLFloaterLand* self = (LLFloaterLand*)data; @@ -300,14 +348,6 @@ void* LLFloaterLand::createPanelLandOptions(void* data) return self->mPanelOptions; } -// static -void* LLFloaterLand::createPanelLandAudio(void* data) -{ - LLFloaterLand* self = (LLFloaterLand*)data; - self->mPanelAudio = new LLPanelLandAudio(self->mParcel); - return self->mPanelAudio; -} - // static void* LLFloaterLand::createPanelLandMedia(void* data) { @@ -324,71 +364,110 @@ void* LLFloaterLand::createPanelLandAccess(void* data) return self->mPanelAccess; } +// static +void* LLFloaterLand::createPanelLandAudio(void* data) +{ + LLFloaterLand* self = (LLFloaterLand*)data; + self->mPanelAudio = new LLPanelLandAudio(self->mParcel); + return self->mPanelAudio; +} + +// static +void* LLFloaterLand::createPanelLandExperiences(void* data) +{ + LLFloaterLand* self = static_cast(data); + self->mPanelExperiences = new LLPanelLandExperiences(self->mParcel); + self->mTabLand->addTabPanel(self->mPanelExperiences, self->mPanelExperiences->getLabel()); // We must build this panel separately from the floater xml, so add it to the tab container manually. + return self->mPanelExperiences; +} + + +LLPointer LLPanelLandGeneral::sSelectionForBuyPass = NULL; + //--------------------------------------------------------------------------- // LLPanelLandGeneral //--------------------------------------------------------------------------- LLPanelLandGeneral::LLPanelLandGeneral(LLParcelSelectionHandle& parcel) -: LLPanel(std::string("land_general_panel")), - mUncheckedSell(FALSE), - mParcel(parcel) + : LLPanel(std::string("land_general_panel")) + , mEditName(nullptr) + , mEditDesc(nullptr) + , mTextSalePending(nullptr) + , mBtnDeedToGroup(nullptr) + , mBtnSetGroup(nullptr) + , mTextOwner(nullptr) + , mContentRating(nullptr) + , mLandType(nullptr) + , mTextGroup(nullptr) + , mTextClaimDate(nullptr) + , mTextPriceLabel(nullptr) + , mTextPrice(nullptr) + , mCheckDeedToGroup(nullptr) + , mCheckContributeWithDeed(nullptr) + , mSaleInfoForSale1(nullptr) + , mSaleInfoForSale2(nullptr) + , mSaleInfoForSaleObjects(nullptr) + , mSaleInfoForSaleNoObjects(nullptr) + , mSaleInfoNotForSale(nullptr) + , mBtnSellLand(nullptr) + , mBtnStopSellLand(nullptr) + , mTextDwell(nullptr) + , mBtnBuyLand(nullptr) + , mBtnScriptLimits(nullptr) + , mBtnBuyGroupLand(nullptr) + , mBtnReleaseLand(nullptr) + , mBtnReclaimLand(nullptr) + , mBtnBuyPass(nullptr) + , mBtnStartAuction(nullptr) + , mParcel(parcel) { } BOOL LLPanelLandGeneral::postBuild() { mEditName = getChild("Name"); - mEditName->setCommitCallback(onCommitAny, this); + mEditName->setCommitCallback(boost::bind(&LLPanelLandGeneral::onCommitAny, this)); getChild("Name")->setPrevalidate(LLLineEditor::prevalidatePrintableNotPipe); mEditDesc = getChild("Description"); mEditDesc->setCommitOnFocusLost(TRUE); - mEditDesc->setCommitCallback(onCommitAny, this); + mEditDesc->setCommitCallback(boost::bind(&LLPanelLandGeneral::onCommitAny, this)); // No prevalidate function - historically the prevalidate function was broken, // allowing residents to put in characters like U+2661 WHITE HEART SUIT, so // preserve that ability. mTextSalePending = getChild("SalePending"); - mTextOwnerLabel = getChild("Owner:"); mTextOwner = getChild("OwnerText"); mContentRating = getChild("ContentRatingText"); mLandType = getChild("LandTypeText"); - - mBtnProfile = getChild("Profile..."); - mBtnProfile->setClickedCallback(boost::bind(&LLPanelLandGeneral::onClickProfile, this)); - - mTextGroupLabel = getChild("Group:"); mTextGroup = getChild("GroupText"); mBtnSetGroup = getChild("Set..."); mBtnSetGroup->setCommitCallback(boost::bind(&LLPanelLandGeneral::onClickSetGroup, this)); - getChild("group_profile")->setClickedCallback(onClickInfoGroup, this); - mCheckDeedToGroup = getChild( "check deed"); - childSetCommitCallback("check deed", onCommitAny, this); + mCheckDeedToGroup->setCommitCallback(boost::bind(&LLPanelLandGeneral::onCommitAny, this)); mBtnDeedToGroup = getChild("Deed..."); - mBtnDeedToGroup->setClickedCallback(onClickDeed, this); + mBtnDeedToGroup->setCommitCallback(boost::bind(&LLPanelLandGeneral::onClickDeed, this)); mCheckContributeWithDeed = getChild( "check contrib"); - childSetCommitCallback("check contrib", onCommitAny, this); + mCheckContributeWithDeed->setCommitCallback(boost::bind(&LLPanelLandGeneral::onCommitAny, this)); - mSaleInfoNotForSale = getChild("Not for sale."); mSaleInfoForSale1 = getChild("For Sale: Price L$[PRICE]."); mBtnSellLand = getChild("Sell Land..."); - mBtnSellLand->setClickedCallback(onClickSellLand, this); + mBtnSellLand->setCommitCallback(boost::bind(&LLPanelLandGeneral::onClickSellLand, this)); mSaleInfoForSale2 = getChild("For sale to"); @@ -398,10 +477,9 @@ BOOL LLPanelLandGeneral::postBuild() mBtnStopSellLand = getChild("Cancel Land Sale"); - mBtnStopSellLand->setClickedCallback(onClickStopSellLand, this); + mBtnStopSellLand->setCommitCallback(boost::bind(&LLPanelLandGeneral::onClickStopSellLand, this)); - mTextClaimDateLabel = getChild("Claimed:"); mTextClaimDate = getChild("DateClaimText"); @@ -414,43 +492,49 @@ BOOL LLPanelLandGeneral::postBuild() mBtnBuyLand = getChild("Buy Land..."); mBtnBuyLand->setClickedCallback(onClickBuyLand, (void*)&BUY_PERSONAL_LAND); + + mBtnBuyGroupLand = getChild("Buy For Group..."); + mBtnBuyGroupLand->setClickedCallback(onClickBuyLand, (void*)&BUY_GROUP_LAND); + + + mBtnBuyPass = getChild("Buy Pass..."); + mBtnBuyPass->setClickedCallback(onClickBuyPass, this); + + mBtnReleaseLand = getChild("Abandon Land..."); + mBtnReleaseLand->setCommitCallback(boost::bind(&LLPanelLandGeneral::onClickRelease, this)); + + mBtnReclaimLand = getChild("Reclaim Land..."); + mBtnReclaimLand->setCommitCallback(boost::bind(&LLPanelLandGeneral::onClickReclaim, this)); + + mBtnStartAuction = getChild("Linden Sale..."); + mBtnStartAuction->setCommitCallback(boost::bind(&LLPanelLandGeneral::onClickStartAuction, this)); + + mBtnScriptLimits = getChild("Scripts..."); + + if(gDisconnected) + { + return TRUE; + } + // note: on region change this will not be re checked, should not matter on Agni as // 99% of the time all regions will return the same caps. In case of an erroneous setting // to enabled the floater will just throw an error when trying to get it's cap - std::string url = gAgent.getRegion()->getCapability("LandResources"); + std::string url = gAgent.getRegionCapability("LandResources"); if (!url.empty()) { - mBtnScriptLimits = getChild("Scripts..."); if(mBtnScriptLimits) { - mBtnScriptLimits->setClickedCallback(onClickScriptLimits, this); + mBtnScriptLimits->setCommitCallback(boost::bind(&LLPanelLandGeneral::onClickScriptLimits, this)); } } else { - mBtnScriptLimits = getChild("Scripts..."); if(mBtnScriptLimits) { mBtnScriptLimits->setVisible(false); } } - mBtnBuyGroupLand = getChild("Buy For Group..."); - mBtnBuyGroupLand->setClickedCallback(onClickBuyLand, (void*)&BUY_GROUP_LAND); - - - mBtnBuyPass = getChild("Buy Pass..."); - mBtnBuyPass->setClickedCallback(onClickBuyPass, this); - - mBtnReleaseLand = getChild("Abandon Land..."); - mBtnReleaseLand->setClickedCallback(onClickRelease, NULL); - - mBtnReclaimLand = getChild("Reclaim Land..."); - mBtnReclaimLand->setClickedCallback(onClickReclaim, NULL); - - mBtnStartAuction = getChild("Linden Sale..."); - mBtnStartAuction->setClickedCallback(onClickStartAuction, this); - return TRUE; } @@ -463,9 +547,56 @@ LLPanelLandGeneral::~LLPanelLandGeneral() // public void LLPanelLandGeneral::refresh() { - mBtnStartAuction->setVisible(gAgent.isGodlike()); + mEditName->setEnabled(FALSE); + mEditName->setText(LLStringUtil::null); - LLParcel *parcel = mParcel->getParcel(); + mEditDesc->setEnabled(FALSE); + mEditDesc->setText(getString("no_selection_text")); + + mTextSalePending->setText(LLStringUtil::null); + mTextSalePending->setEnabled(FALSE); + + mBtnDeedToGroup->setEnabled(FALSE); + mBtnSetGroup->setEnabled(FALSE); + mBtnStartAuction->setEnabled(FALSE); + + mCheckDeedToGroup ->set(FALSE); + mCheckDeedToGroup ->setEnabled(FALSE); + mCheckContributeWithDeed->set(FALSE); + mCheckContributeWithDeed->setEnabled(FALSE); + + mTextOwner->setValue(LLUUID::null); + mContentRating->setText(LLStringUtil::null); + mLandType->setText(LLStringUtil::null); + + mTextClaimDate->setText(LLStringUtil::null); + mTextGroup->setValue(LLUUID::null); + mTextPrice->setText(LLStringUtil::null); + + mSaleInfoForSale1->setVisible(FALSE); + mSaleInfoForSale2->setVisible(FALSE); + mSaleInfoForSaleObjects->setVisible(FALSE); + mSaleInfoForSaleNoObjects->setVisible(FALSE); + mSaleInfoNotForSale->setVisible(FALSE); + mBtnSellLand->setVisible(FALSE); + mBtnStopSellLand->setVisible(FALSE); + + mTextPriceLabel->setText(LLStringUtil::null); + mTextDwell->setText(LLStringUtil::null); + + mBtnBuyLand->setEnabled(FALSE); + mBtnScriptLimits->setEnabled(FALSE); + mBtnBuyGroupLand->setEnabled(FALSE); + mBtnReleaseLand->setEnabled(FALSE); + mBtnReclaimLand->setEnabled(FALSE); + mBtnBuyPass->setEnabled(FALSE); + + if(gDisconnected) + { + return; + } + + mBtnStartAuction->setVisible(gAgent.isGodlike()); bool region_owner = false; LLViewerRegion* regionp = LLViewerParcelMgr::getInstance()->getSelectionRegion(); if(regionp && (regionp->getOwner() == gAgent.getID())) @@ -479,62 +610,14 @@ void LLPanelLandGeneral::refresh() mBtnReleaseLand->setVisible(TRUE); mBtnReclaimLand->setVisible(FALSE); } - if (!parcel) - { - // nothing selected, disable panel - mEditName->setEnabled(FALSE); - mEditName->setText(LLStringUtil::null); - - mEditDesc->setEnabled(FALSE); - mEditDesc->setText(getString("no_selection_text")); - - mTextSalePending->setText(LLStringUtil::null); - mTextSalePending->setEnabled(FALSE); - - mBtnDeedToGroup->setEnabled(FALSE); - mBtnSetGroup->setEnabled(FALSE); - mBtnStartAuction->setEnabled(FALSE); - - mCheckDeedToGroup ->set(FALSE); - mCheckDeedToGroup ->setEnabled(FALSE); - mCheckContributeWithDeed->set(FALSE); - mCheckContributeWithDeed->setEnabled(FALSE); - - mTextOwner->setText(LLStringUtil::null); - mContentRating->setText(LLStringUtil::null); - mLandType->setText(LLStringUtil::null); - mBtnProfile->setLabel(getString("profile_text")); - mBtnProfile->setEnabled(FALSE); - - mTextClaimDate->setText(LLStringUtil::null); - mTextGroup->setText(LLStringUtil::null); - mTextPrice->setText(LLStringUtil::null); - - mSaleInfoForSale1->setVisible(FALSE); - mSaleInfoForSale2->setVisible(FALSE); - mSaleInfoForSaleObjects->setVisible(FALSE); - mSaleInfoForSaleNoObjects->setVisible(FALSE); - mSaleInfoNotForSale->setVisible(FALSE); - mBtnSellLand->setVisible(FALSE); - mBtnStopSellLand->setVisible(FALSE); - - mTextPriceLabel->setText(LLStringUtil::null); - mTextDwell->setText(LLStringUtil::null); - - mBtnBuyLand->setEnabled(FALSE); - mBtnScriptLimits->setEnabled(FALSE); - mBtnBuyGroupLand->setEnabled(FALSE); - mBtnReleaseLand->setEnabled(FALSE); - mBtnReclaimLand->setEnabled(FALSE); - mBtnBuyPass->setEnabled(FALSE); - } - else + LLParcel *parcel = mParcel->getParcel(); + if (parcel) { // something selected, hooray! BOOL is_leased = (LLParcel::OS_LEASED == parcel->getOwnershipStatus()); BOOL region_xfer = FALSE; if(regionp - && !regionp->getRegionFlag(REGION_FLAGS_BLOCK_LAND_RESELL)) + && !(regionp->getRegionFlag(REGION_FLAGS_BLOCK_LAND_RESELL))) { region_xfer = TRUE; } @@ -557,16 +640,19 @@ void LLPanelLandGeneral::refresh() BOOL can_be_sold = owner_sellable || estate_manager_sellable; const LLUUID &owner_id = parcel->getOwnerID(); + const LLUUID& group_id = parcel->getGroupID(); BOOL is_public = parcel->isPublic(); + bool group_owned = parcel->getIsGroupOwned(); // Is it owned? + mTextOwner->setValue(is_public ? LLSD(LLUUID::null) : LLSD().with("id", owner_id).with("type", group_owned ? LFIDBearer::GROUP : LFIDBearer::AVATAR)); + mTextGroup->setValue(is_public ? LLUUID::null : group_id); if (is_public) { mTextSalePending->setText(LLStringUtil::null); mTextSalePending->setEnabled(FALSE); mTextOwner->setText(getString("public_text")); mTextOwner->setEnabled(FALSE); - mBtnProfile->setEnabled(FALSE); mTextClaimDate->setText(LLStringUtil::null); mTextClaimDate->setEnabled(FALSE); mTextGroup->setText(getString("none_text")); @@ -596,21 +682,13 @@ void LLPanelLandGeneral::refresh() mTextOwner->setEnabled(TRUE); // We support both group and personal profiles - mBtnProfile->setEnabled(TRUE); - - if (parcel->getGroupID().isNull()) + if (group_id.isNull()) { - // Not group owned, so "Profile" - mBtnProfile->setLabel(getString("profile_text")); - mTextGroup->setText(getString("none_text")); mTextGroup->setEnabled(FALSE); } else { - // Group owned, so "Info" - mBtnProfile->setLabel(getString("info_text")); - //mTextGroup->setText("HIPPOS!");//parcel->getGroupName()); mTextGroup->setEnabled(TRUE); } @@ -633,9 +711,7 @@ void LLPanelLandGeneral::refresh() mEditDesc->setEnabled(can_edit_identity); BOOL can_edit_agent_only = LLViewerParcelMgr::isParcelModifiableByAgent(parcel, GP_NO_POWERS); - mBtnSetGroup->setEnabled(can_edit_agent_only && !parcel->getIsGroupOwned()); - - const LLUUID& group_id = parcel->getGroupID(); + mBtnSetGroup->setEnabled(can_edit_agent_only && !group_owned); // Can only allow deeding if you own it and it's got a group. BOOL enable_deed = (owner_id == gAgent.getID() @@ -654,11 +730,11 @@ void LLPanelLandGeneral::refresh() mBtnDeedToGroup->setEnabled( parcel->getAllowDeedToGroup() && group_id.notNull() && can_deed - && !parcel->getIsGroupOwned() + && !group_owned ); mEditName->setText( parcel->getName() ); - mEditDesc->setText( parcel->getDesc() ); + mEditDesc->setText( parcel->getDesc(), false ); BOOL for_sale = parcel->getForSale(); @@ -739,6 +815,7 @@ void LLPanelLandGeneral::refresh() mBtnBuyLand->setEnabled( LLViewerParcelMgr::getInstance()->canAgentBuyParcel(parcel, false)); mBtnScriptLimits->setEnabled(true); +// LLViewerParcelMgr::getInstance()->canAgentBuyParcel(parcel, false)); mBtnBuyGroupLand->setEnabled( LLViewerParcelMgr::getInstance()->canAgentBuyParcel(parcel, true)); @@ -759,6 +836,7 @@ void LLPanelLandGeneral::refresh() BOOL use_pass = parcel->getOwnerID()!= gAgent.getID() && parcel->getParcelFlag(PF_USE_PASS_LIST) && !LLViewerParcelMgr::getInstance()->isCollisionBanned();; mBtnBuyPass->setEnabled(use_pass); + } } @@ -768,34 +846,24 @@ void LLPanelLandGeneral::refreshNames() LLParcel *parcel = mParcel->getParcel(); if (!parcel) { - mTextOwner->setText(LLStringUtil::null); - mTextGroup->setText(LLStringUtil::null); + mTextOwner->setValue(LLUUID::null); + mTextGroup->setValue(LLUUID::null); return; } - std::string owner; - if (parcel->getIsGroupOwned()) + bool group_owned = parcel->getIsGroupOwned(); + mTextOwner->setValue(LLSD().with("id", parcel->getOwnerID()).with("type", group_owned ? LFIDBearer::GROUP : LFIDBearer::AVATAR)); + if (group_owned) { - owner = getString("group_owned_text"); - } - else - { - // Figure out the owner's name - gCacheName->getFullName(parcel->getOwnerID(), owner); + mTextOwner->setText(getString("group_owned_text")); } if(LLParcel::OS_LEASE_PENDING == parcel->getOwnershipStatus()) { - owner += getString("sale_pending_text"); + mTextOwner->setText(mTextOwner->getText() + getString("sale_pending_text")); } - mTextOwner->setText(owner); - std::string group; - if (!parcel->getGroupID().isNull()) - { - gCacheName->getGroupName(parcel->getGroupID(), group); - } - mTextGroup->setText(group); + mTextGroup->setValue(parcel->getGroupID()); if (parcel->getForSale()) { @@ -813,13 +881,6 @@ void LLPanelLandGeneral::refreshNames() } } - -// virtual -void LLPanelLandGeneral::draw() -{ - LLPanel::draw(); -} - void LLPanelLandGeneral::onClickSetGroup() { LLFloater* parent_floater = gFloaterView->getParentFloater(this); @@ -837,30 +898,6 @@ void LLPanelLandGeneral::onClickSetGroup() } } -// static -void LLPanelLandGeneral::onClickInfoGroup(void* userdata) -{ - LLPanelLandGeneral* panelp = (LLPanelLandGeneral*)userdata; - LLParcel* parcel = panelp->mParcel->getParcel(); - if (!parcel) return; - LLGroupActions::show(parcel->getGroupID()); -} - -void LLPanelLandGeneral::onClickProfile() -{ - LLParcel* parcel = mParcel->getParcel(); - if (!parcel) return; - - if (parcel->getIsGroupOwned()) - { - LLGroupActions::show(parcel->getGroupID()); - } - else - { - LLAvatarActions::showProfile(parcel->getOwnerID()); - } -} - // public void LLPanelLandGeneral::setGroup(const LLUUID& group_id) { @@ -870,7 +907,6 @@ void LLPanelLandGeneral::setGroup(const LLUUID& group_id) // Set parcel properties and send message parcel->setGroupID(group_id); //parcel->setGroupName(group_name); - //mTextGroup->setText(group_name); // Send update LLViewerParcelMgr::getInstance()->sendParcelPropertiesUpdate(parcel); @@ -882,29 +918,20 @@ void LLPanelLandGeneral::setGroup(const LLUUID& group_id) // static void LLPanelLandGeneral::onClickBuyLand(void* data) { -// [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0a) - if ( (rlv_handler_t::isEnabled()) && (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) ) - { - return; - } -// [/RLVa:KB] BOOL* for_group = (BOOL*)data; LLViewerParcelMgr::getInstance()->startBuyLand(*for_group); } -// static -void LLPanelLandGeneral::onClickScriptLimits(void* data) +void LLPanelLandGeneral::onClickScriptLimits() { - LLPanelLandGeneral* panelp = (LLPanelLandGeneral*)data; - LLParcel* parcel = panelp->mParcel->getParcel(); + LLParcel* parcel = mParcel->getParcel(); if(parcel != NULL) { LLFloaterScriptLimits::showInstance(); } } -// static -void LLPanelLandGeneral::onClickDeed(void*) +void LLPanelLandGeneral::onClickDeed() { //LLParcel* parcel = mParcel->getParcel(); //if (parcel) @@ -913,16 +940,14 @@ void LLPanelLandGeneral::onClickDeed(void*) //} } -// static -void LLPanelLandGeneral::onClickRelease(void*) +void LLPanelLandGeneral::onClickRelease() { LLViewerParcelMgr::getInstance()->startReleaseLand(); } -// static -void LLPanelLandGeneral::onClickReclaim(void*) +void LLPanelLandGeneral::onClickReclaim() { - lldebugs << "LLPanelLandGeneral::onClickReclaim()" << llendl; + LL_DEBUGS() << "LLPanelLandGeneral::onClickReclaim()" << LL_ENDL; LLViewerParcelMgr::getInstance()->reclaimParcel(); } @@ -962,11 +987,9 @@ void LLPanelLandGeneral::onClickBuyPass(void* data) LLNotificationsUtil::add("LandBuyPass", args, LLSD(), cbBuyPass); } -// static -void LLPanelLandGeneral::onClickStartAuction(void* data) +void LLPanelLandGeneral::onClickStartAuction() { - LLPanelLandGeneral* panelp = (LLPanelLandGeneral*)data; - LLParcel* parcelp = panelp->mParcel->getParcel(); + LLParcel* parcelp = mParcel->getParcel(); if(parcelp) { if(parcelp->getForSale()) @@ -994,20 +1017,17 @@ bool LLPanelLandGeneral::cbBuyPass(const LLSD& notification, const LLSD& respons return false; } -// static -void LLPanelLandGeneral::onCommitAny(LLUICtrl *ctrl, void *userdata) +void LLPanelLandGeneral::onCommitAny() { - LLPanelLandGeneral *panelp = (LLPanelLandGeneral *)userdata; - - LLParcel* parcel = panelp->mParcel->getParcel(); + LLParcel* parcel = mParcel->getParcel(); if (!parcel) { return; } // Extract data from UI - std::string name = panelp->mEditName->getText(); - std::string desc = panelp->mEditDesc->getText(); + std::string name = mEditName->getText(); + std::string desc = mEditDesc->getText(); // Valid data from UI @@ -1015,8 +1035,8 @@ void LLPanelLandGeneral::onCommitAny(LLUICtrl *ctrl, void *userdata) parcel->setName(name); parcel->setDesc(desc); - BOOL allow_deed_to_group= panelp->mCheckDeedToGroup->get(); - BOOL contribute_with_deed = panelp->mCheckContributeWithDeed->get(); + BOOL allow_deed_to_group= mCheckDeedToGroup->get(); + BOOL contribute_with_deed = mCheckContributeWithDeed->get(); parcel->setParcelFlag(PF_ALLOW_DEED_TO_GROUP, allow_deed_to_group); parcel->setContributeWithDeed(contribute_with_deed); @@ -1025,20 +1045,18 @@ void LLPanelLandGeneral::onCommitAny(LLUICtrl *ctrl, void *userdata) LLViewerParcelMgr::getInstance()->sendParcelPropertiesUpdate( parcel ); // Might have changed properties, so let's redraw! - panelp->refresh(); + refresh(); } -// static -void LLPanelLandGeneral::onClickSellLand(void* data) +void LLPanelLandGeneral::onClickSellLand() { LLViewerParcelMgr::getInstance()->startSellLand(); + refresh(); } -// static -void LLPanelLandGeneral::onClickStopSellLand(void* data) +void LLPanelLandGeneral::onClickStopSellLand() { - LLPanelLandGeneral* panelp = (LLPanelLandGeneral*)data; - LLParcel* parcel = panelp->mParcel->getParcel(); + LLParcel* parcel = mParcel->getParcel(); parcel->setParcelFlag(PF_FOR_SALE, FALSE); parcel->setSalePrice(0); @@ -1052,7 +1070,7 @@ void LLPanelLandGeneral::onClickStopSellLand(void* data) //--------------------------------------------------------------------------- LLPanelLandObjects::LLPanelLandObjects(LLParcelSelectionHandle& parcel) : LLPanel(std::string("land_objects_panel")), - mParcel(parcel), + mParcelObjectBonus(NULL), mSWTotalObjects(NULL), mObjectContribution(NULL), @@ -1074,7 +1092,8 @@ LLPanelLandObjects::LLPanelLandObjects(LLParcelSelectionHandle& parcel) mOwnerList(NULL), mFirstReply(TRUE), mSelectedCount(0), - mSelectedIsGroup(FALSE) + mSelectedIsGroup(FALSE), + mParcel(parcel) { } @@ -1082,7 +1101,6 @@ LLPanelLandObjects::LLPanelLandObjects(LLParcelSelectionHandle& parcel) BOOL LLPanelLandObjects::postBuild() { - mFirstReply = TRUE; mParcelObjectBonus = getChild("parcel_object_bonus"); mSWTotalObjects = getChild("objects_available"); @@ -1091,37 +1109,37 @@ BOOL LLPanelLandObjects::postBuild() mOwnerObjects = getChild("owner_objects_text"); mBtnShowOwnerObjects = getChild("ShowOwner"); - mBtnShowOwnerObjects->setClickedCallback(onClickShowOwnerObjects, this); + mBtnShowOwnerObjects->setCommitCallback(boost::bind(&LLPanelLandObjects::onClickShowOwnerObjects, this)); mBtnReturnOwnerObjects = getChild("ReturnOwner..."); - mBtnReturnOwnerObjects->setClickedCallback(onClickReturnOwnerObjects, this); + mBtnReturnOwnerObjects->setCommitCallback(boost::bind(&LLPanelLandObjects::onClickReturnOwnerObjects, this)); mGroupObjects = getChild("group_objects_text"); mBtnShowGroupObjects = getChild("ShowGroup"); - mBtnShowGroupObjects->setClickedCallback(onClickShowGroupObjects, this); + mBtnShowGroupObjects->setCommitCallback(boost::bind(&LLPanelLandObjects::onClickShowGroupObjects, this)); mBtnReturnGroupObjects = getChild("ReturnGroup..."); - mBtnReturnGroupObjects->setClickedCallback(onClickReturnGroupObjects, this); + mBtnReturnGroupObjects->setCommitCallback(boost::bind(&LLPanelLandObjects::onClickReturnGroupObjects, this)); mOtherObjects = getChild("other_objects_text"); mBtnShowOtherObjects = getChild("ShowOther"); - mBtnShowOtherObjects->setClickedCallback(onClickShowOtherObjects, this); + mBtnShowOtherObjects->setCommitCallback(boost::bind(&LLPanelLandObjects::onClickShowOtherObjects, this)); mBtnReturnOtherObjects = getChild("ReturnOther..."); - mBtnReturnOtherObjects->setClickedCallback(onClickReturnOtherObjects, this); + mBtnReturnOtherObjects->setCommitCallback(boost::bind(&LLPanelLandObjects::onClickReturnOtherObjects, this)); mSelectedObjects = getChild("selected_objects_text"); mCleanOtherObjectsTime = getChild("clean other time"); mCleanOtherObjectsTime->setFocusLostCallback(boost::bind(&LLPanelLandObjects::onLostFocus, _1, this)); - mCleanOtherObjectsTime->setCommitCallback(onCommitClean, this); + mCleanOtherObjectsTime->setCommitCallback(boost::bind(&LLPanelLandObjects::onCommitClean, this)); mCleanOtherObjectsTime->setPrevalidate(LLLineEditor::prevalidateNonNegativeS32); mBtnRefresh = getChild("Refresh List"); - mBtnRefresh->setClickedCallback(onClickRefresh, this); + mBtnRefresh->setCommitCallback(boost::bind(&LLPanelLandObjects::onClickRefresh, this)); mBtnReturnOwnerList = getChild("Return objects..."); - mBtnReturnOwnerList->setClickedCallback(onClickReturnOwnerList, this); + mBtnReturnOwnerList->setCommitCallback(boost::bind(&LLPanelLandObjects::onClickReturnOwnerList, this)); mIconAvatarOnline = LLUI::getUIImage("icon_avatar_online.tga"); mIconAvatarInSim = LLUI::getUIImage("ff_visible_map.tga"); @@ -1131,46 +1149,16 @@ BOOL LLPanelLandObjects::postBuild() mOwnerList = getChild("owner list"); mOwnerList->sortByColumnIndex(3, FALSE); mOwnerList->setCommitCallback(boost::bind(&LLPanelLandObjects::onCommitList,this)); - mOwnerList->setDoubleClickCallback(boost::bind(&LLPanelLandObjects::onDoubleClickOwner, this)); return TRUE; } - - - // virtual LLPanelLandObjects::~LLPanelLandObjects() { } -// static -void LLPanelLandObjects::onDoubleClickOwner(void *userdata) -{ - LLPanelLandObjects *self = (LLPanelLandObjects *)userdata; - LLScrollListItem* item = self->mOwnerList->getFirstSelected(); - if (item) - { - LLUUID owner_id = item->getUUID(); - // Look up the selected name, for future dialog box use. - const LLScrollListCell* cell; - cell = item->getColumn(1); - if (!cell) - { - return; - } - // Is this a group? - BOOL is_group = cell->getValue().asString() == OWNER_GROUP; - if (is_group) - { - LLGroupActions::show(owner_id); - } - else - { - LLAvatarActions::showProfile(owner_id); - } - } -} +const LLStringExplicit zero_str("0"); // public void LLPanelLandObjects::refresh() @@ -1191,23 +1179,23 @@ void LLPanelLandObjects::refresh() mOwnerList->deleteAllItems(); mOwnerList->setEnabled(FALSE); - if (!parcel) + if (!parcel || gDisconnected) { - mSWTotalObjects->setTextArg("[COUNT]", llformat("%d", 0)); - mSWTotalObjects->setTextArg("[TOTAL]", llformat("%d", 0)); - mSWTotalObjects->setTextArg("[AVAILABLE]", llformat("%d", 0)); - mObjectContribution->setTextArg("[COUNT]", llformat("%d", 0)); - mTotalObjects->setTextArg("[COUNT]", llformat("%d", 0)); - mOwnerObjects->setTextArg("[COUNT]", llformat("%d", 0)); - mGroupObjects->setTextArg("[COUNT]", llformat("%d", 0)); - mOtherObjects->setTextArg("[COUNT]", llformat("%d", 0)); - mSelectedObjects->setTextArg("[COUNT]", llformat("%d", 0)); + mSWTotalObjects->setTextArg("[COUNT]", zero_str); + mSWTotalObjects->setTextArg("[TOTAL]", zero_str); + mSWTotalObjects->setTextArg("[AVAILABLE]", zero_str); + mObjectContribution->setTextArg("[COUNT]", zero_str); + mTotalObjects->setTextArg("[COUNT]", zero_str); + mOwnerObjects->setTextArg("[COUNT]", zero_str); + mGroupObjects->setTextArg("[COUNT]", zero_str); + mOtherObjects->setTextArg("[COUNT]", zero_str); + mSelectedObjects->setTextArg("[COUNT]", zero_str); } else { S32 sw_max = parcel->getSimWideMaxPrimCapacity(); S32 sw_total = parcel->getSimWidePrimCount(); - S32 max = llround(parcel->getMaxPrimCapacity() * parcel->getParcelPrimBonus()); + S32 max = ll_round(parcel->getMaxPrimCapacity() * parcel->getParcelPrimBonus()); S32 total = parcel->getPrimCount(); S32 owned = parcel->getOwnerPrimCount(); S32 group = parcel->getGroupPrimCount(); @@ -1285,12 +1273,6 @@ void LLPanelLandObjects::refresh() } } -// virtual -void LLPanelLandObjects::draw() -{ - LLPanel::draw(); -} - void send_other_clean_time_message(S32 parcel_local_id, S32 other_clean_time) { LLMessageSystem *msg = gMessageSystem; @@ -1309,6 +1291,7 @@ void send_other_clean_time_message(S32 parcel_local_id, S32 other_clean_time) msg->sendReliable(region->getHost()); } + void send_return_objects_message(S32 parcel_local_id, S32 return_type, uuid_list_t* owner_ids = NULL) { @@ -1367,9 +1350,7 @@ bool LLPanelLandObjects::callbackReturnOwnerObjects(const LLSD& notification, co } else { - std::string full_name; - gCacheName->getFullName(owner_id, full_name); - args["NAME"] = full_name; + args["NAME"] = LLSLURL("agent", owner_id, "completename").getSLURLString(); LLNotificationsUtil::add("OtherObjectsReturned", args); } send_return_objects_message(parcel->getLocalID(), RT_OWNER); @@ -1456,57 +1437,49 @@ bool LLPanelLandObjects::callbackReturnOwnerList(const LLSD& notification, const return false; } - -// static -void LLPanelLandObjects::onClickReturnOwnerList(void* userdata) +void LLPanelLandObjects::onClickReturnOwnerList() { - LLPanelLandObjects *self = (LLPanelLandObjects *)userdata; - - LLParcel* parcelp = self->mParcel->getParcel(); + LLParcel* parcelp = mParcel->getParcel(); if (!parcelp) return; // Make sure we have something selected. - if (self->mSelectedOwners.empty()) + if (mSelectedOwners.empty()) { return; } //uuid_list_t::iterator selected_itr = self->mSelectedOwners.begin(); //if (selected_itr == self->mSelectedOwners.end()) return; - send_parcel_select_objects(parcelp->getLocalID(), RT_LIST, &(self->mSelectedOwners)); + send_parcel_select_objects(parcelp->getLocalID(), RT_LIST, &mSelectedOwners); LLSD args; - args["NAME"] = self->mSelectedName; - args["N"] = llformat("%d",self->mSelectedCount); - if (self->mSelectedIsGroup) + args["NAME"] = mSelectedName; + args["N"] = fmt::to_string(mSelectedCount); + if (mSelectedIsGroup) { - LLNotificationsUtil::add("ReturnObjectsDeededToGroup", args, LLSD(), boost::bind(&LLPanelLandObjects::callbackReturnOwnerList, self, _1, _2)); + LLNotificationsUtil::add("ReturnObjectsDeededToGroup", args, LLSD(), boost::bind(&LLPanelLandObjects::callbackReturnOwnerList, this, _1, _2)); } else { - LLNotificationsUtil::add("ReturnObjectsOwnedByUser", args, LLSD(), boost::bind(&LLPanelLandObjects::callbackReturnOwnerList, self, _1, _2)); + LLNotificationsUtil::add("ReturnObjectsOwnedByUser", args, LLSD(), boost::bind(&LLPanelLandObjects::callbackReturnOwnerList, this, _1, _2)); } } - -// static -void LLPanelLandObjects::onClickRefresh(void* userdata) +void LLPanelLandObjects::onClickRefresh() { - LLPanelLandObjects *self = (LLPanelLandObjects*)userdata; - LLMessageSystem *msg = gMessageSystem; - LLParcel* parcel = self->mParcel->getParcel(); + LLParcel* parcel = mParcel->getParcel(); if (!parcel) return; LLViewerRegion* region = LLViewerParcelMgr::getInstance()->getSelectionRegion(); if (!region) return; // ready the list for results - self->mOwnerList->deleteAllItems(); - self->mOwnerList->setCommentText(LLTrans::getString("Searching")); - self->mOwnerList->setEnabled(FALSE); - self->mFirstReply = TRUE; + mOwnerList->deleteAllItems(); + mOwnerList->setCommentText(LLTrans::getString("Searching")); + mOwnerList->setEnabled(FALSE); + mFirstReply = TRUE; // send the message msg->newMessageFast(_PREHASH_ParcelObjectOwnersRequest); @@ -1522,16 +1495,16 @@ void LLPanelLandObjects::onClickRefresh(void* userdata) // static void LLPanelLandObjects::processParcelObjectOwnersReply(LLMessageSystem *msg, void **) { - LLPanelLandObjects* self = LLFloaterLand::getCurrentPanelLandObjects(); + LLPanelLandObjects* self = LLFloaterLand::getInstance()->mPanelObjects; if (!self) { - llwarns << "Received message for nonexistent LLPanelLandObject" - << llendl; + LL_WARNS() << "Received message for nonexistent LLPanelLandObject" + << LL_ENDL; return; } - const std::string FONT = "SANSSERIF"; + constexpr auto&& FONT = "SANSSERIF"; // Extract all of the owners. S32 rows = msg->getNumberOfBlocksFast(_PREHASH_Data); @@ -1540,7 +1513,7 @@ void LLPanelLandObjects::processParcelObjectOwnersReply(LLMessageSystem *msg, vo BOOL is_group_owned; S32 object_count; U32 most_recent_time = 0; - BOOL is_online = 0; + BOOL is_online; std::string object_count_str; //BOOL b_need_refresh = FALSE; @@ -1551,11 +1524,6 @@ void LLPanelLandObjects::processParcelObjectOwnersReply(LLMessageSystem *msg, vo self->mFirstReply = FALSE; } - LLVector3d mypos = gAgent.getPositionGlobal(); - std::vector avatar_ids; - std::vector positions; - LLWorld::instance().getAvatars(&avatar_ids, &positions, mypos, F32_MAX); - for(S32 i = 0; i < rows; ++i) { msg->getUUIDFast(_PREHASH_Data, _PREHASH_OwnerID, owner_id, i); @@ -1566,23 +1534,25 @@ void LLPanelLandObjects::processParcelObjectOwnersReply(LLMessageSystem *msg, vo { msg->getU32("DataExtended", "TimeStamp", most_recent_time, i); } + if (owner_id.isNull()) { continue; } - BOOL in_sim = (std::find(avatar_ids.begin(), avatar_ids.end(), owner_id) != avatar_ids.end()); - LLNameListCtrl::NameItem item_params; item_params.value = owner_id; - item_params.target = is_group_owned ? LLNameListCtrl::GROUP : LLNameListCtrl::INDIVIDUAL; + item_params.target = is_group_owned ? LLNameListItem::GROUP : LLNameListItem::INDIVIDUAL; + + uuid_vec_t avatar_ids; + LLWorld::instance().getAvatars(&avatar_ids, nullptr, gAgent.getPositionGlobal(), F32_MAX); if (is_group_owned) { item_params.columns.add().type("icon").value(self->mIconGroup->getName()).column("type"); item_params.columns.add().value(OWNER_GROUP).font(FONT).column("online_status"); } - else if (in_sim) + else if (std::find(avatar_ids.begin(), avatar_ids.end(), owner_id) != avatar_ids.end()) { item_params.columns.add().type("icon").value(self->mIconAvatarInSim->getName()).column("type"); item_params.columns.add().value(OWNER_INSIM).font(FONT).column("online_status"); @@ -1608,10 +1578,10 @@ void LLPanelLandObjects::processParcelObjectOwnersReply(LLMessageSystem *msg, vo item_params.columns.add().value(LLDate((time_t)most_recent_time)).font(FONT).column("mostrecent").type("date"); self->mOwnerList->addNameItemRow(item_params); - - lldebugs << "object owner " << owner_id << " (" << (is_group_owned ? "group" : "agent") - << ") owns " << object_count << " objects." << llendl; + LL_DEBUGS() << "object owner " << owner_id << " (" << (is_group_owned ? "group" : "agent") + << ") owns " << object_count << " objects." << LL_ENDL; } + // check for no results if (0 == self->mOwnerList->getItemCount()) { @@ -1623,9 +1593,10 @@ void LLPanelLandObjects::processParcelObjectOwnersReply(LLMessageSystem *msg, vo } } +// static void LLPanelLandObjects::onCommitList() { - if (FALSE == mOwnerList->getCanSelect()) + if (mOwnerList->getCanSelect() == FALSE) { return; } @@ -1644,7 +1615,7 @@ void LLPanelLandObjects::onCommitList() cell = item->getColumn(2); mSelectedName = cell->getValue().asString(); cell = item->getColumn(3); - mSelectedCount = atoi(cell->getValue().asString().c_str()); + mSelectedCount = std::stoi(cell->getValue().asString()); // Set the selection, and enable the return button. mSelectedOwners.clear(); @@ -1652,7 +1623,7 @@ void LLPanelLandObjects::onCommitList() mBtnReturnOwnerList->setEnabled(TRUE); // Highlight this user's objects - clickShowCore(this, RT_LIST, &(mSelectedOwners)); + clickShowCore(this, RT_LIST, &mSelectedOwners); } } @@ -1665,31 +1636,26 @@ void LLPanelLandObjects::clickShowCore(LLPanelLandObjects* self, S32 return_type send_parcel_select_objects(parcel->getLocalID(), return_type, list); } -// static -void LLPanelLandObjects::onClickShowOwnerObjects(void* userdata) +void LLPanelLandObjects::onClickShowOwnerObjects() { - clickShowCore((LLPanelLandObjects*)userdata, RT_OWNER); + clickShowCore(this, RT_OWNER); } -// static -void LLPanelLandObjects::onClickShowGroupObjects(void* userdata) +void LLPanelLandObjects::onClickShowGroupObjects() { - clickShowCore((LLPanelLandObjects*)userdata, (RT_GROUP)); + clickShowCore(this, (RT_GROUP)); } -// static -void LLPanelLandObjects::onClickShowOtherObjects(void* userdata) +void LLPanelLandObjects::onClickShowOtherObjects() { - clickShowCore((LLPanelLandObjects*)userdata, RT_OTHER); + clickShowCore(this, RT_OTHER); } -// static -void LLPanelLandObjects::onClickReturnOwnerObjects(void* userdata) +void LLPanelLandObjects::onClickReturnOwnerObjects() { S32 owned = 0; - LLPanelLandObjects* panelp = (LLPanelLandObjects*)userdata; - LLParcel* parcel = panelp->mParcel->getParcel(); + LLParcel* parcel = mParcel->getParcel(); if (!parcel) return; owned = parcel->getOwnerPrimCount(); @@ -1699,26 +1665,22 @@ void LLPanelLandObjects::onClickReturnOwnerObjects(void* userdata) LLUUID owner_id = parcel->getOwnerID(); LLSD args; - args["N"] = llformat("%d",owned); + args["N"] = fmt::to_string(owned); if (owner_id == gAgent.getID()) { - LLNotificationsUtil::add("ReturnObjectsOwnedBySelf", args, LLSD(), boost::bind(&LLPanelLandObjects::callbackReturnOwnerObjects, panelp, _1, _2)); + LLNotificationsUtil::add("ReturnObjectsOwnedBySelf", args, LLSD(), boost::bind(&LLPanelLandObjects::callbackReturnOwnerObjects, this, _1, _2)); } else { - std::string name; - gCacheName->getFullName(owner_id, name); - args["NAME"] = name; - LLNotificationsUtil::add("ReturnObjectsOwnedByUser", args, LLSD(), boost::bind(&LLPanelLandObjects::callbackReturnOwnerObjects, panelp, _1, _2)); + args["NAME"] = LLSLURL("agent", owner_id, "completename").getSLURLString(); + LLNotificationsUtil::add("ReturnObjectsOwnedByUser", args, LLSD(), boost::bind(&LLPanelLandObjects::callbackReturnOwnerObjects, this, _1, _2)); } } -// static -void LLPanelLandObjects::onClickReturnGroupObjects(void* userdata) +void LLPanelLandObjects::onClickReturnGroupObjects() { - LLPanelLandObjects* panelp = (LLPanelLandObjects*)userdata; - LLParcel* parcel = panelp->mParcel->getParcel(); + LLParcel* parcel = mParcel->getParcel(); if (!parcel) return; send_parcel_select_objects(parcel->getLocalID(), RT_GROUP); @@ -1731,16 +1693,14 @@ void LLPanelLandObjects::onClickReturnGroupObjects(void* userdata) args["N"] = llformat("%d", parcel->getGroupPrimCount()); // create and show confirmation textbox - LLNotificationsUtil::add("ReturnObjectsDeededToGroup", args, LLSD(), boost::bind(&LLPanelLandObjects::callbackReturnGroupObjects, panelp, _1, _2)); + LLNotificationsUtil::add("ReturnObjectsDeededToGroup", args, LLSD(), boost::bind(&LLPanelLandObjects::callbackReturnGroupObjects, this, _1, _2)); } -// static -void LLPanelLandObjects::onClickReturnOtherObjects(void* userdata) +void LLPanelLandObjects::onClickReturnOtherObjects() { S32 other = 0; - LLPanelLandObjects* panelp = (LLPanelLandObjects*)userdata; - LLParcel* parcel = panelp->mParcel->getParcel(); + LLParcel* parcel = mParcel->getParcel(); if (!parcel) return; other = parcel->getOtherPrimCount(); @@ -1756,7 +1716,7 @@ void LLPanelLandObjects::onClickReturnOtherObjects(void* userdata) gCacheName->getGroupName(parcel->getGroupID(), group_name); args["NAME"] = group_name; - LLNotificationsUtil::add("ReturnObjectsNotOwnedByGroup", args, LLSD(), boost::bind(&LLPanelLandObjects::callbackReturnOtherObjects, panelp, _1, _2)); + LLNotificationsUtil::add("ReturnObjectsNotOwnedByGroup", args, LLSD(), boost::bind(&LLPanelLandObjects::callbackReturnOtherObjects, this, _1, _2)); } else { @@ -1764,14 +1724,12 @@ void LLPanelLandObjects::onClickReturnOtherObjects(void* userdata) if (owner_id == gAgent.getID()) { - LLNotificationsUtil::add("ReturnObjectsNotOwnedBySelf", args, LLSD(), boost::bind(&LLPanelLandObjects::callbackReturnOtherObjects, panelp, _1, _2)); + LLNotificationsUtil::add("ReturnObjectsNotOwnedBySelf", args, LLSD(), boost::bind(&LLPanelLandObjects::callbackReturnOtherObjects, this, _1, _2)); } else { - std::string name; - gCacheName->getFullName(owner_id, name); - args["NAME"] = name; - LLNotificationsUtil::add("ReturnObjectsNotOwnedByUser", args, LLSD(), boost::bind(&LLPanelLandObjects::callbackReturnOtherObjects, panelp, _1, _2)); + args["NAME"] = LLSLURL("agent", owner_id, "completename").getSLURLString(); + LLNotificationsUtil::add("ReturnObjectsNotOwnedByUser", args, LLSD(), boost::bind(&LLPanelLandObjects::callbackReturnOtherObjects, this, _1, _2)); } } } @@ -1779,20 +1737,24 @@ void LLPanelLandObjects::onClickReturnOtherObjects(void* userdata) // static void LLPanelLandObjects::onLostFocus(LLFocusableElement* caller, void* user_data) { - onCommitClean((LLUICtrl*)caller, user_data); + LLPanelLandObjects *lop = static_cast(user_data); + if (lop) lop->onCommitClean(); } -// static -void LLPanelLandObjects::onCommitClean(LLUICtrl *caller, void* user_data) +void LLPanelLandObjects::onCommitClean() { - LLPanelLandObjects *lop = (LLPanelLandObjects *)user_data; - LLParcel* parcel = lop->mParcel->getParcel(); + LLParcel* parcel = mParcel->getParcel(); if (parcel) { - lop->mOtherTime = atoi(lop->mCleanOtherObjectsTime->getText().c_str()); + S32 return_time = std::stoi(mCleanOtherObjectsTime->getText()); + // Only send return time if it has changed + if (return_time != mOtherTime) + { + mOtherTime = return_time; - parcel->setCleanOtherTime(lop->mOtherTime); - send_other_clean_time_message(parcel->getLocalID(), lop->mOtherTime); + parcel->setCleanOtherTime(mOtherTime); + send_other_clean_time_message(parcel->getLocalID(), mOtherTime); + } } } @@ -1824,8 +1786,8 @@ LLPanelLandOptions::LLPanelLandOptions(LLParcelSelectionHandle& parcel) mGamingCtrl(NULL), mPushRestrictionCtrl(NULL), mSeeAvatarsCtrl(NULL), - mParcel(parcel), - mPublishHelpButton(NULL) + mPublishHelpButton(NULL), + mParcel(parcel) { } @@ -1833,48 +1795,48 @@ LLPanelLandOptions::LLPanelLandOptions(LLParcelSelectionHandle& parcel) BOOL LLPanelLandOptions::postBuild() { mCheckEditObjects = getChild( "edit objects check"); - childSetCommitCallback("edit objects check", onCommitAny, this); + mCheckEditObjects->setCommitCallback(boost::bind(&LLPanelLandOptions::onCommitAny, this)); mCheckEditGroupObjects = getChild( "edit group objects check"); - childSetCommitCallback("edit group objects check", onCommitAny, this); + mCheckEditGroupObjects->setCommitCallback(boost::bind(&LLPanelLandOptions::onCommitAny, this)); mCheckAllObjectEntry = getChild( "all object entry check"); - childSetCommitCallback("all object entry check", onCommitAny, this); + mCheckAllObjectEntry->setCommitCallback(boost::bind(&LLPanelLandOptions::onCommitAny, this)); mCheckGroupObjectEntry = getChild( "group object entry check"); - childSetCommitCallback("group object entry check", onCommitAny, this); + mCheckGroupObjectEntry->setCommitCallback(boost::bind(&LLPanelLandOptions::onCommitAny, this)); mCheckEditLand = getChild( "edit land check"); - childSetCommitCallback("edit land check", onCommitAny, this); + mCheckEditLand->setCommitCallback(boost::bind(&LLPanelLandOptions::onCommitAny, this)); mCheckLandmark = getChild( "check landmark"); - childSetCommitCallback("check landmark", onCommitAny, this); + mCheckLandmark->setCommitCallback(boost::bind(&LLPanelLandOptions::onCommitAny, this)); mCheckLandmark->setVisible(!gHippoGridManager->getConnectedGrid()->isSecondLife()); mCheckGroupScripts = getChild( "check group scripts"); - childSetCommitCallback("check group scripts", onCommitAny, this); + mCheckGroupScripts->setCommitCallback(boost::bind(&LLPanelLandOptions::onCommitAny, this)); mCheckFly = getChild( "check fly"); - childSetCommitCallback("check fly", onCommitAny, this); + mCheckFly->setCommitCallback(boost::bind(&LLPanelLandOptions::onCommitAny, this)); mCheckOtherScripts = getChild( "check other scripts"); - childSetCommitCallback("check other scripts", onCommitAny, this); + mCheckOtherScripts->setCommitCallback(boost::bind(&LLPanelLandOptions::onCommitAny, this)); mCheckSafe = getChild( "check safe"); - childSetCommitCallback("check safe", onCommitAny, this); + mCheckSafe->setCommitCallback(boost::bind(&LLPanelLandOptions::onCommitAny, this)); mPushRestrictionCtrl = getChild( "PushRestrictCheck"); - childSetCommitCallback("PushRestrictCheck", onCommitAny, this); + mPushRestrictionCtrl->setCommitCallback(boost::bind(&LLPanelLandOptions::onCommitAny, this)); mSeeAvatarsCtrl = getChild( "SeeAvatarsCheck"); - childSetCommitCallback("SeeAvatarsCheck", onCommitAny, this); + mSeeAvatarsCtrl->setCommitCallback(boost::bind(&LLPanelLandOptions::onCommitAny, this)); mCheckShowDirectory = getChild( "ShowDirectoryCheck"); - childSetCommitCallback("ShowDirectoryCheck", onCommitAny, this); + mCheckShowDirectory->setCommitCallback(boost::bind(&LLPanelLandOptions::onCommitAny, this)); if (gAgent.getAgentAccess().isInTransition()) @@ -1883,26 +1845,28 @@ BOOL LLPanelLandOptions::postBuild() // Post-transition, it goes away. We can remove this conditional // after the transition and just use the "else" clause. mCategoryCombo = getChild( "land category with adult"); - childSetCommitCallback("land category with adult", onCommitAny, this); } else { // this is the code that should be preserved post-transition // you could also change the XML to set visibility and enabled true. mCategoryCombo = getChild( "land category"); - childSetCommitCallback("land category", onCommitAny, this); } + mCategoryCombo->setCommitCallback(boost::bind(&LLPanelLandOptions::onCommitAny, this)); mCategoryCombo->setVisible(true); mCategoryCombo->setEnabled(true); mMatureCtrl = getChild( "MatureCheck"); - childSetCommitCallback("MatureCheck", onCommitAny, this); + mMatureCtrl->setCommitCallback(boost::bind(&LLPanelLandOptions::onCommitAny, this)); - mGamingCtrl = getChild( "GamingCheck"); - childSetCommitCallback("GamingCheck", onCommitAny, this); - mGamingCtrl->setVisible((gAgent.getRegion()->getGamingFlags() & REGION_GAMING_PRESENT) && !(gAgent.getRegion()->getGamingFlags() & REGION_GAMING_HIDE_PARCEL)); - mGamingCtrl->setEnabled(false); + if (mGamingCtrl = getChild( "GamingCheck")) + { + auto region = gAgent.getRegion(); + mGamingCtrl->setCommitCallback(boost::bind(&LLPanelLandOptions::onCommitAny, this)); + mGamingCtrl->setVisible(region && (region->getGamingFlags() & REGION_GAMING_PRESENT) && !(region->getGamingFlags() & REGION_GAMING_HIDE_PARCEL)); + mGamingCtrl->setEnabled(false); + } mPublishHelpButton = getChild("?"); mPublishHelpButton->setClickedCallback(onClickPublishHelp, this); @@ -1920,29 +1884,29 @@ BOOL LLPanelLandOptions::postBuild() mSnapshotCtrl = getChild("snapshot_ctrl"); if (mSnapshotCtrl) { - mSnapshotCtrl->setCommitCallback( onCommitAny, this ); + mSnapshotCtrl->setCommitCallback(boost::bind(&LLPanelLandOptions::onCommitAny, this)); mSnapshotCtrl->setAllowNoTexture ( TRUE ); mSnapshotCtrl->setImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER); mSnapshotCtrl->setNonImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER); } else { - llwarns << "LLUICtrlFactory::getTexturePickerByName() returned NULL for 'snapshot_ctrl'" << llendl; + LL_WARNS() << "LLUICtrlFactory::getTexturePickerByName() returned NULL for 'snapshot_ctrl'" << LL_ENDL; } mLocationText = getChild("landing_point"); mSetBtn = getChild("Set"); - mSetBtn->setClickedCallback(onClickSet, this); + mSetBtn->setCommitCallback(boost::bind(&LLPanelLandOptions::onClickSet, this)); mClearBtn = getChild("Clear"); - mClearBtn->setClickedCallback(onClickClear, this); + mClearBtn->setCommitCallback(boost::bind(&LLPanelLandOptions::onClickClear, this)); mLandingTypeCombo = getChild( "landing type"); - childSetCommitCallback("landing type", onCommitAny, this); + mLandingTypeCombo->setCommitCallback(boost::bind(&LLPanelLandOptions::onCommitAny, this)); getChild("snapshot_ctrl")->setFallbackImageName("default_land_picture.j2c"); @@ -1961,7 +1925,7 @@ void LLPanelLandOptions::refresh() refreshSearch(); LLParcel *parcel = mParcel->getParcel(); - if (!parcel) + if (!parcel || gDisconnected) { mCheckEditObjects ->set(FALSE); mCheckEditObjects ->setEnabled(FALSE); @@ -2077,6 +2041,10 @@ void LLPanelLandOptions::refresh() mSnapshotCtrl->setImageAssetID(parcel->getSnapshotID()); mSnapshotCtrl->setEnabled( can_change_identity ); + // find out where we're looking and convert that to an angle in degrees on a regular compass (not the internal representation) + LLVector3 user_look_at = parcel->getUserLookAt(); + U32 user_look_at_angle = ( (U32)( ( atan2(user_look_at[1], -user_look_at[0]) + F_PI * 2 ) * RAD_TO_DEG + 0.5) - 90) % 360; + LLVector3 pos = parcel->getUserLocation(); if (pos.isExactlyZero()) { @@ -2084,10 +2052,11 @@ void LLPanelLandOptions::refresh() } else { - mLocationText->setTextArg("[LANDING]",llformat("%d, %d, %d", - llround(pos.mV[VX]), - llround(pos.mV[VY]), - llround(pos.mV[VZ]))); + mLocationText->setTextArg("[LANDING]",llformat("%d, %d, %d (%d\xC2\xB0)", + ll_round(pos.mV[VX]), + ll_round(pos.mV[VY]), + ll_round(pos.mV[VZ]), + user_look_at_angle)); } mSetBtn->setEnabled( can_change_landing_point ); @@ -2150,12 +2119,11 @@ void LLPanelLandOptions::draw() void LLPanelLandOptions::refreshSearch() { LLParcel *parcel = mParcel->getParcel(); - if (!parcel) + if (!parcel || gDisconnected) { mCheckShowDirectory->set(FALSE); mCheckShowDirectory->setEnabled(FALSE); - // *TODO:Translate const std::string& none_string = LLParcel::getCategoryUIString(LLParcel::C_NONE); mCategoryCombo->setSimple(none_string); mCategoryCombo->setEnabled(FALSE); @@ -2167,7 +2135,7 @@ void LLPanelLandOptions::refreshSearch() bool can_change = LLViewerParcelMgr::isParcelModifiableByAgent( - parcel, GP_LAND_CHANGE_IDENTITY) + parcel, GP_LAND_FIND_PLACES) && region && !(region->getRegionFlag(REGION_FLAGS_BLOCK_PARCEL_SEARCH)); @@ -2185,7 +2153,6 @@ void LLPanelLandOptions::refreshSearch() mCheckShowDirectory->setLabelArg("[DIRECTORYFEE]", gHippoGridManager->getConnectedGrid()->getDirectoryFee()); // Set by string in case the order in UI doesn't match the order by index. - // *TODO:Translate LLParcel::ECategory cat = parcel->getCategory(); const std::string& category_string = LLParcel::getCategoryUIString(cat); mCategoryCombo->setSimple(category_string); @@ -2245,38 +2212,35 @@ void LLPanelLandOptions::refreshSearch() } -// static -void LLPanelLandOptions::onCommitAny(LLUICtrl *ctrl, void *userdata) +void LLPanelLandOptions::onCommitAny() { - LLPanelLandOptions *self = (LLPanelLandOptions *)userdata; - - LLParcel* parcel = self->mParcel->getParcel(); + LLParcel* parcel = mParcel->getParcel(); if (!parcel) { return; } // Extract data from UI - BOOL create_objects = self->mCheckEditObjects->get(); - BOOL create_group_objects = self->mCheckEditGroupObjects->get() || self->mCheckEditObjects->get(); - BOOL all_object_entry = self->mCheckAllObjectEntry->get(); - BOOL group_object_entry = self->mCheckGroupObjectEntry->get() || self->mCheckAllObjectEntry->get(); - BOOL allow_terraform = self->mCheckEditLand->get(); - BOOL allow_damage = !self->mCheckSafe->get(); - BOOL allow_fly = self->mCheckFly->get(); - BOOL allow_landmark = self->mCheckLandmark->get(); - BOOL allow_other_scripts = self->mCheckOtherScripts->get(); - BOOL allow_group_scripts = self->mCheckGroupScripts->get() || allow_other_scripts; + BOOL create_objects = mCheckEditObjects->get(); + BOOL create_group_objects = mCheckEditGroupObjects->get() || mCheckEditObjects->get(); + BOOL all_object_entry = mCheckAllObjectEntry->get(); + BOOL group_object_entry = mCheckGroupObjectEntry->get() || mCheckAllObjectEntry->get(); + BOOL allow_terraform = mCheckEditLand->get(); + BOOL allow_damage = !mCheckSafe->get(); + BOOL allow_fly = mCheckFly->get(); + BOOL allow_landmark = mCheckLandmark->get(); + BOOL allow_other_scripts = mCheckOtherScripts->get(); + BOOL allow_group_scripts = mCheckGroupScripts->get() || allow_other_scripts; BOOL allow_publish = FALSE; - BOOL mature_publish = self->mMatureCtrl->get(); - BOOL push_restriction = self->mPushRestrictionCtrl->get(); - BOOL see_avs = self->mSeeAvatarsCtrl->get(); - bool gaming = self->mGamingCtrl->get(); - BOOL show_directory = self->mCheckShowDirectory->get(); + BOOL mature_publish = mMatureCtrl->get(); + BOOL push_restriction = mPushRestrictionCtrl->get(); + BOOL see_avs = mSeeAvatarsCtrl->get(); + bool gaming = mGamingCtrl->get(); + BOOL show_directory = mCheckShowDirectory->get(); // we have to get the index from a lookup, not from the position in the dropdown! - S32 category_index = LLParcel::getCategoryFromString(self->mCategoryCombo->getSelectedValue()); - S32 landing_type_index = self->mLandingTypeCombo->getCurrentIndex(); - LLUUID snapshot_id = self->mSnapshotCtrl->getImageAssetID(); + S32 category_index = LLParcel::getCategoryFromString(mCategoryCombo->getSelectedValue()); + S32 landing_type_index = mLandingTypeCombo->getCurrentIndex(); + LLUUID snapshot_id = mSnapshotCtrl->getImageAssetID(); LLViewerRegion* region; region = LLViewerParcelMgr::getInstance()->getSelectionRegion(); @@ -2285,8 +2249,8 @@ void LLPanelLandOptions::onCommitAny(LLUICtrl *ctrl, void *userdata) if ( (!allow_other_scripts && parcel->getParcelFlag(PF_ALLOW_OTHER_SCRIPTS)) || (!allow_group_scripts && parcel->getParcelFlag(PF_ALLOW_GROUP_SCRIPTS)) ) { // Don't allow turning off "Run Scripts" if damage is allowed in the region - self->mCheckOtherScripts->set(parcel->getParcelFlag(PF_ALLOW_OTHER_SCRIPTS)); // Restore UI to actual settings - self->mCheckGroupScripts->set(parcel->getParcelFlag(PF_ALLOW_GROUP_SCRIPTS)); + mCheckOtherScripts->set(parcel->getParcelFlag(PF_ALLOW_OTHER_SCRIPTS)); // Restore UI to actual settings + mCheckGroupScripts->set(parcel->getParcelFlag(PF_ALLOW_GROUP_SCRIPTS)); LLNotificationsUtil::add("UnableToDisableOutsideScripts"); return; } @@ -2317,16 +2281,12 @@ void LLPanelLandOptions::onCommitAny(LLUICtrl *ctrl, void *userdata) LLViewerParcelMgr::getInstance()->sendParcelPropertiesUpdate( parcel ); // Might have changed properties, so let's redraw! - self->refresh(); + refresh(); } - -// static -void LLPanelLandOptions::onClickSet(void* userdata) +void LLPanelLandOptions::onClickSet() { - LLPanelLandOptions* self = (LLPanelLandOptions*)userdata; - - LLParcel* selected_parcel = self->mParcel->getParcel(); + LLParcel* selected_parcel = mParcel->getParcel(); if (!selected_parcel) return; LLParcel* agent_parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); @@ -2344,14 +2304,12 @@ void LLPanelLandOptions::onClickSet(void* userdata) LLViewerParcelMgr::getInstance()->sendParcelPropertiesUpdate(selected_parcel); - self->refresh(); + refresh(); } -void LLPanelLandOptions::onClickClear(void* userdata) +void LLPanelLandOptions::onClickClear() { - LLPanelLandOptions* self = (LLPanelLandOptions*)userdata; - - LLParcel* selected_parcel = self->mParcel->getParcel(); + LLParcel* selected_parcel = mParcel->getParcel(); if (!selected_parcel) return; // yes, this magic number of 0,0,0 means that it is clear @@ -2361,9 +2319,10 @@ void LLPanelLandOptions::onClickClear(void* userdata) LLViewerParcelMgr::getInstance()->sendParcelPropertiesUpdate(selected_parcel); - self->refresh(); + refresh(); } + // static void LLPanelLandOptions::onClickPublishHelp(void*) { @@ -2392,27 +2351,29 @@ void LLPanelLandOptions::onClickPublishHelp(void*) //--------------------------------------------------------------------------- LLPanelLandAccess::LLPanelLandAccess(LLParcelSelectionHandle& parcel) - : LLPanel(std::string("land_access_panel")), - mParcel(parcel) + : LLPanel(std::string("land_access_panel")) + , mListAccess(nullptr) + , mListBanned(nullptr) + , mParcel(parcel) { } BOOL LLPanelLandAccess::postBuild() { - childSetCommitCallback("public_access", onCommitPublicAccess, this); - childSetCommitCallback("limit_payment", onCommitAny, this); - childSetCommitCallback("limit_age_verified", onCommitAny, this); - childSetCommitCallback("GroupCheck", onCommitAny, this); - childSetCommitCallback("PassCheck", onCommitAny, this); - childSetCommitCallback("pass_combo", onCommitAny, this); - childSetCommitCallback("PriceSpin", onCommitAny, this); - childSetCommitCallback("HoursSpin", onCommitAny, this); + getChild("public_access")->setCommitCallback(boost::bind(&LLPanelLandAccess::onCommitPublicAccess, this, _1)); + getChild("limit_payment")->setCommitCallback(boost::bind(&LLPanelLandAccess::onCommitAny, this)); + getChild("limit_age_verified")->setCommitCallback(boost::bind(&LLPanelLandAccess::onCommitAny, this)); + getChild("GroupCheck")->setCommitCallback(boost::bind(&LLPanelLandAccess::onCommitGroupCheck, this, _1)); + getChild("PassCheck")->setCommitCallback(boost::bind(&LLPanelLandAccess::onCommitAny, this)); + getChild("pass_combo")->setCommitCallback(boost::bind(&LLPanelLandAccess::onCommitAny, this)); + getChild("PriceSpin")->setCommitCallback(boost::bind(&LLPanelLandAccess::onCommitAny, this)); + getChild("HoursSpin")->setCommitCallback(boost::bind(&LLPanelLandAccess::onCommitAny, this)); childSetAction("add_allowed", boost::bind(&LLPanelLandAccess::onClickAddAccess, this)); - childSetAction("remove_allowed", onClickRemoveAccess, this); + getChild("remove_allowed")->setCommitCallback(boost::bind(&LLPanelLandAccess::onClickRemoveAccess, this)); childSetAction("add_banned", boost::bind(&LLPanelLandAccess::onClickAddBanned, this)); - childSetAction("remove_banned", onClickRemoveBanned, this); + getChild("remove_banned")->setCommitCallback(boost::bind(&LLPanelLandAccess::onClickRemoveBanned, this)); mListAccess = getChild("AccessList"); if (mListAccess) @@ -2444,135 +2405,126 @@ void LLPanelLandAccess::refresh() LLParcel *parcel = mParcel->getParcel(); // Display options - if (parcel) + if (parcel && !gDisconnected) { BOOL use_access_list = parcel->getParcelFlag(PF_USE_ACCESS_LIST); BOOL use_group = parcel->getParcelFlag(PF_USE_ACCESS_GROUP); BOOL public_access = !use_access_list && !use_group; - getChild("public_access")->setValue(public_access ); - getChild("GroupCheck")->setValue(use_group ); + getChild("public_access")->setValue(public_access); + getChild("GroupCheck")->setValue(use_group); std::string group_name; gCacheName->getGroupName(parcel->getGroupID(), group_name); getChild("GroupCheck")->setLabelArg("[GROUP]", group_name ); - + + const auto always = getString("Always"); + + static const LLCachedControl date("ShortDateFormat"); + static const LLCachedControl time("LongTimeFormat"); + const auto time_format = date() + ' ' + time(); + // Allow list if (mListAccess) { // Clear the sort order so we don't re-sort on every add. + const auto order = mListAccess->getSortOrder(); mListAccess->clearSortOrder(); mListAccess->deleteAllItems(); S32 count = parcel->mAccessList.size(); - getChild("AccessList")->setToolTipArg(LLStringExplicit("[LISTED]"), llformat("%d",count)); - getChild("AccessList")->setToolTipArg(LLStringExplicit("[MAX]"), llformat("%d",PARCEL_MAX_ACCESS_LIST)); + getChild("AllowedText")->setTextArg("[COUNT]", llformat("%d",count)); + getChild("AllowedText")->setTextArg("[MAX]", llformat("%d",PARCEL_MAX_ACCESS_LIST)); - for (access_map_const_iterator cit = parcel->mAccessList.begin(); - cit != parcel->mAccessList.end(); ++cit) + mListAccess->setToolTipArg(LLStringExplicit("[LISTED]"), llformat("%d",count)); + mListAccess->setToolTipArg(LLStringExplicit("[MAX]"), llformat("%d",PARCEL_MAX_ACCESS_LIST)); + + for (const auto& pair : parcel->mAccessList) { - const LLAccessEntry& entry = (*cit).second; - std::string suffix; + const LLAccessEntry& entry = pair.second; + LLSD item; + item["id"] = entry.mID; + LLSD& columns = item["columns"]; + columns[0]["column"] = "name"; // to be populated later + columns[1]["column"] = "duration"; if (entry.mTime != 0) { - S32 now = time(NULL); - S32 seconds = entry.mTime - now; - if (seconds < 0) seconds = 0; - suffix.assign(" ("); - if (seconds >= 120) - { - std::string buf = llformat("%d ", (seconds/60)) + getString("minutes"); - suffix.append(buf); - } - else if (seconds >= 60) - { - suffix.append(getString("1_minute")); - } - else if (seconds == 1) - { - suffix.append(getString("1_second")); - } - else - { - std::string buf = llformat("%d ", seconds) + getString("seconds"); - suffix.append(buf); - } - suffix.append(" " + getString("remaining") + ")"); + columns[1]["type"] = "date"; + columns[1]["format"] = time_format; + columns[1]["value"] = LLDate(entry.mTime); } - mListAccess->addNameItem(entry.mID, ADD_SORTED, TRUE, suffix); + else + { + columns[1]["value"] = always; + } + mListAccess->addElement(item); } - mListAccess->sortByName(TRUE); + mListAccess->setSortOrder(order); } // Ban List if(mListBanned) { // Clear the sort order so we don't re-sort on every add. + const auto order = mListBanned->getSortOrder(); mListBanned->clearSortOrder(); mListBanned->deleteAllItems(); S32 count = parcel->mBanList.size(); + getChild("BanCheck")->setTextArg("[COUNT]", llformat("%d",count)); + getChild("BanCheck")->setTextArg("[MAX]", llformat("%d",PARCEL_MAX_ACCESS_LIST)); - getChild("BannedList")->setToolTipArg(LLStringExplicit("[LISTED]"), llformat("%d",count)); - getChild("BannedList")->setToolTipArg(LLStringExplicit("[MAX]"), llformat("%d",PARCEL_MAX_ACCESS_LIST)); + mListBanned->setToolTipArg(LLStringExplicit("[LISTED]"), llformat("%d",count)); + mListBanned->setToolTipArg(LLStringExplicit("[MAX]"), llformat("%d",PARCEL_MAX_ACCESS_LIST)); - for (access_map_const_iterator cit = parcel->mBanList.begin(); - cit != parcel->mBanList.end(); ++cit) + for (const auto& pair : parcel->mBanList) { - const LLAccessEntry& entry = (*cit).second; - std::string suffix; + const LLAccessEntry& entry = pair.second; + LLSD item; + item["id"] = entry.mID; + LLSD& columns = item["columns"]; + columns[0]["column"] = "name"; // to be populated later + columns[1]["column"] = "duration"; if (entry.mTime != 0) { - S32 now = time(NULL); - S32 seconds = entry.mTime - now; - if (seconds < 0) seconds = 0; - suffix.assign(" ("); - if (seconds >= 120) - { - std::string buf = llformat("%d ", (seconds/60)) + getString("minutes"); - suffix.append(buf); - } - else if (seconds >= 60) - { - suffix.append(getString("1_minute")); - } - else if (seconds == 1) - { - suffix.append(getString("1_second")); - } - else - { - std::string buf = llformat("%d ", seconds) + getString("seconds"); - suffix.append(buf); - } - suffix.append(" " + getString("remaining") + ")"); + columns[1]["type"] = "date"; + columns[1]["format"] = time_format; + columns[1]["value"] = LLDate(entry.mTime); + } + else + { + columns[1]["value"] = always; } - mListBanned->addNameItem(entry.mID, ADD_SORTED, TRUE, suffix); + mListBanned->addElement(item); } - mListBanned->sortByName(TRUE); + mListBanned->setSortOrder(order); } if(parcel->getRegionDenyAnonymousOverride()) { getChild("limit_payment")->setValue(TRUE); + getChild("limit_payment")->setLabelArg("[ESTATE_PAYMENT_LIMIT]", getString("access_estate_defined") ); } else { getChild("limit_payment")->setValue((parcel->getParcelFlag(PF_DENY_ANONYMOUS))); + getChild("limit_payment")->setLabelArg("[ESTATE_PAYMENT_LIMIT]", std::string() ); } if(parcel->getRegionDenyAgeUnverifiedOverride()) { getChild("limit_age_verified")->setValue(TRUE); + getChild("limit_age_verified")->setLabelArg("[ESTATE_AGE_LIMIT]", getString("access_estate_defined") ); } else { getChild("limit_age_verified")->setValue((parcel->getParcelFlag(PF_DENY_AGEUNVERIFIED))); + getChild("limit_age_verified")->setLabelArg("[ESTATE_AGE_LIMIT]", std::string() ); } BOOL use_pass = parcel->getParcelFlag(PF_USE_PASS_LIST); - getChild("PassCheck")->setValue(use_pass ); + getChild("PassCheck")->setValue(use_pass); LLCtrlSelectionInterface* passcombo = childGetSelectionInterface("pass_combo"); if (passcombo) { - if (public_access || !use_pass || !use_group) + if (public_access || !use_pass) { passcombo->selectByValue("anyone"); } @@ -2595,10 +2547,10 @@ void LLPanelLandAccess::refresh() getChild("PassCheck")->setValue(FALSE); getChild("PriceSpin")->setValue((F32)PARCEL_PASS_PRICE_DEFAULT); getChild("HoursSpin")->setValue(PARCEL_PASS_HOURS_DEFAULT ); - getChild("AccessList")->setToolTipArg(LLStringExplicit("[LISTED]"), llformat("%d",0)); - getChild("AccessList")->setToolTipArg(LLStringExplicit("[MAX]"), llformat("%d",0)); - getChild("BannedList")->setToolTipArg(LLStringExplicit("[LISTED]"), llformat("%d",0)); - getChild("BannedList")->setToolTipArg(LLStringExplicit("[MAX]"), llformat("%d",0)); + mListAccess->setToolTipArg(LLStringExplicit("[LISTED]"), zero_str); + mListAccess->setToolTipArg(LLStringExplicit("[MAX]"), zero_str); + mListBanned->setToolTipArg(LLStringExplicit("[LISTED]"), zero_str); + mListBanned->setToolTipArg(LLStringExplicit("[MAX]"), zero_str); } } @@ -2612,11 +2564,15 @@ void LLPanelLandAccess::refresh_ui() getChildView("pass_combo")->setEnabled(FALSE); getChildView("PriceSpin")->setEnabled(FALSE); getChildView("HoursSpin")->setEnabled(FALSE); - getChildView("AccessList")->setEnabled(FALSE); - getChildView("BannedList")->setEnabled(FALSE); + mListAccess->setEnabled(FALSE); + mListBanned->setEnabled(FALSE); + getChildView("add_allowed")->setEnabled(FALSE); + getChildView("remove_allowed")->setEnabled(FALSE); + getChildView("add_banned")->setEnabled(FALSE); + getChildView("remove_banned")->setEnabled(FALSE); LLParcel *parcel = mParcel->getParcel(); - if (parcel) + if (parcel && !gDisconnected) { BOOL can_manage_allowed = LLViewerParcelMgr::isParcelModifiableByAgent(parcel, GP_LAND_MANAGE_ALLOWED); BOOL can_manage_banned = LLViewerParcelMgr::isParcelModifiableByAgent(parcel, GP_LAND_MANAGE_BANNED); @@ -2655,7 +2611,7 @@ void LLPanelLandAccess::refresh_ui() getChildView("GroupCheck")->setEnabled(FALSE); getChildView("PassCheck")->setEnabled(FALSE); getChildView("pass_combo")->setEnabled(FALSE); - getChildView("AccessList")->setEnabled(FALSE); + mListAccess->setEnabled(FALSE); } else { @@ -2664,26 +2620,25 @@ void LLPanelLandAccess::refresh_ui() std::string group_name; if (gCacheName->getGroupName(parcel->getGroupID(), group_name)) - { + { getChildView("GroupCheck")->setEnabled(can_manage_allowed); } - BOOL group_access = getChild("GroupCheck")->getValue().asBoolean(); BOOL sell_passes = getChild("PassCheck")->getValue().asBoolean(); getChildView("PassCheck")->setEnabled(can_manage_allowed); if (sell_passes) { - getChildView("pass_combo")->setEnabled(group_access && can_manage_allowed); + getChildView("pass_combo")->setEnabled(can_manage_allowed); getChildView("PriceSpin")->setEnabled(can_manage_allowed); getChildView("HoursSpin")->setEnabled(can_manage_allowed); } } - getChildView("AccessList")->setEnabled(true/*can_manage_allowed*/); + mListAccess->setEnabled(true/*can_manage_allowed*/); S32 allowed_list_count = parcel->mAccessList.size(); getChildView("add_allowed")->setEnabled(can_manage_allowed && allowed_list_count < PARCEL_MAX_ACCESS_LIST); BOOL has_selected = (mListAccess && mListAccess->getSelectionInterface()->getFirstSelectedIndex() >= 0); getChildView("remove_allowed")->setEnabled(can_manage_allowed && has_selected); - getChildView("BannedList")->setEnabled(true/*can_manage_banned*/); + mListBanned->setEnabled(true/*can_manage_banned*/); S32 banned_list_count = parcel->mBanList.size(); getChildView("add_banned")->setEnabled(can_manage_banned && banned_list_count < PARCEL_MAX_ACCESS_LIST); has_selected = (mListBanned && mListBanned->getSelectionInterface()->getFirstSelectedIndex() >= 0); @@ -2713,44 +2668,60 @@ void LLPanelLandAccess::draw() LLPanel::draw(); } -// static -void LLPanelLandAccess::onCommitPublicAccess(LLUICtrl *ctrl, void *userdata) +void LLPanelLandAccess::onCommitPublicAccess(LLUICtrl *ctrl) { - LLPanelLandAccess *self = (LLPanelLandAccess *)userdata; - LLParcel* parcel = self->mParcel->getParcel(); + LLParcel* parcel = mParcel->getParcel(); if (!parcel) { return; } // If we disabled public access, enable group access by default (if applicable) - BOOL public_access = self->getChild("public_access")->getValue().asBoolean(); - if (public_access == FALSE) + if (!getChild("public_access")->getValue().asBoolean()) { std::string group_name; if (gCacheName->getGroupName(parcel->getGroupID(), group_name)) { - self->getChild("GroupCheck")->setValue(public_access ? FALSE : TRUE); + getChild("GroupCheck")->setValue(true); } } - onCommitAny(ctrl, userdata); + onCommitAny(); } -// static -void LLPanelLandAccess::onCommitAny(LLUICtrl *ctrl, void *userdata) +void LLPanelLandAccess::onCommitGroupCheck(LLUICtrl *ctrl) { - LLPanelLandAccess *self = (LLPanelLandAccess *)userdata; + LLParcel* parcel = mParcel->getParcel(); + if (!parcel) + { + return; + } - LLParcel* parcel = self->mParcel->getParcel(); + BOOL use_pass_list = !getChild("public_access")->getValue().asBoolean(); + BOOL use_access_group = getChild("GroupCheck")->getValue().asBoolean(); + LLCtrlSelectionInterface* passcombo = childGetSelectionInterface("pass_combo"); + if (passcombo && use_access_group && use_pass_list) + { + if (passcombo->getSelectedValue().asString() == "group") + { + passcombo->selectByValue("anyone"); + } + } + + onCommitAny(); +} + +void LLPanelLandAccess::onCommitAny() +{ + LLParcel* parcel = mParcel->getParcel(); if (!parcel) { return; } // Extract data from UI - BOOL public_access = self->getChild("public_access")->getValue().asBoolean(); - BOOL use_access_group = self->getChild("GroupCheck")->getValue().asBoolean(); + BOOL public_access = getChild("public_access")->getValue().asBoolean(); + BOOL use_access_group = getChild("GroupCheck")->getValue().asBoolean(); if (use_access_group) { std::string group_name; @@ -2768,28 +2739,28 @@ void LLPanelLandAccess::onCommitAny(LLUICtrl *ctrl, void *userdata) { use_access_list = FALSE; use_access_group = FALSE; - limit_payment = self->getChild("limit_payment")->getValue().asBoolean(); - limit_age_verified = self->getChild("limit_age_verified")->getValue().asBoolean(); + limit_payment = getChild("limit_payment")->getValue().asBoolean(); + limit_age_verified = getChild("limit_age_verified")->getValue().asBoolean(); } else { use_access_list = TRUE; - use_pass_list = self->getChild("PassCheck")->getValue().asBoolean(); - if (use_access_group && use_pass_list) + use_pass_list = getChild("PassCheck")->getValue().asBoolean(); + LLCtrlSelectionInterface* passcombo = childGetSelectionInterface("pass_combo"); + if (passcombo) { - LLCtrlSelectionInterface* passcombo = self->childGetSelectionInterface("pass_combo"); - if (passcombo) + if (use_access_group && use_pass_list) { if (passcombo->getSelectedValue().asString() == "group") { - use_access_list = FALSE; + use_access_group = FALSE; } } } } - S32 pass_price = llfloor((F32)self->getChild("PriceSpin")->getValue().asReal()); - F32 pass_hours = (F32)self->getChild("HoursSpin")->getValue().asReal(); + S32 pass_price = llfloor((F32)getChild("PriceSpin")->getValue().asReal()); + F32 pass_hours = (F32)getChild("HoursSpin")->getValue().asReal(); // Push data into current parcel parcel->setParcelFlag(PF_USE_ACCESS_GROUP, use_access_group); @@ -2806,44 +2777,56 @@ void LLPanelLandAccess::onCommitAny(LLUICtrl *ctrl, void *userdata) LLViewerParcelMgr::getInstance()->sendParcelPropertiesUpdate( parcel ); // Might have changed properties, so let's redraw! - self->refresh(); + refresh(); } void LLPanelLandAccess::onClickAddAccess() { + LLFloater* root_floater = gFloaterView->getParentFloater(this); LLFloaterAvatarPicker* picker = LLFloaterAvatarPicker::show( - boost::bind(&LLPanelLandAccess::callbackAvatarCBAccess, this, _1)); + boost::bind(&LLPanelLandAccess::callbackAvatarCBAccess, this, _1), true, true); if (picker) { - gFloaterView->getParentFloater(this)->addDependentFloater(picker); + root_floater->addDependentFloater(picker); } } void LLPanelLandAccess::callbackAvatarCBAccess(const uuid_vec_t& ids) { - if (!ids.empty()) + LLParcel* parcel = mParcel->getParcel(); + if (!parcel) return; + + U32 lists_to_update = 0; + + for (const auto& id : ids) { - LLUUID id = ids[0]; - LLParcel* parcel = mParcel->getParcel(); - if (parcel) + if (parcel->addToAccessList(id, 0)) { - parcel->addToAccessList(id, 0); - LLViewerParcelMgr::getInstance()->sendParcelAccessListUpdate(AL_ACCESS); - refresh(); + lists_to_update |= AL_ACCESS; + // agent was successfully added to access list + // but we also need to check ban list to ensure that agent will not be in two lists simultaneously + if(parcel->removeFromBanList(id)) + { + lists_to_update |= AL_BAN; + } } } + if (lists_to_update) + { + LLViewerParcelMgr::getInstance()->sendParcelAccessListUpdate(lists_to_update); + refresh(); + } } // static -void LLPanelLandAccess::onClickRemoveAccess(void* data) +void LLPanelLandAccess::onClickRemoveAccess() { - LLPanelLandAccess* panelp = (LLPanelLandAccess*)data; - if (panelp && panelp->mListAccess) + if (mListAccess) { - LLParcel* parcel = panelp->mParcel->getParcel(); + LLParcel* parcel = mParcel->getParcel(); if (parcel) { - std::vector names = panelp->mListAccess->getAllSelected(); + std::vector names = mListAccess->getAllSelected(); for (std::vector::iterator iter = names.begin(); iter != names.end(); ) { @@ -2852,46 +2835,70 @@ void LLPanelLandAccess::onClickRemoveAccess(void* data) parcel->removeFromAccessList(agent_id); } LLViewerParcelMgr::getInstance()->sendParcelAccessListUpdate(AL_ACCESS); - panelp->refresh(); + refresh(); } } } +// static void LLPanelLandAccess::onClickAddBanned() { + LLFloater* root_floater = gFloaterView->getParentFloater(this); LLFloaterAvatarPicker* picker = LLFloaterAvatarPicker::show( - boost::bind(&LLPanelLandAccess::callbackAvatarCBBanned, this, _1)); + boost::bind(&LLPanelLandAccess::callbackAvatarCBBanned, this, _1), true, true); if (picker) { - gFloaterView->getParentFloater(this)->addDependentFloater(picker); + root_floater->addDependentFloater(picker); } } +// static void LLPanelLandAccess::callbackAvatarCBBanned(const uuid_vec_t& ids) { - if (!ids.empty()) + LLFloater* root_floater = gFloaterView->getParentFloater(this); + LLFloaterBanDuration* duration_floater = LLFloaterBanDuration::show( + boost::bind(&LLPanelLandAccess::callbackAvatarCBBanned2, this, _1, _2), ids); + if (duration_floater) { - LLUUID id = ids[0]; - LLParcel* parcel = mParcel->getParcel(); - if (parcel) + root_floater->addDependentFloater(duration_floater); + } +} + +void LLPanelLandAccess::callbackAvatarCBBanned2(const uuid_vec_t& ids, S32 duration) +{ + LLParcel* parcel = mParcel->getParcel(); + if (!parcel) return; + + U32 lists_to_update = 0; + + for (const auto& id : ids) + { + if (parcel->addToBanList(id, duration)) { - parcel->addToBanList(id, 0); - LLViewerParcelMgr::getInstance()->sendParcelAccessListUpdate(AL_BAN); - refresh(); + lists_to_update |= AL_BAN; + // agent was successfully added to ban list + // but we also need to check access list to ensure that agent will not be in two lists simultaneously + if(parcel->removeFromAccessList(id)) + { + lists_to_update |= AL_ACCESS; + } } } + if (lists_to_update) + { + LLViewerParcelMgr::getInstance()->sendParcelAccessListUpdate(lists_to_update); + refresh(); + } } -// static -void LLPanelLandAccess::onClickRemoveBanned(void* data) +void LLPanelLandAccess::onClickRemoveBanned() { - LLPanelLandAccess* panelp = (LLPanelLandAccess*)data; - if (panelp && panelp->mListBanned) + if (mListBanned) { - LLParcel* parcel = panelp->mParcel->getParcel(); + LLParcel* parcel = mParcel->getParcel(); if (parcel) { - std::vector names = panelp->mListBanned->getAllSelected(); + std::vector names = mListBanned->getAllSelected(); for (std::vector::iterator iter = names.begin(); iter != names.end(); ) { @@ -2900,7 +2907,7 @@ void LLPanelLandAccess::onClickRemoveBanned(void* data) parcel->removeFromBanList(agent_id); } LLViewerParcelMgr::getInstance()->sendParcelAccessListUpdate(AL_BAN); - panelp->refresh(); + refresh(); } } } @@ -2910,7 +2917,8 @@ void LLPanelLandAccess::onClickRemoveBanned(void* data) //--------------------------------------------------------------------------- LLPanelLandCovenant::LLPanelLandCovenant(LLParcelSelectionHandle& parcel) : LLPanel(std::string("land_covenant_panel")), - mParcel(parcel) + mParcel(parcel), + mNextUpdateTime(0) { } @@ -2928,7 +2936,7 @@ BOOL LLPanelLandCovenant::postBuild() void LLPanelLandCovenant::refresh() { LLViewerRegion* region = LLViewerParcelMgr::getInstance()->getSelectionRegion(); - if(!region) return; + if(!region || gDisconnected) return; LLTextBox* region_name = getChild("region_name_text"); if (region_name) @@ -2971,13 +2979,22 @@ void LLPanelLandCovenant::refresh() } } - // send EstateCovenantInfo message - LLMessageSystem *msg = gMessageSystem; - msg->newMessage("EstateCovenantRequest"); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID,gAgent.getSessionID()); - msg->sendReliable(region->getHost()); + if (mLastRegionID != region->getRegionID() + || mNextUpdateTime < LLTimer::getElapsedSeconds()) + { + // Request Covenant Info + // Note: LLPanelLandCovenant doesn't change Covenant's content and any + // changes made by Estate floater should be requested by Estate floater + LLMessageSystem *msg = gMessageSystem; + msg->newMessage("EstateCovenantRequest"); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID,gAgent.getSessionID()); + msg->sendReliable(region->getHost()); + + mLastRegionID = region->getRegionID(); + mNextUpdateTime = LLTimer::getElapsedSeconds() + COVENANT_REFRESH_TIME_SEC; + } } // static @@ -2988,7 +3005,7 @@ void LLPanelLandCovenant::updateCovenantText(const std::string &string) { LLViewerTextEditor* editor = self->getChild("covenant_editor"); editor->setHandleEditKeysDirectly(TRUE); - editor->setText(string); + editor->setText(string, false); } } @@ -3015,16 +3032,119 @@ void LLPanelLandCovenant::updateLastModified(const std::string& text) } // static -void LLPanelLandCovenant::updateEstateOwnerName(const std::string& name) +void LLPanelLandCovenant::updateEstateOwnerID(const LLUUID& id) { LLPanelLandCovenant* self = LLFloaterLand::getCurrentPanelLandCovenant(); if (self) { - LLTextBox* editor = self->getChild("estate_owner_text"); - if (editor) editor->setText(name); + self->getChildView("estate_owner_text")->setValue(id); + } +} + +LLPanelLandExperiences::LLPanelLandExperiences( LLSafeHandle& parcelp ) + : mParcel(parcelp), + mAllowed(nullptr), + mBlocked(nullptr) +{ + mFactoryMap["panel_allowed"] = LLCallbackMap(create_xp_list_editor, reinterpret_cast(&mAllowed)); + mFactoryMap["panel_blocked"] = LLCallbackMap(create_xp_list_editor, reinterpret_cast(&mBlocked)); + LLUICtrlFactory::getInstance()->buildPanel(this, "panel_region_experiences.xml", &mFactoryMap); +} + + +BOOL LLPanelLandExperiences::postBuild() +{ + setupList(mAllowed, "panel_allowed", EXPERIENCE_KEY_TYPE_ALLOWED, AL_ALLOW_EXPERIENCE); + setupList(mBlocked, "panel_blocked", EXPERIENCE_KEY_TYPE_BLOCKED, AL_BLOCK_EXPERIENCE); + + // only non-grid-wide experiences + mAllowed->addFilter(boost::bind(LLPanelExperiencePicker::FilterWithProperty, _1, LLExperienceCache::PROPERTY_GRID)); + + // no privileged ones + mBlocked->addFilter(boost::bind(LLPanelExperiencePicker::FilterWithoutProperties, _1, LLExperienceCache::PROPERTY_PRIVILEGED|LLExperienceCache::PROPERTY_GRID)); + + getChild("trusted_layout_panel")->setVisible(FALSE); + getChild("experiences_help_text")->setVisible(FALSE); + getChild("allowed_text_help")->setText(getString("allowed_parcel_text")); + getChild("blocked_text_help")->setText(getString("blocked_parcel_text")); + + return LLPanel::postBuild(); +} + +void LLPanelLandExperiences::setupList(LLPanelExperienceListEditor* child, const char* control_name, U32 xp_type, U32 access_type ) +{ + //LLPanelExperienceListEditor* child = findChild(control_name); + if (child) + { + child->getChild("text_name")->setText(child->getString(control_name)); + child->setMaxExperienceIDs(PARCEL_MAX_EXPERIENCE_LIST); + child->setAddedCallback(boost::bind(&LLPanelLandExperiences::experienceAdded, this, _1, xp_type, access_type)); + child->setRemovedCallback(boost::bind(&LLPanelLandExperiences::experienceRemoved, this, _1, access_type)); + } + + //return child; +} + +void LLPanelLandExperiences::experienceAdded( const LLUUID& id, U32 xp_type, U32 access_type ) +{ + LLParcel* parcel = mParcel->getParcel(); + if (parcel) + { + parcel->setExperienceKeyType(id, xp_type); + LLViewerParcelMgr::getInstance()->sendParcelAccessListUpdate(access_type); + refresh(); } } +void LLPanelLandExperiences::experienceRemoved( const LLUUID& id, U32 access_type ) +{ + LLParcel* parcel = mParcel->getParcel(); + if (parcel) + { + parcel->setExperienceKeyType(id, EXPERIENCE_KEY_TYPE_NONE); + LLViewerParcelMgr::getInstance()->sendParcelAccessListUpdate(access_type); + refresh(); + } +} + +void LLPanelLandExperiences::refreshPanel(LLPanelExperienceListEditor* panel, U32 xp_type) +{ + LLParcel *parcel = mParcel->getParcel(); + + // Display options + if (panel == NULL) + { + return; + } + if (!parcel || gDisconnected) + { + // disable the panel + panel->setEnabled(FALSE); + panel->setExperienceIds(LLSD::emptyArray()); + } + else + { + // enable the panel + panel->setEnabled(TRUE); + LLAccessEntry::map entries = parcel->getExperienceKeysByType(xp_type); + LLAccessEntry::map::iterator it = entries.begin(); + LLSD ids = LLSD::emptyArray(); + for (/**/; it != entries.end(); ++it) + { + ids.append(it->second.mID); + } + panel->setExperienceIds(ids); + panel->setReadonly(!LLViewerParcelMgr::isParcelModifiableByAgent(parcel, GP_LAND_OPTIONS)); + panel->refreshExperienceCounter(); + } +} + +void LLPanelLandExperiences::refresh() +{ + refreshPanel(mAllowed, EXPERIENCE_KEY_TYPE_ALLOWED); + refreshPanel(mBlocked, EXPERIENCE_KEY_TYPE_BLOCKED); +} + // [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0a) void LLFloaterLand::open() { @@ -3041,15 +3161,15 @@ void LLFloaterLand::open() // Ideally we could just use LLViewerParcelMgr::isParcelOwnedByAgent(), but that has that sneaky exemption // for fake god like (aka View Admin Options) const LLUUID& idOwner = pParcel->getOwnerID(); - if ( (idOwner != gAgent.getID()) ) + if (idOwner != gAgentID) { // *sighs* LLAgent::hasPowerInGroup() has it too so copy/paste from there - S32 count = gAgent.mGroups.count(); bool fShow = false; + S32 count = gAgent.mGroups.size(); bool fShow = false; for (S32 i = 0; i < count; ++i) { - if (gAgent.mGroups.get(i).mID == idOwner) + if (gAgent.mGroups[i].mID == idOwner) { - fShow |= ((gAgent.mGroups.get(i).mPowers & GP_LAND_RETURN) > 0); + fShow |= ((gAgent.mGroups[i].mPowers & GP_LAND_RETURN) > 0); break; } } @@ -3062,3 +3182,16 @@ void LLFloaterLand::open() LLFloater::open(); } // [/RLVa:KB] + + +// virtual +void LLFloaterLand::onClose(bool app_quitting) +{ + // Might have been showing owned objects + LLSelectMgr::getInstance()->unhighlightAll(); + + // Save which panel we had open + sLastTab = mTabLand->getCurrentPanelIndex(); + + destroy(); +} diff --git a/indra/newview/llfloaterland.h b/indra/newview/llfloaterland.h index 7c73165137..4024d60a27 100644 --- a/indra/newview/llfloaterland.h +++ b/indra/newview/llfloaterland.h @@ -3,46 +3,35 @@ * @author James Cook * @brief "About Land" floater, allowing display and editing of land parcel properties. * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #ifndef LL_LLFLOATERLAND_H #define LL_LLFLOATERLAND_H -#include -#include - #include "llfloater.h" #include "llpointer.h" // LLPointer<> -//#include "llviewertexturelist.h" #include "llsafehandle.h" -typedef std::set uuid_list_t; const F32 CACHE_REFRESH_TIME = 2.5f; class LLButton; @@ -50,6 +39,7 @@ class LLCheckBoxCtrl; class LLRadioGroup; class LLComboBox; class LLLineEditor; +class LLMessageSystem; class LLNameListCtrl; class LLRadioGroup; class LLParcelSelectionObserver; @@ -59,7 +49,6 @@ class LLTextBox; class LLTextEditor; class LLTextureCtrl; class LLUIImage; -class LLViewerTextEditor; class LLParcelSelection; class LLPanelLandGeneral; @@ -72,9 +61,11 @@ class LLPanelLandBan; class LLPanelLandRenters; class LLPanelLandCovenant; class LLParcel; +class LLPanelLandExperiences; -class LLFloaterLand -: public LLFloater, public LLFloaterSingleton +class LLFloaterLand final +: public LLFloater +, public LLFloaterSingleton { friend class LLUISingleton >; public: @@ -86,24 +77,23 @@ class LLFloaterLand LLParcel* getCurrentSelectedParcel(); // Destroys itself on close. - virtual void onClose(bool app_quitting); - virtual void onOpen(); - virtual BOOL postBuild(); + void onClose(bool app_quitting) override; + void onOpen() override; + BOOL postBuild() override; // [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0a) - virtual void open(); + void open() override; // [/RLVa:KB] - - -protected: - +private: // Does its own instance management, so clients not allowed // to allocate or destroy. LLFloaterLand(const LLSD& seed); virtual ~LLFloaterLand(); - /*virtual*/ void refresh(); +protected: + + /*virtual*/ void refresh() override; static void* createPanelLandGeneral(void* data); static void* createPanelLandCovenant(void* data); @@ -112,12 +102,15 @@ class LLFloaterLand static void* createPanelLandAudio(void* data); static void* createPanelLandMedia(void* data); static void* createPanelLandAccess(void* data); + static void* createPanelLandExperiences(void* data); static void* createPanelLandBan(void* data); + protected: static LLParcelSelectionObserver* sObserver; static S32 sLastTab; + friend class LLPanelLandObjects; LLTabContainer* mTabLand; LLPanelLandGeneral* mPanelGeneral; LLPanelLandObjects* mPanelObjects; @@ -126,6 +119,7 @@ class LLFloaterLand LLPanelLandMedia* mPanelMedia; LLPanelLandAccess* mPanelAccess; LLPanelLandCovenant* mPanelCovenant; + LLPanelLandExperiences* mPanelExperiences; LLSafeHandle mParcel; @@ -138,28 +132,25 @@ class LLFloaterLand }; -class LLPanelLandGeneral +class LLPanelLandGeneral final : public LLPanel { public: LLPanelLandGeneral(LLSafeHandle& parcelp); virtual ~LLPanelLandGeneral(); - /*virtual*/ void refresh(); + /*virtual*/ void refresh() override; void refreshNames(); - virtual void draw(); void setGroup(const LLUUID& group_id); - void onClickProfile(); void onClickSetGroup(); - static void onClickInfoGroup(void*); - static void onClickDeed(void*); static void onClickBuyLand(void* data); - static void onClickScriptLimits(void* data); - static void onClickRelease(void*); - static void onClickReclaim(void*); static void onClickBuyPass(void* deselect_when_done); + void onClickDeed(); + void onClickScriptLimits(); + void onClickRelease(); + void onClickReclaim(); static BOOL enableBuyPass(void*); - static void onCommitAny(LLUICtrl* ctrl, void *userdata); + void onCommitAny(); static void finalizeCommit(void * userdata); static void onForSaleChange(LLUICtrl *ctrl, void * userdata); static void finalizeSetSellChange(void * userdata); @@ -167,27 +158,23 @@ class LLPanelLandGeneral static bool cbBuyPass(const LLSD& notification, const LLSD& response); - static void onClickSellLand(void* data); - static void onClickStopSellLand(void* data); - static void onClickSet(void* data); - static void onClickClear(void* data); - static void onClickShow(void* data); - static void callbackAvatarPick(const std::vector& names, const std::vector& ids, void* data); + void onClickSellLand(); + void onClickStopSellLand(); + void onClickSet(); + void onClickClear(); + void onClickShow(); + static void callbackAvatarPick(const std::vector& names, const uuid_vec_t& ids, void* data); static void finalizeAvatarPick(void* data); static void callbackHighlightTransferable(S32 option, void* userdata); - static void onClickStartAuction(void*); + void onClickStartAuction(); // sale change confirmed when "is for sale", "sale price", "sell to whom" fields are changed static void confirmSaleChange(S32 landSize, S32 salePrice, std::string authorizedName, void(*callback)(void*), void* userdata); static void callbackConfirmSaleChange(S32 option, void* userdata); - virtual BOOL postBuild(); + BOOL postBuild() override; protected: - BOOL mUncheckedSell; // True only when verifying land information when land is for sale on sale info change - - LLTextBox* mLabelName; LLLineEditor* mEditName; - LLTextBox* mLabelDesc; LLTextEditor* mEditDesc; LLTextBox* mTextSalePending; @@ -195,16 +182,12 @@ class LLPanelLandGeneral LLButton* mBtnDeedToGroup; LLButton* mBtnSetGroup; - LLTextBox* mTextOwnerLabel; LLTextBox* mTextOwner; - LLButton* mBtnProfile; - + LLTextBox* mContentRating; LLTextBox* mLandType; LLTextBox* mTextGroup; - LLTextBox* mTextGroupLabel; - LLTextBox* mTextClaimDateLabel; LLTextBox* mTextClaimDate; LLTextBox* mTextPriceLabel; @@ -247,39 +230,36 @@ class LLPanelLandGeneral static LLHandle sBuyPassDialogHandle; }; -class LLPanelLandObjects +class LLPanelLandObjects final : public LLPanel { public: LLPanelLandObjects(LLSafeHandle& parcelp); virtual ~LLPanelLandObjects(); - /*virtual*/ void refresh(); - virtual void draw(); + /*virtual*/ void refresh() override; bool callbackReturnOwnerObjects(const LLSD& notification, const LLSD& response); bool callbackReturnGroupObjects(const LLSD& notification, const LLSD& response); bool callbackReturnOtherObjects(const LLSD& notification, const LLSD& response); bool callbackReturnOwnerList(const LLSD& notification, const LLSD& response); - static void clickShowCore(LLPanelLandObjects* panelp, S32 return_type, uuid_list_t* list = 0); - static void onClickShowOwnerObjects(void*); - static void onClickShowGroupObjects(void*); - static void onClickShowOtherObjects(void*); + static void clickShowCore(LLPanelLandObjects* panelp, S32 return_type, uuid_list_t* list = nullptr); + void onClickShowOwnerObjects(); + void onClickShowGroupObjects(); + void onClickShowOtherObjects(); - static void onClickReturnOwnerObjects(void*); - static void onClickReturnGroupObjects(void*); - static void onClickReturnOtherObjects(void*); - static void onClickReturnOwnerList(void*); - static void onClickRefresh(void*); - - static void onDoubleClickOwner(void*); + void onClickReturnOwnerObjects(); + void onClickReturnGroupObjects(); + void onClickReturnOtherObjects(); + void onClickReturnOwnerList(); + void onClickRefresh(); void onCommitList(); static void onLostFocus(LLFocusableElement* caller, void* user_data); - static void onCommitClean(LLUICtrl* caller, void* user_data); + void onCommitClean(); static void processParcelObjectOwnersReply(LLMessageSystem *msg, void **); - virtual BOOL postBuild(); + BOOL postBuild() override; protected: @@ -319,23 +299,23 @@ class LLPanelLandObjects }; -class LLPanelLandOptions +class LLPanelLandOptions final : public LLPanel { public: LLPanelLandOptions(LLSafeHandle& parcelp); virtual ~LLPanelLandOptions(); - /*virtual*/ BOOL postBuild(); - /*virtual*/ void draw(); - /*virtual*/ void refresh(); + /*virtual*/ BOOL postBuild() override; + /*virtual*/ void draw() override; + /*virtual*/ void refresh() override; private: // Refresh the "show in search" checkbox and category selector. void refreshSearch(); - static void onCommitAny(LLUICtrl* ctrl, void *userdata); - static void onClickSet(void* userdata); - static void onClickClear(void* userdata); + void onCommitAny(); + void onClickSet(); + void onClickClear(); static void onClickPublishHelp(void*); private: @@ -370,27 +350,29 @@ class LLPanelLandOptions }; -class LLPanelLandAccess +class LLPanelLandAccess final : public LLPanel { public: LLPanelLandAccess(LLSafeHandle& parcelp); virtual ~LLPanelLandAccess(); - void refresh(); + void refresh() override; void refresh_ui(); void refreshNames(); - virtual void draw(); + void draw() override; - static void onCommitPublicAccess(LLUICtrl* ctrl, void *userdata); - static void onCommitAny(LLUICtrl* ctrl, void *userdata); - static void onClickRemoveAccess(void*); - static void onClickRemoveBanned(void*); + void onCommitPublicAccess(LLUICtrl* ctrl); + void onCommitAny(); + void onCommitGroupCheck(LLUICtrl* ctrl); + void onClickRemoveAccess(); + void onClickRemoveBanned(); - virtual BOOL postBuild(); + BOOL postBuild() override; void onClickAddAccess(); void onClickAddBanned(); void callbackAvatarCBBanned(const uuid_vec_t& ids); + void callbackAvatarCBBanned2(const uuid_vec_t& ids, S32 duration); void callbackAvatarCBAccess(const uuid_vec_t& ids); protected: @@ -400,22 +382,25 @@ class LLPanelLandAccess LLSafeHandle& mParcel; }; - -class LLPanelLandCovenant +class LLPanelLandCovenant final : public LLPanel { public: LLPanelLandCovenant(LLSafeHandle& parcelp); virtual ~LLPanelLandCovenant(); - virtual BOOL postBuild(); - void refresh(); + BOOL postBuild() override; + void refresh() override; static void updateCovenantText(const std::string& string); static void updateEstateName(const std::string& name); static void updateLastModified(const std::string& text); - static void updateEstateOwnerName(const std::string& name); + static void updateEstateOwnerID(const LLUUID& id); protected: LLSafeHandle& mParcel; + +private: + LLUUID mLastRegionID; + F64 mNextUpdateTime; //seconds since client start }; #endif diff --git a/indra/newview/llfloaterlandholdings.cpp b/indra/newview/llfloaterlandholdings.cpp index 4949678c13..11f8d7a59f 100644 --- a/indra/newview/llfloaterlandholdings.cpp +++ b/indra/newview/llfloaterlandholdings.cpp @@ -100,27 +100,26 @@ BOOL LLFloaterLandHoldings::postBuild() childSetAction("Teleport", onClickTeleport, this); childSetAction("Show on Map", onClickMap, this); - LLScrollListCtrl *grant_list = getChild("grant list"); - // Grant list + LLScrollListCtrl *grant_list = getChild("grant list"); grant_list->setDoubleClickCallback(boost::bind(LLGroupActions::show, boost::bind(&LLScrollListCtrl::getCurrentID, grant_list))); LLCtrlListInterface *list = grant_list->getListInterface(); if (!list) return TRUE; - S32 count = gAgent.mGroups.count(); + S32 count = gAgent.mGroups.size(); for(S32 i = 0; i < count; ++i) { - LLUUID id(gAgent.mGroups.get(i).mID); + LLUUID id(gAgent.mGroups.at(i).mID); LLSD element; element["id"] = id; element["columns"][0]["column"] = "group"; - element["columns"][0]["value"] = gAgent.mGroups.get(i).mName; + element["columns"][0]["value"] = gAgent.mGroups.at(i).mName; element["columns"][0]["font"] = "SANSSERIF"; LLUIString areastr = getString("area_string"); - areastr.setArg("[AREA]", llformat("%d", gAgent.mGroups.get(i).mContribution)); + areastr.setArg("[AREA]", llformat("%d", gAgent.mGroups.at(i).mContribution)); element["columns"][1]["column"] = "area"; element["columns"][1]["value"] = areastr; element["columns"][1]["font"] = "SANSSERIF"; @@ -128,6 +127,8 @@ BOOL LLFloaterLandHoldings::postBuild() list->addElement(element, ADD_SORTED); } + center(); + return TRUE; } @@ -157,8 +158,8 @@ void LLFloaterLandHoldings::refresh() enable_btns = TRUE; } - childSetEnabled("Teleport", enable_btns); - childSetEnabled("Show on Map", enable_btns); + getChildView("Teleport")->setEnabled(enable_btns); + getChildView("Show on Map")->setEnabled(enable_btns); refreshAggregates(); } @@ -214,7 +215,7 @@ void LLFloaterLandHoldings::processPlacesReply(LLMessageSystem* msg, void**) if ( msg->getSizeFast(_PREHASH_QueryData, i, _PREHASH_ProductSKU) > 0 ) { msg->getStringFast( _PREHASH_QueryData, _PREHASH_ProductSKU, land_sku, i); - llinfos << "Land sku: " << land_sku << llendl; + LL_INFOS() << "Land sku: " << land_sku << LL_ENDL; land_type = LLProductInfoRequestManager::instance().getDescriptionForSku(land_sku); } else @@ -226,8 +227,8 @@ void LLFloaterLandHoldings::processPlacesReply(LLMessageSystem* msg, void**) self->mActualArea += actual_area; self->mBillableArea += billable_area; - S32 region_x = llround(global_x) % REGION_WIDTH_UNITS; - S32 region_y = llround(global_y) % REGION_WIDTH_UNITS; + S32 region_x = ll_round(global_x) % REGION_WIDTH_UNITS; + S32 region_y = ll_round(global_y) % REGION_WIDTH_UNITS; std::string location; location = llformat("%s (%d, %d)", sim_name.c_str(), region_x, region_y); @@ -291,15 +292,16 @@ void LLFloaterLandHoldings::buttonCore(S32 which) F64 global_z = gAgent.getPositionGlobal().mdV[VZ]; LLVector3d pos_global(global_x, global_y, global_z); + LLFloaterWorldMap* floater_world_map = gFloaterWorldMap; switch(which) { case 0: gAgent.teleportViaLocation(pos_global); - gFloaterWorldMap->trackLocation(pos_global); + if(floater_world_map) floater_world_map->trackLocation(pos_global); break; case 1: - gFloaterWorldMap->trackLocation(pos_global); + if(floater_world_map) floater_world_map->trackLocation(pos_global); LLFloaterWorldMap::show(true); break; default: @@ -329,7 +331,7 @@ void LLFloaterLandHoldings::refreshAggregates() S32 current_area = gStatusBar->getSquareMetersCommitted(); S32 available_area = gStatusBar->getSquareMetersLeft(); - childSetTextArg("allowed_text", "[AREA]", llformat("%d",allowed_area)); - childSetTextArg("current_text", "[AREA]", llformat("%d",current_area)); - childSetTextArg("available_text", "[AREA]", llformat("%d",available_area)); + getChild("allowed_text")->setTextArg("[AREA]", llformat("%d",allowed_area)); + getChild("current_text")->setTextArg("[AREA]", llformat("%d",current_area)); + getChild("available_text")->setTextArg("[AREA]", llformat("%d",available_area)); } diff --git a/indra/newview/llfloaterlandmark.cpp b/indra/newview/llfloaterlandmark.cpp index 885e9ddedd..d94546a08c 100644 --- a/indra/newview/llfloaterlandmark.cpp +++ b/indra/newview/llfloaterlandmark.cpp @@ -72,7 +72,6 @@ LLFloaterLandmark::LLFloaterLandmark(const LLSD& data) mFilterEdit(NULL), mContextConeOpacity(0.f), mInventoryPanel(NULL), - mSavedFolderState(NULL), mNoCopyLandmarkSelected( FALSE ) { LLUICtrlFactory::getInstance()->buildFloater(this,"floater_landmark_ctrl.xml"); @@ -105,7 +104,7 @@ BOOL LLFloaterLandmark::postBuild() mInventoryPanel->setAllowMultiSelect(FALSE); // store this filter as the default one - mInventoryPanel->getRootFolder()->getFilter()->markDefault(); + mInventoryPanel->getRootFolder()->getFilter().markDefault(); // Commented out to stop opening all folders with textures mInventoryPanel->openDefaultFolderForType(LLAssetType::AT_LANDMARK); @@ -115,7 +114,6 @@ BOOL LLFloaterLandmark::postBuild() mInventoryPanel->setSelection(findItemID(mImageAssetID, FALSE), TAKE_FOCUS_NO); } - mSavedFolderState = new LLSaveFolderState(); mNoCopyLandmarkSelected = FALSE; getChild("Close")->setClickedCallback(boost::bind(&LLFloaterLandmark::onBtnClose,this)); @@ -127,15 +125,11 @@ BOOL LLFloaterLandmark::postBuild() setCanMinimize(FALSE); - mSavedFolderState->setApply(FALSE); - return true; } LLFloaterLandmark::~LLFloaterLandmark() { - delete mSavedFolderState; - mSavedFolderState = NULL; } void LLFloaterLandmark::setActive( BOOL active ) @@ -185,7 +179,7 @@ BOOL LLFloaterLandmark::handleDragAndDrop( } handled = TRUE; - lldebugst(LLERR_USER_INPUT) << "dragAndDrop handled by LLFloaterLandmark " << getName() << llendl; + LL_DEBUGS("UserInput") << "dragAndDrop handled by LLFloaterLandmark " << getName() << LL_ENDL; return handled; } @@ -244,10 +238,10 @@ const LLUUID& LLFloaterLandmark::findItemID(const LLUUID& asset_id, BOOL copyabl LLInventoryModel::INCLUDE_TRASH, asset_id_matches); - if (items.count()) + if (items.size()) { // search for copyable version first - for (S32 i = 0; i < items.count(); i++) + for (U32 i = 0; i < items.size(); i++) { LLInventoryItem* itemp = items[i]; LLPermissions item_permissions = itemp->getPermissions(); @@ -291,13 +285,13 @@ void LLFloaterLandmark::onBtnNew() LLViewerRegion* agent_region = gAgent.getRegion(); if(!agent_region) { - llwarns << "No agent region" << llendl; + LL_WARNS() << "No agent region" << LL_ENDL; return; } LLParcel* agent_parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); if (!agent_parcel) { - llwarns << "No agent parcel" << llendl; + LL_WARNS() << "No agent parcel" << LL_ENDL; return; } if (!agent_parcel->getAllowLandmark() @@ -352,15 +346,6 @@ void LLFloaterLandmark::onBtnDelete() gInventory.notifyObservers(); } } - - // Delete the item entirely - /* - item->removeFromServer(); - gInventory.deleteObject(item->getUUID()); - gInventory.notifyObservers(); - */ - - } void LLFloaterLandmark::onBtnRename() @@ -403,35 +388,13 @@ void LLFloaterLandmark::onShowFolders(LLUICtrl* ctrl) void LLFloaterLandmark::onFilterEdit(const LLSD& value ) { - std::string upper_case_search_string = value.asString(); - LLStringUtil::toUpper(upper_case_search_string); - - if (upper_case_search_string.empty()) + if (!mInventoryPanel) { - if (mInventoryPanel->getFilterSubString().empty()) - { - // current filter and new filter empty, do nothing - return; - } - - mSavedFolderState->setApply(TRUE); - mInventoryPanel->getRootFolder()->applyFunctorRecursively(*mSavedFolderState); - // add folder with current item to list of previously opened folders - LLOpenFoldersWithSelection opener; - mInventoryPanel->getRootFolder()->applyFunctorRecursively(opener); - mInventoryPanel->getRootFolder()->scrollToShowSelection(); - - } - else if (mInventoryPanel->getFilterSubString().empty()) - { - // first letter in search term, save existing folder open state - if (!mInventoryPanel->getRootFolder()->isFilterModified()) - { - mSavedFolderState->setApply(FALSE); - mInventoryPanel->getRootFolder()->applyFunctorRecursively(*mSavedFolderState); - } + return; } - mInventoryPanel->setFilterSubString(upper_case_search_string); + // set new filter string + // Internally handles saving/restoring folder states. + mInventoryPanel->setFilterSubString(value.asString()); } diff --git a/indra/newview/llfloaterlandmark.h b/indra/newview/llfloaterlandmark.h index 668590c332..98061e4beb 100644 --- a/indra/newview/llfloaterlandmark.h +++ b/indra/newview/llfloaterlandmark.h @@ -113,7 +113,6 @@ class LLFloaterLandmark: public LLFloater, public LLFloaterSingleton t_panel_status("llpanelmarketplacelistings"); + +LLPanelMarketplaceListings::LLPanelMarketplaceListings() +: mRootFolder(NULL) +, mAuditBtn(nullptr) +, mFilterEditor(nullptr) +, mSortOrder(LLInventoryFilter::SO_FOLDERS_BY_NAME) +, mFilterListingFoldersOnly(false) +{ +} + +LLPanelMarketplaceListings::~LLPanelMarketplaceListings() { delete mMenu; } + +void showMenu(LLView* button, LLMenuGL* menu) +{ + menu->buildDrawLabels(); + menu->updateParent(LLMenuGL::sMenuContainer); + const auto& rect = button->getRect(); + LLMenuGL::showPopup(button->getParent(), menu, rect.mLeft, rect.mBottom); +} + +BOOL LLPanelMarketplaceListings::postBuild() +{ + childSetAction("add_btn", boost::bind(&LLPanelMarketplaceListings::onAddButtonClicked, this)); + childSetAction("audit_btn", boost::bind(&LLPanelMarketplaceListings::onAuditButtonClicked, this)); + mMenu = LLUICtrlFactory::instance().buildMenu("menu_marketplace_view.xml", LLMenuGL::sMenuContainer); + auto sort = getChild("sort_btn"); + sort->setCommitCallback(boost::bind(showMenu, _1, mMenu)); + + mFilterEditor = getChild("filter_editor"); + mFilterEditor->setCommitCallback(boost::bind(&LLPanelMarketplaceListings::onFilterEdit, this, _2)); + + mAuditBtn = getChild("audit_btn"); + mAuditBtn->setEnabled(FALSE); + + return LLPanel::postBuild(); +} + +BOOL LLPanelMarketplaceListings::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg) +{ + LLView * handled_view = childrenHandleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); + // Special case the drop zone, also we're a giant drop zone + if (!handled_view || (handled_view->getName() == "marketplace_drop_zone")) + { + LLFolderView* root_folder = getRootFolder(); + return root_folder->handleDragAndDropToThisFolder(mask, drop, cargo_type, cargo_data, accept, tooltip_msg); + } + return false; +} + +void LLPanelMarketplaceListings::buildAllPanels() +{ + // Build the All panel first + LLInventoryPanel* panel_all_items; + panel_all_items = buildInventoryPanel("All Items", "panel_marketplace_listings_inventory.xml"); + panel_all_items->getFilter().setEmptyLookupMessage("MarketplaceNoMatchingItems"); + panel_all_items->getFilter().markDefault(); + + // Build the other panels + LLInventoryPanel* panel; + panel = buildInventoryPanel("Active Items", "panel_marketplace_listings_listed.xml"); + panel->getFilter().setFilterMarketplaceActiveFolders(); + panel->getFilter().setEmptyLookupMessage("MarketplaceNoMatchingItems"); + panel->getFilter().markDefault(); + panel = buildInventoryPanel("Inactive Items", "panel_marketplace_listings_unlisted.xml"); + panel->getFilter().setFilterMarketplaceInactiveFolders(); + panel->getFilter().setEmptyLookupMessage("MarketplaceNoMatchingItems"); + panel->getFilter().markDefault(); + panel = buildInventoryPanel("Unassociated Items", "panel_marketplace_listings_unassociated.xml"); + panel->getFilter().setFilterMarketplaceUnassociatedFolders(); + panel->getFilter().setEmptyLookupMessage("MarketplaceNoMatchingItems"); + panel->getFilter().markDefault(); + + // Set the tab panel + LLTabContainer* tabs_panel = getChild("marketplace_filter_tabs"); + tabs_panel->setCommitCallback(boost::bind(&LLPanelMarketplaceListings::onTabChange, this)); + tabs_panel->selectTabPanel(panel_all_items); // All panel selected by default + mRootFolder = panel_all_items->getRootFolder(); // Keep the root of the all panel + + // Set the default sort order + setSortOrder(gSavedSettings.getU32("MarketplaceListingsSortOrder")); +} + +LLInventoryPanel* LLPanelMarketplaceListings::buildInventoryPanel(const std::string& childname, const std::string& filename) +{ + LLTabContainer* tabs_panel = getChild("marketplace_filter_tabs"); + // Singu Note: These should already be built!! + LLInventoryPanel* panel = tabs_panel->getChild(childname, false, false); + llassert(panel != NULL); + + // Set sort order and callbacks + panel->getRootFolder()->setSortOrder(LLInventoryFilter::SO_FOLDERS_BY_NAME); + panel->setSelectCallback(boost::bind(&LLPanelMarketplaceListings::onSelectionChange, this, panel, _1, _2)); + + return panel; +} + +void LLPanelMarketplaceListings::setSortOrder(U32 sort_order) +{ + mSortOrder = sort_order; + gSavedSettings.setU32("MarketplaceListingsSortOrder", sort_order); + + // Set each panel with that sort order + LLTabContainer* tabs_panel = getChild("marketplace_filter_tabs"); + LLInventoryPanel* panel = (LLInventoryPanel*)tabs_panel->getPanelByName("All Items"); + panel->setSortOrder(mSortOrder); + panel = (LLInventoryPanel*)tabs_panel->getPanelByName("Active Items"); + panel->setSortOrder(mSortOrder); + panel = (LLInventoryPanel*)tabs_panel->getPanelByName("Inactive Items"); + panel->setSortOrder(mSortOrder); + panel = (LLInventoryPanel*)tabs_panel->getPanelByName("Unassociated Items"); + panel->setSortOrder(mSortOrder); +} + +void LLPanelMarketplaceListings::onFilterEdit(const std::string& search_string) +{ + // Find active panel + LLInventoryPanel* panel = (LLInventoryPanel*)getChild("marketplace_filter_tabs")->getCurrentPanel(); + if (panel) + { + // Save filter string (needed when switching tabs) + mFilterSubString = search_string; + // Set filter string on active panel + panel->setFilterSubString(mFilterSubString); + } +} + +void LLPanelMarketplaceListings::draw() +{ + if (LLMarketplaceData::instance().checkDirtyCount()) + { + update_all_marketplace_count(); + } + + // Get the audit button enabled only after the whole inventory is fetched + if (!mAuditBtn->getEnabled()) + { + mAuditBtn->setEnabled(LLInventoryModelBackgroundFetch::instance().isEverythingFetched()); + } + + LLPanel::draw(); +} + +void LLPanelMarketplaceListings::onSelectionChange(LLInventoryPanel *panel, const std::deque& items, BOOL user_action) +{ + panel->onSelectionChange(items, user_action); +} + +bool LLPanelMarketplaceListings::allowDropOnRoot() +{ + LLInventoryPanel* panel = (LLInventoryPanel*)getChild("marketplace_filter_tabs")->getCurrentPanel(); + return (panel ? panel->getAllowDropOnRoot() : false); +} + +void LLPanelMarketplaceListings::onTabChange() +{ + // Find active panel + LLInventoryPanel* panel = (LLInventoryPanel*)getChild("marketplace_filter_tabs")->getCurrentPanel(); + if (panel) + { + // If the panel doesn't allow drop on root, it doesn't allow the creation of new folder on root either + LLButton* add_btn = getChild("add_btn"); + add_btn->setEnabled(panel->getAllowDropOnRoot()); + + // Set filter string on active panel + panel->setFilterSubString(mFilterSubString); + + // Show/hide the drop zone and resize the inventory tabs panel accordingly + LLPanel* drop_zone = (LLPanel*)getChild("marketplace_drop_zone"); + bool drop_zone_visible = drop_zone->getVisible(); + bool allow_drop_on_root = panel->getAllowDropOnRoot(); + if (drop_zone_visible != allow_drop_on_root) + { + LLPanel* tabs = (LLPanel*)getChild("tab_container_panel"); + S32 delta_height = drop_zone->getRect().getHeight(); + delta_height = (drop_zone_visible ? delta_height : -delta_height); + tabs->reshape(tabs->getRect().getWidth(),tabs->getRect().getHeight() + delta_height); + tabs->translate(0,-delta_height); + } + drop_zone->setVisible(allow_drop_on_root); + } +} + +void LLPanelMarketplaceListings::onAddButtonClicked() +{ + // Find active panel + LLInventoryPanel* panel = (LLInventoryPanel*)getChild("marketplace_filter_tabs")->getCurrentPanel(); + if (panel) + { + LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); + llassert(marketplacelistings_id.notNull()); + LLFolderType::EType preferred_type = LLFolderType::lookup("category"); + LLUUID category = gInventory.createNewCategory(marketplacelistings_id, preferred_type, LLStringUtil::null); + gInventory.notifyObservers(); + panel->setSelectionByID(category, TRUE); + panel->getRootFolder()->setNeedsAutoRename(TRUE); + } +} + +void LLPanelMarketplaceListings::onAuditButtonClicked() +{ + LLSD data(LLSD::emptyMap()); + new LLFloaterMarketplaceValidation(data); // It tracks itself *sigh* +} + +void LLPanelMarketplaceListings::onViewSortMenuItemClicked(const LLSD& userdata) +{ + std::string chosen_item = userdata.asString(); + + // Sort options + if ((chosen_item == "sort_by_stock_amount") || (chosen_item == "sort_by_name") || (chosen_item == "sort_by_recent")) + { + // We're making sort options exclusive, default is SO_FOLDERS_BY_NAME + if (chosen_item == "sort_by_stock_amount") + { + setSortOrder(LLInventoryFilter::SO_FOLDERS_BY_WEIGHT); + } + else if (chosen_item == "sort_by_name") + { + setSortOrder(LLInventoryFilter::SO_FOLDERS_BY_NAME); + } + else if (chosen_item == "sort_by_recent") + { + setSortOrder(LLInventoryFilter::SO_DATE); + } + } + // Filter option + else if (chosen_item == "show_only_listing_folders") + { + mFilterListingFoldersOnly = !mFilterListingFoldersOnly; + // Set each panel with that filter flag + LLTabContainer* tabs_panel = getChild("marketplace_filter_tabs"); + LLInventoryPanel* panel = (LLInventoryPanel*)tabs_panel->getPanelByName("All Items"); + panel->getFilter().setFilterMarketplaceListingFolders(mFilterListingFoldersOnly); + panel = (LLInventoryPanel*)tabs_panel->getPanelByName("Active Items"); + panel->getFilter().setFilterMarketplaceListingFolders(mFilterListingFoldersOnly); + panel = (LLInventoryPanel*)tabs_panel->getPanelByName("Inactive Items"); + panel->getFilter().setFilterMarketplaceListingFolders(mFilterListingFoldersOnly); + panel = (LLInventoryPanel*)tabs_panel->getPanelByName("Unassociated Items"); + panel->getFilter().setFilterMarketplaceListingFolders(mFilterListingFoldersOnly); + } +} + +bool LLPanelMarketplaceListings::onViewSortMenuItemCheck(const LLSD& userdata) +{ + std::string chosen_item = userdata.asString(); + + if ((chosen_item == "sort_by_stock_amount") || (chosen_item == "sort_by_name") || (chosen_item == "sort_by_recent")) + { + if (chosen_item == "sort_by_stock_amount") + { + return (mSortOrder & LLInventoryFilter::SO_FOLDERS_BY_WEIGHT); + } + else if (chosen_item == "sort_by_name") + { + return (mSortOrder & LLInventoryFilter::SO_FOLDERS_BY_NAME); + } + else if (chosen_item == "sort_by_recent") + { + return (mSortOrder & LLInventoryFilter::SO_DATE); + } + } + else if (chosen_item == "show_only_listing_folders") + { + return mFilterListingFoldersOnly; + } + return false; +} + +///---------------------------------------------------------------------------- +/// LLMarketplaceListingsAddedObserver helper class +///---------------------------------------------------------------------------- + +class LLMarketplaceListingsAddedObserver : public LLInventoryCategoryAddedObserver +{ +public: + LLMarketplaceListingsAddedObserver(LLFloaterMarketplaceListings * marketplace_listings_floater) + : LLInventoryCategoryAddedObserver() + , mMarketplaceListingsFloater(marketplace_listings_floater) + { + } + + void done() + { + for (cat_vec_t::iterator it = mAddedCategories.begin(); it != mAddedCategories.end(); ++it) + { + LLViewerInventoryCategory* added_category = *it; + + LLFolderType::EType added_category_type = added_category->getPreferredType(); + + if (added_category_type == LLFolderType::FT_MARKETPLACE_LISTINGS) + { + mMarketplaceListingsFloater->initializeMarketPlace(); + } + } + } + +private: + LLFloaterMarketplaceListings * mMarketplaceListingsFloater; +}; + +///---------------------------------------------------------------------------- +/// LLFloaterMarketplaceListings +///---------------------------------------------------------------------------- + +LLFloaterMarketplaceListings::LLFloaterMarketplaceListings(const LLSD& key) +: LLFloater(key) +, mCategoriesObserver(NULL) +, mCategoryAddedObserver(NULL) +, mRootFolderId(LLUUID::null) +, mInventoryStatus(NULL) +, mInventoryInitializationInProgress(NULL) +, mInventoryPlaceholder(NULL) +, mInventoryText(NULL) +, mInventoryTitle(NULL) +, mPanelListings(NULL) +, mPanelListingsSet(false) +{ + //buildFromFile("floater_marketplace_listings.xml"); + mFactoryMap["panel_marketplace_listing"] = LLCallbackMap([&](void*) { return mPanelListings = new LLPanelMarketplaceListings; }); + LLUICtrlFactory::instance().buildFloater(this, "floater_marketplace_listings.xml", &getFactoryMap()); +} + +LLFloaterMarketplaceListings::~LLFloaterMarketplaceListings() +{ + if (mCategoriesObserver && gInventory.containsObserver(mCategoriesObserver)) + { + gInventory.removeObserver(mCategoriesObserver); + } + delete mCategoriesObserver; + + if (mCategoryAddedObserver && gInventory.containsObserver(mCategoryAddedObserver)) + { + gInventory.removeObserver(mCategoryAddedObserver); + } + delete mCategoryAddedObserver; +} + +BOOL LLFloaterMarketplaceListings::postBuild() +{ + mInventoryStatus = getChild("marketplace_status"); + mInventoryInitializationInProgress = getChild("initialization_progress_indicator"); + mInventoryPlaceholder = getChild("marketplace_listings_inventory_placeholder_panel"); + mInventoryText = mInventoryPlaceholder->getChild("marketplace_listings_inventory_placeholder_text"); + mInventoryTitle = mInventoryPlaceholder->getChild("marketplace_listings_inventory_placeholder_title"); + + LLFocusableElement::setFocusReceivedCallback(boost::bind(&LLFloaterMarketplaceListings::onFocusReceived, this)); + + // Observe category creation to catch marketplace listings creation (moot if already existing) + mCategoryAddedObserver = new LLMarketplaceListingsAddedObserver(this); + gInventory.addObserver(mCategoryAddedObserver); + + // Fetch aggressively so we can interact with listings right onOpen() + fetchContents(); + + return TRUE; +} + +void LLFloaterMarketplaceListings::onClose(bool app_quitting) +{ + LLFloater::onClose(app_quitting); +} + +void LLFloaterMarketplaceListings::onOpen(/*const LLSD& key*/) +{ + // + // Initialize the Market Place or go update the marketplace listings + // + if (LLMarketplaceData::instance().getSLMStatus() <= MarketplaceStatusCodes::MARKET_PLACE_CONNECTION_FAILURE) + { + initializeMarketPlace(); + } + else + { + updateView(); + } +} + +void LLFloaterMarketplaceListings::onFocusReceived() +{ + updateView(); +} + +void LLFloaterMarketplaceListings::fetchContents() +{ + if (mRootFolderId.notNull() && + (LLMarketplaceData::instance().getSLMDataFetched() != MarketplaceFetchCodes::MARKET_FETCH_LOADING) && + (LLMarketplaceData::instance().getSLMDataFetched() != MarketplaceFetchCodes::MARKET_FETCH_DONE)) + { + LLMarketplaceData::instance().setDataFetchedSignal(boost::bind(&LLFloaterMarketplaceListings::updateView, this)); + LLMarketplaceData::instance().setSLMDataFetched(MarketplaceFetchCodes::MARKET_FETCH_LOADING); + LLInventoryModelBackgroundFetch::instance().start(mRootFolderId); + LLMarketplaceData::instance().getSLMListings(); + } +} + +void LLFloaterMarketplaceListings::setRootFolder() +{ + if ((LLMarketplaceData::instance().getSLMStatus() != MarketplaceStatusCodes::MARKET_PLACE_MERCHANT) && + (LLMarketplaceData::instance().getSLMStatus() != MarketplaceStatusCodes::MARKET_PLACE_MIGRATED_MERCHANT)) + { + // If we are *not* a merchant or we have no market place connection established yet, do nothing + return; + } + + // We are a merchant. Get the Marketplace listings folder, create it if needs be. + LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, true); + if (marketplacelistings_id.isNull()) + { + // We should never get there unless the inventory fails badly + LL_ERRS("SLM") << "Inventory problem: failure to create the marketplace listings folder for a merchant!" << LL_ENDL; + return; + } + + // No longer need to observe new category creation + if (mCategoryAddedObserver && gInventory.containsObserver(mCategoryAddedObserver)) + { + gInventory.removeObserver(mCategoryAddedObserver); + delete mCategoryAddedObserver; + mCategoryAddedObserver = NULL; + } + llassert(!mCategoryAddedObserver); + + if (marketplacelistings_id == mRootFolderId) + { + LL_WARNS("SLM") << "Inventory warning: Marketplace listings folder already set" << LL_ENDL; + return; + } + + mRootFolderId = marketplacelistings_id; +} + +void LLFloaterMarketplaceListings::setPanels() +{ + if (mRootFolderId.isNull()) + { + return; + } + + // Consolidate Marketplace listings + // We shouldn't have to do that but with a client/server system relying on a "well known folder" convention, + // things get messy and conventions get broken down eventually + gInventory.consolidateForType(mRootFolderId, LLFolderType::FT_MARKETPLACE_LISTINGS); + + // Now that we do have a non NULL root, we can build the inventory panels + mPanelListings->buildAllPanels(); + + // Create observer for marketplace listings modifications + if (!mCategoriesObserver) + { + mCategoriesObserver = new LLInventoryCategoriesObserver(); + llassert(mCategoriesObserver); + gInventory.addObserver(mCategoriesObserver); + mCategoriesObserver->addCategory(mRootFolderId, boost::bind(&LLFloaterMarketplaceListings::onChanged, this)); + } + + // Get the content of the marketplace listings folder + fetchContents(); + + // Flag that this is done + mPanelListingsSet = true; +} + +void LLFloaterMarketplaceListings::initializeMarketPlace() +{ + LLMarketplaceData::instance().initializeSLM(boost::bind(&LLFloaterMarketplaceListings::updateView, this)); +} + +S32 LLFloaterMarketplaceListings::getFolderCount() +{ + if (mPanelListings && mRootFolderId.notNull()) + { + LLInventoryModel::cat_array_t * cats; + LLInventoryModel::item_array_t * items; + gInventory.getDirectDescendentsOf(mRootFolderId, cats, items); + + return (cats->size() + items->size()); + } + else + { + return 0; + } +} + +void LLFloaterMarketplaceListings::setStatusString(const std::string& statusString) +{ + mInventoryStatus->setText(statusString); +} + +void LLFloaterMarketplaceListings::updateView() +{ + U32 mkt_status = LLMarketplaceData::instance().getSLMStatus(); + bool is_merchant = (mkt_status == MarketplaceStatusCodes::MARKET_PLACE_MERCHANT) || (mkt_status == MarketplaceStatusCodes::MARKET_PLACE_MIGRATED_MERCHANT); + U32 data_fetched = LLMarketplaceData::instance().getSLMDataFetched(); + + // Get or create the root folder if we are a merchant and it hasn't been done already + if (mRootFolderId.isNull() && is_merchant) + { + setRootFolder(); + } + + // Update the bottom initializing status and progress dial if we are initializing or if we're a merchant and still loading + if ((mkt_status <= MarketplaceStatusCodes::MARKET_PLACE_INITIALIZING) || (is_merchant && (data_fetched <= MarketplaceFetchCodes::MARKET_FETCH_LOADING)) ) + { + // Just show the loading indicator in that case and fetch the data (fetch will be skipped if it's already loading) + mInventoryInitializationInProgress->setVisible(true); + mPanelListings->setVisible(FALSE); + fetchContents(); + return; + } + else + { + mInventoryInitializationInProgress->setVisible(false); + } + + // Update the middle portion : tabs or messages + if (getFolderCount() > 0) + { + if (!mPanelListingsSet) + { + // We need to rebuild the tabs cleanly the first time we make them visible + setPanels(); + } + mPanelListings->setVisible(TRUE); + mInventoryPlaceholder->setVisible(FALSE); + } + else + { + mPanelListings->setVisible(FALSE); + mInventoryPlaceholder->setVisible(TRUE); + + std::string text; + std::string title; + std::string tooltip; + + const LLSD& subs = LLMarketplaceData::instance().getMarketplaceStringSubstitutions(); + + // Update the top message or flip to the tabs and folders view + // *TODO : check those messages and create better appropriate ones in strings.xml + if (mRootFolderId.notNull()) + { + // "Marketplace listings is empty!" message strings + text = LLTrans::getString("InventoryMarketplaceListingsNoItems", subs); + title = LLTrans::getString("InventoryMarketplaceListingsNoItemsTitle"); + tooltip = LLTrans::getString("InventoryMarketplaceListingsNoItemsTooltip"); + } + else if (mkt_status <= MarketplaceStatusCodes::MARKET_PLACE_INITIALIZING) + { + // "Initializing!" message strings + text = LLTrans::getString("InventoryOutboxInitializing", subs); + title = LLTrans::getString("InventoryOutboxInitializingTitle"); + tooltip = LLTrans::getString("InventoryOutboxInitializingTooltip"); + } + else if (mkt_status == MarketplaceStatusCodes::MARKET_PLACE_NOT_MERCHANT) + { + // "Not a merchant!" message strings + text = LLTrans::getString("InventoryOutboxNotMerchant", subs); + title = LLTrans::getString("InventoryOutboxNotMerchantTitle"); + tooltip = LLTrans::getString("InventoryOutboxNotMerchantTooltip"); + } + else + { + // "Errors!" message strings + text = LLTrans::getString("InventoryMarketplaceError", subs); + title = LLTrans::getString("InventoryOutboxErrorTitle"); + tooltip = LLTrans::getString("InventoryOutboxErrorTooltip"); + } + + mInventoryText->setValue(text); + mInventoryTitle->setValue(title); + mInventoryPlaceholder->getParent()->setToolTip(tooltip); + } +} + +bool LLFloaterMarketplaceListings::isAccepted(EAcceptance accept) +{ + return (accept >= ACCEPT_YES_COPY_SINGLE); +} + +BOOL LLFloaterMarketplaceListings::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg) +{ + // If there's no panel to accept drops or no existing marketplace listings folder, we refuse all drop + if (!mPanelListings || mRootFolderId.isNull()) + { + return FALSE; + } + + tooltip_msg = ""; + + // Pass to the children + LLView * handled_view = childrenHandleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); + BOOL handled = (handled_view != NULL); + + // If no one handled it or it was not accepted and we drop on an empty panel, we try to accept it at the floater level + // as if it was dropped on the marketplace listings root folder + if ((!handled || !isAccepted(*accept)) && !mPanelListings->getVisible() && mRootFolderId.notNull()) + { + if (!mPanelListingsSet) + { + setPanels(); + } + LLFolderView* root_folder = mPanelListings->getRootFolder(); + handled = root_folder->handleDragAndDropToThisFolder(mask, drop, cargo_type, cargo_data, accept, tooltip_msg); + } + + return handled; +} + +BOOL LLFloaterMarketplaceListings::handleHover(S32 x, S32 y, MASK mask) +{ + return LLFloater::handleHover(x, y, mask); +} + +void LLFloaterMarketplaceListings::onMouseLeave(S32 x, S32 y, MASK mask) +{ + LLFloater::onMouseLeave(x, y, mask); +} + +void LLFloaterMarketplaceListings::onChanged() +{ + LLViewerInventoryCategory* category = gInventory.getCategory(mRootFolderId); + if (mRootFolderId.notNull() && category) + { + updateView(); + } + else + { + // Invalidate the marketplace listings data + mRootFolderId.setNull(); + } +} + +//----------------------------------------------------------------------------- +// LLFloaterAssociateListing +//----------------------------------------------------------------------------- + +// Tell if a listing has one only version folder +bool hasUniqueVersionFolder(const LLUUID& folder_id) +{ + LLInventoryModel::cat_array_t* categories; + LLInventoryModel::item_array_t* items; + gInventory.getDirectDescendentsOf(folder_id, categories, items); + return (categories->size() == 1); +} + +LLFloaterAssociateListing::LLFloaterAssociateListing(const LLSD& key) +: LLFloater(key) +, mUUID() +{ + //buildFromFile("floater_associate_listing.xml"); + LLUICtrlFactory::instance().buildFloater(this, "floater_associate_listing.xml"); +} + +LLFloaterAssociateListing::~LLFloaterAssociateListing() +{ + gFocusMgr.releaseFocusIfNeeded( this ); +} + +BOOL LLFloaterAssociateListing::postBuild() +{ + getChild("OK")->setCommitCallback(boost::bind(&LLFloaterAssociateListing::apply, this, TRUE)); + getChild("Cancel")->setCommitCallback(boost::bind(&LLFloaterAssociateListing::cancel, this)); + getChild("listing_id")->setPrevalidate(&LLLineEditor::prevalidateNonNegativeS32); + center(); + + return LLFloater::postBuild(); +} + +BOOL LLFloaterAssociateListing::handleKeyHere(KEY key, MASK mask) +{ + if (key == KEY_RETURN && mask == MASK_NONE) + { + apply(); + return TRUE; + } + else if (key == KEY_ESCAPE && mask == MASK_NONE) + { + cancel(); + return TRUE; + } + + return LLFloater::handleKeyHere(key, mask); +} + +// static +void LLFloaterAssociateListing::show(LLFloaterAssociateListing* floater, const LLSD& folder_id) +{ + if (!floater) return; + + floater->mUUID = folder_id.asUUID(); + + floater->open(); +} + +// Callback for apply if DAMA required... +void LLFloaterAssociateListing::callback_apply(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option == 0) // YES + { + apply(FALSE); + } +} + +void LLFloaterAssociateListing::apply(BOOL user_confirm) +{ + if (mUUID.notNull()) + { + S32 id = (S32)getChild("listing_id")->getValue().asInteger(); + if (id > 0) + { + // Check if the id exists in the merchant SLM DB: note that this record might exist in the LLMarketplaceData + // structure even if unseen in the UI, for instance, if its listing_uuid doesn't exist in the merchant inventory + LLUUID listing_uuid = LLMarketplaceData::instance().getListingFolder(id); + if (listing_uuid.notNull() && user_confirm && LLMarketplaceData::instance().getActivationState(listing_uuid) && !hasUniqueVersionFolder(mUUID)) + { + // Look for user confirmation before unlisting + LLNotificationsUtil::add("ConfirmMerchantUnlist", LLSD(), LLSD(), boost::bind(&LLFloaterAssociateListing::callback_apply, this, _1, _2)); + return; + } + // Associate the id with the user chosen folder + LLMarketplaceData::instance().associateListing(mUUID,listing_uuid,id); + } + else + { + LLNotificationsUtil::add("AlertMerchantListingInvalidID"); + } + } + close(); +} + +void LLFloaterAssociateListing::cancel() +{ + close(); +} + +//----------------------------------------------------------------------------- +// LLFloaterMarketplaceValidation +//----------------------------------------------------------------------------- + +// Note: The key is the UUID of the folder to validate. +// Validates the whole marketplace listings content if UUID is null. + +LLFloaterMarketplaceValidation::LLFloaterMarketplaceValidation(const LLSD& key) +: LLFloater(), + mKey(key), + mEditor(NULL) +{ + //buildFromFile("floater_marketplace_validation.xml"); + LLUICtrlFactory::instance().buildFloater(this, "floater_marketplace_validation.xml"); +} + +BOOL LLFloaterMarketplaceValidation::postBuild() +{ + childSetAction("OK", onOK, this); + + // This widget displays the validation messages + mEditor = getChild("validation_text"); + mEditor->setEnabled(FALSE); + mEditor->setFocus(TRUE); + mEditor->setValue(LLSD()); + + return TRUE; +} + +LLFloaterMarketplaceValidation::~LLFloaterMarketplaceValidation() +{ +} + +// virtual +void LLFloaterMarketplaceValidation::draw() +{ + // draw children + LLFloater::draw(); +} + +void LLFloaterMarketplaceValidation::onOpen(/*const LLSD& key*/) +{ + // Clear the messages + clearMessages(); + + // Get the folder UUID to validate. Use the whole marketplace listing if none provided. + LLUUID cat_id(mKey.asUUID()); + if (cat_id.isNull()) + { + cat_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); + } + + // Validates the folder + if (cat_id.notNull()) + { + LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id); + validate_marketplacelistings(cat, boost::bind(&LLFloaterMarketplaceValidation::appendMessage, this, _1, _2, _3), false); + } + + // Handle the listing folder being processed + handleCurrentListing(); + + // Dump result to the editor panel + if (mEditor) + { + mEditor->setValue(LLSD()); + if (mMessages.empty()) + { + // Display a no error message + mEditor->appendText(LLTrans::getString("Marketplace Validation No Error"), false, false); + } + else + { + // Print out all the messages to the panel + message_list_t::iterator mCurrentLine = mMessages.begin(); + bool new_line = false; + while (mCurrentLine != mMessages.end()) + { + // Errors are printed in bold, other messages in normal font + LLStyleSP style(new LLStyle); + style->setColor(mEditor->getReadOnlyFgColor()); + style->mBold = mCurrentLine->mErrorLevel == LLError::LEVEL_ERROR; + mEditor->appendText(mCurrentLine->mMessage, false, new_line, style); + new_line = true; + mCurrentLine++; + } + } + } + // We don't need the messages anymore + clearMessages(); +} + +// static +void LLFloaterMarketplaceValidation::onOK( void* userdata ) +{ + // destroys this object + LLFloaterMarketplaceValidation* self = (LLFloaterMarketplaceValidation*) userdata; + self->clearMessages(); + self->close(); +} + +void LLFloaterMarketplaceValidation::appendMessage(std::string& message, S32 depth, LLError::ELevel log_level) +{ + // Dump previous listing messages if we're starting a new listing + if (depth == 1) + { + handleCurrentListing(); + } + + // Store the message in the current listing message list + Message current_message; + current_message.mErrorLevel = log_level; + current_message.mMessage = message; + mCurrentListingMessages.push_back(current_message); + mCurrentListingErrorLevel = (mCurrentListingErrorLevel < log_level ? log_level : mCurrentListingErrorLevel); +} + +// Move the current listing messages to the general list if needs be and reset the current listing data +void LLFloaterMarketplaceValidation::handleCurrentListing() +{ + // Dump the current folder messages to the general message list if level warrants it + if (mCurrentListingErrorLevel > LLError::LEVEL_INFO) + { + message_list_t::iterator mCurrentLine = mCurrentListingMessages.begin(); + while (mCurrentLine != mCurrentListingMessages.end()) + { + mMessages.push_back(*mCurrentLine); + mCurrentLine++; + } + } + + // Reset the current listing + mCurrentListingMessages.clear(); + mCurrentListingErrorLevel = LLError::LEVEL_INFO; +} + +void LLFloaterMarketplaceValidation::clearMessages() +{ + mMessages.clear(); + mCurrentListingMessages.clear(); + mCurrentListingErrorLevel = LLError::LEVEL_INFO; +} + +/* Singu Note: What even is this? Where is this used?! +//----------------------------------------------------------------------------- +// LLFloaterItemProperties +//----------------------------------------------------------------------------- + +LLFloaterItemProperties::LLFloaterItemProperties(const LLSD& key) +: LLFloater(key) +{ +} + +LLFloaterItemProperties::~LLFloaterItemProperties() +{ +} + +BOOL LLFloaterItemProperties::postBuild() +{ + // On the standalone properties floater, we have no need for a back button... + LLPanel* panel = getChild("item_panel"); + LLButton* back_btn = panel->getChild("back_btn"); + back_btn->setVisible(FALSE); + + return LLFloater::postBuild(); +} + +void LLFloaterItemProperties::onOpen(const LLSD& key) +{ + // Tell the panel which item it needs to visualize + LLPanel* panel = getChild("item_panel"); + panel->setItemID(mKey["id"].asUUID()); +} +*/ diff --git a/indra/newview/llfloatermarketplacelistings.h b/indra/newview/llfloatermarketplacelistings.h new file mode 100644 index 0000000000..496117a7f8 --- /dev/null +++ b/indra/newview/llfloatermarketplacelistings.h @@ -0,0 +1,239 @@ +/** + * @file llfloatermarketplacelistings.h + * @brief Implementation of the marketplace listings floater and panels + * @author merov@lindenlab.com + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * ABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLFLOATERMARKETPLACELISTINGS_H +#define LL_LLFLOATERMARKETPLACELISTINGS_H + +#include "llfloater.h" +#include "llinventoryfilter.h" +#include "llinventorypanel.h" +#include "llnotificationptr.h" +#include "llmodaldialog.h" +#include "lltexteditor.h" + +class LLInventoryCategoriesObserver; +class LLInventoryCategoryAddedObserver; +class LLTextBox; +class LLView; +class LLFilterEditor; + +class LLFloaterMarketplaceListings; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLPanelMarketplaceListings +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class LLPanelMarketplaceListings : public LLPanel +{ +public: + LLPanelMarketplaceListings(); + ~LLPanelMarketplaceListings(); + BOOL postBuild(); + BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg); + void draw(); + LLFolderView* getRootFolder() { return mRootFolder; } + bool allowDropOnRoot(); + + void buildAllPanels(); + +private: + friend struct MarketplaceViewSortAction; + friend struct MarketplaceViewSortCheckItem; + + LLInventoryPanel* buildInventoryPanel(const std::string& childname, const std::string& filename); + + // UI callbacks + void onViewSortMenuItemClicked(const LLSD& userdata); + bool onViewSortMenuItemCheck(const LLSD& userdata); + void onAddButtonClicked(); + void onAuditButtonClicked(); + void onSelectionChange(LLInventoryPanel *panel, const std::deque& items, BOOL user_action); + void onTabChange(); + void onFilterEdit(const std::string& search_string); + + void setSortOrder(U32 sort_order); + + LLFolderView* mRootFolder; + LLButton* mAuditBtn; + class LLMenuGL* mMenu; + LLFilterEditor* mFilterEditor; + std::string mFilterSubString; + bool mFilterListingFoldersOnly; + U32 mSortOrder; +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLFloaterMarketplaceListings +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class LLFloaterMarketplaceListings : public LLFloater, public LLFloaterSingleton +{ +public: + LLFloaterMarketplaceListings(const LLSD& key); + ~LLFloaterMarketplaceListings(); + + void initializeMarketPlace(); + + // virtuals + BOOL postBuild(); + BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg); + + void showNotification(const LLNotificationPtr& notification); + + BOOL handleHover(S32 x, S32 y, MASK mask); + void onMouseLeave(S32 x, S32 y, MASK mask); + +protected: + void setRootFolder(); + void setPanels(); + void fetchContents(); + + void setStatusString(const std::string& statusString); + + void onClose(bool app_quitting); + void onOpen(/*const LLSD& key*/); + void onFocusReceived(); + void onChanged(); + + bool isAccepted(EAcceptance accept); + + void updateView(); + +private: + friend struct MarketplaceViewSortAction; + friend struct MarketplaceViewSortCheckItem; + S32 getFolderCount(); + + LLInventoryCategoriesObserver * mCategoriesObserver; + LLInventoryCategoryAddedObserver * mCategoryAddedObserver; + + LLTextBox * mInventoryStatus; + LLView * mInventoryInitializationInProgress; + LLView * mInventoryPlaceholder; + LLTextEditor * mInventoryText; + LLTextBox * mInventoryTitle; + + LLUUID mRootFolderId; + LLPanelMarketplaceListings * mPanelListings; + bool mPanelListingsSet; +}; + +//----------------------------------------------------------------------------- +// LLFloaterAssociateListing +//----------------------------------------------------------------------------- +class LLFloaterAssociateListing : public LLFloater, public LLUISingleton +{ +friend class LLUISingleton; +public: + virtual BOOL postBuild(); + virtual BOOL handleKeyHere(KEY key, MASK mask); + + static bool visible(LLFloaterAssociateListing* floater, const LLSD& key) { return floater && !floater->isMinimized() && floater->isInVisibleChain(); } + static void show(LLFloaterAssociateListing* floater, const LLSD& folder_id); + static void hide(LLFloaterAssociateListing* floater, const LLSD& key) { if (floater) floater->close(); } + +private: + LLFloaterAssociateListing(const LLSD& key); + virtual ~LLFloaterAssociateListing(); + + // UI Callbacks + void apply(BOOL user_confirm = TRUE); + void cancel(); + void callback_apply(const LLSD& notification, const LLSD& response); + + LLUUID mUUID; +}; + +//----------------------------------------------------------------------------- +// LLFloaterMarketplaceValidation +//----------------------------------------------------------------------------- +// Note: The key is the UUID of the folder to validate. Validates the whole +// marketplace listings content if UUID is null. +// Note: For the moment, we just display the validation text. Eventually, we should +// get the validation triggered on the server and display the html report. +// *TODO : morph into an html/text window using the pattern in llfloatertos + +class LLFloaterMarketplaceValidation : public LLFloater +{ +public: + LLFloaterMarketplaceValidation(const LLSD& key); + virtual ~LLFloaterMarketplaceValidation(); + + virtual BOOL postBuild(); + virtual void draw(); + virtual void onOpen(/*const LLSD& key*/); + + void clearMessages(); + void appendMessage(std::string& message, S32 depth, LLError::ELevel log_level); + static void onOK( void* userdata ); + +private: + struct Message { + LLError::ELevel mErrorLevel; + std::string mMessage; + }; + typedef std::vector message_list_t; + + void handleCurrentListing(); + + message_list_t mCurrentListingMessages; + LLError::ELevel mCurrentListingErrorLevel; + + message_list_t mMessages; + + LLSD mKey; + LLTextEditor* mEditor; +}; + + +#if 0 +//----------------------------------------------------------------------------- +// LLFloaterItemProperties +//----------------------------------------------------------------------------- + +class LLFloaterItemProperties : public LLFloater +{ +public: + LLFloaterItemProperties(const LLSD& key); + virtual ~LLFloaterItemProperties(); + + BOOL postBuild(); + virtual void onOpen(/*const LLSD& key*/); + +private: +}; +#endif + +#endif // LL_LLFLOATERMARKETPLACELISTINGS_H diff --git a/indra/newview/llfloatermediafilter.cpp b/indra/newview/llfloatermediafilter.cpp new file mode 100644 index 0000000000..f03216ff07 --- /dev/null +++ b/indra/newview/llfloatermediafilter.cpp @@ -0,0 +1,120 @@ +/* + * @file llfloatermediafilter.cpp + * @brief Stupid floater for listing junk + * @author Cinder Biscuits + * + * Permission is hereby granted, free of charge, to any person or organization + * obtaining a copy of the software and accompanying documentation covered by + * this license (the "Software") to use, reproduce, display, distribute, + * execute, and transmit the Software, and to prepare derivative works of the + * Software, and to permit third-parties to whom the Software is furnished to + * do so, all subject to the following: + * + * The copyright notices in the Software and this entire statement, including + * the above license grant, this restriction and the following disclaimer, + * must be included in all copies of the Software, in whole or in part, and + * all derivative works of the Software, unless such copies or derivative + * works are solely in the form of machine-executable object code generated by + * a source language processor. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT + * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE + * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +#include "llviewerprecompiledheaders.h" +#include "llfloatermediafilter.h" + +#include "llnotificationsutil.h" +#include "llscrolllistctrl.h" +#include "llscrolllistitem.h" +#include "lltrans.h" +#include "lluictrlfactory.h" + +void on_add_to_list(bool white); +bool handle_add_callback(const LLSD& notification, const LLSD& response, const bool& white); +// TODO: Maybe add removal confirmation? +//bool handle_remove_callback(const LLSD& notification, const LLSD& response); + +LLFloaterMediaFilter::LLFloaterMediaFilter(const LLSD& key) +: LLFloater(key) +{ + mCommitCallbackRegistrar.add("MediaFilter.OnAdd", boost::bind(on_add_to_list, boost::bind(&LLSD::asBoolean, _2))); + mCommitCallbackRegistrar.add("MediaFilter.OnRemove", boost::bind(&LLFloaterMediaFilter::onRemoveFromList, this, boost::bind(&LLSD::asBoolean, _2))); + mMediaListConnection = LLMediaFilter::getInstance()->setMediaListUpdateCallback(boost::bind(&LLFloaterMediaFilter::updateLists, this, _1)); + LLUICtrlFactory::getInstance()->buildFloater(this, "floater_media_lists.xml", NULL, false); +} + +LLFloaterMediaFilter::~LLFloaterMediaFilter() +{ + if (mMediaListConnection.connected()) + mMediaListConnection.disconnect(); +} + +BOOL LLFloaterMediaFilter::postBuild() +{ + mWhitelist = getChild("whitelist"); + mBlacklist = getChild("blacklist"); + updateLists(LLMediaFilter::WHITELIST); + updateLists(LLMediaFilter::BLACKLIST); + mWhitelist->setCommitOnSelectionChange(true); + mBlacklist->setCommitOnSelectionChange(true); + mWhitelist->setCommitCallback(boost::bind(&LLFloaterMediaFilter::enableButton, this, getChildView("remove_whitelist"), mWhitelist)); + mBlacklist->setCommitCallback(boost::bind(&LLFloaterMediaFilter::enableButton, this, getChildView("remove_blacklist"), mBlacklist)); + + return TRUE; +} + +void LLFloaterMediaFilter::updateLists(LLMediaFilter::EMediaList list_type) +{ + bool white(list_type == LLMediaFilter::WHITELIST); + const LLMediaFilter& inst(LLMediaFilter::instance()); + const LLMediaFilter::string_list_t& list = white ? inst.getWhiteList() : inst.getBlackList(); + LLScrollListCtrl* scroll(white ? mWhitelist : mBlacklist); + scroll->clearRows(); + for (const auto& value : list) + { + LLSD element; + element["columns"][0]["column"] = "list"; + element["columns"][0]["value"] = value; + scroll->addElement(element); + } + enableButton(getChildView(white ? "remove_whitelist" : "remove_blacklist"), scroll); +} + +void LLFloaterMediaFilter::enableButton(LLView* btn, const LLScrollListCtrl* scroll) +{ + btn->setEnabled(!scroll->isEmpty() && scroll->getFirstSelected()); +} + +void on_add_to_list(bool white) +{ + LLSD args; + args["LIST"] = LLTrans::getString(white ? "MediaFilterWhitelist" : "MediaFilterBlacklist"); + LLNotificationsUtil::add("AddToMediaList", args, LLSD(), boost::bind(handle_add_callback, _1, _2, white)); +} + +void LLFloaterMediaFilter::onRemoveFromList(bool white) +{ + std::vector selected = (white ? mWhitelist : mBlacklist)->getAllSelected(); + LLMediaFilter::string_vec_t domains; + for (auto* item : selected) + { + domains.push_back(item->getColumn(0)->getValue().asString()); + } + LLMediaFilter::getInstance()->removeFromMediaList(domains, white ? LLMediaFilter::WHITELIST : LLMediaFilter::BLACKLIST); +} + +bool handle_add_callback(const LLSD& notification, const LLSD& response, const bool& white) +{ + if (LLNotificationsUtil::getSelectedOption(notification, response) == 0) + { + LLMediaFilter::instance().addToMediaList(response["url"].asString(), white ? LLMediaFilter::WHITELIST : LLMediaFilter::BLACKLIST); + } + return false; +} diff --git a/indra/newview/llfloatermediafilter.h b/indra/newview/llfloatermediafilter.h new file mode 100644 index 0000000000..6ee23bbabd --- /dev/null +++ b/indra/newview/llfloatermediafilter.h @@ -0,0 +1,55 @@ +/* + * @file LLFloaterMediaFilter.h + * @brief Stupid floater for listing junk + * @author Cinder Biscuits + * + * Permission is hereby granted, free of charge, to any person or organization + * obtaining a copy of the software and accompanying documentation covered by + * this license (the "Software") to use, reproduce, display, distribute, + * execute, and transmit the Software, and to prepare derivative works of the + * Software, and to permit third-parties to whom the Software is furnished to + * do so, all subject to the following: + * + * The copyright notices in the Software and this entire statement, including + * the above license grant, this restriction and the following disclaimer, + * must be included in all copies of the Software, in whole or in part, and + * all derivative works of the Software, unless such copies or derivative + * works are solely in the form of machine-executable object code generated by + * a source language processor. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT + * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE + * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef LL_FLOATERMEDIAFILTER_H +#define LL_FLOATERMEDIAFILTER_H + +#include "llfloater.h" +#include "llmediafilter.h" + +class LLScrollListCtrl; + +class LLFloaterMediaFilter : public LLFloater, public LLFloaterSingleton +{ + friend class LLUISingleton >; +public: + LLFloaterMediaFilter(const LLSD& key); + BOOL postBuild(); +private: + ~LLFloaterMediaFilter(); + void updateLists(LLMediaFilter::EMediaList list); + void enableButton(LLView* btn, const LLScrollListCtrl* scroll); + void onRemoveFromList(bool white); + + LLScrollListCtrl* mWhitelist; + LLScrollListCtrl* mBlacklist; + boost::signals2::connection mMediaListConnection; +}; + +#endif // LL_FLOATERMEDIAFILTER_H diff --git a/indra/newview/llfloatermediasettings.cpp b/indra/newview/llfloatermediasettings.cpp index f0f1f38695..53e405af8d 100644 --- a/indra/newview/llfloatermediasettings.cpp +++ b/indra/newview/llfloatermediasettings.cpp @@ -43,10 +43,13 @@ LLFloaterMediaSettings* LLFloaterMediaSettings::sInstance = NULL; // LLFloaterMediaSettings::LLFloaterMediaSettings(const LLSD& key) : LLFloater(key), - mTabContainer(NULL), - mPanelMediaSettingsGeneral(NULL), - mPanelMediaSettingsSecurity(NULL), - mPanelMediaSettingsPermissions(NULL), + mOKBtn(nullptr), + mCancelBtn(nullptr), + mApplyBtn(nullptr), + mTabContainer(nullptr), + mPanelMediaSettingsGeneral(nullptr), + mPanelMediaSettingsSecurity(nullptr), + mPanelMediaSettingsPermissions(nullptr), mWaitingToClose( false ), mIdenticalHasMediaInfo( true ), mMultipleMedia(false), diff --git a/indra/newview/llfloatermemleak.cpp b/indra/newview/llfloatermemleak.cpp index df51918e35..a15bd95203 100644 --- a/indra/newview/llfloatermemleak.cpp +++ b/indra/newview/llfloatermemleak.cpp @@ -256,6 +256,10 @@ LLFloaterMemLeak* LLFloaterMemLeak::instance() void LLFloaterMemLeak::show(void*) { +#ifdef LL_RELEASE_FOR_DOWNLOAD + if (!gSavedSettings.getBOOL("QAMode")) + return; // Singu Note: We should probably tell them why this won't work before returning. +#endif instance()->open(); } diff --git a/indra/newview/llfloatermessagelog.cpp b/indra/newview/llfloatermessagelog.cpp index 8847ca2ca2..39072b1bf0 100644 --- a/indra/newview/llfloatermessagelog.cpp +++ b/indra/newview/llfloatermessagelog.cpp @@ -86,11 +86,11 @@ LLFloaterMessageLogItem::LLFloaterMessageLogItem(LLMessageLogEntry entry) mSummary.append(" ] "); } - LLMessageTemplate::message_block_map_t::iterator blocks_end = temp->mMemberBlocks.end(); - for (LLMessageTemplate::message_block_map_t::iterator blocks_iter = temp->mMemberBlocks.begin(); + LLMessageTemplate::message_block_map_t::const_iterator blocks_end = temp->mMemberBlocks.end(); + for (LLMessageTemplate::message_block_map_t::const_iterator blocks_iter = temp->mMemberBlocks.begin(); blocks_iter != blocks_end; ++blocks_iter) { - LLMessageBlock* block = (*blocks_iter); + const LLMessageBlock* block = temp->mMemberBlocks.toValue(blocks_iter); const char* block_name = block->mName; S32 num_blocks = sTemplateMessageReader->getNumberOfBlocks(block_name); if(!num_blocks) @@ -100,11 +100,11 @@ LLFloaterMessageLogItem::LLFloaterMessageLogItem(LLMessageLogEntry entry) else for(S32 i = 0; i < 1; i++) { mSummary.append(" { "); - LLMessageBlock::message_variable_map_t::iterator var_end = block->mMemberVariables.end(); - for (LLMessageBlock::message_variable_map_t::iterator var_iter = block->mMemberVariables.begin(); + LLMessageBlock::message_variable_map_t::const_iterator var_end = block->mMemberVariables.end(); + for (LLMessageBlock::message_variable_map_t::const_iterator var_iter = block->mMemberVariables.begin(); var_iter != var_end; ++var_iter) { - LLMessageVariable* variable = (*var_iter); + const LLMessageVariable* variable = block->mMemberVariables.toValue(var_iter); const char* var_name = variable->getName(); BOOL returned_hex; std::string value = getString(sTemplateMessageReader, block_name, i, var_name, variable->getType(), returned_hex, TRUE); @@ -179,21 +179,22 @@ std::string LLFloaterMessageLogItem::getFull(BOOL show_header) full.append(llformat("LL_RESENT_FLAG = %s\n", (mFlags & LL_RESENT_FLAG) ? "True" : "False")); full.append(llformat("LL_ACK_FLAG = %s\n", (mFlags & LL_ACK_FLAG) ? "True" : "False")); } - LLMessageTemplate::message_block_map_t::iterator blocks_end = temp->mMemberBlocks.end(); - for (LLMessageTemplate::message_block_map_t::iterator blocks_iter = temp->mMemberBlocks.begin(); + LLMessageTemplate::message_block_map_t::const_iterator blocks_end = temp->mMemberBlocks.end(); + for (LLMessageTemplate::message_block_map_t::const_iterator blocks_iter = temp->mMemberBlocks.begin(); blocks_iter != blocks_end; ++blocks_iter) { - LLMessageBlock* block = (*blocks_iter); + const LLMessageBlock* block = temp->mMemberBlocks.toValue(blocks_iter); const char* block_name = block->mName; S32 num_blocks = sTemplateMessageReader->getNumberOfBlocks(block_name); for(S32 i = 0; i < num_blocks; i++) { full.append(llformat("[%s]\n", block->mName)); - LLMessageBlock::message_variable_map_t::iterator var_end = block->mMemberVariables.end(); - for (LLMessageBlock::message_variable_map_t::iterator var_iter = block->mMemberVariables.begin(); + LLMessageBlock::message_variable_map_t::const_iterator var_end = block->mMemberVariables.end(); + for (LLMessageBlock::message_variable_map_t::const_iterator var_iter = block->mMemberVariables.begin(); var_iter != var_end; ++var_iter) { - LLMessageVariable* variable = (*var_iter); + const LLMessageVariable* variable = block->mMemberVariables.toValue(var_iter); + //LLMessageVariable* variable = var_iter->second; const char* var_name = variable->getName(); BOOL returned_hex; std::string value = getString(sTemplateMessageReader, block_name, i, var_name, variable->getType(), returned_hex); diff --git a/indra/newview/llfloatermessagelog.h b/indra/newview/llfloatermessagelog.h index 1fa01c5afd..a17026233e 100644 --- a/indra/newview/llfloatermessagelog.h +++ b/indra/newview/llfloatermessagelog.h @@ -1,3 +1,6 @@ +#ifndef LL_LLFLOATERMESSAGELOG_H +#define LL_LLFLOATERMESSAGELOG_H + // #include "llfloater.h" #include "llmessagelog.h" @@ -94,3 +97,5 @@ class LLFloaterMessageLog : public LLFloater, public LLEventTimer static void onClickFilterMenu(void* user_data); }; // + +#endif \ No newline at end of file diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 6c22653a3e..dc73d08600 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -32,38 +32,8 @@ #include "llviewerprecompiledheaders.h" -#if LL_MSVC -#pragma warning (disable : 4018) -#pragma warning (push) -#pragma warning (disable : 4068) -#pragma warning (disable : 4263) -#pragma warning (disable : 4264) -#endif -#pragma GCC diagnostic ignored "-Woverloaded-virtual" -#include "dae.h" -//#include "dom.h" -#include "dom/domAsset.h" -#include "dom/domBind_material.h" -#include "dom/domCOLLADA.h" -#include "dom/domConstants.h" -#include "dom/domController.h" -#include "dom/domEffect.h" -#include "dom/domGeometry.h" -#include "dom/domInstance_geometry.h" -#include "dom/domInstance_material.h" -#include "dom/domInstance_node.h" -#include "dom/domInstance_effect.h" -#include "dom/domMaterial.h" -#include "dom/domMatrix.h" -#include "dom/domNode.h" -#include "dom/domProfile_COMMON.h" -#include "dom/domRotate.h" -#include "dom/domScale.h" -#include "dom/domTranslate.h" -#include "dom/domVisual_scene.h" -#if LL_MSVC -#pragma warning (pop) -#endif +#include "llmodelloader.h" +#include "lldaeloader.h" #include "llfloatermodelpreview.h" @@ -81,6 +51,7 @@ #include "llmatrix4a.h" #include "llnotificationsutil.h" #include "llsdutil_math.h" +#include "llskinningutil.h" #include "lltextbox.h" #include "lltoolmgr.h" #include "llui.h" @@ -108,13 +79,13 @@ #include #include "hippogridmanager.h" - -const S32 SLM_SUPPORTED_VERSION = 3; +#include "hippolimits.h" //static S32 LLFloaterModelPreview::sUploadAmount = 10; LLFloaterModelPreview* LLFloaterModelPreview::sInstance = NULL; -std::list LLModelLoader::sActiveLoaderList; + +bool LLModelPreview::sIgnoreLoadedCallback = false; // "Retain%" decomp parameter has values from 0.0 to 1.0 by 0.01 // But according to the UI spec for upload model floater, this parameter @@ -131,222 +102,129 @@ const S32 SMOOTH_VALUES_NUMBER = 10; void drawBoxOutline(const LLVector3& pos, const LLVector3& size); -std::string lod_name[NUM_LOD] = + +std::string lod_name[NUM_LOD+1] = { "lowest", "low", "medium", "high", + "I went off the end of the lod_name array. Me so smart." }; -std::string lod_triangles_name[NUM_LOD] = +std::string lod_triangles_name[NUM_LOD+1] = { "lowest_triangles", "low_triangles", "medium_triangles", "high_triangles", + "I went off the end of the lod_triangles_name array. Me so smart." }; -std::string lod_vertices_name[NUM_LOD] = +std::string lod_vertices_name[NUM_LOD+1] = { "lowest_vertices", "low_vertices", "medium_vertices", "high_vertices", + "I went off the end of the lod_vertices_name array. Me so smart." }; -std::string lod_status_name[NUM_LOD] = +std::string lod_status_name[NUM_LOD+1] = { "lowest_status", "low_status", "medium_status", "high_status", + "I went off the end of the lod_status_name array. Me so smart." }; -std::string lod_icon_name[NUM_LOD] = +std::string lod_icon_name[NUM_LOD+1] = { "status_icon_lowest", "status_icon_low", "status_icon_medium", "status_icon_high", + "I went off the end of the lod_status_name array. Me so smart." }; -std::string lod_status_image[NUM_LOD] = +std::string lod_status_image[] = { "green_checkmark.png", "lag_status_warning.tga", "red_x.png", + "I went off the end of the lod_status_image array. Me so smart." }; -std::string lod_label_name[NUM_LOD] = +std::string lod_label_name[NUM_LOD+1] = { "lowest_label", "low_label", "medium_label", "high_label", + "I went off the end of the lod_label_name array. Me so smart." }; -std::string colladaVersion[VERSIONTYPE_COUNT + 1] = -{ - "1.4.0", - "1.4.1", - "Unsupported" -}; - -#define LL_DEGENERACY_TOLERANCE 1e-7f - -inline F32 dot3fpu(const LLVector4a& a, const LLVector4a& b) -{ - volatile F32 p0 = a[0] * b[0]; - volatile F32 p1 = a[1] * b[1]; - volatile F32 p2 = a[2] * b[2]; - return p0 + p1 + p2; -} - -bool ll_is_degenerate(const LLVector4a& a, const LLVector4a& b, const LLVector4a& c, F32 tolerance = LL_DEGENERACY_TOLERANCE) -{ - // small area check - { - LLVector4a edge1; edge1.setSub(a, b); - LLVector4a edge2; edge2.setSub(a, c); - ////////////////////////////////////////////////////////////////////////// - /// Linden Modified - ////////////////////////////////////////////////////////////////////////// - - // If no one edge is more than 10x longer than any other edge, we weaken - // the tolerance by a factor of 1e-4f. - - LLVector4a edge3; edge3.setSub(c, b); - const F32 len1sq = edge1.dot3(edge1).getF32(); - const F32 len2sq = edge2.dot3(edge2).getF32(); - const F32 len3sq = edge3.dot3(edge3).getF32(); - bool abOK = (len1sq <= 100.f * len2sq) && (len1sq <= 100.f * len3sq); - bool acOK = (len2sq <= 100.f * len1sq) && (len1sq <= 100.f * len3sq); - bool cbOK = (len3sq <= 100.f * len1sq) && (len1sq <= 100.f * len2sq); - if (abOK && acOK && cbOK) - { - tolerance *= 1e-4f; - } - - ////////////////////////////////////////////////////////////////////////// - /// End Modified - ////////////////////////////////////////////////////////////////////////// - - LLVector4a cross; cross.setCross3(edge1, edge2); - - LLVector4a edge1b; edge1b.setSub(b, a); - LLVector4a edge2b; edge2b.setSub(b, c); - LLVector4a crossb; crossb.setCross3(edge1b, edge2b); - - if ((cross.dot3(cross).getF32() < tolerance) || (crossb.dot3(crossb).getF32() < tolerance)) - { - return true; - } - } - - // point triangle distance check - { - LLVector4a Q; Q.setSub(a, b); - LLVector4a R; R.setSub(c, b); - - const F32 QQ = dot3fpu(Q, Q); - const F32 RR = dot3fpu(R, R); - const F32 QR = dot3fpu(R, Q); - - volatile F32 QQRR = QQ * RR; - volatile F32 QRQR = QR * QR; - F32 Det = (QQRR - QRQR); - - if (Det == 0.0f) - { - return true; - } - } - - return false; -} - -bool validate_face(const LLVolumeFace& face) +BOOL stop_gloderror() { - for (U32 i = 0; i < face.mNumIndices; ++i) - { - if (face.mIndices[i] >= face.mNumVertices) - { - llwarns << "Face has invalid index." << llendl; - return false; - } - } + GLuint error = glodGetError(); - if (face.mNumIndices % 3 != 0 || face.mNumIndices == 0) + if (error != GLOD_NO_ERROR) { - llwarns << "Face has invalid number of indices." << llendl; - return false; + LL_WARNS() << "GLOD error detected, cannot generate LOD: " << std::hex << error << LL_ENDL; + return TRUE; } - /*const LLVector4a scale(0.5f); - - for (U32 i = 0; i < face.mNumIndices; i+=3) - { - U16 idx1 = face.mIndices[i]; - U16 idx2 = face.mIndices[i + 1]; - U16 idx3 = face.mIndices[i+2]; - - LLVector4a v1; v1.setMul(face.mPositions[idx1], scale); - LLVector4a v2; v2.setMul(face.mPositions[idx2], scale); - LLVector4a v3; v3.setMul(face.mPositions[idx3], scale); - - if (ll_is_degenerate(v1,v2,v3)) - { - llwarns << "Degenerate face found!" << llendl; - return false; - } - }*/ - - return true; + return FALSE; } -bool validate_model(const LLModel* mdl) +LLViewerFetchedTexture* bindMaterialDiffuseTexture(const LLImportMaterial& material) { - if (mdl->getNumVolumeFaces() == 0) - { - llwarns << "Model has no faces!" << llendl; - return false; - } + LLViewerFetchedTexture *texture = LLViewerTextureManager::getFetchedTexture(material.getDiffuseMap(), FTT_DEFAULT, TRUE, LLGLTexture::BOOST_PREVIEW); - for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) + if (texture) { - if (mdl->getVolumeFace(i).mNumVertices == 0) - { - llwarns << "Face has no vertices." << llendl; - return false; - } - - if (mdl->getVolumeFace(i).mNumIndices == 0) - { - llwarns << "Face has no indices." << llendl; - return false; - } - - if (!validate_face(mdl->getVolumeFace(i))) + if (texture->getDiscardLevel() > -1) { - return false; + gGL.getTexUnit(0)->bind(texture, true); + return texture; } } - return true; + return NULL; } -BOOL stop_gloderror() +std::string stripSuffix(std::string name) { - GLuint error = glodGetError(); - - if (error != GLOD_NO_ERROR) + if ((name.find("_LOD") != std::string::npos) || (name.find("_PHYS") != std::string::npos)) { - llwarns << "GLOD error detected, cannot generate LOD: " << std::hex << error << std::dec << llendl; - return TRUE; + return name.substr(0, name.rfind('_')); } + return name; +} - return FALSE; +void FindModel(LLModelLoader::scene& scene, const std::string& name_to_match, LLModel*& baseModelOut, LLMatrix4& matOut) +{ + LLModelLoader::scene::iterator base_iter = scene.begin(); + bool found = false; + while (!found && (base_iter != scene.end())) + { + matOut = base_iter->first; + + LLModelLoader::model_instance_list::iterator base_instance_iter = base_iter->second.begin(); + while (!found && (base_instance_iter != base_iter->second.end())) + { + LLModelInstance& base_instance = *base_instance_iter++; + LLModel* base_model = base_instance.mModel; + + if (base_model && (base_model->mLabel == name_to_match)) + { + baseModelOut = base_model; + return; + } + } + base_iter++; + } } //----------------------------------------------------------------------------- @@ -486,9 +364,16 @@ BOOL LLFloaterModelPreview::postBuild() mUploadBtn = getChild("ok_btn"); mCalculateBtn = getChild("calculate_btn"); + if (LLConvexDecomposition::getInstance() != NULL) + { mCalculateBtn->setClickedCallback(boost::bind(&LLFloaterModelPreview::onClickCalculateBtn, this)); toggleCalculateButton(true); + } + else + { + mCalculateBtn->setEnabled(false); + } return TRUE; } @@ -577,6 +462,23 @@ void LLFloaterModelPreview::loadModel_continued(AIFilePicker* filepicker, S32 lo if (filepicker->hasFilename()) // User did not click Cancel? { filename = filepicker->getFilename(); + + const U32 lod_high = LLModel::LOD_HIGH; + for (S32 lod = 0; lod <= lod_high; ++lod) + { + std::string message = "status_reading_file"; + + mModelPreview->mFMP->childSetText(lod_triangles_name[lod], LLStringExplicit("?")); + mModelPreview->mFMP->childSetText(lod_vertices_name[lod], LLStringExplicit("?")); + LLIconCtrl* icon = mModelPreview->mFMP->getChild(lod_icon_name[lod]); + icon->setVisible(false); + } + } + + if (lod == LLModel::LOD_PHYSICS) + { + // loading physics from file + mModelPreview->mPhysicsSearchLOD = lod; } mModelPreview->loadModel(filename, lod); // Pass an empty filename if the user clicked Cancel. } @@ -598,7 +500,9 @@ void LLFloaterModelPreview::onClickCalculateBtn() mUploadModelUrl.clear(); gMeshRepo.uploadModel(mModelPreview->mUploadData, mModelPreview->mPreviewScale, - childGetValue("upload_textures").asBoolean(), upload_skinweights, upload_joint_positions, mUploadModelUrl, false, + childGetValue("upload_textures").asBoolean(), + upload_skinweights, upload_joint_positions, + mUploadModelUrl, false, getWholeModelFeeObserverHandle()); toggleCalculateButton(false); @@ -697,6 +601,11 @@ void LLFloaterModelPreview::toggleGenerateNormals() { bool enabled = childGetValue("gen_normals").asBoolean(); childSetEnabled("crease_angle", enabled); + if(enabled) { + mModelPreview->generateNormals(); + } else { + mModelPreview->restoreNormals(); + } } //static @@ -712,12 +621,26 @@ void LLFloaterModelPreview::onAutoFillCommit(LLUICtrl* ctrl, void* userdata) { LLFloaterModelPreview* fp = (LLFloaterModelPreview*) userdata; - fp->mModelPreview->genLODs(); + fp->mModelPreview->queryLODs(); } void LLFloaterModelPreview::onLODParamCommit(S32 lod, bool enforce_tri_limit) { mModelPreview->onLODParamCommit(lod, enforce_tri_limit); + + //refresh LoDs that reference this one + for (S32 i = lod - 1; i >= 0; --i) + { + LLComboBox* lod_source_combo = getChild("lod_source_" + lod_name[i]); + if (lod_source_combo->getCurrentIndex() == LLModelPreview::USE_LOD_ABOVE) + { + onLoDSourceCommit(i); + } + else + { + break; + } + } } @@ -728,6 +651,10 @@ void LLFloaterModelPreview::draw() { LLFloater::draw(); + if (!mModelPreview) + { + return; + } mModelPreview->update(); if (!mModelPreview->mLoading) @@ -737,31 +664,39 @@ void LLFloaterModelPreview::draw() childSetTextArg("status", "[STATUS]", getString("status_material_mismatch")); } else - if (mModelPreview->getLoadState() > LLModelLoader::ERROR_PARSING) + if ( mModelPreview->getLoadState() > LLModelLoader::ERROR_MODEL ) { - childSetTextArg("status", "[STATUS]", getString(LLModel::getStatusString(mModelPreview->getLoadState() - LLModelLoader::ERROR_PARSING))); + childSetTextArg("status", "[STATUS]", getString(LLModel::getStatusString(mModelPreview->getLoadState() - LLModelLoader::ERROR_MODEL))); } else - if (mModelPreview->getLoadState() == LLModelLoader::ERROR_PARSING) + if ( mModelPreview->getLoadState() == LLModelLoader::ERROR_PARSING ) { childSetTextArg("status", "[STATUS]", getString("status_parse_error")); toggleCalculateButton(false); } + else + if (mModelPreview->getLoadState() == LLModelLoader::WARNING_BIND_SHAPE_ORIENTATION) + { + childSetTextArg("status", "[STATUS]", getString("status_bind_shape_orientation")); + } else { childSetTextArg("status", "[STATUS]", getString("status_idle")); } } + /* Singu Note: Dummy views and what for? childSetTextArg("prim_cost", "[PRIM_COST]", llformat("%d", mModelPreview->mResourceCost)); childSetTextArg("description_label", "[TEXTURES]", llformat("%d", mModelPreview->mTextureSet.size())); + */ - if (mModelPreview) + if (mModelPreview->lodsReady()) { gGL.color3f(1.f, 1.f, 1.f); gGL.getTexUnit(0)->bind(mModelPreview); + LLView* preview_panel = getChild("preview_panel"); LLRect rect = preview_panel->getRect(); @@ -771,16 +706,16 @@ void LLFloaterModelPreview::draw() mPreviewRect = preview_panel->getRect(); } - gGL.begin(LLRender::QUADS); + gGL.begin(LLRender::TRIANGLE_STRIP); { gGL.texCoord2f(0.f, 1.f); gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mTop - 1); gGL.texCoord2f(0.f, 0.f); gGL.vertex2i(mPreviewRect.mLeft, mPreviewRect.mBottom); - gGL.texCoord2f(1.f, 0.f); - gGL.vertex2i(mPreviewRect.mRight - 1, mPreviewRect.mBottom); gGL.texCoord2f(1.f, 1.f); gGL.vertex2i(mPreviewRect.mRight - 1, mPreviewRect.mTop - 1); + gGL.texCoord2f(1.f, 0.f); + gGL.vertex2i(mPreviewRect.mRight - 1, mPreviewRect.mBottom); } gGL.end(); @@ -887,17 +822,25 @@ BOOL LLFloaterModelPreview::handleScrollWheel(S32 x, S32 y, S32 clicks) } /*virtual*/ -void LLFloaterModelPreview::onOpen(/*const LLSD& key*/) +void LLFloaterModelPreview::onOpen() { + LLModelPreview::sIgnoreLoadedCallback = false; requestAgentUploadPermissions(); } +/*virtual*/ +void LLFloaterModelPreview::onClose(bool app_quitting) +{ + LLModelPreview::sIgnoreLoadedCallback = true; + LLFloater::onClose(app_quitting); +} + //static void LLFloaterModelPreview::onPhysicsParamCommit(LLUICtrl* ctrl, void* data) { if (LLConvexDecomposition::getInstance() == NULL) { - llinfos << "convex decomposition tool is a stub on this platform. cannot get decomp." << llendl; + LL_INFOS() << "convex decomposition tool is a stub on this platform. cannot get decomp." << LL_ENDL; return; } @@ -945,13 +888,13 @@ void LLFloaterModelPreview::onPhysicsStageExecute(LLUICtrl* ctrl, void* data) { if (!sInstance->mCurRequest.empty()) { - llinfos << "Decomposition request still pending." << llendl; + LL_INFOS() << "Decomposition request still pending." << LL_ENDL; return; } if (sInstance->mModelPreview) { - for (S32 i = 0; i < sInstance->mModelPreview->mModel[LLModel::LOD_PHYSICS].size(); ++i) + for (U32 i = 0; i < sInstance->mModelPreview->mModel[LLModel::LOD_PHYSICS].size(); ++i) { LLModel* mdl = sInstance->mModelPreview->mModel[LLModel::LOD_PHYSICS][i]; DecompRequest* request = new DecompRequest(stage, mdl); @@ -996,13 +939,13 @@ void LLFloaterModelPreview::onPhysicsUseLOD(LLUICtrl* ctrl, void* userdata) } else { - llwarns << "no iface" << llendl; + LL_WARNS() << "no iface" << LL_ENDL; return; } if (which_mode <= 0) { - llwarns << "which_mode out of range, " << which_mode << llendl; + LL_WARNS() << "which_mode out of range, " << which_mode << LL_ENDL; } S32 file_mode = iface->getItemCount() - 1; @@ -1087,8 +1030,8 @@ void LLFloaterModelPreview::initDecompControls() // protected against stub by stage_count being 0 for stub above LLConvexDecomposition::getInstance()->registerCallback(j, LLPhysicsDecomp::llcdCallback); - //llinfos << "Physics decomp stage " << stage[j].mName << " (" << j << ") parameters:" << llendl; - //llinfos << "------------------------------------" << llendl; + //LL_INFOS() << "Physics decomp stage " << stage[j].mName << " (" << j << ") parameters:" << LL_ENDL; + //LL_INFOS() << "------------------------------------" << LL_ENDL; for (S32 i = 0; i < param_count; ++i) { @@ -1102,12 +1045,12 @@ void LLFloaterModelPreview::initDecompControls() std::string type = "unknown"; - llinfos << name << " - " << description << llendl; + LL_INFOS() << name << " - " << description << LL_ENDL; if (param[i].mType == LLCDParam::LLCD_FLOAT) { mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mFloat); - //llinfos << "Type: float, Default: " << param[i].mDefault.mFloat << llendl; + //LL_INFOS() << "Type: float, Default: " << param[i].mDefault.mFloat << LL_ENDL; LLUICtrl* ctrl = getChild(name); if (LLSliderCtrl* slider = dynamic_cast(ctrl)) @@ -1155,7 +1098,7 @@ void LLFloaterModelPreview::initDecompControls() else if (param[i].mType == LLCDParam::LLCD_INTEGER) { mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mIntOrEnumValue); - //llinfos << "Type: integer, Default: " << param[i].mDefault.mIntOrEnumValue << llendl; + //LL_INFOS() << "Type: integer, Default: " << param[i].mDefault.mIntOrEnumValue << LL_ENDL; LLUICtrl* ctrl = getChild(name); if (LLSliderCtrl* slider = dynamic_cast(ctrl)) @@ -1180,9 +1123,9 @@ void LLFloaterModelPreview::initDecompControls() else if (param[i].mType == LLCDParam::LLCD_BOOLEAN) { mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mBool); - //llinfos << "Type: boolean, Default: " << (param[i].mDefault.mBool ? "True" : "False") << llendl; + //LL_INFOS() << "Type: boolean, Default: " << (param[i].mDefault.mBool ? "True" : "False") << LL_ENDL; - LLCheckBoxCtrl* check_box = getChild(name); + LLCheckBoxCtrl* check_box = findChild(name); if (check_box) { check_box->setValue(param[i].mDefault.mBool); @@ -1192,16 +1135,16 @@ void LLFloaterModelPreview::initDecompControls() else if (param[i].mType == LLCDParam::LLCD_ENUM) { mDecompParams[param[i].mName] = LLSD(param[i].mDefault.mIntOrEnumValue); - //llinfos << "Type: enum, Default: " << param[i].mDefault.mIntOrEnumValue << llendl; + //LL_INFOS() << "Type: enum, Default: " << param[i].mDefault.mIntOrEnumValue << LL_ENDL; { //plug into combo box - //llinfos << "Accepted values: " << llendl; + //LL_INFOS() << "Accepted values: " << LL_ENDL; LLComboBox* combo_box = getChild(name); for (S32 k = 0; k < param[i].mDetails.mEnumValues.mNumEnums; ++k) { - //llinfos << param[i].mDetails.mEnumValues.mEnumsArray[k].mValue - // << " - " << param[i].mDetails.mEnumValues.mEnumsArray[k].mName << llendl; + //LL_INFOS() << param[i].mDetails.mEnumValues.mEnumsArray[k].mValue + // << " - " << param[i].mDetails.mEnumValues.mEnumsArray[k].mName << LL_ENDL; std::string name(param[i].mDetails.mEnumValues.mEnumsArray[k].mName); std::string localized_name; @@ -1214,9 +1157,9 @@ void LLFloaterModelPreview::initDecompControls() combo_box->setCommitCallback(onPhysicsParamCommit, (void*) ¶m[i]); } - //llinfos << "----" << llendl; + //LL_INFOS() << "----" << LL_ENDL; } - //llinfos << "-----------------------------" << llendl; + //LL_INFOS() << "-----------------------------" << LL_ENDL; } } @@ -1247,1985 +1190,164 @@ void LLFloaterModelPreview::onMouseCaptureLostModelPreview(LLMouseHandler* handl } //----------------------------------------------------------------------------- -// LLModelLoader +// LLModelPreview //----------------------------------------------------------------------------- -LLModelLoader::LLModelLoader( std::string filename, S32 lod, LLModelPreview* preview, JointTransformMap& jointMap, - std::deque& jointsFromNodes) -: mJointList( jointMap ) -, mJointsFromNode( jointsFromNodes ) -, LLThread("Model Loader"), mFilename(filename), mLod(lod), mPreview(preview), mFirstTransform(TRUE), mNumOfFetchingTextures(0) -{ - mJointMap["mPelvis"] = "mPelvis"; - mJointMap["mTorso"] = "mTorso"; - mJointMap["mChest"] = "mChest"; - mJointMap["mNeck"] = "mNeck"; - mJointMap["mHead"] = "mHead"; - mJointMap["mSkull"] = "mSkull"; - mJointMap["mEyeRight"] = "mEyeRight"; - mJointMap["mEyeLeft"] = "mEyeLeft"; - mJointMap["mCollarLeft"] = "mCollarLeft"; - mJointMap["mShoulderLeft"] = "mShoulderLeft"; - mJointMap["mElbowLeft"] = "mElbowLeft"; - mJointMap["mWristLeft"] = "mWristLeft"; - mJointMap["mCollarRight"] = "mCollarRight"; - mJointMap["mShoulderRight"] = "mShoulderRight"; - mJointMap["mElbowRight"] = "mElbowRight"; - mJointMap["mWristRight"] = "mWristRight"; - mJointMap["mHipRight"] = "mHipRight"; - mJointMap["mKneeRight"] = "mKneeRight"; - mJointMap["mAnkleRight"] = "mAnkleRight"; - mJointMap["mFootRight"] = "mFootRight"; - mJointMap["mToeRight"] = "mToeRight"; - mJointMap["mHipLeft"] = "mHipLeft"; - mJointMap["mKneeLeft"] = "mKneeLeft"; - mJointMap["mAnkleLeft"] = "mAnkleLeft"; - mJointMap["mFootLeft"] = "mFootLeft"; - mJointMap["mToeLeft"] = "mToeLeft"; - - mJointMap["avatar_mPelvis"] = "mPelvis"; - mJointMap["avatar_mTorso"] = "mTorso"; - mJointMap["avatar_mChest"] = "mChest"; - mJointMap["avatar_mNeck"] = "mNeck"; - mJointMap["avatar_mHead"] = "mHead"; - mJointMap["avatar_mSkull"] = "mSkull"; - mJointMap["avatar_mEyeRight"] = "mEyeRight"; - mJointMap["avatar_mEyeLeft"] = "mEyeLeft"; - mJointMap["avatar_mCollarLeft"] = "mCollarLeft"; - mJointMap["avatar_mShoulderLeft"] = "mShoulderLeft"; - mJointMap["avatar_mElbowLeft"] = "mElbowLeft"; - mJointMap["avatar_mWristLeft"] = "mWristLeft"; - mJointMap["avatar_mCollarRight"] = "mCollarRight"; - mJointMap["avatar_mShoulderRight"] = "mShoulderRight"; - mJointMap["avatar_mElbowRight"] = "mElbowRight"; - mJointMap["avatar_mWristRight"] = "mWristRight"; - mJointMap["avatar_mHipRight"] = "mHipRight"; - mJointMap["avatar_mKneeRight"] = "mKneeRight"; - mJointMap["avatar_mAnkleRight"] = "mAnkleRight"; - mJointMap["avatar_mFootRight"] = "mFootRight"; - mJointMap["avatar_mToeRight"] = "mToeRight"; - mJointMap["avatar_mHipLeft"] = "mHipLeft"; - mJointMap["avatar_mKneeLeft"] = "mKneeLeft"; - mJointMap["avatar_mAnkleLeft"] = "mAnkleLeft"; - mJointMap["avatar_mFootLeft"] = "mFootLeft"; - mJointMap["avatar_mToeLeft"] = "mToeLeft"; - - mJointMap["hip"] = "mPelvis"; - mJointMap["abdomen"] = "mTorso"; - mJointMap["chest"] = "mChest"; - mJointMap["neck"] = "mNeck"; - mJointMap["head"] = "mHead"; - mJointMap["figureHair"] = "mSkull"; - mJointMap["lCollar"] = "mCollarLeft"; - mJointMap["lShldr"] = "mShoulderLeft"; - mJointMap["lForeArm"] = "mElbowLeft"; - mJointMap["lHand"] = "mWristLeft"; - mJointMap["rCollar"] = "mCollarRight"; - mJointMap["rShldr"] = "mShoulderRight"; - mJointMap["rForeArm"] = "mElbowRight"; - mJointMap["rHand"] = "mWristRight"; - mJointMap["rThigh"] = "mHipRight"; - mJointMap["rShin"] = "mKneeRight"; - mJointMap["rFoot"] = "mFootRight"; - mJointMap["lThigh"] = "mHipLeft"; - mJointMap["lShin"] = "mKneeLeft"; - mJointMap["lFoot"] = "mFootLeft"; - - if (mPreview) - { - //only try to load from slm if viewer is configured to do so and this is the - //initial model load (not an LoD or physics shape) - mTrySLM = gSavedSettings.getBOOL("MeshImportUseSLM") && mPreview->mUploadData.empty(); - mPreview->setLoadState(STARTING); - } - else - { - mTrySLM = false; - } - - assert_main_thread(); - sActiveLoaderList.push_back(this); -} -LLModelLoader::~LLModelLoader() -{ - assert_main_thread(); - sActiveLoaderList.remove(this); -} - -void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4a& max, BOOL& first_transform) +LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) +: LLViewerDynamicTexture(width, height, 3, ORDER_MIDDLE, FALSE), LLMutex() +, mLodsQuery() +, mLodsWithParsingError() +, mPelvisZOffset( 0.0f ) +, mLegacyRigValid( false ) +, mRigValidJointUpload( false ) +, mPhysicsSearchLOD( LLModel::LOD_PHYSICS ) +, mResetJoints( false ) +, mModelNoErrors( true ) +, mLastJointUpdate( false ) { - LLVector4a box[] = - { - LLVector4a(-1, 1,-1), - LLVector4a(-1, 1, 1), - LLVector4a(-1,-1,-1), - LLVector4a(-1,-1, 1), - LLVector4a( 1, 1,-1), - LLVector4a( 1, 1, 1), - LLVector4a( 1,-1,-1), - LLVector4a( 1,-1, 1), - }; + mNeedsUpdate = TRUE; + mCameraDistance = 0.f; + mCameraYaw = 0.f; + mCameraPitch = 0.f; + mCameraZoom = 1.f; + mTextureName = 0; + mPreviewLOD = 0; + mModelLoader = NULL; + mMaxTriangleLimit = 0; + mDirty = false; + mGenLOD = false; + mLoading = false; + mLoadState = LLModelLoader::STARTING; + mGroup = 0; + mLODFrozen = false; + mBuildShareTolerance = 0.f; + mBuildQueueMode = GLOD_QUEUE_GREEDY; + mBuildBorderMode = GLOD_BORDER_UNLOCK; + mBuildOperator = GLOD_OPERATOR_EDGE_COLLAPSE; - for (S32 j = 0; j < model->getNumVolumeFaces(); ++j) + for (U32 i = 0; i < LLModel::NUM_LODS; ++i) { - const LLVolumeFace& face = model->getVolumeFace(j); - - LLVector4a center; - center.setAdd(face.mExtents[0], face.mExtents[1]); - center.mul(0.5f); - LLVector4a size; - size.setSub(face.mExtents[1],face.mExtents[0]); - size.mul(0.5f); - - for (U32 i = 0; i < 8; i++) - { - LLVector4a t; - t.setMul(size, box[i]); - t.add(center); - - LLVector4a v; - - mat.affineTransform(t, v); - - if (first_transform) - { - first_transform = FALSE; - min = max = v; - } - else - { - update_min_max(min, max, v); - } - } + mRequestedTriangleCount[i] = 0; + mRequestedCreaseAngle[i] = -1.f; + mRequestedLoDMode[i] = 0; + mRequestedErrorThreshold[i] = 0.f; + mRequestedBuildOperator[i] = 0; + mRequestedQueueMode[i] = 0; + mRequestedBorderMode[i] = 0; + mRequestedShareTolerance[i] = 0.f; } -} -void stretch_extents(LLModel* model, LLMatrix4& mat, LLVector3& min, LLVector3& max, BOOL& first_transform) -{ - LLVector4a mina, maxa; - LLMatrix4a mata; + mViewOption["show_textures"] = false; - mata.loadu(mat); - mina.load3(min.mV); - maxa.load3(max.mV); + mFMP = fmp; - stretch_extents(model, mata, mina, maxa, first_transform); + mHasPivot = false; + mModelPivot = LLVector3(0.0f, 0.0f, 0.0f); - min.set(mina.getF32ptr()); - max.set(maxa.getF32ptr()); -} + glodInit(); -void LLModelLoader::run() -{ - doLoadModel(); - doOnIdleOneTime(boost::bind(&LLModelLoader::loadModelCallback,this)); + createPreviewAvatar(); } -bool LLModelLoader::doLoadModel() +LLModelPreview::~LLModelPreview() { - //first, look for a .slm file of the same name that was modified later - //than the .dae - - if (mTrySLM) - { - std::string filename = mFilename; - - std::string::size_type i = filename.rfind("."); - if (i != std::string::npos) - { - filename.replace(i, filename.size() - 1, ".slm"); - llstat slm_status; - if (LLFile::stat(filename, &slm_status) == 0) - { //slm file exists - llstat dae_status; - if (LLFile::stat(mFilename, &dae_status) != 0 || - dae_status.st_mtime < slm_status.st_mtime) - { - if (loadFromSLM(filename)) - { //slm successfully loaded, if this fails, fall through and - //try loading from dae - - mLod = -1; //successfully loading from an slm implicitly sets all - //LoDs - return true; - } - } - } - } - } - - //no suitable slm exists, load from the .dae file - DAE dae; - domCOLLADA* dom = dae.open(mFilename); - - if (!dom) + // glod apparently has internal mem alignment issues that are angering + // the heap-check code in windows, these should be hunted down in that + // TP code, if possible + // + // kernel32.dll!HeapFree() + 0x14 bytes + // msvcr100.dll!free(void * pBlock) Line 51 C + // glod.dll!glodGetGroupParameteriv() + 0x119 bytes + // glod.dll!glodShutdown() + 0x77 bytes + // + //glodShutdown(); + if(mModelLoader) { - llinfos<<" Error with dae - traditionally indicates a corrupt file."<shutdown(); } - //Dom version - daeString domVersion = dae.getDomVersion(); - std::string sldom(domVersion); - llinfos<<"Collada Importer Version: "<getVersion(); - //0=1.4 - //1=1.4.1 - //2=Currently unsupported, however may work - if (docVersion > 1) - { - docVersion = VERSIONTYPE_COUNT; - } - llinfos<<"Dae version "<getElementCount(NULL, COLLADA_TYPE_MESH); +} - daeDocument* doc = dae.getDoc(mFilename); - if (!doc) - { - llwarns << "can't find internal doc" << llendl; - return false; - } +U32 LLModelPreview::calcResourceCost() +{ + assert_main_thread(); - daeElement* root = doc->getDomRoot(); - if (!root) - { - llwarns << "document has no root" << llendl; - return false; - } + rebuildUploadData(); - //Verify some basic properties of the dae - //1. Basic validity check on controller - U32 controllerCount = (int) db->getElementCount(NULL, "controller"); - bool result = false; - for (int i = 0; i < controllerCount; ++i) + //Upload skin is selected BUT check to see if the joints coming in from the asset were malformed. + if (mFMP && mFMP->childGetValue("upload_skin").asBoolean()) { - domController* pController = NULL; - db->getElement((daeElement**) &pController, i , NULL, "controller"); - result = mPreview->verifyController(pController); - if (!result) + bool uploadingJointPositions = mFMP->childGetValue("upload_joints").asBoolean(); + if (uploadingJointPositions && !isRigValidForJointPositionUpload()) { - setLoadState(ERROR_PARSING); - return true; + mFMP->childDisable("ok_btn"); } } - //get unit scale - mTransform.setIdentity(); - - domAsset::domUnit* unit = daeSafeCast(root->getDescendant(daeElement::matchType(domAsset::domUnit::ID()))); - - if (unit) - { - F32 meter = unit->getMeter(); - mTransform.mMatrix[0][0] = meter; - mTransform.mMatrix[1][1] = meter; - mTransform.mMatrix[2][2] = meter; - } - - //get up axis rotation - LLMatrix4 rotation; + std::set accounted; + U32 num_points = 0; + U32 num_hulls = 0; - domUpAxisType up = UPAXISTYPE_Y_UP; // default is Y_UP - domAsset::domUp_axis* up_axis = - daeSafeCast(root->getDescendant(daeElement::matchType(domAsset::domUp_axis::ID()))); + F32 debug_scale = mFMP ? mFMP->childGetValue("import_scale").asReal() : 1.f; + mPelvisZOffset = mFMP ? mFMP->childGetValue("pelvis_offset").asReal() : 3.0f; - if (up_axis) + if (mFMP && mFMP->childGetValue("upload_joints").asBoolean()) { - up = up_axis->getValue(); + // FIXME if preview avatar ever gets reused, this fake mesh ID stuff will fail. + // see also call to addAttachmentPosOverride. + LLUUID fake_mesh_id; + fake_mesh_id.generate(); + getPreviewAvatar()->addPelvisFixup( mPelvisZOffset, fake_mesh_id ); } - if (up == UPAXISTYPE_X_UP) - { - rotation.initRotation(0.0f, 90.0f * DEG_TO_RAD, 0.0f); - } - else if (up == UPAXISTYPE_Y_UP) + F32 streaming_cost = 0.f; + F32 physics_cost = 0.f; + for (U32 i = 0; i < mUploadData.size(); ++i) { - rotation.initRotation(90.0f * DEG_TO_RAD, 0.0f, 0.0f); - } - - rotation *= mTransform; - mTransform = rotation; - - for (daeInt idx = 0; idx < count; ++idx) - { //build map of domEntities to LLModel - domMesh* mesh = NULL; - db->getElement((daeElement**) &mesh, idx, NULL, COLLADA_TYPE_MESH); + LLModelInstance& instance = mUploadData[i]; - if (mesh) + if (accounted.find(instance.mModel) == accounted.end()) { - LLPointer model = LLModel::loadModelFromDomMesh(mesh); + accounted.insert(instance.mModel); + + LLModel::Decomposition& decomp = + instance.mLOD[LLModel::LOD_PHYSICS] ? + instance.mLOD[LLModel::LOD_PHYSICS]->mPhysics : + instance.mModel->mPhysics; - if (model->getStatus() != LLModel::NO_ERRORS) + //update instance skin info for each lods pelvisZoffset + for (int j = 0; j < LLModel::NUM_LODS; ++j) { - setLoadState(ERROR_PARSING + model->getStatus()); - return false; //abort + if (instance.mLOD[j]) + { + instance.mLOD[j]->mSkinInfo.mPelvisOffset = mPelvisZOffset; + } } - if (model.notNull() && validate_model(model)) + std::stringstream ostr; + LLSD ret = LLModel::writeModel(ostr, + instance.mLOD[4], + instance.mLOD[3], + instance.mLOD[2], + instance.mLOD[1], + instance.mLOD[0], + decomp, + mFMP->childGetValue("upload_skin").asBoolean(), + mFMP->childGetValue("upload_joints").asBoolean(), + false, + TRUE, + FALSE, + instance.mModel->mSubmodelID); + + num_hulls += decomp.mHull.size(); + for (U32 i = 0; i < decomp.mHull.size(); ++i) { - mModelList.push_back(model); - mModel[mesh] = model; + num_points += decomp.mHull[i].size(); } - } - } - count = db->getElementCount(NULL, COLLADA_TYPE_SKIN); - for (daeInt idx = 0; idx < count; ++idx) - { //add skinned meshes as instances - domSkin* skin = NULL; - db->getElement((daeElement**) &skin, idx, NULL, COLLADA_TYPE_SKIN); + //calculate streaming cost + LLMatrix4 transformation = instance.mTransform; - if (skin) - { - domGeometry* geom = daeSafeCast(skin->getSource().getElement()); - - if (geom) - { - domMesh* mesh = geom->getMesh(); - if (mesh) - { - LLModel* model = mModel[mesh]; - if (model) - { - LLVector3 mesh_scale_vector; - LLVector3 mesh_translation_vector; - model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); - - LLMatrix4 normalized_transformation; - normalized_transformation.setTranslation(mesh_translation_vector); - - LLMatrix4 mesh_scale; - mesh_scale.initScale(mesh_scale_vector); - mesh_scale *= normalized_transformation; - normalized_transformation = mesh_scale; - - glh::matrix4f inv_mat((F32*) normalized_transformation.mMatrix); - inv_mat = inv_mat.inverse(); - LLMatrix4 inverse_normalized_transformation(inv_mat.m); - - domSkin::domBind_shape_matrix* bind_mat = skin->getBind_shape_matrix(); - - if (bind_mat) - { //get bind shape matrix - domFloat4x4& dom_value = bind_mat->getValue(); - - LLMeshSkinInfo& skin_info = model->mSkinInfo; - - for (int i = 0; i < 4; i++) - { - for (int j = 0; j < 4; j++) - { - skin_info.mBindShapeMatrix.mMatrix[i][j] = dom_value[i + j*4]; - } - } - - LLMatrix4 trans = normalized_transformation; - trans *= skin_info.mBindShapeMatrix; - skin_info.mBindShapeMatrix = trans; - } - - //Some collada setup for accessing the skeleton - daeElement* pElement = 0; - dae.getDatabase()->getElement(&pElement, 0, 0, "skeleton"); - - //Try to get at the skeletal instance controller - domInstance_controller::domSkeleton* pSkeleton = daeSafeCast(pElement); - bool missingSkeletonOrScene = false; - - //If no skeleton, do a breadth-first search to get at specific joints - bool rootNode = false; - - //Need to test for a skeleton that does not have a root node - //This occurs when your instance controller does not have an associated scene - if (pSkeleton) - { - daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement(); - if (pSkeletonRootNode) - { - rootNode = true; - } - - } - if (!pSkeleton || !rootNode) - { - daeElement* pScene = root->getDescendant("visual_scene"); - if (!pScene) - { - llwarns<<"No visual scene - unable to parse bone offsets "< > children = pScene->getChildren(); - S32 childCount = children.getCount(); - - //Process any children that are joints - //Not all children are joints, some code be ambient lights, cameras, geometry etc.. - for (S32 i = 0; i < childCount; ++i) - { - domNode* pNode = daeSafeCast(children[i]); - if (isNodeAJoint(pNode)) - { - processJointNode(pNode, mJointList); - } - } - } - } - else - //Has Skeleton - { - //Get the root node of the skeleton - daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement(); - if (pSkeletonRootNode) - { - //Once we have the root node - start acccessing it's joint components - const int jointCnt = mJointMap.size(); - std::map :: const_iterator jointIt = mJointMap.begin(); - - //Loop over all the possible joints within the .dae - using the allowed joint list in the ctor. - for (int i = 0; i < jointCnt; ++i, ++jointIt) - { - //Build a joint for the resolver to work with - char str[64]={0}; - sprintf(str,"./%s",(*jointIt).first.c_str()); - //llwarns<<"Joint "<< str <(resolver.getElement()); - if (pJoint) - { - //Pull out the translate id and store it in the jointTranslations map - daeSIDResolver jointResolverA(pJoint, "./translate"); - domTranslate* pTranslateA = daeSafeCast(jointResolverA.getElement()); - daeSIDResolver jointResolverB(pJoint, "./location"); - domTranslate* pTranslateB = daeSafeCast(jointResolverB.getElement()); - - LLMatrix4 workingTransform; - - //Translation via SID - if (pTranslateA) - { - extractTranslation(pTranslateA, workingTransform); - } - else - if (pTranslateB) - { - extractTranslation(pTranslateB, workingTransform); - } - else - { - //Translation via child from element - daeElement* pTranslateElement = getChildFromElement(pJoint, "translate"); - if (pTranslateElement && pTranslateElement->typeID() != domTranslate::ID()) - { - llwarns<< "The found element is not a translate node" <getJoints(); - - domInputLocal_Array& joint_input = joints->getInput_array(); - - for (size_t i = 0; i < joint_input.getCount(); ++i) - { - domInputLocal* input = joint_input.get(i); - xsNMTOKEN semantic = input->getSemantic(); - - if (strcmp(semantic, COMMON_PROFILE_INPUT_JOINT) == 0) - { //found joint source, fill model->mJointMap and model->mSkinInfo.mJointNames - daeElement* elem = input->getSource().getElement(); - - domSource* source = daeSafeCast(elem); - if (source) - { - domName_array* names_source = source->getName_array(); - - if (names_source) - { - domListOfNames &names = names_source->getValue(); - - for (size_t j = 0; j < names.getCount(); ++j) - { - std::string name(names.get(j)); - if (mJointMap.find(name) != mJointMap.end()) - { - name = mJointMap[name]; - } - model->mSkinInfo.mJointNames.push_back(name); - model->mSkinInfo.mJointMap[name] = j; - } - } - else - { - domIDREF_array* names_source = source->getIDREF_array(); - if (names_source) - { - xsIDREFS& names = names_source->getValue(); - - for (size_t j = 0; j < names.getCount(); ++j) - { - std::string name(names.get(j).getID()); - if (mJointMap.find(name) != mJointMap.end()) - { - name = mJointMap[name]; - } - model->mSkinInfo.mJointNames.push_back(name); - model->mSkinInfo.mJointMap[name] = j; - } - } - } - } - } - else if (strcmp(semantic, COMMON_PROFILE_INPUT_INV_BIND_MATRIX) == 0) - { //found inv_bind_matrix array, fill model->mInvBindMatrix - domSource* source = daeSafeCast(input->getSource().getElement()); - if (source) - { - domFloat_array* t = source->getFloat_array(); - if (t) - { - domListOfFloats& transform = t->getValue(); - S32 count = transform.getCount()/16; - - for (S32 k = 0; k < count; ++k) - { - LLMatrix4 mat; - - for (int i = 0; i < 4; i++) - { - for (int j = 0; j < 4; j++) - { - mat.mMatrix[i][j] = transform[k*16 + i + j*4]; - } - } - - model->mSkinInfo.mInvBindMatrix.push_back(mat); - } - } - } - } - } - - //Now that we've parsed the joint array, let's determine if we have a full rig - //(which means we have all the joint sthat are required for an avatar versus - //a skinned asset attached to a node in a file that contains an entire skeleton, - //but does not use the skeleton). - buildJointToNodeMappingFromScene(root); - mPreview->critiqueRigForUploadApplicability(model->mSkinInfo.mJointNames); - - if (!missingSkeletonOrScene) - { - //Set the joint translations on the avatar - if it's a full mapping - //The joints are reset in the dtor - if (mPreview->getRigWithSceneParity()) - { - std::map :: const_iterator masterJointIt = mJointMap.begin(); - std::map :: const_iterator masterJointItEnd = mJointMap.end(); - for ( ;masterJointIt!=masterJointItEnd;++masterJointIt) - { - std::string lookingForJoint = (*masterJointIt).first.c_str(); - - if (mJointList.find(lookingForJoint) != mJointList.end()) - { - //llinfos<<"joint "<getPreviewAvatar()->getJoint(lookingForJoint); - if (pJoint) - { - pJoint->storeCurrentXform(jointTransform.getTranslation()); - } - else - { - //Most likely an error in the asset. - llwarns<<"Tried to apply joint position from .dae, but it did not exist in the avatar rig." << llendl; - } - } - } - } - } //missingSkeletonOrScene - - //We need to construct the alternate bind matrix (which contains the new joint positions) - //in the same order as they were stored in the joint buffer. The joints associated - //with the skeleton are not stored in the same order as they are in the exported joint buffer. - //This remaps the skeletal joints to be in the same order as the joints stored in the model. - std::vector :: const_iterator jointIt = model->mSkinInfo.mJointNames.begin(); - const int jointCnt = model->mSkinInfo.mJointNames.size(); - for (int i = 0; i < jointCnt; ++i, ++jointIt) - { - std::string lookingForJoint = (*jointIt).c_str(); - //Look for the joint xform that we extracted from the skeleton, using the jointIt as the key - //and store it in the alternate bind matrix - if (mJointList.find(lookingForJoint) != mJointList.end()) - { - LLMatrix4 jointTransform = mJointList[lookingForJoint]; - LLMatrix4 newInverse = model->mSkinInfo.mInvBindMatrix[i]; - newInverse.setTranslation(mJointList[lookingForJoint].getTranslation()); - model->mSkinInfo.mAlternateBindMatrix.push_back(newInverse); - } - else - { - llwarns<<"Possibly misnamed/missing joint [" <getVertices(); - if (verts) - { - domInputLocal_Array& inputs = verts->getInput_array(); - for (size_t i = 0; i < inputs.getCount() && model->mPosition.empty(); ++i) - { - if (strcmp(inputs[i]->getSemantic(), COMMON_PROFILE_INPUT_POSITION) == 0) - { - domSource* pos_source = daeSafeCast(inputs[i]->getSource().getElement()); - if (pos_source) - { - domFloat_array* pos_array = pos_source->getFloat_array(); - if (pos_array) - { - domListOfFloats& pos = pos_array->getValue(); - - for (size_t j = 0; j < pos.getCount(); j += 3) - { - if (pos.getCount() <= j+2) - { - llerrs << "Invalid position array size." << llendl; - } - - LLVector3 v(pos[j], pos[j + 1], pos[j+2]); - - //transform from COLLADA space to volume space - v = v * inverse_normalized_transformation; - - model->mPosition.push_back(v); - } - } - } - } - } - } - - //grab skin weights array - domSkin::domVertex_weights* weights = skin->getVertex_weights(); - if (weights) - { - domInputLocalOffset_Array& inputs = weights->getInput_array(); - domFloat_array* vertex_weights = NULL; - for (size_t i = 0; i < inputs.getCount(); ++i) - { - if (strcmp(inputs[i]->getSemantic(), COMMON_PROFILE_INPUT_WEIGHT) == 0) - { - domSource* weight_source = daeSafeCast(inputs[i]->getSource().getElement()); - if (weight_source) - { - vertex_weights = weight_source->getFloat_array(); - } - } - } - - if (vertex_weights) - { - domListOfFloats& w = vertex_weights->getValue(); - domListOfUInts& vcount = weights->getVcount()->getValue(); - domListOfInts& v = weights->getV()->getValue(); - - U32 c_idx = 0; - for (size_t vc_idx = 0; vc_idx < vcount.getCount(); ++vc_idx) - { //for each vertex - daeUInt count = vcount[vc_idx]; - - //create list of weights that influence this vertex - LLModel::weight_list weight_list; - - for (daeUInt i = 0; i < count; ++i) - { //for each weight - daeInt joint_idx = v[c_idx++]; - daeInt weight_idx = v[c_idx++]; - - if (joint_idx == -1) - { - //ignore bindings to bind_shape_matrix - continue; - } - - F32 weight_value = w[weight_idx]; - - weight_list.push_back(LLModel::JointWeight(joint_idx, weight_value)); - } - - //sort by joint weight - std::sort(weight_list.begin(), weight_list.end(), LLModel::CompareWeightGreater()); - - std::vector wght; - - F32 total = 0.f; - - for (U32 i = 0; i < llmin((U32) 4, (U32) weight_list.size()); ++i) - { //take up to 4 most significant weights - if (weight_list[i].mWeight > 0.f) - { - wght.push_back(weight_list[i]); - total += weight_list[i].mWeight; - } - } - - F32 scale = 1.f/total; - if (scale != 1.f) - { //normalize weights - for (U32 i = 0; i < wght.size(); ++i) - { - wght[i].mWeight *= scale; - } - } - - model->mSkinWeights[model->mPosition[vc_idx]] = wght; - } - - //add instance to scene for this model - - LLMatrix4 transformation = mTransform; - // adjust the transformation to compensate for mesh normalization - - LLMatrix4 mesh_translation; - mesh_translation.setTranslation(mesh_translation_vector); - mesh_translation *= transformation; - transformation = mesh_translation; - - LLMatrix4 mesh_scale; - mesh_scale.initScale(mesh_scale_vector); - mesh_scale *= transformation; - transformation = mesh_scale; - - std::map materials; - for (U32 i = 0; i < model->mMaterialList.size(); ++i) - { - materials[model->mMaterialList[i]] = LLImportMaterial(); - } - mScene[transformation].push_back(LLModelInstance(model, model->mLabel, transformation, materials)); - stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform); - } - } - } - } - } - } - } - - daeElement* scene = root->getDescendant("visual_scene"); - - if (!scene) - { - llwarns << "document has no visual_scene" << llendl; - setLoadState(ERROR_PARSING); - return true; - } - - setLoadState(DONE); - - bool badElement = false; - - processElement(scene, badElement); - - if (badElement) - { - setLoadState(ERROR_PARSING); - } - - return true; -} - -void LLModelLoader::setLoadState(U32 state) -{ - if (mPreview) - { - mPreview->setLoadState(state); - } -} - -bool LLModelLoader::loadFromSLM(const std::string& filename) -{ - //only need to populate mScene with data from slm - llstat stat; - - if (LLFile::stat(filename, &stat)) - { //file does not exist - return false; - } - - S32 file_size = (S32) stat.st_size; - - llifstream ifstream(filename, std::ifstream::in | std::ifstream::binary); - LLSD data; - LLSDSerialize::fromBinary(data, ifstream, file_size); - ifstream.close(); - - //build model list for each LoD - model_list model[LLModel::NUM_LODS]; - - if (data["version"].asInteger() != SLM_SUPPORTED_VERSION) - { //unsupported version - return false; - } - - LLSD& mesh = data["mesh"]; - - LLVolumeParams volume_params; - volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); - - for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod) - { - for (U32 i = 0; i < mesh.size(); ++i) - { - std::stringstream str(mesh[i].asString()); - LLPointer loaded_model = new LLModel(volume_params, (F32) lod); - if (loaded_model->loadModel(str)) - { - loaded_model->mLocalID = i; - model[lod].push_back(loaded_model); - - if (lod == LLModel::LOD_HIGH && !loaded_model->mSkinInfo.mJointNames.empty()) - { - //check to see if rig is valid - mPreview->critiqueRigForUploadApplicability(loaded_model->mSkinInfo.mJointNames); - } - } - } - } - - if (model[LLModel::LOD_HIGH].empty()) - { //failed to load high lod - return false; - } - - // Set name. - std::string name = data["name"]; - if (!name.empty()) - { - model[LLModel::LOD_HIGH][0]->mLabel = name; - } - - //load instance list - model_instance_list instance_list; - - LLSD& instance = data["instance"]; - - for (U32 i = 0; i < instance.size(); ++i) - { - //deserialize instance list - instance_list.push_back(LLModelInstance(instance[i])); - - //match up model instance pointers - S32 idx = instance_list[i].mLocalMeshID; - - for (U32 lod = 0; lod < LLModel::NUM_LODS; ++lod) - { - if (!model[lod].empty()) - { - instance_list[i].mLOD[lod] = model[lod][idx]; - } - } - - instance_list[i].mModel = model[LLModel::LOD_HIGH][idx]; - } - - //convert instance_list to mScene - mFirstTransform = TRUE; - for (U32 i = 0; i < instance_list.size(); ++i) - { - LLModelInstance& cur_instance = instance_list[i]; - mScene[cur_instance.mTransform].push_back(cur_instance); - stretch_extents(cur_instance.mModel, cur_instance.mTransform, mExtents[0], mExtents[1], mFirstTransform); - } - - setLoadState(DONE); - - return true; -} - -//static -bool LLModelLoader::isAlive(LLModelLoader* loader) -{ - if (!loader) - { - return false; - } - - std::list::iterator iter = sActiveLoaderList.begin(); - for ( ; iter != sActiveLoaderList.end() && (*iter) != loader; ++iter); - - return *iter == loader; -} - -void LLModelLoader::loadModelCallback() -{ - assert_main_thread(); - - if (mPreview) - { - mPreview->loadModelCallback(mLod); - } - - while (!isStopped()) - { //wait until this thread is stopped before deleting self - apr_sleep(100); - } - - //double check if "this" is valid before deleting it, in case it is aborted during running. - if (!isAlive(this)) - { - return; - } - - //cleanup model loader - if (mPreview) - { - mPreview->mModelLoader = NULL; - } - - delete this; -} - -//----------------------------------------------------------------------------- -// buildJointToNodeMappingFromScene() -//----------------------------------------------------------------------------- -void LLModelLoader::buildJointToNodeMappingFromScene(daeElement* pRoot) -{ - daeElement* pScene = pRoot->getDescendant("visual_scene"); - if (pScene) - { - daeTArray< daeSmartRef > children = pScene->getChildren(); - S32 childCount = children.getCount(); - for (S32 i = 0; i < childCount; ++i) - { - domNode* pNode = daeSafeCast(children[i]); - processJointToNodeMapping(pNode); - } - } -} - -//----------------------------------------------------------------------------- -// processJointToNodeMapping() -//----------------------------------------------------------------------------- -void LLModelLoader::processJointToNodeMapping(domNode* pNode) -{ - if (isNodeAJoint(pNode)) - { - //1.Store the parent - std::string nodeName = pNode->getName(); - if (!nodeName.empty()) - { - mJointsFromNode.push_front(pNode->getName()); - } - //2. Handle the kiddo's - processChildJoints(pNode); - } - else - { - //Determine if the're any children wrt to this failed node. - //This occurs when an armature is exported and ends up being what essentially amounts to - //as the root for the visual_scene - if (pNode) - { - processChildJoints(pNode); - } - else - { - llinfos<<"Node is NULL"< > childOfChild = pParentNode->getChildren(); - S32 childOfChildCount = childOfChild.getCount(); - for (S32 i = 0; i < childOfChildCount; ++i) - { - domNode* pChildNode = daeSafeCast(childOfChild[i]); - if (pChildNode) - { - processJointToNodeMapping(pChildNode); - } - } -} - -//----------------------------------------------------------------------------- -// critiqueRigForUploadApplicability() -//----------------------------------------------------------------------------- -void LLModelPreview::critiqueRigForUploadApplicability(const std::vector &jointListFromAsset) -{ - critiqueJointToNodeMappingFromScene(); - - //Determines the following use cases for a rig: - //1. It is suitable for upload with skin weights & joint positions, or - //2. It is suitable for upload as standard av with just skin weights - - bool isJointPositionUploadOK = isRigSuitableForJointPositionUpload(jointListFromAsset); - bool isRigLegacyOK = isRigLegacy(jointListFromAsset); - - //It's OK that both could end up being true, both default to false - if (isJointPositionUploadOK) - { - setRigValidForJointPositionUpload(true); - } - - if (isRigLegacyOK) - { - setLegacyRigValid(true); - } - -} - -//----------------------------------------------------------------------------- -// critiqueJointToNodeMappingFromScene() -//----------------------------------------------------------------------------- -void LLModelPreview::critiqueJointToNodeMappingFromScene(void) -{ - //Do the actual nodes back the joint listing from the dae? - //if yes then this is a fully rigged asset, otherwise it's just a partial rig - - std::deque::iterator jointsFromNodeIt = mJointsFromNode.begin(); - std::deque::iterator jointsFromNodeEndIt = mJointsFromNode.end(); - bool result = true; - - if (!mJointsFromNode.empty()) - { - for ( ;jointsFromNodeIt!=jointsFromNodeEndIt;++jointsFromNodeIt) - { - std::string name = *jointsFromNodeIt; - if (mJointTransformMap.find(name) != mJointTransformMap.end()) - { - continue; - } - else - { - llinfos<<"critiqueJointToNodeMappingFromScene is missing a: "< &jointListFromAsset) -{ - //No joints in asset - if (jointListFromAsset.size() == 0) - { - return false; - } - - bool result = false; - - std::deque :: const_iterator masterJointIt = mMasterLegacyJointList.begin(); - std::deque :: const_iterator masterJointEndIt = mMasterLegacyJointList.end(); - - std::vector :: const_iterator modelJointIt = jointListFromAsset.begin(); - std::vector :: const_iterator modelJointItEnd = jointListFromAsset.end(); - - for ( ;masterJointIt!=masterJointEndIt;++masterJointIt) - { - result = false; - modelJointIt = jointListFromAsset.begin(); - - for ( ;modelJointIt!=modelJointItEnd; ++modelJointIt) - { - if (*masterJointIt == *modelJointIt) - { - result = true; - break; - } - } - if (!result) - { - llinfos<<" Asset did not contain the joint (if you're u/l a fully rigged asset w/joint positions - it is required)." << *masterJointIt<< llendl; - break; - } - } - return result; -} - -//----------------------------------------------------------------------------- -// isRigSuitableForJointPositionUpload() -//----------------------------------------------------------------------------- -bool LLModelPreview::isRigSuitableForJointPositionUpload(const std::vector &jointListFromAsset) -{ - bool result = false; - - std::deque :: const_iterator masterJointIt = mMasterJointList.begin(); - std::deque :: const_iterator masterJointEndIt = mMasterJointList.end(); - - std::vector :: const_iterator modelJointIt = jointListFromAsset.begin(); - std::vector :: const_iterator modelJointItEnd = jointListFromAsset.end(); - - for ( ;masterJointIt!=masterJointEndIt;++masterJointIt) - { - result = false; - modelJointIt = jointListFromAsset.begin(); - - for ( ;modelJointIt!=modelJointItEnd; ++modelJointIt) - { - if (*masterJointIt == *modelJointIt) - { - result = true; - break; - } - } - if (!result) - { - llinfos<<" Asset did not contain the joint (if you're u/l a fully rigged asset w/joint positions - it is required)." << *masterJointIt<< llendl; - break; - } - } - return result; -} - -//called in the main thread -void LLModelLoader::loadTextures() -{ - BOOL is_paused = isPaused(); - pause(); //pause the loader - - for (scene::iterator iter = mScene.begin(); iter != mScene.end(); ++iter) - { - for (U32 i = 0; i < iter->second.size(); i++) - { - for (std::map::iterator j = iter->second[i].mMaterial.begin(); - j != iter->second[i].mMaterial.end(); ++j) - { - LLImportMaterial& material = j->second; - - if (!material.mDiffuseMapFilename.empty()) - { - material.mDiffuseMap = - LLViewerTextureManager::getFetchedTextureFromUrl("file://" + material.mDiffuseMapFilename, TRUE, LLGLTexture::BOOST_PREVIEW); - material.mDiffuseMap->setLoadedCallback(LLModelPreview::textureLoadedCallback, 0, TRUE, FALSE, mPreview, NULL, FALSE); - material.mDiffuseMap->forceToSaveRawImage(0, F32_MAX); - mNumOfFetchingTextures++; - } - } - } - } - - if (!is_paused) - { - unpause(); - } -} - -//----------------------------------------------------------------------------- -// isNodeAJoint() -//----------------------------------------------------------------------------- -bool LLModelLoader::isNodeAJoint(domNode* pNode) -{ - if (!pNode) - { - llinfos<<"Created node is NULL"<getName() == NULL) - { - llinfos<<"Parsed node has no name "<getId()) - { - llinfos<<"Parsed node ID: "<getId()<getName()) != mJointMap.end()) - { - return true; - } - - return false; -} - -//----------------------------------------------------------------------------- -// verifyCount -//----------------------------------------------------------------------------- -bool LLModelPreview::verifyCount(int expected, int result) -{ - if (expected != result) - { - llinfos<< "Error: (expected/got)"<getSkin(); - - if (pSkin) - { - xsAnyURI & uri = pSkin->getSource(); - domElement* pElement = uri.getElement(); - - if (!pElement) - { - llinfos<<"Can't resolve skin source"<getTypeName(); - if (stricmp(type_str, "geometry") == 0) - { - //Skin is reference directly by geometry and get the vertex count from skin - domSkin::domVertex_weights* pVertexWeights = pSkin->getVertex_weights(); - U32 vertexWeightsCount = pVertexWeights->getCount(); - domGeometry* pGeometry = (domGeometry*) (domElement*) uri.getElement(); - domMesh* pMesh = pGeometry->getMesh(); - - if (pMesh) - { - //Get vertex count from geometry - domVertices* pVertices = pMesh->getVertices(); - if (!pVertices) - { - llinfos<<"No vertices!"<getInput_array()[0]->getSource(); - domSource* pSource = (domSource*) (domElement*) src.getElement(); - U32 verticesCount = pSource->getTechnique_common()->getAccessor()->getCount(); - result = verifyCount(verticesCount, vertexWeightsCount); - if (!result) - { - return result; - } - } - } - - U32 vcountCount = (U32) pVertexWeights->getVcount()->getValue().getCount(); - result = verifyCount(vcountCount, vertexWeightsCount); - if (!result) - { - return result; - } - - domInputLocalOffset_Array& inputs = pVertexWeights->getInput_array(); - U32 sum = 0; - for (size_t i = 0; i < vcountCount; i++) - { - sum += pVertexWeights->getVcount()->getValue()[i]; - } - result = verifyCount(sum * inputs.getCount(), (domInt) pVertexWeights->getV()->getValue().getCount()); - } - } - - return result; -} - -//----------------------------------------------------------------------------- -// extractTranslation() -//----------------------------------------------------------------------------- -void LLModelLoader::extractTranslation(domTranslate* pTranslate, LLMatrix4& transform) -{ - domFloat3 jointTrans = pTranslate->getValue(); - LLVector3 singleJointTranslation(jointTrans[0], jointTrans[1], jointTrans[2]); - transform.setTranslation(singleJointTranslation); -} - -//----------------------------------------------------------------------------- -// extractTranslationViaElement() -//----------------------------------------------------------------------------- -void LLModelLoader::extractTranslationViaElement(daeElement* pTranslateElement, LLMatrix4& transform) -{ - if (pTranslateElement) - { - domTranslate* pTranslateChild = dynamic_cast(pTranslateElement); - domFloat3 translateChild = pTranslateChild->getValue(); - LLVector3 singleJointTranslation(translateChild[0], translateChild[1], translateChild[2]); - transform.setTranslation(singleJointTranslation); - } -} - -//----------------------------------------------------------------------------- -// extractTranslationViaSID() -//----------------------------------------------------------------------------- -void LLModelLoader::extractTranslationViaSID(daeElement* pElement, LLMatrix4& transform) -{ - if (pElement) - { - daeSIDResolver resolver(pElement, "./transform"); - domMatrix* pMatrix = daeSafeCast(resolver.getElement()); - //We are only extracting out the translational component atm - LLMatrix4 workingTransform; - if (pMatrix) - { - domFloat4x4 domArray = pMatrix->getValue(); - for (int i = 0; i < 4; i++) - { - for (int j = 0; j < 4; j++) - { - workingTransform.mMatrix[i][j] = domArray[i + j*4]; - } - } - LLVector3 trans = workingTransform.getTranslation(); - transform.setTranslation(trans); - } - } - else - { - llwarns<<"Element is nonexistent - empty/unsupported node."<getName() == NULL) - { - llwarns << "nameless node, can't process" << llendl; - return; - } - - //llwarns<<"ProcessJointNode# Node:" <getName()<(jointResolverA.getElement()); - daeSIDResolver jointResolverB(pNode, "./location"); - domTranslate* pTranslateB = daeSafeCast(jointResolverB.getElement()); - - //Translation via SID was successful - if (pTranslateA) - { - extractTranslation(pTranslateA, workingTransform); - } - else - if (pTranslateB) - { - extractTranslation(pTranslateB, workingTransform); - } - else - { - //Translation via child from element - daeElement* pTranslateElement = getChildFromElement(pNode, "translate"); - if (!pTranslateElement || pTranslateElement->typeID() != domTranslate::ID()) - { - //llwarns<< "The found element is not a translate node" <(jointResolver.getElement()); - if (pMatrix) - { - //llinfos<<"A matrix SID was however found!"<getValue(); - for (int i = 0; i < 4; i++) - { - for (int j = 0; j < 4; j++) - { - workingTransform.mMatrix[i][j] = domArray[i + j*4]; - } - } - } - else - { - llwarns<< "The found element is not translate or matrix node - most likely a corrupt export!" <getName() ] = workingTransform; - - //2. handle the nodes children - - //Gather and handle the incoming nodes children - daeTArray< daeSmartRef > childOfChild = pNode->getChildren(); - S32 childOfChildCount = childOfChild.getCount(); - - for (S32 i = 0; i < childOfChildCount; ++i) - { - domNode* pChildNode = daeSafeCast(childOfChild[i]); - if (pChildNode) - { - processJointNode(pChildNode, jointTransforms); - } - } -} - -//----------------------------------------------------------------------------- -// getChildFromElement() -//----------------------------------------------------------------------------- -daeElement* LLModelLoader::getChildFromElement(daeElement* pElement, std::string const & name) -{ - daeElement* pChildOfElement = pElement->getChild(name.c_str()); - if (pChildOfElement) - { - return pChildOfElement; - } - llwarns<< "Could not find a child [" << name << "] for the element: \"" << pElement->getAttribute("id") << "\"" << llendl; - return NULL; -} - -void LLModelLoader::processElement(daeElement* element, bool& badElement) -{ - LLMatrix4 saved_transform = mTransform; - - domTranslate* translate = daeSafeCast(element); - if (translate) - { - domFloat3 dom_value = translate->getValue(); - - LLMatrix4 translation; - translation.setTranslation(LLVector3(dom_value[0], dom_value[1], dom_value[2])); - - translation *= mTransform; - mTransform = translation; - } - - domRotate* rotate = daeSafeCast(element); - if (rotate) - { - domFloat4 dom_value = rotate->getValue(); - - LLMatrix4 rotation; - rotation.initRotTrans(dom_value[3] * DEG_TO_RAD, LLVector3(dom_value[0], dom_value[1], dom_value[2]), LLVector3(0, 0, 0)); - - rotation *= mTransform; - mTransform = rotation; - } - - domScale* scale = daeSafeCast(element); - if (scale) - { - domFloat3 dom_value = scale->getValue(); - - LLVector3 scale_vector = LLVector3(dom_value[0], dom_value[1], dom_value[2]); - scale_vector.abs(); // Set all values positive, since we don't currently support mirrored meshes - LLMatrix4 scaling; - scaling.initScale(scale_vector); - - scaling *= mTransform; - mTransform = scaling; - } - - domMatrix* matrix = daeSafeCast(element); - if (matrix) - { - domFloat4x4 dom_value = matrix->getValue(); - - LLMatrix4 matrix_transform; - - for (int i = 0; i < 4; i++) - { - for (int j = 0; j < 4; j++) - { - matrix_transform.mMatrix[i][j] = dom_value[i + j*4]; - } - } - - matrix_transform *= mTransform; - mTransform = matrix_transform; - } - - domInstance_geometry* instance_geo = daeSafeCast(element); - if (instance_geo) - { - domGeometry* geo = daeSafeCast(instance_geo->getUrl().getElement()); - if (geo) - { - domMesh* mesh = daeSafeCast(geo->getDescendant(daeElement::matchType(domMesh::ID()))); - if (mesh) - { - LLModel* model = mModel[mesh]; - if (model) - { - LLMatrix4 transformation = mTransform; - - if (mTransform.determinant() < 0) - { //negative scales are not supported - llinfos << "Negative scale detected, unsupported transform. domInstance_geometry: " << LLModel::getElementLabel(instance_geo) << llendl; - badElement = true; - } - - std::map materials = getMaterials(model, instance_geo); - - // adjust the transformation to compensate for mesh normalization - LLVector3 mesh_scale_vector; - LLVector3 mesh_translation_vector; - model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); - - LLMatrix4 mesh_translation; - mesh_translation.setTranslation(mesh_translation_vector); - mesh_translation *= transformation; - transformation = mesh_translation; - - LLMatrix4 mesh_scale; - mesh_scale.initScale(mesh_scale_vector); - mesh_scale *= transformation; - transformation = mesh_scale; - - std::string label = getElementLabel(instance_geo); - mScene[transformation].push_back(LLModelInstance(model, label, transformation, materials)); - - stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform); - } - } - } - else - { - llinfos<<"Unable to resolve geometry URL."<(element); - if (instance_node) - { - daeElement* instance = instance_node->getUrl().getElement(); - if (instance) - { - processElement(instance,badElement); - } - } - - //process children - daeTArray< daeSmartRef > children = element->getChildren(); - int childCount = children.getCount(); - for (S32 i = 0; i < childCount; i++) - { - processElement(children[i],badElement); - } - - domNode* node = daeSafeCast(element); - if (node) - { //this element was a node, restore transform before processiing siblings - mTransform = saved_transform; - } -} - -std::map LLModelLoader::getMaterials(LLModel* model, domInstance_geometry* instance_geo) -{ - std::map materials; - for (int i = 0; i < model->mMaterialList.size(); i++) - { - LLImportMaterial import_material; - - domInstance_material* instance_mat = NULL; - - domBind_material::domTechnique_common* technique = - daeSafeCast(instance_geo->getDescendant(daeElement::matchType(domBind_material::domTechnique_common::ID()))); - - if (technique) - { - daeTArray< daeSmartRef > inst_materials = technique->getChildrenByType(); - for (int j = 0; j < inst_materials.getCount(); j++) - { - std::string symbol(inst_materials[j]->getSymbol()); - - if (symbol == model->mMaterialList[i]) // found the binding - { - instance_mat = inst_materials[j]; - } - } - } - - if (instance_mat) - { - domMaterial* material = daeSafeCast(instance_mat->getTarget().getElement()); - if (material) - { - domInstance_effect* instance_effect = - daeSafeCast(material->getDescendant(daeElement::matchType(domInstance_effect::ID()))); - if (instance_effect) - { - domEffect* effect = daeSafeCast(instance_effect->getUrl().getElement()); - if (effect) - { - domProfile_COMMON* profile = - daeSafeCast(effect->getDescendant(daeElement::matchType(domProfile_COMMON::ID()))); - if (profile) - { - import_material = profileToMaterial(profile); - } - } - } - } - } - - import_material.mBinding = model->mMaterialList[i]; - materials[model->mMaterialList[i]] = import_material; - } - - return materials; -} - -LLImportMaterial LLModelLoader::profileToMaterial(domProfile_COMMON* material) -{ - LLImportMaterial mat; - mat.mFullbright = FALSE; - - daeElement* diffuse = material->getDescendant("diffuse"); - if (diffuse) - { - domCommon_color_or_texture_type_complexType::domTexture* texture = - daeSafeCast(diffuse->getDescendant("texture")); - if (texture) - { - domCommon_newparam_type_Array newparams = material->getNewparam_array(); - for (S32 i = 0; i < newparams.getCount(); i++) - { - domFx_surface_common* surface = newparams[i]->getSurface(); - if (surface) - { - domFx_surface_init_common* init = surface->getFx_surface_init_common(); - if (init) - { - domFx_surface_init_from_common_Array init_from = init->getInit_from_array(); - - if (init_from.getCount() > i) - { - domImage* image = daeSafeCast(init_from[i]->getValue().getElement()); - if (image) - { - // we only support init_from now - embedded data will come later - domImage::domInit_from* init = image->getInit_from(); - if (init) - { - mat.mDiffuseMapFilename = cdom::uriToNativePath(init->getValue().str()); - mat.mDiffuseMapLabel = getElementLabel(material); - } - } - } - } - } - } - } - - domCommon_color_or_texture_type_complexType::domColor* color = - daeSafeCast(diffuse->getDescendant("color")); - if (color) - { - domFx_color_common domfx_color = color->getValue(); - LLColor4 value = LLColor4(domfx_color[0], domfx_color[1], domfx_color[2], domfx_color[3]); - mat.mDiffuseColor = value; - } - } - - daeElement* emission = material->getDescendant("emission"); - if (emission) - { - LLColor4 emission_color = getDaeColor(emission); - if (((emission_color[0] + emission_color[1] + emission_color[2]) / 3.0) > 0.25) - { - mat.mFullbright = TRUE; - } - } - - return mat; -} - -// try to get a decent label for this element -std::string LLModelLoader::getElementLabel(daeElement *element) -{ - // if we have a name attribute, use it - std::string name = element->getAttribute("name"); - if (name.length()) - { - return name; - } - - // if we have an ID attribute, use it - if (element->getID()) - { - return std::string(element->getID()); - } - - // if we have a parent, use it - daeElement* parent = element->getParent(); - if (parent) - { - // if parent has a name, use it - std::string name = parent->getAttribute("name"); - if (name.length()) - { - return name; - } - - // if parent has an ID, use it - if (parent->getID()) - { - return std::string(parent->getID()); - } - } - - // try to use our type - daeString element_name = element->getElementName(); - if (element_name) - { - return std::string(element_name); - } - - // if all else fails, use "object" - return std::string("object"); -} - -LLColor4 LLModelLoader::getDaeColor(daeElement* element) -{ - LLColor4 value; - domCommon_color_or_texture_type_complexType::domColor* color = - daeSafeCast(element->getDescendant("color")); - if (color) - { - domFx_color_common domfx_color = color->getValue(); - value = LLColor4(domfx_color[0], domfx_color[1], domfx_color[2], domfx_color[3]); - } - - return value; -} - -//----------------------------------------------------------------------------- -// LLModelPreview -//----------------------------------------------------------------------------- - -LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) -: LLViewerDynamicTexture(width, height, 3, ORDER_MIDDLE, FALSE), LLMutex() -, mPelvisZOffset( 0.0f ) -, mLegacyRigValid( false ) -, mRigValidJointUpload( false ) -, mResetJoints( false ) -, mRigParityWithScene( false ) -, mLastJointUpdate( false ) -{ - mNeedsUpdate = TRUE; - mCameraDistance = 0.f; - mCameraYaw = 0.f; - mCameraPitch = 0.f; - mCameraZoom = 1.f; - mTextureName = 0; - mPreviewLOD = 0; - mModelLoader = NULL; - mMaxTriangleLimit = 0; - mDirty = false; - mGenLOD = false; - mLoading = false; - mLoadState = LLModelLoader::STARTING; - mGroup = 0; - mLODFrozen = false; - mBuildShareTolerance = 0.f; - mBuildQueueMode = GLOD_QUEUE_GREEDY; - mBuildBorderMode = GLOD_BORDER_UNLOCK; - mBuildOperator = GLOD_OPERATOR_EDGE_COLLAPSE; - - for (U32 i = 0; i < LLModel::NUM_LODS; ++i) - { - mRequestedTriangleCount[i] = 0; - mRequestedCreaseAngle[i] = -1.f; - mRequestedLoDMode[i] = 0; - mRequestedErrorThreshold[i] = 0.f; - mRequestedBuildOperator[i] = 0; - mRequestedQueueMode[i] = 0; - mRequestedBorderMode[i] = 0; - mRequestedShareTolerance[i] = 0.f; - } - - mViewOption["show_textures"] = false; - - mFMP = fmp; - - mHasPivot = false; - mModelPivot = LLVector3(0.0f, 0.0f, 0.0f); - - glodInit(); - - //move into joint mapper class - //1. joints for joint offset verification - mMasterJointList.push_front("mPelvis"); - mMasterJointList.push_front("mTorso"); - mMasterJointList.push_front("mChest"); - mMasterJointList.push_front("mNeck"); - mMasterJointList.push_front("mHead"); - mMasterJointList.push_front("mCollarLeft"); - mMasterJointList.push_front("mShoulderLeft"); - mMasterJointList.push_front("mElbowLeft"); - mMasterJointList.push_front("mWristLeft"); - mMasterJointList.push_front("mCollarRight"); - mMasterJointList.push_front("mShoulderRight"); - mMasterJointList.push_front("mElbowRight"); - mMasterJointList.push_front("mWristRight"); - mMasterJointList.push_front("mHipRight"); - mMasterJointList.push_front("mKneeRight"); - mMasterJointList.push_front("mFootRight"); - mMasterJointList.push_front("mHipLeft"); - mMasterJointList.push_front("mKneeLeft"); - mMasterJointList.push_front("mFootLeft"); - //2. legacy joint list - used to verify rigs that will not be using joint offsets - mMasterLegacyJointList.push_front("mPelvis"); - mMasterLegacyJointList.push_front("mTorso"); - mMasterLegacyJointList.push_front("mChest"); - mMasterLegacyJointList.push_front("mNeck"); - mMasterLegacyJointList.push_front("mHead"); - mMasterLegacyJointList.push_front("mHipRight"); - mMasterLegacyJointList.push_front("mKneeRight"); - mMasterLegacyJointList.push_front("mFootRight"); - mMasterLegacyJointList.push_front("mHipLeft"); - mMasterLegacyJointList.push_front("mKneeLeft"); - mMasterLegacyJointList.push_front("mFootLeft"); - - createPreviewAvatar(); -} - -LLModelPreview::~LLModelPreview() -{ - if (mModelLoader) - { - mModelLoader->mPreview = NULL; - mModelLoader = NULL; - } - // *HACK : *TODO : turn this back on when we understand why this crashes - //glodShutdown(); -} - -U32 LLModelPreview::calcResourceCost() -{ - assert_main_thread(); - - rebuildUploadData(); - - //Upload skin is selected BUT check to see if the joints coming in from the asset were malformed. - if (mFMP && mFMP->childGetValue("upload_skin").asBoolean()) - { - bool uploadingJointPositions = mFMP->childGetValue("upload_joints").asBoolean(); - if (uploadingJointPositions && !isRigValidForJointPositionUpload()) - { - mFMP->childDisable("ok_btn"); - } - } - - std::set accounted; - U32 num_points = 0; - U32 num_hulls = 0; - - F32 debug_scale = mFMP ? mFMP->childGetValue("import_scale").asReal() : 1.f; - mPelvisZOffset = mFMP ? mFMP->childGetValue("pelvis_offset").asReal() : 3.0f; - - if (mFMP && mFMP->childGetValue("upload_joints").asBoolean()) - { - getPreviewAvatar()->setPelvisOffset(mPelvisZOffset); - } - - F32 streaming_cost = 0.f; - F32 physics_cost = 0.f; - for (U32 i = 0; i < mUploadData.size(); ++i) - { - LLModelInstance& instance = mUploadData[i]; - - if (accounted.find(instance.mModel) == accounted.end()) - { - accounted.insert(instance.mModel); - - LLModel::Decomposition& decomp = - instance.mLOD[LLModel::LOD_PHYSICS] ? - instance.mLOD[LLModel::LOD_PHYSICS]->mPhysics : - instance.mModel->mPhysics; - - //update instance skin info for each lods pelvisZoffset - for (int j = 0; j < LLModel::NUM_LODS; ++j) - { - if (instance.mLOD[j]) - { - instance.mLOD[j]->mSkinInfo.mPelvisOffset = mPelvisZOffset; - } - } - - std::stringstream ostr; - LLSD ret = LLModel::writeModel(ostr, - instance.mLOD[4], - instance.mLOD[3], - instance.mLOD[2], - instance.mLOD[1], - instance.mLOD[0], - decomp, - mFMP->childGetValue("upload_skin").asBoolean(), - mFMP->childGetValue("upload_joints").asBoolean(), - TRUE); - - num_hulls += decomp.mHull.size(); - for (U32 i = 0; i < decomp.mHull.size(); ++i) - { - num_points += decomp.mHull[i].size(); - } - - //calculate streaming cost - LLMatrix4 transformation = instance.mTransform; - - LLVector3 position = LLVector3(0, 0, 0) * transformation; + LLVector3 position = LLVector3(0, 0, 0) * transformation; LLVector3 x_transformed = LLVector3(1, 0, 0) * transformation - position; LLVector3 y_transformed = LLVector3(0, 1, 0) * transformation - position; @@ -3237,7 +1359,11 @@ U32 LLModelPreview::calcResourceCost() F32 radius = scale.length()*0.5f*debug_scale; - streaming_cost += LLMeshRepository::getStreamingCost(ret, radius); + LLMeshCostData costs; + if (LLMeshRepository::getCostData(ret, costs)) + { + streaming_cost += costs.getRadiusBasedStreamingCost(radius); + } } } @@ -3258,6 +1384,15 @@ void LLFloaterModelPreview::setDetails(F32 x, F32 y, F32 z, F32 streaming_cost, childSetTextArg("import_dimensions", "[Z]", llformat("%.3f", z)); } +void LLFloaterModelPreview::setPreviewLOD(S32 lod) +{ + if (mModelPreview) + { + mModelPreview->setPreviewLOD(lod); + } +} + + void LLModelPreview::rebuildUploadData() { assert_main_thread(); @@ -3280,29 +1415,12 @@ void LLModelPreview::rebuildUploadData() F32 max_scale = 0.f; - //reorder materials to match mBaseModel - for (U32 i = 0; i < LLModel::NUM_LODS-1; i++) - { - if (mBaseModel.size() == mModel[i].size()) - { - for (U32 j = 0; j < mBaseModel.size(); ++j) - { - - int refFaceCnt = 0; - int modelFaceCnt = 0; - - if (!mModel[i][j]->matchMaterialOrder(mBaseModel[j], refFaceCnt, modelFaceCnt)) - { - setLoadState( LLModelLoader::ERROR_MATERIALS ); - mFMP->childDisable("calculate_btn"); - } - } - } - } + BOOL importerDebug = gSavedSettings.getBOOL("ImporterDebug"); + BOOL legacyMatching = gSavedSettings.getBOOL("ImporterLegacyMatching"); for (LLModelLoader::scene::iterator iter = mBaseScene.begin(); iter != mBaseScene.end(); ++iter) - { //for each transform in scene - LLMatrix4 mat = iter->first; + { //for each transform in scene + LLMatrix4 mat = iter->first; // compute position LLVector3 position = LLVector3(0, 0, 0) * mat; @@ -3324,41 +1442,224 @@ void LLModelPreview::rebuildUploadData() LLModelInstance instance = *model_iter; LLModel* base_model = instance.mModel; - - if (base_model) + + if (base_model && !requested_name.empty()) { base_model->mRequestedLabel = requested_name; base_model->mMetric = metric; } - S32 idx = 0; - for (idx = 0; idx < mBaseModel.size(); ++idx) - { //find reference instance for this model - if (mBaseModel[idx] == base_model) + for (int i = LLModel::NUM_LODS - 1; i >= LLModel::LOD_IMPOSTOR; i--) + { + LLModel* lod_model = NULL; + if (!legacyMatching) { - break; + // Fill LOD slots by finding matching meshes by label with name extensions + // in the appropriate scene for each LOD. This fixes all kinds of issues + // where the indexed method below fails in spectacular fashion. + // If you don't take the time to name your LOD and PHYS meshes + // with the name of their corresponding mesh in the HIGH LOD, + // then the indexed method will be attempted below. + + LLMatrix4 transform; + + std::string name_to_match = instance.mLabel; + llassert(!name_to_match.empty()); + + int extensionLOD; + if (i != LLModel::LOD_PHYSICS || mModel[LLModel::LOD_PHYSICS].empty()) + { + extensionLOD = i; + } + else + { + //Physics can be inherited from other LODs or loaded, so we need to adjust what extension we are searching for + extensionLOD = mPhysicsSearchLOD; + } + + std::string toAdd; + switch (extensionLOD) + { + case LLModel::LOD_IMPOSTOR: toAdd = "_LOD0"; break; + case LLModel::LOD_LOW: toAdd = "_LOD1"; break; + case LLModel::LOD_MEDIUM: toAdd = "_LOD2"; break; + case LLModel::LOD_PHYSICS: toAdd = "_PHYS"; break; + case LLModel::LOD_HIGH: break; + } + + if (name_to_match.find(toAdd) == std::string::npos) + { + name_to_match += toAdd; + } + + FindModel(mScene[i], name_to_match, lod_model, transform); + + if (!lod_model && i != LLModel::LOD_PHYSICS) + { + if (importerDebug) + { + LL_INFOS() << "Search of" << name_to_match << " in LOD" << i << " list failed. Searching for alternative among LOD lists." << LL_ENDL; + } + + int searchLOD = (i > LLModel::LOD_HIGH) ? LLModel::LOD_HIGH : i; + while ((searchLOD <= LLModel::LOD_HIGH) && !lod_model) + { + std::string name_to_match = instance.mLabel; + llassert(!name_to_match.empty()); + + std::string toAdd; + switch (searchLOD) + { + case LLModel::LOD_IMPOSTOR: toAdd = "_LOD0"; break; + case LLModel::LOD_LOW: toAdd = "_LOD1"; break; + case LLModel::LOD_MEDIUM: toAdd = "_LOD2"; break; + case LLModel::LOD_PHYSICS: toAdd = "_PHYS"; break; + case LLModel::LOD_HIGH: break; + } + + if (name_to_match.find(toAdd) == std::string::npos) + { + name_to_match += toAdd; + } + + // See if we can find an appropriately named model in LOD 'searchLOD' + // + FindModel(mScene[searchLOD], name_to_match, lod_model, transform); + searchLOD++; + } + } } - } + else + { + // Use old method of index-based association + U32 idx = 0; + for (idx = 0; idx < mBaseModel.size(); ++idx) + { + // find reference instance for this model + if (mBaseModel[idx] == base_model) + { + if (importerDebug) + { + LL_INFOS() << "Attempting to use model index " << idx << " for LOD " << i << " of " << instance.mLabel << LL_ENDL; + } + break; + } + } - if (idx < mBaseModel.size()) - { - for (U32 i = 0; i < LLModel::NUM_LODS; i++) - { //fill LOD slots based on reference model index + // If the model list for the current LOD includes that index... + // if (mModel[i].size() > idx) { - instance.mLOD[i] = mModel[i][idx]; + // Assign that index from the model list for our LOD as the LOD model for this instance + // + lod_model = mModel[i][idx]; + if (importerDebug) + { + LL_INFOS() << "Indexed match of model index " << idx << " at LOD " << i << " to model named " << lod_model->mLabel << LL_ENDL; + } } - else + else if (importerDebug) + { + LL_INFOS() << "List of models does not include index " << idx << LL_ENDL; + } + } + + if (lod_model) + { + if (importerDebug) + { + if (i == LLModel::LOD_PHYSICS) + { + LL_INFOS() << "Assigning collision for " << instance.mLabel << " to match " << lod_model->mLabel << LL_ENDL; + } + else + { + LL_INFOS() << "Assigning LOD" << i << " for " << instance.mLabel << " to found match " << lod_model->mLabel << LL_ENDL; + } + } + instance.mLOD[i] = lod_model; + } + else + { + if (i < LLModel::LOD_HIGH && !lodsReady()) + { + // assign a placeholder from previous LOD until lod generation is complete. + // Note: we might need to assign it regardless of conditions like named search does, to prevent crashes. + instance.mLOD[i] = instance.mLOD[i + 1]; + } + if (importerDebug) + { + LL_INFOS() << "List of models does not include " << instance.mLabel << LL_ENDL; + } + } + } + + LLModel* high_lod_model = instance.mLOD[LLModel::LOD_HIGH]; + if (!high_lod_model) + { + setLoadState( LLModelLoader::ERROR_MATERIALS ); + mFMP->childDisable( "calculate_btn" ); + } + else + { + for (U32 i = 0; i < LLModel::NUM_LODS-1; i++) + { + int refFaceCnt = 0; + int modelFaceCnt = 0; + llassert(instance.mLOD[i]); + if (instance.mLOD[i] && !instance.mLOD[i]->matchMaterialOrder(high_lod_model, refFaceCnt, modelFaceCnt ) ) { - instance.mLOD[i] = NULL; + setLoadState( LLModelLoader::ERROR_MATERIALS ); + mFMP->childDisable( "calculate_btn" ); } } + LLFloaterModelPreview* fmp = (LLFloaterModelPreview*) mFMP; + bool upload_skinweights = fmp && fmp->childGetValue("upload_skin").asBoolean(); + if (upload_skinweights && high_lod_model->mSkinInfo.mJointNames.size() > 0) + { + LLQuaternion bind_rot = LLSkinningUtil::getUnscaledQuaternion(high_lod_model->mSkinInfo.mBindShapeMatrix); + LLQuaternion identity; + if (!bind_rot.isEqualEps(identity,0.01f)) + { + LL_WARNS() << "non-identity bind shape rot. mat is " << high_lod_model->mSkinInfo.mBindShapeMatrix + << " bind_rot " << bind_rot << LL_ENDL; + setLoadState( LLModelLoader::WARNING_BIND_SHAPE_ORIENTATION ); + } + } } instance.mTransform = mat; mUploadData.push_back(instance); } } + for (U32 lod = 0; lod < LLModel::NUM_LODS-1; lod++) + { + // Search for models that are not included into upload data + // If we found any, that means something we loaded is not a sub-model. + for (U32 model_ind = 0; model_ind < mModel[lod].size(); ++model_ind) + { + bool found_model = false; + for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter) + { + LLModelInstance& instance = *iter; + if (instance.mLOD[lod] == mModel[lod][model_ind]) + { + found_model = true; + break; + } + } + if (!found_model && mModel[lod][model_ind] && !mModel[lod][model_ind]->mSubmodelID) + { + if (importerDebug) + { + LL_INFOS() << "Model " << mModel[lod][model_ind]->mLabel << " was not used - mismatching lod models." << LL_ENDL; + } + setLoadState( LLModelLoader::ERROR_MATERIALS ); + mFMP->childDisable( "calculate_btn" ); + } + } + } + const F32 DEFAULT_MAX_PRIM_SCALE(gHippoLimits->getMaxPrimScale()); F32 max_import_scale = (DEFAULT_MAX_PRIM_SCALE-0.1f)/max_scale; F32 max_axis = llmax(mPreviewScale.mV[0], mPreviewScale.mV[1]); @@ -3366,7 +1667,8 @@ void LLModelPreview::rebuildUploadData() max_axis *= 2.f; //clamp scale so that total imported model bounding box is smaller than 240m on a side - max_import_scale = llmin(max_import_scale, 240.f/max_axis); + if (gHippoGridManager->getConnectedGrid()->isSecondLife()) // on SecondLife only + max_import_scale = llmin(max_import_scale, 240.f/max_axis); scale_spinner->setMaxValue(max_import_scale); @@ -3437,15 +1739,17 @@ void LLModelPreview::saveUploadData(const std::string& filename, bool save_skinw instance.mLOD[LLModel::LOD_LOW], instance.mLOD[LLModel::LOD_IMPOSTOR], decomp, - save_skinweights, save_joint_positions, FALSE, TRUE); - + save_skinweights, + save_joint_positions, + FALSE, TRUE, instance.mModel->mSubmodelID); + data["mesh"][instance.mModel->mLocalID] = str.str(); } data["instance"][i] = instance.asLLSD(); } - llofstream out(filename, std::ios_base::out | std::ios_base::binary); + llofstream out(filename.c_str(), std::ios_base::out | std::ios_base::binary); LLSDSerialize::toBinary(data, out); out.flush(); out.close(); @@ -3463,6 +1767,28 @@ void LLModelPreview::clearModel(S32 lod) mScene[lod].clear(); } +void LLModelPreview::getJointAliases( JointMap& joint_map) +{ + // Get all standard skeleton joints from the preview avatar. + LLVOAvatar *av = getPreviewAvatar(); + + //Joint names and aliases come from avatar_skeleton.xml + + joint_map = av->getJointAliases(); + + std::vector cv_names, attach_names; + av->getSortedJointNames(1, cv_names); + av->getSortedJointNames(2, attach_names); + for (std::vector::iterator it = cv_names.begin(); it != cv_names.end(); ++it) + { + joint_map[*it] = *it; + } + for (std::vector::iterator it = attach_names.begin(); it != attach_names.end(); ++it) + { + joint_map[*it] = *it; + } +} + void LLModelPreview::loadModel(std::string filename, S32 lod, bool force_disable_slm) { assert_main_thread(); @@ -3471,7 +1797,7 @@ void LLModelPreview::loadModel(std::string filename, S32 lod, bool force_disable if (lod < LLModel::LOD_IMPOSTOR || lod > LLModel::NUM_LODS - 1) { - llwarns << "Invalid level of detail: " << lod << llendl; + LL_WARNS() << "Invalid level of detail: " << lod << LL_ENDL; assert(lod >= LLModel::LOD_IMPOSTOR && lod < LLModel::NUM_LODS); return; } @@ -3487,14 +1813,15 @@ void LLModelPreview::loadModel(std::string filename, S32 lod, bool force_disable // this is the initial file picking. Close the whole floater // if we don't have a base model to show for high LOD. mFMP->close(); - mLoading = false; + } + mLoading = false; return; } if (mModelLoader) { - llwarns << "Incompleted model load operation pending." << llendl; + LL_WARNS() << "Incompleted model load operation pending." << LL_ENDL; return; } @@ -3505,13 +1832,34 @@ void LLModelPreview::loadModel(std::string filename, S32 lod, bool force_disable clearGLODGroup(); } - mModelLoader = new LLModelLoader(filename, lod, this, mJointTransformMap, mJointsFromNode); + std::map joint_alias_map; + getJointAliases(joint_alias_map); + + mModelLoader = new LLDAELoader( + filename, + lod, + &LLModelPreview::loadedCallback, + &LLModelPreview::lookupJointByName, + &LLModelPreview::loadTextures, + &LLModelPreview::stateChangedCallback, + this, + mJointTransformMap, + mJointsFromNode, + joint_alias_map, + LLSkinningUtil::getMaxJointCount(), + gSavedSettings.getU32("ImporterModelLimit"), + gSavedSettings.getBOOL("ImporterPreprocessDAE")); if (force_disable_slm) { mModelLoader->mTrySLM = false; } - + else + { + //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(); + } mModelLoader->start(); mFMP->childSetTextArg("status", "[STATUS]", mFMP->getString("status_reading_file")); @@ -3542,6 +1890,7 @@ void LLModelPreview::setPhysicsFromLOD(S32 lod) if (lod >= 0 && lod <= 3) { + mPhysicsSearchLOD = lod; mModel[LLModel::LOD_PHYSICS] = mModel[lod]; mScene[LLModel::LOD_PHYSICS] = mScene[lod]; mLODFile[LLModel::LOD_PHYSICS].clear(); @@ -3561,11 +1910,14 @@ void LLModelPreview::clearIncompatible(S32 lod) return; } + // at this point we don't care about sub-models, + // different amount of sub-models means face count mismatch, not incompatibility + U32 lod_size = countRootModels(mModel[lod]); for (U32 i = 0; i <= LLModel::LOD_HIGH; i++) - { //clear out any entries that aren't compatible with this model + { //clear out any entries that aren't compatible with this model if (i != lod) { - if (mModel[i].size() != mModel[lod].size()) + if (countRootModels(mModel[i]) != lod_size) { mModel[i].clear(); mScene[i].clear(); @@ -3600,7 +1952,7 @@ void LLModelPreview::clearGLODGroup() } } -void LLModelPreview::loadModelCallback(S32 lod) +void LLModelPreview::loadModelCallback(S32 loaded_lod) { assert_main_thread(); @@ -3613,12 +1965,25 @@ void LLModelPreview::loadModelCallback(S32 lod) if (getLoadState() >= LLModelLoader::ERROR_PARSING) { mLoading = false; - return; + mModelLoader = NULL; + mLodsWithParsingError.push_back(loaded_lod); + return ; + } + + mLodsWithParsingError.erase(std::remove(mLodsWithParsingError.begin(), mLodsWithParsingError.end(), loaded_lod), mLodsWithParsingError.end()); + if(mLodsWithParsingError.empty()) + { + mFMP->childEnable( "calculate_btn" ); } - mModelLoader->loadTextures(); + // Copy determinations about rig so UI will reflect them + // + setRigValidForJointPositionUpload(mModelLoader->isRigValidForJointPositionUpload()); + setLegacyRigValid(mModelLoader->isLegacyRigValid()); - if (lod == -1) + mModelLoader->loadTextures() ; + + if (loaded_lod == -1) { //populate all LoDs from model loader scene mBaseModel.clear(); mBaseScene.clear(); @@ -3650,8 +2015,13 @@ void LLModelPreview::loadModelCallback(S32 lod) //override displayed model with current LoD list_iter->mModel = list_iter->mLOD[lod]; + if (!list_iter->mModel) + { + continue; + } + //add current model to current LoD's model list (LLModel::mLocalID makes a good vector index) - S32 idx = list_iter->mModel->mLocalID; + size_t idx = list_iter->mModel->mLocalID; if (mModel[lod].size() <= idx) { //stretch model list to fit model at given index @@ -3700,32 +2070,109 @@ void LLModelPreview::loadModelCallback(S32 lod) resetPreviewTarget(); } else - { //only replace given LoD - mModel[lod] = mModelLoader->mModelList; - mScene[lod] = mModelLoader->mScene; - mVertexBuffer[lod].clear(); + { //only replace given LoD + mModel[loaded_lod] = mModelLoader->mModelList; + mScene[loaded_lod] = mModelLoader->mScene; + mVertexBuffer[loaded_lod].clear(); - setPreviewLOD(lod); + setPreviewLOD(loaded_lod); - if (lod == LLModel::LOD_HIGH) - { //save a copy of the highest LOD for automatic LOD manipulation + if (loaded_lod == LLModel::LOD_HIGH) + { //save a copy of the highest LOD for automatic LOD manipulation if (mBaseModel.empty()) - { //first time we've loaded a model, auto-gen LoD + { //first time we've loaded a model, auto-gen LoD mGenLOD = true; } - mBaseModel = mModel[lod]; + mBaseModel = mModel[loaded_lod]; clearGLODGroup(); - mBaseScene = mScene[lod]; + mBaseScene = mScene[loaded_lod]; mVertexBuffer[5].clear(); } + else + { + BOOL importerDebug = gSavedSettings.getBOOL("ImporterDebug"); + BOOL legacyMatching = gSavedSettings.getBOOL("ImporterLegacyMatching"); + if (!legacyMatching) + { + if (!mBaseModel.empty()) + { + BOOL name_based = FALSE; + BOOL has_submodels = FALSE; + for (U32 idx = 0; idx < mBaseModel.size(); ++idx) + { + if (mBaseModel[idx]->mSubmodelID) + { // don't do index-based renaming when the base model has submodels + has_submodels = TRUE; + if (importerDebug) + { + LL_INFOS() << "High LOD has submodels" << LL_ENDL; + } + break; + } + } + + for (U32 idx = 0; idx < mModel[loaded_lod].size(); ++idx) + { + std::string loaded_name = stripSuffix(mModel[loaded_lod][idx]->mLabel); + + LLModel* found_model = NULL; + LLMatrix4 transform; + FindModel(mBaseScene, loaded_name, found_model, transform); + if (found_model) + { // don't rename correctly named models (even if they are placed in a wrong order) + name_based = TRUE; + } + + if (mModel[loaded_lod][idx]->mSubmodelID) + { // don't rename the models when loaded LOD model has submodels + has_submodels = TRUE; + } + } + + if (importerDebug) + { + LL_INFOS() << "Loaded LOD " << loaded_lod << ": correct names" << (name_based ? "" : "NOT ") << "found; submodels " << (has_submodels ? "" : "NOT ") << "found" << LL_ENDL; + } + + if (!name_based && !has_submodels) + { // replace the name of the model loaded for any non-HIGH LOD to match the others (MAINT-5601) + // this actually works like "ImporterLegacyMatching" for this particular LOD + for (U32 idx = 0; idx < mModel[loaded_lod].size() && idx < mBaseModel.size(); ++idx) + { + std::string name = mBaseModel[idx]->mLabel; + std::string loaded_name = stripSuffix(mModel[loaded_lod][idx]->mLabel); + + if (loaded_name != name) + { + switch (loaded_lod) + { + case LLModel::LOD_IMPOSTOR: name += "_LOD0"; break; + case LLModel::LOD_LOW: name += "_LOD1"; break; + case LLModel::LOD_MEDIUM: name += "_LOD2"; break; + case LLModel::LOD_PHYSICS: name += "_PHYS"; break; + case LLModel::LOD_HIGH: break; + } + + if (importerDebug) + { + LL_WARNS() << "Loded model name " << mModel[loaded_lod][idx]->mLabel << " for LOD " << loaded_lod << " doesn't match the base model. Renaming to " << name << LL_ENDL; + } + + mModel[loaded_lod][idx]->mLabel = name; + } + } + } + } + } + } - clearIncompatible(lod); + clearIncompatible(loaded_lod); mDirty = true; - if (lod == LLModel::LOD_HIGH) + if (loaded_lod == LLModel::LOD_HIGH) { resetPreviewTarget(); } @@ -3737,16 +2184,15 @@ void LLModelPreview::loadModelCallback(S32 lod) mFMP->getChild("confirm_checkbox")->set(FALSE); if (!mBaseModel.empty()) { - if (mFMP->getChild("description_form")->getValue().asString().empty()) - { - const std::string& model_name = mBaseModel[0]->getName(); - mFMP->getChild("description_form")->setValue(model_name); - } + const std::string& model_name = mBaseModel[0]->getName(); + mFMP->getChild("description_form")->setValue(model_name); } } refresh(); mModelLoadedSignal(); + + mModelLoader = NULL; } void LLModelPreview::resetPreviewTarget() @@ -3766,7 +2212,8 @@ void LLModelPreview::generateNormals() S32 which_lod = mPreviewLOD; - if (which_lod > 4 || which_lod < 0 || mModel[which_lod].empty()) + if (which_lod > 4 || which_lod < 0 || + mModel[which_lod].empty()) { return; } @@ -3779,19 +2226,81 @@ void LLModelPreview::generateNormals() if (which_lod == 3 && !mBaseModel.empty()) { - for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) + if(mBaseModelFacesCopy.empty()) + { + mBaseModelFacesCopy.reserve(mBaseModel.size()); + for (LLModelLoader::model_list::iterator it = mBaseModel.begin(), itE = mBaseModel.end(); it != itE; ++it) + { + v_LLVolumeFace_t faces; + (*it)->copyFacesTo(faces); + mBaseModelFacesCopy.push_back(faces); + } + } + + for (LLModelLoader::model_list::iterator it = mBaseModel.begin(), itE = mBaseModel.end(); it != itE; ++it) { - (*iter)->generateNormals(angle_cutoff); + (*it)->generateNormals(angle_cutoff); } mVertexBuffer[5].clear(); } - for (LLModelLoader::model_list::iterator iter = mModel[which_lod].begin(); iter != mModel[which_lod].end(); ++iter) - { - (*iter)->generateNormals(angle_cutoff); + bool perform_copy = mModelFacesCopy[which_lod].empty(); + if(perform_copy) { + mModelFacesCopy[which_lod].reserve(mModel[which_lod].size()); + } + + for (LLModelLoader::model_list::iterator it = mModel[which_lod].begin(), itE = mModel[which_lod].end(); it != itE; ++it) + { + if(perform_copy) + { + v_LLVolumeFace_t faces; + (*it)->copyFacesTo(faces); + mModelFacesCopy[which_lod].push_back(faces); + } + + (*it)->generateNormals(angle_cutoff); + } + + mVertexBuffer[which_lod].clear(); + refresh(); + updateStatusMessages(); +} + +void LLModelPreview::restoreNormals() +{ + S32 which_lod = mPreviewLOD; + + if (which_lod > 4 || which_lod < 0 || + mModel[which_lod].empty()) + { + return; + } + + if(!mBaseModelFacesCopy.empty()) + { + llassert(mBaseModelFacesCopy.size() == mBaseModel.size()); + + vv_LLVolumeFace_t::const_iterator itF = mBaseModelFacesCopy.begin(); + for (LLModelLoader::model_list::iterator it = mBaseModel.begin(), itE = mBaseModel.end(); it != itE; ++it, ++itF) + { + (*it)->copyFacesFrom((*itF)); + } + + mBaseModelFacesCopy.clear(); + } + + if(!mModelFacesCopy[which_lod].empty()) + { + vv_LLVolumeFace_t::const_iterator itF = mModelFacesCopy[which_lod].begin(); + for (LLModelLoader::model_list::iterator it = mModel[which_lod].begin(), itE = mModel[which_lod].end(); it != itE; ++it, ++itF) + { + (*it)->copyFacesFrom((*itF)); + } + + mModelFacesCopy[which_lod].clear(); } - + mVertexBuffer[which_lod].clear(); refresh(); updateStatusMessages(); @@ -3802,7 +2311,7 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim // Allow LoD from -1 to LLModel::LOD_PHYSICS if (which_lod < -1 || which_lod > LLModel::NUM_LODS - 1) { - llwarns << "Invalid level of detail: " << which_lod << llendl; + LL_WARNS() << "Invalid level of detail: " << which_lod << LL_ENDL; assert(which_lod >= -1 && which_lod < LLModel::NUM_LODS); return; } @@ -3830,15 +2339,30 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim U32 triangle_count = 0; - for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) + U32 instanced_triangle_count = 0; + + //get the triangle count for the whole scene + for (LLModelLoader::scene::iterator iter = mBaseScene.begin(), endIter = mBaseScene.end(); iter != endIter; ++iter) { - LLModel* mdl = *iter; - for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) + for (LLModelLoader::model_instance_list::iterator instance = iter->second.begin(), end_instance = iter->second.end(); instance != end_instance; ++instance) { - triangle_count += mdl->getVolumeFace(i).mNumIndices/3; + LLModel* mdl = instance->mModel; + if (mdl) + { + instanced_triangle_count += mdl->getNumTriangles(); + } } } + //get the triangle count for the non-instanced set of models + for (U32 i = 0; i < mBaseModel.size(); ++i) + { + triangle_count += mBaseModel[i]->getNumTriangles(); + } + + //get ratio of uninstanced triangles to instanced triangles + F32 triangle_ratio = (F32) triangle_count / (F32) instanced_triangle_count; + U32 base_triangle_count = triangle_count; U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; @@ -3872,6 +2396,8 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim if (which_lod > -1 && which_lod < NUM_LOD) { limit = mFMP->childGetValue("lod_triangle_limit_" + lod_name[which_lod]).asInteger(); + //convert from "scene wide" to "non-instanced" triangle limit + limit = (S32) ( (F32) limit*triangle_ratio ); } } else @@ -3976,7 +2502,7 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim U32 actual_verts = 0; U32 submeshes = 0; - mRequestedTriangleCount[lod] = triangle_count; + mRequestedTriangleCount[lod] = (S32) ( (F32) triangle_count / triangle_ratio ); mRequestedErrorThreshold[lod] = lod_error_threshold; glodGroupParameteri(mGroup, GLOD_ADAPT_MODE, lod_mode); @@ -4014,6 +2540,20 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); mModel[lod][mdl_idx] = new LLModel(volume_params, 0.f); + std::string name = base->mLabel; + + switch (lod) + { + case LLModel::LOD_IMPOSTOR: name += "_LOD0"; break; + case LLModel::LOD_LOW: name += "_LOD1"; break; + case LLModel::LOD_MEDIUM: name += "_LOD2"; break; + case LLModel::LOD_PHYSICS: name += "_PHYS"; break; + case LLModel::LOD_HIGH: break; + } + + mModel[lod][mdl_idx]->mLabel = name; + mModel[lod][mdl_idx]->mSubmodelID = base->mSubmodelID; + GLint* sizes = new GLint[patch_count*2]; glodGetObjectParameteriv(mObject[base], GLOD_PATCH_SIZES, sizes); stop_gloderror(); @@ -4072,7 +2612,7 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim if (!validate_face(target_model->getVolumeFace(names[i]))) { - llerrs << "Invalid face generated during LOD generation." << llendl; + LL_ERRS() << "Invalid face generated during LOD generation." << LL_ENDL; } } @@ -4087,7 +2627,7 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim if (!validate_model(target_model)) { - llerrs << "Invalid model generated when creating LODs" << llendl; + LL_ERRS() << "Invalid model generated when creating LODs" << LL_ENDL; } delete [] sizes; @@ -4126,17 +2666,112 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim { shader->bind(); } +} +void LLModelPreview::genModelBBox() +{ + LLVector3 min, max; + min = this->mModelLoader->mExtents[0]; + max = this->mModelLoader->mExtents[1]; + std::vector v_list; + v_list.resize(4); + std::map > face_list; + + // Face 0 + v_list[0] = LLVector3(min.mV[VX], max.mV[VY], max.mV[VZ]); + v_list[1] = LLVector3(min.mV[VX], min.mV[VY], max.mV[VZ]); + v_list[2] = LLVector3(max.mV[VX], min.mV[VY], max.mV[VZ]); + v_list[3] = LLVector3(max.mV[VX], max.mV[VY], max.mV[VZ]); + face_list.insert(std::pair >(0, v_list)); + + // Face 1 + v_list[0] = LLVector3(max.mV[VX], min.mV[VY], max.mV[VZ]); + v_list[1] = LLVector3(max.mV[VX], min.mV[VY], min.mV[VZ]); + v_list[2] = LLVector3(max.mV[VX], max.mV[VY], min.mV[VZ]); + v_list[3] = LLVector3(max.mV[VX], max.mV[VY], max.mV[VZ]); + face_list.insert(std::pair >(1, v_list)); + + // Face 2 + v_list[0] = LLVector3(min.mV[VX], max.mV[VY], min.mV[VZ]); + v_list[1] = LLVector3(min.mV[VX], max.mV[VY], max.mV[VZ]); + v_list[2] = LLVector3(max.mV[VX], max.mV[VY], max.mV[VZ]); + v_list[3] = LLVector3(max.mV[VX], max.mV[VY], min.mV[VZ]); + face_list.insert(std::pair >(2, v_list)); + + // Face 3 + v_list[0] = LLVector3(min.mV[VX], max.mV[VY], max.mV[VZ]); + v_list[1] = LLVector3(min.mV[VX], max.mV[VY], min.mV[VZ]); + v_list[2] = LLVector3(min.mV[VX], min.mV[VY], min.mV[VZ]); + v_list[3] = LLVector3(min.mV[VX], min.mV[VY], max.mV[VZ]); + face_list.insert(std::pair >(3, v_list)); + + // Face 4 + v_list[0] = LLVector3(min.mV[VX], min.mV[VY], max.mV[VZ]); + v_list[1] = LLVector3(min.mV[VX], min.mV[VY], min.mV[VZ]); + v_list[2] = LLVector3(max.mV[VX], min.mV[VY], min.mV[VZ]); + v_list[3] = LLVector3(max.mV[VX], min.mV[VY], max.mV[VZ]); + face_list.insert(std::pair >(4, v_list)); + + // Face 5 + v_list[0] = LLVector3(min.mV[VX], min.mV[VY], min.mV[VZ]); + v_list[1] = LLVector3(min.mV[VX], max.mV[VY], min.mV[VZ]); + v_list[2] = LLVector3(max.mV[VX], max.mV[VY], min.mV[VZ]); + v_list[3] = LLVector3(max.mV[VX], min.mV[VY], min.mV[VZ]); + face_list.insert(std::pair >(5, v_list)); + + U16 Idx[] = { 0, 1, 2, 3, 0, 2, }; + + U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; + LLPointer buff = new LLVertexBuffer(type_mask, 0); + buff->allocateBuffer(4, 6, true); + + LLStrider pos; + LLStrider idx; + LLStrider norm; + LLStrider tc; + + buff->getVertexStrider(pos); + buff->getIndexStrider(idx); + + buff->getNormalStrider(norm); + buff->getTexCoord0Strider(tc); + + for (U32 i = 0; i < 6; ++i) + { + idx[i] = Idx[i]; + } + + LLVolumeParams volume_params; + volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); + LLModel* mdl = new LLModel(volume_params, 0.f); + mdl->mLabel = "BBOX"; // please adopt name from high LOD (mBaseModel) or from original model otherwise it breaks search mechanics which is name based + + mdl->setNumVolumeFaces(6); + for (U8 i = 0; i < 6; ++i) + { + for (U8 j = 0; j < 4; ++j) + { + pos[j] = face_list[i][j]; + } + + mdl->setVolumeFaceData(i, pos, norm, tc, idx, buff->getNumVerts(), buff->getNumIndices()); + } + + if (validate_model(mdl)) + { + LLMatrix4 mat; + std::map materials; + std::vector instance_list; + instance_list.push_back(LLModelInstance(mdl, mdl->mLabel, mat, materials)); - /*if (which_lod == -1 && mScene[LLModel::LOD_PHYSICS].empty()) - { //build physics scene - mScene[LLModel::LOD_PHYSICS] = mScene[LLModel::LOD_LOW]; - mModel[LLModel::LOD_PHYSICS] = mModel[LLModel::LOD_LOW]; + for (S32 i = LLModel::LOD_HIGH - 1; i >= 0; i--) + { + mModel[i].clear(); + mModel[i].push_back(mdl); - for (U32 i = 1; i < mModel[LLModel::LOD_PHYSICS].size(); ++i) - { - mPhysicsQ.push(mModel[LLModel::LOD_PHYSICS][i]); - } - }*/ + mScene[i].clear(); + mScene[i].insert(std::pair >(mat, instance_list)); + } + } } void LLModelPreview::updateStatusMessages() @@ -4153,35 +2788,89 @@ void LLModelPreview::updateStatusMessages() S32 total_verts[LLModel::NUM_LODS]; S32 total_submeshes[LLModel::NUM_LODS]; - for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod) + for (U32 i = 0; i < LLModel::NUM_LODS-1; i++) + { + total_tris[i] = 0; + total_verts[i] = 0; + total_submeshes[i] = 0; + } + + for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter) { - //initialize total for this lod to 0 - total_tris[lod] = total_verts[lod] = total_submeshes[lod] = 0; + LLModelInstance& instance = *iter; + + LLModel* model_high_lod = instance.mLOD[LLModel::LOD_HIGH]; + if (!model_high_lod) + { + setLoadState( LLModelLoader::ERROR_MATERIALS ); + mFMP->childDisable( "calculate_btn" ); + continue; + } + + for (U32 i = 0; i < LLModel::NUM_LODS-1; i++) + { + LLModel* lod_model = instance.mLOD[i]; + if (!lod_model) + { + setLoadState( LLModelLoader::ERROR_MATERIALS ); + mFMP->childDisable( "calculate_btn" ); + } - for (U32 i = 0; i < mModel[lod].size(); ++i) - { //for each model in the lod - S32 cur_tris = 0; - S32 cur_verts = 0; - S32 cur_submeshes = mModel[lod][i]->getNumVolumeFaces(); + int refFaceCnt = 0; + int modelFaceCnt = 0; - for (S32 j = 0; j < cur_submeshes; ++j) - { //for each submesh (face), add triangles and vertices to current total - const LLVolumeFace& face = mModel[lod][i]->getVolumeFace(j); - cur_tris += face.mNumIndices/3; - cur_verts += face.mNumVertices; + if (!lod_model->matchMaterialOrder(model_high_lod, refFaceCnt, modelFaceCnt ) ) + { + setLoadState( LLModelLoader::ERROR_MATERIALS ); + mFMP->childDisable( "calculate_btn" ); } - //add this model to the lod total - total_tris[lod] += cur_tris; - total_verts[lod] += cur_verts; - total_submeshes[lod] += cur_submeshes; + if (lod_model) + { + //for each model in the lod + S32 cur_tris = 0; + S32 cur_verts = 0; + S32 cur_submeshes = lod_model->getNumVolumeFaces(); + + for (S32 j = 0; j < cur_submeshes; ++j) + { //for each submesh (face), add triangles and vertices to current total + const LLVolumeFace& face = lod_model->getVolumeFace(j); + cur_tris += face.mNumIndices/3; + cur_verts += face.mNumVertices; + } - //store this model's counts to asset data - tris[lod].push_back(cur_tris); - verts[lod].push_back(cur_verts); - submeshes[lod].push_back(cur_submeshes); + std::string instance_name = instance.mLabel; + + BOOL importerDebug = gSavedSettings.getBOOL("ImporterDebug"); + if (importerDebug) + { + // Useful for debugging generalized complaints below about total submeshes which don't have enough + // context to address exactly what needs to be fixed to move towards compliance with the rules. + // + LL_INFOS() << "Instance " << lod_model->mLabel << " LOD " << i << " Verts: " << cur_verts << LL_ENDL; + LL_INFOS() << "Instance " << lod_model->mLabel << " LOD " << i << " Tris: " << cur_tris << LL_ENDL; + LL_INFOS() << "Instance " << lod_model->mLabel << " LOD " << i << " Faces: " << cur_submeshes << LL_ENDL; + + LLModel::material_list::iterator mat_iter = lod_model->mMaterialList.begin(); + while (mat_iter != lod_model->mMaterialList.end()) + { + LL_INFOS() << "Instance " << lod_model->mLabel << " LOD " << i << " Material " << *(mat_iter) << LL_ENDL; + mat_iter++; + } + } + + //add this model to the lod total + total_tris[i] += cur_tris; + total_verts[i] += cur_verts; + total_submeshes[i] += cur_submeshes; + + //store this model's counts to asset data + tris[i].push_back(cur_tris); + verts[i].push_back(cur_verts); + submeshes[i].push_back(cur_submeshes); + } } - } + } if (mMaxTriangleLimit == 0) { @@ -4194,38 +2883,50 @@ void LLModelPreview::updateStatusMessages() U32 lod = LLModel::LOD_PHYSICS; const LLVector4a scale(0.5f); for (U32 i = 0; i < mModel[lod].size() && !has_degenerate; ++i) - { //for each model in the lod - if (mModel[lod][i]->mPhysics.mHull.empty()) - { //no decomp exists + { //for each model in the lod + if (mModel[lod][i] && mModel[lod][i]->mPhysics.mHull.empty()) + { //no decomp exists S32 cur_submeshes = mModel[lod][i]->getNumVolumeFaces(); for (S32 j = 0; j < cur_submeshes && !has_degenerate; ++j) - { //for each submesh (face), add triangles and vertices to current total - const LLVolumeFace& face = mModel[lod][i]->getVolumeFace(j); - for (S32 k = 0; k < face.mNumIndices && !has_degenerate; ) + { //for each submesh (face), add triangles and vertices to current total + LLVolumeFace& face = mModel[lod][i]->getVolumeFace(j); + for (S32 k = 0; (k < face.mNumIndices) && !has_degenerate; ) { - LLVector4a v1; v1.setMul(face.mPositions[face.mIndices[k++]], scale); - LLVector4a v2; v2.setMul(face.mPositions[face.mIndices[k++]], scale); - LLVector4a v3; v3.setMul(face.mPositions[face.mIndices[k++]], scale); + U16 index_a = face.mIndices[k+0]; + U16 index_b = face.mIndices[k+1]; + U16 index_c = face.mIndices[k+2]; - if (ll_is_degenerate(v1, v2, v3)) + LLVector4a v1; v1.setMul(face.mPositions[index_a], scale); + LLVector4a v2; v2.setMul(face.mPositions[index_b], scale); + LLVector4a v3; v3.setMul(face.mPositions[index_c], scale); + + if (ll_is_degenerate(v1,v2,v3)) { has_degenerate = true; } + else + { + k += 3; + } } } } } } - + /* Singu Note: Dummy views and what for? mFMP->childSetTextArg("submeshes_info", "[SUBMESHES]", llformat("%d", total_submeshes[LLModel::LOD_HIGH])); + */ std::string mesh_status_na = mFMP->getString("mesh_status_na"); S32 upload_status[LLModel::LOD_HIGH + 1]; - bool upload_ok = true; + mModelNoErrors = true; - for (S32 lod = 0; lod <= LLModel::LOD_HIGH; ++lod) + const U32 lod_high = LLModel::LOD_HIGH; + U32 high_submodel_count = mModel[lod_high].size() - countRootModels(mModel[lod_high]); + + for (S32 lod = 0; lod <= lod_high; ++lod) { upload_status[lod] = 0; @@ -4238,7 +2939,7 @@ void LLModelPreview::updateStatusMessages() } else { - if (lod == LLModel::LOD_HIGH) + if (lod == lod_high) { upload_status[lod] = 2; message = "mesh_status_missing_lod"; @@ -4259,8 +2960,6 @@ void LLModelPreview::updateStatusMessages() mFMP->childSetText(lod_vertices_name[lod], mesh_status_na); } - const U32 lod_high = LLModel::LOD_HIGH; - if (lod != lod_high) { if (total_submeshes[lod] && total_submeshes[lod] != total_submeshes[lod_high]) @@ -4268,6 +2967,13 @@ void LLModelPreview::updateStatusMessages() message = "mesh_status_submesh_mismatch"; upload_status[lod] = 2; } + else if (mModel[lod].size() - countRootModels(mModel[lod]) != high_submodel_count) + {//number of submodels is different, not all faces are matched correctly. + message = "mesh_status_submesh_mismatch"; + upload_status[lod] = 2; + // Note: Submodels in instance were loaded from higher LOD and as result face count + // returns same value and total_submeshes[lod] is identical to high_lod one. + } else if (!tris[lod].empty() && tris[lod].size() != tris[lod_high].size()) { //number of meshes is different message = "mesh_status_mesh_mismatch"; @@ -4288,19 +2994,19 @@ void LLModelPreview::updateStatusMessages() { //too many vertices in this lod message = "mesh_status_too_many_vertices"; - upload_status[lod] = 2; + upload_status[lod] = 1; } } } - std::string img = lod_status_image[upload_status[lod]]; LLIconCtrl* icon = mFMP->getChild(lod_icon_name[lod]); - icon->setVisible(true); + LLUIImagePtr img = LLUI::getUIImage(lod_status_image[upload_status[lod]]); + icon->setVisible(lodsReady()); icon->setImage(img); if (upload_status[lod] >= 2) { - upload_ok = false; + mModelNoErrors = false; } if (lod == mPreviewLOD) @@ -4313,76 +3019,103 @@ void LLModelPreview::updateStatusMessages() updateLodControls(lod); } - //make sure no hulls have more than 256 points in them - for (U32 i = 0; upload_ok && i < mModel[LLModel::LOD_PHYSICS].size(); ++i) + + //warn if hulls have more than 256 points in them + BOOL physExceededVertexLimit = FALSE; + for (U32 i = 0; mModelNoErrors && i < mModel[LLModel::LOD_PHYSICS].size(); ++i) { LLModel* mdl = mModel[LLModel::LOD_PHYSICS][i]; - for (U32 j = 0; upload_ok && j < mdl->mPhysics.mHull.size(); ++j) + if (mdl) { - if (mdl->mPhysics.mHull[j].size() > 256) + for (U32 j = 0; j < mdl->mPhysics.mHull.size(); ++j) { - upload_ok = false; + if (mdl->mPhysics.mHull[j].size() > 256) + { + physExceededVertexLimit = TRUE; + LL_INFOS() << "Physical model " << mdl->mLabel << " exceeds vertex per hull limitations." << LL_ENDL; + break; + } } } } + mFMP->childSetVisible("physics_status_message_text", physExceededVertexLimit); + LLIconCtrl* physStatusIcon = mFMP->getChild("physics_status_message_icon"); + physStatusIcon->setVisible(physExceededVertexLimit); + if (physExceededVertexLimit) + { + mFMP->childSetValue("physics_status_message_text", mFMP->getString("phys_status_vertex_limit_exceeded")); + LLUIImagePtr img = LLUI::getUIImage("ModelImport_Status_Warning"); + physStatusIcon->setImage(img); + } - bool errorStateFromLoader = getLoadState() >= LLModelLoader::ERROR_PARSING ? true : false; + if (getLoadState() >= LLModelLoader::ERROR_PARSING) + { + mModelNoErrors = false; + LL_INFOS() << "Loader returned errors, model can't be uploaded" << LL_ENDL; + } - bool skinAndRigOk = true; bool uploadingSkin = mFMP->childGetValue("upload_skin").asBoolean(); bool uploadingJointPositions = mFMP->childGetValue("upload_joints").asBoolean(); - if (uploadingSkin) + if ( uploadingSkin ) { - if (uploadingJointPositions && !isRigValidForJointPositionUpload()) + if ( uploadingJointPositions && !isRigValidForJointPositionUpload() ) { - skinAndRigOk = false; + mModelNoErrors = false; + LL_INFOS() << "Invalid rig, there might be issues with uploading Joint positions" << LL_ENDL; } } - if (upload_ok && mModelLoader) + if(mModelNoErrors && mModelLoader) { - if (!mModelLoader->areTexturesReady() && mFMP->childGetValue("upload_textures").asBoolean()) + if(!mModelLoader->areTexturesReady() && mFMP->childGetValue("upload_textures").asBoolean()) { - upload_ok = false; + // Some textures are still loading, prevent upload until they are done + mModelNoErrors = false; } } - if (!upload_ok || errorStateFromLoader || !skinAndRigOk || has_degenerate) + // Todo: investigate use of has_degenerate and include into mModelNoErrors upload blocking mechanics + // current use of has_degenerate won't block upload permanently - later checks will restore the button + if (!mModelNoErrors || has_degenerate) { mFMP->childDisable("ok_btn"); } //add up physics triangles etc - S32 start = 0; - S32 end = mModel[LLModel::LOD_PHYSICS].size(); - S32 phys_tris = 0; S32 phys_hulls = 0; S32 phys_points = 0; - for (S32 i = start; i < end; ++i) - { //add up hulls and points and triangles for selected mesh(es) - LLModel* model = mModel[LLModel::LOD_PHYSICS][i]; - S32 cur_submeshes = model->getNumVolumeFaces(); - - LLModel::convex_hull_decomposition& decomp = model->mPhysics.mHull; - - if (!decomp.empty()) + //get the triangle count for the whole scene + for (LLModelLoader::scene::iterator iter = mScene[LLModel::LOD_PHYSICS].begin(), endIter = mScene[LLModel::LOD_PHYSICS].end(); iter != endIter; ++iter) + { + for (LLModelLoader::model_instance_list::iterator instance = iter->second.begin(), end_instance = iter->second.end(); instance != end_instance; ++instance) { - phys_hulls += decomp.size(); - for (U32 i = 0; i < decomp.size(); ++i) + LLModel* model = instance->mModel; + if (model) { - phys_points += decomp[i].size(); - } - } - else - { //choose physics shape OR decomposition, can't use both - for (S32 j = 0; j < cur_submeshes; ++j) - { //for each submesh (face), add triangles and vertices to current total - const LLVolumeFace& face = model->getVolumeFace(j); - phys_tris += face.mNumIndices/3; + S32 cur_submeshes = model->getNumVolumeFaces(); + + LLModel::convex_hull_decomposition& decomp = model->mPhysics.mHull; + + if (!decomp.empty()) + { + phys_hulls += decomp.size(); + for (U32 i = 0; i < decomp.size(); ++i) + { + phys_points += decomp[i].size(); + } + } + else + { //choose physics shape OR decomposition, can't use both + for (S32 j = 0; j < cur_submeshes; ++j) + { //for each submesh (face), add triangles and vertices to current total + const LLVolumeFace& face = model->getVolumeFace(j); + phys_tris += face.mNumIndices/3; + } + } } } } @@ -4517,7 +3250,7 @@ void LLModelPreview::updateLodControls(S32 lod) { if (lod < LLModel::LOD_IMPOSTOR || lod > LLModel::LOD_HIGH) { - llwarns << "Invalid level of detail: " << lod << llendl; + LL_WARNS() << "Invalid level of detail: " << lod << LL_ENDL; assert(lod >= LLModel::LOD_IMPOSTOR && lod <= LLModel::LOD_HIGH); return; } @@ -4544,7 +3277,7 @@ void LLModelPreview::updateLodControls(S32 lod) if (!lod_combo) return; S32 lod_mode = lod_combo->getCurrentIndex(); - if (lod_mode == 0) // LoD from file + if (lod_mode == LOD_FROM_FILE) // LoD from file { fmp->mLODMode[lod] = 0; for (U32 i = 0; i < num_file_controls; ++i) @@ -4557,7 +3290,7 @@ void LLModelPreview::updateLodControls(S32 lod) mFMP->childHide(lod_controls[i] + lod_name[lod]); } } - else if (lod_mode == 2) // use LoD above + else if (lod_mode == USE_LOD_ABOVE) // use LoD above { fmp->mLODMode[lod] = 2; for (U32 i = 0; i < num_file_controls; ++i) @@ -4663,11 +3396,6 @@ void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights) model = &(mModel[lod]); } - if (!mVertexBuffer[lod].empty()) - { - mVertexBuffer[lod].clear(); - } - mVertexBuffer[lod].clear(); LLModelLoader::model_list::iterator base_iter = mBaseModel.begin(); @@ -4683,7 +3411,8 @@ void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights) LLModel* base_mdl = *base_iter; base_iter++; - for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) + S32 num_faces = mdl->getNumVolumeFaces(); + for (S32 i = 0; i < num_faces; ++i) { const LLVolumeFace &vf = mdl->getVolumeFace(i); U32 num_vertices = vf.mNumVertices; @@ -4713,7 +3442,7 @@ void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights) LLStrider normal_strider; LLStrider tc_strider; LLStrider index_strider; - LLStrider weights_strider; + LLStrider weights_strider; vb->getVertexStrider(vertex_strider); vb->getIndexStrider(index_strider); @@ -4751,12 +3480,14 @@ void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights) for (U32 i = 0; i < weight_list.size(); ++i) { - F32 wght = llmin(weight_list[i].mWeight, 0.999999f); + F32 wght = llclamp(weight_list[i].mWeight, 0.001f, 0.999f); F32 joint = (F32) weight_list[i].mJointIdx; w.mV[i] = joint + wght; + llassert(w.mV[i]-(S32)w.mV[i]>0.0f); // because weights are non-zero, and range of wt values + //should not cause floating point precision issues. } - *(weights_strider++) = w; + (*(weights_strider++)).loadua(w.mV); } } @@ -4777,21 +3508,32 @@ void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights) void LLModelPreview::update() { - if (mDirty) + if (mGenLOD) + { + bool subscribe_for_generation = mLodsQuery.empty(); + mGenLOD = false; + mDirty = true; + mLodsQuery.clear(); + + for (S32 lod = LLModel::LOD_HIGH; lod >= 0; --lod) + { + // adding all lods into query for generation + mLodsQuery.push_back(lod); + } + + if (subscribe_for_generation) + { + doOnIdleRepeating(lodQueryCallback); + } + } + + if (mDirty && mLodsQuery.empty()) { mDirty = false; mResourceCost = calcResourceCost(); refresh(); updateStatusMessages(); } - - if (mGenLOD) - { - mGenLOD = false; - genLODs(); - refresh(); - updateStatusMessages(); - } } //----------------------------------------------------------------------------- @@ -4811,28 +3553,92 @@ LLVector3 LLModelPreview::getTranslationForJointOffset(std::string joint) //----------------------------------------------------------------------------- // createPreviewAvatar //----------------------------------------------------------------------------- -void LLModelPreview::createPreviewAvatar(void) +void LLModelPreview::createPreviewAvatar( void ) { - mPreviewAvatar = (LLVOAvatar*)gObjectList.createObjectViewer( LL_PCODE_LEGACY_AVATAR, gAgent.getRegion() ); - if (mPreviewAvatar) + mPreviewAvatar = (LLVOAvatar*)gObjectList.createObjectViewer( LL_PCODE_LEGACY_AVATAR, gAgent.getRegion(), LLViewerObject::CO_FLAG_UI_AVATAR ); + if ( mPreviewAvatar ) { - mPreviewAvatar->createDrawable(&gPipeline); - mPreviewAvatar->mIsDummy = TRUE; + mPreviewAvatar->createDrawable( &gPipeline ); mPreviewAvatar->mSpecialRenderMode = 1; - mPreviewAvatar->setPositionAgent(LLVector3::zero); - mPreviewAvatar->slamPosition(); - mPreviewAvatar->updateJointLODs(); - mPreviewAvatar->updateGeometry(mPreviewAvatar->mDrawable); - mPreviewAvatar->startMotion(ANIM_AGENT_STAND); + mPreviewAvatar->startMotion( ANIM_AGENT_STAND ); mPreviewAvatar->hideSkirt(); } else { - llinfos<<"Failed to create preview avatar for upload model window"<mSubmodelID == 0) + { + root_models++; + } + model_iter++; + } + return root_models; +} + +void LLModelPreview::loadedCallback( + LLModelLoader::scene& scene, + LLModelLoader::model_list& model_list, + S32 lod, + void* opaque) +{ + LLModelPreview* pPreview = static_cast< LLModelPreview* >(opaque); + if (pPreview && !LLModelPreview::sIgnoreLoadedCallback) + { + pPreview->loadModelCallback(lod); + } +} + +void LLModelPreview::stateChangedCallback(U32 state,void* opaque) +{ + LLModelPreview* pPreview = static_cast< LLModelPreview* >(opaque); + if (pPreview) + { + pPreview->setLoadState(state); + } +} + +LLJoint* LLModelPreview::lookupJointByName(const std::string& str, void* opaque) +{ + LLModelPreview* pPreview = static_cast< LLModelPreview* >(opaque); + if (pPreview) + { + return pPreview->getPreviewAvatar()->getJoint(str); + } + return NULL; +} + +U32 LLModelPreview::loadTextures(LLImportMaterial& material,void* opaque) +{ + (void)opaque; + + if (material.mDiffuseMapFilename.size()) + { + material.mOpaqueData = new LLPointer< LLViewerFetchedTexture >; + LLPointer< LLViewerFetchedTexture >& tex = (*reinterpret_cast< LLPointer< LLViewerFetchedTexture > * >(material.mOpaqueData)); + + tex = LLViewerTextureManager::getFetchedTextureFromUrl("file://" + material.mDiffuseMapFilename, FTT_LOCAL_FILE, TRUE, LLGLTexture::BOOST_PREVIEW); + tex->setLoadedCallback(LLModelPreview::textureLoadedCallback, 0, TRUE, FALSE, opaque, NULL, FALSE); + tex->forceToSaveRawImage(0, F32_MAX); + material.setDiffuseMap(tex->getID()); // record tex ID + return 1; } + + material.mOpaqueData = NULL; + return 0; } -void LLModelPreview::addEmptyFace(LLModel* pTarget) +void LLModelPreview::addEmptyFace( LLModel* pTarget ) { U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; @@ -4890,10 +3696,10 @@ BOOL LLModelPreview::render() S32 height = getHeight(); LLGLSUIDefault def; - LLGLDisable no_blend(GL_BLEND); - LLGLEnable cull(GL_CULL_FACE); + LLGLDisable no_blend; + LLGLEnable cull; LLGLDepthTest depth(GL_TRUE); - LLGLDisable fog(GL_FOG); + LLGLDisable fog; { if (use_shaders) @@ -4955,8 +3761,9 @@ BOOL LLModelPreview::render() if (fmp && isLegacyRigValid()) { fmp->enableViewOption("show_skin_weight"); - fmp->setViewOptionEnabled("show_joint_positions", skin_weight); + fmp->setViewOptionEnabled("show_joint_positions", skin_weight); mFMP->childEnable("upload_skin"); + mFMP->childSetValue("show_skin_weight", skin_weight); } } else @@ -4967,8 +3774,11 @@ BOOL LLModelPreview::render() mViewOption["show_skin_weight"] = false; fmp->disableViewOption("show_skin_weight"); fmp->disableViewOption("show_joint_positions"); + + skin_weight = false; + mFMP->childSetValue("show_skin_weight", false); + fmp->setViewOptionEnabled("show_skin_weight", skin_weight); } - skin_weight = false; } if (upload_skin && !has_skin_weights) @@ -4991,6 +3801,7 @@ BOOL LLModelPreview::render() F32 explode = mFMP->childGetValue("physics_explode").asReal(); + gGL.syncContextState(); glClear(GL_DEPTH_BUFFER_BIT); LLRect preview_rect; @@ -5026,7 +3837,8 @@ BOOL LLModelPreview::render() } gGL.loadIdentity(); - gPipeline.enableLightsPreview(); + LLGLState light_state; + gPipeline.enableLightsPreview(light_state); LLQuaternion camera_rot = LLQuaternion(mCameraPitch, LLVector3::y_axis) * LLQuaternion(mCameraYaw, LLVector3::z_axis); @@ -5050,7 +3862,7 @@ BOOL LLModelPreview::render() const U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; - LLGLEnable normalize(GL_NORMALIZE); + LLGLEnable normalize; if (!mBaseModel.empty() && mVertexBuffer[5].empty()) { @@ -5072,29 +3884,20 @@ BOOL LLModelPreview::render() const LLVertexBuffer* buff = vb_vec[0]; regen = buff->hasDataType(LLVertexBuffer::TYPE_WEIGHT4) != skin_weight; } - } - - //make sure material lists all match - for (U32 i = 0; i < LLModel::NUM_LODS-1; i++) - { - if (mBaseModel.size() == mModel[i].size()) + else { - for (U32 j = 0; j < mBaseModel.size(); ++j) - { - int refFaceCnt = 0; - int modelFaceCnt = 0; - - if (!mModel[i][j]->matchMaterialOrder(mBaseModel[j], refFaceCnt, modelFaceCnt)) - { - mFMP->childDisable("calculate_btn"); - } - } + LL_INFOS() << "Vertex Buffer[" << mPreviewLOD << "]" << " is EMPTY!!!" << LL_ENDL; + regen = TRUE; } } if (regen) { genBuffers(mPreviewLOD, skin_weight); + { + LL_INFOS() << "Vertex Buffer[" << mPreviewLOD << "]" << " is EMPTY!!!" << LL_ENDL; + regen = TRUE; + } } if (!skin_weight) @@ -5110,38 +3913,40 @@ BOOL LLModelPreview::render() continue; } - gGL.pushMatrix(); - LLMatrix4 mat = instance.mTransform; - - gGL.multMatrix((GLfloat*) mat.mMatrix); + gGL.pushMatrix(); - for (U32 i = 0; i < mVertexBuffer[mPreviewLOD][model].size(); ++i) - { - LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; + LLMatrix4a transform; + transform.loadu(instance.mTransform); + gGL.multMatrix(transform); - buffer->setBuffer(type_mask & buffer->getTypeMask()); - if (textures) + U32 num_models = mVertexBuffer[mPreviewLOD][model].size(); + for (U32 i = 0; i < num_models; ++i) { - int materialCnt = instance.mModel->mMaterialList.size(); - if (i < materialCnt) + LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; + + buffer->setBuffer(type_mask & buffer->getTypeMask()); + + if (textures) { - const std::string& binding = instance.mModel->mMaterialList[i]; - const LLImportMaterial& material = instance.mMaterial[binding]; + U32 materialCnt = instance.mModel->mMaterialList.size(); + if ( i < materialCnt ) + { + const std::string& binding = instance.mModel->mMaterialList[i]; + const LLImportMaterial& material = instance.mMaterial[binding]; - gGL.diffuseColor4fv(material.mDiffuseColor.mV); + gGL.diffuseColor4fv(material.mDiffuseColor.mV); - if (material.mDiffuseMap.notNull()) - { - if (material.mDiffuseMap->getDiscardLevel() > -1) + // Find the tex for this material, bind it, and add it to our set + // + LLViewerFetchedTexture* tex = bindMaterialDiffuseTexture(material); + if (tex) { - gGL.getTexUnit(0)->bind(material.mDiffuseMap, true); - mTextureSet.insert(material.mDiffuseMap.get()); + mTextureSet.insert(tex); } } } - } - else + else { gGL.diffuseColor4f(1,1,1,1); } @@ -5152,11 +3957,11 @@ BOOL LLModelPreview::render() if (edges) { - glLineWidth(3.f); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + gGL.setLineWidth(3.f); + gGL.setPolygonMode(LLRender::PF_FRONT_AND_BACK, LLRender::PM_LINE); buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glLineWidth(1.f); + gGL.setPolygonMode(LLRender::PF_FRONT_AND_BACK, LLRender::PM_FILL); + gGL.setLineWidth(1.f); } } gGL.popMatrix(); @@ -5164,6 +3969,7 @@ BOOL LLModelPreview::render() if (physics) { + gGL.syncContextState(); glClear(GL_DEPTH_BUFFER_BIT); for (U32 i = 0; i < 2; i++) @@ -5178,7 +3984,7 @@ BOOL LLModelPreview::render() } //enable alpha blending on second pass but not first pass - LLGLState blend(GL_BLEND, i); + LLGLState blend(i); gGL.blendFunc(LLRender::BF_SOURCE_ALPHA, LLRender::BF_ONE_MINUS_SOURCE_ALPHA); @@ -5194,9 +4000,10 @@ BOOL LLModelPreview::render() } gGL.pushMatrix(); - LLMatrix4 mat = instance.mTransform; + LLMatrix4a mat; + mat.loadu((F32*)instance.mTransform.mMatrix); - gGL.multMatrix((GLfloat*) mat.mMatrix); + gGL.multMatrix(mat); bool render_mesh = true; @@ -5255,12 +4062,14 @@ BOOL LLModelPreview::render() if (mVertexBuffer[LLModel::LOD_PHYSICS].empty()) { genBuffers(LLModel::LOD_PHYSICS, false); - } - for (U32 i = 0; i < mVertexBuffer[LLModel::LOD_PHYSICS][model].size(); ++i) - { - LLVertexBuffer* buffer = mVertexBuffer[LLModel::LOD_PHYSICS][model][i]; + } + + U32 num_models = mVertexBuffer[LLModel::LOD_PHYSICS][model].size(); + for (U32 i = 0; i < num_models; ++i) + { + LLVertexBuffer* buffer = mVertexBuffer[LLModel::LOD_PHYSICS][model][i]; - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); gGL.diffuseColor4f(0.4f, 0.4f, 0.0f, 0.4f); buffer->setBuffer(type_mask & buffer->getTypeMask()); @@ -5268,24 +4077,25 @@ BOOL LLModelPreview::render() gGL.diffuseColor3f(1.f, 1.f, 0.f); - glLineWidth(2.f); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + gGL.setLineWidth(2.f); + gGL.setPolygonMode(LLRender::PF_FRONT_AND_BACK, LLRender::PM_LINE); buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glLineWidth(1.f); + gGL.setPolygonMode(LLRender::PF_FRONT_AND_BACK, LLRender::PM_FILL); + gGL.setLineWidth(1.f); } } gGL.popMatrix(); } - glLineWidth(3.f); - glPointSize(8.f); - gPipeline.enableLightsFullbright(LLColor4::white); + gGL.setLineWidth(3.f); + gGL.setPointSize(8.f); + LLGLState light_state; + gPipeline.enableLightsFullbright(light_state); //show degenerate triangles LLGLDepthTest depth(GL_TRUE, GL_TRUE, GL_ALWAYS); - LLGLDisable cull(GL_CULL_FACE); + LLGLDisable cull; gGL.diffuseColor4f(1.f,0.f,0.f,1.f); const LLVector4a scale(0.5f); @@ -5301,9 +4111,10 @@ BOOL LLModelPreview::render() } gGL.pushMatrix(); - LLMatrix4 mat = instance.mTransform; + LLMatrix4a mat; + mat.loadu((F32*)instance.mTransform.mMatrix); - gGL.multMatrix((GLfloat*) mat.mMatrix); + gGL.multMatrix(mat); LLPhysicsDecomp* decomp = gMeshRepo.mDecompThread; @@ -5333,7 +4144,7 @@ BOOL LLModelPreview::render() LLStrider idx; buffer->getIndexStrider(idx, 0); - for (U32 i = 0; i < buffer->getNumIndices(); i += 3) + for (S32 i = 0; i < buffer->getNumIndices(); i += 3) { LLVector4a v1; v1.setMul(pos[*idx++], scale); LLVector4a v2; v2.setMul(pos[*idx++], scale); @@ -5351,9 +4162,8 @@ BOOL LLModelPreview::render() gGL.popMatrix(); } - glLineWidth(1.f); - glPointSize(1.f); - gPipeline.enableLightsPreview(); + gGL.setLineWidth(1.f); + gGL.setPointSize(1.f); gGL.setSceneBlendType(LLRender::BT_ALPHA); } } @@ -5367,20 +4177,6 @@ BOOL LLModelPreview::render() LLVector3::z_axis, // up target_pos); // point of interest - if (joint_positions) - { - LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; - if (shader) - { - gDebugProgram.bind(); - } - getPreviewAvatar()->renderCollisionVolumes(); - if (shader) - { - shader->bind(); - } - } - for (LLModelLoader::scene::iterator iter = mScene[mPreviewLOD].begin(); iter != mScene[mPreviewLOD].end(); ++iter) { for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) @@ -5393,71 +4189,11 @@ BOOL LLModelPreview::render() for (U32 i = 0; i < mVertexBuffer[mPreviewLOD][model].size(); ++i) { LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; - const LLVolumeFace& face = model->getVolumeFace(i); - - LLStrider position; - buffer->getVertexStrider(position); - - LLStrider weight; + LLStrider weight; buffer->getWeight4Strider(weight); - //quick 'n dirty software vertex skinning - - //build matrix palette - - LLMatrix4 mat[64]; - for (U32 j = 0; j < model->mSkinInfo.mJointNames.size(); ++j) - { - LLJoint* joint = getPreviewAvatar()->getJoint(model->mSkinInfo.mJointNames[j]); - if (joint) - { - mat[j] = model->mSkinInfo.mInvBindMatrix[j]; - mat[j] *= joint->getWorldMatrix(); - } - } - - for (U32 j = 0; j < buffer->getNumVerts(); ++j) - { - LLMatrix4 final_mat; - final_mat.mMatrix[0][0] = final_mat.mMatrix[1][1] = final_mat.mMatrix[2][2] = final_mat.mMatrix[3][3] = 0.f; - - LLVector4 wght; - S32 idx[4]; - - F32 scale = 0.f; - for (U32 k = 0; k < 4; k++) - { - F32 w = weight[j].mV[k]; - - idx[k] = (S32) floorf(w); - wght.mV[k] = w - floorf(w); - scale += wght.mV[k]; - } - - wght *= 1.f/scale; - - for (U32 k = 0; k < 4; k++) - { - F32* src = (F32*) mat[idx[k]].mMatrix; - F32* dst = (F32*) final_mat.mMatrix; - - F32 w = wght.mV[k]; - - for (U32 l = 0; l < 16; l++) - { - dst[l] += src[l]*w; - } - } - - //VECTORIZE THIS - LLVector3 v(face.mPositions[j].getF32ptr()); - - v = v * model->mSkinInfo.mBindShapeMatrix; - v = v * final_mat; - - position[j] = v; - } + getPreviewAvatar()->updateSoftwareSkinnedVertices(&model->mSkinInfo, weight.get(), face, buffer); const std::string& binding = instance.mModel->mMaterialList[i]; const LLImportMaterial& material = instance.mMaterial[binding]; @@ -5465,30 +4201,46 @@ BOOL LLModelPreview::render() buffer->setBuffer(type_mask & buffer->getTypeMask()); gGL.diffuseColor4fv(material.mDiffuseColor.mV); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - if (material.mDiffuseMap.notNull()) + + // Find the tex for this material, bind it, and add it to our set + // + LLViewerFetchedTexture* tex = bindMaterialDiffuseTexture(material); + if (tex) { - if (material.mDiffuseMap->getDiscardLevel() > -1) - { - gGL.getTexUnit(0)->bind(material.mDiffuseMap, true); - mTextureSet.insert(material.mDiffuseMap.get()); - } + mTextureSet.insert(tex); } - + buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0); gGL.diffuseColor3f(0.4f, 0.4f, 0.4f); if (edges) { - glLineWidth(3.f); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + gGL.setLineWidth(3.f); + gGL.setPolygonMode(LLRender::PF_FRONT_AND_BACK, LLRender::PM_LINE); buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glLineWidth(1.f); + gGL.setPolygonMode(LLRender::PF_FRONT_AND_BACK, LLRender::PM_FILL); + gGL.setLineWidth(1.f); } } } } } + + if (joint_positions) + { + LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; + if (shader) + { + gDebugProgram.bind(); + } + getPreviewAvatar()->renderCollisionVolumes(); + getPreviewAvatar()->renderBones(); + if (shader) + { + shader->bind(); + } + } + } } @@ -5550,7 +4302,7 @@ void LLModelPreview::setPreviewLOD(S32 lod) LLComboBox* combo_box2 = mFMP->getChild("preview_lod_combo2"); combo_box2->setCurrentByIndex((NUM_LOD-1)-mPreviewLOD); // combo box list of lods is in reverse order - + LLComboBox* combo_box3 = mFMP->getChild("preview_lod_combo3"); combo_box3->setCurrentByIndex((NUM_LOD-1)-mPreviewLOD); // combo box list of lods is in reverse order @@ -5586,14 +4338,14 @@ void LLFloaterModelPreview::onReset(void* user_data) LLFloaterModelPreview* fmp = (LLFloaterModelPreview*) user_data; fmp->childDisable("reset_btn"); LLModelPreview* mp = fmp->mModelPreview; - std::string filename = mp->mLODFile[3]; + std::string filename = mp->mLODFile[LLModel::LOD_HIGH]; fmp->resetDisplayOptions(); //reset model preview fmp->initModelPreview(); mp = fmp->mModelPreview; - mp->loadModel(filename,3,true); + mp->loadModel(filename,LLModel::LOD_HIGH,true); } //static @@ -5613,7 +4365,9 @@ void LLFloaterModelPreview::onUpload(void* user_data) mp->mModelPreview->saveUploadData(upload_skinweights, upload_joint_positions); gMeshRepo.uploadModel(mp->mModelPreview->mUploadData, mp->mModelPreview->mPreviewScale, - mp->childGetValue("upload_textures").asBoolean(), upload_skinweights, upload_joint_positions, mp->mUploadModelUrl, + mp->childGetValue("upload_textures").asBoolean(), + upload_skinweights, upload_joint_positions, + mp->mUploadModelUrl, true, LLHandle(), mp->getWholeModelUploadObserverHandle()); } @@ -5624,7 +4378,14 @@ void LLFloaterModelPreview::refresh() } //static -void LLModelPreview::textureLoadedCallback( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* userdata ) +void LLModelPreview::textureLoadedCallback( + BOOL success, + LLViewerFetchedTexture *src_vi, + LLImageRaw* src, + LLImageRaw* src_aux, + S32 discard_level, + BOOL final, + void* userdata ) { LLModelPreview* preview = (LLModelPreview*) userdata; preview->refresh(); @@ -5638,6 +4399,39 @@ void LLModelPreview::textureLoadedCallback( BOOL success, LLViewerFetchedTexture } } +// static +bool LLModelPreview::lodQueryCallback() +{ + // not the best solution, but model preview belongs to floater + // so it is an easy way to check that preview still exists. + LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance; + if (fmp) + { + if (fmp->mModelPreview) + { + LLModelPreview* preview = fmp->mModelPreview; + if (preview->mLodsQuery.size() > 0) + { + S32 lod = preview->mLodsQuery.back(); + preview->mLodsQuery.pop_back(); + preview->genLODs(lod); + + // return false to continue cycle + return false; + } + } + + for (U32 lod = 0; lod < NUM_LOD; ++lod) + { + LLIconCtrl* icon = fmp->getChild(lod_icon_name[lod]); + icon->setVisible(true); + } + } + + // nothing to process + return true; +} + void LLModelPreview::onLODParamCommit(S32 lod, bool enforce_tri_limit) { if (!mLODFrozen) @@ -5686,7 +4480,7 @@ void LLFloaterModelPreview::toggleCalculateButton(bool visible) } mUploadBtn->setVisible(!visible); - mUploadBtn->setEnabled(mHasUploadPerm && !mUploadModelUrl.empty()); + mUploadBtn->setEnabled(isModelUploadAllowed()); if (visible) { @@ -5708,6 +4502,12 @@ void LLFloaterModelPreview::onLoDSourceCommit(S32 lod) { mModelPreview->updateLodControls(lod); refresh(); + + LLComboBox* lod_source_combo = getChild("lod_source_" + lod_name[lod]); + if (lod_source_combo->getCurrentIndex() == LLModelPreview::GENERATE) + { //rebuild LoD to update triangle counts + onLODParamCommit(lod, true); + } } void LLFloaterModelPreview::resetDisplayOptions() @@ -5746,12 +4546,12 @@ void LLFloaterModelPreview::handleModelPhysicsFeeReceived() childSetTextArg("price_breakdown", "[MODEL]", llformat("%d", result["upload_price_breakdown"]["model"].asInteger())); childSetVisible("upload_fee", true); childSetVisible("price_breakdown", true); - mUploadBtn->setEnabled(mHasUploadPerm && !mUploadModelUrl.empty()); + mUploadBtn->setEnabled(isModelUploadAllowed()); } void LLFloaterModelPreview::setModelPhysicsFeeErrorStatus(U32 status, const std::string& reason) { - llwarns << "LLFloaterModelPreview::setModelPhysicsFeeErrorStatus(" << status << " : " << reason << ")" << llendl; + LL_WARNS() << "LLFloaterModelPreview::setModelPhysicsFeeErrorStatus(" << status << " : " << reason << ")" << LL_ENDL; doOnIdleOneTime(boost::bind(&LLFloaterModelPreview::toggleCalculateButton, this, true)); } @@ -5770,6 +4570,16 @@ void LLFloaterModelPreview::onModelUploadFailure() mUploadBtn->setEnabled(true); } +bool LLFloaterModelPreview::isModelUploadAllowed() +{ + bool allow_upload = mHasUploadPerm && !mUploadModelUrl.empty(); + if (mModelPreview) + { + allow_upload &= mModelPreview->mModelNoErrors; + } + return allow_upload; +} + S32 LLFloaterModelPreview::DecompRequest::statusCallback(const char* status, S32 p1, S32 p2) { if (mContinue) @@ -5819,15 +4629,34 @@ void LLFloaterModelPreview::onPermissionsReceived(const LLSD& result) // BAP HACK: handle "" for case that MeshUploadFlag cap is broken. mHasUploadPerm = (("" == upload_status) || ("valid" == upload_status)); - //mUploadBtn->setEnabled(mHasUploadPerm); - mUploadBtn->setEnabled(mHasUploadPerm && !mUploadModelUrl.empty()); + if (!mHasUploadPerm) + { + LL_WARNS() << "Upload permission set to false because upload_status=\"" << upload_status << "\"" << LL_ENDL; + } + else if (mHasUploadPerm && mUploadModelUrl.empty()) + { + LL_WARNS() << "Upload permission set to true but uploadModelUrl is empty!" << LL_ENDL; + } + + // isModelUploadAllowed() includes mHasUploadPerm + mUploadBtn->setEnabled(isModelUploadAllowed()); getChild("warning_title")->setVisible(!mHasUploadPerm); getChild("warning_message")->setVisible(!mHasUploadPerm); } void LLFloaterModelPreview::setPermissonsErrorStatus(U32 status, const std::string& reason) { - llwarns << "LLFloaterModelPreview::setPermissonsErrorStatus(" << status << " : " << reason << ")" << llendl; + LL_WARNS() << "LLFloaterModelPreview::setPermissonsErrorStatus(" << status << " : " << reason << ")" << LL_ENDL; LLNotificationsUtil::add("MeshUploadPermError"); } + +bool LLFloaterModelPreview::isModelLoading() +{ + if(mModelPreview) + { + return mModelPreview->mLoading; + } + return false; +} + diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index 6ca55bb818..7585dce936 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -2,31 +2,25 @@ * @file llfloatermodelpreview.h * @brief LLFloaterModelPreview class definition * - * $LicenseInfo:firstyear=2004&license=viewergpl$ - * - * Copyright (c) 2010, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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$ */ @@ -42,105 +36,24 @@ #include "llviewermenufile.h" #include "llfloatermodeluploadbase.h" +#include "lldaeloader.h" + class LLComboBox; +class LLJoint; +class LLViewerJointMesh; class LLVOAvatar; class LLVertexBuffer; class LLModelPreview; class LLFloaterModelPreview; +class DAE; class daeElement; class domProfile_COMMON; class domInstance_geometry; class domNode; class domTranslate; class domController; - -typedef std::map JointTransformMap; -typedef std::map:: iterator JointTransformMapIt; - -const S32 NUM_LOD = 4; - -class LLModelLoader : public LLThread -{ -public: - typedef enum - { - STARTING = 0, - READING_FILE, - CREATING_FACES, - GENERATING_VERTEX_BUFFERS, - GENERATING_LOD, - DONE, - ERROR_PARSING, //basically loading failed - ERROR_MATERIALS, - } eLoadState; - - U32 mState; - std::string mFilename; - S32 mLod; - LLModelPreview* mPreview; - LLMatrix4 mTransform; - BOOL mFirstTransform; - LLVector3 mExtents[2]; - bool mTrySLM; - - std::map > mModel; - - typedef std::vector > model_list; - model_list mModelList; - - typedef std::vector model_instance_list; - - typedef std::map scene; - - scene mScene; - - typedef std::queue > model_queue; - - //queue of models that need a physics rep - model_queue mPhysicsQ; - - LLModelLoader(std::string filename, S32 lod, LLModelPreview* preview, JointTransformMap& jointMap, - std::deque& jointsFromNodes); - ~LLModelLoader() ; - - virtual void run(); - bool doLoadModel(); - bool loadFromSLM(const std::string& filename); - void loadModelCallback(); - - void loadTextures() ; //called in the main thread. - void processElement(daeElement* element, bool& badElement); - std::map getMaterials(LLModel* model, domInstance_geometry* instance_geo); - LLImportMaterial profileToMaterial(domProfile_COMMON* material); - std::string getElementLabel(daeElement *element); - LLColor4 getDaeColor(daeElement* element); - - daeElement* getChildFromElement(daeElement* pElement, std::string const & name); - - bool isNodeAJoint(domNode* pNode); - void processJointNode(domNode* pNode, std::map& jointTransforms); - void extractTranslation(domTranslate* pTranslate, LLMatrix4& transform); - void extractTranslationViaElement(daeElement* pTranslateElement, LLMatrix4& transform); - void extractTranslationViaSID(daeElement* pElement, LLMatrix4& transform); - - void setLoadState(U32 state); - - void buildJointToNodeMappingFromScene(daeElement* pRoot); - void processJointToNodeMapping(domNode* pNode); - void processChildJoints(domNode* pParentNode); - - //map of avatar joints as named in COLLADA assets to internal joint names - std::map mJointMap; - JointTransformMap& mJointList; - std::deque& mJointsFromNode; - - S32 mNumOfFetchingTextures ; //updated in the main thread - bool areTexturesReady() { return !mNumOfFetchingTextures; } //called in the main thread. - -private: - static std::list sActiveLoaderList; - static bool isAlive(LLModelLoader* loader) ; -}; +class domSkin; +class domMesh; class LLFloaterModelPreview : public LLFloaterModelUploadBase { @@ -171,13 +84,14 @@ class LLFloaterModelPreview : public LLFloaterModelUploadBase BOOL handleHover(S32 x, S32 y, MASK mask); BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); - /*virtual*/ void onOpen(/*const LLSD& key*/); + /*virtual*/ void onOpen(); + /*virtual*/ void onClose(bool app_quitting); static void onMouseCaptureLostModelPreview(LLMouseHandler*); static void setUploadAmount(S32 amount) { sUploadAmount = amount; } void setDetails(F32 x, F32 y, F32 z, F32 streaming_cost, F32 physics_cost); - + void setPreviewLOD(S32 lod); void onBrowseLOD(S32 lod); static void onReset(void* data); @@ -197,6 +111,8 @@ class LLFloaterModelPreview : public LLFloaterModelUploadBase void enableViewOption(const std::string& option); void disableViewOption(const std::string& option); + bool isModelLoading(); + // shows warning message if agent has no permissions to upload model /*virtual*/ void onPermissionsReceived(const LLSD& result); @@ -211,6 +127,8 @@ class LLFloaterModelPreview : public LLFloaterModelUploadBase /*virtual*/ void onModelUploadFailure(); + bool isModelUploadAllowed(); + protected: friend class LLModelPreview; friend class LLPhysicsDecomp; @@ -298,10 +216,29 @@ class LLModelPreview : public LLViewerDynamicTexture, public LLMutex typedef boost::signals2::signal model_loaded_signal_t; typedef boost::signals2::signal model_updated_signal_t; +public: + + typedef enum + { + LOD_FROM_FILE = 0, + GENERATE, + USE_LOD_ABOVE, + } eLoDMode; + public: LLModelPreview(S32 width, S32 height, LLFloater* fmp); virtual ~LLModelPreview(); + void* operator new(size_t size) + { + return ll_aligned_malloc_16(size); + } + + void operator delete(void* ptr) + { + ll_aligned_free_16(ptr); + } + void resetPreviewTarget(); void setPreviewTarget(F32 distance); void setTexture(U32 name) { mTextureName = name; } @@ -318,10 +255,15 @@ class LLModelPreview : public LLViewerDynamicTexture, public LLMutex virtual BOOL needsRender() { return mNeedsUpdate; } void setPreviewLOD(S32 lod); void clearModel(S32 lod); + void getJointAliases(JointMap& joint_map); void loadModel(std::string filename, S32 lod, bool force_disable_slm = false); void loadModelCallback(S32 lod); + bool lodsReady() { return !mGenLOD && mLodsQuery.empty(); } + void queryLODs() { mGenLOD = true; }; void genLODs(S32 which_lod = -1, U32 decimation = 3, bool enforce_tri_limit = false); + void genModelBBox(); // Generate just a model BBox if we can't generate proper LOD void generateNormals(); + void restoreNormals(); U32 calcResourceCost(); void rebuildUploadData(); void saveUploadData(bool save_skinweights, bool save_joint_poisitions); @@ -335,44 +277,52 @@ class LLModelPreview : public LLViewerDynamicTexture, public LLMutex const bool getModelPivot(void) const { return mHasPivot; } void setHasPivot(bool val) { mHasPivot = val; } - void setModelPivot(const LLVector3& pivot) { mModelPivot = pivot; } + void setModelPivot( const LLVector3& pivot ) { mModelPivot = pivot; } - //Determines the viability of an asset to be used as an avatar rig (w or w/o joint upload caps) - void critiqueRigForUploadApplicability(const std::vector &jointListFromAsset); - void critiqueJointToNodeMappingFromScene(void); //Is a rig valid so that it can be used as a criteria for allowing for uploading of joint positions //Accessors for joint position upload friendly rigs - const bool isRigValidForJointPositionUpload(void) const { return mRigValidJointUpload; } - void setRigValidForJointPositionUpload(bool rigValid) { mRigValidJointUpload = rigValid; } - bool isRigSuitableForJointPositionUpload(const std::vector &jointListFromAsset); - //Determines if a rig is a legacy from the joint list - bool isRigLegacy(const std::vector &jointListFromAsset); + const bool isRigValidForJointPositionUpload( void ) const { return mRigValidJointUpload; } + void setRigValidForJointPositionUpload( bool rigValid ) { mRigValidJointUpload = rigValid; } + //Accessors for the legacy rigs - const bool isLegacyRigValid(void) const { return mLegacyRigValid; } - void setLegacyRigValid(bool rigValid) { mLegacyRigValid = rigValid; } - //Verify that a controller matches vertex counts - bool verifyController(domController* pController); + const bool isLegacyRigValid( void ) const { return mLegacyRigValid; } + void setLegacyRigValid( bool rigValid ) { mLegacyRigValid = rigValid; } + + static void textureLoadedCallback( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* userdata ); + static bool lodQueryCallback(); + + boost::signals2::connection setDetailsCallback( const details_signal_t::slot_type& cb ){ return mDetailsSignal.connect(cb); } + boost::signals2::connection setModelLoadedCallback( const model_loaded_signal_t::slot_type& cb ){ return mModelLoadedSignal.connect(cb); } + boost::signals2::connection setModelUpdatedCallback( const model_updated_signal_t::slot_type& cb ){ return mModelUpdatedSignal.connect(cb); } + + void setLoadState( U32 state ) { mLoadState = state; } + U32 getLoadState() { return mLoadState; } + void setRigWithSceneParity( bool state ) { mRigParityWithScene = state; } + const bool getRigWithSceneParity( void ) const { return mRigParityWithScene; } + + LLVector3 getTranslationForJointOffset( std::string joint ); - static void textureLoadedCallback(BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* userdata); + static bool sIgnoreLoadedCallback; + std::vector mLodsQuery; + std::vector mLodsWithParsingError; - boost::signals2::connection setDetailsCallback(const details_signal_t::slot_type& cb){ return mDetailsSignal.connect(cb); } - boost::signals2::connection setModelLoadedCallback(const model_loaded_signal_t::slot_type& cb){ return mModelLoadedSignal.connect(cb); } - boost::signals2::connection setModelUpdatedCallback(const model_updated_signal_t::slot_type& cb){ return mModelUpdatedSignal.connect(cb); } +protected: - void setLoadState(U32 state) { mLoadState = state; } - U32 getLoadState() { return mLoadState; } - void setRigWithSceneParity(bool state) { mRigParityWithScene = state; } - const bool getRigWithSceneParity(void) const { return mRigParityWithScene; } + static void loadedCallback(LLModelLoader::scene& scene,LLModelLoader::model_list& model_list, S32 lod, void* opaque); + static void stateChangedCallback(U32 state, void* opaque); - LLVector3 getTranslationForJointOffset(std::string joint); + static LLJoint* lookupJointByName(const std::string&, void* opaque); + static U32 loadTextures(LLImportMaterial& material, void* opaque); private: //Utility function for controller vertex compare - bool verifyCount(int expected, int result); + bool verifyCount( int expected, int result ); //Creates the dummy avatar for the preview window - void createPreviewAvatar(void); + void createPreviewAvatar( void ); //Accessor for the dummy avatar - LLVOAvatar* getPreviewAvatar(void) { return mPreviewAvatar; } + LLVOAvatar* getPreviewAvatar( void ) { return mPreviewAvatar; } + // Count amount of original models, excluding sub-models + static U32 countRootModels(LLModelLoader::model_list models); protected: friend class LLModelLoader; @@ -394,12 +344,14 @@ class LLModelPreview : public LLViewerDynamicTexture, public LLMutex LLVector3 mPreviewTarget; LLVector3 mPreviewScale; S32 mPreviewLOD; + S32 mPhysicsSearchLOD; U32 mResourceCost; std::string mLODFile[LLModel::NUM_LODS]; bool mLoading; U32 mLoadState; bool mResetJoints; bool mRigParityWithScene; + bool mModelNoErrors; std::map mViewOption; @@ -426,6 +378,12 @@ class LLModelPreview : public LLViewerDynamicTexture, public LLMutex LLModelLoader::model_list mModel[LLModel::NUM_LODS]; LLModelLoader::model_list mBaseModel; + typedef std::vector v_LLVolumeFace_t; + typedef std::vector vv_LLVolumeFace_t; + + vv_LLVolumeFace_t mModelFacesCopy[LLModel::NUM_LODS]; + vv_LLVolumeFace_t mBaseModelFacesCopy; + U32 mGroup; std::map, U32> mObject; U32 mMaxTriangleLimit; @@ -444,16 +402,15 @@ class LLModelPreview : public LLViewerDynamicTexture, public LLMutex bool mHasPivot; float mPelvisZOffset; - + bool mRigValidJointUpload; bool mLegacyRigValid; bool mLastJointUpdate; - std::deque mMasterJointList; - std::deque mMasterLegacyJointList; - std::deque mJointsFromNode; - JointTransformMap mJointTransformMap; + JointNameSet mJointsFromNode; + JointTransformMap mJointTransformMap; + LLPointer mPreviewAvatar; }; diff --git a/indra/newview/llfloatermodeluploadbase.cpp b/indra/newview/llfloatermodeluploadbase.cpp index 70466afd00..5e95053ef6 100644 --- a/indra/newview/llfloatermodeluploadbase.cpp +++ b/indra/newview/llfloatermodeluploadbase.cpp @@ -52,7 +52,7 @@ void LLFloaterModelUploadBase::requestAgentUploadPermissions() if (!url.empty()) { - llinfos<< typeid(*this).name() <<"::requestAgentUploadPermissions() requesting for upload model permissions from: "<< url < - // // Constants // @@ -182,19 +181,12 @@ LLFloaterMute::LLFloaterMute(const LLSD& seed) : LLFloater(std::string("mute floater"), std::string("FloaterMuteRect3"), FLOATER_TITLE, RESIZE_YES, 220, 140, DRAG_ON_TOP, MINIMIZE_YES, CLOSE_YES) { - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_mute.xml", NULL, FALSE); } -// LLMuteListObserver callback interface implementation. -/* virtual */ void LLFloaterMute::onChange() -{ - refreshMuteList(); -} - BOOL LLFloaterMute::postBuild() { - childSetCommitCallback("mutes", onSelectName, this); + childSetCommitCallback("mutes", boost::bind(&LLFloaterMute::updateButtons, this)); childSetAction("Mute resident...", onClickPick, this); childSetAction("Mute object by name...", onClickMuteByName, this); childSetAction("Unmute", onClickRemove, this); @@ -233,17 +225,11 @@ void LLFloaterMute::refreshMuteList() mMuteDict.clear(); std::vector mutes = LLMuteList::getInstance()->getMutes(); - std::vector::iterator it; - U32 count = 0; - for (it = mutes.begin(); it != mutes.end(); ++it) + for (std::vector::iterator it = mutes.begin(); it != mutes.end(); ++it) { std::string display_name = it->mName; LLNameListCtrl::NameItem element; - LLUUID entry_id; - if(it->mType == LLMute::GROUP || it->mType == LLMute::AGENT) - entry_id = it->mID; - else - entry_id.generate(boost::lexical_cast( count++ )); + LLUUID entry_id = it->mID; mMuteDict.insert(std::make_pair(entry_id,*it)); element.value = entry_id; element.name = display_name; @@ -261,20 +247,20 @@ void LLFloaterMute::refreshMuteList() { case LLMute::GROUP: icon_column.value = mGroupIcon->getName(); - element.target = LLNameListCtrl::GROUP; + element.target = LLNameListItem::GROUP; break; case LLMute::AGENT: icon_column.value = mAvatarIcon->getName(); - element.target = LLNameListCtrl::INDIVIDUAL; + element.target = LLNameListItem::INDIVIDUAL; break; case LLMute::OBJECT: icon_column.value = mObjectIcon->getName(); - element.target = LLNameListCtrl::SPECIAL; + element.target = LLNameListItem::SPECIAL; break; case LLMute::BY_NAME: default: icon_column.value = mNameIcon->getName(); - element.target = LLNameListCtrl::SPECIAL; + element.target = LLNameListItem::SPECIAL; break; } @@ -299,24 +285,7 @@ void LLFloaterMute::selectMute(const LLUUID& mute_id) //----------------------------------------------------------------------------- void LLFloaterMute::updateButtons() { - if (mMuteList->getFirstSelected()) - { - childSetEnabled("Unmute", TRUE); - } - else - { - childSetEnabled("Unmute", FALSE); - } -} - -//----------------------------------------------------------------------------- -// onSelectName() -//----------------------------------------------------------------------------- -void LLFloaterMute::onSelectName(LLUICtrl *caller, void *data) -{ - LLFloaterMute *floater = (LLFloaterMute*)data; - - floater->updateButtons(); + getChildView("Unmute")->setEnabled(!!mMuteList->getFirstSelected()); } //----------------------------------------------------------------------------- @@ -328,11 +297,11 @@ void LLFloaterMute::onClickRemove(void *data) S32 last_selected = floater->mMuteList->getFirstSelectedIndex(); bool removed = false; - const std::vector items = floater->mMuteList->getAllSelected(); - for(std::vector::const_iterator it = items.begin(); it != items.end(); ++it) + uuid_vec_t items = floater->mMuteList->getSelectedIDs(); + for(uuid_vec_t::const_iterator it = items.begin(); it != items.end(); ++it) { - std::map::iterator mute_it = floater->mMuteDict.find((*it)->getUUID()); - if(mute_it != floater->mMuteDict.end() && LLMuteList::getInstance()->remove(mute_it->second)) + std::map::iterator mute_it = floater->mMuteDict.find(*it); + if (mute_it != floater->mMuteDict.end() && LLMuteList::getInstance()->remove(mute_it->second)) { floater->mMuteDict.erase(mute_it); removed = true; diff --git a/indra/newview/llfloatermute.h b/indra/newview/llfloatermute.h index 8abb6afdf6..b9a1165286 100644 --- a/indra/newview/llfloatermute.h +++ b/indra/newview/llfloatermute.h @@ -63,16 +63,16 @@ class LLFloaterMute void updateButtons(); // LLMuteListObserver callback interface implementation. - /* virtual */ void onChange(); + /* virtual */ void onChange() { refreshMuteList(); } private: // UI callbacks static void onClickRemove(void *data); static void onClickPick(void *data); - static void onSelectName(LLUICtrl* caller, void *data); void onPickUser(const uuid_vec_t& ids, const std::vector& names); static void onClickMuteByName(void*); static void callbackMuteByName(const std::string& text, void*); + void showProfile() const; private: LLNameListCtrl* mMuteList; diff --git a/indra/newview/llfloaternamedesc.cpp b/indra/newview/llfloaternamedesc.cpp index 3d0645b7c0..32730a5612 100644 --- a/indra/newview/llfloaternamedesc.cpp +++ b/indra/newview/llfloaternamedesc.cpp @@ -48,11 +48,11 @@ #include "llviewermenufile.h" // upload_new_resource() #include "lluictrlfactory.h" #include "llstring.h" -#include "lleconomy.h" // linden includes #include "llassetstorage.h" #include "llinventorytype.h" +#include "llagentbenefits.h" #include "hippogridmanager.h" @@ -134,13 +134,37 @@ BOOL LLFloaterNameDesc::postBuild() // Cancel button getChild("cancel_btn")->setCommitCallback(boost::bind(&LLFloaterNameDesc::onBtnCancel, this)); - getChild("ok_btn")->setLabelArg("[UPLOADFEE]", llformat("%s%d", gHippoGridManager->getConnectedGrid()->getCurrencySymbol().c_str(), LLGlobalEconomy::Singleton::getInstance()->getPriceUpload())); + S32 expected_upload_cost = getExpectedUploadCost(); + getChild("ok_btn")->setLabelArg("[UPLOADFEE]", llformat("%s%d", gHippoGridManager->getConnectedGrid()->getCurrencySymbol().c_str(), expected_upload_cost)); setDefaultBtn("ok_btn"); return TRUE; } +S32 LLFloaterNameDesc::getExpectedUploadCost() const +{ + std::string exten = gDirUtilp->getExtension(mFilename); + LLAssetType::EType asset_type = exten == "wav" ? LLAssetType::AT_SOUND + : (exten == "anim" || exten == "bvh") ? LLAssetType::AT_ANIMATION + : exten != "lsl" ? LLAssetType::AT_TEXTURE + : LLAssetType::AT_NONE; + S32 upload_cost = -1; + + if (asset_type != LLAssetType::AT_NONE) + { + if (!LLAgentBenefitsMgr::current().findUploadCost(asset_type, upload_cost)) + { + LL_WARNS() << "Unable to find upload cost for asset type " << asset_type << LL_ENDL; + } + } + /*else + { + LL_WARNS() << "Unable to find upload cost for " << mFilename << LL_ENDL; + }*/ + return upload_cost; +} + //----------------------------------------------------------------------------- // LLFloaterNameDesc() //----------------------------------------------------------------------------- @@ -173,14 +197,18 @@ void LLFloaterNameDesc::onBtnOK() getChildView("ok_btn")->setEnabled(FALSE); // don't allow inadvertent extra uploads LLAssetStorage::LLStoreAssetCallback callback = NULL; - S32 expected_upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(); // kinda hack - assumes that unsubclassed LLFloaterNameDesc is only used for uploading chargeable assets, which it is right now (it's only used unsubclassed for the sound upload dialog, and THAT should be a subclass). + S32 expected_upload_cost = getExpectedUploadCost(); + void *nruserdata = NULL; std::string display_name = LLStringUtil::null; + upload_new_resource(mFilenameAndPath, // file getChild("name_form")->getValue().asString(), getChild("description_form")->getValue().asString(), 0, LLFolderType::FT_NONE, LLInventoryType::IT_NONE, - LLFloaterPerms::getNextOwnerPerms(), LLFloaterPerms::getGroupPerms(), LLFloaterPerms::getEveryonePerms(), + LLFloaterPerms::getNextOwnerPerms("Uploads"), + LLFloaterPerms::getGroupPerms("Uploads"), + LLFloaterPerms::getEveryonePerms("Uploads"), display_name, callback, expected_upload_cost, nruserdata); close(false); } diff --git a/indra/newview/llfloaternamedesc.h b/indra/newview/llfloaternamedesc.h index ad7472d4f0..5b5229dd49 100644 --- a/indra/newview/llfloaternamedesc.h +++ b/indra/newview/llfloaternamedesc.h @@ -53,6 +53,8 @@ class LLFloaterNameDesc : public LLFloater void onBtnCancel(); void doCommit(); + S32 getExpectedUploadCost() const; + protected: virtual void onCommit(); diff --git a/indra/newview/llfloaternotificationsconsole.cpp b/indra/newview/llfloaternotificationsconsole.cpp index dc03d82377..555bc9d299 100644 --- a/indra/newview/llfloaternotificationsconsole.cpp +++ b/indra/newview/llfloaternotificationsconsole.cpp @@ -290,7 +290,7 @@ void LLFloaterNotification::respond() LLComboBox* responses_combo = getChild("response"); LLCtrlListInterface* response_list = responses_combo->getListInterface(); const std::string& trigger = response_list->getSelectedValue().asString(); - //llinfos << trigger << llendl; + //LL_INFOS() << trigger << LL_ENDL; LLSD response = mNote->getResponseTemplate(); response[trigger] = true; diff --git a/indra/newview/llfloaterobjectiminfo.cpp b/indra/newview/llfloaterobjectiminfo.cpp index 5d433bca62..5d26dac1b9 100644 --- a/indra/newview/llfloaterobjectiminfo.cpp +++ b/indra/newview/llfloaterobjectiminfo.cpp @@ -35,17 +35,13 @@ #include "llfloaterobjectiminfo.h" #include "llagentdata.h" -#include "llavataractions.h" -#include "llcachename.h" #include "llcommandhandler.h" -#include "llfloatergroupinfo.h" #include "llfloatermute.h" -#include "llgroupactions.h" #include "llmutelist.h" +#include "llnamebox.h" #include "llslurl.h" #include "lltrans.h" #include "llui.h" -#include "lluictrl.h" #include "lluictrlfactory.h" #include "llurlaction.h" #include "llweb.h" @@ -58,32 +54,28 @@ // LLFloaterObjectIMInfo LLFloaterObjectIMInfo::LLFloaterObjectIMInfo(const LLSD& seed) -: mObjectID(), mName(), mSLurl(), mOwnerID(), mGroupOwned(false) +: mName(), mSLurl(), mOwnerID(), mGroupOwned(false) { LLUICtrlFactory::getInstance()->buildFloater(this, "floater_object_im_info.xml"); - - if (getRect().mLeft == 0 - && getRect().mBottom == 0) - { + + const auto& rect = getRect(); + if (!rect.mLeft && !rect.mBottom) center(); - } } -BOOL LLFloaterObjectIMInfo::postBuild(void) +BOOL LLFloaterObjectIMInfo::postBuild() { - childSetAction("Mute",onClickMute,this); - childSetActionTextbox("OwnerName",onClickOwner, this); - childSetActionTextbox("Slurl",onClickMap, this); + getChild("Mute")->setCommitCallback(boost::bind(&LLFloaterObjectIMInfo::onClickMute, this)); + getChild("Slurl")->setClickedCallback(boost::bind(LLUrlAction::executeSLURL, boost::bind(std::plus(), "secondlife:///app/worldmap/", boost::ref(mSLurl)), true)); return true; } -void LLFloaterObjectIMInfo::update(LLSD& data) +void LLFloaterObjectIMInfo::update(const LLSD& data) { // Extract appropriate object information from input LLSD // (Eventually, it might be nice to query server for details // rather than require caller to pass in the information.) - mObjectID = data["object_id"].asUUID(); mName = data["name"].asString(); mOwnerID = data["owner_id"].asUUID(); mGroupOwned = data["group_owned"].asBoolean(); @@ -98,87 +90,45 @@ void LLFloaterObjectIMInfo::update(LLSD& data) childSetVisible("Unknown_Slurl",!have_slurl); childSetVisible("Slurl",have_slurl); - childSetText("ObjectName",mName); - childSetText("Slurl",mSLurl); - childSetText("OwnerName",std::string("")); + childSetText("ObjectName", mName); + std::string slurl(mSLurl); + std::string::size_type i = slurl.rfind("?owner_not_object"); + if (i != std::string::npos) + slurl.erase(i) += getString("owner"); + childSetText("Slurl", slurl); + getChild("OwnerName")->setNameID(mOwnerID, mGroupOwned ? LFIDBearer::GROUP : LFIDBearer::AVATAR); + getChildView("ObjectID")->setValue(data["object_id"].asUUID()); -// bool my_object = (owner_id == gAgentID); +// bool my_object = !mGroupOwned && (owner_id == gAgentID); // [RLVa:KB] - Version: 1.23.4 | Checked: 2009-07-08 (RLVa-1.0.0e) | Added: RLVa-0.2.0g - bool my_object = (mOwnerID == gAgentID) || ((gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (RlvUtil::isNearbyAgent(mOwnerID))); + bool my_object = !mGroupOwned && (mOwnerID == gAgentID) || ((gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES) || gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS)) && (RlvUtil::isNearbyAgent(mOwnerID))); // [/RLVa:KB] childSetEnabled("Mute",!my_object); - - if (gCacheName) gCacheName->get(mOwnerID,mGroupOwned,boost::bind(&LLFloaterObjectIMInfo::nameCallback,this,_1,_2,_3)); -} - -//static -void LLFloaterObjectIMInfo::onClickMap(void* data) -{ - LLFloaterObjectIMInfo* self = (LLFloaterObjectIMInfo*)data; - - std::string url = "secondlife://" + self->mSLurl; - LLUrlAction::showLocationOnMap(url); } -//static -void LLFloaterObjectIMInfo::onClickOwner(void* data) +void LLFloaterObjectIMInfo::onClickMute() { - LLFloaterObjectIMInfo* self = (LLFloaterObjectIMInfo*)data; - if (self->mGroupOwned) - { - LLGroupActions::show(self->mOwnerID); - } -// else // [RLVa:KB] - Version: 1.23.4 | Checked: 2009-07-08 (RLVa-1.0.0e) | Added: RLVa-0.2.0g - else if ( (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) || (!RlvUtil::isNearbyAgent(self->mOwnerID)) ) -// [/RLVa:KB] - { - LLAvatarActions::showProfile(self->mOwnerID); - } -} - -//static -void LLFloaterObjectIMInfo::onClickMute(void* data) -{ - LLFloaterObjectIMInfo* self = (LLFloaterObjectIMInfo*)data; - - LLMute::EType mute_type = (self->mGroupOwned) ? LLMute::GROUP : LLMute::AGENT; -// [RLVa:KB] - Version: 1.23.4 | Checked: 2009-07-08 (RLVa-1.0.0e) | Added: RLVa-0.2.0g - if ( (LLMute::GROUP != mute_type) && (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (RlvUtil::isNearbyAgent(self->mOwnerID)) ) - { + if (!mGroupOwned && (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES) || gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS)) && RlvUtil::isNearbyAgent(mOwnerID)) return; - } -// [/RLVa:KB] - - LLMute mute(self->mOwnerID, self->mName, mute_type); - LLMuteList::getInstance()->add(mute); - LLFloaterMute::showInstance(); - self->close(); -} - -//static -void LLFloaterObjectIMInfo::nameCallback(const LLUUID& id, const std::string& full_name, bool is_group) -{ - mName = full_name; -// [RLVa:KB] - Version: 1.23.4 | Checked: 2009-07-08 (RLVa-1.0.0e) | Added: RLVa-0.2.0g - if ( (!is_group) && (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (RlvUtil::isNearbyAgent(id)) ) - { - mName = RlvStrings::getAnonym(mName); - } // [/RLVa:KB] - childSetText("OwnerName", mName); + LLMuteList::instance().add(LLMute(mOwnerID, mName, mGroupOwned ? LLMute::GROUP : LLMute::AGENT)); + LLFloaterMute::showInstance()->selectMute(mOwnerID); + close(); } //////////////////////////////////////////////////////////////////////////// -// LLObjectIMInfoHandler +// LLObjectIMHandler //moved to llchathistory.cpp in v2 -class LLObjectIMInfoHandler : public LLCommandHandler +// support for secondlife:///app/objectim/{UUID}/ SLapps +class LLObjectIMHandler final : public LLCommandHandler { public: - LLObjectIMInfoHandler() : LLCommandHandler("objectim", UNTRUSTED_THROTTLE) { } + // requests will be throttled from a non-trusted browser + LLObjectIMHandler() : LLCommandHandler("objectim", UNTRUSTED_THROTTLE) { } - bool handle(const LLSD& params, const LLSD& query_map,LLMediaCtrl* web) + bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web) override { if (params.size() < 1) { @@ -197,12 +147,8 @@ class LLObjectIMInfoHandler : public LLCommandHandler payload["name"] = query_map["name"]; payload["slurl"] = LLWeb::escapeURL(query_map["slurl"]); payload["group_owned"] = query_map["groupowned"]; - LLFloaterObjectIMInfo::showInstance()->update(payload); - return true; } }; - -// Creating the object registers with the dispatcher. -LLObjectIMInfoHandler gObjectIMHandler; +LLObjectIMHandler gObjectIMHandler; diff --git a/indra/newview/llfloaterobjectiminfo.h b/indra/newview/llfloaterobjectiminfo.h index 58377c0091..acddd14797 100644 --- a/indra/newview/llfloaterobjectiminfo.h +++ b/indra/newview/llfloaterobjectiminfo.h @@ -35,25 +35,20 @@ #include "llfloater.h" -class LLFloaterObjectIMInfo : public LLFloater, public LLFloaterSingleton +class LLFloaterObjectIMInfo final : public LLFloater, public LLFloaterSingleton { public: LLFloaterObjectIMInfo(const LLSD& sd); virtual ~LLFloaterObjectIMInfo() { }; - /*virtual*/ BOOL postBuild(void); + BOOL postBuild() override; - void update(LLSD& payload); + void update(const LLSD& payload); // UI Handlers - static void onClickMap(void* data); - static void onClickOwner(void* data); - static void onClickMute(void* data); - - void nameCallback(const LLUUID& id, const std::string& full_name, bool is_group); + void onClickMute(); private: - LLUUID mObjectID; LLUUID mOwnerID; std::string mSLurl; std::string mName; diff --git a/indra/newview/llfloaterobjectweights.cpp b/indra/newview/llfloaterobjectweights.cpp new file mode 100644 index 0000000000..3eb19e065e --- /dev/null +++ b/indra/newview/llfloaterobjectweights.cpp @@ -0,0 +1,275 @@ +/** + * @file llfloaterobjectweights.cpp + * @brief Object weights advanced view floater + * + * $LicenseInfo:firstyear=2011&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2011, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ +#include "llviewerprecompiledheaders.h" + +#include "llfloaterobjectweights.h" + +#include "llparcel.h" + +#include "lltextbox.h" +#include "lluictrlfactory.h" + +#include "llagent.h" +#include "llfloatertools.h" // Singu Note: For placement beside the tools floater when it is opened. +#include "llviewerparcelmgr.h" +#include "llviewerregion.h" + +// virtual +bool LLCrossParcelFunctor::apply(LLViewerObject* obj) +{ + // Add the root object box. + mBoundingBox.addBBoxAgent(LLBBox(obj->getPositionRegion(), obj->getRotationRegion(), obj->getScale() * -0.5f, obj->getScale() * 0.5f).getAxisAligned()); + + // Extend the bounding box across all the children. + LLViewerObject::const_child_list_t const& children = obj->getChildren(); + for (const auto& iter : children) + { + LLViewerObject* child = iter; + mBoundingBox.addBBoxAgent(LLBBox(child->getPositionRegion(), child->getRotationRegion(), child->getScale() * -0.5f, child->getScale() * 0.5f).getAxisAligned()); + } + + bool result = false; + + LLViewerRegion* region = obj->getRegion(); + if (region) + { + std::vector boxes; + boxes.push_back(mBoundingBox); + result = region->objectsCrossParcel(boxes); + } + + return result; +} + +LLFloaterObjectWeights::LLFloaterObjectWeights(const LLSD& key) +: LLFloater(key), + mSelectedObjects(nullptr), + mSelectedPrims(nullptr), + mSelectedDownloadWeight(nullptr), + mSelectedPhysicsWeight(nullptr), + mSelectedServerWeight(nullptr), + mSelectedDisplayWeight(nullptr), + mSelectedOnLand(nullptr), + mRezzedOnLand(nullptr), + mRemainingCapacity(nullptr), + mTotalCapacity(nullptr) +{ + //buildFromFile("floater_tools.xml"); + LLUICtrlFactory::getInstance()->buildFloater(this,"floater_object_weights.xml", NULL, false); +} + +LLFloaterObjectWeights::~LLFloaterObjectWeights() +{ +} + +// virtual +BOOL LLFloaterObjectWeights::postBuild() +{ + mSelectedObjects = getChild("objects"); + mSelectedPrims = getChild("prims"); + + mSelectedDownloadWeight = getChild("download"); + mSelectedPhysicsWeight = getChild("physics"); + mSelectedServerWeight = getChild("server"); + mSelectedDisplayWeight = getChild("display"); + + mSelectedOnLand = getChild("selected"); + mRezzedOnLand = getChild("rezzed_on_land"); + mRemainingCapacity = getChild("remaining_capacity"); + mTotalCapacity = getChild("total_capacity"); + + return TRUE; +} + +// virtual +void LLFloaterObjectWeights::onOpen() +{ + const LLRect& tools_rect = gFloaterTools->getRect(); + setOrigin(tools_rect.mRight, tools_rect.mTop - getRect().getHeight()); + refresh(); + updateLandImpacts(LLViewerParcelMgr::getInstance()->getFloatingParcelSelection()->getParcel()); +} + +// virtual +void LLFloaterObjectWeights::onWeightsUpdate(const SelectionCost& selection_cost) +{ + mSelectedDownloadWeight->setText(llformat("%.2f", selection_cost.mNetworkCost)); + mSelectedPhysicsWeight->setText(llformat("%.2f", selection_cost.mPhysicsCost)); + mSelectedServerWeight->setText(llformat("%.2f", selection_cost.mSimulationCost)); + + S32 render_cost = LLSelectMgr::getInstance()->getSelection()->getSelectedObjectRenderCost(); + mSelectedDisplayWeight->setText(llformat("%d", render_cost)); + + toggleWeightsLoadingIndicators(false); +} + +//virtual +void LLFloaterObjectWeights::setErrorStatus(U32 status, const std::string& reason) +{ + const std::string text = getString("nothing_selected"); + + mSelectedDownloadWeight->setText(text); + mSelectedPhysicsWeight->setText(text); + mSelectedServerWeight->setText(text); + mSelectedDisplayWeight->setText(text); + + toggleWeightsLoadingIndicators(false); +} + +void LLFloaterObjectWeights::updateLandImpacts(const LLParcel* parcel) +{ + auto selection = LLSelectMgr::instance().getSelection(); + if (!parcel || !selection || selection->isEmpty()) + { + updateIfNothingSelected(); + } + else + { + S32 rezzed_prims = parcel->getSimWidePrimCount(); + S32 total_capacity = parcel->getSimWideMaxPrimCapacity(); + + mRezzedOnLand->setText(llformat("%d", rezzed_prims)); + mRemainingCapacity->setText(llformat("%d", total_capacity - rezzed_prims)); + mTotalCapacity->setText(llformat("%d", total_capacity)); + + toggleLandImpactsLoadingIndicators(false); + } +} + +void LLFloaterObjectWeights::refresh() +{ + auto selection = LLSelectMgr::instance().getSelection(); + + if (!selection || selection->isEmpty()) + { + updateIfNothingSelected(); + } + else + { + S32 prim_count = selection->getObjectCount(); + S32 link_count = selection->getRootObjectCount(); + F32 prim_equiv = selection->getSelectedLinksetCost(); + + mSelectedObjects->setText(llformat("%d", link_count)); + mSelectedPrims->setText(llformat("%d", prim_count)); + mSelectedOnLand->setText(llformat("%.1d", (S32)prim_equiv)); + + LLCrossParcelFunctor func; + if (selection->applyToRootObjects(&func, true)) + { + // Some of the selected objects cross parcel bounds. + // We don't display object weights and land impacts in this case. + const std::string text = getString("nothing_selected"); + + mRezzedOnLand->setText(text); + mRemainingCapacity->setText(text); + mTotalCapacity->setText(text); + + toggleLandImpactsLoadingIndicators(false); + } + + LLViewerRegion* region = gAgent.getRegion(); + if (region && region->capabilitiesReceived()) + { + for (LLObjectSelection::valid_root_iterator iter = selection->valid_root_begin(); + iter != selection->valid_root_end(); ++iter) + { + LLAccountingCostManager::getInstance()->addObject((*iter)->getObject()->getID()); + } + + std::string url = region->getCapability("ResourceCostSelected"); + if (!url.empty()) + { + // Update the transaction id before the new fetch request + generateTransactionID(); + + LLAccountingCostManager::getInstance()->fetchCosts(Roots, url, getObserverHandle()); + toggleWeightsLoadingIndicators(true); + } + } + else + { + LL_WARNS() << "Failed to get region capabilities" << LL_ENDL; + } + } +} + +// virtual +void LLFloaterObjectWeights::generateTransactionID() +{ + mTransactionID.generate(); +} + +void LLFloaterObjectWeights::toggleWeightsLoadingIndicators(bool visible) +{ + /* Singu TODO: LLLoadingIndicator + childSetVisible("download_loading_indicator", visible); + childSetVisible("physics_loading_indicator", visible); + childSetVisible("server_loading_indicator", visible); + childSetVisible("display_loading_indicator", visible); + */ + + mSelectedDownloadWeight->setVisible(!visible); + mSelectedPhysicsWeight->setVisible(!visible); + mSelectedServerWeight->setVisible(!visible); + mSelectedDisplayWeight->setVisible(!visible); +} + +void LLFloaterObjectWeights::toggleLandImpactsLoadingIndicators(bool visible) +{ + /* Singu TODO: LLLoadingIndicator + childSetVisible("selected_loading_indicator", visible); + childSetVisible("rezzed_on_land_loading_indicator", visible); + childSetVisible("remaining_capacity_loading_indicator", visible); + childSetVisible("total_capacity_loading_indicator", visible); + */ + + mSelectedOnLand->setVisible(!visible); + mRezzedOnLand->setVisible(!visible); + mRemainingCapacity->setVisible(!visible); + mTotalCapacity->setVisible(!visible); +} + +void LLFloaterObjectWeights::updateIfNothingSelected() +{ + const std::string text = getString("nothing_selected"); + + mSelectedObjects->setText(text); + mSelectedPrims->setText(text); + + mSelectedDownloadWeight->setText(text); + mSelectedPhysicsWeight->setText(text); + mSelectedServerWeight->setText(text); + mSelectedDisplayWeight->setText(text); + + mSelectedOnLand->setText(text); + mRezzedOnLand->setText(text); + mRemainingCapacity->setText(text); + mTotalCapacity->setText(text); + + toggleWeightsLoadingIndicators(false); + toggleLandImpactsLoadingIndicators(false); +} diff --git a/indra/newview/llfloaterobjectweights.h b/indra/newview/llfloaterobjectweights.h new file mode 100644 index 0000000000..018627824d --- /dev/null +++ b/indra/newview/llfloaterobjectweights.h @@ -0,0 +1,94 @@ +/** + * @file llfloaterobjectweights.h + * @brief Object weights advanced view floater + * + * $LicenseInfo:firstyear=2011&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2011, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLFLOATEROBJECTWEIGHTS_H +#define LL_LLFLOATEROBJECTWEIGHTS_H + +#include "llfloater.h" + +#include "llaccountingcostmanager.h" +#include "llselectmgr.h" + +class LLParcel; +class LLTextBox; + +/** + * struct LLCrossParcelFunctor + * + * A functor that checks whether a bounding box for all + * selected objects crosses a region or parcel bounds. + */ +struct LLCrossParcelFunctor : public LLSelectedObjectFunctor +{ + /*virtual*/ bool apply(LLViewerObject* obj); + +private: + LLBBox mBoundingBox; +}; + + +class LLFloaterObjectWeights : public LLFloater, LLAccountingCostObserver +, public LLFloaterSingleton +{ +public: + LOG_CLASS(LLFloaterObjectWeights); + + LLFloaterObjectWeights(const LLSD& key); + ~LLFloaterObjectWeights(); + + /*virtual*/ BOOL postBuild(); + + /*virtual*/ void onOpen(); + + /*virtual*/ void onWeightsUpdate(const SelectionCost& selection_cost); + /*virtual*/ void setErrorStatus(U32 status, const std::string& reason); + + void updateLandImpacts(const LLParcel* parcel); + void refresh(); + +private: + /*virtual*/ void generateTransactionID(); + + void toggleWeightsLoadingIndicators(bool visible); + void toggleLandImpactsLoadingIndicators(bool visible); + + void updateIfNothingSelected(); + + LLTextBox *mSelectedObjects; + LLTextBox *mSelectedPrims; + + LLTextBox *mSelectedDownloadWeight; + LLTextBox *mSelectedPhysicsWeight; + LLTextBox *mSelectedServerWeight; + LLTextBox *mSelectedDisplayWeight; + + LLTextBox *mSelectedOnLand; + LLTextBox *mRezzedOnLand; + LLTextBox *mRemainingCapacity; + LLTextBox *mTotalCapacity; +}; + +#endif //LL_LLFLOATEROBJECTWEIGHTS_H diff --git a/indra/newview/llfloateropenobject.cpp b/indra/newview/llfloateropenobject.cpp index 6cea68f665..14f5965f67 100644 --- a/indra/newview/llfloateropenobject.cpp +++ b/indra/newview/llfloateropenobject.cpp @@ -129,7 +129,7 @@ void LLFloaterOpenObject::dirty() -void LLFloaterOpenObject::moveToInventory(bool wear) +void LLFloaterOpenObject::moveToInventory(bool wear, bool replace) { if (mObjectSelection->getRootObjectCount() != 1) { @@ -157,40 +157,34 @@ void LLFloaterOpenObject::moveToInventory(bool wear) parent_category_id = gInventory.getRootFolderID(); } - LLCategoryCreate* cat_data = new LLCategoryCreate(object_id, wear); - + inventory_func_type func = boost::bind(LLFloaterOpenObject::callbackCreateInventoryCategory,_1,object_id,wear,replace); LLUUID category_id = gInventory.createNewCategory(parent_category_id, - LLFolderType::FT_NONE, - name, - callbackCreateInventoryCategory, - (void*)cat_data); + LLFolderType::FT_NONE, + name, + func); //If we get a null category ID, we are using a capability in createNewCategory and we will //handle the following in the callbackCreateInventoryCategory routine. if ( category_id.notNull() ) { - LLSD result; - result["folder_id"] = category_id; //Reduce redundant code by just calling the callback. Dur. - callbackCreateInventoryCategory(result,cat_data); + callbackCreateInventoryCategory(category_id, object_id, wear); } } // static -void LLFloaterOpenObject::callbackCreateInventoryCategory(const LLSD& result, void* data) +void LLFloaterOpenObject::callbackCreateInventoryCategory(const LLUUID& category_id, LLUUID object_id, bool wear, bool replace) { - LLCategoryCreate* cat_data = (LLCategoryCreate*)data; - - LLUUID category_id = result["folder_id"].asUUID(); LLCatAndWear* wear_data = new LLCatAndWear; wear_data->mCatID = category_id; - wear_data->mWear = cat_data->mWear; + wear_data->mWear = wear; wear_data->mFolderResponded = true; - + wear_data->mReplace = replace; + // Copy and/or move the items into the newly created folder. // Ignore any "you're going to break this item" messages. - BOOL success = move_inv_category_world_to_agent(cat_data->mObjectID, category_id, TRUE, + BOOL success = move_inv_category_world_to_agent(object_id, category_id, TRUE, callbackMoveInventory, (void*)wear_data); if (!success) @@ -200,7 +194,6 @@ void LLFloaterOpenObject::callbackCreateInventoryCategory(const LLSD& result, vo LLNotificationsUtil::add("OpenObjectCannotCopy"); } - delete cat_data; } // static diff --git a/indra/newview/llfloateropenobject.h b/indra/newview/llfloateropenobject.h index 7639fd9f88..1f5137c4d6 100644 --- a/indra/newview/llfloateropenobject.h +++ b/indra/newview/llfloateropenobject.h @@ -64,6 +64,7 @@ class LLFloaterOpenObject LLUUID mCatID; bool mWear; bool mFolderResponded; + bool mReplace; }; protected: @@ -73,11 +74,11 @@ class LLFloaterOpenObject void refresh(); void draw(); - void moveToInventory(bool wear); + void moveToInventory(bool wear, bool replace = false); static void onClickMoveToInventory(void* data); static void onClickMoveAndWear(void* data); - static void callbackCreateInventoryCategory(const LLSD& result, void* data); + static void callbackCreateInventoryCategory(const LLUUID& category_id, LLUUID object_id, bool wear, bool replace = false); static void callbackMoveInventory(S32 result, void* data); static void* createPanelInventory(void* data); diff --git a/indra/newview/llfloateroutbox.cpp b/indra/newview/llfloateroutbox.cpp deleted file mode 100644 index 07b626de93..0000000000 --- a/indra/newview/llfloateroutbox.cpp +++ /dev/null @@ -1,643 +0,0 @@ -/** - * @file llfloateroutbox.cpp - * @brief Implementation of the merchant outbox window - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llfloateroutbox.h" - -#include "llfolderview.h" -#include "llinventorybridge.h" -#include "llinventorymodelbackgroundfetch.h" -#include "llinventoryobserver.h" -#include "llinventorypanel.h" -#include "llmarketplacefunctions.h" -#include "llnotifications.h" -#include "llnotificationsutil.h" -#include "lltextbox.h" -#include "lltexteditor.h" -//#include "lltransientfloatermgr.h" -#include "lltrans.h" -#include "llviewernetwork.h" -//#include "llwindowshade.h" - -#define USE_WINDOWSHADE_DIALOGS 0 - - -///---------------------------------------------------------------------------- -/// LLOutboxNotification class -///---------------------------------------------------------------------------- - -class LLOutboxNotification -{ -public: - bool processNotification(const LLSD& notify) - { - LLFloaterOutbox* outbox_floater = LLFloaterOutbox::getInstance(); - - outbox_floater->showNotification(notify); - - return false; - } -}; - -///---------------------------------------------------------------------------- -/// LLOutboxAddedObserver helper class -///---------------------------------------------------------------------------- - -class LLOutboxAddedObserver : public LLInventoryCategoryAddedObserver -{ -public: - LLOutboxAddedObserver(LLFloaterOutbox * outboxFloater) - : LLInventoryCategoryAddedObserver() - , mOutboxFloater(outboxFloater) - { - } - - void done() - { - for (cat_vec_t::iterator it = mAddedCategories.begin(); it != mAddedCategories.end(); ++it) - { - LLViewerInventoryCategory* added_category = *it; - - LLFolderType::EType added_category_type = added_category->getPreferredType(); - - if (added_category_type == LLFolderType::FT_OUTBOX) - { - mOutboxFloater->initializeMarketPlace(); - } - } - } - -private: - LLFloaterOutbox * mOutboxFloater; -}; - -///---------------------------------------------------------------------------- -/// LLFloaterOutbox -///---------------------------------------------------------------------------- - -LLFloaterOutbox::LLFloaterOutbox(const LLSD& key) - : LLFloater(key) - , mCategoriesObserver(NULL) - , mCategoryAddedObserver(NULL) - , mImportBusy(false) - , mImportButton(NULL) - , mInventoryFolderCountText(NULL) - , mInventoryImportInProgress(NULL) - , mInventoryPlaceholder(NULL) - , mInventoryText(NULL) - , mInventoryTitle(NULL) - , mOutboxId(LLUUID::null) - , mOutboxInventoryPanel(NULL) - , mOutboxItemCount(0) - , mOutboxTopLevelDropZone(NULL) -// , mWindowShade(NULL) -{ - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_merchant_outbox.xml"); - -} - -LLFloaterOutbox::~LLFloaterOutbox() -{ - if (mCategoriesObserver && gInventory.containsObserver(mCategoriesObserver)) - { - gInventory.removeObserver(mCategoriesObserver); - } - delete mCategoriesObserver; - - if (mCategoryAddedObserver && gInventory.containsObserver(mCategoryAddedObserver)) - { - gInventory.removeObserver(mCategoryAddedObserver); - } - delete mCategoryAddedObserver; -} - -BOOL LLFloaterOutbox::postBuild() -{ - mInventoryFolderCountText = getChild("outbox_folder_count"); - mInventoryImportInProgress = getChild("import_progress_indicator"); - mInventoryPlaceholder = getChild("outbox_inventory_placeholder_panel"); - mInventoryText = mInventoryPlaceholder->getChild("outbox_inventory_placeholder_text"); - // For some reason, adding style doesn't work unless this is true. - mInventoryText->setParseHTML(TRUE); - - mInventoryTitle = mInventoryPlaceholder->getChild("outbox_inventory_placeholder_title"); - - mImportButton = getChild("outbox_import_btn"); - mImportButton->setCommitCallback(boost::bind(&LLFloaterOutbox::onImportButtonClicked, this)); - - // - // Set up the outbox inventory view - // - mOutboxInventoryPanel = getChild("panel_outbox_inventory"); - llassert(mOutboxInventoryPanel); - - mOutboxTopLevelDropZone = getChild("outbox_generic_drag_target"); - - LLFocusableElement::setFocusReceivedCallback(boost::bind(&LLFloaterOutbox::onFocusReceived, this)); - - // Observe category creation to catch outbox creation (moot if already existing) - mCategoryAddedObserver = new LLOutboxAddedObserver(this); - gInventory.addObserver(mCategoryAddedObserver); - - return TRUE; -} - -void LLFloaterOutbox::onClose(bool app_quitting) -{ -/* - if (mWindowShade) - { - delete mWindowShade; - - mWindowShade = NULL; - } -*/ - setVisible(FALSE); - //destroy(); //Don't because outbox should be persistent. -} - -void LLFloaterOutbox::onOpen() -{ - // - // Initialize the Market Place or go update the outbox - // - - if (LLMarketplaceInventoryImporter::getInstance()->getMarketPlaceStatus() == MarketplaceStatusCodes::MARKET_PLACE_NOT_INITIALIZED) - { - initializeMarketPlace(); - } - else - { - setupOutbox(); - } - - // - // Update the floater view - // - updateView(); - - // - // Trigger fetch of outbox contents - // - fetchOutboxContents(); -} - -void LLFloaterOutbox::onFocusReceived() -{ - fetchOutboxContents(); -} - -void LLFloaterOutbox::fetchOutboxContents() -{ - if (mOutboxId.notNull()) - { - LLInventoryModelBackgroundFetch::instance().start(mOutboxId); - } -} - -void LLFloaterOutbox::setupOutbox() -{ - if (LLMarketplaceInventoryImporter::getInstance()->getMarketPlaceStatus() != MarketplaceStatusCodes::MARKET_PLACE_MERCHANT) - { - // If we are *not* a merchant or we have no market place connection established yet, do nothing - return; - } - - // We are a merchant. Get the outbox, create it if needs be. - mOutboxId = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, true, false); - if (mOutboxId.isNull()) - { - // We should never get there unles inventory fails badly - llerrs << "Inventory problem: failure to create the outbox for a merchant!" << llendl; - return; - } - - // No longer need to observe new category creation - if (mCategoryAddedObserver && gInventory.containsObserver(mCategoryAddedObserver)) - { - gInventory.removeObserver(mCategoryAddedObserver); - delete mCategoryAddedObserver; - mCategoryAddedObserver = NULL; - } - llassert(!mCategoryAddedObserver); - - // Create observer for outbox modifications - if (mCategoriesObserver == NULL) - { - mCategoriesObserver = new LLInventoryCategoriesObserver(); - gInventory.addObserver(mCategoriesObserver); - mCategoriesObserver->addCategory(mOutboxId, boost::bind(&LLFloaterOutbox::onOutboxChanged, this)); - } - llassert(mCategoriesObserver); - - // Set up the outbox inventory view - // Singu Note: we handle this in postBuild, grabbing the panel from the built xml. - - // Reshape the inventory to the proper size - LLRect inventory_placeholder_rect = mInventoryPlaceholder->getRect(); - mOutboxInventoryPanel->setShape(inventory_placeholder_rect); - - // Set the sort order newest to oldest - mOutboxInventoryPanel->setSortOrder(LLInventoryFilter::SO_FOLDERS_BY_NAME); - mOutboxInventoryPanel->getFilter()->markDefault(); - - // Get the content of the outbox - fetchOutboxContents(); -} - -void LLFloaterOutbox::initializeMarketPlace() -{ - // - // Initialize the marketplace import API - // - - LLMarketplaceInventoryImporter& importer = LLMarketplaceInventoryImporter::instance(); - - importer.setInitializationErrorCallback(boost::bind(&LLFloaterOutbox::initializationReportError, this, _1, _2)); - importer.setStatusChangedCallback(boost::bind(&LLFloaterOutbox::importStatusChanged, this, _1)); - importer.setStatusReportCallback(boost::bind(&LLFloaterOutbox::importReportResults, this, _1, _2)); - importer.initialize(); -} - -void LLFloaterOutbox::setStatusString(const std::string& statusString) -{ - llassert(mInventoryFolderCountText != NULL); - - mInventoryFolderCountText->setText(statusString); -} - -void LLFloaterOutbox::updateFolderCount() -{ - S32 item_count = 0; - - if (mOutboxId.notNull()) - { - LLInventoryModel::cat_array_t * cats; - LLInventoryModel::item_array_t * items; - gInventory.getDirectDescendentsOf(mOutboxId, cats, items); - - item_count = cats->count() + items->count(); - } - - mOutboxItemCount = item_count; - - if (!mImportBusy) - { - updateFolderCountStatus(); - } -} - -void LLFloaterOutbox::updateFolderCountStatus() -{ - if (mOutboxInventoryPanel) - { - switch (mOutboxItemCount) - { - case 0: setStatusString(getString("OutboxFolderCount0")); break; - case 1: setStatusString(getString("OutboxFolderCount1")); break; - default: - { - std::string item_count_str = llformat("%d", mOutboxItemCount); - - LLStringUtil::format_map_t args; - args["[NUM]"] = item_count_str; - - setStatusString(getString("OutboxFolderCountN", args)); - break; - } - } - } - - mImportButton->setEnabled(mOutboxItemCount > 0); -} - -void LLFloaterOutbox::updateView() -{ - //updateView() is called twice the first time. - updateFolderCount(); - - if (mOutboxItemCount > 0) - { - mOutboxInventoryPanel->setVisible(TRUE); - mInventoryPlaceholder->setVisible(FALSE); - mOutboxTopLevelDropZone->setVisible(TRUE); - } - else - { - if (mOutboxInventoryPanel) - { - mOutboxInventoryPanel->setVisible(FALSE); - } - - // Show the drop zone if there is an outbox folder - mOutboxTopLevelDropZone->setVisible(mOutboxId.notNull()); - - mInventoryPlaceholder->setVisible(TRUE); - - std::string outbox_text; - std::string outbox_text2; - std::string outbox_title; - std::string outbox_tooltip; - - const LLSD& subs = getMarketplaceStringSubstitutions(); - U32 mkt_status = LLMarketplaceInventoryImporter::getInstance()->getMarketPlaceStatus(); - - // Text styles for marketplace hyperlinks - std::string subs_link; - std::string subs_text; - - if (mOutboxId.notNull()) - { - // "Outbox is empty!" message strings - outbox_text = LLTrans::getString("InventoryOutboxNoItems"); - subs_link = "[MARKETPLACE_DASHBOARD_URL]"; - subs_text = " " + LLTrans::getString("InventoryOutboxNoItemsSubs"); - outbox_text2 = LLTrans::getString("InventoryOutboxNoItems2"); - outbox_title = LLTrans::getString("InventoryOutboxNoItemsTitle"); - outbox_tooltip = LLTrans::getString("InventoryOutboxNoItemsTooltip"); - } - else if (mkt_status <= MarketplaceStatusCodes::MARKET_PLACE_INITIALIZING) - { - // "Initializing!" message strings - outbox_text = LLTrans::getString("InventoryOutboxInitializing"); - subs_link = "[MARKETPLACE_CREATE_STORE_URL]"; - subs_text = " " + LLTrans::getString("InventoryOutboxInitializingSubs"); - outbox_text2 = LLTrans::getString("InventoryOutboxInitializing2"); - outbox_title = LLTrans::getString("InventoryOutboxInitializingTitle"); - outbox_tooltip = LLTrans::getString("InventoryOutboxInitializingTooltip"); - } - else if (mkt_status == MarketplaceStatusCodes::MARKET_PLACE_NOT_MERCHANT) - { - // "Not a merchant!" message strings - outbox_text = LLTrans::getString("InventoryOutboxNotMerchant"); - subs_link = "[MARKETPLACE_CREATE_STORE_URL]"; - subs_text = " " + LLTrans::getString("InventoryOutboxNotMerchantSubs"); - outbox_text2 = LLTrans::getString("InventoryOutboxNotMerchant2"); - outbox_title = LLTrans::getString("InventoryOutboxNotMerchantTitle"); - outbox_tooltip = LLTrans::getString("InventoryOutboxNotMerchantTooltip"); - } - else - { - // "Errors!" message strings - outbox_text = LLTrans::getString("InventoryOutboxError"); - subs_link = "[MARKETPLACE_CREATE_STORE_URL]"; - subs_text = " " + LLTrans::getString("InventoryOutboxErrorSubs"); - outbox_text2 = " " + LLTrans::getString("InventoryOutboxError2"); - outbox_title = LLTrans::getString("InventoryOutboxErrorTitle"); - outbox_tooltip = LLTrans::getString("InventoryOutboxErrorTooltip"); - } - - mInventoryText->clear(); - const LLColor4 color = gColors.getColor("TextFgReadOnlyColor"); - mInventoryText->appendColoredText(outbox_text, false, false, color); - LLStringUtil::format(subs_link, subs); - LLStyleSP subs_link_style(new LLStyle); - subs_link_style->setLinkHREF(subs_link); - subs_link_style->setColor(gSavedSettings.getColor4("HTMLLinkColor")); - mInventoryText->appendStyledText(subs_text, false, false, subs_link_style); - mInventoryText->appendColoredText(outbox_text2, false, false, color); - mInventoryTitle->setValue(outbox_title); - mInventoryPlaceholder->getParent()->setToolTip(outbox_tooltip); - } -} - -bool isAccepted(EAcceptance accept) -{ - return (accept >= ACCEPT_YES_COPY_SINGLE); -} - -BOOL LLFloaterOutbox::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg) -{ - if ((mOutboxInventoryPanel == NULL) || - //(mWindowShade && mWindowShade->isShown()) || - LLMarketplaceInventoryImporter::getInstance()->isImportInProgress()) - { - return FALSE; - } - - LLView * handled_view = childrenHandleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); - BOOL handled = (handled_view != NULL); - - // Determine if the mouse is inside the inventory panel itself or just within the floater - bool pointInInventoryPanel = false; - bool pointInInventoryPanelChild = false; - LLFolderView * root_folder = mOutboxInventoryPanel->getRootFolder(); - if (mOutboxInventoryPanel->getVisible()) - { - S32 inv_x, inv_y; - localPointToOtherView(x, y, &inv_x, &inv_y, mOutboxInventoryPanel); - - pointInInventoryPanel = mOutboxInventoryPanel->getRect().pointInRect(inv_x, inv_y); - - LLView * inventory_panel_child_at_point = mOutboxInventoryPanel->childFromPoint(inv_x, inv_y, true); - pointInInventoryPanelChild = (inventory_panel_child_at_point != root_folder); - } - - // Pass all drag and drop for this floater to the outbox inventory control - if (!handled || !isAccepted(*accept)) - { - // Handle the drag and drop directly to the root of the outbox if we're not in the inventory panel - // (otherwise the inventory panel itself will handle the drag and drop operation, without any override) - if (!pointInInventoryPanel) - { - handled = root_folder->handleDragAndDropToThisFolder(mask, drop, cargo_type, cargo_data, accept, tooltip_msg); - } - - mOutboxTopLevelDropZone->setBackgroundVisible(handled && !drop && isAccepted(*accept)); - } - else - { - mOutboxTopLevelDropZone->setBackgroundVisible(!pointInInventoryPanelChild); - } - - return handled; -} - -BOOL LLFloaterOutbox::handleHover(S32 x, S32 y, MASK mask) -{ - mOutboxTopLevelDropZone->setBackgroundVisible(FALSE); - - return LLFloater::handleHover(x, y, mask); -} -/* -void LLFloaterOutbox::onMouseLeave(S32 x, S32 y, MASK mask) -{ - mOutboxTopLevelDropZone->setBackgroundVisible(FALSE); - - LLFloater::onMouseLeave(x, y, mask); -} -*/ -void LLFloaterOutbox::onImportButtonClicked() -{ - mOutboxInventoryPanel->clearSelection(); - - mImportBusy = LLMarketplaceInventoryImporter::instance().triggerImport(); -} - -void LLFloaterOutbox::onOutboxChanged() -{ - llassert(!mOutboxId.isNull()); - - if (mOutboxInventoryPanel) - { - mOutboxInventoryPanel->requestSort(); - } - - fetchOutboxContents(); - - updateView(); -} - -void LLFloaterOutbox::importReportResults(U32 status, const LLSD& content) -{ - if (status == MarketplaceErrorCodes::IMPORT_DONE) - { - LLNotificationsUtil::add("OutboxImportComplete"); - } - else if (status == MarketplaceErrorCodes::IMPORT_DONE_WITH_ERRORS) - { - const LLSD& subs = getMarketplaceStringSubstitutions(); - - LLNotificationsUtil::add("OutboxImportHadErrors", subs); - } - else - { - char status_string[16]; - sprintf(status_string, "%d", status); - - LLSD subs; - subs["[ERROR_CODE]"] = status_string; - - LLNotificationsUtil::add("OutboxImportFailed", subs); - } - - updateView(); -} - -void LLFloaterOutbox::importStatusChanged(bool inProgress) -{ - if (mOutboxId.isNull() && (LLMarketplaceInventoryImporter::getInstance()->getMarketPlaceStatus() == MarketplaceStatusCodes::MARKET_PLACE_MERCHANT)) - { - setupOutbox(); - } - - if (inProgress) - { - if (mImportBusy) - { - setStatusString(getString("OutboxImporting")); - } - else - { - setStatusString(getString("OutboxInitializing")); - } - - mImportBusy = true; - mImportButton->setEnabled(false); - mInventoryImportInProgress->setVisible(true); - } - else - { - setStatusString(""); - mImportBusy = false; - mImportButton->setEnabled(mOutboxItemCount > 0); - mInventoryImportInProgress->setVisible(false); - } - - updateView(); -} - -void LLFloaterOutbox::initializationReportError(U32 status, const LLSD& content) -{ - if (status >= MarketplaceErrorCodes::IMPORT_BAD_REQUEST) - { - char status_string[16]; - sprintf(status_string, "%d", status); - - LLSD subs; - subs["[ERROR_CODE]"] = status_string; - - LLNotificationsUtil::add("OutboxInitFailed", subs); - } - - updateView(); -} - -void LLFloaterOutbox::showNotification(const LLSD& notify) -{ - LLNotificationPtr notification = LLNotifications::instance().find(notify["id"].asUUID()); - - if (!notification) - { - llerrs << "Unable to find outbox notification!" << notify.asString() << llendl; - - return; - } - -#if USE_WINDOWSHADE_DIALOGS - - if (mWindowShade) - { - delete mWindowShade; - } - - LLRect floater_rect = getLocalRect(); - floater_rect.mTop -= getHeaderHeight(); - floater_rect.stretch(-5, 0); - - LLWindowShade::Params params; - params.name = "notification_shade"; - params.rect = floater_rect; - params.follows.flags = FOLLOWS_ALL; - params.modal = true; - params.can_close = false; - params.shade_color = LLColor4::white % 0.25f; - params.text_color = LLColor4::white; - - mWindowShade = LLUICtrlFactory::create(params); - - addChild(mWindowShade); - mWindowShade->show(notification); - -#else //USE_WINDOWSHADE_DIALOGS -/* - LLNotificationsUI::LLEventHandler * handler = - LLNotificationsUI::LLNotificationManager::instance().getHandlerForNotification("alertmodal"); - - LLNotificationsUI::LLSysHandler * sys_handler = dynamic_cast(handler); - llassert(sys_handler); - - sys_handler->processNotification(notify); -*/ - LLNotifications::instance().add(notification); -#endif //USE_WINDOWSHADE_DIALOGS -} - diff --git a/indra/newview/llfloateroutbox.h b/indra/newview/llfloateroutbox.h deleted file mode 100644 index 9f9222cb63..0000000000 --- a/indra/newview/llfloateroutbox.h +++ /dev/null @@ -1,116 +0,0 @@ -/** - * @file llfloateroutbox.h - * @brief LLFloaterOutbox - * class definition - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * ABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLFLOATEROUTBOX_H -#define LL_LLFLOATEROUTBOX_H - -#include "llfloater.h" -#include "llfoldertype.h" -#include "llnotificationptr.h" - - -class LLButton; -class LLInventoryCategoriesObserver; -class LLInventoryCategoryAddedObserver; -class LLInventoryPanel; -class LLLoadingIndicator; -class LLNotification; -class LLTextBox; -class LLTextEditor; -class LLView; -//class LLWindowShade; - - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLFloaterOutbox -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -class LLFloaterOutbox : public LLFloater, public LLFloaterSingleton -{ -public: - LLFloaterOutbox(const LLSD& key); - ~LLFloaterOutbox(); - - void initializeMarketPlace(); - - // virtuals - BOOL postBuild(); - BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg); - - void showNotification(const LLSD& notify); - - BOOL handleHover(S32 x, S32 y, MASK mask); -// void onMouseLeave(S32 x, S32 y, MASK mask); - -protected: - void setupOutbox(); - void fetchOutboxContents(); - - void importReportResults(U32 status, const LLSD& content); - void importStatusChanged(bool inProgress); - void initializationReportError(U32 status, const LLSD& content); - - void onClose(bool app_quitting); - void onOpen(); - - void onFocusReceived(); - - void onImportButtonClicked(); - void onOutboxChanged(); - - void setStatusString(const std::string& statusString); - - void updateFolderCount(); - void updateFolderCountStatus(); - void updateView(); - -private: - LLInventoryCategoriesObserver * mCategoriesObserver; - LLInventoryCategoryAddedObserver * mCategoryAddedObserver; - - bool mImportBusy; - LLButton * mImportButton; - - LLTextBox * mInventoryFolderCountText; - LLView * mInventoryImportInProgress; - LLView * mInventoryPlaceholder; - LLTextEditor * mInventoryText; - LLTextBox * mInventoryTitle; - - LLUUID mOutboxId; - LLInventoryPanel * mOutboxInventoryPanel; - U32 mOutboxItemCount; - LLPanel * mOutboxTopLevelDropZone; - - //LLWindowShade * mWindowShade; -}; - -#endif // LL_LLFLOATEROUTBOX_H diff --git a/indra/newview/llfloaterpathfindingcharacters.cpp b/indra/newview/llfloaterpathfindingcharacters.cpp index d5e7fc0891..0cccc80f76 100644 --- a/indra/newview/llfloaterpathfindingcharacters.cpp +++ b/indra/newview/llfloaterpathfindingcharacters.cpp @@ -219,7 +219,7 @@ LLSD LLFloaterPathfindingCharacters::buildCharacterScrollListItemData(const LLPa columns[2]["column"] = "owner"; columns[2]["value"] = getOwnerName(pCharacterPtr); - S32 cpuTime = llround(pCharacterPtr->getCPUTime()); + S32 cpuTime = ll_round(pCharacterPtr->getCPUTime()); std::string cpuTimeString = llformat("%d", cpuTime); LLStringUtil::format_map_t string_args; string_args["[CPU_TIME]"] = cpuTimeString; diff --git a/indra/newview/llfloaterpathfindinglinksets.cpp b/indra/newview/llfloaterpathfindinglinksets.cpp index 35f6b9c1f4..8352d140cc 100644 --- a/indra/newview/llfloaterpathfindinglinksets.cpp +++ b/indra/newview/llfloaterpathfindinglinksets.cpp @@ -77,6 +77,7 @@ LLFloaterPathfindingLinksets::LLFloaterPathfindingLinksets(const LLSD& pSeed) mFilterByDescription(NULL), mFilterByLinksetUse(NULL), mEditLinksetUse(NULL), + mEditLinksetUseUnset(nullptr), mEditLinksetUseWalkable(NULL), mEditLinksetUseStaticObstacle(NULL), mEditLinksetUseDynamicObstacle(NULL), diff --git a/indra/newview/llfloaterpathfindingobjects.cpp b/indra/newview/llfloaterpathfindingobjects.cpp index 8a606a07b5..f8c1700630 100644 --- a/indra/newview/llfloaterpathfindingobjects.cpp +++ b/indra/newview/llfloaterpathfindingobjects.cpp @@ -41,7 +41,6 @@ #include "llavatarnamecache.h" #include "llbutton.h" #include "llcheckboxctrl.h" -#include "llenvmanager.h" #include "llfloater.h" #include "llfontgl.h" #include "llnotifications.h" @@ -84,7 +83,7 @@ void LLFloaterPathfindingObjects::onOpen(/*const LLSD &pKey*/) if (!mRegionBoundaryCrossingSlot.connected()) { - mRegionBoundaryCrossingSlot = LLEnvManagerNew::getInstance()->setRegionChangeCallback(boost::bind(&LLFloaterPathfindingObjects::onRegionBoundaryCrossed, this)); + mRegionBoundaryCrossingSlot = gAgent.addRegionChangedCallback(boost::bind(&LLFloaterPathfindingObjects::onRegionBoundaryCrossed, this)); } if (!mGodLevelChangeSlot.connected()) @@ -384,23 +383,34 @@ void LLFloaterPathfindingObjects::buildObjectsScrollList(const LLPathfindingObje void LLFloaterPathfindingObjects::addObjectToScrollList(const LLPathfindingObjectPtr pObjectPtr, const LLSD &pScrollListItemData) { - LLSD rowParams; - rowParams["id"] = pObjectPtr->getUUID(); + LLScrollListCell::Params cellParams; + //cellParams.font = LLFontGL::getFontSansSerif(); + + LLScrollListItem::Params rowParams; + rowParams.value = pObjectPtr->getUUID().asString(); llassert(pScrollListItemData.isArray()); - S32 idx = 0; for (LLSD::array_const_iterator cellIter = pScrollListItemData.beginArray(); cellIter != pScrollListItemData.endArray(); ++cellIter) { - rowParams["columns"][idx] = *cellIter; - idx++; + const LLSD &cellElement = *cellIter; + + llassert(cellElement.has("column")); + llassert(cellElement.get("column").isString()); + cellParams.column = cellElement.get("column").asString(); + + llassert(cellElement.has("value")); + llassert(cellElement.get("value").isString()); + cellParams.value = cellElement.get("value").asString(); + + rowParams.columns.add(cellParams); } - LLScrollListItem *scrollListItem = mObjectsScrollList->addElement(rowParams); + LLScrollListItem *scrollListItem = mObjectsScrollList->addRow(rowParams); if (pObjectPtr->hasOwner() && !pObjectPtr->hasOwnerName()) { - mMissingNameObjectsScrollListItems.insert(std::make_pair(pObjectPtr->getUUID().asString(), scrollListItem)); + mMissingNameObjectsScrollListItems.insert(std::make_pair(pObjectPtr->getUUID().asString(), scrollListItem)); pObjectPtr->registerOwnerNameListener(boost::bind(&LLFloaterPathfindingObjects::handleObjectNameResponse, this, _1)); } } diff --git a/indra/newview/llfloaterpermissionsmgr.cpp b/indra/newview/llfloaterpermissionsmgr.cpp deleted file mode 100644 index 750cd8bfd5..0000000000 --- a/indra/newview/llfloaterpermissionsmgr.cpp +++ /dev/null @@ -1,154 +0,0 @@ -/** - * @file llfloaterpermissionsmgr.cpp - * @brief for user control of script permissions - * - * $LicenseInfo:firstyear=2003&license=viewergpl$ - * - * Copyright (c) 2003-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llfloaterpermissionsmgr.h" - -#include "llscrollcontainer.h" -#include "lltextbox.h" -#include "llbutton.h" -#include "llagent.h" -#include "llviewerobjectlist.h" -#include "llviewerregion.h" -#include "llstl.h" - -// constants -const S32 MIN_PERM_MGR_WIDTH = 100; -const S32 MIN_PERM_MGR_HEIGHT = 100; -const S32 VPAD = 8; -const S32 HPAD = 8; -const S32 LINE = 16; - -// statics -LLFloaterPermissionsMgr* LLFloaterPermissionsMgr::sInstance = NULL; - -LLFloaterPermissionsMgr* LLFloaterPermissionsMgr::show() -{ - if (!sInstance) - { - sInstance = new LLFloaterPermissionsMgr(); - - sInstance->open(); /* Flawfinder: ignore */ - gFloaterView->adjustToFitScreen(sInstance, TRUE); - } - else - { - sInstance->open(); /* Flawfinder: ignore */ - } - - return sInstance; -} - -void LLFloaterPermissionsMgr::processPermissionsList(LLMessageSystem* msg, void**) -{ -} - -LLFloaterPermissionsMgr::LLFloaterPermissionsMgr() : - LLFloater(std::string("floater_perm_mgr"), std::string("PermissionsManagerRect"), std::string("Permissions Manager"), - TRUE, MIN_PERM_MGR_WIDTH, MIN_PERM_MGR_HEIGHT) -{ - S32 y = getRect().getHeight() - VPAD - LINE; - LLRect scrollable_container_rect(0, y, getRect().getWidth(), 0); - LLRect permissions_rect(0, 0, getRect().getWidth() - HPAD - HPAD, 0); - mPermissions = new LLPermissionsView(permissions_rect); - mScroller = new LLScrollContainer( - std::string("permissions container"), - scrollable_container_rect, - mPermissions - ); - mScroller->setFollowsAll(); - mScroller->setReserveScrollCorner(TRUE); - addChild(mScroller); -} - -LLFloaterPermissionsMgr::~LLFloaterPermissionsMgr() -{ -} - - -// -// LLPermissionsView -// - -LLPermissionsView::LLPermissionsView(const LLRect &rect) : LLView(std::string("permissions_view"), rect, TRUE, FOLLOWS_NONE) -{ -} - -void LLPermissionsView::clearPermissionsData() -{ - deleteAllChildren(); -} - -void LLPermissionsView::addPermissionsData(const std::string& object_name, const LLUUID& object_id, U32 permissions_flags) -{ - // grow to make room for new element - reshape(getRect().getWidth(), getRect().getHeight() + LINE + VPAD + BTN_HEIGHT + VPAD); - S32 y = getRect().getHeight() - LINE - VPAD; - LLRect label_rect(HPAD, y + LINE, getRect().getWidth(), y); - LLTextBox* text = new LLTextBox(std::string("perm_label"), label_rect, object_name); - text->setFollows(FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_BOTTOM); - addChild(text); - - y -= LINE + VPAD; - - LLRect btn_rect(HPAD, y + BTN_HEIGHT, 120, y); - LLButton* button = new LLButton(std::string("Revoke permissions"), btn_rect, LLStringUtil::null, boost::bind(&LLPermissionsView::revokePermissions, object_id, permissions_flags)); - button->setFollows(FOLLOWS_LEFT | FOLLOWS_BOTTOM); - addChild(button); - - /*btn_rect.set(HPAD + 120 + HPAD, y + BTN_HEIGHT, HPAD + 120 + HPAD + 120, y); - button = new LLButton(std::string("Find in world"), btn_rect, LLStringUtil::null, boost::bind(&LLPermissionsView::findObject, object_id, permissions_flags)); - button->setFollows(FOLLOWS_LEFT | FOLLOWS_BOTTOM); - addChild(button);*/ -} - -void LLPermissionsView::revokePermissions(const LLUUID& object_id, U32 permission_flags) -{ - LLViewerObject* objectp = gObjectList.findObject(object_id); - if (objectp) - { - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_RevokePermissions); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_Data); - msg->addUUIDFast(_PREHASH_ObjectID, object_id); - msg->addU32Fast(_PREHASH_ObjectPermissions, permission_flags); - msg->sendReliable(objectp->getRegion()->getHost()); - } -} - -/*void LLPermissionsView::findObject(const LLUUID& object_id, U32 permission_flags) -{ -}*/ diff --git a/indra/newview/llfloaterpermissionsmgr.h b/indra/newview/llfloaterpermissionsmgr.h deleted file mode 100644 index ac933e3f1a..0000000000 --- a/indra/newview/llfloaterpermissionsmgr.h +++ /dev/null @@ -1,82 +0,0 @@ -/** - * @file llfloaterpermissionsmgr.h - * @brief for user control of script permissions - * - * $LicenseInfo:firstyear=2003&license=viewergpl$ - * - * Copyright (c) 2003-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifndef LL_LLFLOATERPERMISSIONSMGR_H -#define LL_LLFLOATERPERMISSIONSMGR_H - -#include "llfloater.h" -#include - -class LLScrollContainer; -class LLPermissionsView; - -class LLFloaterPermissionsMgr -: public LLFloater -{ -public: - static LLFloaterPermissionsMgr* show(); - - // Message system callbacks - static void processPermissionsList(LLMessageSystem* msg, void**); - - virtual void onClose(bool app_quitting) { setVisible(FALSE); } - -private: - // Must construct by calling show(). - LLFloaterPermissionsMgr(); - virtual ~LLFloaterPermissionsMgr(); - -public: - LLPermissionsView* mPermissions; - -protected: - LLScrollContainer* mScroller; - - static LLFloaterPermissionsMgr* sInstance; -}; - -class LLPermissionsView : public LLView -{ -public: - LLPermissionsView(const LLRect& rect); - virtual ~LLPermissionsView() {}; - -public: - void clearPermissionsData(); - void addPermissionsData(const std::string& object_name, const LLUUID& object_id, U32 permissions_flags); - - static void revokePermissions(const LLUUID& object_id, U32 permission_flags); - //static void findObject(const LLUUID& object_id, U32 permission_flags); -}; - - -#endif diff --git a/indra/newview/llfloaterperms.cpp b/indra/newview/llfloaterperms.cpp index a85abb1a69..a71419139a 100644 --- a/indra/newview/llfloaterperms.cpp +++ b/indra/newview/llfloaterperms.cpp @@ -1,7 +1,7 @@ /** * @file llfloaterperms.cpp * @brief Asset creation permission preferences. - * @author Coco + * @author Jonathan Yap * * $LicenseInfo:firstyear=2001&license=viewergpl$ * @@ -33,173 +33,340 @@ #include "llviewerprecompiledheaders.h" #include "lfsimfeaturehandler.h" +#include "llagent.h" #include "llcheckboxctrl.h" #include "llfloaterperms.h" #include "llnotificationsutil.h" #include "llviewercontrol.h" +#include "llviewerregion.h" #include "llviewerwindow.h" #include "lluictrlfactory.h" #include "llpermissions.h" +#include "llsdserialize.h" #include "hippogridmanager.h" +extern class AIHTTPTimeoutPolicy floaterPermsResponder_timeout; + +//static +U32 LLFloaterPerms::getGroupPerms(std::string prefix) +{ + return gSavedSettings.getBOOL(prefix+"ShareWithGroup") ? PERM_COPY | PERM_MOVE | PERM_MODIFY : PERM_NONE; +} + +//static +U32 LLFloaterPerms::getEveryonePerms(std::string prefix) +{ + U32 flags = PERM_NONE; + if (prefix != "Bulk" && LFSimFeatureHandler::instance().simSupportsExport() && prefix.empty() && gSavedPerAccountSettings.getBOOL(prefix+"EveryoneExport")) // Singu TODO: Bulk? + flags |= PERM_EXPORT; + if (gSavedSettings.getBOOL(prefix+"EveryoneCopy")) + flags |= PERM_COPY; + return flags; +} + +//static +U32 LLFloaterPerms::getNextOwnerPerms(std::string prefix) +{ + U32 flags = PERM_MOVE; + if ( gSavedSettings.getBOOL(prefix+"NextOwnerCopy") ) + { + flags |= PERM_COPY; + } + if ( gSavedSettings.getBOOL(prefix+"NextOwnerModify") ) + { + flags |= PERM_MODIFY; + } + if ( gSavedSettings.getBOOL(prefix+"NextOwnerTransfer") ) + { + flags |= PERM_TRANSFER; + } + return flags; +} + +//static +U32 LLFloaterPerms::getNextOwnerPermsInverted(std::string prefix) +{ + // Sets bits for permissions that are off + U32 flags = PERM_MOVE; + if (!gSavedSettings.getBOOL(prefix+"NextOwnerCopy")) + { + flags |= PERM_COPY; + } + if (!gSavedSettings.getBOOL(prefix+"NextOwnerModify")) + { + flags |= PERM_MODIFY; + } + if (!gSavedSettings.getBOOL(prefix+"NextOwnerTransfer")) + { + flags |= PERM_TRANSFER; + } + return flags; +} + namespace { - bool everyone_export; - void handle_checkboxes(LLUICtrl* ctrl, const LLSD& value) + void handle_checkboxes(LLView* view, const std::string& ctrl_name, const LLSD& value, const std::string& type) { - LLPanel* view = static_cast(ctrl->getParent()); - if (ctrl->getName() == "everyone_export") + if (ctrl_name == type+"everyone_export") { - view->childSetEnabled("next_owner_copy", !value); - view->childSetEnabled("next_owner_modify", !value); - view->childSetEnabled("next_owner_transfer", !value); + view->getChildView(type+"next_owner_copy")->setEnabled(!value); + view->getChildView(type+"next_owner_modify")->setEnabled(!value); + view->getChildView(type+"next_owner_transfer")->setEnabled(!value); } else { - if (ctrl->getName() == "next_owner_copy") + if (ctrl_name == type+"next_owner_copy") { if (!value) // Implements fair use - gSavedSettings.setBOOL("NextOwnerTransfer", true); - view->childSetEnabled("next_owner_transfer", value); + gSavedSettings.setBOOL(type+"NextOwnerTransfer", true); + view->getChildView(type+"next_owner_transfer")->setEnabled(value); } if (!value) // If any of these are unchecked, export can no longer be checked. - view->childSetEnabled("everyone_export", false); + view->getChildView(type+"everyone_export")->setEnabled(false); else - view->childSetEnabled("everyone_export", LFSimFeatureHandler::instance().simSupportsExport() && (LLFloaterPerms::getNextOwnerPerms() & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED); + view->getChildView(type+"everyone_export")->setEnabled(LFSimFeatureHandler::instance().simSupportsExport() && (LLFloaterPerms::getNextOwnerPerms(type) & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED); } } } -LLFloaterPerms::LLFloaterPerms(const LLSD& seed) +static bool mCapSent = false; + +LLFloaterPermsDefault::LLFloaterPermsDefault(const LLSD& seed) + : LLFloater() { + mCommitCallbackRegistrar.add("PermsDefault.OK", boost::bind(&LLFloaterPermsDefault::onClickOK, this)); + mCommitCallbackRegistrar.add("PermsDefault.Cancel", boost::bind(&LLFloaterPermsDefault::onClickCancel, this)); LLUICtrlFactory::getInstance()->buildFloater(this, "floater_perm_prefs.xml"); } -BOOL LLFloaterPerms::postBuild() + +// String equivalents of enum Categories - initialization order must match enum order! +const std::string LLFloaterPermsDefault::sCategoryNames[CAT_LAST] = { - //handle_checkboxes + "Objects", + "Uploads", + "Scripts", + "Notecards", + "Gestures", + "Wearables" +}; + +void LLFloaterPermsDefault::initCheckboxes(bool export_support, const std::string& type) +{ + const U32 next_owner_perms = LLFloaterPerms::getNextOwnerPerms(type); + getChildView(type + "everyone_export")->setEnabled(export_support && (next_owner_perms & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED); + + if (!(next_owner_perms & PERM_COPY)) { - bool export_support = LFSimFeatureHandler::instance().simSupportsExport(); - const U32 next_owner_perms = getNextOwnerPerms(); - childSetEnabled("everyone_export", export_support && (next_owner_perms & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED); - if (!gHippoGridManager->getCurrentGrid()->isSecondLife()) - childSetVisible("everyone_export", false); + getChildView(type + "next_owner_transfer")->setEnabled(false); + } + else if (export_support) + { + bool export_off = !gSavedPerAccountSettings.getBOOL(type+"EveryoneExport"); + getChildView(type + "next_owner_copy")->setEnabled(export_off); + getChildView(type + "next_owner_modify")->setEnabled(export_off); + getChildView(type + "next_owner_transfer")->setEnabled(export_off); + } + else // Set type+EveryoneExport false, just in case. + gSavedPerAccountSettings.setBOOL(type+"EveryoneExport", false); +} - if (!(next_owner_perms & PERM_COPY)) - { - childSetEnabled("next_owner_transfer", false); - } - else if (export_support) - { - bool export_off = !gSavedPerAccountSettings.getBOOL("EveryoneExport"); - childSetEnabled("next_owner_copy", export_off); - childSetEnabled("next_owner_modify", export_off); - childSetEnabled("next_owner_transfer", export_off); - } - else // Set EveryoneExport false, just in case. - gSavedPerAccountSettings.setBOOL("EveryoneExport", false); +BOOL LLFloaterPermsDefault::postBuild() +{ + //handle_checkboxes + bool export_support = LFSimFeatureHandler::instance().simSupportsExport(); + bool is_sl = gHippoGridManager->getCurrentGrid()->isSecondLife(); + for (S32 i = 0; i < CAT_LAST; ++i) + { + const std::string& type(sCategoryNames[i]); + initCheckboxes(export_support, type); + commit_callback_t handle_checks(boost::bind(handle_checkboxes, this, boost::bind(&LLView::getName, _1), _2, type)); + getChild(type + "next_owner_copy")->setCommitCallback(handle_checks); + getChild(type + "next_owner_modify")->setCommitCallback(handle_checks); + getChild(type + "next_owner_transfer")->setCommitCallback(handle_checks); + if (is_sl) + getChildView(type + "everyone_export")->setVisible(false); + else + getChild(type + "everyone_export")->setCommitCallback(handle_checks); + } + if (is_sl) + { + LLView* view(getChildView("ExportationLabel")); + S32 shift(view->getRect().getWidth()); // Determine size of export area + LLRect rect(getRect()); + rect.mRight -= shift; + setRect(rect); // Cut off the export side + view->setVisible(false); // Hide label + // Move bottom buttons over so they look nice. + shift /= -2; + view = getChildView("ok"); + rect = view->getRect(); + rect.translate(shift, 0); + view->setRect(rect); + view = getChildView("cancel"); + rect = view->getRect(); + rect.translate(shift, 0); + view->setRect(rect); } - childSetAction("help", onClickHelp, this); - childSetAction("ok", onClickOK, this); - childSetAction("cancel", onClickCancel, this); - getChild("next_owner_copy")->setCommitCallback(handle_checkboxes); - getChild("next_owner_modify")->setCommitCallback(handle_checkboxes); - getChild("next_owner_transfer")->setCommitCallback(handle_checkboxes); - getChild("everyone_export")->setCommitCallback(handle_checkboxes); refresh(); return TRUE; } -//static -void LLFloaterPerms::onClickOK(void* data) +void LLFloaterPermsDefault::onClickOK() { - LLFloaterPerms* self = static_cast(data); - self->ok(); - self->close(); + ok(); + close(); } -//static -void LLFloaterPerms::onClickCancel(void* data) +void LLFloaterPermsDefault::onClickCancel() { - LLFloaterPerms* self = static_cast(data); - self->cancel(); - self->close(); + cancel(); + close(); } -void LLFloaterPerms::ok() +struct LLFloaterPermsRequester final : LLSingleton { - refresh(); // Changes were already applied to saved settings. Refreshing internal values makes it official. -} + friend class LLSingleton; + std::string mUrl; + LLSD mReport; + U8 mRetriesCount = 0; + static void init(const std::string url, const LLSD report) + { + auto& inst = instance(); + inst.mUrl = url; + inst.mReport = report; + inst.retry(); + } + bool retry(); +}; -void LLFloaterPerms::cancel() +class LLFloaterPermsResponder final : public LLHTTPClient::ResponderWithResult { - gSavedSettings.setBOOL("ShareWithGroup", mShareWithGroup); - gSavedSettings.setBOOL("EveryoneCopy", mEveryoneCopy); - gSavedSettings.setBOOL("NextOwnerCopy", mNextOwnerCopy); - gSavedSettings.setBOOL("NextOwnerModify", mNextOwnerModify); - gSavedSettings.setBOOL("NextOwnerTransfer", mNextOwnerTransfer); - gSavedPerAccountSettings.setBOOL("EveryoneExport", everyone_export); -} + static std::string sPreviousReason; -void LLFloaterPerms::refresh() + void httpFailure() override + { + auto* requester = LLFloaterPermsRequester::getIfExists(); + if (!requester || requester->retry()) return; + + LLFloaterPermsRequester::deleteSingleton(); + const std::string& reason = getReason(); + // Do not display the same error more than once in a row + if (reason != sPreviousReason) + { + sPreviousReason = reason; + LLSD args; + args["REASON"] = reason; + LLNotificationsUtil::add("DefaultObjectPermissions", args); + } + } + void httpSuccess() override + { + //const LLSD& content = getContent(); + //dump_sequential_xml("perms_responder_result.xml", content); + + // Since we have had a successful POST call be sure to display the next error message + // even if it is the same as a previous one. + sPreviousReason = ""; + LL_INFOS("ObjectPermissionsFloater") << "Default permissions successfully sent to simulator" << LL_ENDL; + } + AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy() const override { return floaterPermsResponder_timeout; } + char const* getName() const override { return "LLFloaterPermsResponder"; } +}; + +bool LLFloaterPermsRequester::retry() { - mShareWithGroup = gSavedSettings.getBOOL("ShareWithGroup"); - mEveryoneCopy = gSavedSettings.getBOOL("EveryoneCopy"); - mNextOwnerCopy = gSavedSettings.getBOOL("NextOwnerCopy"); - mNextOwnerModify = gSavedSettings.getBOOL("NextOwnerModify"); - mNextOwnerTransfer = gSavedSettings.getBOOL("NextOwnerTransfer"); - everyone_export = gSavedPerAccountSettings.getBOOL("EveryoneExport"); + if (++mRetriesCount < 5) + { + LLHTTPClient::post(mUrl, mReport, new LLFloaterPermsResponder); + return true; + } + return false; } -void LLFloaterPerms::onClose(bool app_quitting) +std::string LLFloaterPermsResponder::sPreviousReason; + +void LLFloaterPermsDefault::sendInitialPerms() { - // Cancel any unsaved changes before closing. - // Note: when closed due to the OK button this amounts to a no-op. - cancel(); - LLFloater::onClose(app_quitting); + if (!mCapSent) + { + updateCap(); + mCapSent = true; + } } -//static -U32 LLFloaterPerms::getGroupPerms(std::string prefix) -{ - return gSavedSettings.getBOOL(prefix+"ShareWithGroup") ? PERM_COPY : PERM_NONE; +void LLFloaterPermsDefault::updateCap() +{ + std::string object_url = gAgent.getRegionCapability("AgentPreferences"); + + if (!object_url.empty()) + { + LLSD report = LLSD::emptyMap(); + report["default_object_perm_masks"]["Group"] = + (LLSD::Integer)LLFloaterPerms::getGroupPerms(sCategoryNames[CAT_OBJECTS]); + report["default_object_perm_masks"]["Everyone"] = + (LLSD::Integer)LLFloaterPerms::getEveryonePerms(sCategoryNames[CAT_OBJECTS]); + report["default_object_perm_masks"]["NextOwner"] = + (LLSD::Integer)LLFloaterPerms::getNextOwnerPerms(sCategoryNames[CAT_OBJECTS]); + + { + std::ostringstream sent_perms_log; + LLSDSerialize::toPrettyXML(report, sent_perms_log); + LL_DEBUGS("ObjectPermissionsFloater") << "Sending default permissions to '" + << object_url << "'\n" + << sent_perms_log.str() << LL_ENDL; + } + LLFloaterPermsRequester::init(object_url, report); + } + else + { + LL_DEBUGS("ObjectPermissionsFloater") << "AgentPreferences cap not available." << LL_ENDL; + } } -//static -U32 LLFloaterPerms::getEveryonePerms(std::string prefix) +void LLFloaterPermsDefault::ok() { - U32 flags = PERM_NONE; - if (LFSimFeatureHandler::instance().simSupportsExport() && prefix.empty() && gSavedPerAccountSettings.getBOOL("EveryoneExport")) // TODO: Bulk enable export? - flags |= PERM_EXPORT; - if (gSavedSettings.getBOOL(prefix+"EveryoneCopy")) - flags |= PERM_COPY; - return flags; + // Changes were already applied automatically to saved settings. + // Refreshing internal values makes it official. + refresh(); + + // We know some setting has changed but not which one. Just in case it was a setting for + // object permissions tell the server what the values are. + updateCap(); } -//static -U32 LLFloaterPerms::getNextOwnerPerms(std::string prefix) +void LLFloaterPermsDefault::cancel() { - U32 flags = PERM_MOVE; - if ( gSavedSettings.getBOOL(prefix+"NextOwnerCopy") ) + for (U32 iter = CAT_OBJECTS; iter < CAT_LAST; iter++) { - flags |= PERM_COPY; + gSavedSettings.setBOOL(sCategoryNames[iter]+"NextOwnerCopy", mNextOwnerCopy[iter]); + gSavedSettings.setBOOL(sCategoryNames[iter]+"NextOwnerModify", mNextOwnerModify[iter]); + gSavedSettings.setBOOL(sCategoryNames[iter]+"NextOwnerTransfer", mNextOwnerTransfer[iter]); + gSavedSettings.setBOOL(sCategoryNames[iter]+"ShareWithGroup", mShareWithGroup[iter]); + gSavedSettings.setBOOL(sCategoryNames[iter]+"EveryoneCopy", mEveryoneCopy[iter]); + gSavedPerAccountSettings.setBOOL(sCategoryNames[iter]+"EveryoneExport", mEveryoneExport[iter]); } - if ( gSavedSettings.getBOOL(prefix+"NextOwnerModify") ) +} + +void LLFloaterPermsDefault::refresh() +{ + for (U32 iter = CAT_OBJECTS; iter < CAT_LAST; iter++) { - flags |= PERM_MODIFY; + mShareWithGroup[iter] = gSavedSettings.getBOOL(sCategoryNames[iter]+"ShareWithGroup"); + mEveryoneCopy[iter] = gSavedSettings.getBOOL(sCategoryNames[iter]+"EveryoneCopy"); + mNextOwnerCopy[iter] = gSavedSettings.getBOOL(sCategoryNames[iter]+"NextOwnerCopy"); + mNextOwnerModify[iter] = gSavedSettings.getBOOL(sCategoryNames[iter]+"NextOwnerModify"); + mNextOwnerTransfer[iter] = gSavedSettings.getBOOL(sCategoryNames[iter]+"NextOwnerTransfer"); + mEveryoneExport[iter] = gSavedPerAccountSettings.getBOOL(sCategoryNames[iter]+"EveryoneExport"); } - if ( gSavedSettings.getBOOL(prefix+"NextOwnerTransfer") ) - { - flags |= PERM_TRANSFER; - } - return flags; } - -//static -void LLFloaterPerms::onClickHelp(void* data) +void LLFloaterPermsDefault::onClose(bool app_quitting) { - LLNotificationsUtil::add("ClickUploadHelpPermissions"); + // Cancel any unsaved changes before closing. + // Note: when closed due to the OK button this amounts to a no-op. + cancel(); + LLFloater::onClose(app_quitting); } diff --git a/indra/newview/llfloaterperms.h b/indra/newview/llfloaterperms.h index 9193b59837..52c3159d26 100644 --- a/indra/newview/llfloaterperms.h +++ b/indra/newview/llfloaterperms.h @@ -36,35 +36,55 @@ #include "llfloater.h" -class LLFloaterPerms : public LLFloater, public LLFloaterSingleton +namespace LLFloaterPerms { - friend class LLUISingleton >; + // Convenience methods to get current permission preference bitfields from saved settings: + U32 getEveryonePerms(std::string prefix=""); // prefix + "EveryoneCopy" + U32 getGroupPerms(std::string prefix=""); // prefix + "ShareWithGroup" + U32 getNextOwnerPerms(std::string prefix=""); // bitfield for prefix + "NextOwner" + "Copy", "Modify", and "Transfer" + U32 getNextOwnerPermsInverted(std::string prefix=""); +} + +class LLFloaterPermsDefault : public LLFloater, public LLFloaterSingleton +{ + friend class LLUISingleton >; public: /*virtual*/ void onClose(bool app_quitting = false); /*virtual*/ BOOL postBuild(); + void initCheckboxes(bool export_support, const std::string& type); void ok(); void cancel(); - static void onClickOK(void*); - static void onClickCancel(void*); - // Convenience methods to get current permission preference bitfields from saved settings: - static U32 getEveryonePerms(std::string prefix=""); // prefix + "EveryoneCopy" - static U32 getGroupPerms(std::string prefix=""); // prefix + "ShareWithGroup" - static U32 getNextOwnerPerms(std::string prefix=""); // bitfield for prefix + "NextOwner" + "Copy", "Modify", and "Transfer" + void onClickOK(); + void onClickCancel(); + static void sendInitialPerms(); + static void updateCap(); + + // Update instantiation of sCategoryNames in the .cpp file to match if you change this! + enum Categories + { + CAT_OBJECTS, + CAT_UPLOADS, + CAT_SCRIPTS, + CAT_NOTECARDS, + CAT_GESTURES, + CAT_WEARABLES, + CAT_LAST + }; private: - LLFloaterPerms(const LLSD& seed); + LLFloaterPermsDefault(const LLSD& seed); void refresh(); - /// callback for the menus help button - static void onClickHelp(void* data); + static const std::string sCategoryNames[CAT_LAST]; - BOOL // cached values only for implementing cancel. - mShareWithGroup, - mEveryoneCopy, - mNextOwnerCopy, - mNextOwnerModify, - mNextOwnerTransfer; + // cached values only for implementing cancel. + bool mShareWithGroup[CAT_LAST]; + bool mEveryoneCopy[CAT_LAST]; + bool mEveryoneExport[CAT_LAST]; + bool mNextOwnerCopy[CAT_LAST]; + bool mNextOwnerModify[CAT_LAST]; + bool mNextOwnerTransfer[CAT_LAST]; }; #endif diff --git a/indra/newview/llfloaterpostcard.cpp b/indra/newview/llfloaterpostcard.cpp index 16321763ac..045acd953c 100644 --- a/indra/newview/llfloaterpostcard.cpp +++ b/indra/newview/llfloaterpostcard.cpp @@ -41,6 +41,7 @@ #include "lldir.h" #include "llagent.h" +#include "llagentui.h" #include "llui.h" #include "lllineeditor.h" #include "llviewertexteditor.h" @@ -54,7 +55,6 @@ #include "llviewerwindow.h" #include "llstatusbar.h" #include "llviewerregion.h" -#include "lleconomy.h" #include "lltrans.h" #include "llgl.h" @@ -103,11 +103,7 @@ void LLFloaterPostcard::init() if(!gAgent.getID().isNull()) { // we're logged in, so we can get this info. - gMessageSystem->newMessageFast(_PREHASH_UserInfoRequest); - gMessageSystem->nextBlockFast(_PREHASH_AgentData); - gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - gAgent.sendReliableMessage(); + gAgent.sendAgentUserInfoRequest(); } sInstances.insert(this); @@ -128,7 +124,7 @@ BOOL LLFloaterPostcard::postBuild() childDisable("from_form"); std::string name_string; - gAgent.buildFullname(name_string); + LLAgentUI::buildFullname(name_string); childSetValue("name_form", LLSD(name_string)); LLTextEditor* MsgField = getChild("msg_form"); @@ -233,7 +229,7 @@ void LLFloaterPostcard::onClose(bool app_quitting) destroy(); } -class LLSendPostcardResponder : public LLAssetUploadResponder +class LLSendPostcardResponder final : public LLAssetUploadResponder { private: int mSnapshotIndex; @@ -248,22 +244,22 @@ class LLSendPostcardResponder : public LLAssetUploadResponder { } // *TODO define custom uploadFailed here so it's not such a generic message - /*virtual*/ void uploadComplete(const LLSD& content) + void uploadComplete(const LLSD& content) override final { // we don't care about what the server returns from this post, just clean up the UI LLFloaterSnapshot::savePostcardDone(true, mSnapshotIndex); } - /*virtual*/ void uploadFailure(const LLSD& content) + void uploadFailure(const LLSD& content) override final { LLAssetUploadResponder::uploadFailure(content); LLFloaterSnapshot::savePostcardDone(false, mSnapshotIndex); } - /*virtual*/ void error(U32 statusNum, const std::string& reason) + void httpFailure(void) override final { - LLAssetUploadResponder::error(statusNum, reason); + LLAssetUploadResponder::httpFailure(); LLFloaterSnapshot::savePostcardDone(false, mSnapshotIndex); } - /*virtual*/ char const* getName(void) const { return "LLSendPostcardResponder"; } + char const* getName(void) const override final { return "LLSendPostcardResponder"; } }; // static @@ -273,7 +269,6 @@ void LLFloaterPostcard::onClickSend(void* data) { LLFloaterPostcard *self = (LLFloaterPostcard *)data; - std::string from(self->childGetValue("from_form").asString()); std::string to(self->childGetValue("to_form").asString()); boost::regex emailFormat("[A-Za-z0-9.%+-_]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}(,[ \t]*[A-Za-z0-9.%+-_]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,})*"); @@ -284,12 +279,6 @@ void LLFloaterPostcard::onClickSend(void* data) return; } - if (from.empty() || !boost::regex_match(from, emailFormat)) - { - LLNotificationsUtil::add("PromptSelfEmail"); - return; - } - std::string subject(self->childGetValue("subject_form").asString()); if(subject.empty() || !self->mHasFirstMsgFocus) { @@ -349,10 +338,8 @@ void LLFloaterPostcard::uploadCallback(const LLUUID& asset_id, void *user_data, // static void LLFloaterPostcard::updateUserInfo(const std::string& email) { - for (instance_list_t::iterator iter = sInstances.begin(); - iter != sInstances.end(); ++iter) + for (auto& instance : sInstances) { - LLFloaterPostcard *instance = *iter; const std::string& text = instance->childGetValue("from_form").asString(); if (text.empty()) { @@ -411,12 +398,11 @@ void LLFloaterPostcard::sendPostcard() std::string url = gAgent.getRegion()->getCapability("SendPostcard"); if(!url.empty()) { - llinfos << "Send Postcard via capability" << llendl; + LL_INFOS() << "Send Postcard via capability" << LL_ENDL; LLSD body = LLSD::emptyMap(); // the capability already encodes: agent ID, region ID body["pos-global"] = mPosTakenGlobal.getValue(); body["to"] = childGetValue("to_form").asString(); - body["from"] = childGetValue("from_form").asString(); body["name"] = childGetValue("name_form").asString(); body["subject"] = childGetValue("subject_form").asString(); body["msg"] = childGetValue("msg_form").asString(); diff --git a/indra/newview/llfloaterpostcard.h b/indra/newview/llfloaterpostcard.h index e40479c171..2ae0f2fa92 100644 --- a/indra/newview/llfloaterpostcard.h +++ b/indra/newview/llfloaterpostcard.h @@ -46,17 +46,17 @@ class LLLineEditor; class LLButton; class LLImageJPEG; -class LLFloaterPostcard +class LLFloaterPostcard final : public LLFloater { public: LLFloaterPostcard(LLImageJPEG* jpeg, LLViewerTexture *img, const LLVector2& img_scale, const LLVector3d& pos_taken_global, int index); - /*virtual*/ ~LLFloaterPostcard(); + /*virtual*/ ~LLFloaterPostcard() override; - /*virtual*/ void init(); - /*virtual*/ BOOL postBuild(); - /*virtual*/ void draw(); - /*virtual*/ void onClose(bool app_quitting); + void init(); + /*virtual*/ BOOL postBuild() override; + /*virtual*/ void draw() override; + /*virtual*/ void onClose(bool app_quitting) override; static LLFloaterPostcard* showFromSnapshot(LLImageJPEG *jpeg, LLViewerTexture *img, const LLVector2& img_scale, const LLVector3d& pos_taken_global, int index); diff --git a/indra/newview/llfloaterpostprocess.cpp b/indra/newview/llfloaterpostprocess.cpp index 22a89e0152..f7626f333e 100644 --- a/indra/newview/llfloaterpostprocess.cpp +++ b/indra/newview/llfloaterpostprocess.cpp @@ -43,16 +43,11 @@ #include "llcombobox.h" #include "lllineeditor.h" #include "llviewerwindow.h" -#if LL_MSVC -// disable boost::lexical_cast warning -#pragma warning (disable:4702) -#endif -#include LLFloaterPostProcess* LLFloaterPostProcess::sPostProcess = NULL; -LLFloaterPostProcess::LLFloaterPostProcess() : LLFloater(std::string("Post-Process Floater")) +LLFloaterPostProcess::LLFloaterPostProcess(const LLSD&) : LLFloater("Post-Process Floater") { LLUICtrlFactory::getInstance()->buildFloater(this, "floater_post_process.xml"); @@ -91,24 +86,11 @@ LLFloaterPostProcess::LLFloaterPostProcess() : LLFloater(std::string("Post-Proce getChild("PPSaveEffect")->setCommitCallback(boost::bind(&LLFloaterPostProcess::onSaveEffect, this, editBox)); syncMenu(); + LLPostProcess::instance().setSelectedEffectChangeCallback(boost::bind(&LLFloaterPostProcess::syncMenu, this)); } LLFloaterPostProcess::~LLFloaterPostProcess() { - - -} - -LLFloaterPostProcess* LLFloaterPostProcess::instance() -{ - // if we don't have our singleton instance, create it - if (!sPostProcess) - { - sPostProcess = new LLFloaterPostProcess(); - sPostProcess->open(); - sPostProcess->setFocus(TRUE); - } - return sPostProcess; } @@ -122,8 +104,6 @@ void LLFloaterPostProcess::onLoadEffect(LLComboBox* comboBox) LLSD::String effectName(comboBox->getSelectedValue().asString()); LLPostProcess::getInstance()->setSelectedEffect(effectName); - - syncMenu(); } void LLFloaterPostProcess::onSaveEffect(LLLineEditor* editBox) @@ -139,7 +119,6 @@ void LLFloaterPostProcess::onSaveEffect(LLLineEditor* editBox) else { LLPostProcess::getInstance()->saveEffectAs(effectName); - syncMenu(); } } @@ -161,48 +140,40 @@ bool LLFloaterPostProcess::saveAlertCallback(const LLSD& notification, const LLS if (option == 0) { LLPostProcess::getInstance()->saveEffectAs(notification["payload"]["effect_name"].asString()); - - syncMenu(); } return false; } -void LLFloaterPostProcess::show() -{ - // get the instance, make sure the values are synced - // and open the menu - LLFloaterPostProcess* postProcess = instance(); - postProcess->syncMenu(); - postProcess->open(); -} - // virtual void LLFloaterPostProcess::onClose(bool app_quitting) { // just set visibility to false, don't get fancy yet - if (sPostProcess) - { - sPostProcess->setVisible(FALSE); - } + if (app_quitting) + die(); + else + setVisible(FALSE); } -void LLFloaterPostProcess::syncMenu() +void populatePostProcessList(LLComboBox* comboBox) { - // add the combo boxe contents - LLComboBox* comboBox = getChild("PPEffectsCombo"); - comboBox->removeall(); - LLSD::map_const_iterator currEffect; - for(currEffect = LLPostProcess::getInstance()->getAllEffectInfo().beginMap(); - currEffect != LLPostProcess::getInstance()->getAllEffectInfo().endMap(); + const auto& inst(LLPostProcess::instance()); + for(auto currEffect = inst.getAllEffectInfo().beginMap(), end = inst.getAllEffectInfo().endMap(); + currEffect != end; ++currEffect) { comboBox->add(currEffect->first); } // set the current effect as selected. - comboBox->selectByValue(LLPostProcess::getInstance()->getSelectedEffectName()); + comboBox->selectByValue(inst.getSelectedEffectName()); +} + +void LLFloaterPostProcess::syncMenu() +{ + // add the combo boxe contents + populatePostProcessList(getChild("PPEffectsCombo")); const LLSD &tweaks = LLPostProcess::getInstance()->getSelectedEffectInfo(); //Iterate down all uniforms handled by post-process shaders. Update any linked ui elements. @@ -214,7 +185,7 @@ void LLFloaterPostProcess::syncMenu() //llsd["uniform"][1]=>"uniform[1]" for(S32 i=0;isecond.size();++i) { - childSetValue(it->first+"["+boost::lexical_cast(i)+"]",it->second[i]); + childSetValue(it->first+'['+fmt::to_string(i)+']',it->second[i]); } } else diff --git a/indra/newview/llfloaterpostprocess.h b/indra/newview/llfloaterpostprocess.h index f49a339819..e2ffbf86e8 100644 --- a/indra/newview/llfloaterpostprocess.h +++ b/indra/newview/llfloaterpostprocess.h @@ -49,16 +49,13 @@ class LLPanelFace; /** * Menu for adjusting the post process settings of the world */ -class LLFloaterPostProcess : public LLFloater +class LLFloaterPostProcess : public LLFloater, public LLFloaterSingleton { public: - LLFloaterPostProcess(); + LLFloaterPostProcess(const LLSD&); virtual ~LLFloaterPostProcess(); - /// one and one instance only - static LLFloaterPostProcess* instance(); - /// post process callbacks static void onControlChanged(LLUICtrl* ctrl, const LLSD& v); void onLoadEffect(LLComboBox* comboBox); @@ -68,18 +65,12 @@ class LLFloaterPostProcess : public LLFloater /// prompts a user when overwriting an effect bool saveAlertCallback(const LLSD& notification, const LLSD& response); - /// show off our menu - static void show(); - /// stuff to do on exit virtual void onClose(bool app_quitting); /// sync up sliders void syncMenu(); -/* - void refresh(); -*/ public: static LLFloaterPostProcess* sPostProcess; diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index dbbd06f762..680fa258ec 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -333,22 +333,23 @@ void LLPreferenceCore::onTabChanged(LLUICtrl* ctrl) } -void LLPreferenceCore::setPersonalInfo(const std::string& visibility, bool im_via_email, const std::string& email) +void LLPreferenceCore::setPersonalInfo(const std::string& visibility, bool im_via_email, const std::string& email, bool is_verified) { - mPrefsIM->setPersonalInfo(visibility, im_via_email, email); -} - -void LLPreferenceCore::refreshEnabledGraphics() -{ - mDisplayPanel->refreshEnabledState(); + mPrefsIM->setPersonalInfo(visibility, im_via_email, email, is_verified); } ////////////////////////////////////////////// // LLFloaterPreference +void reset_to_default(const std::string& control) +{ + LLUI::getControlControlGroup(control).getControl(control)->resetToDefault(true); +} + LLFloaterPreference::LLFloaterPreference() { mExitWithoutSaving = false; + mCommitCallbackRegistrar.add("Prefs.Reset", boost::bind(reset_to_default, _2)); LLUICtrlFactory::getInstance()->buildFloater(this, "floater_preferences.xml"); } @@ -365,23 +366,13 @@ BOOL LLFloaterPreference::postBuild() return FALSE; } - mAboutBtn = getChild("About..."); - mAboutBtn->setClickedCallback(onClickAbout, this); - - mApplyBtn = getChild("Apply"); - mApplyBtn->setClickedCallback(onBtnApply, this); - - mCancelBtn = getChild("Cancel"); - mCancelBtn->setClickedCallback(onBtnCancel, this); - - mOKBtn = getChild("OK"); - mOKBtn->setClickedCallback(onBtnOK, this); - - mPreferenceCore = new LLPreferenceCore( - getChild("pref core"), - getChild("OK") - ); - + getChild("About...")->setCommitCallback(boost::bind(LLFloaterAbout::show, (void*)0)); + getChild("Apply")->setCommitCallback(boost::bind(&LLFloaterPreference::onBtnApply, this)); + getChild("Cancel")->setCommitCallback(boost::bind(&LLFloaterPreference::onBtnCancel, this)); + getChild("OK")->setCommitCallback(boost::bind(&LLFloaterPreference::onBtnOK, this)); + + mPreferenceCore = new LLPreferenceCore(getChild("pref core"), getChild("OK")); + sInstance = this; return TRUE; @@ -396,13 +387,13 @@ LLFloaterPreference::~LLFloaterPreference() void LLFloaterPreference::apply() { - this->mPreferenceCore->apply(); + mPreferenceCore->apply(); } void LLFloaterPreference::cancel() { - this->mPreferenceCore->cancel(); + mPreferenceCore->cancel(); } @@ -417,33 +408,17 @@ void LLFloaterPreference::show(void*) sInstance->open(); /* Flawfinder: ignore */ - if(!gAgent.getID().isNull()) - { - // we're logged in, so we can get this info. - gMessageSystem->newMessageFast(_PREHASH_UserInfoRequest); - gMessageSystem->nextBlockFast(_PREHASH_AgentData); - gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - gAgent.sendReliableMessage(); - } + gAgent.sendAgentUserInfoRequest(); LLPanelLogin::setAlwaysRefresh(true); } -// static -void LLFloaterPreference::onClickAbout(void*) -{ - LLFloaterAbout::show(NULL); -} - -// static -void LLFloaterPreference::onBtnOK( void* userdata ) +void LLFloaterPreference::onBtnOK() { - LLFloaterPreference *fp =(LLFloaterPreference *)userdata; // commit any outstanding text entry - if (fp->hasFocus()) + if (hasFocus()) { LLUICtrl* cur_focus = dynamic_cast(gFocusMgr.getKeyboardFocus()); if (cur_focus->acceptsTextInput()) @@ -452,32 +427,27 @@ void LLFloaterPreference::onBtnOK( void* userdata ) } } - if (fp->canClose()) + if (canClose()) { - fp->apply(); - fp->close(false); + apply(); + close(false); gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile"), TRUE ); - - std::string crash_settings_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, CRASH_SETTINGS_FILE); - // save all settings, even if equals defaults - gCrashSettings.saveToFile(crash_settings_filename, FALSE); + if (gAgentID.notNull()) + gSavedPerAccountSettings.saveToFile( gSavedSettings.getString("PerAccountSettingsFile"), TRUE ); } else { // Show beep, pop up dialog, etc. - llinfos << "Can't close preferences!" << llendl; + LL_INFOS() << "Can't close preferences!" << LL_ENDL; } LLPanelLogin::updateLocationSelectorsVisibility(); } - -// static -void LLFloaterPreference::onBtnApply( void* userdata ) +void LLFloaterPreference::onBtnApply() { - LLFloaterPreference *fp =(LLFloaterPreference *)userdata; - if (fp->hasFocus()) + if (hasFocus()) { LLUICtrl* cur_focus = dynamic_cast(gFocusMgr.getKeyboardFocus()); if (cur_focus && cur_focus->acceptsTextInput()) @@ -485,7 +455,7 @@ void LLFloaterPreference::onBtnApply( void* userdata ) cur_focus->onCommit(); } } - fp->apply(); + apply(); LLPanelLogin::updateLocationSelectorsVisibility(); } @@ -503,10 +473,9 @@ void LLFloaterPreference::onClose(bool app_quitting) // static -void LLFloaterPreference::onBtnCancel( void* userdata ) +void LLFloaterPreference::onBtnCancel() { - LLFloaterPreference *fp =(LLFloaterPreference *)userdata; - if (fp->hasFocus()) + if (hasFocus()) { LLUICtrl* cur_focus = dynamic_cast(gFocusMgr.getKeyboardFocus()); if (cur_focus->acceptsTextInput()) @@ -514,24 +483,19 @@ void LLFloaterPreference::onBtnCancel( void* userdata ) cur_focus->onCommit(); } } - fp->close(); // side effect will also cancel any unsaved changes. + close(); // side effect will also cancel any unsaved changes. } // static -void LLFloaterPreference::updateUserInfo(const std::string& visibility, bool im_via_email, const std::string& email) +void LLFloaterPreference::updateUserInfo(const std::string& visibility, bool im_via_email, const std::string& email, bool is_verified) { - if(sInstance && sInstance->mPreferenceCore) + if (sInstance && sInstance->mPreferenceCore) { - sInstance->mPreferenceCore->setPersonalInfo(visibility, im_via_email, email); + sInstance->mPreferenceCore->setPersonalInfo(visibility, im_via_email, email, is_verified); } } -void LLFloaterPreference::refreshEnabledGraphics() -{ - sInstance->mPreferenceCore->refreshEnabledGraphics(); -} - //static void LLFloaterPreference::switchTab(S32 i) { diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index ea6a0e0fdd..4ee0053f2e 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -73,12 +73,9 @@ class LLPreferenceCore LLTabContainer* getTabContainer() { return mTabContainer; } - void setPersonalInfo(const std::string& visibility, bool im_via_email, const std::string& email); + void setPersonalInfo(const std::string& visibility, bool im_via_email, const std::string& email, bool is_verified); static void onTabChanged(LLUICtrl* ctrl); - - // refresh all the graphics preferences menus - void refreshEnabledGraphics(); private: LLTabContainer *mTabContainer; @@ -112,10 +109,7 @@ class LLFloaterPreference : public LLFloater static void show(void*); // static data update, called from message handler - static void updateUserInfo(const std::string& visibility, bool im_via_email, const std::string& email); - - // refresh all the graphics preferences menus - static void refreshEnabledGraphics(); + static void updateUserInfo(const std::string& visibility, bool im_via_email, const std::string& email, bool is_verified = false); static void switchTab(S32 i); @@ -129,16 +123,11 @@ class LLFloaterPreference : public LLFloater /*virtual*/ void onClose(bool app_quitting); - LLButton* mAboutBtn; - LLButton *mOKBtn; - LLButton *mCancelBtn; - LLButton *mApplyBtn; bool mExitWithoutSaving; - static void onClickAbout(void*); - static void onBtnOK(void*); - static void onBtnCancel(void*); - static void onBtnApply(void*); + void onBtnOK(); + void onBtnCancel(); + void onBtnApply(); static LLFloaterPreference* sInstance; }; diff --git a/indra/newview/llfloaterproperties.cpp b/indra/newview/llfloaterproperties.cpp index 46b67d1dec..2dac6344f4 100644 --- a/indra/newview/llfloaterproperties.cpp +++ b/indra/newview/llfloaterproperties.cpp @@ -44,6 +44,8 @@ #include "llavataractions.h" #include "llbutton.h" #include "llcheckboxctrl.h" +#include "llcororesponder.h" +#include "llexperiencecache.h" #include "llgroupactions.h" #include "llinventorymodel.h" #include "llinventoryobserver.h" @@ -51,8 +53,8 @@ #include "llradiogroup.h" #include "llresmgr.h" #include "roles_constants.h" +#include "llnamebox.h" #include "llselectmgr.h" -#include "lltextbox.h" #include "lltrans.h" #include "llviewerinventory.h" #include "llviewerobjectlist.h" @@ -64,11 +66,6 @@ #include "lfsimfeaturehandler.h" #include "hippogridmanager.h" - -// [RLVa:KB] -#include "rlvhandler.h" -// [/RLVa:KB] - bool can_set_export(const U32& base, const U32& own, const U32& next); //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -81,7 +78,7 @@ bool can_set_export(const U32& base, const U32& own, const U32& next); // from the inventory observer list when destroyed, which could // happen after gInventory has already been destroyed if a singleton. // Instead, do our own ref counting and create / destroy it as needed -class LLPropertiesObserver : public LLInventoryObserver +class LLPropertiesObserver final : public LLInventoryObserver { public: LLPropertiesObserver(LLFloaterProperties* floater) @@ -93,9 +90,10 @@ class LLPropertiesObserver : public LLInventoryObserver { gInventory.removeObserver(this); } - virtual void changed(U32 mask); + + void changed(U32 mask) override; private: - LLFloaterProperties* mFloater; + LLFloaterProperties* mFloater; // Not a handle because LLFloaterProperties is managing LLPropertiesObserver }; void LLPropertiesObserver::changed(U32 mask) @@ -154,7 +152,7 @@ LLFloaterProperties::LLFloaterProperties(const std::string& name, const LLRect& LLFloaterProperties::~LLFloaterProperties() { delete mPropertiesObserver; - mPropertiesObserver = NULL; + mPropertiesObserver = nullptr; } // virtual @@ -168,12 +166,6 @@ BOOL LLFloaterProperties::postBuild() getChild("LabelItemName")->setCommitCallback(boost::bind(&LLFloaterProperties::onCommitName,this)); getChild("LabelItemDesc")->setPrevalidate(&LLLineEditor::prevalidatePrintableNotPipe); getChild("LabelItemDesc")->setCommitCallback(boost::bind(&LLFloaterProperties::onCommitDescription,this)); - // Creator information - getChild("BtnCreator")->setCommitCallback(boost::bind(&LLFloaterProperties::onClickCreator,this)); - // owner information - getChild("BtnOwner")->setCommitCallback(boost::bind(&LLFloaterProperties::onClickOwner,this)); - // last owner information - getChild("BtnLastOwner")->setCommitCallback(boost::bind(&LLFloaterProperties::onClickLastOwner,this)); // acquired date // owner permissions // Permissions debug text @@ -222,15 +214,12 @@ void LLFloaterProperties::refresh() mDirty = TRUE; - const char* enableNames[]={ + static constexpr std::array enableNames{{ "LabelItemName", "LabelItemDesc", "LabelCreatorName", - "BtnCreator", "LabelOwnerName", - "BtnOwner", "LabelLastOwnerName", - "BtnLastOwner", "CheckOwnerModify", "CheckOwnerCopy", "CheckOwnerTransfer", @@ -247,21 +236,21 @@ void LLFloaterProperties::refresh() "CheckPurchase", "RadioSaleType", "Edit Cost" - }; - for(size_t t=0; tsetEnabled(false); + getChildView(name)->setEnabled(false); } - const char* hideNames[]={ + static constexpr std::array hideNames{{ "BaseMaskDebug", "OwnerMaskDebug", "GroupMaskDebug", "EveryoneMaskDebug", "NextMaskDebug" - }; - for(size_t t=0; tsetVisible(false); + getChildView(name)->setVisible(false); } } } @@ -299,7 +288,7 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item) // You need permission to modify the object to modify an inventory // item in it. - LLViewerObject* object = NULL; + LLViewerObject* object = nullptr; if(!mObjectID.isNull()) object = gObjectList.findObject(mObjectID); BOOL is_obj_modify = TRUE; if(object) @@ -307,6 +296,24 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item) is_obj_modify = object->permOwnerModify(); } + if (item->getInventoryType() == LLInventoryType::IT_LSL) + { + getChildView("LabelItemExperienceTitle")->setVisible(TRUE); + LLTextBox* tb = getChild("LabelItemExperience"); + if (tb->getValue().asUUID().isNull()) + { + tb->setText(getString("loading_experience")); + tb->setVisible(TRUE); + } + std::string url = std::string(); + if(object && object->getRegion()) + { + url = object->getRegion()->getCapability("GetMetadata"); + } + LLExperienceCache::instance().fetchAssociatedExperience(item->getParentUUID(), item->getUUID(), url, + boost::bind(&LLFloaterProperties::setAssociatedExperience, getDerivedHandle(), _1)); + } + ////////////////////// // ITEM NAME & DESC // ////////////////////// @@ -328,72 +335,46 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item) if(!gCacheName) return; if(!gAgent.getRegion()) return; + getChild("LabelCreatorName")->setValue(item->getCreatorUUID()); if (item->getCreatorUUID().notNull()) { - std::string name; - gCacheName->getFullName(item->getCreatorUUID(), name); - getChildView("BtnCreator")->setEnabled(TRUE); getChildView("LabelCreatorTitle")->setEnabled(TRUE); getChildView("LabelCreatorName")->setEnabled(TRUE); - getChild("LabelCreatorName")->setValue(name); } else { - getChildView("BtnCreator")->setEnabled(FALSE); getChildView("LabelCreatorTitle")->setEnabled(FALSE); getChildView("LabelCreatorName")->setEnabled(FALSE); - getChild("LabelCreatorName")->setValue(getString("unknown")); + getChild("LabelCreatorName")->setText(getString("unknown")); } + getChild("LabelLastOwnerName")->setValue(perm.getLastOwner()); if (perm.getLastOwner().notNull()) { - std::string name; - gCacheName->getFullName(perm.getLastOwner(), name); getChildView("LabelLastOwnerTitle")->setEnabled(true); getChildView("LabelLastOwnerName")->setEnabled(true); - getChild("LabelLastOwnerName")->setValue(name); } else { getChildView("LabelLastOwnerTitle")->setEnabled(false); getChildView("LabelLastOwnerName")->setEnabled(false); - getChild("LabelLastOwnerName")->setValue(getString("unknown")); + getChild("LabelLastOwnerName")->setText(getString("unknown")); } //////////////// // OWNER NAME // //////////////// + getChild("LabelOwnerName")->setValue(perm.getOwner()); if(perm.isOwned()) { - std::string name; - if (perm.isGroupOwned()) - { - gCacheName->getGroupName(perm.getGroup(), name); - } - else - { - gCacheName->getFullName(perm.getOwner(), name); -// [RLVa:KB] - Checked: 2009-07-08 (RLVa-1.0.0e) - if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) - { - name = RlvStrings::getAnonym(name); - } -// [/RLVa:KB] - } - getChildView("BtnOwner")->setEnabled(TRUE); -// [RLVa:KB] - Checked: 2009-07-08 (RLVa-1.0.0e) | Added: RLVa-1.0.0e - getChildView("BtnOwner")->setEnabled(!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)); -// [/RLVa:KB] getChildView("LabelOwnerTitle")->setEnabled(TRUE); getChildView("LabelOwnerName")->setEnabled(TRUE); - getChild("LabelOwnerName")->setValue(name); } else { - getChildView("BtnOwner")->setEnabled(FALSE); getChildView("LabelOwnerTitle")->setEnabled(FALSE); getChildView("LabelOwnerName")->setEnabled(FALSE); - getChild("LabelOwnerName")->setValue(getString("public")); + getChild("LabelOwnerName")->setText(getString("public")); } ////////////////// @@ -438,11 +419,11 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item) getChild("CheckOwnerCopy")->setValue(LLSD((BOOL)(owner_mask & PERM_COPY))); getChildView("CheckOwnerTransfer")->setEnabled(FALSE); getChild("CheckOwnerTransfer")->setValue(LLSD((BOOL)(owner_mask & PERM_TRANSFER))); + getChildView("CheckOwnerExport")->setEnabled(FALSE); + getChild("CheckOwnerExport")->setValue(LLSD((BOOL)(owner_mask & PERM_EXPORT))); bool supports_export = LFSimFeatureHandler::instance().simSupportsExport(); - getChildView("CheckOwnerExport")->setEnabled(false); - getChild("CheckOwnerExport")->setValue(LLSD((BOOL)(supports_export && owner_mask & PERM_EXPORT))); - if (!gHippoGridManager->getCurrentGrid()->isSecondLife()) + if (!supports_export) getChildView("CheckOwnerExport")->setVisible(false); /////////////////////// @@ -555,6 +536,9 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item) const LLSaleInfo& sale_info = item->getSaleInfo(); BOOL is_for_sale = sale_info.isForSale(); + LLRadioGroup* radioSaleType = getChild("RadioSaleType"); + LLUICtrl* edit_cost = getChild("Edit Cost"); + // Check for ability to change values. if (is_obj_modify && can_agent_sell && gAgent.allowOperation(PERM_TRANSFER, perm, GP_OBJECT_MANIPULATE)) @@ -568,9 +552,9 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item) getChildView("CheckNextOwnerCopy")->setEnabled(no_export && (base_mask & PERM_COPY) && !cannot_restrict_permissions); getChildView("CheckNextOwnerTransfer")->setEnabled(no_export && (next_owner_mask & PERM_COPY) && !cannot_restrict_permissions); - getChildView("RadioSaleType")->setEnabled(is_complete && is_for_sale); + radioSaleType->setEnabled(is_complete && is_for_sale); getChildView("TextPrice")->setEnabled(is_complete && is_for_sale); - getChildView("Edit Cost")->setEnabled(is_complete && is_for_sale); + edit_cost->setEnabled(is_complete && is_for_sale); } else { @@ -582,69 +566,58 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item) getChildView("CheckNextOwnerCopy")->setEnabled(FALSE); getChildView("CheckNextOwnerTransfer")->setEnabled(FALSE); - getChildView("RadioSaleType")->setEnabled(FALSE); + radioSaleType->setEnabled(FALSE); getChildView("TextPrice")->setEnabled(FALSE); - getChildView("Edit Cost")->setEnabled(FALSE); + edit_cost->setEnabled(FALSE); } // Set values. getChild("CheckPurchase")->setValue(is_for_sale); - getChildView("Edit Cost")->setEnabled(is_for_sale); + edit_cost->setEnabled(is_for_sale); getChild("CheckNextOwnerModify")->setValue(LLSD(BOOL(next_owner_mask & PERM_MODIFY))); getChild("CheckNextOwnerCopy")->setValue(LLSD(BOOL(next_owner_mask & PERM_COPY))); getChild("CheckNextOwnerTransfer")->setValue(LLSD(BOOL(next_owner_mask & PERM_TRANSFER))); - LLRadioGroup* radioSaleType = getChild("RadioSaleType"); if (is_for_sale) { - radioSaleType->setSelectedIndex((S32)sale_info.getSaleType() - 1); S32 numerical_price; numerical_price = sale_info.getSalePrice(); - getChild("Edit Cost")->setValue(llformat("%d",numerical_price)); + edit_cost->setValue(llformat("%d",numerical_price)); + radioSaleType->setSelectedIndex((S32)sale_info.getSaleType() - 1); } else { + edit_cost->setValue("0"); radioSaleType->setSelectedIndex(-1); - getChild("Edit Cost")->setValue(llformat("%d",0)); } } -void LLFloaterProperties::onClickCreator() -{ - LLInventoryItem* item = findItem(); - if(!item) return; - LLAvatarActions::showProfile(item->getCreatorUUID()); -} -// static -void LLFloaterProperties::onClickOwner() +void LLFloaterProperties::setAssociatedExperience(LLHandle hInfo, const LLSD& experience) { - LLInventoryItem* item = findItem(); - if(!item) return; - if(item->getPermissions().isGroupOwned()) - { - LLGroupActions::show(item->getPermissions().getGroup()); - } - else + LLFloaterProperties* info = hInfo.get(); + if (info && experience.has(LLExperienceCache::EXPERIENCE_ID)) { -// [RLVa:KB] - Checked: 2009-07-08 (RLVa-1.0.0e) - if (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) -// [/RLVa:KB] + auto id = experience[LLExperienceCache::EXPERIENCE_ID].asUUID(); + if (id.notNull()) { - LLAvatarActions::showProfile(item->getPermissions().getOwner()); + //info->getChild("LabelItemExperience")->setText(LLSLURL("experience", id, "profile").getSLURLString(); + if (LLNameBox* tb = info->getChild("LabelItemExperience")) + { + tb->setValue(id); + } + } + else + { + info->getChild("LabelItemExperience")->setText(LLTrans::getString("ExperienceNameNull")); } } } -void LLFloaterProperties::onClickLastOwner() -{ - if (const LLInventoryItem* item = findItem()) LLAvatarActions::showProfile(item->getPermissions().getLastOwner()); -} - // static void LLFloaterProperties::onCommitName() { - //llinfos << "LLFloaterProperties::onCommitName()" << llendl; + //LL_INFOS() << "LLFloaterProperties::onCommitName()" << LL_ENDL; LLViewerInventoryItem* item = (LLViewerInventoryItem*)findItem(); if(!item) { @@ -680,7 +653,7 @@ void LLFloaterProperties::onCommitName() void LLFloaterProperties::onCommitDescription() { - //llinfos << "LLFloaterProperties::onCommitDescription()" << llendl; + //LL_INFOS() << "LLFloaterProperties::onCommitDescription()" << LL_ENDL; LLViewerInventoryItem* item = (LLViewerInventoryItem*)findItem(); if(!item) return; @@ -717,7 +690,7 @@ void LLFloaterProperties::onCommitDescription() void LLFloaterProperties::onCommitPermissions() { - //llinfos << "LLFloaterProperties::onCommitPermissions()" << llendl; + //LL_INFOS() << "LLFloaterProperties::onCommitPermissions()" << LL_ENDL; LLViewerInventoryItem* item = (LLViewerInventoryItem*)findItem(); if(!item) return; LLPermissions perm(item->getPermissions()); @@ -754,11 +727,6 @@ void LLFloaterProperties::onCommitPermissions() perm.setEveryoneBits(gAgent.getID(), gAgent.getGroupID(), CheckEveryoneCopy->get(), PERM_COPY); } - LLCheckBoxCtrl* CheckExport = getChild("CheckExport"); - if(CheckExport) - { - perm.setEveryoneBits(gAgent.getID(), gAgent.getGroupID(), CheckExport->get(), PERM_EXPORT); - } LLCheckBoxCtrl* CheckNextOwnerModify = getChild("CheckNextOwnerModify"); if(CheckNextOwnerModify) @@ -778,6 +746,13 @@ void LLFloaterProperties::onCommitPermissions() perm.setNextOwnerBits(gAgent.getID(), gAgent.getGroupID(), CheckNextOwnerTransfer->get(), PERM_TRANSFER); } + + LLCheckBoxCtrl* CheckExport = getChild("CheckExport"); + if(CheckExport && CheckExport->getVisible()) + { + perm.setEveryoneBits(gAgent.getID(), gAgent.getGroupID(), CheckExport->get(), PERM_EXPORT); + } + if(perm != item->getPermissions() && item->isFinished()) { @@ -836,14 +811,14 @@ void LLFloaterProperties::onCommitPermissions() // static void LLFloaterProperties::onCommitSaleInfo() { - //llinfos << "LLFloaterProperties::onCommitSaleInfo()" << llendl; + //LL_INFOS() << "LLFloaterProperties::onCommitSaleInfo()" << LL_ENDL; updateSaleInfo(); } // static void LLFloaterProperties::onCommitSaleType() { - //llinfos << "LLFloaterProperties::onCommitSaleType()" << llendl; + //LL_INFOS() << "LLFloaterProperties::onCommitSaleType()" << LL_ENDL; updateSaleInfo(); } @@ -951,7 +926,7 @@ void LLFloaterProperties::updateSaleInfo() LLInventoryItem* LLFloaterProperties::findItem() const { - LLInventoryItem* item = NULL; + LLInventoryItem* item = nullptr; if(mObjectID.isNull()) { // it is in agent inventory @@ -981,7 +956,7 @@ void LLFloaterProperties::closeByID(const LLUUID& item_id, const LLUUID &object_ //static void LLFloaterProperties::dirtyAll() { - for(instance_iter it = beginInstances();it!=endInstances();++it) + for(instance_iter it = beginInstances(), it_end(endInstances()); it != it_end; ++it) { it->dirty(); } diff --git a/indra/newview/llfloaterproperties.h b/indra/newview/llfloaterproperties.h index d2640f07d3..547040e6b1 100644 --- a/indra/newview/llfloaterproperties.h +++ b/indra/newview/llfloaterproperties.h @@ -74,9 +74,6 @@ class LLFloaterProperties : public LLFloater, public LLInstanceTracker hInfo, const LLSD& experience); + protected: // The item id of the inventory item in question. LLUUID mItemID; diff --git a/indra/newview/llfloaterregiondebugconsole.cpp b/indra/newview/llfloaterregiondebugconsole.cpp index 0418dc180e..dab70ad1d0 100644 --- a/indra/newview/llfloaterregiondebugconsole.cpp +++ b/indra/newview/llfloaterregiondebugconsole.cpp @@ -37,10 +37,6 @@ #include "llviewerregion.h" #include "lluictrlfactory.h" -class AIHTTPTimeoutPolicy; -extern AIHTTPTimeoutPolicy asyncConsoleResponder_timeout; -extern AIHTTPTimeoutPolicy consoleResponder_timeout; - // Two versions of the sim console API are supported. // // SimConsole capability (deprecated): @@ -73,15 +69,14 @@ namespace const std::string CONSOLE_NOT_SUPPORTED( "This region does not support the simulator console."); - // This responder handles the initial response. Unless error() is called + // This responder handles the initial response. Unless httpFailure() is called // we assume that the simulator has received our request. Error will be // called if this request times out. // class AsyncConsoleResponder : public LLHTTPClient::ResponderIgnoreBody { public: - /*virtual*/ void error(U32 status, const std::string& reason) { sConsoleReplySignal(UNABLE_TO_SEND_COMMAND); } - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return asyncConsoleResponder_timeout; } + /*virtual*/ void httpFailure(void) { sConsoleReplySignal(UNABLE_TO_SEND_COMMAND); } /*virtual*/ char const* getName(void) const { return "AsyncConsoleResponder"; } }; @@ -92,7 +87,7 @@ namespace { } - /*virtual*/ void error(U32 status, const std::string& reason) + /*virtual*/ void httpFailure(void) { if (mOutput) { @@ -102,16 +97,15 @@ namespace } } - /*virtual*/ void result(const LLSD& content) + /*virtual*/ void httpSuccess(void) { if (mOutput) { mOutput->appendText( - content.asString() + PROMPT, false, false); + mContent.asString() + PROMPT, false, false); } } - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return consoleResponder_timeout; } /*virtual*/ char const* getName(void) const { return "ConsoleResponder"; } LLTextEditor * mOutput; @@ -129,8 +123,8 @@ namespace const LLSD& context, const LLSD& input) const { - llinfos << "Received response from the debug console: " - << input << llendl; + LL_INFOS() << "Received response from the debug console: " + << input << LL_ENDL; sConsoleReplySignal(input["body"].asString()); } }; diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp index d8e7fadd41..e4d775491c 100644 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -3,31 +3,25 @@ * @author Aaron Brashears * @brief Implementation of the region info and controls floater and panels. * - * $LicenseInfo:firstyear=2004&license=viewergpl$ - * - * Copyright (c) 2004-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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$ */ @@ -53,6 +47,7 @@ #include "llfloateravatarpicker.h" #include "llbutton.h" #include "llcheckboxctrl.h" +#include "llclipboard.h" #include "llcombobox.h" #include "lldaycyclemanager.h" #include "llenvmanager.h" @@ -61,8 +56,10 @@ #include "llfloatergodtools.h" // for send_sim_wide_deletes() #include "llfloatertopobjects.h" // added to fix SL-32336 #include "llfloatergroups.h" +#include "llfloaterregiondebugconsole.h" #include "llfloatertelehub.h" #include "llinventorymodel.h" +#include "lllayoutstack.h" #include "lllineeditor.h" #include "llnamelistctrl.h" #include "llnotifications.h" @@ -86,6 +83,12 @@ #include "llvlcomposition.h" #include "llwaterparammanager.h" #include "llagentui.h" +#include "llpanelexperiencelisteditor.h" +#include +#include "llpanelexperiencepicker.h" +#include "llexperiencecache.h" +#include "llpanelexperiences.h" +#include "hippogridmanager.h" // [RLVa:KB] #include "rlvhandler.h" // [/RLVa:KB] @@ -93,35 +96,46 @@ const S32 TERRAIN_TEXTURE_COUNT = 4; const S32 CORNER_COUNT = 4; -class AIHTTPTimeoutPolicy; -extern AIHTTPTimeoutPolicy estateChangeInfoResponder_timeout; +const U32 MAX_LISTED_NAMES = 100; ///---------------------------------------------------------------------------- /// Local class declaration ///---------------------------------------------------------------------------- -class LLDispatchEstateUpdateInfo : public LLDispatchHandler +class LLDispatchEstateUpdateInfo final : public LLDispatchHandler { public: LLDispatchEstateUpdateInfo() {} virtual ~LLDispatchEstateUpdateInfo() {} - virtual bool operator()( + bool operator()( const LLDispatcher* dispatcher, const std::string& key, const LLUUID& invoice, - const sparam_t& strings); + const sparam_t& strings) override; }; -class LLDispatchSetEstateAccess : public LLDispatchHandler +class LLDispatchSetEstateAccess final : public LLDispatchHandler { public: LLDispatchSetEstateAccess() {} virtual ~LLDispatchSetEstateAccess() {} - virtual bool operator()( + bool operator()( + const LLDispatcher* dispatcher, + const std::string& key, + const LLUUID& invoice, + const sparam_t& strings) override; +}; + +class LLDispatchSetEstateExperience final : public LLDispatchHandler +{ +public: + bool operator()( const LLDispatcher* dispatcher, const std::string& key, const LLUUID& invoice, - const sparam_t& strings); + const sparam_t& strings) override; + + LLSD getIDs(sparam_t::const_iterator it, sparam_t::const_iterator end, S32 count); }; @@ -205,6 +219,9 @@ LLUUID LLFloaterRegionInfo::sRequestInvoice; LLFloaterRegionInfo::LLFloaterRegionInfo(const LLSD& seed) + : LLFloater() + , mTab(nullptr) + , mInfoPanels() { LLUICtrlFactory::getInstance()->buildFloater(this, "floater_region_info.xml", NULL, FALSE); } @@ -221,6 +238,11 @@ BOOL LLFloaterRegionInfo::postBuild() LLUICtrlFactory::getInstance()->buildPanel(panel, "panel_region_estate.xml"); mTab->addTabPanel(panel, panel->getLabel(), FALSE); + panel = new LLPanelEstateAccess; + mInfoPanels.push_back(panel); + LLUICtrlFactory::getInstance()->buildPanel(panel, "panel_region_access.xml"); + mTab->addTabPanel(panel, panel->getLabel(), FALSE); + panel = new LLPanelEstateCovenant; mInfoPanels.push_back(panel); LLUICtrlFactory::getInstance()->buildPanel(panel, "panel_region_covenant.xml"); @@ -246,12 +268,24 @@ BOOL LLFloaterRegionInfo::postBuild() LLUICtrlFactory::getInstance()->buildPanel(panel, "panel_region_debug.xml"); mTab->addTabPanel(panel, panel->getLabel(), FALSE); + if(gDisconnected) + { + return TRUE; + } + + if (!gAgent.getRegion()->getCapability("RegionExperiences").empty()) + { + panel = new LLPanelRegionExperiences; + mInfoPanels.push_back(panel); + mTab->addTabPanel(panel, panel->getLabel(), FALSE); + } + gMessageSystem->setHandlerFunc( "EstateOwnerMessage", &processEstateOwnerRequest); // Request region info when agent region changes. - LLEnvManagerNew::instance().setRegionChangeCallback(boost::bind(&LLFloaterRegionInfo::requestRegionInfo, this)); + gAgent.addRegionChangedCallback(boost::bind(&LLFloaterRegionInfo::requestRegionInfo, this)); return TRUE; } @@ -268,9 +302,25 @@ void LLFloaterRegionInfo::onOpen() refreshFromRegion(gAgent.getRegion()); requestRegionInfo(); + requestMeshRezInfo(); + + if (!mGodLevelChangeSlot.connected()) + { + mGodLevelChangeSlot = gAgent.registerGodLevelChanageListener(boost::bind(&LLFloaterRegionInfo::onGodLevelChange, this, _1)); + } + LLFloater::onOpen(); } +void LLFloaterRegionInfo::onClose(bool app_quitting) +{ + if (mGodLevelChangeSlot.connected()) + { + mGodLevelChangeSlot.disconnect(); + } + LLFloater::onClose(app_quitting); +} + // static void LLFloaterRegionInfo::requestRegionInfo() { @@ -280,6 +330,9 @@ void LLFloaterRegionInfo::requestRegionInfo() tab->getChild("Debug")->setCtrlsEnabled(FALSE); tab->getChild("Terrain")->setCtrlsEnabled(FALSE); tab->getChild("Estate")->setCtrlsEnabled(FALSE); + auto panel = tab->getChild("Access"); + panel->setCtrlsEnabled(FALSE); + panel->getChildView("tabs")->setEnabled(true); // Must allow anyone to request the RegionInfo data // so non-owners/non-gods can see the values. @@ -307,8 +360,7 @@ void LLFloaterRegionInfo::processEstateOwnerRequest(LLMessageSystem* msg,void**) LLPanelEstateInfo::initDispatch(dispatch); } - LLTabContainer* tab = floater->getChild("region_panels"); - LLPanelEstateInfo* panel = (LLPanelEstateInfo*)tab->getChild("Estate"); + LLPanelEstateInfo* panel = LLFloaterRegionInfo::getPanelEstate(); // unpack the message std::string request; @@ -317,14 +369,17 @@ void LLFloaterRegionInfo::processEstateOwnerRequest(LLMessageSystem* msg,void**) LLDispatcher::unpackMessage(msg, request, invoice, strings); if(invoice != getLastInvoice()) { - llwarns << "Mismatched Estate message: " << request << llendl; + LL_WARNS() << "Mismatched Estate message: " << request << LL_ENDL; return; } //dispatch the message dispatch.dispatch(request, invoice, strings); - panel->updateControls(gAgent.getRegion()); + if (panel) + { + panel->updateControls(gAgent.getRegion()); + } } @@ -411,6 +466,7 @@ void LLFloaterRegionInfo::processRegionInfo(LLMessageSystem* msg) panel->getChild("block_terraform_check")->setValue((region_flags & REGION_FLAGS_BLOCK_TERRAFORM) ? TRUE : FALSE ); panel->getChild("block_fly_check")->setValue((region_flags & REGION_FLAGS_BLOCK_FLY) ? TRUE : FALSE ); + panel->getChild("block_fly_over_check")->setValue((region_flags & REGION_FLAGS_BLOCK_FLYOVER) ? TRUE : FALSE ); panel->getChild("allow_damage_check")->setValue((region_flags & REGION_FLAGS_ALLOW_DAMAGE) ? TRUE : FALSE ); panel->getChild("restrict_pushobject")->setValue((region_flags & REGION_FLAGS_RESTRICT_PUSHOBJECT) ? TRUE : FALSE ); panel->getChild("allow_land_resell_check")->setValue((region_flags & REGION_FLAGS_BLOCK_LAND_RESELL) ? FALSE : TRUE ); @@ -456,18 +512,28 @@ void LLFloaterRegionInfo::processRegionInfo(LLMessageSystem* msg) LLPanelEstateInfo* LLFloaterRegionInfo::getPanelEstate() { LLFloaterRegionInfo* floater = LLFloaterRegionInfo::getInstance(); - if (!floater) return NULL; + if (!floater) return nullptr; LLTabContainer* tab = floater->getChild("region_panels"); LLPanelEstateInfo* panel = (LLPanelEstateInfo*)tab->getChild("Estate"); return panel; } // static -LLPanelEstateCovenant* LLFloaterRegionInfo::getPanelCovenant() +LLPanelEstateAccess* LLFloaterRegionInfo::getPanelAccess() { LLFloaterRegionInfo* floater = LLFloaterRegionInfo::getInstance(); if (!floater) return NULL; LLTabContainer* tab = floater->getChild("region_panels"); + LLPanelEstateAccess* panel = (LLPanelEstateAccess*)tab->getChild("Access"); + return panel; +} + +// static +LLPanelEstateCovenant* LLFloaterRegionInfo::getPanelCovenant() +{ + LLFloaterRegionInfo* floater = LLFloaterRegionInfo::getInstance(); + if (!floater) return nullptr; + LLTabContainer* tab = floater->getChild("region_panels"); LLPanelEstateCovenant* panel = (LLPanelEstateCovenant*)tab->getChild("Covenant"); return panel; } @@ -479,7 +545,7 @@ LLPanelRegionTerrainInfo* LLFloaterRegionInfo::getPanelRegionTerrain() if (!floater) { llassert(floater); - return NULL; + return nullptr; } LLTabContainer* tab_container = floater->getChild("region_panels"); @@ -489,6 +555,14 @@ LLPanelRegionTerrainInfo* LLFloaterRegionInfo::getPanelRegionTerrain() return panel; } +LLPanelRegionExperiences* LLFloaterRegionInfo::getPanelExperiences() +{ + LLFloaterRegionInfo* floater = LLFloaterRegionInfo::getInstance(); + if (!floater) return nullptr; + LLTabContainer* tab = floater->getChild("region_panels"); + return (LLPanelRegionExperiences*)tab->getChild("Experiences"); +} + void LLFloaterRegionInfo::onTabSelected(const LLSD& param) { LLPanelRegionInfo* active_panel = getChild(param.asString()); @@ -507,11 +581,7 @@ void LLFloaterRegionInfo::refreshFromRegion(LLViewerRegion* region) mInfoPanels.begin(), mInfoPanels.end(), llbind2nd( -#if LL_WINDOWS - std::mem_fun1(&LLPanelRegionInfo::refreshFromRegion), -#else std::mem_fun(&LLPanelRegionInfo::refreshFromRegion), -#endif region)); } @@ -525,6 +595,14 @@ void LLFloaterRegionInfo::refresh() } } +void LLFloaterRegionInfo::onGodLevelChange(U8 god_level) +{ + LLFloaterRegionInfo* floater = getInstance(); + if (floater && floater->getVisible()) + { + refreshFromRegion(gAgent.getRegion()); + } +} ///---------------------------------------------------------------------------- /// Local class implementation @@ -604,7 +682,7 @@ void LLPanelRegionInfo::sendEstateOwnerMessage( const LLUUID& invoice, const strings_t& strings) { - llinfos << "Sending estate request '" << request << "'" << llendl; + LL_INFOS() << "Sending estate request '" << request << "'" << LL_ENDL; msg->newMessage("EstateOwnerMessage"); msg->nextBlockFast(_PREHASH_AgentData); msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); @@ -616,7 +694,7 @@ void LLPanelRegionInfo::sendEstateOwnerMessage( if(strings.empty()) { msg->nextBlock("ParamList"); - msg->addString("Parameter", NULL); + msg->addString("Parameter", nullptr); } else { @@ -648,9 +726,10 @@ void LLPanelRegionInfo::initCtrl(const std::string& name) getChild(name)->setCommitCallback(boost::bind(&LLPanelRegionInfo::onChangeAnything, this)); } +// Singu TODO: Make this a callback registrar function instead. void LLPanelRegionInfo::initHelpBtn(const std::string& name, const std::string& xml_alert) { - childSetAction(name, boost::bind(&LLPanelRegionInfo::onClickHelp, this, xml_alert)); + getChild(name)->setCommitCallback(boost::bind(&LLPanelRegionInfo::onClickHelp, this, xml_alert)); } void LLPanelRegionInfo::onClickHelp(const std::string& xml_alert) @@ -711,6 +790,7 @@ BOOL LLPanelRegionGeneralInfo::postBuild() // Enable the "Apply" button if something is changed. JC initCtrl("block_terraform_check"); initCtrl("block_fly_check"); + initCtrl("block_fly_over_check"); initCtrl("allow_damage_check"); initCtrl("allow_land_resell_check"); initCtrl("allow_parcel_changes_check"); @@ -755,7 +835,7 @@ BOOL LLPanelRegionGeneralInfo::postBuild() void LLPanelRegionGeneralInfo::onClickKick() { - llinfos << "LLPanelRegionGeneralInfo::onClickKick" << llendl; + LL_INFOS() << "LLPanelRegionGeneralInfo::onClickKick" << LL_ENDL; // this depends on the grandparent view being a floater // in order to set up floater dependency @@ -790,7 +870,7 @@ void LLPanelRegionGeneralInfo::onKickCommit(const uuid_vec_t& ids) // static void LLPanelRegionGeneralInfo::onClickKickAll(void* userdata) { - llinfos << "LLPanelRegionGeneralInfo::onClickKickAll" << llendl; + LL_INFOS() << "LLPanelRegionGeneralInfo::onClickKickAll" << LL_ENDL; LLNotificationsUtil::add("KickUsersFromRegion", LLSD(), LLSD(), @@ -818,7 +898,7 @@ bool LLPanelRegionGeneralInfo::onKickAllCommit(const LLSD& notification, const L // static void LLPanelRegionGeneralInfo::onClickMessage(void* userdata) { - llinfos << "LLPanelRegionGeneralInfo::onClickMessage" << llendl; + LL_INFOS() << "LLPanelRegionGeneralInfo::onClickMessage" << LL_ENDL; LLNotificationsUtil::add("MessageRegion", LLSD(), LLSD(), @@ -833,7 +913,7 @@ bool LLPanelRegionGeneralInfo::onMessageCommit(const LLSD& notification, const L std::string text = response["message"].asString(); if (text.empty()) return false; - llinfos << "Message to everyone: " << text << llendl; + LL_INFOS() << "Message to everyone: " << text << LL_ENDL; strings_t strings; // [0] grid_x, unused here // [1] grid_y, unused here @@ -854,6 +934,46 @@ bool LLPanelRegionGeneralInfo::onMessageCommit(const LLSD& notification, const L return false; } +class ConsoleRequestResponder : public LLHTTPClient::ResponderIgnoreBody +{ + LOG_CLASS(ConsoleRequestResponder); +protected: + /*virtual*/ + void httpFailure() + { + LL_WARNS() << "error requesting mesh_rez_enabled " << dumpResponse() << LL_ENDL; + } + /*virtual*/ const char* getName() const { return "ConsoleRequestResponder"; } +}; + + +// called if this request times out. +class ConsoleUpdateResponder : public LLHTTPClient::ResponderIgnoreBody +{ + LOG_CLASS(ConsoleUpdateResponder); +protected: + /* virtual */ + void httpFailure() + { + LL_WARNS() << "error updating mesh enabled region setting " << dumpResponse() << LL_ENDL; + } +}; + +void LLFloaterRegionInfo::requestMeshRezInfo() +{ + std::string sim_console_url = gAgent.getRegion()->getCapability("SimConsoleAsync"); + + if (!sim_console_url.empty()) + { + std::string request_str = "get mesh_rez_enabled"; + + LLHTTPClient::post( + sim_console_url, + LLSD(request_str), + new ConsoleRequestResponder); + } +} + // setregioninfo // strings[0] = 'Y' - block terraform, 'N' - not // strings[1] = 'Y' - block fly, 'N' - not @@ -867,7 +987,7 @@ bool LLPanelRegionGeneralInfo::onMessageCommit(const LLSD& notification, const L // strings[9] = 'Y' - block parcel search, 'N' - allow BOOL LLPanelRegionGeneralInfo::sendUpdate() { - llinfos << "LLPanelRegionGeneralInfo::sendUpdate()" << llendl; + LL_INFOS() << "LLPanelRegionGeneralInfo::sendUpdate()" << LL_ENDL; // First try using a Cap. If that fails use the old method. LLSD body; @@ -876,6 +996,7 @@ BOOL LLPanelRegionGeneralInfo::sendUpdate() { body["block_terraform"] = getChild("block_terraform_check")->getValue(); body["block_fly"] = getChild("block_fly_check")->getValue(); + body["block_fly_over"] = getChild("block_fly_over_check")->getValue(); body["allow_damage"] = getChild("allow_damage_check")->getValue(); body["allow_land_resell"] = getChild("allow_land_resell_check")->getValue(); body["agent_limit"] = getChild("agent_limit_spin")->getValue(); @@ -965,6 +1086,7 @@ BOOL LLPanelRegionDebugInfo::postBuild() childSetAction("top_scripts_btn", onClickTopScripts, this); childSetAction("restart_btn", onClickRestart, this); childSetAction("cancel_restart_btn", onClickCancelRestart, this); + childSetAction("region_debug_console_btn", onClickDebugConsole, this); return TRUE; } @@ -986,6 +1108,7 @@ bool LLPanelRegionDebugInfo::refreshFromRegion(LLViewerRegion* region) getChildView("top_scripts_btn")->setEnabled(allow_modify); getChildView("restart_btn")->setEnabled(allow_modify); getChildView("cancel_restart_btn")->setEnabled(allow_modify); + getChildView("region_debug_console_btn")->setEnabled(allow_modify); return LLPanelRegionInfo::refreshFromRegion(region); } @@ -993,7 +1116,7 @@ bool LLPanelRegionDebugInfo::refreshFromRegion(LLViewerRegion* region) // virtual BOOL LLPanelRegionDebugInfo::sendUpdate() { - llinfos << "LLPanelRegionDebugInfo::sendUpdate" << llendl; + LL_INFOS() << "LLPanelRegionDebugInfo::sendUpdate" << LL_ENDL; strings_t strings; std::string buffer; @@ -1141,6 +1264,11 @@ void LLPanelRegionDebugInfo::onClickCancelRestart(void* data) self->sendEstateOwnerMessage(gMessageSystem, "restart", invoice, strings); } +// static +void LLPanelRegionDebugInfo::onClickDebugConsole(void* data) +{ + LLFloaterRegionDebugConsole::getInstance()->open(); +} BOOL LLPanelRegionTerrainInfo::validateTextureSizes() { @@ -1158,7 +1286,7 @@ BOOL LLPanelRegionTerrainInfo::validateTextureSizes() S32 width = img->getFullWidth(); S32 height = img->getFullHeight(); - //llinfos << "texture detail " << i << " is " << width << "x" << height << "x" << components << llendl; + //LL_INFOS() << "texture detail " << i << " is " << width << "x" << height << "x" << components << LL_ENDL; if (components != 3) { @@ -1169,7 +1297,7 @@ BOOL LLPanelRegionTerrainInfo::validateTextureSizes() return FALSE; } - if (width > 1024 || height > 1024) + if (width > 1024 || height > 1024) // { LLSD args; @@ -1251,8 +1379,8 @@ bool LLPanelRegionTerrainInfo::refreshFromRegion(LLViewerRegion* region) texture_ctrl = getChild(buffer); if(texture_ctrl) { - lldebugs << "Detail Texture " << i << ": " - << compp->getDetailTextureID(i) << llendl; + LL_DEBUGS() << "Detail Texture " << i << ": " + << compp->getDetailTextureID(i) << LL_ENDL; LLUUID tmp_id(compp->getDetailTextureID(i)); texture_ctrl->setImageAssetID(tmp_id); } @@ -1268,7 +1396,7 @@ bool LLPanelRegionTerrainInfo::refreshFromRegion(LLViewerRegion* region) } else { - lldebugs << "no region set" << llendl; + LL_DEBUGS() << "no region set" << LL_ENDL; getChild("region_text")->setValue(LLSD("")); } @@ -1283,7 +1411,7 @@ bool LLPanelRegionTerrainInfo::refreshFromRegion(LLViewerRegion* region) // virtual BOOL LLPanelRegionTerrainInfo::sendUpdate() { - llinfos << "LLPanelRegionTerrainInfo::sendUpdate" << llendl; + LL_INFOS() << "LLPanelRegionTerrainInfo::sendUpdate" << LL_ENDL; std::string buffer; strings_t strings; LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); @@ -1300,8 +1428,8 @@ BOOL LLPanelRegionTerrainInfo::sendUpdate() // ======================================= // Assemble and send texturedetail message - // Make sure user hasn't chosen wacky textures. - if (!validateTextureSizes()) + // Make sure user hasn't chosen wacky textures on sl grids. + if (gHippoGridManager->getConnectedGrid()->isSecondLife() && !validateTextureSizes()) { return FALSE; } @@ -1434,10 +1562,6 @@ void LLPanelEstateInfo::initDispatch(LLDispatcher& dispatch) { std::string name; -// name.assign("setowner"); -// static LLDispatchSetEstateOwner set_owner; -// dispatch.addHandler(name, &set_owner); - name.assign("estateupdateinfo"); static LLDispatchEstateUpdateInfo estate_update_info; dispatch.addHandler(name, &estate_update_info); @@ -1446,125 +1570,12 @@ void LLPanelEstateInfo::initDispatch(LLDispatcher& dispatch) static LLDispatchSetEstateAccess set_access; dispatch.addHandler(name, &set_access); - estate_dispatch_initialized = true; -} - -//--------------------------------------------------------------------------- -// Add/Remove estate access button callbacks -//--------------------------------------------------------------------------- -void LLPanelEstateInfo::onClickAddAllowedAgent() -{ - LLCtrlListInterface *list = childGetListInterface("allowed_avatar_name_list"); - if (!list) return; - if (list->getItemCount() >= ESTATE_MAX_ACCESS_IDS) - { - //args - - LLSD args; - args["MAX_AGENTS"] = llformat("%d",ESTATE_MAX_ACCESS_IDS); - LLNotificationsUtil::add("MaxAllowedAgentOnRegion", args); - return; - } - accessAddCore(ESTATE_ACCESS_ALLOWED_AGENT_ADD, "EstateAllowedAgentAdd"); -} - -void LLPanelEstateInfo::onClickRemoveAllowedAgent() -{ - accessRemoveCore(ESTATE_ACCESS_ALLOWED_AGENT_REMOVE, "EstateAllowedAgentRemove", "allowed_avatar_name_list"); -} - -void LLPanelEstateInfo::onClickAddAllowedGroup() -{ - LLCtrlListInterface *list = childGetListInterface("allowed_group_name_list"); - if (!list) return; - if (list->getItemCount() >= ESTATE_MAX_ACCESS_IDS) - { - LLSD args; - args["MAX_GROUPS"] = llformat("%d",ESTATE_MAX_ACCESS_IDS); - LLNotificationsUtil::add("MaxAllowedGroupsOnRegion", args); - return; - } - - LLNotification::Params params("ChangeLindenAccess"); - params.functor(boost::bind(&LLPanelEstateInfo::addAllowedGroup, this, _1, _2)); - if (isLindenEstate()) - { - LLNotifications::instance().add(params); - } - else - { - LLNotifications::instance().forceResponse(params, 0); - } -} - -bool LLPanelEstateInfo::addAllowedGroup(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (option != 0) return false; - - LLFloater* parent_floater = gFloaterView->getParentFloater(this); - - LLFloaterGroupPicker* widget = LLFloaterGroupPicker::showInstance(LLSD(gAgent.getID())); - if (widget) - { - widget->removeNoneOption(); - widget->setSelectGroupCallback(boost::bind(&LLPanelEstateInfo::addAllowedGroup2, this, _1)); - if (parent_floater) - { - LLRect new_rect = gFloaterView->findNeighboringPosition(parent_floater, widget); - widget->setOrigin(new_rect.mLeft, new_rect.mBottom); - parent_floater->addDependentFloater(widget); - } - } - - return false; -} - -void LLPanelEstateInfo::onClickRemoveAllowedGroup() -{ - accessRemoveCore(ESTATE_ACCESS_ALLOWED_GROUP_REMOVE, "EstateAllowedGroupRemove", "allowed_group_name_list"); -} - -void LLPanelEstateInfo::onClickAddBannedAgent() -{ - LLCtrlListInterface *list = childGetListInterface("banned_avatar_name_list"); - if (!list) return; - if (list->getItemCount() >= ESTATE_MAX_ACCESS_IDS) - { - LLSD args; - args["MAX_BANNED"] = llformat("%d",ESTATE_MAX_ACCESS_IDS); - LLNotificationsUtil::add("MaxBannedAgentsOnRegion", args); - return; - } - accessAddCore(ESTATE_ACCESS_BANNED_AGENT_ADD, "EstateBannedAgentAdd"); -} - -void LLPanelEstateInfo::onClickRemoveBannedAgent() -{ - accessRemoveCore(ESTATE_ACCESS_BANNED_AGENT_REMOVE, "EstateBannedAgentRemove", "banned_avatar_name_list"); -} -// static -void LLPanelEstateInfo::onClickAddEstateManager() -{ - LLCtrlListInterface *list = childGetListInterface("estate_manager_name_list"); - if (!list) return; - if (list->getItemCount() >= ESTATE_MAX_MANAGERS) - { // Tell user they can't add more managers - LLSD args; - args["MAX_MANAGER"] = llformat("%d",ESTATE_MAX_MANAGERS); - LLNotificationsUtil::add("MaxManagersOnRegion", args); - } - else - { // Go pick managers to add - accessAddCore(ESTATE_ACCESS_MANAGER_ADD, "EstateManagerAdd"); - } -} + name.assign("setexperience"); + static LLDispatchSetEstateExperience set_experience; + dispatch.addHandler(name, &set_experience); -// static -void LLPanelEstateInfo::onClickRemoveEstateManager() -{ - accessRemoveCore(ESTATE_ACCESS_MANAGER_REMOVE, "EstateManagerRemove", "estate_manager_name_list"); + estate_dispatch_initialized = true; } //--------------------------------------------------------------------------- @@ -1586,7 +1597,7 @@ void LLPanelEstateInfo::onClickKickUser() void LLPanelEstateInfo::onKickUserCommit(const uuid_vec_t& ids, const std::vector& names) { if (names.empty() || ids.empty()) return; - + //check to make sure there is one valid user and id if( ids[0].isNull() ) { @@ -1670,12 +1681,9 @@ struct LLEstateAccessChangeInfo { mDialogName = sd["dialog_name"].asString(); mOperationFlag = (U32)sd["operation"].asInteger(); - LLSD::array_const_iterator end_it = sd["allowed_ids"].endArray(); - for (LLSD::array_const_iterator id_it = sd["allowed_ids"].beginArray(); - id_it != end_it; - ++id_it) + for (auto const& id : sd["allowed_ids"].array()) { - mAgentOrGroupIDs.push_back(id_it->asUUID()); + mAgentOrGroupIDs.push_back(id.asUUID()); } } @@ -1684,11 +1692,13 @@ struct LLEstateAccessChangeInfo LLSD sd; sd["name"] = mDialogName; sd["operation"] = (S32)mOperationFlag; - for (uuid_vec_t::const_iterator it = mAgentOrGroupIDs.begin(); - it != mAgentOrGroupIDs.end(); - ++it) + for (U32 i = 0; i < mAgentOrGroupIDs.size(); ++i) { - sd["allowed_ids"].append(*it); + sd["allowed_ids"].append(mAgentOrGroupIDs[i]); + if (mAgentNames.size() > i) + { + sd["allowed_names"].append(mAgentNames[i].asLLSD()); + } } return sd; } @@ -1696,1901 +1706,2750 @@ struct LLEstateAccessChangeInfo U32 mOperationFlag; // ESTATE_ACCESS_BANNED_AGENT_ADD, _REMOVE, etc. std::string mDialogName; uuid_vec_t mAgentOrGroupIDs; // List of agent IDs to apply to this change + std::vector mAgentNames; // Optional list of the agent names for notifications }; -// Special case callback for groups, since it has different callback format than names -void LLPanelEstateInfo::addAllowedGroup2(LLUUID id) +// static +void LLPanelEstateInfo::updateEstateOwnerID(const LLUUID& id) { - LLSD payload; - payload["operation"] = (S32)ESTATE_ACCESS_ALLOWED_GROUP_ADD; - payload["dialog_name"] = "EstateAllowedGroupAdd"; - payload["allowed_ids"].append(id); - - LLSD args; - args["ALL_ESTATES"] = all_estates_text(); - - LLNotification::Params params("EstateAllowedGroupAdd"); - params.payload(payload) - .substitutions(args) - .functor(accessCoreConfirm); - if (isLindenEstate()) - { - LLNotifications::instance().forceResponse(params, 0); - } - else + LLPanelEstateInfo* panelp = LLFloaterRegionInfo::getPanelEstate(); + if (panelp) { - LLNotifications::instance().add(params); + panelp->getChild("estate_owner")->setValue(id); } } // static -void LLPanelEstateInfo::accessAddCore(U32 operation_flag, const std::string& dialog_name) +void LLPanelEstateInfo::updateEstateName(const std::string& name) { - LLSD payload; - payload["operation"] = (S32)operation_flag; - payload["dialog_name"] = dialog_name; - // agent id filled in after avatar picker - - LLNotification::Params params("ChangeLindenAccess"); - params.payload(payload) - .functor(accessAddCore2); - - if (isLindenEstate()) - { - LLNotifications::instance().add(params); - } - else + LLPanelEstateInfo* panelp = LLFloaterRegionInfo::getPanelEstate(); + if (panelp) { - // same as clicking "OK" - LLNotifications::instance().forceResponse(params, 0); + panelp->getChildRef("estate_name").setText(name); } } -// static -bool LLPanelEstateInfo::accessAddCore2(const LLSD& notification, const LLSD& response) +void LLPanelEstateInfo::updateControls(LLViewerRegion* region) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (option != 0) - { - // abort change - return false; - } + BOOL god = gAgent.isGodlike(); + BOOL owner = (region && (region->getOwner() == gAgent.getID())); + BOOL manager = (region && region->isEstateManager()); + setCtrlsEnabled(god || owner || manager); - LLEstateAccessChangeInfo* change_info = new LLEstateAccessChangeInfo(notification["payload"]); - // avatar picker yes multi-select, yes close-on-select - LLFloaterAvatarPicker::show(boost::bind(&LLPanelEstateInfo::accessAddCore3, _1, change_info), TRUE, TRUE); - return false; + getChildView("message_estate_btn")->setEnabled(god || owner || manager); + getChildView("kick_user_from_estate_btn")->setEnabled(god || owner || manager); + + refresh(); } -// static -void LLPanelEstateInfo::accessAddCore3(const uuid_vec_t& ids, LLEstateAccessChangeInfo* change_info) +bool LLPanelEstateInfo::refreshFromRegion(LLViewerRegion* region) { - if (!change_info) return; - if (ids.empty()) - { - // User didn't select a name. - delete change_info; - change_info = NULL; - return; + updateControls(region); + + // let the parent class handle the general data collection. + bool rv = LLPanelRegionInfo::refreshFromRegion(region); + + // We want estate info. To make sure it works across region + // boundaries and multiple packets, we add a serial number to the + // integers and track against that on update. + strings_t strings; + //integers_t integers; + //LLFloaterRegionInfo::incrementSerial(); + LLFloaterRegionInfo::nextInvoice(); + LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); + //integers.push_back(LLFloaterRegionInfo::());::getPanelEstate(); + + + sendEstateOwnerMessage(gMessageSystem, "getinfo", invoice, strings); + + refresh(); + + return rv; +} + +void LLPanelEstateInfo::updateChild(LLUICtrl* child_ctrl) +{ + // Ensure appropriate state of the management ui. + updateControls(gAgent.getRegion()); +} + +bool LLPanelEstateInfo::estateUpdate(LLMessageSystem* msg) +{ + LL_INFOS() << "LLPanelEstateInfo::estateUpdate()" << LL_ENDL; + return false; +} + + +BOOL LLPanelEstateInfo::postBuild() +{ + // set up the callbacks for the generic controls + initCtrl("externally_visible_check"); + initCtrl("allow_direct_teleport"); + initCtrl("limit_payment"); + initCtrl("limit_age_verified"); + initCtrl("voice_chat_check"); + initCtrl("use_global_time_check"); + initCtrl("fixed_sun_check"); + initCtrl("sun_hour_slider"); + initHelpBtn("use_global_time_help", "HelpEstateUseGlobalTime"); + initHelpBtn("fixed_sun_help", "HelpEstateFixedSun"); + initHelpBtn("externally_visible_help", "HelpEstateExternallyVisible"); + initHelpBtn("allow_direct_teleport_help", "HelpEstateAllowDirectTeleport"); + initHelpBtn("voice_chat_help", "HelpEstateVoiceChat"); + + // Set up the Legacy Estate Environment checkboxes + { + LLUICtrl* global_time = getChild("use_global_time_check"); + LLUICtrl* fixed_sun = getChild("fixed_sun_check"); + LLUICtrl* hour_slider = getChild("sun_hour_slider"); + global_time->setCommitCallback(boost::bind(on_change_use_other_sun, _2, fixed_sun, hour_slider)); + fixed_sun->setCommitCallback(boost::bind(on_change_fixed_sun, _2, global_time, hour_slider)); + } + + childSetAction("message_estate_btn", boost::bind(&LLPanelEstateInfo::onClickMessageEstate, this)); + childSetAction("kick_user_from_estate_btn", boost::bind(&LLPanelEstateInfo::onClickKickUser, this)); + + return LLPanelRegionInfo::postBuild(); +} + +void LLPanelEstateInfo::refresh() +{ + // Disable access restriction controls if they make no sense. + bool public_access = getChild("externally_visible_check")->getValue().asBoolean(); + + getChildView("Only Allow")->setEnabled(public_access); + getChildView("limit_payment")->setEnabled(public_access); + getChildView("limit_age_verified")->setEnabled(public_access); + + // if this is set to false, then the limit fields are meaningless and should be turned off + if (public_access == false) + { + getChild("limit_payment")->setValue(false); + getChild("limit_age_verified")->setValue(false); + } +} + +void LLPanelEstateInfo::refreshFromEstate() +{ + const LLEstateInfoModel& estate_info = LLEstateInfoModel::instance(); + + getChild("estate_name")->setValue(estate_info.getName()); + getChild("estate_owner")->setValue(estate_info.getOwnerID()); + + getChild("externally_visible_check")->setValue(estate_info.getIsExternallyVisible()); + getChild("voice_chat_check")->setValue(estate_info.getAllowVoiceChat()); + getChild("allow_direct_teleport")->setValue(estate_info.getAllowDirectTeleport()); + getChild("limit_payment")->setValue(estate_info.getDenyAnonymous()); + getChild("limit_age_verified")->setValue(estate_info.getDenyAgeUnverified()); + + // Ensure appropriate state of the management UI + updateControls(gAgent.getRegion()); + // Support Legacy Estate Environment + { + const LLEstateInfoModel& estate_info = LLEstateInfoModel::instance(); + bool global_time = estate_info.getGlobalTime(); + getChild("use_global_time_check")->setValue(global_time); + getChild("fixed_sun_check")->setEnabled(!global_time); + getChild("sun_hour_slider")->setEnabled(!global_time); + if (global_time) + { + getChild("use_global_time_check")->setEnabled(true); + getChild("fixed_sun_check")->setValue(false); + } + else + { + bool fixed_sun = estate_info.getUseFixedSun(); + getChild("use_global_time_check")->setEnabled(!fixed_sun); + getChild("fixed_sun_check")->setValue(fixed_sun); + F32 sun_hour = estate_info.getSunHour(); + if (sun_hour < 6.0f) sun_hour += 24.0f; + getChild("sun_hour_slider")->setValue(sun_hour); + } + } + refresh(); +} + +BOOL LLPanelEstateInfo::sendUpdate() +{ + LL_INFOS() << "LLPanelEstateInfo::sendUpdate()" << LL_ENDL; + + LLNotification::Params params("ChangeLindenEstate"); + params.functor(boost::bind(&LLPanelEstateInfo::callbackChangeLindenEstate, this, _1, _2)); + + if (isLindenEstate()) + { + // trying to change reserved estate, warn + LLNotifications::instance().add(params); + } + else + { + // for normal estates, just make the change + LLNotifications::instance().forceResponse(params, 0); + } + return TRUE; +} + +bool LLPanelEstateInfo::callbackChangeLindenEstate(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + switch(option) + { + case 0: + { + LLEstateInfoModel& estate_info = LLEstateInfoModel::instance(); + + // update model + estate_info.setIsExternallyVisible(getChild("externally_visible_check")->getValue().asBoolean()); + estate_info.setUseFixedSun(getChild("fixed_sun_check")->getValue().asBoolean()); + estate_info.setSunHour(get_sun_hour(getChild("sun_hour_slider"))); + estate_info.setAllowDirectTeleport(getChild("allow_direct_teleport")->getValue().asBoolean()); + estate_info.setDenyAnonymous(getChild("limit_payment")->getValue().asBoolean()); + estate_info.setDenyAgeUnverified(getChild("limit_age_verified")->getValue().asBoolean()); + estate_info.setAllowVoiceChat(getChild("voice_chat_check")->getValue().asBoolean()); + + // send the update to sim + estate_info.sendEstateInfo(); + } + + // we don't want to do this because we'll get it automatically from the sim + // after the spaceserver processes it +// else +// { +// // caps method does not automatically send this info +// LLFloaterRegionInfo::requestRegionInfo(); +// } + break; + case 1: + default: + // do nothing + break; + } + return false; +} + + +/* +// Request = "getowner" +// SParam[0] = "" (empty string) +// IParam[0] = serial +void LLPanelEstateInfo::getEstateOwner() +{ + // TODO -- disable the panel + // and call this function whenever we cross a region boundary + // re-enable when owner matches, and get new estate info + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_EstateOwnerRequest); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + + msg->nextBlockFast(_PREHASH_RequestData); + msg->addStringFast(_PREHASH_Request, "getowner"); + + // we send an empty string so that the variable block is not empty + msg->nextBlockFast(_PREHASH_StringData); + msg->addStringFast(_PREHASH_SParam, ""); + + msg->nextBlockFast(_PREHASH_IntegerData); + msg->addS32Fast(_PREHASH_IParam, LLFloaterRegionInfo::getSerial()); + + gAgent.sendMessage(); +} +*/ + +const std::string LLPanelEstateInfo::getOwnerName() const +{ + return getChild("estate_owner")->getText(); +} + +// static +void LLPanelEstateInfo::onClickMessageEstate(void* userdata) +{ + LL_INFOS() << "LLPanelEstateInfo::onClickMessageEstate" << LL_ENDL; + LLNotificationsUtil::add("MessageEstate", LLSD(), LLSD(), boost::bind(&LLPanelEstateInfo::onMessageCommit, (LLPanelEstateInfo*)userdata, _1, _2)); +} + +bool LLPanelEstateInfo::onMessageCommit(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + std::string text = response["message"].asString(); + if(option != 0) return false; + if(text.empty()) return false; + LL_INFOS() << "Message to everyone: " << text << LL_ENDL; + strings_t strings; + //integers_t integers; + std::string name; + LLAgentUI::buildFullname(name); + strings.push_back(strings_t::value_type(name)); + strings.push_back(strings_t::value_type(text)); + LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); + sendEstateOwnerMessage(gMessageSystem, "instantmessage", invoice, strings); + return false; +} + +LLPanelEstateCovenant::LLPanelEstateCovenant() + : LLPanelRegionInfo() + , mEstateNameText(nullptr) + , mEstateOwnerText(nullptr) + , mLastModifiedText(nullptr) + , mCovenantID(LLUUID::null) + , mEditor(nullptr) + , mAssetStatus(ASSET_ERROR) +{ +} + +// virtual +bool LLPanelEstateCovenant::refreshFromRegion(LLViewerRegion* region) +{ + LLTextBox* region_name = getChild("region_name_text"); + if (region_name) + { + region_name->setText(region->getName()); + } + + LLTextBox* resellable_clause = getChild("resellable_clause"); + if (resellable_clause) + { + if (region->getRegionFlag(REGION_FLAGS_BLOCK_LAND_RESELL)) + { + resellable_clause->setText(getString("can_not_resell")); + } + else + { + resellable_clause->setText(getString("can_resell")); + } } - // User did select a name. - change_info->mAgentOrGroupIDs = ids; - // Can't put estate owner on ban list - LLPanelEstateInfo* panel = LLFloaterRegionInfo::getPanelEstate(); - if (!panel) return; - LLViewerRegion* region = gAgent.getRegion(); - if (!region) return; - if (change_info->mOperationFlag & ESTATE_ACCESS_ALLOWED_AGENT_ADD) + LLTextBox* changeable_clause = getChild("changeable_clause"); + if (changeable_clause) { - LLCtrlListInterface *list = panel->childGetListInterface("allowed_avatar_name_list"); - int currentCount = (list ? list->getItemCount() : 0); - if (ids.size() + currentCount > ESTATE_MAX_ACCESS_IDS) + if (region->getRegionFlag(REGION_FLAGS_ALLOW_PARCEL_CHANGES)) { - LLSD args; - args["NUM_ADDED"] = llformat("%d",ids.size()); - args["MAX_AGENTS"] = llformat("%d",ESTATE_MAX_ACCESS_IDS); - args["LIST_TYPE"] = "Allowed Residents"; - args["NUM_EXCESS"] = llformat("%d",(ids.size()+currentCount)-ESTATE_MAX_ACCESS_IDS); - LLNotificationsUtil::add("MaxAgentOnRegionBatch", args); - delete change_info; - return; + changeable_clause->setText(getString("can_change")); + } + else + { + changeable_clause->setText(getString("can_not_change")); } } - if (change_info->mOperationFlag & ESTATE_ACCESS_BANNED_AGENT_ADD) + + LLTextBox* region_maturity = getChild("region_maturity_text"); + if (region_maturity) { - LLCtrlListInterface *list = panel->childGetListInterface("banned_avatar_name_list"); - int currentCount = (list ? list->getItemCount() : 0); - if (ids.size() + currentCount > ESTATE_MAX_ACCESS_IDS) + region_maturity->setText(region->getSimAccessString()); + } + + LLTextBox* region_landtype = getChild("region_landtype_text"); + region_landtype->setText(region->getLocalizedSimProductName()); + + // let the parent class handle the general data collection. + bool rv = LLPanelRegionInfo::refreshFromRegion(region); + LLMessageSystem *msg = gMessageSystem; + msg->newMessage("EstateCovenantRequest"); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID,gAgent.getSessionID()); + msg->sendReliable(region->getHost()); + return rv; +} + +// virtual +bool LLPanelEstateCovenant::estateUpdate(LLMessageSystem* msg) +{ + LL_INFOS() << "LLPanelEstateCovenant::estateUpdate()" << LL_ENDL; + return true; +} + +// virtual +BOOL LLPanelEstateCovenant::postBuild() +{ + initHelpBtn("covenant_help", "HelpEstateCovenant"); + mEstateNameText = getChild("estate_name_text"); + mEstateOwnerText = getChild("estate_owner_text"); + mLastModifiedText = getChild("covenant_timestamp_text"); + mEditor = getChild("covenant_editor"); + if (mEditor) mEditor->setHandleEditKeysDirectly(TRUE); + LLButton* reset_button = getChild("reset_covenant"); + reset_button->setEnabled(gAgent.canManageEstate()); + reset_button->setClickedCallback(LLPanelEstateCovenant::resetCovenantID, nullptr); + + return LLPanelRegionInfo::postBuild(); +} + +// virtual +void LLPanelEstateCovenant::updateChild(LLUICtrl* child_ctrl) +{ +} + +// virtual +BOOL LLPanelEstateCovenant::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg) +{ + LLInventoryItem* item = (LLInventoryItem*)cargo_data; + + if (!gAgent.canManageEstate()) + { + *accept = ACCEPT_NO; + return TRUE; + } + + switch(cargo_type) + { + case DAD_NOTECARD: + *accept = ACCEPT_YES_COPY_SINGLE; + if (item && drop) + { + LLSD payload; + payload["item_id"] = item->getUUID(); + LLNotificationsUtil::add("EstateChangeCovenant", LLSD(), payload, + LLPanelEstateCovenant::confirmChangeCovenantCallback); + } + break; + default: + *accept = ACCEPT_NO; + break; + } + + return TRUE; +} + +// static +bool LLPanelEstateCovenant::confirmChangeCovenantCallback(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + LLInventoryItem* item = gInventory.getItem(notification["payload"]["item_id"].asUUID()); + LLPanelEstateCovenant* self = LLFloaterRegionInfo::getPanelCovenant(); + + if (!item || !self) return false; + + switch(option) + { + case 0: + self->loadInvItem(item); + break; + default: + break; + } + return false; +} + +// static +void LLPanelEstateCovenant::resetCovenantID(void* userdata) +{ + LLNotificationsUtil::add("EstateChangeCovenant", LLSD(), LLSD(), confirmResetCovenantCallback); +} + +// static +bool LLPanelEstateCovenant::confirmResetCovenantCallback(const LLSD& notification, const LLSD& response) +{ + LLPanelEstateCovenant* self = LLFloaterRegionInfo::getPanelCovenant(); + if (!self) return false; + + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + switch(option) + { + case 0: + self->loadInvItem(nullptr); + break; + default: + break; + } + return false; +} + +void LLPanelEstateCovenant::loadInvItem(LLInventoryItem *itemp) +{ + const BOOL high_priority = TRUE; + if (itemp) + { + gAssetStorage->getInvItemAsset(gAgent.getRegionHost(), + gAgent.getID(), + gAgent.getSessionID(), + itemp->getPermissions().getOwner(), + LLUUID::null, + itemp->getUUID(), + itemp->getAssetUUID(), + itemp->getType(), + onLoadComplete, + (void*)this, + high_priority); + mAssetStatus = ASSET_LOADING; + } + else + { + mAssetStatus = ASSET_LOADED; + setCovenantTextEditor(LLTrans::getString("RegionNoCovenant")); + sendChangeCovenantID(LLUUID::null); + } +} + +// static +void LLPanelEstateCovenant::onLoadComplete(LLVFS *vfs, + const LLUUID& asset_uuid, + LLAssetType::EType type, + void* user_data, S32 status, LLExtStat ext_status) +{ + LL_INFOS() << "LLPanelEstateCovenant::onLoadComplete()" << LL_ENDL; + LLPanelEstateCovenant* panelp = (LLPanelEstateCovenant*)user_data; + if( panelp ) + { + if(0 == status) + { + LLVFile file(vfs, asset_uuid, type, LLVFile::READ); + + S32 file_length = file.getSize(); + + std::vector buffer(file_length+1); + file.read((U8*)&buffer[0], file_length); + // put a EOS at the end + buffer[file_length] = 0; + + if( (file_length > 19) && !strncmp( &buffer[0], "Linden text version", 19 ) ) + { + if( !panelp->mEditor->importBuffer( &buffer[0], file_length+1 ) ) + { + LL_WARNS() << "Problem importing estate covenant." << LL_ENDL; + LLNotificationsUtil::add("ProblemImportingEstateCovenant"); + } + else + { + panelp->sendChangeCovenantID(asset_uuid); + } + } + else + { + // Version 0 (just text, doesn't include version number) + panelp->sendChangeCovenantID(asset_uuid); + } + } + else { - LLSD args; - args["NUM_ADDED"] = llformat("%d",ids.size()); - args["MAX_AGENTS"] = llformat("%d",ESTATE_MAX_ACCESS_IDS); - args["LIST_TYPE"] = "Banned Residents"; - args["NUM_EXCESS"] = llformat("%d",(ids.size()+currentCount)-ESTATE_MAX_ACCESS_IDS); - LLNotificationsUtil::add("MaxAgentOnRegionBatch", args); - delete change_info; - return; + LLViewerStats::getInstance()->incStat( LLViewerStats::ST_DOWNLOAD_FAILED ); + + if( LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status || + LL_ERR_FILE_EMPTY == status) + { + LLNotificationsUtil::add("MissingNotecardAssetID"); + } + else if (LL_ERR_INSUFFICIENT_PERMISSIONS == status) + { + LLNotificationsUtil::add("NotAllowedToViewNotecard"); + } + else + { + LLNotificationsUtil::add("UnableToLoadNotecardAsset"); + } + + LL_WARNS() << "Problem loading notecard: " << status << LL_ENDL; } + panelp->mAssetStatus = ASSET_LOADED; + panelp->setCovenantID(asset_uuid); } +} - LLSD args; - args["ALL_ESTATES"] = all_estates_text(); +// key = "estatechangecovenantid" +// strings[0] = str(estate_id) (added by simulator before relay - not here) +// strings[1] = str(covenant_id) +void LLPanelEstateCovenant::sendChangeCovenantID(const LLUUID &asset_id) +{ + if (asset_id != getCovenantID()) + { + setCovenantID(asset_id); - LLNotification::Params params(change_info->mDialogName); - params.substitutions(args) - .payload(change_info->asLLSD()) - .functor(accessCoreConfirm); + LLMessageSystem* msg = gMessageSystem; + msg->newMessage("EstateOwnerMessage"); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addUUIDFast(_PREHASH_TransactionID, LLUUID::null); //not used - if (isLindenEstate()) - { - // just apply to this estate - LLNotifications::instance().forceResponse(params, 0); - } - else - { - // ask if this estate or all estates with this owner - LLNotifications::instance().add(params); + msg->nextBlock("MethodData"); + msg->addString("Method", "estatechangecovenantid"); + msg->addUUID("Invoice", LLFloaterRegionInfo::getLastInvoice()); + + msg->nextBlock("ParamList"); + msg->addString("Parameter", getCovenantID().asString()); + gAgent.sendReliableMessage(); } } -// static -void LLPanelEstateInfo::accessRemoveCore(U32 operation_flag, const std::string& dialog_name, const std::string& list_ctrl_name) +// virtual +BOOL LLPanelEstateCovenant::sendUpdate() { - LLPanelEstateInfo* panel = LLFloaterRegionInfo::getPanelEstate(); - if (!panel) return; - LLNameListCtrl* name_list = panel->getChild(list_ctrl_name); - if (!name_list) return; + return TRUE; +} - std::vector list_vector = name_list->getAllSelected(); - if (list_vector.size() == 0) - return; +std::string LLPanelEstateCovenant::getEstateName() const +{ + return mEstateNameText->getText(); +} - LLSD payload; - payload["operation"] = (S32)operation_flag; - payload["dialog_name"] = dialog_name; - - for (std::vector::const_iterator iter = list_vector.begin(); - iter != list_vector.end(); - iter++) +void LLPanelEstateCovenant::setEstateName(const std::string& name) +{ + mEstateNameText->setText(name); +} + +// static +void LLPanelEstateCovenant::updateCovenantText(const std::string& string, const LLUUID& asset_id) +{ + LLPanelEstateCovenant* panelp = LLFloaterRegionInfo::getPanelCovenant(); + if( panelp ) { - LLScrollListItem *item = (*iter); - payload["allowed_ids"].append(item->getUUID()); + panelp->mEditor->setText(string, false); + panelp->setCovenantID(asset_id); } - - LLNotification::Params params("ChangeLindenAccess"); - params.payload(payload) - .functor(accessRemoveCore2); +} - if (isLindenEstate()) +// static +void LLPanelEstateCovenant::updateEstateName(const std::string& name) +{ + LLPanelEstateCovenant* panelp = LLFloaterRegionInfo::getPanelCovenant(); + if( panelp ) { - // warn on change linden estate - LLNotifications::instance().add(params); + panelp->mEstateNameText->setText(name); } - else +} + +// static +void LLPanelEstateCovenant::updateLastModified(const std::string& text) +{ + LLPanelEstateCovenant* panelp = LLFloaterRegionInfo::getPanelCovenant(); + if( panelp ) { - // just proceed, as if clicking OK - LLNotifications::instance().forceResponse(params, 0); + panelp->mLastModifiedText->setText(text); } } // static -bool LLPanelEstateInfo::accessRemoveCore2(const LLSD& notification, const LLSD& response) +void LLPanelEstateCovenant::updateEstateOwnerID(const LLUUID& id) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (option != 0) + LLPanelEstateCovenant* panelp = LLFloaterRegionInfo::getPanelCovenant(); + if( panelp ) { - // abort - return false; + panelp->mEstateOwnerText->setValue(id); } +} - // If Linden estate, can only apply to "this" estate, not all estates - // owned by NULL. - if (isLindenEstate()) +std::string LLPanelEstateCovenant::getOwnerName() const +{ + return mEstateOwnerText->getText(); +} + +void LLPanelEstateCovenant::setCovenantTextEditor(const std::string& text) +{ + mEditor->setText(text, false); +} + +// key = "estateupdateinfo" +// strings[0] = estate name +// strings[1] = str(owner_id) +// strings[2] = str(estate_id) +// strings[3] = str(estate_flags) +// strings[4] = str((S32)(sun_hour * 1024)) +// strings[5] = str(parent_estate_id) +// strings[6] = str(covenant_id) +// strings[7] = str(covenant_timestamp) +// strings[8] = str(send_to_agent_only) +// strings[9] = str(abuse_email_addr) +bool LLDispatchEstateUpdateInfo::operator()( + const LLDispatcher* dispatcher, + const std::string& key, + const LLUUID& invoice, + const sparam_t& strings) +{ + LL_DEBUGS() << "Received estate update" << LL_ENDL; + + // Update estate info model. + // This will call LLPanelEstateInfo::refreshFromEstate(). + // *TODO: Move estate message handling stuff to llestateinfomodel.cpp. + LLEstateInfoModel::instance().update(strings); + + return true; +} + +bool LLDispatchSetEstateAccess::operator()( + const LLDispatcher* dispatcher, + const std::string& key, + const LLUUID& invoice, + const sparam_t& strings) +{ + LLPanelEstateAccess* panel = LLFloaterRegionInfo::getPanelAccess(); + if (!panel) return true; + + S32 index = 1; // skip estate_id + U32 access_flags = strtoul(strings[index++].c_str(), nullptr,10); + S32 num_allowed_agents = strtol(strings[index++].c_str(), nullptr, 10); + S32 num_allowed_groups = strtol(strings[index++].c_str(), nullptr, 10); + S32 num_banned_agents = strtol(strings[index++].c_str(), nullptr, 10); + S32 num_estate_managers = strtol(strings[index++].c_str(), nullptr, 10); + + // sanity ckecks + if (num_allowed_agents > 0 + && !(access_flags & ESTATE_ACCESS_ALLOWED_AGENTS)) { - accessCoreConfirm(notification, response); + LL_WARNS() << "non-zero count for allowed agents, but no corresponding flag" << LL_ENDL; } - else + if (num_allowed_groups > 0 + && !(access_flags & ESTATE_ACCESS_ALLOWED_GROUPS)) { - LLSD args; - args["ALL_ESTATES"] = all_estates_text(); - LLNotificationsUtil::add(notification["payload"]["dialog_name"], - args, - notification["payload"], - accessCoreConfirm); + LL_WARNS() << "non-zero count for allowed groups, but no corresponding flag" << LL_ENDL; + } + if (num_banned_agents > 0 + && !(access_flags & ESTATE_ACCESS_BANNED_AGENTS)) + { + LL_WARNS() << "non-zero count for banned agents, but no corresponding flag" << LL_ENDL; + } + if (num_estate_managers > 0 + && !(access_flags & ESTATE_ACCESS_MANAGERS)) + { + LL_WARNS() << "non-zero count for managers, but no corresponding flag" << LL_ENDL; } - return false; -} - -// Used for both access add and remove operations, depending on the mOperationFlag -// passed in (ESTATE_ACCESS_BANNED_AGENT_ADD, ESTATE_ACCESS_ALLOWED_AGENT_REMOVE, etc.) -// static -bool LLPanelEstateInfo::accessCoreConfirm(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - const U32 originalFlags = (U32)notification["payload"]["operation"].asInteger(); - LLViewerRegion* region = gAgent.getRegion(); - - LLSD::array_const_iterator end_it = notification["payload"]["allowed_ids"].endArray(); + // Build an LLSD to fake the http response on older grids + LLSD result; - for (LLSD::array_const_iterator iter = notification["payload"]["allowed_ids"].beginArray(); - iter != end_it; - iter++) + // grab the UUID's out of the string fields + if (access_flags & ESTATE_ACCESS_ALLOWED_AGENTS) { - U32 flags = originalFlags; - if (iter + 1 != end_it) - flags |= ESTATE_ACCESS_NO_REPLY; + LLNameListCtrl* allowed_agent_name_list = panel->getChild("allowed_avatar_name_list"); - const LLUUID id = iter->asUUID(); - if (((U32)notification["payload"]["operation"].asInteger() & ESTATE_ACCESS_BANNED_AGENT_ADD) - && region && (region->getOwner() == id)) + if (allowed_agent_name_list) { - LLNotificationsUtil::add("OwnerCanNotBeDenied"); - break; + auto& allowed_agents = result["AllowedAgents"]; + for (const auto& id : allowed_agent_name_list->getAllIDs()) + { + allowed_agents.append(LLSD().with("id", id)); + } + for (S32 i = 0; i < num_allowed_agents; ++i) + { + LLUUID id; + memcpy(id.mData, strings[index++].data(), UUID_BYTES); /* Flawfinder: ignore */ + allowed_agents.append(LLSD().with("id", id)); + } } - switch(option) + } + + if (access_flags & ESTATE_ACCESS_ALLOWED_GROUPS) + { + auto& allowed_groups = result["AllowedGroups"]; + for (S32 i = 0; i < num_allowed_groups; ++i) { - case 0: - // This estate - sendEstateAccessDelta(flags, id); - break; - case 1: - { - // All estates, either than I own or manage for this owner. - // This will be verified on simulator. JC - if (!region) break; - if (region->getOwner() == gAgent.getID() - || gAgent.isGodlike()) - { - flags |= ESTATE_ACCESS_APPLY_TO_ALL_ESTATES; - sendEstateAccessDelta(flags, id); - } - else if (region->isEstateManager()) - { - flags |= ESTATE_ACCESS_APPLY_TO_MANAGED_ESTATES; - sendEstateAccessDelta(flags, id); - } - break; + LLUUID id; + memcpy(id.mData, strings[index++].data(), UUID_BYTES); /* Flawfinder: ignore */ + allowed_groups.append(LLSD().with("id", id)); + } + } + + if (access_flags & ESTATE_ACCESS_BANNED_AGENTS) + { + if (LLNameListCtrl* banned_agent_name_list = panel->getChild("banned_avatar_name_list")) + { + auto& banned_agents = result["BannedAgents"]; + for (const auto& id : banned_agent_name_list->getAllIDs()) + { + banned_agents.append(LLSD().with("id", id)); + } + for (S32 i = 0; i < num_banned_agents; i++) + { + LLUUID id; + memcpy(id.mData, strings[index++].data(), UUID_BYTES); /* Flawfinder: ignore */ + banned_agents.append(LLSD().with("id", id)); } - case 2: - default: - break; } } - return false; + + if (access_flags & ESTATE_ACCESS_MANAGERS) + { + auto& managers = result["Managers"]; + for (S32 i = 0; i < num_estate_managers; ++i) + { + LLUUID id; + memcpy(id.mData, strings[index++].data(), UUID_BYTES); /* Flawfinder: ignore */ + managers.append(LLSD().with("id", id)); + } + } + + if (panel) + { + panel->onEstateAccessReceived(result); // Until HTTP response use UDP Result + if (panel->getPendingUpdate()) + { + panel->setPendingUpdate(false); + panel->updateLists(); + } + } + return true; } -// key = "estateaccessdelta" -// str(estate_id) will be added to front of list by forward_EstateOwnerRequest_to_dataserver -// str[0] = str(agent_id) requesting the change -// str[1] = str(flags) (ESTATE_ACCESS_DELTA_*) -// str[2] = str(agent_id) to add or remove -// static -void LLPanelEstateInfo::sendEstateAccessDelta(U32 flags, const LLUUID& agent_or_group_id) +LLSD LLDispatchSetEstateExperience::getIDs( sparam_t::const_iterator it, sparam_t::const_iterator end, S32 count ) { - LLMessageSystem* msg = gMessageSystem; - msg->newMessage("EstateOwnerMessage"); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->addUUIDFast(_PREHASH_TransactionID, LLUUID::null); //not used + LLSD idList = LLSD::emptyArray(); + LLUUID id; + while(count--> 0) + { + memcpy(id.mData, (*(it++)).data(), UUID_BYTES); + idList.append(id); + } + return idList; +} - msg->nextBlock("MethodData"); - msg->addString("Method", "estateaccessdelta"); - msg->addUUID("Invoice", LLFloaterRegionInfo::getLastInvoice()); +// key = "setexperience" +// strings[0] = str(estate_id) +// strings[1] = str(send_to_agent_only) +// strings[2] = str(num blocked) +// strings[3] = str(num trusted) +// strings[4] = str(num allowed) +// strings[8] = bin(uuid) ... +// ... +bool LLDispatchSetEstateExperience::operator()( + const LLDispatcher* dispatcher, + const std::string& key, + const LLUUID& invoice, + const sparam_t& strings) +{ + LLPanelRegionExperiences* panel = LLFloaterRegionInfo::getPanelExperiences(); + if (!panel) return true; - std::string buf; - gAgent.getID().toString(buf); - msg->nextBlock("ParamList"); - msg->addString("Parameter", buf); + 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); - buf = llformat("%u", flags); - msg->nextBlock("ParamList"); - msg->addString("Parameter", buf); + LLUUID id; + S32 num_blocked = strtol((*(it++)).c_str(), nullptr, 10); + S32 num_trusted = strtol((*(it++)).c_str(), nullptr, 10); + S32 num_allowed = strtol((*(it++)).c_str(), nullptr, 10); - agent_or_group_id.toString(buf); - msg->nextBlock("ParamList"); - msg->addString("Parameter", buf); + 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)); + panel->processResponse(ids); - LLPanelEstateInfo* panel = LLFloaterRegionInfo::getPanelEstate(); + return true; +} - if (flags & (ESTATE_ACCESS_ALLOWED_AGENT_ADD | ESTATE_ACCESS_ALLOWED_AGENT_REMOVE | - ESTATE_ACCESS_BANNED_AGENT_ADD | ESTATE_ACCESS_BANNED_AGENT_REMOVE)) - { - - panel->clearAccessLists(); - } - gAgent.sendReliableMessage(); + +LLPanelEnvironmentInfo::LLPanelEnvironmentInfo() +: mEnableEditing(false), + mRegionSettingsRadioGroup(nullptr), + mDayCycleSettingsRadioGroup(nullptr), + mWaterPresetCombo(nullptr), + mSkyPresetCombo(nullptr), + mDayCyclePresetCombo(nullptr) +{ } -// static -void LLPanelEstateInfo::updateEstateOwnerName(const std::string& name) +// virtual +BOOL LLPanelEnvironmentInfo::postBuild() { - LLPanelEstateInfo* panelp = LLFloaterRegionInfo::getPanelEstate(); - if (panelp) - { - panelp->setOwnerName(name); - } + mRegionSettingsRadioGroup = getChild("region_settings_radio_group"); + mRegionSettingsRadioGroup->setCommitCallback(boost::bind(&LLPanelEnvironmentInfo::onSwitchRegionSettings, this)); + + mDayCycleSettingsRadioGroup = getChild("sky_dayc_settings_radio_group"); + mDayCycleSettingsRadioGroup->setCommitCallback(boost::bind(&LLPanelEnvironmentInfo::onSwitchDayCycle, this)); + + mWaterPresetCombo = getChild("water_settings_preset_combo"); + mWaterPresetCombo->setCommitCallback(boost::bind(&LLPanelEnvironmentInfo::onSelectWaterPreset, this)); + + mSkyPresetCombo = getChild("sky_settings_preset_combo"); + mSkyPresetCombo->setCommitCallback(boost::bind(&LLPanelEnvironmentInfo::onSelectSkyPreset, this)); + + mDayCyclePresetCombo = getChild("dayc_settings_preset_combo"); + mDayCyclePresetCombo->setCommitCallback(boost::bind(&LLPanelEnvironmentInfo::onSelectDayCycle, this)); + + getChild("apply_btn")->setCommitCallback(boost::bind(&LLPanelEnvironmentInfo::onBtnApply, this)); + getChild("apply_btn")->setRightMouseDownCallback(boost::bind(&LLEnvManagerNew::dumpUserPrefs, LLEnvManagerNew::getInstance())); + getChild("cancel_btn")->setCommitCallback(boost::bind(&LLPanelEnvironmentInfo::onBtnCancel, this)); + getChild("cancel_btn")->setRightMouseDownCallback(boost::bind(&LLEnvManagerNew::dumpPresets, LLEnvManagerNew::getInstance())); + + LLEnvManagerNew::instance().setRegionSettingsChangeCallback(boost::bind(&LLPanelEnvironmentInfo::onRegionSettingschange, this)); + LLEnvManagerNew::instance().setRegionSettingsAppliedCallback(boost::bind(&LLPanelEnvironmentInfo::onRegionSettingsApplied, this, _1)); + + LLDayCycleManager::instance().setModifyCallback(boost::bind(&LLPanelEnvironmentInfo::populateDayCyclesList, this)); + LLWLParamManager::instance().setPresetListChangeCallback(boost::bind(&LLPanelEnvironmentInfo::populateSkyPresetsList, this)); + LLWaterParamManager::instance().setPresetListChangeCallback(boost::bind(&LLPanelEnvironmentInfo::populateWaterPresetsList, this)); + + return TRUE; } -// static -void LLPanelEstateInfo::updateEstateName(const std::string& name) +// virtual +void LLPanelEnvironmentInfo::onOpen(const LLSD& key) { - LLPanelEstateInfo* panelp = LLFloaterRegionInfo::getPanelEstate(); - if (panelp) + LL_DEBUGS("Windlight") << "Panel opened, refreshing" << LL_ENDL; + refresh(); +} + +// virtual +void LLPanelEnvironmentInfo::handleVisibilityChange(BOOL new_visibility) +{ + // If hiding (user switched to another tab or closed the floater), + // display user's preferred environment. + if (!new_visibility) { - panelp->getChildRef("estate_name").setText(name); + LLEnvManagerNew::instance().usePrefs(); } } -void LLPanelEstateInfo::updateControls(LLViewerRegion* region) +// virtual +bool LLPanelEnvironmentInfo::refreshFromRegion(LLViewerRegion* region) { - BOOL god = gAgent.isGodlike(); - BOOL owner = (region && (region->getOwner() == gAgent.getID())); - BOOL manager = (region && region->isEstateManager()); - setCtrlsEnabled(god || owner || manager); + LL_DEBUGS("Windlight") << "Region updated, enabling/disabling controls" << LL_ENDL; + BOOL owner_or_god = gAgent.isGodlike() || (region && (region->getOwner() == gAgent.getID())); + BOOL owner_or_god_or_manager = owner_or_god || (region && region->isEstateManager()); - BOOL has_allowed_avatar = getChild("allowed_avatar_name_list")->getFirstSelected() ? TRUE : FALSE; - BOOL has_allowed_group = getChild("allowed_group_name_list")->getFirstSelected() ? TRUE : FALSE; - BOOL has_banned_agent = getChild("banned_avatar_name_list")->getFirstSelected() ? TRUE : FALSE; - BOOL has_estate_manager = getChild("estate_manager_name_list")->getFirstSelected() ? TRUE : FALSE; + // Don't refresh from region settings to avoid flicker after applying new region settings. + mEnableEditing = owner_or_god_or_manager; + setControlsEnabled(mEnableEditing); - getChildView("add_allowed_avatar_btn")->setEnabled(god || owner || manager); - getChildView("remove_allowed_avatar_btn")->setEnabled(has_allowed_avatar && (god || owner || manager)); - getChildView("allowed_avatar_name_list")->setEnabled(god || owner || manager); + return LLPanelRegionInfo::refreshFromRegion(region); +} - getChildView("add_allowed_group_btn")->setEnabled(god || owner || manager); - getChildView("remove_allowed_group_btn")->setEnabled(has_allowed_group && (god || owner || manager) ); - getChildView("allowed_group_name_list")->setEnabled(god || owner || manager); +void LLPanelEnvironmentInfo::refresh() +{ + if(gDisconnected) + { + return; + } - // Can't ban people from mainland, orientation islands, etc. because this - // creates much network traffic and server load. - // Disable their accounts in CSR tool instead. - bool linden_estate = isLindenEstate(); - bool enable_ban = (god || owner || manager) && !linden_estate; - getChildView("add_banned_avatar_btn")->setEnabled(enable_ban); - getChildView("remove_banned_avatar_btn")->setEnabled(has_banned_agent && enable_ban); - getChildView("banned_avatar_name_list")->setEnabled(god || owner || manager); + populateWaterPresetsList(); + populateSkyPresetsList(); + populateDayCyclesList(); - getChildView("message_estate_btn")->setEnabled(god || owner || manager); - getChildView("kick_user_from_estate_btn")->setEnabled(god || owner || manager); + // Init radio groups. + const LLEnvironmentSettings& settings = LLEnvManagerNew::instance().getRegionSettings(); + const LLSD& dc = settings.getWLDayCycle(); + LLSD::Real first_frame_time = dc.size() > 0 ? dc[0][0].asReal() : 0.0f; + const bool use_fixed_sky = dc.size() == 1 && first_frame_time < 0; + mRegionSettingsRadioGroup->setSelectedIndex(settings.getSkyMap().size() == 0 ? 0 : 1); + mDayCycleSettingsRadioGroup->setSelectedIndex(use_fixed_sky ? 0 : 1); - // estate managers can't add estate managers - getChildView("add_estate_manager_btn")->setEnabled(god || owner); - getChildView("remove_estate_manager_btn")->setEnabled(has_estate_manager && (god || owner)); - getChildView("estate_manager_name_list")->setEnabled(god || owner); + setControlsEnabled(mEnableEditing); - refresh(); + setDirty(false); } -bool LLPanelEstateInfo::refreshFromRegion(LLViewerRegion* region) +void LLPanelEnvironmentInfo::setControlsEnabled(bool enabled) { - updateControls(region); - - // let the parent class handle the general data collection. - bool rv = LLPanelRegionInfo::refreshFromRegion(region); + mRegionSettingsRadioGroup->setEnabled(enabled); + mDayCycleSettingsRadioGroup->setEnabled(enabled); - // We want estate info. To make sure it works across region - // boundaries and multiple packets, we add a serial number to the - // integers and track against that on update. - strings_t strings; - //integers_t integers; - //LLFloaterRegionInfo::incrementSerial(); - LLFloaterRegionInfo::nextInvoice(); - LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); - //integers.push_back(LLFloaterRegionInfo::());::getPanelEstate(); + mWaterPresetCombo->setEnabled(enabled); + mSkyPresetCombo->setEnabled(enabled); + mDayCyclePresetCombo->setEnabled(enabled); - - LLPanelEstateInfo* panel = LLFloaterRegionInfo::getPanelEstate(); - panel->clearAccessLists(); - + getChildView("apply_btn")->setEnabled(enabled); + getChildView("cancel_btn")->setEnabled(enabled); - sendEstateOwnerMessage(gMessageSystem, "getinfo", invoice, strings); + if (enabled) + { + // Enable/disable some controls based on currently selected radio buttons. + bool use_defaults = mRegionSettingsRadioGroup->getSelectedIndex() == 0; + getChild("user_environment_settings")->setEnabled(!use_defaults); - refresh(); + bool is_fixed_sky = mDayCycleSettingsRadioGroup->getSelectedIndex() == 0; + mSkyPresetCombo->setEnabled(is_fixed_sky); + mDayCyclePresetCombo->setEnabled(!is_fixed_sky); + } +} - return rv; +void LLPanelEnvironmentInfo::setApplyProgress(bool started) +{ + LLTextBox* indicator = getChild("progress_indicator"); + + indicator->setVisible(started); + +/* Singu TODO: LLLoadingIndicator + if (started) + { + indicator->start(); + } + else + { + indicator->stop(); + } +*/ } -void LLPanelEstateInfo::updateChild(LLUICtrl* child_ctrl) +void LLPanelEnvironmentInfo::setDirty(bool dirty) { - // Ensure appropriate state of the management ui. - updateControls(gAgent.getRegion()); + getChildView("apply_btn")->setEnabled(dirty); + getChildView("cancel_btn")->setEnabled(dirty); } -bool LLPanelEstateInfo::estateUpdate(LLMessageSystem* msg) +void LLPanelEnvironmentInfo::sendRegionSunUpdate() { - llinfos << "LLPanelEstateInfo::estateUpdate()" << llendl; - return false; + LLRegionInfoModel& region_info = LLRegionInfoModel::instance(); + + // If the region is being switched to fixed sky, + // change the region's sun hour according to the (fixed) sun position. + // This is needed for llGetSunDirection() LSL function to work properly (STORM-1330). + const LLSD& sky_map = mNewRegionSettings.getSkyMap(); + bool region_use_fixed_sky = sky_map.size() == 1; + if (region_use_fixed_sky) + { + LLWLParamSet param_set; + llassert(sky_map.isMap()); + param_set.setAll(sky_map.beginMap()->second); + F32 sun_angle = param_set.getSunAngle(); + + LL_DEBUGS("Windlight Sync") << "Old sun hour: " << region_info.mSunHour << LL_ENDL; + // convert value range from 0..2pi to 6..30 + region_info.mSunHour = fmodf((sun_angle / F_TWO_PI) * 24.f, 24.f) + 6.f; + } + + region_info.setUseFixedSun(region_use_fixed_sky); + region_info.mUseEstateSun = !region_use_fixed_sky; + LL_DEBUGS("Windlight Sync") << "Sun hour: " << region_info.mSunHour << LL_ENDL; + + region_info.sendRegionTerrain(LLFloaterRegionInfo::getLastInvoice()); } - -BOOL LLPanelEstateInfo::postBuild() +void LLPanelEnvironmentInfo::fixEstateSun() { - // set up the callbacks for the generic controls - initCtrl("externally_visible_check"); - initCtrl("use_global_time_check"); - initCtrl("fixed_sun_check"); - initCtrl("sun_hour_slider"); - initCtrl("allow_direct_teleport"); - initCtrl("limit_payment"); - initCtrl("limit_age_verified"); - initCtrl("voice_chat_check"); - initHelpBtn("estate_manager_help", "HelpEstateEstateManager"); - initHelpBtn("use_global_time_help", "HelpEstateUseGlobalTime"); - initHelpBtn("fixed_sun_help", "HelpEstateFixedSun"); - initHelpBtn("externally_visible_help", "HelpEstateExternallyVisible"); - initHelpBtn("allow_direct_teleport_help", "HelpEstateAllowDirectTeleport"); - initHelpBtn("allow_resident_help", "HelpEstateAllowResident"); - initHelpBtn("allow_group_help", "HelpEstateAllowGroup"); - initHelpBtn("ban_resident_help", "HelpEstateBanResident"); - initHelpBtn("voice_chat_help", "HelpEstateVoiceChat"); - - // Set up the Legacy Estate Environment checkboxes + // We don't support fixed sun estates anymore and need to fix + // such estates for region day cycle to take effect. + // *NOTE: Assuming that current estate settings have arrived already. + LLEstateInfoModel& estate_info = LLEstateInfoModel::instance(); + if (estate_info.getUseFixedSun()) { - LLUICtrl* global_time = getChild("use_global_time_check"); - LLUICtrl* fixed_sun = getChild("fixed_sun_check"); - LLUICtrl* hour_slider = getChild("sun_hour_slider"); - global_time->setCommitCallback(boost::bind(on_change_use_other_sun, _2, fixed_sun, hour_slider)); - fixed_sun->setCommitCallback(boost::bind(on_change_fixed_sun, _2, global_time, hour_slider)); + LL_INFOS() << "Switching estate to global sun" << LL_ENDL; + estate_info.setUseFixedSun(false); + estate_info.sendEstateInfo(); } +} - getChild("allowed_avatar_name_list")->setCommitCallback(boost::bind(&LLPanelEstateInfo::onChangeChildCtrl, this, _1)); - LLNameListCtrl *avatar_name_list = getChild("allowed_avatar_name_list"); - if (avatar_name_list) +void LLPanelEnvironmentInfo::populateWaterPresetsList() +{ + mWaterPresetCombo->removeall(); + + // If the region already has water params, add them to the list. + const LLEnvironmentSettings& region_settings = LLEnvManagerNew::instance().getRegionSettings(); + if (region_settings.getWaterParams().size() != 0) { - avatar_name_list->setCommitOnSelectionChange(TRUE); - avatar_name_list->setMaxItemCount(ESTATE_MAX_ACCESS_IDS); + const std::string& region_name = gAgent.getRegion()->getName(); + mWaterPresetCombo->add(region_name, LLWLParamKey(region_name, LLEnvKey::SCOPE_REGION).toLLSD()); + mWaterPresetCombo->addSeparator(); } - childSetAction("add_allowed_avatar_btn", boost::bind(&LLPanelEstateInfo::onClickAddAllowedAgent, this)); - childSetAction("remove_allowed_avatar_btn", boost::bind(&LLPanelEstateInfo::onClickRemoveAllowedAgent, this)); + std::list user_presets, system_presets; + LLWaterParamManager::instance().getPresetNames(user_presets, system_presets); - getChild("allowed_group_name_list")->setCommitCallback(boost::bind(&LLPanelEstateInfo::onChangeChildCtrl, this, _1)); - LLNameListCtrl* group_name_list = getChild("allowed_group_name_list"); - if (group_name_list) + // Add local user presets first. + for (std::list::const_iterator it = user_presets.begin(); it != user_presets.end(); ++it) { - group_name_list->setCommitOnSelectionChange(TRUE); - group_name_list->setMaxItemCount(ESTATE_MAX_ACCESS_IDS); + mWaterPresetCombo->add(*it, LLWLParamKey(*it, LLEnvKey::SCOPE_LOCAL).toLLSD()); } - getChild("add_allowed_group_btn")->setCommitCallback(boost::bind(&LLPanelEstateInfo::onClickAddAllowedGroup, this)); - childSetAction("remove_allowed_group_btn", boost::bind(&LLPanelEstateInfo::onClickRemoveAllowedGroup, this)); - - getChild("banned_avatar_name_list")->setCommitCallback(boost::bind(&LLPanelEstateInfo::onChangeChildCtrl, this, _1)); - LLNameListCtrl* banned_name_list = getChild("banned_avatar_name_list"); - if (banned_name_list) + if (user_presets.size() > 0) { - banned_name_list->setCommitOnSelectionChange(TRUE); - banned_name_list->setMaxItemCount(ESTATE_MAX_ACCESS_IDS); + mWaterPresetCombo->addSeparator(); } - childSetAction("add_banned_avatar_btn", boost::bind(&LLPanelEstateInfo::onClickAddBannedAgent, this)); - childSetAction("remove_banned_avatar_btn", boost::bind(&LLPanelEstateInfo::onClickRemoveBannedAgent, this)); - - getChild("estate_manager_name_list")->setCommitCallback(boost::bind(&LLPanelEstateInfo::onChangeChildCtrl, this, _1)); - LLNameListCtrl* manager_name_list = getChild("estate_manager_name_list"); - if (manager_name_list) + // Add local system presets. + for (std::list::const_iterator it = system_presets.begin(); it != system_presets.end(); ++it) { - manager_name_list->setCommitOnSelectionChange(TRUE); - manager_name_list->setMaxItemCount(ESTATE_MAX_MANAGERS * 4); // Allow extras for dupe issue + mWaterPresetCombo->add(*it, LLWLParamKey(*it, LLEnvKey::SCOPE_LOCAL).toLLSD()); } - childSetAction("add_estate_manager_btn", boost::bind(&LLPanelEstateInfo::onClickAddEstateManager, this)); - childSetAction("remove_estate_manager_btn", boost::bind(&LLPanelEstateInfo::onClickRemoveEstateManager, this)); - childSetAction("message_estate_btn", boost::bind(&LLPanelEstateInfo::onClickMessageEstate, this)); - childSetAction("kick_user_from_estate_btn", boost::bind(&LLPanelEstateInfo::onClickKickUser, this)); - - return LLPanelRegionInfo::postBuild(); + // There's no way to select current preset because its name is not stored on server. } -void LLPanelEstateInfo::refresh() +void LLPanelEnvironmentInfo::populateSkyPresetsList() { - // Disable access restriction controls if they make no sense. - bool public_access = getChild("externally_visible_check")->getValue().asBoolean(); + mSkyPresetCombo->removeall(); - getChildView("Only Allow")->setEnabled(public_access); - getChildView("limit_payment")->setEnabled(public_access); - getChildView("limit_age_verified")->setEnabled(public_access); + LLWLParamManager::preset_name_list_t region_presets; + LLWLParamManager::preset_name_list_t user_presets, sys_presets; + LLWLParamManager::instance().getPresetNames(region_presets, user_presets, sys_presets); - // if this is set to false, then the limit fields are meaningless and should be turned off - if (public_access == false) + // Add region presets. + std::string region_name = gAgent.getRegion() ? gAgent.getRegion()->getName() : LLTrans::getString("Unknown"); + for (LLWLParamManager::preset_name_list_t::const_iterator it = region_presets.begin(); it != region_presets.end(); ++it) { - getChild("limit_payment")->setValue(false); - getChild("limit_age_verified")->setValue(false); + std::string preset_name = *it; + std::string item_title = preset_name + " (" + region_name + ")"; + mSkyPresetCombo->add(item_title, LLWLParamKey(preset_name, LLEnvKey::SCOPE_REGION).toStringVal()); } -} - -void LLPanelEstateInfo::refreshFromEstate() -{ - const LLEstateInfoModel& estate_info = LLEstateInfoModel::instance(); - - getChild("estate_name")->setValue(estate_info.getName()); - LLAvatarNameCache::get(estate_info.getOwnerID(), boost::bind(&LLPanelEstateInfo::setOwnerPNSName, this, _1, _2)); - - getChild("externally_visible_check")->setValue(estate_info.getIsExternallyVisible()); - getChild("voice_chat_check")->setValue(estate_info.getAllowVoiceChat()); - getChild("allow_direct_teleport")->setValue(estate_info.getAllowDirectTeleport()); - getChild("limit_payment")->setValue(estate_info.getDenyAnonymous()); - getChild("limit_age_verified")->setValue(estate_info.getDenyAgeUnverified()); - // Ensure appropriate state of the management UI - updateControls(gAgent.getRegion()); - // Support Legacy Estate Environment + if (!region_presets.empty()) { - const LLEstateInfoModel& estate_info = LLEstateInfoModel::instance(); - bool global_time = estate_info.getGlobalTime(); - getChild("use_global_time_check")->setValue(global_time); - getChild("fixed_sun_check")->setEnabled(!global_time); - getChild("sun_hour_slider")->setEnabled(!global_time); - if (global_time) - { - getChild("use_global_time_check")->setEnabled(true); - getChild("fixed_sun_check")->setValue(false); - } - else - { - bool fixed_sun = estate_info.getUseFixedSun(); - getChild("use_global_time_check")->setEnabled(!fixed_sun); - getChild("fixed_sun_check")->setValue(fixed_sun); - F32 sun_hour = estate_info.getSunHour(); - if (sun_hour < 6.0f) sun_hour += 24.0f; - getChild("sun_hour_slider")->setValue(sun_hour); - } + mSkyPresetCombo->addSeparator(); } - refresh(); -} - -BOOL LLPanelEstateInfo::sendUpdate() -{ - llinfos << "LLPanelEstateInfo::sendUpdate()" << llendl; - LLNotification::Params params("ChangeLindenEstate"); - params.functor(boost::bind(&LLPanelEstateInfo::callbackChangeLindenEstate, this, _1, _2)); - - if (isLindenEstate()) + // Add user presets. + for (LLWLParamManager::preset_name_list_t::const_iterator it = user_presets.begin(); it != user_presets.end(); ++it) { - // trying to change reserved estate, warn - LLNotifications::instance().add(params); + mSkyPresetCombo->add(*it, LLWLParamKey(*it, LLEnvKey::SCOPE_LOCAL).toStringVal()); } - else + + if (!user_presets.empty()) { - // for normal estates, just make the change - LLNotifications::instance().forceResponse(params, 0); + mSkyPresetCombo->addSeparator(); } - return TRUE; -} -bool LLPanelEstateInfo::callbackChangeLindenEstate(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - switch(option) + // Add system presets. + for (LLWLParamManager::preset_name_list_t::const_iterator it = sys_presets.begin(); it != sys_presets.end(); ++it) { - case 0: - { - LLEstateInfoModel& estate_info = LLEstateInfoModel::instance(); - - // update model - estate_info.setIsExternallyVisible(getChild("externally_visible_check")->getValue().asBoolean()); - estate_info.setUseFixedSun(getChild("fixed_sun_check")->getValue().asBoolean()); - estate_info.setSunHour(get_sun_hour(getChild("sun_hour_slider"))); - estate_info.setAllowDirectTeleport(getChild("allow_direct_teleport")->getValue().asBoolean()); - estate_info.setDenyAnonymous(getChild("limit_payment")->getValue().asBoolean()); - estate_info.setDenyAgeUnverified(getChild("limit_age_verified")->getValue().asBoolean()); - estate_info.setAllowVoiceChat(getChild("voice_chat_check")->getValue().asBoolean()); - - // send the update to sim - estate_info.sendEstateInfo(); - } + mSkyPresetCombo->add(*it, LLWLParamKey(*it, LLEnvKey::SCOPE_LOCAL).toStringVal()); + } - // we don't want to do this because we'll get it automatically from the sim - // after the spaceserver processes it -// else -// { -// // caps method does not automatically send this info -// LLFloaterRegionInfo::requestRegionInfo(); -// } - break; - case 1: - default: - // do nothing - break; + // Select current preset. + LLSD sky_map = LLEnvManagerNew::instance().getRegionSettings().getSkyMap(); + if (sky_map.size() == 1) // if the region is set to fixed sky + { + std::string preset_name = sky_map.beginMap()->first; + mSkyPresetCombo->selectByValue(LLWLParamKey(preset_name, LLEnvKey::SCOPE_REGION).toStringVal()); } - return false; } - -/* -// Request = "getowner" -// SParam[0] = "" (empty string) -// IParam[0] = serial -void LLPanelEstateInfo::getEstateOwner() +void LLPanelEnvironmentInfo::populateDayCyclesList() { - // TODO -- disable the panel - // and call this function whenever we cross a region boundary - // re-enable when owner matches, and get new estate info - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_EstateOwnerRequest); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - - msg->nextBlockFast(_PREHASH_RequestData); - msg->addStringFast(_PREHASH_Request, "getowner"); - - // we send an empty string so that the variable block is not empty - msg->nextBlockFast(_PREHASH_StringData); - msg->addStringFast(_PREHASH_SParam, ""); + mDayCyclePresetCombo->removeall(); - msg->nextBlockFast(_PREHASH_IntegerData); - msg->addS32Fast(_PREHASH_IParam, LLFloaterRegionInfo::getSerial()); + // If the region already has env. settings, add its day cycle to the list. + const LLSD& cur_region_dc = LLEnvManagerNew::instance().getRegionSettings().getWLDayCycle(); + if (cur_region_dc.size() != 0) + { + LLViewerRegion* region = gAgent.getRegion(); + llassert(region != NULL); - gAgent.sendMessage(); -} -*/ + LLWLParamKey key(region->getName(), LLEnvKey::SCOPE_REGION); + mDayCyclePresetCombo->add(region->getName(), key.toStringVal()); + mDayCyclePresetCombo->addSeparator(); + } -class LLEstateChangeInfoResponder : public LLHTTPClient::ResponderWithResult -{ -public: - LLEstateChangeInfoResponder(LLPanelEstateInfo* panel) + // Add local user day cycles. + LLDayCycleManager::preset_name_list_t user_days, sys_days; + LLDayCycleManager::instance().getPresetNames(user_days, sys_days); + for (LLDayCycleManager::preset_name_list_t::const_iterator it = user_days.begin(); it != user_days.end(); ++it) { - mpPanel = panel->getHandle(); + mDayCyclePresetCombo->add(*it, LLWLParamKey(*it, LLEnvKey::SCOPE_LOCAL).toStringVal()); } - - // if we get a normal response, handle it here - /*virtual*/ void result(const LLSD& content) - { - LL_INFOS("Windlight") << "Successfully committed estate info" << llendl; - // refresh the panel from the database - LLPanelEstateInfo* panel = dynamic_cast(mpPanel.get()); - if (panel) - panel->refresh(); - } - - // if we get an error response - /*virtual*/ void error(U32 status, const std::string& reason) + if (user_days.size() > 0) { - llinfos << "LLEstateChangeInfoResponder::error [status:" - << status << "]: " << reason << llendl; + mDayCyclePresetCombo->addSeparator(); } - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return estateChangeInfoResponder_timeout; } - /*virtual*/ char const* getName(void) const { return "LLEstateChangeInfoResponder"; } - -private: - LLHandle mpPanel; -}; - -const std::string LLPanelEstateInfo::getOwnerName() const -{ - return getChild("estate_owner")->getValue().asString(); -} + // Add local system day cycles. + for (LLDayCycleManager::preset_name_list_t::const_iterator it = sys_days.begin(); it != sys_days.end(); ++it) + { + mDayCyclePresetCombo->add(*it, LLWLParamKey(*it, LLEnvKey::SCOPE_LOCAL).toStringVal()); + } -void LLPanelEstateInfo::setOwnerName(const std::string& name) -{ - getChild("estate_owner")->setValue(LLSD(name)); + // Current day cycle is already selected. } -void LLPanelEstateInfo::setOwnerPNSName(const LLUUID& agent_id, const LLAvatarName& av_name) +bool LLPanelEnvironmentInfo::getSelectedWaterParams(LLSD& water_params) { - std::string name; - LLAvatarNameCache::getPNSName(av_name, name); - setOwnerName(name); -} + LLWLParamKey water_key(mWaterPresetCombo->getSelectedValue()); -void LLPanelEstateInfo::clearAccessLists() -{ - LLNameListCtrl* name_list = getChild("allowed_avatar_name_list"); - if (name_list) + if (water_key.scope == LLEnvKey::SCOPE_REGION) { - name_list->deleteAllItems(); + water_params = LLEnvManagerNew::instance().getRegionSettings().getWaterParams(); } - - name_list = getChild("banned_avatar_name_list"); - if (name_list) + else { - name_list->deleteAllItems(); + LLWaterParamSet param_set; + if (!LLWaterParamManager::instance().getParamSet(water_key.name, param_set)) + { + LL_WARNS() << "Error getting water preset: " << water_key.name << LL_ENDL; + return false; + } + + water_params = param_set.getAll(); } - updateControls(gAgent.getRegion()); -} -// static -void LLPanelEstateInfo::onClickMessageEstate(void* userdata) -{ - llinfos << "LLPanelEstateInfo::onClickMessageEstate" << llendl; - LLNotificationsUtil::add("MessageEstate", LLSD(), LLSD(), boost::bind(&LLPanelEstateInfo::onMessageCommit, (LLPanelEstateInfo*)userdata, _1, _2)); + return true; } -bool LLPanelEstateInfo::onMessageCommit(const LLSD& notification, const LLSD& response) +bool LLPanelEnvironmentInfo::getSelectedSkyParams(LLSD& sky_params, std::string& preset_name) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - std::string text = response["message"].asString(); - if(option != 0) return false; - if(text.empty()) return false; - llinfos << "Message to everyone: " << text << llendl; - strings_t strings; - //integers_t integers; - std::string name; - LLAgentUI::buildFullname(name); - strings.push_back(strings_t::value_type(name)); - strings.push_back(strings_t::value_type(text)); - LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); - sendEstateOwnerMessage(gMessageSystem, "instantmessage", invoice, strings); - return false; -} + std::string preset_key(mSkyPresetCombo->getValue().asString()); + LLWLParamKey preset(preset_key); -LLPanelEstateCovenant::LLPanelEstateCovenant() - : - mCovenantID(LLUUID::null) -{ + // Get the preset sky params. + LLWLParamSet param_set; + if (!LLWLParamManager::instance().getParamSet(preset, param_set)) + { + LL_WARNS() << "Error getting sky params: " << preset.toLLSD() << LL_ENDL; + return false; + } + + sky_params = param_set.getAll(); + preset_name = preset.name; + return true; } -// virtual -bool LLPanelEstateCovenant::refreshFromRegion(LLViewerRegion* region) +bool LLPanelEnvironmentInfo::getSelectedDayCycleParams(LLSD& day_cycle, LLSD& sky_map, short& scope) { - LLTextBox* region_name = getChild("region_name_text"); - if (region_name) - { - region_name->setText(region->getName()); - } + std::string preset_key(mDayCyclePresetCombo->getValue().asString()); + LLWLParamKey dc(preset_key); + LL_DEBUGS("Windlight") << "Use day cycle: " << dc.toLLSD() << LL_ENDL; - LLTextBox* resellable_clause = getChild("resellable_clause"); - if (resellable_clause) + if (dc.scope == LLEnvKey::SCOPE_REGION) // current region day cycle { - if (region->getRegionFlag(REGION_FLAGS_BLOCK_LAND_RESELL)) - { - resellable_clause->setText(getString("can_not_resell")); - } - else - { - resellable_clause->setText(getString("can_resell")); - } + const LLEnvironmentSettings& cur_region_settings = LLEnvManagerNew::instance().getRegionSettings(); + day_cycle = cur_region_settings.getWLDayCycle(); + sky_map = cur_region_settings.getSkyMap(); } - - LLTextBox* changeable_clause = getChild("changeable_clause"); - if (changeable_clause) + else // a local day cycle { - if (region->getRegionFlag(REGION_FLAGS_ALLOW_PARCEL_CHANGES)) + if (!LLDayCycleManager::instance().getPreset(dc.name, day_cycle)) { - changeable_clause->setText(getString("can_change")); + LL_WARNS() << "Error getting day cycle " << dc.name << LL_ENDL; + return false; } - else + + // Create sky map from the day cycle. { - changeable_clause->setText(getString("can_not_change")); + LLWLDayCycle tmp_day; + tmp_day.loadDayCycle(day_cycle, dc.scope); + tmp_day.getSkyMap(sky_map); } } - LLTextBox* region_maturity = getChild("region_maturity_text"); - if (region_maturity) - { - region_maturity->setText(region->getSimAccessString()); - } - - LLTextBox* region_landtype = getChild("region_landtype_text"); - region_landtype->setText(region->getLocalizedSimProductName()); - - // let the parent class handle the general data collection. - bool rv = LLPanelRegionInfo::refreshFromRegion(region); - LLMessageSystem *msg = gMessageSystem; - msg->newMessage("EstateCovenantRequest"); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID,gAgent.getSessionID()); - msg->sendReliable(region->getHost()); - return rv; -} + scope = dc.scope; -// virtual -bool LLPanelEstateCovenant::estateUpdate(LLMessageSystem* msg) -{ - llinfos << "LLPanelEstateCovenant::estateUpdate()" << llendl; return true; } - -// virtual -BOOL LLPanelEstateCovenant::postBuild() -{ - initHelpBtn("covenant_help", "HelpEstateCovenant"); - mEstateNameText = getChild("estate_name_text"); - mEstateOwnerText = getChild("estate_owner_text"); - mLastModifiedText = getChild("covenant_timestamp_text"); - mEditor = getChild("covenant_editor"); - if (mEditor) mEditor->setHandleEditKeysDirectly(TRUE); - LLButton* reset_button = getChild("reset_covenant"); - reset_button->setEnabled(gAgent.canManageEstate()); - reset_button->setClickedCallback(LLPanelEstateCovenant::resetCovenantID, NULL); - - return LLPanelRegionInfo::postBuild(); -} - -// virtual -void LLPanelEstateCovenant::updateChild(LLUICtrl* child_ctrl) -{ -} - -// virtual -BOOL LLPanelEstateCovenant::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg) +void LLPanelEnvironmentInfo::onSwitchRegionSettings() { - LLInventoryItem* item = (LLInventoryItem*)cargo_data; + bool use_defaults = mRegionSettingsRadioGroup->getSelectedIndex() == 0; + getChild("user_environment_settings")->setEnabled(!use_defaults); - if (!gAgent.canManageEstate()) + if (use_defaults) { - *accept = ACCEPT_NO; - return TRUE; + LLEnvManagerNew::instance().useDefaults(); } - - switch(cargo_type) + else { - case DAD_NOTECARD: - *accept = ACCEPT_YES_COPY_SINGLE; - if (item && drop) - { - LLSD payload; - payload["item_id"] = item->getUUID(); - LLNotificationsUtil::add("EstateChangeCovenant", LLSD(), payload, - LLPanelEstateCovenant::confirmChangeCovenantCallback); - } - break; - default: - *accept = ACCEPT_NO; - break; + onSelectWaterPreset(); + onSwitchDayCycle(); } - return TRUE; -} + setDirty(true); +} -// static -bool LLPanelEstateCovenant::confirmChangeCovenantCallback(const LLSD& notification, const LLSD& response) +void LLPanelEnvironmentInfo::onSwitchDayCycle() { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - LLInventoryItem* item = gInventory.getItem(notification["payload"]["item_id"].asUUID()); - LLPanelEstateCovenant* self = LLFloaterRegionInfo::getPanelCovenant(); + bool is_fixed_sky = mDayCycleSettingsRadioGroup->getSelectedIndex() == 0; - if (!item || !self) return false; + mSkyPresetCombo->setEnabled(is_fixed_sky); + mDayCyclePresetCombo->setEnabled(!is_fixed_sky); - switch(option) + if (is_fixed_sky) { - case 0: - self->loadInvItem(item); - break; - default: - break; + onSelectSkyPreset(); + } + else + { + onSelectDayCycle(); } - return false; -} -// static -void LLPanelEstateCovenant::resetCovenantID(void* userdata) -{ - LLNotificationsUtil::add("EstateChangeCovenant", LLSD(), LLSD(), confirmResetCovenantCallback); + setDirty(true); } -// static -bool LLPanelEstateCovenant::confirmResetCovenantCallback(const LLSD& notification, const LLSD& response) +void LLPanelEnvironmentInfo::onSelectWaterPreset() { - LLPanelEstateCovenant* self = LLFloaterRegionInfo::getPanelCovenant(); - if (!self) return false; + LLSD water_params; - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - switch(option) + if (getSelectedWaterParams(water_params)) { - case 0: - self->loadInvItem(NULL); - break; - default: - break; + LLEnvManagerNew::instance().useWaterParams(water_params); } - return false; + + setDirty(true); } -void LLPanelEstateCovenant::loadInvItem(LLInventoryItem *itemp) +void LLPanelEnvironmentInfo::onSelectSkyPreset() { - const BOOL high_priority = TRUE; - if (itemp) - { - gAssetStorage->getInvItemAsset(gAgent.getRegionHost(), - gAgent.getID(), - gAgent.getSessionID(), - itemp->getPermissions().getOwner(), - LLUUID::null, - itemp->getUUID(), - itemp->getAssetUUID(), - itemp->getType(), - onLoadComplete, - (void*)this, - high_priority); - mAssetStatus = ASSET_LOADING; - } - else - { - mAssetStatus = ASSET_LOADED; - setCovenantTextEditor(LLTrans::getString("RegionNoCovenant")); - sendChangeCovenantID(LLUUID::null); + LLSD params; + std::string dummy; + + if (getSelectedSkyParams(params, dummy)) + { + LLEnvManagerNew::instance().useSkyParams(params); } + + setDirty(true); } -// static -void LLPanelEstateCovenant::onLoadComplete(LLVFS *vfs, - const LLUUID& asset_uuid, - LLAssetType::EType type, - void* user_data, S32 status, LLExtStat ext_status) +void LLPanelEnvironmentInfo::onSelectDayCycle() { - llinfos << "LLPanelEstateCovenant::onLoadComplete()" << llendl; - LLPanelEstateCovenant* panelp = (LLPanelEstateCovenant*)user_data; - if( panelp ) + LLSD day_cycle; + LLSD sky_map; // unused + short scope; + + if (getSelectedDayCycleParams(day_cycle, sky_map, scope)) { - if(0 == status) - { - LLVFile file(vfs, asset_uuid, type, LLVFile::READ); + LLEnvManagerNew::instance().useDayCycleParams(day_cycle, (LLEnvKey::EScope) scope); + } - S32 file_length = file.getSize(); + setDirty(true); +} - std::vector buffer(file_length+1); - file.read((U8*)&buffer[0], file_length); - // put a EOS at the end - buffer[file_length] = 0; +void LLPanelEnvironmentInfo::onBtnApply() +{ + const bool use_defaults = mRegionSettingsRadioGroup->getSelectedIndex() == 0; + const bool use_fixed_sky = mDayCycleSettingsRadioGroup->getSelectedIndex() == 0; - if( (file_length > 19) && !strncmp( &buffer[0], "Linden text version", 19 ) ) - { - if( !panelp->mEditor->importBuffer( &buffer[0], file_length+1 ) ) - { - llwarns << "Problem importing estate covenant." << llendl; - LLNotificationsUtil::add("ProblemImportingEstateCovenant"); - } - else - { - panelp->sendChangeCovenantID(asset_uuid); - } - } - else + LLSD day_cycle; + LLSD sky_map; + LLSD water_params; + + if (use_defaults) + { + // settings will be empty + LL_DEBUGS("Windlight") << "Defaults" << LL_ENDL; + } + else // use custom region settings + { + if (use_fixed_sky) + { + LL_DEBUGS("Windlight") << "Use fixed sky" << LL_ENDL; + + // Get selected sky params. + LLSD params; + std::string preset_name; + if (!getSelectedSkyParams(params, preset_name)) { - // Version 0 (just text, doesn't include version number) - panelp->sendChangeCovenantID(asset_uuid); + return; } + + // Create a day cycle consisting of a single sky preset. + LLSD key(LLSD::emptyArray()); + key.append(-1.0f); // indicate that user preference is actually fixed sky, not a day cycle + key.append(preset_name); + day_cycle.append(key); + + // Create a sky map consisting of only the sky preset. + std::map refs; + LLWLParamSet param_set; + param_set.setAll(params); + refs[LLWLParamKey(preset_name, LLEnvKey::SCOPE_LOCAL)] = param_set; // scope doesn't matter here + sky_map = LLWLParamManager::createSkyMap(refs); } - else + else // use day cycle { - LLViewerStats::getInstance()->incStat( LLViewerStats::ST_DOWNLOAD_FAILED ); + LL_DEBUGS("Windlight") << "Use day cycle" << LL_ENDL; - if( LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status || - LL_ERR_FILE_EMPTY == status) - { - LLNotificationsUtil::add("MissingNotecardAssetID"); - } - else if (LL_ERR_INSUFFICIENT_PERMISSIONS == status) + short scope; // unused + if (!getSelectedDayCycleParams(day_cycle, sky_map, scope)) { - LLNotificationsUtil::add("NotAllowedToViewNotecard"); + return; } - else + + // If it's a special single-preset day cycle meaning using a fixed sky, + // reset the frame time to a non-negative value, + // so that the region setting is displayed in the floater as + // a day cycle, not a preset. (STORM-1289) + if (day_cycle.size() == 1 && day_cycle[0][0].asReal() < 0.0f) { - LLNotificationsUtil::add("UnableToLoadNotecardAsset"); + LL_DEBUGS("Windlight") << "Fixing negative time" << LL_ENDL; + day_cycle[0][0] = 0.0f; } + } - llwarns << "Problem loading notecard: " << status << llendl; + // Get water params. + if (!getSelectedWaterParams(water_params)) + { + // *TODO: show a notification? + return; } - panelp->mAssetStatus = ASSET_LOADED; - panelp->setCovenantID(asset_uuid); } + + // Send settings apply request. + LLEnvironmentSettings new_region_settings; + new_region_settings.saveParams(day_cycle, sky_map, water_params, 0.0f); + if (!LLEnvManagerNew::instance().sendRegionSettings(new_region_settings)) + { + LL_WARNS() << "Error applying region environment settings" << LL_ENDL; + return; + } + + // When the settings get applied, we'll also send the region sun position update. + // To determine the sun angle we're going to need the new settings. + mNewRegionSettings = new_region_settings; + + // Start spinning the progress indicator. + setApplyProgress(true); } -// key = "estatechangecovenantid" -// strings[0] = str(estate_id) (added by simulator before relay - not here) -// strings[1] = str(covenant_id) -void LLPanelEstateCovenant::sendChangeCovenantID(const LLUUID &asset_id) +void LLPanelEnvironmentInfo::onBtnCancel() { - if (asset_id != getCovenantID()) - { - setCovenantID(asset_id); + // Reload last saved region settings. + refresh(); - LLMessageSystem* msg = gMessageSystem; - msg->newMessage("EstateOwnerMessage"); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->addUUIDFast(_PREHASH_TransactionID, LLUUID::null); //not used + // Apply them. + LLEnvManagerNew& env_mgr = LLEnvManagerNew::instance(); + const LLEnvironmentSettings& cur_settings = env_mgr.getRegionSettings(); + const LLSD& region_day_cycle = cur_settings.getWLDayCycle(); + const LLSD& region_water = cur_settings.getWaterParams(); + env_mgr.useWaterParams(region_water); + env_mgr.useDayCycleParams(region_day_cycle, LLEnvKey::SCOPE_REGION); +} - msg->nextBlock("MethodData"); - msg->addString("Method", "estatechangecovenantid"); - msg->addUUID("Invoice", LLFloaterRegionInfo::getLastInvoice()); +void LLPanelEnvironmentInfo::onRegionSettingschange() +{ + LL_DEBUGS("Windlight") << "Region settings changed, refreshing" << LL_ENDL; + refresh(); - msg->nextBlock("ParamList"); - msg->addString("Parameter", getCovenantID().asString()); - gAgent.sendReliableMessage(); + // Stop applying progress indicator (it may be running if it's us who initiated settings update). + setApplyProgress(false); +} + +void LLPanelEnvironmentInfo::onRegionSettingsApplied(bool ok) +{ + // If applying new settings has failed, stop the indicator right away. + // Otherwise it will be stopped when we receive the updated settings from server. + if (ok) + { + // Set the region sun phase/flags according to the chosen new preferences. + // + // If we do this earlier we may get jerky transition from fixed sky to a day cycle (STORM-1481). + // That is caused by the simulator re-sending the region info, which in turn makes us + // re-request and display old region environment settings while the new ones haven't been applied yet. + sendRegionSunUpdate(); + + // Switch estate to not using fixed sun for the region day cycle to work properly (STORM-1506). + fixEstateSun(); + } + else + { + setApplyProgress(false); + + // We need to re-request environment setting here, + // otherwise our subsequent attempts to change region settings will fail with the following error: + // "Unable to update environment settings because the last update your viewer saw was not the same + // as the last update sent from the simulator. Try sending your update again, and if this + // does not work, try leaving and returning to the region." + LLEnvManagerNew::instance().requestRegionSettings(); } } -// virtual -BOOL LLPanelEstateCovenant::sendUpdate() +LLPanelRegionExperiences::LLPanelRegionExperiences() +: mTrusted(nullptr) +, mAllowed(nullptr) +, mBlocked(nullptr) { - return TRUE; + mFactoryMap["panel_trusted"] = LLCallbackMap(create_xp_list_editor, reinterpret_cast(&mTrusted)); + mFactoryMap["panel_allowed"] = LLCallbackMap(create_xp_list_editor, reinterpret_cast(&mAllowed)); + mFactoryMap["panel_blocked"] = LLCallbackMap(create_xp_list_editor, reinterpret_cast(&mBlocked)); + LLUICtrlFactory::getInstance()->buildPanel(this, "panel_region_experiences.xml", &mFactoryMap); } -std::string LLPanelEstateCovenant::getEstateName() const +BOOL LLPanelRegionExperiences::postBuild() { - return mEstateNameText->getText(); + setupList(mAllowed, "panel_allowed", ESTATE_EXPERIENCE_ALLOWED_ADD, ESTATE_EXPERIENCE_ALLOWED_REMOVE); + setupList(mTrusted, "panel_trusted", ESTATE_EXPERIENCE_TRUSTED_ADD, ESTATE_EXPERIENCE_TRUSTED_REMOVE); + setupList(mBlocked, "panel_blocked", ESTATE_EXPERIENCE_BLOCKED_ADD, ESTATE_EXPERIENCE_BLOCKED_REMOVE); + + getChild("trusted_layout_panel")->setVisible(TRUE); + getChild("experiences_help_text")->setText(getString("estate_caption")); + getChild("trusted_text_help")->setText(getString("trusted_estate_text")); + getChild("allowed_text_help")->setText(getString("allowed_estate_text")); + getChild("blocked_text_help")->setText(getString("blocked_estate_text")); + + return LLPanelRegionInfo::postBuild(); } -void LLPanelEstateCovenant::setEstateName(const std::string& name) +void LLPanelRegionExperiences::setupList(LLPanelExperienceListEditor* child, const char* control_name, U32 add_id, U32 remove_id ) { - mEstateNameText->setText(name); + //LLPanelExperienceListEditor* child = findChild(control_name); + if(child) + { + child->getChild("text_name")->setText(child->getString(control_name)); + child->setMaxExperienceIDs(ESTATE_MAX_EXPERIENCE_IDS); + child->setAddedCallback( boost::bind(&LLPanelRegionExperiences::itemChanged, this, add_id, _1)); + child->setRemovedCallback(boost::bind(&LLPanelRegionExperiences::itemChanged, this, remove_id, _1)); + } + + //return child; } -// static -void LLPanelEstateCovenant::updateCovenantText(const std::string& string, const LLUUID& asset_id) + +void LLPanelRegionExperiences::processResponse( const LLSD& content ) { - LLPanelEstateCovenant* panelp = LLFloaterRegionInfo::getPanelCovenant(); - if( panelp ) + if(content.has("default")) { - panelp->mEditor->setText(string); - panelp->setCovenantID(asset_id); + mDefaultExperience = content["default"].asUUID(); + } + + mAllowed->setExperienceIds(content["allowed"]); + mBlocked->setExperienceIds(content["blocked"]); + + LLSD trusted = content["trusted"]; + if(mDefaultExperience.notNull()) + { + mTrusted->setStickyFunction(boost::bind(LLPanelExperiencePicker::FilterMatching, _1, mDefaultExperience)); + trusted.append(mDefaultExperience); } + + mTrusted->setExperienceIds(trusted); + + mAllowed->refreshExperienceCounter(); + mBlocked->refreshExperienceCounter(); + mTrusted->refreshExperienceCounter(); + } +// Used for both access add and remove operations, depending on the flag +// passed in (ESTATE_EXPERIENCE_ALLOWED_ADD, ESTATE_EXPERIENCE_ALLOWED_REMOVE, etc.) // static -void LLPanelEstateCovenant::updateEstateName(const std::string& name) +bool LLPanelRegionExperiences::experienceCoreConfirm(const LLSD& notification, const LLSD& response) { - LLPanelEstateCovenant* panelp = LLFloaterRegionInfo::getPanelCovenant(); - if( panelp ) + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + const U32 originalFlags = (U32)notification["payload"]["operation"].asInteger(); + + LLViewerRegion* region = gAgent.getRegion(); + + LLSD::array_const_iterator end_it = notification["payload"]["allowed_ids"].endArray(); + + for (LLSD::array_const_iterator iter = notification["payload"]["allowed_ids"].beginArray(); + iter != end_it; + iter++) { - panelp->mEstateNameText->setText(name); + U32 flags = originalFlags; + if (iter + 1 != end_it) + flags |= ESTATE_ACCESS_NO_REPLY; + + const LLUUID id = iter->asUUID(); + switch(option) + { + case 0: + // This estate + sendEstateExperienceDelta(flags, id); + break; + case 1: + { + // All estates, either than I own or manage for this owner. + // This will be verified on simulator. JC + if (!region) break; + if (region->getOwner() == gAgent.getID() + || gAgent.isGodlike()) + { + flags |= ESTATE_ACCESS_APPLY_TO_ALL_ESTATES; + sendEstateExperienceDelta(flags, id); + } + else if (region->isEstateManager()) + { + flags |= ESTATE_ACCESS_APPLY_TO_MANAGED_ESTATES; + sendEstateExperienceDelta(flags, id); + } + break; + } + case 2: + default: + break; + } } + return false; } -// static -void LLPanelEstateCovenant::updateLastModified(const std::string& text) + +// Send the actual "estateexperiencedelta" message +void LLPanelRegionExperiences::sendEstateExperienceDelta(U32 flags, const LLUUID& experience_id) { - LLPanelEstateCovenant* panelp = LLFloaterRegionInfo::getPanelCovenant(); - if( panelp ) + strings_t str(3, std::string()); + gAgent.getID().toString(str[0]); + str[1] = llformat("%u", flags); + experience_id.toString(str[2]); + + LLPanelRegionExperiences* panel = LLFloaterRegionInfo::getPanelExperiences(); + if (panel) { - panelp->mLastModifiedText->setText(text); + panel->sendEstateOwnerMessage(gMessageSystem, "estateexperiencedelta", LLFloaterRegionInfo::getLastInvoice(), str); } } -// static -void LLPanelEstateCovenant::updateEstateOwnerName(const std::string& name) + +void LLPanelRegionExperiences::infoCallback(LLHandle handle, const LLSD& content) { - LLPanelEstateCovenant* panelp = LLFloaterRegionInfo::getPanelCovenant(); - if( panelp ) + if (handle.isDead()) + return; + + LLPanelRegionExperiences* floater = handle.get(); + if (floater) { - panelp->mEstateOwnerText->setText(name); + floater->processResponse(content); } } -std::string LLPanelEstateCovenant::getOwnerName() const +/*static*/ +std::string LLPanelRegionExperiences::regionCapabilityQuery(LLViewerRegion* region, const std::string &cap) { - return mEstateOwnerText->getText(); + // region->getHandle() How to get a region * from a handle? + + return region->getCapability(cap); } -void LLPanelEstateCovenant::setOwnerName(const std::string& name) +bool LLPanelRegionExperiences::refreshFromRegion(LLViewerRegion* region) { - mEstateOwnerText->setText(name); + BOOL allow_modify = gAgent.isGodlike() || (region && region->canManageEstate()); + + mAllowed->loading(); + mAllowed->setReadonly(!allow_modify); + // remove grid-wide experiences + mAllowed->addFilter(boost::bind(LLPanelExperiencePicker::FilterWithProperty, _1, LLExperienceCache::PROPERTY_GRID)); + // remove default experience + mAllowed->addFilter(boost::bind(LLPanelExperiencePicker::FilterMatching, _1, mDefaultExperience)); + + mBlocked->loading(); + mBlocked->setReadonly(!allow_modify); + // only grid-wide experiences + mBlocked->addFilter(boost::bind(LLPanelExperiencePicker::FilterWithoutProperty, _1, LLExperienceCache::PROPERTY_GRID)); + // but not privileged ones + mBlocked->addFilter(boost::bind(LLPanelExperiencePicker::FilterWithProperty, _1, LLExperienceCache::PROPERTY_PRIVILEGED)); + // remove default experience + mBlocked->addFilter(boost::bind(LLPanelExperiencePicker::FilterMatching, _1, mDefaultExperience)); + + mTrusted->loading(); + mTrusted->setReadonly(!allow_modify); + + LLExperienceCache::instance().getRegionExperiences(boost::bind(&LLPanelRegionExperiences::regionCapabilityQuery, region, _1), + boost::bind(&LLPanelRegionExperiences::infoCallback, getDerivedHandle(), _1)); + + return LLPanelRegionInfo::refreshFromRegion(region); } -void LLPanelEstateCovenant::setCovenantTextEditor(const std::string& text) +LLSD LLPanelRegionExperiences::addIds(LLPanelExperienceListEditor* panel) { - mEditor->setText(text); + LLSD ids; + const uuid_list_t& id_list = panel->getExperienceIds(); + for(uuid_list_t::const_iterator it = id_list.begin(); it != id_list.end(); ++it) + { + ids.append(*it); + } + return ids; } -// key = "estateupdateinfo" -// strings[0] = estate name -// strings[1] = str(owner_id) -// strings[2] = str(estate_id) -// strings[3] = str(estate_flags) -// strings[4] = str((S32)(sun_hour * 1024)) -// strings[5] = str(parent_estate_id) -// strings[6] = str(covenant_id) -// strings[7] = str(covenant_timestamp) -// strings[8] = str(send_to_agent_only) -// strings[9] = str(abuse_email_addr) -bool LLDispatchEstateUpdateInfo::operator()( - const LLDispatcher* dispatcher, - const std::string& key, - const LLUUID& invoice, - const sparam_t& strings) + +BOOL LLPanelRegionExperiences::sendUpdate() { - lldebugs << "Received estate update" << llendl; + LLViewerRegion* region = gAgent.getRegion(); - // Update estate info model. - // This will call LLPanelEstateInfo::refreshFromEstate(). - // *TODO: Move estate message handling stuff to llestateinfomodel.cpp. - LLEstateInfoModel::instance().update(strings); + LLSD content; - return true; -} + content["allowed"]=addIds(mAllowed); + content["blocked"]=addIds(mBlocked); + content["trusted"]=addIds(mTrusted); + LLExperienceCache::instance().setRegionExperiences(boost::bind(&LLPanelRegionExperiences::regionCapabilityQuery, region, _1), + content, boost::bind(&LLPanelRegionExperiences::infoCallback, getDerivedHandle(), _1)); -// key = "setaccess" -// strings[0] = str(estate_id) -// strings[1] = str(packed_access_lists) -// strings[2] = str(num allowed agent ids) -// strings[3] = str(num allowed group ids) -// strings[4] = str(num banned agent ids) -// strings[5] = str(num estate manager agent ids) -// strings[6] = bin(uuid) -// strings[7] = bin(uuid) -// strings[8] = bin(uuid) -// ... -bool LLDispatchSetEstateAccess::operator()( - const LLDispatcher* dispatcher, - const std::string& key, - const LLUUID& invoice, - const sparam_t& strings) + return TRUE; +} + +void LLPanelRegionExperiences::itemChanged( U32 event_type, const LLUUID& id ) { - LLPanelEstateInfo* panel = LLFloaterRegionInfo::getPanelEstate(); - if (!panel) return true; + std::string dialog_name; + switch (event_type) + { + case ESTATE_EXPERIENCE_ALLOWED_ADD: + dialog_name = "EstateAllowedExperienceAdd"; + break; - S32 index = 1; // skip estate_id - U32 access_flags = strtoul(strings[index++].c_str(), NULL,10); - S32 num_allowed_agents = strtol(strings[index++].c_str(), NULL, 10); - S32 num_allowed_groups = strtol(strings[index++].c_str(), NULL, 10); - S32 num_banned_agents = strtol(strings[index++].c_str(), NULL, 10); - S32 num_estate_managers = strtol(strings[index++].c_str(), NULL, 10); + case ESTATE_EXPERIENCE_ALLOWED_REMOVE: + dialog_name = "EstateAllowedExperienceRemove"; + break; - // sanity ckecks - if (num_allowed_agents > 0 - && !(access_flags & ESTATE_ACCESS_ALLOWED_AGENTS)) - { - llwarns << "non-zero count for allowed agents, but no corresponding flag" << llendl; - } - if (num_allowed_groups > 0 - && !(access_flags & ESTATE_ACCESS_ALLOWED_GROUPS)) - { - llwarns << "non-zero count for allowed groups, but no corresponding flag" << llendl; + case ESTATE_EXPERIENCE_TRUSTED_ADD: + dialog_name = "EstateTrustedExperienceAdd"; + break; + + case ESTATE_EXPERIENCE_TRUSTED_REMOVE: + dialog_name = "EstateTrustedExperienceRemove"; + break; + + case ESTATE_EXPERIENCE_BLOCKED_ADD: + dialog_name = "EstateBlockedExperienceAdd"; + break; + + case ESTATE_EXPERIENCE_BLOCKED_REMOVE: + dialog_name = "EstateBlockedExperienceRemove"; + break; + + default: + return; } - if (num_banned_agents > 0 - && !(access_flags & ESTATE_ACCESS_BANNED_AGENTS)) + + LLSD payload; + payload["operation"] = (S32)event_type; + payload["dialog_name"] = dialog_name; + payload["allowed_ids"].append(id); + + LLSD args; + args["ALL_ESTATES"] = all_estates_text(); + + LLNotification::Params params(dialog_name); + params.payload(payload) + .substitutions(args) + .functor(LLPanelRegionExperiences::experienceCoreConfirm); + if (LLPanelEstateInfo::isLindenEstate()) { - llwarns << "non-zero count for banned agents, but no corresponding flag" << llendl; + LLNotifications::instance().forceResponse(params, 0); } - if (num_estate_managers > 0 - && !(access_flags & ESTATE_ACCESS_MANAGERS)) + else { - llwarns << "non-zero count for managers, but no corresponding flag" << llendl; + LLNotifications::instance().add(params); } - // grab the UUID's out of the string fields - if (access_flags & ESTATE_ACCESS_ALLOWED_AGENTS) - { - LLNameListCtrl* allowed_agent_name_list; - allowed_agent_name_list = panel->getChild("allowed_avatar_name_list"); + onChangeAnything(); +} - int totalAllowedAgents = num_allowed_agents; - - if (allowed_agent_name_list) - { - totalAllowedAgents += allowed_agent_name_list->getItemCount(); - } - LLStringUtil::format_map_t args; - args["[ALLOWEDAGENTS]"] = llformat ("%d", totalAllowedAgents); - args["[MAXACCESS]"] = llformat ("%d", ESTATE_MAX_ACCESS_IDS); - std::string msg = LLTrans::getString("RegionInfoAllowedResidents", args); - panel->getChild("allow_resident_label")->setValue(LLSD(msg)); +LLPanelEstateAccess::LLPanelEstateAccess() +: LLPanelRegionInfo(), mPendingUpdate(false) +{} - if (allowed_agent_name_list) - { - // Don't sort these as we add them, sort them when we are done. - allowed_agent_name_list->clearSortOrder(); - for (S32 i = 0; i < num_allowed_agents && i < ESTATE_MAX_ACCESS_IDS; i++) - { - LLUUID id; - memcpy(id.mData, strings[index++].data(), UUID_BYTES); /* Flawfinder: ignore */ - allowed_agent_name_list->addNameItem(id); - } - allowed_agent_name_list->sortByName(TRUE); - } +BOOL LLPanelEstateAccess::postBuild() +{ + // set up the callbacks for the generic controls + initHelpBtn("estate_manager_help", "HelpEstateEstateManager"); + initHelpBtn("allow_resident_help", "HelpEstateAllowResident"); + initHelpBtn("allow_group_help", "HelpEstateAllowGroup"); + initHelpBtn("ban_resident_help", "HelpEstateBanResident"); + + getChild("allowed_avatar_name_list")->setCommitCallback(boost::bind(&LLPanelEstateInfo::onChangeChildCtrl, this, _1)); + LLNameListCtrl *avatar_name_list = getChild("allowed_avatar_name_list"); + if (avatar_name_list) + { + avatar_name_list->setCommitOnSelectionChange(TRUE); + avatar_name_list->setMaxItemCount(ESTATE_MAX_ACCESS_IDS); } - if (access_flags & ESTATE_ACCESS_ALLOWED_GROUPS) + getChild("allowed_search_input")->setCommitCallback(boost::bind(&LLPanelEstateAccess::onAllowedSearchEdit, this, _2)); + childSetAction("add_allowed_avatar_btn", boost::bind(&LLPanelEstateAccess::onClickAddAllowedAgent, this)); + childSetAction("remove_allowed_avatar_btn", boost::bind(&LLPanelEstateAccess::onClickRemoveAllowedAgent, this)); + childSetAction("copy_allowed_list_btn", boost::bind(&LLPanelEstateAccess::onClickCopyAllowedList, this)); + + getChild("allowed_group_name_list")->setCommitCallback(boost::bind(&LLPanelEstateInfo::onChangeChildCtrl, this, _1)); + LLNameListCtrl* group_name_list = getChild("allowed_group_name_list"); + if (group_name_list) { - LLNameListCtrl* allowed_group_name_list; - allowed_group_name_list = panel->getChild("allowed_group_name_list"); + group_name_list->setCommitOnSelectionChange(TRUE); + group_name_list->setMaxItemCount(ESTATE_MAX_ACCESS_IDS); + } - LLStringUtil::format_map_t args; - args["[ALLOWEDGROUPS]"] = llformat ("%d", num_allowed_groups); - args["[MAXACCESS]"] = llformat ("%d", ESTATE_MAX_GROUP_IDS); - std::string msg = LLTrans::getString("RegionInfoAllowedGroups", args); - panel->getChild("allow_group_label")->setValue(LLSD(msg)); + getChild("allowed_group_search_input")->setCommitCallback(boost::bind(&LLPanelEstateAccess::onAllowedGroupsSearchEdit, this, _2)); + getChild("add_allowed_group_btn")->setCommitCallback(boost::bind(&LLPanelEstateAccess::onClickAddAllowedGroup, this)); + childSetAction("remove_allowed_group_btn", boost::bind(&LLPanelEstateAccess::onClickRemoveAllowedGroup, this)); + childSetAction("copy_allowed_group_list_btn", boost::bind(&LLPanelEstateAccess::onClickCopyAllowedGroupList, this)); - if (allowed_group_name_list) - { - // Don't sort these as we add them, sort them when we are done. - allowed_group_name_list->clearSortOrder(); - allowed_group_name_list->deleteAllItems(); - for (S32 i = 0; i < num_allowed_groups && i < ESTATE_MAX_GROUP_IDS; i++) - { - LLUUID id; - memcpy(id.mData, strings[index++].data(), UUID_BYTES); /* Flawfinder: ignore */ - allowed_group_name_list->addGroupNameItem(id); - } - allowed_group_name_list->sortByName(TRUE); - } + getChild("banned_avatar_name_list")->setCommitCallback(boost::bind(&LLPanelEstateAccess::updateChild, this, _1)); + LLNameListCtrl* banned_name_list = getChild("banned_avatar_name_list"); + if (banned_name_list) + { + banned_name_list->setCommitOnSelectionChange(TRUE); + banned_name_list->setMaxItemCount(ESTATE_MAX_ACCESS_IDS); } - if (access_flags & ESTATE_ACCESS_BANNED_AGENTS) + getChild("banned_search_input")->setCommitCallback(boost::bind(&LLPanelEstateAccess::onBannedSearchEdit, this, _2)); + childSetAction("add_banned_avatar_btn", boost::bind(&LLPanelEstateAccess::onClickAddBannedAgent, this)); + childSetAction("remove_banned_avatar_btn", boost::bind(&LLPanelEstateAccess::onClickRemoveBannedAgent, this)); + childSetAction("copy_banned_list_btn", boost::bind(&LLPanelEstateAccess::onClickCopyBannedList, this)); + + getChild("estate_manager_name_list")->setCommitCallback(boost::bind(&LLPanelEstateAccess::updateChild, this, _1)); + LLNameListCtrl* manager_name_list = getChild("estate_manager_name_list"); + if (manager_name_list) { - LLNameListCtrl* banned_agent_name_list; - banned_agent_name_list = panel->getChild("banned_avatar_name_list"); + manager_name_list->setCommitOnSelectionChange(TRUE); + manager_name_list->setMaxItemCount(ESTATE_MAX_MANAGERS * 4); // Allow extras for dupe issue + } - int totalBannedAgents = num_banned_agents; - - if (banned_agent_name_list) - { - totalBannedAgents += banned_agent_name_list->getItemCount(); - } + childSetAction("add_estate_manager_btn", boost::bind(&LLPanelEstateAccess::onClickAddEstateManager, this)); + childSetAction("remove_estate_manager_btn", boost::bind(&LLPanelEstateAccess::onClickRemoveEstateManager, this)); + return TRUE; +} - std::string msg = llformat("Banned residents: (%d, max %d)", - totalBannedAgents, - ESTATE_MAX_ACCESS_IDS); - panel->getChild("ban_resident_label")->setValue(LLSD(msg)); +void LLPanelEstateAccess::updateControls(LLViewerRegion* region) +{ + BOOL god = gAgent.isGodlike(); + BOOL owner = (region && (region->getOwner() == gAgent.getID())); + BOOL manager = (region && region->isEstateManager()); + bool enable_cotrols = god || owner || manager; + setCtrlsEnabled(enable_cotrols); - if (banned_agent_name_list) - { - // Don't sort these as we add them, sort them when we are done. - banned_agent_name_list->clearSortOrder(); + BOOL has_allowed_avatar = getChild("allowed_avatar_name_list")->getFirstSelected() ? TRUE : FALSE; + BOOL has_allowed_group = getChild("allowed_group_name_list")->getFirstSelected() ? TRUE : FALSE; + BOOL has_banned_agent = getChild("banned_avatar_name_list")->getFirstSelected() ? TRUE : FALSE; + BOOL has_estate_manager = getChild("estate_manager_name_list")->getFirstSelected() ? TRUE : FALSE; - for (S32 i = 0; i < num_banned_agents && i < ESTATE_MAX_ACCESS_IDS; i++) - { - LLUUID id; - memcpy(id.mData, strings[index++].data(), UUID_BYTES); /* Flawfinder: ignore */ - banned_agent_name_list->addNameItem(id); - } - banned_agent_name_list->sortByName(TRUE); - } - } + getChildView("add_allowed_avatar_btn")->setEnabled(enable_cotrols); + getChildView("remove_allowed_avatar_btn")->setEnabled(has_allowed_avatar && enable_cotrols); + getChildView("allowed_avatar_name_list")->setEnabled(enable_cotrols); - if (access_flags & ESTATE_ACCESS_MANAGERS) - { - std::string msg = llformat("Estate Managers: (%d, max %d)", - num_estate_managers, - ESTATE_MAX_MANAGERS); - panel->getChild("estate_manager_label")->setValue(LLSD(msg)); + getChildView("add_allowed_group_btn")->setEnabled(enable_cotrols); + getChildView("remove_allowed_group_btn")->setEnabled(has_allowed_group && enable_cotrols); + getChildView("allowed_group_name_list")->setEnabled(enable_cotrols); - LLNameListCtrl* estate_manager_name_list = - panel->getChild("estate_manager_name_list"); - if (estate_manager_name_list) - { - // Don't sort these as we add them, sort them when we are done. - estate_manager_name_list->clearSortOrder(); + // Can't ban people from mainland, orientation islands, etc. because this + // creates much network traffic and server load. + // Disable their accounts in CSR tool instead. + bool linden_estate = LLPanelEstateInfo::isLindenEstate(); + bool enable_ban = enable_cotrols && !linden_estate; + getChildView("add_banned_avatar_btn")->setEnabled(enable_ban); + getChildView("remove_banned_avatar_btn")->setEnabled(has_banned_agent && enable_ban); + getChildView("banned_avatar_name_list")->setEnabled(enable_cotrols); - estate_manager_name_list->deleteAllItems(); // Clear existing entries + // estate managers can't add estate managers + getChildView("add_estate_manager_btn")->setEnabled(god || owner); + getChildView("remove_estate_manager_btn")->setEnabled(has_estate_manager && (god || owner)); + getChildView("estate_manager_name_list")->setEnabled(god || owner); - // There should be only ESTATE_MAX_MANAGERS people in the list, but if the database gets more (SL-46107) don't - // truncate the list unless it's really big. Go ahead and show the extras so the user doesn't get confused, - // and they can still remove them. - for (S32 i = 0; i < num_estate_managers && i < (ESTATE_MAX_MANAGERS * 4); i++) - { - LLUUID id; - memcpy(id.mData, strings[index++].data(), UUID_BYTES); /* Flawfinder: ignore */ - estate_manager_name_list->addNameItem(id); - } - estate_manager_name_list->sortByName(TRUE); - } + if (enable_cotrols != mCtrlsEnabled) + { + mCtrlsEnabled = enable_cotrols; + updateLists(); // update the lists on the agent's access level change } +} - // Update the buttons which may change based on the list contents but also needs to account for general access features. - panel->updateControls(gAgent.getRegion()); +//--------------------------------------------------------------------------- +// Add/Remove estate access button callbacks +//--------------------------------------------------------------------------- +void LLPanelEstateAccess::onClickAddAllowedAgent() +{ + LLCtrlListInterface *list = childGetListInterface("allowed_avatar_name_list"); + if (!list) return; + if (list->getItemCount() >= ESTATE_MAX_ACCESS_IDS) + { + //args - return true; + LLSD args; + args["MAX_AGENTS"] = llformat("%d",ESTATE_MAX_ACCESS_IDS); + LLNotificationsUtil::add("MaxAllowedAgentOnRegion", args); + return; + } + accessAddCore(ESTATE_ACCESS_ALLOWED_AGENT_ADD, "EstateAllowedAgentAdd"); } -LLPanelEnvironmentInfo::LLPanelEnvironmentInfo() -: mEnableEditing(false), - mRegionSettingsRadioGroup(NULL), - mDayCycleSettingsRadioGroup(NULL), - mWaterPresetCombo(NULL), - mSkyPresetCombo(NULL), - mDayCyclePresetCombo(NULL) +void LLPanelEstateAccess::onClickRemoveAllowedAgent() { + accessRemoveCore(ESTATE_ACCESS_ALLOWED_AGENT_REMOVE, "EstateAllowedAgentRemove", "allowed_avatar_name_list"); } -// virtual -BOOL LLPanelEnvironmentInfo::postBuild() +void LLPanelEstateAccess::onClickAddAllowedGroup() { - mRegionSettingsRadioGroup = getChild("region_settings_radio_group"); - mRegionSettingsRadioGroup->setCommitCallback(boost::bind(&LLPanelEnvironmentInfo::onSwitchRegionSettings, this)); - - mDayCycleSettingsRadioGroup = getChild("sky_dayc_settings_radio_group"); - mDayCycleSettingsRadioGroup->setCommitCallback(boost::bind(&LLPanelEnvironmentInfo::onSwitchDayCycle, this)); - - mWaterPresetCombo = getChild("water_settings_preset_combo"); - mWaterPresetCombo->setCommitCallback(boost::bind(&LLPanelEnvironmentInfo::onSelectWaterPreset, this)); - - mSkyPresetCombo = getChild("sky_settings_preset_combo"); - mSkyPresetCombo->setCommitCallback(boost::bind(&LLPanelEnvironmentInfo::onSelectSkyPreset, this)); - - mDayCyclePresetCombo = getChild("dayc_settings_preset_combo"); - mDayCyclePresetCombo->setCommitCallback(boost::bind(&LLPanelEnvironmentInfo::onSelectDayCycle, this)); + LLCtrlListInterface *list = childGetListInterface("allowed_group_name_list"); + if (!list) return; + if (list->getItemCount() >= ESTATE_MAX_ACCESS_IDS) + { + LLSD args; + args["MAX_GROUPS"] = llformat("%d",ESTATE_MAX_ACCESS_IDS); + LLNotificationsUtil::add("MaxAllowedGroupsOnRegion", args); + return; + } - getChild("apply_btn")->setCommitCallback(boost::bind(&LLPanelEnvironmentInfo::onBtnApply, this)); - //getChild("apply_btn")->setRightMouseDownCallback(boost::bind(&LLEnvManagerNew::dumpUserPrefs, LLEnvManagerNew::getInstance())); - getChild("cancel_btn")->setCommitCallback(boost::bind(&LLPanelEnvironmentInfo::onBtnCancel, this)); - //getChild("cancel_btn")->setRightMouseDownCallback(boost::bind(&LLEnvManagerNew::dumpPresets, LLEnvManagerNew::getInstance())); + LLNotification::Params params("ChangeLindenAccess"); + params.functor(boost::bind(&LLPanelEstateAccess::addAllowedGroup, this, _1, _2)); + if (LLPanelEstateInfo::isLindenEstate()) + { + LLNotifications::instance().add(params); + } + else + { + LLNotifications::instance().forceResponse(params, 0); + } +} - LLEnvManagerNew::instance().setRegionSettingsChangeCallback(boost::bind(&LLPanelEnvironmentInfo::onRegionSettingschange, this)); - LLEnvManagerNew::instance().setRegionSettingsAppliedCallback(boost::bind(&LLPanelEnvironmentInfo::onRegionSettingsApplied, this, _1)); +bool LLPanelEstateAccess::addAllowedGroup(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option != 0) return false; - LLDayCycleManager::instance().setModifyCallback(boost::bind(&LLPanelEnvironmentInfo::populateDayCyclesList, this)); - LLWLParamManager::instance().setPresetListChangeCallback(boost::bind(&LLPanelEnvironmentInfo::populateSkyPresetsList, this)); - LLWaterParamManager::instance().setPresetListChangeCallback(boost::bind(&LLPanelEnvironmentInfo::populateWaterPresetsList, this)); + LLFloater* parent_floater = gFloaterView->getParentFloater(this); - return TRUE; + LLFloaterGroupPicker* widget = LLFloaterGroupPicker::showInstance(LLSD(gAgent.getID())); + if (widget) + { + widget->removeNoneOption(); + widget->setSelectGroupCallback(boost::bind(&LLPanelEstateAccess::addAllowedGroup2, this, _1)); + if (parent_floater) + { + LLRect new_rect = gFloaterView->findNeighboringPosition(parent_floater, widget); + widget->setOrigin(new_rect.mLeft, new_rect.mBottom); + parent_floater->addDependentFloater(widget); + } + } + + return false; } -// virtual -void LLPanelEnvironmentInfo::onOpen(const LLSD& key) +void LLPanelEstateAccess::onClickRemoveAllowedGroup() { - LL_DEBUGS("Windlight") << "Panel opened, refreshing" << LL_ENDL; - refresh(); + accessRemoveCore(ESTATE_ACCESS_ALLOWED_GROUP_REMOVE, "EstateAllowedGroupRemove", "allowed_group_name_list"); } -// virtual -void LLPanelEnvironmentInfo::handleVisibilityChange(BOOL new_visibility) +void LLPanelEstateAccess::onClickAddBannedAgent() { - // If hiding (user switched to another tab or closed the floater), - // display user's preferred environment. - if (!new_visibility) + LLCtrlListInterface *list = childGetListInterface("banned_avatar_name_list"); + if (!list) return; + if (list->getItemCount() >= ESTATE_MAX_ACCESS_IDS) { - LLEnvManagerNew::instance().usePrefs(); + LLSD args; + args["MAX_BANNED"] = llformat("%d",ESTATE_MAX_ACCESS_IDS); + LLNotificationsUtil::add("MaxBannedAgentsOnRegion", args); + return; } + accessAddCore(ESTATE_ACCESS_BANNED_AGENT_ADD, "EstateBannedAgentAdd"); } -// virtual -bool LLPanelEnvironmentInfo::refreshFromRegion(LLViewerRegion* region) +void LLPanelEstateAccess::onClickRemoveBannedAgent() { - LL_DEBUGS("Windlight") << "Region updated, enabling/disabling controls" << LL_ENDL; - BOOL owner_or_god = gAgent.isGodlike() || (region && (region->getOwner() == gAgent.getID())); - BOOL owner_or_god_or_manager = owner_or_god || (region && region->isEstateManager()); - - // Don't refresh from region settings to avoid flicker after applying new region settings. - mEnableEditing = owner_or_god_or_manager; - setControlsEnabled(mEnableEditing); - - return LLPanelRegionInfo::refreshFromRegion(region); + accessRemoveCore(ESTATE_ACCESS_BANNED_AGENT_REMOVE, "EstateBannedAgentRemove", "banned_avatar_name_list"); } -void LLPanelEnvironmentInfo::refresh() +void LLPanelEstateAccess::onClickCopyAllowedList() { - populateWaterPresetsList(); - populateSkyPresetsList(); - populateDayCyclesList(); - - // Init radio groups. - const LLEnvironmentSettings& settings = LLEnvManagerNew::instance().getRegionSettings(); - const LLSD& dc = settings.getWLDayCycle(); - LLSD::Real first_frame_time = dc.size() > 0 ? dc[0][0].asReal() : 0.0f; - const bool use_fixed_sky = dc.size() == 1 && first_frame_time < 0; - mRegionSettingsRadioGroup->setSelectedIndex(settings.getSkyMap().size() == 0 ? 0 : 1); - mDayCycleSettingsRadioGroup->setSelectedIndex(use_fixed_sky ? 0 : 1); + copyListToClipboard("allowed_avatar_name_list"); +} - setControlsEnabled(mEnableEditing); +void LLPanelEstateAccess::onClickCopyAllowedGroupList() +{ + copyListToClipboard("allowed_group_name_list"); +} - setDirty(false); +void LLPanelEstateAccess::onClickCopyBannedList() +{ + copyListToClipboard("banned_avatar_name_list"); } -void LLPanelEnvironmentInfo::setControlsEnabled(bool enabled) +// static +void LLPanelEstateAccess::onClickAddEstateManager() { - mRegionSettingsRadioGroup->setEnabled(enabled); - mDayCycleSettingsRadioGroup->setEnabled(enabled); + LLCtrlListInterface *list = childGetListInterface("estate_manager_name_list"); + if (!list) return; + if (gHippoGridManager->getConnectedGrid()->isSecondLife() && list->getItemCount() >= ESTATE_MAX_MANAGERS) + { // Tell user they can't add more managers + LLSD args; + args["MAX_MANAGER"] = llformat("%d",ESTATE_MAX_MANAGERS); + LLNotificationsUtil::add("MaxManagersOnRegion", args); + } + else + { // Go pick managers to add + accessAddCore(ESTATE_ACCESS_MANAGER_ADD, "EstateManagerAdd"); + } +} - mWaterPresetCombo->setEnabled(enabled); - mSkyPresetCombo->setEnabled(enabled); - mDayCyclePresetCombo->setEnabled(enabled); +// static +void LLPanelEstateAccess::onClickRemoveEstateManager() +{ + accessRemoveCore(ESTATE_ACCESS_MANAGER_REMOVE, "EstateManagerRemove", "estate_manager_name_list"); +} - getChildView("apply_btn")->setEnabled(enabled); - getChildView("cancel_btn")->setEnabled(enabled); - if (enabled) +// Special case callback for groups, since it has different callback format than names +void LLPanelEstateAccess::addAllowedGroup2(LLUUID id) +{ + LLPanelEstateAccess* panel = LLFloaterRegionInfo::getPanelAccess(); + if (panel) { - // Enable/disable some controls based on currently selected radio buttons. - bool use_defaults = mRegionSettingsRadioGroup->getSelectedIndex() == 0; - getChild("user_environment_settings")->setEnabled(!use_defaults); + LLNameListCtrl* group_list = panel->getChild("allowed_group_name_list"); + LLScrollListItem* item = group_list->getNameItemByAgentId(id); + if (item) + { + LLSD args; + args["GROUP"] = item->getColumn(0)->getValue().asString(); + LLNotificationsUtil::add("GroupIsAlreadyInList", args); + return; + } + } + + LLSD payload; + payload["operation"] = (S32)ESTATE_ACCESS_ALLOWED_GROUP_ADD; + payload["dialog_name"] = "EstateAllowedGroupAdd"; + payload["allowed_ids"].append(id); - bool is_fixed_sky = mDayCycleSettingsRadioGroup->getSelectedIndex() == 0; - mSkyPresetCombo->setEnabled(is_fixed_sky); - mDayCyclePresetCombo->setEnabled(!is_fixed_sky); + LLSD args; + args["ALL_ESTATES"] = all_estates_text(); + + LLNotification::Params params("EstateAllowedGroupAdd"); + params.payload(payload) + .substitutions(args) + .functor(accessCoreConfirm); + if (LLPanelEstateInfo::isLindenEstate()) + { + LLNotifications::instance().forceResponse(params, 0); + } + else + { + LLNotifications::instance().add(params); } } -void LLPanelEnvironmentInfo::setApplyProgress(bool started) +// static +void LLPanelEstateAccess::accessAddCore(U32 operation_flag, const std::string& dialog_name) { - LLTextBox* indicator = getChild("progress_indicator"); + LLSD payload; + payload["operation"] = (S32)operation_flag; + payload["dialog_name"] = dialog_name; + // agent id filled in after avatar picker - indicator->setVisible(started); + LLNotification::Params params("ChangeLindenAccess"); + params.payload(payload) + .functor(accessAddCore2); -/* Singu TODO: LLLoadingIndicator - if (started) + if (LLPanelEstateInfo::isLindenEstate()) { - indicator->start(); + LLNotifications::instance().add(params); } else { - indicator->stop(); + // same as clicking "OK" + LLNotifications::instance().forceResponse(params, 0); } -*/ } -void LLPanelEnvironmentInfo::setDirty(bool dirty) +// static +bool LLPanelEstateAccess::accessAddCore2(const LLSD& notification, const LLSD& response) { - getChildView("apply_btn")->setEnabled(dirty); - getChildView("cancel_btn")->setEnabled(dirty); -} + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option != 0) + { + // abort change + return false; + } -void LLPanelEnvironmentInfo::sendRegionSunUpdate() -{ - LLRegionInfoModel& region_info = LLRegionInfoModel::instance(); + LLEstateAccessChangeInfo* change_info = new LLEstateAccessChangeInfo(notification["payload"]); + LLPanelEstateAccess* panel = LLFloaterRegionInfo::getPanelAccess(); + LLFloater* parent_floater = panel ? gFloaterView->getParentFloater(panel) : NULL; - // If the region is being switched to fixed sky, - // change the region's sun hour according to the (fixed) sun position. - // This is needed for llGetSunDirection() LSL function to work properly (STORM-1330). - const LLSD& sky_map = mNewRegionSettings.getSkyMap(); - bool region_use_fixed_sky = sky_map.size() == 1; - if (region_use_fixed_sky) - { - LLWLParamSet param_set; - llassert(sky_map.isMap()); - param_set.setAll(sky_map.beginMap()->second); - F32 sun_angle = param_set.getSunAngle(); + // avatar picker yes multi-select, yes close-on-select + LLFloater* child_floater = LLFloaterAvatarPicker::show(boost::bind(&LLPanelEstateAccess::accessAddCore3, _1, _2, change_info), TRUE, TRUE); - LL_DEBUGS("Windlight Sync") << "Old sun hour: " << region_info.mSunHour << LL_ENDL; - // convert value range from 0..2pi to 6..30 - region_info.mSunHour = fmodf((sun_angle / F_TWO_PI) * 24.f, 24.f) + 6.f; + //Allows the closed parent floater to close the child floater (avatar picker) + if (child_floater) + { + parent_floater->addDependentFloater(child_floater); } - region_info.setUseFixedSun(region_use_fixed_sky); - region_info.mUseEstateSun = !region_use_fixed_sky; - LL_DEBUGS("Windlight Sync") << "Sun hour: " << region_info.mSunHour << LL_ENDL; - - region_info.sendRegionTerrain(LLFloaterRegionInfo::getLastInvoice()); + return false; } -void LLPanelEnvironmentInfo::fixEstateSun() +// static +void LLPanelEstateAccess::accessAddCore3(const uuid_vec_t& ids, const std::vector& names, LLEstateAccessChangeInfo* change_info) { - // We don't support fixed sun estates anymore and need to fix - // such estates for region day cycle to take effect. - // *NOTE: Assuming that current estate settings have arrived already. - LLEstateInfoModel& estate_info = LLEstateInfoModel::instance(); - if (estate_info.getUseFixedSun()) + if (!change_info) return; + if (ids.empty()) { - llinfos << "Switching estate to global sun" << llendl; - estate_info.setUseFixedSun(false); - estate_info.sendEstateInfo(); + // User didn't select a name. + delete change_info; + change_info = NULL; + return; } -} + // User did select a name. + change_info->mAgentOrGroupIDs = ids; + // Can't put estate owner on ban list + LLPanelEstateAccess* panel = LLFloaterRegionInfo::getPanelAccess(); + if (!panel) return; + LLViewerRegion* region = gAgent.getRegion(); + if (!region) return; + + if (change_info->mOperationFlag & ESTATE_ACCESS_ALLOWED_AGENT_ADD) + { + LLNameListCtrl* name_list = panel->getChild("allowed_avatar_name_list"); + int currentCount = (name_list ? name_list->getItemCount() : 0); + if (ids.size() + currentCount > ESTATE_MAX_ACCESS_IDS) + { + LLSD args; + args["NUM_ADDED"] = llformat("%d",ids.size()); + args["MAX_AGENTS"] = llformat("%d",ESTATE_MAX_ACCESS_IDS); + args["LIST_TYPE"] = LLTrans::getString("RegionInfoListTypeAllowedAgents"); + args["NUM_EXCESS"] = llformat("%d",(ids.size()+currentCount)-ESTATE_MAX_ACCESS_IDS); + LLNotificationsUtil::add("MaxAgentOnRegionBatch", args); + delete change_info; + return; + } + + uuid_vec_t ids_allowed; + std::vector names_allowed; + std::string already_allowed; + bool single = true; + for (U32 i = 0; i < ids.size(); ++i) + { + LLScrollListItem* item = name_list->getNameItemByAgentId(ids[i]); + if (item) + { + if (!already_allowed.empty()) + { + already_allowed += ", "; + single = false; + } + already_allowed += item->getColumn(0)->getValue().asString(); + } + else + { + ids_allowed.push_back(ids[i]); + names_allowed.push_back(names[i]); + } + } + if (!already_allowed.empty()) + { + LLSD args; + args["AGENT"] = already_allowed; + args["LIST_TYPE"] = LLTrans::getString("RegionInfoListTypeAllowedAgents"); + LLNotificationsUtil::add(single ? "AgentIsAlreadyInList" : "AgentsAreAlreadyInList", args); + if (ids_allowed.empty()) + { + delete change_info; + return; + } + } + change_info->mAgentOrGroupIDs = ids_allowed; + change_info->mAgentNames = names_allowed; + } + if (change_info->mOperationFlag & ESTATE_ACCESS_BANNED_AGENT_ADD) + { + LLNameListCtrl* name_list = panel->getChild("banned_avatar_name_list"); + LLNameListCtrl* em_list = panel->getChild("estate_manager_name_list"); + int currentCount = (name_list ? name_list->getItemCount() : 0); + if (ids.size() + currentCount > ESTATE_MAX_ACCESS_IDS) + { + LLSD args; + args["NUM_ADDED"] = llformat("%d",ids.size()); + args["MAX_AGENTS"] = llformat("%d",ESTATE_MAX_ACCESS_IDS); + args["LIST_TYPE"] = LLTrans::getString("RegionInfoListTypeBannedAgents"); + args["NUM_EXCESS"] = llformat("%d",(ids.size()+currentCount)-ESTATE_MAX_ACCESS_IDS); + LLNotificationsUtil::add("MaxAgentOnRegionBatch", args); + delete change_info; + return; + } + + uuid_vec_t ids_allowed; + std::vector names_allowed; + std::string already_banned; + std::string em_ban; + bool single = true; + for (U32 i = 0; i < ids.size(); ++i) + { + bool is_allowed = true; + LLScrollListItem* em_item = em_list->getNameItemByAgentId(ids[i]); + if (em_item) + { + if (!em_ban.empty()) + { + em_ban += ", "; + } + em_ban += em_item->getColumn(0)->getValue().asString(); + is_allowed = false; + } -void LLPanelEnvironmentInfo::populateWaterPresetsList() -{ - mWaterPresetCombo->removeall(); + LLScrollListItem* item = name_list->getNameItemByAgentId(ids[i]); + if (item) + { + if (!already_banned.empty()) + { + already_banned += ", "; + single = false; + } + already_banned += item->getColumn(0)->getValue().asString(); + is_allowed = false; + } - // If the region already has water params, add them to the list. - const LLEnvironmentSettings& region_settings = LLEnvManagerNew::instance().getRegionSettings(); - if (region_settings.getWaterParams().size() != 0) - { - const std::string& region_name = gAgent.getRegion()->getName(); - mWaterPresetCombo->add(region_name, LLWLParamKey(region_name, LLEnvKey::SCOPE_REGION).toLLSD()); - mWaterPresetCombo->addSeparator(); + if (is_allowed) + { + ids_allowed.push_back(ids[i]); + names_allowed.push_back(names[i]); + } + } + if (!em_ban.empty()) + { + LLSD args; + args["AGENT"] = em_ban; + LLNotificationsUtil::add("ProblemBanningEstateManager", args); + if (ids_allowed.empty()) + { + delete change_info; + return; + } + } + if (!already_banned.empty()) + { + LLSD args; + args["AGENT"] = already_banned; + args["LIST_TYPE"] = LLTrans::getString("RegionInfoListTypeBannedAgents"); + LLNotificationsUtil::add(single ? "AgentIsAlreadyInList" : "AgentsAreAlreadyInList", args); + if (ids_allowed.empty()) + { + delete change_info; + return; + } + } + change_info->mAgentOrGroupIDs = ids_allowed; + change_info->mAgentNames = names_allowed; } - std::list user_presets, system_presets; - LLWaterParamManager::instance().getPresetNames(user_presets, system_presets); - - // Add local user presets first. - for (std::list::const_iterator it = user_presets.begin(); it != user_presets.end(); ++it) - { - mWaterPresetCombo->add(*it, LLWLParamKey(*it, LLEnvKey::SCOPE_LOCAL).toLLSD()); - } + LLSD args; + args["ALL_ESTATES"] = all_estates_text(); + LLNotification::Params params(change_info->mDialogName); + params.substitutions(args) + .payload(change_info->asLLSD()) + .functor(accessCoreConfirm); - if (user_presets.size() > 0) + if (LLPanelEstateInfo::isLindenEstate()) { - mWaterPresetCombo->addSeparator(); + // just apply to this estate + LLNotifications::instance().forceResponse(params, 0); } - - // Add local system presets. - for (std::list::const_iterator it = system_presets.begin(); it != system_presets.end(); ++it) + else { - mWaterPresetCombo->add(*it, LLWLParamKey(*it, LLEnvKey::SCOPE_LOCAL).toLLSD()); + // ask if this estate or all estates with this owner + LLNotifications::instance().add(params); } - - // There's no way to select current preset because its name is not stored on server. } -void LLPanelEnvironmentInfo::populateSkyPresetsList() +// static +void LLPanelEstateAccess::accessRemoveCore(U32 operation_flag, const std::string& dialog_name, const std::string& list_ctrl_name) { - mSkyPresetCombo->removeall(); + LLPanelEstateAccess* panel = LLFloaterRegionInfo::getPanelAccess(); + if (!panel) return; + LLNameListCtrl* name_list = panel->getChild(list_ctrl_name); + if (!name_list) return; - LLWLParamManager::preset_name_list_t region_presets; - LLWLParamManager::preset_name_list_t user_presets, sys_presets; - LLWLParamManager::instance().getPresetNames(region_presets, user_presets, sys_presets); + std::vector list_vector = name_list->getAllSelected(); + if (list_vector.size() == 0) + return; - // Add region presets. - std::string region_name = gAgent.getRegion() ? gAgent.getRegion()->getName() : LLTrans::getString("Unknown"); - for (LLWLParamManager::preset_name_list_t::const_iterator it = region_presets.begin(); it != region_presets.end(); ++it) + LLSD payload; + payload["operation"] = (S32)operation_flag; + payload["dialog_name"] = dialog_name; + + for (std::vector::const_iterator iter = list_vector.begin(); + iter != list_vector.end(); + iter++) { - std::string preset_name = *it; - std::string item_title = preset_name + " (" + region_name + ")"; - mSkyPresetCombo->add(item_title, LLWLParamKey(preset_name, LLEnvKey::SCOPE_REGION).toStringVal()); + LLScrollListItem *item = (*iter); + payload["allowed_ids"].append(item->getUUID()); } + + LLNotification::Params params("ChangeLindenAccess"); + params.payload(payload) + .functor(accessRemoveCore2); - if (!region_presets.empty()) + if (LLPanelEstateInfo::isLindenEstate()) { - mSkyPresetCombo->addSeparator(); + // warn on change linden estate + LLNotifications::instance().add(params); } - - // Add user presets. - for (LLWLParamManager::preset_name_list_t::const_iterator it = user_presets.begin(); it != user_presets.end(); ++it) + else { - mSkyPresetCombo->add(*it, LLWLParamKey(*it, LLEnvKey::SCOPE_LOCAL).toStringVal()); + // just proceed, as if clicking OK + LLNotifications::instance().forceResponse(params, 0); } +} - if (!user_presets.empty()) +// static +bool LLPanelEstateAccess::accessRemoveCore2(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option != 0) { - mSkyPresetCombo->addSeparator(); + // abort + return false; } - // Add system presets. - for (LLWLParamManager::preset_name_list_t::const_iterator it = sys_presets.begin(); it != sys_presets.end(); ++it) + // If Linden estate, can only apply to "this" estate, not all estates + // owned by NULL. + if (LLPanelEstateInfo::isLindenEstate()) { - mSkyPresetCombo->add(*it, LLWLParamKey(*it, LLEnvKey::SCOPE_LOCAL).toStringVal()); + accessCoreConfirm(notification, response); } - - // Select current preset. - LLSD sky_map = LLEnvManagerNew::instance().getRegionSettings().getSkyMap(); - if (sky_map.size() == 1) // if the region is set to fixed sky + else { - std::string preset_name = sky_map.beginMap()->first; - mSkyPresetCombo->selectByValue(LLWLParamKey(preset_name, LLEnvKey::SCOPE_REGION).toStringVal()); + LLSD args; + args["ALL_ESTATES"] = all_estates_text(); + LLNotificationsUtil::add(notification["payload"]["dialog_name"], + args, + notification["payload"], + accessCoreConfirm); } + return false; } -void LLPanelEnvironmentInfo::populateDayCyclesList() +// Used for both access add and remove operations, depending on the mOperationFlag +// passed in (ESTATE_ACCESS_BANNED_AGENT_ADD, ESTATE_ACCESS_ALLOWED_AGENT_REMOVE, etc.) +// static +bool LLPanelEstateAccess::accessCoreConfirm(const LLSD& notification, const LLSD& response) { - mDayCyclePresetCombo->removeall(); - - // If the region already has env. settings, add its day cycle to the list. - const LLSD& cur_region_dc = LLEnvManagerNew::instance().getRegionSettings().getWLDayCycle(); - if (cur_region_dc.size() != 0) - { - LLViewerRegion* region = gAgent.getRegion(); - llassert(region != NULL); - - LLWLParamKey key(region->getName(), LLEnvKey::SCOPE_REGION); - mDayCyclePresetCombo->add(region->getName(), key.toStringVal()); - mDayCyclePresetCombo->addSeparator(); - } + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + const U32 originalFlags = (U32)notification["payload"]["operation"].asInteger(); + U32 flags = originalFlags; - // Add local user day cycles. - LLDayCycleManager::preset_name_list_t user_days, sys_days; - LLDayCycleManager::instance().getPresetNames(user_days, sys_days); - for (LLDayCycleManager::preset_name_list_t::const_iterator it = user_days.begin(); it != user_days.end(); ++it) + LLViewerRegion* region = gAgent.getRegion(); + + if (option == 2) // cancel { - mDayCyclePresetCombo->add(*it, LLWLParamKey(*it, LLEnvKey::SCOPE_LOCAL).toStringVal()); + return false; } - - if (user_days.size() > 0) + else if (option == 1) { - mDayCyclePresetCombo->addSeparator(); + // All estates, either than I own or manage for this owner. + // This will be verified on simulator. JC + if (!region) return false; + if (region->getOwner() == gAgent.getID() + || gAgent.isGodlike()) + { + flags |= ESTATE_ACCESS_APPLY_TO_ALL_ESTATES; + } + else if (region->isEstateManager()) + { + flags |= ESTATE_ACCESS_APPLY_TO_MANAGED_ESTATES; + } } - // Add local system day cycles. - for (LLDayCycleManager::preset_name_list_t::const_iterator it = sys_days.begin(); it != sys_days.end(); ++it) + std::string names; + U32 listed_names = 0; + const auto& ids = notification["payload"]["allowed_ids"]; + const auto& allowed_names = notification["payload"]["allowed_names"]; + U32 size = ids.size(); + for (U32 i = 0; i < size; ++i) { - mDayCyclePresetCombo->add(*it, LLWLParamKey(*it, LLEnvKey::SCOPE_LOCAL).toStringVal()); - } + if (i + 1 != size) + { + flags |= ESTATE_ACCESS_NO_REPLY; + } + else + { + flags &= ~ESTATE_ACCESS_NO_REPLY; + } - // Current day cycle is already selected. -} + const LLUUID id = ids[i].asUUID(); + if (((U32)notification["payload"]["operation"].asInteger() & ESTATE_ACCESS_BANNED_AGENT_ADD) + && region && (region->getOwner() == id)) + { + LLNotificationsUtil::add("OwnerCanNotBeDenied"); + break; + } -bool LLPanelEnvironmentInfo::getSelectedWaterParams(LLSD& water_params) -{ - LLWLParamKey water_key(mWaterPresetCombo->getSelectedValue()); + sendEstateAccessDelta(flags, id); - if (water_key.scope == LLEnvKey::SCOPE_REGION) + if ((flags & (ESTATE_ACCESS_ALLOWED_GROUP_ADD | ESTATE_ACCESS_ALLOWED_GROUP_REMOVE)) == 0) + { + // fill the name list for confirmation + if (listed_names < MAX_LISTED_NAMES) + { + if (!names.empty()) + { + names += ", "; + } + const auto& display_name = allowed_names[i]["display_name"].asStringRef(); + if (!display_name.empty()) + { + names += display_name; + } + else + { //try to get an agent name from cache + LLAvatarName av_name; + if (LLAvatarNameCache::get(id, &av_name)) + { + names += av_name.getCompleteName(); + } + } + + } + listed_names++; + } + } + if (listed_names > MAX_LISTED_NAMES) { - water_params = LLEnvManagerNew::instance().getRegionSettings().getWaterParams(); + LLSD args; + args["EXTRA_COUNT"] = llformat("%d", listed_names - MAX_LISTED_NAMES); + names += " " + LLTrans::getString("AndNMore", args); } - else + + if (!names.empty()) // show the conirmation { - LLWaterParamSet param_set; - if (!LLWaterParamManager::instance().getParamSet(water_key.name, param_set)) + LLSD args; + args["AGENT"] = names; + + if (flags & (ESTATE_ACCESS_ALLOWED_AGENT_ADD | ESTATE_ACCESS_ALLOWED_AGENT_REMOVE)) { - llwarns << "Error getting water preset: " << water_key.name << llendl; - return false; + args["LIST_TYPE"] = LLTrans::getString("RegionInfoListTypeAllowedAgents"); + } + else if (flags & (ESTATE_ACCESS_BANNED_AGENT_ADD | ESTATE_ACCESS_BANNED_AGENT_REMOVE)) + { + args["LIST_TYPE"] = LLTrans::getString("RegionInfoListTypeBannedAgents"); } - water_params = param_set.getAll(); + if (flags & ESTATE_ACCESS_APPLY_TO_ALL_ESTATES) + { + args["ESTATE"] = LLTrans::getString("RegionInfoAllEstates"); + } + else if (flags & ESTATE_ACCESS_APPLY_TO_MANAGED_ESTATES) + { + args["ESTATE"] = LLTrans::getString("RegionInfoManagedEstates"); + } + else + { + args["ESTATE"] = LLTrans::getString("RegionInfoThisEstate"); + } + + bool single = (listed_names == 1); + if (flags & (ESTATE_ACCESS_ALLOWED_AGENT_ADD | ESTATE_ACCESS_BANNED_AGENT_ADD)) + { + LLNotificationsUtil::add(single ? "AgentWasAddedToList" : "AgentsWereAddedToList", args); + } + else if (flags & (ESTATE_ACCESS_ALLOWED_AGENT_REMOVE | ESTATE_ACCESS_BANNED_AGENT_REMOVE)) + { + LLNotificationsUtil::add(single ? "AgentWasRemovedFromList" : "AgentsWereRemovedFromList", args); + } } - return true; + LLPanelEstateAccess* panel = LLFloaterRegionInfo::getPanelAccess(); + if (panel) + { + panel->setPendingUpdate(true); + } + + return false; } -bool LLPanelEnvironmentInfo::getSelectedSkyParams(LLSD& sky_params, std::string& preset_name) +// key = "estateaccessdelta" +// str(estate_id) will be added to front of list by forward_EstateOwnerRequest_to_dataserver +// str[0] = str(agent_id) requesting the change +// str[1] = str(flags) (ESTATE_ACCESS_DELTA_*) +// str[2] = str(agent_id) to add or remove +// static +void LLPanelEstateAccess::sendEstateAccessDelta(U32 flags, const LLUUID& agent_or_group_id) { - std::string preset_key(mSkyPresetCombo->getValue().asString()); - LLWLParamKey preset(preset_key); + LLMessageSystem* msg = gMessageSystem; + msg->newMessage("EstateOwnerMessage"); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addUUIDFast(_PREHASH_TransactionID, LLUUID::null); //not used - // Get the preset sky params. - LLWLParamSet param_set; - if (!LLWLParamManager::instance().getParamSet(preset, param_set)) - { - llwarns << "Error getting sky params: " << preset.toLLSD() << llendl; - return false; - } + msg->nextBlock("MethodData"); + msg->addString("Method", "estateaccessdelta"); + msg->addUUID("Invoice", LLFloaterRegionInfo::getLastInvoice()); + + std::string buf; + gAgent.getID().toString(buf); + msg->nextBlock("ParamList"); + msg->addString("Parameter", buf); + + buf = llformat("%u", flags); + msg->nextBlock("ParamList"); + msg->addString("Parameter", buf); - sky_params = param_set.getAll(); - preset_name = preset.name; - return true; -} + agent_or_group_id.toString(buf); + msg->nextBlock("ParamList"); + msg->addString("Parameter", buf); -bool LLPanelEnvironmentInfo::getSelectedDayCycleParams(LLSD& day_cycle, LLSD& sky_map, short& scope) -{ - std::string preset_key(mDayCyclePresetCombo->getValue().asString()); - LLWLParamKey dc(preset_key); - LL_DEBUGS("Windlight") << "Use day cycle: " << dc.toLLSD() << LL_ENDL; - if (dc.scope == LLEnvKey::SCOPE_REGION) // current region day cycle - { - const LLEnvironmentSettings& cur_region_settings = LLEnvManagerNew::instance().getRegionSettings(); - day_cycle = cur_region_settings.getWLDayCycle(); - sky_map = cur_region_settings.getSkyMap(); - } - else // a local day cycle + if (flags & (ESTATE_ACCESS_ALLOWED_AGENT_ADD | ESTATE_ACCESS_ALLOWED_AGENT_REMOVE | + ESTATE_ACCESS_BANNED_AGENT_ADD | ESTATE_ACCESS_BANNED_AGENT_REMOVE)) { - if (!LLDayCycleManager::instance().getPreset(dc.name, day_cycle)) - { - llwarns << "Error getting day cycle " << dc.name << llendl; - return false; - } - - // Create sky map from the day cycle. + if (auto panel = LLFloaterRegionInfo::getPanelAccess()) { - LLWLDayCycle tmp_day; - tmp_day.loadDayCycle(day_cycle, dc.scope); - tmp_day.getSkyMap(sky_map); + // Clear these out before we ask for an update + if (auto name_list = panel->getChild("allowed_avatar_name_list")) + name_list->deleteAllItems(); + if (auto name_list = panel->getChild("banned_avatar_name_list")) + name_list->deleteAllItems(); } } - scope = dc.scope; - - return true; + gAgent.sendReliableMessage(); } -void LLPanelEnvironmentInfo::onSwitchRegionSettings() + +void LLPanelEstateAccess::updateChild(LLUICtrl* child_ctrl) { - bool use_defaults = mRegionSettingsRadioGroup->getSelectedIndex() == 0; - getChild("user_environment_settings")->setEnabled(!use_defaults); + // Ensure appropriate state of the management ui. + updateControls(gAgent.getRegion()); +} - if (use_defaults) +struct RequestEstateGetAccessResponder : public LLHTTPClient::ResponderWithCompleted +{ + void httpCompleted() override { - LLEnvManagerNew::instance().useDefaults(); + LLPanelEstateAccess::onEstateAccessReceived(mContent); } - else + char const* getName() const override { return "requestEstateGetAccessCoro"; } +}; + +void LLPanelEstateAccess::updateLists() +{ + std::string cap_url = gAgent.getRegionCapability("EstateAccess"); + if (!cap_url.empty()) { - onSelectWaterPreset(); - onSwitchDayCycle(); + LLHTTPClient::get(cap_url, new RequestEstateGetAccessResponder); + } +} +/* + LLCoros::instance().launch("LLFloaterRegionInfo::requestEstateGetAccessCoro", boost::bind(LLPanelEstateAccess::requestEstateGetAccessCoro, cap_url)); } - - setDirty(true); } -void LLPanelEnvironmentInfo::onSwitchDayCycle() +void LLPanelEstateAccess::requestEstateGetAccessCoro(std::string url) { - bool is_fixed_sky = mDayCycleSettingsRadioGroup->getSelectedIndex() == 0; + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("requestEstateGetAccessoCoro", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); - mSkyPresetCombo->setEnabled(is_fixed_sky); - mDayCyclePresetCombo->setEnabled(!is_fixed_sky); + LLSD result = httpAdapter->getAndSuspend(httpRequest, url); - if (is_fixed_sky) - { - onSelectSkyPreset(); - } - else - { - onSelectDayCycle(); - } + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); - setDirty(true); + onEstateAccessReceived(result); } +*/ -void LLPanelEnvironmentInfo::onSelectWaterPreset() +const std::string& getNAString() { - LLSD water_params; - - if (getSelectedWaterParams(water_params)) - { - LLEnvManagerNew::instance().useWaterParams(water_params); - } - - setDirty(true); + static const auto na = LLTrans::getString("na"); + return na; } -void LLPanelEnvironmentInfo::onSelectSkyPreset() +#if defined(__GNUC__) && __GNUC__ < 5 // On GCC 4, implement std::get_time using strptime +#include + +namespace std { - LLSD params; - std::string dummy; + struct get_time + { + tm* mTime; + const char* mFmt; + get_time(tm* time, const char* fmt) : mTime(time), mFmt(fmt) {} + }; - if (getSelectedSkyParams(params, dummy)) + istringstream& operator>>(istringstream&& str, get_time&& rhs) { - LLEnvManagerNew::instance().useSkyParams(params); + if (!strptime(str.str().data(), rhs.mFmt, rhs.mTime)) + str.setstate(ios_base::failbit); + return str; } - - setDirty(true); } +#endif -void LLPanelEnvironmentInfo::onSelectDayCycle() +void handlePseudoISO8601(const std::string& date_str, LLSD& column, const std::string& fmt) { - LLSD day_cycle; - LLSD sky_map; // unused - short scope; - - if (getSelectedDayCycleParams(day_cycle, sky_map, scope)) + if (date_str.front() == '0') // server returns the "0000-00-00 00:00:00" date in case it doesn't know it { - LLEnvManagerNew::instance().useDayCycleParams(day_cycle, (LLEnvKey::EScope) scope); + column["value"] = getNAString(); + } + else + { + std::tm time = {}; + if (std::istringstream(date_str) >> std::get_time(&time, "%F %T")) + { + column["value"] = LLDate(mktime(&time)); + column["type"] = "date"; + column["format"] = fmt; + } + else column["value"] = date_str; } - - setDirty(true); } - -void LLPanelEnvironmentInfo::onBtnApply() +void LLPanelEstateAccess::onEstateAccessReceived(const LLSD& result) { - const bool use_defaults = mRegionSettingsRadioGroup->getSelectedIndex() == 0; - const bool use_fixed_sky = mDayCycleSettingsRadioGroup->getSelectedIndex() == 0; - - LLSD day_cycle; - LLSD sky_map; - LLSD water_params; - - if (use_defaults) + LLPanelEstateAccess* panel = LLFloaterRegionInfo::getPanelAccess(); + if (!panel) return; + + LLNameListCtrl* allowed_agent_name_list = panel->getChild("allowed_avatar_name_list"); + if (allowed_agent_name_list && result.has("AllowedAgents")) { - // settings will be empty - LL_DEBUGS("Windlight") << "Defaults" << LL_ENDL; + LLStringUtil::format_map_t args; + args["[ALLOWEDAGENTS]"] = llformat("%d", result["AllowedAgents"].size()); + args["[MAXACCESS]"] = llformat("%d", ESTATE_MAX_ACCESS_IDS); + std::string msg = LLTrans::getString("RegionInfoAllowedResidents", args); + panel->getChild("allow_resident_label")->setValue(LLSD(msg)); + + const auto order = allowed_agent_name_list->getSortOrder(); + allowed_agent_name_list->clearSortOrder(); + allowed_agent_name_list->deleteAllItems(); + for (auto const& entry : result["AllowedAgents"].array()) + { + LLUUID id = entry["id"].asUUID(); + allowed_agent_name_list->addNameItem(id); + } + allowed_agent_name_list->setSortOrder(order); } - else // use custom region settings + + LLNameListCtrl* banned_agent_name_list = panel->getChild("banned_avatar_name_list"); + if (banned_agent_name_list && result.has("BannedAgents")) { - if (use_fixed_sky) + LLStringUtil::format_map_t args; + args["[BANNEDAGENTS]"] = llformat("%d", result["BannedAgents"].size()); + args["[MAXBANNED]"] = llformat("%d", ESTATE_MAX_ACCESS_IDS); + std::string msg = LLTrans::getString("RegionInfoBannedResidents", args); + panel->getChild("ban_resident_label")->setValue(LLSD(msg)); + + const auto format = gSavedSettings.getString("ShortDateFormat"); + const auto order = banned_agent_name_list->getSortOrder(); + banned_agent_name_list->clearSortOrder(); + banned_agent_name_list->deleteAllItems(); + for (auto const& entry : result["BannedAgents"].array()) { - LL_DEBUGS("Windlight") << "Use fixed sky" << LL_ENDL; + LLSD item; + item["id"] = entry["id"].asUUID(); + LLSD& columns = item["columns"]; - // Get selected sky params. - LLSD params; - std::string preset_name; - if (!getSelectedSkyParams(params, preset_name)) - { - return; - } + columns[0]["column"] = "name"; // to be populated later - // Create a day cycle consisting of a single sky preset. - LLSD key(LLSD::emptyArray()); - key.append(-1.0f); // indicate that user preference is actually fixed sky, not a day cycle - key.append(preset_name); - day_cycle.append(key); + auto& col = columns[1]; + col["column"] = "last_login_date"; + handlePseudoISO8601(entry["last_login_date"].asString(), col, format); - // Create a sky map consisting of only the sky preset. - std::map refs; - LLWLParamSet param_set; - param_set.setAll(params); - refs[LLWLParamKey(preset_name, LLEnvKey::SCOPE_LOCAL)] = param_set; // scope doesn't matter here - sky_map = LLWLParamManager::createSkyMap(refs); - } - else // use day cycle - { - LL_DEBUGS("Windlight") << "Use day cycle" << LL_ENDL; + columns[2]["column"] = "ban_date"; + handlePseudoISO8601(entry["ban_date"].asString(), columns[2], format); - short scope; // unused - if (!getSelectedDayCycleParams(day_cycle, sky_map, scope)) + columns[3]["column"] = "bannedby"; + LLUUID banning_id = entry["banning_id"].asUUID(); + LLAvatarName av_name; + if (banning_id.isNull()) { - return; + columns[3]["value"] = getNAString(); } - - // If it's a special single-preset day cycle meaning using a fixed sky, - // reset the frame time to a non-negative value, - // so that the region setting is displayed in the floater as - // a day cycle, not a preset. (STORM-1289) - if (day_cycle.size() == 1 && day_cycle[0][0].asReal() < 0.0f) + else if (LLAvatarNameCache::get(banning_id, &av_name)) { - LL_DEBUGS("Windlight") << "Fixing negative time" << LL_ENDL; - day_cycle[0][0] = 0.0f; + columns[3]["value"] = av_name.getCompleteName(); //TODO: fetch the name if it wasn't cached } + + banned_agent_name_list->addElement(item); } + banned_agent_name_list->setSortOrder(order); + } - // Get water params. - if (!getSelectedWaterParams(water_params)) + LLNameListCtrl* allowed_group_name_list = panel->getChild("allowed_group_name_list"); + if (allowed_group_name_list && result.has("AllowedGroups")) + { + LLStringUtil::format_map_t args; + args["[ALLOWEDGROUPS]"] = llformat("%d", result["AllowedGroups"].size()); + args["[MAXACCESS]"] = llformat("%d", ESTATE_MAX_GROUP_IDS); + std::string msg = LLTrans::getString("RegionInfoAllowedGroups", args); + panel->getChild("allow_group_label")->setValue(LLSD(msg)); + + const auto order = allowed_group_name_list->getSortOrder(); + allowed_group_name_list->clearSortOrder(); + allowed_group_name_list->deleteAllItems(); + for (auto const& entry : result["AllowedGroups"].array()) { - // *TODO: show a notification? - return; + LLUUID id = entry["id"].asUUID(); + allowed_group_name_list->addGroupNameItem(id); } + allowed_group_name_list->setSortOrder(order); } - // Send settings apply request. - LLEnvironmentSettings new_region_settings; - new_region_settings.saveParams(day_cycle, sky_map, water_params, 0.0f); - if (!LLEnvManagerNew::instance().sendRegionSettings(new_region_settings)) + LLNameListCtrl* estate_manager_name_list = panel->getChild("estate_manager_name_list"); + if (estate_manager_name_list && result.has("Managers")) { - llwarns << "Error applying region environment settings" << llendl; - return; + LLStringUtil::format_map_t args; + args["[ESTATEMANAGERS]"] = llformat("%d", result["Managers"].size()); + args["[MAXMANAGERS]"] = llformat("%d", ESTATE_MAX_MANAGERS); + std::string msg = LLTrans::getString("RegionInfoEstateManagers", args); + panel->getChild("estate_manager_label")->setValue(LLSD(msg)); + + const auto order = estate_manager_name_list->getSortOrder(); + estate_manager_name_list->clearSortOrder(); + estate_manager_name_list->deleteAllItems(); + for (auto const& entry : result["Managers"].array()) + { + LLUUID id = entry["agent_id"].asUUID(); + estate_manager_name_list->addNameItem(id); + } + estate_manager_name_list->setSortOrder(order); } - // When the settings get applied, we'll also send the region sun position update. - // To determine the sun angle we're going to need the new settings. - mNewRegionSettings = new_region_settings; - // Start spinning the progress indicator. - setApplyProgress(true); + panel->updateControls(gAgent.getRegion()); } -void LLPanelEnvironmentInfo::onBtnCancel() +//--------------------------------------------------------------------------- +// Access lists search +//--------------------------------------------------------------------------- +void LLPanelEstateAccess::onAllowedSearchEdit(const std::string& search_string) { - // Reload last saved region settings. - refresh(); + LLPanelEstateAccess* panel = LLFloaterRegionInfo::getPanelAccess(); + if (!panel) return; + LLNameListCtrl* allowed_agent_name_list = panel->getChild("allowed_avatar_name_list"); + searchAgent(allowed_agent_name_list, search_string); +} - // Apply them. - LLEnvManagerNew& env_mgr = LLEnvManagerNew::instance(); - const LLEnvironmentSettings& cur_settings = env_mgr.getRegionSettings(); - const LLSD& region_day_cycle = cur_settings.getWLDayCycle(); - const LLSD& region_water = cur_settings.getWaterParams(); - env_mgr.useWaterParams(region_water); - env_mgr.useDayCycleParams(region_day_cycle, LLEnvKey::SCOPE_REGION); +void LLPanelEstateAccess::onAllowedGroupsSearchEdit(const std::string& search_string) +{ + LLPanelEstateAccess* panel = LLFloaterRegionInfo::getPanelAccess(); + if (!panel) return; + LLNameListCtrl* allowed_group_name_list = panel->getChild("allowed_group_name_list"); + searchAgent(allowed_group_name_list, search_string); } -void LLPanelEnvironmentInfo::onRegionSettingschange() +void LLPanelEstateAccess::onBannedSearchEdit(const std::string& search_string) { - LL_DEBUGS("Windlight") << "Region settings changed, refreshing" << LL_ENDL; - refresh(); + LLPanelEstateAccess* panel = LLFloaterRegionInfo::getPanelAccess(); + if (!panel) return; + LLNameListCtrl* banned_agent_name_list = panel->getChild("banned_avatar_name_list"); + searchAgent(banned_agent_name_list, search_string); +} - // Stop applying progress indicator (it may be running if it's us who initiated settings update). - setApplyProgress(false); +void LLPanelEstateAccess::searchAgent(LLNameListCtrl* listCtrl, const std::string& search_string) +{ + if (!listCtrl) return; + listCtrl->setFilter(search_string); } -void LLPanelEnvironmentInfo::onRegionSettingsApplied(bool ok) +void LLPanelEstateAccess::copyListToClipboard(std::string list_name) { - // If applying new settings has failed, stop the indicator right away. - // Otherwise it will be stopped when we receive the updated settings from server. - if (ok) - { - // Set the region sun phase/flags according to the chosen new preferences. - // - // If we do this earlier we may get jerky transition from fixed sky to a day cycle (STORM-1481). - // That is caused by the simulator re-sending the region info, which in turn makes us - // re-request and display old region environment settings while the new ones haven't been applied yet. - sendRegionSunUpdate(); + LLPanelEstateAccess* panel = LLFloaterRegionInfo::getPanelAccess(); + if (!panel) return; + LLNameListCtrl* name_list = panel->getChild(list_name); + if (!name_list) return; - // Switch estate to not using fixed sun for the region day cycle to work properly (STORM-1506). - fixEstateSun(); - } - else - { - setApplyProgress(false); + std::vector list_vector = name_list->getAllData(); + if (list_vector.size() == 0) return; - // We need to re-request environment setting here, - // otherwise our subsequent attempts to change region settings will fail with the following error: - // "Unable to update environment settings because the last update your viewer saw was not the same - // as the last update sent from the simulator. Try sending your update again, and if this - // does not work, try leaving and returning to the region." - LLEnvManagerNew::instance().requestRegionSettings(); + LLSD::String list_to_copy; + for (std::vector::const_iterator iter = list_vector.begin(); + iter != list_vector.end(); + iter++) + { + LLScrollListItem *item = (*iter); + if (item) + { + list_to_copy += item->getColumn(0)->getValue().asString(); + } + if (std::next(iter) != list_vector.end()) + { + list_to_copy += '\n'; + } } + + auto wstr = utf8str_to_wstring(list_to_copy); + gClipboard.copyFromSubstring(wstr, 0, wstr.length()); +} + +bool LLPanelEstateAccess::refreshFromRegion(LLViewerRegion* region) +{ + // Clear these out before we ask for an update + if (auto name_list = getChild("allowed_avatar_name_list")) + name_list->deleteAllItems(); + if (auto name_list = getChild("banned_avatar_name_list")) + name_list->deleteAllItems(); + + updateLists(); + return LLPanelRegionInfo::refreshFromRegion(region); } + // [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0a) void LLFloaterRegionInfo::open() { // We'll allow access to the estate tools for estate managers (and for the sim owner) if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) { - LLViewerRegion* pRegion = gAgent.getRegion(); - if (!pRegion) - return; - + const LLViewerRegion* region(gAgent.getRegion()); // Should be able to call LLRegion::canManageEstate() but then we can fake god like - if ( (!pRegion->isEstateManager()) && (pRegion->getOwner() != gAgent.getID()) ) + if (!region || !region->isEstateManager() || region->getOwner() != gAgentID) return; } LLFloater::open(); } // [/RLVa:KB] + diff --git a/indra/newview/llfloaterregioninfo.h b/indra/newview/llfloaterregioninfo.h index 00c672b9d6..0a5840116c 100644 --- a/indra/newview/llfloaterregioninfo.h +++ b/indra/newview/llfloaterregioninfo.h @@ -3,31 +3,25 @@ * @author Aaron Brashears * @brief Declaration of the region info and controls floater and panels. * - * $LicenseInfo:firstyear=2004&license=viewergpl$ - * - * Copyright (c) 2004-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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$ */ @@ -35,12 +29,14 @@ #define LL_LLFLOATERREGIONINFO_H #include +#include "llagent.h" #include "llfloater.h" #include "llpanel.h" #include "llenvmanager.h" // for LLEnvironmentSettings class LLAvatarName; +class LLDispatcher; struct LLEstateAccessChangeInfo; class LLLineEditor; class LLMessageSystem; @@ -56,6 +52,7 @@ class LLRadioGroup; class LLSliderCtrl; class LLSpinCtrl; class LLTextBox; +class LLVFS; class AIFilePicker; class LLPanelRegionGeneralInfo; @@ -63,18 +60,29 @@ class LLPanelRegionDebugInfo; class LLPanelRegionTerrainInfo; class LLPanelEstateInfo; class LLPanelEstateCovenant; - +class LLPanelExperienceListEditor; +class LLPanelExperiences; +class LLPanelRegionExperiences; +class LLPanelEstateAccess; + +class LLEventTimer; +class LLEnvironmentSettings; +class LLWLParamManager; +class LLWaterParamManager; +class LLWLParamSet; +class LLWaterParamSet; class LLFloaterRegionInfo : public LLFloater, public LLFloaterSingleton { - friend class LLUISingleton >; + friend class LLUISingleton>; public: - /*virtual*/ void onOpen(); - /*virtual*/ BOOL postBuild(); + /*virtual*/ void onOpen(/*const LLSD& key*/) override; + /*virtual*/ void onClose(bool app_quitting) override; + /*virtual*/ BOOL postBuild() override; // [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0a) - /*virtual*/ void open(); + /*virtual*/ void open() override; // [/RLVa:KB] static void processEstateOwnerRequest(LLMessageSystem* msg, void**); @@ -88,20 +96,27 @@ class LLFloaterRegionInfo : public LLFloater, public LLFloaterSingleton& names); @@ -211,6 +231,7 @@ class LLPanelRegionDebugInfo : public LLPanelRegionInfo static void onClickRestart(void* data); bool callbackRestart(const LLSD& notification, const LLSD& response); static void onClickCancelRestart(void* data); + static void onClickDebugConsole(void* data); private: LLUUID mTargetAvatar; @@ -226,9 +247,10 @@ class LLPanelRegionTerrainInfo : public LLPanelRegionInfo LLPanelRegionTerrainInfo() : LLPanelRegionInfo() {} ~LLPanelRegionTerrainInfo() {} - virtual BOOL postBuild(); // LLPanel + BOOL postBuild() override; // LLPanel - virtual bool refreshFromRegion(LLViewerRegion* region); // refresh local settings from region update from simulator + bool refreshFromRegion(LLViewerRegion* region) override; // refresh local settings from region update from simulator + void setEnvControls(bool available); // Whether environment settings are available for this region BOOL validateTextureSizes(); @@ -236,7 +258,7 @@ class LLPanelRegionTerrainInfo : public LLPanelRegionInfo //static void onChangeAnything(LLUICtrl* ctrl, void* userData); // callback for any change, to enable commit button - virtual BOOL sendUpdate(); + BOOL sendUpdate() override; static void onClickDownloadRaw(void*); void onClickDownloadRaw_continued(AIFilePicker* filepicker); @@ -255,41 +277,18 @@ class LLPanelEstateInfo : public LLPanelRegionInfo void onChangeFixedSun(); void onChangeUseGlobalTime(); + void onChangeAccessOverride(); void onClickEditSky(); void onClickEditSkyHelp(); void onClickEditDayCycle(); void onClickEditDayCycleHelp(); - void onClickAddAllowedAgent(); - void onClickRemoveAllowedAgent(); - void onClickAddAllowedGroup(); - void onClickRemoveAllowedGroup(); - void onClickAddBannedAgent(); - void onClickRemoveBannedAgent(); - void onClickAddEstateManager(); - void onClickRemoveEstateManager(); void onClickKickUser(); - // Group picker callback is different, can't use core methods below - bool addAllowedGroup(const LLSD& notification, const LLSD& response); - void addAllowedGroup2(LLUUID id); - - // Core methods for all above add/remove button clicks - static void accessAddCore(U32 operation_flag, const std::string& dialog_name); - static bool accessAddCore2(const LLSD& notification, const LLSD& response); - static void accessAddCore3(const uuid_vec_t& ids, LLEstateAccessChangeInfo* change_info); - - static void accessRemoveCore(U32 operation_flag, const std::string& dialog_name, const std::string& list_ctrl_name); - static bool accessRemoveCore2(const LLSD& notification, const LLSD& response); - // used for both add and remove operations - static bool accessCoreConfirm(const LLSD& notification, const LLSD& response); bool kickUserConfirm(const LLSD& notification, const LLSD& response); - // Send the actual EstateOwnerRequest "estateaccessdelta" message - static void sendEstateAccessDelta(U32 flags, const LLUUID& agent_id); - void onKickUserCommit(const uuid_vec_t& ids, const std::vector& names); static void onClickMessageEstate(void* data); bool onMessageCommit(const LLSD& notification, const LLSD& response); @@ -300,33 +299,30 @@ class LLPanelEstateInfo : public LLPanelRegionInfo void updateControls(LLViewerRegion* region); static void updateEstateName(const std::string& name); - static void updateEstateOwnerName(const std::string& name); + static void updateEstateOwnerID(const LLUUID& id); - virtual bool refreshFromRegion(LLViewerRegion* region); - virtual bool estateUpdate(LLMessageSystem* msg); + bool refreshFromRegion(LLViewerRegion* region) override; + bool estateUpdate(LLMessageSystem* msg) override; // LLPanel - virtual BOOL postBuild(); - virtual void updateChild(LLUICtrl* child_ctrl); - virtual void refresh(); + BOOL postBuild() override; + void updateChild(LLUICtrl* child_ctrl) override; + void refresh() override; void refreshFromEstate(); static bool isLindenEstate(); const std::string getOwnerName() const; - void setOwnerName(const std::string& name); - void setOwnerPNSName(const LLUUID& agent_id, const LLAvatarName& av_name); protected: - virtual BOOL sendUpdate(); + BOOL sendUpdate() override; // confirmation dialog callback bool callbackChangeLindenEstate(const LLSD& notification, const LLSD& response); void commitEstateAccess(); void commitEstateManagers(); - void clearAccessLists(); BOOL checkSunHourSlider(LLUICtrl* child_ctrl); U32 mEstateID; @@ -341,16 +337,16 @@ class LLPanelEstateCovenant : public LLPanelRegionInfo ~LLPanelEstateCovenant() {} // LLPanel - virtual BOOL postBuild(); - virtual void updateChild(LLUICtrl* child_ctrl); - virtual bool refreshFromRegion(LLViewerRegion* region); - virtual bool estateUpdate(LLMessageSystem* msg); + BOOL postBuild() override; + void updateChild(LLUICtrl* child_ctrl) override; + bool refreshFromRegion(LLViewerRegion* region) override; + bool estateUpdate(LLMessageSystem* msg) override; // LLView overrides BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, void *cargo_data, EAcceptance *accept, - std::string& tooltip_msg); + std::string& tooltip_msg) override; static bool confirmChangeCovenantCallback(const LLSD& notification, const LLSD& response); static void resetCovenantID(void* userdata); static bool confirmResetCovenantCallback(const LLSD& notification, const LLSD& response); @@ -365,14 +361,13 @@ class LLPanelEstateCovenant : public LLPanelRegionInfo static void updateCovenantText(const std::string& string, const LLUUID& asset_id); static void updateEstateName(const std::string& name); static void updateLastModified(const std::string& text); - static void updateEstateOwnerName(const std::string& name); + static void updateEstateOwnerID(const LLUUID& id); const LLUUID& getCovenantID() const { return mCovenantID; } void setCovenantID(const LLUUID& id) { mCovenantID = id; } std::string getEstateName() const; void setEstateName(const std::string& name); std::string getOwnerName() const; - void setOwnerName(const std::string& name); void setCovenantTextEditor(const std::string& text); typedef enum e_asset_status @@ -384,7 +379,7 @@ class LLPanelEstateCovenant : public LLPanelRegionInfo } EAssetStatus; protected: - virtual BOOL sendUpdate(); + BOOL sendUpdate() override; LLTextBox* mEstateNameText; LLTextBox* mEstateOwnerText; LLTextBox* mLastModifiedText; @@ -404,19 +399,17 @@ class LLPanelEnvironmentInfo : public LLPanelRegionInfo LLPanelEnvironmentInfo(); // LLPanel - /*virtual*/ BOOL postBuild(); - - // LLPanelRegionInfo - /*virtual*/ void onOpen(const LLSD& key); + /*virtual*/ BOOL postBuild() override; + /*virtual*/ void onOpen(const LLSD& key) override; // LLView - /*virtual*/ void handleVisibilityChange(BOOL new_visibility); + /*virtual*/ void handleVisibilityChange(BOOL new_visibility) override; // LLPanelRegionInfo - /*virtual*/ bool refreshFromRegion(LLViewerRegion* region); + /*virtual*/ bool refreshFromRegion(LLViewerRegion* region) override; private: - void refresh(); + void refresh() override; void setControlsEnabled(bool enabled); void setApplyProgress(bool started); void setDirty(bool dirty); @@ -458,4 +451,102 @@ class LLPanelEnvironmentInfo : public LLPanelRegionInfo LLComboBox* mDayCyclePresetCombo; }; +class LLPanelRegionExperiences : public LLPanelRegionInfo +{ + LOG_CLASS(LLPanelEnvironmentInfo); + +public: + LLPanelRegionExperiences(); + /*virtual*/ BOOL postBuild() override; + BOOL sendUpdate() override; + + static bool experienceCoreConfirm(const LLSD& notification, const LLSD& response); + static void sendEstateExperienceDelta(U32 flags, const LLUUID& agent_id); + + static void infoCallback(LLHandle handle, const LLSD& content); + bool refreshFromRegion(LLViewerRegion* region) override; + void sendPurchaseRequest()const; + void processResponse( const LLSD& content ); +private: + void refreshRegionExperiences(); + + static std::string regionCapabilityQuery(LLViewerRegion* region, const std::string &cap); + + void setupList(LLPanelExperienceListEditor* child, const char* control_name, U32 add_id, U32 remove_id); + static LLSD addIds( LLPanelExperienceListEditor* panel ); + + void itemChanged(U32 event_type, const LLUUID& id); + + LLPanelExperienceListEditor* mTrusted; + LLPanelExperienceListEditor* mAllowed; + LLPanelExperienceListEditor* mBlocked; + LLUUID mDefaultExperience; +}; + + +class LLPanelEstateAccess : public LLPanelRegionInfo +{ + LOG_CLASS(LLPanelEnvironmentInfo); + +public: + LLPanelEstateAccess(); + + virtual BOOL postBuild(); + virtual void updateChild(LLUICtrl* child_ctrl); + + void updateControls(LLViewerRegion* region); + void updateLists(); + + void setPendingUpdate(bool pending) { mPendingUpdate = pending; } + bool getPendingUpdate() { return mPendingUpdate; } + + virtual bool refreshFromRegion(LLViewerRegion* region); + + static void onEstateAccessReceived(const LLSD& result); + +private: + void onClickAddAllowedAgent(); + void onClickRemoveAllowedAgent(); + void onClickCopyAllowedList(); + void onClickAddAllowedGroup(); + void onClickRemoveAllowedGroup(); + void onClickCopyAllowedGroupList(); + void onClickAddBannedAgent(); + void onClickRemoveBannedAgent(); + void onClickCopyBannedList(); + void onClickAddEstateManager(); + void onClickRemoveEstateManager(); + void onAllowedSearchEdit(const std::string& search_string); + void onAllowedGroupsSearchEdit(const std::string& search_string); + void onBannedSearchEdit(const std::string& search_string); + + // Group picker callback is different, can't use core methods below + bool addAllowedGroup(const LLSD& notification, const LLSD& response); + void addAllowedGroup2(LLUUID id); + + // Core methods for all above add/remove button clicks + static void accessAddCore(U32 operation_flag, const std::string& dialog_name); + static bool accessAddCore2(const LLSD& notification, const LLSD& response); + static void accessAddCore3(const uuid_vec_t& ids, const std::vector& names, LLEstateAccessChangeInfo* change_info); + + static void accessRemoveCore(U32 operation_flag, const std::string& dialog_name, const std::string& list_ctrl_name); + static bool accessRemoveCore2(const LLSD& notification, const LLSD& response); + + // used for both add and remove operations + static bool accessCoreConfirm(const LLSD& notification, const LLSD& response); + +public: + // Send the actual EstateOwnerRequest "estateaccessdelta" message + static void sendEstateAccessDelta(U32 flags, const LLUUID& agent_id); + +private: + //static void requestEstateGetAccessCoro(std::string url); + + void searchAgent(LLNameListCtrl* listCtrl, const std::string& search_string); + void copyListToClipboard(std::string list_name); + + bool mPendingUpdate; + bool mCtrlsEnabled; +}; + #endif diff --git a/indra/newview/llfloaterregionrestarting.cpp b/indra/newview/llfloaterregionrestarting.cpp new file mode 100644 index 0000000000..3064425e48 --- /dev/null +++ b/indra/newview/llfloaterregionrestarting.cpp @@ -0,0 +1,241 @@ +/** + * @file llfloaterregionrestarting.cpp + * @brief Shows countdown timer during region restart + * + * $LicenseInfo:firstyear=2006&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llfloaterregionrestarting.h" + +#include "lluictrlfactory.h" +#include "llagent.h" +#include "llagentcamera.h" +#include "llviewercontrol.h" +#include "llviewerwindow.h" + +// For emergency teleports +#include "llinventorymodel.h" +#include "lllandmarklist.h" +#include "llviewerregion.h" +#include "llworldmap.h" +void emergency_teleport(const U32& seconds) +{ + static const LLCachedControl time(gSavedSettings, "EmergencyTeleportSeconds"); + if (seconds > time) return; + + static const LLCachedControl landmark(gSavedPerAccountSettings, "EmergencyTeleportLandmark"); + if (landmark().empty()) return; + LLUUID id(landmark); + if (id.isNull()) return; + bool use_backup = false; + LLViewerInventoryItem* item = gInventory.getItem(id); + if (item) + { + if (LLLandmark* lm = gLandmarkList.getAsset(item->getAssetUUID())) + { + if (LLViewerRegion* region = gAgent.getRegion()) + use_backup = !lm->getRegionID(id) || id == region->getRegionID(); // LM's Region id null or same as current region + if (!use_backup) + { + LLVector3d pos_global; + if (lm->getGlobalPos(pos_global)) + { + if (LLSimInfo* sim_info = LLWorldMap::instance().simInfoFromPosGlobal(pos_global)) + { + use_backup = sim_info->isDown(); + } + } + else use_backup = true; // No coords, this will fail! + } + } + else use_backup = true; + } + else use_backup = true; + + if (use_backup) // Something is wrong with the first provided landmark, fallback. + { + static const LLCachedControl landmark(gSavedPerAccountSettings, "EmergencyTeleportLandmarkBackup"); + if (landmark().empty()) return; + if (!id.set(landmark)) return; + if (!(item = gInventory.getItem(id))) return; + } + + gAgent.teleportViaLandmark(item->getAssetUUID()); +} +// + +enum shake_state +{ + SHAKE_START, + SHAKE_LEFT, + SHAKE_UP, + SHAKE_RIGHT, + SHAKE_DOWN, + SHAKE_DONE +}; +static shake_state sShakeState; + +LLFloaterRegionRestarting::LLFloaterRegionRestarting(const LLSD& key) : + LLEventTimer(1) +, mRestartSeconds(NULL) +, mSeconds(key["SECONDS"].asInteger()) +, mName(key.has("NAME") ? key["NAME"].asString() : gAgent.getRegion()->getName()) // +, mShakeIterations() +, mShakeMagnitude() +{ + //buildFromFile("floater_region_restarting.xml"); + LLUICtrlFactory::getInstance()->buildFloater(this, "floater_region_restarting.xml"); + center(); + +} + +LLFloaterRegionRestarting::~LLFloaterRegionRestarting() +{ + if (sShakeState != SHAKE_DONE && sShakeState != SHAKE_START) // Finish shake if needed + { + gAgentCamera.resetView(TRUE, TRUE); + sShakeState = SHAKE_DONE; + } + mRegionChangedConnection.disconnect(); +} + +BOOL LLFloaterRegionRestarting::postBuild() +{ + mRegionChangedConnection = gAgent.addRegionChangedCallback(boost::bind(&LLFloaterRegionRestarting::regionChange, this)); + emergency_teleport(mSeconds); // For emergency teleports + + LLStringUtil::format_map_t args; + std::string text; + + args["[NAME]"] = mName; + text = getString("RegionName", args); + LLTextBox* textbox = getChild("region_name"); + textbox->setValue(text); + + mRestartSeconds = getChild("restart_seconds"); + + setBackgroundColor(gColors.getColor("NotifyCautionBoxColor")); + sShakeState = SHAKE_START; + + refresh(); + + return TRUE; +} + +void LLFloaterRegionRestarting::regionChange() +{ + close(); +} + +BOOL LLFloaterRegionRestarting::tick() +{ + refresh(); + + return FALSE; +} + +void LLFloaterRegionRestarting::refresh() +{ + LLStringUtil::format_map_t args; + args["[SECONDS]"] = llformat("%d", mSeconds); + mRestartSeconds->setValue(getString("RestartSeconds", args)); + + emergency_teleport(mSeconds); // For emergency teleports + if (!mSeconds) return; // Zero means we're done. + --mSeconds; +} + +void LLFloaterRegionRestarting::draw() +{ + LLFloater::draw(); + + static const LLCachedControl alchemyRegionShake(gSavedSettings, "AlchemyRegionRestartShake", true); + if (!alchemyRegionShake || isMinimized()) // If we're minimized, leave the user alone + return; + + const F32 SHAKE_INTERVAL = 0.025f; + const F32 SHAKE_TOTAL_DURATION = 1.8f; // the length of the default alert tone for this + const F32 SHAKE_INITIAL_MAGNITUDE = 1.5f; + const F32 SHAKE_HORIZONTAL_BIAS = 0.25f; + F32 time_shaking; + + if (SHAKE_START == sShakeState) + { + mShakeTimer.setTimerExpirySec(SHAKE_INTERVAL); + sShakeState = SHAKE_LEFT; + mShakeIterations = 0; + mShakeMagnitude = SHAKE_INITIAL_MAGNITUDE; + } + + if (SHAKE_DONE != sShakeState && mShakeTimer.hasExpired()) + { + gAgentCamera.unlockView(); + + switch(sShakeState) + { + case SHAKE_LEFT: + gAgentCamera.setPanLeftKey(mShakeMagnitude * SHAKE_HORIZONTAL_BIAS); + sShakeState = SHAKE_UP; + break; + + case SHAKE_UP: + gAgentCamera.setPanUpKey(mShakeMagnitude); + sShakeState = SHAKE_RIGHT; + break; + + case SHAKE_RIGHT: + gAgentCamera.setPanRightKey(mShakeMagnitude * SHAKE_HORIZONTAL_BIAS); + sShakeState = SHAKE_DOWN; + break; + + case SHAKE_DOWN: + gAgentCamera.setPanDownKey(mShakeMagnitude); + mShakeIterations++; + time_shaking = SHAKE_INTERVAL * (mShakeIterations * 4 /* left, up, right, down */); + if (SHAKE_TOTAL_DURATION <= time_shaking) + { + sShakeState = SHAKE_DONE; + mShakeMagnitude = 0.0; + } + else + { + sShakeState = SHAKE_LEFT; + F32 percent_done_shaking = (SHAKE_TOTAL_DURATION - time_shaking) / SHAKE_TOTAL_DURATION; + mShakeMagnitude = SHAKE_INITIAL_MAGNITUDE * (percent_done_shaking * percent_done_shaking); // exponential decay + } + break; + + default: + break; + } + mShakeTimer.setTimerExpirySec(SHAKE_INTERVAL); + } +} + +void LLFloaterRegionRestarting::updateTime(const U32& time) +{ + mSeconds = time; + emergency_teleport(mSeconds); // For emergency teleports + sShakeState = SHAKE_START; +} diff --git a/indra/newview/llfloaterregionrestarting.h b/indra/newview/llfloaterregionrestarting.h new file mode 100644 index 0000000000..663fe38091 --- /dev/null +++ b/indra/newview/llfloaterregionrestarting.h @@ -0,0 +1,60 @@ +/** + * @file llfloaterregionrestarting.h + * @brief Shows countdown timer during region restart + * + * $LicenseInfo:firstyear=2006&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLFLOATERREGIONRESTARTING_H +#define LL_LLFLOATERREGIONRESTARTING_H + +#include "llfloater.h" +#include "lleventtimer.h" + +class LLFloaterRegionRestarting : public LLFloater, public LLEventTimer +, public LLFloaterSingleton +{ + friend class LLFloaterReg; + +public: + void updateTime(const U32& time); + + LLFloaterRegionRestarting(const LLSD& key); +private: + virtual ~LLFloaterRegionRestarting(); + virtual BOOL postBuild(); + virtual BOOL tick(); + virtual void refresh(); + virtual void draw(); + virtual void regionChange(); + + class LLTextBox* mRestartSeconds; + U32 mSeconds; + std::string mName; + U32 mShakeIterations; + F32 mShakeMagnitude; + LLTimer mShakeTimer; + + boost::signals2::connection mRegionChangedConnection; +}; + +#endif // LL_LLFLOATERREGIONRESTARTING_H diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp index d41cbf17a4..a6c705ad81 100644 --- a/indra/newview/llfloaterreporter.cpp +++ b/indra/newview/llfloaterreporter.cpp @@ -43,6 +43,7 @@ #include "llfontgl.h" #include "llimagej2c.h" #include "llinventory.h" +#include "llmenugl.h" #include "llnotificationsutil.h" #include "llstring.h" #include "llsys.h" @@ -51,7 +52,6 @@ // viewer project includes #include "llagent.h" -#include "llagentui.h" #include "llbutton.h" #include "lltexturectrl.h" #include "llscrolllistctrl.h" @@ -74,18 +74,21 @@ #include "llfloateravatarpicker.h" #include "lldir.h" #include "llselectmgr.h" -#include "sgversion.h" +#include "llversioninfo.h" #include "lluictrlfactory.h" #include "llviewernetwork.h" #include "llassetuploadresponders.h" +#include "llagentui.h" #include "lltrans.h" +#include "llexperiencecache.h" -const U32 INCLUDE_SCREENSHOT = 0x01 << 0; +#include "llcororesponder.h" -class AIHTTPTimeoutPolicy; -extern AIHTTPTimeoutPolicy userReportResponder_timeout; +#include "rlvhandler.h" + +const U32 INCLUDE_SCREENSHOT = 0x01 << 0; //----------------------------------------------------------------------------- // Globals @@ -105,22 +108,12 @@ LLFloaterReporter::LLFloaterReporter() mPicking( FALSE), mPosition(), mCopyrightWarningSeen( FALSE ), - mResourceDatap(new LLResourceData()) + mResourceDatap(new LLResourceData()), + mAvatarNameCacheConnection() { LLUICtrlFactory::getInstance()->buildFloater(this, "floater_report_abuse.xml"); } -// static -void LLFloaterReporter::processRegionInfo(LLMessageSystem* msg) -{ - U32 region_flags; - msg->getU32("RegionInfo", "RegionFlags", region_flags); - - if (LLFloaterReporter::instanceExists() && LLFloaterReporter::getInstance()->getVisible()) - { - LLNotificationsUtil::add("HelpReportAbuseEmailLL"); - } -} // virtual BOOL LLFloaterReporter::postBuild() { @@ -147,13 +140,14 @@ BOOL LLFloaterReporter::postBuild() // Default text to be blank getChild("object_name")->setValue(LLStringUtil::null); - getChild("owner_name")->setValue(LLStringUtil::null); + getChild("owner_name")->setValue(LLUUID::null); mOwnerName = LLStringUtil::null; getChild("summary_edit")->setFocus(TRUE); mDefaultSummary = getChild("details_edit")->getValue().asString(); + /* Singu Note: We only used this to trigger the notification that's now below, there's no point to this anymore. // send a message and ask for information about this region - // result comes back in processRegionInfo(..) LLMessageSystem* msg = gMessageSystem; @@ -162,6 +156,8 @@ BOOL LLFloaterReporter::postBuild() msg->addUUID("AgentID", gAgent.getID()); msg->addUUID("SessionID", gAgent.getSessionID()); gAgent.sendReliableMessage(); + */ + LLNotificationsUtil::add("HelpReportAbuseEmailLL"); // abuser name is selected from a list @@ -173,22 +169,47 @@ BOOL LLFloaterReporter::postBuild() pick_btn->setImages(std::string("UIImgFaceUUID"), std::string("UIImgFaceSelectedUUID") ); childSetAction("pick_btn", onClickObjPicker, this); + childSetAction("select_abuser", boost::bind(&LLFloaterReporter::onClickSelectAbuser, this)); childSetAction("send_btn", onClickSend, this); childSetAction("cancel_btn", onClickCancel, this); + // grab the user's name - std::string reporter; - gAgent.buildFullname(reporter); - getChild("reporter_field")->setValue(reporter); + getChild("reporter_field")->setValue(gAgent.getID()); + + // request categories + if (gAgent.getRegion() + && gAgent.getRegion()->capabilitiesReceived()) + { + std::string cap_url = gAgent.getRegionCapability("AbuseCategories"); + + if (!cap_url.empty()) + { + std::string lang = gSavedSettings.getString("Language"); + if (lang != "default" && !lang.empty()) + { + cap_url += "?lc="; + cap_url += lang; + } + LLHTTPClient::get(cap_url, new LLCoroResponder( + boost::bind(LLFloaterReporter::requestAbuseCategoriesCoro, _1, cap_url, this->getHandle()))); + } + } center(); return TRUE; } + // virtual LLFloaterReporter::~LLFloaterReporter() { + if (mAvatarNameCacheConnection.connected()) + { + mAvatarNameCacheConnection.disconnect(); + } + // child views automatically deleted mObjectID = LLUUID::null; @@ -205,19 +226,10 @@ LLFloaterReporter::~LLFloaterReporter() delete mResourceDatap; } -// virtual -void LLFloaterReporter::draw() -{ - getChildView("screen_check")->setEnabled(TRUE ); - - LLFloater::draw(); -} - void LLFloaterReporter::enableControls(BOOL enable) { getChildView("category_combo")->setEnabled(enable); - getChildView("screen_check")->setEnabled(enable); - getChildView("screenshot")->setEnabled(false); + getChildView("screenshot")->setEnabled(FALSE); getChildView("pick_btn")->setEnabled(enable); getChildView("summary_edit")->setEnabled(enable); getChildView("details_edit")->setEnabled(enable); @@ -225,6 +237,30 @@ void LLFloaterReporter::enableControls(BOOL enable) getChildView("cancel_btn")->setEnabled(enable); } +void LLFloaterReporter::getExperienceInfo(const LLUUID& experience_id) +{ + mExperienceID = experience_id; + + if (LLUUID::null != mExperienceID) + { + const LLSD& experience = LLExperienceCache::instance().get(mExperienceID); + std::stringstream desc; + + if (experience.isDefined()) + { + setFromAvatarID(experience[LLExperienceCache::AGENT_ID]); + desc << "Experience id: " << mExperienceID; + } + else + { + desc << "Unable to retrieve details for id: "<< mExperienceID; + } + + LLUICtrl* details = getChild("details_edit"); + details->setValue(desc.str()); + } +} + void LLFloaterReporter::getObjectInfo(const LLUUID& object_id) { // TODO -- @@ -303,7 +339,10 @@ void LLFloaterReporter::callbackAvatarID(const uuid_vec_t& ids, const std::vecto { if (ids.empty() || names.empty()) return; - getChild("abuser_name_edit")->setValue(names[0].getCompleteName()); + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES) || gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS)) + getChild("abuser_name_edit")->setValue(RlvStrings::getString(RLV_STRING_HIDDEN)); + else + getChild("abuser_name_edit")->setValue(names[0].getCompleteName()); mAbuserID = ids[0]; @@ -314,28 +353,91 @@ void LLFloaterReporter::callbackAvatarID(const uuid_vec_t& ids, const std::vecto void LLFloaterReporter::setFromAvatarID(const LLUUID& avatar_id) { mAbuserID = mObjectID = avatar_id; - std::string avatar_link; + getChild("owner_name")->setValue(mObjectID); - if (LLAvatarNameCache::getPNSName(avatar_id, avatar_link)) + if (mAvatarNameCacheConnection.connected()) { - getChild("owner_name")->setValue(avatar_link); - getChild("object_name")->setValue(avatar_link); - getChild("abuser_name_edit")->setValue(avatar_link); - return; + mAvatarNameCacheConnection.disconnect(); } - - LLAvatarNameCache::get(avatar_id, boost::bind(&LLFloaterReporter::onAvatarNameCache, this, _1, _2)); + mAvatarNameCacheConnection = LLAvatarNameCache::get(avatar_id, boost::bind(&LLFloaterReporter::onAvatarNameCache, this, _1, _2)); } void LLFloaterReporter::onAvatarNameCache(const LLUUID& avatar_id, const LLAvatarName& av_name) { - std::string avatar_link; - LLAvatarNameCache::getPNSName(av_name, avatar_link); - getChild("owner_name")->setValue(avatar_link); - getChild("object_name")->setValue(avatar_link); - getChild("abuser_name_edit")->setValue(avatar_link); + mAvatarNameCacheConnection.disconnect(); + + if (mObjectID == avatar_id) + { + mOwnerName = av_name.getNSName(); + const std::string& name(((gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES) || gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS)) && RlvUtil::isNearbyAgent(avatar_id)) ? RlvStrings::getString(RLV_STRING_HIDDEN) : mOwnerName); + getChild("owner_name")->setValue(avatar_id); + getChild("object_name")->setValue(name); + getChild("abuser_name_edit")->setValue(name); + } } +void LLFloaterReporter::requestAbuseCategoriesCoro(const LLCoroResponder& responder, std::string url, LLHandle handle) +{ + LLSD result = responder.getContent(); + + if (!responder.isGoodStatus(responder.getStatus()) || !result.has("categories")) // success = httpResults["success"].asBoolean(); + { + LL_WARNS() << "Error requesting Abuse Categories from capability: " << url << LL_ENDL; + return; + } + + if (handle.isDead()) + { + // nothing to do + return; + } + + LLFloater* floater = handle.get(); + LLComboBox* combo = floater->getChild("category_combo"); + if (!combo) + { + LL_WARNS() << "categories category_combo not found!" << LL_ENDL; + return; + } + + //get selection (in case capability took a while) + S32 selection = combo->getCurrentIndex(); + + // Combobox should have a "Select category" element; + // This is a bit of workaround since there is no proper and simple way to save array of + // localizable strings in xml along with data (value). For now combobox is initialized along + // with placeholders, and first element is "Select category" which we want to keep, so remove + // everything but first element. + // Todo: once sim with capability fully releases, just remove this string and all unnecessary + // items from combobox since they will be obsolete (or depending on situation remake this to + // something better, for example move "Select category" to separate string) + while (combo->remove(1)); + + LLSD contents = result["categories"]; + + LLSD::array_iterator i = contents.beginArray(); + LLSD::array_iterator iEnd = contents.endArray(); + for (; i != iEnd; ++i) + { + const LLSD &message_data(*i); + std::string label = message_data["description_localized"]; + const auto& cat = message_data["category"]; + combo->add(label, cat); + switch(cat.asInteger()) + { + // Fraud + case 47: combo->add(floater->getString("Ridiculous3"), 1000); break; + // Harassment + case 51: combo->add(floater->getString("Ridiculous1"), 1000); break; + // Land > Encroachment + case 63: combo->add(floater->getString("Ridiculous2"), 1000); break; + default: break; + } + } + + //restore selection + combo->selectNthItem(selection); +} // static void LLFloaterReporter::onClickSend(void *userdata) @@ -389,19 +491,10 @@ void LLFloaterReporter::onClickSend(void *userdata) } else { - if(self->getChild("screen_check")->getValue()) - { - self->getChildView("send_btn")->setEnabled(FALSE); - self->getChildView("cancel_btn")->setEnabled(FALSE); - // the callback from uploading the image calls sendReportViaLegacy() - self->uploadImage(); - } - else - { - self->sendReportViaLegacy(self->gatherReport()); - LLUploadDialog::modalUploadFinished(); - self->close(); - } + self->getChildView("send_btn")->setEnabled(FALSE); + self->getChildView("cancel_btn")->setEnabled(FALSE); + // the callback from uploading the image calls sendReportViaLegacy() + self->uploadImage(); } } } @@ -431,7 +524,7 @@ void LLFloaterReporter::onClickObjPicker(void *userdata) LLToolMgr::getInstance()->setTransientTool(LLToolObjPicker::getInstance()); self->mPicking = TRUE; self->getChild("object_name")->setValue(LLStringUtil::null); - self->getChild("owner_name")->setValue(LLStringUtil::null); + self->getChild("owner_name")->setValue(LLUUID::null); self->mOwnerName = LLStringUtil::null; LLButton* pick_btn = self->getChild("pick_btn"); if (pick_btn) pick_btn->setToggleState(TRUE); @@ -458,10 +551,12 @@ void LLFloaterReporter::showFromMenu(EReportType report_type) { if (COMPLAINT_REPORT != report_type) { - llwarns << "Unknown LLViewerReporter type : " << report_type << llendl; + LL_WARNS() << "Unknown LLViewerReporter type : " << report_type << LL_ENDL; return; } + // Prevent menu from appearing in screen shot. + LLMenuGL::sMenuContainer->hideMenus(); LLFloaterReporter* f = getInstance(); if (f) { @@ -469,9 +564,8 @@ void LLFloaterReporter::showFromMenu(EReportType report_type) } } - // static -void LLFloaterReporter::show(const LLUUID& object_id, const std::string& avatar_name) +void LLFloaterReporter::show(const LLUUID& object_id, const std::string& avatar_name, const LLUUID& experience_id) { LLFloaterReporter* f = getInstance(); @@ -484,6 +578,23 @@ void LLFloaterReporter::show(const LLUUID& object_id, const std::string& avatar_ { f->setFromAvatarID(object_id); } + if (experience_id.notNull()) + { + f->getExperienceInfo(experience_id); + } + + // Need to deselect on close + f->mDeselectOnClose = TRUE; + + f->open(); /* Flawfinder: ignore */ +} + + + +void LLFloaterReporter::showFromExperience(const LLUUID& experience_id) +{ + LLFloaterReporter* f = getInstance(); + f->getExperienceInfo(experience_id); // Need to deselect on close f->mDeselectOnClose = TRUE; @@ -493,9 +604,9 @@ void LLFloaterReporter::show(const LLUUID& object_id, const std::string& avatar_ // static -void LLFloaterReporter::showFromObject(const LLUUID& object_id) +void LLFloaterReporter::showFromObject(const LLUUID& object_id, const LLUUID& experience_id) { - show(object_id); + show(object_id, LLStringUtil::null, experience_id); } // static @@ -509,8 +620,17 @@ void LLFloaterReporter::setPickedObjectProperties(const std::string& object_name getChild("object_name")->setValue(object_name); - getChild("owner_name")->setValue(owner_name); - getChild("abuser_name_edit")->setValue(owner_name); + if ((gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES) || gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS)) && RlvUtil::isNearbyAgent(owner_id)) + { + const std::string& rlv_hidden(RlvStrings::getString(RLV_STRING_HIDDEN)); + getChild("owner_name")->setValue(rlv_hidden); + getChild("abuser_name_edit")->setValue(rlv_hidden); + } + else + { + getChild("owner_name")->setValue(owner_id); + getChild("abuser_name_edit")->setValue(owner_name); + } mAbuserID = owner_id; mOwnerName = owner_name; } @@ -521,7 +641,7 @@ bool LLFloaterReporter::validateReport() // Ensure user selected a category from the list LLSD category_sd = getChild("category_combo")->getValue(); U8 category = (U8)category_sd.asInteger(); - if(category >= 100) //This is here for reasons (like shenanigans) + if(category == 1000) //This is here for reasons (like shenanigans) { LLNotificationsUtil::add("HelpReportNope"); return false; @@ -595,6 +715,7 @@ LLSD LLFloaterReporter::gatherReport() const char* platform = "Lnx"; #elif LL_SOLARIS const char* platform = "Sol"; + const char* short_platform = "O:S"; #else const char* platform = "???"; #endif @@ -611,10 +732,7 @@ LLSD LLFloaterReporter::gatherReport() std::ostringstream details; - details << "V" << gVersionMajor << "." // client version moved to body of email for abuse reports - << gVersionMinor << "." - << gVersionPatch << "." - << gVersionBuild << std::endl << std::endl; + details << 'V' << LLVersionInfo::getVersion() << "\n\n"; // client version moved to body of email for abuse reports std::string object_name = getChild("object_name")->getValue().asString(); if (!object_name.empty() && !mOwnerName.empty()) @@ -631,22 +749,16 @@ LLSD LLFloaterReporter::gatherReport() std::string version_string; version_string = llformat( - "%d.%d.%d %s %s %s %s", - gVersionMajor, - gVersionMinor, - gVersionPatch, + "%s %s %s %s %s", + LLVersionInfo::getShortVersion().c_str(), platform, gSysCPU.getFamily().c_str(), gGLManager.mGLRenderer.c_str(), gGLManager.mDriverVersionVendorString.c_str()); - // only send a screenshot ID if we're asked to and the email is + // only send a screenshot ID if we're asked to and the email is // going to LL - Estate Owners cannot see the screenshot asset - LLUUID screenshot_id = LLUUID::null; - if (getChild("screen_check")->getValue()) - { - screenshot_id = getChild("screenshot")->getValue(); - } + LLUUID screenshot_id = getChild("screenshot")->getValue().asUUID(); LLSD report = LLSD::emptyMap(); report["report-type"] = (U8) mReportType; @@ -692,7 +804,7 @@ void LLFloaterReporter::sendReportViaLegacy(const LLSD & report) msg->sendReliable(regionp->getHost()); } -class LLUserReportScreenshotResponder : public LLAssetUploadResponder +class LLUserReportScreenshotResponder final : public LLAssetUploadResponder { public: LLUserReportScreenshotResponder(const LLSD & post_data, @@ -712,31 +824,32 @@ class LLUserReportScreenshotResponder : public LLAssetUploadResponder LLUploadDialog::modalUploadFinished(); } - /*virtual*/ char const* getName(void) const { return "LLUserReportScreenshotResponder"; } + char const* getName() const override { return "LLUserReportScreenshotResponder"; } }; -class LLUserReportResponder : public LLHTTPClient::ResponderWithResult +class LLUserReportResponder final : public LLHTTPClient::ResponderWithCompleted { + LOG_CLASS(LLUserReportResponder); public: LLUserReportResponder() { } - /*virtual*/ void error(U32 status, const std::string& reason) - { - // *TODO do some user messaging here - LLUploadDialog::modalUploadFinished(); - } - /*virtual*/ void result(const LLSD& content) +private: + void httpCompleted() override { + if (!isGoodStatus(mStatus)) + { + // *TODO do some user messaging here + LL_WARNS("UserReport") << dumpResponse() << LL_ENDL; + } // we don't care about what the server returns LLUploadDialog::modalUploadFinished(); } - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return userReportResponder_timeout; } - /*virtual*/ char const* getName(void) const { return "LLUserReportResponder"; } + char const* getName() const override { return "LLUserReportResponder"; } }; void LLFloaterReporter::sendReportViaCaps(std::string url, std::string sshot_url, const LLSD& report) { - if(getChild("screen_check")->getValue().asBoolean() && !sshot_url.empty()) + if(!sshot_url.empty()) { // try to upload screenshot LLHTTPClient::post(sshot_url, report, new LLUserReportScreenshotResponder(report, @@ -759,7 +872,7 @@ void LLFloaterReporter::takeScreenshot() LLPointer raw = new LLImageRaw; if( !gViewerWindow->rawSnapshot(raw, IMAGE_WIDTH, IMAGE_HEIGHT, (F32)IMAGE_WIDTH / IMAGE_HEIGHT, TRUE, FALSE)) { - llwarns << "Unable to take screenshot" << llendl; + LL_WARNS() << "Unable to take screenshot" << LL_ENDL; return; } LLPointer upload_data = LLViewerTextureList::convertToUploadFile(raw); @@ -778,7 +891,7 @@ void LLFloaterReporter::takeScreenshot() } else { - llwarns << "Unknown LLFloaterReporter type" << llendl; + LL_WARNS() << "Unknown LLFloaterReporter type" << LL_ENDL; } mResourceDatap->mAssetInfo.mCreatorID = gAgentID; mResourceDatap->mAssetInfo.setName("screenshot_name"); @@ -793,11 +906,11 @@ void LLFloaterReporter::takeScreenshot() // store in the image list so it doesn't try to fetch from the server LLPointer image_in_list = - LLViewerTextureManager::getFetchedTexture(mResourceDatap->mAssetInfo.mUuid, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::FETCHED_TEXTURE); - image_in_list->createGLTexture(0, raw, 0, TRUE, LLViewerTexture::OTHER); + LLViewerTextureManager::getFetchedTexture(mResourceDatap->mAssetInfo.mUuid, FTT_LOCAL_FILE, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::FETCHED_TEXTURE); + image_in_list->createGLTexture(0, raw, nullptr, TRUE, LLViewerTexture::OTHER); // the texture picker then uses that texture - LLTexturePicker* texture = getChild("screenshot"); + LLTextureCtrl* texture = getChild("screenshot"); if (texture) { texture->setImageAssetID(mResourceDatap->mAssetInfo.mUuid); @@ -809,11 +922,11 @@ void LLFloaterReporter::takeScreenshot() void LLFloaterReporter::uploadImage() { - llinfos << "*** Uploading: " << llendl; - llinfos << "Type: " << LLAssetType::lookup(mResourceDatap->mAssetInfo.mType) << llendl; - llinfos << "UUID: " << mResourceDatap->mAssetInfo.mUuid << llendl; - llinfos << "Name: " << mResourceDatap->mAssetInfo.getName() << llendl; - llinfos << "Desc: " << mResourceDatap->mAssetInfo.getDescription() << llendl; + LL_INFOS() << "*** Uploading: " << LL_ENDL; + LL_INFOS() << "Type: " << LLAssetType::lookup(mResourceDatap->mAssetInfo.mType) << LL_ENDL; + LL_INFOS() << "UUID: " << mResourceDatap->mAssetInfo.mUuid << LL_ENDL; + LL_INFOS() << "Name: " << mResourceDatap->mAssetInfo.getName() << LL_ENDL; + LL_INFOS() << "Desc: " << mResourceDatap->mAssetInfo.getDescription() << LL_ENDL; gAssetStorage->storeAssetData(mResourceDatap->mAssetInfo.mTransactionID, mResourceDatap->mAssetInfo.mType, @@ -837,7 +950,7 @@ void LLFloaterReporter::uploadDoneCallback(const LLUUID &uuid, void *user_data, std::string err_msg("There was a problem uploading a report screenshot"); err_msg += " due to the following reason: " + args["REASON"].asString(); - llwarns << err_msg << llendl; + LL_WARNS() << err_msg << LL_ENDL; return; } @@ -848,14 +961,14 @@ void LLFloaterReporter::uploadDoneCallback(const LLUUID &uuid, void *user_data, } else { - llwarns << "Unknown report type : " << data->mPreferredLocation << llendl; + LL_WARNS() << "Unknown report type : " << data->mPreferredLocation << LL_ENDL; } LLFloaterReporter *self = getInstance(); if (self) { self->mScreenID = uuid; - llinfos << "Got screen shot " << uuid << llendl; + LL_INFOS() << "Got screen shot " << uuid << LL_ENDL; self->sendReportViaLegacy(self->gatherReport()); self->close(); } @@ -872,6 +985,7 @@ void LLFloaterReporter::setPosBox(const LLVector3d &pos) getChild("pos_field")->setValue(pos_string); } + //void LLFloaterReporter::setDescription(const std::string& description, LLMeanCollisionData *mcd) //{ // LLFloaterReporter *self = getInstance(); diff --git a/indra/newview/llfloaterreporter.h b/indra/newview/llfloaterreporter.h index 1b10ed6712..0cef2d4e8b 100644 --- a/indra/newview/llfloaterreporter.h +++ b/indra/newview/llfloaterreporter.h @@ -38,7 +38,6 @@ #include "v3math.h" class LLAvatarName; -class LLMessageSystem; class LLViewerTexture; class LLInventoryItem; class LLViewerObject; @@ -48,9 +47,9 @@ class LLMeanCollisionData; struct LLResourceData; // these flags are used to label info requests to the server -//const U32 BUG_REPORT_REQUEST = 0x01 << 0; // DEPRECATED -const U32 COMPLAINT_REPORT_REQUEST = 0x01 << 1; -const U32 OBJECT_PAY_REQUEST = 0x01 << 2; +//constexpr U32 BUG_REPORT_REQUEST = 0x01 << 0; // DEPRECATED +constexpr U32 COMPLAINT_REPORT_REQUEST = 0x01 << 1; +constexpr U32 OBJECT_PAY_REQUEST = 0x01 << 2; // ************************************************************ @@ -78,22 +77,22 @@ enum EReportType CS_REQUEST_REPORT = 4 }; -class LLFloaterReporter +class LLFloaterReporter final : public LLFloater, public LLSingleton { public: LLFloaterReporter(); /*virtual*/ ~LLFloaterReporter(); - /*virtual*/ BOOL postBuild(); - virtual void draw(); + /*virtual*/ BOOL postBuild() override; void setReportType(EReportType type) { mReportType = type; } // Enables all buttons static void showFromMenu(EReportType report_type); - static void showFromObject(const LLUUID& object_id); + static void showFromObject(const LLUUID& object_id, const LLUUID& experience_id = LLUUID::null); static void showFromAvatar(const LLUUID& avatar_id, const std::string avatar_name); + static void showFromExperience(const LLUUID& experience_id); static void onClickSend (void *userdata); static void onClickCancel (void *userdata); @@ -101,16 +100,13 @@ class LLFloaterReporter void onClickSelectAbuser (); static void closePickTool (void *userdata); static void uploadDoneCallback(const LLUUID &uuid, void* user_data, S32 result, LLExtStat ext_status); - static void addDescription(const std::string& description, LLMeanCollisionData *mcd = NULL); - static void setDescription(const std::string& description, LLMeanCollisionData *mcd = NULL); - - // static - static void processRegionInfo(LLMessageSystem* msg); + static void addDescription(const std::string& description, LLMeanCollisionData *mcd = nullptr); + static void setDescription(const std::string& description, LLMeanCollisionData *mcd = nullptr); void setPickedObjectProperties(const std::string& object_name, const std::string& owner_name, const LLUUID owner_id); private: - static void show(const LLUUID& object_id, const std::string& avatar_name = LLStringUtil::null); + static void show(const LLUUID& object_id, const std::string& avatar_name = LLStringUtil::null, const LLUUID& experience_id = LLUUID::null); void takeScreenshot(); void sendReportViaCaps(std::string url); @@ -122,16 +118,20 @@ class LLFloaterReporter void sendReportViaCaps(std::string url, std::string sshot_url, const LLSD & report); void setPosBox(const LLVector3d &pos); void enableControls(BOOL own_avatar); + void getExperienceInfo(const LLUUID& object_id); void getObjectInfo(const LLUUID& object_id); void callbackAvatarID(const uuid_vec_t& ids, const std::vector& names); void setFromAvatarID(const LLUUID& avatar_id); void onAvatarNameCache(const LLUUID& avatar_id, const LLAvatarName& av_name); + static void requestAbuseCategoriesCoro(const struct LLCoroResponder& responder, std::string url, LLHandle handle); + private: EReportType mReportType; LLUUID mObjectID; LLUUID mScreenID; LLUUID mAbuserID; + LLUUID mExperienceID; // Store the real name, not the link, for upstream reporting std::string mOwnerName; BOOL mDeselectOnClose; @@ -141,6 +141,7 @@ class LLFloaterReporter std::list mMCDList; std::string mDefaultSummary; LLResourceData* mResourceDatap; + boost::signals2::connection mAvatarNameCacheConnection; }; #endif diff --git a/indra/newview/llfloaterscriptdebug.cpp b/indra/newview/llfloaterscriptdebug.cpp index df9ff37eb1..e1209ccdf2 100644 --- a/indra/newview/llfloaterscriptdebug.cpp +++ b/indra/newview/llfloaterscriptdebug.cpp @@ -32,20 +32,16 @@ #include "llviewerprecompiledheaders.h" -#include "lluictrlfactory.h" #include "llfloaterscriptdebug.h" -#include "llfontgl.h" -#include "llrect.h" -#include "llerror.h" -#include "llstring.h" -#include "message.h" +#include "lluictrlfactory.h" // project include -#include "llviewertexteditor.h" -#include "llviewercontrol.h" +#include "llslurl.h" #include "llviewerobjectlist.h" -#include "llviewertexturelist.h" +#include "llviewerregion.h" +#include "llviewertexteditor.h" +#include "llvoavatarself.h" // // Statics @@ -122,31 +118,67 @@ LLFloater* LLFloaterScriptDebug::addOutputWindow(const LLUUID &object_id) return floaterp; } -void LLFloaterScriptDebug::addScriptLine(const std::string &utf8mesg, const std::string &user_name, const LLColor4& color, const LLUUID& source_id) +void LLFloaterScriptDebug::addScriptLine(LLChat& chat, const LLColor4& color) { + const auto& utf8mesg = chat.mText; + const auto& user_name = chat.mFromName; + const auto& source_id = chat.mFromID; + LLViewerObject* objectp = gObjectList.findObject(source_id); std::string floater_label; + // Handle /me messages. + std::string prefix = utf8mesg.substr(0, 4); + std::string message = (prefix == "/me " || prefix == "/me'") ? user_name + utf8mesg.substr(3) : utf8mesg; + + LLSD sdQuery = LLSD().with("name", user_name); if (objectp) { - objectp->setIcon(LLViewerTextureManager::getFetchedTextureFromFile("script_error.j2c", TRUE, LLGLTexture::BOOST_UI)); - floater_label = llformat("%s(%.2f, %.2f)", user_name.c_str(), objectp->getPositionRegion().mV[VX], objectp->getPositionRegion().mV[VY]); + if(objectp->isHUDAttachment()) + { + if (isAgentAvatarValid()) + { + ((LLViewerObject*)gAgentAvatarp)->setIcon(LLViewerTextureManager::getFetchedTextureFromFile("script_error.j2c", FTT_LOCAL_FILE, TRUE, LLGLTexture::BOOST_UI)); + } + } + else + { + objectp->setIcon(LLViewerTextureManager::getFetchedTextureFromFile("script_error.j2c", FTT_LOCAL_FILE, TRUE, LLGLTexture::BOOST_UI)); + } + + const auto& pos = objectp->getPositionRegion(); + sdQuery.with("owner", objectp->mOwnerID) + .with("groupowned", objectp->flagObjectGroupOwned()) + .with("slurl", LLSLURL(objectp->getRegion()->getName(), pos).getLocationString()); + + floater_label = llformat("%s(%.0f, %.0f, %.0f)", + user_name.c_str(), + pos.mV[VX], + pos.mV[VY], + pos.mV[VZ]); } else { floater_label = user_name; } + chat.mURL = LLSLURL("objectim", source_id, LLURI::mapToQueryString(sdQuery)).getSLURLString(); + addOutputWindow(LLUUID::null); addOutputWindow(source_id); // add to "All" floater - LLFloaterScriptDebugOutput* floaterp = LLFloaterScriptDebugOutput::getFloaterByID(LLUUID::null); - floaterp->addLine(utf8mesg, user_name, color); - + if (auto floaterp = LLFloaterScriptDebugOutput::getFloaterByID(LLUUID::null)) + { + floaterp->addLine(chat, message, color); + } + // add to specific script instance floater - floaterp = LLFloaterScriptDebugOutput::getFloaterByID(source_id); - floaterp->addLine(utf8mesg, floater_label, color); + if (auto floaterp = LLFloaterScriptDebugOutput::getFloaterByID(source_id)) + { + floaterp->setTitle(floater_label); // Update title + floaterp->addLine(chat, message, color); + } } // @@ -162,7 +194,8 @@ LLFloaterScriptDebugOutput::LLFloaterScriptDebugOutput() } LLFloaterScriptDebugOutput::LLFloaterScriptDebugOutput(const LLUUID& object_id) -: LLFloater(std::string("script instance floater"), LLRect(0, 200, 200, 0), std::string("Script"), TRUE), mObjectID(object_id) +: LLFloater(std::string("script instance floater"), LLRect(0, 200, 200, 0), std::string("Script"), TRUE), mObjectID(object_id), + mHistoryEditor(nullptr) { S32 y = getRect().getHeight() - LLFLOATER_HEADER_SIZE - LLFLOATER_VPAD; S32 x = LLFLOATER_HPAD; @@ -179,6 +212,7 @@ LLFloaterScriptDebugOutput::LLFloaterScriptDebugOutput(const LLUUID& object_id) mHistoryEditor->setFollowsAll(); mHistoryEditor->setEnabled( FALSE ); mHistoryEditor->setTabStop( TRUE ); // We want to be able to cut or copy from the history. + mHistoryEditor->setParseHTML(true); addChild(mHistoryEditor); } @@ -202,6 +236,7 @@ void LLFloaterScriptDebugOutput::initFloater(const std::string& title, BOOL resi mHistoryEditor->setFollowsAll(); mHistoryEditor->setEnabled( FALSE ); mHistoryEditor->setTabStop( TRUE ); // We want to be able to cut or copy from the history. + mHistoryEditor->setParseHTML(true); addChild(mHistoryEditor); } @@ -210,20 +245,15 @@ LLFloaterScriptDebugOutput::~LLFloaterScriptDebugOutput() sInstanceMap.erase(mObjectID); } -void LLFloaterScriptDebugOutput::addLine(const std::string &utf8mesg, const std::string &user_name, const LLColor4& color) +void LLFloaterScriptDebugOutput::addLine(const LLChat& chat, std::string message, const LLColor4& color) { - if (mObjectID.isNull()) - { - //setTitle("[All scripts]"); - setCanTearOff(FALSE); - setCanClose(FALSE); - } - else + if (!chat.mURL.empty()) { - setTitle(user_name); + message.erase(0, chat.mFromName.size()); + mHistoryEditor->appendText(chat.mURL, false, true); } - - mHistoryEditor->appendColoredText(utf8mesg, false, true, color); + LLStyleSP style(new LLStyle(true, color, LLStringUtil::null)); + mHistoryEditor->appendText(message, false, false, style, false); } //static @@ -236,6 +266,13 @@ LLFloaterScriptDebugOutput* LLFloaterScriptDebugOutput::show(const LLUUID& objec floaterp = new LLFloaterScriptDebugOutput(object_id); sInstanceMap[object_id] = floaterp; floaterp->open(); /* Flawfinder: ignore*/ + + if (object_id.isNull()) + { + //floaterp->setTitle("[All scripts]"); + floaterp->setCanTearOff(FALSE); + floaterp->setCanClose(FALSE); + } } else { diff --git a/indra/newview/llfloaterscriptdebug.h b/indra/newview/llfloaterscriptdebug.h index 0d5bc7411f..8e28ea33d0 100644 --- a/indra/newview/llfloaterscriptdebug.h +++ b/indra/newview/llfloaterscriptdebug.h @@ -35,6 +35,7 @@ #include "llmultifloater.h" +class LLChat; class LLTextEditor; class LLUUID; @@ -45,7 +46,7 @@ class LLFloaterScriptDebug : public LLMultiFloater virtual void onClose(bool app_quitting) { setVisible(FALSE); } virtual BOOL postBuild(); static void show(const LLUUID& object_id); - static void addScriptLine(const std::string &utf8mesg, const std::string &user_name, const LLColor4& color, const LLUUID& source_id); + static void addScriptLine(LLChat& chat, const LLColor4& color); protected: LLFloaterScriptDebug(); @@ -67,7 +68,7 @@ class LLFloaterScriptDebugOutput : public LLFloater S32 min_width, S32 min_height, BOOL drag_on_left, BOOL minimizable, BOOL close_btn); - void addLine(const std::string &utf8mesg, const std::string &user_name, const LLColor4& color); + void addLine(const LLChat& chat, std::string message, const LLColor4& color); static LLFloaterScriptDebugOutput* show(const LLUUID& object_id); static LLFloaterScriptDebugOutput* getFloaterByID(const LLUUID& id); diff --git a/indra/newview/llfloaterscriptlimits.cpp b/indra/newview/llfloaterscriptlimits.cpp index e7bf313127..2cd7af83f6 100644 --- a/indra/newview/llfloaterscriptlimits.cpp +++ b/indra/newview/llfloaterscriptlimits.cpp @@ -58,7 +58,7 @@ // debug switches, won't work in release #ifndef LL_RELEASE_FOR_DOWNLOAD -// dump responder replies to llinfos for debugging +// dump responder replies to LL_INFOS() for debugging //#define DUMP_REPLIES_TO_LLINFOS #ifdef DUMP_REPLIES_TO_LLINFOS @@ -84,6 +84,8 @@ const S32 SIZE_OF_ONE_KB = 1024; LLFloaterScriptLimits::LLFloaterScriptLimits(const LLSD& seed) : LLFloater(/*seed*/) + , mTab(nullptr) + , mInfoPanels() { LLUICtrlFactory::getInstance()->buildFloater(this, "floater_script_limits.xml"); } @@ -107,7 +109,7 @@ BOOL LLFloaterScriptLimits::postBuild() if(!mTab) { - llwarns << "Error! couldn't get scriptlimits_panels, aborting Script Information setup" << llendl; + LL_WARNS() << "Error! couldn't get scriptlimits_panels, aborting Script Information setup" << LL_ENDL; return FALSE; } @@ -184,8 +186,14 @@ void LLPanelScriptLimitsInfo::updateChild(LLUICtrl* child_ctr) // Responders ///---------------------------------------------------------------------------- -void fetchScriptLimitsRegionInfoResponder::result(const LLSD& content) +void fetchScriptLimitsRegionInfoResponder::httpSuccess() { + const LLSD& content = getContent(); + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR_OTHER, "Malformed response contents", content); + return; + } //we don't need to test with a fake response here (shouldn't anyway) #ifdef DUMP_REPLIES_TO_LLINFOS @@ -196,7 +204,7 @@ void fetchScriptLimitsRegionInfoResponder::result(const LLSD& content) OSMessageBox(nice_llsd.str(), "main cap response:", 0); - llinfos << "main cap response:" << content << llendl; + LL_INFOS() << "main cap response:" << content << LL_ENDL; #endif @@ -211,7 +219,7 @@ void fetchScriptLimitsRegionInfoResponder::result(const LLSD& content) LLFloaterScriptLimits* instance = LLFloaterScriptLimits::findInstance(); if(!instance) { - llwarns << "Failed to get llfloaterscriptlimits instance" << llendl; + LL_WARNS() << "Failed to get llfloaterscriptlimits instance" << LL_ENDL; } } @@ -222,13 +230,14 @@ void fetchScriptLimitsRegionInfoResponder::result(const LLSD& content) } } -void fetchScriptLimitsRegionInfoResponder::error(U32 status, const std::string& reason) +void fetchScriptLimitsRegionInfoResponder::httpFailure() { - llwarns << "fetchScriptLimitsRegionInfoResponder error [status:" << status << "]: " << reason << llendl; + LL_WARNS() << dumpResponse() << LL_ENDL; } -void fetchScriptLimitsRegionSummaryResponder::result(const LLSD& content_ref) +void fetchScriptLimitsRegionSummaryResponder::httpSuccess() { + const LLSD& content_ref = getContent(); #ifdef USE_FAKE_RESPONSES LLSD fake_content; @@ -269,6 +278,12 @@ void fetchScriptLimitsRegionSummaryResponder::result(const LLSD& content_ref) #endif + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR_OTHER, "Malformed response contents", content); + return; + } + #ifdef DUMP_REPLIES_TO_LLINFOS @@ -278,14 +293,14 @@ void fetchScriptLimitsRegionSummaryResponder::result(const LLSD& content_ref) OSMessageBox(nice_llsd.str(), "summary response:", 0); - llwarns << "summary response:" << *content << llendl; + LL_WARNS() << "summary response:" << *content << LL_ENDL; #endif LLFloaterScriptLimits* instance = LLFloaterScriptLimits::findInstance(); if(!instance) { - llwarns << "Failed to get llfloaterscriptlimits instance" << llendl; + LL_WARNS() << "Failed to get llfloaterscriptlimits instance" << LL_ENDL; } else { @@ -309,13 +324,14 @@ void fetchScriptLimitsRegionSummaryResponder::result(const LLSD& content_ref) } } -void fetchScriptLimitsRegionSummaryResponder::error(U32 status, const std::string& reason) +void fetchScriptLimitsRegionSummaryResponder::httpFailure() { - llwarns << "fetchScriptLimitsRegionSummaryResponder error [status:" << status << "]: " << reason << llendl; + LL_WARNS() << dumpResponse() << LL_ENDL; } -void fetchScriptLimitsRegionDetailsResponder::result(const LLSD& content_ref) +void fetchScriptLimitsRegionDetailsResponder::httpSuccess() { + const LLSD& content_ref = getContent(); #ifdef USE_FAKE_RESPONSES /* Updated detail service, ** denotes field added: @@ -378,6 +394,12 @@ result (map) #endif + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR_OTHER, "Malformed response contents", content); + return; + } + #ifdef DUMP_REPLIES_TO_LLINFOS LLSDNotationStreamer notation_streamer(content); @@ -386,7 +408,7 @@ result (map) OSMessageBox(nice_llsd.str(), "details response:", 0); - llinfos << "details response:" << content << llendl; + LL_INFOS() << "details response:" << content << LL_ENDL; #endif @@ -394,7 +416,7 @@ result (map) if(!instance) { - llwarns << "Failed to get llfloaterscriptlimits instance" << llendl; + LL_WARNS() << "Failed to get llfloaterscriptlimits instance" << LL_ENDL; } else { @@ -408,23 +430,24 @@ result (map) } else { - llwarns << "Failed to get scriptlimits memory panel" << llendl; + LL_WARNS() << "Failed to get scriptlimits memory panel" << LL_ENDL; } } else { - llwarns << "Failed to get scriptlimits_panels" << llendl; + LL_WARNS() << "Failed to get scriptlimits_panels" << LL_ENDL; } } } -void fetchScriptLimitsRegionDetailsResponder::error(U32 status, const std::string& reason) +void fetchScriptLimitsRegionDetailsResponder::httpFailure() { - llwarns << "fetchScriptLimitsRegionDetailsResponder error [status:" << status << "]: " << reason << llendl; + LL_WARNS() << dumpResponse() << LL_ENDL; } -void fetchScriptLimitsAttachmentInfoResponder::result(const LLSD& content_ref) +void fetchScriptLimitsAttachmentInfoResponder::httpSuccess() { + const LLSD& content_ref = getContent(); #ifdef USE_FAKE_RESPONSES @@ -466,6 +489,12 @@ void fetchScriptLimitsAttachmentInfoResponder::result(const LLSD& content_ref) #endif + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR_OTHER, "Malformed response contents", content); + return; + } + #ifdef DUMP_REPLIES_TO_LLINFOS LLSDNotationStreamer notation_streamer(content); @@ -474,7 +503,7 @@ void fetchScriptLimitsAttachmentInfoResponder::result(const LLSD& content_ref) OSMessageBox(nice_llsd.str(), "attachment response:", 0); - llinfos << "attachment response:" << content << llendl; + LL_INFOS() << "attachment response:" << content << LL_ENDL; #endif @@ -482,7 +511,7 @@ void fetchScriptLimitsAttachmentInfoResponder::result(const LLSD& content_ref) if(!instance) { - llwarns << "Failed to get llfloaterscriptlimits instance" << llendl; + LL_WARNS() << "Failed to get llfloaterscriptlimits instance" << LL_ENDL; } else { @@ -504,19 +533,19 @@ void fetchScriptLimitsAttachmentInfoResponder::result(const LLSD& content_ref) } else { - llwarns << "Failed to get script_limits_my_avatar_panel" << llendl; + LL_WARNS() << "Failed to get script_limits_my_avatar_panel" << LL_ENDL; } } else { - llwarns << "Failed to get scriptlimits_panels" << llendl; + LL_WARNS() << "Failed to get scriptlimits_panels" << LL_ENDL; } } } -void fetchScriptLimitsAttachmentInfoResponder::error(U32 status, const std::string& reason) +void fetchScriptLimitsAttachmentInfoResponder::httpFailure() { - llwarns << "fetchScriptLimitsAttachmentInfoResponder error [status:" << status << "]: " << reason << llendl; + LL_WARNS() << dumpResponse() << LL_ENDL; } ///---------------------------------------------------------------------------- @@ -589,7 +618,7 @@ void LLPanelScriptLimitsRegionMemory::setParcelID(const LLUUID& parcel_id) // virtual void LLPanelScriptLimitsRegionMemory::setErrorStatus(U32 status, const std::string& reason) { - llwarns << "Can't handle remote parcel request."<< " Http Status: "<< status << ". Reason : "<< reason<::iterator id_itor; for (id_itor = mObjectListItems.begin(); id_itor != mObjectListItems.end(); ++id_itor) @@ -629,7 +658,7 @@ void LLPanelScriptLimitsRegionMemory::setRegionDetails(LLSD content) if(!list) { - llwarns << "Error getting the scripts_list control" << llendl; + LL_WARNS() << "Error getting the scripts_list control" << LL_ENDL; return; } @@ -706,7 +735,7 @@ void LLPanelScriptLimitsRegionMemory::setRegionDetails(LLSD content) } else { - name_is_cached = LLAvatarNameCache::getPNSName(owner_id, owner_buf); // username + name_is_cached = LLAvatarNameCache::getNSName(owner_id, owner_buf); // username } if(!name_is_cached) { @@ -720,30 +749,43 @@ void LLPanelScriptLimitsRegionMemory::setRegionDetails(LLSD content) } } - LLSD item_params; - item_params["id"] = task_id; + LLScrollListItem::Params item_params; + item_params.value = task_id; - item_params["columns"][0]["column"] = "size"; - item_params["columns"][0]["value"] = size; + LLScrollListCell::Params cell_params; + //cell_params.font = LLFontGL::getFontSansSerif(); + // Start out right justifying numeric displays + cell_params.font_halign = LLFontGL::RIGHT; - item_params["columns"][1]["column"] = "urls"; - item_params["columns"][1]["value"] = urls; + cell_params.column = "size"; + cell_params.value = size; + item_params.columns.add(cell_params); - item_params["columns"][2]["column"] = "name"; - item_params["columns"][2]["value"] = name_buf; + cell_params.column = "urls"; + cell_params.value = urls; + item_params.columns.add(cell_params); - item_params["columns"][3]["column"] = "owner"; - item_params["columns"][3]["value"] = owner_buf; + cell_params.font_halign = LLFontGL::LEFT; + // The rest of the columns are text to left justify them + cell_params.column = "name"; + cell_params.value = name_buf; + item_params.columns.add(cell_params); - item_params["columns"][4]["column"] = "parcel"; - item_params["columns"][4]["value"] = parcel_name; + cell_params.column = "owner"; + cell_params.value = owner_buf; + item_params.columns.add(cell_params); - item_params["columns"][5]["column"] = "location"; - item_params["columns"][5]["value"] = has_locations + cell_params.column = "parcel"; + cell_params.value = parcel_name; + item_params.columns.add(cell_params); + + cell_params.column = "location"; + cell_params.value = has_locations ? llformat("<%0.1f,%0.1f,%0.1f>", location_x, location_y, location_z) : ""; + item_params.columns.add(cell_params); - list->addElement(item_params); + list->addRow(item_params); LLSD element; element["owner_id"] = owner_id; @@ -792,7 +834,7 @@ void LLPanelScriptLimitsRegionMemory::setRegionSummary(LLSD content) } else { - llwarns << "summary doesn't contain memory info" << llendl; + LL_WARNS() << "summary doesn't contain memory info" << LL_ENDL; return; } @@ -810,19 +852,26 @@ void LLPanelScriptLimitsRegionMemory::setRegionSummary(LLSD content) } else { - llwarns << "summary doesn't contain urls info" << llendl; + LL_WARNS() << "summary doesn't contain urls info" << LL_ENDL; return; } if((mParcelMemoryUsed >= 0) && (mParcelMemoryMax >= 0)) { - S32 parcel_memory_available = mParcelMemoryMax - mParcelMemoryUsed; - LLStringUtil::format_map_t args_parcel_memory; args_parcel_memory["[COUNT]"] = llformat ("%d", mParcelMemoryUsed); - args_parcel_memory["[MAX]"] = llformat ("%d", mParcelMemoryMax); - args_parcel_memory["[AVAILABLE]"] = llformat ("%d", parcel_memory_available); - std::string msg_parcel_memory = LLTrans::getString("ScriptLimitsMemoryUsed", args_parcel_memory); + std::string translate_message = "ScriptLimitsMemoryUsedSimple"; + + if (0 < mParcelMemoryMax) + { + S32 parcel_memory_available = mParcelMemoryMax - mParcelMemoryUsed; + + args_parcel_memory["[MAX]"] = llformat ("%d", mParcelMemoryMax); + args_parcel_memory["[AVAILABLE]"] = llformat ("%d", parcel_memory_available); + translate_message = "ScriptLimitsMemoryUsed"; + } + + std::string msg_parcel_memory = LLTrans::getString(translate_message, args_parcel_memory); getChild("memory_used")->setValue(LLSD(msg_parcel_memory)); } @@ -878,13 +927,17 @@ BOOL LLPanelScriptLimitsRegionMemory::StartRequestChain() } LLParcel* parcel = instance->getCurrentSelectedParcel(); LLViewerRegion* region = LLViewerParcelMgr::getInstance()->getSelectionRegion(); - if (!parcel) //Pretend we have the parcel we're on selected. + + LLUUID current_region_id = gAgent.getRegion()->getRegionID(); + + // Fall back to the parcel we're on if none is selected. + // Fixes parcel script info intermittently working and broken in toolbar button. + if (!parcel) { parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); region = gAgent.getRegion(); } - - LLUUID current_region_id = gAgent.getRegion()->getRegionID(); + // if ((region) && (parcel)) { @@ -919,9 +972,9 @@ BOOL LLPanelScriptLimitsRegionMemory::StartRequestChain() } else { - llwarns << "Can't get parcel info for script information request" << region_id + LL_WARNS() << "Can't get parcel info for script information request" << region_id << ". Region: " << region->getName() - << " does not support RemoteParcelRequest" << llendl; + << " does not support RemoteParcelRequest" << LL_ENDL; std::string msg_waiting = LLTrans::getString("ScriptLimitsRequestError"); getChild("loading_text")->setValue(LLSD(msg_waiting)); @@ -986,7 +1039,7 @@ void LLPanelScriptLimitsRegionMemory::onClickRefresh(void* userdata) } else { - llwarns << "could not find LLPanelScriptLimitsRegionMemory instance after refresh button clicked" << llendl; + LL_WARNS() << "could not find LLPanelScriptLimitsRegionMemory instance after refresh button clicked" << LL_ENDL; return; } } @@ -1032,7 +1085,7 @@ void LLPanelScriptLimitsRegionMemory::onClickHighlight(void* userdata) } else { - llwarns << "could not find LLPanelScriptLimitsRegionMemory instance after highlight button clicked" << llendl; + LL_WARNS() << "could not find LLPanelScriptLimitsRegionMemory instance after highlight button clicked" << LL_ENDL; return; } } @@ -1137,7 +1190,7 @@ void LLPanelScriptLimitsRegionMemory::onClickReturn(void* userdata) } else { - llwarns << "could not find LLPanelScriptLimitsRegionMemory instance after highlight button clicked" << llendl; + LL_WARNS() << "could not find LLPanelScriptLimitsRegionMemory instance after highlight button clicked" << LL_ENDL; return; } } @@ -1203,10 +1256,12 @@ void LLPanelScriptLimitsAttachment::setAttachmentDetails(LLSD content) element["columns"][0]["column"] = "size"; element["columns"][0]["value"] = llformat("%d", size); element["columns"][0]["font"] = "SANSSERIF"; + element["columns"][0]["halign"] = LLFontGL::RIGHT; element["columns"][1]["column"] = "urls"; element["columns"][1]["value"] = llformat("%d", urls); element["columns"][1]["font"] = "SANSSERIF"; + element["columns"][1]["halign"] = LLFontGL::RIGHT; element["columns"][2]["column"] = "name"; element["columns"][2]["value"] = name; @@ -1269,7 +1324,7 @@ void LLPanelScriptLimitsAttachment::setAttachmentSummary(LLSD content) } else { - llwarns << "attachment details don't contain memory summary info" << llendl; + LL_WARNS() << "attachment details don't contain memory summary info" << LL_ENDL; return; } @@ -1287,20 +1342,26 @@ void LLPanelScriptLimitsAttachment::setAttachmentSummary(LLSD content) } else { - llwarns << "attachment details don't contain urls summary info" << llendl; + LL_WARNS() << "attachment details don't contain urls summary info" << LL_ENDL; return; } if((mAttachmentMemoryUsed >= 0) && (mAttachmentMemoryMax >= 0)) { - S32 attachment_memory_available = mAttachmentMemoryMax - mAttachmentMemoryUsed; - LLStringUtil::format_map_t args_attachment_memory; args_attachment_memory["[COUNT]"] = llformat ("%d", mAttachmentMemoryUsed); - args_attachment_memory["[MAX]"] = llformat ("%d", mAttachmentMemoryMax); - args_attachment_memory["[AVAILABLE]"] = llformat ("%d", attachment_memory_available); - std::string msg_attachment_memory = LLTrans::getString("ScriptLimitsMemoryUsed", args_attachment_memory); - getChild("memory_used")->setValue(LLSD(msg_attachment_memory)); + std::string translate_message = "ScriptLimitsMemoryUsedSimple"; + + if (0 < mAttachmentMemoryMax) + { + S32 attachment_memory_available = mAttachmentMemoryMax - mAttachmentMemoryUsed; + + args_attachment_memory["[MAX]"] = llformat ("%d", mAttachmentMemoryMax); + args_attachment_memory["[AVAILABLE]"] = llformat ("%d", attachment_memory_available); + translate_message = "ScriptLimitsMemoryUsed"; + } + + getChild("memory_used")->setValue(LLTrans::getString(translate_message, args_attachment_memory)); } if((mAttachmentURLsUsed >= 0) && (mAttachmentURLsMax >= 0)) @@ -1339,7 +1400,7 @@ void LLPanelScriptLimitsAttachment::onClickRefresh(void* userdata) } else { - llwarns << "could not find LLPanelScriptLimitsRegionMemory instance after refresh button clicked" << llendl; + LL_WARNS() << "could not find LLPanelScriptLimitsRegionMemory instance after refresh button clicked" << LL_ENDL; return; } } diff --git a/indra/newview/llfloaterscriptlimits.h b/indra/newview/llfloaterscriptlimits.h index a31d49629e..bb2dd244ea 100644 --- a/indra/newview/llfloaterscriptlimits.h +++ b/indra/newview/llfloaterscriptlimits.h @@ -90,8 +90,8 @@ class fetchScriptLimitsRegionInfoResponder: public LLHTTPClient::ResponderWithRe public: fetchScriptLimitsRegionInfoResponder(const LLSD& info) : mInfo(info) {}; - void result(const LLSD& content); - void error(U32 status, const std::string& reason); + void httpSuccess(void); + void httpFailure(void); public: /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return fetchScriptLimitsRegionInfoResponder_timeout; } /*virtual*/ char const* getName(void) const { return "fetchScriptLimitsRegionInfoResponder"; } @@ -105,8 +105,8 @@ class fetchScriptLimitsRegionSummaryResponder: public LLHTTPClient::ResponderWit public: fetchScriptLimitsRegionSummaryResponder(const LLSD& info) : mInfo(info) {}; - void result(const LLSD& content); - void error(U32 status, const std::string& reason); + void httpSuccess(void); + void httpFailure(void); public: /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return fetchScriptLimitsRegionSummaryResponder_timeout; } /*virtual*/ char const* getName(void) const { return "fetchScriptLimitsRegionSummaryResponder"; } @@ -120,8 +120,8 @@ class fetchScriptLimitsRegionDetailsResponder: public LLHTTPClient::ResponderWit public: fetchScriptLimitsRegionDetailsResponder(const LLSD& info) : mInfo(info) {}; - void result(const LLSD& content); - void error(U32 status, const std::string& reason); + void httpSuccess(void); + void httpFailure(void); public: /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return fetchScriptLimitsRegionDetailsResponder_timeout; } /*virtual*/ char const* getName(void) const { return "fetchScriptLimitsRegionDetailsResponder"; } @@ -135,8 +135,8 @@ class fetchScriptLimitsAttachmentInfoResponder: public LLHTTPClient::ResponderWi public: fetchScriptLimitsAttachmentInfoResponder() {}; - void result(const LLSD& content); - void error(U32 status, const std::string& reason); + void httpSuccess(void); + void httpFailure(void); public: /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return fetchScriptLimitsAttachmentInfoResponder_timeout; } /*virtual*/ char const* getName(void) const { return "fetchScriptLimitsAttachmentInfoResponder"; } diff --git a/indra/newview/llfloatersearch.cpp b/indra/newview/llfloatersearch.cpp index b9cf179d27..f0fdc34445 100644 --- a/indra/newview/llfloatersearch.cpp +++ b/indra/newview/llfloatersearch.cpp @@ -113,20 +113,8 @@ LLFloaterSearch::_Params::_Params() } LLFloaterSearch::LLFloaterSearch(const Params& key) : - LLFloaterWebContent(key), - mSearchGodLevel(0) + LLFloaterWebContent(key) { - // declare a map that transforms a category name into - // the URL suffix that is used to search that category - mCategoryPaths = LLSD::emptyMap(); - mCategoryPaths["all"] = "search"; - mCategoryPaths["people"] = "search/people"; - mCategoryPaths["places"] = "search/places"; - mCategoryPaths["events"] = "search/events"; - mCategoryPaths["groups"] = "search/groups"; - mCategoryPaths["wiki"] = "search/wiki"; - mCategoryPaths["destinations"] = "destinations"; - mCategoryPaths["classifieds"] = "classifieds"; LLUICtrlFactory::getInstance()->buildFloater(this, "floater_web_content.xml"); } @@ -143,7 +131,8 @@ BOOL LLFloaterSearch::postBuild() getChildView("popexternal")->setEnabled(false); setRectControl("FloaterSearchRect"); applyRectControl(); - search(SearchQuery()); + search(SearchQuery(), mWebBrowser); + gSavedSettings.getControl("SearchURL")->getSignal()->connect(boost::bind(LLFloaterSearch::search, SearchQuery(), mWebBrowser)); return TRUE; } @@ -155,30 +144,11 @@ void LLFloaterSearch::showInstance(const SearchQuery& search, bool web) { LLFloaterSearch* floater = getInstance(); floater->open(); // May not be open - floater->search(search); + floater->search(search, floater->mWebBrowser); } else { - const std::string category(search.category()); - if (category.empty() || category == "all") - LLFloaterDirectory::showFindAll(search.query); - else if (category == "people") - LLFloaterDirectory::showPeople(search.query); - else if (category == "places") - LLFloaterDirectory::showPlaces(search.query); - else if (category == "events") - LLFloaterDirectory::showEvents(search.query); - else if (category == "groups") - LLFloaterDirectory::showGroups(search.query); - /* Singu TODO: Wiki tab in secondlife legacy search floater? - else if (category == "wiki") - LLFloaterDirectory::showWiki(search.query);*/ - else if (category == "destinations") - LLFloaterDirectory::showDestinations(); - else if (category == "classifieds") - LLFloaterDirectory::showClassified(search.query); - else - LLNotificationsUtil::add("UnsupportedCommandSLURL"); // Singu Note: Perhaps we should use a special notification here? + LLFloaterDirectory::search(search); } } @@ -189,7 +159,7 @@ void LLFloaterSearch::showInstance(const SearchQuery& search, bool web) p.allow_address_entry = false; LLFloaterWebContent::onOpen(p); - search(p.search); + search(p.search, mWebBrowser); }*/ void LLFloaterSearch::onClose(bool app_quitting) @@ -205,31 +175,30 @@ void LLFloaterSearch::onClose(bool app_quitting) destroy(); } -void LLFloaterSearch::godLevelChanged(U8 godlevel) -{ - // search results can change based upon god level - if the user - // changes god level, then give them a warning (we don't refresh - // the search as this might undo any page navigation or - // AJAX-driven changes since the last search). - - //FIXME: set status bar text - - //getChildView("refresh_search")->setVisible( (godlevel != mSearchGodLevel)); -} - -void LLFloaterSearch::search(const SearchQuery &p) +// static +void LLFloaterSearch::search(const SearchQuery &p, LLMediaCtrl* mWebBrowser) { if (! mWebBrowser || !p.validateBlock()) { return; } - // reset the god level warning as we're sending the latest state - //getChildView("refresh_search")->setVisible(FALSE); - mSearchGodLevel = gAgent.getGodLevel(); - // work out the subdir to use based on the requested category LLSD subs; + // declare a map that transforms a category name into + // the URL suffix that is used to search that category + static LLSD mCategoryPaths = LLSD::emptyMap(); + if (mCategoryPaths.size() == 0) + { + mCategoryPaths["all"] = "search"; + mCategoryPaths["people"] = "search/people"; + mCategoryPaths["places"] = "search/places"; + mCategoryPaths["events"] = "search/events"; + mCategoryPaths["groups"] = "search/groups"; + mCategoryPaths["wiki"] = "search/wiki"; + mCategoryPaths["destinations"] = "destinations"; + mCategoryPaths["classifieds"] = "classifieds"; + } if (mCategoryPaths.has(p.category)) { subs["CATEGORY"] = mCategoryPaths[p.category].asString(); diff --git a/indra/newview/llfloatersearch.h b/indra/newview/llfloatersearch.h index 8cba06a1e5..96fbd35c1f 100644 --- a/indra/newview/llfloatersearch.h +++ b/indra/newview/llfloatersearch.h @@ -79,18 +79,10 @@ class LLFloaterSearch : /// - "id": specifies the text phrase to search for /// - "category": one of "all" (default), "people", "places", /// "events", "groups", "wiki", "destinations", "classifieds" - void search(const SearchQuery &query); - - /// changing godmode can affect the search results that are - /// returned by the search website - use this method to tell the - /// search floater that the user has changed god level. - void godLevelChanged(U8 godlevel); + static void search(const SearchQuery& query, LLMediaCtrl* mWebBrowser); private: /*virtual*/ BOOL postBuild(); - - LLSD mCategoryPaths; - U8 mSearchGodLevel; }; #endif // LL_LLFLOATERSEARCH_H diff --git a/indra/newview/llfloatersettingsdebug.cpp b/indra/newview/llfloatersettingsdebug.cpp index a382c016c6..8d91be3706 100644 --- a/indra/newview/llfloatersettingsdebug.cpp +++ b/indra/newview/llfloatersettingsdebug.cpp @@ -35,26 +35,31 @@ #include "llfloatersettingsdebug.h" #include "llcolorswatch.h" -//#include "llfirstuse.h" #include "llfloater.h" #include "llscrolllistctrl.h" #include "llscrolllistitem.h" +#include "llsdserialize.h" #include "llspinctrl.h" #include "lltexteditor.h" #include "lluictrlfactory.h" #include "llviewercontrol.h" #include "llwindow.h" -// [RLVa:KB] - Checked: 2010-03-18 (RLVa-1.2.0a) -#include "rlvhandler.h" -#include "rlvextensions.h" -// [/RLVa:KB] - LLFloaterSettingsDebug::LLFloaterSettingsDebug() : LLFloater(std::string("Configuration Editor")) -, mCurrentControlVariable(NULL) -, mOldControlVariable(NULL) -, mOldSearchTerm(std::string("---")) +, mOldSearchTerm("---") +, mCurrentControlVariable(nullptr) +, mSettingsScrollList(nullptr) +, mValSpinner1(nullptr) +, mValSpinner2(nullptr) +, mValSpinner3(nullptr) +, mValSpinner4(nullptr) +, mValColor(nullptr) +, mValBool(nullptr) +, mValText(nullptr) +, mComment(nullptr) +, mBtnCopy(nullptr) +, mBtnDefault(nullptr) { mCommitCallbackRegistrar.add("SettingSelect", boost::bind(&LLFloaterSettingsDebug::onSettingSelect, this)); mCommitCallbackRegistrar.add("CommitSettings", boost::bind(&LLFloaterSettingsDebug::onCommitSettings, this)); @@ -67,19 +72,20 @@ LLFloaterSettingsDebug::LLFloaterSettingsDebug() LLFloaterSettingsDebug::~LLFloaterSettingsDebug() { - if (mOldControlVariable) - mOldControlVariable->getCommitSignal()->disconnect(boost::bind(&LLFloaterSettingsDebug::onSettingSelect, this)); + if (mCurrentControlVariable) + mCurrentControlVariable->getCommitSignal()->disconnect(boost::bind(&LLFloaterSettingsDebug::updateControl, this)); } BOOL LLFloaterSettingsDebug::postBuild() { mSettingsScrollList = getChild("settings_scroll_list"); - struct f : public LLControlGroup::ApplyFunctor + struct f final : public LLControlGroup::ApplyFunctor { settings_map_t* map; f(settings_map_t* m) : map(m) {} - virtual void apply(const std::string& name, LLControlVariable* control) + + void apply(const std::string& name, LLControlVariable* control) override final { if (!control->isHiddenFromSettingsEditor()) { @@ -93,26 +99,30 @@ BOOL LLFloaterSettingsDebug::postBuild() gColors.applyToAll(&func); // Populate the list - { - for(settings_map_t::iterator it = mSettingsMap.begin(); it != mSettingsMap.end(); it++) - { - LLSD item; - item["columns"][0]["value"] = it->second->getName(); - mSettingsScrollList->addElement(item, ADD_BOTTOM, it->second); - } - } - mSettingsScrollList->sortByColumnIndex(0, true); - - llinfos << mSettingsScrollList->getItemCount() << " total debug settings displayed." << llendl; + for(const auto& pair : mSettingsMap) + addRow(pair.second); + mSettingsScrollList->sortByColumnIndex(0, true); mComment = getChild("comment_text"); + mValSpinner1 = getChild("val_spinner_1"); + mValSpinner2 = getChild("val_spinner_2"); + mValSpinner3 = getChild("val_spinner_3"); + mValSpinner4 = getChild("val_spinner_4"); + mValColor = getChild("val_color_swatch"); + mValBool = getChild("boolean_combo"); + mValText = getChild("val_text"); + mBtnCopy = getChildView("copy_btn"); + mBtnDefault = getChildView("default_btn"); + + LL_INFOS() << mSettingsScrollList->getItemCount() << " total debug settings displayed." << LL_ENDL; + return TRUE; } void LLFloaterSettingsDebug::draw() { // check for changes in control visibility, like RLVa does - if(mCurrentControlVariable && mCurrentControlVariable->isHiddenFromSettingsEditor() != mOldVisibility) + if (mCurrentControlVariable && mCurrentControlVariable->isHiddenFromSettingsEditor() != mOldVisibility) updateControl(); LLFloater::draw(); @@ -121,36 +131,66 @@ void LLFloaterSettingsDebug::draw() LLControlVariable* LLFloaterSettingsDebug::getControlVariable() { LLScrollListItem* item = mSettingsScrollList->getFirstSelected(); - if (!item) return NULL; + if (!item) return nullptr; LLControlVariable* controlp = static_cast(item->getUserdata()); - return controlp ? controlp->getCOAActive() : NULL; + return controlp ? controlp->getCOAActive() : nullptr; +} + +void LLFloaterSettingsDebug::addRow(LLControlVariable* control, const std::string& searchTerm) +{ + const auto& name = control->getName(); + const auto& comment = control->getComment(); + + if (!searchTerm.empty()) + { + std::string itemValue = control->getName(); + LLStringUtil::toLower(itemValue); + if (itemValue.find(searchTerm, 0) == std::string::npos) + { + std::string itemComment = control->getComment(); + LLStringUtil::toLower(itemComment); + if (itemComment.find(searchTerm, 0) == std::string::npos) + return; + } + } + + auto params = LLScrollListItem::Params(); + params.userdata(control) + .columns.add(LLScrollListCell::Params() + .value(name) + .tool_tip(comment)); + mSettingsScrollList->addRow(params); } void LLFloaterSettingsDebug::onSettingSelect() { - mCurrentControlVariable = getControlVariable(); + auto new_control = getControlVariable(); - if (mOldControlVariable == mCurrentControlVariable) return; + if (new_control == mCurrentControlVariable) return; // unbind change control signal from previously selected control - if(mOldControlVariable) - mOldControlVariable->getCommitSignal()->disconnect(boost::bind(&LLFloaterSettingsDebug::onSettingSelect, this)); + if (mCurrentControlVariable) + mCurrentControlVariable->getCommitSignal()->disconnect(boost::bind(&LLFloaterSettingsDebug::updateControl, this)); - // bind change control signal, so we can see updates to the current control in realtime - if(mCurrentControlVariable) - mCurrentControlVariable->getCommitSignal()->connect(boost::bind(&LLFloaterSettingsDebug::onSettingSelect, this)); + mCurrentControlVariable = new_control; - mOldControlVariable = mCurrentControlVariable; + // bind change control signal, so we can see updates to the current control in realtime + if (mCurrentControlVariable) + mCurrentControlVariable->getCommitSignal()->connect(boost::bind(&LLFloaterSettingsDebug::updateControl, this)); updateControl(); } void LLFloaterSettingsDebug::onCommitSettings() { - if (!mCurrentControlVariable) + LLControlVariable* controlp = mCurrentControlVariable; + + if (!controlp) + { return; + } LLVector3 vector; LLVector3d vectord; @@ -160,60 +200,73 @@ void LLFloaterSettingsDebug::onCommitSettings() LLColor4U col4U; LLColor4 color_with_alpha; - switch(mCurrentControlVariable->type()) + switch(controlp->type()) { case TYPE_U32: - mCurrentControlVariable->set(getChild("val_spinner_1")->getValue()); + controlp->set(mValSpinner1->getValue()); break; case TYPE_S32: - mCurrentControlVariable->set(getChild("val_spinner_1")->getValue()); + controlp->set(mValSpinner1->getValue()); break; case TYPE_F32: - mCurrentControlVariable->set(LLSD(getChild("val_spinner_1")->getValue().asReal())); + controlp->set(LLSD(mValSpinner1->getValue().asReal())); break; case TYPE_BOOLEAN: - mCurrentControlVariable->set(getChild("boolean_combo")->getValue()); + controlp->set(mValBool->getValue()); break; case TYPE_STRING: - mCurrentControlVariable->set(LLSD(getChild("val_text")->getValue().asString())); + controlp->set(mValText->getValue()); break; case TYPE_VEC3: - vector.mV[VX] = (F32)getChild("val_spinner_1")->getValue().asReal(); - vector.mV[VY] = (F32)getChild("val_spinner_2")->getValue().asReal(); - vector.mV[VZ] = (F32)getChild("val_spinner_3")->getValue().asReal(); - mCurrentControlVariable->set(vector.getValue()); + vector.mV[VX] = (F32)mValSpinner1->getValue().asReal(); + vector.mV[VY] = (F32)mValSpinner2->getValue().asReal(); + vector.mV[VZ] = (F32)mValSpinner3->getValue().asReal(); + controlp->set(vector.getValue()); break; case TYPE_VEC3D: - vectord.mdV[VX] = getChild("val_spinner_1")->getValue().asReal(); - vectord.mdV[VY] = getChild("val_spinner_2")->getValue().asReal(); - vectord.mdV[VZ] = getChild("val_spinner_3")->getValue().asReal(); - mCurrentControlVariable->set(vectord.getValue()); + vectord.mdV[VX] = mValSpinner1->getValue().asReal(); + vectord.mdV[VY] = mValSpinner2->getValue().asReal(); + vectord.mdV[VZ] = mValSpinner3->getValue().asReal(); + controlp->set(vectord.getValue()); break; case TYPE_RECT: - rect.mLeft = getChild("val_spinner_1")->getValue().asInteger(); - rect.mRight = getChild("val_spinner_2")->getValue().asInteger(); - rect.mBottom = getChild("val_spinner_3")->getValue().asInteger(); - rect.mTop = getChild("val_spinner_4")->getValue().asInteger(); - mCurrentControlVariable->set(rect.getValue()); + rect.mLeft = mValSpinner1->getValue().asInteger(); + rect.mRight = mValSpinner2->getValue().asInteger(); + rect.mBottom = mValSpinner3->getValue().asInteger(); + rect.mTop = mValSpinner4->getValue().asInteger(); + controlp->set(rect.getValue()); break; case TYPE_COL4: - col3.setValue(getChild("val_color_swatch")->getValue()); - col4 = LLColor4(col3, (F32)getChild("val_spinner_4")->getValue().asReal()); - mCurrentControlVariable->set(col4.getValue()); + col3.setValue(mValColor->getValue()); + col4 = LLColor4(col3, (F32)mValSpinner4->getValue().asReal()); + controlp->set(col4.getValue()); break; case TYPE_COL3: - mCurrentControlVariable->set(getChild("val_color_swatch")->getValue()); - //col3.mV[VRED] = (F32)getChild("val_spinner_1")->getValue().asC(); - //col3.mV[VGREEN] = (F32)getChild("val_spinner_2")->getValue().asReal(); - //col3.mV[VBLUE] = (F32)getChild("val_spinner_3")->getValue().asReal(); + controlp->set(mValColor->getValue()); + //col3.mV[VRED] = (F32)mValSpinner1->getValue().asReal(); + //col3.mV[VGREEN] = (F32)mValSpinner2->getValue().asReal(); + //col3.mV[VBLUE] = (F32)mValSpinner3->getValue().asReal(); //mCurrentControlVariable->set(col3.getValue()); break; case TYPE_COL4U: - col3.setValue(getChild("val_color_swatch")->getValue()); + col3.setValue(mValColor->getValue()); col4U.setVecScaleClamp(col3); - col4U.mV[VALPHA] = getChild("val_spinner_4")->getValue().asInteger(); + col4U.mV[VALPHA] = mValSpinner4->getValue().asInteger(); mCurrentControlVariable->set(col4U.getValue()); break; + case TYPE_LLSD: + { + const auto& val = mValText->getValue().asString(); + LLSD sd; + if (!val.empty()) + { + std::istringstream str(val); + if (LLSDSerialize::fromXML(sd, str) == LLSDParser::PARSE_FAILURE) + break; + } + mCurrentControlVariable->set(sd); + break; + } default: break; } @@ -231,164 +284,156 @@ void LLFloaterSettingsDebug::onClickDefault() void LLFloaterSettingsDebug::onCopyToClipboard() { if (mCurrentControlVariable) + { getWindow()->copyTextToClipboard(utf8str_to_wstring(mCurrentControlVariable->getName())); + } } -// we've switched controls, so update spinners, etc. +// we've switched controls, or doing per-frame update, so update spinners, etc. void LLFloaterSettingsDebug::updateControl() { - LLSpinCtrl* spinner1 = getChild("val_spinner_1"); - LLSpinCtrl* spinner2 = getChild("val_spinner_2"); - LLSpinCtrl* spinner3 = getChild("val_spinner_3"); - LLSpinCtrl* spinner4 = getChild("val_spinner_4"); - LLColorSwatchCtrl* color_swatch = getChild("val_color_swatch"); - LLUICtrl* bool_ctrl = getChild("boolean_combo"); - - if (!spinner1 || !spinner2 || !spinner3 || !spinner4 || !color_swatch) + if (!mValSpinner1 || !mValSpinner2 || !mValSpinner3 || !mValSpinner4 || !mValColor) { - llwarns << "Could not find all desired controls by name" - << llendl; + LL_WARNS() << "Could not find all desired controls by name" + << LL_ENDL; return; } - spinner1->setVisible(FALSE); - spinner2->setVisible(FALSE); - spinner3->setVisible(FALSE); - spinner4->setVisible(FALSE); - color_swatch->setVisible(FALSE); - getChildView("val_text")->setVisible( FALSE); - mComment->setText(LLStringUtil::null); - childSetEnabled("copy_btn", false); - childSetEnabled("default_btn", false); - bool_ctrl->setVisible(false); + mValSpinner1->setVisible(FALSE); + mValSpinner2->setVisible(FALSE); + mValSpinner3->setVisible(FALSE); + mValSpinner4->setVisible(FALSE); + mValColor->setVisible(FALSE); + mValText->setVisible(FALSE); + if (!mComment->hasFocus()) // + { + mComment->setText(LLStringUtil::null); + } + mValBool->setVisible(false); + mBtnCopy->setEnabled(false); + mBtnDefault->setEnabled(false); if (mCurrentControlVariable) { // [RLVa:KB] - Checked: 2011-05-28 (RLVa-1.4.0a) | Modified: RLVa-1.4.0a // If "HideFromEditor" was toggled while the floater is open then we need to manually disable access to the control mOldVisibility = mCurrentControlVariable->isHiddenFromSettingsEditor(); - spinner1->setEnabled(!mOldVisibility); - spinner2->setEnabled(!mOldVisibility); - spinner3->setEnabled(!mOldVisibility); - spinner4->setEnabled(!mOldVisibility); - color_swatch->setEnabled(!mOldVisibility); - childSetEnabled("val_text", !mOldVisibility); - bool_ctrl->setEnabled(!mOldVisibility); - childSetEnabled("default_btn", !mOldVisibility); + mValSpinner1->setEnabled(!mOldVisibility); + mValSpinner2->setEnabled(!mOldVisibility); + mValSpinner3->setEnabled(!mOldVisibility); + mValSpinner4->setEnabled(!mOldVisibility); + mValColor->setEnabled(!mOldVisibility); + mValText->setEnabled(!mOldVisibility); + mValBool->setEnabled(!mOldVisibility); + mBtnDefault->setEnabled(!mOldVisibility); // [/RLVa:KB] - childSetEnabled("copy_btn", true); + mBtnCopy->setEnabled(true); eControlType type = mCurrentControlVariable->type(); - - mComment->setText(mCurrentControlVariable->getName() + std::string(": ") + mCurrentControlVariable->getComment()); - - spinner1->setMaxValue(F32_MAX); - spinner2->setMaxValue(F32_MAX); - spinner3->setMaxValue(F32_MAX); - spinner4->setMaxValue(F32_MAX); - spinner1->setMinValue(-F32_MAX); - spinner2->setMinValue(-F32_MAX); - spinner3->setMinValue(-F32_MAX); - spinner4->setMinValue(-F32_MAX); - if (!spinner1->hasFocus()) + if (!mComment->hasFocus()) // { - spinner1->setIncrement(0.1f); + mComment->setText(mCurrentControlVariable->getName() + std::string(": ") + mCurrentControlVariable->getComment()); } - if (!spinner2->hasFocus()) + mValSpinner1->setMaxValue(F32_MAX); + mValSpinner2->setMaxValue(F32_MAX); + mValSpinner3->setMaxValue(F32_MAX); + mValSpinner4->setMaxValue(F32_MAX); + mValSpinner1->setMinValue(-F32_MAX); + mValSpinner2->setMinValue(-F32_MAX); + mValSpinner3->setMinValue(-F32_MAX); + mValSpinner4->setMinValue(-F32_MAX); + if (!mValSpinner1->hasFocus()) { - spinner2->setIncrement(0.1f); + mValSpinner1->setIncrement(0.1f); } - if (!spinner3->hasFocus()) + if (!mValSpinner2->hasFocus()) { - spinner3->setIncrement(0.1f); + mValSpinner2->setIncrement(0.1f); } - if (!spinner4->hasFocus()) + if (!mValSpinner3->hasFocus()) { - spinner4->setIncrement(0.1f); + mValSpinner3->setIncrement(0.1f); + } + if (!mValSpinner4->hasFocus()) + { + mValSpinner4->setIncrement(0.1f); } LLSD sd = mCurrentControlVariable->get(); switch(type) { case TYPE_U32: - spinner1->setVisible(TRUE); - spinner1->setLabel(std::string("value")); // Debug, don't translate - if (!spinner1->hasFocus()) + mValSpinner1->setVisible(TRUE); + mValSpinner1->setLabel(LLStringExplicit("value")); // Debug, don't translate + if (!mValSpinner1->hasFocus()) { - spinner1->setValue(sd); - spinner1->setMinValue((F32)U32_MIN); - spinner1->setMaxValue((F32)U32_MAX); - spinner1->setIncrement(1.f); - spinner1->setPrecision(0); + mValSpinner1->setValue(sd); + mValSpinner1->setMinValue((F32)U32_MIN); + mValSpinner1->setMaxValue((F32)U32_MAX); + mValSpinner1->setIncrement(1.f); + mValSpinner1->setPrecision(0); } break; case TYPE_S32: - spinner1->setVisible(TRUE); - spinner1->setLabel(std::string("value")); // Debug, don't translate - if (!spinner1->hasFocus()) + mValSpinner1->setVisible(TRUE); + mValSpinner1->setLabel(LLStringExplicit("value")); // Debug, don't translate + if (!mValSpinner1->hasFocus()) { - spinner1->setValue(sd); - spinner1->setMinValue((F32)S32_MIN); - spinner1->setMaxValue((F32)S32_MAX); - spinner1->setIncrement(1.f); - spinner1->setPrecision(0); + mValSpinner1->setValue(sd); + mValSpinner1->setMinValue((F32)S32_MIN); + mValSpinner1->setMaxValue((F32)S32_MAX); + mValSpinner1->setIncrement(1.f); + mValSpinner1->setPrecision(0); } break; case TYPE_F32: - spinner1->setVisible(TRUE); - spinner1->setLabel(std::string("value")); // Debug, don't translate - if (!spinner1->hasFocus()) + mValSpinner1->setVisible(TRUE); + mValSpinner1->setLabel(LLStringExplicit("value")); // Debug, don't translate + if (!mValSpinner1->hasFocus()) { - spinner1->setPrecision(3); - spinner1->setValue(sd); + mValSpinner1->setPrecision(3); + mValSpinner1->setValue(sd); } break; case TYPE_BOOLEAN: - bool_ctrl->setVisible(true); - if (!bool_ctrl->hasFocus()) + mValBool->setVisible(true); + if (!mValBool->hasFocus()) { - if (sd.asBoolean()) - { - bool_ctrl->setValue(LLSD("TRUE")); - } - else - { - bool_ctrl->setValue(LLSD("FALSE")); - } + mValBool->setValue(LLSD(sd.asBoolean() ? "TRUE" : "FALSE")); } break; case TYPE_STRING: - getChildView("val_text")->setVisible( TRUE); - if (!getChild("val_text")->hasFocus()) + mValText->setVisible(TRUE); + if (!mValText->hasFocus()) { - getChild("val_text")->setValue(sd); + mValText->setValue(sd); } break; case TYPE_VEC3: { LLVector3 v; v.setValue(sd); - spinner1->setVisible(TRUE); - spinner1->setLabel(std::string("X")); - spinner2->setVisible(TRUE); - spinner2->setLabel(std::string("Y")); - spinner3->setVisible(TRUE); - spinner3->setLabel(std::string("Z")); - if (!spinner1->hasFocus()) + mValSpinner1->setVisible(TRUE); + mValSpinner1->setLabel(LLStringExplicit("X")); + mValSpinner2->setVisible(TRUE); + mValSpinner2->setLabel(LLStringExplicit("Y")); + mValSpinner3->setVisible(TRUE); + mValSpinner3->setLabel(LLStringExplicit("Z")); + if (!mValSpinner1->hasFocus()) { - spinner1->setPrecision(3); - spinner1->setValue(v[VX]); + mValSpinner1->setPrecision(3); + mValSpinner1->setValue(v[VX]); } - if (!spinner2->hasFocus()) + if (!mValSpinner2->hasFocus()) { - spinner2->setPrecision(3); - spinner2->setValue(v[VY]); + mValSpinner2->setPrecision(3); + mValSpinner2->setValue(v[VY]); } - if (!spinner3->hasFocus()) + if (!mValSpinner3->hasFocus()) { - spinner3->setPrecision(3); - spinner3->setValue(v[VZ]); + mValSpinner3->setPrecision(3); + mValSpinner3->setValue(v[VZ]); } break; } @@ -396,26 +441,26 @@ void LLFloaterSettingsDebug::updateControl() { LLVector3d v; v.setValue(sd); - spinner1->setVisible(TRUE); - spinner1->setLabel(std::string("X")); - spinner2->setVisible(TRUE); - spinner2->setLabel(std::string("Y")); - spinner3->setVisible(TRUE); - spinner3->setLabel(std::string("Z")); - if (!spinner1->hasFocus()) + mValSpinner1->setVisible(TRUE); + mValSpinner1->setLabel(LLStringExplicit("X")); + mValSpinner2->setVisible(TRUE); + mValSpinner2->setLabel(LLStringExplicit("Y")); + mValSpinner3->setVisible(TRUE); + mValSpinner3->setLabel(LLStringExplicit("Z")); + if (!mValSpinner1->hasFocus()) { - spinner1->setPrecision(3); - spinner1->setValue(v[VX]); + mValSpinner1->setPrecision(3); + mValSpinner1->setValue(v[VX]); } - if (!spinner2->hasFocus()) + if (!mValSpinner2->hasFocus()) { - spinner2->setPrecision(3); - spinner2->setValue(v[VY]); + mValSpinner2->setPrecision(3); + mValSpinner2->setValue(v[VY]); } - if (!spinner3->hasFocus()) + if (!mValSpinner3->hasFocus()) { - spinner3->setPrecision(3); - spinner3->setValue(v[VZ]); + mValSpinner3->setPrecision(3); + mValSpinner3->setValue(v[VZ]); } break; } @@ -423,70 +468,70 @@ void LLFloaterSettingsDebug::updateControl() { LLRect r; r.setValue(sd); - spinner1->setVisible(TRUE); - spinner1->setLabel(std::string("Left")); - spinner2->setVisible(TRUE); - spinner2->setLabel(std::string("Right")); - spinner3->setVisible(TRUE); - spinner3->setLabel(std::string("Bottom")); - spinner4->setVisible(TRUE); - spinner4->setLabel(std::string("Top")); - if (!spinner1->hasFocus()) + mValSpinner1->setVisible(TRUE); + mValSpinner1->setLabel(LLStringExplicit("Left")); + mValSpinner2->setVisible(TRUE); + mValSpinner2->setLabel(LLStringExplicit("Right")); + mValSpinner3->setVisible(TRUE); + mValSpinner3->setLabel(LLStringExplicit("Bottom")); + mValSpinner4->setVisible(TRUE); + mValSpinner4->setLabel(LLStringExplicit("Top")); + if (!mValSpinner1->hasFocus()) { - spinner1->setPrecision(0); - spinner1->setValue(r.mLeft); + mValSpinner1->setPrecision(0); + mValSpinner1->setValue(r.mLeft); } - if (!spinner2->hasFocus()) + if (!mValSpinner2->hasFocus()) { - spinner2->setPrecision(0); - spinner2->setValue(r.mRight); + mValSpinner2->setPrecision(0); + mValSpinner2->setValue(r.mRight); } - if (!spinner3->hasFocus()) + if (!mValSpinner3->hasFocus()) { - spinner3->setPrecision(0); - spinner3->setValue(r.mBottom); + mValSpinner3->setPrecision(0); + mValSpinner3->setValue(r.mBottom); } - if (!spinner4->hasFocus()) + if (!mValSpinner4->hasFocus()) { - spinner4->setPrecision(0); - spinner4->setValue(r.mTop); + mValSpinner4->setPrecision(0); + mValSpinner4->setValue(r.mTop); } - spinner1->setMinValue((F32)S32_MIN); - spinner1->setMaxValue((F32)S32_MAX); - spinner1->setIncrement(1.f); + mValSpinner1->setMinValue((F32)S32_MIN); + mValSpinner1->setMaxValue((F32)S32_MAX); + mValSpinner1->setIncrement(1.f); - spinner2->setMinValue((F32)S32_MIN); - spinner2->setMaxValue((F32)S32_MAX); - spinner2->setIncrement(1.f); + mValSpinner2->setMinValue((F32)S32_MIN); + mValSpinner2->setMaxValue((F32)S32_MAX); + mValSpinner2->setIncrement(1.f); - spinner3->setMinValue((F32)S32_MIN); - spinner3->setMaxValue((F32)S32_MAX); - spinner3->setIncrement(1.f); + mValSpinner3->setMinValue((F32)S32_MIN); + mValSpinner3->setMaxValue((F32)S32_MAX); + mValSpinner3->setIncrement(1.f); - spinner4->setMinValue((F32)S32_MIN); - spinner4->setMaxValue((F32)S32_MAX); - spinner4->setIncrement(1.f); + mValSpinner4->setMinValue((F32)S32_MIN); + mValSpinner4->setMaxValue((F32)S32_MAX); + mValSpinner4->setIncrement(1.f); break; } case TYPE_COL4: { LLColor4 clr; clr.setValue(sd); - color_swatch->setVisible(TRUE); + mValColor->setVisible(TRUE); // only set if changed so color picker doesn't update - if(clr != LLColor4(color_swatch->getValue())) + if(clr != LLColor4(mValColor->getValue())) { - color_swatch->set(LLColor4(sd), TRUE, FALSE); + mValColor->set(LLColor4(sd), TRUE, FALSE); } - spinner4->setVisible(TRUE); - spinner4->setLabel(std::string("Alpha")); - if (!spinner4->hasFocus()) + mValSpinner4->setVisible(TRUE); + mValSpinner4->setLabel(LLStringExplicit("Alpha")); + if (!mValSpinner4->hasFocus()) { - spinner4->setPrecision(3); - spinner4->setMinValue(0.0); - spinner4->setMaxValue(1.f); - spinner4->setValue(clr.mV[VALPHA]); + mValSpinner4->setPrecision(3); + mValSpinner4->setMinValue(0.0); + mValSpinner4->setMaxValue(1.f); + mValSpinner4->setValue(clr.mV[VALPHA]); } break; } @@ -494,35 +539,42 @@ void LLFloaterSettingsDebug::updateControl() { LLColor3 clr; clr.setValue(sd); - color_swatch->setVisible(TRUE); - color_swatch->setValue(sd); + mValColor->setVisible(TRUE); + mValColor->setValue(sd); break; } case TYPE_COL4U: { - LLColor4U clr; - clr.setValue(sd); - color_swatch->setVisible(TRUE); - if(LLColor4(clr) != LLColor4(color_swatch->getValue())) + LLColor4U clr(sd); + mValColor->setVisible(TRUE); + if (LLColor4(clr) != LLColor4(mValColor->getValue())) { - color_swatch->set(LLColor4(clr), TRUE, FALSE); + mValColor->set(LLColor4(clr), TRUE, FALSE); } - spinner4->setVisible(TRUE); - spinner4->setLabel(std::string("Alpha")); - if(!spinner4->hasFocus()) + mValSpinner4->setVisible(TRUE); + mValSpinner4->setLabel(std::string("Alpha")); + if(!mValSpinner4->hasFocus()) { - spinner4->setPrecision(0); - spinner4->setValue(clr.mV[VALPHA]); + mValSpinner4->setPrecision(0); + mValSpinner4->setValue(clr.mV[VALPHA]); } - spinner4->setMinValue(0); - spinner4->setMaxValue(255); - spinner4->setIncrement(1.f); + mValSpinner4->setMinValue(0); + mValSpinner4->setMaxValue(255); + mValSpinner4->setIncrement(1.f); break; } + case TYPE_LLSD: + mValText->setVisible(true); + { + std::ostringstream str; + LLSDSerialize::toPrettyXML(sd, str); + mValText->setValue(str.str()); + } + break; default: - mComment->setText(std::string("unknown")); + mComment->setText(LLStringExplicit("unknown")); break; } } @@ -536,49 +588,23 @@ void LLFloaterSettingsDebug::onUpdateFilter(const LLSD& value) void LLFloaterSettingsDebug::updateFilter(std::string searchTerm) { + LLStringUtil::toLower(searchTerm); + // make sure not to reselect the first item in the list on focus restore if (searchTerm == mOldSearchTerm) return; mOldSearchTerm = searchTerm; - LLStringUtil::toLower(searchTerm); - mSettingsScrollList->deleteAllItems(); - for(settings_map_t::iterator it = mSettingsMap.begin(); it != mSettingsMap.end(); it++) - { - bool addItem = searchTerm.empty(); - if (!addItem) - { - std::string itemValue = it->second->getName(); - - LLStringUtil::toLower(itemValue); - - if (itemValue.find(searchTerm, 0) != std::string::npos) - { - addItem = true; - } - else // performance: broken out to save toLower calls on comments - { - std::string itemComment = it->second->getComment(); - LLStringUtil::toLower(itemComment); - if (itemComment.find(searchTerm, 0) != std::string::npos) - addItem = true; - } - } + for(const auto& pair : mSettingsMap) + addRow(pair.second, searchTerm); - if (addItem) - { - LLSD item; - item["columns"][0]["value"] = it->second->getName(); - mSettingsScrollList->addElement(item, ADD_BOTTOM, it->second); - } - } mSettingsScrollList->sortByColumnIndex(0, true); // if at least one match was found, highlight and select the topmost entry in the list // but only if actually a search term was given - if (mSettingsScrollList->getItemCount() && !searchTerm.empty()) + if (!searchTerm.empty() && mSettingsScrollList->getItemCount()) mSettingsScrollList->selectFirstItem(); onSettingSelect(); diff --git a/indra/newview/llfloatersettingsdebug.h b/indra/newview/llfloatersettingsdebug.h index 5c94d6bd08..d9fd50e91a 100644 --- a/indra/newview/llfloatersettingsdebug.h +++ b/indra/newview/llfloatersettingsdebug.h @@ -36,10 +36,14 @@ #include "llcontrol.h" #include "llfloater.h" +class LLControlVariable; +class LLColorSwatchCtrl; class LLScrollListCtrl; +class LLSpinCtrl; class LLTextEditor; +class LLUICtrl; -class LLFloaterSettingsDebug +class LLFloaterSettingsDebug final : public LLFloater , public LLSingleton { @@ -47,8 +51,8 @@ class LLFloaterSettingsDebug LLFloaterSettingsDebug(); virtual ~LLFloaterSettingsDebug(); - virtual BOOL postBuild(); - virtual void draw(); + BOOL postBuild() override; + void draw() override; void updateControl(); @@ -64,6 +68,7 @@ class LLFloaterSettingsDebug private: // returns a pointer to the currently selected control variable, or NULL LLControlVariable* getControlVariable(); + void addRow(LLControlVariable* control, const std::string& searchTerm = LLStringUtil::null); protected: typedef std::map settings_map_t; @@ -72,11 +77,19 @@ class LLFloaterSettingsDebug std::string mOldSearchTerm; LLControlVariable* mCurrentControlVariable; - LLControlVariable* mOldControlVariable; bool mOldVisibility; LLScrollListCtrl* mSettingsScrollList; + LLSpinCtrl* mValSpinner1; + LLSpinCtrl* mValSpinner2; + LLSpinCtrl* mValSpinner3; + LLSpinCtrl* mValSpinner4; + LLColorSwatchCtrl* mValColor; + LLUICtrl* mValBool; + LLUICtrl* mValText; LLTextEditor* mComment; + LLView* mBtnCopy; + LLView* mBtnDefault; }; #endif //LLFLOATERDEBUGSETTINGS_H diff --git a/indra/newview/llfloatersnapshot.cpp b/indra/newview/llfloatersnapshot.cpp index d4830adbfd..7c63c0e773 100644 --- a/indra/newview/llfloatersnapshot.cpp +++ b/indra/newview/llfloatersnapshot.cpp @@ -54,7 +54,7 @@ #include "llfocusmgr.h" #include "llbutton.h" #include "llcombobox.h" -#include "lleconomy.h" +#include "llagentbenefits.h" #include "llsliderctrl.h" #include "llspinctrl.h" #include "llviewercontrol.h" @@ -91,9 +91,9 @@ ///---------------------------------------------------------------------------- /// Local function declarations, constants, enums, and typedefs ///---------------------------------------------------------------------------- -S32 LLFloaterSnapshot::sUIWinHeightLong = 625 ; -S32 LLFloaterSnapshot::sUIWinHeightShort = LLFloaterSnapshot::sUIWinHeightLong - 266 ; -S32 LLFloaterSnapshot::sUIWinWidth = 219 ; +S32 LLFloaterSnapshot::sUIWinHeightLong = 566; +S32 LLFloaterSnapshot::sUIWinHeightShort = LLFloaterSnapshot::sUIWinHeightLong - 266; +S32 LLFloaterSnapshot::sUIWinWidth = 219; S32 const THUMBHEIGHT = 159; LLSnapshotFloaterView* gSnapshotFloaterView = NULL; @@ -109,7 +109,7 @@ F32 FALL_TIME = 0.6f; S32 BORDER_WIDTH = 6; const S32 MAX_POSTCARD_DATASIZE = 1024 * 1024; // one megabyte -const S32 MAX_TEXTURE_SIZE = 512 ; //max upload texture size 512 * 512 +const S32 MAX_TEXTURE_SIZE = 1024; //max upload texture size 1024 * 1024 static std::string snapshotKeepAspectName(); @@ -493,16 +493,16 @@ void LLSnapshotLivePreview::updateSnapshot(BOOL new_snapshot, BOOL new_thumbnail if (mAspectRatio > window_aspect_ratio) { // trim off top and bottom - S32 height_diff = llround(getRect().getHeight() - (F32)getRect().getWidth() / mAspectRatio); - S32 half_height_diff = llround((getRect().getHeight() - (F32)getRect().getWidth() / mAspectRatio) * 0.5); + S32 height_diff = ll_round(getRect().getHeight() - (F32)getRect().getWidth() / mAspectRatio); + S32 half_height_diff = ll_round((getRect().getHeight() - (F32)getRect().getWidth() / mAspectRatio) * 0.5); rect.mBottom += half_height_diff; rect.mTop -= height_diff - half_height_diff; } else if (mAspectRatio < window_aspect_ratio) { // trim off left and right - S32 width_diff = llround(getRect().getWidth() - (F32)getRect().getHeight() * mAspectRatio); - S32 half_width_diff = llround((getRect().getWidth() - (F32)getRect().getHeight() * mAspectRatio) * 0.5f); + S32 width_diff = ll_round(getRect().getWidth() - (F32)getRect().getHeight() * mAspectRatio); + S32 half_width_diff = ll_round((getRect().getWidth() - (F32)getRect().getHeight() * mAspectRatio) * 0.5f); rect.mLeft += half_width_diff; rect.mRight -= width_diff - half_width_diff; } @@ -552,13 +552,12 @@ void LLSnapshotLivePreview::drawPreviewRect(S32 offset_x, S32 offset_y) alpha_color, TRUE); } // Draw border around captured part. - F32 line_width; - glGetFloatv(GL_LINE_WIDTH, &line_width); - glLineWidth(2.0f * line_width); + F32 line_width = gGL.getLineWidth(); + gGL.setLineWidth(2.0f * line_width); gl_rect_2d( mThumbnailPreviewRect.mLeft + offset_x, mThumbnailPreviewRect.mTop + offset_y, mThumbnailPreviewRect.mRight + offset_x, mThumbnailPreviewRect.mBottom + offset_y, LLColor4::black, FALSE); - glLineWidth(line_width); + gGL.setLineWidth(line_width); } //called when the frame is frozen. @@ -583,7 +582,7 @@ void LLSnapshotLivePreview::draw() gGL.pushMatrix(); { gGL.translatef((F32)rect.mLeft, (F32)rect.mBottom, 0.f); - gGL.begin(LLRender::QUADS); + gGL.begin(LLRender::TRIANGLE_STRIP); { gGL.texCoord2f(uv_width, uv_height); gGL.vertex2i(rect.getWidth(), rect.getHeight() ); @@ -591,11 +590,11 @@ void LLSnapshotLivePreview::draw() gGL.texCoord2f(0.f, uv_height); gGL.vertex2i(0, rect.getHeight() ); - gGL.texCoord2f(0.f, 0.f); - gGL.vertex2i(0, 0); - gGL.texCoord2f(uv_width, 0.f); gGL.vertex2i(rect.getWidth(), 0); + + gGL.texCoord2f(0.f, 0.f); + gGL.vertex2i(0, 0); } gGL.end(); } @@ -607,7 +606,7 @@ void LLSnapshotLivePreview::draw() { if (mFlashAlpha < 1.f) { - mFlashAlpha = lerp(mFlashAlpha, 1.f, LLCriticalDamp::getInterpolant(0.02f)); + mFlashAlpha = lerp(mFlashAlpha, 1.f, LLSmoothInterpolation::getInterpolant(0.02f)); } else { @@ -616,7 +615,7 @@ void LLSnapshotLivePreview::draw() } else { - mFlashAlpha = lerp(mFlashAlpha, 0.f, LLCriticalDamp::getInterpolant(0.15f)); + mFlashAlpha = lerp(mFlashAlpha, 0.f, LLSmoothInterpolation::getInterpolant(0.15f)); } if (mShineCountdown > 0) @@ -639,25 +638,25 @@ void LLSnapshotLivePreview::draw() LLLocalClipRect clip(getLocalRect()); { // draw diagonal stripe with gradient that passes over screen - S32 x1 = gViewerWindow->getWindowWidthScaled() * llround((clamp_rescale(shine_interp, 0.f, 1.f, -1.f - SHINE_WIDTH, 1.f))); - S32 x2 = x1 + llround(gViewerWindow->getWindowWidthScaled() * SHINE_WIDTH); - S32 x3 = x2 + llround(gViewerWindow->getWindowWidthScaled() * SHINE_WIDTH); + S32 x1 = gViewerWindow->getWindowWidthScaled() * ll_round((clamp_rescale(shine_interp, 0.f, 1.f, -1.f - SHINE_WIDTH, 1.f))); + S32 x2 = x1 + ll_round(gViewerWindow->getWindowWidthScaled() * SHINE_WIDTH); + S32 x3 = x2 + ll_round(gViewerWindow->getWindowWidthScaled() * SHINE_WIDTH); S32 y1 = 0; S32 y2 = gViewerWindow->getWindowHeightScaled(); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gGL.begin(LLRender::QUADS); + gGL.begin(LLRender::TRIANGLE_STRIP); { gGL.color4f(1.f, 1.f, 1.f, 0.f); - gGL.vertex2i(x1, y1); gGL.vertex2i(x1 + gViewerWindow->getWindowWidthScaled(), y2); + gGL.vertex2i(x1, y1); gGL.color4f(1.f, 1.f, 1.f, SHINE_OPACITY); gGL.vertex2i(x2 + gViewerWindow->getWindowWidthScaled(), y2); gGL.vertex2i(x2, y1); gGL.color4f(1.f, 1.f, 1.f, SHINE_OPACITY); - gGL.vertex2i(x2, y1); gGL.vertex2i(x2 + gViewerWindow->getWindowWidthScaled(), y2); + gGL.vertex2i(x2, y1); gGL.color4f(1.f, 1.f, 1.f, 0.f); gGL.vertex2i(x3 + gViewerWindow->getWindowWidthScaled(), y2); gGL.vertex2i(x3, y1); @@ -678,27 +677,18 @@ void LLSnapshotLivePreview::draw() gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); gGL.color4f(1.f, 1.f, 1.f, 1.f); LLRect outline_rect = mFullScreenImageRect; - gGL.begin(LLRender::QUADS); + gGL.begin(LLRender::TRIANGLE_STRIP); { gGL.vertex2i(outline_rect.mLeft - BORDER_WIDTH, outline_rect.mTop + BORDER_WIDTH); + gGL.vertex2i(outline_rect.mLeft, outline_rect.mTop); gGL.vertex2i(outline_rect.mRight + BORDER_WIDTH, outline_rect.mTop + BORDER_WIDTH); gGL.vertex2i(outline_rect.mRight, outline_rect.mTop); - gGL.vertex2i(outline_rect.mLeft, outline_rect.mTop); - - gGL.vertex2i(outline_rect.mLeft, outline_rect.mBottom); - gGL.vertex2i(outline_rect.mRight, outline_rect.mBottom); gGL.vertex2i(outline_rect.mRight + BORDER_WIDTH, outline_rect.mBottom - BORDER_WIDTH); + gGL.vertex2i(outline_rect.mRight, outline_rect.mBottom); gGL.vertex2i(outline_rect.mLeft - BORDER_WIDTH, outline_rect.mBottom - BORDER_WIDTH); - - gGL.vertex2i(outline_rect.mLeft, outline_rect.mTop); gGL.vertex2i(outline_rect.mLeft, outline_rect.mBottom); - gGL.vertex2i(outline_rect.mLeft - BORDER_WIDTH, outline_rect.mBottom - BORDER_WIDTH); gGL.vertex2i(outline_rect.mLeft - BORDER_WIDTH, outline_rect.mTop + BORDER_WIDTH); - - gGL.vertex2i(outline_rect.mRight, outline_rect.mBottom); - gGL.vertex2i(outline_rect.mRight, outline_rect.mTop); - gGL.vertex2i(outline_rect.mRight + BORDER_WIDTH, outline_rect.mTop + BORDER_WIDTH); - gGL.vertex2i(outline_rect.mRight + BORDER_WIDTH, outline_rect.mBottom - BORDER_WIDTH); + gGL.vertex2i(outline_rect.mLeft, outline_rect.mTop); } gGL.end(); } @@ -719,9 +709,9 @@ void LLSnapshotLivePreview::draw() gGL.pushMatrix(); { LLRect const& rect = mFallFullScreenImageRect; - gGL.translatef((F32)rect.mLeft, (F32)rect.mBottom - llround(getRect().getHeight() * 2.f * (fall_interp * fall_interp)), 0.f); + gGL.translatef((F32)rect.mLeft, (F32)rect.mBottom - ll_round(getRect().getHeight() * 2.f * (fall_interp * fall_interp)), 0.f); gGL.rotatef(-45.f * fall_interp, 0.f, 0.f, 1.f); - gGL.begin(LLRender::QUADS); + gGL.begin(LLRender::TRIANGLE_STRIP); { gGL.texCoord2f(uv_width, uv_height); gGL.vertex2i(rect.getWidth(), rect.getHeight() ); @@ -729,11 +719,11 @@ void LLSnapshotLivePreview::draw() gGL.texCoord2f(0.f, uv_height); gGL.vertex2i(0, rect.getHeight() ); - gGL.texCoord2f(0.f, 0.f); - gGL.vertex2i(0, 0); - gGL.texCoord2f(uv_width, 0.f); gGL.vertex2i(rect.getWidth(), 0); + + gGL.texCoord2f(0.f, 0.f); + gGL.vertex2i(0, 0); } gGL.end(); } @@ -772,13 +762,13 @@ BOOL LLSnapshotLivePreview::setThumbnailImageSize() { // image too wide, shrink to width mThumbnailWidth = max_width; - mThumbnailHeight = llround((F32)max_width / window_aspect_ratio); + mThumbnailHeight = ll_round((F32)max_width / window_aspect_ratio); } else { // image too tall, shrink to height mThumbnailHeight = max_height; - mThumbnailWidth = llround((F32)max_height * window_aspect_ratio); + mThumbnailWidth = ll_round((F32)max_height * window_aspect_ratio); } if(mThumbnailWidth > window_width || mThumbnailHeight > window_height) @@ -790,11 +780,11 @@ BOOL LLSnapshotLivePreview::setThumbnailImageSize() F32 ratio = mAspectRatio * window_height / window_width; if(ratio > 1.f) { - top = llround(top / ratio); + top = ll_round(top / ratio); } else { - right = llround(right * ratio); + right = ll_round(right * ratio); } left = (mThumbnailWidth - right + 1) / 2; bottom = (mThumbnailHeight - top + 1) / 2; @@ -991,8 +981,8 @@ LLSnapshotLivePreview::EAspectSizeProblem LLSnapshotLivePreview::getAspectSizePr // We need an image with the aspect mAspectRatio (from which mWidth and mHeight were derived). // The current aspect ratio of mRawSnapshot. This should be (almost) equal to window_width / window_height, - // since these values are calculated in rawRawSnapshot with llround(window_width * scale_factor) and - // llround(window_height * scale_factor) respectively (since we set uncrop = true). + // since these values are calculated in rawRawSnapshot with ll_round(window_width * scale_factor) and + // ll_round(window_height * scale_factor) respectively (since we set uncrop = true). F32 raw_aspect = (F32)mRawSnapshotWidth / mRawSnapshotHeight; // The smaller dimension might have been rounded up to 0.5 up or down. Calculate upper and lower limits. F32 lower_raw_aspect = (mRawSnapshotWidth - 0.5) / (mRawSnapshotHeight + 0.5); @@ -1017,7 +1007,7 @@ LLSnapshotLivePreview::EAspectSizeProblem LLSnapshotLivePreview::getAspectSizePr height_out = mRawSnapshotHeight; if (mAspectRatio < lower_raw_aspect) { - width_out = llround(width_out * mAspectRatio / raw_aspect); + width_out = ll_round(width_out * mAspectRatio / raw_aspect); if (width_out < mRawSnapshotWidth) { // Only set this to false when there is actually something to crop. @@ -1033,7 +1023,7 @@ LLSnapshotLivePreview::EAspectSizeProblem LLSnapshotLivePreview::getAspectSizePr } else if (mAspectRatio > upper_raw_aspect) { - height_out = llround(height_out * raw_aspect / mAspectRatio); + height_out = ll_round(height_out * raw_aspect / mAspectRatio); if (height_out < mRawSnapshotHeight) { if (!allow_vertical_crop) @@ -1185,7 +1175,7 @@ LLSnapshotLivePreview::EAspectSizeProblem LLSnapshotLivePreview::generateFormatt if (mSnapshotType == SNAPSHOT_TEXTURE) { // 'scaled' must be a power of two. - scaled->biasedScaleToPowerOfTwo(mWidth, mHeight, 512); + scaled->biasedScaleToPowerOfTwo(mWidth, mHeight, 1024); } else { @@ -1331,7 +1321,7 @@ LLFloaterFeed* LLSnapshotLivePreview::getCaptionAndSaveFeed() if (mFullScreenPreviewTexture.isNull()) { // This should never happen! - llwarns << "The snapshot image has not been generated!" << llendl; + LL_WARNS() << "The snapshot image has not been generated!" << LL_ENDL; saveDone(SNAPSHOT_FEED, false, sSnapshotIndex); return NULL; } @@ -1344,7 +1334,7 @@ LLFloaterFeed* LLSnapshotLivePreview::getCaptionAndSaveFeed() LLImagePNG* png = dynamic_cast(mFormattedImage.get()); if (!png) { - llwarns << "Formatted image not a PNG" << llendl; + LL_WARNS() << "Formatted image not a PNG" << LL_ENDL; saveDone(SNAPSHOT_FEED, false, sSnapshotIndex); return NULL; } @@ -1369,7 +1359,7 @@ LLFloaterPostcard* LLSnapshotLivePreview::savePostcard() if(mFullScreenPreviewTexture.isNull()) { //this should never happen!! - llwarns << "The snapshot image has not been generated!" << llendl ; + LL_WARNS() << "The snapshot image has not been generated!" << LL_ENDL ; saveDone(SNAPSHOT_POSTCARD, false, sSnapshotIndex); return NULL ; } @@ -1384,7 +1374,7 @@ LLFloaterPostcard* LLSnapshotLivePreview::savePostcard() LLImageJPEG* jpg = dynamic_cast(mFormattedImage.get()); if(!jpg) { - llwarns << "Formatted image not a JPEG" << llendl; + LL_WARNS() << "Formatted image not a JPEG" << LL_ENDL; saveDone(SNAPSHOT_POSTCARD, false, sSnapshotIndex); return NULL; } @@ -1424,9 +1414,9 @@ void LLSnapshotLivePreview::saveTexture() std::string who_took_it; LLAgentUI::buildFullname(who_took_it); LLAssetStorage::LLStoreAssetCallback callback = &LLSnapshotLivePreview::saveTextureDone; - S32 expected_upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(); + S32 expected_upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost(); saveTextureUserData* user_data = new saveTextureUserData(this, sSnapshotIndex, gSavedSettings.getBOOL("TemporaryUpload")); - if (!upload_new_resource(tid, // tid + if (upload_new_resource(tid, // tid LLAssetType::AT_TEXTURE, "Snapshot : " + pos_string, "Taken by " + who_took_it + " at " + pos_string, @@ -1434,10 +1424,14 @@ void LLSnapshotLivePreview::saveTexture() LLFolderType::FT_SNAPSHOT_CATEGORY, LLInventoryType::IT_SNAPSHOT, PERM_ALL, // Note: Snapshots to inventory is a special case of content upload - LLFloaterPerms::getGroupPerms(), // that is more permissive than other uploads - LLFloaterPerms::getEveryonePerms(), + LLFloaterPerms::getGroupPerms("Uploads"), // that is more permissive than other uploads + LLFloaterPerms::getEveryonePerms("Uploads"), "Snapshot : " + pos_string, - callback, expected_upload_cost, user_data, &LLSnapshotLivePreview::saveTextureDone2)) + callback, expected_upload_cost, user_data)) + { + saveTextureDone2(true, user_data); + } + else { // Something went wrong. delete user_data; @@ -1509,7 +1503,7 @@ void LLSnapshotLivePreview::saveDone(ESnapshotType type, bool success, int index // The snapshot was already replaced, so this callback has nothing to do with us anymore. if (!success) { - llwarns << "Permanent failure to upload or save snapshot" << llendl; + LL_WARNS() << "Permanent failure to upload or save snapshot" << LL_ENDL; } return; } @@ -1551,7 +1545,7 @@ void LLSnapshotLivePreview::saveTextureDone(LLUUID const& asset_id, void* user_d // Call the default call back. LLAssetStorage::LLStoreAssetCallback asset_callback = temporary ? &temp_upload_callback : &upload_done_callback; - (*asset_callback)(asset_id, user_data, status, ext_status); + asset_callback(asset_id, user_data, status, ext_status); } // This callback used when the capability NewFileAgentInventory is available and it wasn't a temporary. @@ -1604,18 +1598,7 @@ LLSnapshotLivePreview* LLFloaterSnapshot::Impl::getPreviewView(void) // static LLSnapshotLivePreview::ESnapshotType LLFloaterSnapshot::Impl::getTypeIndex(LLFloaterSnapshot* floater) { - LLSnapshotLivePreview::ESnapshotType index = LLSnapshotLivePreview::SNAPSHOT_FEED; - LLSD value = floater->childGetValue("snapshot_type_radio"); - const std::string id = value.asString(); - if (id == "feed") - index = LLSnapshotLivePreview::SNAPSHOT_FEED; - else if (id == "postcard") - index = LLSnapshotLivePreview::SNAPSHOT_POSTCARD; - else if (id == "texture") - index = LLSnapshotLivePreview::SNAPSHOT_TEXTURE; - else if (id == "local") - index = LLSnapshotLivePreview::SNAPSHOT_LOCAL; - return index; + return (LLSnapshotLivePreview::ESnapshotType)floater->childGetValue("snapshot_type_radio").asInteger(); } @@ -1768,33 +1751,10 @@ void LLFloaterSnapshot::Impl::freezeTime(bool on) void LLFloaterSnapshot::Impl::updateControls(LLFloaterSnapshot* floater, bool delayed_formatted) { DoutEntering(dc::snapshot, "LLFloaterSnapshot::Impl::updateControls()"); - std::string fee = gHippoGridManager->getConnectedGrid()->getUploadFee(); - if (gSavedSettings.getBOOL("TemporaryUpload")) - { - fee = fee.substr(0, fee.find_first_of("0123456789")) + "0"; - } - floater->childSetLabelArg("upload_btn", "[UPLOADFEE]", fee); + const HippoGridInfo& grid(*gHippoGridManager->getConnectedGrid()); + floater->childSetLabelArg("upload_btn", "[UPLOADFEE]", grid.formatFee(gSavedSettings.getBOOL("TemporaryUpload") ? 0 : LLAgentBenefitsMgr::current().getTextureUploadCost())); LLSnapshotLivePreview::ESnapshotType shot_type = (LLSnapshotLivePreview::ESnapshotType)gSavedSettings.getS32("LastSnapshotType"); - LLRadioGroup* snapshot_type_radio = floater->getChild("snapshot_type_radio"); - if (snapshot_type_radio) - { - snapshot_type_radio->setSelectedIndex(shot_type); - - const child_list_t *childs = snapshot_type_radio->getChildList(); - if (childs) - { - child_list_t::const_iterator it, end=childs->end(); - for (it=childs->begin(); it!=end; ++it) - { - LLRadioCtrl *ctrl = dynamic_cast(*it); - if (ctrl && (ctrl->getName() == "texture")) - { - ctrl->setLabelArg("[UPLOADFEE]", fee); - } - } - } - } ESnapshotFormat shot_format = (ESnapshotFormat)gSavedSettings.getS32("SnapshotFormat"); floater->childSetVisible("feed_size_combo", FALSE); @@ -1897,7 +1857,7 @@ void LLFloaterSnapshot::Impl::updateControls(LLFloaterSnapshot* floater, bool de { bytes_string = floater->getString("unknown"); } - S32 upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(); + S32 upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost(); floater->childSetLabelArg("texture", "[AMOUNT]", llformat("%d",upload_cost)); floater->childSetLabelArg("upload_btn", "[AMOUNT]", llformat("%d",upload_cost)); floater->childSetTextArg("file_size_label", "[SIZE]", bytes_string); @@ -2403,8 +2363,8 @@ void LLFloaterSnapshot::Impl::keepAspect(LLFloaterSnapshot* view, bool on, bool LLSnapshotLivePreview* previewp = getPreviewView(); if (previewp) { - S32 w = llround(view->childGetValue("snapshot_width").asReal(), 1.0); - S32 h = llround(view->childGetValue("snapshot_height").asReal(), 1.0); + S32 w = ll_round(view->childGetValue("snapshot_width").asReal(), 1.0); + S32 h = ll_round(view->childGetValue("snapshot_height").asReal(), 1.0); gSavedSettings.setS32(lastSnapshotWidthName(), w); gSavedSettings.setS32(lastSnapshotHeightName(), h); comboSetCustom(view, previewp->resolutionComboName()); @@ -2464,8 +2424,8 @@ void LLFloaterSnapshot::Impl::updateResolution(LLUICtrl* ctrl, void* data, bool // The size is actually the source aspect now, encoded in the width. F32 source_aspect = width / 630.f; // Use the size of the current window, cropped to the required aspect. - width = llmin(gViewerWindow->getWindowDisplayWidth(), llround(gViewerWindow->getWindowDisplayHeight() * source_aspect)); - height = llmin(gViewerWindow->getWindowDisplayHeight(), llround(gViewerWindow->getWindowDisplayWidth() / source_aspect)); + width = llmin(gViewerWindow->getWindowDisplayWidth(), ll_round(gViewerWindow->getWindowDisplayHeight() * source_aspect)); + height = llmin(gViewerWindow->getWindowDisplayHeight(), ll_round(gViewerWindow->getWindowDisplayWidth() / source_aspect)); previewp->setSize(width, height); } else @@ -2488,8 +2448,7 @@ void LLFloaterSnapshot::Impl::updateResolution(LLUICtrl* ctrl, void* data, bool LLSpinCtrl* width_spinner = view->getChild("snapshot_width"); LLSpinCtrl* height_spinner = view->getChild("snapshot_height"); - if (gSavedSettings.getS32("LastSnapshotType") == LLSnapshotLivePreview::SNAPSHOT_TEXTURE || - gSavedSettings.getBOOL("RenderUIInSnapshot") || + if ( gSavedSettings.getBOOL("RenderUIInSnapshot") || gSavedSettings.getBOOL("RenderHUDInSnapshot")) { // Disable without making label gray. @@ -2653,8 +2612,8 @@ void LLFloaterSnapshot::Impl::enforceResolution(LLFloaterSnapshot* floater, F32 nw = llmin(nw, nh * new_aspect); nh = llmin(nh, nw / new_aspect); // Round off to nearest integer. - S32 new_width = llround(nw); - S32 new_height = llround(nh); + S32 new_width = ll_round(nw); + S32 new_height = ll_round(nh); gSavedSettings.setS32(lastSnapshotWidthName(), new_width); gSavedSettings.setS32(lastSnapshotHeightName(), new_height); @@ -2693,7 +2652,6 @@ void LLFloaterSnapshot::Impl::onCommitSnapshotType(LLUICtrl* ctrl, void* data) } } - //static void LLFloaterSnapshot::Impl::onCommitSnapshotFormat(LLUICtrl* ctrl, void* data) { @@ -2705,14 +2663,11 @@ void LLFloaterSnapshot::Impl::onCommitSnapshotFormat(LLUICtrl* ctrl, void* data) } } - - // Sets the named size combo to "custom" mode. // static void LLFloaterSnapshot::Impl::comboSetCustom(LLFloaterSnapshot* floater, const std::string& comboname) { LLComboBox* combo = floater->getChild(comboname); - combo->setCurrentByIndex(combo->getItemCount() - 1); // "custom" is always the last index storeAspectSetting(combo, comboname); } @@ -2759,8 +2714,8 @@ void LLFloaterSnapshot::Impl::onCommitCustomResolution(LLUICtrl *ctrl, void* dat LLSpinCtrl* width_spinner = view->getChild("snapshot_width"); LLSpinCtrl* height_spinner = view->getChild("snapshot_height"); - S32 w = llround((F32)width_spinner->getValue().asReal(), 1.0f); - S32 h = llround((F32)height_spinner->getValue().asReal(), 1.0f); + S32 w = ll_round((F32)width_spinner->getValue().asReal(), 1.0f); + S32 h = ll_round((F32)height_spinner->getValue().asReal(), 1.0f); LLSnapshotLivePreview* previewp = getPreviewView(); if (previewp) @@ -2787,12 +2742,12 @@ void LLFloaterSnapshot::Impl::onCommitCustomResolution(LLUICtrl *ctrl, void* dat if (h == curh) { // Width was changed. Change height to keep aspect constant. - h = llround(w / aspect); + h = ll_round(w / aspect); } else { // Height was changed. Change width to keep aspect constant. - w = llround(h * aspect); + w = ll_round(h * aspect); } } width_spinner->forceSetValue(LLSD::Real(w)); @@ -2929,7 +2884,14 @@ LLFloaterSnapshot::~LLFloaterSnapshot() BOOL LLFloaterSnapshot::postBuild() { - childSetCommitCallback("snapshot_type_radio", Impl::onCommitSnapshotType, this); + // Don't let statics override the xml. + sUIWinHeightLong = getRect().getHeight(); + sUIWinHeightShort = sUIWinHeightLong - 266; + if (LLUICtrl* snapshot_type_radio = getChild("snapshot_type_radio")) + { + snapshot_type_radio->setCommitCallback(Impl::onCommitSnapshotType, this); + snapshot_type_radio->setValue(gSavedSettings.getS32("LastSnapshotType")); + } childSetCommitCallback("local_format_combo", Impl::onCommitSnapshotFormat, this); childSetAction("new_snapshot_btn", Impl::onClickNewSnapshot, this); @@ -2955,25 +2917,25 @@ BOOL LLFloaterSnapshot::postBuild() childSetCommitCallback("keep_aspect", Impl::onClickKeepAspect, this); childSetCommitCallback("ui_check", Impl::onClickUICheck, this); - childSetValue("ui_check", gSavedSettings.getBOOL("RenderUIInSnapshot")); + getChild("ui_check")->setValue(gSavedSettings.getBOOL("RenderUIInSnapshot")); childSetCommitCallback("hud_check", Impl::onClickHUDCheck, this); - childSetValue("hud_check", gSavedSettings.getBOOL("RenderHUDInSnapshot")); + getChild("hud_check")->setValue(gSavedSettings.getBOOL("RenderHUDInSnapshot")); childSetCommitCallback("keep_open_check", Impl::onClickKeepOpenCheck, this); childSetValue("keep_open_check", !gSavedSettings.getBOOL("CloseSnapshotOnKeep")); childSetCommitCallback("layer_types", Impl::onCommitLayerTypes, this); - childSetValue("layer_types", "colors"); - childSetEnabled("layer_types", FALSE); + getChild("layer_types")->setValue("colors"); + getChildView("layer_types")->setEnabled(FALSE); childSetValue("snapshot_width", gSavedSettings.getS32(lastSnapshotWidthName())); childSetValue("snapshot_height", gSavedSettings.getS32(lastSnapshotHeightName())); - childSetValue("freeze_time_check", gSavedSettings.getBOOL("SnapshotOpenFreezeTime")); + getChild("freeze_time_check")->setValue(gSavedSettings.getBOOL("SnapshotOpenFreezeTime")); childSetCommitCallback("freeze_time_check", Impl::onCommitFreezeTime, this); - childSetValue("auto_snapshot_check", gSavedSettings.getBOOL("AutoSnapshot")); + getChild("auto_snapshot_check")->setValue(gSavedSettings.getBOOL("AutoSnapshot")); childSetCommitCallback("auto_snapshot_check", Impl::onClickAutoSnap, this); childSetCommitCallback("temp_check", Impl::onClickTemporaryImage, this); @@ -3038,7 +3000,7 @@ void LLFloaterSnapshot::draw() S32 offset_y = (thumb_area.mBottom + thumb_area.mTop - previewp->getThumbnailHeight()) / 2; gGL.matrixMode(LLRender::MM_MODELVIEW); - gl_rect_2d(thumb_area, LLColor4::grey4, true); + gl_rect_2d(thumb_area, LLColor4::transparent, true); gl_draw_scaled_image(offset_x, offset_y, previewp->getThumbnailWidth(), previewp->getThumbnailHeight(), previewp->getThumbnailImage(), LLColor4::white); @@ -3224,16 +3186,9 @@ BOOL LLSnapshotFloaterView::handleKey(KEY key, MASK mask, BOOL called_from_paren return LLFloaterView::handleKey(key, mask, called_from_parent); } - if (called_from_parent) - { - // pass all keystrokes down - LLFloaterView::handleKey(key, mask, called_from_parent); - } - else - { - // bounce keystrokes back down - LLFloaterView::handleKey(key, mask, TRUE); - } + // pass all keystrokes down + // bounce keystrokes back down + LLFloaterView::handleKey(key, mask, TRUE); return TRUE; } diff --git a/indra/newview/llfloaterstats.cpp b/indra/newview/llfloaterstats.cpp index 53a6c17085..25243e9f2e 100644 --- a/indra/newview/llfloaterstats.cpp +++ b/indra/newview/llfloaterstats.cpp @@ -53,12 +53,11 @@ const S32 LL_SCROLL_BORDER = 1; void LLFloaterStats::buildStats() { LLRect rect; - LLStatBar *stat_barp; // // Viewer advanced stats // - LLStatView *stat_viewp = NULL; + LLStatView* stat_viewp = NULL; // // Viewer Basic @@ -73,51 +72,62 @@ void LLFloaterStats::buildStats() stat_viewp = LLUICtrlFactory::create(params); addStatView(stat_viewp); - stat_barp = stat_viewp->addStat("FPS", &(LLViewerStats::getInstance()->mFPSStat), - "DebugStatModeFPS", TRUE, TRUE); - stat_barp->setUnitLabel(" fps"); - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 60.f; - stat_barp->mTickSpacing = 3.f; - stat_barp->mLabelSpacing = 15.f; - stat_barp->mPrecision = 1; - - stat_barp = stat_viewp->addStat("Bandwidth", &(LLViewerStats::getInstance()->mKBitStat), - "DebugStatModeBandwidth", TRUE, FALSE); - stat_barp->setUnitLabel(" kbps"); - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 900.f; - stat_barp->mTickSpacing = 100.f; - stat_barp->mLabelSpacing = 300.f; - - stat_barp = stat_viewp->addStat("Packet Loss", &(LLViewerStats::getInstance()->mPacketsLostPercentStat), "DebugStatModePacketLoss"); - stat_barp->setUnitLabel(" %"); - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 5.f; - stat_barp->mTickSpacing = 1.f; - stat_barp->mLabelSpacing = 1.f; - stat_barp->mPerSec = FALSE; - stat_barp->mDisplayMean = TRUE; - stat_barp->mPrecision = 1; - - stat_barp = stat_viewp->addStat("Ping Sim", &(LLViewerStats::getInstance()->mSimPingStat), "DebugStatMode"); - stat_barp->setUnitLabel(" msec"); - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 1000.f; - stat_barp->mTickSpacing = 100.f; - stat_barp->mLabelSpacing = 200.f; - stat_barp->mPerSec = FALSE; - stat_barp->mDisplayMean = FALSE; - - if(SGMemStat::haveStat()) { - stat_barp = stat_viewp->addStat("Allocated memory", &(LLViewerStats::getInstance()->mMallocStat), "DebugStatModeMalloc"); - stat_barp->setUnitLabel(" MB"); - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 2048.f; - stat_barp->mTickSpacing = 128.f; - stat_barp->mLabelSpacing = 512.f; - stat_barp->mPerSec = FALSE; - stat_barp->mDisplayMean = FALSE; + { + LLStatBar::Parameters params; + params.mUnitLabel = " fps"; + params.mMinBar = 0.f; + params.mMaxBar = 60.f; + params.mTickSpacing = 3.f; + params.mLabelSpacing = 15.f; + params.mPrecision = 1; + stat_viewp->addStat("FPS", &(LLViewerStats::getInstance()->mFPSStat), params, "DebugStatModeFPS", TRUE, TRUE); + } + + { + LLStatBar::Parameters params; + params.mUnitLabel = " kbps"; + params.mMinBar = 0.f; + params.mMaxBar = 900.f; + params.mTickSpacing = 100.f; + params.mLabelSpacing = 300.f; + stat_viewp->addStat("Bandwidth", &(LLViewerStats::getInstance()->mKBitStat), params, "DebugStatModeBandwidth", TRUE, FALSE); + } + + { + LLStatBar::Parameters params; + params.mUnitLabel = " %"; + params.mMinBar = 0.f; + params.mMaxBar = 5.f; + params.mTickSpacing = 1.f; + params.mLabelSpacing = 1.f; + params.mPerSec = FALSE; + params.mDisplayMean = TRUE; + params.mDisplayMean = 1; + stat_viewp->addStat("Packet Loss", &(LLViewerStats::getInstance()->mPacketsLostPercentStat), params, "DebugStatModePacketLoss"); + } + + { + LLStatBar::Parameters params; + params.mUnitLabel = " msec"; + params.mMinBar = 0.f; + params.mMaxBar = 1000.f; + params.mTickSpacing = 100.f; + params.mLabelSpacing = 200.f; + params.mPerSec = FALSE; + params.mDisplayMean = FALSE; + stat_viewp->addStat("Ping Sim", &(LLViewerStats::getInstance()->mSimPingStat), params, "DebugStatMode"); + } + + if (SGMemStat::haveStat()) { + LLStatBar::Parameters params; + params.mUnitLabel = " MB"; + params.mMinBar = 0.f; + params.mMaxBar = 2048.f; + params.mTickSpacing = 128.f; + params.mLabelSpacing = 512.f; + params.mPerSec = FALSE; + params.mDisplayMean = FALSE; + stat_viewp->addStat("Allocated memory", &(LLViewerStats::getInstance()->mMallocStat), params, "DebugStatModeMalloc"); } params.name("advanced stat view"); @@ -133,47 +143,63 @@ void LLFloaterStats::buildStats() params.label("Render"); params.setting("OpenDebugStatRender"); params.rect(rect); - LLStatView *render_statviewp = stat_viewp->addStatView(params); - - stat_barp = render_statviewp->addStat("KTris Drawn", &(LLViewerStats::getInstance()->mTrianglesDrawnStat), "DebugStatModeKTrisDrawnFr"); - stat_barp->setUnitLabel("/fr"); - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 3000.f; - stat_barp->mTickSpacing = 100.f; - stat_barp->mLabelSpacing = 500.f; - stat_barp->mPrecision = 1; - stat_barp->mPerSec = FALSE; - - stat_barp = render_statviewp->addStat("KTris Drawn", &(LLViewerStats::getInstance()->mTrianglesDrawnStat), "DebugStatModeKTrisDrawnSec"); - stat_barp->setUnitLabel("/sec"); - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 100000.f; - stat_barp->mTickSpacing = 4000.f; - stat_barp->mLabelSpacing = 20000.f; - stat_barp->mPrecision = 1; - - stat_barp = render_statviewp->addStat("Total Objs", &(LLViewerStats::getInstance()->mNumObjectsStat), "DebugStatModeTotalObjs"); - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 10000.f; - stat_barp->mTickSpacing = 2500.f; - stat_barp->mLabelSpacing = 5000.f; - stat_barp->mPerSec = FALSE; - - stat_barp = render_statviewp->addStat("New Objs", &(LLViewerStats::getInstance()->mNumNewObjectsStat), "DebugStatModeNewObjs"); - stat_barp->setUnitLabel("/sec"); - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 1000.f; - stat_barp->mTickSpacing = 100.f; - stat_barp->mLabelSpacing = 500.f; - stat_barp->mPerSec = TRUE; - - stat_barp = render_statviewp->addStat("Object Cache Hit Rate", &(LLViewerStats::getInstance()->mNumNewObjectsStat), std::string(), false, true); - stat_barp->setUnitLabel("%"); - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 100.f; - stat_barp->mTickSpacing = 20.f; - stat_barp->mLabelSpacing = 20.f; - stat_barp->mPerSec = FALSE; + + LLStatView* render_statviewp = stat_viewp->addStatView(params); + + { + LLStatBar::Parameters params; + params.mUnitLabel = "/fr"; + params.mMinBar = 0.f; + params.mMaxBar = 3000.f; + params.mTickSpacing = 100.f; + params.mLabelSpacing = 500.f; + params.mPrecision = 1; + params.mPerSec = FALSE; + render_statviewp->addStat("KTris Drawn", &(LLViewerStats::getInstance()->mTrianglesDrawnStat), params, "DebugStatModeKTrisDrawnFr"); + } + + { + LLStatBar::Parameters params; + params.mUnitLabel = "/sec"; + params.mMinBar = 0.f; + params.mMaxBar = 100000.f; + params.mTickSpacing = 4000.f; + params.mLabelSpacing = 20000.f; + params.mPrecision = 1; + render_statviewp->addStat("KTris Drawn", &(LLViewerStats::getInstance()->mTrianglesDrawnStat), params, "DebugStatModeKTrisDrawnSec"); + } + + { + LLStatBar::Parameters params; + params.mMinBar = 0.f; + params.mMaxBar = 10000.f; + params.mTickSpacing = 2500.f; + params.mLabelSpacing = 5000.f; + params.mPerSec = FALSE; + render_statviewp->addStat("Total Objs", &(LLViewerStats::getInstance()->mNumObjectsStat), params, "DebugStatModeTotalObjs"); + } + + { + LLStatBar::Parameters params; + params.mUnitLabel = "/sec"; + params.mMinBar = 0.f; + params.mMaxBar = 1000.f; + params.mTickSpacing = 100.f; + params.mLabelSpacing = 500.f; + params.mPerSec = TRUE; + render_statviewp->addStat("New Objs", &(LLViewerStats::getInstance()->mNumNewObjectsStat), params, "DebugStatModeNewObjs"); + } + + { + LLStatBar::Parameters params; + params.mUnitLabel = "%"; + params.mMinBar = 0.f; + params.mMaxBar = 100.f; + params.mTickSpacing = 20.f; + params.mLabelSpacing = 20.f; + params.mPerSec = FALSE; + render_statviewp->addStat("Object Cache Hit Rate", &(LLViewerStats::getInstance()->mNumNewObjectsStat), params, std::string(), false, true); + } // Texture statistics params.name("texture stat view"); @@ -181,152 +207,197 @@ void LLFloaterStats::buildStats() params.label("Texture"); params.setting("OpenDebugStatTexture"); params.rect(rect); - LLStatView *texture_statviewp = render_statviewp->addStatView(params); - - stat_barp = texture_statviewp->addStat("Cache Hit Rate", &(LLTextureFetch::sCacheHitRate), std::string(), false, true); - stat_barp->setUnitLabel("%"); - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 100.f; - stat_barp->mTickSpacing = 20.f; - stat_barp->mLabelSpacing = 20.f; - stat_barp->mPerSec = FALSE; - - stat_barp = texture_statviewp->addStat("Cache Read Latency", &(LLTextureFetch::sCacheReadLatency), std::string(), false, true); - stat_barp->setUnitLabel("msec"); - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 1000.f; - stat_barp->mTickSpacing = 100.f; - stat_barp->mLabelSpacing = 200.f; - stat_barp->mPerSec = FALSE; - stat_barp->mDisplayMean = FALSE; - - stat_barp = texture_statviewp->addStat("Count", &(LLViewerStats::getInstance()->mNumImagesStat), "DebugStatModeTextureCount"); - stat_barp->setUnitLabel(""); - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 8000.f; - stat_barp->mTickSpacing = 2000.f; - stat_barp->mLabelSpacing = 4000.f; - stat_barp->mPerSec = FALSE; - - stat_barp = texture_statviewp->addStat("Raw Count", &(LLViewerStats::getInstance()->mNumRawImagesStat), "DebugStatModeRawCount"); - stat_barp->setUnitLabel(""); - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 8000.f; - stat_barp->mTickSpacing = 2000.f; - stat_barp->mLabelSpacing = 4000.f; - stat_barp->mPerSec = FALSE; - - stat_barp = texture_statviewp->addStat("GL Mem", &(LLViewerStats::getInstance()->mGLTexMemStat), "DebugStatModeGLMem"); - stat_barp->setUnitLabel(""); - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 400.f; - stat_barp->mTickSpacing = 100.f; - stat_barp->mLabelSpacing = 200.f; - stat_barp->mPrecision = 1; - stat_barp->mPerSec = FALSE; - - stat_barp = texture_statviewp->addStat("Formatted Mem", &(LLViewerStats::getInstance()->mFormattedMemStat), "DebugStatModeFormattedMem"); - stat_barp->setUnitLabel(""); - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 400.f; - stat_barp->mTickSpacing = 100.f; - stat_barp->mLabelSpacing = 200.f; - stat_barp->mPrecision = 1; - stat_barp->mPerSec = FALSE; - - stat_barp = texture_statviewp->addStat("Raw Mem", &(LLViewerStats::getInstance()->mRawMemStat), "DebugStatModeRawMem"); - stat_barp->setUnitLabel(""); - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 400.f; - stat_barp->mTickSpacing = 100.f; - stat_barp->mLabelSpacing = 200.f; - stat_barp->mPrecision = 1; - stat_barp->mPerSec = FALSE; - - stat_barp = texture_statviewp->addStat("Bound Mem", &(LLViewerStats::getInstance()->mGLBoundMemStat), "DebugStatModeBoundMem"); - stat_barp->setUnitLabel(""); - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 400.f; - stat_barp->mTickSpacing = 100.f; - stat_barp->mLabelSpacing = 200.f; - stat_barp->mPrecision = 1; - stat_barp->mPerSec = FALSE; - + LLStatView* texture_statviewp = render_statviewp->addStatView(params); + + { + LLStatBar::Parameters params; + params.mUnitLabel = "%"; + params.mMinBar = 0.f; + params.mMaxBar = 100.f; + params.mTickSpacing = 20.f; + params.mLabelSpacing = 20.f; + params.mPerSec = FALSE; + texture_statviewp->addStat("Cache Hit Rate", &(LLTextureFetch::sCacheHitRate), params, std::string(), false, true); + } + + { + LLStatBar::Parameters params; + params.mUnitLabel = "msec"; + params.mMinBar = 0.f; + params.mMaxBar = 1000.f; + params.mTickSpacing = 100.f; + params.mLabelSpacing = 200.f; + params.mPerSec = FALSE; + params.mDisplayMean = FALSE; + texture_statviewp->addStat("Cache Read Latency", &(LLTextureFetch::sCacheReadLatency), params, std::string(), false, true); + } + + { + LLStatBar::Parameters params; + params.mMinBar = 0.f; + params.mMaxBar = 8000.f; + params.mTickSpacing = 2000.f; + params.mLabelSpacing = 4000.f; + params.mPerSec = FALSE; + texture_statviewp->addStat("Count", &(LLViewerStats::getInstance()->mNumImagesStat), params, "DebugStatModeTextureCount"); + } + + { + LLStatBar::Parameters params; + params.mMinBar = 0.f; + params.mMaxBar = 8000.f; + params.mTickSpacing = 2000.f; + params.mLabelSpacing = 4000.f; + params.mPerSec = FALSE; + texture_statviewp->addStat("Raw Count", &(LLViewerStats::getInstance()->mNumRawImagesStat), params, "DebugStatModeRawCount"); + } + + { + LLStatBar::Parameters params; + params.mMinBar = 0.f; + params.mMaxBar = 400.f; + params.mTickSpacing = 100.f; + params.mLabelSpacing = 200.f; + params.mPrecision = 1; + params.mPerSec = FALSE; + texture_statviewp->addStat("GL Mem", &(LLViewerStats::getInstance()->mGLTexMemStat), params, "DebugStatModeGLMem"); + } + + { + LLStatBar::Parameters params; + params.mMinBar = 0.f; + params.mMaxBar = 400.f; + params.mTickSpacing = 100.f; + params.mLabelSpacing = 200.f; + params.mPrecision = 1; + params.mPerSec = FALSE; + texture_statviewp->addStat("Formatted Mem", &(LLViewerStats::getInstance()->mFormattedMemStat), params, "DebugStatModeFormattedMem"); + } + + { + LLStatBar::Parameters params; + params.mMinBar = 0.f; + params.mMaxBar = 400.f; + params.mTickSpacing = 100.f; + params.mLabelSpacing = 200.f; + params.mPrecision = 1; + params.mPerSec = FALSE; + texture_statviewp->addStat("Raw Mem", &(LLViewerStats::getInstance()->mRawMemStat), params, "DebugStatModeRawMem"); + } + + { + LLStatBar::Parameters params; + params.mMinBar = 0.f; + params.mMaxBar = 400.f; + params.mTickSpacing = 100.f; + params.mLabelSpacing = 200.f; + params.mPrecision = 1; + params.mPerSec = FALSE; + texture_statviewp->addStat("Bound Mem", &(LLViewerStats::getInstance()->mGLBoundMemStat), params, "DebugStatModeBoundMem"); + } + // Network statistics params.name("network stat view"); params.show_label(true); params.label("Network"); params.setting("OpenDebugStatNet"); params.rect(rect); - LLStatView *net_statviewp = stat_viewp->addStatView(params); - - stat_barp = net_statviewp->addStat("UDP Packets In", &(LLViewerStats::getInstance()->mPacketsInStat), "DebugStatModePacketsIn"); - stat_barp->setUnitLabel("/sec"); - - stat_barp = net_statviewp->addStat("UDP Packets Out", &(LLViewerStats::getInstance()->mPacketsOutStat), "DebugStatModePacketsOut"); - stat_barp->setUnitLabel("/sec"); - - stat_barp = net_statviewp->addStat("HTTP Textures", &(LLViewerStats::getInstance()->mHTTPTextureKBitStat), "DebugStatModeHTTPTexture"); - stat_barp->setUnitLabel(" kbps"); - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = gSavedSettings.getF32("HTTPThrottleBandwidth"); - stat_barp->mMaxBar *= llclamp(2.0 - (stat_barp->mMaxBar - 400.f) / 3600.f, 1.0, 2.0); // Allow for overshoot (allow more for low bandwidth values). - stat_barp->mTickSpacing = 1.f; - while (stat_barp->mTickSpacing < stat_barp->mMaxBar / 8) - stat_barp->mTickSpacing *= 2.f; - stat_barp->mLabelSpacing = 2 * stat_barp->mTickSpacing; - stat_barp->mPerSec = FALSE; - stat_barp->mDisplayMean = FALSE; - - stat_barp = net_statviewp->addStat("UDP Textures", &(LLViewerStats::getInstance()->mUDPTextureKBitStat), "DebugStatModeUDPTexture"); - stat_barp->setUnitLabel(" kbps"); - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 1024.f; - stat_barp->mTickSpacing = 128.f; - stat_barp->mLabelSpacing = 256.f; - - stat_barp = net_statviewp->addStat("Objects (UDP)", &(LLViewerStats::getInstance()->mObjectKBitStat), "DebugStatModeObjects"); - stat_barp->setUnitLabel(" kbps"); - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 1024.f; - stat_barp->mTickSpacing = 128.f; - stat_barp->mLabelSpacing = 256.f; - - stat_barp = net_statviewp->addStat("Assets (UDP)", &(LLViewerStats::getInstance()->mAssetKBitStat), "DebugStatModeAsset"); - stat_barp->setUnitLabel(" kbps"); - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 1024.f; - stat_barp->mTickSpacing = 128.f; - stat_barp->mLabelSpacing = 256.f; - - stat_barp = net_statviewp->addStat("Layers (UDP)", &(LLViewerStats::getInstance()->mLayersKBitStat), "DebugStatModeLayers"); - stat_barp->setUnitLabel(" kbps"); - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 1024.f; - stat_barp->mTickSpacing = 128.f; - stat_barp->mLabelSpacing = 256.f; - - stat_barp = net_statviewp->addStat("Actual In (UDP)", &(LLViewerStats::getInstance()->mActualInKBitStat), - "DebugStatModeActualIn", TRUE, FALSE); - stat_barp->setUnitLabel(" kbps"); - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 1024.f; - stat_barp->mTickSpacing = 128.f; - stat_barp->mLabelSpacing = 256.f; - - stat_barp = net_statviewp->addStat("Actual Out (UDP)", &(LLViewerStats::getInstance()->mActualOutKBitStat), - "DebugStatModeActualOut", TRUE, FALSE); - stat_barp->setUnitLabel(" kbps"); - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 512.f; - stat_barp->mTickSpacing = 128.f; - stat_barp->mLabelSpacing = 256.f; - - stat_barp = net_statviewp->addStat("VFS Pending Ops", &(LLViewerStats::getInstance()->mVFSPendingOperations), - "DebugStatModeVFSPendingOps"); - stat_barp->setUnitLabel(" "); - stat_barp->mPerSec = FALSE; + LLStatView* net_statviewp = stat_viewp->addStatView(params); + + { + LLStatBar::Parameters params; + params.mUnitLabel = "/sec"; + net_statviewp->addStat("UDP Packets In", &(LLViewerStats::getInstance()->mPacketsInStat), params, "DebugStatModePacketsIn"); + + } + + { + LLStatBar::Parameters params; + params.mUnitLabel = "/sec"; + net_statviewp->addStat("UDP Packets Out", &(LLViewerStats::getInstance()->mPacketsOutStat), params, "DebugStatModePacketsOut"); + } + + { + LLStatBar::Parameters params; + params.mUnitLabel = " kbps"; + params.mMinBar = 0.f; + params.mMaxBar = gSavedSettings.getF32("HTTPThrottleBandwidth"); + params.mMaxBar *= llclamp(2.0 - (params.mMaxBar - 400.f) / 3600.f, 1.0, 2.0); // Allow for overshoot (allow more for low bandwidth values). + params.mTickSpacing = 1.f; + while (params.mTickSpacing < params.mMaxBar / 8) + params.mTickSpacing *= 2.f; + params.mLabelSpacing = 2 * params.mTickSpacing; + params.mPerSec = FALSE; + params.mDisplayMean = FALSE; + net_statviewp->addStat("HTTP Textures", &(LLViewerStats::getInstance()->mHTTPTextureKBitStat), params, "DebugStatModeHTTPTexture"); + } + + { + LLStatBar::Parameters params; + params.mUnitLabel = " kbps"; + params.mMinBar = 0.f; + params.mMaxBar = 1024.f; + params.mTickSpacing = 128.f; + params.mLabelSpacing = 256.f; + net_statviewp->addStat("UDP Textures", &(LLViewerStats::getInstance()->mUDPTextureKBitStat), params, "DebugStatModeUDPTexture"); + } + + { + LLStatBar::Parameters params; + params.mUnitLabel = " kbps"; + params.mMinBar = 0.f; + params.mMaxBar = 1024.f; + params.mTickSpacing = 128.f; + params.mLabelSpacing = 256.f; + net_statviewp->addStat("Objects (UDP)", &(LLViewerStats::getInstance()->mObjectKBitStat), params, "DebugStatModeObjects"); + } + + { + LLStatBar::Parameters params; + params.mUnitLabel = " kbps"; + params.mMinBar = 0.f; + params.mMaxBar = 1024.f; + params.mTickSpacing = 128.f; + params.mLabelSpacing = 256.f; + net_statviewp->addStat("Assets (UDP)", &(LLViewerStats::getInstance()->mAssetKBitStat), params, "DebugStatModeAsset"); + } + + { + LLStatBar::Parameters params; + params.mUnitLabel = " kbps"; + params.mMinBar = 0.f; + params.mMaxBar = 1024.f; + params.mTickSpacing = 128.f; + params.mLabelSpacing = 256.f; + net_statviewp->addStat("Layers (UDP)", &(LLViewerStats::getInstance()->mLayersKBitStat), params, "DebugStatModeLayers"); + } + + { + LLStatBar::Parameters params; + params.mUnitLabel = " kbps"; + params.mMinBar = 0.f; + params.mMaxBar = 1024.f; + params.mTickSpacing = 128.f; + params.mLabelSpacing = 256.f; + net_statviewp->addStat("Actual In (UDP)", &(LLViewerStats::getInstance()->mActualInKBitStat), params, "DebugStatModeActualIn", TRUE, FALSE); + } + { + LLStatBar::Parameters params; + params.mUnitLabel = " kbps"; + params.mMinBar = 0.f; + params.mMaxBar = 512.f; + params.mTickSpacing = 128.f; + params.mLabelSpacing = 256.f; + net_statviewp->addStat("Actual Out (UDP)", &(LLViewerStats::getInstance()->mActualOutKBitStat), params, "DebugStatModeActualOut", TRUE, FALSE); + } + + { + LLStatBar::Parameters params; + params.mUnitLabel = " "; + params.mPerSec = FALSE; + net_statviewp->addStat("VFS Pending Ops", &(LLViewerStats::getInstance()->mVFSPendingOperations), params, "DebugStatModeVFSPendingOps"); + } // Simulator stats params.name("sim stat view"); @@ -334,312 +405,401 @@ void LLFloaterStats::buildStats() params.label("Simulator"); params.setting("OpenDebugStatSim"); params.rect(rect); - LLStatView *sim_statviewp = LLUICtrlFactory::create(params); + LLStatView* sim_statviewp = LLUICtrlFactory::create(params); addStatView(sim_statviewp); - stat_barp = sim_statviewp->addStat("Time Dilation", &(LLViewerStats::getInstance()->mSimTimeDilation), "DebugStatModeTimeDialation"); - stat_barp->mPrecision = 2; - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 1.f; - stat_barp->mTickSpacing = 0.25f; - stat_barp->mLabelSpacing = 0.5f; - stat_barp->mPerSec = FALSE; - stat_barp->mDisplayMean = FALSE; - - stat_barp = sim_statviewp->addStat("Sim FPS", &(LLViewerStats::getInstance()->mSimFPS), "DebugStatModeSimFPS"); - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 200.f; - stat_barp->mTickSpacing = 20.f; - stat_barp->mLabelSpacing = 100.f; - stat_barp->mPerSec = FALSE; - stat_barp->mDisplayMean = FALSE; - - stat_barp = sim_statviewp->addStat("Physics FPS", &(LLViewerStats::getInstance()->mSimPhysicsFPS), "DebugStatModePhysicsFPS"); - stat_barp->mPrecision = 1; - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 66.f; - stat_barp->mTickSpacing = 33.f; - stat_barp->mLabelSpacing = 33.f; - stat_barp->mPerSec = FALSE; - stat_barp->mDisplayMean = FALSE; + { + LLStatBar::Parameters params; + params.mPrecision = 2; + params.mMinBar = 0.f; + params.mMaxBar = 1.f; + params.mTickSpacing = 0.25f; + params.mLabelSpacing = 0.5f; + params.mPerSec = FALSE; + params.mDisplayMean = FALSE; + sim_statviewp->addStat("Time Dilation", &(LLViewerStats::getInstance()->mSimTimeDilation), params, "DebugStatModeTimeDialation"); + } + + { + LLStatBar::Parameters params; + params.mMinBar = 0.f; + params.mMaxBar = 200.f; + params.mTickSpacing = 20.f; + params.mLabelSpacing = 100.f; + params.mPerSec = FALSE; + params.mDisplayMean = FALSE; + sim_statviewp->addStat("Sim FPS", &(LLViewerStats::getInstance()->mSimFPS), params, "DebugStatModeSimFPS"); + } + + { + LLStatBar::Parameters params; + params.mPrecision = 1; + params.mMinBar = 0.f; + params.mMaxBar = 66.f; + params.mTickSpacing = 33.f; + params.mLabelSpacing = 33.f; + params.mPerSec = FALSE; + params.mDisplayMean = FALSE; + sim_statviewp->addStat("Physics FPS", &(LLViewerStats::getInstance()->mSimPhysicsFPS), params, "DebugStatModePhysicsFPS"); + } params.name("phys detail view"); params.show_label(true); params.label("Physics Details"); params.setting("OpenDebugStatPhysicsDetails"); params.rect(rect); - LLStatView *phys_details_viewp = sim_statviewp->addStatView(params); - - stat_barp = phys_details_viewp->addStat("Pinned Objects", &(LLViewerStats::getInstance()->mPhysicsPinnedTasks), "DebugStatModePinnedObjects"); - stat_barp->mPrecision = 0; - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 500.f; - stat_barp->mTickSpacing = 10.f; - stat_barp->mLabelSpacing = 40.f; - stat_barp->mPerSec = FALSE; - stat_barp->mDisplayMean = FALSE; - - stat_barp = phys_details_viewp->addStat("Low LOD Objects", &(LLViewerStats::getInstance()->mPhysicsLODTasks), "DebugStatModeLowLODObjects"); - stat_barp->mPrecision = 0; - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 500.f; - stat_barp->mTickSpacing = 10.f; - stat_barp->mLabelSpacing = 40.f; - stat_barp->mPerSec = FALSE; - stat_barp->mDisplayMean = FALSE; - - stat_barp = phys_details_viewp->addStat("Memory Allocated", &(LLViewerStats::getInstance()->mPhysicsMemoryAllocated), "DebugStatModeMemoryAllocated"); - stat_barp->setUnitLabel(" MB"); - stat_barp->mPrecision = 0; - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 1024.f; - stat_barp->mTickSpacing = 128.f; - stat_barp->mLabelSpacing = 256.f; - stat_barp->mPerSec = FALSE; - stat_barp->mDisplayMean = FALSE; - - stat_barp = sim_statviewp->addStat("Agent Updates/Sec", &(LLViewerStats::getInstance()->mSimAgentUPS), "DebugStatModeAgentUpdatesSec"); - stat_barp->mPrecision = 1; - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 100.f; - stat_barp->mTickSpacing = 25.f; - stat_barp->mLabelSpacing = 50.f; - stat_barp->mPerSec = FALSE; - stat_barp->mDisplayMean = FALSE; - - stat_barp = sim_statviewp->addStat("Main Agents", &(LLViewerStats::getInstance()->mSimMainAgents), "DebugStatModeMainAgents"); - stat_barp->mPrecision = 0; - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 80.f; - stat_barp->mTickSpacing = 10.f; - stat_barp->mLabelSpacing = 40.f; - stat_barp->mPerSec = FALSE; - stat_barp->mDisplayMean = FALSE; - - stat_barp = sim_statviewp->addStat("Child Agents", &(LLViewerStats::getInstance()->mSimChildAgents), "DebugStatModeChildAgents"); - stat_barp->mPrecision = 0; - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 40.f; - stat_barp->mTickSpacing = 5.f; - stat_barp->mLabelSpacing = 10.f; - stat_barp->mPerSec = FALSE; - stat_barp->mDisplayMean = FALSE; - - stat_barp = sim_statviewp->addStat("Objects", &(LLViewerStats::getInstance()->mSimObjects), "DebugStatModeSimObjects"); - stat_barp->mPrecision = 0; - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 30000.f; - stat_barp->mTickSpacing = 5000.f; - stat_barp->mLabelSpacing = 10000.f; - stat_barp->mPerSec = FALSE; - stat_barp->mDisplayMean = FALSE; - - stat_barp = sim_statviewp->addStat("Active Objects", &(LLViewerStats::getInstance()->mSimActiveObjects), "DebugStatModeSimActiveObjects"); - stat_barp->mPrecision = 0; - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 800.f; - stat_barp->mTickSpacing = 100.f; - stat_barp->mLabelSpacing = 200.f; - stat_barp->mPerSec = FALSE; - stat_barp->mDisplayMean = FALSE; - - stat_barp = sim_statviewp->addStat("Active Scripts", &(LLViewerStats::getInstance()->mSimActiveScripts), "DebugStatModeSimActiveScripts"); - stat_barp->mPrecision = 0; - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 800.f; - stat_barp->mTickSpacing = 100.f; - stat_barp->mLabelSpacing = 200.f; - stat_barp->mPerSec = FALSE; - stat_barp->mDisplayMean = FALSE; - - stat_barp = sim_statviewp->addStat("Scripts Run", &(LLViewerStats::getInstance()->mSimPctScriptsRun), std::string(), false, true); - stat_barp->setUnitLabel("%"); - stat_barp->mPrecision = 3; - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 100.f; - stat_barp->mTickSpacing = 10.f; - stat_barp->mLabelSpacing = 20.f; - stat_barp->mPerSec = FALSE; - - stat_barp = sim_statviewp->addStat("Script Events", &(LLViewerStats::getInstance()->mSimScriptEPS), "DebugStatModeSimScriptEvents"); - stat_barp->setUnitLabel(" eps"); - stat_barp->mPrecision = 0; - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 20000.f; - stat_barp->mTickSpacing = 2500.f; - stat_barp->mLabelSpacing = 5000.f; - stat_barp->mPerSec = FALSE; - stat_barp->mDisplayMean = FALSE; + LLStatView* phys_details_viewp = sim_statviewp->addStatView(params); + + { + LLStatBar::Parameters params; + params.mPrecision = 0; + params.mMinBar = 0.f; + params.mMaxBar = 500.f; + params.mTickSpacing = 10.f; + params.mLabelSpacing = 40.f; + params.mPerSec = FALSE; + params.mDisplayMean = FALSE; + phys_details_viewp->addStat("Pinned Objects", &(LLViewerStats::getInstance()->mPhysicsPinnedTasks), params, "DebugStatModePinnedObjects"); + } + + { + LLStatBar::Parameters params; + params.mPrecision = 0; + params.mMinBar = 0.f; + params.mMaxBar = 500.f; + params.mTickSpacing = 10.f; + params.mLabelSpacing = 40.f; + params.mPerSec = FALSE; + params.mDisplayMean = FALSE; + phys_details_viewp->addStat("Low LOD Objects", &(LLViewerStats::getInstance()->mPhysicsLODTasks), params, "DebugStatModeLowLODObjects"); + } + + { + LLStatBar::Parameters params; + params.mUnitLabel = " MB"; + params.mPrecision = 0; + params.mMinBar = 0.f; + params.mMaxBar = 1024.f; + params.mTickSpacing = 128.f; + params.mLabelSpacing = 256.f; + params.mPerSec = FALSE; + params.mDisplayMean = FALSE; + phys_details_viewp->addStat("Memory Allocated", &(LLViewerStats::getInstance()->mPhysicsMemoryAllocated), params, "DebugStatModeMemoryAllocated"); + } + + { + LLStatBar::Parameters params; + params.mPrecision = 1; + params.mMinBar = 0.f; + params.mMaxBar = 100.f; + params.mTickSpacing = 25.f; + params.mLabelSpacing = 50.f; + params.mPerSec = FALSE; + params.mDisplayMean = FALSE; + sim_statviewp->addStat("Agent Updates/Sec", &(LLViewerStats::getInstance()->mSimAgentUPS), params, "DebugStatModeAgentUpdatesSec"); + } + + { + LLStatBar::Parameters params; + params.mPrecision = 0; + params.mMinBar = 0.f; + params.mMaxBar = 80.f; + params.mTickSpacing = 10.f; + params.mLabelSpacing = 40.f; + params.mPerSec = FALSE; + params.mDisplayMean = FALSE; + sim_statviewp->addStat("Main Agents", &(LLViewerStats::getInstance()->mSimMainAgents), params, "DebugStatModeMainAgents"); + } + + { + LLStatBar::Parameters params; + params.mPrecision = 0; + params.mMinBar = 0.f; + params.mMaxBar = 40.f; + params.mTickSpacing = 5.f; + params.mLabelSpacing = 10.f; + params.mPerSec = FALSE; + params.mDisplayMean = FALSE; + sim_statviewp->addStat("Child Agents", &(LLViewerStats::getInstance()->mSimChildAgents), params, "DebugStatModeChildAgents"); + } + + { + LLStatBar::Parameters params; + params.mPrecision = 0; + params.mMinBar = 0.f; + params.mMaxBar = 30000.f; + params.mTickSpacing = 5000.f; + params.mLabelSpacing = 10000.f; + params.mPerSec = FALSE; + params.mDisplayMean = FALSE; + sim_statviewp->addStat("Objects", &(LLViewerStats::getInstance()->mSimObjects), params, "DebugStatModeSimObjects"); + } + + { + LLStatBar::Parameters params; + params.mPrecision = 0; + params.mMinBar = 0.f; + params.mMaxBar = 800.f; + params.mTickSpacing = 100.f; + params.mLabelSpacing = 200.f; + params.mPerSec = FALSE; + params.mDisplayMean = FALSE; + sim_statviewp->addStat("Active Objects", &(LLViewerStats::getInstance()->mSimActiveObjects), params, "DebugStatModeSimActiveObjects"); + } + + { + LLStatBar::Parameters params; + params.mPrecision = 0; + params.mMinBar = 0.f; + params.mMaxBar = 800.f; + params.mTickSpacing = 100.f; + params.mLabelSpacing = 200.f; + params.mPerSec = FALSE; + params.mDisplayMean = FALSE; + sim_statviewp->addStat("Active Scripts", &(LLViewerStats::getInstance()->mSimActiveScripts), params, "DebugStatModeSimActiveScripts"); + } + + { + LLStatBar::Parameters params; + params.mUnitLabel = "%"; + params.mPrecision = 3; + params.mMinBar = 0.f; + params.mMaxBar = 100.f; + params.mTickSpacing = 10.f; + params.mLabelSpacing = 20.f; + params.mPerSec = FALSE; + sim_statviewp->addStat("Scripts Run", &(LLViewerStats::getInstance()->mSimPctScriptsRun), params, std::string(), false, true); + } + + { + LLStatBar::Parameters params; + params.mUnitLabel = " eps"; + params.mPrecision = 0; + params.mMinBar = 0.f; + params.mMaxBar = 20000.f; + params.mTickSpacing = 2500.f; + params.mLabelSpacing = 5000.f; + params.mPerSec = FALSE; + params.mDisplayMean = FALSE; + sim_statviewp->addStat("Script Events", &(LLViewerStats::getInstance()->mSimScriptEPS), params, "DebugStatModeSimScriptEvents"); + } params.name("pathfinding view"); params.show_label(true); params.label("Pathfinding Details"); params.rect(rect); - LLStatView *pathfinding_viewp = sim_statviewp->addStatView(params); - - stat_barp = pathfinding_viewp->addStat("AI Step Time", &(LLViewerStats::getInstance()->mSimSimAIStepMsec)); - stat_barp->setUnitLabel("ms"); - stat_barp->mPrecision = 3; - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 40.f; - stat_barp->mTickSpacing = 10.f; - stat_barp->mLabelSpacing = 20.f; - stat_barp->mPerSec = FALSE; - stat_barp->mDisplayMean = FALSE; - - stat_barp = render_statviewp->addStat("Skipped Silhouette Steps", &(LLViewerStats::getInstance()->mSimSimSkippedSilhouetteSteps)); - stat_barp->setUnitLabel("/sec"); - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 45.f; - stat_barp->mTickSpacing = 4.f; - stat_barp->mLabelSpacing = 8.f; - stat_barp->mPrecision = 0; - - stat_barp = pathfinding_viewp->addStat("Characters Updated", &(LLViewerStats::getInstance()->mSimSimPctSteppedCharacters)); - stat_barp->setUnitLabel("%"); - stat_barp->mPrecision = 1; - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 100.f; - stat_barp->mTickSpacing = 10.f; - stat_barp->mLabelSpacing = 20.f; - stat_barp->mPerSec = FALSE; - stat_barp->mDisplayMean = TRUE; - - stat_barp = sim_statviewp->addStat("Packets In", &(LLViewerStats::getInstance()->mSimInPPS), "DebugStatModeSimInPPS"); - stat_barp->setUnitLabel(" pps"); - stat_barp->mPrecision = 0; - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 2000.f; - stat_barp->mTickSpacing = 250.f; - stat_barp->mLabelSpacing = 1000.f; - stat_barp->mPerSec = FALSE; - stat_barp->mDisplayMean = FALSE; - - stat_barp = sim_statviewp->addStat("Packets Out", &(LLViewerStats::getInstance()->mSimOutPPS), "DebugStatModeSimOutPPS"); - stat_barp->setUnitLabel(" pps"); - stat_barp->mPrecision = 0; - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 2000.f; - stat_barp->mTickSpacing = 250.f; - stat_barp->mLabelSpacing = 1000.f; - stat_barp->mPerSec = FALSE; - stat_barp->mDisplayMean = FALSE; - - stat_barp = sim_statviewp->addStat("Pending Downloads", &(LLViewerStats::getInstance()->mSimPendingDownloads), "DebugStatModeSimPendingDownloads"); - stat_barp->mPrecision = 0; - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 800.f; - stat_barp->mTickSpacing = 100.f; - stat_barp->mLabelSpacing = 200.f; - stat_barp->mPerSec = FALSE; - stat_barp->mDisplayMean = FALSE; - - stat_barp = sim_statviewp->addStat("Pending Uploads", &(LLViewerStats::getInstance()->mSimPendingUploads), "SimPendingUploads"); - stat_barp->mPrecision = 0; - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 100.f; - stat_barp->mTickSpacing = 25.f; - stat_barp->mLabelSpacing = 50.f; - stat_barp->mPerSec = FALSE; - stat_barp->mDisplayMean = FALSE; - - stat_barp = sim_statviewp->addStat("Total Unacked Bytes", &(LLViewerStats::getInstance()->mSimTotalUnackedBytes), "DebugStatModeSimTotalUnackedBytes"); - stat_barp->setUnitLabel(" kb"); - stat_barp->mPrecision = 0; - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 100000.f; - stat_barp->mTickSpacing = 25000.f; - stat_barp->mLabelSpacing = 50000.f; - stat_barp->mPerSec = FALSE; - stat_barp->mDisplayMean = FALSE; + LLStatView* pathfinding_viewp = sim_statviewp->addStatView(params); + + { + LLStatBar::Parameters params; + params.mUnitLabel = "ms"; + params.mPrecision = 3; + params.mMinBar = 0.f; + params.mMaxBar = 40.f; + params.mTickSpacing = 10.f; + params.mLabelSpacing = 20.f; + params.mPerSec = FALSE; + params.mDisplayMean = FALSE; + pathfinding_viewp->addStat("AI Step Time", &(LLViewerStats::getInstance()->mSimSimAIStepMsec), params); + } + + { + LLStatBar::Parameters params; + params.mUnitLabel = "/sec"; + params.mMinBar = 0.f; + params.mMaxBar = 45.f; + params.mTickSpacing = 4.f; + params.mLabelSpacing = 8.f; + params.mPrecision = 0; + render_statviewp->addStat("Skipped Silhouette Steps", &(LLViewerStats::getInstance()->mSimSimSkippedSilhouetteSteps), params); + } + + { + LLStatBar::Parameters params; + params.mUnitLabel = "%"; + params.mPrecision = 1; + params.mMinBar = 0.f; + params.mMaxBar = 100.f; + params.mTickSpacing = 10.f; + params.mLabelSpacing = 20.f; + params.mPerSec = FALSE; + params.mDisplayMean = TRUE; + pathfinding_viewp->addStat("Characters Updated", &(LLViewerStats::getInstance()->mSimSimPctSteppedCharacters), params); + } + + { + LLStatBar::Parameters params; + params.mUnitLabel = " pps"; + params.mPrecision = 0; + params.mMinBar = 0.f; + params.mMaxBar = 2000.f; + params.mTickSpacing = 250.f; + params.mLabelSpacing = 1000.f; + params.mPerSec = FALSE; + params.mDisplayMean = FALSE; + sim_statviewp->addStat("Packets In", &(LLViewerStats::getInstance()->mSimInPPS), params, "DebugStatModeSimInPPS"); + } + + { + LLStatBar::Parameters params; + params.mUnitLabel = " pps"; + params.mPrecision = 0; + params.mMinBar = 0.f; + params.mMaxBar = 2000.f; + params.mTickSpacing = 250.f; + params.mLabelSpacing = 1000.f; + params.mPerSec = FALSE; + params.mDisplayMean = FALSE; + sim_statviewp->addStat("Packets Out", &(LLViewerStats::getInstance()->mSimOutPPS), params, "DebugStatModeSimOutPPS"); + } + + { + LLStatBar::Parameters params; + params.mPrecision = 0; + params.mMinBar = 0.f; + params.mMaxBar = 800.f; + params.mTickSpacing = 100.f; + params.mLabelSpacing = 200.f; + params.mPerSec = FALSE; + params.mDisplayMean = FALSE; + sim_statviewp->addStat("Pending Downloads", &(LLViewerStats::getInstance()->mSimPendingDownloads), params, "DebugStatModeSimPendingDownloads"); + } + + { + LLStatBar::Parameters params; + params.mPrecision = 0; + params.mMinBar = 0.f; + params.mMaxBar = 100.f; + params.mTickSpacing = 25.f; + params.mLabelSpacing = 50.f; + params.mPerSec = FALSE; + params.mDisplayMean = FALSE; + sim_statviewp->addStat("Pending Uploads", &(LLViewerStats::getInstance()->mSimPendingUploads), params, "SimPendingUploads"); + } + + { + LLStatBar::Parameters params; + params.mUnitLabel = " kb"; + params.mPrecision = 0; + params.mMinBar = 0.f; + params.mMaxBar = 100000.f; + params.mTickSpacing = 25000.f; + params.mLabelSpacing = 50000.f; + params.mPerSec = FALSE; + params.mDisplayMean = FALSE; + sim_statviewp->addStat("Total Unacked Bytes", &(LLViewerStats::getInstance()->mSimTotalUnackedBytes), params, "DebugStatModeSimTotalUnackedBytes"); + } params.name("sim perf view"); params.show_label(true); params.label("Time (ms)"); params.setting("OpenDebugStatSimTime"); params.rect(rect); - LLStatView *sim_time_viewp = sim_statviewp->addStatView(params); - - stat_barp = sim_time_viewp->addStat("Total Frame Time", &(LLViewerStats::getInstance()->mSimFrameMsec), "DebugStatModeSimFrameMsec"); - stat_barp->setUnitLabel("ms"); - stat_barp->mPrecision = 1; - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 40.f; - stat_barp->mTickSpacing = 10.f; - stat_barp->mLabelSpacing = 20.f; - stat_barp->mPerSec = FALSE; - stat_barp->mDisplayMean = FALSE; - - stat_barp = sim_time_viewp->addStat("Net Time", &(LLViewerStats::getInstance()->mSimNetMsec), "DebugStatModeSimNetMsec"); - stat_barp->setUnitLabel("ms"); - stat_barp->mPrecision = 1; - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 40.f; - stat_barp->mTickSpacing = 10.f; - stat_barp->mLabelSpacing = 20.f; - stat_barp->mPerSec = FALSE; - stat_barp->mDisplayMean = FALSE; - - stat_barp = sim_time_viewp->addStat("Physics Time", &(LLViewerStats::getInstance()->mSimSimPhysicsMsec), "DebugStatModeSimSimPhysicsMsec"); - stat_barp->setUnitLabel("ms"); - stat_barp->mPrecision = 1; - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 40.f; - stat_barp->mTickSpacing = 10.f; - stat_barp->mLabelSpacing = 20.f; - stat_barp->mPerSec = FALSE; - stat_barp->mDisplayMean = FALSE; - - stat_barp = sim_time_viewp->addStat("Simulation Time", &(LLViewerStats::getInstance()->mSimSimOtherMsec), "DebugStatModeSimSimOtherMsec"); - stat_barp->setUnitLabel("ms"); - stat_barp->mPrecision = 1; - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 40.f; - stat_barp->mTickSpacing = 10.f; - stat_barp->mLabelSpacing = 20.f; - stat_barp->mPerSec = FALSE; - stat_barp->mDisplayMean = FALSE; - - stat_barp = sim_time_viewp->addStat("Agent Time", &(LLViewerStats::getInstance()->mSimAgentMsec), "DebugStatModeSimAgentMsec"); - stat_barp->setUnitLabel("ms"); - stat_barp->mPrecision = 1; - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 40.f; - stat_barp->mTickSpacing = 10.f; - stat_barp->mLabelSpacing = 20.f; - stat_barp->mPerSec = FALSE; - stat_barp->mDisplayMean = FALSE; - - stat_barp = sim_time_viewp->addStat("Images Time", &(LLViewerStats::getInstance()->mSimImagesMsec), "DebugStatModeSimImagesMsec"); - stat_barp->setUnitLabel("ms"); - stat_barp->mPrecision = 1; - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 40.f; - stat_barp->mTickSpacing = 10.f; - stat_barp->mLabelSpacing = 20.f; - stat_barp->mPerSec = FALSE; - stat_barp->mDisplayMean = FALSE; - - stat_barp = sim_time_viewp->addStat("Script Time", &(LLViewerStats::getInstance()->mSimScriptMsec), "DebugStatModeSimScriptMsec"); - stat_barp->setUnitLabel("ms"); - stat_barp->mPrecision = 1; - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 40.f; - stat_barp->mTickSpacing = 10.f; - stat_barp->mLabelSpacing = 20.f; - stat_barp->mPerSec = FALSE; - stat_barp->mDisplayMean = FALSE; - - stat_barp = sim_time_viewp->addStat("Spare Time", &(LLViewerStats::getInstance()->mSimSpareMsec), "DebugStatModeSimSpareMsec"); - stat_barp->setUnitLabel("ms"); - stat_barp->mPrecision = 1; - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 40.f; - stat_barp->mTickSpacing = 10.f; - stat_barp->mLabelSpacing = 20.f; - stat_barp->mPerSec = FALSE; - stat_barp->mDisplayMean = FALSE; + LLStatView* sim_time_viewp = sim_statviewp->addStatView(params); + + { + LLStatBar::Parameters params; + params.mUnitLabel = "ms"; + params.mPrecision = 1; + params.mMinBar = 0.f; + params.mMaxBar = 40.f; + params.mTickSpacing = 10.f; + params.mLabelSpacing = 20.f; + params.mPerSec = FALSE; + params.mDisplayMean = FALSE; + sim_time_viewp->addStat("Total Frame Time", &(LLViewerStats::getInstance()->mSimFrameMsec), params, "DebugStatModeSimFrameMsec"); + } + + { + LLStatBar::Parameters params; + params.mUnitLabel = "ms"; + params.mPrecision = 1; + params.mMinBar = 0.f; + params.mMaxBar = 40.f; + params.mTickSpacing = 10.f; + params.mLabelSpacing = 20.f; + params.mPerSec = FALSE; + params.mDisplayMean = FALSE; + sim_time_viewp->addStat("Net Time", &(LLViewerStats::getInstance()->mSimNetMsec), params, "DebugStatModeSimNetMsec"); + } + + { + LLStatBar::Parameters params; + params.mUnitLabel = "ms"; + params.mPrecision = 1; + params.mMinBar = 0.f; + params.mMaxBar = 40.f; + params.mTickSpacing = 10.f; + params.mLabelSpacing = 20.f; + params.mPerSec = FALSE; + params.mDisplayMean = FALSE; + sim_time_viewp->addStat("Physics Time", &(LLViewerStats::getInstance()->mSimSimPhysicsMsec), params, "DebugStatModeSimSimPhysicsMsec"); + } + + { + LLStatBar::Parameters params; + params.mUnitLabel ="ms"; + params.mPrecision = 1; + params.mMinBar = 0.f; + params.mMaxBar = 40.f; + params.mTickSpacing = 10.f; + params.mLabelSpacing = 20.f; + params.mPerSec = FALSE; + params.mDisplayMean = FALSE; + sim_time_viewp->addStat("Simulation Time", &(LLViewerStats::getInstance()->mSimSimOtherMsec), params, "DebugStatModeSimSimOtherMsec"); + } + + { + LLStatBar::Parameters params; + params.mUnitLabel ="ms"; + params.mPrecision = 1; + params.mMinBar = 0.f; + params.mMaxBar = 40.f; + params.mTickSpacing = 10.f; + params.mLabelSpacing = 20.f; + params.mPerSec = FALSE; + params.mDisplayMean = FALSE; + sim_time_viewp->addStat("Agent Time", &(LLViewerStats::getInstance()->mSimAgentMsec), params, "DebugStatModeSimAgentMsec"); + } + + { + LLStatBar::Parameters params; + params.mUnitLabel ="ms"; + params.mPrecision = 1; + params.mMinBar = 0.f; + params.mMaxBar = 40.f; + params.mTickSpacing = 10.f; + params.mLabelSpacing = 20.f; + params.mPerSec = FALSE; + params.mDisplayMean = FALSE; + sim_time_viewp->addStat("Images Time", &(LLViewerStats::getInstance()->mSimImagesMsec), params, "DebugStatModeSimImagesMsec"); + } + + { + LLStatBar::Parameters params; + params.mUnitLabel ="ms"; + params.mPrecision = 1; + params.mMinBar = 0.f; + params.mMaxBar = 40.f; + params.mTickSpacing = 10.f; + params.mLabelSpacing = 20.f; + params.mPerSec = FALSE; + params.mDisplayMean = FALSE; + sim_time_viewp->addStat("Script Time", &(LLViewerStats::getInstance()->mSimScriptMsec), params, "DebugStatModeSimScriptMsec"); + } + { + LLStatBar::Parameters params; + params.mUnitLabel = "ms"; + params.mPrecision = 1; + params.mMinBar = 0.f; + params.mMaxBar = 40.f; + params.mTickSpacing = 10.f; + params.mLabelSpacing = 20.f; + params.mPerSec = FALSE; + params.mDisplayMean = FALSE; + sim_time_viewp->addStat("Spare Time", &(LLViewerStats::getInstance()->mSimSpareMsec), params, "DebugStatModeSimSpareMsec"); + } // 2nd level time blocks under 'Details' second params.name("sim perf view"); @@ -648,56 +808,70 @@ void LLFloaterStats::buildStats() params.setting("OpenDebugStatSimTimeDetails"); params.rect(rect); LLStatView *detailed_time_viewp = sim_time_viewp->addStatView(params); + + { + LLStatBar::Parameters params; + params.mUnitLabel ="ms"; + params.mPrecision = 1; + params.mMinBar = 0.f; + params.mMaxBar = 40.f; + params.mTickSpacing = 10.f; + params.mLabelSpacing = 20.f; + params.mPerSec = FALSE; + params.mDisplayMean = FALSE; + detailed_time_viewp->addStat(" Physics Step", &(LLViewerStats::getInstance()->mSimSimPhysicsStepMsec), params, "DebugStatModeSimSimPhysicsStepMsec"); + } + + { + LLStatBar::Parameters params; + params.mUnitLabel ="ms"; + params.mPrecision = 1; + params.mMinBar = 0.f; + params.mMaxBar = 40.f; + params.mTickSpacing = 10.f; + params.mLabelSpacing = 20.f; + params.mPerSec = FALSE; + params.mDisplayMean = FALSE; + detailed_time_viewp->addStat(" Update Physics Shapes", &(LLViewerStats::getInstance()->mSimSimPhysicsShapeUpdateMsec), params, "DebugStatModeSimSimPhysicsShapeUpdateMsec"); + } + + { + LLStatBar::Parameters params; + params.mUnitLabel ="ms"; + params.mPrecision = 1; + params.mMinBar = 0.f; + params.mMaxBar = 40.f; + params.mTickSpacing = 10.f; + params.mLabelSpacing = 20.f; + params.mPerSec = FALSE; + params.mDisplayMean = FALSE; + detailed_time_viewp->addStat(" Physics Other", &(LLViewerStats::getInstance()->mSimSimPhysicsOtherMsec), params, "DebugStatModeSimSimPhysicsOtherMsec"); + } + + { + LLStatBar::Parameters params; + params.mUnitLabel ="ms"; + params.mPrecision = 1; + params.mMinBar = 0.f; + params.mMaxBar = 40.f; + params.mTickSpacing = 10.f; + params.mLabelSpacing = 20.f; + params.mPerSec = FALSE; + params.mDisplayMean = FALSE; + detailed_time_viewp->addStat(" Sleep Time", &(LLViewerStats::getInstance()->mSimSleepMsec), params, "DebugStatModeSimSleepMsec"); + } + { - stat_barp = detailed_time_viewp->addStat(" Physics Step", &(LLViewerStats::getInstance()->mSimSimPhysicsStepMsec), "DebugStatModeSimSimPhysicsStepMsec"); - stat_barp->setUnitLabel("ms"); - stat_barp->mPrecision = 1; - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 40.f; - stat_barp->mTickSpacing = 10.f; - stat_barp->mLabelSpacing = 20.f; - stat_barp->mPerSec = FALSE; - stat_barp->mDisplayMean = FALSE; - - stat_barp = detailed_time_viewp->addStat(" Update Physics Shapes", &(LLViewerStats::getInstance()->mSimSimPhysicsShapeUpdateMsec), "DebugStatModeSimSimPhysicsShapeUpdateMsec"); - stat_barp->setUnitLabel("ms"); - stat_barp->mPrecision = 1; - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 40.f; - stat_barp->mTickSpacing = 10.f; - stat_barp->mLabelSpacing = 20.f; - stat_barp->mPerSec = FALSE; - stat_barp->mDisplayMean = FALSE; - - stat_barp = detailed_time_viewp->addStat(" Physics Other", &(LLViewerStats::getInstance()->mSimSimPhysicsOtherMsec), "DebugStatModeSimSimPhysicsOtherMsec"); - stat_barp->setUnitLabel("ms"); - stat_barp->mPrecision = 1; - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 40.f; - stat_barp->mTickSpacing = 10.f; - stat_barp->mLabelSpacing = 20.f; - stat_barp->mPerSec = FALSE; - stat_barp->mDisplayMean = FALSE; - - stat_barp = detailed_time_viewp->addStat(" Sleep Time", &(LLViewerStats::getInstance()->mSimSleepMsec), "DebugStatModeSimSleepMsec"); - stat_barp->setUnitLabel("ms"); - stat_barp->mPrecision = 1; - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 40.f; - stat_barp->mTickSpacing = 10.f; - stat_barp->mLabelSpacing = 20.f; - stat_barp->mPerSec = FALSE; - stat_barp->mDisplayMean = FALSE; - - stat_barp = detailed_time_viewp->addStat(" Pump IO", &(LLViewerStats::getInstance()->mSimPumpIOMsec), "DebugStatModeSimPumpIOMsec"); - stat_barp->setUnitLabel("ms"); - stat_barp->mPrecision = 1; - stat_barp->mMinBar = 0.f; - stat_barp->mMaxBar = 40.f; - stat_barp->mTickSpacing = 10.f; - stat_barp->mLabelSpacing = 20.f; - stat_barp->mPerSec = FALSE; - stat_barp->mDisplayMean = FALSE; + LLStatBar::Parameters params; + params.mUnitLabel ="ms"; + params.mPrecision = 1; + params.mMinBar = 0.f; + params.mMaxBar = 40.f; + params.mTickSpacing = 10.f; + params.mLabelSpacing = 20.f; + params.mPerSec = FALSE; + params.mDisplayMean = FALSE; + detailed_time_viewp->addStat(" Pump IO", &(LLViewerStats::getInstance()->mSimPumpIOMsec), params, "DebugStatModeSimPumpIOMsec"); } LLRect r = getRect(); diff --git a/indra/newview/llfloaterteleport.cpp b/indra/newview/llfloaterteleport.cpp deleted file mode 100644 index dd546c5b05..0000000000 --- a/indra/newview/llfloaterteleport.cpp +++ /dev/null @@ -1,332 +0,0 @@ -/** - * @file llfloaterteleport.cpp - * @brief floater code for agentd teleports. - * - * $LicenseInfo:firstyear=2008&license=viewergpl$ - * - * Copyright (c) 2008, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ -//Teleport floater used for agent domain TP. URI text floater. -//Copyright International Business Machines Corporation 2008-9 -//Contributed to Linden Research, Inc. under the Second Life Viewer Contribution -//Agreement and licensed as above. -#include "llviewerprecompiledheaders.h" // must be first include - -#include "llfloaterteleport.h" - -#include "llagent.h" //for hack in teleport start -#include "llchat.h" -#include "llcombobox.h" -#include "llfloaterchat.h" -#include "llsdserialize.h" -#include "llsdutil.h" -#include "llsdutil_math.h" -#include "lluictrlfactory.h" // builds floaters from XML -#include "llurlhistory.h" -#include "lluserauth.h" // for saving placeavatarresponder result -#include "llviewercontrol.h" // for gSavedSettings -#include "llviewerdisplay.h" // for gTeleportDisplay -#include "llviewermessage.h" // for send_agent_movement_complete attempt -#include "llviewerregion.h" -#include "llviewerwindow.h" // for hack in teleport start -#include "llvoavatar.h" -#include "llworld.h" -#include "pipeline.h" // for gPipeline - -class AIHTTPTimeoutPolicy; -extern AIHTTPTimeoutPolicy placeAvatarTeleportResponder_timeout; - -// OGPX HTTP responder for PlaceAvatar cap used for Teleport -// very similar to the responder in Login, but not as many fields are returned in the TP version -// OGPX TODO: should this be combined with the Login responder for rez_avatar/place? -// OGPX TODO: mResult should not get replaced in result(), instead -// should replace individual LLSD fields in mResult. -class LLPlaceAvatarTeleportResponder : public LLHTTPClient::ResponderWithResult -{ -public: - LLPlaceAvatarTeleportResponder() - { - } - - ~LLPlaceAvatarTeleportResponder() - { - } - - /*virtual*/ void error(U32 statusNum, const std::string& reason) - { - LL_INFOS("OGPX") << "LLPlaceAvatarTeleportResponder error in TP " - << statusNum << " " << reason << LL_ENDL; - - LLSD args; - args["REASON"] = reason; - - - LLNotificationsUtil::add("CouldNotTeleportReason", args); - - gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); - - } - - /*virtual*/ void result(const LLSD& content) - { - - LLSD result; - result["agent_id"] = content["agent_id"]; // need this for send_complete_agent_movement - result["region_x"] = content["region_x"]; // need these for making the first region - result["region_y"] = content["region_y"]; - result["login"] = "true"; // this gets checked in idle_startup() - result["session_id"] = content["session_id"]; - result["secure_session_id"] = content["secure_session_id"]; - result["circuit_code"] = content["circuit_code"]; - result["sim_port"] = content["sim_port"]; - result["sim_host"] = content["sim_host"]; - result["look_at"] = content["look_at"]; - // maintaining result seed_capability name for compatibility with legacy login - result["seed_capability"] = content["region_seed_capability"]; - result["position"] = content["position"]; // save this for agentmovementcomplete type processing - - // Even though we have the pretty print of the complete content returned, we still find it handy - // when scanning SecondLife.log to have these laid out in this way. So they are still here. - LL_DEBUGS("OGPX") << " Teleport placeAvatar responder " << LL_ENDL; - LL_DEBUGS("OGPX") << "agent_id: " << content["agent_id"] << LL_ENDL; - LL_DEBUGS("OGPX") << "region_x: " << content["region_x"] << LL_ENDL; - LL_DEBUGS("OGPX") << "session_id: " << content["session_id"] << LL_ENDL; - LL_DEBUGS("OGPX") << "sim_port: " << content["sim_port"] << LL_ENDL; - LL_DEBUGS("OGPX") << "sim_host: " << content["sim_host"] << LL_ENDL; - LL_DEBUGS("OGPX") << "look_at: " << content["look_at"] << LL_ENDL; - LL_DEBUGS("OGPX") << "position: " << content["position"] << LL_ENDL; - LL_DEBUGS("OGPX") << "seed_capability: " << content["region_seed_capability"] << LL_ENDL; - - LL_INFOS("OGPX") << " All the LLSD PlaceAvatarTeleportResponder content: \n " << ll_pretty_print_sd(content) << LL_ENDL; // OGPX - - - // check "connect" to make sure place_avatar fully successful - if (!content["connect"].asBoolean()) - { - // place_avatar failed somewhere - LL_INFOS("OGPX") << "TP failed, connect false in TP PlaceAvatarResponder " << LL_ENDL; - - LLSD args; - args["REASON"] = "Place Avatar Failed"; - - //gViewerWindow->alertXml("CouldNotTeleportReason", args); - LLNotificationsUtil::add("CouldNotTeleportReason",args); - - gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); - - return; - } - - - U64 region_handle; - region_handle = to_region_handle_global(content["region_x"].asInteger(), content["region_y"].asInteger()); - - LLHost sim_host; - U32 sim_port = strtoul(result["sim_port"].asString().c_str(), NULL, 10); - sim_host.setHostByName(result["sim_host"].asString().c_str()); - sim_host.setPort(sim_port); - - if (sim_host.isOk()) - { - LLMessageSystem* msg = gMessageSystem; - gMessageSystem->enableCircuit(sim_host, TRUE); - msg->newMessageFast(_PREHASH_UseCircuitCode); - msg->nextBlockFast(_PREHASH_CircuitCode); - msg->addU32Fast(_PREHASH_Code, msg->getOurCircuitCode()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->addUUIDFast(_PREHASH_ID, gAgent.getID()); - msg->sendReliable(sim_host); - } - else - { - LL_INFOS("OGPX") << "TP failed, could not resolve hostname for UDP messages." << LL_ENDL; - LLSD args; - args["REASON"] = "Failed to resolve host."; - //gViewerWindow->alertXml("CouldNotTeleportReason", args); - LLNotificationsUtil::add("CouldNotTeleportReason", args); - gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); - return; - } - - - - - // Viewer trusts the simulator. - LLViewerRegion* regionp = LLWorld::getInstance()->addRegion(region_handle, sim_host); - regionp->setSeedCapability(content["seed_capability"].asString().c_str()); - // process_agent_movement_complete needs the region to still be the old region gAgent.setRegion(regionp); - - // placing these in result so they can be set properly in LLUserAuth result - // ...they are only passed in on login, and not on TP - result["session_id"] = gAgent.getSessionID(); - result["agent_id"] = gAgent.getID(); - result["circuit_code"].asString() = gMessageSystem->mOurCircuitCode; // this is what startup sets, is this proper to do? - - // grab the skeleton and root. - result["inventory-skeleton"] = LLUserAuth::getInstance()->mResult["inventory-skeleton"]; - result["inventory-root"] = LLUserAuth::getInstance()->mResult["inventory-root"]; - - LL_DEBUGS("OGPX") << "session_id: " << result["session_id"] << LL_ENDL; - - - - // results need to be stored so process_agent_movement_complete() can pull them - LLUserAuth::getInstance()->mAuthResponse = LLUserAuth::E_OK; - - // OGPX TODO: This just reeks of causing problems, because we are using - // ... mResult to store things that we get from other caps....So slamming a - // ... completely new result in on teleport is going to cause issues. - // ... It makes changing the things we save in mResult error prone. - // ... Question is, how should we really be storing the seemingly random things - // ... that we get back from (now) various different caps that used to all come back - // ... in the result of XMLRPC authenticate? - LLUserAuth::getInstance()->mResult = result; - - - - // ... new sim not sending me much without sending it CompleteAgentMovement msg. - //gAgent.setTeleportState( LLAgent::TELEPORT_MOVING ); // process_agent_mv_complete looks for TELEPORT_MOVING - LLVector3 position = ll_vector3_from_sd(result["position"]); - gAgent.setHomePosRegion(region_handle, position); // taken from teleport_finish (not sure regular code path gets this) - - send_complete_agent_movement(sim_host); - - // Turn off progress msg (also need to do this in all the possible failure places) - // I think we leave this, as the scene is still changing during the - // processing of agentmovementcomeplete message. TELEPORT_NONE resets it anyway - // gViewerWindow->setShowProgress(FALSE); - - } - - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return placeAvatarTeleportResponder_timeout; } - /*virtual*/ char const* getName(void) const { return "LLPlaceAvatarTeleportResponder"; } -}; - -// Statics -LLFloaterTeleport* LLFloaterTeleport::sInstance = NULL; - -LLFloaterTeleport::LLFloaterTeleport() -: LLFloater("floater_teleport") -{ - if(!sInstance) - { - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_teleport.xml"); - - LLComboBox* regioncombo = getChild("teleport_edit"); - regioncombo->setAllowTextEntry(TRUE, 256, FALSE); // URL bar needs to allow user text input - - // iterate on uri list adding to combobox (couldn't figure out how to add them all in one call) - LLSD regionuri_history = LLURLHistory::getURLHistory("regionuri"); - LLSD::array_iterator iter_history = regionuri_history.beginArray(); - LLSD::array_iterator iter_end = regionuri_history.endArray(); - for(; iter_history != iter_end; ++iter_history) - { - regioncombo->addSimpleElement((*iter_history).asString()); - } - - // select which is displayed if we have a current URL. - regioncombo->setSelectedByValue(LLSD(gSavedSettings.getString("CmdLineRegionURI")),TRUE); - - // TODO : decide if 'enter' when selecting something from the combox box should *not* be sent - // to the floater (p.s. and figure out how to change it) - - childSetAction("teleport_btn", onClickTeleport, this); - childSetAction("cancel_btn", onClickCancel, this); - - setDefaultBtn("teleport_btn"); - } - else - { - sInstance->show(NULL); - } -} - -// static -void LLFloaterTeleport::show(void*) -{ - if (!sInstance) - { - sInstance = new LLFloaterTeleport(); - } - - sInstance->open(); -} - -LLFloaterTeleport::~LLFloaterTeleport() -{ - sInstance=NULL; -} - - - -// static -void LLFloaterTeleport::onClickTeleport(void* userdata) -{ - std::string placeAvatarCap = LLAppViewer::instance()->getPlaceAvatarCap(); - LLSD args; - - LLFloaterTeleport* self = (LLFloaterTeleport*)userdata; - std::string text = self->childGetText("teleport_edit"); - if (text.find("://",0) == std::string::npos) - { - // if there is no uri, prepend it with http:// - text = "http://"+text; - LL_DEBUGS("OGPX") << "Teleport URI was prepended, now " << text << LL_ENDL; - } - - LL_DEBUGS("OGPX") << "onClickTeleport! from using place_avatar cap "<< placeAvatarCap << " contains "<< text << LL_ENDL; - LLStringUtil::trim(text); // trim extra spacing - gAgent.setTeleportSourceURL(gSavedSettings.getString("CmdLineRegionURI")); // grab src region name - gSavedSettings.setString("CmdLineRegionURI",text); // save the dst region - args["public_region_seed_capability"] = text; - args["position"] = ll_sd_from_vector3(LLVector3(128, 128, 50)); // default to middle of region above base terrain - LL_INFOS("OGPX") << " args to placeavatar cap " << placeAvatarCap << " on teleport: " << LLSDOStreamer(args) << LL_ENDL; - LLHTTPClient::post(placeAvatarCap, args, new LLPlaceAvatarTeleportResponder()); - gAgent.setTeleportMessage( - LLAgent::sTeleportProgressMessages["requesting"]); - gViewerWindow->setShowProgress(TRUE); - gAgent.teleportCore(); - gAgent.setTeleportState( LLAgent::TELEPORT_PLACE_AVATAR ); // teleportcore() sets tp state to legacy path, so reset. ick! - gTeleportDisplayTimer.reset(); - - - - self->setVisible(FALSE); - if ( LLURLHistory::appendToURLCollection("regionuri",text)) - { - // since URL history only populated on create of sInstance, add to combo list directly - LLComboBox* regioncombo = self->getChild("teleport_edit"); - // BUG : this should add the new item to the combo box, but doesn't - regioncombo->addSimpleElement(text); - } - -} - -void LLFloaterTeleport::onClickCancel(void *userdata) -{ - LLFloaterTeleport* self = (LLFloaterTeleport*)userdata; - LL_INFOS("OGPX") << "Teleport Cancel " << self->getName() << LL_ENDL; - self->setVisible(FALSE); -} diff --git a/indra/newview/llfloaterteleport.h b/indra/newview/llfloaterteleport.h deleted file mode 100644 index 58e907a68b..0000000000 --- a/indra/newview/llfloaterteleport.h +++ /dev/null @@ -1,65 +0,0 @@ -/** - * @file llfloaterteleport.h - * @brief floater header for agentd teleports. - * - * $LicenseInfo:firstyear=2008&license=viewergpl$ - * - * Copyright (c) 2008, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ -// Teleport floater for agent domain TPs using URIs. -//Copyright International Business Machines Corporation 2008-9 -//Contributed to Linden Research, Inc. under the Second Life Viewer Contribution -//Agreement and licensed as above. -#ifndef LL_FLOATER_TELEPORT_H -#define LL_FLOATER_TELEPORT_H -#include "llfloater.h" - -class LLFloaterTeleport : public LLFloater -{ -public: - LLFloaterTeleport(); - - virtual ~LLFloaterTeleport(); - - // by convention, this shows the floater and does instance management - static void show(void*); - -private: - // when a line editor loses keyboard focus, it is committed. - // commit callbacks are named onCommitWidgetName by convention. - static void onCommitTeleport(LLUICtrl* ctrl, void *userdata); - - // by convention, button callbacks are named onClickButtonLabel - static void onClickTeleport(void* userdata); - static void onClickCancel(void *userdata); - - // no pointers to widgets here - they are referenced by name - - // assuming we just need one, which is typical - static LLFloaterTeleport* sInstance; - -}; -#endif - diff --git a/indra/newview/llfloaterteleporthistory.cpp b/indra/newview/llfloaterteleporthistory.cpp index b3a6bad0cb..f3369782dc 100644 --- a/indra/newview/llfloaterteleporthistory.cpp +++ b/indra/newview/llfloaterteleporthistory.cpp @@ -84,7 +84,7 @@ BOOL LLFloaterTeleportHistory::postBuild() mPlacesList=getChild("places_list"); if (!mPlacesList) { - llwarns << "coud not get pointer to places list" << llendl; + LL_WARNS() << "coud not get pointer to places list" << LL_ENDL; return FALSE; } @@ -107,22 +107,10 @@ void LLFloaterTeleportHistory::addPendingEntry(std::string regionName, S16 x, S1 // Set pending entry timestamp - U32 utc_time; - utc_time = time_corrected(); - struct tm* internal_time; - internal_time = utc_to_pacific_time(utc_time, gPacificDaylightTime); + struct tm* internal_time = utc_to_pacific_time(time_corrected(), gPacificDaylightTime); + timeStructToFormattedString(internal_time, gSavedSettings.getString("ShortDateFormat") + gSavedSettings.getString("LongTimeFormat"), mPendingTimeString); // check if we are in daylight savings time - std::string timeZone = " PST"; - if (gPacificDaylightTime) - { - timeZone = " PDT"; - } -#ifdef LOCALIZED_TIME - timeStructToFormattedString(internal_time, gSavedSettings.getString("LongTimeFormat"), mPendingTimeString); - mPendingTimeString += timeZone; -#else - mPendingTimeString = llformat("%02d:%02d:%02d", internal_time->tm_hour, internal_time->tm_min, internal_time->tm_sec) + timeZone; -#endif + mPendingTimeString += gPacificDaylightTime ? " PDT" : " PST"; // Set pending region name mPendingRegionName = regionName; @@ -169,7 +157,12 @@ void LLFloaterTeleportHistory::addEntry(std::string parcelName) // add the new list entry on top of the list, deselect all and disable the buttons const S32 max_entries = gSavedSettings.getS32("TeleportHistoryMaxEntries"); S32 num_entries = mPlacesList->getItemCount(); - while(num_entries >= max_entries) + if (max_entries <= 0) + { + if (!max_entries) + mPlacesList->clearRows(); + } + else while(num_entries >= max_entries) { mPlacesList->deleteItems(LLSD(mID - num_entries--)); } @@ -182,7 +175,7 @@ void LLFloaterTeleportHistory::addEntry(std::string parcelName) } else { - llwarns << "pointer to places list is NULL" << llendl; + LL_WARNS() << "pointer to places list is NULL" << LL_ENDL; } mPendingRegionName.clear(); @@ -212,19 +205,19 @@ void LLFloaterTeleportHistory::loadFile(const std::string &file_name) if (file.is_open()) { - llinfos << "Loading "<< file_name << " file at " << temp_str << llendl; + LL_INFOS() << "Loading "<< file_name << " file at " << temp_str << LL_ENDL; LLSD data; LLSDSerialize::fromXML(data, file); if (data.isUndefined()) { - llinfos << "file missing, ill-formed, " + LL_INFOS() << "file missing, ill-formed, " "or simply undefined; not reading the" - " file" << llendl; + " file" << LL_ENDL; } else { const S32 max_entries = gSavedSettings.getS32("TeleportHistoryMaxEntries"); - const S32 num_entries = llmin(max_entries,(const S32)data.size()); + const S32 num_entries = llmin(max_entries < 0 ? S32_MAX : max_entries,(const S32)data.size()); pScrollList->clear(); for(S32 i = 0; i < num_entries; i++) //Lower entry = newer { @@ -253,17 +246,17 @@ void LLFloaterTeleportHistory::saveFile(const std::string &file_name) std::string temp_str = gDirUtilp->getLindenUserDir(true); if( temp_str.empty() ) { - llinfos << "Can't save teleport history - no user directory set yet." << llendl; + LL_INFOS() << "Can't save teleport history - no user directory set yet." << LL_ENDL; return; } temp_str += gDirUtilp->getDirDelimiter() + file_name; llofstream export_file(temp_str); if (!export_file.good()) { - llwarns << "Unable to open " << file_name << " for output." << llendl; + LL_WARNS() << "Unable to open " << file_name << " for output." << LL_ENDL; return; } - llinfos << "Writing "<< file_name << " file at " << temp_str << llendl; + LL_INFOS() << "Writing "<< file_name << " file at " << temp_str << LL_ENDL; LLSD elements; LLScrollListCtrl* pScrollList = pFloaterHistory->mPlacesList; diff --git a/indra/newview/llfloatertest.cpp b/indra/newview/llfloatertest.cpp index 22628dc09b..717ba97ff6 100644 --- a/indra/newview/llfloatertest.cpp +++ b/indra/newview/llfloatertest.cpp @@ -81,8 +81,6 @@ class LLFloaterTestImpl : public LLFloater LLIconCtrl* mIcon; LLLineEditor* mLineEditor; LLRadioGroup* mRadioGroup; - LLRadioCtrl* mRadio1; - LLRadioCtrl* mRadio2; LLScrollContainer* mScroll; LLScrollListCtrl* mScrollList; LLTabContainer* mTab; @@ -306,56 +304,56 @@ LLFloaterTestImpl::LLFloaterTestImpl() // static void LLFloaterTestImpl::onClickButton() { - llinfos << "button clicked" << llendl; + LL_INFOS() << "button clicked" << LL_ENDL; } // static void LLFloaterTestImpl::onClickText() { - llinfos << "text clicked" << llendl; + LL_INFOS() << "text clicked" << LL_ENDL; } // static void LLFloaterTestImpl::onClickTab() { - llinfos << "click tab" << llendl; + LL_INFOS() << "click tab" << LL_ENDL; } // static void LLFloaterTestImpl::onCommitCheck() { - llinfos << "commit check" << llendl; + LL_INFOS() << "commit check" << LL_ENDL; } // static void LLFloaterTestImpl::onCommitCombo(LLUICtrl* ctrl, const LLSD& value) { LLComboBox* combo = (LLComboBox*)ctrl; - llinfos << "commit combo name " << combo->getSimple() << " value " << value.asString() << llendl; + LL_INFOS() << "commit combo name " << combo->getSimple() << " value " << value.asString() << LL_ENDL; } // static void LLFloaterTestImpl::onCommitLine() { - llinfos << "commit line editor" << llendl; + LL_INFOS() << "commit line editor" << LL_ENDL; } // static void LLFloaterTestImpl::onKeyLine() { - llinfos << "keystroke line editor" << llendl; + LL_INFOS() << "keystroke line editor" << LL_ENDL; } // static void LLFloaterTestImpl::onFocusLostLine() { - llinfos << "focus lost line editor" << llendl; + LL_INFOS() << "focus lost line editor" << LL_ENDL; } // static void LLFloaterTestImpl::onChangeRadioGroup() { - llinfos << "change radio group" << llendl; + LL_INFOS() << "change radio group" << LL_ENDL; } //--------------------------------------------------------------------------- diff --git a/indra/newview/llfloatertools.cpp b/indra/newview/llfloatertools.cpp index d63fde0738..55847532ac 100644 --- a/indra/newview/llfloatertools.cpp +++ b/indra/newview/llfloatertools.cpp @@ -47,6 +47,7 @@ #include "llfloaterbuildoptions.h" #include "llfloatermediasettings.h" #include "llfloateropenobject.h" +#include "llfloaterobjectweights.h" #include "llfocusmgr.h" #include "llmediaentry.h" #include "llmediactrl.h" @@ -99,7 +100,6 @@ // Globals LLFloaterTools *gFloaterTools = NULL; - const std::string PANEL_NAMES[LLFloaterTools::PANEL_COUNT] = { std::string("General"), // PANEL_GENERAL, @@ -112,7 +112,6 @@ const std::string PANEL_NAMES[LLFloaterTools::PANEL_COUNT] = // Local prototypes void commit_grid_mode(LLUICtrl *ctrl); -void commit_select_component(void *data); void click_show_more(void*); void click_popup_info(void*); void click_popup_done(void*); @@ -124,10 +123,27 @@ void commit_radio_group_focus(LLUICtrl* ctrl); void commit_radio_group_move(LLUICtrl* ctrl); void commit_radio_group_edit(LLUICtrl* ctrl); void commit_radio_group_land(LLUICtrl* ctrl); - void commit_slider_zoom(LLUICtrl *ctrl); void commit_select_tool(LLUICtrl *ctrl, void *data); +/** + * Class LLLandImpactsObserver + * + * An observer class to monitor parcel selection and update + * the land impacts data from a parcel containing the selected object. + */ +class LLLandImpactsObserver : public LLParcelObserver +{ +public: + virtual void changed() + { + LLFloaterTools* tools_floater = gFloaterTools; + if(tools_floater) + { + tools_floater->updateLandImpacts(); + } + } +}; //static void* LLFloaterTools::createPanelPermissions(void* data) @@ -249,13 +265,13 @@ BOOL LLFloaterTools::postBuild() mRadioStretch = getChild("radio stretch"); mRadioSelectFace = getChild("radio select face"); mRadioAlign = getChild("radio align"); + mBtnGridOptions = getChild("Options..."); mTitleMedia = getChild("title_media"); mCheckSelectIndividual = getChild("checkbox edit linked parts"); getChild("checkbox edit linked parts")->setValue((BOOL)gSavedSettings.getBOOL("EditLinkedParts")); mCheckSnapToGrid = getChild("checkbox snap to grid"); getChild("checkbox snap to grid")->setValue((BOOL)gSavedSettings.getBOOL("SnapEnabled")); - mBtnGridOptions = getChild("Options..."); mCheckStretchUniform = getChild("checkbox uniform"); getChild("checkbox uniform")->setValue((BOOL)gSavedSettings.getBOOL("ScaleUniform")); mCheckStretchTexture = getChild("checkbox stretch textures"); @@ -267,6 +283,7 @@ BOOL LLFloaterTools::postBuild() mCheckShowHighlight = getChild("checkbox show highlight"); mCheckActualRoot = getChild("checkbox actual root"); + // // Create Buttons // @@ -279,11 +296,11 @@ BOOL LLFloaterTools::postBuild() found->setClickedCallback(boost::bind(&LLFloaterTools::setObjectType, toolData[t])); mButtons.push_back( found ); }else{ - llwarns << "Tool button not found! DOA Pending." << llendl; + LL_WARNS() << "Tool button not found! DOA Pending." << LL_ENDL; } } if ((mComboTreesGrass = findChild("trees_grass"))) - childSetCommitCallback("trees_grass", onSelectTreesGrass, (void*)0); + mComboTreesGrass->setCommitCallback(boost::bind(&LLFloaterTools::onSelectTreesGrass, this)); mCheckCopySelection = getChild("checkbox copy selection"); getChild("checkbox copy selection")->setValue((BOOL)gSavedSettings.getBOOL("CreateToolCopySelection")); mCheckSticky = getChild("checkbox sticky"); @@ -303,7 +320,6 @@ BOOL LLFloaterTools::postBuild() mSliderDozerSize = getChild("slider brush size"); getChild("slider brush size")->setValue(gSavedSettings.getF32("LandBrushSize")); - mSliderDozerForce = getChild("slider force"); // the setting stores the actual force multiplier, but the slider is logarithmic, so we convert here getChild("slider force")->setValue(log10(gSavedSettings.getF32("LandBrushForce"))); @@ -404,6 +420,8 @@ LLFloaterTools::LLFloaterTools() mPanelFace(NULL), mPanelLandInfo(NULL), + mLandImpactsObserver(NULL), + mDirty(TRUE), mNeedMediaTitle(TRUE) { @@ -425,7 +443,7 @@ LLFloaterTools::LLFloaterTools() mCommitCallbackRegistrar.add("BuildTool.commitRadioEdit", boost::bind(&commit_radio_group_edit,_1)); mCommitCallbackRegistrar.add("BuildTool.gridMode", boost::bind(&commit_grid_mode,_1)); - mCommitCallbackRegistrar.add("BuildTool.selectComponent", boost::bind(&commit_select_component, this)); + mCommitCallbackRegistrar.add("BuildTool.selectComponent", boost::bind(&LLFloaterTools::commitSelectComponent, this, _2)); mCommitCallbackRegistrar.add("BuildTool.gridOptions", boost::bind(&LLFloaterTools::onClickGridOptions,this)); mCommitCallbackRegistrar.add("BuildTool.applyToSelection", boost::bind(&click_apply_to_selection, this)); mCommitCallbackRegistrar.add("BuildTool.commitRadioLand", boost::bind(&commit_radio_group_land,_1)); @@ -434,12 +452,24 @@ LLFloaterTools::LLFloaterTools() mCommitCallbackRegistrar.add("BuildTool.DeleteMedia", boost::bind(&LLFloaterTools::onClickBtnDeleteMedia,this)); mCommitCallbackRegistrar.add("BuildTool.EditMedia", boost::bind(&LLFloaterTools::onClickBtnEditMedia,this)); + mLandImpactsObserver = new LLLandImpactsObserver(); + LLViewerParcelMgr::getInstance()->addObserver(mLandImpactsObserver); + LLUICtrlFactory::getInstance()->buildFloater(this,"floater_tools.xml",&factory_map,FALSE); + if (LLTextBox* text = findChild("selection_count")) + { + text->setClickedCallback(boost::bind(LLFloaterObjectWeights::toggleInstance, LLSD())); + text->setColor(gSavedSettings.getColor4("HTMLLinkColor")); + } } LLFloaterTools::~LLFloaterTools() { // children automatically deleted + gFloaterTools = NULL; + + LLViewerParcelMgr::getInstance()->removeObserver(mLandImpactsObserver); + delete mLandImpactsObserver; } void LLFloaterTools::setStatusText(const std::string& text) @@ -480,62 +510,159 @@ void LLFloaterTools::refresh() // Refresh object and prim count labels LLLocale locale(LLLocale::USER_LOCALE); - // Added in Link Num value -HgB - S32 object_count = LLSelectMgr::getInstance()->getSelection()->getRootObjectCount(); - S32 prim_count = LLSelectMgr::getInstance()->getEditSelection()->getObjectCount(); - std::string value_string; - std::string desc_string; - if ((gSavedSettings.getBOOL("EditLinkedParts"))&&(prim_count == 1)) //Selecting a single prim in "Edit Linked" mode, show link number +#if 0 + if (!gMeshRepo.meshRezEnabled()) { - desc_string = "Link number:"; + std::string obj_count_string; + LLResMgr::getInstance()->getIntegerString(obj_count_string, LLSelectMgr::getInstance()->getSelection()->getRootObjectCount()); + getChild("selection_count")->setTextArg("[OBJ_COUNT]", obj_count_string); + std::string prim_count_string; + LLResMgr::getInstance()->getIntegerString(prim_count_string, LLSelectMgr::getInstance()->getSelection()->getObjectCount()); + getChild("selection_count")->setTextArg("[PRIM_COUNT]", prim_count_string); + + // calculate selection rendering cost + if (sShowObjectCost) + { + std::string prim_cost_string; + S32 render_cost = LLSelectMgr::getInstance()->getSelection()->getSelectedObjectRenderCost(); + LLResMgr::getInstance()->getIntegerString(prim_cost_string, render_cost); + getChild("RenderingCost")->setTextArg("[COUNT]", prim_cost_string); + } - LLViewerObject* selected = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); - if (selected && selected->getRootEdit()) + // disable the object and prim counts if nothing selected + bool have_selection = ! LLSelectMgr::getInstance()->getSelection()->isEmpty(); + getChildView("obj_count")->setEnabled(have_selection); + getChildView("prim_count")->setEnabled(have_selection); + getChildView("RenderingCost")->setEnabled(have_selection && sShowObjectCost); + } + else +#endif + { + auto selection = LLSelectMgr::getInstance()->getSelection(); + F32 link_cost = selection->getSelectedLinksetCost(); + S32 link_count = selection->getRootObjectCount(); + S32 prim_count = selection->getObjectCount(); + auto child = getChild("link_num_obj_count"); + auto selected_face = -1; + if (auto node = prim_count == 1 ? *selection->begin() : nullptr) + //for (const auto& node : selection) // All selected objects { - LLViewerObject::child_list_t children = selected->getRootEdit()->getChildren(); - if (children.empty()) + // TODO: Count selected faces? What use is there for this? + if (node->getTESelectMask() == 0xFFFFFFFF) // All faces selected { - value_string = "0"; // An unlinked prim is "link 0". + selected_face = -2; // Multiple } - else + if (const auto& obj = node->getObject()) // This node's object { - children.push_front(selected->getRootEdit()); // need root in the list too - S32 index = 0; - for (LLViewerObject::child_list_t::iterator iter = children.begin(); iter != children.end(); ++iter) + //if (!obj->isSelected()) continue; + const auto& numTEs = obj->getNumTEs(); + for (S32 te = 0; selected_face != -2 && te < numTEs; ++te) // Faces { - index++; - if ((*iter)->isSelected()) + if (!node->isTESelected(te)) continue; + if (selected_face != -1) { - LLResMgr::getInstance()->getIntegerString(value_string, index); - break; + selected_face = -2; // Multiple } + else selected_face = te; } } + //if (selected_face == -2) break; } - } - else - { - desc_string = "Selected objects:"; - LLResMgr::getInstance()->getIntegerString(value_string, object_count); - } - childSetTextArg("link_num_obj_count", "[DESC]", desc_string); - childSetTextArg("link_num_obj_count", "[NUM]", value_string); + // Added in Link Num value -HgB + std::string value_string; + bool edit_linked(mCheckSelectIndividual->getValue()); + if (mRadioSelectFace->getValue() || selected_face > 0) // In select faces mode, show either multiple or the face number, otherwise only show if single face selected + { + child->setTextArg("[DESC]", getString("Selected Face:")); + if (selected_face < 0) + { + value_string = LLTrans::getString(selected_face == -1 && !prim_count ? "None" : "multiple_textures"); + } + else LLResMgr::getInstance()->getIntegerString(value_string, selected_face); + } + else if (edit_linked && prim_count == 1) //Selecting a single prim in "Edit Linked" mode, show link number + { + link_cost = selection->getSelectedObjectCost(); + child->setTextArg("[DESC]", getString("Link number:")); - LLStringUtil::format_map_t selection_args; - selection_args["COUNT"] = llformat("%.1d", (S32)prim_count); - if(gMeshRepo.meshRezEnabled()) - { - F32 link_cost = LLSelectMgr::getInstance()->getSelection()->getSelectedObjectCost(); - LLStringUtil::format_map_t prim_equiv_args; - prim_equiv_args["SEL_WEIGHT"] = llformat("%.1d", (S32)link_cost); - selection_args["PE_STRING"] = getString("status_selectprimequiv", prim_equiv_args); - } - else - { - selection_args["PE_STRING"] = ""; + if (LLViewerObject* selected = selection->getFirstObject()) + { + if (auto root = selected->getRootEdit()) + { + LLViewerObject::child_list_t children = root->getChildren(); + if (children.empty()) + { + value_string = "0"; // An unlinked prim is "link 0". + } + else + { + children.push_front(selected->getRootEdit()); // need root in the list too + S32 index = 1; + for (const auto& child : children) + { + if (child->isSelected()) + { + LLResMgr::getInstance()->getIntegerString(value_string, index); + break; + } + ++index; + } + } + } + } + } + else if (edit_linked) + { + child->setTextArg("[DESC]", getString("Selected prims:")); + LLResMgr::getInstance()->getIntegerString(value_string, prim_count); + link_cost = selection->getSelectedObjectCost(); + } + else + { + child->setTextArg("[DESC]", getString("Selected objects:")); + LLResMgr::getInstance()->getIntegerString(value_string, link_count); + } + child->setTextArg("[NUM]", value_string); + + /* Singu Note: We're not using this yet because we have no place to put it + LLCrossParcelFunctor func; + if (LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func, true)) + { + // Selection crosses parcel bounds. + // We don't display remaining land capacity in this case. + const LLStringExplicit empty_str(""); + childSetTextArg("remaining_capacity", "[CAPACITY_STRING]", empty_str); + } + else + */ + { + LLViewerObject* selected_object = mObjectSelection->getFirstObject(); + if (selected_object) + { + // Select a parcel at the currently selected object's position. + LLViewerParcelMgr::getInstance()->selectParcelAt(selected_object->getPositionGlobal()); + } + else + { + //LL_WARNS() << "Failed to get selected object" << LL_ENDL; + } + } + + auto sel_count = getChild("selection_count"); + bool have_selection = !selection->isEmpty(); + if (have_selection) + { + LLStringUtil::format_map_t selection_args; + selection_args["OBJ_COUNT"] = llformat("%.1d", prim_count); + selection_args["LAND_IMPACT"] = llformat(edit_linked ? "%.2f" : "%.0f", link_cost); + + sel_count->setText(getString("status_selectcount", selection_args)); + } + sel_count->setVisible(have_selection); + //childSetVisible("remaining_capacity", have_selection); + childSetVisible("selection_empty", !have_selection); } - std::string prim_count_string = getString("status_selectcount",selection_args); - childSetText("prim_count", prim_count_string); + // Refresh child tabs mPanelPermissions->refresh(); @@ -546,6 +673,12 @@ void LLFloaterTools::refresh() refreshMedia(); mPanelContents->refresh(); mPanelLandInfo->refresh(); + + // Refresh the advanced weights floater + if (LLFloaterObjectWeights::instanceVisible()) + { + LLFloaterObjectWeights::getInstance()->refresh(); + } } void LLFloaterTools::draw() @@ -606,8 +739,8 @@ void LLFloaterTools::updatePopup(LLCoordGL center, MASK mask) mRadioZoom ->setVisible( focus_visible ); mRadioOrbit ->setVisible( focus_visible ); mRadioPan ->setVisible( focus_visible ); - childSetVisible("slider zoom", focus_visible); - childSetEnabled("slider zoom", gCameraBtnZoom); + getChildView("slider zoom")->setVisible(focus_visible); + getChildView("slider zoom")->setEnabled(gCameraBtnZoom); mRadioZoom ->set(!gCameraBtnOrbit && !gCameraBtnPan && @@ -625,7 +758,7 @@ void LLFloaterTools::updatePopup(LLCoordGL center, MASK mask) (mask == (MASK_PAN | MASK_ALT)) ); // multiply by correction factor because volume sliders go [0, 0.5] - childSetValue( "slider zoom", gAgentCamera.getCameraZoomFraction() * 0.5f); + getChild("slider zoom")->setValue(gAgentCamera.getCameraZoomFraction() * 0.5f); // Move buttons BOOL move_visible = (tool == LLToolGrab::getInstance()); @@ -699,7 +832,6 @@ void LLFloaterTools::updatePopup(LLCoordGL center, MASK mask) case SELECT_TYPE_HUD: mComboGridMode->add(getString("grid_screen_text")); mComboGridMode->add(getString("grid_local_text")); - //mComboGridMode->add(getString("grid_reference_text")); break; case SELECT_TYPE_WORLD: mComboGridMode->add(getString("grid_world_text")); @@ -772,10 +904,8 @@ void LLFloaterTools::updatePopup(LLCoordGL center, MASK mask) if (mBtnLand) mBtnLand ->setToggleState( land_visible ); - // mRadioEditLand ->set( tool == LLToolBrushLand::getInstance() ); if (mRadioSelectLand) mRadioSelectLand->set( tool == LLToolSelectLand::getInstance() ); - // mRadioEditLand ->setVisible( land_visible ); if (mRadioSelectLand) mRadioSelectLand->setVisible( land_visible ); S32 dozer_mode = gSavedSettings.getS32("RadioLandBrushAction"); @@ -810,6 +940,7 @@ void LLFloaterTools::updatePopup(LLCoordGL center, MASK mask) mRadioDozerRevert ->set( tool == LLToolBrushLand::getInstance() && dozer_mode == 5); mRadioDozerRevert ->setVisible( land_visible ); } + if (mBtnApplyToSelection) { mBtnApplyToSelection->setVisible( land_visible ); @@ -826,10 +957,26 @@ void LLFloaterTools::updatePopup(LLCoordGL center, MASK mask) mSliderDozerForce ->setVisible( land_visible ); getChildView("Strength:")->setVisible( land_visible); } - - childSetVisible("link_num_obj_count", !land_visible); - childSetVisible("prim_count", !land_visible); - mTab->setVisible(!land_visible); + + bool have_selection = !LLSelectMgr::getInstance()->getSelection()->isEmpty(); + + getChildView("link_num_obj_count")->setVisible(!land_visible && have_selection); + getChildView("selection_count")->setVisible(!land_visible && have_selection); + //getChildView("remaining_capacity")->setVisible(!land_visible && have_selection); + getChildView("selection_empty")->setVisible(!land_visible && !have_selection); + + static const LLCachedControl mini("LiruMiniBuildFloater"); + mTab->setVisible(!mini && !land_visible); + getChildView("mini_button")->setVisible(!land_visible); + bool small = mini && !land_visible; + const S32 cur_height = getRect().getHeight(); + static const S32 full_height = cur_height; + if (small == (cur_height == full_height)) + { + S32 new_height = small ? full_height - mTab->getRect().getHeight() + 8 : full_height; + translate(0, cur_height - new_height); + reshape(getRect().getWidth(), new_height); + } mPanelLandInfo->setVisible(land_visible); } @@ -898,9 +1045,12 @@ void LLFloaterTools::onClose(bool app_quitting) // gMenuBarView->setItemVisible(std::string("Tools"), FALSE); // gMenuBarView->arrange(); - + if(LLFloaterMediaSettings::instanceExists()) LLFloaterMediaSettings::getInstance()->close(); + + // hide the advanced object weights floater + LLFloaterObjectWeights::hideInstance(); } void LLFloaterTools::showPanel(EInfoPanel panel) @@ -911,7 +1061,6 @@ void LLFloaterTools::showPanel(EInfoPanel panel) void click_popup_info(void*) { -// gBuildView->setPropertiesPanelOpen(TRUE); } void click_popup_done(void*) @@ -1042,19 +1191,14 @@ void commit_radio_group_land(LLUICtrl* ctrl) } } -void commit_select_component(void *data) +void LLFloaterTools::commitSelectComponent(bool select_individuals) { - LLFloaterTools* floaterp = (LLFloaterTools*)data; - //forfeit focus - if (gFocusMgr.childHasKeyboardFocus(floaterp)) + if (gFocusMgr.childHasKeyboardFocus(this)) { gFocusMgr.setKeyboardFocus(NULL); } - - BOOL select_individuals = floaterp->mCheckSelectIndividual->get(); - gSavedSettings.setBOOL("EditLinkedParts", select_individuals); - floaterp->dirty(); + dirty(); if (select_individuals) { @@ -1083,7 +1227,6 @@ void commit_grid_mode(LLUICtrl *ctrl) void LLFloaterTools::onClickGridOptions() { - //LLFloaterTools* floaterp = (LLFloaterTools*)data; LLFloaterBuildOptions::show(NULL); // RN: this makes grid options dependent on build tools window //floaterp->addDependentFloater(LLFloaterBuildOptions::getInstance(), FALSE); @@ -1110,7 +1253,7 @@ void LLFloaterTools::setTool(const LLSD& user_data) else if (control_name == "Land" ) LLToolMgr::getInstance()->getCurrentToolset()->selectTool( (LLTool *) LLToolSelectLand::getInstance()); else - llwarns<<" no parameter name "<getParcel(); + if (!parcel) + { + return; + } + + /* Singu Note: We're not using this yet because we have no place to put it + S32 rezzed_prims = parcel->getSimWidePrimCount(); + S32 total_capacity = parcel->getSimWideMaxPrimCapacity(); + + std::string remaining_capacity_str = ""; + + bool show_mesh_cost = gMeshRepo.meshRezEnabled(); + if (show_mesh_cost) + { + LLStringUtil::format_map_t remaining_capacity_args; + remaining_capacity_args["LAND_CAPACITY"] = llformat("%d", total_capacity - rezzed_prims); + remaining_capacity_str = getString("status_remaining_capacity", remaining_capacity_args); + } + + childSetTextArg("remaining_capacity", "[CAPACITY_STRING]", remaining_capacity_str); + */ + + // Update land impacts info in the weights floater + if (LLFloaterObjectWeights::instanceVisible()) + { + LLFloaterObjectWeights::getInstance()->updateLandImpacts(parcel); + } +} + void LLFloaterTools::getMediaState() { LLObjectSelectionHandle selected_objects =LLSelectMgr::getInstance()->getSelection(); @@ -1207,8 +1383,8 @@ void LLFloaterTools::getMediaState() for ( ; iter != end; ++iter) { LLSelectNode* node = *iter; - LLVOVolume* object = dynamic_cast(node->getObject()); - if (NULL != object) + LLVOVolume* object = node ? node->getObject()->asVolume() : nullptr; + if (nullptr != object) { if (!object->permModify()) { @@ -1313,7 +1489,7 @@ void LLFloaterTools::getMediaState() getChildView("media_tex")->setEnabled(bool_has_media && editable); getChildView("edit_media")->setEnabled(bool_has_media && LLFloaterMediaSettings::getInstance()->mIdenticalHasMediaInfo && editable ); getChildView("delete_media")->setEnabled(bool_has_media && editable ); - getChildView("add_media")->setEnabled(( ! bool_has_media ) && editable ); + getChildView("add_media")->setEnabled(editable); // TODO: display a list of all media on the face - use 'identical' flag } else // not all face has media but at least one does. @@ -1343,7 +1519,7 @@ void LLFloaterTools::getMediaState() getChildView("media_tex")->setEnabled(TRUE); getChildView("edit_media")->setEnabled(LLFloaterMediaSettings::getInstance()->mIdenticalHasMediaInfo); getChildView("delete_media")->setEnabled(TRUE); - getChildView("add_media")->setEnabled(FALSE ); + getChildView("add_media")->setEnabled(editable); } media_info->setText(media_title); @@ -1353,6 +1529,8 @@ void LLFloaterTools::getMediaState() if(mTitleMedia) LLFloaterMediaSettings::initValues(mMediaSettings, editable ); } + + ////////////////////////////////////////////////////////////////////////////// // called when a user wants to add media to a prim or prim face void LLFloaterTools::onClickBtnAddMedia() @@ -1949,10 +2127,9 @@ void LLFloaterTools::updateMediaSettings() mMediaSettings[ base_key + std::string( LLPanelContents::TENTATIVE_SUFFIX ) ] = ! identical; } -// static -void LLFloaterTools::onSelectTreesGrass(LLUICtrl*, void*) +void LLFloaterTools::onSelectTreesGrass() { - const std::string &selected = gFloaterTools->mComboTreesGrass->getValue(); + const std::string& selected = mComboTreesGrass->getValue(); LLPCode pcode = LLToolPlacer::getObjectType(); if (pcode == LL_PCODE_LEGACY_TREE) { @@ -2003,7 +2180,7 @@ void LLFloaterTools::updateTreeGrassCombo(bool visible) } mComboTreesGrass->removeall(); - mComboTreesGrass->add("Random"); + mComboTreesGrass->add(getString("Random")); int select = 0, i = 0; diff --git a/indra/newview/llfloatertools.h b/indra/newview/llfloatertools.h index fec7368194..9029ba17c5 100644 --- a/indra/newview/llfloatertools.h +++ b/indra/newview/llfloatertools.h @@ -53,6 +53,7 @@ class LLMediaCtrl; class LLTool; class LLParcelSelection; class LLObjectSelection; +class LLLandImpactsObserver; typedef LLSafeHandle LLObjectSelectionHandle; @@ -110,6 +111,9 @@ class LLFloaterTools void updateMediaTitle(); void navigateToTitleMedia( const std::string url ); bool selectedMediaEditable(); + void updateLandImpacts(); + + LLPanelFace* getPanelFace() { return mPanelFace; } private: void refresh(); @@ -118,6 +122,7 @@ class LLFloaterTools void updateMediaSettings(); static bool deleteMediaConfirm(const LLSD& notification, const LLSD& response); static bool multipleFacesSelectedConfirm(const LLSD& notification, const LLSD& response); + void commitSelectComponent(bool select_individuals); static void setObjectType( LLPCode pcode ); void onClickGridOptions(); @@ -176,7 +181,6 @@ class LLFloaterTools LLCheckBoxCtrl *mCheckCopyRotates; // Land buttons -// LLCheckBoxCtrl *mRadioEditLand; LLCheckBoxCtrl *mRadioSelectLand; LLCheckBoxCtrl *mRadioDozerFlatten; @@ -200,18 +204,21 @@ class LLFloaterTools LLPanelFace *mPanelFace; LLPanelLandInfo *mPanelLandInfo; + LLLandImpactsObserver* mLandImpactsObserver; + LLParcelSelectionHandle mParcelSelection; LLObjectSelectionHandle mObjectSelection; LLMediaCtrl *mTitleMedia; bool mNeedMediaTitle; + private: BOOL mDirty; std::map mStatusText; + void onSelectTreesGrass(); void updateTreeGrassCombo(bool visible); - static void onSelectTreesGrass(LLUICtrl*, void*); protected: LLSD mMediaSettings; }; diff --git a/indra/newview/llfloatertopobjects.cpp b/indra/newview/llfloatertopobjects.cpp index 8c767e64b1..d78a9ef28c 100644 --- a/indra/newview/llfloatertopobjects.cpp +++ b/indra/newview/llfloatertopobjects.cpp @@ -93,6 +93,7 @@ LLFloaterTopObjects::LLFloaterTopObjects() mCommitCallbackRegistrar.add("TopObjects.CommitObjectsList",boost::bind(&LLFloaterTopObjects::onCommitObjectsList, this)); mCommitCallbackRegistrar.add("TopObjects.TeleportToObject", boost::bind(&LLFloaterTopObjects::onTeleportToObject, this)); + mCommitCallbackRegistrar.add("TopObjects.CamToObject", boost::bind(&LLFloaterTopObjects::onCamToObject, this)); mCommitCallbackRegistrar.add("TopObjects.Kick", boost::bind(&LLFloaterTopObjects::onKick, this)); mCommitCallbackRegistrar.add("TopObjects.Profile", boost::bind(&LLFloaterTopObjects::onProfile, this)); @@ -327,21 +328,11 @@ void LLFloaterTopObjects::doToObjects(int action, bool all) LLViewerRegion* region = gAgent.getRegion(); if (!region) return; - LLCtrlListInterface *list = getChild("objects_list")->getListInterface(); + const auto list = getChild("objects_list"); if (!list || list->getItemCount() == 0) return; - uuid_vec_t::iterator id_itor; - bool start_message = true; - - for (id_itor = mObjectListIDs.begin(); id_itor != mObjectListIDs.end(); ++id_itor) - { - LLUUID task_id = *id_itor; - if (!all && !list->isSelected(task_id)) - { - // Selected only - continue; - } + auto func = [&](const LLUUID& task_id){ if (start_message) { if (action == ACTION_RETURN) @@ -358,10 +349,9 @@ void LLFloaterTopObjects::doToObjects(int action, bool all) msg->nextBlockFast(_PREHASH_ParcelData); msg->addS32Fast(_PREHASH_LocalID, -1); // Whole region msg->addS32Fast(_PREHASH_ReturnType, RT_NONE); + msg->nextBlockFast(_PREHASH_TaskIDs); start_message = false; } - - msg->nextBlockFast(_PREHASH_TaskIDs); msg->addUUIDFast(_PREHASH_TaskID, task_id); if (msg->isSendFullFast(_PREHASH_TaskIDs)) @@ -369,7 +359,10 @@ void LLFloaterTopObjects::doToObjects(int action, bool all) msg->sendReliable(region->getHost()); start_message = true; } - } + }; + + if (all) for (const auto& id : mObjectListIDs) func(id); + else for (const auto& item : list->getAllSelected()) func(item->getUUID()); if (!start_message) { @@ -494,23 +487,11 @@ void LLFloaterTopObjects::onGetByParcelName() void LLFloaterTopObjects::showBeacon() { - LLScrollListCtrl* list = getChild("objects_list"); - if (!list) return; - - LLScrollListItem* first_selected = list->getFirstSelected(); - if (!first_selected) return; - + LLVector3d pos_global = getSelectedPosition(); + if (pos_global.isExactlyZero()) return; + LLScrollListItem* first_selected = getChild("objects_list")->getFirstSelected(); std::string name = first_selected->getColumn(1)->getValue().asString(); - std::string pos_string = first_selected->getColumn(3)->getValue().asString(); - - F32 x, y, z; - S32 matched = sscanf(pos_string.c_str(), "<%g,%g,%g>", &x, &y, &z); - if (matched != 3) return; - - LLVector3 pos_agent(x, y, z); - LLVector3d pos_global = gAgent.getPosGlobalFromAgent(pos_agent); - std::string tooltip(""); - LLTracker::trackLocation(pos_global, name, tooltip, LLTracker::LOCATION_ITEM); + LLTracker::trackLocation(pos_global, name, LLStringUtil::null, LLTracker::LOCATION_ITEM); const LLUUID& taskid = first_selected->getUUID(); if(LLVOAvatar* voavatar = gObjectList.findAvatar(taskid)) @@ -522,26 +503,39 @@ void LLFloaterTopObjects::showBeacon() } } -void LLFloaterTopObjects::onTeleportToObject() +LLVector3d LLFloaterTopObjects::getSelectedPosition() const { LLScrollListCtrl* list = getChild("objects_list"); - if (!list) return; + if (!list) return LLVector3d::zero; LLScrollListItem* first_selected = list->getFirstSelected(); - if (!first_selected) return; + if (!first_selected) return LLVector3d::zero; std::string pos_string = first_selected->getColumn(3)->getValue().asString(); F32 x, y, z; S32 matched = sscanf(pos_string.c_str(), "<%g,%g,%g>", &x, &y, &z); - if (matched != 3) return; + if (matched != 3) return LLVector3d::zero; LLVector3 pos_agent(x, y, z); - LLVector3d pos_global = gAgent.getPosGlobalFromAgent(pos_agent); + return gAgent.getPosGlobalFromAgent(pos_agent); +} +void LLFloaterTopObjects::onTeleportToObject() +{ + LLVector3d pos_global = getSelectedPosition(); + if (pos_global.isExactlyZero()) return; gAgent.teleportViaLocation( pos_global ); } +void LLFloaterTopObjects::onCamToObject() +{ + LLVector3d pos_global = getSelectedPosition(); + if (pos_global.isExactlyZero()) return; + const LLUUID& id = getChild("objects_list")->getFirstSelected()->getUUID(); + gAgentCamera.setCameraPosAndFocusGlobal(pos_global + LLVector3d(3.5,1.35,0.75), pos_global, id); +} + void LLFloaterTopObjects::onKick() { LLScrollListCtrl* list = getChild("objects_list"); diff --git a/indra/newview/llfloatertopobjects.h b/indra/newview/llfloatertopobjects.h index a69de5fc9b..9f1b2794d6 100644 --- a/indra/newview/llfloatertopobjects.h +++ b/indra/newview/llfloatertopobjects.h @@ -74,7 +74,9 @@ class LLFloaterTopObjects : public LLFloater, public LLSingletonbuildFloater(LLFloaterTOS::sInstance, "floater_tos.xml"); - } - else - { - LLUICtrlFactory::getInstance()->buildFloater(LLFloaterTOS::sInstance, "floater_critical.xml"); - } - - return LLFloaterTOS::sInstance; + if (sInstance) sInstance->close(); + return sInstance = new LLFloaterTOS(type, message); } -LLFloaterTOS::LLFloaterTOS(ETOSType type, const std::string & message) -: LLModalDialog( std::string(" "), 100, 100 ), +LLFloaterTOS::LLFloaterTOS(ETOSType type, const std::string& message) +: LLModalDialog(std::string(" "), 100, 100), mType(type), - mMessage(message), - mLoadCompleteCount( 0 ) + mLoadCompleteCount(0) { + LLUICtrlFactory::getInstance()->buildFloater(this, + mType == TOS_CRITICAL_MESSAGE ? "floater_critical.xml" + : mType == TOS_TOS ? "floater_tos.xml" + : "floater_voice_license.xml"); + + if (mType == TOS_CRITICAL_MESSAGE) + { + // this displays the critical message + LLTextEditor *editor = getChild("tos_text"); + editor->setHandleEditKeysDirectly(TRUE); + editor->setEnabled(FALSE); + editor->setWordWrap(TRUE); + editor->setFocus(TRUE); + editor->setValue(message); + } } // helper class that trys to download a URL from a web site and calls a method // on parent class indicating if the web server is working or not class LLIamHere : public LLHTTPClient::ResponderWithResult { - private: - LLIamHere( LLFloaterTOS* parent ) : - mParent( parent ) - {} + LLIamHere(LLFloaterTOS* parent) : mParent(parent->getDerivedHandle()) {} + LLHandle mParent; - LLFloaterTOS* mParent; - - public: - - static boost::intrusive_ptr< LLIamHere > build( LLFloaterTOS* parent ) - { - return boost::intrusive_ptr< LLIamHere >( new LLIamHere( parent ) ); - }; - - virtual void setParent( LLFloaterTOS* parentIn ) - { - mParent = parentIn; - }; +public: + static boost::intrusive_ptr build(LLFloaterTOS* parent) + { + return boost::intrusive_ptr(new LLIamHere(parent)); + } - /*virtual*/ void result( const LLSD& content ) - { - if ( mParent ) - mParent->setSiteIsAlive( true ); - }; + void httpSuccess() override + { + if (!mParent.isDead()) + mParent.get()->setSiteIsAlive(true); + } - /*virtual*/ void error( U32 status, const std::string& reason ) + void httpFailure() override + { + if (!mParent.isDead()) { - if ( mParent ) - { - // *HACK: For purposes of this alive check, 302 Found - // (aka Moved Temporarily) is considered alive. The web site - // redirects this link to a "cache busting" temporary URL. JC - bool alive = (status == HTTP_FOUND); - mParent->setSiteIsAlive( alive ); - } - }; - - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return iamHere_timeout; } - /*virtual*/ bool redirect_status_ok(void) const { return true; } - /*virtual*/ char const* getName(void) const { return "LLIamHere"; } -}; + // *HACK: For purposes of this alive check, 302 Found + // (aka Moved Temporarily) is considered alive. The web site + // redirects this link to a "cache busting" temporary URL. JC + mParent.get()->setSiteIsAlive(mStatus == HTTP_FOUND); + } + } -// this is global and not a class member to keep crud out of the header file -namespace { - boost::intrusive_ptr< LLIamHere > gResponsePtr = 0; + AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy() const override { return iamHere_timeout; } + bool pass_redirect_status() const override { return true; } + char const* getName() const override { return "LLIamHere"; } }; BOOL LLFloaterTOS::postBuild() @@ -146,78 +130,60 @@ BOOL LLFloaterTOS::postBuild() childSetAction("Cancel", onCancel, this); childSetCommitCallback("agree_chk", updateAgree, this); - if ( mType != TOS_TOS ) - { - // this displays the critical message - LLTextEditor *editor = getChild("tos_text"); - editor->setHandleEditKeysDirectly( TRUE ); - editor->setEnabled( FALSE ); - editor->setWordWrap(TRUE); - editor->setFocus(TRUE); - editor->setValue(LLSD(mMessage)); - - return TRUE; - } + if (mType == TOS_CRITICAL_MESSAGE) return TRUE; // disable Agree to TOS radio button until the page has fully loaded LLCheckBoxCtrl* tos_agreement = getChild("agree_chk"); - tos_agreement->setEnabled( false ); + tos_agreement->setEnabled(false); + bool voice = mType == TOS_VOICE; // hide the SL text widget if we're displaying TOS with using a browser widget. - LLTextEditor *editor = getChild("tos_text"); - editor->setVisible( FALSE ); + getChild(voice ? "license_text" : "tos_text")->setVisible(FALSE); - LLMediaCtrl* web_browser = getChild("tos_html"); - if ( web_browser ) + if (LLMediaCtrl* web_browser = getChild(voice ? "license_html" : "tos_html")) { + // start to observe it so we see navigate complete events web_browser->addObserver(this); - gResponsePtr = LLIamHere::build( this ); - LLHTTPClient::get( getString( "real_url" ), gResponsePtr ); + std::string url = getString( "real_url" ); + if (!voice || url.substr(0,4) == "http") { + LLHTTPClient::get(url, LLIamHere::build(this)); + } else { + setSiteIsAlive(false); + } } return TRUE; } -void LLFloaterTOS::setSiteIsAlive( bool alive ) +void LLFloaterTOS::setSiteIsAlive(bool alive) { // only do this for TOS pages - if ( mType == TOS_TOS ) + if (mType != TOS_CRITICAL_MESSAGE) { - LLMediaCtrl* web_browser = getChild("tos_html"); + bool voice = mType == TOS_VOICE; + LLMediaCtrl* web_browser = getChild(voice ? "license_html" : "tos_html"); // if the contents of the site was retrieved - if ( alive ) + if (alive) { - if ( web_browser ) + if (web_browser) { // navigate to the "real" page - web_browser->navigateTo( getString( "real_url" ) ); - }; + web_browser->navigateTo(getString("real_url")); + } } else { + if (voice) web_browser->navigateToLocalPage("license", getString("fallback_html")); // normally this is set when navigation to TOS page navigation completes (so you can't accept before TOS loads) // but if the page is unavailable, we need to do this now - LLCheckBoxCtrl* tos_agreement = getChild("agree_chk"); - tos_agreement->setEnabled( true ); - }; - }; + getChild("agree_chk")->setEnabled(true); + } + } } LLFloaterTOS::~LLFloaterTOS() { - - // tell the responder we're not here anymore - if ( gResponsePtr ) - gResponsePtr->setParent( 0 ); - - LLFloaterTOS::sInstance = NULL; -} - -// virtual -void LLFloaterTOS::draw() -{ - // draw children - LLModalDialog::draw(); + sInstance = nullptr; } // static @@ -229,11 +195,21 @@ void LLFloaterTOS::updateAgree(LLUICtrl*, void* userdata ) } // static -void LLFloaterTOS::onContinue( void* userdata ) +void LLFloaterTOS::onContinue(void* userdata) { LLFloaterTOS* self = (LLFloaterTOS*) userdata; - llinfos << "User agrees with TOS." << llendl; - if (self->mType == TOS_TOS) + bool voice = self->mType == TOS_VOICE; + LL_INFOS() << (voice ? "User agreed to the Vivox personal license" : "User agrees with TOS.") << LL_ENDL; + if (voice) + { + // enabling voice by default here seems like the best behavior + gSavedSettings.setBOOL("EnableVoiceChat", TRUE); + gSavedSettings.setBOOL("VivoxLicenseAccepted", TRUE); + + // save these settings in case something bad happens later + gSavedSettings.saveToFile(gSavedSettings.getString("ClientSettingsFile"), TRUE); + } + else if (self->mType == TOS_TOS) { gAcceptTOS = TRUE; } @@ -242,42 +218,57 @@ void LLFloaterTOS::onContinue( void* userdata ) gAcceptCriticalMessage = TRUE; } + auto state = LLStartUp::getStartupState(); // Testing TOS dialog - #if ! LL_RELEASE_FOR_DOWNLOAD - if ( LLStartUp::getStartupState() == STATE_LOGIN_WAIT ) +#if !LL_RELEASE_FOR_DOWNLOAD + if (!voice && state == STATE_LOGIN_WAIT) { - LLStartUp::setStartupState( STATE_LOGIN_SHOW ); + LLStartUp::setStartupState(STATE_LOGIN_SHOW); } else - #endif - - LLStartUp::setStartupState( STATE_LOGIN_AUTH_INIT ); // Go back and finish authentication +#endif + if (!voice || state == STATE_LOGIN_VOICE_LICENSE) + { + LLStartUp::setStartupState(STATE_LOGIN_AUTH_INIT); // Go back and finish authentication + } self->close(); // destroys this object } // static -void LLFloaterTOS::onCancel( void* userdata ) +void LLFloaterTOS::onCancel(void* userdata) { LLFloaterTOS* self = (LLFloaterTOS*) userdata; - llinfos << "User disagrees with TOS." << llendl; - LLNotificationsUtil::add("MustAgreeToLogIn", LLSD(), LLSD(), login_alert_done); - LLStartUp::setStartupState( STATE_LOGIN_SHOW ); - self->mLoadCompleteCount = 0; // reset counter for next time we come to TOS + if (self->mType == TOS_VOICE) + { + LL_INFOS() << "User disagreed with the Vivox personal license" << LL_ENDL; + gSavedSettings.setBOOL("EnableVoiceChat", FALSE); + gSavedSettings.setBOOL("VivoxLicenseAccepted", FALSE); + + if (LLStartUp::getStartupState() == STATE_LOGIN_VOICE_LICENSE) + { + LLStartUp::setStartupState(STATE_LOGIN_AUTH_INIT); // Go back and finish authentication + } + } + else + { + LL_INFOS() << "User disagrees with TOS." << LL_ENDL; + LLNotificationsUtil::add("MustAgreeToLogIn", LLSD(), LLSD(), login_alert_done); + LLStartUp::setStartupState(STATE_LOGIN_SHOW); + } self->close(); // destroys this object } //virtual void LLFloaterTOS::handleMediaEvent(LLPluginClassMedia* /*self*/, EMediaEvent event) { - if(event == MEDIA_EVENT_NAVIGATE_COMPLETE) + if (event == MEDIA_EVENT_NAVIGATE_COMPLETE) { // skip past the loading screen navigate complete - if ( ++mLoadCompleteCount == 2 ) + if (++mLoadCompleteCount == 2) { - llinfos << "NAVIGATE COMPLETE" << llendl; + LL_INFOS() << "NAVIGATE COMPLETE" << LL_ENDL; // enable Agree to TOS radio button now that page has loaded - LLCheckBoxCtrl * tos_agreement = getChild("agree_chk"); - tos_agreement->setEnabled( true ); + getChild("agree_chk")->setEnabled(true); } } } diff --git a/indra/newview/llfloatertos.h b/indra/newview/llfloatertos.h index 331458178b..6bfced8703 100644 --- a/indra/newview/llfloatertos.h +++ b/indra/newview/llfloatertos.h @@ -24,7 +24,7 @@ * that you have read and understood your obligations described above, * and agree to abide by those obligations. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * ALL SOURCE CODE IS PROVIDED "AS IS." THE AUTHOR MAKES NO * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, * COMPLETENESS OR PERFORMANCE. * $/LicenseInfo$ @@ -54,15 +54,13 @@ class LLFloaterTOS : enum ETOSType { TOS_TOS = 0, - TOS_CRITICAL_MESSAGE = 1 + TOS_CRITICAL_MESSAGE = 1, + TOS_VOICE = 2 }; - // Asset_id is overwritten with LLUUID::null when agree is clicked. - static LLFloaterTOS* show(ETOSType type, const std::string & message); + static LLFloaterTOS* show(ETOSType type, const std::string& message = LLStringUtil::null); BOOL postBuild(); - - virtual void draw(); static void updateAgree( LLUICtrl *, void* userdata ); static void onContinue( void* userdata ); @@ -74,12 +72,9 @@ class LLFloaterTOS : /*virtual*/ void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event); private: - // Asset_id is overwritten with LLUUID::null when agree is clicked. - LLFloaterTOS(ETOSType type, const std::string & message); + LLFloaterTOS(ETOSType type, const std::string& message); -private: ETOSType mType; - std::string mMessage; int mLoadCompleteCount; static LLFloaterTOS* sInstance; diff --git a/indra/newview/llfloaterurldisplay.cpp b/indra/newview/llfloaterurldisplay.cpp index c265c6169a..514f1f758e 100644 --- a/indra/newview/llfloaterurldisplay.cpp +++ b/indra/newview/llfloaterurldisplay.cpp @@ -48,7 +48,7 @@ LLFloaterURLDisplay::LLFloaterURLDisplay(const LLSD& sd) { mFactoryMap["place_details_panel"] = LLCallbackMap(LLFloaterURLDisplay::createPlaceDetail, this); LLUICtrlFactory::getInstance()->buildFloater(this, "floater_preview_url.xml", &getFactoryMap()); - this->setVisible(false); + setVisible(false); // If positioned at 0,0 the teleport button is behind the toolbar. LLRect r = getRect(); diff --git a/indra/newview/llfloaterurlentry.cpp b/indra/newview/llfloaterurlentry.cpp index 65171b0070..727a89b3c6 100644 --- a/indra/newview/llfloaterurlentry.cpp +++ b/indra/newview/llfloaterurlentry.cpp @@ -65,21 +65,21 @@ class LLMediaTypeResponder : public LLHTTPClient::ResponderHeadersOnly LLHandle mParent; - /*virtual*/ void completedHeaders(U32 status, std::string const& reason, AIHTTPReceivedHeaders const& headers) + /*virtual*/ void completedHeaders(void) { - if (200 <= status && status < 300) + if (isGoodStatus(mStatus)) { std::string media_type; - if (headers.getFirstValue("content-type", media_type)) + if (mReceivedHeaders.getFirstValue("content-type", media_type)) { std::string::size_type idx1 = media_type.find_first_of(";"); std::string mime_type = media_type.substr(0, idx1); - completeAny(status, mime_type); + completeAny(mStatus, mime_type); return; } - llwarns << "LLMediaTypeResponder::completedHeaders: OK HTTP status (" << status << ") but no Content-Type! Received headers: " << headers << llendl; + LL_WARNS() << "LLMediaTypeResponder::completedHeaders: OK HTTP status (" << mStatus << ") but no Content-Type! Received headers: " << mReceivedHeaders << LL_ENDL; } - completeAny(status, "none/none"); + completeAny(mStatus, "none/none"); } void completeAny(U32 status, const std::string& mime_type) @@ -103,6 +103,7 @@ class LLMediaTypeResponder : public LLHTTPClient::ResponderHeadersOnly LLFloaterURLEntry::LLFloaterURLEntry(LLHandle parent) : LLFloater(), + mMediaURLEdit(nullptr), mPanelLandMediaHandle(parent) { LLUICtrlFactory::getInstance()->buildFloater(this, "floater_url_entry.xml"); diff --git a/indra/newview/llfloatervoiceeffect.cpp b/indra/newview/llfloatervoiceeffect.cpp index fc74c9e87d..3c0fe3af0b 100644 --- a/indra/newview/llfloatervoiceeffect.cpp +++ b/indra/newview/llfloatervoiceeffect.cpp @@ -38,6 +38,7 @@ LLFloaterVoiceEffect::LLFloaterVoiceEffect(const LLSD& key) : LLFloater(/*key*/) + , mVoiceEffectList(nullptr) { mCommitCallbackRegistrar.add("VoiceEffect.Record", boost::bind(&LLFloaterVoiceEffect::onClickRecord, this)); mCommitCallbackRegistrar.add("VoiceEffect.Play", boost::bind(&LLFloaterVoiceEffect::onClickPlay, this)); @@ -74,7 +75,7 @@ BOOL LLFloaterVoiceEffect::postBuild() LLStyleSP link(new LLStyle); link->setLinkHREF(LLTrans::getString("voice_morphing_url")); link->setColor(gSavedSettings.getColor4("HTMLLinkColor")); - editor->appendStyledText(text, false, false, link); + editor->appendText(text, false, false, link); } mVoiceEffectList = getChild("voice_effect_list"); diff --git a/indra/newview/llfloatervoiceeffect.h b/indra/newview/llfloatervoiceeffect.h index 9bee8937cd..e7c0af852c 100644 --- a/indra/newview/llfloatervoiceeffect.h +++ b/indra/newview/llfloatervoiceeffect.h @@ -67,7 +67,6 @@ class LLFloaterVoiceEffect void onClickStop(); void onClickActivate(); - LLUUID mSelectedID; LLScrollListCtrl* mVoiceEffectList; }; diff --git a/indra/newview/llfloaterwater.cpp b/indra/newview/llfloaterwater.cpp index f444a7cbcc..43507d0fde 100644 --- a/indra/newview/llfloaterwater.cpp +++ b/indra/newview/llfloaterwater.cpp @@ -48,6 +48,7 @@ #include "llagent.h" #include "llwaterparammanager.h" #include "llwaterparamset.h" +#include "rlvactions.h" #undef max // Fixes a Windows compiler error @@ -284,6 +285,7 @@ LLFloaterWater* LLFloaterWater::instance() } void LLFloaterWater::show() { + if (RlvActions::hasBehaviour(RLV_BHVR_SETENV)) return; if (!sWaterMenu) { LLFloaterWater* water = instance(); diff --git a/indra/newview/llfloaterwebcontent.cpp b/indra/newview/llfloaterwebcontent.cpp index 6d2a2ae3e3..9d802c5fad 100644 --- a/indra/newview/llfloaterwebcontent.cpp +++ b/indra/newview/llfloaterwebcontent.cpp @@ -43,6 +43,7 @@ LLFloaterWebContent::_Params::_Params() : url("url"), target("target"), + initial_mime_type("initial_mime_type", "text/html"), id("id"), window_class("window_class", "web_content"), show_chrome("show_chrome", true), @@ -148,8 +149,7 @@ void LLFloaterWebContent::showInstance(const std::string& window_class, Params& LLSD key = p; - instance_iter it = beginInstances(); - for(;it!=endInstances();++it) + for(instance_iter it(beginInstances()), it_end(endInstances()); it != it_end; ++it) { if(it->mKey["window_class"].asString() == window_class) { @@ -166,7 +166,7 @@ void LLFloaterWebContent::showInstance(const std::string& window_class, Params& LLFloaterWebContent* old_inst = getInstance(p.id()); if(old_inst) { - llwarns << "Replacing unexpected duplicate floater: " << p.id() << llendl; + LL_WARNS() << "Replacing unexpected duplicate floater: " << p.id() << LL_ENDL; old_inst->mKey = key; old_inst->mAgeTimer.reset(); old_inst->open(); @@ -224,7 +224,7 @@ void LLFloaterWebContent::geometryChanged(S32 x, S32 y, S32 width, S32 height) width + getRect().getWidth() - browser_rect.getWidth(), height + getRect().getHeight() - browser_rect.getHeight()); - lldebugs << "geometry change: " << geom << llendl; + LL_DEBUGS() << "geometry change: " << geom << LL_ENDL; LLRect new_rect; getParent()->screenRectToLocal(geom, &new_rect); @@ -234,7 +234,7 @@ void LLFloaterWebContent::geometryChanged(S32 x, S32 y, S32 width, S32 height) // static void LLFloaterWebContent::preCreate(LLFloaterWebContent::Params& p) { - lldebugs << "url = " << p.url() << ", target = " << p.target() << ", uuid = " << p.id() << llendl; + LL_DEBUGS() << "url = " << p.url() << ", target = " << p.target() << ", uuid = " << p.id() << LL_ENDL; if (!p.id.isProvided()) { @@ -254,8 +254,7 @@ void LLFloaterWebContent::preCreate(LLFloaterWebContent::Params& p) std::vector instances; instances.reserve(instanceCount()); - instance_iter it = beginInstances(); - for(;it!=endInstances();++it) + for(instance_iter it(beginInstances()), it_end(endInstances()); it != it_end;++it) { if(it->mKey["window_class"].asString() == p.window_class.getValue()) instances.push_back(&*it); @@ -264,11 +263,11 @@ void LLFloaterWebContent::preCreate(LLFloaterWebContent::Params& p) std::sort(instances.begin(), instances.end(), CompareAgeDescending()); //LLFloaterReg::const_instance_list_t &instances = LLFloaterReg::getFloaterList(p.window_class); - lldebugs << "total instance count is " << instances.size() << llendl; + LL_DEBUGS() << "total instance count is " << instances.size() << LL_ENDL; for(std::vector::const_iterator iter = instances.begin(); iter != instances.end(); iter++) { - lldebugs << " " << (*iter)->mKey["target"] << llendl; + LL_DEBUGS() << " " << (*iter)->mKey["target"] << LL_ENDL; } if(instances.size() >= (size_t)browser_window_limit) @@ -283,9 +282,9 @@ void LLFloaterWebContent::open_media(const Params& p) { // Specifying a mime type of text/html here causes the plugin system to skip the MIME type probe and just open a browser plugin. LLViewerMedia::proxyWindowOpened(p.target(), p.id()); - mWebBrowser->setHomePageUrl(p.url, "text/html"); + mWebBrowser->setHomePageUrl(p.url, p.initial_mime_type); mWebBrowser->setTarget(p.target); - mWebBrowser->navigateTo(p.url, "text/html"); + mWebBrowser->navigateTo(p.url, p.initial_mime_type); set_current_url(p.url); diff --git a/indra/newview/llfloaterwebcontent.h b/indra/newview/llfloaterwebcontent.h index 9fabe42ac7..8dbca1d241 100644 --- a/indra/newview/llfloaterwebcontent.h +++ b/indra/newview/llfloaterwebcontent.h @@ -50,6 +50,7 @@ class LLFloaterWebContent : { Optional url, target, + initial_mime_type, window_class, id; Optional show_chrome, diff --git a/indra/newview/llfloaterwebprofile.cpp b/indra/newview/llfloaterwebprofile.cpp index c506c72fa8..8a5e79573d 100644 --- a/indra/newview/llfloaterwebprofile.cpp +++ b/indra/newview/llfloaterwebprofile.cpp @@ -49,11 +49,11 @@ void LLFloaterWebProfile::onOpen() // virtual void LLFloaterWebProfile::handleReshape(const LLRect& new_rect, bool by_user) { - lldebugs << "handleReshape: " << new_rect << llendl; + LL_DEBUGS() << "handleReshape: " << new_rect << LL_ENDL; if (by_user && !isMinimized()) { - lldebugs << "Storing new rect" << llendl; + LL_DEBUGS() << "Storing new rect" << LL_ENDL; gSavedSettings.setRect("WebProfileFloaterRect", new_rect); } @@ -68,8 +68,7 @@ void LLFloaterWebProfile::showInstance(const std::string& window_class, Params& LLSD key = p; - instance_iter it = beginInstances(); - for(;it!=endInstances();++it) + for(instance_iter it(beginInstances()), it_end(endInstances()); it != it_end; ++it) { if(it->mKey["window_class"].asString() == window_class) { @@ -86,7 +85,7 @@ void LLFloaterWebProfile::showInstance(const std::string& window_class, Params& LLFloaterWebContent* old_inst = getInstance(p.id()); if(old_inst) { - llwarns << "Replacing unexpected duplicate floater: " << p.id() << llendl; + LL_WARNS() << "Replacing unexpected duplicate floater: " << p.id() << LL_ENDL; old_inst->mKey = key; old_inst->mAgeTimer.reset(); old_inst->open(); @@ -107,7 +106,7 @@ LLFloater* LLFloaterWebProfile::create(const LLSD& key) void LLFloaterWebProfile::applyPreferredRect() { const LLRect preferred_rect = gSavedSettings.getRect("WebProfileFloaterRect"); - lldebugs << "Applying preferred rect: " << preferred_rect << llendl; + LL_DEBUGS() << "Applying preferred rect: " << preferred_rect << LL_ENDL; // Don't override position that may have been set by floater stacking code. // Singu Note: We do floater stacking here, actually diff --git a/indra/newview/llfloaterwhitelistentry.cpp b/indra/newview/llfloaterwhitelistentry.cpp index f930e09400..c7a17f136f 100644 --- a/indra/newview/llfloaterwhitelistentry.cpp +++ b/indra/newview/llfloaterwhitelistentry.cpp @@ -37,8 +37,9 @@ /////////////////////////////////////////////////////////////////////////////// // -LLFloaterWhiteListEntry::LLFloaterWhiteListEntry() : - LLFloater() +LLFloaterWhiteListEntry::LLFloaterWhiteListEntry() + : LLFloater() + , mWhiteListEdit(nullptr) { LLUICtrlFactory::getInstance()->buildFloater(this, "floater_whitelist_entry.xml"); } diff --git a/indra/newview/llfloaterwindlight.cpp b/indra/newview/llfloaterwindlight.cpp index 7e9eb6a1f8..9a9b9768fa 100644 --- a/indra/newview/llfloaterwindlight.cpp +++ b/indra/newview/llfloaterwindlight.cpp @@ -302,6 +302,10 @@ void LLFloaterWindLight::syncMenu() // blue horizon param_mgr->mBlueHorizon = cur_params.getVector(param_mgr->mBlueHorizon.mName, err); //setColorSwatch("WLBlueHorizon", param_mgr->mBlueHorizon, WL_BLUE_HORIZON_DENSITY_SCALE); + childSetValue("WLBlueHorizonR", param_mgr->mBlueHorizon.r / WL_BLUE_HORIZON_DENSITY_SCALE); + childSetValue("WLBlueHorizonG", param_mgr->mBlueHorizon.g / WL_BLUE_HORIZON_DENSITY_SCALE); + childSetValue("WLBlueHorizonB", param_mgr->mBlueHorizon.b / WL_BLUE_HORIZON_DENSITY_SCALE); + childSetValue("WLBlueHorizonI", param_mgr->mBlueHorizon.i / WL_BLUE_HORIZON_DENSITY_SCALE); // haze density, horizon, mult, and altitude param_mgr->mHazeDensity = cur_params.getFloat(param_mgr->mHazeDensity.mName, err); @@ -316,12 +320,20 @@ void LLFloaterWindLight::syncMenu() // blue density param_mgr->mBlueDensity = cur_params.getVector(param_mgr->mBlueDensity.mName, err); //setColorSwatch("WLBlueDensity", param_mgr->mBlueDensity, WL_BLUE_HORIZON_DENSITY_SCALE); + childSetValue("WLBlueDensityR", param_mgr->mBlueDensity.r / WL_BLUE_HORIZON_DENSITY_SCALE); + childSetValue("WLBlueDensityG", param_mgr->mBlueDensity.g / WL_BLUE_HORIZON_DENSITY_SCALE); + childSetValue("WLBlueDensityB", param_mgr->mBlueDensity.b / WL_BLUE_HORIZON_DENSITY_SCALE); + childSetValue("WLBlueDensityI", param_mgr->mBlueDensity.i / WL_BLUE_HORIZON_DENSITY_SCALE); // Lighting // sunlight param_mgr->mSunlight = cur_params.getVector(param_mgr->mSunlight.mName, err); //setColorSwatch("WLSunlight", param_mgr->mSunlight, WL_SUN_AMBIENT_SLIDER_SCALE); + childSetValue("WLSunlightR", param_mgr->mSunlight.r / WL_SUN_AMBIENT_SLIDER_SCALE); + childSetValue("WLSunlightG", param_mgr->mSunlight.g / WL_SUN_AMBIENT_SLIDER_SCALE); + childSetValue("WLSunlightB", param_mgr->mSunlight.b / WL_SUN_AMBIENT_SLIDER_SCALE); + childSetValue("WLSunlightI", param_mgr->mSunlight.i / WL_SUN_AMBIENT_SLIDER_SCALE); // glow param_mgr->mGlow = cur_params.getVector(param_mgr->mGlow.mName, err); @@ -331,6 +343,10 @@ void LLFloaterWindLight::syncMenu() // ambient param_mgr->mAmbient = cur_params.getVector(param_mgr->mAmbient.mName, err); //setColorSwatch("WLAmbient", param_mgr->mAmbient, WL_SUN_AMBIENT_SLIDER_SCALE); + childSetValue("WLAmbientR", param_mgr->mAmbient.r / WL_SUN_AMBIENT_SLIDER_SCALE); + childSetValue("WLAmbientG", param_mgr->mAmbient.g / WL_SUN_AMBIENT_SLIDER_SCALE); + childSetValue("WLAmbientB", param_mgr->mAmbient.b / WL_SUN_AMBIENT_SLIDER_SCALE); + childSetValue("WLAmbientI", param_mgr->mAmbient.i / WL_SUN_AMBIENT_SLIDER_SCALE); childSetValue("WLSunAngle", param_mgr->mCurParams.getFloat("sun_angle",err) / F_TWO_PI); childSetValue("WLEastAngle", param_mgr->mCurParams.getFloat("east_angle",err) / F_TWO_PI); @@ -340,6 +356,10 @@ void LLFloaterWindLight::syncMenu() // Cloud Color param_mgr->mCloudColor = cur_params.getVector(param_mgr->mCloudColor.mName, err); //setColorSwatch("WLCloudColor", param_mgr->mCloudColor, WL_CLOUD_SLIDER_SCALE); + childSetValue("WLCloudColorR", param_mgr->mCloudColor.r / WL_CLOUD_SLIDER_SCALE); + childSetValue("WLCloudColorG", param_mgr->mCloudColor.g / WL_CLOUD_SLIDER_SCALE); + childSetValue("WLCloudColorB", param_mgr->mCloudColor.b / WL_CLOUD_SLIDER_SCALE); + childSetValue("WLCloudColorI", param_mgr->mCloudColor.i / WL_CLOUD_SLIDER_SCALE); // Cloud param_mgr->mCloudMain = cur_params.getVector(param_mgr->mCloudMain.mName, err); @@ -493,18 +513,7 @@ void LLFloaterWindLight::onColorControlRMoved(LLUICtrl* ctrl, void* userdata) std::string name = color_ctrl->mSliderName; name.append("I"); - if (color_ctrl->isSunOrAmbientColor) - { - childSetValue(name, color_ctrl->r / WL_SUN_AMBIENT_SLIDER_SCALE); - } - else if (color_ctrl->isBlueHorizonOrDensity) - { - childSetValue(name, color_ctrl->r / WL_BLUE_HORIZON_DENSITY_SCALE); - } - else - { - childSetValue(name, color_ctrl->r); - } + childSetValue(name, sldr_ctrl->getValueF32()); } color_ctrl->update(LLWLParamManager::getInstance()->mCurParams); diff --git a/indra/newview/llfloaterworldmap.cpp b/indra/newview/llfloaterworldmap.cpp index 8081912946..e86ad2a184 100644 --- a/indra/newview/llfloaterworldmap.cpp +++ b/indra/newview/llfloaterworldmap.cpp @@ -39,6 +39,7 @@ #include "llfloaterworldmap.h" +#include "alfloaterregiontracker.h" #include "llagent.h" #include "llagentcamera.h" #include "llbutton.h" @@ -268,6 +269,7 @@ LLFloaterWorldMap::LLFloaterWorldMap() mCommitCallbackRegistrar.add("WMap.ShowAgent", boost::bind(&LLFloaterWorldMap::onShowAgentBtn, this)); mCommitCallbackRegistrar.add("WMap.Clear", boost::bind(&LLFloaterWorldMap::onClearBtn, this)); mCommitCallbackRegistrar.add("WMap.CopySLURL", boost::bind(&LLFloaterWorldMap::onCopySLURL, this)); + mCommitCallbackRegistrar.add("WMap.TrackRegion", boost::bind(&LLFloaterWorldMap::onTrackRegion, this)); LLUICtrlFactory::getInstance()->buildFloater(this, "floater_world_map.xml", &getFactoryMap()); gSavedSettings.getControl("PreferredMaturity")->getSignal()->connect(boost::bind(&LLFloaterWorldMap::onChangeMaturity, this)); @@ -513,7 +515,7 @@ void LLFloaterWorldMap::draw() } else { - if (mCompletingRegionName != "") + if (!mCompletingRegionName.empty()) { F64 seconds = LLTimer::getElapsedSeconds(); double value = fmod(seconds, 2); @@ -535,8 +537,10 @@ void LLFloaterWorldMap::draw() getChildView("Teleport")->setEnabled((BOOL)tracking_status); // getChildView("Clear")->setEnabled((BOOL)tracking_status); - getChildView("Show Destination")->setEnabled((BOOL)tracking_status || LLWorldMap::getInstance()->isTracking()); + bool is_tracking((BOOL)tracking_status || LLWorldMap::instance().isTracking()); + getChildView("Show Destination")->setEnabled(is_tracking); getChildView("copy_slurl")->setEnabled((mSLURL.isValid()) ); + getChild("track_region")->setEnabled(is_tracking); setMouseOpaque(TRUE); getDragHandle()->setMouseOpaque(TRUE); @@ -593,11 +597,10 @@ void LLFloaterWorldMap::trackAvatar( const LLUUID& avatar_id, const std::string& getChild("spin z")->setValue(LLSD(200.f)); } // Don't re-request info if we already have it or we won't have it in time to teleport - if (mTrackedStatus != LLTracker::TRACKING_AVATAR || name != mTrackedAvatarName) + if (mTrackedStatus != LLTracker::TRACKING_AVATAR || avatar_id != mTrackedAvatarID) { mTrackedStatus = LLTracker::TRACKING_AVATAR; - mTrackedAvatarName = name; - LLTracker::trackAvatar(avatar_id, name); + LLTracker::trackAvatar(mTrackedAvatarID = avatar_id, name); } } else @@ -614,10 +617,10 @@ void LLFloaterWorldMap::trackLandmark( const LLUUID& landmark_item_id ) buildLandmarkIDLists(); BOOL found = FALSE; - S32 idx; - for (idx = 0; idx < mLandmarkItemIDList.count(); idx++) + U32 idx; + for (idx = 0; idx < mLandmarkItemIDList.size(); idx++) { - if ( mLandmarkItemIDList.get(idx) == landmark_item_id) + if ( mLandmarkItemIDList.at(idx) == landmark_item_id) { found = TRUE; break; @@ -626,13 +629,13 @@ void LLFloaterWorldMap::trackLandmark( const LLUUID& landmark_item_id ) if (found && iface->setCurrentByID( landmark_item_id ) ) { - LLUUID asset_id = mLandmarkAssetIDList.get( idx ); + LLUUID asset_id = mLandmarkAssetIDList.at( idx ); std::string name; LLComboBox* combo = getChild( "landmark combo"); if (combo) name = combo->getSimple(); mTrackedStatus = LLTracker::TRACKING_LANDMARK; - LLTracker::trackLandmark(mLandmarkAssetIDList.get( idx ), // assetID - mLandmarkItemIDList.get( idx ), // itemID + LLTracker::trackLandmark(mLandmarkAssetIDList.at( idx ), // assetID + mLandmarkItemIDList.at( idx ), // itemID name); // name if( asset_id != sHomeID ) @@ -700,13 +703,19 @@ void LLFloaterWorldMap::trackLocation(const LLVector3d& pos_global) } std::string sim_name = sim_info->getName(); - F32 region_x = (F32)fmod( pos_global.mdV[VX], (F64)REGION_WIDTH_METERS ); - F32 region_y = (F32)fmod( pos_global.mdV[VY], (F64)REGION_WIDTH_METERS ); +// Aurora-sim var region teleports + //F32 region_x = (F32)fmod( pos_global.mdV[VX], (F64)REGION_WIDTH_METERS ); + //F32 region_y = (F32)fmod( pos_global.mdV[VY], (F64)REGION_WIDTH_METERS ); + U32 locX, locY; + from_region_handle(sim_info->getHandle(), &locX, &locY); + F32 region_x = pos_global.mdV[VX] - locX; + F32 region_y = pos_global.mdV[VY] - locY; +// std::string full_name = llformat("%s (%d, %d, %d)", sim_name.c_str(), - llround(region_x), - llround(region_y), - llround((F32)pos_global.mdV[VZ])); + ll_round(region_x), + ll_round(region_y), + ll_round((F32)pos_global.mdV[VZ])); std::string tooltip(""); mTrackedStatus = LLTracker::TRACKING_LOCATION; @@ -754,17 +763,27 @@ void LLFloaterWorldMap::updateTeleportCoordsDisplay( const LLVector3d& pos ) { // if we're going to update their value, we should also enable them enableTeleportCoordsDisplay( true ); - + // convert global specified position to a local one F32 region_local_x = (F32)fmod( pos.mdV[VX], (F64)REGION_WIDTH_METERS ); F32 region_local_y = (F32)fmod( pos.mdV[VY], (F64)REGION_WIDTH_METERS ); F32 region_local_z = (F32)llclamp( pos.mdV[VZ], 0.0, 8192.0/*(F64)REGION_HEIGHT_METERS*/ ); + LLSimInfo* sim_info = LLWorldMap::getInstance()->simInfoFromPosGlobal(pos); + if (sim_info) // Singu Note: Aurora var region support + { + U32 locX, locY; + from_region_handle(sim_info->getHandle(), &locX, &locY); + region_local_x = pos.mdV[VX] - locX; + region_local_y = pos.mdV[VY] - locY; + region_local_z = (F32)pos.mdV[VZ]; + // write in the values childSetValue("spin x", region_local_x ); childSetValue("spin y", region_local_y ); childSetValue("spin z", region_local_z ); } +} void LLFloaterWorldMap::updateLocation() { @@ -812,7 +831,10 @@ void LLFloaterWorldMap::updateLocation() // Figure out where user is // Set the current SLURL - mSLURL = LLSLURL(agent_sim_name, gAgent.getPositionGlobal()); +// Aurora-sim var region teleports + //mSLURL = LLSLURL(agent_sim_name, gAgent.getPositionGlobal()); + mSLURL = LLSLURL(agent_sim_name, gAgent.getPositionAgent()); +// } } @@ -856,6 +878,11 @@ void LLFloaterWorldMap::updateLocation() // [/RLVa:KB] // if ( gotSimName ) { + // Singu Note: Var region support for SLURLs + const LLSimInfo* sim = LLWorldMap::getInstance()->simInfoFromPosGlobal(pos_global); + const F64 size(sim ? sim->getSizeX() : 256); + pos_global[0] = fmod(pos_global[0], size); + pos_global[1] = fmod(pos_global[1], size); mSLURL = LLSLURL(sim_name, pos_global); } else @@ -999,15 +1026,15 @@ void LLFloaterWorldMap::buildLandmarkIDLists() list->operateOnSelection(LLCtrlListInterface::OP_DELETE); } - mLandmarkItemIDList.reset(); - mLandmarkAssetIDList.reset(); + mLandmarkItemIDList.clear(); + mLandmarkAssetIDList.clear(); // Get all of the current landmarks - mLandmarkAssetIDList.put( LLUUID::null ); - mLandmarkItemIDList.put( LLUUID::null ); + mLandmarkAssetIDList.push_back(LLUUID::null); + mLandmarkItemIDList.push_back(LLUUID::null); - mLandmarkAssetIDList.put( sHomeID ); - mLandmarkItemIDList.put( sHomeID ); + mLandmarkAssetIDList.push_back(sHomeID); + mLandmarkItemIDList.push_back(sHomeID); LLInventoryModel::cat_array_t cats; LLInventoryModel::item_array_t items; @@ -1020,15 +1047,15 @@ void LLFloaterWorldMap::buildLandmarkIDLists() std::sort(items.begin(), items.end(), LLViewerInventoryItem::comparePointers()); - S32 count = items.count(); + S32 count = items.size(); for(S32 i = 0; i < count; ++i) { - LLInventoryItem* item = items.get(i); + LLInventoryItem* item = items.at(i); list->addSimpleElement(item->getName(), ADD_BOTTOM, item->getUUID()); - mLandmarkAssetIDList.put( item->getAssetUUID() ); - mLandmarkItemIDList.put( item->getUUID() ); + mLandmarkAssetIDList.push_back(item->getAssetUUID()); + mLandmarkItemIDList.push_back(item->getUUID()); } list->sortByColumn(std::string("landmark name"), TRUE); @@ -1070,7 +1097,7 @@ void LLFloaterWorldMap::clearLocationSelection(BOOL clear_ui) } //Singu Note: Don't do this. It basically 'eats' the first click onto void space if the previous tracked target was a valid sim. //LLWorldMap::getInstance()->cancelTracking(); - mCompletingRegionName = ""; + mCompletingRegionName.clear(); } @@ -1404,6 +1431,28 @@ void LLFloaterWorldMap::onCopySLURL() LLNotificationsUtil::add("CopySLURL", args); } +void LLFloaterWorldMap::onTrackRegion() +{ + ALFloaterRegionTracker* floaterp = ALFloaterRegionTracker::getInstance(); + if (floaterp) + { + if (LLTracker::getTrackingStatus() != LLTracker::TRACKING_NOTHING) + { + std::string sim_name; + LLWorldMap::getInstance()->simNameFromPosGlobal(LLTracker::getTrackedPositionGlobal(), sim_name); + if (!sim_name.empty()) + { + const std::string& temp_label = floaterp->getRegionLabelIfExists(sim_name); + LLSD args, payload; + args["REGION"] = sim_name; + args["LABEL"] = !temp_label.empty() ? temp_label : sim_name; + payload["name"] = sim_name; + LLNotificationsUtil::add("RegionTrackerAdd", args, payload, boost::bind(&ALFloaterRegionTracker::onRegionAddedCallback, floaterp, _1, _2)); + } + } + } +} + // protected void LLFloaterWorldMap::centerOnTarget(BOOL animate) { @@ -1599,7 +1648,7 @@ void LLFloaterWorldMap::flyToAvatar() void LLFloaterWorldMap::updateSims(bool found_null_sim) { - if (mCompletingRegionName == "") + if (mCompletingRegionName.empty()) { return; } @@ -1607,8 +1656,6 @@ void LLFloaterWorldMap::updateSims(bool found_null_sim) LLScrollListCtrl *list = getChild("search_results"); list->operateOnAll(LLCtrlListInterface::OP_DELETE); - S32 name_length = mCompletingRegionName.length(); - LLSD match; S32 num_results = 0; @@ -1616,13 +1663,13 @@ void LLFloaterWorldMap::updateSims(bool found_null_sim) std::vector > sim_info_vec(LLWorldMap::getInstance()->getRegionMap().begin(), LLWorldMap::getInstance()->getRegionMap().end()); std::sort(sim_info_vec.begin(), sim_info_vec.end(), SortRegionNames()); - for (std::vector >::const_iterator it = sim_info_vec.begin(); it != sim_info_vec.end(); ++it) + for (const auto& sim_info_pair : sim_info_vec) { - LLSimInfo* info = it->second; + LLSimInfo* info = sim_info_pair.second; std::string sim_name_lower = info->getName(); LLStringUtil::toLower(sim_name_lower); - if (sim_name_lower.substr(0, name_length) == mCompletingRegionName) + if (sim_name_lower.find(mCompletingRegionName) != std::string::npos) { if (sim_name_lower == mCompletingRegionName) { @@ -1640,7 +1687,7 @@ void LLFloaterWorldMap::updateSims(bool found_null_sim) if (found_null_sim || match.isDefined()) { - mCompletingRegionName = ""; + mCompletingRegionName.clear(); } if (num_results > 0) @@ -1680,10 +1727,9 @@ void LLFloaterWorldMap::onCommitSearchResult() } LLStringUtil::toLower(sim_name); - std::map::const_iterator it; - for (it = LLWorldMap::getInstance()->getRegionMap().begin(); it != LLWorldMap::getInstance()->getRegionMap().end(); ++it) + for (auto map_pair : LLWorldMap::getInstance()->getRegionMap()) { - LLSimInfo* info = it->second; + LLSimInfo* info = map_pair.second; if (info->isName(sim_name)) { @@ -1718,10 +1764,10 @@ void LLFloaterWorldMap::onChangeMaturity() bool can_access_adult = gAgent.canAccessAdult(); getChildView("events_mature_icon")->setVisible( can_access_mature); - getChildView("event_mature_chk")->setVisible( can_access_mature); + getChildView("events_mature_chk")->setVisible( can_access_mature); getChildView("events_adult_icon")->setVisible( can_access_adult); - getChildView("event_adult_chk")->setVisible( can_access_adult); + getChildView("events_adult_chk")->setVisible( can_access_adult); // disable mature / adult events. if (!can_access_mature) diff --git a/indra/newview/llfloaterworldmap.h b/indra/newview/llfloaterworldmap.h index 499e9c79a7..2e5a1b9050 100644 --- a/indra/newview/llfloaterworldmap.h +++ b/indra/newview/llfloaterworldmap.h @@ -37,7 +37,6 @@ #ifndef LL_LLFLOATERWORLDMAP_H #define LL_LLFLOATERWORLDMAP_H -#include "lldarray.h" #include "llfloater.h" #include "llhudtext.h" #include "llmapimagetype.h" @@ -132,6 +131,7 @@ class LLFloaterWorldMap : public LLFloater void onShowTargetBtn(); void onShowAgentBtn(); void onCopySLURL(); + void onTrackRegion(); void centerOnTarget(BOOL animate); void updateLocation(); @@ -169,8 +169,8 @@ class LLFloaterWorldMap : public LLFloater // enable/disable teleport destination coordinates void enableTeleportCoordsDisplay( bool enabled ); - LLDynamicArray mLandmarkAssetIDList; - LLDynamicArray mLandmarkItemIDList; + uuid_vec_t mLandmarkAssetIDList; + uuid_vec_t mLandmarkItemIDList; static const LLUUID sHomeID; @@ -192,7 +192,7 @@ class LLFloaterWorldMap : public LLFloater LLVector3d mTrackedLocation; LLTracker::ETrackingStatus mTrackedStatus; std::string mTrackedSimName; - std::string mTrackedAvatarName; + LLUUID mTrackedAvatarID; LLSLURL mSLURL; LLCtrlListInterface * mListFriendCombo; diff --git a/indra/newview/llfolderview.cpp b/indra/newview/llfolderview.cpp index 4b6142a393..67dfddd5b2 100644 --- a/indra/newview/llfolderview.cpp +++ b/indra/newview/llfolderview.cpp @@ -66,6 +66,7 @@ // Linden library includes #include "lldbstrings.h" +#include "llfavoritesbar.h" // Singu TODO: Favorites bar. #include "llfocusmgr.h" #include "llfontgl.h" #include "llgl.h" @@ -176,7 +177,7 @@ void LLCloseAllFoldersFunctor::doItem(LLFolderViewItem* item) // Default constructor LLFolderView::LLFolderView( const std::string& name, - const LLRect& rect, const LLUUID& source_id, LLPanel *parent_view, LLFolderViewEventListener* listener ) : + const LLRect& rect, const LLUUID& source_id, LLPanel* parent_panel, LLFolderViewEventListener* listener, LLFolderViewGroupedItemModel* group_model ) : #if LL_WINDOWS #pragma warning( push ) #pragma warning( disable : 4355 ) // warning C4355: 'this' : used in base member initializer list @@ -201,19 +202,21 @@ LLFolderView::LLFolderView( const std::string& name, mNeedsAutoRename(FALSE), mDebugFilters(FALSE), mSortOrder(LLInventoryFilter::SO_FOLDERS_BY_NAME), // This gets overridden by a pref immediately - mFilter( new LLInventoryFilter(name) ), + mFilter(LLInventoryFilter::Params().name(name)), mShowSelectionContext(FALSE), mShowSingleSelection(FALSE), mArrangeGeneration(0), mSignalSelectCallback(0), mMinWidth(0), mDragAndDropThisFrame(FALSE), - mParentPanel(parent_view), mUseEllipses(FALSE), mDraggingOverItem(NULL), mStatusTextBox(NULL), - mSearchType(1) + mSearchType(1), + mGroupedItemModel(group_model) { + LLPanel* panel = parent_panel; + mParentPanel = panel->getHandle(); mRoot = this; mShowLoadStatus = TRUE; @@ -256,7 +259,7 @@ LLFolderView::LLFolderView( const std::string& name, mStatusTextBox->setVPad(STATUS_TEXT_VPAD); mStatusTextBox->setFollows(FOLLOWS_LEFT|FOLLOWS_TOP); // make the popup menu available - LLMenuGL* menu = LLUICtrlFactory::getInstance()->buildMenu("menu_inventory.xml", parent_view); + LLMenuGL* menu = LLUICtrlFactory::getInstance()->buildMenu("menu_inventory.xml", parent_panel); if (!menu) { menu = new LLMenuGL(LLStringUtil::null); @@ -296,9 +299,6 @@ LLFolderView::~LLFolderView( void ) mFolders.clear(); mItemMap.clear(); - - delete mFilter; - mFilter = NULL; } BOOL LLFolderView::canFocusChildren() const @@ -306,13 +306,13 @@ BOOL LLFolderView::canFocusChildren() const return FALSE; } -static LLFastTimer::DeclareTimer FTM_SORT("Sort Inventory"); +static LLTrace::BlockTimerStatHandle FTM_SORT("Sort Inventory"); void LLFolderView::setSortOrder(U32 order) { if (order != mSortOrder) { - LLFastTimer t(FTM_SORT); + LL_RECORD_BLOCK_TIME(FTM_SORT); mSortOrder = order; @@ -369,7 +369,7 @@ U32 LLFolderView::toggleSearchType(std::string toggle) if (getFilterSubString().length()) { - mFilter->setModified(LLInventoryFilter::FILTER_RESTART); + mFilter.setModified(LLInventoryFilter::FILTER_RESTART); } return mSearchType; @@ -426,7 +426,7 @@ void LLFolderView::setOpenArrangeRecursively(BOOL openitem, ERecurseType recurse mIsOpen = TRUE; } -static LLFastTimer::DeclareTimer FTM_ARRANGE("Arrange"); +static LLTrace::BlockTimerStatHandle FTM_ARRANGE("Arrange"); // This view grows and shrinks to enclose all of its children items and folders. S32 LLFolderView::arrange( S32* unused_width, S32* unused_height, S32 filter_generation ) @@ -443,9 +443,9 @@ S32 LLFolderView::arrange( S32* unused_width, S32* unused_height, S32 filter_gen } } - LLFastTimer t2(FTM_ARRANGE); + LL_RECORD_BLOCK_TIME(FTM_ARRANGE); - filter_generation = mFilter->getMinRequiredGeneration(); + filter_generation = mFilter.getFirstSuccessGeneration(); mMinWidth = 0; mHasVisibleChildren = hasFilteredDescendants(filter_generation); @@ -453,7 +453,7 @@ S32 LLFolderView::arrange( S32* unused_width, S32* unused_height, S32 filter_gen mLastArrangeGeneration = getRoot()->getArrangeGeneration(); LLInventoryFilter::EFolderShow show_folder_state = - getRoot()->getFilter()->getShowFolderState(); + getRoot()->getFilter().getShowFolderState(); S32 total_width = LEFT_PAD; S32 running_height = mDebugFilters ? llceil(LLFontGL::getFontMonospace()->getLineHeight()) : 0; @@ -534,19 +534,19 @@ S32 LLFolderView::arrange( S32* unused_width, S32* unused_height, S32 filter_gen updateRenamerPosition(); mTargetHeight = (F32)target_height; - return llround(mTargetHeight); + return ll_round(mTargetHeight); } const std::string LLFolderView::getFilterSubString(BOOL trim) { - return mFilter->getFilterSubString(trim); + return mFilter.getFilterSubString(trim); } -static LLFastTimer::DeclareTimer FTM_FILTER("Filter Inventory"); +static LLTrace::BlockTimerStatHandle FTM_FILTER("Filter Inventory"); void LLFolderView::filter( LLInventoryFilter& filter ) { - LLFastTimer t2(FTM_FILTER); + LL_RECORD_BLOCK_TIME(FTM_FILTER); filter.setFilterCount(llclamp(gSavedSettings.getS32("FilterItemsPerFrame"), 1, 5000)); if (getCompletedFilterGeneration() < filter.getCurrentGeneration()) @@ -631,6 +631,10 @@ LLFolderViewItem* LLFolderView::getCurSelectedItem( void ) return NULL; } +LLFolderView::selected_items_t& LLFolderView::getSelectedItems( void ) +{ + return mSelectedItems; +} // Record the selected item and pass it down the hierachy. BOOL LLFolderView::setSelection(LLFolderViewItem* selection, BOOL openitem, @@ -645,7 +649,7 @@ BOOL LLFolderView::setSelection(LLFolderViewItem* selection, BOOL openitem, if( selection && take_keyboard_focus) { - mParentPanel->setFocus(TRUE); + mParentPanel.get()->setFocus(TRUE); } // clear selection down here because change of keyboard focus can potentially @@ -734,16 +738,16 @@ BOOL LLFolderView::changeSelection(LLFolderViewItem* selection, BOOL selected) return rv; } -static LLFastTimer::DeclareTimer FTM_SANITIZE_SELECTION("Sanitize Selection"); +static LLTrace::BlockTimerStatHandle FTM_SANITIZE_SELECTION("Sanitize Selection"); void LLFolderView::sanitizeSelection() { - LLFastTimer _(FTM_SANITIZE_SELECTION); + LL_RECORD_BLOCK_TIME(FTM_SANITIZE_SELECTION); // store off current item in case it is automatically deselected // and we want to preserve context LLFolderViewItem* original_selected_item = getCurSelectedItem(); // Cache "Show all folders" filter setting - BOOL show_all_folders = (getRoot()->getFilter()->getShowFolderState() == LLInventoryFilter::SHOW_ALL_FOLDERS); + BOOL show_all_folders = (getRoot()->getFilter().getShowFolderState() == LLInventoryFilter::SHOW_ALL_FOLDERS); std::vector items_to_remove; selected_items_t::iterator item_iter; @@ -861,24 +865,23 @@ void LLFolderView::clearSelection() mSelectThisID.setNull(); } -std::set LLFolderView::getSelectionList() const +uuid_set_t LLFolderView::getSelectionList() const { - std::set selection; - for (selected_items_t::const_iterator item_it = mSelectedItems.begin(); - item_it != mSelectedItems.end(); - ++item_it) + uuid_set_t selection; + for (const auto& item : mSelectedItems) { - selection.insert((*item_it)->getListener()->getUUID()); + selection.insert(item->getListener()->getUUID()); } return selection; } -BOOL LLFolderView::startDrag(LLToolDragAndDrop::ESource source) +bool LLFolderView::startDrag(LLToolDragAndDrop::ESource source) { std::vector types; uuid_vec_t cargo_ids; selected_items_t::iterator item_it; - BOOL can_drag = TRUE; + bool can_drag = true; + if (!mSelectedItems.empty()) { for (item_it = mSelectedItems.begin(); item_it != mSelectedItems.end(); ++item_it) @@ -906,7 +909,7 @@ void LLFolderView::draw() if (mDebugFilters) { std::string current_filter_string = llformat("Current Filter: %d, Least Filter: %d, Auto-accept Filter: %d", - mFilter->getCurrentGeneration(), mFilter->getMinRequiredGeneration(), mFilter->getMustPassGeneration()); + mFilter.getCurrentGeneration(), mFilter.getFirstSuccessGeneration(), mFilter.getFirstRequiredGeneration()); LLFontGL::getFontMonospace()->renderUTF8(current_filter_string, 0, 2, getRect().getHeight() - LLFontGL::getFontMonospace()->getLineHeight(), LLColor4(0.5f, 0.5f, 0.8f, 1.f), LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE ); @@ -920,31 +923,25 @@ void LLFolderView::draw() } // while dragging, update selection rendering to reflect single/multi drag status - if (LLToolDragAndDrop::getInstance()->hasMouseCapture()) + LLToolDragAndDrop& dad_inst(LLToolDragAndDrop::instance()); + if (dad_inst.hasMouseCapture()) { - EAcceptance last_accept = LLToolDragAndDrop::getInstance()->getLastAccept(); - if (last_accept == ACCEPT_YES_SINGLE || last_accept == ACCEPT_YES_COPY_SINGLE) - { - setShowSingleSelection(TRUE); - } - else - { - setShowSingleSelection(FALSE); - } + EAcceptance last_accept = dad_inst.getLastAccept(); + setShowSingleSelection(last_accept == ACCEPT_YES_SINGLE || last_accept == ACCEPT_YES_COPY_SINGLE); } else { setShowSingleSelection(FALSE); } - - if (mSearchTimer.getElapsedTimeF32() > gSavedSettings.getF32("TypeAheadTimeout") || !mSearchString.size()) + static LLUICachedControl type_ahead_timeout("TypeAheadTimeout", 0); + if (mSearchTimer.getElapsedTimeF32() > type_ahead_timeout || !mSearchString.size()) { mSearchString.clear(); } if (hasVisibleChildren() - || mFilter->getShowFolderState() == LLInventoryFilter::SHOW_ALL_FOLDERS) + || mFilter.getShowFolderState() == LLInventoryFilter::SHOW_ALL_FOLDERS) { mStatusText.clear(); mStatusTextBox->setVisible( FALSE ); @@ -952,18 +949,13 @@ void LLFolderView::draw() else if (mShowEmptyMessage) { static LLCachedControl sSearchStatusColor(gColors, "InventorySearchStatusColor", LLColor4::white ); - if (LLInventoryModelBackgroundFetch::instance().folderFetchActive() || mCompletedFilterGeneration < mFilter->getMinRequiredGeneration()) + if (LLInventoryModelBackgroundFetch::instance().folderFetchActive() || mCompletedFilterGeneration < mFilter.getFirstSuccessGeneration()) { mStatusText = LLTrans::getString("Searching"); } else { - // if(getFilter()) - // { - // LLStringUtil::format_map_t args; - // args["[SEARCH_TERM]"] = LLURI::escape(getFilter()->getFilterSubStringOrig()); - mStatusText = LLTrans::getString("InventoryNoMatchingItems"); //, args); - // } + mStatusText = getFilter().getEmptyLookupMessage(); } mStatusTextBox->setWrappedText(mStatusText); mStatusTextBox->setVisible( TRUE ); @@ -975,7 +967,7 @@ void LLFolderView::draw() // get preferable text height... S32 pixel_height = mStatusTextBox->getTextPixelHeight(); - bool height_changed = local_rect.getHeight() != pixel_height; + bool height_changed = (local_rect.getHeight() != pixel_height); if (height_changed) { // ... if it does not match current height, lets rearrange current view. @@ -986,6 +978,8 @@ void LLFolderView::draw() } } + // skip over LLFolderViewFolder::draw since we don't want the folder icon, label, + // and arrow for the root folder LLView::draw(); mDragAndDropThisFrame = FALSE; @@ -1004,7 +998,7 @@ void LLFolderView::finishRenamingItem( void ) closeRenamer(); - // List is re-sorted alphabeticly, so scroll to make sure the selected item is visible. + // List is re-sorted alphabetically, so scroll to make sure the selected item is visible. scrollToShowSelection(); } @@ -1052,9 +1046,9 @@ void LLFolderView::removeCutItems() return; // Get the list of clipboard item uuids and iterate through them - LLDynamicArray objects; + uuid_vec_t objects; LLInventoryClipboard::instance().retrieve(objects); - for (LLDynamicArray::const_iterator iter = objects.begin(); + for (auto iter = objects.begin(); iter != objects.end(); ++iter) { @@ -1062,7 +1056,7 @@ void LLFolderView::removeCutItems() } } -void LLFolderView::removeSelectedItems( void ) +void LLFolderView::removeSelectedItems() { if(getVisible() && getEnabled()) { @@ -1073,8 +1067,7 @@ void LLFolderView::removeSelectedItems( void ) // items, since the removal will futz with internal data // structures. std::vector items; - S32 count = mSelectedItems.size(); - if(count == 0) return; + if(mSelectedItems.empty()) return; LLFolderViewItem* item = NULL; selected_items_t::iterator item_it; for (item_it = mSelectedItems.begin(); item_it != mSelectedItems.end(); ++item_it) @@ -1086,13 +1079,13 @@ void LLFolderView::removeSelectedItems( void ) } else { - llinfos << "Cannot delete " << item->getName() << llendl; + LL_INFOS() << "Cannot delete " << item->getName() << LL_ENDL; return; } } // iterate through the new container. - count = items.size(); + size_t count = items.size(); LLUUID new_selection_id; if(count == 1) { @@ -1110,11 +1103,11 @@ void LLFolderView::removeSelectedItems( void ) // change selection on successful delete if (new_selection) { - setSelectionFromRoot(new_selection, new_selection->isOpen(), mParentPanel->hasFocus()); + setSelectionFromRoot(new_selection, new_selection->isOpen(), mParentPanel.get()->hasFocus()); } else { - setSelectionFromRoot(NULL, mParentPanel->hasFocus()); + setSelectionFromRoot(NULL, mParentPanel.get()->hasFocus()); } } } @@ -1122,7 +1115,7 @@ void LLFolderView::removeSelectedItems( void ) } else if (count > 1) { - LLDynamicArray listeners; + std::vector listeners; LLFolderViewEventListener* listener; LLFolderViewItem* last_item = items[count - 1]; LLFolderViewItem* new_selection = last_item->getNextOpenNode(FALSE); @@ -1140,22 +1133,22 @@ void LLFolderView::removeSelectedItems( void ) } if (new_selection) { - setSelectionFromRoot(new_selection, new_selection->isOpen(), mParentPanel->hasFocus()); + setSelectionFromRoot(new_selection, new_selection->isOpen(), mParentPanel.get()->hasFocus()); } else { - setSelectionFromRoot(NULL, mParentPanel->hasFocus()); + setSelectionFromRoot(NULL, mParentPanel.get()->hasFocus()); } - for(S32 i = 0; i < count; ++i) + for(size_t i = 0; i < count; ++i) { listener = items[i]->getListener(); - if(listener && (listeners.find(listener) == LLDynamicArray::FAIL)) + if(listener && (std::find(listeners.begin(), listeners.end(), listener) == listeners.end())) { - listeners.put(listener); + listeners.push_back(listener); } } - listener = listeners.get(0); + listener = listeners.at(0); if(listener) { listener->removeBatch(listeners); @@ -1340,25 +1333,22 @@ BOOL LLFolderView::canCopy() const } // copy selected item -void LLFolderView::copy() +void LLFolderView::copy() const { // *NOTE: total hack to clear the inventory clipboard LLInventoryClipboard::instance().reset(); S32 count = mSelectedItems.size(); if(getVisible() && getEnabled() && (count > 0)) { - LLFolderViewEventListener* listener = NULL; - selected_items_t::iterator item_it; - for (item_it = mSelectedItems.begin(); item_it != mSelectedItems.end(); ++item_it) + for (auto item : mSelectedItems) { - listener = (*item_it)->getListener(); - if(listener) + if(auto listener = item->getListener()) { listener->copyToClipboard(); } } } - mSearchString.clear(); + //mSearchString.clear(); // Singu Note: There's no good reason to clear out the jumpto item search string now, it'll time out anyway, let's remain const } BOOL LLFolderView::canCut() const @@ -1544,60 +1534,70 @@ BOOL LLFolderView::handleKeyHere( KEY key, MASK mask ) case KEY_PAGE_UP: mSearchString.clear(); - mScrollContainer->pageUp(30); + if (mScrollContainer) + { + mScrollContainer->pageUp(30); + } handled = TRUE; break; case KEY_PAGE_DOWN: mSearchString.clear(); - mScrollContainer->pageDown(30); + if (mScrollContainer) + { + mScrollContainer->pageDown(30); + } handled = TRUE; break; case KEY_HOME: mSearchString.clear(); - mScrollContainer->goToTop(); + if (mScrollContainer) + { + mScrollContainer->goToTop(); + } handled = TRUE; break; case KEY_END: mSearchString.clear(); - mScrollContainer->goToBottom(); + if (mScrollContainer) + { + mScrollContainer->goToBottom(); + } break; case KEY_DOWN: if((mSelectedItems.size() > 0) && mScrollContainer) { LLFolderViewItem* last_selected = getCurSelectedItem(); + bool shift_select = mask & MASK_SHIFT; + LLFolderViewItem* next = last_selected->getNextOpenNode(!shift_select); - if (!mKeyboardSelection) + if (!mKeyboardSelection || (!shift_select && (!next || next == last_selected))) { setSelection(last_selected, FALSE, TRUE); mKeyboardSelection = TRUE; } - LLFolderViewItem* next = NULL; - if (mask & MASK_SHIFT) + if (shift_select) { - // don't shift select down to children of folders (they are implicitly selected through parent) - next = last_selected->getNextOpenNode(FALSE); if (next) { if (next->isSelected()) { // shrink selection - changeSelectionFromRoot(last_selected, FALSE); + changeSelection(last_selected, FALSE); } else if (last_selected->getParentFolder() == next->getParentFolder()) { // grow selection - changeSelectionFromRoot(next, TRUE); + changeSelection(next, TRUE); } } } else { - next = last_selected->getNextOpenNode(); if( next ) { if (next == last_selected) @@ -1633,35 +1633,34 @@ BOOL LLFolderView::handleKeyHere( KEY key, MASK mask ) if((mSelectedItems.size() > 0) && mScrollContainer) { LLFolderViewItem* last_selected = mSelectedItems.back(); + bool shift_select = mask & MASK_SHIFT; + // don't shift select down to children of folders (they are implicitly selected through parent) + LLFolderViewItem* prev = last_selected->getPreviousOpenNode(!shift_select); - if (!mKeyboardSelection) + if (!mKeyboardSelection || (!shift_select && prev == this)) { setSelection(last_selected, FALSE, TRUE); mKeyboardSelection = TRUE; } - LLFolderViewItem* prev = NULL; - if (mask & MASK_SHIFT) + if (shift_select) { - // don't shift select down to children of folders (they are implicitly selected through parent) - prev = last_selected->getPreviousOpenNode(FALSE); if (prev) { if (prev->isSelected()) { // shrink selection - changeSelectionFromRoot(last_selected, FALSE); + changeSelection(last_selected, FALSE); } else if (last_selected->getParentFolder() == prev->getParentFolder()) { // grow selection - changeSelectionFromRoot(prev, TRUE); + changeSelection(prev, TRUE); } } } else { - prev = last_selected->getPreviousOpenNode(); if( prev ) { if (prev == this) @@ -1715,7 +1714,7 @@ BOOL LLFolderView::handleKeyHere( KEY key, MASK mask ) break; } - if (!handled && mParentPanel->hasFocus()) + if (!handled && mParentPanel.get()->hasFocus()) { if (key == KEY_BACKSPACE) { @@ -1724,7 +1723,7 @@ BOOL LLFolderView::handleKeyHere( KEY key, MASK mask ) { mSearchString.erase(mSearchString.size() - 1, 1); } - search(getCurSelectedItem(), mSearchString, FALSE); + search(getCurSelectedItem(), wstring_to_utf8str(mSearchString), FALSE); handled = TRUE; } } @@ -1740,14 +1739,8 @@ BOOL LLFolderView::handleUnicodeCharHere(llwchar uni_char) return FALSE; } - if (uni_char > 0x7f) - { - llwarns << "LLFolderView::handleUnicodeCharHere - Don't handle non-ascii yet, aborting" << llendl; - return FALSE; - } - BOOL handled = FALSE; - if (mParentPanel->hasFocus()) + if (mParentPanel.get()->hasFocus()) { // SL-51858: Key presses are not being passed to the Popup menu. // A proper fix is non-trivial so instead just close the menu. @@ -1758,7 +1751,8 @@ BOOL LLFolderView::handleUnicodeCharHere(llwchar uni_char) } //do text search - if (mSearchTimer.getElapsedTimeF32() > gSavedSettings.getF32("TypeAheadTimeout")) + static LLUICachedControl type_ahead_timeout("TypeAheadTimeout", 0.f); + if (mSearchTimer.getElapsedTimeF32() > type_ahead_timeout) { mSearchString.clear(); } @@ -1767,7 +1761,7 @@ BOOL LLFolderView::handleUnicodeCharHere(llwchar uni_char) { mSearchString += uni_char; } - search(getCurSelectedItem(), mSearchString, FALSE); + search(getCurSelectedItem(), wstring_to_utf8str(mSearchString), FALSE); handled = TRUE; } @@ -1804,7 +1798,7 @@ BOOL LLFolderView::handleMouseDown( S32 x, S32 y, MASK mask ) mKeyboardSelection = FALSE; mSearchString.clear(); - mParentPanel->setFocus(TRUE); + mParentPanel.get()->setFocus(TRUE); LLEditMenuHandler::gEditMenuHandler = this; @@ -1887,13 +1881,13 @@ BOOL LLFolderView::handleRightMouseDown( S32 x, S32 y, MASK mask ) { // all user operations move keyboard focus to inventory // this way, we know when to stop auto-updating a search - mParentPanel->setFocus(TRUE); + mParentPanel.get()->setFocus(TRUE); BOOL handled = childrenHandleRightMouseDown(x, y, mask) != NULL; S32 count = mSelectedItems.size(); LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get(); if ( handled - && ( count > 0 && (hasVisibleChildren() || mFilter->getShowFolderState() == LLInventoryFilter::SHOW_ALL_FOLDERS) ) // show menu only if selected items are visible + && ( count > 0 && (hasVisibleChildren() || mFilter.getShowFolderState() == LLInventoryFilter::SHOW_ALL_FOLDERS) ) // show menu only if selected items are visible && menu ) { updateMenuOptions(menu); @@ -1980,7 +1974,7 @@ BOOL LLFolderView::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, if (handled) { - lldebugst(LLERR_USER_INPUT) << "dragAndDrop handled by LLFolderView" << llendl; + LL_DEBUGS("UserInput") << "dragAndDrop handled by LLFolderView" << LL_ENDL; } return handled; @@ -2016,7 +2010,7 @@ void LLFolderView::scrollToShowSelection() // However we allow scrolling for folder views with mAutoSelectOverride // (used in Places SP) as an exception because the selection in them // is not reset during items filtering. See STORM-133. - if ( (!LLInventoryModelBackgroundFetch::instance().folderFetchActive() || mAutoSelectOverride) + if ( (LLInventoryModelBackgroundFetch::instance().isEverythingFetched() || mAutoSelectOverride) && mSelectedItems.size() ) { mNeedsScroll = TRUE; @@ -2043,7 +2037,7 @@ void LLFolderView::scrollToShowItem(LLFolderViewItem* item, const LLRect& constr LLRect item_scrolled_rect; // item position relative to display area of scroller S32 icon_height = mIcon.isNull() ? 0 : mIcon->getHeight(); - S32 label_height = llround(getLabelFontForStyle(mLabelStyle)->getLineHeight()); + S32 label_height = ll_round(getLabelFontForStyle(mLabelStyle)->getLineHeight()); // when navigating with keyboard, only move top of opened folder on screen, otherwise show whole folder S32 max_height_to_show = item->isOpen() && mScrollContainer->hasFocus() ? (llmax( icon_height, label_height ) + ICON_PAD) : local_rect.getHeight(); @@ -2091,7 +2085,7 @@ BOOL LLFolderView::getShowSelectionContext() return FALSE; } -void LLFolderView::setShowSingleSelection(BOOL show) +void LLFolderView::setShowSingleSelection(bool show) { if (show != mShowSingleSelection) { @@ -2110,17 +2104,16 @@ void LLFolderView::removeItemID(const LLUUID& id) mItemMap.erase(id); } -LLFastTimer::DeclareTimer FTM_GET_ITEM_BY_ID("Get FolderViewItem by ID"); +LLTrace::BlockTimerStatHandle FTM_GET_ITEM_BY_ID("Get FolderViewItem by ID"); LLFolderViewItem* LLFolderView::getItemByID(const LLUUID& id) { - LLFastTimer _(FTM_GET_ITEM_BY_ID); + LL_RECORD_BLOCK_TIME(FTM_GET_ITEM_BY_ID); if (id == getListener()->getUUID()) { return this; } - std::map::iterator map_it; - map_it = mItemMap.find(id); + auto map_it = mItemMap.find(id); if (map_it != mItemMap.end()) { return map_it->second; @@ -2150,20 +2143,25 @@ LLFolderViewFolder* LLFolderView::getFolderByID(const LLUUID& id) } -static LLFastTimer::DeclareTimer FTM_AUTO_SELECT("Open and Select"); -static LLFastTimer::DeclareTimer FTM_INVENTORY("Inventory"); +static LLTrace::BlockTimerStatHandle FTM_AUTO_SELECT("Open and Select"); +static LLTrace::BlockTimerStatHandle FTM_INVENTORY("Inventory"); // Main idle routine void LLFolderView::doIdle() { // If this is associated with the user's inventory, don't do anything // until that inventory is loaded up. - const LLInventoryPanel *inventory_panel = dynamic_cast(mParentPanel); + const LLInventoryPanel *inventory_panel = dynamic_cast(mParentPanel.get()); if (inventory_panel && !inventory_panel->getIsViewsInitialized()) { return; } + + // We have all items, now we can save them to favorites + BOOL collectFavoriteItems(LLInventoryModel::item_array_t&); // Singu TODO: Proper Favorites Bar + LLInventoryModel::item_array_t items; + collectFavoriteItems(items); - LLFastTimer t2(FTM_INVENTORY); + LL_RECORD_BLOCK_TIME(FTM_INVENTORY); BOOL debug_filters = gSavedSettings.getBOOL("DebugInventoryFilters"); if (debug_filters != getDebugFilters()) @@ -2172,9 +2170,9 @@ void LLFolderView::doIdle() arrangeAll(); } - mFilter->clearModified(); - BOOL filter_modified_and_active = mCompletedFilterGeneration < mFilter->getCurrentGeneration() && - mFilter->isNotDefault(); + mFilter.clearModified(); + BOOL filter_modified_and_active = mCompletedFilterGeneration < mFilter.getCurrentGeneration() && + mFilter.isNotDefault(); mNeedsAutoSelect = filter_modified_and_active && !(gFocusMgr.childHasKeyboardFocus(this) || gFocusMgr.getMouseCapture()); @@ -2188,7 +2186,7 @@ void LLFolderView::doIdle() // potentially changed if (mNeedsAutoSelect) { - LLFastTimer t3(FTM_AUTO_SELECT); + LL_RECORD_BLOCK_TIME(FTM_AUTO_SELECT); // select new item only if a filtered item not currently selected LLFolderViewItem* selected_itemp = mSelectedItems.empty() ? NULL : mSelectedItems.back(); if ((selected_itemp && !selected_itemp->getFiltered()) && !mAutoSelectOverride) @@ -2200,7 +2198,7 @@ void LLFolderView::doIdle() // Open filtered folders for folder views with mAutoSelectOverride=TRUE. // Used by LLPlacesFolderView. - if (mAutoSelectOverride && !mFilter->getFilterSubString().empty()) + if (mAutoSelectOverride && !mFilter.getFilterSubString().empty()) { LLOpenFilteredFolders filter; applyFunctorRecursively(filter); @@ -2306,14 +2304,14 @@ void LLFolderView::idle(void* user_data) void LLFolderView::dumpSelectionInformation() { - llinfos << "LLFolderView::dumpSelectionInformation()" << llendl; - llinfos << "****************************************" << llendl; + LL_INFOS() << "LLFolderView::dumpSelectionInformation()" << LL_NEWLINE + << "****************************************" << LL_ENDL; selected_items_t::iterator item_it; for (item_it = mSelectedItems.begin(); item_it != mSelectedItems.end(); ++item_it) { - llinfos << " " << (*item_it)->getName() << llendl; + LL_INFOS() << " " << (*item_it)->getName() << LL_ENDL; } - llinfos << "****************************************" << llendl; + LL_INFOS() << "****************************************" << LL_ENDL; } void LLFolderView::updateRenamerPosition() @@ -2353,15 +2351,23 @@ void LLFolderView::updateMenuOptions(LLMenuGL* menu) } // Successively filter out invalid options - - U32 flags = FIRST_SELECTED_ITEM; + U32 multi_select_flag = (mSelectedItems.size() > 1 ? ITEM_IN_MULTI_SELECTION : 0x0); + U32 flags = multi_select_flag | FIRST_SELECTED_ITEM; for (selected_items_t::iterator item_itor = mSelectedItems.begin(); item_itor != mSelectedItems.end(); ++item_itor) { LLFolderViewItem* selected_item = (*item_itor); selected_item->buildContextMenu(*menu, flags); - flags = 0x0; + flags = multi_select_flag; + } + + // This adds a check for restrictions based on the entire + // selection set - for example, any one wearable may not push you + // over the limit, but all wearables together still might. + if (getFolderViewGroupedItemModel()) + { + getFolderViewGroupedItemModel()->groupFilterContextMenu(mSelectedItems, *menu); } addNoOptions(menu); @@ -2378,6 +2384,22 @@ void LLFolderView::updateMenu() } } +void LLFolderView::saveFolderState() +{ + mSavedFolderState = std::unique_ptr(new LLSaveFolderState()); + applyFunctorRecursively(*mSavedFolderState); +} + +void LLFolderView::restoreFolderState() +{ + if (mSavedFolderState) + { + mSavedFolderState->setApply(true); + applyFunctorRecursively(*mSavedFolderState); + mSavedFolderState.reset(); + } +} + bool LLFolderView::selectFirstItem() { for (folders_t::iterator iter = mFolders.begin(); @@ -2479,34 +2501,24 @@ void LLFolderView::onRenamerLost() } } -LLInventoryFilter* LLFolderView::getFilter() -{ - return mFilter; -} - void LLFolderView::setFilterPermMask( PermissionMask filter_perm_mask ) { - mFilter->setFilterPermissions(filter_perm_mask); -} - -bool LLFolderView::getFilterWorn() const -{ - return mFilter->getFilterWorn(); + mFilter.setFilterPermissions(filter_perm_mask); } U32 LLFolderView::getFilterObjectTypes() const { - return mFilter->getFilterObjectTypes(); + return mFilter.getFilterObjectTypes(); } PermissionMask LLFolderView::getFilterPermissions() const { - return mFilter->getFilterPermissions(); + return mFilter.getFilterPermissions(); } BOOL LLFolderView::isFilterModified() { - return mFilter->isNotDefault(); + return mFilter.isNotDefault(); } void delete_selected_item(void* user_data) diff --git a/indra/newview/llfolderview.h b/indra/newview/llfolderview.h index f441e89950..a0a41f44e6 100644 --- a/indra/newview/llfolderview.h +++ b/indra/newview/llfolderview.h @@ -1,3 +1,4 @@ + /** * @file llfolderview.h * @brief Definition of the folder view collection of classes. @@ -45,15 +46,18 @@ #include "lluictrl.h" #include "v4color.h" -#include "lldarray.h" #include "stdenums.h" #include "lldepthstack.h" #include "lleditmenuhandler.h" #include "llfontgl.h" +#include "llinventoryfilter.h" #include "lltooldraganddrop.h" #include "llviewertexture.h" +#include + class LLFolderViewEventListener; +class LLFolderViewGroupedItemModel; class LLFolderViewFolder; class LLFolderViewItem; class LLInventoryModel; @@ -63,6 +67,7 @@ class LLMenuGL; class LLScrollContainer; class LLUICtrl; class LLTextBox; +class LLSaveFolderState; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLFolderView @@ -78,13 +83,20 @@ class LLFolderView : public LLFolderViewFolder, public LLEditMenuHandler LLFolderView( const std::string& name, const LLRect& rect, - const LLUUID& source_id, LLPanel *parent_view, LLFolderViewEventListener* listener ); + const LLUUID& source_id, LLPanel *parent_view, LLFolderViewEventListener* listener, LLFolderViewGroupedItemModel* group_model = NULL ); + + typedef folder_view_item_deque selected_items_t; + virtual ~LLFolderView( void ); virtual BOOL canFocusChildren() const; + virtual const LLFolderView* getRoot() const { return this; } virtual LLFolderView* getRoot() { return this; } + LLFolderViewGroupedItemModel* getFolderViewGroupedItemModel() { return mGroupedItemModel; } + const LLFolderViewGroupedItemModel* getFolderViewGroupedItemModel() const { return mGroupedItemModel; } + // FolderViews default to sort by name. This will change that, // and resort the items if necessary. void setSortOrder(U32 order); @@ -94,13 +106,15 @@ class LLFolderView : public LLFolderViewFolder, public LLEditMenuHandler void setSelectCallback(const signal_t::slot_type& cb) { mSelectSignal.connect(cb); } void setReshapeCallback(const signal_t::slot_type& cb) { mReshapeSignal.connect(cb); } void setAllowMultiSelect(BOOL allow) { mAllowMultiSelect = allow; } + void setShowEmptyMessage(bool show) { mShowEmptyMessage = show; } + /*void setShowItemLinkOverlays(bool show) { mShowItemLinkOverlays = show; } + void setAllowDropOnRoot(bool show) { mAllowDropOnRoot = show; }*/ - LLInventoryFilter* getFilter(); + LLInventoryFilter& getFilter() { return mFilter; } const std::string getFilterSubString(BOOL trim = FALSE); - bool getFilterWorn() const; U32 getFilterObjectTypes() const; PermissionMask getFilterPermissions() const; - // *NOTE: use getFilter()->getShowFolderState(); + // *NOTE: use getFilter().getShowFolderState(); //LLInventoryFilter::EFolderShow getShowFolderState(); U32 getSortOrder() const; BOOL isFilterModified(); @@ -125,15 +139,16 @@ class LLFolderView : public LLFolderViewFolder, public LLEditMenuHandler void arrangeAll() { mArrangeGeneration++; } S32 getArrangeGeneration() { return mArrangeGeneration; } - // Apply filters to control visibility of inventory items + // applies filters to control visibility of items virtual void filter( LLInventoryFilter& filter); // Get the last selected item virtual LLFolderViewItem* getCurSelectedItem( void ); + selected_items_t& getSelectedItems( void ); // Record the selected item and pass it down the hierarchy. virtual BOOL setSelection(LLFolderViewItem* selection, BOOL openitem, - BOOL take_keyboard_focus); + BOOL take_keyboard_focus = TRUE); // Used by menu callbacks void setSelectionByID(const LLUUID& obj_id, BOOL take_keyboard_focus); @@ -141,19 +156,19 @@ class LLFolderView : public LLFolderViewFolder, public LLEditMenuHandler // Called once a frame to update the selection if mSelectThisID has been set void updateSelection(); - // This method is used to toggle the selection of an item. - // Walks children and keeps track of selected objects. + // This method is used to toggle the selection of an item. Walks + // children, and keeps track of selected objects. virtual BOOL changeSelection(LLFolderViewItem* selection, BOOL selected); - virtual std::set getSelectionList() const; + virtual uuid_set_t getSelectionList() const; - // Make sure if ancestor is selected, descendents are not + // Make sure if ancestor is selected, descendants are not void sanitizeSelection(); - void clearSelection(); + virtual void clearSelection(); void addToSelectionList(LLFolderViewItem* item); void removeFromSelectionList(LLFolderViewItem* item); - BOOL startDrag(LLToolDragAndDrop::ESource source); + bool startDrag(LLToolDragAndDrop::ESource source); void setDragAndDropThisFrame() { mDragAndDropThisFrame = TRUE; } void setDraggingOverItem(LLFolderViewItem* item) { mDraggingOverItem = item; } LLFolderViewItem* getDraggingOverItem() { return mDraggingOverItem; } @@ -172,31 +187,24 @@ class LLFolderView : public LLFolderViewFolder, public LLEditMenuHandler void autoOpenItem(LLFolderViewFolder* item); void closeAutoOpenedFolders(); BOOL autoOpenTest(LLFolderViewFolder* item); + BOOL isOpen() const { return TRUE; } // root folder always open // Copy & paste - virtual void copy(); virtual BOOL canCopy() const; + virtual void copy() const override final; - virtual void cut(); virtual BOOL canCut() const; + virtual void cut(); - virtual void paste(); virtual BOOL canPaste() const; + virtual void paste(); - virtual void doDelete(); virtual BOOL canDoDelete() const; + virtual void doDelete(); // Public rename functionality - can only start the process void startRenamingSelectedItem( void ); - // These functions were used when there was only one folderview, - // and relied on that concept. This functionality is now handled - // by the listeners and the lldraganddroptool. - //LLFolderViewItem* getMovingItem() { return mMovingItem; } - //void setMovingItem( LLFolderViewItem* item ) { mMovingItem = item; } - //void dragItemIntoFolder( LLFolderViewItem* moving_item, LLFolderViewFolder* dst_folder, BOOL drop, BOOL* accept ); - //void dragFolderIntoFolder( LLFolderViewFolder* moving_folder, LLFolderViewFolder* dst_folder, BOOL drop, BOOL* accept ); - // LLView functionality ///*virtual*/ BOOL handleKey( KEY key, MASK mask, BOOL called_from_parent ); /*virtual*/ BOOL handleKeyHere( KEY key, MASK mask ); @@ -211,6 +219,7 @@ class LLFolderView : public LLFolderViewFolder, public LLEditMenuHandler EAcceptance* accept, std::string& tooltip_msg); /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + /*virtual*/ void onMouseLeave(S32 x, S32 y, MASK mask) { setShowSelectionContext(FALSE); } virtual BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); virtual void draw(); virtual void deleteAllChildren(); @@ -221,12 +230,13 @@ class LLFolderView : public LLFolderViewFolder, public LLEditMenuHandler LLRect getVisibleRect(); BOOL search(LLFolderViewItem* first_item, const std::string &search_string, BOOL backward); - void setShowSelectionContext(BOOL show) { mShowSelectionContext = show; } + void setShowSelectionContext(bool show) { mShowSelectionContext = show; } BOOL getShowSelectionContext(); - void setShowSingleSelection(BOOL show); + void setShowSingleSelection(bool show); BOOL getShowSingleSelection() { return mShowSingleSelection; } F32 getSelectionFadeElapsedTime() { return mMultiSelectionFadeTimer.getElapsedTimeF32(); } bool getUseEllipses() { return mUseEllipses; } + S32 getSelectedCount() { return (S32)mSelectedItems.size(); } void addItemID(const LLUUID& id, LLFolderViewItem* itemp); void removeItemID(const LLUUID& id); @@ -241,17 +251,23 @@ class LLFolderView : public LLFolderViewFolder, public LLEditMenuHandler void setNeedsAutoRename(BOOL val) { mNeedsAutoRename = val; } void setPinningSelectedItem(BOOL val) { mPinningSelectedItem = val; } void setAutoSelectOverride(BOOL val) { mAutoSelectOverride = val; } + bool getAutoSelectOverride() const { return mAutoSelectOverride; } BOOL getDebugFilters() { return mDebugFilters; } - LLPanel* getParentPanel() { return mParentPanel; } + LLPanel* getParentPanel() { return mParentPanel.get(); } // DEBUG only void dumpSelectionInformation(); virtual S32 notify(const LLSD& info) ; bool useLabelSuffix() { return mUseLabelSuffix; } - void updateMenu(); + virtual void updateMenu(); + void saveFolderState(); + void restoreFolderState(); + + // Note: We may eventually have to move that method up the hierarchy to LLFolderViewItem. + LLHandle getHandle() const { return getDerivedHandle(); } private: void updateMenuOptions(LLMenuGL* menu); @@ -270,40 +286,44 @@ class LLFolderView : public LLFolderViewFolder, public LLEditMenuHandler bool selectLastItem(); BOOL addNoOptions(LLMenuGL* menu) const; + +private: + std::unique_ptr mSavedFolderState; protected: LLHandle mPopupMenuHandle; - typedef std::deque selected_items_t; selected_items_t mSelectedItems; - BOOL mKeyboardSelection; - BOOL mAllowMultiSelect; - BOOL mShowEmptyMessage; - BOOL mShowFolderHierarchy; + bool mKeyboardSelection, + mAllowMultiSelect, + mShowEmptyMessage, + mShowFolderHierarchy, + mNeedsScroll, + mPinningSelectedItem, + mNeedsAutoSelect, + mAutoSelectOverride, + mNeedsAutoRename, + mUseLabelSuffix, + mDragAndDropThisFrame, + mShowSelectionContext, + mShowSingleSelection; + LLUUID mSourceID; // Renaming variables and methods LLFolderViewItem* mRenameItem; // The item currently being renamed LLLineEditor* mRenamer; - BOOL mNeedsScroll; - BOOL mPinningSelectedItem; LLRect mScrollConstraintRect; - BOOL mNeedsAutoSelect; - BOOL mAutoSelectOverride; - BOOL mNeedsAutoRename; - bool mUseLabelSuffix; - - BOOL mDebugFilters; + + bool mDebugFilters; U32 mSortOrder; U32 mSearchType; LLDepthStack mAutoOpenItems; LLFolderViewFolder* mAutoOpenCandidate; LLFrameTimer mAutoOpenTimer; LLFrameTimer mSearchTimer; - std::string mSearchString; - LLInventoryFilter* mFilter; - BOOL mShowSelectionContext; - BOOL mShowSingleSelection; + LLWString mSearchString; + LLInventoryFilter mFilter; LLFrameTimer mMultiSelectionFadeTimer; S32 mArrangeGeneration; @@ -312,12 +332,12 @@ class LLFolderView : public LLFolderViewFolder, public LLEditMenuHandler S32 mSignalSelectCallback; S32 mMinWidth; S32 mRunningHeight; - std::map mItemMap; - BOOL mDragAndDropThisFrame; - + boost::unordered_map mItemMap; LLUUID mSelectThisID; // if non null, select this item - LLPanel* mParentPanel; + LLHandle mParentPanel; + + LLFolderViewGroupedItemModel* mGroupedItemModel; /** * Is used to determine if we need to cut text In LLFolderViewItem to avoid horizontal scroll. @@ -336,11 +356,10 @@ class LLFolderView : public LLFolderViewFolder, public LLEditMenuHandler }; -bool sort_item_name(LLFolderViewItem* a, LLFolderViewItem* b); -bool sort_item_date(LLFolderViewItem* a, LLFolderViewItem* b); // Flags for buildContextMenu() const U32 SUPPRESS_OPEN_ITEM = 0x1; const U32 FIRST_SELECTED_ITEM = 0x2; +const U32 ITEM_IN_MULTI_SELECTION = 0x4; #endif // LL_LLFOLDERVIEW_H diff --git a/indra/newview/llfoldervieweventlistener.h b/indra/newview/llfoldervieweventlistener.h index 39e96424af..026dcf63f5 100644 --- a/indra/newview/llfoldervieweventlistener.h +++ b/indra/newview/llfoldervieweventlistener.h @@ -25,7 +25,6 @@ #ifndef LLFOLDERVIEWEVENTLISTENER_H #define LLFOLDERVIEWEVENTLISTENER_H -#include "lldarray.h" // *TODO: convert to std::vector #include "llfoldertype.h" #include "llfontgl.h" // just for StyleFlags enum #include "llinventorytype.h" @@ -57,7 +56,7 @@ class LLFolderViewEventListener virtual PermissionMask getPermissionMask() const = 0; virtual LLFolderType::EType getPreferredType() const = 0; virtual LLPointer getIcon() const = 0; - virtual LLPointer getOpenIcon() const { return getIcon(); } + virtual LLPointer getIconOpen() const { return getIcon(); } virtual LLFontGL::StyleFlags getLabelStyle() const = 0; virtual std::string getLabelSuffix() const = 0; virtual void openItem( void ) = 0; @@ -65,6 +64,9 @@ class LLFolderViewEventListener virtual void previewItem( void ) = 0; virtual void selectItem(void) = 0; virtual void showProperties(void) = 0; + + virtual BOOL isItemWearable() const { return FALSE; } + virtual BOOL isItemRenameable() const = 0; virtual BOOL renameItem(const std::string& new_name) = 0; virtual void nameOrDescriptionChanged(void) const { } // Singu note: Currently only used by LLWearableBridge. @@ -72,17 +74,17 @@ class LLFolderViewEventListener virtual BOOL isItemRemovable( void ) const = 0; // Can be destroyed virtual BOOL isItemInTrash( void) const { return FALSE; } // TODO: make into pure virtual. virtual BOOL removeItem() = 0; - virtual void removeBatch(LLDynamicArray& batch) = 0; + virtual void removeBatch(std::vector& batch) = 0; virtual void move( LLFolderViewEventListener* parent_listener ) = 0; virtual BOOL isItemCopyable() const = 0; virtual BOOL copyToClipboard() const = 0; - virtual void cutToClipboard() = 0; + virtual BOOL cutToClipboard() = 0; virtual BOOL isClipboardPasteable() const = 0; virtual void pasteFromClipboard(bool only_copies = false) = 0; virtual void pasteLinkFromClipboard() = 0; virtual void buildContextMenu(LLMenuGL& menu, U32 flags) = 0; virtual BOOL isUpToDate() const = 0; - virtual BOOL hasChildren() const = 0; + virtual bool hasChildren() const = 0; virtual LLInventoryType::EType getInventoryType() const = 0; virtual void performAction(LLInventoryModel* model, std::string action) = 0; virtual LLWearableType::EType getWearableType() const = 0; diff --git a/indra/newview/llfolderviewitem.cpp b/indra/newview/llfolderviewitem.cpp index fdbe6f51ac..3d11804064 100644 --- a/indra/newview/llfolderviewitem.cpp +++ b/indra/newview/llfolderviewitem.cpp @@ -75,7 +75,7 @@ LLFontGL* LLFolderViewItem::getLabelFontForStyle(U8 style) void LLFolderViewItem::initClass() { sArrowImage = LLUI::getUIImage("folder_arrow.tga"); - sBoxImage = LLUI::getUIImage("rounded_square.tga"); + sBoxImage = LLUI::getUIImage("Rounded_Square"); } //static @@ -142,6 +142,10 @@ LLFolderView* LLFolderViewItem::getRoot() return mRoot; } +const LLFolderView* LLFolderViewItem::getRoot() const +{ + return mRoot; +} // Returns true if this object is a child (or grandchild, etc.) of potential_ancestor. BOOL LLFolderViewItem::isDescendantOf( const LLFolderViewFolder* potential_ancestor ) { @@ -210,12 +214,12 @@ BOOL LLFolderViewItem::potentiallyVisible() { // we haven't been checked against min required filter // or we have and we passed - return getLastFilterGeneration() < getRoot()->getFilter()->getMinRequiredGeneration() || getFiltered(); + return getLastFilterGeneration() < getRoot()->getFilter().getFirstSuccessGeneration() || getFiltered(); } BOOL LLFolderViewItem::getFiltered() { - return mPassedFilter && mLastFilterGeneration >= getRoot()->getFilter()->getMinRequiredGeneration(); + return mPassedFilter && mLastFilterGeneration >= getRoot()->getFilter().getFirstSuccessGeneration(); } BOOL LLFolderViewItem::getFiltered(S32 filter_generation) @@ -324,7 +328,7 @@ void LLFolderViewItem::filterFromRoot( void ) { LLFolderViewItem* root = getRoot(); - root->filter(*((LLFolderView*)root)->getFilter()); + root->filter(((LLFolderView*)root)->getFilter()); } // This function is called when the folder view is dirty. It's @@ -374,16 +378,9 @@ void LLFolderViewItem::setSelectionFromRoot(LLFolderViewItem* selection, getRoot()->setSelection(selection, openitem, take_keyboard_focus); } -// helper function to change the selection from the root. -void LLFolderViewItem::changeSelectionFromRoot(LLFolderViewItem* selection, BOOL selected) -{ - getRoot()->changeSelection(selection, selected); -} - -std::set LLFolderViewItem::getSelectionList() const +uuid_set_t LLFolderViewItem::getSelectionList() const { - std::set selection; - return selection; + return uuid_set_t(); } EInventorySortGroup LLFolderViewItem::getSortGroup() const @@ -454,6 +451,9 @@ void LLFolderViewItem::filter( LLInventoryFilter& filter) setFiltered(passed_filter, filter.getCurrentGeneration()); mStringMatchOffset = filter.getStringMatchOffset(); + // If Creator is part of the filter, don't let it get highlighted if it matches + if (mSearchType & 4 && mStringMatchOffset >= mSearchable.length()-mSearchableLabelCreator.length()) + mStringMatchOffset = std::string::npos; filter.decrementFilterCount(); if (getRoot()->getDebugFilters()) @@ -584,7 +584,8 @@ void LLFolderViewItem::buildContextMenu(LLMenuGL& menu, U32 flags) void LLFolderViewItem::openItem( void ) { - if( mListener ) + if (!mListener) return; + //if (mAllowWear || mListener->isItemWearable()) // Singu Note: This will do nothing if can't do anything, so just call it { mListener->openItem(); } @@ -675,7 +676,7 @@ BOOL LLFolderViewItem::handleRightMouseDown( S32 x, S32 y, MASK mask ) { if(!mIsSelected) { - setSelectionFromRoot(this, FALSE); + getRoot()->setSelection(this, FALSE); } make_ui_sound("UISndClick"); return TRUE; @@ -696,7 +697,7 @@ BOOL LLFolderViewItem::handleMouseDown( S32 x, S32 y, MASK mask ) { if(mask & MASK_CONTROL) { - changeSelectionFromRoot(this, !mIsSelected); + getRoot()->changeSelection(this, !mIsSelected); } else if (mask & MASK_SHIFT) { @@ -704,12 +705,14 @@ BOOL LLFolderViewItem::handleMouseDown( S32 x, S32 y, MASK mask ) } else { - setSelectionFromRoot(this, FALSE); + getRoot()->setSelection(this, FALSE); } make_ui_sound("UISndClick"); } else { + // If selected, we reserve the decision of deselecting/reselecting to the mouse up moment. + // This is necessary so we maintain selection consistent when starting a drag. mSelectPending = TRUE; } @@ -765,7 +768,7 @@ BOOL LLFolderViewItem::handleHover( S32 x, S32 y, MASK mask ) // item. gFocusMgr.setKeyboardFocus(NULL); - return LLToolDragAndDrop::getInstance()->handleHover( x, y, mask ); + return LLToolDragAndDrop::getInstance()->handleHover( screen_x, screen_y, mask ); } } } @@ -778,6 +781,7 @@ BOOL LLFolderViewItem::handleHover( S32 x, S32 y, MASK mask ) { gViewerWindow->setCursor(UI_CURSOR_NOLOCKED); } + return TRUE; } else @@ -818,7 +822,7 @@ BOOL LLFolderViewItem::handleMouseUp( S32 x, S32 y, MASK mask ) //...then select if(mask & MASK_CONTROL) { - changeSelectionFromRoot(this, !mIsSelected); + getRoot()->changeSelection(this, !mIsSelected); } else if (mask & MASK_SHIFT) { @@ -826,7 +830,7 @@ BOOL LLFolderViewItem::handleMouseUp( S32 x, S32 y, MASK mask ) } else { - setSelectionFromRoot(this, FALSE); + getRoot()->setSelection(this, FALSE); } } @@ -834,7 +838,10 @@ BOOL LLFolderViewItem::handleMouseUp( S32 x, S32 y, MASK mask ) if( hasMouseCapture() ) { - getRoot()->setShowSelectionContext(FALSE); + if (getRoot()) + { + getRoot()->setShowSelectionContext(FALSE); + } gFocusMgr.setMouseCapture( NULL ); } return TRUE; @@ -871,7 +878,7 @@ BOOL LLFolderViewItem::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, } if (handled) { - lldebugst(LLERR_USER_INPUT) << "dragAndDrop handled by LLFolderViewItem" << llendl; + LL_DEBUGS("UserInput") << "dragAndDrop handled by LLFolderViewItem" << LL_ENDL; } return handled; @@ -892,8 +899,12 @@ void LLFolderViewItem::draw() const S32 FOCUS_LEFT = 1; const LLFontGL* font = getLabelFontForStyle(mLabelStyle); - const BOOL in_inventory = getListener() && gInventory.isObjectDescendentOf(getListener()->getUUID(), gInventory.getRootFolderID()); - const BOOL in_library = getListener() && gInventory.isObjectDescendentOf(getListener()->getUUID(), gInventory.getLibraryRootFolderID()); + const LLUUID* id = getListener() ? &getListener()->getUUID() : nullptr; + const BOOL in_inventory = id && gInventory.isObjectDescendentOf(*id, gInventory.getRootFolderID()); + const BOOL in_library = id && !in_inventory && gInventory.isObjectDescendentOf(*id, gInventory.getLibraryRootFolderID()); + + // Don't draw filtered top level marketplace folders + if (in_inventory && !getFiltered() && depth_nesting_in_marketplace(*id) == 1) return; //--------------------------------------------------------------------------------// // Draw open folder arrow @@ -1029,7 +1040,7 @@ void LLFolderViewItem::draw() { color.mV[VALPHA] *= 0.5f; } - LLColor4 filter_color = mLastFilterGeneration >= getRoot()->getFilter()->getCurrentGeneration() ? + LLColor4 filter_color = mLastFilterGeneration >= getRoot()->getFilter().getCurrentGeneration() ? LLColor4(0.5f, 0.8f, 0.5f, 1.f) : LLColor4(0.8f, 0.5f, 0.5f, 1.f); LLFontGL::getFontMonospace()->renderUTF8(mStatusText, 0, text_left, y, filter_color, @@ -1062,7 +1073,7 @@ void LLFolderViewItem::draw() && root_is_loading && mShowLoadStatus)) { - std::string load_string = " ( " + LLTrans::getString("LoadingData") + " ) "; + static std::string const load_string = " ( " + LLTrans::getString("LoadingData") + " ) "; font->renderUTF8(load_string, 0, right_x, y, sSearchStatusColor, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, &right_x, FALSE); @@ -1088,7 +1099,7 @@ void LLFolderViewItem::draw() if (filter_string_length > 0 && (mRoot->getSearchType() & 1)) { std::string combined_string = mLabel + mLabelSuffix; - S32 left = llround(text_left) + font->getWidth(combined_string, 0, mStringMatchOffset) - 1; + S32 left = ll_round(text_left) + font->getWidth(combined_string, 0, mStringMatchOffset) - 1; S32 right = left + font->getWidth(combined_string, mStringMatchOffset, filter_string_length) + 2; S32 bottom = llfloor(getRect().getHeight() - font->getLineHeight() - 3 - TOP_PAD); S32 top = getRect().getHeight() - TOP_PAD; @@ -1121,7 +1132,7 @@ LLFolderViewFolder::LLFolderViewFolder( const std::string& name, LLUIImagePtr ic LLUIImagePtr icon_open, LLUIImagePtr icon_link, LLFolderView* root, - LLFolderViewEventListener* listener ): + LLFolderViewEventListener* listener): LLFolderViewItem( name, icon, icon_open, icon_link, 0, root, listener ), // 0 = no create time mIsOpen(FALSE), mExpanderHighlighted(FALSE), @@ -1155,7 +1166,7 @@ void LLFolderViewFolder::setFilteredFolder(bool filtered, S32 filter_generation) bool LLFolderViewFolder::getFilteredFolder(S32 filter_generation) { - return mPassedFolderFilter && mLastFilterGeneration >= getRoot()->getFilter()->getMinRequiredGeneration(); + return mPassedFolderFilter && mLastFilterGeneration >= getRoot()->getFilter().getFirstSuccessGeneration(); } // addToFolder() returns TRUE if it succeeds. FALSE otherwise @@ -1182,7 +1193,7 @@ S32 LLFolderViewFolder::arrange( S32* width, S32* height, S32 filter_generation) mNeedsSort = false; } - mHasVisibleChildren = hasFilteredDescendants(filter_generation); + bool filtered = !getFilteredFolder(filter_generation); // calculate height as a single item (without any children), and reshapes rectangle to match LLFolderViewItem::arrange( width, height, filter_generation ); @@ -1195,12 +1206,53 @@ S32 LLFolderViewFolder::arrange( S32* width, S32* height, S32 filter_generation) F32 running_height = (F32)*height; F32 target_height = (F32)*height; + bool marketplace_top = mListener && depth_nesting_in_marketplace(mListener->getUUID()) == 1; + // are my children visible? if (needsArrange()) { // set last arrange generation first, in case children are animating // and need to be arranged again mLastArrangeGeneration = getRoot()->getArrangeGeneration(); + + mHasVisibleChildren = !filtered && hasFilteredDescendants(filter_generation); + if (mHasVisibleChildren) + { + // We have to verify that there's at least one child that's not filtered out + bool found = false; + // Try the items first + for (items_t::iterator iit = mItems.begin(); iit != mItems.end(); ++iit) + { + LLFolderViewItem* itemp = (*iit); + found = itemp->getFiltered(filter_generation); + if (found) + break; + } + if (!found) + { + // If no item found, try the folders + for (folders_t::iterator fit = mFolders.begin(); fit != mFolders.end(); ++fit) + { + LLFolderViewFolder* folderp = (*fit); + found = folderp->getListener() + && (folderp->getFiltered(filter_generation) + || (folderp->getFilteredFolder(filter_generation) + && folderp->hasFilteredDescendants(filter_generation))); + if (found) + break; + } + } + + mHasVisibleChildren = found; + } + + // Hide marketplaces top level folders that don't match the filter for this view + if (marketplace_top) + { + setVisible(!filtered); + if (filtered) mCurHeight = target_height = 0; + } + if (mIsOpen) { // Add sizes of children @@ -1225,7 +1277,7 @@ S32 LLFolderViewFolder::arrange( S32* width, S32* height, S32 filter_generation) { S32 child_width = *width; S32 child_height = 0; - S32 child_top = parent_item_height - llround(running_height); + S32 child_top = parent_item_height - ll_round(running_height); target_height += folderp->arrange( &child_width, &child_height, filter_generation ); @@ -1251,7 +1303,7 @@ S32 LLFolderViewFolder::arrange( S32* width, S32* height, S32 filter_generation) { S32 child_width = *width; S32 child_height = 0; - S32 child_top = parent_item_height - llround(running_height); + S32 child_top = parent_item_height - ll_round(running_height); target_height += itemp->arrange( &child_width, &child_height, filter_generation ); // don't change width, as this item is as wide as its parent folder by construction @@ -1275,9 +1327,9 @@ S32 LLFolderViewFolder::arrange( S32* width, S32* height, S32 filter_generation) } // animate current height towards target height - if (llabs(mCurHeight - mTargetHeight) > 1.f) + if (!(marketplace_top && filtered) && llabs(mCurHeight - mTargetHeight) > 1.f) { - mCurHeight = lerp(mCurHeight, mTargetHeight, LLCriticalDamp::getInterpolant(mIsOpen ? FOLDER_OPEN_TIME_CONSTANT : FOLDER_CLOSE_TIME_CONSTANT)); + mCurHeight = lerp(mCurHeight, mTargetHeight, LLSmoothInterpolation::getInterpolant(mIsOpen ? FOLDER_OPEN_TIME_CONSTANT : FOLDER_CLOSE_TIME_CONSTANT)); requestArrange(); @@ -1288,7 +1340,7 @@ S32 LLFolderViewFolder::arrange( S32* width, S32* height, S32 filter_generation) folders_t::iterator fit = iter++; // number of pixels that bottom of folder label is from top of parent folder if (getRect().getHeight() - (*fit)->getRect().mTop + (*fit)->getItemHeight() - > llround(mCurHeight) + MAX_FOLDER_ITEM_OVERLAP) + > ll_round(mCurHeight) + MAX_FOLDER_ITEM_OVERLAP) { // hide if beyond current folder height (*fit)->setVisible(FALSE); @@ -1301,7 +1353,7 @@ S32 LLFolderViewFolder::arrange( S32* width, S32* height, S32 filter_generation) items_t::iterator iit = iter++; // number of pixels that bottom of item label is from top of parent folder if (getRect().getHeight() - (*iit)->getRect().mBottom - > llround(mCurHeight) + MAX_FOLDER_ITEM_OVERLAP) + > ll_round(mCurHeight) + MAX_FOLDER_ITEM_OVERLAP) { (*iit)->setVisible(FALSE); } @@ -1313,12 +1365,12 @@ S32 LLFolderViewFolder::arrange( S32* width, S32* height, S32 filter_generation) } // don't change width as this item is already as wide as its parent folder - reshape(getRect().getWidth(),llround(mCurHeight)); + reshape(getRect().getWidth(),ll_round(mCurHeight)); // pass current height value back to parent - *height = llround(mCurHeight); + *height = ll_round(mCurHeight); - return llround(mTargetHeight); + return ll_round(mTargetHeight); } BOOL LLFolderViewFolder::needsArrange() @@ -1352,7 +1404,7 @@ void LLFolderViewFolder::filter( LLInventoryFilter& filter) // if failed to pass filter newer than must_pass_generation // you will automatically fail this time, so we only // check against items that have passed the filter - S32 must_pass_generation = filter.getMustPassGeneration(); + S32 must_pass_generation = filter.getFirstRequiredGeneration(); bool autoopen_folders = (filter.hasFilterString()); @@ -1405,7 +1457,7 @@ void LLFolderViewFolder::filter( LLInventoryFilter& filter) // when applying a filter, matching folders get their contents downloaded first if (filter.isNotDefault() - && getFiltered(filter.getMinRequiredGeneration()) + && getFiltered(filter.getFirstSuccessGeneration()) && (mListener && !gInventory.isCategoryComplete(mListener->getUUID()))) { @@ -1430,7 +1482,7 @@ void LLFolderViewFolder::filter( LLInventoryFilter& filter) if (folder->getCompletedFilterGeneration() >= filter_generation) { // track latest generation to pass any child items - if (folder->getFiltered() || folder->hasFilteredDescendants(filter.getMinRequiredGeneration())) + if (folder->getFiltered() || folder->hasFilteredDescendants(filter.getFirstSuccessGeneration())) { mMostFilteredDescendantGeneration = filter_generation; requestArrange(); @@ -1484,7 +1536,7 @@ void LLFolderViewFolder::filter( LLInventoryFilter& filter) item->filter( filter ); - if (item->getFiltered(filter.getMinRequiredGeneration())) + if (item->getFiltered(filter.getFirstSuccessGeneration())) { mMostFilteredDescendantGeneration = filter_generation; requestArrange(); @@ -1544,12 +1596,14 @@ void LLFolderViewFolder::dirtyFilter() { // we're a folder, so invalidate our completed generation setCompletedFilterGeneration(-1, FALSE); + for (auto folder : mFolders) // Dirty our children's filters too, so they get updated. + folder->dirtyFilter(); LLFolderViewItem::dirtyFilter(); } BOOL LLFolderViewFolder::getFiltered() { - return getFilteredFolder(getRoot()->getFilter()->getMinRequiredGeneration()) + return getFilteredFolder(getRoot()->getFilter().getFirstSuccessGeneration()) && LLFolderViewItem::getFiltered(); } @@ -1566,7 +1620,7 @@ BOOL LLFolderViewFolder::hasFilteredDescendants(S32 filter_generation) BOOL LLFolderViewFolder::hasFilteredDescendants() { - return mMostFilteredDescendantGeneration >= getRoot()->getFilter()->getCurrentGeneration(); + return mMostFilteredDescendantGeneration >= getRoot()->getFilter().getCurrentGeneration(); } // Passes selection information on to children and record selection @@ -1767,7 +1821,7 @@ void LLFolderViewFolder::gatherChildRangeExclusive(LLFolderViewItem* start, LLFo { return; } - if (selecting) + if (selecting && (*it)->getVisible()) { items.push_back(*it); } @@ -1786,7 +1840,7 @@ void LLFolderViewFolder::gatherChildRangeExclusive(LLFolderViewItem* start, LLFo return; } - if (selecting) + if (selecting && (*it)->getVisible()) { items.push_back(*it); } @@ -1808,7 +1862,7 @@ void LLFolderViewFolder::gatherChildRangeExclusive(LLFolderViewItem* start, LLFo return; } - if (selecting) + if (selecting && (*it)->getVisible()) { items.push_back(*it); } @@ -1827,7 +1881,7 @@ void LLFolderViewFolder::gatherChildRangeExclusive(LLFolderViewItem* start, LLFo return; } - if (selecting) + if (selecting && (*it)->getVisible()) { items.push_back(*it); } @@ -1935,6 +1989,7 @@ void LLFolderViewFolder::destroyView() while (!mFolders.empty()) { LLFolderViewFolder *folderp = mFolders.back(); + mFolders.pop_back(); folderp->destroyView(); // removes entry from mFolders } @@ -2395,7 +2450,7 @@ BOOL LLFolderViewFolder::handleDragAndDrop(S32 x, S32 y, MASK mask, { handleDragAndDropToThisFolder(mask, drop, cargo_type, cargo_data, accept, tooltip_msg); - lldebugst(LLERR_USER_INPUT) << "dragAndDrop handled by LLFolderViewFolder" << llendl; + LL_DEBUGS("UserInput") << "dragAndDrop handled by LLFolderViewFolder" << LL_ENDL; } return TRUE; @@ -2408,9 +2463,16 @@ BOOL LLFolderViewFolder::handleDragAndDropToThisFolder(MASK mask, EAcceptance* accept, std::string& tooltip_msg) { + if (!mAllowDrop) + { + *accept = ACCEPT_NO; + tooltip_msg = LLTrans::getString("TooltipOutboxCannotDropOnRoot"); + return TRUE; + } + BOOL accepted = mListener && mListener->dragOrDrop(mask, drop, cargo_type, cargo_data); - - if (accepted) + + if (accepted) { mDragAndDropTarget = TRUE; *accept = ACCEPT_YES_MULTI; @@ -2518,11 +2580,11 @@ void LLFolderViewFolder::draw() } else if (mIsOpen) { - mControlLabelRotation = lerp(mControlLabelRotation, -90.f, LLCriticalDamp::getInterpolant(0.04f)); + mControlLabelRotation = lerp(mControlLabelRotation, -90.f, LLSmoothInterpolation::getInterpolant(0.04f)); } else { - mControlLabelRotation = lerp(mControlLabelRotation, 0.f, LLCriticalDamp::getInterpolant(0.025f)); + mControlLabelRotation = lerp(mControlLabelRotation, 0.f, LLSmoothInterpolation::getInterpolant(0.025f)); } bool possibly_has_children = false; @@ -2569,9 +2631,9 @@ BOOL LLFolderViewFolder::potentiallyVisible() // folder should be visible by it's own filter status return LLFolderViewItem::potentiallyVisible() // or one or more of its descendants have passed the minimum filter requirement - || hasFilteredDescendants(getRoot()->getFilter()->getMinRequiredGeneration()) + || hasFilteredDescendants(getRoot()->getFilter().getFirstSuccessGeneration()) // or not all of its descendants have been checked against minimum filter requirement - || getCompletedFilterGeneration() < getRoot()->getFilter()->getMinRequiredGeneration(); + || getCompletedFilterGeneration() < getRoot()->getFilter().getFirstSuccessGeneration(); } // this does prefix traversal, as folders are listed above their contents @@ -2794,6 +2856,7 @@ bool LLInventorySort::updateSort(U32 order) mByDate = (order & LLInventoryFilter::SO_DATE); mSystemToTop = (order & LLInventoryFilter::SO_SYSTEM_FOLDERS_TO_TOP); mFoldersByName = (order & LLInventoryFilter::SO_FOLDERS_BY_NAME); + mFoldersByWeight = (mSortOrder & LLInventoryFilter::SO_FOLDERS_BY_WEIGHT); return true; } return false; @@ -2801,39 +2864,9 @@ bool LLInventorySort::updateSort(U32 order) bool LLInventorySort::operator()(const LLFolderViewItem* const& a, const LLFolderViewItem* const& b) { - /* TO-DO - // ignore sort order for landmarks in the Favorites folder. - // they should be always sorted as in Favorites bar. See EXT-719 - if (a->getSortGroup() == SG_ITEM - && b->getSortGroup() == SG_ITEM - && a->getListener()->getInventoryType() == LLInventoryType::IT_LANDMARK - && b->getListener()->getInventoryType() == LLInventoryType::IT_LANDMARK) - { - - static const LLUUID& favorites_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE); - - LLUUID a_uuid = a->getParentFolder()->getListener()->getUUID(); - LLUUID b_uuid = b->getParentFolder()->getListener()->getUUID(); - - if ((a_uuid == favorites_folder_id && b_uuid == favorites_folder_id)) - { - // *TODO: mantipov: probably it is better to add an appropriate method to LLFolderViewItem - // or to LLInvFVBridge - LLViewerInventoryItem* aitem = (static_cast(a->getListener()))->getItem(); - LLViewerInventoryItem* bitem = (static_cast(b->getListener()))->getItem(); - if (!aitem || !bitem) - return false; - S32 a_sort = aitem->getSortField(); - S32 b_sort = bitem->getSortField(); - return a_sort < b_sort; - } - }*/ - // We sort by name if we aren't sorting by date // OR if these are folders and we are sorting folders by name. - bool by_name = (!mByDate - || (mFoldersByName - && (a->getSortGroup() != SG_ITEM))); + bool by_name = ((!mByDate || (mFoldersByName && (a->getSortGroup() != SG_ITEM))) && !mFoldersByWeight); if (a->getSortGroup() != b->getSortGroup()) { @@ -2865,6 +2898,31 @@ bool LLInventorySort::operator()(const LLFolderViewItem* const& a, const LLFolde return (compare < 0); } } + else if (mFoldersByWeight) + { + S32 weight_a = compute_stock_count(a->getListener()->getUUID()); + S32 weight_b = compute_stock_count(b->getListener()->getUUID()); + if (weight_a == weight_b) + { + // Equal weight -> use alphabetical order + return (LLStringUtil::compareDict(a->getListener()->getDisplayName(), b->getListener()->getDisplayName()) < 0); + } + else if (weight_a == COMPUTE_STOCK_INFINITE) + { + // No stock -> move a at the end of the list + return false; + } + else if (weight_b == COMPUTE_STOCK_INFINITE) + { + // No stock -> move b at the end of the list + return true; + } + else + { + // Lighter is first (sorted in increasing order of weight) + return (weight_a < weight_b); + } + } else { // BUG: This is very very slow. The getCreationDate() is log n in number diff --git a/indra/newview/llfolderviewitem.h b/indra/newview/llfolderviewitem.h index 8d43626837..9bb163c804 100644 --- a/indra/newview/llfolderviewitem.h +++ b/indra/newview/llfolderviewitem.h @@ -27,10 +27,11 @@ #define LLFOLDERVIEWITEM_H #include "llview.h" -#include "lldarray.h" // *TODO: Eliminate, forward declare #include "lluiimage.h" #include "lluictrl.h" +#include + class LLFontGL; class LLFolderView; class LLFolderViewEventListener; @@ -62,7 +63,8 @@ class LLInventorySort : mSortOrder(0), mByDate(false), mSystemToTop(false), - mFoldersByName(false) { } + mFoldersByName(false), + mFoldersByWeight(false) { } // Returns true if order has changed bool updateSort(U32 order); @@ -75,6 +77,7 @@ class LLInventorySort bool mByDate; bool mSystemToTop; bool mFoldersByName; + bool mFoldersByWeight; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -140,12 +143,11 @@ class LLFolderViewItem : public LLUICtrl BOOL mIsLoading; LLTimer mTimeSinceRequestStart; bool mShowLoadStatus; + bool mAllowDrop; + bool mAllowWear; std::string mSearchable; U32 mSearchType; - - // helper function to change the selection from the root. - void changeSelectionFromRoot(LLFolderViewItem* selection, BOOL selected); //Sets extra search criteria 'labels' to be compared against by filter. void updateExtraSearchCriteria(); @@ -218,7 +220,7 @@ class LLFolderViewItem : public LLUICtrl virtual void selectItem(); // gets multiple-element selection - virtual std::set getSelectionList() const; + virtual uuid_set_t getSelectionList() const; // Returns true is this object and all of its children can be removed (deleted by user) virtual BOOL isRemovable(); @@ -241,13 +243,16 @@ class LLFolderViewItem : public LLUICtrl void setShowLoadStatus(bool status) { mShowLoadStatus = status; } + void setAllowDrop(bool allow) { mAllowDrop = allow; } + void setAllowWear(bool allow) { mAllowWear = allow; } + // Call through to the viewed object and return true if it can be // removed. Returns true if it's removed. //virtual BOOL removeRecursively(BOOL single_item); BOOL remove(); // Build an appropriate context menu for the item. Flags unused. - void buildContextMenu(LLMenuGL& menu, U32 flags); + void buildContextMenu(class LLMenuGL& menu, U32 flags); // This method returns the actual name of the thing being // viewed. This method will ask the viewed object itself. @@ -284,12 +289,12 @@ class LLFolderViewItem : public LLUICtrl virtual void openItem( void ); virtual void preview(void); - // Show children (unfortunate that this is called "open") + // Show children virtual void setOpen(BOOL open = TRUE) {}; - virtual BOOL isOpen() const { return FALSE; } virtual LLFolderView* getRoot(); + virtual const LLFolderView* getRoot() const; BOOL isDescendantOf( const LLFolderViewFolder* potential_ancestor ); S32 getIndentation() { return mIndentation; } @@ -356,7 +361,7 @@ class LLFolderViewFolder : public LLFolderViewItem LLUIImagePtr icon_open, LLUIImagePtr icon_link, LLFolderView* root, - LLFolderViewEventListener* listener ); + LLFolderViewEventListener* listener); friend class LLBuildNewViewsScheduler; friend class LLPanelObjectInventory; @@ -533,12 +538,14 @@ class LLFolderViewFolder : public LLFolderViewItem virtual BOOL handleRightMouseDown( S32 x, S32 y, MASK mask ); virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask ); virtual BOOL handleDoubleClick( S32 x, S32 y, MASK mask ); - virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, + BOOL drop, EDragAndDropType cargo_type, void* cargo_data, EAcceptance* accept, std::string& tooltip_msg); - BOOL handleDragAndDropToThisFolder(MASK mask, BOOL drop, + BOOL handleDragAndDropToThisFolder(MASK mask, + BOOL drop, EDragAndDropType cargo_type, void* cargo_data, EAcceptance* accept, @@ -555,6 +562,7 @@ class LLFolderViewFolder : public LLFolderViewItem items_t::const_iterator getItemsBegin() const { return mItems.begin(); } items_t::const_iterator getItemsEnd() const { return mItems.end(); } items_t::size_type getItemsCount() const { return mItems.size(); } + LLFolderViewFolder* getCommonAncestor(LLFolderViewItem* item_a, LLFolderViewItem* item_b, bool& reverse); void gatherChildRangeExclusive(LLFolderViewItem* start, LLFolderViewItem* end, bool reverse, std::vector& items); }; @@ -573,4 +581,12 @@ class LLFolderViewListenerFunctor virtual void operator()(LLFolderViewEventListener* listener) = 0; }; +typedef std::deque folder_view_item_deque; + +class LLFolderViewGroupedItemModel : public LLRefCount +{ +public: + virtual void groupFilterContextMenu(folder_view_item_deque& selected_items, LLMenuGL& menu) = 0; +}; + #endif // LLFOLDERVIEWITEM_H diff --git a/indra/newview/llfollowcam.cpp b/indra/newview/llfollowcam.cpp index b9b4fbe14b..e30eb176c4 100644 --- a/indra/newview/llfollowcam.cpp +++ b/indra/newview/llfollowcam.cpp @@ -334,11 +334,11 @@ void LLFollowCam::update() F32 force = focusOffsetDistance - focusThresholdNormalizedByDistance; */ - F32 focusLagLerp = LLCriticalDamp::getInterpolant( mFocusLag ); + F32 focusLagLerp = LLSmoothInterpolation::getInterpolant( mFocusLag ); focus_pt_agent = lerp( focus_pt_agent, whereFocusWantsToBe, focusLagLerp ); mSimulatedFocusGlobal = gAgent.getPosGlobalFromAgent(focus_pt_agent); } - mRelativeFocus = lerp(mRelativeFocus, (focus_pt_agent - mSubjectPosition) * ~mSubjectRotation, LLCriticalDamp::getInterpolant(0.05f)); + mRelativeFocus = lerp(mRelativeFocus, (focus_pt_agent - mSubjectPosition) * ~mSubjectRotation, LLSmoothInterpolation::getInterpolant(0.05f)); }// if focus is not locked --------------------------------------------- @@ -421,7 +421,7 @@ void LLFollowCam::update() //------------------------------------------------------------------------------------------------- if ( distanceFromPositionToIdealPosition > mPositionThreshold ) { - F32 positionPullLerp = LLCriticalDamp::getInterpolant( mPositionLag ); + F32 positionPullLerp = LLSmoothInterpolation::getInterpolant( mPositionLag ); simulated_pos_agent = lerp( simulated_pos_agent, whereCameraPositionWantsToBe, positionPullLerp ); } @@ -441,7 +441,7 @@ void LLFollowCam::update() updateBehindnessConstraint(gAgent.getPosAgentFromGlobal(mSimulatedFocusGlobal), simulated_pos_agent); mSimulatedPositionGlobal = gAgent.getPosGlobalFromAgent(simulated_pos_agent); - mRelativePos = lerp(mRelativePos, (simulated_pos_agent - mSubjectPosition) * ~mSubjectRotation, LLCriticalDamp::getInterpolant(0.05f)); + mRelativePos = lerp(mRelativePos, (simulated_pos_agent - mSubjectPosition) * ~mSubjectRotation, LLSmoothInterpolation::getInterpolant(0.05f)); } // if position is not locked ----------------------------------------------------------- @@ -496,7 +496,7 @@ BOOL LLFollowCam::updateBehindnessConstraint(LLVector3 focus, LLVector3& cam_pos if ( cameraOffsetAngle > mBehindnessMaxAngle ) { - F32 fraction = ((cameraOffsetAngle - mBehindnessMaxAngle) / cameraOffsetAngle) * LLCriticalDamp::getInterpolant(mBehindnessLag); + F32 fraction = ((cameraOffsetAngle - mBehindnessMaxAngle) / cameraOffsetAngle) * LLSmoothInterpolation::getInterpolant(mBehindnessLag); cam_position = focus + horizontalSubjectBack * (slerp(fraction, camera_offset_rotation, LLQuaternion::DEFAULT)); cam_position.mV[VZ] = cameraZ; // clamp z value back to what it was before we started messing with it constraint_active = TRUE; @@ -883,12 +883,12 @@ bool LLFollowCamMgr::isScriptedCameraSource(const LLUUID& source) void LLFollowCamMgr::dump() { S32 param_count = 0; - llinfos << "Scripted camera active stack" << llendl; + LL_INFOS() << "Scripted camera active stack" << LL_ENDL; for (param_stack_t::iterator param_it = sParamStack.begin(); param_it != sParamStack.end(); ++param_it) { - llinfos << param_count++ << + LL_INFOS() << param_count++ << " rot_limit: " << (*param_it)->getBehindnessAngle() << " rot_lag: " << (*param_it)->getBehindnessLag() << " distance: " << (*param_it)->getDistance() << @@ -901,7 +901,7 @@ void LLFollowCamMgr::dump() " pos: " << (*param_it)->getPosition() << " pos_lag: " << (*param_it)->getPositionLag() << " pos_lock: " << ((*param_it)->getPositionLocked() ? "Y" : "N") << - " pos_thresh: " << (*param_it)->getPositionThreshold() << llendl; + " pos_thresh: " << (*param_it)->getPositionThreshold() << LL_ENDL; } } diff --git a/indra/newview/llframestats.cpp b/indra/newview/llframestats.cpp index be55474b0c..a87fd67a2e 100644 --- a/indra/newview/llframestats.cpp +++ b/indra/newview/llframestats.cpp @@ -96,7 +96,7 @@ LLFrameStats::LLFrameStats() LLFrameStats::~LLFrameStats() { - mFrameData.reset(); + mFrameData.clear(); } void LLFrameStats::start(const EStat stat) @@ -149,12 +149,12 @@ void LLFrameStats::addFrameData() gTerseObjectUpdates = 0; - mFrameData.put(frame_data); + mFrameData.push_back(frame_data); if (mUseTimer) { if (mTimer.getElapsedTimeF32() > mStopTime) { - llinfos << "Grabbed stats for " << mStopTime << " seconds, stopping and dumping" << llendl; + LL_INFOS() << "Grabbed stats for " << mStopTime << " seconds, stopping and dumping" << LL_ENDL; setTrackStats(FALSE); } } @@ -162,11 +162,11 @@ void LLFrameStats::addFrameData() void LLFrameStats::dump() { - if (mFrameData.count()) + if (mFrameData.size()) { F32 total_time = 0; S64 total_triangles = 0; - S32 total_frames = mFrameData.count(); + S32 total_frames = mFrameData.size(); S32 total_num_objects = 0; time_t cur_time; @@ -188,14 +188,14 @@ void LLFrameStats::dump() LLFILE *fp = LLFile::fopen(filename, "w"); /* Flawfinder: ignore */ if (!fp) { - llinfos << "Couldn't open file for dumping frame stats!" << llendl; + LL_INFOS() << "Couldn't open file for dumping frame stats!" << LL_ENDL; return; } - llinfos << "Dumping frame statistics for " << mFrameData.count() << " frames" << llendl; + LL_INFOS() << "Dumping frame statistics for " << mFrameData.size() << " frames" << LL_ENDL; fprintf(fp, "Time\tNumTriangles\t"); - S32 i; + U32 i; for (i = 0; i < NUM_STATS; i++) { fprintf(fp, "%s\t", sStatLabels[i].c_str()); @@ -203,7 +203,7 @@ void LLFrameStats::dump() fprintf(fp, "Full Updates\tTerse Updates\tTotal Vorbis\tLong Vorbis\tNum Vorbis Decodes\t"); fprintf(fp, "\n"); - for (i = 0; i < mFrameData.count(); i++) + for (i = 0; i < mFrameData.size(); i++) { total_time += mFrameData[i].mTotalDuration; total_triangles += mFrameData[i].mNumTriangles; @@ -229,7 +229,7 @@ void LLFrameStats::dump() fp = LLFile::fopen(filename, "a"); /* Flawfinder: ignore */ if (!fp) { - llinfos << "Couldn't open file for dumping frame stats!" << llendl; + LL_INFOS() << "Couldn't open file for dumping frame stats!" << LL_ENDL; return; } @@ -247,7 +247,7 @@ void LLFrameStats::dump() fprintf(fp, "\n"); fclose(fp); } - mFrameData.reset(); + mFrameData.clear(); } void LLFrameStats::setTrackStats(const BOOL track_stats) @@ -260,14 +260,14 @@ void LLFrameStats::setTrackStats(const BOOL track_stats) } else { - llinfos << "Enabling stat logging" << llendl; + LL_INFOS() << "Enabling stat logging" << LL_ENDL; } } if (track_stats) { // Reset the frame data - mFrameData.reset(); + mFrameData.clear(); } mTrackStats = track_stats; } diff --git a/indra/newview/llframestats.h b/indra/newview/llframestats.h index 1bd3e0f428..d9df00a4d8 100644 --- a/indra/newview/llframestats.h +++ b/indra/newview/llframestats.h @@ -36,7 +36,6 @@ #include "stdtypes.h" #include "llstat.h" #include "llstring.h" -#include "lldarray.h" #include "v4color.h" #include "lltimer.h" @@ -119,7 +118,7 @@ class LLFrameStats LLStat mStats[NUM_STATS]; static std::string sStatLabels[NUM_STATS]; static LLColor4 sStatColors[NUM_STATS]; - LLDynamicArray mFrameData; + std::vector mFrameData; void stop(); }; diff --git a/indra/newview/llframestatview.cpp b/indra/newview/llframestatview.cpp index 9eb295794f..a966e70033 100644 --- a/indra/newview/llframestatview.cpp +++ b/indra/newview/llframestatview.cpp @@ -133,7 +133,7 @@ void LLFrameStatView::draw() for (i = 0; i < mNumStats; i++) { - if (mStats[i]->getLastTime() >= min_last_time) + if (mStats[i]->getCurrentTime() >= min_last_time) { is_active[i] = TRUE; } @@ -373,7 +373,7 @@ void LLFrameStatView::addStat(LLStat *statp, const std::string& label, const LLC { if( mNumStats >= MAX_STATS ) { - llwarns << "LLFrameStatView::addStat - too many stats!" << llendl; + LL_WARNS() << "LLFrameStatView::addStat - too many stats!" << LL_ENDL; return; } diff --git a/indra/newview/llgesturemgr.cpp b/indra/newview/llgesturemgr.cpp index c0f37fe5ff..4c18641858 100644 --- a/indra/newview/llgesturemgr.cpp +++ b/indra/newview/llgesturemgr.cpp @@ -61,17 +61,15 @@ #include "shcommandhandler.h" #endif //shy_mod +void fake_local_chat(std::string msg); + // Longest time, in seconds, to wait for all animations to stop playing const F32 MAX_WAIT_ANIM_SECS = 30.f; -// If this gesture is a link, get the base gesture that this link points to, -// otherwise just return this id. -static const LLUUID& get_linked_uuid(const LLUUID& item_id); - // Lightweight constructor. // init() does the heavy lifting. LLGestureMgr::LLGestureMgr() -: mValid(FALSE), +: mValid(false), mPlaying(), mActive(), mLoadingCount(0) @@ -89,7 +87,7 @@ LLGestureMgr::~LLGestureMgr() LLMultiGesture* gesture = (*it).second; delete gesture; - gesture = NULL; + gesture = nullptr; } gInventory.removeObserver(this); } @@ -150,86 +148,64 @@ void LLGestureMgr::activateGesture(const LLUUID& item_id) mLoadingCount = 1; mDeactivateSimilarNames.clear(); - const BOOL inform_server = TRUE; - const BOOL deactivate_similar = FALSE; + const bool inform_server = true; + const bool deactivate_similar = false; activateGestureWithAsset(item_id, asset_id, inform_server, deactivate_similar); } void LLGestureMgr::activateGestures(LLViewerInventoryItem::item_array_t& items) { + mDeactivateSimilarNames.clear(); + // Load up the assets - S32 count = 0; - LLViewerInventoryItem::item_array_t::const_iterator it; - for (it = items.begin(); it != items.end(); ++it) - { - LLViewerInventoryItem* item = *it; + mLoadingCount = 0; - if (isGestureActive(item->getUUID())) + // Inform the database of this change + LLMessageSystem* msg = gMessageSystem; + bool start_message = true; + + for (const auto& item : items) + { + const auto& id = item->getUUID(); + if (isGestureActive(id)) { continue; } - else - { // Make gesture active and persistent through login sessions. -spatters 07-12-06 - activateGesture(item->getUUID()); - } - - count++; - } - mLoadingCount = count; - mDeactivateSimilarNames.clear(); + // Make gesture active and persistent through login sessions. -Aura 07-12-06 + activateGesture(id); - for (it = items.begin(); it != items.end(); ++it) - { - LLViewerInventoryItem* item = *it; + ++mLoadingCount; - if (isGestureActive(item->getUUID())) - { - continue; - } + const auto& asset_id = item->getAssetUUID(); // Don't inform server, we'll do that in bulk - const BOOL no_inform_server = FALSE; - const BOOL deactivate_similar = TRUE; - activateGestureWithAsset(item->getUUID(), item->getAssetUUID(), + const bool no_inform_server = false; + const bool deactivate_similar = true; + activateGestureWithAsset(id, asset_id, no_inform_server, deactivate_similar); - } - - // Inform the database of this change - LLMessageSystem* msg = gMessageSystem; - - BOOL start_message = TRUE; - - for (it = items.begin(); it != items.end(); ++it) - { - LLViewerInventoryItem* item = *it; - - if (isGestureActive(item->getUUID())) - { - continue; - } if (start_message) { msg->newMessage("ActivateGestures"); msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID()); + msg->addUUID("AgentID", gAgentID); msg->addUUID("SessionID", gAgent.getSessionID()); msg->addU32("Flags", 0x0); - start_message = FALSE; + start_message = false; } msg->nextBlock("Data"); - msg->addUUID("ItemID", item->getUUID()); - msg->addUUID("AssetID", item->getAssetUUID()); + msg->addUUID("ItemID", id); + msg->addUUID("AssetID", asset_id); msg->addU32("GestureFlags", 0x0); if (msg->getCurrentSendTotal() > MTUBYTES) { gAgent.sendReliableMessage(); - start_message = TRUE; + start_message = true; } } @@ -243,8 +219,8 @@ void LLGestureMgr::activateGestures(LLViewerInventoryItem::item_array_t& items) struct LLLoadInfo { LLUUID mItemID; - BOOL mInformServer; - BOOL mDeactivateSimilar; + bool mInformServer; + bool mDeactivateSimilar; }; // If inform_server is true, will send a message upstream to update @@ -254,32 +230,32 @@ struct LLLoadInfo */ void LLGestureMgr::activateGestureWithAsset(const LLUUID& item_id, const LLUUID& asset_id, - BOOL inform_server, - BOOL deactivate_similar) + bool inform_server, + bool deactivate_similar) { - const LLUUID& base_item_id = get_linked_uuid(item_id); + const LLUUID& base_item_id = gInventory.getLinkedItemID(item_id); if( !gAssetStorage ) { - llwarns << "LLGestureMgr::activateGestureWithAsset without valid gAssetStorage" << llendl; + LL_WARNS() << "LLGestureMgr::activateGestureWithAsset without valid gAssetStorage" << LL_ENDL; return; } // If gesture is already active, nothing to do. if (isGestureActive(base_item_id)) { - llwarns << "Tried to loadGesture twice " << base_item_id << llendl; + LL_WARNS() << "Tried to loadGesture twice " << base_item_id << LL_ENDL; return; } // if (asset_id.isNull()) // { -// llwarns << "loadGesture() - gesture has no asset" << llendl; +// LL_WARNS() << "loadGesture() - gesture has no asset" << LL_ENDL; // return; // } - // For now, put NULL into the item map. We'll build a gesture + // For now, put nullptr into the item map. We'll build a gesture // class object when the asset data arrives. - mActive[base_item_id] = NULL; + mActive[base_item_id] = nullptr; // Copy the UUID if (asset_id.notNull()) @@ -289,7 +265,7 @@ void LLGestureMgr::activateGestureWithAsset(const LLUUID& item_id, info->mInformServer = inform_server; info->mDeactivateSimilar = deactivate_similar; - const BOOL high_priority = TRUE; + const bool high_priority = true; gAssetStorage->getAssetData(asset_id, LLAssetType::AT_GESTURE, onLoadComplete, @@ -305,24 +281,24 @@ void LLGestureMgr::activateGestureWithAsset(const LLUUID& item_id, void LLGestureMgr::deactivateGesture(const LLUUID& item_id) { - const LLUUID& base_item_id = get_linked_uuid(item_id); - item_map_t::iterator it = mActive.find(base_item_id); + const LLUUID& base_item_id = gInventory.getLinkedItemID(item_id); + const auto& it = mActive.find(base_item_id); if (it == mActive.end()) { - llwarns << "deactivateGesture for inactive gesture " << base_item_id << llendl; + LL_WARNS() << "deactivateGesture for inactive gesture " << base_item_id << LL_ENDL; return; } // mActive owns this gesture pointer, so clean up memory. LLMultiGesture* gesture = (*it).second; - // Can be NULL gestures in the map + // Can be nullptr gestures in the map if (gesture) { stopGesture(gesture); delete gesture; - gesture = NULL; + gesture = nullptr; } mActive.erase(it); @@ -332,7 +308,7 @@ void LLGestureMgr::deactivateGesture(const LLUUID& item_id) LLMessageSystem* msg = gMessageSystem; msg->newMessage("DeactivateGestures"); msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID()); + msg->addUUID("AgentID", gAgentID); msg->addUUID("SessionID", gAgent.getSessionID()); msg->addU32("Flags", 0x0); @@ -348,14 +324,16 @@ void LLGestureMgr::deactivateGesture(const LLUUID& item_id) } -void LLGestureMgr::deactivateSimilarGestures(LLMultiGesture* in, const LLUUID& in_item_id) +void LLGestureMgr::deactivateSimilarGestures(const LLMultiGesture* in, const LLUUID& in_item_id) { - const LLUUID& base_in_item_id = get_linked_uuid(in_item_id); - uuid_vec_t gest_item_ids; + const LLUUID& base_in_item_id = gInventory.getLinkedItemID(in_item_id); + + // Inform database of the change + LLMessageSystem* msg = gMessageSystem; + bool start_message = true; // Deactivate all gestures that match - item_map_t::iterator it; - for (it = mActive.begin(); it != mActive.end(); ) + for (auto it = mActive.begin(), end = mActive.end(); it != end; ) { const LLUUID& item_id = (*it).first; LLMultiGesture* gest = (*it).second; @@ -370,16 +348,38 @@ void LLGestureMgr::deactivateSimilarGestures(LLMultiGesture* in, const LLUUID& i else if ((!gest->mTrigger.empty() && gest->mTrigger == in->mTrigger) || (gest->mKey != KEY_NONE && gest->mKey == in->mKey && gest->mMask == in->mMask)) { - gest_item_ids.push_back(item_id); - stopGesture(gest); delete gest; - gest = NULL; + gest = nullptr; - mActive.erase(it++); + it = mActive.erase(it); + end = mActive.end(); gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); + if (start_message) + { + msg->newMessage("DeactivateGestures"); + msg->nextBlock("AgentData"); + msg->addUUID("AgentID", gAgentID); + msg->addUUID("SessionID", gAgent.getSessionID()); + msg->addU32("Flags", 0x0); + start_message = false; + } + + msg->nextBlock("Data"); + msg->addUUID("ItemID", item_id); + msg->addU32("GestureFlags", 0x0); + + if (msg->getCurrentSendTotal() > MTUBYTES) + { + gAgent.sendReliableMessage(); + start_message = true; + } + + // Add to the list of names for the user. + if (const auto& item = gInventory.getItem(item_id)) + mDeactivateSimilarNames += item->getName() + '\n'; } else { @@ -387,91 +387,48 @@ void LLGestureMgr::deactivateSimilarGestures(LLMultiGesture* in, const LLUUID& i } } - // Inform database of the change - LLMessageSystem* msg = gMessageSystem; - BOOL start_message = TRUE; - uuid_vec_t::const_iterator vit = gest_item_ids.begin(); - while (vit != gest_item_ids.end()) - { - if (start_message) - { - msg->newMessage("DeactivateGestures"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID()); - msg->addUUID("SessionID", gAgent.getSessionID()); - msg->addU32("Flags", 0x0); - start_message = FALSE; - } - - msg->nextBlock("Data"); - msg->addUUID("ItemID", *vit); - msg->addU32("GestureFlags", 0x0); - - if (msg->getCurrentSendTotal() > MTUBYTES) - { - gAgent.sendReliableMessage(); - start_message = TRUE; - } - - ++vit; - } - if (!start_message) { gAgent.sendReliableMessage(); } - // Add to the list of names for the user. - for (vit = gest_item_ids.begin(); vit != gest_item_ids.end(); ++vit) - { - LLViewerInventoryItem* item = gInventory.getItem(*vit); - if (!item) continue; - - mDeactivateSimilarNames.append(item->getName()); - mDeactivateSimilarNames.append("\n"); - } - + // *TODO: We call notify observers in stopGesture above, should we pass a flag to only do that here? notifyObservers(); } -BOOL LLGestureMgr::isGestureActive(const LLUUID& item_id) +bool LLGestureMgr::isGestureActive(const LLUUID& item_id) const { - const LLUUID& base_item_id = get_linked_uuid(item_id); - item_map_t::iterator it = mActive.find(base_item_id); + const LLUUID& base_item_id = gInventory.getLinkedItemID(item_id); + const auto& it = mActive.find(base_item_id); return (it != mActive.end()); } -BOOL LLGestureMgr::isGesturePlaying(const LLUUID& item_id) +bool LLGestureMgr::isGesturePlaying(const LLUUID& item_id) const { - const LLUUID& base_item_id = get_linked_uuid(item_id); - item_map_t::iterator it = mActive.find(base_item_id); - if (it == mActive.end()) return FALSE; + const LLUUID& base_item_id = gInventory.getLinkedItemID(item_id); + const auto& it = mActive.find(base_item_id); + if (it == mActive.end()) return false; - LLMultiGesture* gesture = (*it).second; - if (!gesture) return FALSE; + const LLMultiGesture* gesture = (*it).second; + if (!gesture) return false; return gesture->mPlaying; } -BOOL LLGestureMgr::isGesturePlaying(LLMultiGesture* gesture) +bool LLGestureMgr::isGesturePlaying(const LLMultiGesture* gesture) const { - if(!gesture) - { - return FALSE; - } - - return gesture->mPlaying; + return gesture && gesture->mPlaying; } void LLGestureMgr::replaceGesture(const LLUUID& item_id, LLMultiGesture* new_gesture, const LLUUID& asset_id) { - const LLUUID& base_item_id = get_linked_uuid(item_id); - item_map_t::iterator it = mActive.find(base_item_id); + const LLUUID& base_item_id = gInventory.getLinkedItemID(item_id); + const auto& it = mActive.find(base_item_id); if (it == mActive.end()) { - llwarns << "replaceGesture for inactive gesture " << base_item_id << llendl; + LL_WARNS() << "replaceGesture for inactive gesture " << base_item_id << LL_ENDL; return; } @@ -483,7 +440,7 @@ void LLGestureMgr::replaceGesture(const LLUUID& item_id, LLMultiGesture* new_ges mActive[base_item_id] = new_gesture; delete old_gesture; - old_gesture = NULL; + old_gesture = nullptr; if (asset_id.notNull()) { @@ -492,10 +449,10 @@ void LLGestureMgr::replaceGesture(const LLUUID& item_id, LLMultiGesture* new_ges LLLoadInfo* info = new LLLoadInfo; info->mItemID = base_item_id; - info->mInformServer = TRUE; - info->mDeactivateSimilar = FALSE; + info->mInformServer = true; + info->mDeactivateSimilar = false; - const BOOL high_priority = TRUE; + const bool high_priority = true; gAssetStorage->getAssetData(asset_id, LLAssetType::AT_GESTURE, onLoadComplete, @@ -508,12 +465,12 @@ void LLGestureMgr::replaceGesture(const LLUUID& item_id, LLMultiGesture* new_ges void LLGestureMgr::replaceGesture(const LLUUID& item_id, const LLUUID& new_asset_id) { - const LLUUID& base_item_id = get_linked_uuid(item_id); + const LLUUID& base_item_id = gInventory.getLinkedItemID(item_id); - item_map_t::iterator it = LLGestureMgr::instance().mActive.find(base_item_id); + auto it = LLGestureMgr::instance().mActive.find(base_item_id); if (it == mActive.end()) { - llwarns << "replaceGesture for inactive gesture " << base_item_id << llendl; + LL_WARNS() << "replaceGesture for inactive gesture " << base_item_id << LL_ENDL; return; } @@ -522,7 +479,7 @@ void LLGestureMgr::replaceGesture(const LLUUID& item_id, const LLUUID& new_asset LLGestureMgr::instance().replaceGesture(base_item_id, gesture, new_asset_id); } -void LLGestureMgr::playGesture(LLMultiGesture* gesture) +void LLGestureMgr::playGesture(LLMultiGesture* gesture, bool local) { if (!gesture) return; @@ -530,7 +487,8 @@ void LLGestureMgr::playGesture(LLMultiGesture* gesture) gesture->mCurrentStep = 0; // Add to list of playing - gesture->mPlaying = TRUE; + gesture->mPlaying = true; + gesture->mLocal = local; mPlaying.push_back(gesture); // Load all needed assets to minimize the delays @@ -566,7 +524,7 @@ void LLGestureMgr::playGesture(LLMultiGesture* gesture) LLAssetType::AT_ANIMATION, onAssetLoadComplete, (void *)id, - TRUE); + true); } break; } @@ -582,8 +540,8 @@ void LLGestureMgr::playGesture(LLMultiGesture* gesture) gAssetStorage->getAssetData(sound_id, LLAssetType::AT_SOUND, onAssetLoadComplete, - NULL, - TRUE); + nullptr, + true); } break; } @@ -595,7 +553,7 @@ void LLGestureMgr::playGesture(LLMultiGesture* gesture) } default: { - llwarns << "Unknown gesture step type: " << step->getType() << llendl; + LL_WARNS() << "Unknown gesture step type: " << step->getType() << LL_ENDL; } } } @@ -608,9 +566,9 @@ void LLGestureMgr::playGesture(LLMultiGesture* gesture) // Convenience function that looks up the item_id for you. -void LLGestureMgr::playGesture(const LLUUID& item_id) +void LLGestureMgr::playGesture(const LLUUID& item_id, bool local) { - const LLUUID& base_item_id = get_linked_uuid(item_id); + const LLUUID& base_item_id = gInventory.getLinkedItemID(item_id); item_map_t::iterator it = mActive.find(base_item_id); if (it == mActive.end()) return; @@ -625,12 +583,12 @@ void LLGestureMgr::playGesture(const LLUUID& item_id) // Iterates through space delimited tokens in string, triggering any gestures found. // Generates a revised string that has the found tokens replaced by their replacement strings // and (as a minor side effect) has multiple spaces in a row replaced by single spaces. -BOOL LLGestureMgr::triggerAndReviseString(const std::string &utf8str, std::string* revised_string) +bool LLGestureMgr::triggerAndReviseString(const std::string &utf8str, std::string* revised_string) { std::string tokenized = utf8str; - BOOL found_gestures = FALSE; - BOOL first_token = TRUE; + bool found_gestures = false; + bool first_token = true; typedef boost::tokenizer > tokenizer; boost::char_separator sep(" "); @@ -640,17 +598,16 @@ BOOL LLGestureMgr::triggerAndReviseString(const std::string &utf8str, std::strin for( token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter) { const char* cur_token = token_iter->c_str(); - LLMultiGesture* gesture = NULL; + LLMultiGesture* gesture = nullptr; // Only pay attention to the first gesture in the string. if( !found_gestures ) { // collect gestures that match std::vector matching; - item_map_t::iterator it; - for (it = mActive.begin(); it != mActive.end(); ++it) + for (const auto& pair : mActive) { - gesture = (*it).second; + gesture = pair.second; // Gesture asset data might not have arrived yet if (!gesture) continue; @@ -660,7 +617,7 @@ BOOL LLGestureMgr::triggerAndReviseString(const std::string &utf8str, std::strin matching.push_back(gesture); } - gesture = NULL; + gesture = nullptr; } @@ -674,59 +631,43 @@ BOOL LLGestureMgr::triggerAndReviseString(const std::string &utf8str, std::strin playGesture(gesture); - if (!gesture->mReplaceText.empty()) + if (revised_string && !gesture->mReplaceText.empty()) { - if( !first_token ) - { - if (revised_string) - revised_string->append( " " ); - } + if (!first_token) revised_string->push_back(' '); // Don't muck with the user's capitalization if we don't have to. - if( LLStringUtil::compareInsensitive(cur_token, gesture->mReplaceText) == 0) - { - if (revised_string) - revised_string->append( cur_token ); - } - else - { - if (revised_string) - revised_string->append( gesture->mReplaceText ); - } + revised_string->append(LLStringUtil::compareInsensitive(cur_token, gesture->mReplaceText) == 0 ? + cur_token : gesture->mReplaceText); } - found_gestures = TRUE; + found_gestures = true; } } } - if(!gesture) + if (!gesture && revised_string) { // This token doesn't match a gesture. Pass it through to the output. - if( !first_token ) - { - if (revised_string) - revised_string->append( " " ); - } - if (revised_string) - revised_string->append( cur_token ); + if (!first_token) revised_string->push_back(' '); + revised_string->append(cur_token); } - first_token = FALSE; - gesture = NULL; + first_token = false; + gesture = nullptr; } return found_gestures; } -BOOL LLGestureMgr::triggerGesture(KEY key, MASK mask) +bool LLGestureMgr::triggerGesture(KEY key, MASK mask) { - std::vector matching; - item_map_t::iterator it; + if (mActive.empty()) return false; + + std::vector matching; // collect matching gestures - for (it = mActive.begin(); it != mActive.end(); ++it) + for (const auto& pair : mActive) { - LLMultiGesture* gesture = (*it).second; + LLMultiGesture* gesture = pair.second; // asset data might not have arrived yet if (!gesture) continue; @@ -739,16 +680,13 @@ BOOL LLGestureMgr::triggerGesture(KEY key, MASK mask) } // choose one and play it - if (matching.size() > 0) + const auto& count = matching.size(); + if (count > 0) { - U32 random = ll_rand(matching.size()); - - LLMultiGesture* gesture = matching[random]; - - playGesture(gesture); - return TRUE; + playGesture(matching[ll_rand(count)]); + return true; } - return FALSE; + return false; } @@ -758,53 +696,35 @@ S32 LLGestureMgr::getPlayingCount() const } -struct IsGesturePlaying : public std::unary_function -{ - bool operator()(const LLMultiGesture* gesture) const - { - return gesture->mPlaying ? true : false; - } -}; - void LLGestureMgr::update() { - S32 i; - for (i = 0; i < (S32)mPlaying.size(); ++i) - { - stepGesture(mPlaying[i]); - } - - // Clear out gestures that are done, by moving all the - // ones that are still playing to the front. - std::vector::iterator new_end; - new_end = std::partition(mPlaying.begin(), - mPlaying.end(), - IsGesturePlaying()); - - // Something finished playing - if (new_end != mPlaying.end()) + bool notify = false; + for (auto it = mPlaying.begin(), end = mPlaying.end(); it != end;) { - // Delete the completed gestures that want deletion - std::vector::iterator it; - for (it = new_end; it != mPlaying.end(); ++it) + auto& gesture = *it; + stepGesture(gesture); + if (!gesture->mPlaying) { - LLMultiGesture* gesture = *it; - + // Delete the completed gestures that want deletion if (gesture->mDoneCallback) { gesture->mDoneCallback(gesture); // callback might have deleted gesture, can't // rely on this pointer any more - gesture = NULL; + gesture = nullptr; } - } - - // And take done gestures out of the playing list - mPlaying.erase(new_end, mPlaying.end()); - notifyObservers(); + // And take done gesture out of the playing list + it = mPlaying.erase(it); + end = mPlaying.end(); + notify = true; + } + else ++it; } + + // Something finished playing + if (notify) notifyObservers(); } @@ -819,15 +739,21 @@ void LLGestureMgr::stepGesture(LLMultiGesture* gesture) // Of the ones that started playing, have any stopped? - std::set::iterator gest_it; - for (gest_it = gesture->mPlayingAnimIDs.begin(); - gest_it != gesture->mPlayingAnimIDs.end(); - ) + const auto& signaled(gAgentAvatarp->mSignaledAnimations); + const auto& signaled_end(signaled.end()); + for (auto gest_it = gesture->mPlayingAnimIDs.begin(), end = gesture->mPlayingAnimIDs.end(); gest_it != end;) { + if (gesture->mLocal) + { + // Local, erase if no longer playing (or gone) + LLMotion* motion = gAgentAvatarp->findMotion(*gest_it); + if (!motion || motion->isStopped()) + gest_it = gesture->mPlayingAnimIDs.erase(gest_it); + else ++gest_it; + } // look in signaled animations (simulator's view of what is // currently playing. - LLVOAvatar::AnimIterator play_it = gAgentAvatarp->mSignaledAnimations.find(*gest_it); - if (play_it != gAgentAvatarp->mSignaledAnimations.end()) + else if (signaled.find(*gest_it) != signaled_end) { ++gest_it; } @@ -835,23 +761,20 @@ void LLGestureMgr::stepGesture(LLMultiGesture* gesture) { // not found, so not currently playing or scheduled to play // delete from the triggered set - gesture->mPlayingAnimIDs.erase(gest_it++); + gest_it = gesture->mPlayingAnimIDs.erase(gest_it); } } // Of all the animations that we asked the sim to start for us, // pick up the ones that have actually started. - for (gest_it = gesture->mRequestedAnimIDs.begin(); - gest_it != gesture->mRequestedAnimIDs.end(); - ) + for (auto gest_it = gesture->mRequestedAnimIDs.begin(), end = gesture->mRequestedAnimIDs.end(); gest_it != end;) { - LLVOAvatar::AnimIterator play_it = gAgentAvatarp->mSignaledAnimations.find(*gest_it); - if (play_it != gAgentAvatarp->mSignaledAnimations.end()) + if (signaled.find(*gest_it) != signaled_end) { // Hooray, this animation has started playing! // Copy into playing. gesture->mPlayingAnimIDs.insert(*gest_it); - gesture->mRequestedAnimIDs.erase(gest_it++); + gest_it = gesture->mRequestedAnimIDs.erase(gest_it); } else { @@ -861,21 +784,21 @@ void LLGestureMgr::stepGesture(LLMultiGesture* gesture) } // Run the current steps - BOOL waiting = FALSE; + bool waiting = false; while (!waiting && gesture->mPlaying) { // Get the current step, if there is one. // Otherwise enter the waiting at end state. - LLGestureStep* step = NULL; + LLGestureStep* step = nullptr; if (gesture->mCurrentStep < (S32)gesture->mSteps.size()) { step = gesture->mSteps[gesture->mCurrentStep]; - llassert(step != NULL); + llassert(step != nullptr); } else { // step stays null, we're off the end - gesture->mWaitingAtEnd = TRUE; + gesture->mWaitingAtEnd = true; } @@ -890,12 +813,12 @@ void LLGestureMgr::stepGesture(LLMultiGesture* gesture) && gesture->mPlayingAnimIDs.empty())) { // all animations are done playing - gesture->mWaitingAtEnd = FALSE; - gesture->mPlaying = FALSE; + gesture->mWaitingAtEnd = false; + gesture->mPlaying = false; } else { - waiting = TRUE; + waiting = true; } continue; } @@ -910,20 +833,20 @@ void LLGestureMgr::stepGesture(LLMultiGesture* gesture) && gesture->mPlayingAnimIDs.empty())) { // all animations are done playing - gesture->mWaitingAnimations = FALSE; - gesture->mCurrentStep++; + gesture->mWaitingAnimations = false; + ++gesture->mCurrentStep; } else if (gesture->mWaitTimer.getElapsedTimeF32() > MAX_WAIT_ANIM_SECS) { // we've waited too long for an animation - llinfos << "Waited too long for animations to stop, continuing gesture." - << llendl; - gesture->mWaitingAnimations = FALSE; - gesture->mCurrentStep++; + LL_INFOS() << "Waited too long for animations to stop, continuing gesture." + << LL_ENDL; + gesture->mWaitingAnimations = false; + ++gesture->mCurrentStep; } else { - waiting = TRUE; + waiting = true; } continue; } @@ -939,13 +862,13 @@ void LLGestureMgr::stepGesture(LLMultiGesture* gesture) if (elapsed > wait_step->mWaitSeconds) { // wait is done, continue execution - gesture->mWaitingTimer = FALSE; - gesture->mCurrentStep++; + gesture->mWaitingTimer = false; + ++gesture->mCurrentStep; } else { // we're waiting, so execution is done for now - waiting = TRUE; + waiting = true; } continue; } @@ -965,55 +888,74 @@ void LLGestureMgr::runStep(LLMultiGesture* gesture, LLGestureStep* step) LLGestureStepAnimation* anim_step = (LLGestureStepAnimation*)step; if (anim_step->mAnimAssetID.isNull()) { - gesture->mCurrentStep++; + ++gesture->mCurrentStep; } if (anim_step->mFlags & ANIM_FLAG_STOP) { - gAgent.sendAnimationRequest(anim_step->mAnimAssetID, ANIM_REQUEST_STOP); - // remove it from our request set in case we just requested it - std::set::iterator set_it = gesture->mRequestedAnimIDs.find(anim_step->mAnimAssetID); - if (set_it != gesture->mRequestedAnimIDs.end()) + if (gesture->mLocal) { - gesture->mRequestedAnimIDs.erase(set_it); + gAgentAvatarp->stopMotion(anim_step->mAnimAssetID); + } + else + { + gAgent.sendAnimationRequest(anim_step->mAnimAssetID, ANIM_REQUEST_STOP); + // remove it from our request set in case we just requested it + auto set_it = gesture->mRequestedAnimIDs.find(anim_step->mAnimAssetID); + if (set_it != gesture->mRequestedAnimIDs.end()) + { + gesture->mRequestedAnimIDs.erase(set_it); + } } } else { - gAgent.sendAnimationRequest(anim_step->mAnimAssetID, ANIM_REQUEST_START); - // Indicate that we've requested this animation to play as - // part of this gesture (but it won't start playing for at - // least one round-trip to simulator). - gesture->mRequestedAnimIDs.insert(anim_step->mAnimAssetID); + if (gesture->mLocal) + { + gAgentAvatarp->startMotion(anim_step->mAnimAssetID); + // Indicate we're playing this animation now. + gesture->mPlayingAnimIDs.insert(anim_step->mAnimAssetID); + } + else + { + gAgent.sendAnimationRequest(anim_step->mAnimAssetID, ANIM_REQUEST_START); + // Indicate that we've requested this animation to play as + // part of this gesture (but it won't start playing for at + // least one round-trip to simulator). + gesture->mRequestedAnimIDs.insert(anim_step->mAnimAssetID); + } } - gesture->mCurrentStep++; + ++gesture->mCurrentStep; break; } case STEP_SOUND: { LLGestureStepSound* sound_step = (LLGestureStepSound*)step; const LLUUID& sound_id = sound_step->mSoundAssetID; - const F32 volume = 1.f; - send_sound_trigger(sound_id, volume); - gesture->mCurrentStep++; + constexpr F32 volume = 1.f; + if (gesture->mLocal) + gAudiop->triggerSound(sound_id, gAgentID, volume, LLAudioEngine::AUDIO_TYPE_UI, gAgent.getPositionGlobal()); + else + send_sound_trigger(sound_id, volume); + ++gesture->mCurrentStep; break; } case STEP_CHAT: { LLGestureStepChat* chat_step = (LLGestureStepChat*)step; - std::string chat_text = chat_step->mChatText; + const std::string& chat_text = chat_step->mChatText; // Don't animate the nodding, as this might not blend with // other playing animations. - const BOOL animate = FALSE; - if ( cmd_line_chat(chat_text, CHAT_TYPE_NORMAL)) + constexpr bool animate = false; + if (cmd_line_chat(chat_text, CHAT_TYPE_NORMAL)) { #if SHY_MOD //Command handler if(!SHCommandHandler::handleCommand(true, chat_text, gAgentID, gAgentAvatarp))//returns true if handled #endif //shy_mod - gChatBar->sendChatFromViewer(chat_text, CHAT_TYPE_NORMAL, animate); + gesture->mLocal ? fake_local_chat(chat_text) : gChatBar->sendChatFromViewer(chat_text, CHAT_TYPE_NORMAL, animate); } - gesture->mCurrentStep++; + ++gesture->mCurrentStep; break; } case STEP_WAIT: @@ -1021,19 +963,19 @@ void LLGestureMgr::runStep(LLMultiGesture* gesture, LLGestureStep* step) LLGestureStepWait* wait_step = (LLGestureStepWait*)step; if (wait_step->mFlags & WAIT_FLAG_TIME) { - gesture->mWaitingTimer = TRUE; + gesture->mWaitingTimer = true; gesture->mWaitTimer.reset(); } else if (wait_step->mFlags & WAIT_FLAG_ALL_ANIM) { - gesture->mWaitingAnimations = TRUE; + gesture->mWaitingAnimations = true; // Use the wait timer as a deadlock breaker for animation // waits. gesture->mWaitTimer.reset(); } else { - gesture->mCurrentStep++; + ++gesture->mCurrentStep; } // Don't increment instruction pointer until wait is complete. break; @@ -1054,37 +996,29 @@ void LLGestureMgr::onLoadComplete(LLVFS *vfs, { LLLoadInfo* info = (LLLoadInfo*)user_data; - LLUUID item_id = info->mItemID; - BOOL inform_server = info->mInformServer; - BOOL deactivate_similar = info->mDeactivateSimilar; + const LLUUID item_id = info->mItemID; + const bool inform_server = info->mInformServer; + const bool deactivate_similar = info->mDeactivateSimilar; delete info; - info = NULL; + info = nullptr; LLGestureMgr& self = LLGestureMgr::instance(); - self.mLoadingCount--; + --self.mLoadingCount; if (0 == status) { LLVFile file(vfs, asset_uuid, type, LLVFile::READ); S32 size = file.getSize(); - char* buffer = new char[size+1]; - if (buffer == NULL) - { - llerrs << "Memory Allocation Failed" << llendl; - return; - } - - file.read((U8*)buffer, size); /* Flawfinder: ignore */ - // ensure there's a trailing NULL so strlen will work. - buffer[size] = '\0'; + // ensure there's a trailing nullptr so strlen will work. + std::vector buffer(size+1, '\0'); + file.read((U8*)&buffer[0], size); LLMultiGesture* gesture = new LLMultiGesture(); - LLDataPackerAsciiBuffer dp(buffer, size+1); - BOOL ok = gesture->deserialize(dp); + LLDataPackerAsciiBuffer dp(&buffer[0], size+1); - if (ok) + if (gesture->deserialize(dp)) { if (deactivate_similar) { @@ -1134,8 +1068,8 @@ void LLGestureMgr::onLoadComplete(LLVFS *vfs, gAgent.sendReliableMessage(); } - callback_map_t::iterator i_cb = self.mCallbackMap.find(item_id); - + + auto i_cb = self.mCallbackMap.find(item_id); if(i_cb != self.mCallbackMap.end()) { i_cb->second(gesture); @@ -1146,16 +1080,13 @@ void LLGestureMgr::onLoadComplete(LLVFS *vfs, } else { - llwarns << "Unable to load gesture" << llendl; + LL_WARNS() << "Unable to load gesture" << LL_ENDL; self.mActive.erase(item_id); delete gesture; - gesture = NULL; + gesture = nullptr; } - - delete [] buffer; - buffer = NULL; } else { @@ -1171,7 +1102,7 @@ void LLGestureMgr::onLoadComplete(LLVFS *vfs, LLDelayedGestureError::gestureFailedToLoad( item_id ); } - llwarns << "Problem loading gesture: " << status << llendl; + LL_WARNS() << "Problem loading gesture: " << status << LL_ENDL; LLGestureMgr::instance().mActive.erase(item_id); } @@ -1207,7 +1138,7 @@ void LLGestureMgr::onAssetLoadComplete(LLVFS *vfs, } default: { - llwarns << "Unexpected asset type: " << type << llendl; + LL_WARNS() << "Unexpected asset type: " << type << LL_ENDL; // We don't want to return from this callback without // an animation or sound callback being fired @@ -1222,11 +1153,8 @@ bool LLGestureMgr::hasLoadingAssets(LLMultiGesture* gesture) { LLGestureMgr& self = LLGestureMgr::instance(); - for (std::vector::iterator steps_it = gesture->mSteps.begin(); - steps_it != gesture->mSteps.end(); - ++steps_it) + for (auto& step : gesture->mSteps) { - LLGestureStep* step = *steps_it; switch(step->getType()) { case STEP_ANIMATION: @@ -1262,7 +1190,7 @@ bool LLGestureMgr::hasLoadingAssets(LLMultiGesture* gesture) } default: { - llwarns << "Unknown gesture step type: " << step->getType() << llendl; + LL_WARNS() << "Unknown gesture step type: " << step->getType() << LL_ENDL; } } } @@ -1275,25 +1203,22 @@ void LLGestureMgr::stopGesture(LLMultiGesture* gesture) if (!gesture) return; // Stop any animations that this gesture is currently playing - std::set::const_iterator set_it; - for (set_it = gesture->mRequestedAnimIDs.begin(); set_it != gesture->mRequestedAnimIDs.end(); ++set_it) - { - const LLUUID& anim_id = *set_it; - gAgent.sendAnimationRequest(anim_id, ANIM_REQUEST_STOP); - } - for (set_it = gesture->mPlayingAnimIDs.begin(); set_it != gesture->mPlayingAnimIDs.end(); ++set_it) + for (const auto& anim_id : gesture->mRequestedAnimIDs) { - const LLUUID& anim_id = *set_it; gAgent.sendAnimationRequest(anim_id, ANIM_REQUEST_STOP); } + gesture->mRequestedAnimIDs.clear(); - std::vector::iterator it; - it = std::find(mPlaying.begin(), mPlaying.end(), gesture); - while (it != mPlaying.end()) + for (const auto& anim_id : gesture->mPlayingAnimIDs) { - mPlaying.erase(it); - it = std::find(mPlaying.begin(), mPlaying.end(), gesture); + if (gesture->mLocal) + gAgentAvatarp->stopMotion(anim_id, true); + else + gAgent.sendAnimationRequest(anim_id, ANIM_REQUEST_STOP); } + gesture->mPlayingAnimIDs.clear(); + + mPlaying.erase(std::remove(mPlaying.begin(), mPlaying.end(), gesture), mPlaying.end()); gesture->reset(); @@ -1303,7 +1228,7 @@ void LLGestureMgr::stopGesture(LLMultiGesture* gesture) // callback might have deleted gesture, can't // rely on this pointer any more - gesture = NULL; + gesture = nullptr; } notifyObservers(); @@ -1312,8 +1237,8 @@ void LLGestureMgr::stopGesture(LLMultiGesture* gesture) void LLGestureMgr::stopGesture(const LLUUID& item_id) { - const LLUUID& base_item_id = get_linked_uuid(item_id); - item_map_t::iterator it = mActive.find(base_item_id); + const LLUUID& base_item_id = gInventory.getLinkedItemID(item_id); + auto it = mActive.find(base_item_id); if (it == mActive.end()) return; LLMultiGesture* gesture = (*it).second; @@ -1330,9 +1255,9 @@ void LLGestureMgr::addObserver(LLGestureManagerObserver* observer) void LLGestureMgr::removeObserver(LLGestureManagerObserver* observer) { - std::vector::iterator it; - it = std::find(mObservers.begin(), mObservers.end(), observer); - if (it != mObservers.end()) + const auto& end = mObservers.end(); + auto it = std::find(mObservers.begin(), end, observer); + if (it != end) { mObservers.erase(it); } @@ -1343,68 +1268,115 @@ void LLGestureMgr::removeObserver(LLGestureManagerObserver* observer) // from the list. void LLGestureMgr::notifyObservers() { - lldebugs << "LLGestureMgr::notifyObservers" << llendl; + LL_DEBUGS() << "LLGestureMgr::notifyObservers" << LL_ENDL; - for(std::vector::iterator iter = mObservers.begin(); - iter != mObservers.end(); - ++iter) + for(auto& observer : mObservers) { - LLGestureManagerObserver* observer = (*iter); observer->changed(); } } -BOOL LLGestureMgr::matchPrefix(const std::string& in_str, std::string* out_str) +bool LLGestureMgr::matchPrefix(const std::string& in_str, std::string* out_str) const { S32 in_len = in_str.length(); - item_map_t::iterator it; - for (it = mActive.begin(); it != mActive.end(); ++it) +#ifdef MATCH_COMMON_CHARS + std::string rest_of_match; + std::string buf; +#endif + for (const auto& pair : mActive) { - LLMultiGesture* gesture = (*it).second; + const LLMultiGesture* gesture = pair.second; if (gesture) { const std::string& trigger = gesture->getTrigger(); - - if (in_len > (S32)trigger.length()) +#ifdef MATCH_COMMON_CHARS + //return whole trigger, if received text equals to it + if (!LLStringUtil::compareInsensitive(in_str, trigger)) { - // too short, bail out - continue; + *out_str = trigger; + return true; } +#else + if (in_len > (S32)trigger.length()) continue; // too short, bail out +#endif + //return common chars, if more than one trigger matches the prefix std::string trigger_trunc = trigger; LLStringUtil::truncate(trigger_trunc, in_len); if (!LLStringUtil::compareInsensitive(in_str, trigger_trunc)) { +#ifndef MATCH_COMMON_CHARS *out_str = trigger; - return TRUE; + return true; +#else + if (rest_of_match.empty()) + { + rest_of_match = trigger.substr(in_str.size()); + } + std::string cur_rest_of_match = trigger.substr(in_str.size()); + buf.clear(); + + for (U32 i = 0; i < rest_of_match.length() && i < cur_rest_of_match.length(); ++i) + { + const auto& rest(rest_of_match[i]) + if (rest==cur_rest_of_match[i]) + { + buf.push_back(rest); + } + else + { + if (i==0) + { + rest_of_match.clear(); + } + break; + } + } + if (rest_of_match.empty()) + { + return false; + } + if (!buf.empty()) + { + rest_of_match = buf; + } +#endif } } } - return FALSE; + +#ifdef MATCH_COMMON_CHARS + if (!rest_of_match.empty()) + { + *out_str = in_str+rest_of_match; + return true; + } +#endif + + return false; } -void LLGestureMgr::getItemIDs(uuid_vec_t* ids) +void LLGestureMgr::getItemIDs(uuid_vec_t* ids) const { - item_map_t::const_iterator it; - for (it = mActive.begin(); it != mActive.end(); ++it) + for (const auto& pair : mActive) { - ids->push_back(it->first); + ids->push_back(pair.first); } } void LLGestureMgr::done() { bool notify = false; - for(item_map_t::iterator it = mActive.begin(); it != mActive.end(); ++it) + for(const auto& pair : mActive) { - if(it->second && it->second->mName.empty()) + if (pair.second && pair.second->mName.empty()) { - LLViewerInventoryItem* item = gInventory.getItem(it->first); + LLViewerInventoryItem* item = gInventory.getItem(pair.first); if(item) { - it->second->mName = item->getName(); + pair.second->mName = item->getName(); notify = true; } } @@ -1415,13 +1387,4 @@ void LLGestureMgr::done() } } -// static -const LLUUID& get_linked_uuid(const LLUUID &item_id) -{ - LLViewerInventoryItem* item = gInventory.getItem(item_id); - if (item && item->getIsLinkType()) - { - return item->getLinkedUUID(); - } - return item_id; -} + diff --git a/indra/newview/llgesturemgr.h b/indra/newview/llgesturemgr.h index 9f112261b2..ff28a164d0 100644 --- a/indra/newview/llgesturemgr.h +++ b/indra/newview/llgesturemgr.h @@ -27,8 +27,9 @@ #ifndef LL_LLGESTUREMGR_H #define LL_LLGESTUREMGR_H -#include #include +#include +#include #include #include "llassetstorage.h" // LLAssetType @@ -53,10 +54,10 @@ class LLGestureMgr : public LLSingleton, public LLInventoryFetchIt { public: - typedef boost::function gesture_loaded_callback_t; + typedef std::function gesture_loaded_callback_t; // Maps inventory item_id to gesture - typedef std::map item_map_t; - typedef std::map callback_map_t; + typedef boost::unordered_map item_map_t; + typedef boost::unordered_map callback_map_t; LLGestureMgr(); ~LLGestureMgr(); @@ -81,30 +82,30 @@ class LLGestureMgr : public LLSingleton, public LLInventoryFetchIt // Load gesture into in-memory active form. // Can be called even if the inventory item isn't loaded yet. - // inform_server TRUE will send message upstream to update database + // inform_server true will send message upstream to update database // user_gesture_active table, which isn't necessary on login. // deactivate_similar will cause other gestures with the same trigger phrase // or keybinding to be deactivated. - void activateGestureWithAsset(const LLUUID& item_id, const LLUUID& asset_id, BOOL inform_server, BOOL deactivate_similar); + void activateGestureWithAsset(const LLUUID& item_id, const LLUUID& asset_id, bool inform_server, bool deactivate_similar); // Takes gesture out of active list and deletes it. void deactivateGesture(const LLUUID& item_id); // Deactivates all gestures that match either this trigger phrase, // or this hot key. - void deactivateSimilarGestures(LLMultiGesture* gesture, const LLUUID& in_item_id); + void deactivateSimilarGestures(const LLMultiGesture* gesture, const LLUUID& in_item_id); - BOOL isGestureActive(const LLUUID& item_id); + bool isGestureActive(const LLUUID& item_id) const; - BOOL isGesturePlaying(const LLUUID& item_id); + bool isGesturePlaying(const LLUUID& item_id) const; - BOOL isGesturePlaying(LLMultiGesture* gesture); + bool isGesturePlaying(const LLMultiGesture* gesture) const; const item_map_t& getActiveGestures() const { return mActive; } // Force a gesture to be played, for example, if it is being // previewed. - void playGesture(LLMultiGesture* gesture); - void playGesture(const LLUUID& item_id); + void playGesture(LLMultiGesture* gesture, bool local = false); + void playGesture(const LLUUID& item_id, bool local = false); // Stop all requested or playing anims for this gesture // Also remove from playing list @@ -115,19 +116,19 @@ class LLGestureMgr : public LLSingleton, public LLInventoryFetchIt * Note: * Manager will call cb after gesture will be loaded and will remove cb automatically. */ - void setGestureLoadedCallback(LLUUID inv_item_id, gesture_loaded_callback_t cb) + void setGestureLoadedCallback(const LLUUID& inv_item_id, gesture_loaded_callback_t cb) { mCallbackMap[inv_item_id] = cb; } // Trigger the first gesture that matches this key. // Returns TRUE if it finds a gesture bound to that key. - BOOL triggerGesture(KEY key, MASK mask); + bool triggerGesture(KEY key, MASK mask); // Trigger all gestures referenced as substrings in this string - BOOL triggerAndReviseString(const std::string &str, std::string *revised_string = NULL); + bool triggerAndReviseString(const std::string &str, std::string *revised_string = nullptr); // Does some gesture have this key bound? - BOOL isKeyBound(KEY key, MASK mask); + //bool isKeyBound(KEY key, MASK mask) const; S32 getPlayingCount() const; @@ -138,10 +139,10 @@ class LLGestureMgr : public LLSingleton, public LLInventoryFetchIt // Overriding so we can update active gesture names and notify observers void changed(U32 mask); - BOOL matchPrefix(const std::string& in_str, std::string* out_str); + bool matchPrefix(const std::string& in_str, std::string* out_str) const; // Copy item ids into the vector - void getItemIDs(uuid_vec_t* ids); + void getItemIDs(uuid_vec_t* ids) const; protected: // Handle the processing of a single gesture @@ -172,7 +173,7 @@ class LLGestureMgr : public LLSingleton, public LLInventoryFetchIt private: // Active gestures. - // NOTE: The gesture pointer CAN BE NULL. This means that + // NOTE: The gesture pointer CAN BE a nullptr. This means that // there is a gesture with that item_id, but the asset data // is still on its way down from the server. item_map_t mActive; @@ -183,9 +184,9 @@ class LLGestureMgr : public LLSingleton, public LLInventoryFetchIt std::vector mObservers; callback_map_t mCallbackMap; std::vector mPlaying; - BOOL mValid; + bool mValid; - std::set mLoadingAssets; + uuid_set_t mLoadingAssets; }; #endif diff --git a/indra/newview/llgiveinventory.cpp b/indra/newview/llgiveinventory.cpp index 25885e68f6..73bc6cd835 100644 --- a/indra/newview/llgiveinventory.cpp +++ b/indra/newview/llgiveinventory.cpp @@ -36,6 +36,7 @@ #include "llagentdata.h" #include "llagentui.h" #include "llagentwearables.h" +#include "llavataractions.h" #include "llfloaterchat.h" //for addChatHistory #include "llfloatertools.h" // for gFloaterTool #include "llhudeffecttrail.h" @@ -55,7 +56,7 @@ // MAX ITEMS is based on (sizeof(uuid)+2) * count must be < MTUBYTES // or 18 * count < 1200 => count < 1200/18 => 66. I've cut it down a // bit from there to give some pad. -const S32 MAX_ITEMS = 42; +const size_t MAX_ITEMS = 50; class LLGiveable : public LLInventoryCollectFunctor { @@ -128,36 +129,31 @@ bool LLGiveInventory::isInventoryGiveAcceptable(const LLInventoryItem* item) { return false; } - - + bool acceptable = true; switch(item->getType()) { - case LLAssetType::AT_CALLINGCARD: - acceptable = false; - break; case LLAssetType::AT_OBJECT: - // - /*if(my_avatar->isWearingAttachment(item->getUUID())) + /* + if (get_is_item_worn(item->getUUID())) { acceptable = false; - }*/ - // + } + */ break; case LLAssetType::AT_BODYPART: case LLAssetType::AT_CLOTHING: { // /*bool copyable = false; - if(item->getPermissions().allowCopyBy(gAgent.getID())) copyable = true; + if(item->getPermissions().allowCopyBy(gAgentID)) copyable = true; - if(!copyable && gAgentWearables.isWearingItem(item->getUUID())) + if (!copyable || get_is_item_worn(item->getUUID())) { acceptable = false; }*/ // } - break; default: break; @@ -185,20 +181,16 @@ bool LLGiveInventory::isInventoryGroupGiveAcceptable(const LLInventoryItem* item bool acceptable = true; - switch(item->getType()) { - case LLAssetType::AT_CALLINGCARD: - acceptable = false; - break; - // - /*case LLAssetType::AT_OBJECT: + case LLAssetType::AT_OBJECT: + /* if(gAgentAvatarp->isWearingAttachment(item->getUUID())) { acceptable = false; - }* - break;*/ - // + } + */ + break; default: break; } @@ -212,7 +204,7 @@ bool LLGiveInventory::doGiveInventoryItem(const LLUUID& to_agent, { bool res = true; - llinfos << "LLGiveInventory::giveInventory()" << llendl; + LL_INFOS() << "LLGiveInventory::giveInventory()" << LL_ENDL; if(!isInventoryGiveAcceptable(item)) { return false; @@ -240,17 +232,25 @@ bool LLGiveInventory::doGiveInventoryItem(const LLUUID& to_agent, return res; } -void LLGiveInventory::doGiveInventoryCategory(const LLUUID& to_agent, +bool LLGiveInventory::doGiveInventoryCategory(const LLUUID& to_agent, const LLInventoryCategory* cat, - const LLUUID& im_session_id) + const LLUUID& im_session_id, + const std::string& notification_name) { - if (!cat) return; - llinfos << "LLGiveInventory::giveInventoryCategory() - " - << cat->getUUID() << llendl; + if (!cat) + { + return false; + } + LL_INFOS() << "LLGiveInventory::giveInventoryCategory() - " + << cat->getUUID() << LL_ENDL; - if (!isAgentAvatarValid()) return; + if (!isAgentAvatarValid()) + { + return false; + } + bool give_successful = true; // Test out how many items are being given. LLViewerInventoryCategory::cat_array_t cats; LLViewerInventoryItem::item_array_t items; @@ -260,11 +260,11 @@ void LLGiveInventory::doGiveInventoryCategory(const LLUUID& to_agent, items, LLInventoryModel::EXCLUDE_TRASH, giveable); - S32 count = cats.count(); + size_t count = cats.size(); bool complete = true; - for(S32 i = 0; i < count; ++i) + for(size_t i = 0; i < count; ++i) { - if(!gInventory.isCategoryComplete(cats.get(i)->getUUID())) + if(!gInventory.isCategoryComplete(cats.at(i)->getUUID())) { complete = false; break; @@ -273,24 +273,24 @@ void LLGiveInventory::doGiveInventoryCategory(const LLUUID& to_agent, if(!complete) { LLNotificationsUtil::add("IncompleteInventory"); - return; + give_successful = false; } - count = items.count() + cats.count(); - if(count > MAX_ITEMS) - { + count = items.size() + cats.size(); + if(count > MAX_ITEMS) + { LLNotificationsUtil::add("TooManyItems"); - return; - } - else if(count == 0) - { + give_successful = false; + } + else if(count == 0) + { LLNotificationsUtil::add("NoItems"); - return; - } - else + give_successful = false; + } + else if (give_successful) { if(0 == giveable.countNoCopy()) { - LLGiveInventory::commitGiveInventoryCategory(to_agent, cat, im_session_id); + give_successful = LLGiveInventory::commitGiveInventoryCategory(to_agent, cat, im_session_id); } else { @@ -299,9 +299,16 @@ void LLGiveInventory::doGiveInventoryCategory(const LLUUID& to_agent, LLSD payload; payload["agent_id"] = to_agent; payload["folder_id"] = cat->getUUID(); + if (!notification_name.empty()) + { + payload["success_notification"] = notification_name; + } LLNotificationsUtil::add("CannotCopyCountItems", args, payload, &LLGiveInventory::handleCopyProtectedCategory); + give_successful = false; } } + + return give_successful; } ////////////////////////////////////////////////////////////////////////// @@ -321,11 +328,11 @@ void LLGiveInventory::logInventoryOffer(const LLUUID& to_agent, const LLUUID &im gIMMgr->addSystemMessage(im_session_id, "inventory_item_offered", args); } // [RLVa:KB] - Checked: 2010-05-26 (RLVa-1.2.2a) | Modified: RLVa-1.2.0h - else if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (RlvUtil::isNearbyAgent(to_agent)) && + else if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES) || gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS)) && (RlvUtil::isNearbyAgent(to_agent)) && (!RlvUIEnabler::hasOpenProfile(to_agent)) ) { // Log to chat history if the user didn't drop on an IM session or a profile to avoid revealing the name of the recipient - std::string strMsgName = "inventory_item_offered"; LLSD args; LLAvatarName avName; + std::string strMsgName = "inventory_item_offered-im"; LLSD args; LLAvatarName avName; if (LLAvatarNameCache::get(to_agent, &avName)) { args["NAME"] = RlvStrings::getAnonym(avName); @@ -342,13 +349,9 @@ void LLGiveInventory::logInventoryOffer(const LLUUID& to_agent, const LLUUID &im // If this item was given by drag-and-drop on avatar while IM panel wasn't open, log this action to IM history. else { - std::string full_name; - if (gCacheName->getFullName(to_agent, full_name)) - { - LLChat chat(LLTrans::getString("inventory_item_offered_to") + " " + full_name); - chat.mSourceType = CHAT_SOURCE_SYSTEM; - LLFloaterChat::addChatHistory(chat); - } + LLChat chat(LLTrans::getString("inventory_item_offered_to") + ' ' + LLAvatarActions::getSLURL(to_agent)); + chat.mSourceType = CHAT_SOURCE_SYSTEM; + LLFloaterChat::addChatHistory(chat); } } @@ -358,6 +361,7 @@ bool LLGiveInventory::handleCopyProtectedItem(const LLSD& notification, const LL S32 option = LLNotificationsUtil::getSelectedOption(notification, response); LLSD itmes = notification["payload"]["items"]; LLInventoryItem* item = NULL; + bool give_successful = true; switch(option) { case 0: // "Yes" @@ -376,15 +380,21 @@ bool LLGiveInventory::handleCopyProtectedItem(const LLSD& notification, const LL else { LLNotificationsUtil::add("CannotGiveItem"); + give_successful = false; } } + if (give_successful && notification["payload"]["success_notification"].isDefined()) + { + LLNotificationsUtil::add(notification["payload"]["success_notification"].asString()); + } break; default: // no, cancel, whatever, who cares, not yes. LLNotificationsUtil::add("TransactionCancelled"); + give_successful = false; break; } - return false; + return give_successful; } // static @@ -419,6 +429,7 @@ void LLGiveInventory::commitGiveInventoryItem(const LLUUID& to_agent, bucket, BUCKET_SIZE); gAgent.sendReliableMessage(); + // if (gSavedSettings.getBOOL("BroadcastViewerEffects")) { @@ -444,13 +455,14 @@ bool LLGiveInventory::handleCopyProtectedCategory(const LLSD& notification, cons { S32 option = LLNotificationsUtil::getSelectedOption(notification, response); LLInventoryCategory* cat = NULL; + bool give_successful = true; switch(option) { case 0: // "Yes" cat = gInventory.getCategory(notification["payload"]["folder_id"].asUUID()); if(cat) { - LLGiveInventory::commitGiveInventoryCategory(notification["payload"]["agent_id"].asUUID(), + give_successful = LLGiveInventory::commitGiveInventoryCategory(notification["payload"]["agent_id"].asUUID(), cat); LLViewerInventoryCategory::cat_array_t cats; LLViewerInventoryItem::item_array_t items; @@ -460,35 +472,45 @@ bool LLGiveInventory::handleCopyProtectedCategory(const LLSD& notification, cons items, LLInventoryModel::EXCLUDE_TRASH, remove); - S32 count = items.count(); - for(S32 i = 0; i < count; ++i) + size_t count = items.size(); + for(size_t i = 0; i < count; ++i) { - gInventory.deleteObject(items.get(i)->getUUID()); + gInventory.deleteObject(items.at(i)->getUUID()); } gInventory.notifyObservers(); + + if (give_successful && notification["payload"]["success_notification"].isDefined()) + { + LLNotificationsUtil::add(notification["payload"]["success_notification"].asString()); + } } else { LLNotificationsUtil::add("CannotGiveCategory"); + give_successful = false; } break; default: // no, cancel, whatever, who cares, not yes. LLNotificationsUtil::add("TransactionCancelled"); + give_successful = false; break; } - return false; + return give_successful; } // static -void LLGiveInventory::commitGiveInventoryCategory(const LLUUID& to_agent, +bool LLGiveInventory::commitGiveInventoryCategory(const LLUUID& to_agent, const LLInventoryCategory* cat, const LLUUID& im_session_id) { -if(!cat) return; - llinfos << "LLGiveInventory::commitGiveInventoryCategory() - " - << cat->getUUID() << llendl; + if (!cat) + { + return false; + } + LL_INFOS() << "LLGiveInventory::commitGiveInventoryCategory() - " + << cat->getUUID() << LL_ENDL; // Test out how many items are being given. LLViewerInventoryCategory::cat_array_t cats; @@ -500,19 +522,20 @@ if(!cat) return; LLInventoryModel::EXCLUDE_TRASH, giveable); + bool give_successful = true; // MAX ITEMS is based on (sizeof(uuid)+2) * count must be < // MTUBYTES or 18 * count < 1200 => count < 1200/18 => // 66. I've cut it down a bit from there to give some pad. - S32 count = items.count() + cats.count(); - if(count > MAX_ITEMS) + size_t count = items.size() + cats.size(); + if (count > MAX_ITEMS) { LLNotificationsUtil::add("TooManyItems"); - return; + give_successful = false; } else if(count == 0) { LLNotificationsUtil::add("NoItems"); - return; + give_successful = false; } else { @@ -520,7 +543,7 @@ if(!cat) return; LLAgentUI::buildFullname(name); LLUUID transaction_id; transaction_id.generate(); - S32 bucket_size = (sizeof(U8) + UUID_BYTES) * (count + 1); + size_t bucket_size = (sizeof(U8) + UUID_BYTES) * (count + 1); U8* bucket = new U8[bucket_size]; U8* pos = bucket; U8 type = (U8)cat->getType(); @@ -528,22 +551,22 @@ if(!cat) return; pos += sizeof(U8); memcpy(pos, &(cat->getUUID()), UUID_BYTES); /* Flawfinder: ignore */ pos += UUID_BYTES; - S32 i; - count = cats.count(); + size_t i; + count = cats.size(); for(i = 0; i < count; ++i) { memcpy(pos, &type, sizeof(U8)); /* Flawfinder: ignore */ pos += sizeof(U8); - memcpy(pos, &(cats.get(i)->getUUID()), UUID_BYTES); /* Flawfinder: ignore */ + memcpy(pos, &(cats.at(i)->getUUID()), UUID_BYTES); /* Flawfinder: ignore */ pos += UUID_BYTES; } - count = items.count(); + count = items.size(); for(i = 0; i < count; ++i) { - type = (U8)items.get(i)->getType(); + type = (U8)items.at(i)->getType(); memcpy(pos, &type, sizeof(U8)); /* Flawfinder: ignore */ pos += sizeof(U8); - memcpy(pos, &(items.get(i)->getUUID()), UUID_BYTES); /* Flawfinder: ignore */ + memcpy(pos, &(items.at(i)->getUUID()), UUID_BYTES); /* Flawfinder: ignore */ pos += UUID_BYTES; } pack_instant_message( @@ -565,6 +588,7 @@ if(!cat) return; bucket_size); gAgent.sendReliableMessage(); delete[] bucket; + // if (gSavedSettings.getBOOL("BroadcastViewerEffects")) { @@ -584,5 +608,8 @@ if(!cat) return; logInventoryOffer(to_agent, im_session_id); } + + return give_successful; } + // EOF diff --git a/indra/newview/llgiveinventory.h b/indra/newview/llgiveinventory.h index 19dab82a58..85bc1ed49c 100644 --- a/indra/newview/llgiveinventory.h +++ b/indra/newview/llgiveinventory.h @@ -62,9 +62,11 @@ class LLGiveInventory /** * Gives passed inventory category to specified avatar in specified session. */ - static void doGiveInventoryCategory(const LLUUID& to_agent, + static bool doGiveInventoryCategory(const LLUUID& to_agent, const LLInventoryCategory* item, - const LLUUID &session_id = LLUUID::null); + const LLUUID &session_id = LLUUID::null, + const std::string& notification = std::string()); + // give inventory item functionality static bool handleCopyProtectedItem(const LLSD& notification, const LLSD& response); @@ -84,7 +86,7 @@ class LLGiveInventory // give inventory category functionality static bool handleCopyProtectedCategory(const LLSD& notification, const LLSD& response); - static void commitGiveInventoryCategory(const LLUUID& to_agent, + static bool commitGiveInventoryCategory(const LLUUID& to_agent, const LLInventoryCategory* cat, const LLUUID &im_session_id = LLUUID::null); diff --git a/indra/newview/llgivemoney.cpp b/indra/newview/llgivemoney.cpp index 6816c378ae..31f1ac598f 100644 --- a/indra/newview/llgivemoney.cpp +++ b/indra/newview/llgivemoney.cpp @@ -54,7 +54,6 @@ #include "hippogridmanager.h" -#include ///---------------------------------------------------------------------------- /// Local function declarations, constants, enums, and typedefs ///---------------------------------------------------------------------------- @@ -76,16 +75,13 @@ LLFloaterPay::LLFloaterPay(const std::string& name, DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT, DRAG_ON_TOP, MINIMIZE_NO, CLOSE_YES), mCallback(callback), - mObjectNameText(NULL), mTargetUUID(uuid), mTargetIsObject(target_is_object), mTargetIsGroup(FALSE), - mDefaultValue(0) + mDefaultValue(0), + mQuickPayButton({ {nullptr,nullptr,nullptr,nullptr} }), + mQuickPayInfo({ {PAY_BUTTON_DEFAULT_0, PAY_BUTTON_DEFAULT_1, PAY_BUTTON_DEFAULT_2, PAY_BUTTON_DEFAULT_3} }) { - mQuickPayInfo[0] = PAY_BUTTON_DEFAULT_0; - mQuickPayInfo[1] = PAY_BUTTON_DEFAULT_1; - mQuickPayInfo[2] = PAY_BUTTON_DEFAULT_2; - mQuickPayInfo[3] = PAY_BUTTON_DEFAULT_3; BOOST_STATIC_ASSERT(MAX_PAY_BUTTONS == 4); if (target_is_object) @@ -100,7 +96,7 @@ LLFloaterPay::LLFloaterPay(const std::string& name, for(U32 i = 0; i < MAX_PAY_BUTTONS; ++i) { - mQuickPayButton[i] = getChild("fastpay " + boost::lexical_cast(mQuickPayInfo[i])); + mQuickPayButton[i] = getChild("fastpay " + fmt::to_string(mQuickPayInfo[i])); mQuickPayButton[i]->setClickedCallback(boost::bind(&LLFloaterPay::onGive,this,boost::ref(mQuickPayInfo[i]))); mQuickPayButton[i]->setVisible(FALSE); mQuickPayButton[i]->setLabelArg("[CURRENCY]", gHippoGridManager->getConnectedGrid()->getCurrencySymbol()); @@ -136,6 +132,8 @@ LLFloaterPay::LLFloaterPay(const std::string& name, // Destroys the object LLFloaterPay::~LLFloaterPay() { + // In case this floater is currently waiting for a reply. + gMessageSystem->setHandlerFuncFast(_PREHASH_PayPriceReply, 0, 0); } // static diff --git a/indra/newview/llgivemoney.h b/indra/newview/llgivemoney.h index 540d0dade0..26abf34500 100644 --- a/indra/newview/llgivemoney.h +++ b/indra/newview/llgivemoney.h @@ -81,14 +81,12 @@ class LLFloaterPay : public LLFloater protected: money_callback mCallback; - LLTextBox* mObjectNameText; LLUUID mTargetUUID; BOOL mTargetIsObject; BOOL mTargetIsGroup; - BOOL mHaveName; - LLButton* mQuickPayButton[MAX_PAY_BUTTONS]; - S32 mQuickPayInfo[MAX_PAY_BUTTONS]; + std::array mQuickPayButton; + std::array mQuickPayInfo; S32 mDefaultValue; LLSafeHandle mObjectSelection; diff --git a/indra/newview/llglsandbox.cpp b/indra/newview/llglsandbox.cpp index b40e3d4718..6dca4a376e 100644 --- a/indra/newview/llglsandbox.cpp +++ b/indra/newview/llglsandbox.cpp @@ -100,10 +100,10 @@ void LLToolSelectRect::handleRectangleSelection(S32 x, S32 y, MASK mask) S32 top = llmax(y, mDragStartY); S32 bottom =llmin(y, mDragStartY); - left = llround((F32) left * LLUI::getScaleFactor().mV[VX]); - right = llround((F32) right * LLUI::getScaleFactor().mV[VX]); - top = llround((F32) top * LLUI::getScaleFactor().mV[VY]); - bottom = llround((F32) bottom * LLUI::getScaleFactor().mV[VY]); + left = ll_round((F32) left * LLUI::getScaleFactor().mV[VX]); + right = ll_round((F32) right * LLUI::getScaleFactor().mV[VX]); + top = ll_round((F32) top * LLUI::getScaleFactor().mV[VY]); + bottom = ll_round((F32) bottom * LLUI::getScaleFactor().mV[VY]); F32 old_far_plane = LLViewerCamera::getInstance()->getFar(); F32 old_near_plane = LLViewerCamera::getInstance()->getNear(); @@ -225,7 +225,7 @@ void LLToolSelectRect::handleRectangleSelection(S32 x, S32 y, MASK mask) LLSpatialPartition* part = region->getSpatialPartition(i); if (part) { - part->cull(*LLViewerCamera::getInstance(), &potentials, TRUE); + part->cull(*LLViewerCamera::getInstance(), &potentials); } } } @@ -297,7 +297,10 @@ void LLWind::renderVectors() S32 i,j; F32 x,y; - F32 region_width_meters = LLWorld::getInstance()->getRegionWidthInMeters(); +// Aurora Sim + //F32 region_width_meters = LLWorld::getInstance()->getRegionWidthInMeters(); + F32 region_width_meters = gAgent.getRegion()->getWidth(); +// Aurora Sim gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); gGL.pushMatrix(); @@ -383,25 +386,16 @@ void LLViewerParcelMgr::renderRect(const LLVector3d &west_south_bottom_global, gGL.end(); gGL.color4f(1.f, 1.f, 0.f, 0.2f); - gGL.begin(LLRender::QUADS); + gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.vertex3f(west, north, nw_bottom); gGL.vertex3f(west, north, nw_top); + gGL.vertex3f(west, north, nw_bottom); gGL.vertex3f(east, north, ne_top); gGL.vertex3f(east, north, ne_bottom); - - gGL.vertex3f(east, north, ne_bottom); - gGL.vertex3f(east, north, ne_top); gGL.vertex3f(east, south, se_top); gGL.vertex3f(east, south, se_bottom); - - gGL.vertex3f(east, south, se_bottom); - gGL.vertex3f(east, south, se_top); gGL.vertex3f(west, south, sw_top); gGL.vertex3f(west, south, sw_bottom); - - gGL.vertex3f(west, south, sw_bottom); - gGL.vertex3f(west, south, sw_top); gGL.vertex3f(west, north, nw_top); gGL.vertex3f(west, north, nw_bottom); @@ -505,7 +499,10 @@ void LLViewerParcelMgr::renderOneSegment(F32 x1, F32 y1, F32 x2, F32 y2, F32 hei return; // HACK: At edge of last region of world, we need to make sure the region // resolves correctly so we can get a height value. - const F32 BORDER = REGION_WIDTH_METERS - 0.1f; +// Aurora Sim + //const F32 BORDER = REGION_WIDTH_METERS - 0.1f; + const F32 BORDER = regionp->getWidth() - 0.1f; +// Aurora Sim F32 clamped_x1 = x1; F32 clamped_y1 = y1; @@ -518,8 +515,8 @@ void LLViewerParcelMgr::renderOneSegment(F32 x1, F32 y1, F32 x2, F32 y2, F32 hei if (clamped_y2 > BORDER) clamped_y2 = BORDER; F32 z; - F32 z1 = regionp->getLand().resolveHeightRegion( LLVector3( clamped_x1, clamped_y1, 0.f ) );; - F32 z2 = regionp->getLand().resolveHeightRegion( LLVector3( clamped_x2, clamped_y2, 0.f ) );; + F32 z1 = regionp->getLand().resolveHeightRegion( LLVector3( clamped_x1, clamped_y1, 0.f ) ); + F32 z2 = regionp->getLand().resolveHeightRegion( LLVector3( clamped_x2, clamped_y2, 0.f ) ); // Convert x1 and x2 from region-local to agent coords. LLVector3 origin = regionp->getOriginAgent(); @@ -535,10 +532,11 @@ void LLViewerParcelMgr::renderOneSegment(F32 x1, F32 y1, F32 x2, F32 y2, F32 hei gGL.vertex3f(x1, y1, z1); - gGL.vertex3f(x2, y2, z2); - - z = z2+height; + z = z2 + height; + gGL.vertex3f(x2, y2, z); gGL.vertex3f(x2, y2, z); + gGL.vertex3f(x1, y1, z1); + gGL.vertex3f(x2, y2, z2); } else { @@ -575,11 +573,14 @@ void LLViewerParcelMgr::renderOneSegment(F32 x1, F32 y1, F32 x2, F32 y2, F32 hei // top edge stairsteps z = llmax(z2+height, z1+height); + gGL.texCoord2f(tex_coord1*0.5f + 0.5f, z*0.5f); + gGL.vertex3f(x1, y1, z); + gGL.texCoord2f(tex_coord1*0.5f + 0.5f, z*0.5f); + gGL.vertex3f(x1, y1, z); gGL.texCoord2f(tex_coord2*0.5f+0.5f, z*0.5f); gGL.vertex3f(x2, y2, z); - - gGL.texCoord2f(tex_coord1*0.5f+0.5f, z*0.5f); - gGL.vertex3f(x1, y1, z); + gGL.texCoord2f(tex_coord1*0.5f + 0.5f, z1*0.5f); + gGL.vertex3f(x1, y1, z1); } } @@ -619,7 +620,7 @@ void LLViewerParcelMgr::renderHighlightSegments(const U8* segments, LLViewerRegi if (!has_segments) { has_segments = true; - gGL.begin(LLRender::QUADS); + gGL.begin(LLRender::TRIANGLES); } renderOneSegment(x1, y1, x2, y2, PARCEL_POST_HEIGHT, SOUTH_MASK, regionp); } @@ -635,7 +636,7 @@ void LLViewerParcelMgr::renderHighlightSegments(const U8* segments, LLViewerRegi if (!has_segments) { has_segments = true; - gGL.begin(LLRender::QUADS); + gGL.begin(LLRender::TRIANGLES); } renderOneSegment(x1, y1, x2, y2, PARCEL_POST_HEIGHT, WEST_MASK, regionp); } @@ -669,9 +670,10 @@ void LLViewerParcelMgr::renderCollisionSegments(U8* segments, BOOL use_pass, LLV LLGLSUIDefault gls_ui; LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE); - LLGLDisable cull(GL_CULL_FACE); + LLGLDisable cull; - if (mCollisionBanned == BA_BANNED) + if (mCollisionBanned == BA_BANNED || + regionp->getRegionFlag(REGION_FLAGS_BLOCK_FLYOVER)) { collision_height = BAN_HEIGHT; } @@ -690,7 +692,7 @@ void LLViewerParcelMgr::renderCollisionSegments(U8* segments, BOOL use_pass, LLV gGL.getTexUnit(0)->bind(mBlockedImage); } - gGL.begin(LLRender::QUADS); + gGL.begin(LLRender::TRIANGLES); for (y = 0; y < STRIDE; y++) { @@ -844,8 +846,7 @@ void LLViewerObjectList::renderObjectBeacons() S32 line_width = debug_beacon.mLineWidth; if (line_width != last_line_width) { - gGL.flush(); - glLineWidth( (F32)line_width ); + gGL.setLineWidth(line_width); last_line_width = line_width; } @@ -880,8 +881,7 @@ void LLViewerObjectList::renderObjectBeacons() S32 line_width = debug_beacon.mLineWidth; if (line_width != last_line_width) { - gGL.flush(); - glLineWidth( (F32)line_width ); + gGL.setLineWidth(line_width); last_line_width = line_width; } @@ -900,13 +900,12 @@ void LLViewerObjectList::renderObjectBeacons() gGL.end(); } - gGL.flush(); - glLineWidth(1.f); + gGL.setLineWidth(1.f); for (std::vector::iterator iter = mDebugBeacons.begin(); iter != mDebugBeacons.end(); ++iter) { LLDebugBeacon &debug_beacon = *iter; - if (debug_beacon.mString == "") + if (debug_beacon.mString.empty()) { continue; } diff --git a/indra/newview/llgroupactions.cpp b/indra/newview/llgroupactions.cpp index 60a4a6cafe..91141253c5 100644 --- a/indra/newview/llgroupactions.cpp +++ b/indra/newview/llgroupactions.cpp @@ -40,9 +40,10 @@ #include "llpanelgroup.h" #include "llviewermessage.h" #include "groupchatlistener.h" -#include "hippolimits.h" // for getMaxAgentGroups -// [RLVa:KB] - Checked: 2011-03-28 (RLVa-1.3.0f) +// [RLVa:KB] - Checked: 2011-03-28 (RLVa-1.3.0) #include "llslurl.h" +#include "rlvactions.h" +#include "rlvcommon.h" #include "rlvhandler.h" // [/RLVa:KB] @@ -88,7 +89,6 @@ class LLGroupHandler : public LLCommandHandler // CP_TODO: get the value we pass in via the XUI name // of the tab instead of using a literal like this LLFloaterMyFriends::showInstance( 1 ); - return true; } return false; @@ -121,6 +121,77 @@ class LLGroupHandler : public LLCommandHandler }; LLGroupHandler gGroupHandler; +// This object represents a pending request for specified group member information +// which is needed to check whether avatar can leave group +class LLFetchGroupMemberData : public LLGroupMgrObserver +{ +public: + LLFetchGroupMemberData(const LLUUID& group_id) : + mGroupId(group_id), + mRequestProcessed(false), + LLGroupMgrObserver(group_id) + { + LL_INFOS() << "Sending new group member request for group_id: "<< group_id << LL_ENDL; + LLGroupMgr* mgr = LLGroupMgr::getInstance(); + // register ourselves as an observer + mgr->addObserver(this); + // send a request + mgr->sendGroupPropertiesRequest(group_id); + mgr->sendCapGroupMembersRequest(group_id); + } + + ~LLFetchGroupMemberData() + { + if (!mRequestProcessed) + { + // Request is pending + LL_WARNS() << "Destroying pending group member request for group_id: " + << mGroupId << LL_ENDL; + } + // Remove ourselves as an observer + LLGroupMgr::getInstance()->removeObserver(this); + } + + void changed(LLGroupChange gc) + { + if (gc == GC_PROPERTIES && !mRequestProcessed) + { + LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupId); + if (!gdatap) + { + LL_WARNS() << "LLGroupMgr::getInstance()->getGroupData() was NULL" << LL_ENDL; + } + else if (!gdatap->isMemberDataComplete()) + { + LL_WARNS() << "LLGroupMgr::getInstance()->getGroupData()->isMemberDataComplete() was FALSE" << LL_ENDL; + processGroupData(); + mRequestProcessed = true; + } + } + } + + LLUUID getGroupId() { return mGroupId; } + virtual void processGroupData() = 0; +protected: + LLUUID mGroupId; +private: + bool mRequestProcessed; +}; + +class LLFetchLeaveGroupData : public LLFetchGroupMemberData +{ +public: + LLFetchLeaveGroupData(const LLUUID& group_id) + : LLFetchGroupMemberData(group_id) + {} + void processGroupData() + { + LLGroupActions::processLeaveGroupDataResponse(mGroupId); + } +}; + +LLFetchLeaveGroupData* gFetchLeaveGroupData = NULL; + // static void LLGroupActions::search() { @@ -138,12 +209,12 @@ void LLGroupActions::startCall(const LLUUID& group_id) if (!gAgent.getGroupData(group_id, gdata)) { - llwarns << "Error getting group data" << llendl; + LL_WARNS() << "Error getting group data" << LL_ENDL; return; } -// [RLVa:KB] - Checked: 2011-04-11 (RLVa-1.3.0h) | Added: RLVa-1.3.0h - if ( (rlv_handler_t::isEnabled()) && (!gRlvHandler.canStartIM(group_id)) && (!gIMMgr->hasSession(group_id)) ) +// [RLVa:KB] - Checked: 2013-05-09 (RLVa-1.4.9) + if ( (!RlvActions::canStartIM(group_id)) && (!RlvActions::hasOpenGroupSession(group_id)) ) { make_ui_sound("UISndInvalidOp"); RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTIM, LLSD().with("RECIPIENT", LLSLURL("group", group_id, "about").getSLURLString())); @@ -151,10 +222,10 @@ void LLGroupActions::startCall(const LLUUID& group_id) } // [/RLVa:KB] - LLUUID session_id = gIMMgr->addSession(gdata.mName, IM_SESSION_GROUP_START, group_id, true); + LLUUID session_id = gIMMgr->addSession(gdata.mName, IM_SESSION_GROUP_START, group_id); if (session_id.isNull()) { - llwarns << "Error adding session" << llendl; + LL_WARNS() << "Error adding session" << LL_ENDL; return; } @@ -167,7 +238,7 @@ void LLGroupActions::startCall(const LLUUID& group_id) // static void LLGroupActions::join(const LLUUID& group_id) { - if (gAgent.mGroups.count() >= gHippoLimits->getMaxAgentGroups()) //!gAgent.canJoinGroups() + if (!gAgent.canJoinGroups()) { LLNotificationsUtil::add("JoinedTooManyGroups"); return; @@ -199,8 +270,8 @@ void LLGroupActions::join(const LLUUID& group_id) } else { - llwarns << "LLGroupMgr::getInstance()->getGroupData(" << group_id - << ") was NULL" << llendl; + LL_WARNS() << "LLGroupMgr::getInstance()->getGroupData(" << group_id + << ") was NULL" << LL_ENDL; } } @@ -224,27 +295,55 @@ bool LLGroupActions::onJoinGroup(const LLSD& notification, const LLSD& response) void LLGroupActions::leave(const LLUUID& group_id) { // if (group_id.isNull()) -// return; // [RLVa:KB] - Checked: 2011-03-28 (RLVa-1.4.1a) | Added: RLVa-1.3.0f if ( (group_id.isNull()) || ((gAgent.getGroupID() == group_id) && (gRlvHandler.hasBehaviour(RLV_BHVR_SETGROUP))) ) - return; // [/RLVa:KB] + { + return; + } - S32 count = gAgent.mGroups.count(); - S32 i; - for (i = 0; i < count; ++i) + LLGroupData group_data; + if (gAgent.getGroupData(group_id, group_data)) { - if(gAgent.mGroups.get(i).mID == group_id) - break; + LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(group_id); + if (!gdatap || !gdatap->isMemberDataComplete()) + { + if (gFetchLeaveGroupData != NULL) + { + delete gFetchLeaveGroupData; + gFetchLeaveGroupData = NULL; + } + gFetchLeaveGroupData = new LLFetchLeaveGroupData(group_id); } - if (i < count) + else + { + processLeaveGroupDataResponse(group_id); + } + } +} + +//static +void LLGroupActions::processLeaveGroupDataResponse(const LLUUID group_id) +{ + LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(group_id); + LLUUID agent_id = gAgent.getID(); + LLGroupMgrGroupData::member_list_t::iterator mit = gdatap->mMembers.find(agent_id); + //get the member data for the group + if ( mit != gdatap->mMembers.end() ) { - LLSD args; - args["GROUP"] = gAgent.mGroups.get(i).mName; - LLSD payload; - payload["group_id"] = group_id; - LLNotificationsUtil::add("GroupLeaveConfirmMember", args, payload, onLeaveGroup); + LLGroupMemberData* member_data = (*mit).second; + + if ( member_data && member_data->isOwner() && gdatap->mMemberCount == 1) + { + LLNotificationsUtil::add("OwnerCannotLeaveGroup"); + return; + } } + LLSD args; + args["GROUP"] = gdatap->mName; + LLSD payload; + payload["group_id"] = group_id; + LLNotificationsUtil::add("GroupLeaveConfirmMember", args, payload, onLeaveGroup); } // static @@ -285,7 +384,6 @@ void LLGroupActions::inspect(const LLUUID& group_id) openGroupProfile(group_id); } - // static void LLGroupActions::show(const LLUUID& group_id) { @@ -302,6 +400,13 @@ void LLGroupActions::show(const LLUUID& group_id) openGroupProfile(group_id); } +// static +void LLGroupActions::showProfiles(const uuid_vec_t& ids) +{ + for (const auto& id : ids) + show(id); +} + // static void LLGroupActions::showTab(const LLUUID& group_id, const std::string& tab_name) { @@ -398,8 +503,8 @@ LLUUID LLGroupActions::startIM(const LLUUID& group_id) { if (group_id.isNull()) return LLUUID::null; -// [RLVa:KB] - Checked: 2011-04-11 (RLVa-1.3.0h) | Added: RLVa-1.3.0h - if ( (rlv_handler_t::isEnabled()) && (!gRlvHandler.canStartIM(group_id)) && (!gIMMgr->hasSession(group_id)) ) +// [RLVa:KB] - Checked: 2013-05-09 (RLVa-1.4.9) + if ( (!RlvActions::canStartIM(group_id)) && (!RlvActions::hasOpenGroupSession(group_id)) ) { make_ui_sound("UISndInvalidOp"); RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTIM, LLSD().with("RECIPIENT", LLSLURL("group", group_id, "about").getSLURLString())); @@ -503,3 +608,8 @@ LLFloaterGroupInfo* LLGroupActions::openGroupProfile(const LLUUID& group_id) return fgi; } +std::string LLGroupActions::getSLURL(const LLUUID& id) +{ + return llformat("secondlife:///app/group/%s/about", id.asString().c_str()); +} + diff --git a/indra/newview/llgroupactions.h b/indra/newview/llgroupactions.h index b59fbbe407..dc4ff4fe5d 100644 --- a/indra/newview/llgroupactions.h +++ b/indra/newview/llgroupactions.h @@ -58,6 +58,7 @@ class LLGroupActions * Show group information panel. */ static void show(const LLUUID& group_id); + static void showProfiles(const uuid_vec_t& group_ids); /** * Show group information panel, with specific tab open. @@ -121,11 +122,23 @@ class LLGroupActions */ static bool isAvatarMemberOfGroup(const LLUUID& group_id, const LLUUID& avatar_id); + /** + * @return slurl string from group ID + */ + static std::string getSLURL(const LLUUID& id); + private: static bool onJoinGroup(const LLSD& notification, const LLSD& response); static bool onLeaveGroup(const LLSD& notification, const LLSD& response); + + /** + * This function is called by LLFetchLeaveGroupData upon receiving a response to a group + * members data request. + */ + static void processLeaveGroupDataResponse(const LLUUID group_id); static LLFloaterGroupInfo* openGroupProfile(const LLUUID& group_id); + + friend class LLFetchLeaveGroupData; }; #endif // LL_LLGROUPACTIONS_H - diff --git a/indra/newview/llgroupmgr.cpp b/indra/newview/llgroupmgr.cpp index 70eddbcdc2..1804c558a3 100644 --- a/indra/newview/llgroupmgr.cpp +++ b/indra/newview/llgroupmgr.cpp @@ -38,15 +38,16 @@ #include "llappviewer.h" //For gFrameCount #include "llagent.h" +#include "llavatarnamecache.h" #include "llui.h" #include "message.h" #include "roles_constants.h" #include "lltransactiontypes.h" #include "llstatusbar.h" -#include "lleconomy.h" #include "llviewerregion.h" #include "llviewerwindow.h" #include "llfloaterdirectory.h" +#include "llfloatergroupinfo.h" #include "llgroupactions.h" #include "llnotificationsutil.h" #include "lluictrlfactory.h" @@ -78,6 +79,7 @@ LLRoleActionSet::~LLRoleActionSet() { delete mActionSetData; std::for_each(mActions.begin(), mActions.end(), DeletePointer()); + mActions.clear(); } // @@ -157,7 +159,7 @@ LLGroupRoleData::~LLGroupRoleData() { } -S32 LLGroupRoleData::getMembersInRole(uuid_vec_t members, +S32 LLGroupRoleData::getMembersInRole(uuid_vec_t& members, BOOL needs_sort) { if (mRoleID.isNull()) @@ -231,12 +233,13 @@ LLGroupMgrGroupData::LLGroupMgrGroupData(const LLUUID& id) : mMemberCount(0), mRoleCount(0), mReceivedRoleMemberPairs(0), - mMemberDataComplete(FALSE), - mRoleDataComplete(FALSE), - mRoleMemberDataComplete(FALSE), - mGroupPropertiesDataComplete(FALSE), - mPendingRoleMemberRequest(FALSE), - mAccessTime(0.0f) + mMemberDataComplete(false), + mRoleDataComplete(false), + mRoleMemberDataComplete(false), + mGroupPropertiesDataComplete(false), + mPendingRoleMemberRequest(false), + mAccessTime(0.0f), + mPendingBanRequest(false) { mMemberVersion.generate(); } @@ -327,7 +330,7 @@ void LLGroupMgrGroupData::setRoleData(const LLUUID& role_id, LLRoleData role_dat } else { - llwarns << "Change being made to non-existant role " << role_id << llendl; + LL_WARNS() << "Change being made to non-existant role " << role_id << LL_ENDL; } } @@ -341,7 +344,7 @@ void LLGroupMgrGroupData::createRole(const LLUUID& role_id, LLRoleData role_data { if (mRoleChanges.find(role_id) != mRoleChanges.end()) { - llwarns << "create role for existing role! " << role_id << llendl; + LL_WARNS() << "create role for existing role! " << role_id << LL_ENDL; } else { @@ -378,7 +381,7 @@ void LLGroupMgrGroupData::addRolePower(const LLUUID &role_id, U64 power) } else { - llwarns << "addRolePower: no role data found for " << role_id << llendl; + LL_WARNS() << "addRolePower: no role data found for " << role_id << LL_ENDL; } } @@ -392,7 +395,7 @@ void LLGroupMgrGroupData::removeRolePower(const LLUUID &role_id, U64 power) } else { - llwarns << "removeRolePower: no role data found for " << role_id << llendl; + LL_WARNS() << "removeRolePower: no role data found for " << role_id << LL_ENDL; } } @@ -405,7 +408,7 @@ U64 LLGroupMgrGroupData::getRolePowers(const LLUUID& role_id) } else { - llwarns << "getRolePowers: no role data found for " << role_id << llendl; + LL_WARNS() << "getRolePowers: no role data found for " << role_id << LL_ENDL; return GP_NO_POWERS; } } @@ -424,7 +427,7 @@ void LLGroupMgrGroupData::removeMemberData() delete mi->second; } mMembers.clear(); - mMemberDataComplete = FALSE; + mMemberDataComplete = false; mMemberVersion.generate(); } @@ -446,8 +449,8 @@ void LLGroupMgrGroupData::removeRoleData() } mRoles.clear(); mReceivedRoleMemberPairs = 0; - mRoleDataComplete = FALSE; - mRoleMemberDataComplete = FALSE; + mRoleDataComplete = false; + mRoleMemberDataComplete = false; } void LLGroupMgrGroupData::removeRoleMemberData() @@ -471,7 +474,7 @@ void LLGroupMgrGroupData::removeRoleMemberData() } mReceivedRoleMemberPairs = 0; - mRoleMemberDataComplete = FALSE; + mRoleMemberDataComplete = false; } LLGroupMgrGroupData::~LLGroupMgrGroupData() @@ -489,8 +492,8 @@ bool LLGroupMgrGroupData::changeRoleMember(const LLUUID& role_id, if (ri == mRoles.end() || mi == mMembers.end() ) { - if (ri == mRoles.end()) llwarns << "LLGroupMgrGroupData::changeRoleMember couldn't find role " << role_id << llendl; - if (mi == mMembers.end()) llwarns << "LLGroupMgrGroupData::changeRoleMember couldn't find member " << member_id << llendl; + if (ri == mRoles.end()) LL_WARNS() << "LLGroupMgrGroupData::changeRoleMember couldn't find role " << role_id << LL_ENDL; + if (mi == mMembers.end()) LL_WARNS() << "LLGroupMgrGroupData::changeRoleMember couldn't find member " << member_id << LL_ENDL; return false; } @@ -499,13 +502,13 @@ bool LLGroupMgrGroupData::changeRoleMember(const LLUUID& role_id, if (!grd || !gmd) { - llwarns << "LLGroupMgrGroupData::changeRoleMember couldn't get member or role data." << llendl; + LL_WARNS() << "LLGroupMgrGroupData::changeRoleMember couldn't get member or role data." << LL_ENDL; return false; } if (RMC_ADD == rmc) { - llinfos << " adding member to role." << llendl; + LL_INFOS() << " adding member to role." << LL_ENDL; grd->addMember(member_id); gmd->addRole(role_id,grd); @@ -515,7 +518,7 @@ bool LLGroupMgrGroupData::changeRoleMember(const LLUUID& role_id, } else if (RMC_REMOVE == rmc) { - llinfos << " removing member from role." << llendl; + LL_INFOS() << " removing member from role." << LL_ENDL; grd->removeMember(member_id); gmd->removeRole(role_id); @@ -534,9 +537,9 @@ bool LLGroupMgrGroupData::changeRoleMember(const LLUUID& role_id, if (it->second.mChange == rmc) { // Already recorded this change? Weird. - llinfos << "Received duplicate change for " + LL_INFOS() << "Received duplicate change for " << " role: " << role_id << " member " << member_id - << " change " << (rmc == RMC_ADD ? "ADD" : "REMOVE") << llendl; + << " change " << (rmc == RMC_ADD ? "ADD" : "REMOVE") << LL_ENDL; } else { @@ -544,7 +547,7 @@ bool LLGroupMgrGroupData::changeRoleMember(const LLUUID& role_id, // If that changes this will need more logic if (rmc == RMC_NONE) { - llwarns << "changeRoleMember: existing entry with 'RMC_NONE' change! This shouldn't happen." << llendl; + LL_WARNS() << "changeRoleMember: existing entry with 'RMC_NONE' change! This shouldn't happen." << LL_ENDL; LLRoleMemberChange rc(role_id,member_id,rmc); mRoleMemberChanges[role_member] = rc; } @@ -608,6 +611,11 @@ void LLGroupMgrGroupData::recalcAgentPowers(const LLUUID& agent_id) } } +bool LLGroupMgrGroupData::isSingleMemberNotOwner() +{ + return mMembers.size() == 1 && !mMembers.begin()->second->isOwner(); +} + bool packRoleUpdateMessageBlock(LLMessageSystem* msg, const LLUUID& group_id, const LLUUID& role_id, @@ -721,7 +729,7 @@ CMD_SCRIPT(setroletext) const bool title = args[3].asInteger() == 1; const std::string str = args[4].asString(); const bool force = args[5].asInteger() == 1; - llinfos<<"Updating role- group_id:"<sendCapGroupMembersRequest(mID); + } + + if (!mRoleDataComplete) + { + LLGroupMgr::getInstance()->sendGroupRoleDataRequest(mID); + } + + return; + } + + LLGroupMgrGroupData::member_list_t::iterator mi = mMembers.find((participant_uuid)); + if (mi == mMembers.end()) + { + if (!mPendingBanRequest) + { + mPendingBanRequest = true; + mPendingBanMemberID = participant_uuid; + LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mID); // member isn't in members list, request reloading + } + else + { + mPendingBanRequest = false; + } + + return; + } + + mPendingBanRequest = false; + + LLGroupMemberData* member_data = (*mi).second; + if (member_data && member_data->isInRole(mOwnerRole)) + { + return; // can't ban group owner + } + + uuid_vec_t ids; + ids.push_back(participant_uuid); + + LLGroupBanData ban_data; + createBanEntry(participant_uuid, ban_data); + LLGroupMgr::getInstance()->sendGroupBanRequest(LLGroupMgr::REQUEST_POST, mID, LLGroupMgr::BAN_CREATE, ids); + LLGroupMgr::getInstance()->sendGroupMemberEjects(mID, ids); + LLGroupMgr::getInstance()->sendGroupMembersRequest(mID); + LLSD args; + std::string name; + LLAvatarNameCache::getNSName(participant_uuid, name); + args["AVATAR_NAME"] = name; + args["GROUP_NAME"] = mName; + LLNotifications::instance().add(LLNotification::Params("EjectAvatarFromGroup").substitutions(args)); +} + // // LLGroupMgr // @@ -926,25 +1012,48 @@ LLGroupMgrGroupData* LLGroupMgr::getGroupData(const LLUUID& id) // so that the sorter can sort by year before month before day. static void formatDateString(std::string &date_string) { - tm t; - if (sscanf(date_string.c_str(), "%u/%u/%u", &t.tm_mon, &t.tm_mday, &t.tm_year) == 3 && t.tm_year > 1900) + using namespace boost; + cmatch result; + const regex expression("([0-9]{1,2})/([0-9]{1,2})/([0-9]{4})"); + try + { + if (regex_match(date_string.c_str(), result, expression)) { - t.tm_year -= 1900; - t.tm_mon--; - t.tm_hour = t.tm_min = t.tm_sec = 0; - timeStructToFormattedString(&t, gSavedSettings.getString("ShortDateFormat"), date_string); + // convert matches to integers so that we can pad them with zeroes on Linux + S32 year = boost::lexical_cast(result[3]); + S32 month = boost::lexical_cast(result[1]); + S32 day = boost::lexical_cast(result[2]); + + // ISO 8601 date format + date_string = llformat("%04d-%02d-%02dT00:00:00Z", year, month, day); + } } + catch(...) + { + LL_ERRS() << "Decode of non-compliant DateTime format from [GroupMembersReply.GroupData.MemberData.OnlineStatus]. Please notify grid operators of this defect." << LL_ENDL; + } +} + +const std::string& localized_online() +{ + static const std::string online(LLTrans::getString("group_member_status_online")); + return online; +} +const std::string& localized_unknown() +{ + static const std::string unknown(LLTrans::getString("group_member_status_unknown")); + return unknown; } // static void LLGroupMgr::processGroupMembersReply(LLMessageSystem* msg, void** data) { - lldebugs << "LLGroupMgr::processGroupMembersReply" << llendl; + LL_DEBUGS() << "LLGroupMgr::processGroupMembersReply" << LL_ENDL; LLUUID agent_id; msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id ); if (gAgent.getID() != agent_id) { - llwarns << "Got group members reply for another agent!" << llendl; + LL_WARNS() << "Got group members reply for another agent!" << LL_ENDL; return; } @@ -957,7 +1066,7 @@ void LLGroupMgr::processGroupMembersReply(LLMessageSystem* msg, void** data) LLGroupMgrGroupData* group_datap = LLGroupMgr::getInstance()->getGroupData(group_id); if (!group_datap || (group_datap->mMemberRequestID != request_id)) { - llwarns << "processGroupMembersReply: Received incorrect (stale?) group or request id" << llendl; + LL_WARNS() << "processGroupMembersReply: Received incorrect (stale?) group or request id" << LL_ENDL; return; } @@ -987,15 +1096,18 @@ void LLGroupMgr::processGroupMembersReply(LLMessageSystem* msg, void** data) { if (online_status == "Online") { - static std::string localized_online(LLTrans::getString("group_member_status_online")); - online_status = localized_online; + online_status = localized_online(); + } + else if (online_status == "unknown") + { + online_status = localized_unknown(); } else { formatDateString(online_status); // reformat for sorting, e.g. 12/25/2008 -> 2008/12/25 } - //llinfos << "Member " << member_id << " has powers " << std::hex << agent_powers << std::dec << llendl; + //LL_INFOS() << "Member " << member_id << " has powers " << std::hex << agent_powers << std::dec << LL_ENDL; LLGroupMemberData* newdata = new LLGroupMemberData(member_id, contribution, agent_powers, @@ -1006,14 +1118,14 @@ void LLGroupMgr::processGroupMembersReply(LLMessageSystem* msg, void** data) LLGroupMgrGroupData::member_list_t::iterator mit = group_datap->mMembers.find(member_id); if (mit != group_datap->mMembers.end()) { - llinfos << " *** Received duplicate member data for agent " << member_id << llendl; + LL_INFOS() << " *** Received duplicate member data for agent " << member_id << LL_ENDL; } #endif group_datap->mMembers[member_id] = newdata; } else { - llinfos << "Received null group member data." << llendl; + LL_INFOS() << "Received null group member data." << LL_ENDL; } } @@ -1028,12 +1140,12 @@ void LLGroupMgr::processGroupMembersReply(LLMessageSystem* msg, void** data) if (group_datap->mMembers.size() == (U32)group_datap->mMemberCount) { - group_datap->mMemberDataComplete = TRUE; + group_datap->mMemberDataComplete = true; group_datap->mMemberRequestID.setNull(); // We don't want to make role-member data requests until we have all the members if (group_datap->mPendingRoleMemberRequest) { - group_datap->mPendingRoleMemberRequest = FALSE; + group_datap->mPendingRoleMemberRequest = false; LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(group_datap->mID); } } @@ -1045,12 +1157,12 @@ void LLGroupMgr::processGroupMembersReply(LLMessageSystem* msg, void** data) //static void LLGroupMgr::processGroupPropertiesReply(LLMessageSystem* msg, void** data) { - lldebugs << "LLGroupMgr::processGroupPropertiesReply" << llendl; + LL_DEBUGS() << "LLGroupMgr::processGroupPropertiesReply" << LL_ENDL; LLUUID agent_id; msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id ); if (gAgent.getID() != agent_id) { - llwarns << "Got group properties reply for another agent!" << llendl; + LL_WARNS() << "Got group properties reply for another agent!" << LL_ENDL; return; } @@ -1103,7 +1215,7 @@ void LLGroupMgr::processGroupPropertiesReply(LLMessageSystem* msg, void** data) group_datap->mMemberCount = num_group_members; group_datap->mRoleCount = num_group_roles + 1; // Add the everyone role. - group_datap->mGroupPropertiesDataComplete = TRUE; + group_datap->mGroupPropertiesDataComplete = true; group_datap->mChanged = TRUE; LLGroupMgr::getInstance()->notifyObservers(GC_PROPERTIES); @@ -1112,12 +1224,12 @@ void LLGroupMgr::processGroupPropertiesReply(LLMessageSystem* msg, void** data) // static void LLGroupMgr::processGroupRoleDataReply(LLMessageSystem* msg, void** data) { - lldebugs << "LLGroupMgr::processGroupRoleDataReply" << llendl; + LL_DEBUGS() << "LLGroupMgr::processGroupRoleDataReply" << LL_ENDL; LLUUID agent_id; msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id ); if (gAgent.getID() != agent_id) { - llwarns << "Got group role data reply for another agent!" << llendl; + LL_WARNS() << "Got group role data reply for another agent!" << LL_ENDL; return; } @@ -1130,7 +1242,7 @@ void LLGroupMgr::processGroupRoleDataReply(LLMessageSystem* msg, void** data) LLGroupMgrGroupData* group_datap = LLGroupMgr::getInstance()->getGroupData(group_id); if (!group_datap || (group_datap->mRoleDataRequestID != request_id)) { - llwarns << "processGroupPropertiesReply: Received incorrect (stale?) group or request id" << llendl; + LL_WARNS() << "processGroupPropertiesReply: Received incorrect (stale?) group or request id" << LL_ENDL; return; } @@ -1171,19 +1283,21 @@ void LLGroupMgr::processGroupRoleDataReply(LLMessageSystem* msg, void** data) name = LLTrans::getString("group_role_owners"); } - lldebugs << "Adding role data: " << name << " {" << role_id << "}" << llendl; + + + LL_DEBUGS() << "Adding role data: " << name << " {" << role_id << "}" << LL_ENDL; LLGroupRoleData* rd = new LLGroupRoleData(role_id,name,title,desc,powers,member_count); group_datap->mRoles[role_id] = rd; } if (group_datap->mRoles.size() == (U32)group_datap->mRoleCount) { - group_datap->mRoleDataComplete = TRUE; + group_datap->mRoleDataComplete = true; group_datap->mRoleDataRequestID.setNull(); // We don't want to make role-member data requests until we have all the role data if (group_datap->mPendingRoleMemberRequest) { - group_datap->mPendingRoleMemberRequest = FALSE; + group_datap->mPendingRoleMemberRequest = false; LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(group_datap->mID); } } @@ -1198,12 +1312,12 @@ void LLGroupMgr::processGroupRoleDataReply(LLMessageSystem* msg, void** data) // static void LLGroupMgr::processGroupRoleMembersReply(LLMessageSystem* msg, void** data) { - lldebugs << "LLGroupMgr::processGroupRoleMembersReply" << llendl; + LL_DEBUGS() << "LLGroupMgr::processGroupRoleMembersReply" << LL_ENDL; LLUUID agent_id; msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id ); if (gAgent.getID() != agent_id) { - llwarns << "Got group role members reply for another agent!" << llendl; + LL_WARNS() << "Got group role members reply for another agent!" << LL_ENDL; return; } @@ -1219,7 +1333,7 @@ void LLGroupMgr::processGroupRoleMembersReply(LLMessageSystem* msg, void** data) LLGroupMgrGroupData* group_datap = LLGroupMgr::getInstance()->getGroupData(group_id); if (!group_datap || (group_datap->mRoleMembersRequestID != request_id)) { - llwarns << "processGroupRoleMembersReply: Received incorrect (stale?) group or request id" << llendl; + LL_WARNS() << "processGroupRoleMembersReply: Received incorrect (stale?) group or request id" << LL_ENDL; return; } @@ -1259,14 +1373,14 @@ void LLGroupMgr::processGroupRoleMembersReply(LLMessageSystem* msg, void** data) if (rd && md) { - lldebugs << "Adding role-member pair: " << role_id << ", " << member_id << llendl; + LL_DEBUGS() << "Adding role-member pair: " << role_id << ", " << member_id << LL_ENDL; rd->addMember(member_id); md->addRole(role_id,rd); } else { - if (!rd) llwarns << "Received role data for unknown role " << role_id << " in group " << group_id << llendl; - if (!md) llwarns << "Received role data for unknown member " << member_id << " in group " << group_id << llendl; + if (!rd) LL_WARNS() << "Received role data for unknown role " << role_id << " in group " << group_id << LL_ENDL; + if (!md) LL_WARNS() << "Received role data for unknown member " << member_id << " in group " << group_id << LL_ENDL; } } } @@ -1280,7 +1394,7 @@ void LLGroupMgr::processGroupRoleMembersReply(LLMessageSystem* msg, void** data) LLGroupRoleData* everyone = group_datap->mRoles[LLUUID::null]; if (!everyone) { - llwarns << "Everyone role not found!" << llendl; + LL_WARNS() << "Everyone role not found!" << LL_ENDL; } else { @@ -1295,23 +1409,28 @@ void LLGroupMgr::processGroupRoleMembersReply(LLMessageSystem* msg, void** data) } } - group_datap->mRoleMemberDataComplete = TRUE; + group_datap->mRoleMemberDataComplete = true; group_datap->mRoleMembersRequestID.setNull(); } group_datap->mChanged = TRUE; LLGroupMgr::getInstance()->notifyObservers(GC_ROLE_MEMBER_DATA); + + if (group_datap->mPendingBanRequest) + { + group_datap->banMemberById(group_datap->mPendingBanMemberID); + } } // static void LLGroupMgr::processGroupTitlesReply(LLMessageSystem* msg, void** data) { - lldebugs << "LLGroupMgr::processGroupTitlesReply" << llendl; + LL_DEBUGS() << "LLGroupMgr::processGroupTitlesReply" << LL_ENDL; LLUUID agent_id; msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id ); if (gAgent.getID() != agent_id) { - llwarns << "Got group properties reply for another agent!" << llendl; + LL_WARNS() << "Got group properties reply for another agent!" << LL_ENDL; return; } @@ -1323,7 +1442,7 @@ void LLGroupMgr::processGroupTitlesReply(LLMessageSystem* msg, void** data) LLGroupMgrGroupData* group_datap = LLGroupMgr::getInstance()->getGroupData(group_id); if (!group_datap || (group_datap->mTitlesRequestID != request_id)) { - llwarns << "processGroupTitlesReply: Received incorrect (stale?) group" << llendl; + LL_WARNS() << "processGroupTitlesReply: Received incorrect (stale?) group" << LL_ENDL; return; } @@ -1339,7 +1458,7 @@ void LLGroupMgr::processGroupTitlesReply(LLMessageSystem* msg, void** data) if (!title.mTitle.empty()) { - lldebugs << "LLGroupMgr adding title: " << title.mTitle << ", " << title.mRoleID << ", " << (title.mSelected ? 'Y' : 'N') << llendl; + LL_DEBUGS() << "LLGroupMgr adding title: " << title.mTitle << ", " << title.mRoleID << ", " << (title.mSelected ? 'Y' : 'N') << LL_ENDL; group_datap->mTitles.push_back(title); } } @@ -1351,7 +1470,7 @@ void LLGroupMgr::processGroupTitlesReply(LLMessageSystem* msg, void** data) // static void LLGroupMgr::processEjectGroupMemberReply(LLMessageSystem* msg, void ** data) { - lldebugs << "processEjectGroupMemberReply" << llendl; + LL_DEBUGS() << "processEjectGroupMemberReply" << LL_ENDL; LLUUID group_id; msg->getUUIDFast(_PREHASH_GroupData, _PREHASH_GroupID, group_id); BOOL success; @@ -1367,7 +1486,7 @@ void LLGroupMgr::processEjectGroupMemberReply(LLMessageSystem* msg, void ** data // static void LLGroupMgr::processJoinGroupReply(LLMessageSystem* msg, void ** data) { - lldebugs << "processJoinGroupReply" << llendl; + LL_DEBUGS() << "processJoinGroupReply" << LL_ENDL; LLUUID group_id; BOOL success; msg->getUUIDFast(_PREHASH_GroupData, _PREHASH_GroupID, group_id); @@ -1389,7 +1508,7 @@ void LLGroupMgr::processJoinGroupReply(LLMessageSystem* msg, void ** data) // static void LLGroupMgr::processLeaveGroupReply(LLMessageSystem* msg, void ** data) { - lldebugs << "processLeaveGroupReply" << llendl; + LL_DEBUGS() << "processLeaveGroupReply" << LL_ENDL; LLUUID group_id; BOOL success; msg->getUUIDFast(_PREHASH_GroupData, _PREHASH_GroupID, group_id); @@ -1438,12 +1557,13 @@ void LLGroupMgr::processCreateGroupReply(LLMessageSystem* msg, void ** data) gAgent.mGroups.push_back(gd); - LLGroupActions::closeGroup(LLUUID::null); + if (LLFloaterGroupInfo* flooter = LLFloaterGroupInfo::getInstance(LLUUID::null)) + flooter->onClose(false); LLGroupActions::showTab(group_id, "roles_tab"); } else { - // *TODO:translate + // *TODO: Translate LLSD args; args["MESSAGE"] = message; LLNotificationsUtil::add("UnableToCreateGroup", args); @@ -1551,7 +1671,7 @@ void LLGroupMgr::addGroup(LLGroupMgrGroupData* group_datap) void LLGroupMgr::sendGroupPropertiesRequest(const LLUUID& group_id) { - lldebugs << "LLGroupMgr::sendGroupPropertiesRequest" << llendl; + LL_DEBUGS() << "LLGroupMgr::sendGroupPropertiesRequest" << LL_ENDL; // This will happen when we get the reply //LLGroupMgrGroupData* group_datap = createGroupData(group_id); @@ -1567,7 +1687,7 @@ void LLGroupMgr::sendGroupPropertiesRequest(const LLUUID& group_id) void LLGroupMgr::sendGroupMembersRequest(const LLUUID& group_id) { - lldebugs << "LLGroupMgr::sendGroupMembersRequest" << llendl; + LL_DEBUGS() << "LLGroupMgr::sendGroupMembersRequest" << LL_ENDL; LLGroupMgrGroupData* group_datap = createGroupData(group_id); if (group_datap->mMemberRequestID.isNull()) { @@ -1586,9 +1706,10 @@ void LLGroupMgr::sendGroupMembersRequest(const LLUUID& group_id) } } + void LLGroupMgr::sendGroupRoleDataRequest(const LLUUID& group_id) { - lldebugs << "LLGroupMgr::sendGroupRoleDataRequest" << llendl; + LL_DEBUGS() << "LLGroupMgr::sendGroupRoleDataRequest" << LL_ENDL; LLGroupMgrGroupData* group_datap = createGroupData(group_id); if (group_datap->mRoleDataRequestID.isNull()) { @@ -1609,7 +1730,7 @@ void LLGroupMgr::sendGroupRoleDataRequest(const LLUUID& group_id) void LLGroupMgr::sendGroupRoleMembersRequest(const LLUUID& group_id) { - lldebugs << "LLGroupMgr::sendGroupRoleMembersRequest" << llendl; + LL_DEBUGS() << "LLGroupMgr::sendGroupRoleMembersRequest" << LL_ENDL; LLGroupMgrGroupData* group_datap = createGroupData(group_id); if (group_datap->mRoleMembersRequestID.isNull()) @@ -1619,9 +1740,9 @@ void LLGroupMgr::sendGroupRoleMembersRequest(const LLUUID& group_id) || !group_datap->isRoleDataComplete()) { // *TODO: KLW FIXME: Should we start a member or role data request? - llinfos << " Pending: " << (group_datap->mPendingRoleMemberRequest ? "Y" : "N") + LL_INFOS() << " Pending: " << (group_datap->mPendingRoleMemberRequest ? "Y" : "N") << " MemberDataComplete: " << (group_datap->mMemberDataComplete ? "Y" : "N") - << " RoleDataComplete: " << (group_datap->mRoleDataComplete ? "Y" : "N") << llendl; + << " RoleDataComplete: " << (group_datap->mRoleDataComplete ? "Y" : "N") << LL_ENDL; group_datap->mPendingRoleMemberRequest = TRUE; return; } @@ -1643,7 +1764,7 @@ void LLGroupMgr::sendGroupRoleMembersRequest(const LLUUID& group_id) void LLGroupMgr::sendGroupTitlesRequest(const LLUUID& group_id) { - lldebugs << "LLGroupMgr::sendGroupTitlesRequest" << llendl; + LL_DEBUGS() << "LLGroupMgr::sendGroupTitlesRequest" << LL_ENDL; LLGroupMgrGroupData* group_datap = createGroupData(group_id); group_datap->mTitles.clear(); @@ -1662,7 +1783,7 @@ void LLGroupMgr::sendGroupTitlesRequest(const LLUUID& group_id) void LLGroupMgr::sendGroupTitleUpdate(const LLUUID& group_id, const LLUUID& title_role_id) { - lldebugs << "LLGroupMgr::sendGroupTitleUpdate" << llendl; + LL_DEBUGS() << "LLGroupMgr::sendGroupTitleUpdate" << LL_ENDL; LLMessageSystem* msg = gMessageSystem; msg->newMessage("GroupTitleUpdate"); @@ -1721,7 +1842,7 @@ void LLGroupMgr::sendCreateGroupRequest(const std::string& name, void LLGroupMgr::sendUpdateGroupInfo(const LLUUID& group_id) { - lldebugs << "LLGroupMgr::sendUpdateGroupInfo" << llendl; + LL_DEBUGS() << "LLGroupMgr::sendUpdateGroupInfo" << LL_ENDL; LLGroupMgrGroupData* group_datap = createGroupData(group_id); LLMessageSystem* msg = gMessageSystem; @@ -1750,7 +1871,7 @@ void LLGroupMgr::sendUpdateGroupInfo(const LLUUID& group_id) void LLGroupMgr::sendGroupRoleMemberChanges(const LLUUID& group_id) { - lldebugs << "LLGroupMgr::sendGroupRoleMemberChanges" << llendl; + LL_DEBUGS() << "LLGroupMgr::sendGroupRoleMemberChanges" << LL_ENDL; LLGroupMgrGroupData* group_datap = createGroupData(group_id); if (group_datap->mRoleMemberChanges.empty()) return; @@ -1854,8 +1975,6 @@ void LLGroupMgr::sendGroupMemberEjects(const LLUUID& group_id, bool start_message = true; LLMessageSystem* msg = gMessageSystem; - - LLGroupMgrGroupData* group_datap = LLGroupMgr::getInstance()->getGroupData(group_id); if (!group_datap) return; @@ -1921,30 +2040,170 @@ void LLGroupMgr::sendGroupMemberEjects(const LLUUID& group_id, } -class AIHTTPTimeoutPolicy; -extern AIHTTPTimeoutPolicy groupMemberDataResponder_timeout; +// Responder class for capability group management +class GroupBanDataResponder : public LLHTTPClient::ResponderWithResult +{ +public: + GroupBanDataResponder(const LLUUID& gropup_id, BOOL force_refresh=false); + virtual ~GroupBanDataResponder() {} + virtual void httpSuccess(); + virtual void httpFailure(); + virtual char const* getName() const { return "GroupBanDataResponder"; } +private: + LLUUID mGroupID; + BOOL mForceRefresh; +}; + +GroupBanDataResponder::GroupBanDataResponder(const LLUUID& gropup_id, BOOL force_refresh) : + mGroupID(gropup_id), + mForceRefresh(force_refresh) +{} + +void GroupBanDataResponder::httpFailure() +{ + LL_WARNS("GrpMgr") << "Error receiving group member data [status:" + << mStatus << "]: " << mContent << LL_ENDL; +} + +void GroupBanDataResponder::httpSuccess() +{ + if (mContent.has("ban_list")) + { + // group ban data received + LLGroupMgr::processGroupBanRequest(mContent); + } + else if (mForceRefresh) + { + // no ban data received, refreshing data after successful operation + LLGroupMgr::getInstance()->sendGroupBanRequest(LLGroupMgr::REQUEST_GET, mGroupID); + } +} + +void LLGroupMgr::sendGroupBanRequest( EBanRequestType request_type, + const LLUUID& group_id, + U32 ban_action, /* = BAN_NO_ACTION */ + const uuid_vec_t& ban_list) /* = uuid_vec_t() */ +{ + LLViewerRegion* currentRegion = gAgent.getRegion(); + if (!currentRegion) + { + LL_WARNS("GrpMgr") << "Agent does not have a current region. Uh-oh!" << LL_ENDL; + return; + } + + // Check to make sure we have our capabilities + if (!currentRegion->capabilitiesReceived()) + { + LL_WARNS("GrpMgr") << " Capabilities not received!" << LL_ENDL; + return; + } + + // Get our capability + std::string cap_url = currentRegion->getCapability("GroupAPIv1"); + if (cap_url.empty()) + { + return; + } + cap_url += "?group_id=" + group_id.asString(); + + LLSD body = LLSD::emptyMap(); + body["ban_action"] = (LLSD::Integer)(ban_action & ~BAN_UPDATE); + // Add our list of potential banned residents to the list + body["ban_ids"] = LLSD::emptyArray(); + LLSD ban_entry; + + uuid_vec_t::const_iterator iter = ban_list.begin(); + for(;iter != ban_list.end(); ++iter) + { + ban_entry = (*iter); + body["ban_ids"].append(ban_entry); + } + + LLHTTPClient::ResponderPtr grp_ban_responder = new GroupBanDataResponder(group_id, ban_action & BAN_UPDATE); + switch(request_type) + { + case REQUEST_GET: + LLHTTPClient::get(cap_url, grp_ban_responder); + break; + case REQUEST_POST: + LLHTTPClient::post(cap_url, body, grp_ban_responder); + break; + case REQUEST_PUT: + case REQUEST_DEL: + break; + } +} + + +void LLGroupMgr::processGroupBanRequest(const LLSD& content) +{ + // Did we get anything in content? + if (!content.size()) + { + LL_WARNS("GrpMgr") << "No group member data received." << LL_ENDL; + return; + } + + LLUUID group_id = content["group_id"].asUUID(); + + LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(group_id); + if (!gdatap) + return; + + gdatap->clearBanList(); + LLSD::map_const_iterator i = content["ban_list"].beginMap(); + LLSD::map_const_iterator iEnd = content["ban_list"].endMap(); + for(;i != iEnd; ++i) + { + const LLUUID ban_id(i->first); + LLSD ban_entry(i->second); + + LLGroupBanData ban_data; + if (ban_entry.has("ban_date")) + { + ban_data.mBanDate = ban_entry["ban_date"].asDate(); + // TODO: Ban Reason + } + + gdatap->createBanEntry(ban_id, ban_data); + } + + gdatap->mChanged = TRUE; + LLGroupMgr::getInstance()->notifyObservers(GC_BANLIST); +} + + // Responder class for capability group management class GroupMemberDataResponder : public LLHTTPClient::ResponderWithResult { + LOG_CLASS(GroupMemberDataResponder); public: GroupMemberDataResponder() {} virtual ~GroupMemberDataResponder() {} - /*virtual*/ void result(const LLSD& pContent); - /*virtual*/ void error(U32 pStatus, const std::string& pReason); - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return groupMemberDataResponder_timeout; } - /*virtual*/ char const* getName(void) const { return "GroupMemberDataResponder"; } + private: + /* virtual */ void httpSuccess(); + /* virtual */ void httpFailure(); + /* virtual */ char const* getName() const { return "GroupMemberDataResponder"; } + LLSD mMemberData; }; -void GroupMemberDataResponder::error(U32 pStatus, const std::string& pReason) +void GroupMemberDataResponder::httpFailure() { - LL_WARNS("GrpMgr") << "Error receiving group member data." << LL_ENDL; + LL_WARNS("GrpMgr") << "Error receiving group member data " + << dumpResponse() << LL_ENDL; } -void GroupMemberDataResponder::result(const LLSD& content) +void GroupMemberDataResponder::httpSuccess() { + const LLSD& content = getContent(); + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR_OTHER, "Malformed response contents", content); + return; + } LLGroupMgr::processCapGroupMembersRequest(content); } @@ -1994,6 +2253,7 @@ void LLGroupMgr::sendCapGroupMembersRequest(const LLUUID& group_id) mLastGroupMembersRequestFrame = gFrameCount; } + // static void LLGroupMgr::processCapGroupMembersRequest(const LLSD& content) { @@ -2004,11 +2264,6 @@ void LLGroupMgr::processCapGroupMembersRequest(const LLSD& content) return; } - // If we have no members, there's no reason to do anything else - S32 num_members = content["member_count"]; - if (num_members < 1) - return; - LLUUID group_id = content["group_id"].asUUID(); LLGroupMgrGroupData* group_datap = LLGroupMgr::getInstance()->getGroupData(group_id); @@ -2018,6 +2273,18 @@ void LLGroupMgr::processCapGroupMembersRequest(const LLSD& content) return; } + // If we have no members, there's no reason to do anything else + S32 num_members = content["member_count"]; + if (num_members < 1) + { + LL_INFOS("GrpMgr") << "Received empty group members list for group id: " << group_id.asString() << LL_ENDL; + // Set mMemberDataComplete for correct handling of empty responses. See MAINT-5237 + group_datap->mMemberDataComplete = true; + group_datap->mChanged = TRUE; + LLGroupMgr::getInstance()->notifyObservers(GC_MEMBER_DATA); + return; + } + group_datap->mMemberCount = num_members; LLSD member_list = content["members"]; @@ -2039,7 +2306,7 @@ void LLGroupMgr::processCapGroupMembersRequest(const LLSD& content) for ( ; member_iter_start != member_iter_end; ++member_iter_start) { // Reset defaults - online_status = "unknown"; + online_status = localized_unknown(); title = titles[0].asString(); contribution = 0; member_powers = default_powers; @@ -2052,7 +2319,9 @@ void LLGroupMgr::processCapGroupMembersRequest(const LLSD& content) { online_status = member_info["last_login"].asString(); if (online_status == "Online") - online_status = LLTrans::getString("group_member_status_online"); + online_status = localized_online(); + else if (online_status == "unknown") + online_status = localized_unknown(); else formatDateString(online_status); } @@ -2076,6 +2345,22 @@ void LLGroupMgr::processCapGroupMembersRequest(const LLSD& content) online_status, is_owner); + LLGroupMemberData* member_old = group_datap->mMembers[member_id]; + if (member_old && group_datap->mRoleMemberDataComplete) + { + LLGroupMemberData::role_list_t::iterator rit = member_old->roleBegin(); + LLGroupMemberData::role_list_t::iterator end = member_old->roleEnd(); + + for ( ; rit != end; ++rit) + { + data->addRole((*rit).first, (*rit).second); + } + } + else + { + group_datap->mRoleMemberDataComplete = false; + } + group_datap->mMembers[member_id] = data; } @@ -2086,26 +2371,30 @@ void LLGroupMgr::processCapGroupMembersRequest(const LLSD& content) // I'm going to be dumb and just call services I most likely don't need // with the thought being that the system might need it to be done. // - // TODO: Refactor to reduce multiple calls for data we already have. + // TODO: + // Refactor to reduce multiple calls for data we already have. if (group_datap->mTitles.size() < 1) LLGroupMgr::getInstance()->sendGroupTitlesRequest(group_id); - group_datap->mMemberDataComplete = TRUE; + + group_datap->mMemberDataComplete = true; group_datap->mMemberRequestID.setNull(); // Make the role-member data request - if (group_datap->mPendingRoleMemberRequest) + if (group_datap->mPendingRoleMemberRequest || !group_datap->mRoleMemberDataComplete) { - group_datap->mPendingRoleMemberRequest = FALSE; + group_datap->mPendingRoleMemberRequest = false; LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(group_id); } group_datap->mChanged = TRUE; LLGroupMgr::getInstance()->notifyObservers(GC_MEMBER_DATA); + } + void LLGroupMgr::sendGroupRoleChanges(const LLUUID& group_id) { - lldebugs << "LLGroupMgr::sendGroupRoleChanges" << llendl; + LL_DEBUGS() << "LLGroupMgr::sendGroupRoleChanges" << LL_ENDL; LLGroupMgrGroupData* group_datap = getGroupData(group_id); if (group_datap && group_datap->pendingRoleChanges()) @@ -2120,7 +2409,7 @@ void LLGroupMgr::sendGroupRoleChanges(const LLUUID& group_id) void LLGroupMgr::cancelGroupRoleChanges(const LLUUID& group_id) { - lldebugs << "LLGroupMgr::cancelGroupRoleChanges" << llendl; + LL_DEBUGS() << "LLGroupMgr::cancelGroupRoleChanges" << LL_ENDL; LLGroupMgrGroupData* group_datap = getGroupData(group_id); if (group_datap) group_datap->cancelRoleChanges(); @@ -2135,7 +2424,7 @@ bool LLGroupMgr::parseRoleActions(const std::string& xml_filename) if (!success || !root || !root->hasName( "role_actions" )) { - llerrs << "Problem reading UI role_actions file: " << xml_filename << llendl; + LL_ERRS() << "Problem reading UI role_actions file: " << xml_filename << LL_ENDL; return false; } @@ -2154,12 +2443,12 @@ bool LLGroupMgr::parseRoleActions(const std::string& xml_filename) std::string action_set_name; if (action_set->getAttributeString("name", action_set_name)) { - lldebugs << "Loading action set " << action_set_name << llendl; + LL_DEBUGS() << "Loading action set " << action_set_name << LL_ENDL; role_action_data->mName = action_set_name; } else { - llwarns << "Unable to parse action set with no name" << llendl; + LL_WARNS() << "Unable to parse action set with no name" << LL_ENDL; delete role_action_set; delete role_action_data; continue; @@ -2195,12 +2484,12 @@ bool LLGroupMgr::parseRoleActions(const std::string& xml_filename) std::string action_name; if (action->getAttributeString("name", action_name)) { - lldebugs << "Loading action " << action_name << llendl; + LL_DEBUGS() << "Loading action " << action_name << LL_ENDL; role_action->mName = action_name; } else { - llwarns << "Unable to parse action with no name" << llendl; + LL_WARNS() << "Unable to parse action with no name" << LL_ENDL; delete role_action; continue; } diff --git a/indra/newview/llgroupmgr.h b/indra/newview/llgroupmgr.h index 5a40d3a2ef..73a8546249 100644 --- a/indra/newview/llgroupmgr.h +++ b/indra/newview/llgroupmgr.h @@ -33,7 +33,23 @@ #include #include +// Forward Declarations class LLMessageSystem; +class LLGroupRoleData; +class LLGroupMgr; + +enum LLGroupChange +{ + GC_PROPERTIES, + GC_MEMBER_DATA, + GC_ROLE_DATA, + GC_ROLE_MEMBER_DATA, + GC_TITLES, + GC_BANLIST, + GC_ALL +}; + +const U32 GB_MAX_BANNED_AGENTS = 500; class LLGroupMgrObserver { @@ -54,8 +70,6 @@ class LLParticularGroupObserver virtual void changed(const LLUUID& group_id, LLGroupChange gc) = 0; }; -class LLGroupRoleData; - class LLGroupMemberData { friend class LLGroupMgrGroupData; @@ -134,8 +148,8 @@ friend class LLGroupMgrGroupData; const LLUUID& getID() const { return mRoleID; } const uuid_vec_t& getRoleMembers() const { return mMemberIDs; } - S32 getMembersInRole(uuid_vec_t members, BOOL needs_sort = TRUE); - S32 getTotalMembersInRole() { return mMemberIDs.size(); } + S32 getMembersInRole(uuid_vec_t& members, BOOL needs_sort = TRUE); + S32 getTotalMembersInRole() { return mMemberCount ? mMemberCount : mMemberIDs.size(); } //FIXME: Returns 0 for Everyone role when Member list isn't yet loaded, see MAINT-5225 LLRoleData getRoleData() const { return mRoleData; } void setRoleData(LLRoleData data) { mRoleData = data; } @@ -190,6 +204,17 @@ struct lluuid_pair_less } }; + +struct LLGroupBanData +{ + LLGroupBanData() : mBanDate() {} + ~LLGroupBanData() {} + + LLDate mBanDate; + // TODO: std::string ban_reason; +}; + + struct LLGroupTitle { std::string mTitle; @@ -197,8 +222,6 @@ struct LLGroupTitle BOOL mSelected; }; -class LLGroupMgr; - class LLGroupMgrGroupData { friend class LLGroupMgr; @@ -228,26 +251,38 @@ friend class LLGroupMgr; void recalcAllAgentPowers(); void recalcAgentPowers(const LLUUID& agent_id); - BOOL isMemberDataComplete() { return mMemberDataComplete; } - BOOL isRoleDataComplete() { return mRoleDataComplete; } - BOOL isRoleMemberDataComplete() { return mRoleMemberDataComplete; } - BOOL isGroupPropertiesDataComplete() { return mGroupPropertiesDataComplete; } + bool isMemberDataComplete() { return mMemberDataComplete; } + bool isRoleDataComplete() { return mRoleDataComplete; } + bool isRoleMemberDataComplete() { return mRoleMemberDataComplete; } + bool isGroupPropertiesDataComplete() { return mGroupPropertiesDataComplete; } + + bool isSingleMemberNotOwner(); F32 getAccessTime() const { return mAccessTime; } void setAccessed(); const LLUUID& getMemberVersion() const { return mMemberVersion; } + + void clearBanList() { mBanList.clear(); } + void getBanList(const LLUUID& group_id, LLGroupBanData& ban_data); + const LLGroupBanData& getBanEntry(const LLUUID& ban_id) { return mBanList[ban_id]; } + + void createBanEntry(const LLUUID& ban_id, const LLGroupBanData& ban_data = LLGroupBanData()); + void removeBanEntry(const LLUUID& ban_id); + void banMemberById(const LLUUID& participant_uuid); + public: typedef std::map member_list_t; typedef std::map role_list_t; typedef std::map change_map_t; typedef std::map role_data_map_t; + typedef std::map ban_list_t; + member_list_t mMembers; role_list_t mRoles; - - change_map_t mRoleMemberChanges; role_data_map_t mRoleChanges; + ban_list_t mBanList; std::vector mTitles; @@ -266,6 +301,9 @@ friend class LLGroupMgr; S32 mMemberCount; S32 mRoleCount; + bool mPendingBanRequest; + LLUUID mPendingBanMemberID; + protected: void sendRoleChanges(); void cancelRoleChanges(); @@ -277,12 +315,12 @@ friend class LLGroupMgr; LLUUID mTitlesRequestID; U32 mReceivedRoleMemberPairs; - BOOL mMemberDataComplete; - BOOL mRoleDataComplete; - BOOL mRoleMemberDataComplete; - BOOL mGroupPropertiesDataComplete; + bool mMemberDataComplete; + bool mRoleDataComplete; + bool mRoleMemberDataComplete; + bool mGroupPropertiesDataComplete; - BOOL mPendingRoleMemberRequest; + bool mPendingRoleMemberRequest; F32 mAccessTime; // Generate a new ID every time mMembers @@ -309,6 +347,23 @@ class LLGroupMgr : public LLSingleton { LOG_CLASS(LLGroupMgr); +public: + enum EBanRequestType + { + REQUEST_GET = 0, + REQUEST_POST, + REQUEST_PUT, + REQUEST_DEL + }; + + enum EBanRequestAction + { + BAN_NO_ACTION = 0, + BAN_CREATE = 1, + BAN_DELETE = 2, + BAN_UPDATE = 4 + }; + public: LLGroupMgr(); ~LLGroupMgr(); @@ -343,6 +398,13 @@ class LLGroupMgr : public LLSingleton static void sendGroupMemberEjects(const LLUUID& group_id, uuid_vec_t& member_ids); + static void sendGroupBanRequest(EBanRequestType request_type, + const LLUUID& group_id, + U32 ban_action = BAN_NO_ACTION, + const uuid_vec_t& ban_list = uuid_vec_t()); + + static void processGroupBanRequest(const LLSD& content); + void sendCapGroupMembersRequest(const LLUUID& group_id); static void processCapGroupMembersRequest(const LLSD& content); @@ -387,4 +449,3 @@ class LLGroupMgr : public LLSingleton #endif - diff --git a/indra/newview/llgroupnotify.cpp b/indra/newview/llgroupnotify.cpp index ca9c834f8b..c1af61a3c3 100644 --- a/indra/newview/llgroupnotify.cpp +++ b/indra/newview/llgroupnotify.cpp @@ -36,6 +36,7 @@ #include "llfocusmgr.h" +#include "llavataractions.h" #include "llbutton.h" #include "lliconctrl.h" #include "llfloaterchat.h" // for add_chat_history() @@ -53,11 +54,9 @@ #include "llglheaders.h" #include "llagent.h" // Globals -//LLView* gGroupNotifyBoxView = NULL; - const F32 ANIMATION_TIME = 0.333f; -S32 LLGroupNotifyBox::sGroupNotifyBoxCount = 0; +static S32 sGroupNotifyBoxCount = 0; //--------------------------------------------------------------------------- @@ -90,21 +89,21 @@ LLGroupNotifyBox::LLGroupNotifyBox(const std::string& subject, const std::string& inventory_name, const LLSD& inventory_offer) : LLPanel("groupnotify", LLGroupNotifyBox::getGroupNotifyRect(), BORDER_YES), - mAnimating(TRUE), + mAnimating(true), mTimer(), mGroupID(group_id), mHasInventory(has_inventory), mInventoryOffer(NULL) { - const S32 VPAD = 2; - const S32 TOP = getRect().getHeight() - 32; // Get past the top menu bar - const S32 BOTTOM_PAD = VPAD * 2; - const S32 BTN_TOP = BOTTOM_PAD + BTN_HEIGHT + VPAD; - const S32 RIGHT = getRect().getWidth() - HPAD - HPAD; - const S32 LINE_HEIGHT = 16; + constexpr S32 PAD = 2; + const S32 TOP = getRect().getHeight() - 28; // Get past the top menu bar + const S32 BOTTOM_PAD = PAD * 2; + const S32 BTN_TOP = BOTTOM_PAD + BTN_HEIGHT + PAD; + const S32 RIGHT = getRect().getWidth() - HPAD; + constexpr S32 LINE_HEIGHT = 16; - const S32 LABEL_WIDTH = 64; - const S32 ICON_WIDTH = 64; + constexpr S32 LABEL_WIDTH = 64; + constexpr S32 ICON_WIDTH = 64; time_t timestamp = (time_t)time_stamp.secondsSinceEpoch(); if (!timestamp) time(×tamp); @@ -123,84 +122,76 @@ LLGroupNotifyBox::LLGroupNotifyBox(const std::string& subject, setBackgroundOpaque(TRUE); setBackgroundColor( gColors.getColor("GroupNotifyBoxColor") ); - LLIconCtrl* icon; - LLTextEditor* text; - S32 y = TOP; - S32 x = HPAD + HPAD; + S32 x = ICON_WIDTH + HPAD + PAD; + static const auto text_color = gColors.getColor("GroupNotifyTextColor"); class NoticeText : public LLTextBox { public: - NoticeText(const std::string& name, const LLRect& rect, const std::string& text = LLStringUtil::null, const LLFontGL* font = NULL) + NoticeText(const std::string& name, const LLRect& rect, const std::string& text = LLStringUtil::null, const LLFontGL* font = NULL) : LLTextBox(name, rect, text, font) { setHAlign(LLFontGL::RIGHT); setFontShadow(LLFontGL::DROP_SHADOW_SOFT); setBorderVisible(FALSE); - setColor( gColors.getColor("GroupNotifyTextColor") ); - setBackgroundColor( gColors.getColor("GroupNotifyBoxColor") ); + setColor(text_color); + setBackgroundColor(LLColor4::transparent); } }; - // Title - addChild(new NoticeText(std::string("title"),LLRect(x,y,RIGHT - HPAD,y - LINE_HEIGHT),LLTrans::getString("GroupNotifyGroupNotice"),LLFontGL::getFontSansSerifHuge())); + static LLStyleSP headerstyle = nullptr; + if (!headerstyle) + { + headerstyle = new LLStyle(true, text_color, LLStringUtil::null); + headerstyle->mBold = true; + } + const auto bottom = y - ICON_WIDTH; - y -= llfloor(1.5f*LINE_HEIGHT); + auto links = new LLTextEditor(std::string("group"), LLRect(x, y + 5, RIGHT, bottom), S32_MAX, LLStringUtil::null, nullptr, false, true); // Top adjustment to line up with icon + links->setBorderVisible(FALSE); + static const auto header_bg_color = gColors.getColor("GroupNotifyHeaderBGColor"); + if (header_bg_color[VALPHA]) links->setReadOnlyFgColor(text_color); + links->setReadOnlyBgColor(header_bg_color); + links->setEnabled(false); + links->setTakesNonScrollClicks(TRUE); + links->setHideScrollbarForShortDocs(TRUE); + links->setWordWrap(TRUE); - x += HPAD + HPAD + ICON_WIDTH; + links->appendText(subject, false, false, headerstyle, false); // This is from a user, do not force replace. + links->appendText(time_buf, false, true, nullptr, true); + links->appendText(LLTrans::getString("GroupNotifyBy", LLSD().with("NAME", from_name).with("GROUP", group_name)), false, true, nullptr, true); + addChild(links); - std::stringstream from; - from << LLTrans::getString("GroupNotifySentBy") << " " + from_name << LLTrans::getString(",") + " " << group_name; + x = HPAD; - addChild(new NoticeText(std::string("group"),LLRect(x,y,RIGHT - HPAD,y - LINE_HEIGHT),from.str(),LLFontGL::getFontSansSerif())); - - y -= (LINE_HEIGHT + VPAD); - x = HPAD + HPAD; - - // TODO: change this to be the group icon. - if (!group_insignia.isNull()) - { - icon = new LLIconCtrl(std::string("icon"), - LLRect(x, y, x+ICON_WIDTH, y-ICON_WIDTH), - group_insignia); - } - else - { - icon = new LLIconCtrl(std::string("icon"), - LLRect(x, y, x+ICON_WIDTH, y-ICON_WIDTH), - std::string("notify_box_icon.tga")); - } + LLIconCtrl* icon = new LLIconCtrl(std::string("icon"), + LLRect(x, y, x+ICON_WIDTH, bottom), + group_insignia.isNull() ? "icon_groupnotice.tga" : group_insignia.asString()); icon->setMouseOpaque(FALSE); addChild(icon); - x += HPAD + HPAD + ICON_WIDTH; + y = bottom - PAD*2; + // If we have inventory with this message, leave room for the name. - S32 box_bottom = BTN_TOP + (mHasInventory ? (LINE_HEIGHT + 2*VPAD) : 0); + S32 box_bottom = BTN_TOP + (mHasInventory ? (LINE_HEIGHT + 2*PAD) : 0); - text = new LLViewerTextEditor(std::string("box"), + LLTextEditor* text = new LLViewerTextEditor(std::string("box"), LLRect(x, y, RIGHT, box_bottom), DB_GROUP_NOTICE_MSG_STR_LEN, LLStringUtil::null, LLFontGL::getFontSansSerif(), - FALSE); + FALSE, + true); + text->setBorderVisible(false); - static const LLStyleSP headerstyle(new LLStyle(true,LLColor4::black,"SansSerifBig")); - static const LLStyleSP datestyle(new LLStyle(true,LLColor4::black,"serif")); + static const LLStyleSP msgstyle(new LLStyle(true, LLColor4::grey4, LLStringUtil::null)); - text->appendStyledText(subject + "\n",false,false,headerstyle); - - text->appendStyledText(time_buf,false,false,datestyle); - // Sadly, our LLTextEditor can't handle both styled and unstyled text - // at the same time. Hence this space must be styled. JC - text->appendColoredText(std::string(" "),false,false,LLColor4::grey4); - text->setParseHTML(TRUE); - text->appendColoredText(std::string("\n\n") + message,false,false,LLColor4::grey4); + text->appendText(message, false, false, msgstyle, false); LLColor4 semi_transparent(1.0f,1.0f,1.0f,0.8f); text->setCursor(0,0); - text->setEnabled(FALSE); text->setWordWrap(TRUE); //text->setTabStop(FALSE); // was interfering with copy-and-paste text->setTabsToNextField(TRUE); @@ -213,67 +204,63 @@ LLGroupNotifyBox::LLGroupNotifyBox(const std::string& subject, addChild(text); - y = box_bottom - VPAD; + y = box_bottom - PAD; if (mHasInventory) { - addChild(new NoticeText(std::string("subjecttitle"),LLRect(x,y,x + LABEL_WIDTH,y - LINE_HEIGHT),LLTrans::getString("GroupNotifyAttached"),LLFontGL::getFontSansSerif())); - - LLUIImagePtr item_icon = LLInventoryIcon::getIcon(mInventoryOffer->mType, - LLInventoryType::IT_TEXTURE, - 0, FALSE); - - - x += LABEL_WIDTH + HPAD; - - std::stringstream ss; - ss << " " << inventory_name; - LLTextBox *line = new LLTextBox(std::string("object_name"),LLRect(x,y,RIGHT - HPAD,y - LINE_HEIGHT),ss.str(),LLFontGL::getFontSansSerif()); - line->setEnabled(FALSE); - line->setBorderVisible(TRUE); - line->setDisabledColor(LLColor4::blue4); - line->setFontStyle(LLFontGL::NORMAL); - line->setBackgroundVisible(true); - line->setBackgroundColor( semi_transparent ); - addChild(line); - - icon = new LLIconCtrl(std::string("icon"), - LLRect(x, y, x+16, y-16), - item_icon->getName()); - icon->setMouseOpaque(FALSE); - addChild(icon); + addChild(new NoticeText(std::string("subjecttitle"), LLRect(x,y,x + LABEL_WIDTH,y - LINE_HEIGHT), LLTrans::getString("GroupNotifyAttached") + ' ', LLFontGL::getFontSansSerif())); + + LLUIImagePtr item_icon = LLInventoryIcon::getIcon(mInventoryOffer->mType, + LLInventoryType::IT_TEXTURE, + 0, FALSE); + + x += LABEL_WIDTH + HPAD; + + std::stringstream ss; + ss << " " << inventory_name; + LLTextBox *line = new LLTextBox(std::string("object_name"),LLRect(x,y,RIGHT - HPAD,y - LINE_HEIGHT),ss.str(),LLFontGL::getFontSansSerif()); + line->setEnabled(FALSE); + line->setBorderVisible(TRUE); + line->setDisabledColor(LLColor4::blue4); + line->setFontStyle(LLFontGL::NORMAL); + line->setBackgroundVisible(true); + line->setBackgroundColor( semi_transparent ); + addChild(line); + + icon = new LLIconCtrl(std::string("icon"), + LLRect(x, y, x+16, y-16), + item_icon->getName()); + icon->setMouseOpaque(FALSE); + addChild(icon); } - LLButton* btn; - btn = new LLButton(LLTrans::getString("next"), + mNextBtn = new LLButton(LLTrans::getString("next"), LLRect(getRect().getWidth()-26, BOTTOM_PAD + 20, getRect().getWidth()-2, BOTTOM_PAD), std::string("notify_next.png"), std::string("notify_next.png"), LLStringUtil::null, - boost::bind(&LLGroupNotifyBox::onClickNext, this), + boost::bind(&LLGroupNotifyBox::moveToBack, this), LLFontGL::getFontSansSerif()); - btn->setToolTip(LLTrans::getString("next")); - btn->setScaleImage(TRUE); - addChild(btn); - mNextBtn = btn; + mNextBtn->setToolTip(LLTrans::getString("next")); + mNextBtn->setScaleImage(TRUE); + addChild(mNextBtn); S32 btn_width = 80; - S32 wide_btn_width = 120; + S32 wide_btn_width = 136; LLRect btn_rect; - x = 3 * HPAD; + x = 2 * HPAD; btn_rect.setOriginAndSize(x, BOTTOM_PAD, btn_width, BTN_HEIGHT); - btn = new LLButton(LLTrans::getString("ok"), btn_rect, LLStringUtil::null, boost::bind(&LLGroupNotifyBox::onClickOk,this)); + LLButton* btn = new LLButton(LLTrans::getString("ok"), btn_rect, LLStringUtil::null, boost::bind(&LLGroupNotifyBox::close, this)); addChild(btn, -1); setDefaultBtn(btn); x += btn_width + HPAD; - btn_rect.setOriginAndSize(x, BOTTOM_PAD, wide_btn_width, @@ -292,27 +279,14 @@ LLGroupNotifyBox::LLGroupNotifyBox(const std::string& subject, wide_btn_width, BTN_HEIGHT); - std::string btn_lbl(""); - if(is_openable(mInventoryOffer->mType)) - { - btn_lbl = LLTrans::getString("GroupNotifyOpenAttachment"); - } - else - { - btn_lbl = LLTrans::getString("GroupNotifySaveAttachment"); - } - mSaveInventoryBtn = new LLButton(btn_lbl, btn_rect, LLStringUtil::null, boost::bind(&LLGroupNotifyBox::onClickSaveInventory,this)); + mSaveInventoryBtn = new LLButton(LLTrans::getString(is_openable(mInventoryOffer->mType) ? "GroupNotifyOpenAttachment" : "GroupNotifySaveAttachment"), btn_rect, LLStringUtil::null, boost::bind(&LLGroupNotifyBox::onClickSaveInventory,this)); mSaveInventoryBtn->setVisible(mHasInventory); addChild(mSaveInventoryBtn); } - sGroupNotifyBoxCount++; - // If this is the only notify box, don't show the next button - if (sGroupNotifyBoxCount == 1) - { - mNextBtn->setVisible(FALSE); - } + if (++sGroupNotifyBoxCount == 1) + mNextBtn->setVisible(false); } @@ -325,7 +299,8 @@ LLGroupNotifyBox::~LLGroupNotifyBox() // virtual BOOL LLGroupNotifyBox::handleRightMouseDown(S32 x, S32 y, MASK mask) { - moveToBack(); + if (!LLPanel::handleRightMouseDown(x, y, mask)) + moveToBack(); return TRUE; } @@ -352,7 +327,7 @@ void LLGroupNotifyBox::draw() } else { - mAnimating = FALSE; + mAnimating = false; LLPanel::draw(); } } @@ -363,11 +338,11 @@ void LLGroupNotifyBox::close() // The group notice dialog may be an inventory offer. // If it has an inventory save button and that button is still enabled // Then we need to send the inventory declined message - if(mHasInventory) + if (mHasInventory) { mInventoryOffer->forceResponse(IOR_DECLINE); mInventoryOffer = NULL; - mHasInventory = FALSE; + mHasInventory = false; } gNotifyBoxView->removeChild(this); @@ -384,31 +359,27 @@ void LLGroupNotifyBox::initClass() //static bool LLGroupNotifyBox::onNewNotification(const LLSD& notify) { - LLNotificationPtr notification = LLNotifications::instance().find(notify["id"].asUUID()); - - if (notification) + if (LLNotificationPtr notification = LLNotifications::instance().find(notify["id"].asUUID())) { const LLSD& payload = notification->getPayload(); // Get the group data LLGroupData group_data; if (!gAgent.getGroupData(payload["group_id"].asUUID(),group_data)) { - llwarns << "Group notice for unkown group: " << payload["group_id"].asUUID() << llendl; + LL_WARNS() << "Group notice for unkown group: " << payload["group_id"].asUUID() << LL_ENDL; return false; } - LLGroupNotifyBox* self; - self = new LLGroupNotifyBox(payload["subject"].asString(), + gNotifyBoxView->addChild(new LLGroupNotifyBox(payload["subject"].asString(), payload["message"].asString(), - payload["sender_name"].asString(), + payload.has("sender_id") ? LLAvatarActions::getSLURL(payload["sender_id"]) : payload["sender_name"].asString(), payload["group_id"].asUUID(), group_data.mInsigniaID, - group_data.mName, + LLGroupActions::getSLURL(payload["group_id"].asUUID()), notification->getDate(), payload["inventory_offer"].isDefined(), payload["inventory_name"].asString(), - payload["inventory_offer"]); - gNotifyBoxView->addChild(self); + payload["inventory_offer"])); } return false; } @@ -424,14 +395,12 @@ void LLGroupNotifyBox::moveToBack() if (sGroupNotifyBoxCount > 1) { LLView* view = gNotifyBoxView->getFirstChild(); - - if(view && "groupnotify" == view->getName()) + if (view && "groupnotify" == view->getName()) { - LLGroupNotifyBox* front = (LLGroupNotifyBox*)view; - - if(front->mNextBtn) + LLGroupNotifyBox* front = static_cast(view); + if (front->mNextBtn) { - front->mNextBtn->setVisible(TRUE); + front->mNextBtn->setVisible(true); } } } @@ -452,23 +421,13 @@ LLRect LLGroupNotifyBox::getGroupNotifyRect() } -void LLGroupNotifyBox::onClickOk() -{ - close(); -} - void LLGroupNotifyBox::onClickSaveInventory() { mInventoryOffer->forceResponse(IOR_ACCEPT); mInventoryOffer = NULL; - mHasInventory = FALSE; + mHasInventory = false; // Each item can only be received once, so disable the button. mSaveInventoryBtn->setEnabled(FALSE); } - -void LLGroupNotifyBox::onClickNext() -{ - moveToBack(); -} diff --git a/indra/newview/llgroupnotify.h b/indra/newview/llgroupnotify.h index bd19ccd890..bf741aa342 100644 --- a/indra/newview/llgroupnotify.h +++ b/indra/newview/llgroupnotify.h @@ -35,7 +35,6 @@ #include "llfontgl.h" #include "llpanel.h" -#include "lldarray.h" #include "lltimer.h" #include "llviewermessage.h" #include "llnotifications.h" @@ -44,7 +43,7 @@ class LLButton; // NotifyBox - for notifications that require a response from the // user. Replaces LLMessageBox. -class LLGroupNotifyBox +class LLGroupNotifyBox final : public LLPanel, public LLInitClass { @@ -52,7 +51,6 @@ class LLGroupNotifyBox void close(); static void initClass(); - static void destroyClass(); static bool onNewNotification(const LLSD& notification); protected: @@ -72,15 +70,10 @@ class LLGroupNotifyBox /*virtual*/ ~LLGroupNotifyBox(); -// JC - removed support for clicking in background to dismiss -// the dialogs. -// /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); -// /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask); -// /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask) override; // Animate as sliding onto the screen. - /*virtual*/ void draw(); + /*virtual*/ void draw() override; void moveToBack(); @@ -89,15 +82,11 @@ class LLGroupNotifyBox static LLRect getGroupNotifyRect(); // internal handler for button being clicked - void onClickOk(); void onClickSaveInventory(); - // for "next" button - void onClickNext(); - private: // Are we sliding onscreen? - BOOL mAnimating; + bool mAnimating; // Time since this notification was displayed. // This is an LLTimer not a frame timer because I am concerned @@ -107,17 +96,9 @@ class LLGroupNotifyBox LLButton* mNextBtn; LLButton* mSaveInventoryBtn; - static S32 sGroupNotifyBoxCount; - LLUUID mGroupID; - BOOL mHasInventory; + bool mHasInventory; LLOfferInfo* mInventoryOffer; }; -// This view contains the stack of notification windows. -//extern LLView* gGroupNotifyBoxView; - -const S32 GROUP_LAYOUT_DEFAULT = 0; -const S32 GROUP_LAYOUT_SCRIPT_DIALOG = 1; - #endif diff --git a/indra/newview/llhomelocationresponder.cpp b/indra/newview/llhomelocationresponder.cpp index a782858162..b3582709d7 100644 --- a/indra/newview/llhomelocationresponder.cpp +++ b/indra/newview/llhomelocationresponder.cpp @@ -39,7 +39,7 @@ #include "llagent.h" #include "llviewerregion.h" -void LLHomeLocationResponder::result( const LLSD& content ) +void LLHomeLocationResponder::httpSuccess(void) { LLVector3 agent_pos; bool error = true; @@ -48,63 +48,63 @@ void LLHomeLocationResponder::result( const LLSD& content ) // was the call to /agent//home-location successful? // If not, we keep error set to true - if( ! content.has("success") ) + if( ! mContent.has("success") ) { break; } - if( 0 != strncmp("true", content["success"].asString().c_str(), 4 ) ) + if( 0 != strncmp("true", mContent["success"].asString().c_str(), 4 ) ) { break; } // did the simulator return a "justified" home location? // If no, we keep error set to true - if( ! content.has( "HomeLocation" ) ) + if( ! mContent.has( "HomeLocation" ) ) { break; } - if( ! content["HomeLocation"].has("LocationPos") ) + if( ! mContent["HomeLocation"].has("LocationPos") ) { break; } - if( ! content["HomeLocation"]["LocationPos"].has("X") ) + if( ! mContent["HomeLocation"]["LocationPos"].has("X") ) { break; } - agent_pos.mV[VX] = content["HomeLocation"]["LocationPos"]["X"].asInteger(); + agent_pos.mV[VX] = mContent["HomeLocation"]["LocationPos"]["X"].asInteger(); - if( ! content["HomeLocation"]["LocationPos"].has("Y") ) + if( ! mContent["HomeLocation"]["LocationPos"].has("Y") ) { break; } - agent_pos.mV[VY] = content["HomeLocation"]["LocationPos"]["Y"].asInteger(); + agent_pos.mV[VY] = mContent["HomeLocation"]["LocationPos"]["Y"].asInteger(); - if( ! content["HomeLocation"]["LocationPos"].has("Z") ) + if( ! mContent["HomeLocation"]["LocationPos"].has("Z") ) { break; } - agent_pos.mV[VZ] = content["HomeLocation"]["LocationPos"]["Z"].asInteger(); + agent_pos.mV[VZ] = mContent["HomeLocation"]["LocationPos"]["Z"].asInteger(); error = false; } while( 0 ); if( ! error ) { - llinfos << "setting home position" << llendl; + LL_INFOS() << "setting home position" << LL_ENDL; LLViewerRegion *viewer_region = gAgent.getRegion(); gAgent.setHomePosRegion( viewer_region->getHandle(), agent_pos ); } } -void LLHomeLocationResponder::error( U32 status, const std::string& reason ) +void LLHomeLocationResponder::httpFailure(void) { - llinfos << "received error(" << reason << ")" << llendl; + LL_INFOS() << "httpFailure: " << dumpResponse() << LL_ENDL; } diff --git a/indra/newview/llhomelocationresponder.h b/indra/newview/llhomelocationresponder.h index 9ffffc3046..ef680bdfb8 100644 --- a/indra/newview/llhomelocationresponder.h +++ b/indra/newview/llhomelocationresponder.h @@ -44,8 +44,8 @@ extern AIHTTPTimeoutPolicy homeLocationResponder_timeout; /* Typedef, Enum, Class, Struct, etc. */ class LLHomeLocationResponder : public LLHTTPClient::ResponderWithResult { - /*virtual*/ void result( const LLSD& content ); - /*virtual*/ void error( U32 status, const std::string& reason ); + /*virtual*/ void httpSuccess(void); + /*virtual*/ void httpFailure(void); /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return homeLocationResponder_timeout; } /*virtual*/ char const* getName(void) const { return "LLHomeLocationResponder"; } }; diff --git a/indra/newview/llhoverview.cpp b/indra/newview/llhoverview.cpp index dd53f11d6e..925f7a1a4c 100644 --- a/indra/newview/llhoverview.cpp +++ b/indra/newview/llhoverview.cpp @@ -66,6 +66,7 @@ #include "llviewerparcelmgr.h" #include "llviewerregion.h" #include "llviewerwindow.h" +#include "llvoavatarself.h" #include "llglheaders.h" #include "llviewertexturelist.h" //#include "lltoolobjpicker.h" @@ -88,6 +89,7 @@ // const char* DEFAULT_DESC = "(No Description)"; const F32 DELAY_BEFORE_SHOW_TIP = 0.35f; +const F32 DELAY_BEFORE_REFRESH_TIP = 0.50f; // // Local globals @@ -113,6 +115,9 @@ LLHoverView::LLHoverView(const std::string& name, const LLRect& rect) mUseHover = TRUE; mTyping = FALSE; mHoverOffset.clearVec(); + // + mLastTextHoverObject = NULL; + // } LLHoverView::~LLHoverView() @@ -139,6 +144,9 @@ void LLHoverView::updateHover(LLTool* current_tool) mStartHoverPickTimer = TRUE; // Clear the existing text so that we do not briefly show the wrong data. mText.clear(); + // + mLastTextHoverObject = NULL; + // } if (mDoneHoverPick) @@ -222,6 +230,18 @@ void LLHoverView::updateText() LLViewerObject* hit_object = getLastHoverObject(); std::string line; + // + if (hit_object == mLastTextHoverObject && + !(mLastTextHoverObjectTimer.getStarted() && mLastTextHoverObjectTimer.hasExpired())) + { + // mText is already up to date. + return; + } + mLastTextHoverObject = hit_object; + mLastTextHoverObjectTimer.stop(); + bool retrieving_data = false; + // + mText.clear(); if ( hit_object ) { @@ -252,6 +272,8 @@ void LLHoverView::updateText() line.clear(); if (hit_object->isAvatar()) { + if (gAgentAvatarp != hit_object && gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS)) + return; // No tag, no tip. LLNameValue* title = hit_object->getNVPair("Title"); LLNameValue* firstname = hit_object->getNVPair("FirstName"); LLNameValue* lastname = hit_object->getNVPair("LastName"); @@ -266,7 +288,7 @@ void LLHoverView::updateText() { // [/RLVa:KB] std::string complete_name; - if (!LLAvatarNameCache::getPNSName(hit_object->getID(), complete_name)) + if (!LLAvatarNameCache::getNSName(hit_object->getID(), complete_name)) complete_name = firstname->getString() + std::string(" ") + lastname->getString(); if (title) @@ -285,6 +307,8 @@ void LLHoverView::updateText() line.append(LLTrans::getString("TooltipPerson")); } mText.push_back(line); + + mText.push_back(LLTrans::getString("Complexity", LLSD().with("NUM", static_cast(hit_object->asAvatar()->getVisualComplexity())))); } else { @@ -389,7 +413,7 @@ void LLHoverView::updateText() { line.append(LLTrans::getString("TooltipPublic")); } - else if(LLAvatarNameCache::getPNSName(owner, name)) + else if (LLAvatarNameCache::getNSName(owner, name)) { // [RLVa:KB] - Checked: 2009-07-08 (RLVa-1.0.0e) if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) @@ -403,6 +427,7 @@ void LLHoverView::updateText() else { line.append(LLTrans::getString("RetrievingData")); + retrieving_data = true; } } else @@ -417,12 +442,14 @@ void LLHoverView::updateText() else { line.append(LLTrans::getString("RetrievingData")); + retrieving_data = true; } } } else { line.append(LLTrans::getString("RetrievingData")); + retrieving_data = true; } mText.push_back(line); @@ -514,14 +541,20 @@ void LLHoverView::updateText() { LLStringUtil::format_map_t args; args["[MESSAGE]"] = LLTrans::getString("RetrievingData"); + retrieving_data = true; line.append(LLTrans::getString("TooltipForSaleMsg", args)); } mText.push_back(line); + + auto objects = LLSelectMgr::getInstance()->getHoverObjects(); + line.clear(); - S32 prim_count = LLSelectMgr::getInstance()->getHoverObjects()->getObjectCount(); + S32 prim_count = objects->getObjectCount(); line.append(llformat("Prims: %d", prim_count)); mText.push_back(line); + mText.push_back(llformat("LI: %.2f", objects->getSelectedLinksetCost())); + line.clear(); line.append("Position: "); @@ -604,6 +637,7 @@ void LLHoverView::updateText() else { line.append(LLTrans::getString("RetrievingData")); + retrieving_data = true; } } else if(gCacheName->getFullName(owner, name)) @@ -616,11 +650,13 @@ void LLHoverView::updateText() else { line.append(LLTrans::getString("RetrievingData")); + retrieving_data = true; } } else { line.append(LLTrans::getString("RetrievingData")); + retrieving_data = true; } mText.push_back(line); @@ -699,8 +735,15 @@ void LLHoverView::updateText() mText.push_back(line); } } -} + // + if (retrieving_data) + { + // Keep doing this twice per second, until all data was retrieved. + mLastTextHoverObjectTimer.start(DELAY_BEFORE_REFRESH_TIP); + } + // +} void LLHoverView::draw() { @@ -768,8 +811,8 @@ void LLHoverView::draw() return; } - LLUIImagePtr box_imagep = LLUI::getUIImage("rounded_square.tga"); - LLUIImagePtr shadow_imagep = LLUI::getUIImage("rounded_square_soft.tga"); + LLUIImagePtr box_imagep = LLUI::getUIImage("Rounded_Square"); + LLUIImagePtr shadow_imagep = LLUI::getUIImage("Rounded_Square_Soft"); const LLFontGL* fontp = LLResMgr::getInstance()->getRes(LLFONT_SANSSERIF_SMALL); diff --git a/indra/newview/llhoverview.h b/indra/newview/llhoverview.h index d0bb28d837..47bfa5adad 100644 --- a/indra/newview/llhoverview.h +++ b/indra/newview/llhoverview.h @@ -41,7 +41,6 @@ #include "llcoord.h" #include "v3dmath.h" -#include "lldarray.h" #include "llviewerwindow.h" #include "llviewerobject.h" @@ -105,6 +104,8 @@ class LLHoverView : public LLView // If not null and not dead, we're over an object. LLPointer mLastHoverObject; + LLViewerObject* mLastTextHoverObject; // Singu extension: the value of mLastHoverObject that corresponds to mText. + LLFrameTimer mLastTextHoverObjectTimer; // Singu extension: times how long ago the text was updated (while retrieving data). LLPickInfo mLastPickInfo; // If not LLVector3d::ZERO, we're over land. diff --git a/indra/newview/llhttpretrypolicy.cpp b/indra/newview/llhttpretrypolicy.cpp new file mode 100644 index 0000000000..1fb287cd63 --- /dev/null +++ b/indra/newview/llhttpretrypolicy.cpp @@ -0,0 +1,155 @@ +/** + * @file llhttpretrypolicy.h + * @brief Header for a retry policy class intended for use with http responders. + * + * $LicenseInfo:firstyear=2013&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2013, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llhttpretrypolicy.h" +#include "llhttpstatuscodes.h" +#include "aihttpheaders.h" + +// for curl_getdate() (apparently parsing RFC 1123 dates is hard) +#include + +// Parses 'Retry-After' header contents and returns seconds until retry should occur. +bool getSecondsUntilRetryAfter(const std::string& retry_after, F32& seconds_to_wait) +{ + // *TODO: This needs testing! Not in use yet. + // Examples of Retry-After headers: + // Retry-After: Fri, 31 Dec 1999 23:59:59 GMT + // Retry-After: 120 + + // Check for number of seconds version, first: + char* end = 0; + // Parse as double + double seconds = std::strtod(retry_after.c_str(), &end); + if (end != 0 && *end == 0) + { + // Successful parse + seconds_to_wait = (F32)seconds; + return true; + } + + // Parse rfc1123 date. + time_t date = curl_getdate(retry_after.c_str(), NULL); + if (-1 == date) return false; + + seconds_to_wait = (F64)date - LLTimer::getTotalSeconds(); + + return true; +} + +LLAdaptiveRetryPolicy::LLAdaptiveRetryPolicy(F32 min_delay, F32 max_delay, F32 backoff_factor, U32 max_retries, bool retry_on_4xx): + mMinDelay(min_delay), + mMaxDelay(max_delay), + mBackoffFactor(backoff_factor), + mMaxRetries(max_retries), + mRetryOn4xx(retry_on_4xx) +{ + init(); +} + +void LLAdaptiveRetryPolicy::init() +{ + mDelay = mMinDelay; + mRetryCount = 0; + mShouldRetry = true; +} + +void LLAdaptiveRetryPolicy::reset() +{ + init(); +} + +bool LLAdaptiveRetryPolicy::getRetryAfter(const AIHTTPReceivedHeaders& headers, F32& retry_header_time) +{ + AIHTTPReceivedHeaders::range_type results; + return headers.getValues("retry-after", results) && getSecondsUntilRetryAfter(results.first->second, retry_header_time); +} + +void LLAdaptiveRetryPolicy::onSuccess() +{ + init(); +} + +void LLAdaptiveRetryPolicy::onFailure(S32 status, const AIHTTPReceivedHeaders& headers) +{ + F32 retry_header_time; + bool has_retry_header_time = getRetryAfter(headers,retry_header_time); + onFailureCommon(status, has_retry_header_time, retry_header_time); +} + + +void LLAdaptiveRetryPolicy::onFailureCommon(S32 status, bool has_retry_header_time, F32 retry_header_time) +{ + if (!mShouldRetry) + { + LL_INFOS() << "keep on failing" << LL_ENDL; + return; + } + if (mRetryCount > 0) + { + mDelay = llclamp(mDelay*mBackoffFactor,mMinDelay,mMaxDelay); + } + // Honor server Retry-After header. + // Status 503 may ask us to wait for a certain amount of time before retrying. + F32 wait_time = mDelay; + if (has_retry_header_time) + { + wait_time = retry_header_time; + } + + if (mRetryCount>=mMaxRetries) + { + LL_INFOS() << "Too many retries " << mRetryCount << ", will not retry" << LL_ENDL; + mShouldRetry = false; + } + + if (!mRetryOn4xx && !(status == HTTP_INTERNAL_ERROR_OTHER || ((500 <= status) && (status < 600)))) + { + LL_INFOS() << "Non-server error " << status << ", will not retry" << LL_ENDL; + mShouldRetry = false; + } + if (mShouldRetry) + { + LL_INFOS() << "Retry count " << mRetryCount << " should retry after " << wait_time << LL_ENDL; + mRetryTimer.reset(); + mRetryTimer.setTimerExpirySec(wait_time); + } + mRetryCount++; +} + + +bool LLAdaptiveRetryPolicy::shouldRetry(F32& seconds_to_wait) const +{ + if (mRetryCount == 0) + { + // Called shouldRetry before any failure. + seconds_to_wait = F32_MAX; + return false; + } + seconds_to_wait = mShouldRetry ? (F32) mRetryTimer.getRemainingTimeF32() : F32_MAX; + return mShouldRetry; +} diff --git a/indra/newview/llhttpretrypolicy.h b/indra/newview/llhttpretrypolicy.h new file mode 100644 index 0000000000..58f91f300d --- /dev/null +++ b/indra/newview/llhttpretrypolicy.h @@ -0,0 +1,88 @@ +/** + * @file file llhttpretrypolicy.h + * @brief declarations for http retry policy class. + * + * $LicenseInfo:firstyear=2013&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2013, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_RETRYPOLICY_H +#define LL_RETRYPOLICY_H + +#include "lltimer.h" +#include "llthread.h" + +class AIHTTPReceivedHeaders; + +// This is intended for use with HTTP Clients/Responders, but is not +// specifically coupled with those classes. +class LLHTTPRetryPolicy: public LLThreadSafeRefCount +{ +public: + LLHTTPRetryPolicy() {} + + virtual ~LLHTTPRetryPolicy() {} + // Call after a sucess to reset retry state. + + virtual void onSuccess() = 0; + // Call once after an HTTP failure to update state. + virtual void onFailure(S32 status, const AIHTTPReceivedHeaders& headers) = 0; + + virtual bool shouldRetry(F32& seconds_to_wait) const = 0; + + virtual void reset() = 0; +}; + +// Very general policy with geometric back-off after failures, +// up to a maximum delay, and maximum number of retries. +class LLAdaptiveRetryPolicy: public LLHTTPRetryPolicy +{ +public: + LLAdaptiveRetryPolicy(F32 min_delay, F32 max_delay, F32 backoff_factor, U32 max_retries, bool retry_on_4xx = false); + + // virtual + void onSuccess(); + + void reset(); + + // virtual + void onFailure(S32 status, const AIHTTPReceivedHeaders& headers); + // virtual + bool shouldRetry(F32& seconds_to_wait) const; + +protected: + void init(); + bool getRetryAfter(const AIHTTPReceivedHeaders& headers, F32& retry_header_time); + void onFailureCommon(S32 status, bool has_retry_header_time, F32 retry_header_time); + +private: + F32 mMinDelay; // delay never less than this value + F32 mMaxDelay; // delay never exceeds this value + F32 mBackoffFactor; // delay increases by this factor after each retry, up to mMaxDelay. + U32 mMaxRetries; // maximum number of times shouldRetry will return true. + F32 mDelay; // current delay. + U32 mRetryCount; // number of times shouldRetry has been called. + LLTimer mRetryTimer; // time until next retry. + bool mShouldRetry; // Becomes false after too many retries, or the wrong sort of status received, etc. + bool mRetryOn4xx; // Normally only retry on 5xx server errors. +}; + +#endif diff --git a/indra/newview/llhudeffect.cpp b/indra/newview/llhudeffect.cpp index bfd62805a1..609e0dfa5b 100644 --- a/indra/newview/llhudeffect.cpp +++ b/indra/newview/llhudeffect.cpp @@ -77,7 +77,7 @@ void LLHUDEffect::unpackData(LLMessageSystem *mesgsys, S32 blocknum) void LLHUDEffect::render() { - llerrs << "Never call this!" << llendl; + LL_ERRS() << "Never call this!" << LL_ENDL; } void LLHUDEffect::setID(const LLUUID &id) diff --git a/indra/newview/llhudeffectbeam.cpp b/indra/newview/llhudeffectbeam.cpp index 7d6e515978..39e1089ff5 100644 --- a/indra/newview/llhudeffectbeam.cpp +++ b/indra/newview/llhudeffectbeam.cpp @@ -84,7 +84,7 @@ void LLHUDEffectBeam::packData(LLMessageSystem *mesgsys) { if (!mSourceObject) { - llwarns << "Missing source object!" << llendl; + LL_WARNS() << "Missing source object!" << LL_ENDL; } // Pack the default data @@ -121,7 +121,7 @@ void LLHUDEffectBeam::packData(LLMessageSystem *mesgsys) void LLHUDEffectBeam::unpackData(LLMessageSystem *mesgsys, S32 blocknum) { - llerrs << "Got beam!" << llendl; + LL_ERRS() << "Got beam!" << LL_ENDL; BOOL use_target_object; LLVector3d new_target; U8 packed_data[41]; @@ -132,7 +132,7 @@ void LLHUDEffectBeam::unpackData(LLMessageSystem *mesgsys, S32 blocknum) S32 size = mesgsys->getSizeFast(_PREHASH_Effect, blocknum, _PREHASH_TypeData); if (size != 41) { - llwarns << "Beam effect with bad size " << size << llendl; + LL_WARNS() << "Beam effect with bad size " << size << LL_ENDL; return; } mesgsys->getBinaryDataFast(_PREHASH_Effect, _PREHASH_TypeData, packed_data, 41, blocknum); @@ -178,7 +178,7 @@ void LLHUDEffectBeam::setSourceObject(LLViewerObject *objp) { if (objp->isDead()) { - llwarns << "HUDEffectBeam: Source object is dead!" << llendl; + LL_WARNS() << "HUDEffectBeam: Source object is dead!" << LL_ENDL; mSourceObject = NULL; return; } @@ -216,7 +216,7 @@ void LLHUDEffectBeam::setTargetObject(LLViewerObject *objp) { if (mTargetObject->isDead()) { - llwarns << "HUDEffectBeam: Target object is dead!" << llendl; + LL_WARNS() << "HUDEffectBeam: Target object is dead!" << LL_ENDL; } mTargetObject = objp; diff --git a/indra/newview/llhudeffectlookat.cpp b/indra/newview/llhudeffectlookat.cpp index 2a180897ba..0c529f41b8 100644 --- a/indra/newview/llhudeffectlookat.cpp +++ b/indra/newview/llhudeffectlookat.cpp @@ -2,31 +2,25 @@ * @file llhudeffectlookat.cpp * @brief LLHUDEffectLookAt class implementation * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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$ */ @@ -39,22 +33,22 @@ #include "message.h" #include "llagent.h" #include "llagentcamera.h" -#include "llvoavatarself.h" +#include "llvoavatar.h" #include "lldrawable.h" #include "llviewerobjectlist.h" #include "llrendersphere.h" #include "llselectmgr.h" #include "llglheaders.h" - - #include "llxmltree.h" -// -#include "llresmgr.h" + +// +#include "llavatarnamecache.h" #include "llhudrender.h" -#include "llviewerwindow.h" #include "llviewercontrol.h" -// +// +#include "rlvhandler.h" +//BOOL LLHUDEffectLookAt::sDebugLookAt = FALSE; // // packet layout const S32 SOURCE_AVATAR = 0; @@ -214,7 +208,7 @@ static BOOL loadAttentions() //------------------------------------------------------------------------- if( !root->hasName( "linden_attentions" ) ) { - llwarns << "Invalid linden_attentions file header: " << filename << llendl; + LL_WARNS() << "Invalid linden_attentions file header: " << filename << LL_ENDL; return FALSE; } @@ -222,7 +216,7 @@ static BOOL loadAttentions() static LLStdStringHandle version_string = LLXmlTree::addAttributeString("version"); if( !root->getFastAttributeString( version_string, version ) || (version != "1.0") ) { - llwarns << "Invalid linden_attentions file version: " << version << llendl; + LL_WARNS() << "Invalid linden_attentions file version: " << version << LL_ENDL; return FALSE; } @@ -251,7 +245,10 @@ static BOOL loadAttentions() LLHUDEffectLookAt::LLHUDEffectLookAt(const U8 type) : LLHUDEffect(type), mKillTime(0.f), - mLastSendTime(0.f) +// + mLastSendTime(0.f), + mDebugLookAt(gSavedSettings, "AscentShowLookAt", false) +// { clearLookAtTarget(); // parse the default sets @@ -332,27 +329,27 @@ void LLHUDEffectLookAt::unpackData(LLMessageSystem *mesgsys, S32 blocknum) S32 size = mesgsys->getSizeFast(_PREHASH_Effect, blocknum, _PREHASH_TypeData); if (size != PKT_SIZE) { - llwarns << "LookAt effect with bad size " << size << llendl; + LL_WARNS() << "LookAt effect with bad size " << size << LL_ENDL; return; } mesgsys->getBinaryDataFast(_PREHASH_Effect, _PREHASH_TypeData, packed_data, PKT_SIZE, blocknum); htonmemcpy(source_id.mData, &(packed_data[SOURCE_AVATAR]), MVT_LLUUID, 16); - LLVOAvatar *avatarp = gObjectList.findAvatar(source_id); - if (avatarp) + LLViewerObject *objp = gObjectList.findObject(source_id); + if (objp && objp->isAvatar()) { - setSourceObject(avatarp); + setSourceObject(objp); } else { - //llwarns << "Could not find source avatar for lookat effect" << llendl; + //LL_WARNS() << "Could not find source avatar for lookat effect" << LL_ENDL; return; } htonmemcpy(target_id.mData, &(packed_data[TARGET_OBJECT]), MVT_LLUUID, 16); - LLViewerObject *objp = gObjectList.findObject(target_id); + objp = gObjectList.findObject(target_id); htonmemcpy(new_target.mdV, &(packed_data[TARGET_POS]), MVT_LLVector3d, 24); @@ -366,13 +363,22 @@ void LLHUDEffectLookAt::unpackData(LLMessageSystem *mesgsys, S32 blocknum) } else { - //llwarns << "Could not find target object for lookat effect" << llendl; + //LL_WARNS() << "Could not find target object for lookat effect" << LL_ENDL; } U8 lookAtTypeUnpacked = 0; htonmemcpy(&lookAtTypeUnpacked, &(packed_data[LOOKAT_TYPE]), MVT_U8, 1); - mTargetType = (ELookAtType)lookAtTypeUnpacked; - + // + if ((U8)LOOKAT_NUM_TARGETS > lookAtTypeUnpacked) + { + mTargetType = (ELookAtType)lookAtTypeUnpacked; + } + else + { + mTargetType = LOOKAT_TARGET_NONE; + LL_DEBUGS("HUDEffect") << "Invalid target type: " << lookAtTypeUnpacked << LL_ENDL; + } + // if (mTargetType == LOOKAT_TARGET_NONE) { clearLookAtTarget(); @@ -410,7 +416,7 @@ BOOL LLHUDEffectLookAt::setLookAt(ELookAtType target_type, LLViewerObject *objec if (target_type >= LOOKAT_NUM_TARGETS) { - llwarns << "Bad target_type " << (int)target_type << " - ignoring." << llendl; + LL_WARNS() << "Bad target_type " << (int)target_type << " - ignoring." << LL_ENDL; return FALSE; } @@ -503,15 +509,15 @@ void LLHUDEffectLookAt::setSourceObject(LLViewerObject* objectp) //----------------------------------------------------------------------------- void LLHUDEffectLookAt::render() { - static const LLCachedControl private_look_at("PrivateLookAt",false); - static const LLCachedControl show_look_at("AscentShowLookAt", false); - - if (private_look_at && (gAgentAvatarp == ((LLVOAvatar*)(LLViewerObject*)mSourceObject))) - return; - - if (show_look_at && mSourceObject.notNull()) + // + if (mDebugLookAt && mSourceObject.notNull()) { - LLGLDepthTest gls_depth(GL_TRUE,GL_FALSE); + static LLCachedControl isOwnHidden(gSavedSettings, "AlchemyLookAtHideSelf", true); + static LLCachedControl isPrivate(gSavedSettings, "PrivateLookAt", false); + static const LLCachedControl show_look_at("AscentShowLookAt", false); + + if ((isOwnHidden || isPrivate) && static_cast(mSourceObject.get())->isSelf()) + return; gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); @@ -532,39 +538,70 @@ void LLHUDEffectLookAt::render() gGL.vertex3f(0.f, 0.f, -1.f); gGL.vertex3f(0.f, 0.f, 1.f); - } gGL.end(); - gGL.popMatrix(); - // - const std::string text = ((LLVOAvatar*)(LLViewerObject*)mSourceObject)->getFullname(); - LLVector3 offset = gAgentCamera.getCameraPositionAgent() - target; - offset.normalize(); - LLVector3 shadow_offset = offset * 0.49f; - offset *= 0.5f; - const LLFontGL* font = LLResMgr::getInstance()->getRes(LLFONT_SANSSERIF); - LLGLEnable gl_blend(GL_BLEND); - gGL.pushMatrix(); - gViewerWindow->setup2DViewport(); - hud_render_utf8text(text, - target + shadow_offset, - *font, - LLFontGL::NORMAL, - LLFontGL::NO_SHADOW, - -0.5f * font->getWidthF32(text) + 2.0f, - -2.0f, - LLColor4::black, - FALSE); - hud_render_utf8text(text, - target + offset, - *font, - LLFontGL::NORMAL, - LLFontGL::NO_SHADOW, - -0.5f * font->getWidthF32(text), - 0.0f, - (*mAttentions)[mTargetType].mColor, - FALSE); + + static LLCachedControl lookAtLines(gSavedSettings, "AlchemyLookAtLines", false); + if (lookAtLines) + { + const std::string targname = (*mAttentions)[mTargetType].mName; + if (targname != "None" && targname != "Idle" && targname != "AutoListen") + { + const LLVector3& source_pos(mSourceObject->getWorldPosition()); + if (!gRlvHandler.hasBehaviour(RLV_BHVR_CAMAVDIST) || (gAgent.getPosGlobalFromAgent(source_pos) - gAgent.getPositionGlobal()).magVec() <= gRlvHandler.camPole(RLV_BHVR_CAMAVDIST)) + { + LLVector3 dist = (source_pos - mTargetPos) * 10/3; + gGL.vertex3f(0.f, 0.f, 0.f); + gGL.vertex3f(dist.mV[VX], dist.mV[VY], dist.mV[VZ] + 0.5f); + } + } + } + } + gGL.end(); gGL.popMatrix(); - // + + static LLCachedControl lookAtNames(gSavedSettings, "LookAtNameSystem", 0); + if (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS) && lookAtNames >= 0) + { + std::string text; + if (!LLAvatarNameCache::getNSName(static_cast(mSourceObject.get())->getID(), text, lookAtNames)) return; + if (text.length() > 9 && 0 == text.compare(text.length() - 9, 9, " Resident")) + text.erase(text.length() - 9); + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) + text = RlvStrings::getAnonym(text); + + LLVector3 offset = gAgentCamera.getCameraPositionAgent() - target; + offset.normalize(); + LLVector3 shadow_offset = offset * 0.49f; + offset *= 0.5f; + LLGLEnable gl_blend; + + const LLFontGL* fontp = LLFontGL::getFontSansSerif(); + gGL.pushMatrix(); + hud_render_utf8text( + text, + target + shadow_offset, + *fontp, + LLFontGL::NORMAL, + LLFontGL::NO_SHADOW, + -0.5f * fontp->getWidthF32(text) + 2.0f, + -2.0f, + LLColor4::black, + FALSE + ); + hud_render_utf8text( + text, + target + offset, + *fontp, + LLFontGL::NORMAL, + LLFontGL::NO_SHADOW, + -0.5f * fontp->getWidthF32(text), + 0.0f, + (*mAttentions)[mTargetType].mColor, + FALSE + ); + gGL.popMatrix(); + } } + // } //----------------------------------------------------------------------------- @@ -572,8 +609,6 @@ void LLHUDEffectLookAt::render() //----------------------------------------------------------------------------- void LLHUDEffectLookAt::update() { - static const LLCachedControl show_look_at("AscentShowLookAt", false); - // If the target object is dead, set the target object to NULL if (!mTargetObject.isNull() && mTargetObject->isDead()) { @@ -611,17 +646,18 @@ void LLHUDEffectLookAt::update() { if (calcTargetPosition()) { - LLMotion* head_motion = ((LLVOAvatar*)(LLViewerObject*)mSourceObject)->findMotion(ANIM_AGENT_HEAD_ROT); - if (!head_motion || head_motion->isStopped()) + //LLMotion* head_motion = ((LLVOAvatar*)(LLViewerObject*)mSourceObject)->findMotion(ANIM_AGENT_HEAD_ROT); + //if (!head_motion || head_motion->isStopped()) + // singu: startMotion does basically the same as the above two lines... it starts it, unless it was already started. { ((LLVOAvatar*)(LLViewerObject*)mSourceObject)->startMotion(ANIM_AGENT_HEAD_ROT); } } } - if (show_look_at) + if (mDebugLookAt) // { - ((LLVOAvatar*)(LLViewerObject*)mSourceObject)->addDebugText((*mAttentions)[mTargetType].mName); + // ((LLVOAvatar*)(LLViewerObject*)mSourceObject)->addDebugText((*mAttentions)[mTargetType].mName); // } } @@ -637,11 +673,6 @@ void LLHUDEffectLookAt::update() */ bool LLHUDEffectLookAt::calcTargetPosition() { - if (gNoRender) - { - return false; - } - LLViewerObject *target_obj = (LLViewerObject *)mTargetObject; LLVector3 local_offset; diff --git a/indra/newview/llhudeffectlookat.h b/indra/newview/llhudeffectlookat.h index 93eb2178d5..e9bf176bd6 100644 --- a/indra/newview/llhudeffectlookat.h +++ b/indra/newview/llhudeffectlookat.h @@ -2,31 +2,25 @@ * @file llhudeffectlookat.h * @brief LLHUDEffectLookAt class definition * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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$ */ @@ -34,7 +28,7 @@ #define LL_LLHUDEFFECTLOOKAT_H #include "llhudeffect.h" -#include "llframetimer.h" +#include "llcontrol.h" // class LLViewerObject; class LLVOAvatar; @@ -85,7 +79,8 @@ class LLHUDEffectLookAt : public LLHUDEffect void setTargetObjectAndOffset(LLViewerObject *objp, LLVector3d offset); void setTargetPosGlobal(const LLVector3d &target_pos_global); -public: +//public: +// static BOOL sDebugLookAt; // private: ELookAtType mTargetType; @@ -96,6 +91,7 @@ class LLHUDEffectLookAt : public LLHUDEffect LLVector3 mTargetPos; F32 mLastSendTime; LLAttentionSet* mAttentions; + LLCachedControl mDebugLookAt; // }; #endif // LL_LLHUDEFFECTLOOKAT_H diff --git a/indra/newview/llhudeffectpointat.cpp b/indra/newview/llhudeffectpointat.cpp index 59a9596bca..90546e5b94 100644 --- a/indra/newview/llhudeffectpointat.cpp +++ b/indra/newview/llhudeffectpointat.cpp @@ -165,7 +165,7 @@ void LLHUDEffectPointAt::unpackData(LLMessageSystem *mesgsys, S32 blocknum) S32 size = mesgsys->getSizeFast(_PREHASH_Effect, blocknum, _PREHASH_TypeData); if (size != PKT_SIZE) { - llwarns << "PointAt effect with bad size " << size << llendl; + LL_WARNS() << "PointAt effect with bad size " << size << LL_ENDL; return; } mesgsys->getBinaryDataFast(_PREHASH_Effect, _PREHASH_TypeData, packed_data, PKT_SIZE, blocknum); @@ -182,7 +182,7 @@ void LLHUDEffectPointAt::unpackData(LLMessageSystem *mesgsys, S32 blocknum) } else { - //llwarns << "Could not find source avatar for pointat effect" << llendl; + //LL_WARNS() << "Could not find source avatar for pointat effect" << LL_ENDL; return; } @@ -234,7 +234,7 @@ BOOL LLHUDEffectPointAt::setPointAt(EPointAtType target_type, LLViewerObject *ob if (target_type >= POINTAT_NUM_TARGETS) { - llwarns << "Bad target_type " << (int)target_type << " - ignoring." << llendl; + LL_WARNS() << "Bad target_type " << (int)target_type << " - ignoring." << LL_ENDL; return FALSE; } @@ -258,7 +258,7 @@ BOOL LLHUDEffectPointAt::setPointAt(EPointAtType target_type, LLViewerObject *ob mLastSentOffsetGlobal = position; setDuration(POINTAT_TIMEOUTS[target_type]); setNeedsSendToSim(TRUE); -// llinfos << "Sending pointat data" << llendl; +// LL_INFOS() << "Sending pointat data" << LL_ENDL; } if (target_type == POINTAT_TARGET_CLEAR) @@ -441,7 +441,7 @@ bool LLHUDEffectPointAt::calcTargetPosition() mTargetPos -= mSourceObject->getRenderPosition(); - if (!llfinite(mTargetPos.lengthSquared())) + if (!std::isfinite(mTargetPos.lengthSquared())) { return false; } diff --git a/indra/newview/llhudeffecttrail.cpp b/indra/newview/llhudeffecttrail.cpp index fbba2c354b..486f6a695d 100644 --- a/indra/newview/llhudeffecttrail.cpp +++ b/indra/newview/llhudeffecttrail.cpp @@ -91,7 +91,7 @@ void LLHUDEffectSpiral::packData(LLMessageSystem *mesgsys) { if (!mSourceObject) { - //llwarns << "Missing object in trail pack!" << llendl; + //LL_WARNS() << "Missing object in trail pack!" << LL_ENDL; } LLHUDEffect::packData(mesgsys); @@ -123,7 +123,7 @@ void LLHUDEffectSpiral::unpackData(LLMessageSystem *mesgsys, S32 blocknum) size_t size = mesgsys->getSizeFast(_PREHASH_Effect, blocknum, _PREHASH_TypeData); if (size != EFFECT_SIZE) { - llwarns << "Spiral effect with bad size " << size << llendl; + LL_WARNS() << "Spiral effect with bad size " << size << LL_ENDL; return; } mesgsys->getBinaryDataFast(_PREHASH_Effect, _PREHASH_TypeData, diff --git a/indra/newview/llhudeffecttrail.h b/indra/newview/llhudeffecttrail.h index 033fbeb06d..15daa80db9 100644 --- a/indra/newview/llhudeffecttrail.h +++ b/indra/newview/llhudeffecttrail.h @@ -42,7 +42,7 @@ class LLViewerObject; -const U32 NUM_TRAIL_POINTS = 40; +constexpr U32 NUM_TRAIL_POINTS = 40; class LLHUDEffectSpiral : public LLHUDEffect diff --git a/indra/newview/llhudicon.cpp b/indra/newview/llhudicon.cpp index 6b9ad6a17c..574084991a 100644 --- a/indra/newview/llhudicon.cpp +++ b/indra/newview/llhudicon.cpp @@ -94,7 +94,7 @@ void LLHUDIcon::renderIcon(BOOL for_select) if (mHidden) return; - if (mSourceObject.isNull() || mImagep.isNull()) + if (mSourceObject.isNull() || mImagep.isNull() || mSourceObject->mDrawable.isNull()) { markDead(); return; @@ -169,16 +169,16 @@ void LLHUDIcon::renderIcon(BOOL for_select) gGL.getTexUnit(0)->bind(mImagep); } - gGL.begin(LLRender::QUADS); + gGL.begin(LLRender::TRIANGLE_STRIP); { gGL.texCoord2f(0.f, 1.f); gGL.vertex3fv(upper_left.mV); gGL.texCoord2f(0.f, 0.f); gGL.vertex3fv(lower_left.mV); - gGL.texCoord2f(1.f, 0.f); - gGL.vertex3fv(lower_right.mV); gGL.texCoord2f(1.f, 1.f); gGL.vertex3fv(upper_right.mV); + gGL.texCoord2f(1.f, 0.f); + gGL.vertex3fv(lower_right.mV); } gGL.end(); } @@ -208,7 +208,7 @@ void LLHUDIcon::render() renderIcon(FALSE); } -BOOL LLHUDIcon::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, LLVector3* intersection) +BOOL LLHUDIcon::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, LLVector4a* intersection) { if (mHidden) return FALSE; @@ -281,23 +281,18 @@ BOOL LLHUDIcon::lineSegmentIntersect(const LLVector3& start, const LLVector3& en LLVector4a upper_right; upper_right.setAdd(lower_right, y_scalea); - LLVector4a enda; - enda.load3(end.mV); - LLVector4a starta; - starta.load3(start.mV); LLVector4a dir; - dir.setSub(enda, starta); + dir.setSub(end, start); F32 a,b,t; - if (LLTriangleRayIntersect(upper_right, upper_left, lower_right, starta, dir, a,b,t) || - LLTriangleRayIntersect(upper_left, lower_left, lower_right, starta, dir, a,b,t)) + if (LLTriangleRayIntersect(upper_right, upper_left, lower_right, start, dir, a,b,t) || + LLTriangleRayIntersect(upper_left, lower_left, lower_right, start, dir, a,b,t)) { if (intersection) { dir.mul(t); - starta.add(dir); - *intersection = LLVector3(starta.getF32ptr()); + intersection->setAdd(start, dir); } return TRUE; } @@ -337,12 +332,12 @@ LLHUDIcon* LLHUDIcon::handlePick(S32 pick_id) } //static -LLHUDIcon* LLHUDIcon::lineSegmentIntersectAll(const LLVector3& start, const LLVector3& end, LLVector3* intersection) +LLHUDIcon* LLHUDIcon::lineSegmentIntersectAll(const LLVector4a& start, const LLVector4a& end, LLVector4a* intersection) { icon_instance_t::iterator icon_it; - LLVector3 local_end = end; - LLVector3 position; + LLVector4a local_end = end; + LLVector4a position; LLHUDIcon* ret = NULL; for(icon_it = sIconInstances.begin(); icon_it != sIconInstances.end(); ++icon_it) diff --git a/indra/newview/llhudicon.h b/indra/newview/llhudicon.h index 5697cc94f3..6cf15df488 100644 --- a/indra/newview/llhudicon.h +++ b/indra/newview/llhudicon.h @@ -34,7 +34,6 @@ #define LL_LLHUDICON_H #include "llpointer.h" -#include "lldarrayptr.h" #include "llhudobject.h" #include "v4color.h" @@ -45,7 +44,6 @@ #include "llfontgl.h" #include #include -#include "lldarray.h" // Renders a 2D icon billboard floating at the location specified. class LLDrawable; @@ -68,7 +66,7 @@ friend class LLHUDObject; static S32 generatePickIDs(S32 start_id, S32 step_size); static LLHUDIcon* handlePick(S32 pick_id); - static LLHUDIcon* lineSegmentIntersectAll(const LLVector3& start, const LLVector3& end, LLVector3* intersection); + static LLHUDIcon* lineSegmentIntersectAll(const LLVector4a& start, const LLVector4a& end, LLVector4a* intersection); static void updateAll(); static void cleanupDeadIcons(); @@ -79,7 +77,7 @@ friend class LLHUDObject; BOOL getHidden() const { return mHidden; } void setHidden( BOOL hide ) { mHidden = hide; } - BOOL lineSegmentIntersect(const LLVector3& start, const LLVector3& end, LLVector3* intersection); + BOOL lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, LLVector4a* intersection); protected: LLHUDIcon(const U8 type); diff --git a/indra/newview/llhudmanager.cpp b/indra/newview/llhudmanager.cpp index cb9a2c1d39..c5e21e9b1b 100644 --- a/indra/newview/llhudmanager.cpp +++ b/indra/newview/llhudmanager.cpp @@ -61,13 +61,13 @@ LLHUDManager::~LLHUDManager() { } -static LLFastTimer::DeclareTimer FTM_HUD_EFFECTS("Hud Effects"); +static LLTrace::BlockTimerStatHandle FTM_HUD_EFFECTS("Hud Effects"); void LLHUDManager::updateEffects() { - LLFastTimer ftm(FTM_HUD_EFFECTS); - S32 i; - for (i = 0; i < mHUDEffects.count(); i++) + LL_RECORD_BLOCK_TIME(FTM_HUD_EFFECTS); + U32 i; + for (i = 0; i < mHUDEffects.size(); i++) { LLHUDEffect *hep = mHUDEffects[i]; if (hep->isDead()) @@ -80,22 +80,41 @@ void LLHUDManager::updateEffects() void LLHUDManager::sendEffects() { + static LLCachedControl disable_lookat_effect(gSavedSettings, "PrivateLookAt", false); + static LLCachedControl disable_pointat_effect(gSavedSettings, "DisablePointAtAndBeam", false); + static LLCachedControl broadcast_viewer_effects(gSavedSettings, "BroadcastViewerEffects", true); - if(!gSavedSettings.getBOOL("BroadcastViewerEffects")) - return; - - S32 i; - for (i = 0; i < mHUDEffects.count(); i++) + U32 i; + for (i = 0; i < mHUDEffects.size(); i++) { LLHUDEffect *hep = mHUDEffects[i]; + if (hep->mType == LLHUDObject::LL_HUD_EFFECT_LOOKAT) + { + if (disable_lookat_effect) + { + continue; + } + } + else if (hep->mType == LLHUDObject::LL_HUD_EFFECT_POINTAT || + hep->mType == LLHUDObject::LL_HUD_EFFECT_BEAM) + { + if (disable_pointat_effect) + { + continue; + } + } + else if (!broadcast_viewer_effects) + { + continue; + } if (hep->isDead()) { - llwarns << "Trying to send dead effect!" << llendl; + LL_WARNS() << "Trying to send dead effect!" << LL_ENDL; continue; } if (hep->mType < LLHUDObject::LL_HUD_EFFECT_BEAM) { - llwarns << "Trying to send effect of type " << hep->mType << " which isn't really an effect and shouldn't be in this list!" << llendl; + LL_WARNS() << "Trying to send effect of type " << hep->mType << " which isn't really an effect and shouldn't be in this list!" << LL_ENDL; continue; } if (hep->getNeedsSendToSim() && hep->getOriginatedHere()) @@ -117,18 +136,18 @@ void LLHUDManager::sendEffects() //static void LLHUDManager::shutdownClass() { - getInstance()->mHUDEffects.reset(); + getInstance()->mHUDEffects.clear(); } void LLHUDManager::cleanupEffects() { - S32 i = 0; + U32 i = 0; - while (i < mHUDEffects.count()) + while (i < mHUDEffects.size()) { if (mHUDEffects[i]->isDead()) { - mHUDEffects.remove(i); + mHUDEffects.erase(mHUDEffects.begin() + i); } else { @@ -152,7 +171,7 @@ LLHUDEffect *LLHUDManager::createViewerEffect(const U8 type, BOOL send_to_sim, B hep->setNeedsSendToSim(send_to_sim); hep->setOriginatedHere(originated_here); - mHUDEffects.put(hep); + mHUDEffects.push_back(hep); return hep; } @@ -175,21 +194,21 @@ void LLHUDManager::processViewerEffect(LLMessageSystem *mesgsys, void **user_dat { effectp = NULL; LLHUDEffect::getIDType(mesgsys, k, effect_id, effect_type); - S32 i; - for (i = 0; i < LLHUDManager::getInstance()->mHUDEffects.count(); i++) + U32 i; + for (i = 0; i < LLHUDManager::getInstance()->mHUDEffects.size(); i++) { LLHUDEffect *cur_effectp = LLHUDManager::getInstance()->mHUDEffects[i]; if (!cur_effectp) { - llwarns << "Null effect in effect manager, skipping" << llendl; - LLHUDManager::getInstance()->mHUDEffects.remove(i); + LL_WARNS() << "Null effect in effect manager, skipping" << LL_ENDL; + LLHUDManager::getInstance()->mHUDEffects.erase(LLHUDManager::getInstance()->mHUDEffects.begin() + i); i--; continue; } if (cur_effectp->isDead()) { - // llwarns << "Dead effect in effect manager, removing" << llendl; - LLHUDManager::getInstance()->mHUDEffects.remove(i); + // LL_WARNS() << "Dead effect in effect manager, removing" << LL_ENDL; + LLHUDManager::getInstance()->mHUDEffects.erase(LLHUDManager::getInstance()->mHUDEffects.begin() + i); i--; continue; } @@ -197,7 +216,7 @@ void LLHUDManager::processViewerEffect(LLMessageSystem *mesgsys, void **user_dat { if (cur_effectp->getType() != effect_type) { - llwarns << "Viewer effect update doesn't match old type!" << llendl; + LL_WARNS() << "Viewer effect update doesn't match old type!" << LL_ENDL; } effectp = cur_effectp; break; @@ -218,10 +237,10 @@ void LLHUDManager::processViewerEffect(LLMessageSystem *mesgsys, void **user_dat } else { - llwarns << "Received viewer effect of type " << effect_type << " which isn't really an effect!" << llendl; + LL_WARNS() << "Received viewer effect of type " << effect_type << " which isn't really an effect!" << LL_ENDL; } } - //llinfos << "Got viewer effect: " << effect_id << llendl; + //LL_INFOS() << "Got viewer effect: " << effect_id << LL_ENDL; } diff --git a/indra/newview/llhudmanager.h b/indra/newview/llhudmanager.h index 615eb93a27..f005ba0c73 100644 --- a/indra/newview/llhudmanager.h +++ b/indra/newview/llhudmanager.h @@ -36,7 +36,6 @@ // Responsible for managing all HUD elements. #include "llhudobject.h" -#include "lldarray.h" class LLViewerObject; class LLHUDEffect; @@ -65,7 +64,7 @@ class LLHUDManager : public LLSingleton static LLColor4 sChildColor; protected: - LLDynamicArrayPtr > mHUDEffects; + std::vector > mHUDEffects; }; #endif // LL_LLHUDMANAGER_H diff --git a/indra/newview/llhudnametag.cpp b/indra/newview/llhudnametag.cpp index cc016c07ad..3d712439ae 100644 --- a/indra/newview/llhudnametag.cpp +++ b/indra/newview/llhudnametag.cpp @@ -112,7 +112,7 @@ LLHUDNameTag::LLHUDNameTag(const U8 type) { LLPointer ptr(this); sTextObjects.insert(ptr); - mBubbleImage = LLUI::getUIImage("Rounded_Rect.png"); + mBubbleImage = LLUI::getUIImage("Rounded_Rect"); } LLHUDNameTag::~LLHUDNameTag() @@ -120,7 +120,7 @@ LLHUDNameTag::~LLHUDNameTag() } -BOOL LLHUDNameTag::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, LLVector3& intersection, BOOL debug_render) +BOOL LLHUDNameTag::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, LLVector4a& intersection, BOOL debug_render) { if (!mVisible || mHidden) { @@ -218,16 +218,23 @@ BOOL LLHUDNameTag::lineSegmentIntersect(const LLVector3& start, const LLVector3& gGL.vertex3fv(v[2].mV); gGL.end(); } - - LLVector3 dir = end-start; + LLVector4a dir; + dir.setSub(end,start); F32 a, b, t; - if (LLTriangleRayIntersect(v[0], v[1], v[2], start, dir, a, b, t, FALSE) || - LLTriangleRayIntersect(v[2], v[3], v[0], start, dir, a, b, t, FALSE) ) + LLVector4a v0,v1,v2,v3; + v0.load3(v[0].mV); + v1.load3(v[1].mV); + v2.load3(v[2].mV); + v3.load3(v[3].mV); + + if (LLTriangleRayIntersect(v0, v1, v2, start, dir, a, b, t) || + LLTriangleRayIntersect(v2, v3, v0, start, dir, a, b, t) ) { if (t <= 1.f) { - intersection = start + dir*t; + dir.mul(t); + intersection.setAdd(start, dir); return TRUE; } } @@ -274,8 +281,8 @@ void LLHUDNameTag::renderText(BOOL for_select) gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE); } - LLGLState gls_blend(GL_BLEND, for_select ? FALSE : TRUE); - LLGLState gls_alpha(GL_ALPHA_TEST, for_select ? FALSE : TRUE); + LLGLState gls_blend(for_select ? FALSE : TRUE); + LLGLState gls_alpha(for_select ? FALSE : TRUE); gGL.setSceneBlendType(LLRender::BT_ALPHA); //Workaround avoiding inheriting stale blendstate from... something. LLColor4 shadow_color(0.f, 0.f, 0.f, 1.f); @@ -297,29 +304,14 @@ void LLHUDNameTag::renderText(BOOL for_select) mOffsetY = lltrunc(mHeight * ((mVertAlignment == ALIGN_VERT_CENTER) ? 0.5f : 1.f)); + LLUIImagePtr imagep = mBubbleImage; + // *TODO: make this a per-text setting static const LLCachedControl background_chat_color("BackgroundChatColor", LLColor4(0,0,0,1.f)); static const LLCachedControl chat_bubble_opacity("ChatBubbleOpacity", .5); LLColor4 bg_color = background_chat_color; bg_color.setAlpha(chat_bubble_opacity.get() * alpha_factor); - // maybe a no-op? - //const S32 border_height = 16; - //const S32 border_width = 16; - const S32 border_height = 8; - const S32 border_width = 8; - - // *TODO move this into helper function - F32 border_scale = 1.f; - - if (border_height * 2 > mHeight) - { - border_scale = (F32)mHeight / ((F32)border_height * 2.f); - } - if (border_width * 2 > mWidth) - { - border_scale = llmin(border_scale, (F32)mWidth / ((F32)border_width * 2.f)); - } // scale screen size of borders down //RN: for now, text on hud objects is never occluded @@ -329,34 +321,42 @@ void LLHUDNameTag::renderText(BOOL for_select) LLViewerCamera::getInstance()->getPixelVectors(mPositionAgent, y_pixel_vec, x_pixel_vec); - LLVector2 border_scale_vec((F32)border_width / (F32)mBubbleImage->getTextureWidth(), (F32)border_height / (F32)mBubbleImage->getTextureHeight()); LLVector3 width_vec = mWidth * x_pixel_vec; LLVector3 height_vec = mHeight * y_pixel_vec; - LLVector3 scaled_border_width = (F32)llfloor(border_scale * (F32)border_width) * x_pixel_vec; - LLVector3 scaled_border_height = (F32)llfloor(border_scale * (F32)border_height) * y_pixel_vec; mRadius = (width_vec + height_vec).magVec() * 0.5f; LLCoordGL screen_pos; LLViewerCamera::getInstance()->projectPosAgentToScreen(mPositionAgent, screen_pos, FALSE); - LLVector2 screen_offset; -// if (!mUseBubble) -// { -// screen_offset = mPositionOffset; -// } -// else -// { - screen_offset = updateScreenPos(mPositionOffset); -// } + LLVector2 screen_offset = updateScreenPos(mPositionOffset); LLVector3 render_position = mPositionAgent + (x_pixel_vec * screen_offset.mV[VX]) + (y_pixel_vec * screen_offset.mV[VY]); -// if (mUseBubble) + LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE); + LLRect screen_rect; + screen_rect.setCenterAndSize(0, static_cast(lltrunc(-mHeight / 2 + mOffsetY)), static_cast(lltrunc(mWidth)), static_cast(lltrunc(mHeight))); + imagep->draw3D(render_position, x_pixel_vec, y_pixel_vec, screen_rect, bg_color); + if (mLabelSegments.size()) + { + LLUIImagePtr rect_top_image = LLUI::getUIImage("Rounded_Rect_Top"); + LLRect label_top_rect = screen_rect; + const S32 label_height = ll_round((mFontp->getLineHeight() * (F32)mLabelSegments.size() + (VERTICAL_PADDING / 3.f))); + label_top_rect.mBottom = label_top_rect.mTop - label_height; + LLColor4 label_top_color = text_color; + label_top_color.mV[VALPHA] = chat_bubble_opacity * alpha_factor; + + rect_top_image->draw3D(render_position, x_pixel_vec, y_pixel_vec, label_top_rect, label_top_color); + } + + BOOL outside_width = llabs(mPositionOffset.mV[VX]) > mWidth * 0.5f; + BOOL outside_height = llabs(mPositionOffset.mV[VY] + (mVertAlignment == ALIGN_VERT_TOP ? mHeight * 0.5f : 0.f)) > mHeight * (mVertAlignment == ALIGN_VERT_TOP ? mHeight * 0.75f : 0.5f); + + // draw line segments pointing to parent object + if (!mOffscreen && (outside_width || outside_height)) { - LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE); LLUI::pushMatrix(); { LLVector3 bg_pos = render_position @@ -364,46 +364,9 @@ void LLHUDNameTag::renderText(BOOL for_select) - (width_vec / 2.f) - (height_vec); LLUI::translate(bg_pos.mV[VX], bg_pos.mV[VY], bg_pos.mV[VZ]); - - if (for_select) - { - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - S32 name = mSourceObject->mGLName; - LLColor4U coloru((U8)(name >> 16), (U8)(name >> 8), (U8)name); - gGL.color4ubv(coloru.mV); - gl_segmented_rect_3d_tex(border_scale_vec, scaled_border_width, scaled_border_height, width_vec, height_vec); - LLUI::popMatrix(); - return; - } - else - { - gGL.getTexUnit(0)->bind(mBubbleImage->getImage()); - - gGL.color4fv(bg_color.mV); - gl_segmented_rect_3d_tex(border_scale_vec, scaled_border_width, scaled_border_height, width_vec, height_vec); - - if ( mLabelSegments.size()) - { - LLUI::pushMatrix(); - { - gGL.color4f(text_color.mV[VX], text_color.mV[VY], text_color.mV[VZ], chat_bubble_opacity * alpha_factor); - LLVector3 label_height = (mFontp->getLineHeight() * mLabelSegments.size() + (VERTICAL_PADDING / 3.f)) * y_pixel_vec; - LLVector3 label_offset = height_vec - label_height; - LLUI::translate(label_offset.mV[VX], label_offset.mV[VY], label_offset.mV[VZ]); - gl_segmented_rect_3d_tex_top(border_scale_vec, scaled_border_width, scaled_border_height, width_vec, label_height); - } - LLUI::popMatrix(); - } - } - - BOOL outside_width = llabs(mPositionOffset.mV[VX]) > mWidth * 0.5f; - BOOL outside_height = llabs(mPositionOffset.mV[VY] + (mVertAlignment == ALIGN_VERT_TOP ? mHeight * 0.5f : 0.f)) > mHeight * (mVertAlignment == ALIGN_VERT_TOP ? mHeight * 0.75f : 0.5f); - - // draw line segments pointing to parent object - if (!mOffscreen && (outside_width || outside_height)) + + /*LLUI::pushMatrix(); { - LLUI::pushMatrix(); - { gGL.color4fv(bg_color.mV); LLVector3 target_pos = -1.f * (mPositionOffset.mV[VX] * x_pixel_vec + mPositionOffset.mV[VY] * y_pixel_vec); target_pos += (width_vec / 2.f); @@ -412,67 +375,65 @@ void LLHUDNameTag::renderText(BOOL for_select) target_pos -= 6.f * y_pixel_vec; LLUI::translate(target_pos.mV[VX], target_pos.mV[VY], target_pos.mV[VZ]); gl_segmented_rect_3d_tex(border_scale_vec, 3.f * x_pixel_vec, 3.f * y_pixel_vec, 6.f * x_pixel_vec, 6.f * y_pixel_vec); - } - LLUI::popMatrix(); - - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - LLGLDepthTest gls_depth(mZCompare ? GL_TRUE : GL_FALSE, GL_FALSE); - - LLVector3 box_center_offset; - box_center_offset = (width_vec * 0.5f) + (height_vec * 0.5f); - LLUI::translate(box_center_offset.mV[VX], box_center_offset.mV[VY], box_center_offset.mV[VZ]); - gGL.color4fv(bg_color.mV); - LLUI::setLineWidth(2.0); - gGL.begin(LLRender::LINES); + } + LLUI::popMatrix();*/ + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + LLGLDepthTest gls_depth(mZCompare ? GL_TRUE : GL_FALSE, GL_FALSE); + + LLVector3 box_center_offset; + box_center_offset = (width_vec * 0.5f) + (height_vec * 0.5f); + LLUI::translate(box_center_offset.mV[VX], box_center_offset.mV[VY], box_center_offset.mV[VZ]); + gGL.color4fv(bg_color.mV); + LLUI::setLineWidth(2.0); + gGL.begin(LLRender::LINES); + { + if (outside_width) { - if (outside_width) + LLVector3 vert; + // draw line in x then y + if (mPositionOffset.mV[VX] < 0.f) { - LLVector3 vert; - // draw line in x then y - if (mPositionOffset.mV[VX] < 0.f) - { - // start at right edge - vert = width_vec * 0.5f; - gGL.vertex3fv(vert.mV); - } - else - { - // start at left edge - vert = width_vec * -0.5f; - gGL.vertex3fv(vert.mV); - } - vert = -mPositionOffset.mV[VX] * x_pixel_vec; + // start at right edge + vert = width_vec * 0.5f; gGL.vertex3fv(vert.mV); + } + else + { + // start at left edge + vert = width_vec * -0.5f; gGL.vertex3fv(vert.mV); - vert -= mPositionOffset.mV[VY] * y_pixel_vec; - vert -= ((mVertAlignment == ALIGN_VERT_TOP) ? (height_vec * 0.5f) : LLVector3::zero); + } + vert = -mPositionOffset.mV[VX] * x_pixel_vec; + gGL.vertex3fv(vert.mV); + gGL.vertex3fv(vert.mV); + vert -= mPositionOffset.mV[VY] * y_pixel_vec; + vert -= ((mVertAlignment == ALIGN_VERT_TOP) ? (height_vec * 0.5f) : LLVector3::zero); + gGL.vertex3fv(vert.mV); + } + else + { + LLVector3 vert; + // draw line in y then x + if (mPositionOffset.mV[VY] < 0.f) + { + // start at top edge + vert = (height_vec * 0.5f) - (mPositionOffset.mV[VX] * x_pixel_vec); gGL.vertex3fv(vert.mV); } else { - LLVector3 vert; - // draw line in y then x - if (mPositionOffset.mV[VY] < 0.f) - { - // start at top edge - vert = (height_vec * 0.5f) - (mPositionOffset.mV[VX] * x_pixel_vec); - gGL.vertex3fv(vert.mV); - } - else - { - // start at bottom edge - vert = (height_vec * -0.5f) - (mPositionOffset.mV[VX] * x_pixel_vec); - gGL.vertex3fv(vert.mV); - } - vert = -mPositionOffset.mV[VY] * y_pixel_vec - mPositionOffset.mV[VX] * x_pixel_vec; - vert -= ((mVertAlignment == ALIGN_VERT_TOP) ? (height_vec * 0.5f) : LLVector3::zero); + // start at bottom edge + vert = (height_vec * -0.5f) - (mPositionOffset.mV[VX] * x_pixel_vec); gGL.vertex3fv(vert.mV); } + vert = -mPositionOffset.mV[VY] * y_pixel_vec - mPositionOffset.mV[VX] * x_pixel_vec; + vert -= ((mVertAlignment == ALIGN_VERT_TOP) ? (height_vec * 0.5f) : LLVector3::zero); + gGL.vertex3fv(vert.mV); } - gGL.end(); - LLUI::setLineWidth(1.0); - } + gGL.end(); + LLUI::setLineWidth(1.0); } LLUI::popMatrix(); } @@ -712,7 +673,7 @@ void LLHUDNameTag::updateVisibility() if (!mSourceObject) { - //llwarns << "LLHUDNameTag::updateScreenPos -- mSourceObject is NULL!" << llendl; + //LL_WARNS() << "LLHUDNameTag::updateScreenPos -- mSourceObject is NULL!" << LL_ENDL; mVisible = TRUE; sVisibleTextObjects.push_back(LLPointer (this)); return; @@ -1004,7 +965,7 @@ void LLHUDNameTag::updateAll() // { // continue; // } - (*this_object_it)->mPositionOffset = lerp((*this_object_it)->mPositionOffset, (*this_object_it)->mTargetPositionOffset, LLCriticalDamp::getInterpolant(POSITION_DAMPING_TC)); + (*this_object_it)->mPositionOffset = lerp((*this_object_it)->mPositionOffset, (*this_object_it)->mTargetPositionOffset, LLSmoothInterpolation::getInterpolant(POSITION_DAMPING_TC)); } } @@ -1095,15 +1056,16 @@ void LLHUDNameTag::reshape() F32 LLHUDNameTag::LLHUDTextSegment::getWidth(const LLFontGL* font) { - std::map::iterator iter = mFontWidthMap.find(font); - if (iter != mFontWidthMap.end()) + // Singu note: Reworked hotspot. Less indirection + if (mFontWidthMap[0].first == font) { - return iter->second; + return mFontWidthMap[0].second; } - else + else if (mFontWidthMap[1].first == font) { - F32 width = font->getWidthF32(mText.c_str()); - mFontWidthMap[font] = width; - return width; + return mFontWidthMap[1].second; } + F32 width = font->getWidthF32(mText.c_str()); + mFontWidthMap[mFontWidthMap[0].first != nullptr] = std::make_pair(font, width); + return width; } diff --git a/indra/newview/llhudnametag.h b/indra/newview/llhudnametag.h index 8c6185272c..bc48d788e9 100644 --- a/indra/newview/llhudnametag.h +++ b/indra/newview/llhudnametag.h @@ -63,14 +63,14 @@ class LLHUDNameTag : public LLHUDObject {} F32 getWidth(const LLFontGL* font); const LLWString& getText() const { return mText; } - void clearFontWidthMap() { mFontWidthMap.clear(); } + void clearFontWidthMap() { mFontWidthMap[0].first = nullptr; mFontWidthMap[1].first = nullptr; } LLColor4 mColor; LLFontGL::StyleFlags mStyle; const LLFontGL* mFont; private: LLWString mText; - std::map mFontWidthMap; + std::pair mFontWidthMap[2]; }; public: @@ -126,7 +126,7 @@ class LLHUDNameTag : public LLHUDObject void setHidden( BOOL hide ) { mHidden = hide; } void shift(const LLVector3& offset); - BOOL lineSegmentIntersect(const LLVector3& start, const LLVector3& end, LLVector3& intersection, BOOL debug_render = FALSE); + BOOL lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, LLVector4a& intersection, BOOL debug_render = FALSE); static void shiftAll(const LLVector3& offset); static void addPickable(std::set &pick_list); diff --git a/indra/newview/llhudobject.cpp b/indra/newview/llhudobject.cpp index b5aafcd03c..613c70b219 100644 --- a/indra/newview/llhudobject.cpp +++ b/indra/newview/llhudobject.cpp @@ -131,7 +131,7 @@ void LLHUDObject::cleanupHUDObjects() (*object_it)->markDead(); if ((*object_it)->getNumRefs() > 1) { - llinfos << "LLHUDObject " << (LLHUDObject *)(*object_it) << " type " << (S32)(*object_it)->getType() << " has " << (*object_it)->getNumRefs() << " refs!" << llendl; + LL_INFOS() << "LLHUDObject " << (LLHUDObject *)(*object_it) << " type " << (S32)(*object_it)->getType() << " has " << (*object_it)->getNumRefs() << " refs!" << LL_ENDL; } } sHUDObjects.clear(); @@ -154,7 +154,7 @@ LLHUDObject *LLHUDObject::addHUDObject(const U8 type) hud_objectp = new LLHUDNameTag(type); break; default: - llwarns << "Unknown type of hud object:" << (U32) type << llendl; + LL_WARNS() << "Unknown type of hud object:" << (U32) type << LL_ENDL; } if (hud_objectp) { @@ -247,7 +247,7 @@ LLHUDEffect *LLHUDObject::addHUDEffect(const U8 type) hud_objectp = new LLHUDEffectPointAt(type); break; default: - llwarns << "Unknown type of hud effect:" << (U32) type << llendl; + LL_WARNS() << "Unknown type of hud effect:" << (U32) type << LL_ENDL; } if (hud_objectp) @@ -257,12 +257,12 @@ LLHUDEffect *LLHUDObject::addHUDEffect(const U8 type) return hud_objectp; } -static LLFastTimer::DeclareTimer FTM_HUD_UPDATE("Update Hud"); +static LLTrace::BlockTimerStatHandle FTM_HUD_UPDATE("Update Hud"); // static void LLHUDObject::updateAll() { - LLFastTimer ftm(FTM_HUD_UPDATE); + LL_RECORD_BLOCK_TIME(FTM_HUD_UPDATE); LLHUDText::updateAll(); LLHUDIcon::updateAll(); LLHUDNameTag::updateAll(); @@ -289,7 +289,7 @@ void LLHUDObject::renderAll() } } - LLVertexBuffer::unbind(); + //LLVertexBuffer::unbind(); } // static diff --git a/indra/newview/llhudrender.cpp b/indra/newview/llhudrender.cpp index e9b720d249..4c41737053 100644 --- a/indra/newview/llhudrender.cpp +++ b/indra/newview/llhudrender.cpp @@ -56,8 +56,6 @@ void hud_render_utf8text(const std::string &str, const LLVector3 &pos_agent, hud_render_text(wstr, pos_agent, font, style, shadow, x_offset, y_offset, color, orthographic); } -int glProjectf(const LLVector3& object, const F32* modelview, const F32* projection, const LLRect& viewport, LLVector3& windowCoordinate); - void hud_render_text(const LLWString &wstr, const LLVector3 &pos_agent, const LLFontGL &font, const U8 style, @@ -115,7 +113,7 @@ void hud_render_text(const LLWString &wstr, const LLVector3 &pos_agent, const LLRect& world_view_rect = gViewerWindow->getWorldViewRectRaw(); - glProjectf(render_pos, gGLModelView, gGLProjection, world_view_rect, window_coordinates); + gGL.projectf(render_pos, gGLModelView, gGLProjection, world_view_rect, window_coordinates); //fonts all render orthographically, set up projection`` gGL.matrixMode(LLRender::MM_PROJECTION); diff --git a/indra/newview/llhudtext.cpp b/indra/newview/llhudtext.cpp index 4f4d3b4486..d456584cf4 100644 --- a/indra/newview/llhudtext.cpp +++ b/indra/newview/llhudtext.cpp @@ -134,9 +134,9 @@ void LLHUDText::renderText() return; } - gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE); - LLGLState gls_blend(GL_BLEND, TRUE); - LLGLState gls_alpha(GL_ALPHA_TEST, TRUE); + gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE); + LLGLEnable gls_blend; + LLGLEnable gls_alpha; LLColor4 shadow_color(0.f, 0.f, 0.f, 1.f); F32 alpha_factor = 1.f; @@ -158,7 +158,7 @@ void LLHUDText::renderText() mOffsetY = lltrunc(mHeight * ((mVertAlignment == ALIGN_VERT_CENTER) ? 0.5f : 1.f)); // *TODO: cache this image - LLUIImagePtr imagep = LLUI::getUIImage("rounded_square.tga"); + LLUIImagePtr imagep = LLUI::getUIImage("Rounded_Square"); // *TODO: make this a per-text setting static const LLCachedControl background_chat_color("BackgroundChatColor", LLColor4(0,0,0,1.f)); @@ -273,7 +273,7 @@ void LLHUDText::setString(const std::string &text_utf8) { if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) RlvUtil::filterLocation(text); - if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES) || gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS)) RlvUtil::filterNames(text); } else @@ -397,7 +397,7 @@ void LLHUDText::updateVisibility() if (!mSourceObject) { - //llwarns << "LLHUDText::updateScreenPos -- mSourceObject is NULL!" << llendl; + //LL_WARNS() << "LLHUDText::updateScreenPos -- mSourceObject is NULL!" << LL_ENDL; mVisible = TRUE; if (mOnHUDAttachment) { @@ -613,12 +613,12 @@ void LLHUDText::markDead() void LLHUDText::renderAllHUD() { - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - LLGLState::checkClientArrays(); + LLGLStateValidator::checkStates(); + LLGLStateValidator::checkTextureChannels(); + LLGLStateValidator::checkClientArrays(); { - LLGLEnable color_mat(GL_COLOR_MATERIAL); + LLGLEnable color_mat; LLGLDepthTest depth(GL_FALSE, GL_FALSE); VisibleTextObjectIterator text_it; @@ -633,9 +633,9 @@ void LLHUDText::renderAllHUD() LLVertexBuffer::unbind(); - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - LLGLState::checkClientArrays(); + LLGLStateValidator::checkStates(); + LLGLStateValidator::checkTextureChannels(); + LLGLStateValidator::checkClientArrays(); } void LLHUDText::shiftAll(const LLVector3& offset) @@ -674,17 +674,18 @@ void LLHUDText::reshape() F32 LLHUDText::LLHUDTextSegment::getWidth(const LLFontGL* font) { - std::map::iterator iter = mFontWidthMap.find(font); - if (iter != mFontWidthMap.end()) + // Singu note: Reworked hotspot. Less indirection + if (mFontWidthMap[0].first == font) { - return iter->second; + return mFontWidthMap[0].second; } - else + else if (mFontWidthMap[1].first == font) { - F32 width = font->getWidthF32(mText.c_str()); - mFontWidthMap[font] = width; - return width; + return mFontWidthMap[1].second; } + F32 width = font->getWidthF32(mText.c_str()); + mFontWidthMap[mFontWidthMap[0].first != nullptr] = std::make_pair(font, width); + return width; } // [RLVa:KB] - Checked: 2010-03-27 (RLVa-1.4.0a) | Added: RLVa-1.0.0f diff --git a/indra/newview/llhudtext.h b/indra/newview/llhudtext.h index 68450753ca..9ee224954c 100644 --- a/indra/newview/llhudtext.h +++ b/indra/newview/llhudtext.h @@ -61,14 +61,14 @@ class LLHUDText : public LLHUDObject {} F32 getWidth(const LLFontGL* font); const LLWString& getText() const { return mText; } - void clearFontWidthMap() { mFontWidthMap.clear(); } + void clearFontWidthMap() { mFontWidthMap[0].first = nullptr; mFontWidthMap[1].first = nullptr; } LLColor4 mColor; LLFontGL::StyleFlags mStyle; const LLFontGL* mFont; private: LLWString mText; - std::map mFontWidthMap; + std::pair mFontWidthMap[2]; }; public: diff --git a/indra/newview/llimpanel.cpp b/indra/newview/llimpanel.cpp index 7e74326e0e..2e563cf919 100644 --- a/indra/newview/llimpanel.cpp +++ b/indra/newview/llimpanel.cpp @@ -33,59 +33,51 @@ #include "llimpanel.h" -#include "indra_constants.h" -#include "llfocusmgr.h" -#include "llfontgl.h" -#include "llrect.h" -#include "llerror.h" -#include "llstring.h" -#include "message.h" -#include "lltextbox.h" -#include "llnotificationsutil.h" - +#include "ascentkeyword.h" #include "llagent.h" +#include "llagentcamera.h" +#include "llagentui.h" +#include "llautoreplace.h" #include "llavataractions.h" +#include "llavatarnamecache.h" #include "llbutton.h" -#include "llcallingcard.h" -#include "llchat.h" -#include "llconsole.h" -#include "llgroupactions.h" +#include "llcombobox.h" +#include "llfloateravatarpicker.h" #include "llfloaterchat.h" +#include "llfloaterinventory.h" +#include "llfloaterreporter.h" +#include "llfloaterwebcontent.h" // For web browser display of logs +#include "llgroupactions.h" +#include "llhttpclient.h" #include "llimview.h" #include "llinventory.h" #include "llinventoryfunctions.h" -#include "llfloaterinventory.h" -#include "llcheckboxctrl.h" -#include "llkeyboard.h" #include "lllineeditor.h" -#include "llnotify.h" +#include "llmutelist.h" +#include "llnotificationsutil.h" #include "llparticipantlist.h" -#include "llresmgr.h" #include "llspeakers.h" +#include "llstylemap.h" #include "lltrans.h" -#include "lltabcontainer.h" +#include "lluictrlfactory.h" +#include "llversioninfo.h" +#include "llviewerobjectlist.h" #include "llviewertexteditor.h" -#include "llviewermessage.h" #include "llviewerstats.h" -#include "llviewercontrol.h" -#include "lluictrlfactory.h" #include "llviewerwindow.h" #include "llvoicechannel.h" -#include "lllogchat.h" -#include "llweb.h" -#include "llhttpclient.h" -#include "llmutelist.h" -#include "llstylemap.h" -#include "ascentkeyword.h" -#include "boost/algorithm/string.hpp" +#include +#include -// [RLVa:KB] -#include "rlvhandler.h" +// [RLVa:KB] - Checked: 2013-05-10 (RLVa-1.4.9) +#include "rlvactions.h" +#include "rlvcommon.h" // [/RLVa:KB] +BOOL is_agent_mappable(const LLUUID& agent_id); // For map stalkies + class AIHTTPTimeoutPolicy; -extern AIHTTPTimeoutPolicy startConferenceChatResponder_timeout; extern AIHTTPTimeoutPolicy sessionInviteResponder_timeout; // @@ -124,7 +116,7 @@ void session_starter_helper( msg->addU32Fast(_PREHASH_Timestamp, NO_TIMESTAMP); // no timestamp necessary std::string name; - gAgent.buildFullname(name); + LLAgentUI::buildFullname(name); msg->addStringFast(_PREHASH_FromAgentName, name); msg->addStringFast(_PREHASH_Message, LLStringUtil::null); @@ -188,10 +180,10 @@ class LLStartConferenceChatResponder : public LLHTTPClient::ResponderIgnoreBody mAgents = agents_to_invite; } - /*virtual*/ void error(U32 statusNum, const std::string& reason) + /*virtual*/ void httpFailure() { //try an "old school" way. - if ( statusNum == 400 ) + if ( mStatus == 400 ) { start_deprecated_conference_chat( mTempSessionID, @@ -207,9 +199,7 @@ class LLStartConferenceChatResponder : public LLHTTPClient::ResponderIgnoreBody //and it is not worth the effort switching over all //the possible different language translations } - - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return startConferenceChatResponder_timeout; } - /*virtual*/ char const* getName(void) const { return "LLStartConferenceChatResponder"; } + /*virtual*/ char const* getName() const { return "LLStartConferenceChatResponder"; } private: LLUUID mTempSessionID; @@ -224,7 +214,7 @@ class LLStartConferenceChatResponder : public LLHTTPClient::ResponderIgnoreBody bool send_start_session_messages( const LLUUID& temp_session_id, const LLUUID& other_participant_id, - const LLDynamicArray& ids, + const uuid_vec_t& ids, EInstantMessage dialog) { if ( dialog == IM_SESSION_GROUP_START ) @@ -234,35 +224,28 @@ bool send_start_session_messages( other_participant_id, dialog); - switch(dialog) - { - case IM_SESSION_GROUP_START: - gMessageSystem->addBinaryDataFast( - _PREHASH_BinaryBucket, - EMPTY_BINARY_BUCKET, - EMPTY_BINARY_BUCKET_SIZE); - break; - default: - break; - } + gMessageSystem->addBinaryDataFast( + _PREHASH_BinaryBucket, + EMPTY_BINARY_BUCKET, + EMPTY_BINARY_BUCKET_SIZE); gAgent.sendReliableMessage(); return true; } else if ( dialog == IM_SESSION_CONFERENCE_START ) { + if (ids.empty()) return true; LLSD agents; for (int i = 0; i < (S32) ids.size(); i++) { - agents.append(ids.get(i)); + agents.append(ids.at(i)); } //we have a new way of starting conference calls now LLViewerRegion* region = gAgent.getRegion(); - if (region) + std::string url(region ? region->getCapability("ChatSessionRequest") : ""); + if (!url.empty()) { - std::string url = region->getCapability( - "ChatSessionRequest"); LLSD data; data["method"] = "start conference"; data["session-id"] = temp_session_id; @@ -296,150 +279,90 @@ bool send_start_session_messages( // LLFloaterIMPanel // LLFloaterIMPanel::LLFloaterIMPanel( - const std::string& session_label, + const std::string& log_label, const LLUUID& session_id, const LLUUID& other_participant_id, - EInstantMessage dialog) : - LLFloater(session_label, LLRect(), session_label), + const EInstantMessage& dialog, + const uuid_vec_t& ids) : + LLFloater(log_label, LLRect(), log_label), + mStartCallOnInitialize(false), mInputEditor(NULL), mHistoryEditor(NULL), + mSessionInitialized(false), + mSessionStartMsgPos({0, 0}), + mSessionType(P2P_SESSION), mSessionUUID(session_id), - mVoiceChannel(NULL), - mSessionInitialized(FALSE), - mSessionStartMsgPos(0), + mLogLabel(log_label), + mQueuedMsgsForInit(), mOtherParticipantUUID(other_participant_id), + mInitialTargetIDs(ids), mDialog(dialog), - mTyping(FALSE), - mOtherTyping(FALSE), + mTyping(false), mTypingLineStartIndex(0), - mSentTypingState(TRUE), + mOtherTyping(false), + mOtherTypingName(), mNumUnreadMessages(0), - mShowSpeakersOnConnect(TRUE), - mStartCallOnInitialize(false), - mTextIMPossible(TRUE), - mProfileButtonEnabled(TRUE), - mCallBackEnabled(TRUE), + mSentTypingState(true), + mShowSpeakersOnConnect(true), + mDing(false), + mRPMode(false), + mTextIMPossible(true), + mCallBackEnabled(true), mSpeakers(NULL), mSpeakerPanel(NULL), - mFirstKeystrokeTimer(), - mLastKeystrokeTimer() -{ - if(mOtherParticipantUUID.isNull()) - { - llwarns << "Other participant is NULL" << llendl; - } - - init(session_label); -} - -LLFloaterIMPanel::LLFloaterIMPanel( - const std::string& session_label, - const LLUUID& session_id, - const LLUUID& other_participant_id, - const LLDynamicArray& ids, - EInstantMessage dialog) : - LLFloater(session_label, LLRect(), session_label), - mInputEditor(NULL), - mHistoryEditor(NULL), - mSessionUUID(session_id), mVoiceChannel(NULL), - mSessionInitialized(FALSE), - mSessionStartMsgPos(0), - mOtherParticipantUUID(other_participant_id), - mDialog(dialog), - mTyping(FALSE), - mOtherTyping(FALSE), - mTypingLineStartIndex(0), - mSentTypingState(TRUE), - mShowSpeakersOnConnect(TRUE), - mStartCallOnInitialize(false), - mTextIMPossible(TRUE), - mProfileButtonEnabled(TRUE), - mCallBackEnabled(TRUE), - mSpeakers(NULL), - mSpeakerPanel(NULL), mFirstKeystrokeTimer(), mLastKeystrokeTimer() { - if(mOtherParticipantUUID.isNull()) + if (mOtherParticipantUUID.isNull()) { - llwarns << "Other participant is NULL" << llendl; + LL_WARNS() << "Other participant is NULL" << LL_ENDL; } - mSessionInitialTargetIDs = ids; - init(session_label); -} - - -void LLFloaterIMPanel::init(const std::string& session_label) -{ // set P2P type by default - mSessionType = P2P_SESSION; - - mSessionLabel = session_label; + static LLCachedControl concise_im("UseConciseIMButtons"); + std::string xml_filename = concise_im ? "floater_instant_message_concisebuttons.xml" : "floater_instant_message.xml"; - // [Ansariel: Display name support] - mProfileButtonEnabled = FALSE; - // [/Ansariel: Display name support] - static LLCachedControl concise_im("UseConciseIMButtons"); - static LLCachedControl concise_group("UseConciseGroupChatButtons"); - static LLCachedControl concise_conf("UseConciseConferenceButtons"); - std::string xml_filename; switch(mDialog) { case IM_SESSION_GROUP_START: - mFactoryMap["active_speakers_panel"] = LLCallbackMap(createSpeakersPanel, this); - xml_filename = concise_group ? "floater_instant_message_group_concisebuttons.xml" : "floater_instant_message_group.xml"; - mVoiceChannel = new LLVoiceChannelGroup(mSessionUUID, mSessionLabel); - break; case IM_SESSION_INVITE: - mFactoryMap["active_speakers_panel"] = LLCallbackMap(createSpeakersPanel, this); + case IM_SESSION_CONFERENCE_START: + mCommitCallbackRegistrar.add("FlipDing", [=](LLUICtrl*, const LLSD&) { mDing = !mDing; }); + // determine whether it is group or conference session if (gAgent.isInGroup(mSessionUUID)) { - xml_filename = concise_group ? "floater_instant_message_group_concisebuttons.xml" : "floater_instant_message_group.xml"; + static LLCachedControl concise("UseConciseGroupChatButtons"); + xml_filename = concise ? "floater_instant_message_group_concisebuttons.xml" : "floater_instant_message_group.xml"; + bool support = boost::starts_with(mLogLabel, LLTrans::getString("SHORT_APP_NAME") + ' '); + mSessionType = support ? SUPPORT_SESSION : GROUP_SESSION; } - else // must be invite to ad hoc IM + else { - xml_filename = concise_conf ? "floater_instant_message_ad_hoc_concisebuttons.xml" : "floater_instant_message_ad_hoc.xml"; + static LLCachedControl concise("UseConciseConferenceButtons"); + xml_filename = concise ? "floater_instant_message_ad_hoc_concisebuttons.xml" : "floater_instant_message_ad_hoc.xml"; + mSessionType = ADHOC_SESSION; } - mVoiceChannel = new LLVoiceChannelGroup(mSessionUUID, mSessionLabel); - break; - case IM_SESSION_P2P_INVITE: - xml_filename = concise_im ? "floater_instant_message_concisebuttons.xml" : "floater_instant_message.xml"; - mVoiceChannel = new LLVoiceChannelP2P(mSessionUUID, mSessionLabel, mOtherParticipantUUID); - break; - case IM_SESSION_CONFERENCE_START: mFactoryMap["active_speakers_panel"] = LLCallbackMap(createSpeakersPanel, this); - xml_filename = concise_conf ? "floater_instant_message_ad_hoc_concisebuttons.xml" : "floater_instant_message_ad_hoc.xml"; - mVoiceChannel = new LLVoiceChannelGroup(mSessionUUID, mSessionLabel); + mVoiceChannel = new LLVoiceChannelGroup(mSessionUUID, mLogLabel); break; + default: + LL_WARNS() << "Unknown session type: " << mDialog << LL_ENDL; + // fallthrough, Singu TODO: Find out which cases this happens in, seems to only be P2P, though. // just received text from another user case IM_NOTHING_SPECIAL: - - xml_filename = concise_im ? "floater_instant_message_concisebuttons.xml" : "floater_instant_message.xml"; - mTextIMPossible = LLVoiceClient::getInstance()->isSessionTextIMPossible(mSessionUUID); - mProfileButtonEnabled = LLVoiceClient::getInstance()->isParticipantAvatar(mSessionUUID); mCallBackEnabled = LLVoiceClient::getInstance()->isSessionCallBackPossible(mSessionUUID); - - mVoiceChannel = new LLVoiceChannelP2P(mSessionUUID, mSessionLabel, mOtherParticipantUUID); - break; - default: - llwarns << "Unknown session type" << llendl; - xml_filename = concise_im ? "floater_instant_message_concisebuttons.xml" : "floater_instant_message.xml"; + // fallthrough + case IM_SESSION_P2P_INVITE: + mVoiceChannel = new LLVoiceChannelP2P(mSessionUUID, mLogLabel, mOtherParticipantUUID); + LLAvatarTracker::instance().addParticularFriendObserver(mOtherParticipantUUID, this); + LLMuteList::instance().addObserver(this); + mDing = gSavedSettings.getBOOL("LiruNewMessageSoundIMsOn"); break; } - if ( (IM_NOTHING_SPECIAL != mDialog) && (IM_SESSION_P2P_INVITE != mDialog) ) - { - // determine whether it is group or conference session - if (gAgent.isInGroup(mSessionUUID)) - mSessionType = GROUP_SESSION; - else - mSessionType = ADHOC_SESSION; - } - mSpeakers = new LLIMSpeakerMgr(mVoiceChannel); LLUICtrlFactory::getInstance()->buildFloater(this, @@ -447,24 +370,12 @@ void LLFloaterIMPanel::init(const std::string& session_label) &getFactoryMap(), FALSE); - setTitle(mSessionLabel); - - // [Ansariel: Display name support] - if (mProfileButtonEnabled) - { - lookupName(); - } - // [/Ansariel: Display name support] - - // enable line history support for instant message bar mInputEditor->setEnableLineHistory(TRUE); if ( gSavedPerAccountSettings.getBOOL("LogShowHistory") ) { - LLLogChat::loadHistory(mSessionLabel, - &chatFromLogFile, - (void *)this); + LLLogChat::loadHistory(mLogLabel, mSessionType == P2P_SESSION ? mOtherParticipantUUID : mSessionUUID, boost::bind(&LLFloaterIMPanel::chatFromLogFile, this, _1, _2)); } if ( !mSessionInitialized ) @@ -472,13 +383,12 @@ void LLFloaterIMPanel::init(const std::string& session_label) if ( !send_start_session_messages( mSessionUUID, mOtherParticipantUUID, - mSessionInitialTargetIDs, + ids, mDialog) ) { //we don't need to need to wait for any responses //so we're already initialized - mSessionInitialized = TRUE; - mSessionStartMsgPos = 0; + mSessionInitialized = true; } else { @@ -486,31 +396,39 @@ void LLFloaterIMPanel::init(const std::string& session_label) LLUIString session_start = sSessionStartString; session_start.setArg("[NAME]", getTitle()); - mSessionStartMsgPos = - mHistoryEditor->getWText().length(); + mSessionStartMsgPos.first = mHistoryEditor->getLength(); addHistoryLine( session_start, gSavedSettings.getColor4("SystemChatColor"), false); + + mSessionStartMsgPos.second = mHistoryEditor->getLength() - mSessionStartMsgPos.first; } } } -void LLFloaterIMPanel::lookupName() +void LLFloaterIMPanel::onAvatarNameLookup(const LLAvatarName& avatar_name) { - LLAvatarNameCache::get(mOtherParticipantUUID, boost::bind(&LLFloaterIMPanel::onAvatarNameLookup, this, _1, _2)); -} - -void LLFloaterIMPanel::onAvatarNameLookup(const LLUUID&, const LLAvatarName& avatar_name) -{ - std::string title; - LLAvatarNameCache::getPNSName(avatar_name, title); - setTitle(title); + setTitle(avatar_name.getNSName()); + const S32& ns(gSavedSettings.getS32("IMNameSystem")); + std::string title(avatar_name.getNSName(ns)); + if (!ns || ns == 3) // Remove Resident, if applicable. + { + size_t pos(title.find(" Resident")); + if (pos != std::string::npos && !gSavedSettings.getBOOL("LiruShowLastNameResident")) + title.erase(pos, 9); + } + setShortTitle(title); + if (LLMultiFloater* mf = dynamic_cast(getParent())) + mf->updateFloaterTitle(this); } LLFloaterIMPanel::~LLFloaterIMPanel() { + LLAvatarTracker::instance().removeParticularFriendObserver(mOtherParticipantUUID, this); + LLMuteList::instance().removeObserver(this); + delete mSpeakers; mSpeakers = NULL; @@ -537,11 +455,55 @@ LLFloaterIMPanel::~LLFloaterIMPanel() delete mVoiceChannel; mVoiceChannel = NULL; +} - //delete focus lost callback - mFocusLostSignal.disconnect(); +void add_map_option(LLComboBox& flyout, const std::string& map, const LLUUID& id, U8& did) +{ + flyout.remove(map); + if (is_agent_mappable(id) && LLAvatarTracker::instance().isBuddyOnline(id)) + { + flyout.add(map, -2); + did |= 0x02; // Added map, needs rebuild. + } + did |= 0x01; // Checked map } +// virtual +void LLFloaterIMPanel::changed(U32 mask) +{ + if (mask & (REMOVE|ADD|POWERS|ONLINE)) // Fix remove/add and map friend choices + { + U8 did(0); + LLComboBox& flyout = *getChild("instant_message_flyout"); + if (mask & POWERS) + { + // Powers changed, unfortunately, we never know which. + add_map_option(flyout, getString("find on map"), mOtherParticipantUUID, did); + } + if (mask & ONLINE) + { + if (~did & 0x01) + add_map_option(flyout, getString("find on map"), mOtherParticipantUUID, did); + /* Singu TODO: Chat UI - Online icons? + if (LLAvatarTracker::instance().isBuddyOnline(mOtherParticipantUUID)) + // Show online icon here? + else + // Show offline icon here? + */ + } + if (mask & (REMOVE|ADD) || did & 0x02) // Only rebuild if necessary + rebuildDynamics(&flyout); + } +} + +// virtual +void LLFloaterIMPanel::onChangeDetailed(const LLMute& mute) +{ + if (mute.mID == mOtherParticipantUUID) + rebuildDynamics(getChild("instant_message_flyout")); +} + +// virtual BOOL LLFloaterIMPanel::postBuild() { requires("chat_editor"); @@ -549,11 +511,14 @@ BOOL LLFloaterIMPanel::postBuild() if (checkRequirements()) { - mRPMode = false; + setTitle(mLogLabel); + if (mSessionType == P2P_SESSION && LLVoiceClient::getInstance()->isParticipantAvatar(mSessionUUID)) + LLAvatarNameCache::get(mOtherParticipantUUID, boost::bind(&LLFloaterIMPanel::onAvatarNameLookup, this, _2)); mInputEditor = getChild("chat_editor"); + mInputEditor->setAutoreplaceCallback(boost::bind(&LLAutoReplace::autoreplaceCallback, LLAutoReplace::getInstance(), _1, _2, _3, _4, _5)); mInputEditor->setFocusReceivedCallback( boost::bind(&LLFloaterIMPanel::onInputEditorFocusReceived, this) ); - mFocusLostSignal = mInputEditor->setFocusLostCallback( boost::bind(&LLFloaterIMPanel::onInputEditorFocusLost, this) ); + mInputEditor->setFocusLostCallback(boost::bind(&LLFloaterIMPanel::setTyping, this, false)); mInputEditor->setKeystrokeCallback( boost::bind(&LLFloaterIMPanel::onInputEditorKeystroke, this, _1) ); mInputEditor->setCommitCallback( boost::bind(&LLFloaterIMPanel::onSendMsg,this) ); mInputEditor->setCommitOnFocusLost( FALSE ); @@ -561,32 +526,36 @@ BOOL LLFloaterIMPanel::postBuild() mInputEditor->setReplaceNewlinesWithSpaces( FALSE ); mInputEditor->setPassDelete( TRUE ); - if (LLUICtrl* ctrl = findChild("instant_message_flyout")) + if (LLComboBox* flyout = findChild("instant_message_flyout")) { - ctrl->setCommitCallback(boost::bind(&LLFloaterIMPanel::onFlyoutCommit, this, _2)); + flyout->setCommitCallback(boost::bind(&LLFloaterIMPanel::onFlyoutCommit, this, flyout, _2)); + if (mSessionType == P2P_SESSION) + { + if (is_agent_mappable(mOtherParticipantUUID)) + flyout->add(getString("find on map"), -2); + addDynamics(flyout); + if (gObjectList.findAvatar(mOtherParticipantUUID)) + flyout->add(getString("focus"), -3); + } } + if (LLUICtrl* ctrl = findChild("tp_btn")) + ctrl->setCommitCallback(boost::bind(static_cast(LLAvatarActions::offerTeleport), mOtherParticipantUUID)); + if (LLUICtrl* ctrl = findChild("pay_btn")) + ctrl->setCommitCallback(boost::bind(LLAvatarActions::pay, mOtherParticipantUUID)); if (LLButton* btn = findChild("group_info_btn")) btn->setCommitCallback(boost::bind(LLGroupActions::show, mSessionUUID)); if (LLUICtrl* ctrl = findChild("history_btn")) ctrl->setCommitCallback(boost::bind(&LLFloaterIMPanel::onClickHistory, this)); - if (LLUICtrl* ctrl = findChild("rp_mode")) - ctrl->setCommitCallback(boost::bind(&LLFloaterIMPanel::onRPMode, this, _2)); - getChild("start_call_btn")->setCommitCallback(boost::bind(&LLIMMgr::startCall, gIMMgr, mSessionUUID, LLVoiceChannel::OUTGOING_CALL)); - getChild("end_call_btn")->setCommitCallback(boost::bind(&LLIMMgr::endCall, gIMMgr, mSessionUUID)); + getChild("start_call_btn")->setCommitCallback(boost::bind(&LLIMMgr::startCall, gIMMgr, boost::ref(mSessionUUID), LLVoiceChannel::OUTGOING_CALL)); + getChild("end_call_btn")->setCommitCallback(boost::bind(&LLIMMgr::endCall, gIMMgr, boost::ref(mSessionUUID))); getChild("send_btn")->setCommitCallback(boost::bind(&LLFloaterIMPanel::onSendMsg,this)); if (LLButton* btn = findChild("toggle_active_speakers_btn")) - btn->setCommitCallback(boost::bind(&LLFloaterIMPanel::onClickToggleActiveSpeakers, this, _2)); + btn->setCommitCallback(boost::bind(&LLView::setVisible, getChildView("active_speakers_panel"), _2)); mHistoryEditor = getChild("im_history"); mHistoryEditor->setParseHTML(TRUE); - mHistoryEditor->setParseHighlights(TRUE); - if ( IM_SESSION_GROUP_START == mDialog ) - { - childSetEnabled("profile_btn", FALSE); - } - sTitleString = getString("title_string"); sTypingStartString = getString("typing_start_string"); sSessionStartString = getString("session_start_string"); @@ -596,11 +565,32 @@ BOOL LLFloaterIMPanel::postBuild() mSpeakerPanel->refreshSpeakers(); } - if (mDialog == IM_NOTHING_SPECIAL) + switch (mSessionType) + { + case P2P_SESSION: { getChild("mute_btn")->setCommitCallback(boost::bind(&LLFloaterIMPanel::onClickMuteVoice, this)); getChild("speaker_volume")->setCommitCallback(boost::bind(&LLVoiceClient::setUserVolume, LLVoiceClient::getInstance(), mOtherParticipantUUID, _2)); } + break; + case SUPPORT_SESSION: + { + auto support = getChildView("Support Check"); + support->setVisible(true); + auto control = gSavedSettings.getControl(support->getControlName()); + if (control->get().asInteger() == -1) + { + LLNotificationsUtil::add("SupportChatShowInfo", LLSD(), LLSD(), [control](const LLSD& p, const LLSD& f) + { + control->set(!LLNotificationsUtil::getSelectedOption(p, f)); + }); + } + // Singu Note: We could make a button feature for dumping Help->About contents for support, too. + } + break; + default: + break; + } setDefaultBtn("send_btn"); @@ -640,12 +630,7 @@ void LLFloaterIMPanel::onClickMuteVoice() // virtual void LLFloaterIMPanel::draw() { - LLViewerRegion* region = gAgent.getRegion(); - - BOOL enable_connect = (region && region->getCapability("ChatSessionRequest") != "") - && mSessionInitialized - && LLVoiceClient::getInstance()->voiceEnabled() - && mCallBackEnabled; + bool enable_connect = mSessionInitialized && LLVoiceClient::getInstance()->voiceEnabled() && mCallBackEnabled; // hide/show start call and end call buttons mEndCallBtn->setVisible(LLVoiceClient::getInstance()->voiceEnabled() && mVoiceChannel->getState() >= LLVoiceChannel::STATE_CALL_STARTED); @@ -673,18 +658,16 @@ void LLFloaterIMPanel::draw() // show speakers window when voice first connects if (mShowSpeakersOnConnect && mVoiceChannel->isActive()) { - childSetVisible("active_speakers_panel", true); - mShowSpeakersOnConnect = FALSE; + if (mSpeakerPanel) mSpeakerPanel->setVisible(true); + mShowSpeakersOnConnect = false; } - if (LLUICtrl* ctrl = findChild("toggle_active_speakers_btn")) - ctrl->setValue(getChildView("active_speakers_panel")->getVisible()); if (mTyping) { // Time out if user hasn't typed for a while. if (mLastKeystrokeTimer.getElapsedTimeF32() > LLAgent::TYPING_TIMEOUT_SECS) { - setTyping(FALSE); + setTyping(false); } // If we are typing, and it's been a little while, send the @@ -692,8 +675,8 @@ void LLFloaterIMPanel::draw() if (!mSentTypingState && mFirstKeystrokeTimer.getElapsedTimeF32() > 1.f) { - sendTypingState(TRUE); - mSentTypingState = TRUE; + sendTypingState(true); + mSentTypingState = true; } } @@ -720,26 +703,20 @@ void LLFloaterIMPanel::draw() class LLSessionInviteResponder : public LLHTTPClient::ResponderIgnoreBody { public: - LLSessionInviteResponder(const LLUUID& session_id) - { - mSessionID = session_id; - } + LLSessionInviteResponder(const LLUUID& session_id) : mSessionID(session_id) {} - /*virtual*/ void error(U32 statusNum, const std::string& reason) + /*virtual*/ void httpFailure() { - llwarns << "Error inviting all agents to session [status:" - << statusNum << "]: " << reason << llendl; + LL_WARNS() << "Error inviting all agents to session [status:" << mStatus << "]: " << mReason << LL_ENDL; //throw something back to the viewer here? } - - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return sessionInviteResponder_timeout; } - /*virtual*/ char const* getName(void) const { return "LLSessionInviteResponder"; } + /*virtual*/ char const* getName() const { return "LLSessionInviteResponder"; } private: LLUUID mSessionID; }; -BOOL LLFloaterIMPanel::inviteToSession(const LLDynamicArray& ids) +bool LLFloaterIMPanel::inviteToSession(const uuid_vec_t& ids) { LLViewerRegion* region = gAgent.getRegion(); if (!region) @@ -747,11 +724,11 @@ BOOL LLFloaterIMPanel::inviteToSession(const LLDynamicArray& ids) return FALSE; } - S32 count = ids.count(); + S32 count = ids.size(); if( isInviteAllowed() && (count > 0) ) { - llinfos << "LLFloaterIMPanel::inviteToSession() - inviting participants" << llendl; + LL_INFOS() << "LLFloaterIMPanel::inviteToSession() - inviting participants" << LL_ENDL; std::string url = region->getCapability("ChatSessionRequest"); @@ -760,7 +737,7 @@ BOOL LLFloaterIMPanel::inviteToSession(const LLDynamicArray& ids) data["params"] = LLSD::emptyArray(); for (int i = 0; i < count; i++) { - data["params"].append(ids.get(i)); + data["params"].append(ids.at(i)); } data["method"] = "invite"; @@ -773,9 +750,9 @@ BOOL LLFloaterIMPanel::inviteToSession(const LLDynamicArray& ids) } else { - llinfos << "LLFloaterIMPanel::inviteToSession -" + LL_INFOS() << "LLFloaterIMPanel::inviteToSession -" << " no need to invite agents for " - << mDialog << llendl; + << mDialog << LL_ENDL; // successful add, because everyone that needed to get added // was added. } @@ -785,37 +762,44 @@ BOOL LLFloaterIMPanel::inviteToSession(const LLDynamicArray& ids) void LLFloaterIMPanel::addHistoryLine(const std::string &utf8msg, LLColor4 incolor, bool log_to_file, const LLUUID& source, const std::string& name) { - static const LLCachedControl mKeywordsChangeColor(gSavedPerAccountSettings, "KeywordsChangeColor", false); - static const LLCachedControl mKeywordsColor(gSavedPerAccountSettings, "KeywordsColor", LLColor4(1.f, 1.f, 1.f, 1.f)); - - if (gAgentID != source) + bool is_agent(gAgentID == source), from_user(source.notNull()); + if (!is_agent) { + static const LLCachedControl mKeywordsChangeColor(gSavedPerAccountSettings, "KeywordsChangeColor", false); if (mKeywordsChangeColor) { if (AscentKeyword::hasKeyword(utf8msg, 2)) { + static const LLCachedControl mKeywordsColor(gSavedPerAccountSettings, "KeywordsColor", LLColor4(1.f, 1.f, 1.f, 1.f)); incolor = mKeywordsColor; } } - } - const LLColor4& color = incolor; - // start tab flashing when receiving im for background session from user - if (source.notNull()) - { - LLMultiFloater* hostp = getHost(); - if( !isInVisibleChain() - && hostp - && source != gAgentID) + bool focused(hasFocus()); + if (mDing && (!focused || !gFocusMgr.getAppHasFocus())) + { + static const LLCachedControl ding("LiruNewMessageSound"); + static const LLCachedControl dong("LiruNewMessageSoundForSystemMessages"); + LLUI::sAudioCallback(LLUUID(from_user ? ding : dong)); + } + + // start tab flashing when receiving im for background session from user + if (from_user) { - hostp->setFloaterFlashing(this, TRUE); + bool invisible(!isInVisibleChain()); + LLMultiFloater* host = getHost(); + if (invisible && host) + host->setFloaterFlashing(this, true); + if (invisible || (!host && focused)) + ++mNumUnreadMessages; } + } // Now we're adding the actual line of text, so erase the // "Foo is typing..." text segment, and the optional timestamp // if it was present. JC - removeTypingIndicator(NULL); + removeTypingIndicator(source); // Actually add the line bool prepend_newline = true; @@ -827,25 +811,28 @@ void LLFloaterIMPanel::addHistoryLine(const std::string &utf8msg, LLColor4 incol std::string show_name = name; bool is_irc = false; + bool system = name.empty(); // 'name' is a sender name that we want to hotlink so that clicking on it opens a profile. - if (!name.empty()) // If name exists, then add it to the front of the message. + if (!system) // If name exists, then add it to the front of the message. { // Don't hotlink any messages from the system (e.g. "Second Life:"), so just add those in plain text. if (name == SYSTEM_FROM) { - mHistoryEditor->appendColoredText(name,false,prepend_newline,color); + system = true; + mHistoryEditor->appendColoredText(name,false,prepend_newline,incolor); } else { + system = !from_user; // IRC style text starts with a colon here; empty names and system messages aren't irc style. static const LLCachedControl italicize("LiruItalicizeActions"); is_irc = italicize && utf8msg[0] != ':'; - if (source.notNull()) - LLAvatarNameCache::getPNSName(source, show_name); + if (from_user) + LLAvatarNameCache::getNSName(source, show_name); // Convert the name to a hotlink and add to message. LLStyleSP source_style = LLStyleMap::instance().lookupAgent(source); source_style->mItalic = is_irc; - mHistoryEditor->appendStyledText(show_name,false,prepend_newline,source_style); + mHistoryEditor->appendText(show_name,false,prepend_newline,source_style, system); } prepend_newline = false; } @@ -853,10 +840,10 @@ void LLFloaterIMPanel::addHistoryLine(const std::string &utf8msg, LLColor4 incol // Append the chat message in style { LLStyleSP style(new LLStyle); - style->setColor(color); + style->setColor(incolor); style->mItalic = is_irc; - style->mBold = gSavedSettings.getBOOL("SingularityBoldGroupModerator") && isModerator(source); - mHistoryEditor->appendStyledText(utf8msg, false, prepend_newline, style); + style->mBold = from_user && gSavedSettings.getBOOL("SingularityBoldGroupModerator") && isModerator(source); + mHistoryEditor->appendText(utf8msg, false, prepend_newline, style, system); } if (log_to_file @@ -870,18 +857,13 @@ void LLFloaterIMPanel::addHistoryLine(const std::string &utf8msg, LLColor4 incol // [Ansariel: Display name support] // Floater title contains display name -> bad idea to use that as filename - // mSessionLabel, however, should still be the old legacy name + // mLogLabel, however, is the old legacy name //LLLogChat::saveHistory(getTitle(),histstr); - LLLogChat::saveHistory(mSessionLabel, histstr); + LLLogChat::saveHistory(mLogLabel, mSessionType == P2P_SESSION ? mOtherParticipantUUID : mSessionUUID, histstr); // [/Ansariel: Display name support] } - if (!isInVisibleChain() || (!hasFocus() && getParent() == gFloaterView)) - { - mNumUnreadMessages++; - } - - if (source.notNull()) + if (from_user) { mSpeakers->speakerChatted(source); mSpeakers->setSpeakerTyping(source, FALSE); @@ -901,38 +883,23 @@ void LLFloaterIMPanel::setVisible(BOOL b) } -void LLFloaterIMPanel::setInputFocus( BOOL b ) +void LLFloaterIMPanel::setInputFocus(bool b) { mInputEditor->setFocus( b ); } - -void LLFloaterIMPanel::selectAll() -{ - mInputEditor->selectAll(); -} - - -void LLFloaterIMPanel::selectNone() -{ - mInputEditor->deselect(); -} - - BOOL LLFloaterIMPanel::handleKeyHere( KEY key, MASK mask ) { BOOL handled = FALSE; - if( KEY_RETURN == key && mask == MASK_NONE) + if (KEY_RETURN == key) { onSendMsg(); handled = TRUE; // Close talk panels on hitting return - // but not shift-return or control-return - if ( !gSavedSettings.getBOOL("PinTalkViewOpen") && !(mask & MASK_CONTROL) && !(mask & MASK_SHIFT) ) - { - gIMMgr->toggle(NULL); - } + // without holding a modifier key + if (mask == MASK_NONE) + closeIfNotPinned(); } else if (KEY_ESCAPE == key && mask == MASK_NONE) { @@ -940,10 +907,7 @@ BOOL LLFloaterIMPanel::handleKeyHere( KEY key, MASK mask ) gFocusMgr.setKeyboardFocus(NULL); // Close talk panel with escape - if( !gSavedSettings.getBOOL("PinTalkViewOpen") ) - { - gIMMgr->toggle(NULL); - } + closeIfNotPinned(); } // May need to call base class LLPanel::handleKeyHere if not handled @@ -951,6 +915,16 @@ BOOL LLFloaterIMPanel::handleKeyHere( KEY key, MASK mask ) return handled; } +void LLFloaterIMPanel::closeIfNotPinned() +{ + if (gSavedSettings.getBOOL("PinTalkViewOpen")) return; + + if (getParent() == gFloaterView) // Just minimize, if popped out + setMinimized(true); + else + gIMMgr->toggle(); +} + BOOL LLFloaterIMPanel::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, void* cargo_data, @@ -958,7 +932,7 @@ BOOL LLFloaterIMPanel::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, std::string& tooltip_msg) { - if (mDialog == IM_NOTHING_SPECIAL) + if (mSessionType == P2P_SESSION) { LLToolDragAndDrop::handleGiveDragAndDrop(mOtherParticipantUUID, mSessionUUID, drop, cargo_type, cargo_data, accept); @@ -989,28 +963,21 @@ BOOL LLFloaterIMPanel::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, BOOL LLFloaterIMPanel::dropCallingCard(LLInventoryItem* item, BOOL drop) { - BOOL rv = isInviteAllowed(); - if(rv && item && item->getCreatorUUID().notNull()) + if (item && item->getCreatorUUID().notNull()) { - if(drop) + if (drop) { - LLDynamicArray ids; - ids.put(item->getCreatorUUID()); - inviteToSession(ids); + inviteToSession({ item->getCreatorUUID() }); } + return true; } - else - { - // set to false if creator uuid is null. - rv = FALSE; - } - return rv; + // return false if creator uuid is null. + return false; } BOOL LLFloaterIMPanel::dropCategory(LLInventoryCategory* category, BOOL drop) { - BOOL rv = isInviteAllowed(); - if(rv && category) + if (category) { LLInventoryModel::cat_array_t cats; LLInventoryModel::item_array_t items; @@ -1020,134 +987,247 @@ BOOL LLFloaterIMPanel::dropCategory(LLInventoryCategory* category, BOOL drop) items, LLInventoryModel::EXCLUDE_TRASH, buddies); - S32 count = items.count(); + S32 count = items.size(); if(count == 0) { - rv = FALSE; + return false; } else if(drop) { - LLDynamicArray ids; + uuid_vec_t ids; for(S32 i = 0; i < count; ++i) { - ids.put(items.get(i)->getCreatorUUID()); + ids.push_back(items.at(i)->getCreatorUUID()); } inviteToSession(ids); } } - return rv; + return true; } -BOOL LLFloaterIMPanel::isInviteAllowed() const +bool LLFloaterIMPanel::isInviteAllowed() const { - - return ( (IM_SESSION_CONFERENCE_START == mDialog) - || (IM_SESSION_INVITE == mDialog) ); + return mSessionType == ADHOC_SESSION; } - -// static -void LLFloaterIMPanel::onTabClick(void* userdata) +void LLFloaterIMPanel::onAddButtonClicked() { - LLFloaterIMPanel* self = (LLFloaterIMPanel*) userdata; - self->setInputFocus(TRUE); -} + LLView * button = findChild("instant_message_flyout"); + LLFloater* root_floater = gFloaterView->getParentFloater(this); + LLFloaterAvatarPicker* picker = LLFloaterAvatarPicker::show(boost::bind(&LLFloaterIMPanel::addSessionParticipants, this, _1), TRUE, TRUE, FALSE, root_floater->getName(), button); + if (!picker) + { + return; + } + // Need to disable 'ok' button when selected users are already in conversation. + picker->setOkBtnEnableCb(boost::bind(&LLFloaterIMPanel::canAddSelectedToChat, this, _1)); -void LLFloaterIMPanel::onRPMode(const LLSD& value) -{ - mRPMode = value.asBoolean(); + if (root_floater) + { + root_floater->addDependentFloater(picker); + } } -void LLFloaterIMPanel::onFlyoutCommit(const LLSD& value) +bool LLFloaterIMPanel::canAddSelectedToChat(const uuid_vec_t& uuids) const { - if (value.isUndefined()) + switch (mSessionType) { - LLAvatarActions::showProfile(mOtherParticipantUUID); - return; - } + case P2P_SESSION: return true; // Don't bother blocking self or peer + case ADHOC_SESSION: + { + // For a conference session we need to check against the list from LLSpeakerMgr, + // because this list may change when participants join or leave the session. + + LLSpeakerMgr::speaker_list_t speaker_list; + LLIMSpeakerMgr* speaker_mgr = getSpeakerManager(); + if (speaker_mgr) + { + speaker_mgr->getSpeakerList(&speaker_list, true); + } - int option = value.asInteger(); - if (option == 1) onClickHistory(); - else if (option == 2) LLAvatarActions::offerTeleport(mOtherParticipantUUID); - else if (option == 3) LLAvatarActions::teleportRequest(mOtherParticipantUUID); - else if (option == 4) LLAvatarActions::pay(mOtherParticipantUUID); - else if (option == 5) LLAvatarActions::inviteToGroup(mOtherParticipantUUID); + for (const auto& id : uuids) + for (const LLPointer& speaker : speaker_list) + if (id == speaker->mID) + return false; + } + return true; + default: return false; + } } -void LLFloaterIMPanel::onClickHistory() +void LLFloaterIMPanel::addSessionParticipants(const uuid_vec_t& uuids) { - if (mOtherParticipantUUID.notNull()) + if (mSessionType == P2P_SESSION) { - // [Ansariel: Display name support] - //std::string command("\"" + LLLogChat::makeLogFileName(getTitle()) + "\""); - std::string command("\"" + LLLogChat::makeLogFileName(mSessionLabel) + "\""); - // [/Ansariel: Display name support] - gViewerWindow->getWindow()->ShellEx(command); + LLSD payload; + LLSD args; - llinfos << command << llendl; + LLNotificationsUtil::add("ConfirmAddingChatParticipants", args, payload, + boost::bind(&LLFloaterIMPanel::addP2PSessionParticipants, this, _1, _2, uuids)); } + else inviteToSession(uuids); } -// static -void LLFloaterIMPanel::onClickStartCall(void* userdata) +void LLFloaterIMPanel::addP2PSessionParticipants(const LLSD& notification, const LLSD& response, const uuid_vec_t& uuids) { - LLFloaterIMPanel* self = (LLFloaterIMPanel*) userdata; + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option != 0) + { + return; + } + + LLVoiceChannel* voice_channel = LLActiveSpeakerMgr::getInstance()->getVoiceChannel(); + + // first check whether this is a voice session + bool is_voice_call = voice_channel != nullptr && voice_channel->getSessionID() == mSessionUUID && voice_channel->isActive(); + + uuid_vec_t temp_ids; - self->mVoiceChannel->activate(); + // Add the initial participant of a P2P session + temp_ids.push_back(mOtherParticipantUUID); + temp_ids.insert(temp_ids.end(), uuids.begin(), uuids.end()); + + // Start a new ad hoc voice call if we invite new participants to a P2P call, + // or start a text chat otherwise. + if (is_voice_call) + { + LLAvatarActions::startAdhocCall(temp_ids); + } + else + { + LLAvatarActions::startConference(temp_ids); + } } -void LLFloaterIMPanel::onClickToggleActiveSpeakers(const LLSD& value) +void LLFloaterIMPanel::removeDynamics(LLComboBox* flyout) { - childSetVisible("active_speakers_panel", !value); + flyout->remove(mDing ? getString("ding on") : getString("ding off")); + flyout->remove(mRPMode ? getString("rp mode on") : getString("rp mode off")); + flyout->remove(LLAvatarActions::isFriend(mOtherParticipantUUID) ? getString("remove friend") : getString("add friend")); + flyout->remove(LLAvatarActions::isBlocked(mOtherParticipantUUID) ? getString("unmute") : getString("mute")); } -void LLFloaterIMPanel::onInputEditorFocusReceived() +void LLFloaterIMPanel::addDynamics(LLComboBox* flyout) { - mHistoryEditor->setCursorAndScrollToEnd(); + flyout->add(mDing ? getString("ding on") : getString("ding off"), 6); + flyout->add(mRPMode ? getString("rp mode on") : getString("rp mode off"), 7); + flyout->add(LLAvatarActions::isFriend(mOtherParticipantUUID) ? getString("remove friend") : getString("add friend"), 8); + flyout->add(LLAvatarActions::isBlocked(mOtherParticipantUUID) ? getString("unmute") : getString("mute"), 9); } -void LLFloaterIMPanel::onInputEditorFocusLost() +void LLFloaterIMPanel::addDynamicFocus() { - setTyping(FALSE); + findChild("instant_message_flyout")->add(getString("focus"), -3); } -void LLFloaterIMPanel::onInputEditorKeystroke(LLLineEditor* caller) +void LLFloaterIMPanel::removeDynamicFocus() { - std::string text = caller->getText(); - if (!text.empty()) + findChild("instant_message_flyout")->remove(getString("focus")); +} + +void copy_profile_uri(const LLUUID& id, const LFIDBearer::Type& type = LFIDBearer::AVATAR); + +void LLFloaterIMPanel::onFlyoutCommit(LLComboBox* flyout, const LLSD& value) +{ + if (value.isUndefined() || value.asInteger() == 0) { - setTyping(TRUE); + switch (mSessionType) + { + case SUPPORT_SESSION: + case GROUP_SESSION: LLGroupActions::show(mSessionUUID); return; + case P2P_SESSION: LLAvatarActions::showProfile(mOtherParticipantUUID); return; + default: onClickHistory(); return; // If there's no profile for this type, we should be the history button. + } } - else + + switch (int option = value.asInteger()) + { + case 1: onClickHistory(); break; + case 2: LLAvatarActions::offerTeleport(mOtherParticipantUUID); break; + case 3: LLAvatarActions::teleportRequest(mOtherParticipantUUID); break; + case 4: LLAvatarActions::pay(mOtherParticipantUUID); break; + case 5: LLAvatarActions::inviteToGroup(mOtherParticipantUUID); break; + case -1: copy_profile_uri(mOtherParticipantUUID); break; + case -2: LLAvatarActions::showOnMap(mOtherParticipantUUID); break; + case -3: gAgentCamera.lookAtObject(mOtherParticipantUUID); break; + case -4: onAddButtonClicked(); break; + case -5: LLFloaterReporter::showFromAvatar(mOtherParticipantUUID, mLogLabel); break; + default: // Options >= 6 use dynamic items { - // Deleting all text counts as stopping typing. - setTyping(FALSE); + // First remove them all + removeDynamics(flyout); + + // Toggle as requested, adjust the strings + switch (option) + { + case 6: mDing = !mDing; break; + case 7: mRPMode = !mRPMode; break; + case 8: LLAvatarActions::isFriend(mOtherParticipantUUID) ? LLAvatarActions::removeFriendDialog(mOtherParticipantUUID) : LLAvatarActions::requestFriendshipDialog(mOtherParticipantUUID); break; + case 9: LLAvatarActions::toggleBlock(mOtherParticipantUUID); break; + } + + // Last add them back + addDynamics(flyout); + // Always have Focus last + const std::string focus(getString("focus")); + if (flyout->remove(focus)) // If present, reorder to bottom. + flyout->add(focus, -3); + } } } -void LLFloaterIMPanel::onClose(bool app_quitting) +void show_log_browser(const std::string& name, const LLUUID& id) { - setTyping(FALSE); + const std::string file(LLLogChat::makeLogFileName(name, id)); + if (!LLFile::isfile(file)) + { + make_ui_sound("UISndBadKeystroke"); + LL_WARNS() << "File not present: " << file << LL_ENDL; + return; + } + if (gSavedSettings.getBOOL("LiruLegacyLogLaunch")) + { + if (!LLWindow::ShellEx(file)) // 0 = success, otherwise fallback on internal browser. + return; + } + LLFloaterWebContent::Params p; + p.url("file:///" + file); + p.id(id.asString()); + p.show_chrome(false); + p.trusted_content(true); + LLFloaterWebContent::showInstance("log", p); // If we passed id instead of "log", there would be no control over how many log browsers opened at once. +} - if(mSessionUUID.notNull()) +void LLFloaterIMPanel::onClickHistory() +{ + if (mOtherParticipantUUID.notNull()) { - std::string name; - gAgent.buildFullname(name); - pack_instant_message( - gMessageSystem, - gAgent.getID(), - FALSE, - gAgent.getSessionID(), - mOtherParticipantUUID, - name, - LLStringUtil::null, - IM_ONLINE, - IM_SESSION_LEAVE, - mSessionUUID); - gAgent.sendReliableMessage(); + // [Ansariel: Display name support] + //show_log_browser(getTitle(), mSessionType == P2P_SESSION ? mOtherParticipantUUID : mSessionUUID); + show_log_browser(mLogLabel, mSessionType == P2P_SESSION ? mOtherParticipantUUID : mSessionUUID); + // [/Ansariel: Display name support] } - gIMMgr->removeSession(mSessionUUID); +} + +void LLFloaterIMPanel::onInputEditorFocusReceived() +{ + if (gSavedSettings.getBOOL("LiruLegacyScrollToEnd")) + mHistoryEditor->setCursorAndScrollToEnd(); +} + +void LLFloaterIMPanel::onInputEditorKeystroke(LLLineEditor* caller) +{ + // Deleting all text counts as stopping typing. + setTyping(!caller->getText().empty()); +} + +void leave_group_chat(const LLUUID& from_id, const LLUUID& session_id); +void LLFloaterIMPanel::onClose(bool app_quitting) +{ + setTyping(false); + + leave_group_chat(mOtherParticipantUUID, mSessionUUID); destroy(); } @@ -1167,7 +1247,7 @@ void deliver_message(const std::string& utf8_text, { std::string name; bool sent = false; - gAgent.buildFullname(name); + LLAgentUI::buildFullname(name); const LLRelationship* info = LLAvatarTracker::instance().getBuddyInfo(other_participant_id); @@ -1176,7 +1256,7 @@ void deliver_message(const std::string& utf8_text, if((offline == IM_OFFLINE) && (LLVoiceClient::getInstance()->isOnlineSIP(other_participant_id))) { // User is online through the OOW connector, but not with a regular viewer. Try to send the message via SLVoice. - sent = LLVoiceClient::getInstance()->sendTextMessage(other_participant_id, utf8_text); +// sent = LLVoiceClient::getInstance()->sendTextMessage(other_participant_id, utf8_text); } if(!sent) @@ -1229,13 +1309,16 @@ void deliver_message(const std::string& utf8_text, } } +bool convert_roleplay_text(std::string& text); // Returns true if text is an action + +// Singu Note: LLFloaterIMSession::sendMsg void LLFloaterIMPanel::onSendMsg() { if (!gAgent.isGodlike() - && (mDialog == IM_NOTHING_SPECIAL) + && (mSessionType == P2P_SESSION) && mOtherParticipantUUID.isNull()) { - llinfos << "Cannot send IM to everyone unless you're a god." << llendl; + LL_INFOS() << "Cannot send IM to everyone unless you're a god." << LL_ENDL; return; } @@ -1248,66 +1331,23 @@ void LLFloaterIMPanel::onSendMsg() if (mInputEditor) mInputEditor->updateHistory(); // Truncate and convert to UTF8 for transport std::string utf8_text = wstring_to_utf8str(text); - // Convert MU*s style poses into IRC emotes here. - if (gSavedSettings.getBOOL("AscentAllowMUpose") && utf8_text.length() > 3 && utf8_text[0] == ':') - { - if (utf8_text[1] == '\'') - { - utf8_text.replace(0, 1, "/me"); - } - else if (isalpha(utf8_text[1])) // Do not prevent smileys and such. - { - utf8_text.replace(0, 1, "/me "); - } - } - if (utf8_text.find("/ME'") == 0 || utf8_text.find("/ME ") == 0) //Allow CAPSlock /me - utf8_text.replace(1, 2, "me"); - std::string prefix = utf8_text.substr(0, 4); - if (gSavedSettings.getBOOL("AscentAutoCloseOOC") && (utf8_text.length() > 1) && !mRPMode) - { - //Check if it needs the end-of-chat brackets -HgB - if (utf8_text.find("((") == 0 && utf8_text.find("))") == std::string::npos) - { - if(*utf8_text.rbegin() == ')') - utf8_text+=" "; - utf8_text+="))"; - } - else if(utf8_text.find("[[") == 0 && utf8_text.find("]]") == std::string::npos) - { - if(*utf8_text.rbegin() == ']') - utf8_text+=" "; - utf8_text+="]]"; - } + bool action = convert_roleplay_text(utf8_text); + if (!action && mRPMode) + utf8_text = "((" + utf8_text + "))"; - if (prefix != "/me " && prefix != "/me'") //Allow /me to end with )) or ]] - { - if (utf8_text.find("((") == std::string::npos && utf8_text.find("))") == (utf8_text.length() - 2)) - { - if(utf8_text[0] == '(') - utf8_text.insert(0," "); - utf8_text.insert(0,"(("); - } - else if (utf8_text.find("[[") == std::string::npos && utf8_text.find("]]") == (utf8_text.length() - 2)) - { - if(utf8_text[0] == '[') - utf8_text.insert(0," "); - utf8_text.insert(0,"[["); - } - } - } - if (mRPMode && prefix != "/me " && prefix != "/me'") - utf8_text = "[[" + utf8_text + "]]"; -// [RLVa:KB] - Checked: 2011-09-17 (RLVa-1.1.4b) | Modified: RLVa-1.1.4b - if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SENDIM)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SENDIMTO)) ) +// [RLVa:KB] - Checked: 2010-11-30 (RLVa-1.3.0) + if ( (RlvActions::hasBehaviour(RLV_BHVR_SENDIM)) || (RlvActions::hasBehaviour(RLV_BHVR_SENDIMTO)) ) { bool fRlvFilter = false; switch (mSessionType) { case P2P_SESSION: // One-on-one IM - fRlvFilter = !gRlvHandler.canSendIM(mOtherParticipantUUID); + fRlvFilter = !RlvActions::canSendIM(mOtherParticipantUUID); break; case GROUP_SESSION: // Group chat - fRlvFilter = !gRlvHandler.canSendIM(mSessionUUID); + fRlvFilter = !RlvActions::canSendIM(mSessionUUID); + break; + case SUPPORT_SESSION: // Support Group, never filter, they may need help!! break; case ADHOC_SESSION: // Conference chat: allow if all participants can be sent an IM { @@ -1323,7 +1363,7 @@ void LLFloaterIMPanel::onSendMsg() itSpeaker != speakers.end(); ++itSpeaker) { const LLSpeaker* pSpeaker = *itSpeaker; - if ( (gAgentID != pSpeaker->mID) && (!gRlvHandler.canSendIM(pSpeaker->mID)) ) + if ( (gAgentID != pSpeaker->mID) && (!RlvActions::canSendIM(pSpeaker->mID)) ) { fRlvFilter = true; break; @@ -1337,10 +1377,17 @@ void LLFloaterIMPanel::onSendMsg() } if (fRlvFilter) + { utf8_text = RlvStrings::getString(RLV_STRING_BLOCKED_SENDIM); + } } // [/RLVa:KB] + if (mSessionType == SUPPORT_SESSION && getChildView("Support Check")->getValue()) + { + utf8_text.insert(action ? 3 : 0, llformat(action ? " (%d%s)" : "(%d%s): ", LL_VIEWER_VERSION_BUILD, wstring_to_utf8str(LL_VIEWER_CHANNEL_GRK).data())); + } + if ( mSessionInitialized ) { // Split messages that are too long, same code like in llimpanel.cpp @@ -1382,7 +1429,7 @@ void LLFloaterIMPanel::onSendMsg() std::string send = utf8_text.substr(pos, next_split); pos += next_split; -LL_WARNS("Splitting") << "Pos: " << pos << " next_split: " << next_split << LL_ENDL; + LL_DEBUGS("Splitting") << "Pos: " << pos << " next_split: " << next_split << LL_ENDL; deliver_message(send, mSessionUUID, @@ -1391,17 +1438,16 @@ LL_WARNS("Splitting") << "Pos: " << pos << " next_split: " << next_split << LL_E } // local echo - if((mDialog == IM_NOTHING_SPECIAL) && + if((mSessionType == P2P_SESSION) && (mOtherParticipantUUID.notNull())) { std::string name; - gAgent.buildFullname(name); + LLAgentUI::buildFullname(name); - // Look for IRC-style emotes here. - std::string prefix = utf8_text.substr(0, 4); - if (prefix == "/me " || prefix == "/me'") + // Look for actions here. + if (action) { - utf8_text.replace(0,3,""); + utf8_text.erase(0,3); } else { @@ -1410,7 +1456,7 @@ LL_WARNS("Splitting") << "Pos: " << pos << " next_split: " << next_split << LL_E bool other_was_typing = mOtherTyping; addHistoryLine(utf8_text, gSavedSettings.getColor("UserChatColor"), true, gAgentID, name); - if (other_was_typing) addTypingIndicator(mOtherTypingName); + if (other_was_typing) addTypingIndicator(mOtherParticipantUUID); } } else @@ -1428,8 +1474,8 @@ LL_WARNS("Splitting") << "Pos: " << pos << " next_split: " << next_split << LL_E // Don't need to actually send the typing stop message, the other // client will infer it from receiving the message. - mTyping = FALSE; - mSentTypingState = TRUE; + mTyping = false; + mSentTypingState = true; } void LLFloaterIMPanel::processSessionUpdate(const LLSD& session_update) @@ -1438,15 +1484,15 @@ void LLFloaterIMPanel::processSessionUpdate(const LLSD& session_update) session_update.has("moderated_mode") && session_update["moderated_mode"].has("voice") ) { - BOOL voice_moderated = session_update["moderated_mode"]["voice"]; + bool voice_moderated = session_update["moderated_mode"]["voice"]; if (voice_moderated) { - setTitle(mSessionLabel + std::string(" ") + getString("moderated_chat_label")); + setTitle(mLogLabel + std::string(" ") + getString("moderated_chat_label")); } else { - setTitle(mSessionLabel); + setTitle(mLogLabel); } @@ -1459,18 +1505,12 @@ void LLFloaterIMPanel::sessionInitReplyReceived(const LLUUID& session_id) { mSessionUUID = session_id; mVoiceChannel->updateSessionID(session_id); - mSessionInitialized = TRUE; + mSessionInitialized = true; - //we assume the history editor hasn't moved at all since - //we added the starting session message - //so, we count how many characters to remove - S32 chars_to_remove = mHistoryEditor->getWText().length() - - mSessionStartMsgPos; - mHistoryEditor->removeTextFromEnd(chars_to_remove); + mHistoryEditor->remove(mSessionStartMsgPos.first, mSessionStartMsgPos.second, true); //and now, send the queued msg - LLSD::array_iterator iter; - for ( iter = mQueuedMsgsForInit.beginArray(); + for (LLSD::array_iterator iter = mQueuedMsgsForInit.beginArray(); iter != mQueuedMsgsForInit.endArray(); ++iter) { @@ -1488,7 +1528,7 @@ void LLFloaterIMPanel::sessionInitReplyReceived(const LLUUID& session_id) } } -void LLFloaterIMPanel::setTyping(BOOL typing) +void LLFloaterIMPanel::setTyping(bool typing) { if (typing) { @@ -1501,7 +1541,7 @@ void LLFloaterIMPanel::setTyping(BOOL typing) mFirstKeystrokeTimer.reset(); // Will send typing state after a short delay. - mSentTypingState = FALSE; + mSentTypingState = false; } mSpeakers->setSpeakerTyping(gAgent.getID(), TRUE); @@ -1511,8 +1551,8 @@ void LLFloaterIMPanel::setTyping(BOOL typing) if (mTyping) { // you just stopped typing, send state immediately - sendTypingState(FALSE); - mSentTypingState = TRUE; + sendTypingState(false); + mSentTypingState = true; } mSpeakers->setSpeakerTyping(gAgent.getID(), FALSE); } @@ -1520,16 +1560,16 @@ void LLFloaterIMPanel::setTyping(BOOL typing) mTyping = typing; } -void LLFloaterIMPanel::sendTypingState(BOOL typing) +void LLFloaterIMPanel::sendTypingState(bool typing) { if(gSavedSettings.getBOOL("AscentHideTypingNotification")) return; // Don't want to send typing indicators to multiple people, potentially too // much network traffic. Only send in person-to-person IMs. - if (mDialog != IM_NOTHING_SPECIAL) return; + if (mSessionType != P2P_SESSION) return; std::string name; - gAgent.buildFullname(name); + LLAgentUI::buildFullname(name); pack_instant_message( gMessageSystem, @@ -1546,89 +1586,99 @@ void LLFloaterIMPanel::sendTypingState(BOOL typing) } -void LLFloaterIMPanel::processIMTyping(const LLIMInfo* im_info, BOOL typing) +void LLFloaterIMPanel::processIMTyping(const LLUUID& from_id, BOOL typing) { if (typing) { // other user started typing - std::string name; - if (!LLAvatarNameCache::getPNSName(im_info->mFromID, name)) name = im_info->mName; - addTypingIndicator(name); + addTypingIndicator(from_id); } else { // other user stopped typing - removeTypingIndicator(im_info); + removeTypingIndicator(from_id); } } -void LLFloaterIMPanel::addTypingIndicator(const std::string &name) +void LLFloaterIMPanel::addTypingIndicator(const LLUUID& from_id) { - // we may have lost a "stop-typing" packet, don't add it twice - if (!mOtherTyping) + // Singu TODO: Actually implement this? +/* Operation of " is typing" state machine: +Not Typing state: + + User types in P2P IM chat ... Send Start Typing, save Started time, + start Idle Timer (N seconds) go to Typing state + +Typing State: + + User enters a non-return character: if Now - Started > ME_TYPING_TIMEOUT, send + Start Typing, restart Idle Timer + User enters a return character: stop Idle Timer, send IM and Stop + Typing, go to Not Typing state + Idle Timer expires: send Stop Typing, go to Not Typing state + +The recipient has a complementary state machine in which a Start Typing +that is not followed by either an IM or another Start Typing within OTHER_TYPING_TIMEOUT +seconds switches the sender out of typing state. + +This has the nice quality of being self-healing for lost start/stop +messages while adding messages only for the (relatively rare) case of a +user who types a very long message (one that takes more than ME_TYPING_TIMEOUT seconds +to type). + +Note: OTHER_TYPING_TIMEOUT must be > ME_TYPING_TIMEOUT for proper operation of the state machine + +*/ + + // We may have lost a "stop-typing" packet, don't add it twice + if (from_id.notNull() && !mOtherTyping) { + mOtherTyping = true; + // Save im_info so that removeTypingIndicator can be properly called because a timeout has occurred + LLAvatarNameCache::getNSName(from_id, mOtherTypingName); + mTypingLineStartIndex = mHistoryEditor->getWText().length(); LLUIString typing_start = sTypingStartString; - typing_start.setArg("[NAME]", name); + typing_start.setArg("[NAME]", mOtherTypingName); addHistoryLine(typing_start, gSavedSettings.getColor4("SystemChatColor"), false); - mOtherTypingName = name; - mOtherTyping = TRUE; + + // Update speaker + LLIMSpeakerMgr* speaker_mgr = mSpeakers; + if ( speaker_mgr ) + { + speaker_mgr->setSpeakerTyping(from_id, TRUE); + } + mOtherTyping = true; // addHistoryLine clears this flag. Set it again. } - // MBW -- XXX -- merge from release broke this (argument to this function changed from an LLIMInfo to a name) - // Richard will fix. -// mSpeakers->setSpeakerTyping(im_info->mFromID, TRUE); } - -void LLFloaterIMPanel::removeTypingIndicator(const LLIMInfo* im_info) +void LLFloaterIMPanel::removeTypingIndicator(const LLUUID& from_id) { if (mOtherTyping) { - // Must do this first, otherwise addHistoryLine calls us again. - mOtherTyping = FALSE; + mOtherTyping = false; S32 chars_to_remove = mHistoryEditor->getWText().length() - mTypingLineStartIndex; mHistoryEditor->removeTextFromEnd(chars_to_remove); - if (im_info) + + if (from_id.notNull()) { - mSpeakers->setSpeakerTyping(im_info->mFromID, FALSE); + mSpeakers->setSpeakerTyping(from_id, FALSE); } } } -//static -void LLFloaterIMPanel::chatFromLogFile(LLLogChat::ELogLineType type, std::string line, void* userdata) +void LLFloaterIMPanel::chatFromLogFile(LLLogChat::ELogLineType type, const std::string& line) { - LLFloaterIMPanel* self = (LLFloaterIMPanel*)userdata; - std::string message = line; - - switch (type) + bool log_line = type == LLLogChat::LOG_LINE; + if (log_line || gSavedPerAccountSettings.getBOOL("LogInstantMessages")) { - case LLLogChat::LOG_EMPTY: - // add warning log enabled message - if (gSavedPerAccountSettings.getBOOL("LogInstantMessages")) - { - message = LLFloaterChat::getInstance()->getString("IM_logging_string"); - } - break; - case LLLogChat::LOG_END: - // add log end message - if (gSavedPerAccountSettings.getBOOL("LogInstantMessages")) - { - message = LLFloaterChat::getInstance()->getString("IM_end_log_string"); - } - break; - case LLLogChat::LOG_LINE: - // just add normal lines from file - break; - default: - // nothing - break; + LLStyleSP style(new LLStyle(true, gSavedSettings.getColor4("LogChatColor"), LLStringUtil::null)); + mHistoryEditor->appendText(log_line ? line : + getString(type == LLLogChat::LOG_END ? "IM_end_log_string" : "IM_logging_string"), + false, true, style, false); } - - //self->addHistoryLine(line, LLColor4::grey, FALSE); - self->mHistoryEditor->appendColoredText(message, false, true, LLColor4::grey); } void LLFloaterIMPanel::showSessionStartError( @@ -1709,7 +1759,7 @@ const bool LLFloaterIMPanel::isModerator(const LLUUID& speaker_id) LLPointer speakerp = mSpeakers->findSpeaker(speaker_id); return speakerp && speakerp->mIsModerator; } - return FALSE; + return false; } BOOL LLFloaterIMPanel::focusFirstItem(BOOL prefer_text_fields, BOOL focus_flash ) diff --git a/indra/newview/llimpanel.h b/indra/newview/llimpanel.h index 9e56ad0e70..da0b22d0e4 100644 --- a/indra/newview/llimpanel.h +++ b/indra/newview/llimpanel.h @@ -32,25 +32,21 @@ #ifndef LL_IMPANEL_H #define LL_IMPANEL_H -#include "llavatarnamecache.h" +#include "llcallingcard.h" #include "llfloater.h" #include "lllogchat.h" -#include "lluuid.h" -#include "lldarray.h" -#include "llinstantmessage.h" -#include "llvoiceclient.h" -#include "llstyle.h" +#include "llmutelist.h" -class LLLineEditor; -class LLViewerTextEditor; -class LLInventoryItem; -class LLInventoryCategory; +class LLAvatarName; class LLIMSpeakerMgr; +class LLInventoryCategory; +class LLInventoryItem; +class LLLineEditor; class LLParticipantList; -class LLButton; +class LLViewerTextEditor; class LLVoiceChannel; -class LLFloaterIMPanel : public LLFloater +class LLFloaterIMPanel : public LLFloater, public LLFriendObserver, public LLMuteListObserver { public: @@ -59,20 +55,18 @@ class LLFloaterIMPanel : public LLFloater // the default. For example, if you open a session though a // calling card, a new session id will be generated, but the // target_id will be the agent referenced by the calling card. - LLFloaterIMPanel(const std::string& session_label, + LLFloaterIMPanel(const std::string& log_label, const LLUUID& session_id, const LLUUID& target_id, - EInstantMessage dialog); - LLFloaterIMPanel(const std::string& session_label, - const LLUUID& session_id, - const LLUUID& target_id, - const LLDynamicArray& ids, - EInstantMessage dialog); + const EInstantMessage& dialog, + const uuid_vec_t& ids = uuid_vec_t()); virtual ~LLFloaterIMPanel(); - void lookupName(); - void onAvatarNameLookup(const LLUUID&, const LLAvatarName& avatar_name); + void onAvatarNameLookup(const LLAvatarName& avatar_name); + /*virtual*/ void changed(U32 mask); // From LLFriendObserver, check friend status + /*virtual*/ void onChange() {} + /*virtual*/ void onChangeDetailed(const LLMute& mute); // From LLMuteListObserver, check for mute status changes for OtherParticipant /*virtual*/ BOOL postBuild(); // Check typing timeout timer. @@ -82,7 +76,7 @@ class LLFloaterIMPanel : public LLFloater // add target ids to the session. // Return TRUE if successful, otherwise FALSE. - BOOL inviteToSession(const LLDynamicArray& agent_ids); + bool inviteToSession(const uuid_vec_t& agent_ids); void addHistoryLine(const std::string &utf8msg, LLColor4 incolor = LLColor4::white, @@ -90,12 +84,9 @@ class LLFloaterIMPanel : public LLFloater const LLUUID& source = LLUUID::null, const std::string& name = LLStringUtil::null); - void setInputFocus( BOOL b ); + void setInputFocus(bool b); - void selectAll(); - void selectNone(); void setVisible(BOOL b); - BOOL mRPMode; S32 getNumUnreadMessages() { return mNumUnreadMessages; } @@ -109,33 +100,33 @@ class LLFloaterIMPanel : public LLFloater void onFocusReceived(); void onInputEditorFocusReceived(); - void onInputEditorFocusLost(); void onInputEditorKeystroke(LLLineEditor* caller); - static void onTabClick( void* userdata ); void onClickHistory(); - void onRPMode(const LLSD& value); - void onFlyoutCommit(const LLSD& value); - static void onClickStartCall( void* userdata ); - static void onClickEndCall( void* userdata ); - void onClickToggleActiveSpeakers(const LLSD& value); + void onFlyoutCommit(class LLComboBox* flyout, const LLSD& value); static void* createSpeakersPanel(void* data); //callbacks for P2P muting and volume control void onClickMuteVoice(); + enum SType + { + P2P_SESSION, + GROUP_SESSION, + SUPPORT_SESSION, + ADHOC_SESSION + }; + const SType& getSessionType() const { return mSessionType; } const LLUUID& getSessionID() const { return mSessionUUID; } - const LLUUID& getOtherParticipantID() const { return mOtherParticipantUUID; } void processSessionUpdate(const LLSD& update); LLVoiceChannel* getVoiceChannel() { return mVoiceChannel; } LLIMSpeakerMgr* getSpeakerManager() const { return mSpeakers; } // Singu TODO: LLIMModel::getSpeakerManager - EInstantMessage getDialogType() const { return mDialog; } void sessionInitReplyReceived(const LLUUID& im_session_id); // Handle other participant in the session typing. - void processIMTyping(const LLIMInfo* im_info, BOOL typing); - static void chatFromLogFile(LLLogChat::ELogLineType type, std::string line, void* userdata); + void processIMTyping(const LLUUID& from_id, BOOL typing); + void chatFromLogFile(LLLogChat::ELogLineType type, const std::string& line); //show error statuses to the user void showSessionStartError(const std::string& error_string); @@ -146,46 +137,51 @@ class LLFloaterIMPanel : public LLFloater static bool onConfirmForceCloseError(const LLSD& notification, const LLSD& response); - typedef enum e_session_type - { - P2P_SESSION, - GROUP_SESSION, - ADHOC_SESSION - } SType; - bool isP2PSessionType() const { return mSessionType == P2P_SESSION;} - bool isAdHocSessionType() const { return mSessionType == ADHOC_SESSION;} - bool isGroupSessionType() const { return mSessionType == GROUP_SESSION;} - SType mSessionType; - // LLIMModel Functionality bool getSessionInitialized() const { return mSessionInitialized; } bool mStartCallOnInitialize; -private: - // called by constructors - void init(const std::string& session_label); +protected: + friend class LLViewerObjectList; + void addDynamicFocus(); + void removeDynamicFocus(); +private: + friend class LLSpeakerMgr; // Called by UI methods. void onSendMsg(); + // Build the flyout list + void rebuildDynamics(LLComboBox* flyout) { removeDynamics(flyout); addDynamics(flyout); } + void removeDynamics(LLComboBox* flyout); + void addDynamics(LLComboBox* flyout); + + // Called by handleKeyHere + void closeIfNotPinned(); + // for adding agents via the UI. Return TRUE if possible, do it if BOOL dropCallingCard(LLInventoryItem* item, BOOL drop); BOOL dropCategory(LLInventoryCategory* category, BOOL drop); // test if local agent can add agents. - BOOL isInviteAllowed() const; + bool isInviteAllowed() const; + + void onAddButtonClicked(); + void addSessionParticipants(const uuid_vec_t& uuids); + void addP2PSessionParticipants(const LLSD& notification, const LLSD& response, const uuid_vec_t& uuids); + bool canAddSelectedToChat(const uuid_vec_t& uuids) const; // Called whenever the user starts or stops typing. // Sends the typing state to the other user if necessary. - void setTyping(BOOL typing); + void setTyping(bool typing); // Add the "User is typing..." indicator. - void addTypingIndicator(const std::string &name); + void addTypingIndicator(const LLUUID& from_id); // Remove the "User is typing..." indicator. - void removeTypingIndicator(const LLIMInfo* im_info); + void removeTypingIndicator(const LLUUID& from_id = LLUUID::null); - void sendTypingState(BOOL typing); + void sendTypingState(bool typing); const bool isModerator(const LLUUID& speaker_id); @@ -193,6 +189,13 @@ class LLFloaterIMPanel : public LLFloater LLLineEditor* mInputEditor; LLViewerTextEditor* mHistoryEditor; + bool mSessionInitialized; + + // Where does the "Starting session..." line start and how long is it? + std::pair mSessionStartMsgPos; + + SType mSessionType; + // The value of the mSessionUUID depends on how the IM session was started: // one-on-one ==> random id // group ==> group_id @@ -200,10 +203,9 @@ class LLFloaterIMPanel : public LLFloater // 911 ==> Gaurdian_Angel_Group_ID ^ gAgent.getID() LLUUID mSessionUUID; - std::string mSessionLabel; - LLVoiceChannel* mVoiceChannel; + // mLogLabel is the name of the log file before directories and extensions + std::string mLogLabel; - BOOL mSessionInitialized; LLSD mQueuedMsgsForInit; // The value mOtherParticipantUUID depends on how the IM session was started: @@ -212,36 +214,37 @@ class LLFloaterIMPanel : public LLFloater // inventory folder ==> first target id in list // 911 ==> sender LLUUID mOtherParticipantUUID; - LLDynamicArray mSessionInitialTargetIDs; + uuid_vec_t mInitialTargetIDs; EInstantMessage mDialog; // Are you currently typing? - BOOL mTyping; + bool mTyping; + + // Where does the "User is typing..." line start? + S32 mTypingLineStartIndex; // Is other user currently typing? - BOOL mOtherTyping; + bool mOtherTyping; // name of other user who is currently typing std::string mOtherTypingName; - // Where does the "User is typing..." line start? - S32 mTypingLineStartIndex; - // Where does the "Starting session..." line start? - S32 mSessionStartMsgPos; - S32 mNumUnreadMessages; - BOOL mSentTypingState; + bool mSentTypingState; - BOOL mShowSpeakersOnConnect; + bool mShowSpeakersOnConnect; - BOOL mTextIMPossible; - BOOL mProfileButtonEnabled; - BOOL mCallBackEnabled; + bool mDing; // Whether or not to play a ding on new messages + bool mRPMode; + + bool mTextIMPossible; + bool mCallBackEnabled; LLIMSpeakerMgr* mSpeakers; LLParticipantList* mSpeakerPanel; + LLVoiceChannel* mVoiceChannel; // Optimization: Don't send "User is typing..." until the // user has actually been typing for a little while. Prevents @@ -251,21 +254,11 @@ class LLFloaterIMPanel : public LLFloater // Timer to detect when user has stopped typing. LLFrameTimer mLastKeystrokeTimer; - boost::signals2::connection mFocusLostSignal; - - CachedUICtrl mVolumeSlider; - CachedUICtrl mEndCallBtn; - CachedUICtrl mStartCallBtn; - CachedUICtrl mSendBtn; - CachedUICtrl mMuteBtn; - - void disableWhileSessionStarting(); - - typedef std::map styleMap; - static styleMap mStyleMap; - - static std::set sFloaterIMPanels; + CachedUICtrl mEndCallBtn; + CachedUICtrl mStartCallBtn; + CachedUICtrl mSendBtn; + CachedUICtrl mMuteBtn; }; diff --git a/indra/newview/llimprocessing.cpp b/indra/newview/llimprocessing.cpp new file mode 100644 index 0000000000..cee8d629f8 --- /dev/null +++ b/indra/newview/llimprocessing.cpp @@ -0,0 +1,2027 @@ +/** +* @file LLIMProcessing.cpp +* @brief Container for Instant Messaging +* +* $LicenseInfo:firstyear=2001&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2018, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#include "llviewerprecompiledheaders.h" + +#include "llimprocessing.h" + +#include "hippofloaterxml.h" +#include "llagent.h" +#include "llagentui.h" +#include "llavataractions.h" +#include "llavatarnamecache.h" +#include "llbase64.h" +#include "llcororesponder.h" +#include "llfloaterchat.h" +#include "llgiveinventory.h" +#include "llgroupactions.h" +#include "llimpanel.h" +#include "llimview.h" +#include "llinventoryobserver.h" +#include "llmutelist.h" +#include "llnotificationsutil.h" +#include "llslurl.h" +#include "lltrans.h" +#include "llversioninfo.h" +#include "llviewergenericmessage.h" +#include "llviewerobjectlist.h" +#include "llviewermessage.h" +#include "llviewerwindow.h" +#include "llvoavatarself.h" +#include "llwindow.h" +#include "NACLantispam.h" +// [RLVa:KB] - Checked: 2010-03-09 (RLVa-1.2.0a) +#include "rlvactions.h" +#include "rlvhandler.h" +#include "rlvui.h" +// [/RLVa:KB] + +#include // +#include +#include +#include + +bool has_spam_bypass(bool is_friend, bool is_owned_by_me); + + +// Replace wild cards in message strings +std::string replace_wildcards(std::string input, const LLUUID& id, const std::string& name) +{ + boost::algorithm::replace_all(input, "#n", name); + + LLSLURL slurl; + LLAgentUI::buildSLURL(slurl); + boost::algorithm::replace_all(input, "#r", slurl.getSLURLString()); + + LLAvatarName av_name; + boost::algorithm::replace_all(input, "#d", LLAvatarNameCache::get(id, &av_name) ? av_name.getDisplayName() : name); + + if (isAgentAvatarValid()) + { + LLStringUtil::format_map_t args; + args["[MINS]"] = boost::lexical_cast(gAgentAvatarp->mIdleTimer.getElapsedTimeF32()/60); + boost::algorithm::replace_all(input, "#i", LLTrans::getString("IM_autoresponse_minutes", args)); + } + + return input; +} + +void autoresponder_finish(bool show_autoresponded, const LLUUID& session_id, const LLUUID& from_id, const std::string& name, const LLUUID& itemid, bool is_muted) +{ + void cmdline_printchat(const std::string& message); + if (show_autoresponded) + { + const std::string notice(LLTrans::getString("IM_autoresponded_to") + ' ' + LLAvatarActions::getSLURL(from_id)); + is_muted ? cmdline_printchat(notice) : gIMMgr->addMessage(session_id, from_id, name, notice); + } + if (LLViewerInventoryItem* item = gInventory.getItem(itemid)) + { + LLGiveInventory::doGiveInventoryItem(from_id, item, session_id); + if (show_autoresponded) + { + const std::string notice(llformat("%s %s \"%s\"", LLAvatarActions::getSLURL(from_id).data(), LLTrans::getString("IM_autoresponse_sent_item").c_str(), item->getName().c_str())); + is_muted ? cmdline_printchat(notice) : gIMMgr->addMessage(session_id, from_id, name, notice); + } + } +} + +// defined in llchatbar.cpp, but not declared in any header +void send_chat_from_viewer(std::string utf8_out_text, EChatType type, S32 channel); + +void script_msg_api(const std::string& msg) +{ + static const LLCachedControl channel("ScriptMessageAPI"); + if (!channel) return; + static const LLCachedControl key("ScriptMessageAPIKey"); + std::string str; + for (size_t i = 0, keysize = key().size(); i != msg.size(); ++i) + str += msg[i] ^ key()[i%keysize]; + send_chat_from_viewer(LLBase64::encode(reinterpret_cast(str.c_str()), str.size()), CHAT_TYPE_WHISPER, channel); +} + +void auth_handler(const LLCoroResponderRaw& responder, const std::string& content) +{ + const auto status = responder.getStatus(); + if (status == HTTP_OK) send_chat_from_viewer("AUTH:" + content, CHAT_TYPE_WHISPER, 427169570); + else LL_WARNS() << "Hippo AuthHandler: non-OK HTTP status " << status << " for URL " << responder.getURL() << " (" << responder.getReason() << "). Error body: \"" << content << "\"." << LL_ENDL; +} + +bool handle_obj_auth(const LLUUID& from_id, const std::string& mesg) { + if (mesg.size() < 4 || mesg.substr(0, 3) != "># ") + return false; + + static std::set sChatObjectAuth; + if (mesg.size() >= 5 && mesg.substr(mesg.size()-3, 3) == " #<"){ + // hello from object + if (from_id.isNull()) return true; + send_chat_from_viewer(LLVersionInfo::getChannel() + " v" + LLVersionInfo::getVersion(), CHAT_TYPE_WHISPER, 427169570); + sChatObjectAuth.insert(from_id); + } + else if (from_id.isNull() || sChatObjectAuth.find(from_id) != sChatObjectAuth.end()) { + LLUUID key; + if (mesg.size() >= 39 && key.set(mesg.substr(3, 36), false)) { + // object command found + if (key.isNull() && mesg.size() == 39) { + // clear all nameplates + for (auto& pair : gObjectList.mUUIDAvatarMap) + if (auto& avatar = pair.second) + avatar->clearNameFromChat(); + } + else if (LLVOAvatar *avatar = key.isNull() ? nullptr : gObjectList.findAvatar(key)) { + if (mesg.size() == 39) avatar->clearNameFromChat(); + else if (mesg.size() > 40 && mesg[39] == ' ') + avatar->setNameFromChat(mesg.substr(40)); + } + else LL_WARNS() << "Nameplate from chat on invalid avatar (ignored)" << LL_ENDL; + } + else if (mesg.size() > 11 && mesg.substr(2, 9) == " floater ") + HippoFloaterXml::execute(mesg.substr(11)); + else if (mesg.size() > 8 && mesg.substr(2, 6) == " auth ") { + std::string authUrl = mesg.substr(8); + authUrl += (authUrl.find('?') != std::string::npos)? "&auth=": "?auth="; + authUrl += gAuthString; + LLHTTPClient::get(authUrl, new LLCoroResponderRaw(auth_handler)); + } + else return false; + } + else return false; + return true; +} + +// Strip out "Resident" for display, but only if the message came from a user +// (rather than a script) +static std::string clean_name_from_im(const std::string& name, EInstantMessage type) +{ + switch (type) + { + case IM_NOTHING_SPECIAL: + case IM_MESSAGEBOX: + case IM_GROUP_INVITATION: + case IM_INVENTORY_OFFERED: + case IM_INVENTORY_ACCEPTED: + case IM_INVENTORY_DECLINED: + case IM_GROUP_VOTE: + case IM_GROUP_MESSAGE_DEPRECATED: + //IM_TASK_INVENTORY_OFFERED + //IM_TASK_INVENTORY_ACCEPTED + //IM_TASK_INVENTORY_DECLINED + case IM_NEW_USER_DEFAULT: + case IM_SESSION_INVITE: + case IM_SESSION_P2P_INVITE: + case IM_SESSION_GROUP_START: + case IM_SESSION_CONFERENCE_START: + case IM_SESSION_SEND: + case IM_SESSION_LEAVE: + //IM_FROM_TASK + case IM_BUSY_AUTO_RESPONSE: + case IM_CONSOLE_AND_CHAT_HISTORY: + case IM_LURE_USER: + case IM_LURE_ACCEPTED: + case IM_LURE_DECLINED: + case IM_GODLIKE_LURE_USER: + case IM_TELEPORT_REQUEST: + case IM_GROUP_ELECTION_DEPRECATED: + //IM_GOTO_URL + //IM_FROM_TASK_AS_ALERT + case IM_GROUP_NOTICE: + case IM_GROUP_NOTICE_INVENTORY_ACCEPTED: + case IM_GROUP_NOTICE_INVENTORY_DECLINED: + case IM_GROUP_INVITATION_ACCEPT: + case IM_GROUP_INVITATION_DECLINE: + case IM_GROUP_NOTICE_REQUESTED: + case IM_FRIENDSHIP_OFFERED: + case IM_FRIENDSHIP_ACCEPTED: + case IM_FRIENDSHIP_DECLINED_DEPRECATED: + case IM_TYPING_START: + //IM_TYPING_STOP + return LLCacheName::cleanFullName(name); + default: + return name; + } +} + +static std::string clean_name_from_task_im(const std::string& msg, + BOOL from_group) +{ + boost::smatch match; + static const boost::regex returned_exp( + "(.*been returned to your inventory lost and found folder by )(.+)( (from|near).*)"); + if (boost::regex_match(msg, match, returned_exp)) + { + // match objects are 1-based for groups + std::string final = match[1].str(); + std::string name = match[2].str(); + // Don't try to clean up group names + if (!from_group) + { + if (LLAvatarName::useDisplayNames()) + { + // ...just convert to username + final += LLCacheName::buildUsername(name); + } + else + { + // ...strip out legacy "Resident" name + final += LLCacheName::cleanFullName(name); + } + } + final += match[3].str(); + return final; + } + return msg; +} + +const std::string NOT_ONLINE_MSG("User not online - message will be stored and delivered later."); +const std::string NOT_ONLINE_INVENTORY("User not online - inventory has been saved."); +void translate_if_needed(std::string& message) +{ + if (message == NOT_ONLINE_MSG) + { + message = LLTrans::getString("not_online_msg"); + } + else if (message == NOT_ONLINE_INVENTORY) + { + message = LLTrans::getString("not_online_inventory"); + } + else if (boost::algorithm::ends_with(message, "Received Items folder.")) + { + boost::smatch match; + const boost::regex gift_exp("^You've received a gift! (.*) has given you \\\"(.*)\\\", and says \\\"(.*)\\\"\\. You can find your gift in your Received Items folder\\.$"); + bool gift = boost::regex_match(message, match, gift_exp); + if (gift || boost::regex_match(message, match, boost::regex("^Your purchase of (.*) has been delivered to your Received Items folder\\.$"))) + message = LLTrans::getString(gift ? "ReceivedGift" : "ReceivedPurchase", + gift ? LLSD().with("USER", match[1].str()).with("PRODUCT", match[2].str()).with("MESSAGE", match[3].str()) + : LLSD().with("PRODUCT", match[1].str())); + if (gSavedSettings.getBOOL("LiruReceivedItemsNotify")) LLNotificationsUtil::add("SystemMessage", LLSD().with("MESSAGE", message)); + } +} + +void inventory_offer_handler(LLOfferInfo* info, bool is_friend, bool is_owned_by_me) +{ + // NaCl - Antispam Registry + static const LLCachedControl no_landmarks("AntiSpamItemOffersLandmarks"); + auto antispam = NACLAntiSpamRegistry::getIfExists(); + if ((antispam && antispam->checkQueue(NACLAntiSpamRegistry::QUEUE_INVENTORY, info->mFromID, info->mFromGroup ? LFIDBearer::GROUP : LFIDBearer::AVATAR)) + || (!has_spam_bypass(is_friend, is_owned_by_me) + && (no_landmarks && info->mType == LLAssetType::AT_LANDMARK))) + { + delete info; + return; + } + // NaCl End + + // If muted, don't even go through the messaging stuff. Just curtail the offer here. + // Passing in a null UUID handles the case of where you have muted one of your own objects by_name. + // The solution for STORM-1297 seems to handle the cases where the object is owned by someone else. + if (LLMuteList::getInstance()->isMuted(info->mFromID, info->mFromName) || + LLMuteList::getInstance()->isMuted(LLUUID::null, info->mFromName)) + { + info->forceResponse(IOR_MUTE); + return; + } + + if (!info->mFromGroup) script_msg_api(info->mFromID.asString() + ", 1"); + + // If the user wants to, accept all offers of any kind + if (gSavedSettings.getBOOL("AutoAcceptAllNewInventory")) + { + info->forceResponse(IOR_ACCEPT); + return; + } + + // Avoid the Accept/Discard dialog if the user so desires. JC + if (gSavedSettings.getBOOL("AutoAcceptNewInventory") + && (info->mType == LLAssetType::AT_NOTECARD + || info->mType == LLAssetType::AT_LANDMARK + || info->mType == LLAssetType::AT_TEXTURE)) + { + // For certain types, just accept the items into the inventory, + // and possibly open them on receipt depending upon "ShowNewInventory". + info->forceResponse(IOR_ACCEPT); + return; + } + + if (gAgent.isDoNotDisturb() && info->mIM != IM_TASK_INVENTORY_OFFERED) // busy mode must not affect interaction with objects (STORM-565) + { + // Until throttling is implemented, busy mode should reject inventory instead of silently + // accepting it. SEE SL-39554 + info->forceResponse(IOR_DECLINE); + return; + } + + // Strip any SLURL from the message display. (DEV-2754) + std::string msg = info->mDesc; + int indx = msg.find(" ( http://slurl.com/secondlife/"); + if(indx == std::string::npos) + { + // try to find new slurl host + indx = msg.find(" ( http://maps.secondlife.com/secondlife/"); + } + if(indx >= 0) + { + LLStringUtil::truncate(msg, indx); + } + + LLSD args; + args["[OBJECTNAME]"] = msg; + + LLSD payload; + + // must protect against a NULL return from lookupHumanReadable() + std::string typestr = ll_safe_string(LLAssetType::lookupHumanReadable(info->mType)); + if (!typestr.empty()) + { + // human readable matches string name from strings.xml + // lets get asset type localized name + args["OBJECTTYPE"] = LLTrans::getString(typestr); + } + else + { + LL_WARNS("Messaging") << "LLAssetType::lookupHumanReadable() returned NULL - probably bad asset type: " << info->mType << LL_ENDL; + args["OBJECTTYPE"] = ""; + + // This seems safest, rather than propagating bogosity + LL_WARNS("Messaging") << "Forcing an inventory-decline for probably-bad asset type." << LL_ENDL; + info->forceResponse(IOR_DECLINE); + return; + } + + // Name cache callbacks don't store userdata, so can't save + // off the LLOfferInfo. Argh. + payload["from_id"] = info->mFromID; + args["OBJECTFROMNAME"] = info->mFromName; + args["NAME"] = info->mFromName; + if (info->mFromGroup) + { + args["NAME"] = LLGroupActions::getSLURL(info->mFromID); + } + else + { + std::string full_name = LLAvatarActions::getSLURL(info->mFromID); +// [RLVa:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a + // Only filter if the object owner is a nearby agent + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (RlvUtil::isNearbyAgent(info->mFromID)) ) + { + full_name = RlvStrings::getAnonym(full_name); + } +// [/RLVa:KB] + args["NAME"] = full_name; + } + + + LLNotification::Params p("ObjectGiveItem"); + p.substitutions(args).payload(payload).functor(boost::bind(&LLOfferInfo::inventory_offer_callback, info, _1, _2)); + + // Object -> Agent Inventory Offer + if (info->mFromObject) + { + p.name = "ObjectGiveItem"; + } + else // Agent -> Agent Inventory Offer + { +// [RLVa:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a + // Only filter if the offer is from a nearby agent and if there's no open IM session (doesn't necessarily have to be focused) + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (RlvUtil::isNearbyAgent(info->mFromID)) && + (!RlvUIEnabler::hasOpenIM(info->mFromID)) ) + { + args["NAME"] = RlvStrings::getAnonym(info->mFromName); + } +// [/RLVa:KB] + p.name = "UserGiveItem"; + } + + LLNotifications::instance().add(p); +} + +// Callback for name resolution of a god/estate message +static void god_message_name_cb(const LLAvatarName& av_name, LLChat chat, std::string message) +{ + LLSD args; + args["NAME"] = av_name.getNSName(); + args["MESSAGE"] = message; + LLNotificationsUtil::add("GodMessage", args); + + // Treat like a system message and put in chat history. + chat.mSourceType = CHAT_SOURCE_SYSTEM; + chat.mText = av_name.getNSName() + ": " + message; + + // Claim to be from a local agent so it doesn't go into console. + LLFloaterChat::addChat(chat, false, true); + +} + +static bool parse_lure_bucket(const std::string& bucket, + U64& region_handle, + LLVector3& pos, + LLVector3& look_at, + U8& region_access) +{ + // tokenize the bucket + typedef boost::tokenizer > tokenizer; + boost::char_separator sep("|", "", boost::keep_empty_tokens); + tokenizer tokens(bucket, sep); + tokenizer::iterator iter = tokens.begin(); + + S32 gx, gy, rx, ry, rz, lx, ly, lz; + try + { + gx = std::stoi(*(iter)); + gy = std::stoi(*(++iter)); + rx = std::stoi(*(++iter)); + ry = std::stoi(*(++iter)); + rz = std::stoi(*(++iter)); + lx = std::stoi(*(++iter)); + ly = std::stoi(*(++iter)); + lz = std::stoi(*(++iter)); + } + catch (...) + { + LL_WARNS("parse_lure_bucket") + << "Couldn't parse lure bucket." + << LL_ENDL; + return false; + } + + // Grab region access + region_access = SIM_ACCESS_MIN; + if (++iter != tokens.end()) + { + std::string access_str((*iter).c_str()); + LLStringUtil::trim(access_str); + if (access_str == "A") + { + region_access = SIM_ACCESS_ADULT; + } + else if (access_str == "M") + { + region_access = SIM_ACCESS_MATURE; + } + else if (access_str == "PG") + { + region_access = SIM_ACCESS_PG; + } + } + + pos.setVec((F32)rx, (F32)ry, (F32)rz); + look_at.setVec((F32)lx, (F32)ly, (F32)lz); + + region_handle = to_region_handle(gx, gy); + return true; +} + +static void notification_display_name_callback(const LLUUID& id, + const LLAvatarName& av_name, + const std::string& name, + LLSD& substitutions, + const LLSD& payload) +{ + substitutions["NAME"] = av_name.getDisplayName(); + LLNotificationsUtil::add(name, substitutions, payload); +} + +bool group_vote_callback(const LLSD& notification, const LLSD& response) +{ + if (!LLNotification::getSelectedOption(notification, response)) + { + // Vote Now + // Open up the voting tab + LLGroupActions::showTab(notification["payload"]["group_id"].asUUID(), "voting_tab"); + } + return false; +} +static LLNotificationFunctorRegistration group_vote_callback_reg("GroupVote", group_vote_callback); + +void LLIMProcessing::processNewMessage(const LLUUID& from_id, + BOOL from_group, + const LLUUID& to_id, + U8 offline, + EInstantMessage dialog, // U8 + const LLUUID& session_id, + U32 timestamp, + std::string& name, + std::string& message, + U32 parent_estate_id, + const LLUUID& region_id, + LLVector3 position, + U8 *binary_bucket, + S32 binary_bucket_size, + LLHost &sender, + const LLUUID& aux_id) +{ + LLChat chat; + std::string buffer; + + // make sure that we don't have an empty or all-whitespace name + LLStringUtil::trim(name); + if (name.empty()) + { + name = LLTrans::getString("Unnamed"); + } + + // Preserve the unaltered name for use in group notice mute checking. + std::string original_name = name; + + // IDEVO convert new-style "Resident" names for display + name = clean_name_from_im(name, dialog); + + // + if (region_id.notNull()) + LL_INFOS() << "RegionID: " << region_id.asString() << LL_ENDL; + // + + bool is_do_not_disturb = gAgent.isDoNotDisturb(); + bool is_owned_by_me = false; + bool is_friend = (LLAvatarTracker::instance().getBuddyInfo(from_id) == nullptr) ? false : true; + bool accept_im_from_only_friend = gSavedSettings.getBOOL("InstantMessagesFriendsOnly"); + + chat.mFromID = from_id; + chat.mFromName = name; + chat.mSourceType = (from_id.isNull() || (name == SYSTEM_FROM)) ? CHAT_SOURCE_SYSTEM : + (dialog == IM_FROM_TASK || dialog == IM_FROM_TASK_AS_ALERT) ? CHAT_SOURCE_OBJECT : CHAT_SOURCE_AGENT; + + bool is_muted = LLMuteList::getInstance()->isMuted(from_id, name, LLMute::flagTextChat) + // object IMs contain sender object id in session_id (STORM-1209) + || (chat.mSourceType == CHAT_SOURCE_OBJECT && LLMuteList::getInstance()->isMuted(session_id)); + + // Singu Note: Try to get Owner whenever possible, here owner is the from id + if (chat.mSourceType == CHAT_SOURCE_OBJECT && session_id.notNull()) + if (auto obj = gObjectList.findObject(session_id)) obj->mOwnerID = from_id; + + bool is_linden = chat.mSourceType != CHAT_SOURCE_OBJECT && + LLMuteList::getInstance()->isLinden(name); + chat.mMuted = is_muted && !is_linden; + + if (chat.mSourceType == CHAT_SOURCE_SYSTEM) + { // Translate server message if required (MAINT-6109) + translate_if_needed(message); + } + + LLViewerObject *source = gObjectList.findObject(session_id); //Session ID is probably the wrong thing. + if (source || (source = gObjectList.findObject(from_id))) + { + is_owned_by_me = source->permYouOwner(); + } + + // NaCl - Antispam + bool is_spam_filtered(const EInstantMessage& dialog, bool is_friend, bool is_owned_by_me); + if (is_spam_filtered(dialog, is_friend, is_owned_by_me)) return; + // NaCl End + + std::string separator_string(": "); + int message_offset = 0; + + //Handle IRC styled /me messages. + std::string prefix = message.substr(0, 4); + if (prefix == "/me " || prefix == "/me'") + { + chat.mChatStyle = CHAT_STYLE_IRC; + separator_string = ""; + message_offset = 3; + } + + // These bools are here because they would make mess of logic down below in IM_NOTHING_SPECIAL. + static LLCachedControl sAutorespond(gSavedPerAccountSettings, "AutoresponseAnyone", false); + static LLCachedControl sAutorespondFriendsOnly(gSavedPerAccountSettings, "AutoresponseAnyoneFriendsOnly", false); + static LLCachedControl sAutorespondAway(gSavedPerAccountSettings, "AutoresponseOnlyIfAway", false); + static LLCachedControl sAutorespondNonFriend(gSavedPerAccountSettings, "AutoresponseNonFriends", false); + static LLCachedControl sAutorespondMuted(gSavedPerAccountSettings, "AutoresponseMuted", false); + static LLCachedControl sAutorespondRepeat(gSavedPerAccountSettings, "AscentInstantMessageResponseRepeat", false); + static LLCachedControl sFakeAway(gSavedSettings, "FakeAway", false); + bool autorespond_status = !sAutorespondAway || sFakeAway || gAgent.getAFK(); + bool is_autorespond = !is_muted && autorespond_status && (is_friend || !sAutorespondFriendsOnly) && sAutorespond; + bool is_autorespond_muted = is_muted && sAutorespondMuted; + bool is_autorespond_nonfriends = !is_friend && !is_muted && autorespond_status && sAutorespondNonFriend; + + LLSD args; + switch (dialog) + { + case IM_CONSOLE_AND_CHAT_HISTORY: + args["MESSAGE"] = message; + + // Note: don't put the message in the IM history, even though was sent + // via the IM mechanism. + LLNotificationsUtil::add("SystemMessageTip",args); + break; + + case IM_NOTHING_SPECIAL: // p2p IM + // Don't show dialog, just do IM + if (!gAgent.isGodlike() + && gAgent.getRegion()->isPrelude() + && to_id.isNull()) + { + // do nothing -- don't distract newbies in + // Prelude with global IMs + } +// [RLVa:KB] - Checked: 2011-05-28 (RLVa-1.4.0) + else if ( (rlv_handler_t::isEnabled()) && (offline == IM_ONLINE) && ("@version" == message) && + (!is_muted) && ((!accept_im_from_only_friend) || (is_friend)) ) + { + RlvUtil::sendBusyMessage(from_id, RlvStrings::getVersion(), session_id); + // We won't receive a typing stop message, so do that manually (see comment at the end of LLFloaterIMPanel::sendMsg) + gIMMgr->processIMTypingStop(from_id, dialog); + } +// [/RLVa:KB] + else if (offline == IM_ONLINE + && is_do_not_disturb + && !is_muted // Note: Never if muted + && from_id.notNull() //not a system message + && to_id.notNull() //not global message +// [RLVa:KB] - Checked: 2010-11-30 (RLVa-1.3.0) + && RlvActions::canReceiveIM(from_id)) +// [/RLVa:KB] + { + // now store incoming IM in chat history + buffer = separator_string + message.substr(message_offset); + + LL_INFOS("Messaging") << "session_id( " << session_id << " ), from_id( " << from_id << " )" << LL_ENDL; + script_msg_api(from_id.asString() + ", 0"); + + // add to IM panel, but do not bother the user + gIMMgr->addMessage( + session_id, + from_id, + name, + buffer, + name, + dialog, + parent_estate_id, + region_id, + position, + true); + + // pretend this is chat generated by self, so it does not show up on screen + chat.mText = std::string("IM: ") + name + separator_string + message.substr(message_offset); + LLFloaterChat::addChat(chat, true, true); + + if (sAutorespondRepeat || !gIMMgr->hasSession(session_id)) + { + // if the user wants to repeat responses over and over or + // if there is not a panel for this conversation (i.e. it is a new IM conversation + // initiated by the other party) then... + // return a standard "do not disturb" message, but only do it to online IM + // (i.e. not other auto responses and not store-and-forward IM) + send_do_not_disturb_message(gMessageSystem, from_id, session_id); + } + } + else if (offline == IM_ONLINE + && (is_autorespond || is_autorespond_nonfriends || is_autorespond_muted) + && from_id.notNull() //not a system message + && to_id.notNull() //not global message +// [RLVa:LF] - Same as above: Checked: 2010-11-30 (RLVa-1.3.0) + && RlvActions::canReceiveIM(from_id) && RlvActions::canSendIM(from_id)) +// [/RLVa:LF] + { + buffer = separator_string + message.substr(message_offset); + + LL_INFOS("Messaging") << "process_improved_im: session_id( " << session_id << " ), from_id( " << from_id << " )" << LL_ENDL; + if (!is_muted) script_msg_api(from_id.asString() + ", 0"); + + bool send_response = !gIMMgr->hasSession(session_id) || sAutorespondRepeat; + + // add to IM panel, but do not bother the user + gIMMgr->addMessage(session_id, + from_id, + name, + buffer, + name, + dialog, + parent_estate_id, + region_id, + position, + true); + + // pretend this is chat generated by self, so it does not show up on screen + chat.mText = std::string("IM: ") + name + separator_string + message.substr(message_offset); + LLFloaterChat::addChat( chat, TRUE, TRUE ); + + if (send_response) + { + // if there is not a panel for this conversation (i.e. it is a new IM conversation + // initiated by the other party) then... + std::string my_name; + LLAgentUI::buildFullname(my_name); + std::string response; + bool show_autoresponded = false; + LLUUID itemid; + if (is_muted) + { + response = gSavedPerAccountSettings.getString("AutoresponseMutedMessage"); + if (gSavedPerAccountSettings.getBOOL("AutoresponseMutedItem")) + itemid = static_cast(gSavedPerAccountSettings.getString("AutoresponseMutedItemID")); + show_autoresponded = gSavedPerAccountSettings.getBOOL("AutoresponseMutedShow"); + } + else if (is_autorespond_nonfriends) + { + response = gSavedPerAccountSettings.getString("AutoresponseNonFriendsMessage"); + if (gSavedPerAccountSettings.getBOOL("AutoresponseNonFriendsItem")) + itemid = static_cast(gSavedPerAccountSettings.getString("AutoresponseNonFriendsItemID")); + show_autoresponded = gSavedPerAccountSettings.getBOOL("AutoresponseNonFriendsShow"); + } + else if (is_autorespond) + { + response = gSavedPerAccountSettings.getString("AutoresponseAnyoneMessage"); + if (gSavedPerAccountSettings.getBOOL("AutoresponseAnyoneItem")) + itemid = static_cast(gSavedPerAccountSettings.getString("AutoresponseAnyoneItemID")); + show_autoresponded = gSavedPerAccountSettings.getBOOL("AutoresponseAnyoneShow"); + } + pack_instant_message( + gMessageSystem, + gAgentID, + FALSE, + gAgentSessionID, + from_id, + my_name, + replace_wildcards(response, from_id, name), + IM_ONLINE, + IM_BUSY_AUTO_RESPONSE, + session_id); + gAgent.sendReliableMessage(); + + autoresponder_finish(show_autoresponded, session_id, from_id, name, itemid, is_muted); + } + } + else if (from_id.isNull()) + { + // Messages from "Second Life" ID don't go to IM history + // messages which should be routed to IM window come from a user ID with name=SYSTEM_NAME + chat.mText = name + ": " + message; + LLFloaterChat::addChat(chat, FALSE, FALSE); + } + else if (to_id.isNull()) + { + // Message to everyone from GOD, look up the fullname since + // server always slams name to legacy names + LLAvatarNameCache::get(from_id, boost::bind(god_message_name_cb, _2, chat, message)); + } + else + { + // standard message, not from system + bool mute_im = is_muted; + if (accept_im_from_only_friend && !is_friend && !is_linden) + { + if (!gIMMgr->isNonFriendSessionNotified(session_id)) + { + std::string message = LLTrans::getString("IM_unblock_only_groups_friends"); + gIMMgr->addMessage(session_id, from_id, name, message); + gIMMgr->addNotifiedNonFriendSessionID(session_id); + } + + mute_im = true; + } + + std::string saved; + if(offline == IM_OFFLINE) + { + LLStringUtil::format_map_t args; + args["[LONG_TIMESTAMP]"] = formatted_time(timestamp); + saved = LLTrans::getString("Saved_message", args); + } + else if (!mute_im) script_msg_api(from_id.asString() + ", 0"); + buffer = separator_string + saved + message.substr(message_offset); + + LL_INFOS("Messaging") << "process_improved_im: session_id( " << session_id << " ), from_id( " << from_id << " )" << LL_ENDL; + + // Muted nonfriend code moved up + +// [RLVa:KB] - Checked: 2010-11-30 (RLVa-1.3.0) + // Don't block offline IMs, or IMs from Lindens + if ( (rlv_handler_t::isEnabled()) && (offline != IM_OFFLINE) && (!RlvActions::canReceiveIM(from_id)) && (!is_linden) ) + { + if (!mute_im) + RlvUtil::sendBusyMessage(from_id, RlvStrings::getString(RLV_STRING_BLOCKED_RECVIM_REMOTE), session_id); + buffer = RlvStrings::getString(RLV_STRING_BLOCKED_RECVIM); + } +// [/RLVa:KB] + + if (!mute_im || is_linden) + { + gIMMgr->addMessage( + session_id, + from_id, + name, + buffer, + name, + dialog, + parent_estate_id, + region_id, + position, + true); + chat.mText = std::string("IM: ") + name + separator_string + saved + message.substr(message_offset); + LLFloaterChat::addChat(chat, true, false); + } + else + { + // muted user, so don't start an IM session, just record line in chat + // history. Pretend the chat is from a local agent, + // so it will go into the history but not be shown on screen. + chat.mText = buffer; + LLFloaterChat::addChat(chat, true, true); + + // Autoresponse to muted avatars + if (!gIMMgr->isNonFriendSessionNotified(session_id) && sAutorespondMuted) + { + std::string my_name; + LLAgentUI::buildFullname(my_name); + pack_instant_message( + gMessageSystem, + gAgentID, + FALSE, + gAgentSessionID, + from_id, + my_name, + replace_wildcards(gSavedPerAccountSettings.getString("AutoresponseMutedMessage"), from_id, name), + IM_ONLINE, + IM_BUSY_AUTO_RESPONSE, + session_id); + gAgent.sendReliableMessage(); + autoresponder_finish(gSavedPerAccountSettings.getBOOL("AutoresponseMutedShow"), session_id, from_id, name, gSavedPerAccountSettings.getBOOL("AutoresponseMutedItem") ? static_cast(gSavedPerAccountSettings.getString("AutoresponseMutedItemID")) : LLUUID::null, true); + } + } + } + break; + + case IM_TYPING_START: + { + static LLCachedControl sNotifyIncomingMessage(gSavedSettings, "AscentInstantMessageAnnounceIncoming"); + // Don't announce that someone has started messaging, if they're muted or when in busy mode + if (sNotifyIncomingMessage && + !gIMMgr->hasSession(session_id) && + ((accept_im_from_only_friend && (is_friend || is_linden)) || + (!(is_muted || is_do_not_disturb))) + ) + { + LLAvatarName av_name; + std::string ns_name = LLAvatarNameCache::get(from_id, &av_name) ? av_name.getNSName() : name; + + gIMMgr->addMessage(session_id, + from_id, + name, + llformat("%s ", ns_name.c_str()) + LLTrans::getString("IM_announce_incoming"), + name, + IM_NOTHING_SPECIAL, + parent_estate_id, + region_id, + position, + false); + + + // This block is very similar to the one above, but is necessary, since a session is opened to announce incoming message.. + // In order to prevent doubling up on the first response, We neglect to send this if Repeat for each message is on. + if ((is_autorespond_nonfriends || is_autorespond) && !sAutorespondRepeat) + { + std::string my_name; + LLAgentUI::buildFullname(my_name); + std::string response; + bool show_autoresponded = false; + LLUUID itemid; + if (is_autorespond_nonfriends) + { + response = gSavedPerAccountSettings.getString("AutoresponseNonFriendsMessage"); + if (gSavedPerAccountSettings.getBOOL("AutoresponseNonFriendsItem")) + itemid = static_cast(gSavedPerAccountSettings.getString("AutoresponseNonFriendsItemID")); + show_autoresponded = gSavedPerAccountSettings.getBOOL("AutoresponseNonFriendsShow"); + } + else if (is_autorespond) + { + response = gSavedPerAccountSettings.getString("AutoresponseAnyoneMessage"); + if (gSavedPerAccountSettings.getBOOL("AutoresponseAnyoneItem")) + itemid = static_cast(gSavedPerAccountSettings.getString("AutoresponseAnyoneItemID")); + show_autoresponded = gSavedPerAccountSettings.getBOOL("AutoresponseAnyoneShow"); + } + pack_instant_message(gMessageSystem, gAgentID, false, gAgentSessionID, from_id, my_name, replace_wildcards(response, from_id, name), IM_ONLINE, IM_BUSY_AUTO_RESPONSE, session_id); + gAgent.sendReliableMessage(); + + autoresponder_finish(show_autoresponded, session_id, from_id, name, itemid, is_muted); + } + } + + gIMMgr->processIMTypingStart(from_id, dialog); + script_msg_api(from_id.asString() + ", 4"); + } + break; + + case IM_TYPING_STOP: + { + gIMMgr->processIMTypingStop(from_id, dialog); + script_msg_api(from_id.asString() + ", 5"); + } + break; + + case IM_MESSAGEBOX: + { + // This is a block, modeless dialog. + args["MESSAGE"] = message; + LLNotificationsUtil::add("SystemMessageTip", args); + } + break; + case IM_GROUP_NOTICE: + case IM_GROUP_NOTICE_REQUESTED: + { + LL_INFOS("Messaging") << "Received IM_GROUP_NOTICE message." << LL_ENDL; + + LLUUID agent_id; + U8 has_inventory; + U8 asset_type = 0; + LLUUID group_id; + std::string item_name; + + if (aux_id.notNull()) + { + // aux_id contains group id, binary bucket contains name and asset type + group_id = aux_id; + has_inventory = binary_bucket_size > 1 ? TRUE : FALSE; + from_group = TRUE; // inaccurate value correction + if (has_inventory) + { + std::string str_bucket = ll_safe_string((char*)binary_bucket, binary_bucket_size); + + typedef boost::tokenizer > tokenizer; + boost::char_separator sep("|", "", boost::keep_empty_tokens); + tokenizer tokens(str_bucket, sep); + tokenizer::iterator iter = tokens.begin(); + + asset_type = (LLAssetType::EType)(atoi((*(iter++)).c_str())); + iter++; // wearable type if applicable, otherwise asset type + item_name = std::string((*(iter++)).c_str()); + // Note There is more elements in 'tokens' ... + + + for (int i = 0; i < 6; i++) + { + LL_WARNS() << *(iter++) << LL_ENDL; + iter++; + } + } + } + else + { + // All info is in binary bucket, read it for more information. + struct notice_bucket_header_t + { + U8 has_inventory; + U8 asset_type; + LLUUID group_id; + }; + struct notice_bucket_full_t + { + struct notice_bucket_header_t header; + U8 item_name[DB_INV_ITEM_NAME_BUF_SIZE]; + }*notice_bin_bucket; + + // Make sure the binary bucket is big enough to hold the header + // and a null terminated item name. + if ((binary_bucket_size < (S32)((sizeof(notice_bucket_header_t) + sizeof(U8)))) + || (binary_bucket[binary_bucket_size - 1] != '\0')) + { + LL_WARNS("Messaging") << "Malformed group notice binary bucket" << LL_ENDL; + break; + } + + notice_bin_bucket = (struct notice_bucket_full_t*) &binary_bucket[0]; + has_inventory = notice_bin_bucket->header.has_inventory; + asset_type = notice_bin_bucket->header.asset_type; + group_id = notice_bin_bucket->header.group_id; + item_name = ll_safe_string((const char*)notice_bin_bucket->item_name); + } + + if (group_id != from_id) + { + agent_id = from_id; + } + else + { + std::string::size_type index = original_name.find(" Resident"); + if (index != std::string::npos) + { + original_name = original_name.substr(0, index); + } + + // The group notice packet does not have an AgentID. Obtain one from the name cache. + // If last name is "Resident" strip it out so the cache name lookup works. + std::string legacy_name = gCacheName->buildLegacyName(original_name); + gCacheName->getUUID(legacy_name, agent_id); + + if (agent_id.isNull()) + { + LL_WARNS("Messaging") << "buildLegacyName returned null while processing " << original_name << LL_ENDL; + } + } + + if (agent_id.notNull() && LLMuteList::getInstance()->isMuted(agent_id)) + { + break; + } + + // If there is inventory, give the user the inventory offer. + LLOfferInfo* info = nullptr; + + if (has_inventory) + { + info = new LLOfferInfo(); + + info->mIM = IM_GROUP_NOTICE; + info->mFromID = from_id; + info->mFromGroup = true; + info->mFromObject = false; + info->mTransactionID = session_id; + info->mType = (LLAssetType::EType) asset_type; + info->mFolderID = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(info->mType)); + info->mFromName = LLTrans::getString("AGroupMemberNamed", LLSD().with("GROUP_ID", group_id).with("FROM_ID", from_id)); + info->mDesc = item_name; + info->mHost = sender; + } + + // Tokenize the string. + // TODO: Support escaped tokens ("||" -> "|") + typedef boost::tokenizer > tokenizer; + boost::char_separator sep("|", "", boost::keep_empty_tokens); + tokenizer tokens(message, sep); + tokenizer::iterator iter = tokens.begin(); + + std::string subj(*iter++); + std::string mes(*iter++); + + // Send the notification down the new path. + // For requested notices, we don't want to send the popups. + if (dialog != IM_GROUP_NOTICE_REQUESTED) + { + LLSD payload; + payload["subject"] = subj; + payload["message"] = mes; + payload["sender_name"] = name; + payload["sender_id"] = agent_id; + payload["group_id"] = group_id; + payload["inventory_name"] = item_name; + payload["received_time"] = LLDate::now(); + if (info && info->asLLSD()) + { + payload["inventory_offer"] = info->asLLSD(); + } + + LLSD args; + args["SUBJECT"] = subj; + args["MESSAGE"] = mes; + LLDate notice_date = LLDate(timestamp).notNull() ? LLDate(timestamp) : LLDate::now(); + LLNotifications::instance().add(LLNotification::Params("GroupNotice").substitutions(args).payload(payload).timestamp(notice_date)); + } + + // Also send down the old path for now. + if (IM_GROUP_NOTICE_REQUESTED == dialog) + { + LLGroupActions::showNotice(subj,mes,group_id,has_inventory,item_name,info); + } + else + { + delete info; + } + } + break; + case IM_GROUP_INVITATION: + { + if (!is_muted) + { + // group is not blocked, but we still need to check agent that sent the invitation + // and we have no agent's id + // Note: server sends username "first.last". + size_t index = original_name.find(" Resident"); + if (index != std::string::npos) + { + original_name = original_name.substr(0, index); + } + std::string legacy_name = gCacheName->buildLegacyName(original_name); + LLUUID agent_id; + gCacheName->getUUID(legacy_name, agent_id); + if (agent_id.isNull()) + { + LL_WARNS("Messaging") << "buildLegacyName returned null while processing " << original_name << LL_ENDL; + } + else + { + is_muted |= (bool) LLMuteList::getInstance()->isMuted(agent_id); + } + } + //if (is_do_not_disturb || is_muted) + if (is_muted) return; + if (is_do_not_disturb) + { + send_do_not_disturb_message(gMessageSystem, from_id); + } + + //if (!is_muted) + { + LL_INFOS("Messaging") << "Received IM_GROUP_INVITATION message." << LL_ENDL; + // Read the binary bucket for more information. + struct invite_bucket_t + { + S32 membership_fee; + LLUUID role_id; + }* invite_bucket; + + // Make sure the binary bucket is the correct size. + if (binary_bucket_size != sizeof(invite_bucket_t)) + { + LL_WARNS("Messaging") << "Malformed group invite binary bucket" << LL_ENDL; + break; + } + + invite_bucket = (struct invite_bucket_t*) &binary_bucket[0]; + S32 membership_fee = ntohl(invite_bucket->membership_fee); + // NaCl - Antispam + if (membership_fee > 0 && gSavedSettings.getBOOL("AntiSpamGroupFeeInvites")) + return; + // NaCl End + + LLSD payload; + payload["transaction_id"] = session_id; + payload["group_id"] = from_group ? from_id : aux_id; + payload["name"] = name; + payload["message"] = message; + payload["fee"] = membership_fee; + payload["use_offline_cap"] = session_id.isNull() && (offline == IM_OFFLINE); + + LLSD args; + args["MESSAGE"] = message; + // we shouldn't pass callback functor since it is registered in LLFunctorRegistration + LLNotificationsUtil::add("JoinGroup", args, payload); + } + } + break; + + case IM_INVENTORY_OFFERED: + case IM_TASK_INVENTORY_OFFERED: + // Someone has offered us some inventory. + { + LLOfferInfo* info = new LLOfferInfo; + if (IM_INVENTORY_OFFERED == dialog) + { + struct offer_agent_bucket_t + { + S8 asset_type; + LLUUID object_id; + }* bucketp; + + if (sizeof(offer_agent_bucket_t) != binary_bucket_size) + { + LL_WARNS("Messaging") << "Malformed inventory offer from agent" << LL_ENDL; + delete info; + break; + } + bucketp = (struct offer_agent_bucket_t*) &binary_bucket[0]; + info->mType = (LLAssetType::EType) bucketp->asset_type; + info->mObjectID = bucketp->object_id; + info->mFromObject = FALSE; + } + else // IM_TASK_INVENTORY_OFFERED + { + if (sizeof(S8) == binary_bucket_size) + { + info->mType = (LLAssetType::EType) binary_bucket[0]; + } + else + { + /*RIDER*/ // The previous version of the protocol returned the wrong binary bucket... we + // still might be able to figure out the type... even though the offer is not retrievable. + + // Should be safe to remove once DRTSIM-451 fully deploys + std::string str_bucket(reinterpret_cast(binary_bucket)); + std::string str_type(str_bucket.substr(0, str_bucket.find('|'))); + + std::stringstream type_convert(str_type); + + S32 type; + type_convert >> type; + + // We could try AT_UNKNOWN which would be more accurate, but that causes an auto decline + info->mType = static_cast(type); + // Don't break in the case of a bad binary bucket. Go ahead and show the + // accept/decline popup even though it will not do anything. + LL_WARNS("Messaging") << "Malformed inventory offer from object, type might be " << info->mType << LL_ENDL; + } + info->mObjectID = LLUUID::null; + info->mFromObject = TRUE; + } + + info->mIM = dialog; + info->mFromID = from_id; + info->mFromGroup = from_group; + info->mFolderID = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(info->mType)); + + info->mTransactionID = session_id.notNull() ? session_id : aux_id; + + info->mFromName = name; + info->mDesc = message; + info->mHost = sender; + //if (((is_do_not_disturb && !is_owned_by_me) || is_muted)) + if (is_muted) + { + // Prefetch the offered item so that it can be discarded by the appropriate observer. (EXT-4331) + if (IM_INVENTORY_OFFERED == dialog) + { + LLInventoryFetchItemsObserver* fetch_item = new LLInventoryFetchItemsObserver(info->mObjectID); + fetch_item->startFetch(); + delete fetch_item; + // Same as closing window + info->forceResponse(IOR_DECLINE); + } + else + { + info->forceResponse(IOR_MUTE); + } + } + /* Singu Note: Handle this inside inventory_offer_handler so if the user wants to autoaccept offers, they can while busy. + // old logic: busy mode must not affect interaction with objects (STORM-565) + // new logic: inventory offers from in-world objects should be auto-declined (CHUI-519) + // Singu Note: We should use old logic + else if (is_do_not_disturb && dialog != IM_TASK_INVENTORY_OFFERED) // busy mode must not affect interaction with objects (STORM-565) + { + // Until throttling is implemented, do not disturb mode should reject inventory instead of silently + // accepting it. SEE SL-39554 + info->forceResponse(IOR_DECLINE); + } + */ + else + { + inventory_offer_handler(info, is_friend, is_owned_by_me); + } + } + break; + + case IM_INVENTORY_ACCEPTED: + { +// args["NAME"] = LLAvatarActions::getSLURL(from_id); +// [RLVa:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a + // Only anonymize the name if the agent is nearby, there isn't an open IM session to them and their profile isn't open + bool fRlvFilterName = (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (RlvUtil::isNearbyAgent(from_id)) && + (!RlvUIEnabler::hasOpenProfile(from_id)) && (!RlvUIEnabler::hasOpenIM(from_id)); + args["NAME"] = (!fRlvFilterName) ? LLAvatarActions::getSLURL(from_id) : RlvStrings::getAnonym(name); +// [/RLVa:KB] + LLNotificationsUtil::add("InventoryAccepted", args); + break; + } + case IM_INVENTORY_DECLINED: + { +// args["NAME"] = LLAvatarActions::getSLURL(from_id); +// [RLVa:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a + // Only anonymize the name if the agent is nearby, there isn't an open IM session to them and their profile isn't open + bool fRlvFilterName = (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (RlvUtil::isNearbyAgent(from_id)) && + (!RlvUIEnabler::hasOpenProfile(from_id)) && (!RlvUIEnabler::hasOpenIM(from_id)); + args["NAME"] = (!fRlvFilterName) ? LLAvatarActions::getSLURL(from_id) : RlvStrings::getAnonym(name); +// [/RLVa:KB] + LLNotificationsUtil::add("InventoryDeclined", args); + break; + } + // TODO: _DEPRECATED suffix as part of vote removal - DEV-24856 + case IM_GROUP_VOTE: + { + LLSD args; + args["NAME"] = name; + args["MESSAGE"] = message; + + LLSD payload; + payload["group_id"] = session_id; + LLNotificationsUtil::add("GroupVote", args, payload); + } + break; + + case IM_GROUP_ELECTION_DEPRECATED: + { + LL_WARNS("Messaging") << "Received IM: IM_GROUP_ELECTION_DEPRECATED" << LL_ENDL; + } + break; + + case IM_FROM_TASK: + { + if (is_do_not_disturb && !is_owned_by_me) + { + return; + } + chat.mText = name + separator_string + message.substr(message_offset); + chat.mFromName = name; + + // Build a link to open the object IM info window. + std::string location = ll_safe_string((char*)binary_bucket, binary_bucket_size-1); + + if (session_id.notNull()) + { + chat.mFromID = session_id; + } + else + { + // This message originated on a region without the updated code for task id and slurl information. + // We just need a unique ID for this object that isn't the owner ID. + // If it is the owner ID it will overwrite the style that contains the link to that owner's profile. + // This isn't ideal - it will make 1 style for all objects owned by the the same person/group. + // This works because the only thing we can really do in this case is show the owner name and link to their profile. + chat.mFromID = from_id ^ gAgent.getSessionID(); + } + + chat.mSourceType = CHAT_SOURCE_OBJECT; + + // To conclude that the source type of message is CHAT_SOURCE_SYSTEM it's not + // enough to check only from name (i.e. fromName = "Second Life"). For example + // source type of messages from objects called "Second Life" should not be CHAT_SOURCE_SYSTEM. + bool chat_from_system = (SYSTEM_FROM == name) && region_id.isNull() && position.isNull(); + if (chat_from_system) + { + // System's UUID is NULL (fixes EXT-4766) + chat.mFromID = LLUUID::null; + chat.mSourceType = CHAT_SOURCE_SYSTEM; + } + else script_msg_api(chat.mFromID.asString() + ", 6"); + + // IDEVO Some messages have embedded resident names + message = clean_name_from_task_im(message, from_group); + + LLSD query_string; + query_string["owner"] = from_id; +// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Added: RLVa-1.2.0f + if (rlv_handler_t::isEnabled()) + { + // NOTE: the chat message itself will be filtered in LLNearbyChatHandler::processChat() + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES) || gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS)) && (!from_group) && (RlvUtil::isNearbyAgent(from_id)) ) + { + query_string["rlv_shownames"] = TRUE; + + RlvUtil::filterNames(name); + chat.mFromName = name; + } + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) + { + std::string::size_type idxPos = location.find('/'); + if ( (std::string::npos != idxPos) && (RlvUtil::isNearbyRegion(location.substr(0, idxPos))) ) + location = RlvStrings::getString(RLV_STRING_HIDDEN_REGION); + } + } +// [/RLVa:KB] + query_string["slurl"] = location; + query_string["name"] = name; + if (from_group) + { + query_string["groupowned"] = "true"; + } + +// chat.mURL = LLSLURL("objectim", session_id, "").getSLURLString(); +// [SL:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Added: RLVa-1.2.2a + chat.mURL = LLSLURL("objectim", session_id, LLURI::mapToQueryString(query_string)).getSLURLString(); +// [/SL:KB] + chat.mText = name + separator_string + message.substr(message_offset); + + // Note: lie to Nearby Chat, pretending that this is NOT an IM, because + // IMs from objects don't open IM sessions. + LLFloaterChat::addChat(chat, FALSE, FALSE); + } + break; + + case IM_SESSION_SEND: // ad-hoc or group IMs + { + if (!is_linden && is_do_not_disturb) return; + + // Only show messages if we have a session open (which + // should happen after you get an "invitation" +// if ( !gIMMgr->hasSession(session_id) ) +// [RLVa:KB] - Checked: 2010-11-30 (RLVa-1.3.0c) | Modified: RLVa-1.3.0c + LLFloaterIMPanel* pIMFloater = gIMMgr->findFloaterBySession(session_id); + if (!pIMFloater) + { + return; + } + + if (from_id != gAgentID && (gRlvHandler.hasBehaviour(RLV_BHVR_RECVIM) || gRlvHandler.hasBehaviour(RLV_BHVR_RECVIMFROM))) + { + switch (pIMFloater->getSessionType()) + { + case LLFloaterIMPanel::GROUP_SESSION: // Group chat + if (!RlvActions::canReceiveIM(session_id)) + return; + break; + case LLFloaterIMPanel::ADHOC_SESSION: // Conference chat + if (!RlvActions::canReceiveIM(from_id)) + message = RlvStrings::getString(RLV_STRING_BLOCKED_RECVIM); + break; + default: + RLV_ASSERT(false); + return; + } + } +// [/RLVa:KB] + + // standard message, not from system + std::string saved; + if (offline == IM_OFFLINE) + { + LLStringUtil::format_map_t args; + args["[LONG_TIMESTAMP]"] = formatted_time(timestamp); + saved = LLTrans::getString("Saved_message", args); + } + buffer = separator_string + saved + message.substr(message_offset); + + LL_DEBUGS("Messaging") << "standard message session_id( " << session_id << " ), from_id( " << from_id << " )" << LL_ENDL; + + gIMMgr->addMessage( + session_id, + from_id, + name, + buffer, + ll_safe_string((char*)binary_bucket), + IM_SESSION_INVITE, + parent_estate_id, + region_id, + position, + true); + + std::string prepend_msg; + if (gAgent.isInGroup(session_id)&& gSavedSettings.getBOOL("OptionShowGroupNameInChatIM")) + { + prepend_msg = '['; + prepend_msg += std::string((char*)binary_bucket); + prepend_msg += "] "; + } + else + { + prepend_msg = std::string("IM: "); + } + chat.mText = prepend_msg + name + separator_string + saved + message.substr(message_offset); + LLFloaterChat::addChat(chat, TRUE, from_id == gAgentID); + + break; + } + case IM_FROM_TASK_AS_ALERT: + if (is_do_not_disturb && !is_owned_by_me) + { + return; + } + { + // Construct a viewer alert for this message. + args["NAME"] = name; + args["MESSAGE"] = message; + LLNotificationsUtil::add("ObjectMessage", args); + } + break; + case IM_BUSY_AUTO_RESPONSE: + if (is_muted) + { + LL_DEBUGS("Messaging") << "Ignoring do-not-disturb response from " << from_id << LL_ENDL; + return; + } + else + { + gIMMgr->addMessage(session_id, from_id, name, separator_string + message.substr(message_offset), name, dialog, parent_estate_id, region_id, position, true); + } + break; + + case IM_LURE_USER: + case IM_TELEPORT_REQUEST: + { + // [RLVa:KB] - Checked: RLVa-1.4.9 + // If we auto-accept the offer/request then this will override DnD status (but we'll still let the other party know later) + bool fRlvAutoAccept = (rlv_handler_t::isEnabled()) && + ( ((IM_LURE_USER == dialog) && (RlvActions::autoAcceptTeleportOffer(from_id))) || + ((IM_TELEPORT_REQUEST == dialog) && (RlvActions::autoAcceptTeleportRequest(from_id))) ); +// [/RLVa:KB] + + bool following = gAgent.getAutoPilotLeaderID() == from_id; + + if (!following && is_muted) + { + return; + } +// else if (!following && is_do_not_disturb) +// [RLVa:KB] - Checked: 2013-11-08 (RLVa-1.4.9) + else if (!following && is_do_not_disturb && !fRlvAutoAccept ) +// [/RLVa:KB] + { + send_do_not_disturb_message(gMessageSystem, from_id); + } + else + { +// if (!following && is_do_not_disturb) +// [RLVa:KB] - Checked: RLVa-1.4.9 + if (!following && (is_do_not_disturb) && (!fRlvAutoAccept) ) +// [/RLVa:KB] + { + send_do_not_disturb_message(gMessageSystem, from_id); + } + + LLVector3 pos, look_at; + U64 region_handle(0); + U8 region_access(SIM_ACCESS_MIN); + std::string region_info = ll_safe_string((char*)binary_bucket, binary_bucket_size); + std::string region_access_str = LLStringUtil::null; + std::string region_access_icn = LLStringUtil::null; + std::string region_access_lc = LLStringUtil::null; + + bool canUserAccessDstRegion = true; + bool doesUserRequireMaturityIncrease = false; + + // Do not parse the (empty) lure bucket for TELEPORT_REQUEST + if (IM_TELEPORT_REQUEST != dialog && parse_lure_bucket(region_info, region_handle, pos, look_at, region_access)) + { + region_access_str = LLViewerRegion::accessToString(region_access); + region_access_icn = LLViewerRegion::getAccessIcon(region_access); + region_access_lc = region_access_str; + LLStringUtil::toLower(region_access_lc); + + if (!gAgent.isGodlike()) + { + switch (region_access) + { + case SIM_ACCESS_MIN: + case SIM_ACCESS_PG: + break; + case SIM_ACCESS_MATURE: + if (gAgent.isTeen()) + { + canUserAccessDstRegion = false; + } + else if (gAgent.prefersPG()) + { + doesUserRequireMaturityIncrease = true; + } + break; + case SIM_ACCESS_ADULT: + if (!gAgent.isAdult()) + { + canUserAccessDstRegion = false; + } + else if (!gAgent.prefersAdult()) + { + doesUserRequireMaturityIncrease = true; + } + break; + default: + llassert(0); + break; + } + } + } + +// [RLVa:KB] - Checked: RLVa-1.4.9 + if (rlv_handler_t::isEnabled()) + { + if ( ((IM_LURE_USER == dialog) && (!RlvActions::canAcceptTpOffer(from_id))) || + ((IM_TELEPORT_REQUEST == dialog) && (!RlvActions::canAcceptTpRequest(from_id))) ) + { + RlvUtil::sendBusyMessage(from_id, RlvStrings::getString(RLV_STRING_BLOCKED_TPLUREREQ_REMOTE)); + if (is_do_not_disturb) + send_do_not_disturb_message(gMessageSystem, from_id); + return; + } + + // Censor message if: 1) restricted from receiving IMs from the sender, or 2) teleport offer/request and @showloc=n restricted + if ( (!RlvActions::canReceiveIM(from_id)) || + ((gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) && (IM_LURE_USER == dialog || IM_TELEPORT_REQUEST == dialog)) ) + { + message = RlvStrings::getString(RLV_STRING_HIDDEN); + } + } +// [/RLVa:KB] + + LLSD args; + // *TODO: Translate -> [FIRST] [LAST] (maybe) + args["NAME"] = LLAvatarActions::getSLURL(from_id); + args["MESSAGE"] = message; + args["MATURITY_STR"] = region_access_str; + args["MATURITY_ICON"] = region_access_icn; + args["REGION_CONTENT_MATURITY"] = region_access_lc; + LLSD payload; + payload["from_id"] = from_id; + payload["lure_id"] = session_id; + payload["godlike"] = FALSE; + payload["region_maturity"] = region_access; + + /* Singu TODO: Figure if we should use these + if (!canUserAccessDstRegion) + { + LLNotification::Params params("TeleportOffered_MaturityBlocked"); + params.substitutions = args; + params.payload = payload; + LLPostponedNotification::add(params, from_id, false); + send_simple_im(from_id, LLTrans::getString("TeleportMaturityExceeded"), IM_NOTHING_SPECIAL, session_id); + send_simple_im(from_id, LLStringUtil::null, IM_LURE_DECLINED, session_id); + } + else if (doesUserRequireMaturityIncrease) + { + LLNotification::Params params("TeleportOffered_MaturityExceeded"); + params.substitutions = args; + params.payload = payload; + LLPostponedNotification::add(params, from_id, false); + } + else + */ + { + /* Singu Note: No default constructor for LLNotification::Params + LLNotification::Params params; + if (IM_LURE_USER == dialog) + { + params.name = "TeleportOffered"; + params.functor_name = "TeleportOffered"; + } + else if (IM_TELEPORT_REQUEST == dialog) + { + params.name = "TeleportRequest"; + params.functor_name = "TeleportRequest"; + } + */ + LLNotification::Params params(IM_LURE_USER == dialog ? "TeleportOffered" : "TeleportRequest"); + params.substitutions = args; + params.payload = payload; + + if (following) + { + LLNotifications::instance().forceResponse(LLNotification::Params(params.name).payload(payload), 0); + } + else +// [RLVa:KB] - Checked: 20103-11-08 (RLVa-1.4.9) + if ( (rlv_handler_t::isEnabled()) && (fRlvAutoAccept) ) + { + if (IM_LURE_USER == dialog) + gRlvHandler.setCanCancelTp(false); + if (is_do_not_disturb) + send_do_not_disturb_message(gMessageSystem, from_id); + LLNotifications::instance().forceResponse(LLNotification::Params(params.name).payload(payload), 0); + } + else + { + LLNotifications::instance().add(params); + + // + if (IM_LURE_USER == dialog) + gAgent.showLureDestination(LLAvatarActions::getSLURL(from_id), region_handle, pos.mV[VX], pos.mV[VY], pos.mV[VZ]); + script_msg_api(from_id.asString().append(IM_LURE_USER == dialog ? ", 2" : ", 3")); + // + } +// [/RLVa:KB] +// LLNotifications::instance().add(params); + } + } + } + break; + + case IM_GODLIKE_LURE_USER: + { + LLVector3 pos, look_at; + U64 region_handle(0); + U8 region_access(SIM_ACCESS_MIN); + std::string region_info = ll_safe_string((char*)binary_bucket, binary_bucket_size); + std::string region_access_str = LLStringUtil::null; + std::string region_access_icn = LLStringUtil::null; + std::string region_access_lc = LLStringUtil::null; + + bool canUserAccessDstRegion = true; + bool doesUserRequireMaturityIncrease = false; + + if (parse_lure_bucket(region_info, region_handle, pos, look_at, region_access)) + { + region_access_str = LLViewerRegion::accessToString(region_access); + region_access_icn = LLViewerRegion::getAccessIcon(region_access); + region_access_lc = region_access_str; + LLStringUtil::toLower(region_access_lc); + + if (!gAgent.isGodlike()) + { + switch (region_access) + { + case SIM_ACCESS_MIN: + case SIM_ACCESS_PG: + break; + case SIM_ACCESS_MATURE: + if (gAgent.isTeen()) + { + canUserAccessDstRegion = false; + } + else if (gAgent.prefersPG()) + { + doesUserRequireMaturityIncrease = true; + } + break; + case SIM_ACCESS_ADULT: + if (!gAgent.isAdult()) + { + canUserAccessDstRegion = false; + } + else if (!gAgent.prefersAdult()) + { + doesUserRequireMaturityIncrease = true; + } + break; + default: + llassert(0); + break; + } + } + } + + LLSD args; + // *TODO: Translate -> [FIRST] [LAST] (maybe) + args["NAME"] = LLAvatarActions::getSLURL(from_id); + args["MESSAGE"] = message; + args["MATURITY_STR"] = region_access_str; + args["MATURITY_ICON"] = region_access_icn; + args["REGION_CONTENT_MATURITY"] = region_access_lc; + LLSD payload; + payload["from_id"] = from_id; + payload["lure_id"] = session_id; + payload["godlike"] = TRUE; + payload["region_maturity"] = region_access; + + /*if (!canUserAccessDstRegion) + { + LLNotification::Params params("TeleportOffered_MaturityBlocked"); + params.substitutions = args; + params.payload = payload; + LLPostponedNotification::add(params, from_id, false); + send_simple_im(from_id, LLTrans::getString("TeleportMaturityExceeded"), IM_NOTHING_SPECIAL, session_id); + send_simple_im(from_id, LLStringUtil::null, IM_LURE_DECLINED, session_id); + } + else if (doesUserRequireMaturityIncrease) + { + LLNotification::Params params("TeleportOffered_MaturityExceeded"); + params.substitutions = args; + params.payload = payload; + LLPostponedNotification::add(params, from_id, false); + } + else*/ + { + // do not show a message box, because you're about to be + // teleported. + LLNotifications::instance().forceResponse(LLNotification::Params("TeleportOffered").payload(payload), 0); + } + } + break; + + case IM_GOTO_URL: + { + LLSD args; + // n.b. this is for URLs sent by the system, not for + // URLs sent by scripts (i.e. llLoadURL) + if (binary_bucket_size <= 0) + { + LL_WARNS("Messaging") << "bad binary_bucket_size: " + << binary_bucket_size + << " - aborting function." << LL_ENDL; + return; + } + + std::string url; + + url.assign((char*)binary_bucket, binary_bucket_size-1); + args["MESSAGE"] = message; + args["URL"] = url; + LLSD payload; + payload["url"] = url; + LLNotificationsUtil::add("GotoURL", args, payload); + } + break; + + case IM_FRIENDSHIP_OFFERED: + { + LLSD payload; + payload["from_id"] = from_id; + payload["session_id"] = session_id; + payload["online"] = (offline == IM_ONLINE); + payload["sender"] = sender.getIPandPort(); + + if (is_muted) + { + LLNotifications::instance().forceResponse(LLNotification::Params("OfferFriendship").payload(payload), 1); + } + else + { + if (is_do_not_disturb) + { + send_do_not_disturb_message(gMessageSystem, from_id); + } + args["[NAME_SLURL]"] = LLAvatarActions::getSLURL(from_id); + if (message.empty()) + { + //support for frienship offers from clients before July 2008 + LLNotificationsUtil::add("OfferFriendshipNoMessage", args, payload); + } + else + { + args["[MESSAGE]"] = message; + LLNotificationsUtil::add("OfferFriendship", args, payload); + } + } + } + break; + + case IM_FRIENDSHIP_ACCEPTED: + { + // In the case of an offline IM, the formFriendship() may be extraneous + // as the database should already include the relationship. But it + // doesn't hurt for dupes. + LLAvatarTracker::formFriendship(from_id); + + std::vector strings; + strings.push_back(from_id.asString()); + send_generic_message("requestonlinenotification", strings); + + args["NAME"] = LLAvatarActions::getSLURL(from_id); + LLSD payload; + payload["from_id"] = from_id; + LLAvatarNameCache::get(from_id, boost::bind(¬ification_display_name_callback, _1, _2, "FriendshipAccepted", args, payload)); + } + break; + + case IM_FRIENDSHIP_DECLINED_DEPRECATED: + default: + LL_WARNS("Messaging") << "Instant message calling for unknown dialog " + << (S32)dialog << LL_ENDL; + break; + } + + LLWindow* viewer_window = gViewerWindow->getWindow(); + if (viewer_window && viewer_window->getMinimized() && gSavedSettings.getBOOL("LiruFlashWhenMinimized")) + { + viewer_window->flashIcon(5.f); + } +} + +void LLIMProcessing::requestOfflineMessages() +{ + static BOOL requested = FALSE; + if (!requested + && gMessageSystem + && LLMuteList::getInstance()->isLoaded() + && isAgentAvatarValid() + && gAgent.getRegion() + && gAgent.getRegion()->capabilitiesReceived()) + { + std::string cap_url = gAgent.getRegionCapability("ReadOfflineMsgs"); + + // Auto-accepted inventory items may require the avatar object + // to build a correct name. Likewise, inventory offers from + // muted avatars require the mute list to properly mute. + if (cap_url.empty() + || gAgent.getRegionCapability("AcceptFriendship").empty() + || gAgent.getRegionCapability("AcceptGroupInvite").empty()) + { + // Offline messages capability provides no session/transaction ids for message AcceptFriendship and IM_GROUP_INVITATION to work + // So make sure we have the caps before using it. + requestOfflineMessagesLegacy(); + } + else + { + LLHTTPClient::get(cap_url, new LLCoroResponder( + LLIMProcessing::requestOfflineMessagesCoro)); + } + requested = TRUE; + } +} + +void LLIMProcessing::requestOfflineMessagesCoro(const LLCoroResponder& responder) +{ + if (LLApp::isQuitting() || !gAgent.getRegion()) + { + return; + } + + auto status = responder.getStatus(); + + if (!responder.isGoodStatus(status)) // success = httpResults["success"].asBoolean(); + { + LL_WARNS("Messaging") << "Error requesting offline messages via capability " << responder.getURL() << ", Status: " << status << ", Reason: " << responder.getReason() << "\nFalling back to legacy method." << LL_ENDL; + + requestOfflineMessagesLegacy(); + return; + } + + const auto& contents = responder.getContent(); + + if (!contents.size()) + { + LL_WARNS("Messaging") << "No contents received for offline messages via capability " << responder.getURL() << LL_ENDL; + return; + } + + // Todo: once dirtsim-369 releases, remove one of the map/array options + LLSD messages; + if (contents.isArray()) + { + messages = *contents.beginArray(); + } + else if (contents.has("messages")) + { + messages = contents["messages"]; + } + else + { + LL_WARNS("Messaging") << "Invalid offline message content received via capability " << responder.getURL() << LL_ENDL; + return; + } + + if (!messages.isArray()) + { + LL_WARNS("Messaging") << "Invalid offline message content received via capability " << responder.getURL() << LL_ENDL; + return; + } + + if (messages.emptyArray()) + { + // Nothing to process + return; + } + + LL_INFOS("Messaging") << "Processing offline messages." << LL_ENDL; + + LLHost sender = gAgent.getRegion()->getHost(); + + LLSD::array_iterator i = messages.beginArray(); + LLSD::array_iterator iEnd = messages.endArray(); + for (; i != iEnd; ++i) + { + const LLSD &message_data(*i); + + /* RIDER: Many fields in this message are using a '_' rather than the standard '-'. This + * should be changed but would require tight coordination with the simulator. + */ + LLVector3 position; + if (message_data.has("position")) + { + position.setValue(message_data["position"]); + } + else + { + position.set(message_data["local_x"].asReal(), message_data["local_y"].asReal(), message_data["local_z"].asReal()); + } + + std::vector bin_bucket; + if (message_data.has("binary_bucket")) + { + bin_bucket = message_data["binary_bucket"].asBinary(); + } +#if 0 + else + { + bin_bucket.push_back(0); + } +#endif + // Todo: once drtsim-451 releases, remove the string option + BOOL from_group; + if (message_data["from_group"].isInteger()) + { + from_group = message_data["from_group"].asInteger(); + } + else + { + from_group = message_data["from_group"].asString() == "Y"; + } + + auto agentName = message_data["from_agent_name"].asString(); + auto message = message_data["message"].asString(); + LLIMProcessing::processNewMessage( + message_data["from_agent_id"].asUUID(), + from_group, + message_data["to_agent_id"].asUUID(), + message_data.has("offline") ? static_cast(message_data["offline"].asInteger()) : IM_OFFLINE, + static_cast(message_data["dialog"].asInteger()), + message_data["transaction-id"].asUUID(), + static_cast(message_data["timestamp"].asInteger()), + agentName, + message, + message_data.has("parent_estate_id") ? static_cast(message_data["parent_estate_id"].asInteger()) : 1U, // 1 - IMMainland + message_data["region_id"].asUUID(), + position, + bin_bucket.data(), + bin_bucket.size(), + sender, + message_data["asset_id"].asUUID()); // not necessarily an asset + } +} + +void LLIMProcessing::requestOfflineMessagesLegacy() +{ + LL_INFOS("Messaging") << "Requesting offline messages (Legacy)." << LL_ENDL; + + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_RetrieveInstantMessages); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + gAgent.sendReliableMessage(); +} + diff --git a/indra/newview/llimprocessing.h b/indra/newview/llimprocessing.h new file mode 100644 index 0000000000..c8cc47f494 --- /dev/null +++ b/indra/newview/llimprocessing.h @@ -0,0 +1,68 @@ +/** +* @file LLIMMgr.h +* @brief Container for Instant Messaging +* +* $LicenseInfo:firstyear=2001&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2010, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#ifndef LL_LLIMPROCESSING_H +#define LL_LLIMPROCESSING_H + +#include "llinstantmessage.h" + +struct LLCoroResponder; + +std::string replace_wildcards(std::string input, const LLUUID& id, const std::string& name); +bool handle_obj_auth(const LLUUID& from_id, const std::string& mesg); + +class LLIMProcessing +{ +public: + // Pre-process message for IM manager + static void processNewMessage(const LLUUID& from_id, + BOOL from_group, + const LLUUID& to_id, + U8 offline, + EInstantMessage dialog, // U8 + const LLUUID& session_id, + U32 timestamp, + std::string& agentName, + std::string& message, + U32 parent_estate_id, + const LLUUID& region_id, + LLVector3 position, + U8 *binary_bucket, + S32 binary_bucket_size, + LLHost &sender, + const LLUUID& aux_id = LLUUID::null); + + // Either receives list of offline messages from 'ReadOfflineMsgs' capability + // or uses legacy method + static void requestOfflineMessages(); + +private: + static void requestOfflineMessagesCoro(const LLCoroResponder& responder); + static void requestOfflineMessagesLegacy(); +}; + + +#endif // LL_LLLLIMPROCESSING_H diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index c04cd8348b..351cdaadfe 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -34,39 +34,33 @@ #include "llimview.h" -#include "llfontgl.h" -#include "llrect.h" -#include "llbutton.h" #include "llhttpclient.h" +#include "llhttpnode.h" +#include "llnotifications.h" +#include "llnotificationsutil.h" +#include "llsdserialize.h" #include "llsdutil_math.h" -#include "llstring.h" #include "lltrans.h" #include "lluictrlfactory.h" #include "llagent.h" #include "llagentcamera.h" +#include "llagentui.h" #include "llavataractions.h" -#include "llcallingcard.h" -#include "llchat.h" -#include "llresmgr.h" +#include "llavatarnamecache.h" #include "llfloaterchat.h" #include "llfloaterchatterbox.h" -#include "llhttpnode.h" +#include "llgroupactions.h" #include "llimpanel.h" -#include "llnotificationsutil.h" -#include "llsdserialize.h" -#include "llspeakers.h" -#include "lltabcontainer.h" #include "llmutelist.h" -#include "llviewermenu.h" -#include "llviewermessage.h" -#include "llviewerwindow.h" +#include "llspeakers.h" #include "llvoavatar.h" // For mIdleTimer reset -#include "llnotify.h" +#include "llviewerobjectlist.h" #include "llviewerregion.h" -// [RLVa:KB] -#include "rlvhandler.h" +// [RLVa:KB] - Checked: 2013-05-10 (RLVa-1.4.9) +#include "rlvactions.h" +#include "rlvcommon.h" // [/RLVa:KB] class AIHTTPTimeoutPolicy; @@ -80,6 +74,7 @@ LLIMMgr* gIMMgr = NULL; // // Helper Functions // +std::string formatted_time(const time_t& the_time); LLVOAvatar* find_avatar_from_object(const LLUUID& id); LLColor4 agent_chat_color(const LLUUID& id, const std::string& name, bool local_chat) @@ -91,11 +86,11 @@ LLColor4 agent_chat_color(const LLUUID& id, const std::string& name, bool local_ return gSavedSettings.getColor4("UserChatColor"); static const LLCachedControl color_linden_chat("ColorLindenChat"); - if (color_linden_chat && LLMuteList::getInstance()->isLinden(name)) + if (color_linden_chat && LLMuteList::getInstance()->isLinden(id)) return gSavedSettings.getColor4("AscentLindenColor"); // [RLVa:LF] Chat colors would identify names, don't use them in local chat if restricted - if (local_chat && rlv_handler_t::isEnabled() && gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) + if (local_chat && RlvActions::hasBehaviour(RLV_BHVR_SHOWNAMES)) return gSavedSettings.getColor4("AgentChatColor"); static const LLCachedControl color_friend_chat("ColorFriendChat"); @@ -105,19 +100,22 @@ LLColor4 agent_chat_color(const LLUUID& id, const std::string& name, bool local_ static const LLCachedControl color_eo_chat("ColorEstateOwnerChat"); if (color_eo_chat) { - const LLViewerRegion* parent_estate = gAgent.getRegion(); - if (parent_estate && id == parent_estate->getOwner()) - return gSavedSettings.getColor4("AscentEstateOwnerColor"); + const LLViewerObject* obj = gObjectList.findObject(id); // Nearby? + if (const LLViewerRegion* parent_estate = obj ? obj->getRegion() : gAgent.getRegion()) + if (id == parent_estate->getOwner()) + return gSavedSettings.getColor4("AscentEstateOwnerColor"); } return local_chat ? gSavedSettings.getColor4("AgentChatColor") : gSavedSettings.getColor("IMChatColor"); } -// returns true if a should appear before b -//static BOOL group_dictionary_sort( LLGroupData* a, LLGroupData* b ) -//{ -// return (LLStringUtil::compareDict( a->mName, b->mName ) < 0); -//} +bool block_conference(const LLUUID& id) +{ + const U32 block(gSavedSettings.getU32("LiruBlockConferences")); + if (block == 2) return !LLAvatarActions::isFriend(id); + return block; +} + class LLViewerChatterBoxInvitationAcceptResponder : public LLHTTPClient::ResponderWithResult { @@ -130,7 +128,7 @@ class LLViewerChatterBoxInvitationAcceptResponder : public LLHTTPClient::Respond mInvitiationType = invitation_type; } - /*virtual*/ void result(const LLSD& content) + /*virtual*/ void httpSuccess(void) { if ( gIMMgr) { @@ -150,7 +148,7 @@ class LLViewerChatterBoxInvitationAcceptResponder : public LLHTTPClient::Respond //but unfortunately, our base that we are receiving here //may not be the most up to date. It was accurate at //some point in time though. - speaker_mgr->setSpeakers(content); + speaker_mgr->setSpeakers(mContent); //we now have our base of users in the session //that was accurate at some point, but maybe not now @@ -166,10 +164,13 @@ class LLViewerChatterBoxInvitationAcceptResponder : public LLHTTPClient::Respond if ((mInvitiationType == LLIMMgr::INVITATION_TYPE_VOICE || mInvitiationType == LLIMMgr::INVITATION_TYPE_IMMEDIATE) - && gIMMgr->hasSession(mSessionID)) + && floater) { // always open IM window when connecting to voice - LLFloaterChatterBox::showInstance(TRUE); + if (floater->getParent() == gFloaterView) + floater->open(); + else + LLFloaterChatterBox::showInstance(TRUE); } gIMMgr->clearPendingAgentListUpdates(mSessionID); @@ -177,10 +178,10 @@ class LLViewerChatterBoxInvitationAcceptResponder : public LLHTTPClient::Respond } } - /*virtual*/ void error(U32 statusNum, const std::string& reason) + /*virtual*/ void httpFailure(void) { - llwarns << "LLViewerChatterBoxInvitationAcceptResponder error [status:" - << statusNum << "]: " << reason << llendl; + LL_WARNS() << "LLViewerChatterBoxInvitationAcceptResponder error [status:" + << mStatus << "]: " << mReason << LL_ENDL; //throw something back to the viewer here? if ( gIMMgr ) { @@ -191,7 +192,7 @@ class LLViewerChatterBoxInvitationAcceptResponder : public LLHTTPClient::Respond if ( floaterp ) { - if ( 404 == statusNum ) + if ( 404 == mStatus ) { std::string error_string; error_string = "session_does_not_exist_error"; @@ -252,42 +253,6 @@ LLUUID LLIMMgr::computeSessionID( return session_id; } -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// LLFloaterIM -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -LLFloaterIM::LLFloaterIM() -{ - // autoresize=false is necessary to avoid resizing of the IM window whenever - // a session is opened or closed (it would otherwise resize the window to match - // the size of the im-sesssion when they were created. This happens in - // LLMultiFloater::resizeToContents() when called through LLMultiFloater::addFloater()) - this->mAutoResize = FALSE; - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_im.xml"); -} - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLIMViewFriendObserver -// -// Bridge to suport knowing when the inventory has changed. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -class LLIMViewFriendObserver : public LLFriendObserver -{ -public: - LLIMViewFriendObserver(LLIMMgr* tv) : mTV(tv) {} - virtual ~LLIMViewFriendObserver() {} - virtual void changed(U32 mask) - { - if(mask & (LLFriendObserver::ADD | LLFriendObserver::REMOVE | LLFriendObserver::ONLINE)) - { - mTV->refresh(); - } - } -protected: - LLIMMgr* mTV; -}; - bool inviteUserResponse(const LLSD& notification, const LLSD& response) { @@ -387,22 +352,6 @@ bool inviteUserResponse(const LLSD& notification, const LLSD& response) // Public Static Member Functions // -// This is a helper function to determine what kind of im session -// should be used for the given agent. -// static -EInstantMessage LLIMMgr::defaultIMTypeForAgent(const LLUUID& agent_id) -{ - EInstantMessage type = IM_NOTHING_SPECIAL; - if (LLAvatarActions::isFriend(agent_id)) - { - if(LLAvatarTracker::instance().isBuddyOnline(agent_id)) - { - type = IM_SESSION_CONFERENCE_START; - } - } - return type; -} - // static //void LLIMMgr::onPinButton(void*) //{ @@ -410,14 +359,12 @@ EInstantMessage LLIMMgr::defaultIMTypeForAgent(const LLUUID& agent_id) // gSavedSettings.setBOOL( "PinTalkViewOpen", !state ); //} -// static -void LLIMMgr::toggle(void*) +void LLIMMgr::toggle() { static BOOL return_to_mouselook = FALSE; // Hide the button and show the floater or vice versa. - llassert( gIMMgr ); - BOOL old_state = gIMMgr->getFloaterOpen(); + bool old_state = getFloaterOpen(); // If we're in mouselook and we triggered the Talk View, we want to talk. if( gAgentCamera.cameraMouselook() && old_state ) @@ -448,7 +395,7 @@ void LLIMMgr::toggle(void*) return_to_mouselook = FALSE; } - gIMMgr->setFloaterOpen( new_state ); + setFloaterOpen(new_state); } // @@ -456,26 +403,14 @@ void LLIMMgr::toggle(void*) // LLIMMgr::LLIMMgr() : - mFriendObserver(NULL), - mIMReceived(FALSE), mIMUnreadCount(0) { - mFriendObserver = new LLIMViewFriendObserver(this); - LLAvatarTracker::instance().addObserver(mFriendObserver); - - // *HACK: use floater to initialize string constants from xml file - // then delete it right away - LLFloaterIM* dummy_floater = new LLFloaterIM(); - delete dummy_floater; - mPendingInvitations = LLSD::emptyMap(); mPendingAgentListUpdates = LLSD::emptyMap(); } LLIMMgr::~LLIMMgr() { - LLAvatarTracker::instance().removeObserver(mFriendObserver); - delete mFriendObserver; // Children all cleaned up by default view destructor. } @@ -502,21 +437,20 @@ void LLIMMgr::addMessage( return; } - LLFloaterIMPanel* floater; LLUUID new_session_id = session_id; if (new_session_id.isNull()) { //no session ID...compute new one new_session_id = computeSessionID(dialog, other_participant_id); } - floater = findFloaterBySession(new_session_id); + LLFloaterIMPanel* floater = findFloaterBySession(new_session_id); if (!floater) { floater = findFloaterBySession(other_participant_id); if (floater) { - llinfos << "found the IM session " << session_id - << " by participant " << other_participant_id << llendl; + LL_INFOS() << "found the IM session " << new_session_id + << " by participant " << other_participant_id << LL_ENDL; } } @@ -525,43 +459,13 @@ void LLIMMgr::addMessage( // create IM window as necessary if(!floater) { - if (gIMMgr->getIgnoreGroupListCount() > 0 && gAgent.isInGroup(session_id)) - { - // Check to see if we're blocking this group's chat - LLGroupData* group_data = NULL; - - // Search for this group in the agent's groups list - LLDynamicArray::iterator i; - - for (i = gAgent.mGroups.begin(); i != gAgent.mGroups.end(); i++) - { - if (i->mID == session_id) - { - group_data = &*i; - break; - } - } - - // If the group is in our list then return - if (group_data && gIMMgr->getIgnoreGroup(group_data->mID)) - { - return; - } - } + // Return now if we're blocking this group's chat or conferences + if (gAgent.isInGroup(session_id) ? getIgnoreGroup(session_id) : dialog != IM_NOTHING_SPECIAL && dialog != IM_SESSION_P2P_INVITE && block_conference(other_participant_id)) + return; - std::string name = from; - if(!session_name.empty() && session_name.size()>1) - { - name = session_name; - } + std::string name = (session_name.size() > 1) ? session_name : from; - - floater = createFloater( - new_session_id, - other_participant_id, - name, - dialog, - FALSE); + floater = createFloater(new_session_id, other_participant_id, name, dialog); // When we get a new IM, and if you are a god, display a bit // of information about the source. This is to help liaisons @@ -587,7 +491,13 @@ void LLIMMgr::addMessage( } // now add message to floater - const LLColor4& color = agent_chat_color(other_participant_id, from, false); + LLColor4 color = agent_chat_color(other_participant_id, from, false); + if (dialog == IM_BUSY_AUTO_RESPONSE) + { + color *= .75f; + color += LLColor4::transparent*.25f; + } + if ( !link_name ) { floater->addHistoryLine(msg,color); // No name to prepend, so just add the message normally @@ -606,26 +516,9 @@ void LLIMMgr::addMessage( } } - LLFloaterChatterBox* chat_floater = LLFloaterChatterBox::getInstance(LLSD()); - - if( !chat_floater->getVisible() && !floater->getVisible()) + if (!gIMMgr->getFloaterOpen() && floater->getParent() != gFloaterView) { - //if the IM window is not open and the floater is not visible (i.e. not torn off) - LLFloater* previouslyActiveFloater = chat_floater->getActiveFloater(); - - // select the newly added floater (or the floater with the new line added to it). - // it should be there. - chat_floater->selectFloater(floater); - - //there was a previously unseen IM, make that old tab flashing - //it is assumed that the most recently unseen IM tab is the one current selected/active - if ( previouslyActiveFloater && getIMReceived() ) - { - chat_floater->setFloaterFlashing(previouslyActiveFloater, TRUE); - } - - //notify of a new IM - notifyNewIM(); + // If the chat floater is closed and not torn off) notify of a new IM mIMUnreadCount++; } } @@ -656,25 +549,11 @@ void LLIMMgr::addSystemMessage(const LLUUID& session_id, const std::string& mess } } -void LLIMMgr::notifyNewIM() -{ - if(!gIMMgr->getFloaterOpen()) - { - mIMReceived = TRUE; - } -} - void LLIMMgr::clearNewIMNotification() { - mIMReceived = FALSE; mIMUnreadCount = 0; } -BOOL LLIMMgr::getIMReceived() const -{ - return mIMReceived; -} - int LLIMMgr::getIMUnreadCount() { return mIMUnreadCount; @@ -738,16 +617,10 @@ LLUUID LLIMMgr::addSession( LLFloaterIMPanel* floater = findFloaterBySession(session_id); if(!floater) { - LLDynamicArray ids; - ids.put(other_participant_id); + uuid_vec_t ids; + ids.push_back(other_participant_id); - floater = createFloater( - session_id, - other_participant_id, - name, - ids, - dialog, - TRUE); + floater = createFloater(session_id, other_participant_id, name, dialog, ids, true); noteOfflineUsers(floater, ids); LLFloaterChatterBox::showInstance(session_id); @@ -788,9 +661,9 @@ LLUUID LLIMMgr::addSession( const std::string& name, EInstantMessage dialog, const LLUUID& other_participant_id, - const LLDynamicArray& ids) + const uuid_vec_t& ids) { - if (0 == ids.getLength()) + if (0 == ids.size()) { return LLUUID::null; } @@ -804,13 +677,7 @@ LLUUID LLIMMgr::addSession( { // On creation, use the first element of ids as the // "other_participant_id" - floater = createFloater( - session_id, - other_participant_id, - name, - ids, - dialog, - TRUE); + floater = createFloater(session_id, other_participant_id, name, dialog, ids, true); if ( !floater ) return LLUUID::null; @@ -926,47 +793,19 @@ void LLIMMgr::inviteToSession( if ( !mPendingInvitations.has(session_id.asString()) ) { - if (caller_name.empty()) - { - gCacheName->get(caller_id, true, // voice - boost::bind(&LLIMMgr::onInviteNameLookup, _1, _2, _3, payload)); - } - else - { - LLSD args; - args["NAME"] = caller_name; - args["GROUP"] = session_name; + LLSD args; + args["NAME"] = LLAvatarActions::getSLURL(caller_id); + args["GROUP"] = LLGroupActions::getSLURL(session_id); - LLNotifications::instance().add(notify_box_type, - args, - payload, - &inviteUserResponse); + LLNotifications::instance().add(notify_box_type, + args, + payload, + &inviteUserResponse); - } mPendingInvitations[session_id.asString()] = LLSD(); } } -//static -void LLIMMgr::onInviteNameLookup(const LLUUID& id, const std::string& full_name, bool is_group, LLSD payload) -{ - payload["caller_name"] = full_name; - payload["session_name"] = full_name; - - LLSD args; - args["NAME"] = full_name; - - LLNotifications::instance().add( - payload["notify_box_type"].asString(), - args, - payload, - &inviteUserResponse); -} - -void LLIMMgr::refresh() -{ -} - void LLIMMgr::setFloaterOpen(BOOL set_open) { if (set_open) @@ -1188,20 +1027,18 @@ LLFloaterIMPanel* LLIMMgr::createFloater( const LLUUID& session_id, const LLUUID& other_participant_id, const std::string& session_label, - EInstantMessage dialog, - BOOL user_initiated) + const EInstantMessage& dialog, + const uuid_vec_t& ids, + bool user_initiated) { if (session_id.isNull()) { - llwarns << "Creating LLFloaterIMPanel with null session ID" << llendl; + LL_WARNS() << "Creating LLFloaterIMPanel with null session ID" << LL_ENDL; } - llinfos << "LLIMMgr::createFloater: from " << other_participant_id - << " in session " << session_id << llendl; - LLFloaterIMPanel* floater = new LLFloaterIMPanel(session_label, - session_id, - other_participant_id, - dialog); + LL_INFOS() << "LLIMMgr::createFloater: from " << other_participant_id + << " in session " << session_id << LL_ENDL; + LLFloaterIMPanel* floater = new LLFloaterIMPanel(session_label, session_id, other_participant_id, dialog, ids); LLTabContainer::eInsertionPoint i_pt = user_initiated ? LLTabContainer::RIGHT_OF_CURRENT : LLTabContainer::END; LLFloaterChatterBox::getInstance(LLSD())->addFloater(floater, FALSE, i_pt); static LLCachedControl tear_off("OtherChatsTornOff"); @@ -1227,83 +1064,56 @@ LLFloaterIMPanel* LLIMMgr::createFloater( return floater; } -LLFloaterIMPanel* LLIMMgr::createFloater( - const LLUUID& session_id, - const LLUUID& other_participant_id, - const std::string& session_label, - const LLDynamicArray& ids, - EInstantMessage dialog, - BOOL user_initiated) +void LLIMMgr::addNotifiedNonFriendSessionID(const LLUUID& session_id) { - if (session_id.isNull()) - { - llwarns << "Creating LLFloaterIMPanel with null session ID" << llendl; - } + mNotifiedNonFriendSessions.insert(session_id); +} - llinfos << "LLIMMgr::createFloater: from " << other_participant_id - << " in session " << session_id << llendl; - LLFloaterIMPanel* floater = new LLFloaterIMPanel(session_label, - session_id, - other_participant_id, - ids, - dialog); - LLTabContainer::eInsertionPoint i_pt = user_initiated ? LLTabContainer::RIGHT_OF_CURRENT : LLTabContainer::END; - LLFloaterChatterBox::getInstance(LLSD())->addFloater(floater, FALSE, i_pt); - static LLCachedControl tear_off("OtherChatsTornOff"); - if (tear_off) +bool LLIMMgr::isNonFriendSessionNotified(const LLUUID& session_id) +{ + return mNotifiedNonFriendSessions.end() != mNotifiedNonFriendSessions.find(session_id); +} + +std::string LLIMMgr::getOfflineMessage(const LLUUID& id) +{ + std::string full_name; + if (LLAvatarNameCache::getNSName(id, full_name)) { - LLFloaterChatterBox::getInstance(LLSD())->removeFloater(floater); // removal sets up relationship for re-attach - gFloaterView->addChild(floater); // reparent to floater view - LLFloater* focused_floater = gFloaterView->getFocusedFloater(); // obtain the focused floater - floater->open(); // make the new chat floater appear - static LLCachedControl minimize("OtherChatsTornOffAndMinimized"); - if (focused_floater != NULL) // there was a focused floater - { - floater->setMinimized(minimize); // so minimize this one, for now, if desired - focused_floater->setFocus(true); // and work around focus being removed by focusing on the last - } - else if (minimize) - { - floater->setFocus(false); // work around focus being granted to new floater - floater->setMinimized(true); - } + LLUIString offline = LLTrans::getString("offline_message"); + offline.setArg("[NAME]", full_name); + return offline; } - mFloaters.insert(floater->getHandle()); - return floater; + return LLStringUtil::null; } void LLIMMgr::noteOfflineUsers( LLFloaterIMPanel* floater, - const LLDynamicArray& ids) + const uuid_vec_t& ids) { - S32 count = ids.count(); - if(count == 0) + if(ids.empty()) { const std::string& only_user = LLTrans::getString("only_user_message"); floater->addHistoryLine(only_user, gSavedSettings.getColor4("SystemChatColor")); } else { - const LLRelationship* info = NULL; + const LLRelationship* info = nullptr; LLAvatarTracker& at = LLAvatarTracker::instance(); - for(S32 i = 0; i < count; ++i) + for(const auto& id : ids) { - info = at.getBuddyInfo(ids.get(i)); - std::string full_name; - if (info - && !info->isOnline() - && LLAvatarNameCache::getPNSName(ids.get(i), full_name)) + info = at.getBuddyInfo(id); + if (info && !info->isOnline()) { - LLUIString offline = LLTrans::getString("offline_message"); - offline.setArg("[NAME]", full_name); - floater->addHistoryLine(offline, gSavedSettings.getColor4("SystemChatColor")); + auto offline(getOfflineMessage(id)); + if (!offline.empty()) + floater->addHistoryLine(offline, gSavedSettings.getColor4("SystemChatColor")); } } } } void LLIMMgr::noteMutedUsers(LLFloaterIMPanel* floater, - const LLDynamicArray& ids) + const uuid_vec_t& ids) { // Don't do this if we don't have a mute list. LLMuteList *ml = LLMuteList::getInstance(); @@ -1312,12 +1122,12 @@ void LLIMMgr::noteMutedUsers(LLFloaterIMPanel* floater, return; } - S32 count = ids.count(); + S32 count = ids.size(); if(count > 0) { for(S32 i = 0; i < count; ++i) { - if( ml->isMuted(ids.get(i)) ) + if( ml->isMuted(ids.at(i)) ) { LLUIString muted = LLTrans::getString("muted_message"); @@ -1328,23 +1138,23 @@ void LLIMMgr::noteMutedUsers(LLFloaterIMPanel* floater, } } -void LLIMMgr::processIMTypingStart(const LLIMInfo* im_info) +void LLIMMgr::processIMTypingStart(const LLUUID& from_id, const EInstantMessage im_type) { - processIMTypingCore(im_info, TRUE); + processIMTypingCore(from_id, im_type, TRUE); } -void LLIMMgr::processIMTypingStop(const LLIMInfo* im_info) +void LLIMMgr::processIMTypingStop(const LLUUID& from_id, const EInstantMessage im_type) { - processIMTypingCore(im_info, FALSE); + processIMTypingCore(from_id, im_type, FALSE); } -void LLIMMgr::processIMTypingCore(const LLIMInfo* im_info, BOOL typing) +void LLIMMgr::processIMTypingCore(const LLUUID& from_id, const EInstantMessage im_type, BOOL typing) { - LLUUID session_id = computeSessionID(im_info->mIMType, im_info->mFromID); - LLFloaterIMPanel* floater = findFloaterBySession(session_id); - if (floater) + LLUUID session_id = computeSessionID(im_type, from_id); + LLFloaterIMPanel* im_floater = findFloaterBySession(session_id); + if (im_floater) { - floater->processIMTyping(im_info, typing); + im_floater->processIMTyping(from_id, typing); } } @@ -1368,7 +1178,7 @@ void LLIMMgr::loadIgnoreGroup() file.open(filename); if (file.is_open()) { - // llinfos << "loading group chat ignore from " << filename << "..." << llendl; + // LL_INFOS() << "loading group chat ignore from " << filename << "..." << LL_ENDL; LLSDSerialize::fromXML(settings_llsd, file); mIgnoreGroupList.clear(); @@ -1376,21 +1186,21 @@ void LLIMMgr::loadIgnoreGroup() for(LLSD::array_const_iterator iter = settings_llsd.beginArray(); iter != settings_llsd.endArray(); ++iter) { - // llinfos << "added " << iter->asUUID() - // << " to group chat ignore list" << llendl; + // LL_INFOS() << "added " << iter->asUUID() + // << " to group chat ignore list" << LL_ENDL; mIgnoreGroupList.push_back( iter->asUUID() ); } } else { - // llinfos << "can't load " << filename - // << " (probably it doesn't exist yet)" << llendl; + // LL_INFOS() << "can't load " << filename + // << " (probably it doesn't exist yet)" << LL_ENDL; } } void LLIMMgr::saveIgnoreGroup() { - // llinfos << "saving ignore_groups.xml" << llendl; + // LL_INFOS() << "saving ignore_groups.xml" << LL_ENDL; std::string user_dir = gDirUtilp->getLindenUserDir(true); if (!user_dir.empty()) @@ -1418,20 +1228,20 @@ void LLIMMgr::updateIgnoreGroup(const LLUUID& group_id, bool ignore) if (getIgnoreGroup(group_id) == ignore) { // nothing to do - // llinfos << "no change to group " << group_id << ", it is already " - // << (ignore ? "" : "not ") << "ignored" << llendl; + // LL_INFOS() << "no change to group " << group_id << ", it is already " + // << (ignore ? "" : "not ") << "ignored" << LL_ENDL; return; } else if (!ignore) { // change from ignored to not ignored - // llinfos << "unignoring group " << group_id << llendl; + // LL_INFOS() << "unignoring group " << group_id << LL_ENDL; mIgnoreGroupList.remove(group_id); } else //if (ignore) { // change from not ignored to ignored - // llinfos << "ignoring group " << group_id << llendl; + // LL_INFOS() << "ignoring group " << group_id << LL_ENDL; mIgnoreGroupList.push_back(group_id); } } @@ -1446,11 +1256,11 @@ bool LLIMMgr::getIgnoreGroup(const LLUUID& group_id) const if (found != mIgnoreGroupList.end()) { - // llinfos << "group " << group_id << " is ignored." << llendl; + // LL_INFOS() << "group " << group_id << " is ignored." << LL_ENDL; return true; } } - // llinfos << "group " << group_id << " is not ignored." << llendl; + // LL_INFOS() << "group " << group_id << " is not ignored." << LL_ENDL; return false; } @@ -1465,10 +1275,10 @@ LLFloaterChatterBox* LLIMMgr::getFloater() return LLFloaterChatterBox::getInstance(LLSD()); } -class LLViewerChatterBoxSessionStartReply : public LLHTTPNode +class LLViewerChatterBoxSessionStartReply final : public LLHTTPNode { public: - virtual void describe(Description& desc) const + void describe(Description& desc) const override { desc.shortInfo("Used for receiving a reply to a request to initialize an ChatterBox session"); desc.postAPI(); @@ -1477,18 +1287,15 @@ class LLViewerChatterBoxSessionStartReply : public LLHTTPNode desc.source(__FILE__, __LINE__); } - virtual void post(ResponsePtr response, + void post(ResponsePtr response, const LLSD& context, - const LLSD& input) const + const LLSD& input) const override { - LLSD body; - LLUUID temp_session_id; LLUUID session_id; - bool success; - body = input["body"]; - success = body["success"].asBoolean(); - temp_session_id = body["temp_session_id"].asUUID(); + LLSD body = input["body"]; + bool success = body["success"].asBoolean(); + LLUUID temp_session_id = body["temp_session_id"].asUUID(); if ( success ) { @@ -1526,10 +1333,10 @@ class LLViewerChatterBoxSessionStartReply : public LLHTTPNode } }; -class LLViewerChatterBoxSessionEventReply : public LLHTTPNode +class LLViewerChatterBoxSessionEventReply final : public LLHTTPNode { public: - virtual void describe(Description& desc) const + void describe(Description& desc) const override { desc.shortInfo("Used for receiving a reply to a ChatterBox session event"); desc.postAPI(); @@ -1538,24 +1345,18 @@ class LLViewerChatterBoxSessionEventReply : public LLHTTPNode desc.source(__FILE__, __LINE__); } - virtual void post(ResponsePtr response, + void post(ResponsePtr response, const LLSD& context, - const LLSD& input) const + const LLSD& input) const override { - LLUUID session_id; - bool success; - LLSD body = input["body"]; - success = body["success"].asBoolean(); - session_id = body["session_id"].asUUID(); + bool success = body["success"].asBoolean(); + LLUUID session_id = body["session_id"].asUUID(); if ( !success ) { //throw an error dialog - LLFloaterIMPanel* floater = - gIMMgr->findFloaterBySession(session_id); - - if (floater) + if (auto* floater = gIMMgr->findFloaterBySession(session_id)) { floater->showSessionEventError( body["event"].asString(), @@ -1568,46 +1369,40 @@ class LLViewerChatterBoxSessionEventReply : public LLHTTPNode class LLViewerForceCloseChatterBoxSession: public LLHTTPNode { public: - virtual void post(ResponsePtr response, + void post(ResponsePtr response, const LLSD& context, - const LLSD& input) const + const LLSD& input) const override { - LLUUID session_id; - std::string reason; - - session_id = input["body"]["session_id"].asUUID(); - reason = input["body"]["reason"].asString(); - - LLFloaterIMPanel* floater = - gIMMgr ->findFloaterBySession(session_id); + LLUUID session_id = input["body"]["session_id"].asUUID(); + std::string reason = input["body"]["reason"].asString(); - if ( floater ) + if (auto* floater = gIMMgr ->findFloaterBySession(session_id)) { floater->showSessionForceClose(reason); } } }; -class LLViewerChatterBoxSessionAgentListUpdates : public LLHTTPNode +class LLViewerChatterBoxSessionAgentListUpdates final : public LLHTTPNode { public: - virtual void post( + void post( ResponsePtr responder, const LLSD& context, - const LLSD& input) const + const LLSD& input) const override { const LLUUID& session_id = input["body"]["session_id"].asUUID(); gIMMgr->processAgentListUpdates(session_id, input["body"]); } }; -class LLViewerChatterBoxSessionUpdate : public LLHTTPNode +class LLViewerChatterBoxSessionUpdate final : public LLHTTPNode { public: - virtual void post( + void post( ResponsePtr responder, const LLSD& context, - const LLSD& input) const + const LLSD& input) const override { LLUUID session_id = input["body"]["session_id"].asUUID(); LLFloaterIMPanel* im_floater = gIMMgr->findFloaterBySession(session_id); @@ -1624,14 +1419,25 @@ class LLViewerChatterBoxSessionUpdate : public LLHTTPNode }; -class LLViewerChatterBoxInvitation : public LLHTTPNode +void leave_group_chat(const LLUUID& from_id, const LLUUID& session_id) +{ + // Tell the server we've left group chat + std::string name; + LLAgentUI::buildFullname(name); + pack_instant_message(gMessageSystem, gAgentID, false, gAgentSessionID, from_id, + name, LLStringUtil::null, IM_ONLINE, IM_SESSION_LEAVE, session_id); + gAgent.sendReliableMessage(); + gIMMgr->removeSession(session_id); +} + +class LLViewerChatterBoxInvitation final : public LLHTTPNode { public: - virtual void post( + void post( ResponsePtr response, const LLSD& context, - const LLSD& input) const + const LLSD& input) const override { //for backwards compatiblity reasons...we need to still //check for 'text' or 'voice' invitations...bleh @@ -1660,7 +1466,7 @@ class LLViewerChatterBoxInvitation : public LLHTTPNode time_t timestamp = (time_t) message_params["timestamp"].asInteger(); - BOOL is_busy = gAgent.getBusy(); + bool is_do_not_disturb = gAgent.isDoNotDisturb(); BOOL is_muted = LLMuteList::getInstance()->isMuted( from_id, name, @@ -1683,21 +1489,21 @@ class LLViewerChatterBoxInvitation : public LLHTTPNode chat.mFromID = from_id; chat.mFromName = name; - if (!is_linden && (is_busy || is_muted)) + if (!is_linden && (is_do_not_disturb || is_muted)) { return; } bool group = gAgent.isInGroup(session_id); -// [RLVa:KB] - Checked: 2010-11-30 (RLVa-1.3.0c) | Modified: RLVa-1.3.0c - if ( (gRlvHandler.hasBehaviour(RLV_BHVR_RECVIM)) || (gRlvHandler.hasBehaviour(RLV_BHVR_RECVIMFROM)) ) +// [RLVa:KB] - Checked: 2010-11-30 (RLVa-1.3.0) + if ( (RlvActions::hasBehaviour(RLV_BHVR_RECVIM)) || (RlvActions::hasBehaviour(RLV_BHVR_RECVIMFROM)) ) { - if (group) // Group chat: don't accept the invite if not an exception + if (group) { - if (!gRlvHandler.canReceiveIM(session_id)) + if (!RlvActions::canReceiveIM(session_id)) return; } - else if (!gRlvHandler.canReceiveIM(from_id)) // Conference chat: don't block; censor if not an exception + else if (!RlvActions::canReceiveIM(from_id)) { message = RlvStrings::getString(RLV_STRING_BLOCKED_RECVIM); } @@ -1736,13 +1542,7 @@ class LLViewerChatterBoxInvitation : public LLHTTPNode { if (gIMMgr->getIgnoreGroup(session_id)) { - // Tell the server we've left group chat - std::string name; - gAgent.buildFullname(name); - pack_instant_message(gMessageSystem, gAgentID, false, gAgent.getSessionID(), from_id, - name, LLStringUtil::null, IM_ONLINE, IM_SESSION_LEAVE, session_id); - gAgent.sendReliableMessage(); - gIMMgr->removeSession(session_id); + leave_group_chat(from_id, session_id); return; } else if (gSavedSettings.getBOOL("OptionShowGroupNameInChatIM")) @@ -1756,16 +1556,20 @@ class LLViewerChatterBoxInvitation : public LLHTTPNode } else { + if (from_id != session_id && block_conference(from_id)) // from and session are equal for IMs only. + { + leave_group_chat(from_id, session_id); + return; + } prepend_msg = std::string("IM: "); } chat.mText = prepend_msg + name + separator_string + saved + message.substr(message_offset); LLFloaterChat::addChat(chat, TRUE, is_this_agent); //K now we want to accept the invitation - std::string url = gAgent.getRegion()->getCapability( - "ChatSessionRequest"); + std::string url = gAgent.getRegionCapability("ChatSessionRequest"); - if ( url != "" ) + if (!url.empty()) { LLSD data; data["method"] = "accept invitation"; diff --git a/indra/newview/llimview.h b/indra/newview/llimview.h index 3e7bc6ffff..4f0159c2f6 100644 --- a/indra/newview/llimview.h +++ b/indra/newview/llimview.h @@ -41,9 +41,8 @@ class LLFloaterChatterBox; class LLFloaterIMPanel; -class LLFriendObserver; -class LLIMMgr : public LLSingleton +class LLIMMgr final : public LLSingleton { public: enum EInvitationType @@ -93,7 +92,7 @@ class LLIMMgr : public LLSingleton LLUUID addSession(const std::string& name, EInstantMessage dialog, const LLUUID& other_participant_id, - const LLDynamicArray& ids); + const uuid_vec_t& ids); // Creates a P2P session with the requisite handle for responding to voice calls LLUUID addP2PSession(const std::string& name, @@ -122,20 +121,15 @@ class LLIMMgr : public LLSingleton void updateFloaterSessionID(const LLUUID& old_session_id, const LLUUID& new_session_id); - void processIMTypingStart(const LLIMInfo* im_info); - void processIMTypingStop(const LLIMInfo* im_info); + void processIMTypingStart(const LLUUID& from_id, const EInstantMessage im_type); + void processIMTypingStop(const LLUUID& from_id, const EInstantMessage im_type); - // Rebuild stuff - void refresh(); - - void notifyNewIM(); void clearNewIMNotification(); // automatically start a call once the session has initialized void autoStartCallOnStartup(const LLUUID& session_id); // IM received that you haven't seen yet - BOOL getIMReceived() const; int getIMUnreadCount(); void setFloaterOpen(BOOL open); /*Flawfinder: ignore*/ @@ -149,11 +143,7 @@ class LLIMMgr : public LLSingleton // good connection. void disconnectAllSessions(); - static void toggle(void*); - - // This is a helper function to determine what kind of im session - // should be used for the given agent. - static EInstantMessage defaultIMTypeForAgent(const LLUUID& agent_id); + void toggle(); BOOL hasSession(const LLUUID& session_id); @@ -194,6 +184,12 @@ class LLIMMgr : public LLSingleton **/ bool endCall(const LLUUID& session_id); + void addNotifiedNonFriendSessionID(const LLUUID& session_id); + + bool isNonFriendSessionNotified(const LLUUID& session_id); + + static std::string getOfflineMessage(const LLUUID& id); + private: // create a panel and update internal representation for // consistency. Returns the pointer, caller (the class instance @@ -202,33 +198,31 @@ class LLIMMgr : public LLSingleton LLFloaterIMPanel* createFloater(const LLUUID& session_id, const LLUUID& target_id, const std::string& name, - EInstantMessage dialog, - BOOL user_initiated = FALSE); - - LLFloaterIMPanel* createFloater(const LLUUID& session_id, - const LLUUID& target_id, - const std::string& name, - const LLDynamicArray& ids, - EInstantMessage dialog, - BOOL user_initiated = FALSE); + const EInstantMessage& dialog, + const uuid_vec_t& ids = uuid_vec_t(), + bool user_initiated = false); // This simple method just iterates through all of the ids, and // prints a simple message if they are not online. Used to help // reduce 'hello' messages to the linden employees unlucky enough // to have their calling card in the default inventory. - void noteOfflineUsers(LLFloaterIMPanel* panel, const LLDynamicArray& ids); - void noteMutedUsers(LLFloaterIMPanel* panel, const LLDynamicArray& ids); - - void processIMTypingCore(const LLIMInfo* im_info, BOOL typing); + void noteOfflineUsers(LLFloaterIMPanel* panel, const uuid_vec_t& ids); + void noteMutedUsers(LLFloaterIMPanel* panel, const uuid_vec_t& ids); - static void onInviteNameLookup(const LLUUID& id, const std::string& full_name, bool is_group, LLSD payload); + void processIMTypingCore(const LLUUID& from_id, const EInstantMessage im_type, BOOL typing); private: std::set > mFloaters; - LLFriendObserver* mFriendObserver; + + // EXP-901 + // If "Only friends and groups can IM me" option is ON but the user got message from non-friend, + // the user should be notified that to be able to see this message the option should be OFF. + // This set stores session IDs in which user was notified. Need to store this IDs so that the user + // be notified only one time per session with non-friend. + typedef uuid_set_t notified_non_friend_sessions_t; + notified_non_friend_sessions_t mNotifiedNonFriendSessions; // An IM has been received that you haven't seen yet. - BOOL mIMReceived; int mIMUnreadCount; LLSD mPendingInvitations; @@ -241,14 +235,7 @@ class LLIMMgr : public LLSingleton S32 getIgnoreGroupListCount() { return mIgnoreGroupList.size(); } }; - -class LLFloaterIM : public LLMultiFloater -{ -public: - LLFloaterIM(); -}; - // Globals extern LLIMMgr *gIMMgr; -#endif // LL_LLIMView_H +#endif // LL_LLIMVIEW_H diff --git a/indra/newview/llinventoryactions.cpp b/indra/newview/llinventoryactions.cpp index a02de19980..e06b407241 100644 --- a/indra/newview/llinventoryactions.cpp +++ b/indra/newview/llinventoryactions.cpp @@ -34,6 +34,8 @@ #include "llagentwearables.h" #include "llappearancemgr.h" +#include "llavataractions.h" +#include "llfloaterperms.h" #include "llfoldervieweventlistener.h" #include "llimview.h" #include "llinventorybridge.h" @@ -42,6 +44,7 @@ #include "llinventorymodelbackgroundfetch.h" #include "llinventorypanel.h" #include "llmakeoutfitdialog.h" +#include "llmarketplacefunctions.h" #include "llnotificationsutil.h" #include "llpanelmaininventory.h" #include "llpanelobjectinventory.h" @@ -49,35 +52,161 @@ #include "lltrans.h" #include "llvoavatarself.h" #include "llnotifications.h" +// [RLVa:KB] - Checked: 2013-05-08 (RLVa-1.4.9) +#include "rlvactions.h" +#include "rlvcommon.h" +// [/RLVa:KB] extern LLUUID gAgentID; using namespace LLOldEvents; +bool contains_nocopy_items(const LLUUID& id); + +namespace LLInventoryAction +{ + void callback_doToSelected(const LLSD& notification, const LLSD& response, LLFolderView* folder, const std::string& action); + void callback_copySelected(const LLSD& notification, const LLSD& response, class LLFolderView* root, const std::string& action); + bool doToSelected(LLFolderView* root, std::string action, BOOL user_confirm = TRUE); + + void buildMarketplaceFolders(LLFolderView* root); + void updateMarketplaceFolders(); + std::list sMarketplaceFolders; // Marketplace folders that will need update once the action is completed +} + typedef LLMemberListener object_inventory_listener_t; -typedef LLMemberListener inventory_listener_t; +typedef LLMemberListener inventory_listener_t; typedef LLMemberListener inventory_panel_listener_t; -bool doToSelected(LLFolderView* folder, std::string action) +// Callback for doToSelected if DAMA required... +void LLInventoryAction::callback_doToSelected(const LLSD& notification, const LLSD& response, LLFolderView* folder, const std::string& action) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option == 0) // YES + { + doToSelected(folder, action, false); + } +} + +void LLInventoryAction::callback_copySelected(const LLSD& notification, const LLSD& response, class LLFolderView* root, const std::string& action) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option == 0) // YES, Move no copy item(s) + { + doToSelected(root, "copy_or_move_to_marketplace_listings", false); + } + else if (option == 1) // NO, Don't move no copy item(s) (leave them behind) + { + doToSelected(root, "copy_to_marketplace_listings", false); + } +} + +// Succeeds iff all selected items are bridges to objects, in which +// case returns their corresponding uuids. +bool get_selection_object_uuids(LLFolderView *root, uuid_vec_t& ids) +{ + uuid_vec_t results; + //S32 no_object = 0; + for(const auto& id : root->getSelectionList()) + { + if(id.notNull()) + { + results.push_back(id); + } + else + { + return false; //non_object++; + } + } + //if (non_object == 0) + { + ids = results; + return true; + } + //return false; +} + +bool LLInventoryAction::doToSelected(LLFolderView* root, std::string action, BOOL user_confirm) { + if (!root) + return true; + + auto selected_items = root->getSelectionList(); + + // Prompt the user and check for authorization for some marketplace active listing edits + if (user_confirm && (("delete" == action) || ("cut" == action) || ("rename" == action) || ("properties" == action) || ("task_properties" == action) || ("open" == action))) + { + auto set_iter = std::find_if(selected_items.begin(), selected_items.end(), boost::bind(&depth_nesting_in_marketplace, _1) >= 0); + if (set_iter != selected_items.end()) + { + if ("open" == action) + { + if (get_can_item_be_worn(*set_iter)) + { + // Wearing an object from any listing, active or not, is verbotten + LLNotificationsUtil::add("AlertMerchantListingCannotWear"); + return true; + } + // Note: we do not prompt for change when opening items (e.g. textures or note cards) on the marketplace... + } + else if (LLMarketplaceData::instance().isInActiveFolder(*set_iter) || + LLMarketplaceData::instance().isListedAndActive(*set_iter)) + { + // If item is in active listing, further confirmation is required + if ((("cut" == action) || ("delete" == action)) && (LLMarketplaceData::instance().isListed(*set_iter) || LLMarketplaceData::instance().isVersionFolder(*set_iter))) + { + // Cut or delete of the active version folder or listing folder itself will unlist the listing so ask that question specifically + LLNotificationsUtil::add("ConfirmMerchantUnlist", LLSD(), LLSD(), boost::bind(&LLInventoryAction::callback_doToSelected, _1, _2, root, action)); + return true; + } + // Any other case will simply modify but not unlist a listing + LLNotificationsUtil::add("ConfirmMerchantActiveChange", LLSD(), LLSD(), boost::bind(&LLInventoryAction::callback_doToSelected, _1, _2, root, action)); + return true; + } + // Cutting or deleting a whole listing needs confirmation as SLM will be archived and inaccessible to the user + else if (LLMarketplaceData::instance().isListed(*set_iter) && (("cut" == action) || ("delete" == action))) + { + LLNotificationsUtil::add("ConfirmListingCutOrDelete", LLSD(), LLSD(), boost::bind(&LLInventoryAction::callback_doToSelected, _1, _2, root, action)); + return true; + } + } + } + // Copying to the marketplace needs confirmation if nocopy items are involved + if (("copy_to_marketplace_listings" == action)) + { + auto set_iter = selected_items.begin(); + if (contains_nocopy_items(*set_iter)) + { + LLNotificationsUtil::add("ConfirmCopyToMarketplace", LLSD(), LLSD(), boost::bind(&LLInventoryAction::callback_copySelected, _1, _2, root, action)); + return true; + } + } + + // Keep track of the marketplace folders that will need update of their status/name after the operation is performed + buildMarketplaceFolders(root); + LLInventoryModel* model = &gInventory; if ("rename" == action) { - folder->startRenamingSelectedItem(); + root->startRenamingSelectedItem(); + // Update the marketplace listings that have been affected by the operation + updateMarketplaceFolders(); return true; } - else if ("delete" == action) + + if ("delete" == action) { - folder->removeSelectedItems(); + root->removeSelectedItems(); + + // Update the marketplace listings that have been affected by the operation + updateMarketplaceFolders(); return true; } - else if ("copy" == action || "cut" == action) + if ("copy" == action || "cut" == action) { LLInventoryClipboard::instance().reset(); } - std::set selected_items = folder->getSelectionList(); - LLMultiFloater* multi_floaterp = NULL; if (("task_open" == action || "open" == action) && selected_items.size() > 1) @@ -101,16 +230,30 @@ bool doToSelected(LLFolderView* folder, std::string action) LLFloater::setFloaterHost(multi_floaterp); } - std::set::iterator set_iter; - for (set_iter = selected_items.begin(); set_iter != selected_items.end(); ++set_iter) + // This rather warty piece of code is to allow items to be removed + // from the avatar in a batch, eliminating redundant + // updateAppearanceFromCOF() requests further down the line. (MAINT-4918) + // + // There are probably other cases where similar batching would be + // desirable, but the current item-by-item performAction() + // approach would need to be reworked. + uuid_vec_t object_uuids_to_remove; + if (isRemoveAction(action) && get_selection_object_uuids(root, object_uuids_to_remove)) + { + LLAppearanceMgr::instance().removeItemsFromAvatar(object_uuids_to_remove); + } + else { - LLFolderViewItem* folder_item = folder->getItemByID(*set_iter); - if(!folder_item) continue; - LLInvFVBridge* bridge = (LLInvFVBridge*)folder_item->getListener(); - if(!bridge) continue; + for (const auto& id : selected_items) + { + LLFolderViewItem* folder_item = root->getItemByID(id); + if(!folder_item) continue; + LLInvFVBridge* bridge = (LLInvFVBridge*)folder_item->getListener(); + if(!bridge) continue; - bridge->performAction(model, action); + bridge->performAction(model, action); + } } LLFloater::setFloaterHost(NULL); @@ -122,6 +265,56 @@ bool doToSelected(LLFolderView* folder, std::string action) return true; } +void LLInventoryAction::buildMarketplaceFolders(LLFolderView* root) +{ + // Make a list of all marketplace folders containing the elements in the selected list + // as well as the elements themselves. + // Once those elements are updated (cut, delete in particular but potentially any action), their + // containing folder will need to be updated as well as their initially containing folder. For + // instance, moving a stock folder from a listed folder to another will require an update of the + // target listing *and* the original listing. So we need to keep track of both. + // Note: do not however put the marketplace listings root itself in this list or the whole marketplace data will be rebuilt. + sMarketplaceFolders.clear(); + const LLUUID& marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); + if (marketplacelistings_id.isNull()) + { + return; + } + + for (const auto& item : root->getSelectionList()) + { + const LLInventoryObject* obj(gInventory.getObject(item)); + if (!obj) continue; + if (gInventory.isObjectDescendentOf(obj->getParentUUID(), marketplacelistings_id)) + { + const LLUUID& parent_id = obj->getParentUUID(); + if (parent_id != marketplacelistings_id) + { + sMarketplaceFolders.push_back(parent_id); + } + const LLUUID& curr_id = obj->getUUID(); + if (curr_id != marketplacelistings_id) + { + sMarketplaceFolders.push_back(curr_id); + } + } + } + // Suppress dupes in the list so we wo't update listings twice + sMarketplaceFolders.sort(); + sMarketplaceFolders.unique(); +} + +void LLInventoryAction::updateMarketplaceFolders() +{ + while (!sMarketplaceFolders.empty()) + { + update_marketplace_category(sMarketplaceFolders.back()); + sMarketplaceFolders.pop_back(); + } +} + + + class LLDoToSelectedPanel : public object_inventory_listener_t { bool handleEvent(LLPointer event, const LLSD& userdata) @@ -130,7 +323,7 @@ class LLDoToSelectedPanel : public object_inventory_listener_t LLFolderView* folder = panel->getRootFolder(); if(!folder) return true; - return doToSelected(folder, userdata.asString()); + return LLInventoryAction::doToSelected(folder, userdata.asString()); } }; @@ -142,7 +335,7 @@ class LLDoToSelectedFloater : public inventory_listener_t LLFolderView* folder = panel->getRootFolder(); if(!folder) return true; - return doToSelected(folder, userdata.asString()); + return LLInventoryAction::doToSelected(folder, userdata.asString()); } }; @@ -154,7 +347,7 @@ class LLDoToSelected : public inventory_panel_listener_t LLFolderView* folder = panel->getRootFolder(); if(!folder) return true; - return doToSelected(folder, userdata.asString()); + return LLInventoryAction::doToSelected(folder, userdata.asString()); } }; @@ -166,7 +359,7 @@ class LLNewWindow : public inventory_listener_t S32 left = 0 , top = 0; gFloaterView->getNewFloaterPosition(&left, &top); rect.setLeftTopAndSize(left, top, rect.getWidth(), rect.getHeight()); - LLInventoryView* iv = new LLInventoryView(std::string("Inventory"), + LLPanelMainInventory* iv = new LLPanelMainInventory(std::string("Inventory"), rect, mPtr->getActivePanel()->getModel()); iv->getActivePanel()->setFilterTypes(mPtr->getActivePanel()->getFilterObjectTypes()); @@ -179,105 +372,10 @@ class LLNewWindow : public inventory_listener_t } }; -class LLShowFilters : public inventory_listener_t -{ - bool handleEvent(LLPointer event, const LLSD& userdata) - { - mPtr->toggleFindOptions(); - return true; - } -}; - -class LLResetFilter : public inventory_listener_t -{ - bool handleEvent(LLPointer event, const LLSD& userdata) - { - mPtr->resetFilters(); - return true; - } -}; - -class LLCloseAllFolders : public inventory_panel_listener_t -{ - bool handleEvent(LLPointer event, const LLSD& userdata) - { - mPtr->closeAllFolders(); - return true; - } -}; - -class LLCloseAllFoldersFloater : public inventory_listener_t -{ - bool handleEvent(LLPointer event, const LLSD& userdata) - { - mPtr->getPanel()->closeAllFolders(); - return true; - } -}; - -class LLEmptyTrash : public inventory_panel_listener_t -{ - bool handleEvent(LLPointer event, const LLSD& userdata) - { - LLInventoryModel* model = mPtr->getModel(); - if(!model) return false; - LLNotificationsUtil::add("ConfirmEmptyTrash", LLSD(), LLSD(), boost::bind(&LLEmptyTrash::callback_empty_trash, this, _1, _2)); - return true; - } - - bool callback_empty_trash(const LLSD& notification, const LLSD& response) - { - S32 option = LLNotification::getSelectedOption(notification, response); - if (option == 0) // YES - { - LLInventoryModel* model = mPtr->getModel(); - LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH); - model->purgeDescendentsOf(trash_id); - model->notifyObservers(); - } - return false; - } -}; - -class LLEmptyLostAndFound : public inventory_panel_listener_t -{ - bool handleEvent(LLPointer event, const LLSD& userdata) - { - LLInventoryModel* model = mPtr->getModel(); - if(!model) return false; - LLNotificationsUtil::add("ConfirmEmptyLostAndFound", LLSD(), LLSD(), boost::bind(&LLEmptyLostAndFound::callback_empty_lost_and_found, this, _1, _2)); - return true; - } - - bool callback_empty_lost_and_found(const LLSD& notification, const LLSD& response) - { - S32 option = LLNotification::getSelectedOption(notification, response); - if (option == 0) // YES - { - LLInventoryModel* model = mPtr->getModel(); - LLUUID lost_and_found_id = model->findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); - model->purgeDescendentsOf(lost_and_found_id); - model->notifyObservers(); - } - return false; - } -}; - -class LLEmptyTrashFloater : public inventory_listener_t -{ - bool handleEvent(LLPointer event, const LLSD& userdata) - { - LLInventoryModel* model = mPtr->getPanel()->getModel(); - if(!model) return false; - LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH); - model->purgeDescendentsOf(trash_id); - model->notifyObservers(); - return true; - } -}; - -void do_create(LLInventoryModel *model, LLInventoryPanel *ptr, std::string type, LLFolderBridge *self = NULL) +void do_create(LLInventoryModel *model, LLInventoryPanel *ptr, const LLSD& sdtype, LLFolderBridge *self = NULL) { + const std::string& type = sdtype.asString(); + LL_INFOS() << "self=0x" << std::hex << self << std::dec << LL_ENDL; if ("category" == type) { LLUUID category; @@ -291,7 +389,15 @@ void do_create(LLInventoryModel *model, LLInventoryPanel *ptr, std::string type, LLFolderType::FT_NONE, LLStringUtil::null); } model->notifyObservers(); + + // Singu Note: SV-2036 + // Hack! setSelection sets category to fetching state, which disables scrolling. Scrolling, however, is desired. + // Setting autoSelectOverride to true just happens to skip the fetch check, thus allowing the scroll to proceed. + bool autoselected = ptr->getRootFolder()->getAutoSelectOverride(); + ptr->getRootFolder()->setAutoSelectOverride(true); ptr->setSelection(category, TRUE); + // Restore autoSelectOverride to whatever it was before we hijacked it. + ptr->getRootFolder()->setAutoSelectOverride(autoselected); } else if ("lsl" == type) { @@ -300,7 +406,7 @@ void do_create(LLInventoryModel *model, LLInventoryPanel *ptr, std::string type, parent_id, LLAssetType::AT_LSL_TEXT, LLInventoryType::IT_LSL, - PERM_MOVE | PERM_TRANSFER); + LLFloaterPerms::getNextOwnerPerms("Scripts")); } else if ("notecard" == type) { @@ -309,7 +415,7 @@ void do_create(LLInventoryModel *model, LLInventoryPanel *ptr, std::string type, parent_id, LLAssetType::AT_NOTECARD, LLInventoryType::IT_NOTECARD, - PERM_ALL); + LLFloaterPerms::getNextOwnerPerms("Notecards")); } else if ("gesture" == type) { @@ -318,7 +424,7 @@ void do_create(LLInventoryModel *model, LLInventoryPanel *ptr, std::string type, parent_id, LLAssetType::AT_GESTURE, LLInventoryType::IT_GESTURE, - PERM_ALL); + LLFloaterPerms::getNextOwnerPerms("Gestures")); } else if ("outfit" == type || ("update outfit" == type && !LLAppearanceMgr::getInstance()->updateBaseOutfit())) // If updateBaseOutfit fails, prompt to make a new outfit { @@ -332,31 +438,7 @@ void do_create(LLInventoryModel *model, LLInventoryPanel *ptr, std::string type, ptr->getRootFolder()->setNeedsAutoRename(TRUE); } -class LLDoCreate : public inventory_panel_listener_t -{ - bool handleEvent(LLPointer event, const LLSD& userdata) - { - LLInventoryModel* model = mPtr->getModel(); - if(!model) return false; - std::string type = userdata.asString(); - do_create(model, mPtr, type, LLFolderBridge::sSelf.get()); - return true; - } -}; - -class LLDoCreateFloater : public inventory_listener_t -{ - bool handleEvent(LLPointer event, const LLSD& userdata) - { - LLInventoryModel* model = mPtr->getPanel()->getModel(); - if(!model) return false; - std::string type = userdata.asString(); - do_create(model, mPtr->getPanel(), type); - return true; - } -}; - -class LLSetSortBy : public inventory_listener_t +struct LLSetSortBy : public inventory_listener_t { bool handleEvent(LLPointer event, const LLSD& userdata) { @@ -415,20 +497,7 @@ class LLSetSortBy : public inventory_listener_t return true; } }; - -class LLRefreshInvModel : public inventory_listener_t -{ - bool handleEvent(LLPointer event, const LLSD& userdata) - { - LLInventoryModel* model = mPtr->getPanel()->getModel(); - if(!model) return false; - model->empty(); - LLInventoryModelBackgroundFetch::instance().start(); - return true; - } -}; - -class LLSetSearchType : public inventory_listener_t +struct LLSetSearchType : public inventory_listener_t { bool handleEvent(LLPointer event, const LLSD& userdata) { @@ -440,25 +509,26 @@ class LLSetSearchType : public inventory_listener_t } }; -class LLBeginIMSession : public inventory_panel_listener_t +struct LLBeginIMSession : public inventory_panel_listener_t { bool handleEvent(LLPointer event, const LLSD& userdata) { LLInventoryPanel *panel = mPtr; LLInventoryModel* model = panel->getModel(); if(!model) return true; - std::set selected_items = panel->getRootFolder()->getSelectionList(); std::string name; static int session_num = 1; - LLDynamicArray members; + uuid_vec_t members; EInstantMessage type = IM_SESSION_CONFERENCE_START; - for (std::set::const_iterator iter = selected_items.begin(); iter != selected_items.end(); iter++) - { +// [RLVa:KB] - Checked: 2013-05-08 (RLVa-1.4.9) + bool fRlvCanStartIM = true; +// [/RLVa:KB] - LLUUID item = *iter; + for (const auto& item : panel->getRootFolder()->getSelectionList()) + { LLFolderViewItem* folder_item = panel->getRootFolder()->getItemByID(item); if(folder_item) @@ -480,7 +550,7 @@ class LLBeginIMSession : public inventory_panel_listener_t item_array, LLInventoryModel::EXCLUDE_TRASH, is_buddy); - S32 count = item_array.count(); + S32 count = item_array.size(); if(count > 0) { // create the session @@ -490,10 +560,13 @@ class LLBeginIMSession : public inventory_panel_listener_t LLUUID id; for(S32 i = 0; i < count; ++i) { - id = item_array.get(i)->getCreatorUUID(); + id = item_array.at(i)->getCreatorUUID(); if(at.isBuddyOnline(id)) { - members.put(id); +// [RLVa:KB] - Checked: 2013-05-08 (RLVa-1.4.9) + fRlvCanStartIM &= RlvActions::canStartIM(id); +// [RLVa:KB] + members.push_back(id); } } } @@ -515,7 +588,10 @@ class LLBeginIMSession : public inventory_panel_listener_t if(at.isBuddyOnline(id)) { - members.put(id); +// [RLVa:KB] - Checked: 2013-05-08 (RLVa-1.4.9) + fRlvCanStartIM &= RlvActions::canStartIM(id); +// [RLVa:KB] + members.push_back(id); } } } //if IT_CALLINGCARD @@ -526,6 +602,15 @@ class LLBeginIMSession : public inventory_panel_listener_t // the session_id is randomly generated UUID which will be replaced later // with a server side generated number +// [RLVa:KB] - Checked: 2013-05-08 (RLVa-1.4.9) + if (!fRlvCanStartIM) + { + make_ui_sound("UISndIvalidOp"); + RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTCONF); + return true; + } +// [/RLVa:KB] + if (name.empty()) { name = llformat("Session %d", session_num++); @@ -542,7 +627,7 @@ class LLBeginIMSession : public inventory_panel_listener_t } }; -class LLAttachObject : public inventory_panel_listener_t +struct LLAttachObject : public inventory_panel_listener_t { bool handleEvent(LLPointer event, const LLSD& userdata) { @@ -550,14 +635,13 @@ class LLAttachObject : public inventory_panel_listener_t LLFolderView* folder = panel->getRootFolder(); if(!folder) return true; - std::set selected_items = folder->getSelectionList(); + auto selected_items = folder->getSelectionList(); LLUUID id = *selected_items.begin(); std::string joint_name = userdata.asString(); - LLVOAvatar *avatarp = gAgentAvatarp; LLViewerJointAttachment* attachmentp = NULL; - for (LLVOAvatar::attachment_map_t::iterator iter = avatarp->mAttachmentPoints.begin(); - iter != avatarp->mAttachmentPoints.end(); ) + for (LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin(); + iter != gAgentAvatarp->mAttachmentPoints.end(); ) { LLVOAvatar::attachment_map_t::iterator curiter = iter++; LLViewerJointAttachment* attachment = curiter->second; @@ -571,7 +655,7 @@ class LLAttachObject : public inventory_panel_listener_t { return true; } - if (LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(id)) + if (LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getLinkedItem(id)) { if(gInventory.isObjectDescendentOf(id, gInventory.getRootFolderID())) { @@ -580,7 +664,10 @@ class LLAttachObject : public inventory_panel_listener_t else if(item->isFinished()) { // must be in library. copy it to our inventory and put it on. - LLPointer cb = new LLBoostFuncInventoryCallback(boost::bind(rez_attachment_cb, _1, attachmentp, false)); +// LLPointer cb = new LLBoostFuncInventoryCallback(boost::bind(&rez_attachment_cb, _1, attachmentp)); +// [SL:KB] - Patch: Appearance-DnDWear | Checked: 2013-02-04 (Catznip-3.4) + LLPointer cb = new LLBoostFuncInventoryCallback(boost::bind(&rez_attachment_cb, _1, attachmentp, false)); +// [/SL;KB] copy_inventory_item( gAgentID, item->getPermissions().getOwner(), @@ -598,31 +685,30 @@ class LLAttachObject : public inventory_panel_listener_t void init_object_inventory_panel_actions(LLPanelObjectInventory *panel) { - (new LLDoToSelectedPanel())->registerListener(panel, "Inventory.DoToSelected"); + (new LLBindMemberListener(panel, "Inventory.DoToSelected", boost::bind(&LLInventoryAction::doToSelected, boost::bind(&LLPanelObjectInventory::getRootFolder, panel), _2, true))); } -void init_inventory_actions(LLInventoryView *floater) +void init_inventory_actions(LLPanelMainInventory *floater) { - (new LLDoToSelectedFloater())->registerListener(floater, "Inventory.DoToSelected"); - (new LLCloseAllFoldersFloater())->registerListener(floater, "Inventory.CloseAllFolders"); - (new LLEmptyTrashFloater())->registerListener(floater, "Inventory.EmptyTrash"); - (new LLDoCreateFloater())->registerListener(floater, "Inventory.DoCreate"); - + (new LLBindMemberListener(floater, "Inventory.DoToSelected", boost::bind(&LLInventoryAction::doToSelected, boost::bind(&LLPanelMainInventory::getRootFolder, floater), _2, true))); + (new LLBindMemberListener(floater, "Inventory.CloseAllFolders", boost::bind(&LLInventoryPanel::closeAllFolders, boost::bind(&LLPanelMainInventory::getPanel, floater)))); + (new LLBindMemberListener(floater, "Inventory.EmptyTrash", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "", LLFolderType::FT_TRASH))); + (new LLBindMemberListener(floater, "Inventory.DoCreate", boost::bind(&do_create, &gInventory, boost::bind(&LLPanelMainInventory::getPanel, floater), _2, (LLFolderBridge*)0))); (new LLNewWindow())->registerListener(floater, "Inventory.NewWindow"); - (new LLShowFilters())->registerListener(floater, "Inventory.ShowFilters"); - (new LLResetFilter())->registerListener(floater, "Inventory.ResetFilter"); + (new LLBindMemberListener(floater, "Inventory.ShowFilters", boost::bind(&LLPanelMainInventory::toggleFindOptions, floater))); + (new LLBindMemberListener(floater, "Inventory.ResetFilter", boost::bind(&LLPanelMainInventory::resetFilters, floater))); (new LLSetSortBy())->registerListener(floater, "Inventory.SetSortBy"); - (new LLSetSearchType())->registerListener(floater, "Inventory.SetSearchType"); } void init_inventory_panel_actions(LLInventoryPanel *panel) { - (new LLDoToSelected())->registerListener(panel, "Inventory.DoToSelected"); + (new LLBindMemberListener(panel, "Inventory.DoToSelected", boost::bind(&LLInventoryAction::doToSelected, boost::bind(&LLInventoryPanel::getRootFolder, panel), _2, true))); (new LLAttachObject())->registerListener(panel, "Inventory.AttachObject"); - (new LLCloseAllFolders())->registerListener(panel, "Inventory.CloseAllFolders"); - (new LLEmptyTrash())->registerListener(panel, "Inventory.EmptyTrash"); - (new LLEmptyLostAndFound())->registerListener(panel, "Inventory.EmptyLostAndFound"); - (new LLDoCreate())->registerListener(panel, "Inventory.DoCreate"); + (new LLBindMemberListener(panel, "Inventory.CloseAllFolders", boost::bind(&LLInventoryPanel::closeAllFolders, panel))); + (new LLBindMemberListener(panel, "Inventory.EmptyTrash", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyTrash", LLFolderType::FT_TRASH))); + (new LLBindMemberListener(panel, "Inventory.EmptyLostAndFound", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyLostAndFound", LLFolderType::FT_LOST_AND_FOUND))); + (new LLBindMemberListener(panel, "Inventory.DoCreate", boost::bind(&do_create, &gInventory, panel, _2, boost::bind(&LLHandle::get, boost::cref(LLFolderBridge::sSelf))))); (new LLBeginIMSession())->registerListener(panel, "Inventory.BeginIMSession"); + (new LLBindMemberListener(panel, "Inventory.Share", boost::bind(&LLAvatarActions::shareWithAvatars, panel))); } diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index f8e9390dad..fb645329a2 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -36,14 +36,17 @@ #include "lffloaterinvpanel.h" #include "llagent.h" +#include "llagentbenefits.h" #include "llagentcamera.h" #include "llagentwearables.h" #include "llappearancemgr.h" #include "llattachmentsmgr.h" #include "llavataractions.h" #include "llcallingcard.h" +#include "llfavoritesbar.h" // management of favorites folder #include "llfirstuse.h" #include "llfloatercustomize.h" +#include "llfloatermarketplacelistings.h" #include "llfloateropenobject.h" #include "llfloaterproperties.h" #include "llfloaterworldmap.h" @@ -61,6 +64,7 @@ #include "llmarketplacefunctions.h" #include "llnotifications.h" #include "llnotificationsutil.h" +#include "llpanelmaininventory.h" #include "llpreviewanim.h" #include "llpreviewgesture.h" #include "llpreviewlandmark.h" @@ -71,6 +75,7 @@ #include "llselectmgr.h" #include "lltooldraganddrop.h" #include "lltrans.h" +#include "llurlaction.h" #include "llviewerassettype.h" #include "llviewerfoldertype.h" #include "llviewermenu.h" @@ -85,24 +90,17 @@ #include "hippogridmanager.h" -// [RLVa:KB] +// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1) +#include "rlvactions.h" #include "rlvhandler.h" #include "rlvlocks.h" // [/RLVa:KB] -// Marketplace outbox current disabled -#define ENABLE_MERCHANT_OUTBOX_CONTEXT_MENU 1 -#define ENABLE_MERCHANT_SEND_TO_MARKETPLACE_CONTEXT_MENU 1 -#define BLOCK_WORN_ITEMS_IN_OUTBOX 1 - -bool InventoryLinksEnabled() -{ - return gHippoGridManager->getConnectedGrid()->supportsInvLinks(); -} - typedef std::pair two_uuids_t; typedef std::list two_uuids_list_t; +const F32 SOUND_GAIN = 1.0f; + struct LLMoveInv { LLUUID mObjectID; @@ -114,27 +112,13 @@ struct LLMoveInv using namespace LLOldEvents; -// Helpers -// bug in busy count inc/dec right now, logic is complex... do we really need it? -void inc_busy_count() -{ -// gViewerWindow->getWindow()->incBusyCount(); -// check balance of these calls if this code is changed to ever actually -// *do* something! -} -void dec_busy_count() -{ -// gViewerWindow->getWindow()->decBusyCount(); -// check balance of these calls if this code is changed to ever actually -// *do* something! -} - // Function declarations void remove_inventory_category_from_avatar(LLInventoryCategory* category); void remove_inventory_category_from_avatar_step2( BOOL proceed, LLUUID category_id); bool move_task_inventory_callback(const LLSD& notification, const LLSD& response, LLMoveInv*); bool confirm_attachment_rez(const LLSD& notification, const LLSD& response); static BOOL can_move_to_outfit(LLInventoryItem* inv_item, BOOL move_is_into_current_outfit); +void build_context_menu_folder_options(LLInventoryModel* mModel, const LLUUID& mUUID, menuentry_vec_t& items, menuentry_vec_t& disabled_items); // Helper functions @@ -145,17 +129,7 @@ bool isAddAction(const std::string& action) bool isRemoveAction(const std::string& action) { - return ("take_off" == action || "detach" == action || "deactivate" == action); -} - -bool isMarketplaceCopyAction(const std::string& action) -{ - return (("copy_to_outbox" == action) || ("move_to_outbox" == action)); -} - -bool isMarketplaceSendAction(const std::string& action) -{ - return ("send_to_marketplace" == action); + return ("take_off" == action || "detach" == action); } // Used by LLFolderBridge as callback for directory fetching recursion @@ -181,7 +155,6 @@ class LLRightClickInventoryFetchObserver : public LLInventoryFetchItemsObserver { if (clear_observer) { - dec_busy_count(); gInventory.removeObserver(this); delete this; } @@ -223,7 +196,11 @@ const std::string& LLInvFVBridge::getName() const const std::string& LLInvFVBridge::getDisplayName() const { - return getName(); + if(mDisplayName.empty()) + { + buildDisplayName(); + } + return mDisplayName; } // Folders have full perms @@ -242,9 +219,24 @@ LLFolderType::EType LLInvFVBridge::getPreferredType() const // Folders don't have creation dates. time_t LLInvFVBridge::getCreationDate() const { - return 0; + LLInventoryObject* objectp = getInventoryObject(); + if (objectp) + { + return objectp->getCreationDate(); + } + return (time_t)0; +} + +void LLInvFVBridge::setCreationDate(time_t creation_date_utc) +{ + LLInventoryObject* objectp = getInventoryObject(); + if (objectp) + { + objectp->setCreationDate(creation_date_utc); + } } + // Can be destroyed (or moved to trash) BOOL LLInvFVBridge::isItemRemovable() const { @@ -262,16 +254,57 @@ BOOL LLInvFVBridge::isLink() const return mIsLink; } +BOOL LLInvFVBridge::isLibraryItem() const +{ + return gInventory.isObjectDescendentOf(getUUID(),gInventory.getLibraryRootFolderID()); +} + /*virtual*/ /** * @brief Adds this item into clipboard storage */ -void LLInvFVBridge::cutToClipboard() +BOOL LLInvFVBridge::cutToClipboard() { if(isItemMovable()) + { + const LLUUID& marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); + const BOOL cut_from_marketplacelistings = gInventory.isObjectDescendentOf(mUUID, marketplacelistings_id); + + if (cut_from_marketplacelistings && (LLMarketplaceData::instance().isInActiveFolder(mUUID) || + LLMarketplaceData::instance().isListedAndActive(mUUID))) + { + // Prompt the user if cutting from a marketplace active listing + LLNotificationsUtil::add("ConfirmMerchantActiveChange", LLSD(), LLSD(), boost::bind(&LLInvFVBridge::callback_cutToClipboard, this, _1, _2)); + } + else + { + // Otherwise just perform the cut + return perform_cutToClipboard(); + } + } + return FALSE; +} + +// Callback for cutToClipboard if DAMA required... +BOOL LLInvFVBridge::callback_cutToClipboard(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option == 0) // YES + { + return perform_cutToClipboard(); + } + return FALSE; +} + +BOOL LLInvFVBridge::perform_cutToClipboard() +{ + if (isItemMovable()) { LLInventoryClipboard::instance().cut(mUUID); + LLFolderView::removeCutItems(); + return true; } + return false; } BOOL LLInvFVBridge::copyToClipboard() const @@ -285,18 +318,26 @@ BOOL LLInvFVBridge::copyToClipboard() const return FALSE; } -// *TODO: make sure this does the right thing void LLInvFVBridge::showProperties() { - show_item_profile(mUUID); - - // Disable old properties floater; this is replaced by the sidepanel. - /* - LLFloaterReg::showInstance("properties", mUUID); - */ + if (isMarketplaceListingsFolder()) + { + show_item_profile(mUUID); + LLFloater* floater_properties = LLFloaterProperties::find(mUUID, LLUUID::null); + if (floater_properties) + { + floater_properties->setVisible(true); + floater_properties->setFrontmost(true); + //floater_properties->setVisibleAndFrontmost(); + } + } + else + { + show_item_profile(mUUID); + } } -void LLInvFVBridge::removeBatch(LLDynamicArray& batch) +void LLInvFVBridge::removeBatch(std::vector& batch) { // Deactivate gestures when moving them into Trash LLInvFVBridge* bridge; @@ -305,11 +346,11 @@ void LLInvFVBridge::removeBatch(LLDynamicArray& batc LLViewerInventoryCategory* cat = NULL; LLInventoryModel::cat_array_t descendent_categories; LLInventoryModel::item_array_t descendent_items; - S32 count = batch.count(); - S32 i,j; + U32 count = batch.size(); + U32 i,j; for(i = 0; i < count; ++i) { - bridge = (LLInvFVBridge*)(batch.get(i)); + bridge = (LLInvFVBridge*)(batch[i]); if(!bridge || !bridge->isItemRemovable()) continue; item = (LLViewerInventoryItem*)model->getItem(bridge->getUUID()); if (item) @@ -322,13 +363,13 @@ void LLInvFVBridge::removeBatch(LLDynamicArray& batc } for(i = 0; i < count; ++i) { - bridge = (LLInvFVBridge*)(batch.get(i)); + bridge = (LLInvFVBridge*)(batch[i]); if(!bridge || !bridge->isItemRemovable()) continue; cat = (LLViewerInventoryCategory*)model->getCategory(bridge->getUUID()); if (cat) { gInventory.collectDescendents( cat->getUUID(), descendent_categories, descendent_items, FALSE ); - for (j=0; jgetType()) { @@ -340,7 +381,7 @@ void LLInvFVBridge::removeBatch(LLDynamicArray& batc removeBatchNoCheck(batch); } -void LLInvFVBridge::removeBatchNoCheck(LLDynamicArray& batch) +void LLInvFVBridge::removeBatchNoCheck(std::vector& batch) { // this method moves a bunch of items and folders to the trash. As // per design guidelines for the inventory model, the message is @@ -356,14 +397,14 @@ void LLInvFVBridge::removeBatchNoCheck(LLDynamicArrayisItemRemovable()) continue; item = (LLViewerInventoryItem*)model->getItem(bridge->getUUID()); if(item) @@ -376,7 +417,7 @@ void LLInvFVBridge::removeBatchNoCheck(LLDynamicArrayisItemRemovable()) continue; item = (LLViewerInventoryItem*)model->getItem(bridge->getUUID()); if(item) @@ -417,7 +458,7 @@ void LLInvFVBridge::removeBatchNoCheck(LLDynamicArrayisItemRemovable()) continue; LLViewerInventoryCategory* cat = (LLViewerInventoryCategory*)model->getCategory(bridge->getUUID()); if(cat) @@ -459,6 +500,11 @@ void LLInvFVBridge::removeBatchNoCheck(LLDynamicArrayupdateItem(item); + } } // notify inventory observers. @@ -486,14 +532,14 @@ BOOL LLInvFVBridge::isClipboardPasteable() const // In normal mode, we need to check each element of the clipboard to know if we can paste or not LLInventoryPanel* panel = dynamic_cast(mInventoryPanel.get()); - LLDynamicArray objects; + uuid_vec_t objects; LLInventoryClipboard::instance().retrieve(objects); - S32 count = objects.count(); + S32 count = objects.size(); for(S32 i = 0; i < count; i++) { - const LLUUID &item_id = objects.get(i); + const LLUUID &item_id = objects.at(i); - // Folders are pasteable if all items in there are copyable + // Folders are pastable if all items in there are copyable const LLInventoryCategory *cat = model->getCategory(item_id); if (cat) { @@ -504,7 +550,7 @@ BOOL LLInvFVBridge::isClipboardPasteable() const continue; } - // Each item must be copyable to be pasteable + // Each item must be copyable to be pastable LLItemBridge item_br(panel, mRoot, item_id); if (!item_br.isItemCopyable()) return FALSE; @@ -528,12 +574,12 @@ bool LLInvFVBridge::isClipboardPasteableAsCopy() const // In copy mode, we need to check each element of the clipboard to know if it's a link LLInventoryPanel* panel = dynamic_cast(mInventoryPanel.get()); - LLDynamicArray objects; + uuid_vec_t objects; LLInventoryClipboard::instance().retrieve(objects); - const S32 count = objects.count(); + const S32 count = objects.size(); for(S32 i = 0; i < count; i++) { - const LLUUID &item_id = objects.get(i); + const LLUUID &item_id = objects.at(i); // Folders may be links const LLInventoryCategory *cat = model->getCategory(item_id); @@ -556,10 +602,6 @@ bool LLInvFVBridge::isClipboardPasteableAsCopy() const BOOL LLInvFVBridge::isClipboardPasteableAsLink() const { - if (!InventoryLinksEnabled()) - { - return FALSE; - } if (!LLInventoryClipboard::instance().hasContents() || !isAgentInventory()) { return FALSE; @@ -570,12 +612,12 @@ BOOL LLInvFVBridge::isClipboardPasteableAsLink() const return FALSE; } - LLDynamicArray objects; + uuid_vec_t objects; LLInventoryClipboard::instance().retrieve(objects); - S32 count = objects.count(); + S32 count = objects.size(); for(S32 i = 0; i < count; i++) { - const LLInventoryItem *item = model->getItem(objects.get(i)); + const LLInventoryItem *item = model->getItem(objects.at(i)); if (item) { if (!LLAssetType::lookupCanLink(item->getActualType())) @@ -583,7 +625,7 @@ BOOL LLInvFVBridge::isClipboardPasteableAsLink() const return FALSE; } } - const LLViewerInventoryCategory *cat = model->getCategory(objects.get(i)); + const LLViewerInventoryCategory *cat = model->getCategory(objects.at(i)); if (cat && LLFolderType::lookupIsProtectedType(cat->getPreferredType())) { return FALSE; @@ -592,6 +634,41 @@ BOOL LLInvFVBridge::isClipboardPasteableAsLink() const return TRUE; } +void disable_context_entries_if_present(LLMenuGL& menu, + const menuentry_vec_t &disabled_entries) +{ + const LLView::child_list_t *list = menu.getChildList(); + for (LLView::child_list_t::const_iterator itor = list->begin(); + itor != list->end(); + ++itor) + { + LLView *menu_item = (*itor); + std::string name = menu_item->getName(); + + // descend into split menus: + LLMenuItemBranchGL* branchp = dynamic_cast(menu_item); + if ((name == "More") && branchp) + { + disable_context_entries_if_present(*branchp->getBranch(), disabled_entries); + } + + bool found = false; + menuentry_vec_t::const_iterator itor2; + for (itor2 = disabled_entries.begin(); itor2 != disabled_entries.end(); ++itor2) + { + if (*itor2 == name) + { + found = true; + break; + } + } + + if (found) + { + menu_item->setEnabled(FALSE); + } + } +} void hide_context_entries(LLMenuGL& menu, const menuentry_vec_t &entries_to_show, const menuentry_vec_t &disabled_entries) @@ -631,7 +708,7 @@ void hide_context_entries(LLMenuGL& menu, // between two separators). if (found) { - const bool is_entry_separator = (dynamic_cast(menu_item) != NULL); + const bool is_entry_separator = !branchp && (dynamic_cast(menu_item) != NULL); found = !(is_entry_separator && is_previous_entry_separator); is_previous_entry_separator = is_entry_separator; } @@ -704,7 +781,7 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id, if (!isInboxFolder()) { items.push_back(std::string("Rename")); - if (!isItemRenameable() || (flags & FIRST_SELECTED_ITEM) == 0) + if (!isItemRenameable() || ((flags & FIRST_SELECTED_ITEM) == 0)) { disabled_items.push_back(std::string("Rename")); } @@ -742,14 +819,19 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id, disabled_items.push_back(std::string("Cut")); } - if (canListOnMarketplace()) + if (canListOnMarketplace() && !isMarketplaceListingsFolder() && !isInboxFolder()) { items.push_back(std::string("Marketplace Separator")); - items.push_back(std::string("Merchant Copy")); - if (!canListOnMarketplaceNow()) + if (gMenuHolder->getChild("MarketplaceListings")->getVisible()) { - disabled_items.push_back(std::string("Merchant Copy")); + items.push_back(std::string("Marketplace Copy")); + items.push_back(std::string("Marketplace Move")); + if (!canListOnMarketplaceNow()) + { + disabled_items.push_back(std::string("Marketplace Copy")); + disabled_items.push_back(std::string("Marketplace Move")); + } } } } @@ -757,11 +839,11 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id, bool paste_as_copy = false; // If Paste As Copy is on the menu, Paste As Link will always show up disabled, so don't bother. // Don't allow items to be pasted directly into the COF or the inbox/outbox - if (!isCOFFolder() && !isInboxFolder() && !isOutboxFolder()) + if (!isCOFFolder() && !isInboxFolder()) { items.push_back(std::string("Paste")); // Paste as copy if we have links. - if (InventoryLinksEnabled() && isClipboardPasteableAsCopy()) + if (isClipboardPasteableAsCopy()) { items.push_back(std::string("Paste As Copy")); paste_as_copy = true; @@ -774,7 +856,7 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id, paste_as_copy = false; } - if (!paste_as_copy && InventoryLinksEnabled()) + if (!paste_as_copy) { items.push_back(std::string("Paste As Link")); if (!isClipboardPasteableAsLink() || (flags & FIRST_SELECTED_ITEM) == 0) @@ -796,19 +878,21 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id, void LLInvFVBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { - lldebugs << "LLInvFVBridge::buildContextMenu()" << llendl; + LL_DEBUGS() << "LLInvFVBridge::buildContextMenu()" << LL_ENDL; menuentry_vec_t items; menuentry_vec_t disabled_items; if(isItemInTrash()) { addTrashContextMenuOptions(items, disabled_items); - } - else if(isOutboxFolder()) - { - addOutboxContextMenuOptions(flags, items, disabled_items); } else { + items.push_back(std::string("Share")); + if (!canShare()) + { + disabled_items.push_back(std::string("Share")); + } + addOpenRightClickMenuOption(items); items.push_back(std::string("Properties")); @@ -831,6 +915,31 @@ void LLInvFVBridge::buildContextMenu(LLMenuGL& menu, U32 flags) hide_context_entries(menu, items, disabled_items); } +bool get_selection_item_uuids(LLFolderView::selected_items_t& selected_items, uuid_vec_t& ids) +{ + uuid_vec_t results; + S32 non_item = 0; + for(LLFolderView::selected_items_t::iterator it = selected_items.begin(); it != selected_items.end(); ++it) + { + LLItemBridge *view_model = dynamic_cast((*it)->getListener()); + + if(view_model && view_model->getUUID().notNull()) + { + results.push_back(view_model->getUUID()); + } + else + { + non_item++; + } + } + if (non_item == 0) + { + ids = results; + return true; + } + return false; +} + void LLInvFVBridge::addTrashContextMenuOptions(menuentry_vec_t &items, menuentry_vec_t &disabled_items) { @@ -890,30 +999,126 @@ void LLInvFVBridge::addOpenRightClickMenuOption(menuentry_vec_t &items) items.push_back(std::string("Open")); } -void LLInvFVBridge::addOutboxContextMenuOptions(U32 flags, +void LLInvFVBridge::addMarketplaceContextMenuOptions(U32 flags, menuentry_vec_t &items, menuentry_vec_t &disabled_items) { - items.push_back(std::string("Rename")); - items.push_back(std::string("Delete")); - - if ((flags & FIRST_SELECTED_ITEM) == 0) + S32 depth = depth_nesting_in_marketplace(mUUID); + if (depth == 1) + { + // Options available at the Listing Folder level + items.push_back(std::string("Marketplace Create Listing")); + items.push_back(std::string("Marketplace Associate Listing")); + items.push_back(std::string("Marketplace Check Listing")); + items.push_back(std::string("Marketplace List")); + items.push_back(std::string("Marketplace Unlist")); + if (LLMarketplaceData::instance().isUpdating(mUUID,depth) || ((flags & FIRST_SELECTED_ITEM) == 0)) + { + // During SLM update, disable all marketplace related options + // Also disable all if multiple selected items + disabled_items.push_back(std::string("Marketplace Create Listing")); + disabled_items.push_back(std::string("Marketplace Associate Listing")); + disabled_items.push_back(std::string("Marketplace Check Listing")); + disabled_items.push_back(std::string("Marketplace List")); + disabled_items.push_back(std::string("Marketplace Unlist")); + } + else + { + if (gSavedSettings.getBOOL("MarketplaceListingsLogging")) + { + items.push_back(std::string("Marketplace Get Listing")); + } + if (LLMarketplaceData::instance().isListed(mUUID)) + { + disabled_items.push_back(std::string("Marketplace Create Listing")); + disabled_items.push_back(std::string("Marketplace Associate Listing")); + items.push_back(std::string("Marketplace Copy ID")); + if (LLMarketplaceData::instance().getVersionFolder(mUUID).isNull()) + { + disabled_items.push_back(std::string("Marketplace List")); + disabled_items.push_back(std::string("Marketplace Unlist")); + } + else + { + if (LLMarketplaceData::instance().getActivationState(mUUID)) + { + disabled_items.push_back(std::string("Marketplace List")); + } + else + { + disabled_items.push_back(std::string("Marketplace Unlist")); + } + } + } + else + { + disabled_items.push_back(std::string("Marketplace List")); + disabled_items.push_back(std::string("Marketplace Unlist")); + if (gSavedSettings.getBOOL("MarketplaceListingsLogging")) + { + disabled_items.push_back(std::string("Marketplace Get Listing")); + } + } + } + } + if (depth == 2) { - disabled_items.push_back(std::string("Rename")); + // Options available at the Version Folder levels and only for folders + LLInventoryCategory* cat = gInventory.getCategory(mUUID); + if (cat && LLMarketplaceData::instance().isListed(cat->getParentUUID())) + { + items.push_back(std::string("Marketplace Activate")); + items.push_back(std::string("Marketplace Deactivate")); + if (LLMarketplaceData::instance().isUpdating(mUUID,depth) || ((flags & FIRST_SELECTED_ITEM) == 0)) + { + // During SLM update, disable all marketplace related options + // Also disable all if multiple selected items + disabled_items.push_back(std::string("Marketplace Activate")); + disabled_items.push_back(std::string("Marketplace Deactivate")); + } + else + { + if (LLMarketplaceData::instance().isVersionFolder(mUUID)) + { + disabled_items.push_back(std::string("Marketplace Activate")); + if (LLMarketplaceData::instance().getActivationState(mUUID)) + { + disabled_items.push_back(std::string("Marketplace Deactivate")); + } + } + else + { + disabled_items.push_back(std::string("Marketplace Deactivate")); + } + } + } } - -#if ENABLE_MERCHANT_SEND_TO_MARKETPLACE_CONTEXT_MENU - if (isOutboxFolderDirectParent()) + + items.push_back(std::string("Marketplace Edit Listing")); + LLUUID listing_folder_id = nested_parent_id(mUUID,depth); + LLUUID version_folder_id = LLMarketplaceData::instance().getVersionFolder(listing_folder_id); + + if (depth >= 2) { - items.push_back(std::string("Marketplace Separator")); - items.push_back(std::string("Marketplace Send")); - - if (!canListOnMarketplaceNow() || (flags & FIRST_SELECTED_ITEM) == 0) + // Prevent creation of new folders if the max count has been reached on this version folder (active or not) + LLUUID local_version_folder_id = nested_parent_id(mUUID,depth-1); + LLInventoryModel::cat_array_t categories; + LLInventoryModel::item_array_t items; + gInventory.collectDescendents(local_version_folder_id, categories, items, FALSE); + if (categories.size() >= gSavedSettings.getU32("InventoryOutboxMaxFolderCount")) { - disabled_items.push_back(std::string("Marketplace Send")); + disabled_items.push_back(std::string("New Folder")); } } -#endif // ENABLE_MERCHANT_SEND_TO_MARKETPLACE_CONTEXT_MENU + + // Options available at all levels on items and categories + if (!LLMarketplaceData::instance().isListed(listing_folder_id) || version_folder_id.isNull()) + { + disabled_items.push_back(std::string("Marketplace Edit Listing")); + } + + // Separator + items.push_back(std::string("Marketplace Listings Separator")); } // *TODO: remove this @@ -932,7 +1137,7 @@ BOOL LLInvFVBridge::startDrag(EDragAndDropType* type, LLUUID* id) const } *id = obj->getUUID(); - //object_ids.put(obj->getUUID()); + //object_ids.push_back(obj->getUUID()); if (*type == DAD_CATEGORY) { @@ -959,7 +1164,13 @@ LLInventoryObject* LLInvFVBridge::getInventoryObject() const LLInventoryModel* LLInvFVBridge::getInventoryModel() const { LLInventoryPanel* panel = mInventoryPanel.get(); - return panel ? panel->getModel() : NULL; + return panel ? panel->getModel() : nullptr; +} + +LLInventoryFilter* LLInvFVBridge::getInventoryFilter() const +{ + LLInventoryPanel* panel = mInventoryPanel.get(); + return panel ? &panel->getFilter() : nullptr; } BOOL LLInvFVBridge::isItemInTrash() const @@ -1012,9 +1223,10 @@ BOOL LLInvFVBridge::isCOFFolder() const return LLAppearanceMgr::instance().getIsInCOF(mUUID); } +// *TODO : Suppress isInboxFolder() once Merchant Outbox is fully deprecated BOOL LLInvFVBridge::isInboxFolder() const { - const LLUUID inbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX, false, false); + const LLUUID inbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX, false); if (inbox_id.isNull()) { @@ -1024,39 +1236,16 @@ BOOL LLInvFVBridge::isInboxFolder() const return gInventory.isObjectDescendentOf(mUUID, inbox_id); } -BOOL LLInvFVBridge::isOutboxFolder() const +BOOL LLInvFVBridge::isMarketplaceListingsFolder() const { - const LLUUID outbox_id = getOutboxFolder(); + const LLUUID folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); - if (outbox_id.isNull()) + if (folder_id.isNull()) { return FALSE; } - return gInventory.isObjectDescendentOf(mUUID, outbox_id); -} - -BOOL LLInvFVBridge::isOutboxFolderDirectParent() const -{ - BOOL outbox_is_parent = FALSE; - - const LLInventoryCategory *cat = gInventory.getCategory(mUUID); - - if (cat) - { - const LLUUID outbox_id = getOutboxFolder(); - - outbox_is_parent = (outbox_id.notNull() && (outbox_id == cat->getParentUUID())); - } - - return outbox_is_parent; -} - -const LLUUID LLInvFVBridge::getOutboxFolder() const -{ - const LLUUID outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false, false); - - return outbox_id; + return gInventory.isObjectDescendentOf(mUUID, folder_id); } BOOL LLInvFVBridge::isItemPermissive() const @@ -1096,7 +1285,7 @@ LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type, case LLAssetType::AT_TEXTURE: if(!(inv_type == LLInventoryType::IT_TEXTURE || inv_type == LLInventoryType::IT_SNAPSHOT)) { - llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl; + LL_WARNS() << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << LL_ENDL; } new_listener = new LLTextureBridge(inventory, root, uuid, inv_type); break; @@ -1104,7 +1293,7 @@ LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type, case LLAssetType::AT_SOUND: if(!(inv_type == LLInventoryType::IT_SOUND)) { - llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl; + LL_WARNS() << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << LL_ENDL; } new_listener = new LLSoundBridge(inventory, root, uuid); break; @@ -1112,7 +1301,7 @@ LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type, case LLAssetType::AT_LANDMARK: if(!(inv_type == LLInventoryType::IT_LANDMARK)) { - llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl; + LL_WARNS() << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << LL_ENDL; } new_listener = new LLLandmarkBridge(inventory, root, uuid, flags); break; @@ -1120,7 +1309,7 @@ LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type, case LLAssetType::AT_CALLINGCARD: if(!(inv_type == LLInventoryType::IT_CALLINGCARD)) { - llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl; + LL_WARNS() << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << LL_ENDL; } new_listener = new LLCallingCardBridge(inventory, root, uuid); break; @@ -1128,7 +1317,7 @@ LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type, case LLAssetType::AT_SCRIPT: if(!(inv_type == LLInventoryType::IT_LSL)) { - llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl; + LL_WARNS() << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << LL_ENDL; } new_listener = new LLItemBridge(inventory, root, uuid); break; @@ -1138,7 +1327,7 @@ LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type, || inv_type == LLInventoryType::IT_TEXTURE ) //There's an abundance of objects in inv that have texture (0) as their inv type, right out of unpack. //May have been bug either in an old client, or server version. Either way... it causes a lot of spam over something ultimately harmless. { - llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl; + LL_WARNS() << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << LL_ENDL; } new_listener = new LLObjectBridge(inventory, root, uuid, inv_type, flags); break; @@ -1146,7 +1335,7 @@ LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type, case LLAssetType::AT_NOTECARD: if(!(inv_type == LLInventoryType::IT_NOTECARD)) { - llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl; + LL_WARNS() << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << LL_ENDL; } new_listener = new LLNotecardBridge(inventory, root, uuid); break; @@ -1154,7 +1343,7 @@ LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type, case LLAssetType::AT_ANIMATION: if(!(inv_type == LLInventoryType::IT_ANIMATION)) { - llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl; + LL_WARNS() << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << LL_ENDL; } new_listener = new LLAnimationBridge(inventory, root, uuid); break; @@ -1162,7 +1351,7 @@ LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type, case LLAssetType::AT_GESTURE: if(!(inv_type == LLInventoryType::IT_GESTURE)) { - llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl; + LL_WARNS() << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << LL_ENDL; } new_listener = new LLGestureBridge(inventory, root, uuid); break; @@ -1170,7 +1359,7 @@ LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type, case LLAssetType::AT_LSL_TEXT: if(!(inv_type == LLInventoryType::IT_LSL)) { - llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl; + LL_WARNS() << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << LL_ENDL; } new_listener = new LLLSLTextBridge(inventory, root, uuid); break; @@ -1179,18 +1368,25 @@ LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type, case LLAssetType::AT_BODYPART: if(!(inv_type == LLInventoryType::IT_WEARABLE)) { - llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl; + LL_WARNS() << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << LL_ENDL; } - new_listener = new LLWearableBridge(inventory, root, uuid, asset_type, inv_type, (LLWearableType::EType)flags); + new_listener = new LLWearableBridge(inventory, root, uuid, asset_type, inv_type, LLWearableType::inventoryFlagsToWearableType(flags)); break; case LLAssetType::AT_CATEGORY: if (actual_asset_type == LLAssetType::AT_LINK_FOLDER) { - // Create a link folder handler instead. + // Create a link folder handler instead new_listener = new LLLinkFolderBridge(inventory, root, uuid); - break; } - new_listener = new LLFolderBridge(inventory, root, uuid); + else if (actual_asset_type == LLAssetType::AT_MARKETPLACE_FOLDER) + { + // Create a marketplace folder handler + new_listener = new LLMarketplaceFolderBridge(inventory, root, uuid); + } + else + { + new_listener = new LLFolderBridge(inventory, root, uuid); + } break; case LLAssetType::AT_LINK: case LLAssetType::AT_LINK_FOLDER: @@ -1200,19 +1396,22 @@ LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type, case LLAssetType::AT_MESH: if(!(inv_type == LLInventoryType::IT_MESH)) { - llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl; + LL_WARNS() << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << LL_ENDL; } new_listener = new LLMeshBridge(inventory, root, uuid); break; case LLAssetType::AT_IMAGE_TGA: case LLAssetType::AT_IMAGE_JPEG: - //llwarns << LLAssetType::lookup(asset_type) << " asset type is unhandled for uuid " << uuid << llendl; + //LL_WARNS() << LLAssetType::lookup(asset_type) << " asset type is unhandled for uuid " << uuid << LL_ENDL; + break; + + case LLAssetType::AT_SETTINGS: break; default: - llinfos << "Unhandled asset type (llassetstorage.h): " - << (S32)asset_type << " (" << LLAssetType::lookup(asset_type) << ")" << llendl; + LL_INFOS() << "Unhandled asset type (llassetstorage.h): " + << (S32)asset_type << " (" << LLAssetType::lookup(asset_type) << ")" << LL_ENDL; break; } @@ -1226,28 +1425,62 @@ LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type, void LLInvFVBridge::purgeItem(LLInventoryModel *model, const LLUUID &uuid) { - LLInventoryCategory* cat = model->getCategory(uuid); - if (cat) - { - model->purgeDescendentsOf(uuid); - model->notifyObservers(); - } LLInventoryObject* obj = model->getObject(uuid); if (obj) { - model->purgeObject(uuid); + remove_inventory_object(uuid, NULL); + } +} + +void LLInvFVBridge::removeObject(LLInventoryModel *model, const LLUUID &uuid) +{ + // Keep track of the parent + LLInventoryItem* itemp = model->getItem(uuid); + LLUUID parent_id = (itemp ? itemp->getParentUUID() : LLUUID::null); + // Remove the object + model->removeObject(uuid); + // Get the parent updated + if (parent_id.notNull()) + { + LLViewerInventoryCategory* parent_cat = model->getCategory(parent_id); + model->updateCategory(parent_cat); model->notifyObservers(); } } +bool LLInvFVBridge::canShare() const +{ + bool can_share = false; + + if (!isItemInTrash() && isAgentInventory()) + { + const LLInventoryModel* model = getInventoryModel(); + if (model) + { + const LLViewerInventoryItem *item = model->getItem(mUUID); + if (item) + { + if (LLInventoryCollectFunctor::itemTransferCommonlyAllowed(item)) + { + can_share = LLGiveInventory::isInventoryGiveAcceptable(item); + } + } + else + { + // Categories can be given. + can_share = (model->getCategory(mUUID) != NULL); + } + } + } + + return can_share; +} bool LLInvFVBridge::canListOnMarketplace() const { -#if ENABLE_MERCHANT_OUTBOX_CONTEXT_MENU - LLInventoryModel * model = getInventoryModel(); - const LLViewerInventoryCategory * cat = model->getCategory(mUUID); + LLViewerInventoryCategory * cat = model->getCategory(mUUID); if (cat && LLFolderType::lookupIsProtectedType(cat->getPreferredType())) { return false; @@ -1258,16 +1491,6 @@ bool LLInvFVBridge::canListOnMarketplace() const return false; } - if (getOutboxFolder().isNull()) - { - return false; - } - - if (isInboxFolder() || isOutboxFolder()) - { - return false; - } - LLViewerInventoryItem * item = model->getItem(mUUID); if (item) { @@ -1283,24 +1506,12 @@ bool LLInvFVBridge::canListOnMarketplace() const } return true; - -#else - return false; -#endif } bool LLInvFVBridge::canListOnMarketplaceNow() const { -#if ENABLE_MERCHANT_OUTBOX_CONTEXT_MENU - bool can_list = true; - // Do not allow listing while import is in progress - if (LLMarketplaceInventoryImporter::instanceExists()) - { - can_list = !LLMarketplaceInventoryImporter::instance().isImportInProgress(); - } - const LLInventoryObject* obj = getInventoryObject(); can_list &= (obj != NULL); @@ -1317,37 +1528,41 @@ bool LLInvFVBridge::canListOnMarketplaceNow() const can_list = !object_folderp->isLoading(); } } - + if (can_list) { - // Get outbox id - const LLUUID & outbox_id = getInventoryModel()->findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false); - LLFolderViewItem * outbox_itemp = mRoot->getItemByID(outbox_id); - - if (outbox_itemp) + std::string error_msg; + LLInventoryModel* model = getInventoryModel(); + const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); + if (marketplacelistings_id.notNull()) { - MASK mask = 0x0; - BOOL drop = FALSE; - EDragAndDropType cargo_type = LLViewerAssetType::lookupDragAndDropType(obj->getActualType()); - void * cargo_data = (void *) obj; - - can_list = outbox_itemp->getListener()->dragOrDrop(mask, drop, cargo_type, cargo_data); + LLViewerInventoryCategory * master_folder = model->getCategory(marketplacelistings_id); + LLInventoryCategory *cat = model->getCategory(mUUID); + if (cat) + { + can_list = can_move_folder_to_marketplace(master_folder, master_folder, cat, error_msg); + } + else + { + LLInventoryItem *item = model->getItem(mUUID); + can_list = (item ? can_move_item_to_marketplace(master_folder, master_folder, item, error_msg) : false); + } + } + else + { + can_list = false; } } } - - return can_list; -#else - return false; -#endif + return can_list; } // +=================================================+ // | InventoryFVBridgeBuilder | // +=================================================+ -LLInvFVBridge* LLInventoryFVBridgeBuilder::createBridge(LLAssetType::EType asset_type, +LLInvFVBridge* LLInventoryFolderViewModelBuilder::createBridge(LLAssetType::EType asset_type, LLAssetType::EType actual_asset_type, LLInventoryType::EType inv_type, LLInventoryPanel* inventory, @@ -1415,7 +1630,6 @@ void LLItemBridge::performAction(LLInventoryModel* model, std::string action) else if ("cut" == action) { cutToClipboard(); - LLFolderView::removeCutItems(); return; } else if ("copy" == action) @@ -1458,15 +1672,18 @@ void LLItemBridge::performAction(LLInventoryModel* model, std::string action) folder_view_itemp->getListener()->pasteLinkFromClipboard(); return; } - else if (isMarketplaceCopyAction(action)) + else if (("move_to_marketplace_listings" == action) || ("copy_to_marketplace_listings" == action) || ("copy_or_move_to_marketplace_listings" == action)) { - llinfos << "Copy item to marketplace action!" << llendl; - LLInventoryItem* itemp = model->getItem(mUUID); if (!itemp) return; - - const LLUUID outbox_id = getInventoryModel()->findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false, false); - copy_item_to_outbox(itemp, outbox_id, LLUUID::null, LLToolDragAndDrop::getOperationId()); + const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); + // Note: For a single item, if it's not a copy, then it's a move + move_item_to_marketplacelistings(itemp, marketplacelistings_id, ("copy_to_marketplace_listings" == action)); + } + else if ("marketplace_edit_listing" == action) + { + std::string url = LLMarketplaceData::instance().getListingURL(mUUID); + LLUrlAction::openURL(url); } } @@ -1492,46 +1709,42 @@ void LLItemBridge::restoreItem() } } -void LLItemBridge::restoreToWorld() +void restore_to_world(LLViewerInventoryItem* itemp, bool no_copy, bool response = true) { - //Similar functionality to the drag and drop rez logic - bool remove_from_inventory = false; - - LLViewerInventoryItem* itemp = static_cast(getItem()); - if (itemp) - { - LLMessageSystem* msg = gMessageSystem; - msg->newMessage("RezRestoreToWorld"); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + if (!response) return; + LLMessageSystem* msg = gMessageSystem; + msg->newMessage("RezRestoreToWorld"); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgentID); + msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID); - msg->nextBlockFast(_PREHASH_InventoryData); - itemp->packMessage(msg); - msg->sendReliable(gAgent.getRegion()->getHost()); + msg->nextBlockFast(_PREHASH_InventoryData); + itemp->packMessage(msg); + msg->sendReliable(gAgent.getRegion()->getHost()); - //remove local inventory copy, sim will deal with permissions and removing the item - //from the actual inventory if its a no-copy etc - if(!itemp->getPermissions().allowCopyBy(gAgent.getID())) - { - remove_from_inventory = true; - } - - // Check if it's in the trash. (again similar to the normal rez logic) - const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); - if(gInventory.isObjectDescendentOf(itemp->getUUID(), trash_id)) - { - remove_from_inventory = true; - } - } - - if(remove_from_inventory) + //remove local inventory copy, sim will deal with permissions and removing the item + //from the actual inventory if it's a no-copy etc + // Check if it's in the trash. (again similar to the normal rez logic) + if (no_copy || gInventory.isObjectDescendentOf(itemp->getUUID(), gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH))) { gInventory.deleteObject(itemp->getUUID()); gInventory.notifyObservers(); } } +void LLItemBridge::restoreToWorld() +{ + if (LLViewerInventoryItem* itemp = static_cast(getItem())) + { + //Similar functionality to the drag and drop rez logic + bool no_copy = !itemp->getPermissions().allowCopyBy(gAgentID); + if (no_copy && gHippoGridManager->getCurrentGrid()->isSecondLife()) + LLNotificationsUtil::add("RezRestoreToWorld", LLSD(), LLSD(), boost::bind(restore_to_world, itemp, true, !boost::bind(LLNotification::getSelectedOption, _1, _2))); + else + restore_to_world(itemp, no_copy); + } +} + void LLItemBridge::gotoItem() { LLInventoryObject *obj = getInventoryObject(); @@ -1558,6 +1771,15 @@ LLUIImagePtr LLItemBridge::getIcon() const return LLInventoryIcon::getIcon(LLInventoryType::ICONNAME_OBJECT); } +LLUIImagePtr LLItemBridge::getIconOverlay() const +{ + if (getItem() && getItem()->getIsLinkType()) + { + return LLUI::getUIImage("inv_link_overlay.tga"); + } + return NULL; +} + PermissionMask LLItemBridge::getPermissionMask() const { LLViewerInventoryItem* item = getItem(); @@ -1566,24 +1788,15 @@ PermissionMask LLItemBridge::getPermissionMask() const return perm_mask; } -const std::string& LLItemBridge::getDisplayName() const -{ - if(mDisplayName.empty()) - { - buildDisplayName(getItem(), mDisplayName); - } - return mDisplayName; -} - -void LLItemBridge::buildDisplayName(LLInventoryItem* item, std::string& name) +void LLItemBridge::buildDisplayName() const { - if(item) + if(getItem()) { - name.assign(item->getName()); + mDisplayName.assign(getItem()->getName()); } else { - name.assign(LLStringUtil::null); + mDisplayName.assign(LLStringUtil::null); } } @@ -1594,7 +1807,7 @@ LLFontGL::StyleFlags LLItemBridge::getLabelStyle() const if (get_is_item_worn(mUUID)) { - // llinfos << "BOLD" << llendl; + // LL_INFOS() << "BOLD" << LL_ENDL; font |= LLFontGL::BOLD; } else if(item && item->getIsLinkType()) @@ -1647,9 +1860,7 @@ std::string LLItemBridge::getLabelSuffix() const suffix += NO_XFER; } - BOOL temp = item->getPermissions().getGroup() == gAgent.getID(); - - if (temp) + if (item->getPermissions().getGroup() == gAgent.getID()) { suffix += TEMPO; } @@ -1686,16 +1897,17 @@ BOOL LLItemBridge::isItemRenameable() const return FALSE; } -// [RLVa:KB] - Checked: 2011-03-29 (RLVa-1.3.0g) | Modified: RLVa-1.3.0g - if ( (rlv_handler_t::isEnabled()) && (!RlvFolderLocks::instance().canRenameItem(mUUID)) ) + if (isInboxFolder()) { return FALSE; } -// [/RLVa:KB] - if (isInboxFolder()) + +// [RLVa:KB] - Checked: 2011-03-29 (RLVa-1.3.0g) | Modified: RLVa-1.3.0g + if ( (rlv_handler_t::isEnabled()) && (!RlvFolderLocks::instance().canRenameItem(mUUID)) ) { return FALSE; } +// [/RLVa:KB] return (item->getPermissions().allowModifyBy(gAgent.getID())); } @@ -1713,13 +1925,9 @@ BOOL LLItemBridge::renameItem(const std::string& new_name) LLViewerInventoryItem* item = getItem(); if(item && (item->getName() != new_name)) { - LLPointer new_item = new LLViewerInventoryItem(item); - new_item->rename(new_name); - buildDisplayName(new_item, mDisplayName); - new_item->updateServer(FALSE); - model->updateItem(new_item); - - model->notifyObservers(); + LLSD updates; + updates["name"] = new_name; + update_inventory_item(item->getUUID(),updates, NULL); } // return FALSE because we either notified observers (& therefore // rebuilt) or we didn't update. @@ -1733,15 +1941,16 @@ BOOL LLItemBridge::removeItem() return FALSE; } - // move it to the trash - LLPreview::hide(mUUID, TRUE); LLInventoryModel* model = getInventoryModel(); if(!model) return FALSE; const LLUUID& trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH); LLViewerInventoryItem* item = getItem(); if (!item) return FALSE; - + if (item->getType() != LLAssetType::AT_LSL_TEXT) + { + LLPreview::hide(mUUID, TRUE); + } // Already in trash if (model->isObjectDescendentOf(mUUID, trash_id)) return FALSE; @@ -1755,29 +1964,18 @@ BOOL LLItemBridge::removeItem() // [SL:KB] - Patch: Inventory-Links | Checked: 2010-06-01 (Catznip-2.2.0a) | Added: Catznip-2.0.1a // Users move folders around and reuse links that way... if we know something has links then it's just bad not to warn them :| // [/SL:KB] -// if (!InventoryLinksEnabled()) + if (!item->getIsLinkType()) { - if (!item->getIsLinkType()) + LLInventoryModel::item_array_t item_array = gInventory.collectLinksTo(mUUID); + const U32 num_links = item_array.size(); + if (num_links > 0) { - LLInventoryModel::cat_array_t cat_array; - LLInventoryModel::item_array_t item_array; - LLLinkedItemIDMatches is_linked_item_match(mUUID); - gInventory.collectDescendentsIf(gInventory.getRootFolderID(), - cat_array, - item_array, - LLInventoryModel::INCLUDE_TRASH, - is_linked_item_match); - - const U32 num_links = cat_array.size() + item_array.size(); - if (num_links > 0) - { - // Warn if the user is will break any links when deleting this item. - LLNotifications::instance().add(params); - return FALSE; - } + // Warn if the user is will break any links when deleting this item. + LLNotifications::instance().add(params); + return FALSE; } } - + LLNotifications::instance().forceResponse(params, 0); return TRUE; } @@ -1835,7 +2033,7 @@ BOOL LLItemBridge::isItemCopyable() const // NOTE: we do *not* want to return TRUE on everything like LL seems to do in SL-2.1.0 because not all types are "linkable" return (item->getPermissions().allowCopyBy(gAgent.getID())) || (LLAssetType::lookupCanLink(item->getType())); // [/SL:KB] -// return item->getPermissions().allowCopyBy(gAgent.getID()) || InventoryLinksEnabled(); +// return item->getPermissions().allowCopyBy(gAgent.getID()); } return FALSE; } @@ -1873,15 +2071,46 @@ BOOL LLFolderBridge::isItemMovable() const LLInventoryObject* obj = getInventoryObject(); if(obj) { - return (!LLFolderType::lookupIsProtectedType(((LLInventoryCategory*)obj)->getPreferredType())); + // If it's a protected type folder, we can't move it + if (LLFolderType::lookupIsProtectedType(((LLInventoryCategory*)obj)->getPreferredType())) + return FALSE; + return TRUE; } return FALSE; } void LLFolderBridge::selectItem() { + // Have no fear: the first thing start() does is to test if everything for that folder has been fetched... + LLInventoryModelBackgroundFetch::instance().start(getUUID(), true); +} + +void LLFolderBridge::buildDisplayName() const +{ + mDisplayName.assign(getName()); +} + +std::string LLFolderBridge::getLabelSuffix() const +{ + /* Singu TODO? + static LLCachedControl folder_loading_message_delay(gSavedSettings, "FolderLoadingMessageWaitTime", 0.5f); + + if (mIsLoading && mTimeSinceRequestStart.getElapsedTimeF32() >= folder_loading_message_delay()) + { + return llformat(" ( %s ) ", LLTrans::getString("LoadingData").c_str()); + } + */ + + return LLInvFVBridge::getLabelSuffix(); +} + +LLFontGL::StyleFlags LLFolderBridge::getLabelStyle() const +{ + return LLFontGL::NORMAL; } + + // Iterate through a folder's children to determine if // all the children are removable. class LLIsItemRemovable : public LLFolderViewFunctor @@ -1919,6 +2148,11 @@ BOOL LLFolderBridge::isItemRemovable() const } } + if (isMarketplaceListingsFolder() && LLMarketplaceData::instance().getActivationState(mUUID)) + { + return FALSE; + } + return TRUE; } @@ -1984,15 +2218,15 @@ BOOL LLFolderBridge::isClipboardPasteable() const return FALSE; } - LLDynamicArray objects; + uuid_vec_t objects; LLInventoryClipboard::instance().retrieve(objects); const LLViewerInventoryCategory *current_cat = getCategory(); // Search for the direct descendent of current Friends subfolder among all pasted items, // and return false if is found. - for(S32 i = objects.count() - 1; i >= 0; --i) + for(S32 i = objects.size() - 1; i >= 0; --i) { - const LLUUID &obj_id = objects.get(i); + const LLUUID &obj_id = objects.at(i); if ( LLFriendCardsManager::instance().isObjDirectDescendentOfCategory(model->getObject(obj_id), current_cat) ) { return FALSE; @@ -2032,12 +2266,12 @@ BOOL LLFolderBridge::isClipboardPasteableAsLink() const const BOOL is_in_friend_folder = LLFriendCardsManager::instance().isCategoryInFriendFolder(current_cat); */ const LLUUID ¤t_cat_id = current_cat->getUUID(); - LLDynamicArray objects; + uuid_vec_t objects; LLInventoryClipboard::instance().retrieve(objects); - S32 count = objects.count(); + S32 count = objects.size(); for (S32 i = 0; i < count; i++) { - const LLUUID &obj_id = objects.get(i); + const LLUUID &obj_id = objects.at(i); const LLInventoryCategory *cat = model->getCategory(obj_id); if (cat) { @@ -2068,84 +2302,10 @@ BOOL LLFolderBridge::isClipboardPasteableAsLink() const } -static BOOL can_move_to_outbox(LLInventoryItem* inv_item) -{ - // Collapse links directly to items/folders - LLViewerInventoryItem * viewer_inv_item = (LLViewerInventoryItem *) inv_item; - LLViewerInventoryItem * linked_item = viewer_inv_item->getLinkedItem(); - if (linked_item != NULL) - { - inv_item = linked_item; - } - - bool allow_transfer = inv_item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID()); - if (!allow_transfer) - { - return false; - } - -#if BLOCK_WORN_ITEMS_IN_OUTBOX - bool worn = get_is_item_worn(inv_item->getUUID()); - if (worn) - { - return false; - } -#endif - - bool calling_card = (LLAssetType::AT_CALLINGCARD == inv_item->getType()); - if (calling_card) - { - return false; - } - - return true; -} - - -int get_folder_levels(LLInventoryCategory* inv_cat) -{ - LLInventoryModel::cat_array_t* cats; - LLInventoryModel::item_array_t* items; - gInventory.getDirectDescendentsOf(inv_cat->getUUID(), cats, items); - - int max_child_levels = 0; - - for (S32 i=0; i < cats->count(); ++i) - { - LLInventoryCategory* category = cats->get(i); - max_child_levels = llmax(max_child_levels, get_folder_levels(category)); - } - - return 1 + max_child_levels; -} - -int get_folder_path_length(const LLUUID& ancestor_id, const LLUUID& descendant_id) -{ - int depth = 0; - - if (ancestor_id == descendant_id) return depth; - - const LLInventoryCategory* category = gInventory.getCategory(descendant_id); - - while(category) - { - LLUUID parent_id = category->getParentUUID(); - - if (parent_id.isNull()) break; - - depth++; - - if (parent_id == ancestor_id) return depth; - - category = gInventory.getCategory(parent_id); - } - - llwarns << "get_folder_path_length() couldn't trace a path from the descendant to the ancestor" << llendl; - return -1; -} BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, - BOOL drop) + BOOL drop, + BOOL user_confirm) { LLInventoryModel* model = getInventoryModel(); @@ -2157,11 +2317,12 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, const LLUUID &cat_id = inv_cat->getUUID(); const LLUUID ¤t_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false); - const LLUUID &outbox_id = model->findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false); + const LLUUID& marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); + const LLUUID from_folder_uuid = inv_cat->getParentUUID(); const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id); - const BOOL move_is_into_outbox = model->isObjectDescendentOf(mUUID, outbox_id); - const BOOL move_is_from_outbox = model->isObjectDescendentOf(cat_id, outbox_id); + const BOOL move_is_into_marketplacelistings = model->isObjectDescendentOf(mUUID, marketplacelistings_id); + const BOOL move_is_from_marketplacelistings = model->isObjectDescendentOf(cat_id, marketplacelistings_id); // check to make sure source is agent inventory, and is represented there. LLToolDragAndDrop::ESource source = LLToolDragAndDrop::getInstance()->getSource(); @@ -2173,9 +2334,11 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, { const LLUUID &trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH, false); const LLUUID &landmarks_id = model->findCategoryUUIDForType(LLFolderType::FT_LANDMARK, false); + //const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false); const BOOL move_is_into_trash = (mUUID == trash_id) || model->isObjectDescendentOf(mUUID, trash_id); - const BOOL move_is_into_outfit = getCategory() && (getCategory()->getPreferredType() == LLFolderType::FT_OUTFIT); + //const BOOL move_is_into_my_outfits = (mUUID == my_outifts_id) || model->isObjectDescendentOf(mUUID, my_outifts_id); + const BOOL move_is_into_outfit = /*move_is_into_my_outfits ||*/ (getCategory() && getCategory()->getPreferredType() == LLFolderType::FT_OUTFIT); const BOOL move_is_into_landmarks = (mUUID == landmarks_id) || model->isObjectDescendentOf(mUUID, landmarks_id); //-------------------------------------------------------------------------------- @@ -2183,7 +2346,20 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, // BOOL is_movable = TRUE; + std::string tooltip_msg; + if (is_movable && (marketplacelistings_id == cat_id)) + { + is_movable = FALSE; + tooltip_msg = LLTrans::getString("TooltipOutboxCannotMoveRoot"); + } + if (is_movable && move_is_from_marketplacelistings && LLMarketplaceData::instance().getActivationState(cat_id)) + { + // If the incoming folder is listed and active (and is therefore either the listing or the version folder), + // then moving is *not* allowed + is_movable = FALSE; + tooltip_msg = LLTrans::getString("TooltipOutboxDragActive"); + } // Can't move a folder into itself if (is_movable && (mUUID == cat_id)) { @@ -2214,13 +2390,19 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, is_movable = FALSE; // tooltip? } + if (is_movable && (getPreferredType() == LLFolderType::FT_MARKETPLACE_STOCK)) + { + // One cannot move a folder into a stock folder + is_movable = FALSE; + // tooltip? + } LLInventoryModel::cat_array_t descendent_categories; LLInventoryModel::item_array_t descendent_items; if (is_movable) { model->collectDescendents(cat_id, descendent_categories, descendent_items, FALSE); - for (S32 i=0; i < descendent_categories.count(); ++i) + for (U32 i=0; i < descendent_categories.size(); ++i) { LLInventoryCategory* category = descendent_categories[i]; if(LLFolderType::lookupIsProtectedType(category->getPreferredType())) @@ -2231,9 +2413,31 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, } } } + U32 max_items_to_wear = gSavedSettings.getU32("WearFolderLimit"); + if (is_movable + && move_is_into_current_outfit + && descendent_items.size() > max_items_to_wear) + { + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + LLFindWearablesEx not_worn(/*is_worn=*/ false, /*include_body_parts=*/ false); + gInventory.collectDescendentsIf(cat_id, + cats, + items, + LLInventoryModel::EXCLUDE_TRASH, + not_worn); + + if (items.size() > max_items_to_wear) + { + // Can't move 'large' folders into current outfit: MAINT-4086 + is_movable = FALSE; + LLStringUtil::format_map_t args; + args["AMOUNT"] = llformat("%d", max_items_to_wear); + } + } if (is_movable && move_is_into_trash) { - for (S32 i=0; i < descendent_items.count(); ++i) + for (U32 i=0; i < descendent_items.size(); ++i) { LLInventoryItem* item = descendent_items[i]; if (get_is_item_worn(item->getUUID())) @@ -2245,7 +2449,7 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, } if (is_movable && move_is_into_landmarks) { - for (S32 i=0; i < descendent_items.count(); ++i) + for (U32 i=0; i < descendent_items.size(); ++i) { LLViewerInventoryItem* item = descendent_items[i]; @@ -2265,103 +2469,68 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, is_movable = RlvFolderLocks::instance().canMoveFolder(cat_id, mUUID); } // [/RLVa:KB] - if (is_movable && move_is_into_outbox) + + if (is_movable && move_is_into_marketplacelistings) { - const int nested_folder_levels = get_folder_path_length(outbox_id, mUUID) + get_folder_levels(inv_cat); - - if (nested_folder_levels > (S32)gSavedSettings.getU32("InventoryOutboxMaxFolderDepth")) - { - is_movable = FALSE; - } - else + const LLViewerInventoryCategory* master_folder = model->getFirstDescendantOf(marketplacelistings_id, mUUID); + LLViewerInventoryCategory * dest_folder = getCategory(); + S32 bundle_size = (drop ? 1 : LLToolDragAndDrop::instance().getCargoCount()); + is_movable = can_move_folder_to_marketplace(master_folder, dest_folder, inv_cat, tooltip_msg, bundle_size); + } + + // + //-------------------------------------------------------------------------------- + + accept = is_movable; + + if (accept && drop) + { + // Dropping in or out of marketplace needs (sometimes) confirmation + if (user_confirm && (move_is_from_marketplacelistings || move_is_into_marketplacelistings)) { - int dragged_folder_count = descendent_categories.count(); - int existing_item_count = 0; - int existing_folder_count = 0; - - const LLViewerInventoryCategory * master_folder = model->getFirstDescendantOf(outbox_id, mUUID); - - if (master_folder != NULL) + if (move_is_from_marketplacelistings && (LLMarketplaceData::instance().isInActiveFolder(cat_id) || + LLMarketplaceData::instance().isListedAndActive(cat_id))) { - if (model->isObjectDescendentOf(cat_id, master_folder->getUUID())) + if (LLMarketplaceData::instance().isListed(cat_id) || LLMarketplaceData::instance().isVersionFolder(cat_id)) { - // Don't use count because we're already inside the same category anyway - dragged_folder_count = 0; + // Move the active version folder or listing folder itself outside marketplace listings will unlist the listing so ask that question specifically + LLNotificationsUtil::add("ConfirmMerchantUnlist", LLSD(), LLSD(), boost::bind(&LLFolderBridge::callback_dropCategoryIntoFolder, this, _1, _2, inv_cat)); } else { - existing_folder_count = 1; // Include the master folder in the count! - - // If we're in the drop operation as opposed to the drag without drop, we are doing a - // single category at a time so don't block based on the total amount of cargo data items - if (drop) - { - dragged_folder_count += 1; - } - else - { - // NOTE: The cargo id's count is a total of categories AND items but we err on the side of - // prevention rather than letting too many folders into the hierarchy of the outbox, - // when we're dragging the item to a new parent - dragged_folder_count += LLToolDragAndDrop::instance().getCargoIDsCount(); - } + // Any other case will simply modify but not unlist an active listed listing + LLNotificationsUtil::add("ConfirmMerchantActiveChange", LLSD(), LLSD(), boost::bind(&LLFolderBridge::callback_dropCategoryIntoFolder, this, _1, _2, inv_cat)); } - - // Tally the total number of categories and items inside the master folder - - LLInventoryModel::cat_array_t existing_categories; - LLInventoryModel::item_array_t existing_items; - - model->collectDescendents(master_folder->getUUID(), existing_categories, existing_items, FALSE); - - existing_folder_count += existing_categories.count(); - existing_item_count += existing_items.count(); + return true; } - else + if (move_is_from_marketplacelistings && LLMarketplaceData::instance().isVersionFolder(cat_id)) { - // Assume a single category is being dragged to the outbox since we evaluate one at a time - // when not putting them under a parent item. - dragged_folder_count += 1; + // Moving the version folder from its location will deactivate it. Ask confirmation. + LLNotificationsUtil::add("ConfirmMerchantClearVersion", LLSD(), LLSD(), boost::bind(&LLFolderBridge::callback_dropCategoryIntoFolder, this, _1, _2, inv_cat)); + return true; } - - const int nested_folder_count = existing_folder_count + dragged_folder_count; - const int nested_item_count = existing_item_count + descendent_items.count(); - - if (nested_folder_count > (S32)gSavedSettings.getU32("InventoryOutboxMaxFolderCount")) + if (move_is_into_marketplacelistings && LLMarketplaceData::instance().isInActiveFolder(mUUID)) { - is_movable = FALSE; + // Moving something in an active listed listing will modify it. Ask confirmation. + LLNotificationsUtil::add("ConfirmMerchantActiveChange", LLSD(), LLSD(), boost::bind(&LLFolderBridge::callback_dropCategoryIntoFolder, this, _1, _2, inv_cat)); + return true; } - else if (nested_item_count > (S32)gSavedSettings.getU32("InventoryOutboxMaxItemCount")) + if (move_is_from_marketplacelistings && LLMarketplaceData::instance().isListed(cat_id)) { - is_movable = FALSE; + // Moving a whole listing folder will result in archival of SLM data. Ask confirmation. + LLNotificationsUtil::add("ConfirmListingCutOrDelete", LLSD(), LLSD(), boost::bind(&LLFolderBridge::callback_dropCategoryIntoFolder, this, _1, _2, inv_cat)); + return true; } - - if (is_movable == TRUE) + if (move_is_into_marketplacelistings && !move_is_from_marketplacelistings) { - for (S32 i=0; i < descendent_items.count(); ++i) - { - LLInventoryItem* item = descendent_items[i]; - if (!can_move_to_outbox(item)) - { - is_movable = FALSE; - break; - } - } + LLNotificationsUtil::add("ConfirmMerchantMoveInventory", LLSD(), LLSD(), boost::bind(&LLFolderBridge::callback_dropCategoryIntoFolder, this, _1, _2, inv_cat)); + return true; } } - } - - // - //-------------------------------------------------------------------------------- - - accept = is_movable; - - if (accept && drop) - { // Look for any gestures and deactivate them if (move_is_into_trash) { - for (S32 i=0; i < descendent_items.count(); i++) + for (U32 i=0; i < descendent_items.size(); i++) { LLInventoryItem* item = descendent_items[i]; if (item->getType() == LLAssetType::AT_GESTURE @@ -2371,6 +2540,7 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, } } } + // if target is an outfit or current outfit folder we use link if (move_is_into_current_outfit || move_is_into_outfit) { @@ -2388,40 +2558,22 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, LLInventoryModel::cat_array_t cats; LLInventoryModel::item_array_t items; model->collectDescendents(cat_id, cats, items, LLInventoryModel::EXCLUDE_TRASH); - LLAppearanceMgr::instance().linkAll(mUUID,items,NULL); - } - } - else - { -#if SUPPORT_ENSEMBLES - // BAP - should skip if dup. - if (move_is_into_current_outfit) - { - LLAppearanceMgr::instance().addEnsembleLink(inv_cat); - } - else - { - LLPointer cb = NULL; - const std::string empty_description = ""; - link_inventory_item( - gAgent.getID(), - cat_id, - mUUID, - inv_cat->getName(), - empty_description, - LLAssetType::AT_LINK_FOLDER, - cb); + LLInventoryObject::const_object_list_t citems; + for (LLPointer item : items) + { + citems.push_back(item.get()); + } + link_inventory_array(mUUID, citems, NULL); } -#endif } } - else if (move_is_into_outbox && !move_is_from_outbox) + else if (move_is_into_marketplacelistings) { - copy_folder_to_outbox(inv_cat, mUUID, cat_id, LLToolDragAndDrop::getOperationId()); + move_folder_to_marketplacelistings(inv_cat, mUUID); } else { - if (model->isObjectDescendentOf(cat_id, model->findCategoryUUIDForType(LLFolderType::FT_INBOX, false, false))) + if (model->isObjectDescendentOf(cat_id, model->findCategoryUUIDForType(LLFolderType::FT_INBOX, false))) { set_dad_inbox_object(cat_id); } @@ -2434,11 +2586,38 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, mUUID, move_is_into_trash); } + if (move_is_from_marketplacelistings) + { + // If we are moving a folder at the listing folder level (i.e. its parent is the marketplace listings folder) + if (from_folder_uuid == marketplacelistings_id) + { + // Clear the folder from the marketplace in case it is a listing folder + if (LLMarketplaceData::instance().isListed(cat_id)) + { + LLMarketplaceData::instance().clearListing(cat_id); + } + } + else + { + // If we move from within an active (listed) listing, check that it's still valid, if not, unlist + LLUUID version_folder_id = LLMarketplaceData::instance().getActiveFolder(from_folder_uuid); + if (version_folder_id.notNull()) + { + LLViewerInventoryCategory* cat = gInventory.getCategory(version_folder_id); + if (!validate_marketplacelistings(cat, NULL)) + { + LLMarketplaceData::instance().activateListing(version_folder_id,false); + } + } + // In all cases, update the listing we moved from so suffix are updated + update_marketplace_category(from_folder_uuid); + } + } } } else if (LLToolDragAndDrop::SOURCE_WORLD == source) { - if (move_is_into_outbox) + if (move_is_into_marketplacelistings) { accept = FALSE; } @@ -2449,7 +2628,7 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, } else if (LLToolDragAndDrop::SOURCE_LIBRARY == source) { - if (move_is_into_outbox) + if (move_is_into_marketplacelistings) { accept = FALSE; } @@ -2497,7 +2676,7 @@ BOOL move_inv_category_world_to_agent(const LLUUID& object_id, LLViewerObject* object = gObjectList.findObject(object_id); if(!object) { - llinfos << "Object not found for drop." << llendl; + LL_INFOS() << "Object not found for drop." << LL_ENDL; return FALSE; } @@ -2508,11 +2687,11 @@ BOOL move_inv_category_world_to_agent(const LLUUID& object_id, if (inventory_objects.empty()) { - llinfos << "Object contents not found for drop." << llendl; + LL_INFOS() << "Object contents not found for drop." << LL_ENDL; return FALSE; } - BOOL accept = TRUE; + BOOL accept = FALSE; BOOL is_move = FALSE; // coming from a task. Need to figure out if the person can @@ -2524,7 +2703,7 @@ BOOL move_inv_category_world_to_agent(const LLUUID& object_id, LLInventoryItem* item = dynamic_cast(it->get()); if (!item) { - llwarns << "Invalid inventory item for drop" << llendl; + LL_WARNS() << "Invalid inventory item for drop" << LL_ENDL; continue; } @@ -2545,9 +2724,9 @@ BOOL move_inv_category_world_to_agent(const LLUUID& object_id, is_move = TRUE; accept = TRUE; } - else + + if (!accept) { - accept = FALSE; break; } } @@ -2587,10 +2766,9 @@ void LLRightClickInventoryFetchDescendentsObserver::execute(bool clear_observer) // Bail out immediately if no descendents if( mComplete.empty() ) { - llwarns << "LLRightClickInventoryFetchDescendentsObserver::done with empty mCompleteFolders" << llendl; + LL_WARNS() << "LLRightClickInventoryFetchDescendentsObserver::done with empty mCompleteFolders" << LL_ENDL; if (clear_observer) { - dec_busy_count(); gInventory.removeObserver(this); delete this; } @@ -2604,7 +2782,6 @@ void LLRightClickInventoryFetchDescendentsObserver::execute(bool clear_observer) // could notify observers and throw us into an infinite loop. if (clear_observer) { - dec_busy_count(); gInventory.removeObserver(this); delete this; } @@ -2616,8 +2793,17 @@ void LLRightClickInventoryFetchDescendentsObserver::execute(bool clear_observer) LLInventoryModel::item_array_t* item_array; gInventory.getDirectDescendentsOf(*current_folder, cat_array, item_array); - S32 item_count = item_array->count(); - S32 cat_count = cat_array->count(); + S32 item_count(0); + if (item_array) + { + item_count = item_array->size(); + } + + S32 cat_count(0); + if (cat_array) + { + cat_count = cat_array->size(); + } // Move to next if current folder empty if ((item_count == 0) && (cat_count == 0)) @@ -2634,7 +2820,7 @@ void LLRightClickInventoryFetchDescendentsObserver::execute(bool clear_observer) { for (S32 i = 0; i < item_count; ++i) { - ids.push_back(item_array->get(i)->getUUID()); + ids.push_back(item_array->at(i)->getUUID()); } outfit = new LLRightClickInventoryFetchObserver(ids); } @@ -2643,7 +2829,7 @@ void LLRightClickInventoryFetchDescendentsObserver::execute(bool clear_observer) { for (S32 i = 0; i < cat_count; ++i) { - ids.push_back(cat_array->get(i)->getUUID()); + ids.push_back(cat_array->at(i)->getUUID()); } categories = new LLRightClickInventoryFetchDescendentsObserver(ids); } @@ -2666,7 +2852,6 @@ void LLRightClickInventoryFetchDescendentsObserver::execute(bool clear_observer) { // it's all on its way - add an observer, and the inventory // will call done for us when everything is here. - inc_busy_count(); gInventory.addObserver(outfit); } */ @@ -2685,7 +2870,6 @@ void LLRightClickInventoryFetchDescendentsObserver::execute(bool clear_observer) { // it's all on its way - add an observer, and the inventory // will call done for us when everything is here. - inc_busy_count(); gInventory.addObserver(categories); } } @@ -2702,8 +2886,8 @@ void LLRightClickInventoryFetchDescendentsObserver::execute(bool clear_observer) class LLInventoryCopyAndWearObserver : public LLInventoryObserver { public: - LLInventoryCopyAndWearObserver(const LLUUID& cat_id, int count, bool folder_added=false) : - mCatID(cat_id), mContentsCount(count), mFolderAdded(folder_added) {} + LLInventoryCopyAndWearObserver(const LLUUID& cat_id, int count, bool folder_added=false, bool replace=false) : + mCatID(cat_id), mContentsCount(count), mFolderAdded(folder_added), mReplace(replace){} virtual ~LLInventoryCopyAndWearObserver() {} virtual void changed(U32 mask); @@ -2711,6 +2895,7 @@ class LLInventoryCopyAndWearObserver : public LLInventoryObserver LLUUID mCatID; int mContentsCount; bool mFolderAdded; + bool mReplace; }; @@ -2721,10 +2906,10 @@ void LLInventoryCopyAndWearObserver::changed(U32 mask) { if (!mFolderAdded) { - const std::set& changed_items = gInventory.getChangedIDs(); + const uuid_set_t& changed_items = gInventory.getChangedIDs(); - std::set::const_iterator id_it = changed_items.begin(); - std::set::const_iterator id_end = changed_items.end(); + auto id_it = changed_items.begin(); + auto id_end = changed_items.end(); for (;id_it != id_end; ++id_it) { if ((*id_it) == mCatID) @@ -2740,8 +2925,8 @@ void LLInventoryCopyAndWearObserver::changed(U32 mask) LLViewerInventoryCategory* category = gInventory.getCategory(mCatID); if (NULL == category) { - llwarns << "gInventory.getCategory(" << mCatID - << ") was NULL" << llendl; + LL_WARNS() << "gInventory.getCategory(" << mCatID + << ") was NULL" << LL_ENDL; } else { @@ -2749,7 +2934,7 @@ void LLInventoryCopyAndWearObserver::changed(U32 mask) mContentsCount) { gInventory.removeObserver(this); - LLAppearanceMgr::instance().wearInventoryCategory(category, FALSE, FALSE); + LLAppearanceMgr::instance().wearInventoryCategory(category, FALSE, !mReplace); delete this; } } @@ -2777,7 +2962,13 @@ void LLFolderBridge::performAction(LLInventoryModel* model, std::string action) LLInventoryModel* model = getInventoryModel(); LLViewerInventoryCategory* cat = getCategory(); if (!model || !cat) return; - LFFloaterInvPanel::show(mUUID, model, cat->getName()); + LFFloaterInvPanel::show(LLSD().with("id", mUUID), cat->getName(), model); + return; + } + else if ("copy_folder_uuid" == action) + { + // Single folder only + gViewerWindow->getWindow()->copyTextToClipboard(utf8str_to_wstring(mUUID.asString())); return; } else if ("paste" == action) @@ -2813,7 +3004,6 @@ void LLFolderBridge::performAction(LLInventoryModel* model, std::string action) else if ("cut" == action) { cutToClipboard(); - LLFolderView::removeCutItems(); return; } else if ("copy" == action) @@ -2832,7 +3022,7 @@ void LLFolderBridge::performAction(LLInventoryModel* model, std::string action) LLViewerInventoryCategory* cat = getCategory(); if(!cat) return; - remove_inventory_category_from_avatar( cat ); + LLAppearanceMgr::instance().takeOffOutfit( cat->getLinkedUUID() ); return; } else if ("purge" == action) @@ -2845,49 +3035,179 @@ void LLFolderBridge::performAction(LLInventoryModel* model, std::string action) restoreItem(); return; } -#ifdef DELETE_SYSTEM_FOLDERS - else if ("delete_system_folder" == action) + else if ("marketplace_list" == action) { - removeSystemFolder(); + if (depth_nesting_in_marketplace(mUUID) == 1) + { + LLUUID version_folder_id = LLMarketplaceData::instance().getVersionFolder(mUUID); + LLViewerInventoryCategory* cat = gInventory.getCategory(version_folder_id); + mMessage = ""; + if (!validate_marketplacelistings(cat, boost::bind(&LLFolderBridge::gatherMessage, this, _1, _2, _3))) + { + LLSD subs; + subs["[ERROR_CODE]"] = mMessage; + LLNotificationsUtil::add("MerchantListingFailed", subs); + } + else + { + LLMarketplaceData::instance().activateListing(mUUID,true); + } + } + return; } -#endif - else if (isMarketplaceCopyAction(action)) - { - llinfos << "Copy folder to marketplace action!" << llendl; - - LLInventoryCategory * cat = gInventory.getCategory(mUUID); - if (!cat) return; - - const LLUUID outbox_id = getInventoryModel()->findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false, false); - copy_folder_to_outbox(cat, outbox_id, cat->getUUID(), LLToolDragAndDrop::getOperationId()); + else if ("marketplace_activate" == action) + { + if (depth_nesting_in_marketplace(mUUID) == 2) + { + LLInventoryCategory* category = gInventory.getCategory(mUUID); + mMessage = ""; + if (!validate_marketplacelistings(category,boost::bind(&LLFolderBridge::gatherMessage, this, _1, _2, _3),false,2)) + { + LLSD subs; + subs["[ERROR_CODE]"] = mMessage; + LLNotificationsUtil::add("MerchantFolderActivationFailed", subs); + } + else + { + LLMarketplaceData::instance().setVersionFolder(category->getParentUUID(), mUUID); + } + } + return; } -#if ENABLE_MERCHANT_SEND_TO_MARKETPLACE_CONTEXT_MENU - else if (isMarketplaceSendAction(action)) + else if ("marketplace_unlist" == action) { - llinfos << "Send to marketplace action!" << llendl; - - /*LLInventoryCategory * cat = gInventory.getCategory(mUUID); - if (!cat) return; - - send_to_marketplace(cat);*/ - LLMarketplaceInventoryImporter::instance().triggerImport(); + if (depth_nesting_in_marketplace(mUUID) == 1) + { + LLMarketplaceData::instance().activateListing(mUUID, false,1); + } + return; } -#endif // ENABLE_MERCHANT_SEND_TO_MARKETPLACE_CONTEXT_MENU -} - -void LLFolderBridge::openItem() -{ - lldebugs << "LLFolderBridge::openItem()" << llendl; - LLInventoryModel* model = getInventoryModel(); - if(!model) return; - if(mUUID.isNull()) return; - bool fetching_inventory = model->fetchDescendentsOf(mUUID); - // Only change folder type if we have the folder contents. - if (!fetching_inventory) + else if ("marketplace_deactivate" == action) { - // Disabling this for now, it's causing crash when new items are added to folders - // since folder type may change before new item item has finished processing. - // determineFolderType(); + if (depth_nesting_in_marketplace(mUUID) == 2) + { + LLInventoryCategory* category = gInventory.getCategory(mUUID); + LLMarketplaceData::instance().setVersionFolder(category->getParentUUID(), LLUUID::null, 1); + } + return; + } + else if ("marketplace_create_listing" == action) + { + LLViewerInventoryCategory* cat = gInventory.getCategory(mUUID); + mMessage = ""; + bool validates = validate_marketplacelistings(cat,boost::bind(&LLFolderBridge::gatherMessage, this, _1, _2, _3),false); + if (!validates) + { + mMessage = ""; + validates = validate_marketplacelistings(cat,boost::bind(&LLFolderBridge::gatherMessage, this, _1, _2, _3),true); + if (validates) + { + LLNotificationsUtil::add("MerchantForceValidateListing"); + } + } + + if (!validates) + { + LLSD subs; + subs["[ERROR_CODE]"] = mMessage; + LLNotificationsUtil::add("MerchantListingFailed", subs); + } + else + { + LLMarketplaceData::instance().createListing(mUUID); + } + return; + } + else if ("marketplace_disassociate_listing" == action) + { + LLMarketplaceData::instance().clearListing(mUUID); + return; + } + else if ("marketplace_get_listing" == action) + { + // This is used only to exercise the SLM API but won't be shown to end users + LLMarketplaceData::instance().getListing(mUUID); + return; + } + else if ("marketplace_associate_listing" == action) + { + LLFloaterAssociateListing::showInstance(mUUID); + return; + } + else if ("marketplace_check_listing" == action) + { + LLSD data(mUUID); + new LLFloaterMarketplaceValidation(data); // new.. but floaters clean themselves up. + return; + } + else if ("marketplace_edit_listing" == action) + { + std::string url = LLMarketplaceData::instance().getListingURL(mUUID); + if (!url.empty()) + { + LLUrlAction::openURL(url); + } + return; + } + else if ("marketplace_copy_id" == action) + { + auto id = LLMarketplaceData::instance().getListingID(mUUID); + gViewerWindow->getWindow()->copyTextToClipboard(utf8str_to_wstring(fmt::to_string(id))); + } + // Move displaced inventory to lost and found + else if ("move_to_lost_and_found" == action) + { + gInventory.changeCategoryParent(getCategory(), gInventory.findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND), TRUE); + gInventory.addChangedMask(LLInventoryObserver::REBUILD, mUUID); + gInventory.notifyObservers(); + } + // +#ifdef DELETE_SYSTEM_FOLDERS + else if ("delete_system_folder" == action) + { + removeSystemFolder(); + } +#endif + else if (("move_to_marketplace_listings" == action) || ("copy_to_marketplace_listings" == action) || ("copy_or_move_to_marketplace_listings" == action)) + { + LLInventoryCategory * cat = gInventory.getCategory(mUUID); + if (!cat) return; + const LLUUID &marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); + move_folder_to_marketplacelistings(cat, marketplacelistings_id, ("move_to_marketplace_listings" != action), (("copy_or_move_to_marketplace_listings" == action))); + } +} + +void LLFolderBridge::gatherMessage(std::string& message, S32 depth, LLError::ELevel log_level) +{ + if (log_level >= LLError::LEVEL_ERROR) + { + if (!mMessage.empty()) + { + // Currently, we do not gather all messages as it creates very long alerts + // Users can get to the whole list of errors on a listing using the "Check for Errors" audit button or "Check listing" right click menu + //mMessage += "\n"; + return; + } + // Take the leading spaces out... + std::string::size_type start = message.find_first_not_of(" "); + // Append the message + mMessage += message.substr(start, message.length() - start); + } +} + +void LLFolderBridge::openItem() +{ + LL_DEBUGS() << "LLFolderBridge::openItem()" << LL_ENDL; + LLInventoryModel* model = getInventoryModel(); + if(!model) return; + if(mUUID.isNull()) return; + bool fetching_inventory = model->fetchDescendentsOf(mUUID); + // Only change folder type if we have the folder contents. + if (!fetching_inventory) + { + // Disabling this for now, it's causing crash when new items are added to folders + // since folder type may change before new item item has finished processing. + // determineFolderType(); } } @@ -2942,32 +3262,47 @@ LLFolderType::EType LLFolderBridge::getPreferredType() const // Icons for folders are based on the preferred type LLUIImagePtr LLFolderBridge::getIcon() const { - LLFolderType::EType preferred_type = LLFolderType::FT_NONE; - LLViewerInventoryCategory* cat = getCategory(); - if(cat) + return getFolderIcon(FALSE); +} + +LLUIImagePtr LLFolderBridge::getIconOpen() const +{ + return getFolderIcon(TRUE); +} + +LLUIImagePtr LLFolderBridge::getFolderIcon(BOOL is_open) const +{ + LLFolderType::EType preferred_type = getPreferredType(); + S32 depth = depth_nesting_in_marketplace(mUUID); + if ((preferred_type == LLFolderType::FT_NONE) && (depth == 2)) { - preferred_type = cat->getPreferredType(); + // We override the type when in the marketplace listings folder and only for version folder + preferred_type = LLFolderType::FT_MARKETPLACE_VERSION; } - return getIcon(preferred_type); + return LLUI::getUIImage(LLViewerFolderType::lookupIconName(preferred_type, is_open)); } -// static +// static : use by LLLinkFolderBridge to get the closed type icons LLUIImagePtr LLFolderBridge::getIcon(LLFolderType::EType preferred_type) { return LLUI::getUIImage(LLViewerFolderType::lookupIconName(preferred_type, FALSE)); - /*case LLAssetType::AT_MESH: - control = "inv_folder_mesh.tga"; - break;*/ } -LLUIImagePtr LLFolderBridge::getOpenIcon() const +LLUIImagePtr LLFolderBridge::getIconOverlay() const { - return LLUI::getUIImage(LLViewerFolderType::lookupIconName(getPreferredType(), TRUE)); - + if (getInventoryObject() && getInventoryObject()->getIsLinkType()) + { + return LLUI::getUIImage("inv_link_overlay.tga"); + } + return NULL; } BOOL LLFolderBridge::renameItem(const std::string& new_name) { + + LLScrollOnRenameObserver *observer = new LLScrollOnRenameObserver(mUUID, mRoot); + gInventory.addObserver(observer); + rename_category(getInventoryModel(), mUUID, new_name); // return FALSE because we either notified observers (& therefore @@ -3032,52 +3367,114 @@ bool LLFolderBridge::removeItemResponse(const LLSD& notification, const LLSD& re void LLFolderBridge::pasteFromClipboard(bool only_copies) { LLInventoryModel* model = getInventoryModel(); - if(model && isClipboardPasteable()) + if (model && isClipboardPasteable()) + { + const LLUUID& marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); + const BOOL paste_into_marketplacelistings = model->isObjectDescendentOf(mUUID, marketplacelistings_id); + + BOOL cut_from_marketplacelistings = FALSE; + const auto& clipboard(LLInventoryClipboard::instance()); + if (clipboard.isCutMode()) + { + //Items are not removed from folder on "cut", so we need update listing folder on "paste" operation + uuid_vec_t objects; + clipboard.retrieve(objects); + for (auto iter = objects.begin(); iter != objects.end(); ++iter) + { + const LLUUID& item_id = (*iter); + if(gInventory.isObjectDescendentOf(item_id, marketplacelistings_id) && (LLMarketplaceData::instance().isInActiveFolder(item_id) || + LLMarketplaceData::instance().isListedAndActive(item_id))) + { + cut_from_marketplacelistings = TRUE; + break; + } + } + } + if (cut_from_marketplacelistings || (paste_into_marketplacelistings && !LLMarketplaceData::instance().isListed(mUUID) && LLMarketplaceData::instance().isInActiveFolder(mUUID))) + { + // Prompt the user if pasting in a marketplace active version listing (note that pasting right under the listing folder root doesn't need a prompt) + LLNotificationsUtil::add("ConfirmMerchantActiveChange", LLSD(), LLSD(), boost::bind(&LLFolderBridge::callback_pasteFromClipboard, this, _1, _2, only_copies)); + } + else + { + // Otherwise just do the paste + perform_pasteFromClipboard(only_copies); + } + } +} + +// Callback for pasteFromClipboard if DAMA required... +void LLFolderBridge::callback_pasteFromClipboard(const LLSD& notification, const LLSD& response, bool only_copies) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option == 0) // YES + { + perform_pasteFromClipboard(only_copies); + } +} + +void LLFolderBridge::perform_pasteFromClipboard(bool only_copies) +{ + LLInventoryModel* model = getInventoryModel(); + if (model && isClipboardPasteable()) { const LLUUID ¤t_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false); - const LLUUID &outbox_id = model->findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false); + const LLUUID& marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); + const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false); const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id); - const BOOL move_is_into_outfit = (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT); - const BOOL move_is_into_outbox = model->isObjectDescendentOf(mUUID, outbox_id); + const BOOL move_is_into_my_outfits = (mUUID == my_outifts_id) || model->isObjectDescendentOf(mUUID, my_outifts_id); + const BOOL move_is_into_outfit = move_is_into_my_outfits || (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT); + const BOOL move_is_into_marketplacelistings = model->isObjectDescendentOf(mUUID, marketplacelistings_id); - LLDynamicArray objects; + uuid_vec_t objects; LLInventoryClipboard::instance().retrieve(objects); - if (move_is_into_outbox) + LLViewerInventoryCategory* dest_folder = getCategory(); + if (move_is_into_marketplacelistings) { - LLFolderViewItem * outbox_itemp = mRoot->getItemByID(mUUID); - - if (outbox_itemp) + std::string error_msg; + const LLViewerInventoryCategory* master_folder = model->getFirstDescendantOf(marketplacelistings_id, mUUID); + int index = 0; + for (auto iter = objects.begin(); iter != objects.end(); ++iter) { - //LLToolDragAndDrop::instance().setCargoCount(objects.size()); + const LLUUID& item_id = (*iter); + LLInventoryItem *item = model->getItem(item_id); + LLInventoryCategory *cat = model->getCategory(item_id); - BOOL can_list = TRUE; - - for (LLDynamicArray::const_iterator iter = objects.begin(); - (iter != objects.end()) && (can_list == TRUE); - ++iter) + if (item && !can_move_item_to_marketplace(master_folder, dest_folder, item, error_msg, objects.size() - index, true)) { - const LLUUID& item_id = (*iter); - LLInventoryItem *item = model->getItem(item_id); - - if (item) - { - MASK mask = 0x0; - BOOL drop = FALSE; - EDragAndDropType cargo_type = LLViewerAssetType::lookupDragAndDropType(item->getActualType()); - void * cargo_data = (void *) item; - //std::string tooltip_msg; - - can_list = outbox_itemp->getListener()->dragOrDrop(mask, drop, cargo_type, cargo_data/*, tooltip_msg*/); - } + break; } + if (cat && !can_move_folder_to_marketplace(master_folder, dest_folder, cat, error_msg, objects.size() - index, true, true)) + { + break; + } + ++index; + } + if (!error_msg.empty()) + { + LLSD subs; + subs["[ERROR_CODE]"] = error_msg; + LLNotificationsUtil::add("MerchantPasteFailed", subs); + return; + } + } + else + { + // Check that all items can be moved into that folder : for the moment, only stock folder mismatch is checked + for (auto iter = objects.begin(); iter != objects.end(); ++iter) + { + const LLUUID& item_id = (*iter); + LLInventoryItem *item = model->getItem(item_id); + LLInventoryCategory *cat = model->getCategory(item_id); - //LLToolDragAndDrop::instance().resetCargoCount(); - - if (can_list == FALSE) + if ((item && !dest_folder->acceptItem(item)) || (cat && (dest_folder->getPreferredType() == LLFolderType::FT_MARKETPLACE_STOCK))) { - // Notify user of failure somehow -- play error sound? modal dialog? + std::string error_msg = LLTrans::getString("TooltipOutboxMixedStock"); + LLSD subs; + subs["[ERROR_CODE]"] = error_msg; + LLNotificationsUtil::add("StockPasteFailed", subs); return; } } @@ -3085,7 +3482,7 @@ void LLFolderBridge::pasteFromClipboard(bool only_copies) const LLUUID parent_id(mUUID); - for (LLDynamicArray::const_iterator iter = objects.begin(); + for (auto iter = objects.begin(); iter != objects.end(); ++iter) { @@ -3097,7 +3494,7 @@ void LLFolderBridge::pasteFromClipboard(bool only_copies) { if (move_is_into_current_outfit || move_is_into_outfit) { - if (can_move_to_outfit(item, move_is_into_current_outfit)) + if (item && can_move_to_outfit(item, move_is_into_current_outfit)) { dropToOutfit(item, move_is_into_current_outfit); } @@ -3108,11 +3505,24 @@ void LLFolderBridge::pasteFromClipboard(bool only_copies) // move_inventory_item() is not enough, as we have to update inventory locally too if (LLAssetType::AT_CATEGORY == obj->getType()) { - LLViewerInventoryCategory* vicat = (LLViewerInventoryCategory *) model->getCategory(item_id); + LLViewerInventoryCategory* vicat = (LLViewerInventoryCategory *)model->getCategory(item_id); llassert(vicat); if (vicat) { - changeCategoryParent(model, vicat, parent_id, FALSE); + // Clear the cut folder from the marketplace if it is a listing folder + if (LLMarketplaceData::instance().isListed(item_id)) + { + LLMarketplaceData::instance().clearListing(item_id); + } + if (move_is_into_marketplacelistings) + { + move_folder_to_marketplacelistings(vicat, parent_id); + } + else + { + //changeCategoryParent() implicitly calls dirtyFilter + changeCategoryParent(model, vicat, parent_id, FALSE); + } } } else @@ -3121,7 +3531,19 @@ void LLFolderBridge::pasteFromClipboard(bool only_copies) llassert(viitem); if (viitem) { - changeItemParent(model, viitem, parent_id, FALSE); + if (move_is_into_marketplacelistings) + { + if (!move_item_to_marketplacelistings(viitem, parent_id)) + { + // Stop pasting into the marketplace as soon as we get an error + break; + } + } + else + { + //changeItemParent() implicitly calls dirtyFilter + changeItemParent(model, viitem, parent_id, FALSE); + } } } } @@ -3135,35 +3557,54 @@ void LLFolderBridge::pasteFromClipboard(bool only_copies) // Do a "copy" to "paste" a regular copy clipboard if (LLAssetType::AT_CATEGORY == obj->getType()) { - LLViewerInventoryCategory* vicat = (LLViewerInventoryCategory *) model->getCategory(item_id); + LLViewerInventoryCategory* vicat = (LLViewerInventoryCategory *)model->getCategory(item_id); llassert(vicat); if (vicat) { - copy_inventory_category(model, vicat, parent_id); + if (move_is_into_marketplacelistings) + { + move_folder_to_marketplacelistings(vicat, parent_id, true); + } + else + { + copy_inventory_category(model, vicat, parent_id); + } } } -// [SL:KB] - Patch: Inventory-Links | Checked: 2010-04-12 (Catznip-2.2.0a) | Added: Catznip-2.0.0a - else if (!only_copies && LLAssetType::lookupIsLinkType(item->getActualType())) + // [SL:KB] - Patch: Inventory-Links | Checked: 2010-04-12 (Catznip-2.2.0a) | Added: Catznip-2.0.0a + else if (!move_is_into_marketplacelistings && !only_copies && LLAssetType::lookupIsLinkType(item->getActualType())) { - link_inventory_item( - gAgent.getID(), - item->getLinkedUUID(), + link_inventory_object( parent_id, - item->getName(), - item->getDescription(), - item->getActualType(), - LLPointer(NULL)); + item, + NULL); } -// [/SL:KB] + // [/SL:KB] else { - copy_inventory_item( - gAgent.getID(), - item->getPermissions().getOwner(), - item->getUUID(), - parent_id, - std::string(), - LLPointer(NULL)); + LLViewerInventoryItem* viitem = dynamic_cast(item); + llassert(viitem); + if (viitem) + { + if (move_is_into_marketplacelistings) + { + if (!move_item_to_marketplacelistings(viitem, parent_id, true)) + { + // Stop pasting into the marketplace as soon as we get an error + break; + } + } + else + { + copy_inventory_item( + gAgent.getID(), + item->getPermissions().getOwner(), + item->getUUID(), + parent_id, + std::string(), + LLPointer(NULL)); + } + } } } } @@ -3179,13 +3620,15 @@ void LLFolderBridge::pasteLinkFromClipboard() if(model) { const LLUUID ¤t_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false); - const LLUUID &outbox_id = model->findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false); + const LLUUID& marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); + const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false); const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id); - const BOOL move_is_into_outfit = (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT); - const BOOL move_is_into_outbox = model->isObjectDescendentOf(mUUID, outbox_id); + const BOOL move_is_into_my_outfits = (mUUID == my_outifts_id) || model->isObjectDescendentOf(mUUID, my_outifts_id); + const BOOL move_is_into_outfit = move_is_into_my_outfits || (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT); + const BOOL move_is_into_marketplacelistings = model->isObjectDescendentOf(mUUID, marketplacelistings_id); - if (move_is_into_outbox) + if (move_is_into_marketplacelistings) { // Notify user of failure somehow -- play error sound? modal dialog? return; @@ -3193,9 +3636,9 @@ void LLFolderBridge::pasteLinkFromClipboard() const LLUUID parent_id(mUUID); - LLDynamicArray objects; + uuid_vec_t objects; LLInventoryClipboard::instance().retrieve(objects); - for (LLDynamicArray::const_iterator iter = objects.begin(); + for (auto iter = objects.begin(); iter != objects.end(); ++iter) { @@ -3208,28 +3651,9 @@ void LLFolderBridge::pasteLinkFromClipboard() dropToOutfit(item, move_is_into_current_outfit); } } - else if (LLInventoryCategory *cat = model->getCategory(object_id)) + else if (LLConstPointer obj = model->getObject(object_id)) { - const std::string empty_description = ""; - link_inventory_item( - gAgent.getID(), - cat->getUUID(), - parent_id, - cat->getName(), - empty_description, - LLAssetType::AT_LINK_FOLDER, - LLPointer(NULL)); - } - else if (LLInventoryItem *item = model->getItem(object_id)) - { - link_inventory_item( - gAgent.getID(), - item->getLinkedUUID(), - parent_id, - item->getName(), - item->getDescription(), - LLAssetType::AT_LINK, - LLPointer(NULL)); + link_inventory_object(parent_id, obj, LLPointer(NULL)); } } //Singu Note: Don't setCutMode(false) here, we can link now but real paste later. @@ -3246,7 +3670,7 @@ void LLFolderBridge::staticFolderOptionsMenu() } } -BOOL LLFolderBridge::checkFolderForContentsOfType(LLInventoryModel* model, LLInventoryCollectFunctor& is_type) +BOOL checkFolderForContentsOfType(LLInventoryModel* model, LLInventoryCollectFunctor& is_type, const LLUUID& mUUID) { LLInventoryModel::cat_array_t cat_array; LLInventoryModel::item_array_t item_array; @@ -3254,90 +3678,120 @@ BOOL LLFolderBridge::checkFolderForContentsOfType(LLInventoryModel* model, LLInv cat_array, item_array, LLInventoryModel::EXCLUDE_TRASH, - is_type); - return ((item_array.count() > 0) ? TRUE : FALSE ); + is_type, + true); + return ((item_array.size() > 0) ? TRUE : FALSE ); +} +BOOL LLFolderBridge::checkFolderForContentsOfType(LLInventoryModel* model, LLInventoryCollectFunctor& is_type) +{ + return ::checkFolderForContentsOfType(model, is_type, mUUID); } -void LLFolderBridge::buildContextMenuBaseOptions(U32 flags) +void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items, menuentry_vec_t& disabled_items) { LLInventoryModel* model = getInventoryModel(); llassert(model != NULL); - const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH); - const LLUUID lost_and_found_id = model->findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); - -// [RLVa:KB] - Checked: 2009-07-10 (RLVa-1.0.0g) - // Fixes LL bug - mItems.clear(); - mDisabledItems.clear(); -// [/RLVa:KB] + const LLUUID& trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH); + const LLUUID& lost_and_found_id = model->findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); + const LLUUID& marketplace_listings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); if (lost_and_found_id == mUUID) { // This is the lost+found folder. - mItems.push_back(std::string("Empty Lost And Found")); + items.push_back(std::string("Empty Lost And Found")); - mDisabledItems.push_back(std::string("New Folder")); - mDisabledItems.push_back(std::string("New Script")); - mDisabledItems.push_back(std::string("New Note")); - mDisabledItems.push_back(std::string("New Gesture")); - mDisabledItems.push_back(std::string("New Clothes")); - mDisabledItems.push_back(std::string("New Body Parts")); + disabled_items.push_back(std::string("New Folder")); + disabled_items.push_back(std::string("New Script")); + disabled_items.push_back(std::string("New Note")); + disabled_items.push_back(std::string("New Gesture")); + disabled_items.push_back(std::string("New Clothes")); + disabled_items.push_back(std::string("New Body Parts")); + } + if (isMarketplaceListingsFolder()) + { + addMarketplaceContextMenuOptions(flags, items, disabled_items); + if (LLMarketplaceData::instance().isUpdating(mUUID)) + { + disabled_items.push_back(std::string("New Folder")); + disabled_items.push_back(std::string("Rename")); + disabled_items.push_back(std::string("Cut")); + disabled_items.push_back(std::string("Copy")); + disabled_items.push_back(std::string("Paste")); + disabled_items.push_back(std::string("Delete")); + } + } + if (getPreferredType() == LLFolderType::FT_MARKETPLACE_STOCK) + { + disabled_items.push_back(std::string("New Folder")); + disabled_items.push_back(std::string("New Script")); + disabled_items.push_back(std::string("New Note")); + disabled_items.push_back(std::string("New Gesture")); + disabled_items.push_back(std::string("New Clothes")); + disabled_items.push_back(std::string("New Body Parts")); + } + if (marketplace_listings_id == mUUID) + { + disabled_items.push_back(std::string("New Folder")); + disabled_items.push_back(std::string("Rename")); + disabled_items.push_back(std::string("Cut")); + disabled_items.push_back(std::string("Delete")); } if(trash_id == mUUID) { // This is the trash. - mItems.push_back(std::string("Empty Trash")); + items.push_back(std::string("Empty Trash")); } else if(isItemInTrash()) { // This is a folder in the trash. - mItems.clear(); // clear any items that used to exist - addTrashContextMenuOptions(mItems, mDisabledItems); - } - else if(isOutboxFolder()) - { - addOutboxContextMenuOptions(flags, mItems, mDisabledItems); + items.clear(); // clear any items that used to exist + addTrashContextMenuOptions(items, disabled_items); } else if(isAgentInventory()) // do not allow creating in library { LLViewerInventoryCategory *cat = getCategory(); // BAP removed protected check to re-enable standard ops in untyped folders. // Not sure what the right thing is to do here. - if (!isCOFFolder() && cat && (cat->getPreferredType() != LLFolderType::FT_OUTFIT)) + const bool is_cof(isCOFFolder()); + if (!is_cof && cat && (cat->getPreferredType() != LLFolderType::FT_OUTFIT)) { - LLInventoryPanel* panel = mInventoryPanel.get(); - if(panel && !panel->getFilterWorn()) - if (!isInboxFolder() && !isOutboxFolder()) // don't allow creation in inbox or outbox + if (!isInboxFolder()) // don't allow creation in inbox { - mItems.push_back(std::string("New Folder")); - mItems.push_back(std::string("New Script")); - mItems.push_back(std::string("New Note")); - mItems.push_back(std::string("New Gesture")); - mItems.push_back(std::string("New Clothes")); - mItems.push_back(std::string("New Body Parts")); + { + items.push_back(std::string("New Folder")); + } + if (!isMarketplaceListingsFolder()) + { + items.push_back(std::string("New Folder")); + items.push_back(std::string("New Script")); + items.push_back(std::string("New Note")); + items.push_back(std::string("New Gesture")); + items.push_back(std::string("New Clothes")); + items.push_back(std::string("New Body Parts")); + } } - - getClipboardEntries(false, mItems, mDisabledItems, flags); + getClipboardEntries(false, items, disabled_items, flags); } else { // Want some but not all of the items from getClipboardEntries for outfits. if (cat && (cat->getPreferredType() == LLFolderType::FT_OUTFIT)) { - mItems.push_back(std::string("Rename")); + items.push_back(std::string("Rename")); - addDeleteContextMenuOptions(mItems, mDisabledItems); + addDeleteContextMenuOptions(items, disabled_items); // EXT-4030: disallow deletion of currently worn outfit const LLViewerInventoryItem *base_outfit_link = LLAppearanceMgr::instance().getBaseOutfitLink(); if (base_outfit_link && (cat == base_outfit_link->getLinkedCategory())) { - mDisabledItems.push_back(std::string("Delete")); + disabled_items.push_back(std::string("Delete")); } } } + if (!is_cof) getClipboardEntries(false, items, disabled_items, flags); - //Added by spatters to force inventory pull on right-click to display folder options correctly. 07-17-06 + //Added by aura to force inventory pull on right-click to display folder options correctly. 07-17-06 mCallingCards = mWearables = FALSE; LLIsType is_callingcard(LLAssetType::AT_CALLINGCARD); @@ -3357,35 +3811,104 @@ void LLFolderBridge::buildContextMenuBaseOptions(U32 flags) mWearables=TRUE; } } + // Move displaced inventory to lost and found + else if (!isAgentInventory()) + { + const LLUUID& library(gInventory.getLibraryRootFolderID()); + if (library != mUUID && !gInventory.isObjectDescendentOf(mUUID, library)) + items.push_back(std::string("Move to Lost And Found")); + } + // // Preemptively disable system folder removal if more than one item selected. if ((flags & FIRST_SELECTED_ITEM) == 0) { - mDisabledItems.push_back(std::string("Delete System Folder")); + disabled_items.push_back(std::string("Delete System Folder")); + } + + if (!isMarketplaceListingsFolder() && !isItemInTrash()) // + { + items.push_back(std::string("Share")); + if (!canShare()) + { + disabled_items.push_back(std::string("Share")); + } + } + + // Add menu items that are dependent on the contents of the folder. + LLViewerInventoryCategory* category = (LLViewerInventoryCategory *) model->getCategory(mUUID); + if (category && (marketplace_listings_id != mUUID)) + { + uuid_vec_t folders; + folders.push_back(category->getUUID()); + + sSelf = getHandle(); + LLRightClickInventoryFetchDescendentsObserver* fetch = new LLRightClickInventoryFetchDescendentsObserver(folders); + fetch->startFetch(); + if (fetch->isFinished()) + { + // Do not call execute() or done() here as if the folder is here, there's likely no point drilling down + // This saves lots of time as buildContextMenu() is called a lot + delete fetch; + buildContextMenuFolderOptions(flags, items, disabled_items); + } + else + { + // it's all on its way - add an observer, and the inventory will call done for us when everything is here. + gInventory.addObserver(fetch); } } +} -void LLFolderBridge::buildContextMenuFolderOptions(U32 flags) +void LLFolderBridge::buildContextMenuFolderOptions(U32 flags, menuentry_vec_t& items, menuentry_vec_t& disabled_items) { // Build folder specific options back up LLInventoryModel* model = getInventoryModel(); + + if (!isAgentInventory()) return; + + build_context_menu_folder_options(model, mUUID, items, disabled_items); + + if (!isItemRemovable()) + { + disabled_items.push_back(std::string("Delete")); + } + +#ifdef DELETE_SYSTEM_FOLDERS + if (LLFolderType::lookupIsProtectedType(type)) + { + mItems.push_back(std::string("Delete System Folder")); + } +#endif +} + +void build_context_menu_folder_options(LLInventoryModel* model, const LLUUID& mUUID, menuentry_vec_t& items, menuentry_vec_t& disabled_items) +{ if(!model) return; const LLInventoryCategory* category = model->getCategory(mUUID); if(!category) return; + items.push_back(std::string("Open Folder In New Window")); + items.push_back(std::string("Copy Folder UUID")); + const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH); if (trash_id == mUUID) return; - if (isItemInTrash()) return; - if (!isAgentInventory()) return; - if (isOutboxFolder()) return; + if (model->isObjectDescendentOf(mUUID, trash_id)) return; - mItems.push_back(std::string("Open Folder In New Window")); + if (!get_is_item_removable(model, mUUID)) + { + disabled_items.push_back(std::string("Delete")); + } + + // copied from ::isMarketplaceListingsFolder + const LLUUID listings_folder = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); + if (listings_folder.notNull() && gInventory.isObjectDescendentOf(mUUID, listings_folder)) return; LLFolderType::EType type = category->getPreferredType(); const bool is_system_folder = LLFolderType::lookupIsProtectedType(type); // calling card related functionality for folders. -// [SL:KB] - Patch: Appearance-Misc | Checked: 2010-11-24 (Catznip-3.0.0a) | Added: Catznip-2.4.0e +// [SL:KB] - Patch: Appearance-Misc | Checked: 2010-11-24 (Catznip-2.4) const bool is_outfit = (type == LLFolderType::FT_OUTFIT); // [/SL:KB] @@ -3393,67 +3916,59 @@ void LLFolderBridge::buildContextMenuFolderOptions(U32 flags) if (!is_system_folder) { LLIsType is_callingcard(LLAssetType::AT_CALLINGCARD); - if (mCallingCards || checkFolderForContentsOfType(model, is_callingcard)) + if (/*mCallingCards ||*/ checkFolderForContentsOfType(model, is_callingcard, mUUID)) { - mItems.push_back(std::string("Calling Card Separator")); - mItems.push_back(std::string("Conference Chat Folder")); - mItems.push_back(std::string("IM All Contacts In Folder")); + items.push_back(std::string("Calling Card Separator")); + items.push_back(std::string("Conference Chat Folder")); + items.push_back(std::string("IM All Contacts In Folder")); } } - if (!isItemRemovable()) - { - mDisabledItems.push_back(std::string("Delete")); - } - -#ifdef DELETE_SYSTEM_FOLDERS - if (LLFolderType::lookupIsProtectedType(type)) - { - mItems.push_back(std::string("Delete System Folder")); - } -#endif - // wearables related functionality for folders. //is_wearable LLFindWearables is_wearable; LLIsType is_object( LLAssetType::AT_OBJECT ); LLIsType is_gesture( LLAssetType::AT_GESTURE ); - if (mWearables || - checkFolderForContentsOfType(model, is_wearable) || - checkFolderForContentsOfType(model, is_object) || - checkFolderForContentsOfType(model, is_gesture) ) + if (/*mWearables ||*/ + checkFolderForContentsOfType(model, is_wearable, mUUID) || + checkFolderForContentsOfType(model, is_object, mUUID) || + checkFolderForContentsOfType(model, is_gesture, mUUID) ) { - mItems.push_back(std::string("Folder Wearables Separator")); + items.push_back(std::string("Folder Wearables Separator")); // Only enable add/replace outfit for non-system folders. if (!is_system_folder) { - if (InventoryLinksEnabled() && // Adding an outfit onto another (versus replacing) doesn't make sense. - type != LLFolderType::FT_OUTFIT) + // Actually, it does make a bit of sense, in some cases. + //if(!is_outfit) { - mItems.push_back(std::string("Add To Outfit")); + items.push_back(std::string("Add To Outfit")); } - else if(!InventoryLinksEnabled()) - mItems.push_back(std::string("Wearable And Object Wear")); + //items.push_back(std::string("Wearable And Object Wear")); - mItems.push_back(std::string("Replace Outfit")); + items.push_back(std::string("Replace Outfit")); } - mItems.push_back(std::string("Remove From Outfit")); + items.push_back(std::string("Replace Remove Separator")); + items.push_back(std::string("Remove From Outfit")); if (!LLAppearanceMgr::getCanRemoveFromCOF(mUUID)) { - mDisabledItems.push_back(std::string("Remove From Outfit")); + disabled_items.push_back(std::string("Remove From Outfit")); } // if (!LLAppearanceMgr::instance().getCanReplaceCOF(mUUID)) -// [SL:KB] - Patch: Appearance-Misc | Checked: 2010-11-24 (Catznip-3.0.0a) | Added: Catznip-2.4.0e +// [SL:KB] - Patch: Appearance-Misc | Checked: 2010-11-24 (Catznip-2.4) if ( ((is_outfit) && (!LLAppearanceMgr::instance().getCanReplaceCOF(mUUID))) || ((!is_outfit) && (gAgentWearables.isCOFChangeInProgress())) ) // [/SL:KB] { - mDisabledItems.push_back(std::string("Replace Outfit")); + disabled_items.push_back(std::string("Replace Outfit")); + } + if (!LLAppearanceMgr::instance().getCanAddToCOF(mUUID)) + { + disabled_items.push_back(std::string("Add To Outfit")); } - mItems.push_back(std::string("Outfit Separator")); + items.push_back(std::string("Outfit Separator")); } } @@ -3462,49 +3977,28 @@ void LLFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { sSelf.markDead(); - mItems.clear(); - mDisabledItems.clear(); + // fetch contents of this folder, as context menu can depend on contents + // still, user would have to open context menu again to see the changes + gInventory.fetchDescendentsOf(getUUID()); - lldebugs << "LLFolderBridge::buildContextMenu()" << llendl; - LLInventoryModel* model = getInventoryModel(); - if(!model) return; - - buildContextMenuBaseOptions(flags); + menuentry_vec_t items; + menuentry_vec_t disabled_items; - // Add menu items that are dependent on the contents of the folder. - LLViewerInventoryCategory* category = (LLViewerInventoryCategory *) model->getCategory(mUUID); - if (category) - { - uuid_vec_t folders; - folders.push_back(category->getUUID()); + LL_DEBUGS() << "LLFolderBridge::buildContextMenu()" << LL_ENDL; - sSelf = getHandle(); - LLRightClickInventoryFetchDescendentsObserver* fetch = new LLRightClickInventoryFetchDescendentsObserver(folders); - fetch->startFetch(); - if (fetch->isFinished()) - { - // Do not call execute() or done() here as if the folder is here, there's likely no point drilling down - // This saves lots of time as buildContextMenu() is called a lot - delete fetch; - buildContextMenuFolderOptions(flags); - } - else - { - // it's all on its way - add an observer, and the inventory will call done for us when everything is here. - inc_busy_count(); - gInventory.addObserver(fetch); - } - } + LLInventoryModel* model = getInventoryModel(); + if(!model) return; - hide_context_entries(menu, mItems, mDisabledItems); + buildContextMenuOptions(flags, items, disabled_items); + hide_context_entries(menu, items, disabled_items); // Reposition the menu, in case we're adding items to an existing menu. menu.needsArrange(); menu.arrangeAndClear(); } -BOOL LLFolderBridge::hasChildren() const +bool LLFolderBridge::hasChildren() const { LLInventoryModel* model = getInventoryModel(); if(!model) return FALSE; @@ -3519,7 +4013,7 @@ BOOL LLFolderBridge::dragOrDrop(MASK mask, BOOL drop, { LLInventoryItem* inv_item = (LLInventoryItem*)cargo_data; - //llinfos << "LLFolderBridge::dragOrDrop()" << llendl; + //LL_INFOS() << "LLFolderBridge::dragOrDrop()" << LL_ENDL; BOOL accept = FALSE; switch(cargo_type) { @@ -3541,6 +4035,7 @@ BOOL LLFolderBridge::dragOrDrop(MASK mask, BOOL drop, // DAD_LINK type might mean one of two asset types: AT_LINK or AT_LINK_FOLDER. // If we have an item of AT_LINK_FOLDER type we should process the linked // category being dragged or dropped into folder. + /* Note: No, we shouldn't, this behavior is misleading, just copy the link as usual. if (inv_item && LLAssetType::AT_LINK_FOLDER == inv_item->getActualType()) { LLInventoryCategory* linked_category = gInventory.getCategory(inv_item->getLinkedUUID()); @@ -3550,6 +4045,7 @@ BOOL LLFolderBridge::dragOrDrop(MASK mask, BOOL drop, } } else + */ { accept = dragItemIntoFolder(inv_item, drop); } @@ -3560,7 +4056,7 @@ BOOL LLFolderBridge::dragOrDrop(MASK mask, BOOL drop, case DAD_NONE: break; default: - llwarns << "Unhandled cargo type for drag&drop " << cargo_type << llendl; + LL_WARNS() << "Unhandled cargo type for drag&drop " << cargo_type << LL_ENDL; break; } return accept; @@ -3701,6 +4197,124 @@ void LLFolderBridge::modifyOutfit(BOOL append/*, BOOL replace*/) LLAppearanceMgr::instance().wearInventoryCategory( cat, FALSE, append ); } + +// +=================================================+ +// | LLMarketplaceFolderBridge | +// +=================================================+ + +// LLMarketplaceFolderBridge is a specialized LLFolderBridge for use in Marketplace Inventory panels +LLMarketplaceFolderBridge::LLMarketplaceFolderBridge(LLInventoryPanel* inventory, + LLFolderView* root, + const LLUUID& uuid) : +LLFolderBridge(inventory, root, uuid) +{ + m_depth = depth_nesting_in_marketplace(mUUID); + m_stockCountCache = COMPUTE_STOCK_NOT_EVALUATED; +} + +LLUIImagePtr LLMarketplaceFolderBridge::getIcon() const +{ + return getMarketplaceFolderIcon(FALSE); +} + +LLUIImagePtr LLMarketplaceFolderBridge::getIconOpen() const +{ + return getMarketplaceFolderIcon(TRUE); +} + +LLUIImagePtr LLMarketplaceFolderBridge::getMarketplaceFolderIcon(BOOL is_open) const +{ + LLFolderType::EType preferred_type = getPreferredType(); + if (!LLMarketplaceData::instance().isUpdating(getUUID())) + { + // Skip computation (expensive) if we're waiting for updates. Use the old value in that case. + m_depth = depth_nesting_in_marketplace(mUUID); + } + if ((preferred_type == LLFolderType::FT_NONE) && (m_depth == 2)) + { + // We override the type when in the marketplace listings folder and only for version folder + preferred_type = LLFolderType::FT_MARKETPLACE_VERSION; + } + return LLUI::getUIImage(LLViewerFolderType::lookupIconName(preferred_type, is_open)); +} + +std::string LLMarketplaceFolderBridge::getLabelSuffix() const +{ + /* Singu TODO? + static LLCachedControl folder_loading_message_delay(gSavedSettings, "FolderLoadingMessageWaitTime", 0.5f); + + if (mIsLoading && mTimeSinceRequestStart.getElapsedTimeF32() >= folder_loading_message_delay()) + { + return llformat(" ( %s ) ", LLTrans::getString("LoadingData").c_str()); + } + */ + + std::string suffix = ""; + // Listing folder case + if (LLMarketplaceData::instance().isListed(getUUID())) + { + suffix = llformat("%d",LLMarketplaceData::instance().getListingID(getUUID())); + if (suffix.empty()) + { + suffix = LLTrans::getString("MarketplaceNoID"); + } + suffix = " (" + suffix + ")"; + if (LLMarketplaceData::instance().getActivationState(getUUID())) + { + suffix += " (" + LLTrans::getString("MarketplaceLive") + ")"; + } + } + // Version folder case + else if (LLMarketplaceData::instance().isVersionFolder(getUUID())) + { + suffix += " (" + LLTrans::getString("MarketplaceActive") + ")"; + } + // Add stock amount + bool updating = LLMarketplaceData::instance().isUpdating(getUUID()); + if (!updating) + { + // Skip computation (expensive) if we're waiting for update anyway. Use the old value in that case. + m_stockCountCache = compute_stock_count(getUUID()); + } + if (m_stockCountCache == 0) + { + suffix += " (" + LLTrans::getString("MarketplaceNoStock") + ")"; + } + else if (m_stockCountCache != COMPUTE_STOCK_INFINITE) + { + if (getPreferredType() == LLFolderType::FT_MARKETPLACE_STOCK) + { + suffix += " (" + LLTrans::getString("MarketplaceStock"); + } + else + { + suffix += " (" + LLTrans::getString("MarketplaceMax"); + } + if (m_stockCountCache == COMPUTE_STOCK_NOT_EVALUATED) + { + suffix += "=" + LLTrans::getString("MarketplaceUpdating") + ")"; + } + else + { + suffix += "=" + llformat("%d", m_stockCountCache) + ")"; + } + } + // Add updating suffix + if (updating) + { + suffix += " (" + LLTrans::getString("MarketplaceUpdating") + ")"; + } + return LLInvFVBridge::getLabelSuffix() + suffix; +} + +LLFontGL::StyleFlags LLMarketplaceFolderBridge::getLabelStyle() const +{ + return (LLMarketplaceData::instance().getActivationState(getUUID()) ? LLFontGL::BOLD : LLFontGL::NORMAL); +} + + + + // helper stuff bool move_task_inventory_callback(const LLSD& notification, const LLSD& response, LLMoveInv* move_inv) { @@ -3710,12 +4324,13 @@ bool move_task_inventory_callback(const LLSD& notification, const LLSD& response if(option == 0 && object) { - if (cat_and_wear && cat_and_wear->mWear) + if (cat_and_wear && cat_and_wear->mWear) // && !cat_and_wear->mFolderResponded) { LLInventoryObject::object_list_t inventory_objects; object->getInventoryContents(inventory_objects); int contents_count = inventory_objects.size()-1; //subtract one for containing folder - LLInventoryCopyAndWearObserver* inventoryObserver = new LLInventoryCopyAndWearObserver(cat_and_wear->mCatID, contents_count, cat_and_wear->mFolderResponded); + LLInventoryCopyAndWearObserver* inventoryObserver = new LLInventoryCopyAndWearObserver(cat_and_wear->mCatID, contents_count, cat_and_wear->mFolderResponded, + cat_and_wear->mReplace); gInventory.addObserver(inventoryObserver); } @@ -3752,6 +4367,12 @@ static BOOL can_move_to_outfit(LLInventoryItem* inv_item, BOOL move_is_into_curr return FALSE; } + U32 flags = inv_item->getFlags(); + if(flags & LLInventoryItemFlags::II_FLAGS_OBJECT_HAS_MULTIPLE_ITEMS) + { + return FALSE; + } + if (move_is_into_current_outfit && get_is_item_worn(inv_item->getUUID())) { return FALSE; @@ -3808,15 +4429,30 @@ void LLFolderBridge::dropToOutfit(LLInventoryItem* inv_item, BOOL move_is_into_c } else { - LLPointer cb = NULL; - link_inventory_item( - gAgent.getID(), - inv_item->getLinkedUUID(), - mUUID, - inv_item->getName(), - inv_item->getDescription(), - LLAssetType::AT_LINK, - cb); + LLPointer cb = nullptr; + link_inventory_object(mUUID, LLConstPointer(inv_item), cb); + } +} + +// Callback for drop item if DAMA required... +void LLFolderBridge::callback_dropItemIntoFolder(const LLSD& notification, const LLSD& response, LLInventoryItem* inv_item) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option == 0) // YES + { + //std::string tooltip_msg; + dragItemIntoFolder(inv_item, TRUE, /*tooltip_msg,*/ FALSE); + } +} + +// Callback for drop category if DAMA required... +void LLFolderBridge::callback_dropCategoryIntoFolder(const LLSD& notification, const LLSD& response, LLInventoryCategory* inv_category) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option == 0) // YES + { + //std::string tooltip_msg; + dragCategoryIntoFolder(inv_category, TRUE, /*tooltip_msg,*/ FALSE); } } @@ -3824,7 +4460,8 @@ void LLFolderBridge::dropToOutfit(LLInventoryItem* inv_item, BOOL move_is_into_c // into the folder, as well as performing the actual drop, depending // if drop == TRUE. BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, - BOOL drop) + BOOL drop, + BOOL user_confirm) { LLInventoryModel* model = getInventoryModel(); @@ -3835,17 +4472,23 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, LLInventoryPanel* destination_panel = mInventoryPanel.get(); if (!destination_panel) return false; + LLInventoryFilter* filter = getInventoryFilter(); + if (!filter) return false; + const LLUUID ¤t_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false); const LLUUID &favorites_id = model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE, false); const LLUUID &landmarks_id = model->findCategoryUUIDForType(LLFolderType::FT_LANDMARK, false); - const LLUUID &outbox_id = model->findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false); + const LLUUID& marketplacelistings_id = model->findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); + const LLUUID &my_outifts_id = model->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS, false); + const LLUUID from_folder_uuid = inv_item->getParentUUID(); const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id); const BOOL move_is_into_favorites = (mUUID == favorites_id); - const BOOL move_is_into_outfit = (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT); + const BOOL move_is_into_my_outfits = (mUUID == my_outifts_id) || model->isObjectDescendentOf(mUUID, my_outifts_id); + const BOOL move_is_into_outfit = move_is_into_my_outfits || (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT); const BOOL move_is_into_landmarks = (mUUID == landmarks_id) || model->isObjectDescendentOf(mUUID, landmarks_id); - const BOOL move_is_into_outbox = model->isObjectDescendentOf(mUUID, outbox_id); //(mUUID == outbox_id); - const BOOL move_is_from_outbox = model->isObjectDescendentOf(inv_item->getUUID(), outbox_id); + const BOOL move_is_into_marketplacelistings = model->isObjectDescendentOf(mUUID, marketplacelistings_id); + const BOOL move_is_from_marketplacelistings = model->isObjectDescendentOf(inv_item->getUUID(), marketplacelistings_id); LLToolDragAndDrop::ESource source = LLToolDragAndDrop::getInstance()->getSource(); BOOL accept = FALSE; @@ -3865,10 +4508,6 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, switch (inv_item->getActualType()) { - //case LLFolderType::FT_ROOT_CATEGORY: - // is_movable = FALSE; - // break; - case LLAssetType::AT_CATEGORY: is_movable = !LLFolderType::lookupIsProtectedType(((LLInventoryCategory*)inv_item)->getPreferredType()); break; @@ -3919,57 +4558,46 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, //-------------------------------------------------------------------------------- // Determine if item can be moved & dropped - // + // Note: if user_confirm is false, we already went through those accept logic test and can skip them accept = TRUE; - if (!is_movable) + if (user_confirm && !is_movable) { accept = FALSE; } - else if ((mUUID == inv_item->getParentUUID()) && !move_is_into_favorites) + else if (user_confirm && (mUUID == inv_item->getParentUUID()) && !move_is_into_favorites) { accept = FALSE; } - else if (move_is_into_current_outfit || move_is_into_outfit) + else if (user_confirm && (move_is_into_current_outfit || move_is_into_outfit)) { accept = can_move_to_outfit(inv_item, move_is_into_current_outfit); } - else if (move_is_into_favorites || move_is_into_landmarks) + else if (user_confirm && (/*move_is_into_favorites ||*/ move_is_into_landmarks)) { accept = can_move_to_landmarks(inv_item); } - else if (move_is_into_outbox) + else if (user_confirm && move_is_into_marketplacelistings) { - accept = can_move_to_outbox(inv_item); - - if (accept) - { - const LLViewerInventoryCategory * master_folder = model->getFirstDescendantOf(outbox_id, mUUID); - - int existing_item_count = LLToolDragAndDrop::instance().getCargoIDsCount(); - - if (master_folder != NULL) - { - LLInventoryModel::cat_array_t existing_categories; - LLInventoryModel::item_array_t existing_items; - - gInventory.collectDescendents(master_folder->getUUID(), existing_categories, existing_items, FALSE); - - existing_item_count += existing_items.count(); - } - - if (existing_item_count > (S32)gSavedSettings.getU32("InventoryOutboxMaxItemCount")) - { - accept = FALSE; - } - } + const LLViewerInventoryCategory* master_folder = model->getFirstDescendantOf(marketplacelistings_id, mUUID); + LLViewerInventoryCategory* dest_folder = getCategory(); + std::string tooltip_msg; + accept = can_move_item_to_marketplace(master_folder, dest_folder, inv_item, tooltip_msg, LLToolDragAndDrop::instance().getCargoCount() - LLToolDragAndDrop::instance().getCargoIndex()); + } + + // Check that the folder can accept this item based on folder/item type compatibility (e.g. stock folder compatibility) + if (user_confirm && accept) + { + LLViewerInventoryCategory * dest_folder = getCategory(); + accept = dest_folder->acceptItem(inv_item); } LLInventoryPanel* active_panel = LLInventoryPanel::getActiveInventoryPanel(FALSE); // Check whether the item being dragged from active inventory panel - if (accept && active_panel) + // passes the filter of the destination panel. + if (user_confirm && accept && active_panel) { LLFolderView* active_folder_view = active_panel->getRootFolder(); if (!active_folder_view) return false; @@ -3984,16 +4612,33 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, } // If an item is being dragged between windows, unselect everything in the active window // so that we don't follow the selection to its new location (which is very annoying). + // RN: a better solution would be to deselect automatically when an item is moved + // and then select any item that is dropped only in the panel that it is dropped in if (active_panel && (destination_panel != active_panel)) { - active_panel->unSelectAll(); + active_panel->unSelectAll(); + } + // Dropping in or out of marketplace needs (sometimes) confirmation + if (user_confirm && (move_is_from_marketplacelistings || move_is_into_marketplacelistings)) + { + if ((move_is_from_marketplacelistings && (LLMarketplaceData::instance().isInActiveFolder(inv_item->getUUID()) + || LLMarketplaceData::instance().isListedAndActive(inv_item->getUUID()))) || + (move_is_into_marketplacelistings && LLMarketplaceData::instance().isInActiveFolder(mUUID))) + { + LLNotificationsUtil::add("ConfirmMerchantActiveChange", LLSD(), LLSD(), boost::bind(&LLFolderBridge::callback_dropItemIntoFolder, this, _1, _2, inv_item)); + return true; + } + if (move_is_into_marketplacelistings && !move_is_from_marketplacelistings) + { + LLNotificationsUtil::add("ConfirmMerchantMoveInventory", LLSD(), LLSD(), boost::bind(&LLFolderBridge::callback_dropItemIntoFolder, this, _1, _2, inv_item)); + return true; + } } //-------------------------------------------------------------------------------- // Destination folder logic // - /* Singu TODO: Favorites // REORDER // (only reorder the item in Favorites folder) if ((mUUID == inv_item->getParentUUID()) && move_is_into_favorites) @@ -4003,13 +4648,13 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, { LLUUID srcItemId = inv_item->getUUID(); LLUUID destItemId = itemp->getListener()->getUUID(); - gInventory.rearrangeFavoriteLandmarks(srcItemId, destItemId); + LLFavoritesOrderStorage::instance().rearrangeFavoriteLandmarks(srcItemId, destItemId); } } // FAVORITES folder // (copy the item) - else */if (move_is_into_favorites) + else if (move_is_into_favorites) { dropToFavorites(inv_item); } @@ -4019,23 +4664,18 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, { dropToOutfit(inv_item, move_is_into_current_outfit); } - else if (move_is_into_outbox) + // MARKETPLACE LISTINGS folder + // Move the item + else if (move_is_into_marketplacelistings) { - if (move_is_from_outbox) - { - move_item_within_outbox(inv_item, mUUID, LLToolDragAndDrop::getOperationId()); - } - else - { - copy_item_to_outbox(inv_item, mUUID, LLUUID::null, LLToolDragAndDrop::getOperationId()); - } + move_item_to_marketplacelistings(inv_item, mUUID); } // NORMAL or TRASH folder // (move the item, restamp if into trash) else { // set up observer to select item once drag and drop from inbox is complete - if (gInventory.isObjectDescendentOf(inv_item->getUUID(), gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX, false, false))) + if (gInventory.isObjectDescendentOf(inv_item->getUUID(), gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX, false))) { set_dad_inbox_object(inv_item->getUUID()); } @@ -4047,7 +4687,21 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, move_is_into_trash); } - // + if (move_is_from_marketplacelistings) + { + // If we move from an active (listed) listing, checks that it's still valid, if not, unlist + LLUUID version_folder_id = LLMarketplaceData::instance().getActiveFolder(from_folder_uuid); + if (version_folder_id.notNull()) + { + LLViewerInventoryCategory* cat = gInventory.getCategory(version_folder_id); + if (!validate_marketplacelistings(cat, NULL)) + { + LLMarketplaceData::instance().activateListing(version_folder_id, false); + } + } + } + + // //-------------------------------------------------------------------------------- } } @@ -4059,7 +4713,7 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, object = gObjectList.findObject(inv_item->getParentUUID()); if (!object) { - llinfos << "Object not found for drop." << llendl; + LL_INFOS() << "Object not found for drop." << LL_ENDL; return FALSE; } @@ -4091,12 +4745,12 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, } // Don't allow to move a single item to Favorites or Landmarks // if it is not a landmark or a link to a landmark. - else if ((move_is_into_favorites || move_is_into_landmarks) + else if ((/*move_is_into_favorites ||*/ move_is_into_landmarks) && !can_move_to_landmarks(inv_item)) { accept = FALSE; } - else if (move_is_into_outbox) + else if (move_is_into_marketplacelistings) { accept = FALSE; } @@ -4126,7 +4780,7 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, } else if(LLToolDragAndDrop::SOURCE_NOTECARD == source) { - if (move_is_into_outbox) + if (move_is_into_marketplacelistings) { accept = FALSE; } @@ -4152,7 +4806,7 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, { accept = TRUE; - if (move_is_into_outbox) + if (move_is_into_marketplacelistings) { accept = FALSE; } @@ -4162,7 +4816,7 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, } // Don't allow to move a single item to Favorites or Landmarks // if it is not a landmark or a link to a landmark. - else if (move_is_into_favorites || move_is_into_landmarks) + else if (/*move_is_into_favorites ||*/ move_is_into_landmarks) { accept = can_move_to_landmarks(inv_item); } @@ -4205,20 +4859,11 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, } else { - llwarns << "unhandled drag source" << llendl; + LL_WARNS() << "unhandled drag source" << LL_ENDL; } return accept; } -// +=================================================+ -// | LLTextureBridge | -// +=================================================+ - -LLUIImagePtr LLTextureBridge::getIcon() const -{ - return LLInventoryIcon::getIcon(LLAssetType::AT_TEXTURE, mInvType); -} - void open_texture(const LLUUID& item_id, const std::string& title, BOOL show_keep_discard, @@ -4256,6 +4901,15 @@ void open_texture(const LLUUID& item_id, } } +// +=================================================+ +// | LLTextureBridge | +// +=================================================+ + +LLUIImagePtr LLTextureBridge::getIcon() const +{ + return LLInventoryIcon::getIcon(LLAssetType::AT_TEXTURE, mInvType); +} + void LLTextureBridge::openItem() { LLViewerInventoryItem* item = getItem(); @@ -4284,19 +4938,27 @@ bool LLTextureBridge::canSaveTexture() void LLTextureBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { - lldebugs << "LLTextureBridge::buildContextMenu()" << llendl; + LL_DEBUGS() << "LLTextureBridge::buildContextMenu()" << LL_ENDL; menuentry_vec_t items; menuentry_vec_t disabled_items; if(isItemInTrash()) { addTrashContextMenuOptions(items, disabled_items); - } - else if(isOutboxFolder()) + } + else if (isMarketplaceListingsFolder()) { - addOutboxContextMenuOptions(flags, items, disabled_items); + addMarketplaceContextMenuOptions(flags, items, disabled_items); + items.push_back(std::string("Properties")); + getClipboardEntries(false, items, disabled_items, flags); } else { + items.push_back(std::string("Share")); + if (!canShare()) + { + disabled_items.push_back(std::string("Share")); + } + addOpenRightClickMenuOption(items); items.push_back(std::string("Properties")); @@ -4347,7 +5009,7 @@ void LLSoundBridge::previewItem() LLViewerInventoryItem* item = getItem(); if(item) { - send_sound_trigger(item->getAssetUUID(), 1.0); + send_sound_trigger(item->getAssetUUID(), SOUND_GAIN); } } @@ -4372,13 +5034,15 @@ void LLSoundBridge::openSoundPreview(void* which) void LLSoundBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { - lldebugs << "LLSoundBridge::buildContextMenu()" << llendl; + LL_DEBUGS() << "LLSoundBridge::buildContextMenu()" << LL_ENDL; menuentry_vec_t items; menuentry_vec_t disabled_items; - if (isOutboxFolder()) + if (isMarketplaceListingsFolder()) { - addOutboxContextMenuOptions(flags, items, disabled_items); + addMarketplaceContextMenuOptions(flags, items, disabled_items); + items.push_back(std::string("Properties")); + getClipboardEntries(false, items, disabled_items, flags); } else { @@ -4388,6 +5052,11 @@ void LLSoundBridge::buildContextMenu(LLMenuGL& menu, U32 flags) } else { + items.push_back(std::string("Share")); + if (!canShare()) + { + disabled_items.push_back(std::string("Share")); + } items.push_back(std::string("Sound Open")); items.push_back(std::string("Properties")); @@ -4401,6 +5070,23 @@ void LLSoundBridge::buildContextMenu(LLMenuGL& menu, U32 flags) hide_context_entries(menu, items, disabled_items); } +void LLSoundBridge::performAction(LLInventoryModel* model, std::string action) +{ + if ("sound_play" == action) + { + LLViewerInventoryItem* item = getItem(); + if(item) + { + send_sound_trigger(item->getAssetUUID(), SOUND_GAIN); + } + } + else if ("open" == action) + { + openSoundPreview((void*)this); + } + else LLItemBridge::performAction(model, action); +} + // +=================================================+ // | LLLandmarkBridge | // +=================================================+ @@ -4428,10 +5114,12 @@ void LLLandmarkBridge::buildContextMenu(LLMenuGL& menu, U32 flags) menuentry_vec_t items; menuentry_vec_t disabled_items; - lldebugs << "LLLandmarkBridge::buildContextMenu()" << llendl; - if(isOutboxFolder()) + LL_DEBUGS() << "LLLandmarkBridge::buildContextMenu()" << LL_ENDL; + if (isMarketplaceListingsFolder()) { - addOutboxContextMenuOptions(flags, items, disabled_items); + addMarketplaceContextMenuOptions(flags, items, disabled_items); + items.push_back(std::string("Properties")); + getClipboardEntries(false, items, disabled_items, flags); } else { @@ -4441,6 +5129,11 @@ void LLLandmarkBridge::buildContextMenu(LLMenuGL& menu, U32 flags) } else { + items.push_back(std::string("Share")); + if (!canShare()) + { + disabled_items.push_back(std::string("Share")); + } items.push_back(std::string("Landmark Open")); items.push_back(std::string("Properties")); @@ -4696,20 +5389,27 @@ void LLCallingCardBridge::openItem() void LLCallingCardBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { - lldebugs << "LLCallingCardBridge::buildContextMenu()" << llendl; + LL_DEBUGS() << "LLCallingCardBridge::buildContextMenu()" << LL_ENDL; menuentry_vec_t items; menuentry_vec_t disabled_items; if(isItemInTrash()) { addTrashContextMenuOptions(items, disabled_items); - } - else if(isOutboxFolder()) + } + else if (isMarketplaceListingsFolder()) { - items.push_back(std::string("Delete")); + addMarketplaceContextMenuOptions(flags, items, disabled_items); + items.push_back(std::string("Properties")); + getClipboardEntries(false, items, disabled_items, flags); } else { + items.push_back(std::string("Share")); + if (!canShare()) + { + disabled_items.push_back(std::string("Share")); + } /* Singu Note: Multiple profiles get opened in a multifloater if ((flags & FIRST_SELECTED_ITEM) == 0) { @@ -4723,7 +5423,7 @@ void LLCallingCardBridge::buildContextMenu(LLMenuGL& menu, U32 flags) LLInventoryItem* item = getItem(); BOOL good_card = (item - && (item->getCreatorUUID().notNull()) + && (LLUUID::null != item->getCreatorUUID()) && (item->getCreatorUUID() != gAgent.getID())); BOOL user_online = FALSE; if (item) @@ -4860,26 +5560,6 @@ void open_notecard(LLViewerInventoryItem* inv_item, if(take_focus) preview->setFocus(TRUE); // Force to be entirely onscreen. gFloaterView->adjustToFitScreen(preview, FALSE); - - //if (source_id.notNull()) - //{ - // // look for existing tabbed view for content from same source - // LLPreview* existing_preview = LLPreview::getPreviewForSource(source_id); - // if (existing_preview) - // { - // // found existing preview from this source - // // is it already hosted in a multi-preview window? - // LLMultiPreview* preview_hostp = (LLMultiPreview*)existing_preview->getHost(); - // if (!preview_hostp) - // { - // // create new multipreview if it doesn't exist - // LLMultiPreview* preview_hostp = new LLMultiPreview(existing_preview->getRect()); - // preview_hostp->addFloater(existing_preview); - // } - // // add this preview to existing host - // preview_hostp->addFloater(preview); - // } - //} } } @@ -4893,6 +5573,25 @@ void LLNotecardBridge::openItem() } } +void LLNotecardBridge::buildContextMenu(LLMenuGL& menu, U32 flags) +{ + LL_DEBUGS() << "LLNotecardBridge::buildContextMenu()" << LL_ENDL; + + if (isMarketplaceListingsFolder()) + { + menuentry_vec_t items; + menuentry_vec_t disabled_items; + addMarketplaceContextMenuOptions(flags, items, disabled_items); + items.push_back(std::string("Properties")); + getClipboardEntries(false, items, disabled_items, flags); + hide_context_entries(menu, items, disabled_items); + } + else + { + LLItemBridge::buildContextMenu(menu, flags); + } +} + // +=================================================+ // | LLGestureBridge | // +=================================================+ @@ -4944,7 +5643,7 @@ void LLGestureBridge::performAction(LLInventoryModel* model, std::string action) gInventory.updateItem(item); gInventory.notifyObservers(); } - else if (isRemoveAction(action)) + else if ("deactivate" == action || isRemoveAction(action)) { LLGestureMgr::instance().deactivateGesture(mUUID); @@ -4963,7 +5662,7 @@ void LLGestureBridge::performAction(LLInventoryModel* model, std::string action) // we need to inform server about gesture activating to be consistent with LLPreviewGesture and LLGestureComboList. BOOL inform_server = TRUE; BOOL deactivate_similar = FALSE; - LLGestureMgr::instance().setGestureLoadedCallback(mUUID, boost::bind(&LLGestureBridge::playGesture, mUUID)); + LLGestureMgr::instance().setGestureLoadedCallback(mUUID, std::bind(&LLGestureBridge::playGesture, mUUID)); LLViewerInventoryItem* item = gInventory.getItem(mUUID); llassert(item); if (item) @@ -5022,19 +5721,26 @@ BOOL LLGestureBridge::removeItem() void LLGestureBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { - lldebugs << "LLGestureBridge::buildContextMenu()" << llendl; + LL_DEBUGS() << "LLGestureBridge::buildContextMenu()" << LL_ENDL; menuentry_vec_t items; menuentry_vec_t disabled_items; if(isItemInTrash()) { addTrashContextMenuOptions(items, disabled_items); } - else if(isOutboxFolder()) + else if (isMarketplaceListingsFolder()) { - items.push_back(std::string("Delete")); + addMarketplaceContextMenuOptions(flags, items, disabled_items); + items.push_back(std::string("Properties")); + getClipboardEntries(false, items, disabled_items, flags); } else { + items.push_back(std::string("Share")); + if (!canShare()) + { + disabled_items.push_back(std::string("Share")); + } addOpenRightClickMenuOption(items); items.push_back(std::string("Properties")); @@ -5077,10 +5783,12 @@ void LLAnimationBridge::buildContextMenu(LLMenuGL& menu, U32 flags) menuentry_vec_t items; menuentry_vec_t disabled_items; - lldebugs << "LLAnimationBridge::buildContextMenu()" << llendl; - if(isOutboxFolder()) + LL_DEBUGS() << "LLAnimationBridge::buildContextMenu()" << LL_ENDL; + if (isMarketplaceListingsFolder()) { - items.push_back(std::string("Delete")); + addMarketplaceContextMenuOptions(flags, items, disabled_items); + items.push_back(std::string("Properties")); + getClipboardEntries(false, items, disabled_items, flags); } else { @@ -5090,6 +5798,11 @@ void LLAnimationBridge::buildContextMenu(LLMenuGL& menu, U32 flags) } else { + items.push_back(std::string("Share")); + if (!canShare()) + { + disabled_items.push_back(std::string("Share")); + } items.push_back(std::string("Animation Open")); items.push_back(std::string("Properties")); @@ -5110,9 +5823,7 @@ void LLAnimationBridge::performAction(LLInventoryModel* model, std::string actio if ((action == "playworld") || (action == "playlocal")) { // See if we can bring an existing preview to the front - if (LLPreview::show(mUUID)) - return; - + if (LLPreview::show(mUUID)) return; if (getItem()) { LLPreviewAnim::e_activation_type activate = LLPreviewAnim::NONE; @@ -5205,7 +5916,7 @@ void LLObjectBridge::performAction(LLInventoryModel* model, std::string action) else if(item && item->isFinished()) { // must be in library. copy it to our inventory and put it on. - LLPointer cb = new LLBoostFuncInventoryCallback(boost::bind(rez_attachment_cb, _1, (LLViewerJointAttachment*)0, false)); + LLPointer cb = new LLBoostFuncInventoryCallback(boost::bind(&rez_attachment_cb, _1, (LLViewerJointAttachment*)0, false)); copy_inventory_item( gAgent.getID(), item->getPermissions().getOwner(), @@ -5247,28 +5958,35 @@ std::string LLObjectBridge::getLabelSuffix() const { return LLItemBridge::getLabelSuffix() + LLTrans::getString("worn"); } - std::string attachment_point_name = gAgentAvatarp->getAttachedPointName(mUUID); - if (attachment_point_name == LLStringUtil::null) // Error condition, invalid attach point + std::string attachment_point_name; + if (gAgentAvatarp->getAttachedPointName(mUUID, attachment_point_name)) { - attachment_point_name = "Invalid Attachment"; - } - // e.g. "(worn on ...)" / "(attached to ...)" - LLStringUtil::format_map_t args; - args["[ATTACHMENT_POINT]"] = LLTrans::getString(attachment_point_name); + // e.g. "(worn on ...)" / "(attached to ...)" + LLStringUtil::format_map_t args; + args["[ATTACHMENT_POINT]"] = LLTrans::getString(attachment_point_name); - if(gRlvAttachmentLocks.canDetach(getItem())) - return LLItemBridge::getLabelSuffix() + LLTrans::getString("WornOnAttachmentPoint", args); + if (gRlvAttachmentLocks.canDetach(getItem())) + return LLItemBridge::getLabelSuffix() + LLTrans::getString("WornOnAttachmentPoint", args); + else + return LLItemBridge::getLabelSuffix() + LLTrans::getString("LockedOnAttachmentPoint", args); + } else - return LLItemBridge::getLabelSuffix() + LLTrans::getString("LockedOnAttachmentPoint", args); + { + LLStringUtil::format_map_t args; + args["[ATTACHMENT_ERROR]"] = LLTrans::getString(attachment_point_name); + return LLItemBridge::getLabelSuffix() + LLTrans::getString("AttachmentErrorMessage", args); + } } return LLItemBridge::getLabelSuffix(); } void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attachment, bool replace) { -// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1a) | Added: RLVa-1.2.1a +// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1) // If no attachment point was specified, try looking it up from the item name - if ( (rlv_handler_t::isEnabled()) && (!attachment) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) ) + static LLCachedControl fRlvDeprecateAttachPt(gSavedSettings, "RLVaDebugDeprecateExplicitPoint", false); + if ( (rlv_handler_t::isEnabled()) && (!fRlvDeprecateAttachPt) && + (!attachment) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_ANY)) ) { attachment = RlvAttachPtLookup::getAttachPoint(item); } @@ -5278,13 +5996,11 @@ void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attach // Check for duplicate request. if (isAgentAvatarValid() && - (gAgentAvatarp->attachmentWasRequested(item_id) || - gAgentAvatarp->isWearingAttachment(item_id))) + gAgentAvatarp->isWearingAttachment(item_id)) { - llwarns << "duplicate attachment request, ignoring" << llendl; + LL_WARNS() << "ATT duplicate attachment request, ignoring" << LL_ENDL; return; } - gAgentAvatarp->addAttachmentRequest(item_id); S32 attach_pt = 0; if (isAgentAvatarValid() && attachment) @@ -5308,19 +6024,23 @@ void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attach if (replace && (attachment && attachment->getNumObjects() > 0)) { -// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1a) | Modified: RLVa-1.2.1a +// [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1) // Block if we can't "replace wear" what's currently there if ( (rlv_handler_t::isEnabled()) && ((gRlvAttachmentLocks.canAttach(attachment) & RLV_WEAR_REPLACE) == 0) ) + { return; + } // [/RLVa:KB] LLNotificationsUtil::add("ReplaceAttachment", LLSD(), payload, confirm_attachment_rez); } else { -// [RLVa:KB] - Checked: 2010-08-07 (RLVa-1.2.0i) | Modified: RLVa-1.2.0i +// [RLVa:KB] - Checked: 2010-08-07 (RLVa-1.2.0) // Block wearing anything on a non-attachable attachment point if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.isLockedAttachmentPoint(attach_pt, RLV_LOCK_ADD)) ) + { return; + } // [/RLVa:KB] LLNotifications::instance().forceResponse(LLNotification::Params("ReplaceAttachment").payload(payload), 0/*YES*/); } @@ -5331,7 +6051,7 @@ bool confirm_attachment_rez(const LLSD& notification, const LLSD& response) if (!gAgentAvatarp->canAttachMoreObjects()) { LLSD args; - args["MAX_ATTACHMENTS"] = llformat("%d", MAX_AGENT_ATTACHMENTS); + args["MAX_ATTACHMENTS"] = llformat("%d", LLAgentBenefitsMgr::current().getAttachmentLimit()); LLNotificationsUtil::add("MaxAttachmentsOnOutfit", args); return false; } @@ -5344,36 +6064,14 @@ bool confirm_attachment_rez(const LLSD& notification, const LLSD& response) if (itemp) { - /* - { - U8 attachment_pt = notification["payload"]["attachment_point"].asInteger(); - - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_RezSingleAttachmentFromInv); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_ObjectData); - msg->addUUIDFast(_PREHASH_ItemID, itemp->getUUID()); - msg->addUUIDFast(_PREHASH_OwnerID, itemp->getPermissions().getOwner()); - msg->addU8Fast(_PREHASH_AttachmentPt, attachment_pt); - pack_permissions_slam(msg, itemp->getFlags(), itemp->getPermissions()); - msg->addStringFast(_PREHASH_Name, itemp->getName()); - msg->addStringFast(_PREHASH_Description, itemp->getDescription()); - msg->sendReliable(gAgent.getRegion()->getHost()); - return false; - } - */ - // Queue up attachments to be sent in next idle tick, this way the // attachments are batched up all into one message versus each attachment // being sent in its own separate attachments message. U8 attachment_pt = notification["payload"]["attachment_point"].asInteger(); BOOL is_add = notification["payload"]["is_add"].asBoolean(); - LLAttachmentsMgr::instance().addAttachment(item_id, - attachment_pt, - is_add); + LL_DEBUGS("Avatar") << "ATT calling addAttachmentRequest " << (itemp ? itemp->getName() : "UNKNOWN") << " id " << item_id << LL_ENDL; + LLAttachmentsMgr::instance().addAttachmentRequest(item_id, attachment_pt, is_add); } } return false; @@ -5394,13 +6092,21 @@ void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags) if(isItemInTrash()) { addTrashContextMenuOptions(items, disabled_items); - } - else if(isOutboxFolder()) + } + else if (isMarketplaceListingsFolder()) { - items.push_back(std::string("Delete")); + addMarketplaceContextMenuOptions(flags, items, disabled_items); + items.push_back(std::string("Properties")); + getClipboardEntries(false, items, disabled_items, flags); } else { + items.push_back(std::string("Share")); + if (!canShare()) + { + disabled_items.push_back(std::string("Share")); + } + items.push_back(std::string("Properties")); getClipboardEntries(true, items, disabled_items, flags); @@ -5426,8 +6132,7 @@ void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { items.push_back(std::string("Wearable And Object Separator")); items.push_back(std::string("Wearable And Object Wear")); - if (InventoryLinksEnabled()) - items.push_back(std::string("Wearable Add")); + items.push_back(std::string("Wearable Add")); items.push_back(std::string("Attach To")); items.push_back(std::string("Attach To HUD")); // commented out for DEV-32347 - AND Commented back in for non-morons. -HgB @@ -5505,10 +6210,10 @@ BOOL LLObjectBridge::renameItem(const std::string& new_name) { LLPointer new_item = new LLViewerInventoryItem(item); new_item->rename(new_name); - buildDisplayName(new_item, mDisplayName); new_item->updateServer(FALSE); model->updateItem(new_item); model->notifyObservers(); + buildDisplayName(); if (isAgentAvatarValid()) { @@ -5558,124 +6263,6 @@ LLWearableBridge::LLWearableBridge(LLInventoryPanel* inventory, mInvType = inv_type; } -void remove_inventory_category_from_avatar( LLInventoryCategory* category ) -{ - if(!category) return; - lldebugs << "remove_inventory_category_from_avatar( " << category->getName() - << " )" << llendl; - if (LLFloaterCustomize::instanceExists()) - { - LLFloaterCustomize::getInstance()->askToSaveIfDirty(boost::bind(&remove_inventory_category_from_avatar_step2,_1,category->getUUID())); - } - else - remove_inventory_category_from_avatar_step2(TRUE, category->getUUID() ); -} - -//struct OnRemoveStruct -//{ -// LLUUID mUUID; -// OnRemoveStruct(const LLUUID& uuid): -// mUUID(uuid) -// { -// } -//}; - -void remove_inventory_category_from_avatar_step2( BOOL proceed, LLUUID category_id) -{ - - // Find all the wearables that are in the category's subtree. - lldebugs << "remove_inventory_category_from_avatar_step2()" << llendl; - if(proceed) - { - LLInventoryModel::cat_array_t cat_array; - LLInventoryModel::item_array_t item_array; - LLFindWearables is_wearable; - gInventory.collectDescendentsIf(category_id, - cat_array, - item_array, - LLInventoryModel::EXCLUDE_TRASH, - is_wearable); - S32 i; - S32 wearable_count = item_array.count(); - - LLInventoryModel::cat_array_t obj_cat_array; - LLInventoryModel::item_array_t obj_item_array; - LLIsType is_object( LLAssetType::AT_OBJECT ); - gInventory.collectDescendentsIf(category_id, - obj_cat_array, - obj_item_array, - LLInventoryModel::EXCLUDE_TRASH, - is_object); - S32 obj_count = obj_item_array.count(); - - // Find all gestures in this folder - LLInventoryModel::cat_array_t gest_cat_array; - LLInventoryModel::item_array_t gest_item_array; - LLIsType is_gesture( LLAssetType::AT_GESTURE ); - gInventory.collectDescendentsIf(category_id, - gest_cat_array, - gest_item_array, - LLInventoryModel::EXCLUDE_TRASH, - is_gesture); - S32 gest_count = gest_item_array.count(); - - if (wearable_count > 0) //Loop through wearables. If worn, remove. - { - for(i = 0; i < wearable_count; ++i) - { - LLViewerInventoryItem *item = item_array.get(i); - if (item->getType() == LLAssetType::AT_BODYPART) - continue; - if (gAgent.isTeen() && item->isWearableType() && - (item->getWearableType() == LLWearableType::WT_UNDERPANTS || item->getWearableType() == LLWearableType::WT_UNDERSHIRT)) - continue; - if (get_is_item_worn(item->getUUID())) - { -// [RLVa:KB] - Checked: 2010-04-04 (RLVa-1.2.0c) | Modified: RLVa-0.2.2a -// if ( (rlv_handler_t::isEnabled()) && (!gRlvWearableLocks.canRemove(item)) ) -// continue; -// [/RLVa:KB] -// LLWearableList::instance().getAsset(item->getAssetUUID(), -// item->getName(), -// item->getType(), -// LLWearableBridge::onRemoveFromAvatarArrived, -// new OnRemoveStruct(item->getLinkedUUID())); -// [SL:KB] - Patch: Appearance-RemoveWearableFromAvatar | Checked: 2010-08-13 (Catznip-3.0.0a) | Added: Catznip-2.1.1d - LLAppearanceMgr::instance().removeItemFromAvatar(item->getUUID()); -// [/SL:KB] - } - } - } - - if (obj_count > 0) - { - for(i = 0; i < obj_count; ++i) - { - LLViewerInventoryItem *obj_item = obj_item_array.get(i); - if (get_is_item_worn(obj_item->getUUID())) - { - LLVOAvatarSelf::detachAttachmentIntoInventory(obj_item->getLinkedUUID()); - } - } - } - - if (gest_count > 0) - { - for(i = 0; i < gest_count; ++i) - { - LLViewerInventoryItem *gest_item = gest_item_array.get(i); - if (get_is_item_worn(gest_item->getUUID())) - { - LLGestureMgr::instance().deactivateGesture( gest_item->getLinkedUUID() ); - gInventory.updateItem( gest_item ); - gInventory.notifyObservers(); - } - - } - } - } -} - BOOL LLWearableBridge::renameItem(const std::string& new_name) { if (get_is_item_worn(mUUID)) @@ -5779,26 +6366,24 @@ void LLWearableBridge::performAction(LLInventoryModel* model, std::string action void LLWearableBridge::openItem() { - LLViewerInventoryItem* item = getItem(); - - if (item) - { + if (LLViewerInventoryItem* item = getItem()) LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel()); - } } void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { - lldebugs << "LLWearableBridge::buildContextMenu()" << llendl; + LL_DEBUGS() << "LLWearableBridge::buildContextMenu()" << LL_ENDL; menuentry_vec_t items; menuentry_vec_t disabled_items; if(isItemInTrash()) { addTrashContextMenuOptions(items, disabled_items); } - else if(isOutboxFolder()) + else if (isMarketplaceListingsFolder()) { - items.push_back(std::string("Delete")); + addMarketplaceContextMenuOptions(flags, items, disabled_items); + items.push_back(std::string("Properties")); + getClipboardEntries(false, items, disabled_items, flags); } else { // FWIW, it looks like SUPPRESS_OPEN_ITEM is not set anywhere @@ -5815,6 +6400,12 @@ void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { can_open = FALSE; } + items.push_back(std::string("Share")); + if (!canShare()) + { + disabled_items.push_back(std::string("Share")); + } + if (can_open) { addOpenRightClickMenuOption(items); @@ -5832,15 +6423,8 @@ void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags) items.push_back(std::string("Wearable And Object Separator")); items.push_back(std::string("Wearable Edit")); -/*// [RLVa:KB] - Checked: 2011-09-16 (RLVa-1.1.4a) | Added: RLVa-1.1.4a - if ( (rlv_handler_t::isEnabled()) && (!gRlvWearableLocks.canRemove(item)) ) - { - disabled_items.push_back(std::string("Wearable And Object Wear")); - disabled_items.push_back(std::string("Wearable Edit")); - } -// [/RLVa:KB]*/ - bool not_modifiable = !gAgentWearables.isWearableModifiable(item->getUUID()); + bool not_modifiable = !item || !gAgentWearables.isWearableModifiable(item->getUUID()); if (((flags & FIRST_SELECTED_ITEM) == 0) || not_modifiable) { disabled_items.push_back(std::string("Wearable Edit")); @@ -5860,27 +6444,38 @@ void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { case LLAssetType::AT_CLOTHING: items.push_back(std::string("Take Off")); -/*// [RLVa:KB] - Checked: 2011-09-16 (RLVa-1.1.4a) | Added: RLVa-1.1.4a - if ( (rlv_handler_t::isEnabled()) && (!gRlvWearableLocks.canRemove(item)) ) - disabled_items.push_back(std::string("Take Off")); -// [/RLVa:KB]*/ // Fallthrough since clothing and bodypart share wear options case LLAssetType::AT_BODYPART: - if (get_is_item_worn(item->getUUID())) + items.push_back(std::string("Wearable And Object Wear")); + + if (LLUpdateAppearanceOnDestroy::sActiveCallbacks) // cof_pending + { + disabled_items.push_back(std::string("Wearable And Object Wear")); + disabled_items.push_back(std::string("Wearable Add")); + disabled_items.push_back(std::string("Take Off")); + disabled_items.push_back(std::string("Wearable Move Forward")); + disabled_items.push_back(std::string("Wearable Move Back")); + } + else if (get_is_item_worn(item->getUUID())) { disabled_items.push_back(std::string("Wearable And Object Wear")); disabled_items.push_back(std::string("Wearable Add")); // [RLVa:KB] - Checked: 2010-04-04 (RLVa-1.2.0c) | Added: RLVa-1.2.0c - if ( (rlv_handler_t::isEnabled()) && (!gRlvWearableLocks.canRemove(item)) ) + if ((rlv_handler_t::isEnabled()) && (!gRlvWearableLocks.canRemove(item))) disabled_items.push_back(std::string("Take Off")); // [/RLVa:KB] } else { - items.push_back(std::string("Wearable And Object Wear")); disabled_items.push_back(std::string("Take Off")); disabled_items.push_back(std::string("Wearable Edit")); - + if (gAgentWearables.getWearableFromAssetID(item->getAssetUUID())) + { + disabled_items.push_back(std::string("Wearable Add")); + LLViewerWearable* wearable = gAgentWearables.getWearableFromAssetID(item->getAssetUUID()); + if (wearable && wearable != gAgentWearables.getTopWearable(mWearableType)) + disabled_items.push_back(std::string("Wearable And Object Wear")); + } // [RLVa:KB] - Checked: 2010-06-09 (RLVa-1.2.0g) | Modified: RLVa-1.2.0g if (rlv_handler_t::isEnabled()) { @@ -5900,16 +6495,13 @@ void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags) items.push_back(std::string("Wearable Move Back")); bool is_worn = get_is_item_worn(item->getUUID()); - if(!is_worn || !gAgentWearables.canMoveWearable(item->getUUID(),false)) + if (!is_worn || !gAgentWearables.canMoveWearable(item->getUUID(), false)) disabled_items.push_back(std::string("Wearable Move Forward")); - if(!is_worn || !gAgentWearables.canMoveWearable(item->getUUID(),true)) + if (!is_worn || !gAgentWearables.canMoveWearable(item->getUUID(), true)) disabled_items.push_back(std::string("Wearable Move Back")); -// if (gAgentWearables.getWearableCount(mWearableType) >= LLAgentWearables::MAX_CLOTHING_PER_TYPE) -// [SL:KB] - Patch: Appearance-WearableDuplicateAssets | Checked: 2011-07-24 (Catznip-2.6.0e) | Added: Catznip-2.6.0e - if ( (gAgentWearables.getWearableCount(mWearableType) >= LLAgentWearables::MAX_CLOTHING_PER_TYPE) || - (gAgentWearables.getWearableFromAssetID(item->getAssetUUID())) ) -// [/SL:KB] + // Allow adding for the behavior of replacing bodyparts but keeping worn things else. + if (item->getType() != LLAssetType::AT_BODYPART && !gAgentWearables.canAddWearable(mWearableType)) { disabled_items.push_back(std::string("Wearable Add")); } @@ -5948,6 +6540,20 @@ void LLWearableBridge::onWearOnAvatar(void* user_data) void LLWearableBridge::wearOnAvatar() { + // Note: This test is not in any other viewer and it seriously harms Singularity: + // On many opensim grids people start without a base outfit: they are not wearing + // anything (no shape, skin, eyes or hair). Even if one of those is missing, which + // ALSO happens due to (another) bug specific to Singularity (namely wearing a + // pre-multiwear wearable that is erroneously marked as 'shape' and causes the + // current shape to be removed), the user is eternally stuck as cloud since they + // are not ALLOWED to add the body parts that are missing BECAUSE they are missing?! + // The only way to recover from that is then to install another viewer and log in + // with that - go figure. + // + // Nevertheless, I won't break this test without good reason (although, again, no + // other viewer has it - so it can't be that serious) and therefore will only + // change it that users CAN wear body parts if those are missing :p (see below). +#if 0 // TODO: investigate wearables may not be loaded at this point EXT-8231 // Don't wear anything until initial wearables are loaded, can // destroy clothing items. @@ -5956,10 +6562,20 @@ void LLWearableBridge::wearOnAvatar() LLNotificationsUtil::add("CanNotChangeAppearanceUntilLoaded"); return; } +#endif LLViewerInventoryItem* item = getItem(); - if(item) + if (item) { + // + // Don't wear anything until initial wearables are loaded unless the user tries to replace + // a body part, which might be missing and be the REASON that areWearablesLoaded() returns false. + if ((item->getType() != LLAssetType::AT_BODYPART && !gAgentWearables.areWearablesLoaded())) + { + LLNotificationsUtil::add("CanNotChangeAppearanceUntilLoaded"); + return; + } + // LLAppearanceMgr::instance().wearItemOnAvatar(item->getUUID(), true, true); } } @@ -5982,6 +6598,7 @@ void LLWearableBridge::wearAddOnAvatar() } } +//Never used. // static //void LLWearableBridge::onWearOnAvatarArrived( LLViewerWearable* wearable, void* userdata ) //{ @@ -6000,7 +6617,7 @@ void LLWearableBridge::wearAddOnAvatar() // } // else // { -// llinfos << "By the time wearable asset arrived, its inv item already pointed to a different asset." << llendl; +// LL_INFOS() << "By the time wearable asset arrived, its inv item already pointed to a different asset." << LL_ENDL; // } // } // } @@ -6027,7 +6644,7 @@ void LLWearableBridge::wearAddOnAvatar() // } // else // { -// llinfos << "By the time wearable asset arrived, its inv item already pointed to a different asset." << llendl; +// LL_INFOS() << "By the time wearable asset arrived, its inv item already pointed to a different asset." << LL_ENDL; // } // } // } @@ -6069,62 +6686,6 @@ BOOL LLWearableBridge::canRemoveFromAvatar(void* user_data) return FALSE; } -// static -//void LLWearableBridge::onRemoveFromAvatar(void* user_data) -//{ -// LLWearableBridge* self = (LLWearableBridge*)user_data; -// if(!self) return; -// if(get_is_item_worn(self->mUUID)) -// { -// LLViewerInventoryItem* item = self->getItem(); -// if (item) -// { -// LLUUID parent_id = item->getParentUUID(); -// LLWearableList::instance().getAsset(item->getAssetUUID(), -// item->getName(), -// item->getType(), -// onRemoveFromAvatarArrived, -// new OnRemoveStruct(LLUUID(self->mUUID))); -// } -// } -//} - -// static -//void LLWearableBridge::onRemoveFromAvatarArrived(LLViewerWearable* wearable, -// void* userdata) -//{ -// OnRemoveStruct *on_remove_struct = (OnRemoveStruct*) userdata; -// const LLUUID &item_id = gInventory.getLinkedItemID(on_remove_struct->mUUID); -// [RLVa:KB] - Checked: 2010-03-20 (RLVa-1.2.0c) | Modified: RLVa-1.2.0a -// if ( (rlv_handler_t::isEnabled()) && ((!wearable) || (!gRlvWearableLocks.canRemove(gInventory.getItem(item_id)))) ) -// { -// delete on_remove_struct; -// return; -// } -// [/RLVa:KB] -// if(wearable) -// { -// if( get_is_item_worn( item_id ) ) -// { -// LLWearableType::EType type = wearable->getType(); -// -// if( !(type==LLWearableType::WT_SHAPE || type==LLWearableType::WT_SKIN || type==LLWearableType::WT_HAIR || type==LLWearableType::WT_EYES ) ) //&& -// //!((!gAgent.isTeen()) && ( type==LLWearableType::WT_UNDERPANTS || type==LLWearableType::WT_UNDERSHIRT )) ) -// { -// bool do_remove_all = false; -// U32 index = gAgentWearables.getWearableIndex(wearable); -// gAgentWearables.removeWearable( type, do_remove_all, index ); -// } -// } -// } -// -// // Find and remove this item from the COF. -// LLAppearanceMgr::instance().removeCOFItemLinks(item_id,false); -// gInventory.notifyObservers(); -// -// delete on_remove_struct; -//} - void LLWearableBridge::removeFromAvatar() { if (get_is_item_worn(mUUID)) @@ -6157,7 +6718,7 @@ LLUIImagePtr LLLinkItemBridge::getIcon() const void LLLinkItemBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { // *TODO: Translate - lldebugs << "LLLink::buildContextMenu()" << llendl; + LL_DEBUGS() << "LLLink::buildContextMenu()" << LL_ENDL; menuentry_vec_t items; menuentry_vec_t disabled_items; @@ -6195,18 +6756,9 @@ void LLMeshBridge::openItem() } } -void LLMeshBridge::previewItem() -{ - LLViewerInventoryItem* item = getItem(); - if(item) - { - // preview mesh - } -} - void LLMeshBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { - lldebugs << "LLMeshBridge::buildContextMenu()" << llendl; + LL_DEBUGS() << "LLMeshBridge::buildContextMenu()" << LL_ENDL; std::vector items; std::vector disabled_items; @@ -6220,9 +6772,11 @@ void LLMeshBridge::buildContextMenu(LLMenuGL& menu, U32 flags) items.push_back(std::string("Restore Item")); } - else if(isOutboxFolder()) + else if (isMarketplaceListingsFolder()) { - addOutboxContextMenuOptions(flags, items, disabled_items); + addMarketplaceContextMenuOptions(flags, items, disabled_items); + items.push_back(std::string("Properties")); + getClipboardEntries(false, items, disabled_items, flags); } else { @@ -6263,7 +6817,7 @@ LLUIImagePtr LLLinkFolderBridge::getIcon() const void LLLinkFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { // *TODO: Translate - lldebugs << "LLLink::buildContextMenu()" << llendl; + LL_DEBUGS() << "LLLink::buildContextMenu()" << LL_ENDL; menuentry_vec_t items; menuentry_vec_t disabled_items; @@ -6273,7 +6827,9 @@ void LLLinkFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) } else { - items.push_back(std::string("Find Original")); + getClipboardEntries(false, items, disabled_items, flags); + if (LLPanelMainInventory::getActiveInventory() && isAgentInventory()) + build_context_menu_folder_options(getInventoryModel(), getFolderID(), items, disabled_items); addDeleteContextMenuOptions(items, disabled_items); } hide_context_entries(menu, items, disabled_items); @@ -6285,6 +6841,35 @@ void LLLinkFolderBridge::performAction(LLInventoryModel* model, std::string acti gotoItem(); return; } + if ("purge" == action) + { + purgeItem(model, mUUID); + return; + } + if ("restore" == action) + { + restoreItem(); + return; + } + if ("cut" == action) + { + cutToClipboard(); + LLFolderView::removeCutItems(); + return; + } + if ("copy" == action) + { + copyToClipboard(); + return; + } + if (LLPanelMainInventory* iv = LLPanelMainInventory::getActiveInventory()) + { + if (LLFolderViewItem* folder_item = iv->getActivePanel()->getRootFolder()->getItemByID(getFolderID())) + { + folder_item->getListener()->performAction(model, action); + return; + } + } LLItemBridge::performAction(model,action); } void LLLinkFolderBridge::gotoItem() @@ -6446,7 +7031,7 @@ class LLCallingCardBridgeAction: public LLInvFVBridgeAction virtual void doIt() { LLViewerInventoryItem* item = getItem(); - if (item) + if (item && item->getCreatorUUID().notNull()) { LLAvatarActions::showProfile(item->getCreatorUUID()); } @@ -6638,7 +7223,7 @@ void LLWearableBridgeAction::wearOnAvatar() LLViewerInventoryItem* item = getItem(); if(item) { - if (get_is_item_worn(item)) + if (get_is_item_worn(item->getUUID())) { LLAppearanceMgr::instance().removeItemFromAvatar(item->getUUID()); } @@ -6703,9 +7288,8 @@ LLInvFVBridgeAction* LLInvFVBridgeAction::createAction(LLAssetType::EType asset_ /************************************************************************/ void LLRecentItemsFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { - LLFolderBridge::buildContextMenu(menu, flags); - - menuentry_vec_t disabled_items, items = getMenuItems(); + menuentry_vec_t disabled_items, items; + buildContextMenuOptions(flags, items, disabled_items); items.erase(std::remove(items.begin(), items.end(), std::string("New Folder")), items.end()); @@ -6729,7 +7313,7 @@ LLInvFVBridge* LLRecentInventoryBridgeBuilder::createBridge( } else { - new_listener = LLInventoryFVBridgeBuilder::createBridge(asset_type, + new_listener = LLInventoryFolderViewModelBuilder::createBridge(asset_type, actual_asset_type, inv_type, inventory, @@ -6740,4 +7324,22 @@ LLInvFVBridge* LLRecentInventoryBridgeBuilder::createBridge( return new_listener; } +LLFolderViewGroupedItemBridge::LLFolderViewGroupedItemBridge() +{ +} + +void LLFolderViewGroupedItemBridge::groupFilterContextMenu(folder_view_item_deque& selected_items, LLMenuGL& menu) +{ + uuid_vec_t ids; + menuentry_vec_t disabled_items; + if (get_selection_item_uuids(selected_items, ids)) + { + if (!LLAppearanceMgr::instance().canAddWearables(ids)) + { + disabled_items.push_back(std::string("Wearable Add")); + } + } + disable_context_entries_if_present(menu, disabled_items); +} + // EOF diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index 5fa3641a79..84bbc985e2 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -29,6 +29,7 @@ #include "llcallingcard.h" #include "llfloaterproperties.h" +#include "llfolderview.h" #include "llfoldervieweventlistener.h" #include "llinventorymodel.h" #include "llinventoryobserver.h" @@ -69,6 +70,7 @@ class LLInvFVBridge : public LLFolderViewEventListener U32 flags = 0x00); virtual ~LLInvFVBridge() {} + bool canShare() const; bool canListOnMarketplace() const; bool canListOnMarketplaceNow() const; @@ -76,7 +78,7 @@ class LLInvFVBridge : public LLFolderViewEventListener // LLInvFVBridge functionality //-------------------------------------------------------------------- virtual const LLUUID& getUUID() const { return mUUID; } - virtual void clearDisplayName() {} + virtual void clearDisplayName() { mDisplayName.clear(); } virtual const std::string& getPrefix() { return LLStringUtil::null; } virtual void restoreItem() {} virtual void restoreToWorld() {} @@ -86,9 +88,11 @@ class LLInvFVBridge : public LLFolderViewEventListener //-------------------------------------------------------------------- virtual const std::string& getName() const; virtual const std::string& getDisplayName() const; + virtual PermissionMask getPermissionMask() const; virtual LLFolderType::EType getPreferredType() const; virtual time_t getCreationDate() const; + virtual void setCreationDate(time_t creation_date_utc); virtual LLFontGL::StyleFlags getLabelStyle() const { return LLFontGL::NORMAL; } virtual std::string getLabelSuffix() const { return LLStringUtil::null; } virtual void openItem() {} @@ -101,12 +105,13 @@ class LLInvFVBridge : public LLFolderViewEventListener virtual BOOL isItemMovable() const; virtual BOOL isItemInTrash() const; virtual BOOL isLink() const; + virtual BOOL isLibraryItem() const; //virtual BOOL removeItem() = 0; - virtual void removeBatch(LLDynamicArray& batch); + virtual void removeBatch(std::vector& batch); virtual void move(LLFolderViewEventListener* new_parent_bridge) {} virtual BOOL isItemCopyable() const { return FALSE; } virtual BOOL copyToClipboard() const; - virtual void cutToClipboard(); + virtual BOOL cutToClipboard(); virtual BOOL isClipboardPasteable() const; bool isClipboardPasteableAsCopy() const; virtual BOOL isClipboardPasteableAsLink() const; @@ -121,6 +126,8 @@ class LLInvFVBridge : public LLFolderViewEventListener void* cargo_data) { return FALSE; } virtual LLInventoryType::EType getInventoryType() const { return mInvType; } virtual LLWearableType::EType getWearableType() const { return LLWearableType::WT_NONE; } + virtual LLInventoryObject* getInventoryObject() const; + //-------------------------------------------------------------------- // Convenience functions for adding various common menu options. @@ -131,24 +138,23 @@ class LLInvFVBridge : public LLFolderViewEventListener virtual void addDeleteContextMenuOptions(menuentry_vec_t &items, menuentry_vec_t &disabled_items); virtual void addOpenRightClickMenuOption(menuentry_vec_t &items); - virtual void addOutboxContextMenuOptions(U32 flags, + virtual void addMarketplaceContextMenuOptions(U32 flags, menuentry_vec_t &items, menuentry_vec_t &disabled_items); protected: LLInvFVBridge(LLInventoryPanel* inventory, LLFolderView* root, const LLUUID& uuid); - LLInventoryObject* getInventoryObject() const; LLInventoryModel* getInventoryModel() const; + LLInventoryFilter* getInventoryFilter() const; BOOL isLinkedObjectInTrash() const; // Is this obj or its baseobj in the trash? BOOL isLinkedObjectMissing() const; // Is this a linked obj whose baseobj is not in inventory? BOOL isAgentInventory() const; // false if lost or in the inventory library - BOOL isCOFFolder() const; // true if COF or descendent of - BOOL isInboxFolder() const; // true if COF or descendent of marketplace inbox - BOOL isOutboxFolder() const; // true if COF or descendent of marketplace outbox - BOOL isOutboxFolderDirectParent() const; - const LLUUID getOutboxFolder() const; + BOOL isCOFFolder() const; // true if COF or descendant of + BOOL isInboxFolder() const; // true if COF or descendant of marketplace inbox + + BOOL isMarketplaceListingsFolder() const; // true if descendant of Marketplace listings folder virtual BOOL isItemPermissive() const; static void changeItemParent(LLInventoryModel* model, @@ -159,14 +165,23 @@ class LLInvFVBridge : public LLFolderViewEventListener LLViewerInventoryCategory* item, const LLUUID& new_parent, BOOL restamp); - void removeBatchNoCheck(LLDynamicArray& batch); + void removeBatchNoCheck(std::vector& batch); +public: + + BOOL callback_cutToClipboard(const LLSD& notification, const LLSD& response); + BOOL perform_cutToClipboard(); + protected: LLHandle mInventoryPanel; LLFolderView* mRoot; const LLUUID mUUID; // item id LLInventoryType::EType mInvType; - BOOL mIsLink; + bool mIsLink; + mutable std::string mDisplayName; + void purgeItem(LLInventoryModel *model, const LLUUID &uuid); + virtual void buildDisplayName() const {} + void removeObject(LLInventoryModel* model, const LLUUID& uuid); }; class AIFilePicker; @@ -176,11 +191,11 @@ class AIFilePicker; // This class intended to build Folder View Bridge via LLInvFVBridge::createBridge. // It can be overridden with another way of creation necessary Inventory-Folder-View-Bridge. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLInventoryFVBridgeBuilder +class LLInventoryFolderViewModelBuilder { public: - LLInventoryFVBridgeBuilder() {} - virtual ~LLInventoryFVBridgeBuilder() {} + LLInventoryFolderViewModelBuilder() {} + virtual ~LLInventoryFolderViewModelBuilder() {} virtual LLInvFVBridge* createBridge(LLAssetType::EType asset_type, LLAssetType::EType actual_asset_type, LLInventoryType::EType inv_type, @@ -204,7 +219,6 @@ class LLItemBridge : public LLInvFVBridge virtual void restoreToWorld(); virtual void gotoItem(); virtual LLUIImagePtr getIcon() const; - virtual const std::string& getDisplayName() const; virtual std::string getLabelSuffix() const; virtual LLFontGL::StyleFlags getLabelStyle() const; virtual PermissionMask getPermissionMask() const; @@ -213,21 +227,17 @@ class LLItemBridge : public LLInvFVBridge virtual BOOL renameItem(const std::string& new_name); virtual BOOL removeItem(); virtual BOOL isItemCopyable() const; - virtual BOOL hasChildren() const { return FALSE; } + virtual bool hasChildren() const { return FALSE; } virtual BOOL isUpToDate() const { return TRUE; } - + virtual LLUIImagePtr getIconOverlay() const; static void showFloaterImagePreview(LLInventoryItem* item, AIFilePicker* filepicker); - /*virtual*/ void clearDisplayName() { mDisplayName.clear(); } - LLViewerInventoryItem* getItem() const; protected: BOOL confirmRemoveItem(const LLSD& notification, const LLSD& response); virtual BOOL isItemPermissive() const; - static void buildDisplayName(LLInventoryItem* item, std::string& name); - - mutable std::string mDisplayName; + virtual void buildDisplayName() const; }; class LLFolderBridge : public LLInvFVBridge @@ -235,14 +245,18 @@ class LLFolderBridge : public LLInvFVBridge public: LLFolderBridge(LLInventoryPanel* inventory, LLFolderView* root, - const LLUUID& uuid) : - LLInvFVBridge(inventory, root, uuid), + const LLUUID& uuid) + : LLInvFVBridge(inventory, root, uuid), mCallingCards(FALSE), mWearables(FALSE) {} - BOOL dragItemIntoFolder(LLInventoryItem* inv_item, BOOL drop); - BOOL dragCategoryIntoFolder(LLInventoryCategory* inv_category, BOOL drop); + BOOL dragItemIntoFolder(LLInventoryItem* inv_item, BOOL drop, BOOL user_confirm = TRUE); + BOOL dragCategoryIntoFolder(LLInventoryCategory* inv_category, BOOL drop, BOOL user_confirm = TRUE); + void callback_dropItemIntoFolder(const LLSD& notification, const LLSD& response, LLInventoryItem* inv_item); + void callback_dropCategoryIntoFolder(const LLSD& notification, const LLSD& response, LLInventoryCategory* inv_item); + + virtual void buildDisplayName() const; virtual void performAction(LLInventoryModel* model, std::string action); virtual void openItem(); @@ -253,8 +267,11 @@ class LLFolderBridge : public LLInvFVBridge virtual LLFolderType::EType getPreferredType() const; virtual LLUIImagePtr getIcon() const; - virtual LLUIImagePtr getOpenIcon() const; + virtual LLUIImagePtr getIconOpen() const; + virtual LLUIImagePtr getIconOverlay() const; static LLUIImagePtr getIcon(LLFolderType::EType preferred_type); + virtual std::string getLabelSuffix() const; + virtual LLFontGL::StyleFlags getLabelStyle() const; virtual BOOL renameItem(const std::string& new_name); @@ -265,7 +282,7 @@ class LLFolderBridge : public LLInvFVBridge virtual void pasteFromClipboard(bool only_copies = false); virtual void pasteLinkFromClipboard(); virtual void buildContextMenu(LLMenuGL& menu, U32 flags); - virtual BOOL hasChildren() const; + virtual bool hasChildren() const; virtual BOOL dragOrDrop(MASK mask, BOOL drop, EDragAndDropType cargo_type, void* cargo_data); @@ -283,8 +300,8 @@ class LLFolderBridge : public LLInvFVBridge LLHandle getHandle() { mHandle.bind(this); return mHandle; } protected: - void buildContextMenuBaseOptions(U32 flags); - void buildContextMenuFolderOptions(U32 flags); + void buildContextMenuOptions(U32 flags, menuentry_vec_t& items, menuentry_vec_t& disabled_items); + void buildContextMenuFolderOptions(U32 flags, menuentry_vec_t& items, menuentry_vec_t& disabled_items); //-------------------------------------------------------------------- // Menu callbacks @@ -313,8 +330,6 @@ class LLFolderBridge : public LLInvFVBridge void modifyOutfit(BOOL append); void determineFolderType(); - menuentry_vec_t getMenuItems() { return mItems; } // returns a copy of current menu items - void dropToFavorites(LLInventoryItem* inv_item); void dropToOutfit(LLInventoryItem* inv_item, BOOL move_is_into_current_outfit); @@ -325,11 +340,15 @@ class LLFolderBridge : public LLInvFVBridge static LLHandle sSelf; static void staticFolderOptionsMenu(); -private: - BOOL mCallingCards; - BOOL mWearables; - menuentry_vec_t mItems; - menuentry_vec_t mDisabledItems; +protected: + void callback_pasteFromClipboard(const LLSD& notification, const LLSD& response, bool only_copies); + void perform_pasteFromClipboard(bool only_copies); + void gatherMessage(std::string& message, S32 depth, LLError::ELevel log_level); + LLUIImagePtr getFolderIcon(BOOL is_open) const; + + bool mCallingCards; + bool mWearables; + std::string mMessage; LLRootHandle mHandle; }; @@ -362,6 +381,7 @@ class LLSoundBridge : public LLItemBridge virtual void openItem(); virtual void previewItem(); virtual void buildContextMenu(LLMenuGL& menu, U32 flags); + virtual void performAction(LLInventoryModel* model, std::string action); static void openSoundPreview(void*); }; @@ -405,7 +425,6 @@ class LLCallingCardBridge : public LLItemBridge LLCallingCardObserver* mObserver; }; - class LLNotecardBridge : public LLItemBridge { public: @@ -415,6 +434,7 @@ class LLNotecardBridge : public LLItemBridge const LLUUID& uuid) : LLItemBridge(inventory, root, uuid) {} virtual void openItem(); + virtual void buildContextMenu(LLMenuGL& menu, U32 flags); }; class LLGestureBridge : public LLItemBridge @@ -436,7 +456,6 @@ class LLGestureBridge : public LLItemBridge static void playGesture(const LLUUID& item_id); }; - class LLAnimationBridge : public LLItemBridge { public: @@ -450,7 +469,6 @@ class LLAnimationBridge : public LLItemBridge virtual void openItem(); }; - class LLObjectBridge : public LLItemBridge { public: @@ -463,6 +481,7 @@ class LLObjectBridge : public LLItemBridge virtual LLUIImagePtr getIcon() const; virtual void performAction(LLInventoryModel* model, std::string action); virtual void openItem(); + virtual BOOL isItemWearable() const { return TRUE; } virtual std::string getLabelSuffix() const; virtual void buildContextMenu(LLMenuGL& menu, U32 flags); virtual BOOL renameItem(const std::string& new_name); @@ -496,6 +515,7 @@ class LLWearableBridge : public LLItemBridge virtual LLUIImagePtr getIcon() const; virtual void performAction(LLInventoryModel* model, std::string action); virtual void openItem(); + virtual BOOL isItemWearable() const { return TRUE; } virtual void buildContextMenu(LLMenuGL& menu, U32 flags); virtual std::string getLabelSuffix() const; virtual BOOL renameItem(const std::string& new_name); @@ -515,8 +535,6 @@ class LLWearableBridge : public LLItemBridge void editOnAvatar(); static BOOL canRemoveFromAvatar( void* userdata ); - //static void onRemoveFromAvatar( void* userdata ); - //static void onRemoveFromAvatarArrived( LLViewerWearable* wearable, void* userdata ); //static void removeAllClothesFromAvatar(); void removeFromAvatar(); protected: @@ -562,7 +580,6 @@ class LLMeshBridge : public LLItemBridge public: virtual LLUIImagePtr getIcon() const; virtual void openItem(); - virtual void previewItem(); virtual void buildContextMenu(LLMenuGL& menu, U32 flags); protected: @@ -626,10 +643,10 @@ class LLRecentItemsFolderBridge : public LLFolderBridge }; // Bridge builder to create Inventory-Folder-View-Bridge for Recent Inventory Panel -class LLRecentInventoryBridgeBuilder : public LLInventoryFVBridgeBuilder +class LLRecentInventoryBridgeBuilder : public LLInventoryFolderViewModelBuilder { public: - LLRecentInventoryBridgeBuilder(): LLInventoryFVBridgeBuilder() {} + LLRecentInventoryBridgeBuilder() {} // Overrides FolderBridge for Recent Inventory Panel. // It use base functionality for bridges other than FolderBridge. virtual LLInvFVBridge* createBridge(LLAssetType::EType asset_type, @@ -641,6 +658,31 @@ class LLRecentInventoryBridgeBuilder : public LLInventoryFVBridgeBuilder U32 flags = 0x00) const; }; +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Marketplace Inventory Panel related classes +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class LLMarketplaceFolderBridge : public LLFolderBridge +{ +public: + // Overloads some display related methods specific to folders in a marketplace floater context + LLMarketplaceFolderBridge(LLInventoryPanel* inventory, + LLFolderView* root, + const LLUUID& uuid); + + virtual LLUIImagePtr getIcon() const; + virtual LLUIImagePtr getIconOpen() const; + virtual std::string getLabelSuffix() const; + virtual LLFontGL::StyleFlags getLabelStyle() const; + +private: + LLUIImagePtr getMarketplaceFolderIcon(BOOL is_open) const; + // Those members are mutable because they are cached variables to speed up display, not a state variables + mutable S32 m_depth; + mutable S32 m_stockCountCache; +}; + + void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attachment, bool replace = false); @@ -661,4 +703,15 @@ void hide_context_entries(LLMenuGL& menu, const menuentry_vec_t &entries_to_show, const menuentry_vec_t &disabled_entries); +class LLFolderViewGroupedItemBridge: public LLFolderViewGroupedItemModel +{ +public: + LLFolderViewGroupedItemBridge(); + virtual void groupFilterContextMenu(folder_view_item_deque& selected_items, LLMenuGL& menu); +}; + +// Helper functions to classify actions. +bool isAddAction(const std::string& action); +bool isRemoveAction(const std::string& action); + #endif // LL_LLINVENTORYBRIDGE_H diff --git a/indra/newview/llinventoryclipboard.cpp b/indra/newview/llinventoryclipboard.cpp index 50a9d2a921..fd121ee010 100644 --- a/indra/newview/llinventoryclipboard.cpp +++ b/indra/newview/llinventoryclipboard.cpp @@ -52,23 +52,23 @@ LLInventoryClipboard::~LLInventoryClipboard() void LLInventoryClipboard::add(const LLUUID& object) { - mObjects.put(object); + mObjects.push_back(object); } // this stores a single inventory object void LLInventoryClipboard::store(const LLUUID& object) { reset(); - mObjects.put(object); + mObjects.push_back(object); } -void LLInventoryClipboard::store(const LLDynamicArray& inv_objects) +void LLInventoryClipboard::store(const uuid_vec_t& inv_objects) { reset(); - S32 count = inv_objects.count(); + S32 count = inv_objects.size(); for(S32 i = 0; i < count; i++) { - mObjects.put(inv_objects[i]); + mObjects.push_back(inv_objects[i]); } } @@ -82,32 +82,32 @@ void LLInventoryClipboard::cut(const LLUUID& object) mCutMode = true; add(object); } -void LLInventoryClipboard::retrieve(LLDynamicArray& inv_objects) const +void LLInventoryClipboard::retrieve(uuid_vec_t& inv_objects) const { - inv_objects.reset(); - S32 count = mObjects.count(); + inv_objects.clear(); + S32 count = mObjects.size(); for(S32 i = 0; i < count; i++) { - inv_objects.put(mObjects[i]); + inv_objects.push_back(mObjects[i]); } } void LLInventoryClipboard::reset() { - mObjects.reset(); + mObjects.clear(); mCutMode = false; } // returns true if the clipboard has something pasteable in it. BOOL LLInventoryClipboard::hasContents() const { - return (mObjects.count() > 0); + return (mObjects.size() > 0); } // returns true if the input uuid is in the list of clipboard objects. bool LLInventoryClipboard::isOnClipboard(const LLUUID& object) const { - std::vector::const_iterator iter = std::find(mObjects.begin(), mObjects.end(), object); + auto iter = std::find(mObjects.begin(), mObjects.end(), object); return (iter != mObjects.end()); } diff --git a/indra/newview/llinventoryclipboard.h b/indra/newview/llinventoryclipboard.h index 398ac5c11a..e6d4938820 100644 --- a/indra/newview/llinventoryclipboard.h +++ b/indra/newview/llinventoryclipboard.h @@ -27,7 +27,6 @@ #ifndef LL_LLINVENTORYCLIPBOARD_H #define LL_LLINVENTORYCLIPBOARD_H -#include "lldarray.h" #include "lluuid.h" //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -52,12 +51,12 @@ class LLInventoryClipboard void store(const LLUUID& object); // this method stores an array of objects - void store(const LLDynamicArray& inventory_objects); + void store(const uuid_vec_t& inventory_objects); void cut(const LLUUID& object); // this method gets the objects in the clipboard by copying them // into the array provided. - void retrieve(LLDynamicArray& inventory_objects) const; + void retrieve(uuid_vec_t& inventory_objects) const; // this method empties out the clipboard void reset(); @@ -73,7 +72,7 @@ class LLInventoryClipboard protected: static LLInventoryClipboard sInstance; - LLDynamicArray mObjects; + uuid_vec_t mObjects; bool mCutMode; public: diff --git a/indra/newview/llinventoryfilter.cpp b/indra/newview/llinventoryfilter.cpp index ceabe493a3..c43103fce5 100644 --- a/indra/newview/llinventoryfilter.cpp +++ b/indra/newview/llinventoryfilter.cpp @@ -29,75 +29,75 @@ #include "llinventoryfilter.h" // viewer includes +#include "llappearancemgr.h" #include "llfoldervieweventlistener.h" #include "llfolderviewitem.h" +#include "llinventoryfunctions.h" #include "llinventorymodel.h" #include "llinventorymodelbackgroundfetch.h" +#include "llinventoryfunctions.h" +#include "llmarketplacefunctions.h" #include "llviewercontrol.h" #include "llfolderview.h" #include "llinventorybridge.h" #include "llviewerfoldertype.h" +#include "llstartup.h" #include "llagentwearables.h" #include "llvoavatarself.h" -#include "llinventoryclipboard.h" // linden library includes +#include "llinventoryclipboard.h" #include "lltrans.h" -LLInventoryFilter::FilterOps::FilterOps() : - mFilterObjectTypes(0xffffffffffffffffULL), - mFilterCategoryTypes(0xffffffffffffffffULL), - mFilterWearableTypes(0xffffffffffffffffULL), - mMinDate(time_min()), - mMaxDate(time_max()), - mHoursAgo(0), - mShowFolderState(SHOW_NON_EMPTY_FOLDERS), - mPermissions(PERM_NONE), - mFilterTypes(FILTERTYPE_OBJECT), - mFilterWorn(false), - mFilterUUID(LLUUID::null), - mFilterLinks(FILTERLINK_INCLUDE_LINKS) +LLInventoryFilter::FilterOps::FilterOps(const Params& p) +: mFilterTypes(p.types), + mFilterObjectTypes(p.object_types), + mFilterWearableTypes(p.wearable_types), + mFilterCategoryTypes(p.category_types), + mFilterLinks(p.links), + mFilterUUID(p.uuid), + mMinDate(p.date_range.min_date), + mMaxDate(p.date_range.max_date), + mHoursAgo(p.hours_ago), + mDateSearchDirection(p.date_search_direction), + mShowFolderState(p.show_folder_state), + mPermissions(p.permissions), + mFilterWornItems(p.worn_items) { } ///---------------------------------------------------------------------------- /// Class LLInventoryFilter ///---------------------------------------------------------------------------- -LLInventoryFilter::LLInventoryFilter(const std::string& name) -: mName(name), - mModified(FALSE), - mNeedTextRebuild(TRUE) +LLInventoryFilter::LLInventoryFilter(const Params& p) +: mFilterOps(p.filter_ops), + mFilterSubString(p.substring), + mName(p.name), + mFilterModified(FILTER_NONE), + mEmptyLookupMessage("InventoryNoMatchingItems"), + mCurrentGeneration(0), + mFirstRequiredGeneration(0), + mFirstSuccessGeneration(0) { mOrder = SO_FOLDERS_BY_NAME; // This gets overridden by a pref immediately - mSubStringMatchOffset = 0; - mFilterSubString.clear(); - mFilterGeneration = 0; - mMustPassGeneration = S32_MAX; - mMinRequiredGeneration = 0; + mSubStringMatchOffset = std::string::npos; mFilterCount = 0; - mNextFilterGeneration = mFilterGeneration + 1; - - mLastLogoff = gSavedPerAccountSettings.getU32("LastLogoff"); - mFilterBehavior = FILTER_NONE; + // Singu Note: Why aren't we calling fromParams here? // copy mFilterOps into mDefaultFilterOps markDefault(); } -LLInventoryFilter::~LLInventoryFilter() -{ -} - -BOOL LLInventoryFilter::check(LLFolderViewItem* item) +bool LLInventoryFilter::check(LLFolderViewItem* item) { // Clipboard cut items are *always* filtered so we need this value upfront const LLFolderViewEventListener* listener = item->getListener(); const LLUUID item_id = listener ? listener->getUUID() : LLUUID::null; - const bool passed_clipboard = item_id.notNull() ? checkAgainstClipboard(item_id) : true; + const bool passed_clipboard = listener && item_id.notNull() ? checkAgainstClipboard(item_id) : true; // If it's a folder and we're showing all folders, return automatically. - const BOOL is_folder = (dynamic_cast(item) != NULL); + const BOOL is_folder = listener->getInventoryType() == LLInventoryType::IT_CATEGORY; if (is_folder && (mFilterOps.mShowFolderState == LLInventoryFilter::SHOW_ALL_FOLDERS)) { return passed_clipboard; @@ -105,17 +105,16 @@ BOOL LLInventoryFilter::check(LLFolderViewItem* item) mSubStringMatchOffset = mFilterSubString.size() ? item->getSearchableLabel().find(mFilterSubString) : std::string::npos; - const BOOL passed_filtertype = checkAgainstFilterType(item); - const BOOL passed_permissions = checkAgainstPermissions(item); - const BOOL passed_filterlink = checkAgainstFilterLinks(item); - const BOOL passed_wearable = !mFilterOps.mFilterWorn || (gAgentWearables.isWearingItem(item_id) || (gAgentAvatarp && gAgentAvatarp->isWearingAttachment(item_id))); - const BOOL passed = (passed_filtertype && + const bool passed_filtertype = checkAgainstFilterType(item); + const bool passed_permissions = checkAgainstPermissions(item); + const bool passed_filterlink = checkAgainstFilterLinks(item); + const bool passed_wearable = (mFilterOps.mFilterTypes & FILTERTYPE_WORN) != FILTERTYPE_WORN || (gAgentWearables.isWearingItem(item_id) || (gAgentAvatarp && gAgentAvatarp->isWearingAttachment(item_id))); + const bool passed = (passed_filtertype && passed_permissions && passed_filterlink && passed_clipboard && passed_wearable && (mFilterSubString.size() == 0 || mSubStringMatchOffset != std::string::npos)); - return passed; } @@ -123,7 +122,7 @@ bool LLInventoryFilter::checkFolder(const LLFolderViewFolder* folder) const { if (!folder) { - llwarns << "The filter can not be checked on an invalid folder." << llendl; + LL_WARNS() << "The filter can not be checked on an invalid folder." << LL_ENDL; llassert(false); // crash in development builds return false; } @@ -131,13 +130,17 @@ bool LLInventoryFilter::checkFolder(const LLFolderViewFolder* folder) const const LLFolderViewEventListener* listener = folder->getListener(); if (!listener) { - llwarns << "Folder view event listener not found." << llendl; - llassert(false); // crash in development builds + LL_ERRS() << "Folder view event listener not found." << LL_ENDL; return false; } const LLUUID folder_id = listener->getUUID(); - + + return checkFolder(folder_id); +} + +bool LLInventoryFilter::checkFolder(const LLUUID& folder_id) const +{ // Always check against the clipboard const BOOL passed_clipboard = checkAgainstClipboard(folder_id); @@ -147,13 +150,81 @@ bool LLInventoryFilter::checkFolder(const LLFolderViewFolder* folder) const return passed_clipboard; } + // when applying a filter, matching folders get their contents downloaded first + // but make sure we are not interfering with pre-download + if (isNotDefault() + && !gInventory.isCategoryComplete(folder_id) + && LLStartUp::getStartupState() > STATE_WEARABLES_WAIT) + { + LLInventoryModelBackgroundFetch::instance().start(folder_id); + } + + // Marketplace folder filtering + const U32 filterTypes = mFilterOps.mFilterTypes; + const U32 marketplace_filter = FILTERTYPE_MARKETPLACE_ACTIVE | FILTERTYPE_MARKETPLACE_INACTIVE | + FILTERTYPE_MARKETPLACE_UNASSOCIATED | FILTERTYPE_MARKETPLACE_LISTING_FOLDER | + FILTERTYPE_NO_MARKETPLACE_ITEMS; + if (filterTypes & marketplace_filter) + { + S32 depth = depth_nesting_in_marketplace(folder_id); + + if (filterTypes & FILTERTYPE_NO_MARKETPLACE_ITEMS) + { + if (depth >= 0) + { + return false; + } + } + + if (filterTypes & FILTERTYPE_MARKETPLACE_LISTING_FOLDER) + { + if (depth > 1) + { + return false; + } + } + + if (depth > 0) + { + LLUUID listing_uuid = nested_parent_id(folder_id, depth); + if (filterTypes & FILTERTYPE_MARKETPLACE_ACTIVE) + { + if (!LLMarketplaceData::instance().getActivationState(listing_uuid)) + { + return false; + } + } + else if (filterTypes & FILTERTYPE_MARKETPLACE_INACTIVE) + { + if (!LLMarketplaceData::instance().isListed(listing_uuid) || LLMarketplaceData::instance().getActivationState(listing_uuid)) + { + return false; + } + } + else if (filterTypes & FILTERTYPE_MARKETPLACE_UNASSOCIATED) + { + if (LLMarketplaceData::instance().isListed(listing_uuid)) + { + return false; + } + } + } + } + + // show folder links + LLViewerInventoryItem* item = gInventory.getItem(folder_id); + if (item && item->getActualType() == LLAssetType::AT_LINK_FOLDER) + { + return passed_clipboard; + } + if (mFilterOps.mFilterTypes & FILTERTYPE_CATEGORY) { // Can only filter categories for items in your inventory // (e.g. versus in-world object contents). const LLViewerInventoryCategory *cat = gInventory.getCategory(folder_id); if (!cat) - return false; + return folder_id.isNull(); LLFolderType::EType cat_type = cat->getPreferredType(); if (cat_type != LLFolderType::FT_NONE && (1LL << cat_type & mFilterOps.mFilterCategoryTypes) == U64(0)) return false; @@ -162,7 +233,7 @@ bool LLInventoryFilter::checkFolder(const LLFolderViewFolder* folder) const return passed_clipboard; } -BOOL LLInventoryFilter::checkAgainstFilterType(const LLFolderViewItem* item) const +bool LLInventoryFilter::checkAgainstFilterType(const LLFolderViewItem* item) const { const LLFolderViewEventListener* listener = item->getListener(); if (!listener) return FALSE; @@ -178,6 +249,7 @@ BOOL LLInventoryFilter::checkAgainstFilterType(const LLFolderViewItem* item) con // Pass if this item's type is of the correct filter type if (filterTypes & FILTERTYPE_OBJECT) { + // If it has no type, pass it, unless it's a link. if (object_type == LLInventoryType::IT_NONE) { @@ -210,6 +282,7 @@ BOOL LLInventoryFilter::checkAgainstFilterType(const LLFolderViewItem* item) con { const U16 HOURS_TO_SECONDS = 3600; time_t earliest = time_corrected() - mFilterOps.mHoursAgo * HOURS_TO_SECONDS; + if (mFilterOps.mMinDate > time_min() && mFilterOps.mMinDate < earliest) { earliest = mFilterOps.mMinDate; @@ -218,9 +291,19 @@ BOOL LLInventoryFilter::checkAgainstFilterType(const LLFolderViewItem* item) con { earliest = 0; } - if (listener->getCreationDate() < earliest || - listener->getCreationDate() > mFilterOps.mMaxDate) - return FALSE; + + if (FILTERDATEDIRECTION_NEWER == mFilterOps.mDateSearchDirection || isSinceLogoff()) + { + if (listener->getCreationDate() < earliest || + listener->getCreationDate() > mFilterOps.mMaxDate) + return FALSE; + } + else + { + if (listener->getCreationDate() > earliest || + listener->getCreationDate() > mFilterOps.mMaxDate) + return FALSE; + } } //////////////////////////////////////////////////////////////////////////////// @@ -245,16 +328,96 @@ BOOL LLInventoryFilter::checkAgainstFilterType(const LLFolderViewItem* item) con bool is_hidden_if_empty = LLViewerFolderType::lookupIsHiddenIfEmpty(listener->getPreferredType()); if (is_hidden_if_empty) { - // Force the fetching of those folders so they are hidden iff they really are empty... - gInventory.fetchDescendentsOf(object_id); - return FALSE; + // Force the fetching of those folders so they are hidden if they really are empty... + // But don't interfere with startup download + if (LLStartUp::getStartupState() > STATE_WEARABLES_WAIT) + { + gInventory.fetchDescendentsOf(object_id); + } + + LLInventoryModel::cat_array_t* cat_array = NULL; + LLInventoryModel::item_array_t* item_array = NULL; + gInventory.getDirectDescendentsOf(object_id,cat_array,item_array); + S32 descendents_actual = 0; + if (cat_array && item_array) + { + descendents_actual = cat_array->size() + item_array->size(); + } + if (descendents_actual == 0) + { + return FALSE; + } } } } + //////////////////////////////////////////////////////////////////////////////// + // FILTERTYPE_WORN + // Pass if this item is worn + if (filterTypes & FILTERTYPE_WORN) + { + if (!object) return FALSE; + LLUUID cat_id = object->getParentUUID(); + const LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id); + return (get_is_item_worn(object_id) // if it's worn + && !LLAppearanceMgr::instance().getIsInCOF(object_id) // if it's not in CoF + && (!cat || cat->getPreferredType() != LLFolderType::FT_OUTFIT) // if it's not in an outfit + && !object->getIsLinkType()); // and it's not a link + } + return TRUE; } +bool LLInventoryFilter::checkAgainstFilterType(const LLInventoryItem* item) const +{ + LLInventoryType::EType object_type = item->getInventoryType(); + const LLUUID object_id = item->getUUID(); + + const U32 filterTypes = mFilterOps.mFilterTypes; + + //////////////////////////////////////////////////////////////////////////////// + // FILTERTYPE_OBJECT + // Pass if this item's type is of the correct filter type + if (filterTypes & FILTERTYPE_OBJECT) + { + // If it has no type, pass it, unless it's a link. + if (object_type == LLInventoryType::IT_NONE) + { + if (item && item->getIsLinkType()) + { + return false; + } + } + else if ((1LL << object_type & mFilterOps.mFilterObjectTypes) == U64(0)) + { + return false; + } + } + + //////////////////////////////////////////////////////////////////////////////// + // FILTERTYPE_UUID + // Pass if this item is the target UUID or if it links to the target UUID + if (filterTypes & FILTERTYPE_UUID) + { + if (!item) return false; + + if (item->getLinkedUUID() != mFilterOps.mFilterUUID) + return false; + } + + //////////////////////////////////////////////////////////////////////////////// + // FILTERTYPE_DATE + // Pass if this item is within the date range. + if (filterTypes & FILTERTYPE_DATE) + { + // We don't get the updated item creation date for the task inventory or + // a notecard embedded item. See LLTaskInvFVBridge::getCreationDate(). + return false; + } + + return true; +} + // Items and folders that are on the clipboard or, recursively, in a folder which // is on the clipboard must be filtered out if the clipboard is in the "cut" mode. bool LLInventoryFilter::checkAgainstClipboard(const LLUUID& object_id) const @@ -279,7 +442,7 @@ bool LLInventoryFilter::checkAgainstClipboard(const LLUUID& object_id) const return true; } -BOOL LLInventoryFilter::checkAgainstPermissions(const LLFolderViewItem* item) const +bool LLInventoryFilter::checkAgainstPermissions(const LLFolderViewItem* item) const { const LLFolderViewEventListener* listener = item->getListener(); if (!listener) return FALSE; @@ -296,12 +459,23 @@ BOOL LLInventoryFilter::checkAgainstPermissions(const LLFolderViewItem* item) co return (perm & mFilterOps.mPermissions) == mFilterOps.mPermissions; } -BOOL LLInventoryFilter::checkAgainstFilterLinks(const LLFolderViewItem* item) const +bool LLInventoryFilter::checkAgainstPermissions(const LLInventoryItem* item) const +{ + if (!item) return false; + + LLPointer new_item = new LLViewerInventoryItem(item); + PermissionMask perm = new_item->getPermissionMask(); + new_item = NULL; + + return (perm & mFilterOps.mPermissions) == mFilterOps.mPermissions; +} + +bool LLInventoryFilter::checkAgainstFilterLinks(const LLFolderViewItem* item) const { const LLFolderViewEventListener* listener = item->getListener(); if (!listener) return TRUE; - const LLUUID object_id = listener->getUUID(); + const LLUUID& object_id = listener->getUUID(); const LLInventoryObject *object = gInventory.getObject(object_id); if (!object) return TRUE; @@ -323,27 +497,31 @@ std::string::size_type LLInventoryFilter::getStringMatchOffset() const return mSubStringMatchOffset; } +bool LLInventoryFilter::isDefault() const +{ + return !isNotDefault(); +} + // has user modified default filter params? -BOOL LLInventoryFilter::isNotDefault() const +bool LLInventoryFilter::isNotDefault() const { - BOOL not_default = FALSE; + bool not_default = false; not_default |= (mFilterOps.mFilterObjectTypes != mDefaultFilterOps.mFilterObjectTypes); not_default |= (mFilterOps.mFilterCategoryTypes != mDefaultFilterOps.mFilterCategoryTypes); not_default |= (mFilterOps.mFilterWearableTypes != mDefaultFilterOps.mFilterWearableTypes); not_default |= (mFilterOps.mFilterTypes != mDefaultFilterOps.mFilterTypes); not_default |= (mFilterOps.mFilterLinks != mDefaultFilterOps.mFilterLinks); - not_default |= (mFilterSubString.size()); - not_default |= (mFilterOps.mFilterWorn != mDefaultFilterOps.mFilterWorn); + not_default |= (mFilterSubString.size() > 0); not_default |= (mFilterOps.mPermissions != mDefaultFilterOps.mPermissions); not_default |= (mFilterOps.mMinDate != mDefaultFilterOps.mMinDate); not_default |= (mFilterOps.mMaxDate != mDefaultFilterOps.mMaxDate); not_default |= (mFilterOps.mHoursAgo != mDefaultFilterOps.mHoursAgo); - return not_default; + return not_default != 0; } -BOOL LLInventoryFilter::isActive() const +bool LLInventoryFilter::isActive() const { return mFilterOps.mFilterObjectTypes != 0xffffffffffffffffULL || mFilterOps.mFilterCategoryTypes != 0xffffffffffffffffULL @@ -351,23 +529,15 @@ BOOL LLInventoryFilter::isActive() const || mFilterOps.mFilterTypes != FILTERTYPE_OBJECT || mFilterOps.mFilterLinks != FILTERLINK_INCLUDE_LINKS || mFilterSubString.size() - || mFilterOps.mFilterWorn != false || mFilterOps.mPermissions != PERM_NONE || mFilterOps.mMinDate != time_min() || mFilterOps.mMaxDate != time_max() || mFilterOps.mHoursAgo != 0; } -BOOL LLInventoryFilter::isModified() const +bool LLInventoryFilter::isModified() const { - return mModified; -} - -BOOL LLInventoryFilter::isModifiedAndClear() -{ - BOOL ret = mModified; - mModified = FALSE; - return ret; + return mFilterModified != FILTER_NONE; } void LLInventoryFilter::updateFilterTypes(U64 types, U64& current_types) @@ -381,7 +551,7 @@ void LLInventoryFilter::updateFilterTypes(U64 types, U64& current_types) current_types = types; if (more_bits_set && fewer_bits_set) { - // neither less or more restrive, both simultaneously + // neither less or more restrictive, both simultaneously // so we need to filter from scratch setModified(FILTER_RESTART); } @@ -399,6 +569,8 @@ void LLInventoryFilter::updateFilterTypes(U64 types, U64& current_types) void LLInventoryFilter::setFilterObjectTypes(U64 types) { + if (types == mFilterOps.mFilterObjectTypes && mFilterOps.mFilterTypes & FILTERTYPE_OBJECT) + return; updateFilterTypes(types, mFilterOps.mFilterObjectTypes); mFilterOps.mFilterTypes |= FILTERTYPE_OBJECT; } @@ -420,8 +592,51 @@ void LLInventoryFilter::setFilterEmptySystemFolders() mFilterOps.mFilterTypes |= FILTERTYPE_EMPTYFOLDERS; } +void LLInventoryFilter::setFilterWornItems() +{ + mFilterOps.mFilterTypes |= FILTERTYPE_WORN; +} + +void LLInventoryFilter::setFilterMarketplaceActiveFolders() +{ + mFilterOps.mFilterTypes |= FILTERTYPE_MARKETPLACE_ACTIVE; +} + +void LLInventoryFilter::setFilterMarketplaceInactiveFolders() +{ + mFilterOps.mFilterTypes |= FILTERTYPE_MARKETPLACE_INACTIVE; +} + +void LLInventoryFilter::setFilterMarketplaceUnassociatedFolders() +{ + mFilterOps.mFilterTypes |= FILTERTYPE_MARKETPLACE_UNASSOCIATED; +} + +void LLInventoryFilter::setFilterMarketplaceListingFolders(bool select_only_listing_folders) +{ + if (select_only_listing_folders) + { + mFilterOps.mFilterTypes |= FILTERTYPE_MARKETPLACE_LISTING_FOLDER; + setModified(FILTER_MORE_RESTRICTIVE); + } + else + { + mFilterOps.mFilterTypes &= ~FILTERTYPE_MARKETPLACE_LISTING_FOLDER; + setModified(FILTER_LESS_RESTRICTIVE); + } +} + +void LLInventoryFilter::setFilterNoMarketplaceFolder() +{ + mFilterOps.mFilterTypes |= FILTERTYPE_NO_MARKETPLACE_ITEMS; +} + void LLInventoryFilter::setFilterUUID(const LLUUID& object_id) { + if (mFilterOps.mFilterUUID == object_id) + { + return; + } if (mFilterOps.mFilterUUID == LLUUID::null) { setModified(FILTER_MORE_RESTRICTIVE); @@ -431,7 +646,10 @@ void LLInventoryFilter::setFilterUUID(const LLUUID& object_id) setModified(FILTER_RESTART); } mFilterOps.mFilterUUID = object_id; - mFilterOps.mFilterTypes = FILTERTYPE_UUID; + if(object_id.isNull()) + mFilterOps.mFilterTypes &= ~FILTERTYPE_UUID; + else + mFilterOps.mFilterTypes |= FILTERTYPE_UUID; } void LLInventoryFilter::setFilterSubString(const std::string& string) @@ -466,18 +684,12 @@ void LLInventoryFilter::setFilterSubString(const std::string& string) } // Cancel out UUID once the search string is modified - if (mFilterOps.mFilterTypes == FILTERTYPE_UUID) + if (mFilterOps.mFilterTypes & FILTERTYPE_UUID) { mFilterOps.mFilterTypes &= ~FILTERTYPE_UUID; - //mFilterOps.mFilterUUID == LLUUID::null; + mFilterOps.mFilterUUID == LLUUID::null; setModified(FILTER_RESTART); } - - // Cancel out filter links once the search string is modified - // Singu Note: No, don't do this... - { - //mFilterOps.mFilterLinks = FILTERLINK_INCLUDE_LINKS; - } } } @@ -519,39 +731,53 @@ void LLInventoryFilter::setDateRange(time_t min_date, time_t max_date) mFilterOps.mMaxDate = llmax(mFilterOps.mMinDate, max_date); setModified(); } - mFilterOps.mFilterTypes |= FILTERTYPE_DATE; + + if (areDateLimitsSet()) + { + mFilterOps.mFilterTypes |= FILTERTYPE_DATE; + } + else + { + mFilterOps.mFilterTypes &= ~FILTERTYPE_DATE; + } } void LLInventoryFilter::setDateRangeLastLogoff(BOOL sl) { + static LLCachedControl s_last_logoff(gSavedPerAccountSettings, "LastLogoff", 0); if (sl && !isSinceLogoff()) { - setDateRange(mLastLogoff, time_max()); + setDateRange(s_last_logoff, time_max()); setModified(); } if (!sl && isSinceLogoff()) { - setDateRange(0, time_max()); + setDateRange(time_min(), time_max()); setModified(); } - mFilterOps.mFilterTypes |= FILTERTYPE_DATE; + + if (areDateLimitsSet()) + { + mFilterOps.mFilterTypes |= FILTERTYPE_DATE; + } + else + { + mFilterOps.mFilterTypes &= ~FILTERTYPE_DATE; + } } -BOOL LLInventoryFilter::isSinceLogoff() const +bool LLInventoryFilter::isSinceLogoff() const { - bool min_date = (mFilterOps.mMinDate == (time_t)mLastLogoff); + static LLCachedControl s_last_logoff(gSavedSettings, "LastLogoff", 0); + bool min_date = (mFilterOps.mMinDate == (time_t)s_last_logoff); bool max_date = (mFilterOps.mMaxDate == time_max()); bool is_filter = (mFilterOps.mFilterTypes & FILTERTYPE_DATE); return min_date && max_date && is_filter; - //return (mFilterOps.mMinDate == (time_t)mLastLogoff) && - // (mFilterOps.mMaxDate == time_max()) && - // (mFilterOps.mFilterTypes & FILTERTYPE_DATE); } void LLInventoryFilter::clearModified() { - mModified = FALSE; - mFilterBehavior = FILTER_NONE; + mFilterModified = FILTER_NONE; } void LLInventoryFilter::setHoursAgo(U32 hours) @@ -560,12 +786,37 @@ void LLInventoryFilter::setHoursAgo(U32 hours) { bool are_date_limits_valid = mFilterOps.mMinDate == time_min() && mFilterOps.mMaxDate == time_max(); - bool is_increasing = hours > mFilterOps.mHoursAgo; - bool is_increasing_from_zero = is_increasing && !mFilterOps.mHoursAgo; - // *NOTE: need to cache last filter time, in case filter goes stale - BOOL less_restrictive = ((are_date_limits_valid && ((is_increasing && mFilterOps.mHoursAgo))) || !hours); - BOOL more_restrictive = ((are_date_limits_valid && (!is_increasing && hours)) || is_increasing_from_zero); + bool less_restrictive = false; + bool more_restrictive = false; + + switch (mFilterOps.mDateSearchDirection) + { + case FILTERDATEDIRECTION_NEWER: + less_restrictive = ((are_date_limits_valid && (hours > mFilterOps.mHoursAgo + && mFilterOps.mHoursAgo)) + || !hours); + + more_restrictive = ((are_date_limits_valid && (hours < mFilterOps.mHoursAgo + && hours)) + || (hours > mFilterOps.mHoursAgo + && !mFilterOps.mHoursAgo + && !isSinceLogoff())); + break; + case FILTERDATEDIRECTION_OLDER: + less_restrictive = ((are_date_limits_valid && (hours < mFilterOps.mHoursAgo + && mFilterOps.mHoursAgo)) + || !hours); + + more_restrictive = ((are_date_limits_valid && (hours > mFilterOps.mHoursAgo + && hours)) + || (hours < mFilterOps.mHoursAgo + && !mFilterOps.mHoursAgo + && !isSinceLogoff())); + break; + default: + break; + } mFilterOps.mHoursAgo = hours; mFilterOps.mMinDate = time_min(); @@ -583,20 +834,42 @@ void LLInventoryFilter::setHoursAgo(U32 hours) setModified(FILTER_RESTART); } } - mFilterOps.mFilterTypes |= FILTERTYPE_DATE; + + if (areDateLimitsSet()) + { + mFilterOps.mFilterTypes |= FILTERTYPE_DATE; + } + else + { + mFilterOps.mFilterTypes &= ~FILTERTYPE_DATE; + } } -void LLInventoryFilter::setFilterLinks(U64 filter_links) +void LLInventoryFilter::setDateSearchDirection(U32 direction) +{ + if (direction != mFilterOps.mDateSearchDirection) + { + mFilterOps.mDateSearchDirection = direction; + setModified(FILTER_RESTART); + } +} + +U32 LLInventoryFilter::getDateSearchDirection() const +{ + return mFilterOps.mDateSearchDirection; +} + +void LLInventoryFilter::setFilterLinks(EFilterLink filter_links) { if (mFilterOps.mFilterLinks != filter_links) { - if (mFilterOps.mFilterLinks == FILTERLINK_EXCLUDE_LINKS || - mFilterOps.mFilterLinks == FILTERLINK_ONLY_LINKS) + mFilterOps.mFilterLinks = filter_links; + if (filter_links == FILTERLINK_EXCLUDE_LINKS || + filter_links == FILTERLINK_ONLY_LINKS) setModified(FILTER_MORE_RESTRICTIVE); else setModified(FILTER_LESS_RESTRICTIVE); } - mFilterOps.mFilterLinks = filter_links; } void LLInventoryFilter::setShowFolderState(EFolderShow state) @@ -641,83 +914,68 @@ void LLInventoryFilter::resetDefault() setModified(); } -void LLInventoryFilter::setModified(EFilterBehavior behavior) +void LLInventoryFilter::setModified(EFilterModified behavior) { - mModified = TRUE; - mNeedTextRebuild = TRUE; - mFilterGeneration = mNextFilterGeneration++; + mFilterText.clear(); + mCurrentGeneration++; - if (mFilterBehavior == FILTER_NONE) + if (mFilterModified == FILTER_NONE) { - mFilterBehavior = behavior; + mFilterModified = behavior; } - else if (mFilterBehavior != behavior) + else if (mFilterModified != behavior) { // trying to do both less restrictive and more restrictive filter // basically means restart from scratch - mFilterBehavior = FILTER_RESTART; + mFilterModified = FILTER_RESTART; } - if (isNotDefault()) + // if not keeping current filter results, update last valid as well + switch(mFilterModified) { - // if not keeping current filter results, update last valid as well - switch(mFilterBehavior) - { - case FILTER_RESTART: - mMustPassGeneration = mFilterGeneration; - mMinRequiredGeneration = mFilterGeneration; - break; - case FILTER_LESS_RESTRICTIVE: - mMustPassGeneration = mFilterGeneration; - break; - case FILTER_MORE_RESTRICTIVE: - mMinRequiredGeneration = mFilterGeneration; - // must have passed either current filter generation (meaningless, as it hasn't been run yet) - // or some older generation, so keep the value - mMustPassGeneration = llmin(mMustPassGeneration, mFilterGeneration); - break; - default: - llerrs << "Bad filter behavior specified" << llendl; - } - } - else - { - // shortcut disabled filters to show everything immediately - mMinRequiredGeneration = 0; - mMustPassGeneration = S32_MAX; + case FILTER_RESTART: + mFirstRequiredGeneration = mCurrentGeneration; + mFirstSuccessGeneration = mCurrentGeneration; + break; + case FILTER_LESS_RESTRICTIVE: + mFirstRequiredGeneration = mCurrentGeneration; + break; + case FILTER_MORE_RESTRICTIVE: + mFirstSuccessGeneration = mCurrentGeneration; + break; + default: + LL_ERRS() << "Bad filter behavior specified" << LL_ENDL; } } -BOOL LLInventoryFilter::isFilterObjectTypesWith(LLInventoryType::EType t) const +bool LLInventoryFilter::isFilterObjectTypesWith(LLInventoryType::EType t) const { return mFilterOps.mFilterObjectTypes & (1LL << t); } const std::string& LLInventoryFilter::getFilterText() { - if (!mNeedTextRebuild) + if (!mFilterText.empty()) { return mFilterText; } - mNeedTextRebuild = FALSE; std::string filtered_types; std::string not_filtered_types; BOOL filtered_by_type = FALSE; BOOL filtered_by_all_types = TRUE; S32 num_filter_types = 0; + mFilterText.clear(); if (isFilterObjectTypesWith(LLInventoryType::IT_ANIMATION)) { - //filtered_types += " Animations,"; filtered_types += LLTrans::getString("Animations"); filtered_by_type = TRUE; num_filter_types++; } else { - //not_filtered_types += " Animations,"; not_filtered_types += LLTrans::getString("Animations"); filtered_by_all_types = FALSE; @@ -725,146 +983,126 @@ const std::string& LLInventoryFilter::getFilterText() if (isFilterObjectTypesWith(LLInventoryType::IT_CALLINGCARD)) { - //filtered_types += " Calling Cards,"; filtered_types += LLTrans::getString("Calling Cards"); filtered_by_type = TRUE; num_filter_types++; } else { - //not_filtered_types += " Calling Cards,"; not_filtered_types += LLTrans::getString("Calling Cards"); filtered_by_all_types = FALSE; } if (isFilterObjectTypesWith(LLInventoryType::IT_WEARABLE)) { - //filtered_types += " Clothing,"; filtered_types += LLTrans::getString("Clothing"); filtered_by_type = TRUE; num_filter_types++; } else { - //not_filtered_types += " Clothing,"; not_filtered_types += LLTrans::getString("Clothing"); filtered_by_all_types = FALSE; } if (isFilterObjectTypesWith(LLInventoryType::IT_GESTURE)) { - //filtered_types += " Gestures,"; filtered_types += LLTrans::getString("Gestures"); filtered_by_type = TRUE; num_filter_types++; } else { - //not_filtered_types += " Gestures,"; not_filtered_types += LLTrans::getString("Gestures"); filtered_by_all_types = FALSE; } if (isFilterObjectTypesWith(LLInventoryType::IT_LANDMARK)) { - //filtered_types += " Landmarks,"; filtered_types += LLTrans::getString("Landmarks"); filtered_by_type = TRUE; num_filter_types++; } else { - //not_filtered_types += " Landmarks,"; not_filtered_types += LLTrans::getString("Landmarks"); filtered_by_all_types = FALSE; } if (isFilterObjectTypesWith(LLInventoryType::IT_NOTECARD)) { - //filtered_types += " Notecards,"; filtered_types += LLTrans::getString("Notecards"); filtered_by_type = TRUE; num_filter_types++; } else { - //not_filtered_types += " Notecards,"; not_filtered_types += LLTrans::getString("Notecards"); filtered_by_all_types = FALSE; } - + if (isFilterObjectTypesWith(LLInventoryType::IT_OBJECT) && isFilterObjectTypesWith(LLInventoryType::IT_ATTACHMENT)) { - //filtered_types += " Objects,"; filtered_types += LLTrans::getString("Objects"); filtered_by_type = TRUE; num_filter_types++; } else { - //not_filtered_types += " Objects,"; not_filtered_types += LLTrans::getString("Objects"); filtered_by_all_types = FALSE; } - + if (isFilterObjectTypesWith(LLInventoryType::IT_LSL)) { - //filtered_types += " Scripts,"; filtered_types += LLTrans::getString("Scripts"); filtered_by_type = TRUE; num_filter_types++; } else { - //not_filtered_types += " Scripts,"; not_filtered_types += LLTrans::getString("Scripts"); filtered_by_all_types = FALSE; } - + if (isFilterObjectTypesWith(LLInventoryType::IT_SOUND)) { - //filtered_types += " Sounds,"; filtered_types += LLTrans::getString("Sounds"); filtered_by_type = TRUE; num_filter_types++; } else { - //not_filtered_types += " Sounds,"; not_filtered_types += LLTrans::getString("Sounds"); filtered_by_all_types = FALSE; } if (isFilterObjectTypesWith(LLInventoryType::IT_TEXTURE)) { - //filtered_types += " Textures,"; filtered_types += LLTrans::getString("Textures"); filtered_by_type = TRUE; num_filter_types++; } else { - //not_filtered_types += " Textures,"; not_filtered_types += LLTrans::getString("Textures"); filtered_by_all_types = FALSE; } if (isFilterObjectTypesWith(LLInventoryType::IT_SNAPSHOT)) { - //filtered_types += " Snapshots,"; filtered_types += LLTrans::getString("Snapshots"); filtered_by_type = TRUE; num_filter_types++; } else { - //not_filtered_types += " Snapshots,"; not_filtered_types += LLTrans::getString("Snapshots"); filtered_by_all_types = FALSE; } - if (!LLInventoryModelBackgroundFetch::instance().folderFetchActive() - && filtered_by_type + if (!LLInventoryModelBackgroundFetch::instance().folderFetchActive() + && filtered_by_type && !filtered_by_all_types) { mFilterText += " - "; @@ -874,7 +1112,6 @@ const std::string& LLInventoryFilter::getFilterText() } else { - //mFilterText += "No "; mFilterText += LLTrans::getString("No Filters"); mFilterText += not_filtered_types; } @@ -884,73 +1121,79 @@ const std::string& LLInventoryFilter::getFilterText() if (isSinceLogoff()) { - //mFilterText += " - Since Logoff"; mFilterText += LLTrans::getString("Since Logoff"); } - - if (getFilterWorn()) + + if (getFilterWornItems()) { - //mFilterText += " - Worn"; mFilterText += LLTrans::getString("Worn"); } - + return mFilterText; } -void LLInventoryFilter::toLLSD(LLSD& data) const +LLInventoryFilter& LLInventoryFilter::operator=( const LLInventoryFilter& other ) { - data["filter_types"] = (LLSD::Integer)getFilterObjectTypes(); - data["min_date"] = (LLSD::Integer)getMinDate(); - data["max_date"] = (LLSD::Integer)getMaxDate(); - data["hours_ago"] = (LLSD::Integer)getHoursAgo(); - data["show_folder_state"] = (LLSD::Integer)getShowFolderState(); - data["permissions"] = (LLSD::Integer)getFilterPermissions(); - data["substring"] = (LLSD::String)getFilterSubString(); - data["sort_order"] = (LLSD::Integer)getSortOrder(); - data["since_logoff"] = (LLSD::Boolean)isSinceLogoff(); + setFilterObjectTypes(other.getFilterObjectTypes()); + setDateRange(other.getMinDate(), other.getMaxDate()); + setHoursAgo(other.getHoursAgo()); + setDateSearchDirection(other.getDateSearchDirection()); + setShowFolderState(other.getShowFolderState()); + setFilterPermissions(other.getFilterPermissions()); + setFilterSubString(other.getFilterSubString()); + setDateRangeLastLogoff(other.isSinceLogoff()); + return *this; } -void LLInventoryFilter::fromLLSD(LLSD& data) -{ - if(data.has("filter_types")) - { - setFilterObjectTypes((U32)data["filter_types"].asInteger()); - } - - if(data.has("min_date") && data.has("max_date")) - { - setDateRange(data["min_date"].asInteger(), data["max_date"].asInteger()); - } - if(data.has("hours_ago")) - { - setHoursAgo((U32)data["hours_ago"].asInteger()); - } - - if(data.has("show_folder_state")) +void LLInventoryFilter::toParams(Params& params) const +{ + params.filter_ops.types = getFilterObjectTypes(); + params.filter_ops.category_types = getFilterCategoryTypes(); + if (getFilterObjectTypes() & FILTERTYPE_WEARABLE) { - setShowFolderState((EFolderShow)data["show_folder_state"].asInteger()); + params.filter_ops.wearable_types = getFilterWearableTypes(); } + params.filter_ops.date_range.min_date = getMinDate(); + params.filter_ops.date_range.max_date = getMaxDate(); + params.filter_ops.hours_ago = getHoursAgo(); + params.filter_ops.date_search_direction = getDateSearchDirection(); + params.filter_ops.show_folder_state = getShowFolderState(); + params.filter_ops.permissions = getFilterPermissions(); + params.substring = getFilterSubString(); + params.since_logoff = isSinceLogoff(); +} - if(data.has("permissions")) +void LLInventoryFilter::fromParams(const Params& params) +{ + if (!params.validateBlock()) { - setFilterPermissions((PermissionMask)data["permissions"].asInteger()); + return; } - if(data.has("substring")) + setFilterObjectTypes(params.filter_ops.types); + setFilterCategoryTypes(params.filter_ops.category_types); + if (params.filter_ops.wearable_types.isProvided()) { - setFilterSubString(std::string(data["substring"].asString())); + setFilterWearableTypes(params.filter_ops.wearable_types); } - if(data.has("sort_order")) + setDateRange(params.filter_ops.date_range.min_date, params.filter_ops.date_range.max_date); + setHoursAgo(params.filter_ops.hours_ago); + setDateSearchDirection(params.filter_ops.date_search_direction); + setShowFolderState(params.filter_ops.show_folder_state); + setFilterPermissions(params.filter_ops.permissions); + setFilterSubString(params.substring); + setDateRangeLastLogoff(params.since_logoff); + if (params.filter_ops.links.isProvided()) { - setSortOrder((U32)data["sort_order"].asInteger()); + setFilterLinks(params.filter_ops.links); } +} - if(data.has("since_logoff")) - { - setDateRangeLastLogoff((bool)data["since_logoff"].asBoolean()); - } +U64 LLInventoryFilter::getFilterTypes() const +{ + return mFilterOps.mFilterTypes; } U64 LLInventoryFilter::getFilterObjectTypes() const @@ -963,11 +1206,26 @@ U64 LLInventoryFilter::getFilterCategoryTypes() const return mFilterOps.mFilterCategoryTypes; } -BOOL LLInventoryFilter::hasFilterString() const +U64 LLInventoryFilter::getFilterWearableTypes() const +{ + return mFilterOps.mFilterWearableTypes; +} + +U64 LLInventoryFilter::getFilterWornItems() const +{ + return mFilterOps.mFilterTypes & FILTERTYPE_WORN; +} + +bool LLInventoryFilter::hasFilterString() const { return mFilterSubString.size() > 0; } +std::string::size_type LLInventoryFilter::getFilterStringSize() const +{ + return mFilterSubString.size(); +} + PermissionMask LLInventoryFilter::getFilterPermissions() const { return mFilterOps.mPermissions; @@ -986,7 +1244,7 @@ U32 LLInventoryFilter::getHoursAgo() const { return mFilterOps.mHoursAgo; } -U64 LLInventoryFilter::getFilterLinks() const +LLInventoryFilter::EFilterLink LLInventoryFilter::getFilterLinks() const { return mFilterOps.mFilterLinks; } @@ -998,10 +1256,6 @@ U32 LLInventoryFilter::getSortOrder() const { return mOrder; } -const std::string& LLInventoryFilter::getName() const -{ - return mName; -} void LLInventoryFilter::setFilterCount(S32 count) { @@ -1019,13 +1273,58 @@ void LLInventoryFilter::decrementFilterCount() S32 LLInventoryFilter::getCurrentGeneration() const { - return mFilterGeneration; + return mCurrentGeneration; } -S32 LLInventoryFilter::getMinRequiredGeneration() const +S32 LLInventoryFilter::getFirstSuccessGeneration() const { - return mMinRequiredGeneration; + return mFirstSuccessGeneration; } -S32 LLInventoryFilter::getMustPassGeneration() const +S32 LLInventoryFilter::getFirstRequiredGeneration() const { - return mMustPassGeneration; + return mFirstRequiredGeneration; +} + +void LLInventoryFilter::setEmptyLookupMessage(const std::string& message) +{ + mEmptyLookupMessage = message; +} + +std::string LLInventoryFilter::getEmptyLookupMessage() const +{ + LLStringUtil::format_map_t args; + args["[SEARCH_TERM]"] = LLURI::escape(getFilterSubStringOrig()); + + return LLTrans::getString(mEmptyLookupMessage, args); + +} + +bool LLInventoryFilter::areDateLimitsSet() +{ + return mFilterOps.mMinDate != time_min() + || mFilterOps.mMaxDate != time_max() + || mFilterOps.mHoursAgo != 0; +} + +bool LLInventoryFilter::showAllResults() const +{ + return hasFilterString(); +} + + + +bool LLInventoryFilter::FilterOps::DateRange::validateBlock( bool emit_errors /*= true*/ ) const +{ + bool valid = LLInitParam::Block::validateBlock(emit_errors); + if (valid) + { + if (max_date() < min_date()) + { + if (emit_errors) + { + LL_WARNS() << "max_date should be greater or equal to min_date" << LL_ENDL; + } + valid = false; + } + } + return valid; } diff --git a/indra/newview/llinventoryfilter.h b/indra/newview/llinventoryfilter.h index 588844c013..789e37dcf3 100644 --- a/indra/newview/llinventoryfilter.h +++ b/indra/newview/llinventoryfilter.h @@ -32,24 +32,25 @@ class LLFolderViewItem; class LLFolderViewFolder; +class LLInventoryItem; class LLInventoryFilter { public: - enum EFolderShow - { - SHOW_ALL_FOLDERS, - SHOW_NON_EMPTY_FOLDERS, - SHOW_NO_FOLDERS - }; - - enum EFilterBehavior + enum EFilterModified { FILTER_NONE, // nothing to do, already filtered FILTER_RESTART, // restart filtering from scratch FILTER_LESS_RESTRICTIVE, // existing filtered items will certainly pass this filter FILTER_MORE_RESTRICTIVE // if you didn't pass the previous filter, you definitely won't pass this one }; + + enum EFolderShow + { + SHOW_ALL_FOLDERS, + SHOW_NON_EMPTY_FOLDERS, + SHOW_NO_FOLDERS + }; enum EFilterType { FILTERTYPE_NONE = 0, @@ -58,7 +59,20 @@ class LLInventoryFilter FILTERTYPE_UUID = 0x1 << 2, // find the object with UUID and any links to it FILTERTYPE_DATE = 0x1 << 3, // search by date range FILTERTYPE_WEARABLE = 0x1 << 4, // search by wearable type - FILTERTYPE_EMPTYFOLDERS = 0x1 << 5 // pass if folder is not a system folder to be hidden if empty + FILTERTYPE_EMPTYFOLDERS = 0x1 << 5, // pass if folder is not a system folder to be hidden if empty + FILTERTYPE_MARKETPLACE_ACTIVE = 0x1 << 6, // pass if folder is a marketplace active folder + FILTERTYPE_MARKETPLACE_INACTIVE = 0x1 << 7, // pass if folder is a marketplace inactive folder + FILTERTYPE_MARKETPLACE_UNASSOCIATED = 0x1 << 8, // pass if folder is a marketplace non associated (no market ID) folder + FILTERTYPE_MARKETPLACE_LISTING_FOLDER = 0x1 << 9, // pass iff folder is a listing folder + FILTERTYPE_NO_MARKETPLACE_ITEMS = 0x1 << 10, // pass iff folder is not under the marketplace + FILTERTYPE_WORN = 0x1 << 11 // search by worn items + + }; + + enum EFilterDateDirection + { + FILTERDATEDIRECTION_NEWER, + FILTERDATEDIRECTION_OLDER }; enum EFilterLink @@ -73,32 +87,124 @@ class LLInventoryFilter SO_NAME = 0, // Sort inventory by name SO_DATE = 0x1, // Sort inventory by date SO_FOLDERS_BY_NAME = 0x1 << 1, // Force folder sort by name - SO_SYSTEM_FOLDERS_TO_TOP = 0x1 << 2 // Force system folders to be on top + SO_SYSTEM_FOLDERS_TO_TOP = 0x1 << 2, // Force system folders to be on top + SO_FOLDERS_BY_WEIGHT = 0x1 << 3, // Force folder sort by weight, usually, amount of some elements in their descendents }; - LLInventoryFilter(const std::string& name); - virtual ~LLInventoryFilter(); + struct FilterOps + { + struct DateRange : public LLInitParam::Block + { + Optional min_date, + max_date; + + DateRange() + : min_date("min_date", time_min()), + max_date("max_date", time_max()) + {} + + bool validateBlock(bool emit_errors = true) const; + }; + + struct Params : public LLInitParam::Block + { + Optional types; + Optional object_types, + wearable_types, + category_types, + worn_items; + Optional links; + Optional uuid; + Optional date_range; + Optional hours_ago; + Optional date_search_direction; + Optional show_folder_state; + Optional permissions; + + Params() + : types("filter_types", FILTERTYPE_OBJECT), + object_types("object_types", 0xffffFFFFffffFFFFULL), + wearable_types("wearable_types", 0/*0xffffFFFFffffFFFFULL*/), + category_types("category_types", 0xffffFFFFffffFFFFULL), + worn_items("worn_items", 0xffffFFFFffffFFFFULL), + links("links", FILTERLINK_INCLUDE_LINKS), + uuid("uuid"), + date_range("date_range"), + hours_ago("hours_ago", 0), + date_search_direction("date_search_direction", FILTERDATEDIRECTION_NEWER), + show_folder_state("show_folder_state", SHOW_NON_EMPTY_FOLDERS), + permissions("permissions", PERM_NONE) + { + addSynonym(links, "filter_links"); + } + }; + + FilterOps(const Params& = Params()); + + U32 mFilterTypes; + U64 mFilterObjectTypes, // For _OBJECT + mFilterWearableTypes, + mFilterCategoryTypes, // For _CATEGORY + mFilterWornItems; + EFilterLink mFilterLinks; + LLUUID mFilterUUID; // for UUID + + time_t mMinDate, + mMaxDate; + U32 mHoursAgo; + U32 mDateSearchDirection; + + EFolderShow mShowFolderState; + PermissionMask mPermissions; + + bool mFilterWorn; + }; + + struct Params : public LLInitParam::Block + { + Optional name; + Optional filter_ops; + Optional substring; + Optional since_logoff; + + Params() + : name("name"), + filter_ops(""), + substring("substring"), + since_logoff("since_logoff") + {} + }; + + LLInventoryFilter(const Params& p = Params()); + LLInventoryFilter(const LLInventoryFilter& other) { *this = other; } + virtual ~LLInventoryFilter() {} // +-------------------------------------------------------------------+ // + Parameters // +-------------------------------------------------------------------+ - void setFilterObjectTypes(U64 types); + U64 getFilterTypes() const; U64 getFilterObjectTypes() const; U64 getFilterCategoryTypes() const; - BOOL isFilterObjectTypesWith(LLInventoryType::EType t) const; + U64 getFilterWearableTypes() const; + U64 getFilterWornItems() const; + bool isFilterObjectTypesWith(LLInventoryType::EType t) const; + void setFilterObjectTypes(U64 types); void setFilterCategoryTypes(U64 types); void setFilterUUID(const LLUUID &object_id); void setFilterWearableTypes(U64 types); void setFilterEmptySystemFolders(); + void setFilterMarketplaceActiveFolders(); + void setFilterMarketplaceInactiveFolders(); + void setFilterMarketplaceUnassociatedFolders(); + void setFilterMarketplaceListingFolders(bool select_only_listing_folders); + void setFilterNoMarketplaceFolder(); void updateFilterTypes(U64 types, U64& current_types); + void setFilterWornItems(); void setFilterSubString(const std::string& string); const std::string& getFilterSubString(BOOL trim = FALSE) const; const std::string& getFilterSubStringOrig() const { return mFilterSubStringOrig; } - BOOL hasFilterString() const; - - void setFilterWorn(bool worn) { mFilterOps.mFilterWorn = worn; } - bool getFilterWorn() const { return mFilterOps.mFilterWorn; } + bool hasFilterString() const; void setFilterPermissions(PermissionMask perms); PermissionMask getFilterPermissions() const; @@ -110,46 +216,48 @@ class LLInventoryFilter void setHoursAgo(U32 hours); U32 getHoursAgo() const; + void setDateSearchDirection(U32 direction); + U32 getDateSearchDirection() const; - void setFilterLinks(U64 filter_link); - U64 getFilterLinks() const; + void setFilterLinks(EFilterLink filter_link); + EFilterLink getFilterLinks() const; // +-------------------------------------------------------------------+ // + Execution And Results // +-------------------------------------------------------------------+ - BOOL check(LLFolderViewItem* item); + bool check(LLFolderViewItem* item); + bool check(const LLInventoryItem* item); bool checkFolder(const LLFolderViewFolder* folder) const; - BOOL checkAgainstFilterType(const LLFolderViewItem* item) const; - BOOL checkAgainstPermissions(const LLFolderViewItem* item) const; - BOOL checkAgainstFilterLinks(const LLFolderViewItem* item) const; - bool checkAgainstClipboard(const LLUUID& object_id) const; + bool checkFolder(const LLUUID& folder_id) const; - std::string::size_type getStringMatchOffset() const; + bool showAllResults() const; + std::string::size_type getStringMatchOffset() const; + std::string::size_type getFilterStringSize() const; // +-------------------------------------------------------------------+ // + Presentation // +-------------------------------------------------------------------+ void setShowFolderState( EFolderShow state); EFolderShow getShowFolderState() const; + void setEmptyLookupMessage(const std::string& message); + std::string getEmptyLookupMessage() const; + void setSortOrder(U32 order); U32 getSortOrder() const; - - // +-------------------------------------------------------------------+ // + Status // +-------------------------------------------------------------------+ - BOOL isActive() const; + bool isActive() const; - BOOL isModified() const; - BOOL isModifiedAndClear(); - BOOL isSinceLogoff() const; + bool isModified() const; + bool isSinceLogoff() const; void clearModified(); - const std::string& getName() const; + const std::string& getName() const { return mName; } const std::string& getFilterText(); //RN: this is public to allow system to externally force a global refilter - void setModified(EFilterBehavior behavior = FILTER_RESTART); + void setModified(EFilterModified behavior = FILTER_RESTART); // +-------------------------------------------------------------------+ // + Count @@ -161,7 +269,8 @@ class LLInventoryFilter // +-------------------------------------------------------------------+ // + Default // +-------------------------------------------------------------------+ - BOOL isNotDefault() const; + bool isDefault() const; + bool isNotDefault() const; void markDefault(); void resetDefault(); @@ -169,37 +278,27 @@ class LLInventoryFilter // + Generation // +-------------------------------------------------------------------+ S32 getCurrentGeneration() const; - S32 getMinRequiredGeneration() const; - S32 getMustPassGeneration() const; + S32 getFirstSuccessGeneration() const; + S32 getFirstRequiredGeneration() const; // +-------------------------------------------------------------------+ // + Conversion // +-------------------------------------------------------------------+ - void toLLSD(LLSD& data) const; - void fromLLSD(LLSD& data); + void toParams(Params& params) const; + void fromParams(const Params& p); -private: - struct FilterOps - { - FilterOps(); - U32 mFilterTypes; - - U64 mFilterObjectTypes; // For _OBJECT - U64 mFilterWearableTypes; - U64 mFilterCategoryTypes; // For _CATEGORY - LLUUID mFilterUUID; // for UUID + LLInventoryFilter& operator =(const LLInventoryFilter& other); - time_t mMinDate; - time_t mMaxDate; - U32 mHoursAgo; - EFolderShow mShowFolderState; - PermissionMask mPermissions; - U64 mFilterLinks; - bool mFilterWorn; - }; +private: + bool areDateLimitsSet(); + bool checkAgainstFilterType(const LLFolderViewItem* item) const; + bool checkAgainstFilterType(const LLInventoryItem* item) const; + bool checkAgainstPermissions(const LLFolderViewItem* item) const; + bool checkAgainstPermissions(const LLInventoryItem* item) const; + bool checkAgainstFilterLinks(const LLFolderViewItem* item) const; + bool checkAgainstClipboard(const LLUUID& object_id) const; U32 mOrder; - U32 mLastLogoff; FilterOps mFilterOps; FilterOps mDefaultFilterOps; @@ -209,17 +308,18 @@ class LLInventoryFilter std::string mFilterSubStringOrig; const std::string mName; - S32 mFilterGeneration; - S32 mMustPassGeneration; - S32 mMinRequiredGeneration; - S32 mNextFilterGeneration; + S32 mCurrentGeneration; + // The following makes checking for pass/no pass possible even if the item is not checked against the current generation + // Any item that *did not pass* the "required generation" will *not pass* the current one + // Any item that *passes* the "success generation" will *pass* the current one + S32 mFirstRequiredGeneration; + S32 mFirstSuccessGeneration; S32 mFilterCount; - EFilterBehavior mFilterBehavior; + EFilterModified mFilterModified; - BOOL mModified; - BOOL mNeedTextRebuild; std::string mFilterText; + std::string mEmptyLookupMessage; }; #endif diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index fe77aa6c34..d23ad44178 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -37,6 +37,7 @@ #include "llinventorydefines.h" #include "llsdserialize.h" #include "llspinctrl.h" +#include "lltrans.h" #include "llui.h" #include "message.h" @@ -45,7 +46,7 @@ #include "llappviewer.h" //#include "llfirstuse.h" #include "llfloaterinventory.h" -#include "llfloateroutbox.h" +#include "llfloatermarketplacelistings.h" #include "llfocusmgr.h" #include "llfolderview.h" #include "llgesturemgr.h" @@ -57,6 +58,7 @@ #include "llinventorypanel.h" #include "lllineeditor.h" #include "llmarketplacenotifications.h" +#include "llmarketplacefunctions.h" #include "llmenugl.h" #include "llnotificationsutil.h" #include "llpanelmaininventory.h" @@ -79,17 +81,135 @@ #include "llviewerwindow.h" #include "llvoavatarself.h" #include "llwearablelist.h" - -#include - // [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a) #include "rlvhandler.h" #include "rlvlocks.h" // [/RLVa:KB] +#include + BOOL LLInventoryState::sWearNewClothing = FALSE; LLUUID LLInventoryState::sWearNewClothingTransactionID; +// Helper function : callback to update a folder after inventory action happened in the background +void update_folder_cb(const LLUUID& dest_folder) +{ + LLViewerInventoryCategory* dest_cat = gInventory.getCategory(dest_folder); + gInventory.updateCategory(dest_cat); + gInventory.notifyObservers(); +} + +// Helper function : Count only the copyable items, i.e. skip the stock items (which are no copy) +S32 count_copyable_items(LLInventoryModel::item_array_t& items) +{ + S32 count = 0; + for (LLInventoryModel::item_array_t::const_iterator it = items.begin(); it != items.end(); ++it) + { + LLViewerInventoryItem* item = *it; + if (item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID())) + { + count++; + } + } + return count; +} + +// Helper function : Count only the non-copyable items, i.e. the stock items, skip the others +S32 count_stock_items(LLInventoryModel::item_array_t& items) +{ + S32 count = 0; + for (LLInventoryModel::item_array_t::const_iterator it = items.begin(); it != items.end(); ++it) + { + LLViewerInventoryItem* item = *it; + if (!item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID())) + { + count++; + } + } + return count; +} + +// Helper function : Count the number of stock folders +S32 count_stock_folders(LLInventoryModel::cat_array_t& categories) +{ + S32 count = 0; + for (LLInventoryModel::cat_array_t::const_iterator it = categories.begin(); it != categories.end(); ++it) + { + LLInventoryCategory* cat = *it; + if (cat->getPreferredType() == LLFolderType::FT_MARKETPLACE_STOCK) + { + count++; + } + } + return count; +} + +// Helper funtion : Count the number of items (not folders) in the descending hierarchy +S32 count_descendants_items(const LLUUID& cat_id) +{ + LLInventoryModel::cat_array_t* cat_array; + LLInventoryModel::item_array_t* item_array; + gInventory.getDirectDescendentsOf(cat_id,cat_array,item_array); + + S32 count = item_array->size(); + + LLInventoryModel::cat_array_t cat_array_copy = *cat_array; + for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++) + { + LLViewerInventoryCategory* category = *iter; + count += count_descendants_items(category->getUUID()); + } + + return count; +} + +// Helper function : Returns true if the hierarchy contains nocopy items +bool contains_nocopy_items(const LLUUID& id) +{ + LLInventoryCategory* cat = gInventory.getCategory(id); + + if (cat) + { + // Get the content + LLInventoryModel::cat_array_t* cat_array; + LLInventoryModel::item_array_t* item_array; + gInventory.getDirectDescendentsOf(id,cat_array,item_array); + + // Check all the items: returns true upon encountering a nocopy item + for (LLInventoryModel::item_array_t::iterator iter = item_array->begin(); iter != item_array->end(); iter++) + { + LLInventoryItem* item = *iter; + LLViewerInventoryItem * inv_item = (LLViewerInventoryItem *) item; + if (!inv_item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID())) + { + return true; + } + } + + // Check all the sub folders recursively + for (LLInventoryModel::cat_array_t::iterator iter = cat_array->begin(); iter != cat_array->end(); iter++) + { + LLViewerInventoryCategory* cat = *iter; + if (contains_nocopy_items(cat->getUUID())) + { + return true; + } + } + } + else + { + LLInventoryItem* item = gInventory.getItem(id); + LLViewerInventoryItem * inv_item = (LLViewerInventoryItem *) item; + if (!inv_item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID())) + { + return true; + } + } + + // Exit without meeting a nocopy item + return false; +} + // Generates a string containing the path to the item specified by // item_id. void append_path(const LLUUID& id, std::string& path) @@ -111,35 +231,149 @@ void append_path(const LLUUID& id, std::string& path) path.append(temp); } -// Path should already end on '/' if it is not empty. -void append_path_short(LLUUID const& id, std::string& path) +void update_marketplace_folder_hierarchy(const LLUUID cat_id) { - LLInventoryObject const* obj = gInventory.getObject(id); - if (!obj) return; + // When changing the marketplace status of a folder, the only thing that needs to happen is + // for all observers of the folder to, possibly, change the display label of the folder + // so that's the only thing we change on the update mask. + gInventory.addChangedMask(LLInventoryObserver::LABEL, cat_id); - LLUUID const root_id = gInventory.getRootFolderID(); - std::string const forward_slash("/"); + // Update all descendent folders down + LLInventoryModel::cat_array_t* cat_array; + LLInventoryModel::item_array_t* item_array; + gInventory.getDirectDescendentsOf(cat_id,cat_array,item_array); - std::string result; - while(1) + LLInventoryModel::cat_array_t cat_array_copy = *cat_array; + for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++) { - LLUUID parent_id = obj->getParentUUID(); - if (parent_id == root_id || - !(obj = gInventory.getCategory(parent_id))) + LLInventoryCategory* category = *iter; + update_marketplace_folder_hierarchy(category->getUUID()); + } + return; +} + +void update_marketplace_category(const LLUUID& cur_uuid, bool perform_consistency_enforcement) +{ + // When changing the marketplace status of an item, we usually have to change the status of all + // folders in the same listing. This is because the display of each folder is affected by the + // overall status of the whole listing. + // Consequently, the only way to correctly update an item anywhere in the marketplace is to + // update the whole listing from its listing root. + // This is not as bad as it seems as we only update folders, not items, and the folder nesting depth + // is limited to 4. + // We also take care of degenerated cases so we don't update all folders in the inventory by mistake. + + if (cur_uuid.isNull() + || gInventory.getCategory(cur_uuid) == NULL + || gInventory.getCategory(cur_uuid)->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN) + { + return; + } + + // Grab marketplace listing data for this item + S32 depth = depth_nesting_in_marketplace(cur_uuid); + if (depth > 0) + { + // Retrieve the listing uuid this object is in + LLUUID listing_uuid = nested_parent_id(cur_uuid, depth); + LLViewerInventoryCategory* listing_cat = gInventory.getCategory(listing_uuid); + bool listing_cat_loaded = listing_cat != NULL && listing_cat->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN; + + // Verify marketplace data consistency for this listing + if (perform_consistency_enforcement + && listing_cat_loaded + && LLMarketplaceData::instance().isListed(listing_uuid)) { - break; + LLUUID version_folder_uuid = LLMarketplaceData::instance().getVersionFolder(listing_uuid); + S32 version_depth = depth_nesting_in_marketplace(version_folder_uuid); + if (version_folder_uuid.notNull() && (!gInventory.isObjectDescendentOf(version_folder_uuid, listing_uuid) || (version_depth != 2))) + { + LL_INFOS("SLM") << "Unlist and clear version folder as the version folder is not at the right place anymore!!" << LL_ENDL; + LLMarketplaceData::instance().setVersionFolder(listing_uuid, LLUUID::null,1); + } + else if (version_folder_uuid.notNull() + && gInventory.isCategoryComplete(version_folder_uuid) + && LLMarketplaceData::instance().getActivationState(version_folder_uuid) + && (count_descendants_items(version_folder_uuid) == 0) + && !LLMarketplaceData::instance().isUpdating(version_folder_uuid,version_depth)) + { + LL_INFOS("SLM") << "Unlist as the version folder is empty of any item!!" << LL_ENDL; + LLNotificationsUtil::add("AlertMerchantVersionFolderEmpty"); + LLMarketplaceData::instance().activateListing(listing_uuid, false,1); + } } - std::string temp; - temp.swap(result); - result = obj->getName(); - if (!temp.empty()) + + // Check if the count on hand needs to be updated on SLM + if (perform_consistency_enforcement + && listing_cat_loaded + && (compute_stock_count(listing_uuid) != LLMarketplaceData::instance().getCountOnHand(listing_uuid))) { - result.append(forward_slash); - result.append(temp); + LLMarketplaceData::instance().updateCountOnHand(listing_uuid,1); } + // Update all descendents starting from the listing root + update_marketplace_folder_hierarchy(listing_uuid); } + else if (depth == 0) + { + // If this is the marketplace listings root itself, update all descendents + if (gInventory.getCategory(cur_uuid)) + { + update_marketplace_folder_hierarchy(cur_uuid); + } + } + else + { + // If the folder is outside the marketplace listings root, clear its SLM data if needs be + if (perform_consistency_enforcement && LLMarketplaceData::instance().isListed(cur_uuid)) + { + LL_INFOS("SLM") << "Disassociate as the listing folder is not under the marketplace folder anymore!!" << LL_ENDL; + LLMarketplaceData::instance().clearListing(cur_uuid); + } + // Update all descendents if this is a category + if (gInventory.getCategory(cur_uuid)) + { + update_marketplace_folder_hierarchy(cur_uuid); + } + } + + return; +} + +// Iterate through the marketplace and flag for label change all categories that countain a stock folder (i.e. stock folders and embedding folders up the hierarchy) +void update_all_marketplace_count(const LLUUID& cat_id) +{ + // Get all descendent folders down + LLInventoryModel::cat_array_t* cat_array; + LLInventoryModel::item_array_t* item_array; + gInventory.getDirectDescendentsOf(cat_id, cat_array, item_array); - path.append(result); + LLInventoryModel::cat_array_t cat_array_copy = *cat_array; + for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++) + { + LLInventoryCategory* category = *iter; + if (category->getPreferredType() == LLFolderType::FT_MARKETPLACE_STOCK) + { + // Listing containing stock folders needs to be updated but not others + // Note: we take advantage of the fact that stock folder *do not* contain sub folders to avoid a recursive call here + update_marketplace_category(category->getUUID()); + } + else + { + // Explore the contained folders recursively + update_all_marketplace_count(category->getUUID()); + } + } +} + +void update_all_marketplace_count() +{ + // Get the marketplace root and launch the recursive exploration + const LLUUID marketplace_listings_uuid = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); + if (!marketplace_listings_uuid.isNull()) + { + update_all_marketplace_count(marketplace_listings_uuid); + } + return; } void rename_category(LLInventoryModel* model, const LLUUID& cat_id, const std::string& new_name) @@ -154,18 +388,16 @@ void rename_category(LLInventoryModel* model, const LLUUID& cat_id, const std::s return; } - LLPointer new_cat = new LLViewerInventoryCategory(cat); - new_cat->rename(new_name); - new_cat->updateServer(FALSE); - model->updateCategory(new_cat); - - model->notifyObservers(); + LLSD updates; + updates["name"] = new_name; + update_inventory_category(cat_id, updates, NULL); } void copy_inventory_category(LLInventoryModel* model, LLViewerInventoryCategory* cat, const LLUUID& parent_id, - const LLUUID& root_copy_id) + const LLUUID& root_copy_id, + bool move_no_copy_items) { // Create the initial folder LLUUID new_cat_uuid = gInventory.createNewCategory(parent_id, LLFolderType::FT_NONE, cat->getName()); @@ -179,18 +411,41 @@ void copy_inventory_category(LLInventoryModel* model, LLInventoryModel::item_array_t* item_array; gInventory.getDirectDescendentsOf(cat->getUUID(),cat_array,item_array); + // If root_copy_id is null, tell the marketplace model we'll be waiting for new items to be copied over for this folder + if (root_copy_id.isNull()) + { + LLMarketplaceData::instance().setValidationWaiting(root_id,count_descendants_items(cat->getUUID())); + } + // Copy all the items LLInventoryModel::item_array_t item_array_copy = *item_array; for (LLInventoryModel::item_array_t::iterator iter = item_array_copy.begin(); iter != item_array_copy.end(); iter++) { LLInventoryItem* item = *iter; - copy_inventory_item( - gAgent.getID(), - item->getPermissions().getOwner(), - item->getUUID(), - new_cat_uuid, - std::string(), - LLPointer(NULL)); + LLPointer cb = new LLBoostFuncInventoryCallback(boost::bind(update_folder_cb, new_cat_uuid)); + + if (!item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID())) + { + // If the item is nocopy, we do nothing or, optionally, move it + if (move_no_copy_items) + { + // Reparent the item + LLViewerInventoryItem * viewer_inv_item = (LLViewerInventoryItem *) item; + gInventory.changeItemParent(viewer_inv_item, new_cat_uuid, true); + } + // Decrement the count in root_id since that one item won't be copied over + LLMarketplaceData::instance().decrementValidationWaiting(root_id); + } + else + { + copy_inventory_item( + gAgent.getID(), + item->getPermissions().getOwner(), + item->getUUID(), + new_cat_uuid, + std::string(), + cb); + } } // Copy all the folders @@ -200,7 +455,7 @@ void copy_inventory_category(LLInventoryModel* model, LLViewerInventoryCategory* category = *iter; if (category->getUUID() != root_id) { - copy_inventory_category(model, category, new_cat_uuid, root_id); + copy_inventory_category(model, category, new_cat_uuid, root_id, move_no_copy_items); } } } @@ -256,16 +511,19 @@ BOOL get_is_parent_to_worn_item(const LLUUID& id) return FALSE; } -BOOL get_is_item_worn(const LLInventoryItem *item) + +BOOL get_is_item_worn(const LLUUID& id) { + const LLViewerInventoryItem* item = gInventory.getItem(id); if (!item) return FALSE; // Consider the item as worn if it has links in COF. - /* if (LLCOFMgr::instance().isLinkInCOF(item->getUUID())) - { REMOVED due to advice from Kitty Barnett, looks like it WILL cause trouble on some grids -SG - return TRUE; - } */ +// [SL:KB] - The code below causes problems across the board so it really just needs to go +// if (LLAppearanceMgr::instance().isLinkedInCOF(id)) +// { +// return TRUE; +// } switch(item->getType()) { @@ -290,18 +548,13 @@ BOOL get_is_item_worn(const LLInventoryItem *item) return FALSE; } -BOOL get_is_item_worn(const LLUUID& id) -{ - return get_is_item_worn(gInventory.getItem(id)); -} - BOOL get_can_item_be_worn(const LLUUID& id) { const LLViewerInventoryItem* item = gInventory.getItem(id); if (!item) return FALSE; - if (LLAppearanceMgr::isLinkInCOF(item->getLinkedUUID())) + if (LLAppearanceMgr::instance().isLinkedInCOF(item->getLinkedUUID())) { // an item having links in COF (i.e. a worn item) return FALSE; @@ -505,174 +758,1007 @@ void show_item_profile(const LLUUID& item_uuid) } } -void open_outbox() +void open_marketplace_listings() { - LLFloaterOutbox::showInstance(); + LLFloaterMarketplaceListings::showInstance(); } -LLUUID create_folder_in_outbox_for_item(LLInventoryItem* item, const LLUUID& destFolderId, S32 operation_id) +///---------------------------------------------------------------------------- +// Marketplace functions +// +// Handles Copy and Move to or within the Marketplace listings folder. +// Handles creation of stock folders, nesting of listings and version folders, +// permission checking and listings validation. +///---------------------------------------------------------------------------- + +S32 depth_nesting_in_marketplace(LLUUID cur_uuid) { - llassert(item); - llassert(destFolderId.notNull()); + // Get the marketplace listings root, exit with -1 (i.e. not under the marketplace listings root) if none + const LLUUID marketplace_listings_uuid = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); + if (marketplace_listings_uuid.isNull()) + { + return -1; + } + // If not a descendent of the marketplace listings root, then the nesting depth is -1 by definition + if (!gInventory.isObjectDescendentOf(cur_uuid, marketplace_listings_uuid)) + { + return -1; + } - LLUUID created_folder_id = gInventory.createNewCategory(destFolderId, LLFolderType::FT_NONE, item->getName()); - gInventory.notifyObservers(); + // Iterate through the parents till we hit the marketplace listings root + // Note that the marketplace listings root itself will return 0 + S32 depth = 0; + LLInventoryObject* cur_object = gInventory.getObject(cur_uuid); + while (cur_uuid != marketplace_listings_uuid) + { + depth++; + cur_uuid = cur_object->getParentUUID(); + cur_object = gInventory.getCategory(cur_uuid); + } + return depth; +} - LLNotificationsUtil::add("OutboxFolderCreated"); +// Returns the UUID of the marketplace listing this object is in +LLUUID nested_parent_id(LLUUID cur_uuid, S32 depth) +{ + if (depth < 1) + { + // For objects outside the marketplace listings root (or root itself), we return a NULL UUID + return LLUUID::null; + } + else if (depth == 1) + { + // Just under the root, we return the passed UUID itself if it's a folder, NULL otherwise (not a listing) + LLViewerInventoryCategory* cat = gInventory.getCategory(cur_uuid); + return (cat ? cur_uuid : LLUUID::null); + } - return created_folder_id; + // depth > 1 + LLInventoryObject* cur_object = gInventory.getObject(cur_uuid); + while (depth > 1) + { + depth--; + cur_uuid = cur_object->getParentUUID(); + cur_object = gInventory.getCategory(cur_uuid); + } + return cur_uuid; } -void move_to_outbox_cb_action(const LLSD& payload) +S32 compute_stock_count(LLUUID cat_uuid, bool force_count /* false */) { - LLViewerInventoryItem * viitem = gInventory.getItem(payload["item_id"].asUUID()); - LLUUID dest_folder_id = payload["dest_folder_id"].asUUID(); + // Handle the case of the folder being a stock folder immediately + LLViewerInventoryCategory* cat = gInventory.getCategory(cat_uuid); + if (!cat) + { + // Not a category so no stock count to speak of + return COMPUTE_STOCK_INFINITE; + } + if (cat->getPreferredType() == LLFolderType::FT_MARKETPLACE_STOCK) + { + if (cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN) + { + // If the folder is not completely fetched, we do not want to return any confusing value that could lead to unlisting + // "COMPUTE_STOCK_NOT_EVALUATED" denotes that a stock folder has a count that cannot be evaluated at this time (folder not up to date) + return COMPUTE_STOCK_NOT_EVALUATED; + } + // Note: stock folders are *not* supposed to have nested subfolders so we stop recursion here but we count only items (subfolders will be ignored) + // Note: we *always* give a stock count for stock folders, it's useful even if the listing is unassociated + LLInventoryModel::cat_array_t* cat_array; + LLInventoryModel::item_array_t* item_array; + gInventory.getDirectDescendentsOf(cat_uuid,cat_array,item_array); + return item_array->size(); + } + + // When force_count is true, we do not do any verification of the marketplace status and simply compute + // the stock amount based on the descendent hierarchy. This is used specifically when creating a listing. + if (!force_count) + { + // Grab marketplace data for this folder + S32 depth = depth_nesting_in_marketplace(cat_uuid); + LLUUID listing_uuid = nested_parent_id(cat_uuid, depth); + if (!LLMarketplaceData::instance().isListed(listing_uuid)) + { + // If not listed, the notion of stock is meaningless so it won't be computed for any level + return COMPUTE_STOCK_INFINITE; + } + + LLUUID version_folder_uuid = LLMarketplaceData::instance().getVersionFolder(listing_uuid); + // Handle the case of the first 2 levels : listing and version folders + if (depth == 1) + { + if (version_folder_uuid.notNull()) + { + // If there is a version folder, the stock value for the listing is the version folder stock + return compute_stock_count(version_folder_uuid, true); + } + else + { + // If there's no version folder associated, the notion of stock count has no meaning + return COMPUTE_STOCK_INFINITE; + } + } + else if (depth == 2) + { + if (version_folder_uuid.notNull() && (version_folder_uuid != cat_uuid)) + { + // If there is a version folder but we're not it, our stock count is meaningless + return COMPUTE_STOCK_INFINITE; + } + } + } - if (viitem) - { - // when moving item directly into outbox create folder with that name - if (dest_folder_id == gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false)) + // In all other cases, the stock count is the min of stock folders count found in the descendents + // "COMPUTE_STOCK_NOT_EVALUATED" denotes that a stock folder in the hierarchy has a count that cannot be evaluated at this time (folder not up to date) + LLInventoryModel::cat_array_t* cat_array; + LLInventoryModel::item_array_t* item_array; + gInventory.getDirectDescendentsOf(cat_uuid,cat_array,item_array); + + // "COMPUTE_STOCK_INFINITE" denotes a folder that doesn't contain any stock folders in its descendents + S32 curr_count = COMPUTE_STOCK_INFINITE; + + // Note: marketplace listings have a maximum depth nesting of 4 + LLInventoryModel::cat_array_t cat_array_copy = *cat_array; + for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++) + { + LLInventoryCategory* category = *iter; + S32 count = compute_stock_count(category->getUUID(), true); + if ((curr_count == COMPUTE_STOCK_INFINITE) || ((count != COMPUTE_STOCK_INFINITE) && (count < curr_count))) { - S32 operation_id = payload["operation_id"].asInteger(); - dest_folder_id = create_folder_in_outbox_for_item(viitem, dest_folder_id, operation_id); + curr_count = count; } + } - LLUUID parent = viitem->getParentUUID(); + return curr_count; +} - gInventory.changeItemParent( - viitem, - dest_folder_id, - false); +// local helper +bool can_move_to_marketplace(LLInventoryItem* inv_item, std::string& tooltip_msg, bool resolve_links) +{ + // Collapse links directly to items/folders + LLViewerInventoryItem* viewer_inv_item = (LLViewerInventoryItem *) inv_item; + LLViewerInventoryItem* linked_item = viewer_inv_item->getLinkedItem(); + LLViewerInventoryCategory* linked_category = viewer_inv_item->getLinkedCategory(); - LLUUID top_level_folder = payload["top_level_folder"].asUUID(); + // Linked items and folders cannot be put for sale + if (linked_category || linked_item) + { + tooltip_msg = LLTrans::getString("TooltipOutboxLinked"); + return false; + } - if (top_level_folder != LLUUID::null) + // A category is always considered as passing... + if (linked_category != NULL) + { + return true; + } + + // Take the linked item if necessary + if (linked_item != NULL) + { + inv_item = linked_item; + } + + // Check that the agent has transfer permission on the item: this is required as a resident cannot + // put on sale items she cannot transfer. Proceed with move if we have permission. + bool allow_transfer = inv_item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID()); + if (!allow_transfer) + { + tooltip_msg = LLTrans::getString("TooltipOutboxNoTransfer"); + return false; + } + + // Check worn/not worn status: worn items cannot be put on the marketplace + bool worn = get_is_item_worn(inv_item->getUUID()); + if (worn) + { + tooltip_msg = LLTrans::getString("TooltipOutboxWorn"); + return false; + } + + // Check library status: library items cannot be put on the marketplace + if (!gInventory.isObjectDescendentOf(inv_item->getUUID(), gInventory.getRootFolderID())) + { + tooltip_msg = LLTrans::getString("TooltipOutboxNotInInventory"); + return false; + } + + // Check type: for the moment, calling cards cannot be put on the marketplace + bool calling_card = (LLAssetType::AT_CALLINGCARD == inv_item->getType()); + if (calling_card) + { + tooltip_msg = LLTrans::getString("TooltipOutboxCallingCard"); + return false; + } + + return true; +} + +// local helper +// Returns the max tree length (in folder nodes) down from the argument folder +int get_folder_levels(LLInventoryCategory* inv_cat) +{ + LLInventoryModel::cat_array_t* cats; + LLInventoryModel::item_array_t* items; + gInventory.getDirectDescendentsOf(inv_cat->getUUID(), cats, items); + + int max_child_levels = 0; + + for (U32 i = 0; i < cats->size(); ++i) + { + LLInventoryCategory* category = cats->at(i); + max_child_levels = llmax(max_child_levels, get_folder_levels(category)); + } + + return 1 + max_child_levels; +} + +// local helper +// Returns the distance (in folder nodes) between the ancestor and its descendant. Returns -1 if not related. +int get_folder_path_length(const LLUUID& ancestor_id, const LLUUID& descendant_id) +{ + int depth = 0; + + if (ancestor_id == descendant_id) return depth; + + const LLInventoryCategory* category = gInventory.getCategory(descendant_id); + + while (category) + { + LLUUID parent_id = category->getParentUUID(); + + if (parent_id.isNull()) break; + + depth++; + + if (parent_id == ancestor_id) return depth; + + category = gInventory.getCategory(parent_id); + } + + LL_WARNS("SLM") << "get_folder_path_length() couldn't trace a path from the descendant to the ancestor" << LL_ENDL; + return -1; +} + +// local helper +// Returns true if all items within the argument folder are fit for sale, false otherwise +bool has_correct_permissions_for_sale(LLInventoryCategory* cat, std::string& error_msg) +{ + LLInventoryModel::cat_array_t* cat_array; + LLInventoryModel::item_array_t* item_array; + gInventory.getDirectDescendentsOf(cat->getUUID(),cat_array,item_array); + + LLInventoryModel::item_array_t item_array_copy = *item_array; + + for (LLInventoryModel::item_array_t::iterator iter = item_array_copy.begin(); iter != item_array_copy.end(); iter++) + { + LLInventoryItem* item = *iter; + if (!can_move_to_marketplace(item, error_msg, false)) { - LLViewerInventoryCategory* category; + return false; + } + } + + LLInventoryModel::cat_array_t cat_array_copy = *cat_array; - while (parent.notNull()) + for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++) + { + LLInventoryCategory* category = *iter; + if (!has_correct_permissions_for_sale(category, error_msg)) + { + return false; + } + } + return true; +} + +// Returns true if inv_item can be dropped in dest_folder, a folder nested in marketplace listings (or merchant inventory) under the root_folder root +// If returns is false, tooltip_msg contains an error message to display to the user (localized and all). +// bundle_size is the amount of sibling items that are getting moved to the marketplace at the same time. +bool can_move_item_to_marketplace(const LLInventoryCategory* root_folder, LLInventoryCategory* dest_folder, LLInventoryItem* inv_item, std::string& tooltip_msg, S32 bundle_size, bool from_paste) +{ + // Check stock folder type matches item type in marketplace listings (even if of no use there for the moment) + LLViewerInventoryCategory* view_folder = dynamic_cast(dest_folder); + bool move_in_stock = (view_folder && (view_folder->getPreferredType() == LLFolderType::FT_MARKETPLACE_STOCK)); + bool accept = (view_folder && view_folder->acceptItem(inv_item)); + if (!accept) + { + tooltip_msg = LLTrans::getString("TooltipOutboxMixedStock"); + } + + // Check that the item has the right type and permissions to be sold on the marketplace + if (accept) + { + accept = can_move_to_marketplace(inv_item, tooltip_msg, true); + } + + // Check that the total amount of items won't violate the max limit on the marketplace + if (accept) + { + // If the dest folder is a stock folder, we do not count the incoming items toward the total (stock items are seen as one) + S32 existing_item_count = (move_in_stock ? 0 : bundle_size); + + // If the dest folder is a stock folder, we do assume that the incoming items are also stock items (they should anyway) + S32 existing_stock_count = (move_in_stock ? bundle_size : 0); + + S32 existing_folder_count = 0; + + // Get the version folder: that's where the counts start from + const LLViewerInventoryCategory* version_folder = ((root_folder && (root_folder != dest_folder)) ? gInventory.getFirstDescendantOf(root_folder->getUUID(), dest_folder->getUUID()) : NULL); + + if (version_folder) + { + if (!from_paste && gInventory.isObjectDescendentOf(inv_item->getUUID(), version_folder->getUUID())) { - LLInventoryModel::cat_array_t* cat_array; - LLInventoryModel::item_array_t* item_array; - gInventory.getDirectDescendentsOf(parent,cat_array,item_array); + // Clear those counts or they will be counted twice because we're already inside the version category + existing_item_count = 0; + } - LLUUID next_parent; + LLInventoryModel::cat_array_t existing_categories; + LLInventoryModel::item_array_t existing_items; - category = gInventory.getCategory(parent); + gInventory.collectDescendents(version_folder->getUUID(), existing_categories, existing_items, FALSE); - if (!category) break; + existing_item_count += count_copyable_items(existing_items) + count_stock_folders(existing_categories); + existing_stock_count += count_stock_items(existing_items); + existing_folder_count += existing_categories.size(); - next_parent = category->getParentUUID(); + // If the incoming item is a nocopy (stock) item, we need to consider that it will create a stock folder + if (!inv_item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID()) && !move_in_stock) + { + // Note : we do not assume that all incoming items are nocopy of different kinds... + existing_folder_count += 1; + } + } - if (cat_array->empty() && item_array->empty()) - { - gInventory.removeCategory(parent); - } + if (existing_item_count > (S32)gSavedSettings.getU32("InventoryOutboxMaxItemCount")) + { + LLStringUtil::format_map_t args; + U32 amount = gSavedSettings.getU32("InventoryOutboxMaxItemCount"); + args["[AMOUNT]"] = llformat("%d",amount); + tooltip_msg = LLTrans::getString("TooltipOutboxTooManyObjects", args); + accept = false; + } + else if (existing_stock_count > (S32)gSavedSettings.getU32("InventoryOutboxMaxStockItemCount")) + { + LLStringUtil::format_map_t args; + U32 amount = gSavedSettings.getU32("InventoryOutboxMaxStockItemCount"); + args["[AMOUNT]"] = llformat("%d",amount); + tooltip_msg = LLTrans::getString("TooltipOutboxTooManyStockItems", args); + accept = false; + } + else if (existing_folder_count > (S32)gSavedSettings.getU32("InventoryOutboxMaxFolderCount")) + { + LLStringUtil::format_map_t args; + U32 amount = gSavedSettings.getU32("InventoryOutboxMaxFolderCount"); + args["[AMOUNT]"] = llformat("%d",amount); + tooltip_msg = LLTrans::getString("TooltipOutboxTooManyFolders", args); + accept = false; + } + } + + return accept; +} + +// Returns true if inv_cat can be dropped in dest_folder, a folder nested in marketplace listings (or merchant inventory) under the root_folder root +// If returns is false, tooltip_msg contains an error message to display to the user (localized and all). +// bundle_size is the amount of sibling items that are getting moved to the marketplace at the same time. +bool can_move_folder_to_marketplace(const LLInventoryCategory* root_folder, LLInventoryCategory* dest_folder, LLInventoryCategory* inv_cat, std::string& tooltip_msg, S32 bundle_size, bool check_items, bool from_paste) +{ + bool accept = true; + + // Compute the nested folders level we'll add into with that incoming folder + int incoming_folder_depth = get_folder_levels(inv_cat); + // Compute the nested folders level we're inserting ourselves in + // Note: add 1 when inserting under a listing folder as we need to take the root listing folder in the count + int insertion_point_folder_depth = (root_folder ? get_folder_path_length(root_folder->getUUID(), dest_folder->getUUID()) + 1 : 1); + + // Get the version folder: that's where the folders and items counts start from + const LLViewerInventoryCategory* version_folder = (insertion_point_folder_depth >= 2 ? gInventory.getFirstDescendantOf(root_folder->getUUID(), dest_folder->getUUID()) : NULL); + + // Compare the whole with the nested folders depth limit + // Note: substract 2 as we leave root and version folder out of the count threshold + if ((incoming_folder_depth + insertion_point_folder_depth - 2) > (S32)(gSavedSettings.getU32("InventoryOutboxMaxFolderDepth"))) + { + LLStringUtil::format_map_t args; + U32 amount = gSavedSettings.getU32("InventoryOutboxMaxFolderDepth"); + args["[AMOUNT]"] = llformat("%d",amount); + tooltip_msg = LLTrans::getString("TooltipOutboxFolderLevels", args); + accept = false; + } + + if (accept) + { + LLInventoryModel::cat_array_t descendent_categories; + LLInventoryModel::item_array_t descendent_items; + gInventory.collectDescendents(inv_cat->getUUID(), descendent_categories, descendent_items, FALSE); + + S32 dragged_folder_count = descendent_categories.size() + bundle_size; // Note: We assume that we're moving a bunch of folders in. That might be wrong... + S32 dragged_item_count = count_copyable_items(descendent_items) + count_stock_folders(descendent_categories); + S32 dragged_stock_count = count_stock_items(descendent_items); + S32 existing_item_count = 0; + S32 existing_stock_count = 0; + S32 existing_folder_count = 0; - if (parent == top_level_folder) + if (version_folder) + { + if (!from_paste && gInventory.isObjectDescendentOf(inv_cat->getUUID(), version_folder->getUUID())) + { + // Clear those counts or they will be counted twice because we're already inside the version category + dragged_folder_count = 0; + dragged_item_count = 0; + dragged_stock_count = 0; + } + + // Tally the total number of categories and items inside the root folder + LLInventoryModel::cat_array_t existing_categories; + LLInventoryModel::item_array_t existing_items; + gInventory.collectDescendents(version_folder->getUUID(), existing_categories, existing_items, FALSE); + + existing_folder_count += existing_categories.size(); + existing_item_count += count_copyable_items(existing_items) + count_stock_folders(existing_categories); + existing_stock_count += count_stock_items(existing_items); + } + + const S32 total_folder_count = existing_folder_count + dragged_folder_count; + const S32 total_item_count = existing_item_count + dragged_item_count; + const S32 total_stock_count = existing_stock_count + dragged_stock_count; + + if (total_folder_count > (S32)gSavedSettings.getU32("InventoryOutboxMaxFolderCount")) + { + LLStringUtil::format_map_t args; + U32 amount = gSavedSettings.getU32("InventoryOutboxMaxFolderCount"); + args["[AMOUNT]"] = llformat("%d",amount); + tooltip_msg = LLTrans::getString("TooltipOutboxTooManyFolders", args); + accept = false; + } + else if (total_item_count > (S32)gSavedSettings.getU32("InventoryOutboxMaxItemCount")) + { + LLStringUtil::format_map_t args; + U32 amount = gSavedSettings.getU32("InventoryOutboxMaxItemCount"); + args["[AMOUNT]"] = llformat("%d",amount); + tooltip_msg = LLTrans::getString("TooltipOutboxTooManyObjects", args); + accept = false; + } + else if (total_stock_count > (S32)gSavedSettings.getU32("InventoryOutboxMaxStockItemCount")) + { + LLStringUtil::format_map_t args; + U32 amount = gSavedSettings.getU32("InventoryOutboxMaxStockItemCount"); + args["[AMOUNT]"] = llformat("%d",amount); + tooltip_msg = LLTrans::getString("TooltipOutboxTooManyStockItems", args); + accept = false; + } + + // Now check that each item in the folder can be moved in the marketplace + if (accept && check_items) + { + for (U32 i=0; i < descendent_items.size(); ++i) + { + LLInventoryItem* item = descendent_items[i]; + if (!can_move_to_marketplace(item, tooltip_msg, false)) { + accept = false; break; } - - parent = next_parent; } } - - open_outbox(); } + + return accept; } -void copy_item_to_outbox(LLInventoryItem* inv_item, LLUUID dest_folder, const LLUUID& top_level_folder, S32 operation_id) +bool move_item_to_marketplacelistings(LLInventoryItem* inv_item, LLUUID dest_folder, bool copy) { - // Collapse links directly to items/folders + // Get the marketplace listings depth of the destination folder, exit with error if not under marketplace + S32 depth = depth_nesting_in_marketplace(dest_folder); + if (depth < 0) + { + LLSD subs; + subs["[ERROR_CODE]"] = LLTrans::getString("Marketplace Error Prefix") + LLTrans::getString("Marketplace Error Not Merchant"); + LLNotificationsUtil::add("MerchantPasteFailed", subs); + return false; + } + + // We will collapse links into items/folders LLViewerInventoryItem * viewer_inv_item = (LLViewerInventoryItem *) inv_item; LLViewerInventoryCategory * linked_category = viewer_inv_item->getLinkedCategory(); + if (linked_category != NULL) { - copy_folder_to_outbox(linked_category, dest_folder, top_level_folder, operation_id); + // Move the linked folder directly + return move_folder_to_marketplacelistings(linked_category, dest_folder, copy); } else { + // Grab the linked item if any LLViewerInventoryItem * linked_item = viewer_inv_item->getLinkedItem(); - if (linked_item != NULL) + viewer_inv_item = (linked_item != NULL ? linked_item : viewer_inv_item); + + // If we want to copy but the item is no copy, fail silently (this is a common case that doesn't warrant notification) + if (copy && !viewer_inv_item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID())) { - inv_item = (LLInventoryItem *) linked_item; + return false; } - - // Check for copy permissions - if (inv_item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID())) + + // Check that the agent has transfer permission on the item: this is required as a resident cannot + // put on sale items she cannot transfer. Proceed with move if we have permission. + std::string error_msg; + if (can_move_to_marketplace(inv_item, error_msg, true)) { - // when moving item directly into outbox create folder with that name - if (dest_folder == gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false)) + // When moving an isolated item, we might need to create the folder structure to support it + if (depth == 0) { - dest_folder = create_folder_in_outbox_for_item(inv_item, dest_folder, operation_id); + // We need a listing folder + dest_folder = gInventory.createNewCategory(dest_folder, LLFolderType::FT_NONE, viewer_inv_item->getName()); + depth++; + } + if (depth == 1) + { + // We need a version folder + dest_folder = gInventory.createNewCategory(dest_folder, LLFolderType::FT_NONE, viewer_inv_item->getName()); + depth++; + } + LLViewerInventoryCategory* dest_cat = gInventory.getCategory(dest_folder); + if (!viewer_inv_item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID()) && + (dest_cat->getPreferredType() != LLFolderType::FT_MARKETPLACE_STOCK)) + { + // We need to create a stock folder to move a no copy item + dest_folder = gInventory.createNewCategory(dest_folder, LLFolderType::FT_MARKETPLACE_STOCK, viewer_inv_item->getName()); + dest_cat = gInventory.getCategory(dest_folder); + depth++; + } + + // Verify we can have this item in that destination category + if (!dest_cat->acceptItem(viewer_inv_item)) + { + LLSD subs; + subs["[ERROR_CODE]"] = LLTrans::getString("Marketplace Error Prefix") + LLTrans::getString("Marketplace Error Not Accepted"); + LLNotificationsUtil::add("MerchantPasteFailed", subs); + return false; } - - copy_inventory_item(gAgent.getID(), - inv_item->getPermissions().getOwner(), - inv_item->getUUID(), - dest_folder, - inv_item->getName(), - LLPointer(NULL)); - open_outbox(); + // Get the parent folder of the moved item : we may have to update it + LLUUID src_folder = viewer_inv_item->getParentUUID(); + + if (copy) + { + // Copy the item + LLPointer cb = new LLBoostFuncInventoryCallback(boost::bind(update_folder_cb, dest_folder)); + copy_inventory_item( + gAgent.getID(), + viewer_inv_item->getPermissions().getOwner(), + viewer_inv_item->getUUID(), + dest_folder, + std::string(), + cb); + } + else + { + // Reparent the item + gInventory.changeItemParent(viewer_inv_item, dest_folder, true); + } } else { - LLSD payload; - payload["item_id"] = inv_item->getUUID(); - payload["dest_folder_id"] = dest_folder; - payload["top_level_folder"] = top_level_folder; - payload["operation_id"] = operation_id; - - LLMarketplaceInventoryNotifications::addNoCopyNotification(payload, move_to_outbox_cb_action); + LLSD subs; + subs["[ERROR_CODE]"] = LLTrans::getString("Marketplace Error Prefix") + error_msg; + LLNotificationsUtil::add("MerchantPasteFailed", subs); + return false; } } + + open_marketplace_listings(); + return true; } -void move_item_within_outbox(LLInventoryItem* inv_item, LLUUID dest_folder, S32 operation_id) +bool move_folder_to_marketplacelistings(LLInventoryCategory* inv_cat, const LLUUID& dest_folder, bool copy, bool move_no_copy_items) { - // when moving item directly into outbox create folder with that name - if (dest_folder == gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false)) + // Check that we have adequate permission on all items being moved. Proceed if we do. + std::string error_msg; + if (has_correct_permissions_for_sale(inv_cat, error_msg)) + { + // Get the destination folder + LLViewerInventoryCategory* dest_cat = gInventory.getCategory(dest_folder); + + // Check it's not a stock folder + if (dest_cat->getPreferredType() == LLFolderType::FT_MARKETPLACE_STOCK) + { + LLSD subs; + subs["[ERROR_CODE]"] = LLTrans::getString("Marketplace Error Prefix") + LLTrans::getString("Marketplace Error Not Accepted"); + LLNotificationsUtil::add("MerchantPasteFailed", subs); + return false; + } + + // Get the parent folder of the moved item : we may have to update it + LLUUID src_folder = inv_cat->getParentUUID(); + + LLViewerInventoryCategory* viewer_inv_cat = (LLViewerInventoryCategory*) inv_cat; + if (copy) + { + // Copy the folder + copy_inventory_category(&gInventory, viewer_inv_cat, dest_folder, LLUUID::null, move_no_copy_items); + } + else + { + // Reparent the folder + gInventory.changeCategoryParent(viewer_inv_cat, dest_folder, false); + // Check the destination folder recursively for no copy items and promote the including folders if any + validate_marketplacelistings(dest_cat); + } + + // Update the modified folders + update_marketplace_category(src_folder); + update_marketplace_category(dest_folder); + gInventory.notifyObservers(); + } + else { - dest_folder = create_folder_in_outbox_for_item(inv_item, dest_folder, operation_id); + LLSD subs; + subs["[ERROR_CODE]"] = LLTrans::getString("Marketplace Error Prefix") + error_msg; + LLNotificationsUtil::add("MerchantPasteFailed", subs); + return false; } - - LLViewerInventoryItem * viewer_inv_item = (LLViewerInventoryItem *) inv_item; - gInventory.changeItemParent( - viewer_inv_item, - dest_folder, - false); + open_marketplace_listings(); + return true; } -void copy_folder_to_outbox(LLInventoryCategory* inv_cat, const LLUUID& dest_folder, const LLUUID& top_level_folder, S32 operation_id) +bool sort_alpha(const LLViewerInventoryCategory* cat1, const LLViewerInventoryCategory* cat2) { - LLUUID new_folder_id = gInventory.createNewCategory(dest_folder, LLFolderType::FT_NONE, inv_cat->getName()); - gInventory.notifyObservers(); + return cat1->getName().compare(cat2->getName()) < 0; +} + +void dump_trace(std::string& message, S32 depth, LLError::ELevel log_level) +{ + LL_INFOS() << "validate_marketplacelistings : error = "<< log_level << ", depth = " << depth << ", message = " << message << LL_ENDL; +} + +// Make all relevant business logic checks on the marketplace listings starting with the folder as argument. +// This function does no deletion of listings but a mere audit and raises issues to the user (through the +// optional callback cb). It also returns a boolean, true if things validate, false if issues are raised. +// The only inventory changes that are done is to move and sort folders containing no-copy items to stock folders. +bool validate_marketplacelistings(LLInventoryCategory* cat, validation_callback_t cb, bool fix_hierarchy, S32 depth) +{ +#if 0 + // Used only for debug + if (!cb) + { + cb = boost::bind(&dump_trace, _1, _2, _3); + } +#endif + // Folder is valid unless issue is raised + bool result = true; + + // Get the type and the depth of the folder + LLViewerInventoryCategory* viewer_cat = (LLViewerInventoryCategory*) (cat); + const LLFolderType::EType folder_type = cat->getPreferredType(); + if (depth < 0) + { + // If the depth argument was not provided, evaluate the depth directly + depth = depth_nesting_in_marketplace(cat->getUUID()); + } + if (depth < 0) + { + // If the folder is not under the marketplace listings root, we run validation as if it was a listing folder and prevent any hierarchy fix + // This allows the function to be used to pre-validate a folder anywhere in the inventory + depth = 1; + fix_hierarchy = false; + } + + // Set the indentation for print output (typically, audit button in marketplace folder floater) + std::string indent; + for (int i = 1; i < depth; i++) + { + indent += " "; + } + + // Check out that version folders are marketplace ready + if (depth == 2) + { + std::string message; + // Note: if we fix the hierarchy, we want to check the items individually, hence the last argument here + if (!can_move_folder_to_marketplace(cat, cat, cat, message, 0, fix_hierarchy)) + { + result = false; + if (cb) + { + message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Error") + " " + message; + cb(message, depth, LLError::LEVEL_ERROR); + } + } + } + + // Check out that stock folders are at the right level + if ((folder_type == LLFolderType::FT_MARKETPLACE_STOCK) && (depth <= 2)) + { + if (fix_hierarchy) + { + if (cb) + { + std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Warning") + " " + LLTrans::getString("Marketplace Validation Warning Stock"); + cb(message, depth, LLError::LEVEL_WARN); + } + // Nest the stock folder one level deeper in a normal folder and restart from there + LLUUID parent_uuid = cat->getParentUUID(); + LLUUID folder_uuid = gInventory.createNewCategory(parent_uuid, LLFolderType::FT_NONE, cat->getName()); + LLInventoryCategory* new_cat = gInventory.getCategory(folder_uuid); + gInventory.changeCategoryParent(viewer_cat, folder_uuid, false); + result &= validate_marketplacelistings(new_cat, cb, fix_hierarchy, depth + 1); + return result; + } + else + { + result = false; + if (cb) + { + std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Error") + " " + LLTrans::getString("Marketplace Validation Warning Stock"); + cb(message, depth, LLError::LEVEL_ERROR); + } + } + } + + // Item sorting and validation : sorting and moving the various stock items is complicated as the set of constraints is high + // We need to: + // * separate non stock items, stock items per types in different folders + // * have stock items nested at depth 2 at least + // * never ever move the non-stock items LLInventoryModel::cat_array_t* cat_array; LLInventoryModel::item_array_t* item_array; - gInventory.getDirectDescendentsOf(inv_cat->getUUID(),cat_array,item_array); + gInventory.getDirectDescendentsOf(cat->getUUID(),cat_array,item_array); - // copy the vector because otherwise the iterator won't be happy if we delete from it - LLInventoryModel::item_array_t item_array_copy = *item_array; + // We use a composite (type,permission) key on that map to store UUIDs of items of same (type,permissions) + std::map items_vector; + // Parse the items and create vectors of item UUIDs sorting copyable items and stock items of various types + bool has_bad_items = false; + LLInventoryModel::item_array_t item_array_copy = *item_array; for (LLInventoryModel::item_array_t::iterator iter = item_array_copy.begin(); iter != item_array_copy.end(); iter++) { LLInventoryItem* item = *iter; - copy_item_to_outbox(item, new_folder_id, top_level_folder, operation_id); + LLViewerInventoryItem * viewer_inv_item = (LLViewerInventoryItem *) item; + + // Test but skip items that shouldn't be there to start with, raise an error message for those + std::string error_msg; + if (!can_move_to_marketplace(item, error_msg, false)) + { + has_bad_items = true; + if (cb && fix_hierarchy) + { + std::string message = indent + viewer_inv_item->getName() + LLTrans::getString("Marketplace Validation Error") + " " + error_msg; + cb(message, depth, LLError::LEVEL_ERROR); + } + continue; + } + // Update the appropriate vector item for that type + LLInventoryType::EType type = LLInventoryType::IT_COUNT; // Default value for non stock items + U32 perms = 0; + if (!viewer_inv_item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID())) + { + // Get the item type for stock items + type = viewer_inv_item->getInventoryType(); + perms = viewer_inv_item->getPermissions().getMaskNextOwner(); + } + U32 key = (((U32)(type) & 0xFF) << 24) | (perms & 0xFFFFFF); + items_vector[key].push_back(viewer_inv_item->getUUID()); } + // How many types of items? Which type is it if only one? + S32 count = items_vector.size(); + U32 default_key = (U32)(LLInventoryType::IT_COUNT) << 24; // This is the key for any normal copyable item + U32 unique_key = (count == 1 ? items_vector.begin()->first : default_key); // The key in the case of one item type only + + // If we have no items in there (only folders or empty), analyze a bit further + if ((count == 0) && !has_bad_items) + { + if (cat_array->size() == 0) + { + // So we have no item and no folder. That's at least a warning. + if (depth == 2) + { + // If this is an empty version folder, warn only (listing won't be delivered by AIS, but only AIS should unlist) + if (cb) + { + std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Error Empty Version"); + cb(message, depth, LLError::LEVEL_WARN); + } + } + else if ((folder_type == LLFolderType::FT_MARKETPLACE_STOCK) && (depth > 2)) + { + // If this is a legit but empty stock folder, warn only (listing must stay searchable when out of stock) + if (cb) + { + std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Error Empty Stock"); + cb(message, depth, LLError::LEVEL_WARN); + } + } + else if (cb) + { + // We warn if there's nothing in a regular folder (maybe it's an under construction listing) + std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Warning Empty"); + cb(message, depth, LLError::LEVEL_WARN); + } + } + else + { + // Done with that folder : Print out the folder name unless we already found an error here + if (cb && result && (depth >= 1)) + { + std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Log"); + cb(message, depth, LLError::LEVEL_INFO); + } + } + } + // If we have a single type of items of the right type in the right place, we're done + else if ((count == 1) && !has_bad_items && (((unique_key == default_key) && (depth > 1)) || ((folder_type == LLFolderType::FT_MARKETPLACE_STOCK) && (depth > 2) && (cat_array->size() == 0)))) + { + // Done with that folder : Print out the folder name unless we already found an error here + if (cb && result && (depth >= 1)) + { + std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Log"); + cb(message, depth, LLError::LEVEL_INFO); + } + } + else + { + if (fix_hierarchy && !has_bad_items) + { + // Alert the user when an existing stock folder has to be split + if ((folder_type == LLFolderType::FT_MARKETPLACE_STOCK) && ((count >= 2) || (cat_array->size() > 0))) + { + LLNotificationsUtil::add("AlertMerchantStockFolderSplit"); + } + // If we have more than 1 type of items or we are at the listing level or we have stock/no stock type mismatch, wrap the items in subfolders + if ((count > 1) || (depth == 1) || + ((folder_type == LLFolderType::FT_MARKETPLACE_STOCK) && (unique_key == default_key)) || + ((folder_type != LLFolderType::FT_MARKETPLACE_STOCK) && (unique_key != default_key))) + { + // Create one folder per vector at the right depth and of the right type + auto items_vector_it = items_vector.begin(); + while (items_vector_it != items_vector.end()) + { + // Create a new folder + LLUUID parent_uuid = (depth > 2 ? viewer_cat->getParentUUID() : viewer_cat->getUUID()); + LLViewerInventoryItem* viewer_inv_item = gInventory.getItem(items_vector_it->second.back()); + std::string folder_name = (depth >= 1 ? viewer_cat->getName() : viewer_inv_item->getName()); + LLFolderType::EType new_folder_type = (items_vector_it->first == default_key ? LLFolderType::FT_NONE : LLFolderType::FT_MARKETPLACE_STOCK); + if (cb) + { + std::string message = ""; + if (new_folder_type == LLFolderType::FT_MARKETPLACE_STOCK) + { + message = indent + folder_name + LLTrans::getString("Marketplace Validation Warning Create Stock"); + } + else + { + message = indent + folder_name + LLTrans::getString("Marketplace Validation Warning Create Version"); + } + cb(message, depth, LLError::LEVEL_WARN); + } + LLUUID folder_uuid = gInventory.createNewCategory(parent_uuid, new_folder_type, folder_name); + + // Move each item to the new folder + while (!items_vector_it->second.empty()) + { + LLViewerInventoryItem* viewer_inv_item = gInventory.getItem(items_vector_it->second.back()); + if (cb) + { + std::string message = indent + viewer_inv_item->getName() + LLTrans::getString("Marketplace Validation Warning Move"); + cb(message, depth, LLError::LEVEL_WARN); + } + gInventory.changeItemParent(viewer_inv_item, folder_uuid, true); + items_vector_it->second.pop_back(); + } + + // Next type + update_marketplace_category(parent_uuid); + update_marketplace_category(folder_uuid); + gInventory.notifyObservers(); + items_vector_it++; + } + } + // Stock folder should have no sub folder so reparent those up + if (folder_type == LLFolderType::FT_MARKETPLACE_STOCK) + { + LLUUID parent_uuid = cat->getParentUUID(); + gInventory.getDirectDescendentsOf(cat->getUUID(),cat_array,item_array); + LLInventoryModel::cat_array_t cat_array_copy = *cat_array; + for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++) + { + LLViewerInventoryCategory* viewer_cat = (LLViewerInventoryCategory*) (*iter); + gInventory.changeCategoryParent(viewer_cat, parent_uuid, false); + result &= validate_marketplacelistings(viewer_cat, cb, fix_hierarchy, depth); + } + } + } + else if (cb) + { + // We are not fixing the hierarchy but reporting problems, report everything we can find + // Print the folder name + if (result && (depth >= 1)) + { + if ((folder_type == LLFolderType::FT_MARKETPLACE_STOCK) && (count >= 2)) + { + // Report if a stock folder contains a mix of items + result = false; + std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Error Mixed Stock"); + cb(message, depth, LLError::LEVEL_ERROR); + } + else if ((folder_type == LLFolderType::FT_MARKETPLACE_STOCK) && (cat_array->size() != 0)) + { + // Report if a stock folder contains subfolders + result = false; + std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Error Subfolder In Stock"); + cb(message, depth, LLError::LEVEL_ERROR); + } + else + { + // Simply print the folder name + std::string message = indent + cat->getName() + LLTrans::getString("Marketplace Validation Log"); + cb(message, depth, LLError::LEVEL_INFO); + + } + } + // Scan each item and report if there's a problem + LLInventoryModel::item_array_t item_array_copy = *item_array; + for (LLInventoryModel::item_array_t::iterator iter = item_array_copy.begin(); iter != item_array_copy.end(); iter++) + { + LLInventoryItem* item = *iter; + LLViewerInventoryItem* viewer_inv_item = (LLViewerInventoryItem*) item; + std::string error_msg; + if (!can_move_to_marketplace(item, error_msg, false)) + { + // Report items that shouldn't be there to start with + result = false; + std::string message = indent + " " + viewer_inv_item->getName() + LLTrans::getString("Marketplace Validation Error") + " " + error_msg; + cb(message, depth, LLError::LEVEL_ERROR); + } + else if ((!viewer_inv_item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID())) && (folder_type != LLFolderType::FT_MARKETPLACE_STOCK)) + { + // Report stock items that are misplaced + result = false; + std::string message = indent + " " + viewer_inv_item->getName() + LLTrans::getString("Marketplace Validation Error Stock Item"); + cb(message, depth, LLError::LEVEL_ERROR); + } + else if (depth == 1) + { + // Report items not wrapped in version folder + result = false; + std::string message = indent + " " + viewer_inv_item->getName() + LLTrans::getString("Marketplace Validation Warning Unwrapped Item"); + cb(message, depth, LLError::LEVEL_ERROR); + } + } + } + + // Clean up + if (viewer_cat->getDescendentCount() == 0) + { + // Remove the current folder if it ends up empty + if (cb) + { + std::string message = indent + viewer_cat->getName() + LLTrans::getString("Marketplace Validation Warning Delete"); + cb(message, depth, LLError::LEVEL_WARN); + } + gInventory.removeCategory(cat->getUUID()); + gInventory.notifyObservers(); + return result && !has_bad_items; + } + } + + // Recursion : Perform the same validation on each nested folder + gInventory.getDirectDescendentsOf(cat->getUUID(),cat_array,item_array); LLInventoryModel::cat_array_t cat_array_copy = *cat_array; + // Sort the folders in alphabetical order first + std::sort(cat_array_copy.begin(), cat_array_copy.end(), sort_alpha); for (LLInventoryModel::cat_array_t::iterator iter = cat_array_copy.begin(); iter != cat_array_copy.end(); iter++) { - LLViewerInventoryCategory* category = *iter; - copy_folder_to_outbox(category, new_folder_id, top_level_folder, operation_id); + LLInventoryCategory* category = *iter; + result &= validate_marketplacelistings(category, cb, fix_hierarchy, depth + 1); } - open_outbox(); + update_marketplace_category(cat->getUUID()); + gInventory.notifyObservers(); + return result && !has_bad_items; } ///---------------------------------------------------------------------------- @@ -690,14 +1776,14 @@ bool LLInventoryCollectFunctor::itemTransferCommonlyAllowed(const LLInventoryIte case LLAssetType::AT_OBJECT: case LLAssetType::AT_BODYPART: case LLAssetType::AT_CLOTHING: - if (!get_is_item_worn(item->getUUID())) + //if (!get_is_item_worn(item->getUUID())) // return true; break; default: return true; break; } - return false; +// return false; } bool LLIsType::operator()(LLInventoryCategory* cat, LLInventoryItem* item) @@ -740,6 +1826,13 @@ bool LLIsOfAssetType::operator()(LLInventoryCategory* cat, LLInventoryItem* item return FALSE; } +bool LLIsValidItemLink::operator()(LLInventoryCategory* cat, LLInventoryItem* item) +{ + LLViewerInventoryItem *vitem = dynamic_cast(item); + if (!vitem) return false; + return (vitem->getActualType() == LLAssetType::AT_LINK && !vitem->getIsBrokenLink()); +} + bool LLIsTypeWithPermissions::operator()(LLInventoryCategory* cat, LLInventoryItem* item) { if(mType == LLAssetType::AT_CATEGORY) @@ -876,7 +1969,7 @@ bool LLFindWearablesEx::operator()(LLInventoryCategory* cat, LLInventoryItem* it if (!vitem) return false; // Skip non-wearables. - if (!vitem->isWearableType() && vitem->getType() != LLAssetType::AT_OBJECT) + if (!vitem->isWearableType() && vitem->getType() != LLAssetType::AT_OBJECT && vitem->getType() != LLAssetType::AT_GESTURE) { return false; } @@ -927,7 +2020,7 @@ bool LLFindNonRemovableObjects::operator()(LLInventoryCategory* cat, LLInventory return !get_is_category_removable(&gInventory, cat->getUUID()); } - llwarns << "Not a category and not an item?" << llendl; + LL_WARNS() << "Not a category and not an item?" << LL_ENDL; return false; } diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h index f42543e527..4b82be393c 100644 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -32,6 +32,10 @@ #include "llinventory.h" #include "llwearabletype.h" +// compute_stock_count() return error code +const S32 COMPUTE_STOCK_INFINITE = -1; +const S32 COMPUTE_STOCK_NOT_EVALUATED = -2; + /******************************************************************************** ** ** ** MISCELLANEOUS GLOBAL FUNCTIONS @@ -41,7 +45,6 @@ BOOL get_is_parent_to_worn_item(const LLUUID& id); // Is this item or its baseitem is worn, attached, etc... -BOOL get_is_item_worn(const LLInventoryItem *item); BOOL get_is_item_worn(const LLUUID& id); // Could this item be worn (correct type + not already being worn) @@ -55,20 +58,28 @@ BOOL get_is_category_renameable(const LLInventoryModel* model, const LLUUID& id) void show_item_profile(const LLUUID& item_uuid); +// Nudge the listing categories in the inventory to signal that their marketplace status changed +void update_marketplace_category(const LLUUID& cat_id, bool perform_consistency_enforcement = true); +// Nudge all listing categories to signal that their marketplace status changed +void update_all_marketplace_count(); + void rename_category(LLInventoryModel* model, const LLUUID& cat_id, const std::string& new_name); -void copy_inventory_category(LLInventoryModel* model, LLViewerInventoryCategory* cat, const LLUUID& parent_id, const LLUUID& root_copy_id = LLUUID::null); +void copy_inventory_category(LLInventoryModel* model, LLViewerInventoryCategory* cat, const LLUUID& parent_id, const LLUUID& root_copy_id = LLUUID::null, bool move_no_copy_items = false); // Generates a string containing the path to the item specified by item_id. void append_path(const LLUUID& id, std::string& path); -// Same as append_path but omits the root prefix "/My Inventory/". -void append_path_short(const LLUUID& id, std::string& path); - -void copy_item_to_outbox(LLInventoryItem* inv_item, LLUUID dest_folder, const LLUUID& top_level_folder, S32 operation_id); -void move_item_within_outbox(LLInventoryItem* inv_item, LLUUID dest_folder, S32 operation_id); +typedef boost::function validation_callback_t; -void copy_folder_to_outbox(LLInventoryCategory* inv_cat, const LLUUID& dest_folder, const LLUUID& top_level_folder, S32 operation_id); +bool can_move_item_to_marketplace(const LLInventoryCategory* root_folder, LLInventoryCategory* dest_folder, LLInventoryItem* inv_item, std::string& tooltip_msg, S32 bundle_size = 1, bool from_paste = false); +bool can_move_folder_to_marketplace(const LLInventoryCategory* root_folder, LLInventoryCategory* dest_folder, LLInventoryCategory* inv_cat, std::string& tooltip_msg, S32 bundle_size = 1, bool check_items = true, bool from_paste = false); +bool move_item_to_marketplacelistings(LLInventoryItem* inv_item, LLUUID dest_folder, bool copy = false); +bool move_folder_to_marketplacelistings(LLInventoryCategory* inv_cat, const LLUUID& dest_folder, bool copy = false, bool move_no_copy_items = false); +bool validate_marketplacelistings(LLInventoryCategory* inv_cat, validation_callback_t cb = NULL, bool fix_hierarchy = true, S32 depth = -1); +S32 depth_nesting_in_marketplace(LLUUID cur_uuid); +LLUUID nested_parent_id(LLUUID cur_uuid, S32 depth); +S32 compute_stock_count(LLUUID cat_uuid, bool force_count = false); /** Miscellaneous global functions ** ** @@ -186,6 +197,13 @@ class LLIsOfAssetType : public LLInventoryCollectFunctor LLAssetType::EType mType; }; +class LLIsValidItemLink : public LLInventoryCollectFunctor +{ +public: + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); +}; + class LLIsTypeWithPermissions : public LLInventoryCollectFunctor { public: @@ -231,7 +249,7 @@ class LLUniqueBuddyCollector : public LLInventoryCollectFunctor LLInventoryItem* item); protected: - std::set mSeen; + uuid_set_t mSeen; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -474,7 +492,7 @@ class LLSaveFolderState : public LLFolderViewFunctor void setApply(BOOL apply); void clearOpenFolders() { mOpenFolders.clear(); } protected: - std::set mOpenFolders; + uuid_set_t mOpenFolders; BOOL mApply; }; diff --git a/indra/newview/llinventoryicon.cpp b/indra/newview/llinventoryicon.cpp index f93dc8dd71..65b21fa7c8 100644 --- a/indra/newview/llinventoryicon.cpp +++ b/indra/newview/llinventoryicon.cpp @@ -79,6 +79,7 @@ LLIconDictionary::LLIconDictionary() addEntry(LLInventoryType::ICONNAME_CLOTHING_SKIRT, new IconEntry("inv_item_skirt.tga")); addEntry(LLInventoryType::ICONNAME_CLOTHING_ALPHA, new IconEntry("inv_item_alpha.tga")); addEntry(LLInventoryType::ICONNAME_CLOTHING_TATTOO, new IconEntry("inv_item_tattoo.tga")); + addEntry(LLInventoryType::ICONNAME_CLOTHING_UNIVERSAL, new IconEntry("Inv_Universal.png")); addEntry(LLInventoryType::ICONNAME_ANIMATION, new IconEntry("inv_item_animation.tga")); addEntry(LLInventoryType::ICONNAME_GESTURE, new IconEntry("inv_item_gesture.tga")); @@ -88,8 +89,14 @@ LLIconDictionary::LLIconDictionary() addEntry(LLInventoryType::ICONNAME_LINKFOLDER, new IconEntry("inv_link_folder.tga")); addEntry(LLInventoryType::ICONNAME_MESH, new IconEntry("inv_item_mesh.tga")); + addEntry(LLInventoryType::ICONNAME_SETTINGS_SKY, new IconEntry("Inv_SettingsSky.png")); + addEntry(LLInventoryType::ICONNAME_SETTINGS_WATER, new IconEntry("Inv_SettingsWater.png")); + addEntry(LLInventoryType::ICONNAME_SETTINGS_DAY, new IconEntry("Inv_SettingsDay.png")); + addEntry(LLInventoryType::ICONNAME_SETTINGS, new IconEntry("Inv_Settings.png")); + addEntry(LLInventoryType::ICONNAME_CLOTHING_UNKNOWN, new IconEntry("inv_item_unknown.tga")); addEntry(LLInventoryType::ICONNAME_INVALID, new IconEntry("inv_invalid.png")); + addEntry(LLInventoryType::ICONNAME_UNKNOWN, new IconEntry("Inv_UnknownObject.png")); addEntry(LLInventoryType::ICONNAME_NONE, new IconEntry("NONE")); } @@ -163,6 +170,14 @@ const std::string& LLInventoryIcon::getIconName(LLAssetType::EType asset_type, break; case LLAssetType::AT_MESH: idx = LLInventoryType::ICONNAME_MESH; + break; + case LLAssetType::AT_SETTINGS: + // TODO: distinguish between Sky and Water settings. + idx = assignSettingsIcon(misc_flag); + break; + case LLAssetType::AT_UNKNOWN: + idx = LLInventoryType::ICONNAME_UNKNOWN; + break; default: break; } @@ -179,6 +194,17 @@ const std::string& LLInventoryIcon::getIconName(LLInventoryType::EIconName idx) LLInventoryType::EIconName LLInventoryIcon::assignWearableIcon(U32 misc_flag) { - const LLWearableType::EType wearable_type = LLWearableType::EType(LLInventoryItemFlags::II_FLAGS_WEARABLES_MASK & misc_flag); + const LLWearableType::EType wearable_type = LLWearableType::EType(LLInventoryItemFlags::II_FLAGS_SUBTYPE_MASK & misc_flag); return LLWearableType::getIconName(wearable_type); } + +LLInventoryType::EIconName LLInventoryIcon::assignSettingsIcon(U32 misc_flag) +{ + switch (misc_flag & LLInventoryItemFlags::II_FLAGS_SUBTYPE_MASK) + { + case 0: return LLInventoryType::ICONNAME_SETTINGS_SKY; + case 1: return LLInventoryType::ICONNAME_SETTINGS_WATER; + case 2: return LLInventoryType::ICONNAME_SETTINGS_DAY; + } + return LLInventoryType::ICONNAME_SETTINGS; +} diff --git a/indra/newview/llinventoryicon.h b/indra/newview/llinventoryicon.h index 659448143d..58e1ffdb61 100644 --- a/indra/newview/llinventoryicon.h +++ b/indra/newview/llinventoryicon.h @@ -49,6 +49,7 @@ class LLInventoryIcon protected: static LLInventoryType::EIconName assignWearableIcon(U32 misc_flag); + static LLInventoryType::EIconName assignSettingsIcon(U32 misc_flag); }; #endif // LL_LLINVENTORYICON_H diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index e36753bfe1..3d020e9d48 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -4,7 +4,7 @@ * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. + * Copyright (C) 2014, Linden Research, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -25,11 +25,16 @@ */ #include "llviewerprecompiledheaders.h" + +#include + #include "llinventorymodel.h" +#include "llaisapi.h" #include "llagent.h" #include "llagentwearables.h" #include "llappearancemgr.h" +#include "llavatarnamecache.h" #include "llinventoryclipboard.h" #include "llinventorypanel.h" #include "llinventorybridge.h" @@ -37,6 +42,7 @@ #include "llinventoryobserver.h" #include "llinventorypanel.h" #include "llnotificationsutil.h" +#include "llmarketplacefunctions.h" #include "llwindow.h" #include "llviewercontrol.h" #include "llpreview.h" @@ -48,7 +54,7 @@ #include "llcallbacklist.h" #include "llvoavatarself.h" #include "llgesturemgr.h" -#include +#include "llsdutil.h" #include "statemachine/aievent.h" // [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a) @@ -61,11 +67,8 @@ #include "process.h" #endif -class AIHTTPTimeoutPolicy; -extern AIHTTPTimeoutPolicy createInventoryCategoryResponder_timeout; - // Increment this if the inventory contents change in a non-backwards-compatible way. -// For viewers with link items support, former caches are incorrect. +// For viewer 2, the addition of link items makes a pre-viewer-2 cache incorrect. const S32 LLInventoryModel::sCurrentInvCacheVersion = 2; BOOL LLInventoryModel::sFirstTimeInViewer2 = TRUE; @@ -74,7 +77,8 @@ BOOL LLInventoryModel::sFirstTimeInViewer2 = TRUE; ///---------------------------------------------------------------------------- //BOOL decompress_file(const char* src_filename, const char* dst_filename); -const char CACHE_FORMAT_STRING[] = "%s.inv"; +static const char CACHE_FORMAT_STRING[] = "%s.inv"; +static const char * const LOG_INV("Inventory"); struct InventoryIDPtrLess { @@ -88,11 +92,11 @@ class LLCanCache : public LLInventoryCollectFunctor { public: LLCanCache(LLInventoryModel* model) : mModel(model) {} - virtual ~LLCanCache() {} - virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); + virtual ~LLCanCache() = default; + bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) override; protected: LLInventoryModel* mModel; - std::set mCachedCatIDs; + uuid_set_t mCachedCatIDs; }; bool LLCanCache::operator()(LLInventoryCategory* cat, LLInventoryItem* item) @@ -112,17 +116,7 @@ bool LLCanCache::operator()(LLInventoryCategory* cat, LLInventoryItem* item) if(c->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN) { S32 descendents_server = c->getDescendentCount(); - LLInventoryModel::cat_array_t* cats; - LLInventoryModel::item_array_t* items; - mModel->getDirectDescendentsOf( - c->getUUID(), - cats, - items); - S32 descendents_actual = 0; - if(cats && items) - { - descendents_actual = cats->count() + items->count(); - } + S32 descendents_actual = c->getViewerDescendentCount(); if(descendents_server == descendents_actual) { mCachedCatIDs.insert(c->getUUID()); @@ -142,23 +136,25 @@ LLInventoryModel gInventory; // Default constructor LLInventoryModel::LLInventoryModel() -: mModifyMask(LLInventoryObserver::ALL), - mChangedItemIDs(), +: // These are now ordered, keep them that way. + mIsAgentInvUsable(false), + mRootFolderID(), + mLibraryRootFolderID(), + mLibraryOwnerID(), mCategoryMap(), mItemMap(), - mCategoryLock(), - mItemLock(), - mLastItem(NULL), mParentChildCategoryTree(), mParentChildItemTree(), - mObservers(), - mRootFolderID(), - mLibraryRootFolderID(), - mLibraryOwnerID(), + mBacklinkMMap(), + mLastItem(nullptr), mIsNotifyObservers(FALSE), - mIsAgentInvUsable(false) -{ -} + mModifyMask(LLInventoryObserver::ALL), + mChangedItemIDs(), + mObservers(), + mCategoryLock(), + mItemLock() +{} + // Destroys the object LLInventoryModel::~LLInventoryModel() @@ -189,7 +185,7 @@ BOOL LLInventoryModel::isObjectDescendentOf(const LLUUID& obj_id, if (obj_id == cat_id) return TRUE; //The while loop will ALWAYS return false if parent_id is null, regardless of cat_id being null too. Don't bother trying. if(cat_id.isNull()) return FALSE; - LLInventoryObject* obj = getObject(obj_id); + const LLInventoryObject* obj = getObject(obj_id); int depthCounter = 0; while(obj) { @@ -199,14 +195,14 @@ BOOL LLInventoryModel::isObjectDescendentOf(const LLUUID& obj_id, { if(depthCounter++ >= 100) { - llwarns << "In way too damn deep, possibly recursive parenting" << llendl; - llinfos << obj->getName() << " : " << obj->getUUID() << " : " << parent_id << llendl; + LL_WARNS() << "In way too damn deep, possibly recursive parenting" << LL_ENDL; + LL_INFOS() << obj->getName() << " : " << obj->getUUID() << " : " << parent_id << LL_ENDL; return FALSE; } if(parent_id == obj->getUUID()) { // infinite loop... same thing as having no parent, hopefully. - llwarns << "This shit has itself as parent! " << parent_id.asString() << ", " << obj->getName() << llendl; + LL_WARNS() << "This shit has itself as parent! " << parent_id.asString() << ", " << obj->getName() << LL_ENDL; return FALSE; } } @@ -229,7 +225,11 @@ BOOL LLInventoryModel::isObjectDescendentOf(const LLUUID& obj_id, const LLViewerInventoryCategory *LLInventoryModel::getFirstNondefaultParent(const LLUUID& obj_id) const { const LLInventoryObject* obj = getObject(obj_id); - + if(!obj) + { + LL_WARNS(LOG_INV) << "Non-existent object [ id: " << obj_id << " ] " << LL_ENDL; + return nullptr; + } // Search up the parent chain until we get to root or an acceptable folder. // This assumes there are no cycles in the tree else we'll get a hang. LLUUID parent_id = obj->getParentUUID(); @@ -246,7 +246,7 @@ const LLViewerInventoryCategory *LLInventoryModel::getFirstNondefaultParent(cons } parent_id = cat->getParentUUID(); } - return NULL; + return nullptr; } // @@ -256,17 +256,17 @@ const LLViewerInventoryCategory* LLInventoryModel::getFirstDescendantOf(const LL { if (master_parent_id == obj_id) { - return NULL; + return nullptr; } const LLViewerInventoryCategory* current_cat = getCategory(obj_id); - if (current_cat == NULL) + if (current_cat == nullptr) { current_cat = getCategory(getObject(obj_id)->getParentUUID()); } - while (current_cat != NULL) + while (current_cat != nullptr) { const LLUUID& current_parent_id = current_cat->getParentUUID(); @@ -278,7 +278,24 @@ const LLViewerInventoryCategory* LLInventoryModel::getFirstDescendantOf(const LL current_cat = getCategory(current_parent_id); } - return NULL; + return nullptr; +} + +bool LLInventoryModel::getObjectTopmostAncestor(const LLUUID& object_id, LLUUID& result) const +{ + LLInventoryObject *object = getObject(object_id); + while (object && object->getParentUUID().notNull()) + { + LLInventoryObject *parent_object = getObject(object->getParentUUID()); + if (!parent_object) + { + LL_WARNS(LOG_INV) << "unable to trace topmost ancestor, missing item for uuid " << object->getParentUUID() << LL_ENDL; + return false; + } + object = parent_object; + } + result = object->getUUID(); + return true; } // Get the object by id. Returns NULL if not found. @@ -294,21 +311,21 @@ LLInventoryObject* LLInventoryModel::getObject(const LLUUID& id) const { return item; } - return NULL; + return nullptr; } // Get the item by id. Returns NULL if not found. LLViewerInventoryItem* LLInventoryModel::getItem(const LLUUID& id) const { - LLViewerInventoryItem* item = NULL; + LLViewerInventoryItem* item = nullptr; if(mLastItem.notNull() && mLastItem->getUUID() == id) { item = mLastItem; } else { - item_map_t::const_iterator iter = mItemMap.find(id); - if (iter != mItemMap.end()) + const auto iter = mItemMap.find(id); + if (iter != mItemMap.cend()) { item = iter->second; mLastItem = item; @@ -320,13 +337,12 @@ LLViewerInventoryItem* LLInventoryModel::getItem(const LLUUID& id) const // Get the category by id. Returns NULL if not found LLViewerInventoryCategory* LLInventoryModel::getCategory(const LLUUID& id) const { - LLViewerInventoryCategory* category = NULL; - cat_map_t::const_iterator iter = mCategoryMap.find(id); - if (iter != mCategoryMap.end()) + const auto iter = mCategoryMap.find(id); + if (iter != mCategoryMap.cend()) { - category = iter->second; + return iter->second; } - return category; + return nullptr; } S32 LLInventoryModel::getItemCount() const @@ -372,7 +388,7 @@ LLMD5 LLInventoryModel::hashDirectDescendentNames(const LLUUID& cat_id) const } for (LLInventoryModel::item_array_t::const_iterator iter = item_array->begin(); iter != item_array->end(); - iter++) + ++iter) { const LLViewerInventoryItem *item = (*iter); if (!item) @@ -405,40 +421,98 @@ void LLInventoryModel::unlockDirectDescendentArrays(const LLUUID& cat_id) mItemLock[cat_id] = false; } -// findCategoryUUIDForType() returns the uuid of the category that -// specifies 'type' as what it defaults to containing. The category is -// not necessarily only for that type. *NOTE: This will create a new -// inventory category on the fly if one does not exist. -const LLUUID LLInventoryModel::findCategoryUUIDForType(LLFolderType::EType preferred_type, - bool create_folder, - bool find_in_library) +void LLInventoryModel::consolidateForType(const LLUUID& main_id, LLFolderType::EType type) +{ + // Make a list of folders that are not "main_id" and are of "type" + uuid_vec_t folder_ids; + for (const auto& cat_pair : mCategoryMap) + { + LLViewerInventoryCategory* cat = cat_pair.second; + if ((cat->getPreferredType() == type) && (cat->getUUID() != main_id)) + { + folder_ids.push_back(cat->getUUID()); + } + } + + // Iterate through those folders + for (LLUUID const& folder_id: folder_ids) + { + // Get the content of this folder + cat_array_t* cats; + item_array_t* items; + getDirectDescendentsOf(folder_id, cats, items); + + // Move all items to the main folder + // Note : we get the list of UUIDs and iterate on them instead of iterating directly on item_array_t + // elements. This is because moving elements modify the maps and, consequently, invalidate iterators on them. + // This "gather and iterate" method is verbose but resilient. + uuid_vec_t list_uuids; + for (item_array_t::const_iterator it = items->begin(); it != items->end(); ++it) + { + list_uuids.push_back((*it)->getUUID()); + } + for (auto it = list_uuids.begin(); it != list_uuids.end(); ++it) + { + LLViewerInventoryItem* item = getItem(*it); + changeItemParent(item, main_id, TRUE); + } + + // Move all folders to the main folder + list_uuids.clear(); + for (cat_array_t::const_iterator it = cats->begin(); it != cats->end(); ++it) + { + list_uuids.push_back((*it)->getUUID()); + } + for (auto it = list_uuids.begin(); it != list_uuids.end(); ++it) + { + LLViewerInventoryCategory* cat = getCategory(*it); + changeCategoryParent(cat, main_id, TRUE); + } + + // Purge the emptied folder + // Note: we'd like to use purgeObject() but it doesn't cleanly eliminate the folder + // which leads to issues further down the road when the folder is found again + //purgeObject(folder_id); + // We remove the folder and empty the trash instead which seems to work + removeCategory(folder_id); + gInventory.emptyFolderType("", LLFolderType::FT_TRASH); + } +} + + + +const LLUUID LLInventoryModel::findCategoryUUIDForTypeInRoot( + LLFolderType::EType preferred_type, + bool create_folder, + const LLUUID& root_id) { LLUUID rv = LLUUID::null; - - const LLUUID &root_id = (find_in_library) ? gInventory.getLibraryRootFolderID() : gInventory.getRootFolderID(); if(LLFolderType::FT_ROOT_INVENTORY == preferred_type) { rv = root_id; } else if (root_id.notNull()) { - cat_array_t* cats = NULL; + cat_array_t* cats = nullptr; cats = get_ptr_in_map(mParentChildCategoryTree, root_id); if(cats) { - S32 count = cats->count(); + S32 count = cats->size(); for(S32 i = 0; i < count; ++i) { - if(cats->get(i)->getPreferredType() == preferred_type) + if(cats->at(i)->getPreferredType() == preferred_type) { - rv = cats->get(i)->getUUID(); - break; + const LLUUID& folder_id = cats->at(i)->getUUID(); + if (rv.isNull() || folder_id < rv) + { + rv = folder_id; + } } } } } - if(rv.isNull() && isInventoryUsable() && (create_folder && !find_in_library)) + if(rv.isNull() && isInventoryUsable() && create_folder) { if(root_id.notNull()) { @@ -448,6 +522,20 @@ const LLUUID LLInventoryModel::findCategoryUUIDForType(LLFolderType::EType prefe return rv; } +// findCategoryUUIDForType() returns the uuid of the category that +// specifies 'type' as what it defaults to containing. The category is +// not necessarily only for that type. *NOTE: This will create a new +// inventory category on the fly if one does not exist. +const LLUUID LLInventoryModel::findCategoryUUIDForType(LLFolderType::EType preferred_type, bool create_folder) +{ + return findCategoryUUIDForTypeInRoot(preferred_type, create_folder, gInventory.getRootFolderID()); +} + +const LLUUID LLInventoryModel::findLibraryCategoryUUIDForType(LLFolderType::EType preferred_type, bool create_folder) +{ + return findCategoryUUIDForTypeInRoot(preferred_type, create_folder, gInventory.getLibraryRootFolderID()); +} + LLUUID LLInventoryModel::findCategoryByName(std::string name) { LLUUID root_id = gInventory.getRootFolderID(); @@ -457,12 +545,12 @@ LLUUID LLInventoryModel::findCategoryByName(std::string name) cats = get_ptr_in_map(mParentChildCategoryTree, root_id); if(cats) { - S32 count = cats->count(); + S32 count = cats->size(); for(S32 i = 0; i < count; ++i) { - if(cats->get(i)->getName() == name) + if(cats->at(i)->getName() == name) { - return cats->get(i)->getUUID(); + return cats->at(i)->getUUID(); } } } @@ -470,56 +558,58 @@ LLUUID LLInventoryModel::findCategoryByName(std::string name) return LLUUID::null; } -class LLCreateInventoryCategoryResponder : public LLHTTPClient::ResponderWithResult +class LLCreateInventoryCategoryResponder final : public LLHTTPClient::ResponderWithResult { + LOG_CLASS(LLCreateInventoryCategoryResponder); public: - LLCreateInventoryCategoryResponder(LLInventoryModel* model, - void (*callback)(const LLSD&, void*), - void* user_data) : - mModel(model), - mCallback(callback), - mData(user_data) + LLCreateInventoryCategoryResponder(LLInventoryModel* model, + boost::optional callback): + mModel(model), + mCallback(callback) { } - /*virtual*/ void error(U32 status, const std::string& reason) +protected: + void httpFailure() override { - LL_WARNS("InvAPI") << "CreateInventoryCategory failed. status = " << status << ", reasion = \"" << reason << "\"" << LL_ENDL; + LL_WARNS(LOG_INV) << dumpResponse() << LL_ENDL; } - /*virtual*/ void result(const LLSD& content) + void httpSuccess() override { //Server has created folder. - + const LLSD& content = getContent(); + if (!content.isMap() || !content.has("folder_id")) + { + failureResult(400, "Malformed response contents", content); + return; + } LLUUID category_id = content["folder_id"].asUUID(); - - + + LL_DEBUGS(LOG_INV) << ll_pretty_print_sd(content) << LL_ENDL; // Add the category to the internal representation LLPointer cat = - new LLViewerInventoryCategory( category_id, + new LLViewerInventoryCategory( category_id, content["parent_id"].asUUID(), (LLFolderType::EType)content["type"].asInteger(), - content["name"].asString(), + content["name"].asString(), gAgent.getID() ); cat->setVersion(LLViewerInventoryCategory::VERSION_INITIAL); cat->setDescendentCount(0); LLInventoryModel::LLCategoryUpdate update(cat->getParentUUID(), 1); mModel->accountForUpdate(update); mModel->updateCategory(cat); - - if (mCallback && mData) + + if (mCallback) { - mCallback(content, mData); + mCallback.get()(category_id); } - } - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return createInventoryCategoryResponder_timeout; } - /*virtual*/ char const* getName(void) const { return "LLCreateInventoryCategoryResponder"; } + char const* getName(void) const override { return "LLCreateInventoryCategoryResponder"; } private: - void (*mCallback)(const LLSD&, void*); - void* mData; + boost::optional mCallback; LLInventoryModel* mModel; }; @@ -530,19 +620,19 @@ class LLCreateInventoryCategoryResponder : public LLHTTPClient::ResponderWithRes LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id, LLFolderType::EType preferred_type, const std::string& pname, - void (*callback)(const LLSD&, void*), //Default to NULL - void* user_data) //Default to NULL + boost::optional callback) { + LLUUID id; if(!isInventoryUsable()) { - llwarns << "Inventory is broken." << llendl; + LL_WARNS(LOG_INV) << "Inventory is broken." << LL_ENDL; return id; } if(LLFolderType::lookup(preferred_type) == LLFolderType::badLookup()) { - lldebugs << "Attempt to create undefined category. (" << preferred_type << ")" << llendl; + LL_DEBUGS(LOG_INV) << "Attempt to create undefined category." << LL_ENDL; return id; } @@ -556,41 +646,44 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id, { name.assign(LLViewerFolderType::lookupNewCategoryName(preferred_type)); } - - if ( callback && user_data ) //callback required for acked message. + + LLViewerRegion* viewer_region = gAgent.getRegion(); + std::string url; + if ( viewer_region ) + url = viewer_region->getCapability("CreateInventoryCategory"); + + if (!url.empty() && callback.get_ptr()) { - LLViewerRegion* viewer_region = gAgent.getRegion(); - std::string url; - if ( viewer_region ) - url = viewer_region->getCapability("CreateInventoryCategory"); - - if (!url.empty()) - { - //Let's use the new capability. + //Let's use the new capability. + + LLSD request, body; + body["folder_id"] = id; + body["parent_id"] = parent_id; + body["type"] = (LLSD::Integer) preferred_type; + body["name"] = name; + + request["message"] = "CreateInventoryCategory"; + request["payload"] = body; -// LLSD request; - LLSD body; - body["folder_id"] = id; - body["parent_id"] = parent_id; - body["type"] = (LLSD::Integer) preferred_type; - body["name"] = name; + LL_DEBUGS(LOG_INV) << "create category request: " << ll_pretty_print_sd(request) << LL_ENDL; + // viewer_region->getCapAPI().post(request); + LLHTTPClient::post( + url, + body, + new LLCreateInventoryCategoryResponder(this, callback) ); -// request["message"] = "CreateInventoryCategory"; -// request["payload"] = body; + return LLUUID::null; + } -// viewer_region->getCapAPI().post(request); - LLHTTPClient::post( - url, - body, - new LLCreateInventoryCategoryResponder(this, callback, user_data) ); - return LLUUID::null; - } + if (!gMessageSystem) + { + return LLUUID::null; } // Add the category to the internal representation LLPointer cat = new LLViewerInventoryCategory(id, parent_id, preferred_type, name, gAgent.getID()); - cat->setVersion(LLViewerInventoryCategory::VERSION_INITIAL); + cat->setVersion(LLViewerInventoryCategory::VERSION_INITIAL - 1); // accountForUpdate() will icrease version by 1 cat->setDescendentCount(0); LLCategoryUpdate update(cat->getParentUUID(), 1); accountForUpdate(update); @@ -611,7 +704,53 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id, return id; } -// Starting with the object specified, add it's descendents to the +// This is optimized for the case that we just want to know whether a +// category has any immediate children meeting a condition, without +// needing to recurse or build up any lists. +bool LLInventoryModel::hasMatchingDirectDescendent(const LLUUID& cat_id, + LLInventoryCollectFunctor& filter, bool follow_folder_links) +{ + LLInventoryModel::cat_array_t *cats; + LLInventoryModel::item_array_t *items; + getDirectDescendentsOf(cat_id, cats, items); + if (cats) + { + for (LLInventoryModel::cat_array_t::const_iterator it = cats->begin(); + it != cats->end(); ++it) + { + if (filter(*it, nullptr)) + { + return true; + } + } + } + if (items) + { + for (LLInventoryModel::item_array_t::const_iterator it = items->begin(); + it != items->end(); ++it) + { + if (filter(nullptr, *it)) + { + return true; + } + // Follow folder links recursively. Currently never goes more + // than one level deep (for current outfit support) + // Note: if making it fully recursive, need more checking against infinite loops. + else if (follow_folder_links && *it && it->get()->getActualType() == LLAssetType::AT_LINK_FOLDER) + { + LLViewerInventoryCategory *linked_cat = it->get()->getLinkedCategory(); + if (linked_cat && linked_cat->getPreferredType() != LLFolderType::FT_OUTFIT) + { + if (hasMatchingDirectDescendent(linked_cat->getUUID(), filter)) + return true; + } + } + } + } + return false; +} + +// Starting with the object specified, add its descendents to the // array provided, but do not add the inventory object specified by // id. There is no guaranteed order. Neither array will be erased // before adding objects to it. Do not store a copy of the pointers @@ -621,9 +760,10 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id, class LLAlwaysCollect : public LLInventoryCollectFunctor { public: - virtual ~LLAlwaysCollect() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item) + virtual ~LLAlwaysCollect() = default; + + bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item) override { return TRUE; } @@ -638,12 +778,19 @@ void LLInventoryModel::collectDescendents(const LLUUID& id, collectDescendentsIf(id, cats, items, include_trash, always); } +//void LLInventoryModel::collectDescendentsIf(const LLUUID& id, +// cat_array_t& cats, +// item_array_t& items, +// BOOL include_trash, +// LLInventoryCollectFunctor& add) +// [RLVa:KB] - Checked: 2013-04-15 (RLVa-1.4.8) void LLInventoryModel::collectDescendentsIf(const LLUUID& id, cat_array_t& cats, item_array_t& items, BOOL include_trash, LLInventoryCollectFunctor& add, - BOOL follow_folder_links) + bool follow_folder_links) +// [/RLVa:KB] { // Start with categories if(!include_trash) @@ -655,31 +802,34 @@ void LLInventoryModel::collectDescendentsIf(const LLUUID& id, cat_array_t* cat_array = get_ptr_in_map(mParentChildCategoryTree, id); if(cat_array) { - S32 count = cat_array->count(); + S32 count = cat_array->size(); for(S32 i = 0; i < count; ++i) { - LLViewerInventoryCategory* cat = cat_array->get(i); - if(add(cat,NULL)) + LLViewerInventoryCategory* cat = cat_array->at(i); + if(add(cat, nullptr)) { - cats.put(cat); + cats.push_back(cat); } - collectDescendentsIf(cat->getUUID(), cats, items, include_trash, add); +// [RLVa:KB] - Checked: 2013-04-15 (RLVa-1.4.8) + collectDescendentsIf(cat->getUUID(), cats, items, include_trash, add, follow_folder_links); +// [/RLVa:KB] +// collectDescendentsIf(cat->getUUID(), cats, items, include_trash, add); } } - LLViewerInventoryItem* item = NULL; + LLViewerInventoryItem* item = nullptr; item_array_t* item_array = get_ptr_in_map(mParentChildItemTree, id); // Move onto items if(item_array) { - S32 count = item_array->count(); + S32 count = item_array->size(); for(S32 i = 0; i < count; ++i) { - item = item_array->get(i); - if(add(NULL, item)) + item = item_array->at(i); + if(add(nullptr, item)) { - items.put(item); + items.push_back(item); } } } @@ -691,16 +841,15 @@ void LLInventoryModel::collectDescendentsIf(const LLUUID& id, // This breaks the "finish collecting all folders before collecting items (top to bottom and then bottom to top)" // assumption but no functor is (currently) relying on it (and likely never should since it's an implementation detail?) // [Only LLAppearanceMgr actually ever passes in 'follow_folder_links == TRUE'] -// [/RLVa:KB] // Follow folder links recursively. Currently never goes more // than one level deep (for current outfit support) // Note: if making it fully recursive, need more checking against infinite loops. if (follow_folder_links && item_array) { - S32 count = item_array->count(); + S32 count = item_array->size(); for(S32 i = 0; i < count; ++i) { - item = item_array->get(i); + item = item_array->at(i); if (item && item->getActualType() == LLAssetType::AT_LINK_FOLDER) { LLViewerInventoryCategory *linked_cat = item->getLinkedCategory(); @@ -714,13 +863,14 @@ void LLInventoryModel::collectDescendentsIf(const LLUUID& id, // BAP should this be added here? May not // matter if it's only being used in current // outfit traversal. - cats.put(LLPointer(linked_cat)); + cats.push_back(LLPointer(linked_cat)); } - collectDescendentsIf(linked_cat->getUUID(), cats, items, include_trash, add, FALSE); + collectDescendentsIf(linked_cat->getUUID(), cats, items, include_trash, add, false); } } } } +// [/RLVa:KB] } void LLInventoryModel::addChangedMaskForLinks(const LLUUID& object_id, U32 mask) @@ -729,31 +879,10 @@ void LLInventoryModel::addChangedMaskForLinks(const LLUUID& object_id, U32 mask) if (!obj || obj->getIsLinkType()) return; - LLInventoryModel::cat_array_t cat_array; - LLInventoryModel::item_array_t item_array; - LLLinkedItemIDMatches is_linked_item_match(object_id); - collectDescendentsIf(gInventory.getRootFolderID(), - cat_array, - item_array, - LLInventoryModel::INCLUDE_TRASH, - is_linked_item_match); - if (cat_array.empty() && item_array.empty()) + LLInventoryModel::item_array_t item_array = collectLinksTo(object_id); + for (auto& iter : item_array) { - return; - } - for (LLInventoryModel::cat_array_t::iterator cat_iter = cat_array.begin(); - cat_iter != cat_array.end(); - cat_iter++) - { - LLViewerInventoryCategory *linked_cat = (*cat_iter); - addChangedMask(mask, linked_cat->getUUID()); - }; - - for (LLInventoryModel::item_array_t::iterator iter = item_array.begin(); - iter != item_array.end(); - iter++) - { - LLViewerInventoryItem *linked_item = (*iter); + LLViewerInventoryItem *linked_item = iter; addChangedMask(mask, linked_item->getUUID()); }; } @@ -776,17 +905,29 @@ LLViewerInventoryItem* LLInventoryModel::getLinkedItem(const LLUUID& object_id) return object_id.notNull() ? getItem(getLinkedItemID(object_id)) : NULL; } -LLInventoryModel::item_array_t LLInventoryModel::collectLinkedItems(const LLUUID& id, +LLInventoryModel::item_array_t LLInventoryModel::collectLinksTo(const LLUUID& id, const LLUUID& start_folder_id) { + // Get item list via collectDescendents (slow!) item_array_t items; - LLInventoryModel::cat_array_t cat_array; - LLLinkedItemIDMatches is_linked_item_match(id); - collectDescendentsIf((start_folder_id == LLUUID::null ? gInventory.getRootFolderID() : start_folder_id), - cat_array, - items, - LLInventoryModel::INCLUDE_TRASH, - is_linked_item_match); + const LLInventoryObject *obj = getObject(id); + // FIXME - should be as in next line, but this is causing a + // stack-smashing crash of cause TBD... check in the REBUILD code. + //if (obj && obj->getIsLinkType()) + if (!obj || obj->getIsLinkType()) + return items; + + std::pair range = mBacklinkMMap.equal_range(id); + for (backlink_mmap_t::iterator it = range.first; it != range.second; ++it) + { + LLViewerInventoryItem *item = getItem(it->second); + if (item) + { + if(start_folder_id.isNull() || isObjectDescendentOf(it->second, start_folder_id)) + items.push_back(item); + } + } + return items; } @@ -803,9 +944,8 @@ bool LLInventoryModel::isInventoryUsable() const // Calling this method with an inventory item will either change an // existing item with a matching item_id, or will add the item to the // current inventory. -U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item) +U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item, U32 mask) { - U32 mask = LLInventoryObserver::NONE; if(item->getUUID().isNull()) { return mask; @@ -813,19 +953,11 @@ U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item) if(!isInventoryUsable()) { - llwarns << "Inventory is broken." << llendl; + LL_WARNS(LOG_INV) << "Inventory is broken." << LL_ENDL; return mask; } - // We're hiding mesh types -#if 0 - if (item->getType() == LLAssetType::AT_MESH) - { - return mask; - } -#endif - - LLViewerInventoryItem* old_item = getItem(item->getUUID()); + LLPointer old_item = getItem(item->getUUID()); LLPointer new_item; if(old_item) { @@ -833,20 +965,36 @@ U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item) new_item = old_item; LLUUID old_parent_id = old_item->getParentUUID(); LLUUID new_parent_id = item->getParentUUID(); + bool update_parent_on_server = false; + + if (new_parent_id.isNull()) + { + // item with null parent will end in random location and then in Lost&Found, + // either move to default folder as if it is new item or don't move at all + LL_WARNS(LOG_INV) << "Update attempts to reparent item " << item->getUUID() + << " to null folder. Moving to Lost&Found. Old item name: " << old_item->getName() + << ". New name: " << item->getName() + << "." << LL_ENDL; + new_parent_id = findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); + update_parent_on_server = true; + } if(old_parent_id != new_parent_id) { - // need to update the parent-child tree - item_array_t* item_array; - item_array = get_ptr_in_map(mParentChildItemTree, old_parent_id); + item_array_t * item_array = get_ptr_in_map(mParentChildItemTree, old_parent_id); if(item_array) { - item_array->removeObj(old_item); + vector_replace_with_last(*item_array, old_item); } item_array = get_ptr_in_map(mParentChildItemTree, new_parent_id); if(item_array) { - item_array->put(old_item); + if (update_parent_on_server) + { + LLInventoryModel::LLCategoryUpdate update(new_parent_id, 1); + gInventory.accountForUpdate(update); + } + item_array->push_back(old_item); } mask |= LLInventoryObserver::STRUCTURE; } @@ -859,6 +1007,12 @@ U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item) mask |= LLInventoryObserver::DESCRIPTION; } old_item->copyViewerItem(item); + if (update_parent_on_server) + { + // Parent id at server is null, so update server even if item already is in the same folder + old_item->setParent(new_parent_id); + new_item->updateParentOnServer(FALSE); + } mask |= LLInventoryObserver::INTERNAL; } else @@ -874,13 +1028,16 @@ U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item) item_array_t* item_array = get_ptr_in_map(mParentChildItemTree, category_id); if( item_array ) { + LLInventoryModel::LLCategoryUpdate update(category_id, 1); + gInventory.accountForUpdate(update); + // *FIX: bit of a hack to call update server from here... - new_item->updateServer(TRUE); - item_array->put(new_item); + new_item->updateParentOnServer(FALSE); + item_array->push_back(new_item); } else { - llwarns << "Couldn't find parent-child item tree for " << new_item->getName() << llendl; + LL_WARNS(LOG_INV) << "Couldn't find parent-child item tree for " << new_item->getName() << LL_ENDL; } } else @@ -904,26 +1061,28 @@ U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item) item_array_t* item_array = get_ptr_in_map(mParentChildItemTree, parent_id); if(item_array) { - item_array->put(new_item); + item_array->push_back(new_item); } else { // Whoops! No such parent, make one. - llinfos << "Lost item: " << new_item->getUUID() << " - " - << new_item->getName() << llendl; + LL_INFOS(LOG_INV) << "Lost item: " << new_item->getUUID() << " - " + << new_item->getName() << LL_ENDL; parent_id = findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); new_item->setParent(parent_id); item_array = get_ptr_in_map(mParentChildItemTree, parent_id); if(item_array) { + LLInventoryModel::LLCategoryUpdate update(parent_id, 1); + gInventory.accountForUpdate(update); // *FIX: bit of a hack to call update server from // here... - new_item->updateServer(TRUE); - item_array->put(new_item); + new_item->updateParentOnServer(FALSE); + item_array->push_back(new_item); } else { - llwarns << "Lost and found Not there!!" << llendl; + LL_WARNS(LOG_INV) << "Lost and found Not there!!" << LL_ENDL; } } } @@ -941,19 +1100,17 @@ U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item) { // Valid UUID; set the item UUID and rename it new_item->setCreator(id); - std::string avatar_name; + LLAvatarName av_name; - if (gCacheName->getFullName(id, avatar_name)) + if (LLAvatarNameCache::get(id, &av_name)) { - new_item->rename(avatar_name); + new_item->rename(av_name.getLegacyName()); mask |= LLInventoryObserver::LABEL; } else { // Fetch the current name - gCacheName->get(id, FALSE, - boost::bind(&LLViewerInventoryItem::onCallingCardNameLookup, new_item.get(), - _1, _2, _3)); + LLAvatarNameCache::get(id, boost::bind(&LLViewerInventoryItem::onCallingCardNameLookup, new_item.get(), _1, _2)); } } @@ -988,46 +1145,51 @@ LLInventoryModel::item_array_t* LLInventoryModel::getUnlockedItemArray(const LLU // Calling this method with an inventory category will either change // an existing item with the matching id, or it will add the category. -void LLInventoryModel::updateCategory(const LLViewerInventoryCategory* cat) +void LLInventoryModel::updateCategory(const LLViewerInventoryCategory* cat, U32 mask) { - if(cat->getUUID().isNull()) + if(!cat || cat->getUUID().isNull()) { return; } if(!isInventoryUsable()) { - llwarns << "Inventory is broken." << llendl; + LL_WARNS(LOG_INV) << "Inventory is broken." << LL_ENDL; return; } - LLViewerInventoryCategory* old_cat = getCategory(cat->getUUID()); + LLPointer old_cat = getCategory(cat->getUUID()); if(old_cat) { - // We already have an old category, modify it's values - U32 mask = LLInventoryObserver::NONE; + // We already have an old category, modify its values LLUUID old_parent_id = old_cat->getParentUUID(); LLUUID new_parent_id = cat->getParentUUID(); if(old_parent_id != new_parent_id) { // need to update the parent-child tree - cat_array_t* cat_array; - cat_array = getUnlockedCatArray(old_parent_id); + cat_array_t* cat_array = getUnlockedCatArray(old_parent_id); if(cat_array) { - cat_array->removeObj(old_cat); + vector_replace_with_last(*cat_array, old_cat); } cat_array = getUnlockedCatArray(new_parent_id); if(cat_array) { - cat_array->put(old_cat); + cat_array->push_back(old_cat); } mask |= LLInventoryObserver::STRUCTURE; + mask |= LLInventoryObserver::INTERNAL; } if(old_cat->getName() != cat->getName()) { mask |= LLInventoryObserver::LABEL; } + // Under marketplace, category labels are quite complex and need extra upate + const LLUUID marketplace_id = findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); + if (marketplace_id.notNull() && isObjectDescendentOf(cat->getUUID(), marketplace_id)) + { + mask |= LLInventoryObserver::LABEL; + } old_cat->copyViewerCategory(cat); addChangedMask(mask, cat->getUUID()); } @@ -1038,12 +1200,11 @@ void LLInventoryModel::updateCategory(const LLViewerInventoryCategory* cat) new_cat->copyViewerCategory(cat); addCategory(new_cat); - // make sure this category is correctly referenced by it's parent. - cat_array_t* cat_array; - cat_array = getUnlockedCatArray(cat->getParentUUID()); + // make sure this category is correctly referenced by its parent. + cat_array_t* cat_array = getUnlockedCatArray(cat->getParentUUID()); if(cat_array) { - cat_array->put(new_cat); + cat_array->push_back(new_cat); } // make space in the tree for this category's children. @@ -1053,46 +1214,45 @@ void LLInventoryModel::updateCategory(const LLViewerInventoryCategory* cat) item_array_t* itemsp = new item_array_t; mParentChildCategoryTree[new_cat->getUUID()] = catsp; mParentChildItemTree[new_cat->getUUID()] = itemsp; - addChangedMask(LLInventoryObserver::ADD, cat->getUUID()); + mask |= LLInventoryObserver::ADD; + addChangedMask(mask, cat->getUUID()); } } void LLInventoryModel::moveObject(const LLUUID& object_id, const LLUUID& cat_id) { - lldebugs << "LLInventoryModel::moveObject()" << llendl; + LL_DEBUGS(LOG_INV) << "LLInventoryModel::moveObject()" << LL_ENDL; if(!isInventoryUsable()) { - llwarns << "Inventory is broken." << llendl; + LL_WARNS(LOG_INV) << "Inventory is broken." << LL_ENDL; return; } if((object_id == cat_id) || !is_in_map(mCategoryMap, cat_id)) { - llwarns << "Could not move inventory object " << object_id << " to " - << cat_id << llendl; + LL_WARNS(LOG_INV) << "Could not move inventory object " << object_id << " to " + << cat_id << LL_ENDL; return; } - LLViewerInventoryCategory* cat = getCategory(object_id); + LLPointer cat = getCategory(object_id); if(cat && (cat->getParentUUID() != cat_id)) { - cat_array_t* cat_array; - cat_array = getUnlockedCatArray(cat->getParentUUID()); - if(cat_array) cat_array->removeObj(cat); + cat_array_t* cat_array = getUnlockedCatArray(cat->getParentUUID()); + if(cat_array) vector_replace_with_last(*cat_array, cat); cat_array = getUnlockedCatArray(cat_id); cat->setParent(cat_id); - if(cat_array) cat_array->put(cat); + if(cat_array) cat_array->push_back(cat); addChangedMask(LLInventoryObserver::STRUCTURE, object_id); return; } - LLViewerInventoryItem* item = getItem(object_id); + LLPointer item = getItem(object_id); if(item && (item->getParentUUID() != cat_id)) { - item_array_t* item_array; - item_array = getUnlockedItemArray(item->getParentUUID()); - if(item_array) item_array->removeObj(item); + item_array_t* item_array = getUnlockedItemArray(item->getParentUUID()); + if(item_array) vector_replace_with_last(*item_array, item); item_array = getUnlockedItemArray(cat_id); item->setParent(cat_id); - if(item_array) item_array->put(item); + if(item_array) item_array->push_back(item); addChangedMask(LLInventoryObserver::STRUCTURE, object_id); return; } @@ -1105,14 +1265,14 @@ void LLInventoryModel::changeItemParent(LLViewerInventoryItem* item, { if (item->getParentUUID() == new_parent_id) { - LL_DEBUGS("Inventory") << "'" << item->getName() << "' (" << item->getUUID() - << ") is already in folder " << new_parent_id << LL_ENDL; + LL_DEBUGS(LOG_INV) << "'" << item->getName() << "' (" << item->getUUID() + << ") is already in folder " << new_parent_id << LL_ENDL; } else { - LL_INFOS("Inventory") << "Moving '" << item->getName() << "' (" << item->getUUID() - << ") from " << item->getParentUUID() << " to folder " - << new_parent_id << LL_ENDL; + LL_INFOS(LOG_INV) << "Moving '" << item->getName() << "' (" << item->getUUID() + << ") from " << item->getParentUUID() << " to folder " + << new_parent_id << LL_ENDL; LLInventoryModel::update_list_t update; LLInventoryModel::LLCategoryUpdate old_folder(item->getParentUUID(),-1); update.push_back(old_folder); @@ -1123,7 +1283,7 @@ void LLInventoryModel::changeItemParent(LLViewerInventoryItem* item, LLPointer new_item = new LLViewerInventoryItem(item); new_item->setParent(new_parent_id); // - if(gInventory.isObjectDescendentOf(item->getUUID(), gInventory.getRootFolderID())) + if(isObjectDescendentOf(item->getUUID(), gInventory.getRootFolderID())) // new_item->updateParentOnServer(restamp); updateItem(new_item); @@ -1161,19 +1321,211 @@ void LLInventoryModel::changeCategoryParent(LLViewerInventoryCategory* cat, notifyObservers(); } +void LLInventoryModel::onAISUpdateReceived(const std::string& context, const LLSD& update) +{ + LLTimer timer; + static LLCachedControl debug_ava_appr_msg(gSavedSettings, "DebugAvatarAppearanceMessage"); + if (debug_ava_appr_msg) + { + dump_sequential_xml(gAgentAvatarp->getFullname() + "_ais_update", update); + } + + AISUpdate ais_update(update); // parse update llsd into stuff to do. + ais_update.doUpdate(); // execute the updates in the appropriate order. + LL_INFOS(LOG_INV) << "elapsed: " << timer.getElapsedTimeF32() << LL_ENDL; +} + +// Does not appear to be used currently. +void LLInventoryModel::onItemUpdated(const LLUUID& item_id, const LLSD& updates, bool update_parent_version) +{ + U32 mask = LLInventoryObserver::NONE; + + LLPointer item = gInventory.getItem(item_id); + LL_DEBUGS(LOG_INV) << "item_id: [" << item_id << "] name " << (item ? item->getName() : "(NOT FOUND)") << LL_ENDL; + if(item) + { + for (LLSD::map_const_iterator it = updates.beginMap(); + it != updates.endMap(); ++it) + { + if (it->first == "name") + { + LL_INFOS(LOG_INV) << "Updating name from " << item->getName() << " to " << it->second.asString() << LL_ENDL; + item->rename(it->second.asString()); + mask |= LLInventoryObserver::LABEL; + } + else if (it->first == "desc") + { + LL_INFOS(LOG_INV) << "Updating description from " << item->getActualDescription() + << " to " << it->second.asString() << LL_ENDL; + item->setDescription(it->second.asString()); + } + else + { + LL_ERRS(LOG_INV) << "unhandled updates for field: " << it->first << LL_ENDL; + } + } + mask |= LLInventoryObserver::INTERNAL; + addChangedMask(mask, item->getUUID()); + if (update_parent_version) + { + // Descendent count is unchanged, but folder version incremented. + LLInventoryModel::LLCategoryUpdate up(item->getParentUUID(), 0); + accountForUpdate(up); + } + notifyObservers(); // do we want to be able to make this optional? + } +} + +// Not used? +void LLInventoryModel::onCategoryUpdated(const LLUUID& cat_id, const LLSD& updates) +{ + U32 mask = LLInventoryObserver::NONE; + + LLPointer cat = gInventory.getCategory(cat_id); + LL_DEBUGS(LOG_INV) << "cat_id: [" << cat_id << "] name " << (cat ? cat->getName() : "(NOT FOUND)") << LL_ENDL; + if(cat) + { + for (LLSD::map_const_iterator it = updates.beginMap(); + it != updates.endMap(); ++it) + { + if (it->first == "name") + { + LL_INFOS(LOG_INV) << "Updating name from " << cat->getName() << " to " << it->second.asString() << LL_ENDL; + cat->rename(it->second.asString()); + mask |= LLInventoryObserver::LABEL; + } + else + { + LL_ERRS(LOG_INV) << "unhandled updates for field: " << it->first << LL_ENDL; + } + } + mask |= LLInventoryObserver::INTERNAL; + addChangedMask(mask, cat->getUUID()); + notifyObservers(); // do we want to be able to make this optional? + } +} + +// Update model after descendents have been purged. +void LLInventoryModel::onDescendentsPurgedFromServer(const LLUUID& object_id, bool fix_broken_links) +{ + LLPointer cat = getCategory(object_id); + if (cat.notNull()) + { + // do the cache accounting + S32 descendents = cat->getDescendentCount(); + if(descendents > 0) + { + LLInventoryModel::LLCategoryUpdate up(object_id, -descendents); + accountForUpdate(up); + } + + // we know that descendent count is 0, however since the + // accounting may actually not do an update, we should force + // it here. + cat->setDescendentCount(0); + + // unceremoniously remove anything we have locally stored. + LLInventoryModel::cat_array_t categories; + LLInventoryModel::item_array_t items; + collectDescendents(object_id, + categories, + items, + LLInventoryModel::INCLUDE_TRASH); + S32 count = items.size(); + + LLUUID uu_id; + for(S32 i = 0; i < count; ++i) + { + uu_id = items.at(i)->getUUID(); + + // This check prevents the deletion of a previously deleted item. + // This is necessary because deletion is not done in a hierarchical + // order. The current item may have been already deleted as a child + // of its deleted parent. + if (getItem(uu_id)) + { + deleteObject(uu_id, fix_broken_links); + } + } + + count = categories.size(); + // Slightly kludgy way to make sure categories are removed + // only after their child categories have gone away. + + // FIXME: Would probably make more sense to have this whole + // descendent-clearing thing be a post-order recursive + // function to get the leaf-up behavior automatically. + S32 deleted_count; + S32 total_deleted_count = 0; + do + { + deleted_count = 0; + for(S32 i = 0; i < count; ++i) + { + uu_id = categories.at(i)->getUUID(); + if (getCategory(uu_id)) + { + cat_array_t* cat_list = getUnlockedCatArray(uu_id); + if (!cat_list || (cat_list->empty())) + { + deleteObject(uu_id, fix_broken_links); + deleted_count++; + } + } + } + total_deleted_count += deleted_count; + } + while (deleted_count > 0); + if (total_deleted_count != count) + { + LL_WARNS(LOG_INV) << "Unexpected count of categories deleted, got " + << total_deleted_count << " expected " << count << LL_ENDL; + } + //gInventory.validate(); + } +} + +// Update model after an item is confirmed as removed from +// server. Works for categories or items. +void LLInventoryModel::onObjectDeletedFromServer(const LLUUID& object_id, bool fix_broken_links, bool update_parent_version, bool do_notify_observers) +{ + LLPointer obj = getObject(object_id); + if(obj) + { + if (getCategory(object_id)) + { + // For category, need to delete/update all children first. + onDescendentsPurgedFromServer(object_id, fix_broken_links); + } + + + // From item/cat removeFromServer() + if (update_parent_version) + { + LLInventoryModel::LLCategoryUpdate up(obj->getParentUUID(), -1); + accountForUpdate(up); + } + + // From purgeObject() + LLPreview::hide(object_id); + deleteObject(object_id, fix_broken_links, do_notify_observers); + } +} + + // Delete a particular inventory object by ID. -void LLInventoryModel::deleteObject(const LLUUID& id) +void LLInventoryModel::deleteObject(const LLUUID& id, bool fix_broken_links, bool do_notify_observers) { - lldebugs << "LLInventoryModel::deleteObject()" << llendl; + LL_DEBUGS(LOG_INV) << "LLInventoryModel::deleteObject()" << LL_ENDL; LLPointer obj = getObject(id); if (!obj) { - llwarns << "Deleting non-existent object [ id: " << id << " ] " << llendl; + LL_WARNS(LOG_INV) << "Deleting non-existent object [ id: " << id << " ] " << LL_ENDL; return; } - lldebugs << "Deleting inventory object " << id << llendl; - mLastItem = NULL; + LL_DEBUGS(LOG_INV) << "Deleting inventory object " << id << LL_ENDL; + mLastItem = nullptr; LLUUID parent_id = obj->getParentUUID(); mCategoryMap.erase(id); mItemMap.erase(id); @@ -1181,157 +1533,81 @@ void LLInventoryModel::deleteObject(const LLUUID& id) item_array_t* item_list = getUnlockedItemArray(parent_id); if(item_list) { - LLViewerInventoryItem* item = (LLViewerInventoryItem*)((LLInventoryObject*)obj); - item_list->removeObj(item); + LLPointer item = (LLViewerInventoryItem*)((LLInventoryObject*)obj); + vector_replace_with_last(*item_list, item); } cat_array_t* cat_list = getUnlockedCatArray(parent_id); if(cat_list) { - LLViewerInventoryCategory* cat = (LLViewerInventoryCategory*)((LLInventoryObject*)obj); - cat_list->removeObj(cat); + LLPointer cat = (LLViewerInventoryCategory*)((LLInventoryObject*)obj); + vector_replace_with_last(*cat_list, cat); } + + // Note : We need to tell the inventory observers that those things are going to be deleted *before* the tree is cleared or they won't know what to delete (in views and view models) + addChangedMask(LLInventoryObserver::REMOVE, id); + gInventory.notifyObservers(); + item_list = getUnlockedItemArray(id); if(item_list) { + if (!item_list->empty()) + { + LL_WARNS(LOG_INV) << "Deleting cat " << id << " while it still has child items" << LL_ENDL; + } delete item_list; mParentChildItemTree.erase(id); } cat_list = getUnlockedCatArray(id); if(cat_list) { + if (!cat_list->empty()) + { + LL_WARNS(LOG_INV) << "Deleting cat " << id << " while it still has child cats" << LL_ENDL; + } delete cat_list; mParentChildCategoryTree.erase(id); } addChangedMask(LLInventoryObserver::REMOVE, id); - obj = NULL; // delete obj - updateLinkedObjectsFromPurge(id); - gInventory.notifyObservers(); -} -// Delete a particular inventory item by ID, and remove it from the server. -void LLInventoryModel::purgeObject(const LLUUID &id) -{ - lldebugs << "LLInventoryModel::purgeObject() [ id: " << id << " ] " << llendl; - LLPointer obj = getObject(id); - if(obj) + bool is_link_type = obj->getIsLinkType(); + if (is_link_type) + { + removeBacklinkInfo(obj->getUUID(), obj->getLinkedUUID()); + } + + // Can't have links to links, so there's no need for this update + // if the item removed is a link. Can also skip if source of the + // update is getting broken link info separately. + if (fix_broken_links && !is_link_type) { - obj->removeFromServer(); - LLPreview::hide(id); - deleteObject(id); + updateLinkedObjectsFromPurge(id); + } + obj = nullptr; // delete obj + if (do_notify_observers) + { + notifyObservers(); } } void LLInventoryModel::updateLinkedObjectsFromPurge(const LLUUID &baseobj_id) { - LLInventoryModel::item_array_t item_array = collectLinkedItems(baseobj_id); + LLInventoryModel::item_array_t item_array = collectLinksTo(baseobj_id); // REBUILD is expensive, so clear the current change list first else // everything else on the changelist will also get rebuilt. - gInventory.notifyObservers(); - for (LLInventoryModel::item_array_t::const_iterator iter = item_array.begin(); - iter != item_array.end(); - iter++) + if (!item_array.empty()) { - const LLViewerInventoryItem *linked_item = (*iter); - const LLUUID &item_id = linked_item->getUUID(); - if (item_id == baseobj_id) continue; - addChangedMask(LLInventoryObserver::REBUILD, item_id); - } - gInventory.notifyObservers(); -} - -// This is a method which collects the descendents of the id -// provided. If the category is not found, no action is -// taken. This method goes through the long winded process of -// cancelling any calling cards, removing server representation of -// folders, items, etc in a fairly efficient manner. -void LLInventoryModel::purgeDescendentsOf(const LLUUID& id) -{ - EHasChildren children = categoryHasChildren(id); - if(children == CHILDREN_NO) - { - llinfos << "Not purging descendents of " << id << llendl; - return; - } - LLPointer cat = getCategory(id); - if (cat.notNull()) - { - if (LLInventoryClipboard::instance().hasContents() && LLInventoryClipboard::instance().isCutMode()) + notifyObservers(); + for (LLInventoryModel::item_array_t::const_iterator iter = item_array.begin(); + iter != item_array.end(); + ++iter) { - // Something on the clipboard is in "cut mode" and needs to be preserved - llinfos << "LLInventoryModel::purgeDescendentsOf " << cat->getName() - << " iterate and purge non hidden items" << llendl; - cat_array_t* categories; - item_array_t* items; - // Get the list of direct descendants in tha categoy passed as argument - getDirectDescendentsOf(id, categories, items); - std::vector list_uuids; - // Make a unique list with all the UUIDs of the direct descendants (items and categories are not treated differently) - // Note: we need to do that shallow copy as purging things will invalidate the categories or items lists - for (cat_array_t::const_iterator it = categories->begin(); it != categories->end(); ++it) - { - list_uuids.push_back((*it)->getUUID()); - } - for (item_array_t::const_iterator it = items->begin(); it != items->end(); ++it) - { - list_uuids.push_back((*it)->getUUID()); - } - // Iterate through the list and only purge the UUIDs that are not on the clipboard - for (std::vector::const_iterator it = list_uuids.begin(); it != list_uuids.end(); ++it) - { - if (!LLInventoryClipboard::instance().isOnClipboard(*it)) - { - purgeObject(*it); - } - } - } - else - { - // Fast purge - // do the cache accounting - llinfos << "LLInventoryModel::purgeDescendentsOf " << cat->getName() - << llendl; - S32 descendents = cat->getDescendentCount(); - if(descendents > 0) - { - LLCategoryUpdate up(id, -descendents); - accountForUpdate(up); - } - - // we know that descendent count is 0, however since the - // accounting may actually not do an update, we should force - // it here. - cat->setDescendentCount(0); - - // send it upstream - LLMessageSystem* msg = gMessageSystem; - msg->newMessage("PurgeInventoryDescendents"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID()); - msg->addUUID("SessionID", gAgent.getSessionID()); - msg->nextBlock("InventoryData"); - msg->addUUID("FolderID", id); - gAgent.sendReliableMessage(); - - // unceremoniously remove anything we have locally stored. - cat_array_t categories; - item_array_t items; - collectDescendents(id, - categories, - items, - INCLUDE_TRASH); - S32 count = items.count(); - for(S32 i = 0; i < count; ++i) - { - deleteObject(items.get(i)->getUUID()); - } - - count = categories.count(); - for(S32 i = 0; i < count; ++i) - { - deleteObject(categories.get(i)->getUUID()); - } + const LLViewerInventoryItem *linked_item = (*iter); + const LLUUID &item_id = linked_item->getUUID(); + if (item_id == baseobj_id) continue; + addChangedMask(LLInventoryObserver::REBUILD, item_id); } + notifyObservers(); } } @@ -1354,7 +1630,7 @@ BOOL LLInventoryModel::containsObserver(LLInventoryObserver* observer) const void LLInventoryModel::idleNotifyObservers() { - if (mModifyMask == LLInventoryObserver::NONE && (mChangedItemIDs.size() == 0)) + if (mModifyMask == LLInventoryObserver::NONE && (mChangedItemIDs.empty())) { return; } @@ -1369,7 +1645,7 @@ void LLInventoryModel::notifyObservers() // Within notifyObservers, something called notifyObservers // again. This type of recursion is unsafe because it causes items to be // processed twice, and this can easily lead to infinite loops. - llwarns << "Call was made to notifyObservers within notifyObservers!" << llendl; + LL_WARNS(LOG_INV) << "Call was made to notifyObservers within notifyObservers!" << LL_ENDL; return; } @@ -1386,6 +1662,7 @@ void LLInventoryModel::notifyObservers() mModifyMask = LLInventoryObserver::NONE; mChangedItemIDs.clear(); + mAddedItemIDs.clear(); mIsNotifyObservers = FALSE; } @@ -1398,103 +1675,54 @@ void LLInventoryModel::addChangedMask(U32 mask, const LLUUID& referent) // Something marked an item for change within a call to notifyObservers // (which is in the process of processing the list of items marked for change). // This means the change may fail to be processed. - llwarns << "Adding changed mask within notify observers! Change will likely be lost." << llendl; + LL_WARNS(LOG_INV) << "Adding changed mask within notify observers! Change will likely be lost." << LL_ENDL; + LLViewerInventoryItem *item = getItem(referent); + if (item) + { + LL_WARNS(LOG_INV) << "Item " << item->getName() << LL_ENDL; + } + else + { + LLViewerInventoryCategory *cat = getCategory(referent); + if (cat) + { + LL_WARNS(LOG_INV) << "Category " << cat->getName() << LL_ENDL; + } + } } mModifyMask |= mask; - if (referent.notNull()) + if (referent.notNull() && (mChangedItemIDs.find(referent) == mChangedItemIDs.end())) { mChangedItemIDs.insert(referent); - } - - // Update all linked items. Starting with just LABEL because I'm - // not sure what else might need to be accounted for this. - if (mModifyMask & LLInventoryObserver::LABEL) - { - addChangedMaskForLinks(referent, LLInventoryObserver::LABEL); - } -} - -// If we get back a normal response, handle it here -void LLInventoryModel::fetchInventoryResponder::result(const LLSD& content) -{ - start_new_inventory_observer(); + update_marketplace_category(referent, false); - /*LLUUID agent_id; - agent_id = content["agent_id"].asUUID(); - if(agent_id != gAgent.getID()) - { - llwarns << "Got a inventory update for the wrong agent: " << agent_id - << llendl; - return; - }*/ - item_array_t items; - update_map_t update; - S32 count = content["items"].size(); - LLUUID folder_id; - // Does this loop ever execute more than once? - for(S32 i = 0; i < count; ++i) - { - LLPointer titem = new LLViewerInventoryItem; - titem->unpackMessage(content["items"][i]); - - lldebugs << "LLInventoryModel::messageUpdateCore() item id:" - << titem->getUUID() << llendl; - items.push_back(titem); - // examine update for changes. - LLViewerInventoryItem* itemp = gInventory.getItem(titem->getUUID()); - if(itemp) + if (mask & LLInventoryObserver::ADD) { - if(titem->getParentUUID() == itemp->getParentUUID()) - { - update[titem->getParentUUID()]; - } - else - { - ++update[titem->getParentUUID()]; - --update[itemp->getParentUUID()]; - } - } - else - { - ++update[titem->getParentUUID()]; + mAddedItemIDs.insert(referent); } - if (folder_id.isNull()) + + // Update all linked items. Starting with just LABEL because I'm + // not sure what else might need to be accounted for this. + if (mask & LLInventoryObserver::LABEL) { - folder_id = titem->getParentUUID(); + addChangedMaskForLinks(referent, LLInventoryObserver::LABEL); } } - - U32 changes = 0x0; - //as above, this loop never seems to loop more than once per call - for (item_array_t::iterator it = items.begin(); it != items.end(); ++it) - { - changes |= gInventory.updateItem(*it); - } - gInventory.notifyObservers(); - gViewerWindow->getWindow()->decBusyCount(); -} - -//If we get back an error (not found, etc...), handle it here -void LLInventoryModel::fetchInventoryResponder::error(U32 status, const std::string& reason) -{ - llinfos << "fetchInventory::error " - << status << ": " << reason << llendl; - gInventory.notifyObservers(); } bool LLInventoryModel::fetchDescendentsOf(const LLUUID& folder_id) const { if(folder_id.isNull()) { - llwarns << "Calling fetch descendents on NULL folder id!" << llendl; + LL_WARNS(LOG_INV) << "Calling fetch descendents on NULL folder id!" << LL_ENDL; return false; } LLViewerInventoryCategory* cat = getCategory(folder_id); if(!cat) { - llwarns << "Asked to fetch descendents of non-existent folder: " - << folder_id << llendl; + LL_WARNS(LOG_INV) << "Asked to fetch descendents of non-existent folder: " + << folder_id << LL_ENDL; return false; } //S32 known_descendents = 0; @@ -1502,11 +1730,11 @@ bool LLInventoryModel::fetchDescendentsOf(const LLUUID& folder_id) const //item_array_t* items = get_ptr_in_map(mParentChildItemTree, folder_id); //if(categories) //{ - // known_descendents += categories->count(); + // known_descendents += categories->size(); //} //if(items) //{ - // known_descendents += items->count(); + // known_descendents += items->size(); //} return cat->fetch(); } @@ -1515,16 +1743,16 @@ void LLInventoryModel::cache( const LLUUID& parent_folder_id, const LLUUID& agent_id) { - lldebugs << "Caching " << parent_folder_id << " for " << agent_id - << llendl; + LL_DEBUGS(LOG_INV) << "Caching " << parent_folder_id << " for " << agent_id + << LL_ENDL; LLViewerInventoryCategory* root_cat = getCategory(parent_folder_id); if(!root_cat) return; cat_array_t categories; - categories.put(root_cat); + categories.push_back(root_cat); item_array_t items; LLCanCache can_cache(this); - can_cache(root_cat, NULL); + can_cache(root_cat, nullptr); collectDescendentsIf( parent_folder_id, categories, @@ -1541,23 +1769,23 @@ void LLInventoryModel::cache( gzip_filename.append(".gz"); if(gzip_file(inventory_filename, gzip_filename)) { - lldebugs << "Successfully compressed " << inventory_filename << llendl; + LL_DEBUGS(LOG_INV) << "Successfully compressed " << inventory_filename << LL_ENDL; LLFile::remove(inventory_filename); } else { - llwarns << "Unable to compress " << inventory_filename << llendl; + LL_WARNS(LOG_INV) << "Unable to compress " << inventory_filename << LL_ENDL; } } void LLInventoryModel::addCategory(LLViewerInventoryCategory* category) { - //llinfos << "LLInventoryModel::addCategory()" << llendl; + //LL_INFOS(LOG_INV) << "LLInventoryModel::addCategory()" << LL_ENDL; if(category) { // We aren't displaying the Meshes folder - if (category->getPreferredType() == LLFolderType::FT_MESH) + if (category->mPreferredType == LLFolderType::FT_MESH) { return; } @@ -1571,28 +1799,90 @@ void LLInventoryModel::addCategory(LLViewerInventoryCategory* category) } } +bool LLInventoryModel::hasBacklinkInfo(const LLUUID& link_id, const LLUUID& target_id) const +{ + std::pair range = mBacklinkMMap.equal_range(target_id); + for (backlink_mmap_t::const_iterator it = range.first; it != range.second; ++it) + { + if (it->second == link_id) + { + return true; + } + } + return false; +} + +void LLInventoryModel::addBacklinkInfo(const LLUUID& link_id, const LLUUID& target_id) +{ + if (!hasBacklinkInfo(link_id, target_id)) + { + mBacklinkMMap.insert(std::make_pair(target_id, link_id)); + } +} + +void LLInventoryModel::removeBacklinkInfo(const LLUUID& link_id, const LLUUID& target_id) +{ + std::pair range = mBacklinkMMap.equal_range(target_id); + for (backlink_mmap_t::iterator it = range.first; it != range.second; ) + { + if (it->second == link_id) + { + backlink_mmap_t::iterator delete_it = it; // iterator will be invalidated by erase. + ++it; + mBacklinkMMap.erase(delete_it); + } + else + { + ++it; + } + } +} + void LLInventoryModel::addItem(LLViewerInventoryItem* item) { llassert(item); if(item) { - // This can happen if assettype enums from llassettype.h ever change. - // For example, there is a known backwards compatibility issue in some viewer prototypes prior to when - // the AT_LINK enum changed from 23 to 24. - if ((item->getType() == LLAssetType::AT_NONE) - || LLAssetType::lookup(item->getType()) == LLAssetType::badLookup()) + if (item->getType() <= LLAssetType::AT_NONE) { - llwarns << "Got bad asset type for item [ name: " << item->getName() << " type: " << item->getType() << " inv-type: " << item->getInventoryType() << " ], ignoring." << llendl; + LL_WARNS(LOG_INV) << "Got bad asset type for item [ name: " << item->getName() + << " type: " << item->getType() + << " inv-type: " << item->getInventoryType() << " ], ignoring." << LL_ENDL; return; } + if (LLAssetType::lookup(item->getType()) == LLAssetType::badLookup()) + { + if (item->getType() >= LLAssetType::AT_COUNT) + { + // Not yet supported. + LL_DEBUGS(LOG_INV) << "Got unknown asset type for item [ name: " << item->getName() + << " type: " << item->getType() + << " inv-type: " << item->getInventoryType() << " ]." << LL_ENDL; + } + else + { + LL_WARNS(LOG_INV) << "Got unknown asset type for item [ name: " << item->getName() + << " type: " << item->getType() + << " inv-type: " << item->getInventoryType() << " ]." << LL_ENDL; + } + } + // This condition means that we tried to add a link without the baseobj being in memory. // The item will show up as a broken link. if (item->getIsBrokenLink()) { - llinfos << "Adding broken link [ name: " << item->getName() << " itemID: " << item->getUUID() << " assetID: " << item->getAssetUUID() << " ) parent: " << item->getParentUUID() << llendl; + LL_INFOS(LOG_INV) << "Adding broken link [ name: " << item->getName() + << " itemID: " << item->getUUID() + << " assetID: " << item->getAssetUUID() << " ) parent: " << item->getParentUUID() << LL_ENDL; + } + if (item->getIsLinkType()) + { + // Add back-link from linked-to UUID. + const LLUUID& link_id = item->getUUID(); + const LLUUID& target_id = item->getLinkedUUID(); + addBacklinkInfo(link_id, target_id); } - mItemMap[item->getUUID()] = item; } } @@ -1600,7 +1890,7 @@ void LLInventoryModel::addItem(LLViewerInventoryItem* item) // Empty the entire contents void LLInventoryModel::empty() { -// llinfos << "LLInventoryModel::empty()" << llendl; + // LL_INFOS(LOG_INV) << "LLInventoryModel::empty()" << LL_ENDL; std::for_each( mParentChildCategoryTree.begin(), mParentChildCategoryTree.end(), @@ -1611,6 +1901,7 @@ void LLInventoryModel::empty() mParentChildItemTree.end(), DeletePairedPointer()); mParentChildItemTree.clear(); + mBacklinkMMap.clear(); // forget all backlink information. mCategoryMap.clear(); // remove all references (should delete entries) mItemMap.clear(); // remove all references (should delete entries) mLastItem = NULL; @@ -1622,47 +1913,43 @@ void LLInventoryModel::accountForUpdate(const LLCategoryUpdate& update) const LLViewerInventoryCategory* cat = getCategory(update.mCategoryID); if(cat) { - bool accounted = false; S32 version = cat->getVersion(); if(version != LLViewerInventoryCategory::VERSION_UNKNOWN) { S32 descendents_server = cat->getDescendentCount(); - LLInventoryModel::cat_array_t* cats; - LLInventoryModel::item_array_t* items; - getDirectDescendentsOf(update.mCategoryID, cats, items); - S32 descendents_actual = 0; - if(cats && items) - { - descendents_actual = cats->count() + items->count(); - } + S32 descendents_actual = cat->getViewerDescendentCount(); if(descendents_server == descendents_actual) { - accounted = true; descendents_actual += update.mDescendentDelta; cat->setDescendentCount(descendents_actual); cat->setVersion(++version); - lldebugs << "accounted: '" << cat->getName() << "' " - << version << " with " << descendents_actual - << " descendents." << llendl; + LL_DEBUGS(LOG_INV) << "accounted: '" << cat->getName() << "' " + << version << " with " << descendents_actual + << " descendents." << LL_ENDL; + } + else + { + // Error condition, this means that the category did not register that + // it got new descendents (perhaps because it is still being loaded) + // which means its descendent count will be wrong. + LL_WARNS(LOG_INV) << "Accounting failed for '" << cat->getName() << "' version:" + << version << " due to mismatched descendent count: server == " + << descendents_server << ", viewer == " << descendents_actual << LL_ENDL; } } - if(!accounted) + else { - // Error condition, this means that the category did not register that - // it got new descendents (perhaps because it is still being loaded) - // which means its descendent count will be wrong. - llwarns << "Accounting failed for '" << cat->getName() << "' version:" - << version << llendl; + LL_WARNS(LOG_INV) << "Accounting failed for '" << cat->getName() << "' version: unknown (" + << version << ")" << LL_ENDL; } } else { - llwarns << "No category found for update " << update.mCategoryID << llendl; + LL_WARNS(LOG_INV) << "No category found for update " << update.mCategoryID << LL_ENDL; } } -void LLInventoryModel::accountForUpdate( - const LLInventoryModel::update_list_t& update) +void LLInventoryModel::accountForUpdate(const LLInventoryModel::update_list_t& update) { update_list_t::const_iterator it = update.begin(); update_list_t::const_iterator end = update.end(); @@ -1672,8 +1959,7 @@ void LLInventoryModel::accountForUpdate( } } -void LLInventoryModel::accountForUpdate( - const LLInventoryModel::update_map_t& update) +void LLInventoryModel::accountForUpdate(const LLInventoryModel::update_map_t& update) { LLCategoryUpdate up; update_map_t::const_iterator it = update.begin(); @@ -1686,49 +1972,7 @@ void LLInventoryModel::accountForUpdate( } } - -/* -void LLInventoryModel::incrementCategoryVersion(const LLUUID& category_id) -{ - LLViewerInventoryCategory* cat = getCategory(category_id); - if(cat) - { - S32 version = cat->getVersion(); - if(LLViewerInventoryCategory::VERSION_UNKNOWN != version) - { - cat->setVersion(version + 1); - llinfos << "IncrementVersion: " << cat->getName() << " " - << cat->getVersion() << llendl; - } - else - { - llinfos << "Attempt to increment version when unknown: " - << category_id << llendl; - } - } - else - { - llinfos << "Attempt to increment category: " << category_id << llendl; - } -} -void LLInventoryModel::incrementCategorySetVersion( - const std::set& categories) -{ - if(!categories.empty()) - { - std::set::const_iterator it = categories.begin(); - std::set::const_iterator end = categories.end(); - for(; it != end; ++it) - { - incrementCategoryVersion(*it); - } - } -} -*/ - - -LLInventoryModel::EHasChildren LLInventoryModel::categoryHasChildren( - const LLUUID& cat_id) const +LLInventoryModel::EHasChildren LLInventoryModel::categoryHasChildren(const LLUUID& cat_id) const { LLViewerInventoryCategory* cat = getCategory(cat_id); if(!cat) return CHILDREN_NO; @@ -1747,13 +1991,13 @@ LLInventoryModel::EHasChildren LLInventoryModel::categoryHasChildren( } // Shouldn't have to run this, but who knows. - parent_cat_map_t::const_iterator cat_it = mParentChildCategoryTree.find(cat->getUUID()); - if (cat_it != mParentChildCategoryTree.end() && cat_it->second->count() > 0) + const auto cat_it = mParentChildCategoryTree.find(cat->getUUID()); + if (cat_it != mParentChildCategoryTree.cend() && !cat_it->second->empty()) { return CHILDREN_YES; } - parent_item_map_t::const_iterator item_it = mParentChildItemTree.find(cat->getUUID()); - if (item_it != mParentChildItemTree.end() && item_it->second->count() > 0) + const auto item_it = mParentChildItemTree.find(cat->getUUID()); + if (item_it != mParentChildItemTree.cend() && !item_it->second->empty()) { return CHILDREN_YES; } @@ -1767,20 +2011,12 @@ bool LLInventoryModel::isCategoryComplete(const LLUUID& cat_id) const if(cat && (cat->getVersion()!=LLViewerInventoryCategory::VERSION_UNKNOWN)) { S32 descendents_server = cat->getDescendentCount(); - LLInventoryModel::cat_array_t* cats; - LLInventoryModel::item_array_t* items; - getDirectDescendentsOf(cat_id, cats, items); - S32 descendents_actual = 0; - if(cats && items) - { - descendents_actual = cats->count() + items->count(); - } + S32 descendents_actual = cat->getViewerDescendentCount(); if(descendents_server == descendents_actual) { return true; } } - return false; } @@ -1788,7 +2024,7 @@ bool LLInventoryModel::loadSkeleton( const LLSD& options, const LLUUID& owner_id) { - lldebugs << "importing inventory skeleton for " << owner_id << llendl; + LL_DEBUGS(LOG_INV) << "importing inventory skeleton for " << owner_id << LL_ENDL; typedef std::set, InventoryIDPtrLess> cat_set_t; cat_set_t temp_cats; @@ -1825,7 +2061,7 @@ bool LLInventoryModel::loadSkeleton( } else { - llwarns << "Unable to import near " << name.asString() << llendl; + LL_WARNS(LOG_INV) << "Unable to import near " << name.asString() << LL_ENDL; rv = false; } } @@ -1837,6 +2073,7 @@ bool LLInventoryModel::loadSkeleton( update_map_t child_counts; cat_array_t categories; item_array_t items; + changed_items_t categories_to_update; item_array_t possible_broken_links; cat_set_t invalid_categories; // Used to mark categories that weren't successfully loaded. std::string owner_id_str; @@ -1849,11 +2086,11 @@ bool LLInventoryModel::loadSkeleton( gzip_filename.append(".gz"); LLFILE* fp = LLFile::fopen(gzip_filename, "rb"); bool remove_inventory_file = false; - if (fp) + if(fp) { fclose(fp); - fp = NULL; - if (gunzip_file(gzip_filename, inventory_filename)) + fp = nullptr; + if(gunzip_file(gzip_filename, inventory_filename)) { // we only want to remove the inventory file if it was // gzipped before we loaded, and we successfully @@ -1862,20 +2099,20 @@ bool LLInventoryModel::loadSkeleton( } else { - llinfos << "Unable to gunzip " << gzip_filename << llendl; + LL_INFOS(LOG_INV) << "Unable to gunzip " << gzip_filename << LL_ENDL; } } bool is_cache_obsolete = false; - if (loadFromFile(inventory_filename, categories, items, is_cache_obsolete)) + if (loadFromFile(inventory_filename, categories, items, categories_to_update, is_cache_obsolete)) { // We were able to find a cache of files. So, use what we // found to generate a set of categories we should add. We // will go through each category loaded and if the version // does not match, invalidate the version. - S32 count = categories.count(); + S32 count = categories.size(); cat_set_t::iterator not_cached = temp_cats.end(); - std::set cached_ids; - for (S32 i = 0; i < count; ++i) + uuid_set_t cached_ids; + for(S32 i = 0; i < count; ++i) { LLViewerInventoryCategory* cat = categories[i]; cat_set_t::iterator cit = temp_cats.find(cat); @@ -1885,13 +2122,19 @@ bool LLInventoryModel::loadSkeleton( } LLViewerInventoryCategory* tcat = *cit; + if (categories_to_update.find(tcat->getUUID()) != categories_to_update.end()) + { + tcat->setVersion(NO_VERSION); + LL_WARNS() << "folder to update: " << tcat->getName() << LL_ENDL; + } + // we can safely ignore anything loaded from file, but // not sent down in the skeleton. Must have been removed from inventory. if (cit == not_cached) { continue; } - if (cat->getVersion() != tcat->getVersion()) + else if (cat->getVersion() != tcat->getVersion()) { // if the cached version does not match the server version, // throw away the version we have so we can fetch the @@ -1905,20 +2148,20 @@ bool LLInventoryModel::loadSkeleton( } // go ahead and add the cats returned during the download - std::set::const_iterator not_cached_id = cached_ids.end(); + auto not_cached_id = cached_ids.end(); cached_category_count = cached_ids.size(); - for(cat_set_t::iterator it = temp_cats.begin(); it != temp_cats.end(); ++it) + for (const auto& temp_cat : temp_cats) { - if (cached_ids.find((*it)->getUUID()) == not_cached_id) + if(cached_ids.find(temp_cat->getUUID()) == not_cached_id) { // this check is performed so that we do not // mark new folders in the skeleton (and not in cache) // as being cached. - LLViewerInventoryCategory *llvic = (*it); + LLViewerInventoryCategory *llvic = temp_cat; llvic->setVersion(NO_VERSION); } - addCategory(*it); - ++child_counts[(*it)->getParentUUID()]; + addCategory(temp_cat); + ++child_counts[temp_cat->getParentUUID()]; } // Add all the items loaded which are parented to a @@ -1926,14 +2169,13 @@ bool LLInventoryModel::loadSkeleton( S32 bad_link_count = 0; S32 good_link_count = 0; S32 recovered_link_count = 0; - cat_map_t::iterator unparented = mCategoryMap.end(); + const auto unparented = mCategoryMap.cend(); for(item_array_t::const_iterator item_iter = items.begin(); item_iter != items.end(); ++item_iter) { LLViewerInventoryItem *item = (*item_iter).get(); - const cat_map_t::iterator cit = mCategoryMap.find(item->getParentUUID()); - + const auto cit = mCategoryMap.find(item->getParentUUID()); if(cit != unparented) { const LLViewerInventoryCategory* cat = cit->second.get(); @@ -1943,14 +2185,14 @@ bool LLInventoryModel::loadSkeleton( if (item->getIsBrokenLink()) { //bad_link_count++; - lldebugs << "Attempted to add cached link item without baseobj present ( name: " - << item->getName() << " itemID: " << item->getUUID() - << " assetID: " << item->getAssetUUID() - << " ). Ignoring and invalidating " << cat->getName() << " . " << llendl; + LL_DEBUGS(LOG_INV) << "Attempted to add cached link item without baseobj present ( name: " + << item->getName() << " itemID: " << item->getUUID() + << " assetID: " << item->getAssetUUID() + << " ). Ignoring and invalidating " << cat->getName() << " . " << LL_ENDL; possible_broken_links.push_back(item); continue; } - else if (item->getIsLinkType()) + if (item->getIsLinkType()) { good_link_count++; } @@ -1960,20 +2202,20 @@ bool LLInventoryModel::loadSkeleton( } } } - if (possible_broken_links.size() > 0) + if (!possible_broken_links.empty()) { for(item_array_t::const_iterator item_iter = possible_broken_links.begin(); item_iter != possible_broken_links.end(); ++item_iter) { LLViewerInventoryItem *item = (*item_iter).get(); - const cat_map_t::iterator cit = mCategoryMap.find(item->getParentUUID()); + const auto cit = mCategoryMap.find(item->getParentUUID()); const LLViewerInventoryCategory* cat = cit->second.get(); if (item->getIsBrokenLink()) { bad_link_count++; invalid_categories.insert(cit->second); - //llinfos << "link still broken: " << item->getName() << " in folder " << cat->getName() << llendl; + //LL_INFOS(LOG_INV) << "link still broken: " << item->getName() << " in folder " << cat->getName() << LL_ENDL; } else { @@ -1985,11 +2227,11 @@ bool LLInventoryModel::loadSkeleton( } } - llinfos << "Attempted to add " << bad_link_count - << " cached link items without baseobj present. " - << good_link_count << " link items were successfully added. " - << recovered_link_count << " links added in recovery. " - << "The corresponding categories were invalidated." << llendl; + LL_INFOS(LOG_INV) << "Attempted to add " << bad_link_count + << " cached link items without baseobj present. " + << good_link_count << " link items were successfully added. " + << recovered_link_count << " links added in recovery. " + << "The corresponding categories were invalidated." << LL_ENDL; } } @@ -1997,32 +2239,31 @@ bool LLInventoryModel::loadSkeleton( { // go ahead and add everything after stripping the version // information. - for (cat_set_t::iterator it = temp_cats.begin(); it != temp_cats.end(); ++it) + for (const auto& temp_cat : temp_cats) { - LLViewerInventoryCategory *llvic = (*it); + LLViewerInventoryCategory *llvic = temp_cat; llvic->setVersion(NO_VERSION); - addCategory(*it); + addCategory(temp_cat); } } // Invalidate all categories that failed fetching descendents for whatever // reason (e.g. one of the descendents was a broken link). - for (cat_set_t::iterator invalid_cat_it = invalid_categories.begin(); - invalid_cat_it != invalid_categories.end(); - invalid_cat_it++) + for (const auto& invalid_categorie : invalid_categories) { - LLViewerInventoryCategory* cat = (*invalid_cat_it).get(); + LLViewerInventoryCategory* cat = invalid_categorie.get(); cat->setVersion(NO_VERSION); - llinfos << "Invalidating category name: " << cat->getName() << " UUID: " << cat->getUUID() << " due to invalid descendents cache" << llendl; + LL_DEBUGS(LOG_INV) << "Invalidating category name: " << cat->getName() << " UUID: " << cat->getUUID() << " due to invalid descendents cache" << LL_ENDL; } + LL_INFOS(LOG_INV) << "Invalidated " << invalid_categories.size() << " categories due to invalid descendents cache" << LL_ENDL; // At this point, we need to set the known descendents for each // category which successfully cached so that we do not // needlessly fetch descendents for categories which we have. update_map_t::const_iterator no_child_counts = child_counts.end(); - for(cat_set_t::iterator it = temp_cats.begin(); it != temp_cats.end(); ++it) + for (const auto& temp_cat : temp_cats) { - LLViewerInventoryCategory* cat = (*it).get(); + LLViewerInventoryCategory* cat = temp_cat.get(); if(cat->getVersion() != NO_VERSION) { update_map_t::const_iterator the_count = child_counts.find(cat->getUUID()); @@ -2038,52 +2279,33 @@ bool LLInventoryModel::loadSkeleton( } } - if (remove_inventory_file) + if(remove_inventory_file) { // clean up the gunzipped file. LLFile::remove(inventory_filename); } - if (is_cache_obsolete) + if(is_cache_obsolete) { // If out of date, remove the gzipped file too. - llwarns << "Inv cache out of date, removing" << llendl; + LL_WARNS(LOG_INV) << "Inv cache out of date, removing" << LL_ENDL; LLFile::remove(gzip_filename); } categories.clear(); // will unref and delete entries } - llinfos << "Successfully loaded " << cached_category_count - << " categories and " << cached_item_count << " items from cache." - << llendl; + LL_INFOS(LOG_INV) << "Successfully loaded " << cached_category_count + << " categories and " << cached_item_count << " items from cache." + << LL_ENDL; return rv; } -//OGPX crap. Since this function is actually functionally the same as its LLSD variant.. -// just convert options_t to LLSD and route to the LLSD version. Yuck. -bool LLInventoryModel::loadSkeleton( - const LLInventoryModel::options_t& options, - const LLUUID& owner_id) -{ - LLSD options_list; - for(options_t::const_iterator it = options.begin(); it < options.end(); ++it) - { - LLSD entry; - for(response_t::const_iterator it2 = it->begin(); it2 != it->end(); ++it2) - { - entry[it2->first]=it2->second; - } - options_list.append(entry); - } - return loadSkeleton(options_list,owner_id); -} - // This is a brute force method to rebuild the entire parent-child // relations. The overall operation has O(NlogN) performance, which // should be sufficient for our needs. void LLInventoryModel::buildParentChildMap() { - llinfos << "LLInventoryModel::buildParentChildMap()" << llendl; + LL_INFOS(LOG_INV) << "LLInventoryModel::buildParentChildMap()" << LL_ENDL; // *NOTE: I am skipping the logic around folder version // synchronization here because it seems if a folder is lost, we @@ -2097,10 +2319,10 @@ void LLInventoryModel::buildParentChildMap() cat_array_t* catsp; item_array_t* itemsp; - for(cat_map_t::iterator cit = mCategoryMap.begin(); cit != mCategoryMap.end(); ++cit) + for (auto& cit : mCategoryMap) { - LLViewerInventoryCategory* cat = cit->second; - cats.put(cat); + LLViewerInventoryCategory* cat = cit.second; + cats.push_back(cat); if (mParentChildCategoryTree.count(cat->getUUID()) == 0) { llassert_always(mCategoryLock[cat->getUUID()] == false); @@ -2128,60 +2350,81 @@ void LLInventoryModel::buildParentChildMap() // Now we have a structure with all of the categories that we can // iterate over and insert into the correct place in the child // category tree. - S32 count = cats.count(); - S32 i; - S32 lost = 0; + U32 count = cats.size(); + U32 i; + U32 lost = 0; + cat_array_t lost_cats; for(i = 0; i < count; ++i) { - LLViewerInventoryCategory* cat = cats.get(i); + LLViewerInventoryCategory* cat = cats.at(i); + catsp = getUnlockedCatArray(cat->getParentUUID()); + if (catsp && + // Only the two root folders should be children of null. + // Others should go to lost & found. + (cat->getParentUUID().notNull() || + (cat->getPreferredType() == LLFolderType::FT_ROOT_INVENTORY + || (cat->getParentUUID().isNull() && cat->getName() == "My Inventory")))) + { + catsp->push_back(cat); + } + else + { + // *NOTE: This process could be a lot more efficient if we + // used the new MoveInventoryFolder message, but we would + // have to continue to do the update & build here. So, to + // implement it, we would need a set or map of uuid pairs + // which would be (folder_id, new_parent_id) to be sent up + // to the server. + LL_INFOS(LOG_INV) << "Lost category: " << cat->getUUID() << " - " + << cat->getName() << LL_ENDL; + ++lost; + lost_cats.push_back(cat); + } + } + if(lost) + { + LL_WARNS(LOG_INV) << "Found " << lost << " lost categories." << LL_ENDL; + } + + // Do moves in a separate pass to make sure we've properly filed + // the FT_LOST_AND_FOUND category before we try to find its UUID. + for(i = 0; igetPreferredType(); + if(LLFolderType::FT_NONE == pref) + { + cat->setParent(findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND)); + } + else if(LLFolderType::FT_ROOT_INVENTORY == pref) + { + // it's the root + cat->setParent(LLUUID::null); + } + else + { + // it's a protected folder. + cat->setParent(gInventory.getRootFolderID()); + } + // FIXME note that updateServer() fails with protected + // types, so this will not work as intended in that case. + // UpdateServer uses AIS, AIS cat move is not implemented yet + // cat->updateServer(TRUE); + + // MoveInventoryFolder message, intentionally per item + cat->updateParentOnServer(FALSE); catsp = getUnlockedCatArray(cat->getParentUUID()); if(catsp) { - catsp->put(cat); + catsp->push_back(cat); } else - { - // *NOTE: This process could be a lot more efficient if we - // used the new MoveInventoryFolder message, but we would - // have to continue to do the update & build here. So, to - // implement it, we would need a set or map of uuid pairs - // which would be (folder_id, new_parent_id) to be sent up - // to the server. - llinfos << "Lost categroy: " << cat->getUUID() << " - " - << cat->getName() << " with parent:" << cat->getParentUUID() << llendl; - ++lost; - // plop it into the lost & found. - LLFolderType::EType pref = cat->getPreferredType(); - if(LLFolderType::FT_NONE == pref) - { - cat->setParent(findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND)); - } - else if(LLFolderType::FT_ROOT_INVENTORY == pref) - { - // it's the root - cat->setParent(LLUUID::null); - } - else - { - // it's a protected folder. - cat->setParent(gInventory.getRootFolderID()); - } - cat->updateServer(TRUE); - catsp = getUnlockedCatArray(cat->getParentUUID()); - if(catsp) - { - catsp->put(cat); - } - else - { - llwarns << "Lost and found Not there!!" << llendl; - } + { + LL_WARNS(LOG_INV) << "Lost and found Not there!!" << LL_ENDL; } } - if(lost) - { - llwarns << "Found " << lost << " lost categories." << llendl; - } const BOOL COF_exists = (findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, FALSE) != LLUUID::null); sFirstTimeInViewer2 = !COF_exists || gAgent.isFirstLogin(); @@ -2193,29 +2436,27 @@ void LLInventoryModel::buildParentChildMap() item_array_t items; if(!mItemMap.empty()) { - LLPointer item; - for(item_map_t::iterator iit = mItemMap.begin(); iit != mItemMap.end(); ++iit) + for (auto& iit : mItemMap) { - item = (*iit).second; - items.put(item); + LLPointer item = iit.second; + items.push_back(item); } } - count = items.count(); + count = items.size(); lost = 0; uuid_vec_t lost_item_ids; for(i = 0; i < count; ++i) { - LLPointer item; - item = items.get(i); + LLPointer item = items.at(i); itemsp = getUnlockedItemArray(item->getParentUUID()); if(itemsp) { - itemsp->put(item); + itemsp->push_back(item); } else { - llinfos << "Lost item: " << item->getUUID() << " - " - << item->getName() << llendl; + LL_INFOS(LOG_INV) << "Lost item: " << item->getUUID() << " - " + << item->getName() << LL_ENDL; ++lost; // plop it into the lost & found. // @@ -2227,17 +2468,17 @@ void LLInventoryModel::buildParentChildMap() itemsp = getUnlockedItemArray(item->getParentUUID()); if(itemsp) { - itemsp->put(item); + itemsp->push_back(item); } else { - llwarns << "Lost and found Not there!!" << llendl; + LL_WARNS(LOG_INV) << "Lost and found Not there!!" << LL_ENDL; } } } if(lost) { - llwarns << "Found " << lost << " lost items." << llendl; + LL_WARNS(LOG_INV) << "Found " << lost << " lost items." << LL_ENDL; LLMessageSystem* msg = gMessageSystem; BOOL start_new_message = TRUE; const LLUUID lnf = findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); @@ -2255,7 +2496,7 @@ void LLInventoryModel::buildParentChildMap() msg->nextBlockFast(_PREHASH_InventoryData); msg->addUUIDFast(_PREHASH_ItemID, (*it)); msg->addUUIDFast(_PREHASH_FolderID, lnf); - msg->addString("NewName", NULL); + msg->addString("NewName", nullptr); if(msg->isSendFull(NULL)) { start_new_message = TRUE; @@ -2268,16 +2509,16 @@ void LLInventoryModel::buildParentChildMap() } } - const LLUUID& agent_inv_root_id = gInventory.getRootFolderID(); + const LLUUID &agent_inv_root_id = gInventory.getRootFolderID(); if (agent_inv_root_id.notNull()) { cat_array_t* catsp = get_ptr_in_map(mParentChildCategoryTree, agent_inv_root_id); if(catsp) { // *HACK - fix root inventory folder - // some accounts has pbroken inventory root folders + // some accounts has broken inventory root folders - std::string name = "My Inventory"; + static const std::string name = "My Inventory"; LLUUID prev_root_id = mRootFolderID; for (parent_cat_map_t::const_iterator it = mParentChildCategoryTree.begin(), it_end = mParentChildCategoryTree.end(); it != it_end; ++it) @@ -2305,19 +2546,32 @@ void LLInventoryModel::buildParentChildMap() // root of the agent's inv found. // The inv tree is built. mIsAgentInvUsable = true; + AIEvent::trigger(AIEvent::LLInventoryModel_mIsAgentInvUsable_true); - llinfos << "Inventory initialized, notifying observers" << llendl; - addChangedMask(LLInventoryObserver::ALL, LLUUID::null); - notifyObservers(); + // notifyObservers() has been moved to + // llstartup/idle_startup() after this func completes. + // Allows some system categories to be created before + // observers start firing. } } - llinfos << " finished buildParentChildMap " << llendl; - // dumpInventory(); // enable this if debugging inventory or appearance issues OGPX + + if (!gInventory.validate()) + { + LL_WARNS(LOG_INV) << "model failed validity check!" << LL_ENDL; + } +} + +void LLInventoryModel::createCommonSystemCategories() +{ + gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH,true); + gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE,true); + gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD,true); + gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS,true); } struct LLUUIDAndName { - LLUUIDAndName() {} + LLUUIDAndName() = default; LLUUIDAndName(const LLUUID& id, const std::string& name); bool operator==(const LLUUIDAndName& rhs) const; bool operator<(const LLUUIDAndName& rhs) const; @@ -2351,18 +2605,19 @@ bool LLUUIDAndName::operator>(const LLUUIDAndName& rhs) const bool LLInventoryModel::loadFromFile(const std::string& filename, LLInventoryModel::cat_array_t& categories, LLInventoryModel::item_array_t& items, + LLInventoryModel::changed_items_t& cats_to_update, bool &is_cache_obsolete) { if(filename.empty()) { - llerrs << "Filename is Null!" << llendl; + LL_ERRS(LOG_INV) << "Filename is Null!" << LL_ENDL; return false; } - llinfos << "LLInventoryModel::loadFromFile(" << filename << ")" << llendl; + LL_INFOS(LOG_INV) << "LLInventoryModel::loadFromFile(" << filename << ")" << LL_ENDL; LLFILE* file = LLFile::fopen(filename, "rb"); /*Flawfinder: ignore*/ if(!file) { - llinfos << "unable to load inventory from: " << filename << llendl; + LL_INFOS(LOG_INV) << "unable to load inventory from: " << filename << LL_ENDL; return false; } // *NOTE: This buffer size is hard coded into scanf() below. @@ -2373,7 +2628,7 @@ bool LLInventoryModel::loadFromFile(const std::string& filename, while(!feof(file) && fgets(buffer, MAX_STRING, file)) { sscanf(buffer, " %126s %126s", keyword, value); /* Flawfinder: ignore */ - if (0 == strcmp("inv_cache_version", keyword)) + if(0 == strcmp("inv_cache_version", keyword)) { S32 version; int succ = sscanf(value,"%d",&version); @@ -2397,11 +2652,11 @@ bool LLInventoryModel::loadFromFile(const std::string& filename, LLPointer inv_cat = new LLViewerInventoryCategory(LLUUID::null); if(inv_cat->importFileLocal(file)) { - categories.put(inv_cat); + categories.push_back(inv_cat); } else { - llwarns << "loadInventoryFromFile(). Ignoring invalid inventory category: " << inv_cat->getName() << llendl; + LL_WARNS(LOG_INV) << "loadInventoryFromFile(). Ignoring invalid inventory category: " << inv_cat->getName() << LL_ENDL; //delete inv_cat; // automatic when inv_cat is reassigned or destroyed } } @@ -2419,25 +2674,32 @@ bool LLInventoryModel::loadFromFile(const std::string& filename, if(inv_item->getUUID().isNull()) { //delete inv_item; // automatic when inv_cat is reassigned or destroyed - llwarns << "Ignoring inventory with null item id: " - << inv_item->getName() << llendl; + LL_WARNS(LOG_INV) << "Ignoring inventory with null item id: " + << inv_item->getName() << LL_ENDL; } else { - items.put(inv_item); + if (inv_item->getType() == LLAssetType::AT_UNKNOWN) + { + cats_to_update.insert(inv_item->getParentUUID()); + } + else + { + items.push_back(inv_item); + } } } else { - llwarns << "loadInventoryFromFile(). Ignoring invalid inventory item: " << inv_item->getName() << llendl; + LL_WARNS(LOG_INV) << "loadInventoryFromFile(). Ignoring invalid inventory item: " << inv_item->getName() << LL_ENDL; //delete inv_item; // automatic when inv_cat is reassigned or destroyed } } else { - llwarns << "Unknown token in inventory file '" << keyword << "'" - << llendl; + LL_WARNS(LOG_INV) << "Unknown token in inventory file '" << keyword << "'" + << LL_ENDL; } } fclose(file); @@ -2453,19 +2715,19 @@ bool LLInventoryModel::saveToFile(const std::string& filename, { if(filename.empty()) { - llerrs << "Filename is Null!" << llendl; + LL_ERRS(LOG_INV) << "Filename is Null!" << LL_ENDL; return false; } - llinfos << "LLInventoryModel::saveToFile(" << filename << ")" << llendl; + LL_INFOS(LOG_INV) << "LLInventoryModel::saveToFile(" << filename << ")" << LL_ENDL; LLFILE* file = LLFile::fopen(filename, "wb"); /*Flawfinder: ignore*/ if(!file) { - llwarns << "unable to save inventory to: " << filename << llendl; + LL_WARNS(LOG_INV) << "unable to save inventory to: " << filename << LL_ENDL; return false; } - fprintf(file, "\tinv_cache_version\t%d\n", sCurrentInvCacheVersion); - S32 count = categories.count(); + fprintf(file, "\tinv_cache_version\t%d\n",sCurrentInvCacheVersion); + S32 count = categories.size(); S32 i; for(i = 0; i < count; ++i) { @@ -2476,7 +2738,7 @@ bool LLInventoryModel::saveToFile(const std::string& filename, } } - count = items.count(); + count = items.size(); for(i = 0; i < count; ++i) { items[i]->exportFile(file); @@ -2536,7 +2798,7 @@ void LLInventoryModel::registerCallbacks(LLMessageSystem* msg) void LLInventoryModel::processUpdateCreateInventoryItem(LLMessageSystem* msg, void**) { // do accounting and highlight new items if they arrive - if (gInventory.messageUpdateCore(msg, true)) + if (gInventory.messageUpdateCore(msg, true, LLInventoryObserver::UPDATE_CREATE)) { U32 callback_id; LLUUID item_id; @@ -2556,7 +2818,7 @@ void LLInventoryModel::processFetchInventoryReply(LLMessageSystem* msg, void**) } -bool LLInventoryModel::messageUpdateCore(LLMessageSystem* msg, bool account) +bool LLInventoryModel::messageUpdateCore(LLMessageSystem* msg, bool account, U32 mask) { //make sure our added inventory observer is active start_new_inventory_observer(); @@ -2565,21 +2827,20 @@ bool LLInventoryModel::messageUpdateCore(LLMessageSystem* msg, bool account) msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); if(agent_id != gAgent.getID()) { - llwarns << "Got a inventory update for the wrong agent: " << agent_id - << llendl; + LL_WARNS(LOG_INV) << "Got a inventory update for the wrong agent: " << agent_id + << LL_ENDL; return false; } item_array_t items; update_map_t update; S32 count = msg->getNumberOfBlocksFast(_PREHASH_InventoryData); - LLUUID folder_id; // Does this loop ever execute more than once? for(S32 i = 0; i < count; ++i) { LLPointer titem = new LLViewerInventoryItem; titem->unpackMessage(msg, _PREHASH_InventoryData, i); - lldebugs << "LLInventoryModel::messageUpdateCore() item id:" - << titem->getUUID() << llendl; + LL_DEBUGS(LOG_INV) << "LLInventoryModel::messageUpdateCore() item id: " + << titem->getUUID() << LL_ENDL; items.push_back(titem); // examine update for changes. LLViewerInventoryItem* itemp = gInventory.getItem(titem->getUUID()); @@ -2599,10 +2860,6 @@ bool LLInventoryModel::messageUpdateCore(LLMessageSystem* msg, bool account) { ++update[titem->getParentUUID()]; } - if (folder_id.isNull()) - { - folder_id = titem->getParentUUID(); - } } if(account) { @@ -2610,10 +2867,14 @@ bool LLInventoryModel::messageUpdateCore(LLMessageSystem* msg, bool account) } U32 changes = 0x0; + if (account) + { + mask |= LLInventoryObserver::CREATE; + } //as above, this loop never seems to loop more than once per call - for (item_array_t::iterator it = items.begin(); it != items.end(); ++it) + for (auto& item : items) { - changes |= gInventory.updateItem(*it); + changes |= gInventory.updateItem(item, mask); } gInventory.notifyObservers(); gViewerWindow->getWindow()->decBusyCount(); @@ -2626,17 +2887,17 @@ void LLInventoryModel::removeInventoryItem(LLUUID agent_id, LLMessageSystem* msg { LLUUID item_id; S32 count = msg->getNumberOfBlocksFast(msg_label); - lldebugs << "Message has " << count << " item blocks" << llendl; + LL_DEBUGS(LOG_INV) << "Message has " << count << " item blocks" << LL_ENDL; uuid_vec_t item_ids; update_map_t update; for(S32 i = 0; i < count; ++i) { msg->getUUIDFast(msg_label, _PREHASH_ItemID, item_id, i); - lldebugs << "Checking for item-to-be-removed " << item_id << llendl; + LL_DEBUGS(LOG_INV) << "Checking for item-to-be-removed " << item_id << LL_ENDL; LLViewerInventoryItem* itemp = gInventory.getItem(item_id); if(itemp) { - lldebugs << "Item will be removed " << item_id << llendl; + LL_DEBUGS(LOG_INV) << "Item will be removed " << item_id << LL_ENDL; // we only bother with the delete and account if we found // the item - this is usually a back-up for permissions, // so frequently the item will already be gone. @@ -2645,23 +2906,23 @@ void LLInventoryModel::removeInventoryItem(LLUUID agent_id, LLMessageSystem* msg } } gInventory.accountForUpdate(update); - for(uuid_vec_t::iterator it = item_ids.begin(); it != item_ids.end(); ++it) + for (auto& item_id : item_ids) { - lldebugs << "Calling deleteObject " << *it << llendl; - gInventory.deleteObject(*it); + LL_DEBUGS(LOG_INV) << "Calling deleteObject " << item_id << LL_ENDL; + gInventory.deleteObject(item_id); } } // static void LLInventoryModel::processRemoveInventoryItem(LLMessageSystem* msg, void**) { - lldebugs << "LLInventoryModel::processRemoveInventoryItem()" << llendl; - LLUUID agent_id, item_id; + LL_DEBUGS(LOG_INV) << "LLInventoryModel::processRemoveInventoryItem()" << LL_ENDL; + LLUUID agent_id; msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); if(agent_id != gAgent.getID()) { - llwarns << "Got a RemoveInventoryItem for the wrong agent." - << llendl; + LL_WARNS(LOG_INV) << "Got a RemoveInventoryItem for the wrong agent." + << LL_ENDL; return; } LLInventoryModel::removeInventoryItem(agent_id, msg, _PREHASH_InventoryData); @@ -2672,14 +2933,14 @@ void LLInventoryModel::processRemoveInventoryItem(LLMessageSystem* msg, void**) void LLInventoryModel::processUpdateInventoryFolder(LLMessageSystem* msg, void**) { - lldebugs << "LLInventoryModel::processUpdateInventoryFolder()" << llendl; - LLUUID agent_id, folder_id, parent_id; + LL_DEBUGS(LOG_INV) << "LLInventoryModel::processUpdateInventoryFolder()" << LL_ENDL; + LLUUID agent_id; //char name[DB_INV_ITEM_NAME_BUF_SIZE]; msg->getUUIDFast(_PREHASH_FolderData, _PREHASH_AgentID, agent_id); if(agent_id != gAgent.getID()) { - llwarns << "Got an UpdateInventoryFolder for the wrong agent." - << llendl; + LL_WARNS(LOG_INV) << "Got an UpdateInventoryFolder for the wrong agent." + << LL_ENDL; return; } LLPointer lastfolder; // hack @@ -2714,9 +2975,9 @@ void LLInventoryModel::processUpdateInventoryFolder(LLMessageSystem* msg, } } gInventory.accountForUpdate(update); - for (cat_array_t::iterator it = folders.begin(); it != folders.end(); ++it) + for (auto& folder : folders) { - gInventory.updateCategory(*it); + gInventory.updateCategory(folder); } gInventory.notifyObservers(); @@ -2729,8 +2990,7 @@ void LLInventoryModel::processUpdateInventoryFolder(LLMessageSystem* msg, } // static -void LLInventoryModel::removeInventoryFolder(LLUUID agent_id, - LLMessageSystem* msg) +void LLInventoryModel::removeInventoryFolder(LLUUID agent_id, LLMessageSystem* msg) { LLUUID folder_id; uuid_vec_t folder_ids; @@ -2747,24 +3007,23 @@ void LLInventoryModel::removeInventoryFolder(LLUUID agent_id, } } gInventory.accountForUpdate(update); - for(uuid_vec_t::iterator it = folder_ids.begin(); it != folder_ids.end(); ++it) + for (auto& folder_id : folder_ids) { - gInventory.deleteObject(*it); + gInventory.deleteObject(folder_id); } } // static -void LLInventoryModel::processRemoveInventoryFolder(LLMessageSystem* msg, - void**) +void LLInventoryModel::processRemoveInventoryFolder(LLMessageSystem* msg, void**) { - lldebugs << "LLInventoryModel::processRemoveInventoryFolder()" << llendl; + LL_DEBUGS() << "LLInventoryModel::processRemoveInventoryFolder()" << LL_ENDL; LLUUID agent_id, session_id; msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_SessionID, session_id); if(agent_id != gAgent.getID()) { - llwarns << "Got a RemoveInventoryFolder for the wrong agent." - << llendl; + LL_WARNS() << "Got a RemoveInventoryFolder for the wrong agent." + << LL_ENDL; return; } LLInventoryModel::removeInventoryFolder( agent_id, msg ); @@ -2772,17 +3031,16 @@ void LLInventoryModel::processRemoveInventoryFolder(LLMessageSystem* msg, } // static -void LLInventoryModel::processRemoveInventoryObjects(LLMessageSystem* msg, - void**) +void LLInventoryModel::processRemoveInventoryObjects(LLMessageSystem* msg, void**) { - lldebugs << "LLInventoryModel::processRemoveInventoryObjects()" << llendl; + LL_DEBUGS() << "LLInventoryModel::processRemoveInventoryObjects()" << LL_ENDL; LLUUID agent_id, session_id; msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_SessionID, session_id); if(agent_id != gAgent.getID()) { - llwarns << "Got a RemoveInventoryObjects for the wrong agent." - << llendl; + LL_WARNS() << "Got a RemoveInventoryObjects for the wrong agent." + << LL_ENDL; return; } LLInventoryModel::removeInventoryFolder( agent_id, msg ); @@ -2791,15 +3049,14 @@ void LLInventoryModel::processRemoveInventoryObjects(LLMessageSystem* msg, } // static -void LLInventoryModel::processSaveAssetIntoInventory(LLMessageSystem* msg, - void**) +void LLInventoryModel::processSaveAssetIntoInventory(LLMessageSystem* msg, void**) { LLUUID agent_id; msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); if(agent_id != gAgent.getID()) { - llwarns << "Got a SaveAssetIntoInventory message for the wrong agent." - << llendl; + LL_WARNS() << "Got a SaveAssetIntoInventory message for the wrong agent." + << LL_ENDL; return; } @@ -2809,8 +3066,8 @@ void LLInventoryModel::processSaveAssetIntoInventory(LLMessageSystem* msg, // The viewer ignores the asset id because this message is only // used for attachments/objects, so the asset id is not used in // the viewer anyway. - lldebugs << "LLInventoryModel::processSaveAssetIntoInventory itemID=" - << item_id << llendl; + LL_DEBUGS() << "LLInventoryModel::processSaveAssetIntoInventory itemID=" + << item_id << LL_ENDL; LLViewerInventoryItem* item = gInventory.getItem( item_id ); if( item ) { @@ -2821,8 +3078,8 @@ void LLInventoryModel::processSaveAssetIntoInventory(LLMessageSystem* msg, } else { - llinfos << "LLInventoryModel::processSaveAssetIntoInventory item" - " not found: " << item_id << llendl; + LL_INFOS() << "LLInventoryModel::processSaveAssetIntoInventory item" + " not found: " << item_id << LL_ENDL; } // [RLVa:KB] - Checked: 2010-03-05 (RLVa-1.2.0a) | Added: RLVa-0.2.0e @@ -2853,28 +3110,38 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**) msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); if(agent_id != gAgent.getID()) { - llwarns << "Got a BulkUpdateInventory for the wrong agent." << llendl; + LL_WARNS() << "Got a BulkUpdateInventory for the wrong agent." << LL_ENDL; return; } LLUUID tid; msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_TransactionID, tid); #ifndef LL_RELEASE_FOR_DOWNLOAD - llinfos << "Bulk inventory: " << tid << llendl; + LL_DEBUGS("Inventory") << "Bulk inventory: " << tid << LL_ENDL; #endif update_map_t update; cat_array_t folders; - S32 count; S32 i; - count = msg->getNumberOfBlocksFast(_PREHASH_FolderData); + S32 count = msg->getNumberOfBlocksFast(_PREHASH_FolderData); for(i = 0; i < count; ++i) { LLPointer tfolder = new LLViewerInventoryCategory(gAgent.getID()); tfolder->unpackMessage(msg, _PREHASH_FolderData, i); - //llinfos << "unpacked folder '" << tfolder->getName() << "' (" - // << tfolder->getUUID() << ") in " << tfolder->getParentUUID() - // << llendl; - if(tfolder->getUUID().notNull()) + LL_DEBUGS("Inventory") << "unpacked folder '" << tfolder->getName() << "' (" + << tfolder->getUUID() << ") in " << tfolder->getParentUUID() + << LL_ENDL; + + // If the folder is a listing or a version folder, all we need to do is update the SLM data + int depth_folder = depth_nesting_in_marketplace(tfolder->getUUID()); + if ((depth_folder == 1) || (depth_folder == 2)) + { + // Trigger an SLM listing update + LLUUID listing_uuid = (depth_folder == 1 ? tfolder->getUUID() : tfolder->getParentUUID()); + S32 listing_id = LLMarketplaceData::instance().getListingID(listing_uuid); + LLMarketplaceData::instance().getListing(listing_id); + // In that case, there is no item to update so no callback -> we skip the rest of the update + } + else if(tfolder->getUUID().notNull()) { folders.push_back(tfolder); LLViewerInventoryCategory* folderp = gInventory.getCategory(tfolder->getUUID()); @@ -2927,14 +3194,14 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**) { LLPointer titem = new LLViewerInventoryItem; titem->unpackMessage(msg, _PREHASH_ItemData, i); - //llinfos << "unpacked item '" << titem->getName() << "' in " - // << titem->getParentUUID() << llendl; + LL_DEBUGS("Inventory") << "unpacked item '" << titem->getName() << "' in " + << titem->getParentUUID() << LL_ENDL; U32 callback_id; msg->getU32Fast(_PREHASH_ItemData, _PREHASH_CallbackID, callback_id); if(titem->getUUID().notNull() ) // && callback_id.notNull() ) { items.push_back(titem); - cblist.push_back(InventoryCallbackInfo(callback_id, titem->getUUID())); + cblist.emplace_back(callback_id, titem->getUUID()); if (titem->getInventoryType() == LLInventoryType::IT_WEARABLE) { wearable_ids.push_back(titem->getUUID()); @@ -2964,18 +3231,18 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**) } else { - cblist.push_back(InventoryCallbackInfo(callback_id, LLUUID::null)); + cblist.emplace_back(callback_id, LLUUID::null); } } gInventory.accountForUpdate(update); - for (cat_array_t::iterator cit = folders.begin(); cit != folders.end(); ++cit) + for (auto& folder : folders) { - gInventory.updateCategory(*cit); + gInventory.updateCategory(folder); } - for (item_array_t::iterator iit = items.begin(); iit != items.end(); ++iit) + for (auto& item : items) { - gInventory.updateItem(*iit); + gInventory.updateItem(item); } gInventory.notifyObservers(); @@ -2993,20 +3260,21 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**) count = wearable_ids.size(); for (i = 0; i < count; ++i) { - LLViewerInventoryItem* wearable_item; - wearable_item = gInventory.getItem(wearable_ids[i]); + LLViewerInventoryItem * wearable_item = gInventory.getItem(wearable_ids[i]); LLAppearanceMgr::instance().wearItemOnAvatar(wearable_item->getUUID(), true, true); } } - std::list::iterator inv_it; - for (inv_it = cblist.begin(); inv_it != cblist.end(); ++inv_it) + for (auto& inv_it : cblist) { - InventoryCallbackInfo cbinfo = (*inv_it); + InventoryCallbackInfo cbinfo = inv_it; gInventoryCallbacks.fire(cbinfo.mCallback, cbinfo.mInvID); } + + //gInventory.validate(); + // Don't show the inventory. We used to call showAgentInventory here. - //LLInventoryView* view = LLInventoryView::getActiveInventory(); + //LLFloaterInventory* view = LLFloaterInventory::getActiveInventory(); //if(view) //{ // const BOOL take_keyboard_focus = FALSE; @@ -3016,10 +3284,10 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**) // // HACK to open inventory offers that are accepted. This information // // really needs to flow through the instant messages and inventory // // transfer/update messages. - // if (LLInventoryView::sOpenNextNewItem) + // if (LLFloaterInventory::sOpenNextNewItem) // { // view->openSelected(); - // LLInventoryView::sOpenNextNewItem = FALSE; + // LLFloaterInventory::sOpenNextNewItem = FALSE; // } // // // restore keyboard focus @@ -3034,7 +3302,7 @@ void LLInventoryModel::processInventoryDescendents(LLMessageSystem* msg,void**) msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); if(agent_id != gAgent.getID()) { - llwarns << "Got a UpdateInventoryItem for the wrong agent." << llendl; + LL_WARNS() << "Got a UpdateInventoryItem for the wrong agent." << LL_ENDL; return; } LLUUID parent_id; @@ -3063,7 +3331,8 @@ void LLInventoryModel::processInventoryDescendents(LLMessageSystem* msg,void**) // If the item has already been added (e.g. from link prefetch), then it doesn't need to be re-added. if (gInventory.getItem(titem->getUUID())) { - lldebugs << "Skipping prefetched item [ Name: " << titem->getName() << " | Type: " << titem->getActualType() << " | ItemUUID: " << titem->getUUID() << " ] " << llendl; + LL_DEBUGS("Inventory") << "Skipping prefetched item [ Name: " << titem->getName() + << " | Type: " << titem->getActualType() << " | ItemUUID: " << titem->getUUID() << " ] " << LL_ENDL; continue; } gInventory.updateItem(titem); @@ -3085,13 +3354,13 @@ void LLInventoryModel::processInventoryDescendents(LLMessageSystem* msg,void**) // static void LLInventoryModel::processMoveInventoryItem(LLMessageSystem* msg, void**) { - lldebugs << "LLInventoryModel::processMoveInventoryItem()" << llendl; + LL_DEBUGS() << "LLInventoryModel::processMoveInventoryItem()" << LL_ENDL; LLUUID agent_id; msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); if(agent_id != gAgent.getID()) { - llwarns << "Got a MoveInventoryItem message for the wrong agent." - << llendl; + LL_WARNS() << "Got a MoveInventoryItem message for the wrong agent." + << LL_ENDL; return; } @@ -3110,8 +3379,8 @@ void LLInventoryModel::processMoveInventoryItem(LLMessageSystem* msg, void**) msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_FolderID, folder_id, i); msg->getString("InventoryData", "NewName", new_name, i); - lldebugs << "moving item " << item_id << " to folder " - << folder_id << llendl; + LL_DEBUGS() << "moving item " << item_id << " to folder " + << folder_id << LL_ENDL; update_list_t update; LLCategoryUpdate old_folder(item->getParentUUID(), -1); update.push_back(old_folder); @@ -3129,7 +3398,7 @@ void LLInventoryModel::processMoveInventoryItem(LLMessageSystem* msg, void**) } else { - llinfos << "LLInventoryModel::processMoveInventoryItem item not found: " << item_id << llendl; + LL_INFOS() << "LLInventoryModel::processMoveInventoryItem item not found: " << item_id << LL_ENDL; } } if(anything_changed) @@ -3149,8 +3418,7 @@ bool LLInventoryModel::callbackEmptyFolderType(const LLSD& notification, const L if (option == 0) // YES { const LLUUID folder_id = findCategoryUUIDForType(preferred_type); - purgeDescendentsOf(folder_id); - notifyObservers(); + purge_descendents_of(folder_id, nullptr); } return false; } @@ -3165,8 +3433,7 @@ void LLInventoryModel::emptyFolderType(const std::string notification, LLFolderT else { const LLUUID folder_id = findCategoryUUIDForType(preferred_type); - purgeDescendentsOf(folder_id); - notifyObservers(); + purge_descendents_of(folder_id, nullptr); } } @@ -3228,6 +3495,11 @@ void LLInventoryModel::removeCategory(const LLUUID& category_id) void LLInventoryModel::removeObject(const LLUUID& object_id) { + if(object_id.isNull()) + { + return; + } + LLInventoryObject* obj = getObject(object_id); if (dynamic_cast(obj)) { @@ -3285,7 +3557,7 @@ BOOL LLInventoryModel::getIsFirstTimeInViewer2() // Do not call this before parentchild map is built. if (!gInventory.mIsAgentInvUsable) { - llwarns << "Parent Child Map not yet built; guessing as first time in viewer2." << llendl; + LL_WARNS() << "Parent Child Map not yet built; guessing as first time in viewer2." << LL_ENDL; return TRUE; } @@ -3375,25 +3647,25 @@ void LLInventoryModel::saveItemsOrder(const LLInventoryModel::item_array_t& item } */ // See also LLInventorySort where landmarks in the Favorites folder are sorted. -/*class LLViewerInventoryItemSort +class LLViewerInventoryItemSort { public: - bool operator()(const LLPointer& a, const LLPointer& b) + bool operator()(const LLPointer& a, const LLPointer& b) const { return a->getSortField() < b->getSortField(); } -};*/ +}; /** * Sorts passed items by LLViewerInventoryItem sort field. * * @param[in, out] items - array of items, not sorted. */ -/*static void rearrange_item_order_by_sort_field(LLInventoryModel::item_array_t& items) -{ - static LLViewerInventoryItemSort sort_functor; - std::sort(items.begin(), items.end(), sort_functor); -}*/ +//static void rearrange_item_order_by_sort_field(LLInventoryModel::item_array_t& items) +//{ +// static LLViewerInventoryItemSort sort_functor; +// std::sort(items.begin(), items.end(), sort_functor); +//} // * @param source_item_id - LLUUID of the source item to be moved into new position // * @param target_item_id - LLUUID of the target item before which source item should be placed. @@ -3420,37 +3692,337 @@ void LLInventoryModel::rearrangeFavoriteLandmarks(const LLUUID& source_item_id, // *NOTE: DEBUG functionality void LLInventoryModel::dumpInventory() const { - llinfos << "\nBegin Inventory Dump\n**********************:" << llendl; - llinfos << "mCategory[] contains " << mCategoryMap.size() << " items." << llendl; - for(cat_map_t::const_iterator cit = mCategoryMap.begin(); cit != mCategoryMap.end(); ++cit) + LL_INFOS() << "\nBegin Inventory Dump\n**********************:" << LL_ENDL; + LL_INFOS() << "mCategory[] contains " << mCategoryMap.size() << " items." << LL_ENDL; + for (const auto& cit : mCategoryMap) { - const LLViewerInventoryCategory* cat = cit->second; + const LLViewerInventoryCategory* cat = cit.second; if(cat) { - llinfos << " " << cat->getUUID() << " '" << cat->getName() << "' " - << cat->getVersion() << " " << cat->getDescendentCount() << " parent: " << cat->getParentUUID() - << llendl; + LL_INFOS() << " " << cat->getUUID() << " '" << cat->getName() << "' " + << cat->getVersion() << " " << cat->getDescendentCount() + << " parent: " << cat->getParentUUID() + << LL_ENDL; } else { - llinfos << " NULL!" << llendl; + LL_INFOS() << " NULL!" << LL_ENDL; } } - llinfos << "mItemMap[] contains " << mItemMap.size() << " items." << llendl; - for(item_map_t::const_iterator iit = mItemMap.begin(); iit != mItemMap.end(); ++iit) + LL_INFOS() << "mItemMap[] contains " << mItemMap.size() << " items." << LL_ENDL; + for (const auto& iit : mItemMap) { - const LLViewerInventoryItem* item = iit->second; + const LLViewerInventoryItem* item = iit.second; if(item) { - llinfos << " " << item->getUUID() << " " - << item->getName() << llendl; + LL_INFOS() << " " << item->getUUID() << " " + << item->getName() << LL_ENDL; + } + else + { + LL_INFOS() << " NULL!" << LL_ENDL; + } + } + LL_INFOS() << "\n**********************\nEnd Inventory Dump" << LL_ENDL; +} + +// Do various integrity checks on model, logging issues found and +// returning an overall good/bad flag. +bool LLInventoryModel::validate() const +{ + bool valid = true; + + if (getRootFolderID().isNull()) + { + LL_WARNS() << "no root folder id" << LL_ENDL; + valid = false; + } + if (getLibraryRootFolderID().isNull()) + { + LL_WARNS() << "no root folder id" << LL_ENDL; + valid = false; + } + + if (mCategoryMap.size() + 1 != mParentChildCategoryTree.size()) + { + // ParentChild should be one larger because of the special entry for null uuid. + LL_INFOS() << "unexpected sizes: cat map size " << mCategoryMap.size() + << " parent/child " << mParentChildCategoryTree.size() << LL_ENDL; + valid = false; + } + S32 cat_lock = 0; + S32 item_lock = 0; + S32 desc_unknown_count = 0; + S32 version_unknown_count = 0; + for (const auto& cit : mCategoryMap) + { + const LLUUID& cat_id = cit.first; + const LLViewerInventoryCategory *cat = cit.second; + if (!cat) + { + LL_WARNS() << "invalid cat" << LL_ENDL; + valid = false; + continue; + } + if (cat_id != cat->getUUID()) + { + LL_WARNS() << "cat id/index mismatch " << cat_id << " " << cat->getUUID() << LL_ENDL; + valid = false; + } + + if (cat->getParentUUID().isNull()) + { + if (cat_id != getRootFolderID() && cat_id != getLibraryRootFolderID()) + { + LL_WARNS() << "cat " << cat_id << " has no parent, but is not root (" + << getRootFolderID() << ") or library root (" + << getLibraryRootFolderID() << ")" << LL_ENDL; + } + } + cat_array_t* cats; + item_array_t* items; + getDirectDescendentsOf(cat_id,cats,items); + if (!cats || !items) + { + LL_WARNS() << "invalid direct descendents for " << cat_id << LL_ENDL; + valid = false; + continue; + } + if (cat->getDescendentCount() == LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN) + { + desc_unknown_count++; + } + else if (cats->size() + items->size() != cat->getDescendentCount()) + { + LL_WARNS() << "invalid desc count for " << cat_id << " name [" << cat->getName() + << "] parent " << cat->getParentUUID() + << " cached " << cat->getDescendentCount() + << " expected " << cats->size() << "+" << items->size() + << "=" << cats->size() +items->size() << LL_ENDL; + valid = false; + } + if (cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN) + { + version_unknown_count++; + } + if (mCategoryLock.count(cat_id)) + { + cat_lock++; + } + if (mItemLock.count(cat_id)) + { + item_lock++; + } + for (U32 i = 0; isize(); i++) + { + LLViewerInventoryItem *item = items->at(i); + + if (!item) + { + LL_WARNS() << "null item at index " << i << " for cat " << cat_id << LL_ENDL; + valid = false; + continue; + } + + const LLUUID& item_id = item->getUUID(); + + if (item->getParentUUID() != cat_id) + { + LL_WARNS() << "wrong parent for " << item_id << " found " + << item->getParentUUID() << " expected " << cat_id + << LL_ENDL; + valid = false; + } + + + // Entries in items and mItemMap should correspond. + item_map_t::const_iterator it = mItemMap.find(item_id); + if (it == mItemMap.end()) + { + LL_WARNS() << "item " << item_id << " found as child of " + << cat_id << " but not in top level mItemMap" << LL_ENDL; + valid = false; + } + else + { + LLViewerInventoryItem *top_item = it->second; + if (top_item != item) + { + LL_WARNS() << "item mismatch, item_id " << item_id + << " top level entry is different, uuid " << top_item->getUUID() << LL_ENDL; + } + } + + // Topmost ancestor should be root or library. + LLUUID topmost_ancestor_id; + bool found = getObjectTopmostAncestor(item_id, topmost_ancestor_id); + if (!found) + { + LL_WARNS() << "unable to find topmost ancestor for " << item_id << LL_ENDL; + valid = false; + } + else + { + if (topmost_ancestor_id != getRootFolderID() && + topmost_ancestor_id != getLibraryRootFolderID()) + { + LL_WARNS() << "unrecognized top level ancestor for " << item_id + << " got " << topmost_ancestor_id + << " expected " << getRootFolderID() + << " or " << getLibraryRootFolderID() << LL_ENDL; + valid = false; + } + } + } + + // Does this category appear as a child of its supposed parent? + const LLUUID& parent_id = cat->getParentUUID(); + if (!parent_id.isNull()) + { + cat_array_t* cats; + item_array_t* items; + getDirectDescendentsOf(parent_id,cats,items); + if (!cats) + { + LL_WARNS() << "cat " << cat_id << " name [" << cat->getName() + << "] orphaned - no child cat array for alleged parent " << parent_id << LL_ENDL; + valid = false; + } + else + { + bool found = false; + for (auto& i : *cats) + { + LLViewerInventoryCategory *kid_cat = i; + if (kid_cat == cat) + { + found = true; + break; + } + } + if (!found) + { + LL_WARNS() << "cat " << cat_id << " name [" << cat->getName() + << "] orphaned - not found in child cat array of alleged parent " << parent_id << LL_ENDL; + } + } + } + } + + for (const auto& iit : mItemMap) + { + const LLUUID& item_id = iit.first; + LLViewerInventoryItem *item = iit.second; + if (item->getUUID() != item_id) + { + LL_WARNS() << "item_id " << item_id << " does not match " << item->getUUID() << LL_ENDL; + valid = false; + } + + const LLUUID& parent_id = item->getParentUUID(); + if (parent_id.isNull()) + { + LL_WARNS() << "item " << item_id << " name [" << item->getName() << "] has null parent id!" << LL_ENDL; + } + else + { + cat_array_t* cats; + item_array_t* items; + getDirectDescendentsOf(parent_id,cats,items); + if (!items) + { + LL_WARNS() << "item " << item_id << " name [" << item->getName() + << "] orphaned - alleged parent has no child items list " << parent_id << LL_ENDL; + } + else + { + bool found = false; + for (auto& i : *items) + { + if (i == item) + { + found = true; + break; + } + } + if (!found) + { + LL_WARNS() << "item " << item_id << " name [" << item->getName() + << "] orphaned - not found as child of alleged parent " << parent_id << LL_ENDL; + } + } + + } + // Link checking + if (item->getIsLinkType()) + { + const LLUUID& link_id = item->getUUID(); + const LLUUID& target_id = item->getLinkedUUID(); + LLViewerInventoryItem *target_item = getItem(target_id); + LLViewerInventoryCategory *target_cat = getCategory(target_id); + // Linked-to UUID should have back reference to this link. + if (!hasBacklinkInfo(link_id, target_id)) + { + LL_WARNS() << "link " << item->getUUID() << " type " << item->getActualType() + << " missing backlink info at target_id " << target_id + << LL_ENDL; + } + // Links should have referents. + if (item->getActualType() == LLAssetType::AT_LINK && !target_item) + { + LL_WARNS() << "broken item link " << item->getName() << " id " << item->getUUID() << LL_ENDL; + } + else if (item->getActualType() == LLAssetType::AT_LINK_FOLDER && !target_cat) + { + LL_WARNS() << "broken folder link " << item->getName() << " id " << item->getUUID() << LL_ENDL; + } + if (target_item && target_item->getIsLinkType()) + { + LL_WARNS() << "link " << item->getName() << " references a link item " + << target_item->getName() << " " << target_item->getUUID() << LL_ENDL; + } + + // Links should not have backlinks. + std::pair range = mBacklinkMMap.equal_range(link_id); + if (range.first != range.second) + { + LL_WARNS() << "Link item " << item->getName() << " has backlinks!" << LL_ENDL; + } } else { - llinfos << " NULL!" << llendl; + // Check the backlinks of a non-link item. + const LLUUID& target_id = item->getUUID(); + std::pair range = mBacklinkMMap.equal_range(target_id); + for (backlink_mmap_t::const_iterator it = range.first; it != range.second; ++it) + { + const LLUUID& link_id = it->second; + LLViewerInventoryItem *link_item = getItem(link_id); + if (!link_item || !link_item->getIsLinkType()) + { + LL_WARNS() << "invalid backlink from target " << item->getName() << " to " << link_id << LL_ENDL; + } + } } } - llinfos << "\n**********************\nEnd Inventory Dump" << llendl; + + if (cat_lock > 0 || item_lock > 0) + { + LL_INFOS() << "Found locks on some categories: sub-cat arrays " + << cat_lock << ", item arrays " << item_lock << LL_ENDL; + } + if (desc_unknown_count != 0) + { + LL_INFOS() << "Found " << desc_unknown_count << " cats with unknown descendent count" << LL_ENDL; + } + if (version_unknown_count != 0) + { + LL_INFOS() << "Found " << version_unknown_count << " cats with unknown version" << LL_ENDL; + } + + LL_INFOS() << "Validate done, valid = " << (U32) valid << LL_ENDL; + + return valid; } ///---------------------------------------------------------------------------- @@ -3458,7 +4030,7 @@ void LLInventoryModel::dumpInventory() const ///---------------------------------------------------------------------------- -/* +#if 0 BOOL decompress_file(const char* src_filename, const char* dst_filename) { BOOL rv = FALSE; @@ -3468,13 +4040,17 @@ BOOL decompress_file(const char* src_filename, const char* dst_filename) S32 bytes = 0; const S32 DECOMPRESS_BUFFER_SIZE = 32000; - // open the files +// open the files +#if LL_WINDOWS + src = gzopen_w(utf8str_to_utf16str(src_filename).c_str(), "rb"); +#else src = gzopen(src_filename, "rb"); +#endif if(!src) goto err_decompress; dst = LLFile::fopen(dst_filename, "wb"); if(!dst) goto err_decompress; - // decompress. +// decompress. buffer = new U8[DECOMPRESS_BUFFER_SIZE + 1]; do @@ -3488,7 +4064,7 @@ BOOL decompress_file(const char* src_filename, const char* dst_filename) fwrite(buffer, bytes, 1, dst); } while(gzeof(src) == 0); - // success +// success rv = TRUE; err_decompress: @@ -3497,4 +4073,82 @@ BOOL decompress_file(const char* src_filename, const char* dst_filename) if(dst != NULL) fclose(dst); return rv; } -*/ +#endif + +// If we get back a normal response, handle it here +void LLInventoryModel::FetchItemHttpHandler::httpSuccess() +{ + start_new_inventory_observer(); + +#if 0 + LLUUID agent_id; + agent_id = mContent["agent_id"].asUUID(); + if (agent_id != gAgent.getID()) + { + LL_WARNS(LOG_INV) << "Got a inventory update for the wrong agent: " << agent_id + << LL_ENDL; + return; + } +#endif + + LLInventoryModel::item_array_t items; + LLInventoryModel::update_map_t update; + LLUUID folder_id; + LLSD content_items(mContent["items"]); + const S32 count(content_items.size()); + + // Does this loop ever execute more than once? + for (S32 i(0); i < count; ++i) + { + LLPointer titem = new LLViewerInventoryItem; + titem->unpackMessage(content_items[i]); + + LL_DEBUGS(LOG_INV) << "ItemHttpHandler::httpSuccess item id: " + << titem->getUUID() << LL_ENDL; + items.push_back(titem); + + // examine update for changes. + LLViewerInventoryItem * itemp(gInventory.getItem(titem->getUUID())); + + if (itemp) + { + if (titem->getParentUUID() == itemp->getParentUUID()) + { + update[titem->getParentUUID()]; + } + else + { + ++update[titem->getParentUUID()]; + --update[itemp->getParentUUID()]; + } + } + else + { + ++update[titem->getParentUUID()]; + } + + if (folder_id.isNull()) + { + folder_id = titem->getParentUUID(); + } + } + + // as above, this loop never seems to loop more than once per call + U32 changes(0U); + for (auto& item : items) + { + changes |= gInventory.updateItem(item); + } + // *HUH: Have computed 'changes', nothing uses it. + + gInventory.notifyObservers(); + gViewerWindow->getWindow()->decBusyCount(); +} +//If we get back an error (not found, etc...), handle it here +void LLInventoryModel::FetchItemHttpHandler::httpFailure() +{ + LL_WARNS(LOG_INV) << "FetchItemHttpHandler::error " + << mStatus << ": " << mReason << LL_ENDL; + gInventory.notifyObservers(); +} + diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index a73a1fee61..d81fe7b97e 100644 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -27,33 +27,28 @@ #ifndef LL_LLINVENTORYMODEL_H #define LL_LLINVENTORYMODEL_H +#include +#include +#include +#include + #include "llassettype.h" #include "llfoldertype.h" -#include "lldarray.h" #include "llframetimer.h" #include "llhttpclient.h" #include "lluuid.h" #include "llpermissionsflags.h" +#include "llviewerinventory.h" #include "llstring.h" - #include "llmd5.h" -#include -#include -#include -#include - class AIHTTPTimeoutPolicy; -extern AIHTTPTimeoutPolicy fetchInventoryResponder_timeout; +extern AIHTTPTimeoutPolicy FetchItemHttpHandler_timeout; class LLInventoryObserver; class LLInventoryObject; class LLInventoryItem; class LLInventoryCategory; -class LLViewerInventoryItem; -class LLViewerInventoryCategory; -class LLViewerInventoryItem; -class LLViewerInventoryCategory; class LLMessageSystem; class LLInventoryCollectFunctor; @@ -79,19 +74,21 @@ class LLInventoryModel CHILDREN_MAYBE }; - typedef LLDynamicArray > cat_array_t; - typedef LLDynamicArray > item_array_t; - typedef std::set changed_items_t; + typedef std::vector > cat_array_t; + typedef std::vector > item_array_t; + typedef uuid_set_t changed_items_t; - class fetchInventoryResponder : public LLHTTPClient::ResponderWithResult + class FetchItemHttpHandler : public LLHTTPClient::ResponderWithResult { public: - fetchInventoryResponder(const LLSD& request_sd) : mRequestSD(request_sd) {}; - /*virtual*/ void result(const LLSD& content); - /*virtual*/ void error(U32 status, const std::string& reason); + LOG_CLASS(FetchItemHttpHandler); + + FetchItemHttpHandler(const LLSD& request_sd) : mRequestSD(request_sd) {}; + /*virtual*/ void httpSuccess(void); + /*virtual*/ void httpFailure(void); /*virtual*/ AICapabilityType capability_type(void) const { return cap_inventory; } - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return fetchInventoryResponder_timeout; } - /*virtual*/ char const* getName(void) const { return "fetchInventoryResponder"; } + /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return FetchItemHttpHandler_timeout; } + /*virtual*/ char const* getName(void) const { return "FetchItemHttpHandler"; } protected: LLSD mRequestSD; }; @@ -147,6 +144,8 @@ class LLInventoryModel // during authentication. Returns true if everything parsed. bool loadSkeleton(const LLSD& options, const LLUUID& owner_id); void buildParentChildMap(); // brute force method to rebuild the entire parent-child relations + void createCommonSystemCategories(); + // Call on logout to save a terse representation. void cache(const LLUUID& parent_folder_id, const LLUUID& agent_id); private: @@ -155,16 +154,25 @@ class LLInventoryModel // the inventory using several different identifiers. // mInventory member data is the 'master' list of inventory, and // mCategoryMap and mItemMap store uuid->object mappings. - typedef std::map > cat_map_t; - typedef std::map > item_map_t; + typedef boost::unordered_map > cat_map_t; + typedef boost::unordered_map > item_map_t; cat_map_t mCategoryMap; item_map_t mItemMap; // This last set of indices is used to map parents to children. - typedef std::map parent_cat_map_t; - typedef std::map parent_item_map_t; + typedef boost::unordered_map parent_cat_map_t; + typedef boost::unordered_map parent_item_map_t; parent_cat_map_t mParentChildCategoryTree; parent_item_map_t mParentChildItemTree; + // Track links to items and categories. We do not store item or + // category pointers here, because broken links are also supported. + typedef std::multimap backlink_mmap_t; + backlink_mmap_t mBacklinkMMap; // key = target_id: ID of item, values = link_ids: IDs of item or folder links referencing it. + // For internal use only + bool hasBacklinkInfo(const LLUUID& link_id, const LLUUID& target_id) const; + void addBacklinkInfo(const LLUUID& link_id, const LLUUID& target_id); + void removeBacklinkInfo(const LLUUID& link_id, const LLUUID& target_id); + //-------------------------------------------------------------------- // Login //-------------------------------------------------------------------- @@ -184,14 +192,14 @@ class LLInventoryModel **/ //-------------------------------------------------------------------- - // Descendents + // Descendants //-------------------------------------------------------------------- public: - // Make sure we have the descendents in the structure. Returns true + // Make sure we have the descendants in the structure. Returns true // if a fetch was performed. bool fetchDescendentsOf(const LLUUID& folder_id) const; - // Return the direct descendents of the id provided.Set passed + // Return the direct descendants of the id provided.Set passed // in values to NULL if the call fails. // NOTE: The array provided points straight into the guts of // this object, and should only be used for read operations, since @@ -203,10 +211,10 @@ class LLInventoryModel void getDirectDescendentsOf(const LLUUID& cat_id, cat_array_t*& categories) const; - // Compute a hash of direct descendent names (for detecting child name changes) + // Compute a hash of direct descendant names (for detecting child name changes) LLMD5 hashDirectDescendentNames(const LLUUID& cat_id) const; - // Starting with the object specified, add its descendents to the + // Starting with the object specified, add its descendants to the // array provided, but do not add the inventory object specified // by id. There is no guaranteed order. // NOTE: Neither array will be erased before adding objects to it. @@ -216,38 +224,58 @@ class LLInventoryModel EXCLUDE_TRASH = FALSE, INCLUDE_TRASH = TRUE }; + // Simpler existence test if matches don't actually need to be collected. + bool hasMatchingDirectDescendent(const LLUUID& cat_id, + LLInventoryCollectFunctor& filter, bool follow_folder_links = false); void collectDescendents(const LLUUID& id, cat_array_t& categories, item_array_t& items, BOOL include_trash); +// [RLVa:KB] - Checked: 2013-04-15 (RLVa-1.4.8) void collectDescendentsIf(const LLUUID& id, cat_array_t& categories, item_array_t& items, BOOL include_trash, LLInventoryCollectFunctor& add, - BOOL follow_folder_links = FALSE); + bool follow_folder_links = false); +// [/RLVa:KB] +// void collectDescendentsIf(const LLUUID& id, +// cat_array_t& categories, +// item_array_t& items, +// BOOL include_trash, +// LLInventoryCollectFunctor& add); // Collect all items in inventory that are linked to item_id. // Assumes item_id is itself not a linked item. - item_array_t collectLinkedItems(const LLUUID& item_id, + item_array_t collectLinksTo(const LLUUID& item_id, const LLUUID& start_folder_id = LLUUID::null); // Check if one object has a parent chain up to the category specified by UUID. BOOL isObjectDescendentOf(const LLUUID& obj_id, const LLUUID& cat_id, const BOOL break_on_recursion=FALSE) const; + // Follow parent chain to the top. + bool getObjectTopmostAncestor(const LLUUID& object_id, LLUUID& result) const; + //-------------------------------------------------------------------- // Find //-------------------------------------------------------------------- public: + const LLUUID findCategoryUUIDForTypeInRoot( + LLFolderType::EType preferred_type, + bool create_folder, + const LLUUID& root_id); + // Returns the uuid of the category that specifies 'type' as what it // defaults to containing. The category is not necessarily only for that type. // NOTE: If create_folder is true, this will create a new inventory category // on the fly if one does not exist. *NOTE: if find_in_library is true it // will search in the user's library folder instead of "My Inventory" const LLUUID findCategoryUUIDForType(LLFolderType::EType preferred_type, - bool create_folder = true, - bool find_in_library = false); + bool create_folder = true); + // will search in the user's library folder instead of "My Inventory" + const LLUUID findLibraryCategoryUUIDForType(LLFolderType::EType preferred_type, + bool create_folder = true); // Get whatever special folder this object is a child of, if any. const LLViewerInventoryCategory *getFirstNondefaultParent(const LLUUID& obj_id) const; @@ -275,6 +303,11 @@ class LLInventoryModel LLViewerInventoryItem* getLinkedItem(const LLUUID& object_id) const; LLUUID findCategoryByName(std::string name); + + // Copy content of all folders of type "type" into folder "id" and delete/purge the empty folders + // Note : This method has been designed for FT_OUTBOX (aka Merchant Outbox) but can be used for other categories + void consolidateForType(const LLUUID& id, LLFolderType::EType type); + private: mutable LLPointer mLastItem; // cache recent lookups @@ -304,16 +337,16 @@ class LLInventoryModel // NOTE: In usage, you will want to perform cache accounting // operations in LLInventoryModel::accountForUpdate() or // LLViewerInventoryItem::updateServer() before calling this method. - U32 updateItem(const LLViewerInventoryItem* item); + U32 updateItem(const LLViewerInventoryItem* item, U32 mask = 0); // Change an existing item with the matching id or add - // the category. No notifcation will be sent to observers. This + // the category. No notification will be sent to observers. This // method will only generate network traffic if the item had to be // reparented. // NOTE: In usage, you will want to perform cache accounting // operations in accountForUpdate() or LLViewerInventoryCategory:: // updateServer() before calling this method. - void updateCategory(const LLViewerInventoryCategory* cat); + void updateCategory(const LLViewerInventoryCategory* cat, U32 mask = 0); // Move the specified object id to the specified category and // update the internal structures. No cache accounting, @@ -334,11 +367,31 @@ class LLInventoryModel // Delete //-------------------------------------------------------------------- public: + + // Update model after an AISv3 update received for any operation. + void onAISUpdateReceived(const std::string& context, const LLSD& update); + + // Update model after an item is confirmed as removed from + // server. Works for categories or items. + void onObjectDeletedFromServer(const LLUUID& item_id, + bool fix_broken_links = true, + bool update_parent_version = true, + bool do_notify_observers = true); + + // Update model after all descendants removed from server. + void onDescendentsPurgedFromServer(const LLUUID& object_id, bool fix_broken_links = true); + + // Update model after an existing item gets updated on server. + void onItemUpdated(const LLUUID& item_id, const LLSD& updates, bool update_parent_version); + + // Update model after an existing category gets updated on server. + void onCategoryUpdated(const LLUUID& cat_id, const LLSD& updates); + // Delete a particular inventory object by ID. Will purge one // object from the internal data structures, maintaining a // consistent internal state. No cache accounting, observer // notification, or server update is performed. - void deleteObject(const LLUUID& id); + void deleteObject(const LLUUID& id, bool fix_broken_links = true, bool do_notify_observers = true); /// move Item item_id to Trash void removeItem(const LLUUID& item_id); /// move Category category_id to Trash @@ -346,17 +399,6 @@ class LLInventoryModel /// removeItem() or removeCategory(), whichever is appropriate void removeObject(const LLUUID& object_id); - // Delete a particular inventory object by ID, and delete it from - // the server. Also updates linked items. - void purgeObject(const LLUUID& id); - - // Collects and purges the descendants of the id - // provided. If the category is not found, no action is - // taken. This method goes through the long winded process of - // removing server representation of folders and items while doing - // cache accounting in a fairly efficient manner. This method does - // not notify observers (though maybe it should...) - void purgeDescendentsOf(const LLUUID& id); protected: void updateLinkedObjectsFromPurge(const LLUUID& baseobj_id); @@ -376,15 +418,6 @@ class LLInventoryModel // Returns end() of the vector if not found. static LLInventoryModel::item_array_t::iterator findItemIterByUUID(LLInventoryModel::item_array_t& items, const LLUUID& id); - // Saves current order of the passed items using inventory item sort field. - // Resets 'items' sort fields and saves them on server. - // Is used to save order for Favorites folder. - //void saveItemsOrder(const LLInventoryModel::item_array_t& items); - - // Rearranges Landmarks inside Favorites folder. - // Moves source landmark before target one. - void rearrangeFavoriteLandmarks(const LLUUID& source_item_id, const LLUUID& target_item_id); - //-------------------------------------------------------------------- // Creation //-------------------------------------------------------------------- @@ -394,9 +427,8 @@ class LLInventoryModel LLUUID createNewCategory(const LLUUID& parent_id, LLFolderType::EType preferred_type, const std::string& name, - void (*callback)(const LLSD&, void*) = NULL, - void* user_data = NULL); -public: + boost::optional callback = boost::optional()); +protected: // Internal methods that add inventory and make sure that all of // the internal data structures are consistent. These methods // should be passed pointers of newly created objects, and the @@ -404,14 +436,6 @@ class LLInventoryModel void addCategory(LLViewerInventoryCategory* category); void addItem(LLViewerInventoryItem* item); - // methods to load up inventory skeleton & meat. These are used - // during authentication. return true if everything parsed. - typedef std::map response_t; - typedef std::vector options_t; - - - //OGPX really screwed with the login process. This is needed until it's all sorted out. - bool loadSkeleton(const options_t& options, const LLUUID& owner_id); /** Mutators ** ** *******************************************************************************/ @@ -443,7 +467,7 @@ class LLInventoryModel LLInitializedS32& operator++() { ++mValue; return *this; } LLInitializedS32& operator--() { --mValue; return *this; } }; - typedef std::map update_map_t; + typedef boost::unordered_map update_map_t; // Call when there are category updates. Call them *before* the // actual update so the method can do descendent accounting correctly. @@ -475,11 +499,14 @@ class LLInventoryModel // Call to explicitly update everyone on a new state. void notifyObservers(); + // Allows outsiders to tell the inventory if something has // been changed 'under the hood', but outside the control of the // inventory. The next notify will include that notification. void addChangedMask(U32 mask, const LLUUID& referent); + const changed_items_t& getChangedIDs() const { return mChangedItemIDs; } + const changed_items_t& getAddedIDs() const { return mAddedItemIDs; } protected: // Updates all linked items pointing to this id. void addChangedMaskForLinks(const LLUUID& object_id, U32 mask); @@ -490,6 +517,8 @@ class LLInventoryModel // Variables used to track what has changed since the last notify. U32 mModifyMask; changed_items_t mChangedItemIDs; + changed_items_t mAddedItemIDs; + //-------------------------------------------------------------------- // Observers @@ -526,10 +555,10 @@ class LLInventoryModel // File I/O //-------------------------------------------------------------------- protected: - friend class LLLocalInventory; static bool loadFromFile(const std::string& filename, cat_array_t& categories, item_array_t& items, + changed_items_t& cats_to_update, bool& is_cache_obsolete); static bool saveToFile(const std::string& filename, const cat_array_t& categories, @@ -552,7 +581,7 @@ class LLInventoryModel static void processMoveInventoryItem(LLMessageSystem* msg, void**); static void processFetchInventoryReply(LLMessageSystem* msg, void**); protected: - bool messageUpdateCore(LLMessageSystem* msg, bool do_accounting); + bool messageUpdateCore(LLMessageSystem* msg, bool do_accounting, U32 mask = 0x0); //-------------------------------------------------------------------- // Locks @@ -566,14 +595,16 @@ class LLInventoryModel cat_array_t* getUnlockedCatArray(const LLUUID& id); item_array_t* getUnlockedItemArray(const LLUUID& id); private: - std::map mCategoryLock; - std::map mItemLock; - - + boost::unordered_map mCategoryLock; + boost::unordered_map mItemLock; + + //-------------------------------------------------------------------- + // Debugging + //-------------------------------------------------------------------- public: - // *NOTE: DEBUG functionality void dumpInventory() const; - + bool validate() const; + /** Miscellaneous ** ** *******************************************************************************/ diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp index 6a828db9b2..e3060d226d 100644 --- a/indra/newview/llinventorymodelbackgroundfetch.cpp +++ b/indra/newview/llinventorymodelbackgroundfetch.cpp @@ -40,23 +40,112 @@ #include "hippogridmanager.h" class AIHTTPTimeoutPolicy; -extern AIHTTPTimeoutPolicy inventoryModelFetchDescendentsResponder_timeout; -extern AIHTTPTimeoutPolicy inventoryModelFetchItemResponder_timeout; +extern AIHTTPTimeoutPolicy BGItemHttpHandler_timeout; +extern AIHTTPTimeoutPolicy BGFolderHttpHandler_timeout; const F32 MAX_TIME_FOR_SINGLE_FETCH = 10.f; const S32 MAX_FETCH_RETRIES = 10; + +///---------------------------------------------------------------------------- +/// Class ::BGItemHttpHandler +///---------------------------------------------------------------------------- + +// +// Http request handler class for single inventory item requests. +// +// We'll use a handler-per-request pattern here rather than +// a shared handler. Mainly convenient as this was converted +// from a Responder class model. +// +// Derives from and is identical to the normal FetchItemHttpHandler +// except that: 1) it uses the background request object which is +// updated more slowly than the foreground and 2) keeps a count of +// active requests on the LLInventoryModelBackgroundFetch object +// to indicate outstanding operations are in-flight. +// +class BGItemHttpHandler : public LLInventoryModel::FetchItemHttpHandler +{ + LOG_CLASS(BGItemHttpHandler); + +public: + BGItemHttpHandler(const LLSD & request_sd) + : LLInventoryModel::FetchItemHttpHandler(request_sd) + { + LLInventoryModelBackgroundFetch::instance().incrFetchCount(1); + } + + virtual ~BGItemHttpHandler() + { + LLInventoryModelBackgroundFetch::instance().incrFetchCount(-1); + } + + /*virtual*/ AICapabilityType capability_type(void) const { return cap_inventory; } + /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return BGItemHttpHandler_timeout; } + /*virtual*/ char const* getName(void) const { return "BGItemHttpHandler"; } +protected: + BGItemHttpHandler(const BGItemHttpHandler &); // Not defined + void operator=(const BGItemHttpHandler &); // Not defined +}; + + +///---------------------------------------------------------------------------- +/// Class ::BGFolderHttpHandler +///---------------------------------------------------------------------------- + +// Http request handler class for folders. +// +// Handler for FetchInventoryDescendents2 and FetchLibDescendents2 +// caps requests for folders. +// +class BGFolderHttpHandler : public LLHTTPClient::ResponderWithResult +{ + LOG_CLASS(BGFolderHttpHandler); + +public: + BGFolderHttpHandler(const LLSD & request_sd, const uuid_vec_t & recursive_cats) + : LLHTTPClient::ResponderWithResult(), + mRequestSD(request_sd), + mRecursiveCatUUIDs(recursive_cats) + { + LLInventoryModelBackgroundFetch::instance().incrFetchCount(1); + } + + virtual ~BGFolderHttpHandler() + { + LLInventoryModelBackgroundFetch::instance().incrFetchCount(-1); + } + + /*virtual*/ AICapabilityType capability_type(void) const { return cap_inventory; } + /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return BGFolderHttpHandler_timeout; } + /*virtual*/ char const* getName(void) const { return "BGFolderHttpHandler"; } + +protected: + BGFolderHttpHandler(const BGFolderHttpHandler &); // Not defined + void operator=(const BGFolderHttpHandler &); // Not defined + BOOL getIsRecursive(const LLUUID& cat_id) const; +private: + /*virtual*/ void httpSuccess(void); + /*virtual*/ void httpFailure(void); + LLSD mRequestSD; + uuid_vec_t mRecursiveCatUUIDs; // hack for storing away which cat fetches are recursive +}; + + +const char * const LOG_INV("Inventory"); + + LLInventoryModelBackgroundFetch::LLInventoryModelBackgroundFetch() : mBackgroundFetchActive(FALSE), mFolderFetchActive(false), + mFetchCount(0), mAllFoldersFetched(FALSE), mRecursiveInventoryFetchStarted(FALSE), mRecursiveLibraryFetchStarted(FALSE), mNumFetchRetries(0), mMinTimeBetweenFetches(0.3f), mMaxTimeBetweenFetches(10.f), - mTimelyFetchPending(FALSE), - mFetchCount(0) + mTimelyFetchPending(FALSE) { } @@ -109,12 +198,24 @@ BOOL LLInventoryModelBackgroundFetch::folderFetchActive() const return mFolderFetchActive; } +void LLInventoryModelBackgroundFetch::addRequestAtFront(const LLUUID & id, BOOL recursive, bool is_category) +{ + mFetchQueue.push_front(FetchQueueInfo(id, recursive, is_category)); +} + +void LLInventoryModelBackgroundFetch::addRequestAtBack(const LLUUID & id, BOOL recursive, bool is_category) +{ + mFetchQueue.push_back(FetchQueueInfo(id, recursive, is_category)); +} + void LLInventoryModelBackgroundFetch::start(const LLUUID& id, BOOL recursive) { - LLViewerInventoryCategory* cat = gInventory.getCategory(id); - if (cat || (id.isNull() && !isEverythingFetched())) - { // it's a folder, do a bulk fetch - LL_DEBUGS("InventoryFetch") << "Start fetching category: " << id << ", recursive: " << recursive << LL_ENDL; + LLViewerInventoryCategory * cat(gInventory.getCategory(id)); + + if (cat || (id.isNull() && ! isEverythingFetched())) + { + // it's a folder, do a bulk fetch + LL_DEBUGS(LOG_INV) << "Start fetching category: " << id << ", recursive: " << recursive << LL_ENDL; mFolderFetchActive = true; if (id.isNull()) @@ -181,11 +282,13 @@ void LLInventoryModelBackgroundFetch::setAllFoldersFetched() mAllFoldersFetched = TRUE; } mFolderFetchActive = false; + if (mBackgroundFetchActive) { gIdleCallbacks.deleteFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); - mBackgroundFetchActive = FALSE; } + mBackgroundFetchActive = false; + LL_INFOS(LOG_INV) << "Inventory background fetch completed" << LL_ENDL; } void LLInventoryModelBackgroundFetch::backgroundFetchCB(void *) @@ -193,12 +296,17 @@ void LLInventoryModelBackgroundFetch::backgroundFetchCB(void *) LLInventoryModelBackgroundFetch::instance().backgroundFetch(); } +bool use_http_inventory() +{ + return gHippoGridManager->getConnectedGrid()->isSecondLife() || gSavedSettings.getBOOL("UseHTTPInventory"); +} + void LLInventoryModelBackgroundFetch::backgroundFetch() { LLViewerRegion* region = gAgent.getRegion(); if (mBackgroundFetchActive && region && region->capabilitiesReceived()) { - if (gSavedSettings.getBOOL("UseHTTPInventory")) + if (use_http_inventory()) { // If we'll be using the capability, we'll be sending batches and the background thing isn't as important. std::string url = region->getCapability("FetchInventory2"); @@ -211,7 +319,7 @@ void LLInventoryModelBackgroundFetch::backgroundFetch() std::string servicename = AIPerService::extract_canonical_servicename(url); if (!servicename.empty()) { - llinfos << "Initialized service name for bulk inventory fetching with \"" << servicename << "\"." << llendl; + LL_INFOS() << "Initialized service name for bulk inventory fetching with \"" << servicename << "\"." << LL_ENDL; mPerServicePtr = AIPerService::instance(servicename); mPerServicePtr_initialized = true; } @@ -232,7 +340,7 @@ void LLInventoryModelBackgroundFetch::backgroundFetch() // No more categories to fetch, stop fetch process. if (mFetchQueue.empty()) { - llinfos << "Inventory fetch completed" << llendl; + LL_INFOS() << "Inventory fetch completed" << LL_ENDL; setAllFoldersFetched(); return; @@ -245,7 +353,7 @@ void LLInventoryModelBackgroundFetch::backgroundFetch() // double timeouts on failure mMinTimeBetweenFetches = llmin(mMinTimeBetweenFetches * 2.f, 10.f); mMaxTimeBetweenFetches = llmin(mMaxTimeBetweenFetches * 2.f, 120.f); - lldebugs << "Inventory fetch times grown to (" << mMinTimeBetweenFetches << ", " << mMaxTimeBetweenFetches << ")" << llendl; + LL_DEBUGS() << "Inventory fetch times grown to (" << mMinTimeBetweenFetches << ", " << mMaxTimeBetweenFetches << ")" << LL_ENDL; // fetch is no longer considered "timely" although we will wait for full time-out. mTimelyFetchPending = FALSE; } @@ -317,7 +425,7 @@ void LLInventoryModelBackgroundFetch::backgroundFetch() // Shrink timeouts based on success. mMinTimeBetweenFetches = llmax(mMinTimeBetweenFetches * 0.8f, 0.3f); mMaxTimeBetweenFetches = llmax(mMaxTimeBetweenFetches * 0.8f, 10.f); - lldebugs << "Inventory fetch times shrunk to (" << mMinTimeBetweenFetches << ", " << mMaxTimeBetweenFetches << ")" << llendl; + LL_DEBUGS() << "Inventory fetch times shrunk to (" << mMinTimeBetweenFetches << ", " << mMaxTimeBetweenFetches << ")" << LL_ENDL; } mTimelyFetchPending = FALSE; @@ -380,241 +488,41 @@ void LLInventoryModelBackgroundFetch::backgroundFetch() } } -void LLInventoryModelBackgroundFetch::incrFetchCount(S16 fetching) +void LLInventoryModelBackgroundFetch::incrFetchCount(S32 fetching) { mFetchCount += fetching; if (mFetchCount < 0) { + LL_WARNS_ONCE(LOG_INV) << "Inventory fetch count fell below zero (0)." << LL_ENDL; mFetchCount = 0; } } -class LLInventoryModelFetchItemResponder : public LLInventoryModel::fetchInventoryResponder -{ -public: - LLInventoryModelFetchItemResponder(const LLSD& request_sd) : LLInventoryModel::fetchInventoryResponder(request_sd) {}; - /*virtual*/ void result(const LLSD& content); - /*virtual*/ void error(U32 status, const std::string& reason); - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return inventoryModelFetchItemResponder_timeout; } - /*virtual*/ char const* getName(void) const { return "LLInventoryModelFetchItemResponder"; } -}; - -void LLInventoryModelFetchItemResponder::result( const LLSD& content ) -{ - LLInventoryModel::fetchInventoryResponder::result(content); - LLInventoryModelBackgroundFetch::instance().incrFetchCount(-1); -} - -void LLInventoryModelFetchItemResponder::error( U32 status, const std::string& reason ) -{ - LLInventoryModel::fetchInventoryResponder::error(status, reason); - LLInventoryModelBackgroundFetch::instance().incrFetchCount(-1); -} - -class LLInventoryModelFetchDescendentsResponder : public LLHTTPClient::ResponderWithResult -{ - public: - LLInventoryModelFetchDescendentsResponder(const LLSD& request_sd, uuid_vec_t recursive_cats) : - mRequestSD(request_sd), - mRecursiveCatUUIDs(recursive_cats) - {}; - /*virtual*/ void result(const LLSD& content); - /*virtual*/ void error(U32 status, const std::string& reason); - /*virtual*/ AICapabilityType capability_type(void) const { return cap_inventory; } - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return inventoryModelFetchDescendentsResponder_timeout; } - /*virtual*/ char const* getName(void) const { return "LLInventoryModelFetchDescendentsResponder"; } - -protected: - BOOL getIsRecursive(const LLUUID& cat_id) const; -private: - LLSD mRequestSD; - uuid_vec_t mRecursiveCatUUIDs; // hack for storing away which cat fetches are recursive -}; - -// If we get back a normal response, handle it here. -void LLInventoryModelFetchDescendentsResponder::result(const LLSD& content) -{ - LLInventoryModelBackgroundFetch *fetcher = LLInventoryModelBackgroundFetch::getInstance(); - if (content.has("folders")) - { - - for(LLSD::array_const_iterator folder_it = content["folders"].beginArray(); - folder_it != content["folders"].endArray(); - ++folder_it) - { - LLSD folder_sd = *folder_it; - - - //LLUUID agent_id = folder_sd["agent_id"]; - - //if(agent_id != gAgent.getID()) //This should never happen. - //{ - // llwarns << "Got a UpdateInventoryItem for the wrong agent." - // << llendl; - // break; - //} - - LLUUID parent_id = folder_sd["folder_id"]; - LLUUID owner_id = folder_sd["owner_id"]; - S32 version = (S32)folder_sd["version"].asInteger(); - S32 descendents = (S32)folder_sd["descendents"].asInteger(); - LLPointer tcategory = new LLViewerInventoryCategory(owner_id); - - if (parent_id.isNull()) - { - LLPointer titem = new LLViewerInventoryItem; - for(LLSD::array_const_iterator item_it = folder_sd["items"].beginArray(); - item_it != folder_sd["items"].endArray(); - ++item_it) - { - LLUUID lost_uuid = gInventory.findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); - if (lost_uuid.notNull()) - { - LLSD item = *item_it; - titem->unpackMessage(item); - - LLInventoryModel::update_list_t update; - LLInventoryModel::LLCategoryUpdate new_folder(lost_uuid, 1); - update.push_back(new_folder); - gInventory.accountForUpdate(update); - - titem->setParent(lost_uuid); - titem->updateParentOnServer(FALSE); - gInventory.updateItem(titem); - gInventory.notifyObservers(); - - } - } - } - - LLViewerInventoryCategory* pcat = gInventory.getCategory(parent_id); - if (!pcat) - { - continue; - } - - for(LLSD::array_const_iterator category_it = folder_sd["categories"].beginArray(); - category_it != folder_sd["categories"].endArray(); - ++category_it) - { - LLSD category = *category_it; - tcategory->fromLLSD(category); - - const BOOL recursive = getIsRecursive(tcategory->getUUID()); - - if (recursive) - { - fetcher->mFetchQueue.push_back(LLInventoryModelBackgroundFetch::FetchQueueInfo(tcategory->getUUID(), recursive)); - } - else if ( !gInventory.isCategoryComplete(tcategory->getUUID()) ) - { - gInventory.updateCategory(tcategory); - } - - } - LLPointer titem = new LLViewerInventoryItem; - for(LLSD::array_const_iterator item_it = folder_sd["items"].beginArray(); - item_it != folder_sd["items"].endArray(); - ++item_it) - { - LLSD item = *item_it; - titem->unpackMessage(item); - - gInventory.updateItem(titem); - } - - // set version and descendentcount according to message. - LLViewerInventoryCategory* cat = gInventory.getCategory(parent_id); - if(cat) - { - cat->setVersion(version); - cat->setDescendentCount(descendents); - cat->determineFolderType(); - } - - } - } - - if (content.has("bad_folders")) - { - for(LLSD::array_const_iterator folder_it = content["bad_folders"].beginArray(); - folder_it != content["bad_folders"].endArray(); - ++folder_it) - { - LLSD folder_sd = *folder_it; - - //These folders failed on the dataserver. We probably don't want to retry them. - llinfos << "Folder " << folder_sd["folder_id"].asString() - << "Error: " << folder_sd["error"].asString() << llendl; - } - } - - fetcher->incrFetchCount(-1); - - if (fetcher->isBulkFetchProcessingComplete()) - { - llinfos << "Inventory fetch completed" << llendl; - fetcher->setAllFoldersFetched(); - } - - gInventory.notifyObservers(); -} - -//If we get back an error (not found, etc...), handle it here -void LLInventoryModelFetchDescendentsResponder::error(U32 status, const std::string& reason) -{ - LLInventoryModelBackgroundFetch *fetcher = LLInventoryModelBackgroundFetch::getInstance(); - - llinfos << "LLInventoryModelFetchDescendentsResponder::error " - << status << ": " << reason << llendl; - - fetcher->incrFetchCount(-1); - - if (is_internal_http_error_that_warrants_a_retry(status)) // timed out - { - for(LLSD::array_const_iterator folder_it = mRequestSD["folders"].beginArray(); - folder_it != mRequestSD["folders"].endArray(); - ++folder_it) - { - LLSD folder_sd = *folder_it; - LLUUID folder_id = folder_sd["folder_id"]; - const BOOL recursive = getIsRecursive(folder_id); - fetcher->mFetchQueue.push_front(LLInventoryModelBackgroundFetch::FetchQueueInfo(folder_id, recursive)); - } - } - else - { - if (fetcher->isBulkFetchProcessingComplete()) - { - fetcher->setAllFoldersFetched(); - } - } - gInventory.notifyObservers(); -} - -BOOL LLInventoryModelFetchDescendentsResponder::getIsRecursive(const LLUUID& cat_id) const -{ - return (std::find(mRecursiveCatUUIDs.begin(),mRecursiveCatUUIDs.end(), cat_id) != mRecursiveCatUUIDs.end()); -} - // Bundle up a bunch of requests to send all at once. void LLInventoryModelBackgroundFetch::bulkFetch() { //Background fetch is called from gIdleCallbacks in a loop until background fetch is stopped. //If there are items in mFetchQueue, we want to check the time since the last bulkFetch was //sent. If it exceeds our retry time, go ahead and fire off another batch. - LLViewerRegion* region = gAgent.getRegion(); - if (gDisconnected || !region) return; + LLViewerRegion * region(gAgent.getRegion()); + if (! region || gDisconnected) + { + return; + } + // *TODO: These values could be tweaked at runtime to effect + // a fast/slow fetch throttle. Once login is complete and the scene U32 const max_batch_size = 5; - U32 sort_order = gSavedSettings.getU32(LLInventoryPanel::DEFAULT_SORT_ORDER) & 0x1; + + U32 item_count(0); + U32 folder_count(0); + + const U32 sort_order(gSavedSettings.getU32(LLInventoryPanel::DEFAULT_SORT_ORDER) & 0x1); uuid_vec_t recursive_cats; - U32 folder_count=0; U32 folder_lib_count=0; - U32 item_count=0; U32 item_lib_count=0; // This function can do up to four requests at once. @@ -628,15 +536,26 @@ void LLInventoryModelBackgroundFetch::bulkFetch() LLSD item_request_body; LLSD item_request_body_lib; - while (!mFetchQueue.empty()) + while (! mFetchQueue.empty()) { - const FetchQueueInfo& fetch_info = mFetchQueue.front(); + const FetchQueueInfo & fetch_info(mFetchQueue.front()); if (fetch_info.mIsCategory) { - const LLUUID &cat_id = fetch_info.mUUID; - if (!cat_id.isNull()) + const LLUUID & cat_id(fetch_info.mUUID); + if (cat_id.isNull()) //DEV-17797 + { + LLSD folder_sd; + folder_sd["folder_id"] = LLUUID::null.asString(); + folder_sd["owner_id"] = gAgent.getID(); + folder_sd["sort_order"] = LLSD::Integer(sort_order); + folder_sd["fetch_folders"] = LLSD::Boolean(FALSE); + folder_sd["fetch_items"] = LLSD::Boolean(TRUE); + folder_request_body["folders"].append(folder_sd); + folder_count++; + } + else { - const LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id); + const LLViewerInventoryCategory * cat(gInventory.getCategory(cat_id)); if (cat) { @@ -645,9 +564,9 @@ void LLInventoryModelBackgroundFetch::bulkFetch() LLSD folder_sd; folder_sd["folder_id"] = cat->getUUID(); folder_sd["owner_id"] = cat->getOwnerID(); - folder_sd["sort_order"] = (LLSD::Integer)sort_order; - folder_sd["fetch_folders"] = TRUE; //(LLSD::Boolean)sFullFetchStarted; - folder_sd["fetch_items"] = (LLSD::Boolean)TRUE; + folder_sd["sort_order"] = LLSD::Integer(sort_order); + folder_sd["fetch_folders"] = LLSD::Boolean(TRUE); //(LLSD::Boolean)sFullFetchStarted; + folder_sd["fetch_items"] = LLSD::Boolean(TRUE); if (ALEXANDRIA_LINDEN_ID == cat->getOwnerID()) { @@ -675,8 +594,8 @@ void LLInventoryModelBackgroundFetch::bulkFetch() // May already have this folder, but append child folders to list. if (fetch_info.mRecursive) { - LLInventoryModel::cat_array_t* categories; - LLInventoryModel::item_array_t* items; + LLInventoryModel::cat_array_t * categories(NULL); + LLInventoryModel::item_array_t * items(NULL); gInventory.getDirectDescendentsOf(cat->getUUID(), categories, items); for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin(); it != categories->end(); @@ -686,13 +605,16 @@ void LLInventoryModelBackgroundFetch::bulkFetch() } } } - if (fetch_info.mRecursive) - recursive_cats.push_back(cat_id); + } + if (fetch_info.mRecursive) + { + recursive_cats.push_back(cat_id); } } else { - LLViewerInventoryItem* itemp = gInventory.getItem(fetch_info.mUUID); + LLViewerInventoryItem * itemp(gInventory.getItem(fetch_info.mUUID)); + if (itemp) { LLSD item_sd; @@ -730,45 +652,68 @@ void LLInventoryModelBackgroundFetch::bulkFetch() { if (folder_count) { - std::string url = region->getCapability("FetchInventoryDescendents2"); - llassert(!url.empty()); - ++mFetchCount; - LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(folder_request_body, recursive_cats); - LLHTTPClient::post_approved(url, folder_request_body, fetcher, approved_folder); + if (folder_request_body["folders"].size()) + { + const std::string url(region->getCapability("FetchInventoryDescendents2")); + + if (! url.empty()) + { + BGFolderHttpHandler * handler(new BGFolderHttpHandler(folder_request_body, recursive_cats)); + LLHTTPClient::post_approved(url, folder_request_body, handler, approved_folder); + } + } } if (folder_lib_count) { - std::string url = gAgent.getRegion()->getCapability("FetchLibDescendents2"); - llassert(!url.empty()); - ++mFetchCount; - LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(folder_request_body_lib, recursive_cats); - LLHTTPClient::post_approved(url, folder_request_body_lib, fetcher, approved_folder_lib); + if (folder_request_body_lib["folders"].size()) + { + const std::string url(region->getCapability("FetchLibDescendents2")); + + if (! url.empty()) + { + BGFolderHttpHandler * handler(new BGFolderHttpHandler(folder_request_body_lib, recursive_cats)); + LLHTTPClient::post_approved(url, folder_request_body_lib, handler, approved_folder_lib); + } + } } + if (item_count) { - std::string url = region->getCapability("FetchInventory2"); - llassert(!url.empty()); - ++mFetchCount; - LLSD body; - body["agent_id"] = gAgent.getID(); - body["items"] = item_request_body; - LLHTTPClient::post_approved(url, body, new LLInventoryModelFetchItemResponder(body), approved_item); + if (item_request_body.size()) + { + const std::string url(region->getCapability("FetchInventory2")); + + if (! url.empty()) + { + LLSD body; + body["agent_id"] = gAgent.getID(); + body["items"] = item_request_body; + BGItemHttpHandler * handler(new BGItemHttpHandler(body)); + LLHTTPClient::post_approved(url, body, handler, approved_item); + } + } } if (item_lib_count) { - std::string url = region->getCapability("FetchLib2"); - llassert(!url.empty()); - ++mFetchCount; - LLSD body; - body["agent_id"] = gAgent.getID(); - body["items"] = item_request_body_lib; - LLHTTPClient::post_approved(url, body, new LLInventoryModelFetchItemResponder(body), approved_item_lib); + if (item_request_body_lib.size()) + { + const std::string url(region->getCapability("FetchLib2")); + + if (! url.empty()) + { + LLSD body; + body["agent_id"] = gAgent.getID(); + body["items"] = item_request_body_lib; + BGItemHttpHandler * handler(new BGItemHttpHandler(body)); + LLHTTPClient::post_approved(url, body, handler, approved_item_lib); + } + } } mFetchTimer.reset(); } else if (isBulkFetchProcessingComplete()) { - llinfos << "Inventory fetch completed" << llendl; + LL_INFOS() << "Inventory fetch completed" << LL_ENDL; setAllFoldersFetched(); } } @@ -776,7 +721,8 @@ void LLInventoryModelBackgroundFetch::bulkFetch() bool LLInventoryModelBackgroundFetch::fetchQueueContainsNoDescendentsOf(const LLUUID& cat_id) const { for (fetch_queue_t::const_iterator it = mFetchQueue.begin(); - it != mFetchQueue.end(); ++it) + it != mFetchQueue.end(); + ++it) { const LLUUID& fetch_id = (*it).mUUID; if (gInventory.isObjectDescendentOf(fetch_id, cat_id)) @@ -784,4 +730,172 @@ bool LLInventoryModelBackgroundFetch::fetchQueueContainsNoDescendentsOf(const LL } return true; } +// If we get back a normal response, handle it here. +void BGFolderHttpHandler::httpSuccess(void) +{ + LLInventoryModelBackgroundFetch *fetcher = LLInventoryModelBackgroundFetch::getInstance(); + const LLSD& content = mContent; + // in response as an application-level error. + + // Instead, we assume success and attempt to extract information. + if (content.has("folders")) + { + LLSD folders(content["folders"]); + + for (LLSD::array_const_iterator folder_it = folders.beginArray(); + folder_it != folders.endArray(); + ++folder_it) + { + LLSD folder_sd(*folder_it); + + //LLUUID agent_id = folder_sd["agent_id"]; + + //if(agent_id != gAgent.getID()) //This should never happen. + //{ + // LL_WARNS(LOG_INV) << "Got a UpdateInventoryItem for the wrong agent." + // << LL_ENDL; + // break; + //} + + LLUUID parent_id(folder_sd["folder_id"].asUUID()); + LLUUID owner_id(folder_sd["owner_id"].asUUID()); + S32 version(folder_sd["version"].asInteger()); + S32 descendents(folder_sd["descendents"].asInteger()); + LLPointer tcategory = new LLViewerInventoryCategory(owner_id); + + if (parent_id.isNull()) + { + LLSD items(folder_sd["items"]); + LLPointer titem = new LLViewerInventoryItem; + + for (LLSD::array_const_iterator item_it = items.beginArray(); + item_it != items.endArray(); + ++item_it) + { + const LLUUID lost_uuid(gInventory.findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND)); + + if (lost_uuid.notNull()) + { + LLSD item(*item_it); + + titem->unpackMessage(item); + + LLInventoryModel::update_list_t update; + LLInventoryModel::LLCategoryUpdate new_folder(lost_uuid, 1); + update.push_back(new_folder); + gInventory.accountForUpdate(update); + + titem->setParent(lost_uuid); + titem->updateParentOnServer(FALSE); + gInventory.updateItem(titem); + gInventory.notifyObservers(); + } + } + } + + LLViewerInventoryCategory * pcat(gInventory.getCategory(parent_id)); + if (! pcat) + { + continue; + } + + LLSD categories(folder_sd["categories"]); + for (LLSD::array_const_iterator category_it = categories.beginArray(); + category_it != categories.endArray(); + ++category_it) + { + LLSD category(*category_it); + tcategory->fromLLSD(category); + + const bool recursive(getIsRecursive(tcategory->getUUID())); + if (recursive) + { + fetcher->addRequestAtBack(tcategory->getUUID(), recursive, true); + } + else if (! gInventory.isCategoryComplete(tcategory->getUUID())) + { + gInventory.updateCategory(tcategory); + } + } + + LLSD items(folder_sd["items"]); + LLPointer titem = new LLViewerInventoryItem; + for (LLSD::array_const_iterator item_it = items.beginArray(); + item_it != items.endArray(); + ++item_it) + { + LLSD item(*item_it); + titem->unpackMessage(item); + + gInventory.updateItem(titem); + } + + // Set version and descendentcount according to message. + LLViewerInventoryCategory * cat(gInventory.getCategory(parent_id)); + if (cat) + { + cat->setVersion(version); + cat->setDescendentCount(descendents); + cat->determineFolderType(); + } + } + } + + if (content.has("bad_folders")) + { + LLSD bad_folders(content["bad_folders"]); + for (LLSD::array_const_iterator folder_it = bad_folders.beginArray(); + folder_it != bad_folders.endArray(); + ++folder_it) + { + // *TODO: Stop copying data [ed: this isn't copying data] + LLSD folder_sd(*folder_it); + + // These folders failed on the dataserver. We probably don't want to retry them. + LL_WARNS(LOG_INV) << "Folder " << folder_sd["folder_id"].asString() + << "Error: " << folder_sd["error"].asString() << LL_ENDL; + } + } + + if (fetcher->isBulkFetchProcessingComplete()) + { + LL_INFOS() << "Inventory fetch completed" << LL_ENDL; + fetcher->setAllFoldersFetched(); + } + + gInventory.notifyObservers(); +} + +//If we get back an error (not found, etc...), handle it here +void BGFolderHttpHandler::httpFailure(void) +{ + LLInventoryModelBackgroundFetch *fetcher = LLInventoryModelBackgroundFetch::getInstance(); + + LL_INFOS() << "BGFolderHttpHandler::error " + << mStatus << ": " << mReason << LL_ENDL; + + if (is_internal_http_error_that_warrants_a_retry(mStatus)) // timed out + { + for (auto const& entry : mRequestSD["folders"].array()) + { + LLUUID folder_id(entry["folder_id"].asUUID()); + const BOOL recursive = getIsRecursive(folder_id); + fetcher->addRequestAtFront(folder_id, recursive, true); + } + } + else + { + if (fetcher->isBulkFetchProcessingComplete()) + { + fetcher->setAllFoldersFetched(); + } + } + gInventory.notifyObservers(); +} + +BOOL BGFolderHttpHandler::getIsRecursive(const LLUUID& cat_id) const +{ + return (std::find(mRecursiveCatUUIDs.begin(),mRecursiveCatUUIDs.end(), cat_id) != mRecursiveCatUUIDs.end()); +} + diff --git a/indra/newview/llinventorymodelbackgroundfetch.h b/indra/newview/llinventorymodelbackgroundfetch.h index 4056bdfbdb..a1d85652ab 100644 --- a/indra/newview/llinventorymodelbackgroundfetch.h +++ b/indra/newview/llinventorymodelbackgroundfetch.h @@ -39,8 +39,6 @@ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class LLInventoryModelBackgroundFetch : public LLSingleton { - friend class LLInventoryModelFetchDescendentsResponder; - public: LLInventoryModelBackgroundFetch(); ~LLInventoryModelBackgroundFetch(); @@ -61,16 +59,22 @@ class LLInventoryModelBackgroundFetch : public LLSingletongetUUID(), cats, items); if (!cats || !items) { - llwarns << "Category '" << cat->getName() << "' descendents corrupted, fetch failed." << llendl; + LL_WARNS() << "Category '" << cat->getName() << "' descendents corrupted, fetch failed." << LL_ENDL; // NULL means the call failed -- cats/items map doesn't exist (note: this does NOT mean // that the cat just doesn't have any items or subfolders). // Unrecoverable, so just return done so that this observer can be cleared // from memory. return TRUE; } - const S32 current_num_known_descendents = cats->count() + items->count(); + const S32 current_num_known_descendents = cats->size() + items->size(); // Got the number of descendents that we were expecting, so we're done. if (current_num_known_descendents == expected_num_descendents) @@ -411,7 +412,7 @@ BOOL LLInventoryFetchDescendentsObserver::isCategoryComplete(const LLViewerInven // count and thus the category thinks it has fewer descendents than it actually has. if (current_num_known_descendents >= expected_num_descendents) { - llwarns << "Category '" << cat->getName() << "' expected descendentcount:" << expected_num_descendents << " descendents but got descendentcount:" << current_num_known_descendents << llendl; + LL_WARNS() << "Category '" << cat->getName() << "' expected descendentcount:" << expected_num_descendents << " descendents but got descendentcount:" << current_num_known_descendents << LL_ENDL; const_cast(cat)->setDescendentCount(current_num_known_descendents); return TRUE; } @@ -464,42 +465,13 @@ void LLInventoryFetchComboObserver::startFetch() mFetchItems->startFetch(); mFetchDescendents->startFetch(); } - -void LLInventoryExistenceObserver::watchItem(const LLUUID& id) -{ - if (id.notNull()) - { - mMIA.push_back(id); - } -} - -void LLInventoryExistenceObserver::changed(U32 mask) -{ - // scan through the incomplete items and move or erase them as - // appropriate. - if (!mMIA.empty()) - { - for (uuid_vec_t::iterator it = mMIA.begin(); it < mMIA.end(); ) - { - LLViewerInventoryItem* item = gInventory.getItem(*it); - if (!item) - { - ++it; - continue; - } - mExist.push_back(*it); - it = mMIA.erase(it); - } - if (mMIA.empty()) - { - done(); - } - } -} - +// See comment preceding LLInventoryAddedObserver::changed() for some +// concerns that also apply to this observer. void LLInventoryAddItemByAssetObserver::changed(U32 mask) { - if(!(mask & LLInventoryObserver::ADD)) + if(!(mask & LLInventoryObserver::ADD) || + !(mask & LLInventoryObserver::CREATE) || + !(mask & LLInventoryObserver::UPDATE_CREATE)) { return; } @@ -510,20 +482,12 @@ void LLInventoryAddItemByAssetObserver::changed(U32 mask) return; } - LLMessageSystem* msg = gMessageSystem; - if (!(msg->getMessageName() && (0 == strcmp(msg->getMessageName(), "UpdateCreateInventoryItem")))) - { - // this is not our message - return; // to prevent a crash. EXT-7921; - } - - LLPointer item = new LLViewerInventoryItem; - S32 num_blocks = msg->getNumberOfBlocksFast(_PREHASH_InventoryData); - for(S32 i = 0; i < num_blocks; ++i) + const uuid_set_t& added = gInventory.getAddedIDs(); + for (uuid_set_t::iterator it = added.begin(); it != added.end(); ++it) { - item->unpackMessage(msg, _PREHASH_InventoryData, i); + LLInventoryItem *item = gInventory.getItem(*it); const LLUUID& asset_uuid = item->getAssetUUID(); - if (item->getUUID().notNull() && asset_uuid.notNull()) + if (item && item->getUUID().notNull() && asset_uuid.notNull()) { if (isAssetWatched(asset_uuid)) { @@ -532,11 +496,11 @@ void LLInventoryAddItemByAssetObserver::changed(U32 mask) } } } - + if (mAddedItems.size() == mWatchedAssets.size()) { - done(); LL_DEBUGS("Inventory_Move") << "All watched items are added & processed." << LL_ENDL; + done(); mAddedItems.clear(); // Unable to clean watched items here due to somebody can require to check them in current frame. @@ -566,41 +530,28 @@ bool LLInventoryAddItemByAssetObserver::isAssetWatched( const LLUUID& asset_id ) return std::find(mWatchedAssets.begin(), mWatchedAssets.end(), asset_id) != mWatchedAssets.end(); } +// This observer used to explicitly check for whether it was being +// called as a result of an UpdateCreateInventoryItem message. It has +// now been decoupled enough that it's not actually checking the +// message system, but now we have the special UPDATE_CREATE flag +// being used for the same purpose. Fixing this, as we would need to +// do to get rid of the message, is somewhat subtle because there's no +// particular obvious criterion for when creating a new item should +// trigger this observer and when it shouldn't. For example, creating +// a new notecard with new->notecard causes a preview window to pop up +// via the derived class LLOpenTaskOffer, but creating a new notecard +// by copy and paste does not, solely because one goes through +// UpdateCreateInventoryItem and the other doesn't. void LLInventoryAddedObserver::changed(U32 mask) { - if (!(mask & LLInventoryObserver::ADD)) + if (!(mask & LLInventoryObserver::ADD) || + !(mask & LLInventoryObserver::CREATE) || + !(mask & LLInventoryObserver::UPDATE_CREATE)) { return; } - // *HACK: If this was in response to a packet off - // the network, figure out which item was updated. - LLMessageSystem* msg = gMessageSystem; - - std::string msg_name = msg->getMessageName(); - if (msg_name.empty()) - { - return; - } - - // We only want newly created inventory items. JC - if ( msg_name != "UpdateCreateInventoryItem") - { - return; - } - - LLPointer titem = new LLViewerInventoryItem; - S32 num_blocks = msg->getNumberOfBlocksFast(_PREHASH_InventoryData); - for (S32 i = 0; i < num_blocks; ++i) - { - titem->unpackMessage(msg, _PREHASH_InventoryData, i); - if (!(titem->getUUID().isNull())) - { - //we don't do anything with null keys - mAdded.push_back(titem->getUUID()); - } - } - if (!mAdded.empty()) + if (!gInventory.getAddedIDs().empty()) { done(); } @@ -613,9 +564,9 @@ void LLInventoryCategoryAddedObserver::changed(U32 mask) return; } - const LLInventoryModel::changed_items_t& changed_ids = gInventory.getChangedIDs(); + const LLInventoryModel::changed_items_t& added_ids = gInventory.getChangedIDs(); - for (LLInventoryModel::changed_items_t::const_iterator cit = changed_ids.begin(); cit != changed_ids.end(); ++cit) + for (LLInventoryModel::changed_items_t::const_iterator cit = added_ids.begin(); cit != added_ids.end(); ++cit) { LLViewerInventoryCategory* cat = gInventory.getCategory(*cit); @@ -633,72 +584,29 @@ void LLInventoryCategoryAddedObserver::changed(U32 mask) } } - -LLInventoryTransactionObserver::LLInventoryTransactionObserver(const LLTransactionID& transaction_id) : - mTransactionID(transaction_id) -{ -} - -void LLInventoryTransactionObserver::changed(U32 mask) -{ - if (mask & LLInventoryObserver::ADD) - { - // This could be it - see if we are processing a bulk update - LLMessageSystem* msg = gMessageSystem; - if (msg->getMessageName() - && (0 == strcmp(msg->getMessageName(), "BulkUpdateInventory"))) - { - // we have a match for the message - now check the - // transaction id. - LLUUID id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_TransactionID, id); - if (id == mTransactionID) - { - // woo hoo, we found it - uuid_vec_t folders; - uuid_vec_t items; - S32 count; - count = msg->getNumberOfBlocksFast(_PREHASH_FolderData); - S32 i; - for (i = 0; i < count; ++i) - { - msg->getUUIDFast(_PREHASH_FolderData, _PREHASH_FolderID, id, i); - if (id.notNull()) - { - folders.push_back(id); - } - } - count = msg->getNumberOfBlocksFast(_PREHASH_ItemData); - for (i = 0; i < count; ++i) - { - msg->getUUIDFast(_PREHASH_ItemData, _PREHASH_ItemID, id, i); - if (id.notNull()) - { - items.push_back(id); - } - } - - // call the derived class the implements this method. - done(folders, items); - } - } - } -} - void LLInventoryCategoriesObserver::changed(U32 mask) { if (!mCategoryMap.size()) return; + uuid_vec_t deleted_categories_ids; + for (category_map_t::iterator iter = mCategoryMap.begin(); iter != mCategoryMap.end(); ++iter) { const LLUUID& cat_id = (*iter).first; + LLCategoryData& cat_data = (*iter).second; LLViewerInventoryCategory* category = gInventory.getCategory(cat_id); if (!category) + { + LL_WARNS() << "Category : Category id = " << cat_id << " disappeared" << LL_ENDL; + cat_data.mCallback(); + // Keep track of those deleted categories so we can remove them + deleted_categories_ids.push_back(cat_id); continue; + } const S32 version = category->getVersion(); const S32 expected_num_descendents = category->getDescendentCount(); @@ -714,7 +622,7 @@ void LLInventoryCategoriesObserver::changed(U32 mask) gInventory.getDirectDescendentsOf(cat_id, cats, items); if (!cats || !items) { - llwarns << "Category '" << category->getName() << "' descendents corrupted, fetch failed." << llendl; + LL_WARNS() << "Category '" << category->getName() << "' descendents corrupted, fetch failed." << LL_ENDL; // NULL means the call failed -- cats/items map doesn't exist (note: this does NOT mean // that the cat just doesn't have any items or subfolders). // Unrecoverable, so just skip this category. @@ -724,9 +632,7 @@ void LLInventoryCategoriesObserver::changed(U32 mask) continue; } - const S32 current_num_known_descendents = cats->count() + items->count(); - - LLCategoryData& cat_data = (*iter).second; + const S32 current_num_known_descendents = cats->size() + items->size(); bool cat_changed = false; @@ -757,6 +663,12 @@ void LLInventoryCategoriesObserver::changed(U32 mask) if (cat_changed) cat_data.mCallback(); } + + // Remove deleed categories from the list + for (auto deleted_id = deleted_categories_ids.begin(); deleted_id != deleted_categories_ids.end(); ++deleted_id) + { + removeCategory(*deleted_id); + } } bool LLInventoryCategoriesObserver::addCategory(const LLUUID& cat_id, callback_t cb) @@ -781,7 +693,7 @@ bool LLInventoryCategoriesObserver::addCategory(const LLUUID& cat_id, callback_t gInventory.getDirectDescendentsOf(cat_id, cats, items); if (!cats || !items) { - llwarns << "Category '" << category->getName() << "' descendents corrupted, fetch failed." << llendl; + LL_WARNS() << "Category '" << category->getName() << "' descendents corrupted, fetch failed." << LL_ENDL; // NULL means the call failed -- cats/items map doesn't exist (note: this does NOT mean // that the cat just doesn't have any items or subfolders). // Unrecoverable, so just return "false" meaning that the category can't be observed. @@ -791,7 +703,7 @@ bool LLInventoryCategoriesObserver::addCategory(const LLUUID& cat_id, callback_t } else { - current_num_known_descendents = cats->count() + items->count(); + current_num_known_descendents = cats->size() + items->size(); } } @@ -820,3 +732,23 @@ LLInventoryCategoriesObserver::LLCategoryData::LLCategoryData( { mItemNameHash.finalize(); } + +void LLScrollOnRenameObserver::changed(U32 mask) +{ + if (mask & LLInventoryObserver::LABEL) + { + const uuid_set_t& changed_item_ids = gInventory.getChangedIDs(); + for (uuid_set_t::const_iterator it = changed_item_ids.begin(); it != changed_item_ids.end(); ++it) + { + const LLUUID& id = *it; + if (id == mUUID) + { + mView->scrollToShowSelection(); + + gInventory.removeObserver(this); + delete this; + return; + } + } + } +} diff --git a/indra/newview/llinventoryobserver.h b/indra/newview/llinventoryobserver.h index 13dcd9a12a..afc4bebd09 100644 --- a/indra/newview/llinventoryobserver.h +++ b/indra/newview/llinventoryobserver.h @@ -30,6 +30,7 @@ #include "lluuid.h" #include "llmd5.h" #include +#include #include class LLViewerInventoryCategory; @@ -58,7 +59,10 @@ class LLInventoryObserver GESTURE = 64, REBUILD = 128, // Item UI changed (e.g. item type different) SORT = 256, // Folder needs to be resorted. - DESCRIPTION = 0x10000, // Singu extension to keep track of description changes. + CREATE = 512, // With ADD, item has just been created. + // unfortunately a particular message is still associated with some unique semantics. + UPDATE_CREATE = 1024, // With ADD, item added via UpdateCreateInventoryItem + DESCRIPTION = 2048, // Singu extension to keep track of description changes. ALL = 0xffffffff }; LLInventoryObserver(); @@ -152,25 +156,6 @@ class LLInventoryFetchComboObserver : public LLInventoryObserver LLInventoryFetchDescendentsObserver *mFetchDescendents; }; -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLInventoryExistenceObserver -// -// Used as a base class for doing something when all the -// observed item ids exist in the inventory somewhere. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLInventoryExistenceObserver : public LLInventoryObserver -{ -public: - LLInventoryExistenceObserver() {} - /*virtual*/ void changed(U32 mask); - - void watchItem(const LLUUID& id); -protected: - virtual void done() = 0; - uuid_vec_t mExist; - uuid_vec_t mMIA; -}; - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLInventoryMovedObserver // @@ -193,7 +178,7 @@ class LLInventoryAddItemByAssetObserver : public LLInventoryObserver virtual void onAssetAdded(const LLUUID& asset_id) {} virtual void done() = 0; - typedef std::vector item_ref_t; + typedef uuid_vec_t item_ref_t; item_ref_t mAddedItems; item_ref_t mWatchedAssets; @@ -210,13 +195,11 @@ class LLInventoryAddItemByAssetObserver : public LLInventoryObserver class LLInventoryAddedObserver : public LLInventoryObserver { public: - LLInventoryAddedObserver() : mAdded() {} + LLInventoryAddedObserver() {} /*virtual*/ void changed(U32 mask); protected: virtual void done() = 0; - - uuid_vec_t mAdded; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -241,25 +224,6 @@ class LLInventoryCategoryAddedObserver : public LLInventoryObserver cat_vec_t mAddedCategories; }; -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLInventoryTransactionObserver -// -// Base class for doing something when an inventory transaction completes. -// NOTE: This class is not quite complete. Avoid using unless you fix up its -// functionality gaps. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLInventoryTransactionObserver : public LLInventoryObserver -{ -public: - LLInventoryTransactionObserver(const LLTransactionID& transaction_id); - /*virtual*/ void changed(U32 mask); - -protected: - virtual void done(const uuid_vec_t& folders, const uuid_vec_t& items) = 0; - - LLTransactionID mTransactionID; -}; - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLInventoryCompletionObserver // @@ -293,7 +257,7 @@ class LLInventoryCompletionObserver : public LLInventoryObserver class LLInventoryCategoriesObserver : public LLInventoryObserver { public: - typedef boost::function callback_t; + typedef std::function callback_t; LLInventoryCategoriesObserver() {}; virtual void changed(U32 mask); @@ -321,9 +285,28 @@ class LLInventoryCategoriesObserver : public LLInventoryObserver LLUUID mCatID; }; - typedef std::map category_map_t; + typedef boost::unordered_map category_map_t; typedef category_map_t::value_type category_map_value_t; category_map_t mCategoryMap; }; + +class LLFolderView; + +// Force a FolderView to scroll after an item in the corresponding view has been renamed. +class LLScrollOnRenameObserver: public LLInventoryObserver +{ +public: + LLFolderView *mView; + LLUUID mUUID; + + LLScrollOnRenameObserver(const LLUUID& uuid, LLFolderView *view): + mUUID(uuid), + mView(view) + { + } + /* virtual */ void changed(U32 mask); +}; + + #endif // LL_LLINVENTORYOBSERVERS_H diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index 6d8793a4d3..4cb2bf65fd 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -37,6 +37,7 @@ #include "llfolderview.h" #include "llimview.h" #include "llinventorybridge.h" +#include "llinventoryfilter.h" #include "llinventoryfunctions.h" #include "llinventorymodelbackgroundfetch.h" #include "llviewerfoldertype.h" @@ -44,7 +45,6 @@ #include "llscrollcontainer.h" #include "llviewerassettype.h" #include "llpanelmaininventory.h" -#include "llpanelmarketplaceoutboxinventory.h" #include "llsdserialize.h" @@ -58,7 +58,7 @@ const std::string LLInventoryPanel::DEFAULT_SORT_ORDER = std::string("InventoryS const std::string LLInventoryPanel::RECENTITEMS_SORT_ORDER = std::string("RecentItemsSortOrder"); const std::string LLInventoryPanel::WORNITEMS_SORT_ORDER = std::string("WornItemsSortOrder"); const std::string LLInventoryPanel::INHERIT_SORT_ORDER = std::string(""); -static const LLInventoryFVBridgeBuilder INVENTORY_BRIDGE_BUILDER; +static const LLInventoryFolderViewModelBuilder INVENTORY_BRIDGE_BUILDER; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -72,7 +72,8 @@ class LLInventoryPanelObserver : public LLInventoryObserver public: LLInventoryPanelObserver(LLInventoryPanel* ip) : mIP(ip) {} virtual ~LLInventoryPanelObserver() {} - virtual void changed(U32 mask) + + void changed(U32 mask) override { mIP->modelChanged(mask); } @@ -80,12 +81,6 @@ class LLInventoryPanelObserver : public LLInventoryObserver LLInventoryPanel* mIP; }; - - - - - - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLInvPanelComplObserver // @@ -102,7 +97,7 @@ class LLInventoryPanelObserver : public LLInventoryObserver class LLInvPanelComplObserver : public LLInventoryCompletionObserver { public: - typedef boost::function callback_t; + typedef std::function callback_t; LLInvPanelComplObserver(callback_t cb) : mCallback(cb) @@ -112,7 +107,7 @@ class LLInvPanelComplObserver : public LLInventoryCompletionObserver void reset(); private: - /*virtual*/ void done(); + /*virtual*/ void done() override; /// Called when all the items are complete. callback_t mCallback; @@ -129,9 +124,13 @@ void LLInvPanelComplObserver::done() mCallback(); } +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLInventoryPanel +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + LLInventoryPanel::LLInventoryPanel(const std::string& name, const std::string& sort_order_setting, - const std::string& start_folder, + const LLSD& start_folder, const LLRect& rect, LLInventoryModel* inventory, BOOL allow_multi_select, @@ -139,14 +138,20 @@ LLInventoryPanel::LLInventoryPanel(const std::string& name, LLPanel(name, rect, TRUE), mInventoryObserver(NULL), mCompletionObserver(NULL), - mFolderRoot(NULL), mScroller(NULL), mSortOrderSetting(sort_order_setting), mStartFolder(start_folder), + mShowRootFolder(false), + mShowEmptyMessage(true), + //mShowItemLinkOverlays(false), + mAllowDropOnRoot(true), + mAllowWear(true), + mUseMarketplaceFolders(false), mInventory(inventory), mAllowMultiSelect(allow_multi_select), mViewsInitialized(false), - mInvFVBridgeBuilder(NULL) + mInvFVBridgeBuilder(NULL), + mGroupedItemBridge(new LLFolderViewGroupedItemBridge) { mInvFVBridgeBuilder = &INVENTORY_BRIDGE_BUILDER; @@ -159,39 +164,21 @@ void LLInventoryPanel::buildFolderView() { // Determine the root folder in case specified, and // build the views starting with that folder. - - //std::string start_folder_name(params.start_folder()); - - const LLFolderType::EType preferred_type = LLViewerFolderType::lookupTypeFromNewCategoryName(mStartFolder); - - LLUUID root_id; - - if ("LIBRARY" == mStartFolder) - { - root_id = gInventory.getLibraryRootFolderID(); - } - else - { - root_id = (preferred_type != LLFolderType::FT_NONE) - ? gInventory.findCategoryUUIDForType(preferred_type, false, false) - : gInventory.getCategory(static_cast(mStartFolder)) ? static_cast(mStartFolder) // Singu Note: if start folder is an id of a folder, use it - : LLUUID::null; - } - - if ((root_id == LLUUID::null) && !mStartFolder.empty()) - { - llwarns << "No category found that matches start_folder: " << mStartFolder << llendl; - root_id = LLUUID::generateNewID(); - } + LLUUID root_id = getRootFolderID(); + if (!mStartFolder.has("id")) + mStartFolder["id"] = root_id; // Cache this, so we don't waste time on future getRootFolderID calls LLInvFVBridge* new_listener = mInvFVBridgeBuilder->createBridge(LLAssetType::AT_CATEGORY, - LLAssetType::AT_CATEGORY, + (mUseMarketplaceFolders/*mParams.use_marketplace_folders*/ ? LLAssetType::AT_MARKETPLACE_FOLDER : LLAssetType::AT_CATEGORY), LLInventoryType::IT_CATEGORY, this, NULL, root_id); - mFolderRoot = createFolderView(new_listener, true/*params.use_label_suffix()*/); + LLFolderView* folder_view = createFolderView(new_listener, true/*params.use_label_suffix()*/); + mFolderRoot = folder_view->getHandle(); + + addItemID(root_id, mFolderRoot.get()); } BOOL LLInventoryPanel::postBuild() { @@ -199,16 +186,16 @@ BOOL LLInventoryPanel::postBuild() buildFolderView(); { - // scroller + // Scroller LLRect scroller_view_rect = getRect(); scroller_view_rect.translate(-scroller_view_rect.mLeft, -scroller_view_rect.mBottom); mScroller = new LLScrollContainer(std::string("Inventory Scroller"), scroller_view_rect, - mFolderRoot); + mFolderRoot.get()); mScroller->setFollowsAll(); mScroller->setReserveScrollCorner(TRUE); addChild(mScroller); - mFolderRoot->setScrollContainer(mScroller); + mFolderRoot.get()->setScrollContainer(mScroller); } // Set up the callbacks from the inventory we're viewing, and then build everything. @@ -224,6 +211,7 @@ BOOL LLInventoryPanel::postBuild() { initializeViews(); } + gIdleCallbacks.addFunction(onIdle, (void*)this); if (mSortOrderSetting != INHERIT_SORT_ORDER) @@ -234,30 +222,66 @@ BOOL LLInventoryPanel::postBuild() { setSortOrder(gSavedSettings.getU32(DEFAULT_SORT_ORDER)); } - getFilter()->setFilterEmptySystemFolders(); + + // hide inbox + if (!gSavedSettings.getBOOL("InventoryOutboxMakeVisible")) + { + //getFilter().setFilterCategoryTypes(getFilter().getFilterCategoryTypes() & ~(1ULL << LLFolderType::FT_INBOX)); // Singu Nope! + getFilter().setFilterCategoryTypes(getFilter().getFilterCategoryTypes() & ~(1ULL << LLFolderType::FT_OUTBOX)); + } + // hide marketplace listing box, unless we are a marketplace panel + if (!gSavedSettings.getBOOL("InventoryOutboxMakeVisible") && !mUseMarketplaceFolders/*mParams.use_marketplace_folders*/) + { + getFilter().setFilterCategoryTypes(getFilter().getFilterCategoryTypes() & ~(1ULL << LLFolderType::FT_MARKETPLACE_LISTINGS)); + } + + // set the filter for the empty folder if the debug setting is on + if (gSavedSettings.getBOOL("DebugHideEmptySystemFolders")) + { + getFilter().setFilterEmptySystemFolders(); + } + return LLPanel::postBuild(); } LLInventoryPanel::~LLInventoryPanel() { - if (mFolderRoot) + if (mFolderRoot.get()) { - U32 sort_order = mFolderRoot->getSortOrder(); + U32 sort_order = mFolderRoot.get()->getSortOrder(); if (mSortOrderSetting != INHERIT_SORT_ORDER) { gSavedSettings.setU32(mSortOrderSetting, sort_order); } } + clearFolderRoot(); +} + +void LLInventoryPanel::clearFolderRoot() +{ gIdleCallbacks.deleteFunction(onIdle, this); - // LLView destructor will take care of the sub-views. - mInventory->removeObserver(mInventoryObserver); - mInventory->removeObserver(mCompletionObserver); - delete mInventoryObserver; - delete mCompletionObserver; + if (mInventoryObserver) + { + mInventory->removeObserver(mInventoryObserver); + delete mInventoryObserver; + mInventoryObserver = NULL; + } + + if (mCompletionObserver) + { + mInventory->removeObserver(mCompletionObserver); + delete mCompletionObserver; + mCompletionObserver = NULL; + } - mScroller = NULL; + if (mScroller) + { + removeChild(mScroller); + delete mScroller; + mScroller = NULL; + } } // virtual @@ -267,7 +291,7 @@ LLXMLNodePtr LLInventoryPanel::getXML(bool save_children) const node->setName(LL_INVENTORY_PANEL_TAG); - node->createChild("allow_multi_select", TRUE)->setBoolValue(mFolderRoot->getAllowMultiSelect()); + node->createChild("allow_multi_select", TRUE)->setBoolValue(mFolderRoot.get()->getAllowMultiSelect()); return node; } @@ -277,7 +301,7 @@ class LLInventoryRecentItemsPanel : public LLInventoryPanel public: LLInventoryRecentItemsPanel(const std::string& name, const std::string& sort_order_setting, - const std::string& start_folder, + const LLSD& start_folder, const LLRect& rect, LLInventoryModel* inventory, BOOL allow_multi_select, @@ -287,6 +311,14 @@ class LLInventoryRecentItemsPanel : public LLInventoryPanel LLView* LLInventoryPanel::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) { + std::string filename; + if (node->getAttributeString("filename", filename) && !filename.empty()) + { + LLXMLNodePtr node; + if (LLUICtrlFactory::getLayeredXMLNode(filename, node)) + return factory->createCtrlWidget(static_cast(parent), node); + } + LLInventoryPanel* panel; std::string name("inventory_panel"); @@ -301,22 +333,32 @@ LLView* LLInventoryPanel::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFac std::string sort_order(INHERIT_SORT_ORDER); node->getAttributeString("sort_order", sort_order); - std::string start_folder; - node->getAttributeString("start_folder", start_folder); + LLSD start_folder; + std::string start; + if (node->getAttributeString("start_folder.name", start)) + start_folder["name"] = start; + if (node->getAttributeString("start_folder.id", start)) + start_folder["id"] = LLUUID(start); + if (node->getAttributeString("start_folder.type", start)) + start_folder["type"] = start; - if(name == "Recent Items") + if (name == "Recent Items") panel = new LLInventoryRecentItemsPanel(name, sort_order, start_folder, rect, &gInventory, allow_multi_select, parent); - else if(name == "panel_outbox_inventory") - panel = new LLOutboxInventoryPanel(name, sort_order, start_folder, - rect, &gInventory, - allow_multi_select, parent); else panel = new LLInventoryPanel(name, sort_order, start_folder, rect, &gInventory, allow_multi_select, parent); + // Singu TODO: Turn these into mParams like upstream. + node->getAttribute_bool("show_root_folder", panel->mShowRootFolder); + node->getAttribute_bool("show_empty_message", panel->mShowEmptyMessage); + //node->getAttribute_bool("show_item_link_overlays", panel->mShowItemLinkOverlays); + node->getAttribute_bool("allow_drop_on_root", panel->mAllowDropOnRoot); + node->getAttribute_bool("allow_wear", panel->mAllowWear); + node->getAttribute_bool("use_marketplace_folders", panel->mUseMarketplaceFolders); + panel->initFromXML(node, parent); panel->postBuild(); @@ -327,123 +369,154 @@ LLView* LLInventoryPanel::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFac void LLInventoryPanel::draw() { // Select the desired item (in case it wasn't loaded when the selection was requested) - mFolderRoot->updateSelection(); + updateSelection(); + LLPanel::draw(); } -LLInventoryFilter* LLInventoryPanel::getFilter() +LLInventoryFilter& LLInventoryPanel::getFilter() { - if (mFolderRoot) - { - return mFolderRoot->getFilter(); - } - return NULL; + return mFolderRoot.get()->getFilter(); } -const LLInventoryFilter* LLInventoryPanel::getFilter() const +const LLInventoryFilter& LLInventoryPanel::getFilter() const { - if (mFolderRoot) - { - return mFolderRoot->getFilter(); - } - return NULL; + return mFolderRoot.get()->getFilter(); } void LLInventoryPanel::setFilterTypes(U64 types, LLInventoryFilter::EFilterType filter_type) { if (filter_type == LLInventoryFilter::FILTERTYPE_OBJECT) - getFilter()->setFilterObjectTypes(types); + { + getFilter().setFilterObjectTypes(types); + } if (filter_type == LLInventoryFilter::FILTERTYPE_CATEGORY) - getFilter()->setFilterCategoryTypes(types); + getFilter().setFilterCategoryTypes(types); } U32 LLInventoryPanel::getFilterObjectTypes() const { - return mFolderRoot->getFilterObjectTypes(); + return getFilter().getFilterObjectTypes(); } U32 LLInventoryPanel::getFilterPermMask() const { - return mFolderRoot->getFilterPermissions(); + return getFilter().getFilterPermissions(); } void LLInventoryPanel::setFilterPermMask(PermissionMask filter_perm_mask) { - getFilter()->setFilterPermissions(filter_perm_mask); + getFilter().setFilterPermissions(filter_perm_mask); } void LLInventoryPanel::setFilterWearableTypes(U64 types) { - getFilter()->setFilterWearableTypes(types); + getFilter().setFilterWearableTypes(types); } -void LLInventoryPanel::setFilterWorn(bool worn) +void LLInventoryPanel::setFilterWornItems() { - getFilter()->setFilterWorn(worn); + getFilter().setFilterWornItems(); } void LLInventoryPanel::setFilterSubString(const std::string& string) { - getFilter()->setFilterSubString(string); + if (!getRootFolder()) + return; + + std::string uppercase_search_string = string; + LLStringUtil::toUpper(uppercase_search_string); + const std::string prior_search_string = getFilterSubString(); + + if (prior_search_string == uppercase_search_string) + { + // current filter and new filter match, do nothing + return; + } + + if (string.empty()) + { + // Unlike v3, do not clear other filters. Text is independent. + getFilter().setFilterSubString(LLStringUtil::null); + getRootFolder()->restoreFolderState(); + LLOpenFoldersWithSelection opener; + getRootFolder()->applyFunctorRecursively(opener); + getRootFolder()->scrollToShowSelection(); + } + else + { + if (prior_search_string.empty()) + { + // save current folder open state if no filter currently applied + getRootFolder()->saveFolderState(); + } + // set new filter string + getFilter().setFilterSubString(string); + } } const std::string LLInventoryPanel::getFilterSubString() { - return mFolderRoot->getFilterSubString(); + return getFilter().getFilterSubString(); } - void LLInventoryPanel::setSortOrder(U32 order) { - getFilter()->setSortOrder(order); - if (getFilter()->isModified()) + getFilter().setSortOrder(order); + if (getFilter().isModified()) { - mFolderRoot->setSortOrder(order); + mFolderRoot.get()->setSortOrder(order); // try to keep selection onscreen, even if it wasn't to start with - mFolderRoot->scrollToShowSelection(); + mFolderRoot.get()->scrollToShowSelection(); } } U32 LLInventoryPanel::getSortOrder() const { - return mFolderRoot->getSortOrder(); + return mFolderRoot.get()->getSortOrder(); } void LLInventoryPanel::requestSort() { - mFolderRoot->requestSort(); + mFolderRoot.get()->requestSort(); } void LLInventoryPanel::setSinceLogoff(BOOL sl) { - getFilter()->setDateRangeLastLogoff(sl); + getFilter().setDateRangeLastLogoff(sl); } void LLInventoryPanel::setHoursAgo(U32 hours) { - getFilter()->setHoursAgo(hours); + getFilter().setHoursAgo(hours); } -void LLInventoryPanel::setFilterLinks(U64 filter_links) +void LLInventoryPanel::setDateSearchDirection(U32 direction) { - getFilter()->setFilterLinks(filter_links); + getFilter().setDateSearchDirection(direction); +} + +void LLInventoryPanel::setFilterLinks(LLInventoryFilter::EFilterLink filter_links) +{ + getFilter().setFilterLinks(filter_links); } void LLInventoryPanel::setShowFolderState(LLInventoryFilter::EFolderShow show) { - getFilter()->setShowFolderState(show); + getFilter().setShowFolderState(show); } LLInventoryFilter::EFolderShow LLInventoryPanel::getShowFolderState() { - return getFilter()->getShowFolderState(); + return getFilter().getShowFolderState(); } +// Called when something changed in the global model (new item, item coming through the wire, rename, move, etc...) (CHUI-849) void LLInventoryPanel::modelChanged(U32 mask) { - static LLFastTimer::DeclareTimer FTM_REFRESH("Inventory Refresh"); - LLFastTimer t2(FTM_REFRESH); + static LLTrace::BlockTimerStatHandle FTM_REFRESH("Inventory Refresh"); + LL_RECORD_BLOCK_TIME(FTM_REFRESH); if (!mViewsInitialized) return; @@ -459,11 +532,18 @@ void LLInventoryPanel::modelChanged(U32 mask) { const LLUUID& item_id = (*items_iter); const LLInventoryObject* model_item = model->getObject(item_id); - LLFolderViewItem* view_item = mFolderRoot->getItemByID(item_id); + LLFolderViewItem* view_item = getItemByID(item_id); // LLFolderViewFolder is derived from LLFolderViewItem so dynamic_cast from item // to folder is the fast way to get a folder without searching through folders tree. - LLFolderViewFolder* view_folder = dynamic_cast(view_item); + LLFolderViewFolder* view_folder = NULL; + + // Check requires as this item might have already been deleted + // as a child of its deleted parent. + if (model_item && view_item) + { + view_folder = dynamic_cast(view_item); + } ////////////////////////////// // LABEL Operation @@ -482,6 +562,11 @@ void LLInventoryPanel::modelChanged(U32 mask) } // Singu note: Needed to propagate name change to wearables. view_item->nameOrDescriptionChanged(); + LLFolderViewFolder* parent = view_item->getParentFolder(); + if(parent) + { + parent->requestSort(); + } } } @@ -503,7 +588,9 @@ void LLInventoryPanel::modelChanged(U32 mask) { if (model_item && view_item) { + const LLUUID& idp = view_item->getListener()->getUUID(); view_item->destroyView(); + removeItemID(idp); } view_item = buildNewViews(item_id); view_folder = dynamic_cast(view_item); @@ -547,11 +634,13 @@ void LLInventoryPanel::modelChanged(U32 mask) { // Add the UI element for this item. buildNewViews(item_id); + if (auto parent = getFolderByID(model_item->getParentUUID())) parent->requestSort(); // Select any newly created object that has the auto rename at top of folder root set. - if(mFolderRoot->getRoot()->needsAutoRename()) + if(mFolderRoot.get()->getRoot()->needsAutoRename()) { setSelection(item_id, FALSE); } + //updateFolderLabel(model_item->getParentUUID()); } ////////////////////////////// @@ -559,25 +648,46 @@ void LLInventoryPanel::modelChanged(U32 mask) // This item already exists in both memory and UI. It was probably reparented. else if (model_item && view_item) { + LLFolderViewFolder* old_parent = view_item->getParentFolder(); // Don't process the item if it is the root if (view_item->getRoot() != view_item) { - LLFolderViewFolder* new_parent = (LLFolderViewFolder*)mFolderRoot->getItemByID(model_item->getParentUUID()); + //auto* viewmodel_folder = old_parent->getListener(); + LLFolderViewFolder* new_parent = (LLFolderViewFolder*)getItemByID(model_item->getParentUUID()); // Item has been moved. - if (view_item->getParentFolder() != new_parent) + if (old_parent != new_parent) { if (new_parent != NULL) { // Item is to be moved and we found its new parent in the panel's directory, so move the item's UI. view_item->getParentFolder()->extractItem(view_item); - view_item->addToFolder(new_parent, mFolderRoot); + view_item->addToFolder(new_parent, mFolderRoot.get()); + addItemID(view_item->getListener()->getUUID(), view_item); + if (mInventory) + { + const LLUUID trash_id = mInventory->findCategoryUUIDForType(LLFolderType::FT_TRASH); + if (trash_id != model_item->getParentUUID() && (mask & LLInventoryObserver::INTERNAL) && new_parent->isOpen()) + { + setSelection(item_id, FALSE); + } + } + //updateFolderLabel(model_item->getParentUUID()); } else { + // Remove the item ID before destroying the view because the view-model-item gets + // destroyed when the view is destroyed + removeItemID(view_item->getListener()->getUUID()); + // Item is to be moved outside the panel's directory (e.g. moved to trash for a panel that // doesn't include trash). Just remove the item's UI. view_item->destroyView(); } + /*if(viewmodel_folder) + { + updateFolderLabel(viewmodel_folder->getUUID()); + }*/ + old_parent->requestSort(); } } } @@ -588,17 +698,62 @@ void LLInventoryPanel::modelChanged(U32 mask) else if (!model_item && view_item) { // Remove the item's UI. + LLFolderViewFolder* parent = view_item->getParentFolder(); + removeItemID(view_item->getListener()->getUUID()); view_item->destroyView(); + if(parent) + { + parent->requestSort(); + /*auto* viewmodel_folder = parent->getListener(); + if(viewmodel_folder) + { + updateFolderLabel(viewmodel_folder->getUUID()); + }*/ + } } } } } -LLFolderView* LLInventoryPanel::getRootFolder() -{ - return mFolderRoot; -} +const LLUUID LLInventoryPanel::getRootFolderID() const +{ + LLUUID root_id; + if (mFolderRoot.get() && mFolderRoot.get()->getListener()) + { + root_id = mFolderRoot.get()->getListener()->getUUID(); + } + else + { + if (mStartFolder.has("id")) + { + root_id = mStartFolder["id"]; + } + else + { + LLStringExplicit label(mStartFolder["name"]); + const LLFolderType::EType preferred_type = mStartFolder.has("type") + ? LLFolderType::lookup(mStartFolder["type"]) + : LLViewerFolderType::lookupTypeFromNewCategoryName(label); + if ("LIBRARY" == label) + { + root_id = gInventory.getLibraryRootFolderID(); + } + else if (preferred_type != LLFolderType::FT_NONE) + { + //setLabel(label); + + root_id = gInventory.findCategoryUUIDForType(preferred_type, false); + if (root_id.isNull()) + { + LL_WARNS() << "Could not find folder for " << mStartFolder << LL_ENDL; + root_id.generateNewID(); + } + } + } + } + return root_id; +} // static void LLInventoryPanel::onIdle(void *userdata) @@ -618,10 +773,7 @@ void LLInventoryPanel::onIdle(void *userdata) } } -const LLUUID& LLInventoryPanel::getRootFolderID() const -{ - return mFolderRoot->getListener()->getUUID(); -} + void LLInventoryPanel::initializeViews() { @@ -637,14 +789,14 @@ void LLInventoryPanel::initializeViews() if (gAgent.isFirstLogin()) { // Auto open the user's library - LLFolderViewFolder* lib_folder = mFolderRoot->getFolderByID(gInventory.getLibraryRootFolderID()); + LLFolderViewFolder* lib_folder = getFolderByID(gInventory.getLibraryRootFolderID()); if (lib_folder) { lib_folder->setOpen(TRUE); } // Auto close the user's my inventory folder - LLFolderViewFolder* my_inv_folder = mFolderRoot->getFolderByID(gInventory.getRootFolderID()); + LLFolderViewFolder* my_inv_folder = getFolderByID(gInventory.getRootFolderID()); if (my_inv_folder) { my_inv_folder->setOpenArrangeRecursively(FALSE, LLFolderViewFolder::RECURSE_DOWN); @@ -654,7 +806,7 @@ void LLInventoryPanel::initializeViews() LLFolderViewItem* LLInventoryPanel::rebuildViewsFor(const LLUUID& id) { // Destroy the old view for this ID so we can rebuild it. - LLFolderViewItem* old_view = mFolderRoot->getItemByID(id); + LLFolderViewItem* old_view = mFolderRoot.get()->getItemByID(id); if (old_view) { old_view->destroyView(); @@ -675,19 +827,23 @@ LLFolderView * LLInventoryPanel::createFolderView(LLInvFVBridge * bridge, bool u folder_rect, LLUUID::null, this, - bridge); + bridge, + mGroupedItemBridge); ret->setAllowMultiSelect(mAllowMultiSelect); + ret->setShowEmptyMessage(mShowEmptyMessage); + /*ret->setShowItemLinkOverlays(mShowItemLinkOverlays); + ret->setAllowDropOnRoot(mAllowDropOnRoot);*/ return ret; } -LLFolderViewFolder * LLInventoryPanel::createFolderViewFolder(LLInvFVBridge * bridge) +LLFolderViewFolder * LLInventoryPanel::createFolderViewFolder(LLInvFVBridge* bridge) { return new LLFolderViewFolder( bridge->getDisplayName(), bridge->getIcon(), - bridge->getOpenIcon(), + bridge->getIconOpen(), LLUI::getUIImage("inv_link_overlay.tga"), - mFolderRoot, + mFolderRoot.get(), bridge); } @@ -696,89 +852,115 @@ LLFolderViewItem * LLInventoryPanel::createFolderViewItem(LLInvFVBridge * bridge return new LLFolderViewItem( bridge->getDisplayName(), bridge->getIcon(), - bridge->getOpenIcon(), + bridge->getIconOpen(), LLUI::getUIImage("inv_link_overlay.tga"), bridge->getCreationDate(), - mFolderRoot, + mFolderRoot.get(), bridge); } LLFolderViewItem* LLInventoryPanel::buildNewViews(const LLUUID& id) { - LLInventoryObject const* objectp = gInventory.getObject(id); - LLUUID root_id = mFolderRoot->getListener()->getUUID(); - LLFolderViewFolder* parent_folder = NULL; - LLFolderViewItem* itemp = NULL; - - if (id == root_id) - { - parent_folder = mFolderRoot; - } - else if (objectp) - { - const LLUUID &parent_id = objectp->getParentUUID(); - parent_folder = (LLFolderViewFolder*)mFolderRoot->getItemByID(parent_id); - - if (parent_folder) - { - if (objectp->getType() <= LLAssetType::AT_NONE || - objectp->getType() >= LLAssetType::AT_COUNT) - { - llwarns << "LLInventoryPanel::buildNewViews called with invalid objectp->mType : " - << ((S32) objectp->getType()) << " name " << objectp->getName() << " UUID " << objectp->getUUID() - << llendl; - return NULL; - } - - if ((objectp->getType() == LLAssetType::AT_CATEGORY) && - (objectp->getActualType() != LLAssetType::AT_LINK_FOLDER)) + LLInventoryObject const* objectp = gInventory.getObject(id); + LLFolderViewFolder* parent_folder = mFolderRoot.get(); + LLUUID root_id = parent_folder->getListener()->getUUID(); + LLFolderViewItem* folder_view_item = nullptr; + + if (id != root_id && !objectp) + { + return NULL; + } + + if (objectp) + { + folder_view_item = getItemByID(id); + + const LLUUID& parent_id = objectp->getParentUUID(); + parent_folder = (LLFolderViewFolder*)getItemByID(parent_id); + + // Force the creation of an extra root level folder item if required by the inventory panel (default is "false") + bool allow_drop = true; + bool create_root = false; + if (mShowRootFolder) + { + LLUUID root_id = getRootFolderID(); + if (root_id == id) + { + // We insert an extra level that's seen by the UI but has no influence on the model + parent_folder = dynamic_cast(folder_view_item); + folder_view_item = NULL; + allow_drop = mAllowDropOnRoot; + create_root = true; + } + } + + if (!folder_view_item && parent_folder) + { + if (objectp->getType() <= LLAssetType::AT_NONE || + objectp->getType() >= LLAssetType::AT_COUNT) + { + LL_WARNS() << "LLInventoryPanel::buildNewViews called with invalid objectp->mType : " + << ((S32) objectp->getType()) << " name " << objectp->getName() << " UUID " << objectp->getUUID() + << LL_ENDL; + return NULL; + } + + if ((objectp->getType() == LLAssetType::AT_CATEGORY) && + (objectp->getActualType() != LLAssetType::AT_LINK_FOLDER)) + { + LLInvFVBridge* new_listener = mInvFVBridgeBuilder->createBridge(LLAssetType::AT_CATEGORY, + (mUseMarketplaceFolders ? LLAssetType::AT_MARKETPLACE_FOLDER : LLAssetType::AT_CATEGORY), + LLInventoryType::IT_CATEGORY, + this, + mFolderRoot.get(), + objectp->getUUID()); + if (new_listener) { - LLInvFVBridge* new_listener = mInvFVBridgeBuilder->createBridge(objectp->getType(), - objectp->getType(), - LLInventoryType::IT_CATEGORY, - this, - mFolderRoot, - objectp->getUUID()); - if (new_listener) - { - LLFolderViewFolder* folderp = createFolderViewFolder(new_listener); - if (folderp) - { - folderp->setItemSortOrder(mFolderRoot->getSortOrder()); - } - itemp = folderp; - } - } - else - { - // Build new view for item. - LLInventoryItem* item = (LLInventoryItem*)objectp; - LLInvFVBridge* new_listener = mInvFVBridgeBuilder->createBridge(item->getType(), - item->getActualType(), - item->getInventoryType(), - this, - mFolderRoot, - item->getUUID(), - item->getFlags()); - - if (new_listener) - { - itemp = createFolderViewItem(new_listener); - } - } - - if (itemp) - { - itemp->addToFolder(parent_folder, mFolderRoot); - } + folder_view_item = createFolderViewFolder(new_listener); + if (folder_view_item) + { + static_cast(folder_view_item)->setItemSortOrder(mFolderRoot.get()->getSortOrder()); + folder_view_item->setAllowDrop(allow_drop); + folder_view_item->setAllowWear(mAllowWear); + } + } + } + else + { + // Build new view for item. + LLInventoryItem* item = (LLInventoryItem*)objectp; + LLInvFVBridge* new_listener = mInvFVBridgeBuilder->createBridge(item->getType(), + item->getActualType(), + item->getInventoryType(), + this, + mFolderRoot.get(), + item->getUUID(), + item->getFlags()); + + if (new_listener) + { + folder_view_item = createFolderViewItem(new_listener); + } } + + if (folder_view_item) + { + llassert(parent_folder != NULL); + folder_view_item->addToFolder(parent_folder, mFolderRoot.get()); + addItemID(id, folder_view_item); + // In the case of the root folder been shown, open that folder by default once the widget is created + if (create_root) + { + folder_view_item->setOpen(TRUE); + } + } + } } // If this is a folder, add the children of the folder and recursively add any // child folders. if (id.isNull() - || (objectp - && objectp->getType() == LLAssetType::AT_CATEGORY)) + || (folder_view_item && objectp->getType() == LLAssetType::AT_CATEGORY)) { LLViewerInventoryCategory::cat_array_t* categories; LLViewerInventoryItem::item_array_t* items; @@ -795,7 +977,7 @@ LLFolderViewItem* LLInventoryPanel::buildNewViews(const LLUUID& id) } } - if(items && parent_folder) + if(items) { for (LLViewerInventoryItem::item_array_t::const_iterator item_iter = items->begin(); item_iter != items->end(); @@ -808,14 +990,14 @@ LLFolderViewItem* LLInventoryPanel::buildNewViews(const LLUUID& id) mInventory->unlockDirectDescendentArrays(id); } - return itemp; + return folder_view_item; } // bit of a hack to make sure the inventory is open. void LLInventoryPanel::openStartFolderOrMyInventory() { // Find My Inventory folder and open it up by name - for (LLView *child = mFolderRoot->getFirstChild(); child; child = mFolderRoot->findNextSibling(child)) + for (LLView *child = mFolderRoot.get()->getFirstChild(); child; child = mFolderRoot.get()->findNextSibling(child)) { LLFolderViewFolder *fchild = dynamic_cast(child); if (fchild @@ -828,24 +1010,6 @@ void LLInventoryPanel::openStartFolderOrMyInventory() } } -struct LLConfirmPurgeData -{ - LLUUID mID; - LLInventoryModel* mModel; -}; - -class LLIsNotWorn : public LLInventoryCollectFunctor -{ -public: - LLIsNotWorn() {} - virtual ~LLIsNotWorn() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item) - { - return !gAgentWearables.isWearingItem(item->getUUID()); - } -}; - class LLOpenFolderByID : public LLFolderViewFunctor { public: @@ -862,12 +1026,12 @@ class LLOpenFolderByID : public LLFolderViewFunctor void LLInventoryPanel::onItemsCompletion() { - if (mFolderRoot) mFolderRoot->updateMenu(); + if (mFolderRoot.get()) mFolderRoot.get()->updateMenu(); } void LLInventoryPanel::openSelected() { - LLFolderViewItem* folder_item = mFolderRoot->getCurSelectedItem(); + LLFolderViewItem* folder_item = mFolderRoot.get()->getCurSelectedItem(); if(!folder_item) return; LLInvFVBridge* bridge = (LLInvFVBridge*)folder_item->getListener(); if(!bridge) return; @@ -876,7 +1040,7 @@ void LLInventoryPanel::openSelected() void LLInventoryPanel::unSelectAll() { - mFolderRoot->setSelection(NULL, FALSE, FALSE); + mFolderRoot.get()->setSelection(NULL, FALSE, FALSE); } @@ -885,7 +1049,8 @@ BOOL LLInventoryPanel::handleHover(S32 x, S32 y, MASK mask) BOOL handled = LLView::handleHover(x, y, mask); if(handled) { - if (LLInventoryModelBackgroundFetch::instance().folderFetchActive()) + ECursorType cursor = getWindow()->getCursor(); + if (LLInventoryModelBackgroundFetch::instance().folderFetchActive() && cursor == UI_CURSOR_ARROW) { // replace arrow cursor with arrow and hourglass cursor getWindow()->setCursor(UI_CURSOR_WORKING); @@ -913,14 +1078,14 @@ BOOL LLInventoryPanel::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, // If folder view is empty the (x, y) point won't be in its rect // so the handler must be called explicitly. // but only if was not handled before. See EXT-6746. - if (!handled && !mFolderRoot->hasVisibleChildren()) + if (!handled && mAllowDropOnRoot && !mFolderRoot.get()->hasVisibleChildren()) { - handled = mFolderRoot->handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); + handled = mFolderRoot.get()->handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); } if (handled) { - mFolderRoot->setDragAndDropThisFrame(); + mFolderRoot.get()->setDragAndDropThisFrame(); } } @@ -930,7 +1095,7 @@ BOOL LLInventoryPanel::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, void LLInventoryPanel::onFocusLost() { // inventory no longer handles cut/copy/paste/delete - if (LLEditMenuHandler::gEditMenuHandler == mFolderRoot) + if (LLEditMenuHandler::gEditMenuHandler == mFolderRoot.get()) { LLEditMenuHandler::gEditMenuHandler = NULL; } @@ -941,28 +1106,28 @@ void LLInventoryPanel::onFocusLost() void LLInventoryPanel::onFocusReceived() { // inventory now handles cut/copy/paste/delete - LLEditMenuHandler::gEditMenuHandler = mFolderRoot; + LLEditMenuHandler::gEditMenuHandler = mFolderRoot.get(); LLPanel::onFocusReceived(); } void LLInventoryPanel::openAllFolders() { - mFolderRoot->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_DOWN); - mFolderRoot->arrangeAll(); + mFolderRoot.get()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_DOWN); + mFolderRoot.get()->arrangeAll(); } void LLInventoryPanel::closeAllFolders() { - mFolderRoot->setOpenArrangeRecursively(FALSE, LLFolderViewFolder::RECURSE_DOWN); - mFolderRoot->arrangeAll(); + mFolderRoot.get()->setOpenArrangeRecursively(FALSE, LLFolderViewFolder::RECURSE_DOWN); + mFolderRoot.get()->arrangeAll(); } void LLInventoryPanel::openDefaultFolderForType(LLAssetType::EType type) { LLUUID category_id = mInventory->findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(type)); LLOpenFolderByID opener(category_id); - mFolderRoot->applyFunctorRecursively(opener); + mFolderRoot.get()->applyFunctorRecursively(opener); } void LLInventoryPanel::setSelection(const LLUUID& obj_id, BOOL take_keyboard_focus) @@ -973,20 +1138,21 @@ void LLInventoryPanel::setSelection(const LLUUID& obj_id, BOOL take_keyboard_foc { return; } - mFolderRoot->setSelectionByID(obj_id, take_keyboard_focus); + setSelectionByID(obj_id, take_keyboard_focus); } -void LLInventoryPanel::setSelectCallback(const boost::function& items, BOOL user_action)>& cb) +void LLInventoryPanel::setSelectCallback(const std::function& items, BOOL user_action)>& cb) { - if (mFolderRoot) + if (mFolderRoot.get()) { - mFolderRoot->setSelectCallback(cb); + mFolderRoot.get()->setSelectCallback(cb); } } void LLInventoryPanel::clearSelection() { - mFolderRoot->clearSelection(); + mFolderRoot.get()->clearSelection(); + mSelectThisID.setNull(); } void LLInventoryPanel::onSelectionChange(const std::deque& items, BOOL user_action) @@ -1004,7 +1170,7 @@ void LLInventoryPanel::onSelectionChange(const std::deque& it } } - LLFolderView* fv = getRootFolder(); + LLFolderView* fv = mFolderRoot.get(); if (fv->needsAutoRename()) // auto-selecting a new user-created asset and preparing to rename { fv->setNeedsAutoRename(FALSE); @@ -1045,7 +1211,7 @@ void LLInventoryPanel::createNewItem(const std::string& name, BOOL LLInventoryPanel::getSinceLogoff() { - return getFilter()->isSinceLogoff(); + return getFilter().isSinceLogoff(); } // DEBUG ONLY @@ -1053,16 +1219,16 @@ BOOL LLInventoryPanel::getSinceLogoff() void LLInventoryPanel::dumpSelectionInformation(void* user_data) { LLInventoryPanel* iv = (LLInventoryPanel*)user_data; - iv->mFolderRoot->dumpSelectionInformation(); + iv->mFolderRoot.get()->dumpSelectionInformation(); } // static LLInventoryPanel* LLInventoryPanel::getActiveInventoryPanel(BOOL auto_open) { LLInventoryPanel* res = NULL; - LLInventoryView* floater_inventory = LLInventoryView::getActiveInventory(); + LLPanelMainInventory* floater_inventory = LLPanelMainInventory::getActiveInventory(); if (!floater_inventory) { - llwarns << "Could not find My Inventory floater" << llendl; + LL_WARNS() << "Could not find My Inventory floater" << LL_ENDL; return FALSE; } res = floater_inventory ? floater_inventory->getActivePanel() : NULL; @@ -1080,18 +1246,169 @@ LLInventoryPanel* LLInventoryPanel::getActiveInventoryPanel(BOOL auto_open) res = floater_inventory->getActivePanel(); } + return res; } void LLInventoryPanel::addHideFolderType(LLFolderType::EType folder_type) { - getFilter()->setFilterCategoryTypes(getFilter()->getFilterCategoryTypes() & ~(1ULL << folder_type)); + getFilter().setFilterCategoryTypes(getFilter().getFilterCategoryTypes() & ~(1ULL << folder_type)); } BOOL LLInventoryPanel::getIsHiddenFolderType(LLFolderType::EType folder_type) const { - return !(getFilter()->getFilterCategoryTypes() & (1ULL << folder_type)); + return !(getFilter().getFilterCategoryTypes() & (1ULL << folder_type)); } +void LLInventoryPanel::addItemID( const LLUUID& id, LLFolderViewItem* itemp ) +{ + mItemMap[id] = itemp; +} + +void LLInventoryPanel::removeItemID(const LLUUID& id) +{ + LLInventoryModel::cat_array_t categories; + LLInventoryModel::item_array_t items; + gInventory.collectDescendents(id, categories, items, TRUE); + + mItemMap.erase(id); + + for (LLInventoryModel::cat_array_t::iterator it = categories.begin(), end_it = categories.end(); + it != end_it; + ++it) + { + mItemMap.erase((*it)->getUUID()); +} + + for (LLInventoryModel::item_array_t::iterator it = items.begin(), end_it = items.end(); + it != end_it; + ++it) + { + mItemMap.erase((*it)->getUUID()); + } +} + +//static LLFastTimer::DeclareTimer FTM_GET_ITEM_BY_ID("Get FolderViewItem by ID"); +LLFolderViewItem* LLInventoryPanel::getItemByID(const LLUUID& id) +{ + return mFolderRoot.get()->getItemByID(id); + /* + LLFastTimer mew(FTM_GET_ITEM_BY_ID); + + std::map::iterator map_it; + map_it = mItemMap.find(id); + if (map_it != mItemMap.end()) + { + return map_it->second; + } + + return NULL;*/ +} + +LLFolderViewFolder* LLInventoryPanel::getFolderByID(const LLUUID& id) +{ + return mFolderRoot.get()->getFolderByID(id); +/* + LLFolderViewItem* item = getItemByID(id); + return dynamic_cast(item); +*/ +} + + +void LLInventoryPanel::setSelectionByID( const LLUUID& obj_id, BOOL take_keyboard_focus ) +{ + mFolderRoot.get()->setSelectionByID(obj_id, take_keyboard_focus); + /* + LLFolderViewItem* itemp = getItemByID(obj_id); + if(itemp && itemp->getListener()) + { + itemp->arrangeAndSet(TRUE, take_keyboard_focus); + mSelectThisID.setNull(); + return; + } + else + { + // save the desired item to be selected later (if/when ready) + mSelectThisID = obj_id; + }*/ +} + +void LLInventoryPanel::updateSelection() +{ + mFolderRoot.get()->updateSelection(); +/* + if (mSelectThisID.notNull()) + { + setSelectionByID(mSelectThisID, false); + } +*/ +} + +namespace LLInventoryAction +{ + bool doToSelected(LLFolderView* root, std::string action, BOOL user_confirm = TRUE); +} + +void LLInventoryPanel::doToSelected(const LLSD& userdata) +{ + LLInventoryAction::doToSelected(mFolderRoot.get(), userdata.asString()); + + return; +} + +BOOL LLInventoryPanel::handleKeyHere( KEY key, MASK mask ) +{ + /* + BOOL handled = FALSE; + switch (key) + { + case KEY_RETURN: + // Open selected items if enter key hit on the inventory panel + if (mask == MASK_NONE) + { + LLInventoryAction::doToSelected(mFolderRoot.get(), "open"); + handled = TRUE; + } + break; + case KEY_DELETE: + case KEY_BACKSPACE: + // Delete selected items if delete or backspace key hit on the inventory panel + // Note: on Mac laptop keyboards, backspace and delete are one and the same + if (isSelectionRemovable() && (mask == MASK_NONE)) + { + LLInventoryAction::doToSelected(mFolderRoot.get(), "delete"); + handled = TRUE; + } + break; + }*/ + return LLPanel::handleKeyHere(key, mask); +} + +bool LLInventoryPanel::isSelectionRemovable() +{ + bool can_delete = false; + if (mFolderRoot.get()) + { + auto selection_set = mFolderRoot.get()->getSelectionList(); + if (!selection_set.empty()) + { + can_delete = true; + for (const auto& id : selection_set) + { + LLFolderViewItem *item = getItemByID(id); + const LLFolderViewEventListener* listener =item->getListener(); + if (!listener) + { + can_delete = false; + } + else + { + can_delete &= listener->isItemRemovable() && !listener->isItemInTrash(); + } + } + } + } + return can_delete; +} /************************************************************************/ /* Recent Inventory Panel related class */ @@ -1102,13 +1419,14 @@ static const LLRecentInventoryBridgeBuilder RECENT_ITEMS_BUILDER; LLInventoryRecentItemsPanel:: LLInventoryRecentItemsPanel(const std::string& name, const std::string& sort_order_setting, - const std::string& start_folder, + const LLSD& start_folder, const LLRect& rect, LLInventoryModel* inventory, BOOL allow_multi_select, LLView *parent_view) : - LLInventoryPanel(name, sort_order_setting, start_folder,rect,inventory,allow_multi_select,parent_view) + LLInventoryPanel(name, sort_order_setting,start_folder,rect,inventory,allow_multi_select,parent_view) { + // replace bridge builder to have necessary View bridges. mInvFVBridgeBuilder = &RECENT_ITEMS_BUILDER; } diff --git a/indra/newview/llinventorypanel.h b/indra/newview/llinventorypanel.h index 5a858143ab..524710b67e 100644 --- a/indra/newview/llinventorypanel.h +++ b/indra/newview/llinventorypanel.h @@ -1,6 +1,6 @@ /** - * @file llinventoryview.h - * @brief LLInventoryView, LLInventoryFolder, and LLInventoryItem + * @file llinventorypanel.h + * @brief LLInventoryPanel * class definition * * $LicenseInfo:firstyear=2001&license=viewergpl$ @@ -35,7 +35,6 @@ #define LL_LLINVENTORYPANEL_H #include "llassetstorage.h" -#include "lldarray.h" #include "llfloater.h" #include "llinventory.h" #include "llfolderview.h" @@ -53,7 +52,7 @@ class LLFolderViewItem; class LLInventoryFilter; class LLInventoryModel; class LLInvFVBridge; -class LLInventoryFVBridgeBuilder; +class LLInventoryFolderViewModelBuilder; class LLMenuBarGL; class LLCheckBoxCtrl; class LLSpinCtrl; @@ -62,14 +61,41 @@ class LLTextBox; class LLIconCtrl; class LLSaveFolderState; class LLInvPanelComplObserver; +class LLFolderViewGroupedItemBridge; class LLInventoryPanel : public LLPanel { + //-------------------------------------------------------------------- + // Data + //-------------------------------------------------------------------- +public: + struct Filter : public LLInitParam::Block + { + Optional sort_order; + Optional types; + Optional search_string; + + Filter() + : sort_order("sort_order"), + types("types", 0xffffffff), + search_string("search_string") + {} + }; + + struct InventoryState : public LLInitParam::Block + { + Mandatory filter; + //Mandatory sort; + }; + + //-------------------------------------------------------------------- + // Initialization + //-------------------------------------------------------------------- protected: friend class LFFloaterInvPanel; LLInventoryPanel(const std::string& name, const std::string& sort_order_setting, - const std::string& start_folder, + const LLSD& start_folder, const LLRect& rect, LLInventoryModel* inventory, BOOL allow_multi_select, @@ -87,6 +113,7 @@ class LLInventoryPanel : public LLPanel // LLView methods void draw(); + /*virtual*/ BOOL handleKeyHere( KEY key, MASK mask ); BOOL handleHover(S32 x, S32 y, MASK mask); BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, @@ -102,10 +129,11 @@ class LLInventoryPanel : public LLPanel void closeAllFolders(); void openDefaultFolderForType(LLAssetType::EType); void setSelection(const LLUUID& obj_id, BOOL take_keyboard_focus); - void setSelectCallback(const boost::function& items, BOOL user_action)>& cb); + void setSelectCallback(const std::function& items, BOOL user_action)>& cb); void clearSelection(); - LLInventoryFilter* getFilter(); - const LLInventoryFilter* getFilter() const; + bool isSelectionRemovable(); + LLInventoryFilter& getFilter(); + const LLInventoryFilter& getFilter() const; void setFilterTypes(U64 filter, LLInventoryFilter::EFilterType = LLInventoryFilter::FILTERTYPE_OBJECT); U32 getFilterObjectTypes() const; void setFilterPermMask(PermissionMask filter_perm_mask); @@ -113,25 +141,29 @@ class LLInventoryPanel : public LLPanel void setFilterWearableTypes(U64 filter); void setFilterSubString(const std::string& string); const std::string getFilterSubString(); - void setFilterWorn(bool worn); - bool getFilterWorn() const { return mFolderRoot->getFilterWorn(); } - + void setFilterWornItems(); + void setSinceLogoff(BOOL sl); void setHoursAgo(U32 hours); + void setDateSearchDirection(U32 direction); BOOL getSinceLogoff(); - void setFilterLinks(U64 filter_links); + void setFilterLinks(LLInventoryFilter::EFilterLink filter_links); void setShowFolderState(LLInventoryFilter::EFolderShow show); LLInventoryFilter::EFolderShow getShowFolderState(); - void setAllowMultiSelect(BOOL allow) { mFolderRoot->setAllowMultiSelect(allow); } + void setAllowMultiSelect(BOOL allow) { mFolderRoot.get()->setAllowMultiSelect(allow); } // This method is called when something has changed about the inventory. void modelChanged(U32 mask); - LLFolderView* getRootFolder(); + LLFolderView* getRootFolder() { return mFolderRoot.get(); } LLScrollContainer* getScrollableContainer() { return mScroller; } + bool getAllowDropOnRoot() const { return mAllowDropOnRoot; } void onSelectionChange(const std::deque &items, BOOL user_action); LLHandle getInventoryPanelHandle() const { return getDerivedHandle(); } + + // Callbacks + void doToSelected(const LLSD& userdata); // DEBUG ONLY: static void dumpSelectionInformation(void* user_data); @@ -155,26 +187,39 @@ class LLInventoryPanel : public LLPanel LLInventoryType::EType inv_type, U32 next_owner_perm = 0); + void addItemID(const LLUUID& id, LLFolderViewItem* itemp); + void removeItemID(const LLUUID& id); + LLFolderViewItem* getItemByID(const LLUUID& id); + LLFolderViewFolder* getFolderByID(const LLUUID& id); + void setSelectionByID(const LLUUID& obj_id, BOOL take_keyboard_focus); + void updateSelection(); + + // Clean up stuff when the folder root gets deleted + void clearFolderRoot(); + protected: void openStartFolderOrMyInventory(); // open the first level of inventory void onItemsCompletion(); // called when selected items are complete + LLUUID mSelectThisID; LLInventoryModel* mInventory; LLInventoryObserver* mInventoryObserver; LLInvPanelComplObserver* mCompletionObserver; - - BOOL mAllowMultiSelect; - LLFolderView* mFolderRoot; + bool mAllowMultiSelect; + + LLHandle mFolderRoot; LLScrollContainer* mScroller; + LLPointer mGroupedItemBridge; + boost::unordered_map mItemMap; /** - * Pointer to LLInventoryFVBridgeBuilder. + * Pointer to LLInventoryFolderViewModelBuilder. * * It is set in LLInventoryPanel's constructor and can be overridden in derived classes with * another implementation. * Take into account it will not be deleted by LLInventoryPanel itself. */ - const LLInventoryFVBridgeBuilder* mInvFVBridgeBuilder; + const LLInventoryFolderViewModelBuilder* mInvFVBridgeBuilder; //-------------------------------------------------------------------- @@ -191,7 +236,13 @@ class LLInventoryPanel : public LLPanel void requestSort(); private: - const std::string mStartFolder; + LLSD mStartFolder; + bool mShowRootFolder; + bool mShowEmptyMessage; + //bool mShowItemLinkOverlays; + bool mAllowDropOnRoot; + bool mAllowWear; + bool mUseMarketplaceFolders; const std::string mSortOrderSetting; //-------------------------------------------------------------------- @@ -202,7 +253,7 @@ class LLInventoryPanel : public LLPanel public: BOOL getIsViewsInitialized() const { return mViewsInitialized; } - const LLUUID& getRootFolderID() const; + const LLUUID getRootFolderID() const; protected: // Builds the UI. Call this once the inventory is usable. void initializeViews(); @@ -218,10 +269,7 @@ class LLInventoryPanel : public LLPanel BOOL mViewsInitialized; // Views have been generated }; -class LLInventoryView; - - - +class LLPanelMainInventory; ///---------------------------------------------------------------------------- /// Function declarations, constants, enums, and typedefs @@ -230,7 +278,7 @@ class LLInventoryView; // useful functions with the inventory view // *FIX: move these methods. -void init_inventory_actions(LLInventoryView *floater); +void init_inventory_actions(LLPanelMainInventory *floater); void init_inventory_panel_actions(LLInventoryPanel *panel); class LLInventoryCategory; @@ -245,6 +293,3 @@ const BOOL TAKE_FOCUS_YES = TRUE; const BOOL TAKE_FOCUS_NO = FALSE; #endif // LL_LLINVENTORYPANEL_H - - - diff --git a/indra/newview/lljoystickbutton.cpp b/indra/newview/lljoystickbutton.cpp index c33667061d..2c1698538f 100644 --- a/indra/newview/lljoystickbutton.cpp +++ b/indra/newview/lljoystickbutton.cpp @@ -119,7 +119,7 @@ void LLJoystick::updateSlop() break; default: - llerrs << "LLJoystick::LLJoystick() - bad switch case" << llendl; + LL_ERRS() << "LLJoystick::LLJoystick() - bad switch case" << LL_ENDL; break; } @@ -129,7 +129,7 @@ void LLJoystick::updateSlop() BOOL LLJoystick::handleMouseDown(S32 x, S32 y, MASK mask) { - //llinfos << "joystick mouse down " << x << ", " << y << llendl; + //LL_INFOS() << "joystick mouse down " << x << ", " << y << LL_ENDL; mLastMouse.set(x, y); mFirstMouse.set(x, y); @@ -141,7 +141,7 @@ BOOL LLJoystick::handleMouseDown(S32 x, S32 y, MASK mask) BOOL LLJoystick::handleMouseUp(S32 x, S32 y, MASK mask) { - // llinfos << "joystick mouse up " << x << ", " << y << llendl; + // LL_INFOS() << "joystick mouse up " << x << ", " << y << LL_ENDL; if( hasMouseCapture() ) { @@ -265,7 +265,7 @@ void LLJoystickAgentTurn::onHeldDown() F32 time = getElapsedHeldDownTime(); updateSlop(); - //llinfos << "move forward/backward (and/or turn)" << llendl; + //LL_INFOS() << "move forward/backward (and/or turn)" << LL_ENDL; S32 dx = mLastMouse.mX - mFirstMouse.mX + mInitialOffset.mX; S32 dy = mLastMouse.mY - mFirstMouse.mY + mInitialOffset.mY; @@ -393,7 +393,7 @@ void LLJoystickAgentSlide::onMouseUp() void LLJoystickAgentSlide::onHeldDown() { - //llinfos << "slide left/right (and/or move forward/backward)" << llendl; + //LL_INFOS() << "slide left/right (and/or move forward/backward)" << LL_ENDL; updateSlop(); @@ -592,7 +592,7 @@ F32 LLJoystickCameraRotate::getOrbitRate() if( time < NUDGE_TIME ) { F32 rate = ORBIT_NUDGE_RATE + time * (1 - ORBIT_NUDGE_RATE)/ NUDGE_TIME; - //llinfos << rate << llendl; + //LL_INFOS() << rate << LL_ENDL; return rate; } else @@ -661,7 +661,7 @@ void LLJoystickCameraRotate::drawRotatedImage( LLTexture* image, S32 rotations ) gGL.color4fv(UI_VERTEX_COLOR.mV); - gGL.begin(LLRender::QUADS); + gGL.begin(LLRender::TRIANGLE_STRIP); { gGL.texCoord2fv( uv[ (rotations + 0) % 4]); gGL.vertex2i(width, height ); @@ -669,11 +669,11 @@ void LLJoystickCameraRotate::drawRotatedImage( LLTexture* image, S32 rotations ) gGL.texCoord2fv( uv[ (rotations + 1) % 4]); gGL.vertex2i(0, height ); - gGL.texCoord2fv( uv[ (rotations + 2) % 4]); - gGL.vertex2i(0, 0); - gGL.texCoord2fv( uv[ (rotations + 3) % 4]); gGL.vertex2i(width, 0); + + gGL.texCoord2fv( uv[ (rotations + 2) % 4]); + gGL.vertex2i(0, 0); } gGL.end(); } @@ -852,7 +852,7 @@ void LLJoystickCameraZoom::updateSlop() break; default: - llerrs << "LLJoystick::LLJoystick() - bad switch case" << llendl; + LL_ERRS() << "LLJoystick::LLJoystick() - bad switch case" << LL_ENDL; break; } @@ -866,7 +866,7 @@ F32 LLJoystickCameraZoom::getOrbitRate() if( time < NUDGE_TIME ) { F32 rate = ORBIT_NUDGE_RATE + time * (1 - ORBIT_NUDGE_RATE)/ NUDGE_TIME; -// llinfos << "rate " << rate << " time " << time << llendl; +// LL_INFOS() << "rate " << rate << " time " << time << LL_ENDL; return rate; } else diff --git a/indra/newview/lllandmarkactions.cpp b/indra/newview/lllandmarkactions.cpp new file mode 100644 index 0000000000..7652164d9b --- /dev/null +++ b/indra/newview/lllandmarkactions.cpp @@ -0,0 +1,422 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +/** +* @file lllandmarkactions.cpp +* @brief LLLandmarkActions class implementation +* +* $LicenseInfo:firstyear=2001&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2010, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#include "llviewerprecompiledheaders.h" +#include "lllandmarkactions.h" + +#include "roles_constants.h" + +#include "llinventory.h" +#include "llinventoryfunctions.h" +#include "lllandmark.h" +#include "llparcel.h" +#include "llregionhandle.h" + +#include "llnotificationsutil.h" + +#include "llagent.h" +#include "llagentui.h" +#include "llinventorymodel.h" +#include "lllandmarklist.h" +#include "llslurl.h" +#include "llstring.h" +#include "llviewerinventory.h" +#include "llviewerparcelmgr.h" +#include "llworldmapmessage.h" +#include "llviewerwindow.h" +#include "llwindow.h" +#include "llworldmap.h" + +void copy_slurl_to_clipboard_callback(const std::string& slurl); + +class LLFetchlLandmarkByPos : public LLInventoryCollectFunctor +{ +private: + LLVector3d mPos; +public: + LLFetchlLandmarkByPos(const LLVector3d& pos) : + mPos(pos) + {} + + bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) override + { + if (!item || item->getType() != LLAssetType::AT_LANDMARK) + return false; + + LLLandmark* landmark = gLandmarkList.getAsset(item->getAssetUUID()); + if (!landmark) // the landmark not been loaded yet + return false; + + LLVector3d landmark_global_pos; + if (!landmark->getGlobalPos(landmark_global_pos)) + return false; + //we have to round off each coordinates to compare positions properly + return ll_round(mPos.mdV[VX]) == ll_round(landmark_global_pos.mdV[VX]) + && ll_round(mPos.mdV[VY]) == ll_round(landmark_global_pos.mdV[VY]) + && ll_round(mPos.mdV[VZ]) == ll_round(landmark_global_pos.mdV[VZ]); + } +}; + +class LLFetchLandmarksByName : public LLInventoryCollectFunctor +{ +private: + std::string name; + BOOL use_substring; + //this member will be contain copy of founded items to keep the result unique + std::set check_duplicate; + +public: +LLFetchLandmarksByName(std::string &landmark_name, BOOL if_use_substring) +:name(landmark_name), +use_substring(if_use_substring) + { + LLStringUtil::toLower(name); + } + +public: + bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) override + { + if (!item || item->getType() != LLAssetType::AT_LANDMARK) + return false; + + LLLandmark* landmark = gLandmarkList.getAsset(item->getAssetUUID()); + if (!landmark) // the landmark not been loaded yet + return false; + + bool acceptable = false; + std::string landmark_name = item->getName(); + LLStringUtil::toLower(landmark_name); + if(use_substring) + { + acceptable = landmark_name.find( name ) != std::string::npos; + } + else + { + acceptable = landmark_name == name; + } + if(acceptable){ + if(check_duplicate.find(landmark_name) != check_duplicate.end()){ + // we have duplicated items in landmarks + acceptable = false; + }else{ + check_duplicate.insert(landmark_name); + } + } + + return acceptable; + } +}; + +// Returns true if the given inventory item is a landmark pointing to the current parcel. +// Used to find out if there is at least one landmark from current parcel. +class LLFirstAgentParcelLandmark : public LLInventoryCollectFunctor +{ +private: + bool mFounded;// to avoid unnecessary check + +public: + LLFirstAgentParcelLandmark(): mFounded(false){} + + bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) override + { + if (mFounded || !item || item->getType() != LLAssetType::AT_LANDMARK) + return false; + + LLLandmark* landmark = gLandmarkList.getAsset(item->getAssetUUID()); + if (!landmark) // the landmark not been loaded yet + return false; + + LLVector3d landmark_global_pos; + if (!landmark->getGlobalPos(landmark_global_pos)) + return false; + mFounded = LLViewerParcelMgr::getInstance()->inAgentParcel(landmark_global_pos); + return mFounded; + } +}; + +static void fetch_landmarks(LLInventoryModel::cat_array_t& cats, + LLInventoryModel::item_array_t& items, + LLInventoryCollectFunctor& add) +{ + // Look in "My Favorites" + const LLUUID favorites_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE); + gInventory.collectDescendentsIf(favorites_folder_id, + cats, + items, + LLInventoryModel::EXCLUDE_TRASH, + add); + + // Look in "Landmarks" + const LLUUID landmarks_folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK); + gInventory.collectDescendentsIf(landmarks_folder_id, + cats, + items, + LLInventoryModel::EXCLUDE_TRASH, + add); +} + +LLInventoryModel::item_array_t LLLandmarkActions::fetchLandmarksByName(std::string& name, BOOL use_substring) +{ + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + LLFetchLandmarksByName by_name(name, use_substring); + fetch_landmarks(cats, items, by_name); + + return items; +} + +bool LLLandmarkActions::landmarkAlreadyExists() +{ + // Determine whether there are landmarks pointing to the current global agent position. + return findLandmarkForAgentPos() != nullptr; +} + +//static +bool LLLandmarkActions::hasParcelLandmark() +{ + LLFirstAgentParcelLandmark get_first_agent_landmark; + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + fetch_landmarks(cats, items, get_first_agent_landmark); + return !items.empty(); + +} + +// *TODO: This could be made more efficient by only fetching the FIRST +// landmark that meets the criteria +LLViewerInventoryItem* LLLandmarkActions::findLandmarkForGlobalPos(const LLVector3d &pos) +{ + // Determine whether there are landmarks pointing to the current parcel. + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + LLFetchlLandmarkByPos is_current_pos_landmark(pos); + fetch_landmarks(cats, items, is_current_pos_landmark); + + return (items.empty()) ? nullptr : items[0]; +} + +LLViewerInventoryItem* LLLandmarkActions::findLandmarkForAgentPos() +{ + return findLandmarkForGlobalPos(gAgent.getPositionGlobal()); +} + +bool LLLandmarkActions::canCreateLandmarkHere() +{ + LLParcel* agent_parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + if(!agent_parcel) + { + LL_WARNS() << "No agent region" << LL_ENDL; + return false; + } + if (agent_parcel->getAllowLandmark() + || LLViewerParcelMgr::isParcelOwnedByAgent(agent_parcel, GP_LAND_ALLOW_LANDMARK)) + { + return true; + } + + return false; +} + +void LLLandmarkActions::createLandmarkHere( + const std::string& name, + const std::string& desc, + const LLUUID& folder_id) +{ + if(!gAgent.getRegion()) + { + LL_WARNS() << "No agent region" << LL_ENDL; + return; + } + LLParcel* agent_parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + if (!agent_parcel) + { + LL_WARNS() << "No agent parcel" << LL_ENDL; + return; + } + if (!canCreateLandmarkHere()) + { + LLNotificationsUtil::add("CannotCreateLandmarkNotOwner"); + return; + } + + create_inventory_item(gAgent.getID(), gAgent.getSessionID(), + folder_id, LLTransactionID::tnull, + name, desc, + LLAssetType::AT_LANDMARK, + LLInventoryType::IT_LANDMARK, + NOT_WEARABLE, PERM_ALL, + NULL); +} + +void LLLandmarkActions::createLandmarkHere() +{ + std::string landmark_name, landmark_desc; + + LLAgentUI::buildLocationString(landmark_name, LLAgentUI::LOCATION_FORMAT_LANDMARK); + LLAgentUI::buildLocationString(landmark_desc, LLAgentUI::LOCATION_FORMAT_FULL); + const LLUUID folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK); + + createLandmarkHere(landmark_name, landmark_desc, folder_id); +} + +LLVector3d getRegionPosFromGlobalPos(const LLVector3d& global_pos, const LLSimInfo* siminfo) +{ + LLVector3d local_pos; + local_pos[0] = fmod(global_pos[0], siminfo ? siminfo->getSizeX() : 256); + local_pos[1] = fmod(global_pos[1], siminfo ? siminfo->getSizeY() : 256); + local_pos[2] = global_pos[2]; + return local_pos; +} + +void LLLandmarkActions::getSLURLfromPosGlobal(const LLVector3d& global_pos, slurl_callback_t cb, bool escaped /* = true */) +{ + const LLSimInfo* siminfo = LLWorldMap::getInstance()->simInfoFromPosGlobal(global_pos); + if (siminfo) + { + std::string slurl = LLSLURL(siminfo->getName(), getRegionPosFromGlobalPos(global_pos, siminfo)).getSLURLString(); + cb(slurl); + } + else + { + U64 new_region_handle = to_region_handle(global_pos); + + LLWorldMapMessage::url_callback_t url_cb = boost::bind(&LLLandmarkActions::onRegionResponseSLURL, + cb, + global_pos, + escaped, + _2); + + LLWorldMapMessage::getInstance()->sendHandleRegionRequest(new_region_handle, url_cb, LLStringExplicit("unused"), false); + } +} + +void LLLandmarkActions::getRegionNameAndCoordsFromPosGlobal(const LLVector3d& global_pos, region_name_and_coords_callback_t cb) +{ + LLSimInfo* sim_infop = LLWorldMap::getInstance()->simInfoFromPosGlobal(global_pos); + if (sim_infop) + { + LLVector3 pos = sim_infop->getLocalPos(global_pos); + std::string name = sim_infop->getName() ; + cb(name, ll_round(pos.mV[VX]), ll_round(pos.mV[VY]),ll_round(pos.mV[VZ])); + } + else + { + U64 new_region_handle = to_region_handle(global_pos); + + LLWorldMapMessage::url_callback_t url_cb = boost::bind(&LLLandmarkActions::onRegionResponseNameAndCoords, + cb, + global_pos, + _1); + + LLWorldMapMessage::getInstance()->sendHandleRegionRequest(new_region_handle, url_cb, std::string("unused"), false); + } +} + +void LLLandmarkActions::onRegionResponseSLURL(slurl_callback_t cb, + const LLVector3d& global_pos, + bool escaped, + const std::string& url) +{ + std::string sim_name; + std::string slurl; + const LLSimInfo* siminfo = LLWorldMap::getInstance()->simInfoFromPosGlobal(global_pos); + if (siminfo) + { + slurl = LLSLURL(siminfo->getName(), getRegionPosFromGlobalPos(global_pos, siminfo)).getSLURLString(); + } + else + { + slurl.clear(); + } + + cb(slurl); +} + +void LLLandmarkActions::onRegionResponseNameAndCoords(region_name_and_coords_callback_t cb, + const LLVector3d& global_pos, + U64 region_handle) +{ + LLSimInfo* sim_infop = LLWorldMap::getInstance()->simInfoFromHandle(region_handle); + if (sim_infop) + { + LLVector3 local_pos = sim_infop->getLocalPos(global_pos); + std::string name = sim_infop->getName() ; + cb(name, ll_round(local_pos.mV[VX]), ll_round(local_pos.mV[VY]), ll_round(local_pos.mV[VZ])); + } +} + +bool LLLandmarkActions::getLandmarkGlobalPos(const LLUUID& landmarkInventoryItemID, LLVector3d& posGlobal) +{ + LLViewerInventoryItem* item = gInventory.getItem(landmarkInventoryItemID); + if (NULL == item) + return false; + + const LLUUID& asset_id = item->getAssetUUID(); + + LLLandmark* landmark = gLandmarkList.getAsset(asset_id); + if (NULL == landmark) + return false; + + return landmark->getGlobalPos(posGlobal); +} + +LLLandmark* LLLandmarkActions::getLandmark(const LLUUID& landmarkInventoryItemID, LLLandmarkList::loaded_callback_t cb) +{ + LLViewerInventoryItem* item = gInventory.getItem(landmarkInventoryItemID); + if (NULL == item) + return NULL; + + const LLUUID& asset_id = item->getAssetUUID(); + + LLLandmark* landmark = gLandmarkList.getAsset(asset_id, cb); + if (landmark) + { + return landmark; + } + + return NULL; +} + +void LLLandmarkActions::copySLURLtoClipboard(const LLUUID& landmarkInventoryItemID) +{ + LLLandmark* landmark = LLLandmarkActions::getLandmark(landmarkInventoryItemID); + if(landmark) + { + LLVector3d global_pos; + landmark->getGlobalPos(global_pos); + LLLandmarkActions::getSLURLfromPosGlobal(global_pos,©_slurl_to_clipboard_callback,true); + } +} + +void copy_slurl_to_clipboard_callback(const std::string& slurl) +{ + gViewerWindow->getWindow()->copyTextToClipboard(utf8str_to_wstring(slurl)); + LLSD args; + args["SLURL"] = slurl; + LLNotificationsUtil::add("CopySLURL", args); +} diff --git a/indra/newview/lllandmarkactions.h b/indra/newview/lllandmarkactions.h new file mode 100644 index 0000000000..8ac61d6af4 --- /dev/null +++ b/indra/newview/lllandmarkactions.h @@ -0,0 +1,138 @@ +/** + * @file lllandmarkactions.h + * @brief LLLandmark class declaration + * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLLANDMARKACTIONS_H +#define LL_LLLANDMARKACTIONS_H + +#include "llinventorymodel.h" + +#include "lllandmarklist.h" + +class LLLandmark; + +/** + * @brief Provides helper functions to manage landmarks + */ +class LLLandmarkActions +{ +public: + typedef std::function slurl_callback_t; + typedef std::function region_name_and_coords_callback_t; + + /** + * @brief Fetches landmark LLViewerInventoryItems for the given landmark name. + */ + static LLInventoryModel::item_array_t fetchLandmarksByName(std::string& name, BOOL if_use_substring); + /** + * @brief Checks whether landmark exists for current agent position. + */ + static bool landmarkAlreadyExists(); + + /** + * @brief Checks whether landmark exists for current agent parcel. + */ + static bool hasParcelLandmark(); + + /** + * @brief Searches landmark for global position. + * @return Returns landmark or NULL. + * + * *TODO: dzaporozhan: There can be many landmarks for single parcel. + */ + static LLViewerInventoryItem* findLandmarkForGlobalPos(const LLVector3d &pos); + + /** + * @brief Searches landmark for agent global position. + * @return Returns landmark or NULL. + * + * *TODO: dzaporozhan: There can be many landmarks for single parcel. + */ + static LLViewerInventoryItem* findLandmarkForAgentPos(); + + + /** + * @brief Checks whether agent has rights to create landmark for current parcel. + */ + static bool canCreateLandmarkHere(); + + /** + * @brief Creates landmark for current parcel. + */ + static void createLandmarkHere(); + + /** + * @brief Creates landmark for current parcel. + */ + static void createLandmarkHere( + const std::string& name, + const std::string& desc, + const LLUUID& folder_id); + /** + * @brief Creates SLURL for given global position. + */ + static void getSLURLfromPosGlobal(const LLVector3d& global_pos, slurl_callback_t cb, bool escaped = true); + + static void getRegionNameAndCoordsFromPosGlobal(const LLVector3d& global_pos, region_name_and_coords_callback_t cb); + + /** + * @brief Gets landmark global position specified by inventory LLUUID. + * Found position is placed into "posGlobal" variable. + *. + * @return - true if specified item exists in Inventory and an appropriate landmark found. + * and its position is known, false otherwise. + */ + // *TODO: mantipov: profide callback for cases, when Landmark is not loaded yet. + static bool getLandmarkGlobalPos(const LLUUID& landmarkInventoryItemID, LLVector3d& posGlobal); + + /** + * @brief Retrieve a landmark from gLandmarkList by inventory item's id + * If a landmark is not currently in the gLandmarkList a callback "cb" is called when it is loaded. + * + * @return pointer to loaded landmark from gLandmarkList or NULL if landmark does not exist or wasn't loaded. + */ + static LLLandmark* getLandmark(const LLUUID& landmarkInventoryItemID, LLLandmarkList::loaded_callback_t cb = nullptr); + + /** + * @brief Performs standard action of copying of SLURL from landmark to user's clipboard. + * This action requires additional server request. The user will be notified by info message, + * when URL is copied . + */ + static void copySLURLtoClipboard(const LLUUID& landmarkInventoryItemID); + +private: + LLLandmarkActions() = delete; + LLLandmarkActions(const LLLandmarkActions&) = delete; + + static void onRegionResponseSLURL(slurl_callback_t cb, + const LLVector3d& global_pos, + bool escaped, + const std::string& url); + static void onRegionResponseNameAndCoords(region_name_and_coords_callback_t cb, + const LLVector3d& global_pos, + U64 region_handle); +}; + +#endif //LL_LLLANDMARKACTIONS_H diff --git a/indra/newview/lllandmarklist.cpp b/indra/newview/lllandmarklist.cpp index b26d19c7af..02cfd326a8 100644 --- a/indra/newview/lllandmarklist.cpp +++ b/indra/newview/lllandmarklist.cpp @@ -1,3 +1,5 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com /** * @file lllandmarklist.cpp * @brief Landmark asset list class @@ -35,7 +37,6 @@ #include "llagent.h" #include "llvfile.h" #include "llviewerstats.h" -#include "llnotificationsutil.h" // Globals LLLandmarkList gLandmarkList; @@ -47,6 +48,7 @@ LLLandmarkList gLandmarkList; LLLandmarkList::~LLLandmarkList() { std::for_each(mList.begin(), mList.end(), DeletePairedPointer()); + mList.clear(); } LLLandmark* LLLandmarkList::getAsset(const LLUUID& asset_uuid, loaded_callback_t cb) @@ -67,7 +69,7 @@ LLLandmark* LLLandmarkList::getAsset(const LLUUID& asset_uuid, loaded_callback_t { if ( mBadList.find(asset_uuid) != mBadList.end() ) { - return NULL; + return nullptr; } landmark_requested_list_t::iterator iter = mRequestedList.find(asset_uuid); @@ -76,7 +78,7 @@ LLLandmark* LLLandmarkList::getAsset(const LLUUID& asset_uuid, loaded_callback_t const F32 rerequest_time = 30.f; // 30 seconds between requests if (gFrameTimeSeconds - iter->second < rerequest_time) { - return NULL; + return nullptr; } } @@ -89,10 +91,10 @@ LLLandmark* LLLandmarkList::getAsset(const LLUUID& asset_uuid, loaded_callback_t gAssetStorage->getAssetData(asset_uuid, LLAssetType::AT_LANDMARK, LLLandmarkList::processGetAssetReply, - NULL); + nullptr); mRequestedList[asset_uuid] = gFrameTimeSeconds; } - return NULL; + return nullptr; } // static @@ -143,14 +145,16 @@ void LLLandmarkList::processGetAssetReply( else { LLViewerStats::getInstance()->incStat( LLViewerStats::ST_DOWNLOAD_FAILED ); - + // SJB: No use case for a notification here. Use LL_DEBUGS() instead if( LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status ) { - LLNotificationsUtil::add("LandmarkMissing"); + LL_WARNS("Landmarks") << "Missing Landmark" << LL_ENDL; + //LLNotificationsUtil::add("LandmarkMissing"); } else { - LLNotificationsUtil::add("UnableToLoadLandmark"); + LL_WARNS("Landmarks") << "Unable to load Landmark" << LL_ENDL; + //LLNotificationsUtil::add("UnableToLoadLandmark"); } gLandmarkList.mBadList.insert(uuid); @@ -174,7 +178,7 @@ void LLLandmarkList::onRegionHandle(const LLUUID& landmark_id) if (!landmark) { - llwarns << "Got region handle but the landmark not found." << llendl; + LL_WARNS() << "Got region handle but the landmark not found." << LL_ENDL; return; } @@ -183,7 +187,7 @@ void LLLandmarkList::onRegionHandle(const LLUUID& landmark_id) LLVector3d pos; if (!landmark->getGlobalPos(pos)) { - llwarns << "Got region handle but the landmark global position is still unknown." << llendl; + LL_WARNS() << "Got region handle but the landmark global position is still unknown." << LL_ENDL; return; } @@ -196,7 +200,7 @@ void LLLandmarkList::makeCallbacks(const LLUUID& landmark_id) if (!landmark) { - llwarns << "Landmark to make callbacks for not found." << llendl; + LL_WARNS() << "Landmark to make callbacks for not found." << LL_ENDL; } // make all the callbacks here. diff --git a/indra/newview/lllandmarklist.h b/indra/newview/lllandmarklist.h index 3356f866ce..057c8d5e75 100644 --- a/indra/newview/lllandmarklist.h +++ b/indra/newview/lllandmarklist.h @@ -27,8 +27,6 @@ #ifndef LL_LLLANDMARKLIST_H #define LL_LLLANDMARKLIST_H -#include -#include #include "lllandmark.h" #include "lluuid.h" #include "llassetstorage.h" @@ -40,7 +38,7 @@ class LLInventoryItem; class LLLandmarkList { public: - typedef boost::function loaded_callback_t; + typedef std::function loaded_callback_t; LLLandmarkList() {} ~LLLandmarkList(); @@ -50,7 +48,7 @@ class LLLandmarkList //const LLLandmark* getNext() { return mList.getNextData(); } BOOL assetExists(const LLUUID& asset_uuid); - LLLandmark* getAsset(const LLUUID& asset_uuid, loaded_callback_t cb = NULL); + LLLandmark* getAsset(const LLUUID& asset_uuid, loaded_callback_t cb = nullptr); static void processGetAssetReply( LLVFS *vfs, const LLUUID& uuid, @@ -70,7 +68,7 @@ class LLLandmarkList typedef std::map landmark_list_t; landmark_list_t mList; - typedef std::set landmark_bad_list_t; + typedef uuid_set_t landmark_bad_list_t; landmark_bad_list_t mBadList; typedef std::map landmark_requested_list_t; diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp index 7818e59001..7da15ec618 100644 --- a/indra/newview/lllogchat.cpp +++ b/indra/newview/lllogchat.cpp @@ -36,37 +36,132 @@ #include "lllogchat.h" #include "llappviewer.h" #include "llfloaterchat.h" -#include "llviewercontrol.h" +#include "llsdserialize.h" -const S32 LOG_RECALL_SIZE = 2048; +static std::string get_log_dir_file(const std::string& filename) +{ + return gDirUtilp->getExpandedFilename(LL_PATH_PER_ACCOUNT_CHAT_LOGS, filename); +} //static -std::string LLLogChat::makeLogFileName(std::string filename) +std::string LLLogChat::makeLogFileNameInternal(std::string filename) { - if (gSavedPerAccountSettings.getBOOL("LogFileNamewithDate")) + static const LLCachedControl with_date(gSavedPerAccountSettings, "LogFileNamewithDate"); + if (with_date) { time_t now; time(&now); - char dbuffer[100]; /* Flawfinder: ignore */ - if (filename == "chat") - { - static const LLCachedControl local_chat_date_format(gSavedPerAccountSettings, "LogFileLocalChatDateFormat", "-%Y-%m-%d"); - strftime(dbuffer, 100, local_chat_date_format().c_str(), localtime(&now)); - } - else - { - static const LLCachedControl ims_date_format(gSavedPerAccountSettings, "LogFileIMsDateFormat", "-%Y-%m"); - strftime(dbuffer, 100, ims_date_format().c_str(), localtime(&now)); - } - filename += dbuffer; + std::array dbuffer; + static const LLCachedControl local_chat_date_format(gSavedPerAccountSettings, "LogFileLocalChatDateFormat", "-%Y-%m-%d"); + static const LLCachedControl ims_date_format(gSavedPerAccountSettings, "LogFileIMsDateFormat", "-%Y-%m"); + strftime(dbuffer.data(), dbuffer.size(), (filename == "chat" ? local_chat_date_format : ims_date_format)().c_str(), localtime(&now)); + filename += dbuffer.data(); + } + cleanFileName(filename); + return get_log_dir_file(filename + ".txt"); +} + +bool LLLogChat::migrateFile(const std::string& old_name, const std::string& filename) +{ + std::string oldfile = makeLogFileNameInternal(old_name); + if (!LLFile::isfile(oldfile)) return false; // An old file by this name doesn't exist + + if (LLFile::isfile(filename)) // A file by the new name also exists, but wasn't being tracked yet + { + auto&& new_untracked_log = llifstream(filename); + auto&& tracked_log = llofstream(oldfile, llofstream::out|llofstream::app); + // Append new to old and find out if it failed + bool failed = !(tracked_log << new_untracked_log.rdbuf()); + // Close streams + new_untracked_log.close(); + tracked_log.close(); + if (failed || LLFile::remove(filename)) // Delete the untracked new file so that reclaiming its name won't fail + return true; // We failed to remove it or update the old file, let's just use the new file and leave the old one alone + } + + LLFile::rename(oldfile, filename); // Move the existing file to the new name + return true; // Report success +} + +static LLSD sIDMap; + +static std::string get_ids_map_file() { return get_log_dir_file("ids_to_names.json"); } +void LLLogChat::initializeIDMap() +{ + const auto map_file = get_ids_map_file(); + bool write = true; // Do we want to write back to map_file? + if (LLFile::isfile(map_file)) // If we've already made this file, load our map from it + { + if (auto&& fstr = llifstream(map_file)) + { + LLSDSerialize::fromNotation(sIDMap, fstr, LLSDSerialize::SIZE_UNLIMITED); + fstr.close(); + } + write = false; // Don't write what we just read + } + + if (gCacheName) // Load what we can from name cache to initialize or update the map and its file + { + bool empty = sIDMap.size() == 0; // Opt out of searching the map for IDs we added if we started with none + for (const auto& r : gCacheName->getReverseMap()) // For every name id pair + { + const auto id = r.second.asString(); + const auto& name = r.first; + const auto filename = makeLogFileNameInternal(name); + bool id_known = !empty && sIDMap.has(id); // Is this ID known? + if (id_known ? name != sIDMap[id].asStringRef() // If names don't match + && migrateFile(sIDMap[id].asStringRef(), filename) // Do we need to migrate an existing log? + : LLFile::isfile(filename)) // Otherwise if there's a log file for them but they're not in the map yet + { + if (id_known) write = true; // We updated, write + sIDMap[id] = name; // Add them to the map + } + } + + if (write) + if (auto&& fstr = llofstream(map_file)) + { + LLSDSerialize::toPrettyNotation(sIDMap, fstr); + fstr.close(); + } + } + +} + +//static +std::string LLLogChat::makeLogFileName(const std::string& username, const LLUUID& id) +{ + const auto name = username.empty() ? id.asString() : username; // Fall back on ID if the grid sucks and we have no name + std::string filename = makeLogFileNameInternal(name); + if (id.notNull() && !LLFile::isfile(filename)) // No existing file by this user's current name, check for possible file rename + { + auto& entry = sIDMap[id.asString()]; + const bool empty = !entry.size(); + if (empty || entry != name) // If we haven't seen this entry yet, or the name is different than we remember + { + if (empty) // We didn't see this entry on load + { + // Ideally, we would look up the old names here via server request + // In lieu of that, our reverse cache has old names and new names that we've gained since our initialization of the ID map + for (const auto& r : gCacheName->getReverseMap()) + if (r.second == id && migrateFile(r.first, filename)) + break; + } + else migrateFile(entry.asStringRef(), filename); // We've seen this entry before, migrate old file if it exists + + entry = name; // Update the entry to point to the new name + + if (auto&& fstr = llofstream(get_ids_map_file())) // Write back to our map file + { + LLSDSerialize::toPrettyNotation(sIDMap, fstr); + fstr.close(); + } + } } - filename = cleanFileName(filename); - filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_ACCOUNT_CHAT_LOGS,filename); - filename += ".txt"; return filename; } -std::string LLLogChat::cleanFileName(std::string filename) +void LLLogChat::cleanFileName(std::string& filename) { std::string invalidChars = "\"\'\\/?*:<>|[]{}~"; // Cannot match glob or illegal filename chars S32 position = filename.find_first_of(invalidChars); @@ -75,51 +170,62 @@ std::string LLLogChat::cleanFileName(std::string filename) filename[position] = '_'; position = filename.find_first_of(invalidChars, position); } - return filename; } -std::string LLLogChat::timestamp(bool withdate) +static void time_format(std::string& out, const char* fmt, const std::tm* time) { - time_t utc_time; - utc_time = time_corrected(); + typedef typename std::vector> vec_t; + static thread_local vec_t charvector(1024); // Evolves into charveleon + #define format_the_time() std::strftime(charvector.data(), charvector.capacity(), fmt, time) + const auto smallsize(charvector.capacity()); + const auto size = format_the_time(); + if (size < 0) + { + LL_ERRS() << "Formatting time failed, code " << size << ". String hint: " << out << '/' << fmt << LL_ENDL; + } + else if (static_cast(size) >= smallsize) // Resize if we need more space + { + charvector.resize(1+size); // Use the String Stone + format_the_time(); + } + #undef format_the_time + out.assign(charvector.data()); +} - // There's only one internal tm buffer. - struct tm* timep; +std::string LLLogChat::timestamp(bool withdate) +{ // Convert to Pacific, based on server's opinion of whether // it's daylight savings time there. - timep = utc_to_pacific_time(utc_time, gPacificDaylightTime); - - static LLCachedControl withseconds("SecondsInLog"); - std::string text; - if (withdate) - if (withseconds) - text = llformat("[%d-%02d-%02d %02d:%02d:%02d] ", (timep->tm_year-100)+2000, timep->tm_mon+1, timep->tm_mday, timep->tm_hour, timep->tm_min, timep->tm_sec); - else - text = llformat("[%d/%02d/%02d %02d:%02d] ", (timep->tm_year-100)+2000, timep->tm_mon+1, timep->tm_mday, timep->tm_hour, timep->tm_min); - else - if (withseconds) - text = llformat("[%02d:%02d:%02d] ", timep->tm_hour, timep->tm_min, timep->tm_sec); - else - text = llformat("[%02d:%02d] ", timep->tm_hour, timep->tm_min); + auto time = utc_to_pacific_time(time_corrected(), gPacificDaylightTime); + + static const LLCachedControl withseconds("SecondsInLog"); + static const LLCachedControl date("ShortDateFormat"); + static const LLCachedControl shorttime("ShortTimeFormat"); + static const LLCachedControl longtime("LongTimeFormat"); + std::string text = "["; + if (withdate) text += date() + ' '; + text += (withseconds ? longtime : shorttime)() + "] "; + + time_format(text, text.data(), time); return text; } //static -void LLLogChat::saveHistory(std::string const& filename, std::string line) +void LLLogChat::saveHistory(const std::string& name, const LLUUID& id, const std::string& line) { - if(!filename.size()) + if(name.empty() && id.isNull()) { - llinfos << "Filename is Empty!" << llendl; + LL_INFOS() << "Filename is Empty!" << LL_ENDL; return; } - LLFILE* fp = LLFile::fopen(LLLogChat::makeLogFileName(filename), "a"); /*Flawfinder: ignore*/ + LLFILE* fp = LLFile::fopen(LLLogChat::makeLogFileName(name, id), "a"); /*Flawfinder: ignore*/ if (!fp) { - llinfos << "Couldn't open chat history log!" << llendl; + LL_INFOS() << "Couldn't open chat history log!" << LL_ENDL; } else { @@ -129,55 +235,75 @@ void LLLogChat::saveHistory(std::string const& filename, std::string line) } } -void LLLogChat::loadHistory(std::string const& filename , void (*callback)(ELogLineType,std::string,void*), void* userdata) -{ - if(!filename.size()) - { - llwarns << "Filename is Empty!" << llendl; - return ; - } +static long const LOG_RECALL_BUFSIZ = 2048; - LLFILE* fptr = LLFile::fopen(makeLogFileName(filename), "r"); /*Flawfinder: ignore*/ - if (!fptr) +void LLLogChat::loadHistory(const std::string& name, const LLUUID& id, std::function callback) +{ + if (name.empty() && id.isNull()) { - //LLUIString message = LLFloaterChat::getInstance()->getString("IM_logging_string"); - //callback(LOG_EMPTY,"IM_logging_string",userdata); - callback(LOG_EMPTY,LLStringUtil::null,userdata); - return; //No previous conversation with this name. + LL_WARNS() << "filename is empty!" << LL_ENDL; } - else + else while(1) // So we can use break. { - char buffer[LOG_RECALL_SIZE]; /*Flawfinder: ignore*/ - char *bptr; - S32 len; - bool firstline=TRUE; - - if ( fseek(fptr, (LOG_RECALL_SIZE - 1) * -1 , SEEK_END) ) - { //File is smaller than recall size. Get it all. - firstline = FALSE; - if ( fseek(fptr, 0, SEEK_SET) ) + // The number of lines to return. + static const LLCachedControl lines("LogShowHistoryLines", 32); + if (lines == 0) break; + + // Open the log file. + LLFILE* fptr = LLFile::fopen(makeLogFileName(name, id), "rb"); + if (!fptr) break; + + // Set pos to point to the last character of the file, if any. + if (fseek(fptr, 0, SEEK_END)) break; + long pos = ftell(fptr) - 1; + if (pos < 0) break; + + char buffer[LOG_RECALL_BUFSIZ]; + bool error = false; + U32 nlines = 0; + while (pos > 0 && nlines < lines) + { + // Read the LOG_RECALL_BUFSIZ characters before pos. + size_t size = llmin(LOG_RECALL_BUFSIZ, pos); + pos -= size; + fseek(fptr, pos, SEEK_SET); + size_t len = fread(buffer, 1, size, fptr); + error = len != size; + if (error) break; + // Count the number of newlines in it and set pos to the beginning of the first line to return when we found enough. + for (char const* p = buffer + size - 1; p >= buffer; --p) { - fclose(fptr); - return; + if (*p == '\n') + { + if (++nlines == lines) + { + pos += p - buffer + 1; + break; + } + } } } + if (error) + { + fclose(fptr); + break; + } + + // Set the file pointer at the first line to return. + fseek(fptr, pos, SEEK_SET); - while ( fgets(buffer, LOG_RECALL_SIZE, fptr) && !feof(fptr) ) + // Read lines from the file one by one until we reach the end of the file. + while (fgets(buffer, LOG_RECALL_BUFSIZ, fptr)) { - len = strlen(buffer) - 1; /*Flawfinder: ignore*/ - for ( bptr = (buffer + len); (*bptr == '\n' || *bptr == '\r') && bptr>buffer; bptr--) *bptr='\0'; - - if (!firstline) - { - callback(LOG_LINE,std::string(buffer),userdata); - } - else - { - firstline = FALSE; - } + // strip newline chars from the end of the string + for (S32 i = strlen(buffer) - 1; i >= 0 && (buffer[i] == '\r' || buffer[i] == '\n'); --i) + buffer[i] = '\0'; + callback(LOG_LINE, buffer); } - callback(LOG_END,LLStringUtil::null,userdata); - + fclose(fptr); + callback(LOG_END, LLStringUtil::null); + return; } + callback(LOG_EMPTY, LLStringUtil::null); } diff --git a/indra/newview/lllogchat.h b/indra/newview/lllogchat.h index 84f6760ab6..245eb95ce0 100644 --- a/indra/newview/lllogchat.h +++ b/indra/newview/lllogchat.h @@ -45,14 +45,16 @@ class LLLogChat LOG_LINE, LOG_END }; + static void initializeIDMap(); static std::string timestamp(bool withdate = false); - static std::string makeLogFileName(std::string filename); - static void saveHistory(std::string const& filename, std::string line); - static void loadHistory(std::string const& filename, - void (*callback)(ELogLineType,std::string,void*), - void* userdata); + static std::string makeLogFileName(const std::string& name, const LLUUID& id); + static void saveHistory(const std::string& name, const LLUUID& id, const std::string& line); + static void loadHistory(const std::string& name, const LLUUID& id, + std::function callback); private: - static std::string cleanFileName(std::string filename); + static std::string makeLogFileNameInternal(std::string filename); + static bool migrateFile(const std::string& old_name, const std::string& filename); + static void cleanFileName(std::string& filename); }; #endif diff --git a/indra/newview/llmainlooprepeater.cpp b/indra/newview/llmainlooprepeater.cpp index d73048a28b..6736e9a950 100644 --- a/indra/newview/llmainlooprepeater.cpp +++ b/indra/newview/llmainlooprepeater.cpp @@ -81,7 +81,7 @@ bool LLMainLoopRepeater::onMessage(LLSD const & event) try { mQueue->pushFront(event); } catch(LLThreadSafeQueueError & e) { - llwarns << "could not repeat message (" << e.what() << ")" << + LL_WARNS() << "could not repeat message (" << e.what() << ")" << event.asString() << LL_ENDL; } return false; diff --git a/indra/newview/llmakeoutfitdialog.cpp b/indra/newview/llmakeoutfitdialog.cpp index 2c607e6c71..f029210b9e 100644 --- a/indra/newview/llmakeoutfitdialog.cpp +++ b/indra/newview/llmakeoutfitdialog.cpp @@ -52,7 +52,15 @@ LLMakeOutfitDialog::LLMakeOutfitDialog(bool modal) : LLModalDialog(LLStringUtil: // Build list of check boxes for (S32 i = 0; i < LLWearableType::WT_COUNT; i++) { - std::string name = std::string("checkbox_") + LLWearableType::getTypeLabel((LLWearableType::EType)i); + std::string label = LLWearableType::getTypeLabel((LLWearableType::EType)i); + std::string name = std::string("checkbox_") + label; + std::string labellower = label; + labellower[0] = tolower(labellower[0]); + std::string namelower = std::string("checkbox_") + labellower; + if (findChild(namelower)) + { + name = namelower; + } mCheckBoxList.push_back(std::make_pair(name, i)); // Hide undergarments from teens if (gAgent.isTeen() && ((LLWearableType::WT_UNDERSHIRT == (LLWearableType::EType)i) || (LLWearableType::WT_UNDERPANTS == (LLWearableType::EType)i))) @@ -62,9 +70,9 @@ LLMakeOutfitDialog::LLMakeOutfitDialog(bool modal) : LLModalDialog(LLStringUtil: else { bool enabled = gAgentWearables.getWearableCount((LLWearableType::EType)i); // TODO: MULTI-WEARABLE - bool selected = enabled && (LLWearableType::WT_SHIRT <= i); // only select clothing by default + //bool selected = enabled && (LLWearableType::WT_SHIRT <= i); // only select clothing by default childSetEnabled(name, enabled); - childSetValue(name, selected); + childSetValue(name, enabled); } } @@ -81,16 +89,10 @@ LLMakeOutfitDialog::LLMakeOutfitDialog(bool modal) : LLModalDialog(LLStringUtil: std::string name = std::string("checkbox_") + attachment->getName(); mCheckBoxList.push_back(std::make_pair(name, attachment_pt)); childSetEnabled(name, object_attached); + childSetValue(name, object_attached); } } - if (!gHippoGridManager->getConnectedGrid()->supportsInvLinks()) - { - childSetValue("checkbox_use_links", false); - childSetEnabled("checkbox_use_outfits", false); - childSetValue("checkbox_use_outfits", false); - } - getChild("Save")->setCommitCallback(boost::bind(&LLMakeOutfitDialog::onSave, this)); getChild("Cancel")->setCommitCallback(boost::bind(&LLMakeOutfitDialog::close, this, _1)); getChild("Check All")->setCommitCallback(boost::bind(&LLMakeOutfitDialog::onCheckAll, this, true)); @@ -139,7 +141,7 @@ void LLMakeOutfitDialog::refresh() if (fUseOutfits) pCheckCtrl->setValue(true); } - getChild("checkbox_use_links")->setEnabled(!fUseOutfits && gHippoGridManager->getConnectedGrid()->supportsInvLinks()); + getChild("checkbox_use_links")->setEnabled(!fUseOutfits); getChild("checkbox_legacy_copy_changes")->setEnabled(!fUseOutfits); } diff --git a/indra/newview/llmanip.cpp b/indra/newview/llmanip.cpp index 44ab0f9bc6..fc4e2a46da 100644 --- a/indra/newview/llmanip.cpp +++ b/indra/newview/llmanip.cpp @@ -47,9 +47,9 @@ #include "llviewercamera.h" #include "llviewerjoint.h" #include "llviewerobject.h" +#include "llviewerregion.h" #include "llviewerwindow.h" #include "llvoavatar.h" -#include "llworld.h" // for LLWorld::getInstance() #include "llresmgr.h" #include "pipeline.h" #include "llglheaders.h" @@ -226,11 +226,11 @@ BOOL LLManip::handleHover(S32 x, S32 y, MASK mask) setMouseCapture( FALSE ); } - lldebugst(LLERR_USER_INPUT) << "hover handled by LLManip (active)" << llendl; + LL_DEBUGS("UserInput") << "hover handled by LLManip (active)" << LL_ENDL; } else { - lldebugst(LLERR_USER_INPUT) << "hover handled by LLManip (inactive)" << llendl; + LL_DEBUGS("UserInput") << "hover handled by LLManip (inactive)" << LL_ENDL; } gViewerWindow->setCursor(UI_CURSOR_ARROW); return TRUE; @@ -406,7 +406,7 @@ void LLManip::renderGuidelines(BOOL draw_x, BOOL draw_y, BOOL draw_z) grid_rot.getAngleAxis(&angle_radians, &x, &y, &z); gGL.rotatef(angle_radians * RAD_TO_DEG, x, y, z); - F32 region_size = LLWorld::getInstance()->getRegionWidthInMeters(); + F32 region_size = object->getRegion()->getWidth(); const F32 LINE_ALPHA = 0.33f; @@ -456,7 +456,7 @@ void LLManip::renderXYZ(const LLVector3 &vec) gGL.pushMatrix(); { - LLUIImagePtr imagep = LLUI::getUIImage("rounded_square.tga"); + LLUIImagePtr imagep = LLUI::getUIImage("Rounded_Square"); gViewerWindow->setup2DRender(); const LLVector2& display_scale = gViewerWindow->getDisplayScale(); gGL.scalef(display_scale.mV[VX], display_scale.mV[VY], 1.f); @@ -538,8 +538,8 @@ void LLManip::renderTickValue(const LLVector3& pos, F32 value, const std::string std::string val_string; std::string fraction_string; - F32 val_to_print = llround(value, 0.001f); - S32 fractional_portion = llround(fmodf(llabs(val_to_print), 1.f) * 100.f); + F32 val_to_print = ll_round(value, 0.001f); + S32 fractional_portion = ll_round(fmodf(llabs(val_to_print), 1.f) * 100.f); if (val_to_print < 0.f) { if (fractional_portion == 0) diff --git a/indra/newview/llmaniprotate.cpp b/indra/newview/llmaniprotate.cpp index 6f014f5984..6204b8ba1b 100644 --- a/indra/newview/llmaniprotate.cpp +++ b/indra/newview/llmaniprotate.cpp @@ -115,8 +115,8 @@ void LLManipRotate::render() LLGLSUIDefault gls_ui; gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep); LLGLDepthTest gls_depth(GL_TRUE); - LLGLEnable gl_blend(GL_BLEND); - LLGLEnable gls_alpha_test(GL_ALPHA_TEST); + LLGLEnable gl_blend; + LLGLEnable gls_alpha_test; // You can rotate if you can move LLViewerObject* first_object = mObjectSelection->getFirstMoveableObject(TRUE); @@ -160,7 +160,7 @@ void LLManipRotate::render() gDebugProgram.bind(); } - LLGLEnable cull_face(GL_CULL_FACE); + LLGLEnable cull_face; LLGLDepthTest gls_depth(GL_FALSE); gGL.pushMatrix(); { @@ -183,9 +183,12 @@ void LLManipRotate::render() LLMatrix4 mat; mat.initRows(a, b, c, LLVector4(0.f, 0.f, 0.f, 1.f)); - gGL.multMatrix( &mat.mMatrix[0][0] ); + LLMatrix4a mata; + mata.loadu((F32*)mat.mMatrix); + gGL.multMatrix( mata ); - gGL.rotatef( -90, 0.f, 1.f, 0.f); + static const LLMatrix4a rot = gGL.genRot(-90, 0.f, 1.f, 0.f); + gGL.rotatef(rot); LLColor4 color; if (mManipPart == LL_ROT_ROLL || mHighlightedPart == LL_ROT_ROLL) { @@ -239,7 +242,7 @@ void LLManipRotate::render() if (mManipPart == LL_ROT_Z) { - mManipulatorScales = lerp(mManipulatorScales, LLVector4(1.f, 1.f, SELECTED_MANIPULATOR_SCALE, 1.f), LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE)); + mManipulatorScales = lerp(mManipulatorScales, LLVector4(1.f, 1.f, SELECTED_MANIPULATOR_SCALE, 1.f), LLSmoothInterpolation::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE)); gGL.pushMatrix(); { // selected part @@ -250,10 +253,11 @@ void LLManipRotate::render() } else if (mManipPart == LL_ROT_Y) { - mManipulatorScales = lerp(mManipulatorScales, LLVector4(1.f, SELECTED_MANIPULATOR_SCALE, 1.f, 1.f), LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE)); + mManipulatorScales = lerp(mManipulatorScales, LLVector4(1.f, SELECTED_MANIPULATOR_SCALE, 1.f, 1.f), LLSmoothInterpolation::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE)); gGL.pushMatrix(); { - gGL.rotatef( 90.f, 1.f, 0.f, 0.f ); + static const LLMatrix4a rot = gGL.genRot( 90.f, 1.f, 0.f, 0.f ); + gGL.rotatef(rot); gGL.scalef(mManipulatorScales.mV[VY], mManipulatorScales.mV[VY], mManipulatorScales.mV[VY]); renderActiveRing( mRadiusMeters, width_meters, LLColor4( 0.f, 1.f, 0.f, 1.f), LLColor4( 0.f, 1.f, 0.f, 0.3f)); } @@ -261,10 +265,11 @@ void LLManipRotate::render() } else if (mManipPart == LL_ROT_X) { - mManipulatorScales = lerp(mManipulatorScales, LLVector4(SELECTED_MANIPULATOR_SCALE, 1.f, 1.f, 1.f), LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE)); + mManipulatorScales = lerp(mManipulatorScales, LLVector4(SELECTED_MANIPULATOR_SCALE, 1.f, 1.f, 1.f), LLSmoothInterpolation::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE)); gGL.pushMatrix(); { - gGL.rotatef( 90.f, 0.f, 1.f, 0.f ); + static const LLMatrix4a rot = gGL.genRot( 90.f, 0.f, 1.f, 0.f ); + gGL.rotatef( rot ); gGL.scalef(mManipulatorScales.mV[VX], mManipulatorScales.mV[VX], mManipulatorScales.mV[VX]); renderActiveRing( mRadiusMeters, width_meters, LLColor4( 1.f, 0.f, 0.f, 1.f), LLColor4( 1.f, 0.f, 0.f, 0.3f)); } @@ -272,17 +277,17 @@ void LLManipRotate::render() } else if (mManipPart == LL_ROT_ROLL) { - mManipulatorScales = lerp(mManipulatorScales, LLVector4(1.f, 1.f, 1.f, SELECTED_MANIPULATOR_SCALE), LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE)); + mManipulatorScales = lerp(mManipulatorScales, LLVector4(1.f, 1.f, 1.f, SELECTED_MANIPULATOR_SCALE), LLSmoothInterpolation::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE)); } else if (mManipPart == LL_NO_PART) { if (mHighlightedPart == LL_NO_PART) { - mManipulatorScales = lerp(mManipulatorScales, LLVector4(1.f, 1.f, 1.f, 1.f), LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE)); + mManipulatorScales = lerp(mManipulatorScales, LLVector4(1.f, 1.f, 1.f, 1.f), LLSmoothInterpolation::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE)); } - LLGLEnable cull_face(GL_CULL_FACE); - LLGLEnable clip_plane0(GL_CLIP_PLANE0); + LLGLEnable cull_face; + LLGLEnable clip_plane0; LLGLDepthTest gls_depth(GL_FALSE); // First pass: centers. Second pass: sides. @@ -293,7 +298,7 @@ void LLManipRotate::render() { if (mHighlightedPart == LL_ROT_Z) { - mManipulatorScales = lerp(mManipulatorScales, LLVector4(1.f, 1.f, SELECTED_MANIPULATOR_SCALE, 1.f), LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE)); + mManipulatorScales = lerp(mManipulatorScales, LLVector4(1.f, 1.f, SELECTED_MANIPULATOR_SCALE, 1.f), LLSmoothInterpolation::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE)); gGL.scalef(mManipulatorScales.mV[VZ], mManipulatorScales.mV[VZ], mManipulatorScales.mV[VZ]); // hovering over part gl_ring( mRadiusMeters, width_meters, LLColor4( 0.f, 0.f, 1.f, 1.f ), LLColor4( 0.f, 0.f, 1.f, 0.5f ), CIRCLE_STEPS, i); @@ -308,10 +313,11 @@ void LLManipRotate::render() gGL.pushMatrix(); { - gGL.rotatef( 90.f, 1.f, 0.f, 0.f ); + static const LLMatrix4a rot = gGL.genRot( 90.f, 1.f, 0.f, 0.f ); + gGL.rotatef( rot ); if (mHighlightedPart == LL_ROT_Y) { - mManipulatorScales = lerp(mManipulatorScales, LLVector4(1.f, SELECTED_MANIPULATOR_SCALE, 1.f, 1.f), LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE)); + mManipulatorScales = lerp(mManipulatorScales, LLVector4(1.f, SELECTED_MANIPULATOR_SCALE, 1.f, 1.f), LLSmoothInterpolation::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE)); gGL.scalef(mManipulatorScales.mV[VY], mManipulatorScales.mV[VY], mManipulatorScales.mV[VY]); // hovering over part gl_ring( mRadiusMeters, width_meters, LLColor4( 0.f, 1.f, 0.f, 1.f ), LLColor4( 0.f, 1.f, 0.f, 0.5f ), CIRCLE_STEPS, i); @@ -326,10 +332,11 @@ void LLManipRotate::render() gGL.pushMatrix(); { - gGL.rotatef( 90.f, 0.f, 1.f, 0.f ); + static const LLMatrix4a rot = gGL.genRot( 90.f, 0.f, 1.f, 0.f ); + gGL.rotatef( rot ); if (mHighlightedPart == LL_ROT_X) { - mManipulatorScales = lerp(mManipulatorScales, LLVector4(SELECTED_MANIPULATOR_SCALE, 1.f, 1.f, 1.f), LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE)); + mManipulatorScales = lerp(mManipulatorScales, LLVector4(SELECTED_MANIPULATOR_SCALE, 1.f, 1.f, 1.f), LLSmoothInterpolation::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE)); gGL.scalef(mManipulatorScales.mV[VX], mManipulatorScales.mV[VX], mManipulatorScales.mV[VX]); // hovering over part @@ -345,7 +352,7 @@ void LLManipRotate::render() if (mHighlightedPart == LL_ROT_ROLL) { - mManipulatorScales = lerp(mManipulatorScales, LLVector4(1.f, 1.f, 1.f, SELECTED_MANIPULATOR_SCALE), LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE)); + mManipulatorScales = lerp(mManipulatorScales, LLVector4(1.f, 1.f, 1.f, SELECTED_MANIPULATOR_SCALE), LLSmoothInterpolation::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE)); } } @@ -366,9 +373,9 @@ void LLManipRotate::render() LLQuaternion object_rot = first_object->getRotationEdit(); object_rot.getEulerAngles(&(euler_angles.mV[VX]), &(euler_angles.mV[VY]), &(euler_angles.mV[VZ])); euler_angles *= RAD_TO_DEG; - euler_angles.mV[VX] = llround(fmodf(euler_angles.mV[VX] + 360.f, 360.f), 0.05f); - euler_angles.mV[VY] = llround(fmodf(euler_angles.mV[VY] + 360.f, 360.f), 0.05f); - euler_angles.mV[VZ] = llround(fmodf(euler_angles.mV[VZ] + 360.f, 360.f), 0.05f); + euler_angles.mV[VX] = ll_round(fmodf(euler_angles.mV[VX] + 360.f, 360.f), 0.05f); + euler_angles.mV[VY] = ll_round(fmodf(euler_angles.mV[VY] + 360.f, 360.f), 0.05f); + euler_angles.mV[VZ] = ll_round(fmodf(euler_angles.mV[VZ] + 360.f, 360.f), 0.05f); renderXYZ(euler_angles); } @@ -481,7 +488,7 @@ BOOL LLManipRotate::handleMouseUp(S32 x, S32 y, MASK mask) LLViewerObject* root_object = (object == NULL) ? NULL : object->getRootEdit(); // have permission to move and object is root of selection or individually selected - if (object->permMove() && !object->isPermanentEnforced() && + if (object && object->permMove() && !object->isPermanentEnforced() && ((root_object == NULL) || !root_object->isPermanentEnforced()) && (object->isRootEdit() || selectNode->mIndividualSelection)) { @@ -517,12 +524,12 @@ BOOL LLManipRotate::handleHover(S32 x, S32 y, MASK mask) drag(x, y); } - lldebugst(LLERR_USER_INPUT) << "hover handled by LLManipRotate (active)" << llendl; + LL_DEBUGS("UserInput") << "hover handled by LLManipRotate (active)" << LL_ENDL; } else { highlightManipulators(x, y); - lldebugst(LLERR_USER_INPUT) << "hover handled by LLManipRotate (inactive)" << llendl; + LL_DEBUGS("UserInput") << "hover handled by LLManipRotate (inactive)" << LL_ENDL; } gViewerWindow->setCursor(UI_CURSOR_TOOLROTATE); @@ -571,7 +578,7 @@ void LLManipRotate::drag( S32 x, S32 y ) LLViewerObject* root_object = (object == NULL) ? NULL : object->getRootEdit(); // have permission to move and object is root of selection or individually selected - if (object->permMove() && !object->isPermanentEnforced() && + if (object && object->permMove() && !object->isPermanentEnforced() && ((root_object == NULL) || !root_object->isPermanentEnforced()) && (object->isRootEdit() || selectNode->mIndividualSelection)) { @@ -729,7 +736,7 @@ void LLManipRotate::drag( S32 x, S32 y ) void LLManipRotate::renderActiveRing( F32 radius, F32 width, const LLColor4& front_color, const LLColor4& back_color) { - LLGLEnable cull_face(GL_CULL_FACE); + LLGLEnable cull_face; { gl_ring(radius, width, back_color, back_color * 0.5f, CIRCLE_STEPS, FALSE); gl_ring(radius, width, back_color, back_color * 0.5f, CIRCLE_STEPS, TRUE); @@ -1209,8 +1216,8 @@ LLQuaternion LLManipRotate::dragUnconstrained( S32 x, S32 y ) F32 dist_from_sphere_center = sqrt(delta_x * delta_x + delta_y * delta_y); LLVector3 axis = mMouseDown % mMouseCur; + F32 angle = atan2(sqrtf(axis * axis), mMouseDown * mMouseCur); axis.normVec(); - F32 angle = acos(mMouseDown * mMouseCur); LLQuaternion sphere_rot( angle, axis ); if (is_approx_zero(1.f - mMouseDown * mMouseCur)) @@ -1270,9 +1277,9 @@ LLVector3 LLManipRotate::getConstraintAxis() else { #ifndef LL_RELEASE_FOR_DOWNLOAD - llerrs << "Got bogus hit part in LLManipRotate::getConstraintAxis():" << mManipPart << llendl; + LL_ERRS() << "Got bogus hit part in LLManipRotate::getConstraintAxis():" << mManipPart << LL_ENDL; #else - llwarns << "Got bogus hit part in LLManipRotate::getConstraintAxis():" << mManipPart << llendl; + LL_WARNS() << "Got bogus hit part in LLManipRotate::getConstraintAxis():" << mManipPart << LL_ENDL; #endif axis.mV[0] = 1.f; } @@ -1493,7 +1500,7 @@ LLQuaternion LLManipRotate::dragConstrained( S32 x, S32 y ) F32 mouse_angle = fmodf(atan2(projected_mouse * axis1, projected_mouse * axis2) * RAD_TO_DEG + 360.f, 360.f); F32 relative_mouse_angle = fmodf(mouse_angle + (SNAP_ANGLE_DETENTE / 2), SNAP_ANGLE_INCREMENT); - //fmodf(llround(mouse_angle * RAD_TO_DEG, 7.5f) + 360.f, 360.f); + //fmodf(ll_round(mouse_angle * RAD_TO_DEG, 7.5f) + 360.f, 360.f); LLVector3 object_axis; getObjectAxisClosestToMouse(object_axis); @@ -1577,7 +1584,7 @@ LLQuaternion LLManipRotate::dragConstrained( S32 x, S32 y ) F32 mouse_angle = fmodf(atan2(projected_mouse * axis1, projected_mouse * axis2) * RAD_TO_DEG + 360.f, 360.f); F32 relative_mouse_angle = fmodf(mouse_angle + (SNAP_ANGLE_DETENTE / 2), SNAP_ANGLE_INCREMENT); - //fmodf(llround(mouse_angle * RAD_TO_DEG, 7.5f) + 360.f, 360.f); + //fmodf(ll_round(mouse_angle * RAD_TO_DEG, 7.5f) + 360.f, 360.f); LLVector3 object_axis; getObjectAxisClosestToMouse(object_axis); @@ -1607,9 +1614,9 @@ LLQuaternion LLManipRotate::dragConstrained( S32 x, S32 y ) mInSnapRegime = FALSE; } - angle = acos(mMouseCur * mMouseDown); - - F32 dir = (mMouseDown % mMouseCur) * constraint_axis; // cross product + LLVector3 cross_product = mMouseDown % mMouseCur; + angle = atan2(sqrtf(cross_product * cross_product), mMouseCur * mMouseDown); + F32 dir = cross_product * constraint_axis; // cross product if( dir < 0.f ) { angle *= -1.f; diff --git a/indra/newview/llmanipscale.cpp b/indra/newview/llmanipscale.cpp index 76aa997754..fedebbd108 100644 --- a/indra/newview/llmanipscale.cpp +++ b/indra/newview/llmanipscale.cpp @@ -54,23 +54,21 @@ #include "llviewerobject.h" #include "llviewerregion.h" #include "llviewerwindow.h" -#include "llwindow.h" #include "llhudrender.h" #include "llworld.h" #include "v2math.h" #include "llvoavatar.h" #include "llmeshrepository.h" +#include "lltrans.h" #include "hippolimits.h" - const F32 MAX_MANIP_SELECT_DISTANCE_SQUARED = 11.f * 11.f; const F32 SNAP_GUIDE_SCREEN_OFFSET = 0.05f; const F32 SNAP_GUIDE_SCREEN_LENGTH = 0.7f; const F32 SELECTED_MANIPULATOR_SCALE = 1.2f; const F32 MANIPULATOR_SCALE_HALF_LIFE = 0.07f; -const S32 NUM_MANIPULATORS = 14; -const LLManip::EManipPart MANIPULATOR_IDS[NUM_MANIPULATORS] = +const LLManip::EManipPart MANIPULATOR_IDS[LLManipScale::NUM_MANIPULATORS] = { LLManip::LL_CORNER_NNN, LLManip::LL_CORNER_NNP, @@ -88,6 +86,25 @@ const LLManip::EManipPart MANIPULATOR_IDS[NUM_MANIPULATORS] = LLManip::LL_FACE_NEGZ }; + +F32 get_default_max_prim_scale(bool is_flora) +{ + return gHippoLimits->getMaxPrimScale(); + /* Singu Note: We must check with the grid + // a bit of a hack, but if it's foilage, we don't want to use the + // new larger scale which would result in giant trees and grass + if (gMeshRepo.meshRezEnabled() && + !is_flora) + { + return DEFAULT_MAX_PRIM_SCALE; + } + else + { + return DEFAULT_MAX_PRIM_SCALE_NO_MESH; + } + */ +} + // static void LLManipScale::setUniform(BOOL b) { @@ -129,18 +146,16 @@ inline void LLManipScale::conditionalHighlight( U32 part, const LLColor4* highli LLColor4 default_highlight( 1.f, 1.f, 1.f, 1.f ); LLColor4 default_normal( 0.7f, 0.7f, 0.7f, 0.6f ); LLColor4 invisible(0.f, 0.f, 0.f, 0.f); - F32 manipulator_scale = 1.f; for (S32 i = 0; i < NUM_MANIPULATORS; i++) { if((U32)MANIPULATOR_IDS[i] == part) { - manipulator_scale = mManipulatorScales[i]; + mScaledBoxHandleSize = mManipulatorScales[i] * mBoxHandleSize[i]; break; } } - mScaledBoxHandleSize = mBoxHandleSize * manipulator_scale; if (mManipPart != (S32)LL_NO_PART && mManipPart != (S32)part) { gGL.color4fv( invisible.mV ); @@ -167,7 +182,6 @@ void LLManipScale::handleSelect() LLManipScale::LLManipScale( LLToolComposite* composite ) : LLManip( std::string("Scale"), composite ), - mBoxHandleSize( 1.f ), mScaledBoxHandleSize( 1.f ), mLastMouseX( -1 ), mLastMouseY( -1 ), @@ -176,21 +190,22 @@ LLManipScale::LLManipScale( LLToolComposite* composite ) mScaleSnapUnit1(1.f), mScaleSnapUnit2(1.f), mSnapRegimeOffset(0.f), + mTickPixelSpacing1(0.f), + mTickPixelSpacing2(0.f), mSnapGuideLength(0.f), - mInSnapRegime(FALSE), - mScaleSnapValue(0.f) + mSnapRegime(SNAP_REGIME_NONE), + mScaleSnappedValue(0.f) { - mManipulatorScales = new F32[NUM_MANIPULATORS]; for (S32 i = 0; i < NUM_MANIPULATORS; i++) { mManipulatorScales[i] = 1.f; + mBoxHandleSize[i] = 1.f; } } LLManipScale::~LLManipScale() { for_each(mProjectedManipulators.begin(), mProjectedManipulators.end(), DeletePointer()); - delete[] mManipulatorScales; } void LLManipScale::render() @@ -198,9 +213,10 @@ void LLManipScale::render() LLGLSUIDefault gls_ui; gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); LLGLDepthTest gls_depth(GL_TRUE); - LLGLEnable gl_blend(GL_BLEND); - LLGLEnable gls_alpha_test(GL_ALPHA_TEST); - + LLGLEnable gl_blend; + LLGLEnable gls_alpha_test; + LLBBox bbox = LLSelectMgr::getInstance()->getBBoxOfSelection(); + if( canAffectSelection() ) { gGL.matrixMode(LLRender::MM_MODELVIEW); @@ -221,42 +237,48 @@ void LLManipScale::render() if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD) { - mBoxHandleSize = BOX_HANDLE_BASE_SIZE * BOX_HANDLE_BASE_FACTOR / (F32) LLViewerCamera::getInstance()->getViewHeightInPixels(); - mBoxHandleSize /= gAgentCamera.mHUDCurZoom; + for (S32 i = 0; i < NUM_MANIPULATORS; i++) + { + mBoxHandleSize[i] = BOX_HANDLE_BASE_SIZE * BOX_HANDLE_BASE_FACTOR / (F32) LLViewerCamera::getInstance()->getViewHeightInPixels(); + mBoxHandleSize[i] /= gAgentCamera.mHUDCurZoom; + } } else { - F32 range_squared = dist_vec_squared(gAgentCamera.getCameraPositionAgent(), center_agent); - F32 range_from_agent_squared = dist_vec_squared(gAgent.getPositionAgent(), center_agent); - - // Don't draw manip if object too far away - if (gSavedSettings.getBOOL("LimitSelectDistance")) + for (S32 i = 0; i < NUM_MANIPULATORS; i++) { - F32 max_select_distance = gSavedSettings.getF32("MaxSelectDistance"); - if (range_from_agent_squared > max_select_distance * max_select_distance) + LLVector3 manipulator_pos = bbox.localToAgent(unitVectorToLocalBBoxExtent(partToUnitVector(MANIPULATOR_IDS[i]), bbox)); + F32 range_squared = dist_vec_squared(gAgentCamera.getCameraPositionAgent(), manipulator_pos); + F32 range_from_agent_squared = dist_vec_squared(gAgent.getPositionAgent(), manipulator_pos); + + // Don't draw manip if object too far away + if (gSavedSettings.getBOOL("LimitSelectDistance")) { - return; + F32 max_select_distance = gSavedSettings.getF32("MaxSelectDistance"); + if (range_from_agent_squared > max_select_distance * max_select_distance) + { + return; + } } - } - if (range_squared > 0.001f * 0.001f) - { - // range != zero - F32 fraction_of_fov = BOX_HANDLE_BASE_SIZE / (F32) LLViewerCamera::getInstance()->getViewHeightInPixels(); - F32 apparent_angle = fraction_of_fov * LLViewerCamera::getInstance()->getView(); // radians - mBoxHandleSize = (F32) sqrtf(range_squared) * tan(apparent_angle) * BOX_HANDLE_BASE_FACTOR; - } - else - { - // range == zero - mBoxHandleSize = BOX_HANDLE_BASE_FACTOR; + if (range_squared > 0.001f * 0.001f) + { + // range != zero + F32 fraction_of_fov = BOX_HANDLE_BASE_SIZE / (F32) LLViewerCamera::getInstance()->getViewHeightInPixels(); + F32 apparent_angle = fraction_of_fov * LLViewerCamera::getInstance()->getView(); // radians + mBoxHandleSize[i] = (F32) sqrtf(range_squared) * tan(apparent_angle) * BOX_HANDLE_BASE_FACTOR; + } + else + { + // range == zero + mBoxHandleSize[i] = BOX_HANDLE_BASE_FACTOR; + } } } //////////////////////////////////////////////////////////////////////// // Draw bounding box - LLBBox bbox = LLSelectMgr::getInstance()->getBBoxOfSelection(); LLVector3 pos_agent = bbox.getPositionAgent(); LLQuaternion rot = bbox.getRotation(); @@ -271,8 +293,8 @@ void LLManipScale::render() { - LLGLEnable poly_offset(GL_POLYGON_OFFSET_FILL); - glPolygonOffset( -2.f, -2.f); + LLGLEnable poly_offset; + gGL.setPolygonOffset( -2.f, -2.f); // JC - Band-aid until edge stretch working similar to side stretch // in non-uniform. @@ -286,7 +308,7 @@ void LLManipScale::render() renderGuidelinesPart( bbox ); } - glPolygonOffset( 0.f, 0.f); + gGL.setPolygonOffset( 0.f, 0.f); } } gGL.popMatrix(); @@ -379,6 +401,7 @@ BOOL LLManipScale::handleMouseUp(S32 x, S32 y, MASK mask) // Might have missed last update due to UPDATE_DELAY timing LLSelectMgr::getInstance()->sendMultipleUpdate( mLastUpdateFlags ); + //gAgent.setObjectTracking(gSavedSettings.getBOOL("TrackFocusObject")); LLSelectMgr::getInstance()->saveSelectedObjectTransform(SELECT_ACTION_TYPE_PICK); } return LLManip::handleMouseUp(x, y, mask); @@ -398,11 +421,11 @@ BOOL LLManipScale::handleHover(S32 x, S32 y, MASK mask) { drag( x, y ); } - lldebugst(LLERR_USER_INPUT) << "hover handled by LLManipScale (active)" << llendl; + LL_DEBUGS("UserInput") << "hover handled by LLManipScale (active)" << LL_ENDL; } else { - mInSnapRegime = FALSE; + mSnapRegime = SNAP_REGIME_NONE; // not dragging... highlightManipulators(x, y); } @@ -410,7 +433,7 @@ BOOL LLManipScale::handleHover(S32 x, S32 y, MASK mask) // Patch up textures, if possible. LLSelectMgr::getInstance()->adjustTexturesByScale(FALSE, getStretchTextures()); - gViewerWindow->getWindow()->setCursor(UI_CURSOR_TOOLSCALE); + gViewerWindow->setCursor(UI_CURSOR_TOOLSCALE); return TRUE; } @@ -429,7 +452,7 @@ void LLManipScale::highlightManipulators(S32 x, S32 y) { LLVector4 translation(bbox.getPositionAgent()); transform.initRotTrans(bbox.getRotation(), translation); - LLMatrix4 cfr(OGL_TO_CFR_ROTATION); + LLMatrix4 cfr(OGL_TO_CFR_ROTATION.getF32ptr()); transform *= cfr; LLMatrix4 window_scale; F32 zoom_level = 2.f * gAgentCamera.mHUDCurZoom; @@ -440,8 +463,8 @@ void LLManipScale::highlightManipulators(S32 x, S32 y) } else { - LLMatrix4 projMatrix = LLViewerCamera::getInstance()->getProjection(); - LLMatrix4 modelView = LLViewerCamera::getInstance()->getModelview(); + LLMatrix4 projMatrix( LLViewerCamera::getInstance()->getProjection().getF32ptr() ); + LLMatrix4 modelView( LLViewerCamera::getInstance()->getModelview().getF32ptr() ); transform.initAll(LLVector3(1.f, 1.f, 1.f), bbox.getRotation(), bbox.getPositionAgent()); transform *= modelView; @@ -497,19 +520,19 @@ void LLManipScale::highlightManipulators(S32 x, S32 y) mHighlightedPart = LL_NO_PART; - for (minpulator_list_t::iterator iter = mProjectedManipulators.begin(); + for (manipulator_list_t::iterator iter = mProjectedManipulators.begin(); iter != mProjectedManipulators.end(); ++iter) { ManipulatorHandle* manipulator = *iter; { - manip2d.setVec(manipulator->mPosition.mV[VX] * half_width, manipulator->mPosition.mV[VY] * half_height); + manip2d.set(manipulator->mPosition.mV[VX] * half_width, manipulator->mPosition.mV[VY] * half_height); delta = manip2d - mousePos; - if (delta.magVecSquared() < MAX_MANIP_SELECT_DISTANCE_SQUARED) + if (delta.lengthSquared() < MAX_MANIP_SELECT_DISTANCE_SQUARED) { mHighlightedPart = manipulator->mManipID; - //llinfos << "Tried: " << mHighlightedPart << llendl; + //LL_INFOS() << "Tried: " << mHighlightedPart << LL_ENDL; break; } } @@ -520,15 +543,15 @@ void LLManipScale::highlightManipulators(S32 x, S32 y) { if (mHighlightedPart == MANIPULATOR_IDS[i]) { - mManipulatorScales[i] = lerp(mManipulatorScales[i], SELECTED_MANIPULATOR_SCALE, LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE)); + mManipulatorScales[i] = lerp(mManipulatorScales[i], SELECTED_MANIPULATOR_SCALE, LLSmoothInterpolation::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE)); } else { - mManipulatorScales[i] = lerp(mManipulatorScales[i], 1.f, LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE)); + mManipulatorScales[i] = lerp(mManipulatorScales[i], 1.f, LLSmoothInterpolation::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE)); } } - lldebugst(LLERR_USER_INPUT) << "hover handled by LLManipScale (inactive)" << llendl; + LL_DEBUGS("UserInput") << "hover handled by LLManipScale (inactive)" << LL_ENDL; } @@ -587,43 +610,55 @@ void LLManipScale::renderFaces( const LLBBox& bbox ) { gGL.color4fv( default_normal_color.mV ); LLGLDepthTest gls_depth(GL_FALSE); - gGL.begin(LLRender::QUADS); + gGL.begin(LLRender::TRIANGLES); { // Face 0 gGL.vertex3f(min.mV[VX], max.mV[VY], max.mV[VZ]); gGL.vertex3f(min.mV[VX], min.mV[VY], max.mV[VZ]); - gGL.vertex3f(max.mV[VX], min.mV[VY], max.mV[VZ]); gGL.vertex3f(max.mV[VX], max.mV[VY], max.mV[VZ]); + gGL.vertex3f(max.mV[VX], max.mV[VY], max.mV[VZ]); + gGL.vertex3f(min.mV[VX], min.mV[VY], max.mV[VZ]); + gGL.vertex3f(max.mV[VX], min.mV[VY], max.mV[VZ]); // Face 1 gGL.vertex3f(max.mV[VX], min.mV[VY], max.mV[VZ]); gGL.vertex3f(max.mV[VX], min.mV[VY], min.mV[VZ]); - gGL.vertex3f(max.mV[VX], max.mV[VY], min.mV[VZ]); gGL.vertex3f(max.mV[VX], max.mV[VY], max.mV[VZ]); + gGL.vertex3f(max.mV[VX], max.mV[VY], max.mV[VZ]); + gGL.vertex3f(max.mV[VX], min.mV[VY], min.mV[VZ]); + gGL.vertex3f(max.mV[VX], max.mV[VY], min.mV[VZ]); // Face 2 gGL.vertex3f(min.mV[VX], max.mV[VY], min.mV[VZ]); gGL.vertex3f(min.mV[VX], max.mV[VY], max.mV[VZ]); - gGL.vertex3f(max.mV[VX], max.mV[VY], max.mV[VZ]); gGL.vertex3f(max.mV[VX], max.mV[VY], min.mV[VZ]); + gGL.vertex3f(max.mV[VX], max.mV[VY], min.mV[VZ]); + gGL.vertex3f(min.mV[VX], max.mV[VY], max.mV[VZ]); + gGL.vertex3f(max.mV[VX], max.mV[VY], max.mV[VZ]); // Face 3 gGL.vertex3f(min.mV[VX], max.mV[VY], max.mV[VZ]); gGL.vertex3f(min.mV[VX], max.mV[VY], min.mV[VZ]); - gGL.vertex3f(min.mV[VX], min.mV[VY], min.mV[VZ]); gGL.vertex3f(min.mV[VX], min.mV[VY], max.mV[VZ]); + gGL.vertex3f(min.mV[VX], min.mV[VY], max.mV[VZ]); + gGL.vertex3f(min.mV[VX], max.mV[VY], min.mV[VZ]); + gGL.vertex3f(min.mV[VX], min.mV[VY], min.mV[VZ]); // Face 4 gGL.vertex3f(min.mV[VX], min.mV[VY], max.mV[VZ]); gGL.vertex3f(min.mV[VX], min.mV[VY], min.mV[VZ]); - gGL.vertex3f(max.mV[VX], min.mV[VY], min.mV[VZ]); gGL.vertex3f(max.mV[VX], min.mV[VY], max.mV[VZ]); + gGL.vertex3f(max.mV[VX], min.mV[VY], max.mV[VZ]); + gGL.vertex3f(min.mV[VX], min.mV[VY], min.mV[VZ]); + gGL.vertex3f(max.mV[VX], min.mV[VY], min.mV[VZ]); // Face 5 gGL.vertex3f(min.mV[VX], min.mV[VY], min.mV[VZ]); gGL.vertex3f(min.mV[VX], max.mV[VY], min.mV[VZ]); - gGL.vertex3f(max.mV[VX], max.mV[VY], min.mV[VZ]); gGL.vertex3f(max.mV[VX], min.mV[VY], min.mV[VZ]); + gGL.vertex3f(max.mV[VX], min.mV[VY], min.mV[VZ]); + gGL.vertex3f(min.mV[VX], max.mV[VY], min.mV[VZ]); + gGL.vertex3f(max.mV[VX], max.mV[VY], min.mV[VZ]); } gGL.end(); } @@ -662,32 +697,32 @@ void LLManipScale::renderFaces( const LLBBox& bbox ) { case 0: conditionalHighlight( LL_FACE_POSZ, &z_highlight_color, &z_normal_color ); - renderAxisHandle( ctr, LLVector3( ctr.mV[VX], ctr.mV[VY], max.mV[VZ] ) ); + renderAxisHandle( LL_FACE_POSZ, ctr, LLVector3( ctr.mV[VX], ctr.mV[VY], max.mV[VZ] ) ); break; case 1: conditionalHighlight( LL_FACE_POSX, &x_highlight_color, &x_normal_color ); - renderAxisHandle( ctr, LLVector3( max.mV[VX], ctr.mV[VY], ctr.mV[VZ] ) ); + renderAxisHandle( LL_FACE_POSX, ctr, LLVector3( max.mV[VX], ctr.mV[VY], ctr.mV[VZ] ) ); break; case 2: conditionalHighlight( LL_FACE_POSY, &y_highlight_color, &y_normal_color ); - renderAxisHandle( ctr, LLVector3( ctr.mV[VX], max.mV[VY], ctr.mV[VZ] ) ); + renderAxisHandle( LL_FACE_POSY, ctr, LLVector3( ctr.mV[VX], max.mV[VY], ctr.mV[VZ] ) ); break; case 3: conditionalHighlight( LL_FACE_NEGX, &x_highlight_color, &x_normal_color ); - renderAxisHandle( ctr, LLVector3( min.mV[VX], ctr.mV[VY], ctr.mV[VZ] ) ); + renderAxisHandle( LL_FACE_NEGX, ctr, LLVector3( min.mV[VX], ctr.mV[VY], ctr.mV[VZ] ) ); break; case 4: conditionalHighlight( LL_FACE_NEGY, &y_highlight_color, &y_normal_color ); - renderAxisHandle( ctr, LLVector3( ctr.mV[VX], min.mV[VY], ctr.mV[VZ] ) ); + renderAxisHandle( LL_FACE_NEGY, ctr, LLVector3( ctr.mV[VX], min.mV[VY], ctr.mV[VZ] ) ); break; case 5: conditionalHighlight( LL_FACE_NEGZ, &z_highlight_color, &z_normal_color ); - renderAxisHandle( ctr, LLVector3( ctr.mV[VX], ctr.mV[VY], min.mV[VZ] ) ); + renderAxisHandle( LL_FACE_NEGZ, ctr, LLVector3( ctr.mV[VX], ctr.mV[VY], min.mV[VZ] ) ); break; } } @@ -697,10 +732,10 @@ void LLManipScale::renderFaces( const LLBBox& bbox ) void LLManipScale::renderEdges( const LLBBox& bbox ) { LLVector3 extent = bbox.getExtentLocal(); - F32 edge_width = mBoxHandleSize * .6f; for( U32 part = LL_EDGE_MIN; part <= LL_EDGE_MAX; part++ ) { + F32 edge_width = mBoxHandleSize[part] * .6f; LLVector3 direction = edgeToUnitVector( part ); LLVector3 center_to_edge = unitVectorToLocalBBoxExtent( direction, bbox ); @@ -761,14 +796,14 @@ void LLManipScale::renderBoxHandle( F32 x, F32 y, F32 z ) } -void LLManipScale::renderAxisHandle( const LLVector3& start, const LLVector3& end ) +void LLManipScale::renderAxisHandle( U32 part, const LLVector3& start, const LLVector3& end ) { if( getShowAxes() ) { // Draws a single "jacks" style handle: a long, retangular box from start to end. LLVector3 offset_start = end - start; - offset_start.normVec(); - offset_start = start + mBoxHandleSize * offset_start; + offset_start.normalize(); + offset_start = start + mBoxHandleSize[part] * offset_start; LLVector3 delta = end - offset_start; LLVector3 pos = offset_start + 0.5f * delta; @@ -777,9 +812,9 @@ void LLManipScale::renderAxisHandle( const LLVector3& start, const LLVector3& en { gGL.translatef( pos.mV[VX], pos.mV[VY], pos.mV[VZ] ); gGL.scalef( - mBoxHandleSize + llabs(delta.mV[VX]), - mBoxHandleSize + llabs(delta.mV[VY]), - mBoxHandleSize + llabs(delta.mV[VZ])); + mBoxHandleSize[part] + llabs(delta.mV[VX]), + mBoxHandleSize[part] + llabs(delta.mV[VY]), + mBoxHandleSize[part] + llabs(delta.mV[VZ])); gBox.render(); } gGL.popMatrix(); @@ -790,7 +825,7 @@ void LLManipScale::renderAxisHandle( const LLVector3& start, const LLVector3& en } } - +// General scale call void LLManipScale::drag( S32 x, S32 y ) { if( (LL_FACE_MIN <= (S32)mManipPart) @@ -798,8 +833,7 @@ void LLManipScale::drag( S32 x, S32 y ) { dragFace( x, y ); } - else - if( (LL_CORNER_MIN <= (S32)mManipPart) + else if( (LL_CORNER_MIN <= (S32)mManipPart) && ((S32)mManipPart <= LL_CORNER_MAX) ) { dragCorner( x, y ); @@ -825,123 +859,86 @@ void LLManipScale::drag( S32 x, S32 y ) gAgentCamera.clearFocusObject(); } -// Scale around the +// Scale on three axis simultaneously void LLManipScale::dragCorner( S32 x, S32 y ) { - LLBBox bbox = LLSelectMgr::getInstance()->getBBoxOfSelection(); - // Suppress scale if mouse hasn't moved. if (x == mLastMouseX && y == mLastMouseY) { - // sendUpdates(TRUE,TRUE,TRUE); return; } - mLastMouseX = x; mLastMouseY = y; - LLVector3d drag_start_point_global = mDragStartPointGlobal; - LLVector3d drag_start_center_global = mDragStartCenterGlobal; - LLVector3 drag_start_point_agent = gAgent.getPosAgentFromGlobal(drag_start_point_global); - LLVector3 drag_start_center_agent = gAgent.getPosAgentFromGlobal(drag_start_center_global); + LLVector3 drag_start_point_agent = gAgent.getPosAgentFromGlobal(mDragStartPointGlobal); + LLVector3 drag_start_center_agent = gAgent.getPosAgentFromGlobal(mDragStartCenterGlobal); LLVector3d drag_start_dir_d; - drag_start_dir_d.setVec(drag_start_point_global - drag_start_center_global); - LLVector3 drag_start_dir_f; - drag_start_dir_f.setVec(drag_start_dir_d); + drag_start_dir_d.set(mDragStartPointGlobal - mDragStartCenterGlobal); F32 s = 0; F32 t = 0; - nearestPointOnLineFromMouse(x, y, drag_start_center_agent, drag_start_point_agent, s, t ); - F32 drag_start_dist = dist_vec(drag_start_point_agent, drag_start_center_agent); - if( s <= 0 ) // we only care about intersections in front of the camera { return; } + mDragPointGlobal = lerp(mDragStartCenterGlobal, mDragStartPointGlobal, t); - LLVector3d drag_point_global = drag_start_center_global + t * drag_start_dir_d; - - F32 scale_factor = t; - + LLBBox bbox = LLSelectMgr::getInstance()->getBBoxOfSelection(); + F32 scale_factor = 1.f; + F32 max_scale = partToMaxScale(mManipPart, bbox); + F32 min_scale = partToMinScale(mManipPart, bbox); BOOL uniform = LLManipScale::getUniform(); - if( !uniform ) - { - scale_factor = 0.5f + (scale_factor * 0.5f); - } - // check for snapping - LLVector3 drag_center_agent = gAgent.getPosAgentFromGlobal(drag_point_global); LLVector3 mouse_on_plane1; - getMousePointOnPlaneAgent(mouse_on_plane1, x, y, drag_center_agent, mScalePlaneNormal1); - LLVector3 mouse_on_plane2; - getMousePointOnPlaneAgent(mouse_on_plane2, x, y, drag_center_agent, mScalePlaneNormal2); - LLVector3 mouse_dir_1 = mouse_on_plane1 - mScaleCenter; - LLVector3 mouse_dir_2 = mouse_on_plane2 - mScaleCenter; - LLVector3 mouse_to_scale_line_1 = mouse_dir_1 - projected_vec(mouse_dir_1, mScaleDir); - LLVector3 mouse_to_scale_line_2 = mouse_dir_2 - projected_vec(mouse_dir_2, mScaleDir); - LLVector3 mouse_to_scale_line_dir_1 = mouse_to_scale_line_1; - mouse_to_scale_line_dir_1.normVec(); - if (mouse_to_scale_line_dir_1 * mSnapGuideDir1 < 0.f) - { - // need to keep sign of mouse offset wrt to snap guide direction - mouse_to_scale_line_dir_1 *= -1.f; - } - LLVector3 mouse_to_scale_line_dir_2 = mouse_to_scale_line_2; - mouse_to_scale_line_dir_2.normVec(); - if (mouse_to_scale_line_dir_2 * mSnapGuideDir2 < 0.f) - { - // need to keep sign of mouse offset wrt to snap guide direction - mouse_to_scale_line_dir_2 *= -1.f; - } + getMousePointOnPlaneAgent(mouse_on_plane1, x, y, mScaleCenter, mScalePlaneNormal1); + mouse_on_plane1 -= mScaleCenter; - F32 snap_dir_dot_mouse_offset1 = mSnapGuideDir1 * mouse_to_scale_line_dir_1; - F32 snap_dir_dot_mouse_offset2 = mSnapGuideDir2 * mouse_to_scale_line_dir_2; - - F32 dist_from_scale_line_1 = mouse_to_scale_line_1 * mouse_to_scale_line_dir_1; - F32 dist_from_scale_line_2 = mouse_to_scale_line_2 * mouse_to_scale_line_dir_2; + LLVector3 mouse_on_plane2; + getMousePointOnPlaneAgent(mouse_on_plane2, x, y, mScaleCenter, mScalePlaneNormal2); + mouse_on_plane2 -= mScaleCenter; - F32 max_scale = partToMaxScale(mManipPart, bbox); - F32 min_scale = partToMinScale(mManipPart, bbox); + LLVector3 projected_drag_pos1 = inverse_projected_vec(mScaleDir, orthogonal_component(mouse_on_plane1, mSnapGuideDir1)); + LLVector3 projected_drag_pos2 = inverse_projected_vec(mScaleDir, orthogonal_component(mouse_on_plane2, mSnapGuideDir2)); BOOL snap_enabled = gSavedSettings.getBOOL("SnapEnabled"); - if (snap_enabled && dist_from_scale_line_1 > mSnapRegimeOffset * snap_dir_dot_mouse_offset1) + if (snap_enabled && (mouse_on_plane1 - projected_drag_pos1) * mSnapGuideDir1 > mSnapRegimeOffset) { - mInSnapRegime = TRUE; - LLVector3 projected_drag_pos = mouse_on_plane1 - (dist_from_scale_line_1 / snap_dir_dot_mouse_offset1) * mSnapGuideDir1; - F32 drag_dist = (projected_drag_pos - mScaleCenter) * mScaleDir; + F32 drag_dist = mScaleDir * projected_drag_pos1; // Projecting the drag position allows for negative results, vs using the length which will result in a "reverse scaling" bug. - F32 cur_subdivisions = llclamp(getSubdivisionLevel(projected_drag_pos, mScaleDir, mScaleSnapUnit1), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel); + F32 cur_subdivisions = llclamp(getSubdivisionLevel(mScaleCenter + projected_drag_pos1, mScaleDir, mScaleSnapUnit1, mTickPixelSpacing1), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel); F32 snap_dist = mScaleSnapUnit1 / (2.f * cur_subdivisions); F32 relative_snap_dist = fmodf(drag_dist + snap_dist, mScaleSnapUnit1 / cur_subdivisions); - mScaleSnapValue = llclamp((drag_dist - (relative_snap_dist - snap_dist)), min_scale, max_scale); + mScaleSnappedValue = llclamp((drag_dist - (relative_snap_dist - snap_dist)), min_scale, max_scale); + scale_factor = mScaleSnappedValue / dist_vec(drag_start_point_agent, drag_start_center_agent); + mScaleSnappedValue /= mScaleSnapUnit1 * 2.f; + mSnapRegime = SNAP_REGIME_UPPER; - scale_factor = mScaleSnapValue / drag_start_dist; if( !uniform ) { scale_factor *= 0.5f; } } - else if (snap_enabled && dist_from_scale_line_2 > mSnapRegimeOffset * snap_dir_dot_mouse_offset2) + else if (snap_enabled && (mouse_on_plane2 - projected_drag_pos2) * mSnapGuideDir2 > mSnapRegimeOffset ) { - mInSnapRegime = TRUE; - LLVector3 projected_drag_pos = mouse_on_plane2 - (dist_from_scale_line_2 / snap_dir_dot_mouse_offset2) * mSnapGuideDir2; - F32 drag_dist = (projected_drag_pos - mScaleCenter) * mScaleDir; + F32 drag_dist = mScaleDir * projected_drag_pos2; // Projecting the drag position allows for negative results, vs using the length which will result in a "reverse scaling" bug. - F32 cur_subdivisions = llclamp(getSubdivisionLevel(projected_drag_pos, mScaleDir, mScaleSnapUnit2), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel); + F32 cur_subdivisions = llclamp(getSubdivisionLevel(mScaleCenter + projected_drag_pos2, mScaleDir, mScaleSnapUnit2, mTickPixelSpacing2), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel); F32 snap_dist = mScaleSnapUnit2 / (2.f * cur_subdivisions); F32 relative_snap_dist = fmodf(drag_dist + snap_dist, mScaleSnapUnit2 / cur_subdivisions); - mScaleSnapValue = llclamp((drag_dist - (relative_snap_dist - snap_dist)), min_scale, max_scale); + mScaleSnappedValue = llclamp((drag_dist - (relative_snap_dist - snap_dist)), min_scale, max_scale); + scale_factor = mScaleSnappedValue / dist_vec(drag_start_point_agent, drag_start_center_agent); + mScaleSnappedValue /= mScaleSnapUnit2 * 2.f; + mSnapRegime = SNAP_REGIME_LOWER; - scale_factor = mScaleSnapValue / drag_start_dist; if( !uniform ) { scale_factor *= 0.5f; @@ -949,14 +946,18 @@ void LLManipScale::dragCorner( S32 x, S32 y ) } else { - mInSnapRegime = FALSE; + mSnapRegime = SNAP_REGIME_NONE; + scale_factor = t; + if (!uniform) + { + scale_factor = 0.5f + (scale_factor * 0.5f); + } } - F32 max_prim_scale = gHippoLimits->getMaxPrimScale(); - F32 min_prim_scale = gHippoLimits->getMinPrimScale(); + F32 MIN_PRIM_SCALE = gHippoLimits->getMinPrimScale(); - F32 max_scale_factor = max_prim_scale / min_prim_scale; - F32 min_scale_factor = min_prim_scale / max_prim_scale; + F32 max_scale_factor = get_default_max_prim_scale() / MIN_PRIM_SCALE; + F32 min_scale_factor = MIN_PRIM_SCALE / get_default_max_prim_scale(); // find max and min scale factors that will make biggest object hit max absolute scale and smallest object hit min absolute scale for (LLObjectSelection::iterator iter = mObjectSelection->begin(); @@ -971,10 +972,10 @@ void LLManipScale::dragCorner( S32 x, S32 y ) { const LLVector3& scale = selectNode->mSavedScale; - F32 cur_max_scale_factor = llmin( max_prim_scale / scale.mV[VX], max_prim_scale / scale.mV[VY], max_prim_scale / scale.mV[VZ] ); + F32 cur_max_scale_factor = llmin( get_default_max_prim_scale(LLPickInfo::isFlora(cur)) / scale.mV[VX], get_default_max_prim_scale(LLPickInfo::isFlora(cur)) / scale.mV[VY], get_default_max_prim_scale(LLPickInfo::isFlora(cur)) / scale.mV[VZ] ); max_scale_factor = llmin( max_scale_factor, cur_max_scale_factor ); - F32 cur_min_scale_factor = llmax( min_prim_scale / scale.mV[VX], min_prim_scale / scale.mV[VY], min_prim_scale / scale.mV[VZ] ); + F32 cur_min_scale_factor = llmax( MIN_PRIM_SCALE / scale.mV[VX], MIN_PRIM_SCALE / scale.mV[VY], MIN_PRIM_SCALE / scale.mV[VZ] ); min_scale_factor = llmax( min_scale_factor, cur_min_scale_factor ); } } @@ -1056,19 +1057,14 @@ void LLManipScale::dragCorner( S32 x, S32 y ) rebuild(cur); } } - - - - mDragPointGlobal = drag_point_global; } - +// Scale on a single axis void LLManipScale::dragFace( S32 x, S32 y ) { // Suppress scale if mouse hasn't moved. if (x == mLastMouseX && y == mLastMouseY) { - // sendUpdates(TRUE,TRUE,FALSE); return; } @@ -1081,9 +1077,9 @@ void LLManipScale::dragFace( S32 x, S32 y ) LLVector3 drag_start_center_agent = gAgent.getPosAgentFromGlobal(drag_start_center_global); LLVector3d drag_start_dir_d; - drag_start_dir_d.setVec(drag_start_point_global - drag_start_center_global); + drag_start_dir_d.set(drag_start_point_global - drag_start_center_global); LLVector3 drag_start_dir_f; - drag_start_dir_f.setVec(drag_start_dir_d); + drag_start_dir_f.set(drag_start_dir_d); LLBBox bbox = LLSelectMgr::getInstance()->getBBoxOfSelection(); @@ -1127,26 +1123,26 @@ void LLManipScale::dragFace( S32 x, S32 y ) if (snap_enabled && dist_from_scale_line > mSnapRegimeOffset) { - mInSnapRegime = TRUE; + mSnapRegime = static_cast(SNAP_REGIME_UPPER | SNAP_REGIME_LOWER); // A face drag doesn't have split regimes. if (dist_along_scale_line > max_drag_dist) { - mScaleSnapValue = max_drag_dist; + mScaleSnappedValue = max_drag_dist; LLVector3 clamp_point = mScaleCenter + max_drag_dist * mScaleDir; - drag_delta.setVec(clamp_point - drag_start_point_agent); + drag_delta.set(clamp_point - drag_start_point_agent); } else if (dist_along_scale_line < min_drag_dist) { - mScaleSnapValue = min_drag_dist; + mScaleSnappedValue = min_drag_dist; LLVector3 clamp_point = mScaleCenter + min_drag_dist * mScaleDir; - drag_delta.setVec(clamp_point - drag_start_point_agent); + drag_delta.set(clamp_point - drag_start_point_agent); } else { F32 drag_dist = scale_center_to_mouse * mScaleDir; - F32 cur_subdivisions = llclamp(getSubdivisionLevel(mScaleCenter + mScaleDir * drag_dist, mScaleDir, mScaleSnapUnit1), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel); + F32 cur_subdivisions = llclamp(getSubdivisionLevel(mScaleCenter + mScaleDir * drag_dist, mScaleDir, mScaleSnapUnit1, mTickPixelSpacing1), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel); F32 snap_dist = mScaleSnapUnit1 / (2.f * cur_subdivisions); F32 relative_snap_dist = fmodf(drag_dist + snap_dist, mScaleSnapUnit1 / cur_subdivisions); relative_snap_dist -= snap_dist; @@ -1160,7 +1156,7 @@ void LLManipScale::dragFace( S32 x, S32 y ) drag_dist - max_drag_dist, drag_dist - min_drag_dist); - mScaleSnapValue = drag_dist - relative_snap_dist; + mScaleSnappedValue = (drag_dist - relative_snap_dist) / (mScaleSnapUnit1 * 2.f); if (llabs(relative_snap_dist) < snap_dist) { @@ -1176,7 +1172,7 @@ void LLManipScale::dragFace( S32 x, S32 y ) } else { - mInSnapRegime = FALSE; + mSnapRegime = SNAP_REGIME_NONE; } LLVector3 dir_agent; @@ -1259,7 +1255,7 @@ void LLManipScale::stretchFace( const LLVector3& drag_start_agent, const LLVecto S32 axis_index = axis.mV[0] ? 0 : (axis.mV[1] ? 1 : 2 ); LLVector3 delta_local = end_local - start_local; - F32 delta_local_mag = delta_local.magVec(); + F32 delta_local_mag = delta_local.length(); LLVector3 dir_local; if (delta_local_mag == 0.f) { @@ -1272,7 +1268,7 @@ void LLManipScale::stretchFace( const LLVector3& drag_start_agent, const LLVecto F32 denom = axis * dir_local; F32 desired_delta_size = is_approx_zero(denom) ? 0.f : (delta_local_mag / denom); // in meters - F32 desired_scale = llclamp(selectNode->mSavedScale.mV[axis_index] + desired_delta_size, gHippoLimits->getMinPrimScale(), gHippoLimits->getMaxPrimScale()); + F32 desired_scale = llclamp(selectNode->mSavedScale.mV[axis_index] + desired_delta_size, gHippoLimits->getMinPrimScale(), get_default_max_prim_scale(LLPickInfo::isFlora(cur))); // propagate scale constraint back to position offset desired_delta_size = desired_scale - selectNode->mSavedScale.mV[axis_index]; // propagate constraint back to position @@ -1285,7 +1281,7 @@ void LLManipScale::stretchFace( const LLVector3& drag_start_agent, const LLVecto { LLVector3 delta_pos_local = axis * (0.5f * desired_delta_size); LLVector3d delta_pos_global; - delta_pos_global.setVec(cur_bbox.localToAgent( delta_pos_local ) - cur_bbox.getCenterAgent()); + delta_pos_global.set(cur_bbox.localToAgent( delta_pos_local ) - cur_bbox.getCenterAgent()); LLVector3 cur_pos = cur->getPositionEdit(); if (cur->isRootEdit() && !cur->isAttachment()) @@ -1343,8 +1339,8 @@ void LLManipScale::renderGuidelinesPart( const LLBBox& bbox ) } guideline_end -= guideline_start; - guideline_end.normVec(); - guideline_end *= LLWorld::getInstance()->getRegionWidthInMeters(); + guideline_end.normalize(); + guideline_end *= gAgent.getRegion()->getWidth(); guideline_end += guideline_start; { @@ -1364,26 +1360,27 @@ void LLManipScale::updateSnapGuides(const LLBBox& bbox) LLQuaternion grid_rotation; LLSelectMgr::getInstance()->getGrid(grid_origin, grid_rotation, grid_scale); + bool uniform = LLManipScale::getUniform(); + LLVector3 box_corner_agent = bbox.localToAgent(unitVectorToLocalBBoxExtent( partToUnitVector( mManipPart ), bbox )); - mScaleCenter = getUniform() ? bbox.getCenterAgent() : bbox.localToAgent(unitVectorToLocalBBoxExtent( -1.f * partToUnitVector( mManipPart ), bbox )); + mScaleCenter = uniform ? bbox.getCenterAgent() : bbox.localToAgent(unitVectorToLocalBBoxExtent( -1.f * partToUnitVector( mManipPart ), bbox )); mScaleDir = box_corner_agent - mScaleCenter; - mScaleDir.normVec(); + mScaleDir.normalize(); if(mObjectSelection->getSelectType() == SELECT_TYPE_HUD) { mSnapRegimeOffset = SNAP_GUIDE_SCREEN_OFFSET / gAgentCamera.mHUDCurZoom; - } else { - F32 object_distance = dist_vec(mScaleCenter, LLViewerCamera::getInstance()->getOrigin()); + F32 object_distance = dist_vec(box_corner_agent, LLViewerCamera::getInstance()->getOrigin()); mSnapRegimeOffset = (SNAP_GUIDE_SCREEN_OFFSET * gViewerWindow->getWorldViewWidthRaw() * object_distance) / LLViewerCamera::getInstance()->getPixelMeterRatio(); } LLVector3 cam_at_axis; F32 snap_guide_length; if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD) { - cam_at_axis.setVec(1.f, 0.f, 0.f); + cam_at_axis.set(1.f, 0.f, 0.f); snap_guide_length = SNAP_GUIDE_SCREEN_LENGTH / gAgentCamera.mHUDCurZoom; } else @@ -1396,18 +1393,17 @@ void LLManipScale::updateSnapGuides(const LLBBox& bbox) mSnapGuideLength = snap_guide_length / llmax(0.1f, (llmin(mSnapGuideDir1 * cam_at_axis, mSnapGuideDir2 * cam_at_axis))); LLVector3 off_axis_dir = mScaleDir % cam_at_axis; - off_axis_dir.normVec(); + off_axis_dir.normalize(); if( (LL_FACE_MIN <= (S32)mManipPart) && ((S32)mManipPart <= LL_FACE_MAX) ) { - LLVector3 object_scale = bbox.getMaxLocal(); - object_scale.scaleVec(off_axis_dir * ~bbox.getRotation()); - object_scale.abs(); - if (object_scale.mV[VX] > object_scale.mV[VY] && object_scale.mV[VX] > object_scale.mV[VZ]) + LLVector3 bbox_relative_cam_dir = off_axis_dir * ~bbox.getRotation(); + bbox_relative_cam_dir.abs(); + if (bbox_relative_cam_dir.mV[VX] > bbox_relative_cam_dir.mV[VY] && bbox_relative_cam_dir.mV[VX] > bbox_relative_cam_dir.mV[VZ]) { mSnapGuideDir1 = LLVector3::x_axis * bbox.getRotation(); } - else if (object_scale.mV[VY] > object_scale.mV[VZ]) + else if (bbox_relative_cam_dir.mV[VY] > bbox_relative_cam_dir.mV[VZ]) { mSnapGuideDir1 = LLVector3::y_axis * bbox.getRotation(); } @@ -1417,7 +1413,7 @@ void LLManipScale::updateSnapGuides(const LLBBox& bbox) } LLVector3 scale_snap = grid_scale; - mScaleSnapUnit1 = scale_snap.scaleVec(partToUnitVector( mManipPart )).magVec(); + mScaleSnapUnit1 = scale_snap.scaleVec(partToUnitVector( mManipPart )).length(); mScaleSnapUnit2 = mScaleSnapUnit1; mSnapGuideDir1 *= mSnapGuideDir1 * LLViewerCamera::getInstance()->getUpAxis() > 0.f ? 1.f : -1.f; mSnapGuideDir2 = mSnapGuideDir1 * -1.f; @@ -1426,7 +1422,6 @@ void LLManipScale::updateSnapGuides(const LLBBox& bbox) } else if( (LL_CORNER_MIN <= (S32)mManipPart) && ((S32)mManipPart <= LL_CORNER_MAX) ) { - LLVector3 local_scale_dir = partToUnitVector( mManipPart ); LLVector3 local_camera_dir; if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD) { @@ -1434,74 +1429,133 @@ void LLManipScale::updateSnapGuides(const LLBBox& bbox) } else { - local_camera_dir = (LLViewerCamera::getInstance()->getOrigin() - bbox.getCenterAgent()) * ~bbox.getRotation(); - local_camera_dir.normVec(); - } - local_scale_dir -= projected_vec(local_scale_dir, local_camera_dir); - local_scale_dir.normVec(); - LLVector3 x_axis_proj_camera = LLVector3::x_axis - projected_vec(LLVector3::x_axis, local_camera_dir); - x_axis_proj_camera.normVec(); - LLVector3 y_axis_proj_camera = LLVector3::y_axis - projected_vec(LLVector3::y_axis, local_camera_dir); - y_axis_proj_camera.normVec(); - LLVector3 z_axis_proj_camera = LLVector3::z_axis - projected_vec(LLVector3::z_axis, local_camera_dir); - z_axis_proj_camera.normVec(); - F32 x_axis_proj = llabs(local_scale_dir * x_axis_proj_camera); - F32 y_axis_proj = llabs(local_scale_dir * y_axis_proj_camera); - F32 z_axis_proj = llabs(local_scale_dir * z_axis_proj_camera); - - if (x_axis_proj > y_axis_proj && x_axis_proj > z_axis_proj) - { - mSnapGuideDir1 = LLVector3::y_axis; - mScaleSnapUnit2 = grid_scale.mV[VY]; - mSnapGuideDir2 = LLVector3::z_axis; - mScaleSnapUnit1 = grid_scale.mV[VZ]; - } - else if (y_axis_proj > z_axis_proj) - { - mSnapGuideDir1 = LLVector3::x_axis; - mScaleSnapUnit2 = grid_scale.mV[VX]; - mSnapGuideDir2 = LLVector3::z_axis; - mScaleSnapUnit1 = grid_scale.mV[VZ]; - } - else - { - mSnapGuideDir1 = LLVector3::x_axis; - mScaleSnapUnit2 = grid_scale.mV[VX]; - mSnapGuideDir2 = LLVector3::y_axis; - mScaleSnapUnit1 = grid_scale.mV[VY]; + local_camera_dir = (LLViewerCamera::getInstance()->getOrigin() - box_corner_agent) * ~bbox.getRotation(); + local_camera_dir.normalize(); } - LLVector3 snap_guide_flip(1.f, 1.f, 1.f); + LLVector3 axis_flip; switch (mManipPart) { case LL_CORNER_NNN: + axis_flip.set(1.f, 1.f, 1.f); break; case LL_CORNER_NNP: - snap_guide_flip.setVec(1.f, 1.f, -1.f); + axis_flip.set(1.f, 1.f, -1.f); break; case LL_CORNER_NPN: - snap_guide_flip.setVec(1.f, -1.f, 1.f); + axis_flip.set(1.f, -1.f, 1.f); break; case LL_CORNER_NPP: - snap_guide_flip.setVec(1.f, -1.f, -1.f); + axis_flip.set(1.f, -1.f, -1.f); break; case LL_CORNER_PNN: - snap_guide_flip.setVec(-1.f, 1.f, 1.f); + axis_flip.set(-1.f, 1.f, 1.f); break; case LL_CORNER_PNP: - snap_guide_flip.setVec(-1.f, 1.f, -1.f); + axis_flip.set(-1.f, 1.f, -1.f); break; case LL_CORNER_PPN: - snap_guide_flip.setVec(-1.f, -1.f, 1.f); + axis_flip.set(-1.f, -1.f, 1.f); break; case LL_CORNER_PPP: - snap_guide_flip.setVec(-1.f, -1.f, -1.f); + axis_flip.set(-1.f, -1.f, -1.f); + break; + default: + break; + } + + // account for which side of the object the camera is located and negate appropriate axes + local_camera_dir.scaleVec(axis_flip); + + // normalize to object scale + LLVector3 bbox_extent = bbox.getExtentLocal(); + local_camera_dir.scaleVec(LLVector3(1.f / bbox_extent.mV[VX], 1.f / bbox_extent.mV[VY], 1.f / bbox_extent.mV[VZ])); + + S32 scale_face = -1; + + if ((local_camera_dir.mV[VX] > 0.f) == (local_camera_dir.mV[VY] > 0.f)) + { + if ((local_camera_dir.mV[VZ] > 0.f) == (local_camera_dir.mV[VY] > 0.f)) + { + LLVector3 local_camera_dir_abs = local_camera_dir; + local_camera_dir_abs.abs(); + // all neighboring faces of bbox are pointing towards camera or away from camera + // use largest magnitude face for snap guides + if (local_camera_dir_abs.mV[VX] > local_camera_dir_abs.mV[VY]) + { + if (local_camera_dir_abs.mV[VX] > local_camera_dir_abs.mV[VZ]) + { + scale_face = VX; + } + else + { + scale_face = VZ; + } + } + else // y > x + { + if (local_camera_dir_abs.mV[VY] > local_camera_dir_abs.mV[VZ]) + { + scale_face = VY; + } + else + { + scale_face = VZ; + } + } + } + else + { + // z axis facing opposite direction from x and y relative to camera, use x and y for snap guides + scale_face = VZ; + } + } + else // x and y axes are facing in opposite directions relative to camera + { + if ((local_camera_dir.mV[VZ] > 0.f) == (local_camera_dir.mV[VY] > 0.f)) + { + // x axis facing opposite direction from y and z relative to camera, use y and z for snap guides + scale_face = VX; + } + else + { + // y axis facing opposite direction from x and z relative to camera, use x and z for snap guides + scale_face = VY; + } + } + + switch(scale_face) + { + case VX: + // x axis face being scaled, use y and z for snap guides + mSnapGuideDir1 = LLVector3::y_axis.scaledVec(axis_flip); + mScaleSnapUnit1 = grid_scale.mV[VZ]; + mSnapGuideDir2 = LLVector3::z_axis.scaledVec(axis_flip); + mScaleSnapUnit2 = grid_scale.mV[VY]; + break; + case VY: + // y axis facing being scaled, use x and z for snap guides + mSnapGuideDir1 = LLVector3::x_axis.scaledVec(axis_flip); + mScaleSnapUnit1 = grid_scale.mV[VZ]; + mSnapGuideDir2 = LLVector3::z_axis.scaledVec(axis_flip); + mScaleSnapUnit2 = grid_scale.mV[VX]; + break; + case VZ: + // z axis facing being scaled, use x and y for snap guides + mSnapGuideDir1 = LLVector3::x_axis.scaledVec(axis_flip); + mScaleSnapUnit1 = grid_scale.mV[VY]; + mSnapGuideDir2 = LLVector3::y_axis.scaledVec(axis_flip); + mScaleSnapUnit2 = grid_scale.mV[VX]; break; default: + mSnapGuideDir1.setZero(); + mScaleSnapUnit1 = 0.f; + + mSnapGuideDir2.setZero(); + mScaleSnapUnit2 = 0.f; break; } - mSnapGuideDir1.scaleVec(snap_guide_flip); - mSnapGuideDir2.scaleVec(snap_guide_flip); + mSnapGuideDir1.rotVec(bbox.getRotation()); mSnapGuideDir2.rotVec(bbox.getRotation()); mSnapDir1 = -1.f * mSnapGuideDir2; @@ -1509,13 +1563,22 @@ void LLManipScale::updateSnapGuides(const LLBBox& bbox) } mScalePlaneNormal1 = mSnapGuideDir1 % mScaleDir; - mScalePlaneNormal1.normVec(); + mScalePlaneNormal1.normalize(); mScalePlaneNormal2 = mSnapGuideDir2 % mScaleDir; - mScalePlaneNormal2.normVec(); + mScalePlaneNormal2.normalize(); mScaleSnapUnit1 = mScaleSnapUnit1 / (mSnapDir1 * mScaleDir); mScaleSnapUnit2 = mScaleSnapUnit2 / (mSnapDir2 * mScaleDir); + + mTickPixelSpacing1 = ll_round((F32)MIN_DIVISION_PIXEL_WIDTH / (mScaleDir % mSnapGuideDir1).length()); + mTickPixelSpacing2 = ll_round((F32)MIN_DIVISION_PIXEL_WIDTH / (mScaleDir % mSnapGuideDir2).length()); + + if (uniform) + { + mScaleSnapUnit1 *= 0.5f; + mScaleSnapUnit2 *= 0.5f; + } } void LLManipScale::renderSnapGuides(const LLBBox& bbox) @@ -1526,7 +1589,6 @@ void LLManipScale::renderSnapGuides(const LLBBox& bbox) return; } - F32 max_subdivisions = sGridMaxSubdivisionLevel; static const LLCachedControl grid_alpha("GridOpacity",1.f); F32 max_point_on_scale_line = partToMaxScale(mManipPart, bbox); @@ -1540,9 +1602,9 @@ void LLManipScale::renderSnapGuides(const LLBBox& bbox) LLColor4 tick_color = setupSnapGuideRenderPass(pass); gGL.begin(LLRender::LINES); - LLVector3 line_mid = mScaleCenter + (mScaleSnapValue * mScaleDir) + (mSnapGuideDir1 * mSnapRegimeOffset); - LLVector3 line_start = line_mid - (mScaleDir * (llmin(mScaleSnapValue, mSnapGuideLength * 0.5f))); - LLVector3 line_end = line_mid + (mScaleDir * llmin(max_point_on_scale_line - mScaleSnapValue, mSnapGuideLength * 0.5f)); + LLVector3 line_mid = mScaleCenter + (mScaleSnappedValue * mScaleDir) + (mSnapGuideDir1 * mSnapRegimeOffset); + LLVector3 line_start = line_mid - (mScaleDir * (llmin(mScaleSnappedValue, mSnapGuideLength * 0.5f))); + LLVector3 line_end = line_mid + (mScaleDir * llmin(max_point_on_scale_line - mScaleSnappedValue, mSnapGuideLength * 0.5f)); gGL.color4f(tick_color.mV[VRED], tick_color.mV[VGREEN], tick_color.mV[VBLUE], tick_color.mV[VALPHA] * 0.1f); gGL.vertex3fv(line_start.mV); @@ -1552,9 +1614,9 @@ void LLManipScale::renderSnapGuides(const LLBBox& bbox) gGL.color4f(tick_color.mV[VRED], tick_color.mV[VGREEN], tick_color.mV[VBLUE], tick_color.mV[VALPHA] * 0.1f); gGL.vertex3fv(line_end.mV); - line_mid = mScaleCenter + (mScaleSnapValue * mScaleDir) + (mSnapGuideDir2 * mSnapRegimeOffset); - line_start = line_mid - (mScaleDir * (llmin(mScaleSnapValue, mSnapGuideLength * 0.5f))); - line_end = line_mid + (mScaleDir * llmin(max_point_on_scale_line - mScaleSnapValue, mSnapGuideLength * 0.5f)); + line_mid = mScaleCenter + (mScaleSnappedValue * mScaleDir) + (mSnapGuideDir2 * mSnapRegimeOffset); + line_start = line_mid - (mScaleDir * (llmin(mScaleSnappedValue, mSnapGuideLength * 0.5f))); + line_end = line_mid + (mScaleDir * llmin(max_point_on_scale_line - mScaleSnappedValue, mSnapGuideLength * 0.5f)); gGL.vertex3fv(line_start.mV); gGL.color4fv(tick_color.mV); gGL.vertex3fv(line_mid.mV); @@ -1567,31 +1629,38 @@ void LLManipScale::renderSnapGuides(const LLBBox& bbox) { LLGLDepthTest gls_depth(GL_FALSE); - F32 dist_grid_axis = (drag_point - mScaleCenter) * mScaleDir; + F32 dist_grid_axis = llmax(0.f, (drag_point - mScaleCenter) * mScaleDir); + + F32 smallest_subdivision1 = mScaleSnapUnit1 / sGridMaxSubdivisionLevel; + F32 smallest_subdivision2 = mScaleSnapUnit2 / sGridMaxSubdivisionLevel; + + F32 dist_scale_units_1 = dist_grid_axis / smallest_subdivision1; + F32 dist_scale_units_2 = dist_grid_axis / smallest_subdivision2; + // find distance to nearest smallest grid unit - F32 grid_offset1 = fmodf(dist_grid_axis, mScaleSnapUnit1 / max_subdivisions); - F32 grid_offset2 = fmodf(dist_grid_axis, mScaleSnapUnit2 / max_subdivisions); + F32 grid_multiple1 = llfloor(dist_scale_units_1); + F32 grid_multiple2 = llfloor(dist_scale_units_2); + F32 grid_offset1 = fmodf(dist_grid_axis, smallest_subdivision1); + F32 grid_offset2 = fmodf(dist_grid_axis, smallest_subdivision2); // how many smallest grid units are we away from largest grid scale? - S32 sub_div_offset_1 = llround(fmod(dist_grid_axis - grid_offset1, mScaleSnapUnit1 / sGridMinSubdivisionLevel) / (mScaleSnapUnit1 / max_subdivisions)); - S32 sub_div_offset_2 = llround(fmod(dist_grid_axis - grid_offset2, mScaleSnapUnit2 / sGridMinSubdivisionLevel) / (mScaleSnapUnit2 / max_subdivisions)); + S32 sub_div_offset_1 = ll_round(fmod(dist_grid_axis - grid_offset1, mScaleSnapUnit1 / sGridMinSubdivisionLevel) / smallest_subdivision1); + S32 sub_div_offset_2 = ll_round(fmod(dist_grid_axis - grid_offset2, mScaleSnapUnit2 / sGridMinSubdivisionLevel) / smallest_subdivision2); - S32 num_ticks_per_side1 = llmax(1, lltrunc(0.5f * mSnapGuideLength / (mScaleSnapUnit1 / max_subdivisions))); - S32 num_ticks_per_side2 = llmax(1, lltrunc(0.5f * mSnapGuideLength / (mScaleSnapUnit2 / max_subdivisions))); - F32 dist_scale_units_1 = dist_grid_axis / (mScaleSnapUnit1 / max_subdivisions); - F32 dist_scale_units_2 = dist_grid_axis / (mScaleSnapUnit2 / max_subdivisions); + S32 num_ticks_per_side1 = llmax(1, lltrunc(0.5f * mSnapGuideLength / smallest_subdivision1)); + S32 num_ticks_per_side2 = llmax(1, lltrunc(0.5f * mSnapGuideLength / smallest_subdivision2)); S32 ticks_from_scale_center_1 = lltrunc(dist_scale_units_1); S32 ticks_from_scale_center_2 = lltrunc(dist_scale_units_2); - S32 max_ticks1 = llceil(max_point_on_scale_line / (mScaleSnapUnit1 / max_subdivisions) - dist_scale_units_1); - S32 max_ticks2 = llceil(max_point_on_scale_line / (mScaleSnapUnit2 / max_subdivisions) - dist_scale_units_2); + S32 max_ticks1 = llceil(max_point_on_scale_line / smallest_subdivision1 - dist_scale_units_1); + S32 max_ticks2 = llceil(max_point_on_scale_line / smallest_subdivision2 - dist_scale_units_2); S32 start_tick = 0; S32 stop_tick = 0; - if (mInSnapRegime) + if (mSnapRegime != SNAP_REGIME_NONE) { // draw snap guide line gGL.begin(LLRender::LINES); - LLVector3 snap_line_center = mScaleCenter + (mScaleSnapValue * mScaleDir); + LLVector3 snap_line_center = bbox.localToAgent(unitVectorToLocalBBoxExtent( partToUnitVector( mManipPart ), bbox )); LLVector3 snap_line_start = snap_line_center + (mSnapGuideDir1 * mSnapRegimeOffset); LLVector3 snap_line_end = snap_line_center + (mSnapGuideDir2 * mSnapRegimeOffset); @@ -1613,24 +1682,24 @@ void LLManipScale::renderSnapGuides(const LLBBox& bbox) LLVector3 arrow_span = mScaleDir; arrow_dir = snap_line_start - snap_line_center; - arrow_dir.normVec(); - gGL.vertex3fv((snap_line_start + arrow_dir * mBoxHandleSize).mV); - gGL.vertex3fv((snap_line_start + arrow_span * mBoxHandleSize).mV); - gGL.vertex3fv((snap_line_start - arrow_span * mBoxHandleSize).mV); + arrow_dir.normalize(); + gGL.vertex3fv((snap_line_start + arrow_dir * mSnapRegimeOffset * 0.1f).mV); + gGL.vertex3fv((snap_line_start + arrow_span * mSnapRegimeOffset * 0.1f).mV); + gGL.vertex3fv((snap_line_start - arrow_span * mSnapRegimeOffset * 0.1f).mV); arrow_dir = snap_line_end - snap_line_center; - arrow_dir.normVec(); - gGL.vertex3fv((snap_line_end + arrow_dir * mBoxHandleSize).mV); - gGL.vertex3fv((snap_line_end + arrow_span * mBoxHandleSize).mV); - gGL.vertex3fv((snap_line_end - arrow_span * mBoxHandleSize).mV); + arrow_dir.normalize(); + gGL.vertex3fv((snap_line_end + arrow_dir * mSnapRegimeOffset * 0.1f).mV); + gGL.vertex3fv((snap_line_end + arrow_span * mSnapRegimeOffset * 0.1f).mV); + gGL.vertex3fv((snap_line_end - arrow_span * mSnapRegimeOffset * 0.1f).mV); } gGL.end(); } LLVector2 screen_translate_axis(llabs(mScaleDir * LLViewerCamera::getInstance()->getLeftAxis()), llabs(mScaleDir * LLViewerCamera::getInstance()->getUpAxis())); - screen_translate_axis.normVec(); + screen_translate_axis.normalize(); - S32 tick_label_spacing = llround(screen_translate_axis * sTickLabelSpacing); + S32 tick_label_spacing = ll_round(screen_translate_axis * sTickLabelSpacing); for (pass = 0; pass < 3; pass++) { @@ -1644,17 +1713,17 @@ void LLManipScale::renderSnapGuides(const LLBBox& bbox) for (S32 i = start_tick; i <= stop_tick; i++) { F32 alpha = (1.f - (1.f * ((F32)llabs(i) / (F32)num_ticks_per_side1))); - LLVector3 tick_pos = drag_point + (mScaleDir * (mScaleSnapUnit1 / max_subdivisions * (F32)i - grid_offset1)); + LLVector3 tick_pos = mScaleCenter + (mScaleDir * (grid_multiple1 + i) * smallest_subdivision1); - F32 cur_subdivisions = llclamp(getSubdivisionLevel(tick_pos, mScaleDir, mScaleSnapUnit1), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel); + F32 cur_subdivisions = llclamp(getSubdivisionLevel(tick_pos, mScaleDir, mScaleSnapUnit1, mTickPixelSpacing1), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel); - if (fmodf((F32)(i + sub_div_offset_1), (max_subdivisions / cur_subdivisions)) != 0.f) + if (fmodf((F32)(i + sub_div_offset_1), (sGridMaxSubdivisionLevel / cur_subdivisions)) != 0.f) { continue; } F32 tick_scale = 1.f; - for (F32 division_level = max_subdivisions; division_level >= sGridMinSubdivisionLevel; division_level /= 2.f) + for (F32 division_level = sGridMaxSubdivisionLevel; division_level >= sGridMinSubdivisionLevel; division_level /= 2.f) { if (fmodf((F32)(i + sub_div_offset_1), division_level) == 0.f) { @@ -1677,17 +1746,17 @@ void LLManipScale::renderSnapGuides(const LLBBox& bbox) for (S32 i = start_tick; i <= stop_tick; i++) { F32 alpha = (1.f - (1.f * ((F32)llabs(i) / (F32)num_ticks_per_side2))); - LLVector3 tick_pos = drag_point + (mScaleDir * (mScaleSnapUnit2 / max_subdivisions * (F32)i - grid_offset2)); + LLVector3 tick_pos = mScaleCenter + (mScaleDir * (grid_multiple2 + i) * smallest_subdivision2); - F32 cur_subdivisions = llclamp(getSubdivisionLevel(tick_pos, mScaleDir, mScaleSnapUnit2), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel); + F32 cur_subdivisions = llclamp(getSubdivisionLevel(tick_pos, mScaleDir, mScaleSnapUnit2, mTickPixelSpacing2), sGridMinSubdivisionLevel, sGridMaxSubdivisionLevel); - if (fmodf((F32)(i + sub_div_offset_2), (max_subdivisions / cur_subdivisions)) != 0.f) + if (fmodf((F32)(i + sub_div_offset_2), (sGridMaxSubdivisionLevel / cur_subdivisions)) != 0.f) { continue; } F32 tick_scale = 1.f; - for (F32 division_level = max_subdivisions; division_level >= sGridMinSubdivisionLevel; division_level /= 2.f) + for (F32 division_level = sGridMaxSubdivisionLevel; division_level >= sGridMinSubdivisionLevel; division_level /= 2.f) { if (fmodf((F32)(i + sub_div_offset_2), division_level) == 0.f) { @@ -1705,21 +1774,21 @@ void LLManipScale::renderSnapGuides(const LLBBox& bbox) gGL.end(); } - // render tick labels + // render upper tick labels start_tick = -(llmin(ticks_from_scale_center_1, num_ticks_per_side1)); stop_tick = llmin(max_ticks1, num_ticks_per_side1); F32 grid_resolution = mObjectSelection->getSelectType() == SELECT_TYPE_HUD ? 0.25f : llmax(gSavedSettings.getF32("GridResolution"), 0.001f); - S32 label_sub_div_offset_1 = llround(fmod(dist_grid_axis - grid_offset1, mScaleSnapUnit1 * 32.f) / (mScaleSnapUnit1 / max_subdivisions)); - S32 label_sub_div_offset_2 = llround(fmod(dist_grid_axis - grid_offset2, mScaleSnapUnit2 * 32.f) / (mScaleSnapUnit2 / max_subdivisions)); + S32 label_sub_div_offset_1 = ll_round(fmod(dist_grid_axis - grid_offset1, mScaleSnapUnit1 * 32.f) / smallest_subdivision1); + S32 label_sub_div_offset_2 = ll_round(fmod(dist_grid_axis - grid_offset2, mScaleSnapUnit2 * 32.f) / smallest_subdivision2); for (S32 i = start_tick; i <= stop_tick; i++) { F32 tick_scale = 1.f; F32 alpha = grid_alpha * (1.f - (0.5f * ((F32)llabs(i) / (F32)num_ticks_per_side1))); - LLVector3 tick_pos = drag_point + (mScaleDir * (mScaleSnapUnit1 / max_subdivisions * (F32)i - grid_offset1)); + LLVector3 tick_pos = mScaleCenter + (mScaleDir * (grid_multiple1 + i) * smallest_subdivision1); - for (F32 division_level = max_subdivisions; division_level >= sGridMinSubdivisionLevel; division_level /= 2.f) + for (F32 division_level = sGridMaxSubdivisionLevel; division_level >= sGridMinSubdivisionLevel; division_level /= 2.f) { if (fmodf((F32)(i + label_sub_div_offset_1), division_level) == 0.f) { @@ -1728,39 +1797,34 @@ void LLManipScale::renderSnapGuides(const LLBBox& bbox) tick_scale *= 0.7f; } - if (fmodf((F32)(i + label_sub_div_offset_1), (max_subdivisions / llmin(sGridMaxSubdivisionLevel, getSubdivisionLevel(tick_pos, mScaleDir, mScaleSnapUnit1, tick_label_spacing)))) == 0.f) + if (fmodf((F32)(i + label_sub_div_offset_1), (sGridMaxSubdivisionLevel / llmin(sGridMaxSubdivisionLevel, getSubdivisionLevel(tick_pos, mScaleDir, mScaleSnapUnit1, tick_label_spacing)))) == 0.f) { - LLVector3 text_origin = tick_pos + - (mSnapGuideDir1 * mSnapRegimeOffset * (1.f + tick_scale)); + LLVector3 text_origin = tick_pos + (mSnapGuideDir1 * mSnapRegimeOffset * (1.f + tick_scale)); EGridMode grid_mode = LLSelectMgr::getInstance()->getGridMode(); - F32 tick_val; + F32 tick_value; if (grid_mode == GRID_MODE_WORLD) { - tick_val = (tick_pos - mScaleCenter) * mScaleDir / (mScaleSnapUnit1 / grid_resolution); + tick_value = (grid_multiple1 + i) / (sGridMaxSubdivisionLevel / grid_resolution); } else { - tick_val = (tick_pos - mScaleCenter) * mScaleDir / (mScaleSnapUnit1 * 2.f); - } - - if (getUniform()) - { - tick_val *= 2.f; + tick_value = (grid_multiple1 + i) / (2.f * sGridMaxSubdivisionLevel); } F32 text_highlight = 0.8f; - if (is_approx_equal(tick_val, mScaleSnapValue) && mInSnapRegime) + // Highlight this text if the tick value matches the snapped to value, and if either the second set of ticks isn't going to be shown or cursor is in the first snap regime. + if (is_approx_equal(tick_value, mScaleSnappedValue) && (mScaleSnapUnit2 == mScaleSnapUnit1 || (mSnapRegime & SNAP_REGIME_UPPER))) { text_highlight = 1.f; } - renderTickValue(text_origin, tick_val, grid_mode == GRID_MODE_WORLD ? std::string("m") : std::string("x"), LLColor4(text_highlight, text_highlight, text_highlight, alpha)); + renderTickValue(text_origin, tick_value, grid_mode == GRID_MODE_WORLD ? std::string("m") : std::string("x"), LLColor4(text_highlight, text_highlight, text_highlight, alpha)); } } - // label ticks on opposite side + // label ticks on opposite side, only can happen in scaling modes that effect more than one axis and when the object's axis don't have the same scale. A differing scale indicates both conditions. if (mScaleSnapUnit2 != mScaleSnapUnit1) { start_tick = -(llmin(ticks_from_scale_center_2, num_ticks_per_side2)); @@ -1769,9 +1833,9 @@ void LLManipScale::renderSnapGuides(const LLBBox& bbox) { F32 tick_scale = 1.f; F32 alpha = grid_alpha * (1.f - (0.5f * ((F32)llabs(i) / (F32)num_ticks_per_side2))); - LLVector3 tick_pos = drag_point + (mScaleDir * (mScaleSnapUnit2 / max_subdivisions * (F32)i - grid_offset2)); + LLVector3 tick_pos = mScaleCenter + (mScaleDir * (grid_multiple2 + i) * smallest_subdivision2); - for (F32 division_level = max_subdivisions; division_level >= sGridMinSubdivisionLevel; division_level /= 2.f) + for (F32 division_level = sGridMaxSubdivisionLevel; division_level >= sGridMinSubdivisionLevel; division_level /= 2.f) { if (fmodf((F32)(i + label_sub_div_offset_2), division_level) == 0.f) { @@ -1780,35 +1844,29 @@ void LLManipScale::renderSnapGuides(const LLBBox& bbox) tick_scale *= 0.7f; } - if (fmodf((F32)(i + label_sub_div_offset_2), (max_subdivisions / llmin(max_subdivisions, getSubdivisionLevel(tick_pos, mScaleDir, mScaleSnapUnit2, tick_label_spacing)))) == 0.f) + if (fmodf((F32)(i + label_sub_div_offset_2), (sGridMaxSubdivisionLevel / llmin(sGridMaxSubdivisionLevel, getSubdivisionLevel(tick_pos, mScaleDir, mScaleSnapUnit2, tick_label_spacing)))) == 0.f) { - LLVector3 text_origin = tick_pos + - (mSnapGuideDir2 * mSnapRegimeOffset * (1.f + tick_scale)); + LLVector3 text_origin = tick_pos + (mSnapGuideDir2 * mSnapRegimeOffset * (1.f + tick_scale)); EGridMode grid_mode = LLSelectMgr::getInstance()->getGridMode(); - F32 tick_val; + F32 tick_value; if (grid_mode == GRID_MODE_WORLD) { - tick_val = (tick_pos - mScaleCenter) * mScaleDir / (mScaleSnapUnit2 / grid_resolution); + tick_value = (grid_multiple2 + i) / (sGridMaxSubdivisionLevel / grid_resolution); } else { - tick_val = (tick_pos - mScaleCenter) * mScaleDir / (mScaleSnapUnit2 * 2.f); - } - - if (getUniform()) - { - tick_val *= 2.f; + tick_value = (grid_multiple2 + i) / (2.f * sGridMaxSubdivisionLevel); } F32 text_highlight = 0.8f; - if (is_approx_equal(tick_val, mScaleSnapValue) && mInSnapRegime) + if (is_approx_equal(tick_value, mScaleSnappedValue) && (mSnapRegime & SNAP_REGIME_LOWER)) { text_highlight = 1.f; } - renderTickValue(text_origin, tick_val, grid_mode == GRID_MODE_WORLD ? std::string("m") : std::string("x"), LLColor4(text_highlight, text_highlight, text_highlight, alpha)); + renderTickValue(text_origin, tick_value, grid_mode == GRID_MODE_WORLD ? std::string("m") : std::string("x"), LLColor4(text_highlight, text_highlight, text_highlight, alpha)); } } } @@ -1834,13 +1892,13 @@ void LLManipScale::renderSnapGuides(const LLBBox& bbox) LLVector3 help_text_pos = selection_center_start + (mSnapRegimeOffset * 5.f * offset_dir); const LLFontGL* big_fontp = LLFontGL::getFontSansSerif(); - std::string help_text = "Move mouse cursor over ruler"; + std::string help_text = LLTrans::getString("manip_hint1"); LLColor4 help_text_color = LLColor4::white; help_text_color.mV[VALPHA] = clamp_rescale(mHelpTextTimer.getElapsedTimeF32(), sHelpTextVisibleTime, sHelpTextVisibleTime + sHelpTextFadeTime, grid_alpha, 0.f); - hud_render_utf8text(help_text, help_text_pos, *big_fontp, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, -0.5f * big_fontp->getWidthF32(help_text), 3.f, help_text_color, mObjectSelection->getSelectType() == SELECT_TYPE_HUD); - help_text = "to snap to grid"; + hud_render_utf8text(help_text, help_text_pos, *big_fontp, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, -0.5f * big_fontp->getWidthF32(help_text), 3.f, help_text_color, false); + help_text = LLTrans::getString("manip_hint2"); help_text_pos -= LLViewerCamera::getInstance()->getUpAxis() * mSnapRegimeOffset * 0.4f; - hud_render_utf8text(help_text, help_text_pos, *big_fontp, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, -0.5f * big_fontp->getWidthF32(help_text), 3.f, help_text_color, mObjectSelection->getSelectType() == SELECT_TYPE_HUD); + hud_render_utf8text(help_text, help_text_pos, *big_fontp, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, -0.5f * big_fontp->getWidthF32(help_text), 3.f, help_text_color, false); } } } @@ -1853,13 +1911,11 @@ LLVector3 LLManipScale::partToUnitVector( S32 part ) const { return faceToUnitVector( part ); } - else - if( (LL_CORNER_MIN <= part) && (part <= LL_CORNER_MAX) ) + else if ( (LL_CORNER_MIN <= part) && (part <= LL_CORNER_MAX) ) { return cornerToUnitVector( part ); } - else - if( (LL_EDGE_MIN <= part) && (part <= LL_EDGE_MAX ) ) + else if ( (LL_EDGE_MIN <= part) && (part <= LL_EDGE_MAX ) ) { return edgeToUnitVector( part ); } @@ -1871,27 +1927,32 @@ LLVector3 LLManipScale::partToUnitVector( S32 part ) const LLVector3 LLManipScale::faceToUnitVector( S32 part ) const { llassert( (LL_FACE_MIN <= part) && (part <= LL_FACE_MAX) ); + LLVector3 vec; switch( part ) { case LL_FACE_POSX: - return LLVector3( 1.f, 0.f, 0.f ); - + vec.set( 1.f, 0.f, 0.f ); + break; case LL_FACE_NEGX: - return LLVector3( -1.f, 0.f, 0.f ); - + vec.set( -1.f, 0.f, 0.f ); + break; case LL_FACE_POSY: - return LLVector3( 0.f, 1.f, 0.f ); - + vec.set( 0.f, 1.f, 0.f ); + break; case LL_FACE_NEGY: - return LLVector3( 0.f, -1.f, 0.f ); - + vec.set( 0.f, -1.f, 0.f ); + break; case LL_FACE_POSZ: - return LLVector3( 0.f, 0.f, 1.f ); - + vec.set( 0.f, 0.f, 1.f ); + break; case LL_FACE_NEGZ: - return LLVector3( 0.f, 0.f, -1.f ); + vec.set( 0.f, 0.f, -1.f ); + break; + default: + vec.clear(); } - return LLVector3(); + + return vec; } @@ -1903,31 +1964,31 @@ LLVector3 LLManipScale::cornerToUnitVector( S32 part ) const switch(part) { case LL_CORNER_NNN: - vec.setVec(-F_SQRT3, -F_SQRT3, -F_SQRT3); + vec.set(-OO_SQRT3, -OO_SQRT3, -OO_SQRT3); break; case LL_CORNER_NNP: - vec.setVec(-F_SQRT3, -F_SQRT3, F_SQRT3); + vec.set(-OO_SQRT3, -OO_SQRT3, OO_SQRT3); break; case LL_CORNER_NPN: - vec.setVec(-F_SQRT3, F_SQRT3, -F_SQRT3); + vec.set(-OO_SQRT3, OO_SQRT3, -OO_SQRT3); break; case LL_CORNER_NPP: - vec.setVec(-F_SQRT3, F_SQRT3, F_SQRT3); + vec.set(-OO_SQRT3, OO_SQRT3, OO_SQRT3); break; case LL_CORNER_PNN: - vec.setVec(F_SQRT3, -F_SQRT3, -F_SQRT3); + vec.set(OO_SQRT3, -OO_SQRT3, -OO_SQRT3); break; case LL_CORNER_PNP: - vec.setVec(F_SQRT3, -F_SQRT3, F_SQRT3); + vec.set(OO_SQRT3, -OO_SQRT3, OO_SQRT3); break; case LL_CORNER_PPN: - vec.setVec(F_SQRT3, F_SQRT3, -F_SQRT3); + vec.set(OO_SQRT3, OO_SQRT3, -OO_SQRT3); break; case LL_CORNER_PPP: - vec.setVec(F_SQRT3, F_SQRT3, F_SQRT3); + vec.set(OO_SQRT3, OO_SQRT3, OO_SQRT3); break; default: - vec.clearVec(); + vec.clear(); } return vec; @@ -1973,7 +2034,7 @@ F32 LLManipScale::partToMaxScale( S32 part, const LLBBox &bbox ) const max_extent = bbox_extents.mV[i]; } } - max_scale_factor = bbox_extents.magVec() * gHippoLimits->getMaxPrimScale() / max_extent; + max_scale_factor = bbox_extents.length() * get_default_max_prim_scale() / max_extent; if (getUniform()) { @@ -1988,7 +2049,7 @@ F32 LLManipScale::partToMinScale( S32 part, const LLBBox &bbox ) const { LLVector3 bbox_extents = unitVectorToLocalBBoxExtent( partToUnitVector( part ), bbox ); bbox_extents.abs(); - F32 min_extent = gHippoLimits->getMaxPrimScale(); + F32 min_extent = get_default_max_prim_scale(); for (U32 i = VX; i <= VZ; i++) { if (bbox_extents.mV[i] > 0.f && bbox_extents.mV[i] < min_extent) diff --git a/indra/newview/llmanipscale.h b/indra/newview/llmanipscale.h index 521a65e498..e5a96ca0a5 100644 --- a/indra/newview/llmanipscale.h +++ b/indra/newview/llmanipscale.h @@ -40,6 +40,8 @@ #include "llbbox.h" +F32 get_default_max_prim_scale(bool is_flora = false); + class LLToolComposite; class LLColor4; @@ -49,6 +51,13 @@ typedef enum e_scale_manipulator_type SCALE_MANIP_FACE } EScaleManipulatorType; +typedef enum e_snap_regimes +{ + SNAP_REGIME_NONE = 0, //!< The cursor is not in either of the snap regimes. + SNAP_REGIME_UPPER = 0x1, //!< The cursor is, non-exclusively, in the first of the snap regimes. Prefer to treat as bitmask. + SNAP_REGIME_LOWER = 0x2 //!< The cursor is, non-exclusively, in the second of the snap regimes. Prefer to treat as bitmask. +} ESnapRegimes; + class LLManipScale : public LLManip { @@ -62,7 +71,7 @@ class LLManipScale : public LLManip ManipulatorHandle(LLVector3 pos, EManipPart id, EScaleManipulatorType type):mPosition(pos), mManipID(id), mType(type){} }; - + static const S32 NUM_MANIPULATORS = 14; LLManipScale( LLToolComposite* composite ); ~LLManipScale(); @@ -89,7 +98,7 @@ class LLManipScale : public LLManip void renderFaces( const LLBBox& local_bbox ); void renderEdges( const LLBBox& local_bbox ); void renderBoxHandle( F32 x, F32 y, F32 z ); - void renderAxisHandle( const LLVector3& start, const LLVector3& end ); + void renderAxisHandle( U32 part, const LLVector3& start, const LLVector3& end ); void renderGuidelinesPart( const LLBBox& local_bbox ); void renderSnapGuides( const LLBBox& local_bbox ); @@ -133,34 +142,36 @@ class LLManipScale : public LLManip }; - F32 mBoxHandleSize; // The size of the handles at the corners of the bounding box - F32 mScaledBoxHandleSize; // handle size after scaling for selection feedback + F32 mScaledBoxHandleSize; //!< Handle size after scaling for selection feedback. LLVector3d mDragStartPointGlobal; - LLVector3d mDragStartCenterGlobal; // The center of the bounding box of all selected objects at time of drag start + LLVector3d mDragStartCenterGlobal; //!< The center of the bounding box of all selected objects at time of drag start. LLVector3d mDragPointGlobal; LLVector3d mDragFarHitGlobal; S32 mLastMouseX; S32 mLastMouseY; BOOL mSendUpdateOnMouseUp; U32 mLastUpdateFlags; - typedef std::set minpulator_list_t; - minpulator_list_t mProjectedManipulators; + typedef std::set manipulator_list_t; + manipulator_list_t mProjectedManipulators; LLVector4 mManipulatorVertices[14]; - F32 mScaleSnapUnit1; // size of snap multiples for axis 1 - F32 mScaleSnapUnit2; // size of snap multiples for axis 2 - LLVector3 mScalePlaneNormal1; // normal of plane in which scale occurs that most faces camera - LLVector3 mScalePlaneNormal2; // normal of plane in which scale occurs that most faces camera - LLVector3 mSnapGuideDir1; - LLVector3 mSnapGuideDir2; - LLVector3 mSnapDir1; - LLVector3 mSnapDir2; - F32 mSnapRegimeOffset; + F32 mScaleSnapUnit1; //!< Size of snap multiples for the upper scale. + F32 mScaleSnapUnit2; //!< Size of snap multiples for the lower scale. + LLVector3 mScalePlaneNormal1; //!< Normal of plane in which scale occurs that most faces camera. + LLVector3 mScalePlaneNormal2; //!< Normal of plane in which scale occurs that most faces camera. + LLVector3 mSnapGuideDir1; //!< The direction in which the upper snap guide tick marks face. + LLVector3 mSnapGuideDir2; //!< The direction in which the lower snap guide tick marks face. + LLVector3 mSnapDir1; //!< The direction in which the upper snap guides face. + LLVector3 mSnapDir2; //!< The direction in which the lower snap guides face. + F32 mSnapRegimeOffset; //!< How far off the scale axis centerline the mouse can be before it exits/enters the snap regime. + F32 mTickPixelSpacing1; //!< The pixel spacing between snap guide tick marks for the upper scale. + F32 mTickPixelSpacing2; //!< The pixel spacing between snap guide tick marks for the lower scale. F32 mSnapGuideLength; - LLVector3 mScaleCenter; - LLVector3 mScaleDir; - F32 mScaleSnapValue; - BOOL mInSnapRegime; - F32* mManipulatorScales; + LLVector3 mScaleCenter; //!< The location of the origin of the scaling operation. + LLVector3 mScaleDir; //!< The direction of the scaling action. In face-dragging this is aligned with one of the cardinal axis relative to the prim, but in corner-dragging this is along the diagonal. + F32 mScaleSnappedValue; //!< The distance of the current position nearest the mouse location, measured along mScaleDir. Is measured either from the center or from the far face/corner depending upon whether uniform scaling is true or false respectively. + ESnapRegimes mSnapRegime; //setCursor(UI_CURSOR_TOOLTRANSLATE); return TRUE; } @@ -390,7 +390,7 @@ BOOL LLManipTranslate::handleMouseDownOnPart( S32 x, S32 y, MASK mask ) if (!LLViewerCamera::getInstance()->projectPosAgentToScreen(select_center_agent, mouse_pos)) { // mouse_pos may be nonsense - llwarns << "Failed to project object center to screen" << llendl; + LL_WARNS() << "Failed to project object center to screen" << LL_ENDL; } else if (gSavedSettings.getBOOL("SnapToMouseCursor")) { @@ -418,7 +418,7 @@ BOOL LLManipTranslate::handleHover(S32 x, S32 y, MASK mask) // Bail out if mouse not down. if( !hasMouseCapture() ) { - lldebugst(LLERR_USER_INPUT) << "hover handled by LLManipTranslate (inactive)" << llendl; + LL_DEBUGS("UserInput") << "hover handled by LLManipTranslate (inactive)" << LL_ENDL; // Always show cursor // gViewerWindow->setCursor(UI_CURSOR_ARROW); gViewerWindow->setCursor(UI_CURSOR_TOOLTRANSLATE); @@ -454,7 +454,7 @@ BOOL LLManipTranslate::handleHover(S32 x, S32 y, MASK mask) // rotation above. if( x == mLastHoverMouseX && y == mLastHoverMouseY && !rotated) { - lldebugst(LLERR_USER_INPUT) << "hover handled by LLManipTranslate (mouse unmoved)" << llendl; + LL_DEBUGS("UserInput") << "hover handled by LLManipTranslate (mouse unmoved)" << LL_ENDL; gViewerWindow->setCursor(UI_CURSOR_TOOLTRANSLATE); return TRUE; } @@ -467,7 +467,7 @@ BOOL LLManipTranslate::handleHover(S32 x, S32 y, MASK mask) { if (abs(mMouseDownX - x) < MOUSE_DRAG_SLOP && abs(mMouseDownY - y) < MOUSE_DRAG_SLOP ) { - lldebugst(LLERR_USER_INPUT) << "hover handled by LLManipTranslate (mouse inside slop)" << llendl; + LL_DEBUGS("UserInput") << "hover handled by LLManipTranslate (mouse inside slop)" << LL_ENDL; gViewerWindow->setCursor(UI_CURSOR_TOOLTRANSLATE); return TRUE; } @@ -491,7 +491,7 @@ BOOL LLManipTranslate::handleHover(S32 x, S32 y, MASK mask) // When we make the copy, we don't want to do any other processing. // If so, the object will also be moved, and the copy will be offset. - lldebugst(LLERR_USER_INPUT) << "hover handled by LLManipTranslate (made copy)" << llendl; + LL_DEBUGS("UserInput") << "hover handled by LLManipTranslate (made copy)" << LL_ENDL; gViewerWindow->setCursor(UI_CURSOR_TOOLTRANSLATE); } } @@ -508,7 +508,7 @@ BOOL LLManipTranslate::handleHover(S32 x, S32 y, MASK mask) if (!selectNode) { // somehow we lost the object! - llwarns << "Translate manip lost the object, no selectNode" << llendl; + LL_WARNS() << "Translate manip lost the object, no selectNode" << LL_ENDL; gViewerWindow->setCursor(UI_CURSOR_TOOLTRANSLATE); return TRUE; } @@ -517,7 +517,7 @@ BOOL LLManipTranslate::handleHover(S32 x, S32 y, MASK mask) if (!object) { // somehow we lost the object! - llwarns << "Translate manip lost the object, no object in selectNode" << llendl; + LL_WARNS() << "Translate manip lost the object, no object in selectNode" << LL_ENDL; gViewerWindow->setCursor(UI_CURSOR_TOOLTRANSLATE); return TRUE; } @@ -542,12 +542,12 @@ BOOL LLManipTranslate::handleHover(S32 x, S32 y, MASK mask) { F32 max_drag_distance = gSavedSettings.getF32("MaxDragDistance"); - if (gHippoGridManager->getConnectedGrid()->isAurora()) + if (gHippoGridManager->getConnectedGrid()->isWhiteCore()) max_drag_distance = llmin(10000.f, max_drag_distance); if (relative_move.magVecSquared() > max_drag_distance * max_drag_distance) { - lldebugst(LLERR_USER_INPUT) << "hover handled by LLManipTranslate (too far)" << llendl; + LL_DEBUGS("UserInput") << "hover handled by LLManipTranslate (too far)" << LL_ENDL; gViewerWindow->setCursor(UI_CURSOR_NOLOCKED); return TRUE; } @@ -704,7 +704,7 @@ BOOL LLManipTranslate::handleHover(S32 x, S32 y, MASK mask) } LLViewerObject* root_object = (object == NULL) ? NULL : object->getRootEdit(); - if (object->permMove() && !object->isPermanentEnforced() && + if (object && object->permMove() && !object->isPermanentEnforced() && ((root_object == NULL) || !root_object->isPermanentEnforced())) { // handle attachments in local space @@ -792,7 +792,7 @@ BOOL LLManipTranslate::handleHover(S32 x, S32 y, MASK mask) gAgentCamera.clearFocusObject(); dialog_refresh_all(); // ??? is this necessary? - lldebugst(LLERR_USER_INPUT) << "hover handled by LLManipTranslate (active)" << llendl; + LL_DEBUGS("UserInput") << "hover handled by LLManipTranslate (active)" << LL_ENDL; gViewerWindow->setCursor(UI_CURSOR_TOOLTRANSLATE); return TRUE; } @@ -807,8 +807,8 @@ void LLManipTranslate::highlightManipulators(S32 x, S32 y) } //LLBBox bbox = LLSelectMgr::getInstance()->getBBoxOfSelection(); - LLMatrix4 projMatrix = LLViewerCamera::getInstance()->getProjection(); - LLMatrix4 modelView = LLViewerCamera::getInstance()->getModelview(); + LLMatrix4 projMatrix( LLViewerCamera::getInstance()->getProjection().getF32ptr() ); + LLMatrix4 modelView( LLViewerCamera::getInstance()->getModelview().getF32ptr() ); LLVector3 object_position = getPivotPoint(); @@ -827,7 +827,7 @@ void LLManipTranslate::highlightManipulators(S32 x, S32 y) relative_camera_dir = LLVector3(1.f, 0.f, 0.f) * ~grid_rotation; LLVector4 translation(object_position); transform.initRotTrans(grid_rotation, translation); - LLMatrix4 cfr(OGL_TO_CFR_ROTATION); + LLMatrix4 cfr(OGL_TO_CFR_ROTATION.getF32ptr()); transform *= cfr; LLMatrix4 window_scale; F32 zoom_level = 2.f * gAgentCamera.mHUDCurZoom; @@ -1103,7 +1103,7 @@ void LLManipTranslate::renderSnapGuides() gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); LLGLDepthTest gls_depth(GL_TRUE); - LLGLDisable gls_cull(GL_CULL_FACE); + LLGLDisable gls_cull; LLVector3 translate_axis; if (mManipPart == LL_NO_PART) @@ -1263,7 +1263,7 @@ void LLManipTranslate::renderSnapGuides() // find distance to nearest smallest grid unit F32 offset_nearest_grid_unit = fmodf(dist_grid_axis, smallest_grid_unit_scale); // how many smallest grid units are we away from largest grid scale? - S32 sub_div_offset = llround(fmod(dist_grid_axis - offset_nearest_grid_unit, getMinGridScale() / sGridMinSubdivisionLevel) / smallest_grid_unit_scale); + S32 sub_div_offset = ll_round(fmodf(dist_grid_axis - offset_nearest_grid_unit, getMinGridScale() / sGridMinSubdivisionLevel) / smallest_grid_unit_scale); S32 num_ticks_per_side = llmax(1, llfloor(0.5f * guide_size_meters / smallest_grid_unit_scale)); LLGLDepthTest gls_depth(GL_FALSE); @@ -1377,12 +1377,12 @@ void LLManipTranslate::renderSnapGuides() } } - sub_div_offset = llround(fmod(dist_grid_axis - offset_nearest_grid_unit, getMinGridScale() * 32.f) / smallest_grid_unit_scale); + sub_div_offset = ll_round(fmod(dist_grid_axis - offset_nearest_grid_unit, getMinGridScale() * 32.f) / smallest_grid_unit_scale); LLVector2 screen_translate_axis(llabs(translate_axis * LLViewerCamera::getInstance()->getLeftAxis()), llabs(translate_axis * LLViewerCamera::getInstance()->getUpAxis())); screen_translate_axis.normVec(); - S32 tick_label_spacing = llround(screen_translate_axis * sTickLabelSpacing); + S32 tick_label_spacing = ll_round(screen_translate_axis * sTickLabelSpacing); // render tickmark values for (S32 i = -num_ticks_per_side; i <= num_ticks_per_side; i++) @@ -1420,7 +1420,7 @@ void LLManipTranslate::renderSnapGuides() F32 offset_val = 0.5f * tick_offset.mV[ARROW_TO_AXIS[mManipPart]] / getMinGridScale(); EGridMode grid_mode = LLSelectMgr::getInstance()->getGridMode(); F32 text_highlight = 0.8f; - if(i - llround(offset_nearest_grid_unit / smallest_grid_unit_scale) == 0 && mInSnapRegime) + if(i - ll_round(offset_nearest_grid_unit / smallest_grid_unit_scale) == 0 && mInSnapRegime) { text_highlight = 1.f; } @@ -1546,7 +1546,7 @@ void LLManipTranslate::renderSnapGuides() LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE); { - LLGLDisable stencil(GL_STENCIL_TEST); + LLGLDisable stencil; { LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE, GL_GREATER); gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, getGridTexName()); @@ -1558,7 +1558,7 @@ void LLManipTranslate::renderSnapGuides() } { - LLGLDisable alpha_test(GL_ALPHA_TEST); + LLGLDisable alpha_test; //draw black overlay gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); renderGrid(u,v,tiles,0.0f, 0.0f, 0.0f,a*0.16f); @@ -1579,7 +1579,7 @@ void LLManipTranslate::renderSnapGuides() { LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE, GL_GREATER); - LLGLEnable stipple(GL_LINE_STIPPLE); + LLGLEnable stipple; gGL.flush(); if (!LLGLSLShader::sNoFixedFunction) @@ -1675,9 +1675,11 @@ void LLManipTranslate::highlightIntersection(LLVector3 normal, { glStencilMask(stencil_mask); glClearStencil(1); + gGL.syncContextState(); glClear(GL_STENCIL_BUFFER_BIT); - LLGLEnable cull_face(GL_CULL_FACE); - LLGLEnable stencil(GL_STENCIL_TEST); + glClearStencil(0); + LLGLEnable cull_face; + LLGLEnable stencil; LLGLDepthTest depth (GL_TRUE, GL_FALSE, GL_ALWAYS); glStencilFunc(GL_ALWAYS, 0, stencil_mask); gGL.setColorMask(false, false); @@ -1692,11 +1694,15 @@ void LLManipTranslate::highlightIntersection(LLVector3 normal, normal = -normal; } F32 d = -(selection_center * normal); - glh::vec4f plane(normal.mV[0], normal.mV[1], normal.mV[2], d ); + LLVector4a plane(normal.mV[0], normal.mV[1], normal.mV[2], d ); - gGL.getModelviewMatrix().inverse().mult_vec_matrix(plane); + LLMatrix4a inv_mat = gGL.getModelviewMatrix(); + inv_mat.invert(); + inv_mat.transpose(); + inv_mat.rotate4(plane,plane); - gClipProgram.uniform4fv("clip_plane", 1, plane.v); + static LLStaticHashedString sClipPlane("clip_plane"); + gClipProgram.uniform4fv(sClipPlane, 1, plane.getF32ptr()); BOOL particles = gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_PARTICLES); #if ENABLE_CLASSIC_CLOUDS @@ -1763,7 +1769,7 @@ void LLManipTranslate::highlightIntersection(LLVector3 normal, { gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); LLGLDepthTest depth(GL_FALSE); - LLGLEnable stencil(GL_STENCIL_TEST); + LLGLEnable stencil; glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); glStencilFunc(GL_EQUAL, 0, stencil_mask); renderGrid(0,0,tiles,inner_color.mV[0], inner_color.mV[1], inner_color.mV[2], 0.25f); @@ -1910,7 +1916,7 @@ void LLManipTranslate::renderTranslationHandles() { gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - LLGLDisable cull_face(GL_CULL_FACE); + LLGLDisable cull_face; LLColor4 color1; LLColor4 color2; @@ -1920,18 +1926,18 @@ void LLManipTranslate::renderTranslationHandles() { if (index == mManipPart - LL_X_ARROW || index == mHighlightedPart - LL_X_ARROW) { - mArrowScales.mV[index] = lerp(mArrowScales.mV[index], SELECTED_ARROW_SCALE, LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE )); - mPlaneScales.mV[index] = lerp(mPlaneScales.mV[index], 1.f, LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE )); + mArrowScales.mV[index] = lerp(mArrowScales.mV[index], SELECTED_ARROW_SCALE, LLSmoothInterpolation::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE )); + mPlaneScales.mV[index] = lerp(mPlaneScales.mV[index], 1.f, LLSmoothInterpolation::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE )); } else if (index == mManipPart - LL_YZ_PLANE || index == mHighlightedPart - LL_YZ_PLANE) { - mArrowScales.mV[index] = lerp(mArrowScales.mV[index], 1.f, LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE )); - mPlaneScales.mV[index] = lerp(mPlaneScales.mV[index], SELECTED_ARROW_SCALE, LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE )); + mArrowScales.mV[index] = lerp(mArrowScales.mV[index], 1.f, LLSmoothInterpolation::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE )); + mPlaneScales.mV[index] = lerp(mPlaneScales.mV[index], SELECTED_ARROW_SCALE, LLSmoothInterpolation::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE )); } else { - mArrowScales.mV[index] = lerp(mArrowScales.mV[index], 1.f, LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE )); - mPlaneScales.mV[index] = lerp(mPlaneScales.mV[index], 1.f, LLCriticalDamp::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE )); + mArrowScales.mV[index] = lerp(mArrowScales.mV[index], 1.f, LLSmoothInterpolation::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE )); + mPlaneScales.mV[index] = lerp(mPlaneScales.mV[index], 1.f, LLSmoothInterpolation::getInterpolant(MANIPULATOR_SCALE_HALF_LIFE )); } } @@ -2202,8 +2208,8 @@ void LLManipTranslate::renderTranslationHandles() void LLManipTranslate::renderArrow(S32 which_arrow, S32 selected_arrow, F32 box_size, F32 arrow_size, F32 handle_size, BOOL reverse_direction) { gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - LLGLEnable gls_blend(GL_BLEND); - LLGLEnable gls_color_material(GL_COLOR_MATERIAL); + LLGLEnable gls_blend; + LLGLEnable gls_color_material; for (S32 pass = 1; pass <= 2; pass++) { @@ -2266,7 +2272,7 @@ void LLManipTranslate::renderArrow(S32 which_arrow, S32 selected_arrow, F32 box_ axis.mV[0] = 1.0f; break; default: - llerrs << "renderArrow called with bad arrow " << which_arrow << llendl; + LL_ERRS() << "renderArrow called with bad arrow " << which_arrow << LL_ENDL; break; } @@ -2312,7 +2318,7 @@ BOOL LLManipTranslate::canAffectSelection() virtual bool apply(LLViewerObject* objectp) { LLViewerObject *root_object = (objectp == NULL) ? NULL : objectp->getRootEdit(); - return objectp->permMove() && !objectp->isPermanentEnforced() && + return objectp && objectp->permMove() && !objectp->isPermanentEnforced() && ((root_object == NULL) || !root_object->isPermanentEnforced()) && (objectp->permModify() || !gSavedSettings.getBOOL("EditLinkedParts")); } diff --git a/indra/newview/llmapresponders.cpp b/indra/newview/llmapresponders.cpp index eaae3e4505..813830a135 100644 --- a/indra/newview/llmapresponders.cpp +++ b/indra/newview/llmapresponders.cpp @@ -42,16 +42,16 @@ #include "llsdserialize.h" //virtual -void LLMapLayerResponder::result(const LLSD& result) +void LLMapLayerResponder::httpSuccess(void) { - llinfos << "LLMapLayerResponder::result from capabilities" << llendl; + LL_INFOS() << "LLMapLayerResponder::mContent from capabilities" << LL_ENDL; - S32 agent_flags = result["AgentData"]["Flags"]; + S32 agent_flags = mContent["AgentData"]["Flags"]; U32 layer = flagsToLayer(agent_flags); if (layer != SIM_LAYER_COMPOSITE) { - llwarns << "Invalid or out of date map image type returned!" << llendl; + LL_WARNS() << "Invalid or out of date map image type returned!" << LL_ENDL; return; } @@ -59,11 +59,8 @@ void LLMapLayerResponder::result(const LLSD& result) LLWorldMap::getInstance()->mMapLayers.clear(); - LLSD::array_const_iterator iter; - for(iter = result["LayerData"].beginArray(); iter != result["LayerData"].endArray(); ++iter) + for (auto const& layer_data : mContent["LayerData"].array()) { - const LLSD& layer_data = *iter; - LLWorldMapLayer new_layer; new_layer.LayerDefined = TRUE; diff --git a/indra/newview/llmapresponders.h b/indra/newview/llmapresponders.h index 835722348e..6f6a08f5db 100644 --- a/indra/newview/llmapresponders.h +++ b/indra/newview/llmapresponders.h @@ -40,7 +40,7 @@ extern AIHTTPTimeoutPolicy mapLayerResponder_timeout; class LLMapLayerResponder : public LLHTTPClient::ResponderWithResult { - /*virtual*/ void result(const LLSD& content); + /*virtual*/ void httpSuccess(void); /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return mapLayerResponder_timeout; } /*virtual*/ char const* getName(void) const { return "LLMapLayerResponder"; } }; diff --git a/indra/newview/llmarketplacefunctions.cpp b/indra/newview/llmarketplacefunctions.cpp index ed7c774c8f..5234efbac8 100644 --- a/indra/newview/llmarketplacefunctions.cpp +++ b/indra/newview/llmarketplacefunctions.cpp @@ -29,19 +29,28 @@ #include "llmarketplacefunctions.h" #include "llagent.h" +#include "llbufferstream.h" #include "llhttpclient.h" +#include "llinventoryfunctions.h" +#include "llinventoryobserver.h" +#include "llnotificationsutil.h" +#include "llsdjson.h" #include "lltimer.h" #include "lltrans.h" #include "llviewercontrol.h" +#include "llviewerinventory.h" #include "llviewermedia.h" #include "llviewernetwork.h" +#include "llviewerregion.h" #include "hippogridmanager.h" +#include "llsdutil.h" + // // Helpers // -static std::string getLoginUriDomain() +std::string getLoginUriDomain() { LLURI uri(gHippoGridManager->getConnectedGrid()->getLoginUri()); std::string hostname = uri.hostName(); // Ie, "login..lindenlab.com" @@ -84,7 +93,7 @@ static std::string getMarketplaceDomain() else { // TODO: Find out if OpenSim, and Avination adopted any outbox stuffs, if so code HippoGridManager for this - // Aurora grid has not. + // WhiteCore has not. // For now, set domain on other grids to the loginUri domain, so we don't harass LL web services. domain = getLoginUriDomain(); //gHippoGridManager->getCurrentGrid()->getMarketPlaceDomain(); } @@ -101,7 +110,7 @@ static std::string getMarketplaceURL(const std::string& urlStringName) return marketplace_url; } -LLSD getMarketplaceStringSubstitutions() +LLSD LLMarketplaceData::getMarketplaceStringSubstitutions() { std::string marketplace_url = getMarketplaceURL("MarketplaceURL"); std::string marketplace_url_create = getMarketplaceURL("MarketplaceURL_CreateStore"); @@ -120,19 +129,549 @@ LLSD getMarketplaceStringSubstitutions() return marketplace_sub_map; } -class AIHTTPTimeoutPolicy; -extern AIHTTPTimeoutPolicy MPImportGetResponder_timeout; -extern AIHTTPTimeoutPolicy MPImportPostResponder_timeout; +// Get the version folder: if there is only one subfolder, we will use it as a version folder +LLUUID getVersionFolderIfUnique(const LLUUID& folder_id) +{ + LLUUID version_id = LLUUID::null; + LLInventoryModel::cat_array_t* categories; + LLInventoryModel::item_array_t* items; + gInventory.getDirectDescendentsOf(folder_id, categories, items); + if (categories->size() == 1) + { + version_id = categories->begin()->get()->getUUID(); + } + else + { + LLNotificationsUtil::add("AlertMerchantListingActivateRequired"); + } + return version_id; +} + +/////////////////////////////////////////////////////////////////////////////// + // SLM Reporters +void log_SLM_warning(const std::string& request, U32 status, const std::string& reason, const std::string& code, const LLSD& content) +{ + LL_WARNS("SLM") << "SLM API : Responder to " << request << ". status : " << status << ", reason : " << reason << ", code : " << code << ", description : " << ll_pretty_print_sd(content) << LL_ENDL; + if ((status == 422) && + content.isArray() && + content.size() > 4) + { + // Unprocessable Entity : Special case that error as it is a frequent answer when trying to list an incomplete listing + LLNotificationsUtil::add("MerchantUnprocessableEntity"); + } + else + { + // Prompt the user with the warning (so they know why things are failing) + LLSD subs; + // We do show long descriptions in the alert (unlikely to be readable). The description string will be in the log though. + std::string description; + { + if (content.isArray()) + { + for (auto it = content.beginArray(); it != content.endArray(); ++it) + { + if (!description.empty()) + description += '\n'; + description += (*it).asString(); + } + } + else + { + description = content.asString(); + } + } + std::string reason_lc = reason; + LLStringUtil::toLower(reason_lc); + if (!description.empty() && reason_lc.find("unknown") != std::string::npos) + { + subs["[ERROR_REASON]"] = LLStringUtil::null; + } + else + { + subs["[ERROR_REASON]"] = '\'' + reason +"'\n"; + } + subs["[ERROR_DESCRIPTION]"] = description; + LLNotificationsUtil::add("MerchantTransactionFailed", subs); + } +} + +void log_SLM_infos(const std::string& request, U32 status, const std::string& body) +{ + if (gSavedSettings.getBOOL("MarketplaceListingsLogging")) + { + LL_INFOS("SLM") << "SLM API : Responder to " << request << ". status : " << status << ", body or description : " << body << LL_ENDL; + } +} + +void log_SLM_infos(const std::string& request, const std::string& url, const std::string& body) +{ + if (gSavedSettings.getBOOL("MarketplaceListingsLogging")) + { + LL_INFOS("SLM") << "SLM API : Sending " << request << ". url : " << url << ", body : " << body << LL_ENDL; + } +} + +class LLSLMGetMerchantResponder : public LLHTTPClient::ResponderWithCompleted +{ + LOG_CLASS(LLSLMGetMerchantResponder); +public: + + LLSLMGetMerchantResponder() {} + +protected: + void completedRaw(const LLChannelDescriptors& channels, const LLIOPipe::buffer_ptr_t& buffer) override + { + S32 httpCode = getStatus(); + + if (!isGoodStatus(mStatus)) + { + if (httpCode == HTTP_NOT_FOUND) + { + log_SLM_infos("Get /merchant", httpCode, std::string("User is not a merchant")); + LLMarketplaceData::instance(). + setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_NOT_MERCHANT); + } + else if (httpCode == HTTP_SERVICE_UNAVAILABLE) + { + log_SLM_infos("Get /merchant", httpCode, std::string("Merchant is not migrated")); + LLMarketplaceData::instance(). + setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_NOT_MIGRATED_MERCHANT); + } + else if (httpCode == 499) + { + const auto& content(getContent()); + // 499 includes timeout and ssl error - marketplace is down or having issues, we do not show it in this request according to MAINT-5938 + LL_WARNS("SLM") << "SLM Merchant Request failed with status: " << httpCode + << ", reason : " << getReason() + << ", code : " << content.get("error_code") + << ", description : " << content.get("error_description") << LL_ENDL; + LLMarketplaceData::instance().setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_CONNECTION_FAILURE); + } + else + { + log_SLM_warning("Get /merchant", httpCode, getReason(), LLStringUtil::null, getContent()); + LLMarketplaceData::instance(). + setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_CONNECTION_FAILURE); + } + return; + } + + log_SLM_infos("Get /merchant", getStatus(), "User is a merchant"); + LLMarketplaceData::instance(). + setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_MERCHANT); + } + virtual char const* getName() const { return "getMerchantStatus"; } +}; + +class LLSLMGetListingsResponder : public LLHTTPClient::ResponderWithCompleted +{ + LOG_CLASS(LLSLMGetListingsResponder); +public: + LLSLMGetListingsResponder(const LLUUID& folder_id) + { + folderId = folder_id; + } + + virtual void completedRaw(const LLChannelDescriptors& channels, + const LLIOPipe::buffer_ptr_t& buffer) + { + LLMarketplaceData::instance(). + setUpdating(folderId, false); + + std::string body; + decode_raw_body(channels, buffer, body); + + LLSD result = LlsdFromJsonString(body); + if (result.isUndefined()) + { + log_SLM_warning("Get /listings", getStatus(), getReason(), LLStringUtil::null, "Empty or Invalid JSON Response"); + return; + } + + if (!isGoodStatus(mStatus)) + { + log_SLM_warning("Get /listings", getStatus(), getReason(), LLStringUtil::null, result); + LLMarketplaceData::instance(). + setSLMDataFetched(MarketplaceFetchCodes::MARKET_FETCH_FAILED); + update_marketplace_category(folderId, false); + gInventory.notifyObservers(); + return; + } + + log_SLM_infos("Get /listings", getStatus(), body); + + // Extract the info from the results + for (auto const& listing : result["listings"].array()) + { + int listingId = listing["id"].asInteger(); + bool isListed = listing["is_listed"].asBoolean(); + std::string editUrl = listing["edit_url"].asString(); + LLUUID folderUuid = listing["inventory_info"]["listing_folder_id"].asUUID(); + LLUUID versionUuid = listing["inventory_info"]["version_folder_id"].asUUID(); + int count = listing["inventory_info"]["count_on_hand"].asInteger(); + + if (folderUuid.notNull()) + { + LLMarketplaceData::instance(). + addListing(folderUuid, listingId, versionUuid, isListed, editUrl, count); + } + } + + // Update all folders under the root + LLMarketplaceData::instance(). + setSLMDataFetched(MarketplaceFetchCodes::MARKET_FETCH_DONE); + update_marketplace_category(folderId, false); + gInventory.notifyObservers(); + } + virtual char const* getName() const { return "getSLMListings"; } +private: + LLUUID folderId; +}; + +class LLSLMCreateListingsResponder : public LLHTTPClient::ResponderWithCompleted +{ + LOG_CLASS(LLSLMCreateListingsResponder); +public: + + LLSLMCreateListingsResponder(const LLUUID& folder_id) + { + folderId = folder_id; + } + + virtual void completedRaw(const LLChannelDescriptors& channels, + const LLIOPipe::buffer_ptr_t& buffer) + { + LLMarketplaceData::instance().setUpdating(folderId, false); + + std::string body; + decode_raw_body(channels, buffer, body); + + LLSD result = LlsdFromJsonString(body); + if (result.isUndefined()) + { + log_SLM_warning("Post /listings", getStatus(), getReason(), LLStringUtil::null, "Empty or Invalid JSON Response"); + return; + } + + if (!isGoodStatus(mStatus)) + { + log_SLM_warning("Post /listings", getStatus(), getReason(), LLStringUtil::null, result); + update_marketplace_category(folderId, false); + gInventory.notifyObservers(); + return; + } + + log_SLM_infos("Post /listings", getStatus(), body); + + // Extract the info from the Json string + for (auto const& listing : result["listings"].array()) + { + int listing_id = listing["id"].asInteger(); + bool is_listed = listing["is_listed"].asBoolean(); + std::string edit_url = listing["edit_url"].asString(); + std::string folder_uuid_string = listing["inventory_info"]["listing_folder_id"].asString(); + std::string version_uuid_string = listing["inventory_info"]["version_folder_id"].asString(); + int count = listing["inventory_info"]["count_on_hand"].asInteger(); + + LLUUID folder_id(folder_uuid_string); + LLUUID version_id(version_uuid_string); + LLMarketplaceData::instance().addListing(folder_id,listing_id,version_id,is_listed,edit_url,count); + update_marketplace_category(folder_id, false); + gInventory.notifyObservers(); + } + } + virtual char const* getName() const { return "LLSLMCreateListingsResponder"; } +private: + LLUUID folderId; +}; + +class LLSLMGetListingResponder : public LLHTTPClient::ResponderWithCompleted +{ + LOG_CLASS(LLSLMGetListingResponder); +public: + + LLSLMGetListingResponder(const LLUUID& folder_id) + { + folderId = folder_id; + } + + virtual void completedRaw(const LLChannelDescriptors& channels, + const LLIOPipe::buffer_ptr_t& buffer) + { + LLMarketplaceData::instance(). + setUpdating(folderId, false); + + std::string body; + decode_raw_body(channels, buffer, body); + + LLSD result = LlsdFromJsonString(body); + if (result.isUndefined()) + { + log_SLM_warning("Get /listing", getStatus(), getReason(), LLStringUtil::null, "Empty or Invalid JSON Response"); + return; + } + + if (!isGoodStatus(mStatus)) + { + if (getStatus() == HTTP_NOT_FOUND) + { + // That listing does not exist -> delete its record from the local SLM data store + LLMarketplaceData::instance(). + deleteListing(folderId, false); + } + else + { + log_SLM_warning("Get /listing", getStatus(), getReason(), LLStringUtil::null, result); + } + update_marketplace_category(folderId, false); + gInventory.notifyObservers(); + return; + } + + log_SLM_infos("Get /listing", getStatus(), body); + + // Extract the info from the results + for (auto const& listing : result["listings"].array()) + { + int resListingId = listing["id"].asInteger(); + bool isListed = listing["is_listed"].asBoolean(); + std::string editUrl = listing["edit_url"].asString(); + LLUUID folderUuid = listing["inventory_info"]["listing_folder_id"].asUUID(); + LLUUID versionUuid = listing["inventory_info"]["version_folder_id"].asUUID(); + int count = listing["inventory_info"]["count_on_hand"].asInteger(); + + // Update that listing + LLMarketplaceData::instance(). + setListingID(folderUuid, resListingId, false); + LLMarketplaceData::instance(). + setVersionFolderID(folderUuid, versionUuid, false); + LLMarketplaceData::instance(). + setActivationState(folderUuid, isListed, false); + LLMarketplaceData::instance(). + setListingURL(folderUuid, editUrl, false); + LLMarketplaceData::instance(). + setCountOnHand(folderUuid, count, false); + update_marketplace_category(folderUuid, false); + gInventory.notifyObservers(); + } + } + virtual char const* getName() const { return "getSingleListingCoro"; } +private: + LLUUID folderId; +}; + +class LLSLMUpdateListingsResponder : public LLHTTPClient::ResponderWithCompleted +{ + LOG_CLASS(LLSLMUpdateListingsResponder); +public: + + LLSLMUpdateListingsResponder(const LLUUID& folder_id, bool expected_listed_state, const LLUUID& expected_version_id) + { + folderId = folder_id; + isListed = expected_listed_state; + versionId = expected_version_id; + } + + virtual void completedRaw(const LLChannelDescriptors& channels, + const LLIOPipe::buffer_ptr_t& buffer) + { + LLMarketplaceData::instance(). + setUpdating(folderId, false); + + std::string body; + decode_raw_body(channels, buffer, body); + + LLSD result = LlsdFromJsonString(body); + if (result.isUndefined()) + { + log_SLM_warning("Put /listing", getStatus(), getReason(), LLStringUtil::null, "Empty or Invalid JSON Response"); + return; + } + + if (!isGoodStatus(mStatus)) + { + log_SLM_warning("Put /listing", getStatus(), getReason(), LLStringUtil::null, result); + update_marketplace_category(folderId, false); + gInventory.notifyObservers(); + return; + } + + log_SLM_infos("Put /listing", getStatus(), body); + + // Extract the info from the Json string + for (auto const& listing : result["listings"].array()) + { + int listing_id = listing["id"].asInteger(); + bool is_listed = listing["is_listed"].asBoolean(); + std::string edit_url = listing["edit_url"].asString(); + LLUUID folderUuid = listing["inventory_info"]["listing_folder_id"].asUUID(); + LLUUID versionUuid = listing["inventory_info"]["version_folder_id"].asUUID(); + int onHand = listing["inventory_info"]["count_on_hand"].asInteger(); + + // Update that listing + LLMarketplaceData::instance(). + setListingID(folderUuid, listing_id, false); + LLMarketplaceData::instance(). + setVersionFolderID(folderUuid, versionUuid, false); + LLMarketplaceData::instance(). + setActivationState(folderUuid, is_listed, false); + LLMarketplaceData::instance(). + setListingURL(folderUuid, edit_url, false); + LLMarketplaceData::instance(). + setCountOnHand(folderUuid, onHand, false); + update_marketplace_category(folderUuid, false); + gInventory.notifyObservers(); + + // Show a notification alert if what we got is not what we expected + // (this actually doesn't result in an error status from the SLM API protocol) + if ((isListed != is_listed) || (versionId != versionUuid)) + { + LLSD subs; + subs["[URL]"] = edit_url; + LLNotificationsUtil::add("AlertMerchantListingNotUpdated", subs); + } + } + } + virtual char const* getName() const { return "updateSLMListingCoro"; } +private: + LLUUID folderId; + bool isListed; + LLUUID versionId; +}; + +class LLSLMAssociateListingsResponder : public LLHTTPClient::ResponderWithCompleted +{ + LOG_CLASS(LLSLMAssociateListingsResponder); +public: + + LLSLMAssociateListingsResponder(const LLUUID& folder_id, const LLUUID& source_folder_id) + { + folderId = folder_id; + sourceFolderId = source_folder_id; + } + + virtual void completedRaw(const LLChannelDescriptors& channels, + const LLIOPipe::buffer_ptr_t& buffer) + { + LLMarketplaceData::instance().setUpdating(folderId, false); + LLMarketplaceData::instance().setUpdating(sourceFolderId, false); + + std::string body; + decode_raw_body(channels, buffer, body); + + LLSD result = LlsdFromJsonString(body); + if (result.isUndefined()) + { + log_SLM_warning("Put /associate_inventory", getStatus(), getReason(), LLStringUtil::null, "Empty or Invalid JSON Response"); + return; + } + + if (!isGoodStatus(mStatus)) + { + log_SLM_warning("Put /associate_inventory", getStatus(), getReason(), LLStringUtil::null, result); + update_marketplace_category(folderId, false); + update_marketplace_category(sourceFolderId, false); + gInventory.notifyObservers(); + return; + } + + log_SLM_infos("Put /associate_inventory", getStatus(), body); + + for (auto const& listing : result["listings"].array()) + { + int listing_id = listing["id"].asInteger(); + bool is_listed = listing["is_listed"].asBoolean(); + std::string edit_url = listing["edit_url"].asString(); + LLUUID folder_uuid = listing["inventory_info"]["listing_folder_id"].asUUID(); + LLUUID version_uuid = listing["inventory_info"]["version_folder_id"].asUUID(); + int count = listing["inventory_info"]["count_on_hand"].asInteger(); + + // Check that the listing ID is not already associated to some other record + LLUUID old_listing = LLMarketplaceData::instance().getListingFolder(listing_id); + if (old_listing.notNull()) + { + // If it is already used, unlist the old record (we can't have 2 listings with the same listing ID) + LLMarketplaceData::instance().deleteListing(old_listing); + } + + // Add the new association + LLMarketplaceData::instance(). + addListing(folder_uuid, listing_id, version_uuid, is_listed, edit_url, count); + update_marketplace_category(folder_uuid, false); + gInventory.notifyObservers(); + + // The stock count needs to be updated with the new local count now + LLMarketplaceData::instance(). + updateCountOnHand(folder_uuid, 1); + } + + // Always update the source folder so its widget updates + update_marketplace_category(sourceFolderId, false); + } + + virtual char const* getName() const { return "associateSLMListingCoro"; } +private: + LLUUID folderId; // This is the folder now associated with the id. + LLUUID sourceFolderId; // This is the folder initially associated with the id. Can be LLUUID::null +}; + +class LLSLMDeleteListingsResponder : public LLHTTPClient::ResponderWithCompleted +{ + LOG_CLASS(LLSLMDeleteListingsResponder); +public: + + LLSLMDeleteListingsResponder(const LLUUID& folder_id) + { + folderId = folder_id; + } + + virtual void completedRaw(const LLChannelDescriptors& channels, + const LLIOPipe::buffer_ptr_t& buffer) + { + LLMarketplaceData::instance().setUpdating(folderId, false); + + std::string body; + decode_raw_body(channels, buffer, body); + LLSD result = LlsdFromJsonString(body); + if (result.isUndefined()) + { + log_SLM_warning("Delete /listing", getStatus(), getReason(), LLStringUtil::null, "Empty or Invalid JSON Response"); + return; + } + + if (!isGoodStatus(mStatus)) + { + log_SLM_warning("Delete /listing", getStatus(), getReason(), LLStringUtil::null, result); + update_marketplace_category(folderId, false); + gInventory.notifyObservers(); + return; + } + + log_SLM_infos("Delete /listing", getStatus(), body); + + for (auto const& listing : result["listings"].array()) + { + int listing_id = listing["id"].asInteger(); + LLUUID folder_id = LLMarketplaceData::instance().getListingFolder(listing_id); + LLMarketplaceData::instance().deleteListing(folder_id); + } + } + virtual char const* getName() const { return "deleteSLMListingCoro"; } +private: + LLUUID folderId; +}; + +// SLM Responders End +/////////////////////////////////////////////////////////////////////////////// namespace LLMarketplaceImport { // Basic interface for this namespace - bool hasSessionCookie(); bool inProgress(); bool resultPending(); - U32 getResultStatus(); + S32 getResultStatus(); const LLSD& getResults(); bool establishMarketplaceSessionCookie(); @@ -141,12 +680,12 @@ namespace LLMarketplaceImport // Internal state variables - static std::string sMarketplaceCookie = ""; + static std::string sMarketplaceCookie; static LLSD sImportId = LLSD::emptyMap(); static bool sImportInProgress = false; static bool sImportPostPending = false; static bool sImportGetPending = false; - static U32 sImportResultStatus = 0; + static S32 sImportResultStatus = 0; static LLSD sImportResults = LLSD::emptyMap(); static LLTimer slmGetTimer; @@ -156,57 +695,59 @@ namespace LLMarketplaceImport class LLImportPostResponder : public LLHTTPClient::ResponderWithCompleted { + LOG_CLASS(LLImportPostResponder); public: - /*virtual*/ void completed(U32 status, const std::string& reason, const LLSD& content) + void httpCompleted() override { slmPostTimer.stop(); if (gSavedSettings.getBOOL("InventoryOutboxLogging")) { - llinfos << " SLM POST status: " << status << llendl; - llinfos << " SLM POST reason: " << reason << llendl; - llinfos << " SLM POST content: " << content.asString() << llendl; - llinfos << " SLM POST timer: " << slmPostTimer.getElapsedTimeF32() << llendl; + LL_INFOS() << " SLM [timer:" << slmPostTimer.getElapsedTimeF32() << "] " + << dumpResponse() << LL_ENDL; } - // MAINT-2301 : we determined we can safely ignore that error in that context - if (status == MarketplaceErrorCodes::IMPORT_JOB_TIMEOUT) + S32 httpCode = getStatus(); + if ((httpCode == MarketplaceErrorCodes::IMPORT_REDIRECT) || + (httpCode == MarketplaceErrorCodes::IMPORT_AUTHENTICATION_ERROR) || + // MAINT-2301 : we determined we can safely ignore that error in that context + (httpCode == MarketplaceErrorCodes::IMPORT_JOB_TIMEOUT)) { if (gSavedSettings.getBOOL("InventoryOutboxLogging")) { - llinfos << " SLM POST : Ignoring time out status and treating it as success" << llendl; + LL_INFOS() << " SLM POST : Ignoring time out status and treating it as success" << LL_ENDL; } - status = MarketplaceErrorCodes::IMPORT_DONE; + httpCode = MarketplaceErrorCodes::IMPORT_DONE; } - if (status >= MarketplaceErrorCodes::IMPORT_BAD_REQUEST) + if (httpCode >= MarketplaceErrorCodes::IMPORT_BAD_REQUEST) { if (gSavedSettings.getBOOL("InventoryOutboxLogging")) { - llinfos << " SLM POST clearing marketplace cookie due to client or server error" << llendl; + LL_INFOS() << " SLM POST clearing marketplace cookie due to client or server error" << LL_ENDL; } sMarketplaceCookie.clear(); } - sImportInProgress = (status == MarketplaceErrorCodes::IMPORT_DONE); + sImportInProgress = (httpCode == MarketplaceErrorCodes::IMPORT_DONE); sImportPostPending = false; - sImportResultStatus = status; - sImportId = content; + sImportResultStatus = httpCode; + + sImportId = getContent(); } - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return MPImportPostResponder_timeout; } - /*virtual*/ char const* getName(void) const { return "LLImportPostResponder"; } + char const* getName() const override { return "LLImportPostResponder"; } }; class LLImportGetResponder : public LLHTTPClient::ResponderWithCompleted { + LOG_CLASS(LLImportGetResponder); public: - /*virtual*/ bool followRedir(void) const { return true; } /*virtual*/ bool needsHeaders(void) const { return true; } - /*virtual*/ void completedHeaders(U32 status, std::string const& reason, AIHTTPReceivedHeaders const& headers) + /*virtual*/ void completedHeaders(void) { - if (status == HTTP_OK) + if (mStatus == HTTP_OK) { std::string value = get_cookie("_slm_session"); if (!value.empty()) @@ -215,46 +756,47 @@ namespace LLMarketplaceImport } else if (sMarketplaceCookie.empty()) { - llwarns << "No such cookie \"_slm_session\" received!" << llendl; + LL_WARNS() << "No such cookie \"_slm_session\" received!" << LL_ENDL; } } } - /*virtual*/ void completed(U32 status, const std::string& reason, const LLSD& content) + /*virtual*/ void httpCompleted() { slmGetTimer.stop(); if (gSavedSettings.getBOOL("InventoryOutboxLogging")) { - llinfos << " SLM GET status: " << status << llendl; - llinfos << " SLM GET reason: " << reason << llendl; - llinfos << " SLM GET content: " << content.asString() << llendl; - llinfos << " SLM GET timer: " << slmGetTimer.getElapsedTimeF32() << llendl; + LL_INFOS() << " SLM [timer:" << slmGetTimer.getElapsedTimeF32() << "] " + << dumpResponse() << LL_ENDL; } - // MAINT-2452 : Do not clear the cookie on IMPORT_DONE_WITH_ERRORS - if ((status >= MarketplaceErrorCodes::IMPORT_BAD_REQUEST) && - (status != MarketplaceErrorCodes::IMPORT_DONE_WITH_ERRORS)) + // MAINT-2452 : Do not clear the cookie on IMPORT_DONE_WITH_ERRORS : Happens when trying to import objects with wrong permissions + // ACME-1221 : Do not clear the cookie on IMPORT_NOT_FOUND : Happens for newly created Merchant accounts that are initially empty + S32 httpCode = getStatus(); + if ((httpCode >= MarketplaceErrorCodes::IMPORT_BAD_REQUEST) && + (httpCode != MarketplaceErrorCodes::IMPORT_DONE_WITH_ERRORS) && + (httpCode != MarketplaceErrorCodes::IMPORT_NOT_FOUND)) { if (gSavedSettings.getBOOL("InventoryOutboxLogging")) { - llinfos << " SLM GET clearing marketplace cookie due to client or server error (" << status << " / " << reason << ")." << llendl; + LL_INFOS() << " SLM GET clearing marketplace cookie due to client or server error" << LL_ENDL; } sMarketplaceCookie.clear(); } - else if (gSavedSettings.getBOOL("InventoryOutboxLogging") && (status == MarketplaceErrorCodes::IMPORT_DONE_WITH_ERRORS)) + else if (gSavedSettings.getBOOL("InventoryOutboxLogging") && (httpCode >= MarketplaceErrorCodes::IMPORT_BAD_REQUEST)) { - llinfos << " SLM GET : Got IMPORT_DONE_WITH_ERRORS, marketplace cookie not cleared." << llendl; + LL_INFOS() << " SLM GET : Got error status = " << httpCode << ", but marketplace cookie not cleared." << LL_ENDL; } - sImportInProgress = (status == MarketplaceErrorCodes::IMPORT_PROCESSING); + sImportInProgress = (httpCode == MarketplaceErrorCodes::IMPORT_PROCESSING); sImportGetPending = false; - sImportResultStatus = status; - sImportResults = content; + sImportResultStatus = httpCode; + + sImportResults = getContent(); } - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return MPImportGetResponder_timeout; } - /*virtual*/ char const* getName(void) const { return "LLImportGetResponder"; } + char const* getName() const override { return "LLImportGetResponder"; } }; // Basic API @@ -274,7 +816,7 @@ namespace LLMarketplaceImport return (sImportPostPending || sImportGetPending); } - U32 getResultStatus() + S32 getResultStatus() { return sImportResultStatus; } @@ -307,13 +849,17 @@ namespace LLMarketplaceImport std::string url = getInventoryImportURL(); + AIHTTPHeaders headers = LLViewerMedia::getHeaders(); if (gSavedSettings.getBOOL("InventoryOutboxLogging")) { - llinfos << " SLM GET: " << url << llendl; + LL_INFOS() << " SLM GET: establishMarketplaceSessionCookie, LLHTTPClient::get, url = " << url << LL_ENDL; + std::stringstream str; + str << headers; //LLSDSerialize::toPrettyXML(headers, str); + LL_INFOS() << " SLM GET: headers " << LL_ENDL; + LL_INFOS() << str.str() << LL_ENDL; } slmGetTimer.start(); - AIHTTPHeaders headers = LLViewerMedia::getHeaders(); LLHTTPClient::get(url, new LLImportGetResponder(), headers); return true; @@ -336,14 +882,17 @@ namespace LLMarketplaceImport AIHTTPHeaders headers; headers.addHeader("Accept", "*/*"); headers.addHeader("Cookie", sMarketplaceCookie); + // *TODO: Why are we setting Content-Type for a GET request? headers.addHeader("Content-Type", "application/llsd+xml"); headers.addHeader("User-Agent", LLViewerMedia::getCurrentUserAgent()); if (gSavedSettings.getBOOL("InventoryOutboxLogging")) { - llinfos << " SLM GET: pollStatus, LLHTTPClient::get, url = " << url << llendl; - llinfos << " SLM GET: headers " << llendl; - llinfos << headers << llendl; + LL_INFOS() << " SLM GET: pollStatus, LLHTTPClient::get, url = " << url << LL_ENDL; + std::stringstream str; + str << headers; //LLSDSerialize::toPrettyXML(headers, str); + LL_INFOS() << " SLM GET: headers " << LL_ENDL; + LL_INFOS() << str.str() << LL_ENDL; } slmGetTimer.start(); @@ -377,9 +926,11 @@ namespace LLMarketplaceImport if (gSavedSettings.getBOOL("InventoryOutboxLogging")) { - llinfos << " SLM POST: triggerImport, LLHTTPClient::post, url = " << url << llendl; - llinfos << " SLM POST: headers " << llendl; - llinfos << headers << llendl; + LL_INFOS() << " SLM POST: triggerImport, LLHTTPClient::post, url = " << url << LL_ENDL; + std::stringstream str; + str << headers; //LLSDSerialize::toPrettyXML(headers, str); + LL_INFOS() << " SLM POST: headers " << LL_ENDL; + LL_INFOS() << str.str() << LL_ENDL; } slmPostTimer.start(); @@ -405,7 +956,6 @@ void LLMarketplaceInventoryImporter::update() if (update_timer.hasExpired()) { LLMarketplaceInventoryImporter::instance().updateImport(); - //static LLCachedControl MARKET_IMPORTER_UPDATE_FREQUENCY("MarketImporterUpdateFreq", 1.0f); update_timer.setTimerExpirySec(MARKET_IMPORTER_UPDATE_FREQUENCY); } } @@ -454,7 +1004,10 @@ boost::signals2::connection LLMarketplaceInventoryImporter::setStatusReportCallb void LLMarketplaceInventoryImporter::initialize() { - llassert(!mInitialized); + if (mInitialized) + { + return; + } if (!LLMarketplaceImport::hasSessionCookie()) { @@ -508,54 +1061,967 @@ void LLMarketplaceInventoryImporter::updateImport() // If we are no longer in progress if (!mImportInProgress) { + // Look for results success + mInitialized = LLMarketplaceImport::hasSessionCookie(); + + // Report results + if (mStatusReportSignal) + { + (*mStatusReportSignal)(LLMarketplaceImport::getResultStatus(), LLMarketplaceImport::getResults()); + } + if (mInitialized) { - // Report results - if (mStatusReportSignal) + mMarketPlaceStatus = MarketplaceStatusCodes::MARKET_PLACE_MERCHANT; + // Follow up with auto trigger of import + if (mAutoTriggerImport) { - (*mStatusReportSignal)(LLMarketplaceImport::getResultStatus(), LLMarketplaceImport::getResults()); + mAutoTriggerImport = false; + mImportInProgress = triggerImport(); } } else { - // Look for results success - mInitialized = LLMarketplaceImport::hasSessionCookie(); + U32 status = LLMarketplaceImport::getResultStatus(); + if ((status == MarketplaceErrorCodes::IMPORT_FORBIDDEN) || + (status == MarketplaceErrorCodes::IMPORT_AUTHENTICATION_ERROR)) + { + mMarketPlaceStatus = MarketplaceStatusCodes::MARKET_PLACE_NOT_MERCHANT; + } + else if (status == MarketplaceErrorCodes::IMPORT_SERVER_API_DISABLED) + { + mMarketPlaceStatus = MarketplaceStatusCodes::MARKET_PLACE_MIGRATED_MERCHANT; + } + else + { + mMarketPlaceStatus = MarketplaceStatusCodes::MARKET_PLACE_CONNECTION_FAILURE; + } + if (mErrorInitSignal && (mMarketPlaceStatus == MarketplaceStatusCodes::MARKET_PLACE_CONNECTION_FAILURE)) + { + (*mErrorInitSignal)(LLMarketplaceImport::getResultStatus(), LLMarketplaceImport::getResults()); + } + } + } + } + + // Make sure we trigger the status change with the final state (in case of auto trigger after initialize) + if (mStatusChangedSignal) + { + (*mStatusChangedSignal)(mImportInProgress); + } +} + +// +// Direct Delivery : Marketplace tuples and data +// +class LLMarketplaceInventoryObserver : public LLInventoryObserver +{ +public: + LLMarketplaceInventoryObserver() {} + virtual ~LLMarketplaceInventoryObserver() {} + virtual void changed(U32 mask); +}; + +void LLMarketplaceInventoryObserver::changed(U32 mask) +{ + // When things are added to the marketplace, we might need to re-validate and fix the containing listings + if (mask & LLInventoryObserver::ADD) + { + const uuid_set_t& changed_items = gInventory.getChangedIDs(); + + auto id_it = changed_items.begin(); + auto id_end = changed_items.end(); + // First, count the number of items in this list... + S32 count = 0; + for (;id_it != id_end; ++id_it) + { + LLInventoryObject* obj = gInventory.getObject(*id_it); + if (obj && (LLAssetType::AT_CATEGORY != obj->getType())) + { + count++; + } + } + // Then, decrement the folders of that amount + // Note that of all of those, only one folder will be a listing folder (if at all). + // The other will be ignored by the decrement method. + id_it = changed_items.begin(); + for (;id_it != id_end; ++id_it) + { + LLInventoryObject* obj = gInventory.getObject(*id_it); + if (obj && (LLAssetType::AT_CATEGORY == obj->getType())) + { + LLMarketplaceData::instance().decrementValidationWaiting(obj->getUUID(),count); + } + } + } + + // When things are changed in the inventory, this can trigger a host of changes in the marketplace listings folder: + // * stock counts changing : no copy items coming in and out will change the stock count on folders + // * version and listing folders : moving those might invalidate the marketplace data itself + // Since we should cannot raise inventory change while the observer is called (the list will be cleared + // once observers are called) we need to raise a flag in the inventory to signal that things have been dirtied. + + if (mask & (LLInventoryObserver::INTERNAL | LLInventoryObserver::STRUCTURE)) + { + const uuid_set_t& changed_items = gInventory.getChangedIDs(); - if (mInitialized) + auto id_it = changed_items.begin(); + auto id_end = changed_items.end(); + for (;id_it != id_end; ++id_it) + { + LLInventoryObject* obj = gInventory.getObject(*id_it); + if (obj) + { + if (LLAssetType::AT_CATEGORY == obj->getType()) { - mMarketPlaceStatus = MarketplaceStatusCodes::MARKET_PLACE_MERCHANT; - // Follow up with auto trigger of import - if (mAutoTriggerImport) + // If it's a folder known to the marketplace, let's check it's in proper shape + if (LLMarketplaceData::instance().isListed(*id_it) || LLMarketplaceData::instance().isVersionFolder(*id_it)) { - mAutoTriggerImport = false; - mImportInProgress = triggerImport(); + LLInventoryCategory* cat = (LLInventoryCategory*)(obj); + validate_marketplacelistings(cat); } } else { - U32 status = LLMarketplaceImport::getResultStatus(); - if ((status == MarketplaceErrorCodes::IMPORT_FORBIDDEN) || - (status == MarketplaceErrorCodes::IMPORT_AUTHENTICATION_ERROR)) - { - mMarketPlaceStatus = MarketplaceStatusCodes::MARKET_PLACE_NOT_MERCHANT; - } - else + // If it's not a category, it's an item... + LLInventoryItem* item = (LLInventoryItem*)(obj); + // If it's a no copy item, we may need to update the label count of marketplace listings + if (!item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID())) { - mMarketPlaceStatus = MarketplaceStatusCodes::MARKET_PLACE_CONNECTION_FAILURE; - } - if (mErrorInitSignal && (mMarketPlaceStatus == MarketplaceStatusCodes::MARKET_PLACE_CONNECTION_FAILURE)) - { - (*mErrorInitSignal)(LLMarketplaceImport::getResultStatus(), LLMarketplaceImport::getResults()); + LLMarketplaceData::instance().setDirtyCount(); } } } } + } +} - // Make sure we trigger the status change with the final state (in case of auto trigger after initialize) - if (mStatusChangedSignal) - { - (*mStatusChangedSignal)(mImportInProgress); - } +// Tuple == Item +LLMarketplaceTuple::LLMarketplaceTuple() : + mListingFolderId(), + mListingId(0), + mVersionFolderId(), + mIsActive(false), + mEditURL("") +{ +} + +LLMarketplaceTuple::LLMarketplaceTuple(const LLUUID& folder_id) : + mListingFolderId(folder_id), + mListingId(0), + mVersionFolderId(), + mIsActive(false), + mEditURL("") +{ +} + +LLMarketplaceTuple::LLMarketplaceTuple(const LLUUID& folder_id, S32 listing_id, const LLUUID& version_id, bool is_listed) : + mListingFolderId(folder_id), + mListingId(listing_id), + mVersionFolderId(version_id), + mIsActive(is_listed), + mEditURL("") +{ +} + + +// Data map +LLMarketplaceData::LLMarketplaceData() : + mMarketPlaceStatus(MarketplaceStatusCodes::MARKET_PLACE_NOT_INITIALIZED), + mMarketPlaceDataFetched(MarketplaceFetchCodes::MARKET_FETCH_NOT_DONE), + mStatusUpdatedSignal(NULL), + mDataFetchedSignal(NULL), + mDirtyCount(false) +{ + mInventoryObserver = new LLMarketplaceInventoryObserver; + gInventory.addObserver(mInventoryObserver); +} + +LLMarketplaceData::~LLMarketplaceData() +{ + gInventory.removeObserver(mInventoryObserver); +} + +void LLMarketplaceData::initializeSLM(const status_updated_signal_t::slot_type& cb) +{ + if (mStatusUpdatedSignal == NULL) + { + mStatusUpdatedSignal = new status_updated_signal_t(); } + mStatusUpdatedSignal->connect(cb); + + if (mMarketPlaceStatus != MarketplaceStatusCodes::MARKET_PLACE_NOT_INITIALIZED) + { + // If already initialized, just confirm the status so the callback gets called + setSLMStatus(mMarketPlaceStatus); + } + else + { + mMarketPlaceStatus = MarketplaceStatusCodes::MARKET_PLACE_INITIALIZING; + } + + std::string url = getSLMConnectURL("/merchant"); + if (url.empty()) + { + LL_WARNS("Marketplace") << "No marketplace capability on Sim" << LL_ENDL; + setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_CONNECTION_FAILURE); + return; + } + + log_SLM_infos("LLHTTPClient::get", url, LLStringUtil::null); + LLHTTPClient::get(url, new LLSLMGetMerchantResponder); +} + +void LLMarketplaceData::setDataFetchedSignal(const status_updated_signal_t::slot_type& cb) +{ + if (mDataFetchedSignal == NULL) + { + mDataFetchedSignal = new status_updated_signal_t(); + } + mDataFetchedSignal->connect(cb); +} + +// Get/Post/Put requests to the SLM Server using the SLM API +void LLMarketplaceData::getSLMListings() +{ + AIHTTPHeaders headers; + headers.addHeader("Accept", "application/json"); + headers.addHeader("Content-Type", "application/json"); + + // Send request + std::string url = getSLMConnectURL("/listings"); + log_SLM_infos("LLHTTPClient::get", url, ""); + const LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); + setUpdating(marketplacelistings_id, true); + LLHTTPClient::get(url, new LLSLMGetListingsResponder(marketplacelistings_id), headers); +} + +void LLMarketplaceData::getSLMListing(S32 listingId) +{ + LLUUID folderId = getListingFolder(listingId); + setUpdating(folderId, true); + + AIHTTPHeaders headers; + headers.addHeader("Accept", "application/json"); + headers.addHeader("Content-Type", "application/json"); + + // Send request + std::string url = getSLMConnectURL("/listing/") + llformat("%d", listingId); + log_SLM_infos("LLHTTPClient::get", url, LLStringUtil::null); + LLHTTPClient::get(url, new LLSLMGetListingResponder(folderId), headers); +} + +void LLMarketplaceData::createSLMListing(const LLUUID& folderId, const LLUUID& versionId, S32 count) +{ + AIHTTPHeaders headers; + headers.addHeader("Accept", "application/json"); + headers.addHeader("Content-Type", "application/json"); + + LLViewerInventoryCategory* category = gInventory.getCategory(folderId); + LLSD invInfo; + invInfo["listing_folder_id"] = folderId; + invInfo["version_folder_id"] = versionId; + invInfo["count_on_hand"] = count; + LLSD listing; + listing["name"] = category->getName(); + listing["inventory_info"] = invInfo; + LLSD postData; + postData["listing"] = listing; + + auto json = LlsdToJson(postData); + auto json_str = json.dump(); + + // postRaw() takes ownership of the buffer and releases it later. + size_t size = json_str.length(); + U8* data = new U8[size]; + memcpy(data, (U8*)(json_str.c_str()), size); + + // Send request + std::string url = getSLMConnectURL("/listings"); + log_SLM_infos("LLHTTPClient::postRaw", url, json_str); + setUpdating(folderId, true); + LLHTTPClient::postRaw(url, data, size, new LLSLMCreateListingsResponder(folderId), headers); +} + +void LLMarketplaceData::updateSLMListing(const LLUUID& folderId, S32 listingId, const LLUUID& versionId, bool isListed, S32 count) +{ + AIHTTPHeaders headers; + headers.addHeader("Accept", "application/json"); + headers.addHeader("Content-Type", "application/json"); + + // Note : auto unlist if the count is 0 (out of stock) + if (isListed && (count == 0)) + { + isListed = false; + LLNotificationsUtil::add("AlertMerchantStockFolderEmpty"); + } + + LLSD invInfo; + invInfo["listing_folder_id"] = folderId; + invInfo["version_folder_id"] = versionId; + invInfo["count_on_hand"] = count; + LLSD listing; + listing["inventory_info"] = invInfo; + listing["id"] = listingId; + listing["is_listed"] = isListed; + LLSD postData; + postData["listing"] = listing; + + auto json = LlsdToJson(postData); + auto json_str = json.dump(); + + // postRaw() takes ownership of the buffer and releases it later. + size_t size = json_str.size(); + U8* data = new U8[size]; + memcpy(data, (U8*)(json_str.c_str()), size); + + std::string url = getSLMConnectURL("/listing/") + llformat("%d", listingId); + log_SLM_infos("LLHTTPClient::putRaw", url, json_str); + setUpdating(folderId, true); + LLHTTPClient::putRaw(url, data, size, new LLSLMUpdateListingsResponder(folderId, isListed, versionId), headers); +} + +void LLMarketplaceData::associateSLMListing(const LLUUID& folderId, S32 listingId, const LLUUID& versionId, const LLUUID& sourceFolderId) +{ + AIHTTPHeaders headers; + headers.addHeader("Accept", "application/json"); + headers.addHeader("Content-Type", "application/json"); + + LLSD invInfo; + invInfo["listing_folder_id"] = folderId; + invInfo["version_folder_id"] = versionId; + LLSD listing; + listing["id"] = listingId; + listing["inventory_info"] = invInfo; + LLSD postData; + postData["listing"] = listing; + + auto json = LlsdToJson(postData); + auto json_str = json.dump(); + + // postRaw() takes ownership of the buffer and releases it later. + size_t size = json_str.size(); + U8* data = new U8[size]; + memcpy(data, (U8*)(json_str.c_str()), size); + + // Send request + std::string url = getSLMConnectURL("/associate_inventory/") + llformat("%d", listingId); + log_SLM_infos("LLHTTPClient::putRaw", url, json_str); + setUpdating(folderId, true); + setUpdating(sourceFolderId, true); + + LLHTTPClient::putRaw(url, data, size, new LLSLMAssociateListingsResponder(folderId, sourceFolderId), headers); +} + +void LLMarketplaceData::deleteSLMListing(S32 listingId) +{ + AIHTTPHeaders headers; + headers.addHeader("Accept", "application/json"); + headers.addHeader("Content-Type", "application/json"); + + // Send request + std::string url = getSLMConnectURL("/listing/") + llformat("%d", listingId); + log_SLM_infos("LLHTTPClient::del", url, ""); + LLUUID folderId = getListingFolder(listingId); + + setUpdating(folderId, true); + LLHTTPClient::del(url, new LLSLMDeleteListingsResponder(folderId), headers); +} + +std::string LLMarketplaceData::getSLMConnectURL(const std::string& route) +{ + std::string url; + LLViewerRegion* regionp = gAgent.getRegion(); + if (regionp) + { + // Get DirectDelivery cap + url = regionp->getCapability("DirectDelivery"); + if (!url.empty()) + { + url += route; + } + } + return url; +} + +void LLMarketplaceData::setSLMStatus(U32 status) +{ + mMarketPlaceStatus = status; + if (mStatusUpdatedSignal) + { + (*mStatusUpdatedSignal)(); + } +} + +void LLMarketplaceData::setSLMDataFetched(U32 status) +{ + mMarketPlaceDataFetched = status; + if (mDataFetchedSignal) + { + (*mDataFetchedSignal)(); + } +} + +// Creation / Deletion / Update +// Methods publicly called +bool LLMarketplaceData::createListing(const LLUUID& folder_id) +{ + if (isListed(folder_id)) + { + // Listing already exists -> exit with error + return false; + } + + // Get the version folder: if there is only one subfolder, we will set it as a version folder immediately + S32 count = -1; + LLUUID version_id = getVersionFolderIfUnique(folder_id); + if (version_id.notNull()) + { + count = compute_stock_count(version_id, true); + } + + // Validate the count on hand + if (count == COMPUTE_STOCK_NOT_EVALUATED) + { + // If the count on hand cannot be evaluated, we will consider it empty (out of stock) at creation time + // It will get reevaluated and updated once the items are fetched + count = 0; + } + + // Post the listing creation request to SLM + createSLMListing(folder_id, version_id, count); + + return true; +} + +bool LLMarketplaceData::clearListing(const LLUUID& folder_id, S32 depth) +{ + if (folder_id.isNull()) + { + // Folder doesn't exist -> exit with error + return false; + } + + // Evaluate the depth if it wasn't passed as a parameter + if (depth < 0) + { + depth = depth_nesting_in_marketplace(folder_id); + + } + // Folder id can be the root of the listing or not so we need to retrieve the root first + LLUUID listing_uuid = (isListed(folder_id) ? folder_id : nested_parent_id(folder_id, depth)); + S32 listing_id = getListingID(listing_uuid); + + if (listing_id == 0) + { + // Listing doesn't exist -> exit with error + return false; + } + + // Update the SLM Server so that this listing is deleted (actually, archived...) + deleteSLMListing(listing_id); + + return true; +} + +bool LLMarketplaceData::getListing(const LLUUID& folder_id, S32 depth) +{ + if (folder_id.isNull()) + { + // Folder doesn't exist -> exit with error + return false; + } + + // Evaluate the depth if it wasn't passed as a parameter + if (depth < 0) + { + depth = depth_nesting_in_marketplace(folder_id); + + } + // Folder id can be the root of the listing or not so we need to retrieve the root first + LLUUID listing_uuid = (isListed(folder_id) ? folder_id : nested_parent_id(folder_id, depth)); + S32 listing_id = getListingID(listing_uuid); + + if (listing_id == 0) + { + // Listing doesn't exist -> exit with error + return false; + } + + // Get listing data from SLM + getSLMListing(listing_id); + + return true; +} + +bool LLMarketplaceData::getListing(S32 listing_id) +{ + if (listing_id == 0) + { + return false; + } + + // Get listing data from SLM + getSLMListing(listing_id); + return true; +} + +bool LLMarketplaceData::activateListing(const LLUUID& folder_id, bool activate, S32 depth) +{ + // Evaluate the depth if it wasn't passed as a parameter + if (depth < 0) + { + depth = depth_nesting_in_marketplace(folder_id); + + } + // Folder id can be the root of the listing or not so we need to retrieve the root first + LLUUID listing_uuid = nested_parent_id(folder_id, depth); + S32 listing_id = getListingID(listing_uuid); + if (listing_id == 0) + { + // Listing doesn't exist -> exit with error + return false; + } + + if (getActivationState(listing_uuid) == activate) + { + // If activation state is unchanged, no point spamming SLM with an update + return true; + } + + LLUUID version_uuid = getVersionFolder(listing_uuid); + + // Also update the count on hand + S32 count = compute_stock_count(folder_id); + if (count == COMPUTE_STOCK_NOT_EVALUATED) + { + // If the count on hand cannot be evaluated locally, we should not change that SLM value + // We are assuming that this issue is local and should not modify server side values + count = getCountOnHand(listing_uuid); + } + + // Post the listing update request to SLM + updateSLMListing(listing_uuid, listing_id, version_uuid, activate, count); + + return true; +} + +bool LLMarketplaceData::setVersionFolder(const LLUUID& folder_id, const LLUUID& version_id, S32 depth) +{ + // Evaluate the depth if it wasn't passed as a parameter + if (depth < 0) + { + depth = depth_nesting_in_marketplace(folder_id); + + } + // Folder id can be the root of the listing or not so we need to retrieve the root first + LLUUID listing_uuid = nested_parent_id(folder_id, depth); + S32 listing_id = getListingID(listing_uuid); + if (listing_id == 0) + { + // Listing doesn't exist -> exit with error + return false; + } + + if (getVersionFolder(listing_uuid) == version_id) + { + // If version folder is unchanged, no point spamming SLM with an update + return true; + } + + // Note: if the version_id is cleared, we need to unlist the listing, otherwise, state unchanged + bool is_listed = (version_id.isNull() ? false : getActivationState(listing_uuid)); + + // Also update the count on hand + S32 count = compute_stock_count(version_id); + if (count == COMPUTE_STOCK_NOT_EVALUATED) + { + // If the count on hand cannot be evaluated, we will consider it empty (out of stock) when resetting the version folder + // It will get reevaluated and updated once the items are fetched + count = 0; + } + + // Post the listing update request to SLM + updateSLMListing(listing_uuid, listing_id, version_id, is_listed, count); + + return true; +} + +bool LLMarketplaceData::updateCountOnHand(const LLUUID& folder_id, S32 depth) +{ + // Evaluate the depth if it wasn't passed as a parameter + if (depth < 0) + { + depth = depth_nesting_in_marketplace(folder_id); + + } + // Folder id can be the root of the listing or not so we need to retrieve the root first + LLUUID listing_uuid = nested_parent_id(folder_id, depth); + S32 listing_id = getListingID(listing_uuid); + if (listing_id == 0) + { + // Listing doesn't exist -> exit with error + return false; + } + + // Compute the new count on hand + S32 count = compute_stock_count(folder_id); + + if (count == getCountOnHand(listing_uuid)) + { + // If count on hand is unchanged, no point spamming SLM with an update + return true; + } + else if (count == COMPUTE_STOCK_NOT_EVALUATED) + { + // If local count on hand is not known at that point, do *not* force an update to SLM + return false; + } + + // Get the unchanged values + bool is_listed = getActivationState(listing_uuid); + LLUUID version_uuid = getVersionFolder(listing_uuid); + + + // Post the listing update request to SLM + updateSLMListing(listing_uuid, listing_id, version_uuid, is_listed, count); + + // Force the local value as it prevents spamming (count update may occur in burst when restocking) + // Note that if SLM has a good reason to return a different value, it'll be updated by the responder + setCountOnHand(listing_uuid, count, false); + + return true; +} + +bool LLMarketplaceData::associateListing(const LLUUID& folder_id, const LLUUID& source_folder_id, S32 listing_id) +{ + if (isListed(folder_id)) + { + // Listing already exists -> exit with error + return false; + } + + // Get the version folder: if there is only one subfolder, we will set it as a version folder immediately + LLUUID version_id = getVersionFolderIfUnique(folder_id); + + // Post the listing associate request to SLM + associateSLMListing(folder_id, listing_id, version_id, source_folder_id); + + return true; +} + +// Methods privately called or called by SLM responders to perform changes +bool LLMarketplaceData::addListing(const LLUUID& folder_id, S32 listing_id, const LLUUID& version_id, bool is_listed, const std::string& edit_url, S32 count) +{ + mMarketplaceItems[folder_id] = LLMarketplaceTuple(folder_id, listing_id, version_id, is_listed); + mMarketplaceItems[folder_id].mEditURL = edit_url; + mMarketplaceItems[folder_id].mCountOnHand = count; + if (version_id.notNull()) + { + mVersionFolders[version_id] = folder_id; + } + return true; +} + +bool LLMarketplaceData::deleteListing(const LLUUID& folder_id, bool update) +{ + LLUUID version_folder = getVersionFolder(folder_id); + + if (mMarketplaceItems.erase(folder_id) != 1) + { + return false; + } + mVersionFolders.erase(version_folder); + + if (update) + { + update_marketplace_category(folder_id, false); + gInventory.notifyObservers(); + } + return true; +} + +bool LLMarketplaceData::deleteListing(S32 listing_id, bool update) +{ + if (listing_id == 0) + { + return false; + } + + LLUUID folder_id = getListingFolder(listing_id); + return deleteListing(folder_id, update); +} + +// Accessors +bool LLMarketplaceData::getActivationState(const LLUUID& folder_id) +{ + // Listing folder case + marketplace_items_list_t::iterator it = mMarketplaceItems.find(folder_id); + if (it != mMarketplaceItems.end()) + { + return (it->second).mIsActive; + } + // Version folder case + version_folders_list_t::iterator it_version = mVersionFolders.find(folder_id); + if (it_version != mVersionFolders.end()) + { + marketplace_items_list_t::iterator it = mMarketplaceItems.find(it_version->second); + if (it != mMarketplaceItems.end()) + { + return (it->second).mIsActive; + } + } + return false; +} + +S32 LLMarketplaceData::getListingID(const LLUUID& folder_id) +{ + marketplace_items_list_t::iterator it = mMarketplaceItems.find(folder_id); + return (it == mMarketplaceItems.end() ? 0 : (it->second).mListingId); +} + +S32 LLMarketplaceData::getCountOnHand(const LLUUID& folder_id) +{ + marketplace_items_list_t::iterator it = mMarketplaceItems.find(folder_id); + return (it == mMarketplaceItems.end() ? -1 : (it->second).mCountOnHand); +} + +LLUUID LLMarketplaceData::getVersionFolder(const LLUUID& folder_id) +{ + marketplace_items_list_t::iterator it = mMarketplaceItems.find(folder_id); + return (it == mMarketplaceItems.end() ? LLUUID::null : (it->second).mVersionFolderId); +} + +// Reverse lookup : find the listing folder id from the listing id +LLUUID LLMarketplaceData::getListingFolder(S32 listing_id) +{ + marketplace_items_list_t::iterator it = mMarketplaceItems.begin(); + while (it != mMarketplaceItems.end()) + { + if ((it->second).mListingId == listing_id) + { + return (it->second).mListingFolderId; + } + it++; + } + return LLUUID::null; +} + +std::string LLMarketplaceData::getListingURL(const LLUUID& folder_id, S32 depth) +{ + // Evaluate the depth if it wasn't passed as a parameter + if (depth < 0) + { + depth = depth_nesting_in_marketplace(folder_id); + + } + + LLUUID listing_uuid = nested_parent_id(folder_id, depth); + + marketplace_items_list_t::iterator it = mMarketplaceItems.find(listing_uuid); + return (it == mMarketplaceItems.end() ? "" : (it->second).mEditURL); +} + +bool LLMarketplaceData::isListed(const LLUUID& folder_id) +{ + marketplace_items_list_t::iterator it = mMarketplaceItems.find(folder_id); + return (it != mMarketplaceItems.end()); +} + +bool LLMarketplaceData::isListedAndActive(const LLUUID& folder_id) +{ + return (isListed(folder_id) && getActivationState(folder_id)); +} + +bool LLMarketplaceData::isVersionFolder(const LLUUID& folder_id) +{ + version_folders_list_t::iterator it = mVersionFolders.find(folder_id); + return (it != mVersionFolders.end()); +} + +bool LLMarketplaceData::isInActiveFolder(const LLUUID& obj_id, S32 depth) +{ + // Evaluate the depth if it wasn't passed as a parameter + if (depth < 0) + { + depth = depth_nesting_in_marketplace(obj_id); + + } + + LLUUID listing_uuid = nested_parent_id(obj_id, depth); + bool active = getActivationState(listing_uuid); + LLUUID version_uuid = getVersionFolder(listing_uuid); + return (active && ((obj_id == version_uuid) || gInventory.isObjectDescendentOf(obj_id, version_uuid))); +} + +LLUUID LLMarketplaceData::getActiveFolder(const LLUUID& obj_id, S32 depth) +{ + // Evaluate the depth if it wasn't passed as a parameter + if (depth < 0) + { + depth = depth_nesting_in_marketplace(obj_id); + + } + + LLUUID listing_uuid = nested_parent_id(obj_id, depth); + return (getActivationState(listing_uuid) ? getVersionFolder(listing_uuid) : LLUUID::null); +} + +bool LLMarketplaceData::isUpdating(const LLUUID& folder_id, S32 depth) +{ + // Evaluate the depth if it wasn't passed as a parameter + if (depth < 0) + { + depth = depth_nesting_in_marketplace(folder_id); + } + if ((depth <= 0) || (depth > 2)) + { + // Only listing and version folders though are concerned by that status + return false; + } + else + { + const LLUUID marketplace_listings_uuid = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); + auto it = mPendingUpdateSet.find(marketplace_listings_uuid); + if (it != mPendingUpdateSet.end()) + { + // If we're waiting for data for the marketplace listings root, we are in the updating process for all + return true; + } + else + { + // Check if the listing folder is waiting for data + LLUUID listing_uuid = nested_parent_id(folder_id, depth); + it = mPendingUpdateSet.find(listing_uuid); + return (it != mPendingUpdateSet.end()); + } + } +} + +void LLMarketplaceData::setUpdating(const LLUUID& folder_id, bool isUpdating) +{ + auto it = mPendingUpdateSet.find(folder_id); + if (it != mPendingUpdateSet.end()) + { + mPendingUpdateSet.erase(it); + } + if (isUpdating) + { + mPendingUpdateSet.insert(folder_id); + } +} + +void LLMarketplaceData::setValidationWaiting(const LLUUID& folder_id, S32 count) +{ + mValidationWaitingList[folder_id] = count; +} + +void LLMarketplaceData::decrementValidationWaiting(const LLUUID& folder_id, S32 count) +{ + waiting_list_t::iterator found = mValidationWaitingList.find(folder_id); + if (found != mValidationWaitingList.end()) + { + found->second -= count; + if (found->second <= 0) + { + mValidationWaitingList.erase(found); + LLInventoryCategory *cat = gInventory.getCategory(folder_id); + validate_marketplacelistings(cat); + update_marketplace_category(folder_id); + gInventory.notifyObservers(); + } + } +} + +// Private Modifiers +bool LLMarketplaceData::setListingID(const LLUUID& folder_id, S32 listing_id, bool update) +{ + marketplace_items_list_t::iterator it = mMarketplaceItems.find(folder_id); + if (it == mMarketplaceItems.end()) + { + return false; + } + + (it->second).mListingId = listing_id; + + if (update) + { + update_marketplace_category(folder_id, false); + gInventory.notifyObservers(); + } + return true; +} + +bool LLMarketplaceData::setCountOnHand(const LLUUID& folder_id, S32 count, bool update) +{ + marketplace_items_list_t::iterator it = mMarketplaceItems.find(folder_id); + if (it == mMarketplaceItems.end()) + { + return false; + } + + (it->second).mCountOnHand = count; + + return true; +} + +bool LLMarketplaceData::setVersionFolderID(const LLUUID& folder_id, const LLUUID& version_id, bool update) +{ + marketplace_items_list_t::iterator it = mMarketplaceItems.find(folder_id); + if (it == mMarketplaceItems.end()) + { + return false; + } + + LLUUID old_version_id = (it->second).mVersionFolderId; + if (old_version_id == version_id) + { + return false; + } + + (it->second).mVersionFolderId = version_id; + mVersionFolders.erase(old_version_id); + if (version_id.notNull()) + { + mVersionFolders[version_id] = folder_id; + } + + if (update) + { + update_marketplace_category(old_version_id, false); + update_marketplace_category(version_id, false); + gInventory.notifyObservers(); + } + return true; +} + +bool LLMarketplaceData::setActivationState(const LLUUID& folder_id, bool activate, bool update) +{ + marketplace_items_list_t::iterator it = mMarketplaceItems.find(folder_id); + if (it == mMarketplaceItems.end()) + { + return false; + } + + (it->second).mIsActive = activate; + + if (update) + { + update_marketplace_category((it->second).mListingFolderId, false); + gInventory.notifyObservers(); + } + return true; +} + +bool LLMarketplaceData::setListingURL(const LLUUID& folder_id, const std::string& edit_url, bool update) +{ + marketplace_items_list_t::iterator it = mMarketplaceItems.find(folder_id); + if (it == mMarketplaceItems.end()) + { + return false; + } + + (it->second).mEditURL = edit_url; + return true; } diff --git a/indra/newview/llmarketplacefunctions.h b/indra/newview/llmarketplacefunctions.h index 4e9e6ee81d..91a7410181 100644 --- a/indra/newview/llmarketplacefunctions.h +++ b/indra/newview/llmarketplacefunctions.h @@ -38,26 +38,24 @@ #include "llhttpstatuscodes.h" -LLSD getMarketplaceStringSubstitutions(); - namespace MarketplaceErrorCodes { enum eCode { - IMPORT_DONE = HTTP_OK, - IMPORT_PROCESSING = HTTP_ACCEPTED, - IMPORT_REDIRECT = HTTP_FOUND, - IMPORT_BAD_REQUEST = HTTP_BAD_REQUEST, - IMPORT_AUTHENTICATION_ERROR = HTTP_UNAUTHORIZED, - IMPORT_FORBIDDEN = HTTP_FORBIDDEN, - IMPORT_NOT_FOUND = HTTP_NOT_FOUND, - IMPORT_DONE_WITH_ERRORS = HTTP_CONFLICT, - IMPORT_JOB_FAILED = HTTP_GONE, + IMPORT_DONE = 200, + IMPORT_PROCESSING = 202, + IMPORT_REDIRECT = 302, + IMPORT_BAD_REQUEST = 400, + IMPORT_AUTHENTICATION_ERROR = 401, + IMPORT_FORBIDDEN = 403, + IMPORT_NOT_FOUND = 404, + IMPORT_DONE_WITH_ERRORS = 409, + IMPORT_JOB_FAILED = 410, IMPORT_JOB_LOW_SPEED = HTTP_INTERNAL_ERROR_LOW_SPEED, - IMPORT_JOB_TIMEOUT = HTTP_INTERNAL_ERROR_CURL_TIMEOUT, - IMPORT_SERVER_SITE_DOWN = HTTP_INTERNAL_SERVER_ERROR, - IMPORT_SERVER_API_DISABLED = HTTP_SERVICE_UNAVAILABLE, + IMPORT_JOB_TIMEOUT = 499, + IMPORT_SERVER_SITE_DOWN = 500, + IMPORT_SERVER_API_DISABLED = 503, }; } @@ -68,8 +66,21 @@ namespace MarketplaceStatusCodes MARKET_PLACE_NOT_INITIALIZED = 0, MARKET_PLACE_INITIALIZING = 1, MARKET_PLACE_CONNECTION_FAILURE = 2, - MARKET_PLACE_MERCHANT = 3, - MARKET_PLACE_NOT_MERCHANT = 4, + MARKET_PLACE_NOT_MERCHANT = 3, + MARKET_PLACE_MERCHANT = 4, + MARKET_PLACE_NOT_MIGRATED_MERCHANT = 5, + MARKET_PLACE_MIGRATED_MERCHANT = 6 + }; +} + +namespace MarketplaceFetchCodes +{ + enum sCode + { + MARKET_FETCH_NOT_DONE = 0, + MARKET_FETCH_LOADING = 1, + MARKET_FETCH_FAILED = 2, + MARKET_FETCH_DONE = 3 }; } @@ -92,6 +103,7 @@ class LLMarketplaceInventoryImporter void initialize(); bool triggerImport(); bool isImportInProgress() const { return mImportInProgress; } + bool isInitialized() const { return mInitialized; } U32 getMarketPlaceStatus() const { return mMarketPlaceStatus; } protected: @@ -110,6 +122,167 @@ class LLMarketplaceInventoryImporter }; +// Classes handling the data coming from and going to the Marketplace SLM Server DB: +// * implement the Marketplace API +// * cache the current Marketplace data (tuples) +// * provide methods to get Marketplace data on any inventory item +// * set Marketplace data +// * signal Marketplace updates to inventory +namespace SLMErrorCodes +{ + enum eCode + { + SLM_SUCCESS = 200, + SLM_RECORD_CREATED = 201, + SLM_MALFORMED_PAYLOAD = 400, + SLM_NOT_FOUND = 404, + }; +} + +class LLMarketplaceData; +class LLInventoryObserver; + +// A Marketplace item is known by its tuple +class LLMarketplaceTuple +{ +public: + friend class LLMarketplaceData; + + LLMarketplaceTuple(); + LLMarketplaceTuple(const LLUUID& folder_id); + LLMarketplaceTuple(const LLUUID& folder_id, S32 listing_id, const LLUUID& version_id, bool is_listed = false); + +private: + // Representation of a marketplace item in the Marketplace DB (well, what we know of it...) + LLUUID mListingFolderId; + S32 mListingId; + LLUUID mVersionFolderId; + bool mIsActive; + S32 mCountOnHand; + std::string mEditURL; +}; +// Notes: +// * The mListingFolderId is used as a key to this map. It could therefore be taken off the LLMarketplaceTuple objects themselves. +// * The SLM DB however uses mListingId as its primary key and it shows in its API. In the viewer though, the mListingFolderId is what we use to grab an inventory record. +typedef std::map marketplace_items_list_t; +typedef std::map version_folders_list_t; + +// Session cache of all Marketplace tuples +// Notes: +// * There's one and only one possible set of Marketplace dataset per agent and per session thus making it an LLSingleton +// * Some of those records might correspond to folders that do not exist in the inventory anymore. We do not clear them out though. They just won't show up in the UI. + +class LLSLMGetMerchantResponder; +class LLSLMGetListingsResponder; +class LLSLMCreateListingsResponder; +class LLSLMGetListingResponder; +class LLSLMUpdateListingsResponder; +class LLSLMAssociateListingsResponder; +class LLSLMDeleteListingsResponder; + +class LLMarketplaceData + : public LLSingleton +{ +public: + friend class LLSLMGetMerchantResponder; + friend class LLSLMGetListingsResponder; + friend class LLSLMCreateListingsResponder; + friend class LLSLMGetListingResponder; + friend class LLSLMUpdateListingsResponder; + friend class LLSLMAssociateListingsResponder; + friend class LLSLMDeleteListingsResponder; + + static LLSD getMarketplaceStringSubstitutions(); + LLMarketplaceData(); + virtual ~LLMarketplaceData(); + + // Public SLM API : Initialization and status + typedef boost::signals2::signal status_updated_signal_t; + void initializeSLM(const status_updated_signal_t::slot_type& cb); + U32 getSLMStatus() const { return mMarketPlaceStatus; } + void setSLMStatus(U32 status); + void getSLMListings(); + bool isEmpty() const { return (mMarketplaceItems.size() == 0); } + void setDataFetchedSignal(const status_updated_signal_t::slot_type& cb); + void setSLMDataFetched(U32 status); + U32 getSLMDataFetched() { return mMarketPlaceDataFetched; } + + // High level create/delete/set Marketplace data: each method returns true if the function succeeds, false if error + bool createListing(const LLUUID& folder_id); + bool activateListing(const LLUUID& folder_id, bool activate, S32 depth = -1); + bool clearListing(const LLUUID& folder_id, S32 depth = -1); + bool setVersionFolder(const LLUUID& folder_id, const LLUUID& version_id, S32 depth = -1); + bool associateListing(const LLUUID& folder_id, const LLUUID& source_folder_id, S32 listing_id); + bool updateCountOnHand(const LLUUID& folder_id, S32 depth = -1); + bool getListing(const LLUUID& folder_id, S32 depth = -1); + bool getListing(S32 listing_id); + bool deleteListing(S32 listing_id, bool update = true); + + // Probe the Marketplace data set to identify folders + bool isListed(const LLUUID& folder_id); // returns true if folder_id is a Listing folder + bool isListedAndActive(const LLUUID& folder_id); // returns true if folder_id is an active (listed) Listing folder + bool isVersionFolder(const LLUUID& folder_id); // returns true if folder_id is a Version folder + bool isInActiveFolder(const LLUUID& obj_id, S32 depth = -1); // returns true if the obj_id is buried in an active version folder + LLUUID getActiveFolder(const LLUUID& obj_id, S32 depth = -1); // returns the UUID of the active version folder obj_id is in + bool isUpdating(const LLUUID& folder_id, S32 depth = -1); // returns true if we're waiting from SLM incoming data for folder_id + + // Access Marketplace data set : each method returns a default value if the argument can't be found + bool getActivationState(const LLUUID& folder_id); + S32 getListingID(const LLUUID& folder_id); + LLUUID getVersionFolder(const LLUUID& folder_id); + std::string getListingURL(const LLUUID& folder_id, S32 depth = -1); + LLUUID getListingFolder(S32 listing_id); + S32 getCountOnHand(const LLUUID& folder_id); + + // Used to flag if stock count values for Marketplace have to be updated + bool checkDirtyCount() { if (mDirtyCount) { mDirtyCount = false; return true; } else { return false; } } + void setDirtyCount() { mDirtyCount = true; } + void setUpdating(const LLUUID& folder_id, bool isUpdating); + + // Used to decide when to run a validation on listing folders + void setValidationWaiting(const LLUUID& folder_id, S32 count); + void decrementValidationWaiting(const LLUUID& folder_id, S32 count = 1); + +private: + // Modify Marketplace data set : each method returns true if the function succeeds, false if error + // Used internally only by SLM Responders when data are received from the SLM Server + bool addListing(const LLUUID& folder_id, S32 listing_id, const LLUUID& version_id, bool is_listed, const std::string& edit_url, S32 count); + bool deleteListing(const LLUUID& folder_id, bool update = true); + bool setListingID(const LLUUID& folder_id, S32 listing_id, bool update = true); + bool setVersionFolderID(const LLUUID& folder_id, const LLUUID& version_id, bool update = true); + bool setActivationState(const LLUUID& folder_id, bool activate, bool update = true); + bool setListingURL(const LLUUID& folder_id, const std::string& edit_url, bool update = true); + bool setCountOnHand(const LLUUID& folder_id, S32 count, bool update = true); + + // Private SLM API : package data and get/post/put requests to the SLM Server through the SLM API + void createSLMListing(const LLUUID& folder_id, const LLUUID& version_id, S32 count); + void getSLMListing(S32 listing_id); + void updateSLMListing(const LLUUID& folder_id, S32 listing_id, const LLUUID& version_id, bool is_listed, S32 count); + void associateSLMListing(const LLUUID& folder_id, S32 listing_id, const LLUUID& version_id, const LLUUID& source_folder_id); + void deleteSLMListing(S32 listing_id); + std::string getSLMConnectURL(const std::string& route); + + // Handling Marketplace connection and inventory connection + U32 mMarketPlaceStatus; + status_updated_signal_t* mStatusUpdatedSignal; + LLInventoryObserver* mInventoryObserver; + bool mDirtyCount; // If true, stock count value need to be updated at the next check + + // Update data + U32 mMarketPlaceDataFetched; + status_updated_signal_t* mDataFetchedSignal; + uuid_set_t mPendingUpdateSet; + + // Listing folders waiting for validation + typedef std::map waiting_list_t; + waiting_list_t mValidationWaitingList; + + // The cache of SLM data (at last...) + marketplace_items_list_t mMarketplaceItems; + // We need a list (version folder -> listing folder) because such reverse lookups are frequent + version_folders_list_t mVersionFolders; +}; + #endif // LL_LLMARKETPLACEFUNCTIONS_H diff --git a/indra/newview/llmarketplacenotifications.cpp b/indra/newview/llmarketplacenotifications.cpp index 0886f9a990..8944d293ff 100644 --- a/indra/newview/llmarketplacenotifications.cpp +++ b/indra/newview/llmarketplacenotifications.cpp @@ -33,10 +33,6 @@ #include "llerror.h" -#include -#include - - namespace LLMarketplaceInventoryNotifications { typedef boost::signals2::signal no_copy_payload_cb_signal_t; @@ -54,7 +50,7 @@ namespace LLMarketplaceInventoryNotifications llassert(!no_copy_payloads.empty()); llassert(no_copy_cb_action != NULL); - BOOST_FOREACH(const LLSD& payload, no_copy_payloads) + for (const LLSD& payload : no_copy_payloads) { (*no_copy_cb_action)(payload); } diff --git a/indra/newview/llmarketplacenotifications.h b/indra/newview/llmarketplacenotifications.h index 83a4e163c7..d54761e462 100644 --- a/indra/newview/llmarketplacenotifications.h +++ b/indra/newview/llmarketplacenotifications.h @@ -30,7 +30,10 @@ #include +#ifndef BOOST_FUNCTION_HPP_INCLUDED #include +#define BOOST_FUNCTION_HPP_INCLUDED +#endif // diff --git a/indra/newview/llmaterialmgr.cpp b/indra/newview/llmaterialmgr.cpp index 0648b902a6..7ccded7883 100644 --- a/indra/newview/llmaterialmgr.cpp +++ b/indra/newview/llmaterialmgr.cpp @@ -50,6 +50,7 @@ #define MATERIALS_CAP_MATERIAL_FIELD "Material" #define MATERIALS_CAP_OBJECT_ID_FIELD "ID" #define MATERIALS_CAP_MATERIAL_ID_FIELD "MaterialID" +#define SIM_FEATURE_MAX_MATERIALS_PER_TRANSACTION "MaxMaterialsPerTransaction" #define MATERIALS_GET_MAX_ENTRIES 50 #define MATERIALS_GET_TIMEOUT (60.f * 20) @@ -72,8 +73,8 @@ class LLMaterialsResponder : public LLHTTPClient::ResponderWithResult LLMaterialsResponder(const std::string& pMethod, const std::string& pCapabilityURL, CallbackFunction pCallback); virtual ~LLMaterialsResponder(); - virtual void result(const LLSD& pContent); - virtual void error(U32 pStatus, const std::string& pReason); + virtual void httpSuccess(void); + virtual void httpFailure(void); /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return materialsResponder_timeout; } /*virtual*/ char const* getName(void) const { return "LLMaterialsResponder"; } @@ -95,18 +96,18 @@ LLMaterialsResponder::~LLMaterialsResponder() { } -void LLMaterialsResponder::result(const LLSD& pContent) +void LLMaterialsResponder::httpSuccess(void) { LL_DEBUGS("Materials") << LL_ENDL; - mCallback(true, pContent); + mCallback(true, mContent); } -void LLMaterialsResponder::error(U32 pStatus, const std::string& pReason) +void LLMaterialsResponder::httpFailure(void) { LL_WARNS("Materials") << "\n--------------------------------------------------------------------------\n" - << mMethod << " Error[" << pStatus << "] cannot access cap '" << MATERIALS_CAPABILITY_NAME - << "'\n with url '" << mCapabilityURL << "' because " << pReason + << mMethod << " Error[" << mStatus << "] cannot access cap '" << MATERIALS_CAPABILITY_NAME + << "'\n with url '" << mCapabilityURL << "' because " << mReason << "\n--------------------------------------------------------------------------" << LL_ENDL; @@ -133,7 +134,7 @@ LLMaterialMgr::~LLMaterialMgr() bool LLMaterialMgr::isGetPending(const LLUUID& region_id, const LLMaterialID& material_id) const { get_pending_map_t::const_iterator itPending = mGetPending.find(pending_material_t(region_id, material_id)); - return (mGetPending.end() != itPending) && (LLFrameTimer::getTotalSeconds() < itPending->second + MATERIALS_POST_TIMEOUT); + return (mGetPending.end() != itPending) && (LLFrameTimer::getTotalSeconds() < itPending->second + F64(MATERIALS_POST_TIMEOUT)); } void LLMaterialMgr::markGetPending(const LLUUID& region_id, const LLMaterialID& material_id) @@ -269,7 +270,7 @@ boost::signals2::connection LLMaterialMgr::getTE(const LLUUID& region_id, const bool LLMaterialMgr::isGetAllPending(const LLUUID& region_id) const { getall_pending_map_t::const_iterator itPending = mGetAllPending.find(region_id); - return (mGetAllPending.end() != itPending) && (LLFrameTimer::getTotalSeconds() < itPending->second + MATERIALS_GET_TIMEOUT); + return (mGetAllPending.end() != itPending) && (LLFrameTimer::getTotalSeconds() < itPending->second + F64(MATERIALS_GET_TIMEOUT)); } void LLMaterialMgr::getAll(const LLUUID& region_id) @@ -327,6 +328,25 @@ void LLMaterialMgr::remove(const LLUUID& object_id, const U8 te) put(object_id, te, LLMaterial::null); } +void LLMaterialMgr::setLocalMaterial(const LLUUID& region_id, LLMaterialPtr material_ptr) +{ + LLUUID uuid; + uuid.generate(); + LLMaterialID material_id(uuid); + while (mMaterials.end() != mMaterials.find(material_id)) + { //probability that this loop will executed is very, very low (one in a billion chance) + uuid.generate(); + material_id.set(uuid.mData); + } + + LL_DEBUGS("Materials") << "region " << region_id << "new local material id " << material_id << LL_ENDL; + mMaterials.insert(std::pair(material_id, material_ptr)); + + setMaterialCallbacks(material_id, material_ptr); + + mGetPending.erase(pending_material_t(region_id, material_id)); +} + const LLMaterialPtr LLMaterialMgr::setMaterial(const LLUUID& region_id, const LLMaterialID& material_id, const LLSD& material_data) { LL_DEBUGS("Materials") << "region " << region_id << " material id " << material_id << LL_ENDL; @@ -339,41 +359,39 @@ const LLMaterialPtr LLMaterialMgr::setMaterial(const LLUUID& region_id, const LL itMaterial = ret.first; } - // we may have cleared our queues on leaving a region before we recv'd our - // update for this material...too late now! - // - if (isGetPending(region_id, material_id)) - { - - TEMaterialPair te_mat_pair; - te_mat_pair.materialID = material_id; + setMaterialCallbacks(material_id, itMaterial->second); - U32 i = 0; - while (i < LLTEContents::MAX_TES) - { - te_mat_pair.te = i++; - get_callback_te_map_t::iterator itCallbackTE = mGetTECallbacks.find(te_mat_pair); - if (itCallbackTE != mGetTECallbacks.end()) - { - (*itCallbackTE->second)(material_id, itMaterial->second, te_mat_pair.te); - delete itCallbackTE->second; - mGetTECallbacks.erase(itCallbackTE); - } - } + mGetPending.erase(pending_material_t(region_id, material_id)); - get_callback_map_t::iterator itCallback = mGetCallbacks.find(material_id); - if (itCallback != mGetCallbacks.end()) - { - (*itCallback->second)(material_id, itMaterial->second); + return itMaterial->second; +} - delete itCallback->second; - mGetCallbacks.erase(itCallback); +void LLMaterialMgr::setMaterialCallbacks(const LLMaterialID& material_id, const LLMaterialPtr material_ptr) +{ + TEMaterialPair te_mat_pair; + te_mat_pair.materialID = material_id; + + U32 i = 0; + while (i < LLTEContents::MAX_TES && !mGetTECallbacks.empty()) + { + te_mat_pair.te = i++; + get_callback_te_map_t::iterator itCallbackTE = mGetTECallbacks.find(te_mat_pair); + if (itCallbackTE != mGetTECallbacks.end()) + { + (*itCallbackTE->second)(material_id, material_ptr, te_mat_pair.te); + delete itCallbackTE->second; + mGetTECallbacks.erase(itCallbackTE); } } - mGetPending.erase(pending_material_t(region_id, material_id)); + get_callback_map_t::iterator itCallback = mGetCallbacks.find(material_id); + if (itCallback != mGetCallbacks.end()) + { + (*itCallback->second)(material_id, material_ptr); - return itMaterial->second; + delete itCallback->second; + mGetCallbacks.erase(itCallback); + } } void LLMaterialMgr::onGetResponse(bool success, const LLSD& content, const LLUUID& region_id) @@ -402,9 +420,8 @@ void LLMaterialMgr::onGetResponse(bool success, const LLSD& content, const LLUUI llassert(response_data.isArray()); LL_DEBUGS("Materials") << "response has "<< response_data.size() << " materials" << LL_ENDL; - for (LLSD::array_const_iterator itMaterial = response_data.beginArray(); itMaterial != response_data.endArray(); ++itMaterial) + for (auto const& material_data : response_data.array()) { - const LLSD& material_data = *itMaterial; llassert(material_data.isMap()); llassert(material_data.has(MATERIALS_CAP_OBJECT_ID_FIELD)); @@ -447,9 +464,8 @@ void LLMaterialMgr::onGetAllResponse(bool success, const LLSD& content, const LL llassert(response_data.isArray()); LL_DEBUGS("Materials") << "response has "<< response_data.size() << " materials" << LL_ENDL; - for (LLSD::array_const_iterator itMaterial = response_data.beginArray(); itMaterial != response_data.endArray(); ++itMaterial) + for (auto const& material_data : response_data.array()) { - const LLSD& material_data = *itMaterial; llassert(material_data.isMap()); llassert(material_data.has(MATERIALS_CAP_OBJECT_ID_FIELD)); @@ -513,11 +529,9 @@ void LLMaterialMgr::onPutResponse(bool success, const LLSD& content) { llassert(response_data.isArray()); LL_DEBUGS("Materials") << "response has "<< response_data.size() << " materials" << LL_ENDL; - for (LLSD::array_const_iterator faceIter = response_data.beginArray(); faceIter != response_data.endArray(); ++faceIter) +#ifdef SHOW_ASSERT + for (auto const& face_data : response_data.array()) { -# ifndef LL_RELEASE_FOR_DOWNLOAD - const LLSD& face_data = *faceIter; // conditional to avoid unused variable warning -# endif llassert(face_data.isMap()); llassert(face_data.has(MATERIALS_CAP_OBJECT_ID_FIELD)); @@ -534,14 +548,15 @@ void LLMaterialMgr::onPutResponse(bool success, const LLSD& content) // *TODO: do we really still need to process this? } +#endif } } -static LLFastTimer::DeclareTimer FTM_MATERIALS_IDLE("Materials"); +static LLTrace::BlockTimerStatHandle FTM_MATERIALS_IDLE("Materials"); void LLMaterialMgr::onIdle(void*) { - LLFastTimer t(FTM_MATERIALS_IDLE); + LL_RECORD_BLOCK_TIME(FTM_MATERIALS_IDLE); LLMaterialMgr* instancep = LLMaterialMgr::getInstance(); @@ -555,11 +570,9 @@ void LLMaterialMgr::onIdle(void*) instancep->processGetAllQueue(); } - static LLFrameTimer mPutTimer; - if ( (!instancep->mPutQueue.empty()) && (mPutTimer.hasExpired()) ) + if (!instancep->mPutQueue.empty()) { instancep->processPutQueue(); - mPutTimer.reset(MATERIALS_PUT_THROTTLE_SECS); } } @@ -570,20 +583,20 @@ void LLMaterialMgr::processGetQueue() { get_queue_t::iterator itRegionQueue = loopRegionQueue++; - const LLUUID& region_id = itRegionQueue->first; + const LLUUID region_id = itRegionQueue->first; if (isGetAllPending(region_id)) { continue; } - const LLViewerRegion* regionp = LLWorld::instance().getRegionFromID(region_id); + LLViewerRegion* regionp = LLWorld::instance().getRegionFromID(region_id); if (!regionp) { LL_WARNS("Materials") << "Unknown region with id " << region_id.asString() << LL_ENDL; mGetQueue.erase(itRegionQueue); continue; } - else if (!regionp->capabilitiesReceived()) + else if (!regionp->capabilitiesReceived() || regionp->materialsCapThrottled()) { continue; } @@ -606,13 +619,14 @@ void LLMaterialMgr::processGetQueue() LLSD materialsData = LLSD::emptyArray(); material_queue_t& materials = itRegionQueue->second; + U32 max_entries = regionp->getMaxMaterialsPerTransaction(); material_queue_t::iterator loopMaterial = materials.begin(); - while ( (materials.end() != loopMaterial) && (materialsData.size() <= MATERIALS_GET_MAX_ENTRIES) ) + while ( (materials.end() != loopMaterial) && ((U32)materialsData.size() < max_entries) ) { material_queue_t::iterator itMaterial = loopMaterial++; materialsData.append((*itMaterial).asLLSD()); - materials.erase(itMaterial); markGetPending(region_id, *itMaterial); + materials.erase(itMaterial); } if (materials.empty()) { @@ -639,6 +653,7 @@ void LLMaterialMgr::processGetQueue() LL_DEBUGS("Materials") << "POSTing to region '" << regionp->getName() << "' at '"<< capURL << " for " << materialsData.size() << " materials." << "\ndata: " << ll_pretty_print_sd(materialsData) << LL_ENDL; LLHTTPClient::post(capURL, postData, materialsResponder); + regionp->resetMaterialsCapThrottle(); } } @@ -657,7 +672,7 @@ void LLMaterialMgr::processGetAllQueue() clearGetQueues(region_id); // Invalidates region_id continue; } - else if (!regionp->capabilitiesReceived()) + else if (!regionp->capabilitiesReceived() || regionp->materialsCapThrottled()) { continue; } @@ -674,6 +689,7 @@ void LLMaterialMgr::processGetAllQueue() LL_DEBUGS("Materials") << "GET all for region " << region_id << "url " << capURL << LL_ENDL; LLHTTPClient::ResponderPtr materialsResponder = new LLMaterialsResponder("GET", capURL, boost::bind(&LLMaterialMgr::onGetAllResponse, this, _1, _2, *itRegion)); LLHTTPClient::get(capURL, materialsResponder); + regionp->resetMaterialsCapThrottle(); mGetAllPending.insert(std::pair(region_id, LLFrameTimer::getTotalSeconds())); mGetAllQueue.erase(itRegion); // Invalidates region_id } @@ -681,7 +697,7 @@ void LLMaterialMgr::processGetAllQueue() void LLMaterialMgr::processPutQueue() { - typedef std::map regionput_request_map; + typedef std::map regionput_request_map; regionput_request_map requests; put_queue_t::iterator loopQueue = mPutQueue.begin(); @@ -691,25 +707,27 @@ void LLMaterialMgr::processPutQueue() const LLUUID& object_id = itQueue->first; const LLViewerObject* objectp = gObjectList.findObject(object_id); - if ( (!objectp) || (!objectp->getRegion()) ) + if ( !objectp ) { - LL_WARNS("Materials") << "Object or object region is NULL" << LL_ENDL; - + LL_WARNS("Materials") << "Object is NULL" << LL_ENDL; mPutQueue.erase(itQueue); - continue; } - - const LLViewerRegion* regionp = objectp->getRegion(); - if (!regionp->capabilitiesReceived()) + else { - continue; + LLViewerRegion* regionp = objectp->getRegion(); + if ( !regionp ) + { + LL_WARNS("Materials") << "Object region is NULL" << LL_ENDL; + mPutQueue.erase(itQueue); } - + else if ( regionp->capabilitiesReceived() && !regionp->materialsCapThrottled()) + { LLSD& facesData = requests[regionp]; facematerial_map_t& face_map = itQueue->second; + U32 max_entries = regionp->getMaxMaterialsPerTransaction(); facematerial_map_t::iterator itFace = face_map.begin(); - while ( (face_map.end() != itFace) && (facesData.size() < MATERIALS_GET_MAX_ENTRIES) ) + while ( (face_map.end() != itFace) && ((U32)facesData.size() < max_entries) ) { LLSD faceData = LLSD::emptyMap(); faceData[MATERIALS_CAP_FACE_FIELD] = static_cast(itFace->first); @@ -726,14 +744,17 @@ void LLMaterialMgr::processPutQueue() mPutQueue.erase(itQueue); } } + } + } for (regionput_request_map::const_iterator itRequest = requests.begin(); itRequest != requests.end(); ++itRequest) { - std::string capURL = itRequest->first->getCapability(MATERIALS_CAPABILITY_NAME); + LLViewerRegion* regionp = itRequest->first; + std::string capURL = regionp->getCapability(MATERIALS_CAPABILITY_NAME); if (capURL.empty()) { LL_WARNS("Materials") << "Capability '" << MATERIALS_CAPABILITY_NAME - << "' is not defined on region '" << itRequest->first->getName() << "'" << LL_ENDL; + << "' is not defined on region '" << regionp->getName() << "'" << LL_ENDL; continue; } @@ -756,6 +777,7 @@ void LLMaterialMgr::processPutQueue() LL_DEBUGS("Materials") << "put for " << itRequest->second.size() << " faces to region " << itRequest->first->getName() << LL_ENDL; LLHTTPClient::ResponderPtr materialsResponder = new LLMaterialsResponder("PUT", capURL, boost::bind(&LLMaterialMgr::onPutResponse, this, _1, _2)); LLHTTPClient::put(capURL, putData, materialsResponder); + regionp->resetMaterialsCapThrottle(); } else { diff --git a/indra/newview/llmaterialmgr.h b/indra/newview/llmaterialmgr.h index e317a791ad..b20fed92fd 100644 --- a/indra/newview/llmaterialmgr.h +++ b/indra/newview/llmaterialmgr.h @@ -55,14 +55,17 @@ class LLMaterialMgr : public LLSingleton boost::signals2::connection getAll(const LLUUID& region_id, getall_callback_t::slot_type cb); void put(const LLUUID& object_id, const U8 te, const LLMaterial& material); void remove(const LLUUID& object_id, const U8 te); - -protected: + + //explicitly add new material to material manager + void setLocalMaterial(const LLUUID& region_id, LLMaterialPtr material_ptr); + +private: void clearGetQueues(const LLUUID& region_id); bool isGetPending(const LLUUID& region_id, const LLMaterialID& material_id) const; bool isGetAllPending(const LLUUID& region_id) const; void markGetPending(const LLUUID& region_id, const LLMaterialID& material_id); const LLMaterialPtr setMaterial(const LLUUID& region_id, const LLMaterialID& material_id, const LLSD& material_data); - + void setMaterialCallbacks(const LLMaterialID& material_id, const LLMaterialPtr material_ptr); static void onIdle(void*); void processGetQueue(); void onGetResponse(bool success, const LLSD& content, const LLUUID& region_id); @@ -72,15 +75,6 @@ class LLMaterialMgr : public LLSingleton void onPutResponse(bool success, const LLSD& content); void onRegionRemoved(LLViewerRegion* regionp); -protected: - typedef std::set material_queue_t; - typedef std::map get_queue_t; - get_queue_t mGetQueue; - typedef std::pair pending_material_t; - typedef std::map get_pending_map_t; - get_pending_map_t mGetPending; - typedef std::map get_callback_map_t; - get_callback_map_t mGetCallbacks; // struct for TE-specific material ID query class TEMaterialPair @@ -108,22 +102,34 @@ class LLMaterialMgr : public LLSingleton bool operator()(const TEMaterialPair& left, const TEMaterialPair& right) const { return left < right; } }; - typedef boost::unordered_map get_callback_te_map_t; - get_callback_te_map_t mGetTECallbacks; + typedef std::set material_queue_t; + typedef std::map get_queue_t; + typedef std::pair pending_material_t; + typedef std::map get_pending_map_t; + typedef std::map get_callback_map_t; + + typedef boost::unordered_map get_callback_te_map_t; typedef std::set getall_queue_t; - getall_queue_t mGetAllQueue; - getall_queue_t mGetAllRequested; typedef std::map getall_pending_map_t; - getall_pending_map_t mGetAllPending; typedef std::map getall_callback_map_t; - getall_callback_map_t mGetAllCallbacks; - typedef std::map facematerial_map_t; typedef std::map put_queue_t; - put_queue_t mPutQueue; - material_map_t mMaterials; + + get_queue_t mGetQueue; + get_pending_map_t mGetPending; + get_callback_map_t mGetCallbacks; + + get_callback_te_map_t mGetTECallbacks; + getall_queue_t mGetAllQueue; + getall_queue_t mGetAllRequested; + getall_pending_map_t mGetAllPending; + getall_callback_map_t mGetAllCallbacks; + put_queue_t mPutQueue; + material_map_t mMaterials; + + U32 getMaxEntries(const LLViewerRegion* regionp); }; #endif // LL_LLMATERIALMGR_H diff --git a/indra/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp index b6a7fdb071..fe5b50253c 100644 --- a/indra/newview/llmediactrl.cpp +++ b/indra/newview/llmediactrl.cpp @@ -54,6 +54,7 @@ #include "llviewermenu.h" // linden library includes +#include "llclipboard.h" #include "llfocusmgr.h" #include "llsdutil.h" #include "lltextbox.h" @@ -70,14 +71,14 @@ LLMediaCtrl::Params::Params() : start_url("start_url"), border_visible("border_visible", false), decouple_texture_size("decouple_texture_size", false), + trusted_content("trusted_content", false), + focus_on_click("focus_on_click", true), texture_width("texture_width", 1024), texture_height("texture_height", 1024), caret_color("caret_color"), initial_mime_type("initial_mime_type"), - error_page_url("error_page_url"), media_id("media_id"), - trusted_content("trusted_content", false), - focus_on_click("focus_on_click", true) + error_page_url("error_page_url") { } @@ -85,24 +86,25 @@ LLMediaCtrl::LLMediaCtrl( const Params& p) : LLPanel( p.name, p.rect, FALSE), LLInstanceTracker(LLUUID::generateNewID()), mTextureDepthBytes( 4 ), - mBorder(NULL), + mBorder(nullptr), mFrequentUpdates( true ), mForceUpdate( false ), - mHomePageUrl( "" ), + mTrusted(p.trusted_content), mAlwaysRefresh( false ), - mMediaSource( 0 ), mTakeFocusOnClick( p.focus_on_click ), - mCurrentNavUrl( "about:blank" ), mStretchToFill( true ), mMaintainAspectRatio ( true ), - mDecoupleTextureSize ( false ), - mTextureWidth ( 1024 ), - mTextureHeight ( 1024 ), mClearCache(false), + mHoverTextChanged(false), + mDecoupleTextureSize ( false ), + mUpdateScrolls( false ), + mHomePageUrl( "" ), mHomePageMimeType(p.initial_mime_type), + mCurrentNavUrl( "about:blank" ), mErrorPageURL(p.error_page_url), - mTrusted(p.trusted_content), - mHoverTextChanged(false), + mMediaSource( nullptr ), + mTextureWidth ( 1024 ), + mTextureHeight ( 1024 ), mContextMenu() { { @@ -120,8 +122,8 @@ LLMediaCtrl::LLMediaCtrl( const Params& p) : if(!getDecoupleTextureSize()) { - S32 screen_width = llround((F32)getRect().getWidth() * LLUI::getScaleFactor().mV[VX]); - S32 screen_height = llround((F32)getRect().getHeight() * LLUI::getScaleFactor().mV[VY]); + S32 screen_width = ll_round((F32)getRect().getWidth() * LLUI::getScaleFactor().mV[VX]); + S32 screen_height = ll_round((F32)getRect().getHeight() * LLUI::getScaleFactor().mV[VY]); setTextureSize(screen_width, screen_height); } @@ -140,10 +142,17 @@ LLMediaCtrl::LLMediaCtrl( const Params& p) : LLMediaCtrl::~LLMediaCtrl() { + auto menu = mContextMenu.get(); + if (menu) + { + menu->die(); + mContextMenu.markDead(); + } + if (mMediaSource) { mMediaSource->remObserver( this ); - mMediaSource = NULL; + mMediaSource = nullptr; } } @@ -157,7 +166,9 @@ void LLMediaCtrl::setBorderVisible( BOOL border_visible ) addChild( mBorder ); } if(mBorder) + { mBorder->setVisible(border_visible); + } }; //////////////////////////////////////////////////////////////////////////////// @@ -196,7 +207,10 @@ BOOL LLMediaCtrl::handleScrollWheel( S32 x, S32 y, S32 clicks ) { if (LLPanel::handleScrollWheel(x, y, clicks)) return TRUE; if (mMediaSource && mMediaSource->hasMedia()) - mMediaSource->getMediaPlugin()->scrollEvent(0, clicks, gKeyboard->currentMask(TRUE)); + { + convertInputCoords(x, y); + mMediaSource->scrollWheel(x, y, 0, clicks, gKeyboard->currentMask(TRUE)); + } return TRUE; } @@ -240,7 +254,7 @@ BOOL LLMediaCtrl::handleMouseUp( S32 x, S32 y, MASK mask ) mMediaSource->mouseUp(x, y, mask); } - gFocusMgr.setMouseCapture( NULL ); + gFocusMgr.setMouseCapture(nullptr ); return TRUE; } @@ -285,7 +299,7 @@ BOOL LLMediaCtrl::handleRightMouseUp( S32 x, S32 y, MASK mask ) } } - gFocusMgr.setMouseCapture( NULL ); + gFocusMgr.setMouseCapture(nullptr ); return TRUE; } @@ -309,12 +323,19 @@ BOOL LLMediaCtrl::handleRightMouseDown( S32 x, S32 y, MASK mask ) setFocus( TRUE ); } - LLMenuGL* menu = (LLMenuGL*)mContextMenu.get(); - if (menu) + auto con_menu = (LLMenuGL*)mContextMenu.get(); + if (con_menu) { - menu->buildDrawLabels(); - menu->updateParent(LLMenuGL::sMenuContainer); - LLMenuGL::showPopup(this,menu, x, y); + /* Singu Note: Share your toys!! + // hide/show debugging options + bool media_plugin_debugging_enabled = gSavedSettings.getBOOL("MediaPluginDebugging"); + con_menu->setItemVisible("open_webinspector", media_plugin_debugging_enabled ); + con_menu->setItemVisible("debug_separator", media_plugin_debugging_enabled ); + */ + + con_menu->buildDrawLabels(); + con_menu->updateParent(LLMenuGL::sMenuContainer); + LLMenuGL::showPopup(this, con_menu, x, y); } return TRUE; @@ -366,7 +387,7 @@ void LLMediaCtrl::onFocusLost() if( LLEditMenuHandler::gEditMenuHandler == mMediaSource ) { // Clear focus for edit menu items - LLEditMenuHandler::gEditMenuHandler = NULL; + LLEditMenuHandler::gEditMenuHandler = nullptr; } } @@ -379,22 +400,43 @@ void LLMediaCtrl::onFocusLost() // BOOL LLMediaCtrl::postBuild () { - LLMenuGL* menu = LLUICtrlFactory::getInstance()->buildMenu("menu_media_ctrl.xml",LLMenuGL::sMenuContainer); + /*LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registar; + registar.add("Copy.PageURL", boost::bind(&LLMediaCtrl::onCopyURL, this)); + registar.add("Open.WebInspector", boost::bind(&LLMediaCtrl::onOpenWebInspector, this)); + registar.add("Open.ViewSource", boost::bind(&LLMediaCtrl::onShowSource, this)); + + // stinson 05/05/2014 : use this as the parent of the context menu if the static menu + // container has yet to be created + LLView* menuParent = (gMenuHolder != nullptr) ? dynamic_cast(gMenuHolder) : dynamic_cast(this); + llassert(menuParent != NULL);*/ + auto menu = LLUICtrlFactory::getInstance()->buildMenu("menu_media_ctrl.xml",LLMenuGL::sMenuContainer); if(menu) { mContextMenu = menu->getHandle(); } - setVisibleCallback(boost::bind(&LLMediaCtrl::onVisibilityChange, this, _2)); + setVisibleCallback(boost::bind(&LLMediaCtrl::onVisibilityChanged, this, _2)); return true; } +void LLMediaCtrl::onCopyURL() const +{ + auto wurl = utf8str_to_wstring(mCurrentNavUrl); + gClipboard.copyFromSubstring(wurl, 0, wurl.size()); +} + void LLMediaCtrl::onOpenWebInspector() { if (mMediaSource && mMediaSource->hasMedia()) mMediaSource->getMediaPlugin()->showWebInspector( true ); } +void LLMediaCtrl::onShowSource() +{ + if (mMediaSource && mMediaSource->hasMedia()) + mMediaSource->getMediaPlugin()->showPageSource(); +} + //////////////////////////////////////////////////////////////////////////////// // BOOL LLMediaCtrl::handleKeyHere( KEY key, MASK mask ) @@ -412,11 +454,28 @@ BOOL LLMediaCtrl::handleKeyHere( KEY key, MASK mask ) return result; } +//////////////////////////////////////////////////////////////////////////////// +// +BOOL LLMediaCtrl::handleKeyUpHere(KEY key, MASK mask) +{ + BOOL result = FALSE; + + if (mMediaSource) + { + result = mMediaSource->handleKeyUpHere(key, mask); + } + + if (!result) + result = LLPanel::handleKeyUpHere(key, mask); + + return result; +} + //////////////////////////////////////////////////////////////////////////////// // void LLMediaCtrl::handleVisibilityChange ( BOOL new_visibility ) { - llinfos << "visibility changed to " << (new_visibility?"true":"false") << llendl; + LL_INFOS() << "visibility changed to " << (new_visibility?"true":"false") << LL_ENDL; if(mMediaSource) { mMediaSource->setVisible( new_visibility ); @@ -429,12 +488,9 @@ BOOL LLMediaCtrl::handleUnicodeCharHere(llwchar uni_char) { BOOL result = FALSE; - // only accept 'printable' characters, sigh... - if (uni_char >= 32 // discard 'control' characters - && uni_char != 127) // SDL thinks this is 'delete' - yuck. + if (mMediaSource) { - if (mMediaSource) - result = mMediaSource->handleUnicodeCharHere(uni_char); + result = mMediaSource->handleUnicodeCharHere(uni_char); } if ( ! result ) @@ -445,7 +501,7 @@ BOOL LLMediaCtrl::handleUnicodeCharHere(llwchar uni_char) //////////////////////////////////////////////////////////////////////////////// // -void LLMediaCtrl::onVisibilityChange ( const LLSD& new_visibility ) +void LLMediaCtrl::onVisibilityChanged( const LLSD& new_visibility ) { // set state of frequent updates automatically if visibility changes if ( new_visibility.asBoolean() ) @@ -464,8 +520,8 @@ void LLMediaCtrl::reshape( S32 width, S32 height, BOOL called_from_parent ) { if(!getDecoupleTextureSize()) { - S32 screen_width = llround((F32)width * LLUI::getScaleFactor().mV[VX]); - S32 screen_height = llround((F32)height * LLUI::getScaleFactor().mV[VY]); + S32 screen_width = ll_round((F32)width * LLUI::getScaleFactor().mV[VX]); + S32 screen_height = ll_round((F32)height * LLUI::getScaleFactor().mV[VY]); // when floater is minimized, these sizes are negative if ( screen_height > 0 && screen_width > 0 ) @@ -497,6 +553,16 @@ void LLMediaCtrl::navigateForward() } } +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaCtrl::navigateStop() +{ + if (mMediaSource && mMediaSource->hasMedia()) + { + mMediaSource->getMediaPlugin()->browse_stop(); + } +} + //////////////////////////////////////////////////////////////////////////////// // bool LLMediaCtrl::canNavigateBack() @@ -534,23 +600,7 @@ void LLMediaCtrl::clearCache() //////////////////////////////////////////////////////////////////////////////// // -void LLMediaCtrl::set404RedirectUrl( std::string redirect_url ) -{ - if(mMediaSource && mMediaSource->hasMedia()) - mMediaSource->getMediaPlugin()->set_status_redirect( 404, redirect_url ); -} - -//////////////////////////////////////////////////////////////////////////////// -// -void LLMediaCtrl::clr404RedirectUrl() -{ - if(mMediaSource && mMediaSource->hasMedia()) - mMediaSource->getMediaPlugin()->set_status_redirect(404, ""); -} - -//////////////////////////////////////////////////////////////////////////////// -// -void LLMediaCtrl::navigateTo( std::string url_in, std::string mime_type) +void LLMediaCtrl::navigateTo( std::string url_in, std::string mime_type, bool clean_browser) { // don't browse to anything that starts with secondlife:// or sl:// const std::string protocol1 = "secondlife://"; @@ -559,7 +609,7 @@ void LLMediaCtrl::navigateTo( std::string url_in, std::string mime_type) (LLStringUtil::compareInsensitive(url_in.substr(0, protocol2.length()), protocol2) == 0)) { // TODO: Print out/log this attempt? - // llinfos << "Rejecting attempt to load restricted website :" << urlIn << llendl; + // LL_INFOS() << "Rejecting attempt to load restricted website :" << urlIn << LL_ENDL; return; } @@ -567,7 +617,7 @@ void LLMediaCtrl::navigateTo( std::string url_in, std::string mime_type) { mCurrentNavUrl = url_in; mMediaSource->setSize(mTextureWidth, mTextureHeight); - mMediaSource->navigateTo(url_in, mime_type, mime_type.empty()); + mMediaSource->navigateTo(url_in, mime_type, mime_type.empty(), false, clean_browser); } } @@ -575,27 +625,20 @@ void LLMediaCtrl::navigateTo( std::string url_in, std::string mime_type) // void LLMediaCtrl::navigateToLocalPage( const std::string& subdir, const std::string& filename_in ) { - std::string language = LLUI::getLanguage(); std::string filename(gDirUtilp->add(subdir, filename_in)); + std::string expanded_filename = gDirUtilp->findSkinnedFilename("html", filename); - std::string expanded_filename = gDirUtilp->findSkinnedFilename("html", language, filename); - - if (expanded_filename.empty() && language != "en-us") - { - expanded_filename = gDirUtilp->findSkinnedFilename("html", "en-us", filename); - } if(expanded_filename.empty()) { - llwarns << "File " << filename << "not found" << llendl; + LL_WARNS() << "File " << filename << "not found" << LL_ENDL; return; } if (ensureMediaSourceExists()) { mCurrentNavUrl = expanded_filename; mMediaSource->setSize(mTextureWidth, mTextureHeight); - mMediaSource->navigateTo(expanded_filename, "text/html", false); + mMediaSource->navigateTo(LLWeb::escapeURL(expanded_filename), "text/html", false); } - } //////////////////////////////////////////////////////////////////////////////// @@ -685,7 +728,13 @@ bool LLMediaCtrl::ensureMediaSourceExists() mMediaSource->addObserver( this ); mMediaSource->setBackgroundColor( getBackgroundColor() ); mMediaSource->setTrustedBrowser(mTrusted); - mMediaSource->setPageZoomFactor( LLUI::getScaleFactor().mV[ VX ] ); + + F32 scale_factor = LLUI::getScaleFactor().mV[ VX ]; + if (scale_factor != mMediaSource->getPageZoomFactor()) + { + mMediaSource->setPageZoomFactor( scale_factor ); + mUpdateScrolls = true; + } if(mClearCache) { @@ -695,7 +744,7 @@ bool LLMediaCtrl::ensureMediaSourceExists() } else { - llwarns << "media source create failed " << llendl; + LL_WARNS() << "media source create failed " << LL_ENDL; // return; } } @@ -707,7 +756,11 @@ bool LLMediaCtrl::ensureMediaSourceExists() // void LLMediaCtrl::unloadMediaSource() { - mMediaSource = NULL; + if (mMediaSource) + { + mMediaSource->remObserver(this); + mMediaSource = nullptr; + } } //////////////////////////////////////////////////////////////////////////////// @@ -721,10 +774,11 @@ LLPluginClassMedia* LLMediaCtrl::getMediaPlugin() // void LLMediaCtrl::draw() { - if ( gRestoreGL == 1 ) + if ( gRestoreGL == 1 || mUpdateScrolls) { LLRect r = getRect(); reshape( r.getWidth(), r.getHeight(), FALSE ); + mUpdateScrolls = false; return; } @@ -742,12 +796,12 @@ void LLMediaCtrl::draw() // alpha off for this LLGLSUIDefault gls_ui; - LLGLDisable gls_alphaTest( GL_ALPHA_TEST ); + LLGLDisable gls_alpha_test; bool draw_media = false; - LLPluginClassMedia* media_plugin = NULL; - LLViewerMediaTexture* media_texture = NULL; + LLPluginClassMedia* media_plugin = nullptr; + LLViewerMediaTexture* media_texture = nullptr; if(mMediaSource && mMediaSource->hasMedia()) { @@ -770,7 +824,12 @@ void LLMediaCtrl::draw() { gGL.pushUIMatrix(); { - mMediaSource->setPageZoomFactor( LLUI::getScaleFactor().mV[ VX ] ); + F32 scale_factor = LLUI::getScaleFactor().mV[ VX ]; + if (scale_factor != mMediaSource->getPageZoomFactor()) + { + mMediaSource->setPageZoomFactor( scale_factor ); + mUpdateScrolls = true; + } // scale texture to fit the space using texture coords gGL.getTexUnit(0)->bind(media_texture); @@ -779,56 +838,12 @@ void LLMediaCtrl::draw() F32 max_u = ( F32 )media_plugin->getWidth() / ( F32 )media_plugin->getTextureWidth(); F32 max_v = ( F32 )media_plugin->getHeight() / ( F32 )media_plugin->getTextureHeight(); - LLRect r = getRect(); - S32 width, height; - S32 x_offset = 0; - S32 y_offset = 0; - - if(mStretchToFill) - { - if(mMaintainAspectRatio) - { - F32 media_aspect = (F32)(media_plugin->getWidth()) / (F32)(media_plugin->getHeight()); - F32 view_aspect = (F32)(r.getWidth()) / (F32)(r.getHeight()); - if(media_aspect > view_aspect) - { - // max width, adjusted height - width = r.getWidth(); - height = llmin(llmax(llround(width / media_aspect), 0), r.getHeight()); - } - else - { - // max height, adjusted width - height = r.getHeight(); - width = llmin(llmax(llround(height * media_aspect), 0), r.getWidth()); - } - } - else - { - width = r.getWidth(); - height = r.getHeight(); - } - } - else - { - width = llmin(media_plugin->getWidth(), r.getWidth()); - height = llmin(media_plugin->getHeight(), r.getHeight()); - } - - x_offset = (r.getWidth() - width) / 2; - y_offset = (r.getHeight() - height) / 2; - - /*if (mIgnoreUIScale) - { - x_offset = llround((F32)x_offset * LLUI::getScaleFactor().mV[VX]); - y_offset = llround((F32)y_offset * LLUI::getScaleFactor().mV[VY]); - width = llround((F32)width * LLUI::getScaleFactor().mV[VX]); - height = llround((F32)height * LLUI::getScaleFactor().mV[VY]); - }*/ + S32 x_offset, y_offset, width, height; + calcOffsetsAndSize(&x_offset, &y_offset, &width, &height); // draw the browser gGL.setSceneBlendType(LLRender::BT_REPLACE); - gGL.begin( LLRender::QUADS ); + gGL.begin( LLRender::TRIANGLE_STRIP ); if (! media_plugin->getTextureCoordsOpenGL()) { // render using web browser reported width and height, instead of trying to invert GL scale @@ -838,11 +853,11 @@ void LLMediaCtrl::draw() gGL.texCoord2f( 0.f, 0.f ); gGL.vertex2i( x_offset, y_offset + height ); + gGL.texCoord2f(max_u, max_v); + gGL.vertex2i(x_offset + width, y_offset); + gGL.texCoord2f( 0.f, max_v ); gGL.vertex2i( x_offset, y_offset ); - - gGL.texCoord2f( max_u, max_v ); - gGL.vertex2i( x_offset + width, y_offset ); } else { @@ -853,11 +868,11 @@ void LLMediaCtrl::draw() gGL.texCoord2f( 0.f, max_v ); gGL.vertex2i( x_offset, y_offset + height ); + gGL.texCoord2f(max_u, 0.f); + gGL.vertex2i(x_offset + width, y_offset); + gGL.texCoord2f( 0.f, 0.f ); gGL.vertex2i( x_offset, y_offset ); - - gGL.texCoord2f( max_u, 0.f ); - gGL.vertex2i( x_offset + width, y_offset ); } gGL.end(); gGL.setSceneBlendType(LLRender::BT_ALPHA); @@ -883,6 +898,50 @@ void LLMediaCtrl::draw() setBackgroundOpaque(background_opaque); } +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaCtrl::calcOffsetsAndSize(S32 *x_offset, S32 *y_offset, S32 *width, S32 *height) +{ + const LLRect &r = getRect(); + *x_offset = *y_offset = 0; + + const auto& media_plugin = mMediaSource->getMediaPlugin(); + + if(mStretchToFill) + { + if(mMaintainAspectRatio) + { + F32 media_aspect = (F32)(media_plugin->getWidth()) / (F32)(media_plugin->getHeight()); + F32 view_aspect = (F32)(r.getWidth()) / (F32)(r.getHeight()); + if(media_aspect > view_aspect) + { + // max width, adjusted height + *width = r.getWidth(); + *height = llmin(llmax(ll_round(*width / media_aspect), 0), r.getHeight()); + } + else + { + // max height, adjusted width + *height = r.getHeight(); + *width = llmin(llmax(ll_round(*height * media_aspect), 0), r.getWidth()); + } + } + else + { + *width = r.getWidth(); + *height = r.getHeight(); + } + } + else + { + *width = llmin(media_plugin->getWidth(), r.getWidth()); + *height = llmin(media_plugin->getHeight(), r.getHeight()); + } + + *x_offset = (r.getWidth() - *width) / 2; + *y_offset = (r.getHeight() - *height) / 2; +} + //////////////////////////////////////////////////////////////////////////////// // void LLMediaCtrl::convertInputCoords(S32& x, S32& y) @@ -894,14 +953,14 @@ void LLMediaCtrl::convertInputCoords(S32& x, S32& y) coords_opengl = mMediaSource->getMediaPlugin()->getTextureCoordsOpenGL(); } - x = llround((F32)x * LLUI::getScaleFactor().mV[VX]); + x = ll_round((F32)x * LLUI::getScaleFactor().mV[VX]); if ( ! coords_opengl ) { - y = llround((F32)(y) * LLUI::getScaleFactor().mV[VY]); + y = ll_round((F32)(y) * LLUI::getScaleFactor().mV[VY]); } else { - y = llround((F32)(getRect().getHeight() - y) * LLUI::getScaleFactor().mV[VY]); + y = ll_round((F32)(getRect().getHeight() - y) * LLUI::getScaleFactor().mV[VY]); }; } @@ -937,7 +996,7 @@ void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event) LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CURSOR_CHANGED, new cursor is " << self->getCursorName() << LL_ENDL; } break; - + case MEDIA_EVENT_NAVIGATE_BEGIN: { LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_NAVIGATE_BEGIN, url is " << self->getNavigateURI() << LL_ENDL; @@ -970,6 +1029,7 @@ void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event) case MEDIA_EVENT_LOCATION_CHANGED: { LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_LOCATION_CHANGED, new uri is: " << self->getLocation() << LL_ENDL; + mCurrentNavUrl = self->getLocation(); }; break; @@ -985,27 +1045,36 @@ void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event) case MEDIA_EVENT_CLICK_LINK_HREF: { - LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CLICK_LINK_HREF, target is \"" << self->getClickTarget() << "\", uri is " << self->getClickURL() << LL_ENDL; // retrieve the event parameters std::string url = self->getClickURL(); std::string target = self->getClickTarget(); std::string uuid = self->getClickUUID(); + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CLICK_LINK_HREF, target is \"" << target << "\", uri is " << url << LL_ENDL; - LLNotification::Params notify_params("PopupAttempt"); - notify_params.payload = LLSD().with("target", target).with("url", url).with("uuid", uuid).with("media_id", mMediaTextureID); - notify_params.functor(boost::bind(&LLMediaCtrl::onPopup, this, _1, _2)); - - if (mTrusted) - { - LLNotifications::instance().forceResponse(notify_params, 0); - } - else + // try as slurl first + if (!LLURLDispatcher::dispatch(url, "clicked", nullptr, mTrusted)) { - LLNotifications::instance().add(notify_params); + LLWeb::loadURL(url, target, uuid); } + + // CP: removing this code because we no longer support popups so this breaks the flow. + // replaced with a bare call to LLWeb::LoadURL(...) + //LLNotification::Params notify_params; + //notify_params.name = "PopupAttempt"; + //notify_params.payload = LLSD().with("target", target).with("url", url).with("uuid", uuid).with("media_id", mMediaTextureID); + //notify_params.functor.function = boost::bind(&LLMediaCtrl::onPopup, this, _1, _2); + + //if (mTrusted) + //{ + // LLNotifications::instance().forceResponse(notify_params, 0); + //} + //else + //{ + // LLNotifications::instance().add(notify_params); + //} break; }; - + case MEDIA_EVENT_CLICK_LINK_NOFOLLOW: { LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CLICK_LINK_NOFOLLOW, uri is " << self->getClickURL() << LL_ENDL; @@ -1072,9 +1141,33 @@ void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event) }; break; + case MEDIA_EVENT_FILE_DOWNLOAD: + { + //llinfos << "Media event - file download requested - filename is " << self->getFileDownloadFilename() << llendl; + //LLNotificationsUtil::add("MediaFileDownloadUnsupported"); + }; + break; + case MEDIA_EVENT_DEBUG_MESSAGE: { - LL_INFOS("media") << self->getDebugMessageText() << LL_ENDL; + std::string level = self->getDebugMessageLevel(); + if (level == "debug") + { + LL_DEBUGS("Media") << self->getDebugMessageText() << LL_ENDL; + } + else if (level == "info") + { + LL_INFOS("Media") << self->getDebugMessageText() << LL_ENDL; + } + else if (level == "warn") + { + LL_WARNS("Media") << self->getDebugMessageText() << LL_ENDL; + } + else if (level == "error") + { + LL_ERRS("Media") << self->getDebugMessageText() << LL_ENDL; + } + }; break; @@ -1095,7 +1188,7 @@ std::string LLMediaCtrl::getCurrentNavUrl() return mCurrentNavUrl; } -bool LLMediaCtrl::onPopup(const LLSD& notification, const LLSD& response) +void LLMediaCtrl::onPopup(const LLSD& notification, const LLSD& response) { if (response["open"]) { @@ -1106,7 +1199,6 @@ bool LLMediaCtrl::onPopup(const LLSD& notification, const LLSD& response) // Make sure the opening instance knows its window open request was denied, so it can clean things up. LLViewerMedia::proxyWindowClosed(notification["payload"]["uuid"]); } - return FALSE; } void LLMediaCtrl::showNotification(LLNotificationPtr notify) @@ -1138,6 +1230,16 @@ void LLMediaCtrl::setTrustedContent(bool trusted) } } +bool LLMediaCtrl::wantsKeyUpKeyDown() const +{ + return true; +} + +bool LLMediaCtrl::wantsReturnKey() const +{ + return true; +} + // virtual LLXMLNodePtr LLMediaCtrl::getXML(bool save_children) const { diff --git a/indra/newview/llmediactrl.h b/indra/newview/llmediactrl.h index 306d686500..87c17413f6 100644 --- a/indra/newview/llmediactrl.h +++ b/indra/newview/llmediactrl.h @@ -2,31 +2,25 @@ * @file llmediactrl.h * @brief Web browser UI control * - * $LicenseInfo:firstyear=2006&license=viewergpl$ - * - * Copyright (c) 2006-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -37,6 +31,7 @@ #include "lluictrl.h" #include "llframetimer.h" +#include "llnotificationptr.h" class LLViewBorder; class LLUICtrlFactory; @@ -51,6 +46,7 @@ class LLMediaCtrl : { LOG_CLASS(LLMediaCtrl); public: + struct Params : public LLInitParam::Block { Optional start_url; @@ -88,24 +84,25 @@ class LLMediaCtrl : // Defaults to true. void setTakeFocusOnClick( bool take_focus ); - virtual LLXMLNodePtr getXML(bool save_children = true) const; + virtual LLXMLNodePtr getXML(bool save_children = true) const override; static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); // handle mouse related methods - virtual BOOL handleHover( S32 x, S32 y, MASK mask ); - virtual BOOL handleMouseUp( S32 x, S32 y, MASK mask ); - virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask ); - virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); - virtual BOOL handleRightMouseUp(S32 x, S32 y, MASK mask); - virtual BOOL handleDoubleClick( S32 x, S32 y, MASK mask ); - virtual BOOL handleScrollWheel( S32 x, S32 y, S32 clicks ); - virtual BOOL handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_rect_screen); + BOOL handleHover( S32 x, S32 y, MASK mask ) override; + BOOL handleMouseUp( S32 x, S32 y, MASK mask ) override; + BOOL handleMouseDown( S32 x, S32 y, MASK mask ) override; + BOOL handleRightMouseDown(S32 x, S32 y, MASK mask) override; + BOOL handleRightMouseUp(S32 x, S32 y, MASK mask) override; + BOOL handleDoubleClick( S32 x, S32 y, MASK mask ) override; + BOOL handleScrollWheel( S32 x, S32 y, S32 clicks ) override; + BOOL handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_rect_screen) override; // navigation - void navigateTo( std::string url_in, std::string mime_type = ""); + void navigateTo( std::string url_in, std::string mime_type = "", bool clean_browser = false); void navigateBack(); void navigateHome(); void navigateForward(); + void navigateStop(); void navigateToLocalPage( const std::string& subdir, const std::string& filename_in ); bool canNavigateBack(); bool canNavigateForward(); @@ -128,9 +125,6 @@ class LLMediaCtrl : // Clear the browser cache when the instance gets loaded void clearCache(); - void set404RedirectUrl( std::string redirect_url ); - void clr404RedirectUrl(); - // accessor/mutator for flag that indicates if frequent updates to texture happen bool getFrequentUpdates() { return mFrequentUpdates; }; void setFrequentUpdates( bool frequentUpdatesIn ) { mFrequentUpdates = frequentUpdatesIn; }; @@ -153,37 +147,49 @@ class LLMediaCtrl : void setTextureSize(S32 width, S32 height); - void showNotification(boost::shared_ptr notify); + void showNotification(LLNotificationPtr notify); void hideNotification(); void setTrustedContent(bool trusted); // over-rides - virtual BOOL handleKeyHere( KEY key, MASK mask); - virtual void handleVisibilityChange ( BOOL new_visibility ); - virtual BOOL handleUnicodeCharHere(llwchar uni_char); - virtual void reshape( S32 width, S32 height, BOOL called_from_parent = TRUE); - virtual void draw(); - virtual BOOL postBuild(); + BOOL handleKeyHere( KEY key, MASK mask) override; + BOOL handleKeyUpHere(KEY key, MASK mask) override; + void handleVisibilityChange ( BOOL new_visibility ) override; + BOOL handleUnicodeCharHere(llwchar uni_char) override; + void reshape( S32 width, S32 height, BOOL called_from_parent = TRUE) override; + void draw() override; + BOOL postBuild() override; // focus overrides - void onFocusLost(); - void onFocusReceived(); + void onFocusLost() override; + void onFocusReceived() override; // Incoming media event dispatcher - virtual void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event); + void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event) override; + void onCopyURL() const; // right click debugging item void onOpenWebInspector(); + void onShowSource(); LLUUID getTextureID() {return mMediaTextureID;} + // The Browser windows want keyup and keydown events. Overridden from LLFocusableElement to return true. + bool wantsKeyUpKeyDown() const override; + bool wantsReturnKey() const override; + + virtual BOOL acceptsTextInput() const override { return TRUE; } + protected: void convertInputCoords(S32& x, S32& y); private: - void onVisibilityChange ( const LLSD& new_visibility ); - bool onPopup(const LLSD& notification, const LLSD& response); + void calcOffsetsAndSize(S32 *x_offset, S32 *y_offset, S32 *width, S32 *height); + + private: + void onVisibilityChanged ( const LLSD& new_visibility ); + void onPopup(const LLSD& notification, const LLSD& response); const S32 mTextureDepthBytes; LLUUID mMediaTextureID; @@ -199,7 +205,8 @@ class LLMediaCtrl : mHidingInitialLoad, mClearCache, mHoverTextChanged, - mDecoupleTextureSize; + mDecoupleTextureSize, + mUpdateScrolls; std::string mHomePageUrl, mHomePageMimeType, diff --git a/indra/newview/llmediadataclient.cpp b/indra/newview/llmediadataclient.cpp index 31038b4aac..2690e39581 100644 --- a/indra/newview/llmediadataclient.cpp +++ b/indra/newview/llmediadataclient.cpp @@ -28,13 +28,6 @@ #include "llmediadataclient.h" -#if LL_MSVC -// disable boost::lexical_cast warning -#pragma warning (disable:4702) -#endif - -#include - #include "llhttpstatuscodes.h" #include "llsdutil.h" #include "llmediaentry.h" @@ -92,7 +85,7 @@ std::ostream& operator<<(std::ostream &s, const LLMediaDataClient::request_queue std::ostream& operator<<(std::ostream &s, const LLMediaDataClient::Request &q); template -static typename T::iterator find_matching_request(T &c, const LLMediaDataClient::Request *request, LLMediaDataClient::Request::Type match_type) +typename T::iterator find_matching_request(T &c, const LLMediaDataClient::Request *request, LLMediaDataClient::Request::Type match_type) { for(typename T::iterator iter = c.begin(); iter != c.end(); ++iter) { @@ -106,7 +99,7 @@ static typename T::iterator find_matching_request(T &c, const LLMediaDataClient: } template -static typename T::iterator find_matching_request(T &c, const LLUUID &id, LLMediaDataClient::Request::Type match_type) +typename T::iterator find_matching_request(T &c, const LLUUID &id, LLMediaDataClient::Request::Type match_type) { for(typename T::iterator iter = c.begin(); iter != c.end(); ++iter) { @@ -123,7 +116,7 @@ static typename T::iterator find_matching_request(T &c, const LLUUID &id, LLMedi // to other elements in the container (such as std::vector). // If the implementation is changed to use a container with this property, this will need to be revisited. template -static void remove_matching_requests(T &c, const LLUUID &id, LLMediaDataClient::Request::Type match_type) +void remove_matching_requests(T &c, const LLUUID &id, LLMediaDataClient::Request::Type match_type) { for(typename T::iterator iter = c.begin(); iter != c.end();) { @@ -171,10 +164,10 @@ bool LLMediaDataClient::isEmpty() const bool LLMediaDataClient::isInQueue(const LLMediaDataClientObject::ptr_t &object) { - if(find_matching_request(mQueue, object->getID()) != mQueue.end()) + if(find_matching_request(mQueue, object->getID(), LLMediaDataClient::Request::ANY) != mQueue.end()) return true; - if(find_matching_request(mUnQueuedRequests, object->getID()) != mUnQueuedRequests.end()) + if(find_matching_request(mUnQueuedRequests, object->getID(), LLMediaDataClient::Request::ANY) != mUnQueuedRequests.end()) return true; return false; @@ -183,8 +176,8 @@ bool LLMediaDataClient::isInQueue(const LLMediaDataClientObject::ptr_t &object) void LLMediaDataClient::removeFromQueue(const LLMediaDataClientObject::ptr_t &object) { LL_DEBUGS("LLMediaDataClient") << "removing requests matching ID " << object->getID() << LL_ENDL; - remove_matching_requests(mQueue, object->getID()); - remove_matching_requests(mUnQueuedRequests, object->getID()); + remove_matching_requests(mQueue, object->getID(), LLMediaDataClient::Request::ANY); + remove_matching_requests(mUnQueuedRequests, object->getID(), LLMediaDataClient::Request::ANY); } void LLMediaDataClient::startQueueTimer() @@ -564,7 +557,7 @@ LLMediaDataClient::Responder::Responder(const request_ptr_t &request) } /*virtual*/ -void LLMediaDataClient::Responder::error(U32 status, const std::string& reason) +void LLMediaDataClient::Responder::httpFailure(void) { mRequest->stopTracking(); @@ -574,7 +567,7 @@ void LLMediaDataClient::Responder::error(U32 status, const std::string& reason) return; } - if (status == HTTP_SERVICE_UNAVAILABLE) + if (mStatus == HTTP_SERVICE_UNAVAILABLE) { F32 retry_timeout = mRequest->getRetryTimerDelay(); @@ -596,13 +589,12 @@ void LLMediaDataClient::Responder::error(U32 status, const std::string& reason) } else { - std::string msg = boost::lexical_cast(status) + ": " + reason; - LL_WARNS("LLMediaDataClient") << *mRequest << " http error(" << msg << ")" << LL_ENDL; + LL_WARNS("LLMediaDataClient") << *mRequest << " http error: " << dumpResponse() << LL_ENDL; } } /*virtual*/ -void LLMediaDataClient::Responder::result(const LLSD& content) +void LLMediaDataClient::Responder::httpSuccess(void) { mRequest->stopTracking(); @@ -612,7 +604,7 @@ void LLMediaDataClient::Responder::result(const LLSD& content) return; } - LL_DEBUGS("LLMediaDataClientResponse") << *mRequest << " result : " << ll_print_sd(content) << LL_ENDL; + LL_DEBUGS("LLMediaDataClientResponse") << *mRequest << " result : " << ll_print_sd(mContent) << LL_ENDL; } ////////////////////////////////////////////////////////////////////////////////////// @@ -776,7 +768,7 @@ bool LLObjectMediaDataClient::isInQueue(const LLMediaDataClientObject::ptr_t &ob if(LLMediaDataClient::isInQueue(object)) return true; - if(find_matching_request(mRoundRobinQueue, object->getID()) != mRoundRobinQueue.end()) + if(find_matching_request(mRoundRobinQueue, object->getID(), LLMediaDataClient::Request::ANY) != mRoundRobinQueue.end()) return true; return false; @@ -787,7 +779,7 @@ void LLObjectMediaDataClient::removeFromQueue(const LLMediaDataClientObject::ptr // First, call parent impl. LLMediaDataClient::removeFromQueue(object); - remove_matching_requests(mRoundRobinQueue, object->getID()); + remove_matching_requests(mRoundRobinQueue, object->getID(), LLMediaDataClient::Request::ANY); } bool LLObjectMediaDataClient::processQueueTimer() @@ -876,7 +868,7 @@ LLMediaDataClient::Responder *LLObjectMediaDataClient::RequestUpdate::createResp /*virtual*/ -void LLObjectMediaDataClient::Responder::result(const LLSD& content) +void LLObjectMediaDataClient::Responder::httpSuccess(void) { getRequest()->stopTracking(); @@ -888,12 +880,12 @@ void LLObjectMediaDataClient::Responder::result(const LLSD& content) // This responder is only used for GET requests, not UPDATE. - LL_DEBUGS("LLMediaDataClientResponse") << *(getRequest()) << " GET returned: " << ll_print_sd(content) << LL_ENDL; + LL_DEBUGS("LLMediaDataClientResponse") << *(getRequest()) << " GET returned: " << ll_print_sd(mContent) << LL_ENDL; // Look for an error - if (content.has("error")) + if (mContent.has("error")) { - const LLSD &error = content["error"]; + const LLSD &error = mContent["error"]; LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error getting media data for object: code=" << error["code"].asString() << ": " << error["message"].asString() << LL_ENDL; @@ -902,7 +894,7 @@ void LLObjectMediaDataClient::Responder::result(const LLSD& content) else { // Check the data - const LLUUID &object_id = content[LLTextureEntry::OBJECT_ID_KEY]; + const LLUUID &object_id = mContent[LLTextureEntry::OBJECT_ID_KEY]; if (object_id != getRequest()->getObject()->getID()) { // NOT good, wrong object id!! @@ -911,8 +903,8 @@ void LLObjectMediaDataClient::Responder::result(const LLSD& content) } // Otherwise, update with object media data - getRequest()->getObject()->updateObjectMediaData(content[LLTextureEntry::OBJECT_MEDIA_DATA_KEY], - content[LLTextureEntry::MEDIA_VERSION_KEY]); + getRequest()->getObject()->updateObjectMediaData(mContent[LLTextureEntry::OBJECT_MEDIA_DATA_KEY], + mContent[LLTextureEntry::MEDIA_VERSION_KEY]); } } @@ -937,7 +929,7 @@ void LLObjectMediaNavigateClient::enqueue(Request *request) } // If there's already a matching request in the queue, remove it. - request_queue_t::iterator iter = find_matching_request(mQueue, request); + request_queue_t::iterator iter = find_matching_request(mQueue, request, LLMediaDataClient::Request::ANY); if(iter != mQueue.end()) { LL_DEBUGS("LLMediaDataClient") << "removing matching queued request " << (**iter) << LL_ENDL; @@ -945,7 +937,7 @@ void LLObjectMediaNavigateClient::enqueue(Request *request) } else { - request_set_t::iterator set_iter = find_matching_request(mUnQueuedRequests, request); + request_set_t::iterator set_iter = find_matching_request(mUnQueuedRequests, request, LLMediaDataClient::Request::ANY); if(set_iter != mUnQueuedRequests.end()) { LL_DEBUGS("LLMediaDataClient") << "removing matching unqueued request " << (**set_iter) << LL_ENDL; @@ -1003,7 +995,7 @@ LLMediaDataClient::Responder *LLObjectMediaNavigateClient::RequestNavigate::crea } /*virtual*/ -void LLObjectMediaNavigateClient::Responder::error(U32 status, const std::string& reason) +void LLObjectMediaNavigateClient::Responder::httpFailure(void) { getRequest()->stopTracking(); @@ -1015,14 +1007,14 @@ void LLObjectMediaNavigateClient::Responder::error(U32 status, const std::string // Bounce back (unless HTTP_SERVICE_UNAVAILABLE, in which case call base // class - if (status == HTTP_SERVICE_UNAVAILABLE) + if (mStatus == HTTP_SERVICE_UNAVAILABLE) { - LLMediaDataClient::Responder::error(status, reason); + LLMediaDataClient::Responder::httpFailure(); } else { // bounce the face back - LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error navigating: http code=" << status << LL_ENDL; + LL_WARNS("LLMediaDataClient") << *(getRequest()) << " Error navigating: http code=" << mStatus << LL_ENDL; const LLSD &payload = getRequest()->getPayload(); // bounce the face back getRequest()->getObject()->mediaNavigateBounceBack((LLSD::Integer)payload[LLTextureEntry::TEXTURE_INDEX_KEY]); @@ -1030,7 +1022,7 @@ void LLObjectMediaNavigateClient::Responder::error(U32 status, const std::string } /*virtual*/ -void LLObjectMediaNavigateClient::Responder::result(const LLSD& content) +void LLObjectMediaNavigateClient::Responder::httpSuccess(void) { getRequest()->stopTracking(); @@ -1040,11 +1032,11 @@ void LLObjectMediaNavigateClient::Responder::result(const LLSD& content) return; } - LL_INFOS("LLMediaDataClient") << *(getRequest()) << " NAVIGATE returned " << ll_print_sd(content) << LL_ENDL; + LL_INFOS("LLMediaDataClient") << *(getRequest()) << " NAVIGATE returned " << ll_print_sd(mContent) << LL_ENDL; - if (content.has("error")) + if (mContent.has("error")) { - const LLSD &error = content["error"]; + const LLSD &error = mContent["error"]; int error_code = error["code"]; if (ERROR_PERMISSION_DENIED_CODE == error_code) @@ -1065,6 +1057,6 @@ void LLObjectMediaNavigateClient::Responder::result(const LLSD& content) else { // No action required. - LL_DEBUGS("LLMediaDataClientResponse") << *(getRequest()) << " result : " << ll_print_sd(content) << LL_ENDL; + LL_DEBUGS("LLMediaDataClientResponse") << *(getRequest()) << " result : " << ll_print_sd(mContent) << LL_ENDL; } } diff --git a/indra/newview/llmediadataclient.h b/indra/newview/llmediadataclient.h index 19ea5c6cef..140d248f11 100644 --- a/indra/newview/llmediadataclient.h +++ b/indra/newview/llmediadataclient.h @@ -197,9 +197,9 @@ class LLMediaDataClient : public LLRefCount Responder(const request_ptr_t &request); //If we get back an error (not found, etc...), handle it here - virtual void error(U32 status, const std::string& reason); + virtual void httpFailure(void); //If we get back a normal response, handle it here. Default just logs it. - virtual void result(const LLSD& content); + virtual void httpSuccess(void); /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return mediaDataClientResponder_timeout; } /*virtual*/ char const* getName(void) const { return "LLMediaDataClientResponder"; } @@ -282,9 +282,9 @@ class LLMediaDataClient : public LLRefCount bool mQueueTimerIsRunning; - template friend typename T::iterator find_matching_request(T &c, const LLMediaDataClient::Request *request, LLMediaDataClient::Request::Type match_type = LLMediaDataClient::Request::ANY); - template friend typename T::iterator find_matching_request(T &c, const LLUUID &id, LLMediaDataClient::Request::Type match_type = LLMediaDataClient::Request::ANY); - template friend void remove_matching_requests(T &c, const LLUUID &id, LLMediaDataClient::Request::Type match_type = LLMediaDataClient::Request::ANY); + template friend typename T::iterator find_matching_request(T &c, const LLMediaDataClient::Request *request, LLMediaDataClient::Request::Type match_type); + template friend typename T::iterator find_matching_request(T &c, const LLUUID &id, LLMediaDataClient::Request::Type match_type); + template friend void remove_matching_requests(T &c, const LLUUID &id, LLMediaDataClient::Request::Type match_type); }; @@ -348,7 +348,7 @@ class LLObjectMediaDataClient : public LLMediaDataClient public: Responder(const request_ptr_t &request) : LLMediaDataClient::Responder(request) {} - virtual void result(const LLSD &content); + virtual void httpSuccess(void); }; private: // The Get/Update data client needs a second queue to avoid object updates starving load-ins. @@ -404,8 +404,8 @@ class LLObjectMediaNavigateClient : public LLMediaDataClient public: Responder(const request_ptr_t &request) : LLMediaDataClient::Responder(request) {} - virtual void error(U32 status, const std::string& reason); - virtual void result(const LLSD &content); + virtual void httpFailure(void); + virtual void httpSuccess(void); private: void mediaNavigateBounceBack(); }; diff --git a/indra/newview/llmediafilter.cpp b/indra/newview/llmediafilter.cpp new file mode 100644 index 0000000000..9ab66af5af --- /dev/null +++ b/indra/newview/llmediafilter.cpp @@ -0,0 +1,442 @@ +/* + * @file llmediafilter.h + * @brief Hyperbalistic SLU paranoia controls + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2011, Sione Lomu. + * Copyright (C) 2014, Cinder Roxley. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llmediafilter.h" + +#include "llaudioengine.h" +#include "llnotificationsutil.h" +#include "llparcel.h" +#include "llsdserialize.h" +#include "lltrans.h" +#include "llvieweraudio.h" +#include "llviewerparcelmgr.h" +#include "llviewerparcelmedia.h" + +const std::string MEDIALIST_XML = "medialist.xml"; +bool handle_audio_filter_callback(const LLSD& notification, const LLSD& response, const std::string& url); +bool handle_media_filter_callback(const LLSD& notification, const LLSD& response, LLParcel* parcel); +std::string extractDomain(const std::string& in_url); + +LLMediaFilter::LLMediaFilter() +: mMediaCommandQueue(0) +, mCurrentParcel(NULL) +, mMediaQueue(NULL) +, mAlertActive(false) +{ + loadMediaFilterFromDisk(); +} + +void LLMediaFilter::filterMediaUrl(LLParcel* parcel) +{ + if (!parcel) return; + const std::string& url = parcel->getMediaURL(); + if (url.empty()) + { + return; + } + + const std::string domain = extractDomain(url); + mCurrentParcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + U32 enabled = gSavedSettings.getU32("MediaFilterEnable"); + + if (enabled > 1 && (filter(domain, WHITELIST) || filter(url, WHITELIST))) + { + LL_DEBUGS("MediaFilter") << "Media filter: URL allowed by whitelist: " << url << LL_ENDL; + LLViewerParcelMedia::play(parcel); + //mAudioState = PLAY; + } + else if (enabled && (filter(domain, BLACKLIST) || filter(url, BLACKLIST))) + { + LLNotificationsUtil::add("MediaBlocked", LLSD().with("DOMAIN", domain)); + //mAudioState = STOP; + } + else if (enabled && isAlertActive()) + { + mMediaQueue = parcel; + } + else if (enabled > 1) + { + LL_DEBUGS("MediaFilter") << "Media Filter: Unhanded by lists. Toasting: " << url << LL_ENDL; + setAlertStatus(true); + LLSD args, payload; + args["MEDIA_TYPE"] = LLTrans::getString("media"); + args["URL"] = url; + args["DOMAIN"] = domain; + payload = url; + LLNotificationsUtil::add("MediaAlert", args, payload, + boost::bind(&handle_media_filter_callback, _1, _2, parcel)); + } + else + { + LL_DEBUGS("MediaFilter") << "Media Filter: Skipping filters and playing " << url << LL_ENDL; + LLViewerParcelMedia::play(parcel); + //mAudioState = PLAY; + } +} + +void LLMediaFilter::filterAudioUrl(const std::string& url) +{ + if (url.empty()) + { + return; + } + if (url == mCurrentAudioURL) return; + + const std::string domain = extractDomain(url); + mCurrentParcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + U32 enabled = gSavedSettings.getU32("MediaFilterEnable"); + + if (enabled > 1 && (filter(domain, WHITELIST) || filter(url, WHITELIST))) + { + LL_DEBUGS("MediaFilter") << "Audio filter: URL allowed by whitelist: " << url << LL_ENDL; + gAudiop->startInternetStream(url); + } + else if (enabled && (filter(domain, BLACKLIST) || filter(url, BLACKLIST))) + { + LLNotificationsUtil::add("MediaBlocked", LLSD().with("DOMAIN", domain)); + gAudiop->stopInternetStream(); + } + else if (enabled && isAlertActive()) + { + mAudioQueue = url; + } + else if (enabled > 1) + { + LL_DEBUGS("MediaFilter") << "Audio Filter: Unhanded by lists. Toasting: " << url << LL_ENDL; + setAlertStatus(true); + LLSD args, payload; + args["MEDIA_TYPE"] = LLTrans::getString("audio"); + args["URL"] = url; + args["DOMAIN"] = domain; + LLNotificationsUtil::add("MediaAlert", args, LLSD(), + boost::bind(&handle_audio_filter_callback, _1, _2, url)); + } + else + { + LL_DEBUGS("MediaFilter") << "Audio Filter: Skipping filters and playing: " << url << LL_ENDL; + gAudiop->startInternetStream(url); + } + +} + +bool LLMediaFilter::filter(const std::string& url, EMediaList list) +{ + const string_list_t& p_list = (list == WHITELIST) ? mWhiteList : mBlackList; + string_list_t::const_iterator find_itr = std::find(p_list.begin(), p_list.end(), url); + return (find_itr != p_list.end()); +} + +// List bizznizz +void LLMediaFilter::addToMediaList(const std::string& in_url, EMediaList list, bool extract) +{ + const std::string url = extract ? extractDomain(in_url) : in_url; + if (url.empty()) + { + LL_INFOS("MediaFilter") << "No url found. Can't add to list." << LL_ENDL; + return; + } + + string_list_t& p_list(list == WHITELIST ? mWhiteList : mBlackList); + // Check for duplicates + for (const auto& p : p_list) + { + if (url == p) + { + LL_INFOS("MediaFilter") << "URL " << url << " already in list!" << LL_ENDL; + return; + } + } + p_list.push_back(url); + mMediaListUpdate(list); + saveMediaFilterToDisk(); +} + +void LLMediaFilter::removeFromMediaList(string_vec_t domains, EMediaList list) +{ + if (domains.empty()) return; + for (const auto& domain : domains) + (list == WHITELIST ? mWhiteList : mBlackList).remove(domain); + mMediaListUpdate(list); + saveMediaFilterToDisk(); +} + +void LLMediaFilter::loadMediaFilterFromDisk() +{ + const std::string medialist_filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, MEDIALIST_XML); + mWhiteList.clear(); + mBlackList.clear(); + + LLSD medialist; + if (LLFile::isfile(medialist_filename)) + { + llifstream medialist_xml(medialist_filename); + LLSDSerialize::fromXML(medialist, medialist_xml); + medialist_xml.close(); + } + else + LL_INFOS("MediaFilter") << medialist_filename << " not found." << LL_ENDL; + + for (LLSD::array_const_iterator p_itr = medialist.beginArray(); + p_itr != medialist.endArray(); + ++p_itr) + { + LLSD itr = (*p_itr); + /// I hate this string shit more than you could ever imagine, + /// but I'm retaining it for backwards and cross-compatibility. :| + if (itr["action"].asString() == "allow") + { + LL_DEBUGS("MediaFilter") << "Adding " << itr["domain"].asString() << " to whitelist." << LL_ENDL; + mWhiteList.push_back(itr["domain"].asString()); + } + else if (itr["action"].asString() == "deny") + { + LL_DEBUGS("MediaFilter") << "Adding " << itr["domain"].asString() << " to blacklist." << LL_ENDL; + mBlackList.push_back(itr["domain"].asString()); + } + } +} + +void medialist_to_llsd(const LLMediaFilter::string_list_t& list, LLSD& list_llsd, const LLSD& action) +{ + for (const auto& domain : list) + { + LLSD item; + item["domain"] = domain; + item["action"] = action; + list_llsd.append(item); + } +} + +void LLMediaFilter::saveMediaFilterToDisk() const +{ + const std::string medialist_filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, MEDIALIST_XML); + + LLSD medialist_llsd; + medialist_to_llsd(mWhiteList, medialist_llsd, "allow"); // <- $*#@()&%@ + medialist_to_llsd(mBlackList, medialist_llsd, "deny"); // sigh. + + llofstream medialist; + medialist.open(medialist_filename); + LLSDSerialize::toPrettyXML(medialist_llsd, medialist); + medialist.close(); +} + +void perform_queued_command(LLMediaFilter& inst) +{ + if (U32 command = inst.getQueuedMediaCommand()) + { + if (command == PARCEL_MEDIA_COMMAND_STOP) + { + LLViewerParcelMedia::stop(); + } + else if (command == PARCEL_MEDIA_COMMAND_PAUSE) + { + LLViewerParcelMedia::pause(); + } + else if (command == PARCEL_MEDIA_COMMAND_UNLOAD) + { + LLViewerParcelMedia::stop(); + } + else if (command == PARCEL_MEDIA_COMMAND_TIME) + { + LLViewerParcelMedia::seek(LLViewerParcelMedia::sMediaCommandTime); + } + inst.setQueuedMediaCommand(0); + } +} + +bool handle_audio_filter_callback(const LLSD& notification, const LLSD& response, const std::string& url) +{ + LLMediaFilter& inst(LLMediaFilter::instance()); + inst.setAlertStatus(false); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + const std::string queue = inst.getQueuedAudio(); + switch(option) + { + case 3: // Whitelist domain + inst.addToMediaList(url, LLMediaFilter::WHITELIST); + case 0: // Allow + if (gAudiop != NULL) + { + if (inst.getCurrentParcel() == LLViewerParcelMgr::getInstance()->getAgentParcel()) + { + gAudiop->startInternetStream(url); + } + } + break; + case 2: // Blacklist domain + inst.addToMediaList(url, LLMediaFilter::BLACKLIST); + case 1: // Deny + if (gAudiop != NULL) + { + if (inst.getCurrentParcel() == LLViewerParcelMgr::getInstance()->getAgentParcel()) + { + gAudiop->stopInternetStream(); + } + } + break; + /*case 4: //Whitelist url + inst.addToMediaList(url, LLMediaFilter::WHITELIST, false); + if (gAudiop != NULL) + { + if (inst.getCurrentParcel() == LLViewerParcelMgr::getInstance()->getAgentParcel()) + { + gAudiop->startInternetStream(url); + } + } + break; + case 5: //Blacklist url + inst.addToMediaList(url, LLMediaFilter::BLACKLIST, false); + if (gAudiop != NULL) + { + if (inst.getCurrentParcel() == LLViewerParcelMgr::getInstance()->getAgentParcel()) + { + gAudiop->stopInternetStream(); + } + } + break;*/ + default: + // We should never be able to get here. + llassert(option); + break; + } + if (!queue.empty()) + { + inst.clearQueuedAudio(); + inst.filterAudioUrl(queue); + } + else if (inst.getQueuedMedia()) + { + inst.clearQueuedMedia(); + LLParcel* queued_media = inst.getQueuedMedia(); + if (queued_media) + inst.filterMediaUrl(queued_media); + } + else + { + perform_queued_command(inst); + } + + return false; +} + +bool handle_media_filter_callback(const LLSD& notification, const LLSD& response, LLParcel* parcel) +{ + LLMediaFilter& inst(LLMediaFilter::instance()); + inst.setAlertStatus(false); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + const std::string& url = notification["payload"].asString(); + LLParcel* queue = inst.getQueuedMedia(); + switch(option) + { + case 3: // Whitelist domain + inst.addToMediaList(url, LLMediaFilter::WHITELIST); + case 0: // Allow + if (inst.getCurrentParcel() == LLViewerParcelMgr::getInstance()->getAgentParcel()) + LLViewerParcelMedia::play(parcel); + break; + case 2: // Blacklist domain + inst.addToMediaList(url, LLMediaFilter::BLACKLIST); + case 1: // Deny + break; + case 4: //Whitelist url + inst.addToMediaList(url, LLMediaFilter::WHITELIST, false); + if (inst.getCurrentParcel() == LLViewerParcelMgr::getInstance()->getAgentParcel()) + LLViewerParcelMedia::play(parcel); + break; + case 5: + inst.addToMediaList(url, LLMediaFilter::BLACKLIST, false); + break; + default: + // We should never be able to get here. + llassert(option); + break; + } + const std::string audio_queue = inst.getQueuedAudio(); + if (queue) + { + inst.clearQueuedMedia(); + inst.filterMediaUrl(queue); + } + else if (!audio_queue.empty()) + { + inst.clearQueuedAudio(); + inst.filterAudioUrl(audio_queue); + } + else + { + perform_queued_command(inst); + } + + return false; +} + +// Local Functions +std::string extractDomain(const std::string& in_url) +{ + std::string url = in_url; + // First, find and strip any protocol prefix. + size_t pos = url.find("//"); + + if (pos != std::string::npos) + { + size_t count = url.size()-pos+2; + url = url.substr(pos+2, count); + } + + // Now, look for a / marking a local part; if there is one, + // strip it and anything after. + pos = url.find("/"); + + if (pos != std::string::npos) + { + url = url.substr(0, pos); + } + + // If there's a user{,:password}@ part, remove it, + pos = url.find("@"); + + if (pos != std::string::npos) + { + size_t count = url.size()-pos+1; + url = url.substr(pos+1, count); + } + + // Finally, find and strip away any port number. This has to be done + // after the previous step, or else the extra : for the password, + // if supplied, will confuse things. + pos = url.find(":"); + + if (pos != std::string::npos) + { + url = url.substr(0, pos); + } + + // Now map the whole thing to lowercase, since domain names aren't + // case sensitive. + std::transform(url.begin(), url.end(), url.begin(), ::tolower); + return url; +} diff --git a/indra/newview/llmediafilter.h b/indra/newview/llmediafilter.h new file mode 100644 index 0000000000..4e05eaf4a7 --- /dev/null +++ b/indra/newview/llmediafilter.h @@ -0,0 +1,91 @@ +/* + * @file llmediafilter.h + * @brief Definitions for paranoia controls + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2011, Sione Lomu. + * Copyright (C) 2014, Cinder Roxley. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * $/LicenseInfo$ + */ + +#ifndef LL_MEDIAFILTER_H +#define LL_MEDIAFILTER_H + +class LLParcel; + +class LLMediaFilter : public LLSingleton +{ +public: + typedef enum e_media_list { + WHITELIST, + BLACKLIST + } EMediaList; + + typedef std::list string_list_t; + typedef std::vector string_vec_t; + typedef boost::signals2::signal media_list_signal_t; + boost::signals2::connection setMediaListUpdateCallback(const media_list_signal_t::slot_type& cb) + { + return mMediaListUpdate.connect(cb); + } + + LLMediaFilter(); + void filterMediaUrl(LLParcel* parcel); + void filterAudioUrl(const std::string& url); + //void filterSharedMediaUrl + + void addToMediaList(const std::string& in_url, EMediaList list, bool extract = true); + void removeFromMediaList(string_vec_t, EMediaList list); + string_list_t getWhiteList() const { return mWhiteList; } + string_list_t getBlackList() const { return mBlackList; } + U32 getQueuedMediaCommand() const { return mMediaCommandQueue; } + void setQueuedMediaCommand(U32 command) { mMediaCommandQueue = command; } + bool isAlertActive() const { return mAlertActive; } + void setAlertStatus(bool active) { mAlertActive = active; } + LLParcel* getCurrentParcel() const { return mCurrentParcel; } + LLParcel* getQueuedMedia() const { return mMediaQueue; } + void clearQueuedMedia() { mMediaQueue = NULL; } + std::string getQueuedAudio() const { return mAudioQueue; } + void clearQueuedAudio() { mAudioQueue.clear(); } + void setCurrentAudioURL(const std::string url ) { mCurrentAudioURL = url; } + void clearCurrentAudioURL() { mCurrentAudioURL.clear(); } + bool filter(const std::string& url, EMediaList list); + +private: + void loadMediaFilterFromDisk(); + void saveMediaFilterToDisk() const; + + media_list_signal_t mMediaListUpdate; + string_list_t mBlackList; + string_list_t mWhiteList; + U32 mMediaCommandQueue; + LLParcel* mCurrentParcel; + LLParcel* mMediaQueue; + std::string mAudioQueue; + std::string mCurrentAudioURL; + std::string mCurrentMediaURL; + bool mAlertActive; + //typedef enum e_audio_state { + // PLAY, + // STOP + //} EAudioState; + //EAudioState mAudioState; + +}; + +#endif // LL_MEDIAFILTER_H diff --git a/indra/newview/llmediaremotectrl.cpp b/indra/newview/llmediaremotectrl.cpp index 38ce628dab..e6d0aece19 100644 --- a/indra/newview/llmediaremotectrl.cpp +++ b/indra/newview/llmediaremotectrl.cpp @@ -192,7 +192,7 @@ void LLMediaRemoteCtrl::enableMediaButtons() play_media_enabled = true; media_icon_color = LLUI::sColorsGroup->getColor( "IconEnabledColor" ); - + /* LLViewerMediaImpl::EMediaStatus status = LLViewerParcelMedia::getStatus(); switch(status) { @@ -216,6 +216,18 @@ void LLMediaRemoteCtrl::enableMediaButtons() // inherit defaults above break; } + */ + if (LLViewerMedia::isParcelMediaPlaying()) + { + stop_media_enabled = true; + play_media_enabled = false; + } + else + { + stop_media_enabled = false; + play_media_enabled = true; + } + // } } @@ -277,8 +289,11 @@ void LLMediaRemoteCtrl::enableMediaButtons() { sLastTooltip = info_text; LLChat chat; - chat.mText = getString("Now_playing") + " " + info_text; + chat.mText = getString("Now_playing") + ' ' + info_text; chat.mSourceType = CHAT_SOURCE_SYSTEM; + // Lie to RLVa so it won't filter this + chat.mRlvLocFiltered = true; + chat.mRlvNamesFiltered = true; LLFloaterChat::addChat(chat); } } @@ -290,7 +305,7 @@ void LLMediaRemoteCtrl::enableMediaButtons() mMusicIcon->setColor(music_icon_color); if(!media_icon_name.empty()) { - media_icon->setImage(media_icon_name); + media_icon->setValue(media_icon_name); } media_play_btn->setEnabled(play_media_enabled); diff --git a/indra/newview/llmenucommands.cpp b/indra/newview/llmenucommands.cpp index 652b3ed310..01bf1fd7f0 100644 --- a/indra/newview/llmenucommands.cpp +++ b/indra/newview/llmenucommands.cpp @@ -34,116 +34,262 @@ #include "llmenucommands.h" -#include "imageids.h" -#include "llfontgl.h" -#include "llrect.h" -#include "llerror.h" -#include "llstring.h" -#include "message.h" - -#include "llagent.h" +#include "aihttpview.h" +#include "alfloaterregiontracker.h" +#include "floaterao.h" +#include "floaterlocalassetbrowse.h" +#include "hbfloatergrouptitles.h" +#include "jcfloaterareasearch.h" #include "llagentcamera.h" -#include "llcallingcard.h" #include "llchatbar.h" -#include "llviewercontrol.h" -#include "llfirstuse.h" +#include "llconsole.h" +#include "lldebugview.h" +#include "llfasttimerview.h" +#include "llfloaterabout.h" +#include "llfloateractivespeakers.h" +#include "llfloaterautoreplacesettings.h" +#include "llfloateravatar.h" +#include "llfloateravatarlist.h" +#include "llfloaterbeacons.h" +#include "llfloaterblacklist.h" +#include "llfloaterbuildoptions.h" +#include "llfloaterbump.h" +#include "llfloaterbuycurrency.h" +#include "llfloatercamera.h" #include "llfloaterchat.h" -#include "llfloaterdirectory.h" +#include "llfloaterchatterbox.h" +#include "llfloatercustomize.h" +#include "llfloaterdaycycle.h" +#include "llfloaterdestinations.h" +#include "llfloaterdisplayname.h" +#include "llfloatereditui.h" +#include "llfloaterenvsettings.h" +#include "llfloaterexperiences.h" +#include "llfloaterexploreanimations.h" +#include "llfloaterexploresounds.h" +#include "llfloaterfonttest.h" +#include "llfloatergesture.h" +#include "llfloatergodtools.h" +#include "llfloaterhud.h" +#include "llfloaterinspect.h" #include "llfloaterinventory.h" +#include "llfloaterjoystick.h" +#include "llfloaterland.h" +#include "llfloaterlandholdings.h" #include "llfloatermap.h" +#include "llfloatermarketplacelistings.h" +#include "llfloatermediafilter.h" +#include "llfloatermemleak.h" +#include "llfloatermessagelog.h" +#include "llfloatermute.h" +#include "llfloaternotificationsconsole.h" +#include "llfloaterpathfindingcharacters.h" +#include "llfloaterpathfindinglinksets.h" +#include "llfloaterperms.h" +#include "llfloaterpostprocess.h" +#include "llfloaterpreference.h" +#include "llfloaterregiondebugconsole.h" +#include "llfloaterregioninfo.h" +#include "llfloaterreporter.h" +#include "llfloaterscriptdebug.h" +#include "llfloaterscriptlimits.h" +#include "llfloatersettingsdebug.h" +#include "llfloatersnapshot.h" +#include "llfloaterstats.h" +#include "llfloaterteleporthistory.h" +#include "llfloatertest.h" +#include "llfloatervoiceeffect.h" +#include "llfloaterwater.h" +#include "llfloaterwebcontent.h" +#include "llfloaterwindlight.h" #include "llfloaterworldmap.h" -#include "llgivemoney.h" -#include "llinventorypanel.h" -#include "llnotify.h" -#include "llstatusbar.h" -#include "llimview.h" -#include "lltextbox.h" -#include "llui.h" -#include "llviewergesture.h" // for triggering gestures -#include "llviewermessage.h" -#include "llviewerparceloverlay.h" -#include "llviewerregion.h" -#include "llviewerstats.h" +#include "llframestatview.h" +#include "llmakeoutfitdialog.h" +#include "llmoveview.h" // LLFloaterMove +#include "lltextureview.h" +#include "lltoolgrab.h" +#include "lltoolmgr.h" #include "lluictrlfactory.h" -#include "llviewerwindow.h" -#include "llworld.h" -#include "llworldmap.h" -#include "llfocusmgr.h" +#include "llvelocitybar.h" +#include "llviewerparcelmgr.h" +// [RLVa:LF] +#include "rlvfloaters.h" +// [/RLVa:LF] +#include "shfloatermediaticker.h" +void handle_debug_avatar_textures(void*); +template void handle_singleton_toggle(void*); +void show_outfit_dialog() { new LLMakeOutfitDialog(false); } +class LLFloaterExperiencePicker* show_xp_picker(const LLSD& key); +void toggle_build() { LLToolMgr::getInstance()->toggleBuildMode(); } +void toggle_control(const std::string& name) { if (LLControlVariable* control = gSavedSettings.getControl(name)) control->set(!control->get()); } void toggle_search_floater(); +void toggle_always_run() { gAgent.getAlwaysRun() ? gAgent.clearAlwaysRun() : gAgent.setAlwaysRun(); } +void toggle_sit(); +void toggle_mouselook() { gAgentCamera.cameraMouselook() ? gAgentCamera.changeCameraToDefault() : gAgentCamera.changeCameraToMouselook(); } -void handle_track_avatar(const LLUUID& agent_id, const std::string& name) -{ - LLAvatarTracker::instance().track(agent_id, name); - - LLFloaterDirectory::hide(NULL); - LLFloaterWorldMap::show(true); -} - -void handle_mouselook(void*) -{ - gAgentCamera.changeCameraToMouselook(); -} - - -void handle_map(void*) +bool is_visible_view(std::function get) { - LLFloaterWorldMap::toggle(); + if (LLView* v = get()) + return v->getVisible(); + return false; } -void handle_mini_map(void*) +struct CommWrapper { - LLFloaterMap::toggleInstance(); -} - - -void handle_find(void*) -{ - toggle_search_floater(); -} - + static bool only_comm() + { + static const LLCachedControl only("CommunicateSpecificShortcut"); + return only || LLFloaterChatterBox::getInstance()->getFloaterCount(); + } + static bool instanceVisible(const LLSD& key) { return only_comm() ? LLFloaterChatterBox::instanceVisible(key) : LLFloaterMyFriends::instanceVisible(key); } + static void toggleInstance(const LLSD& key) { only_comm() ? LLFloaterChatterBox::toggleInstance(key) : LLFloaterMyFriends::toggleInstance(key); } +}; -void handle_events(void*) +struct MenuFloaterDict final : public LLSingleton { - LLFloaterDirectory::toggleEvents(NULL); -} + typedef std::map, std::function>> menu_floater_map_t; + menu_floater_map_t mEntries; + MenuFloaterDict() + { + registerConsole("debug console", gDebugView->mDebugConsolep); + registerConsole("fast timers", gDebugView->mFastTimerView); + registerConsole("frame console", gDebugView->mFrameStatView); + registerConsole("http console", gHttpView); + registerConsole("texture console", gTextureView); + if (gAuditTexture) + { + registerConsole("texture category console", gTextureCategoryView); + registerConsole("texture size console", gTextureSizeView); + } + registerConsole("velocity", gVelocityBar); + registerFloater("about", boost::bind(&LLFloaterAbout::show,nullptr)); + registerFloater("always run", boost::bind(toggle_always_run), boost::bind(&LLAgent::getAlwaysRun, &gAgent)); + registerFloater("anims_explorer", boost::bind(LLFloaterExploreAnimations::show)); + registerFloater("appearance", boost::bind(LLFloaterCustomize::show)); + registerFloater("asset_blacklist", boost::bind(LLFloaterBlacklist::toggle), boost::bind(LLFloaterBlacklist::visible)); + registerFloater("build", boost::bind(toggle_build)); + registerFloater("buy currency", boost::bind(LLFloaterBuyCurrency::buyCurrency)); + registerFloater("buy land", boost::bind(&LLViewerParcelMgr::startBuyLand, boost::bind(LLViewerParcelMgr::getInstance), false)); + registerFloater("complaint reporter", boost::bind(LLFloaterReporter::showFromMenu, COMPLAINT_REPORT)); + registerFloater("DayCycle", boost::bind(LLFloaterDayCycle::show), boost::bind(LLFloaterDayCycle::isOpen)); + registerFloater("debug avatar", boost::bind(handle_debug_avatar_textures, nullptr)); + registerFloater("debug settings", boost::bind(handle_singleton_toggle, nullptr)); + registerFloater("edit ui", boost::bind(LLFloaterEditUI::show, nullptr)); + registerFloater("EnvSettings", boost::bind(LLFloaterEnvSettings::show), boost::bind(LLFloaterEnvSettings::isOpen)); + registerFloater("experience_search", boost::bind(show_xp_picker, LLSD())); + registerFloater("fly", boost::bind(LLAgent::toggleFlying)); + registerFloater("font test", boost::bind(LLFloaterFontTest::show, nullptr)); + registerFloater("god tools", boost::bind(LLFloaterGodTools::show, nullptr)); + registerFloater("grid options", boost::bind(LLFloaterBuildOptions::show, nullptr)); + registerFloater("group titles", boost::bind(HBFloaterGroupTitles::toggle)); + //Singu TODO: Re-implement f1 help. + //registerFloater("help f1", boost::bind(/*gViewerHtmlHelp.show*/)); + registerFloater("help tutorial", boost::bind(LLFloaterHUD::showHUD)); + registerFloater("inventory", boost::bind(LLPanelMainInventory::toggleVisibility, nullptr), boost::bind(is_visible_view, static_cast >(LLPanelMainInventory::getActiveInventory))); + registerFloater("local assets", boost::bind(FloaterLocalAssetBrowser::show, (void*)0)); + registerFloater("mean events", boost::bind(LLFloaterBump::show, nullptr)); + registerFloater("media ticker", boost::bind(handle_ticker_toggle, nullptr), boost::bind(SHFloaterMediaTicker::instanceExists)); + registerFloater("memleak", boost::bind(LLFloaterMemLeak::show, nullptr)); + registerFloater("messagelog", boost::bind(LLFloaterMessageLog::show)); + registerFloater("mouselook", boost::bind(toggle_mouselook)); + registerFloater("my land", boost::bind(LLFloaterLandHoldings::show, nullptr)); + registerFloater("outfit", boost::bind(show_outfit_dialog)); + registerFloater("preferences", boost::bind(LLFloaterPreference::show, nullptr)); + registerFloater("quit", boost::bind(&LLAppViewer::userQuit, LLAppViewer::instance())); + registerFloater("RegionDebugConsole", boost::bind(handle_singleton_toggle, nullptr), boost::bind(LLFloaterRegionDebugConsole::instanceExists)); + registerFloater("script errors", boost::bind(LLFloaterScriptDebug::show, LLUUID::null)); + registerFloater("search", boost::bind(toggle_search_floater)); + registerFloater("show inspect", boost::bind(LLFloaterInspect::showInstance, LLSD())); + registerFloater("sit", boost::bind(toggle_sit)); + registerFloater("snapshot", boost::bind(LLFloaterSnapshot::show, nullptr)); + registerFloater("sound_explorer", boost::bind(LLFloaterExploreSounds::toggle), boost::bind(LLFloaterExploreSounds::visible)); + registerFloater("test", boost::bind(LLFloaterTest::show, nullptr)); + // Phoenix: Wolfspirit: Enabled Show Floater out of viewer menu + registerFloater("WaterSettings", boost::bind(LLFloaterWater::show), boost::bind(LLFloaterWater::isOpen)); + registerFloater("Windlight", boost::bind(LLFloaterWindLight::show), boost::bind(LLFloaterWindLight::isOpen)); + registerFloater("world map", boost::bind(LLFloaterWorldMap::toggle)); + registerFloater ("about land"); + registerFloater ("about region"); + registerFloater ("active speakers"); + registerFloater ("ao"); + registerFloater ("areasearch"); + registerFloater ("autoreplace"); + registerFloater ("avatar"); + registerFloater ("beacons"); + registerFloater ("camera controls"); + registerFloater ("chat history"); + registerFloater ("communicate"); + registerFloater ("destinations"); + registerFloater ("displayname"); + registerFloater ("experiences"); + registerFloater ("friends", 0); + registerFloater ("gestures"); + registerFloater ("groups", 1); + registerFloater ("im"); + registerFloater ("inspect"); + registerFloater ("joystick"); + registerFloater ("media filter"); + registerFloater ("mini map"); + registerFloater ("marketplace_listings"); + registerFloater ("movement controls"); + registerFloater ("mute list"); + registerFloater ("notifications console"); + registerFloater ("pathfinding_characters"); + registerFloater ("pathfinding_linksets"); + registerFloater ("perm prefs"); + registerFloater ("PostProcess"); + registerFloater ("radar"); + registerFloater ("region_tracker"); + registerFloater ("script info"); + registerFloater ("stat bar"); + registerFloater ("teleport history"); + registerFloater ("voice effect"); + // [RLVa:LF] + registerFloater("rlv restrictions"); + registerFloater("rlv locks"); + registerFloater("rlv strings"); + // [/RLVa:LF] + } +public: + template + void registerConsole(const std::string& name, T* console) + { + registerFloater(name, boost::bind(&T::setVisible, console, !boost::bind(&T::getVisible, console)), boost::bind(&T::getVisible, console)); + } + void registerFloater(const std::string& name, std::function show, std::function visible = nullptr) + { + mEntries.insert( std::make_pair( name, std::make_pair( show, visible ) ) ); + } + template + void registerFloater(const std::string& name, const LLSD& key = LLSD()) + { + registerFloater(name, boost::bind(&T::toggleInstance,key), boost::bind(&T::instanceVisible,key)); + } +}; -void handle_inventory(void*) +void show_floater(const std::string& floater_name) { - // We're using the inventory, possibly for the - // first time. - LLFirstUse::useInventory(); - - LLInventoryView::toggleVisibility(NULL); -} + if (floater_name.empty()) return; - -void handle_chat(void*) -{ - // give focus to chatbar if it's open but not focused - static const LLCachedControl chat_visible("ChatVisible",true); - if (chat_visible && gFocusMgr.childHasKeyboardFocus(gChatBar)) + MenuFloaterDict::menu_floater_map_t::iterator it = MenuFloaterDict::instance().mEntries.find(floater_name); + if (it == MenuFloaterDict::instance().mEntries.end()) // Simple codeless floater { - LLChatBar::stopChat(); + if (LLFloater* floater = LLUICtrlFactory::getInstance()->getBuiltFloater(floater_name)) + floater->isFrontmost() ? floater->close() : gFloaterView->bringToFront(floater); + else + LLUICtrlFactory::getInstance()->buildFloater(new LLFloater(), floater_name); } - else + else if (it->second.first) { - LLChatBar::startChat(NULL); + it->second.first(); } } -void handle_slash_key(void*) +// Singu TODO: It'd be reallllly nice if we could use this as a control for buttons too. +bool floater_visible(const std::string& floater_name) { - // LLChatBar::startChat("/"); - // - // Don't do this, it results in a double-slash in the input field. - // Another "/" will be automatically typed for us, because the WM_KEYDOWN event - // that generated the menu accelerator call (and hence puts focus in - // the chat edtior) will be followed by a "/" WM_CHAR character message, - // which will type the slash. Yes, it's weird. It only matters for - // menu accelerators that put input focus into a field. And Mac works - // the same way. JC - - LLChatBar::startChat(NULL); + MenuFloaterDict::menu_floater_map_t::iterator it = MenuFloaterDict::instance().mEntries.find(floater_name); + return it != MenuFloaterDict::instance().mEntries.end() && it->second.second && it->second.second(); } diff --git a/indra/newview/llmenucommands.h b/indra/newview/llmenucommands.h index 1c4550b07c..1ec7be3094 100644 --- a/indra/newview/llmenucommands.h +++ b/indra/newview/llmenucommands.h @@ -33,17 +33,4 @@ #ifndef LL_LLMENUCOMMANDS_H #define LL_LLMENUCOMMANDS_H -class LLUUID; - -void handle_track_avatar(const LLUUID& agent_id, const std::string& name); -void handle_mouselook(void*); -void handle_map(void*); -void handle_mini_map(void*); -void handle_find(void*); -void handle_events(void*); -void handle_inventory(void*); -void handle_chat(void*); -void handle_return_key(void*); -void handle_slash_key(void*); - #endif diff --git a/indra/newview/llmenuoptionpathfindingrebakenavmesh.cpp b/indra/newview/llmenuoptionpathfindingrebakenavmesh.cpp index 0dea26fb74..4b08cae72d 100644 --- a/indra/newview/llmenuoptionpathfindingrebakenavmesh.cpp +++ b/indra/newview/llmenuoptionpathfindingrebakenavmesh.cpp @@ -54,6 +54,8 @@ LLMenuOptionPathfindingRebakeNavmesh::LLMenuOptionPathfindingRebakeNavmesh() LLMenuOptionPathfindingRebakeNavmesh::~LLMenuOptionPathfindingRebakeNavmesh() { + if (mIsInitialized) + { if (mRebakeNavMeshMode == kRebakeNavMesh_RequestSent) { LL_WARNS("navmeshRebaking") << "During destruction of the LLMenuOptionPathfindingRebakeNavmesh " @@ -61,9 +63,6 @@ LLMenuOptionPathfindingRebakeNavmesh::~LLMenuOptionPathfindingRebakeNavmesh() << "to be received. This could contribute to a crash on exit." << LL_ENDL; } - llassert(!mIsInitialized); - if (mIsInitialized) - { quit(); } } @@ -80,7 +79,7 @@ void LLMenuOptionPathfindingRebakeNavmesh::initialize() if ( !mRegionCrossingSlot.connected() ) { - mRegionCrossingSlot = LLEnvManagerNew::getInstance()->setRegionChangeCallback(boost::bind(&LLMenuOptionPathfindingRebakeNavmesh::handleRegionBoundaryCrossed, this)); + mRegionCrossingSlot = gAgent.addRegionChangedCallback(boost::bind(&LLMenuOptionPathfindingRebakeNavmesh::handleRegionBoundaryCrossed, this)); } if (!mAgentStateSlot.connected()) @@ -93,8 +92,7 @@ void LLMenuOptionPathfindingRebakeNavmesh::initialize() void LLMenuOptionPathfindingRebakeNavmesh::quit() { - llassert(mIsInitialized); - if (mIsInitialized) + if (mIsInitialized) // Quitting from the login screen leaves this uninitialized { if (mNavMeshSlot.connected()) { @@ -174,51 +172,60 @@ void LLMenuOptionPathfindingRebakeNavmesh::handleAgentState(BOOL pCanRebakeRegio void LLMenuOptionPathfindingRebakeNavmesh::handleRebakeNavMeshResponse(bool pResponseStatus) { llassert(mIsInitialized); - if (getMode() == kRebakeNavMesh_RequestSent) + if (mIsInitialized) { - setMode(pResponseStatus ? kRebakeNavMesh_InProgress : kRebakeNavMesh_Default); - } + if (getMode() == kRebakeNavMesh_RequestSent) + { + setMode(pResponseStatus ? kRebakeNavMesh_InProgress : kRebakeNavMesh_Default); + } - if (!pResponseStatus) - { - LLNotificationsUtil::add("PathfindingCannotRebakeNavmesh"); + if (!pResponseStatus) + { + LLNotificationsUtil::add("PathfindingCannotRebakeNavmesh"); + } } } void LLMenuOptionPathfindingRebakeNavmesh::handleNavMeshStatus(const LLPathfindingNavMeshStatus &pNavMeshStatus) { llassert(mIsInitialized); - ERebakeNavMeshMode rebakeNavMeshMode = kRebakeNavMesh_Default; - if (pNavMeshStatus.isValid()) + if (mIsInitialized) { - switch (pNavMeshStatus.getStatus()) + ERebakeNavMeshMode rebakeNavMeshMode = kRebakeNavMesh_Default; + if (pNavMeshStatus.isValid()) { - case LLPathfindingNavMeshStatus::kPending : - case LLPathfindingNavMeshStatus::kRepending : - rebakeNavMeshMode = kRebakeNavMesh_Available; - break; - case LLPathfindingNavMeshStatus::kBuilding : - rebakeNavMeshMode = kRebakeNavMesh_InProgress; - break; - case LLPathfindingNavMeshStatus::kComplete : - rebakeNavMeshMode = kRebakeNavMesh_NotAvailable; - break; - default : - rebakeNavMeshMode = kRebakeNavMesh_Default; - llassert(0); - break; + switch (pNavMeshStatus.getStatus()) + { + case LLPathfindingNavMeshStatus::kPending : + case LLPathfindingNavMeshStatus::kRepending : + rebakeNavMeshMode = kRebakeNavMesh_Available; + break; + case LLPathfindingNavMeshStatus::kBuilding : + rebakeNavMeshMode = kRebakeNavMesh_InProgress; + break; + case LLPathfindingNavMeshStatus::kComplete : + rebakeNavMeshMode = kRebakeNavMesh_NotAvailable; + break; + default: + rebakeNavMeshMode = kRebakeNavMesh_Default; + llassert(0); + break; + } } - } - setMode(rebakeNavMeshMode); + setMode(rebakeNavMeshMode); + } } void LLMenuOptionPathfindingRebakeNavmesh::handleRegionBoundaryCrossed() { llassert(mIsInitialized); - createNavMeshStatusListenerForCurrentRegion(); - mCanRebakeRegion = FALSE; - LLPathfindingManager::getInstance()->requestGetAgentState(); + if (mIsInitialized) + { + createNavMeshStatusListenerForCurrentRegion(); + mCanRebakeRegion = FALSE; + LLPathfindingManager::getInstance()->requestGetAgentState(); + } } void LLMenuOptionPathfindingRebakeNavmesh::createNavMeshStatusListenerForCurrentRegion() @@ -235,3 +242,4 @@ void LLMenuOptionPathfindingRebakeNavmesh::createNavMeshStatusListenerForCurrent LLPathfindingManager::getInstance()->requestGetNavMeshForRegion(currentRegion, true); } } + diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 66ed09f265..160dc67be3 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -38,7 +38,6 @@ #include "lldatapacker.h" #include "llfasttimer.h" #include "llfloaterperms.h" -#include "lleconomy.h" #include "llimagej2c.h" #include "llhost.h" #include "llnotificationsutil.h" @@ -66,7 +65,8 @@ #include "lluploadfloaterobservers.h" #include "aicurl.h" -#include "boost/lexical_cast.hpp" +#include + #ifndef LL_WINDOWS #include "netdb.h" #endif @@ -103,14 +103,13 @@ U32 LLMeshRepository::sLODPending = 0; U32 LLMeshRepository::sCacheBytesRead = 0; U32 LLMeshRepository::sCacheBytesWritten = 0; U32 LLMeshRepository::sPeakKbps = 0; - const U32 MAX_TEXTURE_UPLOAD_RETRIES = 5; static S32 dump_num = 0; std::string make_dump_name(std::string prefix, S32 num) { - return prefix + boost::lexical_cast(num) + std::string(".xml"); + return prefix + fmt::to_string(num) + std::string(".xml"); } void dump_llsd_to_file(const LLSD& content, std::string filename); @@ -123,6 +122,7 @@ std::string header_lod[] = "medium_lod", "high_lod" }; +const char * const LOG_MESH = "Mesh"; //get the number of bytes resident in memory for given volume @@ -205,6 +205,12 @@ void get_vertex_buffer_from_mesh(LLCDMeshData& mesh, LLModel::PhysicsMesh& res, } } +LLViewerFetchedTexture* LLMeshUploadThread::FindViewerTexture(const LLImportMaterial& material) +{ + LLPointer< LLViewerFetchedTexture > * ppTex = static_cast< LLPointer< LLViewerFetchedTexture > * >(material.mOpaqueData); + return ppTex ? (*ppTex).get() : NULL; +} + S32 LLMeshRepoThread::sActiveHeaderRequests = 0; S32 LLMeshRepoThread::sActiveLODRequests = 0; U32 LLMeshRepoThread::sMaxConcurrentRequests = 1; @@ -214,6 +220,7 @@ class LLMeshHeaderResponder : public LLHTTPClient::ResponderWithCompleted public: LLVolumeParams mMeshParams; bool mProcessed; + void retry(); LLMeshHeaderResponder(const LLVolumeParams& mesh_params) : mMeshParams(mesh_params) @@ -228,20 +235,19 @@ class LLMeshHeaderResponder : public LLHTTPClient::ResponderWithCompleted { if (!mProcessed) { //something went wrong, retry - llwarns << "Timeout or service unavailable, retrying." << llendl; + LL_WARNS() << "Timeout or service unavailable, retrying." << LL_ENDL; LLMeshRepository::sHTTPRetryCount++; - LLMeshRepoThread::HeaderRequest req(mMeshParams); LLMutexLock lock(gMeshRepo.mThread->mMutex); - gMeshRepo.mThread->mHeaderReqQ.push(req); + gMeshRepo.mThread->pushHeaderRequest(mMeshParams, 10.f); } LLMeshRepoThread::decActiveHeaderRequests(); } } - /*virtual*/ void completedRaw(U32 status, const std::string& reason, - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer); + + virtual void completedRaw(LLChannelDescriptors const& channels, + LLIOPipe::buffer_ptr_t const& buffer); /*virtual*/ AICapabilityType capability_type(void) const { return cap_mesh; } /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return meshHeaderResponder_timeout; } @@ -256,6 +262,7 @@ class LLMeshLODResponder : public LLHTTPClient::ResponderWithCompleted U32 mRequestedBytes; U32 mOffset; bool mProcessed; + void retry(); LLMeshLODResponder(const LLVolumeParams& mesh_params, S32 lod, U32 offset, U32 requested_bytes) : mMeshParams(mesh_params), mLOD(lod), mOffset(offset), mRequestedBytes(requested_bytes) @@ -266,11 +273,11 @@ class LLMeshLODResponder : public LLHTTPClient::ResponderWithCompleted ~LLMeshLODResponder() { - if (!LLApp::isQuitting()) + if (!LLApp::isExiting()) { if (!mProcessed) { - llwarns << "Killed without being processed, retrying." << llendl; + LL_WARNS() << "Killed without being processed, retrying." << LL_ENDL; LLMeshRepository::sHTTPRetryCount++; gMeshRepo.mThread->lockAndLoadMeshLOD(mMeshParams, mLOD); } @@ -278,9 +285,8 @@ class LLMeshLODResponder : public LLHTTPClient::ResponderWithCompleted } } - /*virtual*/ void completedRaw(U32 status, const std::string& reason, - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer); + virtual void completedRaw(LLChannelDescriptors const& channels, + LLIOPipe::buffer_ptr_t const& buffer); /*virtual*/ AICapabilityType capability_type(void) const { return cap_mesh; } /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return meshLODResponder_timeout; } @@ -294,6 +300,7 @@ class LLMeshSkinInfoResponder : public LLHTTPClient::ResponderWithCompleted U32 mRequestedBytes; U32 mOffset; bool mProcessed; + void retry(); LLMeshSkinInfoResponder(const LLUUID& id, U32 offset, U32 size) : mMeshID(id), mRequestedBytes(size), mOffset(offset) @@ -303,12 +310,18 @@ class LLMeshSkinInfoResponder : public LLHTTPClient::ResponderWithCompleted ~LLMeshSkinInfoResponder() { - llassert(mProcessed); + if (!LLApp::isQuitting() && + !mProcessed && + mMeshID.notNull()) + { // Something went wrong, retry + LL_WARNS() << "Timeout or service unavailable, retrying loadMeshSkinInfo() for " << mMeshID << LL_ENDL; + LLMeshRepository::sHTTPRetryCount++; + gMeshRepo.mThread->loadMeshSkinInfo(mMeshID); + } } - /*virtual*/ void completedRaw(U32 status, const std::string& reason, - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer); + virtual void completedRaw(LLChannelDescriptors const& channels, + LLIOPipe::buffer_ptr_t const& buffer); /*virtual*/ AICapabilityType capability_type(void) const { return cap_mesh; } /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return meshSkinInfoResponder_timeout; } @@ -322,6 +335,7 @@ class LLMeshDecompositionResponder : public LLHTTPClient::ResponderWithCompleted U32 mRequestedBytes; U32 mOffset; bool mProcessed; + void retry(); LLMeshDecompositionResponder(const LLUUID& id, U32 offset, U32 size) : mMeshID(id), mRequestedBytes(size), mOffset(offset) @@ -331,12 +345,18 @@ class LLMeshDecompositionResponder : public LLHTTPClient::ResponderWithCompleted ~LLMeshDecompositionResponder() { - llassert(mProcessed); + if (!LLApp::isQuitting() && + !mProcessed && + mMeshID.notNull()) + { // Something went wrong, retry + LL_WARNS() << "Timeout or service unavailable, retrying loadMeshDecomposition() for " << mMeshID << LL_ENDL; + LLMeshRepository::sHTTPRetryCount++; + gMeshRepo.mThread->loadMeshDecomposition(mMeshID); + } } - /*virtual*/ void completedRaw(U32 status, const std::string& reason, - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer); + virtual void completedRaw(LLChannelDescriptors const& channels, + LLIOPipe::buffer_ptr_t const& buffer); /*virtual*/ AICapabilityType capability_type(void) const { return cap_mesh; } /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return meshDecompositionResponder_timeout; } @@ -350,6 +370,7 @@ class LLMeshPhysicsShapeResponder : public LLHTTPClient::ResponderWithCompleted U32 mRequestedBytes; U32 mOffset; bool mProcessed; + void retry(); LLMeshPhysicsShapeResponder(const LLUUID& id, U32 offset, U32 size) : mMeshID(id), mRequestedBytes(size), mOffset(offset) @@ -359,12 +380,18 @@ class LLMeshPhysicsShapeResponder : public LLHTTPClient::ResponderWithCompleted ~LLMeshPhysicsShapeResponder() { - llassert(mProcessed); + if (!LLApp::isQuitting() && + !mProcessed && + mMeshID.notNull()) + { // Something went wrong, retry + LL_WARNS() << "Timeout or service unavailable, retrying loadMeshPhysicsShape() for " << mMeshID << LL_ENDL; + LLMeshRepository::sHTTPRetryCount++; + gMeshRepo.mThread->loadMeshPhysicsShape(mMeshID); + } } - /*virtual*/ void completedRaw(U32 status, const std::string& reason, - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer); + virtual void completedRaw(LLChannelDescriptors const& channels, + LLIOPipe::buffer_ptr_t const& buffer); /*virtual*/ AICapabilityType capability_type(void) const { return cap_mesh; } /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return meshPhysicsShapeResponder_timeout; } @@ -383,16 +410,16 @@ void log_upload_error(S32 status, const LLSD& content, std::string stage, std::s gMeshRepo.uploadError(args); // Log details. - llwarns << "stage: " << stage << " http status: " << status << llendl; + LL_WARNS() << "stage: " << stage << " http status: " << status << LL_ENDL; if (content.has("error")) { const LLSD& err = content["error"]; - llwarns << "err: " << err << llendl; - llwarns << "mesh upload failed, stage '" << stage + LL_WARNS() << "err: " << err << LL_ENDL; + LL_WARNS() << "mesh upload failed, stage '" << stage << "' error '" << err["error"].asString() << "', message '" << err["message"].asString() << "', id '" << err["identifier"].asString() - << "'" << llendl; + << "'" << LL_ENDL; if (err.has("errors")) { S32 error_num = 0; @@ -402,13 +429,13 @@ void log_upload_error(S32 status, const LLSD& content, std::string stage, std::s ++it) { const LLSD& err_entry = *it; - llwarns << "error[" << error_num << "]:" << llendl; + LL_WARNS() << "error[" << error_num << "]:" << LL_ENDL; for (LLSD::map_const_iterator map_it = err_entry.beginMap(); map_it != err_entry.endMap(); ++map_it) { - llwarns << "\t" << map_it->first << ": " - << map_it->second << llendl; + LL_WARNS() << "\t" << map_it->first << ": " + << map_it->second << LL_ENDL; } error_num++; } @@ -416,7 +443,7 @@ void log_upload_error(S32 status, const LLSD& content, std::string stage, std::s } else { - llwarns << "bad mesh, no error information available" << llendl; + LL_WARNS() << "bad mesh, no error information available" << LL_ENDL; } } @@ -437,11 +464,9 @@ class LLWholeModelFeeResponder : public LLHTTPClient::ResponderWithCompleted { } - /*virtual*/ void completed(U32 status, - const std::string& reason, - const LLSD& content) + virtual void httpCompleted(void) { - LLSD cc = content; + LLSD cc = mContent; if (gSavedSettings.getS32("MeshUploadFakeErrors")&1) { cc = llsd_from_file("fake_upload_error.xml"); @@ -451,7 +476,7 @@ class LLWholeModelFeeResponder : public LLHTTPClient::ResponderWithCompleted LLWholeModelFeeObserver* observer = mObserverHandle.get(); - if (((200 <= status) && (status < 300)) && + if (isGoodStatus(mStatus) && cc["state"].asString() == "upload") { mWholeModelUploadURL = cc["uploader"].asString(); @@ -464,13 +489,13 @@ class LLWholeModelFeeResponder : public LLHTTPClient::ResponderWithCompleted } else { - llwarns << "fee request failed" << llendl; - log_upload_error(status,cc,"fee",mModelData["name"]); + LL_WARNS() << "fee request failed" << LL_ENDL; + log_upload_error(mStatus,cc,"fee",mModelData["name"]); mWholeModelUploadURL = ""; if (observer) { - observer->setModelPhysicsFeeErrorStatus(status, reason); + observer->setModelPhysicsFeeErrorStatus(mStatus, mReason); } } } @@ -495,11 +520,9 @@ class LLWholeModelUploadResponder : public LLHTTPClient::ResponderWithCompleted { } - /*virtual*/ void completed(U32 status, - const std::string& reason, - const LLSD& content) + virtual void httpCompleted(void) { - LLSD cc = content; + LLSD cc = mContent; if (gSavedSettings.getS32("MeshUploadFakeErrors")&2) { cc = llsd_from_file("fake_upload_error.xml"); @@ -511,7 +534,7 @@ class LLWholeModelUploadResponder : public LLHTTPClient::ResponderWithCompleted // requested "mesh" asset type isn't actually the type // of the resultant object, fix it up here. - if (((200 <= status) && (status < 300)) && + if (isGoodStatus(mStatus) && cc["state"].asString() == "complete") { mModelData["asset_type"] = "object"; @@ -524,9 +547,9 @@ class LLWholeModelUploadResponder : public LLHTTPClient::ResponderWithCompleted } else { - llwarns << "upload failed" << llendl; + LL_WARNS() << "upload failed" << LL_ENDL; std::string model_name = mModelData["name"].asString(); - log_upload_error(status,cc,"upload",model_name); + log_upload_error(mStatus,cc,"upload",model_name); if (observer) { @@ -545,6 +568,8 @@ LLMeshRepoThread::LLMeshRepoThread() mMutex = new LLMutex(); mHeaderMutex = new LLMutex(); mSignal = new LLCondition(); + mSkinInfoQMutex = new LLMutex(); + mDecompositionQMutex = new LLMutex(); } LLMeshRepoThread::~LLMeshRepoThread() @@ -555,6 +580,84 @@ LLMeshRepoThread::~LLMeshRepoThread() mHeaderMutex = NULL; delete mSignal; mSignal = NULL; + delete mSkinInfoQMutex; + mSkinInfoQMutex = NULL; + delete mDecompositionQMutex; + mDecompositionQMutex = NULL; +} + +bool LLMeshRepoThread::HeaderRequest::fetch(U32& count) +{ + return gMeshRepo.mThread->fetchMeshHeader(this->mMeshParams, count); +} + +void LLMeshRepoThread::LODRequest::preFetch() +{ + --LLMeshRepository::sLODProcessing; +} + +bool LLMeshRepoThread::LODRequest::fetch(U32& count) +{ + if (!gMeshRepo.mThread->fetchMeshLOD(this->mMeshParams, this->mLOD, count)) + { + gMeshRepo.mThread->mMutex->lock(); + ++LLMeshRepository::sLODProcessing; + gMeshRepo.mThread->mMutex->unlock(); + return false; + } + return true; +} + +void LLMeshRepoThread::runQueue(std::deque, F32> >& query, U32& count, S32& active_requests) +{ + std::queue, F32> > incomplete; + while (!query.empty() && count < MAX_MESH_REQUESTS_PER_SECOND && active_requests < (S32)sMaxConcurrentRequests) + { + if (mMutex) + { + mMutex->lock(); + auto req = query.front().first; + F32 delay = query.front().second; + query.pop_front(); + req->preFetch(); + mMutex->unlock(); + F32 remainder = delay - req->mTimer.getElapsedTimeF32(); + if (remainder > 0.f) + { + //LL_INFOS() << req->mMeshParams.getSculptID() << " skipped. " << remainder << "s remaining" << LL_ENDL; + incomplete.push(std::make_pair(req, delay)); + } + else if (!req->fetch(count))//failed, resubmit + { + LL_INFOS() << req->mMeshParams.getSculptID() << " fetch failed outright. Delaying for " << (delay ? delay : 15) << "s" << LL_ENDL; + req->mTimer.reset(); + incomplete.push(std::make_pair(req, delay ? delay : 15)); + } + else { + //LL_INFOS() << req->mMeshParams.getSculptID() << " fetch request created. " << std::hex << &(req->mMeshParams) << std::dec << LL_ENDL; + } + } + } + if (!incomplete.empty()) + { + mMutex->lock(); + while (!incomplete.empty()) + { + query.push_back(incomplete.front()); + incomplete.pop(); + } + mMutex->unlock(); + } +} + +void LLMeshRepoThread::runSet(uuid_set_t& set, std::function fn) +{ + for (auto iter = set.begin(); iter != set.end();) + { + if (fn(*iter)) + iter = set.erase(iter); + else ++iter; + } } void LLMeshRepoThread::run() @@ -562,12 +665,13 @@ void LLMeshRepoThread::run() LLCDResult res = LLConvexDecomposition::initThread(); if (res != LLCD_OK) { - llwarns << "convex decomposition unable to be loaded" << llendl; + LL_WARNS() << "convex decomposition unable to be loaded" << LL_ENDL; } mSignal->lock(); while (!LLApp::isQuitting()) { + if (!LLApp::isQuitting()) { static U32 count = 0; @@ -580,133 +684,32 @@ void LLMeshRepoThread::run() } // NOTE: throttling intentionally favors LOD requests over header requests + runQueue(mLODReqQ, count, sActiveLODRequests); + runQueue(mHeaderReqQ, count, sActiveHeaderRequests); - while (!mLODReqQ.empty() && count < MAX_MESH_REQUESTS_PER_SECOND && sActiveLODRequests < (S32)sMaxConcurrentRequests) - { - { - mMutex->lock(); - LODRequest req = mLODReqQ.front(); - mLODReqQ.pop(); - LLMeshRepository::sLODProcessing--; - mMutex->unlock(); - try - { - fetchMeshLOD(req.mMeshParams, req.mLOD, count); - } - catch(AICurlNoEasyHandle const& error) - { - llwarns << "fetchMeshLOD() failed: " << error.what() << llendl; - mMutex->lock(); - LLMeshRepository::sLODProcessing++; - mLODReqQ.push(req); - mMutex->unlock(); - break; - } - } - } + // Protected by mSignal + runSet(mSkinRequests, std::bind(&LLMeshRepoThread::fetchMeshSkinInfo, this, std::placeholders::_1)); + runSet(mDecompositionRequests, std::bind(&LLMeshRepoThread::fetchMeshDecomposition, this, std::placeholders::_1)); + runSet(mPhysicsShapeRequests, std::bind(&LLMeshRepoThread::fetchMeshPhysicsShape, this, std::placeholders::_1)); - while (!mHeaderReqQ.empty() && count < MAX_MESH_REQUESTS_PER_SECOND && sActiveHeaderRequests < (S32)sMaxConcurrentRequests) - { - { - mMutex->lock(); - HeaderRequest req = mHeaderReqQ.front(); - mHeaderReqQ.pop(); - mMutex->unlock(); - bool success = false; - try - { - success = fetchMeshHeader(req.mMeshParams, count); - } - catch(AICurlNoEasyHandle const& error) - { - llwarns << "fetchMeshHeader() failed: " << error.what() << llendl; - } - if (!success) - { - mMutex->lock(); - mHeaderReqQ.push(req) ; - mMutex->unlock(); - break; - } - } - } - - { //mSkinRequests is protected by mSignal - std::set incomplete; - for (std::set::iterator iter = mSkinRequests.begin(); iter != mSkinRequests.end(); ++iter) - { - LLUUID mesh_id = *iter; - bool success = false; - try - { - success = fetchMeshSkinInfo(mesh_id); - } - catch(AICurlNoEasyHandle const& error) - { - llwarns << "fetchMeshSkinInfo(" << mesh_id << ") failed: " << error.what() << llendl; - } - if (!success) - { - incomplete.insert(mesh_id); - } - } - mSkinRequests = incomplete; - } - - { //mDecompositionRequests is protected by mSignal - std::set incomplete; - for (std::set::iterator iter = mDecompositionRequests.begin(); iter != mDecompositionRequests.end(); ++iter) - { - LLUUID mesh_id = *iter; - bool success = false; - try - { - success = fetchMeshDecomposition(mesh_id); - } - catch(AICurlNoEasyHandle const& error) - { - llwarns << "fetchMeshDecomposition(" << mesh_id << ") failed: " << error.what() << llendl; - } - if (!success) - { - incomplete.insert(mesh_id); - } - } - mDecompositionRequests = incomplete; - } + } - { //mPhysicsShapeRequests is protected by mSignal - std::set incomplete; - for (std::set::iterator iter = mPhysicsShapeRequests.begin(); iter != mPhysicsShapeRequests.end(); ++iter) - { - LLUUID mesh_id = *iter; - bool success = false; - try - { - success = fetchMeshPhysicsShape(mesh_id); - } - catch(AICurlNoEasyHandle const& error) - { - llwarns << "fetchMeshPhysicsShape(" << mesh_id << ") failed: " << error.what() << llendl; - } - if (!success) - { - incomplete.insert(mesh_id); - } - } - mPhysicsShapeRequests = incomplete; - } + mSignal->unlock(); + ms_sleep(1000 / 60); + mSignal->lock(); - } + //mSignal->wait(); + } - mSignal->wait(); + if (mSignal->isLocked()) + { //make sure to let go of the mutex associated with the given signal before shutting down + mSignal->unlock(); } - mSignal->unlock(); res = LLConvexDecomposition::quitThread(); if (res != LLCD_OK) { - llwarns << "convex decomposition unable to be quit" << llendl; + LL_WARNS() << "convex decomposition unable to be quit" << LL_ENDL; } } @@ -734,22 +737,22 @@ void LLMeshRepoThread::lockAndLoadMeshLOD(const LLVolumeParams& mesh_params, S32 } } + + void LLMeshRepoThread::loadMeshLOD(const LLVolumeParams& mesh_params, S32 lod) { //could be called from any thread + std::unique_lock header_lock(*mHeaderMutex); + bool exists = mMeshHeader.find(mesh_params.getSculptID()) != mMeshHeader.end(); + header_lock.unlock(); LLMutexLock lock(mMutex); - mesh_header_map::iterator iter = mMeshHeader.find(mesh_params.getSculptID()); - if (iter != mMeshHeader.end()) - { //if we have the header, request LOD byte range - LODRequest req(mesh_params, lod); - { - mLODReqQ.push(req); - LLMeshRepository::sLODProcessing++; - } + if (exists) + { + //if we have the header, request LOD byte range + gMeshRepo.mThread->pushLODRequest(mesh_params, lod, 0.f); + LLMeshRepository::sLODProcessing++; } else { - HeaderRequest req(mesh_params); - pending_lod_map::iterator pending = mPendingLOD.find(mesh_params); if (pending != mPendingLOD.end()) @@ -759,7 +762,7 @@ void LLMeshRepoThread::loadMeshLOD(const LLVolumeParams& mesh_params, S32 lod) } else { //if no header request is pending, fetch header - mHeaderReqQ.push(req); + gMeshRepo.mThread->pushHeaderRequest(mesh_params, 0.f); mPendingLOD[mesh_params].push_back(lod); } } @@ -782,219 +785,156 @@ std::string LLMeshRepoThread::constructUrl(LLUUID mesh_id) } else { - llwarns << "Current region does not have GetMesh capability! Cannot load " << mesh_id << ".mesh" << llendl; + LL_WARNS() << "Current region does not have GetMesh capability! Cannot load " << mesh_id << ".mesh" << LL_ENDL; } return http_url; } -bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id) +bool LLMeshRepoThread::getMeshHeaderInfo(const LLUUID& mesh_id, const char* block_name, MeshHeaderInfo& info) { //protected by mMutex - mHeaderMutex->lock(); - if (mMeshHeader.find(mesh_id) == mMeshHeader.end()) + if (!mHeaderMutex) { - // We have no header info for this mesh, try again later. - mHeaderMutex->unlock(); return false; } - U32 header_size = mMeshHeaderSize[mesh_id]; - - if (header_size > 0) + LLMutexLock lock(mHeaderMutex); + + if (mMeshHeader.find(mesh_id) == mMeshHeader.end()) + { //we have no header info for this mesh, do nothing + return false; + } + + if ((info.mHeaderSize = mMeshHeaderSize[mesh_id]) > 0) { - S32 version = mMeshHeader[mesh_id]["version"].asInteger(); - S32 offset = header_size + mMeshHeader[mesh_id]["skin"]["offset"].asInteger(); - S32 size = mMeshHeader[mesh_id]["skin"]["size"].asInteger(); + const LLSD& header = mMeshHeader[mesh_id]; + const LLSD& block = header[block_name]; + info.mVersion = header["version"].asInteger(); + info.mOffset = info.mHeaderSize + block["offset"].asInteger(); + info.mSize = block["size"].asInteger(); + } + return true; +} - mHeaderMutex->unlock(); +bool LLMeshRepoThread::loadInfoFromVFS(const LLUUID& mesh_id, MeshHeaderInfo& info, boost::function fn) +{ + //check VFS for mesh skin info + LLVFile file(gVFS, mesh_id, LLAssetType::AT_MESH); + if (file.getSize() >= info.mOffset + info.mSize) + { + LLMeshRepository::sCacheBytesRead += info.mSize; - if (version <= MAX_MESH_VERSION && offset >= 0 && size > 0) - { - //check VFS for mesh skin info - LLVFile file(gVFS, mesh_id, LLAssetType::AT_MESH); - if (file.getSize() >= offset+size) - { - LLMeshRepository::sCacheBytesRead += size; - file.seek(offset); - U8* buffer = new U8[size]; - file.read(buffer, size); - - //make sure buffer isn't all 0's (reserved block but not written) - bool zero = true; - for (S32 i = 0; i < llmin(size, 1024) && zero; ++i) - { - zero = buffer[i] > 0 ? false : true; - } + file.seek(info.mOffset); + U8* buffer = new U8[info.mSize]; + file.read(buffer, info.mSize); - if (!zero) - { //attempt to parse - if (skinInfoReceived(mesh_id, buffer, size)) - { - delete[] buffer; - return true; - } - } + //make sure buffer isn't all 0's by checking the first 1KB (reserved block but not written) + bool zero = true; + for (S32 i = 0; i < llmin(info.mSize, S32(1024)) && zero; ++i) + { + zero = buffer[i] > 0 ? false : true; + } + if (!zero) + { //attempt to parse + if (fn(mesh_id, buffer, info.mSize)) + { delete[] buffer; + return true; } + } - //reading from VFS failed for whatever reason, fetch from sim - AIHTTPHeaders headers("Accept", "application/octet-stream"); + delete[] buffer; + } + return false; +} - std::string http_url = constructUrl(mesh_id); - if (!http_url.empty()) - { - LLHTTPClient::getByteRange(http_url, offset, size, - new LLMeshSkinInfoResponder(mesh_id, offset, size), headers); - LLMeshRepository::sHTTPRequestCount++; - } - } +bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id) +{ + MeshHeaderInfo info; + if (!getMeshHeaderInfo(mesh_id, "skin", info)) + { + return false; } - else - { - mHeaderMutex->unlock(); + + if (info.mHeaderSize > 0 && info.mVersion <= MAX_MESH_VERSION && info.mOffset >= 0 && info.mSize > 0) + { + //check VFS for mesh skin info + if (loadInfoFromVFS(mesh_id, info, boost::bind(&LLMeshRepoThread::skinInfoReceived, this, _1, _2, _3 ))) + return true; + + //reading from VFS failed for whatever reason, fetch from sim + AIHTTPHeaders headers("Accept", "application/octet-stream"); + + std::string http_url = constructUrl(mesh_id); + if (!http_url.empty()) + { + if (!LLHTTPClient::getByteRange(http_url, headers, info.mOffset, info.mSize, + new LLMeshSkinInfoResponder(mesh_id, info.mOffset, info.mSize))) + return false; + LLMeshRepository::sHTTPRequestCount++; + } } //early out was not hit, effectively fetched return true; } -//return false if failed to get header bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id) -{ //protected by mMutex - mHeaderMutex->lock(); - - if (mMeshHeader.find(mesh_id) == mMeshHeader.end()) +{ + MeshHeaderInfo info; + if (!getMeshHeaderInfo(mesh_id, "physics_convex", info)) { - // We have no header info for this mesh, try again later. - mHeaderMutex->unlock(); return false; } - U32 header_size = mMeshHeaderSize[mesh_id]; - - if (header_size > 0) + if (info.mHeaderSize > 0 && info.mVersion <= MAX_MESH_VERSION && info.mOffset >= 0 && info.mSize > 0) { - S32 version = mMeshHeader[mesh_id]["version"].asInteger(); - S32 offset = header_size + mMeshHeader[mesh_id]["physics_convex"]["offset"].asInteger(); - S32 size = mMeshHeader[mesh_id]["physics_convex"]["size"].asInteger(); - - mHeaderMutex->unlock(); - - if (version <= MAX_MESH_VERSION && offset >= 0 && size > 0) - { - //check VFS for mesh skin info - LLVFile file(gVFS, mesh_id, LLAssetType::AT_MESH); - if (file.getSize() >= offset+size) - { - LLMeshRepository::sCacheBytesRead += size; - file.seek(offset); - U8* buffer = new U8[size]; - file.read(buffer, size); - - //make sure buffer isn't all 0's (reserved block but not written) - bool zero = true; - for (S32 i = 0; i < llmin(size, 1024) && zero; ++i) - { - zero = buffer[i] > 0 ? false : true; - } - - if (!zero) - { //attempt to parse - if (decompositionReceived(mesh_id, buffer, size)) - { - delete[] buffer; - return true; - } - } + if (loadInfoFromVFS(mesh_id, info, boost::bind(&LLMeshRepoThread::decompositionReceived, this, _1, _2, _3 ))) + return true; - delete[] buffer; - } + //reading from VFS failed for whatever reason, fetch from sim + AIHTTPHeaders headers("Accept", "application/octet-stream"); - //reading from VFS failed for whatever reason, fetch from sim - AIHTTPHeaders headers("Accept", "application/octet-stream"); - - std::string http_url = constructUrl(mesh_id); - if (!http_url.empty()) - { - // This might throw AICurlNoEasyHandle. - LLHTTPClient::getByteRange(http_url, offset, size, - new LLMeshDecompositionResponder(mesh_id, offset, size), headers); - LLMeshRepository::sHTTPRequestCount++; - } + std::string http_url = constructUrl(mesh_id); + if (!http_url.empty()) + { + if (!LLHTTPClient::getByteRange(http_url, headers, info.mOffset, info.mSize, + new LLMeshDecompositionResponder(mesh_id, info.mOffset, info.mSize))) + return false; + LLMeshRepository::sHTTPRequestCount++; } } - else - { - mHeaderMutex->unlock(); - } //early out was not hit, effectively fetched return true; } -//return false if failed to get header bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id) -{ //protected by mMutex - mHeaderMutex->lock(); - - if (mMeshHeader.find(mesh_id) == mMeshHeader.end()) +{ + MeshHeaderInfo info; + if (!getMeshHeaderInfo(mesh_id, "physics_mesh", info)) { - // We have no header info for this mesh, retry later. - mHeaderMutex->unlock(); return false; } - U32 header_size = mMeshHeaderSize[mesh_id]; - - if (header_size > 0) + if (info.mHeaderSize > 0) { - S32 version = mMeshHeader[mesh_id]["version"].asInteger(); - S32 offset = header_size + mMeshHeader[mesh_id]["physics_mesh"]["offset"].asInteger(); - S32 size = mMeshHeader[mesh_id]["physics_mesh"]["size"].asInteger(); - - mHeaderMutex->unlock(); - - if (version <= MAX_MESH_VERSION && offset >= 0 && size > 0) + if (info.mVersion <= MAX_MESH_VERSION && info.mOffset >= 0 && info.mSize > 0) { - //check VFS for mesh physics shape info - LLVFile file(gVFS, mesh_id, LLAssetType::AT_MESH); - if (file.getSize() >= offset+size) - { - LLMeshRepository::sCacheBytesRead += size; - file.seek(offset); - U8* buffer = new U8[size]; - file.read(buffer, size); - - //make sure buffer isn't all 0's (reserved block but not written) - bool zero = true; - for (S32 i = 0; i < llmin(size, 1024) && zero; ++i) - { - zero = buffer[i] > 0 ? false : true; - } - - if (!zero) - { //attempt to parse - if (physicsShapeReceived(mesh_id, buffer, size)) - { - delete[] buffer; - return true; - } - } - - delete[] buffer; - } + if (loadInfoFromVFS(mesh_id, info, boost::bind(&LLMeshRepoThread::physicsShapeReceived, this, _1, _2, _3 ))) + return true; //reading from VFS failed for whatever reason, fetch from sim AIHTTPHeaders headers("Accept", "application/octet-stream"); std::string http_url = constructUrl(mesh_id); if (!http_url.empty()) - { - // This might throw AICurlNoEasyHandle. - LLHTTPClient::getByteRange(http_url, offset, size, - new LLMeshPhysicsShapeResponder(mesh_id, offset, size), headers); + { + if (!LLHTTPClient::getByteRange(http_url, headers, info.mOffset, info.mSize, + new LLMeshPhysicsShapeResponder(mesh_id, info.mOffset, info.mSize))) + return false; LLMeshRepository::sHTTPRequestCount++; } } @@ -1003,11 +943,7 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id) physicsShapeReceived(mesh_id, NULL, 0); } } - else - { - mHeaderMutex->unlock(); - } - + //early out was not hit, effectively fetched return true; } @@ -1056,14 +992,14 @@ bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params, U32& c LLMeshRepository::sCacheBytesRead += bytes; file.read(buffer, bytes); if (headerReceived(mesh_params, buffer, bytes)) - { - // Already have header, no need to retry. + { //did not do an HTTP request, return false return true; } } } //either cache entry doesn't exist or is corrupt, request header from simulator + bool retval = true; AIHTTPHeaders headers("Accept", "application/octet-stream"); std::string http_url = constructUrl(mesh_params.getSculptID()); @@ -1072,72 +1008,47 @@ bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params, U32& c //grab first 4KB if we're going to bother with a fetch. Cache will prevent future fetches if a full mesh fits //within the first 4KB //NOTE -- this will break of headers ever exceed 4KB - // This might throw AICurlNoEasyHandle. - LLHTTPClient::getByteRange(http_url, 0, 4096, new LLMeshHeaderResponder(mesh_params), headers); - LLMeshRepository::sHTTPRequestCount++; + retval = LLHTTPClient::getByteRange(http_url, headers, 0, 4096, new LLMeshHeaderResponder(mesh_params)); + if (retval) + { + LLMeshRepository::sHTTPRequestCount++; + } count++; } - return true; + return retval; } -void LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod, U32& count) -{ //protected by mMutex - mHeaderMutex->lock(); - +//return false if failed to get mesh lod. +bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod, U32& count) +{ LLUUID mesh_id = mesh_params.getSculptID(); - - U32 header_size = mMeshHeaderSize[mesh_id]; + MeshHeaderInfo info; - if (header_size > 0) + if (!getMeshHeaderInfo(mesh_id, header_lod[lod].c_str(), info)) { - S32 version = mMeshHeader[mesh_id]["version"].asInteger(); - S32 offset = header_size + mMeshHeader[mesh_id][header_lod[lod]]["offset"].asInteger(); - S32 size = mMeshHeader[mesh_id][header_lod[lod]]["size"].asInteger(); - mHeaderMutex->unlock(); - - if (version <= MAX_MESH_VERSION && offset >= 0 && size > 0) + return false; + } + + if (info.mHeaderSize > 0) + { + if(info.mVersion <= MAX_MESH_VERSION && info.mOffset >= 0 && info.mSize > 0) { - - //check VFS for mesh asset - LLVFile file(gVFS, mesh_id, LLAssetType::AT_MESH); - if (file.getSize() >= offset+size) - { - LLMeshRepository::sCacheBytesRead += size; - file.seek(offset); - U8* buffer = new U8[size]; - file.read(buffer, size); - - //make sure buffer isn't all 0's (reserved block but not written) - bool zero = true; - for (S32 i = 0; i < llmin(size, 1024) && zero; ++i) - { - zero = buffer[i] > 0 ? false : true; - } - - if (!zero) - { //attempt to parse - if (lodReceived(mesh_params, lod, buffer, size)) - { - delete[] buffer; - return; - } - } - - delete[] buffer; - } + if (loadInfoFromVFS(mesh_id, info, boost::bind(&LLMeshRepoThread::lodReceived, this, mesh_params, lod, _2, _3 ))) + return true; //reading from VFS failed for whatever reason, fetch from sim AIHTTPHeaders headers("Accept", "application/octet-stream"); std::string http_url = constructUrl(mesh_id); if (!http_url.empty()) - { - // This might throw AICurlNoEasyHandle. - LLHTTPClient::getByteRange(constructUrl(mesh_id), offset, size, - new LLMeshLODResponder(mesh_params, lod, offset, size), headers); + { + count++; + if (!LLHTTPClient::getByteRange(constructUrl(mesh_id), headers, info.mOffset, info.mSize, + new LLMeshLODResponder(mesh_params, lod, info.mOffset, info.mSize))) + return false; LLMeshRepository::sHTTPRequestCount++; - count++; + } else { @@ -1149,10 +1060,8 @@ void LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod, mUnavailableQ.push(LODRequest(mesh_params, lod)); } } - else - { - mHeaderMutex->unlock(); - } + + return true; } bool LLMeshRepoThread::headerReceived(const LLVolumeParams& mesh_params, U8* data, S32 data_size) @@ -1177,7 +1086,7 @@ bool LLMeshRepoThread::headerReceived(const LLVolumeParams& mesh_params, U8* dat if (!LLSDSerialize::fromBinary(header, stream, data_size)) { - llwarns << "Mesh header parse error. Not a valid mesh asset!" << llendl; + LL_WARNS() << "Mesh header parse error. Not a valid mesh asset!" << LL_ENDL; return false; } @@ -1185,8 +1094,8 @@ bool LLMeshRepoThread::headerReceived(const LLVolumeParams& mesh_params, U8* dat } else { - llinfos - << "Marking header as non-existent, will not retry." << llendl; + LL_INFOS() + << "Marking header as non-existent, will not retry." << LL_ENDL; header["404"] = 1; } @@ -1199,7 +1108,6 @@ bool LLMeshRepoThread::headerReceived(const LLVolumeParams& mesh_params, U8* dat mMeshHeader[mesh_id] = header; } - LLMutexLock lock(mMutex); // make sure only one thread access mPendingLOD at the same time. //check for pending requests @@ -1208,14 +1116,11 @@ bool LLMeshRepoThread::headerReceived(const LLVolumeParams& mesh_params, U8* dat { for (U32 i = 0; i < iter->second.size(); ++i) { - LODRequest req(mesh_params, iter->second[i]); - mLODReqQ.push(req); LLMeshRepository::sLODProcessing++; + gMeshRepo.mThread->pushLODRequest(mesh_params, iter->second[i], 0.f); } - - mPendingLOD.erase(iter); // FIRE-7182, only call erase if iter is really valid. + mPendingLOD.erase(iter); } - // mPendingLOD.erase(iter); // avoid crash by moving erase up. } return true; @@ -1223,16 +1128,21 @@ bool LLMeshRepoThread::headerReceived(const LLVolumeParams& mesh_params, U8* dat bool LLMeshRepoThread::lodReceived(const LLVolumeParams& mesh_params, S32 lod, U8* data, S32 data_size) { + AIStateMachine::StateTimer timer("lodReceived"); LLPointer volume = new LLVolume(mesh_params, LLVolumeLODGroup::getVolumeScaleFromDetail(lod)); std::string mesh_string((char*) data, data_size); std::istringstream stream(mesh_string); + AIStateMachine::StateTimer timer2("unpackVolumeFaces"); if (volume->unpackVolumeFaces(stream, data_size)) { + AIStateMachine::StateTimer timer("getNumFaces"); if (volume->getNumFaces() > 0) { + AIStateMachine::StateTimer timer("LoadedMesh"); LoadedMesh mesh(volume, mesh_params, lod); { + AIStateMachine::StateTimer timer("LLMutexLock"); LLMutexLock lock(mMutex); mLoadedQ.push(mesh); } @@ -1255,7 +1165,7 @@ bool LLMeshRepoThread::skinInfoReceived(const LLUUID& mesh_id, U8* data, S32 dat if (!unzip_llsd(skin, stream, data_size)) { - llwarns << "Mesh skin info parse error. Not a valid mesh asset!" << llendl; + LL_WARNS() << "Mesh skin info parse error. Not a valid mesh asset!" << LL_ENDL; return false; } } @@ -1264,8 +1174,10 @@ bool LLMeshRepoThread::skinInfoReceived(const LLUUID& mesh_id, U8* data, S32 dat LLMeshSkinInfo info(skin); info.mMeshID = mesh_id; - //llinfos<<"info pelvis offset"<lock(); mSkinInfoQ.push(info); + mSkinInfoQMutex->unlock(); } return true; @@ -1283,7 +1195,7 @@ bool LLMeshRepoThread::decompositionReceived(const LLUUID& mesh_id, U8* data, S3 if (!unzip_llsd(decomp, stream, data_size)) { - llwarns << "Mesh decomposition parse error. Not a valid mesh asset!" << llendl; + LL_WARNS() << "Mesh decomposition parse error. Not a valid mesh asset!" << LL_ENDL; return false; } } @@ -1291,7 +1203,9 @@ bool LLMeshRepoThread::decompositionReceived(const LLUUID& mesh_id, U8* data, S3 { LLModel::Decomposition* d = new LLModel::Decomposition(decomp); d->mMeshID = mesh_id; + mDecompositionQMutex->lock(); mDecompositionQ.push(d); + mDecompositionQMutex->unlock(); } return true; @@ -1350,7 +1264,9 @@ bool LLMeshRepoThread::physicsShapeReceived(const LLUUID& mesh_id, U8* data, S32 } } + mDecompositionQMutex->lock(); mDecompositionQ.push(d); + mDecompositionQMutex->unlock(); return true; } @@ -1375,6 +1291,11 @@ void LLMeshUploadThread::init(LLMeshUploadThread::instance_list& data, LLVector3 mMeshUploadTimeOut = gSavedSettings.getS32("MeshUploadTimeOut") ; } +LLMeshUploadThread::~LLMeshUploadThread() +{ + +} + LLMeshUploadThread::DecompRequest::DecompRequest(LLModel* mdl, LLModel* base_model, LLMeshUploadThread* thread) { mStage = "single_hull"; @@ -1414,7 +1335,10 @@ void LLMeshUploadThread::preStart() AIMeshUpload::AIMeshUpload(LLMeshUploadThread::instance_list& data, LLVector3& scale, bool upload_textures, bool upload_skin, bool upload_joints, std::string const& upload_url, bool do_upload, LLHandle const& fee_observer, LLHandle const& upload_observer) : - mMeshUpload(new AIStateMachineThread), mWholeModelUploadURL(upload_url) +#ifdef CWDEBUG + AIStateMachine(false), +#endif + mMeshUpload(new AIStateMachineThread(CWD_ONLY(false))), mWholeModelUploadURL(upload_url) { mMeshUpload->thread_impl().init(data, scale, upload_textures, upload_skin, upload_joints, do_upload, fee_observer, upload_observer); } @@ -1473,18 +1397,18 @@ bool LLMeshUploadThread::run() void LLMeshUploadThread::postRequest(std::string& whole_model_upload_url, AIMeshUpload* state_machine) { - if (!mDoUpload) - { - LLHTTPClient::post(mWholeModelFeeCapability, mModelData, - new LLWholeModelFeeResponder(mModelData, mFeeObserverHandle, whole_model_upload_url)/*,*/ - DEBUG_CURLIO_PARAM(debug_on), keep_alive, state_machine, AIMeshUpload_responderFinished); - } - else + if (mDoUpload) { LLHTTPClient::post(whole_model_upload_url, mBody, new LLWholeModelUploadResponder(mModelData, mUploadObserverHandle)/*,*/ DEBUG_CURLIO_PARAM(debug_off), keep_alive, state_machine, AIMeshUpload_responderFinished); } + else + { + LLHTTPClient::post(mWholeModelFeeCapability, mModelData, + new LLWholeModelFeeResponder(mModelData, mFeeObserverHandle, whole_model_upload_url)/*,*/ + DEBUG_CURLIO_PARAM(debug_on), keep_alive, state_machine, AIMeshUpload_responderFinished); + } } void dump_llsd_to_file(const LLSD& content, std::string filename) @@ -1514,9 +1438,9 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures) result["asset_type"] = "mesh"; result["inventory_type"] = "object"; result["description"] = "(No Description)"; - result["next_owner_mask"] = LLSD::Integer(LLFloaterPerms::getNextOwnerPerms()); - result["group_mask"] = LLSD::Integer(LLFloaterPerms::getGroupPerms()); - result["everyone_mask"] = LLSD::Integer(LLFloaterPerms::getEveryonePerms()); + result["next_owner_mask"] = LLSD::Integer(LLFloaterPerms::getNextOwnerPerms("Uploads")); + result["group_mask"] = LLSD::Integer(LLFloaterPerms::getGroupPerms("Uploads")); + result["everyone_mask"] = LLSD::Integer(LLFloaterPerms::getEveryonePerms("Uploads")); res["mesh_list"] = LLSD::emptyArray(); res["texture_list"] = LLSD::emptyArray(); @@ -1537,6 +1461,13 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures) { LLMeshUploadData data; data.mBaseModel = iter->first; + + if (data.mBaseModel->mSubmodelID) + { + // These are handled below to insure correct parenting order on creation + // due to map walking being based on model address (aka random) + continue; + } LLModelInstance& first_instance = *(iter->second.begin()); for (S32 i = 0; i < 5; i++) { @@ -1574,7 +1505,10 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures) data.mModel[LLModel::LOD_IMPOSTOR], decomp, mUploadSkin, - mUploadJoints); + mUploadJoints, + FALSE, + FALSE, + data.mBaseModel->mSubmodelID); data.mAssetData = ostr.str(); std::string str = ostr.str(); @@ -1608,17 +1542,27 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures) instance_entry["scale"] = ll_sd_from_vector3(scale); instance_entry["material"] = LL_MCODE_WOOD; - instance_entry["physics_shape_type"] = (U8)(LLViewerObject::PHYSICS_SHAPE_CONVEX_HULL); + instance_entry["physics_shape_type"] = data.mModel[LLModel::LOD_PHYSICS].notNull() ? (U8)(LLViewerObject::PHYSICS_SHAPE_PRIM) : (U8)(LLViewerObject::PHYSICS_SHAPE_CONVEX_HULL); instance_entry["mesh"] = mesh_index[data.mBaseModel]; + instance_entry["mesh_name"] = instance.mLabel; instance_entry["face_list"] = LLSD::emptyArray(); - S32 end = llmin((S32)data.mBaseModel->mMaterialList.size(), data.mBaseModel->getNumVolumeFaces()) ; + // We want to be able to allow more than 8 materials... + // + S32 end = llmin((S32)instance.mMaterial.size(), instance.mModel->getNumVolumeFaces()) ; + for (S32 face_num = 0; face_num < end; face_num++) { LLImportMaterial& material = instance.mMaterial[data.mBaseModel->mMaterialList[face_num]]; LLSD face_entry = LLSD::emptyMap(); - LLViewerFetchedTexture *texture = material.mDiffuseMap.get(); + + LLViewerFetchedTexture *texture = NULL; + + if (material.mDiffuseMapFilename.size()) + { + texture = FindViewerTexture(material); + } if ((texture != NULL) && (textures.find(texture) == textures.end())) @@ -1633,9 +1577,171 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures) { LLPointer upload_file = LLViewerTextureList::convertToUploadFile(texture->getSavedRawImage()); + + if (!upload_file.isNull() && upload_file->getDataSize()) + { + texture_str.write((const char*) upload_file->getData(), upload_file->getDataSize()); + } + } + } + + if (texture != NULL && + mUploadTextures && + texture_index.find(texture) == texture_index.end()) + { + texture_index[texture] = texture_num; + std::string str = texture_str.str(); + res["texture_list"][texture_num] = LLSD::Binary(str.begin(),str.end()); + texture_num++; + } + + // Subset of TextureEntry fields. + if (texture != NULL && mUploadTextures) + { + face_entry["image"] = texture_index[texture]; + face_entry["scales"] = 1.0; + face_entry["scalet"] = 1.0; + face_entry["offsets"] = 0.0; + face_entry["offsett"] = 0.0; + face_entry["imagerot"] = 0.0; + } + face_entry["diffuse_color"] = ll_sd_from_color4(material.mDiffuseColor); + face_entry["fullbright"] = material.mFullbright; + instance_entry["face_list"][face_num] = face_entry; + } + + res["instance_list"][instance_num] = instance_entry; + instance_num++; + } + } + + for (instance_map::iterator iter = mInstance.begin(); iter != mInstance.end(); ++iter) + { + LLMeshUploadData data; + data.mBaseModel = iter->first; + + if (!data.mBaseModel->mSubmodelID) + { + // These were handled above already... + // + continue; + } + + LLModelInstance& first_instance = *(iter->second.begin()); + for (S32 i = 0; i < 5; i++) + { + data.mModel[i] = first_instance.mLOD[i]; + } + + if (mesh_index.find(data.mBaseModel) == mesh_index.end()) + { + // Have not seen this model before - create a new mesh_list entry for it. + if (model_name.empty()) + { + model_name = data.mBaseModel->getName(); + } + + if (model_metric.empty()) + { + model_metric = data.mBaseModel->getMetric(); + } + + std::stringstream ostr; + + LLModel::Decomposition& decomp = + data.mModel[LLModel::LOD_PHYSICS].notNull() ? + data.mModel[LLModel::LOD_PHYSICS]->mPhysics : + data.mBaseModel->mPhysics; + + decomp.mBaseHull = mHullMap[data.mBaseModel]; + + LLSD mesh_header = LLModel::writeModel( + ostr, + data.mModel[LLModel::LOD_PHYSICS], + data.mModel[LLModel::LOD_HIGH], + data.mModel[LLModel::LOD_MEDIUM], + data.mModel[LLModel::LOD_LOW], + data.mModel[LLModel::LOD_IMPOSTOR], + decomp, + mUploadSkin, + mUploadJoints, + FALSE, + FALSE, + data.mBaseModel->mSubmodelID); + + data.mAssetData = ostr.str(); + std::string str = ostr.str(); + + res["mesh_list"][mesh_num] = LLSD::Binary(str.begin(),str.end()); + mesh_index[data.mBaseModel] = mesh_num; + mesh_num++; + } + + // For all instances that use this model + for (instance_list::iterator instance_iter = iter->second.begin(); + instance_iter != iter->second.end(); + ++instance_iter) + { + + LLModelInstance& instance = *instance_iter; + + LLSD instance_entry; + + for (S32 i = 0; i < 5; i++) + { + data.mModel[i] = instance.mLOD[i]; + } + + LLVector3 pos, scale; + LLQuaternion rot; + LLMatrix4 transformation = instance.mTransform; + decomposeMeshMatrix(transformation,pos,rot,scale); + instance_entry["position"] = ll_sd_from_vector3(pos); + instance_entry["rotation"] = ll_sd_from_quaternion(rot); + instance_entry["scale"] = ll_sd_from_vector3(scale); + + instance_entry["material"] = LL_MCODE_WOOD; + instance_entry["physics_shape_type"] = (U8)(LLViewerObject::PHYSICS_SHAPE_NONE); + instance_entry["mesh"] = mesh_index[data.mBaseModel]; + + instance_entry["face_list"] = LLSD::emptyArray(); + + // We want to be able to allow more than 8 materials... + // + S32 end = llmin((S32)instance.mMaterial.size(), instance.mModel->getNumVolumeFaces()) ; + + for (S32 face_num = 0; face_num < end; face_num++) + { + LLImportMaterial& material = instance.mMaterial[data.mBaseModel->mMaterialList[face_num]]; + LLSD face_entry = LLSD::emptyMap(); + + LLViewerFetchedTexture *texture = NULL; + + if (material.mDiffuseMapFilename.size()) + { + texture = FindViewerTexture(material); + } + + if ((texture != NULL) && + (textures.find(texture) == textures.end())) + { + textures.insert(texture); + } + + std::stringstream texture_str; + if (texture != NULL && include_textures && mUploadTextures) + { + if(texture->hasSavedRawImage()) + { + LLPointer upload_file = + LLViewerTextureList::convertToUploadFile(texture->getSavedRawImage()); + + if (!upload_file.isNull() && upload_file->getDataSize()) + { texture_str.write((const char*) upload_file->getData(), upload_file->getDataSize()); } } + } if (texture != NULL && mUploadTextures && @@ -1732,8 +1838,14 @@ void LLMeshUploadThread::generateHulls() } } -void LLMeshRepoThread::notifyLoadedMeshes() -{//called via gMeshRepo.notifyLoadedMeshes(). mMutex already locked + +void LLMeshRepoThread::notifyLoadedMeshes() +{ + if (!mMutex) + { + return; + } + while (!mLoadedQ.empty()) { mMutex->lock(); @@ -1764,14 +1876,22 @@ void LLMeshRepoThread::notifyLoadedMeshes() while (!mSkinInfoQ.empty()) { - gMeshRepo.notifySkinInfoReceived(mSkinInfoQ.front()); + mSkinInfoQMutex->lock(); + auto req = mSkinInfoQ.front(); mSkinInfoQ.pop(); + mSkinInfoQMutex->unlock(); + + gMeshRepo.notifySkinInfoReceived(req); } while (!mDecompositionQ.empty()) { - gMeshRepo.notifyDecompositionReceived(mDecompositionQ.front()); + mDecompositionQMutex->lock(); + auto req = mDecompositionQ.front(); mDecompositionQ.pop(); + mDecompositionQMutex->unlock(); + + gMeshRepo.notifyDecompositionReceived(req); } } @@ -1795,7 +1915,7 @@ S32 LLMeshRepository::getActualMeshLOD(LLSD& header, S32 lod) { lod = llclamp(lod, 0, 3); - S32 version = header["version"]; + S32 version = header["version"].asInteger(); if (header.has("404") || version > MAX_MESH_VERSION) { @@ -1851,30 +1971,42 @@ void LLMeshRepository::cacheOutgoingMesh(LLMeshUploadData& data, LLSD& header) } -void LLMeshLODResponder::completedRaw(U32 status, const std::string& reason, - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) +void LLMeshLODResponder::retry() +{ + AIStateMachine::StateTimer timer("loadMeshLOD"); + LLMeshRepository::sHTTPRetryCount++; + gMeshRepo.mThread->loadMeshLOD(mMeshParams, mLOD); +} + +void LLMeshLODResponder::completedRaw(LLChannelDescriptors const& channels, + LLIOPipe::buffer_ptr_t const& buffer) { mProcessed = true; + // thread could have already be destroyed during logout + if( !gMeshRepo.mThread ) + { + return; + } + S32 data_size = buffer->countAfter(channels.in(), NULL); - if (status < 200 || status >= 400) + if (mStatus < 200 || mStatus >= 400) { - llwarns << status << ": " << reason << llendl; + LL_WARNS() << mStatus << ": " << mReason << LL_ENDL; } if (data_size < (S32)mRequestedBytes) { - if (is_internal_http_error_that_warrants_a_retry(status) || status == HTTP_SERVICE_UNAVAILABLE) + if (is_internal_http_error_that_warrants_a_retry(mStatus) || mStatus == HTTP_SERVICE_UNAVAILABLE) { //timeout or service unavailable, try again - llwarns << "Timeout or service unavailable, retrying." << llendl; - LLMeshRepository::sHTTPRetryCount++; - gMeshRepo.mThread->loadMeshLOD(mMeshParams, mLOD); + LL_WARNS() << "Timeout or service unavailable, retrying." << LL_ENDL; + retry(); } else { - llwarns << "Unhandled status " << status << llendl; + llassert(is_internal_http_error_that_warrants_a_retry(mStatus) || mStatus == HTTP_SERVICE_UNAVAILABLE); //intentionally trigger a breakpoint + LL_WARNS() << "Unhandled status " << mStatus << LL_ENDL; } return; } @@ -1885,12 +2017,14 @@ void LLMeshLODResponder::completedRaw(U32 status, const std::string& reason, if (data_size > 0) { + AIStateMachine::StateTimer timer("readAfter"); data = new U8[data_size]; buffer->readAfter(channels.in(), NULL, data, data_size); } if (gMeshRepo.mThread->lodReceived(mMeshParams, mLOD, data, data_size)) { + AIStateMachine::StateTimer timer("FileOpen"); //good fetch from sim, write to VFS for caching LLVFile file(gVFS, mMeshParams.getSculptID(), LLAssetType::AT_MESH, LLVFile::WRITE); @@ -1899,6 +2033,7 @@ void LLMeshLODResponder::completedRaw(U32 status, const std::string& reason, if (file.getSize() >= offset+size) { + AIStateMachine::StateTimer timer("WriteData"); file.seek(offset); file.write(data, size); LLMeshRepository::sCacheBytesWritten += size; @@ -1908,30 +2043,41 @@ void LLMeshLODResponder::completedRaw(U32 status, const std::string& reason, delete [] data; } -void LLMeshSkinInfoResponder::completedRaw(U32 status, const std::string& reason, - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) +void LLMeshSkinInfoResponder::retry() +{ + LLMeshRepository::sHTTPRetryCount++; + gMeshRepo.mThread->loadMeshSkinInfo(mMeshID); +} + +void LLMeshSkinInfoResponder::completedRaw(LLChannelDescriptors const& channels, + LLIOPipe::buffer_ptr_t const& buffer) { mProcessed = true; + // thread could have already be destroyed during logout + if( !gMeshRepo.mThread ) + { + return; + } + S32 data_size = buffer->countAfter(channels.in(), NULL); - if (status < 200 || status >= 400) + if (mStatus < 200 || mStatus >= 400) { - llwarns << status << ": " << reason << llendl; + LL_WARNS() << mStatus << ": " << mReason << LL_ENDL; } if (data_size < (S32)mRequestedBytes) { - if (is_internal_http_error_that_warrants_a_retry(status) || status == HTTP_SERVICE_UNAVAILABLE) + if (is_internal_http_error_that_warrants_a_retry(mStatus) || mStatus == HTTP_SERVICE_UNAVAILABLE) { //timeout or service unavailable, try again - llwarns << "Timeout or service unavailable, retrying." << llendl; - LLMeshRepository::sHTTPRetryCount++; - gMeshRepo.mThread->loadMeshSkinInfo(mMeshID); + LL_WARNS() << "Timeout or service unavailable, retrying loadMeshSkinInfo() for " << mMeshID << LL_ENDL; + retry(); } else { - llwarns << "Unhandled status " << status << llendl; + llassert(is_internal_http_error_that_warrants_a_retry(mStatus) || mStatus == HTTP_SERVICE_UNAVAILABLE); //intentionally trigger a breakpoint + LL_WARNS() << "Unhandled status " << mStatus << LL_ENDL; } return; } @@ -1965,30 +2111,40 @@ void LLMeshSkinInfoResponder::completedRaw(U32 status, const std::string& reason delete [] data; } -void LLMeshDecompositionResponder::completedRaw(U32 status, const std::string& reason, - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) +void LLMeshDecompositionResponder::retry() +{ + LLMeshRepository::sHTTPRetryCount++; + gMeshRepo.mThread->loadMeshDecomposition(mMeshID); +} + +void LLMeshDecompositionResponder::completedRaw(LLChannelDescriptors const& channels, + LLIOPipe::buffer_ptr_t const& buffer) { mProcessed = true; + if( !gMeshRepo.mThread ) + { + return; + } + S32 data_size = buffer->countAfter(channels.in(), NULL); - if (status < 200 || status >= 400) + if (mStatus < 200 || mStatus >= 400) { - llwarns << status << ": " << reason << llendl; + LL_WARNS() << mStatus << ": " << mReason << LL_ENDL; } if (data_size < (S32)mRequestedBytes) { - if (is_internal_http_error_that_warrants_a_retry(status) || status == HTTP_SERVICE_UNAVAILABLE) + if (is_internal_http_error_that_warrants_a_retry(mStatus) || mStatus == HTTP_SERVICE_UNAVAILABLE) { //timeout or service unavailable, try again - llwarns << "Timeout or service unavailable, retrying." << llendl; - LLMeshRepository::sHTTPRetryCount++; - gMeshRepo.mThread->loadMeshDecomposition(mMeshID); + LL_WARNS() << "Timeout or service unavailable, retrying loadMeshDecomposition() for " << mMeshID << LL_ENDL; + retry(); } else { - llwarns << "Unhandled status " << status << llendl; + llassert(is_internal_http_error_that_warrants_a_retry(mStatus) || mStatus == HTTP_SERVICE_UNAVAILABLE); //intentionally trigger a breakpoint + LL_WARNS() << "Unhandled status " << mStatus << LL_ENDL; } return; } @@ -2022,30 +2178,40 @@ void LLMeshDecompositionResponder::completedRaw(U32 status, const std::string& r delete [] data; } -void LLMeshPhysicsShapeResponder::completedRaw(U32 status, const std::string& reason, - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) +void LLMeshPhysicsShapeResponder::retry() +{ + LLMeshRepository::sHTTPRetryCount++; + gMeshRepo.mThread->loadMeshPhysicsShape(mMeshID); +} +void LLMeshPhysicsShapeResponder::completedRaw(LLChannelDescriptors const& channels, + LLIOPipe::buffer_ptr_t const& buffer) { mProcessed = true; + // thread could have already be destroyed during logout + if( !gMeshRepo.mThread ) + { + return; + } + S32 data_size = buffer->countAfter(channels.in(), NULL); - if (status < 200 || status >= 400) + if (mStatus < 200 || mStatus >= 400) { - llwarns << status << ": " << reason << llendl; + LL_WARNS() << mStatus << ": " << mReason << LL_ENDL; } if (data_size < (S32)mRequestedBytes) { - if (is_internal_http_error_that_warrants_a_retry(status) || status == HTTP_SERVICE_UNAVAILABLE) + if (is_internal_http_error_that_warrants_a_retry(mStatus) || mStatus == HTTP_SERVICE_UNAVAILABLE) { //timeout or service unavailable, try again - llwarns << "Timeout or service unavailable, retrying." << llendl; - LLMeshRepository::sHTTPRetryCount++; - gMeshRepo.mThread->loadMeshPhysicsShape(mMeshID); + LL_WARNS() << "Timeout or service unavailable, retrying loadMeshPhysicsShape() for " << mMeshID << LL_ENDL; + retry(); } else { - llwarns << "Unhandled status " << status << llendl; + llassert(is_internal_http_error_that_warrants_a_retry(mStatus) || mStatus == HTTP_SERVICE_UNAVAILABLE); //intentionally trigger a breakpoint + LL_WARNS() << "Unhandled status " << mStatus << LL_ENDL; } return; } @@ -2079,63 +2245,82 @@ void LLMeshPhysicsShapeResponder::completedRaw(U32 status, const std::string& re delete [] data; } -void LLMeshHeaderResponder::completedRaw(U32 status, const std::string& reason, - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) +void LLMeshHeaderResponder::retry() +{ + AIStateMachine::StateTimer timer("Retry"); + LLMeshRepository::sHTTPRetryCount++; + LLMutexLock lock(gMeshRepo.mThread->mMutex); + gMeshRepo.mThread->pushHeaderRequest(mMeshParams, 10.f); +} + +void LLMeshHeaderResponder::completedRaw(LLChannelDescriptors const& channels, + LLIOPipe::buffer_ptr_t const& buffer) { + //LL_INFOS() << mMeshParams.getSculptID() << " Status: " << mStatus << LL_ENDL; mProcessed = true; - if (status < 200 || status >= 400) + // thread could have already be destroyed during logout + if( !gMeshRepo.mThread ) + { + return; + } + + if (mStatus < 200 || mStatus >= 400) { //llwarns // << "Header responder failed with status: " - // << status << ": " << reason << llendl; + // << mStatus << ": " << mReason << LL_ENDL; - // HTTP_SERVICE_UNAVAILABLE (503) or HTTP_INTERNAL_ERROR_*'s. + // 503 (service unavailable) or HTTP_INTERNAL_ERROR_*'s. // can be due to server load and can be retried // TODO*: Add maximum retry logic, exponential backoff // and (somewhat more optional than the others) retries // again after some set period of time - if (is_internal_http_error_that_warrants_a_retry(status) || status == HTTP_SERVICE_UNAVAILABLE) - { //retry - llwarns << "Timeout or service unavailable, retrying." << llendl; - LLMeshRepository::sHTTPRetryCount++; - LLMeshRepoThread::HeaderRequest req(mMeshParams); - LLMutexLock lock(gMeshRepo.mThread->mMutex); - gMeshRepo.mThread->mHeaderReqQ.push(req); + llassert(mStatus == HTTP_NOT_FOUND || mStatus == HTTP_SERVICE_UNAVAILABLE || mStatus == HTTP_REQUEST_TIME_OUT || is_internal_http_error_that_warrants_a_retry(mStatus)); + + if (is_internal_http_error_that_warrants_a_retry(mStatus) || mStatus == HTTP_SERVICE_UNAVAILABLE) + { //retry + LL_WARNS() << "Timeout or service unavailable, retrying." << LL_ENDL; + retry(); return; } else { - llwarns << "Unhandled status." << llendl; + LL_WARNS() << "Unhandled status: " << mStatus << LL_ENDL; } } S32 data_size = buffer->countAfter(channels.in(), NULL); - U8* data = NULL; + static const U32 BUFF_MAX_STATIC_SIZE = 16384; //If we exceed this size just bump the vector back to BUFF_MAX_STATIC_SIZE after we're done. + static std::vector data(BUFF_MAX_STATIC_SIZE); + if (data_size > (S32)data.size()) + data.resize(data_size); + else + memset(&data[0] + data_size, 0, data.size() - data_size); if (data_size > 0) { - data = new U8[data_size]; - buffer->readAfter(channels.in(), NULL, data, data_size); + AIStateMachine::StateTimer timer("readAfter"); + buffer->readAfter(channels.in(), NULL, &data[0], data_size); } LLMeshRepository::sBytesReceived += llmin(data_size, 4096); - bool success = gMeshRepo.mThread->headerReceived(mMeshParams, data, data_size); + AIStateMachine::StateTimer timer("headerReceived"); + bool success = gMeshRepo.mThread->headerReceived(mMeshParams, &data[0], data_size); llassert(success); if (!success) { - llwarns + LL_WARNS() << "Unable to parse mesh header: " - << status << ": " << reason << llendl; + << mStatus << ": " << mReason << LL_ENDL; } - else if (data && data_size > 0) + else if (data_size > 0) { //header was successfully retrieved from sim, cache in vfs LLUUID mesh_id = mMeshParams.getSculptID(); @@ -2167,40 +2352,41 @@ void LLMeshHeaderResponder::completedRaw(U32 status, const std::string& reason, //only allocate as much space in the VFS as is needed for the local cache data_size = llmin(data_size, bytes); + AIStateMachine::StateTimer timer("FileOpen"); LLVFile file(gVFS, mesh_id, LLAssetType::AT_MESH, LLVFile::WRITE); if (file.getMaxSize() >= bytes || file.setMaxSize(bytes)) { LLMeshRepository::sCacheBytesWritten += data_size; - file.write((const U8*) data, data_size); - - //zero out the rest of the file - U8 block[4096]; - memset(block, 0, 4096); - - while (bytes-file.tell() > 4096) + AIStateMachine::StateTimer timer("WriteData"); + S32 bytes_remaining = bytes; + while (bytes_remaining > 0) { - file.write(block, 4096); - } - - S32 remaining = bytes-file.tell(); - - if (remaining > 0) - { - file.write(block, remaining); + const S32 bytes_to_write = llmin(bytes_remaining, data_size); + file.write(&data[0], bytes_to_write); + if (bytes_remaining == bytes && bytes_to_write < bytes_remaining) + { + memset(&data[0], 0, data.size()); + } + bytes_remaining -= llmin(bytes_remaining, bytes_to_write); } } } } - delete [] data; + if (data.size() > BUFF_MAX_STATIC_SIZE) + { + std::vector().swap(data); + data.resize(BUFF_MAX_STATIC_SIZE); + } } LLMeshRepository::LLMeshRepository() : mMeshMutex(NULL), mMeshThreadCount(0), - mThread(NULL) + mThread(NULL), + mDecompThread(nullptr) { } @@ -2227,7 +2413,7 @@ void LLMeshRepository::init() void LLMeshRepository::shutdown() { - llinfos << "Shutting down mesh repository." << llendl; + LL_INFOS(LOG_MESH) << "Shutting down mesh repository." << LL_ENDL; mThread->mSignal->signal(); @@ -2241,7 +2427,7 @@ void LLMeshRepository::shutdown() delete mMeshMutex; mMeshMutex = NULL; - llinfos << "Shutting down decomposition system." << llendl; + LL_INFOS(LOG_MESH) << "Shutting down decomposition system." << LL_ENDL; if (mDecompThread) { @@ -2253,6 +2439,17 @@ void LLMeshRepository::shutdown() LLConvexDecomposition::quitSystem(); } +void LLMeshRepository::unregisterMesh(LLVOVolume* vobj) +{ + for (auto& lod : mLoadingMeshes) + { + for (auto& param : lod) + { + vector_replace_with_last(param.second, vobj); + } + } +} + S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_params, S32 detail, S32 last_lod) { if (detail < 0 || detail > 4) @@ -2266,12 +2463,15 @@ S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_para mesh_load_map::iterator iter = mLoadingMeshes[detail].find(mesh_params); if (iter != mLoadingMeshes[detail].end()) { //request pending for this mesh, append volume id to list - iter->second.insert(vobj->getID()); + auto it = std::find(iter->second.begin(), iter->second.end(), vobj); + if (it == iter->second.end()) { + iter->second.push_back(vobj); + } } else { //first request for this mesh - mLoadingMeshes[detail][mesh_params].insert(vobj->getID()); + mLoadingMeshes[detail][mesh_params].push_back(vobj); mPendingRequests.push_back(LLMeshRepoThread::LODRequest(mesh_params, detail)); LLMeshRepository::sLODPending++; } @@ -2397,9 +2597,8 @@ void LLMeshRepository::notifyLoadedMeshes() //call completed callbacks on finished decompositions mDecompThread->notifyCompleted(); - if (!mThread->mSignal->tryLock()) - { - // Curl thread is churning, wait for it to go idle. + if (!mThread->mSignal->try_lock()) + { //curl thread is churning, wait for it to go idle return; } mThread->mSignal->unlock(); @@ -2411,8 +2610,12 @@ void LLMeshRepository::notifyLoadedMeshes() if (gAgent.getRegion()->getName() != region_name && gAgent.getRegion()->capabilitiesReceived()) { region_name = gAgent.getRegion()->getName(); - - mGetMeshCapability = gAgent.getRegion()->getCapability("GetMesh"); + const std::string mesh_cap(gAgent.getRegion()->getViewerAssetUrl()); + mGetMeshCapability = !mesh_cap.empty() ? mesh_cap : gAgent.getRegion()->getCapability("GetMesh2"); + if (mGetMeshCapability.empty()) + { + mGetMeshCapability = gAgent.getRegion()->getCapability("GetMesh"); + } } } @@ -2429,34 +2632,30 @@ void LLMeshRepository::notifyLoadedMeshes() S32 push_count = LLMeshRepoThread::sMaxConcurrentRequests-(LLMeshRepoThread::sActiveHeaderRequests+LLMeshRepoThread::sActiveLODRequests); + push_count = llmin(push_count, (S32)mPendingRequests.size()); + if (push_count > 0) { //calculate "score" for pending requests //create score map - std::map score_map; + boost::unordered_map score_map; - for (U32 i = 0; i < 4; ++i) + for (auto& lod : mLoadingMeshes) { - for (mesh_load_map::iterator iter = mLoadingMeshes[i].begin(); iter != mLoadingMeshes[i].end(); ++iter) + for (auto& param : lod) { F32 max_score = 0.f; - for (std::set::iterator obj_iter = iter->second.begin(); obj_iter != iter->second.end(); ++obj_iter) + for (auto& vobj : param.second) { - LLViewerObject* object = gObjectList.findObject(*obj_iter); - - if (object) + if (LLDrawable* drawable = vobj->mDrawable) { - LLDrawable* drawable = object->mDrawable; - if (drawable) - { - F32 cur_score = drawable->getRadius()/llmax(drawable->mDistanceWRTCamera, 1.f); - max_score = llmax(max_score, cur_score); - } + F32 cur_score = drawable->getRadius() / llmax(drawable->mDistanceWRTCamera, 1.f); + max_score = llmax(max_score, cur_score); } } - score_map[iter->first.getSculptID()] = max_score; + score_map[param.first.getSculptID()] = max_score; } } @@ -2467,7 +2666,8 @@ void LLMeshRepository::notifyLoadedMeshes() } //sort by "score" - std::sort(mPendingRequests.begin(), mPendingRequests.end(), LLMeshRepoThread::CompareScoreGreater()); + std::partial_sort(mPendingRequests.begin(), mPendingRequests.begin() + push_count, + mPendingRequests.end(), LLMeshRepoThread::CompareScoreGreater()); while (!mPendingRequests.empty() && push_count > 0) { @@ -2508,12 +2708,12 @@ void LLMeshRepository::notifyLoadedMeshes() void LLMeshRepository::notifySkinInfoReceived(LLMeshSkinInfo& info) { - mSkinMap[info.mMeshID] = info; + mSkinMap.insert_or_assign(info.mMeshID, info); skin_load_map::iterator iter = mLoadingSkins.find(info.mMeshID); if (iter != mLoadingSkins.end()) { - for (std::set::iterator obj_id = iter->second.begin(); obj_id != iter->second.end(); ++obj_id) + for (auto obj_id = iter->second.begin(); obj_id != iter->second.end(); ++obj_id) { LLVOVolume* vobj = (LLVOVolume*) gObjectList.findObject(*obj_id); if (vobj) @@ -2521,9 +2721,8 @@ void LLMeshRepository::notifySkinInfoReceived(LLMeshSkinInfo& info) vobj->notifyMeshLoaded(); } } + mLoadingSkins.erase(info.mMeshID); } - - mLoadingSkins.erase(info.mMeshID); } void LLMeshRepository::notifyDecompositionReceived(LLModel::Decomposition* decomp) @@ -2532,18 +2731,18 @@ void LLMeshRepository::notifyDecompositionReceived(LLModel::Decomposition* decom if (iter == mDecompositionMap.end()) { //just insert decomp into map mDecompositionMap[decomp->mMeshID] = decomp; + mLoadingDecompositions.erase(decomp->mMeshID); } else - { //merge decomp with existing entry + { //merge decomp with existing entry iter->second->merge(decomp); + mLoadingDecompositions.erase(decomp->mMeshID); delete decomp; } - - mLoadingDecompositions.erase(decomp->mMeshID); } void LLMeshRepository::notifyMeshLoaded(const LLVolumeParams& mesh_params, LLVolume* volume) -{ //called from main thread +{ //called from main thread S32 detail = LLVolumeLODGroup::getVolumeDetailFromScale(volume->getDetail()); //get list of objects waiting to be notified this mesh is loaded @@ -2554,7 +2753,8 @@ void LLMeshRepository::notifyMeshLoaded(const LLVolumeParams& mesh_params, LLVol //make sure target volume is still valid if (volume->getNumVolumeFaces() <= 0) { - llwarns << "Mesh loading returned empty volume." << llendl; + LL_WARNS(LOG_MESH) << "Mesh loading returned empty volume. ID: " << mesh_params.getSculptID() + << LL_ENDL; } { //update system volume @@ -2567,18 +2767,15 @@ void LLMeshRepository::notifyMeshLoaded(const LLVolumeParams& mesh_params, LLVol } else { - llwarns << "Couldn't find system volume for given mesh." << llendl; + LL_WARNS(LOG_MESH) << "Couldn't find system volume for mesh " << mesh_params.getSculptID() + << LL_ENDL; } } //notify waiting LLVOVolume instances that their requested mesh is available - for (std::set::iterator vobj_iter = obj_iter->second.begin(); vobj_iter != obj_iter->second.end(); ++vobj_iter) + for (auto& vobj : obj_iter->second) { - LLVOVolume* vobj = (LLVOVolume*) gObjectList.findObject(*vobj_iter); - if (vobj) - { - vobj->notifyMeshLoaded(); - } + vobj->notifyMeshLoaded(); } mLoadingMeshes[detail].erase(mesh_params); @@ -2594,19 +2791,14 @@ void LLMeshRepository::notifyMeshUnavailable(const LLVolumeParams& mesh_params, if (obj_iter != mLoadingMeshes[lod].end()) { - for (std::set::iterator vobj_iter = obj_iter->second.begin(); vobj_iter != obj_iter->second.end(); ++vobj_iter) + for (auto& vobj : obj_iter->second) { - LLVOVolume* vobj = (LLVOVolume*) gObjectList.findObject(*vobj_iter); - if (vobj) - { - LLVolume* obj_volume = vobj->getVolume(); - - if (obj_volume && - obj_volume->getDetail() == detail && - obj_volume->getParams() == mesh_params) - { //should force volume to find most appropriate LOD + LLVolume* obj_volume = vobj->getVolume(); + if (obj_volume && + obj_volume->getDetail() == detail && + obj_volume->getParams() == mesh_params) + { //should force volume to find most appropriate LOD vobj->setVolume(obj_volume->getParams(), lod); - } } } @@ -2623,8 +2815,8 @@ const LLMeshSkinInfo* LLMeshRepository::getSkinInfo(const LLUUID& mesh_id, const { if (mesh_id.notNull()) { - skin_map::iterator iter = mSkinMap.find(mesh_id); - if (iter != mSkinMap.end()) + const auto iter = mSkinMap.find(mesh_id); + if (iter != mSkinMap.cend()) { return &(iter->second); } @@ -2661,7 +2853,7 @@ void LLMeshRepository::fetchPhysicsShape(const LLUUID& mesh_id) { LLMutexLock lock(mMeshMutex); //add volume to list of loading meshes - std::set::iterator iter = mLoadingPhysicsShapes.find(mesh_id); + auto iter = mLoadingPhysicsShapes.find(mesh_id); if (iter == mLoadingPhysicsShapes.end()) { //no request pending for this skin info mLoadingPhysicsShapes.insert(mesh_id); @@ -2689,7 +2881,7 @@ LLModel::Decomposition* LLMeshRepository::getDecomposition(const LLUUID& mesh_id { LLMutexLock lock(mMeshMutex); //add volume to list of loading meshes - std::set::iterator iter = mLoadingDecompositions.find(mesh_id); + auto iter = mLoadingDecompositions.find(mesh_id); if (iter == mLoadingDecompositions.end()) { //no request pending for this skin info mLoadingDecompositions.insert(mesh_id); @@ -2746,7 +2938,7 @@ LLSD& LLMeshRepoThread::getMeshHeader(const LLUUID& mesh_id) { LLMutexLock lock(mHeaderMutex); mesh_header_map::iterator iter = mMeshHeader.find(mesh_id); - if (iter != mMeshHeader.end()) + if (iter != mMeshHeader.end() && mMeshHeaderSize[mesh_id] > 0) { return iter->second; } @@ -2762,19 +2954,21 @@ void LLMeshRepository::uploadModel(std::vector& data, LLVector3 { if (do_upload && upload_url.empty()) { - llinfos << "unable to upload, fee request failed" << llendl; + LL_INFOS() << "unable to upload, fee request failed" << LL_ENDL; return; } - AIMeshUpload* uploader = new AIMeshUpload(data, scale, upload_textures, upload_skin, upload_joints, upload_url, do_upload, fee_observer, upload_observer); - uploader->run(NULL, 0, false, true, &gMainThreadEngine); + AIMeshUpload* thread = new AIMeshUpload(data, scale, upload_textures, upload_skin, upload_joints, upload_url, + do_upload, fee_observer, upload_observer); + thread->run(NULL, 0, false, true, &gMainThreadEngine); } S32 LLMeshRepository::getMeshSize(const LLUUID& mesh_id, S32 lod) { - if (mThread) + if (mThread && mesh_id.notNull() && LLPrimitive::NO_LOD != lod) { + LLMutexLock lock(mThread->mHeaderMutex); LLMeshRepoThread::mesh_header_map::iterator iter = mThread->mMeshHeader.find(mesh_id); - if (iter != mThread->mMeshHeader.end()) + if (iter != mThread->mMeshHeader.end() && mThread->mMeshHeaderSize[mesh_id] > 0) { LLSD& header = iter->second; @@ -2833,37 +3027,6 @@ void LLMeshUploadThread::decomposeMeshMatrix(LLMatrix4& transformation, result_rot = quat_rotation; } -bool LLImportMaterial::operator<(const LLImportMaterial &rhs) const -{ - if (mDiffuseMap != rhs.mDiffuseMap) - { - return mDiffuseMap < rhs.mDiffuseMap; - } - - if (mDiffuseMapFilename != rhs.mDiffuseMapFilename) - { - return mDiffuseMapFilename < rhs.mDiffuseMapFilename; - } - - if (mDiffuseMapLabel != rhs.mDiffuseMapLabel) - { - return mDiffuseMapLabel < rhs.mDiffuseMapLabel; - } - - if (mDiffuseColor != rhs.mDiffuseColor) - { - return mDiffuseColor < rhs.mDiffuseColor; - } - - if (mBinding != rhs.mBinding) - { - return mBinding < rhs.mBinding; - } - - return mFullbright < rhs.mFullbright; -} - - void LLMeshRepository::updateInventory(inventory_data data) { LLMutexLock lock(mMeshMutex); @@ -2878,9 +3041,88 @@ void LLMeshRepository::uploadError(LLSD& args) mUploadErrorQ.push(args); } +F32 LLMeshRepository::getEstTrianglesMax(LLUUID mesh_id) +{ + LLMeshCostData costs; + if (getCostData(mesh_id, costs)) + { + return costs.getEstTrisMax(); + } + else + { + return 0.f; + } +} + +F32 LLMeshRepository::getEstTrianglesStreamingCost(LLUUID mesh_id) +{ + LLMeshCostData costs; + if (getCostData(mesh_id, costs)) + { + return costs.getEstTrisForStreamingCost(); + } + else + { + return 0.f; + } +} + +// FIXME replace with calc based on LLMeshCostData +F32 LLMeshRepository::getStreamingCostLegacy(LLUUID mesh_id, F32 radius, S32* bytes, S32* bytes_visible, S32 lod, F32 *unscaled_value) +{ + F32 result = 0.f; + if (mThread && mesh_id.notNull()) + { + LLMutexLock lock(mThread->mHeaderMutex); + LLMeshRepoThread::mesh_header_map::iterator iter = mThread->mMeshHeader.find(mesh_id); + if (iter != mThread->mMeshHeader.end() && mThread->mMeshHeaderSize[mesh_id] > 0) + { + result = getStreamingCostLegacy(iter->second, radius, bytes, bytes_visible, lod, unscaled_value); + } + } + if (result > 0.f) + { + LLMeshCostData data; + if (getCostData(mesh_id, data)) + { + F32 ref_streaming_cost = data.getRadiusBasedStreamingCost(radius); + F32 ref_weighted_tris = data.getRadiusWeightedTris(radius); + if (!is_approx_equal(ref_streaming_cost,result)) + { + LL_WARNS() << mesh_id << "streaming mismatch " << result << " " << ref_streaming_cost << LL_ENDL; + } + if (unscaled_value && !is_approx_equal(ref_weighted_tris,*unscaled_value)) + { + LL_WARNS() << mesh_id << "weighted_tris mismatch " << *unscaled_value << " " << ref_weighted_tris << LL_ENDL; + } + if (bytes && (*bytes != data.getSizeTotal())) + { + LL_WARNS() << mesh_id << "bytes mismatch " << *bytes << " " << data.getSizeTotal() << LL_ENDL; + } + if (bytes_visible && (lod >=0) && (lod < 4) && (*bytes_visible != data.getSizeByLOD(lod))) + { + LL_WARNS() << mesh_id << "bytes_visible mismatch " << *bytes_visible << " " << data.getSizeByLOD(lod) << LL_ENDL; + } + } + else + { + LL_WARNS() << "getCostData failed!!!" << LL_ENDL; + } + } + return result; +} + +// FIXME replace with calc based on LLMeshCostData //static -F32 LLMeshRepository::getStreamingCost(LLSD& header, F32 radius, S32* bytes, S32* bytes_visible, S32 lod, F32 *unscaled_value) +F32 LLMeshRepository::getStreamingCostLegacy(LLSD& header, F32 radius, S32* bytes, S32* bytes_visible, S32 lod, F32 *unscaled_value) { + if (header.has("404") + || !header.has("lowest_lod") + || (header.has("version") && header["version"].asInteger() > MAX_MESH_VERSION)) + { + return 0.f; + } + F32 max_distance = 512.f; F32 dlowest = llmin(radius/0.03f, max_distance); @@ -2945,7 +3187,7 @@ F32 LLMeshRepository::getStreamingCost(LLSD& header, F32 radius, S32* bytes, S32 } } - F32 max_area = 102932.f; //area of circle that encompasses region + F32 max_area = 102944.f; //area of circle that encompasses region (see MAINT-6559) F32 min_area = 1.f; F32 high_area = llmin(F_PI*dmid*dmid, max_area); @@ -2981,7 +3223,205 @@ F32 LLMeshRepository::getStreamingCost(LLSD& header, F32 radius, S32* bytes, S32 return weighted_avg/mesh_triangle_budget*15000.f; } +LLMeshCostData::LLMeshCostData() +{ + mSizeByLOD.resize(4); + mEstTrisByLOD.resize(4); + + std::fill(mSizeByLOD.begin(), mSizeByLOD.end(), 0); + std::fill(mEstTrisByLOD.begin(), mEstTrisByLOD.end(), 0.f); +} + +bool LLMeshCostData::init(const LLSD& header) +{ + mSizeByLOD.resize(4); + mEstTrisByLOD.resize(4); + + std::fill(mSizeByLOD.begin(), mSizeByLOD.end(), 0); + std::fill(mEstTrisByLOD.begin(), mEstTrisByLOD.end(), 0.f); + + S32 bytes_high = header["high_lod"]["size"].asInteger(); + S32 bytes_med = header["medium_lod"]["size"].asInteger(); + if (bytes_med == 0) + { + bytes_med = bytes_high; + } + S32 bytes_low = header["low_lod"]["size"].asInteger(); + if (bytes_low == 0) + { + bytes_low = bytes_med; + } + S32 bytes_lowest = header["lowest_lod"]["size"].asInteger(); + if (bytes_lowest == 0) + { + bytes_lowest = bytes_low; + } + mSizeByLOD[0] = bytes_lowest; + mSizeByLOD[1] = bytes_low; + mSizeByLOD[2] = bytes_med; + mSizeByLOD[3] = bytes_high; + + F32 METADATA_DISCOUNT = (F32) gSavedSettings.getU32("MeshMetaDataDiscount"); //discount 128 bytes to cover the cost of LLSD tags and compression domain overhead + F32 MINIMUM_SIZE = (F32) gSavedSettings.getU32("MeshMinimumByteSize"); //make sure nothing is "free" + F32 bytes_per_triangle = (F32) gSavedSettings.getU32("MeshBytesPerTriangle"); + + for (S32 i=0; i<4; i++) + { + mEstTrisByLOD[i] = llmax((F32) mSizeByLOD[i]-METADATA_DISCOUNT, MINIMUM_SIZE)/bytes_per_triangle; + } + + return true; +} + + +S32 LLMeshCostData::getSizeByLOD(S32 lod) +{ + if (llclamp(lod,0,3) != lod) + { + return 0; + } + return mSizeByLOD[lod]; +} + +S32 LLMeshCostData::getSizeTotal() +{ + return mSizeByLOD[0] + mSizeByLOD[1] + mSizeByLOD[2] + mSizeByLOD[3]; +} + +F32 LLMeshCostData::getEstTrisByLOD(S32 lod) +{ + if (llclamp(lod,0,3) != lod) + { + return 0.f; + } + return mEstTrisByLOD[lod]; +} + +F32 LLMeshCostData::getEstTrisMax() +{ + return llmax(mEstTrisByLOD[0], mEstTrisByLOD[1], mEstTrisByLOD[2], mEstTrisByLOD[3]); +} + +F32 LLMeshCostData::getRadiusWeightedTris(F32 radius) +{ + F32 max_distance = 512.f; + + F32 dlowest = llmin(radius/0.03f, max_distance); + F32 dlow = llmin(radius/0.06f, max_distance); + F32 dmid = llmin(radius/0.24f, max_distance); + + F32 triangles_lowest = mEstTrisByLOD[0]; + F32 triangles_low = mEstTrisByLOD[1]; + F32 triangles_mid = mEstTrisByLOD[2]; + F32 triangles_high = mEstTrisByLOD[3]; + + F32 max_area = 102944.f; //area of circle that encompasses region (see MAINT-6559) + F32 min_area = 1.f; + + F32 high_area = llmin(F_PI*dmid*dmid, max_area); + F32 mid_area = llmin(F_PI*dlow*dlow, max_area); + F32 low_area = llmin(F_PI*dlowest*dlowest, max_area); + F32 lowest_area = max_area; + + lowest_area -= low_area; + low_area -= mid_area; + mid_area -= high_area; + + high_area = llclamp(high_area, min_area, max_area); + mid_area = llclamp(mid_area, min_area, max_area); + low_area = llclamp(low_area, min_area, max_area); + lowest_area = llclamp(lowest_area, min_area, max_area); + + F32 total_area = high_area + mid_area + low_area + lowest_area; + high_area /= total_area; + mid_area /= total_area; + low_area /= total_area; + lowest_area /= total_area; + + F32 weighted_avg = triangles_high*high_area + + triangles_mid*mid_area + + triangles_low*low_area + + triangles_lowest*lowest_area; + + return weighted_avg; +} + +F32 LLMeshCostData::getEstTrisForStreamingCost() +{ + LL_DEBUGS("StreamingCost") << "tris_by_lod: " + << mEstTrisByLOD[0] << ", " + << mEstTrisByLOD[1] << ", " + << mEstTrisByLOD[2] << ", " + << mEstTrisByLOD[3] << LL_ENDL; + + F32 charged_tris = mEstTrisByLOD[3]; + F32 allowed_tris = mEstTrisByLOD[3]; + const F32 ENFORCE_FLOOR = 64.0f; + for (S32 i=2; i>=0; i--) + { + // How many tris can we have in this LOD without affecting land impact? + // - normally an LOD should be at most half the size of the previous one. + // - once we reach a floor of ENFORCE_FLOOR, don't require LODs to get any smaller. + allowed_tris = llclamp(allowed_tris/2.0f,ENFORCE_FLOOR,mEstTrisByLOD[i]); + F32 excess_tris = mEstTrisByLOD[i]-allowed_tris; + if (excess_tris>0.f) + { + LL_DEBUGS("StreamingCost") << "excess tris in lod[" << i << "] " << excess_tris << " allowed " << allowed_tris << LL_ENDL; + charged_tris += excess_tris; + } + } + return charged_tris; +} + +F32 LLMeshCostData::getRadiusBasedStreamingCost(F32 radius) +{ + return getRadiusWeightedTris(radius)/gSavedSettings.getU32("MeshTriangleBudget")*15000.f; +} + +F32 LLMeshCostData::getTriangleBasedStreamingCost() +{ + F32 result = ANIMATED_OBJECT_COST_PER_KTRI * 0.001 * getEstTrisForStreamingCost(); + return result; +} + + +bool LLMeshRepository::getCostData(LLUUID mesh_id, LLMeshCostData& data) +{ + data = LLMeshCostData(); + + if (mThread && mesh_id.notNull()) + { + LLMutexLock lock(mThread->mHeaderMutex); + LLMeshRepoThread::mesh_header_map::iterator iter = mThread->mMeshHeader.find(mesh_id); + if (iter != mThread->mMeshHeader.end() && mThread->mMeshHeaderSize[mesh_id] > 0) + { + const LLSD& header = iter->second; + + bool header_invalid = (header.has("404") + || !header.has("lowest_lod") + || (header.has("version") && header["version"].asInteger() > MAX_MESH_VERSION)); + if (!header_invalid) + { + return getCostData(header, data); + } + + return true; + } + } + return false; +} + +bool LLMeshRepository::getCostData(LLSD& header, LLMeshCostData& data) +{ + data = LLMeshCostData(); + + if (!data.init(header)) + { + return false; + } + return true; +} LLPhysicsDecomp::LLPhysicsDecomp() : LLThread("Physics Decomp") { @@ -3062,13 +3502,15 @@ bool needTriangles( LLConvexDecomposition *aDC ) void LLPhysicsDecomp::setMeshData(LLCDMeshData& mesh, bool vertex_based) { - LLConvexDecomposition *pDeComp = LLConvexDecomposition::getInstance(); - - if( !pDeComp ) - return; - - if( vertex_based ) - vertex_based = !needTriangles( pDeComp ); + // HACD + if (vertex_based) + { + if (LLConvexDecomposition* pDeComp = LLConvexDecomposition::getInstance()) + vertex_based = !needTriangles(pDeComp); + else + return; + } + // mesh.mVertexBase = mCurRequest->mPositions[0].mV; mesh.mVertexStrideBytes = 12; @@ -3086,11 +3528,14 @@ void LLPhysicsDecomp::setMeshData(LLCDMeshData& mesh, bool vertex_based) if ((vertex_based || mesh.mNumTriangles > 0) && mesh.mNumVertices > 2) { LLCDResult ret = LLCD_OK; - ret = LLConvexDecomposition::getInstance()->setMeshData(&mesh, vertex_based); + if (LLConvexDecomposition::getInstance() != NULL) + { + ret = LLConvexDecomposition::getInstance()->setMeshData(&mesh, vertex_based); + } if (ret) { - llerrs << "Convex Decomposition thread valid but could not set mesh data" << llendl; + LL_ERRS(LOG_MESH) << "Convex Decomposition thread valid but could not set mesh data." << LL_ENDL; } } } @@ -3141,6 +3586,7 @@ void LLPhysicsDecomp::doDecomposition() continue; } + if (param->mType == LLCDParam::LLCD_FLOAT) { ret = LLConvexDecomposition::getInstance()->setParam(param->mName, (F32) value.asReal()); @@ -3165,7 +3611,8 @@ void LLPhysicsDecomp::doDecomposition() if (ret) { - llwarns << "Convex Decomposition thread valid but could not execute stage " << stage << llendl; + LL_WARNS(LOG_MESH) << "Convex Decomposition thread valid but could not execute stage " << stage << "." + << LL_ENDL; LLMutexLock lock(mMutex); mCurRequest->mHull.clear(); @@ -3296,7 +3743,7 @@ void LLPhysicsDecomp::doDecompositionSingleHull() LLCDResult ret = decomp->buildSingleHull() ; if(ret) { - llwarns << "Could not execute decomposition stage when attempting to create single hull." << llendl; + LL_WARNS(LOG_MESH) << "Could not execute decomposition stage when attempting to create single hull." << LL_ENDL; make_box(mCurRequest); } else @@ -3351,17 +3798,17 @@ class ndDecompTracer: public ndConvexDecompositionTracer virtual void trace( char const *a_strMsg ) { - llinfos << a_strMsg << llendl; + LL_INFOS() << a_strMsg << LL_ENDL; } virtual void startTraceData( char const *a_strWhat) { - llinfos << a_strWhat << llendl; + LL_INFOS() << a_strWhat << LL_ENDL; } virtual void traceData( char const *a_strData ) { - llinfos << a_strData << llendl; + LL_INFOS() << a_strData << LL_ENDL; } virtual void endTraceData() @@ -3454,10 +3901,12 @@ void LLPhysicsDecomp::run() } } - mSignal->unlock(); - decomp->quitThread(); + if (mSignal->isLocked()) + { //let go of mSignal's associated mutex + mSignal->unlock(); + } mDone = true; } @@ -3542,60 +3991,6 @@ void LLPhysicsDecomp::Request::setStatusMessage(const std::string& msg) mStatusMessage = msg; } -LLModelInstance::LLModelInstance(LLSD& data) -{ - mLocalMeshID = data["mesh_id"].asInteger(); - mLabel = data["label"].asString(); - mTransform.setValue(data["transform"]); - - for (U32 i = 0; i < (U32)data["material"].size(); ++i) - { - LLImportMaterial mat(data["material"][i]); - mMaterial[mat.mBinding] = mat; - } -} - - -LLSD LLModelInstance::asLLSD() -{ - LLSD ret; - - ret["mesh_id"] = mModel->mLocalID; - ret["label"] = mLabel; - ret["transform"] = mTransform.getValue(); - - U32 i = 0; - for (std::map::iterator iter = mMaterial.begin(); iter != mMaterial.end(); ++iter) - { - ret["material"][i++] = iter->second.asLLSD(); - } - - return ret; -} - -LLImportMaterial::LLImportMaterial(LLSD& data) -{ - mDiffuseMapFilename = data["diffuse"]["filename"].asString(); - mDiffuseMapLabel = data["diffuse"]["label"].asString(); - mDiffuseColor.setValue(data["diffuse"]["color"]); - mFullbright = data["fullbright"].asBoolean(); - mBinding = data["binding"].asString(); -} - - -LLSD LLImportMaterial::asLLSD() -{ - LLSD ret; - - ret["diffuse"]["filename"] = mDiffuseMapFilename; - ret["diffuse"]["label"] = mDiffuseMapLabel; - ret["diffuse"]["color"] = mDiffuseColor.getValue(); - ret["fullbright"] = mFullbright; - ret["binding"] = mBinding; - - return ret; -} - void LLMeshRepository::buildPhysicsMesh(LLModel::Decomposition& decomp) { decomp.mMesh.resize(decomp.mHull.size()); @@ -3663,4 +4058,3 @@ bool LLMeshRepository::meshRezEnabled() } return false; } - diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h index 4b535f3979..c73511dcd0 100644 --- a/indra/newview/llmeshrepository.h +++ b/indra/newview/llmeshrepository.h @@ -32,14 +32,20 @@ #include "lluuid.h" #include "llviewertexture.h" #include "llvolume.h" -#include "sguuidhash.h" #define LLCONVEXDECOMPINTER_STATIC 1 -#include "LLConvexDecomposition.h" +#include "llconvexdecomposition.h" #include "lluploadfloaterobservers.h" #include "aistatemachinethread.h" +#include + +#ifndef BOOST_FUNCTION_HPP_INCLUDED +#include +#define BOOST_FUNCTION_HPP_INCLUDED +#endif + class LLVOVolume; class LLMeshResponder; class LLMutex; @@ -88,54 +94,6 @@ class LLTextureUploadData } }; -class LLImportMaterial -{ -public: - LLPointer mDiffuseMap; - std::string mDiffuseMapFilename; - std::string mDiffuseMapLabel; - std::string mBinding; - LLColor4 mDiffuseColor; - bool mFullbright; - - bool operator<(const LLImportMaterial ¶ms) const; - - LLImportMaterial() - : mFullbright(false) - { - mDiffuseColor.set(1, 1, 1, 1); - } - - LLImportMaterial(LLSD& data); - - LLSD asLLSD(); -}; - -class LLModelInstance -{ -public: - LLPointer mModel; - LLPointer mLOD[5]; - - std::string mLabel; - - LLUUID mMeshID; - S32 mLocalMeshID; - - LLMatrix4 mTransform; - std::map mMaterial; - - LLModelInstance(LLModel* model, const std::string& label, LLMatrix4& transform, std::map& materials) - : mModel(model), mLabel(label), mTransform(transform), mMaterial(materials) - { - mLocalMeshID = -1; - } - - LLModelInstance(LLSD& data); - - LLSD asLLSD(); -}; - class LLPhysicsDecomp : public LLThread { public: @@ -231,33 +189,42 @@ class LLMeshRepoThread : public LLThread std::map mMeshHeaderSize; - class HeaderRequest + struct MeshRequest + { + LLTimer mTimer; + LLVolumeParams mMeshParams; + MeshRequest(const LLVolumeParams& mesh_params) : mMeshParams(mesh_params) + { + mTimer.start(); + } + virtual ~MeshRequest() {} + virtual void preFetch() {} + virtual bool fetch(U32& count) = 0; + }; + class HeaderRequest : public MeshRequest { public: - const LLVolumeParams mMeshParams; - HeaderRequest(const LLVolumeParams& mesh_params) - : mMeshParams(mesh_params) - { - } - + : MeshRequest(mesh_params) + {} + bool fetch(U32& count); bool operator<(const HeaderRequest& rhs) const { return mMeshParams < rhs.mMeshParams; } }; - class LODRequest + class LODRequest : public MeshRequest { public: - LLVolumeParams mMeshParams; S32 mLOD; F32 mScore; LODRequest(const LLVolumeParams& mesh_params, S32 lod) - : mMeshParams(mesh_params), mLOD(lod), mScore(0.f) - { - } + : MeshRequest(mesh_params), mLOD(lod), mScore(0.f) + {} + void preFetch(); + bool fetch(U32& count); }; struct CompareScoreGreater @@ -283,26 +250,38 @@ class LLMeshRepoThread : public LLThread }; + struct MeshHeaderInfo + { + MeshHeaderInfo() + : mHeaderSize(0), mVersion(0), mOffset(-1), mSize(0) {} + U32 mHeaderSize; + U32 mVersion; + S32 mOffset; + S32 mSize; + }; + //set of requested skin info - std::set mSkinRequests; + uuid_set_t mSkinRequests; //queue of completed skin info requests std::queue mSkinInfoQ; + LLMutex* mSkinInfoQMutex; //set of requested decompositions - std::set mDecompositionRequests; + uuid_set_t mDecompositionRequests; //set of requested physics shapes - std::set mPhysicsShapeRequests; + uuid_set_t mPhysicsShapeRequests; //queue of completed Decomposition info requests std::queue mDecompositionQ; + LLMutex* mDecompositionQMutex; //queue of requested headers - std::queue mHeaderReqQ; + std::deque, F32> > mHeaderReqQ; //queue of requested LODs - std::queue mLODReqQ; + std::deque, F32> > mLODReqQ; //queue of unavailable LODs (either asset doesn't exist or asset doesn't have desired LOD) std::queue mUnavailableQ; @@ -319,12 +298,26 @@ class LLMeshRepoThread : public LLThread LLMeshRepoThread(); ~LLMeshRepoThread(); + void runQueue(std::deque, F32> >& queue, U32& count, S32& active_requests); + void runSet(uuid_set_t& set, std::function fn); + void pushHeaderRequest(const LLVolumeParams& mesh_params, F32 delay = 0) + { + std::shared_ptr req; + req.reset(new LLMeshRepoThread::HeaderRequest(mesh_params)); + mHeaderReqQ.push_back(std::make_pair(req, delay)); + } + void pushLODRequest(const LLVolumeParams& mesh_params, S32 lod, F32 delay = 0) + { + std::shared_ptr req; + req.reset(new LLMeshRepoThread::LODRequest(mesh_params, lod)); + mLODReqQ.push_back(std::make_pair(req, delay)); + } virtual void run(); void lockAndLoadMeshLOD(const LLVolumeParams& mesh_params, S32 lod); void loadMeshLOD(const LLVolumeParams& mesh_params, S32 lod); bool fetchMeshHeader(const LLVolumeParams& mesh_params, U32& count); - void fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod, U32& count); + bool fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod, U32& count); bool headerReceived(const LLVolumeParams& mesh_params, U8* data, S32 data_size); bool lodReceived(const LLVolumeParams& mesh_params, S32 lod, U8* data, S32 data_size); bool skinInfoReceived(const LLUUID& mesh_id, U8* data, S32 data_size); @@ -332,6 +325,9 @@ class LLMeshRepoThread : public LLThread bool physicsShapeReceived(const LLUUID& mesh_id, U8* data, S32 data_size); LLSD& getMeshHeader(const LLUUID& mesh_id); + bool getMeshHeaderInfo(const LLUUID& mesh_id, const char* block_name, MeshHeaderInfo& info); + bool loadInfoFromVFS(const LLUUID& mesh_id, MeshHeaderInfo& info, boost::function fn); + void notifyLoadedMeshes(); S32 getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lod); @@ -405,10 +401,11 @@ class LLMeshUploadThread : public AIThreadImpl #endif void init(instance_list& data, LLVector3& scale, bool upload_textures, bool upload_skin, bool upload_joints, bool do_upload, LLHandle const& fee_observer, LLHandle const& upload_observer); + ~LLMeshUploadThread(); void postRequest(std::string& url, AIMeshUpload* state_machine); - /*virtual*/ bool run(); + virtual bool run(); void preStart(); void generateHulls(); @@ -423,6 +420,7 @@ class LLMeshUploadThread : public AIThreadImpl void setFeeObserverHandle(LLHandle observer_handle) { mFeeObserverHandle = observer_handle; } void setUploadObserverHandle(LLHandle observer_handle) { mUploadObserverHandle = observer_handle; } + LLViewerFetchedTexture* FindViewerTexture(const LLImportMaterial& material); private: LLHandle mFeeObserverHandle; LLHandle mUploadObserverHandle; @@ -449,6 +447,8 @@ class AIMeshUpload : public AIStateMachine void setWholeModelUploadURL(std::string const& whole_model_upload_url) { mWholeModelUploadURL = whole_model_upload_url; } + /*virtual*/ const char* getName() const { return "AIMeshUpload"; } + protected: // Implement AIStateMachine. /*virtual*/ const char* state_str_impl(state_type run_state) const; @@ -456,6 +456,53 @@ class AIMeshUpload : public AIStateMachine /*virtual*/ void multiplex_impl(state_type run_state); }; +// Params related to streaming cost, render cost, and scene complexity tracking. +class LLMeshCostData +{ +public: + LLMeshCostData(); + + bool init(const LLSD& header); + + // Size for given LOD + S32 getSizeByLOD(S32 lod); + + // Sum of all LOD sizes. + S32 getSizeTotal(); + + // Estimated triangle counts for the given LOD. + F32 getEstTrisByLOD(S32 lod); + + // Estimated triangle counts for the largest LOD. Typically this + // is also the "high" LOD, but not necessarily. + F32 getEstTrisMax(); + + // Triangle count as computed by original streaming cost + // formula. Triangles in each LOD are weighted based on how + // frequently they will be seen. + // This was called "unscaled_value" in the original getStreamingCost() functions. + F32 getRadiusWeightedTris(F32 radius); + + // Triangle count used by triangle-based cost formula. Based on + // triangles in highest LOD plus potentially partial charges for + // lower LODs depending on complexity. + F32 getEstTrisForStreamingCost(); + + // Streaming cost. This should match the server-side calculation + // for the corresponding volume. + F32 getRadiusBasedStreamingCost(F32 radius); + + // New streaming cost formula, currently only used for animated objects. + F32 getTriangleBasedStreamingCost(); + +private: + // From the "size" field of the mesh header. LOD 0=lowest, 3=highest. + std::vector mSizeByLOD; + + // Estimated triangle counts derived from the LOD sizes. LOD 0=lowest, 3=highest. + std::vector mEstTrisByLOD; +}; + class LLMeshRepository { public: @@ -470,13 +517,20 @@ class LLMeshRepository static U32 sCacheBytesWritten; static U32 sPeakKbps; - static F32 getStreamingCost(LLSD& header, F32 radius, S32* bytes = NULL, S32* visible_bytes = NULL, S32 detail = -1, F32 *unscaled_value = NULL); + // Estimated triangle count of the largest LOD + F32 getEstTrianglesMax(LLUUID mesh_id); + F32 getEstTrianglesStreamingCost(LLUUID mesh_id); + F32 getStreamingCostLegacy(LLUUID mesh_id, F32 radius, S32* bytes = NULL, S32* visible_bytes = NULL, S32 detail = -1, F32 *unscaled_value = NULL); + static F32 getStreamingCostLegacy(LLSD& header, F32 radius, S32* bytes = NULL, S32* visible_bytes = NULL, S32 detail = -1, F32 *unscaled_value = NULL); + bool getCostData(LLUUID mesh_id, LLMeshCostData& data); + static bool getCostData(LLSD& header, LLMeshCostData& data); LLMeshRepository(); void init(); void shutdown(); + void unregisterMesh(LLVOVolume* volume); //mesh management functions S32 loadMesh(LLVOVolume* volume, const LLVolumeParams& mesh_params, S32 detail = 0, S32 last_lod = -1); @@ -504,15 +558,14 @@ class LLMeshRepository void uploadModel(std::vector& data, LLVector3& scale, bool upload_textures, bool upload_skin, bool upload_joints, std::string upload_url, bool do_upload = true, - LLHandle fee_observer= (LLHandle()), - LLHandle upload_observer = (LLHandle())); + LLHandle fee_observer= (LLHandle()), LLHandle upload_observer = (LLHandle())); S32 getMeshSize(const LLUUID& mesh_id, S32 lod); - typedef std::map > mesh_load_map; + typedef std::map > mesh_load_map; mesh_load_map mLoadingMeshes[4]; - typedef boost::unordered_map skin_map; + typedef absl::node_hash_map skin_map; skin_map mSkinMap; typedef std::map decomposition_map; @@ -523,20 +576,20 @@ class LLMeshRepository std::vector mPendingRequests; //list of mesh ids awaiting skin info - typedef std::map > skin_load_map; + typedef std::map skin_load_map; skin_load_map mLoadingSkins; //list of mesh ids that need to send skin info fetch requests std::queue mPendingSkinRequests; //list of mesh ids awaiting decompositions - std::set mLoadingDecompositions; + uuid_set_t mLoadingDecompositions; //list of mesh ids that need to send decomposition fetch requests std::queue mPendingDecompositionRequests; //list of mesh ids awaiting physics shapes - std::set mLoadingPhysicsShapes; + uuid_set_t mLoadingPhysicsShapes; //list of mesh ids that need to send physics shape fetch requests std::queue mPendingPhysicsShapeRequests; @@ -569,9 +622,11 @@ class LLMeshRepository void updateInventory(inventory_data data); std::string mGetMeshCapability; - }; extern LLMeshRepository gMeshRepo; +const F32 ANIMATED_OBJECT_BASE_COST = 15.0f; +const F32 ANIMATED_OBJECT_COST_PER_KTRI = 1.5f; + #endif diff --git a/indra/newview/llmimetypes.cpp b/indra/newview/llmimetypes.cpp index 3825c2bcba..697f5e911b 100644 --- a/indra/newview/llmimetypes.cpp +++ b/indra/newview/llmimetypes.cpp @@ -35,6 +35,7 @@ #include "llmimetypes.h" #include "lltrans.h" +#include "llxmlnode.h" #include "lluictrlfactory.h" @@ -78,13 +79,13 @@ bool LLMIMETypes::parseMIMETypes(const std::string& xml_filename) if ( ! success || root.isNull() || ! root->hasName( "mimetypes" ) ) { - llwarns << "Unable to read MIME type file: " - << xml_filename << llendl; + LL_WARNS() << "Unable to read MIME type file: " + << xml_filename << LL_ENDL; return false; } for (LLXMLNode* node = root->getFirstChild(); - node != NULL; + node != nullptr; node = node->getNextSibling()) { if (node->hasName("defaultlabel")) @@ -105,7 +106,7 @@ bool LLMIMETypes::parseMIMETypes(const std::string& xml_filename) node->getAttributeString("name", mime_type); LLMIMEInfo info; for (LLXMLNode* child = node->getFirstChild(); - child != NULL; + child != nullptr; child = child->getNextSibling()) { if (child->hasName("label")) @@ -129,7 +130,7 @@ bool LLMIMETypes::parseMIMETypes(const std::string& xml_filename) node->getAttributeString("name", set_name); LLMIMEWidgetSet info; for (LLXMLNode* child = node->getFirstChild(); - child != NULL; + child != nullptr; child = child->getNextSibling()) { if (child->hasName("label")) diff --git a/indra/newview/llmimetypes.h b/indra/newview/llmimetypes.h index 3461769ff3..1ac983cd03 100644 --- a/indra/newview/llmimetypes.h +++ b/indra/newview/llmimetypes.h @@ -34,9 +34,6 @@ #ifndef LLMIMETYPES_H #define LLMIMETYPES_H -#include -#include - class LLMIMETypes { public: diff --git a/indra/newview/llmutelist.cpp b/indra/newview/llmutelist.cpp index 99b541b239..aae99afdd9 100644 --- a/indra/newview/llmutelist.cpp +++ b/indra/newview/llmutelist.cpp @@ -50,28 +50,29 @@ #include "llmutelist.h" +#include "pipeline.h" + #include #include "lldispatcher.h" #include "llxfermanager.h" #include "llagent.h" +#include "llavataractions.h" #include "llviewergenericmessage.h" // for gGenericDispatcher #include "llworld.h" //for particle system banning #include "llfloaterchat.h" #include "llimpanel.h" #include "llimview.h" #include "llnotifications.h" -#include "lluistring.h" -#include "llviewerobject.h" #include "llviewerobjectlist.h" -#include "llenvmanager.h" +#include "lltrans.h" namespace { // This method is used to return an object to mute given an object id. // Its used by the LLMute constructor and LLMuteList::isMuted. - LLViewerObject* get_object_to_mute_from_id(LLUUID object_id) + LLViewerObject* get_object_to_mute_from_id(const LLUUID& object_id) { LLViewerObject *objectp = gObjectList.findObject(object_id); if ((objectp) && (!objectp->isAvatar())) @@ -90,11 +91,11 @@ namespace class LLDispatchEmptyMuteList : public LLDispatchHandler { public: - virtual bool operator()( + bool operator()( const LLDispatcher* dispatcher, const std::string& key, const LLUUID& invoice, - const sparam_t& strings) + const sparam_t& strings) override { LLMuteList::getInstance()->setLoaded(); return true; @@ -106,12 +107,6 @@ static LLDispatchEmptyMuteList sDispatchEmptyMuteList; //----------------------------------------------------------------------------- // LLMute() //----------------------------------------------------------------------------- -const char BY_NAME_SUFFIX[] = " (by name)"; -const char AGENT_SUFFIX[] = " (resident)"; -const char OBJECT_SUFFIX[] = " (object)"; -const char GROUP_SUFFIX[] = " (group)"; -const char EXTERNAL_SUFFIX[] = " (avaline)"; - LLMute::LLMute(const LLUUID& id, const std::string& name, EType type, U32 flags) : mID(id), @@ -137,88 +132,38 @@ LLMute::LLMute(const LLUUID& id, const std::string& name, EType type, U32 flags) } -std::string LLMute::getDisplayName() const +std::string LLMute::getDisplayType() const { - std::string name_with_suffix = mName; switch (mType) { case BY_NAME: default: - name_with_suffix += BY_NAME_SUFFIX; + return LLTrans::getString("MuteByName"); break; case AGENT: - name_with_suffix += AGENT_SUFFIX; + return LLTrans::getString("MuteAgent"); break; case OBJECT: - name_with_suffix += OBJECT_SUFFIX; + return LLTrans::getString("MuteObject"); break; case GROUP: - name_with_suffix += GROUP_SUFFIX; + return LLTrans::getString("MuteGroup"); break; case EXTERNAL: - name_with_suffix += EXTERNAL_SUFFIX; + return LLTrans::getString("MuteExternal"); break; } - return name_with_suffix; } -void LLMute::setFromDisplayName(const std::string& display_name) -{ - size_t pos = 0; - mName = display_name; - - pos = mName.rfind(GROUP_SUFFIX); - if (pos != std::string::npos) - { - mName.erase(pos); - mType = GROUP; - return; - } - - pos = mName.rfind(OBJECT_SUFFIX); - if (pos != std::string::npos) - { - mName.erase(pos); - mType = OBJECT; - return; - } - - pos = mName.rfind(AGENT_SUFFIX); - if (pos != std::string::npos) - { - mName.erase(pos); - mType = AGENT; - return; - } - - pos = mName.rfind(BY_NAME_SUFFIX); - if (pos != std::string::npos) - { - mName.erase(pos); - mType = BY_NAME; - return; - } - - pos = mName.rfind(EXTERNAL_SUFFIX); - if (pos != std::string::npos) - { - mName.erase(pos); - mType = EXTERNAL; - return; - } - - llwarns << "Unable to set mute from display name " << display_name << llendl; - return; -} /* static */ LLMuteList* LLMuteList::getInstance() { // Register callbacks at the first time that we find that the message system has been created. - static BOOL registered = FALSE; - if( !registered && gMessageSystem != NULL) + static bool registered = false; + if( !registered && gMessageSystem) { - registered = TRUE; + registered = true; // Register our various callbacks gMessageSystem->setHandlerFuncFast(_PREHASH_MuteListUpdate, processMuteListUpdate); gMessageSystem->setHandlerFuncFast(_PREHASH_UseCachedMuteList, processUseCachedMuteList); @@ -233,9 +178,6 @@ LLMuteList::LLMuteList() : mIsLoaded(FALSE) { gGenericDispatcher.addHandler("emptymutelist", &sDispatchEmptyMuteList); - - checkNewRegion(); - LLEnvManagerNew::instance().setRegionChangeCallback(boost::bind(&LLMuteList::checkNewRegion, this)); } //----------------------------------------------------------------------------- @@ -264,7 +206,7 @@ BOOL LLMuteList::isLinden(const std::string& name) const tokenizer::iterator token_iter = tokens.begin(); if (token_iter == tokens.end()) return FALSE; - token_iter++; + ++token_iter; if (token_iter == tokens.end()) return FALSE; std::string last_name = *token_iter; @@ -285,7 +227,7 @@ static LLVOAvatar* find_avatar(const LLUUID& id) } else { - return NULL; + return nullptr; } } @@ -295,6 +237,7 @@ BOOL LLMuteList::add(const LLMute& mute, U32 flags) if ((mute.mType == LLMute::AGENT) && isLinden(mute.mName) && (flags & LLMute::flagTextChat || flags == 0)) { + LL_WARNS() << "Trying to mute a Linden; ignored" << LL_ENDL; LLNotifications::instance().add("MuteLinden", LLSD(), LLSD()); return FALSE; } @@ -303,6 +246,7 @@ BOOL LLMuteList::add(const LLMute& mute, U32 flags) if (mute.mType == LLMute::AGENT && mute.mID == gAgent.getID()) { + LL_WARNS() << "Trying to self; ignored" << LL_ENDL; return FALSE; } @@ -311,87 +255,89 @@ BOOL LLMuteList::add(const LLMute& mute, U32 flags) // Can't mute empty string by name if (mute.mName.empty()) { - llwarns << "Trying to mute empty string by-name" << llendl; + LL_WARNS() << "Trying to mute empty string by-name" << LL_ENDL; return FALSE; } // Null mutes must have uuid null if (mute.mID.notNull()) { - llwarns << "Trying to add by-name mute with non-null id" << llendl; + LL_WARNS() << "Trying to add by-name mute with non-null id" << LL_ENDL; return FALSE; } std::pair result = mLegacyMutes.insert(mute.mName); if (result.second) { - llinfos << "Muting by name " << mute.mName << llendl; + LL_INFOS() << "Muting by name " << mute.mName << LL_ENDL; updateAdd(mute); notifyObservers(); + notifyObserversDetailed(mute); return TRUE; } else { + LL_INFOS() << "duplicate mute ignored" << LL_ENDL; // was duplicate return FALSE; } } - else + + // Need a local (non-const) copy to set up flags properly. + LLMute localmute = mute; + + // If an entry for the same entity is already in the list, remove it, saving flags as necessary. + mute_set_t::iterator it = mMutes.find(localmute); + bool duplicate = it != mMutes.end(); + if (duplicate) { - // Need a local (non-const) copy to set up flags properly. - LLMute localmute = mute; + // This mute is already in the list. Save the existing entry's flags if that's warranted. + localmute.mFlags = it->mFlags; - // If an entry for the same entity is already in the list, remove it, saving flags as necessary. - mute_set_t::iterator it = mMutes.find(localmute); - if (it != mMutes.end()) - { - // This mute is already in the list. Save the existing entry's flags if that's warranted. - localmute.mFlags = it->mFlags; - - mMutes.erase(it); - // Don't need to call notifyObservers() here, since it will happen after the entry has been re-added below. - } - else - { - // There was no entry in the list previously. Fake things up by making it look like the previous entry had all properties unmuted. - localmute.mFlags = LLMute::flagAll; - } + mMutes.erase(it); + // Don't need to call notifyObservers() here, since it will happen after the entry has been re-added below. + } + else + { + // There was no entry in the list previously. Fake things up by making it look like the previous entry had all properties unmuted. + localmute.mFlags = LLMute::flagAll; + } - if(flags) - { - // The user passed some combination of flags. Make sure those flag bits are turned off (i.e. those properties will be muted). - localmute.mFlags &= (~flags); - } - else - { - // The user passed 0. Make sure all flag bits are turned off (i.e. all properties will be muted). - localmute.mFlags = 0; - } + if(flags) + { + // The user passed some combination of flags. Make sure those flag bits are turned off (i.e. those properties will be muted). + localmute.mFlags &= (~flags); + } + else + { + // The user passed 0. Make sure all flag bits are turned off (i.e. all properties will be muted). + localmute.mFlags = 0; + } - // (re)add the mute entry. - { - std::pair result = mMutes.insert(localmute); - if (result.second) + // (re)add the mute entry. + { + auto result = mMutes.insert(localmute); + if (result.second) + { + LL_INFOS() << "Muting " << localmute.mName << " id " << localmute.mID << " flags " << localmute.mFlags << LL_ENDL; + updateAdd(localmute); + notifyObservers(); + notifyObserversDetailed(localmute); + if(!(localmute.mFlags & LLMute::flagParticles)) { - llinfos << "Muting " << localmute.mName << " id " << localmute.mID << " flags " << localmute.mFlags << llendl; - updateAdd(localmute); - notifyObservers(); - if(!(localmute.mFlags & LLMute::flagParticles)) + //Kill all particle systems owned by muted task + if(localmute.mType == LLMute::AGENT || localmute.mType == LLMute::OBJECT) { - //Kill all particle systems owned by muted task - if(localmute.mType == LLMute::AGENT || localmute.mType == LLMute::OBJECT) - { - LLViewerPartSim::getInstance()->clearParticlesByOwnerID(localmute.mID); - } + LLViewerPartSim::getInstance()->clearParticlesByOwnerID(localmute.mID); } - //mute local lights that are attached to the avatar - LLVOAvatar *avatarp = find_avatar(localmute.mID); - if (avatarp) - { - LLPipeline::removeMutedAVsLights(avatarp); - } - return TRUE; } + //mute local lights that are attached to the avatar + LLVOAvatar *avatarp = find_avatar(localmute.mID); + if (avatarp) + { + LLPipeline::removeMutedAVsLights(avatarp); + } + return !duplicate; } } @@ -462,30 +408,34 @@ BOOL LLMuteList::remove(const LLMute& mute, U32 flags) { // The entry was actually removed. Notify the server. updateRemove(localmute); - llinfos << "Unmuting " << localmute.mName << " id " << localmute.mID << " flags " << localmute.mFlags << llendl; + LL_INFOS() << "Unmuting " << localmute.mName << " id " << localmute.mID << " flags " << localmute.mFlags << LL_ENDL; } else { // Flags were updated, the mute entry needs to be retransmitted to the server and re-added to the list. mMutes.insert(localmute); updateAdd(localmute); - llinfos << "Updating mute entry " << localmute.mName << " id " << localmute.mID << " flags " << localmute.mFlags << llendl; + LL_INFOS() << "Updating mute entry " << localmute.mName << " id " << localmute.mID << " flags " << localmute.mFlags << LL_ENDL; } // Must be after erase. + notifyObserversDetailed(localmute); setLoaded(); // why is this here? -MG } - - // Clean up any legacy mutes - string_set_t::iterator legacy_it = mLegacyMutes.find(mute.mName); - if (legacy_it != mLegacyMutes.end()) + else { - // Database representation of legacy mute is UUID null. - LLMute mute(LLUUID::null, *legacy_it, LLMute::BY_NAME); - updateRemove(mute); - mLegacyMutes.erase(legacy_it); - // Must be after erase. - setLoaded(); // why is this here? -MG + // Clean up any legacy mutes + string_set_t::iterator legacy_it = mLegacyMutes.find(mute.mName); + if (legacy_it != mLegacyMutes.end()) + { + // Database representation of legacy mute is UUID null. + LLMute mute(LLUUID::null, *legacy_it, LLMute::BY_NAME); + updateRemove(mute); + mLegacyMutes.erase(legacy_it); + // Must be after erase. + notifyObserversDetailed(mute); + setLoaded(); // why is this here? -MG + } } return found; @@ -511,7 +461,7 @@ void LLMuteList::updateRemove(const LLMute& mute) gAgent.sendReliableMessage(); } -void notify_automute_callback(const LLUUID& agent_id, const std::string& full_name, bool is_group, LLMuteList::EAutoReason reason) +static void notify_automute_callback(const LLUUID& agent_id, const LLMuteList::EAutoReason& reason) { std::string notif_name; switch (reason) @@ -528,25 +478,19 @@ void notify_automute_callback(const LLUUID& agent_id, const std::string& full_na break; } - LLSD args; - args["NAME"] = full_name; - - LLNotificationPtr notif_ptr = LLNotifications::instance().add(notif_name, args, LLSD()); - if (notif_ptr) + if (auto notif_ptr = LLNotifications::instance().add(notif_name, LLSD().with("NAME", LLAvatarActions::getSLURL(agent_id)), LLSD())) { std::string message = notif_ptr->getMessage(); if (reason == LLMuteList::AR_IM) { - LLFloaterIMPanel *timp = gIMMgr->findFloaterBySession(agent_id); - if (timp) + if (LLFloaterIMPanel* timp = gIMMgr->findFloaterBySession(agent_id)) { timp->addHistoryLine(message); } } - LLChat auto_chat(message); - LLFloaterChat::addChat(auto_chat, FALSE, FALSE); + LLFloaterChat::addChat(message, FALSE, FALSE); } } @@ -555,24 +499,13 @@ BOOL LLMuteList::autoRemove(const LLUUID& agent_id, const EAutoReason reason) { BOOL removed = FALSE; - if (isMuted(agent_id)) + if (isMuted(agent_id) && !(reason == AR_INVENTORY && gSavedPerAccountSettings.getBOOL("AutoresponseMutedItem"))) { LLMute automute(agent_id, LLStringUtil::null, LLMute::AGENT); removed = TRUE; remove(automute); - std::string full_name; - if (gCacheName->getFullName(agent_id, full_name)) - { - // name in cache, call callback directly - notify_automute_callback(agent_id, full_name, false, reason); - } - else - { - // not in cache, lookup name from cache - gCacheName->get(agent_id, false, - boost::bind(¬ify_automute_callback, _1, _2, _3, reason)); - } + notify_automute_callback(agent_id, reason); } return removed; @@ -583,18 +516,14 @@ std::vector LLMuteList::getMutes() const { std::vector mutes; - for (mute_set_t::const_iterator it = mMutes.begin(); - it != mMutes.end(); - ++it) + for (const auto& mMute : mMutes) { - mutes.push_back(*it); + mutes.push_back(mMute); } - for (string_set_t::const_iterator it = mLegacyMutes.begin(); - it != mLegacyMutes.end(); - ++it) + for (const auto& mLegacyMute : mLegacyMutes) { - LLMute legacy(LLUUID::null, *it); + LLMute legacy(LLUUID::null, mLegacyMute); mutes.push_back(legacy); } @@ -607,16 +536,16 @@ std::vector LLMuteList::getMutes() const //----------------------------------------------------------------------------- BOOL LLMuteList::loadFromFile(const std::string& filename) { - if(!filename.size()) + if(filename.empty()) { - llwarns << "Mute List Filename is Empty!" << llendl; + LL_WARNS() << "Mute List Filename is Empty!" << LL_ENDL; return FALSE; } LLFILE* fp = LLFile::fopen(filename, "rb"); /*Flawfinder: ignore*/ if (!fp) { - llwarns << "Couldn't open mute list " << filename << llendl; + LL_WARNS() << "Couldn't open mute list " << filename << LL_ENDL; return FALSE; } @@ -657,38 +586,34 @@ BOOL LLMuteList::loadFromFile(const std::string& filename) //----------------------------------------------------------------------------- BOOL LLMuteList::saveToFile(const std::string& filename) { - if(!filename.size()) + if(filename.empty()) { - llwarns << "Mute List Filename is Empty!" << llendl; + LL_WARNS() << "Mute List Filename is Empty!" << LL_ENDL; return FALSE; } LLFILE* fp = LLFile::fopen(filename, "wb"); /*Flawfinder: ignore*/ if (!fp) { - llwarns << "Couldn't open mute list " << filename << llendl; + LL_WARNS() << "Couldn't open mute list " << filename << LL_ENDL; return FALSE; } // legacy mutes have null uuid std::string id_string; LLUUID::null.toString(id_string); - for (string_set_t::iterator it = mLegacyMutes.begin(); - it != mLegacyMutes.end(); - ++it) + for (const auto& mLegacyMute : mLegacyMutes) { - fprintf(fp, "%d %s %s|\n", (S32)LLMute::BY_NAME, id_string.c_str(), it->c_str()); + fprintf(fp, "%d %s %s|\n", (S32)LLMute::BY_NAME, id_string.c_str(), mLegacyMute.c_str()); } - for (mute_set_t::iterator it = mMutes.begin(); - it != mMutes.end(); - ++it) + for (const auto& mMute : mMutes) { // Don't save external mutes as they are not sent to the server and probably won't //be valid next time anyway. - if (it->mType != LLMute::EXTERNAL) + if (mMute.mType != LLMute::EXTERNAL) { - it->mID.toString(id_string); - const std::string& name = it->mName; - fprintf(fp, "%d %s %s|%u\n", (S32)it->mType, id_string.c_str(), name.c_str(), it->mFlags); + mMute.mID.toString(id_string); + const std::string& name = mMute.mName; + fprintf(fp, "%d %s %s|%u\n", (S32)mMute.mType, id_string.c_str(), name.c_str(), mMute.mFlags); } } fclose(fp); @@ -698,18 +623,17 @@ BOOL LLMuteList::saveToFile(const std::string& filename) BOOL LLMuteList::isMuted(const LLUUID& id, const std::string& name, U32 flags) const { + if (mMutes.empty() && mLegacyMutes.empty()) + return FALSE; + // for objects, check for muting on their parent prim LLViewerObject* mute_object = get_object_to_mute_from_id(id); LLUUID id_to_check = (mute_object) ? mute_object->getID() : id; + if (id_to_check == gAgentID) return false; // Can't mute self. + // don't need name or type for lookup LLMute mute(id_to_check); - // Can't mute self. - if (mute.mID == gAgent.getID() && !mute_object) - { - getInstance()->remove(mute); - return false; - } mute_set_t::const_iterator mute_it = mMutes.find(mute); if (mute_it != mMutes.end()) { @@ -722,7 +646,8 @@ BOOL LLMuteList::isMuted(const LLUUID& id, const std::string& name, U32 flags) c } // empty names can't be legacy-muted - if (name.empty()) return FALSE; + bool avatar = mute_object && mute_object->isAvatar(); + if (name.empty() || avatar) return FALSE; // Look in legacy pile string_set_t::const_iterator legacy_it = mLegacyMutes.find(name); @@ -734,10 +659,8 @@ BOOL LLMuteList::isMuted(const LLUUID& id, const std::string& name, U32 flags) c //----------------------------------------------------------------------------- void LLMuteList::requestFromServer(const LLUUID& agent_id) { - std::string agent_id_string; - std::string filename; - agent_id.toString(agent_id_string); - filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,agent_id_string) + ".cached_mute"; + std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, + llformat("%s.cached_mute", agent_id.asString().c_str())); LLCRC crc; crc.update(filename); @@ -760,10 +683,8 @@ void LLMuteList::cache(const LLUUID& agent_id) // Write to disk even if empty. if(mIsLoaded) { - std::string agent_id_string; - std::string filename; - agent_id.toString(agent_id_string); - filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,agent_id_string) + ".cached_mute"; + std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, + llformat("%s.cached_mute", agent_id.asString().c_str())); saveToFile(filename); } } @@ -774,12 +695,12 @@ void LLMuteList::cache(const LLUUID& agent_id) void LLMuteList::processMuteListUpdate(LLMessageSystem* msg, void**) { - llinfos << "LLMuteList::processMuteListUpdate()" << llendl; + LL_INFOS() << "LLMuteList::processMuteListUpdate()" << LL_ENDL; LLUUID agent_id; msg->getUUIDFast(_PREHASH_MuteData, _PREHASH_AgentID, agent_id); if(agent_id != gAgent.getID()) { - llwarns << "Got an mute list update for the wrong agent." << llendl; + LL_WARNS() << "Got an mute list update for the wrong agent." << LL_ENDL; return; } std::string unclean_filename; @@ -799,18 +720,16 @@ void LLMuteList::processMuteListUpdate(LLMessageSystem* msg, void**) void LLMuteList::processUseCachedMuteList(LLMessageSystem* msg, void**) { - llinfos << "LLMuteList::processUseCachedMuteList()" << llendl; + LL_INFOS() << "LLMuteList::processUseCachedMuteList()" << LL_ENDL; - std::string agent_id_string; - gAgent.getID().toString(agent_id_string); - std::string filename; - filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,agent_id_string) + ".cached_mute"; + std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, + llformat("%s.cached_mute", gAgent.getID().asString().c_str())); LLMuteList::getInstance()->loadFromFile(filename); } void LLMuteList::onFileMuteList(void** user_data, S32 error_code, LLExtStat ext_status) { - llinfos << "LLMuteList::processMuteListFile()" << llendl; + LL_INFOS() << "LLMuteList::processMuteListFile()" << LL_ENDL; std::string* local_filename_and_path = (std::string*)user_data; if(local_filename_and_path && !local_filename_and_path->empty() && (error_code == 0)) @@ -850,52 +769,15 @@ void LLMuteList::notifyObservers() } } -void LLMuteList::checkNewRegion() +void LLMuteList::notifyObserversDetailed(const LLMute& mute) { - LLViewerRegion* regionp = gAgent.getRegion(); - if (!regionp) return; - - if (regionp->getFeaturesReceived()) - { - parseSimulatorFeatures(); - } - else - { - regionp->setFeaturesReceivedCallback(boost::bind(&LLMuteList::parseSimulatorFeatures, this)); - } -} - -void LLMuteList::parseSimulatorFeatures() -{ - LLViewerRegion* regionp = gAgent.getRegion(); - if (!regionp) return; - - LLSD info; - regionp->getSimulatorFeatures(info); - - mGodLastNames.clear(); - mGodFullNames.clear(); - - if (info.has("god_names")) - { - if (info["god_names"].has("last_names")) - { - LLSD godNames = info["god_names"]["last_names"]; - - for (LLSD::array_iterator godNames_it = godNames.beginArray(); godNames_it != godNames.endArray(); ++godNames_it) - mGodLastNames.insert((*godNames_it).asString()); - } - - if (info["god_names"].has("full_names")) - { - LLSD godNames = info["god_names"]["full_names"]; - - for (LLSD::array_iterator godNames_it = godNames.beginArray(); godNames_it != godNames.endArray(); ++godNames_it) - mGodFullNames.insert((*godNames_it).asString()); - } - } - else // Just use Linden + for (observer_set_t::iterator it = mObservers.begin(); + it != mObservers.end(); + ) { - mGodLastNames.insert("Linden"); + LLMuteListObserver* observer = *it; + observer->onChangeDetailed(mute); + // In case onChange() deleted an entry. + it = mObservers.upper_bound(observer); } } diff --git a/indra/newview/llmutelist.h b/indra/newview/llmutelist.h index cbf78e25a6..da8620eac7 100644 --- a/indra/newview/llmutelist.h +++ b/indra/newview/llmutelist.h @@ -64,18 +64,12 @@ class LLMute LLMute(const LLUUID& id, const std::string& name = std::string(), EType type = BY_NAME, U32 flags = 0); - // Returns name + suffix based on type - // For example: "James Tester (resident)" - std::string getDisplayName() const; - - // Converts a UI name into just the agent or object name - // For example: "James Tester (resident)" sets the name to "James Tester" - // and the type to AGENT. - void setFromDisplayName(const std::string& display_name); + // Returns localized type name of muted item + std::string getDisplayType() const; public: LLUUID mID; // agent or object id - std::string mName; // agent or object name + std::string mName; // agent or object name, does not store last name "Resident" EType mType; // needed for UI display of existing mutes U32 mFlags; // flags pertaining to this mute entry }; @@ -119,6 +113,9 @@ class LLMuteList : public LLSingleton BOOL isLinden(const std::string& name) const; bool isLinden(const LLUUID& id) const; + // Quick way to check if LLMute is in the set + bool hasMute(const LLMute& mute) const { return mMutes.find(mute) != mMutes.end(); } + BOOL isLoaded() const { return mIsLoaded; } std::vector getMutes() const; @@ -135,6 +132,7 @@ class LLMuteList : public LLSingleton void setLoaded(); void notifyObservers(); + void notifyObserversDetailed(const LLMute &mute); void updateAdd(const LLMute& mute); void updateRemove(const LLMute& mute); @@ -145,9 +143,6 @@ class LLMuteList : public LLSingleton static void onFileMuteList(void** user_data, S32 code, LLExtStat ext_status); - void checkNewRegion(); - void parseSimulatorFeatures(); - private: struct compare_by_name { @@ -182,6 +177,7 @@ class LLMuteList : public LLSingleton friend class LLDispatchEmptyMuteList; + friend class LFSimFeatureHandler; std::set mGodLastNames; std::set mGodFullNames; }; @@ -191,6 +187,7 @@ class LLMuteListObserver public: virtual ~LLMuteListObserver() { } virtual void onChange() = 0; + virtual void onChangeDetailed(const LLMute& ) { } }; diff --git a/indra/newview/llnamebox.cpp b/indra/newview/llnamebox.cpp index 28381301d3..d20e5429f7 100644 --- a/indra/newview/llnamebox.cpp +++ b/indra/newview/llnamebox.cpp @@ -33,114 +33,93 @@ #include "llviewerprecompiledheaders.h" #include "llnamebox.h" - -#include "llerror.h" -#include "llfontgl.h" -#include "llui.h" -#include "llviewercontrol.h" -#include "lluuid.h" - -#include "llcachename.h" -#include "llagent.h" - -// statics -std::set LLNameBox::sInstances; +#include "llwindow.h" static LLRegisterWidget r("name_box"); - -LLNameBox::LLNameBox(const std::string& name) -: LLTextBox(name, LLRect(), "" , NULL, TRUE) -{ - mNameID = LLUUID::null; - mLink = false; - //mParseHTML = mLink; // STORM-215 - mInitialValue = "(retrieving)"; - LLNameBox::sInstances.insert(this); - setText(LLStringUtil::null); -} - -LLNameBox::~LLNameBox() +LLNameBox::LLNameBox(const std::string& name, + const LLUUID& name_id, + const Type& type, + const std::string& loading, + bool rlv_sensitive, + const std::string& name_system, + bool click_for_profile) +: LLNameUI(loading, rlv_sensitive, name_id, type, name_system, click_for_profile) +, LLTextBox(name, LLRect(), LLStringUtil::null, nullptr, TRUE) { - LLNameBox::sInstances.erase(this); -} - -void LLNameBox::setNameID(const LLUUID& name_id, BOOL is_group) -{ - mNameID = name_id; - - std::string name; - BOOL got_name = FALSE; - - if (!is_group) - { - got_name = gCacheName->getFullName(name_id, name); - } - else + setClickedCallback(boost::bind(&LLNameUI::showProfile, this)); + if (!name_id.isNull()) { - got_name = gCacheName->getGroupName(name_id, name); + setNameID(name_id, type); } - - // Got the name already? Set it. - // Otherwise it will be set later in refresh(). - if (got_name) - setName(name, is_group); - else - setText(mInitialValue); + else setText(mInitialValue); } -void LLNameBox::refresh(const LLUUID& id, const std::string& full_name, bool is_group) +void LLNameBox::displayAsLink(bool link) { - if (id == mNameID) - { - setName(full_name, is_group); - } + static const LLUICachedControl color("HTMLAgentColor"); + setColor(link ? color : LLUI::sColorsGroup->getColor("LabelTextColor")); + setDisabledColor(link ? color : LLUI::sColorsGroup->getColor("LabelDisabledColor")); } -void LLNameBox::refreshAll(const LLUUID& id, const std::string& full_name, bool is_group) +// virtual +BOOL LLNameBox::handleRightMouseDown(S32 x, S32 y, MASK mask) { - std::set::iterator it; - for (it = LLNameBox::sInstances.begin(); - it != LLNameBox::sInstances.end(); - ++it) + auto handled = LLTextBox::handleRightMouseDown(x, y, mask); + if (mAllowInteract && !handled) { - LLNameBox* box = *it; - box->refresh(id, full_name, is_group); + if (mNameID.notNull()) + { + showMenu(this, sMenus[getSelectedType()], x, y); + handled = true; + } } + return handled; } -void LLNameBox::setName(const std::string& name, BOOL is_group) +// virtual +BOOL LLNameBox::handleHover(S32 x, S32 y, MASK mask) { - if (mLink) + auto handled = LLTextBox::handleHover(x, y, mask); + if (mClickForProfile && mAllowInteract) { - std::string url; - - if (is_group) - url = "[secondlife:///app/group/" + mNameID.asString() + "/about " + name + "]"; - else - url = "[secondlife:///app/agent/" + mNameID.asString() + "/about " + name + "]"; - - setText(url); - } - else - { - setText(name); + getWindow()->setCursor(UI_CURSOR_HAND); + handled = true; } + return handled; } // virtual -void LLNameBox::initFromXML(LLXMLNodePtr node, LLView* parent) +LLXMLNodePtr LLNameBox::getXML(bool save_children) const { - LLTextBox::initFromXML(node, parent); - node->getAttributeBOOL("link", mLink); - node->getAttributeString("initial_value", mInitialValue); + LLXMLNodePtr node = LLTextBox::getXML(); + + node->setName("name_box"); + node->createChild("initial_value", TRUE)->setStringValue(mInitialValue); + node->createChild("rlv_sensitive", TRUE)->setBoolValue(mRLVSensitive); + node->createChild("click_for_profile", TRUE)->setBoolValue(mClickForProfile); + node->createChild("name_system", TRUE)->setStringValue(mNameSystem); + + return node; } // static LLView* LLNameBox::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) { - LLNameBox* name_box = new LLNameBox("name_box"); + S8 type = AVATAR; + node->getAttributeS8("id_type", type); + LLUUID id; + node->getAttributeUUID("id", id); + std::string loading; + node->getAttributeString("initial_value", loading); + bool rlv_sensitive = false; + node->getAttribute_bool("rlv_sensitive", rlv_sensitive); + std::string name_system; + node->getAttributeString("name_system", name_system); + bool click_for_profile = true; + node->getAttribute_bool("click_for_profile", click_for_profile); + LLNameBox* name_box = new LLNameBox("name_box", id, (Type)type, loading, rlv_sensitive, name_system, click_for_profile); name_box->initFromXML(node,parent); + return name_box; } - diff --git a/indra/newview/llnamebox.h b/indra/newview/llnamebox.h index 0d5ec6a834..f27d6bbff3 100644 --- a/indra/newview/llnamebox.h +++ b/indra/newview/llnamebox.h @@ -33,42 +33,34 @@ #ifndef LL_LLNAMEBOX_H #define LL_LLNAMEBOX_H -#include - -#include "llview.h" -#include "llstring.h" -#include "llfontgl.h" +#include "llnameui.h" #include "lltextbox.h" -class LLNameBox +class LLNameBox final : public LLTextBox +, public LLNameUI { public: - virtual void initFromXML(LLXMLNodePtr node, LLView* parent); + LLXMLNodePtr getXML(bool save_children = true) const override final; static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); - virtual ~LLNameBox(); - - void setNameID(const LLUUID& name_id, BOOL is_group); - - void refresh(const LLUUID& id, const std::string& full_name, bool is_group); - - static void refreshAll(const LLUUID& id, const std::string& full_name, bool is_group); - -protected: - LLNameBox (const std::string& name); - - friend class LLUICtrlFactory; -private: - void setName(const std::string& name, BOOL is_group); - - static std::set sInstances; + void displayAsLink(bool link) override final; + void setText(const std::string& text) override final { LLTextBox::setText(text); } + void setValue(const LLSD& value) override final { LLNameUI::setValue(value); } + LLSD getValue() const override final { return LLNameUI::getValue(); } -private: - LLUUID mNameID; - BOOL mLink; - std::string mInitialValue; + BOOL handleMouseDown(S32 x, S32 y, MASK mask) override final { return mClickForProfile && mAllowInteract && LLTextBox::handleMouseDown(x, y, mask); } + BOOL handleMouseUp(S32 x, S32 y, MASK mask) override final { return mClickForProfile && mAllowInteract && LLTextBox::handleMouseUp(x, y, mask); } + BOOL handleRightMouseDown(S32 x, S32 y, MASK mask) override final; + BOOL handleHover(S32 x, S32 y, MASK mask) override final; + LLNameBox(const std::string& name, + const LLUUID& name_id = LLUUID::null, + const Type& type = AVATAR, + const std::string& loading = LLStringUtil::null, + bool rlv_sensitive = false, + const std::string& name_system = LLStringUtil::null, + bool click_for_profile = false); }; #endif diff --git a/indra/newview/llnameeditor.cpp b/indra/newview/llnameeditor.cpp index d7c948d36c..7a10ae3ff6 100644 --- a/indra/newview/llnameeditor.cpp +++ b/indra/newview/llnameeditor.cpp @@ -33,91 +33,85 @@ #include "llviewerprecompiledheaders.h" #include "llnameeditor.h" -#include "llcachename.h" -#include "llagent.h" -#include "llfontgl.h" - -#include "lluuid.h" -#include "llrect.h" -#include "llstring.h" -#include "llui.h" +#include "llmenugl.h" +#include "lluictrlfactory.h" +#include "llwindow.h" static LLRegisterWidget r("name_editor"); -// statics -std::set LLNameEditor::sInstances; - LLNameEditor::LLNameEditor(const std::string& name, const LLRect& rect, - const LLUUID& name_id, - BOOL is_group, + const LLUUID& name_id, + const Type& type, + const std::string& loading, + bool rlv_sensitive, + const std::string& name_system, + bool click_for_profile, const LLFontGL* glfont, S32 max_text_length) -: LLLineEditor(name, rect, - std::string("(retrieving)"), - glfont, - max_text_length), - mNameID(name_id) +: LLNameUI(loading, rlv_sensitive, name_id, type, name_system, click_for_profile) +, LLLineEditor(name, rect, LLStringUtil::null, glfont, max_text_length) { - LLNameEditor::sInstances.insert(this); - if(!name_id.isNull()) + if (!name_id.isNull()) { - setNameID(name_id, is_group); + setNameID(name_id, type); } + else setText(mInitialValue); } - -LLNameEditor::~LLNameEditor() +// virtual +BOOL LLNameEditor::handleMouseDown(S32 x, S32 y, MASK mask) { - LLNameEditor::sInstances.erase(this); + if (mClickForProfile && mAllowInteract) + { + showProfile(); + return true; + } + else return LLLineEditor::handleMouseDown(x, y, mask); } -void LLNameEditor::setNameID(const LLUUID& name_id, BOOL is_group) +// virtual +BOOL LLNameEditor::handleRightMouseDown(S32 x, S32 y, MASK mask) { - mNameID = name_id; - - std::string name; - - if (!is_group) + bool simple_menu = mContextMenuHandle.get()->getName() == "rclickmenu"; + std::string new_menu; + bool needs_simple = !mAllowInteract || mNameID.isNull(); // Need simple if no ID or blocking interaction + if (!simple_menu && needs_simple) // Switch to simple menu { - gCacheName->getFullName(name_id, name); + new_menu = "menu_texteditor.xml"; } - else + else // TODO: This is lazy, but I cannot recall a name editor that switches between group and avatar, so logic is not needed yet. { - gCacheName->getGroupName(name_id, name); + new_menu = mType == GROUP ? "menu_nameeditor_group.xml" : "menu_nameeditor_avatar.xml"; } + if (!new_menu.empty()) setContextMenu(LLUICtrlFactory::instance().buildMenu(new_menu, LLMenuGL::sMenuContainer)); + setActive(); - setText(name); + return LLLineEditor::handleRightMouseDown(x, y, mask); } -void LLNameEditor::refresh(const LLUUID& id, const std::string& full_name, bool is_group) -{ - if (id == mNameID) - { - setText(full_name); - } -} - -void LLNameEditor::refreshAll(const LLUUID& id, const std::string& full_name, bool is_group) +// virtual +BOOL LLNameEditor::handleHover(S32 x, S32 y, MASK mask) { - std::set::iterator it; - for (it = LLNameEditor::sInstances.begin(); - it != LLNameEditor::sInstances.end(); - ++it) + auto handled = LLLineEditor::handleHover(x, y, mask); + if (mAllowInteract && mClickForProfile && !mIsSelecting) { - LLNameEditor* box = *it; - box->refresh(id, full_name, is_group); + getWindow()->setCursor(UI_CURSOR_HAND); + handled = true; } + return handled; } -void LLNameEditor::setValue( const LLSD& value ) +void LLNameEditor::displayAsLink(bool link) { - setNameID(value.asUUID(), FALSE); + static const LLUICachedControl color("HTMLAgentColor"); + setReadOnlyFgColor(link ? color : LLUI::sColorsGroup->getColor("TextFgReadOnlyColor")); } -LLSD LLNameEditor::getValue() const +void LLNameEditor::setText(const std::string& text) { - return LLSD(mNameID); + setToolTip(text); + LLLineEditor::setText(text); } // virtual @@ -126,6 +120,10 @@ LLXMLNodePtr LLNameEditor::getXML(bool save_children) const LLXMLNodePtr node = LLLineEditor::getXML(); node->setName(LL_NAME_EDITOR_TAG); + node->createChild("label", TRUE)->setStringValue(mInitialValue); + node->createChild("rlv_sensitive", TRUE)->setBoolValue(mRLVSensitive); + node->createChild("click_for_profile", TRUE)->setBoolValue(mClickForProfile); + node->createChild("name_system", TRUE)->setStringValue(mNameSystem); return node; } @@ -135,22 +133,28 @@ LLView* LLNameEditor::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory LLRect rect; createRect(node, rect, parent, LLRect()); - S32 max_text_length = 128; + S32 max_text_length = 1024; node->getAttributeS32("max_length", max_text_length); - - LLFontGL* font = LLView::selectFont(node); + S8 type = AVATAR; + node->getAttributeS8("id_type", type); + LLUUID id; + node->getAttributeUUID("id", id); + std::string loading; + node->getAttributeString("label", loading); + bool rlv_sensitive = false; + node->getAttribute_bool("rlv_sensitive", rlv_sensitive); + bool click_for_profile = true; + node->getAttribute_bool("click_for_profile", click_for_profile); + std::string name_system; + node->getAttributeString("name_system", name_system); LLNameEditor* line_editor = new LLNameEditor("name_editor", - rect, - LLUUID::null, FALSE, - font, + rect, + id, (Type)type, loading, rlv_sensitive, name_system, + click_for_profile, + LLView::selectFont(node), max_text_length); - std::string label; - if(node->getAttributeString("label", label)) - { - line_editor->setLabel(label); - } line_editor->setColorParameters(node); line_editor->initFromXML(node, parent); diff --git a/indra/newview/llnameeditor.h b/indra/newview/llnameeditor.h index 6ac6e45383..aa61336123 100644 --- a/indra/newview/llnameeditor.h +++ b/indra/newview/llnameeditor.h @@ -33,50 +33,36 @@ #ifndef LL_LLNAMEEDITOR_H #define LL_LLNAMEEDITOR_H -#include - -#include "llview.h" -#include "v4color.h" -#include "llstring.h" -#include "llfontgl.h" #include "lllineeditor.h" +#include "llnameui.h" - -class LLNameEditor +class LLNameEditor final : public LLLineEditor +, public LLNameUI { public: LLNameEditor(const std::string& name, const LLRect& rect, const LLUUID& name_id = LLUUID::null, - BOOL is_group = FALSE, - const LLFontGL* glfont = NULL, + const Type& type = AVATAR, + const std::string& loading = LLStringUtil::null, + bool rlv_sensitive = false, + const std::string& name_system = LLStringUtil::null, + bool click_for_profile = true, + const LLFontGL* glfont = nullptr, S32 max_text_length = 254); - // By default, follows top and left and is mouse-opaque. - // If no text, text = name. - // If no font, uses default system font. - virtual ~LLNameEditor(); + BOOL handleMouseDown(S32 x, S32 y, MASK mask) override final; + BOOL handleRightMouseDown(S32 x, S32 y, MASK mask) override final; + BOOL handleHover(S32 x, S32 y, MASK mask) override final; - virtual LLXMLNodePtr getXML(bool save_children = true) const; + LLXMLNodePtr getXML(bool save_children = true) const override final; static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); - void setNameID(const LLUUID& name_id, BOOL is_group); - - void refresh(const LLUUID& id, const std::string& full_name, bool is_group); - - static void refreshAll(const LLUUID& id, const std::string& full_name, bool is_group); - - - // Take/return agent UUIDs - virtual void setValue( const LLSD& value ); - virtual LLSD getValue() const; - -private: - static std::set sInstances; - -private: - LLUUID mNameID; + void setValue(const LLSD& value) override final { LLNameUI::setValue(value); } + LLSD getValue() const override final { return LLNameUI::getValue(); } + void displayAsLink(bool link) override final; + void setText(const std::string& text) override final; }; #endif diff --git a/indra/newview/llnamelistctrl.cpp b/indra/newview/llnamelistctrl.cpp index ab22836442..f19520b011 100644 --- a/indra/newview/llnamelistctrl.cpp +++ b/indra/newview/llnamelistctrl.cpp @@ -33,8 +33,12 @@ #include "llavatarnamecache.h" #include "llcachename.h" #include "llagent.h" +#include "llavataractions.h" +#include "llfloaterexperienceprofile.h" +#include "llgroupactions.h" #include "llinventory.h" #include "llscrolllistitem.h" +#include "llscrolllistcell.h" #include "llscrolllistcolumn.h" #include "llsdparam.h" #include "lltrans.h" @@ -42,35 +46,36 @@ static LLRegisterWidget r("name_list"); -void LLNameListCtrl::NameTypeNames::declareValues() +void LLNameListItem::NameTypeNames::declareValues() { - declare("INDIVIDUAL", LLNameListCtrl::INDIVIDUAL); - declare("GROUP", LLNameListCtrl::GROUP); - declare("SPECIAL", LLNameListCtrl::SPECIAL); + declare("INDIVIDUAL", INDIVIDUAL); + declare("GROUP", GROUP); + declare("SPECIAL", SPECIAL); + declare("EXPERIENCE", EXPERIENCE); } -LLNameListCtrl::LLNameListCtrl(const std::string& name, const LLRect& rect, BOOL allow_multiple_selection, BOOL draw_border, bool draw_heading, S32 name_column_index, const std::string& tooltip) +LLNameListCtrl::LLNameListCtrl(const std::string& name, const LLRect& rect, BOOL allow_multiple_selection, BOOL draw_border, bool draw_heading, S32 name_column_index, const std::string& name_system, const std::string& tooltip) : LLScrollListCtrl(name, rect, NULL, allow_multiple_selection, draw_border,draw_heading), mNameColumnIndex(name_column_index), mAllowCallingCardDrop(false), - mShortNames(false), - mAvatarNameCacheConnection() + mNameSystem(name_system), + mPendingLookupsRemaining(0) { setToolTip(tooltip); } // public LLScrollListItem* LLNameListCtrl::addNameItem(const LLUUID& agent_id, EAddPosition pos, - BOOL enabled, const std::string& suffix) + BOOL enabled, const std::string& suffix, const std::string& prefix) { - //llinfos << "LLNameListCtrl::addNameItem " << agent_id << llendl; + //LL_INFOS() << "LLNameListCtrl::addNameItem " << agent_id << LL_ENDL; NameItem item; item.value = agent_id; item.enabled = enabled; - item.target = INDIVIDUAL; + item.target = LLNameListItem::INDIVIDUAL; - return addNameItemRow(item, pos, suffix); + return addNameItemRow(item, pos, suffix, prefix); } // virtual, public @@ -116,11 +121,57 @@ BOOL LLNameListCtrl::handleDragAndDrop( } handled = TRUE; - lldebugst(LLERR_USER_INPUT) << "dragAndDrop handled by LLNameListCtrl " << getName() << llendl; + LL_DEBUGS("UserInput") << "dragAndDrop handled by LLNameListCtrl " << getName() << LL_ENDL; return handled; } +BOOL LLNameListCtrl::handleDoubleClick(S32 x, S32 y, MASK mask) +{ + bool handled = LLScrollListCtrl::handleDoubleClick(x, y, mask); + if (!handled) + { + if (auto item = static_cast(hitItem(x, y))) + { + switch (item->getNameType()) + { + case LLNameListItem::INDIVIDUAL: LLAvatarActions::showProfile(item->getValue()); break; + case LLNameListItem::GROUP: LLGroupActions::show(item->getValue()); break; + case LLNameListItem::EXPERIENCE: LLFloaterExperienceProfile::showInstance(item->getValue()); break; + default: return false; + } + handled = true; + } + } + return handled; +} + +#define CONVERT_TO_RETTYPE(nametype, rettype) \ +nametype: \ +{ \ + if (ret == NONE) \ + ret = rettype; \ + else if (ret != rettype) \ + return MULTIPLE; \ + break; \ +} + +LFIDBearer::Type LLNameListCtrl::getSelectedType() const +{ + auto ret = NONE; + for (const auto& item : getAllSelected()) + { + switch (static_cast(item)->getNameType()) + { + CONVERT_TO_RETTYPE(case LLNameListItem::INDIVIDUAL, AVATAR) + CONVERT_TO_RETTYPE(case LLNameListItem::GROUP, GROUP) + CONVERT_TO_RETTYPE(case LLNameListItem::EXPERIENCE, EXPERIENCE) + CONVERT_TO_RETTYPE(default, COUNT) // Invalid, but just use count instead + } + } + return ret; +} +#undef CONVERT_TO_RETTYPE // public void LLNameListCtrl::addGroupNameItem(const LLUUID& group_id, EAddPosition pos, @@ -129,7 +180,7 @@ void LLNameListCtrl::addGroupNameItem(const LLUUID& group_id, EAddPosition pos, NameItem item; item.value = group_id; item.enabled = enabled; - item.target = GROUP; + item.target = LLNameListItem::GROUP; addNameItemRow(item, pos); } @@ -137,13 +188,13 @@ void LLNameListCtrl::addGroupNameItem(const LLUUID& group_id, EAddPosition pos, // public void LLNameListCtrl::addGroupNameItem(LLNameListCtrl::NameItem& item, EAddPosition pos) { - item.target = GROUP; + item.target = LLNameListItem::GROUP; addNameItemRow(item, pos); } LLScrollListItem* LLNameListCtrl::addNameItem(LLNameListCtrl::NameItem& item, EAddPosition pos) { - item.target = INDIVIDUAL; + item.target = LLNameListItem::INDIVIDUAL; return addNameItemRow(item, pos); } @@ -160,12 +211,13 @@ LLScrollListItem* LLNameListCtrl::addElement(const LLSD& element, EAddPosition p LLScrollListItem* LLNameListCtrl::addNameItemRow( const LLNameListCtrl::NameItem& name_item, EAddPosition pos, - const std::string& suffix) + const std::string& suffix, + const std::string& prefix) { LLUUID id = name_item.value().asUUID(); - LLNameListItem* item = new LLNameListItem(name_item,name_item.target() == GROUP); + LLNameListItem* item = new LLNameListItem(name_item); - if (!item) return NULL; + if (!item) return nullptr; LLScrollListCtrl::addRow(item, name_item, pos); @@ -173,41 +225,65 @@ LLScrollListItem* LLNameListCtrl::addNameItemRow( std::string fullname = name_item.name; switch(name_item.target) { - case GROUP: - gCacheName->getGroupName(id, fullname); - // fullname will be "nobody" if group not found + case LLNameListItem::GROUP: + if (!gCacheName->getGroupName(id, fullname)) + { + avatar_name_cache_connection_map_t::iterator it = mAvatarNameCacheConnections.find(id); + if (it != mAvatarNameCacheConnections.end()) + { + if (it->second.connected()) + { + it->second.disconnect(); + } + mAvatarNameCacheConnections.erase(it); + } + mAvatarNameCacheConnections[id] = gCacheName->getGroup(id, boost::bind(&LLNameListCtrl::onGroupNameCache, this, _1, _2, item->getHandle())); + } break; - case SPECIAL: + case LLNameListItem::SPECIAL: // just use supplied name break; - case INDIVIDUAL: + case LLNameListItem::INDIVIDUAL: { LLAvatarName av_name; if (id.isNull()) { - fullname = LLTrans::getString("AvatarNameNobody"); + static const auto nobody = LLTrans::getString("AvatarNameNobody"); + fullname = nobody; } else if (LLAvatarNameCache::get(id, &av_name)) { - if (mShortNames) - fullname = av_name.mDisplayName; - else - fullname = av_name.getCompleteName(); + fullname = av_name.getNSName(mNameSystem); } else { // ...schedule a callback - // This is not correct and will likely lead to partially populated lists in cases where avatar names are not cached. - // *TODO : Change this to have 2 callbacks : one callback per list item and one for the whole list. - /* Singu Note: Indeed it does, for now let's not use it - if (mAvatarNameCacheConnection.connected()) + avatar_name_cache_connection_map_t::iterator it = mAvatarNameCacheConnections.find(id); + if (it != mAvatarNameCacheConnections.end()) + { + if (it->second.connected()) { - mAvatarNameCacheConnection.disconnect(); + it->second.disconnect(); } - mAvatarNameCacheConnection =*/ LLAvatarNameCache::get(id,boost::bind(&LLNameListCtrl::onAvatarNameCache,this, _1, _2, item->getHandle())); - } - break; + mAvatarNameCacheConnections.erase(it); + } + mAvatarNameCacheConnections[id] = LLAvatarNameCache::get(id,boost::bind(&LLNameListCtrl::onAvatarNameCache,this, _1, _2, suffix, prefix, item->getHandle())); + + if (mPendingLookupsRemaining <= 0) + { + // BAKER TODO: + // We might get into a state where mPendingLookupsRemaining might + // go negative. So just reset it right now and figure out if it's + // possible later :) + mPendingLookupsRemaining = 0; + mNameListCompleteSignal(false); + } + mPendingLookupsRemaining++; } + break; + } + case LLNameListItem::EXPERIENCE: + // just use supplied name default: break; } @@ -221,7 +297,7 @@ LLScrollListItem* LLNameListCtrl::addNameItemRow( LLScrollListCell* cell = item->getColumn(mNameColumnIndex); if (cell) { - cell->setValue(fullname); + cell->setValue(prefix + fullname); } dirtyColumns(); @@ -256,20 +332,54 @@ void LLNameListCtrl::removeNameItem(const LLUUID& agent_id) { selectNthItem(idx); // not sure whether this is needed, taken from previous implementation deleteSingleItem(idx); + + mPendingLookupsRemaining--; + } +} + +// public +LLScrollListItem* LLNameListCtrl::getNameItemByAgentId(const LLUUID& agent_id) +{ + for (item_list::iterator it = getItemList().begin(); it != getItemList().end(); it++) + { + LLScrollListItem* item = *it; + if (item && item->getUUID() == agent_id) + { + return item; + } } + return NULL; } void LLNameListCtrl::onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name, + std::string suffix, + std::string prefix, LLHandle item) { - //mAvatarNameCacheConnection.disconnect(); + avatar_name_cache_connection_map_t::iterator it = mAvatarNameCacheConnections.find(agent_id); + if (it != mAvatarNameCacheConnections.end()) + { + if (it->second.connected()) + { + it->second.disconnect(); + } + mAvatarNameCacheConnections.erase(it); + } std::string name; - if (mShortNames) - name = av_name.mDisplayName; - else - name = av_name.getCompleteName(); + name = av_name.getNSName(mNameSystem); + + // Append optional suffix. + if (!suffix.empty()) + { + name.append(suffix); + } + + if (!prefix.empty()) + { + name.insert(0, prefix); + } LLNameListItem* list_item = item.get(); if (list_item && list_item->getUUID() == agent_id) @@ -282,9 +392,53 @@ void LLNameListCtrl::onAvatarNameCache(const LLUUID& agent_id, } } + ////////////////////////////////////////////////////////////////////////// + // BAKER - FIX NameListCtrl + //if (mPendingLookupsRemaining <= 0) + { + // We might get into a state where mPendingLookupsRemaining might + // go negative. So just reset it right now and figure out if it's + // possible later :) + //mPendingLookupsRemaining = 0; + + mNameListCompleteSignal(true); + } + //else + { + // mPendingLookupsRemaining--; + } + ////////////////////////////////////////////////////////////////////////// + + dirtyColumns(); +} + +void LLNameListCtrl::onGroupNameCache(const LLUUID& group_id, const std::string name, LLHandle item) +{ + avatar_name_cache_connection_map_t::iterator it = mAvatarNameCacheConnections.find(group_id); + if (it != mAvatarNameCacheConnections.end()) + { + if (it->second.connected()) + { + it->second.disconnect(); + } + mAvatarNameCacheConnections.erase(it); + } + + LLNameListItem* list_item = item.get(); + if (list_item && list_item->getUUID() == group_id) + { + LLScrollListCell* cell = list_item->getColumn(mNameColumnIndex); + if (cell) + { + cell->setValue(name); + setNeedsSort(); + } + } + dirtyColumns(); } + void LLNameListCtrl::sortByName(BOOL ascending) { sortByColumnIndex(mNameColumnIndex,ascending); @@ -314,19 +468,22 @@ LLView* LLNameListCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFacto LLRect rect; createRect(node, rect, parent, LLRect()); - BOOL multi_select = FALSE; + BOOL multi_select = false; node->getAttributeBOOL("multi_select", multi_select); - BOOL draw_border = TRUE; + BOOL draw_border = true; node->getAttributeBOOL("draw_border", draw_border); - BOOL draw_heading = FALSE; + BOOL draw_heading = false; node->getAttributeBOOL("draw_heading", draw_heading); S32 name_column_index = 0; node->getAttributeS32("name_column_index", name_column_index); - LLNameListCtrl* name_list = new LLNameListCtrl("name_list", rect, multi_select, draw_border, draw_heading, name_column_index); + std::string name_system("PhoenixNameSystem"); + node->getAttributeString("name_system", name_system); + + LLNameListCtrl* name_list = new LLNameListCtrl("name_list", rect, multi_select, draw_border, draw_heading, name_column_index, name_system); if (node->hasAttribute("heading_height")) { S32 heading_height; @@ -344,108 +501,5 @@ LLView* LLNameListCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFacto name_list->initFromXML(node, parent); - LLSD columns; - S32 index = 0; - LLXMLNodePtr child; - for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling()) - { - if (child->hasName("column")) - { - std::string labelname(""); - child->getAttributeString("label", labelname); - - std::string columnname(labelname); - child->getAttributeString("name", columnname); - - std::string sortname(columnname); - child->getAttributeString("sort", sortname); - - if (child->hasAttribute("relative_width")) - { - F32 columnrelwidth = 0.f; - child->getAttributeF32("relative_width", columnrelwidth); - columns[index]["relative_width"] = columnrelwidth; - } - else if (child->hasAttribute("relwidth")) - { - F32 columnrelwidth = 0.f; - child->getAttributeF32("relwidth", columnrelwidth); - columns[index]["relative_width"] = columnrelwidth; - } - else if (child->hasAttribute("dynamic_width")) - { - BOOL columndynamicwidth = FALSE; - child->getAttributeBOOL("dynamic_width", columndynamicwidth); - columns[index]["dynamic_width"] = columndynamicwidth; - } - else if (child->hasAttribute("dynamicwidth")) - { - BOOL columndynamicwidth = FALSE; - child->getAttributeBOOL("dynamicwidth", columndynamicwidth); - columns[index]["dynamic_width"] = columndynamicwidth; - } - else - { - S32 columnwidth = -1; - child->getAttributeS32("width", columnwidth); - columns[index]["width"] = columnwidth; - } - - LLFontGL::HAlign h_align = LLFontGL::LEFT; - h_align = LLView::selectFontHAlign(child); - - columns[index]["name"] = columnname; - columns[index]["label"] = labelname; - columns[index]["halign"] = (S32)h_align; - columns[index]["sort"] = sortname; - - index++; - } - } - name_list->setColumnHeadings(columns); - - - for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling()) - { - if (child->hasName("row")) - { - LLUUID id; - child->getAttributeUUID("id", id); - - LLSD row; - - row["id"] = id; - - S32 column_idx = 0; - LLXMLNodePtr row_child; - for (row_child = node->getFirstChild(); row_child.notNull(); row_child = row_child->getNextSibling()) - { - if (row_child->hasName("column")) - { - std::string value = row_child->getTextContents(); - - std::string columnname(""); - row_child->getAttributeString("name", columnname); - - std::string font(""); - row_child->getAttributeString("font", font); - - std::string font_style(""); - row_child->getAttributeString("font-style", font_style); - - row["columns"][column_idx]["column"] = columnname; - row["columns"][column_idx]["value"] = value; - row["columns"][column_idx]["font"] = font; - row["columns"][column_idx]["font-style"] = font_style; - column_idx++; - } - } - name_list->addElement(row); - } - } - - std::string contents = node->getTextContents(); - name_list->setCommentText(contents); - return name_list; } diff --git a/indra/newview/llnamelistctrl.h b/indra/newview/llnamelistctrl.h index 451f1ae7c1..b1dd64da5f 100644 --- a/indra/newview/llnamelistctrl.h +++ b/indra/newview/llnamelistctrl.h @@ -39,90 +39,98 @@ class LLAvatarName; * We don't use LLScrollListItem to be able to override getUUID(), which is needed * because the name list item value is not simply an UUID but a map (uuid, is_group). */ -class LLNameListItem : public LLScrollListItem, public LLHandleProvider +class LLNameListItem final : public LLScrollListItem, public LLHandleProvider { public: - bool isGroup() const { return mIsGroup; } - void setIsGroup(bool is_group) { mIsGroup = is_group; } + enum ENameType + { + INDIVIDUAL, + GROUP, + SPECIAL, + EXPERIENCE + }; + + // provide names for enums + struct NameTypeNames : public LLInitParam::TypeValuesHelper + { + static void declareValues(); + }; + + struct Params : public LLInitParam::Block + { + Optional name; + Optional target; + + Params() + : name("name"), + target("target", INDIVIDUAL) + {} + }; + ENameType getNameType() const { return mNameType; } + void setNameType(ENameType name_type) { mNameType = name_type; } protected: friend class LLNameListCtrl; - LLNameListItem( const LLScrollListItem::Params& p ) - : LLScrollListItem(p), mIsGroup(false) + LLNameListItem( const Params& p ) + : LLScrollListItem(p), mNameType(p.target) { } - LLNameListItem( const LLScrollListItem::Params& p, bool is_group ) - : LLScrollListItem(p), mIsGroup(is_group) + LLNameListItem( const LLScrollListItem::Params& p, ENameType name_type) + : LLScrollListItem(p), mNameType(name_type) { } private: - bool mIsGroup; + ENameType mNameType; }; -class LLNameListCtrl +class LLNameListCtrl final : public LLScrollListCtrl, public LLInstanceTracker { public: - typedef enum e_name_type - { - INDIVIDUAL, - GROUP, - SPECIAL - } ENameType; - - // provide names for enums - struct NameTypeNames : public LLInitParam::TypeValuesHelper - { - static void declareValues(); - }; - - struct NameItem : public LLInitParam::Block - { - Optional name; - Optional target; - - NameItem() - : name("name"), - target("target", INDIVIDUAL) - {} - }; + typedef boost::signals2::signal namelist_complete_signal_t; + typedef LLNameListItem::Params NameItem; struct NameColumn : public LLInitParam::ChoiceBlock { Alternative column_index; Alternative column_name; NameColumn() - : column_name("name_column"), - column_index("name_column_index", 0) + : column_index("name_column_index", 0), + column_name("name_column") {} }; protected: - LLNameListCtrl(const std::string& name, const LLRect& rect, BOOL allow_multiple_selection, BOOL draw_border = TRUE, bool draw_heading = false, S32 name_column_index = 0, const std::string& tooltip = LLStringUtil::null); + LLNameListCtrl(const std::string& name, const LLRect& rect, BOOL allow_multiple_selection, BOOL draw_border = TRUE, bool draw_heading = false, S32 name_column_index = 0, const std::string& name_system = "PhoenixNameSystem", const std::string& tooltip = LLStringUtil::null); virtual ~LLNameListCtrl() { - if (mAvatarNameCacheConnection.connected()) + for (avatar_name_cache_connection_map_t::iterator it = mAvatarNameCacheConnections.begin(); it != mAvatarNameCacheConnections.end(); ++it) { - mAvatarNameCacheConnection.disconnect(); + if (it->second.connected()) + { + it->second.disconnect(); + } } + mAvatarNameCacheConnections.clear(); } friend class LLUICtrlFactory; public: - virtual LLXMLNodePtr getXML(bool save_children = true) const; + virtual LLXMLNodePtr getXML(bool save_children = true) const override; static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); // Add a user to the list by name. It will be added, the name // requested from the cache, and updated as necessary. LLScrollListItem* addNameItem(const LLUUID& agent_id, EAddPosition pos = ADD_BOTTOM, - BOOL enabled = TRUE, const std::string& suffix = LLStringUtil::null); + BOOL enabled = TRUE, const std::string& suffix = LLStringUtil::null, const std::string& prefix = LLStringUtil::null); LLScrollListItem* addNameItem(NameItem& item, EAddPosition pos = ADD_BOTTOM); - /*virtual*/ LLScrollListItem* addElement(const LLSD& element, EAddPosition pos = ADD_BOTTOM, void* userdata = NULL); - LLScrollListItem* addNameItemRow(const NameItem& value, EAddPosition pos = ADD_BOTTOM, const std::string& suffix = LLStringUtil::null); + /*virtual*/ LLScrollListItem* addElement(const LLSD& element, EAddPosition pos = ADD_BOTTOM, void* userdata = NULL) override; + LLScrollListItem* addNameItemRow(const NameItem& value, EAddPosition pos = ADD_BOTTOM, const std::string& suffix = LLStringUtil::null, + const std::string& prefix = LLStringUtil::null); // Add a user to the list by name. It will be added, the name // requested from the cache, and updated as necessary. @@ -133,23 +141,41 @@ class LLNameListCtrl void removeNameItem(const LLUUID& agent_id); + LLScrollListItem* getNameItemByAgentId(const LLUUID& agent_id); + // LLView interface /*virtual*/ BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, void *cargo_data, EAcceptance *accept, - std::string& tooltip_msg); + std::string& tooltip_msg) override; + BOOL handleDoubleClick(S32 x, S32 y, MASK mask) override; + + Type getSelectedType() const override final; void setAllowCallingCardDrop(BOOL b) { mAllowCallingCardDrop = b; } void sortByName(BOOL ascending); private: - void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name, LLHandle item); + void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name, std::string suffix, std::string prefix, LLHandle item); + void onGroupNameCache(const LLUUID& group_id, const std::string name, LLHandle item); private: S32 mNameColumnIndex; + //std::string mNameColumn; BOOL mAllowCallingCardDrop; - bool mShortNames; // display name only, no SLID - boost::signals2::connection mAvatarNameCacheConnection; + const LLCachedControl mNameSystem; // Singu Note: Instead of mShortNames + typedef std::map avatar_name_cache_connection_map_t; + avatar_name_cache_connection_map_t mAvatarNameCacheConnections; + + S32 mPendingLookupsRemaining; + namelist_complete_signal_t mNameListCompleteSignal; + +public: + boost::signals2::connection setOnNameListCompleteCallback(std::function onNameListCompleteCallback) + { + return mNameListCompleteSignal.connect(onNameListCompleteCallback); + } + }; diff --git a/indra/newview/llnameui.cpp b/indra/newview/llnameui.cpp new file mode 100644 index 0000000000..5699684cdd --- /dev/null +++ b/indra/newview/llnameui.cpp @@ -0,0 +1,168 @@ +/** + * @file llnameui.cpp + * @brief Name UI refreshes a name and bears a menu for interacting with it + * + * $LicenseInfo:firstyear=2003&license=viewergpl$ + * + * Copyright (c) 2003-2009, Linden Research, Inc. 2019, Liru Frs + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llnameui.h" + +#include "llagentdata.h" +#include "llavataractions.h" +#include "llavatarnamecache.h" +#include "llexperiencecache.h" +#include "llfloaterexperienceprofile.h" +#include "llgroupactions.h" +#include "lltrans.h" + +#include "rlvactions.h" +#include "rlvcommon.h" + +// statics +std::set LLNameUI::sInstances; + +LLNameUI::LLNameUI(const std::string& loading, bool rlv_sensitive, const LLUUID& id, const Type& type, const std::string& name_system, bool click_for_profile) +: mNameID(id), mRLVSensitive(rlv_sensitive), mType(NONE), mAllowInteract(false) +, mNameSystem(name_system.empty() ? "PhoenixNameSystem" : name_system), mInitialValue(!loading.empty() ? loading : LLTrans::getString("LoadingData")) +, mClickForProfile(click_for_profile) +{ + setType(type); +} + +void LLNameUI::setType(const Type& type) +{ + // Disconnect active connections if needed + for (auto& connection : mConnections) + connection.disconnect(); + + if (mType != type) + { + if (type == GROUP) + sInstances.insert(this); + else + { + sInstances.erase(this); + if (type == AVATAR) + mConnections[1] = gSavedSettings.getControl(mNameSystem)->getCommitSignal()->connect(boost::bind(&LLNameUI::setNameText, this)); + } + mType = type; + } +} + +void LLNameUI::setNameID(const LLUUID& name_id, const Type& type) +{ + mNameID = name_id; + setType(type); + + if (mAllowInteract = mNameID.notNull()) + { + setNameText(); + } + else + { + setText(LLTrans::getString(mType == GROUP ? "GroupNameNone" : + mType == AVATAR ? "AvatarNameNobody" : "ExperienceNameNull")); + displayAsLink(false); + } +} + +void LLNameUI::setNameText() +{ + std::string name; + bool got_name = false; + + if (mType == GROUP) + { + got_name = gCacheName->getGroupName(mNameID, name); + } + else if (mType == EXPERIENCE) + { + auto& cache = LLExperienceCache::instance(); + const auto& exp = cache.get(mNameID); + if (got_name = exp.isMap()) + name = exp.has(LLExperienceCache::MISSING) && exp[LLExperienceCache::MISSING] ? LLTrans::getString("ExperienceNameNull") : exp[LLExperienceCache::NAME].asString(); + else + cache.get(mNameID, boost::bind(&LLNameUI::setNameText, this)); + } + else + { + LLAvatarName av_name; + if (got_name = LLAvatarNameCache::get(mNameID, &av_name)) + name = mNameSystem.empty() ? av_name.getNSName() : av_name.getNSName(gSavedSettings.getS32(mNameSystem)); + else + mConnections[0] = LLAvatarNameCache::get(mNameID, boost::bind(&LLNameUI::setNameText, this)); + } + + if (mType == AVATAR && got_name && mRLVSensitive) // Filter if needed + { + if ((RlvActions::hasBehaviour(RLV_BHVR_SHOWNAMES) || RlvActions::hasBehaviour(RLV_BHVR_SHOWNAMETAGS)) + && mNameID != gAgentID && RlvUtil::isNearbyAgent(mNameID)) + { + mAllowInteract = false; + name = RlvStrings::getAnonym(name); + } + else mAllowInteract = true; + } + + displayAsLink(mAllowInteract); + + // Got the name already? Set it. + // Otherwise it will be set later in refresh(). + setText(got_name ? name : mInitialValue); +} + +void LLNameUI::refresh(const LLUUID& id, const std::string& full_name) +{ + if (id == mNameID) + { + setNameText(); + } +} + +void LLNameUI::refreshAll(const LLUUID& id, const std::string& full_name) +{ + for (auto box : sInstances) + { + box->refresh(id, full_name); + } +} + +void LLNameUI::showProfile() +{ + if (!mAllowInteract) return; + + switch (mType) + { + case LFIDBearer::GROUP: LLGroupActions::show(mNameID); break; + case LFIDBearer::AVATAR: LLAvatarActions::showProfile(mNameID); break; + case LFIDBearer::EXPERIENCE: LLFloaterExperienceProfile::showInstance(mNameID); break; + default: break; + } +} diff --git a/indra/newview/llnameui.h b/indra/newview/llnameui.h new file mode 100644 index 0000000000..bade1a1cf1 --- /dev/null +++ b/indra/newview/llnameui.h @@ -0,0 +1,86 @@ +/** + * @file llnameui.h + * @brief display and refresh a name from the name cache + * + * $LicenseInfo:firstyear=2003&license=viewergpl$ + * + * Copyright (c) 2003-2009, Linden Research, Inc. 2019, Liru Frs + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#pragma once + +#include + +#include "lfidbearer.h" + +struct LLNameUI : public LFIDBearer +{ + LLNameUI(const std::string& loading = LLStringUtil::null, bool rlv_sensitive = false, const LLUUID& id = LLUUID::null, const Type& type = AVATAR, const std::string& name_system = LLStringUtil::null, bool click_for_profile = true); + virtual ~LLNameUI() + { + if (mType == GROUP) sInstances.erase(this); + for (auto& connection : mConnections) + connection.disconnect(); + } + + LLUUID getStringUUIDSelectedItem() const override final { return mNameID; } + Type getSelectedType() const override final { return mType; } + + void setType(const Type& type); + void setNameID(const LLUUID& name_id, const Type& type); + void setNameText(); // Sets the name to whatever the name cache has at the moment + void refresh(const LLUUID& id, const std::string& name); + static void refreshAll(const LLUUID& id, const std::string& name); + + void showProfile(); + + virtual void displayAsLink(bool link) = 0; // Override to make the name display as a link + virtual void setText(const std::string& text) = 0; + + // Take either UUID or a map of "id" to UUID and "group" to boolean + virtual void setValue(const LLSD& value) + { + if (value.has("id")) + setNameID(value["id"].asUUID(), (Type)value["type"].asInteger()); + else + setNameID(value.asUUID(), mType); + } + // Return agent UUIDs + virtual LLSD getValue() const { return LLSD(mNameID); } + +private: + static std::set sInstances; + std::array mConnections; + +protected: + LLUUID mNameID; + bool mRLVSensitive; // Whether or not we're doing RLV filtering + Type mType; + bool mAllowInteract; + std::string mInitialValue; + std::string mNameSystem; + bool mClickForProfile; +}; diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp index 7094c67b1e..727597f244 100644 --- a/indra/newview/llnetmap.cpp +++ b/indra/newview/llnetmap.cpp @@ -1,7 +1,7 @@ /** * @file llnetmap.cpp * @author James Cook - * @brief Display of surrounding regions, objects, and agents. View contained by LLFloaterMap. + * @brief Display of surrounding regions, objects, and agents. * * $LicenseInfo:firstyear=2001&license=viewergpl$ * @@ -35,41 +35,49 @@ #include "llnetmap.h" -#include "llmath.h" // clampf() +#include "llmath.h" #include "llfocusmgr.h" #include "lllocalcliprect.h" +#include "llmenugl.h" #include "llrender.h" +#include "lltextbox.h" +#include "lluictrlfactory.h" -#include "llfloateravatarlist.h" +#include "llglheaders.h" +// Viewer includes #include "llagent.h" #include "llagentcamera.h" +#include "llappviewer.h" // for gDisconnected #include "llavataractions.h" #include "llavatarnamecache.h" #include "llcallingcard.h" #include "llcolorscheme.h" +#include "llfloatermap.h" #include "llfloaterworldmap.h" #include "llframetimer.h" +// [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-06-20 (Catznip-3.3.0) +#include "llparcel.h" +// [/SL:KB] #include "lltracker.h" -#include "llmenugl.h" #include "llsurface.h" -#include "lltextbox.h" -#include "lluictrlfactory.h" #include "llviewercamera.h" #include "llviewertexturelist.h" #include "llviewermenu.h" #include "llviewerobjectlist.h" +// [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-06-20 (Catznip-3.3.0) +#include "llviewerparcelmgr.h" +#include "llviewerparceloverlay.h" +// [/SL:KB] #include "llviewerregion.h" #include "llviewerwindow.h" -#include "llvoavatar.h" #include "llworld.h" #include "llworldmapview.h" // shared draw code -#include "llappviewer.h" // Only for constants! - -#include "llglheaders.h" // -#include "llmutelist.h" +#include "lfsimfeaturehandler.h" +#include "llfloateravatarlist.h" +#include "llvoavatar.h" // // [RLVa:KB] @@ -77,10 +85,87 @@ // [/RLVa:KB] using namespace LLOldEvents; +typedef LLMemberListener view_listener_t; + +class LLScaleMap : public view_listener_t +{ +public: + /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata) override final; +}; + +class LLChatRings : public view_listener_t +{ +public: + /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata) override final; +}; + +class LLCheckChatRings : public view_listener_t +{ +public: + /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata) override final; +}; + +class LLStopTracking : public view_listener_t +{ +public: + /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata) override final; +}; + +class LLIsTracking : public view_listener_t +{ +public: + /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata) override final; +}; + +//moymod - Custom minimap markers :o +class mmsetred : public view_listener_t //moymod +{ +public: + /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata) override final; +}; +class mmsetgreen : public view_listener_t //moymod +{ +public: + /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata) override final; +}; +class mmsetblue : public view_listener_t //moymod +{ +public: + /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata) override final; +}; +class mmsetyellow : public view_listener_t //moymod +{ +public: + /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata) override final; +}; +class mmsetcustom : public view_listener_t //moymod +{ +public: + /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata) override final; +}; +class mmsetunmark : public view_listener_t //moymod +{ +public: + /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata) override final; +}; +class mmenableunmark : public view_listener_t //moymod +{ +public: + /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata) override final; +}; + +// [SL:KB] - Patch: World-MiniMap | Checked: 2012-07-08 (Catznip-3.3.0) +class OverlayToggle : public view_listener_t +{ +public: + /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata) override final; +}; +// [/SL:KB] + +const F32 LLNetMap::MAP_SCALE_MIN = 32; +const F32 LLNetMap::MAP_SCALE_MID = 256; +const F32 LLNetMap::MAP_SCALE_MAX = 4096; -const F32 MAP_SCALE_MIN = 32; -const F32 MAP_SCALE_MID = 256; -const F32 MAP_SCALE_MAX = 4096; const F32 MAP_SCALE_INCREMENT = 16; const F32 MAP_SCALE_ZOOM_FACTOR = 1.1f; // Zoom in factor per click of the scroll wheel (10%) const F32 MAP_MINOR_DIR_THRESHOLD = 0.08f; @@ -89,67 +174,95 @@ const F32 DOT_SCALE = 0.75f; const F32 MIN_PICK_SCALE = 2.f; const S32 MOUSE_DRAG_SLOP = 2; // How far the mouse needs to move before we think it's a drag +const F32 WIDTH_PIXELS = 2.f; +const S32 CIRCLE_STEPS = 100; + +const F64 COARSEUPDATE_MAX_Z = 1020.0f; + +std::map LLNetMap::mClosestAgentsToCursor; // +uuid_vec_t LLNetMap::mClosestAgentsAtLastClick; // + LLNetMap::LLNetMap(const std::string& name) : LLPanel(name), mScale(128.f), mObjectMapTPM(1.f), mObjectMapPixels(255.f), - mTargetPanX( 0.f ), - mTargetPanY( 0.f ), - mCurPanX( 0.f ), - mCurPanY( 0.f ), - mUpdateNow( FALSE ) + mPickRadius(gSavedSettings, "ExodusMinimapAreaEffect"), // + mTargetPan(0.f, 0.f), + mCurPan(0.f, 0.f), + mStartPan(0.f, 0.f), + mMouseDown(0, 0), + mPanning(false), +// mUpdateNow( false ), +// [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-06-20 (Catznip-3.3.0) + mUpdateObjectImage(false), + mUpdateParcelImage(false), +// [/SL:KB] + mObjectImageCenterGlobal( gAgentCamera.getCameraPositionGlobal() ), + mObjectRawImagep(), + mObjectImagep(), +// [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-06-20 (Catznip-3.3.0) + mParcelImageCenterGlobal( gAgentCamera.getCameraPositionGlobal() ), + mParcelRawImagep(), + mParcelImagep(), +// [/SL:KB] + mClosestAgentToCursor(), + mPopupMenu(NULL) { - mScale = gSavedSettings.getF32("MiniMapScale"); - mPixelsPerMeter = mScale / LLWorld::getInstance()->getRegionWidthInMeters(); - mDotRadius = llmax(DOT_SCALE * mPixelsPerMeter, MIN_DOT_RADIUS); - - mObjectImageCenterGlobal = gAgentCamera.getCameraPositionGlobal(); - - // Register event listeners for popup menu - (new LLScaleMap())->registerListener(this, "MiniMap.ZoomLevel"); - (new LLCenterMap())->registerListener(this, "MiniMap.Center"); - (new LLCheckCenterMap())->registerListener(this, "MiniMap.CheckCenter"); - (new LLRotateMap())->registerListener(this, "MiniMap.Rotate"); - (new LLCheckRotateMap())->registerListener(this, "MiniMap.CheckRotate"); - (new LLStopTracking())->registerListener(this, "MiniMap.StopTracking"); - (new LLEnableTracking())->registerListener(this, "MiniMap.EnableTracking"); - (new LLShowAgentProfile())->registerListener(this, "MiniMap.ShowProfile"); - (new LLEnableProfile())->registerListener(this, "MiniMap.EnableProfile"); - (new LLCamFollow())->registerListener(this, "MiniMap.CamFollow"); //moymod - add cam follow crap thingie - (new mmsetred())->registerListener(this, "MiniMap.setred"); - (new mmsetgreen())->registerListener(this, "MiniMap.setgreen"); - (new mmsetblue())->registerListener(this, "MiniMap.setblue"); - (new mmsetyellow())->registerListener(this, "MiniMap.setyellow"); - (new mmsetcustom())->registerListener(this, "MiniMap.setcustom"); - (new mmsetunmark())->registerListener(this, "MiniMap.setunmark"); - (new mmenableunmark())->registerListener(this, "MiniMap.enableunmark"); + setScale(gSavedSettings.getF32("MiniMapScale")); LLUICtrlFactory::getInstance()->buildPanel(this, "panel_mini_map.xml"); - - updateMinorDirections(); - - LLMenuGL* menu = LLUICtrlFactory::getInstance()->buildMenu("menu_mini_map.xml", this); - if (!menu) - { - menu = new LLMenuGL(LLStringUtil::null); - } - menu->setVisible(FALSE); - mPopupMenuHandle = menu->getHandle(); } LLNetMap::~LLNetMap() { + gSavedSettings.setF32("MiniMapScale", mScale); +} + +BOOL LLNetMap::postBuild() +{ + mELabel = getChild("e_label"); + mNLabel = getChild("n_label"); + mWLabel = getChild("w_label"); + mSLabel = getChild("s_label"); + mNELabel = getChild("ne_label"); + mNWLabel = getChild("nw_label"); + mSWLabel = getChild("sw_label"); + mSELabel = getChild("se_label"); + + // Register event listeners for popup menu + (new LLScaleMap())->registerListener(gMenuHolder, "MiniMap.ZoomLevel"); + (new LLChatRings())->registerListener(gMenuHolder, "MiniMap.ChatRings"); + (new LLCheckChatRings())->registerListener(gMenuHolder, "MiniMap.CheckChatRings"); + (new LLStopTracking())->registerListener(gMenuHolder, "StopTracking"); + (new LLIsTracking())->registerListener(gMenuHolder, "IsTracking"); + (new mmsetred())->registerListener(gMenuHolder, "MiniMap.setred"); + (new mmsetgreen())->registerListener(gMenuHolder, "MiniMap.setgreen"); + (new mmsetblue())->registerListener(gMenuHolder, "MiniMap.setblue"); + (new mmsetyellow())->registerListener(gMenuHolder, "MiniMap.setyellow"); + (new mmsetcustom())->registerListener(gMenuHolder, "MiniMap.setcustom"); + (new mmsetunmark())->registerListener(gMenuHolder, "MiniMap.setunmark"); + (new mmenableunmark())->registerListener(gMenuHolder, "MiniMap.enableunmark"); + (new OverlayToggle())->registerListener(gMenuHolder, "Minimap.ToggleOverlay"); + +// [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-06-20 (Catznip-3.3.0) + LLViewerParcelMgr::instance().setCollisionUpdateCallback(boost::bind(&LLNetMap::refreshParcelOverlay, this)); + LLViewerParcelOverlay::setUpdateCallback(boost::bind(&LLNetMap::refreshParcelOverlay, this)); +// [/SL:KB] + + updateMinorDirections(); + + mPopupMenu = LLUICtrlFactory::getInstance()->buildMenu("menu_mini_map.xml", gMenuHolder); + if (!mPopupMenu) mPopupMenu = new LLMenuGL(LLStringUtil::null); + mPopupMenu->setVisible(FALSE); + return TRUE; } void LLNetMap::setScale( F32 scale ) { + scale = llclamp(scale, MAP_SCALE_MIN, MAP_SCALE_MAX); + mCurPan *= scale / mScale; mScale = scale; - if (mScale == 0.f) - { - mScale = 0.1f; - } - gSavedSettings.setF32("MiniMapScale", mScale); if (mObjectImagep.notNull()) { @@ -157,77 +270,106 @@ void LLNetMap::setScale( F32 scale ) F32 height = (F32)(getRect().getHeight()); F32 diameter = sqrt(width * width + height * height); F32 region_widths = diameter / mScale; - F32 meters = region_widths * LLWorld::getInstance()->getRegionWidthInMeters(); +// Aurora Sim + //F32 meters = region_widths * LLWorld::getInstance()->getRegionWidthInMeters(); + F32 meters = region_widths * REGION_WIDTH_METERS; +// Aurora Sim F32 num_pixels = (F32)mObjectImagep->getWidth(); mObjectMapTPM = num_pixels / meters; mObjectMapPixels = diameter; } - mPixelsPerMeter = mScale / LLWorld::getInstance()->getRegionWidthInMeters(); + mPixelsPerMeter = mScale / REGION_WIDTH_METERS; mDotRadius = llmax(DOT_SCALE * mPixelsPerMeter, MIN_DOT_RADIUS); - mUpdateNow = TRUE; -} - -void LLNetMap::translatePan( F32 delta_x, F32 delta_y ) -{ - mTargetPanX += delta_x; - mTargetPanY += delta_y; +// [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-06-20 (Catznip-3.3.0) + mUpdateObjectImage = true; + mUpdateParcelImage = true; +// [/SL:KB] +// mUpdateNow = true; } /////////////////////////////////////////////////////////////////////////////////// std::size_t hash_value(const LLUUID& uuid) { - return (std::size_t)uuid.getCRC32(); + return (std::size_t)uuid.getCRC32(); } boost::unordered_map mm_MarkerColors; +const LLColor4* mm_getMarkerColor(const LLUUID& id, bool mark_only) +{ + if (!mark_only) // They're trying to get the color and they're not the minimap or the radar mark + { + static const LLCachedControl use_marked_color("LiruUseMarkedColor"); + if (!use_marked_color) return nullptr; + } + auto it = mm_MarkerColors.find(id); + return it == mm_MarkerColors.end() ? nullptr : &it->second; +} +const LLColor4* mm_getMarkerColor(const LLUUID& id) { return mm_getMarkerColor(id, false); } + +bool mm_getMarkerColor(const LLUUID& id, LLColor4& color) +{ + auto c = mm_getMarkerColor(id); + if (c) color = *c; + return c; +} -void LLNetMap::mm_setcolor(LLUUID key,LLColor4 col) +void mm_clearMark(const LLUUID& id) +{ + mm_MarkerColors.erase(id); +} + +void mm_setcolor(LLUUID key,LLColor4 col) { mm_MarkerColors[key] = col; } void LLNetMap::draw() { + LLViewerRegion* region = gAgent.getRegion(); + + if (region == NULL) return; + static LLFrameTimer map_timer; + static LLUIColor map_track_color = gTrackColor; + static const LLCachedControl map_frustum_color(gColors, "NetMapFrustum", LLColor4::white); + static const LLCachedControl map_frustum_rotating_color(gColors, "NetMapFrustumRotating", LLColor4::white); +// [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-08-17 (Catznip-3.3.0) + static const LLCachedControl map_property_line("MiniMapPropertyLine", LLColor4::white); +// [/SL:KB] + static const LLCachedControl map_whisper_ring_color("MiniMapWhisperRingColor", LLColor4(0.f,1.f,0.f,0.5f)); + static const LLCachedControl map_chat_ring_color("MiniMapChatRingColor", LLColor4(0.f,0.f,1.f,0.5f)); + static const LLCachedControl map_shout_ring_color("MiniMapShoutRingColor", LLColor4(1.f,0.f,0.f,0.5f)); if (mObjectImagep.isNull()) { createObjectImage(); } - if (gSavedSettings.getS32( "MiniMapCenter") != MAP_CENTER_NONE) +// [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-06-20 (Catznip-3.3.0) + if (mParcelImagep.isNull()) { - mCurPanX = lerp(mCurPanX, mTargetPanX, LLCriticalDamp::getInterpolant(0.1f)); - mCurPanY = lerp(mCurPanY, mTargetPanY, LLCriticalDamp::getInterpolant(0.1f)); + createParcelImage(); } +// [/SL:KB] - F32 rotation = 0; + static const LLUICachedControl center("MiniMapCenter"); + if (center) + { + mCurPan = lerp(mCurPan, mTargetPan, LLSmoothInterpolation::getInterpolant(0.1f)); + } + // Prepare a scissor region + F32 rotation = 0; - gGL.pushMatrix(); gGL.pushUIMatrix(); - - LLVector3 offset = gGL.getUITranslation(); - LLVector3 scale = gGL.getUIScale(); - gGL.loadIdentity(); - gGL.loadUIIdentity(); - - gGL.scalef(scale.mV[0], scale.mV[1], scale.mV[2]); - gGL.translatef(offset.mV[0], offset.mV[1], offset.mV[2]); - - // Prepare a scissor region { - LLGLEnable scissor(GL_SCISSOR_TEST); - + LLLocalClipRect clip(getLocalRect()); { gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - LLLocalClipRect clip(getLocalRect()); - - gGL.matrixMode(LLRender::MM_MODELVIEW); - // Draw background rectangle + // Draw background rectangle. if(isBackgroundVisible()) { LLColor4 background_color = isBackgroundOpaque() ? getBackgroundColor().mV : getTransparentColor().mV; @@ -236,62 +378,110 @@ void LLNetMap::draw() } } - // region 0,0 is in the middle - S32 center_sw_left = getRect().getWidth() / 2 + llfloor(mCurPanX); - S32 center_sw_bottom = getRect().getHeight() / 2 + llfloor(mCurPanY); + // Region 0,0 is in the middle. + S32 center_sw_left = getRect().getWidth() / 2 + llfloor(mCurPan.mV[VX]); + S32 center_sw_bottom = getRect().getHeight() / 2 + llfloor(mCurPan.mV[VY]); - gGL.pushMatrix(); + gGL.pushUIMatrix(); + gGL.translateUI( (F32) center_sw_left, (F32) center_sw_bottom, 0.f); - gGL.translatef( (F32) center_sw_left, (F32) center_sw_bottom, 0.f); - static LLCachedControl rotate_map("MiniMapRotate", true); if (rotate_map) { - // rotate subsequent draws to agent rotation + // Rotate subsequent draws to agent rotation. rotation = atan2( LLViewerCamera::getInstance()->getAtAxis().mV[VX], LLViewerCamera::getInstance()->getAtAxis().mV[VY] ); - gGL.rotatef( rotation * RAD_TO_DEG, 0.f, 0.f, 1.f); + LLQuaternion rot(rotation, LLVector3(0.f, 0.f, 1.f)); + gGL.rotateUI(rot); } - // figure out where agent is - LLColor4 this_region_color = gColors.getColor( "NetMapThisRegion" ); - LLColor4 live_region_color = gColors.getColor( "NetMapLiveRegion" ); - LLColor4 dead_region_color = gColors.getColor( "NetMapDeadRegion" ); + // Figure out where agent is. + static const LLCachedControl this_region_color(gColors, "NetMapThisRegion"); + static const LLCachedControl live_region_color(gColors, "NetMapLiveRegion"); + static const LLCachedControl dead_region_color(gColors, "NetMapDeadRegion"); +// Aurora Sim + //S32 region_width = ll_round(LLWorld::getInstance()->getRegionWidthInMeters()); + S32 region_width = REGION_WIDTH_UNITS; +// Aurora Sim for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); iter != LLWorld::getInstance()->getRegionList().end(); ++iter) { LLViewerRegion* regionp = *iter; - S32 region_width = llround(regionp->getWidth()); + // Find x and y position relative to camera's center. LLVector3 origin_agent = regionp->getOriginAgent(); LLVector3 rel_region_pos = origin_agent - gAgentCamera.getCameraPositionAgent(); F32 relative_x = (rel_region_pos.mV[0] / region_width) * mScale; F32 relative_y = (rel_region_pos.mV[1] / region_width) * mScale; - // background region rectangle + const F32 real_width(regionp->getWidth()); + // Background region rectangle. F32 bottom = relative_y; F32 left = relative_x; - F32 top = bottom + mScale ; - F32 right = left + mScale ; - - gGL.color4fv(regionp == gAgent.getRegion() ? this_region_color.mV : live_region_color.mV); - if (!regionp->isAlive()) +// Aurora Sim + //F32 top = bottom + mScale ; + //F32 right = left + mScale ; + F32 top = bottom + (real_width / REGION_WIDTH_METERS) * mScale ; + F32 right = left + (real_width / REGION_WIDTH_METERS) * mScale ; +// Aurora Sim + + if (regionp == region) gGL.color4fv(this_region_color().mV); + else if (!regionp->isAlive()) gGL.color4fv(dead_region_color().mV); + else gGL.color4fv(live_region_color().mV); + +// [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-07-26 (Catznip-3.3) + static LLCachedControl s_fUseWorldMapTextures(gSavedSettings, "MiniMapWorldMapTextures"); + bool fRenderTerrain = true; + + if (s_fUseWorldMapTextures) { - gGL.color4fv(dead_region_color.mV); - } + const LLViewerRegion::tex_matrix_t& tiles(regionp->getWorldMapTiles()); + for (S32 i(0), scaled_width((S32)real_width/region_width), square_width(scaled_width*scaled_width); i < square_width; ++i) + { + const F32 y(i / (F32)scaled_width); + const F32 x(i - y*scaled_width); + const F32 local_left(left + x*mScale); + const F32 local_right(local_left + mScale); + const F32 local_bottom(bottom + y*mScale); + const F32 local_top(local_bottom + mScale); + LLViewerTexture* pRegionImage = tiles[x*scaled_width+y]; + if (pRegionImage && pRegionImage->hasGLTexture()) + { + gGL.getTexUnit(0)->bind(pRegionImage); + gGL.begin(LLRender::TRIANGLE_STRIP); + gGL.texCoord2f(0.f, 1.f); + gGL.vertex2f(local_left, local_top); + gGL.texCoord2f(0.f, 0.f); + gGL.vertex2f(local_left, local_bottom); + gGL.texCoord2f(1.f, 1.f); + gGL.vertex2f(local_right, local_top); + gGL.texCoord2f(1.f, 0.f); + gGL.vertex2f(local_right, local_bottom); + gGL.end(); + + pRegionImage->setBoostLevel(LLViewerTexture::BOOST_MAP_VISIBLE); + fRenderTerrain = false; + } + } + } +// [/SL:KB] +// [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-07-26 (Catznip-3.3) + if (fRenderTerrain) + { +// [/SL:KB] // Draw using texture. gGL.getTexUnit(0)->bind(regionp->getLand().getSTexture()); - gGL.begin(LLRender::QUADS); + gGL.begin(LLRender::TRIANGLE_STRIP); gGL.texCoord2f(0.f, 1.f); gGL.vertex2f(left, top); gGL.texCoord2f(0.f, 0.f); gGL.vertex2f(left, bottom); - gGL.texCoord2f(1.f, 0.f); - gGL.vertex2f(right, bottom); gGL.texCoord2f(1.f, 1.f); gGL.vertex2f(right, top); + gGL.texCoord2f(1.f, 0.f); + gGL.vertex2f(right, bottom); gGL.end(); // Draw water @@ -300,186 +490,299 @@ void LLNetMap::draw() if (regionp->getLand().getWaterTexture()) { gGL.getTexUnit(0)->bind(regionp->getLand().getWaterTexture()); - gGL.begin(LLRender::QUADS); + gGL.begin(LLRender::TRIANGLE_STRIP); gGL.texCoord2f(0.f, 1.f); gGL.vertex2f(left, top); gGL.texCoord2f(0.f, 0.f); gGL.vertex2f(left, bottom); - gGL.texCoord2f(1.f, 0.f); - gGL.vertex2f(right, bottom); gGL.texCoord2f(1.f, 1.f); gGL.vertex2f(right, top); + gGL.texCoord2f(1.f, 0.f); + gGL.vertex2f(right, bottom); gGL.end(); } } gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); +// [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-07-26 (Catznip-3.3) + } +// [/SL:KB] } // Redraw object layer periodically - if (mUpdateNow || (map_timer.getElapsedTimeF32() > 0.5f)) +// if (mUpdateNow || (map_timer.getElapsedTimeF32() > 0.5f)) +// { +// mUpdateNow = false; +// [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-06-20 (Catznip-3.3.0) + // Locate the center + LLVector3 posCenter = globalPosToView(gAgentCamera.getCameraPositionGlobal()); + posCenter.mV[VX] -= mCurPan.mV[VX]; + posCenter.mV[VY] -= mCurPan.mV[VY]; + posCenter.mV[VZ] = 0.f; + LLVector3d posCenterGlobal = viewPosToGlobal(llfloor(posCenter.mV[VX]), llfloor(posCenter.mV[VY])); + + static LLCachedControl s_fShowObjects(gSavedSettings, "ShowMiniMapObjects") ; + if ( (s_fShowObjects) && ((mUpdateObjectImage) || ((map_timer.getElapsedTimeF32() > 0.5f))) ) { - mUpdateNow = false; - - // Locate the centre of the object layer, accounting for panning - LLVector3 new_center = globalPosToView(gAgentCamera.getCameraPositionGlobal(), rotate_map); - new_center.mV[VX] -= mCurPanX; - new_center.mV[VY] -= mCurPanY; - new_center.mV[VZ] = 0.f; - mObjectImageCenterGlobal = viewPosToGlobal(llround(new_center.mV[VX]), llround(new_center.mV[VY]), rotate_map); + mUpdateObjectImage = false; +// [/SL:KB] + +// // Locate the centre of the object layer, accounting for panning +// LLVector3 new_center = globalPosToView(gAgentCamera.getCameraPositionGlobal()); +// new_center.mV[VX] -= mCurPan.mV[VX]; +// new_center.mV[VY] -= mCurPan.mV[VY]; +// new_center.mV[VZ] = 0.f; +// mObjectImageCenterGlobal = viewPosToGlobal(llfloor(new_center.mV[VX]), llfloor(new_center.mV[VY])); +// [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-06-20 (Catznip-3.3.0) + mObjectImageCenterGlobal = posCenterGlobal; +// [/SL:KB] // Create the base texture. U8 *default_texture = mObjectRawImagep->getData(); memset( default_texture, 0, mObjectImagep->getWidth() * mObjectImagep->getHeight() * mObjectImagep->getComponents() ); - // Draw buildings + // Draw objects gObjectList.renderObjectsForMap(*this); mObjectImagep->setSubImage(mObjectRawImagep, 0, 0, mObjectImagep->getWidth(), mObjectImagep->getHeight()); - map_timer.reset(); } +// [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-06-20 (Catznip-3.3.0) + static LLCachedControl s_fShowPropertyLines(gSavedSettings, "MiniMapPropertyLines") ; + if ( (s_fShowPropertyLines) && ((mUpdateParcelImage) || (dist_vec_squared2D(mParcelImageCenterGlobal, posCenterGlobal) > 9.0f)) ) + { + mUpdateParcelImage = false; + mParcelImageCenterGlobal = posCenterGlobal; + + U8* pTextureData = mParcelRawImagep->getData(); + memset(pTextureData, 0, mParcelImagep->getWidth() * mParcelImagep->getHeight() * mParcelImagep->getComponents()); + + // Process each region + for (LLWorld::region_list_t::const_iterator itRegion = LLWorld::getInstance()->getRegionList().begin(); + itRegion != LLWorld::getInstance()->getRegionList().end(); ++itRegion) + { + const LLViewerRegion* pRegion = *itRegion; LLColor4U clrOverlay; + if (pRegion->isAlive()) + clrOverlay = map_property_line.get(); + else + clrOverlay = LLColor4U(255, 128, 128, 255); + renderPropertyLinesForRegion(pRegion, clrOverlay); + } + + mParcelImagep->setSubImage(mParcelRawImagep, 0, 0, mParcelImagep->getWidth(), mParcelImagep->getHeight()); + } +// [/SL:KB] + LLVector3 map_center_agent = gAgent.getPosAgentFromGlobal(mObjectImageCenterGlobal); - map_center_agent -= gAgentCamera.getCameraPositionAgent(); - map_center_agent.mV[0] *= mScale/LLWorld::getInstance()->getRegionWidthInMeters(); - map_center_agent.mV[1] *= mScale/LLWorld::getInstance()->getRegionWidthInMeters(); + LLVector3 camera_position = gAgentCamera.getCameraPositionAgent(); + map_center_agent -= camera_position; + map_center_agent.mV[VX] *= mScale/region_width; + map_center_agent.mV[VY] *= mScale/region_width; - gGL.getTexUnit(0)->bind(mObjectImagep); +// gGL.getTexUnit(0)->bind(mObjectImagep); F32 image_half_width = 0.5f*mObjectMapPixels; F32 image_half_height = 0.5f*mObjectMapPixels; - gGL.begin(LLRender::QUADS); +// [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-07-26 (Catznip-3.3) + if (s_fShowObjects) + { + gGL.getTexUnit(0)->bind(mObjectImagep); +// [/SL:KB] + gGL.begin(LLRender::TRIANGLE_STRIP); gGL.texCoord2f(0.f, 1.f); gGL.vertex2f(map_center_agent.mV[VX] - image_half_width, image_half_height + map_center_agent.mV[VY]); gGL.texCoord2f(0.f, 0.f); gGL.vertex2f(map_center_agent.mV[VX] - image_half_width, map_center_agent.mV[VY] - image_half_height); - gGL.texCoord2f(1.f, 0.f); - gGL.vertex2f(image_half_width + map_center_agent.mV[VX], map_center_agent.mV[VY] - image_half_height); gGL.texCoord2f(1.f, 1.f); gGL.vertex2f(image_half_width + map_center_agent.mV[VX], image_half_height + map_center_agent.mV[VY]); + gGL.texCoord2f(1.f, 0.f); + gGL.vertex2f(image_half_width + map_center_agent.mV[VX], map_center_agent.mV[VY] - image_half_height); gGL.end(); +// [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-07-26 (Catznip-3.3) + } +// [/SL:KB] - gGL.popMatrix(); +// [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-06-20 (Catznip-3.3.0) + if (s_fShowPropertyLines) + { + map_center_agent = gAgent.getPosAgentFromGlobal(mParcelImageCenterGlobal) - camera_position; + map_center_agent.mV[VX] *= mScale / region_width; + map_center_agent.mV[VY] *= mScale / region_width; - LLVector3d pos_global; - LLVector3 pos_map; + gGL.getTexUnit(0)->bind(mParcelImagep); + gGL.begin(LLRender::TRIANGLE_STRIP); + gGL.texCoord2f(0.f, 1.f); + gGL.vertex2f(map_center_agent.mV[VX] - image_half_width, image_half_height + map_center_agent.mV[VY]); + gGL.texCoord2f(0.f, 0.f); + gGL.vertex2f(map_center_agent.mV[VX] - image_half_width, map_center_agent.mV[VY] - image_half_height); + gGL.texCoord2f(1.f, 1.f); + gGL.vertex2f(image_half_width + map_center_agent.mV[VX], image_half_height + map_center_agent.mV[VY]); + gGL.texCoord2f(1.f, 0.f); + gGL.vertex2f(image_half_width + map_center_agent.mV[VX], map_center_agent.mV[VY] - image_half_height); + gGL.end(); + } +// [/SL:KB] + + gGL.popUIMatrix(); // Mouse pointer in local coordinates S32 local_mouse_x; S32 local_mouse_y; + LLUI::getMousePositionLocal(this, &local_mouse_x, &local_mouse_y); - mClosestAgentToCursor.setNull(); - F32 closest_dist = F32_MAX; - F32 min_pick_dist = mDotRadius * MIN_PICK_SCALE; - // Draw avatars -// LLColor4 mapcolor = gAvatarMapColor; + F32 min_pick_dist = mDotRadius * mPickRadius; - static const LLCachedControl standard_color(gColors,"MapAvatar",LLColor4(0.f,1.f,0.f,1.f)); - static const LLCachedControl friend_color_stored("AscentFriendColor",LLColor4(1.f,1.f,0.f,1.f)); - static const LLCachedControl em_color("AscentEstateOwnerColor",LLColor4(1.f,0.6f,1.f,1.f)); - static const LLCachedControl linden_color("AscentLindenColor",LLColor4(0.f,0.f,1.f,1.f)); - static const LLCachedControl muted_color("AscentMutedColor",LLColor4(0.7f,0.7f,0.7f,1.f)); + mClosestAgentToCursor.setNull(); + mClosestAgentsToCursor.clear(); - // Draw avatars + F32 closest_dist_squared = F32_MAX; + F32 min_pick_dist_squared = (mDotRadius * MIN_PICK_SCALE) * (mDotRadius * MIN_PICK_SCALE); + + LLVector3 pos_map; // [RLVa:KB] - Version: 1.23.4 | Alternate: Snowglobe-1.2.4 | Checked: 2009-07-08 (RLVa-1.0.0e) | Modified: RLVa-0.2.0b - LLColor4 friend_color = (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) ? friend_color_stored : standard_color; + bool show_friends = !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES); // [/RLVa:KB] - std::vector avatar_ids; - std::vector positions; - LLWorld::getInstance()->getAvatars(&avatar_ids, &positions); - for(U32 i=0; igetAvatars(&positions, gAgentCamera.getCameraPositionGlobal()); + + // Get the selected ids from radar now, as they are loop invariant + uuid_vec_t gmSelected; + static const LLCachedControl radar_tracking_circle("MiniMapRadarTrackingCircles"); + if (radar_tracking_circle && LLFloaterAvatarList::instanceVisible()) + gmSelected = LLFloaterAvatarList::instance().getSelectedIDs(); + + // Draw avatars + for(const auto& pair : positions) { - const LLUUID &id = avatar_ids[i]; - const LLVector3d& pos = positions[i]; - LLColor4 avColor = standard_color; + const LLUUID& uuid = pair.first; + static const LLCachedControl standard_color("MapAvatar",LLColor4(0.f,1.f,0.f,1.f)); + LLColor4 color = standard_color; // TODO: it'd be very cool to draw these in sorted order from lowest Z to highest. // just be careful to sort the avatar IDs along with the positions. -MG - pos_map = globalPosToView(pos, rotate_map); - if (pos.mdV[VZ] == 0.f) + const LLVector3d& position = pair.second; + pos_map = globalPosToView(position); + if (position.mdV[VZ] == 0.f || position.mdV[VZ] == COARSEUPDATE_MAX_Z) { pos_map.mV[VZ] = 16000.f; } - std::string avName; - gCacheName->getFullName(id, avName); - if(LLMuteList::getInstance()->isMuted(id)) + if (dist_vec(LLVector2(pos_map.mV[VX], pos_map.mV[VY]), LLVector2(local_mouse_x, local_mouse_y)) < min_pick_dist) { - avColor = muted_color; + mClosestAgentsToCursor[uuid] = position; + static const LLCachedControl map_avatar_rollover_color(gSavedSettings, "ExodusMapRolloverColor", LLColor4::cyan); + color = map_avatar_rollover_color; } - - LLViewerRegion* avatar_region = LLWorld::getInstance()->getRegionFromPosGlobal(pos); - LLUUID estate_owner = avatar_region? avatar_region->getOwner() : LLUUID::null; - - // MOYMOD Minimap custom av colors. - boost::unordered_map::const_iterator it = mm_MarkerColors.find(id); - if(it != mm_MarkerColors.end()) + else if (auto mark_color = mm_getMarkerColor(uuid, true)) { - avColor = it->second; + color = *mark_color; } - //Lindens are always more Linden than your friend, make that take precedence - else if(LLMuteList::getInstance()->isLinden(id)) + else { - avColor = linden_color; - } - //check if they are an estate owner at their current position - else if(estate_owner.notNull() && id == estate_owner) - { - avColor = em_color; - } - //without these dots, SL would suck. - else if(LLAvatarActions::isFriend(id)) - { - avColor = friend_color; + bool getColorFor(const LLUUID & id, LLViewerRegion * parent_estate, LLColor4 & color, bool name_restricted = false); + getColorFor(uuid, LLWorld::getInstance()->getRegionFromPosGlobal(position), color, !show_friends); } LLWorldMapView::drawAvatar( - pos_map.mV[VX], pos_map.mV[VY], - avColor, - pos_map.mV[VZ], - mDotRadius); + pos_map.mV[VX], pos_map.mV[VY], + color, + pos_map.mV[VZ], mDotRadius); + + if (!gmSelected.empty()) + if (uuid.notNull()) + { + bool selected = false; + uuid_vec_t::iterator sel_iter = gmSelected.begin(); + + for (; sel_iter != gmSelected.end(); sel_iter++) + { + if(*sel_iter == uuid) + { + selected = true; + break; + } + } + + if (selected) + { + if( (pos_map.mV[VX] < 0) || + (pos_map.mV[VY] < 0) || + (pos_map.mV[VX] >= getRect().getWidth()) || + (pos_map.mV[VY] >= getRect().getHeight()) ) + { + S32 x = ll_round( pos_map.mV[VX] ); + S32 y = ll_round( pos_map.mV[VY] ); + + LLWorldMapView::drawTrackingCircle( getRect(), x, y, color, 1, 10); + } + else LLWorldMapView::drawTrackingDot(pos_map.mV[VX],pos_map.mV[VY],color,0.f); + } + } - F32 dist_to_cursor = dist_vec(LLVector2(pos_map.mV[VX], pos_map.mV[VY]), LLVector2(local_mouse_x,local_mouse_y)); - if(dist_to_cursor < min_pick_dist && dist_to_cursor < closest_dist) + F32 dist_to_cursor_squared = dist_vec_squared(LLVector2(pos_map.mV[VX], pos_map.mV[VY]), LLVector2(local_mouse_x,local_mouse_y)); + if (dist_to_cursor_squared < min_pick_dist_squared && dist_to_cursor_squared < closest_dist_squared) { - closest_dist = dist_to_cursor; - mClosestAgentToCursor = id; - mClosestAgentPosition = pos; + closest_dist_squared = dist_to_cursor_squared; + mClosestAgentToCursor = uuid; } } // Draw dot for autopilot target if (gAgent.getAutoPilot()) { - drawTracking(gAgent.getAutoPilotTargetGlobal(), rotate_map, gTrackColor); + drawTracking( gAgent.getAutoPilotTargetGlobal(), map_track_color ); } else { LLTracker::ETrackingStatus tracking_status = LLTracker::getTrackingStatus(); if ( LLTracker::TRACKING_AVATAR == tracking_status ) { - drawTracking(LLAvatarTracker::instance().getGlobalPos(), rotate_map, gTrackColor); + drawTracking( LLAvatarTracker::instance().getGlobalPos(), map_track_color ); } - else if ( LLTracker::TRACKING_LANDMARK == tracking_status - || LLTracker::TRACKING_LOCATION == tracking_status ) + else if ( LLTracker::TRACKING_LANDMARK == tracking_status || + LLTracker::TRACKING_LOCATION == tracking_status ) { - drawTracking(LLTracker::getTrackedPositionGlobal(), rotate_map, gTrackColor); + drawTracking( LLTracker::getTrackedPositionGlobal(), map_track_color ); } } - // Draw dot for self avatar position - pos_global = gAgent.getPositionGlobal(); - pos_map = globalPosToView(pos_global, rotate_map); + pos_map = globalPosToView(gAgent.getPositionGlobal()); + S32 dot_width = ll_round(mDotRadius * 2.f); LLUIImagePtr you = LLWorldMapView::sAvatarYouLargeImage; - S32 dot_width = llround(mDotRadius * 2.f); - you->draw( - llround(pos_map.mV[VX] - mDotRadius), - llround(pos_map.mV[VY] - mDotRadius), - dot_width, - dot_width); + + if (you) + { + you->draw(ll_round(pos_map.mV[VX] - mDotRadius), + ll_round(pos_map.mV[VY] - mDotRadius), + dot_width, + dot_width); + + F32 dist_to_cursor_squared = dist_vec_squared(LLVector2(pos_map.mV[VX], pos_map.mV[VY]), + LLVector2(local_mouse_x,local_mouse_y)); + + if (dist_to_cursor_squared < min_pick_dist_squared && dist_to_cursor_squared < closest_dist_squared) + { + mClosestAgentToCursor = gAgent.getID(); + } + } + + // Draw chat range ring(s) + static LLCachedControl whisper_ring("MiniMapWhisperRing"); + if(whisper_ring) + drawRing(LFSimFeatureHandler::getInstance()->whisperRange(), pos_map, map_whisper_ring_color); + static LLCachedControl chat_ring("MiniMapChatRing"); + if(chat_ring) + drawRing(LFSimFeatureHandler::getInstance()->sayRange(), pos_map, map_chat_ring_color); + static LLCachedControl shout_ring("MiniMapShoutRing"); + if(shout_ring) + drawRing(LFSimFeatureHandler::getInstance()->shoutRange(), pos_map, map_shout_ring_color); // Draw frustum - F32 meters_to_pixels = mScale/ LLWorld::getInstance()->getRegionWidthInMeters(); +// Aurora Sim + //F32 meters_to_pixels = mScale/ LLWorld::getInstance()->getRegionWidthInMeters(); + F32 meters_to_pixels = mScale/ REGION_WIDTH_METERS; +// Aurora Sim F32 horiz_fov = LLViewerCamera::getInstance()->getView() * LLViewerCamera::getInstance()->getAspect(); F32 far_clip_meters = LLViewerCamera::getInstance()->getFar(); @@ -494,58 +797,65 @@ void LLNetMap::draw() gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - if (rotate_map) - { - gGL.color4fv(gColors.getColor("NetMapFrustum").mV); + LLColor4 c = rotate_map ? map_frustum_color() : map_frustum_rotating_color(); - gGL.begin( LLRender::TRIANGLES ); - gGL.vertex2f( ctr_x, ctr_y ); - gGL.vertex2f( ctr_x - half_width_pixels, ctr_y + far_clip_pixels ); - gGL.vertex2f( ctr_x + half_width_pixels, ctr_y + far_clip_pixels ); - gGL.end(); - } - else + gGL.pushUIMatrix(); + + gGL.translateUI(ctr_x, ctr_y, 0); + + // If we don't rotate the map, we have to rotate the frustum. + if (!rotate_map) { - gGL.color4fv(gColors.getColor("NetMapFrustumRotating").mV); - - // If we don't rotate the map, we have to rotate the frustum. - gGL.pushMatrix(); - gGL.translatef( ctr_x, ctr_y, 0 ); - gGL.rotatef( atan2( LLViewerCamera::getInstance()->getAtAxis().mV[VX], LLViewerCamera::getInstance()->getAtAxis().mV[VY] ) * RAD_TO_DEG, 0.f, 0.f, -1.f); - gGL.begin( LLRender::TRIANGLES ); - gGL.vertex2f( 0, 0 ); - gGL.vertex2f( -half_width_pixels, far_clip_pixels ); - gGL.vertex2f( half_width_pixels, far_clip_pixels ); - gGL.end(); - gGL.popMatrix(); + LLQuaternion rot(atan2(LLViewerCamera::getInstance()->getAtAxis().mV[VX], LLViewerCamera::getInstance()->getAtAxis().mV[VY]), LLVector3(0.f, 0.f, -1.f)); + gGL.rotateUI(rot); } + + gGL.begin( LLRender::TRIANGLES ); + gGL.color4fv(c.mV); + gGL.vertex2f( 0, 0 ); + c.mV[VW] *= .1f; + gGL.color4fv(c.mV); + gGL.vertex2f( half_width_pixels, far_clip_pixels ); + gGL.vertex2f( -half_width_pixels, far_clip_pixels ); + gGL.end(); + + gGL.popUIMatrix(); + + // Draw mouse radius + static const LLCachedControl map_avatar_rollover_color("ExodusMapRolloverCircleColor"); + gGL.color4fv((map_avatar_rollover_color()).mV); + // Todo: Detect if over the window and don't render a circle? + gl_circle_2d(local_mouse_x, local_mouse_y, min_pick_dist, 32, true); + // } - - gGL.popMatrix(); + ; gGL.popUIMatrix(); - + // Rotation of 0 means that North is up - setDirectionPos( getChild("e_label"), rotation); - setDirectionPos( getChild("n_label"), rotation + F_PI_BY_TWO); - setDirectionPos( getChild("w_label"), rotation + F_PI); - setDirectionPos( getChild("s_label"), rotation + F_PI + F_PI_BY_TWO); + setDirectionPos(mELabel, rotation); + setDirectionPos(mNLabel, rotation + F_PI_BY_TWO); + setDirectionPos(mWLabel, rotation + F_PI); + setDirectionPos(mSLabel, rotation + F_PI + F_PI_BY_TWO); - setDirectionPos( getChild("ne_label"), rotation + F_PI_BY_TWO / 2); - setDirectionPos( getChild("nw_label"), rotation + F_PI_BY_TWO + F_PI_BY_TWO / 2); - setDirectionPos( getChild("sw_label"), rotation + F_PI + F_PI_BY_TWO / 2); - setDirectionPos( getChild("se_label"), rotation + F_PI + F_PI_BY_TWO + F_PI_BY_TWO / 2); + setDirectionPos(mNELabel, rotation + F_PI_BY_TWO / 2); + setDirectionPos(mNWLabel, rotation + F_PI_BY_TWO + F_PI_BY_TWO / 2); + setDirectionPos(mSWLabel, rotation + F_PI + F_PI_BY_TWO / 2); + setDirectionPos(mSELabel, rotation + F_PI + F_PI_BY_TWO + F_PI_BY_TWO / 2); - LLView::draw(); + LLUICtrl::draw(); } void LLNetMap::reshape(S32 width, S32 height, BOOL called_from_parent) { LLPanel::reshape(width, height, called_from_parent); createObjectImage(); +// [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-07-28 (Catznip-3.3) + createParcelImage(); +// [/SL:KB] updateMinorDirections(); } -LLVector3 LLNetMap::globalPosToView(const LLVector3d& global_pos, BOOL rotated) +LLVector3 LLNetMap::globalPosToView(const LLVector3d& global_pos) { LLVector3d relative_pos_global = global_pos - gAgentCamera.getCameraPositionGlobal(); LLVector3 pos_local; @@ -555,23 +865,34 @@ LLVector3 LLNetMap::globalPosToView(const LLVector3d& global_pos, BOOL rotated) pos_local.mV[VY] *= mPixelsPerMeter; // leave Z component in meters - if( rotated ) + static LLUICachedControl rotate_map("MiniMapRotate", true); + if( rotate_map ) { F32 radians = atan2( LLViewerCamera::getInstance()->getAtAxis().mV[VX], LLViewerCamera::getInstance()->getAtAxis().mV[VY] ); LLQuaternion rot(radians, LLVector3(0.f, 0.f, 1.f)); pos_local.rotVec( rot ); } - pos_local.mV[VX] += getRect().getWidth() / 2 + mCurPanX; - pos_local.mV[VY] += getRect().getHeight() / 2 + mCurPanY; + pos_local.mV[VX] += getRect().getWidth() / 2 + mCurPan.mV[VX]; + pos_local.mV[VY] += getRect().getHeight() / 2 + mCurPan.mV[VY]; return pos_local; } -void LLNetMap::drawTracking(const LLVector3d& pos_global, BOOL rotated, - const LLColor4& color, BOOL draw_arrow ) +void LLNetMap::drawRing(const F32 radius, const LLVector3 pos_map, const LLColor4& color) { - LLVector3 pos_local = globalPosToView( pos_global, rotated ); + F32 radius_pixels = radius * mPixelsPerMeter; + + gGL.pushUIMatrix(); + gGL.translateUI(pos_map.mV[VX], pos_map.mV[VY], 0.f); + gl_washer_2d(radius_pixels, radius_pixels-WIDTH_PIXELS, CIRCLE_STEPS, color, color); + gGL.popUIMatrix(); +} + +void LLNetMap::drawTracking(const LLVector3d& pos_global, const LLColor4& color, + BOOL draw_arrow ) +{ + LLVector3 pos_local = globalPosToView(pos_global); if( (pos_local.mV[VX] < 0) || (pos_local.mV[VY] < 0) || (pos_local.mV[VX] >= getRect().getWidth()) || @@ -579,8 +900,8 @@ void LLNetMap::drawTracking(const LLVector3d& pos_global, BOOL rotated, { if (draw_arrow) { - S32 x = llround( pos_local.mV[VX] ); - S32 y = llround( pos_local.mV[VY] ); + S32 x = ll_round( pos_local.mV[VX] ); + S32 y = ll_round( pos_local.mV[VY] ); LLWorldMapView::drawTrackingCircle( getRect(), x, y, color, 1, 10 ); LLWorldMapView::drawTrackingArrow( getRect(), x, y, color ); } @@ -594,22 +915,26 @@ void LLNetMap::drawTracking(const LLVector3d& pos_global, BOOL rotated, } } -LLVector3d LLNetMap::viewPosToGlobal( S32 x, S32 y, BOOL rotated ) +LLVector3d LLNetMap::viewPosToGlobal( S32 x, S32 y ) { - x -= llround(getRect().getWidth() / 2 + mCurPanX); - y -= llround(getRect().getHeight() / 2 + mCurPanY); + x -= ll_round(getRect().getWidth() / 2 + mCurPan.mV[VX]); + y -= ll_round(getRect().getHeight() / 2 + mCurPan.mV[VY]); - LLVector3 pos_local( (F32)x, (F32)y, 0.f ); + LLVector3 pos_local( (F32)x, (F32)y, 0 ); F32 radians = - atan2( LLViewerCamera::getInstance()->getAtAxis().mV[VX], LLViewerCamera::getInstance()->getAtAxis().mV[VY] ); - if( rotated ) + static LLUICachedControl rotate_map("MiniMapRotate", true); + if( rotate_map ) { LLQuaternion rot(radians, LLVector3(0.f, 0.f, 1.f)); pos_local.rotVec( rot ); } - pos_local *= ( LLWorld::getInstance()->getRegionWidthInMeters() / mScale ); +// Aurora Sim + //pos_local *= ( LLWorld::getInstance()->getRegionWidthInMeters() / mScale ); + pos_local *= ( REGION_WIDTH_METERS / mScale ); +// Aurora Sim LLVector3d pos_global; pos_global.setVec( pos_local ); @@ -620,85 +945,109 @@ LLVector3d LLNetMap::viewPosToGlobal( S32 x, S32 y, BOOL rotated ) BOOL LLNetMap::handleScrollWheel(S32 x, S32 y, S32 clicks) { + // + if (gKeyboard->currentMask(TRUE) & MASK_SHIFT) + { + mPickRadius = llclamp(mPickRadius + (2.5f * clicks), 1.f, 64.f); + return true; + } + // // note that clicks are reversed from what you'd think: i.e. > 0 means zoom out, < 0 means zoom in - F32 scale = mScale; - - scale *= pow(MAP_SCALE_ZOOM_FACTOR, -clicks); - setScale(llclamp(scale, MAP_SCALE_MIN, MAP_SCALE_MAX)); + F32 new_scale = mScale * pow(MAP_SCALE_ZOOM_FACTOR, -clicks); + F32 old_scale = mScale; + + setScale(new_scale); + + static const LLUICachedControl center("MiniMapCenter"); + if (!center) + { + // Adjust pan to center the zoom on the mouse pointer + LLVector2 zoom_offset; + zoom_offset.mV[VX] = x - getRect().getWidth() / 2; + zoom_offset.mV[VY] = y - getRect().getHeight() / 2; + mCurPan -= zoom_offset * mScale / old_scale - zoom_offset; + } return TRUE; } -BOOL LLNetMap::handleToolTip( S32 x, S32 y, std::string& msg, LLRect* sticky_rect_screen ) +BOOL LLNetMap::handleToolTip( S32 x, S32 y, std::string& tool_tip, LLRect* sticky_rect_screen ) { - BOOL handled = FALSE; if (gDisconnected) { return FALSE; } - LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal(viewPosToGlobal(x, y, gSavedSettings.getBOOL( "MiniMapRotate" ))); + + LLRect sticky_rect; + LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal(viewPosToGlobal(x, y)); if( region ) { - msg.assign(""); - std::string fullname; - if(mClosestAgentToCursor.notNull() && LLAvatarNameCache::getPNSName(mClosestAgentToCursor, fullname)) - { - //msg.append(fullname); -// [RLVa:KB] - Version: 1.23.4 | Checked: 2009-07-08 (RLVa-1.0.0e) | Modified: RLVa-0.2.0b - msg.append( (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) ? fullname : RlvStrings::getAnonym(fullname) ); -// [/RLVa:KB] - msg.append("\n"); + // set sticky_rect + S32 SLOP = 4; + localPointToScreen(x - SLOP, y - SLOP, &(sticky_rect.mLeft), &(sticky_rect.mBottom)); + sticky_rect.mRight = sticky_rect.mLeft + 2 * SLOP; + sticky_rect.mTop = sticky_rect.mBottom + 2 * SLOP; - LLVector3d mypos = gAgent.getPositionGlobal(); - LLVector3d position = mClosestAgentPosition; + tool_tip.clear(); - if ( LLFloaterAvatarList::instanceExists() ) + if (region->mMapAvatarIDs.size()) + { + if (mClosestAgentsToCursor.size()) { - LLAvatarListEntry *ent = LLFloaterAvatarList::getInstance()->getAvatarEntry(mClosestAgentToCursor); - if ( NULL != ent ) - { - //position = LLFloaterAvatarList::AvatarPosition(mClosestAgentToCursor); - position = ent->getPosition(); - } - } - LLVector3d delta = position - mypos; - F32 distance = (F32)delta.magVec(); + bool single_agent(mClosestAgentsToCursor.size() == 1); // Singu note: For old look, only add the count if we have more than one + if (!single_agent) + tool_tip.append(llformat("Agents under cursor (%d/%d)\n", mClosestAgentsToCursor.size(), region->mMapAvatarIDs.size() + 1)); + LLVector3d myPosition = gAgent.getPositionGlobal(); - //llinfos << distance << " - " << position << llendl; + for (const auto& target : mClosestAgentsToCursor) + { + const auto& targetUUID = target.first; + auto targetPosition = target.second; - msg.append( llformat("\n(Distance: %.02fm)\n\n",distance) ); + std::string fullName; + if (targetUUID.notNull() && LLAvatarNameCache::getNSName(targetUUID, fullName)) + { + //tool_tip.append(fullName); +// [RLVa:KB] - Version: 1.23.4 | Checked: 2009-07-08 (RLVa-1.0.0e) | Modified: RLVa-0.2.0b + if (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS)) + tool_tip.append( (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) ? fullName : RlvStrings::getAnonym(fullName) ); +// [/RLVa:KB] + + // Use the radar for positioning, when possible. + if (LLFloaterAvatarList::instanceExists()) + { + if (LLAvatarListEntry* ent = LLFloaterAvatarList::getInstance()->getAvatarEntry(targetUUID)) + targetPosition = ent->getPosition(); + } + // + + LLVector3d delta = targetPosition - myPosition; + F32 distance = (F32)delta.magVec(); + if (single_agent) + tool_tip.append( llformat("\n(Distance: %.02fm)\n",distance) ); + else + tool_tip.append(llformat(" (%.02fm)\n", distance)); + } + } + tool_tip += '\n'; + } } // [RLVa:KB] - Version: 1.23.4 | Checked: 2009-07-04 (RLVa-1.0.0a) | Modified: RLVa-0.2.0b - msg.append( (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) ? region->getName() : RlvStrings::getString(RLV_STRING_HIDDEN) ); + tool_tip.append((!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC) ? region->getName() : RlvStrings::getString(RLV_STRING_HIDDEN))); // [/RLVa:KB] - //msg.append( region->getName() ); - -//#ifndef LL_RELEASE_FOR_DOWNLOAD - std::string buffer; - msg.append("\n"); - buffer = region->getHost().getHostName(); - msg.append(buffer); - msg.append("\n"); - buffer = region->getHost().getString(); - msg.append(buffer); -//#endif - msg.append("\n"); - msg.append(getToolTip()); + //tool_tip.append("\n\n" + region->getName()); - S32 SLOP = 4; - localPointToScreen( - x - SLOP, y - SLOP, - &(sticky_rect_screen->mLeft), &(sticky_rect_screen->mBottom) ); - sticky_rect_screen->mRight = sticky_rect_screen->mLeft + 2 * SLOP; - sticky_rect_screen->mTop = sticky_rect_screen->mBottom + 2 * SLOP; - handled = TRUE; + tool_tip.append('\n' + region->getHost().getHostName()); + tool_tip.append('\n' + region->getHost().getString()); + tool_tip.append('\n' + getToolTip()); } - if(!handled) + else { - return LLPanel::handleToolTip(x, y, msg, sticky_rect_screen); + return LLPanel::handleToolTip(x, y, tool_tip, sticky_rect_screen); } - return handled; + *sticky_rect_screen = sticky_rect; + return TRUE; } @@ -714,25 +1063,22 @@ void LLNetMap::setDirectionPos( LLTextBox* text_box, F32 rotation ) // Inset by a little to account for position display. radius -= 8.f; - text_box->setOrigin(llround(half_width + radius * cos( rotation )), - llround(half_height + radius * sin( rotation ))); + text_box->setOrigin(ll_round(half_width + radius * cos( rotation )), + ll_round(half_height + radius * sin( rotation ))); } void LLNetMap::updateMinorDirections() { - if (getChild("ne_label", TRUE, FALSE) == NULL) - { - return; - } + if (!mNELabel) return; // Hide minor directions if they cover too much of the map - bool show_minors = getChild("ne_label")->getRect().getHeight() < MAP_MINOR_DIR_THRESHOLD * + bool show_minors = mNELabel->getRect().getHeight() < MAP_MINOR_DIR_THRESHOLD * llmin(getRect().getWidth(), getRect().getHeight()); - getChild("ne_label")->setVisible(show_minors); - getChild("nw_label")->setVisible(show_minors); - getChild("sw_label")->setVisible(show_minors); - getChild("se_label")->setVisible(show_minors); + mNELabel->setVisible(show_minors); + mNWLabel->setVisible(show_minors); + mSWLabel->setVisible(show_minors); + mSELabel->setVisible(show_minors); } void LLNetMap::renderScaledPointGlobal( const LLVector3d& pos, const LLColor4U &color, F32 radius_meters ) @@ -743,8 +1089,8 @@ void LLNetMap::renderScaledPointGlobal( const LLVector3d& pos, const LLColor4U & // DEV-17370 - megaprims of size > 4096 cause lag. (go figger.) const F32 MAX_RADIUS = 256.0f; F32 radius_clamped = llmin(radius_meters, MAX_RADIUS); - - S32 diameter_pixels = llround(2 * radius_clamped * mObjectMapTPM); + + S32 diameter_pixels = ll_round(2 * radius_clamped * mObjectMapTPM); renderPoint( local_pos, color, diameter_pixels ); } @@ -760,8 +1106,8 @@ void LLNetMap::renderPoint(const LLVector3 &pos_local, const LLColor4U &color, const S32 image_width = (S32)mObjectImagep->getWidth(); const S32 image_height = (S32)mObjectImagep->getHeight(); - S32 x_offset = llround(pos_local.mV[VX] * mObjectMapTPM + image_width / 2); - S32 y_offset = llround(pos_local.mV[VY] * mObjectMapTPM + image_height / 2); + S32 x_offset = ll_round(pos_local.mV[VX] * mObjectMapTPM + image_width / 2); + S32 y_offset = ll_round(pos_local.mV[VY] * mObjectMapTPM + image_height / 2); if ((x_offset < 0) || (x_offset >= image_width)) { @@ -834,35 +1180,159 @@ void LLNetMap::renderPoint(const LLVector3 &pos_local, const LLColor4U &color, } } -void LLNetMap::createObjectImage() +// [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-06-20 (Catznip-3.3.0) +void LLNetMap::renderPropertyLinesForRegion(const LLViewerRegion* pRegion, const LLColor4U& clrOverlay) +{ + const S32 imgWidth = (S32)mParcelImagep->getWidth(); + const S32 imgHeight = (S32)mParcelImagep->getHeight(); + + const LLVector3 originLocal(pRegion->getOriginGlobal() - mParcelImageCenterGlobal); + const S32 originX = ll_round(originLocal.mV[VX] * mObjectMapTPM + imgWidth / 2); + const S32 originY = ll_round(originLocal.mV[VY] * mObjectMapTPM + imgHeight / 2); + + U32* pTextureData = (U32*)mParcelRawImagep->getData(); + + // + // Draw the north and east region borders + // + const F32 real_width(pRegion->getWidth()); + const S32 borderY = originY + ll_round(real_width * mObjectMapTPM); + if ( (borderY >= 0) && (borderY < imgHeight) ) + { + S32 curX = llclamp(originX, 0, imgWidth), endX = llclamp(originX + ll_round(real_width * mObjectMapTPM), 0, imgWidth - 1); + for (; curX <= endX; curX++) + pTextureData[borderY * imgWidth + curX] = clrOverlay.mAll; + } + const S32 borderX = originX + ll_round(real_width * mObjectMapTPM); + if ( (borderX >= 0) && (borderX < imgWidth) ) + { + S32 curY = llclamp(originY, 0, imgHeight), endY = llclamp(originY + ll_round(real_width * mObjectMapTPM), 0, imgHeight - 1); + for (; curY <= endY; curY++) + pTextureData[curY * imgWidth + borderX] = clrOverlay.mAll; + } + + // + // Render parcel lines + // + const F32 GRID_STEP = PARCEL_GRID_STEP_METERS; + const S32 GRIDS_PER_EDGE = real_width / GRID_STEP; + + const U8* pOwnership = pRegion->getParcelOverlay()->getOwnership(); + const U8* pCollision = (pRegion->getHandle() == LLViewerParcelMgr::instance().getCollisionRegionHandle()) ? LLViewerParcelMgr::instance().getCollisionBitmap() : NULL; + for (S32 idxRow = 0; idxRow < GRIDS_PER_EDGE; idxRow++) + { + for (S32 idxCol = 0; idxCol < GRIDS_PER_EDGE; idxCol++) + { + S32 overlay = pOwnership[idxRow * GRIDS_PER_EDGE + idxCol]; + S32 idxCollision = idxRow * GRIDS_PER_EDGE + idxCol; + bool fForSale = ((overlay & PARCEL_COLOR_MASK) == PARCEL_FOR_SALE); + bool fCollision = (pCollision) && (pCollision[idxCollision / 8] & (1 << (idxCollision % 8))); + if ( (!fForSale) && (!fCollision) && (0 == (overlay & (PARCEL_SOUTH_LINE | PARCEL_WEST_LINE))) ) + continue; + + const S32 posX = originX + ll_round(idxCol * GRID_STEP * mObjectMapTPM); + const S32 posY = originY + ll_round(idxRow * GRID_STEP * mObjectMapTPM); + + static LLCachedControl s_fForSaleParcels(gSavedSettings, "MiniMapForSaleParcels"); + static LLCachedControl s_fShowCollisionParcels(gSavedSettings, "MiniMapCollisionParcels"); + if ( ((s_fForSaleParcels) && (fForSale)) || ((s_fShowCollisionParcels) && (fCollision)) ) + { + S32 curY = llclamp(posY, 0, imgHeight), endY = llclamp(posY + ll_round(GRID_STEP * mObjectMapTPM), 0, imgHeight - 1); + for (; curY <= endY; curY++) + { + S32 curX = llclamp(posX, 0, imgWidth) , endX = llclamp(posX + ll_round(GRID_STEP * mObjectMapTPM), 0, imgWidth - 1); + for (; curX <= endX; curX++) + { + pTextureData[curY * imgWidth + curX] = (fForSale) ? LLColor4U(255, 255, 128, 192).mAll + : LLColor4U(255, 128, 128, 192).mAll; + } + } + } + if (overlay & PARCEL_SOUTH_LINE) + { + if ( (posY >= 0) && (posY < imgHeight) ) + { + S32 curX = llclamp(posX, 0, imgWidth), endX = llclamp(posX + ll_round(GRID_STEP * mObjectMapTPM), 0, imgWidth - 1); + for (; curX <= endX; curX++) + pTextureData[posY * imgWidth + curX] = clrOverlay.mAll; + } + } + if (overlay & PARCEL_WEST_LINE) + { + if ( (posX >= 0) && (posX < imgWidth) ) + { + S32 curY = llclamp(posY, 0, imgHeight), endY = llclamp(posY + ll_round(GRID_STEP * mObjectMapTPM), 0, imgHeight - 1); + for (; curY <= endY; curY++) + pTextureData[curY * imgWidth + posX] = clrOverlay.mAll; + } + } + } + } +} +// [/SL:KB] + +//void LLNetMap::createObjectImage() +// [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-06-20 (Catznip-3.3.0) +bool LLNetMap::createImage(LLPointer& rawimagep) const +// [/SL:KB] { // Find the size of the side of a square that surrounds the circle that surrounds getRect(). // ... which is, the diagonal of the rect. - F32 width = getRect().getWidth(); - F32 height = getRect().getHeight(); - S32 square_size = llround( sqrt(width*width + height*height) ); + F32 width = (F32)getRect().getWidth(); + F32 height = (F32)getRect().getHeight(); + S32 square_size = ll_round( sqrt(width*width + height*height) ); // Find the least power of two >= the minimum size. const S32 MIN_SIZE = 64; - const S32 MAX_SIZE = 256; +// [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-07-28 (Catznip-3.3) + const S32 MAX_SIZE = 512; +// [/SL:KB] +// const S32 MAX_SIZE = 256; S32 img_size = MIN_SIZE; while( (img_size*2 < square_size ) && (img_size < MAX_SIZE) ) { img_size <<= 1; } - if( mObjectImagep.isNull() || - (mObjectImagep->getWidth() != img_size) || - (mObjectImagep->getHeight() != img_size) ) +// [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-06-20 (Catznip-3.3.0) + if( rawimagep.isNull() || (rawimagep->getWidth() != img_size) || (rawimagep->getHeight() != img_size) ) { - mObjectRawImagep = new LLImageRaw(img_size, img_size, 4); - U8* data = mObjectRawImagep->getData(); + rawimagep = new LLImageRaw(img_size, img_size, 4); + U8* data = rawimagep->getData(); memset( data, 0, img_size * img_size * 4 ); - mObjectImagep = LLViewerTextureManager::getLocalTexture( mObjectRawImagep.get(), FALSE); + return true; } + return false; +// [/SL:KB] +// if( mObjectImagep.isNull() || +// (mObjectImagep->getWidth() != img_size) || +// (mObjectImagep->getHeight() != img_size) ) +// { +// mObjectRawImagep = new LLImageRaw(img_size, img_size, 4); +// U8* data = mObjectRawImagep->getData(); +// memset( data, 0, img_size * img_size * 4 ); +// mObjectImagep = LLViewerTextureManager::getLocalTexture( mObjectRawImagep.get(), FALSE); +// } +// setScale(mScale); +// mUpdateNow = true; +} + +// [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-06-20 (Catznip-3.3.0) +void LLNetMap::createObjectImage() +{ + if (createImage(mObjectRawImagep)) + mObjectImagep = LLViewerTextureManager::getLocalTexture( mObjectRawImagep.get(), FALSE); setScale(mScale); - mUpdateNow = TRUE; + mUpdateObjectImage = true; +} + +void LLNetMap::createParcelImage() +{ + if (createImage(mParcelRawImagep)) + mParcelImagep = LLViewerTextureManager::getLocalTexture( mParcelRawImagep.get(), FALSE); + mUpdateParcelImage = true; } +// [/SL:KB] BOOL LLNetMap::handleMouseDown( S32 x, S32 y, MASK mask ) { @@ -871,10 +1341,9 @@ BOOL LLNetMap::handleMouseDown( S32 x, S32 y, MASK mask ) // Start panning gFocusMgr.setMouseCapture(this); - mMouseDownPanX = llround(mCurPanX); - mMouseDownPanY = llround(mCurPanY); - mMouseDownX = x; - mMouseDownY = y; + mStartPan = mCurPan; + mMouseDown.mX = x; + mMouseDown.mY = y; return TRUE; } @@ -886,22 +1355,20 @@ BOOL LLNetMap::handleMouseUp( S32 x, S32 y, MASK mask ) { // restore mouse cursor S32 local_x, local_y; - local_x = mMouseDownX + llfloor(mCurPanX - mMouseDownPanX); - local_y = mMouseDownY + llfloor(mCurPanY - mMouseDownPanY); + local_x = mMouseDown.mX + llfloor(mCurPan.mV[VX] - mStartPan.mV[VX]); + local_y = mMouseDown.mY + llfloor(mCurPan.mV[VY] - mStartPan.mV[VY]); LLRect clip_rect = getRect(); clip_rect.stretch(-8); - clip_rect.clipPointToRect(mMouseDownX, mMouseDownY, local_x, local_y); + clip_rect.clipPointToRect(mMouseDown.mX, mMouseDown.mY, local_x, local_y); LLUI::setMousePositionLocal(this, local_x, local_y); // finish the pan - mPanning = FALSE; + mPanning = false; - mMouseDownX = 0; - mMouseDownY = 0; + mMouseDown.set(0, 0); // auto centre - mTargetPanX = 0; - mTargetPanY = 0; + mTargetPan.setZero(); } gViewerWindow->showCursor(); gFocusMgr.setMouseCapture(NULL); @@ -910,8 +1377,70 @@ BOOL LLNetMap::handleMouseUp( S32 x, S32 y, MASK mask ) return FALSE; } +// [SL:KB] - Patch: World-MiniMap | Checked: 2012-07-08 (Catznip-3.3.0) +bool OverlayToggle::handleEvent(LLPointer event, const LLSD& sdParam) +{ + // Force an overlay update + LLFloaterMap::findInstance()->mPanelMap->mUpdateParcelImage = true; + return true; +} +// [/SL:KB] + +BOOL LLNetMap::handleRightMouseDown(S32 x, S32 y, MASK mask) +{ + mClosestAgentsAtLastClick.clear(); + mClosestAgentsAtLastClick.reserve(mClosestAgentsToCursor.size()); + for (const auto& pair : mClosestAgentsToCursor) + mClosestAgentsAtLastClick.push_back(pair.first); + mClosestAgentAtLastRightClick = mClosestAgentToCursor; + if (mPopupMenu) + { + showMenu(this, mPopupMenu, x, y); + mPopupMenu->getChildView("avs_menu")->setVisible(!mClosestAgentsAtLastClick.empty() && ! +// [RLVa:LF] - 2019 + gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES) +// [/RLVa:LF] + ); + } + return TRUE; +} + +BOOL LLNetMap::handleDoubleClick( S32 x, S32 y, MASK mask ) +{ + LLVector3d pos_global = viewPosToGlobal(x, y); + + bool double_click_teleport = gSavedSettings.getBOOL("DoubleClickTeleport"); + bool double_click_show_world_map = gSavedSettings.getBOOL("DoubleClickShowWorldMap"); + + bool new_target = false; + if (double_click_teleport || double_click_show_world_map) + { + // If we're not tracking a beacon already, double-click will set one + if (!LLTracker::isTracking()) + { + LLFloaterWorldMap* world_map = gFloaterWorldMap; + if (world_map) + { + world_map->trackLocation(pos_global); + new_target = true; + } + } + } + + if (double_click_teleport) + { + // If DoubleClickTeleport is on, double clicking the minimap will teleport there + gAgent.teleportViaLocationLookAt(pos_global); + } + else if (double_click_show_world_map) + { + LLFloaterWorldMap::show(new_target); + } + return TRUE; +} + // static -BOOL LLNetMap::outsideSlop( S32 x, S32 y, S32 start_x, S32 start_y, S32 slop ) +bool LLNetMap::outsideSlop( S32 x, S32 y, S32 start_x, S32 start_y, S32 slop ) { S32 dx = x - start_x; S32 dy = y - start_y; @@ -923,23 +1452,21 @@ BOOL LLNetMap::handleHover( S32 x, S32 y, MASK mask ) { if (hasMouseCapture()) { - if (mPanning || outsideSlop(x, y, mMouseDownX, mMouseDownY, MOUSE_DRAG_SLOP)) + if (mPanning || outsideSlop(x, y, mMouseDown.mX, mMouseDown.mY, MOUSE_DRAG_SLOP)) { if (!mPanning) { // just started panning, so hide cursor - mPanning = TRUE; + mPanning = true; gViewerWindow->hideCursor(); } - F32 delta_x = (F32)(gViewerWindow->getCurrentMouseDX()); - F32 delta_y = (F32)(gViewerWindow->getCurrentMouseDY()); + LLVector2 delta(static_cast(gViewerWindow->getCurrentMouseDX()), + static_cast(gViewerWindow->getCurrentMouseDY())); // Set pan to value at start of drag + offset - mCurPanX += delta_x; - mCurPanY += delta_y; - mTargetPanX = mCurPanX; - mTargetPanY = mCurPanY; + mCurPan += delta; + mTargetPan = mCurPan; gViewerWindow->moveCursorToCenter(); } @@ -963,58 +1490,23 @@ BOOL LLNetMap::handleHover( S32 x, S32 y, MASK mask ) return TRUE; } -BOOL LLNetMap::handleDoubleClick( S32 x, S32 y, MASK mask ) -{ - LLVector3d pos_global = viewPosToGlobal(x, y, gSavedSettings.getBOOL( "MiniMapRotate" )); - BOOL new_target = FALSE; - if (!LLTracker::isTracking()) - { - gFloaterWorldMap->trackLocation(pos_global); - new_target = TRUE; - } - - if (gSavedSettings.getBOOL("DoubleClickTeleport")) - { - gAgent.teleportViaLocationLookAt(pos_global); - } - else - { - LLFloaterWorldMap::show(new_target); - } - return TRUE; -} - -BOOL LLNetMap::handleRightMouseDown(S32 x, S32 y, MASK mask) -{ - mClosestAgentAtLastRightClick = mClosestAgentToCursor; - LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get(); - if (menu) - { - menu->buildDrawLabels(); - menu->updateParent(LLMenuGL::sMenuContainer); - LLMenuGL::showPopup(this, menu, x, y); - } - return TRUE; -} - - // static -bool LLNetMap::LLScaleMap::handleEvent(LLPointer event, const LLSD& userdata) +bool LLScaleMap::handleEvent(LLPointer event, const LLSD& userdata) { - LLNetMap *self = mPtr; + auto self = LLFloaterMap::findInstance()->mPanelMap; S32 level = userdata.asInteger(); switch(level) { case 0: - self->setScale(MAP_SCALE_MIN); + self->setScale(LLNetMap::MAP_SCALE_MIN); break; case 1: - self->setScale(MAP_SCALE_MID); + self->setScale(LLNetMap::MAP_SCALE_MID); break; case 2: - self->setScale(MAP_SCALE_MAX); + self->setScale(LLNetMap::MAP_SCALE_MAX); break; default: break; @@ -1024,142 +1516,96 @@ bool LLNetMap::LLScaleMap::handleEvent(LLPointer event, const LLSD& use } //moymod - minimap color shit -bool LLNetMap::mmsetred::handleEvent(LLPointer event, const LLSD& userdata) +void markMassAgents(const LLColor4& color) { - LLNetMap *self = mPtr; - //if(self->mClosestAgentAtLastRightClick){ - mm_setcolor(self->mClosestAgentAtLastRightClick,LLColor4(1.0,0.0,0.0,1.0)); - //} - return true; -} -bool LLNetMap::mmsetgreen::handleEvent(LLPointer event, const LLSD& userdata) -{ - LLNetMap *self = mPtr; - //if(self->mClosestAgentAtLastRightClick){ - mm_setcolor(self->mClosestAgentAtLastRightClick,LLColor4(0.0,1.0,0.0,1.0)); - //} - return true; + auto radar = LLFloaterAvatarList::getInstance(); + for (const auto& id : LFIDBearer::getActiveSelectedIDs()) + { + mm_setcolor(id, color); + if (auto entry = radar ? radar->getAvatarEntry(id) : nullptr) + entry->setMarked(true); + } } -bool LLNetMap::mmsetblue::handleEvent(LLPointer event, const LLSD& userdata) + +bool mmsetred::handleEvent(LLPointer, const LLSD&) { - LLNetMap *self = mPtr; - //if(self->mClosestAgentAtLastRightClick){ - mm_setcolor(self->mClosestAgentAtLastRightClick,LLColor4(0.0,0.0,1.0,1.0)); - //} + markMassAgents(LLColor4::red); return true; } -bool LLNetMap::mmsetyellow::handleEvent(LLPointer event, const LLSD& userdata) +bool mmsetgreen::handleEvent(LLPointer, const LLSD&) { - LLNetMap *self = mPtr; - //if(self->mClosestAgentAtLastRightClick){ - mm_setcolor(self->mClosestAgentAtLastRightClick,LLColor4(1.0,1.0,0.0,1.0)); - //} + markMassAgents(LLColor4::green); return true; } -bool LLNetMap::mmsetcustom::handleEvent(LLPointer event, const LLSD& userdata) +bool mmsetblue::handleEvent(LLPointer, const LLSD&) { - LLNetMap *self = mPtr; - //if(self->mClosestAgentAtLastRightClick){ - mm_setcolor(self->mClosestAgentAtLastRightClick,gSavedSettings.getColor4("MoyMiniMapCustomColor")); - //} + markMassAgents(LLColor4::blue); return true; } -bool LLNetMap::mmsetunmark::handleEvent(LLPointer event, const LLSD& userdata) +bool mmsetyellow::handleEvent(LLPointer, const LLSD&) { - mm_MarkerColors.erase(mPtr->mClosestAgentAtLastRightClick); + markMassAgents(LLColor4::yellow); return true; } -bool LLNetMap::mmenableunmark::handleEvent(LLPointer event, const LLSD& userdata) +bool mmsetcustom::handleEvent(LLPointer, const LLSD&) { - LLNetMap *self = mPtr; - BOOL enabled = mPtr->mClosestAgentAtLastRightClick.notNull() && mm_MarkerColors.find(mPtr->mClosestAgentAtLastRightClick) != mm_MarkerColors.end(); - self->findControl(userdata["control"].asString())->setValue(enabled); + markMassAgents(gSavedSettings.getColor4("MoyMiniMapCustomColor")); return true; } -bool LLNetMap::LLCenterMap::handleEvent(LLPointer event, const LLSD& userdata) +bool mmsetunmark::handleEvent(LLPointer, const LLSD&) { - EMiniMapCenter center = (EMiniMapCenter)userdata.asInteger(); - - if (gSavedSettings.getS32("MiniMapCenter") == center) + auto radar = LLFloaterAvatarList::getInstance(); + for (const auto& id : LFIDBearer::getActiveSelectedIDs()) { - gSavedSettings.setS32("MiniMapCenter", MAP_CENTER_NONE); + mm_clearMark(id); + if (auto entry = radar ? radar->getAvatarEntry(id) : nullptr) + entry->setMarked(false); } - else - { - gSavedSettings.setS32("MiniMapCenter", userdata.asInteger()); - } - return true; } - -bool LLNetMap::LLCheckCenterMap::handleEvent(LLPointer event, const LLSD& userdata) +bool mmenableunmark::handleEvent(LLPointer, const LLSD& userdata) { - LLNetMap *self = mPtr; - EMiniMapCenter center = (EMiniMapCenter)userdata["data"].asInteger(); - BOOL enabled = (gSavedSettings.getS32("MiniMapCenter") == center); - - self->findControl(userdata["control"].asString())->setValue(enabled); + bool enabled(false); + for (const auto& id : LFIDBearer::getActiveSelectedIDs()) + if (enabled = mm_MarkerColors.find(id) != mm_MarkerColors.end()) + break; + mPtr->findControl(userdata["control"].asString())->setValue(enabled); return true; } -bool LLNetMap::LLRotateMap::handleEvent(LLPointer event, const LLSD& userdata) +bool LLChatRings::handleEvent(LLPointer event, const LLSD& userdata) { - BOOL rotate = gSavedSettings.getBOOL("MiniMapRotate"); - gSavedSettings.setBOOL("MiniMapRotate", !rotate); + auto whisper = gSavedSettings.getControl("MiniMapWhisperRing"); + auto chat = gSavedSettings.getControl("MiniMapChatRing"); + auto shout = gSavedSettings.getControl("MiniMapShoutRing"); + bool all_enabled = whisper->get() && chat->get() && shout->get(); - return true; -} + whisper->set(!all_enabled); + chat->set(!all_enabled); + shout->set(!all_enabled); -bool LLNetMap::LLCheckRotateMap::handleEvent(LLPointer event, const LLSD& userdata) -{ - LLNetMap *self = mPtr; - BOOL enabled = gSavedSettings.getBOOL("MiniMapRotate"); - self->findControl(userdata["control"].asString())->setValue(enabled); return true; } -bool LLNetMap::LLStopTracking::handleEvent(LLPointer event, const LLSD& userdata) +bool LLCheckChatRings::handleEvent(LLPointer event, const LLSD& userdata) { - LLTracker::stopTracking(false); - return true; -} + bool all_enabled = gSavedSettings.getBOOL("MiniMapWhisperRing") + && gSavedSettings.getBOOL("MiniMapChatRing") + && gSavedSettings.getBOOL("MiniMapShoutRing"); -bool LLNetMap::LLEnableTracking::handleEvent(LLPointer event, const LLSD& userdata) -{ - LLNetMap *self = mPtr; - self->findControl(userdata["control"].asString())->setValue(LLTracker::isTracking()); + mPtr->findControl(userdata["control"].asString())->setValue(all_enabled); return true; } - -bool LLNetMap::LLCamFollow::handleEvent(LLPointer event, const LLSD& userdata) +bool LLStopTracking::handleEvent(LLPointer event, const LLSD& userdata) { - LLNetMap *self = mPtr; - LLFloaterAvatarList::lookAtAvatar(self->mClosestAgentAtLastRightClick); + LLTracker::stopTracking(false); return true; } - -bool LLNetMap::LLShowAgentProfile::handleEvent(LLPointer event, const LLSD& userdata) +bool LLIsTracking::handleEvent(LLPointer event, const LLSD& userdata) { - LLNetMap *self = mPtr; -// [RLVa:KB] - Version: 1.23.4 | Checked: 2009-07-08 (RLVa-1.0.0e) | Modified: RLVa-0.2.0b - if (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) - { - LLAvatarActions::showProfile(self->mClosestAgentAtLastRightClick); - } -// [/RLVa:KB] - //LLAvatarActions::showProfile(self->mClosestAgentAtLastRightClick); + mPtr->findControl(userdata["control"].asString())->setValue(LLTracker::isTracking()); return true; } -bool LLNetMap::LLEnableProfile::handleEvent(LLPointer event, const LLSD& userdata) -{ - LLNetMap *self = mPtr; -// [RLVa:KB] - Version: 1.23.4 | Checked: 2009-07-08 (RLVa-1.0.0e) | Modified: RLVa-0.2.0b - self->findControl(userdata["control"].asString())->setValue( - (self->isAgentUnderCursor()) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) ); -// [/RLVa:KB] - //self->findControl(userdata["control"].asString())->setValue(self->isAgentUnderCursor()); - return true; -} diff --git a/indra/newview/llnetmap.h b/indra/newview/llnetmap.h index a709761d66..67eb3d4bee 100644 --- a/indra/newview/llnetmap.h +++ b/indra/newview/llnetmap.h @@ -33,203 +33,128 @@ #ifndef LL_LLNETMAP_H #define LL_LLNETMAP_H +#include "lfidbearer.h" #include "llpanel.h" -#include "llmemberlistener.h" -#include "v3math.h" -#include "v3dmath.h" -#include "v4color.h" -#include "llimage.h" + class LLTextBox; +class LLImageRaw; class LLViewerTexture; +class LLFloaterMap; +// [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-06-20 (Catznip-3.3.0) +class LLViewerRegion; +class LLAvatarName; +// [/SL:KB] -typedef enum e_minimap_center -{ - MAP_CENTER_NONE = 0, - MAP_CENTER_CAMERA = 1 -} EMiniMapCenter; - -class LLNetMap : public LLPanel +class LLNetMap final : public LLPanel, public LFIDBearer { public: LLNetMap(const std::string& name); virtual ~LLNetMap(); - virtual void draw(); - virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); - virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask ); - virtual BOOL handleMouseUp( S32 x, S32 y, MASK mask ); - virtual BOOL handleHover( S32 x, S32 y, MASK mask ); - virtual BOOL handleDoubleClick( S32 x, S32 y, MASK mask ); - virtual BOOL handleRightMouseDown( S32 x, S32 y, MASK mask ); - virtual BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); - virtual BOOL handleToolTip( S32 x, S32 y, std::string& msg, LLRect* sticky_rect_screen ); + static const F32 MAP_SCALE_MIN; + static const F32 MAP_SCALE_MID; + static const F32 MAP_SCALE_MAX; - void renderScaledPointGlobal( const LLVector3d& pos, const LLColor4U &color, F32 radius ); + /*virtual*/ void draw(); + /*virtual*/ BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); + /*virtual*/ BOOL handleMouseDown( S32 x, S32 y, MASK mask ); + /*virtual*/ BOOL handleMouseUp( S32 x, S32 y, MASK mask ); + /*virtual*/ BOOL handleHover( S32 x, S32 y, MASK mask ); + /*virtual*/ BOOL handleToolTip( S32 x, S32 y, std::string& msg, LLRect* sticky_rect_screen ); + /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); - static void mm_setcolor(LLUUID key,LLColor4 col); //moymod + /*virtual*/ BOOL postBuild(); + /*virtual*/ BOOL handleRightMouseDown( S32 x, S32 y, MASK mask ); + /*virtual*/ BOOL handleDoubleClick( S32 x, S32 y, MASK mask ); -private: + LLUUID getStringUUIDSelectedItem() const override final { return mClosestAgentAtLastRightClick; } + uuid_vec_t getSelectedIDs() const override final { return mClosestAgentsAtLastClick; } +// [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-06-20 (Catznip-3.3.0) + void refreshParcelOverlay() { mUpdateParcelImage = true; } +// [/SL:KB] void setScale( F32 scale ); + void renderScaledPointGlobal( const LLVector3d& pos, const LLColor4U &color, F32 radius ); - // Not used at present - void translatePan( F32 delta_x, F32 delta_y ); - void setPan( F32 x, F32 y ) { mTargetPanX = x; mTargetPanY = y; } - +private: + const LLVector3d& getObjectImageCenterGlobal() { return mObjectImageCenterGlobal; } void renderPoint(const LLVector3 &pos, const LLColor4U &color, S32 diameter, S32 relative_height = 0); - LLVector3 globalPosToView(const LLVector3d& global_pos, BOOL rotated); - LLVector3d viewPosToGlobal(S32 x,S32 y, BOOL rotated); + + LLVector3 globalPosToView(const LLVector3d& global_pos); + LLVector3d viewPosToGlobal(S32 x,S32 y); + + void drawRing(const F32 radius, LLVector3 pos_map, const LLColor4& color); void drawTracking( const LLVector3d& pos_global, - BOOL rotated, const LLColor4& color, BOOL draw_arrow = TRUE); void setDirectionPos( LLTextBox* text_box, F32 rotation ); void updateMinorDirections(); +// [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-06-20 (Catznip-3.3.0) + bool createImage(LLPointer& rawimagep) const; void createObjectImage(); + void createParcelImage(); - LLHandle mPopupMenuHandle; + void renderPropertyLinesForRegion(const LLViewerRegion* pRegion, const LLColor4U& clrOverlay); +// [/SL:KB] +// void createObjectImage(); + + static bool outsideSlop(S32 x, S32 y, S32 start_x, S32 start_y, S32 slop); + +private: +// bool mUpdateNow; +// [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-06-20 (Catznip-3.3.0) + bool mUpdateObjectImage; +protected: + friend class OverlayToggle; + bool mUpdateParcelImage; +private: +// [/SL:KB] + + LLTextBox *mELabel = nullptr, + *mNLabel = nullptr, + *mWLabel = nullptr, + *mSLabel = nullptr, + *mNELabel = nullptr, + *mNWLabel = nullptr, + *mSWLabel = nullptr, + *mSELabel = nullptr; F32 mScale; // Size of a region in pixels F32 mPixelsPerMeter; // world meters to map pixels F32 mObjectMapTPM; // texels per meter on map F32 mObjectMapPixels; // Width of object map in pixels F32 mDotRadius; // Size of avatar markers - F32 mTargetPanX; - F32 mTargetPanY; - F32 mCurPanX; - F32 mCurPanY; - - BOOL mPanning; // map has been dragged - S32 mMouseDownPanX; // value at start of drag - S32 mMouseDownPanY; // value at start of drag - S32 mMouseDownX; - S32 mMouseDownY; - - BOOL mUpdateNow; + // + LLCachedControl mPickRadius; // Size of the rightclick area of affect + // + + bool mPanning; // map is being dragged + LLVector2 mTargetPan; + LLVector2 mCurPan; + LLVector2 mStartPan; // pan offset at start of drag + LLCoordGL mMouseDown; // pointer position at start of drag + LLVector3d mObjectImageCenterGlobal; LLPointer mObjectRawImagep; LLPointer mObjectImagep; +// [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-06-20 (Catznip-3.3.0) + LLVector3d mParcelImageCenterGlobal; + LLPointer mParcelRawImagep; + LLPointer mParcelImagep; +// [/SL:KB] + + static std::map mClosestAgentsToCursor; // + static uuid_vec_t mClosestAgentsAtLastClick; // -private: LLUUID mClosestAgentToCursor; - LLVector3d mClosestAgentPosition; LLUUID mClosestAgentAtLastRightClick; - static BOOL sRotateMap; - static LLNetMap* sInstance; - static BOOL isAgentUnderCursor(void*) { return sInstance && sInstance->mClosestAgentToCursor.notNull(); } - static BOOL outsideSlop(S32 x, S32 y, S32 start_x, S32 start_y, S32 slop); - - static void showAgentProfile(void*); - BOOL isAgentUnderCursor() { return mClosestAgentToCursor.notNull(); } - - class LLScaleMap : public LLMemberListener - { - public: - /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata); - }; - - class LLCenterMap : public LLMemberListener - { - public: - /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata); - }; - - class LLCheckCenterMap : public LLMemberListener - { - public: - /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata); - }; - - class LLRotateMap : public LLMemberListener - { - public: - /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata); - }; - - class LLCheckRotateMap : public LLMemberListener - { - public: - /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata); - }; - - class LLStopTracking : public LLMemberListener - { - public: - /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata); - }; - - class LLEnableTracking : public LLMemberListener - { - public: - /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata); - }; - - class LLShowAgentProfile : public LLMemberListener - { - public: - /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata); - }; - - class LLCamFollow : public LLMemberListener //moymod - { - public: - /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata); - }; - - - - //moymod - Custom minimap markers :o - - class mmsetred : public LLMemberListener //moymod - { - public: - /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata); - }; - class mmsetgreen : public LLMemberListener //moymod - { - public: - /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata); - }; - class mmsetblue : public LLMemberListener //moymod - { - public: - /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata); - }; - class mmsetyellow : public LLMemberListener //moymod - { - public: - /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata); - }; - class mmsetcustom : public LLMemberListener //moymod - { - public: - /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata); - }; - class mmsetunmark : public LLMemberListener //moymod - { - public: - /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata); - }; - class mmenableunmark : public LLMemberListener //moymod - { - public: - /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata); - }; - - - - - - class LLEnableProfile : public LLMemberListener - { - public: - /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata); - }; + BOOL isAgentUnderCursor() const { return mClosestAgentToCursor.notNull(); } + LLMenuGL* mPopupMenu; }; diff --git a/indra/newview/llnotify.cpp b/indra/newview/llnotify.cpp index 4f6cca0084..b8c9150c63 100644 --- a/indra/newview/llnotify.cpp +++ b/indra/newview/llnotify.cpp @@ -35,25 +35,20 @@ #include "llnotify.h" #include "llchat.h" -#include "llfocusmgr.h" -#include "llrender.h" -#include "llbutton.h" -#include "llfocusmgr.h" -#include "llglheaders.h" #include "lliconctrl.h" +#include "llmenugl.h" #include "lltextbox.h" #include "lltexteditor.h" #include "lltrans.h" #include "lluiconstants.h" -#include "llui.h" -#include "llxmlnode.h" -#include "llviewercontrol.h" #include "llviewerdisplay.h" #include "llviewertexturelist.h" +#include "llviewerwindow.h" // for gViewerWindow #include "llfloaterchat.h" // for add_chat_history() #include "lloverlaybar.h" // for gOverlayBar #include "lluictrlfactory.h" +#include "llcheckboxctrl.h" #include "hippogridmanager.h" @@ -69,11 +64,22 @@ const S32 BOTTOM_PAD = VPAD * 3; // statics -S32 LLNotifyBox::sNotifyBoxCount = 0; -const LLFontGL* LLNotifyBox::sFont = NULL; -const LLFontGL* LLNotifyBox::sFontSmall = NULL; -std::map LLNotifyBox::sOpenUniqueNotifyBoxes; +S32 sNotifyBoxCount = 0; +static const LLFontGL* sFont = NULL; +void chat_notification(const LLNotificationPtr notification) +{ + // TODO: Make a separate archive for these. + if (gSavedSettings.getBOOL("HideNotificationsInChat")) return; + LLChat chat(notification->getMessage()); + chat.mSourceType = CHAT_SOURCE_SYSTEM; +// [RLVa:KB] - Checked: 2009-07-10 (RLVa-1.0.0e) | Added: RLVa-0.2.0b + // Notices should already have their contents filtered where necessary + if (rlv_handler_t::isEnabled()) + chat.mRlvLocFiltered = chat.mRlvNamesFiltered = true; +// [/RLVa:KB] + LLFloaterChat::getInstance()->addChatHistory(chat); +} //--------------------------------------------------------------------------- // LLNotifyBox @@ -82,6 +88,7 @@ std::map LLNotifyBox::sOpenUniqueNotifyBoxes; //static void LLNotifyBox::initClass() { + sFont = LLFontGL::getFontSansSerif(); LLNotificationChannel::buildChannel("Notifications", "Visible", LLNotificationFilters::filterBy(&LLNotification::getType, "notify")); LLNotificationChannel::buildChannel("NotificationTips", "Visible", LLNotificationFilters::filterBy(&LLNotification::getType, "notifytip")); @@ -96,8 +103,13 @@ bool LLNotifyBox::onNotification(const LLSD& notify) if (!notification) return false; - if(notify["sigtype"].asString() == "add" || notify["sigtype"].asString() == "change") + if (notify["sigtype"].asString() == "add" || notify["sigtype"].asString() == "change") { + if (notification->getPayload().has("SUPPRESS_TOAST")) + { + chat_notification(notification); + return false; + } //bring existing notification to top //This getInstance is ugly, as LLNotifyBox is derived from both LLInstanceTracker and LLEventTimer, which also is derived from its own LLInstanceTracker //Have to explicitly determine which getInstance function to use. @@ -108,12 +120,7 @@ bool LLNotifyBox::onNotification(const LLSD& notify) } else { - bool is_script_dialog = (notification->getName() == "ScriptDialog" || notification->getName() == "ScriptDialogGroup"); - LLNotifyBox* notify_box = new LLNotifyBox( - notification, - is_script_dialog); //layout_script_dialog); - - gNotifyBoxView->addChild(notify_box); + gNotifyBoxView->addChild(new LLNotifyBox(notification)); } } else if (notify["sigtype"].asString() == "delete") @@ -129,8 +136,8 @@ bool LLNotifyBox::onNotification(const LLSD& notify) } //--------------------------------------------------------------------------- -LLNotifyBox::LLNotifyBox(LLNotificationPtr notification, - BOOL layout_script_dialog) +// Singu Note: We could clean a lot of this up by creating derived classes for Notifications and NotificationTips. +LLNotifyBox::LLNotifyBox(LLNotificationPtr notification) : LLPanel(notification->getName(), LLRect(), BORDER_NO), LLEventTimer(notification->getExpiration() == LLDate() ? LLDate(LLDate::now().secondsSinceEpoch() + (F64)gSavedSettings.getF32("NotifyTipDuration")) @@ -138,25 +145,18 @@ LLNotifyBox::LLNotifyBox(LLNotificationPtr notification, LLInstanceTracker(notification->getID()), mNotification(notification), mIsTip(notification->getType() == "notifytip"), - mAnimating(TRUE), + mAnimating(gNotifyBoxView->getChildCount() == 0), // Only animate first window mNextBtn(NULL), mNumOptions(0), mNumButtons(0), - mAddedDefaultBtn(FALSE), - mLayoutScriptDialog(layout_script_dialog), + mAddedDefaultBtn(false), mUserInputBox(NULL) { std::string edit_text_name; std::string edit_text_contents; - // class init - { - sFont = LLFontGL::getFontSansSerif(); - sFontSmall = LLFontGL::getFontSansSerifSmall(); - } - // setup paramaters - mMessage = notification->getMessage(); + const std::string& message(notification->getMessage()); // initialize setFocusRoot(!mIsTip); @@ -169,185 +169,102 @@ LLNotifyBox::LLNotifyBox(LLNotificationPtr notification, // they display the tip in a different color mIsCaution = notification->getPriority() >= NOTIFICATION_PRIORITY_HIGH; - // Only animate first window - if( gNotifyBoxView->getChildCount() > 0 ) - mAnimating = FALSE; - else - mAnimating = TRUE; - LLNotificationFormPtr form(notification->getForm()); mNumOptions = form->getNumElements(); bool is_textbox = form->getElement("message").isDefined(); - LLRect rect = mIsTip ? getNotifyTipRect(mMessage) + bool layout_script_dialog(notification->getName() == "ScriptDialog" || notification->getName() == "ScriptDialogGroup"); + LLRect rect = mIsTip ? getNotifyTipRect(message) : getNotifyRect(is_textbox ? 10 : mNumOptions, layout_script_dialog, mIsCaution); + if ((form->getIgnoreType() == LLNotificationForm::IGNORE_WITH_DEFAULT_RESPONSE || form->getIgnoreType() == LLNotificationForm::IGNORE_WITH_LAST_RESPONSE)) + rect.mBottom -= BTN_HEIGHT; setRect(rect); setFollows(mIsTip ? (FOLLOWS_BOTTOM|FOLLOWS_RIGHT) : (FOLLOWS_TOP|FOLLOWS_RIGHT)); setBackgroundVisible(FALSE); setBackgroundOpaque(TRUE); - LLIconCtrl* icon; - LLTextEditor* text; - const S32 TOP = getRect().getHeight() - (mIsTip ? (S32)sFont->getLineHeight() : 32); const S32 BOTTOM = (S32)sFont->getLineHeight(); S32 x = HPAD + HPAD; S32 y = TOP; - if (mIsTip) - { - // use the tip notification icon - icon = new LLIconCtrl(std::string("icon"), LLRect(x, y, x+32, TOP-32), std::string("notify_tip_icon.tga")); - } - else if (mIsCaution) - { - // use the caution notification icon - icon = new LLIconCtrl(std::string("icon"), LLRect(x, y, x+32, TOP-32), std::string("notify_caution_icon.tga")); - } - else - { - // use the default notification icon - icon = new LLIconCtrl(std::string("icon"), LLRect(x, y, x+32, TOP-32), std::string("notify_box_icon.tga")); - } + auto icon = new LLIconCtrl(std::string("icon"), LLRect(x, y, x+32, TOP-32), mIsTip ? "notify_tip_icon.tga" : mIsCaution ? "notify_caution_icon.tga" : "notify_box_icon.tga"); icon->setMouseOpaque(FALSE); addChild(icon); x += HPAD + HPAD + 32; - // add a caution textbox at the top of a caution notification - LLTextBox* caution_box = NULL; - if (mIsCaution && !mIsTip) { - S32 caution_height = ((S32)sFont->getLineHeight() * 2) + VPAD; - caution_box = new LLTextBox( - std::string("caution_box"), - LLRect(x, y, getRect().getWidth() - 2, caution_height), - LLStringUtil::null, - sFont, - FALSE); - - caution_box->setFontStyle(LLFontGL::BOLD); - caution_box->setColor(gColors.getColor("NotifyCautionWarnColor")); - caution_box->setBackgroundColor(gColors.getColor("NotifyCautionBoxColor")); - caution_box->setBorderVisible(FALSE); - caution_box->setWrappedText(notification->getMessage()); - - addChild(caution_box); - - // adjust the vertical position of the next control so that - // it appears below the caution textbox - y = y - caution_height; - } - else if (mIsCaution && mIsTip) - { - const S32 BTN_TOP = BOTTOM_PAD + (((mNumOptions-1+2)/3)) * (BTN_HEIGHT+VPAD); // Tokenization on \n is handled by LLTextBox const S32 MAX_LENGTH = 512 + 20 + DB_FIRST_NAME_BUF_SIZE + DB_LAST_NAME_BUF_SIZE + DB_INV_ITEM_NAME_BUF_SIZE; // For script dialogs: add space for title. + const auto height = mIsTip ? BOTTOM : BTN_TOP+16; - text = new LLTextEditor(std::string("box"), LLRect(x, y, getRect().getWidth()-2, mIsTip ? BOTTOM : BTN_TOP+16), MAX_LENGTH, mMessage, sFont, FALSE); - text->setWordWrap(TRUE); - text->setTabStop(FALSE); - text->setMouseOpaque(FALSE); - text->setBorderVisible(FALSE); - text->setTakesNonScrollClicks(FALSE); - text->setHideScrollbarForShortDocs(TRUE); - text->setReadOnlyBgColor ( LLColor4::transparent ); // the background color of the box is manually + mText = new LLTextEditor(std::string("box"), LLRect(x, y, getRect().getWidth()-2, height), MAX_LENGTH, LLStringUtil::null, sFont, FALSE, true); + + mText->setWordWrap(TRUE); + mText->setMouseOpaque(TRUE); + mText->setBorderVisible(FALSE); + mText->setTakesNonScrollClicks(TRUE); + mText->setHideScrollbarForShortDocs(TRUE); + mText->setReadOnlyBgColor ( LLColor4::transparent ); // the background color of the box is manually // rendered under the text box, therefore we want // the actual text box to be transparent - text->setReadOnlyFgColor ( gColors.getColor("NotifyCautionWarnColor") ); //sets caution text color for tip notifications - text->setEnabled(FALSE); // makes it read-only - text->setTabStop(FALSE); // can't tab to it (may be a problem for scrolling via keyboard) - addChild(text); - } - else - { - const S32 BTN_TOP = BOTTOM_PAD + (((mNumOptions-1+2)/3)) * (BTN_HEIGHT+VPAD); - - // Tokenization on \n is handled by LLTextBox + auto text_color = gColors.getColor(mIsCaution ? "NotifyCautionWarnColor" : "NotifyTextColor"); + LLStyleSP style = new LLStyle(true, text_color, LLStringUtil::null); + style->mBold = mIsCaution && !mIsTip; - const S32 MAX_LENGTH = 512 + 20 + - DB_FIRST_NAME_BUF_SIZE + - DB_LAST_NAME_BUF_SIZE + - DB_INV_ITEM_NAME_BUF_SIZE; // For script dialogs: add space for title. - - text = new LLTextEditor(std::string("box"), - LLRect(x, y, getRect().getWidth()-2, mIsTip ? BOTTOM : BTN_TOP+16), - MAX_LENGTH, - mMessage, - sFont, - FALSE); - text->setWordWrap(TRUE); - text->setTabStop(FALSE); - text->setMouseOpaque(FALSE); - text->setBorderVisible(FALSE); - text->setTakesNonScrollClicks(FALSE); - text->setHideScrollbarForShortDocs(TRUE); - text->setReadOnlyBgColor ( LLColor4::transparent ); // the background color of the box is manually - // rendered under the text box, therefore we want - // the actual text box to be transparent - text->setReadOnlyFgColor ( gColors.getColor("NotifyTextColor") ); - text->setEnabled(FALSE); // makes it read-only - text->setTabStop(FALSE); // can't tab to it (may be a problem for scrolling via keyboard) - addChild(text); + mText->setReadOnlyFgColor(text_color); //sets caution text color for tip notifications + if (!mIsCaution || !mIsTip) // We could do some extra color math here to determine if bg's too close to link color, but let's just cross with the link color instead + mText->setLinkColor(new LLColor4(lerp(text_color, gSavedSettings.getColor4("HTMLLinkColor"), 0.4f))); + mText->setTabStop(FALSE); // can't tab to it (may be a problem for scrolling via keyboard) + mText->appendText(message,false,false,style); // Now we can set the text, since colors have been set. + if (is_textbox || layout_script_dialog) + mText->appendText(notification->getSubstitutions()["SCRIPT_MESSAGE"], false, true, style, false); + addChild(mText); } if (mIsTip) { - // TODO: Make a separate archive for these. - LLChat chat(mMessage); - chat.mSourceType = CHAT_SOURCE_SYSTEM; -// [RLVa:KB] - Checked: 2009-07-10 (RLVa-1.0.0e) | Added: RLVa-0.2.0b - if (rlv_handler_t::isEnabled()) - { - // Notices should already have their contents filtered where necessary - chat.mRlvLocFiltered = chat.mRlvNamesFiltered = TRUE; - } -// [/RLVa:KB] - if (!gSavedSettings.getBOOL("HideNotificationsInChat")) { - LLFloaterChat::getInstance(LLSD())->addChatHistory(chat); - } + chat_notification(mNotification); } else { - LLButton* btn; - btn = new LLButton(std::string("next"), + mNextBtn = new LLButton(std::string("next"), LLRect(getRect().getWidth()-26, BOTTOM_PAD + 20, getRect().getWidth()-2, BOTTOM_PAD), std::string("notify_next.png"), std::string("notify_next.png"), LLStringUtil::null, - boost::bind(&LLNotifyBox::onClickNext,this), + boost::bind(&LLNotifyBox::moveToBack, this, true), sFont); - btn->setScaleImage(TRUE); - btn->setToolTip(LLTrans::getString("next")); - addChild(btn); - mNextBtn = btn; + mNextBtn->setScaleImage(TRUE); + mNextBtn->setToolTip(LLTrans::getString("next")); + addChild(mNextBtn); for (S32 i = 0; i < mNumOptions; i++) { - LLSD form_element = form->getElement(i); std::string element_type = form_element["type"].asString(); if (element_type == "button") { - addButton(form_element["name"].asString(), form_element["text"].asString(), TRUE, form_element["default"].asBoolean()); + addButton(form_element["name"].asString(), form_element["text"].asString(), TRUE, form_element["default"].asBoolean(), layout_script_dialog); } else if (element_type == "input") { edit_text_contents = form_element["value"].asString(); edit_text_name = form_element["name"].asString(); } - } + } if (is_textbox) { - S32 button_rows = (layout_script_dialog) ? 2 : 1; + S32 button_rows = layout_script_dialog ? 2 : 1; LLRect input_rect; input_rect.setOriginAndSize(x, BOTTOM_PAD + button_rows * (BTN_HEIGHT + VPAD), @@ -373,23 +290,54 @@ LLNotifyBox::LLNotifyBox(LLNotificationPtr notification, if (mNumButtons == 0) { - addButton("OK", "OK", FALSE, TRUE); - mAddedDefaultBtn = TRUE; + addButton("OK", "OK", false, true, layout_script_dialog); + mAddedDefaultBtn = true; } - - sNotifyBoxCount++; - if (sNotifyBoxCount <= 0) + std::string check_title; + if (form->getIgnoreType() == LLNotificationForm::IGNORE_WITH_DEFAULT_RESPONSE) { - llwarns << "A notification was mishandled. sNotifyBoxCount = " << sNotifyBoxCount << llendl; + check_title = LLNotificationTemplates::instance().getGlobalString("skipnexttime"); } - - // If this is the only notify box, don't show the next button - if (sNotifyBoxCount == 1 - && mNextBtn) + else if (form->getIgnoreType() == LLNotificationForm::IGNORE_WITH_LAST_RESPONSE) + { + check_title = LLNotificationTemplates::instance().getGlobalString("alwayschoose"); + } + if (!check_title.empty()) { - mNextBtn->setVisible(FALSE); + const LLFontGL* font = LLResMgr::getInstance()->getRes(LLFONT_SANSSERIF); + S32 line_height = llfloor(font->getLineHeight() + 0.99f); + + // Extend dialog for "check next time" + S32 max_msg_width = getRect().getWidth() - HPAD * 9; + S32 check_width = S32(font->getWidth(check_title) + 0.99f) + 16; + max_msg_width = llmax(max_msg_width, check_width); + + S32 msg_x = (getRect().getWidth() - max_msg_width) / 2; + + LLRect check_rect; + check_rect.setOriginAndSize(msg_x, BOTTOM_PAD + BTN_HEIGHT + VPAD*2 + (BTN_HEIGHT + VPAD) * (mNumButtons / 3), + max_msg_width, line_height); + + LLCheckboxCtrl* check = new LLCheckboxCtrl(std::string("check"), check_rect, check_title, font, + // Lambda abuse. + [this](LLUICtrl* ctrl, const LLSD& param) + { + this->mNotification->setIgnored(ctrl->getValue()); + }); + check->setEnabledColor(LLUI::sColorsGroup->getColor(mIsCaution ? "AlertCautionTextColor" : "AlertTextColor")); + if (mIsCaution) + { + check->setButtonColor(LLUI::sColorsGroup->getColor("ButtonCautionImageColor")); + } + addChild(check); } + + if (++sNotifyBoxCount <= 0) + LL_WARNS() << "A notification was mishandled. sNotifyBoxCount = " << sNotifyBoxCount << LL_ENDL; + // If this is the only notify box, don't show the next button + else if (sNotifyBoxCount == 1 && mNextBtn) + mNextBtn->setVisible(false); } } @@ -399,14 +347,13 @@ LLNotifyBox::~LLNotifyBox() } // virtual -LLButton* LLNotifyBox::addButton(const std::string& name, const std::string& label, BOOL is_option, BOOL is_default) +LLButton* LLNotifyBox::addButton(const std::string& name, const std::string& label, bool is_option, bool is_default, bool layout_script_dialog) { // make caution notification buttons slightly narrower // so that 3 of them can fit without overlapping the "next" button - S32 btn_width = mIsCaution? 84 : 90; + S32 btn_width = (mIsCaution || mNumOptions >= 3) ? 84 : 90; LLRect btn_rect; - LLButton* btn; S32 btn_height= BTN_HEIGHT; const LLFontGL* font = sFont; S32 ignore_pad = 0; @@ -414,14 +361,15 @@ LLButton* LLNotifyBox::addButton(const std::string& name, const std::string& lab S32 index = button_index; S32 x = (HPAD * 4) + 32; - if (mLayoutScriptDialog) + if (layout_script_dialog) { - // Add two "blank" option spaces, before the "Ignore" button - index = button_index + 2; - if (button_index == 0) + // Add one "blank" option space, before the "Block" and "Ignore" buttons + index = button_index + 1; + if (button_index == 0 || button_index == 1) { // Ignore button is smaller, less wide btn_height = BTN_HEIGHT_SMALL; + static const LLFontGL* sFontSmall = LLFontGL::getFontSansSerifSmall(); font = sFontSmall; ignore_pad = 10; } @@ -432,8 +380,9 @@ LLButton* LLNotifyBox::addButton(const std::string& name, const std::string& lab btn_width - 2*ignore_pad, btn_height); - btn = new LLButton(name, btn_rect, "", boost::bind(&LLNotifyBox::onClickButton, this, is_option ? name : "")); + LLButton* btn = new LLButton(name, btn_rect, "", boost::bind(&LLNotifyBox::onClickButton, this, is_option ? name : "")); btn->setLabel(label); + btn->setToolTip(label); btn->setFont(font); if (mIsCaution) @@ -445,9 +394,7 @@ LLButton* LLNotifyBox::addButton(const std::string& name, const std::string& lab addChild(btn, -1); if (is_default) - { setDefaultBtn(btn); - } mNumButtons++; return btn; @@ -455,7 +402,8 @@ LLButton* LLNotifyBox::addButton(const std::string& name, const std::string& lab BOOL LLNotifyBox::handleMouseUp(S32 x, S32 y, MASK mask) { - if (mIsTip) + bool done = LLPanel::handleMouseUp(x, y, mask); + if (!done && mIsTip) { mNotification->respond(mNotification->getResponseTemplate(LLNotification::WITH_DEFAULT_BUTTON)); @@ -465,35 +413,44 @@ BOOL LLNotifyBox::handleMouseUp(S32 x, S32 y, MASK mask) setFocus(TRUE); - return LLPanel::handleMouseUp(x, y, mask); + return done; } // virtual BOOL LLNotifyBox::handleRightMouseDown(S32 x, S32 y, MASK mask) { - if (!mIsTip) - { + if (!LLPanel::handleRightMouseDown(x, y, mask)) // Allow Children to handle first moveToBack(true); - return TRUE; - } + return true; +} - return LLPanel::handleRightMouseDown(x, y, mask); +// virtual +BOOL LLNotifyBox::handleHover(S32 x, S32 y, MASK mask) +{ + if (mIsTip) mEventTimer.stop(); // Stop timer on hover so the user can interact + return LLPanel::handleHover(x, y, mask); } +bool LLNotifyBox::userIsInteracting() const +{ + // If the mouse is over us, the user may wish to interact + S32 local_x; + S32 local_y; + screenPointToLocal(gViewerWindow->getCurrentMouseX(), gViewerWindow->getCurrentMouseY(), &local_x, &local_y); + return pointInView(local_x, local_y) || // We're actively hovered + // our text is the target of an active menu that could be open (getVisibleMenu sucks because it contains a loop of two dynamic casts, so keep this at the end) + (mText && mText->getActive() == mText && LLMenuGL::sMenuContainer->getVisibleMenu()); +} // virtual void LLNotifyBox::draw() { // If we are teleporting, stop the timer and restart it when the teleporting completes if (gTeleportDisplay) - { mEventTimer.stop(); - } - else if (!mEventTimer.getStarted()) - { + else if (!mEventTimer.getStarted() && (!mIsTip || !userIsInteracting())) // If it's not a tip, we can resume instantly, otherwise the user may be interacting mEventTimer.start(); - } - + F32 display_time = mAnimateTimer.getElapsedTimeF32(); if (mAnimating && display_time < ANIMATION_TIME) @@ -508,21 +465,18 @@ void LLNotifyBox::draw() LLUI::translate(0.f, voffset, 0.f); drawBackground(); - LLPanel::draw(); LLUI::popMatrix(); } else { - if(mAnimating) + if (mAnimating) { - mAnimating = FALSE; - if(!mIsTip) - { + mAnimating = false; + if (!mIsTip) // hide everyone behind me once I'm done animating gNotifyBoxView->showOnly(this); - } } drawBackground(); LLPanel::draw(); @@ -531,64 +485,49 @@ void LLNotifyBox::draw() void LLNotifyBox::drawBackground() const { - LLUIImagePtr imagep = LLUI::getUIImage("rounded_square.tga"); - if (imagep) + if (LLUIImagePtr imagep = LLUI::getUIImage("Rounded_Square")) { gGL.getTexUnit(0)->bind(imagep->getImage()); // set proper background color depending on whether notify box is a caution or not - LLColor4 color = mIsCaution? gColors.getColor("NotifyCautionBoxColor") : gColors.getColor("NotifyBoxColor"); - if(gFocusMgr.childHasKeyboardFocus( this )) + bool has_focus(gFocusMgr.childHasKeyboardFocus(this)); + if (has_focus) { const S32 focus_width = 2; - color = gColors.getColor("FloaterFocusBorderColor"); + static const LLCachedControl sBorder(gColors, "FloaterFocusBorderColor"); + LLColor4 color = sBorder; gGL.color4fv(color.mV); gl_segmented_rect_2d_tex(-focus_width, getRect().getHeight() + focus_width, getRect().getWidth() + focus_width, -focus_width, imagep->getTextureWidth(), imagep->getTextureHeight(), 16, mIsTip ? ROUNDED_RECT_TOP : ROUNDED_RECT_BOTTOM); - color = gColors.getColor("ColorDropShadow"); - gGL.color4fv(color.mV); - gl_segmented_rect_2d_tex(0, getRect().getHeight(), getRect().getWidth(), 0, imagep->getTextureWidth(), imagep->getTextureHeight(), 16, mIsTip ? ROUNDED_RECT_TOP : ROUNDED_RECT_BOTTOM); - - if( mIsCaution ) - color = gColors.getColor("NotifyCautionBoxColor"); - else - color = gColors.getColor("NotifyBoxColor"); - - gGL.color4fv(color.mV); - gl_segmented_rect_2d_tex(1, getRect().getHeight()-1, getRect().getWidth()-1, 1, imagep->getTextureWidth(), imagep->getTextureHeight(), 16, mIsTip ? ROUNDED_RECT_TOP : ROUNDED_RECT_BOTTOM); - } - else - { + static const LLCachedControl sDropShadow(gColors, "ColorDropShadow"); + color = sDropShadow; gGL.color4fv(color.mV); gl_segmented_rect_2d_tex(0, getRect().getHeight(), getRect().getWidth(), 0, imagep->getTextureWidth(), imagep->getTextureHeight(), 16, mIsTip ? ROUNDED_RECT_TOP : ROUNDED_RECT_BOTTOM); } + + static const LLCachedControl sCautionColor(gColors, "NotifyCautionBoxColor"); + static const LLCachedControl sColor(gColors, "NotifyBoxColor"); + LLColor4 color = mIsCaution ? sCautionColor : sColor; + gGL.color4fv(color.mV); + gl_segmented_rect_2d_tex(has_focus, getRect().getHeight()-has_focus, getRect().getWidth()-has_focus, has_focus, imagep->getTextureWidth(), imagep->getTextureHeight(), 16, mIsTip ? ROUNDED_RECT_TOP : ROUNDED_RECT_BOTTOM); } } void LLNotifyBox::close() { - BOOL isTipTmp = mIsTip; - - if (!mIsTip) - { - sNotifyBoxCount--; - } - + bool not_tip = !mIsTip; die(); - if(!isTipTmp) + if (not_tip) { - LLNotifyBox * front = gNotifyBoxView->getFirstNontipBox(); - if(front) + --sNotifyBoxCount; + if (LLNotifyBox* front = gNotifyBoxView->getFirstNontipBox()) { gNotifyBoxView->showOnly(front); - // we're assuming that close is only called by user action (for non-tips), - // so we then give focus to the next close button - if (front->getDefaultButton()) - { - front->getDefaultButton()->setFocus(TRUE); - } + // we're assuming that close is only called by user action (for non-tips), so we then give focus to the next close button + if (LLView* view = front->getDefaultButton()) + view->setFocus(true); gFocusMgr.triggerFocusFlash(); // TODO it's ugly to call this here } } @@ -614,6 +553,7 @@ BOOL LLNotifyBox::tick() { if (mIsTip) { + LLNotifications::instance().cancel(mNotification); close(); } return FALSE; @@ -622,11 +562,8 @@ BOOL LLNotifyBox::tick() void LLNotifyBox::setVisible(BOOL visible) { // properly set the status of the next button - if(visible && !mIsTip) - { + if (visible && !mIsTip) mNextBtn->setVisible(sNotifyBoxCount > 1); - mNextBtn->setEnabled(sNotifyBoxCount > 1); - } LLPanel::setVisible(visible); } @@ -634,35 +571,30 @@ void LLNotifyBox::moveToBack(bool getfocus) { // Move this dialog to the back. gNotifyBoxView->sendChildToBack(this); - if(!mIsTip && mNextBtn) + if (!mIsTip && mNextBtn) { - mNextBtn->setVisible(FALSE); + mNextBtn->setVisible(false); // And enable the next button on the frontmost one, if there is one - if (gNotifyBoxView->getChildCount() > 0) - { - LLNotifyBox* front = gNotifyBoxView->getFirstNontipBox(); - if (front) + if (gNotifyBoxView->getChildCount()) + if (LLNotifyBox* front = gNotifyBoxView->getFirstNontipBox()) { gNotifyBoxView->showOnly(front); if (getfocus) { // if are called from a user interaction // we give focus to the next next button - if (front->mNextBtn != NULL) - { - front->mNextBtn->setFocus(TRUE); - } + if (front->mNextBtn) + front->mNextBtn->setFocus(true); gFocusMgr.triggerFocusFlash(); // TODO: it's ugly to call this here } } - } } } // static -LLRect LLNotifyBox::getNotifyRect(S32 num_options, BOOL layout_script_dialog, BOOL is_caution) +LLRect LLNotifyBox::getNotifyRect(S32 num_options, bool layout_script_dialog, bool is_caution) { S32 notify_height = gSavedSettings.getS32("NotifyBoxHeight"); if (is_caution) @@ -680,15 +612,11 @@ LLRect LLNotifyBox::getNotifyRect(S32 num_options, BOOL layout_script_dialog, BO const S32 LEFT = RIGHT - NOTIFY_WIDTH; if (num_options < 1) - { num_options = 1; - } - // Add two "blank" option spaces. + // Add one "blank" option space. if (layout_script_dialog) - { - num_options += 2; - } + num_options += 1; S32 additional_lines = (num_options-1) / 3; @@ -700,7 +628,6 @@ LLRect LLNotifyBox::getNotifyRect(S32 num_options, BOOL layout_script_dialog, BO // static LLRect LLNotifyBox::getNotifyTipRect(const std::string &utf8message) { - S32 line_count = 1; LLWString message = utf8str_to_wstring(utf8message); S32 message_len = message.length(); @@ -712,27 +639,24 @@ LLRect LLNotifyBox::getNotifyTipRect(const std::string &utf8message) const llwchar* start = wchars; const llwchar* end; S32 total_drawn = 0; - BOOL done = FALSE; + bool done = false; + S32 line_count; - do + for (line_count = 2; !done; ++line_count) { - line_count++; + for (end = start; *end != 0 && *end != '\n'; end++); - for (end=start; *end != 0 && *end != '\n'; end++) - ; - - if( *end == 0 ) + if (*end == 0) { end = wchars + message_len; - done = TRUE; + done = true; } - S32 remaining = end - start; - while( remaining ) + for (S32 remaining = end - start; remaining;) { - S32 drawn = sFont->maxDrawableChars( start, (F32)text_area_width, remaining, LLFontGL::WORD_BOUNDARY_IF_POSSIBLE ); + S32 drawn = sFont->maxDrawableChars(start, (F32)text_area_width, remaining, LLFontGL::WORD_BOUNDARY_IF_POSSIBLE); - if( 0 == drawn ) + if (0 == drawn) { drawn = 1; // Draw at least one character, even if it doesn't all fit. (avoids an infinite loop) } @@ -740,10 +664,10 @@ LLRect LLNotifyBox::getNotifyTipRect(const std::string &utf8message) total_drawn += drawn; start += drawn; remaining -= drawn; - - if( total_drawn < message_len ) + + if (total_drawn < message_len) { - if( (wchars[ total_drawn ] != '\n') ) + if (wchars[ total_drawn ] != '\n') { // wrap because line was too long line_count++; @@ -751,19 +675,18 @@ LLRect LLNotifyBox::getNotifyTipRect(const std::string &utf8message) } else { - done = TRUE; + done = true; } } total_drawn++; // for '\n' - end++; - start = end; - } while( !done ); + start = ++end; + } const S32 MIN_NOTIFY_HEIGHT = 72; const S32 MAX_NOTIFY_HEIGHT = 600; S32 notify_height = llceil((F32) (line_count+1) * sFont->getLineHeight()); - if(gOverlayBar) + if (gOverlayBar) { notify_height += gOverlayBar->getBoundingRect().mTop; } @@ -799,18 +722,12 @@ void LLNotifyBox::onClickButton(const std::string name) } -void LLNotifyBox::onClickNext() -{ - moveToBack(true); -} - - LLNotifyBoxView::LLNotifyBoxView(const std::string& name, const LLRect& rect, BOOL mouse_opaque, U32 follows) : LLUICtrl(name,rect,mouse_opaque,NULL,follows) { } -LLNotifyBox * LLNotifyBoxView::getFirstNontipBox() const +LLNotifyBox* LLNotifyBoxView::getFirstNontipBox() const { // *TODO: Don't make assumptions like this! // assumes every child is a notify box @@ -819,50 +736,41 @@ LLNotifyBox * LLNotifyBoxView::getFirstNontipBox() const iter++) { // hack! *TODO: Integrate llnotify and llgroupnotify - if(isGroupNotifyBox(*iter)) - { + if (isGroupNotifyBox(*iter)) continue; - } - - LLNotifyBox* box = (LLNotifyBox*)(*iter); - if(!box->isTip() && !box->isDead()) - { + + LLNotifyBox* box = static_cast(*iter); + if (!box->isTip() && !box->isDead()) return box; - } } return NULL; } -void LLNotifyBoxView::showOnly(LLView * view) +void LLNotifyBoxView::showOnly(LLView* view) { - if(view) - { - // assumes that the argument is actually a child - LLNotifyBox * shown = dynamic_cast(view); - if(!shown) - { - return ; - } + // assumes that the argument is actually a child + if (!dynamic_cast(view)) return; - // make every other notification invisible - for(child_list_const_iter_t iter = getChildList()->begin(); + // make every other notification invisible + for(child_list_const_iter_t iter = getChildList()->begin(); iter != getChildList()->end(); iter++) - { - if(isGroupNotifyBox(*iter)) - { - continue; - } - - LLNotifyBox * box = (LLNotifyBox*)(*iter); - if(box != view && box->getVisible() && !box->isTip()) - { - box->setVisible(FALSE); - } - } - shown->setVisible(TRUE); - sendChildToFront(shown); + { + if (view == (*iter)) continue; + LLView* view(*iter); + if (isGroupNotifyBox(view) || !view->getVisible()) + continue; + if (!static_cast(view)->isTip()) + view->setVisible(false); } + view->setVisible(true); + sendChildToFront(view); +} + +void LLNotifyBoxView::deleteAllChildren() +{ + LLUICtrl::deleteAllChildren(); + sNotifyBoxCount = 0; } void LLNotifyBoxView::purgeMessagesMatching(const Matcher& matcher) @@ -874,13 +782,11 @@ void LLNotifyBoxView::purgeMessagesMatching(const Matcher& matcher) iter != notification_queue.end(); iter++) { - if(isGroupNotifyBox(*iter)) - { + if (isGroupNotifyBox(*iter)) continue; - } - LLNotifyBox* notification = (LLNotifyBox*)*iter; - if(matcher.matches(notification->getNotification())) + LLNotifyBox* notification = static_cast(*iter); + if (matcher.matches(notification->getNotification())) { removeChild(notification); } @@ -889,11 +795,6 @@ void LLNotifyBoxView::purgeMessagesMatching(const Matcher& matcher) bool LLNotifyBoxView::isGroupNotifyBox(const LLView* view) const { - if (view->getName() == "groupnotify") - { - return TRUE ; - } - - return FALSE ; + return view->getName() == "groupnotify"; } diff --git a/indra/newview/llnotify.h b/indra/newview/llnotify.h index c0b03b8f9f..4ea8ca9cb4 100644 --- a/indra/newview/llnotify.h +++ b/indra/newview/llnotify.h @@ -37,30 +37,25 @@ #include "llpanel.h" #include "lleventtimer.h" #include "llnotifications.h" -#include class LLButton; class LLNotifyBoxTemplate; class LLTextEditor; // NotifyBox - for notifications that require a response from the user. -class LLNotifyBox : +class LLNotifyBox final : public LLPanel, public LLEventTimer, public LLInitClass, public LLInstanceTracker { public: - typedef void (*notify_callback_t)(S32 option, void* data); - typedef std::vector option_list_t; - static void initClass(); - static void destroyClass(); - BOOL isTip() const { return mIsTip; } - BOOL isCaution() const { return mIsCaution; } - /*virtual*/ void setVisible(BOOL visible); - void stopAnimation() { mAnimating = FALSE; } + bool isTip() const { return mIsTip; } + bool isCaution() const { return mIsCaution; } + /*virtual*/ void setVisible(BOOL visible) override; + void stopAnimation() { mAnimating = false; } void close(); @@ -69,47 +64,42 @@ class LLNotifyBox : static void format(std::string& msg, const LLStringUtil::format_map_t& args); protected: - LLNotifyBox(LLNotificationPtr notification, BOOL layout_script_dialog); + LLNotifyBox(LLNotificationPtr notification); /*virtual*/ ~LLNotifyBox(); - LLButton* addButton(std::string const &name, const std::string& label, BOOL is_option, BOOL is_default); + LLButton* addButton(const std::string& name, const std::string& label, bool is_option, bool is_default, bool layout_script_dialog); - /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask); - /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask) override; + /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask) override; + BOOL handleHover(S32 x, S32 y, MASK mask) override; + bool userIsInteracting() const; // Animate as sliding onto the screen. - /*virtual*/ void draw(); - /*virtual*/ BOOL tick(); + /*virtual*/ void draw() override; + /*virtual*/ BOOL tick() override; void moveToBack(bool getfocus = false); // Returns the rect, relative to gNotifyView, where this // notify box should be placed. - static LLRect getNotifyRect(S32 num_options, BOOL layout_script_dialog, BOOL is_caution); + static LLRect getNotifyRect(S32 num_options, bool layout_script_dialog, bool is_caution); static LLRect getNotifyTipRect(const std::string &message); // internal handler for button being clicked void onClickButton(const std::string name); - // for "next" button - void onClickNext(); - - //static LLNotifyBox* findExistingNotify(LLPointer notify_template, const LLString::format_map_t& args); - private: static bool onNotification(const LLSD& notify); void drawBackground() const; protected: - std::string mMessage; - - LLTextEditor *mUserInputBox; + LLTextEditor *mUserInputBox = nullptr, *mText = nullptr; LLNotificationPtr mNotification; - BOOL mIsTip; - BOOL mIsCaution; // is this a caution notification? - BOOL mAnimating; // Are we sliding onscreen? + bool mIsTip; + bool mIsCaution; // is this a caution notification? + bool mAnimating; // Are we sliding onscreen? // Time since this notification was displayed. // This is an LLTimer not a frame timer because I am concerned @@ -120,34 +110,19 @@ class LLNotifyBox : S32 mNumOptions; S32 mNumButtons; - BOOL mAddedDefaultBtn; - - BOOL mLayoutScriptDialog; - - // Used for callbacks - struct InstanceAndS32 - { - LLNotifyBox* mSelf; - std::string mButtonName; - }; - static S32 sNotifyBoxCount; - static const LLFontGL* sFont; - static const LLFontGL* sFontSmall; - - typedef std::map unique_map_t; - static unique_map_t sOpenUniqueNotifyBoxes; + bool mAddedDefaultBtn; }; -class LLNotifyBoxView : public LLUICtrl +class LLNotifyBoxView final : public LLUICtrl { public: LLNotifyBoxView(const std::string& name, const LLRect& rect, BOOL mouse_opaque, U32 follows=FOLLOWS_NONE); - void showOnly(LLView * ctrl); - LLNotifyBox * getFirstNontipBox() const; + void showOnly(LLView* ctrl); + LLNotifyBox* getFirstNontipBox() const; + /*virtual*/ void deleteAllChildren() override; - class Matcher + struct Matcher { - public: Matcher(){} virtual ~Matcher() {} virtual bool matches(const LLNotificationPtr) const = 0; @@ -157,7 +132,7 @@ class LLNotifyBoxView : public LLUICtrl void purgeMessagesMatching(const Matcher& matcher); private: - bool isGroupNotifyBox(const LLView* view) const ; + bool isGroupNotifyBox(const LLView* view) const; }; // This view contains the stack of notification windows. diff --git a/indra/newview/lloverlaybar.cpp b/indra/newview/lloverlaybar.cpp index 07357d32ac..d57235dcd7 100644 --- a/indra/newview/lloverlaybar.cpp +++ b/indra/newview/lloverlaybar.cpp @@ -39,21 +39,13 @@ #include "aoremotectrl.h" #include "llaudioengine.h" -#include "importtracker.h" -#include "llrender.h" #include "llagent.h" #include "llagentcamera.h" -#include "llbutton.h" #include "llchatbar.h" -#include "llfocusmgr.h" -#include "llimpanel.h" -#include "llimview.h" +#include "llfloaterchatterbox.h" #include "llmediaremotectrl.h" #include "llpanelaudiovolume.h" #include "llparcel.h" -#include "lltextbox.h" -#include "llui.h" -#include "llviewercontrol.h" #include "llviewertexturelist.h" #include "llviewerjoystick.h" #include "llviewermedia.h" @@ -62,25 +54,18 @@ #include "llviewerparcelmedia.h" #include "llviewerparcelmgr.h" #include "lluictrlfactory.h" -#include "llviewercontrol.h" -#include "llviewerwindow.h" #include "llvoiceclient.h" #include "llvoavatarself.h" #include "llvoiceremotectrl.h" -#include "llmediactrl.h" #include "llselectmgr.h" #include "wlfPanel_AdvSettings.h" #include "llpanelnearbymedia.h" - - -#include "llcontrol.h" - // [RLVa:KB] #include "rlvhandler.h" // [/RLVa:KB] -#include +#include // // Globals @@ -259,7 +244,7 @@ void LLOverlayBar::layoutButtons() { U32 button_count = 0; const child_list_t& view_list = *(mStateManagementContainer->getChildList()); - BOOST_FOREACH(LLView* viewp, view_list) + for (LLView* viewp : view_list) { if(!viewp->getEnabled()) continue; @@ -279,7 +264,7 @@ void LLOverlayBar::layoutButtons() S32 left = 0; S32 bottom = 1; - BOOST_REVERSE_FOREACH(LLView* viewp, view_list) + for (LLView* viewp : boost::adaptors::reverse(view_list)) { if(!viewp->getEnabled()) continue; @@ -309,22 +294,19 @@ void LLOverlayBar::refresh() { bool buttons_changed = FALSE; - if (LLButton* button = updateButtonVisiblity(mNewIM,gIMMgr->getIMReceived())) + int unread_count(gIMMgr->getIMUnreadCount()); + static const LLCachedControl per_conversation("NewIMsPerConversation"); + static const LLCachedControl reset_count("NewIMsPerConversationReset"); + if (per_conversation && (!reset_count || unread_count) && !LLFloaterChatterBox::instanceVisible()) + { + unread_count = 0; + for(std::set >::const_iterator it = gIMMgr->getIMFloaterHandles().begin(); it != gIMMgr->getIMFloaterHandles().end(); ++it) + if (LLFloaterIMPanel* im_floater = static_cast(it->get())) + if (im_floater->getParent() != gFloaterView && im_floater->getNumUnreadMessages()) // Only count docked IMs + ++unread_count; + } + if (LLButton* button = updateButtonVisiblity(mNewIM, unread_count)) { - int unread_count(0); - static const LLCachedControl per_conversation("NewIMsPerConversation"); - if (per_conversation) - { - for(std::set >::const_iterator it = gIMMgr->getIMFloaterHandles().begin(); it != gIMMgr->getIMFloaterHandles().end(); ++it) - if (LLFloaterIMPanel* im_floater = static_cast(it->get())) - if (im_floater->getParent() != gFloaterView && im_floater->getNumUnreadMessages()) // Only count docked IMs - ++unread_count; - } - else - { - unread_count = gIMMgr->getIMUnreadCount(); - } - if (unread_count > 0) { if (unread_count > 1) @@ -340,9 +322,9 @@ void LLOverlayBar::refresh() } buttons_changed = true; } - buttons_changed |= updateButtonVisiblity(mNotBusy,gAgent.getBusy()) != NULL; + buttons_changed |= updateButtonVisiblity(mNotBusy, gAgent.isDoNotDisturb()) != NULL; buttons_changed |= updateButtonVisiblity(mFlyCam,LLViewerJoystick::getInstance()->getOverrideCamera()) != NULL; - buttons_changed |= updateButtonVisiblity(mMouseLook,gAgent.isControlGrabbed(CONTROL_ML_LBUTTON_DOWN_INDEX)||gAgent.isControlGrabbed(CONTROL_ML_LBUTTON_UP_INDEX)) != NULL; + buttons_changed |= updateButtonVisiblity(mMouseLook,gAgent.isControlBlocked(CONTROL_ML_LBUTTON_DOWN_INDEX)||gAgent.isControlBlocked(CONTROL_ML_LBUTTON_UP_INDEX)) != NULL; // [RLVa:KB] - Checked: 2009-07-10 (RLVa-1.0.0g) // buttons_changed |= updateButtonVisiblity("Stand Up", isAgentAvatarValid() && gAgentAvatarp->isSitting()) != NULL; buttons_changed |= updateButtonVisiblity(mStandUp,isAgentAvatarValid() && gAgentAvatarp->isSitting() && !gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) != NULL; @@ -392,7 +374,7 @@ void LLOverlayBar::onClickIMReceived(void*) // static void LLOverlayBar::onClickSetNotBusy(void*) { - gAgent.clearBusy(); + gAgent.setDoNotDisturb(false); } @@ -434,7 +416,7 @@ void LLOverlayBar::onClickCancelTP(void* data) LLOverlayBar* self = (LLOverlayBar*)data; self->setCancelTPButtonVisible(FALSE, std::string("Cancel TP")); gAgent.teleportCancel(); - llinfos << "trying to cancel teleport" << llendl; + LL_INFOS() << "trying to cancel teleport" << LL_ENDL; } void LLOverlayBar::setCancelTPButtonVisible(BOOL b, const std::string& label) @@ -497,7 +479,6 @@ void LLOverlayBar::toggleMediaPlay(void*) LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); if (parcel) { - LLViewerParcelMedia::sIsUserAction = true; LLViewerParcelMedia::play(parcel); } } @@ -523,7 +504,6 @@ void LLOverlayBar::toggleMusicPlay(void*) // stream is stopped, it doesn't return the right thing - commenting out for now. // if ( gAudiop->isInternetStreamPlaying() == 0 ) { - LLViewerParcelMedia::sIsUserAction = true; LLViewerParcelMedia::playStreamingMusic(parcel); } } diff --git a/indra/newview/llpanelaudioprefs.cpp b/indra/newview/llpanelaudioprefs.cpp index e61028fa83..1929e693cf 100644 --- a/indra/newview/llpanelaudioprefs.cpp +++ b/indra/newview/llpanelaudioprefs.cpp @@ -89,6 +89,7 @@ LLPanelAudioPrefs::~LLPanelAudioPrefs() BOOL LLPanelAudioPrefs::postBuild() { + getChildView("filter_group")->setValue(S32(gSavedSettings.getU32("MediaFilterEnable"))); refreshValues(); // initialize member data from saved settings childSetLabelArg("currency_change_threshold", "[CURRENCY]", gHippoGridManager->getConnectedGrid()->getCurrencySymbol()); @@ -115,6 +116,7 @@ void LLPanelAudioPrefs::refreshValues() mPreviousMuteAudio = gSavedSettings.getBOOL("MuteAudio"); mPreviousMuteWhenMinimized = gSavedSettings.getBOOL("MuteWhenMinimized"); + gSavedSettings.setU32("MediaFilterEnable", getChildView("filter_group")->getValue().asInteger()); } void LLPanelAudioPrefs::cancel() diff --git a/indra/newview/llpanelavatar.cpp b/indra/newview/llpanelavatar.cpp index 4cda01c3b0..3e284649d9 100644 --- a/indra/newview/llpanelavatar.cpp +++ b/indra/newview/llpanelavatar.cpp @@ -45,7 +45,9 @@ #include "llwindow.h" #include "llagent.h" +#include "llagentbenefits.h" #include "llavataractions.h" +#include "llavatarpropertiesprocessor.h" #include "llcallingcard.h" #include "lldroptarget.h" #include "llfloatergroupinfo.h" @@ -69,6 +71,9 @@ #include #include + +#include "hippogridmanager.h" // Include Gridmanager for OpenSim Support in profiles, provides ability for the helpbutton to redirect to GRID Websites Help page + // [RLVa:KB] #include "rlvhandler.h" // [/RLVa:KB] @@ -95,20 +100,24 @@ LLPanelAvatarTab::LLPanelAvatarTab(const std::string& name, const LLRect &rect, void LLPanelAvatarTab::setAvatarID(const LLUUID& avatar_id) { - if(mAvatarID != avatar_id) + if (mAvatarID != avatar_id) { - if(mAvatarID.notNull()) + if (mAvatarID.notNull()) LLAvatarPropertiesProcessor::getInstance()->removeObserver(mAvatarID, this); mAvatarID = avatar_id; - if(mAvatarID.notNull()) + if (mAvatarID.notNull()) + { LLAvatarPropertiesProcessor::getInstance()->addObserver(mAvatarID, this); + if (LLUICtrl* ctrl = findChild("Mute")) + ctrl->setValue(LLMuteList::instance().isMuted(mAvatarID)); + } } } // virtual LLPanelAvatarTab::~LLPanelAvatarTab() { - if(mAvatarID.notNull()) + if (mAvatarID.notNull()) LLAvatarPropertiesProcessor::getInstance()->removeObserver(mAvatarID, this); } @@ -116,7 +125,6 @@ LLPanelAvatarTab::~LLPanelAvatarTab() void LLPanelAvatarTab::draw() { refresh(); - LLPanel::draw(); } @@ -129,22 +137,16 @@ LLPanelAvatarSecondLife::LLPanelAvatarSecondLife(const std::string& name, : LLPanelAvatarTab(name, rect, panel_avatar), mPartnerID() { + LLMuteList::instance().addObserver(this); } -void LLPanelAvatarSecondLife::refresh() +LLPanelAvatarSecondLife::~LLPanelAvatarSecondLife() { - updatePartnerName(); + LLMuteList::instance().removeObserver(this); } -void LLPanelAvatarSecondLife::updatePartnerName() +void LLPanelAvatarSecondLife::refresh() { - if (mPartnerID.notNull()) - { - std::string name; - if (LLAvatarNameCache::getPNSName(mPartnerID, name)) - childSetTextArg("partner_edit", "[NAME]", name); - childSetEnabled("partner_info", TRUE); - } } //----------------------------------------------------------------------------- @@ -154,24 +156,15 @@ void LLPanelAvatarSecondLife::updatePartnerName() //----------------------------------------------------------------------------- void LLPanelAvatarSecondLife::clearControls() { - LLTextureCtrl* image_ctrl = getChild("img"); - if(image_ctrl) - { - image_ctrl->setImageAssetID(LLUUID::null); - } - childSetValue("about", ""); - childSetValue("born", ""); - childSetValue("acct", ""); - - childSetTextArg("partner_edit", "[NAME]", LLStringUtil::null); + getChild("img")->setImageAssetID(LLUUID::null); + childSetValue("about", LLStringUtil::null); + childSetValue("born", LLStringUtil::null); + childSetValue("acct", LLStringUtil::null); + childSetValue("partner_edit", LLUUID::null); mPartnerID = LLUUID::null; - - LLScrollListCtrl* group_list = getChild("groups"); - if(group_list) - { - group_list->deleteAllItems(); - } + + getChild("groups")->deleteAllItems(); } // virtual @@ -183,56 +176,16 @@ void LLPanelAvatarSecondLife::processProperties(void* data, EAvatarProcessorType if (pAvatarData && (mAvatarID == pAvatarData->avatar_id) && (pAvatarData->avatar_id != LLUUID::null)) { LLStringUtil::format_map_t args; - - U8 caption_index = 0; - std::string caption_text = getString("CaptionTextAcctInfo"); - - const char* ACCT_TYPE[] = - { - "AcctTypeResident", - "AcctTypeTrial", - "AcctTypeCharterMember", - "AcctTypeEmployee" - }; - - - caption_index = llclamp(caption_index, (U8)0, (U8)(LL_ARRAY_SIZE(ACCT_TYPE)-1)); - args["[ACCTTYPE]"] = getString(ACCT_TYPE[caption_index]); + args["[ACCTTYPE]"] = LLAvatarPropertiesProcessor::accountType(pAvatarData); + args["[PAYMENTINFO]"] = LLAvatarPropertiesProcessor::paymentInfo(pAvatarData); + args["[AGEVERIFICATION]"] = LLStringUtil::null; - std::string payment_text = " "; - const S32 DEFAULT_CAPTION_LINDEN_INDEX = 3; - if(caption_index != DEFAULT_CAPTION_LINDEN_INDEX) - { - if(pAvatarData->flags & AVATAR_TRANSACTED) - { - payment_text = "PaymentInfoUsed"; - } - else if (pAvatarData->flags & AVATAR_IDENTIFIED) - { - payment_text = "PaymentInfoOnFile"; - } - else - { - payment_text = "NoPaymentInfoOnFile"; - } - args["[PAYMENTINFO]"] = getString(payment_text); - - // Do not display age verification status at this time - Mostly because it /doesn't work/. -HgB - /*bool age_verified = (pAvatarData->flags & AVATAR_AGEVERIFIED); // Not currently getting set in dataserver/lldataavatar.cpp for privacy consideration - std::string age_text = age_verified ? "AgeVerified" : "NotAgeVerified"; - - args["[AGEVERIFICATION]"] = getString(age_text); - */ - args["[AGEVERIFICATION]"] = " "; - } - else { - args["[PAYMENTINFO]"] = " "; - args["[AGEVERIFICATION]"] = " "; + const auto account_info = getString("CaptionTextAcctInfo", args); + auto acct = getChild("acct"); + acct->setValue(account_info); + acct->setToolTip(account_info); } - LLStringUtil::format(caption_text, args); - - childSetValue("acct", caption_text); getChild("img")->setImageAssetID(pAvatarData->image_id); @@ -240,30 +193,34 @@ void LLPanelAvatarSecondLife::processProperties(void* data, EAvatarProcessorType { using namespace boost::gregorian; int year, month, day; - sscanf(pAvatarData->born_on.c_str(),"%d/%d/%d",&month,&day,&year); - std::ostringstream born_on; - born_on << pAvatarData->born_on << " (" << day_clock::local_day() - date(year, month, day) << ")"; - childSetValue("born", born_on.str()); + const auto& born = pAvatarData->born_on; + if (!born.empty() && sscanf(born.c_str(),"%d/%d/%d", &month, &day, &year) == 3 // Make sure input is valid + && month > 0 && month <= 12 && day > 0 && day <= 31 && year >= 1400) // Don't use numbers that gregorian will choke on + { + date birthday(year, month, day), today(day_clock::local_day()); + std::ostringstream born_on; + const std::locale date_fmt(std::locale::classic(), new date_facet(gSavedSettings.getString("ShortDateFormat").data())); + born_on.imbue(date_fmt); + born_on << birthday << " (" << today - birthday << ')'; + childSetValue("born", born_on.str()); + } + else childSetValue("born", born); } bool allow_publish = (pAvatarData->flags & AVATAR_ALLOW_PUBLISH); childSetValue("allow_publish", allow_publish); - setPartnerID(pAvatarData->partner_id); - updatePartnerName(); + mPartnerID = pAvatarData->partner_id; + getChildView("partner_edit")->setValue(mPartnerID); } } - else if(type == APT_GROUPS) + else if (type == APT_GROUPS) { - const LLAvatarGroups* pAvatarGroups = static_cast( data ); - if(pAvatarGroups && pAvatarGroups->avatar_id == mAvatarID && pAvatarGroups->avatar_id.notNull()) + const LLAvatarGroups* pAvatarGroups = static_cast(data); + if (pAvatarGroups && pAvatarGroups->avatar_id == mAvatarID && pAvatarGroups->avatar_id.notNull()) { - LLScrollListCtrl* group_list = getChild("groups"); -// if(group_list) -// { -// group_list->deleteAllItems(); -// } - if (0 == pAvatarGroups->group_list.size()) + LLScrollListCtrl* group_list = getChild("groups"); + if (!pAvatarGroups->group_list.size()) { group_list->setCommentText(getString("None")); } @@ -273,55 +230,38 @@ void LLPanelAvatarSecondLife::processProperties(void* data, EAvatarProcessorType { // Is this really necessary? Remove existing entry if it exists. // TODO: clear the whole list when a request for data is made - if (group_list) - { - S32 index = group_list->getItemIndex(it->group_id); - if ( index >= 0 ) - { - group_list->deleteSingleItem(index); - } - } + S32 index = group_list->getItemIndex(it->group_id); + if (index >= 0) + group_list->deleteSingleItem(index); - LLSD row; - row["id"] = it->group_id; - row["columns"][0]["value"] = it->group_id.notNull() ? it->group_name : ""; - row["columns"][0]["font"] = "SANSSERIF_SMALL"; - LLGroupData *group_data = NULL; + LLScrollListItem::Params row; + row.value(it->group_id); + std::string font_style("NORMAL"); // Set normal color if not found or if group is visible in profile if (pAvatarGroups->avatar_id == pAvatarGroups->agent_id) // own avatar - { - // Search for this group in the agent's groups list - LLDynamicArray::iterator i; - - for (i = gAgent.mGroups.begin(); i != gAgent.mGroups.end(); i++) - { + for (std::vector::iterator i = gAgent.mGroups.begin(); i != gAgent.mGroups.end(); ++i) // Search for this group in the agent's groups list if (i->mID == it->group_id) { - group_data = &*i; + if (i->mListInProfile) + font_style = "BOLD"; break; } - } - // Set normal color if not found or if group is visible in profile - if (group_data) - { - std::string font_style = group_data->mListInProfile ? "BOLD" : "NORMAL"; - if(group_data->mID == gAgent.getGroupID()) - font_style.append("|ITALIC"); - row["columns"][0]["font-style"] = font_style; - } - else - row["columns"][0]["font-style"] = "NORMAL"; - } - - if (group_list) - { - group_list->addElement(row,ADD_SORTED); - } + + if (it->group_id == gAgent.getGroupID()) + font_style.append("|ITALIC"); + row.columns.add(LLScrollListCell::Params().value(it->group_id.notNull() ? it->group_name : "").font("SANSSERIF_SMALL").font_style(font_style)); + group_list->addRow(row,ADD_SORTED); } } } } +void LLPanelAvatarSecondLife::onChangeDetailed(const LLMute& mute) +{ + if (mute.mID != mAvatarID) return; + getChild("Mute")->setValue(LLMuteList::instance().hasMute(mute)); +} + //----------------------------------------------------------------------------- // enableControls() //----------------------------------------------------------------------------- @@ -342,138 +282,39 @@ void LLPanelAvatarSecondLife::enableControls(BOOL self) childSetEnabled("?", self); } -// static -void LLPanelAvatarFirstLife::onClickImage(void* data) -{ - LLPanelAvatarFirstLife* self = (LLPanelAvatarFirstLife*)data; - - LLTextureCtrl* image_ctrl = self->getChild("img"); - if(image_ctrl) - { - LLUUID mUUID = image_ctrl->getImageAssetID(); - llinfos << "LLPanelAvatarFirstLife::onClickImage" << llendl; - if(!LLPreview::show(mUUID)) - { - // There isn't one, so make a new preview - S32 left, top; - gFloaterView->getNewFloaterPosition(&left, &top); - LLRect rect = gSavedSettings.getRect("PreviewTextureRect"); - rect.translate( left - rect.mLeft, rect.mTop - top ); // Changed to avoid textures being sunken below the window border. - LLPreviewTexture* preview = new LLPreviewTexture("preview task texture", - rect, - std::string("Profile First Life Picture"), - mUUID); - preview->setFocus(TRUE); - //preview->mIsCopyable=FALSE; - //preview->canSaveAs - } - - } -} - // virtual void LLPanelAvatarFirstLife::processProperties(void* data, EAvatarProcessorType type) { - if(type == APT_PROPERTIES) + if (type == APT_PROPERTIES) { - const LLAvatarData* pAvatarData = static_cast( data ); + const LLAvatarData* pAvatarData = static_cast(data); if (pAvatarData && (mAvatarID == pAvatarData->avatar_id) && (pAvatarData->avatar_id != LLUUID::null)) { // Teens don't get these - childSetValue("about", pAvatarData->fl_about_text); + getChild("about")->setText(pAvatarData->fl_about_text, false); getChild("img")->setImageAssetID(pAvatarData->fl_image_id); } } } -// static -void LLPanelAvatarSecondLife::onClickImage(void* data) -{ - LLPanelAvatarSecondLife* self = (LLPanelAvatarSecondLife*)data; - LLNameEditor* name_ctrl = self->getChild("dnname"); - if(name_ctrl) - { - std::string name_text = name_ctrl->getText(); - - LLTextureCtrl* image_ctrl = self->getChild("img"); - if(image_ctrl) - { - LLUUID mUUID = image_ctrl->getImageAssetID(); - llinfos << "LLPanelAvatarSecondLife::onClickImage" << llendl; - if(!LLPreview::show(mUUID)) - { - // There isn't one, so make a new preview - S32 left, top; - gFloaterView->getNewFloaterPosition(&left, &top); - LLRect rect = gSavedSettings.getRect("PreviewTextureRect"); - rect.translate( left - rect.mLeft, rect.mTop - top ); // Changed to avoid textures being sunken below the window border. - LLPreviewTexture* preview = new LLPreviewTexture("preview task texture", - rect, - std::string("Profile Picture: ") + name_text, - mUUID - ); - preview->setFocus(TRUE); - - //preview->mIsCopyable=FALSE; - } - /*open_texture(LLUUID::null,//image_ctrl->getImageAssetID(), - std::string("Profile Picture: ") + - name_text+ - "and image id is "+ - image_ctrl->getImageAssetID().asString() - , FALSE, image_ctrl->getImageAssetID(), TRUE);*/ - } - } - - -} - -// static -void LLPanelAvatarSecondLife::onDoubleClickGroup(void* data) -{ - LLPanelAvatarSecondLife* self = (LLPanelAvatarSecondLife*)data; - - LLScrollListCtrl* group_list = self->getChild("groups"); - if(group_list) - { - LLScrollListItem* item = group_list->getFirstSelected(); - if (item) - { - LLGroupActions::show(item->getUUID()); - } - } -} - -// static -void LLPanelAvatarSecondLife::onClickPublishHelp(void *) -{ - LLNotificationsUtil::add("ClickPublishHelpAvatar"); -} - -// static -void LLPanelAvatarSecondLife::onClickPartnerHelp(void *) +void LLPanelAvatarSecondLife::onDoubleClickGroup() { - LLNotificationsUtil::add("ClickPartnerHelpAvatar", LLSD(), LLSD(), onClickPartnerHelpLoadURL); + if (LLScrollListItem* item = getChild("groups")->getFirstSelected()) + LLGroupActions::show(item->getUUID()); } -// static +// static - Not anymore :P bool LLPanelAvatarSecondLife::onClickPartnerHelpLoadURL(const LLSD& notification, const LLSD& response) { - S32 option = LLNotification::getSelectedOption(notification, response); - if (option == 0) + if (!LLNotification::getSelectedOption(notification, response)) { - LLWeb::loadURL("http://secondlife.com/partner"); + const auto& grid = *gHippoGridManager->getConnectedGrid(); + const std::string url = grid.isSecondLife() ? "http://secondlife.com/partner" : grid.getPartnerUrl(); + if (!url.empty()) LLWeb::loadURL(url); } return false; } -// static -void LLPanelAvatarSecondLife::onClickPartnerInfo(void *data) -{ - LLPanelAvatarSecondLife* self = (LLPanelAvatarSecondLife*) data; - LLAvatarActions::showProfile(self->mPartnerID); -} - //----------------------------------------------------------------------------- // LLPanelAvatarFirstLife() //----------------------------------------------------------------------------- @@ -494,15 +335,32 @@ void LLPanelAvatarFirstLife::enableControls(BOOL self) // postBuild //----------------------------------------------------------------------------- -BOOL LLPanelAvatarSecondLife::postBuild(void) +void show_picture(const LLUUID& id, const std::string& name); +static std::string profile_picture_title(const std::string& str) { return "Profile Picture: " + str; } +static void show_partner_help() { LLNotificationsUtil::add("ClickPartnerHelpAvatar", LLSD(), LLSD(), boost::bind(LLPanelAvatarSecondLife::onClickPartnerHelpLoadURL, _1, _2)); } +void show_log_browser(const LLUUID& id, const LFIDBearer::Type& type) +{ + void show_log_browser(const std::string& name, const LLUUID& id); + std::string name; + if (type == LFIDBearer::AVATAR) + { + LLAvatarName av_name; + LLAvatarNameCache::get(id, &av_name); + name = av_name.getLegacyName(); + } + else // GROUP + { + gCacheName->getGroupName(id, name); + } + show_log_browser(name, id); +} +BOOL LLPanelAvatarSecondLife::postBuild() { childSetEnabled("born", FALSE); childSetEnabled("partner_edit", FALSE); - childSetAction("partner_help",onClickPartnerHelp,this); - childSetAction("partner_info", onClickPartnerInfo, this); - childSetEnabled("partner_info", mPartnerID.notNull()); - - childSetAction("?",onClickPublishHelp,this); + getChild("partner_help")->setCommitCallback(boost::bind(show_partner_help)); + + childSetAction("?", boost::bind(LLNotificationsUtil::add, "ClickPublishHelpAvatar")); LLPanelAvatar* pa = getPanelAvatar(); enableControls(pa->getAvatarID() == gAgentID); @@ -517,59 +375,75 @@ BOOL LLPanelAvatarSecondLife::postBuild(void) getChild("Find on Map")->setCommitCallback(boost::bind(LLAvatarActions::showOnMap, boost::bind(&LLPanelAvatar::getAvatarID, pa))); getChild("Instant Message...")->setCommitCallback(boost::bind(LLAvatarActions::startIM, boost::bind(&LLPanelAvatar::getAvatarID, pa))); - getChild("GroupInvite_Button")->setCommitCallback(boost::bind(LLAvatarActions::inviteToGroup, boost::bind(&LLPanelAvatar::getAvatarID, pa))); + getChild("GroupInvite_Button")->setCommitCallback(boost::bind(static_cast(LLAvatarActions::inviteToGroup), boost::bind(&LLPanelAvatar::getAvatarID, pa))); getChild("Add Friend...")->setCommitCallback(boost::bind(LLAvatarActions::requestFriendshipDialog, boost::bind(&LLPanelAvatar::getAvatarID, pa))); + getChild("Log")->setCommitCallback(boost::bind(show_log_browser, boost::bind(&LLPanelAvatar::getAvatarID, pa), LFIDBearer::AVATAR)); getChild("Pay...")->setCommitCallback(boost::bind(LLAvatarActions::pay, boost::bind(&LLPanelAvatar::getAvatarID, pa))); - getChild("Mute")->setCommitCallback(boost::bind(LLAvatarActions::toggleBlock, boost::bind(&LLPanelAvatar::getAvatarID, pa))); + if (LLUICtrl* ctrl = findChild("Mute")) + { + ctrl->setCommitCallback(boost::bind(LLAvatarActions::toggleBlock, boost::bind(&LLPanelAvatar::getAvatarID, pa))); + ctrl->setValue(LLMuteList::instance().isMuted(mAvatarID)); + } getChild("Offer Teleport...")->setCommitCallback(boost::bind(static_cast(LLAvatarActions::offerTeleport), boost::bind(&LLPanelAvatar::getAvatarID, pa))); getChild("groups")->setDoubleClickCallback(boost::bind(&LLPanelAvatarSecondLife::onDoubleClickGroup,this)); - - childSetAction("bigimg", onClickImage, this); - - getChild("img")->setFallbackImageName("default_profile_picture.j2c"); + + LLTextureCtrl* ctrl = getChild("img"); + ctrl->setFallbackImageName("default_profile_picture.j2c"); + auto show_pic = [&] + { + show_picture(getChild("img")->getImageAssetID(), profile_picture_title(getChild("dnname")->getText())); + }; + auto show_pic_if_not_self = [=] { if (!ctrl->canChange()) show_pic(); }; + + ctrl->setMouseUpCallback(std::bind(show_pic_if_not_self)); + getChild("bigimg")->setCommitCallback(std::bind(show_pic)); return TRUE; } -BOOL LLPanelAvatarFirstLife::postBuild(void) +BOOL LLPanelAvatarFirstLife::postBuild() { - BOOL own_avatar = (getPanelAvatar()->getAvatarID() == gAgent.getID() ); - enableControls(own_avatar); + enableControls(getPanelAvatar()->getAvatarID() == gAgentID); - getChild("img")->setFallbackImageName("default_profile_picture.j2c"); + LLTextureCtrl* ctrl = getChild("img"); + ctrl->setFallbackImageName("default_profile_picture.j2c"); + auto show_pic = [&] + { + show_picture(getChild("img")->getImageAssetID(), "First Life Picture"); + }; + auto show_pic_if_not_self = [=] { if (!ctrl->canChange()) show_pic(); }; - childSetAction("flbigimg", onClickImage, this); + ctrl->setMouseUpCallback(std::bind(show_pic_if_not_self)); + getChild("flbigimg")->setCommitCallback(std::bind(show_pic)); return TRUE; } -BOOL LLPanelAvatarNotes::postBuild(void) +BOOL LLPanelAvatarNotes::postBuild() { - getChild("notes edit")->setCommitCallback(boost::bind(&LLPanelAvatar::sendAvatarNotesUpdate, getPanelAvatar())); - - LLTextEditor* te = getChild("notes edit"); - if(te) te->setCommitOnFocusLost(TRUE); + LLTextEditor* te(getChild("notes edit")); + te->setCommitCallback(boost::bind(&LLPanelAvatar::sendAvatarNotesUpdate, getPanelAvatar())); + te->setCommitOnFocusLost(true); return TRUE; } -BOOL LLPanelAvatarWeb::postBuild(void) +BOOL LLPanelAvatarWeb::postBuild() { LLLineEditor* url_edit = getChild("url_edit"); - url_edit->setKeystrokeCallback(boost::bind(&LLPanelAvatarWeb::onURLKeystroke,this,_1)); - url_edit->setCommitCallback(boost::bind(&LLPanelAvatarWeb::onCommitURL,this,_2)); + LLUICtrl* loadctrl = getChild("load"); - getChild("load")->setCommitCallback(boost::bind(&LLPanelAvatarWeb::onCommitLoad, this, _2)); + url_edit->setKeystrokeCallback(boost::bind(&LLView::setEnabled, loadctrl, boost::bind(&std::string::length, boost::bind(&LLLineEditor::getText, _1)))); + url_edit->setCommitCallback(boost::bind(&LLPanelAvatarWeb::load, this, boost::bind(&LLSD::asString, _2))); - childSetAction("web_profile_help",onClickWebProfileHelp,this); + loadctrl->setCommitCallback(boost::bind(&LLPanelAvatarWeb::onCommitLoad, this, _2)); + + getChild("web_profile_help")->setCommitCallback(boost::bind(LLNotificationsUtil::add, "ClickWebProfileHelpAvatar")); mWebBrowser = getChild("profile_html"); mWebBrowser->addObserver(this); - // links open in internally - //mWebBrowser->setOpenInExternalBrowser( false ); - return TRUE; } @@ -586,21 +460,27 @@ void LLPanelAvatarWeb::processProperties(void* data, EAvatarProcessorType type) } } -BOOL LLPanelAvatarClassified::postBuild(void) +BOOL LLPanelAvatarClassified::postBuild() { - childSetAction("New...",onClickNew,this); - childSetAction("Delete...",onClickDelete,this); + getChild("New...")->setCommitCallback(boost::bind(&LLPanelAvatarClassified::onClickNew, this)); + getChild("Delete...")->setCommitCallback(boost::bind(&LLPanelAvatarClassified::onClickDelete, this)); + // *HACK: Don't allow making new classifieds from inside the directory. + // The logic for save/don't save when closing is too hairy, and the + // directory is conceptually read-only. JC + for (LLView* view = this; !mInDirectory && view; view = view->getParent()) + if (view->getName() == "directory") + mInDirectory = true; return TRUE; } -BOOL LLPanelAvatarPicks::postBuild(void) +BOOL LLPanelAvatarPicks::postBuild() { - childSetAction("New...",onClickNew,this); - childSetAction("Delete...",onClickDelete,this); + getChild("New...")->setCommitCallback(boost::bind(&LLPanelAvatarPicks::onClickNew, this)); + getChild("Delete...")->setCommitCallback(boost::bind(&LLPanelAvatarPicks::onClickDelete, this)); //For pick import and export - RK - childSetAction("Import...",onClickImport,this); - childSetAction("Export...",onClickExport,this); + getChild("Import...")->setCommitCallback(boost::bind(&LLPanelAvatarPicks::onClickImport, this)); + getChild("Export...")->setCommitCallback(boost::bind(&LLPanelAvatarPicks::onClickExport, this)); return TRUE; } @@ -662,15 +542,15 @@ LLPanelAvatarWeb::~LLPanelAvatarWeb() if ( mWebBrowser ) { mWebBrowser->remObserver( this ); - }; + } } void LLPanelAvatarWeb::refresh() { - if (mNavigateTo != "") + if (!mNavigateTo.empty()) { - llinfos << "Loading " << mNavigateTo << llendl; - mWebBrowser->navigateTo( mNavigateTo ); + LL_INFOS() << "Loading " << mNavigateTo << LL_ENDL; + mWebBrowser->navigateTo(mNavigateTo); mNavigateTo = ""; } } @@ -688,45 +568,29 @@ void LLPanelAvatarWeb::setWebURL(std::string url) bool changed_url = (mHome != url); mHome = url; - bool have_url = !mHome.empty(); childSetText("url_edit", mHome); childSetEnabled("load", mHome.length() > 0); - if (have_url - && gSavedSettings.getBOOL("AutoLoadWebProfiles")) + if (!mHome.empty() && gSavedSettings.getBOOL("AutoLoadWebProfiles")) { if (changed_url) { load(mHome); } + childSetVisible("status_text", getPanelAvatar()->getAvatarID() != gAgentID); } else { - childSetVisible("profile_html",false); + childSetVisible("profile_html", false); childSetVisible("status_text", false); } - BOOL own_avatar = (getPanelAvatar()->getAvatarID() == gAgent.getID() ); - childSetVisible("status_text",!own_avatar && !mHome.empty()); -} - - -void LLPanelAvatarWeb::onCommitURL(const LLSD& value) -{ - load(value.asString()); -} - -// static -void LLPanelAvatarWeb::onClickWebProfileHelp(void *) -{ - LLNotificationsUtil::add("ClickWebProfileHelpAvatar"); } -void LLPanelAvatarWeb::load(std::string url) +void LLPanelAvatarWeb::load(const std::string& url) { bool have_url = (!url.empty()); - childSetVisible("profile_html", have_url); childSetVisible("status_text", have_url); childSetText("status_text", LLStringUtil::null); @@ -737,34 +601,21 @@ void LLPanelAvatarWeb::load(std::string url) } } -void LLPanelAvatarWeb::onURLKeystroke(LLLineEditor* editor) -{ - LLSD::String url = editor->getText(); - childSetEnabled("load", url.length() > 0); - return; -} - void LLPanelAvatarWeb::onCommitLoad(const LLSD& value) { - LLSD::String valstr = value.asString(); - LLSD::String urlstr = childGetText("url_edit"); - if (valstr == "") // load url string into browser panel + const std::string& valstr(value.asString()); + if (valstr.empty()) // load url string into browser panel { - load(urlstr); + load(childGetText("url_edit")); } else if (valstr == "open") // open in user's external browser { - if (!urlstr.empty()) - { - LLWeb::loadURLExternal(urlstr); - } + const std::string& urlstr(childGetText("url_edit")); + if (!urlstr.empty()) LLWeb::loadURLExternal(urlstr); } else if (valstr == "home") // reload profile owner's home page { - if (!mHome.empty()) - { - load(mHome); - } + if (!mHome.empty()) load(mHome); } } @@ -775,13 +626,13 @@ void LLPanelAvatarWeb::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent ev switch(event) { case MEDIA_EVENT_STATUS_TEXT_CHANGED: - childSetText("status_text", self->getStatusText() ); + childSetText("status_text", self->getStatusText()); break; - + case MEDIA_EVENT_LOCATION_CHANGED: - childSetText("url_edit", self->getLocation() ); + childSetText("url_edit", self->getLocation()); break; - + default: // Having a default case makes the compiler happy. break; @@ -804,37 +655,35 @@ LLPanelAvatarAdvanced::LLPanelAvatarAdvanced(const std::string& name, void LLPanelAvatarAdvanced::enableControls(BOOL self) { - S32 t; - for(t=0;tsetEnabled(self); - } - for(t=0;tsetEnabled(self); - } - - if (mWantToEdit) mWantToEdit->setEnabled(self); - if (mSkillsEdit) mSkillsEdit->setEnabled(self); - childSetEnabled("languages_edit",self); + for(S32 t(0); t < mWantToCount; ++t) + if (mWantToCheck[t]) + mWantToCheck[t]->setEnabled(self); + for(S32 t(0); t < mSkillsCount; ++t) + if (mSkillsCheck[t]) + mSkillsCheck[t]->setEnabled(self); + if (mWantToEdit) + mWantToEdit->setEnabled(self); + if (mSkillsEdit) + mSkillsEdit->setEnabled(self); + childSetEnabled("languages_edit", self); } void LLPanelAvatarAdvanced::setWantSkills(U32 want_to_mask, const std::string& want_to_text, U32 skills_mask, const std::string& skills_text, const std::string& languages_text) { - for(int id =0;idset( want_to_mask & 1<set(want_to_mask & 1<set( skills_mask & 1<set(skills_mask & 1<setText( want_to_text ); - mSkillsEdit->setText( skills_text ); + mWantToEdit->setText(want_to_text); + mSkillsEdit->setText(skills_text); } childSetText("languages_edit",languages_text); @@ -847,30 +696,22 @@ void LLPanelAvatarAdvanced::getWantSkills(U32* want_to_mask, std::string& want_t if (want_to_mask) { *want_to_mask = 0; - for(int t=0;tget()) + for(S32 t = 0; t < mWantToCount; ++t) + if (mWantToCheck[t]->get()) *want_to_mask |= 1<get()) *skills_mask |= 1<getText(); - } if (mSkillsEdit) - { skills_text = mSkillsEdit->getText(); - } languages_text = childGetText("languages_edit"); } @@ -894,8 +735,9 @@ void LLPanelAvatarNotes::refresh() void LLPanelAvatarNotes::clearControls() { - childSetText("notes edit", getString("Loading")); - childSetEnabled("notes edit", false); + LLView* view(getChildView("notes edit")); + view->setValue(getString("Loading")); + view->setEnabled(false); } @@ -905,45 +747,12 @@ void LLPanelAvatarNotes::clearControls() LLPanelAvatarClassified::LLPanelAvatarClassified(const std::string& name, const LLRect& rect, LLPanelAvatar* panel_avatar) : LLPanelAvatarTab(name, rect, panel_avatar) +, mInDirectory(false) { } - void LLPanelAvatarClassified::refresh() { - BOOL self = (gAgent.getID() == getPanelAvatar()->getAvatarID()); - - LLTabContainer* tabs = getChild("classified tab"); - - S32 tab_count = tabs ? tabs->getTabCount() : 0; - - bool allow_new = tab_count < MAX_CLASSIFIEDS; -// [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0a) - allow_new &= !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC); -// [/RLVa:KB] - bool allow_delete = (tab_count > 0); - bool show_help = (tab_count == 0); - - // *HACK: Don't allow making new classifieds from inside the directory. - // The logic for save/don't save when closing is too hairy, and the - // directory is conceptually read-only. JC - bool in_directory = false; - LLView* view = this; - while (view) - { - if (view->getName() == "directory") - { - in_directory = true; - break; - } - view = view->getParent(); - } - childSetEnabled("New...", self && !in_directory && allow_new); - childSetVisible("New...", !in_directory); - childSetEnabled("Delete...", self && !in_directory && allow_delete); - childSetVisible("Delete...", !in_directory); - childSetVisible("classified tab",!show_help); - if (!isDataRequested()) { LLAvatarPropertiesProcessor::getInstance()->sendAvatarClassifiedsRequest(mAvatarID); @@ -957,7 +766,7 @@ BOOL LLPanelAvatarClassified::canClose() LLTabContainer* tabs = getChild("classified tab"); for (S32 i = 0; i < tabs->getTabCount(); i++) { - LLPanelClassified* panel = (LLPanelClassified*)tabs->getPanelByIndex(i); + LLPanelClassifiedInfo* panel = (LLPanelClassifiedInfo*)tabs->getPanelByIndex(i); if (!panel->canClose()) { return FALSE; @@ -968,19 +777,10 @@ BOOL LLPanelAvatarClassified::canClose() BOOL LLPanelAvatarClassified::titleIsValid() { - LLTabContainer* tabs = getChild("classified tab"); - if ( tabs ) - { - LLPanelClassified* panel = (LLPanelClassified*)tabs->getCurrentPanel(); - if ( panel ) - { - if ( ! panel->titleIsValid() ) - { + if (LLTabContainer* tabs = getChild("classified tab")) + if (LLPanelClassifiedInfo* panel = (LLPanelClassifiedInfo*)tabs->getCurrentPanel()) + if (!panel->titleIsValid()) return FALSE; - }; - }; - }; - return TRUE; } @@ -989,7 +789,7 @@ void LLPanelAvatarClassified::apply() LLTabContainer* tabs = getChild("classified tab"); for (S32 i = 0; i < tabs->getTabCount(); i++) { - LLPanelClassified* panel = (LLPanelClassified*)tabs->getPanelByIndex(i); + LLPanelClassifiedInfo* panel = (LLPanelClassifiedInfo*)tabs->getPanelByIndex(i); panel->apply(); } } @@ -997,12 +797,7 @@ void LLPanelAvatarClassified::apply() void LLPanelAvatarClassified::deleteClassifiedPanels() { - LLTabContainer* tabs = getChild("classified tab"); - if (tabs) - { - tabs->deleteAllTabs(); - } - + getChild("classified tab")->deleteAllTabs(); childSetVisible("New...", false); childSetVisible("Delete...", false); childSetVisible("loading_text", true); @@ -1011,17 +806,17 @@ void LLPanelAvatarClassified::deleteClassifiedPanels() // virtual void LLPanelAvatarClassified::processProperties(void* data, EAvatarProcessorType type) { - if(type == APT_CLASSIFIEDS) + if (type == APT_CLASSIFIEDS) { LLAvatarClassifieds* c_info = static_cast(data); - if(c_info && mAvatarID == c_info->target_id) + if (c_info && mAvatarID == c_info->target_id) { LLTabContainer* tabs = getChild("classified tab"); - + for(LLAvatarClassifieds::classifieds_list_t::iterator it = c_info->classifieds_list.begin(); it != c_info->classifieds_list.end(); ++it) { - LLPanelClassified* panel_classified = new LLPanelClassified(false, false); + LLPanelClassifiedInfo* panel_classified = new LLPanelClassifiedInfo(false, false); panel_classified->setClassifiedID(it->classified_id); @@ -1029,22 +824,27 @@ void LLPanelAvatarClassified::processProperties(void* data, EAvatarProcessorType panel_classified->markForServerRequest(); // The button should automatically truncate long names for us - if(tabs) - { - tabs->addTabPanel(panel_classified, it->name); - } + tabs->addTabPanel(panel_classified, it->name); } // Make sure somebody is highlighted. This works even if there // are no tabs in the container. - if(tabs) - { - tabs->selectFirstTab(); - } + tabs->selectFirstTab(); - childSetVisible("New...", true); - childSetVisible("Delete...", true); - childSetVisible("loading_text", false); + bool self = gAgentID == mAvatarID; + S32 tab_count = tabs->getTabCount(); + bool allow_new = tab_count < MAX_CLASSIFIEDS +// [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0a) + && !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC); +// [/RLVa:KB] + LLView* view(getChildView("New...")); + view->setEnabled(self && !mInDirectory && allow_new); + view->setVisible(!mInDirectory); + view = getChildView("Delete..."); + view->setEnabled(self && !mInDirectory && tab_count); + view->setVisible(!mInDirectory); + view = getChildView("loading_text"); + view->setVisible(false); } } } @@ -1052,82 +852,63 @@ void LLPanelAvatarClassified::processProperties(void* data, EAvatarProcessorType // Create a new classified panel. It will automatically handle generating // its own id when it's time to save. // static -void LLPanelAvatarClassified::onClickNew(void* data) +void LLPanelAvatarClassified::onClickNew() { // [RLVa:KB] - Version: 1.23.4 | Checked: 2009-07-04 (RLVa-1.0.0a) - if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) - { - return; - } + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) return; // [/RLVa:KB] - LLPanelAvatarClassified* self = (LLPanelAvatarClassified*)data; - - LLNotificationsUtil::add("AddClassified", LLSD(), LLSD(), boost::bind(&LLPanelAvatarClassified::callbackNew, self, _1, _2)); + LLNotificationsUtil::add("AddClassified", LLSD(), LLSD(), boost::bind(&LLPanelAvatarClassified::callbackNew, this, _1, _2)); } bool LLPanelAvatarClassified::callbackNew(const LLSD& notification, const LLSD& response) { - S32 option = LLNotification::getSelectedOption(notification, response); - if (0 == option) - { - LLPanelClassified* panel_classified = new LLPanelClassified(false, false); - panel_classified->initNewClassified(); - LLTabContainer* tabs = getChild("classified tab"); - if(tabs) - { - tabs->addTabPanel(panel_classified, panel_classified->getClassifiedName()); - tabs->selectLastTab(); - } - } - return false; + if (LLNotification::getSelectedOption(notification, response)) + return false; + LLPanelClassifiedInfo* panel_classified = new LLPanelClassifiedInfo(false, false); + panel_classified->initNewClassified(); + LLTabContainer* tabs = getChild("classified tab"); + tabs->addTabPanel(panel_classified, panel_classified->getClassifiedName()); + tabs->selectLastTab(); + bool allow_new = tabs->getTabCount() < MAX_CLASSIFIEDS +// [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0a) + && !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC); +// [/RLVa:KB] + childSetEnabled("New...", allow_new); + childSetEnabled("Delete...", true); + return true; } // static -void LLPanelAvatarClassified::onClickDelete(void* data) +void LLPanelAvatarClassified::onClickDelete() { - LLPanelAvatarClassified* self = (LLPanelAvatarClassified*)data; - - LLTabContainer* tabs = self->getChild("classified tab"); - LLPanelClassified* panel_classified = NULL; - if(tabs) - { - panel_classified = (LLPanelClassified*)tabs->getCurrentPanel(); - } + LLTabContainer* tabs = getChild("classified tab"); + LLPanelClassifiedInfo* panel_classified = (LLPanelClassifiedInfo*)tabs->getCurrentPanel(); if (!panel_classified) return; LLSD args; args["NAME"] = panel_classified->getClassifiedName(); - LLNotificationsUtil::add("DeleteClassified", args, LLSD(), boost::bind(&LLPanelAvatarClassified::callbackDelete, self, _1, _2)); - + LLNotificationsUtil::add("DeleteClassified", args, LLSD(), boost::bind(&LLPanelAvatarClassified::callbackDelete, this, _1, _2)); } -bool LLPanelAvatarClassified::callbackDelete(const LLSD& notification, const LLSD& response) +bool LLPanelAvatarClassified::callbackDelete(const LLSD& notification, const LLSD& response) { - S32 option = LLNotification::getSelectedOption(notification, response); + if (LLNotification::getSelectedOption(notification, response)) + return false; LLTabContainer* tabs = getChild("classified tab"); - LLPanelClassified* panel_classified=NULL; - if(tabs) - { - panel_classified = (LLPanelClassified*)tabs->getCurrentPanel(); - } + LLPanelClassifiedInfo* panel_classified = (LLPanelClassifiedInfo*)tabs->getCurrentPanel(); if (!panel_classified) return false; - if (0 == option) - { - LLAvatarPropertiesProcessor::getInstance()->sendClassifiedDelete(panel_classified->getClassifiedID()); - - if(tabs) - { - tabs->removeTabPanel(panel_classified); - } - delete panel_classified; - panel_classified = NULL; - } - return false; + LLAvatarPropertiesProcessor::getInstance()->sendClassifiedDelete(panel_classified->getClassifiedID()); + tabs->removeTabPanel(panel_classified); + delete panel_classified; + panel_classified = NULL; + childSetEnabled("New...", !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)); + childSetEnabled("Delete...", tabs->getTabCount()); + return true; } @@ -1144,22 +925,6 @@ LLPanelAvatarPicks::LLPanelAvatarPicks(const std::string& name, void LLPanelAvatarPicks::refresh() { - BOOL self = (gAgent.getID() == getPanelAvatar()->getAvatarID()); - LLTabContainer* tabs = getChild("picks tab"); - S32 tab_count = tabs ? tabs->getTabCount() : 0; -// [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0a) - childSetEnabled("New...", self && tab_count < MAX_AVATAR_PICKS && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) ); -// [/RLVa:KB] - //childSetEnabled("New...", self && tab_count < MAX_AVATAR_PICKS); - childSetEnabled("Delete...", self && tab_count > 0); - childSetVisible("New...", self && getPanelAvatar()->isEditable()); - childSetVisible("Delete...", self && getPanelAvatar()->isEditable()); - - //For pick import/export - RK - childSetVisible("Import...", self && getPanelAvatar()->isEditable()); - childSetEnabled("Export...", self && tab_count > 0); - childSetVisible("Export...", self && getPanelAvatar()->isEditable()); - if (!isDataRequested()) { LLAvatarPropertiesProcessor::getInstance()->sendAvatarPicksRequest(mAvatarID); @@ -1170,11 +935,7 @@ void LLPanelAvatarPicks::refresh() void LLPanelAvatarPicks::deletePickPanels() { - LLTabContainer* tabs = getChild("picks tab"); - if(tabs) - { - tabs->deleteAllTabs(); - } + getChild("picks tab")->deleteAllTabs(); childSetVisible("New...", false); childSetVisible("Delete...", false); @@ -1189,14 +950,14 @@ void LLPanelAvatarPicks::deletePickPanels() // virtual void LLPanelAvatarPicks::processProperties(void* data, EAvatarProcessorType type) { - if(type == APT_PICKS) + if (type == APT_PICKS) { LLAvatarPicks* picks = static_cast(data); //llassert_always(picks->target_id != gAgent.getID()); //llassert_always(mAvatarID != gAgent.getID()); - if(picks && mAvatarID == picks->target_id) + if (picks && mAvatarID == picks->target_id) { LLTabContainer* tabs = getChild("picks tab"); @@ -1204,7 +965,8 @@ void LLPanelAvatarPicks::processProperties(void* data, EAvatarProcessorType type // number of new panels. deletePickPanels(); - for(LLAvatarPicks::picks_list_t::iterator it = picks->picks_list.begin(); + bool self(gAgentID == mAvatarID); + for (LLAvatarPicks::picks_list_t::iterator it = picks->picks_list.begin(); it != picks->picks_list.end(); ++it) { LLPanelPick* panel_pick = new LLPanelPick(); @@ -1215,146 +977,140 @@ void LLPanelAvatarPicks::processProperties(void* data, EAvatarProcessorType type panel_pick->markForServerRequest(); // The button should automatically truncate long names for us - if(tabs) - { - llinfos << "Adding tab for " << mAvatarID << " " << ((mAvatarID == gAgent.getID()) ? "Self" : "Other") << ": '" << it->second << "'" << llendl; - tabs->addTabPanel(panel_pick, it->second); - } + LL_INFOS() << "Adding tab for " << mAvatarID << " " << (self ? "Self" : "Other") << ": '" << it->second << "'" << LL_ENDL; + tabs->addTabPanel(panel_pick, it->second); } // Make sure somebody is highlighted. This works even if there // are no tabs in the container. - if(tabs) - { - tabs->selectFirstTab(); - } + tabs->selectFirstTab(); + bool edit(getPanelAvatar()->isEditable()); + auto count = tabs->getTabCount(); + bool can_add = self && count < LLAgentBenefitsMgr::current().getPicksLimit(); + LLView* view = getChildView("New..."); + view->setEnabled(can_add +// [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0a) + && !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)); +// [/RLVa:KB] + view->setVisible(self && edit); + view = getChildView("Delete..."); + view->setEnabled(count); + view->setVisible(self && edit); + + //For pick import/export - RK + view = getChildView("Import..."); + view->setVisible(self && edit); + view->setEnabled(can_add); + view = getChildView("Export..."); + view->setEnabled(count); + view->setVisible(self); - childSetVisible("New...", true); - childSetVisible("Delete...", true); childSetVisible("loading_text", false); - - //For pick import and export - RK - childSetVisible("Import...", true); - childSetVisible("Export...", true); } } } // Create a new pick panel. It will automatically handle generating // its own id when it's time to save. -// static -void LLPanelAvatarPicks::onClickNew(void* data) +void LLPanelAvatarPicks::onClickNew() { // [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0a) if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) - { return; - } // [/RLVa:KB] - LLPanelAvatarPicks* self = (LLPanelAvatarPicks*)data; - LLPanelPick* panel_pick = new LLPanelPick(); - LLTabContainer* tabs = self->getChild("picks tab"); + LLPanelPick* panel_pick = new LLPanelPick; + LLTabContainer* tabs = getChild("picks tab"); panel_pick->initNewPick(); - if(tabs) - { - tabs->addTabPanel(panel_pick, panel_pick->getPickName()); - tabs->selectLastTab(); - } + tabs->addTabPanel(panel_pick, panel_pick->getPickName()); + tabs->selectLastTab(); + bool can_add = tabs->getTabCount() < LLAgentBenefitsMgr::current().getPicksLimit(); + getChildView("New...")->setEnabled(can_add +// [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0a) + && !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)); +// [/RLVa:KB] + getChildView("Delete...")->setEnabled(true); + getChildView("Import...")->setEnabled(can_add); } //Pick import and export - RK -// static -void LLPanelAvatarPicks::onClickImport(void* data) +void LLPanelAvatarPicks::onClickImport() { - LLPanelAvatarPicks* self = (LLPanelAvatarPicks*)data; - self->mPanelPick = new LLPanelPick(); - self->mPanelPick->importNewPick(&LLPanelAvatarPicks::onClickImport_continued, data); + mPanelPick = new LLPanelPick; + mPanelPick->importNewPick(&LLPanelAvatarPicks::onClickImport_continued, this); } // static -void LLPanelAvatarPicks::onClickImport_continued(void* data, bool import) +void LLPanelAvatarPicks::onClickImport_continued(void* data, bool importt) { LLPanelAvatarPicks* self = (LLPanelAvatarPicks*)data; LLTabContainer* tabs = self->getChild("picks tab"); - if(tabs && import && self->mPanelPick) + if (importt && self->mPanelPick) { tabs->addTabPanel(self->mPanelPick, self->mPanelPick->getPickName()); tabs->selectLastTab(); + self->childSetEnabled("New...", !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)); + self->childSetEnabled("Delete...", false); + self->childSetEnabled("Import...", tabs->getTabCount() < LLAgentBenefitsMgr::current().getPicksLimit()); } } -// static -void LLPanelAvatarPicks::onClickExport(void* data) +void LLPanelAvatarPicks::onClickExport() { - LLPanelAvatarPicks* self = (LLPanelAvatarPicks*)data; - LLTabContainer* tabs = self->getChild("picks tab"); - LLPanelPick* panel_pick = tabs?(LLPanelPick*)tabs->getCurrentPanel():NULL; - + LLPanelPick* panel_pick = (LLPanelPick*)getChild("picks tab")->getCurrentPanel(); if (!panel_pick) return; panel_pick->exportPick(); } - -// static -void LLPanelAvatarPicks::onClickDelete(void* data) +void LLPanelAvatarPicks::onClickDelete() { - LLPanelAvatarPicks* self = (LLPanelAvatarPicks*)data; - LLTabContainer* tabs = self->getChild("picks tab"); - LLPanelPick* panel_pick = tabs?(LLPanelPick*)tabs->getCurrentPanel():NULL; - + LLPanelPick* panel_pick = (LLPanelPick*)getChild("picks tab")->getCurrentPanel(); if (!panel_pick) return; LLSD args; args["PICK"] = panel_pick->getPickName(); LLNotificationsUtil::add("DeleteAvatarPick", args, LLSD(), - boost::bind(&LLPanelAvatarPicks::callbackDelete, self, _1, _2)); + boost::bind(&LLPanelAvatarPicks::callbackDelete, this, _1, _2)); } - -// static bool LLPanelAvatarPicks::callbackDelete(const LLSD& notification, const LLSD& response) { - S32 option = LLNotification::getSelectedOption(notification, response); + if (LLNotification::getSelectedOption(notification, response)) + return false; LLTabContainer* tabs = getChild("picks tab"); - LLPanelPick* panel_pick = tabs ? (LLPanelPick*)tabs->getCurrentPanel() : NULL; - LLMessageSystem* msg = gMessageSystem; - + LLPanelPick* panel_pick = (LLPanelPick*)tabs->getCurrentPanel(); if (!panel_pick) return false; - if (0 == option) - { - // If the viewer has a hacked god-mode, then this call will - // fail. - if(gAgent.isGodlike()) - { - msg->newMessage("PickGodDelete"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID()); - msg->addUUID("SessionID", gAgent.getSessionID()); - msg->nextBlock("Data"); - msg->addUUID("PickID", panel_pick->getPickID()); - // *HACK: We need to send the pick's creator id to accomplish - // the delete, and we don't use the query id for anything. JC - msg->addUUID( "QueryID", panel_pick->getPickCreatorID() ); - gAgent.sendReliableMessage(); - } - else - { - LLAvatarPropertiesProcessor::getInstance()->sendPickDelete(panel_pick->getPickID()); - } - + LLMessageSystem* msg = gMessageSystem; - if(tabs) - { - tabs->removeTabPanel(panel_pick); - } - delete panel_pick; - panel_pick = NULL; + // If the viewer has a hacked god-mode, then this call will fail. + if (gAgent.isGodlike()) + { + msg->newMessage("PickGodDelete"); + msg->nextBlock("AgentData"); + msg->addUUID("AgentID", gAgentID); + msg->addUUID("SessionID", gAgentSessionID); + msg->nextBlock("Data"); + msg->addUUID("PickID", panel_pick->getPickID()); + // *HACK: We need to send the pick's creator id to accomplish + // the delete, and we don't use the query id for anything. JC + msg->addUUID( "QueryID", panel_pick->getPickCreatorID() ); + gAgent.sendReliableMessage(); } - return false; + else + { + LLAvatarPropertiesProcessor::getInstance()->sendPickDelete(panel_pick->getPickID()); + } + + tabs->removeTabPanel(panel_pick); + delete panel_pick; + panel_pick = NULL; + childSetEnabled("New...", !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)); + childSetEnabled("Delete...", tabs->getTabCount()); + childSetEnabled("Import...", true); + return true; } @@ -1400,20 +1156,31 @@ LLPanelAvatar::LLPanelAvatar( selectTab(0); } -BOOL LLPanelAvatar::postBuild(void) +BOOL LLPanelAvatar::postBuild() { mTab = getChild("tab"); - getChild("Kick")->setCommitCallback(boost::bind(LLAvatarActions::kick, boost::bind(&LLPanelAvatar::getAvatarID, this))); - getChild("Freeze")->setCommitCallback(boost::bind(LLAvatarActions::freeze, boost::bind(&LLPanelAvatar::getAvatarID, this))); - getChild("Unfreeze")->setCommitCallback(boost::bind(LLAvatarActions::unfreeze, boost::bind(&LLPanelAvatar::getAvatarID, this))); - getChild("csr_btn")->setCommitCallback(boost::bind(LLAvatarActions::csr, boost::bind(&LLPanelAvatar::getAvatarID, this))); - childSetAction("OK", onClickOK, this); - childSetAction("Cancel", onClickCancel, this); - - childSetAction("copy_key",onClickGetKey,this); + LLUICtrl* ctrl = getChild("Kick"); + ctrl->setCommitCallback(boost::bind(LLAvatarActions::kick, boost::bind(&LLPanelAvatar::getAvatarID, this))); + ctrl->setVisible(false); + ctrl->setEnabled(false); + ctrl = getChild("Freeze"); + ctrl->setCommitCallback(boost::bind(LLAvatarActions::freeze, boost::bind(&LLPanelAvatar::getAvatarID, this))); + ctrl->setVisible(false); + ctrl->setEnabled(false); + ctrl = getChild("Unfreeze"); + ctrl->setCommitCallback(boost::bind(LLAvatarActions::unfreeze, boost::bind(&LLPanelAvatar::getAvatarID, this))); + ctrl->setVisible(false); + ctrl->setEnabled(false); + ctrl = getChild("csr_btn"); + ctrl->setCommitCallback(boost::bind(LLAvatarActions::csr, boost::bind(&LLPanelAvatar::getAvatarID, this))); + ctrl->setVisible(false); + ctrl->setEnabled(false); + getChild("OK")->setCommitCallback(boost::bind(&LLPanelAvatar::onClickOK, this)); + getChild("Cancel")->setCommitCallback(boost::bind(&LLPanelAvatar::onClickCancel, this)); + getChild("copy_flyout")->setCommitCallback(boost::bind(&LLPanelAvatar::onClickCopy, this, _2)); getChildView("web_profile")->setVisible(!gSavedSettings.getString("WebProfileURL").empty()); - if(mTab && !sAllowFirstLife) + if (mTab && !sAllowFirstLife) { LLPanel* panel = mTab->getPanelByName("1st Life"); if (panel) mTab->removeTabPanel(panel); @@ -1421,19 +1188,11 @@ BOOL LLPanelAvatar::postBuild(void) panel = mTab->getPanelByName("WebProfile"); if (panel) mTab->removeTabPanel(panel); } - childSetVisible("Kick",FALSE); - childSetEnabled("Kick",FALSE); - childSetVisible("Freeze",FALSE); - childSetEnabled("Freeze",FALSE); - childSetVisible("Unfreeze",FALSE); - childSetEnabled("Unfreeze",FALSE); - childSetVisible("csr_btn", FALSE); - childSetEnabled("csr_btn", FALSE); //This text never changes. We simply toggle visibility. - childSetVisible("online_yes", FALSE); - childSetColor("online_yes",LLColor4::green); - childSetValue("online_yes","Currently Online"); + ctrl = getChild("online_yes"); + ctrl->setVisible(false); + ctrl->setColor(LLColor4::green); return TRUE; } @@ -1441,8 +1200,9 @@ BOOL LLPanelAvatar::postBuild(void) LLPanelAvatar::~LLPanelAvatar() { - LLAvatarPropertiesProcessor::getInstance()->removeObserver(mAvatarID,this); + LLAvatarPropertiesProcessor::getInstance()->removeObserver(mAvatarID, this); sAllPanels.remove(this); + mCacheConnection.disconnect(); } @@ -1457,81 +1217,46 @@ void LLPanelAvatar::setOnlineStatus(EOnlineStatus online_status) // If they are a friend, we may know the truth! if ((ONLINE_STATUS_YES != online_status) && mIsFriend - && (LLAvatarTracker::instance().isBuddyOnline( mAvatarID ))) + && LLAvatarTracker::instance().isBuddyOnline(mAvatarID)) { online_status = ONLINE_STATUS_YES; } - + if(mPanelSecondLife) - mPanelSecondLife->childSetVisible("online_yes", online_status == ONLINE_STATUS_YES); + mPanelSecondLife->childSetVisible("online_yes", online_status == ONLINE_STATUS_YES); + LLView* offer_tp(getChildView("Offer Teleport...")); + LLView* map_stalk(getChildView("Find on Map")); // Since setOnlineStatus gets called after setAvatarID // need to make sure that "Offer Teleport" doesn't get set // to TRUE again for yourself - if (mAvatarID != gAgent.getID()) - { - childSetVisible("Offer Teleport...",TRUE); - childSetVisible("Find on Map", true); - } - - BOOL in_prelude = gAgent.inPrelude(); - if(gAgent.isGodlike()) - { - childSetEnabled("Offer Teleport...", TRUE); - childSetToolTip("Offer Teleport...", getString("TeleportGod")); - } - else if (in_prelude) + if (mAvatarID != gAgentID) { - childSetEnabled("Offer Teleport...",FALSE); - childSetToolTip("Offer Teleport...", getString("TeleportPrelude")); - } - else - { - childSetEnabled("Offer Teleport...", TRUE /*(online_status == ONLINE_STATUS_YES)*/); - childSetToolTip("Offer Teleport...", getString("TeleportNormal")); - } + offer_tp->setVisible(true); + map_stalk->setVisible(true); - // Note: we don't always know online status, so always allow gods to try to track - childSetEnabled("Find on Map", gAgent.isGodlike() || is_agent_mappable(mAvatarID)); - if (!mIsFriend) - { - childSetToolTip("Find on Map", getString("ShowOnMapNonFriend")); - } - else if (ONLINE_STATUS_YES != online_status) - { - childSetToolTip("Find on Map", getString("ShowOnMapFriendOffline")); - } - else - { - childSetToolTip("Find on Map", getString("ShowOnMapFriendOnline")); + bool prelude(gAgent.inPrelude()); + bool godlike(gAgent.isGodlike()); + offer_tp->setEnabled(!prelude /*(&& online_status == ONLINE_STATUS_YES)*/); + offer_tp->setToolTip(godlike ? getString("TeleportGod") : prelude ? getString("TeleportPrelude") : getString("TeleportNormal")); + // Note: we don't always know online status, so always allow gods to try to track + map_stalk->setEnabled(godlike || is_agent_mappable(mAvatarID)); + map_stalk->setToolTip(!mIsFriend ? getString("ShowOnMapNonFriend") : (ONLINE_STATUS_YES != online_status) ? getString("ShowOnMapFriendOffline") : getString("ShowOnMapFriendOnline")); } } -void LLPanelAvatar::onAvatarNameResponse(const LLUUID& agent_id, const LLAvatarName& av_name) -{ - std::string name; - if (gSavedSettings.getBOOL("SinguCompleteNameProfiles")) - name = av_name.getCompleteName(); - else - LLAvatarNameCache::getPNSName(av_name, name); - getChild("dnname")->setText(name); -} - void LLPanelAvatar::setAvatarID(const LLUUID &avatar_id) { - if (avatar_id.isNull()) return; - - //BOOL avatar_changed = FALSE; if (avatar_id != mAvatarID) { - //avatar_changed = TRUE; - if(mAvatarID.notNull()) - { + if (mAvatarID.notNull()) LLAvatarPropertiesProcessor::getInstance()->removeObserver(mAvatarID, this); - } mAvatarID = avatar_id; + getChild("dnname")->setNameID(avatar_id, LFIDBearer::AVATAR); } + if (avatar_id.isNull()) return; + LLAvatarPropertiesProcessor::getInstance()->addObserver(mAvatarID, this); // Determine if we have their calling card. @@ -1540,7 +1265,7 @@ void LLPanelAvatar::setAvatarID(const LLUUID &avatar_id) // setOnlineStatus uses mIsFriend setOnlineStatus(ONLINE_STATUS_NO); - BOOL own_avatar = (mAvatarID == gAgent.getID() ); + bool own_avatar(mAvatarID == gAgentID); for(std::list::iterator it=mAvatarPanelList.begin();it!=mAvatarPanelList.end();++it) { @@ -1556,113 +1281,84 @@ void LLPanelAvatar::setAvatarID(const LLUUID &avatar_id) if (LLDropTarget* drop_target = findChild("drop_target_rect")) drop_target->setEntityID(mAvatarID); - LLAvatarNameCache::get(avatar_id, boost::bind(&LLPanelAvatar::onAvatarNameResponse, this, _1, _2)); - - LLNameEditor* key_edit = getChild("avatar_key"); - if(key_edit) - { - key_edit->setText(mAvatarID.asString()); - } -// if (avatar_changed) - { - // While we're waiting for data off the network, clear out the - // old data. - if(mPanelSecondLife) mPanelSecondLife->clearControls(); - - if(mPanelPicks) mPanelPicks->deletePickPanels(); - if(mPanelPicks) mPanelPicks->setDataRequested(false); - - if(mPanelClassified) mPanelClassified->deleteClassifiedPanels(); - if(mPanelClassified) mPanelClassified->setDataRequested(false); + if (auto key_edit = getChildView("avatar_key")) + key_edit->setValue(mAvatarID.asString()); - if(mPanelNotes) mPanelNotes->clearControls(); - if(mPanelNotes) mPanelNotes->setDataRequested(false); - mHaveNotes = false; - mLastNotes.clear(); - - // Request just the first two pages of data. The picks, - // classifieds, and notes will be requested when that panel - // is made visible. JC - sendAvatarPropertiesRequest(); + // While we're waiting for data off the network, clear out the old data. + if (mPanelSecondLife) + mPanelSecondLife->clearControls(); + if (mPanelPicks) + mPanelPicks->deletePickPanels(); + if (mPanelPicks) + mPanelPicks->setDataRequested(false); + if (mPanelClassified) + mPanelClassified->deleteClassifiedPanels(); + if (mPanelClassified) + mPanelClassified->setDataRequested(false); + if (mPanelNotes) + mPanelNotes->clearControls(); + if (mPanelNotes) + mPanelNotes->setDataRequested(false); + mHaveNotes = false; + mLastNotes.clear(); + + // Request just the first two pages of data. The picks, + // classifieds, and notes will be requested when that panel + // is made visible. JC + sendAvatarPropertiesRequest(); + + LLView* view(getChildView("OK")); + view->setVisible(own_avatar && mAllowEdit); + view->setEnabled(false); // OK button disabled until properties data arrives + view = getChildView("Cancel"); + view->setVisible(own_avatar && mAllowEdit); + view->setEnabled(own_avatar && mAllowEdit); + view = getChildView("Instant Message..."); + view->setVisible(!own_avatar); + view->setEnabled(false); + view = getChildView("GroupInvite_Button"); + view->setVisible(!own_avatar); + view->setEnabled(false); + view = getChildView("Mute"); + view->setVisible(!own_avatar); + view->setEnabled(false); + if (own_avatar) + { + view = getChildView("Offer Teleport..."); + view->setVisible(false); + view->setEnabled(false); + view = getChildView("Find on Map"); + view->setVisible(false); + view->setEnabled(false); + } + view = getChildView("Add Friend..."); + view->setVisible(!own_avatar); + view->setEnabled(!own_avatar && !mIsFriend); + view = getChildView("Pay..."); + view->setVisible(!own_avatar); + view->setEnabled(false); + getChildView("Log")->setVisible(!own_avatar); - if (own_avatar) - { - if (mAllowEdit) - { - // OK button disabled until properties data arrives - childSetVisible("OK", true); - childSetEnabled("OK", false); - childSetVisible("Cancel",TRUE); - childSetEnabled("Cancel",TRUE); - } - else - { - childSetVisible("OK",FALSE); - childSetEnabled("OK",FALSE); - childSetVisible("Cancel",FALSE); - childSetEnabled("Cancel",FALSE); - } - childSetVisible("Instant Message...",FALSE); - childSetEnabled("Instant Message...",FALSE); - childSetVisible("GroupInvite_Button",FALSE); - childSetEnabled("GroupInvite_Button",FALSE); - childSetVisible("Mute",FALSE); - childSetEnabled("Mute",FALSE); - childSetVisible("Offer Teleport...",FALSE); - childSetEnabled("Offer Teleport...",FALSE); - childSetVisible("Find on Map",FALSE); - childSetEnabled("Find on Map",FALSE); - childSetVisible("Add Friend...",FALSE); - childSetEnabled("Add Friend...",FALSE); - childSetVisible("Pay...",FALSE); - childSetEnabled("Pay...",FALSE); - } - else - { - childSetVisible("OK",FALSE); - childSetEnabled("OK",FALSE); - - childSetVisible("Cancel",FALSE); - childSetEnabled("Cancel",FALSE); - - childSetVisible("Instant Message...",TRUE); - childSetEnabled("Instant Message...",FALSE); - childSetVisible("GroupInvite_Button",TRUE); - childSetEnabled("GroupInvite_Button",FALSE); - childSetVisible("Mute",TRUE); - childSetEnabled("Mute",FALSE); - - childSetVisible("Add Friend...", true); - childSetEnabled("Add Friend...", !mIsFriend); - childSetVisible("Pay...",TRUE); - childSetEnabled("Pay...",FALSE); - } - LLNameEditor* avatar_key = getChild("avatar_key"); - if (avatar_key) - { - avatar_key->setText(avatar_id.asString()); - } - } - bool is_god = gAgent.isGodlike(); - childSetVisible("Kick", is_god); - childSetEnabled("Kick", is_god); - childSetVisible("Freeze", is_god); - childSetEnabled("Freeze", is_god); - childSetVisible("Unfreeze", is_god); - childSetEnabled("Unfreeze", is_god); - childSetVisible("csr_btn", is_god); - childSetEnabled("csr_btn", is_god); + view = getChildView("Kick"); + view->setVisible(is_god); + view->setEnabled(is_god); + view = getChildView("Freeze"); + view->setVisible(is_god); + view->setEnabled(is_god); + view = getChildView("Unfreeze"); + view->setVisible(is_god); + view->setEnabled(is_god); + view = getChildView("csr_btn"); + view->setVisible(is_god); + view->setEnabled(is_god); } void LLPanelAvatar::resetGroupList() { // only get these updates asynchronously via the group floater, which works on the agent only - if (mAvatarID != gAgent.getID()) - { - return; - } + if (mAvatarID != gAgentID) return; if (mPanelSecondLife) { @@ -1675,42 +1371,27 @@ void LLPanelAvatar::resetGroupList() group_list->deleteAllItems(); - S32 count = gAgent.mGroups.count(); - LLUUID id; - + S32 count = gAgent.mGroups.size(); for(S32 i = 0; i < count; ++i) { - LLGroupData group_data = gAgent.mGroups.get(i); - id = group_data.mID; - std::string group_string; - /* Show group title? DUMMY_POWER for Don Grep - if(group_data.mOfficer) - { - group_string = "Officer of "; - } - else - { - group_string = "Member of "; - } - */ - - group_string += group_data.mName; + LLGroupData group_data = gAgent.mGroups[i]; - LLSD row; - row["id"] = id ; - row["columns"][0]["value"] = group_string; - row["columns"][0]["font"] = "SANSSERIF_SMALL"; + const LLUUID& id(group_data.mID); + LLScrollListItem::Params row; + row.value(id); std::string font_style = group_data.mListInProfile ? "BOLD" : "NORMAL"; - if(group_data.mID == gAgent.getGroupID()) + if (id == gAgent.getGroupID()) font_style.append("|ITALIC"); - row["columns"][0]["font-style"] = font_style; - row["columns"][0]["width"] = 0; - group_list->addElement(row,ADD_SORTED); + /* Show group title? DUMMY_POWER for Don Grep + (group_data.mOfficer ? "Officer of " : "Member of ") + group_data.mName; + */ + row.columns.add(LLScrollListCell::Params().value(group_data.mName).font("SANSSERIF_SMALL").font_style(font_style).width(0)); + group_list->addRow(row, ADD_SORTED); } - if(selected_id.notNull()) + if (selected_id.notNull()) group_list->selectByValue(selected_id); - if(selected_idx!=group_list->getFirstSelectedIndex()) //if index changed then our stored pos is pointless. + if (selected_idx != group_list->getFirstSelectedIndex()) //if index changed then our stored pos is pointless. group_list->scrollToShowSelected(); else group_list->setScrollPos(scroll_pos); @@ -1718,82 +1399,51 @@ void LLPanelAvatar::resetGroupList() } } -//static -void LLPanelAvatar::onClickGetKey(void *userdata) +void LLPanelAvatar::onClickCopy(const LLSD& val) { - LLPanelAvatar* self = (LLPanelAvatar*)userdata; - LLUUID agent_id = self->getAvatarID(); - - llinfos << "Copy agent id: " << agent_id << llendl; - - gViewerWindow->getWindow()->copyTextToClipboard(utf8str_to_wstring(agent_id.asString())); + if (val.isUndefined()) + { + LL_INFOS() << "Copy agent id: " << mAvatarID << LL_ENDL; + gViewerWindow->getWindow()->copyTextToClipboard(utf8str_to_wstring(mAvatarID.asString())); + } + else + { + void copy_profile_uri(const LLUUID& id, const LFIDBearer::Type& type = LFIDBearer::AVATAR); + copy_profile_uri(mAvatarID); + } } -// static -void LLPanelAvatar::onClickOK(void *userdata) +void LLPanelAvatar::onClickOK() { - LLPanelAvatar *self = (LLPanelAvatar *)userdata; - // JC: Only save the data if we actually got the original // properties. Otherwise we might save blanks into // the database. - if (self - && self->mHaveProperties) + if (mHaveProperties) { - self->sendAvatarPropertiesUpdate(); + sendAvatarPropertiesUpdate(); - LLTabContainer* tabs = self->getChild("tab"); - if ( tabs->getCurrentPanel() != self->mPanelClassified ) + if (mTab->getCurrentPanel() != mPanelClassified || mPanelClassified->titleIsValid()) { - self->mPanelClassified->apply(); + mPanelClassified->apply(); - LLFloaterAvatarInfo *infop = LLFloaterAvatarInfo::getInstance(self->mAvatarID); - if (infop) - { + if (LLFloaterAvatarInfo* infop = LLFloaterAvatarInfo::getInstance(mAvatarID)) infop->close(); - } - } - else - { - if ( self->mPanelClassified->titleIsValid() ) - { - self->mPanelClassified->apply(); - - LLFloaterAvatarInfo *infop = LLFloaterAvatarInfo::getInstance(self->mAvatarID); - if (infop) - { - infop->close(); - } - } } } } -// static -void LLPanelAvatar::onClickCancel(void *userdata) +void LLPanelAvatar::onClickCancel() { - LLPanelAvatar *self = (LLPanelAvatar *)userdata; - - if (self) - { - LLFloaterAvatarInfo *infop; - if ((infop = LLFloaterAvatarInfo::getInstance(self->mAvatarID))) - { - infop->close(); - } - else - { - // We're in the Search directory and are cancelling an edit - // to our own profile, so reset. - self->sendAvatarPropertiesRequest(); - } - } + if (LLFloaterAvatarInfo* infop = LLFloaterAvatarInfo::getInstance(mAvatarID)) + infop->close(); + else // We're in the Search directory and are cancelling an edit to our own profile, so reset. + sendAvatarPropertiesRequest(); } void LLPanelAvatar::sendAvatarPropertiesRequest() { - lldebugs << "LLPanelAvatar::sendAvatarPropertiesRequest()" << llendl; + LL_DEBUGS() << "LLPanelAvatar::sendAvatarPropertiesRequest()" << LL_ENDL; LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesRequest(mAvatarID); } @@ -1802,25 +1452,19 @@ void LLPanelAvatar::sendAvatarNotesUpdate() { std::string notes = mPanelNotes->childGetValue("notes edit").asString(); - if (!mHaveNotes - && (notes.empty() || notes == getString("Loading"))) - { - // no notes from server and no user updates - return; - } - if (notes == mLastNotes) - { - // Avatar notes unchanged + if (!mHaveNotes && (notes.empty() || notes == getString("Loading")) || // no notes from server and no user updates + notes == mLastNotes) // Avatar notes unchanged return; - } - LLAvatarPropertiesProcessor::getInstance()->sendNotes(mAvatarID,notes); + auto& inst(LLAvatarPropertiesProcessor::instance()); + inst.sendNotes(mAvatarID, notes); + inst.sendAvatarNotesRequest(mAvatarID); // Rerequest notes to update anyone that might be listening, also to be sure we match the server. } // virtual void LLPanelAvatar::processProperties(void* data, EAvatarProcessorType type) { - if(type == APT_PROPERTIES) + if (type == APT_PROPERTIES) { const LLAvatarData* pAvatarData = static_cast( data ); if (pAvatarData && (mAvatarID == pAvatarData->avatar_id) && (pAvatarData->avatar_id.notNull())) @@ -1841,25 +1485,22 @@ void LLPanelAvatar::processProperties(void* data, EAvatarProcessorType type) t.tm_hour = t.tm_min = t.tm_sec = 0; timeStructToFormattedString(&t, gSavedSettings.getString("ShortDateFormat"), born_on); }*/ - - - bool online = (pAvatarData->flags & AVATAR_ONLINE); - - EOnlineStatus online_status = (online) ? ONLINE_STATUS_YES : ONLINE_STATUS_NO; - - setOnlineStatus(online_status); - - childSetValue("about", pAvatarData->about_text); + setOnlineStatus(pAvatarData->flags & AVATAR_ONLINE ? ONLINE_STATUS_YES : ONLINE_STATUS_NO); + getChild("about")->setText(pAvatarData->about_text, false); } } - else if(type == APT_NOTES) + else if (type == APT_NOTES) { const LLAvatarNotes* pAvatarNotes = static_cast( data ); if (pAvatarNotes && (mAvatarID == pAvatarNotes->target_id) && (pAvatarNotes->target_id != LLUUID::null)) { - childSetValue("notes edit", pAvatarNotes->notes); - childSetEnabled("notes edit", true); - mHaveNotes = true; + if (!mHaveNotes) // Only update the UI if we don't already have the notes, we could be editing them now! + { + auto notes = getChildView("notes edit"); + notes->setEnabled(true); + notes->setValue(pAvatarNotes->notes); + mHaveNotes = true; + } mLastNotes = pAvatarNotes->notes; } } @@ -1869,49 +1510,19 @@ void LLPanelAvatar::processProperties(void* data, EAvatarProcessorType type) // Otherwise you will write blanks back into the database. void LLPanelAvatar::enableOKIfReady() { - if(mHaveProperties && childIsVisible("OK")) - { - childSetEnabled("OK", TRUE); - } - else - { - childSetEnabled("OK", FALSE); - } + LLView* OK(getChildView("OK")); + OK->setEnabled(mHaveProperties && OK->getVisible()); } void LLPanelAvatar::sendAvatarPropertiesUpdate() { - llinfos << "Sending avatarinfo update" << llendl; - BOOL allow_publish = FALSE; - BOOL mature = FALSE; - if (LLPanelAvatar::sAllowFirstLife) - { - allow_publish = childGetValue("allow_publish"); - //A profile should never be mature. - mature = FALSE; - } - - LLUUID first_life_image_id; - std::string first_life_about_text; - if (mPanelFirstLife) - { - first_life_about_text = mPanelFirstLife->childGetValue("about").asString(); - LLTextureCtrl* image_ctrl = mPanelFirstLife->getChild("img"); - if(image_ctrl) - { - first_life_image_id = image_ctrl->getImageAssetID(); - } - } - - std::string about_text = mPanelSecondLife->childGetValue("about").asString(); - + LL_INFOS() << "Sending avatarinfo update" << LL_ENDL; LLAvatarData avatar_data; avatar_data.image_id = mPanelSecondLife->getChild("img")->getImageAssetID(); - avatar_data.fl_image_id = first_life_image_id; - avatar_data.about_text = about_text; - avatar_data.fl_about_text = first_life_about_text; - avatar_data.allow_publish = allow_publish; - //avatar_data.mature = mature; + avatar_data.fl_image_id = mPanelFirstLife ? mPanelFirstLife->getChild("img")->getImageAssetID() : LLUUID::null; + avatar_data.about_text = mPanelSecondLife->childGetValue("about").asString(); + avatar_data.fl_about_text = mPanelFirstLife ? mPanelFirstLife->childGetValue("about").asString() : LLStringUtil::null; + avatar_data.allow_publish = sAllowFirstLife && childGetValue("allow_publish"); avatar_data.profile_url = mPanelWeb->childGetText("url_edit"); LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesUpdate(&avatar_data); @@ -1925,73 +1536,64 @@ void LLPanelAvatar::sendAvatarPropertiesUpdate() void LLPanelAvatar::selectTab(S32 tabnum) { - if(mTab) - { - mTab->selectTab(tabnum); - } + if (mTab) mTab->selectTab(tabnum); } void LLPanelAvatar::selectTabByName(std::string tab_name) { - if (mTab) - { - if (tab_name.empty()) - { - mTab->selectFirstTab(); - } - else - { - mTab->selectTabByName(tab_name); - } - } + if (!mTab) return; + if (tab_name.empty()) + mTab->selectFirstTab(); + else + mTab->selectTabByName(tab_name); } -void* LLPanelAvatar::createPanelAvatarSecondLife(void* data) +void* LLPanelAvatar::createPanelAvatarSecondLife(void* data) { LLPanelAvatar* self = (LLPanelAvatar*)data; - self->mPanelSecondLife = new LLPanelAvatarSecondLife(std::string("2nd Life"),LLRect(),self); + self->mPanelSecondLife = new LLPanelAvatarSecondLife("2nd Life", LLRect(), self); return self->mPanelSecondLife; } -void* LLPanelAvatar::createPanelAvatarWeb(void* data) +void* LLPanelAvatar::createPanelAvatarWeb(void* data) { LLPanelAvatar* self = (LLPanelAvatar*)data; - self->mPanelWeb = new LLPanelAvatarWeb(std::string("Web"),LLRect(),self); + self->mPanelWeb = new LLPanelAvatarWeb("Web",LLRect(),self); return self->mPanelWeb; } -void* LLPanelAvatar::createPanelAvatarInterests(void* data) +void* LLPanelAvatar::createPanelAvatarInterests(void* data) { LLPanelAvatar* self = (LLPanelAvatar*)data; - self->mPanelAdvanced = new LLPanelAvatarAdvanced(std::string("Interests"),LLRect(),self); + self->mPanelAdvanced = new LLPanelAvatarAdvanced("Interests", LLRect(), self); return self->mPanelAdvanced; } -void* LLPanelAvatar::createPanelAvatarPicks(void* data) +void* LLPanelAvatar::createPanelAvatarPicks(void* data) { LLPanelAvatar* self = (LLPanelAvatar*)data; - self->mPanelPicks = new LLPanelAvatarPicks(std::string("Picks"),LLRect(),self); + self->mPanelPicks = new LLPanelAvatarPicks("Picks", LLRect(), self); return self->mPanelPicks; } -void* LLPanelAvatar::createPanelAvatarClassified(void* data) +void* LLPanelAvatar::createPanelAvatarClassified(void* data) { LLPanelAvatar* self = (LLPanelAvatar*)data; - self->mPanelClassified = new LLPanelAvatarClassified(std::string("Classified"),LLRect(),self); + self->mPanelClassified = new LLPanelAvatarClassified("Classified", LLRect(), self); return self->mPanelClassified; } -void* LLPanelAvatar::createPanelAvatarFirstLife(void* data) +void* LLPanelAvatar::createPanelAvatarFirstLife(void* data) { LLPanelAvatar* self = (LLPanelAvatar*)data; - self->mPanelFirstLife = new LLPanelAvatarFirstLife(std::string("1st Life"), LLRect(), self); + self->mPanelFirstLife = new LLPanelAvatarFirstLife("1st Life", LLRect(), self); return self->mPanelFirstLife; } -void* LLPanelAvatar::createPanelAvatarNotes(void* data) +void* LLPanelAvatar::createPanelAvatarNotes(void* data) { LLPanelAvatar* self = (LLPanelAvatar*)data; - self->mPanelNotes = new LLPanelAvatarNotes(std::string("My Notes"),LLRect(),self); + self->mPanelNotes = new LLPanelAvatarNotes("My Notes", LLRect(),self); return self->mPanelNotes; } diff --git a/indra/newview/llpanelavatar.h b/indra/newview/llpanelavatar.h index a7c18e7967..6876b224c1 100644 --- a/indra/newview/llpanelavatar.h +++ b/indra/newview/llpanelavatar.h @@ -38,6 +38,7 @@ #include "lluuid.h" #include "llmediactrl.h" #include "llavatarpropertiesprocessor.h" +#include "llmutelist.h" class LLAvatarName; class LLCheckBoxCtrl; @@ -88,44 +89,37 @@ class LLPanelAvatarFirstLife : public LLPanelAvatarTab public: LLPanelAvatarFirstLife(const std::string& name, const LLRect &rect, LLPanelAvatar* panel_avatar); - /*virtual*/ BOOL postBuild(void); - + /*virtual*/ BOOL postBuild(); /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); - static void onClickImage( void *userdata); - - void enableControls(BOOL own_avatar); }; class LLPanelAvatarSecondLife : public LLPanelAvatarTab +, public LLMuteListObserver { public: LLPanelAvatarSecondLife(const std::string& name, const LLRect &rect, LLPanelAvatar* panel_avatar ); + ~LLPanelAvatarSecondLife(); - /*virtual*/ BOOL postBuild(void); + /*virtual*/ BOOL postBuild(); /*virtual*/ void refresh(); /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); + /*virtual*/ void onChange() {} + /*virtual*/ void onChangeDetailed(const LLMute& mute); - static void onClickImage( void *userdata); - static void onClickFriends( void *userdata); - static void onDoubleClickGroup(void* userdata); - static void onClickPublishHelp(void *userdata); - static void onClickPartnerHelp(void *userdata); + void onClickFriends(); + void onDoubleClickGroup(); static bool onClickPartnerHelpLoadURL(const LLSD& notification, const LLSD& response); - static void onClickPartnerInfo(void *userdata); // Clear out the controls anticipating new network data. void clearControls(); void enableControls(BOOL own_avatar); void updateOnlineText(BOOL online, BOOL have_calling_card); - void updatePartnerName(); - void setPartnerID(LLUUID id) { mPartnerID = id; } - private: LLUUID mPartnerID; }; @@ -139,7 +133,7 @@ class LLPanelAvatarWeb : public: LLPanelAvatarWeb(const std::string& name, const LLRect& rect, LLPanelAvatar* panel_avatar); /*virtual*/ ~LLPanelAvatarWeb(); - /*virtual*/ BOOL postBuild(void); + /*virtual*/ BOOL postBuild(); /*virtual*/ void refresh(); @@ -149,11 +143,8 @@ class LLPanelAvatarWeb : void setWebURL(std::string url); - void load(std::string url); - void onURLKeystroke(LLLineEditor* editor); + void load(const std::string& url); void onCommitLoad(const LLSD& value); - void onCommitURL(const LLSD& value); - static void onClickWebProfileHelp(void *); // inherited from LLViewerMediaObserver /*virtual*/ void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event); @@ -170,7 +161,7 @@ class LLPanelAvatarAdvanced : public LLPanelAvatarTab public: LLPanelAvatarAdvanced(const std::string& name, const LLRect& rect, LLPanelAvatar* panel_avatar); - /*virtual*/ BOOL postBuild(void); + /*virtual*/ BOOL postBuild(); /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); @@ -197,7 +188,7 @@ class LLPanelAvatarNotes : public LLPanelAvatarTab public: LLPanelAvatarNotes(const std::string& name, const LLRect& rect, LLPanelAvatar* panel_avatar); - /*virtual*/ BOOL postBuild(void); + /*virtual*/ BOOL postBuild(); /*virtual*/ void refresh(); @@ -212,7 +203,7 @@ class LLPanelAvatarClassified : public LLPanelAvatarTab public: LLPanelAvatarClassified(const std::string& name, const LLRect& rect, LLPanelAvatar* panel_avatar); - /*virtual*/ BOOL postBuild(void); + /*virtual*/ BOOL postBuild(); /*virtual*/ void refresh(); @@ -230,11 +221,13 @@ class LLPanelAvatarClassified : public LLPanelAvatarTab void deleteClassifiedPanels(); private: - static void onClickNew(void* data); - static void onClickDelete(void* data); + void onClickNew(); + void onClickDelete(); bool callbackDelete(const LLSD& notification, const LLSD& response); bool callbackNew(const LLSD& notification, const LLSD& response); + + bool mInDirectory; }; @@ -253,13 +246,13 @@ class LLPanelAvatarPicks : public LLPanelAvatarTab void deletePickPanels(); private: - static void onClickNew(void* data); - static void onClickDelete(void* data); + void onClickNew(); + void onClickDelete(); //Pick import and export - RK - static void onClickImport(void* data); - static void onClickImport_continued(void* self, bool import); - static void onClickExport(void* data); + void onClickImport(); + static void onClickImport_continued(void* self, bool importt); + void onClickExport(); bool callbackDelete(const LLSD& notification, const LLSD& response); @@ -285,8 +278,6 @@ class LLPanelAvatar : public LLPanel, public LLAvatarPropertiesObserver void setAvatar(LLViewerObject *avatarp); - void onAvatarNameResponse(const LLUUID& agent_id, const LLAvatarName& av_name); - // Fill in the avatar ID and handle some field fill-in, as well as // button enablement. void setAvatarID(const LLUUID &avatar_id); @@ -310,12 +301,12 @@ class LLPanelAvatar : public LLPanel, public LLAvatarPropertiesObserver void selectTab(S32 tabnum); void selectTabByName(std::string tab_name); - BOOL haveData() { return mHaveProperties && mHaveStatistics; } - BOOL isEditable() const { return mAllowEdit; } + bool haveData() const { return mHaveProperties && mHaveStatistics; } + bool isEditable() const { return mAllowEdit; } - static void onClickGetKey(void *userdata); - static void onClickOK( void *userdata); - static void onClickCancel( void *userdata); + void onClickCopy(const LLSD& val); + void onClickOK(); + void onClickCancel(); private: void enableOKIfReady(); @@ -347,15 +338,16 @@ class LLPanelAvatar : public LLPanel, public LLAvatarPropertiesObserver private: LLUUID mAvatarID; // for which avatar is this window? - BOOL mIsFriend; // Are we friends? - BOOL mHaveProperties; - BOOL mHaveStatistics; + bool mIsFriend; // Are we friends? + bool mHaveProperties; + bool mHaveStatistics; // only update note if data received from database and // note is changed from database version bool mHaveNotes; std::string mLastNotes; LLTabContainer* mTab; - BOOL mAllowEdit; + bool mAllowEdit; + boost::signals2::connection mCacheConnection; typedef std::list panel_list_t; static panel_list_t sAllPanels; diff --git a/indra/newview/llpanelclassified.cpp b/indra/newview/llpanelclassified.cpp index de5f765ccf..786088cc01 100644 --- a/indra/newview/llpanelclassified.cpp +++ b/indra/newview/llpanelclassified.cpp @@ -75,14 +75,13 @@ #include "rlvhandler.h" // [/RLVa:KB] -const S32 MINIMUM_PRICE_FOR_LISTING = 50; // L$ const S32 MATURE_UNDEFINED = -1; const S32 MATURE_CONTENT = 1; const S32 PG_CONTENT = 2; const S32 DECLINE_TO_STATE = 0; //static -std::list LLPanelClassified::sAllPanels; +LLPanelClassifiedInfo::panel_list_t LLPanelClassifiedInfo::sAllPanels; // "classifiedclickthrough" // strings[0] = classified_id @@ -103,10 +102,10 @@ class LLDispatchClassifiedClickThrough : public LLDispatchHandler S32 teleport_clicks = atoi(strings[1].c_str()); S32 map_clicks = atoi(strings[2].c_str()); S32 profile_clicks = atoi(strings[3].c_str()); - LLPanelClassified::setClickThrough(classified_id, teleport_clicks, - map_clicks, - profile_clicks, - false); + + LLPanelClassifiedInfo::setClickThrough( + classified_id, teleport_clicks, map_clicks, profile_clicks, false); + return true; } }; @@ -139,11 +138,11 @@ class LLClassifiedTeleportHandler : public LLCommandHandler url += tokens[i].asString(); url += "/"; } - llinfos << "classified teleport to " << url << llendl; + LL_INFOS() << "classified teleport to " << url << LL_ENDL; // *TODO: separately track old search, sidebar, and new search // Right now detail HTML pages count as new search. const bool from_search = true; - LLPanelClassified::sendClassifiedClickMessage(classified_id, "teleport", from_search); + LLPanelClassifiedInfo::sendClassifiedClickMessage(classified_id, "teleport", from_search); // Invoke teleport LLMediaCtrl* web = NULL; const bool trusted_browser = true; @@ -154,7 +153,11 @@ class LLClassifiedTeleportHandler : public LLCommandHandler LLClassifiedTeleportHandler gClassifiedTeleportHandler; */ -LLPanelClassified::LLPanelClassified(bool in_finder, bool from_search) +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +LLPanelClassifiedInfo::LLPanelClassifiedInfo(bool in_finder, bool from_search) : LLPanel(std::string("Classified Panel")), mInFinder(in_finder), mFromSearch(from_search), @@ -202,24 +205,19 @@ LLPanelClassified::LLPanelClassified(bool in_finder, bool from_search) } // Register dispatcher - gGenericDispatcher.addHandler("classifiedclickthrough", - &sClassifiedClickThrough); + gGenericDispatcher.addHandler("classifiedclickthrough", &sClassifiedClickThrough); } - -LLPanelClassified::~LLPanelClassified() +LLPanelClassifiedInfo::~LLPanelClassifiedInfo() { - if(mCreatorID.notNull()) - { - LLAvatarPropertiesProcessor::getInstance()->removeObserver(mCreatorID, this); - } - sAllPanels.remove(this); + LLAvatarPropertiesProcessor::getInstance()->removeObserver(mCreatorID, this); + sAllPanels.remove(this); } -void LLPanelClassified::reset() +void LLPanelClassifiedInfo::reset() { - if(mCreatorID.notNull()) + if (mInFinder || mCreatorID.notNull()) { LLAvatarPropertiesProcessor::getInstance()->removeObserver(mCreatorID, this); } @@ -240,41 +238,40 @@ void LLPanelClassified::reset() resetDirty(); } - -BOOL LLPanelClassified::postBuild() +BOOL LLPanelClassifiedInfo::postBuild() { - mSnapshotCtrl = getChild("snapshot_ctrl"); - mSnapshotCtrl->setCommitCallback(boost::bind(&LLPanelClassified::checkDirty, this)); + mSnapshotCtrl = getChild("snapshot_ctrl"); + mSnapshotCtrl->setCommitCallback(boost::bind(&LLPanelClassifiedInfo::checkDirty, this)); mSnapshotSize = mSnapshotCtrl->getRect(); - mNameEditor = getChild("given_name_editor"); + mNameEditor = getChild("given_name_editor"); mNameEditor->setMaxTextLength(DB_PARCEL_NAME_LEN); mNameEditor->setCommitOnFocusLost(TRUE); - mNameEditor->setFocusReceivedCallback(boost::bind(&LLPanelClassified::checkDirty, this)); - mNameEditor->setCommitCallback(boost::bind(&LLPanelClassified::checkDirty, this)); + mNameEditor->setFocusReceivedCallback(boost::bind(&LLPanelClassifiedInfo::checkDirty, this)); + mNameEditor->setCommitCallback(boost::bind(&LLPanelClassifiedInfo::checkDirty, this)); mNameEditor->setPrevalidate( LLLineEditor::prevalidateASCII ); - mDescEditor = getChild("desc_editor"); + mDescEditor = getChild("desc_editor"); mDescEditor->setCommitOnFocusLost(TRUE); - mDescEditor->setFocusReceivedCallback(boost::bind(&LLPanelClassified::checkDirty, this)); - mDescEditor->setCommitCallback(boost::bind(&LLPanelClassified::checkDirty, this)); + mDescEditor->setFocusReceivedCallback(boost::bind(&LLPanelClassifiedInfo::checkDirty, this)); + mDescEditor->setCommitCallback(boost::bind(&LLPanelClassifiedInfo::checkDirty, this)); mDescEditor->setTabsToNextField(TRUE); - mLocationEditor = getChild("location_editor"); + mLocationEditor = getChild("location_editor"); - mSetBtn = getChild( "set_location_btn"); - mSetBtn->setCommitCallback(boost::bind(&LLPanelClassified::onClickSet, this)); + mSetBtn = getChild( "set_location_btn"); + mSetBtn->setCommitCallback(boost::bind(&LLPanelClassifiedInfo::onClickSet, this)); - mTeleportBtn = getChild( "classified_teleport_btn"); - mTeleportBtn->setCommitCallback(boost::bind(&LLPanelClassified::onClickTeleport, this)); + mTeleportBtn = getChild( "classified_teleport_btn"); + mTeleportBtn->setCommitCallback(boost::bind(&LLPanelClassifiedInfo::onClickTeleport, this)); - mMapBtn = getChild( "classified_map_btn"); - mMapBtn->setCommitCallback(boost::bind(&LLPanelClassified::onClickMap, this)); + mMapBtn = getChild( "classified_map_btn"); + mMapBtn->setCommitCallback(boost::bind(&LLPanelClassifiedInfo::onClickMap, this)); if(mInFinder) { mProfileBtn = getChild( "classified_profile_btn"); - mProfileBtn->setCommitCallback(boost::bind(&LLPanelClassified::onClickProfile, this)); + mProfileBtn->setCommitCallback(boost::bind(&LLPanelClassifiedInfo::onClickProfile, this)); } mCategoryCombo = getChild( "classified_category_combo"); @@ -286,11 +283,11 @@ BOOL LLPanelClassified::postBuild() mCategoryCombo->add(iter->second, (void *)((intptr_t)iter->first), ADD_BOTTOM); } mCategoryCombo->setCurrentByIndex(0); - mCategoryCombo->setCommitCallback(boost::bind(&LLPanelClassified::checkDirty, this)); + mCategoryCombo->setCommitCallback(boost::bind(&LLPanelClassifiedInfo::checkDirty, this)); mMatureCombo = getChild( "classified_mature_check"); mMatureCombo->setCurrentByIndex(0); - mMatureCombo->setCommitCallback(boost::bind(&LLPanelClassified::checkDirty, this)); + mMatureCombo->setCommitCallback(boost::bind(&LLPanelClassifiedInfo::checkDirty, this)); if (gAgent.wantsPGOnly()) { // Teens don't get to set mature flag. JC @@ -301,11 +298,11 @@ BOOL LLPanelClassified::postBuild() if (!mInFinder) { mAutoRenewCheck = getChild( "auto_renew_check"); - mAutoRenewCheck->setCommitCallback(boost::bind(&LLPanelClassified::checkDirty, this)); + mAutoRenewCheck->setCommitCallback(boost::bind(&LLPanelClassifiedInfo::checkDirty, this)); } mUpdateBtn = getChild("classified_update_btn"); - mUpdateBtn->setCommitCallback(boost::bind(&LLPanelClassified::onClickUpdate, this)); + mUpdateBtn->setCommitCallback(boost::bind(&LLPanelClassifiedInfo::onClickUpdate, this)); if (!mInFinder) { @@ -313,30 +310,30 @@ BOOL LLPanelClassified::postBuild() } resetDirty(); - return TRUE; + return TRUE; } -void LLPanelClassified::processProperties(void* data, EAvatarProcessorType type) +void LLPanelClassifiedInfo::processProperties(void* data, EAvatarProcessorType type) { if(APT_CLASSIFIED_INFO == type) { - lldebugs << "processClassifiedInfoReply()" << llendl; - + LL_DEBUGS() << "processClassifiedInfoReply()" << LL_ENDL; + LLAvatarClassifiedInfo* c_info = static_cast(data); if(c_info && mClassifiedID == c_info->classified_id) { - LLAvatarPropertiesProcessor::getInstance()->removeObserver(LLUUID::null, this); + LLAvatarPropertiesProcessor::getInstance()->removeObserver(mCreatorID, this); - // "Location text" is actually the original - // name that owner gave the parcel, and the location. + // "Location text" is actually the original + // name that owner gave the parcel, and the location. std::string location_text = c_info->parcel_name; if (!location_text.empty()) location_text.append(", "); - S32 region_x = llround((F32)c_info->pos_global.mdV[VX]) % REGION_WIDTH_UNITS; - S32 region_y = llround((F32)c_info->pos_global.mdV[VY]) % REGION_WIDTH_UNITS; - S32 region_z = llround((F32)c_info->pos_global.mdV[VZ]); + S32 region_x = ll_round((F32)c_info->pos_global.mdV[VX]) % REGION_WIDTH_UNITS; + S32 region_y = ll_round((F32)c_info->pos_global.mdV[VY]) % REGION_WIDTH_UNITS; + S32 region_z = ll_round((F32)c_info->pos_global.mdV[VZ]); std::string buffer = llformat("%s (%d, %d, %d)", c_info->sim_name.c_str(), region_x, region_y, region_z); location_text.append(buffer); @@ -347,7 +344,7 @@ void LLPanelClassified::processProperties(void* data, EAvatarProcessorType type) tm *now=localtime(&tim); - // Found the panel, now fill in the information + // Found the panel, now fill in the information mClassifiedID = c_info->classified_id; mCreatorID = c_info->creator_id; mParcelID = c_info->parcel_id; @@ -356,10 +353,10 @@ void LLPanelClassified::processProperties(void* data, EAvatarProcessorType type) mPosGlobal = c_info->pos_global; // Update UI controls - mNameEditor->setText(c_info->name); - mDescEditor->setText(c_info->description); - mSnapshotCtrl->setImageAssetID(c_info->snapshot_id); - mLocationEditor->setText(location_text); + mNameEditor->setText(c_info->name); + mDescEditor->setText(c_info->description, false); + mSnapshotCtrl->setImageAssetID(c_info->snapshot_id); + mLocationEditor->setText(location_text); mLocationChanged = false; mCategoryCombo->setCurrentByIndex(c_info->category - 1); @@ -386,10 +383,10 @@ void LLPanelClassified::processProperties(void* data, EAvatarProcessorType type) resetDirty(); } - } + } } -BOOL LLPanelClassified::titleIsValid() +BOOL LLPanelClassifiedInfo::titleIsValid() { // Disallow leading spaces, punctuation, etc. that screw up // sort order. @@ -408,7 +405,7 @@ BOOL LLPanelClassified::titleIsValid() return TRUE; } -void LLPanelClassified::apply() +void LLPanelClassifiedInfo::apply() { // Apply is used for automatically saving results, so only // do that if there is a difference, and this is a save not create. @@ -418,7 +415,7 @@ void LLPanelClassified::apply() } } -bool LLPanelClassified::saveCallback(const LLSD& notification, const LLSD& response) +bool LLPanelClassifiedInfo::saveCallback(const LLSD& notification, const LLSD& response) { S32 option = LLNotification::getSelectedOption(notification, response); @@ -442,26 +439,26 @@ bool LLPanelClassified::saveCallback(const LLSD& notification, const LLSD& respo case 2: // Cancel default: - LLAppViewer::instance()->abortQuit(); + LLAppViewer::instance()->abortQuit(); break; } return false; } -BOOL LLPanelClassified::canClose() +BOOL LLPanelClassifiedInfo::canClose() { if (mForceClose || !checkDirty()) return TRUE; LLSD args; args["NAME"] = mNameEditor->getText(); - LLNotificationsUtil::add("ClassifiedSave", args, LLSD(), boost::bind(&LLPanelClassified::saveCallback, this, _1, _2)); + LLNotificationsUtil::add("ClassifiedSave", args, LLSD(), boost::bind(&LLPanelClassifiedInfo::saveCallback, this, _1, _2)); return FALSE; } // Fill in some reasonable defaults for a new classified. -void LLPanelClassified::initNewClassified() +void LLPanelClassifiedInfo::initNewClassified() { // TODO: Don't generate this on the client. mClassifiedID.generate(); @@ -490,13 +487,15 @@ void LLPanelClassified::initNewClassified() } -void LLPanelClassified::setClassifiedID(const LLUUID& id) +void LLPanelClassifiedInfo::setClassifiedID(const LLUUID& id) { mClassifiedID = id; + if (mInFinder) mCreatorID = LLUUID::null; // Singu Note: HACKS! } //static -void LLPanelClassified::setClickThrough(const LLUUID& classified_id, +void LLPanelClassifiedInfo::setClickThrough( + const LLUUID& classified_id, S32 teleport, S32 map, S32 profile, @@ -504,7 +503,7 @@ void LLPanelClassified::setClickThrough(const LLUUID& classified_id, { for (panel_list_t::iterator iter = sAllPanels.begin(); iter != sAllPanels.end(); ++iter) { - LLPanelClassified* self = *iter; + LLPanelClassifiedInfo* self = *iter; // For top picks, must match pick id if (self->mClassifiedID != classified_id) { @@ -541,23 +540,23 @@ void LLPanelClassified::setClickThrough(const LLUUID& classified_id, // Schedules the panel to request data // from the server next time it is drawn. -void LLPanelClassified::markForServerRequest() +void LLPanelClassifiedInfo::markForServerRequest() { mDataRequested = FALSE; } -std::string LLPanelClassified::getClassifiedName() +std::string LLPanelClassifiedInfo::getClassifiedName() { return mNameEditor->getText(); } -void LLPanelClassified::sendClassifiedInfoRequest() +void LLPanelClassifiedInfo::sendClassifiedInfoRequest() { if (mClassifiedID != mRequestedID) { - LLAvatarPropertiesProcessor::getInstance()->addObserver(LLUUID::null, this); + LLAvatarPropertiesProcessor::getInstance()->addObserver(mCreatorID, this); LLAvatarPropertiesProcessor::getInstance()->sendClassifiedInfoRequest(mClassifiedID); mDataRequested = TRUE; @@ -572,13 +571,13 @@ void LLPanelClassified::sendClassifiedInfoRequest() if (!url.empty()) { - llinfos << "Classified stat request via capability" << llendl; + LL_INFOS() << "Classified stat request via capability" << LL_ENDL; LLHTTPClient::post(url, body, new LLClassifiedStatsResponder(((LLView*)this)->getHandle(), mClassifiedID)); } } } -void LLPanelClassified::sendClassifiedInfoUpdate() +void LLPanelClassifiedInfo::sendClassifiedInfoUpdate() { LLAvatarClassifiedInfo c_data; @@ -608,7 +607,7 @@ void LLPanelClassified::sendClassifiedInfoUpdate() mDirty = false; } -void LLPanelClassified::draw() +void LLPanelClassifiedInfo::draw() { refresh(); @@ -616,25 +615,25 @@ void LLPanelClassified::draw() } -void LLPanelClassified::refresh() +void LLPanelClassifiedInfo::refresh() { if (!mDataRequested) { sendClassifiedInfoRequest(); } - // Check for god mode - BOOL godlike = gAgent.isGodlike(); + // Check for god mode + BOOL godlike = gAgent.isGodlike(); BOOL is_self = (gAgent.getID() == mCreatorID); - // Set button visibility/enablement appropriately + // Set button visibility/enablement appropriately if (mInFinder) { // End user doesn't ned to see price twice, or date posted. mSnapshotCtrl->setEnabled(godlike); - if(godlike) + if (godlike) { //make it smaller, so text is more legible mSnapshotCtrl->setOrigin(20, 175); @@ -673,22 +672,22 @@ void LLPanelClassified::refresh() mMatureCombo->setEnabled(is_self); if( is_self ) - { + { if( mMatureCombo->getCurrentIndex() == 0 ) { // It's a new panel. // PG regions should have PG classifieds. AO should have mature. - + setDefaultAccessCombo(); } } - + if (mAutoRenewCheck) { mAutoRenewCheck->setEnabled(is_self); mAutoRenewCheck->setVisible(is_self); } - + mClickThroughText->setEnabled(is_self); mClickThroughText->setVisible(is_self); @@ -703,7 +702,7 @@ void LLPanelClassified::refresh() } } -void LLPanelClassified::onClickUpdate() +void LLPanelClassifiedInfo::onClickUpdate() { // Disallow leading spaces, punctuation, etc. that screw up // sort order. @@ -719,7 +718,7 @@ void LLPanelClassified::onClickUpdate() LLNotificationsUtil::add("SetClassifiedMature", LLSD(), LLSD(), - boost::bind(&LLPanelClassified::confirmMature, this, _1, _2)); + boost::bind(&LLPanelClassifiedInfo::confirmMature, this, _1, _2)); return; } @@ -728,7 +727,7 @@ void LLPanelClassified::onClickUpdate() } // Callback from a dialog indicating response to mature notification -bool LLPanelClassified::confirmMature(const LLSD& notification, const LLSD& response) +bool LLPanelClassifiedInfo::confirmMature(const LLSD& notification, const LLSD& response) { S32 option = LLNotification::getSelectedOption(notification, response); @@ -754,29 +753,31 @@ bool LLPanelClassified::confirmMature(const LLSD& notification, const LLSD& resp // Called after we have determined whether this classified has // mature content or not. -void LLPanelClassified::gotMature() +void LLPanelClassifiedInfo::gotMature() { // if already paid for, just do the update if (mPaidFor) { LLNotification::Params params("PublishClassified"); - params.functor(boost::bind(&LLPanelClassified::confirmPublish, this, _1, _2)); + params.functor(boost::bind(&LLPanelClassifiedInfo::confirmPublish, this, _1, _2)); LLNotifications::instance().forceResponse(params, 0); } else { // Ask the user how much they want to pay - new LLFloaterPriceForListing(boost::bind(&LLPanelClassified::callbackGotPriceForListing, this, _1)); + new LLFloaterPriceForListing(boost::bind(&LLPanelClassifiedInfo::callbackGotPriceForListing, this, _1)); } } -void LLPanelClassified::callbackGotPriceForListing(const std::string& text) +void LLPanelClassifiedInfo::callbackGotPriceForListing(const std::string& text) { S32 price_for_listing = strtol(text.c_str(), NULL, 10); - if (price_for_listing < MINIMUM_PRICE_FOR_LISTING) + const HippoGridInfo& grid(*gHippoGridManager->getConnectedGrid()); + const int& min_fee(grid.getClassifiedFee()); + if (price_for_listing < min_fee) { LLSD args; - args["MIN_PRICE"] = llformat("%d", MINIMUM_PRICE_FOR_LISTING); + args["MIN_PRICE"] = llformat("%d", min_fee); LLNotificationsUtil::add("MinClassifiedPrice", args); return; } @@ -787,12 +788,12 @@ void LLPanelClassified::callbackGotPriceForListing(const std::string& text) LLSD args; args["AMOUNT"] = llformat("%d", price_for_listing); - args["CURRENCY"] = gHippoGridManager->getConnectedGrid()->getCurrencySymbol(); + args["CURRENCY"] = grid.getCurrencySymbol(); LLNotificationsUtil::add("PublishClassified", args, LLSD(), - boost::bind(&LLPanelClassified::confirmPublish, this, _1, _2)); + boost::bind(&LLPanelClassifiedInfo::confirmPublish, this, _1, _2)); } -void LLPanelClassified::resetDirty() +void LLPanelClassifiedInfo::resetDirty() { // Tell all the widgets to reset their dirty state since the ad was just saved if (mSnapshotCtrl) @@ -813,7 +814,7 @@ void LLPanelClassified::resetDirty() } // invoked from callbackConfirmPublish -bool LLPanelClassified::confirmPublish(const LLSD& notification, const LLSD& response) +bool LLPanelClassifiedInfo::confirmPublish(const LLSD& notification, const LLSD& response) { S32 option = LLNotification::getSelectedOption(notification, response); // Option 0 = publish @@ -839,18 +840,18 @@ bool LLPanelClassified::confirmPublish(const LLSD& notification, const LLSD& res return false; } -void LLPanelClassified::onClickTeleport() +void LLPanelClassifiedInfo::onClickTeleport() { if (!mPosGlobal.isExactlyZero()) - { + { gAgent.teleportViaLocation(mPosGlobal); gFloaterWorldMap->trackLocation(mPosGlobal); sendClassifiedClickMessage("teleport"); - } + } } -void LLPanelClassified::onClickMap() +void LLPanelClassifiedInfo::onClickMap() { gFloaterWorldMap->trackLocation(mPosGlobal); LLFloaterWorldMap::show(true); @@ -858,20 +859,20 @@ void LLPanelClassified::onClickMap() sendClassifiedClickMessage("map"); } -void LLPanelClassified::onClickProfile() +void LLPanelClassifiedInfo::onClickProfile() { LLAvatarActions::showProfile(mCreatorID); sendClassifiedClickMessage("profile"); } /* -void LLPanelClassified::onClickLandmark() +void LLPanelClassifiedInfo::onClickLandmark() { create_landmark(mNameEditor->getText(), "", mPosGlobal); } */ -void LLPanelClassified::onClickSet() +void LLPanelClassifiedInfo::onClickSet() { // [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0a) if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) @@ -893,12 +894,12 @@ void LLPanelClassified::onClickSet() location_text.assign(regionName); location_text.append(", "); - S32 region_x = llround((F32)mPosGlobal.mdV[VX]) % REGION_WIDTH_UNITS; - S32 region_y = llround((F32)mPosGlobal.mdV[VY]) % REGION_WIDTH_UNITS; - S32 region_z = llround((F32)mPosGlobal.mdV[VZ]); - + S32 region_x = ll_round((F32)mPosGlobal.mdV[VX]) % REGION_WIDTH_UNITS; + S32 region_y = ll_round((F32)mPosGlobal.mdV[VY]) % REGION_WIDTH_UNITS; + S32 region_z = ll_round((F32)mPosGlobal.mdV[VZ]); + location_text.append(mSimName); - location_text.append(llformat(" (%d, %d, %d)", region_x, region_y, region_z)); + location_text.append(llformat(" (%d, %d, %d)", region_x, region_y, region_z)); mLocationEditor->setText(location_text); mLocationChanged = true; @@ -912,14 +913,14 @@ void LLPanelClassified::onClickSet() } -BOOL LLPanelClassified::checkDirty() +BOOL LLPanelClassifiedInfo::checkDirty() { mDirty = FALSE; if ( mSnapshotCtrl ) mDirty |= mSnapshotCtrl->isDirty(); if ( mNameEditor ) mDirty |= mNameEditor->isDirty(); if ( mDescEditor ) mDirty |= mDescEditor->isDirty(); if ( mLocationEditor ) mDirty |= mLocationEditor->isDirty(); - if ( mLocationChanged ) mDirty |= TRUE; + if ( mLocationChanged ) mDirty |= TRUE; if ( mCategoryCombo ) mDirty |= mCategoryCombo->isDirty(); if ( mMatureCombo ) mDirty |= mMatureCombo->isDirty(); if ( mAutoRenewCheck ) mDirty |= mAutoRenewCheck->isDirty(); @@ -928,7 +929,7 @@ BOOL LLPanelClassified::checkDirty() } -void LLPanelClassified::sendClassifiedClickMessage(const std::string& type) +void LLPanelClassifiedInfo::sendClassifiedClickMessage(const std::string& type) { // You're allowed to click on your own ads to reassure yourself // that the system is working. @@ -941,7 +942,7 @@ void LLPanelClassified::sendClassifiedClickMessage(const std::string& type) body["region_name"] = mSimName; std::string url = gAgent.getRegion()->getCapability("SearchStatTracking"); - llinfos << "LLPanelClassified::sendClassifiedClickMessage via capability" << llendl; + LL_INFOS() << "LLPanelClassifiedInfo::sendClassifiedClickMessage via capability" << LL_ENDL; LLHTTPClient::post(url, body, new LLHTTPClient::ResponderIgnore); } @@ -971,7 +972,7 @@ BOOL LLFloaterPriceForListing::postBuild() if (edit) { edit->setPrevalidate(LLLineEditor::prevalidateNonNegativeS32); - std::string min_price = llformat("%d", MINIMUM_PRICE_FOR_LISTING); + std::string min_price = llformat("%d", gHippoGridManager->getConnectedGrid()->getClassifiedFee()); edit->setText(min_price); edit->selectAll(); edit->setFocus(TRUE); @@ -991,7 +992,7 @@ void LLFloaterPriceForListing::buttonCore() close(); } -void LLPanelClassified::setDefaultAccessCombo() +void LLPanelClassifiedInfo::setDefaultAccessCombo() { // PG regions should have PG classifieds. AO should have mature. @@ -1010,3 +1011,5 @@ void LLPanelClassified::setDefaultAccessCombo() break; } } + +//EOF diff --git a/indra/newview/llpanelclassified.h b/indra/newview/llpanelclassified.h index 04432edfd0..36b84e6d2d 100644 --- a/indra/newview/llpanelclassified.h +++ b/indra/newview/llpanelclassified.h @@ -1,6 +1,6 @@ /** * @file llpanelclassified.h - * @brief LLPanelClassified class definition + * @brief LLPanelClassifiedInfo class definition * * $LicenseInfo:firstyear=2005&license=viewergpl$ * @@ -52,11 +52,11 @@ class LLTextEditor; class LLTextureCtrl; class LLUICtrl; -class LLPanelClassified : public LLPanel, public LLAvatarPropertiesObserver +class LLPanelClassifiedInfo : public LLPanel, public LLAvatarPropertiesObserver { public: - LLPanelClassified(bool in_finder, bool from_search); - /*virtual*/ ~LLPanelClassified(); + LLPanelClassifiedInfo(bool in_finder, bool from_search); + /*virtual*/ ~LLPanelClassifiedInfo(); void reset(); @@ -167,7 +167,7 @@ class LLPanelClassified : public LLPanel, public LLAvatarPropertiesObserver LLTextBox* mClickThroughText; LLRect mSnapshotSize; - typedef std::list panel_list_t; + typedef std::list panel_list_t; static panel_list_t sAllPanels; }; diff --git a/indra/newview/llpanelcontents.cpp b/indra/newview/llpanelcontents.cpp index c44a855b79..e9f394b31d 100644 --- a/indra/newview/llpanelcontents.cpp +++ b/indra/newview/llpanelcontents.cpp @@ -36,39 +36,17 @@ #include "llpanelcontents.h" // linden library includes -#include "llerror.h" -#include "llrect.h" -#include "llstring.h" -#include "llmaterialtable.h" -#include "llfontgl.h" -#include "m3math.h" -#include "llpermissionsflags.h" -#include "lleconomy.h" -#include "material_codes.h" #include "llinventorydefines.h" // project includes -#include "llui.h" -#include "llspinctrl.h" -#include "llcheckboxctrl.h" -#include "lltextbox.h" -#include "llbutton.h" -#include "llcombobox.h" -#include "llfloaterbulkpermission.h" - #include "llagent.h" -#include "llviewerwindow.h" +#include "llfloaterbulkpermission.h" +#include "llfloaterperms.h" +#include "llpanelobjectinventory.h" +#include "llpreviewscript.h" +#include "llselectmgr.h" #include "llviewerassettype.h" -#include "llworld.h" #include "llviewerobject.h" -#include "llviewerregion.h" -#include "llresmgr.h" -#include "llselectmgr.h" -#include "llpreviewscript.h" -#include "lltool.h" -#include "lltoolmgr.h" -#include "lltoolcomp.h" -#include "llpanelobjectinventory.h" // [RLVa:KB] - Checked: 2010-03-31 (RLVa-1.2.0c) #include "rlvhandler.h" #include "rlvlocks.h" @@ -122,7 +100,7 @@ void LLPanelContents::getState(LLViewerObject *objectp ) } LLUUID group_id; // used for SL-23488 - LLSelectMgr::getInstance()->selectGetGroup(group_id); // sets group_id as a side effect SL-23488 + (void)LLSelectMgr::getInstance()->selectGetGroup(group_id); // sets group_id as a side effect SL-23488 // BUG? Check for all objects being editable? bool editable = gAgent.isGodlike() @@ -203,12 +181,14 @@ void LLPanelContents::onClickNewScript(void *userdata) LLPermissions perm; perm.init(gAgent.getID(), gAgent.getID(), LLUUID::null, LLUUID::null); + + // Parameters are base, owner, everyone, group, next perm.initMasks( PERM_ALL, PERM_ALL, - PERM_NONE, - PERM_NONE, - PERM_MOVE | PERM_TRANSFER); + LLFloaterPerms::getEveryonePerms("Scripts"), + LLFloaterPerms::getGroupPerms("Scripts"), + LLFloaterPerms::getNextOwnerPerms("Scripts")); std::string desc; LLViewerAssetType::generateDescriptionFor(LLAssetType::AT_LSL_TEXT, desc); LLPointer new_item = diff --git a/indra/newview/llpaneldirbrowser.cpp b/indra/newview/llpaneldirbrowser.cpp index bd0a7b3edb..65aa2de461 100644 --- a/indra/newview/llpaneldirbrowser.cpp +++ b/indra/newview/llpaneldirbrowser.cpp @@ -470,7 +470,7 @@ void LLPanelDirBrowser::showDetailPanel(S32 type, LLSD id) break; default: { - llwarns << "Unknown event type!" << llendl; + LL_WARNS() << "Unknown event type!" << LL_ENDL; } break; } @@ -722,7 +722,7 @@ void LLPanelDirBrowser::processDirEventsReply(LLMessageSystem* msg, void**) if (owner_id.isNull()) { //RN: should this check event_id instead? - llwarns << "skipped event due to owner_id null, event_id " << event_id << llendl; + LL_WARNS() << "skipped event due to owner_id null, event_id " << event_id << LL_ENDL; continue; } @@ -730,19 +730,19 @@ void LLPanelDirBrowser::processDirEventsReply(LLMessageSystem* msg, void**) // there's no PG flag, so we make sure neither adult nor mature is set if (((event_flags & (EVENT_FLAG_ADULT | EVENT_FLAG_MATURE)) == EVENT_FLAG_NONE) && !show_pg) { - //llwarns << "Skipped pg event because we're not showing pg, event_id " << event_id << llendl; + //LL_WARNS() << "Skipped pg event because we're not showing pg, event_id " << event_id << LL_ENDL; continue; } if ((event_flags & EVENT_FLAG_MATURE) && !show_mature) { - //llwarns << "Skipped mature event because we're not showing mature, event_id " << event_id << llendl; + //LL_WARNS() << "Skipped mature event because we're not showing mature, event_id " << event_id << LL_ENDL; continue; } if ((event_flags & EVENT_FLAG_ADULT) && !show_adult) { - //llwarns << "Skipped adult event because we're not showing adult, event_id " << event_id << llendl; + //LL_WARNS() << "Skipped adult event because we're not showing adult, event_id " << event_id << LL_ENDL; continue; } @@ -903,8 +903,8 @@ void LLPanelDirBrowser::processDirClassifiedReply(LLMessageSystem* msg, void**) msg->getUUID("AgentData", "AgentID", agent_id); if (agent_id != gAgent.getID()) { - llwarns << "Message for wrong agent " << agent_id - << " in processDirClassifiedReply" << llendl; + LL_WARNS() << "Message for wrong agent " << agent_id + << " in processDirClassifiedReply" << LL_ENDL; return; } @@ -1032,7 +1032,7 @@ void LLPanelDirBrowser::processDirLandReply(LLMessageSystem *msg, void**) if ( msg->getSizeFast(_PREHASH_QueryReplies, i, _PREHASH_ProductSKU) > 0 ) { msg->getStringFast( _PREHASH_QueryReplies, _PREHASH_ProductSKU, land_sku, i); - llinfos << "Land sku: " << land_sku << llendl; + LL_INFOS() << "Land sku: " << land_sku << LL_ENDL; land_type = LLProductInfoRequestManager::instance().getDescriptionForSku(land_sku); } else diff --git a/indra/newview/llpaneldirclassified.cpp b/indra/newview/llpaneldirclassified.cpp index 2bc8548640..7b97163af6 100644 --- a/indra/newview/llpaneldirclassified.cpp +++ b/indra/newview/llpaneldirclassified.cpp @@ -32,8 +32,6 @@ #include "llviewerprecompiledheaders.h" -#include "llenum.h" - #include "llpaneldirclassified.h" #include "llclassifiedflags.h" @@ -119,7 +117,8 @@ BOOL LLPanelDirClassified::postBuild() // Don't do this every time we open find, it's expensive; require clicking 'search' //requestClassified(); - childSetVisible("filter_gaming", (gAgent.getRegion()->getGamingFlags() & REGION_GAMING_PRESENT) && !(gAgent.getRegion()->getGamingFlags() & REGION_GAMING_HIDE_FIND_CLASSIFIEDS)); + LLViewerRegion* region(gAgent.getRegion()); + getChildView("filter_gaming")->setVisible(region && (region->getGamingFlags() & REGION_GAMING_PRESENT) && !(region->getGamingFlags() & REGION_GAMING_HIDE_FIND_CLASSIFIEDS)); return TRUE; } @@ -173,7 +172,7 @@ void LLPanelDirClassified::onClickDelete() void LLPanelDirClassified::performQuery() { - lldebugs << "LLPanelDirClassified::performQuery()" << llendl; + LL_DEBUGS() << "LLPanelDirClassified::performQuery()" << LL_ENDL; BOOL inc_pg = childGetValue("incpg").asBoolean(); BOOL inc_mature = childGetValue("incmature").asBoolean(); diff --git a/indra/newview/llpaneldirevents.cpp b/indra/newview/llpaneldirevents.cpp index 8b7453b1b8..eed058cc91 100644 --- a/indra/newview/llpaneldirevents.cpp +++ b/indra/newview/llpaneldirevents.cpp @@ -37,7 +37,6 @@ #include // linden library includes -#include "llenum.h" #include "message.h" #include "llqueryflags.h" @@ -53,8 +52,6 @@ #include "llnotificationsutil.h" #include "llviewerregion.h" -BOOL gDisplayEventHack = FALSE; - LLPanelDirEvents::LLPanelDirEvents(const std::string& name, LLFloaterDirectory* floater) : LLPanelDirBrowser(name, floater), mDoneQuery(FALSE), @@ -86,14 +83,10 @@ BOOL LLPanelDirEvents::postBuild() mCurrentSortColumn = "time"; - if (!gDisplayEventHack) - { - setDay(0); // for today - //performQuery(); // Temporary change to help DB - Sabin - } - gDisplayEventHack = FALSE; + setDay(0); // for today - childSetVisible("filter_gaming", (gAgent.getRegion()->getGamingFlags() & REGION_GAMING_PRESENT) && !(gAgent.getRegion()->getGamingFlags() & REGION_GAMING_HIDE_FIND_EVENTS)); + LLViewerRegion* region(gAgent.getRegion()); + getChildView("filter_gaming")->setVisible(region && (gAgent.getRegion()->getGamingFlags() & REGION_GAMING_PRESENT) && !(gAgent.getRegion()->getGamingFlags() & REGION_GAMING_HIDE_FIND_EVENTS)); return TRUE; } diff --git a/indra/newview/llpaneldirfind.cpp b/indra/newview/llpaneldirfind.cpp index c181497cc9..e046e1b42b 100644 --- a/indra/newview/llpaneldirfind.cpp +++ b/indra/newview/llpaneldirfind.cpp @@ -65,17 +65,99 @@ #include "llpaneldirbrowser.h" #include "hippogridmanager.h" +#include "lfsimfeaturehandler.h" -#if LL_MSVC -// disable boost::lexical_cast warning -#pragma warning (disable:4702) -#endif #include -#include //--------------------------------------------------------------------------- // LLPanelDirFindAll - Google search appliance based search //--------------------------------------------------------------------------- +namespace +{ + std::string getSearchUrl() + { + return LFSimFeatureHandler::instance().searchURL(); + } + enum SearchType + { + SEARCH_ALL_EMPTY, + SEARCH_ALL_QUERY, + SEARCH_ALL_TEMPLATE + }; + std::string getSearchUrl(SearchType ty, bool is_web) + { + const std::string mSearchUrl(getSearchUrl()); + if (is_web) + { + if (gHippoGridManager->getConnectedGrid()->isSecondLife()) + { + // Second Life defaults + if (ty == SEARCH_ALL_EMPTY) + { + return gSavedSettings.getString("SearchURLDefault"); + } + else if (ty == SEARCH_ALL_QUERY) + { + return gSavedSettings.getString("SearchURLQuery"); + } + else if (ty == SEARCH_ALL_TEMPLATE) + { + return gSavedSettings.getString("SearchURLSuffix2"); + } + } + else if (!mSearchUrl.empty()) + { + // Search url sent to us in the login response + if (ty == SEARCH_ALL_EMPTY) + { + return mSearchUrl; + } + else if (ty == SEARCH_ALL_QUERY) + { + return mSearchUrl + "q=[QUERY]&s=[COLLECTION]&"; + } + else if (ty == SEARCH_ALL_TEMPLATE) + { + return "lang=[LANG]&mat=[MATURITY]&t=[TEEN]®ion=[REGION]&x=[X]&y=[Y]&z=[Z]&session=[SESSION]&dice=[DICE]"; + } + } + else + { + // OpenSim and other web search defaults + if (ty == SEARCH_ALL_EMPTY) + { + return gSavedSettings.getString("SearchURLDefaultOpenSim"); + } + else if (ty == SEARCH_ALL_QUERY) + { + return gSavedSettings.getString("SearchURLQueryOpenSim"); + } + else if (ty == SEARCH_ALL_TEMPLATE) + { + return gSavedSettings.getString("SearchURLSuffixOpenSim"); + } + } + } + else + { + // Use the old search all + if (ty == SEARCH_ALL_EMPTY) + { + return mSearchUrl + "panel=All&"; + } + else if (ty == SEARCH_ALL_QUERY) + { + return mSearchUrl + "q=[QUERY]&s=[COLLECTION]&"; + } + else if (ty == SEARCH_ALL_TEMPLATE) + { + return "lang=[LANG]&m=[MATURITY]&t=[TEEN]®ion=[REGION]&x=[X]&y=[Y]&z=[Z]&session=[SESSION]&dice=[DICE]"; + } + } + LL_INFOS() << "Illegal search URL type " << ty << LL_ENDL; + return ""; + } +} class LLPanelDirFindAll : public LLPanelDirFind @@ -90,6 +172,7 @@ class LLPanelDirFindAll LLPanelDirFindAll::LLPanelDirFindAll(const std::string& name, LLFloaterDirectory* floater) : LLPanelDirFind(name, floater, "find_browser") { + LFSimFeatureHandler::getInstance()->setSearchURLCallback(boost::bind(&LLPanelDirFindAll::navigateToDefaultPage, this)); } //--------------------------------------------------------------------------- @@ -155,14 +238,14 @@ BOOL LLPanelDirFind::postBuild() // need to handle secondlife:///app/ URLs for direct teleports mWebBrowser->setTrustedContent( true ); - // redirect 404 pages from S3 somewhere else - mWebBrowser->set404RedirectUrl( getString("redirect_404_url") ); - navigateToDefaultPage(); } if (LLUICtrl* ctrl = findChild("filter_gaming")) - ctrl->setVisible((gAgent.getRegion()->getGamingFlags() & REGION_GAMING_PRESENT) && !(gAgent.getRegion()->getGamingFlags() & REGION_GAMING_HIDE_FIND_ALL)); + { + const LLViewerRegion* region(gAgent.getRegion()); + ctrl->setVisible(region && (region->getGamingFlags() & REGION_GAMING_PRESENT) && !(region->getGamingFlags() & REGION_GAMING_HIDE_FIND_ALL)); + } return TRUE; } @@ -237,7 +320,7 @@ void LLPanelDirFindAll::search(const std::string& search_text) } else { - llwarns << "search panel not found! How can this be?!" << llendl; + LL_WARNS() << "search panel not found! How can this be?!" << LL_ENDL; } std::string selected_collection = childGetValue( "Category" ).asString(); @@ -264,52 +347,42 @@ void LLPanelDirFind::focus() void LLPanelDirFind::navigateToDefaultPage() { - std::string start_url = ""; + bool showcase(mBrowserName == "showcase_browser"); + std::string start_url = showcase ? LLWeb::expandURLSubstitutions(LFSimFeatureHandler::instance().destinationGuideURL(), LLSD()) : getSearchUrl(); + bool secondlife(gHippoGridManager->getConnectedGrid()->isSecondLife()); // Note: we use the web panel in OpenSim as well as Second Life -- MC - if (gHippoGridManager->getConnectedGrid()->getSearchUrl().empty() && - !gHippoGridManager->getConnectedGrid()->isSecondLife()) + if (start_url.empty() && !secondlife) { // OS-based but doesn't have its own web search url -- MC start_url = gSavedSettings.getString("SearchURLDefaultOpenSim"); } else { - if (gHippoGridManager->getConnectedGrid()->isSecondLife()) + if (!showcase) { - if (mBrowserName == "showcase_browser") - { - // note that the showcase URL in floater_directory.xml is no longer used - start_url = gSavedSettings.getString("ShowcaseURLDefault"); - } - else - { + if (secondlife) // Legacy Web Search start_url = gSavedSettings.getString("SearchURLDefault"); - } - } - else - { - // OS-based but has its own web search url -- MC - start_url = gHippoGridManager->getConnectedGrid()->getSearchUrl(); - start_url += "panel=" + getName() + "&"; - } + else // OS-based but has its own web search url -- MC + start_url += "panel=" + getName() + "&"; - if (hasChild("incmature")) - { - bool inc_pg = childGetValue("incpg").asBoolean(); - bool inc_mature = childGetValue("incmature").asBoolean(); - bool inc_adult = childGetValue("incadult").asBoolean(); - if (!(inc_pg || inc_mature || inc_adult)) + if (hasChild("incmature")) { - // if nothing's checked, just go for pg; we don't notify in - // this case because it's a default page. - inc_pg = true; + bool inc_pg = getChildView("incpg")->getValue().asBoolean(); + bool inc_mature = getChildView("incmature")->getValue().asBoolean(); + bool inc_adult = getChildView("incadult")->getValue().asBoolean(); + if (!(inc_pg || inc_mature || inc_adult)) + { + // if nothing's checked, just go for pg; we don't notify in + // this case because it's a default page. + inc_pg = true; + } + + start_url += getSearchURLSuffix(inc_pg, inc_mature, inc_adult, true); } - - start_url += getSearchURLSuffix(inc_pg, inc_mature, inc_adult, true); } } - llinfos << "default web search url: " << start_url << llendl; + LL_INFOS() << "default web search url: " << start_url << LL_ENDL; if (mWebBrowser) { @@ -323,7 +396,7 @@ const std::string LLPanelDirFind::buildSearchURL(const std::string& search_text, std::string url; if (search_text.empty()) { - url = gHippoGridManager->getConnectedGrid()->getSearchUrl(HippoGridInfo::SEARCH_ALL_EMPTY, is_web); + url = getSearchUrl(SEARCH_ALL_EMPTY, is_web); } else { @@ -348,7 +421,7 @@ const std::string LLPanelDirFind::buildSearchURL(const std::string& search_text, "-._~$+!*'()"; std::string query = LLURI::escape(search_text_with_plus, allowed); - url = gHippoGridManager->getConnectedGrid()->getSearchUrl(HippoGridInfo::SEARCH_ALL_QUERY, is_web); + url = getSearchUrl(SEARCH_ALL_QUERY, is_web); std::string substring = "[QUERY]"; std::string::size_type where = url.find(substring); if (where != std::string::npos) @@ -367,20 +440,19 @@ const std::string LLPanelDirFind::buildSearchURL(const std::string& search_text, } url += getSearchURLSuffix(inc_pg, inc_mature, inc_adult, is_web); - llinfos << "web search url " << url << llendl; + LL_INFOS() << "web search url " << url << LL_ENDL; return url; } const std::string LLPanelDirFind::getSearchURLSuffix(bool inc_pg, bool inc_mature, bool inc_adult, bool is_web) const { - std::string url = gHippoGridManager->getConnectedGrid()->getSearchUrl(HippoGridInfo::SEARCH_ALL_TEMPLATE, is_web); - llinfos << "Suffix template " << url << llendl; + std::string url = getSearchUrl(SEARCH_ALL_TEMPLATE, is_web); + LL_INFOS() << "Suffix template " << url << LL_ENDL; if (!url.empty()) { // Note: opensim's default template (SearchURLSuffixOpenSim) is currently empty -- MC - if (gHippoGridManager->getConnectedGrid()->isSecondLife() || - !gHippoGridManager->getConnectedGrid()->getSearchUrl().empty()) + if (gHippoGridManager->getConnectedGrid()->isSecondLife() || !getSearchUrl().empty()) { // if the mature checkbox is unchecked, modify query to remove // terms with given phrase from the result set @@ -391,7 +463,7 @@ const std::string LLPanelDirFind::getSearchURLSuffix(bool inc_pg, bool inc_matur (inc_pg ? SEARCH_PG : SEARCH_NONE) | (inc_mature ? SEARCH_MATURE : SEARCH_NONE) | (inc_adult ? SEARCH_ADULT : SEARCH_NONE); - url.replace(url.find(substring), substring.length(), boost::lexical_cast(maturityFlag)); + url.replace(url.find(substring), substring.length(), fmt::to_string(maturityFlag)); // Include region and x/y position, not for the GSA, but // just to get logs on the web server for search_proxy.php @@ -505,7 +577,7 @@ void LLPanelDirFind::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent even case MEDIA_EVENT_LOCATION_CHANGED: // Debugging info to console - llinfos << self->getLocation() << llendl; + LL_INFOS() << self->getLocation() << LL_ENDL; break; default: @@ -518,17 +590,38 @@ void LLPanelDirFind::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent even // LLPanelDirFindAllInterface //--------------------------------------------------------------------------- +static LLPanelDirFindAll* sFindAll = NULL; // static LLPanelDirFindAll* LLPanelDirFindAllInterface::create(LLFloaterDirectory* floater) { return new LLPanelDirFindAll("find_all_panel", floater); } +static LLPanelDirFindAllOld* sFindAllOld = NULL; // static -void LLPanelDirFindAllInterface::search(LLPanelDirFindAll* panel, - const std::string& search_text) +void LLPanelDirFindAllInterface::search(LLFloaterDirectory* inst, + const LLFloaterSearch::SearchQuery& search, bool show) { - panel->search(search_text); + bool secondlife(gHippoGridManager->getConnectedGrid()->isSecondLife()); + LLPanelDirFind* find_panel(secondlife ? inst->findChild("web_panel") : sFindAll); + LLPanel* panel(find_panel); + if (secondlife) + LLFloaterSearch::search(search, find_panel->mWebBrowser); + else + { + bool has_url(!getSearchUrl().empty()); + if (has_url) find_panel->search(search.query); + if (sFindAllOld) + { + sFindAllOld->search(search.query); + if (!has_url) panel = sFindAllOld; + } + } + if (show && panel) + { + inst->findChild("Directory Tabs")->selectTabPanel(panel); + panel->setFocus(true); + } } // static @@ -544,6 +637,7 @@ void LLPanelDirFindAllInterface::focus(LLPanelDirFindAll* panel) LLPanelDirFindAllOld::LLPanelDirFindAllOld(const std::string& name, LLFloaterDirectory* floater) : LLPanelDirBrowser(name, floater) { + sFindAllOld = this; mMinSearchChars = 3; } @@ -558,13 +652,14 @@ BOOL LLPanelDirFindAllOld::postBuild() setDefaultBtn( "Search" ); if (LLUICtrl* ctrl = findChild("filter_gaming")) - ctrl->setVisible((gAgent.getRegion()->getGamingFlags() & REGION_GAMING_PRESENT) && !(gAgent.getRegion()->getGamingFlags() & REGION_GAMING_HIDE_FIND_ALL_CLASSIC)); + ctrl->setVisible(gAgent.getRegion() && (gAgent.getRegion()->getGamingFlags() & REGION_GAMING_PRESENT) && !(gAgent.getRegion()->getGamingFlags() & REGION_GAMING_HIDE_FIND_ALL_CLASSIC)); return TRUE; } LLPanelDirFindAllOld::~LLPanelDirFindAllOld() { + sFindAllOld = NULL; // Children all cleaned up by default view destructor. } @@ -575,12 +670,18 @@ void LLPanelDirFindAllOld::draw() LLPanelDirBrowser::draw(); } +void LLPanelDirFindAllOld::search(const std::string& query) +{ + getChildView("name")->setValue(query); + onClickSearch(); +} + void LLPanelDirFindAllOld::onClickSearch() { if (childGetValue("name").asString().length() < mMinSearchChars) { return; - }; + } BOOL inc_pg = childGetValue("incpg").asBoolean(); BOOL inc_mature = childGetValue("incmature").asBoolean(); diff --git a/indra/newview/llpaneldirfind.h b/indra/newview/llpaneldirfind.h index 8ec0e51aac..f5e4b690cc 100644 --- a/indra/newview/llpaneldirfind.h +++ b/indra/newview/llpaneldirfind.h @@ -34,10 +34,8 @@ #define LL_LLPANELDIRFIND_H #include "llpaneldirbrowser.h" -#include "llmediactrl.h" +#include "llfloatersearch.h" -class LLUICtrl; -class LLLineEditor; class LLPanelDirFindAll; class LLFloaterDirectory; @@ -76,6 +74,7 @@ class LLPanelDirFind /*virtual*/ void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event); protected: + friend class LLPanelDirFindAllInterface; LLMediaCtrl* mWebBrowser; std::string mBrowserName; }; @@ -84,7 +83,7 @@ class LLPanelDirFindAllInterface { public: static LLPanelDirFindAll* create(LLFloaterDirectory* floater); - static void search(LLPanelDirFindAll* panel, const std::string& search_text); + static void search(LLFloaterDirectory* inst, const LLFloaterSearch::SearchQuery& search, bool show = false); static void focus(LLPanelDirFindAll* panel); }; @@ -99,6 +98,7 @@ class LLPanelDirFindAllOld : public LLPanelDirBrowser /*virtual*/ void draw(); + void search(const std::string& query); void onClickSearch(); }; diff --git a/indra/newview/llpaneldirgroups.cpp b/indra/newview/llpaneldirgroups.cpp index 6cdcdd538a..bbd07ed2df 100644 --- a/indra/newview/llpaneldirgroups.cpp +++ b/indra/newview/llpaneldirgroups.cpp @@ -61,7 +61,8 @@ BOOL LLPanelDirGroups::postBuild() childDisable("Search"); setDefaultBtn( "Search" ); - childSetVisible("filter_gaming", (gAgent.getRegion()->getGamingFlags() & REGION_GAMING_PRESENT) && !(gAgent.getRegion()->getGamingFlags() & REGION_GAMING_HIDE_FIND_GROUPS)); + LLViewerRegion* region(gAgent.getRegion()); + getChildView("filter_gaming")->setVisible(region && (region->getGamingFlags() & REGION_GAMING_PRESENT) && !(region->getGamingFlags() & REGION_GAMING_HIDE_FIND_GROUPS)); return TRUE; } diff --git a/indra/newview/llpaneldirland.cpp b/indra/newview/llpaneldirland.cpp index 9c249a81db..ccb2531110 100644 --- a/indra/newview/llpaneldirland.cpp +++ b/indra/newview/llpaneldirland.cpp @@ -126,7 +126,8 @@ BOOL LLPanelDirLand::postBuild() } } - childSetVisible("filter_gaming", (gAgent.getRegion()->getGamingFlags() & REGION_GAMING_PRESENT) && !(gAgent.getRegion()->getGamingFlags() & REGION_GAMING_HIDE_FIND_LAND)); + LLViewerRegion* region(gAgent.getRegion()); + getChildView("filter_gaming")->setVisible(region && (region->getGamingFlags() & REGION_GAMING_PRESENT) && !(region->getGamingFlags() & REGION_GAMING_HIDE_FIND_LAND)); return TRUE; } diff --git a/indra/newview/llpaneldirplaces.cpp b/indra/newview/llpaneldirplaces.cpp index 706d9013c2..ae278412ae 100644 --- a/indra/newview/llpaneldirplaces.cpp +++ b/indra/newview/llpaneldirplaces.cpp @@ -68,7 +68,7 @@ LLPanelDirPlaces::LLPanelDirPlaces(const std::string& name, LLFloaterDirectory* // The crash seems unrelated to this code, but the commit that introduced it was narrowed down to this file. // Adding llinfos calls to both the constructor and destructor here makes the crash go away, even though they don't get called before the point of the crash. // This is wrong on many levels and scares the hell out of me. - llinfos << "called" << llendl; + LL_INFOS() << "called" << LL_ENDL; mMinSearchChars = 3; } @@ -99,7 +99,8 @@ BOOL LLPanelDirPlaces::postBuild() childSetEnabled("Category", true); } - childSetVisible("filter_gaming", (gAgent.getRegion()->getGamingFlags() & REGION_GAMING_PRESENT) && !(gAgent.getRegion()->getGamingFlags() & REGION_GAMING_HIDE_FIND_SIMS)); + LLViewerRegion* region(gAgent.getRegion()); + getChildView("filter_gaming")->setVisible(region && (region->getGamingFlags() & REGION_GAMING_PRESENT) && !(region->getGamingFlags() & REGION_GAMING_HIDE_FIND_SIMS)); // Don't prepopulate the places list, as it hurts the database as of 2006-12-04. JC // initialQuery(); @@ -114,7 +115,7 @@ LLPanelDirPlaces::~LLPanelDirPlaces() // The crash seems unrelated to this code, but the commit that introduced it was narrowed down to this file. // Adding llinfos calls to both the constructor and destructor here makes the crash go away, even though they don't get called before the point of the crash. // This is wrong on many levels and scares the hell out of me. - llinfos << "called" << llendl; + LL_INFOS() << "called" << LL_ENDL; // Children all cleaned up by default view destructor. } diff --git a/indra/newview/llpaneldirpopular.cpp b/indra/newview/llpaneldirpopular.cpp index ddb9d3aa5e..fa678d416c 100644 --- a/indra/newview/llpaneldirpopular.cpp +++ b/indra/newview/llpaneldirpopular.cpp @@ -33,11 +33,13 @@ #include "llviewerprecompiledheaders.h" #include "llpaneldirpopular.h" +#include "lfsimfeaturehandler.h" LLPanelDirPopular::LLPanelDirPopular(const std::string& name, LLFloaterDirectory* floater) : LLPanelDirFind(name, floater, "showcase_browser") { // *NOTE: This is now the "Showcase" section + LFSimFeatureHandler::instance().setSearchURLCallback(boost::bind(&LLPanelDirPopular::navigateToDefaultPage, this)); } // virtual diff --git a/indra/newview/llpaneldisplay.cpp b/indra/newview/llpaneldisplay.cpp index 0f7184757c..3bc5db91cb 100644 --- a/indra/newview/llpaneldisplay.cpp +++ b/indra/newview/llpaneldisplay.cpp @@ -97,15 +97,31 @@ const F32 MIN_USER_FAR_CLIP = 64.f; const S32 ASPECT_RATIO_STR_LEN = 100; +void reset_to_default(const std::string& control); +void reset_all_to_default(const LLView* panel) +{ + LLView::child_list_const_iter_t end(panel->endChild()); + for (LLView::child_list_const_iter_t i = panel->beginChild(); i != end; ++i) + { + const std::string& control_name((*i)->getControlName()); + if (control_name.empty()) continue; + if (control_name == "RenderDepthOfField") continue; // Don't touch render settings *sigh* hack + reset_to_default(control_name); + } +} + LLPanelDisplay::LLPanelDisplay() { + mCommitCallbackRegistrar.add("Graphics.ResetTab", boost::bind(reset_all_to_default, boost::bind(&LLView::getChildView, this, _2, true, false))); LLUICtrlFactory::getInstance()->buildPanel(this, "panel_preferences_graphics1.xml"); } +void updateSliderText(LLSliderCtrl* slider, LLTextBox* text_box); + BOOL LLPanelDisplay::postBuild() { // return to default values - getChild("Defaults")->setClickedCallback(boost::bind(&LLPanelDisplay::setHardwareDefaults)); + getChild("Defaults")->setClickedCallback(boost::bind(&LLPanelDisplay::setHardwareDefaults, this)); //============================================================================ // Resolution @@ -167,7 +183,7 @@ BOOL LLPanelDisplay::postBuild() } initWindowSizeControls(); - + if (gSavedSettings.getBOOL("FullScreenAutoDetectAspectRatio")) { mAspectRatio = gViewerWindow->getDisplayAspectRatio(); @@ -192,27 +208,22 @@ BOOL LLPanelDisplay::postBuild() aspect_ratio_text = llformat("%.3f", mAspectRatio); } + mCtrlAutoDetectAspect = getChild( "aspect_auto_detect"); + mCtrlAutoDetectAspect->setCommitCallback(boost::bind(&LLPanelDisplay::onCommitAutoDetectAspect,this,_2)); + mCtrlAspectRatio = getChild( "aspect_ratio"); - mCtrlAspectRatio->setTextEntryCallback(boost::bind(&LLPanelDisplay::onKeystrokeAspectRatio,this)); - mCtrlAspectRatio->setCommitCallback(boost::bind(&LLPanelDisplay::onSelectAspectRatio,this)); + mCtrlAspectRatio->setTextEntryCallback(boost::bind(&LLUICtrl::setValue, mCtrlAutoDetectAspect, false)); + mCtrlAspectRatio->setCommitCallback(boost::bind(&LLUICtrl::setValue, mCtrlAutoDetectAspect, false)); // add default aspect ratios mCtrlAspectRatio->add(aspect_ratio_text, &mAspectRatio, ADD_TOP); mCtrlAspectRatio->setCurrentByIndex(0); - mCtrlAutoDetectAspect = getChild( "aspect_auto_detect"); - mCtrlAutoDetectAspect->setCommitCallback(boost::bind(&LLPanelDisplay::onCommitAutoDetectAspect,this,_2)); - // radio performance box mCtrlSliderQuality = getChild("QualityPerformanceSelection"); mCtrlSliderQuality->setSliderMouseUpCallback(boost::bind(&LLPanelDisplay::onChangeQuality,this,_1)); mCtrlCustomSettings = getChild("CustomSettings"); - mCtrlCustomSettings->setCommitCallback(boost::bind(&LLPanelDisplay::onChangeCustom)); - - //mGraphicsBorder = getChild("GraphicsBorder"); - - // Enable Transparent Water - mCtrlTransparentWater = getChild("TransparentWater"); + mCtrlCustomSettings->setCommitCallback(boost::bind(&LLPanelDisplay::refreshEnabledState, this)); //---------------------------------------------------------------------------- // Enable Bump/Shiny @@ -221,19 +232,19 @@ BOOL LLPanelDisplay::postBuild() //---------------------------------------------------------------------------- // Enable Reflections mCtrlReflectionDetail = getChild("ReflectionDetailCombo"); - mCtrlReflectionDetail->setCommitCallback(boost::bind(&LLPanelDisplay::onVertexShaderEnable)); + mCtrlReflectionDetail->setCommitCallback(boost::bind(&LLPanelDisplay::refreshEnabledState, this)); // WindLight mCtrlWindLight = getChild("WindLightUseAtmosShaders"); - mCtrlWindLight->setCommitCallback(boost::bind(&LLPanelDisplay::onVertexShaderEnable)); + mCtrlWindLight->setCommitCallback(boost::bind(&LLPanelDisplay::refreshEnabledState, this)); // Deferred mCtrlDeferred = getChild("RenderDeferred"); - mCtrlDeferred->setCommitCallback(boost::bind(&LLPanelDisplay::onVertexShaderEnable)); + mCtrlDeferred->setCommitCallback(boost::bind(&LLPanelDisplay::refreshEnabledState, this)); mCtrlDeferredDoF = getChild("RenderDepthOfField"); - mCtrlDeferredDoF->setCommitCallback(boost::bind(&LLPanelDisplay::onVertexShaderEnable)); + mCtrlDeferredDoF->setCommitCallback(boost::bind(&LLPanelDisplay::refreshEnabledState, this)); mCtrlShadowDetail = getChild("ShadowDetailCombo"); - mCtrlShadowDetail->setCommitCallback(boost::bind(&LLPanelDisplay::onVertexShaderEnable)); + mCtrlShadowDetail->setCommitCallback(boost::bind(&LLPanelDisplay::refreshEnabledState, this)); //---------------------------------------------------------------------------- // Terrain Scale @@ -242,18 +253,13 @@ BOOL LLPanelDisplay::postBuild() //---------------------------------------------------------------------------- // Enable Avatar Shaders mCtrlAvatarVP = getChild("AvatarVertexProgram"); - mCtrlAvatarVP->setCommitCallback(boost::bind(&LLPanelDisplay::onVertexShaderEnable)); + mCtrlAvatarVP->setCommitCallback(boost::bind(&LLPanelDisplay::refreshEnabledState, this)); //---------------------------------------------------------------------------- // Avatar Render Mode mCtrlAvatarCloth = getChild("AvatarCloth"); mCtrlAvatarImpostors = getChild("AvatarImpostors"); - mCtrlAvatarImpostors->setCommitCallback(boost::bind(&LLPanelDisplay::onVertexShaderEnable)); - mCtrlNonImpostors = getChild("AvatarMaxVisible"); - - //---------------------------------------------------------------------------- - // Checkbox for lighting detail - mCtrlLightingDetail2 = getChild("LightingDetailRadio"); + mCtrlAvatarImpostors->setCommitCallback(boost::bind(&LLPanelDisplay::refreshEnabledState, this)); //---------------------------------------------------------------------------- // Checkbox for ambient occlusion @@ -266,74 +272,74 @@ BOOL LLPanelDisplay::postBuild() //---------------------------------------------------------------------------- // Global Shader Enable mCtrlShaderEnable = getChild("BasicShaders"); - mCtrlShaderEnable->setCommitCallback(boost::bind(&LLPanelDisplay::onVertexShaderEnable)); + mCtrlShaderEnable->setCommitCallback(boost::bind(&LLPanelDisplay::refreshEnabledState, this)); //============================================================================ // Object detail slider - mCtrlDrawDistance = getChild("DrawDistance"); - mDrawDistanceMeterText1 = getChild("DrawDistanceMeterText1"); - mDrawDistanceMeterText2 = getChild("DrawDistanceMeterText2"); - mCtrlDrawDistance->setCommitCallback(boost::bind(&LLPanelDisplay::updateMeterText, this)); - - // Object detail slider - mCtrlLODFactor = getChild("ObjectMeshDetail"); - mLODFactorText = getChild("ObjectMeshDetailText"); - mCtrlLODFactor->setCommitCallback(boost::bind(&LLPanelDisplay::updateSliderText, _1,mLODFactorText)); + LLSliderCtrl* ctrl_slider = getChild("ObjectMeshDetail"); + LLTextBox* slider_text = getChild("ObjectMeshDetailText"); + ctrl_slider->setCommitCallback(boost::bind(updateSliderText, ctrl_slider, slider_text)); + updateSliderText(ctrl_slider, slider_text); // Flex object detail slider - mCtrlFlexFactor = getChild("FlexibleMeshDetail"); - mFlexFactorText = getChild("FlexibleMeshDetailText"); - mCtrlFlexFactor->setCommitCallback(boost::bind(&LLPanelDisplay::updateSliderText,_1, mFlexFactorText)); + ctrl_slider = getChild("FlexibleMeshDetail"); + slider_text = getChild("FlexibleMeshDetailText"); + ctrl_slider->setCommitCallback(boost::bind(updateSliderText, ctrl_slider, slider_text)); + updateSliderText(ctrl_slider, slider_text); // Tree detail slider - mCtrlTreeFactor = getChild("TreeMeshDetail"); - mTreeFactorText = getChild("TreeMeshDetailText"); - mCtrlTreeFactor->setCommitCallback(boost::bind(&LLPanelDisplay::updateSliderText, _1, mTreeFactorText)); + ctrl_slider = getChild("TreeMeshDetail"); + slider_text = getChild("TreeMeshDetailText"); + ctrl_slider->setCommitCallback(boost::bind(updateSliderText, ctrl_slider, slider_text)); + updateSliderText(ctrl_slider, slider_text); // Avatar detail slider - mCtrlAvatarFactor = getChild("AvatarMeshDetail"); - mAvatarFactorText = getChild("AvatarMeshDetailText"); - mCtrlAvatarFactor->setCommitCallback(boost::bind(&LLPanelDisplay::updateSliderText, _1, mAvatarFactorText)); + ctrl_slider = getChild("AvatarMeshDetail"); + slider_text = getChild("AvatarMeshDetailText"); + ctrl_slider->setCommitCallback(boost::bind(updateSliderText, ctrl_slider, slider_text)); + updateSliderText(ctrl_slider, slider_text); // Avatar physics detail slider - mCtrlAvatarPhysicsFactor = getChild("AvatarPhysicsDetail"); - mAvatarPhysicsFactorText = getChild("AvatarPhysicsDetailText"); - mCtrlAvatarPhysicsFactor->setCommitCallback(boost::bind(&LLPanelDisplay::updateSliderText, _1, mAvatarPhysicsFactorText)); + ctrl_slider = getChild("AvatarPhysicsDetail"); + slider_text = getChild("AvatarPhysicsDetailText"); + ctrl_slider->setCommitCallback(boost::bind(updateSliderText, ctrl_slider, slider_text)); + updateSliderText(ctrl_slider, slider_text); // Terrain detail slider - mCtrlTerrainFactor = getChild("TerrainMeshDetail"); - mTerrainFactorText = getChild("TerrainMeshDetailText"); - mCtrlTerrainFactor->setCommitCallback(boost::bind(&LLPanelDisplay::updateSliderText, _1, mTerrainFactorText)); + ctrl_slider = getChild("TerrainMeshDetail"); + slider_text = getChild("TerrainMeshDetailText"); + ctrl_slider->setCommitCallback(boost::bind(updateSliderText, ctrl_slider, slider_text)); + updateSliderText(ctrl_slider, slider_text); // Terrain detail slider - mCtrlSkyFactor = getChild("SkyMeshDetail"); - mSkyFactorText = getChild("SkyMeshDetailText"); - mCtrlSkyFactor->setCommitCallback(boost::bind(&LLPanelDisplay::updateSliderText, _1, mSkyFactorText)); - - // Particle detail slider - mCtrlMaxParticle = getChild("MaxParticleCount"); + ctrl_slider = getChild("SkyMeshDetail"); + slider_text = getChild("SkyMeshDetailText"); + ctrl_slider->setCommitCallback(boost::bind(updateSliderText, ctrl_slider, slider_text)); + updateSliderText(ctrl_slider, slider_text); // Glow detail slider - mCtrlPostProcess = getChild("RenderPostProcess"); - mPostProcessText = getChild("PostProcessText"); - mCtrlPostProcess->setCommitCallback(boost::bind(&LLPanelDisplay::updateSliderText, _1, mPostProcessText)); + ctrl_slider = getChild("RenderPostProcess"); + slider_text = getChild("PostProcessText"); + ctrl_slider->setCommitCallback(boost::bind(updateSliderText, ctrl_slider, slider_text)); + updateSliderText(ctrl_slider, slider_text); // Text boxes (for enabling/disabling) - mShaderText = getChild("ShadersText"); - mReflectionText = getChild("ReflectionDetailText"); - mAvatarText = getChild("AvatarRenderingText"); - mTerrainText = getChild("TerrainDetailText"); - mMeshDetailText = getChild("MeshDetailText"); - mShadowDetailText = getChild("ShadowDetailText"); - mTerrainScaleText = getChild("TerrainScaleText"); // Hardware tab mVBO = getChild("vbo"); - mVBO->setCommitCallback(boost::bind(&LLPanelDisplay::onVertexShaderEnable)); - - mVBOStream = getChild("vbo_stream"); + mVBO->setCommitCallback(boost::bind(&LLPanelDisplay::refreshEnabledState, this)); + if(gGLManager.mIsATI) //AMD gpus don't go beyond 8x fsaa. + { + LLComboBox* fsaa = getChild("fsaa"); + fsaa->remove("16x"); + } + if(!gGLManager.mHasAdaptiveVsync) + { + LLComboBox* vsync = getChild("vsync"); + vsync->remove("VSyncAdaptive"); + } refresh(); @@ -401,6 +407,7 @@ void LLPanelDisplay::refresh() mAvatarVP = gSavedSettings.getBOOL("RenderAvatarVP"); mDeferred = gSavedSettings.getBOOL("RenderDeferred"); mDeferredDoF = gSavedSettings.getBOOL("RenderDepthOfField"); + mDeferredSSAO = gSavedSettings.getBOOL("RenderDeferredSSAO"); // combo boxes mReflectionDetail = gSavedSettings.getS32("RenderReflectionDetail"); @@ -429,16 +436,6 @@ void LLPanelDisplay::refresh() mLocalLights = gSavedSettings.getBOOL("RenderLocalLights"); mTerrainDetail = gSavedSettings.getS32("RenderTerrainDetail"); - // slider text boxes - updateSliderText(mCtrlLODFactor, mLODFactorText); - updateSliderText(mCtrlFlexFactor, mFlexFactorText); - updateSliderText(mCtrlTreeFactor, mTreeFactorText); - updateSliderText(mCtrlAvatarFactor, mAvatarFactorText); - updateSliderText(mCtrlAvatarPhysicsFactor, mAvatarPhysicsFactorText); - updateSliderText(mCtrlTerrainFactor, mTerrainFactorText); - updateSliderText(mCtrlPostProcess, mPostProcessText); - updateSliderText(mCtrlSkyFactor, mSkyFactorText); - // Hardware tab mUseVBO = gSavedSettings.getBOOL("RenderVBOEnable"); mUseFBO = gSavedSettings.getBOOL("RenderUseFBO"); @@ -447,8 +444,17 @@ void LLPanelDisplay::refresh() mGamma = gSavedSettings.getF32("RenderGamma"); mVideoCardMem = gSavedSettings.getS32("TextureMemory"); mFogRatio = gSavedSettings.getF32("RenderFogRatio"); + mVsyncMode = gSavedSettings.getS32("SHRenderVsyncMode"); childSetValue("fsaa", (LLSD::Integer) mFSAASamples); + childSetValue("vsync", (LLSD::Integer) mVsyncMode); + + // Depth of Field tab + mFNumber = gSavedSettings.getF32("CameraFNumber"); + mFocalLength = gSavedSettings.getF32("CameraFocalLength"); + mMaxCoF = gSavedSettings.getF32("CameraMaxCoF"); + mFocusTrans = gSavedSettings.getF32("CameraFocusTransitionTime"); + mDoFRes = gSavedSettings.getF32("CameraDoFResScale"); refreshEnabledState(); } @@ -466,19 +472,30 @@ void LLPanelDisplay::refreshEnabledState() mWindowSizeLabel->setVisible(!isFullScreen); mCtrlWindowSize->setVisible(!isFullScreen); - // disable graphics settings and exit if it's not set to custom - if(!gSavedSettings.getBOOL("RenderCustomSettings")) - { - setHiddenGraphicsState(true); - return; - } + F32 mem_multiplier = gSavedSettings.getF32("RenderTextureMemoryMultiple"); + S32Megabytes min_tex_mem = LLViewerTextureList::getMinVideoRamSetting(); + S32Megabytes max_tex_mem = LLViewerTextureList::getMaxVideoRamSetting(false, mem_multiplier); - // otherwise turn them all on and selectively turn off others - else + // Hardware tab + getChild("GrapicsCardTextureMemory")->setMinValue(min_tex_mem.value()); + getChild("GrapicsCardTextureMemory")->setMaxValue(max_tex_mem.value()); + + if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderVBOEnable") || + !gGLManager.mHasVertexBufferObject) { - setHiddenGraphicsState(false); + mVBO->setEnabled(false); + mVBO->setValue(false); } + static LLCachedControl wlatmos("WindLightUseAtmosShaders",false); + // if no windlight shaders, enable gamma, and fog distance + getChildView("gamma")->setEnabled(!wlatmos); + getChildView("fog")->setEnabled(!wlatmos); + getChildView("note")->setVisible(wlatmos); + + // disable graphics settings and exit if it's not set to custom + if (!gSavedSettings.getBOOL("RenderCustomSettings")) return; + // Reflections BOOL reflections = gSavedSettings.getBOOL("VertexShaderEnable") && gGLManager.mHasCubeMap @@ -487,27 +504,16 @@ void LLPanelDisplay::refreshEnabledState() // Bump & Shiny bool bumpshiny = gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps && LLFeatureManager::getInstance()->isFeatureAvailable("RenderObjectBump"); - mCtrlBumpShiny->setEnabled(bumpshiny ? TRUE : FALSE); + mCtrlBumpShiny->setEnabled(bumpshiny); - if (gSavedSettings.getBOOL("VertexShaderEnable") == FALSE || - gSavedSettings.getBOOL("RenderAvatarVP") == FALSE) - { - mCtrlAvatarCloth->setEnabled(false); - } - else - { - mCtrlAvatarCloth->setEnabled(true); - } + mCtrlAvatarCloth->setEnabled(gSavedSettings.getBOOL("VertexShaderEnable") && gSavedSettings.getBOOL("RenderAvatarVP")); - static LLCachedControl wlatmos("WindLightUseAtmosShaders",false); //I actually recommend RenderUseFBO:FALSE for ati users when not using deferred, so RenderUseFBO shouldn't control visibility of the element. // Instead, gGLManager.mHasFramebufferObject seems better as it is determined by hardware and not current user settings. -Shyotl //Enabling deferred will force RenderUseFBO to TRUE. - BOOL can_defer = gGLManager.mHasFramebufferObject && - LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") && //Ensure it's enabled in the gpu feature table - LLFeatureManager::getInstance()->isFeatureAvailable("RenderAvatarVP") && //Hardware Skinning. Deferred forces RenderAvatarVP to true - LLFeatureManager::getInstance()->isFeatureAvailable("VertexShaderEnable") && gSavedSettings.getBOOL("VertexShaderEnable") && //Basic Shaders - LLFeatureManager::getInstance()->isFeatureAvailable("WindLightUseAtmosShaders") && wlatmos; //Atmospheric Shaders + BOOL can_defer = LLPipeline::isRenderDeferredCapable() && + gSavedSettings.getBOOL("VertexShaderEnable") && //Basic Shaders + wlatmos; //Atmospheric Shaders mCtrlDeferred->setEnabled(can_defer); @@ -516,9 +522,6 @@ void LLPanelDisplay::refreshEnabledState() mCtrlAmbientOcc->setEnabled(can_defer && render_deferred); mCtrlDeferredDoF->setEnabled(can_defer && render_deferred); - // Disable max non-impostors slider if avatar impostors are off - mCtrlNonImpostors->setEnabled(gSavedSettings.getBOOL("RenderUseImpostors")); - // Vertex Shaders // mCtrlShaderEnable->setEnabled(LLFeatureManager::getInstance()->isFeatureAvailable("VertexShaderEnable")); // [RLVa:KB] - Checked: 2009-07-10 (RLVa-1.0.0g) | Modified: RLVa-0.2.0a @@ -547,61 +550,44 @@ void LLPanelDisplay::refreshEnabledState() mCtrlWindLight->setEnabled(fCtrlWindLightEnable && (!gRlvHandler.hasBehaviour(RLV_BHVR_SETENV) || !mWindLight)); // [/RLVa:KB] - // turn off sky detail if atmospherics isn't on - mCtrlSkyFactor->setEnabled(wlatmos); - mSkyFactorText->setEnabled(wlatmos); - // Avatar Mode and FBO if (render_deferred && wlatmos && shaders) { - childSetEnabled("fbo", false); - childSetValue("fbo", true); + getChildView("fbo")->setEnabled(false); + //getChildView("fbo")->setValue(true); mCtrlAvatarVP->setEnabled(false); - gSavedSettings.setBOOL("RenderAvatarVP", true); - } - else if (!shaders) - { - childSetEnabled("fbo", gGLManager.mHasFramebufferObject); - mCtrlAvatarVP->setEnabled(false); - gSavedSettings.setBOOL("RenderAvatarVP", false); + //gSavedSettings.setBOOL("RenderAvatarVP", true); } else { - childSetEnabled("fbo", gGLManager.mHasFramebufferObject); - mCtrlAvatarVP->setEnabled(true); + getChildView("fbo")->setEnabled(gGLManager.mHasFramebufferObject); + //getChildView("fbo")->setValue(gSavedSettings.getBOOL("RenderUseFBO")); + mCtrlAvatarVP->setEnabled(shaders); + //if (!shaders) gSavedSettings.setBOOL("RenderAvatarVP", false); } - // Hardware tab - S32 min_tex_mem = LLViewerTextureList::getMinVideoRamSetting(); - S32 max_tex_mem = LLViewerTextureList::getMaxVideoRamSetting(); - childSetMinValue("GrapicsCardTextureMemory", min_tex_mem); - childSetMaxValue("GrapicsCardTextureMemory", max_tex_mem); - - if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderVBOEnable") || - !gGLManager.mHasVertexBufferObject) - { - mVBO->setEnabled(false); - //Streaming VBOs -Shyotl - mVBOStream->setEnabled(false); - } - else - { - mVBOStream->setEnabled(gSavedSettings.getBOOL("RenderVBOEnable")); - } - - // if no windlight shaders, enable gamma, and fog distance - childSetEnabled("gamma",!wlatmos); - childSetEnabled("fog", !wlatmos); - childSetVisible("note", wlatmos); - // now turn off any features that are unavailable disableUnavailableSettings(); } void LLPanelDisplay::disableUnavailableSettings() { + // disabled terrain scale + if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderTerrainScale")) + { + mCtrlTerrainScale->setEnabled(false); + mCtrlTerrainScale->setValue(false); + } + // disabled impostors + if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderUseImpostors")) + { + mCtrlAvatarImpostors->setEnabled(false); + mCtrlAvatarImpostors->setValue(false); + } + // if vertex shaders off, disable all shader related products - if(!LLFeatureManager::getInstance()->isFeatureAvailable("VertexShaderEnable")) + // Singu Note: Returns early this, place all unrelated checks above now. + if (!LLFeatureManager::getInstance()->isFeatureAvailable("VertexShaderEnable")) { mCtrlShaderEnable->setEnabled(FALSE); mCtrlShaderEnable->setValue(FALSE); @@ -626,6 +612,7 @@ void LLPanelDisplay::disableUnavailableSettings() mCtrlDeferredDoF->setValue(FALSE); mCtrlShadowDetail->setEnabled(FALSE); mCtrlShadowDetail->setValue(FALSE); + return; } // disabled windlight @@ -642,13 +629,6 @@ void LLPanelDisplay::disableUnavailableSettings() mCtrlReflectionDetail->setValue(FALSE); } - // disabled terrain scale - if(!LLFeatureManager::getInstance()->isFeatureAvailable("RenderTerrainScale")) - { - mCtrlTerrainScale->setEnabled(false); - mCtrlTerrainScale->setValue(false); - } - // disabled av if(!LLFeatureManager::getInstance()->isFeatureAvailable("RenderAvatarVP")) { @@ -659,18 +639,11 @@ void LLPanelDisplay::disableUnavailableSettings() mCtrlAvatarCloth->setValue(FALSE); } // disabled cloth - if(!LLFeatureManager::getInstance()->isFeatureAvailable("RenderAvatarCloth")) + else if(!LLFeatureManager::getInstance()->isFeatureAvailable("RenderAvatarCloth")) { mCtrlAvatarCloth->setEnabled(FALSE); mCtrlAvatarCloth->setValue(FALSE); } - // disabled impostors - if(!LLFeatureManager::getInstance()->isFeatureAvailable("RenderUseImpostors")) - { - mCtrlAvatarImpostors->setEnabled(FALSE); - mCtrlAvatarImpostors->setValue(FALSE); - mCtrlNonImpostors->setEnabled(FALSE); - } // disabled deferred if(!LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred")) { @@ -686,119 +659,6 @@ void LLPanelDisplay::disableUnavailableSettings() } -void LLPanelDisplay::setHiddenGraphicsState(bool isHidden) -{ - // quick check - //llassert(mGraphicsBorder != NULL); - - llassert(mCtrlDrawDistance != NULL); - llassert(mCtrlLODFactor != NULL); - llassert(mCtrlFlexFactor != NULL); - llassert(mCtrlTreeFactor != NULL); - llassert(mCtrlAvatarFactor != NULL); - llassert(mCtrlTerrainFactor != NULL); - llassert(mCtrlSkyFactor != NULL); - llassert(mCtrlMaxParticle != NULL); - llassert(mCtrlPostProcess != NULL); - - llassert(mLODFactorText != NULL); - llassert(mFlexFactorText != NULL); - llassert(mTreeFactorText != NULL); - llassert(mAvatarFactorText != NULL); - llassert(mTerrainFactorText != NULL); - llassert(mSkyFactorText != NULL); - llassert(mPostProcessText != NULL); - - llassert(mCtrlTransparentWater != NULL); - llassert(mCtrlBumpShiny != NULL); - llassert(mCtrlWindLight != NULL); - llassert(mCtrlAvatarVP != NULL); - llassert(mCtrlShaderEnable != NULL); - llassert(mCtrlAvatarImpostors != NULL); - llassert(mCtrlNonImpostors != NULL); - llassert(mCtrlAvatarCloth != NULL); - llassert(mCtrlLightingDetail2 != NULL); - llassert(mCtrlAmbientOcc != NULL); - - llassert(mRadioTerrainDetail != NULL); - llassert(mCtrlReflectionDetail != NULL); - llassert(mCtrlTerrainScale != NULL); - - llassert(mMeshDetailText != NULL); - llassert(mShaderText != NULL); - llassert(mReflectionText != NULL); - llassert(mTerrainScaleText != NULL); - llassert(mAvatarText != NULL); - llassert(mTerrainText != NULL); - llassert(mDrawDistanceMeterText1 != NULL); - llassert(mDrawDistanceMeterText2 != NULL); - - // enable/disable the states - //mGraphicsBorder->setVisible(!isHidden); - /* - LLColor4 light(.45098f, .51765f, .6078f, 1.0f); - LLColor4 dark(.10196f, .10196f, .10196f, 1.0f); - b ? mGraphicsBorder->setColors(dark, light) : mGraphicsBorder->setColors(dark, dark); - */ - - mCtrlDrawDistance->setVisible(!isHidden); - mCtrlLODFactor->setVisible(!isHidden); - mCtrlFlexFactor->setVisible(!isHidden); - mCtrlTreeFactor->setVisible(!isHidden); - mCtrlAvatarFactor->setVisible(!isHidden); - mCtrlAvatarPhysicsFactor->setVisible(!isHidden); - mCtrlTerrainFactor->setVisible(!isHidden); - mCtrlSkyFactor->setVisible(!isHidden); - mCtrlMaxParticle->setVisible(!isHidden); - mCtrlPostProcess->setVisible(!isHidden); - - mLODFactorText->setVisible(!isHidden); - mFlexFactorText->setVisible(!isHidden); - mTreeFactorText->setVisible(!isHidden); - mAvatarFactorText->setVisible(!isHidden); - mAvatarPhysicsFactorText->setVisible(!isHidden); - mTerrainFactorText->setVisible(!isHidden); - mSkyFactorText->setVisible(!isHidden); - mPostProcessText->setVisible(!isHidden); - - mCtrlTransparentWater->setVisible(!isHidden); - mCtrlBumpShiny->setVisible(!isHidden); - mCtrlWindLight->setVisible(!isHidden); - mCtrlAvatarVP->setVisible(!isHidden); - mCtrlShaderEnable->setVisible(!isHidden); - mCtrlAvatarImpostors->setVisible(!isHidden); - mCtrlNonImpostors->setVisible(!isHidden); - mCtrlAvatarCloth->setVisible(!isHidden); - mCtrlLightingDetail2->setVisible(!isHidden); - mCtrlAmbientOcc->setVisible(!isHidden); - - mRadioTerrainDetail->setVisible(!isHidden); - mCtrlReflectionDetail->setVisible(!isHidden); - mCtrlTerrainScale->setVisible(!isHidden); - - mCtrlDeferred->setVisible(!isHidden); - mCtrlDeferredDoF->setVisible(!isHidden); - mCtrlShadowDetail->setVisible(!isHidden); - - // text boxes - mShaderText->setVisible(!isHidden); - mReflectionText->setVisible(!isHidden); - mAvatarText->setVisible(!isHidden); - mTerrainText->setVisible(!isHidden); - mDrawDistanceMeterText1->setVisible(!isHidden); - mDrawDistanceMeterText2->setVisible(!isHidden); - mShadowDetailText->setVisible(!isHidden); - mTerrainScaleText->setVisible(!isHidden); - - // hide one meter text if we're making things visible - if(!isHidden) - { - updateMeterText(); - } - - mMeshDetailText->setVisible(!isHidden); -} - void LLPanelDisplay::cancel() { gSavedSettings.setBOOL("FullScreenAutoDetectAspectRatio", mFSAutoDetectAspect); @@ -816,6 +676,7 @@ void LLPanelDisplay::cancel() gSavedSettings.setBOOL("RenderAvatarVP", mAvatarVP); gSavedSettings.setBOOL("RenderDeferred", mDeferred); gSavedSettings.setBOOL("RenderDepthOfField", mDeferredDoF); + gSavedSettings.setBOOL("RenderDeferredSSAO", mDeferredSSAO); gSavedSettings.setS32("RenderReflectionDetail", mReflectionDetail); gSavedSettings.setS32("RenderShadowDetail", mShadowDetail); @@ -846,16 +707,39 @@ void LLPanelDisplay::cancel() gSavedSettings.setF32("RenderGamma", mGamma); gSavedSettings.setS32("TextureMemory", mVideoCardMem); gSavedSettings.setF32("RenderFogRatio", mFogRatio); + gSavedSettings.setS32("SHRenderVsyncMode", mVsyncMode); + + // Depth of Field tab + gSavedSettings.setF32("CameraFNumber", mFNumber); + gSavedSettings.setF32("CameraFocalLength", mFocalLength); + gSavedSettings.setF32("CameraMaxCoF", mMaxCoF); + gSavedSettings.setF32("CameraFocusTransitionTime", mFocusTrans); + gSavedSettings.setF32("CameraDoFResScale", mDoFRes); } void LLPanelDisplay::apply() { - U32 fsaa_value = childGetValue("fsaa").asInteger(); - bool apply_fsaa_change = !gSavedSettings.getBOOL("RenderUseFBO") && (mFSAASamples != fsaa_value); - gSavedSettings.setU32("RenderFSAASamples", fsaa_value); + bool can_defer = LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred"); + + S32 vsync_value = childGetValue("vsync").asInteger(); + bool fbo_value = childGetValue("fbo").asBoolean() || (can_defer && mCtrlDeferred->getValue().asBoolean()); + bool fbo_prior_value = mUseFBO || (can_defer && mDeferred ); + U8 fsaa_value = fbo_value ? 0 : childGetValue("fsaa").asInteger(); + U8 fsaa_prior_value = fbo_prior_value ? 0 : mFSAASamples; + LLWindow* window = gViewerWindow->getWindow(); + + if(vsync_value == -1 && !gGLManager.mHasAdaptiveVsync) + vsync_value = 0; + + bool apply_fsaa_change = fsaa_value != fsaa_prior_value; + + bool apply_vsync_change = vsync_value != mVsyncMode; + + gSavedSettings.setU32("RenderFSAASamples", childGetValue("fsaa").asInteger()); + gSavedSettings.setS32("SHRenderVsyncMode", vsync_value); applyResolution(); - + // Only set window size if we're not in fullscreen mode if (mCtrlWindowed->get()) { @@ -865,47 +749,31 @@ void LLPanelDisplay::apply() // Hardware tab //Still do a bit of voodoo here. V2 forces restart to change FSAA with FBOs off. //Let's not do that, and instead do pre-V2 FSAA change handling for that particular case - if(apply_fsaa_change) + if(apply_fsaa_change || apply_vsync_change) { bool logged_in = (LLStartUp::getStartupState() >= STATE_STARTED); - LLWindow* window = gViewerWindow->getWindow(); LLCoordScreen size; window->getSize(&size); - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); + LLGLStateValidator::checkStates(); + LLGLStateValidator::checkTextureChannels(); gViewerWindow->changeDisplaySettings(window->getFullscreen(), size, - gSavedSettings.getBOOL("DisableVerticalSync"), + vsync_value, logged_in); - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); + LLGLStateValidator::checkStates(); + LLGLStateValidator::checkTextureChannels(); } } -void LLPanelDisplay::onChangeQuality(LLUICtrl* caller) +void LLPanelDisplay::onChangeQuality(LLUICtrl* ctrl) { - LLSlider* sldr = dynamic_cast(caller); - - if(sldr == NULL) - { - return; - } - - U32 set = (U32)sldr->getValueF32(); - LLFeatureManager::getInstance()->setGraphicsLevel(set, true); - - LLFloaterPreference::refreshEnabledGraphics(); + LLFeatureManager::getInstance()->setGraphicsLevel(ctrl->getValue(), true); + refreshEnabledState(); refresh(); } -void LLPanelDisplay::onChangeCustom() -{ - LLFloaterPreference::refreshEnabledGraphics(); -} - void LLPanelDisplay::applyResolution() { - gGL.flush(); char aspect_ratio_text[ASPECT_RATIO_STR_LEN]; /*Flawfinder: ignore*/ if (mCtrlAspectRatio->getCurrentIndex() == -1) @@ -1030,16 +898,6 @@ void LLPanelDisplay::onCommitAutoDetectAspect(const LLSD& value) } } -void LLPanelDisplay::onKeystrokeAspectRatio() -{ - mCtrlAutoDetectAspect->set(FALSE); -} - -void LLPanelDisplay::onSelectAspectRatio() -{ - mCtrlAutoDetectAspect->set(FALSE); -} - //static void LLPanelDisplay::fractionFromDecimal(F32 decimal_val, S32& numerator, S32& denominator) { @@ -1049,63 +907,45 @@ void LLPanelDisplay::fractionFromDecimal(F32 decimal_val, S32& numerator, S32& d { if (fmodf((decimal_val * test_denominator) + 0.01f, 1.f) < 0.02f) { - numerator = llround(decimal_val * test_denominator); - denominator = llround(test_denominator); + numerator = ll_round(decimal_val * test_denominator); + denominator = ll_round(test_denominator); break; } } } -void LLPanelDisplay::onVertexShaderEnable() -{ - LLFloaterPreference::refreshEnabledGraphics(); -} - -//static void LLPanelDisplay::setHardwareDefaults() { LLFeatureManager::getInstance()->applyRecommendedSettings(); - LLControlVariable* controlp = gSavedSettings.getControl("RenderAvatarMaxVisible"); - if (controlp) + if (LLControlVariable* controlp = gSavedSettings.getControl("RenderAvatarMaxVisible")) { controlp->resetToDefault(true); } - LLFloaterPreference::refreshEnabledGraphics(); + refreshEnabledState(); } -//static -void LLPanelDisplay::updateSliderText(LLUICtrl* ctrl, LLTextBox* text_box) +void updateSliderText(LLSliderCtrl* slider, LLTextBox* text_box) { - // get our UI widgets - LLSliderCtrl* slider = dynamic_cast(ctrl); - if(text_box == NULL || slider == NULL) - { - return; - } - - //Hack to display 'Off' for avatar physics slider. - if(slider->getName() == "AvatarPhysicsDetail" && !slider->getValueF32()) - { - text_box->setText(std::string("Off")); - return; - } - // get range and points when text should change - F32 range = slider->getMaxValue() - slider->getMinValue(); - llassert(range > 0); - F32 midPoint = slider->getMinValue() + range / 3.0f; - F32 highPoint = slider->getMinValue() + (2.0f * range / 3.0f); + const F32 value = slider->getValue().asFloat(); + const F32 min_val = slider->getMinValue(); + const F32 max_val = slider->getMaxValue(); + const F32 range = (max_val - min_val)/3.f; // choose the right text - if(slider->getValueF32() < midPoint) + if (value < min_val + range) { - text_box->setText(std::string("Low")); + //Hack to display 'Off' for avatar physics slider. + if (!value && slider->getName() == "AvatarPhysicsDetail") + text_box->setText(std::string("Off")); + else + text_box->setText(std::string("Low")); } - else if (slider->getValueF32() < highPoint) + else if (value < min_val + 2.0f * range) { text_box->setText(std::string("Mid")); } - else if(slider->getValueF32() < slider->getMaxValue()) + else if (value < max_val) { text_box->setText(std::string("High")); } @@ -1115,14 +955,3 @@ void LLPanelDisplay::updateSliderText(LLUICtrl* ctrl, LLTextBox* text_box) } } -void LLPanelDisplay::updateMeterText() -{ - // toggle the two text boxes based on whether we have 2 or 3 digits - F32 val = mCtrlDrawDistance->getValueF32(); - bool two_digits = val < 100; - mDrawDistanceMeterText1->setVisible(two_digits); - mDrawDistanceMeterText2->setVisible(!two_digits); -} - - - diff --git a/indra/newview/llpaneldisplay.h b/indra/newview/llpaneldisplay.h index 9b39ee5551..3c91d665d1 100644 --- a/indra/newview/llpaneldisplay.h +++ b/indra/newview/llpaneldisplay.h @@ -70,7 +70,6 @@ class LLPanelDisplay void refresh(); // Refresh enable/disable void refreshEnabledState(); void disableUnavailableSettings(); - void setHiddenGraphicsState(bool isHidden); void apply(); // Apply the changed values. void applyResolution(); void applyWindowSize(); @@ -92,22 +91,6 @@ class LLPanelDisplay LLSliderCtrl *mCtrlSliderQuality; LLCheckBoxCtrl *mCtrlCustomSettings; - // performance sliders and boxes - //LLViewBorder *mGraphicsBorder; - - LLSliderCtrl *mCtrlDrawDistance; // the draw distance slider - LLSliderCtrl *mCtrlLODFactor; // LOD for volume objects - LLSliderCtrl *mCtrlFlexFactor; // Timeslice for flexible objects - LLSliderCtrl *mCtrlTreeFactor; // Control tree cutoff distance - LLSliderCtrl *mCtrlAvatarFactor; // LOD for avatars - LLSliderCtrl *mCtrlAvatarPhysicsFactor; // Physics LOD for avatars - LLSliderCtrl *mCtrlTerrainFactor; // LOD for terrain - LLSliderCtrl *mCtrlSkyFactor; // LOD for terrain - LLSliderCtrl *mCtrlMaxParticle; // Max Particle - LLSliderCtrl *mCtrlPostProcess; // Max Particle - LLSliderCtrl *mCtrlNonImpostors; // Max non-impostors - - LLCheckBoxCtrl *mCtrlTransparentWater; LLCheckBoxCtrl *mCtrlBumpShiny; LLCheckBoxCtrl *mCtrlWindLight; LLCheckBoxCtrl *mCtrlAvatarVP; @@ -119,7 +102,6 @@ class LLPanelDisplay LLComboBox *mCtrlTerrainScale; LLCheckBoxCtrl *mCtrlAvatarImpostors; LLCheckBoxCtrl *mCtrlAvatarCloth; - LLCheckBoxCtrl *mCtrlLightingDetail2; LLCheckBoxCtrl *mCtrlAmbientOcc; LLRadioGroup *mRadioTerrainDetail; @@ -127,27 +109,7 @@ class LLPanelDisplay LLTextBox *mDisplayResLabel; LLTextBox *mWindowSizeLabel; - LLTextBox *mShaderText; - LLTextBox *mReflectionText; - LLTextBox *mAvatarText; - LLTextBox *mTerrainText; - LLTextBox *mDrawDistanceMeterText1; - LLTextBox *mDrawDistanceMeterText2; - - LLTextBox *mMeshDetailText; - LLTextBox *mLODFactorText; - LLTextBox *mFlexFactorText; - LLTextBox *mTreeFactorText; - LLTextBox *mAvatarFactorText; - LLTextBox *mAvatarPhysicsFactorText; - LLTextBox *mTerrainFactorText; - LLTextBox *mSkyFactorText; - LLTextBox *mPostProcessText; - LLTextBox *mShadowDetailText; - LLTextBox *mTerrainScaleText; - LLCheckBoxCtrl *mVBO; - LLCheckBoxCtrl *mVBOStream; BOOL mFSAutoDetectAspect; F32 mAspectRatio; @@ -163,6 +125,7 @@ class LLPanelDisplay BOOL mWindLight; BOOL mDeferred; BOOL mDeferredDoF; + bool mDeferredSSAO; BOOL mAvatarVP; S32 mReflectionDetail; @@ -194,25 +157,24 @@ class LLPanelDisplay F32 mGamma; S32 mVideoCardMem; F32 mFogRatio; + S32 mVsyncMode; + + // Depth of Field tab + F32 mFNumber; + F32 mFocalLength; + F32 mMaxCoF; + F32 mFocusTrans; + F32 mDoFRes; // if the quality radio buttons are changed void onChangeQuality(LLUICtrl* caller); - // if the custom settings box is clicked - static void onChangeCustom(); - void onCommitAutoDetectAspect(const LLSD& value); - void onKeystrokeAspectRatio(); - void onSelectAspectRatio(); void onCommitWindowedMode(); - static void updateSliderText(LLUICtrl* ctrl, LLTextBox* text_box); void updateMeterText(); /// callback for defaults - static void setHardwareDefaults(); - - // callback for when client turns on shaders - static void onVertexShaderEnable(); + void setHardwareDefaults(); // helper function static void fractionFromDecimal(F32 decimal_val, S32& numerator, S32& denominator); diff --git a/indra/newview/llpaneleditwearable.cpp b/indra/newview/llpaneleditwearable.cpp index 8e4f890fff..e179b971ee 100644 --- a/indra/newview/llpaneleditwearable.cpp +++ b/indra/newview/llpaneleditwearable.cpp @@ -28,6 +28,7 @@ #include "lfsimfeaturehandler.h" #include "llpaneleditwearable.h" +#include "lllocaltextureobject.h" #include "llpanel.h" #include "llviewerwearable.h" #include "lluictrl.h" @@ -64,48 +65,53 @@ #include "llwearablelist.h" #include "llinventoryicon.h" +#ifndef BOOST_FUNCTION_HPP_INCLUDED #include +#define BOOST_FUNCTION_HPP_INCLUDED +#endif // subparts of the UI for focus, camera position, etc. -enum ESubpart { - SUBPART_SHAPE_HEAD = 1, // avoid 0 - SUBPART_SHAPE_EYES, - SUBPART_SHAPE_EARS, - SUBPART_SHAPE_NOSE, - SUBPART_SHAPE_MOUTH, - SUBPART_SHAPE_CHIN, - SUBPART_SHAPE_TORSO, - SUBPART_SHAPE_LEGS, - SUBPART_SHAPE_WHOLE, - SUBPART_SHAPE_DETAIL, - SUBPART_SKIN_COLOR, - SUBPART_SKIN_FACEDETAIL, - SUBPART_SKIN_MAKEUP, - SUBPART_SKIN_BODYDETAIL, - SUBPART_HAIR_COLOR, - SUBPART_HAIR_STYLE, - SUBPART_HAIR_EYEBROWS, - SUBPART_HAIR_FACIAL, - SUBPART_EYES, - SUBPART_SHIRT, - SUBPART_PANTS, - SUBPART_SHOES, - SUBPART_SOCKS, - SUBPART_JACKET, - SUBPART_GLOVES, - SUBPART_UNDERSHIRT, - SUBPART_UNDERPANTS, - SUBPART_SKIRT, - SUBPART_ALPHA, - SUBPART_TATTOO, - SUBPART_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, - }; +enum ESubpart +{ + SUBPART_SHAPE_HEAD = 1, // avoid 0 + SUBPART_SHAPE_EYES, + SUBPART_SHAPE_EARS, + SUBPART_SHAPE_NOSE, + SUBPART_SHAPE_MOUTH, + SUBPART_SHAPE_CHIN, + SUBPART_SHAPE_TORSO, + SUBPART_SHAPE_LEGS, + SUBPART_SHAPE_WHOLE, + SUBPART_SHAPE_DETAIL, + SUBPART_SKIN_COLOR, + SUBPART_SKIN_FACEDETAIL, + SUBPART_SKIN_MAKEUP, + SUBPART_SKIN_BODYDETAIL, + SUBPART_HAIR_COLOR, + SUBPART_HAIR_STYLE, + SUBPART_HAIR_EYEBROWS, + SUBPART_HAIR_FACIAL, + SUBPART_EYES, + SUBPART_SHIRT, + SUBPART_PANTS, + SUBPART_SHOES, + SUBPART_SOCKS, + SUBPART_JACKET, + SUBPART_GLOVES, + SUBPART_UNDERSHIRT, + SUBPART_UNDERPANTS, + SUBPART_SKIRT, + SUBPART_ALPHA, + SUBPART_TATTOO, + SUBPART_UNIVERSAL, + SUBPART_PHYSICS_BREASTS_UPDOWN, + SUBPART_PHYSICS_BREASTS_INOUT, + SUBPART_PHYSICS_BREASTS_LEFTRIGHT, + SUBPART_PHYSICS_BELLY_UPDOWN, + SUBPART_PHYSICS_BUTT_UPDOWN, + SUBPART_PHYSICS_BUTT_LEFTRIGHT, + SUBPART_PHYSICS_ADVANCED, +}; using namespace LLAvatarAppearanceDefines; @@ -115,99 +121,99 @@ typedef std::vector subpart_vec_t; class LLEditWearableDictionary : public LLSingleton { - //-------------------------------------------------------------------- - // Constructors and Destructors - //-------------------------------------------------------------------- + //-------------------------------------------------------------------- + // Constructors and Destructors + //-------------------------------------------------------------------- public: - LLEditWearableDictionary(); - virtual ~LLEditWearableDictionary(); - - //-------------------------------------------------------------------- - // Wearable Types - //-------------------------------------------------------------------- + LLEditWearableDictionary(); + virtual ~LLEditWearableDictionary(); + + //-------------------------------------------------------------------- + // Wearable Types + //-------------------------------------------------------------------- public: - struct WearableEntry : public LLDictionaryEntry - { - WearableEntry(LLWearableType::EType type, - const std::string &title, - U8 num_color_swatches, // number of 'color_swatches' - U8 num_texture_pickers, // number of 'texture_pickers' - U8 num_subparts, ... ); // number of subparts followed by a list of ETextureIndex and ESubparts - - - const LLWearableType::EType mWearableType; - subpart_vec_t mSubparts; - texture_vec_t mColorSwatchCtrls; - texture_vec_t mTextureCtrls; - }; - - struct Wearables : public LLDictionary - { - Wearables(); - } mWearables; - - const WearableEntry* getWearable(LLWearableType::EType type) const { return mWearables.lookup(type); } - - //-------------------------------------------------------------------- - // Subparts - //-------------------------------------------------------------------- + struct WearableEntry : public LLDictionaryEntry + { + WearableEntry(LLWearableType::EType type, + const std::string &title, + U8 num_color_swatches, // number of 'color_swatches' + U8 num_texture_pickers, // number of 'texture_pickers' + unsigned int num_subparts, ... ); // number of subparts followed by a list of ETextureIndex and ESubparts + + + const LLWearableType::EType mWearableType; + subpart_vec_t mSubparts; + texture_vec_t mColorSwatchCtrls; + texture_vec_t mTextureCtrls; + }; + + struct Wearables : public LLDictionary + { + Wearables(); + } mWearables; + + const WearableEntry* getWearable(LLWearableType::EType type) const { return mWearables.lookup(type); } + + //-------------------------------------------------------------------- + // Subparts + //-------------------------------------------------------------------- public: - struct SubpartEntry : public LLDictionaryEntry - { - SubpartEntry(ESubpart part, - const std::string &joint, - const std::string &edit_group, - const std::string &button_name, - const LLVector3d &target_offset, - const LLVector3d &camera_offset, - const ESex &sex); + struct SubpartEntry : public LLDictionaryEntry + { + SubpartEntry(ESubpart part, + const std::string &joint, + const std::string &edit_group, + const std::string &button_name, + const LLVector3d &target_offset, + const LLVector3d &camera_offset, + const ESex &sex); + + + ESubpart mSubpart; + std::string mTargetJoint; + std::string mEditGroup; + std::string mButtonName; + LLVector3d mTargetOffset; + LLVector3d mCameraOffset; + ESex mSex; + }; + + struct Subparts : public LLDictionary + { + Subparts(); + } mSubparts; - - ESubpart mSubpart; - std::string mTargetJoint; - std::string mEditGroup; - std::string mButtonName; - LLVector3d mTargetOffset; - LLVector3d mCameraOffset; - ESex mSex; - }; - - struct Subparts : public LLDictionary - { - Subparts(); - } mSubparts; - - const SubpartEntry* getSubpart(ESubpart subpart) const { return mSubparts.lookup(subpart); } - - //-------------------------------------------------------------------- - // Picker Control Entries - //-------------------------------------------------------------------- + const SubpartEntry* getSubpart(ESubpart subpart) const { return mSubparts.lookup(subpart); } + + //-------------------------------------------------------------------- + // Picker Control Entries + //-------------------------------------------------------------------- public: - struct PickerControlEntry : public LLDictionaryEntry - { - PickerControlEntry(ETextureIndex tex_index, - const std::string name, - const LLUUID default_image_id = LLUUID::null, - const bool allow_no_texture = false - ); - ETextureIndex mTextureIndex; - const std::string mControlName; - const LLUUID mDefaultImageId; - const bool mAllowNoTexture; - }; - - struct ColorSwatchCtrls : public LLDictionary - { - ColorSwatchCtrls(); - } mColorSwatchCtrls; - - struct TextureCtrls : public LLDictionary - { - TextureCtrls(); - } mTextureCtrls; - - const PickerControlEntry* getTexturePicker(ETextureIndex index) const { return mTextureCtrls.lookup(index); } - const PickerControlEntry* getColorSwatch(ETextureIndex index) const { return mColorSwatchCtrls.lookup(index); } + struct PickerControlEntry : public LLDictionaryEntry + { + PickerControlEntry(ETextureIndex tex_index, + const std::string name, + const LLUUID default_image_id = LLUUID::null, + const bool allow_no_texture = false + ); + ETextureIndex mTextureIndex; + const std::string mControlName; + const LLUUID mDefaultImageId; + const bool mAllowNoTexture; + }; + + struct ColorSwatchCtrls : public LLDictionary + { + ColorSwatchCtrls(); + } mColorSwatchCtrls; + + struct TextureCtrls : public LLDictionary + { + TextureCtrls(); + } mTextureCtrls; + + const PickerControlEntry* getTexturePicker(ETextureIndex index) const { return mTextureCtrls.lookup(index); } + const PickerControlEntry* getColorSwatch(ETextureIndex index) const { return mColorSwatchCtrls.lookup(index); } }; LLEditWearableDictionary::LLEditWearableDictionary() @@ -222,55 +228,56 @@ LLEditWearableDictionary::~LLEditWearableDictionary() LLEditWearableDictionary::Wearables::Wearables() { - // note the subpart that is listed first is treated as "default", regardless of what order is in enum. - // Please match the order presented in XUI. -Nyx - // this will affect what camera angle is shown when first editing a wearable - addEntry(LLWearableType::WT_SHAPE, new WearableEntry(LLWearableType::WT_SHAPE,"edit_shape_title",0,0,9, SUBPART_SHAPE_WHOLE, SUBPART_SHAPE_HEAD, SUBPART_SHAPE_EYES, SUBPART_SHAPE_EARS, SUBPART_SHAPE_NOSE, SUBPART_SHAPE_MOUTH, SUBPART_SHAPE_CHIN, SUBPART_SHAPE_TORSO, SUBPART_SHAPE_LEGS)); - addEntry(LLWearableType::WT_SKIN, new WearableEntry(LLWearableType::WT_SKIN,"edit_skin_title",0,3,4, TEX_HEAD_BODYPAINT, TEX_UPPER_BODYPAINT, TEX_LOWER_BODYPAINT, SUBPART_SKIN_COLOR, SUBPART_SKIN_FACEDETAIL, SUBPART_SKIN_MAKEUP, SUBPART_SKIN_BODYDETAIL)); - addEntry(LLWearableType::WT_HAIR, new WearableEntry(LLWearableType::WT_HAIR,"edit_hair_title",0,1,4, TEX_HAIR, SUBPART_HAIR_COLOR, SUBPART_HAIR_STYLE, SUBPART_HAIR_EYEBROWS, SUBPART_HAIR_FACIAL)); - addEntry(LLWearableType::WT_EYES, new WearableEntry(LLWearableType::WT_EYES,"edit_eyes_title",0,1,1, TEX_EYES_IRIS, SUBPART_EYES)); - addEntry(LLWearableType::WT_SHIRT, new WearableEntry(LLWearableType::WT_SHIRT,"edit_shirt_title",1,1,1, TEX_UPPER_SHIRT, TEX_UPPER_SHIRT, SUBPART_SHIRT)); - addEntry(LLWearableType::WT_PANTS, new WearableEntry(LLWearableType::WT_PANTS,"edit_pants_title",1,1,1, TEX_LOWER_PANTS, TEX_LOWER_PANTS, SUBPART_PANTS)); - addEntry(LLWearableType::WT_SHOES, new WearableEntry(LLWearableType::WT_SHOES,"edit_shoes_title",1,1,1, TEX_LOWER_SHOES, TEX_LOWER_SHOES, SUBPART_SHOES)); - addEntry(LLWearableType::WT_SOCKS, new WearableEntry(LLWearableType::WT_SOCKS,"edit_socks_title",1,1,1, TEX_LOWER_SOCKS, TEX_LOWER_SOCKS, SUBPART_SOCKS)); - addEntry(LLWearableType::WT_JACKET, new WearableEntry(LLWearableType::WT_JACKET,"edit_jacket_title",1,2,1, TEX_UPPER_JACKET, TEX_UPPER_JACKET, TEX_LOWER_JACKET, SUBPART_JACKET)); - addEntry(LLWearableType::WT_GLOVES, new WearableEntry(LLWearableType::WT_GLOVES,"edit_gloves_title",1,1,1, TEX_UPPER_GLOVES, TEX_UPPER_GLOVES, SUBPART_GLOVES)); - addEntry(LLWearableType::WT_UNDERSHIRT, new WearableEntry(LLWearableType::WT_UNDERSHIRT,"edit_undershirt_title",1,1,1, TEX_UPPER_UNDERSHIRT, TEX_UPPER_UNDERSHIRT, SUBPART_UNDERSHIRT)); - addEntry(LLWearableType::WT_UNDERPANTS, new WearableEntry(LLWearableType::WT_UNDERPANTS,"edit_underpants_title",1,1,1, TEX_LOWER_UNDERPANTS, TEX_LOWER_UNDERPANTS, SUBPART_UNDERPANTS)); - addEntry(LLWearableType::WT_SKIRT, new WearableEntry(LLWearableType::WT_SKIRT,"edit_skirt_title",1,1,1, TEX_SKIRT, TEX_SKIRT, SUBPART_SKIRT)); - addEntry(LLWearableType::WT_ALPHA, new WearableEntry(LLWearableType::WT_ALPHA,"edit_alpha_title",0,5,1, TEX_LOWER_ALPHA, TEX_UPPER_ALPHA, TEX_HEAD_ALPHA, TEX_EYES_ALPHA, TEX_HAIR_ALPHA, SUBPART_ALPHA)); - addEntry(LLWearableType::WT_TATTOO, new WearableEntry(LLWearableType::WT_TATTOO,"edit_tattoo_title",1,3,1, TEX_HEAD_TATTOO, TEX_LOWER_TATTOO, TEX_UPPER_TATTOO, TEX_HEAD_TATTOO, SUBPART_TATTOO)); - addEntry(LLWearableType::WT_PHYSICS, new WearableEntry(LLWearableType::WT_PHYSICS,"edit_physics_title",0,0,7, SUBPART_PHYSICS_BREASTS_UPDOWN, SUBPART_PHYSICS_BREASTS_INOUT, SUBPART_PHYSICS_BREASTS_LEFTRIGHT, SUBPART_PHYSICS_BELLY_UPDOWN, SUBPART_PHYSICS_BUTT_UPDOWN, SUBPART_PHYSICS_BUTT_LEFTRIGHT, SUBPART_PHYSICS_ADVANCED)); + // 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",0,0,9, SUBPART_SHAPE_WHOLE, SUBPART_SHAPE_HEAD, SUBPART_SHAPE_EYES, SUBPART_SHAPE_EARS, SUBPART_SHAPE_NOSE, SUBPART_SHAPE_MOUTH, SUBPART_SHAPE_CHIN, SUBPART_SHAPE_TORSO, SUBPART_SHAPE_LEGS)); + addEntry(LLWearableType::WT_SKIN, new WearableEntry(LLWearableType::WT_SKIN,"edit_skin_title",0,3,4, TEX_HEAD_BODYPAINT, TEX_UPPER_BODYPAINT, TEX_LOWER_BODYPAINT, SUBPART_SKIN_COLOR, SUBPART_SKIN_FACEDETAIL, SUBPART_SKIN_MAKEUP, SUBPART_SKIN_BODYDETAIL)); + addEntry(LLWearableType::WT_HAIR, new WearableEntry(LLWearableType::WT_HAIR,"edit_hair_title",0,1,4, TEX_HAIR, SUBPART_HAIR_COLOR, SUBPART_HAIR_STYLE, SUBPART_HAIR_EYEBROWS, SUBPART_HAIR_FACIAL)); + addEntry(LLWearableType::WT_EYES, new WearableEntry(LLWearableType::WT_EYES,"edit_eyes_title",0,1,1, TEX_EYES_IRIS, SUBPART_EYES)); + addEntry(LLWearableType::WT_SHIRT, new WearableEntry(LLWearableType::WT_SHIRT,"edit_shirt_title",1,1,1, TEX_UPPER_SHIRT, TEX_UPPER_SHIRT, SUBPART_SHIRT)); + addEntry(LLWearableType::WT_PANTS, new WearableEntry(LLWearableType::WT_PANTS,"edit_pants_title",1,1,1, TEX_LOWER_PANTS, TEX_LOWER_PANTS, SUBPART_PANTS)); + addEntry(LLWearableType::WT_SHOES, new WearableEntry(LLWearableType::WT_SHOES,"edit_shoes_title",1,1,1, TEX_LOWER_SHOES, TEX_LOWER_SHOES, SUBPART_SHOES)); + addEntry(LLWearableType::WT_SOCKS, new WearableEntry(LLWearableType::WT_SOCKS,"edit_socks_title",1,1,1, TEX_LOWER_SOCKS, TEX_LOWER_SOCKS, SUBPART_SOCKS)); + addEntry(LLWearableType::WT_JACKET, new WearableEntry(LLWearableType::WT_JACKET,"edit_jacket_title",1,2,1, TEX_UPPER_JACKET, TEX_UPPER_JACKET, TEX_LOWER_JACKET, SUBPART_JACKET)); + addEntry(LLWearableType::WT_GLOVES, new WearableEntry(LLWearableType::WT_GLOVES,"edit_gloves_title",1,1,1, TEX_UPPER_GLOVES, TEX_UPPER_GLOVES, SUBPART_GLOVES)); + addEntry(LLWearableType::WT_UNDERSHIRT, new WearableEntry(LLWearableType::WT_UNDERSHIRT,"edit_undershirt_title",1,1,1, TEX_UPPER_UNDERSHIRT, TEX_UPPER_UNDERSHIRT, SUBPART_UNDERSHIRT)); + addEntry(LLWearableType::WT_UNDERPANTS, new WearableEntry(LLWearableType::WT_UNDERPANTS,"edit_underpants_title",1,1,1, TEX_LOWER_UNDERPANTS, TEX_LOWER_UNDERPANTS, SUBPART_UNDERPANTS)); + addEntry(LLWearableType::WT_SKIRT, new WearableEntry(LLWearableType::WT_SKIRT,"edit_skirt_title",1,1,1, TEX_SKIRT, TEX_SKIRT, SUBPART_SKIRT)); + addEntry(LLWearableType::WT_ALPHA, new WearableEntry(LLWearableType::WT_ALPHA,"edit_alpha_title",0,5,1, TEX_LOWER_ALPHA, TEX_UPPER_ALPHA, TEX_HEAD_ALPHA, TEX_EYES_ALPHA, TEX_HAIR_ALPHA, SUBPART_ALPHA)); + addEntry(LLWearableType::WT_TATTOO, new WearableEntry(LLWearableType::WT_TATTOO,"edit_tattoo_title",1,3,1, TEX_HEAD_TATTOO, TEX_LOWER_TATTOO, TEX_UPPER_TATTOO, TEX_HEAD_TATTOO, SUBPART_TATTOO)); + addEntry(LLWearableType::WT_UNIVERSAL, new WearableEntry(LLWearableType::WT_UNIVERSAL, "edit_universal_title", 1, 11, 1, TEX_HEAD_UNIVERSAL_TATTOO, 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_UNIVERSAL)); + addEntry(LLWearableType::WT_PHYSICS, new WearableEntry(LLWearableType::WT_PHYSICS,"edit_physics_title",0,0,7, SUBPART_PHYSICS_BREASTS_UPDOWN, SUBPART_PHYSICS_BREASTS_INOUT, SUBPART_PHYSICS_BREASTS_LEFTRIGHT, SUBPART_PHYSICS_BELLY_UPDOWN, SUBPART_PHYSICS_BUTT_UPDOWN, SUBPART_PHYSICS_BUTT_LEFTRIGHT, SUBPART_PHYSICS_ADVANCED)); } LLEditWearableDictionary::WearableEntry::WearableEntry(LLWearableType::EType type, - const std::string &title, - U8 num_color_swatches, - U8 num_texture_pickers, - U8 num_subparts, ... ) : - LLDictionaryEntry(title), - mWearableType(type) -{ - va_list argp; - va_start(argp, num_subparts); - - for (U8 i = 0; i < num_color_swatches; ++i) - { - ETextureIndex index = (ETextureIndex)va_arg(argp,int); - mColorSwatchCtrls.push_back(index); - } - - for (U8 i = 0; i < num_texture_pickers; ++i) - { - ETextureIndex index = (ETextureIndex)va_arg(argp,int); - mTextureCtrls.push_back(index); - } - - for (U8 i = 0; i < num_subparts; ++i) - { - ESubpart part = (ESubpart)va_arg(argp,int); - mSubparts.push_back(part); - } + const std::string &title, + U8 num_color_swatches, + U8 num_texture_pickers, + unsigned int num_subparts, ... ) : + LLDictionaryEntry(title), + mWearableType(type) +{ + va_list argp; + va_start(argp, num_subparts); + + for (U8 i = 0; i < num_color_swatches; ++i) + { + ETextureIndex index = (ETextureIndex)va_arg(argp,int); + mColorSwatchCtrls.push_back(index); + } + + for (U8 i = 0; i < num_texture_pickers; ++i) + { + ETextureIndex index = (ETextureIndex)va_arg(argp,int); + mTextureCtrls.push_back(index); + } + + for (U8 i = 0; i < num_subparts; ++i) + { + ESubpart part = (ESubpart)va_arg(argp,int); + mSubparts.push_back(part); + } } LLEditWearableDictionary::Subparts::Subparts() @@ -310,6 +317,8 @@ LLEditWearableDictionary::Subparts::Subparts() addEntry(SUBPART_UNDERPANTS, new SubpartEntry(SUBPART_UNDERPANTS, "mPelvis", "underpants",LLStringUtil::null, LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f), SEX_BOTH)); addEntry(SUBPART_ALPHA, new SubpartEntry(SUBPART_ALPHA, "mPelvis", "alpha",LLStringUtil::null, 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", LLStringUtil::null, 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", LLStringUtil::null, 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", "Breast Bounce", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-0.8f, 0.15f, 0.38),SEX_FEMALE)); addEntry(SUBPART_PHYSICS_BREASTS_INOUT, new SubpartEntry(SUBPART_PHYSICS_BREASTS_INOUT, "mTorso", "physics_breasts_inout", "Breast Cleavage", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-0.8f, 0.15f, 0.38f),SEX_FEMALE)); addEntry(SUBPART_PHYSICS_BREASTS_LEFTRIGHT, new SubpartEntry(SUBPART_PHYSICS_BREASTS_LEFTRIGHT, "mTorso", "physics_breasts_leftright", "Breast Sway", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-0.8f, 0.15f, 0.38f),SEX_FEMALE)); @@ -320,73 +329,85 @@ LLEditWearableDictionary::Subparts::Subparts() } LLEditWearableDictionary::SubpartEntry::SubpartEntry(ESubpart part, - const std::string &joint, - const std::string &edit_group, - const std::string &button_name, - const LLVector3d &target_offset, - const LLVector3d &camera_offset, - const ESex &sex) : - LLDictionaryEntry(edit_group), - mSubpart(part), - mTargetJoint(joint), - mEditGroup(edit_group), - mButtonName(button_name), - mTargetOffset(target_offset), - mCameraOffset(camera_offset), - mSex(sex) + const std::string &joint, + const std::string &edit_group, + const std::string &button_name, + const LLVector3d &target_offset, + const LLVector3d &camera_offset, + const ESex &sex) : + LLDictionaryEntry(edit_group), + mSubpart(part), + mTargetJoint(joint), + mEditGroup(edit_group), + mButtonName(button_name), + mTargetOffset(target_offset), + mCameraOffset(camera_offset), + mSex(sex) { } LLEditWearableDictionary::ColorSwatchCtrls::ColorSwatchCtrls() { - addEntry ( TEX_UPPER_SHIRT, new PickerControlEntry (TEX_UPPER_SHIRT, "Color/Tint" )); - addEntry ( TEX_LOWER_PANTS, new PickerControlEntry (TEX_LOWER_PANTS, "Color/Tint" )); - addEntry ( TEX_LOWER_SHOES, new PickerControlEntry (TEX_LOWER_SHOES, "Color/Tint" )); - addEntry ( TEX_LOWER_SOCKS, new PickerControlEntry (TEX_LOWER_SOCKS, "Color/Tint" )); - addEntry ( TEX_UPPER_JACKET, new PickerControlEntry (TEX_UPPER_JACKET, "Color/Tint" )); - addEntry ( TEX_SKIRT, new PickerControlEntry (TEX_SKIRT, "Color/Tint" )); - addEntry ( TEX_UPPER_GLOVES, new PickerControlEntry (TEX_UPPER_GLOVES, "Color/Tint" )); - addEntry ( TEX_UPPER_UNDERSHIRT, new PickerControlEntry (TEX_UPPER_UNDERSHIRT, "Color/Tint" )); - addEntry ( TEX_LOWER_UNDERPANTS, new PickerControlEntry (TEX_LOWER_UNDERPANTS, "Color/Tint" )); - addEntry ( TEX_HEAD_TATTOO, new PickerControlEntry(TEX_HEAD_TATTOO, "Color/Tint" )); + addEntry ( TEX_UPPER_SHIRT, new PickerControlEntry (TEX_UPPER_SHIRT, "Color/Tint" )); + addEntry ( TEX_LOWER_PANTS, new PickerControlEntry (TEX_LOWER_PANTS, "Color/Tint" )); + addEntry ( TEX_LOWER_SHOES, new PickerControlEntry (TEX_LOWER_SHOES, "Color/Tint" )); + addEntry ( TEX_LOWER_SOCKS, new PickerControlEntry (TEX_LOWER_SOCKS, "Color/Tint" )); + addEntry ( TEX_UPPER_JACKET, new PickerControlEntry (TEX_UPPER_JACKET, "Color/Tint" )); + addEntry ( TEX_SKIRT, new PickerControlEntry (TEX_SKIRT, "Color/Tint" )); + addEntry ( TEX_UPPER_GLOVES, new PickerControlEntry (TEX_UPPER_GLOVES, "Color/Tint" )); + addEntry ( TEX_UPPER_UNDERSHIRT, new PickerControlEntry (TEX_UPPER_UNDERSHIRT, "Color/Tint" )); + addEntry ( TEX_LOWER_UNDERPANTS, new PickerControlEntry (TEX_LOWER_UNDERPANTS, "Color/Tint" )); + addEntry ( TEX_HEAD_TATTOO, new PickerControlEntry(TEX_HEAD_TATTOO, "Color/Tint" )); + 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 Tattoos", LLUUID::null, TRUE )); - addEntry ( TEX_UPPER_BODYPAINT, new PickerControlEntry (TEX_UPPER_BODYPAINT, "Upper Tattoos", LLUUID::null, TRUE )); - addEntry ( TEX_LOWER_BODYPAINT, new PickerControlEntry (TEX_LOWER_BODYPAINT, "Lower Tattoos", LLUUID::null, TRUE )); - addEntry ( TEX_HAIR, new PickerControlEntry (TEX_HAIR, "Texture", LLUUID( gSavedSettings.getString( "UIImgDefaultHairUUID" ) ), FALSE )); - addEntry ( TEX_EYES_IRIS, new PickerControlEntry (TEX_EYES_IRIS, "Iris", LLUUID( gSavedSettings.getString( "UIImgDefaultEyesUUID" ) ), FALSE )); - addEntry ( TEX_UPPER_SHIRT, new PickerControlEntry (TEX_UPPER_SHIRT, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultShirtUUID" ) ), FALSE )); - addEntry ( TEX_LOWER_PANTS, new PickerControlEntry (TEX_LOWER_PANTS, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultPantsUUID" ) ), FALSE )); - addEntry ( TEX_LOWER_SHOES, new PickerControlEntry (TEX_LOWER_SHOES, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultShoesUUID" ) ), FALSE )); - addEntry ( TEX_LOWER_SOCKS, new PickerControlEntry (TEX_LOWER_SOCKS, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultSocksUUID" ) ), FALSE )); - addEntry ( TEX_UPPER_JACKET, new PickerControlEntry (TEX_UPPER_JACKET, "Upper Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultJacketUUID" ) ), FALSE )); - addEntry ( TEX_LOWER_JACKET, new PickerControlEntry (TEX_LOWER_JACKET, "Lower Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultJacketUUID" ) ), FALSE )); - addEntry ( TEX_SKIRT, new PickerControlEntry (TEX_SKIRT, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultSkirtUUID" ) ), FALSE )); - addEntry ( TEX_UPPER_GLOVES, new PickerControlEntry (TEX_UPPER_GLOVES, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultGlovesUUID" ) ), FALSE )); - addEntry ( TEX_UPPER_UNDERSHIRT, new PickerControlEntry (TEX_UPPER_UNDERSHIRT, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultUnderwearUUID" ) ), FALSE )); - addEntry ( TEX_LOWER_UNDERPANTS, new PickerControlEntry (TEX_LOWER_UNDERPANTS, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultUnderwearUUID" ) ), FALSE )); - addEntry ( TEX_LOWER_ALPHA, new PickerControlEntry (TEX_LOWER_ALPHA, "Lower Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE )); - addEntry ( TEX_UPPER_ALPHA, new PickerControlEntry (TEX_UPPER_ALPHA, "Upper Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE )); - addEntry ( TEX_HEAD_ALPHA, new PickerControlEntry (TEX_HEAD_ALPHA, "Head Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE )); - addEntry ( TEX_EYES_ALPHA, new PickerControlEntry (TEX_EYES_ALPHA, "Eye Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE )); - addEntry ( TEX_HAIR_ALPHA, new PickerControlEntry (TEX_HAIR_ALPHA, "Hair Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE )); - addEntry ( TEX_LOWER_TATTOO, new PickerControlEntry (TEX_LOWER_TATTOO, "Lower Tattoo", LLUUID::null, TRUE )); - addEntry ( TEX_UPPER_TATTOO, new PickerControlEntry (TEX_UPPER_TATTOO, "Upper Tattoo", LLUUID::null, TRUE )); - addEntry ( TEX_HEAD_TATTOO, new PickerControlEntry (TEX_HEAD_TATTOO, "Head Tattoo", LLUUID::null, TRUE )); + addEntry ( TEX_HEAD_BODYPAINT, new PickerControlEntry (TEX_HEAD_BODYPAINT, "Head Tattoos", LLUUID::null, TRUE )); + addEntry ( TEX_UPPER_BODYPAINT, new PickerControlEntry (TEX_UPPER_BODYPAINT, "Upper Tattoos", LLUUID::null, TRUE )); + addEntry ( TEX_LOWER_BODYPAINT, new PickerControlEntry (TEX_LOWER_BODYPAINT, "Lower Tattoos", LLUUID::null, TRUE )); + addEntry ( TEX_HAIR, new PickerControlEntry (TEX_HAIR, "Texture", LLUUID( gSavedSettings.getString( "UIImgDefaultHairUUID" ) ), FALSE )); + addEntry ( TEX_EYES_IRIS, new PickerControlEntry (TEX_EYES_IRIS, "Iris", LLUUID( gSavedSettings.getString( "UIImgDefaultEyesUUID" ) ), FALSE )); + addEntry ( TEX_UPPER_SHIRT, new PickerControlEntry (TEX_UPPER_SHIRT, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultShirtUUID" ) ), FALSE )); + addEntry ( TEX_LOWER_PANTS, new PickerControlEntry (TEX_LOWER_PANTS, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultPantsUUID" ) ), FALSE )); + addEntry ( TEX_LOWER_SHOES, new PickerControlEntry (TEX_LOWER_SHOES, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultShoesUUID" ) ), FALSE )); + addEntry ( TEX_LOWER_SOCKS, new PickerControlEntry (TEX_LOWER_SOCKS, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultSocksUUID" ) ), FALSE )); + addEntry ( TEX_UPPER_JACKET, new PickerControlEntry (TEX_UPPER_JACKET, "Upper Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultJacketUUID" ) ), FALSE )); + addEntry ( TEX_LOWER_JACKET, new PickerControlEntry (TEX_LOWER_JACKET, "Lower Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultJacketUUID" ) ), FALSE )); + addEntry ( TEX_SKIRT, new PickerControlEntry (TEX_SKIRT, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultSkirtUUID" ) ), FALSE )); + addEntry ( TEX_UPPER_GLOVES, new PickerControlEntry (TEX_UPPER_GLOVES, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultGlovesUUID" ) ), FALSE )); + addEntry ( TEX_UPPER_UNDERSHIRT, new PickerControlEntry (TEX_UPPER_UNDERSHIRT, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultUnderwearUUID" ) ), FALSE )); + addEntry ( TEX_LOWER_UNDERPANTS, new PickerControlEntry (TEX_LOWER_UNDERPANTS, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultUnderwearUUID" ) ), FALSE )); + addEntry ( TEX_LOWER_ALPHA, new PickerControlEntry (TEX_LOWER_ALPHA, "Lower Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE )); + addEntry ( TEX_UPPER_ALPHA, new PickerControlEntry (TEX_UPPER_ALPHA, "Upper Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE )); + addEntry ( TEX_HEAD_ALPHA, new PickerControlEntry (TEX_HEAD_ALPHA, "Head Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE )); + addEntry ( TEX_EYES_ALPHA, new PickerControlEntry (TEX_EYES_ALPHA, "Eye Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE )); + addEntry ( TEX_HAIR_ALPHA, new PickerControlEntry (TEX_HAIR_ALPHA, "Hair Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE )); + addEntry ( TEX_LOWER_TATTOO, new PickerControlEntry (TEX_LOWER_TATTOO, "Lower Tattoo", LLUUID::null, TRUE )); + addEntry ( TEX_UPPER_TATTOO, new PickerControlEntry (TEX_UPPER_TATTOO, "Upper Tattoo", LLUUID::null, TRUE )); + addEntry ( TEX_HEAD_TATTOO, new PickerControlEntry (TEX_HEAD_TATTOO, "Head Tattoo", LLUUID::null, TRUE )); + 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, - const std::string name, - const LLUUID default_image_id, - const bool allow_no_texture) : - LLDictionaryEntry(name), - mTextureIndex(tex_index), - mControlName(name), - mDefaultImageId(default_image_id), - mAllowNoTexture(allow_no_texture) + const std::string name, + const LLUUID default_image_id, + const bool allow_no_texture) : + LLDictionaryEntry(name), + mTextureIndex(tex_index), + mControlName(name), + mDefaultImageId(default_image_id), + mAllowNoTexture(allow_no_texture) { } @@ -402,19 +423,19 @@ get_pickers_indexes(const LLEditWearableDictionary::WearableEntry *wearable_entr // Specializations of this template function return picker control entry for particular control type. template const LLEditWearableDictionary::PickerControlEntry* -get_picker_entry (const ETextureIndex index) { return NULL; } +get_picker_entry (const ETextureIndex index) { return nullptr; } -typedef boost::function function_t; +typedef std::function function_t; typedef struct PickerControlEntryNamePredicate { - PickerControlEntryNamePredicate(const std::string name) : mName (name) {}; - bool operator()(const LLEditWearableDictionary::PickerControlEntry* entry) const - { - return (entry && entry->mName == mName); - } -private: - const std::string mName; + PickerControlEntryNamePredicate(const std::string name) : mName (name) {}; + bool operator()(const LLEditWearableDictionary::PickerControlEntry* entry) const + { + return (entry && entry->mName == mName); + } + private: + const std::string mName; } PickerControlEntryNamePredicate; // A full specialization of get_pickers_indexes for LLColorSwatchCtrl @@ -422,12 +443,12 @@ template <> const texture_vec_t& get_pickers_indexes (const LLEditWearableDictionary::WearableEntry *wearable_entry) { - if (!wearable_entry) - { - llwarns << "could not get LLColorSwatchCtrl indexes for null wearable entry." << llendl; - return null_texture_vec; - } - return wearable_entry->mColorSwatchCtrls; + if (!wearable_entry) + { + LL_WARNS() << "could not get LLColorSwatchCtrl indexes for null wearable entry." << LL_ENDL; + return null_texture_vec; + } + return wearable_entry->mColorSwatchCtrls; } // A full specialization of get_pickers_indexes for LLTextureCtrl @@ -435,12 +456,12 @@ template <> const texture_vec_t& get_pickers_indexes (const LLEditWearableDictionary::WearableEntry *wearable_entry) { - if (!wearable_entry) - { - llwarns << "could not get LLTextureCtrl indexes for null wearable entry." << llendl; - return null_texture_vec; - } - return wearable_entry->mTextureCtrls; + if (!wearable_entry) + { + LL_WARNS() << "could not get LLTextureCtrl indexes for null wearable entry." << LL_ENDL; + return null_texture_vec; + } + return wearable_entry->mTextureCtrls; } // A full specialization of get_picker_entry for LLColorSwatchCtrl @@ -448,7 +469,7 @@ template <> const LLEditWearableDictionary::PickerControlEntry* get_picker_entry (const ETextureIndex index) { - return LLEditWearableDictionary::getInstance()->getColorSwatch(index); + return LLEditWearableDictionary::getInstance()->getColorSwatch(index); } // A full specialization of get_picker_entry for LLTextureCtrl @@ -456,154 +477,143 @@ template <> const LLEditWearableDictionary::PickerControlEntry* get_picker_entry (const ETextureIndex index) { - return LLEditWearableDictionary::getInstance()->getTexturePicker(index); + return LLEditWearableDictionary::getInstance()->getTexturePicker(index); } template const LLEditWearableDictionary::PickerControlEntry* find_picker_ctrl_entry_if(LLWearableType::EType type, const Predicate pred) { - const LLEditWearableDictionary::WearableEntry *wearable_entry - = LLEditWearableDictionary::getInstance()->getWearable(type); - if (!wearable_entry) - { - llwarns << "could not get wearable dictionary entry for wearable of type: " << type << llendl; - return NULL; - } - const texture_vec_t& indexes = get_pickers_indexes(wearable_entry); - for (texture_vec_t::const_iterator - iter = indexes.begin(), - iter_end = indexes.end(); - iter != iter_end; ++iter) - { - const ETextureIndex te = *iter; - const LLEditWearableDictionary::PickerControlEntry* entry + 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; + return nullptr; + } + const texture_vec_t& indexes = get_pickers_indexes(wearable_entry); + for (auto te : indexes) + { + const LLEditWearableDictionary::PickerControlEntry* entry = get_picker_entry(te); - if (!entry) - { - llwarns << "could not get picker dictionary entry (" << te << ") for wearable of type: " << type << llendl; - continue; - } - if (pred(entry)) - { - return entry; - } - } - return NULL; + if (!entry) + { + LL_WARNS() << "could not get picker dictionary entry (" << te << ") for wearable of type: " << type << LL_ENDL; + continue; + } + if (pred(entry)) + { + return entry; + } + } + return nullptr; } template -void -for_each_picker_ctrl_entry(LLPanel* panel, LLWearableType::EType type, function_t fun) -{ - if (!panel) - { - llwarns << "the panel wasn't passed for wearable of type: " << type << llendl; - return; - } - const LLEditWearableDictionary::WearableEntry *wearable_entry - = LLEditWearableDictionary::getInstance()->getWearable(type); - if (!wearable_entry) - { - llwarns << "could not get wearable dictionary entry for wearable of type: " << type << llendl; - return; - } - const texture_vec_t& indexes = get_pickers_indexes(wearable_entry); - for (texture_vec_t::const_iterator - iter = indexes.begin(), - iter_end = indexes.end(); - iter != iter_end; ++iter) - { - const ETextureIndex te = *iter; - const LLEditWearableDictionary::PickerControlEntry* entry - = get_picker_entry(te); - if (!entry) - { - llwarns << "could not get picker dictionary entry (" << te << ") for wearable of type: " << type << llendl; - continue; - } - fun (panel, entry); - } +void for_each_picker_ctrl_entry(LLPanel* panel, LLWearableType::EType type, function_t fun) +{ + if (!panel) + { + LL_WARNS() << "the panel wasn't passed for wearable of type: " << type << LL_ENDL; + return; + } + 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; + return; + } + const texture_vec_t& indexes = get_pickers_indexes(wearable_entry); + for (const auto& te : indexes) + { + 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); + } } // The helper functions for pickers management static void init_color_swatch_ctrl(LLPanelEditWearable* self, LLPanel* panel, const LLEditWearableDictionary::PickerControlEntry* entry) { - LLColorSwatchCtrl* color_swatch_ctrl = panel->getChild(entry->mControlName); - if (color_swatch_ctrl) - { - color_swatch_ctrl->setCommitCallback(boost::bind(&LLPanelEditWearable::onColorSwatchCommit, self, _1)); - // Can't get the color from the wearable here, since the wearable may not be set when this is called. - color_swatch_ctrl->setOriginal(LLColor4::white); - } + LLColorSwatchCtrl* color_swatch_ctrl = panel->getChild(entry->mControlName); + if (color_swatch_ctrl) + { + color_swatch_ctrl->setCommitCallback(boost::bind(&LLPanelEditWearable::onColorSwatchCommit, self, _1)); + // Can't get the color from the wearable here, since the wearable may not be set when this is called. + color_swatch_ctrl->setOriginal(LLColor4::white); + } } static void init_texture_ctrl(LLPanelEditWearable* self, LLPanel* panel, const LLEditWearableDictionary::PickerControlEntry* entry) { - LLTextureCtrl* texture_ctrl = panel->getChild(entry->mControlName); - if (texture_ctrl) - { - texture_ctrl->setCommitCallback(boost::bind(&LLPanelEditWearable::onTexturePickerCommit, self, _1)); - texture_ctrl->setDefaultImageAssetID(entry->mDefaultImageId); - texture_ctrl->setAllowNoTexture(entry->mAllowNoTexture); - // Don't allow (no copy) or (notransfer) textures to be selected. - texture_ctrl->setImmediateFilterPermMask(PERM_NONE);//PERM_COPY | PERM_TRANSFER); - texture_ctrl->setNonImmediateFilterPermMask(PERM_NONE);//PERM_COPY | PERM_TRANSFER); - } + LLTextureCtrl* texture_ctrl = panel->getChild(entry->mControlName); + if (texture_ctrl) + { + texture_ctrl->setCommitCallback(boost::bind(&LLPanelEditWearable::onTexturePickerCommit, self, _1)); + texture_ctrl->setDefaultImageAssetID(entry->mDefaultImageId); + texture_ctrl->setAllowNoTexture(entry->mAllowNoTexture); + // Don't allow (no copy) or (notransfer) textures to be selected. + texture_ctrl->setImmediateFilterPermMask(PERM_NONE);//PERM_COPY | PERM_TRANSFER); + texture_ctrl->setNonImmediateFilterPermMask(PERM_NONE);//PERM_COPY | PERM_TRANSFER); + } } static void update_color_swatch_ctrl(LLPanelEditWearable* self, LLPanel* panel, const LLEditWearableDictionary::PickerControlEntry* entry) { - LLColorSwatchCtrl* color_swatch_ctrl = panel->getChild(entry->mControlName); - if (color_swatch_ctrl) - { - color_swatch_ctrl->set(self->getWearable()->getClothesColor(entry->mTextureIndex)); - } + LLColorSwatchCtrl* color_swatch_ctrl = panel->getChild(entry->mControlName); + if (color_swatch_ctrl) + { + color_swatch_ctrl->set(self->getWearable()->getClothesColor(entry->mTextureIndex)); + } } static void update_texture_ctrl(LLPanelEditWearable* self, LLPanel* panel, const LLEditWearableDictionary::PickerControlEntry* entry) { - LLTextureCtrl* texture_ctrl = panel->getChild(entry->mControlName); - if (texture_ctrl) - { - LLUUID new_id; - LLLocalTextureObject *lto = self->getWearable()->getLocalTextureObject(entry->mTextureIndex); - if( lto && (lto->getID() != IMG_DEFAULT_AVATAR) ) - { - new_id = lto->getID(); - } - else - { - new_id = LLUUID::null; - } - LLUUID old_id = texture_ctrl->getImageAssetID(); - if (old_id != new_id) - { - // texture has changed, close the floater to avoid DEV-22461 - texture_ctrl->closeFloater(); - } - texture_ctrl->setImageAssetID(new_id); - } + LLTextureCtrl* texture_ctrl = panel->getChild(entry->mControlName); + if (texture_ctrl) + { + LLUUID new_id; + LLLocalTextureObject *lto = self->getWearable()->getLocalTextureObject(entry->mTextureIndex); + if (lto && (lto->getID() != IMG_DEFAULT_AVATAR)) + { + new_id = lto->getID(); + } + else + { + new_id = LLUUID::null; + } + LLUUID old_id = texture_ctrl->getImageAssetID(); + if (old_id != new_id) + { + // texture has changed, close the floater to avoid DEV-22461 + texture_ctrl->closeFloater(); + } + texture_ctrl->setImageAssetID(new_id); + } } static void set_enabled_color_swatch_ctrl(bool enabled, LLPanel* panel, const LLEditWearableDictionary::PickerControlEntry* entry) { - LLColorSwatchCtrl* color_swatch_ctrl = panel->getChild(entry->mControlName); - if (color_swatch_ctrl) - { - color_swatch_ctrl->setEnabled(enabled); - color_swatch_ctrl->setVisible(enabled); - } + LLColorSwatchCtrl* color_swatch_ctrl = panel->getChild(entry->mControlName); + if (color_swatch_ctrl) + { + color_swatch_ctrl->setEnabled(enabled); + color_swatch_ctrl->setVisible(enabled); + } } static void set_enabled_texture_ctrl(bool enabled, LLPanel* panel, const LLEditWearableDictionary::PickerControlEntry* entry) { - LLTextureCtrl* texture_ctrl = panel->getChild(entry->mControlName); - if (texture_ctrl) - { - texture_ctrl->setEnabled(enabled); - texture_ctrl->setVisible(enabled); - } + LLTextureCtrl* texture_ctrl = panel->getChild(entry->mControlName); + if (texture_ctrl) + { + texture_ctrl->setEnabled(enabled); + texture_ctrl->setVisible(enabled); + } } class LLWearableSaveAsDialog : public LLModalDialog @@ -620,11 +630,11 @@ class LLWearableSaveAsDialog : public LLModalDialog mParent( parent ) { LLUICtrlFactory::getInstance()->buildFloater(this, "floater_wearable_save_as.xml"); - - childSetAction("Save", boost::bind(&LLWearableSaveAsDialog::onSave, this) ); - childSetAction("Cancel", boost::bind(&LLWearableSaveAsDialog::onCancel, this) ); - childSetTextArg("name ed", "[DESC]", desc); + getChild("Save")->setCommitCallback(boost::bind(&LLWearableSaveAsDialog::onSave, this) ); + getChild("Cancel")->setCommitCallback(boost::bind(&LLWearableSaveAsDialog::onCancel, this) ); + + getChild("name ed")->setTextArg("[DESC]", desc); } ~LLWearableSaveAsDialog() { @@ -644,7 +654,7 @@ class LLWearableSaveAsDialog : public LLModalDialog void onSave() { - mItemName = childGetValue("name ed").asString(); + mItemName = getChildView("name ed")->getValue().asString(); LLStringUtil::trim(mItemName); if( !mItemName.empty() ) { @@ -671,7 +681,8 @@ LLPanelEditWearable::LLPanelEditWearable( LLWearableType::EType type, LLFloaterC mCurrentWearable( NULL ), mPendingWearable( NULL ), mPendingRefresh( false ), - mCustomizeFloater( parent ) + mCustomizeFloater( parent ), + mSubpartBtns() { } LLPanelEditWearable::~LLPanelEditWearable() @@ -682,32 +693,73 @@ LLPanelEditWearable::~LLPanelEditWearable() } } +static std::string getTabName(U32 i) { return llformat("%i", i); } +void LLPanelEditWearable::addLayerTabs(U32 index, U32 last) +{ + for(U32 i = index; i <= last; ++i) + { + const auto number = getTabName(i); + mTab->addTabPanel(new LLPanel(number), "Layer " + number); + } +} + BOOL LLPanelEditWearable::postBuild() { std::string icon_name = LLInventoryIcon::getIconName(LLWearableType::getAssetType( mType ),LLInventoryType::IT_WEARABLE,mType,FALSE); - childSetValue("icon", icon_name); + getChildView("icon")->setValue(icon_name); + + mCreateNew = getChild("Create New"); + mCreateNew->setCommitCallback(boost::bind(&LLPanelEditWearable::onBtnCreateNew, this)); - childSetAction("Create New", boost::bind(&LLPanelEditWearable::onBtnCreateNew, this) ); + if (mCreateNewLayer = findChild("New Layer")) + { + mCreateNewLayer->setCommitCallback(boost::bind(&LLPanelEditWearable::onBtnCreateNew, this)); + } - // If PG, can't take off underclothing or shirt - mCanTakeOff = - LLWearableType::getAssetType( mType ) == LLAssetType::AT_CLOTHING && - !( gAgent.isTeen() && (mType == LLWearableType::WT_UNDERSHIRT || mType == LLWearableType::WT_UNDERPANTS) ); - childSetVisible("Take Off", mCanTakeOff); - childSetAction("Take Off", boost::bind(&LLPanelEditWearable::onBtnTakeOff, this) ); + if (mTakeOff = findChild("Take Off")) + { + // If PG, can't take off underclothing or shirt + mCanTakeOff = !(gAgent.isTeen() && (mType == LLWearableType::WT_UNDERSHIRT || mType == LLWearableType::WT_UNDERPANTS) ); + mTakeOff->setVisible(mCanTakeOff); + mTakeOff->setCommitCallback(boost::bind(&LLPanelEditWearable::onBtnTakeOff, this)); + } - LLUICtrl* sex_radio = getChild("sex radio", true, false); - if(sex_radio) + if (mArrowLeft = findChild("Arrow Left")) { - sex_radio->setCommitCallback(boost::bind(&LLPanelEditWearable::onCommitSexChange,this) ); + mArrowLeft->setCommitCallback(boost::bind(&LLPanelEditWearable::onMoveToLayer, this, true)); } - childSetAction("Save", boost::bind(&LLPanelEditWearable::saveChanges, this, false, std::string()) ); + if (mArrowRight = findChild("Arrow Right")) + { + mArrowRight->setCommitCallback(boost::bind(&LLPanelEditWearable::onMoveToLayer, this, false)); + } - childSetAction("Save As", boost::bind(&LLPanelEditWearable::onBtnSaveAs, this) ); - childSetAction("Revert", boost::bind(&LLPanelEditWearable::revertChanges, this) ); + if (mSexRadio = findChild("sex radio")) + { + mSexRadio->setCommitCallback(boost::bind(&LLPanelEditWearable::onCommitSexChange, this)); + } + + mSave = getChild("Save"); + mSave->setCommitCallback(boost::bind(&LLPanelEditWearable::saveChanges, this, false, LLStringUtil::null) ); + + mSaveAs = getChild("Save As"); + mSaveAs->setCommitCallback(boost::bind(&LLPanelEditWearable::onBtnSaveAs, this) ); + + mRevert = getChild("Revert"); + mRevert->setCommitCallback(boost::bind(&LLPanelEditWearable::revertChanges, this) ); + + // Cache other UI for later + mNotWornI = getChildView("not worn instructions"); + mNoModI = getChildView("no modify instructions"); + mNotWornT = getChild("title_not_worn"); + mNoModT = getChild("title_no_modify"); + mTitle = getChild("title"); + mTitleLoading = getChild("title_loading"); + mPath = getChild("path"); + mSquare = getChildView("square"); + mAvHeight = getChild("avheight", false, false); configureAlphaCheckbox(LLAvatarAppearanceDefines::TEX_LOWER_ALPHA, "lower alpha texture invisible"); configureAlphaCheckbox(LLAvatarAppearanceDefines::TEX_UPPER_ALPHA, "upper alpha texture invisible"); @@ -719,11 +771,11 @@ BOOL LLPanelEditWearable::postBuild() const LLEditWearableDictionary::WearableEntry *wearable_entry = LLEditWearableDictionary::getInstance()->getWearable(mType); if (!wearable_entry) { - llwarns << "could not get wearable dictionary entry for wearable of type: " << mType << llendl; + LL_WARNS() << "could not get wearable dictionary entry for wearable of type: " << mType << LL_ENDL; } - U8 num_subparts = wearable_entry->mSubparts.size(); - - for (U8 index = 0; index < num_subparts; ++index) + const U8 num_subparts = (U8) wearable_entry->mSubparts.size(); + + for (U8 index = 0; num_subparts > 1 && index < num_subparts; ++index) { // dive into data structures to get the panel we need ESubpart subpart_e = wearable_entry->mSubparts[index]; @@ -731,38 +783,41 @@ BOOL LLPanelEditWearable::postBuild() if (!subpart_entry) { - llwarns << "could not get wearable subpart dictionary entry for subpart: " << subpart_e << llendl; - continue; + LL_WARNS() << "could not get wearable subpart dictionary entry for subpart: " << subpart_e << LL_ENDL; + mSubpartBtns.push_back(NULL); + continue; } - if(!subpart_entry->mButtonName.empty()) + if (!subpart_entry->mButtonName.empty()) { - llinfos << "Finding button " << subpart_entry->mButtonName << llendl; - llassert_always(getChild(subpart_entry->mButtonName,true,false)); - childSetAction(subpart_entry->mButtonName, boost::bind(&LLPanelEditWearable::changeCamera, this, index)); + //LL_INFOS() << "Finding button " << subpart_entry->mButtonName << LL_ENDL; + LLButton* btn(findChild(subpart_entry->mButtonName)); + llassert_always(btn); + mSubpartBtns.push_back(btn); + btn->setCommitCallback(boost::bind(&LLPanelEditWearable::changeCamera, this, index)); } - } + else + { + mSubpartBtns.push_back(NULL); + LL_WARNS() << "could not get wearable subpart button for subpart num: " << subpart_e << LL_ENDL; + } + } // initialize texture and color picker controls for_each_picker_ctrl_entry (this, mType, boost::bind(init_color_swatch_ctrl, this, _1, _2)); for_each_picker_ctrl_entry (this, mType, boost::bind(init_texture_ctrl, this, _1, _2)); } - LLTabContainer* tab = getChild("layer_tabs", true, false); - if(tab) + if (mTab = findChild("layer_tabs")) { - for(U32 i = 1; i <= LLAgentWearables::MAX_CLOTHING_PER_TYPE; ++i) - { - LLPanel* new_panel = new LLPanel(llformat("%i",i)); - tab->addTabPanel(new_panel, llformat("Layer %i",i)); - } - tab->setCommitCallback(boost::bind(&LLPanelEditWearable::onTabChanged, this, _1)); - tab->setValidateCallback(boost::bind(&LLPanelEditWearable::onTabPrecommit, this)); + addLayerTabs(1, gAgentWearables.getWearableCount(mType)); + mTab->setCommitCallback(boost::bind(&LLPanelEditWearable::onTabChanged, this, _1)); + mTab->setValidateCallback(boost::bind(&LLPanelEditWearable::onTabPrecommit, this)); } - childSetTextArg("title_not_worn", "[DESC]", LLWearableType::getTypeLabel( mType )); - childSetTextArg("title_loading", "[DESC]", LLWearableType::getTypeLabel( mType )); - childSetTextArg("title_no_modify", "[DESC]", LLWearableType::getTypeLabel( mType )); - childSetTextArg("title", "[DESC]", LLWearableType::getTypeLabel( mType )); + mNotWornT->setTextArg("[DESC]", LLWearableType::getTypeLabel(mType)); + mTitleLoading->setTextArg("[DESC]", LLWearableType::getTypeLabel(mType)); + mNoModT->setTextArg("[DESC]", LLWearableType::getTypeLabel(mType)); + mTitle->setTextArg("[DESC]", LLWearableType::getTypeLabel(mType)); return TRUE; } @@ -774,20 +829,19 @@ BOOL LLPanelEditWearable::isDirty() const void LLPanelEditWearable::draw() { - if( mCustomizeFloater->isMinimized() || !isAgentAvatarValid()) + if (mCustomizeFloater->isMinimized() || !isAgentAvatarValid()) return; refreshWearables(false); LLViewerWearable* wearable = getWearable(); - BOOL has_wearable = (wearable != NULL ); - BOOL has_any_wearable = has_wearable || gAgentWearables.getWearableCount(mType); + BOOL has_wearable = wearable != nullptr; BOOL is_dirty = isDirty(); BOOL is_modifiable = FALSE; BOOL is_copyable = FALSE; BOOL is_complete = FALSE; - LLInventoryItem* item = NULL; - if(wearable && (item = gInventory.getItem(wearable->getItemID()))) + LLInventoryItem* item = nullptr; + if (wearable && (item = gInventory.getItem(wearable->getItemID()))) { const LLPermissions& perm = item->getPermissions(); is_modifiable = perm.allowModifyBy(gAgent.getID(), gAgent.getGroupID()); @@ -795,40 +849,23 @@ void LLPanelEditWearable::draw() is_complete = ((LLViewerInventoryItem*)item)->isComplete(); } - childSetEnabled("Save", has_wearable && is_modifiable && is_complete && is_dirty); - childSetEnabled("Save As", has_wearable && is_copyable && is_complete); - childSetEnabled("Revert", has_wearable && is_dirty ); - childSetEnabled("Take Off", has_wearable); - childSetVisible("Take Off", has_wearable && mCanTakeOff); - childSetVisible("Create New", !has_any_wearable); - childSetVisible("not worn instructions", !has_any_wearable); - childSetVisible("title_not_worn", !has_any_wearable); - childSetVisible("no modify instructions",has_wearable && !is_modifiable); - childSetVisible("title_no_modify", has_wearable && !is_modifiable); - childSetVisible("title", has_wearable && is_modifiable && is_complete); - childSetVisible("title_loading", (!has_wearable && has_any_wearable) || (has_wearable && is_modifiable && !is_complete)); - childSetVisible("path", has_wearable); - childSetVisible("square", has_wearable && !is_modifiable); //lock icon - - /*LLTabContainer* tab = getChild("layer_tabs", true, false); - if(tab) - { - tab->setEnabled(has_any_wearable); - tab->setVisible(has_any_wearable); - }*/ + mSave->setEnabled(has_wearable && is_modifiable && is_complete && is_dirty); + mSaveAs->setEnabled(has_wearable && is_copyable && is_complete); + mRevert->setEnabled(has_wearable && is_dirty ); + mTitle->setVisible(has_wearable && is_modifiable && is_complete); + mTitleLoading->setVisible(has_wearable && is_modifiable && !is_complete); - if(has_wearable && is_modifiable) + if (has_wearable && is_modifiable) { for_each_picker_ctrl_entry (this, mType, boost::bind(update_color_swatch_ctrl, this, _1, _2)); for_each_picker_ctrl_entry (this, mType, boost::bind(update_texture_ctrl, this, _1, _2)); for_each_picker_ctrl_entry (this, mType, boost::bind(set_enabled_color_swatch_ctrl, is_complete, _1, _2)); - for_each_picker_ctrl_entry (this, mType, boost::bind(set_enabled_texture_ctrl, is_complete, _1, _2)); - for(string_texture_index_map_t::iterator iter = mAlphaCheckbox2Index.begin(); - iter != mAlphaCheckbox2Index.end(); ++iter ) - { - LLCheckBoxCtrl* ctrl = getChild(iter->first, true, false); - if (ctrl) - { + for_each_picker_ctrl_entry (this, mType, boost::bind(set_enabled_texture_ctrl, is_complete, _1, _2)); + for(ctrl_texture_index_map_t::iterator iter = mAlphaCheckbox2Index.begin(); + iter != mAlphaCheckbox2Index.end(); ++iter) + { + if (LLUICtrl* ctrl = iter->first) + { ctrl->setEnabled(is_copyable && is_complete); ctrl->setVisible(is_copyable && is_complete); } @@ -842,34 +879,37 @@ void LLPanelEditWearable::draw() const LLEditWearableDictionary::WearableEntry *wearable_entry = LLEditWearableDictionary::getInstance()->getWearable(mType); if (wearable_entry) { - U8 num_subparts = wearable_entry->mSubparts.size(); + const U8 num_subparts = (U8) wearable_entry->mSubparts.size(); - for (U8 index = 0; index < num_subparts; ++index) - { + for (U8 index = 0; num_subparts > 1 && index < num_subparts; ++index) + { // dive into data structures to get the panel we need ESubpart subpart_e = wearable_entry->mSubparts[index]; const LLEditWearableDictionary::SubpartEntry *subpart_entry = LLEditWearableDictionary::getInstance()->getSubpart(subpart_e); - + if (!subpart_entry) - { - llwarns << "could not get wearable subpart dictionary entry for subpart: " << subpart_e << llendl; - continue; - } + { + LL_WARNS() << "could not get wearable subpart dictionary entry for subpart: " << subpart_e << LL_ENDL; + continue; + } + + if (index >= mSubpartBtns.size()) continue; + LLButton* child = mSubpartBtns[index]; + if (!child) continue; - childSetVisible(subpart_entry->mButtonName,has_wearable); - if( has_wearable && is_complete && is_modifiable ) + child->setVisible(has_wearable); + if (has_wearable && is_complete && is_modifiable) { - childSetEnabled(subpart_entry->mButtonName, subpart_entry->mSex & gAgentAvatarp->getSex() ); + child->setEnabled(subpart_entry->mSex & gAgentAvatarp->getSex()); } else { - childSetEnabled(subpart_entry->mButtonName, FALSE ); + child->setEnabled(false); } } } - LLTextBox *av_height = getChild("avheight",FALSE,FALSE); - if(av_height) //Only display this if the element exists + if (mAvHeight) //Only display this if the element exists { // Display the shape's nominal height. // @@ -883,8 +923,8 @@ void LLPanelEditWearable::draw() std::ostringstream avheight(std::ostringstream::trunc); avheight << std::fixed << std::setprecision(2) << avsize << " m (" << feet << "' " << inches << "\")"; - av_height->setVisible(TRUE); - av_height->setTextArg("[AVHEIGHT]",avheight.str()); + mAvHeight->setVisible(TRUE); + mAvHeight->setTextArg("[AVHEIGHT]",avheight.str()); } LLPanel::draw(); @@ -893,7 +933,7 @@ void LLPanelEditWearable::draw() void LLPanelEditWearable::setVisible(BOOL visible) { LLPanel::setVisible( visible ); - if( !visible ) + if (!visible) { for_each_picker_ctrl_entry (this, mType, boost::bind(set_enabled_color_swatch_ctrl, FALSE, _1, _2)); } @@ -901,11 +941,11 @@ void LLPanelEditWearable::setVisible(BOOL visible) void LLPanelEditWearable::onTabChanged(LLUICtrl* ctrl) { - if(mPendingWearable) + if (mPendingWearable) return; U32 tab_index = ((LLTabContainer*)ctrl)->getCurrentPanelIndex(); - U32 wearable_index = gAgentWearables.getWearableCount(mType) - tab_index - 1; - if(wearable_index != mCurrentIndex ) + U32 wearable_index = tab_index ; + if (wearable_index != mCurrentIndex ) { setWearableIndex(wearable_index); } @@ -918,35 +958,26 @@ bool LLPanelEditWearable::onTabPrecommit() void LLPanelEditWearable::setWearableIndex(S32 index) { - if(mPendingWearable) + if (mPendingWearable) return; mCurrentIndex = index; - LLTabContainer* tab = getChild("layer_tabs", true, false); - if(tab) + if (mTab) { - U32 tab_index = gAgentWearables.getWearableCount(mType) - index - 1; + if (mTab->getTabCount() && mTab->getCurrentPanelIndex() != index) + mTab->selectTab(index); + } - if(tab->getCurrentPanelIndex() != tab_index) - tab->selectTab(tab_index); - } LLViewerWearable* wearable = gAgentWearables.getViewerWearable(mType,mCurrentIndex); // Singu note: Set title even if the wearable didn't change: the name might have changed (when renamed). - if(wearable) - { - childSetTextArg("title", "[DESC]", wearable->getName() ); - childSetTextArg("title_no_modify", "[DESC]", wearable->getName()); - } - else - { - childSetTextArg("title", "[DESC]", std::string(LLWearableType::getTypeLabel( mType )) ); - childSetTextArg("title_no_modify", "[DESC]", std::string(LLWearableType::getTypeLabel( mType ))); - } + const auto& desc = wearable ? wearable->getName() : LLWearableType::getTypeLabel(mType); + mTitle->setTextArg("[DESC]", desc); + mNoModT->setTextArg("[DESC]", desc); - if(wearable == getWearable()) + if (wearable == getWearable()) return; mCurrentWearable = wearable; @@ -964,59 +995,66 @@ void LLPanelEditWearable::setWearableIndex(S32 index) } const LLEditWearableDictionary::SubpartEntry *subpart_entry = LLEditWearableDictionary::getInstance()->getSubpart((ESubpart)mCurrentSubpart); - if(subpart_entry) + if (subpart_entry) { value_map_t sorted_params; getSortedParams(sorted_params, subpart_entry->mEditGroup, editable); buildParamList(mCustomizeFloater->getScrollingPanelList(), sorted_params); } - if(wearable) + if (wearable) { std::string path; const LLUUID& item_id = wearable->getItemID(); append_path(item_id, path); - childSetTextArg("path", "[PATH]", path); + mPath->setTextArg("[PATH]", path); } updateScrollingPanelList(); - } void LLPanelEditWearable::refreshWearables(bool force_immediate) { - if(!force_immediate && !mPendingRefresh) + if (!force_immediate && !mPendingRefresh) return; mPendingRefresh = false; U32 index; - if(mPendingWearable) + if (mPendingWearable) { - index = gAgentWearables.getWearableIndex(mPendingWearable); - if(index == LLAgentWearables::MAX_CLOTHING_PER_TYPE) + if (!gAgentWearables.getWearableIndex(mPendingWearable, index)) return; mPendingWearable = NULL; } else { - index = gAgentWearables.getWearableIndex(getWearable()); - if(index == LLAgentWearables::MAX_CLOTHING_PER_TYPE) + if (!gAgentWearables.getWearableIndex(mPendingWearable, index)) { index = gAgentWearables.getWearableCount(mType); - if(index) + if (index) --index; } } - - - LLTabContainer* tab = getChild("layer_tabs", true, false); - if(tab) + if (mTab) { - for(U32 i = 0; i < LLAgentWearables::MAX_CLOTHING_PER_TYPE; ++i) + S32 layer_count = gAgentWearables.getWearableCount(mType); + S32 tab_count = mTab->getTabCount(); + if (tab_count > layer_count) // Remove some tabs + { + while (tab_count && tab_count > layer_count) + { + if (auto tab = mTab->getChild(getTabName(tab_count--), false, false)) + { + mTab->removeTabPanel(tab); + delete tab; + } + } + } + else if (layer_count > tab_count) // Add some tabs { - tab->enableTabButton(i, i < gAgentWearables.getWearableCount(mType)); + addLayerTabs(tab_count+1, layer_count); } } setWearableIndex(index); @@ -1029,10 +1067,10 @@ void LLPanelEditWearable::wearablesChanged() void LLPanelEditWearable::onBtnSaveAs() { - if(mActiveModal) + if (mActiveModal) return; LLViewerWearable* wearable = getWearable(); - if( wearable ) + if (wearable) { mActiveModal = new LLWearableSaveAsDialog( wearable->getName(), this, boost::bind(&LLPanelEditWearable::onSaveAsCommit, this, _1)); mActiveModal->startModal(); @@ -1050,48 +1088,32 @@ void LLPanelEditWearable::onCommitSexChange() if (!isAgentAvatarValid()) return; LLWearableType::EType type = mType; // TODO: MULTI-WEARABLE - U32 index = mCurrentIndex; // TODO: MULTI-WEARABLE + U32 index = mCurrentIndex; // TODO: MULTI-WEARABLE - if( !gAgentWearables.isWearableModifiable(type, index)) - { + if (!gAgentWearables.isWearableModifiable(type, index)) + { return; - } + } LLViewerVisualParam* param = static_cast(gAgentAvatarp->getVisualParam( "male" )); - if( !param ) + if (!param) { return; } - bool is_new_sex_male = (gSavedSettings.getU32("AvatarSex") ? SEX_MALE : SEX_FEMALE) == SEX_MALE; - LLViewerWearable* wearable = gAgentWearables.getViewerWearable(type, index); + bool is_new_sex_male = gSavedSettings.getU32("AvatarSex") ? true : false; + LLViewerWearable* wearable = gAgentWearables.getViewerWearable(type, index); if (wearable) { wearable->setVisualParamWeight(param->getID(), is_new_sex_male, FALSE); } - param->setWeight( is_new_sex_male, FALSE ); - + param->setWeight( is_new_sex_male, FALSE ); + gAgentAvatarp->updateSexDependentLayerSets( FALSE ); gAgentAvatarp->updateVisualParams(); updateScrollingPanelUI(); - - //if(!wearable) - //{ - // return; - //} - - - - //wearable->setVisualParamWeight(param->getID(), (new_sex == SEX_MALE), TRUE); - //wearable->writeToAvatar(); - //avatar->updateVisualParams(); - -// gFloaterCustomize->clearScrollingPanelList(); - - // Assumes that we're in the "Shape" Panel. - //self->setSubpart( SUBPART_SHAPE_WHOLE ); } void LLPanelEditWearable::onBtnCreateNew() @@ -1105,7 +1127,7 @@ bool LLPanelEditWearable::onSelectAutoWearOption(const LLSD& notification, const { S32 option = LLNotification::getSelectedOption(notification, response); LLVOAvatar* avatar = gAgentAvatarp; - if(avatar) + if (avatar) { // Create a new wearable in the default folder for the wearable's asset type. LLViewerWearable* wearable = LLWearableList::instance().createNewWearable( (LLWearableType::EType)notification["payload"]["wearable_type"].asInteger(), avatar ); @@ -1117,7 +1139,7 @@ bool LLPanelEditWearable::onSelectAutoWearOption(const LLSD& notification, const // Only auto wear the new item if the AutoWearNewClothing checkbox is selected. LLPointer cb = option == 0 ? - new LLBoostFuncInventoryCallback(boost::bind(&wear_on_avatar_cb,_1,false)) : NULL; + new LLBoostFuncInventoryCallback(boost::bind(&wear_on_avatar_cb,_1,false)) : nullptr; create_inventory_item(gAgent.getID(), gAgent.getSessionID(), folder_id, wearable->getTransactionID(), wearable->getName(), wearable->getDescription(), asset_type, LLInventoryType::IT_WEARABLE, wearable->getType(), @@ -1126,9 +1148,27 @@ bool LLPanelEditWearable::onSelectAutoWearOption(const LLSD& notification, const return false; } +void LLPanelEditWearable::onMoveToLayer(bool closer) +{ + const auto wearable = getWearable(); + auto& appearance_mgr(LLAppearanceMgr::instance()); + auto links = appearance_mgr.findCOFItemLinks(wearable->getItemID()); + if (links.empty()) return; + auto link = links.front(); + if (gAgentWearables.moveWearable(link, closer)) + { + gAgentAvatarp->wearableUpdated(mType, true); + /* Singu TODO: Figure out how to maintain focus on the current tab + U32 index(0); + gAgentWearables.getWearableIndex(wearable, index); + setWearableIndex(index); + */ + } +} + LLViewerWearable* LLPanelEditWearable::getWearable() const { - return mCurrentWearable;//gAgentWearables.getWearable(mType, mCurrentIndex); // TODO: MULTI-WEARABLE + return mCurrentWearable; } U32 LLPanelEditWearable::getIndex() const @@ -1141,7 +1181,7 @@ void LLPanelEditWearable::onTexturePickerCommit(const LLUICtrl* ctrl) const LLTextureCtrl* texture_ctrl = dynamic_cast(ctrl); if (!texture_ctrl) { - llwarns << "got commit signal from not LLTextureCtrl." << llendl; + LL_WARNS() << "got commit signal from not LLTextureCtrl." << LL_ENDL; return; } @@ -1158,29 +1198,32 @@ void LLPanelEditWearable::onTexturePickerCommit(const LLUICtrl* ctrl) } else { - llwarns << "could not get texture picker dictionary entry for wearable of type: " << type << llendl; + LL_WARNS() << "could not get texture picker dictionary entry for wearable of type: " << type << LL_ENDL; } } } void LLPanelEditWearable::setNewImageID(ETextureIndex te_index, LLUUID const& uuid) { - LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture(uuid); - if( image->getID() == IMG_DEFAULT ) - { - image = LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT_AVATAR); - } - if (getWearable()) - { - U32 index = gAgentWearables.getWearableIndex(getWearable()); - gAgentAvatarp->setLocalTexture(te_index, image, FALSE, index); - LLVisualParamHint::requestHintUpdates(); - gAgentAvatarp->wearableUpdated(mType, FALSE); - } - if (mType == LLWearableType::WT_ALPHA && image->getID() != IMG_INVISIBLE) - { - mPreviousAlphaTexture[te_index] = image->getID(); - } + LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture(uuid); + if (image->getID() == IMG_DEFAULT) + { + image = LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT_AVATAR); + } + if (getWearable()) + { + U32 index; + if (gAgentWearables.getWearableIndex(getWearable(), index)) + { + gAgentAvatarp->setLocalTexture(te_index, image, FALSE, index); + LLVisualParamHint::requestHintUpdates(); + gAgentAvatarp->wearableUpdated(mType, FALSE); + } + } + if (mType == LLWearableType::WT_ALPHA && image->getID() != IMG_INVISIBLE) + { + mPreviousAlphaTexture[te_index] = image->getID(); + } } void LLPanelEditWearable::onColorSwatchCommit(const LLUICtrl* base_ctrl ) @@ -1191,22 +1234,21 @@ void LLPanelEditWearable::onColorSwatchCommit(const LLUICtrl* base_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 ) - { - getWearable()->setClothesColor(entry->mTextureIndex, new_color, TRUE); - LLVisualParamHint::requestHintUpdates(); - gAgentAvatarp->wearableUpdated(getWearable()->getType(), FALSE); - } + const LLColor4& old_color = getWearable()->getClothesColor(entry->mTextureIndex); + const LLColor4& new_color = LLColor4(ctrl->getValue()); + if (old_color != new_color) + { + getWearable()->setClothesColor(entry->mTextureIndex, new_color, TRUE); + LLVisualParamHint::requestHintUpdates(); + gAgentAvatarp->wearableUpdated(getWearable()->getType(), FALSE); + } } else { - llwarns << "could not get color swatch dictionary entry for wearable of type: " << type << llendl; + LL_WARNS() << "could not get color swatch dictionary entry for wearable of type: " << type << LL_ENDL; } } } @@ -1216,12 +1258,11 @@ void LLPanelEditWearable::hideTextureControls() { for_each_picker_ctrl_entry (this, mType, boost::bind(set_enabled_texture_ctrl, FALSE, _1, _2)); for_each_picker_ctrl_entry (this, mType, boost::bind(set_enabled_color_swatch_ctrl, FALSE, _1, _2)); - for(string_texture_index_map_t::iterator iter = mAlphaCheckbox2Index.begin(); + for(ctrl_texture_index_map_t::iterator iter = mAlphaCheckbox2Index.begin(); iter != mAlphaCheckbox2Index.end(); ++iter ) { - LLCheckBoxCtrl* ctrl = getChild(iter->first, true, false); - if (ctrl) - { + if (LLUICtrl* ctrl = iter->first) + { ctrl->setEnabled(FALSE); ctrl->setVisible(FALSE); } @@ -1232,24 +1273,24 @@ void LLPanelEditWearable::saveChanges(bool force_save_as, std::string new_name) { if (!getWearable() || (!force_save_as && !isDirty())) { - // do nothing if no unsaved changes - return; + // do nothing if no unsaved changes + return; } - U32 index = gAgentWearables.getWearableIndex(getWearable()); - + U32 index; + gAgentWearables.getWearableIndex(getWearable(), index); // Find an existing link to this wearable's inventory item, if any, and its description field. LLInventoryItem *link_item = NULL; std::string description; - if(gAgentAvatarp->isUsingServerBakes()) + if (gAgentAvatarp->isUsingServerBakes()) { LLInventoryModel::item_array_t links = LLAppearanceMgr::instance().findCOFItemLinks(getWearable()->getItemID()); if (links.size()>0) { - link_item = links.get(0).get(); + link_item = links.at(0).get(); if (link_item && link_item->getIsLinkType()) { description = link_item->getActualDescription(); @@ -1266,10 +1307,10 @@ void LLPanelEditWearable::saveChanges(bool force_save_as, std::string new_name) { mPendingWearable = new_wearable; mCurrentWearable = new_wearable; - childSetTextArg("title", "[DESC]", new_wearable->getName()); - childSetTextArg("title_no_modify", "[DESC]", new_wearable->getName()); + mTitle->setTextArg("[DESC]", new_wearable->getName()); + mNoModT->setTextArg("[DESC]", new_wearable->getName()); } - } + } else { // Make another copy of this link, with the same @@ -1278,17 +1319,18 @@ void LLPanelEditWearable::saveChanges(bool force_save_as, std::string new_name) if (link_item) { // Create new link - link_inventory_item( gAgent.getID(), - link_item->getLinkedUUID(), - LLAppearanceMgr::instance().getCOF(), - link_item->getName(), - description, - LLAssetType::AT_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; + + link_inventory_object( LLAppearanceMgr::instance().getCOF(), + link_item, NULL); + // Remove old link - gInventory.purgeObject(link_item->getUUID()); + remove_inventory_item(link_item, NULL); } - gAgentWearables.saveWearable(mType, index, TRUE, new_name); + gAgentWearables.saveWearable(mType, index, new_name); } } @@ -1300,9 +1342,9 @@ void LLPanelEditWearable::revertChanges() // no unsaved changes to revert return; } - + wearable->revertValues(); - childSetTextArg("title", "[DESC]", wearable->getName() ); + mTitle->setTextArg("[DESC]", wearable->getName()); gAgentAvatarp->wearableUpdated(mType, FALSE); if (mType == LLWearableType::WT_ALPHA) @@ -1322,18 +1364,17 @@ void LLPanelEditWearable::setUIPermissions(U32 perm_mask, BOOL is_complete) BOOL is_copyable = (perm_mask & PERM_COPY) ? TRUE : FALSE; BOOL is_modifiable = (perm_mask & PERM_MODIFY) ? TRUE : FALSE; - childSetEnabled("Save", is_modifiable && is_complete); - childSetEnabled("Save As", is_copyable && is_complete); - if (LLView* view = findChild("sex radio")) - view->setEnabled(is_modifiable && is_complete); + mSave->setEnabled(is_modifiable && is_complete); + mSaveAs->setEnabled(is_copyable && is_complete); + if (mSexRadio) + mSexRadio->setEnabled(is_modifiable && is_complete); for_each_picker_ctrl_entry (this, mType, boost::bind(set_enabled_texture_ctrl, is_copyable && is_modifiable && is_complete, _1, _2)); for_each_picker_ctrl_entry (this, mType, boost::bind(set_enabled_color_swatch_ctrl, is_modifiable && is_complete, _1, _2)); - for(string_texture_index_map_t::iterator iter = mAlphaCheckbox2Index.begin(); + for(ctrl_texture_index_map_t::iterator iter = mAlphaCheckbox2Index.begin(); iter != mAlphaCheckbox2Index.end(); ++iter ) - { - LLCheckBoxCtrl* ctrl = getChild(iter->first, true, false); - if (ctrl) - { + { + if (LLUICtrl* ctrl = iter->first) + { ctrl->setEnabled(is_copyable && is_modifiable && is_complete); ctrl->setVisible(is_copyable && is_modifiable && is_complete); } @@ -1345,25 +1386,25 @@ void LLPanelEditWearable::changeCamera(U8 subpart) const LLEditWearableDictionary::WearableEntry *wearable_entry = LLEditWearableDictionary::getInstance()->getWearable(mType); if (!wearable_entry) { - llinfos << "could not get wearable dictionary entry for wearable type: " << mType << llendl; + LL_INFOS() << "could not get wearable dictionary entry for wearable type: " << mType << LL_ENDL; return; } - + if (subpart >= wearable_entry->mSubparts.size()) { - llinfos << "accordion tab expanded for invalid subpart. Wearable type: " << mType << " subpart num: " << subpart << llendl; + LL_INFOS() << "accordion tab expanded for invalid subpart. Wearable type: " << mType << " subpart num: " << subpart << LL_ENDL; return; } - + ESubpart subpart_e = wearable_entry->mSubparts[subpart]; const LLEditWearableDictionary::SubpartEntry *subpart_entry = LLEditWearableDictionary::getInstance()->getSubpart(subpart_e); - + if (!subpart_entry) { - llwarns << "could not get wearable subpart dictionary entry for subpart: " << subpart_e << llendl; + LL_WARNS() << "could not get wearable subpart dictionary entry for subpart: " << subpart_e << LL_ENDL; return; } - + mCurrentSubpart = subpart_e; //Update the buttons to reflect the current selected subpart. for (U8 index = 0; index < wearable_entry->mSubparts.size(); ++index) @@ -1371,12 +1412,13 @@ void LLPanelEditWearable::changeCamera(U8 subpart) // 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) - { - LLButton* btn = getChild(subpart_entry->mButtonName); + { + if (index < mSubpartBtns.size()) + if (LLButton* btn = mSubpartBtns[index]) { - btn->setToggleState( subpart == subpart_e ); + btn->setToggleState(subpart == subpart_e); } } } @@ -1389,7 +1431,7 @@ void LLPanelEditWearable::changeCamera(U8 subpart) updateScrollingPanelUI(); // Update the camera - if(gMorphView) + if (gMorphView) { gMorphView->setCameraTargetJoint( gAgentAvatarp->getJoint( subpart_entry->mTargetJoint ) ); gMorphView->setCameraTargetOffset( subpart_entry->mTargetOffset ); @@ -1444,29 +1486,64 @@ void LLPanelEditWearable::updateScrollingPanelList() void LLPanelEditWearable::updateScrollingPanelUI() { LLViewerWearable* wearable = getWearable(); - // do nothing if we don't have a valid wearable we're editing - if(!wearable) - { - return; - } - - llinfos << llformat("%#.8lX",wearable) << llendl; - llinfos << "cur_wearable->isDirty()=" << wearable->isDirty() << llendl; - LLViewerInventoryItem* item = gInventory.getItem(wearable->getItemID()); - if(item) + BOOL is_modifiable = FALSE; + BOOL is_copyable = FALSE; + LLViewerInventoryItem* item = wearable ? gInventory.getItem(wearable->getItemID()) : nullptr; + if (item) { - U32 perm_mask = item->getPermissions().getMaskOwner(); BOOL is_complete = item->isComplete(); LLScrollingPanelParam::sUpdateDelayFrames = 0; - mCustomizeFloater->getScrollingPanelList()->updatePanels((perm_mask & PERM_MODIFY) && is_complete); + const LLPermissions& perm = item->getPermissions(); + const auto& group_id(gAgent.getGroupID()); + is_modifiable = perm.allowModifyBy(gAgentID, group_id); + is_copyable = perm.allowCopyBy(gAgentID, group_id); + mCustomizeFloater->getScrollingPanelList()->updatePanels(is_modifiable && is_complete); + } + + // Update some UI here instead of the draw call + bool has_wearable = wearable != nullptr; + bool max_layers = gAgentWearables.getClothingLayerCount() == LLAgentWearables::MAX_CLOTHING_LAYERS; + bool show_create_new = !has_wearable && !max_layers; + + if (mTakeOff) + { + mTakeOff->setEnabled(has_wearable); + if (mCanTakeOff) mTakeOff->setVisible(has_wearable); + } + if (mCreateNewLayer) + { + mCreateNewLayer->setVisible(has_wearable && !max_layers); + } + if (mArrowLeft) + { + mArrowLeft->setEnabled(has_wearable && gAgentWearables.getBottomWearable(mType) != wearable); + mArrowLeft->setVisible(has_wearable); } + if (mArrowRight) + { + mArrowRight->setEnabled(has_wearable && gAgentWearables.getTopWearable(mType) != wearable); + mArrowRight->setVisible(has_wearable); + } + mCreateNew->setVisible(show_create_new); + mNotWornI->setVisible(show_create_new); + mNotWornT->setVisible(show_create_new); + mNoModI->setVisible(has_wearable && !is_modifiable); + mNoModT->setVisible(has_wearable && !is_modifiable); + mPath->setVisible(has_wearable); + mSquare->setVisible(has_wearable && !is_modifiable); //lock icon + + // do nothing else if we don't have a valid wearable we're editing + if (!wearable) return; + //LL_INFOS() << llformat("%#.8lX", wearable) << LL_ENDL; + //LL_INFOS() << "cur_wearable->isDirty()=" << wearable->isDirty() << LL_ENDL; + refreshWearables(false); } void LLPanelEditWearable::onBtnTakeOff() { LLViewerWearable* wearable = getWearable(); - if( !wearable ) + if (!wearable) { return; } @@ -1478,7 +1555,7 @@ void LLPanelEditWearable::onBtnTakeOff() // static void LLPanelEditWearable::getSortedParams(value_map_t &sorted_params, const std::string &edit_group, bool editable) { - if(!getWearable())return; + if (!getWearable()) return; LLViewerWearable::visual_param_vec_t param_list; ESex avatar_sex = gAgentAvatarp->getSex(); @@ -1496,7 +1573,7 @@ void LLPanelEditWearable::getSortedParams(value_map_t &sorted_params, const std: || param->getEditGroup() != edit_group || !(param->getSex() & avatar_sex)) { - continue; + continue; } // negative getDisplayOrder() to make lowest order the highest priority @@ -1511,7 +1588,7 @@ 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(); @@ -1526,34 +1603,36 @@ void LLPanelEditWearable::buildParamList(LLScrollingPanelList *panel_list, value void LLPanelEditWearable::configureAlphaCheckbox(LLAvatarAppearanceDefines::ETextureIndex te, const std::string& name) { - LLCheckBoxCtrl* checkbox = getChild(name, true, false); - if(checkbox) - { - checkbox->setCommitCallback(boost::bind(&LLPanelEditWearable::onInvisibilityCommit, this, checkbox, te)); - initPreviousAlphaTextureEntry(te); - mAlphaCheckbox2Index[name] = te; - } + if (LLUICtrl* checkbox = findChild(name)) + { + checkbox->setCommitCallback(boost::bind(&LLPanelEditWearable::onInvisibilityCommit, this, checkbox, te)); + initPreviousAlphaTextureEntry(te); + mAlphaCheckbox2Index[checkbox] = te; + } } -void LLPanelEditWearable::onInvisibilityCommit(LLCheckBoxCtrl* checkbox_ctrl, LLAvatarAppearanceDefines::ETextureIndex te) +void LLPanelEditWearable::onInvisibilityCommit(LLUICtrl* ctrl, LLAvatarAppearanceDefines::ETextureIndex te) { - if (!checkbox_ctrl) + if (!ctrl) return; if (!getWearable()) return; - llinfos << "onInvisibilityCommit, self " << this << " checkbox_ctrl " << checkbox_ctrl << llendl; + LL_INFOS() << "onInvisibilityCommit, self " << this << " ctrl " << ctrl << LL_ENDL; - bool new_invis_state = checkbox_ctrl->get(); + bool new_invis_state = ctrl->getValue(); if (new_invis_state) { LLLocalTextureObject *lto = getWearable()->getLocalTextureObject(te); mPreviousAlphaTexture[te] = lto->getID(); LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture( IMG_INVISIBLE ); - U32 index = gAgentWearables.getWearableIndex(getWearable()); - gAgentAvatarp->setLocalTexture(te, image, FALSE, index); - gAgentAvatarp->wearableUpdated(getWearable()->getType(), FALSE); + U32 index; + if (gAgentWearables.getWearableIndex(getWearable(), index)) + { + gAgentAvatarp->setLocalTexture(te, image, FALSE, index); + gAgentAvatarp->wearableUpdated(getWearable()->getType(), FALSE); + } } else { @@ -1561,7 +1640,7 @@ void LLPanelEditWearable::onInvisibilityCommit(LLCheckBoxCtrl* checkbox_ctrl, LL LLUUID prev_id = mPreviousAlphaTexture[te]; if (prev_id.isNull() || (prev_id == IMG_INVISIBLE)) { - prev_id = LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ); + prev_id = LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ); } if (prev_id.isNull()) return; @@ -1571,40 +1650,42 @@ void LLPanelEditWearable::onInvisibilityCommit(LLCheckBoxCtrl* checkbox_ctrl, LL if (!image) return; - U32 index = gAgentWearables.getWearableIndex(getWearable()); - gAgentAvatarp->setLocalTexture(te, image, FALSE, index); - gAgentAvatarp->wearableUpdated(getWearable()->getType(), FALSE); + U32 index; + if (gAgentWearables.getWearableIndex(getWearable(), index)) + { + gAgentAvatarp->setLocalTexture(te, image, FALSE, index); + gAgentAvatarp->wearableUpdated(getWearable()->getType(), FALSE); + } } } void LLPanelEditWearable::updateAlphaCheckboxes() { - if(!getWearable()) + if (!getWearable()) return; - for(string_texture_index_map_t::iterator iter = mAlphaCheckbox2Index.begin(); + for(ctrl_texture_index_map_t::iterator iter = mAlphaCheckbox2Index.begin(); iter != mAlphaCheckbox2Index.end(); ++iter ) { LLAvatarAppearanceDefines::ETextureIndex te = (LLAvatarAppearanceDefines::ETextureIndex)iter->second; - LLCheckBoxCtrl* ctrl = getChild(iter->first, true, false); - if (ctrl) + if (LLUICtrl* ctrl = iter->first) { - ctrl->set(!gAgentAvatarp->isTextureVisible(te, getWearable())); + ctrl->setValue(!gAgentAvatarp->isTextureVisible(te, getWearable())); } } } void LLPanelEditWearable::initPreviousAlphaTextures() { - initPreviousAlphaTextureEntry(TEX_LOWER_ALPHA); - initPreviousAlphaTextureEntry(TEX_UPPER_ALPHA); - initPreviousAlphaTextureEntry(TEX_HEAD_ALPHA); - initPreviousAlphaTextureEntry(TEX_EYES_ALPHA); - initPreviousAlphaTextureEntry(TEX_LOWER_ALPHA); + initPreviousAlphaTextureEntry(TEX_LOWER_ALPHA); + initPreviousAlphaTextureEntry(TEX_UPPER_ALPHA); + initPreviousAlphaTextureEntry(TEX_HEAD_ALPHA); + initPreviousAlphaTextureEntry(TEX_EYES_ALPHA); + initPreviousAlphaTextureEntry(TEX_HAIR_ALPHA); } void LLPanelEditWearable::initPreviousAlphaTextureEntry(LLAvatarAppearanceDefines::ETextureIndex te) { - if(!getWearable()) + if (!getWearable()) return; LLLocalTextureObject *lto = getWearable()->getLocalTextureObject(te); if (lto) diff --git a/indra/newview/llpaneleditwearable.h b/indra/newview/llpaneleditwearable.h index a57a4b9d28..a6da8c73c5 100644 --- a/indra/newview/llpaneleditwearable.h +++ b/indra/newview/llpaneleditwearable.h @@ -34,7 +34,7 @@ #include "llwearabletype.h" class LLAccordionCtrl; -class LLCheckBoxCtrl; +class LLButton; class LLViewerWearable; class LLTextBox; class LLViewerInventoryItem; @@ -56,6 +56,7 @@ class LLPanelEditWearable : public LLPanel LLPanelEditWearable( LLWearableType::EType type, LLFloaterCustomize* parent ); virtual ~LLPanelEditWearable(); + void addLayerTabs(U32 index, U32 last); /*virtual*/ BOOL postBuild(); /*virtual*/ BOOL isDirty() const; // LLUICtrl /*virtual*/ void draw(); @@ -108,13 +109,15 @@ class LLPanelEditWearable : public LLPanel void onBtnCreateNew(); static bool onSelectAutoWearOption(const LLSD& notification, const LLSD& response); + void onMoveToLayer(bool closer); + void onColorSwatchCommit(const LLUICtrl*); void onTexturePickerCommit(const LLUICtrl*); void setNewImageID(ETextureIndex te_index, LLUUID const& uuid); //Singu note: this used to be part of onTexturePickerCommit. //alpha mask checkboxes void configureAlphaCheckbox(LLAvatarAppearanceDefines::ETextureIndex te, const std::string& name); - void onInvisibilityCommit(LLCheckBoxCtrl* checkbox_ctrl, LLAvatarAppearanceDefines::ETextureIndex te); + void onInvisibilityCommit(LLUICtrl* checkbox_ctrl, LLAvatarAppearanceDefines::ETextureIndex te); void updateAlphaCheckboxes(); void initPreviousAlphaTextures(); void initPreviousAlphaTextureEntry(LLAvatarAppearanceDefines::ETextureIndex te); @@ -123,8 +126,8 @@ class LLPanelEditWearable : public LLPanel LLFloaterCustomize* mCustomizeFloater; LLWearableType::EType mType; BOOL mCanTakeOff; - typedef std::map string_texture_index_map_t; - string_texture_index_map_t mAlphaCheckbox2Index; + typedef std::map ctrl_texture_index_map_t; + ctrl_texture_index_map_t mAlphaCheckbox2Index; typedef std::map s32_uuid_map_t; s32_uuid_map_t mPreviousAlphaTexture; @@ -135,6 +138,12 @@ class LLPanelEditWearable : public LLPanel //so this is needed to retain focus on this wearables tab over the messy transition. bool mPendingRefresh; //LLAgentWearables::setWearableOutfit fires a buttload of remove/wear calls which spams wearablesChanged //a bazillion pointless (and not particularly valid) times. Deferring to draw effectively sorts it all out. + + // Cached UI + LLUICtrl *mCreateNew, *mCreateNewLayer, *mTakeOff, *mArrowLeft, *mArrowRight, *mSexRadio, *mSave, *mSaveAs, *mRevert, *mNotWornT, *mNoModT, *mTitle, *mTitleLoading, *mPath, *mAvHeight; + LLView *mNotWornI, *mNoModI, *mSquare; + LLTabContainer* mTab; + std::vector mSubpartBtns; public: LLModalDialog* mActiveModal; }; diff --git a/indra/newview/llpanelevent.cpp b/indra/newview/llpanelevent.cpp index ef25b25e90..5eb6fe51d8 100644 --- a/indra/newview/llpanelevent.cpp +++ b/indra/newview/llpanelevent.cpp @@ -54,6 +54,8 @@ #include "llweb.h" #include "llworldmap.h" #include "lluictrlfactory.h" +#include "hippogridmanager.h" +#include "lfsimfeaturehandler.h" //static std::list LLPanelEvent::sAllPanels; @@ -69,6 +71,10 @@ LLPanelEvent::~LLPanelEvent() sAllPanels.remove(this); } +void enable_create(const std::string& url, LLView* btn) +{ + btn->setEnabled(!url.empty()); +} BOOL LLPanelEvent::postBuild() { @@ -97,8 +103,15 @@ BOOL LLPanelEvent::postBuild() mNotifyBtn = getChild( "notify_btn"); mNotifyBtn->setClickedCallback(boost::bind(&LLPanelEvent::onClickNotify,this)); - mCreateEventBtn = getChild( "create_event_btn"); - mCreateEventBtn->setClickedCallback(boost::bind(&LLPanelEvent::onClickCreateEvent,this)); + mCreateEventBtn = getChild("create_event_btn"); + mCreateEventBtn->setClickedCallback(boost::bind(&LLPanelEvent::onClickCreateEvent, this)); + if (!gHippoGridManager->getConnectedGrid()->isSecondLife()) + { + auto& inst(LFSimFeatureHandler::instance()); + mCreateEventBtn->setEnabled(!inst.getEventsURL().empty()); + inst.setEventsURLCallback(boost::bind(enable_create, _1, mCreateEventBtn)); + } + return TRUE; } @@ -126,9 +139,8 @@ void LLPanelEvent::processEventInfoReply(LLMessageSystem *msg, void **) msg->getU32("EventData", "EventID", event_id); // look up all panels which have this avatar - for (panel_list_t::iterator iter = sAllPanels.begin(); iter != sAllPanels.end(); ++iter) + for (auto& self : sAllPanels) { - LLPanelEvent* self = *iter; // Skip updating panels which aren't for this event if (self->mEventID != event_id) { @@ -138,7 +150,8 @@ void LLPanelEvent::processEventInfoReply(LLMessageSystem *msg, void **) self->mTBName->setText(self->mEventInfo.mName); self->mTBCategory->setText(self->mEventInfo.mCategoryStr); self->mTBDate->setText(self->mEventInfo.mTimeStr); - self->mTBDesc->setText(self->mEventInfo.mDesc); + self->mTBDesc->setText(self->mEventInfo.mDesc, false); + self->mTBRunBy->setValue(self->mEventInfo.mRunByID); self->mTBDuration->setText(llformat("%d:%.2d", self->mEventInfo.mDuration / 60, self->mEventInfo.mDuration % 60)); @@ -154,9 +167,9 @@ void LLPanelEvent::processEventInfoReply(LLMessageSystem *msg, void **) F32 global_x = (F32)self->mEventInfo.mPosGlobal.mdV[VX]; F32 global_y = (F32)self->mEventInfo.mPosGlobal.mdV[VY]; - S32 region_x = llround(global_x) % REGION_WIDTH_UNITS; - S32 region_y = llround(global_y) % REGION_WIDTH_UNITS; - S32 region_z = llround((F32)self->mEventInfo.mPosGlobal.mdV[VZ]); + S32 region_x = ll_round(global_x) % REGION_WIDTH_UNITS; + S32 region_y = ll_round(global_y) % REGION_WIDTH_UNITS; + S32 region_z = ll_round((F32)self->mEventInfo.mPosGlobal.mdV[VZ]); std::string desc = self->mEventInfo.mSimName + llformat(" (%d, %d, %d)", region_x, region_y, region_z); self->mTBLocation->setText(desc); @@ -192,17 +205,6 @@ void LLPanelEvent::processEventInfoReply(LLMessageSystem *msg, void **) } } - -void LLPanelEvent::draw() -{ - std::string name; - gCacheName->getFullName(mEventInfo.mRunByID, name); - - mTBRunBy->setText(name); - - LLPanel::draw(); -} - void LLPanelEvent::resetInfo() { // Clear all of the text fields. @@ -285,9 +287,9 @@ bool LLPanelEvent::callbackCreateEventWebPage(const LLSD& notification, const LL S32 option = LLNotification::getSelectedOption(notification, response); if (0 == option) { - llinfos << "Loading events page " << EVENTS_URL << llendl; - - LLWeb::loadURL(EVENTS_URL); + LL_INFOS() << "Loading events page " << EVENTS_URL << LL_ENDL; + const std::string& opensim_events = LFSimFeatureHandler::instance().getEventsURL(); + LLWeb::loadURL(opensim_events.empty() ? EVENTS_URL : opensim_events); } return false; } diff --git a/indra/newview/llpanelevent.h b/indra/newview/llpanelevent.h index 90c08bde0a..353b66fd16 100644 --- a/indra/newview/llpanelevent.h +++ b/indra/newview/llpanelevent.h @@ -51,7 +51,6 @@ class LLPanelEvent : public LLPanel /*virtual*/ ~LLPanelEvent(); /*virtual*/ BOOL postBuild(); - /*virtual*/ void draw(); void setEventID(const U32 event_id); void sendEventInfoRequest(); diff --git a/indra/newview/llpanelexperiencelisteditor.cpp b/indra/newview/llpanelexperiencelisteditor.cpp new file mode 100644 index 0000000000..784fc9cfea --- /dev/null +++ b/indra/newview/llpanelexperiencelisteditor.cpp @@ -0,0 +1,280 @@ +/** + * @file llpanelexperiencelisteditor.cpp + * @brief Editor for building a list of experiences + * + * $LicenseInfo:firstyear=2014&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llpanelexperiencelisteditor.h" + +#include "llbutton.h" +#include "llexperiencecache.h" +#include "llfloaterexperiencepicker.h" +#include "llfloaterexperienceprofile.h" +//#include "llfloaterreg.h" +#include "llhandle.h" +#include "llnamelistctrl.h" +#include "llscrolllistctrl.h" +#include "llviewerregion.h" +#include "llagent.h" +#include "lltextbox.h" +#include "lltrans.h" + + +/* Singu Note: We do not have injectors, so we'll have to call this function instead +static LLPanelInjector t_panel_experience_list_editor("panel_experience_list_editor"); +*/ +void* create_xp_list_editor(void* data) +{ + return *reinterpret_cast(data) = new LLPanelExperienceListEditor; +} + + +LLPanelExperienceListEditor::LLPanelExperienceListEditor() + :mItems(nullptr) + ,mAdd(nullptr) + ,mRemove(nullptr) + ,mProfile(nullptr) + ,mAddedCallback() + ,mRemovedCallback() + ,mReadonly(false) + ,mMaxExperienceIDs(0) +{ +} + +BOOL LLPanelExperienceListEditor::postBuild() +{ + mItems = getChild("experience_list"); + mAdd = getChild("btn_add"); + mRemove = getChild("btn_remove"); + mProfile = getChild("btn_profile"); + + childSetAction("btn_add", boost::bind(&LLPanelExperienceListEditor::onAdd, this)); + childSetAction("btn_remove", boost::bind(&LLPanelExperienceListEditor::onRemove, this)); + childSetAction("btn_profile", boost::bind(&LLPanelExperienceListEditor::onProfile, this)); + + mItems->setCommitCallback(boost::bind(&LLPanelExperienceListEditor::checkButtonsEnabled, this)); + + checkButtonsEnabled(); + return TRUE; +} + +const uuid_list_t& LLPanelExperienceListEditor::getExperienceIds() const +{ + return mExperienceIds; +} + +void LLPanelExperienceListEditor::addExperienceIds( const uuid_vec_t& experience_ids ) +{ + // the commented out code in this function is handled by the callback and no longer necessary! + + //mExperienceIds.insert(experience_ids.begin(), experience_ids.end()); + //onItems(); + if(!mAddedCallback.empty()) + { + for(uuid_vec_t::const_iterator it = experience_ids.begin(); it != experience_ids.end(); ++it) + { + mAddedCallback(*it); + } + } +} + + +void LLPanelExperienceListEditor::setExperienceIds( const LLSD& experience_ids ) +{ + mExperienceIds.clear(); + for (const auto& id : experience_ids.array()) + { + // Using insert(range) doesn't work here because the conversion from + // LLSD to LLUUID is ambiguous: have to specify asUUID() for each entry. + mExperienceIds.insert(id.asUUID()); + } + onItems(); +} + +void LLPanelExperienceListEditor::addExperience( const LLUUID& id ) +{ + mExperienceIds.insert(id); + onItems(); +} +void LLPanelExperienceListEditor::onAdd() +{ + if(!mPicker.isDead()) + { + mPicker.markDead(); + } + + mKey.generateNewID(); + + LLFloaterExperiencePicker* picker = LLFloaterExperiencePicker::show(boost::bind(&LLPanelExperienceListEditor::addExperienceIds, this, _1), mKey, FALSE, TRUE, mFilters, mAdd); + mPicker = picker->getDerivedHandle(); +} + + +void LLPanelExperienceListEditor::onRemove() +{ + // the commented out code in this function is handled by the callback and no longer necessary! + + std::vector items= mItems->getAllSelected(); + std::vector::iterator it = items.begin(); + for(/**/; it != items.end(); ++it) + { + if((*it) != nullptr) + { + //mExperienceIds.erase((*it)->getValue()); + mRemovedCallback((*it)->getValue()); + } + } + mItems->selectFirstItem(); + checkButtonsEnabled(); + //onItems(); +} + +void LLPanelExperienceListEditor::onProfile() +{ + LLScrollListItem* item = mItems->getFirstSelected(); + if(item) + { + LLFloaterExperienceProfile::showInstance(item->getUUID()); + } +} + +void LLPanelExperienceListEditor::checkButtonsEnabled() +{ + mAdd->setEnabled(!mReadonly); + int selected = mItems->getNumSelected(); + + bool remove_enabled = !mReadonly && selected>0; + if(remove_enabled && mSticky) + { + std::vector items= mItems->getAllSelected(); + std::vector::iterator it = items.begin(); + for(/**/; it != items.end() && remove_enabled; ++it) + { + if((*it) != nullptr) + { + remove_enabled = !mSticky((*it)->getValue()); + } + } + + + } + mRemove->setEnabled(remove_enabled); + mProfile->setEnabled(selected==1); +} + +void LLPanelExperienceListEditor::onItems() +{ + mItems->deleteAllItems(); + + LLSD item; + uuid_list_t::iterator it = mExperienceIds.begin(); + for(/**/; it != mExperienceIds.end(); ++it) + { + const LLUUID& experience = *it; + item["id"]=experience; + item["target"] = LLNameListItem::EXPERIENCE; + LLSD& columns = item["columns"]; + columns[0]["column"] = "experience_name"; + columns[0]["value"] = getString("loading"); + mItems->addElement(item); + + LLExperienceCache::instance().get(experience, boost::bind(&LLPanelExperienceListEditor::experienceDetailsCallback, + getDerivedHandle(), _1)); + } + + + if(mItems->getItemCount() == 0) + { + mItems->setCommentText(getString("no_results")); + } + + + checkButtonsEnabled(); +} + +void LLPanelExperienceListEditor::experienceDetailsCallback( LLHandle panel, const LLSD& experience ) +{ + if(!panel.isDead()) + { + panel.get()->onExperienceDetails(experience); + } +} + +void LLPanelExperienceListEditor::onExperienceDetails( const LLSD& experience ) +{ + LLScrollListItem* item = mItems->getItem(experience[LLExperienceCache::EXPERIENCE_ID]); + if(!item) + return; + + std::string experience_name_string = experience[LLExperienceCache::NAME].asString(); + if (experience_name_string.empty()) + { + experience_name_string = LLTrans::getString("ExperienceNameUntitled"); + } + + item->getColumn(0)->setValue(experience_name_string); +} + +LLPanelExperienceListEditor::~LLPanelExperienceListEditor() +{ + if(!mPicker.isDead()) + { + mPicker.get()->close(); + } +} + +void LLPanelExperienceListEditor::loading() +{ + mItems->clear(); + mItems->setCommentText( getString("loading")); +} + +void LLPanelExperienceListEditor::setReadonly( bool val ) +{ + mReadonly = val; + checkButtonsEnabled(); +} + +void LLPanelExperienceListEditor::refreshExperienceCounter() +{ + if(mMaxExperienceIDs > 0) + { + LLStringUtil::format_map_t args; + args["[EXPERIENCES]"] = llformat("%d", mItems->getItemCount()); + args["[MAXEXPERIENCES]"] = llformat("%d", mMaxExperienceIDs); + getChild("text_count")->setText(LLTrans::getString("ExperiencesCounter", args)); + } +} + +boost::signals2::connection LLPanelExperienceListEditor::setAddedCallback( list_changed_signal_t::slot_type cb ) +{ + return mAddedCallback.connect(cb); +} + +boost::signals2::connection LLPanelExperienceListEditor::setRemovedCallback( list_changed_signal_t::slot_type cb ) +{ + return mRemovedCallback.connect(cb); +} + diff --git a/indra/newview/llpanelexperiencelisteditor.h b/indra/newview/llpanelexperiencelisteditor.h new file mode 100644 index 0000000000..38b2c2179c --- /dev/null +++ b/indra/newview/llpanelexperiencelisteditor.h @@ -0,0 +1,102 @@ +/** +* @file llpanelexperiencelisteditor.cpp +* @brief Editor for building a list of experiences +* +* $LicenseInfo:firstyear=2014&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLPANELEXPERIENCELISTEDITOR_H +#define LL_LLPANELEXPERIENCELISTEDITOR_H + +#include "llpanel.h" +#include "lluuid.h" +#include + +class LLNameListCtrl; +class LLScrollListCtrl; +class LLButton; +class LLFloaterExperiencePicker; + +void* create_xp_list_editor(void* data); // +class LLPanelExperienceListEditor final : public LLPanel +{ +public: + + typedef boost::signals2::signal list_changed_signal_t; + // filter function for experiences, return true if the experience should be hidden. + typedef std::function experience_function; + typedef std::vector filter_list; + typedef LLHandle PickerHandle; + LLPanelExperienceListEditor(); + ~LLPanelExperienceListEditor(); + BOOL postBuild() override; + + void loading(); + + const uuid_list_t& getExperienceIds()const; + void setExperienceIds(const LLSD& experience_ids); + void addExperienceIds(const uuid_vec_t& experience_ids); + + void addExperience(const LLUUID& id); + + boost::signals2::connection setAddedCallback(list_changed_signal_t::slot_type cb ); + boost::signals2::connection setRemovedCallback(list_changed_signal_t::slot_type cb ); + + bool getReadonly() const { return mReadonly; } + void setReadonly(bool val); + + void refreshExperienceCounter(); + + void addFilter(experience_function func){mFilters.push_back(func);} + void setStickyFunction(experience_function func){mSticky = func;} + U32 getMaxExperienceIDs() const { return mMaxExperienceIDs; } + void setMaxExperienceIDs(U32 val) { mMaxExperienceIDs = val; } +private: + + void onItems(); + void onRemove(); + void onAdd(); + void onProfile(); + + void checkButtonsEnabled(); + static void experienceDetailsCallback( LLHandle panel, const LLSD& experience ); + void onExperienceDetails( const LLSD& experience ); + void processResponse( const LLSD& content ); + uuid_list_t mExperienceIds; + + + LLScrollListCtrl* mItems; + filter_list mFilters; + LLButton* mAdd; + LLButton* mRemove; + LLButton* mProfile; + PickerHandle mPicker; + list_changed_signal_t mAddedCallback; + list_changed_signal_t mRemovedCallback; + LLUUID mKey; + bool mReadonly; + experience_function mSticky; + U32 mMaxExperienceIDs; + +}; + +#endif //LL_LLPANELEXPERIENCELISTEDITOR_H diff --git a/indra/newview/llpanelexperiencelog.cpp b/indra/newview/llpanelexperiencelog.cpp new file mode 100644 index 0000000000..fb866261a2 --- /dev/null +++ b/indra/newview/llpanelexperiencelog.cpp @@ -0,0 +1,270 @@ +/** + * @file llpanelexperiencelog.cpp + * @brief llpanelexperiencelog + * + * $LicenseInfo:firstyear=2014&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2014, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + + +#include "llviewerprecompiledheaders.h" +#include "llpanelexperiencelog.h" + +#include "llexperiencelog.h" +#include "llexperiencecache.h" +#include "llbutton.h" +#include "llscrolllistctrl.h" +#include "llcombobox.h" +#include "llspinctrl.h" +#include "llcheckboxctrl.h" +#include "llfloaterexperienceprofile.h" +//#include "llfloaterreg.h" +#include "lluictrlfactory.h" +#include "llfloaterreporter.h" +#include "llinventoryfunctions.h" + +#include + + +#define BTN_PROFILE_XP "btn_profile_xp" +#define BTN_REPORT_XP "btn_report_xp" + +/* Singu Note: We do not have injectors, so we'll have to call this function instead +static LLPanelInjector register_experiences_panel("experience_log"); +*/ +void* create_xp_log(void* data) { return new LLPanelExperienceLog(false); } + + +LLPanelExperienceLog::LLPanelExperienceLog(bool build) + : mEventList(nullptr) + , mPageSize(25) + , mCurrentPage(0) +{ + //buildFromFile("panel_experience_log.xml"); + if (build) LLUICtrlFactory::getInstance()->buildPanel(this, "panel_experience_log.xml"); // Singu Note: Use filename in xml +} + +BOOL LLPanelExperienceLog::postBuild( void ) +{ + LLExperienceLog* log = LLExperienceLog::getInstance(); + mEventList = getChild("experience_log_list"); + mEventList->setCommitCallback(boost::bind(&LLPanelExperienceLog::onSelectionChanged, this)); + mEventList->setDoubleClickCallback( boost::bind(&LLPanelExperienceLog::onProfileExperience, this)); + + getChild("btn_clear")->setCommitCallback(boost::bind(&LLExperienceLog::clear, log)); + getChild("btn_clear")->setCommitCallback(boost::bind(&LLPanelExperienceLog::refresh, this)); + + getChild(BTN_PROFILE_XP)->setCommitCallback(boost::bind(&LLPanelExperienceLog::onProfileExperience, this)); + getChild(BTN_REPORT_XP )->setCommitCallback(boost::bind(&LLPanelExperienceLog::onReportExperience, this)); + getChild("btn_notify" )->setCommitCallback(boost::bind(&LLPanelExperienceLog::onNotify, this)); + getChild("btn_next" )->setCommitCallback(boost::bind(&LLPanelExperienceLog::onNext, this)); + getChild("btn_prev" )->setCommitCallback(boost::bind(&LLPanelExperienceLog::onPrev, this)); + + LLCheckBoxCtrl* check = getChild("notify_all"); + check->set(log->getNotifyNewEvent()); + check->setCommitCallback(boost::bind(&LLPanelExperienceLog::notifyChanged, this)); + + + LLSpinCtrl* spin = getChild("logsizespinner"); + spin->set(log->getMaxDays()); + spin->setCommitCallback(boost::bind(&LLPanelExperienceLog::logSizeChanged, this)); + + mPageSize = log->getPageSize(); + refresh(); + mNewEvent = LLExperienceLog::instance().addUpdateSignal(boost::bind(&LLPanelExperienceLog::refresh, this)); + return TRUE; +} + +LLPanelExperienceLog* LLPanelExperienceLog::create() +{ + return new LLPanelExperienceLog(); +} + +void LLPanelExperienceLog::refresh() +{ + S32 selected = mEventList->getFirstSelectedIndex(); + mEventList->deleteAllItems(); + const LLSD events = LLExperienceLog::instance().getEvents(); + + if(events.size() == 0) + { + mEventList->setCommentText(getString("no_events")); + return; + } + + setAllChildrenEnabled(FALSE); + + LLSD item; + bool waiting = false; + LLUUID waiting_id; + + U32 itemsToSkip = mPageSize*mCurrentPage; + U32 items = 0; + bool moreItems = false; + + if (!events.emptyMap()) + { + for (const auto& day : boost::adaptors::reverse(events.map())) + { + const std::string& date = day.first; + if (LLExperienceLog::instance().isExpired(date)) + { + continue; + } + const LLSD& dayArray = day.second; + U32 size = dayArray.size(); + if(itemsToSkip > size) + { + itemsToSkip -= size; + continue; + } + if(items >= mPageSize && size > 0) + { + moreItems = true; + break; + } + for(int i = dayArray.size() - itemsToSkip - 1; i >= 0; i--) + { + if (items >= mPageSize) + { + moreItems = true; + break; + } + const LLSD event = dayArray[i]; + LLUUID id = event[LLExperienceCache::EXPERIENCE_ID].asUUID(); + const LLSD& experience = LLExperienceCache::instance().get(id); + if(experience.isUndefined()){ + waiting = true; + waiting_id = id; + } + if(!waiting) + { + item["id"] = event; + + LLSD& columns = item["columns"]; + columns[0]["column"] = "time"; + columns[0]["value"] = day.first+event["Time"].asString(); + columns[1]["column"] = "event"; + columns[1]["value"] = LLExperienceLog::getPermissionString(event, "ExperiencePermissionShort"); + columns[2]["column"] = "experience_name"; + columns[2]["value"] = experience[LLExperienceCache::NAME].asString(); + columns[3]["column"] = "object_name"; + columns[3]["value"] = event["ObjectName"].asString(); + mEventList->addElement(item); + } + ++items; + } + } + } + if (waiting) + { + mEventList->deleteAllItems(); + mEventList->setCommentText(getString("loading")); + LLExperienceCache::instance().get(waiting_id, boost::bind(&LLPanelExperienceLog::refresh, this)); + } + else + { + setAllChildrenEnabled(TRUE); + + mEventList->setEnabled(TRUE); + getChild("btn_next")->setEnabled(moreItems); + getChild("btn_prev")->setEnabled(mCurrentPage>0); + getChild("btn_clear")->setEnabled(mEventList->getItemCount()>0); + if (selected < 0) + { + selected = 0; + } + mEventList->selectNthItem(selected); + onSelectionChanged(); + } +} + +void LLPanelExperienceLog::onProfileExperience() +{ + LLSD event = getSelectedEvent(); + if (event.isDefined()) + { + LLFloaterExperienceProfile::showInstance(event[LLExperienceCache::EXPERIENCE_ID].asUUID()); + } +} + +void LLPanelExperienceLog::onReportExperience() +{ + LLSD event = getSelectedEvent(); + if (event.isDefined()) + { + LLFloaterReporter::showFromExperience(event[LLExperienceCache::EXPERIENCE_ID].asUUID()); + } +} + +void LLPanelExperienceLog::onNotify() +{ + LLSD event = getSelectedEvent(); + if (event.isDefined()) + { + LLExperienceLog::instance().notify(event); + } +} + +void LLPanelExperienceLog::onNext() +{ + mCurrentPage++; + refresh(); +} + +void LLPanelExperienceLog::onPrev() +{ + if(mCurrentPage>0) + { + mCurrentPage--; + refresh(); + } +} + +void LLPanelExperienceLog::notifyChanged() +{ + LLExperienceLog::instance().setNotifyNewEvent(getChild("notify_all")->get()); +} + +void LLPanelExperienceLog::logSizeChanged() +{ + int value = (int)(getChild("logsizespinner")->get()); + LLExperienceLog::instance().setMaxDays(value); + refresh(); +} + +void LLPanelExperienceLog::onSelectionChanged() +{ + bool enabled = (1 == mEventList->getNumSelected()); + getChild(BTN_REPORT_XP)->setEnabled(enabled); + getChild(BTN_PROFILE_XP)->setEnabled(enabled); + getChild("btn_notify")->setEnabled(enabled); +} + +LLSD LLPanelExperienceLog::getSelectedEvent() +{ + LLScrollListItem* item = mEventList->getFirstSelected(); + if(item) + { + return item->getValue(); + } + return LLSD(); +} diff --git a/indra/newview/llpanelexperiencelog.h b/indra/newview/llpanelexperiencelog.h new file mode 100644 index 0000000000..03e50a6045 --- /dev/null +++ b/indra/newview/llpanelexperiencelog.h @@ -0,0 +1,65 @@ +/** + * @file llpanelexperiencelog.h + * @brief llpanelexperiencelog and related class definitions + * + * $LicenseInfo:firstyear=2014&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2014, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + + +#ifndef LL_LLPANELEXPERIENCELOG_H +#define LL_LLPANELEXPERIENCELOG_H + +#include "llpanel.h" +class LLScrollListCtrl; + +void* create_xp_log(void* data); +class LLPanelExperienceLog final + : public LLPanel +{ +public: + + LLPanelExperienceLog(bool build = true); + + static LLPanelExperienceLog* create(); + + /*virtual*/ BOOL postBuild(void) override; + + void refresh() override; +protected: + void logSizeChanged(); + void notifyChanged(); + void onNext(); + void onNotify(); + void onPrev(); + void onProfileExperience(); + void onReportExperience(); + void onSelectionChanged(); + + LLSD getSelectedEvent(); +private: + LLScrollListCtrl* mEventList; + U32 mPageSize; + U32 mCurrentPage; + boost::signals2::scoped_connection mNewEvent; +}; + +#endif // LL_LLPANELEXPERIENCELOG_H diff --git a/indra/newview/llpanelexperiencepicker.cpp b/indra/newview/llpanelexperiencepicker.cpp new file mode 100644 index 0000000000..d27393d255 --- /dev/null +++ b/indra/newview/llpanelexperiencepicker.cpp @@ -0,0 +1,453 @@ +/** +* @file llpanelexperiencepicker.cpp +* @brief Implementation of llpanelexperiencepicker +* @author dolphin@lindenlab.com +* +* $LicenseInfo:firstyear=2014&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2014, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#include "llviewerprecompiledheaders.h" + +#include "llpanelexperiencepicker.h" + + +#include "lllineeditor.h" +#include "llfloaterexperienceprofile.h" +#include "llfloaterexperiences.h" +//#include "llfloaterreg.h" +#include "lluictrlfactory.h" +#include "llscrolllistctrl.h" +#include "llviewerregion.h" +#include "llagent.h" +#include "llexperiencecache.h" +#include "llslurl.h" +#include "llavatarnamecache.h" +#include "llcombobox.h" +#include "llviewercontrol.h" +#include "llfloater.h" +#include "lltrans.h" +#include + +#define BTN_FIND "find" +#define BTN_OK "ok_btn" +#define BTN_CANCEL "cancel_btn" +#define BTN_PROFILE "profile_btn" +#define BTN_LEFT "left_btn" +#define BTN_RIGHT "right_btn" +#define TEXT_EDIT "edit" +#define TEXT_MATURITY "maturity" +#define LIST_RESULTS "search_results" +#define PANEL_SEARCH "search_panel" + +const static std::string columnSpace = " "; + +/* Singu Note: We do not have injectors, so we'll have to call this function instead +static LLPanelInjector t_panel_status("llpanelexperiencepicker"); +*/ + +LLPanelExperiencePicker::LLPanelExperiencePicker() + :LLPanel() +{ + //buildFromFile("panel_experience_search.xml"); + LLUICtrlFactory::getInstance()->buildPanel(this, "panel_experience_search.xml"); // Singu Note: Use filename in xml + setDefaultFilters(); +} + +LLPanelExperiencePicker::~LLPanelExperiencePicker() +{ +} + +BOOL LLPanelExperiencePicker::postBuild() +{ + getChild(TEXT_EDIT)->setKeystrokeCallback(boost::bind(&LLPanelExperiencePicker::editKeystroke, this, _1)); + + childSetAction(BTN_FIND, boost::bind(&LLPanelExperiencePicker::onBtnFind, this)); + getChildView(BTN_FIND)->setEnabled(TRUE); + + LLScrollListCtrl* searchresults = getChild(LIST_RESULTS); + searchresults->setDoubleClickCallback( boost::bind(&LLPanelExperiencePicker::onBtnSelect, this)); + searchresults->setCommitCallback(boost::bind(&LLPanelExperiencePicker::onList, this)); + getChildView(LIST_RESULTS)->setEnabled(FALSE); + getChild(LIST_RESULTS)->setCommentText(getString("no_results")); + + childSetAction(BTN_OK, boost::bind(&LLPanelExperiencePicker::onBtnSelect, this)); + getChildView(BTN_OK)->setEnabled(FALSE); + childSetAction(BTN_CANCEL, boost::bind(&LLPanelExperiencePicker::onBtnClose, this)); + childSetAction(BTN_PROFILE, boost::bind(&LLPanelExperiencePicker::onBtnProfile, this)); + getChildView(BTN_PROFILE)->setEnabled(FALSE); + + getChild(TEXT_MATURITY)->setCurrentByIndex(2); + getChild(TEXT_MATURITY)->setCommitCallback(boost::bind(&LLPanelExperiencePicker::onMaturity, this)); + getChild(TEXT_EDIT)->setFocus(TRUE); + + childSetAction(BTN_LEFT, boost::bind(&LLPanelExperiencePicker::onPage, this, -1)); + childSetAction(BTN_RIGHT, boost::bind(&LLPanelExperiencePicker::onPage, this, 1)); + + LLPanel* search_panel = getChild(PANEL_SEARCH); + if (search_panel) + { + // Start searching when Return is pressed in the line editor. + search_panel->setDefaultBtn(BTN_FIND); + } + return TRUE; +} + +void LLPanelExperiencePicker::editKeystroke(class LLLineEditor* caller) +{ + getChildView(BTN_FIND)->setEnabled(!caller->getText().empty()); +} + +void LLPanelExperiencePicker::onBtnFind() +{ + mCurrentPage=1; + boost::cmatch what; + std::string text = getChild(TEXT_EDIT)->getValue().asString(); + // *TODO: this should be part of LLUrlEntry + static const boost::regex expression("secondlife:///app/experience/[\\da-f-]+/profile"); + if (boost::regex_match(text.c_str(), what, expression)) + { + LLURI uri(text); + LLSD path_array = uri.pathArray(); + if (path_array.size() == 4) + { + std::string exp_id = path_array.get(2).asString(); + LLUUID experience_id(exp_id); + if (!experience_id.isNull()) + { + const LLSD& experience_details = LLExperienceCache::instance().get(experience_id); + if(!experience_details.isUndefined()) + { + std::string experience_name_string = experience_details[LLExperienceCache::NAME].asString(); + if(!experience_name_string.empty()) + { + getChild(TEXT_EDIT)->setValue(experience_name_string); + } + } + else + { + getChild(LIST_RESULTS)->deleteAllItems(); + getChild(LIST_RESULTS)->setCommentText(getString("searching")); + + getChildView(BTN_OK)->setEnabled(FALSE); + getChildView(BTN_PROFILE)->setEnabled(FALSE); + + getChildView(BTN_RIGHT)->setEnabled(FALSE); + getChildView(BTN_LEFT)->setEnabled(FALSE); + LLExperienceCache::instance().get(experience_id, boost::bind(&LLPanelExperiencePicker::onBtnFind, this)); + return; + } + } + } + } + + + find(); +} + +void LLPanelExperiencePicker::onList() +{ + bool enabled = isSelectButtonEnabled(); + getChildView(BTN_OK)->setEnabled(enabled); + + enabled = enabled && getChild(LIST_RESULTS)->getNumSelected() == 1; + getChildView(BTN_PROFILE)->setEnabled(enabled); +} + +void LLPanelExperiencePicker::find() +{ + std::string text = getChild(TEXT_EDIT)->getValue().asString(); + mQueryID.generate(); + + LLExperienceCache::instance().findExperienceByName(text, mCurrentPage, + boost::bind(&LLPanelExperiencePicker::findResults, getDerivedHandle(), mQueryID, _1)); + + getChild(LIST_RESULTS)->deleteAllItems(); + getChild(LIST_RESULTS)->setCommentText(getString("searching")); + + getChildView(BTN_OK)->setEnabled(FALSE); + getChildView(BTN_PROFILE)->setEnabled(FALSE); + + getChildView(BTN_RIGHT)->setEnabled(FALSE); + getChildView(BTN_LEFT)->setEnabled(FALSE); +} + +/*static*/ +void LLPanelExperiencePicker::findResults(LLHandle hparent, LLUUID queryId, LLSD foundResult) +{ + if (hparent.isDead()) + return; + + LLPanelExperiencePicker* panel = hparent.get(); + if (panel) + { + panel->processResponse(queryId, foundResult); + } +} + +bool LLPanelExperiencePicker::isSelectButtonEnabled() +{ + LLScrollListCtrl* list=getChild(LIST_RESULTS); + return list->getFirstSelectedIndex() >=0; +} + +void LLPanelExperiencePicker::getSelectedExperienceIds( const LLScrollListCtrl* results, uuid_vec_t &experience_ids ) +{ + std::vector items = results->getAllSelected(); + for(std::vector::iterator it = items.begin(); it != items.end(); ++it) + { + LLScrollListItem* item = *it; + if (item->getUUID().notNull()) + { + experience_ids.push_back(item->getUUID()); + } + } +} + +void LLPanelExperiencePicker::setAllowMultiple( bool allow_multiple ) +{ + getChild(LIST_RESULTS)->setAllowMultipleSelection(allow_multiple); +} + + +void name_callback(const LLHandle& floater, const LLUUID& experience_id, const LLUUID& agent_id, const LLAvatarName& av_name) +{ + if (floater.isDead()) + return; + LLPanelExperiencePicker* picker = floater.get(); + LLScrollListCtrl* search_results = picker->getChild(LIST_RESULTS); + + LLScrollListItem* item = search_results->getItem(experience_id); + if (!item) + return; + + item->getColumn(2)->setValue(columnSpace+av_name.getNSName()); + +} + +void LLPanelExperiencePicker::processResponse( const LLUUID& query_id, const LLSD& content ) +{ + if (query_id != mQueryID) + { + return; + } + + mResponse = content; + + getChildView(BTN_RIGHT)->setEnabled(content.has("next_page_url")); + getChildView(BTN_LEFT)->setEnabled(content.has("previous_page_url")); + + filterContent(); + +} + +void LLPanelExperiencePicker::onBtnSelect() +{ + if (!isSelectButtonEnabled()) + { + return; + } + + if(mSelectionCallback != nullptr) + { + const LLScrollListCtrl* results = getChild(LIST_RESULTS); + uuid_vec_t experience_ids; + + getSelectedExperienceIds(results, experience_ids); + mSelectionCallback(experience_ids); + getChild(LIST_RESULTS)->deselectAllItems(TRUE); + if (mCloseOnSelect) + { + mCloseOnSelect = FALSE; + onBtnClose(); + } + } + else + { + onBtnProfile(); + } +} + +void LLPanelExperiencePicker::onBtnClose() +{ + LLFloater* floater = mSelectionCallback ? static_cast(getParent()) : LLFloaterExperiences::findInstance(); + if (floater) + { + floater->close(); + } +} + +void LLPanelExperiencePicker::onBtnProfile() +{ + LLScrollListItem* item = getChild(LIST_RESULTS)->getFirstSelected(); + if (item) + { + LLFloaterExperienceProfile::showInstance(item->getUUID()); + } +} + +std::string LLPanelExperiencePicker::getMaturityString(int maturity) +{ + if (maturity <= SIM_ACCESS_PG) + { + return getString("maturity_icon_general"); + } + else if (maturity <= SIM_ACCESS_MATURE) + { + return getString("maturity_icon_moderate"); + } + return getString("maturity_icon_adult"); +} + +void LLPanelExperiencePicker::filterContent() +{ + LLScrollListCtrl* search_results = getChild(LIST_RESULTS); + + const LLSD& experiences=mResponse["experience_keys"]; + + search_results->deleteAllItems(); + + LLSD item; + for (const auto& experience : experiences.array()) + { + if (isExperienceHidden(experience)) + continue; + + std::string experience_name_string = experience[LLExperienceCache::NAME].asString(); + if (experience_name_string.empty()) + { + experience_name_string = LLTrans::getString("ExperienceNameUntitled"); + } + + item["id"]=experience[LLExperienceCache::EXPERIENCE_ID]; + LLSD& columns = item["columns"]; + columns[0]["column"] = "maturity"; + columns[0]["value"] = getMaturityString(experience[LLExperienceCache::MATURITY].asInteger()); + columns[0]["type"]="icon"; + columns[0]["halign"]="right"; + columns[1]["column"] = "experience_name"; + columns[1]["value"] = columnSpace+experience_name_string; + columns[2]["column"] = "owner"; + columns[2]["value"] = columnSpace+getString("loading"); + search_results->addElement(item); + LLAvatarNameCache::get(experience[LLExperienceCache::AGENT_ID], boost::bind(name_callback, getDerivedHandle(), experience[LLExperienceCache::EXPERIENCE_ID], _1, _2)); + } + + if (search_results->isEmpty()) + { + LLStringUtil::format_map_t map; + std::string search_text = getChild(TEXT_EDIT)->getValue().asString(); + map["[TEXT]"] = search_text; + if (search_text.empty()) + { + getChild(LIST_RESULTS)->setCommentText(getString("no_results")); + } + else + { + getChild(LIST_RESULTS)->setCommentText(getString("not_found", map)); + } + search_results->setEnabled(false); + getChildView(BTN_OK)->setEnabled(false); + getChildView(BTN_PROFILE)->setEnabled(false); + } + else + { + getChildView(BTN_OK)->setEnabled(true); + search_results->setEnabled(true); + search_results->sortByColumnIndex(1, TRUE); + std::string text = getChild(TEXT_EDIT)->getValue().asString(); + if (!search_results->selectItemByLabel(text, TRUE)) + { + search_results->selectFirstItem(); + } + onList(); + search_results->setFocus(TRUE); + } +} + +void LLPanelExperiencePicker::onMaturity() +{ + if (mResponse.has("experience_keys") && mResponse["experience_keys"].beginArray() != mResponse["experience_keys"].endArray()) + { + filterContent(); + } +} + +bool LLPanelExperiencePicker::isExperienceHidden( const LLSD& experience) const +{ + bool hide=false; + filter_list::const_iterator it = mFilters.begin(); + for(/**/;it != mFilters.end(); ++it) + { + if ((*it)(experience)){ + return true; + } + } + + return hide; +} + +bool LLPanelExperiencePicker::FilterOverRating( const LLSD& experience ) +{ + int maturity = getChild(TEXT_MATURITY)->getSelectedValue().asInteger(); + return experience[LLExperienceCache::MATURITY].asInteger() > maturity; +} + +bool LLPanelExperiencePicker::FilterWithProperty( const LLSD& experience, S32 prop) +{ + return (experience[LLExperienceCache::PROPERTIES].asInteger() & prop) != 0; +} + +bool LLPanelExperiencePicker::FilterWithoutProperties( const LLSD& experience, S32 prop) +{ + return ((experience[LLExperienceCache::PROPERTIES].asInteger() & prop) == prop); +} + +bool LLPanelExperiencePicker::FilterWithoutProperty( const LLSD& experience, S32 prop ) +{ + return (experience[LLExperienceCache::PROPERTIES].asInteger() & prop) == 0; +} + +void LLPanelExperiencePicker::setDefaultFilters() +{ + mFilters.clear(); + addFilter(boost::bind(&LLPanelExperiencePicker::FilterOverRating, this, _1)); +} + +bool LLPanelExperiencePicker::FilterMatching( const LLSD& experience, const LLUUID& id ) +{ + if (experience.isUUID()) + { + return experience.asUUID() == id; + } + return experience[LLExperienceCache::EXPERIENCE_ID].asUUID() == id; +} + +void LLPanelExperiencePicker::onPage( S32 direction ) +{ + mCurrentPage += direction; + if (mCurrentPage < 1) + { + mCurrentPage = 1; + } + find(); +} + diff --git a/indra/newview/llpanelexperiencepicker.h b/indra/newview/llpanelexperiencepicker.h new file mode 100644 index 0000000000..1af7fe108b --- /dev/null +++ b/indra/newview/llpanelexperiencepicker.h @@ -0,0 +1,95 @@ +/** +* @file llpanelexperiencepicker.h +* @brief Header file for llpanelexperiencepicker +* @author dolphin@lindenlab.com +* +* $LicenseInfo:firstyear=2014&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2014, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ +#ifndef LL_LLPANELEXPERIENCEPICKER_H +#define LL_LLPANELEXPERIENCEPICKER_H + +#include "llpanel.h" + +class LLScrollListCtrl; +class LLLineEditor; + +class LLPanelExperiencePicker final : public LLPanel +{ +public: + friend class LLExperienceSearchResponder; + friend class LLFloaterExperiencePicker; + + typedef std::function select_callback_t; + // filter function for experiences, return true if the experience should be hidden. + typedef std::function filter_function; + typedef std::vector filter_list; + + LLPanelExperiencePicker(); + virtual ~LLPanelExperiencePicker(); + + BOOL postBuild() override; + + void addFilter(filter_function func){mFilters.push_back(func);} + template + void addFilters(IT begin, IT end){mFilters.insert(mFilters.end(), begin, end);} + void setDefaultFilters(); + + static bool FilterWithProperty(const LLSD& experience, S32 prop); + static bool FilterWithoutProperties(const LLSD& experience, S32 prop); + static bool FilterWithoutProperty(const LLSD& experience, S32 prop); + static bool FilterMatching(const LLSD& experience, const LLUUID& id); + bool FilterOverRating(const LLSD& experience); + +private: + void editKeystroke(LLLineEditor* caller); + + void onBtnFind(); + void onBtnSelect(); + void onBtnClose(); + void onBtnProfile(); + void onList(); + void onMaturity(); + void onPage(S32 direction); + + void getSelectedExperienceIds( const LLScrollListCtrl* results, uuid_vec_t &experience_ids ); + void setAllowMultiple(bool allow_multiple); + + void find(); + static void findResults(LLHandle hparent, LLUUID queryId, LLSD foundResult); + + bool isSelectButtonEnabled(); + void processResponse( const LLUUID& query_id, const LLSD& content ); + + void filterContent(); + bool isExperienceHidden(const LLSD& experience) const ; + std::string getMaturityString(int maturity); + + + select_callback_t mSelectionCallback; + filter_list mFilters; + LLUUID mQueryID; + LLSD mResponse; + bool mCloseOnSelect; + S32 mCurrentPage; +}; + +#endif // LL_LLPANELEXPERIENCEPICKER_H diff --git a/indra/newview/llpanelexperiences.cpp b/indra/newview/llpanelexperiences.cpp new file mode 100644 index 0000000000..97473a006b --- /dev/null +++ b/indra/newview/llpanelexperiences.cpp @@ -0,0 +1,152 @@ +/** + * @file llpanelexperiences.cpp + * @brief LLPanelExperiences class implementation + * + * $LicenseInfo:firstyear=2013&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2013, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + + +#include "llviewerprecompiledheaders.h" + + +#include "lluictrlfactory.h" +#include "llexperiencecache.h" +#include "llagent.h" + +#include "llfloaterexperienceprofile.h" +#include "llpanelexperiences.h" +#include "lllayoutstack.h" +#include "llnamelistctrl.h" + +//static LLPanelInjector register_experiences_panel("experiences_panel"); + +LLPanelExperiences::LLPanelExperiences() + : mExperiencesList(nullptr) +{ + //buildFromFile("panel_experiences.xml"); + LLUICtrlFactory::getInstance()->buildPanel(this, "panel_experiences.xml"); +} + +BOOL LLPanelExperiences::postBuild( void ) +{ + mExperiencesList = getChild("experiences_list"); + if (hasString("loading_experiences")) + { + mExperiencesList->setCommentText(getString("loading_experiences")); + } + else if (hasString("no_experiences")) + { + mExperiencesList->setCommentText(getString("no_experiences")); + } + + return TRUE; +} + +void addExperienceToList(const LLSD& experience, LLNameListCtrl* list) +{ + // Don't add missing experiences, that seems wrong + if (experience.has(LLExperienceCache::MISSING) && experience[LLExperienceCache::MISSING].asBoolean()) + return; + + const auto& id = experience[LLExperienceCache::EXPERIENCE_ID]; + list->removeNameItem(id); // Don't add the same item twice, this can happen + auto item = LLNameListCtrl::NameItem() + .name(experience[LLExperienceCache::NAME].asString()) + .target(LLNameListItem::EXPERIENCE); + item.value(id) + .columns.add(LLScrollListCell::Params()); // Dummy column for names + list->addNameItemRow(item); +} + +void LLPanelExperiences::setExperienceList( const LLSD& experiences ) +{ + mExperiencesList->setSortEnabled(false); + + if (hasString("no_experiences")) + { + mExperiencesList->setCommentText(getString("no_experiences")); + } + mExperiencesList->clear(); + + auto& cache = LLExperienceCache::instance(); + for(const auto& exp : experiences.array()) + { + LLUUID public_key = exp.asUUID(); + if (public_key.notNull()) + cache.get(public_key, boost::bind(addExperienceToList, _1, mExperiencesList)); + } + + mExperiencesList->setSortEnabled(true); +} + +void LLPanelExperiences::getExperienceIdsList(uuid_vec_t& result) +{ + result = mExperiencesList->getAllIDs(); +} + +LLPanelExperiences* LLPanelExperiences::create(const std::string& name) +{ + LLPanelExperiences* panel= new LLPanelExperiences(); + panel->setName(name); + return panel; +} + +void LLPanelExperiences::removeExperiences( const LLSD& ids ) +{ + for (const auto& id : ids.array()) + { + removeExperience(id.asUUID()); + } +} + +void LLPanelExperiences::removeExperience( const LLUUID& id ) +{ + mExperiencesList->removeNameItem(id); +} + +void LLPanelExperiences::addExperience( const LLUUID& id ) +{ + if (!mExperiencesList->getItem(id)) + { + LLExperienceCache::instance().get(id, boost::bind(addExperienceToList, _1, mExperiencesList)); + } +} + +void LLPanelExperiences::setButtonAction(const std::string& label, const commit_signal_t::slot_type& cb ) +{ + if(label.empty()) + { + getChild("button_panel")->setVisible(false); + } + else + { + getChild("button_panel")->setVisible(true); + LLButton* child = getChild("btn_action"); + child->setCommitCallback(cb); + child->setLabel(getString(label)); + } +} + +void LLPanelExperiences::enableButton( bool enable ) +{ + getChild("btn_action")->setEnabled(enable); +} diff --git a/indra/newview/llpanelexperiences.h b/indra/newview/llpanelexperiences.h new file mode 100644 index 0000000000..31e9d1a002 --- /dev/null +++ b/indra/newview/llpanelexperiences.h @@ -0,0 +1,54 @@ +/** + * @file llpanelexperiences.h + * @brief LLPanelExperiences class definition + * + * $LicenseInfo:firstyear=2013&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2013, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLPANELEXPERIENCES_H +#define LL_LLPANELEXPERIENCES_H + +#include "llpanel.h" + +class LLPanelExperiences final + : public LLPanel +{ +public: + LLPanelExperiences(); + + static LLPanelExperiences* create(const std::string& name); + + /*virtual*/ BOOL postBuild(void) override; + + void setExperienceList(const LLSD& experiences); + void getExperienceIdsList(uuid_vec_t& result); + + void removeExperiences( const LLSD& ids ); + void removeExperience( const LLUUID& id); + void addExperience( const LLUUID& id); + void setButtonAction(const std::string& label, const commit_signal_t::slot_type& cb); + void enableButton(bool enable); + +private: + class LLNameListCtrl* mExperiencesList; +}; +#endif // LL_LLPANELEXPERIENCES_H diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index 78ae39ddac..8c6f103367 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -53,6 +53,7 @@ #include "llface.h" #include "llinventorymodel.h" //Perms check for texture params #include "lllineeditor.h" +#include "llmaterialmgr.h" #include "llmediaentry.h" #include "llnotificationsutil.h" #include "llresmgr.h" @@ -62,6 +63,7 @@ #include "lltexturectrl.h" #include "lltextureentry.h" #include "lltooldraganddrop.h" +#include "lltrans.h" #include "llui.h" #include "llviewercontrol.h" #include "llviewermedia.h" @@ -71,43 +73,138 @@ #include "llvovolume.h" #include "lluictrlfactory.h" #include "llpluginclassmedia.h" -#include "llviewertexturelist.h" +#include "llviewertexturelist.h"// Update sel manager as to which channel we're editing so it can reflect the correct overlay UI // -// Methods +// Constant definitions for comboboxes +// Must match the commbobox definitions in panel_tools_texture.xml // +const S32 MATMEDIA_MATERIAL = 0; // Material +const S32 MATMEDIA_MEDIA = 1; // Media +const S32 MATTYPE_DIFFUSE = 0; // Diffuse material texture +const S32 MATTYPE_NORMAL = 1; // Normal map +const S32 MATTYPE_SPECULAR = 2; // Specular map +const S32 ALPHAMODE_NONE = 0; // No alpha mask applied +const S32 ALPHAMODE_BLEND = 1; // Alpha blending mode +const S32 ALPHAMODE_MASK = 2; // Alpha masking mode +const S32 BUMPY_TEXTURE = 18; // use supplied normal map +const S32 SHINY_TEXTURE = 4; // use supplied specular map -BOOL LLPanelFace::postBuild() +// +// "Use texture" label for normal/specular type comboboxes +// Filled in at initialization from translated strings +// +std::string USE_TEXTURE; + +LLRender::eTexIndex LLPanelFace::getTextureChannelToEdit() { - childSetCommitCallback("combobox shininess",&LLPanelFace::onCommitShiny,this); - childSetCommitCallback("combobox bumpiness",&LLPanelFace::onCommitBump,this); - - childSetCommitCallback("TexScaleU",&LLPanelFace::onCommitTextureInfo, this); - childSetCommitCallback("checkbox flip s",&LLPanelFace::onCommitTextureInfo, this); - childSetCommitCallback("TexScaleV",&LLPanelFace::onCommitTextureInfo, this); - childSetCommitCallback("checkbox flip t",&LLPanelFace::onCommitTextureInfo, this); - childSetCommitCallback("TexRot",&LLPanelFace::onCommitTextureInfo, this); - childSetAction("button apply",&LLPanelFace::onClickApply,this); - childSetCommitCallback("checkbox planar align",&LLPanelFace::onCommitPlanarAlign, this); - childSetCommitCallback("TexOffsetU",LLPanelFace::onCommitTextureInfo, this); - childSetCommitCallback("TexOffsetV",LLPanelFace::onCommitTextureInfo, this); - childSetAction("button align",&LLPanelFace::onClickAutoFix,this); - childSetAction("copytextures",&LLPanelFace::onClickCopy,this); - childSetAction("pastetextures",&LLPanelFace::onClickPaste,this); - - LLTextureCtrl* mTextureCtrl; - LLColorSwatchCtrl* mColorSwatch; +// + LLRender::eTexIndex channel_to_edit = (mComboMatMedia && mComboMatMedia->getCurrentIndex() == MATMEDIA_MATERIAL) ? + (mComboMatType ? (LLRender::eTexIndex)mComboMatType->getCurrentIndex() : LLRender::DIFFUSE_MAP) : LLRender::DIFFUSE_MAP; + + channel_to_edit = (channel_to_edit == LLRender::NORMAL_MAP) ? (getCurrentNormalMap().isNull() ? LLRender::DIFFUSE_MAP : channel_to_edit) : channel_to_edit; + channel_to_edit = (channel_to_edit == LLRender::SPECULAR_MAP) ? (getCurrentSpecularMap().isNull() ? LLRender::DIFFUSE_MAP : channel_to_edit) : channel_to_edit; + return channel_to_edit; +// +} - LLComboBox* mComboTexGen; +// Things the UI provides... +// +// +LLUUID LLPanelFace::getCurrentNormalMap() { return mBumpyTextureCtrl->getImageAssetID(); } +LLUUID LLPanelFace::getCurrentSpecularMap() { return mShinyTextureCtrl->getImageAssetID(); } +U8 LLPanelFace::getCurrentDiffuseAlphaMode() { return (U8)mComboAlpha->getCurrentIndex(); } +// - LLCheckBoxCtrl *mCheckFullbright; - - LLTextBox* mLabelColorTransp; - LLSpinCtrl* mCtrlColorTransp; // transparency = 1 - alpha +// +// Methods +// - LLSpinCtrl* mCtrlGlow; +BOOL LLPanelFace::postBuild() +{ + // Media button caching + mMediaInfo = getChildView("media_info"); + mMediaAdd = getChildView("add_media"); + mMediaDelete = getChildView("delete_media"); + + // Label caching + mLabelGlossy = getChildView("label glossiness"); + mLabelEnvironment = getChildView("label environment"); + mLabelShinyColor = getChildView("label shinycolor"); + mLabelAlphaMode = getChildView("label alphamode"); + mLabelMaskCutoff = getChildView("label maskcutoff"); + mLabelBumpy = getChildView("label bumpiness"); + mLabelShiny = getChildView("label shininess"); + mLabelColor = getChildView("color label"); + mLabelGlow = getChildView("glow label"); + mLabelTexGen = getChildView("tex gen"); + + // UICtrl Caching + mComboShiny = getChild("combobox shininess"); + mComboBumpy = getChild("combobox bumpiness"); + mComboAlpha = getChild("combobox alphamode"); + mCtrlTexScaleU = getChild("TexScaleU"); + mCtrlFlipTexScaleU = getChild("flipTextureScaleU"); + mCtrlTexScaleV = getChild("TexScaleV"); + mCtrlFlipTexScaleV = getChild("flipTextureScaleV"); + mCtrlTexRot = getChild("TexRot"); + mCtrlRpt = getChild("rptctrl"); + mCtrlPlanar = getChild("checkbox planar align"); + mCtrlTexOffsetU = getChild("TexOffsetU"); + mCtrlTexOffsetV = getChild("TexOffsetV"); + mBumpyScaleU = getChild("bumpyScaleU"); + mBumpyScaleV = getChild("bumpyScaleV"); + mBumpyRot = getChild("bumpyRot"); + mBumpyOffsetU = getChild("bumpyOffsetU"); + mBumpyOffsetV = getChild("bumpyOffsetV"); + mShinyScaleU = getChild("shinyScaleU"); + mShinyScaleV = getChild("shinyScaleV"); + mShinyRot = getChild("shinyRot"); + mShinyOffsetU = getChild("shinyOffsetU"); + mShinyOffsetV = getChild("shinyOffsetV"); + mGlossyCtrl = getChild("glossiness"); + mEnvironmentCtrl = getChild("environment"); + mCtrlMaskCutoff = getChild("maskcutoff"); + mCtrlAlign = getChild("button align"); + mCtrlMapsSync = getChild("checkbox maps sync"); + mCtrlCopy = getChild("copytextures"); + mCtrlPaste = getChild("pastetextures"); + + mComboShiny->setCommitCallback(boost::bind(&LLPanelFace::sendShiny, this, boost::bind(&LLComboBox::getCurrentIndex, mComboShiny))); + mComboBumpy->setCommitCallback(boost::bind(&LLPanelFace::sendBump, this, boost::bind(&LLComboBox::getCurrentIndex, mComboBumpy))); + mComboAlpha->setCommitCallback(boost::bind(&LLPanelFace::onCommitAlphaMode, this)); + mCtrlTexScaleU->setCommitCallback(boost::bind(&LLPanelFace::onCommitTextureInfo, this)); + mCtrlFlipTexScaleU->setCommitCallback(boost::bind(&LLPanelFace::onCommitFlip, this, true)); + mCtrlTexScaleV->setCommitCallback(boost::bind(&LLPanelFace::onCommitTextureInfo, this)); + mCtrlFlipTexScaleV->setCommitCallback(boost::bind(&LLPanelFace::onCommitFlip, this, false)); + mCtrlTexRot->setCommitCallback(boost::bind(&LLPanelFace::onCommitTextureInfo, this)); + mCtrlRpt->setCommitCallback(boost::bind(&LLPanelFace::onCommitRepeatsPerMeter, this, _1)); + mCtrlPlanar->setCommitCallback(boost::bind(&LLPanelFace::onCommitPlanarAlign, this)); + mCtrlTexOffsetU->setCommitCallback(boost::bind(&LLPanelFace::onCommitTextureInfo, this)); + mCtrlTexOffsetV->setCommitCallback(boost::bind(&LLPanelFace::onCommitTextureInfo, this)); + + mBumpyScaleU->setCommitCallback(boost::bind(&LLPanelFace::onCommitMaterialBumpyScaleX, this, _2)); + mBumpyScaleV->setCommitCallback(boost::bind(&LLPanelFace::onCommitMaterialBumpyScaleY, this, _2)); + mBumpyRot->setCommitCallback(boost::bind(&LLPanelFace::onCommitMaterialBumpyRot, this, _2)); + mBumpyOffsetU->setCommitCallback(boost::bind(LLSelectedTEMaterial::setNormalOffsetX, this, _2)); + mBumpyOffsetV->setCommitCallback(boost::bind(LLSelectedTEMaterial::setNormalOffsetY, this, _2)); + mShinyScaleU->setCommitCallback(boost::bind(&LLPanelFace::onCommitMaterialShinyScaleX, this, _2)); + mShinyScaleV->setCommitCallback(boost::bind(&LLPanelFace::onCommitMaterialShinyScaleY, this, _2)); + mShinyRot->setCommitCallback(boost::bind(&LLPanelFace::onCommitMaterialShinyRot, this, _2)); + mShinyOffsetU->setCommitCallback(boost::bind(LLSelectedTEMaterial::setSpecularOffsetX, this, _2)); + mShinyOffsetV->setCommitCallback(boost::bind(LLSelectedTEMaterial::setSpecularOffsetY, this, _2)); + mGlossyCtrl->setCommitCallback(boost::bind(LLSelectedTEMaterial::setSpecularLightExponent, this, boost::bind(&LLSD::asInteger, _2))); + mEnvironmentCtrl->setCommitCallback(boost::bind(LLSelectedTEMaterial::setEnvironmentIntensity, this, boost::bind(&LLSD::asInteger, _2))); + mCtrlMaskCutoff->setCommitCallback(boost::bind(LLSelectedTEMaterial::setAlphaMaskCutoff, this, boost::bind(&LLSD::asInteger, _2))); + + mCtrlAlign->setCommitCallback(boost::bind(&LLPanelFace::onClickAutoFix,this)); + + mCtrlMapsSync->setCommitCallback(boost::bind(&LLPanelFace::onClickMapsSync, this)); + mCtrlCopy->setCommitCallback(boost::bind(&LLPanelFace::onClickCopy,this)); + mCtrlPaste->setCommitCallback(boost::bind(&LLPanelFace::onClickPaste,this)); setMouseOpaque(FALSE); + mTextureCtrl = getChild("texture control"); if(mTextureCtrl) { @@ -116,33 +213,54 @@ BOOL LLPanelFace::postBuild() mTextureCtrl->setOnCancelCallback( boost::bind(&LLPanelFace::onCancelTexture, this, _2) ); mTextureCtrl->setOnSelectCallback( boost::bind(&LLPanelFace::onSelectTexture, this, _2) ); mTextureCtrl->setDragCallback(boost::bind(&LLPanelFace::onDragTexture, this, _2)); + mTextureCtrl->setOnTextureSelectedCallback(boost::bind(&LLPanelFace::onTextureSelectionChanged, this, _1)); + mTextureCtrl->setOnCloseCallback( boost::bind(&LLPanelFace::onCloseTexturePicker, this, _2) ); + mTextureCtrl->setFollowsTop(); mTextureCtrl->setFollowsLeft(); - // Don't allow (no copy) or (no transfer) textures to be selected during immediate mode - mTextureCtrl->setImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER); - // Allow any texture to be used during non-immediate mode. - mTextureCtrl->setNonImmediateFilterPermMask(PERM_NONE); - LLAggregatePermissions texture_perms; - if (LLSelectMgr::getInstance()->selectGetAggregateTexturePermissions(texture_perms)) - { - BOOL can_copy = - texture_perms.getValue(PERM_COPY) == LLAggregatePermissions::AP_EMPTY || - texture_perms.getValue(PERM_COPY) == LLAggregatePermissions::AP_ALL; - BOOL can_transfer = - texture_perms.getValue(PERM_TRANSFER) == LLAggregatePermissions::AP_EMPTY || - texture_perms.getValue(PERM_TRANSFER) == LLAggregatePermissions::AP_ALL; - mTextureCtrl->setCanApplyImmediately(can_copy && can_transfer); - } - else - { - mTextureCtrl->setCanApplyImmediately(FALSE); - } + mTextureCtrl->setImmediateFilterPermMask(PERM_NONE); + mTextureCtrl->setDnDFilterPermMask(PERM_COPY | PERM_TRANSFER); + } + + mShinyTextureCtrl = getChild("shinytexture control"); + if(mShinyTextureCtrl) + { + mShinyTextureCtrl->setDefaultImageAssetID(LLUUID( gSavedSettings.getString( "DefaultObjectSpecularTexture" ))); + mShinyTextureCtrl->setCommitCallback( boost::bind(&LLPanelFace::onCommitSpecularTexture, this, _2) ); + mShinyTextureCtrl->setOnCancelCallback( boost::bind(&LLPanelFace::onCancelSpecularTexture, this, _2) ); + mShinyTextureCtrl->setOnSelectCallback( boost::bind(&LLPanelFace::onSelectSpecularTexture, this, _2) ); + mShinyTextureCtrl->setOnCloseCallback( boost::bind(&LLPanelFace::onCloseTexturePicker, this, _2) ); + + mShinyTextureCtrl->setDragCallback(boost::bind(&LLPanelFace::onDragTexture, this, _2)); + mShinyTextureCtrl->setOnTextureSelectedCallback(boost::bind(&LLPanelFace::onTextureSelectionChanged, this, _1)); + mShinyTextureCtrl->setFollowsTop(); + mShinyTextureCtrl->setFollowsLeft(); + mShinyTextureCtrl->setImmediateFilterPermMask(PERM_NONE); + mShinyTextureCtrl->setDnDFilterPermMask(PERM_COPY | PERM_TRANSFER); + } + + mBumpyTextureCtrl = getChild("bumpytexture control"); + if(mBumpyTextureCtrl) + { + mBumpyTextureCtrl->setDefaultImageAssetID(LLUUID( gSavedSettings.getString( "DefaultObjectNormalTexture" ))); + mBumpyTextureCtrl->setBlankImageAssetID(LLUUID( gSavedSettings.getString( "DefaultBlankNormalTexture" ))); + mBumpyTextureCtrl->setCommitCallback( boost::bind(&LLPanelFace::onCommitNormalTexture, this, _2) ); + mBumpyTextureCtrl->setOnCancelCallback( boost::bind(&LLPanelFace::onCancelNormalTexture, this, _2) ); + mBumpyTextureCtrl->setOnSelectCallback( boost::bind(&LLPanelFace::onSelectNormalTexture, this, _2) ); + mBumpyTextureCtrl->setOnCloseCallback( boost::bind(&LLPanelFace::onCloseTexturePicker, this, _2) ); + + mBumpyTextureCtrl->setDragCallback(boost::bind(&LLPanelFace::onDragTexture, this, _2)); + mBumpyTextureCtrl->setOnTextureSelectedCallback(boost::bind(&LLPanelFace::onTextureSelectionChanged, this, _1)); + mBumpyTextureCtrl->setFollowsTop(); + mBumpyTextureCtrl->setFollowsLeft(); + mBumpyTextureCtrl->setImmediateFilterPermMask(PERM_NONE); + mBumpyTextureCtrl->setDnDFilterPermMask(PERM_COPY | PERM_TRANSFER); } mColorSwatch = getChild("colorswatch"); if(mColorSwatch) { - mColorSwatch->setCommitCallback(boost::bind(&LLPanelFace::onCommitColor, this, _2)); + mColorSwatch->setCommitCallback(boost::bind(&LLPanelFace::sendColor, this)); mColorSwatch->setOnCancelCallback(boost::bind(&LLPanelFace::onCancelColor, this, _2)); mColorSwatch->setOnSelectCallback(boost::bind(&LLPanelFace::onSelectColor, this, _2)); mColorSwatch->setFollowsTop(); @@ -150,6 +268,15 @@ BOOL LLPanelFace::postBuild() mColorSwatch->setCanApplyImmediately(TRUE); } + mShinyColorSwatch = getChild("shinycolorswatch"); + if(mShinyColorSwatch) + { + mShinyColorSwatch->setCommitCallback(boost::bind(&LLPanelFace::onCommitShinyColor, this, _2)); + mShinyColorSwatch->setFollowsTop(); + mShinyColorSwatch->setFollowsLeft(); + mShinyColorSwatch->setCanApplyImmediately(TRUE); + } + mLabelColorTransp = getChild("color trans"); if(mLabelColorTransp) { @@ -160,7 +287,7 @@ BOOL LLPanelFace::postBuild() mCtrlColorTransp = getChild("ColorTrans"); if(mCtrlColorTransp) { - mCtrlColorTransp->setCommitCallback(boost::bind(&LLPanelFace::onCommitAlpha, this, _2)); + mCtrlColorTransp->setCommitCallback(boost::bind(&LLPanelFace::sendAlpha, this)); mCtrlColorTransp->setPrecision(0); mCtrlColorTransp->setFollowsTop(); mCtrlColorTransp->setFollowsLeft(); @@ -169,22 +296,36 @@ BOOL LLPanelFace::postBuild() mCheckFullbright = getChild("checkbox fullbright"); if (mCheckFullbright) { - mCheckFullbright->setCommitCallback(LLPanelFace::onCommitFullbright, this); + mCheckFullbright->setCommitCallback(boost::bind(&LLPanelFace::sendFullbright, this)); } mComboTexGen = getChild("combobox texgen"); if(mComboTexGen) { - mComboTexGen->setCommitCallback(LLPanelFace::onCommitTexGen, this); + mComboTexGen->setCommitCallback(boost::bind(&LLPanelFace::sendTexGen, this)); mComboTexGen->setFollows(FOLLOWS_LEFT | FOLLOWS_TOP); } + mComboMatMedia = getChild("combobox matmedia"); + if(mComboMatMedia) + { + mComboMatMedia->setCommitCallback(boost::bind(&LLPanelFace::onCommitMaterialsMedia,this)); + mComboMatMedia->selectNthItem(MATMEDIA_MATERIAL); + } + + mComboMatType = getChild("combobox mattype"); + if(mComboMatType) + { + mComboMatType->setCommitCallback(boost::bind(&LLPanelFace::onCommitMaterialType, this)); + mComboMatType->selectNthItem(MATTYPE_DIFFUSE); + } + mCtrlGlow = getChild("glow"); if(mCtrlGlow) { - mCtrlGlow->setCommitCallback(LLPanelFace::onCommitGlow, this); + mCtrlGlow->setCommitCallback(boost::bind(&LLPanelFace::sendGlow, this)); } - + clearCtrls(); @@ -192,8 +333,66 @@ BOOL LLPanelFace::postBuild() } LLPanelFace::LLPanelFace(const std::string& name) -: LLPanel(name) +: LLPanel(name), +// + mMediaInfo(NULL), + mMediaAdd(NULL), + mMediaDelete(NULL), + mLabelGlossy(NULL), + mLabelEnvironment(NULL), + mLabelShinyColor(NULL), + mLabelAlphaMode(NULL), + mLabelMaskCutoff(NULL), + mLabelBumpy(NULL), + mLabelShiny(NULL), + mLabelColor(NULL), + mLabelGlow(NULL), + mLabelTexGen(NULL), + mComboShiny(NULL), + mComboBumpy(NULL), + mComboAlpha(NULL), + mCtrlTexScaleU(NULL), + mCtrlFlipTexScaleU(NULL), + mCtrlTexScaleV(NULL), + mCtrlFlipTexScaleV(NULL), + mCtrlTexRot(NULL), + mCtrlRpt(NULL), + mCtrlPlanar(NULL), + mCtrlTexOffsetU(NULL), + mCtrlTexOffsetV(NULL), + mBumpyScaleU(NULL), + mBumpyScaleV(NULL), + mBumpyRot(NULL), + mBumpyOffsetU(NULL), + mBumpyOffsetV(NULL), + mShinyScaleU(NULL), + mShinyScaleV(NULL), + mShinyRot(NULL), + mShinyOffsetU(NULL), + mShinyOffsetV(NULL), + mGlossyCtrl(NULL), + mEnvironmentCtrl(NULL), + mCtrlMaskCutoff(NULL), + mCtrlAlign(NULL), + mCtrlMapsSync(NULL), + mCtrlCopy(NULL), + mCtrlPaste(NULL), + mTextureCtrl(NULL), + mShinyTextureCtrl(NULL), + mBumpyTextureCtrl(NULL), + mColorSwatch(NULL), + mShinyColorSwatch(NULL), + mComboTexGen(NULL), + mComboMatMedia(NULL), + mComboMatType(NULL), + mCheckFullbright(NULL), + mLabelColorTransp(NULL), + mCtrlColorTransp(NULL), // transparency = 1 - alpha + mCtrlGlow(NULL), +// + mIsAlpha(false) { + USE_TEXTURE = LLTrans::getString("use_texture"); } @@ -205,7 +404,6 @@ LLPanelFace::~LLPanelFace() void LLPanelFace::sendTexture() { - LLTextureCtrl* mTextureCtrl = getChild("texture control"); if(!mTextureCtrl) return; if( !mTextureCtrl->getTentative() ) { @@ -220,33 +418,67 @@ void LLPanelFace::sendTexture() } } -void LLPanelFace::sendBump() +void LLPanelFace::sendBump(U32 bumpiness) { - LLComboBox* mComboBumpiness = getChild("combobox bumpiness"); - if(!mComboBumpiness)return; - U8 bump = (U8) mComboBumpiness->getCurrentIndex() & TEM_BUMP_MASK; + LLTextureCtrl* bumpytexture_ctrl = mBumpyTextureCtrl; + if (bumpiness < BUMPY_TEXTURE) + { + LL_DEBUGS("Materials") << "clearing bumptexture control" << LL_ENDL; + bumpytexture_ctrl->clear(); + bumpytexture_ctrl->setImageAssetID(LLUUID()); + } + + updateBumpyControls(bumpiness == BUMPY_TEXTURE, true); + + LLUUID current_normal_map = bumpytexture_ctrl->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 ); } void LLPanelFace::sendTexGen() { - LLComboBox* mComboTexGen = getChild("combobox texgen"); if(!mComboTexGen)return; U8 tex_gen = (U8) mComboTexGen->getCurrentIndex() << TEM_TEX_GEN_SHIFT; LLSelectMgr::getInstance()->selectionSetTexGen( tex_gen ); } -void LLPanelFace::sendShiny() +void LLPanelFace::sendShiny(U32 shininess) { - LLComboBox* mComboShininess = getChild("combobox shininess"); - if(!mComboShininess)return; - U8 shiny = (U8) mComboShininess->getCurrentIndex() & TEM_SHINY_MASK; + LLTextureCtrl* texture_ctrl = mShinyTextureCtrl; + + if (shininess < SHINY_TEXTURE) + { + texture_ctrl->clear(); + texture_ctrl->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 ); + + updateShinyControls(!specmap.isNull(), true); + } void LLPanelFace::sendFullbright() { - LLCheckBoxCtrl* mCheckFullbright = getChild("checkbox fullbright"); if(!mCheckFullbright)return; U8 fullbright = mCheckFullbright->get() ? TEM_FULLBRIGHT_MASK : 0; LLSelectMgr::getInstance()->selectionSetFullbright( fullbright ); @@ -254,8 +486,6 @@ void LLPanelFace::sendFullbright() void LLPanelFace::sendColor() { - - LLColorSwatchCtrl* mColorSwatch = getChild("colorswatch"); if(!mColorSwatch)return; LLColor4 color = mColorSwatch->get(); @@ -264,7 +494,6 @@ void LLPanelFace::sendColor() void LLPanelFace::sendAlpha() { - LLSpinCtrl* mCtrlColorTransp = getChild("ColorTrans"); if(!mCtrlColorTransp)return; F32 alpha = (100.f - mCtrlColorTransp->get()) / 100.f; @@ -274,7 +503,6 @@ void LLPanelFace::sendAlpha() void LLPanelFace::sendGlow() { - LLSpinCtrl* mCtrlGlow = getChild("glow"); llassert(mCtrlGlow); if (mCtrlGlow) { @@ -290,26 +518,21 @@ struct LLPanelFaceSetTEFunctor : public LLSelectedTEFunctor { BOOL valid; F32 value; - LLSpinCtrl* ctrlTexScaleS = mPanel->getChild("TexScaleU"); - LLSpinCtrl* ctrlTexScaleT = mPanel->getChild("TexScaleV"); - LLSpinCtrl* ctrlTexOffsetS = mPanel->getChild("TexOffsetU"); - LLSpinCtrl* ctrlTexOffsetT = mPanel->getChild("TexOffsetV"); - LLSpinCtrl* ctrlTexRotation = mPanel->getChild("TexRot"); - LLCheckBoxCtrl* checkFlipScaleS = mPanel->getChild("checkbox flip s"); - LLCheckBoxCtrl* checkFlipScaleT = mPanel->getChild("checkbox flip t"); - LLComboBox* comboTexGen = mPanel->getChild("combobox texgen"); + LLSpinCtrl* ctrlTexScaleS = mPanel->mCtrlTexScaleU; + LLSpinCtrl* ctrlTexScaleT = mPanel->mCtrlTexScaleV; + LLSpinCtrl* ctrlTexOffsetS = mPanel->mCtrlTexOffsetU; + LLSpinCtrl* ctrlTexOffsetT = mPanel->mCtrlTexOffsetV; + LLSpinCtrl* ctrlTexRotation = mPanel->mCtrlTexRot; + LLComboBox* comboTexGen = mPanel->mComboTexGen; llassert(comboTexGen); llassert(object); + if (ctrlTexScaleS) { - valid = !ctrlTexScaleS->getTentative() || !checkFlipScaleS->getTentative(); + valid = !ctrlTexScaleS->getTentative(); if (valid) { value = ctrlTexScaleS->get(); - if( checkFlipScaleS->get() ) - { - value = -value; - } if (comboTexGen && comboTexGen->getCurrentIndex() == 1) { @@ -321,14 +544,10 @@ struct LLPanelFaceSetTEFunctor : public LLSelectedTEFunctor if (ctrlTexScaleT) { - valid = !ctrlTexScaleT->getTentative() || !checkFlipScaleT->getTentative(); + valid = !ctrlTexScaleT->getTentative(); if (valid) { value = ctrlTexScaleT->get(); - if( checkFlipScaleT->get() ) - { - value = -value; - } if (comboTexGen && comboTexGen->getCurrentIndex() == 1) { @@ -456,10 +675,10 @@ struct LLPanelFaceGetIsAlignedTEFunctor : public LLSelectedTEFunctor tep->getScale(&st_scale.mV[VX], &st_scale.mV[VY]); F32 st_rot = tep->getRotation(); // needs a fuzzy comparison, because of fp errors - if (is_approx_equal_fraction(st_offset.mV[VX], aligned_st_offset.mV[VX], 16) && - is_approx_equal_fraction(st_offset.mV[VY], aligned_st_offset.mV[VY], 16) && - is_approx_equal_fraction(st_scale.mV[VX], aligned_st_scale.mV[VX], 16) && - is_approx_equal_fraction(st_scale.mV[VY], aligned_st_scale.mV[VY], 16) && + if (is_approx_equal_fraction(st_offset.mV[VX], aligned_st_offset.mV[VX], 12) && + is_approx_equal_fraction(st_offset.mV[VY], aligned_st_offset.mV[VY], 12) && + is_approx_equal_fraction(st_scale.mV[VX], aligned_st_scale.mV[VX], 12) && + is_approx_equal_fraction(st_scale.mV[VY], aligned_st_scale.mV[VY], 12) && is_approx_equal_fraction(st_rot, aligned_st_rot, 14)) { return true; @@ -482,18 +701,11 @@ struct LLPanelFaceSendFunctor : public LLSelectedObjectFunctor void LLPanelFace::sendTextureInfo() { - if ((bool)childGetValue("checkbox planar align").asBoolean()) + if ((bool)mCtrlPlanar->getValue().asBoolean()) { - struct f1 : public LLSelectedTEGetFunctor - { - LLFace* get(LLViewerObject* object, S32 te) - { - return (object->mDrawable) ? object->mDrawable->getFace(te): NULL; - } - } get_last_face_func; - LLFace* last_face(NULL); - LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue(&get_last_face_func, last_face); - + LLFace* last_face = NULL; + bool identical_face = false; + LLSelectedTE::getFace(last_face, identical_face); LLPanelFaceSetAlignedTEFunctor setfunc(this, last_face); LLSelectMgr::getInstance()->getSelection()->applyToTEs(&setfunc); } @@ -509,8 +721,13 @@ void LLPanelFace::sendTextureInfo() void LLPanelFace::getState() { + updateUI(); +} + +void LLPanelFace::updateUI() +{ //set state of UI to match state of texture entry(ies) (calls setEnabled, setValue, etc, but NOT setVisible) LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); - LLCalc* calcp = LLCalc::getInstance(); + if( objectp && objectp->getPCode() == LL_PCODE_VOLUME && objectp->permModify()) @@ -518,269 +735,66 @@ void LLPanelFace::getState() BOOL editable = objectp->permModify() && !objectp->isPermanentEnforced(); // only turn on auto-adjust button if there is a media renderer and the media is loaded - getChildView("button align")->setEnabled(editable); - - //if ( LLMediaEngine::getInstance()->getMediaRenderer () ) - // if ( LLMediaEngine::getInstance()->getMediaRenderer ()->isLoaded () ) - // { - // - // //mLabelTexAutoFix->setEnabled ( editable ); - // - // //mBtnAutoFix->setEnabled ( editable ); - // } + mCtrlAlign->setEnabled(editable); + + bool enable_material_controls = (!gSavedSettings.getBOOL("FSSynchronizeTextureMaps")); S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount(); BOOL single_volume = (LLSelectMgr::getInstance()->selectionAllPCode( LL_PCODE_VOLUME )) && (selected_count == 1); - childSetEnabled("copytextures", single_volume && editable); - childSetEnabled("pastetextures", single_volume && editable); - childSetEnabled("textbox params", single_volume && editable); - getChildView("button apply")->setEnabled(editable); + mCtrlCopy->setEnabled(single_volume && editable); + mCtrlPaste->setEnabled(editable); - bool identical; - LLTextureCtrl* texture_ctrl = getChild("texture control"); - texture_ctrl->setFallbackImageName( "" ); //Singu Note: Don't show the 'locked' image when the texid is null. - // Texture + LLComboBox* combobox_matmedia = mComboMatMedia; + if (combobox_matmedia) { - LLUUID id; - struct f1 : public LLSelectedTEGetFunctor - { - LLUUID get(LLViewerObject* object, S32 te_index) - { - LLUUID id; - //LLViewerTexture* image = object->getTEImage(te); - LLTextureEntry* image = object->getTE(te_index); //Singu Note: Use this instead of the above. - //The above actually returns LLViewerFetchedTexture::sDefaultImagep when - //the texture id is null, which gives us IMG_DEFAULT, not LLUUID::null - //Such behavior prevents the 'None' button from ever greying out in the face panel. - if (image) id = image->getID(); - - if (!id.isNull() && LLViewerMedia::textureHasMedia(id)) - { - LLTextureEntry *te = object->getTE(te_index); - if (te) - { - LLViewerTexture* tex = te->getID().notNull() ? gTextureList.findImage(te->getID()) : NULL ; - if(!tex) - { - tex = LLViewerFetchedTexture::sDefaultImagep; - } - if (tex) - { - id = tex->getID(); - } - } - } - return id; - } - } func; - identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, id ); - - if(LLViewerMedia::textureHasMedia(id)) + if (combobox_matmedia->getCurrentIndex() < MATMEDIA_MATERIAL) { - getChildView("button align")->setEnabled(editable); - } - - if (identical) - { - // All selected have the same texture - if(texture_ctrl) - { - texture_ctrl->setTentative( FALSE ); - texture_ctrl->setEnabled( editable ); - texture_ctrl->setImageAssetID( id ); - } - } - else - { - if(texture_ctrl) - { - if( id.isNull() ) - { - // None selected - texture_ctrl->setTentative( FALSE ); - texture_ctrl->setEnabled( FALSE ); - texture_ctrl->setImageAssetID( LLUUID::null ); - } - else - { - // Tentative: multiple selected with different textures - texture_ctrl->setTentative( TRUE ); - texture_ctrl->setEnabled( editable ); - texture_ctrl->setImageAssetID( id ); - } - } + combobox_matmedia->selectNthItem(MATMEDIA_MATERIAL); } } + mComboMatMedia->setEnabled(editable); - - LLAggregatePermissions texture_perms; - if(texture_ctrl) + LLComboBox* combobox_mattype = mComboMatType; + if (combobox_mattype) { -// texture_ctrl->setValid( editable ); - - if (LLSelectMgr::getInstance()->selectGetAggregateTexturePermissions(texture_perms)) - { - BOOL can_copy = - texture_perms.getValue(PERM_COPY) == LLAggregatePermissions::AP_EMPTY || - texture_perms.getValue(PERM_COPY) == LLAggregatePermissions::AP_ALL; - BOOL can_transfer = - texture_perms.getValue(PERM_TRANSFER) == LLAggregatePermissions::AP_EMPTY || - texture_perms.getValue(PERM_TRANSFER) == LLAggregatePermissions::AP_ALL; - texture_ctrl->setCanApplyImmediately(can_copy && can_transfer); - } - else + if (combobox_mattype->getCurrentIndex() < MATTYPE_DIFFUSE) { - texture_ctrl->setCanApplyImmediately(FALSE); + combobox_mattype->selectNthItem(MATTYPE_DIFFUSE); } } + mComboMatType->setEnabled(editable); + updateVisibility(); - // planar align - bool align_planar = false; - bool identical_planar_aligned = false; - bool is_planar = false; - { - LLCheckBoxCtrl* cb_planar_align = getChild("checkbox planar align"); - align_planar = (cb_planar_align && cb_planar_align->get()); - struct f1 : public LLSelectedTEGetFunctor - { - bool get(LLViewerObject* object, S32 face) - { - return (object->getTE(face)->getTexGen() == LLTextureEntry::TEX_GEN_PLANAR); - } - } func; - - bool texgens_identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, is_planar ); - bool enabled = (editable && texgens_identical && is_planar); - childSetValue("checkbox planar align", align_planar && enabled); - childSetEnabled("checkbox planar align", enabled); - - if (align_planar && enabled) - { - struct f2 : public LLSelectedTEGetFunctor - { - LLFace* get(LLViewerObject* object, S32 te) - { - return (object->mDrawable) ? object->mDrawable->getFace(te): NULL; - } - } get_te_face_func; - LLFace* last_face(NULL); - LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue(&get_te_face_func, last_face); - LLPanelFaceGetIsAlignedTEFunctor 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); - } - } - - // Texture scale - { - getChildView("tex scale")->setEnabled(editable); - //mLabelTexScale->setEnabled( editable ); - F32 scale_s = 1.f; - struct f2 : public LLSelectedTEGetFunctor - { - F32 get(LLViewerObject* object, S32 face) - { - return object->getTE(face)->mScaleS; - } - } func; - identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, scale_s ); - identical = align_planar ? identical_planar_aligned : identical; - getChild("TexScaleU")->setValue(editable ? llabs(scale_s) : 0); - getChild("TexScaleU")->setTentative(LLSD((BOOL)(!identical))); - getChildView("TexScaleU")->setEnabled(editable); - getChild("checkbox flip s")->setValue(LLSD((BOOL)(scale_s < 0 ? TRUE : FALSE ))); - getChild("checkbox flip s")->setTentative(LLSD((BOOL)((!identical) ? TRUE : FALSE ))); - getChildView("checkbox flip s")->setEnabled(editable); - } - - { - F32 scale_t = 1.f; - struct f3 : public LLSelectedTEGetFunctor - { - F32 get(LLViewerObject* object, S32 face) - { - return object->getTE(face)->mScaleT; - } - } func; - identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, scale_t ); - identical = align_planar ? identical_planar_aligned : identical; + bool identical = true; // true because it is anded below + bool identical_diffuse = false; + bool identical_norm = false; + bool identical_spec = false; - getChild("TexScaleV")->setValue(llabs(editable ? llabs(scale_t) : 0)); - getChild("TexScaleV")->setTentative(LLSD((BOOL)(!identical))); - getChildView("TexScaleV")->setEnabled(editable); - getChild("checkbox flip t")->setValue(LLSD((BOOL)(scale_t< 0 ? TRUE : FALSE ))); - getChild("checkbox flip t")->setTentative(LLSD((BOOL)((!identical) ? TRUE : FALSE ))); - getChildView("checkbox flip t")->setEnabled(editable); - } + LLTextureCtrl* texture_ctrl = mTextureCtrl; + texture_ctrl->setFallbackImageName( "" ); //Singu Note: Don't show the 'locked' image when the texid is null. + LLTextureCtrl* shinytexture_ctrl = mShinyTextureCtrl; + shinytexture_ctrl->setFallbackImageName( "" ); //Singu Note: Don't show the 'locked' image when the texid is null. + LLTextureCtrl* bumpytexture_ctrl = mBumpyTextureCtrl; + bumpytexture_ctrl->setFallbackImageName( "" ); //Singu Note: Don't show the 'locked' image when the texid is null. - // Texture offset - { - getChildView("tex offset")->setEnabled(editable); - F32 offset_s = 0.f; - struct f4 : public LLSelectedTEGetFunctor - { - F32 get(LLViewerObject* object, S32 face) - { - return object->getTE(face)->mOffsetS; - } - } func; - identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, offset_s ); - identical = align_planar ? identical_planar_aligned : identical; - getChild("TexOffsetU")->setValue(editable ? offset_s : 0); - getChild("TexOffsetU")->setTentative(!identical); - getChildView("TexOffsetU")->setEnabled(editable); - } + LLUUID id; + LLUUID normmap_id; + LLUUID specmap_id; + // Color swatch { - F32 offset_t = 0.f; - struct f5 : public LLSelectedTEGetFunctor - { - F32 get(LLViewerObject* object, S32 face) - { - return object->getTE(face)->mOffsetT; - } - } func; - identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, offset_t ); - identical = align_planar ? identical_planar_aligned : identical; - getChild("TexOffsetV")->setValue(editable ? offset_t : 0); - getChild("TexOffsetV")->setTentative(!identical); - getChildView("TexOffsetV")->setEnabled(editable); + mLabelColor->setEnabled(editable); } - // Texture rotation - { - getChildView("tex rotate")->setEnabled(editable); - F32 rotation = 0.f; - struct f6 : public LLSelectedTEGetFunctor - { - F32 get(LLViewerObject* object, S32 face) - { - return object->getTE(face)->mRotation; - } - } func; - identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, rotation ); - identical = align_planar ? identical_planar_aligned : identical; - getChild("TexRot")->setValue(editable ? rotation * RAD_TO_DEG : 0); - getChild("TexRot")->setTentative(!identical); - getChildView("TexRot")->setEnabled(editable); - } + LLColor4 color = LLColor4::white; + bool identical_color =false; - // Color swatch - LLColorSwatchCtrl* mColorSwatch = getChild("colorswatch"); - LLColor4 color = LLColor4::white; if(mColorSwatch) { - struct f7 : public LLSelectedTEGetFunctor - { - LLColor4 get(LLViewerObject* object, S32 face) - { - return object->getTE(face)->getColor(); - } - } func; - identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, color ); - + LLSelectedTE::getColor(color, identical_color); + mColorSwatch->setOriginal(color); mColorSwatch->set(color, TRUE); @@ -788,183 +802,666 @@ void LLPanelFace::getState() mColorSwatch->setEnabled( editable ); mColorSwatch->setCanApplyImmediately( editable ); } + // Color transparency - { - getChildView("color trans")->setEnabled(editable); - } + mLabelColorTransp->setEnabled(editable); F32 transparency = (1.f - color.mV[VALPHA]) * 100.f; + mCtrlColorTransp->setValue(editable ? transparency : 0); + mCtrlColorTransp->setEnabled(editable); + + // Specular map + LLSelectedTEMaterial::getSpecularID(specmap_id, identical_spec); + + U8 shiny = 0; + bool identical_shiny = false; + + // Shiny + LLSelectedTE::getShiny(shiny, identical_shiny); + identical = identical && identical_shiny; + + shiny = specmap_id.isNull() ? shiny : SHINY_TEXTURE; + + if (mComboShiny) { - getChild("ColorTrans")->setValue(editable ? transparency : 0); - getChildView("ColorTrans")->setEnabled(editable); + mComboShiny->selectNthItem((S32)shiny); } - { - F32 glow = 0.f; - struct f8 : public LLSelectedTEGetFunctor - { - F32 get(LLViewerObject* object, S32 face) - { - return object->getTE(face)->getGlow(); - } - } func; - identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, glow ); + mLabelShiny->setEnabled(editable); + mComboShiny->setEnabled(editable); + + mLabelGlossy->setEnabled(editable); + mGlossyCtrl->setEnabled(editable); + + mLabelEnvironment->setEnabled(editable); + mEnvironmentCtrl->setEnabled(editable); + mLabelShinyColor->setEnabled(editable); - getChild("glow")->setValue(glow); - getChildView("glow")->setEnabled(editable); - getChild("glow")->setTentative(!identical); - getChildView("glow label")->setEnabled(editable); + mComboShiny->setTentative(!identical_spec); + mGlossyCtrl->setTentative(!identical_spec); + mEnvironmentCtrl->setTentative(!identical_spec); + mShinyColorSwatch->setTentative(!identical_spec); + if(mShinyColorSwatch) + { + mShinyColorSwatch->setValid(editable); + mShinyColorSwatch->setEnabled( editable ); + mShinyColorSwatch->setCanApplyImmediately( editable ); } - // Bump + U8 bumpy = 0; + // Bumpy { - F32 shinyf = 0.f; - struct f9 : public LLSelectedTEGetFunctor - { - F32 get(LLViewerObject* object, S32 face) - { - return (F32)(object->getTE(face)->getShiny()); - } - } func; - identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, shinyf ); - LLCtrlSelectionInterface* combobox_shininess = - childGetSelectionInterface("combobox shininess"); - if (combobox_shininess) - { - combobox_shininess->selectNthItem((S32)shinyf); - } - else + bool identical_bumpy = false; + LLSelectedTE::getBumpmap(bumpy,identical_bumpy); + + LLUUID norm_map_id = getCurrentNormalMap(); + LLCtrlSelectionInterface* combobox_bumpiness = mComboBumpy; + + bumpy = norm_map_id.isNull() ? bumpy : BUMPY_TEXTURE; + + if (combobox_bumpiness) { - llwarns << "failed childGetSelectionInterface for 'combobox shininess'" << llendl; + combobox_bumpiness->selectNthItem((S32)bumpy); } - getChildView("combobox shininess")->setEnabled(editable); - getChild("combobox shininess")->setTentative(!identical); - getChildView("label shininess")->setEnabled(editable); + + mComboBumpy->setEnabled(editable); + mComboBumpy->setTentative(!identical_bumpy); + mLabelBumpy->setEnabled(editable); } + // Texture { - F32 bumpf = 0.f; - struct f10 : public LLSelectedTEGetFunctor + LLSelectedTE::getTexId(id,identical_diffuse); + + // Normal map + LLSelectedTEMaterial::getNormalID(normmap_id, identical_norm); + + mIsAlpha = FALSE; + LLGLenum image_format = GL_RGB; + bool identical_image_format = false; + LLSelectedTE::getImageFormat(image_format, identical_image_format); + + mIsAlpha = FALSE; + switch (image_format) { - F32 get(LLViewerObject* object, S32 face) + case GL_RGBA: + case GL_ALPHA: { - return (F32)(object->getTE(face)->getBumpmap()); + mIsAlpha = TRUE; } - } func; - identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, bumpf ); - LLCtrlSelectionInterface* combobox_bumpiness = - childGetSelectionInterface("combobox bumpiness"); - if (combobox_bumpiness) + break; + + case GL_RGB: break; + default: + { + LL_WARNS("Materials") << "Unexpected tex format in LLPanelFace...resorting to no alpha" << LL_ENDL; + } + break; + } + + if(LLViewerMedia::textureHasMedia(id)) { - combobox_bumpiness->selectNthItem((S32)bumpf); + mCtrlAlign->setEnabled(editable); } - else + + // 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); + + LLCtrlSelectionInterface* combobox_alphamode = mComboAlpha; + if (combobox_alphamode) { - llwarns << "failed childGetSelectionInterface for 'combobox bumpiness'" << llendl; + //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; + + combobox_alphamode->selectNthItem(alpha_mode); } - getChildView("combobox bumpiness")->setEnabled(editable); - getChild("combobox bumpiness")->setTentative(!identical); - getChildView("label bumpiness")->setEnabled(editable); - } - { - F32 genf = 0.f; - struct f11 : public LLSelectedTEGetFunctor + updateAlphaControls(); + + if (texture_ctrl) { - F32 get(LLViewerObject* object, S32 face) + if (identical_diffuse) { - return (F32)(object->getTE(face)->getTexGen()); + texture_ctrl->setTentative( FALSE ); + texture_ctrl->setEnabled( editable ); + texture_ctrl->setImageAssetID( id ); + mComboAlpha->setEnabled(editable && mIsAlpha && transparency <= 0.f); + mLabelAlphaMode->setEnabled(editable && mIsAlpha); + mCtrlMaskCutoff->setEnabled(editable && mIsAlpha); + mLabelMaskCutoff->setEnabled(editable && mIsAlpha); + } + else if (id.isNull()) + { + // None selected + texture_ctrl->setTentative( FALSE ); + texture_ctrl->setEnabled( FALSE ); + texture_ctrl->setImageAssetID( LLUUID::null ); + mComboAlpha->setEnabled( FALSE ); + mLabelAlphaMode->setEnabled( FALSE ); + mCtrlMaskCutoff->setEnabled( FALSE); + mLabelMaskCutoff->setEnabled( FALSE ); + } + else + { + // Tentative: multiple selected with different textures + texture_ctrl->setTentative( TRUE ); + texture_ctrl->setEnabled( editable ); + texture_ctrl->setImageAssetID( id ); + mComboAlpha->setEnabled(editable && mIsAlpha && transparency <= 0.f); + mLabelAlphaMode->setEnabled(editable && mIsAlpha); + mCtrlMaskCutoff->setEnabled(editable && mIsAlpha); + mLabelMaskCutoff->setEnabled(editable && mIsAlpha); } - } func; - identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, genf ); - S32 selected_texgen = ((S32) genf) >> TEM_TEX_GEN_SHIFT; - LLCtrlSelectionInterface* combobox_texgen = - childGetSelectionInterface("combobox texgen"); - if (combobox_texgen) - { - combobox_texgen->selectNthItem(selected_texgen); - } - else - { - llwarns << "failed childGetSelectionInterface for 'combobox texgen'" << llendl; } - getChildView("combobox texgen")->setEnabled(editable); - getChild("combobox texgen")->setTentative(!identical); - getChildView("tex gen")->setEnabled(editable); - if (selected_texgen == 1) + if (shinytexture_ctrl) { - getChild("TexScaleU")->setValue(2.0f * getChild("TexScaleU")->getValue().asReal() ); - getChild("TexScaleV")->setValue(2.0f * getChild("TexScaleV")->getValue().asReal() ); - - // EXP-1507 (change label based on the mapping mode) - getChild("tex scale")->setValue(getString("string repeats per meter")); + if (identical_spec && (shiny == SHINY_TEXTURE)) + { + shinytexture_ctrl->setTentative( FALSE ); + shinytexture_ctrl->setEnabled( editable ); + shinytexture_ctrl->setImageAssetID( specmap_id ); + } + else if (specmap_id.isNull()) + { + shinytexture_ctrl->setTentative( FALSE ); + shinytexture_ctrl->setEnabled( editable ); + shinytexture_ctrl->setImageAssetID( LLUUID::null ); + } + else + { + shinytexture_ctrl->setTentative( TRUE ); + shinytexture_ctrl->setEnabled( editable ); + shinytexture_ctrl->setImageAssetID( specmap_id ); + } } - else + + if (bumpytexture_ctrl) { - getChild("tex scale")->setValue(getString("string repeats per face")); + if (identical_norm && (bumpy == BUMPY_TEXTURE)) + { + bumpytexture_ctrl->setTentative( FALSE ); + bumpytexture_ctrl->setEnabled( editable ); + bumpytexture_ctrl->setImageAssetID( normmap_id ); + } + else if (normmap_id.isNull()) + { + bumpytexture_ctrl->setTentative( FALSE ); + bumpytexture_ctrl->setEnabled( editable ); + bumpytexture_ctrl->setImageAssetID( LLUUID::null ); + } + else + { + bumpytexture_ctrl->setTentative( TRUE ); + bumpytexture_ctrl->setEnabled( editable ); + bumpytexture_ctrl->setImageAssetID( normmap_id ); + } } - } + // planar align + bool align_planar = false; + bool identical_planar_aligned = false; { - F32 fullbrightf = 0.f; - struct f12 : public LLSelectedTEGetFunctor + LLUICtrl* cb_planar_align = mCtrlPlanar; + align_planar = (cb_planar_align && cb_planar_align->getValue().asBoolean()); + + bool enabled = (editable && isIdenticalPlanarTexgen()); + mCtrlPlanar->setValue(align_planar && enabled); + mCtrlPlanar->setEnabled(enabled); + + if (align_planar && enabled) { - F32 get(LLViewerObject* object, S32 face) - { - return (F32)(object->getTE(face)->getFullbright()); - } - } func; - identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, fullbrightf ); + LLFace* last_face = NULL; + bool identical_face = false; + LLSelectedTE::getFace(last_face, identical_face); - getChild("checkbox fullbright")->setValue((S32)fullbrightf); - getChildView("checkbox fullbright")->setEnabled(editable); - getChild("checkbox fullbright")->setTentative(!identical); + LLPanelFaceGetIsAlignedTEFunctor 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); + } } - // Repeats per meter label + // 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; + { - getChildView("rpt")->setEnabled(editable); + 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); + mShinyScaleU->setValue(spec_scale_s); + mBumpyScaleU->setValue(norm_scale_s); + + mCtrlTexScaleU->setEnabled(editable); + mShinyScaleU->setEnabled(editable && specmap_id.notNull() + && enable_material_controls); // Materials alignment + mBumpyScaleU->setEnabled(editable && normmap_id.notNull() + && enable_material_controls); // Materials alignment + + 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)); + mShinyScaleU->setTentative(LLSD(spec_scale_tentative)); + mBumpyScaleU->setTentative(LLSD(norm_scale_tentative)); + + // FIRE-11407 - Materials alignment + mCtrlMapsSync->setEnabled(editable && (specmap_id.notNull() || normmap_id.notNull())); + // + } + + { + 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; + + mCtrlTexScaleV->setEnabled(editable); + mShinyScaleV->setEnabled(editable && specmap_id.notNull() + && enable_material_controls); // Materials alignment + mBumpyScaleV->setEnabled(editable && normmap_id.notNull() + && enable_material_controls); // Materials alignment + + mCtrlTexScaleV->setValue(diff_scale_t); + mShinyScaleV->setValue(norm_scale_t); + mBumpyScaleV->setValue(spec_scale_t); + + mCtrlTexScaleV->setTentative(LLSD(diff_scale_tentative)); + mShinyScaleV->setTentative(LLSD(norm_scale_tentative)); + mBumpyScaleV->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); + mBumpyOffsetU->setValue(editable ? norm_offset_s : 0.0f); + mShinyOffsetU->setValue(editable ? spec_offset_s : 0.0f); + + mCtrlTexOffsetU->setTentative(LLSD(diff_offset_u_tentative)); + mShinyOffsetU->setTentative(LLSD(norm_offset_u_tentative)); + mBumpyOffsetU->setTentative(LLSD(spec_offset_u_tentative)); + + mCtrlTexOffsetU->setEnabled(editable); + mShinyOffsetU->setEnabled(editable && specmap_id.notNull() + && enable_material_controls); // Materials alignment + mBumpyOffsetU->setEnabled(editable && normmap_id.notNull() + && enable_material_controls); // Materials alignment + } + + { + 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); + mBumpyOffsetV->setValue(editable ? norm_offset_t : 0.0f); + mShinyOffsetV->setValue(editable ? spec_offset_t : 0.0f); + + mCtrlTexOffsetV->setTentative(LLSD(diff_offset_v_tentative)); + mShinyOffsetV->setTentative(LLSD(norm_offset_v_tentative)); + mBumpyOffsetV->setTentative(LLSD(spec_offset_v_tentative)); + + mCtrlTexOffsetV->setEnabled(editable); + mShinyOffsetV->setEnabled(editable && specmap_id.notNull() + && enable_material_controls); // Materials alignment + mBumpyOffsetV->setEnabled(editable && normmap_id.notNull() + && enable_material_controls); // Materials alignment + } + + // 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; + + mCtrlTexRot->setEnabled(editable); + mShinyRot->setEnabled(editable && specmap_id.notNull() + && enable_material_controls); // Materials alignment + mBumpyRot->setEnabled(editable && normmap_id.notNull() + && enable_material_controls); // Materials alignment + + mCtrlTexRot->setTentative(diff_rot_tentative); + mShinyRot->setTentative(LLSD(norm_rot_tentative)); + mBumpyRot->setTentative(LLSD(spec_rot_tentative)); + + mCtrlTexRot->setValue( editable ? diff_rot_deg : 0.0f); + mShinyRot->setValue(editable ? spec_rot_deg : 0.0f); + mBumpyRot->setValue(editable ? norm_rot_deg : 0.0f); } - // Repeats per meter { - F32 repeats = 1.f; - struct f13 : public LLSelectedTEGetFunctor + F32 glow = 0.f; + bool identical_glow = false; + LLSelectedTE::getGlow(glow,identical_glow); + mCtrlGlow->setValue(glow); + mCtrlGlow->setTentative(!identical_glow); + mCtrlGlow->setEnabled(editable); + mLabelGlow->setEnabled(editable); + } + + { + LLCtrlSelectionInterface* combobox_texgen = mComboTexGen; + if (combobox_texgen) + { + // Maps from enum to combobox entry index + combobox_texgen->selectNthItem(((S32)selected_texgen) >> 1); + } + + mComboTexGen->setEnabled(editable); + mComboTexGen->setTentative(!identical); + mLabelTexGen->setEnabled(editable); + + /* Singu Note: Dead code + if (selected_texgen == LLTextureEntry::TEX_GEN_PLANAR) + { + // EXP-1507 (change label based on the mapping mode) + getChild("rpt")->setValue(getString("string repeats per meter")); + } + else + if (selected_texgen == LLTextureEntry::TEX_GEN_DEFAULT) { - F32 get(LLViewerObject* object, S32 face) + getChild("rpt")->setValue(getString("string repeats per face")); + } + */ + } + + { + U8 fullbright_flag = 0; + bool identical_fullbright = false; + + LLSelectedTE::getFullbright(fullbright_flag,identical_fullbright); + + mCheckFullbright->setValue(fullbright_flag != 0); + mCheckFullbright->setEnabled(editable); + mCheckFullbright->setTentative(!identical_fullbright); + } + + + // 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); + + if (mComboTexGen) + { + S32 index = mComboTexGen ? mComboTexGen->getCurrentIndex() : 0; + BOOL enabled = editable && (index != 1); + BOOL identical_repeats = true; + F32 repeats = 1.0f; + + U32 material_type = (combobox_matmedia->getCurrentIndex() == MATMEDIA_MATERIAL) ? combobox_mattype->getCurrentIndex() : MATTYPE_DIFFUSE; + + LLSelectMgr::getInstance()->setTextureChannel(LLRender::eTexIndex(material_type)); + + switch (material_type) { - U32 s_axis = VX; - U32 t_axis = VY; - // BUG: Only repeats along S axis - // BUG: Only works for boxes. - LLPrimitive::getTESTAxes(face, &s_axis, &t_axis); - return object->getTE(face)->mScaleS / object->getScale().mV[s_axis]; + default: + case MATTYPE_DIFFUSE: + { + enabled = editable && !id.isNull(); + identical_repeats = identical_diff_repeats; + repeats = repeats_diff; + } + break; + + case MATTYPE_SPECULAR: + { + 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: + { + enabled = (editable && ((bumpy == BUMPY_TEXTURE) && !normmap_id.isNull()) + && enable_material_controls); // Materials Alignment + identical_repeats = identical_norm_repeats; + repeats = repeats_norm; + } + break; } - } func; - identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, repeats ); - - getChild("rptctrl")->setValue(editable ? repeats : 0); - getChild("rptctrl")->setTentative(!identical); - LLComboBox* mComboTexGen = getChild("combobox texgen"); - if (mComboTexGen) + + BOOL repeats_tentative = !identical_repeats; + + mCtrlRpt->setEnabled(identical_planar_texgen ? FALSE : enabled); + mCtrlRpt->setValue(editable ? repeats : 1.0f); + mCtrlRpt->setTentative(LLSD(repeats_tentative)); + + // FIRE-11407 - Flip buttons + mCtrlFlipTexScaleU->setEnabled(enabled); + mCtrlFlipTexScaleV->setEnabled(enabled); + // + } + } + + // Materials + { + LLMaterialPtr material; + LLSelectedTEMaterial::getCurrent(material, identical); + + if (material && editable) { - BOOL enabled = editable && (!mComboTexGen || mComboTexGen->getCurrentIndex() != 1); - getChildView("rptctrl")->setEnabled(enabled); - getChildView("button apply")->setEnabled(enabled); + LL_DEBUGS("Materials: OnMaterialsLoaded:") << material->asLLSD() << LL_ENDL; + + // Alpha + LLCtrlSelectionInterface* combobox_alphamode = + mComboAlpha; + if (combobox_alphamode) + { + 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 ebe none + alpha_mode = LLMaterial::DIFFUSE_ALPHA_MODE_NONE; + } + + combobox_alphamode->selectNthItem(alpha_mode); + } + mCtrlMaskCutoff->setValue(material->getAlphaMaskCutoff()); + updateAlphaControls(); + + identical_planar_texgen = isIdenticalPlanarTexgen(); + + // Shiny (specular) + F32 offset_x, offset_y, repeat_x, repeat_y, rot; + LLTextureCtrl* texture_ctrl = mShinyTextureCtrl; + texture_ctrl->setImageAssetID(material->getSpecularID()); + + if (!material->getSpecularID().isNull() && (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(); + mShinyScaleU->setValue(repeat_x); + mShinyScaleV->setValue(repeat_y); + mShinyRot->setValue(rot*RAD_TO_DEG); + mShinyOffsetU->setValue(offset_x); + mShinyOffsetV->setValue(offset_y); + mGlossyCtrl->setValue(material->getSpecularLightExponent()); + mEnvironmentCtrl->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().isNull()) + { + mShinyColorSwatch->setOriginal(material->getSpecularLightColor()); + mShinyColorSwatch->set(material->getSpecularLightColor(),TRUE); + } + + // Bumpy (normal) + texture_ctrl = mBumpyTextureCtrl; + texture_ctrl->setImageAssetID(material->getNormalID()); + + if (!material->getNormalID().isNull()) + { + 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(); + mBumpyScaleU->setValue(repeat_x); + mBumpyScaleV->setValue(repeat_y); + mBumpyRot->setValue(rot*RAD_TO_DEG); + mBumpyOffsetU->setValue(offset_x); + mBumpyOffsetV->setValue(offset_y); + + updateBumpyControls(!material->getNormalID().isNull(), true); + } } } // Set variable values for numeric expressions - calcp->setVar(LLCalc::TEX_U_SCALE, childGetValue("TexScaleU").asReal()); - calcp->setVar(LLCalc::TEX_V_SCALE, childGetValue("TexScaleV").asReal()); - calcp->setVar(LLCalc::TEX_U_OFFSET, childGetValue("TexOffsetU").asReal()); - calcp->setVar(LLCalc::TEX_V_OFFSET, childGetValue("TexOffsetV").asReal()); - calcp->setVar(LLCalc::TEX_ROTATION, childGetValue("TexRot").asReal()); - calcp->setVar(LLCalc::TEX_TRANSPARENCY, childGetValue("ColorTrans").asReal()); - calcp->setVar(LLCalc::TEX_GLOW, childGetValue("glow").asReal()); + LLCalc* calcp = LLCalc::getInstance(); + calcp->setVar(LLCalc::TEX_U_SCALE, mCtrlTexScaleU->getValue().asReal()); + calcp->setVar(LLCalc::TEX_V_SCALE, mCtrlTexScaleV->getValue().asReal()); + calcp->setVar(LLCalc::TEX_U_OFFSET, mCtrlTexOffsetU->getValue().asReal()); + calcp->setVar(LLCalc::TEX_V_OFFSET, mCtrlTexOffsetV->getValue().asReal()); + calcp->setVar(LLCalc::TEX_ROTATION, mCtrlTexRot->getValue().asReal()); + calcp->setVar(LLCalc::TEX_TRANSPARENCY, mCtrlColorTransp->getValue().asReal()); + calcp->setVar(LLCalc::TEX_GLOW, mCtrlGlow->getValue().asReal()); } else { @@ -972,49 +1469,49 @@ void LLPanelFace::getState() clearCtrls(); // Disable non-UICtrls - LLTextureCtrl* texture_ctrl = getChild("texture control"); + LLTextureCtrl* texture_ctrl = mTextureCtrl; if(texture_ctrl) { texture_ctrl->setImageAssetID( LLUUID::null ); - texture_ctrl->setFallbackImageName( "locked_image.j2c" ); texture_ctrl->setEnabled( FALSE ); // this is a LLUICtrl, but we don't want it to have keyboard focus so we add it as a child, not a ctrl. // texture_ctrl->setValid(FALSE); } - LLColorSwatchCtrl* mColorSwatch = getChild("colorswatch"); if(mColorSwatch) { mColorSwatch->setEnabled( FALSE ); mColorSwatch->setFallbackImageName("locked_image.j2c" ); mColorSwatch->setValid(FALSE); } - getChildView("color trans")->setEnabled(FALSE); + mLabelColorTransp->setEnabled(FALSE); + /* Singu Note: This is missing in xml getChildView("rpt")->setEnabled(FALSE); - getChildView("tex scale")->setEnabled(FALSE); getChildView("tex offset")->setEnabled(FALSE); - getChildView("tex rotate")->setEnabled(FALSE); - getChildView("tex gen")->setEnabled(FALSE); - getChildView("label shininess")->setEnabled(FALSE); - getChildView("label bumpiness")->setEnabled(FALSE); - getChildView("button align")->setEnabled(FALSE); - getChildView("button apply")->setEnabled(FALSE); + */ + mLabelTexGen->setEnabled(FALSE); + mLabelShiny->setEnabled(FALSE); + mLabelBumpy->setEnabled(FALSE); + mCtrlAlign->setEnabled(FALSE); //getChildView("has media")->setEnabled(FALSE); //getChildView("media info set")->setEnabled(FALSE); + updateVisibility(); // Set variable values for numeric expressions + LLCalc* calcp = LLCalc::getInstance(); calcp->clearVar(LLCalc::TEX_U_SCALE); calcp->clearVar(LLCalc::TEX_V_SCALE); calcp->clearVar(LLCalc::TEX_U_OFFSET); calcp->clearVar(LLCalc::TEX_V_OFFSET); calcp->clearVar(LLCalc::TEX_ROTATION); calcp->clearVar(LLCalc::TEX_TRANSPARENCY); - calcp->clearVar(LLCalc::TEX_GLOW); + calcp->clearVar(LLCalc::TEX_GLOW); } } void LLPanelFace::refresh() { + LL_DEBUGS("Materials") << LL_ENDL; getState(); } @@ -1029,14 +1526,9 @@ F32 LLPanelFace::valueGlow(LLViewerObject* object, S32 face) } -void LLPanelFace::onCommitColor(const LLSD& data) +void LLPanelFace::onCommitShinyColor(const LLSD& data) { - sendColor(); -} - -void LLPanelFace::onCommitAlpha(const LLSD& data) -{ - sendAlpha(); + LLSelectedTEMaterial::setSpecularLightColor(this, mShinyColorSwatch->get()); } void LLPanelFace::onCancelColor(const LLSD& data) @@ -1050,39 +1542,228 @@ void LLPanelFace::onSelectColor(const LLSD& data) sendColor(); } -// static -void LLPanelFace::onCommitBump(LLUICtrl* ctrl, void* userdata) +void LLPanelFace::onCommitMaterialsMedia() { - LLPanelFace* self = (LLPanelFace*) userdata; - self->sendBump(); + // Force to default states to side-step problems with menu contents + // and generally reflecting old state when switching tabs or objects + // + updateShinyControls(false,true); + updateBumpyControls(false,true); + updateUI(); } // static -void LLPanelFace::onCommitTexGen(LLUICtrl* ctrl, void* userdata) +void LLPanelFace::updateVisibility() { - LLPanelFace* self = (LLPanelFace*) userdata; - self->sendTexGen(); + LLComboBox* combo_matmedia = mComboMatMedia; + LLComboBox* combo_mattype = mComboMatType; + LLComboBox* combo_shininess = mComboShiny; + LLComboBox* combo_bumpiness = mComboBumpy; + if (!combo_mattype || !combo_matmedia || !combo_shininess || !combo_bumpiness) + { + LL_WARNS("Materials") << "Combo box not found...exiting." << LL_ENDL; + return; + } + U32 materials_media = combo_matmedia->getCurrentIndex(); + U32 material_type = combo_mattype->getCurrentIndex(); + bool show_media = (materials_media == MATMEDIA_MEDIA) && combo_matmedia->getEnabled(); + bool show_texture = (show_media || ((material_type == MATTYPE_DIFFUSE) && combo_matmedia->getEnabled())); + bool show_bumpiness = (!show_media) && (material_type == MATTYPE_NORMAL) && combo_matmedia->getEnabled(); + bool show_shininess = (!show_media) && (material_type == MATTYPE_SPECULAR) && combo_matmedia->getEnabled(); + mComboMatType->setVisible(!show_media); + // FIRE-11407 - Be consistant and hide this with the other controls + //mCtrlRpt->setVisible(true); + mCtrlRpt->setVisible(combo_matmedia->getEnabled()); + // and other additions... + mCtrlFlipTexScaleU->setVisible(combo_matmedia->getEnabled()); + mCtrlFlipTexScaleV->setVisible(combo_matmedia->getEnabled()); + // + + // Media controls + mMediaInfo->setVisible(show_media); + mMediaAdd->setVisible(show_media); + mMediaDelete->setVisible(show_media); + mCtrlAlign->setVisible(show_media); + + // Diffuse texture controls + mTextureCtrl->setVisible(show_texture && !show_media); + mLabelAlphaMode->setVisible(show_texture && !show_media); + mComboAlpha->setVisible(show_texture && !show_media); + mLabelMaskCutoff->setVisible(false); + mCtrlMaskCutoff->setVisible(false); + if (show_texture && !show_media) + { + updateAlphaControls(); + } + mCtrlTexScaleU->setVisible(show_texture); + mCtrlTexScaleV->setVisible(show_texture); + mCtrlTexRot->setVisible(show_texture); + mCtrlTexOffsetU->setVisible(show_texture); + mCtrlTexOffsetV->setVisible(show_texture); + + // Specular map controls + mShinyTextureCtrl->setVisible(show_shininess); + mComboShiny->setVisible(show_shininess); + mLabelShiny->setVisible(show_shininess); + mLabelGlossy->setVisible(false); + mGlossyCtrl->setVisible(false); + mLabelEnvironment->setVisible(false); + mEnvironmentCtrl->setVisible(false); + mLabelShinyColor->setVisible(false); + mShinyColorSwatch->setVisible(false); + if (show_shininess) + { + updateShinyControls(); + } + mShinyScaleU->setVisible(show_shininess); + mShinyScaleV->setVisible(show_shininess); + mShinyRot->setVisible(show_shininess); + mShinyOffsetU->setVisible(show_shininess); + mShinyOffsetV->setVisible(show_shininess); + + // Normal map controls + if (show_bumpiness) + { + updateBumpyControls(); + } + mBumpyTextureCtrl->setVisible(show_bumpiness); + mComboBumpy->setVisible(show_bumpiness); + mLabelBumpy->setVisible(show_bumpiness); + mBumpyScaleU->setVisible(show_bumpiness); + mBumpyScaleV->setVisible(show_bumpiness); + mBumpyRot->setVisible(show_bumpiness); + mBumpyOffsetU->setVisible(show_bumpiness); + mBumpyOffsetV->setVisible(show_bumpiness); } -// static -void LLPanelFace::onCommitShiny(LLUICtrl* ctrl, void* userdata) +void LLPanelFace::onCommitMaterialType() { - LLPanelFace* self = (LLPanelFace*) userdata; - self->sendShiny(); + // Force to default states to side-step problems with menu contents + // and generally reflecting old state when switching tabs or objects + // + updateShinyControls(false,true); + updateBumpyControls(false,true); + updateUI(); } -// static -void LLPanelFace::onCommitFullbright(LLUICtrl* ctrl, void* userdata) +void LLPanelFace::updateShinyControls(bool is_setting_texture, bool mess_with_shiny_combobox) { - LLPanelFace* self = (LLPanelFace*) userdata; - self->sendFullbright(); + LLTextureCtrl* texture_ctrl = mShinyTextureCtrl; + LLUUID shiny_texture_ID = texture_ctrl->getImageAssetID(); + LL_DEBUGS("Materials") << "Shiny texture selected: " << shiny_texture_ID << LL_ENDL; + LLComboBox* comboShiny = mComboShiny; + + if(mess_with_shiny_combobox) + { + if (!comboShiny) + { + return; + } + if (!shiny_texture_ID.isNull() && is_setting_texture) + { + if (!comboShiny->itemExists(USE_TEXTURE)) + { + comboShiny->add(USE_TEXTURE); + } + comboShiny->setSimple(USE_TEXTURE); + } + else + { + if (comboShiny->itemExists(USE_TEXTURE)) + { + comboShiny->remove(SHINY_TEXTURE); + comboShiny->selectFirstItem(); + } + } + } + + LLComboBox* combo_matmedia = mComboMatMedia; + LLComboBox* combo_mattype =mComboMatType; + U32 materials_media = combo_matmedia->getCurrentIndex(); + U32 material_type = combo_mattype->getCurrentIndex(); + bool show_media = (materials_media == MATMEDIA_MEDIA) && combo_matmedia->getEnabled(); + bool show_shininess = (!show_media) && (material_type == MATTYPE_SPECULAR) && combo_matmedia->getEnabled(); + U32 shiny_value = comboShiny->getCurrentIndex(); + bool show_shinyctrls = (shiny_value == SHINY_TEXTURE) && show_shininess; // Use texture + mLabelGlossy->setVisible(show_shinyctrls); + mGlossyCtrl->setVisible(show_shinyctrls); + mLabelEnvironment->setVisible(show_shinyctrls); + mEnvironmentCtrl->setVisible(show_shinyctrls); + mLabelShinyColor->setVisible(show_shinyctrls); + mShinyColorSwatch->setVisible(show_shinyctrls); } -// static -void LLPanelFace::onCommitGlow(LLUICtrl* ctrl, void* userdata) +void LLPanelFace::updateBumpyControls(bool is_setting_texture, bool mess_with_combobox) { - LLPanelFace* self = (LLPanelFace*) userdata; - self->sendGlow(); + LLTextureCtrl* texture_ctrl = mBumpyTextureCtrl; + LLUUID bumpy_texture_ID = texture_ctrl->getImageAssetID(); + LL_DEBUGS("Materials") << "texture: " << bumpy_texture_ID << (mess_with_combobox ? "" : " do not") << " update combobox" << LL_ENDL; + LLComboBox* comboBumpy = mComboBumpy; + if (!comboBumpy) + { + return; + } + + if (mess_with_combobox) + { + LLTextureCtrl* texture_ctrl = mBumpyTextureCtrl; + LLUUID bumpy_texture_ID = texture_ctrl->getImageAssetID(); + LL_DEBUGS("Materials") << "texture: " << bumpy_texture_ID << (mess_with_combobox ? "" : " do not") << " update combobox" << LL_ENDL; + + if (!bumpy_texture_ID.isNull() && is_setting_texture) + { + if (!comboBumpy->itemExists(USE_TEXTURE)) + { + comboBumpy->add(USE_TEXTURE); + } + comboBumpy->setSimple(USE_TEXTURE); + } + else + { + if (comboBumpy->itemExists(USE_TEXTURE)) + { + comboBumpy->remove(BUMPY_TEXTURE); + comboBumpy->selectFirstItem(); + } + } + } +} + +void LLPanelFace::updateAlphaControls() +{ + LLComboBox* comboAlphaMode = mComboAlpha; + if (!comboAlphaMode) + { + return; + } + U32 alpha_value = comboAlphaMode->getCurrentIndex(); + bool show_alphactrls = (alpha_value == ALPHAMODE_MASK); // Alpha masking + + LLComboBox* combobox_matmedia = mComboMatMedia; + U32 mat_media = MATMEDIA_MATERIAL; + if (combobox_matmedia) + { + mat_media = combobox_matmedia->getCurrentIndex(); + } + + LLComboBox* combobox_mattype = mComboMatType; + U32 mat_type = MATTYPE_DIFFUSE; + if (combobox_mattype) + { + mat_type = combobox_mattype->getCurrentIndex(); + } + + show_alphactrls = show_alphactrls && (mat_media == MATMEDIA_MATERIAL); + show_alphactrls = show_alphactrls && (mat_type == MATTYPE_DIFFUSE); + + mLabelMaskCutoff->setVisible(show_alphactrls); + mCtrlMaskCutoff->setVisible(show_alphactrls); +} + +void LLPanelFace::onCommitAlphaMode() +{ + updateAlphaControls(); + LLSelectedTEMaterial::setDiffuseAlphaMode(this, getCurrentDiffuseAlphaMode()); } // static @@ -1118,27 +1799,211 @@ void LLPanelFace::onSelectTexture(const LLSD& data) { LLSelectMgr::getInstance()->saveSelectedObjectTextures(); sendTexture(); + + LLGLenum image_format(0); + bool identical_image_format = false; + LLSelectedTE::getImageFormat(image_format, identical_image_format); + + LLCtrlSelectionInterface* combobox_alphamode = + mComboAlpha; + + U32 alpha_mode = LLMaterial::DIFFUSE_ALPHA_MODE_NONE; + if (combobox_alphamode) + { + 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 LLPanelFace...resorting to no alpha" << LL_ENDL; + } + break; + } + + combobox_alphamode->selectNthItem(alpha_mode); + } + LLSelectedTEMaterial::setDiffuseAlphaMode(this, getCurrentDiffuseAlphaMode()); } +void LLPanelFace::onCloseTexturePicker(const LLSD& data) +{ + LL_DEBUGS("Materials") << data << LL_ENDL; + updateUI(); +} -// static -void LLPanelFace::onCommitTextureInfo( LLUICtrl* ctrl, void* userdata ) +void LLPanelFace::onCommitSpecularTexture( const LLSD& data ) +{ + LL_DEBUGS("Materials") << data << LL_ENDL; + sendShiny(SHINY_TEXTURE); +} + +void LLPanelFace::onCommitNormalTexture( const LLSD& data ) +{ + LL_DEBUGS("Materials") << data << LL_ENDL; + LLUUID nmap_id = getCurrentNormalMap(); + sendBump(nmap_id.isNull() ? 0 : BUMPY_TEXTURE); +} + +void LLPanelFace::onCancelSpecularTexture(const LLSD& data) +{ + 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); +} + +void LLPanelFace::onCancelNormalTexture(const LLSD& data) +{ + U8 bumpy = 0; + bool identical_bumpy = false; + LLSelectedTE::getBumpmap(bumpy, identical_bumpy); + LLUUID norm_map_id = mBumpyTextureCtrl->getImageAssetID(); + bumpy = norm_map_id.isNull() ? bumpy : BUMPY_TEXTURE; + sendBump(bumpy); +} + +void LLPanelFace::onSelectSpecularTexture(const LLSD& data) +{ + LL_DEBUGS("Materials") << data << LL_ENDL; + sendShiny(SHINY_TEXTURE); +} + +void LLPanelFace::onSelectNormalTexture(const LLSD& data) +{ + LL_DEBUGS("Materials") << data << LL_ENDL; + LLUUID nmap_id = getCurrentNormalMap(); + sendBump(nmap_id.isNull() ? 0 : BUMPY_TEXTURE); +} + +void LLPanelFace::onCommitMaterialBumpyScaleX(const LLSD& value) +{ + F32 bumpy_scale_u = value.asReal(); + if (isIdenticalPlanarTexgen()) + { + bumpy_scale_u *= 0.5f; + } + LLSelectedTEMaterial::setNormalRepeatX(this, bumpy_scale_u); +} + +void LLPanelFace::onCommitMaterialBumpyScaleY(const LLSD& value) +{ + F32 bumpy_scale_v = value.asReal(); + if (isIdenticalPlanarTexgen()) + { + bumpy_scale_v *= 0.5f; + } + LLSelectedTEMaterial::setNormalRepeatY(this, bumpy_scale_v); +} + +void LLPanelFace::onCommitMaterialShinyScaleX(const LLSD& value) +{ + F32 shiny_scale_u = value.asReal(); + if (isIdenticalPlanarTexgen()) + { + shiny_scale_u *= 0.5f; + } + LLSelectedTEMaterial::setSpecularRepeatX(this, shiny_scale_u); +} + +void LLPanelFace::onCommitMaterialShinyScaleY(const LLSD& value) { - LLPanelFace* self = (LLPanelFace*) userdata; - self->sendTextureInfo(); + F32 shiny_scale_v = value.asReal(); + if (isIdenticalPlanarTexgen()) + { + shiny_scale_v *= 0.5f; + } + LLSelectedTEMaterial::setSpecularRepeatY(this, shiny_scale_v); +} + +void LLPanelFace::onCommitMaterialBumpyRot(const LLSD& value) +{ + LLSelectedTEMaterial::setNormalRotation(this, value.asReal() * DEG_TO_RAD); +} + +void LLPanelFace::onCommitMaterialShinyRot(const LLSD& value) +{ + LLSelectedTEMaterial::setSpecularRotation(this, value.asReal() * DEG_TO_RAD); +} + +void LLPanelFace::onCommitTextureInfo() +{ + sendTextureInfo(); + // Materials alignment + if (gSavedSettings.getBOOL("FSSynchronizeTextureMaps")) + { + alignMaterialsProperties(); + } + // } // Commit the number of repeats per meter -// static -void LLPanelFace::onClickApply(void* userdata) +void LLPanelFace::onCommitRepeatsPerMeter(LLUICtrl* repeats_ctrl) { - LLPanelFace* self = (LLPanelFace*) userdata; - - gFocusMgr.setKeyboardFocus( NULL ); + LLComboBox* combo_matmedia = mComboMatMedia; + LLComboBox* combo_mattype = mComboMatType; + + U32 materials_media = combo_matmedia->getCurrentIndex(); + + + U32 material_type = (materials_media == MATMEDIA_MATERIAL) ? combo_mattype->getCurrentIndex() : 0; + F32 repeats_per_meter = repeats_ctrl->getValue().asReal(); + + F32 obj_scale_s = 1.0f; + F32 obj_scale_t = 1.0f; + + bool identical_scale_s = false; + bool identical_scale_t = false; - //F32 repeats_per_meter = self->mCtrlRepeatsPerMeter->get(); - F32 repeats_per_meter = (F32)self->getChild("rptctrl")->getValue().asReal();//self->mCtrlRepeatsPerMeter->get(); - LLSelectMgr::getInstance()->selectionTexScaleAutofit( repeats_per_meter ); + LLSelectedTE::getObjectScaleS(obj_scale_s, identical_scale_s); + LLSelectedTE::getObjectScaleS(obj_scale_t, identical_scale_t); + + switch (material_type) + { + case MATTYPE_DIFFUSE: + { + LLSelectMgr::getInstance()->selectionTexScaleAutofit( repeats_per_meter ); + } + break; + + case MATTYPE_NORMAL: + { + LLUICtrl* bumpy_scale_u = mBumpyScaleU; + LLUICtrl* bumpy_scale_v = mBumpyScaleV; + + bumpy_scale_u->setValue(obj_scale_s * repeats_per_meter); + bumpy_scale_v->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: + { + LLUICtrl* shiny_scale_u = mShinyScaleU; + LLUICtrl* shiny_scale_v = mShinyScaleV; + + shiny_scale_u->setValue(obj_scale_s * repeats_per_meter); + shiny_scale_v->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; + } } struct LLPanelFaceSetMediaFunctor : public LLSelectedTEFunctor @@ -1183,7 +2048,7 @@ struct LLPanelFaceSetMediaFunctor : public LLSelectedTEFunctor }; }; -void LLPanelFace::onClickAutoFix(void* userdata) +void LLPanelFace::onClickAutoFix() { LLPanelFaceSetMediaFunctor setfunc; LLSelectMgr::getInstance()->getSelection()->applyToTEs(&setfunc); @@ -1202,17 +2067,282 @@ void LLPanelFace::setMediaType(const std::string& mime_type) { } -// static -void LLPanelFace::onCommitPlanarAlign(LLUICtrl* ctrl, void* userdata) +void LLPanelFace::onCommitPlanarAlign() +{ + getState(); + sendTextureInfo(); +} + +void LLPanelFace::onTextureSelectionChanged(LLInventoryItem* itemp) +{ + LL_DEBUGS("Materials") << "item asset " << itemp->getAssetUUID() << LL_ENDL; + LLComboBox* combo_mattype = mComboMatType; + if (!combo_mattype) + { + return; + } + U32 mattype = combo_mattype->getCurrentIndex(); + LLTextureCtrl* texture_ctrl = mTextureCtrl; + switch (mattype) + { + case MATTYPE_SPECULAR: + texture_ctrl = mShinyTextureCtrl; + break; + case MATTYPE_NORMAL: + texture_ctrl = mBumpyTextureCtrl; + break; + // no default needed + } + if (texture_ctrl) + { + 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("ApplyTextureImmediately")) + { + LLNotificationsUtil::add("LivePreviewUnavailable"); + } + } +} + +bool LLPanelFace::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 LLPanelFace::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); +} + +void LLPanelFace::LLSelectedTE::getImageFormat(LLGLenum& image_format_to_return, bool& identical_face) +{ + LLGLenum image_format(0); + 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 LLPanelFace::LLSelectedTE::getTexId(LLUUID& id, bool& identical) { - LLPanelFace* self = (LLPanelFace*) userdata; - self->getState(); - self->sendTextureInfo(); + 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::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 LLPanelFace::LLSelectedTEMaterial::getCurrent(LLMaterialPtr& material_ptr, bool& identical_material) +{ + struct MaterialFunctor : public LLSelectedTEGetFunctor + { + LLMaterialPtr get(LLViewerObject* object, S32 te_index) + { + return object->getTE(te_index)->getMaterialParams(); + } + } func; + identical_material = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, material_ptr); +} + +void LLPanelFace::LLSelectedTEMaterial::getMaxSpecularRepeats(F32& repeats, bool& identical) +{ + struct LLSelectedTEGetMaxSpecRepeats : public LLSelectedTEGetFunctor + { + F32 get(LLViewerObject* object, S32 face) + { + LLMaterial* mat = object->getTE(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 LLPanelFace::LLSelectedTEMaterial::getMaxNormalRepeats(F32& repeats, bool& identical) +{ + struct LLSelectedTEGetMaxNormRepeats : public LLSelectedTEGetFunctor + { + F32 get(LLViewerObject* object, S32 face) + { + LLMaterial* mat = object->getTE(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 LLPanelFace::LLSelectedTEMaterial::getCurrentDiffuseAlphaMode(U8& diffuse_alpha_mode, bool& identical, 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 LLPanelFace::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 LLPanelFace::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 LLPanelFace::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->getTE(face)->mScaleS / object->getScale().mV[s_axis]; + F32 repeats_t = object->getTE(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 ); } static LLSD textures; -void LLPanelFace::onClickCopy(void* userdata) +void LLPanelFace::onClickCopy() { LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstRootObject(); if(!objectp) @@ -1241,12 +2371,12 @@ void LLPanelFace::onClickCopy(void* userdata) tex_params["imageid"] = tex; } } - llinfos << "Copying params on face " << i << "." << llendl; + LL_INFOS() << "Copying params on face " << i << "." << LL_ENDL; textures.append(tex_params); } } -void LLPanelFace::onClickPaste(void* userdata) +void LLPanelFace::onClickPaste() { LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstRootObject(); if(!objectp) @@ -1272,7 +2402,7 @@ void LLPanelFace::onClickPaste(void* userdata) for (int i = 0; i < textures.size() && i < objectp->getNumTEs(); i++) { - llinfos << "Pasting params on face " << i << "." << llendl; + LL_INFOS() << "Pasting params on face " << i << "." << LL_ENDL; LLSD cur_tex = objectp->getTE(i)->asLLSD(); if (textures[i]["imageid"].asUUID() == LLUUID::null) textures[i]["imageid"] = cur_tex["imageid"]; @@ -1285,3 +2415,101 @@ void LLPanelFace::onClickPaste(void* userdata) msg->sendReliable(gAgent.getRegion()->getHost()); } + +// Materials alignment +void LLPanelFace::onClickMapsSync() +{ + getState(); + if (gSavedSettings.getBOOL("FSSynchronizeTextureMaps")) + { + alignMaterialsProperties(); + } +} + +void LLPanelFace::alignMaterialsProperties() +{ + F32 tex_scale_u = mCtrlTexScaleU->getValue().asReal(); + F32 tex_scale_v = mCtrlTexScaleV->getValue().asReal(); + F32 tex_offset_u = mCtrlTexOffsetU->getValue().asReal(); + F32 tex_offset_v = mCtrlTexOffsetV->getValue().asReal(); + F32 tex_rot = mCtrlTexRot->getValue().asReal(); + + mShinyScaleU->setValue(tex_scale_u); + mShinyScaleV->setValue(tex_scale_v); + mShinyOffsetU->setValue(tex_offset_u); + mShinyOffsetV->setValue(tex_offset_v); + mShinyRot->setValue(tex_rot); + + 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); + + mBumpyScaleU->setValue(tex_scale_u); + mBumpyScaleV->setValue(tex_scale_v); + mBumpyOffsetU->setValue(tex_offset_u); + mBumpyOffsetV->setValue(tex_offset_v); + mBumpyRot->setValue(tex_rot); + + 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); +} + +// FIRE-11407 - Flip buttons +void LLPanelFace::onCommitFlip(bool flip_x) +{ + S32 mattype(mComboMatType->getCurrentIndex()); + LLUICtrl* spinner = NULL; + switch (mattype) + { + case MATTYPE_DIFFUSE: + spinner = flip_x ? mCtrlTexScaleU : mCtrlTexScaleV; + break; + case MATTYPE_NORMAL: + spinner = flip_x ? mBumpyScaleU : mBumpyScaleV; + break; + case MATTYPE_SPECULAR: + spinner = flip_x ? mShinyScaleU : mShinyScaleV; + break; + default: + //llassert(mattype); + return; + } + + if (spinner) + { + F32 value = -(spinner->getValue().asReal()); + spinner->setValue(value); + + switch (mattype) + { + case MATTYPE_DIFFUSE: + sendTextureInfo(); + if (gSavedSettings.getBOOL("FSSyncronizeTextureMaps")) + { + alignMaterialsProperties(); + } + break; + case MATTYPE_NORMAL: + if (flip_x) + LLSelectedTEMaterial::setNormalRepeatX(this, value); + else + LLSelectedTEMaterial::setNormalRepeatY(this, value); + break; + case MATTYPE_SPECULAR: + if (flip_x) + LLSelectedTEMaterial::setSpecularRepeatX(this, value); + else + LLSelectedTEMaterial::setSpecularRepeatY(this, value); + break; + default: + //llassert(mattype); + return; + } + } +} +// diff --git a/indra/newview/llpanelface.h b/indra/newview/llpanelface.h index 52ccbaf109..5bbcf58682 100644 --- a/indra/newview/llpanelface.h +++ b/indra/newview/llpanelface.h @@ -35,6 +35,10 @@ #include "v4color.h" #include "llpanel.h" +#include "llmaterial.h" +#include "llmaterialmgr.h" +#include "lltextureentry.h" +#include "llselectmgr.h" class LLButton; class LLCheckBoxCtrl; @@ -47,6 +51,49 @@ class LLTextBox; class LLTextureCtrl; class LLUICtrl; class LLViewerObject; +class LLFloater; +class LLMaterialID; + +// 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 LLMaterialEditFunctor +{ +public: + LLMaterialEditFunctor(const DataType& data) : _data(data) {} + virtual ~LLMaterialEditFunctor() {} + virtual void apply(LLMaterialPtr& material) { (material->*(MaterialEditFunc))(_data); } + DataType _data; +}; + +template< + typename DataType, + DataType (LLMaterial::*MaterialGetFunc)() > +class LLMaterialGetFunctor +{ +public: + LLMaterialGetFunctor() {} + virtual DataType get(LLMaterialPtr& material) { return (material->*(MaterialGetFunc)); } +}; + +template< + typename DataType, + DataType (LLTextureEntry::*TEGetFunc)() > +class LLTEGetFunctor +{ +public: + LLTEGetFunctor() {} + virtual DataType get(LLTextureEntry* entry) { return (entry*(TEGetFunc)); } +}; class LLPanelFace : public LLPanel { @@ -59,6 +106,19 @@ class LLPanelFace : public LLPanel void setMediaURL(const std::string& url); void setMediaType(const std::string& mime_type); + LLMaterialPtr createDefaultMaterial(LLMaterialPtr current_material) + { + LLMaterialPtr new_material(!current_material.isNull() ? 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; + } + + LLRender::eTexIndex getTextureChannelToEdit(); + protected: void getState(); @@ -66,11 +126,11 @@ class LLPanelFace : public LLPanel void sendTextureInfo(); // applies and sends texture scale, offset, etc. void sendColor(); // applies and sends color void sendAlpha(); // applies and sends transparency - void sendBump(); // applies and sends bump map + void sendBump(U32 bumpiness); // applies and sends bump map void sendTexGen(); // applies and sends bump map - void sendShiny(); // applies and sends shininess + void sendShiny(U32 shininess); // applies and sends shininess void sendFullbright(); // applies and sends full bright - void sendGlow(); + void sendGlow(); void sendMedia(); // this function is to return TRUE if the drag should succeed. @@ -79,23 +139,404 @@ class LLPanelFace : public LLPanel void onCommitTexture(const LLSD& data); void onCancelTexture(const LLSD& data); void onSelectTexture(const LLSD& data); - void onCommitColor(const LLSD& data); - void onCommitAlpha(const LLSD& data); + void onCommitSpecularTexture(const LLSD& data); + void onCancelSpecularTexture(const LLSD& data); + void onSelectSpecularTexture(const LLSD& data); + void onCommitNormalTexture(const LLSD& data); + void onCancelNormalTexture(const LLSD& data); + void onSelectNormalTexture(const LLSD& data); + void onCommitShinyColor(const LLSD& data); void onCancelColor(const LLSD& data); void onSelectColor(const LLSD& data); - static void onCommitTextureInfo( LLUICtrl* ctrl, void* userdata); - static void onCommitBump( LLUICtrl* ctrl, void* userdata); - static void onCommitTexGen( LLUICtrl* ctrl, void* userdata); - static void onCommitShiny( LLUICtrl* ctrl, void* userdata); - static void onCommitFullbright( LLUICtrl* ctrl, void* userdata); - static void onCommitGlow( LLUICtrl* ctrl, void *userdata); - static void onCommitPlanarAlign( LLUICtrl* ctrl, void* userdata); - static void onClickApply(void*); - static void onClickAutoFix(void*); - static void onClickCopy(void*); - static void onClickPaste(void*); + + void onCloseTexturePicker(const LLSD& data); + + // Make UI reflect state of currently selected material (refresh) + // and UI mode (e.g. editing normal map v diffuse map) + // + void updateUI(); + + // Convenience func to determine if all faces in selection have + // identical planar texgen settings during edits + // + bool isIdenticalPlanarTexgen(); + + // Callback funcs for individual controls + // + void onCommitTextureInfo(); + + void onCommitMaterialBumpyScaleX(const LLSD& value); + void onCommitMaterialBumpyScaleY(const LLSD& value); + void onCommitMaterialBumpyRot(const LLSD& value); + + void onCommitMaterialShinyScaleX(const LLSD& value); + void onCommitMaterialShinyScaleY(const LLSD& value); + void onCommitMaterialShinyRot(const LLSD& value); + + + void onCommitMaterialsMedia(); + void onCommitMaterialType(); + void onCommitAlphaMode(); + void onCommitPlanarAlign(); + void onCommitRepeatsPerMeter(LLUICtrl* repeats_ctrl); + void onClickAutoFix(); static F32 valueGlow(LLViewerObject* object, S32 face); + void onClickCopy(); + void onClickPaste(); + // Build tool enhancements + void onClickMapsSync(); + void alignMaterialsProperties(); + void onCommitFlip(bool flip_x); + // + +private: + + bool isAlpha() { return mIsAlpha; } + + // Convenience funcs to keep the visual flack to a minimum + // + LLUUID getCurrentNormalMap(); + LLUUID getCurrentSpecularMap(); + U8 getCurrentDiffuseAlphaMode(); + + // 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(); + + // Make material(s) reflect current state of UI (apply edit) + // + void updateMaterial(); + + // 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(LLPanelFace* p, DataType data) + { + LLMaterialEditFunctor< DataType, SetValueType, MaterialEditFunc > edit(data); + struct LLSelectedTEEditMaterial : public LLSelectedTEMaterialFunctor + { + LLSelectedTEEditMaterial(LLPanelFace* panel, LLMaterialEditFunctor< DataType, SetValueType, MaterialEditFunc >* editp) : _panel(panel), _edit(editp) {} + virtual ~LLSelectedTEEditMaterial() {}; + virtual LLMaterialPtr apply(LLViewerObject* object, S32 face, LLTextureEntry* tep, LLMaterialPtr& current_material) + { + if (_edit) + { + 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(); + } + + // Ensure 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; + } + LLMaterialEditFunctor< DataType, SetValueType, MaterialEditFunc >* _edit; + LLPanelFace* _panel; + } editor(p, &edit); + LLSelectMgr::getInstance()->selectionSetMaterialParams(&editor); + } + + template< + typename DataType, + typename ReturnType, + ReturnType (LLMaterial::* const MaterialGetFunc)() const > + static void getTEMaterialValue(DataType& data_to_return, bool& identical,DataType default_value) + { + DataType data_value = DataType(); + 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); + 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) + { + DataType data_value = DataType(); + 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 ); + data_to_return = data_value; + } + +// + friend struct LLPanelFaceSetTEFunctor; // Must access some of these + // UI Widgets + LLView* mMediaInfo; + LLView* mMediaAdd; + LLView* mMediaDelete; + LLView* mLabelGlossy; + LLView* mLabelEnvironment; + LLView* mLabelShinyColor; + LLView* mLabelAlphaMode; + LLView* mLabelMaskCutoff; + LLView* mLabelBumpy; + LLView* mLabelShiny; + LLView* mLabelColor; + LLView* mLabelGlow; + LLView* mLabelTexGen; + LLComboBox* mComboShiny; + LLComboBox* mComboBumpy; + LLComboBox* mComboAlpha; + LLSpinCtrl* mCtrlTexScaleU; + LLUICtrl* mCtrlFlipTexScaleU; + LLSpinCtrl* mCtrlTexScaleV; + LLUICtrl* mCtrlFlipTexScaleV; + LLSpinCtrl* mCtrlTexRot; + LLUICtrl* mCtrlRpt; + LLUICtrl* mCtrlPlanar; + LLSpinCtrl* mCtrlTexOffsetU; + LLSpinCtrl* mCtrlTexOffsetV; + LLUICtrl* mBumpyScaleU; + LLUICtrl* mBumpyScaleV; + LLUICtrl* mBumpyRot; + LLUICtrl* mBumpyOffsetU; + LLUICtrl* mBumpyOffsetV; + LLUICtrl* mShinyScaleU; + LLUICtrl* mShinyScaleV; + LLUICtrl* mShinyRot; + LLUICtrl* mShinyOffsetU; + LLUICtrl* mShinyOffsetV; + LLUICtrl* mGlossyCtrl; + LLUICtrl* mEnvironmentCtrl; + LLUICtrl* mCtrlMaskCutoff; + LLUICtrl* mCtrlAlign; + LLUICtrl* mCtrlMapsSync; + LLUICtrl* mCtrlCopy; + LLUICtrl* mCtrlPaste; + LLTextureCtrl* mTextureCtrl; + LLTextureCtrl* mShinyTextureCtrl; + LLTextureCtrl* mBumpyTextureCtrl; + LLColorSwatchCtrl* mColorSwatch; + LLColorSwatchCtrl* mShinyColorSwatch; + + LLComboBox* mComboTexGen; + LLComboBox* mComboMatMedia; + LLComboBox* mComboMatType; + + LLCheckBoxCtrl* mCheckFullbright; + + LLTextBox* mLabelColorTransp; + LLSpinCtrl* mCtrlColorTransp; // transparency = 1 - alpha + + LLSpinCtrl* mCtrlGlow; +// + + // 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(); + + /* + * 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(LLInventoryItem* itemp); + + bool mIsAlpha; + + + #if defined(DEF_GET_MAT_STATE) + #undef DEF_GET_MAT_STATE + #endif + + #if defined(DEF_GET_TE_STATE) + #undef DEF_GET_TE_STATE + #endif + + #if defined(DEF_EDIT_MAT_STATE) + DEF_EDIT_MAT_STATE + #endif + + // Accessors for selected TE material state + // + #define DEF_GET_MAT_STATE(DataType,ReturnType,MaterialMemberFunc,DefaultValue) \ + static void MaterialMemberFunc(DataType& data, bool& identical) \ + { \ + getTEMaterialValue< DataType, ReturnType, &LLMaterial::MaterialMemberFunc >(data, identical,DefaultValue); \ + } + + // Mutators for selected TE material + // + #define DEF_EDIT_MAT_STATE(DataType,ReturnType,MaterialMemberFunc) \ + static void MaterialMemberFunc(LLPanelFace* p,DataType data) \ + { \ + edit< DataType, ReturnType, &LLMaterial::MaterialMemberFunc >(p,data); \ + } + + // Accessors for selected TE state proper (legacy settings etc) + // + #define DEF_GET_TE_STATE(DataType,ReturnType,TexEntryMemberFunc,DefaultValue) \ + static void TexEntryMemberFunc(DataType& data, bool& identical) \ + { \ + getTEValue< DataType, ReturnType, &LLTextureEntry::TexEntryMemberFunc >(data, identical,DefaultValue); \ + } + + 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); + + DEF_GET_MAT_STATE(LLUUID,const LLUUID&,getNormalID,LLUUID::null) + DEF_GET_MAT_STATE(LLUUID,const LLUUID&,getSpecularID,LLUUID::null) + DEF_GET_MAT_STATE(F32,F32,getSpecularRepeatX,1.0f) + DEF_GET_MAT_STATE(F32,F32,getSpecularRepeatY,1.0f) + DEF_GET_MAT_STATE(F32,F32,getSpecularOffsetX,0.0f) + DEF_GET_MAT_STATE(F32,F32,getSpecularOffsetY,0.0f) + DEF_GET_MAT_STATE(F32,F32,getSpecularRotation,0.0f) + + DEF_GET_MAT_STATE(F32,F32,getNormalRepeatX,1.0f) + DEF_GET_MAT_STATE(F32,F32,getNormalRepeatY,1.0f) + DEF_GET_MAT_STATE(F32,F32,getNormalOffsetX,0.0f) + DEF_GET_MAT_STATE(F32,F32,getNormalOffsetY,0.0f) + DEF_GET_MAT_STATE(F32,F32,getNormalRotation,0.0f) + + DEF_EDIT_MAT_STATE(U8,U8,setDiffuseAlphaMode); + DEF_EDIT_MAT_STATE(U8,U8,setAlphaMaskCutoff); + + DEF_EDIT_MAT_STATE(F32,F32,setNormalOffsetX); + DEF_EDIT_MAT_STATE(F32,F32,setNormalOffsetY); + DEF_EDIT_MAT_STATE(F32,F32,setNormalRepeatX); + DEF_EDIT_MAT_STATE(F32,F32,setNormalRepeatY); + DEF_EDIT_MAT_STATE(F32,F32,setNormalRotation); + + DEF_EDIT_MAT_STATE(F32,F32,setSpecularOffsetX); + DEF_EDIT_MAT_STATE(F32,F32,setSpecularOffsetY); + DEF_EDIT_MAT_STATE(F32,F32,setSpecularRepeatX); + DEF_EDIT_MAT_STATE(F32,F32,setSpecularRepeatY); + DEF_EDIT_MAT_STATE(F32,F32,setSpecularRotation); + + DEF_EDIT_MAT_STATE(U8,U8,setEnvironmentIntensity); + DEF_EDIT_MAT_STATE(U8,U8,setSpecularLightExponent); + + DEF_EDIT_MAT_STATE(LLUUID,const LLUUID&,setNormalID); + DEF_EDIT_MAT_STATE(LLUUID,const LLUUID&,setSpecularID); + DEF_EDIT_MAT_STATE(LLColor4U, const LLColor4U&,setSpecularLightColor); + }; + + class LLSelectedTE + { + public: + + static void getFace(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); + + DEF_GET_TE_STATE(U8,U8,getBumpmap,0) + DEF_GET_TE_STATE(U8,U8,getShiny,0) + DEF_GET_TE_STATE(U8,U8,getFullbright,0) + DEF_GET_TE_STATE(F32,F32,getRotation,0.0f) + DEF_GET_TE_STATE(F32,F32,getOffsetS,0.0f) + DEF_GET_TE_STATE(F32,F32,getOffsetT,0.0f) + DEF_GET_TE_STATE(F32,F32,getScaleS,1.0f) + DEF_GET_TE_STATE(F32,F32,getScaleT,1.0f) + DEF_GET_TE_STATE(F32,F32,getGlow,0.0f) + DEF_GET_TE_STATE(LLTextureEntry::e_texgen,LLTextureEntry::e_texgen,getTexGen,LLTextureEntry::TEX_GEN_DEFAULT) + DEF_GET_TE_STATE(LLColor4,const LLColor4&,getColor,LLColor4::white) + }; }; #endif diff --git a/indra/newview/llpanelgeneral.cpp b/indra/newview/llpanelgeneral.cpp index 812cbc80f8..30a0e64301 100644 --- a/indra/newview/llpanelgeneral.cpp +++ b/indra/newview/llpanelgeneral.cpp @@ -87,7 +87,7 @@ BOOL LLPanelGeneral::postBuild() childSetValue("ui_auto_scale", gSavedSettings.getBOOL("UIAutoScale")); LLComboBox* crash_behavior_combobox = getChild("crash_behavior_combobox"); - crash_behavior_combobox->setCurrentByIndex(gCrashSettings.getS32(CRASH_BEHAVIOR_SETTING)); + crash_behavior_combobox->setValue(gSavedSettings.getS32("CrashSubmitBehavior")); childSetValue("language_combobox", gSavedSettings.getString("Language")); @@ -142,19 +142,8 @@ void LLPanelGeneral::apply() LLComboBox* fade_out_combobox = getChild("fade_out_combobox"); gSavedSettings.setS32("RenderName", fade_out_combobox->getCurrentIndex()); - S32 namesystem_combobox_index = getChild("namesystem_combobox")->getCurrentIndex(); - BOOL show_resident = getChild("show_resident_checkbox")->getValue(); - if(gSavedSettings.getS32("PhoenixNameSystem")!=namesystem_combobox_index || gSavedSettings.getBOOL("LiruShowLastNameResident")!=show_resident){ - gSavedSettings.setS32("PhoenixNameSystem", namesystem_combobox_index); - gSavedSettings.setBOOL("LiruShowLastNameResident", show_resident); - if(gAgent.getRegion()){ - if(namesystem_combobox_index<=0 || namesystem_combobox_index>2) LLAvatarNameCache::setUseDisplayNames(false); - else LLAvatarNameCache::setUseDisplayNames(true); - LLVOAvatar::invalidateNameTags(); // Remove all clienttags to get them updated - - LLAvatarTracker::instance().updateFriends(); - } - } + gSavedSettings.setS32("PhoenixNameSystem", getChild("namesystem_combobox")->getCurrentIndex()); + gSavedSettings.setBOOL("LiruShowLastNameResident", getChild("show_resident_checkbox")->getValue()); gSavedSettings.setString("LoginLocation", childGetValue("default_start_location").asString()); gSavedSettings.setBOOL("ShowStartLocation", childGetValue("show_location_checkbox")); @@ -174,7 +163,7 @@ void LLPanelGeneral::apply() gSavedSettings.setString("Language", childGetValue("language_combobox")); LLComboBox* crash_behavior_combobox = getChild("crash_behavior_combobox"); - gCrashSettings.setS32(CRASH_BEHAVIOR_SETTING, crash_behavior_combobox->getCurrentIndex()); + gSavedSettings.setS32("CrashSubmitBehavior", crash_behavior_combobox->getValue()); } void LLPanelGeneral::cancel() diff --git a/indra/newview/llpanelgroup.cpp b/indra/newview/llpanelgroup.cpp index 4975ddcd7c..56e61a5597 100644 --- a/indra/newview/llpanelgroup.cpp +++ b/indra/newview/llpanelgroup.cpp @@ -34,6 +34,7 @@ #include "llpanelgroup.h" // Library includes +#include "lfidbearer.h" #include "llbutton.h" #include "lltabcontainer.h" #include "lltextbox.h" @@ -53,6 +54,9 @@ #include "llpanelgrouproles.h" #include "llpanelgroupvoting.h" #include "llpanelgrouplandmoney.h" +#include "llpanelgroupexperiences.h" + +#include "hippogridmanager.h" // static void* LLPanelGroupTab::createTab(void* data) @@ -129,10 +133,7 @@ void LLPanelGroupTab::handleClickHelp() } } -static void copy_group_profile_uri(const LLUUID& id) -{ - gViewerWindow->getWindow()->copyTextToClipboard(utf8str_to_wstring("secondlife:///app/group/"+id.asString()+"/about")); -} +void copy_profile_uri(const LLUUID& id, const LFIDBearer::Type& type); LLPanelGroup::LLPanelGroup(const LLUUID& group_id) : LLPanel("PanelGroup", LLRect(), FALSE), @@ -156,14 +157,17 @@ LLPanelGroup::LLPanelGroup(const LLUUID& group_id) &mID); mFactoryMap["land_money_tab"]= LLCallbackMap(LLPanelGroupLandMoney::createTab, &mID); + mFactoryMap["experiences_tab"] = LLCallbackMap(LLPanelGroupExperiences::createTab, + &mID); // Roles sub tabs mFactoryMap["members_sub_tab"] = LLCallbackMap(LLPanelGroupMembersSubTab::createTab, &mID); mFactoryMap["roles_sub_tab"] = LLCallbackMap(LLPanelGroupRolesSubTab::createTab, &mID); mFactoryMap["actions_sub_tab"] = LLCallbackMap(LLPanelGroupActionsSubTab::createTab, &mID); + mFactoryMap["banlist_sub_tab"] = LLCallbackMap(LLPanelGroupBanListSubTab::createTab, &mID); LLGroupMgr::getInstance()->addObserver(this); - mCommitCallbackRegistrar.add("Group.CopyURI", boost::bind(copy_group_profile_uri, group_id)); + mCommitCallbackRegistrar.add("Group.CopyURI", boost::bind(copy_profile_uri, boost::ref(mID), LFIDBearer::GROUP)); // Pass on construction of this panel to the control factory. LLUICtrlFactory::getInstance()->buildPanel(this, "panel_group.xml", &getFactoryMap()); } @@ -210,6 +214,14 @@ BOOL LLPanelGroup::postBuild() if (mTabContainer) { + // Group Voting no longer exists on SecondLife, hide it + if (gHippoGridManager->getConnectedGrid()->isSecondLife()) + { + auto panel = mTabContainer->getPanelByName("voting_tab"); + mTabContainer->removeTabPanel(panel); + delete panel; + } + //our initial tab selection was invalid, just select the //first tab then or default to selecting the initial //selected tab specified in the layout file diff --git a/indra/newview/llpanelgroup.h b/indra/newview/llpanelgroup.h index f9ea381369..1367c87603 100644 --- a/indra/newview/llpanelgroup.h +++ b/indra/newview/llpanelgroup.h @@ -168,12 +168,16 @@ class LLPanelGroupTab : public LLPanel virtual BOOL isVisibleByAgent(LLAgent* agentp); + virtual void setGroupID(const LLUUID& id) { mGroupID = id; } + void setAllowEdit(BOOL v) { mAllowEdit = v; } void addObserver(LLPanelGroupTabObserver *obs); void removeObserver(LLPanelGroupTabObserver *obs); void notifyObservers(); + const LLUUID& getGroupID() const { return mGroupID; } + protected: LLUUID mGroupID; LLTabContainer* mTabContainer; diff --git a/indra/newview/llpanelgroupbulk.cpp b/indra/newview/llpanelgroupbulk.cpp new file mode 100644 index 0000000000..0414594305 --- /dev/null +++ b/indra/newview/llpanelgroupbulk.cpp @@ -0,0 +1,418 @@ +/** +* @file llpanelgroupbulk.cpp +* @brief Implementation of llpanelgroupbulk +* @author Baker@lindenlab.com +* +* $LicenseInfo:firstyear=2013&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2013, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#include "llviewerprecompiledheaders.h" + +#include "llpanelgroupbulk.h" +#include "llpanelgroupbulkimpl.h" + +#include "llagent.h" +#include "llavatarnamecache.h" +#include "llfloateravatarpicker.h" +#include "llbutton.h" +#include "llcallingcard.h" +#include "llcombobox.h" +#include "llgroupactions.h" +#include "llgroupmgr.h" +#include "llnamelistctrl.h" +#include "llnotificationsutil.h" +#include "llscrolllistitem.h" +#include "llspinctrl.h" +#include "lltextbox.h" +#include "llviewerobject.h" +#include "llviewerobjectlist.h" +#include "lluictrlfactory.h" +#include "llviewerwindow.h" + + +////////////////////////////////////////////////////////////////////////// +// Implementation of llpanelgroupbulkimpl.h functions +////////////////////////////////////////////////////////////////////////// +LLPanelGroupBulkImpl::LLPanelGroupBulkImpl(const LLUUID& group_id) : + mGroupID(group_id), + mBulkAgentList(NULL), + mOKButton(NULL), + mRemoveButton(NULL), + mGroupName(NULL), + mLoadingText(), + mTooManySelected(), + mCloseCallback(NULL), + mCloseCallbackUserData(NULL), + mRoleNames(NULL), + mOwnerWarning(), + mAlreadyInGroup(), + mConfirmedOwnerInvite(false), + mListFullNotificationSent(false) +{} + +LLPanelGroupBulkImpl::~LLPanelGroupBulkImpl() +{ + for (avatar_name_cache_connection_map_t::iterator it = mAvatarNameCacheConnections.begin(); it != mAvatarNameCacheConnections.end(); ++it) + { + if (it->second.connected()) + { + it->second.disconnect(); + } + } + mAvatarNameCacheConnections.clear(); +} + +void LLPanelGroupBulkImpl::callbackClickAdd(void* userdata) +{ + LLPanelGroupBulk* panelp = (LLPanelGroupBulk*)userdata; + + if(panelp) + { + //Right now this is hard coded with some knowledge that it is part + //of a floater since the avatar picker needs to be added as a dependent + //floater to the parent floater. + //Soon the avatar picker will be embedded into this panel + //instead of being it's own separate floater. But that is next week. + //This will do for now. -jwolk May 10, 2006 + /* Singu Note: We're different, we don't do this.. + LLView* button = panelp->findChild("add_button"); + */ + LLFloater* root_floater = gFloaterView->getParentFloater(panelp); + LLFloaterAvatarPicker* picker = LLFloaterAvatarPicker::show( + // boost::bind(callbackAddUsers, _1, panelp->mImplementation), TRUE, FALSE, FALSE, root_floater->getName(), button); + boost::bind(&LLPanelGroupBulkImpl::callbackAddUsers, panelp->mImplementation, _1), TRUE); + if(picker) + { + root_floater->addDependentFloater(picker); + } + } +} + +void LLPanelGroupBulkImpl::callbackClickRemove(void* userdata) +{ + LLPanelGroupBulkImpl* selfp = (LLPanelGroupBulkImpl*)userdata; + if (selfp) + selfp->handleRemove(); +} + +void LLPanelGroupBulkImpl::callbackClickCancel(void* userdata) +{ + LLPanelGroupBulkImpl* selfp = (LLPanelGroupBulkImpl*)userdata; + if(selfp) + (*(selfp->mCloseCallback))(selfp->mCloseCallbackUserData); +} + +void LLPanelGroupBulkImpl::callbackSelect(LLUICtrl* ctrl, void* userdata) +{ + LLPanelGroupBulkImpl* selfp = (LLPanelGroupBulkImpl*)userdata; + if (selfp) + selfp->handleSelection(); +} + +void LLPanelGroupBulkImpl::callbackAddUsers(const uuid_vec_t& agent_ids) +{ + std::vector names; + for (S32 i = 0; i < (S32)agent_ids.size(); i++) + { + LLAvatarName av_name; + if (LLAvatarNameCache::get(agent_ids[i], &av_name)) + { + onAvatarNameCache(agent_ids[i], av_name); + } + else + { + if (mAvatarNameCacheConnections[agent_ids[i]].connected()) + { + mAvatarNameCacheConnections[agent_ids[i]].disconnect(); + } + // *TODO : Add a callback per avatar name being fetched. + mAvatarNameCacheConnections[agent_ids[i]] = LLAvatarNameCache::get(agent_ids[i],boost::bind(&LLPanelGroupBulkImpl::onAvatarNameCache, this, _1, _2)); + } + } +} + +void LLPanelGroupBulkImpl::onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name) +{ + if (mAvatarNameCacheConnections[agent_id].connected()) + { + mAvatarNameCacheConnections[agent_id].disconnect(); + } + std::vector names; + uuid_vec_t agent_ids; + agent_ids.push_back(agent_id); + names.push_back(av_name.getNSName()); + + addUsers(names, agent_ids); +} + +void LLPanelGroupBulkImpl::handleRemove() +{ + std::vector selection = mBulkAgentList->getAllSelected(); + if (selection.empty()) + return; + + std::vector::iterator iter; + for(iter = selection.begin(); iter != selection.end(); ++iter) + { + mInviteeIDs.erase((*iter)->getUUID()); + } + + mBulkAgentList->deleteSelectedItems(); + mRemoveButton->setEnabled(FALSE); + + if( mOKButton && mOKButton->getEnabled() && + mBulkAgentList->isEmpty()) + { + mOKButton->setEnabled(FALSE); + } +} + +void LLPanelGroupBulkImpl::handleSelection() +{ + std::vector selection = mBulkAgentList->getAllSelected(); + if (selection.empty()) + mRemoveButton->setEnabled(FALSE); + else + mRemoveButton->setEnabled(TRUE); +} + +void LLPanelGroupBulkImpl::addUsers(const std::vector& names, const uuid_vec_t& agent_ids) +{ + std::string name; + LLUUID id; + + if(mListFullNotificationSent) + { + return; + } + + if( !mListFullNotificationSent && + (names.size() + mInviteeIDs.size() > MAX_GROUP_INVITES)) + { + mListFullNotificationSent = true; + + // Fail! Show a warning and don't add any names. + LLSD msg; + msg["MESSAGE"] = mTooManySelected; + LLNotificationsUtil::add("GenericAlert", msg); + return; + } + + for (S32 i = 0; i < (S32)names.size(); ++i) + { + name = names[i]; + id = agent_ids[i]; + + if(mInviteeIDs.find(id) != mInviteeIDs.end()) + { + continue; + } + + //add the name to the names list + LLSD row; + row["id"] = id; + row["columns"][0]["value"] = name; + + mBulkAgentList->addElement(row); + mInviteeIDs.insert(id); + + // We've successfully added someone to the list. + if(mOKButton && !mOKButton->getEnabled()) + mOKButton->setEnabled(TRUE); + } +} + +void LLPanelGroupBulkImpl::setGroupName(std::string name) +{ + if(mGroupName) + mGroupName->setText(name); +} + + +LLPanelGroupBulk::LLPanelGroupBulk(const LLUUID& group_id) : + LLPanel(), + mImplementation(new LLPanelGroupBulkImpl(group_id)), + mPendingGroupPropertiesUpdate(false), + mPendingRoleDataUpdate(false), + mPendingMemberDataUpdate(false) +{} + +LLPanelGroupBulk::~LLPanelGroupBulk() +{ + delete mImplementation; +} + +void LLPanelGroupBulk::clear() +{ + mImplementation->mInviteeIDs.clear(); + + if(mImplementation->mBulkAgentList) + mImplementation->mBulkAgentList->deleteAllItems(); + + if(mImplementation->mOKButton) + mImplementation->mOKButton->setEnabled(FALSE); +} + +void LLPanelGroupBulk::update() +{ + updateGroupName(); + updateGroupData(); +} + +void LLPanelGroupBulk::draw() +{ + LLPanel::draw(); + update(); +} + +void LLPanelGroupBulk::updateGroupName() +{ + LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mImplementation->mGroupID); + + if( gdatap && + gdatap->isGroupPropertiesDataComplete()) + { + // Only do work if the current group name differs + if(mImplementation->mGroupName->getText().compare(gdatap->mName) != 0) + mImplementation->setGroupName(gdatap->mName); + } + else + { + mImplementation->setGroupName(mImplementation->mLoadingText); + } +} + +void LLPanelGroupBulk::updateGroupData() +{ + LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mImplementation->mGroupID); + if(gdatap && gdatap->isGroupPropertiesDataComplete()) + { + mPendingGroupPropertiesUpdate = false; + } + else + { + if(!mPendingGroupPropertiesUpdate) + { + mPendingGroupPropertiesUpdate = true; + LLGroupMgr::getInstance()->sendGroupPropertiesRequest(mImplementation->mGroupID); + } + } + + if(gdatap && gdatap->isRoleDataComplete()) + { + mPendingRoleDataUpdate = false; + } + else + { + if(!mPendingRoleDataUpdate) + { + mPendingRoleDataUpdate = true; + LLGroupMgr::getInstance()->sendGroupRoleDataRequest(mImplementation->mGroupID); + } + } + + if(gdatap && gdatap->isMemberDataComplete()) + { + mPendingMemberDataUpdate = false; + } + else + { + if(!mPendingMemberDataUpdate) + { + mPendingMemberDataUpdate = true; + LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mImplementation->mGroupID); + } + } +} + +void LLPanelGroupBulk::addUserCallback(const LLUUID& id, const LLAvatarName& av_name) +{ + std::vector names; + uuid_vec_t agent_ids; + agent_ids.push_back(id); + names.push_back(av_name.getNSName()); + + mImplementation->addUsers(names, agent_ids); +} + +void LLPanelGroupBulk::setCloseCallback(void (*close_callback)(void*), void* data) +{ + mImplementation->mCloseCallback = close_callback; + mImplementation->mCloseCallbackUserData = data; +} + +void LLPanelGroupBulk::addUsers(uuid_vec_t& agent_ids) +{ + std::vector names; + for (S32 i = 0; i < (S32)agent_ids.size(); i++) + { + std::string fullname; + LLUUID agent_id = agent_ids[i]; + LLViewerObject* dest = gObjectList.findObject(agent_id); + if(dest && dest->isAvatar()) + { + LLNameValue* nvfirst = dest->getNVPair("FirstName"); + LLNameValue* nvlast = dest->getNVPair("LastName"); + if(nvfirst && nvlast) + { + fullname = LLCacheName::buildFullName( + nvfirst->getString(), nvlast->getString()); + + } + if (!fullname.empty()) + { + names.push_back(fullname); + } + else + { + LL_WARNS() << "llPanelGroupBulk: Selected avatar has no name: " << dest->getID() << LL_ENDL; + names.push_back("(Unknown)"); + } + } + else + { + //looks like user try to invite offline friend + //for offline avatar_id gObjectList.findObject() will return null + //so we need to do this additional search in avatar tracker, see EXT-4732 + //if (LLAvatarTracker::instance().isBuddy(agent_id)) // Singu Note: We may be using this from another avatar list like group profile, disregard friendship status. + { + LLAvatarName av_name; + if (!LLAvatarNameCache::get(agent_id, &av_name)) + { + // actually it should happen, just in case + LLAvatarNameCache::get(LLUUID(agent_id), boost::bind(&LLPanelGroupBulk::addUserCallback, this, _1, _2)); + // for this special case! + //when there is no cached name we should remove resident from agent_ids list to avoid breaking of sequence + // removed id will be added in callback + agent_ids.erase(agent_ids.begin() + i); + } + else + { + names.push_back(av_name.getNSName()); + } + } + } + } + mImplementation->mListFullNotificationSent = false; + mImplementation->addUsers(names, agent_ids); +} + diff --git a/indra/newview/llpanelgroupbulk.h b/indra/newview/llpanelgroupbulk.h new file mode 100644 index 0000000000..4c8081b738 --- /dev/null +++ b/indra/newview/llpanelgroupbulk.h @@ -0,0 +1,74 @@ +/** +* @file llpanelgroupbulk.h +* @brief Header file for llpanelgroupbulk +* @author Baker@lindenlab.com +* +* $LicenseInfo:firstyear=2013&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2013, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ +#ifndef LL_LLPANELGROUPBULK_H +#define LL_LLPANELGROUPBULK_H + +#include "llpanel.h" +#include "lluuid.h" + +class LLAvatarName; +class LLGroupMgrGroupData; +class LLPanelGroupBulkImpl; + +// Base panel class for bulk group invite / ban floaters +class LLPanelGroupBulk : public LLPanel +{ +public: + LLPanelGroupBulk(const LLUUID& group_id); + /*virtual*/ ~LLPanelGroupBulk(); + +public: + static void callbackClickSubmit(void* userdata) {} + virtual void submit() = 0; + +public: + virtual void clear(); + virtual void update(); + virtual void draw(); + +protected: + virtual void updateGroupName(); + virtual void updateGroupData(); + +public: + // this callback is being used to add a user whose fullname isn't been loaded before invoking of addUsers(). + virtual void addUserCallback(const LLUUID& id, const LLAvatarName& av_name); + virtual void setCloseCallback(void (*close_callback)(void*), void* data); + + virtual void addUsers(uuid_vec_t& agent_ids); + +public: + LLPanelGroupBulkImpl* mImplementation; + +protected: + bool mPendingGroupPropertiesUpdate; + bool mPendingRoleDataUpdate; + bool mPendingMemberDataUpdate; +}; + +#endif // LL_LLPANELGROUPBULK_H + diff --git a/indra/newview/llpanelgroupbulkban.cpp b/indra/newview/llpanelgroupbulkban.cpp new file mode 100644 index 0000000000..aa7f55196a --- /dev/null +++ b/indra/newview/llpanelgroupbulkban.cpp @@ -0,0 +1,248 @@ +/** +* @file llpanelgroupbulkban.cpp +* +* $LicenseInfo:firstyear=2013&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2013, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#include "llviewerprecompiledheaders.h" + +#include "llpanelgroupbulkban.h" +#include "llpanelgroupbulk.h" +#include "llpanelgroupbulkimpl.h" + +#include "llagent.h" +#include "llavatarnamecache.h" +#include "llavataractions.h" +#include "llfloateravatarpicker.h" +#include "llbutton.h" +#include "llcallingcard.h" +#include "llcombobox.h" +#include "llgroupactions.h" +#include "llgroupmgr.h" +#include "llnamelistctrl.h" +#include "llnotificationsutil.h" +#include "llscrolllistitem.h" +#include "llslurl.h" +#include "llspinctrl.h" +#include "lltextbox.h" +#include "llviewerobject.h" +#include "llviewerobjectlist.h" +#include "lluictrlfactory.h" +#include "llviewerwindow.h" + +LLPanelGroupBulkBan::LLPanelGroupBulkBan(const LLUUID& group_id) : LLPanelGroupBulk(group_id) +{ + // Pass on construction of this panel to the control factory. + //buildFromFile( "panel_group_bulk_ban.xml"); + LLUICtrlFactory::getInstance()->buildPanel(this, "panel_group_bulk_ban.xml"); +} + +BOOL LLPanelGroupBulkBan::postBuild() +{ + BOOL recurse = TRUE; + + mImplementation->mLoadingText = getString("loading"); + mImplementation->mGroupName = getChild("group_name_text", recurse); + mImplementation->mBulkAgentList = getChild("banned_agent_list", recurse); + if ( mImplementation->mBulkAgentList ) + { + mImplementation->mBulkAgentList->setCommitOnSelectionChange(TRUE); + mImplementation->mBulkAgentList->setCommitCallback(LLPanelGroupBulkImpl::callbackSelect, mImplementation); + } + + LLButton* button = getChild("add_button", recurse); + if ( button ) + { + // default to opening avatarpicker automatically + // (*impl::callbackClickAdd)((void*)this); + button->setClickedCallback(LLPanelGroupBulkImpl::callbackClickAdd, this); + } + + mImplementation->mRemoveButton = + getChild("remove_button", recurse); + if ( mImplementation->mRemoveButton ) + { + mImplementation->mRemoveButton->setClickedCallback(LLPanelGroupBulkImpl::callbackClickRemove, mImplementation); + mImplementation->mRemoveButton->setEnabled(FALSE); + } + + mImplementation->mOKButton = + getChild("ban_button", recurse); + if ( mImplementation->mOKButton ) + { + mImplementation->mOKButton->setCommitCallback(boost::bind(&LLPanelGroupBulkBan::submit, this)); + mImplementation->mOKButton->setEnabled(FALSE); + } + + button = getChild("cancel_button", recurse); + if ( button ) + { + button->setClickedCallback(LLPanelGroupBulkImpl::callbackClickCancel, mImplementation); + } + + mImplementation->mTooManySelected = getString("ban_selection_too_large"); + mImplementation->mBanNotPermitted = getString("ban_not_permitted"); + mImplementation->mBanLimitFail = getString("ban_limit_fail"); + mImplementation->mCannotBanYourself = getString("cant_ban_yourself"); + + update(); + return TRUE; +} + +void LLPanelGroupBulkBan::submit() +{ + if (!gAgent.hasPowerInGroup(mImplementation->mGroupID, GP_GROUP_BAN_ACCESS)) + { + // Fail! Agent no longer have ban rights. Permissions could have changed after button was pressed. + LLSD msg; + msg["MESSAGE"] = mImplementation->mBanNotPermitted; + LLNotificationsUtil::add("GenericAlert", msg); + (*(mImplementation->mCloseCallback))(mImplementation->mCloseCallbackUserData); + return; + } + LLGroupMgrGroupData * group_datap = LLGroupMgr::getInstance()->getGroupData(mImplementation->mGroupID); + if (group_datap && group_datap->mBanList.size() >= GB_MAX_BANNED_AGENTS) + { + // Fail! Size limit exceeded. List could have updated after button was pressed. + LLSD msg; + msg["MESSAGE"] = mImplementation->mBanLimitFail; + LLNotificationsUtil::add("GenericAlert", msg); + (*(mImplementation->mCloseCallback))(mImplementation->mCloseCallbackUserData); + return; + } + uuid_vec_t banned_agent_list; + std::vector agents = mImplementation->mBulkAgentList->getAllData(); + std::vector::iterator iter = agents.begin(); + for(;iter != agents.end(); ++iter) + { + LLScrollListItem* agent = *iter; + banned_agent_list.push_back(agent->getUUID()); + } + + const S32 MAX_BANS_PER_REQUEST = 100; // Max bans per request. 100 to match server cap. + if (banned_agent_list.size() > MAX_BANS_PER_REQUEST) + { + // Fail! + LLSD msg; + msg["MESSAGE"] = mImplementation->mTooManySelected; + LLNotificationsUtil::add("GenericAlert", msg); + (*(mImplementation->mCloseCallback))(mImplementation->mCloseCallbackUserData); + return; + } + + // remove already banned users and yourself from request. + std::vector banned_avatar_names; + std::vector out_of_limit_names; + bool banning_self = FALSE; + auto conflict = std::find(banned_agent_list.begin(), banned_agent_list.end(), gAgent.getID()); + if (conflict != banned_agent_list.end()) + { + banned_agent_list.erase(conflict); + banning_self = TRUE; + } + if (group_datap) + { + for (const LLGroupMgrGroupData::ban_list_t::value_type& group_ban_pair : group_datap->mBanList) + { + const LLUUID& group_ban_agent_id = group_ban_pair.first; + auto conflict = std::find(banned_agent_list.begin(), banned_agent_list.end(), group_ban_agent_id); + if (conflict != banned_agent_list.end()) + { + LLAvatarName av_name; + LLAvatarNameCache::get(group_ban_agent_id, &av_name); + banned_avatar_names.push_back(av_name); + + banned_agent_list.erase(conflict); + if (banned_agent_list.size() == 0) + { + break; + } + } + } + // this check should always be the last one before we send the request. + // Otherwise we have a possibility of cutting more then we need to. + if (banned_agent_list.size() > GB_MAX_BANNED_AGENTS - group_datap->mBanList.size()) + { + auto exeedes_limit = banned_agent_list.begin() + GB_MAX_BANNED_AGENTS - group_datap->mBanList.size(); + for (auto itor = exeedes_limit ; + itor != banned_agent_list.end(); ++itor) + { + LLAvatarName av_name; + LLAvatarNameCache::get(*itor, &av_name); + out_of_limit_names.push_back(av_name); + } + banned_agent_list.erase(exeedes_limit,banned_agent_list.end()); + } + } + + // sending request and ejecting members + if (banned_agent_list.size() != 0) + { + LLGroupMgr::getInstance()->sendGroupBanRequest(LLGroupMgr::REQUEST_POST, mImplementation->mGroupID, LLGroupMgr::BAN_CREATE | LLGroupMgr::BAN_UPDATE, banned_agent_list); + LLGroupMgr::getInstance()->sendGroupMemberEjects(mImplementation->mGroupID, banned_agent_list); + } + + // building notification + if (banned_avatar_names.size() > 0 || banning_self || out_of_limit_names.size() > 0) + { + std::string reasons; + if(banned_avatar_names.size() > 0) + { + reasons = "\n " + buildResidentsArgument(banned_avatar_names, "residents_already_banned"); + } + + if(banning_self) + { + reasons += "\n " + mImplementation->mCannotBanYourself; + } + + if(out_of_limit_names.size() > 0) + { + reasons += "\n " + buildResidentsArgument(out_of_limit_names, "ban_limit_reached"); + } + + LLStringUtil::format_map_t msg_args; + msg_args["[REASONS]"] = reasons; + LLSD msg; + if (banned_agent_list.size() == 0) + { + msg["MESSAGE"] = getString("ban_failed", msg_args); + } + else + { + msg["MESSAGE"] = getString("partial_ban", msg_args); + } + LLNotificationsUtil::add("GenericAlert", msg); + } + + //then close + (*(mImplementation->mCloseCallback))(mImplementation->mCloseCallbackUserData); +} + +std::string LLPanelGroupBulkBan::buildResidentsArgument(std::vector avatar_names, const std::string &format) +{ + std::string names_string; + LLAvatarActions::buildResidentsString(avatar_names, names_string); + LLStringUtil::format_map_t args; + args["[RESIDENTS]"] = names_string; + return getString(format, args); +} diff --git a/indra/newview/llpanelgroupbulkban.h b/indra/newview/llpanelgroupbulkban.h new file mode 100644 index 0000000000..150bb43c76 --- /dev/null +++ b/indra/newview/llpanelgroupbulkban.h @@ -0,0 +1,49 @@ +/** +* @file llpanelgroupbulkban.h +* +* $LicenseInfo:firstyear=2013&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2013, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#ifndef LL_LLPANELGROUPBULKBAN_H +#define LL_LLPANELGROUPBULKBAN_H + +#include "llpanel.h" +#include "lluuid.h" +#include "llpanelgroupbulk.h" + +class LLAvatarName; + +class LLPanelGroupBulkBan : public LLPanelGroupBulk +{ +public: + LLPanelGroupBulkBan(const LLUUID& group_id); + ~LLPanelGroupBulkBan() {} + + virtual BOOL postBuild(); + + //static void callbackClickSubmit(void* userdata); + virtual void submit(); +private: + std::string buildResidentsArgument(std::vector avatar_names, const std::string &format); +}; + +#endif // LL_LLPANELGROUPBULKBAN_H diff --git a/indra/newview/llpanelgroupbulkimpl.h b/indra/newview/llpanelgroupbulkimpl.h new file mode 100644 index 0000000000..ec2e06b477 --- /dev/null +++ b/indra/newview/llpanelgroupbulkimpl.h @@ -0,0 +1,100 @@ + /** +* @file llpanelgroupbulkimpl.h +* @brief Class definition for implementation class of LLPanelGroupBulk +* @author Baker@lindenlab.com +* +* $LicenseInfo:firstyear=2013&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2013, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ +#ifndef LL_LLPANELGROUPBULKIMPL_H +#define LL_LLPANELGROUPBULKIMPL_H + +#include "llpanel.h" +#include "lluuid.h" + +class LLAvatarName; +class LLNameListCtrl; +class LLTextBox; +class LLComboBox; + +////////////////////////////////////////////////////////////////////////// +// Implementation found in llpanelgroupbulk.cpp +////////////////////////////////////////////////////////////////////////// +class LLPanelGroupBulkImpl +{ +public: + LLPanelGroupBulkImpl(const LLUUID& group_id); + ~LLPanelGroupBulkImpl(); + + static void callbackClickAdd(void* userdata); + static void callbackClickRemove(void* userdata); + + static void callbackClickCancel(void* userdata); + + static void callbackSelect(LLUICtrl* ctrl, void* userdata); + void callbackAddUsers(const uuid_vec_t& agent_ids); + + void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name); + + void handleRemove(); + void handleSelection(); + + void addUsers(const std::vector& names, const uuid_vec_t& agent_ids); + void setGroupName(std::string name); + + +public: + static const S32 MAX_GROUP_INVITES = 100; // Max invites per request. 100 to match server cap. + + + LLUUID mGroupID; + + LLNameListCtrl* mBulkAgentList; + LLButton* mOKButton; + LLButton* mRemoveButton; + LLTextBox* mGroupName; + + std::string mLoadingText; + std::string mTooManySelected; + std::string mBanNotPermitted; + std::string mBanLimitFail; + std::string mCannotBanYourself; + + uuid_set_t mInviteeIDs; + + void (*mCloseCallback)(void* data); + void* mCloseCallbackUserData; + typedef std::map avatar_name_cache_connection_map_t; + avatar_name_cache_connection_map_t mAvatarNameCacheConnections; + + // The following are for the LLPanelGroupInvite subclass only. + // These aren't needed for LLPanelGroupBulkBan, but if we have to add another + // group bulk floater for some reason, we'll have these objects too. +public: + LLComboBox* mRoleNames; + std::string mOwnerWarning; + std::string mAlreadyInGroup; + bool mConfirmedOwnerInvite; + bool mListFullNotificationSent; +}; + +#endif // LL_LLPANELGROUPBULKIMPL_H + diff --git a/indra/newview/llpanelgroupexperiences.cpp b/indra/newview/llpanelgroupexperiences.cpp new file mode 100644 index 0000000000..76553b4334 --- /dev/null +++ b/indra/newview/llpanelgroupexperiences.cpp @@ -0,0 +1,130 @@ +/** + * @file llpanelgroupexperiences.cpp + * @brief List of experiences owned by a group. + * + * $LicenseInfo:firstyear=2006&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llpanelgroupexperiences.h" + +#include "lluictrlfactory.h" +#include "llappviewer.h" +#include "llexperiencecache.h" +#include "llnamelistctrl.h" + +void addExperienceToList(const LLSD& experience, LLNameListCtrl* list); + +//static LLPanelInjector t_panel_group_experiences("panel_group_experiences"); +//static +void* LLPanelGroupExperiences::createTab(void* data) +{ + LLUUID* group_id = static_cast(data); + return new LLPanelGroupExperiences("panel group experiences", *group_id); +} + + +LLPanelGroupExperiences::LLPanelGroupExperiences(const std::string& name, const LLUUID& id) +: LLPanelGroupTab(name, id), mExperiencesList(nullptr) +{ +} + +LLPanelGroupExperiences::~LLPanelGroupExperiences() +{ +} + +BOOL LLPanelGroupExperiences::isVisibleByAgent(LLAgent* agentp) +{ + //default to being visible + return TRUE; +} + +BOOL LLPanelGroupExperiences::postBuild() +{ + mExperiencesList = getChild("experiences_list"); + if (hasString("loading_experiences")) + { + mExperiencesList->setCommentText(getString("loading_experiences")); + } + else if (hasString("no_experiences")) + { + mExperiencesList->setCommentText(getString("no_experiences")); + } + + return LLPanelGroupTab::postBuild(); +} + +void LLPanelGroupExperiences::activate() +{ + if ((getGroupID() == LLUUID::null) || gDisconnected) + { + return; + } + + LLExperienceCache::instance().getGroupExperiences(getGroupID(), + boost::bind(&LLPanelGroupExperiences::groupExperiencesResults, getDerivedHandle(), _1)); +} + +void LLPanelGroupExperiences::setGroupID(const LLUUID& id) +{ + LLPanelGroupTab::setGroupID(id); + + if (id == LLUUID::null) + { + return; + } + + activate(); +} + +void LLPanelGroupExperiences::setExperienceList(const LLSD& experiences) +{ + if (hasString("no_experiences")) + { + mExperiencesList->setCommentText(getString("no_experiences")); + } + mExperiencesList->clear(); + + auto& cache = LLExperienceCache::instance(); + for (const auto& exp : experiences.array()) + { + LLUUID public_key = exp.asUUID(); + if (public_key.notNull()) + cache.get(public_key, boost::bind(addExperienceToList, _1, mExperiencesList)); + } +} + +/*static*/ +void LLPanelGroupExperiences::groupExperiencesResults(LLHandle handle, const LLSD &experiences) +{ + if (handle.isDead()) + { + return; + } + + LLPanelGroupExperiences* panel = handle.get(); + if (panel) + { + panel->setExperienceList(experiences); + } +} diff --git a/indra/newview/llpanelgroupexperiences.h b/indra/newview/llpanelgroupexperiences.h new file mode 100644 index 0000000000..e16cd98adb --- /dev/null +++ b/indra/newview/llpanelgroupexperiences.h @@ -0,0 +1,56 @@ +/** + * @file llpanelgroupexperiences.h + * @brief List of experiences owned by a group. + * + * $LicenseInfo:firstyear=2006&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLPANELGROUPEXPERIENCES_H +#define LL_LLPANELGROUPEXPERIENCES_H + +#include "llpanelgroup.h" + +class LLPanelGroupExperiences final : public LLPanelGroupTab +{ +public: + static void* createTab(void* data); + LLPanelGroupExperiences(const std::string& name, const LLUUID& id); + virtual ~LLPanelGroupExperiences(); + + // LLPanelGroupTab + void activate() override; + BOOL isVisibleByAgent(LLAgent* agentp) override; + + BOOL postBuild() override; + + void setGroupID(const LLUUID& id) override; + + void setExperienceList(const LLSD& experiences); + +protected: + class LLNameListCtrl* mExperiencesList; + +private: + static void groupExperiencesResults(LLHandle, const LLSD &); +}; + +#endif diff --git a/indra/newview/llpanelgroupgeneral.cpp b/indra/newview/llpanelgroupgeneral.cpp index ac3ecd30ef..54a73ccc02 100644 --- a/indra/newview/llpanelgroupgeneral.cpp +++ b/indra/newview/llpanelgroupgeneral.cpp @@ -35,6 +35,7 @@ #include "llpanelgroupgeneral.h" #include "llagent.h" +#include "llagentbenefits.h" #include "lluictrlfactory.h" #include "roles_constants.h" @@ -43,7 +44,6 @@ #include "llcheckboxctrl.h" #include "llcombobox.h" #include "lldbstrings.h" -#include "llavataractions.h" #include "llgroupactions.h" #include "llimview.h" #include "lllineeditor.h" @@ -83,7 +83,6 @@ LLPanelGroupGeneral::LLPanelGroupGeneral(const std::string& name, mGroupNameEditor(NULL), mFounderName(NULL), mInsignia(NULL), - mGroupName(NULL), mEditCharter(NULL), mBtnJoinGroup(NULL), mListVisibleMembers(NULL), @@ -103,23 +102,35 @@ LLPanelGroupGeneral::LLPanelGroupGeneral(const std::string& name, LLPanelGroupGeneral::~LLPanelGroupGeneral() { + for (avatar_name_cache_connection_map_t::iterator it = mAvatarNameCacheConnections.begin(); it != mAvatarNameCacheConnections.end(); ++it) + { + if (it->second.connected()) + { + it->second.disconnect(); + } + } + mAvatarNameCacheConnections.clear(); } BOOL LLPanelGroupGeneral::postBuild() { - llinfos << "LLPanelGroupGeneral::postBuild()" << llendl; + LL_INFOS() << "LLPanelGroupGeneral::postBuild()" << LL_ENDL; bool recurse = true; // General info mGroupNameEditor = getChild("group_name_editor", recurse); - mGroupName = getChild("group_name", recurse); - + mInsignia = getChild("insignia", recurse); if (mInsignia) { mInsignia->setCommitCallback(boost::bind(&LLPanelGroupGeneral::onCommitAny,this)); mDefaultIconID = mInsignia->getImageAssetID(); + void show_picture(const LLUUID& id, const std::string& name); + auto show_pic = [this] { show_picture(mInsignia->getImageAssetID(), "Group Insignia"); }; + auto show_pic_if_not_self = [=] { if (!mInsignia->canChange()) show_pic(); }; + mInsignia->setMouseUpCallback(std::bind(show_pic_if_not_self)); + getChild("bigimg")->setCommitCallback(std::bind(show_pic)); } mEditCharter = getChild("charter", recurse); @@ -145,10 +156,6 @@ BOOL LLPanelGroupGeneral::postBuild() mFounderName = getChild("founder_name"); mListVisibleMembers = getChild("visible_members", recurse); - if (mListVisibleMembers) - { - mListVisibleMembers->setDoubleClickCallback(boost::bind(LLAvatarActions::showProfile, boost::bind(&LLScrollListCtrl::getCurrentID, mListVisibleMembers), false)); - } // Options mCtrlShowInGroupList = getChild("show_in_group_list", recurse); @@ -175,10 +182,11 @@ BOOL LLPanelGroupGeneral::postBuild() mCtrlOpenEnrollment->setCommitCallback(boost::bind(&LLPanelGroupGeneral::onCommitAny,this)); } + auto& grid = *gHippoGridManager->getConnectedGrid(); mCtrlEnrollmentFee = getChild("check_enrollment_fee", recurse); if (mCtrlEnrollmentFee) { - mCtrlEnrollmentFee->setLabelArg("[CURRENCY]", gHippoGridManager->getConnectedGrid()->getCurrencySymbol()); + mCtrlEnrollmentFee->setLabelArg("[CURRENCY]", grid.getCurrencySymbol()); mCtrlEnrollmentFee->setCommitCallback(boost::bind(&LLPanelGroupGeneral::onCommitEnrollment,this)); } @@ -235,7 +243,7 @@ BOOL LLPanelGroupGeneral::postBuild() } LLStringUtil::format_map_t args; - args["[GROUPCREATEFEE]"] = gHippoGridManager->getConnectedGrid()->getGroupCreationFee(); + args["[GROUPCREATEFEE]"] = grid.formatFee(LLAgentBenefitsMgr::current().getCreateGroupCost()); mIncompleteMemberDataStr = getString("incomplete_member_data_str"); mConfirmGroupCreateStr = getString("confirm_group_create_str", args); @@ -254,9 +262,14 @@ BOOL LLPanelGroupGeneral::postBuild() mBtnJoinGroup->setVisible(FALSE); mBtnInfo->setVisible(FALSE); - mGroupName->setVisible(FALSE); + getChildView("group_name")->setVisible(FALSE); } + std::string member_count(LLTrans::getString("LoadingData")); + if (LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID)) + member_count = fmt::to_string(gdatap->mMembers.size()); + getChild("text_owners_and_visible_members")->setTextArg("[COUNT]", member_count); + return LLPanelGroupTab::postBuild(); } @@ -359,7 +372,7 @@ bool LLPanelGroupGeneral::apply(std::string& mesg) if (has_power_in_group || mGroupID.isNull()) { - llinfos << "LLPanelGroupGeneral::apply" << llendl; + LL_INFOS() << "LLPanelGroupGeneral::apply" << LL_ENDL; // Check to make sure mature has been set if(mComboMature && @@ -717,15 +730,14 @@ void LLPanelGroupGeneral::update(LLGroupChange gc) if (mInsignia) mInsignia->setEnabled(can_change_ident); if (mEditCharter) mEditCharter->setEnabled(can_change_ident); - - if (mGroupName) mGroupName->setText(gdatap->mName); + + getChildView("group_name")->setValue(mGroupID); if (mGroupNameEditor) mGroupNameEditor->setVisible(FALSE); - if (mFounderName) mFounderName->setNameID(gdatap->mFounderID,FALSE); + if (mFounderName) mFounderName->setValue(gdatap->mFounderID); - LLNameEditor* key_edit = getChild("group_key"); - if(key_edit) + if (auto key_edit = getChildView("group_key")) { - key_edit->setText(gdatap->getID().asString()); + key_edit->setValue(gdatap->getID().asString()); } if (mInsignia) @@ -742,7 +754,7 @@ void LLPanelGroupGeneral::update(LLGroupChange gc) if (mEditCharter) { - mEditCharter->setText(gdatap->mCharter); + mEditCharter->setText(gdatap->mCharter, false); mEditCharter->resetDirty(); } } @@ -810,15 +822,24 @@ void LLPanelGroupGeneral::updateMembers() else { // If name is not cached, onNameCache() should be called when it is cached and add this member to list. - LLAvatarNameCache::get(mMemberProgress->first, - boost::bind(&LLPanelGroupGeneral::onNameCache, - this, gdatap->getMemberVersion(), member, _2)); + avatar_name_cache_connection_map_t::iterator it = mAvatarNameCacheConnections.find(mMemberProgress->first); + if (it != mAvatarNameCacheConnections.end()) + { + if (it->second.connected()) + { + it->second.disconnect(); + } + mAvatarNameCacheConnections.erase(it); + } + mAvatarNameCacheConnections[mMemberProgress->first] = LLAvatarNameCache::get(mMemberProgress->first, boost::bind(&LLPanelGroupGeneral::onNameCache, this, gdatap->getMemberVersion(), member, _2, _1)); } } + getChild("text_owners_and_visible_members")->setTextArg("[COUNT]", fmt::to_string(gdatap->mMembers.size())); + if (mMemberProgress == gdatap->mMembers.end()) { - lldebugs << " member list completed." << llendl; + LL_DEBUGS() << " member list completed." << LL_ENDL; mListVisibleMembers->setEnabled(TRUE); } else @@ -828,6 +849,8 @@ void LLPanelGroupGeneral::updateMembers() } } +bool is_online_status_string(const std::string& status); + void LLPanelGroupGeneral::addMember(LLGroupMemberData* member) { // Owners show up in bold. @@ -844,13 +867,26 @@ void LLPanelGroupGeneral::addMember(LLGroupMemberData* member) item_params.columns.add().column("title").value(member->getTitle()).font/*.name*/("SANSSERIF_SMALL").font_style(style); - item_params.columns.add().column("online").value(member->getOnlineStatus()).font/*.name*/("SANSSERIF_SMALL").font_style(style); + static const LLCachedControl format(gSavedSettings, "ShortDateFormat"); + item_params.columns.add().column("online").value(member->getOnlineStatus()) + .format(format).type(is_online_status_string(member->getOnlineStatus()) ? "text" : "date") + .font/*.name*/("SANSSERIF_SMALL").font_style(style); /*LLScrollListItem* member_row =*/ mListVisibleMembers->addNameItemRow(item_params); } -void LLPanelGroupGeneral::onNameCache(const LLUUID& update_id, LLGroupMemberData* member, const LLAvatarName& av_name) +void LLPanelGroupGeneral::onNameCache(const LLUUID& update_id, LLGroupMemberData* member, const LLAvatarName& av_name, const LLUUID& av_id) { + avatar_name_cache_connection_map_t::iterator it = mAvatarNameCacheConnections.find(av_id); + if (it != mAvatarNameCacheConnections.end()) + { + if (it->second.connected()) + { + it->second.disconnect(); + } + mAvatarNameCacheConnections.erase(it); + } + LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID); if (!gdatap @@ -870,7 +906,6 @@ void LLPanelGroupGeneral::updateChanged() LLUICtrl *check_list[] = { mGroupNameEditor, - mGroupName, mFounderName, mInsignia, mEditCharter, diff --git a/indra/newview/llpanelgroupgeneral.h b/indra/newview/llpanelgroupgeneral.h index 84058ac847..aa54e83b74 100644 --- a/indra/newview/llpanelgroupgeneral.h +++ b/indra/newview/llpanelgroupgeneral.h @@ -68,7 +68,7 @@ class LLPanelGroupGeneral : public LLPanelGroupTab virtual void draw(); - void onNameCache(const LLUUID& update_id, LLGroupMemberData* member, const LLAvatarName& av_name); + void onNameCache(const LLUUID& update_id, LLGroupMemberData* member, const LLAvatarName& av_name, const LLUUID& av_id); private: void onFocusEdit(); void onCommitAny(); @@ -91,7 +91,6 @@ class LLPanelGroupGeneral : public LLPanelGroupTab // Group information (include any updates in updateChanged) LLLineEditor *mGroupNameEditor; - LLTextBox *mGroupName; LLNameBox *mFounderName; LLTextureCtrl *mInsignia; LLTextEditor *mEditCharter; @@ -113,6 +112,8 @@ class LLPanelGroupGeneral : public LLPanelGroupTab LLComboBox *mComboMature; LLGroupMgrGroupData::member_list_t::iterator mMemberProgress; + typedef std::map avatar_name_cache_connection_map_t; + avatar_name_cache_connection_map_t mAvatarNameCacheConnections; }; #endif diff --git a/indra/newview/llpanelgroupinvite.cpp b/indra/newview/llpanelgroupinvite.cpp index f16d4985ca..f84c6c7259 100644 --- a/indra/newview/llpanelgroupinvite.cpp +++ b/indra/newview/llpanelgroupinvite.cpp @@ -51,6 +51,8 @@ #include "lluictrlfactory.h" #include "llviewerwindow.h" +#include + class LLPanelGroupInvite::impl : public boost::signals2::trackable { public: @@ -69,7 +71,7 @@ class LLPanelGroupInvite::impl : public boost::signals2::trackable static void callbackClickAdd(void* userdata); static void callbackClickRemove(void* userdata); static void callbackSelect(LLUICtrl* ctrl, void* userdata); - void callbackAddUsers(const uuid_vec_t& agent_idsa); + void callbackAddUsers(const uuid_vec_t& agent_ids); void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name); @@ -93,6 +95,8 @@ class LLPanelGroupInvite::impl : public boost::signals2::trackable void (*mCloseCallback)(void* data); void* mCloseCallbackUserData; + + std::map mAvatarNameCacheConnection; }; @@ -106,14 +110,20 @@ LLPanelGroupInvite::impl::impl(const LLUUID& group_id): mGroupName( NULL ), mConfirmedOwnerInvite( false ), mCloseCallback( NULL ), - mCloseCallbackUserData( NULL ) + mCloseCallbackUserData( NULL ), + mAvatarNameCacheConnection() { } LLPanelGroupInvite::impl::~impl() { + for (std::map::const_iterator it = mAvatarNameCacheConnection.begin(); it != mAvatarNameCacheConnection.end(); ++it) + if ((*it).second.connected()) + (*it).second.disconnect(); } +const S32 MAX_GROUP_INVITES = 100; // Max invites per request. 100 to match server cap. + void LLPanelGroupInvite::impl::addUsers(const std::vector& names, const uuid_vec_t& agent_ids) { @@ -191,7 +201,6 @@ void LLPanelGroupInvite::impl::submitInvitations() role_member_pairs[item->getUUID()] = role_id; } - const S32 MAX_GROUP_INVITES = 100; // Max invites per request. 100 to match server cap. if (role_member_pairs.size() > MAX_GROUP_INVITES) { // Fail! @@ -258,7 +267,7 @@ void LLPanelGroupInvite::impl::addRoleNames(LLGroupMgrGroupData* gdatap) //else if they have the limited add to roles power //we add every role the user is in //else we just add to everyone - bool is_owner = member_data->isInRole(gdatap->mOwnerRole); + bool is_owner = member_data->isOwner(); bool can_assign_any = gAgent.hasPowerInGroup(mGroupID, GP_ROLE_ASSIGN_MEMBER); bool can_assign_limited = gAgent.hasPowerInGroup(mGroupID, @@ -381,7 +390,12 @@ void LLPanelGroupInvite::impl::callbackAddUsers(const uuid_vec_t& agent_ids) std::vector names; for (S32 i = 0; i < (S32)agent_ids.size(); i++) { - LLAvatarNameCache::get(agent_ids[i], + const LLUUID& id(agent_ids[i]); + if (mAvatarNameCacheConnection[id].connected()) + { + mAvatarNameCacheConnection[id].disconnect(); + } + mAvatarNameCacheConnection[id] = LLAvatarNameCache::get(id, boost::bind(&LLPanelGroupInvite::impl::onAvatarNameCache, this, _1, _2)); } } @@ -389,6 +403,10 @@ void LLPanelGroupInvite::impl::callbackAddUsers(const uuid_vec_t& agent_ids) void LLPanelGroupInvite::impl::onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name) { + if (mAvatarNameCacheConnection[agent_id].connected()) + { + mAvatarNameCacheConnection[agent_id].disconnect(); + } std::vector names; uuid_vec_t agent_ids; agent_ids.push_back(agent_id); @@ -452,7 +470,7 @@ void LLPanelGroupInvite::addUsers(uuid_vec_t& agent_ids) } else { - llwarns << "llPanelGroupInvite: Selected avatar has no name: " << dest->getID() << llendl; + LL_WARNS() << "llPanelGroupInvite: Selected avatar has no name: " << dest->getID() << LL_ENDL; names.push_back("(Unknown)"); } } @@ -461,7 +479,7 @@ void LLPanelGroupInvite::addUsers(uuid_vec_t& agent_ids) //looks like user try to invite offline friend //for offline avatar_id gObjectList.findObject() will return null //so we need to do this additional search in avatar tracker, see EXT-4732 - if (LLAvatarTracker::instance().isBuddy(agent_id)) + //if (LLAvatarTracker::instance().isBuddy(agent_id)) // Singu Note: We may be using this from another avatar list like group profile, disregard friendship status. { LLAvatarName av_name; if (!LLAvatarNameCache::get(agent_id, &av_name)) @@ -476,7 +494,7 @@ void LLPanelGroupInvite::addUsers(uuid_vec_t& agent_ids) } else { - names.push_back(av_name.getLegacyName()); + names.push_back(av_name.getNSName()); } } } @@ -489,7 +507,7 @@ void LLPanelGroupInvite::addUserCallback(const LLUUID& id, const LLAvatarName& a std::vector names; uuid_vec_t agent_ids; agent_ids.push_back(id); - names.push_back(av_name.getLegacyName()); + names.push_back(av_name.getNSName()); mImplementation->addUsers(names, agent_ids); } @@ -540,7 +558,7 @@ void LLPanelGroupInvite::updateLists() { waiting = true; } - if (gdatap->isRoleDataComplete() && gdatap->isMemberDataComplete()) + if (gdatap->isRoleDataComplete() && gdatap->isMemberDataComplete() && gdatap->isRoleMemberDataComplete()) { if ( mImplementation->mRoleNames ) { @@ -568,6 +586,7 @@ void LLPanelGroupInvite::updateLists() { LLGroupMgr::getInstance()->sendGroupPropertiesRequest(mImplementation->mGroupID); LLGroupMgr::getInstance()->sendGroupRoleDataRequest(mImplementation->mGroupID); + LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(mImplementation->mGroupID); LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mImplementation->mGroupID); } mPendingUpdate = TRUE; @@ -615,7 +634,7 @@ BOOL LLPanelGroupInvite::postBuild() } mImplementation->mOKButton = - getChild("ok_button", recurse); + getChild("invite_button", recurse); if ( mImplementation->mOKButton ) { mImplementation->mOKButton->setClickedCallback(impl::callbackClickOK, mImplementation); diff --git a/indra/newview/llpanelgrouplandmoney.cpp b/indra/newview/llpanelgrouplandmoney.cpp index dec32551ab..ac779221be 100644 --- a/indra/newview/llpanelgrouplandmoney.cpp +++ b/indra/newview/llpanelgrouplandmoney.cpp @@ -195,7 +195,7 @@ class LLPanelGroupLandMoney::impl void requestGroupLandInfo(); - int getStoredContribution(); + S32 getStoredContribution(); void setYourContributionTextField(int contrib); void setYourMaxContributionTextBox(int max); @@ -322,7 +322,7 @@ bool LLPanelGroupLandMoney::impl::applyContribution() if(!gAgent.setGroupContribution(mPanel.mGroupID, new_contribution)) { // should never happen... - llwarns << "Unable to set contribution." << llendl; + LL_WARNS() << "Unable to set contribution." << LL_ENDL; return false; } } @@ -341,20 +341,20 @@ bool LLPanelGroupLandMoney::impl::applyContribution() // Retrieves the land contribution for this agent that is currently // stored in the database, NOT what is currently entered in the text field -int LLPanelGroupLandMoney::impl::getStoredContribution() +S32 LLPanelGroupLandMoney::impl::getStoredContribution() { LLGroupData group_data; group_data.mContribution = 0; - gAgent.getGroupData(mPanel.mGroupID, group_data); + bool found_group = gAgent.getGroupData(mPanel.mGroupID, group_data); - return group_data.mContribution; + return found_group ? group_data.mContribution : 0; } // Fills in the text field with the contribution, contrib void LLPanelGroupLandMoney::impl::setYourContributionTextField(int contrib) { - std::string buffer = llformat("%d", contrib); + std::string buffer = fmt::to_string(contrib); if ( mYourContributionEditorp ) { @@ -364,7 +364,7 @@ void LLPanelGroupLandMoney::impl::setYourContributionTextField(int contrib) void LLPanelGroupLandMoney::impl::setYourMaxContributionTextBox(int max) { - mPanel.getChild("your_contribution_max_value")->setTextArg("[AMOUNT]", llformat("%d", max)); + mPanel.getChild("your_contribution_max_value")->setTextArg("[AMOUNT]", fmt::to_string(max)); } //static @@ -414,18 +414,32 @@ void LLPanelGroupLandMoney::impl::processGroupLand(LLMessageSystem* msg) { // special block which has total contribution ++first_block; - + + S32 committed = 0; + S32 billable_area = 0; + + if(count == 1) + { + msg->getS32("QueryData", "BillableArea", committed, 0); + } + else + { + for(S32 i = first_block; i < count; ++i) + { + msg->getS32("QueryData", "BillableArea", billable_area, i); + committed+=billable_area; + } + } + S32 total_contribution; msg->getS32("QueryData", "ActualArea", total_contribution, 0); mPanel.getChild("total_contributed_land_value")->setTextArg("[AREA]", llformat("%d", total_contribution)); - S32 committed; - msg->getS32("QueryData", "BillableArea", committed, 0); mPanel.getChild("total_land_in_use_value")->setTextArg("[AREA]", llformat("%d", committed)); - S32 available = total_contribution - committed; mPanel.getChild("land_available_value")->setTextArg("[AREA]", llformat("%d", available)); + if ( mGroupOverLimitTextp && mGroupOverLimitIconp ) { mGroupOverLimitIconp->setVisible(available < 0); @@ -434,9 +448,11 @@ void LLPanelGroupLandMoney::impl::processGroupLand(LLMessageSystem* msg) } if ( trans_id != mTransID ) return; + // This power was removed to make group roles simpler //if ( !gAgent.hasPowerInGroup(mGroupID, GP_LAND_VIEW_OWNED) ) return; if (!gAgent.isInGroup(mPanel.mGroupID)) return; + mGroupParcelsp->setCommentText(mEmptyParcelsText); std::string name; @@ -449,7 +465,7 @@ void LLPanelGroupLandMoney::impl::processGroupLand(LLMessageSystem* msg) std::string sim_name; std::string land_sku; std::string land_type; - + for(S32 i = first_block; i < count; ++i) { msg->getUUID("QueryData", "OwnerID", owner_id, i); @@ -465,7 +481,7 @@ void LLPanelGroupLandMoney::impl::processGroupLand(LLMessageSystem* msg) if ( msg->getSizeFast(_PREHASH_QueryData, i, _PREHASH_ProductSKU) > 0 ) { msg->getStringFast( _PREHASH_QueryData, _PREHASH_ProductSKU, land_sku, i); - llinfos << "Land sku: " << land_sku << llendl; + LL_INFOS() << "Land sku: " << land_sku << LL_ENDL; land_type = LLProductInfoRequestManager::instance().getDescriptionForSku(land_sku); } else @@ -474,10 +490,12 @@ void LLPanelGroupLandMoney::impl::processGroupLand(LLMessageSystem* msg) land_type = LLTrans::getString("land_type_unknown"); } - S32 region_x = llround(global_x) % REGION_WIDTH_UNITS; - S32 region_y = llround(global_y) % REGION_WIDTH_UNITS; + S32 region_x = ll_round(global_x) % REGION_WIDTH_UNITS; + S32 region_y = ll_round(global_y) % REGION_WIDTH_UNITS; std::string location = sim_name + llformat(" (%d, %d)", region_x, region_y); std::string area; + + if(billable_area == actual_area) { area = llformat("%d", billable_area); @@ -827,10 +845,10 @@ void LLPanelGroupLandMoney::processPlacesReply(LLMessageSystem* msg, void**) LLPanelGroupLandMoney* selfp = sGroupIDs.getIfThere(group_id); if(!selfp) { - llinfos << "Group Panel Land " + LL_INFOS() << "Group Panel Land " << gHippoGridManager->getConnectedGrid()->getCurrencySymbol() << ' ' << group_id << " no longer in existence." - << llendl; + << LL_ENDL; return; } @@ -1055,7 +1073,7 @@ void LLGroupMoneyDetailsTabEventHandler::processReply(LLMessageSystem* msg, msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_GroupID, group_id ); if (mImplementationp->getGroupID() != group_id) { - llwarns << "Group Account details not for this group!" << llendl; + LL_WARNS() << "Group Account details not for this group!" << LL_ENDL; return; } @@ -1070,8 +1088,8 @@ void LLGroupMoneyDetailsTabEventHandler::processReply(LLMessageSystem* msg, if ( interval_days != mImplementationp->mIntervalLength || current_interval != mImplementationp->mCurrentInterval ) { - llinfos << "Out of date details packet " << interval_days << " " - << current_interval << llendl; + LL_INFOS() << "Out of date details packet " << interval_days << " " + << current_interval << LL_ENDL; return; } @@ -1118,9 +1136,9 @@ void LLPanelGroupLandMoney::processGroupAccountDetailsReply(LLMessageSystem* msg msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id ); if (gAgent.getID() != agent_id) { - llwarns << "Got group " + LL_WARNS() << "Got group " << gHippoGridManager->getConnectedGrid()->getCurrencySymbol() - << " history reply for another agent!" << llendl; + << " history reply for another agent!" << LL_ENDL; return; } @@ -1129,7 +1147,7 @@ void LLPanelGroupLandMoney::processGroupAccountDetailsReply(LLMessageSystem* msg LLGroupMoneyTabEventHandler* selfp = LLGroupMoneyTabEventHandler::sInstanceIDs.getIfThere(request_id); if (!selfp) { - llwarns << "GroupAccountDetails recieved for non-existent group panel." << llendl; + LL_WARNS() << "GroupAccountDetails recieved for non-existent group panel." << LL_ENDL; return; } @@ -1192,7 +1210,7 @@ void LLGroupMoneySalesTabEventHandler::processReply(LLMessageSystem* msg, msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_GroupID, group_id ); if (mImplementationp->getGroupID() != group_id) { - llwarns << "Group Account Transactions not for this group!" << llendl; + LL_WARNS() << "Group Account Transactions not for this group!" << LL_ENDL; return; } @@ -1209,8 +1227,8 @@ void LLGroupMoneySalesTabEventHandler::processReply(LLMessageSystem* msg, if (interval_days != mImplementationp->mIntervalLength || current_interval != mImplementationp->mCurrentInterval) { - llinfos << "Out of date details packet " << interval_days << " " - << current_interval << llendl; + LL_INFOS() << "Out of date details packet " << interval_days << " " + << current_interval << LL_ENDL; return; } @@ -1291,9 +1309,9 @@ void LLPanelGroupLandMoney::processGroupAccountTransactionsReply(LLMessageSystem msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id ); if (gAgent.getID() != agent_id) { - llwarns << "Got group " + LL_WARNS() << "Got group " << gHippoGridManager->getConnectedGrid()->getCurrencySymbol() - << " history reply for another agent!" << llendl; + << " history reply for another agent!" << LL_ENDL; return; } @@ -1305,7 +1323,7 @@ void LLPanelGroupLandMoney::processGroupAccountTransactionsReply(LLMessageSystem self = LLGroupMoneyTabEventHandler::sInstanceIDs.getIfThere(request_id); if (!self) { - llwarns << "GroupAccountTransactions recieved for non-existent group panel." << llendl; + LL_WARNS() << "GroupAccountTransactions recieved for non-existent group panel." << LL_ENDL; return; } @@ -1366,7 +1384,7 @@ void LLGroupMoneyPlanningTabEventHandler::processReply(LLMessageSystem* msg, msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_GroupID, group_id ); if (mImplementationp->getGroupID() != group_id) { - llwarns << "Group Account Summary received not for this group!" << llendl; + LL_WARNS() << "Group Account Summary received not for this group!" << LL_ENDL; return; } @@ -1416,8 +1434,8 @@ void LLGroupMoneyPlanningTabEventHandler::processReply(LLMessageSystem* msg, if (interval_days != mImplementationp->mIntervalLength || current_interval != mImplementationp->mCurrentInterval) { - llinfos << "Out of date summary packet " << interval_days << " " - << current_interval << llendl; + LL_INFOS() << "Out of date summary packet " << interval_days << " " + << current_interval << LL_ENDL; return; } @@ -1464,9 +1482,9 @@ void LLPanelGroupLandMoney::processGroupAccountSummaryReply(LLMessageSystem* msg msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id ); if (gAgent.getID() != agent_id) { - llwarns << "Got group " + LL_WARNS() << "Got group " << gHippoGridManager->getConnectedGrid()->getCurrencySymbol() - << " history reply for another agent!" << llendl; + << " history reply for another agent!" << LL_ENDL; return; } @@ -1478,9 +1496,9 @@ void LLPanelGroupLandMoney::processGroupAccountSummaryReply(LLMessageSystem* msg self = LLGroupMoneyTabEventHandler::sInstanceIDs.getIfThere(request_id); if (!self) { - llwarns << "GroupAccountSummary recieved for non-existent group " + LL_WARNS() << "GroupAccountSummary recieved for non-existent group " << gHippoGridManager->getConnectedGrid()->getCurrencySymbol() - << " planning tab." << llendl; + << " planning tab." << LL_ENDL; return; } diff --git a/indra/newview/llpanelgroupnotices.cpp b/indra/newview/llpanelgroupnotices.cpp index 001a1179a4..862a89dd4c 100644 --- a/indra/newview/llpanelgroupnotices.cpp +++ b/indra/newview/llpanelgroupnotices.cpp @@ -53,6 +53,7 @@ #include "llscrolllistctrl.h" #include "llscrolllistitem.h" #include "lltextbox.h" +#include "lltrans.h" #include "roles_constants.h" #include "llviewerwindow.h" @@ -70,7 +71,14 @@ const S32 NOTICE_DATE_STRING_SIZE = 30; class LLGroupDropTarget : public LLDropTarget { public: - LLGroupDropTarget(const LLDropTarget::Params& p = LLDropTarget::Params()); + struct Params : public LLInitParam::Block + { + Params() + { + changeDefault(show_reset, false); // We have a button for this + } + }; + LLGroupDropTarget(const Params& p = Params()); ~LLGroupDropTarget() {}; // @@ -91,21 +99,21 @@ class LLGroupDropTarget : public LLDropTarget LLPanelGroupNotices* mGroupNoticesPanel; }; -LLGroupDropTarget::LLGroupDropTarget(const LLDropTarget::Params& p) +LLGroupDropTarget::LLGroupDropTarget(const LLGroupDropTarget::Params& p) : LLDropTarget(p) {} // static LLView* LLGroupDropTarget::fromXML(LLXMLNodePtr node, LLView* parent, LLUICtrlFactory* factory) { - LLGroupDropTarget* target = new LLGroupDropTarget(); + LLGroupDropTarget* target = new LLGroupDropTarget; target->initFromXML(node, parent); return target; } void LLGroupDropTarget::doDrop(EDragAndDropType cargo_type, void* cargo_data) { - llinfos << "LLGroupDropTarget::doDrop()" << llendl; + LL_INFOS() << "LLGroupDropTarget::doDrop()" << LL_ENDL; } BOOL LLGroupDropTarget::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, @@ -116,7 +124,7 @@ BOOL LLGroupDropTarget::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, { BOOL handled = FALSE; - if (!gAgent.hasPowerInGroup(mEntityID,GP_NOTICES_SEND)) + if (!gAgent.hasPowerInGroup(mID,GP_NOTICES_SEND)) { *accept = ACCEPT_NO; return TRUE; @@ -310,7 +318,7 @@ void LLPanelGroupNotices::setItem(LLPointer inv_item) inv_item->getFlags(), item_is_multi ); - mCreateInventoryIcon->setImage(icon_name); + mCreateInventoryIcon->setValue(icon_name); mCreateInventoryIcon->setVisible(TRUE); std::stringstream ss; @@ -385,7 +393,7 @@ void LLPanelGroupNotices::onClickNewMessage(void* data) void LLPanelGroupNotices::onClickRefreshNotices(void* data) { - lldebugs << "LLPanelGroupNotices::onClickGetPastNotices" << llendl; + LL_DEBUGS() << "LLPanelGroupNotices::onClickGetPastNotices" << LL_ENDL; LLPanelGroupNotices* self = (LLPanelGroupNotices*)data; self->mNoticesList->deleteAllItems(); @@ -412,16 +420,16 @@ void LLPanelGroupNotices::processGroupNoticesListReply(LLMessageSystem* msg, voi std::map::iterator it = sInstances.find(group_id); if (it == sInstances.end()) { - llinfos << "Group Panel Notices " << group_id << " no longer in existence." - << llendl; + LL_INFOS() << "Group Panel Notices " << group_id << " no longer in existence." + << LL_ENDL; return; } LLPanelGroupNotices* selfp = it->second; if(!selfp) { - llinfos << "Group Panel Notices " << group_id << " no longer in existence." - << llendl; + LL_INFOS() << "Group Panel Notices " << group_id << " no longer in existence." + << LL_ENDL; return; } @@ -455,7 +463,6 @@ void LLPanelGroupNotices::processNotices(LLMessageSystem* msg) msg->getBOOL("Data","HasAttachment",has_attachment,i); msg->getU8("Data","AssetType",asset_type,i); msg->getU32("Data","Timestamp",timestamp,i); - time_t t = timestamp; LLSD row; row["id"] = id; @@ -480,9 +487,10 @@ void LLPanelGroupNotices::processNotices(LLMessageSystem* msg) std::string format(gSavedSettings.getString("ShortDateFormat")); if (gSavedSettings.getBOOL("LiruGroupNoticeTimes")) format += " " + gSavedSettings.getString("ShortTimeFormat"); - timeToFormattedString(t, format, buffer); + row["columns"][3]["type"] = "date"; + row["columns"][3]["format"] = format; row["columns"][3]["column"] = "date"; - row["columns"][3]["value"] = buffer; + row["columns"][3]["value"] = LLDate(timestamp); buffer = llformat( "%u", timestamp); row["columns"][4]["column"] = "sort"; @@ -508,9 +516,10 @@ void LLPanelGroupNotices::onSelectNotice() msg->addUUID("GroupNoticeID",item->getUUID()); gAgent.sendReliableMessage(); - lldebugs << "Item " << item->getUUID() << " selected." << llendl; + LL_DEBUGS() << "Item " << item->getUUID() << " selected." << LL_ENDL; } +bool is_openable(LLAssetType::EType type); void LLPanelGroupNotices::showNotice(const std::string& subject, const std::string& message, const bool& has_inventory, @@ -520,12 +529,7 @@ void LLPanelGroupNotices::showNotice(const std::string& subject, arrangeNoticeView(VIEW_PAST_NOTICE); if(mViewSubject) mViewSubject->setText(subject); - if (mViewMessage) { - // We need to prune the highlights, and clear() is not doing it... - mViewMessage->removeTextFromEnd(mViewMessage->getMaxLength()); - // Now we append the new text (setText() won't highlight URLs) - mViewMessage->appendColoredText(message, false, false, mViewMessage->getReadOnlyFgColor()); - } + if (mViewMessage) mViewMessage->setText(message, false); if (mInventoryOffer) { @@ -541,7 +545,7 @@ void LLPanelGroupNotices::showNotice(const std::string& subject, std::string icon_name = LLInventoryIcon::getIconName(mInventoryOffer->mType, LLInventoryType::IT_TEXTURE); - mViewInventoryIcon->setImage(icon_name); + mViewInventoryIcon->setValue(icon_name); mViewInventoryIcon->setVisible(TRUE); std::stringstream ss; @@ -549,6 +553,7 @@ void LLPanelGroupNotices::showNotice(const std::string& subject, mViewInventoryName->setText(ss.str()); mBtnOpenAttachment->setEnabled(TRUE); + mBtnOpenAttachment->setLabel(LLTrans::getString(is_openable(inventory_offer->mType) ? "GroupNotifyOpenAttachment" : "GroupNotifySaveAttachment")); } else { diff --git a/indra/newview/llpanelgrouproles.cpp b/indra/newview/llpanelgrouproles.cpp index 2a540e1c14..38fef06e43 100644 --- a/indra/newview/llpanelgrouproles.cpp +++ b/indra/newview/llpanelgrouproles.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llpanelgrouproles.cpp * @brief Panel for roles information about a particular group. * @@ -34,10 +34,10 @@ #include "llcheckboxctrl.h" #include "llagent.h" -#include "llavataractions.h" #include "llavatarnamecache.h" #include "llbutton.h" #include "llfiltereditor.h" +#include "llfloatergroupbulkban.h" #include "llfloatergroupinvite.h" #include "lliconctrl.h" #include "lllineeditor.h" @@ -71,8 +71,8 @@ bool agentCanAddToRole(const LLUUID& group_id, LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(group_id); if (!gdatap) { - llwarns << "agentCanAddToRole " - << "-- No group data!" << llendl; + LL_WARNS() << "agentCanAddToRole " + << "-- No group data!" << LL_ENDL; return false; } @@ -108,6 +108,9 @@ bool agentCanAddToRole(const LLUUID& group_id, return false; } + +// LLPanelGroupRoles ///////////////////////////////////////////////////// + // static void* LLPanelGroupRoles::createTab(void* data) { @@ -136,7 +139,7 @@ LLPanelGroupRoles::~LLPanelGroupRoles() BOOL LLPanelGroupRoles::postBuild() { - lldebugs << "LLPanelGroupRoles::postBuild()" << llendl; + LL_DEBUGS() << "LLPanelGroupRoles::postBuild()" << LL_ENDL; mSubTabContainer = getChild("roles_tab_container"); @@ -149,7 +152,7 @@ BOOL LLPanelGroupRoles::postBuild() LLPanelGroupSubTab* subtabp = dynamic_cast(panel); if (!subtabp) { - llwarns << "Invalid subtab panel: " << panel->getName() << llendl; + LL_WARNS() << "Invalid subtab panel: " << panel->getName() << LL_ENDL; return FALSE; } @@ -307,7 +310,6 @@ bool LLPanelGroupRoles::onModalClose(const LLSD& notification, const LLSD& respo return false; } - bool LLPanelGroupRoles::apply(std::string& mesg) { // Pass this along to the currently visible sub tab. @@ -365,7 +367,7 @@ void LLPanelGroupRoles::update(LLGroupChange gc) } else { - llwarns << "LLPanelGroupRoles::update() -- No subtab to update!" << llendl; + LL_WARNS() << "LLPanelGroupRoles::update() -- No subtab to update!" << LL_ENDL; } } @@ -373,39 +375,33 @@ void LLPanelGroupRoles::activate() { // Start requesting member and role data if needed. LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID); - //if (!gdatap || mFirstUse) + if (!gdatap || !gdatap->isMemberDataComplete()) { - // Check member data. - - if (!gdatap || !gdatap->isMemberDataComplete() ) - { - LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mGroupID); - } - - // Check role data. - if (!gdatap || !gdatap->isRoleDataComplete() ) - { - // Mildly hackish - clear all pending changes - cancel(); + LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mGroupID); + } - LLGroupMgr::getInstance()->sendGroupRoleDataRequest(mGroupID); - } + if (!gdatap || !gdatap->isRoleDataComplete() ) + { + // Mildly hackish - clear all pending changes + cancel(); - // Check role-member mapping data. - if (!gdatap || !gdatap->isRoleMemberDataComplete() ) - { - LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(mGroupID); - } + LLGroupMgr::getInstance()->sendGroupRoleDataRequest(mGroupID); + } - // Need this to get base group member powers - if (!gdatap || !gdatap->isGroupPropertiesDataComplete() ) - { - LLGroupMgr::getInstance()->sendGroupPropertiesRequest(mGroupID); - } + // Check role-member mapping data. + if (!gdatap || !gdatap->isRoleMemberDataComplete() ) + { + LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(mGroupID); + } - mFirstUse = FALSE; + // Need this to get base group member powers + if (!gdatap || !gdatap->isGroupPropertiesDataComplete() ) + { + LLGroupMgr::getInstance()->sendGroupPropertiesRequest(mGroupID); } + mFirstUse = FALSE; + LLPanelGroupTab* panelp = (LLPanelGroupTab*) mSubTabContainer->getCurrentPanel(); if (panelp) panelp->activate(); } @@ -440,14 +436,38 @@ void LLPanelGroupRoles::tabChanged() notifyObservers(); } -//////////////////////////// -// LLPanelGroupSubTab -//////////////////////////// +void LLPanelGroupRoles::setGroupID(const LLUUID& id) +{ + LLPanelGroupTab::setGroupID(id); + + LLPanelGroupMembersSubTab* group_members_tab = findChild("members_sub_tab"); + LLPanelGroupRolesSubTab* group_roles_tab = findChild("roles_sub_tab"); + LLPanelGroupActionsSubTab* group_actions_tab = findChild("actions_sub_tab"); + LLPanelGroupBanListSubTab* group_ban_tab = findChild("banlist_sub_tab"); + + if (group_members_tab) group_members_tab->setGroupID(id); + if (group_roles_tab) group_roles_tab->setGroupID(id); + if (group_actions_tab) group_actions_tab->setGroupID(id); + if (group_ban_tab) group_ban_tab->setGroupID(id); + + LLButton* button = getChild("member_invite"); + if (button) + button->setEnabled(gAgent.hasPowerInGroup(mGroupID, GP_MEMBER_INVITE)); + + if (mSubTabContainer) + mSubTabContainer->selectTab(1); + group_roles_tab->mFirstOpen = TRUE; + activate(); +} + + +// LLPanelGroupSubTab //////////////////////////////////////////////////// LLPanelGroupSubTab::LLPanelGroupSubTab(const std::string& name, const LLUUID& group_id) : LLPanelGroupTab(name, group_id), mHeader(NULL), mFooter(NULL), mActivated(false), + mHasGroupBanPower(false), mSearchEditor(NULL) { } @@ -492,6 +512,17 @@ BOOL LLPanelGroupSubTab::postBuild() return LLPanelGroupTab::postBuild(); } +void LLPanelGroupSubTab::setGroupID(const LLUUID& id) +{ + LLPanelGroupTab::setGroupID(id); + if(mSearchEditor) + { + mSearchEditor->clear(); + setSearchFilter(""); + } + + mActivated = false; +} void LLPanelGroupSubTab::setSearchFilter(const std::string& filter) { @@ -554,13 +585,14 @@ void LLPanelGroupSubTab::buildActionsList(LLScrollListCtrl* ctrl, { if (LLGroupMgr::getInstance()->mRoleActionSets.empty()) { - llwarns << "Can't build action list - no actions found." << llendl; + LL_WARNS() << "Can't build action list - no actions found." << LL_ENDL; return; } + mHasGroupBanPower = false; + std::vector::iterator ras_it = LLGroupMgr::getInstance()->mRoleActionSets.begin(); std::vector::iterator ras_end = LLGroupMgr::getInstance()->mRoleActionSets.end(); - for ( ; ras_it != ras_end; ++ras_it) { buildActionCategory(ctrl, @@ -583,7 +615,7 @@ void LLPanelGroupSubTab::buildActionCategory(LLScrollListCtrl* ctrl, BOOL filter, BOOL is_owner_role) { - lldebugs << "Building role list for: " << action_set->mActionSetData->mName << llendl; + LL_DEBUGS() << "Building role list for: " << action_set->mActionSetData->mName << LL_ENDL; // See if the allow mask matches anything in this category. if (show_all || (allowed_by_some & action_set->mActionSetData->mPowerBit)) { @@ -684,6 +716,33 @@ void LLPanelGroupSubTab::buildActionCategory(LLScrollListCtrl* ctrl, row["columns"][column_index]["value"] = (*ra_it)->mDescription; row["columns"][column_index]["font"] = "SANSSERIF_SMALL"; + if (mHasGroupBanPower) + { + // The ban ability is being set. Prevent these abilities from being manipulated + if ((*ra_it)->mPowerBit == GP_MEMBER_EJECT) + { + row["enabled"] = false; + } + else if ((*ra_it)->mPowerBit == GP_ROLE_REMOVE_MEMBER) + { + row["enabled"] = false; + } + } + else + { + /* Singu Note: enabled should not be set on here if it was turned off above for another reason... right? Oh well, we'll find out. + */ + // The ban ability is not set. Allow these abilities to be manipulated + if ((*ra_it)->mPowerBit == GP_MEMBER_EJECT) + { + row["enabled"] = true; + } + else if ((*ra_it)->mPowerBit == GP_ROLE_REMOVE_MEMBER) + { + row["enabled"] = true; + } + } + LLScrollListItem* item = ctrl->addElement(row, ADD_BOTTOM, (*ra_it)); if (-1 != check_box_index) @@ -719,6 +778,15 @@ void LLPanelGroupSubTab::buildActionCategory(LLScrollListCtrl* ctrl, check->setTentative(TRUE); } } + + // Regardless of whether or not this ability is allowed by all or some, we want to prevent + // the group managers from accidentally disabling either of the two additional abilities + // tied with GP_GROUP_BAN_ACCESS. + if ( (allowed_by_all & GP_GROUP_BAN_ACCESS) == GP_GROUP_BAN_ACCESS || + (allowed_by_some & GP_GROUP_BAN_ACCESS) == GP_GROUP_BAN_ACCESS) + { + mHasGroupBanPower = true; + } } } @@ -738,10 +806,7 @@ void LLPanelGroupSubTab::setFooterEnabled(BOOL enable) } } -//////////////////////////// -// LLPanelGroupMembersSubTab -//////////////////////////// - +// LLPanelGroupMembersSubTab ///////////////////////////////////////////// // static void* LLPanelGroupMembersSubTab::createTab(void* data) { @@ -763,6 +828,14 @@ LLPanelGroupMembersSubTab::LLPanelGroupMembersSubTab(const std::string& name, co LLPanelGroupMembersSubTab::~LLPanelGroupMembersSubTab() { + for (avatar_name_cache_connection_map_t::iterator it = mAvatarNameCacheConnections.begin(); it != mAvatarNameCacheConnections.end(); ++it) + { + if (it->second.connected()) + { + it->second.disconnect(); + } + } + mAvatarNameCacheConnections.clear(); } BOOL LLPanelGroupMembersSubTab::postBuildSubTab(LLView* root) @@ -786,8 +859,6 @@ BOOL LLPanelGroupMembersSubTab::postBuildSubTab(LLView* root) // We want to be notified whenever a member is selected. mMembersList->setCommitOnSelectionChange(TRUE); mMembersList->setCommitCallback(boost::bind(&LLPanelGroupMembersSubTab::onMemberSelect,_1,this)); - // Show the member's profile on double click. - mMembersList->setDoubleClickCallback(boost::bind(&LLPanelGroupMembersSubTab::onMemberDoubleClick,this)); LLButton* button = parent->getChild("member_invite", recurse); if ( button ) @@ -803,9 +874,27 @@ BOOL LLPanelGroupMembersSubTab::postBuildSubTab(LLView* root) mEjectBtn->setEnabled(FALSE); } + mBanBtn = parent->getChild("member_ban", recurse); + if (mBanBtn) + { + mBanBtn->setClickedCallback(boost::bind(&LLPanelGroupMembersSubTab::handleBanMember,this)); + mBanBtn->setEnabled(FALSE); + } + return TRUE; } +void LLPanelGroupMembersSubTab::setGroupID(const LLUUID& id) +{ + //clear members list + if(mMembersList) mMembersList->deleteAllItems(); + if(mAssignedRolesList) mAssignedRolesList->deleteAllItems(); + if(mAllowedActionsList) mAllowedActionsList->deleteAllItems(); + + LLPanelGroupSubTab::setGroupID(id); +} + + // static void LLPanelGroupMembersSubTab::onMemberSelect(LLUICtrl* ctrl, void* user_data) @@ -816,7 +905,7 @@ void LLPanelGroupMembersSubTab::onMemberSelect(LLUICtrl* ctrl, void* user_data) void LLPanelGroupMembersSubTab::handleMemberSelect() { - lldebugs << "LLPanelGroupMembersSubTab::handleMemberSelect" << llendl; + LL_DEBUGS() << "LLPanelGroupMembersSubTab::handleMemberSelect" << LL_ENDL; mAssignedRolesList->deleteAllItems(); mAllowedActionsList->deleteAllItems(); @@ -824,8 +913,8 @@ void LLPanelGroupMembersSubTab::handleMemberSelect() LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID); if (!gdatap) { - llwarns << "LLPanelGroupMembersSubTab::handleMemberSelect() " - << "-- No group data!" << llendl; + LL_WARNS() << "LLPanelGroupMembersSubTab::handleMemberSelect() " + << "-- No group data!" << LL_ENDL; return; } @@ -835,7 +924,7 @@ void LLPanelGroupMembersSubTab::handleMemberSelect() // Build a vector of all selected members, and gather allowed actions. uuid_vec_t selected_members; - U64 allowed_by_all = 0xffffffffffffLL; + U64 allowed_by_all = GP_ALL_POWERS; //0xffffffffffffLL; U64 allowed_by_some = 0; std::vector::iterator itor; @@ -872,8 +961,8 @@ void LLPanelGroupMembersSubTab::handleMemberSelect() LLGroupMgrGroupData::role_list_t::iterator iter = gdatap->mRoles.begin(); LLGroupMgrGroupData::role_list_t::iterator end = gdatap->mRoles.end(); - BOOL can_eject_members = gAgent.hasPowerInGroup(mGroupID, - GP_MEMBER_EJECT); + BOOL can_ban_members = gAgent.hasPowerInGroup(mGroupID, GP_GROUP_BAN_ACCESS); + BOOL can_eject_members = gAgent.hasPowerInGroup(mGroupID, GP_MEMBER_EJECT); BOOL member_is_owner = FALSE; for( ; iter != end; ++iter) @@ -920,6 +1009,7 @@ void LLPanelGroupMembersSubTab::handleMemberSelect() { // Can't remove other owners. cb_enable = FALSE; + can_ban_members = FALSE; break; } } @@ -997,13 +1087,16 @@ void LLPanelGroupMembersSubTab::handleMemberSelect() else { // This could happen if changes are not synced right on sub-panel change. - llwarns << "No group role data for " << iter->second << llendl; + LL_WARNS() << "No group role data for " << iter->second << LL_ENDL; } } mAssignedRolesList->setEnabled(TRUE); if (gAgent.isGodlike()) + { can_eject_members = TRUE; + can_ban_members = TRUE; + } if (!can_eject_members && !member_is_owner) { @@ -1016,18 +1109,42 @@ void LLPanelGroupMembersSubTab::handleMemberSelect() if ( member_data && member_data->isInRole(gdatap->mOwnerRole) ) { can_eject_members = TRUE; + can_ban_members = TRUE; } } + } - mEjectBtn->setEnabled(can_eject_members); -} + // ... or we can eject them because we have all the requisite powers... + if ( gAgent.hasPowerInGroup(mGroupID, GP_ROLE_REMOVE_MEMBER) && + !member_is_owner) + { + if (gAgent.hasPowerInGroup(mGroupID, GP_MEMBER_EJECT)) + { + can_eject_members = TRUE; + } -// static -void LLPanelGroupMembersSubTab::onMemberDoubleClick(void* user_data) -{ - LLPanelGroupMembersSubTab* self = static_cast(user_data); - self->handleMemberDoubleClick(); + if (gAgent.hasPowerInGroup(mGroupID, GP_GROUP_BAN_ACCESS)) + { + can_ban_members = TRUE; + } + } + + + uuid_vec_t::const_iterator member_iter = selected_members.begin(); + uuid_vec_t::const_iterator member_end = selected_members.end(); + for ( ; member_iter != member_end; ++member_iter) + { + // Don't count the agent. + if ((*member_iter) == gAgent.getID()) + { + can_eject_members = FALSE; + can_ban_members = FALSE; + } + } + + mBanBtn->setEnabled(can_ban_members); + mEjectBtn->setEnabled(can_eject_members); } //static @@ -1074,10 +1191,31 @@ void LLPanelGroupMembersSubTab::handleEjectMembers() mMembersList->deleteSelectedItems(); + sendEjectNotifications(mGroupID, selected_members); + LLGroupMgr::getInstance()->sendGroupMemberEjects(mGroupID, selected_members); } +void LLPanelGroupMembersSubTab::sendEjectNotifications(const LLUUID& group_id, const uuid_vec_t& selected_members) +{ + LLGroupMgrGroupData* group_data = LLGroupMgr::getInstance()->getGroupData(group_id); + + if (group_data) + { + for (uuid_vec_t::const_iterator i = selected_members.begin(); i != selected_members.end(); ++i) + { + LLSD args; + std::string av_name; + LLAvatarNameCache::getNSName(*i, av_name); + args["AVATAR_NAME"] = av_name; + args["GROUP_NAME"] = group_data->mName; + + LLNotifications::instance().add(LLNotification::Params("EjectAvatarFromGroup").substitutions(args)); + } + } +} + void LLPanelGroupMembersSubTab::handleRoleCheck(const LLUUID& role_id, LLRoleMemberChangeType type) { @@ -1086,12 +1224,11 @@ void LLPanelGroupMembersSubTab::handleRoleCheck(const LLUUID& role_id, //add that the user is requesting to change the roles for selected //members - U64 powers_all_have = 0xffffffffffffLL; + U64 powers_all_have = GP_ALL_POWERS; U64 powers_some_have = 0; BOOL is_owner_role = ( gdatap->mOwnerRole == role_id ); LLUUID member_id; - std::vector selection = mMembersList->getAllSelected(); if (selection.empty()) @@ -1102,7 +1239,6 @@ void LLPanelGroupMembersSubTab::handleRoleCheck(const LLUUID& role_id, for (std::vector::iterator itor = selection.begin() ; itor != selection.end(); ++itor) { - member_id = (*itor)->getUUID(); //see if we requested a change for this member before @@ -1168,7 +1304,6 @@ void LLPanelGroupMembersSubTab::handleRoleCheck(const LLUUID& role_id, FALSE); } - // static void LLPanelGroupMembersSubTab::onRoleCheck(LLUICtrl* ctrl, void* user_data) { @@ -1189,15 +1324,6 @@ void LLPanelGroupMembersSubTab::onRoleCheck(LLUICtrl* ctrl, void* user_data) } } -void LLPanelGroupMembersSubTab::handleMemberDoubleClick() -{ - LLScrollListItem* selected = mMembersList->getFirstSelected(); - if (selected) - { - LLAvatarActions::showProfile(selected->getUUID()); - } -} - void LLPanelGroupMembersSubTab::activate() { LLPanelGroupSubTab::activate(); @@ -1237,7 +1363,7 @@ bool LLPanelGroupMembersSubTab::apply(std::string& mesg) LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID); if (!gdatap) { - llwarns << "Unable to get group data for group " << mGroupID << llendl; + LL_WARNS() << "Unable to get group data for group " << mGroupID << LL_ENDL; mesg.assign("Unable to save member data. Try again later."); return false; @@ -1263,7 +1389,7 @@ bool LLPanelGroupMembersSubTab::apply(std::string& mesg) } else { - llwarns << "Unable to get role information for the owner role in group " << mGroupID << llendl; + LL_WARNS() << "Unable to get role information for the owner role in group " << mGroupID << LL_ENDL; mesg.assign("Unable to retried specific group information. Try again later"); return false; @@ -1299,7 +1425,7 @@ void LLPanelGroupMembersSubTab::applyMemberChanges() LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID); if (!gdatap) { - llwarns << "Unable to get group data for group " << mGroupID << llendl; + LL_WARNS() << "Unable to get group data for group " << mGroupID << LL_ENDL; return; } @@ -1363,21 +1489,21 @@ U64 LLPanelGroupMembersSubTab::getAgentPowersBasedOnRoleChanges(const LLUUID& ag LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID); if (!gdatap) { - llwarns << "LLPanelGroupMembersSubTab::getAgentPowersBasedOnRoleChanges() -- No group data!" << llendl; + LL_WARNS() << "LLPanelGroupMembersSubTab::getAgentPowersBasedOnRoleChanges() -- No group data!" << LL_ENDL; return GP_NO_POWERS; } LLGroupMgrGroupData::member_list_t::iterator iter = gdatap->mMembers.find(agent_id); if ( iter == gdatap->mMembers.end() ) { - llwarns << "LLPanelGroupMembersSubTab::getAgentPowersBasedOnRoleChanges() -- No member data for member with UUID " << agent_id << llendl; + LL_WARNS() << "LLPanelGroupMembersSubTab::getAgentPowersBasedOnRoleChanges() -- No member data for member with UUID " << agent_id << LL_ENDL; return GP_NO_POWERS; } LLGroupMemberData* member_data = (*iter).second; if (!member_data) { - llwarns << "LLPanelGroupMembersSubTab::getAgentPowersBasedOnRoleChanges() -- Null member data for member with UUID " << agent_id << llendl; + LL_WARNS() << "LLPanelGroupMembersSubTab::getAgentPowersBasedOnRoleChanges() -- Null member data for member with UUID " << agent_id << LL_ENDL; return GP_NO_POWERS; } @@ -1483,7 +1609,7 @@ void LLPanelGroupMembersSubTab::update(LLGroupChange gc) LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID); if (!gdatap) { - llwarns << "LLPanelGroupMembersSubTab::update() -- No group data!" << llendl; + LL_WARNS() << "LLPanelGroupMembersSubTab::update() -- No group data!" << LL_ENDL; return; } @@ -1522,6 +1648,13 @@ void LLPanelGroupMembersSubTab::update(LLGroupChange gc) } } +bool is_online_status_string(const std::string& status) +{ + const std::string& localized_online(); + const std::string& localized_unknown(); + return status == localized_online() || status == localized_unknown(); +} + void LLPanelGroupMembersSubTab::addMemberToList(LLGroupMemberData* data) { if (!data) return; @@ -1531,20 +1664,38 @@ void LLPanelGroupMembersSubTab::addMemberToList(LLGroupMemberData* data) LLNameListCtrl::NameItem item_params; item_params.value = data->getID(); - item_params.columns.add().column("name").font/*.name*/("SANSSERIF_SMALL")/*.style("NORMAL")*/; + item_params.columns.add().column("name").font/*.name*/("SANSSERIF_SMALL").font_style("NORMAL"); item_params.columns.add().column("donated").value(donated.getString()) - .font/*.name*/("SANSSERIF_SMALL")/*.style("NORMAL")*/; + .font/*.name*/("SANSSERIF_SMALL").font_style("NORMAL"); + static const LLCachedControl format(gSavedSettings, "ShortDateFormat"); item_params.columns.add().column("online").value(data->getOnlineStatus()) - .font/*.name*/("SANSSERIF_SMALL")/*.style("NORMAL")*/; + .format(format).type(is_online_status_string(data->getOnlineStatus()) ? "text" : "date") + .font/*.name*/("SANSSERIF_SMALL").font_style("NORMAL"); mMembersList->addNameItemRow(item_params); mHasMatch = TRUE; } -void LLPanelGroupMembersSubTab::onNameCache(const LLUUID& update_id, LLGroupMemberData* member, const LLAvatarName& av_name) +const S32& group_member_name_system() +{ + static const LLCachedControl name_system("GroupMembersNameSystem", 0); + return name_system; +} + +void LLPanelGroupMembersSubTab::onNameCache(const LLUUID& update_id, LLGroupMemberData* member, const LLAvatarName& av_name, const LLUUID& av_id) { + avatar_name_cache_connection_map_t::iterator it = mAvatarNameCacheConnections.find(av_id); + if (it != mAvatarNameCacheConnections.end()) + { + if (it->second.connected()) + { + it->second.disconnect(); + } + mAvatarNameCacheConnections.erase(it); + } + LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID); if (!gdatap || gdatap->getMemberVersion() != update_id @@ -1554,9 +1705,8 @@ void LLPanelGroupMembersSubTab::onNameCache(const LLUUID& update_id, LLGroupMemb } // trying to avoid unnecessary hash lookups - std::string name; - LLAvatarNameCache::getPNSName(av_name, name); // Singu Note: Diverge from LL Viewer and filter by name displayed - if (matchesSearchFilter(name)) + // Singu Note: Diverge from LL Viewer and filter by name displayed + if (matchesSearchFilter(av_name.getNSName(group_member_name_system()))) { addMemberToList(member); if(!mMembersList->getEnabled()) @@ -1575,7 +1725,7 @@ void LLPanelGroupMembersSubTab::updateMembers() LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID); if (!gdatap) { - llwarns << "LLPanelGroupMembersSubTab::updateMembers() -- No group data!" << llendl; + LL_WARNS() << "LLPanelGroupMembersSubTab::updateMembers() -- No group data!" << LL_ENDL; return; } @@ -1594,7 +1744,6 @@ void LLPanelGroupMembersSubTab::updateMembers() mMembersList->deleteAllItems(); } - LLGroupMgrGroupData::member_list_t::iterator end = gdatap->mMembers.end(); LLTimer update_time; @@ -1606,11 +1755,11 @@ void LLPanelGroupMembersSubTab::updateMembers() continue; // Do filtering on name if it is already in the cache. - // Singu Note: Diverge from LL Viewer and filter by name displayed - std::string fullname; - if (LLAvatarNameCache::getPNSName(mMemberProgress->first, fullname)) + LLAvatarName av_name; + if (LLAvatarNameCache::get(mMemberProgress->first, &av_name)) { - if (matchesSearchFilter(fullname)) + // Singu Note: Diverge from LL Viewer and filter by name displayed + if (matchesSearchFilter(av_name.getNSName(group_member_name_system()))) { addMemberToList(mMemberProgress->second); } @@ -1618,8 +1767,16 @@ void LLPanelGroupMembersSubTab::updateMembers() else { // If name is not cached, onNameCache() should be called when it is cached and add this member to list. - LLAvatarNameCache::get(mMemberProgress->first, boost::bind(&LLPanelGroupMembersSubTab::onNameCache, - this, gdatap->getMemberVersion(), mMemberProgress->second, _2)); + avatar_name_cache_connection_map_t::iterator it = mAvatarNameCacheConnections.find(mMemberProgress->first); + if (it != mAvatarNameCacheConnections.end()) + { + if (it->second.connected()) + { + it->second.disconnect(); + } + mAvatarNameCacheConnections.erase(it); + } + mAvatarNameCacheConnections[mMemberProgress->first] = LLAvatarNameCache::get(mMemberProgress->first, boost::bind(&LLPanelGroupMembersSubTab::onNameCache, this, gdatap->getMemberVersion(), mMemberProgress->second, _2, _1)); } } @@ -1644,12 +1801,35 @@ void LLPanelGroupMembersSubTab::updateMembers() handleMemberSelect(); } +void LLPanelGroupMembersSubTab::handleBanMember() +{ + LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID); + if (!gdatap) + { + LL_WARNS("Groups") << "Unable to get group data for group " << mGroupID << LL_ENDL; + return; + } + // Singu Note: We have this function, so there's less code here. + uuid_vec_t ban_ids = mMembersList->getSelectedIDs(); + if (ban_ids.empty()) + { + return; + } + + uuid_vec_t::iterator itor; + for(itor = ban_ids.begin(); itor != ban_ids.end(); ++itor) + { + LLGroupBanData ban_data; + gdatap->createBanEntry(*itor, ban_data); + } + + LLGroupMgr::getInstance()->sendGroupBanRequest(LLGroupMgr::REQUEST_POST, mGroupID, LLGroupMgr::BAN_CREATE, ban_ids); + handleEjectMembers(); +} -//////////////////////////// -// LLPanelGroupRolesSubTab -//////////////////////////// +// LLPanelGroupRolesSubTab /////////////////////////////////////////////// // static void* LLPanelGroupRolesSubTab::createTab(void* data) { @@ -1668,7 +1848,7 @@ LLPanelGroupRolesSubTab::LLPanelGroupRolesSubTab(const std::string& name, const mMemberVisibleCheck(NULL), mDeleteRoleButton(NULL), mCreateRoleButton(NULL), - + mFirstOpen(TRUE), mHasRoleChange(FALSE) { } @@ -1703,7 +1883,7 @@ BOOL LLPanelGroupRolesSubTab::postBuildSubTab(LLView* root) if (!mRolesList || !mAssignedMembersList || !mAllowedActionsList || !mRoleName || !mRoleTitle || !mRoleDescription || !mMemberVisibleCheck) { - llwarns << "ARG! element not found." << llendl; + LL_WARNS() << "ARG! element not found." << LL_ENDL; return FALSE; } @@ -1765,16 +1945,23 @@ void LLPanelGroupRolesSubTab::activate() void LLPanelGroupRolesSubTab::deactivate() { - lldebugs << "LLPanelGroupRolesSubTab::deactivate()" << llendl; + LL_DEBUGS() << "LLPanelGroupRolesSubTab::deactivate()" << LL_ENDL; LLPanelGroupSubTab::deactivate(); + mFirstOpen = FALSE; } bool LLPanelGroupRolesSubTab::needsApply(std::string& mesg) { - lldebugs << "LLPanelGroupRolesSubTab::needsApply()" << llendl; + LL_DEBUGS() << "LLPanelGroupRolesSubTab::needsApply()" << LL_ENDL; LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID); + if (!gdatap) + { + LL_WARNS() << "Unable to get group data for group " << mGroupID << LL_ENDL; + return false; + } + return (mHasRoleChange // Text changed in current role || (gdatap && gdatap->pendingRoleChanges())); // Pending role changes in the group @@ -1782,10 +1969,10 @@ bool LLPanelGroupRolesSubTab::needsApply(std::string& mesg) bool LLPanelGroupRolesSubTab::apply(std::string& mesg) { - lldebugs << "LLPanelGroupRolesSubTab::apply()" << llendl; + LL_DEBUGS() << "LLPanelGroupRolesSubTab::apply()" << LL_ENDL; saveRoleChanges(true); - + mFirstOpen = FALSE; LLGroupMgr::getInstance()->sendGroupRoleChanges(mGroupID); notifyObservers(); @@ -1845,7 +2032,7 @@ bool LLPanelGroupRolesSubTab::matchesSearchFilter(std::string rolename, std::str void LLPanelGroupRolesSubTab::update(LLGroupChange gc) { - lldebugs << "LLPanelGroupRolesSubTab::update()" << llendl; + LL_DEBUGS() << "LLPanelGroupRolesSubTab::update()" << LL_ENDL; if (mGroupID.isNull()) return; @@ -1890,7 +2077,7 @@ void LLPanelGroupRolesSubTab::update(LLGroupChange gc) } else { - llwarns << "LLPanelGroupRolesSubTab::update() No role data for role " << (*rit).first << llendl; + LL_WARNS() << "LLPanelGroupRolesSubTab::update() No role data for role " << (*rit).first << LL_ENDL; } } @@ -1922,14 +2109,17 @@ void LLPanelGroupRolesSubTab::update(LLGroupChange gc) } } - if (!gdatap || !gdatap->isMemberDataComplete()) - { - LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mGroupID); - } - - if (!gdatap || !gdatap->isRoleMemberDataComplete()) + if (!mFirstOpen) { - LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(mGroupID); + if (!gdatap || !gdatap->isMemberDataComplete()) + { + LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mGroupID); + } + + if (!gdatap || !gdatap->isRoleMemberDataComplete()) + { + LLGroupMgr::getInstance()->sendGroupRoleMembersRequest(mGroupID); + } } if ((GC_ROLE_MEMBER_DATA == gc || GC_MEMBER_DATA == gc) @@ -1945,13 +2135,16 @@ void LLPanelGroupRolesSubTab::update(LLGroupChange gc) void LLPanelGroupRolesSubTab::onRoleSelect(LLUICtrl* ctrl, void* user_data) { LLPanelGroupRolesSubTab* self = static_cast(user_data); + if (!self) + return; + self->handleRoleSelect(); } void LLPanelGroupRolesSubTab::handleRoleSelect() { BOOL can_delete = TRUE; - lldebugs << "LLPanelGroupRolesSubTab::handleRoleSelect()" << llendl; + LL_DEBUGS() << "LLPanelGroupRolesSubTab::handleRoleSelect()" << LL_ENDL; mAssignedMembersList->deleteAllItems(); mAllowedActionsList->deleteAllItems(); @@ -1959,8 +2152,8 @@ void LLPanelGroupRolesSubTab::handleRoleSelect() LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID); if (!gdatap) { - llwarns << "LLPanelGroupRolesSubTab::handleRoleSelect() " - << "-- No group data!" << llendl; + LL_WARNS() << "LLPanelGroupRolesSubTab::handleRoleSelect() " + << "-- No group data!" << LL_ENDL; return; } @@ -2048,8 +2241,8 @@ void LLPanelGroupRolesSubTab::buildMembersList() LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID); if (!gdatap) { - llwarns << "LLPanelGroupRolesSubTab::handleRoleSelect() " - << "-- No group data!" << llendl; + LL_WARNS() << "LLPanelGroupRolesSubTab::handleRoleSelect() " + << "-- No group data!" << LL_ENDL; return; } @@ -2098,13 +2291,13 @@ void LLPanelGroupRolesSubTab::handleActionCheck(LLUICtrl* ctrl, bool force) if (!check) return; - lldebugs << "LLPanelGroupRolesSubTab::handleActionSelect()" << llendl; + LL_DEBUGS() << "LLPanelGroupRolesSubTab::handleActionSelect()" << LL_ENDL; LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID); if (!gdatap) { - llwarns << "LLPanelGroupRolesSubTab::handleRoleSelect() " - << "-- No group data!" << llendl; + LL_WARNS() << "LLPanelGroupRolesSubTab::handleRoleSelect() " + << "-- No group data!" << LL_ENDL; return; } @@ -2124,40 +2317,115 @@ void LLPanelGroupRolesSubTab::handleActionCheck(LLUICtrl* ctrl, bool force) LLRoleAction* rap = (LLRoleAction*)action_item->getUserdata(); U64 power = rap->mPowerBit; - if (check->get()) + bool isEnablingAbility = check->get(); + LLRoleData rd; + LLSD args; + + if (isEnablingAbility && + !force && + ((GP_ROLE_ASSIGN_MEMBER == power) || (GP_ROLE_CHANGE_ACTIONS == power) )) { - if (!force && ( (GP_ROLE_ASSIGN_MEMBER == power) - || (GP_ROLE_CHANGE_ACTIONS == power) )) + // Uncheck the item, for now. It will be + // checked if they click 'Yes', below. + check->set(FALSE); + + LLRoleData rd; + LLSD args; + + if ( gdatap->getRoleData(role_id, rd) ) + { + args["ACTION_NAME"] = rap->mDescription; + args["ROLE_NAME"] = rd.mRoleName; + mHasModal = TRUE; + std::string warning = "AssignDangerousActionWarning"; + if (GP_ROLE_CHANGE_ACTIONS == power) + { + warning = "AssignDangerousAbilityWarning"; + } + LLNotificationsUtil::add(warning, args, LLSD(), boost::bind(&LLPanelGroupRolesSubTab::addActionCB, this, _1, _2, check)); + } + else { - // Uncheck the item, for now. It will be - // checked if they click 'Yes', below. - check->set(FALSE); + LL_WARNS() << "Unable to look up role information for role id: " + << role_id << LL_ENDL; + } + } - LLRoleData rd; - LLSD args; + if (GP_GROUP_BAN_ACCESS == power) + { + std::string warning = isEnablingAbility ? "AssignBanAbilityWarning" : "RemoveBanAbilityWarning"; - if ( gdatap->getRoleData(role_id, rd) ) + ////////////////////////////////////////////////////////////////////////// + // Get role data for both GP_ROLE_REMOVE_MEMBER and GP_MEMBER_EJECT + // Add description and role name to LLSD + // Pop up dialog saying "Yo, you also granted these other abilities when you did this!" + if (gdatap->getRoleData(role_id, rd)) + { + args["ACTION_NAME"] = rap->mDescription; + args["ROLE_NAME"] = rd.mRoleName; + mHasModal = TRUE; + + std::vector all_data = mAllowedActionsList->getAllData(); + std::vector::iterator ad_it = all_data.begin(); + std::vector::iterator ad_end = all_data.end(); + LLRoleAction* adp; + for( ; ad_it != ad_end; ++ad_it) { - args["ACTION_NAME"] = rap->mDescription; - args["ROLE_NAME"] = rd.mRoleName; - mHasModal = TRUE; - std::string warning = "AssignDangerousActionWarning"; - if (GP_ROLE_CHANGE_ACTIONS == power) + adp = (LLRoleAction*)(*ad_it)->getUserdata(); + if (adp->mPowerBit == GP_MEMBER_EJECT) { - warning = "AssignDangerousAbilityWarning"; + args["ACTION_NAME_2"] = adp->mDescription; + } + else if (adp->mPowerBit == GP_ROLE_REMOVE_MEMBER) + { + args["ACTION_NAME_3"] = adp->mDescription; } - LLNotificationsUtil::add(warning, args, LLSD(), boost::bind(&LLPanelGroupRolesSubTab::addActionCB, this, _1, _2, check)); - } - else - { - llwarns << "Unable to look up role information for role id: " - << role_id << llendl; } + + LLNotificationsUtil::add(warning, args); } else { - gdatap->addRolePower(role_id,power); + LL_WARNS() << "Unable to look up role information for role id: " + << role_id << LL_ENDL; } + + ////////////////////////////////////////////////////////////////////////// + + LLGroupMgrGroupData::role_list_t::iterator rit = gdatap->mRoles.find(role_id); + U64 current_role_powers = GP_NO_POWERS; + if (rit != gdatap->mRoles.end()) + { + current_role_powers = ((*rit).second->getRoleData().mRolePowers); + } + + if (isEnablingAbility) + { + power |= (GP_ROLE_REMOVE_MEMBER | GP_MEMBER_EJECT); + current_role_powers |= power; + } + else + { + current_role_powers &= ~GP_GROUP_BAN_ACCESS; + } + + mAllowedActionsList->deleteAllItems(); + buildActionsList( mAllowedActionsList, + current_role_powers, + current_role_powers, + boost::bind(&LLPanelGroupRolesSubTab::handleActionCheck, this, _1, false), + TRUE, + FALSE, + FALSE); + + } + + ////////////////////////////////////////////////////////////////////////// + // Adding non-specific ability to role + ////////////////////////////////////////////////////////////////////////// + if (isEnablingAbility) + { + gdatap->addRolePower(role_id, power); } else { @@ -2166,6 +2434,7 @@ void LLPanelGroupRolesSubTab::handleActionCheck(LLUICtrl* ctrl, bool force) mHasRoleChange = TRUE; notifyObservers(); + } bool LLPanelGroupRolesSubTab::addActionCB(const LLSD& notification, const LLSD& response, LLCheckBoxCtrl* check) @@ -2185,7 +2454,6 @@ bool LLPanelGroupRolesSubTab::addActionCB(const LLSD& notification, const LLSD& return false; } - // static void LLPanelGroupRolesSubTab::onPropertiesKey(LLLineEditor* ctrl, void* user_data) { @@ -2224,13 +2492,13 @@ void LLPanelGroupRolesSubTab::onMemberVisibilityChange(LLUICtrl* ctrl, void* use void LLPanelGroupRolesSubTab::handleMemberVisibilityChange(bool value) { - lldebugs << "LLPanelGroupRolesSubTab::handleMemberVisibilityChange()" << llendl; + LL_DEBUGS() << "LLPanelGroupRolesSubTab::handleMemberVisibilityChange()" << LL_ENDL; LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID); if (!gdatap) { - llwarns << "LLPanelGroupRolesSubTab::handleRoleSelect() " - << "-- No group data!" << llendl; + LL_WARNS() << "LLPanelGroupRolesSubTab::handleRoleSelect() " + << "-- No group data!" << LL_ENDL; return; } @@ -2363,10 +2631,26 @@ void LLPanelGroupRolesSubTab::saveRoleChanges(bool select_saved_role) mHasRoleChange = FALSE; } } -//////////////////////////// -// LLPanelGroupActionsSubTab -//////////////////////////// +void LLPanelGroupRolesSubTab::setGroupID(const LLUUID& id) +{ + if (mRolesList) mRolesList->deleteAllItems(); + if (mAssignedMembersList) mAssignedMembersList->deleteAllItems(); + if (mAllowedActionsList) mAllowedActionsList->deleteAllItems(); + + if (mRoleName) mRoleName->clear(); + if (mRoleDescription) mRoleDescription->clear(); + if (mRoleTitle) mRoleTitle->clear(); + + mHasRoleChange = FALSE; + + setFooterEnabled(FALSE); + + LLPanelGroupSubTab::setGroupID(id); +} + + +// LLPanelGroupActionsSubTab ///////////////////////////////////////////// // static void* LLPanelGroupActionsSubTab::createTab(void* data) { @@ -2420,27 +2704,27 @@ void LLPanelGroupActionsSubTab::activate() void LLPanelGroupActionsSubTab::deactivate() { - lldebugs << "LLPanelGroupActionsSubTab::deactivate()" << llendl; + LL_DEBUGS() << "LLPanelGroupActionsSubTab::deactivate()" << LL_ENDL; LLPanelGroupSubTab::deactivate(); } bool LLPanelGroupActionsSubTab::needsApply(std::string& mesg) { - lldebugs << "LLPanelGroupActionsSubTab::needsApply()" << llendl; + LL_DEBUGS() << "LLPanelGroupActionsSubTab::needsApply()" << LL_ENDL; return false; } bool LLPanelGroupActionsSubTab::apply(std::string& mesg) { - lldebugs << "LLPanelGroupActionsSubTab::apply()" << llendl; + LL_DEBUGS() << "LLPanelGroupActionsSubTab::apply()" << LL_ENDL; return true; } void LLPanelGroupActionsSubTab::update(LLGroupChange gc) { - lldebugs << "LLPanelGroupActionsSubTab::update()" << llendl; + LL_DEBUGS() << "LLPanelGroupActionsSubTab::update()" << LL_ENDL; if (mGroupID.isNull()) return; @@ -2544,3 +2828,223 @@ void LLPanelGroupActionsSubTab::handleActionSelect() LLGroupMgr::getInstance()->sendGroupRoleDataRequest(mGroupID); } } + +void LLPanelGroupActionsSubTab::setGroupID(const LLUUID& id) +{ + if (mActionList) mActionList->deleteAllItems(); + if (mActionRoles) mActionRoles->deleteAllItems(); + if (mActionMembers) mActionMembers->deleteAllItems(); + + if (mActionDescription) mActionDescription->clear(); + + LLPanelGroupSubTab::setGroupID(id); +} + +// LLPanelGroupBanListSubTab ///////////////////////////////////////////// +// static +void* LLPanelGroupBanListSubTab::createTab(void* data) +{ + LLUUID* group_id = static_cast(data); + return new LLPanelGroupBanListSubTab("panel group ban list sub tab", *group_id); +} + +LLPanelGroupBanListSubTab::LLPanelGroupBanListSubTab(const std::string& name, const LLUUID& group_id) + : LLPanelGroupSubTab(name, group_id), + mBanList(NULL), + mCreateBanButton(NULL), + mDeleteBanButton(NULL) +{} + +BOOL LLPanelGroupBanListSubTab::postBuildSubTab(LLView* root) +{ + LLPanelGroupSubTab::postBuildSubTab(root); + + // Upcast parent so we can ask it for sibling controls. + LLPanelGroupRoles* parent = (LLPanelGroupRoles*)root; + + // Look recursively from the parent to find all our widgets. + bool recurse = true; + + mHeader = parent->getChild("banlist_header", recurse); + mFooter = parent->getChild("banlist_footer", recurse); + + mBanList = parent->getChild("ban_list", recurse); + + mCreateBanButton = parent->getChild("ban_create", recurse); + mDeleteBanButton = parent->getChild("ban_delete", recurse); + mRefreshBanListButton = parent->getChild("ban_refresh", recurse); + + if (!mBanList || !mCreateBanButton || !mDeleteBanButton || !mRefreshBanListButton) + return FALSE; + + mBanList->setCommitOnSelectionChange(TRUE); + mBanList->setCommitCallback(boost::bind(&LLPanelGroupBanListSubTab::handleBanEntrySelect, this)); + + mCreateBanButton->setCommitCallback(boost::bind(&LLPanelGroupBanListSubTab::handleCreateBanEntry, this)); + mCreateBanButton->setEnabled(FALSE); + + mDeleteBanButton->setCommitCallback(boost::bind(&LLPanelGroupBanListSubTab::handleDeleteBanEntry, this)); + mDeleteBanButton->setEnabled(FALSE); + + mRefreshBanListButton->setCommitCallback(boost::bind(&LLPanelGroupBanListSubTab::handleRefreshBanList, this)); + mRefreshBanListButton->setEnabled(FALSE); + + mBanList->setOnNameListCompleteCallback(boost::bind(&LLPanelGroupBanListSubTab::onBanListCompleted, this, _1)); + + populateBanList(); + + //setFooterEnabled(FALSE); // Singu Note: This probably serves no purpose upstream, but for us, we need the footer enabled because we use it to make use of this entire panel. + return TRUE; +} + +void LLPanelGroupBanListSubTab::activate() +{ + LLPanelGroupSubTab::activate(); + + mBanList->deselectAllItems(); + mDeleteBanButton->setEnabled(FALSE); + + mCreateBanButton->setEnabled(gAgent.hasPowerInGroup(mGroupID, GP_GROUP_BAN_ACCESS)); + + // BAKER: Should I really request everytime activate() is called? + // Perhaps I should only do it on a force refresh, or if an action on the list happens... + // Because it's not going to live-update the list anyway... You'd have to refresh if you + // wanted to see someone else's additions anyway... + // + LLGroupMgr::getInstance()->sendGroupBanRequest(LLGroupMgr::REQUEST_GET, mGroupID); + + //setFooterEnabled(FALSE); // Singu Note: This probably serves no purpose upstream, but for us, we need the footer enabled because we use it to make use of this entire panel. + update(GC_ALL); +} + +void LLPanelGroupBanListSubTab::update(LLGroupChange gc) +{ + populateBanList(); +} + +void LLPanelGroupBanListSubTab::draw() +{ + LLPanelGroupSubTab::draw(); + + // BAKER: Might be good to put it here instead of update, maybe.. See how often draw gets hit. + //if( + // populateBanList(); +} + +void LLPanelGroupBanListSubTab::handleBanEntrySelect() +{ + if (gAgent.hasPowerInGroup(mGroupID, GP_GROUP_BAN_ACCESS)) + { + mDeleteBanButton->setEnabled(!!mBanList->getFirstSelected()); // Singu Note: Avoid empty selection. + } +} + +void LLPanelGroupBanListSubTab::handleCreateBanEntry() +{ + LLFloaterGroupBulkBan::showForGroup(mGroupID); + //populateBanList(); +} + +void LLPanelGroupBanListSubTab::handleDeleteBanEntry() +{ + LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID); + if (!gdatap) + { + LL_WARNS("Groups") << "Unable to get group data for group " << mGroupID << LL_ENDL; + return; + } + + // Singu Note: We have this function, so there's less code here. + uuid_vec_t ban_ids = mBanList->getSelectedIDs(); + if (ban_ids.empty()) + { + return; + } + + bool can_ban_members = false; + if (gAgent.isGodlike() || + gAgent.hasPowerInGroup(mGroupID, GP_GROUP_BAN_ACCESS)) + { + can_ban_members = true; + } + + // Owners can ban anyone in the group. + LLGroupMgrGroupData::member_list_t::iterator mi = gdatap->mMembers.find(gAgent.getID()); + if (mi != gdatap->mMembers.end()) + { + LLGroupMemberData* member_data = (*mi).second; + if (member_data && member_data->isInRole(gdatap->mOwnerRole)) + { + can_ban_members = true; + } + } + + if (!can_ban_members) + return; + + uuid_vec_t::iterator itor; + for(itor = ban_ids.begin(); itor != ban_ids.end(); ++itor) + { + LLUUID ban_id = (*itor); + + gdatap->removeBanEntry(ban_id); + mBanList->removeNameItem(ban_id); + + } + // Removing an item removes the selection, we shouldn't be able to click the button anymore until we reselect another entry. + mDeleteBanButton->setEnabled(FALSE); + + LLGroupMgr::getInstance()->sendGroupBanRequest(LLGroupMgr::REQUEST_POST, mGroupID, LLGroupMgr::BAN_DELETE, ban_ids); +} + +void LLPanelGroupBanListSubTab::handleRefreshBanList() +{ + mRefreshBanListButton->setEnabled(FALSE); + LLGroupMgr::getInstance()->sendGroupBanRequest(LLGroupMgr::REQUEST_GET, mGroupID); +} + +void LLPanelGroupBanListSubTab::onBanListCompleted(bool isComplete) +{ + if (isComplete) + { + mRefreshBanListButton->setEnabled(TRUE); + populateBanList(); + } +} + +void LLPanelGroupBanListSubTab::populateBanList() +{ + LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID); + if (!gdatap) + { + LL_WARNS("Groups") << "Unable to get group data for group " << mGroupID << LL_ENDL; + return; + } + + mBanList->deleteAllItems(); + std::map::const_iterator entry = gdatap->mBanList.begin(); + for(; entry != gdatap->mBanList.end(); entry++) + { + LLNameListCtrl::NameItem ban_entry; + ban_entry.value = entry->first; + LLGroupBanData bd = entry->second; + + ban_entry.columns.add().column("name").font/*.name*/("SANSSERIF_SMALL").font_style("NORMAL"); + + // Singu Note: We have special date columns, so our code is unique here + ban_entry.columns.add().column("ban_date").value(bd.mBanDate).type("date").format("%Y/%m/%d").font/*.name*/("SANSSERIF_SMALL").font_style("NORMAL"); + + mBanList->addNameItemRow(ban_entry); + } + + mRefreshBanListButton->setEnabled(TRUE); +} + +void LLPanelGroupBanListSubTab::setGroupID(const LLUUID& id) +{ + if (mBanList) + mBanList->deleteAllItems(); + + //setFooterEnabled(FALSE); + LLPanelGroupSubTab::setGroupID(id); +} diff --git a/indra/newview/llpanelgrouproles.h b/indra/newview/llpanelgrouproles.h index fe1103f2ff..c6fb9871f6 100644 --- a/indra/newview/llpanelgrouproles.h +++ b/indra/newview/llpanelgrouproles.h @@ -46,11 +46,9 @@ class LLScrollListItem; class LLTextEditor; class LLGroupMemberData; -// Forward declare for friend usage. -//virtual BOOL LLPanelGroupSubTab::postBuildSubTab(LLView*); - typedef std::map icon_map_t; + class LLPanelGroupRoles : public LLPanelGroupTab, public LLPanelGroupTabObserver { @@ -89,6 +87,8 @@ class LLPanelGroupRoles : public LLPanelGroupTab, virtual void cancel(); virtual void update(LLGroupChange gc); + virtual void setGroupID(const LLUUID& id); + // PanelGroupTab observer trigger virtual void tabChanged(); @@ -103,6 +103,7 @@ class LLPanelGroupRoles : public LLPanelGroupTab, std::string mWantApplyMesg; }; + class LLPanelGroupSubTab : public LLPanelGroupTab { public: @@ -123,6 +124,8 @@ class LLPanelGroupSubTab : public LLPanelGroupTab bool matchesActionSearchFilter(std::string action); void setFooterEnabled(BOOL enable); + + virtual void setGroupID(const LLUUID& id); protected: void buildActionsList(LLScrollListCtrl* ctrl, U64 allowed_by_some, @@ -152,9 +155,13 @@ class LLPanelGroupSubTab : public LLPanelGroupTab bool mActivated; + bool mHasGroupBanPower; // Used to communicate between action sets due to the dependency between + // GP_GROUP_BAN_ACCESS and GP_EJECT_MEMBER and GP_ROLE_REMOVE_MEMBER + void setOthersVisible(BOOL b); }; + class LLPanelGroupMembersSubTab : public LLPanelGroupSubTab { public: @@ -168,19 +175,20 @@ class LLPanelGroupMembersSubTab : public LLPanelGroupSubTab static void onMemberSelect(LLUICtrl*, void*); void handleMemberSelect(); - static void onMemberDoubleClick(void*); - void handleMemberDoubleClick(); - static void onInviteMember(void*); void handleInviteMember(); static void onEjectMembers(void*); void handleEjectMembers(); + void sendEjectNotifications(const LLUUID& group_id, const uuid_vec_t& selected_members); static void onRoleCheck(LLUICtrl* check, void* user_data); void handleRoleCheck(const LLUUID& role_id, LLRoleMemberChangeType type); + void handleBanMember(); + + void applyMemberChanges(); bool addOwnerCB(const LLSD& notification, const LLSD& response); @@ -194,8 +202,10 @@ class LLPanelGroupMembersSubTab : public LLPanelGroupSubTab virtual void draw(); + virtual void setGroupID(const LLUUID& id); + void addMemberToList(LLGroupMemberData* data); - void onNameCache(const LLUUID& update_id, LLGroupMemberData* member, const LLAvatarName& av_name); + void onNameCache(const LLUUID& update_id, LLGroupMemberData* member, const LLAvatarName& av_name, const LLUUID& av_id); protected: typedef std::map role_change_data_map_t; @@ -212,6 +222,7 @@ class LLPanelGroupMembersSubTab : public LLPanelGroupSubTab LLScrollListCtrl* mAssignedRolesList; LLScrollListCtrl* mAllowedActionsList; LLButton* mEjectBtn; + LLButton* mBanBtn; BOOL mChanged; BOOL mPendingMemberUpdate; @@ -221,8 +232,11 @@ class LLPanelGroupMembersSubTab : public LLPanelGroupSubTab U32 mNumOwnerAdditions; LLGroupMgrGroupData::member_list_t::iterator mMemberProgress; + typedef std::map avatar_name_cache_connection_map_t; + avatar_name_cache_connection_map_t mAvatarNameCacheConnections; }; + class LLPanelGroupRolesSubTab : public LLPanelGroupSubTab { public: @@ -263,6 +277,11 @@ class LLPanelGroupRolesSubTab : public LLPanelGroupSubTab void handleDeleteRole(); void saveRoleChanges(bool select_saved_role); + + virtual void setGroupID(const LLUUID& id); + + BOOL mFirstOpen; + protected: void handleActionCheck(LLUICtrl* ctrl, bool force); LLSD createRoleItem(const LLUUID& role_id, std::string name, std::string title, S32 members); @@ -284,6 +303,7 @@ class LLPanelGroupRolesSubTab : public LLPanelGroupSubTab std::string mRemoveEveryoneTxt; }; + class LLPanelGroupActionsSubTab : public LLPanelGroupSubTab { public: @@ -301,6 +321,8 @@ class LLPanelGroupActionsSubTab : public LLPanelGroupSubTab virtual void update(LLGroupChange gc); void handleActionSelect(); + + virtual void setGroupID(const LLUUID& id); protected: LLScrollListCtrl* mActionList; LLScrollListCtrl* mActionRoles; @@ -310,4 +332,42 @@ class LLPanelGroupActionsSubTab : public LLPanelGroupSubTab }; +class LLPanelGroupBanListSubTab : public LLPanelGroupSubTab +{ +public: + LLPanelGroupBanListSubTab(const std::string& name, const LLUUID& group_id); + virtual ~LLPanelGroupBanListSubTab() {} + + virtual BOOL postBuildSubTab(LLView* root); + + static void* createTab(void* data); + + virtual void activate(); + virtual void update(LLGroupChange gc); + virtual void draw(); + + void handleBanEntrySelect(); + + void handleCreateBanEntry(); + + void handleDeleteBanEntry(); + + void handleRefreshBanList(); + + void onBanListCompleted(bool isComplete); + +protected: + void populateBanList(); + +public: + virtual void setGroupID(const LLUUID& id); + +protected: + LLNameListCtrl* mBanList; + LLButton* mCreateBanButton; + LLButton* mDeleteBanButton; + LLButton* mRefreshBanListButton; + +}; + #endif // LL_LLPANELGROUPROLES_H diff --git a/indra/newview/llpanelgroupvoting.cpp b/indra/newview/llpanelgroupvoting.cpp index f45cd2818b..b58f15721a 100644 --- a/indra/newview/llpanelgroupvoting.cpp +++ b/indra/newview/llpanelgroupvoting.cpp @@ -307,7 +307,7 @@ void LLPanelGroupVoting::impl::setEnableVoteProposal() if ( proposal_cell ) { //proposal text - mProposalText->setText(proposal_cell->getValue().asString()); + mProposalText->setText(proposal_cell->getValue().asString(), false); } else { // Something's wrong... should have some text @@ -556,7 +556,7 @@ void LLPanelGroupVoting::impl::setEnableHistoryItem() const LLScrollListCell *cell = item->getColumn(5); if (cell) { - mVoteHistoryText->setText(cell->getValue().asString()); + mVoteHistoryText->setText(cell->getValue().asString(), false); } else { // Something's wrong... @@ -688,7 +688,7 @@ class LLStartGroupVoteResponder : public LLHTTPClient::ResponderWithResult } //If we get back a normal response, handle it here - /*virtual*/ void result(const LLSD& content) + /*virtual*/ void httpSuccess(void) { //Ack'd the proposal initialization, now let's finish up. LLPanelGroupVoting::handleResponse( @@ -697,10 +697,10 @@ class LLStartGroupVoteResponder : public LLHTTPClient::ResponderWithResult } //If we get back an error (not found, etc...), handle it here - /*virtual*/ void error(U32 status, const std::string& reason) + /*virtual*/ void httpFailure(void) { - llinfos << "LLPanelGroupVotingResponder::error " - << status << ": " << reason << llendl; + LL_INFOS() << "LLPanelGroupVotingResponder::error " + << mStatus << ": " << mReason << LL_ENDL; LLPanelGroupVoting::handleFailure(mGroupID); } @@ -721,20 +721,20 @@ class LLGroupProposalBallotResponder : public LLHTTPClient::ResponderWithResult } //If we get back a normal response, handle it here - /*virtual*/ void result(const LLSD& content) + /*virtual*/ void httpSuccess(void) { //Ack'd the proposal initialization, now let's finish up. LLPanelGroupVoting::handleResponse( mGroupID, LLPanelGroupVoting::BALLOT, - content["voted"].asBoolean()); + mContent["voted"].asBoolean()); } //If we get back an error (not found, etc...), handle it here - /*virtual*/ void error(U32 status, const std::string& reason) + /*virtual*/ void httpFailure(void) { - llinfos << "LLPanelGroupVotingResponder::error " - << status << ": " << reason << llendl; + LL_INFOS() << "LLPanelGroupVotingResponder::error " + << mStatus << ": " << mReason << LL_ENDL; LLPanelGroupVoting::handleFailure(mGroupID); } @@ -968,7 +968,7 @@ void LLPanelGroupVoting::impl::processGroupActiveProposalItemReply(LLMessageSyst msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id ); if (gAgent.getID() != agent_id) { - llwarns << "Got active group proposals reply for another agent!" << llendl; + LL_WARNS() << "Got active group proposals reply for another agent!" << LL_ENDL; return; } @@ -1130,7 +1130,7 @@ void LLPanelGroupVoting::impl::processGroupVoteHistoryItemReply(LLMessageSystem msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id ); if (gAgent.getID() != agent_id) { - llwarns << "Got group voting history reply for another agent!" << llendl; + LL_WARNS() << "Got group voting history reply for another agent!" << LL_ENDL; return; } @@ -1275,7 +1275,7 @@ void LLPanelGroupVoting::impl::processGroupVoteHistoryItemReply(LLMessageSystem } //end if proposal else { - llinfos << "Vote is not a proposal, but a " << vote_type << llendl; + LL_INFOS() << "Vote is not a proposal, but a " << vote_type << LL_ENDL; self->mOtherGroupHistoryItems++; } } //end if vote_items > 0 diff --git a/indra/newview/llpanelland.cpp b/indra/newview/llpanelland.cpp index 19d1a8d821..a235cea5f9 100644 --- a/indra/newview/llpanelland.cpp +++ b/indra/newview/llpanelland.cpp @@ -52,10 +52,6 @@ #include "hippogridmanager.h" -// [RLVa:KB] -#include "rlvhandler.h" -// [/RLVa:KB] - LLPanelLandSelectObserver* LLPanelLandInfo::sObserver = NULL; LLPanelLandInfo* LLPanelLandInfo::sInstance = NULL; @@ -159,13 +155,13 @@ void LLPanelLandInfo::refresh() && ((gAgent.getID() == auth_buyer_id) || (auth_buyer_id.isNull()))); - if (is_public) + if (is_public && !LLViewerParcelMgr::getInstance()->getParcelSelection()->getMultipleOwners()) { - childSetEnabled("button buy land",TRUE); + getChildView("button buy land")->setEnabled(TRUE); } else { - childSetEnabled("button buy land",can_buy); + getChildView("button buy land")->setEnabled(can_buy); } BOOL owner_release = LLViewerParcelMgr::isParcelOwnedByAgent(parcel, GP_LAND_RELEASE); @@ -201,7 +197,7 @@ void LLPanelLandInfo::refresh() } else { - lldebugs << "Invalid selection for joining land" << llendl; + LL_DEBUGS() << "Invalid selection for joining land" << LL_ENDL; childSetEnabled("button join land",FALSE); } @@ -239,12 +235,6 @@ void LLPanelLandInfo::refresh() //static void LLPanelLandInfo::onClickClaim(void*) { -// [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0a) - if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) - { - return; - } -// [/RLVa:KB] LLViewerParcelMgr::getInstance()->startBuyLand(); } diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index 11ae081019..3c7abe1742 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -42,7 +42,6 @@ #include "llfontgl.h" #include "llmd5.h" #include "llsecondlifeurls.h" -#include "sgversion.h" #include "v4color.h" #include "llappviewer.h" @@ -62,7 +61,7 @@ #include "llui.h" #include "lluiconstants.h" #include "llurlhistory.h" // OGPX : regionuri text box has a history of region uris (if FN/LN are loaded at startup) -#include "llviewerbuild.h" +#include "llversioninfo.h" #include "llviewertexturelist.h" #include "llviewermenu.h" // for handle_preferences() #include "llviewernetwork.h" @@ -84,147 +83,205 @@ // #include "llspinctrl.h" #include "llviewermessage.h" -#include // #include + +#include "llsdserialize.h" #include "llstring.h" #include const S32 BLACK_BORDER_HEIGHT = 160; const S32 MAX_PASSWORD = 16; -LLPanelLogin *LLPanelLogin::sInstance = NULL; -BOOL LLPanelLogin::sCapslockDidNotification = FALSE; +LLPanelLogin* LLPanelLogin::sInstance = NULL; -static bool nameSplit(const std::string& full, std::string& first, std::string& last) { +static bool nameSplit(const std::string& full, std::string& first, std::string& last) +{ std::vector fragments; boost::algorithm::split(fragments, full, boost::is_any_of(" .")); if (!fragments.size() || !fragments[0].length()) return false; first = fragments[0]; - if (fragments.size() == 1) - { - if (gHippoGridManager->getCurrentGrid()->isAurora()) - last = ""; - else - last = "Resident"; - } - else - last = fragments[1]; + last = (fragments.size() == 1) ? + gHippoGridManager->getCurrentGrid()->isWhiteCore() ? LLStringUtil::null : "Resident" : + fragments[1]; return (fragments.size() <= 2); } -static std::string nameJoin(const std::string& first,const std::string& last, bool strip_resident) { +static std::string nameJoin(const std::string& first,const std::string& last, bool strip_resident) +{ if (last.empty() || (strip_resident && boost::algorithm::iequals(last, "Resident"))) return first; - else { - if(std::islower(last[0])) - return first + "." + last; - else - return first + " " + last; - } + else if (std::islower(last[0])) + return first + '.' + last; + else + return first + ' ' + last; } -static std::string getDisplayString(const std::string& first, const std::string& last, const std::string& grid, bool is_secondlife) { +static std::string getDisplayString(const std::string& first, const std::string& last, const std::string& grid, bool is_secondlife) +{ //grid comes via LLSavedLoginEntry, which uses full grid names, not nicks - if(grid == gHippoGridManager->getDefaultGridName()) + if (grid == gHippoGridManager->getDefaultGridName()) return nameJoin(first, last, is_secondlife); else - return nameJoin(first, last, is_secondlife) + " (" + grid + ")"; + return nameJoin(first, last, is_secondlife) + " (" + grid + ')'; } -static std::string getDisplayString(const LLSavedLoginEntry& entry) { +static std::string getDisplayString(const LLSavedLoginEntry& entry) +{ return getDisplayString(entry.getFirstName(), entry.getLastName(), entry.getGrid(), entry.isSecondLife()); } -class LLLoginRefreshHandler : public LLCommandHandler + +class LLLoginLocationAutoHandler : public LLCommandHandler { public: // don't allow from external browsers - LLLoginRefreshHandler() : LLCommandHandler("login_refresh", UNTRUSTED_BLOCK) { } + LLLoginLocationAutoHandler() : LLCommandHandler("location_login", UNTRUSTED_BLOCK) { } bool handle(const LLSD& tokens, const LLSD& query_map, LLMediaCtrl* web) { if (LLStartUp::getStartupState() < STATE_LOGIN_CLEANUP) { - LLPanelLogin::loadLoginPage(); + if ( tokens.size() == 0 || tokens.size() > 4 ) + return false; + + // unescape is important - uris with spaces are escaped in this code path + // (e.g. space -> %20) and the code to log into a region doesn't support that. + const std::string region = LLURI::unescape( tokens[0].asString() ); + + // just region name as payload + if ( tokens.size() == 1 ) + { + // region name only - slurl will end up as center of region + LLSLURL slurl(region); + LLPanelLogin::autologinToLocation(slurl); + } + else + // region name and x coord as payload + if ( tokens.size() == 2 ) + { + // invalid to only specify region and x coordinate + // slurl code will revert to same as region only, so do this anyway + LLSLURL slurl(region); + LLPanelLogin::autologinToLocation(slurl); + } + else + // region name and x/y coord as payload + if ( tokens.size() == 3 ) + { + // region and x/y specified - default z to 0 + F32 xpos; + std::istringstream codec(tokens[1].asString()); + codec >> xpos; + + F32 ypos; + codec.clear(); + codec.str(tokens[2].asString()); + codec >> ypos; + + const LLVector3 location(xpos, ypos, 0.0f); + LLSLURL slurl(region, location); + + LLPanelLogin::autologinToLocation(slurl); + } + else + // region name and x/y/z coord as payload + if ( tokens.size() == 4 ) + { + // region and x/y/z specified - ok + F32 xpos; + std::istringstream codec(tokens[1].asString()); + codec >> xpos; + + F32 ypos; + codec.clear(); + codec.str(tokens[2].asString()); + codec >> ypos; + + F32 zpos; + codec.clear(); + codec.str(tokens[3].asString()); + codec >> zpos; + + const LLVector3 location(xpos, ypos, zpos); + LLSLURL slurl(region, location); + + LLPanelLogin::autologinToLocation(slurl); + }; } return true; } }; - -LLLoginRefreshHandler gLoginRefreshHandler; - +LLLoginLocationAutoHandler gLoginLocationAutoHandler; //--------------------------------------------------------------------------- // Public methods //--------------------------------------------------------------------------- -LLPanelLogin::LLPanelLogin(const LLRect &rect, - void (*callback)(S32 option, void* user_data), - void *cb_data) -: LLPanel(std::string("panel_login"), LLRect(0,600,800,0), FALSE), // not bordered - mLogoImage(), - mCallback(callback), - mCallbackData(cb_data) +LLPanelLogin::LLPanelLogin(const LLRect& rect) +: LLPanel(std::string("panel_login"), rect, FALSE), // not bordered + mLogoImage(LLUI::getUIImage("startup_logo.j2c")) { setFocusRoot(TRUE); setBackgroundVisible(FALSE); setBackgroundOpaque(TRUE); - gViewerWindow->abortShowProgress(); //Kill previous instance. It might still be alive, and if so, its probably pending - //deletion via the progressviews idle callback. Kill it now and unregister said idle callback. - LLPanelLogin::sInstance = this; // add to front so we are the bottom-most child gViewerWindow->getRootView()->addChildInBack(this); - // Logo - mLogoImage = LLUI::getUIImage("startup_logo.j2c"); - LLUICtrlFactory::getInstance()->buildPanel(this, "panel_login.xml"); - + reshape(rect.getWidth(), rect.getHeight()); +#ifndef LL_FMODSTUDIO + getChildView("fmod_text")->setVisible(false); + getChildView("fmod_logo")->setVisible(false); +#endif + LLComboBox* username_combo(getChild("username_combo")); - username_combo->setCommitCallback(boost::bind(LLPanelLogin::onSelectLoginEntry, _1, this)); + username_combo->setCommitCallback(boost::bind(LLPanelLogin::onSelectLoginEntry, _2)); username_combo->setFocusLostCallback(boost::bind(&LLPanelLogin::onLoginComboLostFocus, this, username_combo)); username_combo->setPrevalidate(LLLineEditor::prevalidatePrintableNotPipe); username_combo->setSuppressTentative(true); username_combo->setSuppressAutoComplete(true); - childSetCommitCallback("remember_name_check", onNameCheckChanged); + getChild("remember_name_check")->setCommitCallback(boost::bind(&LLPanelLogin::onNameCheckChanged, this, _2)); LLLineEditor* password_edit(getChild("password_edit")); - password_edit->setKeystrokeCallback(onPassKey); + password_edit->setKeystrokeCallback(boost::bind(LLPanelLogin::onPassKey)); // STEAM-14: When user presses Enter with this field in focus, initiate login - password_edit->setCommitCallback(mungePassword, this); + password_edit->setCommitCallback(boost::bind(&LLPanelLogin::mungePassword, this, _2)); password_edit->setDrawAsterixes(TRUE); + getChild("remove_login")->setCommitCallback(boost::bind(&LLPanelLogin::confirmDelete, this)); + // change z sort of clickable text to be behind buttons sendChildToBack(getChildView("channel_text")); sendChildToBack(getChildView("forgot_password_text")); - //llinfos << " url history: " << LLSDOStreamer(LLURLHistory::getURLHistory("regionuri")) << llendl; + //LL_INFOS() << " url history: " << LLSDOStreamer(LLURLHistory::getURLHistory("regionuri")) << LL_ENDL; LLComboBox* location_combo = getChild("start_location_combo"); updateLocationSelectorsVisibility(); // separate so that it can be called from preferences location_combo->setAllowTextEntry(TRUE, 128, FALSE); location_combo->setFocusLostCallback( boost::bind(&LLPanelLogin::onLocationSLURL, this) ); - LLComboBox *server_choice_combo = getChild("grids_combo"); - server_choice_combo->setCommitCallback(boost::bind(&LLPanelLogin::onSelectGrid, _1)); + LLComboBox* server_choice_combo = getChild("grids_combo"); + server_choice_combo->setCommitCallback(boost::bind(&LLPanelLogin::onSelectGrid, this, _1)); + server_choice_combo->setFocusLostCallback(boost::bind(&LLPanelLogin::onSelectGrid, this, server_choice_combo)); // Load all of the grids, sorted, and then add a bar and the current grid at the top updateGridCombo(); LLSLURL start_slurl(LLStartUp::getStartSLURL()); - if ( !start_slurl.isSpatial() ) // has a start been established by the command line or NextLoginLocation ? + if (!start_slurl.isSpatial()) // has a start been established by the command line or NextLoginLocation ? { // no, so get the preference setting std::string defaultStartLocation = gSavedSettings.getString("LoginLocation"); - LL_INFOS("AppInit")<<"default LoginLocation '"<("connect_btn")); + connect_btn->setCommitCallback(boost::bind(&LLPanelLogin::onClickConnect, this)); + setDefaultBtn(connect_btn); findChild("name_panel")->setDefaultBtn(connect_btn); findChild("password_panel")->setDefaultBtn(connect_btn); findChild("grids_panel")->setDefaultBtn(connect_btn); @@ -255,19 +312,18 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, findChild("login_html")->setDefaultBtn(connect_btn); } - childSetAction("grids_btn", onClickGrids, this); + getChild("grids_btn")->setCommitCallback(boost::bind(LLPanelLogin::onClickGrids)); - std::string channel = gVersionChannel; + std::string channel = LLVersionInfo::getChannel(); + + std::string version = llformat("%s (%d)", + LLVersionInfo::getShortVersion().c_str(), + LLVersionInfo::getBuild()); - std::string version = llformat("%d.%d.%d (%d)", - gVersionMajor, - gVersionMinor, - gVersionPatch, - LL_VIEWER_BUILD ); LLTextBox* channel_text = getChild("channel_text"); channel_text->setTextArg("[CHANNEL]", channel); // though not displayed channel_text->setTextArg("[VERSION]", version); - channel_text->setClickedCallback(boost::bind(&LLPanelLogin::onClickVersion,(void*)NULL)); + channel_text->setClickedCallback(boost::bind(LLFloaterAbout::show,(void*)NULL)); LLTextBox* forgot_password_text = getChild("forgot_password_text"); forgot_password_text->setClickedCallback(boost::bind(&onClickForgotPassword)); @@ -286,46 +342,133 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, refreshLoginPage(); gHippoGridManager->setCurrentGridChangeCallback(boost::bind(&LLPanelLogin::onCurGridChange,this,_1,_2)); + + // Load login history + std::string login_hist_filepath = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "saved_logins_sg2.xml"); + mLoginHistoryData = LLSavedLogins::loadFile(login_hist_filepath); + + const LLSavedLoginsList& saved_login_entries(mLoginHistoryData.getEntries()); + for (LLSavedLoginsList::const_reverse_iterator i = saved_login_entries.rbegin(); + i != saved_login_entries.rend(); ++i) + { + const LLSD& e = i->asLLSD(); + if (e.isMap() && gHippoGridManager->getGrid(i->getGrid())) + username_combo->add(getDisplayString(*i), e); + } + + if (saved_login_entries.size() > 0) + { + setFields(*saved_login_entries.rbegin()); + } + + addFavoritesToStartLocation(); } -void LLPanelLogin::setSiteIsAlive( bool alive ) +void LLPanelLogin::addFavoritesToStartLocation() { - LLMediaCtrl* web_browser = getChild("login_html"); - // if the contents of the site was retrieved - if ( alive ) + // Clear the combo. + auto combo = getChild("start_location_combo"); + if (!combo) return; + S32 num_items = combo->getItemCount(); + for (S32 i = num_items - 1; i > 2; i--) + { + combo->remove(i); + } + + // Load favorites into the combo. + const auto grid = gHippoGridManager->getCurrentGrid(); + std::string first, last, password; + getFields(first, last, password); + auto user_defined_name(first + ' ' + last); + std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "stored_favorites_" + grid->getGridName() + ".xml"); + std::string old_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "stored_favorites.xml"); + + LLSD fav_llsd; + llifstream file; + file.open(filename); + if (!file.is_open()) { - if ( web_browser ) + file.open(old_filename); + if (!file.is_open()) return; + } + LLSDSerialize::fromXML(fav_llsd, file); + + for (LLSD::map_const_iterator iter = fav_llsd.beginMap(); + iter != fav_llsd.endMap(); ++iter) + { + // The account name in stored_favorites.xml has Resident last name even if user has + // a single word account name, so it can be compared case-insensitive with the + // user defined "firstname lastname". + S32 res = LLStringUtil::compareInsensitive(user_defined_name, iter->first); + if (res != 0) { - loadLoginPage(); - - web_browser->setVisible(true); + LL_DEBUGS() << "Skipping favorites for " << iter->first << LL_ENDL; + continue; + } + + combo->addSeparator(); + LL_DEBUGS() << "Loading favorites for " << iter->first << LL_ENDL; + auto user_llsd = iter->second; + for (LLSD::array_const_iterator iter1 = user_llsd.beginArray(); + iter1 != user_llsd.endArray(); ++iter1) + { + std::string label = (*iter1)["name"].asString(); + std::string value = (*iter1)["slurl"].asString(); + if (!label.empty() && !value.empty()) + { + combo->add(label, value); + } } + break; } - else - // the site is not available (missing page, server down, other badness) +} + +void LLPanelLogin::setSiteIsAlive(bool alive) +{ + if (LLMediaCtrl* web_browser = getChild("login_html")) { - if ( web_browser ) - { - // hide browser control (revealing default one) - web_browser->setVisible( FALSE ); + if (alive) // if the contents of the site was retrieved + loadLoginPage(); + else // the site is not available (missing page, server down, other badness) web_browser->navigateTo( "data:text/html,%3Chtml%3E%3Cbody%20bgcolor=%22#000000%22%3E%3C/body%3E%3C/html%3E", "text/html" ); - } + web_browser->setVisible(alive); } } -void LLPanelLogin::mungePassword(LLUICtrl* caller, void* user_data) +void LLPanelLogin::clearPassword() +{ + getChild("password_edit")->setValue(mIncomingPassword = mMungedPassword = LLStringUtil::null); +} + +void LLPanelLogin::hidePassword() { - LLPanelLogin* self = (LLPanelLogin*)user_data; - LLLineEditor* editor = (LLLineEditor*)caller; - std::string password = editor->getText(); + // This is a MD5 hex digest of a password. + // We don't actually use the password input field, + // fill it with MAX_PASSWORD characters so we get a + // nice row of asterixes. + getChild("password_edit")->setValue("123456789!123456"); +} +void LLPanelLogin::mungePassword(const std::string& password) +{ // Re-md5 if we've changed at all - if (password != self->mIncomingPassword) + if (password != mIncomingPassword) { - LLMD5 pass((unsigned char *)password.c_str()); - char munged_password[MD5HEX_STR_SIZE]; - pass.hex_digest(munged_password); - self->mMungedPassword = munged_password; + // Max "actual" password length is 16 characters. + // Hex digests are always 32 characters. + if (password.length() == MD5HEX_STR_BYTES) + { + hidePassword(); + mMungedPassword = password; + } + else + { + LLMD5 pass((unsigned char *)utf8str_truncate(password, gHippoGridManager->getCurrentGrid()->isOpenSimulator() ? 24 : 16).c_str()); + char munged_password[MD5HEX_STR_SIZE]; + pass.hex_digest(munged_password); + mMungedPassword = munged_password; + } + mIncomingPassword = password; } } @@ -333,7 +476,7 @@ void LLPanelLogin::mungePassword(LLUICtrl* caller, void* user_data) // (with some padding so the other login screen doesn't show through) void LLPanelLogin::reshapeBrowser() { - LLMediaCtrl* web_browser = getChild("login_html"); + auto web_browser = getChild("login_html"); LLRect rect = gViewerWindow->getWindowRectScaled(); LLRect html_rect; html_rect.setCenterAndSize( @@ -346,30 +489,15 @@ void LLPanelLogin::reshapeBrowser() LLPanelLogin::~LLPanelLogin() { - LLPanelLogin::sInstance = NULL; + std::string login_hist_filepath = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "saved_logins_sg2.xml"); + LLSavedLogins::saveFile(mLoginHistoryData, login_hist_filepath); - if ( gFocusMgr.getDefaultKeyboardFocus() == this ) - { - gFocusMgr.setDefaultKeyboardFocus(NULL); - } -} + sInstance = nullptr; -void LLPanelLogin::setLoginHistory(LLSavedLogins const& login_history) -{ - sInstance->mLoginHistoryData = login_history; - - LLComboBox* login_combo = sInstance->getChild("username_combo"); - llassert(login_combo); - login_combo->clear(); - - LLSavedLoginsList const& saved_login_entries(login_history.getEntries()); - for (LLSavedLoginsList::const_reverse_iterator i = saved_login_entries.rbegin(); - i != saved_login_entries.rend(); ++i) - { - LLSD e = i->asLLSD(); - if (e.isMap() && gHippoGridManager->getGrid(i->getGrid())) - login_combo->add(getDisplayString(*i), e); - } + // Controls having keyboard focus by default + // must reset it on destroy. (EXT-2748) + if (gFocusMgr.getDefaultKeyboardFocus() == this) + gFocusMgr.setDefaultKeyboardFocus(nullptr); } // virtual @@ -412,48 +540,22 @@ void LLPanelLogin::draw() // virtual BOOL LLPanelLogin::handleKeyHere(KEY key, MASK mask) { - if (( KEY_RETURN == key ) && (MASK_ALT == mask)) - { - gViewerWindow->toggleFullscreen(FALSE); - return TRUE; - } - - if (('P' == key) && (MASK_CONTROL == mask)) - { - LLFloaterPreference::show(NULL); - return TRUE; - } - if (('T' == key) && (MASK_CONTROL == mask)) { new LLFloaterSimple("floater_test.xml"); return TRUE; } - - //Singu TODO: Re-implement f1 help. - /*if ( KEY_F1 == key ) - { - llinfos << "Spawning HTML help window" << llendl; - gViewerHtmlHelp.show(); - return TRUE; - }*/ # if !LL_RELEASE_FOR_DOWNLOAD if ( KEY_F2 == key ) { - llinfos << "Spawning floater TOS window" << llendl; - LLFloaterTOS* tos_dialog = LLFloaterTOS::show(LLFloaterTOS::TOS_TOS,""); + LL_INFOS() << "Spawning floater TOS window" << LL_ENDL; + LLFloaterTOS* tos_dialog = LLFloaterTOS::show(LLFloaterTOS::TOS_TOS,LLStringUtil::null); tos_dialog->startModal(); return TRUE; } #endif - if (KEY_RETURN == key && MASK_NONE == mask) - { - // let the panel handle UICtrl processing: calls onClickConnect() - return LLPanel::handleKeyHere(key, mask); - } - return LLPanel::handleKeyHere(key, mask); } @@ -478,6 +580,7 @@ void LLPanelLogin::giveFocus() { if( sInstance ) { + if (!sInstance->getVisible()) sInstance->setVisible(true); // Grab focus and move cursor to first blank input field std::string username = sInstance->getChild("username_combo")->getValue().asString(); std::string pass = sInstance->getChild("password_edit")->getValue().asString(); @@ -485,8 +588,8 @@ void LLPanelLogin::giveFocus() BOOL have_username = !username.empty(); BOOL have_pass = !pass.empty(); - LLLineEditor* edit = NULL; - LLComboBox* combo = NULL; + LLLineEditor* edit = nullptr; + LLComboBox* combo = nullptr; if (have_username && !have_pass) { // User saved his name but not his password. Move @@ -513,11 +616,10 @@ void LLPanelLogin::giveFocus() // static -void LLPanelLogin::show(const LLRect &rect, - void (*callback)(S32 option, void* user_data), - void* callback_data) +void LLPanelLogin::show() { - new LLPanelLogin(rect, callback, callback_data); + if (sInstance) sInstance->setVisible(true); + else new LLPanelLogin(gViewerWindow->getVirtualWindowRect()); if( !gFocusMgr.getKeyboardFocus() ) { @@ -536,7 +638,7 @@ void LLPanelLogin::setFields(const std::string& firstname, { if (!sInstance) { - llwarns << "Attempted fillFields with no login view shown" << llendl; + LL_WARNS() << "Attempted fillFields with no login view shown" << LL_ENDL; return; } @@ -545,29 +647,11 @@ void LLPanelLogin::setFields(const std::string& firstname, llassert_always(firstname.find(' ') == std::string::npos); login_combo->setLabel(nameJoin(firstname, lastname, false)); - // Max "actual" password length is 16 characters. - // Hex digests are always 32 characters. - if (password.length() == 32) - { - // This is a MD5 hex digest of a password. - // We don't actually use the password input field, - // fill it with MAX_PASSWORD characters so we get a - // nice row of asterixes. - const std::string filler("123456789!123456"); - sInstance->childSetText("password_edit", filler); - sInstance->mIncomingPassword = filler; - sInstance->mMungedPassword = password; - } + sInstance->mungePassword(password); + if (sInstance->mIncomingPassword != sInstance->mMungedPassword) + sInstance->getChild("password_edit")->setValue(password); else - { - // this is a normal text password - sInstance->childSetText("password_edit", password); - sInstance->mIncomingPassword = password; - LLMD5 pass((unsigned char *)password.c_str()); - char munged_password[MD5HEX_STR_SIZE]; - pass.hex_digest(munged_password); - sInstance->mMungedPassword = munged_password; - } + sInstance->hidePassword(); } // static @@ -575,7 +659,7 @@ void LLPanelLogin::setFields(const LLSavedLoginEntry& entry, bool takeFocus) { if (!sInstance) { - llwarns << "Attempted setFields with no login view shown" << llendl; + LL_WARNS() << "Attempted setFields with no login view shown" << LL_ENDL; return; } @@ -584,51 +668,42 @@ void LLPanelLogin::setFields(const LLSavedLoginEntry& entry, bool takeFocus) LLComboBox* login_combo = sInstance->getChild("username_combo"); login_combo->setTextEntry(fullname); login_combo->resetTextDirty(); - //sInstance->childSetText("username_combo", fullname); + //login_combo->setValue(fullname); - std::string grid = entry.getGrid(); + const auto& grid = entry.getGrid(); //grid comes via LLSavedLoginEntry, which uses full grid names, not nicks - if(!grid.empty() && gHippoGridManager->getGrid(grid) && grid != gHippoGridManager->getCurrentGridName()) + if (!grid.empty() && gHippoGridManager->getGrid(grid) && grid != gHippoGridManager->getCurrentGridName()) { gHippoGridManager->setCurrentGrid(grid); } - - if (entry.getPassword().empty()) - { - sInstance->childSetText("password_edit", std::string("")); - remember_pass_check->setValue(LLSD(false)); - } - else - { - const std::string filler("123456789!123456"); - sInstance->childSetText("password_edit", filler); - sInstance->mIncomingPassword = filler; - sInstance->mMungedPassword = entry.getPassword(); - remember_pass_check->setValue(LLSD(true)); - } - if (takeFocus) + const auto& password = entry.getPassword(); + bool remember_pass = !password.empty(); + if (remember_pass) { - giveFocus(); + sInstance->mIncomingPassword = sInstance->mMungedPassword = password; + sInstance->hidePassword(); } + else sInstance->clearPassword(); + remember_pass_check->setValue(remember_pass); + + if (takeFocus) giveFocus(); } // static -void LLPanelLogin::getFields(std::string *firstname, - std::string *lastname, - std::string *password) +void LLPanelLogin::getFields(std::string& firstname, std::string& lastname, std::string& password) { if (!sInstance) { - llwarns << "Attempted getFields with no login view shown" << llendl; + LL_WARNS() << "Attempted getFields with no login view shown" << LL_ENDL; return; } - nameSplit(sInstance->getChild("username_combo")->getTextEntry(), *firstname, *lastname); - LLStringUtil::trim(*firstname); - LLStringUtil::trim(*lastname); + nameSplit(sInstance->getChild("username_combo")->getTextEntry(), firstname, lastname); + LLStringUtil::trim(firstname); + LLStringUtil::trim(lastname); - *password = sInstance->mMungedPassword; + password = sInstance->mMungedPassword; } // static @@ -636,7 +711,7 @@ void LLPanelLogin::getFields(std::string *firstname, { if (!sInstance) { - llwarns << "Attempted getLocation with no login view shown" << llendl; + LL_WARNS() << "Attempted getLocation with no login view shown" << LL_ENDL; return; } @@ -662,9 +737,6 @@ void LLPanelLogin::updateLocationSelectorsVisibility() // [/RLVa:KB] sInstance->getChildView("location_panel")->setVisible(show_start); - - bool show_server = true; - sInstance->getChildView("grids_panel")->setVisible(show_server); } } @@ -676,7 +748,7 @@ void LLPanelLogin::onUpdateStartSLURL(const LLSLURL& new_start_slurl) LL_DEBUGS("AppInit")<getChild("start_location_combo"); + auto location_combo = sInstance->getChild("start_location_combo"); /* * Determine whether or not the new_start_slurl modifies the grid. * @@ -687,20 +759,23 @@ void LLPanelLogin::onUpdateStartSLURL(const LLSLURL& new_start_slurl) * and the grid selector to match the new value. */ enum LLSLURL::SLURL_TYPE new_slurl_type = new_start_slurl.getType(); - switch ( new_slurl_type ) + switch (new_slurl_type) { case LLSLURL::LOCATION: { - location_combo->setCurrentByIndex( 2 ); + location_combo->setCurrentByIndex(2); location_combo->setTextEntry(new_start_slurl.getLocationString()); } break; + case LLSLURL::HOME_LOCATION: - location_combo->setCurrentByIndex( 0 ); // home location + location_combo->setCurrentByIndex(0); // home location break; + case LLSLURL::LAST_LOCATION: - location_combo->setCurrentByIndex( 1 ); // last location + location_combo->setCurrentByIndex(1); // last location break; + default: LL_WARNS("AppInit")<<"invalid login slurl, using home"<setCurrentByIndex(1); // home location @@ -716,15 +791,27 @@ void LLPanelLogin::setLocation(const LLSLURL& slurl) LLStartUp::setStartSLURL(slurl); // calls onUpdateStartSLURL, above } +void LLPanelLogin::autologinToLocation(const LLSLURL& slurl) +{ + LL_DEBUGS("AppInit")<<"automatically logging into Location "<onClickConnect(); + } +} + + // static void LLPanelLogin::close() { if (sInstance) { - LLPanelLogin::sInstance->getParent()->removeChild( LLPanelLogin::sInstance ); + sInstance->getParent()->removeChild(sInstance); delete sInstance; - sInstance = NULL; + sInstance = nullptr; } } @@ -732,47 +819,44 @@ void LLPanelLogin::close() void LLPanelLogin::setAlwaysRefresh(bool refresh) { if (sInstance && LLStartUp::getStartupState() < STATE_LOGIN_CLEANUP) - { - LLMediaCtrl* web_browser = sInstance->getChild("login_html"); - - if (web_browser) - { + if (LLMediaCtrl* web_browser = sInstance->getChild("login_html")) web_browser->setAlwaysRefresh(refresh); - } - } } void LLPanelLogin::updateGridCombo() { - const std::string &defaultGrid = gHippoGridManager->getDefaultGridName(); + const std::string& defaultGrid = gHippoGridManager->getDefaultGridName(); - LLComboBox *grids = getChild("grids_combo"); + LLComboBox* grids = getChild("grids_combo"); std::string top_entry; grids->removeall(); - const HippoGridInfo *curGrid = gHippoGridManager->getCurrentGrid(); - const HippoGridInfo *defGrid = gHippoGridManager->getGrid(defaultGrid); + const HippoGridInfo* curGrid = gHippoGridManager->getCurrentGrid(); + const HippoGridInfo* defGrid = gHippoGridManager->getGrid(defaultGrid); + S32 idx(-1); HippoGridManager::GridIterator it, end = gHippoGridManager->endGrid(); for (it = gHippoGridManager->beginGrid(); it != end; ++it) { std::string grid = it->second->getGridName(); - if(grid.empty() || it->second == defGrid || it->second == curGrid) + if (grid.empty() || it->second == defGrid) continue; + if (it->second == curGrid) idx = grids->getItemCount(); grids->add(grid); } - if(curGrid || defGrid) + if (curGrid || defGrid) { - if(defGrid) - grids->add(defGrid->getGridName(),ADD_TOP); - if(curGrid && defGrid != curGrid) - grids->add(curGrid->getGridName(),ADD_TOP); - grids->setCurrentByIndex(0); + if (defGrid) + { + grids->add(defGrid->getGridName(), ADD_TOP); + ++idx; + } + grids->setCurrentByIndex(idx); } else { - grids->setLabel(LLStringExplicit("")); // LLComboBox::removeall() does not clear the label + grids->setLabel(LLStringUtil::null); // LLComboBox::removeall() does not clear the label } } @@ -788,29 +872,32 @@ void LLPanelLogin::loadLoginPage() sInstance->setSiteIsAlive(false); return; } - + // Use the right delimeter depending on how LLURI parses the URL LLURI login_page = LLURI(login_page_str); LLSD params(login_page.queryMap()); LL_DEBUGS("AppInit") << "login_page: " << login_page << LL_ENDL; - // Language + // Language params["lang"] = LLUI::getLanguage(); - - // First Login? - if (gSavedSettings.getBOOL("FirstLoginThisInstall")) + + // First Login? + if (gSavedSettings.getBOOL("FirstLoginThisInstall")) { params["firstlogin"] = "TRUE"; // not bool: server expects string TRUE - } - - params["version"]= llformat("%d.%d.%d (%d)", - gVersionMajor, gVersionMinor, gVersionPatch, gVersionBuild); - params["channel"] = gVersionChannel; + } + + // Channel and Version + params["version"] = llformat("%s (%d)", + LLVersionInfo::getShortVersion().c_str(), + LLVersionInfo::getBuild()); + params["channel"] = LLVersionInfo::getChannel(); // Grid - if (gHippoGridManager->getCurrentGrid()->isSecondLife()) { + if (gHippoGridManager->getCurrentGrid()->isSecondLife()) + { // find second life grid from login URI // yes, this is heuristic, but hey, it is just to get the right login page... std::string tmp = gHippoGridManager->getCurrentGrid()->getLoginUri(); @@ -830,18 +917,21 @@ void LLPanelLogin::loadLoginPage() { params["grid"] = gHippoGridManager->getCurrentGrid()->getGridNick(); } - else if (gHippoGridManager->getCurrentGrid()->getPlatform() == HippoGridInfo::PLATFORM_AURORA) + else if (gHippoGridManager->getCurrentGrid()->getPlatform() == HippoGridInfo::PLATFORM_WHITECORE) { params["grid"] = LLViewerLogin::getInstance()->getGridLabel(); } // add OS info params["os"] = LLAppViewer::instance()->getOSInfo().getOSStringSimple(); - + + auto&& uri_with_params = [](const LLURI& uri, const LLSD& params) { + return LLURI(uri.scheme(), uri.userName(), uri.password(), uri.hostName(), uri.hostPort(), uri.path(), + LLURI::mapToQueryString(params)); + }; + // Make an LLURI with this augmented info - LLURI login_uri(LLURI::buildHTTP(login_page.authority(), - login_page.path(), - params)); + LLURI login_uri(uri_with_params(login_page, params)); gViewerWindow->setMenuBackgroundColor(false, !LLViewerLogin::getInstance()->isInProductionGrid()); gLoginMenuBarView->setBackgroundColor(gMenuBarView->getBackgroundColor()); @@ -850,7 +940,14 @@ void LLPanelLogin::loadLoginPage() if (!singularity_splash_uri.empty()) { params["original_page"] = login_uri.asString(); - login_uri = LLURI::buildHTTP(singularity_splash_uri, gSavedSettings.getString("SingularitySplashPagePath"), params); + login_uri = LLURI(singularity_splash_uri + gSavedSettings.getString("SingularitySplashPagePath")); + + // Copy any existent splash path params + auto& params_map = params.map(); + for (auto&& pair : login_uri.queryMap().map()) + params_map.emplace(pair); + + login_uri = uri_with_params(login_uri, params); } LLMediaCtrl* web_browser = sInstance->getChild("login_html"); @@ -865,71 +962,33 @@ void LLPanelLogin::handleMediaEvent(LLPluginClassMedia* /*self*/, EMediaEvent ev { } - -bool LLPanelLogin::getRememberLogin() -{ - bool remember = false; - - if (sInstance) - { - LLCheckBoxCtrl* remember_login = sInstance->getChild("remember_name_check"); - if (remember_login) - { - remember = remember_login->getValue().asBoolean(); - } - } - else - { - llwarns << "Attempted to query rememberLogin with no login view shown" << llendl; - } - - return remember; -} - //--------------------------------------------------------------------------- // Protected methods //--------------------------------------------------------------------------- -// static -void LLPanelLogin::onClickConnect(void *) +void LLPanelLogin::onClickConnect() { - if (sInstance && sInstance->mCallback) - { - - // JC - Make sure the fields all get committed. - gFocusMgr.setKeyboardFocus(NULL); - - std::string first, last, password; - if (nameSplit(sInstance->getChild("username_combo")->getTextEntry(), first, last)) - { - // has both first and last name typed - sInstance->mCallback(0, sInstance->mCallbackData); - } - else - { - if (gHippoGridManager->getCurrentGrid()->getRegisterUrl().empty()) { - LLNotificationsUtil::add("MustHaveAccountToLogInNoLinks"); - } else { - LLNotificationsUtil::add("MustHaveAccountToLogIn", LLSD(), LLSD(), - LLPanelLogin::newAccountAlertCallback); - } - } - } + // JC - Make sure the fields all get committed. + gFocusMgr.setKeyboardFocus(NULL); + + std::string first, last; + if (nameSplit(getChild("username_combo")->getTextEntry(), first, last)) + LLStartUp::setStartupState(STATE_LOGIN_CLEANUP); + else if (gHippoGridManager->getCurrentGrid()->getRegisterUrl().empty()) + LLNotificationsUtil::add("MustHaveAccountToLogInNoLinks"); + else + LLNotificationsUtil::add("MustHaveAccountToLogIn", LLSD(), LLSD(), + LLPanelLogin::newAccountAlertCallback); } // static bool LLPanelLogin::newAccountAlertCallback(const LLSD& notification, const LLSD& response) { - S32 option = LLNotification::getSelectedOption(notification, response); - if (0 == option) + if (0 == LLNotification::getSelectedOption(notification, response)) { - llinfos << "Going to account creation URL" << llendl; - LLWeb::loadURLExternal( CREATE_ACCOUNT_URL ); - } - else - { - sInstance->setFocus(TRUE); + LL_INFOS() << "Going to account creation URL" << LL_ENDL; + LLWeb::loadURLExternal(CREATE_ACCOUNT_URL); } return false; } @@ -938,18 +997,20 @@ bool LLPanelLogin::newAccountAlertCallback(const LLSD& notification, const LLSD& // static void LLPanelLogin::onClickNewAccount() { - const std::string &url = gHippoGridManager->getCurrentGrid()->getRegisterUrl(); - if (!url.empty()) { - llinfos << "Going to account creation URL." << llendl; + const std::string& url = gHippoGridManager->getCurrentGrid()->getRegisterUrl(); + if (!url.empty()) + { + LL_INFOS() << "Going to account creation URL." << LL_ENDL; LLWeb::loadURLExternal(url); - } else { - llinfos << "Account creation URL is empty." << llendl; - sInstance->setFocus(TRUE); + } + else + { + LL_INFOS() << "Account creation URL is empty." << LL_ENDL; } } // static -void LLPanelLogin::onClickGrids(void*) +void LLPanelLogin::onClickGrids() { //LLFloaterPreference::overrideLastTab(LLPreferenceCore::TAB_GRIDS); LLFloaterPreference::show(NULL); @@ -957,39 +1018,30 @@ void LLPanelLogin::onClickGrids(void*) } // static -void LLPanelLogin::onClickVersion(void*) -{ - LLFloaterAbout::show(NULL); -} - -//static void LLPanelLogin::onClickForgotPassword() { - if (sInstance ) - { - const std::string &url = gHippoGridManager->getCurrentGrid()->getPasswordUrl(); - if (!url.empty()) { - LLWeb::loadURLExternal(url); - } else { - llwarns << "Link for 'forgotton password' not set." << llendl; - } - } + const std::string& url = gHippoGridManager->getCurrentGrid()->getPasswordUrl(); + if (!url.empty()) + LLWeb::loadURLExternal(url); + else + LL_WARNS() << "Link for 'forgotton password' not set." << LL_ENDL; } // static -void LLPanelLogin::onPassKey(LLLineEditor* caller) +void LLPanelLogin::onPassKey() { - if (gKeyboard->getKeyDown(KEY_CAPSLOCK) && sCapslockDidNotification == FALSE) + static bool sCapslockDidNotification = false; + if (gKeyboard->getKeyDown(KEY_CAPSLOCK) && sCapslockDidNotification == false) { LLNotificationsUtil::add("CapsKeyOn"); - sCapslockDidNotification = TRUE; + sCapslockDidNotification = true; } } void LLPanelLogin::onCurGridChange(HippoGridInfo* new_grid, HippoGridInfo* old_grid) { refreshLoginPage(); - if(old_grid != new_grid) //Changed grid? Reset the location combobox + if (old_grid != new_grid) //Changed grid? Reset the location combobox { std::string defaultStartLocation = gSavedSettings.getString("LoginLocation"); LLSLURL defaultStart(defaultStartLocation); @@ -1006,10 +1058,8 @@ void LLPanelLogin::refreshLoginPage() sInstance->updateGridCombo(); - sInstance->childSetVisible("create_new_account_text", - !gHippoGridManager->getCurrentGrid()->getRegisterUrl().empty()); - sInstance->childSetVisible("forgot_password_text", - !gHippoGridManager->getCurrentGrid()->getPasswordUrl().empty()); + sInstance->getChildView("create_new_account_text")->setVisible(!gHippoGridManager->getCurrentGrid()->getRegisterUrl().empty()); + sInstance->getChildView("forgot_password_text")->setVisible(!gHippoGridManager->getCurrentGrid()->getPasswordUrl().empty()); std::string login_page = gHippoGridManager->getCurrentGrid()->getLoginPage(); if (!login_page.empty()) @@ -1031,75 +1081,150 @@ void LLPanelLogin::refreshLoginPage() //void LLPanelLogin::onSelectServer() void LLPanelLogin::onSelectGrid(LLUICtrl *ctrl) { - gHippoGridManager->setCurrentGrid(ctrl->getValue()); + std::string grid(ctrl->getValue().asString()); + LLStringUtil::trim(grid); // Guard against copy paste + if (!gHippoGridManager->getGrid(grid)) // We can't get an input grid by name or nick, perhaps a Login URI was entered + { + HippoGridInfo* info(new HippoGridInfo(LLStringUtil::null)); // Start off with empty grid name, otherwise we don't know what to name + info->setLoginUri(grid); + try + { + info->getGridInfo(); + + grid = info->getGridName(); + if (HippoGridInfo* nick_info = gHippoGridManager->getGrid(info->getGridNick())) // Grid of same nick exists + { + delete info; + grid = nick_info->getGridName(); + } + else // Guess not, try adding this grid + { + gHippoGridManager->addGrid(info); // deletes info if not needed (existing or no name) + } + } + catch(AIAlert::ErrorCode const& error) + { + // Inform the user of the problem, but only if something was entered that at least looks like a Login URI. + std::string::size_type pos1 = grid.find('.'); + std::string::size_type pos2 = grid.find_last_of(".:"); + if (grid.substr(0, 4) == "http" || (pos1 != std::string::npos && pos1 != pos2)) + { + if (error.getCode() == HTTP_METHOD_NOT_ALLOWED || error.getCode() == HTTP_OK) + { + AIAlert::add("GridInfoError", error); + } + else + { + // Append GridInfoErrorInstruction to error message. + AIAlert::add("GridInfoError", AIAlert::Error(AIAlert::Prefix(), AIAlert::not_modal, error, "GridInfoErrorInstruction")); + } + } + delete info; + grid = gHippoGridManager->getCurrentGridName(); + } + } + gHippoGridManager->setCurrentGrid(grid); + ctrl->setValue(grid); + addFavoritesToStartLocation(); + + /* + * Determine whether or not the value in the start_location_combo makes sense + * with the new grid value. + * + * Note that some forms that could be in the location combo are grid-agnostic, + * such as "MyRegion/128/128/0". There could be regions with that name on any + * number of grids, so leave them alone. Other forms, such as + * https://grid.example.com/region/Party%20Town/20/30/5 specify a particular + * grid; in those cases we want to clear the location. + */ + auto location_combo = getChild("start_location_combo"); + S32 index = location_combo->getCurrentIndex(); + switch (index) + { + case 0: // last location + case 1: // home location + // do nothing - these are grid-agnostic locations + break; + + default: + { + std::string location = location_combo->getValue().asString(); + LLSLURL slurl(location); // generata a slurl from the location combo contents + if ( slurl.getType() == LLSLURL::LOCATION + && slurl.getGrid() != gHippoGridManager->getCurrentGridNick() + ) + { + // the grid specified by the location is not this one, so clear the combo + location_combo->setCurrentByIndex(0); // last location on the new grid + location_combo->setTextEntry(LLStringUtil::null); + } + } + break; + } } void LLPanelLogin::onLocationSLURL() { - LLComboBox* location_combo = getChild("start_location_combo"); + auto location_combo = getChild("start_location_combo"); std::string location = location_combo->getValue().asString(); + LLStringUtil::trim(location); LL_DEBUGS("AppInit")<getChild("username_combo"); - if (ctrl == combo) - { - LLSD selected_entry = combo->getSelectedValue(); - if (!selected_entry.isUndefined()) - { - LLSavedLoginEntry entry(selected_entry); - setFields(entry); - } - // This stops the automatic matching of the first name to a selected grid. - LLViewerLogin::getInstance()->setNameEditted(true); - } - } + if (selected_entry.isMap()) + setFields(LLSavedLoginEntry(selected_entry)); + // This stops the automatic matching of the first name to a selected grid. + LLViewerLogin::getInstance()->setNameEditted(true); + + sInstance->addFavoritesToStartLocation(); } void LLPanelLogin::onLoginComboLostFocus(LLComboBox* combo_box) { - if(combo_box->isTextDirty()) + if (combo_box->isTextDirty()) { clearPassword(); combo_box->resetTextDirty(); } } -// static -void LLPanelLogin::onNameCheckChanged(LLUICtrl* ctrl, void* data) +void LLPanelLogin::onNameCheckChanged(const LLSD& value) { - if (sInstance) + if (LLCheckBoxCtrl* remember_pass_check = findChild("remember_check")) { - LLCheckBoxCtrl* remember_login_check = sInstance->getChild("remember_name_check"); - LLCheckBoxCtrl* remember_pass_check = sInstance->getChild("remember_check"); - if (remember_login_check && remember_pass_check) + if (value.asBoolean()) { - if (remember_login_check->getValue().asBoolean()) - { - remember_pass_check->setEnabled(true); - } - else - { - remember_pass_check->setValue(LLSD(false)); - remember_pass_check->setEnabled(false); - } + remember_pass_check->setEnabled(true); + } + else + { + remember_pass_check->setValue(LLSD(false)); + remember_pass_check->setEnabled(false); } } } -// static -void LLPanelLogin::clearPassword() +void LLPanelLogin::confirmDelete() { - std::string blank; - sInstance->childSetText("password_edit", blank); - sInstance->mIncomingPassword = blank; - sInstance->mMungedPassword = blank; + LLNotificationsUtil::add("ConfirmDeleteUser", LLSD(), LLSD(), boost::bind(&LLPanelLogin::removeLogin, this, boost::bind(LLNotificationsUtil::getSelectedOption, _1, _2))); +} + +void LLPanelLogin::removeLogin(bool knot) +{ + if (knot) return; + LLComboBox* combo(getChild("username_combo")); + const std::string label(combo->getTextEntry()); + if (combo->isTextDirty() || !combo->itemExists(label)) return; // Text entries aren't in the list + const LLSD& selected = combo->getSelectedValue(); + if (!selected.isUndefined()) + { + mLoginHistoryData.deleteEntry(selected.get("firstname").asString(), selected.get("lastname").asString(), selected.get("grid").asString()); + combo->remove(label); + combo->selectFirstItem(); + } } diff --git a/indra/newview/llpanellogin.h b/indra/newview/llpanellogin.h index b1a7ff9354..478588aa48 100644 --- a/indra/newview/llpanellogin.h +++ b/indra/newview/llpanellogin.h @@ -49,18 +49,15 @@ class LLPanelLogin: { LOG_CLASS(LLPanelLogin); public: - LLPanelLogin(const LLRect &rect, - void (*callback)(S32 option, void* user_data), - void *callback_data); + LLPanelLogin(const LLRect& rect = LLRect()); ~LLPanelLogin(); virtual BOOL handleKeyHere(KEY key, MASK mask); virtual void draw(); virtual void setFocus( BOOL b ); - static void show(const LLRect &rect, - void (*callback)(S32 option, void* user_data), - void* callback_data); + static void show(); + static void hide() { if (sInstance) sInstance->setVisible(false); } // Remember password checkbox is set via gSavedSettings "RememberPassword" @@ -69,7 +66,6 @@ class LLPanelLogin: * @param firstname First name value. * @param lastname Last name value. * @param password Password, as plaintext or munged. - * @param is_secondlife True if First/Last refer to a SecondLife(tm) account. */ static void setFields(const std::string& firstname, const std::string& lastname, const std::string& password); @@ -80,9 +76,10 @@ class LLPanelLogin: */ static void setFields(const LLSavedLoginEntry& entry, bool takeFocus = true); - static void getFields(std::string *firstname, std::string *lastname, std::string *password); + static void getFields(std::string& firstname, std::string& lastname, std::string& password); static void setLocation(const LLSLURL& slurl); + static void autologinToLocation(const LLSLURL& slurl); /// Call when preferences that control visibility may have changed static void updateLocationSelectorsVisibility(); @@ -98,8 +95,10 @@ class LLPanelLogin: static void refreshLoginPage(); static void giveFocus(); static void setAlwaysRefresh(bool refresh); - static void mungePassword(LLUICtrl* caller, void* user_data); - + void clearPassword(); + void hidePassword(); + void mungePassword(const std::string& password); + // inherited from LLViewerMediaObserver /*virtual*/ void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event); @@ -108,26 +107,23 @@ class LLPanelLogin: private: void reshapeBrowser(); + void addFavoritesToStartLocation(); void onLocationSLURL(); - static void onClickConnect(void*); + void onClickConnect(); static void onClickNewAccount(); static bool newAccountAlertCallback(const LLSD& notification, const LLSD& response); - static void onClickGrids(void*); - static void onSelectGrid(LLUICtrl *ctrl); - static void onClickVersion(void*); + static void onClickGrids(); + void onSelectGrid(LLUICtrl *ctrl); static void onClickForgotPassword(); - static void onPassKey(LLLineEditor* caller); - static void onSelectLoginEntry(LLUICtrl*, void*); + static void onPassKey(); + static void onSelectLoginEntry(const LLSD& selected_entry); void onLoginComboLostFocus(LLComboBox* combo_box); - static void onNameCheckChanged(LLUICtrl* ctrl, void* data); - static void clearPassword(); + void onNameCheckChanged(const LLSD& value); + void confirmDelete(); + void removeLogin(bool knot); public: - /** - * @brief Set the login history data. - */ - static void setLoginHistory(LLSavedLogins const& login_history); /** * @brief Returns the login history data. @@ -138,25 +134,13 @@ class LLPanelLogin: return (sInstance ? sInstance->mLoginHistoryData : LLSavedLogins()); } - /** - * @brief Returns the state of the "remember resident name" checkbox if it exists. - * @return Checkbox state, or false if the instance is not instantiated. - */ - static bool getRememberLogin(); - - //static void selectFirstElement(void); - private: LLPointer mLogoImage; - void (*mCallback)(S32 option, void *userdata); - void* mCallbackData; - std::string mIncomingPassword; std::string mMungedPassword; static LLPanelLogin* sInstance; - static BOOL sCapslockDidNotification; LLSavedLogins mLoginHistoryData; }; diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp index cd7b2ebd46..659a5dfb4a 100644 --- a/indra/newview/llpanelmaininventory.cpp +++ b/indra/newview/llpanelmaininventory.cpp @@ -29,7 +29,7 @@ #include "llagent.h" #include "llagentcamera.h" -#include "lleconomy.h" +#include "llfirstuse.h" #include "llfiltereditor.h" #include "llinventorybridge.h" #include "llinventoryfunctions.h" @@ -39,6 +39,7 @@ #include "llresmgr.h" #include "llscrollcontainer.h" #include "llsdserialize.h" +#include "llsdparam.h" #include "llspinctrl.h" #include "lltooldraganddrop.h" #include "llviewermenu.h" @@ -46,67 +47,79 @@ #include "llpanelobjectinventory.h" #include "llappviewer.h" +#include "llradiogroup.h" + #include "rlvhandler.h" const std::string FILTERS_FILENAME("filters.xml"); -LLDynamicArray LLInventoryView::sActiveViews; +std::vector LLPanelMainInventory::sActiveViews; const S32 INV_MIN_WIDTH = 240; const S32 INV_MIN_HEIGHT = 150; const S32 INV_FINDER_WIDTH = 160; const S32 INV_FINDER_HEIGHT = 408; -//BOOL LLInventoryView::sOpenNextNewItem = FALSE; class LLFloaterInventoryFinder : public LLFloater { public: LLFloaterInventoryFinder(const std::string& name, const LLRect& rect, - LLInventoryView* inventory_view); + LLPanelMainInventory* inventory_view); virtual void draw(); /*virtual*/ BOOL postBuild(); virtual void onClose(bool app_quitting); void changeFilter(LLInventoryFilter* filter); void updateElementsFromFilter(); + BOOL getCheckShowLinks(); BOOL getCheckShowEmpty(); BOOL getCheckSinceLogoff(); + U32 getDateSearchDirection(); + void onLinks(const LLSD& val); static void onTimeAgo(LLUICtrl*, void *); static void onCloseBtn(void* user_data); static void selectAllTypes(void* user_data); static void selectNoTypes(void* user_data); protected: - LLInventoryView* mInventoryView; + LLPanelMainInventory* mPanelMainInventory; LLSpinCtrl* mSpinSinceDays; LLSpinCtrl* mSpinSinceHours; + LLUICtrl* mRadioLinks; LLInventoryFilter* mFilter; }; - ///---------------------------------------------------------------------------- -/// LLInventoryView +/// LLPanelMainInventory ///---------------------------------------------------------------------------- // Default constructor -LLInventoryView::LLInventoryView(const std::string& name, +LLPanelMainInventory::LLPanelMainInventory(const std::string& name, const std::string& rect, LLInventoryModel* inventory) : LLFloater(name, rect, std::string("Inventory"), RESIZE_YES, INV_MIN_WIDTH, INV_MIN_HEIGHT, DRAG_ON_TOP, MINIMIZE_NO, CLOSE_YES), - mActivePanel(NULL) + mFilterEditor(nullptr), + mFilterTabs(nullptr), + mActivePanel(nullptr), + mResortActivePanel(true), + mFilterText("") //LLHandle mFinderHandle takes care of its own initialization { init(inventory); } -LLInventoryView::LLInventoryView(const std::string& name, +LLPanelMainInventory::LLPanelMainInventory(const std::string& name, const LLRect& rect, LLInventoryModel* inventory) : LLFloater(name, rect, std::string("Inventory"), RESIZE_YES, INV_MIN_WIDTH, INV_MIN_HEIGHT, DRAG_ON_TOP, MINIMIZE_NO, CLOSE_YES), - mActivePanel(NULL) + mFilterEditor(nullptr), + mFilterTabs(nullptr), + mActivePanel(nullptr), + mResortActivePanel(true), + mFilterText("") //LLHandle mFinderHandle takes care of its own initialization { init(inventory); @@ -114,7 +127,7 @@ LLInventoryView::LLInventoryView(const std::string& name, } -void LLInventoryView::init(LLInventoryModel* inventory) +void LLPanelMainInventory::init(LLInventoryModel* inventory) { // Callbacks init_inventory_actions(this); @@ -131,13 +144,10 @@ void LLInventoryView::init(LLInventoryModel* inventory) addBoolControl("Inventory.SearchDesc", FALSE); addBoolControl("Inventory.SearchCreator", FALSE); - mSavedFolderState = new LLSaveFolderState(); - mSavedFolderState->setApply(FALSE); - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_inventory.xml", NULL); } -BOOL LLInventoryView::postBuild() +BOOL LLPanelMainInventory::postBuild() { gInventory.addObserver(this); @@ -149,9 +159,8 @@ BOOL LLInventoryView::postBuild() { // "All Items" is the previous only view, so it gets the InventorySortOrder mActivePanel->setSortOrder(gSavedSettings.getU32(LLInventoryPanel::DEFAULT_SORT_ORDER)); - mActivePanel->getFilter()->markDefault(); - mActivePanel->getRootFolder()->applyFunctorRecursively(*mSavedFolderState); - mActivePanel->setSelectCallback(boost::bind(&LLInventoryView::onSelectionChange, this, mActivePanel, _1, _2)); + mActivePanel->getFilter().markDefault(); + mActivePanel->setSelectCallback(boost::bind(&LLPanelMainInventory::onSelectionChange, this, mActivePanel, _1, _2)); mResortActivePanel = true; } LLInventoryPanel* recent_items_panel = getChild("Recent Items"); @@ -160,24 +169,26 @@ BOOL LLInventoryView::postBuild() recent_items_panel->setSinceLogoff(TRUE); recent_items_panel->setSortOrder(gSavedSettings.getU32(LLInventoryPanel::RECENTITEMS_SORT_ORDER)); recent_items_panel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); - recent_items_panel->getFilter()->markDefault(); - recent_items_panel->setSelectCallback(boost::bind(&LLInventoryView::onSelectionChange, this, recent_items_panel, _1, _2)); + LLInventoryFilter& recent_filter = recent_items_panel->getFilter(); + recent_filter.setFilterObjectTypes(recent_filter.getFilterObjectTypes() & ~(0x1 << LLInventoryType::IT_CATEGORY)); + recent_filter.markDefault(); + recent_items_panel->setSelectCallback(boost::bind(&LLPanelMainInventory::onSelectionChange, this, recent_items_panel, _1, _2)); } LLInventoryPanel* worn_items_panel = getChild("Worn Items"); if (worn_items_panel) { worn_items_panel->setSortOrder(gSavedSettings.getU32(LLInventoryPanel::WORNITEMS_SORT_ORDER)); worn_items_panel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); - worn_items_panel->getFilter()->markDefault(); - worn_items_panel->setFilterWorn(true); + worn_items_panel->getFilter().markDefault(); + worn_items_panel->setFilterWornItems(); worn_items_panel->setFilterLinks(LLInventoryFilter::FILTERLINK_EXCLUDE_LINKS); - worn_items_panel->setSelectCallback(boost::bind(&LLInventoryView::onSelectionChange, this, worn_items_panel, _1, _2)); + worn_items_panel->setSelectCallback(boost::bind(&LLPanelMainInventory::onSelectionChange, this, worn_items_panel, _1, _2)); } // Now load the stored settings from disk, if available. std::ostringstream filterSaveName; filterSaveName << gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, FILTERS_FILENAME); - llinfos << "LLInventoryView::init: reading from " << filterSaveName.str() << llendl; + LL_INFOS() << "LLPanelMainInventory::init: reading from " << filterSaveName.str() << LL_ENDL; llifstream file(filterSaveName.str()); LLSD savedFilterState; if (file.is_open()) @@ -186,36 +197,50 @@ BOOL LLInventoryView::postBuild() file.close(); // Load the persistent "Recent Items" settings. - // Note that the "All Items" and "Worn Items" settings do not persist per-account. + // Note that the "All Items" settings do not persist. if(recent_items_panel) { - if(savedFilterState.has(recent_items_panel->getFilter()->getName())) + if(savedFilterState.has(recent_items_panel->getFilter().getName())) { LLSD recent_items = savedFilterState.get( - recent_items_panel->getFilter()->getName()); - recent_items_panel->getFilter()->fromLLSD(recent_items); + recent_items_panel->getFilter().getName()); + LLInventoryFilter::Params p; + LLParamSDParser parser; + parser.readSD(recent_items, p); + recent_items_panel->getFilter().fromParams(p); + } + } + if(worn_items_panel) + { + if(savedFilterState.has(worn_items_panel->getFilter().getName())) + { + LLSD worn_items = savedFilterState.get( + worn_items_panel->getFilter().getName()); + LLInventoryFilter::Params p; + LLParamSDParser parser; + parser.readSD(worn_items, p); + worn_items_panel->getFilter().fromParams(p); } } } - mFilterEditor = getChild("inventory search editor"); if (mFilterEditor) { - mFilterEditor->setCommitCallback(boost::bind(&LLInventoryView::onFilterEdit, this, _2)); + mFilterEditor->setCommitCallback(boost::bind(&LLPanelMainInventory::onFilterEdit, this, _2)); } mQuickFilterCombo = getChild("Quick Filter"); if (mQuickFilterCombo) { - mQuickFilterCombo->setCommitCallback(boost::bind(LLInventoryView::onQuickFilterCommit, _1, this)); + mQuickFilterCombo->setCommitCallback(boost::bind(LLPanelMainInventory::onQuickFilterCommit, _1, this)); } - sActiveViews.put(this); + sActiveViews.push_back(this); - getChild("inventory filter tabs")->setCommitCallback(boost::bind(&LLInventoryView::onFilterSelected,this)); + getChild("inventory filter tabs")->setCommitCallback(boost::bind(&LLPanelMainInventory::onFilterSelected,this)); childSetAction("Inventory.ResetAll",onResetAll,this); childSetAction("Inventory.ExpandAll",onExpandAll,this); @@ -224,62 +249,65 @@ BOOL LLInventoryView::postBuild() } // Destroys the object -LLInventoryView::~LLInventoryView( void ) +LLPanelMainInventory::~LLPanelMainInventory( void ) { // Save the filters state. LLSD filterRoot; LLInventoryPanel* all_items_panel = getChild("All Items"); if (all_items_panel) { - LLInventoryFilter* filter = all_items_panel->getFilter(); - if (filter) + LLSD filterState; + LLInventoryPanel::InventoryState p; + all_items_panel->getFilter().toParams(p.filter); + if (p.validateBlock(false)) { - LLSD filterState; - filter->toLLSD(filterState); - filterRoot[filter->getName()] = filterState; + LLParamSDParser().writeSD(filterState, p); + filterRoot[all_items_panel->getName()] = filterState; } } - LLInventoryPanel* recent_items_panel = getChild("Recent Items"); - if (recent_items_panel) + LLInventoryPanel* recent_panel = findChild("Recent Items"); + if (recent_panel) { - LLInventoryFilter* filter = recent_items_panel->getFilter(); - if (filter) + LLSD filterState; + LLInventoryPanel::InventoryState p; + recent_panel->getFilter().toParams(p.filter); + if (p.validateBlock(false)) { - LLSD filterState; - filter->toLLSD(filterState); - filterRoot[filter->getName()] = filterState; + LLParamSDParser().writeSD(filterState, p); + filterRoot[recent_panel->getName()] = filterState; } } - LLInventoryPanel* worn_items_panel = getChild("Worn Items"); - if (worn_items_panel) + LLInventoryPanel* worn_panel = findChild("Worn Items"); + if (worn_panel) { - LLInventoryFilter* filter = worn_items_panel->getFilter(); - if (filter) + LLSD filterState; + LLInventoryPanel::InventoryState p; + worn_panel->getFilter().toParams(p.filter); + if (p.validateBlock(false)) { - LLSD filterState; - filter->toLLSD(filterState); - filterRoot[filter->getName()] = filterState; + LLParamSDParser().writeSD(filterState, p); + filterRoot[worn_panel->getName()] = filterState; } } - std::ostringstream filterSaveName; - filterSaveName << gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "filters.xml"); - llofstream filtersFile(filterSaveName.str()); + std::string filterSaveName(gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, FILTERS_FILENAME)); + llofstream filtersFile(filterSaveName.c_str()); if(!LLSDSerialize::toPrettyXML(filterRoot, filtersFile)) { - llwarns << "Could not write to filters save file " << filterSaveName << llendl; + LL_WARNS() << "Could not write to filters save file " << filterSaveName.c_str() << LL_ENDL; } else + { filtersFile.close(); + } - sActiveViews.removeObj(this); + vector_replace_with_last(sActiveViews, this); gInventory.removeObserver(this); - delete mSavedFolderState; } -void LLInventoryView::startSearch() +void LLPanelMainInventory::startSearch() { // this forces focus to line editor portion of search editor if (mFilterEditor) @@ -289,22 +317,22 @@ void LLInventoryView::startSearch() } // virtual, from LLView -void LLInventoryView::setVisible( BOOL visible ) +void LLPanelMainInventory::setVisible( BOOL visible ) { gSavedSettings.setBOOL("ShowInventory", visible); LLFloater::setVisible(visible); } // Destroy all but the last floater, which is made invisible. -void LLInventoryView::onClose(bool app_quitting) +void LLPanelMainInventory::onClose(bool app_quitting) { // S32 count = sActiveViews.count(); // [RLVa:KB] - Checked: 2009-07-10 (RLVa-1.0.0g) - // See LLInventoryView::closeAll() on why we're doing it this way + // See LLPanelMainInventory::closeAll() on why we're doing it this way S32 count = 0; - for (S32 idx = 0, cnt = sActiveViews.count(); idx < cnt; idx++) + for (S32 idx = 0, cnt = sActiveViews.size(); idx < cnt; idx++) { - if (!sActiveViews.get(idx)->isDead()) + if (!sActiveViews.at(idx)->isDead()) count++; } // [/RLVa:KB] @@ -319,21 +347,13 @@ void LLInventoryView::onClose(bool app_quitting) { gSavedSettings.setBOOL("ShowInventory", FALSE); } - // clear filters, but save user's folder state first - if (!mActivePanel->getRootFolder()->isFilterModified()) - { - mSavedFolderState->setApply(FALSE); - mActivePanel->getRootFolder()->applyFunctorRecursively(*mSavedFolderState); - } - - // onClearSearch(this); // pass up LLFloater::setVisible(FALSE); } } -BOOL LLInventoryView::handleKeyHere(KEY key, MASK mask) +BOOL LLPanelMainInventory::handleKeyHere(KEY key, MASK mask) { LLFolderView* root_folder = mActivePanel ? mActivePanel->getRootFolder() : NULL; if (root_folder) @@ -365,21 +385,15 @@ BOOL LLInventoryView::handleKeyHere(KEY key, MASK mask) // static // *TODO: remove take_keyboard_focus param -LLInventoryView* LLInventoryView::showAgentInventory(BOOL take_keyboard_focus) +LLPanelMainInventory* LLPanelMainInventory::showAgentInventory(BOOL take_keyboard_focus) { - if (gDisconnected || gNoRender) - { - return NULL; - } + if (gDisconnected) return NULL; // [RLVa:KB] - Checked: 2009-07-10 (RLVa-1.0.0g) - if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWINV)) - { - return NULL; - } + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWINV)) return NULL; // [/RLVa:KB] - LLInventoryView* iv = LLInventoryView::getActiveInventory(); + LLPanelMainInventory* iv = LLPanelMainInventory::getActiveInventory(); #if 0 && !LL_RELEASE_FOR_DOWNLOAD if (sActiveViews.count() == 1) { @@ -390,7 +404,7 @@ LLInventoryView* LLInventoryView::showAgentInventory(BOOL take_keyboard_focus) if(!iv && !gAgentCamera.cameraMouselook()) { // create one. - iv = new LLInventoryView(std::string("Inventory"), + iv = new LLPanelMainInventory(std::string("Inventory"), std::string("FloaterInventoryRect"), &gInventory); iv->open(); @@ -405,28 +419,23 @@ LLInventoryView* LLInventoryView::showAgentInventory(BOOL take_keyboard_focus) iv->setTitle(std::string("Inventory")); iv->open(); /*Flawfinder: ignore*/ } - //if (take_keyboard_focus) - //{ - // iv->startSearch(); - // gFocusMgr.triggerFocusFlash(); - //} return iv; } // static -LLInventoryView* LLInventoryView::getActiveInventory() +LLPanelMainInventory* LLPanelMainInventory::getActiveInventory() { - LLInventoryView* iv = NULL; - S32 count = sActiveViews.count(); + LLPanelMainInventory* iv = NULL; + S32 count = sActiveViews.size(); if(count > 0) { - iv = sActiveViews.get(0); + iv = sActiveViews.front(); S32 z_order = gFloaterView->getZOrder(iv); S32 z_next = 0; - LLInventoryView* next_iv = NULL; + LLPanelMainInventory* next_iv = NULL; for(S32 i = 1; i < count; ++i) { - next_iv = sActiveViews.get(i); + next_iv = sActiveViews[i]; z_next = gFloaterView->getZOrder(next_iv); if(z_next < z_order) { @@ -439,18 +448,20 @@ LLInventoryView* LLInventoryView::getActiveInventory() } // static -void LLInventoryView::toggleVisibility() +void LLPanelMainInventory::toggleVisibility() { - S32 count = sActiveViews.count(); + S32 count = sActiveViews.size(); if (0 == count) { + // We're using the inventory, possibly for the first time. + LLFirstUse::useInventory(); showAgentInventory(TRUE); } else if (1 == count) { - if (sActiveViews.get(0)->getVisible()) + if (sActiveViews.front()->getVisible()) { - sActiveViews.get(0)->close(); + sActiveViews.front()->close(); gSavedSettings.setBOOL("ShowInventory", FALSE); } else @@ -464,23 +475,23 @@ void LLInventoryView::toggleVisibility() // is visible. // Close all the last one spawned. - S32 last_index = sActiveViews.count() - 1; - sActiveViews.get(last_index)->close(); + sActiveViews.back()->close(); } } // static -void LLInventoryView::cleanup() +void LLPanelMainInventory::cleanup() { - S32 count = sActiveViews.count(); + S32 count = sActiveViews.size(); for (S32 i = 0; i < count; i++) { - sActiveViews.get(i)->destroy(); + sActiveViews.at(i)->destroy(); } + sActiveViews.clear(); } -void LLInventoryView::updateSortControls() +void LLPanelMainInventory::updateSortControls() { U32 order = mActivePanel ? mActivePanel->getSortOrder() : gSavedSettings.getU32("InventorySortOrder"); bool sort_by_date = order & LLInventoryFilter::SO_DATE; @@ -493,11 +504,10 @@ void LLInventoryView::updateSortControls() getControl("Inventory.SystemFoldersToTop")->setValue(sys_folders_on_top); } -void LLInventoryView::resetFilters() +void LLPanelMainInventory::resetFilters() { - LLFloaterInventoryFinder *finder = getFinder(); - getActivePanel()->getFilter()->resetDefault(); - if (finder) + getActivePanel()->getFilter().resetDefault(); + if (LLFloaterInventoryFinder* finder = getFinder()) { finder->updateElementsFromFilter(); } @@ -506,72 +516,34 @@ void LLInventoryView::resetFilters() } // static -BOOL LLInventoryView::filtersVisible(void* user_data) +BOOL LLPanelMainInventory::filtersVisible(void* user_data) { - LLInventoryView* self = (LLInventoryView*)user_data; + LLPanelMainInventory* self = (LLPanelMainInventory*)user_data; if(!self) return FALSE; return self->getFinder() != NULL; } -void LLInventoryView::onClearSearch() -{ - LLFloater *finder = getFinder(); - if (mActivePanel) - { - mActivePanel->setFilterSubString(LLStringUtil::null); - mActivePanel->setFilterTypes(0xffffffffffffffffULL); - } - - if (finder) - { - LLFloaterInventoryFinder::selectAllTypes(finder); - } - - // re-open folders that were initially open - if (mActivePanel) - { - mSavedFolderState->setApply(TRUE); - mActivePanel->getRootFolder()->applyFunctorRecursively(*mSavedFolderState); - LLOpenFoldersWithSelection opener; - mActivePanel->getRootFolder()->applyFunctorRecursively(opener); - mActivePanel->getRootFolder()->scrollToShowSelection(); - } - //self->mFilterSubString = ""; -} - -void LLInventoryView::onFilterEdit(const std::string& search_string ) +void LLPanelMainInventory::onFilterEdit(const std::string& search_string ) { - if (search_string == "") - { - onClearSearch(); - } if (!mActivePanel) { return; } - LLInventoryModelBackgroundFetch::instance().start(); - - //self->mFilterSubString = search_string; - std::string filter_text = search_string; - std::string uppercase_search_string = filter_text; - LLStringUtil::toUpper(uppercase_search_string); - if (mActivePanel->getFilterSubString().empty() && uppercase_search_string.empty() /*self->mFilterSubString.empty()*/) - { - // current filter and new filter empty, do nothing - return; - } - - // save current folder open state if no filter currently applied - if (!mActivePanel->getRootFolder()->isFilterModified()) + /* Singu Note: This is the old behavior, desired by SV-2078, but we'd prefer the new behavior. + * I've left this here in case we want to add it back in some way. + if (search_string.empty()) { - mSavedFolderState->setApply(FALSE); - mActivePanel->getRootFolder()->applyFunctorRecursively(*mSavedFolderState); + mActivePanel->setFilterTypes(0xffffffffffffffffULL); + if (auto* finder = getFinder()) + LLFloaterInventoryFinder::selectAllTypes(finder); } + */ // set new filter string - mActivePanel->setFilterSubString(uppercase_search_string/*self->mFilterSubString*/); + // Internally handles saving/restoring folder states. + mActivePanel->setFilterSubString(search_string); } struct FilterEntry : public LLDictionaryEntry @@ -586,7 +558,7 @@ class LLFilterDictionary : public LLSingleton, public: LLFilterDictionary() {} - void init(LLInventoryView *view) + void init(LLPanelMainInventory *view) { addEntry(0x1 << LLInventoryType::IT_ANIMATION, new FilterEntry(view->getString("filter_type_animation"))); addEntry(0x1 << LLInventoryType::IT_CALLINGCARD, new FilterEntry(view->getString("filter_type_callingcard"))); @@ -608,12 +580,12 @@ class LLFilterDictionary : public LLSingleton, }; //static -void LLInventoryView::onQuickFilterCommit(LLUICtrl* ctrl, void* user_data) +void LLPanelMainInventory::onQuickFilterCommit(LLUICtrl* ctrl, void* user_data) { LLComboBox* quickfilter = (LLComboBox*)ctrl; - LLInventoryView* view = (LLInventoryView*)(quickfilter->getParent()); + LLPanelMainInventory* view = (LLPanelMainInventory*)(quickfilter->getParent()); if (!view->mActivePanel) { return; @@ -638,7 +610,7 @@ void LLInventoryView::onQuickFilterCommit(LLUICtrl* ctrl, void* user_data) U32 filter_type = LLFilterDictionary::instance().lookup(item_type); if(!filter_type) { - llwarns << "Ignoring unknown filter: " << item_type << llendl; + LL_WARNS() << "Ignoring unknown filter: " << item_type << LL_ENDL; return; } else @@ -646,8 +618,7 @@ void LLInventoryView::onQuickFilterCommit(LLUICtrl* ctrl, void* user_data) view->mActivePanel->setFilterTypes( filter_type ); // Force the filters window to update itself, if it's open. - LLFloaterInventoryFinder* finder = view->getFinder(); - if( finder ) + if (LLFloaterInventoryFinder* finder = view->getFinder()) finder->updateElementsFromFilter(); } } @@ -656,9 +627,9 @@ void LLInventoryView::onQuickFilterCommit(LLUICtrl* ctrl, void* user_data) //static -void LLInventoryView::refreshQuickFilter(LLUICtrl* ctrl) +void LLPanelMainInventory::refreshQuickFilter(LLUICtrl* ctrl) { - LLInventoryView* view = (LLInventoryView*)(ctrl->getParent()); + LLPanelMainInventory* view = (LLPanelMainInventory*)(ctrl->getParent()); if (!view->mActivePanel) { return; @@ -687,7 +658,7 @@ void LLInventoryView::refreshQuickFilter(LLUICtrl* ctrl) filter_type &= filter_mask; - //llinfos << "filter_type: " << filter_type << llendl; + //LL_INFOS() << "filter_type: " << filter_type << LL_ENDL; std::string selection; if (filter_type == filter_mask) @@ -696,25 +667,22 @@ void LLInventoryView::refreshQuickFilter(LLUICtrl* ctrl) } else { - const FilterEntry *entry = LLFilterDictionary::instance().lookup(filter_type); - if(entry) + if (const FilterEntry *entry = LLFilterDictionary::instance().lookup(filter_type)) selection = entry->mName; else selection = view->getString("filter_type_custom"); } // Select the chosen item by label text - BOOL result = quickfilter->setSimple( (selection) ); - - if( !result ) + if (!quickfilter->setSimple(selection)) { - llinfos << "The item didn't exist: " << selection << llendl; + LL_INFOS() << "The item didn't exist: " << selection << LL_ENDL; } } -void LLInventoryView::onResetAll(void* userdata) +void LLPanelMainInventory::onResetAll(void* userdata) { - LLInventoryView* self = (LLInventoryView*) userdata; + LLPanelMainInventory* self = (LLPanelMainInventory*) userdata; self->mActivePanel = (LLInventoryPanel*)self->childGetVisibleTab("inventory filter tabs"); if (!self->mActivePanel) @@ -725,14 +693,17 @@ void LLInventoryView::onResetAll(void* userdata) { self->mFilterEditor->setText(LLStringUtil::null); } - self->onFilterEdit(""); + self->onFilterEdit(LLStringUtil::null); + self->mActivePanel->setFilterTypes(0xffffffffffffffffULL); + if (auto* finder = self->getFinder()) + LLFloaterInventoryFinder::selectAllTypes(finder); self->mActivePanel->closeAllFolders(); } //static -void LLInventoryView::onExpandAll(void* userdata) +void LLPanelMainInventory::onExpandAll(void* userdata) { - LLInventoryView* self = (LLInventoryView*) userdata; + LLPanelMainInventory* self = (LLPanelMainInventory*) userdata; self->mActivePanel = (LLInventoryPanel*)self->childGetVisibleTab("inventory filter tabs"); if (!self->mActivePanel) @@ -744,9 +715,9 @@ void LLInventoryView::onExpandAll(void* userdata) //static -void LLInventoryView::onCollapseAll(void* userdata) +void LLPanelMainInventory::onCollapseAll(void* userdata) { - LLInventoryView* self = (LLInventoryView*) userdata; + LLPanelMainInventory* self = (LLPanelMainInventory*) userdata; self->mActivePanel = (LLInventoryPanel*)self->childGetVisibleTab("inventory filter tabs"); if (!self->mActivePanel) @@ -756,24 +727,23 @@ void LLInventoryView::onCollapseAll(void* userdata) self->mActivePanel->closeAllFolders(); } -void LLInventoryView::onFilterSelected() +void LLPanelMainInventory::onFilterSelected() { // Find my index - mActivePanel = (LLInventoryPanel*)childGetVisibleTab("inventory filter tabs"); + mActivePanel = (LLInventoryPanel*)getChild("inventory filter tabs")->getCurrentPanel(); if (!mActivePanel) { return; } - //>setFilterSubString(self->mFilterSubString); - LLInventoryFilter* filter = mActivePanel->getFilter(); + LLInventoryFilter& filter = mActivePanel->getFilter(); LLFloaterInventoryFinder *finder = getFinder(); if (finder) { - finder->changeFilter(filter); + finder->changeFilter(&filter); } - if (filter->isActive()) + if (filter.isActive()) { // If our filter is active we may be the first thing requiring a fetch so we better start it here. LLInventoryModelBackgroundFetch::instance().start(); @@ -782,18 +752,18 @@ void LLInventoryView::onFilterSelected() updateSortControls(); } -const std::string LLInventoryView::getFilterSubString() +const std::string LLPanelMainInventory::getFilterSubString() { return mActivePanel->getFilterSubString(); } -void LLInventoryView::setFilterSubString(const std::string& string) +void LLPanelMainInventory::setFilterSubString(const std::string& string) { mActivePanel->setFilterSubString(string); } -BOOL LLInventoryView::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, +BOOL LLPanelMainInventory::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, void* cargo_data, EAcceptance* accept, @@ -815,7 +785,7 @@ BOOL LLInventoryView::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, return handled; } -void LLInventoryView::changed(U32 mask) +void LLPanelMainInventory::changed(U32 mask) { // Singu note: only if there's a change we're interested in. if ((mask & (LLInventoryObserver::ADD | LLInventoryObserver::REMOVE)) != 0) @@ -824,7 +794,7 @@ void LLInventoryView::changed(U32 mask) } } -void LLInventoryView::draw() +void LLPanelMainInventory::draw() { if (mActivePanel && mFilterEditor) { @@ -835,7 +805,6 @@ void LLInventoryView::draw() { refreshQuickFilter( mQuickFilterCombo ); } - if (mActivePanel && mResortActivePanel) { // EXP-756: Force resorting of the list the first time we draw the list: @@ -847,12 +816,11 @@ void LLInventoryView::draw() mActivePanel->setSortOrder(order); mResortActivePanel = false; } - updateItemcountText(); LLFloater::draw(); } -void LLInventoryView::updateItemcountText() +void LLPanelMainInventory::updateItemcountText() { std::ostringstream title; title << "Inventory"; @@ -870,12 +838,12 @@ void LLInventoryView::updateItemcountText() setTitle(title.str()); } -void LLInventoryView::setFilterTextFromFilter() +void LLPanelMainInventory::setFilterTextFromFilter() { - mFilterText = mActivePanel->getFilter()->getFilterText(); + mFilterText = mActivePanel->getFilter().getFilterText(); } -void LLInventoryView::toggleFindOptions() +void LLPanelMainInventory::toggleFindOptions() { LLFloater *floater = getFinder(); if (!floater) @@ -900,14 +868,19 @@ void LLInventoryView::toggleFindOptions() } } -void LLInventoryView::setSelectCallback(const LLFolderView::signal_t::slot_type& cb) +LLFolderView* LLPanelMainInventory::getRootFolder() const +{ + return mActivePanel ? (mActivePanel->getRootFolder()) : NULL; +} + +void LLPanelMainInventory::setSelectCallback(const LLFolderView::signal_t::slot_type& cb) { getChild("All Items")->setSelectCallback(cb); getChild("Recent Items")->setSelectCallback(cb); getChild("Worn Items")->setSelectCallback(cb); } -void LLInventoryView::onSelectionChange(LLInventoryPanel *panel, const std::deque& items, BOOL user_action) +void LLPanelMainInventory::onSelectionChange(LLInventoryPanel *panel, const std::deque& items, BOOL user_action) { panel->onSelectionChange(items, user_action); } @@ -916,7 +889,7 @@ void LLInventoryView::onSelectionChange(LLInventoryPanel *panel, const std::dequ /// LLFloaterInventoryFinder ///---------------------------------------------------------------------------- -LLFloaterInventoryFinder* LLInventoryView::getFinder() +LLFloaterInventoryFinder* LLPanelMainInventory::getFinder() { return (LLFloaterInventoryFinder*)mFinderHandle.get(); } @@ -924,12 +897,12 @@ LLFloaterInventoryFinder* LLInventoryView::getFinder() LLFloaterInventoryFinder::LLFloaterInventoryFinder(const std::string& name, const LLRect& rect, - LLInventoryView* inventory_view) : + LLPanelMainInventory* inventory_view) : LLFloater(name, rect, std::string("Filters"), RESIZE_NO, INV_FINDER_WIDTH, INV_FINDER_HEIGHT, DRAG_ON_TOP, MINIMIZE_NO, CLOSE_YES), - mInventoryView(inventory_view), - mFilter(inventory_view->getPanel()->getFilter()) + mPanelMainInventory(inventory_view), + mFilter(&inventory_view->getPanel()->getFilter()) { LLUICtrlFactory::getInstance()->buildFloater(this, "floater_inventory_view_finder.xml"); @@ -938,7 +911,7 @@ LLFloaterInventoryFinder::LLFloaterInventoryFinder(const std::string& name, BOOL LLFloaterInventoryFinder::postBuild() { - const LLRect& viewrect = mInventoryView->getRect(); + const LLRect& viewrect = mPanelMainInventory->getRect(); setRect(LLRect(viewrect.mLeft - getRect().getWidth(), viewrect.mTop, viewrect.mLeft, viewrect.mTop - getRect().getHeight())); childSetAction("All", selectAllTypes, this); @@ -950,23 +923,54 @@ BOOL LLFloaterInventoryFinder::postBuild() mSpinSinceDays = getChild("spin_days_ago"); childSetCommitCallback("spin_days_ago", onTimeAgo, this); + mRadioLinks = getChild("radio_links"); + mRadioLinks->setCommitCallback(std::bind(&LLFloaterInventoryFinder::onLinks, this, std::placeholders::_2)); + childSetAction("Close", onCloseBtn, this); updateElementsFromFilter(); return TRUE; } +void LLFloaterInventoryFinder::onLinks(const LLSD& val) +{ + auto value = val.asInteger(); + mFilter->setFilterLinks(value == 0 ? LLInventoryFilter::FILTERLINK_INCLUDE_LINKS : value == 1 ? LLInventoryFilter::FILTERLINK_EXCLUDE_LINKS : LLInventoryFilter::FILTERLINK_ONLY_LINKS); +} + void LLFloaterInventoryFinder::onTimeAgo(LLUICtrl *ctrl, void *user_data) { LLFloaterInventoryFinder *self = (LLFloaterInventoryFinder *)user_data; if (!self) return; - bool since_logoff=true; if ( self->mSpinSinceDays->get() || self->mSpinSinceHours->get() ) { - since_logoff = false; + self->getChild("check_since_logoff")->setValue(false); + + U32 days = (U32)self->mSpinSinceDays->get(); + U32 hours = (U32)self->mSpinSinceHours->get(); + if (hours >= 24) + { + // Try to handle both cases of spinner clicking and text input in a sensible fashion as best as possible. + // There is no way to tell if someone has clicked the spinner to get to 24 or input 24 manually, so in + // this case add to days. Any value > 24 means they have input the hours manually, so do not add to the + // current day value. + if (24 == hours) // Got to 24 via spinner clicking or text input of 24 + { + days = days + hours / 24; + } + else // Text input, so do not add to days + { + days = hours / 24; + } + hours = (U32)hours % 24; + self->mSpinSinceHours->setFocus(false); + self->mSpinSinceDays->setFocus(false); + self->mSpinSinceDays->set((F32)days); + self->mSpinSinceHours->set((F32)hours); + self->mSpinSinceHours->setFocus(true); + } } - self->childSetValue("check_since_logoff", since_logoff); } void LLFloaterInventoryFinder::changeFilter(LLInventoryFilter* filter) @@ -983,11 +987,13 @@ void LLFloaterInventoryFinder::updateElementsFromFilter() // Get data needed for filter display U32 filter_types = mFilter->getFilterObjectTypes(); std::string filter_string = mFilter->getFilterSubString(); + LLInventoryFilter::EFilterLink show_links = mFilter->getFilterLinks(); LLInventoryFilter::EFolderShow show_folders = mFilter->getShowFolderState(); U32 hours = mFilter->getHoursAgo(); + U32 date_search_direction = mFilter->getDateSearchDirection(); // update the ui elements - LLFloater::setTitle(mFilter->getName()); + setTitle(mFilter->getName()); getChild("check_animation")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_ANIMATION)); @@ -1001,10 +1007,14 @@ void LLFloaterInventoryFinder::updateElementsFromFilter() getChild("check_sound")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_SOUND)); getChild("check_texture")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_TEXTURE)); getChild("check_snapshot")->setValue((S32) (filter_types & 0x1 << LLInventoryType::IT_SNAPSHOT)); + getChild("check_show_links")->setValue(show_links == LLInventoryFilter::FILTERLINK_INCLUDE_LINKS); getChild("check_show_empty")->setValue(show_folders == LLInventoryFilter::SHOW_ALL_FOLDERS); getChild("check_since_logoff")->setValue(mFilter->isSinceLogoff()); mSpinSinceHours->set((F32)(hours % 24)); mSpinSinceDays->set((F32)(hours / 24)); + auto value = mFilter->getFilterLinks(); + mRadioLinks->setValue(value == LLInventoryFilter::FILTERLINK_INCLUDE_LINKS ? 0 : value == LLInventoryFilter::FILTERLINK_EXCLUDE_LINKS ? 1 : 2); + getChild("date_search_direction")->setSelectedIndex(date_search_direction); } void LLFloaterInventoryFinder::draw() @@ -1083,16 +1093,19 @@ void LLFloaterInventoryFinder::draw() filtered_by_all_types = FALSE; } - if (!filtered_by_all_types) + if (!filtered_by_all_types || (mPanelMainInventory->getPanel()->getFilter().getFilterTypes() & LLInventoryFilter::FILTERTYPE_DATE)) { - // don't include folders in filter, unless I've selected everything + // don't include folders in filter, unless I've selected everything or filtering by date filter &= ~(0x1 << LLInventoryType::IT_CATEGORY); } // update the panel, panel will update the filter - mInventoryView->getPanel()->setShowFolderState(getCheckShowEmpty() ? + mPanelMainInventory->getPanel()->setFilterLinks(getCheckShowLinks() ? + LLInventoryFilter::FILTERLINK_INCLUDE_LINKS : LLInventoryFilter::FILTERLINK_EXCLUDE_LINKS); + + mPanelMainInventory->getPanel()->setShowFolderState(getCheckShowEmpty() ? LLInventoryFilter::SHOW_ALL_FOLDERS : LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); - mInventoryView->getPanel()->setFilterTypes(filter); + mPanelMainInventory->getPanel()->setFilterTypes(filter); if (getCheckSinceLogoff()) { mSpinSinceDays->set(0); @@ -1100,7 +1113,7 @@ void LLFloaterInventoryFinder::draw() } U32 days = (U32)mSpinSinceDays->get(); U32 hours = (U32)mSpinSinceHours->get(); - if (hours > 24) + if (hours >= 24) { days += hours / 24; hours = (U32)hours % 24; @@ -1108,38 +1121,49 @@ void LLFloaterInventoryFinder::draw() mSpinSinceHours->set((F32)hours); } hours += days * 24; - mInventoryView->getPanel()->setHoursAgo(hours); - mInventoryView->getPanel()->setSinceLogoff(getCheckSinceLogoff()); - mInventoryView->setFilterTextFromFilter(); + mPanelMainInventory->getPanel()->setHoursAgo(hours); + mPanelMainInventory->getPanel()->setSinceLogoff(getCheckSinceLogoff()); + mPanelMainInventory->setFilterTextFromFilter(); + mPanelMainInventory->getPanel()->setDateSearchDirection(getDateSearchDirection()); LLFloater::draw(); } void LLFloaterInventoryFinder::onClose(bool app_quitting) { - if (mInventoryView) mInventoryView->getControl("Inventory.ShowFilters")->setValue(FALSE); + if (mPanelMainInventory) mPanelMainInventory->getControl("Inventory.ShowFilters")->setValue(FALSE); // If you want to reset the filter on close, do it here. This functionality was // hotly debated - Paulm #if 0 - if (mInventoryView) + if (mPanelMainInventory) { - LLInventoryView::onResetFilter((void *)mInventoryView); + LLPanelMainInventory::onResetFilter((void *)mPanelMainInventory); } #endif destroy(); } +BOOL LLFloaterInventoryFinder::getCheckShowLinks() +{ + return getChild("check_show_links")->getValue(); +} BOOL LLFloaterInventoryFinder::getCheckShowEmpty() { return getChild("check_show_empty")->getValue(); } + BOOL LLFloaterInventoryFinder::getCheckSinceLogoff() { return getChild("check_since_logoff")->getValue(); } +U32 LLFloaterInventoryFinder::getDateSearchDirection() +{ + return getChild("date_search_direction")->getSelectedIndex(); +} + void LLFloaterInventoryFinder::onCloseBtn(void* user_data) { LLFloaterInventoryFinder* finderp = (LLFloaterInventoryFinder*)user_data; diff --git a/indra/newview/llpanelmaininventory.h b/indra/newview/llpanelmaininventory.h index c19befd789..2f74cbda2e 100644 --- a/indra/newview/llpanelmaininventory.h +++ b/indra/newview/llpanelmaininventory.h @@ -1,4 +1,4 @@ -/** + /** * @file llpanelmaininventory.h * @brief llpanelmaininventory.h * class definition @@ -46,22 +46,22 @@ class LLFilterEditor; class LLComboBox; class LLFloaterInventoryFinder; -class LLInventoryView : public LLFloater, LLInventoryObserver +class LLPanelMainInventory : public LLFloater, LLInventoryObserver { friend class LLFloaterInventoryFinder; public: - LLInventoryView(const std::string& name, const std::string& rect, + LLPanelMainInventory(const std::string& name, const std::string& rect, LLInventoryModel* inventory); - LLInventoryView(const std::string& name, const LLRect& rect, + LLPanelMainInventory(const std::string& name, const LLRect& rect, LLInventoryModel* inventory); - ~LLInventoryView(); + ~LLPanelMainInventory(); BOOL postBuild(); //TODO: Move these statics. - static LLInventoryView* showAgentInventory(BOOL take_keyboard_focus=FALSE); - static LLInventoryView* getActiveInventory(); + static LLPanelMainInventory* showAgentInventory(BOOL take_keyboard_focus=FALSE); + static LLPanelMainInventory* getActiveInventory(); static void toggleVisibility(); static void toggleVisibility(void*) { toggleVisibility(); } // Final cleanup, destroy all open inventory views. @@ -80,17 +80,18 @@ friend class LLFloaterInventoryFinder; void* cargo_data, EAcceptance* accept, std::string& tooltip_msg); - /*virtual*/ void changed(U32 mask); + /*virtual*/ void changed(U32); /*virtual*/ void draw(); - LLInventoryPanel* getPanel() { return mActivePanel; } LLInventoryPanel* getActivePanel() { return mActivePanel; } const LLInventoryPanel* getActivePanel() const { return mActivePanel; } + LLFolderView* getRootFolder() const; const std::string& getFilterText() const { return mFilterText; } void setSelectCallback(const LLFolderView::signal_t::slot_type& cb); + void onFilterEdit(const std::string& search_string); // // Misc functions @@ -102,25 +103,21 @@ friend class LLFloaterInventoryFinder; void onSelectionChange(LLInventoryPanel *panel, const std::deque& items, BOOL user_action); static BOOL filtersVisible(void* user_data); - void onClearSearch(); static void onFoldersByName(void *user_data); static BOOL checkFoldersByName(void *user_data); - void onFilterSelected(); const std::string getFilterSubString(); void setFilterSubString(const std::string& string); - - static void onQuickFilterCommit(LLUICtrl* ctrl, void* user_data); static void refreshQuickFilter(LLUICtrl* ctrl); - + static void onResetAll(void* userdata); static void onExpandAll(void* userdata); - static void onCollapseAll(void* userdata); - + static void onCollapseAll(void* userdata); + void updateSortControls(); void resetFilters(); @@ -131,7 +128,7 @@ friend class LLFloaterInventoryFinder; { // If there are mulitple inventory floaters open then clicking the "Inventory" button will close // them one by one (see LLToolBar::onClickInventory() => toggleVisibility() ) until we get to the - // last one which will just be hidden instead of closed/destroyed (see LLInventoryView::onClose) + // last one which will just be hidden instead of closed/destroyed (see LLPanelMainInventory::onClose) // // However the view isn't removed from sActiveViews until its destructor is called and since // 'LLMortician::sDestroyImmediate == FALSE' while the viewer is running the destructor won't be @@ -142,10 +139,10 @@ friend class LLFloaterInventoryFinder; // // Workaround: "fix" onClose() to count only views that aren't marked as "dead" - LLInventoryView* pView; U8 flagsSound; - for (S32 idx = sActiveViews.count() - 1; idx >= 0; idx--) + LLPanelMainInventory* pView; U8 flagsSound; + for (S32 idx = sActiveViews.size() - 1; idx >= 0; idx--) { - pView = sActiveViews.get(idx); + pView = sActiveViews.at(idx); flagsSound = pView->getSoundFlags(); pView->setSoundFlags(LLView::SILENT); // Suppress the window close sound pView->close(); // onClose() protects against closing the last inventory floater @@ -161,23 +158,22 @@ friend class LLFloaterInventoryFinder; protected: LLFloaterInventoryFinder* getFinder(); + LLFilterEditor* mFilterEditor; LLComboBox* mQuickFilterCombo; LLTabContainer* mFilterTabs; LLHandle mFinderHandle; LLInventoryPanel* mActivePanel; bool mResortActivePanel; - LLSaveFolderState* mSavedFolderState; std::string mFilterText; //std::string mFilterSubString; // This container is used to hold all active inventory views. This // is here to support the inventory toggle show button. - static LLDynamicArray sActiveViews; + static std::vector sActiveViews; }; - #endif // LL_LLPANELMAININVENTORY_H diff --git a/indra/newview/llpanelmarketplaceoutboxinventory.cpp b/indra/newview/llpanelmarketplaceoutboxinventory.cpp deleted file mode 100644 index 7800eb7918..0000000000 --- a/indra/newview/llpanelmarketplaceoutboxinventory.cpp +++ /dev/null @@ -1,149 +0,0 @@ -/** - * @file llpanelmarketplaceoutboxinventory.cpp - * @brief LLOutboxInventoryPanel class definition - * - * $LicenseInfo:firstyear=2009&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llpanelmarketplaceoutboxinventory.h" - -//#include "llfolderview.h" -//#include "llfoldervieweventlistener.h" -#include "llinventorybridge.h" -//#include "llinventoryfunctions.h" -#include "lltrans.h" -//#include "llviewerfoldertype.h" - - -// -// statics -// - -static LLRegisterWidget r1("outbox_inventory_panel"); -//static LLRegisterWidget r2("outbox_folder_view_folder"); - -// -// LLOutboxInventoryPanel Implementation -// - -LLOutboxInventoryPanel::LLOutboxInventoryPanel(const std::string& name, - const std::string& sort_order_setting, - const std::string& start_folder, - const LLRect& rect, - LLInventoryModel* inventory, - BOOL allow_multi_select, - LLView* parent_view) - : LLInventoryPanel(name, sort_order_setting, start_folder, rect, inventory, allow_multi_select, parent_view) -{ -} - -LLOutboxInventoryPanel::~LLOutboxInventoryPanel() -{ -} - -// virtual -void LLOutboxInventoryPanel::buildFolderView(/*const LLInventoryPanel::Params& params*/) -{ - // Determine the root folder in case specified, and - // build the views starting with that folder. - - LLUUID root_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false, false); - - if (root_id == LLUUID::null) - { - llwarns << "Outbox inventory panel has no root folder!" << llendl; - root_id = LLUUID::generateNewID(); - } - - LLInvFVBridge* new_listener = mInvFVBridgeBuilder->createBridge(LLAssetType::AT_CATEGORY, - LLAssetType::AT_CATEGORY, - LLInventoryType::IT_CATEGORY, - this, - NULL, - root_id); - - mFolderRoot = createFolderView(new_listener, true/*params.use_label_suffix()*/); -} - -LLFolderViewFolder * LLOutboxInventoryPanel::createFolderViewFolder(LLInvFVBridge * bridge) -{ - return new LLOutboxFolderViewFolder( - bridge->getDisplayName(), - bridge->getIcon(), - bridge->getOpenIcon(), - LLUI::getUIImage("inv_link_overlay.tga"), - mFolderRoot, - bridge); -} - -LLFolderViewItem * LLOutboxInventoryPanel::createFolderViewItem(LLInvFVBridge * bridge) -{ - return new LLOutboxFolderViewItem( - bridge->getDisplayName(), - bridge->getIcon(), - bridge->getOpenIcon(), - LLUI::getUIImage("inv_link_overlay.tga"), - bridge->getCreationDate(), - mFolderRoot, - bridge); -} - -// -// LLOutboxFolderViewFolder Implementation -// - -LLOutboxFolderViewFolder::LLOutboxFolderViewFolder(const std::string& name, LLUIImagePtr icon, - LLUIImagePtr icon_open, - LLUIImagePtr icon_link, - LLFolderView* root, - LLFolderViewEventListener* listener) - : LLFolderViewFolder(name, icon, icon_open, icon_link, root, listener) -{ -} - -// -// LLOutboxFolderViewItem Implementation -// - -LLOutboxFolderViewItem::LLOutboxFolderViewItem(const std::string& name, LLUIImagePtr icon, - LLUIImagePtr icon_open, - LLUIImagePtr icon_overlay, - S32 creation_date, - LLFolderView* root, - LLFolderViewEventListener* listener) - : LLFolderViewItem(name, icon, icon_open, icon_overlay, creation_date, root, listener) -{ -} - -BOOL LLOutboxFolderViewItem::handleDoubleClick(S32 x, S32 y, MASK mask) -{ - return TRUE; -} - -void LLOutboxFolderViewItem::openItem() -{ - // Intentionally do nothing to block attaching items from the outbox -} - -// eof diff --git a/indra/newview/llpanelmarketplaceoutboxinventory.h b/indra/newview/llpanelmarketplaceoutboxinventory.h deleted file mode 100644 index 0eee7ed9e6..0000000000 --- a/indra/newview/llpanelmarketplaceoutboxinventory.h +++ /dev/null @@ -1,74 +0,0 @@ -/** - * @file llpanelmarketplaceoutboxinventory.h - * @brief LLOutboxInventoryPanel class declaration - * - * $LicenseInfo:firstyear=2009&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_OUTBOXINVENTORYPANEL_H -#define LL_OUTBOXINVENTORYPANEL_H - - -#include "llinventorypanel.h" -#include "llfolderviewitem.h" - - -class LLOutboxInventoryPanel : public LLInventoryPanel -{ -public: - LLOutboxInventoryPanel(const std::string& name, - const std::string& sort_order_setting, - const std::string& start_folder, - const LLRect& rect, - LLInventoryModel* inventory, - BOOL allow_multi_select, - LLView *parent_view = NULL); - ~LLOutboxInventoryPanel(); - - // virtual - void buildFolderView(/*const LLInventoryPanel::Params& params*/); - - // virtual - LLFolderViewFolder * createFolderViewFolder(LLInvFVBridge * bridge); - LLFolderViewItem * createFolderViewItem(LLInvFVBridge * bridge); -}; - - -class LLOutboxFolderViewFolder : public LLFolderViewFolder -{ -public: - LLOutboxFolderViewFolder(const std::string& name, LLUIImagePtr icon, LLUIImagePtr icon_open, LLUIImagePtr icon_link, LLFolderView* root, LLFolderViewEventListener* listener); -}; - - -class LLOutboxFolderViewItem : public LLFolderViewItem -{ -public: - LLOutboxFolderViewItem(const std::string& name, LLUIImagePtr icon, LLUIImagePtr icon_open, LLUIImagePtr icon_overlay, S32 creation_date, LLFolderView* root, LLFolderViewEventListener* listener); - - // virtual - BOOL handleDoubleClick(S32 x, S32 y, MASK mask); - void openItem(); -}; - - -#endif //LL_OUTBOXINVENTORYPANEL_H diff --git a/indra/newview/llpanelmediasettingsgeneral.cpp b/indra/newview/llpanelmediasettingsgeneral.cpp index f8ede13ba9..7372064c43 100644 --- a/indra/newview/llpanelmediasettingsgeneral.cpp +++ b/indra/newview/llpanelmediasettingsgeneral.cpp @@ -467,7 +467,7 @@ bool LLPanelMediaSettingsGeneral::navigateHomeSelectedFace(bool only_if_current_ bool all_face_media_navigated = false; LLObjectSelectionHandle selected_objects =LLSelectMgr::getInstance()->getSelection(); - selected_objects->getSelectedTEValue( &functor_navigate_media, all_face_media_navigated ); + (void)selected_objects->getSelectedTEValue( &functor_navigate_media, all_face_media_navigated ); // Note: we don't update the 'current URL' field until the media data itself changes diff --git a/indra/newview/llpanelmediasettingspermissions.cpp b/indra/newview/llpanelmediasettingspermissions.cpp index d9e5d4ad27..2b0043372a 100644 --- a/indra/newview/llpanelmediasettingspermissions.cpp +++ b/indra/newview/llpanelmediasettingspermissions.cpp @@ -101,15 +101,15 @@ void LLPanelMediaSettingsPermissions::draw() { if(mPermsGroupName) { - mPermsGroupName->setNameID(group_id, true); + mPermsGroupName->setNameID(group_id, LFIDBearer::GROUP); } } else { if(mPermsGroupName) { - mPermsGroupName->setNameID(LLUUID::null, TRUE); - mPermsGroupName->refresh(LLUUID::null, std::string(), true); + mPermsGroupName->setNameID(LLUUID::null, LFIDBearer::GROUP); + mPermsGroupName->refresh(LLUUID::null, std::string()); } } } diff --git a/indra/newview/llpanelnearbymedia.cpp b/indra/newview/llpanelnearbymedia.cpp index c578c9a8d3..9503de65f9 100644 --- a/indra/newview/llpanelnearbymedia.cpp +++ b/indra/newview/llpanelnearbymedia.cpp @@ -76,13 +76,24 @@ static const LLUUID PARCEL_AUDIO_LIST_ITEM_UUID = LLUUID("DF4B020D-8A24-4B95-AB5 LLPanelNearByMedia::LLPanelNearByMedia(bool standalone_panel) -: mMediaList(NULL), - mEnableAllCtrl(NULL), - mAllMediaDisabled(false), - mDebugInfoVisible(false), - mParcelMediaItem(NULL), - mParcelAudioItem(NULL), - mStandalonePanel(standalone_panel) + : mNearbyMediaPanel(nullptr) + , mMediaList(nullptr) + , mEnableAllCtrl(nullptr) + , mDisableAllCtrl(nullptr) + , mShowCtrl(nullptr) + , mStopCtrl(nullptr) + , mPlayCtrl(nullptr) + , mPauseCtrl(nullptr) + , mMuteCtrl(nullptr) + , mVolumeSliderCtrl(nullptr) + , mZoomCtrl(nullptr) + , mUnzoomCtrl(nullptr) + , mVolumeSlider(nullptr) + , mMuteBtn(nullptr) + , mDebugInfoVisible(false) + , mParcelMediaItem(nullptr) + , mParcelAudioItem(nullptr) + , mStandalonePanel(standalone_panel) { mHoverTimer.stop(); diff --git a/indra/newview/llpanelnearbymedia.h b/indra/newview/llpanelnearbymedia.h index 410dfb48c5..8b5bbdc357 100644 --- a/indra/newview/llpanelnearbymedia.h +++ b/indra/newview/llpanelnearbymedia.h @@ -165,7 +165,6 @@ class LLPanelNearByMedia : public LLPanel LLSlider* mVolumeSlider; LLButton* mMuteBtn; - bool mAllMediaDisabled; bool mDebugInfoVisible; bool mParcelAudioAutoStart; std::string mEmptyNameString; diff --git a/indra/newview/llpanelnetwork.cpp b/indra/newview/llpanelnetwork.cpp index 95b91731b2..ebf19eb5fb 100644 --- a/indra/newview/llpanelnetwork.cpp +++ b/indra/newview/llpanelnetwork.cpp @@ -67,20 +67,39 @@ BOOL LLPanelNetwork::postBuild() childSetEnabled("connection_port", gSavedSettings.getBOOL("ConnectionPortEnabled")); childSetCommitCallback("connection_port_enabled", onCommitPort, this); - childSetValue("cache_size", (F32)gSavedSettings.getU32("CacheSize")); + if (LLUICtrl* ctrl = getChild("cache_size")) + { + ctrl->setValue((F32)gSavedSettings.getU32("CacheSize")); + ctrl->setCommitCallback(boost::bind(LLPanelNetwork::onClickClearCache, (void*)NULL)); + } childSetValue("max_bandwidth", gSavedSettings.getF32("ThrottleBandwidthKBPS")); childSetValue("tex_bandwidth", gSavedSettings.getF32("HTTPThrottleBandwidth")); - childSetValue("http_textures", gSavedSettings.getBOOL("ImagePipelineUseHTTP")); - childSetValue("http_inventory", gSavedSettings.getBOOL("UseHTTPInventory")); childSetValue("connection_port_enabled", gSavedSettings.getBOOL("ConnectionPortEnabled")); childSetValue("connection_port", (F32)gSavedSettings.getU32("ConnectionPort")); - // If in Avination, hide the texture bandwidth slider, Avination throttles server-side - if (gHippoGridManager->getConnectedGrid()->isAvination()) + const auto& grid = gHippoGridManager->getConnectedGrid(); + if (!grid->isSecondLife()) { - childSetVisible("text_box4", FALSE); - childSetVisible("tex_bandwidth", FALSE); - childSetVisible("text_box3", FALSE); + if (auto view = getChildView("use_http_for")) + view->setVisible(true); + if (auto view = getChildView("http_textures")) + { + view->setVisible(true); + view->setValue(gSavedSettings.getBOOL("ImagePipelineUseHTTP")); + } + if (auto view = getChildView("http_inventory")) + { + view->setVisible(true); + view->setValue(gSavedSettings.getBOOL("UseHTTPInventory")); + } + + // If in Avination, hide the texture bandwidth slider, Avination throttles server-side + if (grid->isAvination()) + { + childSetVisible("text_box4", FALSE); + childSetVisible("tex_bandwidth", FALSE); + childSetVisible("text_box3", FALSE); + } } // Socks 5 proxy settings, commit callbacks @@ -118,16 +137,17 @@ LLPanelNetwork::~LLPanelNetwork() void LLPanelNetwork::apply() { - U32 cache_size = (U32)childGetValue("cache_size").asInteger(); - if (gSavedSettings.getU32("CacheSize") != cache_size) - { - onClickClearCache(this); - gSavedSettings.setU32("CacheSize", cache_size); - } + gSavedSettings.setU32("CacheSize", childGetValue("cache_size").asInteger()); gSavedSettings.setF32("ThrottleBandwidthKBPS", childGetValue("max_bandwidth").asReal()); - gSavedSettings.setF32("HTTPThrottleBandwidth", childGetValue("tex_bandwidth").asReal()); - gSavedSettings.setBOOL("ImagePipelineUseHTTP", childGetValue("http_textures")); - gSavedSettings.setBOOL("UseHTTPInventory", childGetValue("http_inventory")); + if (const auto& view = getChildView("tex_bandwidth")) + if (view->getVisible()) + gSavedSettings.setF32("HTTPThrottleBandwidth", view->getValue().asReal()); + if (const auto& view = getChildView("http_textures")) + if (view->getVisible()) + gSavedSettings.setBOOL("ImagePipelineUseHTTP", view->getValue()); + if (const auto& view = getChildView("http_inventory")) + if (view->getVisible()) + gSavedSettings.setBOOL("UseHTTPInventory", view->getValue()); gSavedSettings.setBOOL("ConnectionPortEnabled", childGetValue("connection_port_enabled")); gSavedSettings.setU32("ConnectionPort", childGetValue("connection_port").asInteger()); @@ -162,8 +182,11 @@ void LLPanelNetwork::cancel() void LLPanelNetwork::onClickClearCache(void*) { // flag client cache for clearing next time the client runs - gSavedSettings.setBOOL("PurgeCacheOnNextStartup", TRUE); - LLNotificationsUtil::add("CacheWillClear"); + if (!gSavedSettings.getBOOL("PurgeCacheOnNextStartup")) + { + gSavedSettings.setBOOL("PurgeCacheOnNextStartup", TRUE); + LLNotificationsUtil::add("CacheWillClear"); + } } // static diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index 7cf9872ae9..e9d82f8c01 100644 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -36,7 +36,6 @@ #include "llpanelobject.h" // linden library includes -#include "lleconomy.h" #include "llerror.h" #include "llfontgl.h" #include "llpermissionsflags.h" @@ -130,10 +129,10 @@ LLVector3 LLPanelObject::mClipboardPos; LLVector3 LLPanelObject::mClipboardSize; LLVector3 LLPanelObject::mClipboardRot; LLVolumeParams LLPanelObject::mClipboardVolumeParams; -LLFlexibleObjectData* LLPanelObject::mClipboardFlexiParams = NULL; -LLLightParams* LLPanelObject::mClipboardLightParams = NULL; -LLSculptParams* LLPanelObject::mClipboardSculptParams = NULL; -LLLightImageParams* LLPanelObject::mClipboardLightImageParams = NULL; +const LLFlexibleObjectData* LLPanelObject::mClipboardFlexiParams = NULL; +const LLLightParams* LLPanelObject::mClipboardLightParams = NULL; +const LLSculptParams* LLPanelObject::mClipboardSculptParams = NULL; +const LLLightImageParams* LLPanelObject::mClipboardLightImageParams = NULL; BOOL LLPanelObject::hasParamClipboard = FALSE; BOOL LLPanelObject::postBuild() @@ -404,10 +403,10 @@ const LLUUID& LLPanelObject::findItemID(const LLUUID& asset_id) LLInventoryModel::INCLUDE_TRASH, asset_id_matches); - if (items.count()) + if (items.size()) { // search for copyable version first - for (S32 i = 0; i < items.count(); i++) + for (U32 i = 0; i < items.size(); i++) { LLInventoryItem* itemp = items[i]; LLPermissions item_permissions = itemp->getPermissions(); @@ -465,10 +464,10 @@ void LLPanelObject::getState( ) return; } - // can move or rotate only linked group with move permissions, or sub-object with move and modify perms - BOOL enable_move = objectp->permMove() && !objectp->isPermanentEnforced() && ((root_objectp == NULL) || !root_objectp->isPermanentEnforced()) && ( (objectp->permModify() && !objectp->isAttachment()) || !gSavedSettings.getBOOL("EditLinkedParts")); - BOOL enable_scale = objectp->permMove() && !objectp->isPermanentEnforced() && ((root_objectp == NULL) || !root_objectp->isPermanentEnforced()) && objectp->permModify(); - BOOL enable_rotate = objectp->permMove() && !objectp->isPermanentEnforced() && ((root_objectp == NULL) || !root_objectp->isPermanentEnforced()) && ( (objectp->permModify() && !objectp->isAttachment()) || !gSavedSettings.getBOOL("EditLinkedParts")); + // can move or rotate only linked group with move permissions + BOOL enable_move = objectp->permMove() && !objectp->isPermanentEnforced() && ((root_objectp == NULL) || !root_objectp->isPermanentEnforced()); + BOOL enable_scale = enable_move && objectp->permModify(); + BOOL enable_rotate = enable_move; S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount(); BOOL single_volume = (LLSelectMgr::getInstance()->selectionAllPCode( LL_PCODE_VOLUME )) @@ -552,6 +551,8 @@ void LLPanelObject::getState( ) mBtnCopySize->setEnabled( enable_scale ); mBtnPasteSize->setEnabled( enable_scale ); mBtnPasteSizeClip->setEnabled( enable_scale ); + mCtrlPosX->setMaxValue(objectp->getRegion()->getWidth()); + mCtrlPosY->setMaxValue(objectp->getRegion()->getWidth()); // Singu TODO: VarRegions, getLength() mCtrlPosZ->setMaxValue(gHippoLimits->getMaxHeight()); mCtrlScaleX->setMaxValue(gHippoLimits->getMaxPrimScale()); mCtrlScaleY->setMaxValue(gHippoLimits->getMaxPrimScale()); @@ -563,9 +564,9 @@ void LLPanelObject::getState( ) LLQuaternion object_rot = objectp->getRotationEdit(); object_rot.getEulerAngles(&(mCurEulerDegrees.mV[VX]), &(mCurEulerDegrees.mV[VY]), &(mCurEulerDegrees.mV[VZ])); mCurEulerDegrees *= RAD_TO_DEG; - mCurEulerDegrees.mV[VX] = fmod(llround(mCurEulerDegrees.mV[VX], OBJECT_ROTATION_PRECISION) + 360.f, 360.f); - mCurEulerDegrees.mV[VY] = fmod(llround(mCurEulerDegrees.mV[VY], OBJECT_ROTATION_PRECISION) + 360.f, 360.f); - mCurEulerDegrees.mV[VZ] = fmod(llround(mCurEulerDegrees.mV[VZ], OBJECT_ROTATION_PRECISION) + 360.f, 360.f); + mCurEulerDegrees.mV[VX] = fmod(ll_round(mCurEulerDegrees.mV[VX], OBJECT_ROTATION_PRECISION) + 360.f, 360.f); + mCurEulerDegrees.mV[VY] = fmod(ll_round(mCurEulerDegrees.mV[VY], OBJECT_ROTATION_PRECISION) + 360.f, 360.f); + mCurEulerDegrees.mV[VZ] = fmod(ll_round(mCurEulerDegrees.mV[VZ], OBJECT_ROTATION_PRECISION) + 360.f, 360.f); if (enable_rotate) { @@ -888,12 +889,12 @@ void LLPanelObject::getState( ) // else { - llinfos << "Unknown path " << (S32) path << " profile " << (S32) profile << " in getState" << llendl; + LL_INFOS() << "Unknown path " << (S32) path << " profile " << (S32) profile << " in getState" << LL_ENDL; selected_item = MI_BOX; } - if (objectp->getParameterEntryInUse(LLNetworkData::PARAMS_SCULPT)) + if (objectp->getSculptParams()) { selected_item = MI_SCULPT; LLFirstUse::useSculptedPrim(); @@ -1396,7 +1397,7 @@ void LLPanelObject::getState( ) LLUUID id; - LLSculptParams *sculpt_params = (LLSculptParams *)objectp->getParameterEntry(LLNetworkData::PARAMS_SCULPT); + const LLSculptParams *sculpt_params = objectp->getSculptParams(); if (sculpt_params) // if we have a legal sculpt param block for this object: @@ -1480,11 +1481,11 @@ void LLPanelObject::sendIsPhysical() LLSelectMgr::getInstance()->selectionUpdatePhysics(value); mIsPhysical = value; - llinfos << "update physics sent" << llendl; + LL_INFOS() << "update physics sent" << LL_ENDL; } else { - llinfos << "update physics not changed" << llendl; + LL_INFOS() << "update physics not changed" << LL_ENDL; } } @@ -1496,11 +1497,11 @@ void LLPanelObject::sendIsTemporary() LLSelectMgr::getInstance()->selectionUpdateTemporary(value); mIsTemporary = value; - llinfos << "update temporary sent" << llendl; + LL_INFOS() << "update temporary sent" << LL_ENDL; } else { - llinfos << "update temporary not changed" << llendl; + LL_INFOS() << "update temporary not changed" << LL_ENDL; } } @@ -1513,11 +1514,11 @@ void LLPanelObject::sendIsPhantom() LLSelectMgr::getInstance()->selectionUpdatePhantom(value); mIsPhantom = value; - llinfos << "update phantom sent" << llendl; + LL_INFOS() << "update phantom sent" << LL_ENDL; } else { - llinfos << "update phantom not changed" << llendl; + LL_INFOS() << "update phantom not changed" << LL_ENDL; } } @@ -1572,13 +1573,13 @@ void LLPanelObject::onCommitParametric( LLUICtrl* ctrl, void* userdata ) if (selected_type == MI_SCULPT) { self->mObject->setParameterEntryInUse(LLNetworkData::PARAMS_SCULPT, TRUE, TRUE); - LLSculptParams *sculpt_params = (LLSculptParams *)self->mObject->getParameterEntry(LLNetworkData::PARAMS_SCULPT); + const LLSculptParams *sculpt_params = self->mObject->getSculptParams(); if (sculpt_params) volume_params.setSculptID(sculpt_params->getSculptTexture(), sculpt_params->getSculptType()); } else { - LLSculptParams *sculpt_params = (LLSculptParams *)self->mObject->getParameterEntry(LLNetworkData::PARAMS_SCULPT); + const LLSculptParams *sculpt_params = self->mObject->getSculptParams(); if (sculpt_params) self->mObject->setParameterEntryInUse(LLNetworkData::PARAMS_SCULPT, FALSE, TRUE); } @@ -1686,8 +1687,8 @@ void LLPanelObject::getVolumeParams(LLVolumeParams& volume_params) // default: - llwarns << "Unknown base type " << selected_type - << " in getVolumeParams()" << llendl; + LL_WARNS() << "Unknown base type " << selected_type + << " in getVolumeParams()" << LL_ENDL; // assume a box selected_type = MI_BOX; profile = LL_PCODE_PROFILE_SQUARE; @@ -1963,9 +1964,9 @@ void LLPanelObject::sendRotation(BOOL btn_down) if (mObject.isNull()) return; LLVector3 new_rot(mCtrlRotX->get(), mCtrlRotY->get(), mCtrlRotZ->get()); - new_rot.mV[VX] = llround(new_rot.mV[VX], OBJECT_ROTATION_PRECISION); - new_rot.mV[VY] = llround(new_rot.mV[VY], OBJECT_ROTATION_PRECISION); - new_rot.mV[VZ] = llround(new_rot.mV[VZ], OBJECT_ROTATION_PRECISION); + new_rot.mV[VX] = ll_round(new_rot.mV[VX], OBJECT_ROTATION_PRECISION); + new_rot.mV[VY] = ll_round(new_rot.mV[VY], OBJECT_ROTATION_PRECISION); + new_rot.mV[VZ] = ll_round(new_rot.mV[VZ], OBJECT_ROTATION_PRECISION); // Note: must compare before conversion to radians LLVector3 delta = new_rot - mCurEulerDegrees; @@ -2037,11 +2038,11 @@ void LLPanelObject::sendScale(BOOL btn_down) } LLSelectMgr::getInstance()->adjustTexturesByScale(TRUE, !dont_stretch_textures); -// llinfos << "scale sent" << llendl; +// LL_INFOS() << "scale sent" << LL_ENDL; } else { -// llinfos << "scale not changed" << llendl; +// LL_INFOS() << "scale not changed" << LL_ENDL; } } @@ -2139,17 +2140,17 @@ void LLPanelObject::sendSculpt() return; LLSculptParams sculpt_params; + LLUUID sculpt_id = LLUUID::null; if (mCtrlSculptTexture) - sculpt_params.setSculptTexture(mCtrlSculptTexture->getImageAssetID()); + sculpt_id = mCtrlSculptTexture->getImageAssetID(); U8 sculpt_type = 0; if (mCtrlSculptType) sculpt_type |= mCtrlSculptType->getCurrentIndex(); - bool enabled = true; - enabled = sculpt_type != LL_SCULPT_TYPE_MESH; + bool enabled = sculpt_type != LL_SCULPT_TYPE_MESH; if (mCtrlSculptMirror) { @@ -2166,7 +2167,7 @@ void LLPanelObject::sendSculpt() if ((mCtrlSculptInvert) && (mCtrlSculptInvert->get())) sculpt_type |= LL_SCULPT_FLAG_INVERT; - sculpt_params.setSculptType(sculpt_type); + sculpt_params.setSculptTexture(sculpt_id, sculpt_type); mObject->setParameterEntry(LLNetworkData::PARAMS_SCULPT, sculpt_params, TRUE); } @@ -2255,47 +2256,6 @@ void LLPanelObject::draw() LLPanel::draw(); } -// virtual -void LLPanelObject::clearCtrls() -{ - LLPanel::clearCtrls(); - - mCheckLock ->set(FALSE); - mCheckLock ->setEnabled( FALSE ); - mCheckPhysics ->set(FALSE); - mCheckPhysics ->setEnabled( FALSE ); - mCheckTemporary ->set(FALSE); - mCheckTemporary ->setEnabled( FALSE ); - mCheckPhantom ->set(FALSE); - mCheckPhantom ->setEnabled( FALSE ); - mComboMaterial ->setEnabled( FALSE ); - mLabelMaterial ->setEnabled( FALSE ); - // Disable text labels - mLabelPosition ->setEnabled( FALSE ); - mLabelSize ->setEnabled( FALSE ); - mLabelRotation ->setEnabled( FALSE ); - mLabelBaseType ->setEnabled( FALSE ); - mLabelCut ->setEnabled( FALSE ); - mLabelHollow ->setEnabled( FALSE ); - mLabelHoleType ->setEnabled( FALSE ); - mLabelTwist ->setEnabled( FALSE ); - mLabelSkew ->setEnabled( FALSE ); - mLabelShear ->setEnabled( FALSE ); - mLabelTaper ->setEnabled( FALSE ); - mLabelRadiusOffset->setEnabled( FALSE ); - mLabelRevolutions->setEnabled( FALSE ); - - childSetVisible("select_single", FALSE); - childSetVisible("edit_object", TRUE); - childSetEnabled("edit_object", FALSE); - - childSetEnabled("scale_hole", FALSE); - childSetEnabled("scale_taper", FALSE); - childSetEnabled("advanced_cut", FALSE); - childSetEnabled("advanced_dimple", FALSE); - childSetVisible("advanced_slice", FALSE); -} - // // Static functions // @@ -2502,16 +2462,16 @@ void LLPanelObject::onCopyParams(void* user_data) LLViewerObject* objp = self->mObject; - mClipboardFlexiParams = objp->getParameterEntryInUse(LLNetworkData::PARAMS_FLEXIBLE) ? static_cast(objp->getParameterEntry(LLNetworkData::PARAMS_FLEXIBLE)) : NULL; - mClipboardLightParams = objp->getParameterEntryInUse(LLNetworkData::PARAMS_LIGHT) ? static_cast(objp->getParameterEntry(LLNetworkData::PARAMS_LIGHT)) : NULL; - mClipboardSculptParams = objp->getParameterEntryInUse(LLNetworkData::PARAMS_SCULPT) ? static_cast(objp->getParameterEntry(LLNetworkData::PARAMS_SCULPT)) : NULL; + mClipboardFlexiParams = objp->getFlexibleObjectData(); + mClipboardLightParams = objp->getLightParams(); + mClipboardSculptParams = objp->getSculptParams(); if (mClipboardSculptParams) { const LLUUID id = mClipboardSculptParams->getSculptTexture(); if (id != LLUUID(SCULPT_DEFAULT_TEXTURE) && !texturePermsCheck(id)) mClipboardSculptParams = NULL; } - mClipboardLightImageParams = objp->getParameterEntryInUse(LLNetworkData::PARAMS_LIGHT_IMAGE) ? static_cast(objp->getParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE)) : NULL; + mClipboardLightImageParams = objp->getLightImageParams(); if (mClipboardLightImageParams && texturePermsCheck(mClipboardLightImageParams->getLightTexture())) { mClipboardLightImageParams = NULL; @@ -2552,13 +2512,13 @@ void LLPanelObject::onPasteParams(void* user_data) void LLPanelObject::onLinkObj(void* user_data) { - llinfos << "Attempting link." << llendl; + LL_INFOS() << "Attempting link." << LL_ENDL; LLSelectMgr::getInstance()->linkObjects(); } void LLPanelObject::onUnlinkObj(void* user_data) { - llinfos << "Attempting unlink." << llendl; + LL_INFOS() << "Attempting unlink." << LL_ENDL; LLSelectMgr::getInstance()->unlinkObjects(); } @@ -2568,7 +2528,7 @@ void LLPanelObject::onPastePos(void* user_data) LLPanelObject* self = (LLPanelObject*) user_data; LLCalc* calcp = LLCalc::getInstance(); - float region_width = LLWorld::getInstance()->getRegionWidthInMeters(); + float region_width = gAgent.getRegion()->getWidth(); mClipboardPos.mV[VX] = llclamp( mClipboardPos.mV[VX], -3.5f, region_width); mClipboardPos.mV[VY] = llclamp( mClipboardPos.mV[VY], -3.5f, region_width); mClipboardPos.mV[VZ] = llclamp( mClipboardPos.mV[VZ], -3.5f, gHippoLimits->getMaxHeight()); @@ -2648,7 +2608,9 @@ void LLPanelObject::onPastePosClip(void* user_data) std::string stringVec = wstring_to_utf8str(temp_string); if(!getvectorfromclip(stringVec, &mClipboardPos)) return; - float region_width = LLWorld::getInstance()->getRegionWidthInMeters(); + const LLViewerRegion* region(self->mObject ? self->mObject->getRegion() : NULL); + if (!region) return; + F32 region_width = region->getWidth(); mClipboardPos.mV[VX] = llclamp(mClipboardPos.mV[VX], -3.5f, region_width); mClipboardPos.mV[VY] = llclamp(mClipboardPos.mV[VY], -3.5f, region_width); mClipboardPos.mV[VZ] = llclamp(mClipboardPos.mV[VZ], -3.5f, gHippoLimits->getMaxHeight()); diff --git a/indra/newview/llpanelobject.h b/indra/newview/llpanelobject.h index 675a93053d..18877663c3 100644 --- a/indra/newview/llpanelobject.h +++ b/indra/newview/llpanelobject.h @@ -63,7 +63,6 @@ class LLPanelObject : public LLPanel virtual BOOL postBuild(); virtual void draw(); - virtual void clearCtrls(); void refresh(); @@ -123,10 +122,10 @@ class LLPanelObject : public LLPanel static LLVector3 mClipboardSize; static LLVector3 mClipboardRot; static LLVolumeParams mClipboardVolumeParams; - static LLFlexibleObjectData* mClipboardFlexiParams; - static LLLightParams* mClipboardLightParams; - static LLSculptParams* mClipboardSculptParams; - static LLLightImageParams* mClipboardLightImageParams; + static const LLFlexibleObjectData* mClipboardFlexiParams; + static const LLLightParams* mClipboardLightParams; + static const LLSculptParams* mClipboardSculptParams; + static const LLLightImageParams* mClipboardLightImageParams; static BOOL hasParamClipboard; S32 mComboMaterialItemCount; diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp index e9f46c0b4c..09a6a77cdc 100644 --- a/indra/newview/llpanelobjectinventory.cpp +++ b/indra/newview/llpanelobjectinventory.cpp @@ -40,6 +40,7 @@ #include "roles_constants.h" #include "llagent.h" +#include "llavataractions.h" #include "llcallbacklist.h" #include "llfloaterbuycontents.h" #include "llfloaterbuycurrency.h" @@ -126,20 +127,20 @@ class LLTaskInvFVBridge : public LLFolderViewEventListener virtual BOOL isItemMovable() const; virtual BOOL isItemRemovable() const; virtual BOOL removeItem(); - virtual void removeBatch(LLDynamicArray& batch); + virtual void removeBatch(std::vector& batch); virtual void move(LLFolderViewEventListener* parent_listener); virtual BOOL isItemCopyable() const; virtual BOOL copyToClipboard() const; - virtual void cutToClipboard(); + virtual BOOL cutToClipboard(); virtual BOOL isClipboardPasteable() const; virtual void pasteFromClipboard(bool only_copies = false); virtual void pasteLinkFromClipboard(); virtual void buildContextMenu(LLMenuGL& menu, U32 flags); virtual void performAction(LLInventoryModel* model, std::string action); virtual BOOL isUpToDate() const { return TRUE; } - virtual BOOL hasChildren() const { return FALSE; } - virtual LLInventoryType::EType getInventoryType() const { return LLInventoryType::IT_NONE; } - virtual LLWearableType::EType getWearableType() const { return LLWearableType::WT_NONE; } + virtual bool hasChildren() const { return FALSE; } + virtual LLInventoryType::EType getInventoryType() const { return LLInventoryType::EType::IT_NONE; } + virtual LLWearableType::EType getWearableType() const { return LLWearableType::EType::WT_NONE; } // LLDragAndDropBridge functionality virtual BOOL startDrag(EDragAndDropType* type, LLUUID* id) const; @@ -160,7 +161,7 @@ LLTaskInvFVBridge::LLTaskInvFVBridge( mPanel(panel), mFlags(flags), mAssetType(LLAssetType::AT_NONE), - mInventoryType(LLInventoryType::IT_NONE) + mInventoryType(LLInventoryType::EType::IT_NONE) { const LLInventoryItem *item = findItem(); if (item) @@ -203,27 +204,11 @@ void LLTaskInvFVBridge::showProperties() } } -struct LLBuyInvItemData -{ - LLUUID mTaskID; - LLUUID mItemID; - LLAssetType::EType mType; - - LLBuyInvItemData(const LLUUID& task, - const LLUUID& item, - LLAssetType::EType type) : - mTaskID(task), mItemID(item), mType(type) - {} -}; - void LLTaskInvFVBridge::buyItem() { - llinfos << "LLTaskInvFVBridge::buyItem()" << llendl; + LL_INFOS() << "LLTaskInvFVBridge::buyItem()" << LL_ENDL; LLInventoryItem* item = findItem(); if(!item || !item->getSaleInfo().isForSale()) return; - LLBuyInvItemData* inv = new LLBuyInvItemData(mPanel->getTaskUUID(), - mUUID, - item->getType()); const LLSaleInfo& sale_info = item->getSaleInfo(); const LLPermissions& perm = item->getPermissions(); @@ -233,8 +218,7 @@ void LLTaskInvFVBridge::buyItem() if( ( obj = gObjectList.findObject( mPanel->getTaskUUID() ) ) && obj->isAttachment() ) { LLNotificationsUtil::add("Cannot_Purchase_an_Attachment"); - llinfos << "Attempt to purchase an attachment" << llendl; - delete inv; + LL_INFOS() << "Attempt to purchase an attachment" << LL_ENDL; } else { @@ -265,9 +249,9 @@ void LLTaskInvFVBridge::buyItem() } LLSD payload; - payload["task_id"] = inv->mTaskID; - payload["item_id"] = inv->mItemID; - payload["type"] = inv->mType; + payload["task_id"] = mPanel->getTaskUUID(); + payload["item_id"] = mUUID; + payload["type"] = item->getType(); LLNotificationsUtil::add(alertdesc, args, payload, LLTaskInvFVBridge::commitBuyItem); } } @@ -369,7 +353,7 @@ LLUIImagePtr LLTaskInvFVBridge::getIcon() const void LLTaskInvFVBridge::openItem() { // no-op. - lldebugs << "LLTaskInvFVBridge::openItem()" << llendl; + LL_DEBUGS() << "LLTaskInvFVBridge::openItem()" << LL_ENDL; } void LLTaskInvFVBridge::previewItem() @@ -495,12 +479,9 @@ bool remove_task_inventory_callback(const LLSD& notification, const LLSD& respon if(option == 0 && object) { // yes - LLSD::array_const_iterator list_end = notification["payload"]["inventory_ids"].endArray(); - for (LLSD::array_const_iterator list_it = notification["payload"]["inventory_ids"].beginArray(); - list_it != list_end; - ++list_it) + for (auto const& entry : notification["payload"]["inventory_ids"].array()) { - object->removeInventory(list_it->asUUID()); + object->removeInventory(entry.asUUID()); } // refresh the UI. @@ -539,7 +520,7 @@ BOOL LLTaskInvFVBridge::removeItem() return FALSE; } -void LLTaskInvFVBridge::removeBatch(LLDynamicArray& batch) +void LLTaskInvFVBridge::removeBatch(std::vector& batch) { if (!mPanel) { @@ -596,8 +577,9 @@ BOOL LLTaskInvFVBridge::copyToClipboard() const return FALSE; } -void LLTaskInvFVBridge::cutToClipboard() +BOOL LLTaskInvFVBridge::cutToClipboard() { + return FALSE; } BOOL LLTaskInvFVBridge::isClipboardPasteable() const @@ -605,7 +587,7 @@ BOOL LLTaskInvFVBridge::isClipboardPasteable() const return FALSE; } -void LLTaskInvFVBridge::pasteFromClipboard(bool only_copies) +void LLTaskInvFVBridge::pasteFromClipboard(bool) { } @@ -615,7 +597,7 @@ void LLTaskInvFVBridge::pasteLinkFromClipboard() BOOL LLTaskInvFVBridge::startDrag(EDragAndDropType* type, LLUUID* id) const { - //llinfos << "LLTaskInvFVBridge::startDrag()" << llendl; + //LL_INFOS() << "LLTaskInvFVBridge::startDrag()" << LL_ENDL; if(mPanel) { LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); @@ -662,28 +644,38 @@ BOOL LLTaskInvFVBridge::dragOrDrop(MASK mask, BOOL drop, EDragAndDropType cargo_type, void* cargo_data) { - //llinfos << "LLTaskInvFVBridge::dragOrDrop()" << llendl; + //LL_INFOS() << "LLTaskInvFVBridge::dragOrDrop()" << LL_ENDL; return FALSE; } -//void LLTaskInvFVBridge::dropped() -//{ -// llwarns << "LLTaskInvFVBridge::dropped() - not implemented" << llendl; -//} +void pack_script_message(LLMessageSystem*, const LLInventoryItem*, const LLViewerObject*); + +void reset_script(const LLInventoryItem* item, const LLViewerObject* obj) +{ + if (!item || !obj) return; + gMessageSystem->newMessageFast(_PREHASH_ScriptReset); + pack_script_message(gMessageSystem, item, obj); + gMessageSystem->sendReliable(obj->getRegion()->getHost()); +} void set_script_running(bool running, const LLInventoryItem* item, const LLViewerObject* obj) { if (!item || !obj) return; LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_SetScriptRunning); + pack_script_message(msg, item, obj); + msg->addBOOLFast(_PREHASH_Running, running); + msg->sendReliable(obj->getRegion()->getHost()); +} + +void pack_script_message(LLMessageSystem* msg, const LLInventoryItem* item, const LLViewerObject* obj) +{ msg->nextBlockFast(_PREHASH_AgentData); msg->addUUIDFast(_PREHASH_AgentID, gAgentID); msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID); msg->nextBlockFast(_PREHASH_Script); msg->addUUIDFast(_PREHASH_ObjectID, obj->getID()); msg->addUUIDFast(_PREHASH_ItemID, item->getUUID()); - msg->addBOOLFast(_PREHASH_Running, running); - msg->sendReliable(obj->getRegion()->getHost()); } // virtual @@ -695,7 +687,7 @@ void LLTaskInvFVBridge::performAction(LLInventoryModel* model, std::string actio S32 price = getPrice(); if (-1 == price) { - llwarns << "label_buy_task_bridged_item: Invalid price" << llendl; + LL_WARNS() << "label_buy_task_bridged_item: Invalid price" << LL_ENDL; } else { @@ -719,6 +711,10 @@ void LLTaskInvFVBridge::performAction(LLInventoryModel* model, std::string actio { showProperties(); } + else if (action == "reset_script") + { + reset_script(findItem(), gObjectList.findObject(mPanel->getTaskUUID())); + } else if (action == "start_script") { set_script_running(true, findItem(), gObjectList.findObject(mPanel->getTaskUUID())); @@ -741,7 +737,7 @@ void LLTaskInvFVBridge::buildContextMenu(LLMenuGL& menu, U32 flags) return; } - if(gAgent.allowOperation(PERM_OWNER, item->getPermissions(), + if(!gAgent.allowOperation(PERM_OWNER, item->getPermissions(), GP_OBJECT_MANIPULATE) && item->getSaleInfo().isForSale()) { @@ -752,7 +748,7 @@ void LLTaskInvFVBridge::buildContextMenu(LLMenuGL& menu, U32 flags) S32 price = getPrice(); if (-1 == price) { - llwarns << "label_buy_task_bridged_item: Invalid price" << llendl; + LL_WARNS() << "label_buy_task_bridged_item: Invalid price" << LL_ENDL; } else { @@ -777,11 +773,13 @@ void LLTaskInvFVBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { if (LLAssetType::AT_LSL_TEXT == item->getType()) { + items.push_back(std::string("Task Reset")); items.push_back(std::string("Task Set Running")); items.push_back(std::string("Task Set Not Running")); const LLViewerObject* obj = gObjectList.findObject(mPanel->getTaskUUID()); if (!obj || !(obj->permModify() || obj->permYouOwner())) { + disabled_items.push_back(std::string("Task Reset")); disabled_items.push_back(std::string("Task Set Running")); disabled_items.push_back(std::string("Task Set Not Running")); } @@ -851,7 +849,7 @@ class LLTaskCategoryBridge : public LLTaskInvFVBridge virtual BOOL renameItem(const std::string& new_name); virtual BOOL isItemRemovable() const; virtual void buildContextMenu(LLMenuGL& menu, U32 flags); - virtual BOOL hasChildren() const; + virtual bool hasChildren() const; virtual BOOL startDrag(EDragAndDropType* type, LLUUID* id) const; virtual BOOL dragOrDrop(MASK mask, BOOL drop, EDragAndDropType cargo_type, @@ -901,7 +899,7 @@ void LLTaskCategoryBridge::buildContextMenu(LLMenuGL& menu, U32 flags) hide_context_entries(menu, items, disabled_items); } -BOOL LLTaskCategoryBridge::hasChildren() const +bool LLTaskCategoryBridge::hasChildren() const { // return TRUE if we have or do know know if we have children. // *FIX: For now, return FALSE - we will know for sure soon enough. @@ -914,7 +912,7 @@ void LLTaskCategoryBridge::openItem() BOOL LLTaskCategoryBridge::startDrag(EDragAndDropType* type, LLUUID* id) const { - //llinfos << "LLTaskInvFVBridge::startDrag()" << llendl; + //LL_INFOS() << "LLTaskInvFVBridge::startDrag()" << LL_ENDL; if(mPanel && mUUID.notNull()) { LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); @@ -936,7 +934,7 @@ BOOL LLTaskCategoryBridge::dragOrDrop(MASK mask, BOOL drop, EDragAndDropType cargo_type, void* cargo_data) { - //llinfos << "LLTaskCategoryBridge::dragOrDrop()" << llendl; + //LL_INFOS() << "LLTaskCategoryBridge::dragOrDrop()" << LL_ENDL; BOOL accept = FALSE; LLViewerObject* object = gObjectList.findObject(mPanel->getTaskUUID()); if(object) @@ -958,16 +956,6 @@ BOOL LLTaskCategoryBridge::dragOrDrop(MASK mask, BOOL drop, case DAD_CALLINGCARD: case DAD_MESH: accept = LLToolDragAndDrop::isInventoryDropAcceptable(object, (LLViewerInventoryItem*)cargo_data); - // testzone - //if(LLToolDragAndDrop::isInventoryDropAcceptable( - // object, (LLViewerInventoryItem*)cargo_data) - /*if(object->permModify() - // - && (LLToolDragAndDrop::SOURCE_WORLD != LLToolDragAndDrop::getInstance()->getSource()) - && (LLToolDragAndDrop::SOURCE_NOTECARD != LLToolDragAndDrop::getInstance()->getSource())) - { - accept = TRUE; - }*/ if(accept && drop) { LLToolDragAndDrop::dropInventory(object, @@ -1033,7 +1021,7 @@ void LLTaskTextureBridge::openItem() } // [/RLVa:KB] - llinfos << "LLTaskTextureBridge::openItem()" << llendl; + LL_INFOS() << "LLTaskTextureBridge::openItem()" << LL_ENDL; if(!LLPreview::show(mUUID)) { // There isn't one, so make a new preview @@ -1127,7 +1115,7 @@ void LLTaskSoundBridge::buildContextMenu(LLMenuGL& menu, U32 flags) S32 price = getPrice(); if (-1 == price) { - llwarns << "label_buy_task_bridged_item: Invalid price" << llendl; + LL_WARNS() << "label_buy_task_bridged_item: Invalid price" << LL_ENDL; } else { @@ -1150,7 +1138,6 @@ void LLTaskSoundBridge::buildContextMenu(LLMenuGL& menu, U32 flags) } else if (canOpenItem()) { - //items.push_back(std::string("Task Open")); if (!isItemCopyable()) { disabled_items.push_back(std::string("Task Open")); @@ -1216,6 +1203,7 @@ BOOL LLTaskCallingCardBridge::renameItem(const std::string& new_name) return FALSE; } + ///---------------------------------------------------------------------------- /// Class LLTaskScriptBridge ///---------------------------------------------------------------------------- @@ -1249,7 +1237,7 @@ class LLTaskLSLBridge : public LLTaskScriptBridge void LLTaskLSLBridge::openItem() { - llinfos << "LLTaskLSLBridge::openItem() " << mUUID << llendl; + LL_INFOS() << "LLTaskLSLBridge::openItem() " << mUUID << LL_ENDL; if(LLLiveLSLEditor::show(mUUID)) { return; @@ -1549,7 +1537,7 @@ LLTaskInvFVBridge* LLTaskInvFVBridge::createObjectBridge(LLPanelObjectInventory* break; case LLAssetType::AT_SCRIPT: // OLD SCRIPTS DEPRECATED - JC - llwarns << "Old script" << llendl; + LL_WARNS() << "Old script" << LL_ENDL; //new_bridge = new LLTaskOldScriptBridge(panel, // object_id, // object_name); @@ -1594,8 +1582,8 @@ LLTaskInvFVBridge* LLTaskInvFVBridge::createObjectBridge(LLPanelObjectInventory* break; break; default: - llinfos << "Unhandled inventory type (llassetstorage.h): " - << (S32)type << llendl; + LL_INFOS() << "Unhandled inventory type (llassetstorage.h): " + << (S32)type << LL_ENDL; break; } return new_bridge; @@ -1626,7 +1614,7 @@ LLPanelObjectInventory::~LLPanelObjectInventory() { if (!gIdleCallbacks.deleteFunction(idle, this)) { - llwarns << "LLPanelObjectInventory::~LLPanelObjectInventory() failed to delete callback" << llendl; + LL_WARNS() << "LLPanelObjectInventory::~LLPanelObjectInventory() failed to delete callback" << LL_ENDL; } } @@ -1643,7 +1631,7 @@ void LLPanelObjectInventory::clearContents() if( mScroller ) { // removes mFolders - removeChild( mScroller ); + removeChild( mScroller ); //*TODO: Really shouldn't do this during draw()/refresh() mScroller->die(); mScroller = NULL; mFolders = NULL; @@ -1660,7 +1648,7 @@ void LLPanelObjectInventory::reset() LLRect dummy_rect(0, 1, 1, 0); mFolders = new LLFolderView(std::string("task inventory"), dummy_rect, getTaskUUID(), this, LLTaskInvFVBridge::createObjectBridge(this, NULL)); // this ensures that we never say "searching..." or "no items found" - mFolders->getFilter()->setShowFolderState(LLInventoryFilter::SHOW_ALL_FOLDERS); + mFolders->getFilter().setShowFolderState(LLInventoryFilter::SHOW_ALL_FOLDERS); LLRect scroller_rect(0, getRect().getHeight(), getRect().getWidth(), 0); mScroller = new LLScrollContainer(std::string("task inventory scroller"), scroller_rect, mFolders ); @@ -1677,9 +1665,9 @@ void LLPanelObjectInventory::inventoryChanged(LLViewerObject* object, { if(!object) return; - //llinfos << "invetnory arrived: \n" + //LL_INFOS() << "invetnory arrived: \n" // << " panel UUID: " << panel->mTaskUUID << "\n" - // << " task UUID: " << object->mID << llendl; + // << " task UUID: " << object->mID << LL_ENDL; if(mTaskUUID == object->mID) { mInventoryNeedsUpdate = TRUE; @@ -1692,7 +1680,7 @@ void LLPanelObjectInventory::inventoryChanged(LLViewerObject* object, // temporary object because we cannot iterate through the // object inventory twice... A pox on stateful iteration! LLFloaterProperties* floater = NULL; - LLDynamicArray refresh; + std::vector refresh; LLInventoryObject::object_list_t::const_iterator it = inventory->begin(); LLInventoryObject::object_list_t::const_iterator end = inventory->end(); @@ -1702,52 +1690,52 @@ void LLPanelObjectInventory::inventoryChanged(LLViewerObject* object, object->getID()); if(floater) { - refresh.put(floater); + refresh.push_back(floater); } } - S32 count = refresh.count(); + S32 count = refresh.size(); for(S32 i = 0; i < count; ++i) { - refresh.get(i)->refresh(); + refresh.at(i)->refresh(); } } } void LLPanelObjectInventory::updateInventory() { - //llinfos << "inventory arrived: \n" + //LL_INFOS() << "inventory arrived: \n" // << " panel UUID: " << panel->mTaskUUID << "\n" - // << " task UUID: " << object->mID << llendl; + // << " task UUID: " << object->mID << LL_ENDL; // We're still interested in this task's inventory. - std::set selected_items; + uuid_set_t selected_items; BOOL inventory_has_focus = FALSE; - if (mHaveInventory) + if (mHaveInventory && mFolders) { selected_items = mFolders->getSelectionList(); inventory_has_focus = gFocusMgr.childHasKeyboardFocus(mFolders); } - reset(); - LLViewerObject* objectp = gObjectList.findObject(mTaskUUID); if (objectp) { LLInventoryObject* inventory_root = objectp->getInventoryRoot(); LLInventoryObject::object_list_t contents; objectp->getInventoryContents(contents); + if (inventory_root) { - createFolderViews(inventory_root, contents); - mHaveInventory = TRUE; + reset(); mIsInventoryEmpty = FALSE; + createFolderViews(inventory_root, contents); mFolders->setEnabled(TRUE); } else { // TODO: create an empty inventory mIsInventoryEmpty = TRUE; - mHaveInventory = TRUE; } + + mHaveInventory = TRUE; } else { @@ -1757,11 +1745,11 @@ void LLPanelObjectInventory::updateInventory() } // restore previous selection - std::set::iterator selection_it; - BOOL first_item = TRUE; - for (selection_it = selected_items.begin(); selection_it != selected_items.end(); ++selection_it) + bool first_item = true; + for (const auto id : selected_items) { - LLFolderViewItem* selected_item = mFolders->getItemByID(*selection_it); + LLFolderViewItem* selected_item = mFolders->getItemByID(id); + if (selected_item) { //HACK: "set" first item then "change" each other one to get keyboard focus right @@ -1777,8 +1765,12 @@ void LLPanelObjectInventory::updateInventory() } } - mFolders->requestArrange(); + if (mFolders) + { + mFolders->requestArrange(); + } mInventoryNeedsUpdate = FALSE; + // Edit menu handler is set in onFocusReceived } // *FIX: This is currently a very expensive operation, because we have @@ -1800,7 +1792,7 @@ void LLPanelObjectInventory::createFolderViews(LLInventoryObject* inventory_root LLFolderViewFolder* new_folder = NULL; new_folder = new LLFolderViewFolder(inventory_root->getName(), bridge->getIcon(), - bridge->getOpenIcon(), + bridge->getIconOpen(), NULL, mFolders, bridge); @@ -1818,7 +1810,7 @@ void LLPanelObjectInventory::createViewsForCategory(LLInventoryObject::object_li LLFolderViewFolder* folder) { // Find all in the first pass - LLDynamicArray child_categories; + std::vector child_categories; LLTaskInvFVBridge* bridge; LLFolderViewItem* view; @@ -1839,18 +1831,18 @@ void LLPanelObjectInventory::createViewsForCategory(LLInventoryObject::object_li { view = new LLFolderViewFolder(obj->getName(), bridge->getIcon(), - bridge->getOpenIcon(), + bridge->getIconOpen(), NULL, mFolders, bridge); - child_categories.put(new obj_folder_pair(obj, + child_categories.push_back(new obj_folder_pair(obj, (LLFolderViewFolder*)view)); } else { view = new LLFolderViewItem(obj->getName(), bridge->getIcon(), - bridge->getOpenIcon(), + bridge->getIconOpen(), NULL, bridge->getCreationDate(), mFolders, @@ -1861,7 +1853,7 @@ void LLPanelObjectInventory::createViewsForCategory(LLInventoryObject::object_li } // now, for each category, do the second pass - for(S32 i = 0; i < child_categories.count(); i++) + for(U32 i = 0; i < child_categories.size(); i++) { createViewsForCategory(inventory, child_categories[i]->first, child_categories[i]->second ); @@ -1871,7 +1863,7 @@ void LLPanelObjectInventory::createViewsForCategory(LLInventoryObject::object_li void LLPanelObjectInventory::refresh() { - //llinfos << "LLPanelObjectInventory::refresh()" << llendl; + //LL_INFOS() << "LLPanelObjectInventory::refresh()" << LL_ENDL; BOOL has_inventory = FALSE; const BOOL non_root_ok = TRUE; LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(NULL, non_root_ok); @@ -1920,11 +1912,16 @@ void LLPanelObjectInventory::refresh() } if(!has_inventory) { - mTaskUUID = LLUUID::null; - removeVOInventoryListener(); - clearContents(); + clearInventoryTask(); } - //llinfos << "LLPanelObjectInventory::refresh() " << mTaskUUID << llendl; + //LL_INFOS() << "LLPanelObjectInventory::refresh() " << mTaskUUID << LL_ENDL; +} + +void LLPanelObjectInventory::clearInventoryTask() +{ + mTaskUUID = LLUUID::null; + removeVOInventoryListener(); + clearContents(); } void LLPanelObjectInventory::removeSelectedItem() @@ -2011,7 +2008,6 @@ void LLPanelObjectInventory::idle(void* user_data) { LLPanelObjectInventory* self = (LLPanelObjectInventory*)user_data; - if (self->mInventoryNeedsUpdate) { self->updateInventory(); diff --git a/indra/newview/llpanelobjectinventory.h b/indra/newview/llpanelobjectinventory.h index 736900c76a..e43c1b37fa 100644 --- a/indra/newview/llpanelobjectinventory.h +++ b/indra/newview/llpanelobjectinventory.h @@ -52,6 +52,7 @@ class LLPanelObjectInventory : public LLPanel, public LLVOInventoryListener void refresh(); const LLUUID& getTaskUUID() { return mTaskUUID;} + void clearInventoryTask(); void removeSelectedItem(); void startRenamingSelectedItem(); @@ -77,7 +78,6 @@ class LLPanelObjectInventory : public LLPanel, public LLVOInventoryListener void createViewsForCategory(LLInventoryObject::object_list_t* inventory, LLInventoryObject* parent, LLFolderViewFolder* folder); - void clearContents(); private: diff --git a/indra/newview/llpanelpermissions.cpp b/indra/newview/llpanelpermissions.cpp index ad33397e35..9d82fb8d45 100644 --- a/indra/newview/llpanelpermissions.cpp +++ b/indra/newview/llpanelpermissions.cpp @@ -69,10 +69,6 @@ -// [RLVa:KB] -#include "rlvhandler.h" -// [/RLVa:KB] - // base and own must have EXPORT, next owner must be UNRESTRICTED bool can_set_export(const U32& base, const U32& own, const U32& next) { @@ -92,7 +88,7 @@ bool is_asset_exportable(const LLUUID& asset_id) LLAssetIDMatches asset_id_matches(asset_id); gInventory.collectDescendentsIf(LLUUID::null, cats, items, true, asset_id_matches, false); - for (int i = 0; i < items.count(); ++i) + for (U32 i = 0; i < items.size(); ++i) { if (perms_allow_export(items[i]->getPermissions())) return true; } @@ -117,13 +113,7 @@ BOOL LLPanelPermissions::postBuild() childSetCommitCallback("Object Description",LLPanelPermissions::onCommitDesc,this); getChild("Object Description")->setPrevalidate(&LLLineEditor::prevalidatePrintableNotPipe); - - getChild("button owner profile")->setCommitCallback(boost::bind(&LLPanelPermissions::onClickOwner,this)); - getChild("button last owner profile")->setCommitCallback(boost::bind(&LLPanelPermissions::onClickLastOwner,this)); - getChild("button creator profile")->setCommitCallback(boost::bind(&LLPanelPermissions::onClickCreator,this)); - getChild("button set group")->setCommitCallback(boost::bind(&LLPanelPermissions::onClickGroup,this)); - getChild("button open group")->setCommitCallback(boost::bind(LLPanelPermissions::onClickOpenGroup)); childSetCommitCallback("checkbox share with group",LLPanelPermissions::onCommitGroupShare,this); @@ -182,34 +172,46 @@ void LLPanelPermissions::disableAll() getChild("pathfinding_attributes_value")->setValue(LLStringUtil::null); getChildView("Creator:")->setEnabled(FALSE); - getChild("Creator Name")->setValue(LLStringUtil::null); - getChildView("Creator Name")->setEnabled(FALSE); - getChildView("button creator profile")->setEnabled(FALSE); + if (auto view = getChildView("Creator Name")) + { + view->setValue(LLUUID::null); + view->setEnabled(FALSE); + } getChildView("Owner:")->setEnabled(FALSE); - getChild("Owner Name")->setValue(LLStringUtil::null); - getChildView("Owner Name")->setEnabled(FALSE); - getChildView("button owner profile")->setEnabled(FALSE); + if (auto view = getChildView("Owner Name")) + { + view->setValue(LLUUID::null); + view->setEnabled(FALSE); + } getChildView("Last Owner:")->setEnabled(FALSE); - getChild("Last Owner Name")->setValue(LLStringUtil::null); - getChildView("Last Owner Name")->setEnabled(FALSE); - getChildView("button last owner profile")->setEnabled(FALSE); - + if (auto view = getChildView("Last Owner Name")) + { + view->setValue(LLUUID::null); + view->setEnabled(FALSE); + } + getChildView("Group:")->setEnabled(FALSE); - getChild("Group Name Proxy")->setValue(LLStringUtil::null); - getChildView("Group Name Proxy")->setEnabled(FALSE); + if (mLabelGroupName) + { + mLabelGroupName->setNameID(LLUUID::null, LFIDBearer::GROUP); + mLabelGroupName->setEnabled(FALSE); + } getChildView("button set group")->setEnabled(FALSE); - getChildView("button open group")->setEnabled(FALSE); - getChild("Object Name")->setValue(LLStringUtil::null); - getChildView("Object Name")->setEnabled(FALSE); + LLLineEditor* ed = getChild("Object Name"); + ed->setValue(LLStringUtil::null); + ed->setEnabled(FALSE); + ed->setLabel(LLStringUtil::null); getChildView("Name:")->setEnabled(FALSE); //getChild("Group Name")->setValue(LLStringUtil::null); //getChildView("Group Name")->setEnabled(FALSE); getChildView("Description:")->setEnabled(FALSE); - getChild("Object Description")->setValue(LLStringUtil::null); - getChildView("Object Description")->setEnabled(FALSE); + ed = getChild("Object Description"); + ed->setEnabled(FALSE); + ed->setValue(LLStringUtil::null); + ed->setLabel(LLStringUtil::null); getChildView("Permissions:")->setEnabled(FALSE); @@ -325,7 +327,7 @@ void LLPanelPermissions::refresh() const LLFocusableElement* keyboard_focus_view = gFocusMgr.getKeyboardFocus(); S32 string_index = 0; - std::string MODIFY_INFO_STRINGS[] = + static std::string MODIFY_INFO_STRINGS[] = { getString("text modify info 1"), getString("text modify info 2"), @@ -381,18 +383,6 @@ void LLPanelPermissions::refresh() // Update creator text field getChildView("Creator:")->setEnabled(TRUE); -// [RLVa:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a - BOOL creators_identical = FALSE; -// [/RLVa:KB] - std::string creator_name; -// [RLVa:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a - creators_identical = LLSelectMgr::getInstance()->selectGetCreator(mCreatorID, creator_name); -// [/RLVa:KB] -// LLSelectMgr::getInstance()->selectGetCreator(mCreatorID, creator_name); - -// getChild("Creator Name")->setValue(creator_name); -// getChildView("Creator Name")->setEnabled(TRUE); -// [RLVa:KB] - Moved further down to avoid an annoying flicker when the text is set twice in a row // Update owner text field getChildView("Owner:")->setEnabled(TRUE); @@ -400,91 +390,62 @@ void LLPanelPermissions::refresh() // Update last owner text field getChildView("Last Owner:")->setEnabled(TRUE); - std::string owner_name; - const BOOL owners_identical = LLSelectMgr::getInstance()->selectGetOwner(mOwnerID, owner_name); - -// llinfos << "owners_identical " << (owners_identical ? "TRUE": "FALSE") << llendl; - std::string last_owner_name; - LLSelectMgr::getInstance()->selectGetLastOwner(mLastOwnerID, last_owner_name); - - if (mOwnerID.isNull()) + static const auto none_str = LLTrans::getString("GroupNameNone"); + std::string owner_app_link(none_str); + if (auto view = getChild("Creator Name")) { - if(LLSelectMgr::getInstance()->selectIsGroupOwned()) + if (LLSelectMgr::getInstance()->selectGetCreator(mCreatorID, owner_app_link)) { - // Group owned already displayed by selectGetOwner + view->setValue(mCreatorID); } else { - // Display last owner if public - std::string last_owner_name; - LLSelectMgr::getInstance()->selectGetLastOwner(mLastOwnerID, last_owner_name); - - // It should never happen that the last owner is null and the owner - // is null, but it seems to be a bug in the simulator right now. JC - if (!mLastOwnerID.isNull() && !last_owner_name.empty()) - { - owner_name.append(", last "); - owner_name.append( last_owner_name ); - } + view->setValue(LLUUID::null); + view->setText(owner_app_link); } + view->setEnabled(true); } -// getChild("Owner Name")->setValue(owner_name); -// getChildView("Owner Name")->setEnabled(TRUE); -// [RLVa:KB] - Moved further down to avoid an annoying flicker when the text is set twice in a row - -// [RLVa:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a - bool fRlvEnableOwner = true; - bool fRlvEnableCreator = true; - bool fRlvEnableLastOwner = true; - if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) + + owner_app_link = none_str; + const BOOL owners_identical = LLSelectMgr::getInstance()->selectGetOwner(mOwnerID, owner_app_link); + if (auto view = getChild("Owner Name")) { - // Only anonymize the creator if all of the selection was created by the same avie who's also the owner or they're a nearby avie - if ( (creators_identical) && (mCreatorID != gAgent.getID()) && ((mCreatorID == mOwnerID) || (RlvUtil::isNearbyAgent(mCreatorID))) ) + if (owners_identical) { - creator_name = RlvStrings::getAnonym(creator_name); - fRlvEnableOwner = false; + view->setValue(mOwnerID); } - - // Only anonymize the owner name if all of the selection is owned by the same avie and isn't group owned - if ( (owners_identical) && (!LLSelectMgr::getInstance()->selectIsGroupOwned()) && (mOwnerID != gAgent.getID()) ) + else { - owner_name = RlvStrings::getAnonym(owner_name); - fRlvEnableCreator = false; + view->setValue(LLUUID::null); + view->setText(owner_app_link); } + view->setEnabled(true); + } - if (RlvUtil::isNearbyAgent(mLastOwnerID)) + if (auto view = getChild("Last Owner Name")) + { + owner_app_link = none_str; + if (LLSelectMgr::getInstance()->selectGetLastOwner(mLastOwnerID, owner_app_link)) + { + view->setValue(mLastOwnerID); + } + else { - creator_name = RlvStrings::getAnonym(creator_name); - fRlvEnableLastOwner = false; + view->setValue(LLUUID::null); + view->setText(owner_app_link); } + view->setEnabled(true); } -// [/RLVa:KB] - getChild("Creator Name")->setValue(creator_name); - getChildView("Creator Name")->setEnabled(TRUE); - - getChild("Owner Name")->setValue(owner_name); - getChildView("Owner Name")->setEnabled(TRUE); -// childSetEnabled("button owner profile",owners_identical && (mOwnerID.notNull() || LLSelectMgr::getInstance()->selectIsGroupOwned())); -// getChildView("button last owner profile")->setEnabled(owners_identical && mLastOwnerID.notNull()); -// [RLVa:KB] - Checked: 2009-07-08 (RLVa-1.0.0e) - getChildView("button owner profile")->setEnabled(fRlvEnableOwner && owners_identical && (mOwnerID.notNull() || LLSelectMgr::getInstance()->selectIsGroupOwned())); - getChildView("button creator profile")->setEnabled(fRlvEnableCreator && creators_identical && mCreatorID.notNull()); - getChildView("button last owner profile")->setEnabled(fRlvEnableLastOwner && owners_identical && mLastOwnerID.notNull()); -// [/RLVa:KB] - - getChild("Last Owner Name")->setValue(last_owner_name); - getChildView("Last Owner Name")->setEnabled(TRUE); // update group text field getChildView("Group:")->setEnabled(TRUE); - //getChild("Group Name")->setValue(LLStringUtil::null); LLUUID group_id; BOOL groups_identical = LLSelectMgr::getInstance()->selectGetGroup(group_id); if (groups_identical) { if(mLabelGroupName) { - mLabelGroupName->setNameID(group_id, TRUE); + mLabelGroupName->setNameID(group_id, LFIDBearer::GROUP); mLabelGroupName->setEnabled(TRUE); } } @@ -492,14 +453,13 @@ void LLPanelPermissions::refresh() { if(mLabelGroupName) { - mLabelGroupName->setNameID(LLUUID::null, TRUE); - mLabelGroupName->refresh(LLUUID::null, std::string(), true); + mLabelGroupName->setNameID(LLUUID::null, LFIDBearer::GROUP); + mLabelGroupName->setNameText(); mLabelGroupName->setEnabled(FALSE); } } getChildView("button set group")->setEnabled(root_selected && owners_identical && (mOwnerID == gAgent.getID()) && is_nonpermanent_enforced); - getChildView("button open group")->setEnabled(group_id.notNull()); getChildView("Name:")->setEnabled(TRUE); LLLineEditor* LineEditorObjectName = getChild("Object Name"); @@ -510,7 +470,7 @@ void LLPanelPermissions::refresh() { if(keyboard_focus_view != LineEditorObjectName) { - getChild("Object Name")->setValue(nodep->mName); + LineEditorObjectName->setValue(nodep->mName); } if(LineEditorObjectDesc) @@ -523,25 +483,26 @@ void LLPanelPermissions::refresh() } else { - getChild("Object Name")->setValue(LLStringUtil::null); + LineEditorObjectName->setText(LLStringUtil::null); LineEditorObjectDesc->setText(LLStringUtil::null); } // figure out the contents of the name, description, & category - BOOL edit_name_desc = FALSE; - if(is_one_object && objectp->permModify() && !objectp->isPermanentEnforced()) + // Singu Note: It was requested that the user be able to bulk change description { - edit_name_desc = TRUE; + const std::string& str(object_count > 1 ? getString("multiple_objects_selected") : LLStringUtil::null); + LineEditorObjectName->setLabel(str); + LineEditorObjectDesc->setLabel(str); } - if(edit_name_desc) + if (/*is_one_object &&*/ objectp->permModify() && !objectp->isPermanentEnforced()) { - getChildView("Object Name")->setEnabled(TRUE); - getChildView("Object Description")->setEnabled(TRUE); + LineEditorObjectName->setEnabled(TRUE); + LineEditorObjectDesc->setEnabled(TRUE); } else { - getChildView("Object Name")->setEnabled(FALSE); - getChildView("Object Description")->setEnabled(FALSE); + LineEditorObjectName->setEnabled(FALSE); + LineEditorObjectDesc->setEnabled(FALSE); } S32 total_sale_price = 0; @@ -692,16 +653,18 @@ void LLPanelPermissions::refresh() getChild("B:")->setValue("B: " + perm_string); getChildView("B:")->setVisible( TRUE); + /* perm_string = mask_to_string(owner_mask_on); if (!supports_export && owner_mask_on & PERM_EXPORT) // Hide Export when not available perm_string.erase(perm_string.find_last_of("E")); - //getChild("O:")->setValue("O: " + perm_string); - //getChildView("O:")->setVisible( TRUE); + getChild("O:")->setValue("O: " + perm_string); + getChildView("O:")->setVisible( TRUE); + */ getChild("G:")->setValue("G: " + mask_to_string(group_mask_on)); getChildView("G:")->setVisible( TRUE); - perm_string = mask_to_string(owner_mask_on); + perm_string = mask_to_string(everyone_mask_on); if (!supports_export && everyone_mask_on & PERM_EXPORT) // Hide Export when not available perm_string.erase(perm_string.find_last_of("E")); getChild("E:")->setValue("E: " + perm_string); @@ -1025,36 +988,6 @@ void LLPanelPermissions::onClickRelease(void*) LLSelectMgr::getInstance()->sendOwner(LLUUID::null, LLUUID::null); } -void LLPanelPermissions::onClickCreator() -{ - LLAvatarActions::showProfile(mCreatorID); -} - -void LLPanelPermissions::onClickOwner() -{ - if (LLSelectMgr::getInstance()->selectIsGroupOwned()) - { - LLUUID group_id; - LLSelectMgr::getInstance()->selectGetGroup(group_id); - LLGroupActions::show(group_id); - } - else - { -// [RLVa:KB] - Checked: 2009-07-08 (RLVa-1.0.0e) - if (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) - { - LLAvatarActions::showProfile(mOwnerID); - } -// [/RLVa:KB] -// LLAvatarActions::showProfile(mOwnerID); - } -} - -void LLPanelPermissions::onClickLastOwner() -{ - LLAvatarActions::showProfile(mLastOwnerID); -} - void LLPanelPermissions::onClickGroup() { LLUUID owner_id; @@ -1079,18 +1012,11 @@ void LLPanelPermissions::onClickGroup() } } -void LLPanelPermissions::onClickOpenGroup() -{ - LLUUID group_id; - LLSelectMgr::getInstance()->selectGetGroup(group_id); - LLGroupActions::show(group_id); -} - void LLPanelPermissions::cbGroupID(LLUUID group_id) { if(mLabelGroupName) { - mLabelGroupName->setNameID(group_id, TRUE); + mLabelGroupName->setNameID(group_id, LFIDBearer::GROUP); } LLSelectMgr::getInstance()->sendGroup(group_id); } @@ -1116,16 +1042,17 @@ void LLPanelPermissions::onClickDeedToGroup(void* data) LLNotificationsUtil::add( "DeedObjectToGroup", LLSD(), LLSD(), callback_deed_to_group); } -void LLPanelPermissions::onClickCopyObjKey() +template +std::string gather_keys(iterator iter, iterator end) { //NAMESHORT - Was requested on the forums, was going to integrate a textbox with the ID, but due to lack of room on the floater, //We now have a copy button :> //Madgeek - Hacked together method to copy more than one key, separated by comma. //At some point the separator was changed to read from the xml settings - I'll probably try to make this openly changable from settings. -HgB + //Lirusaito - Tweaked to copy selected prim(s) when EditLinkedParts, main functionality moved into gather_keys std::string output; std::string separator = gSavedSettings.getString("AscentDataSeparator"); - for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin(); - iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++) + for (; iter != end; ++iter) { LLSelectNode* selectNode = *iter; LLViewerObject* object = selectNode->getObject(); @@ -1135,6 +1062,14 @@ void LLPanelPermissions::onClickCopyObjKey() output.append(object->getID().asString()); } } + return output; +} + +void LLPanelPermissions::onClickCopyObjKey() +{ + bool parts(gSavedSettings.getBOOL("EditLinkedParts")); + LLObjectSelectionHandle selection(LLSelectMgr::getInstance()->getSelection()); + std::string output = parts ? gather_keys(selection->begin(), selection->end()) : gather_keys(selection->root_begin(), selection->root_end()); if (!output.empty()) gViewerWindow->getWindow()->copyTextToClipboard(utf8str_to_wstring(output)); } @@ -1183,28 +1118,28 @@ void LLPanelPermissions::onCommitExport(const LLSD& param) // static void LLPanelPermissions::onCommitNextOwnerModify(LLUICtrl* ctrl, void* data) { - //llinfos << "LLPanelPermissions::onCommitNextOwnerModify" << llendl; + //LL_INFOS() << "LLPanelPermissions::onCommitNextOwnerModify" << LL_ENDL; onCommitPerm(ctrl, data, PERM_NEXT_OWNER, PERM_MODIFY); } // static void LLPanelPermissions::onCommitNextOwnerCopy(LLUICtrl* ctrl, void* data) { - //llinfos << "LLPanelPermissions::onCommitNextOwnerCopy" << llendl; + //LL_INFOS() << "LLPanelPermissions::onCommitNextOwnerCopy" << LL_ENDL; onCommitPerm(ctrl, data, PERM_NEXT_OWNER, PERM_COPY); } // static void LLPanelPermissions::onCommitNextOwnerTransfer(LLUICtrl* ctrl, void* data) { - //llinfos << "LLPanelPermissions::onCommitNextOwnerTransfer" << llendl; + //LL_INFOS() << "LLPanelPermissions::onCommitNextOwnerTransfer" << LL_ENDL; onCommitPerm(ctrl, data, PERM_NEXT_OWNER, PERM_TRANSFER); } // static void LLPanelPermissions::onCommitName(LLUICtrl*, void* data) { - //llinfos << "LLPanelPermissions::onCommitName()" << llendl; + //LL_INFOS() << "LLPanelPermissions::onCommitName()" << LL_ENDL; LLPanelPermissions* self = (LLPanelPermissions*)data; LLLineEditor* tb = self->getChild("Object Name"); if(tb) @@ -1218,7 +1153,7 @@ void LLPanelPermissions::onCommitName(LLUICtrl*, void* data) // static void LLPanelPermissions::onCommitDesc(LLUICtrl*, void* data) { - //llinfos << "LLPanelPermissions::onCommitDesc()" << llendl; + //LL_INFOS() << "LLPanelPermissions::onCommitDesc()" << LL_ENDL; LLPanelPermissions* self = (LLPanelPermissions*)data; LLLineEditor* le = self->getChild("Object Description"); if(le) @@ -1243,7 +1178,7 @@ void LLPanelPermissions::onCommitSaleType(LLUICtrl*, void* data) void LLPanelPermissions::setAllSaleInfo() { - llinfos << "LLPanelPermissions::setAllSaleInfo()" << llendl; + LL_INFOS() << "LLPanelPermissions::setAllSaleInfo()" << LL_ENDL; LLSaleInfo::EForSale sale_type = LLSaleInfo::FS_NOT; LLStringUtil::format_map_t argsCurrency; diff --git a/indra/newview/llpanelpermissions.h b/indra/newview/llpanelpermissions.h index 58b6dbac9b..87868108b7 100644 --- a/indra/newview/llpanelpermissions.h +++ b/indra/newview/llpanelpermissions.h @@ -58,11 +58,7 @@ class LLPanelPermissions : public LLPanel // statics static void onClickClaim(void*); static void onClickRelease(void*); - void onClickCreator(); - void onClickOwner(); - void onClickLastOwner(); void onClickGroup(); - static void onClickOpenGroup(); void cbGroupID(LLUUID group_id); static void onClickDeedToGroup(void*); static void onClickCopyObjKey(); diff --git a/indra/newview/llpanelpick.cpp b/indra/newview/llpanelpick.cpp index 674d9b65da..99d5f0c916 100644 --- a/indra/newview/llpanelpick.cpp +++ b/indra/newview/llpanelpick.cpp @@ -61,10 +61,14 @@ void show_picture(const LLUUID& id, const std::string& name) { // Try to show and focus existing preview - if (LLPreview::show(id)) return; + if (id.isNull() || LLPreview::show(id)) return; // If there isn't one, make a new preview - LLPreview* preview = new LLPreviewTexture("preview texture", gSavedSettings.getRect("PreviewTextureRect"), name, id); + S32 left, top; + gFloaterView->getNewFloaterPosition(&left, &top); + LLRect rect = gSavedSettings.getRect("PreviewTextureRect"); + auto preview = new LLPreviewTexture("preview texture", rect.translate(left - rect.mLeft, rect.mTop - top), name, id); preview->setFocus(true); + gFloaterView->adjustToFitScreen(preview, false); } //static @@ -124,8 +128,11 @@ void LLPanelPick::reset() BOOL LLPanelPick::postBuild() { + auto show_pic = [this] { show_picture(mSnapshotCtrl->getImageAssetID(), mNameEditor->getText()); }; + auto show_pic_if_not_self = [=] { if (!mSnapshotCtrl->canChange()) show_pic(); }; mSnapshotCtrl = getChild("snapshot_ctrl"); mSnapshotCtrl->setCommitCallback(boost::bind(&LLPanelPick::onCommitAny, this)); + mSnapshotCtrl->setMouseUpCallback(std::bind(show_pic_if_not_self)); mNameEditor = getChild("given_name_editor"); mNameEditor->setCommitOnFocusLost(true); @@ -142,7 +149,7 @@ BOOL LLPanelPick::postBuild() mSetBtn->setCommitCallback(boost::bind(&LLPanelPick::onClickSet,this)); mOpenBtn = getChild("open_picture_btn"); - mOpenBtn->setCommitCallback(boost::bind(show_picture, boost::bind(&LLTextureCtrl::getImageAssetID, mSnapshotCtrl), boost::bind(&LLLineEditor::getText, mNameEditor))); + mOpenBtn->setCommitCallback(std::bind(show_pic)); getChild("pick_teleport_btn")->setCommitCallback(boost::bind(&LLPanelPick::onClickTeleport,this)); getChild("pick_map_btn")->setCommitCallback(boost::bind(&LLPanelPick::onClickMap,this)); @@ -178,9 +185,9 @@ void LLPanelPick::processProperties(void* data, EAvatarProcessorType type) self->mImporting = false; } - S32 region_x = llround((F32)pick_info->pos_global.mdV[VX]) % REGION_WIDTH_UNITS; - S32 region_y = llround((F32)pick_info->pos_global.mdV[VY]) % REGION_WIDTH_UNITS; - S32 region_z = llround((F32)pick_info->pos_global.mdV[VZ]); + S32 region_x = ll_round((F32)pick_info->pos_global.mdV[VX]) % REGION_WIDTH_UNITS; + S32 region_y = ll_round((F32)pick_info->pos_global.mdV[VY]) % REGION_WIDTH_UNITS; + S32 region_z = ll_round((F32)pick_info->pos_global.mdV[VZ]); location_text.append(llformat("(%d, %d, %d)", region_x, region_y, region_z)); mDataReceived = true; @@ -194,7 +201,7 @@ void LLPanelPick::processProperties(void* data, EAvatarProcessorType type) // Update UI controls mNameEditor->setText(pick_info->name); - mDescEditor->setText(pick_info->desc); + mDescEditor->setText(pick_info->desc, false); mSnapshotCtrl->setImageAssetID(pick_info->snapshot_id); mLocationEditor->setText(location_text); } @@ -401,9 +408,9 @@ void LLPanelPick::onClickSet() std::string location_text("(will update after save), " + mSimName); - S32 region_x = llround((F32)mPosGlobal.mdV[VX]) % REGION_WIDTH_UNITS; - S32 region_y = llround((F32)mPosGlobal.mdV[VY]) % REGION_WIDTH_UNITS; - S32 region_z = llround((F32)mPosGlobal.mdV[VZ]); + S32 region_x = ll_round((F32)mPosGlobal.mdV[VX]) % REGION_WIDTH_UNITS; + S32 region_y = ll_round((F32)mPosGlobal.mdV[VY]) % REGION_WIDTH_UNITS; + S32 region_z = ll_round((F32)mPosGlobal.mdV[VZ]); location_text.append(llformat(" (%d, %d, %d)", region_x, region_y, region_z)); // if sim name in pick is different from current sim name diff --git a/indra/newview/llpanelplace.cpp b/indra/newview/llpanelplace.cpp index 80af2ac563..00f7bc4d11 100644 --- a/indra/newview/llpanelplace.cpp +++ b/indra/newview/llpanelplace.cpp @@ -125,7 +125,7 @@ BOOL LLPanelPlace::postBuild() void LLPanelPlace::displayItemInfo(const LLInventoryItem* pItem) { mNameEditor->setText(pItem->getName()); - mDescEditor->setText(pItem->getDescription()); + mDescEditor->setText(pItem->getDescription(), false); } // Use this for search directory clicks, because we are totally @@ -161,7 +161,7 @@ void LLPanelPlace::resetName(const std::string& name) } if(mNameEditor) { - llinfos << "Clearing place name" << llendl; + LL_INFOS() << "Clearing place name" << LL_ENDL; mNameEditor->setText( LLStringUtil::null ); } if(mInfoEditor) @@ -221,7 +221,7 @@ void LLPanelPlace::setErrorStatus(U32 status, const std::string& reason) } else { - llwarns << "Unexpected error (" << status << "): " << reason << llendl; + LL_WARNS() << "Unexpected error (" << status << "): " << reason << LL_ENDL; error_text = llformat("Unexpected Error (%u): %s", status, reason.c_str()); } mDescEditor->setText(error_text); @@ -248,7 +248,7 @@ void LLPanelPlace::processParcelInfo(const LLParcelData& parcel_data) if( !parcel_data.desc.empty() && mDescEditor && mDescEditor->getText().empty()) { - mDescEditor->setText(parcel_data.desc); + mDescEditor->setText(parcel_data.desc, false); } std::string info_text; @@ -289,16 +289,16 @@ void LLPanelPlace::processParcelInfo(const LLParcelData& parcel_data) } // Just use given region position for display - S32 region_x = llround(mPosRegion.mV[0]); - S32 region_y = llround(mPosRegion.mV[1]); - S32 region_z = llround(mPosRegion.mV[2]); + S32 region_x = ll_round(mPosRegion.mV[0]); + S32 region_y = ll_round(mPosRegion.mV[1]); + S32 region_z = ll_round(mPosRegion.mV[2]); // If the region position is zero, grab position from the global if(mPosRegion.isExactlyZero()) { - region_x = llround(parcel_data.global_x) % REGION_WIDTH_UNITS; - region_y = llround(parcel_data.global_y) % REGION_WIDTH_UNITS; - region_z = llround(parcel_data.global_z); + region_x = ll_round(parcel_data.global_x) % REGION_WIDTH_UNITS; + region_y = ll_round(parcel_data.global_y) % REGION_WIDTH_UNITS; + region_z = ll_round(parcel_data.global_z); } if(mPosGlobal.isExactlyZero()) @@ -419,7 +419,7 @@ bool LLPanelPlace::callbackAuctionWebPage(const LLSD& notification, const LLSD& S32 auction_id = notification["payload"]["auction_id"].asInteger(); url = AUCTION_URL + llformat("%010d", auction_id ); - llinfos << "Loading auction page " << url << llendl; + LL_INFOS() << "Loading auction page " << url << LL_ENDL; LLWeb::loadURL(url); } diff --git a/indra/newview/llpanelprimmediacontrols.cpp b/indra/newview/llpanelprimmediacontrols.cpp index 3ebc387106..79237f8067 100644 --- a/indra/newview/llpanelprimmediacontrols.cpp +++ b/indra/newview/llpanelprimmediacontrols.cpp @@ -70,10 +70,10 @@ #include "lllayoutstack.h" // Functions pulled from pipeline.cpp -glh::matrix4f glh_get_current_modelview(); -glh::matrix4f glh_get_current_projection(); +const LLMatrix4a& glh_get_current_modelview(); +const LLMatrix4a& glh_get_current_projection(); // Functions pulled from llviewerdisplay.cpp -bool get_hud_matrices(glh::matrix4f &proj, glh::matrix4f &model); +bool get_hud_matrices(LLMatrix4a &proj, LLMatrix4a &model); // Warning: make sure these two match! const LLPanelPrimMediaControls::EZoomLevel LLPanelPrimMediaControls::kZoomLevels[] = { ZOOM_NONE, ZOOM_MEDIUM }; @@ -84,12 +84,12 @@ const int LLPanelPrimMediaControls::kNumZoomLevels = 2; // LLPanelPrimMediaControls::LLPanelPrimMediaControls() : - mAlpha(1.f), - mCurrentURL(""), - mPreviousURL(""), mPauseFadeout(false), mUpdateSlider(true), mClearFaceOnFade(false), + mAlpha(1.f), + mCurrentURL(""), + mPreviousURL(""), mCurrentRate(0.0), mMovieDuration(0.0), mTargetObjectID(LLUUID::null), @@ -118,6 +118,7 @@ LLPanelPrimMediaControls::LLPanelPrimMediaControls() : mCommitCallbackRegistrar.add("MediaCtrl.CommitVolumeDown", boost::bind(&LLPanelPrimMediaControls::onCommitVolumeDown, this)); mCommitCallbackRegistrar.add("MediaCtrl.Volume", boost::bind(&LLPanelPrimMediaControls::onCommitVolumeSlider, this)); mCommitCallbackRegistrar.add("MediaCtrl.ToggleMute", boost::bind(&LLPanelPrimMediaControls::onToggleMute, this)); + mCommitCallbackRegistrar.add("MediaCtrl.MOAPStop", std::bind([this]() { getTargetMediaImpl()->setDisabled(true); })); mCommitCallbackRegistrar.add("MediaCtrl.ShowVolumeSlider", boost::bind(&LLPanelPrimMediaControls::showVolumeSlider, this)); mCommitCallbackRegistrar.add("MediaCtrl.HideVolumeSlider", boost::bind(&LLPanelPrimMediaControls::hideVolumeSlider, this)); mCommitCallbackRegistrar.add("MediaCtrl.SkipBack", boost::bind(&LLPanelPrimMediaControls::onClickSkipBack, this)); @@ -150,6 +151,7 @@ BOOL LLPanelPrimMediaControls::postBuild() mPauseCtrl = getChild("pause"); mStopCtrl = getChild("stop"); mMediaStopCtrl = getChild("media_stop"); + mMOAPStopCtrl = getChild("moap_stop"); mHomeCtrl = getChild("home"); mUnzoomCtrl = getChild("close"); // This is actually "unzoom" mOpenCtrl = getChild("new_window"); @@ -283,7 +285,7 @@ LLPluginClassMedia* LLPanelPrimMediaControls::getTargetMediaPlugin() return impl->getMediaPlugin(); } - return NULL; + return nullptr; } void LLPanelPrimMediaControls::updateShape() @@ -297,7 +299,7 @@ void LLPanelPrimMediaControls::updateShape() return; } - LLPluginClassMedia* media_plugin = NULL; + LLPluginClassMedia* media_plugin = nullptr; if(media_impl->hasMedia()) { media_plugin = media_impl->getMediaPlugin(); @@ -318,10 +320,11 @@ void LLPanelPrimMediaControls::updateShape() { bool mini_controls = false; LLMediaEntry *media_data = objectp->getTE(mTargetObjectFace)->getMediaData(); - if (media_data && NULL != dynamic_cast(objectp)) + LLVOVolume *vol = objectp ? objectp->asVolume() : nullptr; + if (media_data && vol) { // Don't show the media controls if we do not have permissions - enabled = dynamic_cast(objectp)->hasMediaPermission(media_data, LLVOVolume::MEDIA_PERM_CONTROL); + enabled = vol->hasMediaPermission(media_data, LLVOVolume::MEDIA_PERM_CONTROL); mini_controls = (LLMediaEntry::MINI == media_data->getControls()); } const bool is_hud = objectp->isHUDAttachment(); @@ -351,11 +354,11 @@ void LLPanelPrimMediaControls::updateShape() mSecureLockIcon->setVisible(false); mCurrentURL = media_impl->getCurrentMediaURL(); - mBackCtrl->setEnabled((media_impl != NULL) && media_impl->canNavigateBack() && can_navigate); - mFwdCtrl->setEnabled((media_impl != NULL) && media_impl->canNavigateForward() && can_navigate); + mBackCtrl->setEnabled((media_impl != nullptr) && media_impl->canNavigateBack() && can_navigate); + mFwdCtrl->setEnabled((media_impl != nullptr) && media_impl->canNavigateForward() && can_navigate); mStopCtrl->setEnabled(has_focus && can_navigate); mHomeCtrl->setEnabled(has_focus && can_navigate); - LLPluginClassMediaOwner::EMediaStatus result = ((media_impl != NULL) && media_impl->hasMedia()) ? media_plugin->getStatus() : LLPluginClassMediaOwner::MEDIA_NONE; + LLPluginClassMediaOwner::EMediaStatus result = ((media_impl != nullptr) && media_impl->hasMedia()) ? media_plugin->getStatus() : LLPluginClassMediaOwner::MEDIA_NONE; mVolumeCtrl->setVisible(has_focus); mVolumeCtrl->setEnabled(has_focus); @@ -367,6 +370,7 @@ void LLPanelPrimMediaControls::updateShape() mReloadCtrl->setEnabled(false); mReloadCtrl->setVisible(false); mMediaStopCtrl->setVisible(has_focus); + mMOAPStopCtrl->setVisible(false); mHomeCtrl->setVisible(has_focus); mBackCtrl->setVisible(false); mFwdCtrl->setVisible(false); @@ -419,7 +423,7 @@ void LLPanelPrimMediaControls::updateShape() mMediaPlaySliderCtrl->setEnabled(true); } - // video vloume + // video volume if(volume <= 0.0) { mMuteBtn->setToggleState(true); @@ -465,6 +469,7 @@ void LLPanelPrimMediaControls::updateShape() mPlayCtrl->setVisible(FALSE); mPauseCtrl->setVisible(FALSE); mMediaStopCtrl->setVisible(FALSE); + mMOAPStopCtrl->setVisible(!!media_plugin); mMediaAddressCtrl->setVisible(has_focus && !mini_controls); mMediaAddressCtrl->setEnabled(has_focus && !mini_controls); mMediaPlaySliderPanel->setVisible(FALSE); @@ -547,21 +552,21 @@ void LLPanelPrimMediaControls::updateShape() switch (mScrollState) { case SCROLL_UP: - media_impl->scrollWheel(0, -1, MASK_NONE); + media_impl->scrollWheel(0, 0, 0, -1, MASK_NONE); break; case SCROLL_DOWN: - media_impl->scrollWheel(0, 1, MASK_NONE); + media_impl->scrollWheel(0, 0, 0, 1, MASK_NONE); break; case SCROLL_LEFT: - media_impl->scrollWheel(1, 0, MASK_NONE); + media_impl->scrollWheel(0, 0, 1, 0, MASK_NONE); // media_impl->handleKeyHere(KEY_LEFT, MASK_NONE); break; case SCROLL_RIGHT: - media_impl->scrollWheel(-1, 0, MASK_NONE); + media_impl->scrollWheel(0, 0, -1, 0, MASK_NONE); // media_impl->handleKeyHere(KEY_RIGHT, MASK_NONE); break; case SCROLL_NONE: - default: + default: break; } } @@ -609,37 +614,45 @@ void LLPanelPrimMediaControls::updateShape() vert_it = vect_face.begin(); vert_end = vect_face.end(); - glh::matrix4f mat; + LLMatrix4a mat; if (!is_hud) { - mat = glh_get_current_projection() * glh_get_current_modelview(); + mat.setMul(glh_get_current_projection(),glh_get_current_modelview()); } else { - glh::matrix4f proj, modelview; + LLMatrix4a proj, modelview; if (get_hud_matrices(proj, modelview)) - mat = proj * modelview; + { + //mat = proj * modelview; + mat.setMul(proj,modelview); + } } - LLVector3 min = LLVector3(1,1,1); - LLVector3 max = LLVector3(-1,-1,-1); + LLVector4a min; + min.splat(1.f); + LLVector4a max; + max.splat(-1.f); for(; vert_it != vert_end; ++vert_it) { // project silhouette vertices into screen space - glh::vec3f screen_vert = glh::vec3f(vert_it->mV); - mat.mult_matrix_vec(screen_vert); - + LLVector4a screen_vert; + screen_vert.load3(vert_it->mV,1.f); + + mat.perspectiveTransform(screen_vert,screen_vert); + // add to screenspace bounding box - update_min_max(min, max, LLVector3(screen_vert.v)); + min.setMin(screen_vert,min); + max.setMax(screen_vert,max); } // convert screenspace bbox to pixels (in screen coords) LLRect window_rect = gViewerWindow->getWorldViewRectScaled(); LLCoordGL screen_min; - screen_min.mX = llround((F32)window_rect.mLeft + (F32)window_rect.getWidth() * (min.mV[VX] + 1.f) * 0.5f); - screen_min.mY = llround((F32)window_rect.mBottom + (F32)window_rect.getHeight() * (min.mV[VY] + 1.f) * 0.5f); + screen_min.mX = ll_round((F32)window_rect.mLeft + (F32)window_rect.getWidth() * (min.getF32ptr()[VX] + 1.f) * 0.5f); + screen_min.mY = ll_round((F32)window_rect.mBottom + (F32)window_rect.getHeight() * (min.getF32ptr()[VY] + 1.f) * 0.5f); LLCoordGL screen_max; - screen_max.mX = llround((F32)window_rect.mLeft + (F32)window_rect.getWidth() * (max.mV[VX] + 1.f) * 0.5f); - screen_max.mY = llround((F32)window_rect.mBottom + (F32)window_rect.getHeight() * (max.mV[VY] + 1.f) * 0.5f); + screen_max.mX = ll_round((F32)window_rect.mLeft + (F32)window_rect.getWidth() * (max.getF32ptr()[VX] + 1.f) * 0.5f); + screen_max.mY = ll_round((F32)window_rect.mBottom + (F32)window_rect.getHeight() * (max.getF32ptr()[VY] + 1.f) * 0.5f); // grow panel so that screenspace bounding box fits inside "media_region" element of panel LLRect media_panel_rect; @@ -831,7 +844,7 @@ bool LLPanelPrimMediaControls::isMouseOver() if(hit_child && hit_child->getVisible()) { // This was useful for debugging both coordinate translation and view hieararchy problems... - // llinfos << "mouse coords: " << x << ", " << y << " hit child " << hit_child->getName() << llendl; + // LL_INFOS() << "mouse coords: " << x << ", " << y << " hit child " << hit_child->getName() << LL_ENDL; // This will be a direct child of the LLLayoutStack, which should be a layout_panel. // These may not shown/hidden by the logic in updateShape(), so we need to do another hit test on the children of the layout panel, @@ -842,7 +855,7 @@ bool LLPanelPrimMediaControls::isMouseOver() if(hit_child_2 && hit_child_2->getVisible()) { // This was useful for debugging both coordinate translation and view hieararchy problems... - // llinfos << " mouse coords: " << x << ", " << y << " hit child 2 " << hit_child_2->getName() << llendl; + // LL_INFOS() << " mouse coords: " << x << ", " << y << " hit child 2 " << hit_child_2->getName() << LL_ENDL; result = true; } } @@ -1093,7 +1106,7 @@ void LLPanelPrimMediaControls::onScrollUp(void* user_data) if(impl) { - impl->scrollWheel(0, -1, MASK_NONE); + impl->scrollWheel(0, 0, 0, -1, MASK_NONE); } } void LLPanelPrimMediaControls::onScrollUpHeld(void* user_data) @@ -1110,7 +1123,7 @@ void LLPanelPrimMediaControls::onScrollRight(void* user_data) if(impl) { - impl->scrollWheel(-1, 0, MASK_NONE); + impl->scrollWheel(0, 0, -1, 0, MASK_NONE); // impl->handleKeyHere(KEY_RIGHT, MASK_NONE); } } @@ -1129,7 +1142,7 @@ void LLPanelPrimMediaControls::onScrollLeft(void* user_data) if(impl) { - impl->scrollWheel(1, 0, MASK_NONE); + impl->scrollWheel(0, 0, 1, 0, MASK_NONE); // impl->handleKeyHere(KEY_LEFT, MASK_NONE); } } @@ -1148,7 +1161,7 @@ void LLPanelPrimMediaControls::onScrollDown(void* user_data) if(impl) { - impl->scrollWheel(0, 1, MASK_NONE); + impl->scrollWheel(0, 0, 0, 1, MASK_NONE); } } void LLPanelPrimMediaControls::onScrollDownHeld(void* user_data) diff --git a/indra/newview/llpanelprimmediacontrols.h b/indra/newview/llpanelprimmediacontrols.h index 7db687d23d..2cf196a225 100644 --- a/indra/newview/llpanelprimmediacontrols.h +++ b/indra/newview/llpanelprimmediacontrols.h @@ -155,6 +155,7 @@ class LLPanelPrimMediaControls : public LLPanel LLUICtrl *mPauseCtrl; LLUICtrl *mStopCtrl; LLUICtrl *mMediaStopCtrl; + LLUICtrl *mMOAPStopCtrl; LLUICtrl *mHomeCtrl; LLUICtrl *mUnzoomCtrl; LLUICtrl *mOpenCtrl; diff --git a/indra/newview/llpanelprofile.cpp b/indra/newview/llpanelprofile.cpp index 8237555ca5..6c26444409 100644 --- a/indra/newview/llpanelprofile.cpp +++ b/indra/newview/llpanelprofile.cpp @@ -41,7 +41,11 @@ #include "lltabcontainer.h" #include "llviewercontrol.h" #include "llviewernetwork.h" +#include "llmutelist.h" +#endif +#include "llfloatermute.h" +#ifdef AI_UNUSED static const std::string PANEL_PICKS = "panel_picks"; #endif // AI_UNUSED @@ -55,23 +59,23 @@ std::string getProfileURL(const std::string& agent_name) llassert(!url.empty()); LLSD subs; subs["AGENT_NAME"] = agent_name; - url = LLWeb::expandURLSubstitutions(url,subs); + url = LLWeb::expandURLSubstitutions(url, subs); LLStringUtil::toLower(url); return url; } -class LLProfileHandler : public LLCommandHandler +class LLProfileHandler final : public LLCommandHandler { public: // requires trusted browser to trigger LLProfileHandler() : LLCommandHandler("profile", UNTRUSTED_THROTTLE) { } bool handle(const LLSD& params, const LLSD& query_map, - LLMediaCtrl* web) + LLMediaCtrl* web) override { if (params.size() < 1) return false; std::string agent_name = params[0]; - llinfos << "Profile, agent_name " << agent_name << llendl; + LL_INFOS() << "Profile, agent_name " << agent_name << LL_ENDL; std::string url = getProfileURL(agent_name); LLWeb::loadURLInternal(url); @@ -80,14 +84,14 @@ class LLProfileHandler : public LLCommandHandler }; LLProfileHandler gProfileHandler; -class LLAgentHandler : public LLCommandHandler +class LLAgentHandler final : public LLCommandHandler { public: // requires trusted browser to trigger LLAgentHandler() : LLCommandHandler("agent", UNTRUSTED_THROTTLE) { } bool handle(const LLSD& params, const LLSD& query_map, - LLMediaCtrl* web) + LLMediaCtrl* web) override { if (params.size() < 2) return false; LLUUID avatar_id; @@ -96,8 +100,9 @@ class LLAgentHandler : public LLCommandHandler return false; } - const std::string verb = params[1].asString(); - if (verb == "about") + std::string verb = params[1].asString(); + for (; !verb.empty() && std::ispunct(verb.back()); verb.pop_back()); + if (verb == "about" || verb == "completename" || verb == "displayname" || verb == "username") { LLAvatarActions::showProfile(avatar_id); return true; @@ -143,6 +148,12 @@ class LLAgentHandler : public LLCommandHandler return true; } + if (verb == "removefriend") + { + LLAvatarActions::removeFriendDialog(avatar_id); + return true; + } + if (verb == "mute") { if (! LLAvatarActions::isBlocked(avatar_id)) @@ -161,6 +172,28 @@ class LLAgentHandler : public LLCommandHandler return true; } + if (verb == "block") + { + if (params.size() > 2) + { + const std::string object_name = LLURI::unescape(params[2].asString()); + LLMute mute(avatar_id, object_name, LLMute::OBJECT); + LLMuteList::getInstance()->add(mute); + LLFloaterMute::showInstance()->selectMute(mute.mID); + } + return true; + } + + if (verb == "unblock") + { + if (params.size() > 2) + { + const std::string object_name = params[2].asString(); + LLMute mute(avatar_id, object_name, LLMute::OBJECT); + LLMuteList::getInstance()->remove(mute); + } + return true; + } return false; } }; @@ -170,13 +203,13 @@ LLAgentHandler gAgentHandler; #ifdef AI_UNUSED //-- LLPanelProfile::ChildStack begins ---------------------------------------- LLPanelProfile::ChildStack::ChildStack() -: mParent(NULL) +: mParent(nullptr) { } LLPanelProfile::ChildStack::~ChildStack() { - while (mStack.size() != 0) + while (!mStack.empty()) { view_list_t& top = mStack.back(); for (view_list_t::const_iterator it = top.begin(); it != top.end(); ++it) @@ -216,9 +249,9 @@ bool LLPanelProfile::ChildStack::push() /// Restore saved children (adding them back to the child list). bool LLPanelProfile::ChildStack::pop() { - if (mStack.size() == 0) + if (mStack.empty()) { - llwarns << "Empty stack" << llendl; + LL_WARNS() << "Empty stack" << LL_ENDL; llassert(mStack.size() == 0); return false; } @@ -239,7 +272,7 @@ bool LLPanelProfile::ChildStack::pop() void LLPanelProfile::ChildStack::preParentReshape() { mSavedStack = mStack; - while(mStack.size() > 0) + while(!mStack.empty()) { pop(); } @@ -254,10 +287,9 @@ void LLPanelProfile::ChildStack::postParentReshape() for (stack_t::const_iterator stack_it = mStack.begin(); stack_it != mStack.end(); ++stack_it) { const view_list_t& vlist = (*stack_it); - for (view_list_t::const_iterator list_it = vlist.begin(); list_it != vlist.end(); ++list_it) + for (auto viewp : vlist) { - LLView* viewp = *list_it; - lldebugs << "removing " << viewp->getName() << llendl; + LL_DEBUGS() << "removing " << viewp->getName() << LL_ENDL; mParent->removeChild(viewp); } } @@ -266,17 +298,17 @@ void LLPanelProfile::ChildStack::postParentReshape() void LLPanelProfile::ChildStack::dump() { unsigned lvl = 0; - lldebugs << "child stack dump:" << llendl; + LL_DEBUGS() << "child stack dump:" << LL_ENDL; for (stack_t::const_iterator stack_it = mStack.begin(); stack_it != mStack.end(); ++stack_it, ++lvl) { std::ostringstream dbg_line; dbg_line << "lvl #" << lvl << ":"; const view_list_t& vlist = (*stack_it); - for (view_list_t::const_iterator list_it = vlist.begin(); list_it != vlist.end(); ++list_it) + for (auto list_it : vlist) { - dbg_line << " " << (*list_it)->getName(); + dbg_line << " " << list_it->getName(); } - lldebugs << dbg_line.str() << llendl; + LL_DEBUGS() << dbg_line.str() << LL_ENDL; } } @@ -371,7 +403,7 @@ void LLPanelProfile::onOpen() void LLPanelProfile::onTabSelected(const LLSD& param) { std::string tab_name = param.asString(); - if (NULL != getTabContainer()[tab_name]) + if (nullptr != getTabContainer()[tab_name]) { getTabContainer()[tab_name]->onOpen(getAvatarId()); } @@ -415,13 +447,13 @@ void LLPanelProfile::closePanel(LLPanel* panel) // Prevent losing focus by the floater const child_list_t* child_list = getChildList(); - if (child_list->size() > 0) + if (!child_list->empty()) { child_list->front()->setFocus(TRUE); } else { - llwarns << "No underlying panel to focus." << llendl; + LL_WARNS() << "No underlying panel to focus." << LL_ENDL; } } } diff --git a/indra/newview/llpanelskins.cpp b/indra/newview/llpanelskins.cpp index 610c8249d8..834fd98329 100644 --- a/indra/newview/llpanelskins.cpp +++ b/indra/newview/llpanelskins.cpp @@ -81,7 +81,7 @@ void LLPanelSkins::refresh() datas.clear(); //comboBox->add("===OFF==="); std::string path_name(gDirUtilp->getSkinBaseDir()+gDirUtilp->getDirDelimiter()); - llinfos << "Reading skin listing from " << path_name << llendl; + LL_INFOS() << "Reading skin listing from " << path_name << LL_ENDL; bool found = true; std::string currentSkinName(""); LLDirIterator iter(path_name, "*.xml"); @@ -89,7 +89,7 @@ void LLPanelSkins::refresh() { std::string name; found = iter.next(name); - //llinfos << "path name " << path_name << " and name " << name << " and found " << found << llendl; + //LL_INFOS() << "path name " << path_name << " and name " << name << " and found " << found << LL_ENDL; if(found) { LLSD data; @@ -100,11 +100,11 @@ void LLPanelSkins::refresh() { datas.push_back(data); comboBox->add(data["skin_name"].asString()); - /*llinfos << "data is length " << datas.size() << " foldername field is " - << data["folder_name"].asString() << " and looking for " << gSavedSettings.getString("SkinCurrent") <("custom_skin_preview"); std::string imagename = data["preview_image"].asString(); if(imagename == "" || imagename == " " || !LLFile::isfile(imagename)) imagename = "preview.png"; - std::string imageprev(".."+gDirUtilp->getDirDelimiter()+ - ".."+gDirUtilp->getDirDelimiter()+ + std::string imageprev(path_name+ data["folder_name"].asString()+gDirUtilp->getDirDelimiter()+ "textures"+gDirUtilp->getDirDelimiter()+ imagename); diff --git a/indra/newview/llpanelvolume.cpp b/indra/newview/llpanelvolume.cpp index adf752e312..36cc6647ef 100644 --- a/indra/newview/llpanelvolume.cpp +++ b/indra/newview/llpanelvolume.cpp @@ -36,7 +36,6 @@ // linden library includes #include "llclickaction.h" -#include "lleconomy.h" #include "llerror.h" #include "llfontgl.h" #include "llflexibleobject.h" @@ -84,6 +83,8 @@ #include "llviewercontrol.h" #include "llmeshrepository.h" +#include "llvoavatarself.h" + #include // "Features" Tab @@ -92,7 +93,8 @@ BOOL LLPanelVolume::postBuild() { // Flexible Objects Parameters { - getChild("Flexible1D Checkbox Ctrl")->setCommitCallback(boost::bind(&LLPanelVolume::onCommitIsFlexible, this, _1, _2), NULL); + childSetCommitCallback("Animated Mesh Checkbox Ctrl", boost::bind(&LLPanelVolume::onCommitAnimatedMeshCheckbox, this, _1, _2), NULL); + childSetCommitCallback("Flexible1D Checkbox Ctrl", boost::bind(&LLPanelVolume::onCommitIsFlexible, this, _1, _2), NULL); childSetCommitCallback("FlexNumSections",onCommitFlexible,this); getChild("FlexNumSections")->setValidateBeforeCommit(precommitValidate); childSetCommitCallback("FlexGravity",onCommitFlexible,this); @@ -228,6 +230,11 @@ void LLPanelVolume::getState( ) { volobjp = (LLVOVolume *)objectp; } + LLVOVolume *root_volobjp = NULL; + if (root_objectp && (root_objectp->getPCode() == LL_PCODE_VOLUME)) + { + root_volobjp = (LLVOVolume *)root_objectp; + } if( !objectp ) { @@ -251,6 +258,8 @@ void LLPanelVolume::getState( ) BOOL editable = root_objectp->permModify() && !root_objectp->isPermanentEnforced(); BOOL single_volume = LLSelectMgr::getInstance()->selectionAllPCode( LL_PCODE_VOLUME ) && LLSelectMgr::getInstance()->getSelection()->getObjectCount() == 1; + BOOL single_root_volume = LLSelectMgr::getInstance()->selectionAllPCode( LL_PCODE_VOLUME ) && + LLSelectMgr::getInstance()->getSelection()->getRootObjectCount() == 1; // Select Single Message if (single_volume) @@ -340,7 +349,57 @@ void LLPanelVolume::getState( ) getChildView("Light Focus")->setEnabled(false); getChildView("Light Ambiance")->setEnabled(false); } - + + // Animated Mesh + BOOL is_animated_mesh = single_root_volume && root_volobjp && root_volobjp->isAnimatedObject(); + getChild("Animated Mesh Checkbox Ctrl")->setValue(is_animated_mesh); + BOOL enabled_animated_object_box = FALSE; + if (root_volobjp && root_volobjp == volobjp) + { + enabled_animated_object_box = single_root_volume && root_volobjp && root_volobjp->canBeAnimatedObject() && editable; +#if 0 + if (!enabled_animated_object_box) + { + LL_INFOS() << "not enabled: srv " << single_root_volume << " root_volobjp " << (bool) root_volobjp << LL_ENDL; + if (root_volobjp) + { + LL_INFOS() << " cba " << root_volobjp->canBeAnimatedObject() + << " editable " << editable << " permModify() " << root_volobjp->permModify() + << " ispermenf " << root_volobjp->isPermanentEnforced() << LL_ENDL; + } + } +#endif + if (enabled_animated_object_box && !is_animated_mesh && + root_volobjp->isAttachment() && !gAgentAvatarp->canAttachMoreAnimatedObjects()) + { + // Turning this attachment animated would cause us to exceed the limit. + enabled_animated_object_box = false; + } + } + getChildView("Animated Mesh Checkbox Ctrl")->setEnabled(enabled_animated_object_box); + + //refresh any bakes + if (root_volobjp) + { + root_volobjp->refreshBakeTexture(); + + LLViewerObject::const_child_list_t& child_list = root_volobjp->getChildren(); + for (const auto& iter : child_list) + { + LLViewerObject* objectp = iter; + if (objectp) + { + objectp->refreshBakeTexture(); + } + } + + if (gAgentAvatarp) + { + gAgentAvatarp->updateMeshVisibility(); + } + } + + // Flexible properties BOOL is_flexible = volobjp && volobjp->isFlexible(); getChild("Flexible1D Checkbox Ctrl")->setValue(is_flexible); @@ -372,7 +431,7 @@ void LLPanelVolume::getState( ) getChildView("FlexForceY")->setEnabled(true); getChildView("FlexForceZ")->setEnabled(true); - LLFlexibleObjectData *attributes = (LLFlexibleObjectData *)objectp->getParameterEntry(LLNetworkData::PARAMS_FLEXIBLE); + const LLFlexibleObjectData *attributes = objectp->getFlexibleObjectData(); getChild("FlexNumSections")->setValue((F32)attributes->getSimulateLOD()); getChild("FlexGravity")->setValue(attributes->getGravity()); @@ -424,7 +483,7 @@ void LLPanelVolume::getState( ) mComboPhysicsShapeType->add(getString("None"), LLSD(1)); BOOL isMesh = FALSE; - LLSculptParams *sculpt_params = (LLSculptParams *)objectp->getParameterEntry(LLNetworkData::PARAMS_SCULPT); + const LLSculptParams *sculpt_params = objectp->getSculptParams(); if (sculpt_params) { U8 sculpt_type = sculpt_params->getSculptType(); @@ -512,51 +571,6 @@ void LLPanelVolume::draw() LLPanel::draw(); } -// virtual -void LLPanelVolume::clearCtrls() -{ - LLPanel::clearCtrls(); - - getChildView("select_single")->setEnabled(false); - getChildView("select_single")->setVisible(true); - getChildView("edit_object")->setEnabled(false); - getChildView("edit_object")->setVisible(false); - getChildView("Light Checkbox Ctrl")->setEnabled(false); - getChildView("label color")->setEnabled(false); - LLColorSwatchCtrl* LightColorSwatch = getChild("colorswatch"); - if(LightColorSwatch) - { - LightColorSwatch->setEnabled( FALSE ); - LightColorSwatch->setValid( FALSE ); - } - childSetEnabled("label texture",false); - LLTextureCtrl* LightTextureCtrl = getChild("light texture control"); - if(LightTextureCtrl) - { - LightTextureCtrl->setEnabled( FALSE ); - LightTextureCtrl->setValid( FALSE ); - } - - getChildView("Light Intensity")->setEnabled(false); - getChildView("Light Radius")->setEnabled(false); - getChildView("Light Falloff")->setEnabled(false); - - getChildView("Flexible1D Checkbox Ctrl")->setEnabled(false); - getChildView("FlexNumSections")->setEnabled(false); - getChildView("FlexGravity")->setEnabled(false); - getChildView("FlexTension")->setEnabled(false); - getChildView("FlexFriction")->setEnabled(false); - getChildView("FlexWind")->setEnabled(false); - getChildView("FlexForceX")->setEnabled(false); - getChildView("FlexForceY")->setEnabled(false); - getChildView("FlexForceZ")->setEnabled(false); - - mSpinPhysicsGravity->setEnabled(FALSE); - mSpinPhysicsFriction->setEnabled(FALSE); - mSpinPhysicsDensity->setEnabled(FALSE); - mSpinPhysicsRestitution->setEnabled(FALSE); -} - // // Static functions // @@ -572,7 +586,7 @@ void LLPanelVolume::sendIsLight() BOOL value = getChild("Light Checkbox Ctrl")->getValue(); volobjp->setIsLight(value); - llinfos << "update light sent" << llendl; + LL_INFOS() << "update light sent" << LL_ENDL; } void LLPanelVolume::sendIsFlexible() @@ -604,7 +618,7 @@ void LLPanelVolume::sendIsFlexible() LLSelectMgr::getInstance()->selectionUpdatePhantom(volobjp->flagPhantom()); } - llinfos << "update flexible sent" << llendl; + LL_INFOS() << "update flexible sent" << LL_ENDL; } void LLPanelVolume::sendPhysicsShapeType(LLUICtrl* ctrl, void* userdata) @@ -784,7 +798,7 @@ void LLPanelVolume::onCommitFlexible( LLUICtrl* ctrl, void* userdata ) return; } - LLFlexibleObjectData *attributes = (LLFlexibleObjectData *)objectp->getParameterEntry(LLNetworkData::PARAMS_FLEXIBLE); + const LLFlexibleObjectData *attributes = objectp->getFlexibleObjectData(); if (attributes) { LLFlexibleObjectData new_attributes; @@ -809,6 +823,52 @@ void LLPanelVolume::onCommitFlexible( LLUICtrl* ctrl, void* userdata ) self->refresh(); } +void LLPanelVolume::onCommitAnimatedMeshCheckbox(LLUICtrl *, void*) +{ + LLViewerObject* objectp = mObject; + if (!objectp || (objectp->getPCode() != LL_PCODE_VOLUME)) + { + return; + } + LLVOVolume *volobjp = (LLVOVolume *)objectp; + BOOL animated_mesh = getChild("Animated Mesh Checkbox Ctrl")->getValue(); + U32 flags = volobjp->getExtendedMeshFlags(); + U32 new_flags = flags; + if (animated_mesh) + { + new_flags |= LLExtendedMeshParams::ANIMATED_MESH_ENABLED_FLAG; + } + else + { + new_flags &= ~LLExtendedMeshParams::ANIMATED_MESH_ENABLED_FLAG; + } + if (new_flags != flags) + { + volobjp->setExtendedMeshFlags(new_flags); + } + + //refresh any bakes + if (volobjp) + { + volobjp->refreshBakeTexture(); + + LLViewerObject::const_child_list_t& child_list = volobjp->getChildren(); + for (const auto& iter : child_list) + { + LLViewerObject* objectp = iter; + if (objectp) + { + objectp->refreshBakeTexture(); + } + } + + if (gAgentAvatarp) + { + gAgentAvatarp->updateMeshVisibility(); + } + } +} + void LLPanelVolume::onCommitIsFlexible(LLUICtrl *, void*) { if (mObject->flagObjectPermanent()) diff --git a/indra/newview/llpanelvolume.h b/indra/newview/llpanelvolume.h index b82fc3916a..76a206f74b 100644 --- a/indra/newview/llpanelvolume.h +++ b/indra/newview/llpanelvolume.h @@ -53,7 +53,6 @@ class LLPanelVolume : public LLPanel virtual ~LLPanelVolume(); virtual void draw(); - virtual void clearCtrls(); virtual BOOL postBuild(); @@ -68,7 +67,8 @@ class LLPanelVolume : public LLPanel static void onCommitLight( LLUICtrl* ctrl, void* userdata); void onCommitIsFlexible( LLUICtrl* ctrl, void* userdata); static void onCommitFlexible( LLUICtrl* ctrl, void* userdata); - static void onCommitPhysicsParam( LLUICtrl* ctrl, void* userdata); + void onCommitAnimatedMeshCheckbox(LLUICtrl* ctrl, void* userdata); + static void onCommitPhysicsParam( LLUICtrl* ctrl, void* userdata); void onLightCancelColor(const LLSD& data); void onLightSelectColor(const LLSD& data); diff --git a/indra/newview/llparticipantlist.cpp b/indra/newview/llparticipantlist.cpp index 86db29ccbe..872b90514d 100644 --- a/indra/newview/llparticipantlist.cpp +++ b/indra/newview/llparticipantlist.cpp @@ -30,11 +30,12 @@ #include "llagent.h" #include "llmutelist.h" #include "llparticipantlist.h" -#include "llscrolllistctrl.h" -#include "llscrolllistitem.h" +#include "llnamelistctrl.h" #include "llspeakers.h" +#include "lluictrlfactory.h" // Edit: For menu duality +#include "llviewermenu.h" // Edit: For menu duality #include "llviewerwindow.h" -#include "llvoiceclient.h" +#include "llvoicechannel.h" // Edit: For menu duality #include "llworld.h" // Edit: For ghost detection // [RLVa:KB] #include "rlvhandler.h" @@ -43,7 +44,7 @@ LLParticipantList::LLParticipantList(LLSpeakerMgr* data_source, bool show_text_chatters) : mSpeakerMgr(data_source), - mAvatarList(NULL), + mAvatarList(nullptr), mShowTextChatters(show_text_chatters), mValidateSpeakerCallback(NULL) { @@ -58,16 +59,31 @@ LLParticipantList::LLParticipantList(LLSpeakerMgr* data_source, mSpeakerClearListener = new SpeakerClearListener(*this); //mSpeakerModeratorListener = new SpeakerModeratorUpdateListener(*this); mSpeakerMuteListener = new SpeakerMuteListener(*this); - + mSpeakerBatchBeginListener = new SpeakerBatchBeginListener(*this); + mSpeakerBatchEndListener = new SpeakerBatchEndListener(*this); + mSpeakerSortingUpdateListener = new SpeakerSortingUpdateListener(*this); mSpeakerMgr->addListener(mSpeakerAddListener, "add"); mSpeakerMgr->addListener(mSpeakerRemoveListener, "remove"); mSpeakerMgr->addListener(mSpeakerClearListener, "clear"); + mSpeakerMgr->addListener(mSpeakerBatchBeginListener, "batch_begin"); + mSpeakerMgr->addListener(mSpeakerBatchEndListener, "batch_end"); + mSpeakerMgr->addListener(mSpeakerSortingUpdateListener, "update_sorting"); //mSpeakerMgr->addListener(mSpeakerModeratorListener, "update_moderator"); } +void LLParticipantList::setupContextMenu() +{ + if (mSpeakerMgr->getVoiceChannel() == LLVoiceChannelProximal::getInstance()) + { + static LLMenuGL* menu = LLUICtrlFactory::getInstance()->buildMenu("menu_local_avs.xml", gMenuHolder); + mAvatarList->setContextMenu(menu); + } + else mAvatarList->setContextMenu(LFIDBearer::AVATAR); +} + BOOL LLParticipantList::postBuild() { - mAvatarList = getChild("speakers_list"); + mAvatarList = getChild("speakers_list"); mAvatarList->sortByColumn(gSavedSettings.getString("FloaterActiveSpeakersSortColumn"), gSavedSettings.getBOOL("FloaterActiveSpeakersSortAscending")); mAvatarList->setDoubleClickCallback(boost::bind(&LLParticipantList::onAvatarListDoubleClicked, this)); @@ -92,6 +108,7 @@ BOOL LLParticipantList::postBuild() // update speaker UI handleSpeakerSelect(); + setupContextMenu(); return true; } @@ -103,25 +120,6 @@ LLParticipantList::~LLParticipantList() mAvatarListRefreshConnection.disconnect(); mAvatarListReturnConnection.disconnect(); mAvatarListToggleIconsConnection.disconnect(); - - // It is possible Participant List will be re-created from LLCallFloater::onCurrentChannelChanged() - // See ticket EXT-3427 - // hide menu before deleting it to stop enable and check handlers from triggering. - if(mParticipantListMenu && !LLApp::isExiting()) - { - mParticipantListMenu->hide(); - } - - if (mParticipantListMenu) - { - delete mParticipantListMenu; - mParticipantListMenu = NULL; - } - - mAvatarList->setContextMenu(NULL); - mAvatarList->setComparator(NULL); - - delete mAvalineUpdater; */ } @@ -140,7 +138,7 @@ void LLParticipantList::handleSpeakerSelect() { const LLUUID& speaker_id = mAvatarList->getValue().asUUID(); LLPointer selected_speakerp = mSpeakerMgr->findSpeaker(speaker_id); - if (speaker_id.isNull() || selected_speakerp.isNull()) + if (speaker_id.isNull() || selected_speakerp.isNull() || mAvatarList->getNumSelected() != 1) { // Disable normal controls if (LLView* view = findChild("mute_btn")) @@ -226,6 +224,11 @@ void LLParticipantList::handleSpeakerSelect() void LLParticipantList::refreshSpeakers() { + if (mUpdateTimer.getElapsedTimeF32() < .5f) + { + return; + } + mUpdateTimer.reset(); // store off current selection and scroll state to preserve across list rebuilds const S32 scroll_pos = mAvatarList->getScrollInterface()->getScrollPos(); @@ -236,27 +239,42 @@ void LLParticipantList::refreshSpeakers() // panel and hasn't been motionless for more than a few seconds. see DEV-6655 -MG LLRect screen_rect; localRectToScreen(getLocalRect(), &screen_rect); - mSpeakerMgr->update(!(screen_rect.pointInRect(gViewerWindow->getCurrentMouseX(), gViewerWindow->getCurrentMouseY()) && gMouseIdleTimer.getElapsedTimeF32() < 5.f)); + bool resort_ok = !(screen_rect.pointInRect(gViewerWindow->getCurrentMouseX(), gViewerWindow->getCurrentMouseY()) && gMouseIdleTimer.getElapsedTimeF32() < 5.f); + mSpeakerMgr->update(resort_ok); + bool re_sort = false; + size_t start_pos = llmax(0, scroll_pos - 20); + size_t end_pos = scroll_pos + mAvatarList->getLinesPerPage() + 20; std::vector items = mAvatarList->getAllData(); + if (start_pos >= items.size()) + { + return; + } + size_t count = 0; for (std::vector::iterator item_it = items.begin(); item_it != items.end(); ++item_it) { + LLScrollListItem* itemp = (*item_it); LLPointer speakerp = mSpeakerMgr->findSpeaker(itemp->getUUID()); if (speakerp.isNull()) continue; - if (LLScrollListCell* icon_cell = itemp->getColumn(0)) + ++count; + + // Color changes. Only perform for rows that are near or in the viewable area. + if (count > start_pos && count <= end_pos) { - if (speakerp->mStatus == LLSpeaker::STATUS_MUTED) - { - icon_cell->setValue("mute_icon.tga"); - static const LLCachedControl sAscentMutedColor("AscentMutedColor"); - icon_cell->setColor(speakerp->mModeratorMutedVoice ? /*LLColor4::grey*/sAscentMutedColor : LLColor4(1.f, 71.f / 255.f, 71.f / 255.f, 1.f)); - } - else + if (LLScrollListCell* icon_cell = itemp->getColumn(0)) { - switch(llmin(2, llfloor((speakerp->mSpeechVolume / LLVoiceClient::OVERDRIVEN_POWER_LEVEL) * 3.f))) + if (speakerp->mStatus == LLSpeaker::STATUS_MUTED) + { + icon_cell->setValue("mute_icon.tga"); + static const LLCachedControl sAscentMutedColor("AscentMutedColor"); + icon_cell->setColor(speakerp->mModeratorMutedVoice ? /*LLColor4::grey*/sAscentMutedColor : LLColor4(1.f, 71.f / 255.f, 71.f / 255.f, 1.f)); + } + else { + switch (llmin(2, llfloor((speakerp->mSpeechVolume / LLVoiceClient::OVERDRIVEN_POWER_LEVEL) * 3.f))) + { case 0: icon_cell->setValue("icn_active-speakers-dot-lvl0.tga"); break; @@ -266,62 +284,68 @@ void LLParticipantList::refreshSpeakers() case 2: icon_cell->setValue("icn_active-speakers-dot-lvl2.tga"); break; + } + // non voice speakers have hidden icons, render as transparent + icon_cell->setColor(speakerp->mStatus > LLSpeaker::STATUS_VOICE_ACTIVE ? LLColor4::transparent : speakerp->mDotColor); } - // non voice speakers have hidden icons, render as transparent - icon_cell->setColor(speakerp->mStatus > LLSpeaker::STATUS_VOICE_ACTIVE ? LLColor4::transparent : speakerp->mDotColor); } - } - // update name column - if (LLScrollListCell* name_cell = itemp->getColumn(1)) - { - if (speakerp->mStatus == LLSpeaker::STATUS_NOT_IN_CHANNEL) + // update name column + if (LLScrollListCell* name_cell = itemp->getColumn(1)) { - // draw inactive speakers in different color - static const LLCachedControl sSpeakersInactive(gColors, "SpeakersInactive"); - name_cell->setColor(sSpeakersInactive); - } - else - { - // - bool found = mShowTextChatters || speakerp->mID == gAgentID; - const LLWorld::region_list_t& regions = LLWorld::getInstance()->getRegionList(); - for (LLWorld::region_list_t::const_iterator iter = regions.begin(); !found && iter != regions.end(); ++iter) + if (speakerp->mStatus == LLSpeaker::STATUS_NOT_IN_CHANNEL) { - // Are they in this sim? - if (const LLViewerRegion* regionp = *iter) - if (regionp->mMapAvatarIDs.find(speakerp->mID) != -1) - found = true; - } - if (!found) - { - static const LLCachedControl sSpeakersGhost(gColors, "SpeakersGhost"); - name_cell->setColor(sSpeakersGhost); + // draw inactive speakers in different color + static const LLCachedControl sSpeakersInactive(gColors, "SpeakersInactive"); + name_cell->setColor(sSpeakersInactive); } else - // { - static const LLCachedControl sDefaultListText(gColors, "DefaultListText"); - name_cell->setColor(sDefaultListText); + // + bool found = mShowTextChatters || speakerp->mID == gAgentID; + if (!found) + for (const LLViewerRegion* regionp : LLWorld::getInstance()->getRegionList()) + { + // Are they in this sim? + if (std::find(regionp->mMapAvatarIDs.begin(), regionp->mMapAvatarIDs.end(), speakerp->mID) != regionp->mMapAvatarIDs.end()) + { + found = true; + break; + } + } + if (!found) + { + static const LLCachedControl sSpeakersGhost(gColors, "SpeakersGhost"); + name_cell->setColor(sSpeakersGhost); + } + else + // + { + static const LLCachedControl sDefaultListText(gColors, "DefaultListText"); + name_cell->setColor(sDefaultListText); + } } } - + } + // update name column. Need to update all rows to make name sorting behave correctly. + if (LLScrollListCell* name_cell = itemp->getColumn(1)) + { std::string speaker_name = speakerp->mDisplayName.empty() ? LLCacheName::getDefaultName() : speakerp->mDisplayName; if (speakerp->mIsModerator) - speaker_name += " " + getString("moderator_label"); - name_cell->setValue(speaker_name); + speaker_name += ' ' + getString("moderator_label"); + if (name_cell->getValue().asString() != speaker_name) + { + re_sort = true; + name_cell->setValue(speaker_name); + } static_cast(name_cell)->setFontStyle(speakerp->mIsModerator ? LLFontGL::BOLD : LLFontGL::NORMAL); } - // update speaking order column - if (LLScrollListCell* speaking_status_cell = itemp->getColumn(2)) - { - // since we are forced to sort by text, encode sort order as string - // print speaking ordinal in a text-sorting friendly manner - speaking_status_cell->setValue(llformat("%010d", speakerp->mSortIndex)); - } } // we potentially modified the sort order by touching the list items - mAvatarList->setNeedsSort(); + if (re_sort) + { + mAvatarList->setNeedsSortColumn(1); + } // keep scroll value stable mAvatarList->getScrollInterface()->setScrollPos(scroll_pos); @@ -358,6 +382,7 @@ bool LLParticipantList::onRemoveItemEvent(LLPointer event, bool LLParticipantList::onClearListEvent(LLPointer event, const LLSD& userdata) { mAvatarList->clearRows(); + setupContextMenu(); return true; } @@ -378,6 +403,44 @@ bool LLParticipantList::onSpeakerMuteEvent(LLPointer event return true; } +void LLParticipantList::onSpeakerBatchBeginEvent() +{ + mAvatarList->setSortEnabled(false); +} + +void LLParticipantList::onSpeakerBatchEndEvent() +{ + mAvatarList->setSortEnabled(true); +} + +void LLParticipantList::onSpeakerSortingUpdateEvent() +{ + bool re_sort = false; + for (auto&& item : mAvatarList->getAllData()) + { + // update speaking order column + if (LLScrollListCell* speaking_status_cell = item->getColumn(2)) + { + LLPointer speakerp = mSpeakerMgr->findSpeaker(item->getUUID()); + if (speakerp) + { + re_sort = true; + std::string sort_index = llformat("%010d", speakerp->mSortIndex); + // since we are forced to sort by text, encode sort order as string + // print speaking ordinal in a text-sorting friendly manner + if (speaking_status_cell->getValue().asString() != sort_index) + { + speaking_status_cell->setValue(sort_index); + } + } + } + } + if (re_sort) + { + mAvatarList->setNeedsSortColumn(2); + } +} + void LLParticipantList::addAvatarIDExceptAgent(const LLUUID& avatar_id) { //if (mExcludeAgent && gAgent.getID() == avatar_id) return; @@ -405,22 +468,16 @@ void LLParticipantList::adjustParticipant(const LLUUID& speaker_id) LLPointer speakerp = mSpeakerMgr->findSpeaker(speaker_id); if (speakerp.isNull()) return; - LLSD row; - row["id"] = speaker_id; - LLSD& columns = row["columns"]; - columns[0]["column"] = "icon_speaking_status"; - columns[0]["type"] = "icon"; - columns[0]["value"] = "icn_active-speakers-dot-lvl0.tga"; - + LLNameListItem::Params name_item; + name_item.value = speaker_id; + name_item.columns.add(LLScrollListCell::Params().column("icon_speaking_status").type("icon").value("icn_active-speakers-dot-lvl0.tga")); const std::string& display_name = LLVoiceClient::getInstance()->getDisplayName(speaker_id); - columns[1]["column"] = "speaker_name"; - columns[1]["type"] = "text"; - columns[1]["value"] = display_name.empty() ? LLCacheName::getDefaultName() : display_name; + name_item.name = display_name; + name_item.columns.add(LLScrollListCell::Params().column("speaker_name").type("text").value(display_name)); + name_item.columns.add(LLScrollListCell::Params().column("speaking_status").type("text") + .value(llformat("%010d", speakerp->mSortIndex))); // print speaking ordinal in a text-sorting friendly manner - columns[2]["column"] = "speaking_status"; - columns[2]["type"] = "text"; - columns[2]["value"] = llformat("%010d", speakerp->mSortIndex); // print speaking ordinal in a text-sorting friendly manner - mAvatarList->addElement(row); + mAvatarList->addNameItemRow(name_item); // add listener to process moderation changes speakerp->addListener(mSpeakerMuteListener); @@ -468,6 +525,23 @@ bool LLParticipantList::SpeakerMuteListener::handleEvent(LLPointer event, const LLSD& userdata) +{ + mParent.onSpeakerBatchBeginEvent(); + return true; +} +bool LLParticipantList::SpeakerBatchEndListener::handleEvent(LLPointer event, const LLSD& userdata) +{ + mParent.onSpeakerBatchEndEvent(); + return true; +} + +bool LLParticipantList::SpeakerSortingUpdateListener::handleEvent(LLPointer event, const LLSD& userdata) +{ + mParent.onSpeakerSortingUpdateEvent(); + return true; +} + // Singu Note: The following functions are actually of the LLParticipantListMenu class, but we haven't married lists with menus yet. void LLParticipantList::toggleAllowTextChat(const LLSD& userdata) { @@ -490,7 +564,7 @@ void LLParticipantList::toggleMute(const LLSD& userdata, U32 flags) LLPointer speakerp = mSpeakerMgr->findSpeaker(speaker_id); if (speakerp.isNull()) { - LL_WARNS("Speakers") << "Speaker " << speaker_id << " not found" << llendl; + LL_WARNS("Speakers") << "Speaker " << speaker_id << " not found" << LL_ENDL; return; } diff --git a/indra/newview/llparticipantlist.h b/indra/newview/llparticipantlist.h index 1177b778a0..091753d5dc 100644 --- a/indra/newview/llparticipantlist.h +++ b/indra/newview/llparticipantlist.h @@ -30,7 +30,7 @@ #include "lllayoutstack.h" class LLSpeakerMgr; -class LLScrollListCtrl; +class LLNameListCtrl; class LLUICtrl; class LLParticipantList : public LLLayoutPanel @@ -76,6 +76,9 @@ class LLParticipantList : public LLLayoutPanel bool onClearListEvent(LLPointer event, const LLSD& userdata); //bool onModeratorUpdateEvent(LLPointer event, const LLSD& userdata); bool onSpeakerMuteEvent(LLPointer event, const LLSD& userdata); + void onSpeakerBatchBeginEvent(); + void onSpeakerBatchEndEvent(); + void onSpeakerSortingUpdateEvent(); /** * List of listeners implementing LLOldEvents::LLSimpleListener. @@ -126,6 +129,27 @@ class LLParticipantList : public LLLayoutPanel /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata); }; + class SpeakerBatchBeginListener : public BaseSpeakerListener + { + public: + SpeakerBatchBeginListener(LLParticipantList& parent) : BaseSpeakerListener(parent) {} + /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata); + }; + + class SpeakerBatchEndListener : public BaseSpeakerListener + { + public: + SpeakerBatchEndListener(LLParticipantList& parent) : BaseSpeakerListener(parent) {} + /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata); + }; + + class SpeakerSortingUpdateListener : public BaseSpeakerListener + { + public: + SpeakerSortingUpdateListener(LLParticipantList& parent) : BaseSpeakerListener(parent) {} + /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata); + }; + /** * Menu used in the participant list. class LLParticipantListMenu : public LLListContextMenu @@ -179,6 +203,7 @@ class LLParticipantList : public LLLayoutPanel private: void onAvatarListDoubleClicked(); + void setupContextMenu(); /** * Adjusts passed participant to work properly. @@ -194,14 +219,18 @@ class LLParticipantList : public LLLayoutPanel void onVolumeChange(const LLSD& param); LLSpeakerMgr* mSpeakerMgr; - LLScrollListCtrl* mAvatarList; + LLNameListCtrl* mAvatarList; bool mShowTextChatters; + LLFrameTimer mUpdateTimer; LLPointer mSpeakerAddListener; LLPointer mSpeakerRemoveListener; LLPointer mSpeakerClearListener; //LLPointer mSpeakerModeratorListener; LLPointer mSpeakerMuteListener; + LLPointer mSpeakerBatchBeginListener; + LLPointer mSpeakerBatchEndListener; + LLPointer mSpeakerSortingUpdateListener; validate_speaker_callback_t mValidateSpeakerCallback; }; diff --git a/indra/newview/llpatchvertexarray.cpp b/indra/newview/llpatchvertexarray.cpp index 4eab931670..044bd376e3 100644 --- a/indra/newview/llpatchvertexarray.cpp +++ b/indra/newview/llpatchvertexarray.cpp @@ -82,7 +82,8 @@ void LLPatchVertexArray::create(U32 surface_width, U32 patch_width, F32 meters_p surface_order += 1; } - if (power_of_two == (surface_width-1)) + if (power_of_two != (surface_width-1)) + surface_width = power_of_two + 1; { mSurfaceWidth = surface_width; @@ -99,16 +100,11 @@ void LLPatchVertexArray::create(U32 surface_width, U32 patch_width, F32 meters_p power_of_two *= 2; patch_order += 1; } - if (power_of_two == patch_width) - { - mPatchWidth = patch_width; - mPatchOrder = patch_order; - } - else // patch_width is not a power of two... - { - mPatchWidth = 0; - mPatchOrder = 0; - } + if (power_of_two != patch_width) + patch_width = power_of_two; + + mPatchWidth = patch_width; + mPatchOrder = patch_order; } else // patch_width is not a factor of (surface_width - 1)... { @@ -116,12 +112,6 @@ void LLPatchVertexArray::create(U32 surface_width, U32 patch_width, F32 meters_p mPatchOrder = 0; } } - else // surface_width is not a power of two... - { - mSurfaceWidth = 0; - mPatchWidth = 0; - mPatchOrder = 0; - } // PART 2 -- Allocate memory for the render level table if (mPatchWidth > 0) @@ -134,7 +124,7 @@ void LLPatchVertexArray::create(U32 surface_width, U32 patch_width, F32 meters_p { // init() and some other things all want to deref these // pointers, so this is serious. - llerrs << "mRenderLevelp or mRenderStridep was NULL; we'd crash soon." << llendl; + LL_ERRS() << "mRenderLevelp or mRenderStridep was NULL; we'd crash soon." << LL_ENDL; return; } diff --git a/indra/newview/llpathfindingmanager.cpp b/indra/newview/llpathfindingmanager.cpp index 7e5bec5468..8c8096991a 100644 --- a/indra/newview/llpathfindingmanager.cpp +++ b/indra/newview/llpathfindingmanager.cpp @@ -34,7 +34,10 @@ #include #include +#ifndef BOOST_FUNCTION_HPP_INCLUDED #include +#define BOOST_FUNCTION_HPP_INCLUDED +#endif #include #include @@ -56,15 +59,6 @@ #include "llviewerregion.h" #include "llweb.h" -class AIHTTPTimeoutPolicy; -extern AIHTTPTimeoutPolicy navMeshStatusResponder_timeout; -extern AIHTTPTimeoutPolicy navMeshResponder_timeout; -extern AIHTTPTimeoutPolicy agentStateResponder_timeout; -extern AIHTTPTimeoutPolicy navMeshRebakeResponder_timeout; -extern AIHTTPTimeoutPolicy objectLinksetsResponder_timeout; -extern AIHTTPTimeoutPolicy terrainLinksetsResponder_timeout; -extern AIHTTPTimeoutPolicy charactersResponder_timeout; - #define CAP_SERVICE_RETRIEVE_NAVMESH "RetrieveNavMeshSrc" #define CAP_SERVICE_NAVMESH_STATUS "NavMeshGenerationStatus" @@ -112,19 +106,18 @@ LLHTTPRegistration gHTTPRegistrationAgentStateChangeNode class NavMeshStatusResponder : public LLHTTPClient::ResponderWithResult { + LOG_CLASS(NavMeshStatusResponder); public: - NavMeshStatusResponder(const std::string &pCapabilityURL, LLViewerRegion *pRegion, bool pIsGetStatusOnly); + NavMeshStatusResponder(LLViewerRegion *pRegion, bool pIsGetStatusOnly); virtual ~NavMeshStatusResponder(); - /*virtual*/ void result(const LLSD &pContent); - /*virtual*/ void error(U32 pStatus, const std::string& pReason); - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return navMeshStatusResponder_timeout; } /*virtual*/ char const* getName(void) const { return "NavMeshStatusResponder"; } protected: + virtual void httpSuccess(); + virtual void httpFailure(); private: - std::string mCapabilityURL; LLViewerRegion *mRegion; LLUUID mRegionUUID; bool mIsGetStatusOnly; @@ -136,19 +129,18 @@ class NavMeshStatusResponder : public LLHTTPClient::ResponderWithResult class NavMeshResponder : public LLHTTPClient::ResponderWithResult { + LOG_CLASS(NavMeshResponder); public: - NavMeshResponder(const std::string &pCapabilityURL, U32 pNavMeshVersion, LLPathfindingNavMeshPtr pNavMeshPtr); + NavMeshResponder(U32 pNavMeshVersion, LLPathfindingNavMeshPtr pNavMeshPtr); virtual ~NavMeshResponder(); - /*virtual*/ void result(const LLSD &pContent); - /*virtual*/ void error(U32 pStatus, const std::string& pReason); - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return navMeshResponder_timeout; } /*virtual*/ char const* getName(void) const { return "NavMeshResponder"; } protected: + virtual void httpSuccess(); + virtual void httpFailure(); private: - std::string mCapabilityURL; U32 mNavMeshVersion; LLPathfindingNavMeshPtr mNavMeshPtr; }; @@ -159,20 +151,16 @@ class NavMeshResponder : public LLHTTPClient::ResponderWithResult class AgentStateResponder : public LLHTTPClient::ResponderWithResult { + LOG_CLASS(AgentStateResponder); public: - AgentStateResponder(const std::string &pCapabilityURL); + AgentStateResponder(); virtual ~AgentStateResponder(); - /*virtual*/ void result(const LLSD &pContent); - /*virtual*/ void error(U32 pStatus, const std::string& pReason); - /*virtual*/ bool followRedir(void) const { return true; } - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return agentStateResponder_timeout; } /*virtual*/ char const* getName(void) const { return "AgentStateResponder"; } protected: - -private: - std::string mCapabilityURL; + virtual void httpSuccess(); + virtual void httpFailure(); }; @@ -181,19 +169,18 @@ class AgentStateResponder : public LLHTTPClient::ResponderWithResult //--------------------------------------------------------------------------- class NavMeshRebakeResponder : public LLHTTPClient::ResponderWithResult { + LOG_CLASS(NavMeshRebakeResponder); public: - NavMeshRebakeResponder(const std::string &pCapabilityURL, LLPathfindingManager::rebake_navmesh_callback_t pRebakeNavMeshCallback); + NavMeshRebakeResponder(LLPathfindingManager::rebake_navmesh_callback_t pRebakeNavMeshCallback); virtual ~NavMeshRebakeResponder(); - /*virtual*/ void result(const LLSD &pContent); - /*virtual*/ void error(U32 pStatus, const std::string& pReason); - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return navMeshRebakeResponder_timeout; } /*virtual*/ char const* getName(void) const { return "NavMeshRebakeResponder"; } protected: + virtual void httpSuccess(); + virtual void httpFailure(); private: - std::string mCapabilityURL; LLPathfindingManager::rebake_navmesh_callback_t mRebakeNavMeshCallback; }; @@ -208,9 +195,9 @@ class LinksetsResponder virtual ~LinksetsResponder(); void handleObjectLinksetsResult(const LLSD &pContent); - void handleObjectLinksetsError(U32 pStatus, const std::string &pReason, const std::string &pURL); + void handleObjectLinksetsError(); void handleTerrainLinksetsResult(const LLSD &pContent); - void handleTerrainLinksetsError(U32 pStatus, const std::string &pReason, const std::string &pURL); + void handleTerrainLinksetsError(); protected: @@ -242,19 +229,18 @@ typedef boost::shared_ptr LinksetsResponderPtr; //--------------------------------------------------------------------------- class ObjectLinksetsResponder : public LLHTTPClient::ResponderWithResult { + LOG_CLASS(ObjectLinksetsResponder); public: - ObjectLinksetsResponder(const std::string &pCapabilityURL, LinksetsResponderPtr pLinksetsResponsderPtr); + ObjectLinksetsResponder(LinksetsResponderPtr pLinksetsResponsderPtr); virtual ~ObjectLinksetsResponder(); - /*virtual*/ void result(const LLSD &pContent); - /*virtual*/ void error(U32 pStatus, const std::string &pReason); - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return objectLinksetsResponder_timeout; } /*virtual*/ char const* getName(void) const { return "ObjectLinksetsResponder"; } protected: + virtual void httpSuccess(); + virtual void httpFailure(); private: - std::string mCapabilityURL; LinksetsResponderPtr mLinksetsResponsderPtr; }; @@ -263,19 +249,18 @@ class ObjectLinksetsResponder : public LLHTTPClient::ResponderWithResult //--------------------------------------------------------------------------- class TerrainLinksetsResponder : public LLHTTPClient::ResponderWithResult { + LOG_CLASS(TerrainLinksetsResponder); public: - TerrainLinksetsResponder(const std::string &pCapabilityURL, LinksetsResponderPtr pLinksetsResponsderPtr); + TerrainLinksetsResponder(LinksetsResponderPtr pLinksetsResponsderPtr); virtual ~TerrainLinksetsResponder(); - /*virtual*/ void result(const LLSD &pContent); - /*virtual*/ void error(U32 pStatus, const std::string &pReason); - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return terrainLinksetsResponder_timeout; } /*virtual*/ char const* getName(void) const { return "TerrainLinksetsResponder"; } protected: + virtual void httpSuccess(); + virtual void httpFailure(); private: - std::string mCapabilityURL; LinksetsResponderPtr mLinksetsResponsderPtr; }; @@ -284,19 +269,18 @@ class TerrainLinksetsResponder : public LLHTTPClient::ResponderWithResult //--------------------------------------------------------------------------- class CharactersResponder : public LLHTTPClient::ResponderWithResult { + LOG_CLASS(TerrainLinksetsResponder); public: - CharactersResponder(const std::string &pCapabilityURL, LLPathfindingManager::request_id_t pRequestId, LLPathfindingManager::object_request_callback_t pCharactersCallback); + CharactersResponder(LLPathfindingManager::request_id_t pRequestId, LLPathfindingManager::object_request_callback_t pCharactersCallback); virtual ~CharactersResponder(); - /*virtual*/ void result(const LLSD &pContent); - /*virtual*/ void error(U32 pStatus, const std::string &pReason); - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return charactersResponder_timeout; } /*virtual*/ char const* getName(void) const { return "CharactersResponder"; } protected: + virtual void httpSuccess(); + virtual void httpFailure(); private: - std::string mCapabilityURL; LLPathfindingManager::request_id_t mRequestId; LLPathfindingManager::object_request_callback_t mCharactersCallback; }; @@ -383,7 +367,7 @@ void LLPathfindingManager::requestGetNavMeshForRegion(LLViewerRegion *pRegion, b std::string navMeshStatusURL = getNavMeshStatusURLForRegion(pRegion); llassert(!navMeshStatusURL.empty()); navMeshPtr->handleNavMeshCheckVersion(); - LLHTTPClient::ResponderPtr navMeshStatusResponder = new NavMeshStatusResponder(navMeshStatusURL, pRegion, pIsGetStatusOnly); + LLHTTPClient::ResponderPtr navMeshStatusResponder = new NavMeshStatusResponder(pRegion, pIsGetStatusOnly); LLHTTPClient::get(navMeshStatusURL, navMeshStatusResponder); } } @@ -417,12 +401,12 @@ void LLPathfindingManager::requestGetLinksets(request_id_t pRequestId, object_re bool doRequestTerrain = isAllowViewTerrainProperties(); LinksetsResponderPtr linksetsResponderPtr(new LinksetsResponder(pRequestId, pLinksetsCallback, true, doRequestTerrain)); - LLHTTPClient::ResponderPtr objectLinksetsResponder = new ObjectLinksetsResponder(objectLinksetsURL, linksetsResponderPtr); + LLHTTPClient::ResponderPtr objectLinksetsResponder = new ObjectLinksetsResponder(linksetsResponderPtr); LLHTTPClient::get(objectLinksetsURL, objectLinksetsResponder); if (doRequestTerrain) { - LLHTTPClient::ResponderPtr terrainLinksetsResponder = new TerrainLinksetsResponder(terrainLinksetsURL, linksetsResponderPtr); + LLHTTPClient::ResponderPtr terrainLinksetsResponder = new TerrainLinksetsResponder(linksetsResponderPtr); LLHTTPClient::get(terrainLinksetsURL, terrainLinksetsResponder); } } @@ -466,13 +450,13 @@ void LLPathfindingManager::requestSetLinksets(request_id_t pRequestId, const LLP if (!objectPostData.isUndefined()) { - LLHTTPClient::ResponderPtr objectLinksetsResponder = new ObjectLinksetsResponder(objectLinksetsURL, linksetsResponderPtr); + LLHTTPClient::ResponderPtr objectLinksetsResponder = new ObjectLinksetsResponder(linksetsResponderPtr); LLHTTPClient::put(objectLinksetsURL, objectPostData, objectLinksetsResponder); } if (!terrainPostData.isUndefined()) { - LLHTTPClient::ResponderPtr terrainLinksetsResponder = new TerrainLinksetsResponder(terrainLinksetsURL, linksetsResponderPtr); + LLHTTPClient::ResponderPtr terrainLinksetsResponder = new TerrainLinksetsResponder(linksetsResponderPtr); LLHTTPClient::put(terrainLinksetsURL, terrainPostData, terrainLinksetsResponder); } } @@ -505,7 +489,7 @@ void LLPathfindingManager::requestGetCharacters(request_id_t pRequestId, object_ { pCharactersCallback(pRequestId, kRequestStarted, emptyCharacterListPtr); - LLHTTPClient::ResponderPtr charactersResponder = new CharactersResponder(charactersURL, pRequestId, pCharactersCallback); + LLHTTPClient::ResponderPtr charactersResponder = new CharactersResponder(pRequestId, pCharactersCallback); LLHTTPClient::get(charactersURL, charactersResponder); } } @@ -538,7 +522,7 @@ void LLPathfindingManager::requestGetAgentState() { std::string agentStateURL = getAgentStateURLForRegion(currentRegion); llassert(!agentStateURL.empty()); - LLHTTPClient::ResponderPtr responder = new AgentStateResponder(agentStateURL); + LLHTTPClient::ResponderPtr responder = new AgentStateResponder(); LLHTTPClient::get(agentStateURL, responder); } } @@ -562,7 +546,7 @@ void LLPathfindingManager::requestRebakeNavMesh(rebake_navmesh_callback_t pRebak llassert(!navMeshStatusURL.empty()); LLSD postData; postData["command"] = "rebuild"; - LLHTTPClient::ResponderPtr responder = new NavMeshRebakeResponder(navMeshStatusURL, pRebakeNavMeshCallback); + LLHTTPClient::ResponderPtr responder = new NavMeshRebakeResponder(pRebakeNavMeshCallback); LLHTTPClient::post(navMeshStatusURL, postData, responder); } } @@ -584,7 +568,7 @@ void LLPathfindingManager::sendRequestGetNavMeshForRegion(LLPathfindingNavMeshPt else { navMeshPtr->handleNavMeshStart(pNavMeshStatus); - LLHTTPClient::ResponderPtr responder = new NavMeshResponder(navMeshURL, pNavMeshStatus.getVersion(), navMeshPtr); + LLHTTPClient::ResponderPtr responder = new NavMeshResponder(pNavMeshStatus.getVersion(), navMeshPtr); LLSD postData; LLHTTPClient::post(navMeshURL, postData, responder); @@ -755,8 +739,8 @@ std::string LLPathfindingManager::getCapabilityURLForRegion(LLViewerRegion *pReg if (capabilityURL.empty()) { - llwarns << "cannot find capability '" << pCapabilityName << "' for current region '" - << ((pRegion != NULL) ? pRegion->getName() : "") << "'" << llendl; + LL_WARNS() << "cannot find capability '" << pCapabilityName << "' for current region '" + << ((pRegion != NULL) ? pRegion->getName() : "") << "'" << LL_ENDL; } return capabilityURL; @@ -798,8 +782,8 @@ void LLAgentStateChangeNode::post(ResponsePtr pResponse, const LLSD &pContext, c // NavMeshStatusResponder //--------------------------------------------------------------------------- -NavMeshStatusResponder::NavMeshStatusResponder(const std::string &pCapabilityURL, LLViewerRegion *pRegion, bool pIsGetStatusOnly) : - mCapabilityURL(pCapabilityURL), +NavMeshStatusResponder::NavMeshStatusResponder(LLViewerRegion *pRegion, bool pIsGetStatusOnly) + : mRegion(pRegion), mRegionUUID(), mIsGetStatusOnly(pIsGetStatusOnly) @@ -814,15 +798,15 @@ NavMeshStatusResponder::~NavMeshStatusResponder() { } -void NavMeshStatusResponder::result(const LLSD &pContent) +void NavMeshStatusResponder::httpSuccess() { - LLPathfindingNavMeshStatus navMeshStatus(mRegionUUID, pContent); + LLPathfindingNavMeshStatus navMeshStatus(mRegionUUID, getContent()); LLPathfindingManager::getInstance()->handleNavMeshStatusRequest(navMeshStatus, mRegion, mIsGetStatusOnly); } -void NavMeshStatusResponder::error(U32 pStatus, const std::string& pReason) +void NavMeshStatusResponder::httpFailure() { - llwarns << "error with request to URL '" << mCapabilityURL << "' because " << pReason << " (statusCode:" << pStatus << ")" << llendl; + LL_WARNS() << dumpResponse() << LL_ENDL; LLPathfindingNavMeshStatus navMeshStatus(mRegionUUID); LLPathfindingManager::getInstance()->handleNavMeshStatusRequest(navMeshStatus, mRegion, mIsGetStatusOnly); } @@ -831,8 +815,8 @@ void NavMeshStatusResponder::error(U32 pStatus, const std::string& pReason) // NavMeshResponder //--------------------------------------------------------------------------- -NavMeshResponder::NavMeshResponder(const std::string &pCapabilityURL, U32 pNavMeshVersion, LLPathfindingNavMeshPtr pNavMeshPtr) : - mCapabilityURL(pCapabilityURL), +NavMeshResponder::NavMeshResponder(U32 pNavMeshVersion, LLPathfindingNavMeshPtr pNavMeshPtr) + : mNavMeshVersion(pNavMeshVersion), mNavMeshPtr(pNavMeshPtr) { @@ -842,21 +826,22 @@ NavMeshResponder::~NavMeshResponder() { } -void NavMeshResponder::result(const LLSD &pContent) +void NavMeshResponder::httpSuccess() { - mNavMeshPtr->handleNavMeshResult(pContent, mNavMeshVersion); + mNavMeshPtr->handleNavMeshResult(getContent(), mNavMeshVersion); } -void NavMeshResponder::error(U32 pStatus, const std::string& pReason) +void NavMeshResponder::httpFailure() { - mNavMeshPtr->handleNavMeshError(pStatus, pReason, mCapabilityURL, mNavMeshVersion); + LL_WARNS() << dumpResponse() << LL_ENDL; + mNavMeshPtr->handleNavMeshError(mNavMeshVersion); } //--------------------------------------------------------------------------- // AgentStateResponder //--------------------------------------------------------------------------- -AgentStateResponder::AgentStateResponder(const std::string &pCapabilityURL) : mCapabilityURL(pCapabilityURL) +AgentStateResponder::AgentStateResponder() { } @@ -864,17 +849,18 @@ AgentStateResponder::~AgentStateResponder() { } -void AgentStateResponder::result(const LLSD &pContent) +void AgentStateResponder::httpSuccess() { + const LLSD& pContent = getContent(); llassert(pContent.has(AGENT_STATE_CAN_REBAKE_REGION_FIELD)); llassert(pContent.get(AGENT_STATE_CAN_REBAKE_REGION_FIELD).isBoolean()); BOOL canRebakeRegion = pContent.get(AGENT_STATE_CAN_REBAKE_REGION_FIELD).asBoolean(); LLPathfindingManager::getInstance()->handleAgentState(canRebakeRegion); } -void AgentStateResponder::error(U32 pStatus, const std::string &pReason) +void AgentStateResponder::httpFailure() { - llwarns << "error with request to URL '" << mCapabilityURL << "' because " << pReason << " (statusCode:" << pStatus << ")" << llendl; + LL_WARNS() << dumpResponse() << LL_ENDL; LLPathfindingManager::getInstance()->handleAgentState(FALSE); } @@ -882,8 +868,8 @@ void AgentStateResponder::error(U32 pStatus, const std::string &pReason) //--------------------------------------------------------------------------- // navmesh rebake responder //--------------------------------------------------------------------------- -NavMeshRebakeResponder::NavMeshRebakeResponder(const std::string &pCapabilityURL, LLPathfindingManager::rebake_navmesh_callback_t pRebakeNavMeshCallback) : - mCapabilityURL(pCapabilityURL), +NavMeshRebakeResponder::NavMeshRebakeResponder(LLPathfindingManager::rebake_navmesh_callback_t pRebakeNavMeshCallback) + : mRebakeNavMeshCallback(pRebakeNavMeshCallback) { } @@ -892,14 +878,14 @@ NavMeshRebakeResponder::~NavMeshRebakeResponder() { } -void NavMeshRebakeResponder::result(const LLSD &pContent) +void NavMeshRebakeResponder::httpSuccess() { mRebakeNavMeshCallback(true); } -void NavMeshRebakeResponder::error(U32 pStatus, const std::string &pReason) +void NavMeshRebakeResponder::httpFailure() { - llwarns << "error with request to URL '" << mCapabilityURL << "' because " << pReason << " (statusCode:" << pStatus << ")" << llendl; + LL_WARNS() << dumpResponse() << LL_ENDL; mRebakeNavMeshCallback(false); } @@ -932,9 +918,9 @@ void LinksetsResponder::handleObjectLinksetsResult(const LLSD &pContent) } } -void LinksetsResponder::handleObjectLinksetsError(U32 pStatus, const std::string &pReason, const std::string &pURL) +void LinksetsResponder::handleObjectLinksetsError() { - llwarns << "error with request to URL '" << pURL << "' because " << pReason << " (statusCode:" << pStatus << ")" << llendl; + LL_WARNS() << "LinksetsResponder object linksets error" << LL_ENDL; mObjectMessagingState = kReceivedError; if (mTerrainMessagingState != kWaiting) { @@ -953,8 +939,9 @@ void LinksetsResponder::handleTerrainLinksetsResult(const LLSD &pContent) } } -void LinksetsResponder::handleTerrainLinksetsError(U32 pStatus, const std::string &pReason, const std::string &pURL) +void LinksetsResponder::handleTerrainLinksetsError() { + LL_WARNS() << "LinksetsResponder terrain linksets error" << LL_ENDL; mTerrainMessagingState = kReceivedError; if (mObjectMessagingState != kWaiting) { @@ -988,8 +975,8 @@ void LinksetsResponder::sendCallback() // ObjectLinksetsResponder //--------------------------------------------------------------------------- -ObjectLinksetsResponder::ObjectLinksetsResponder(const std::string &pCapabilityURL, LinksetsResponderPtr pLinksetsResponsderPtr) : - mCapabilityURL(pCapabilityURL), +ObjectLinksetsResponder::ObjectLinksetsResponder(LinksetsResponderPtr pLinksetsResponsderPtr) + : mLinksetsResponsderPtr(pLinksetsResponsderPtr) { } @@ -998,22 +985,23 @@ ObjectLinksetsResponder::~ObjectLinksetsResponder() { } -void ObjectLinksetsResponder::result(const LLSD &pContent) +void ObjectLinksetsResponder::httpSuccess() { - mLinksetsResponsderPtr->handleObjectLinksetsResult(pContent); + mLinksetsResponsderPtr->handleObjectLinksetsResult(getContent()); } -void ObjectLinksetsResponder::error(U32 pStatus, const std::string &pReason) +void ObjectLinksetsResponder::httpFailure() { - mLinksetsResponsderPtr->handleObjectLinksetsError(pStatus, pReason, mCapabilityURL); + LL_WARNS() << dumpResponse() << LL_ENDL; + mLinksetsResponsderPtr->handleObjectLinksetsError(); } //--------------------------------------------------------------------------- // TerrainLinksetsResponder //--------------------------------------------------------------------------- -TerrainLinksetsResponder::TerrainLinksetsResponder(const std::string &pCapabilityURL, LinksetsResponderPtr pLinksetsResponsderPtr) : - mCapabilityURL(pCapabilityURL), +TerrainLinksetsResponder::TerrainLinksetsResponder(LinksetsResponderPtr pLinksetsResponsderPtr) + : mLinksetsResponsderPtr(pLinksetsResponsderPtr) { } @@ -1022,22 +1010,23 @@ TerrainLinksetsResponder::~TerrainLinksetsResponder() { } -void TerrainLinksetsResponder::result(const LLSD &pContent) +void TerrainLinksetsResponder::httpSuccess() { - mLinksetsResponsderPtr->handleTerrainLinksetsResult(pContent); + mLinksetsResponsderPtr->handleTerrainLinksetsResult(getContent()); } -void TerrainLinksetsResponder::error(U32 pStatus, const std::string &pReason) +void TerrainLinksetsResponder::httpFailure() { - mLinksetsResponsderPtr->handleTerrainLinksetsError(pStatus, pReason, mCapabilityURL); + LL_WARNS() << dumpResponse() << LL_ENDL; + mLinksetsResponsderPtr->handleTerrainLinksetsError(); } //--------------------------------------------------------------------------- // CharactersResponder //--------------------------------------------------------------------------- -CharactersResponder::CharactersResponder(const std::string &pCapabilityURL, LLPathfindingManager::request_id_t pRequestId, LLPathfindingManager::object_request_callback_t pCharactersCallback) : - mCapabilityURL(pCapabilityURL), +CharactersResponder::CharactersResponder(LLPathfindingManager::request_id_t pRequestId, LLPathfindingManager::object_request_callback_t pCharactersCallback) + : mRequestId(pRequestId), mCharactersCallback(pCharactersCallback) { @@ -1047,15 +1036,15 @@ CharactersResponder::~CharactersResponder() { } -void CharactersResponder::result(const LLSD &pContent) +void CharactersResponder::httpSuccess() { - LLPathfindingObjectListPtr characterListPtr = LLPathfindingObjectListPtr(new LLPathfindingCharacterList(pContent)); + LLPathfindingObjectListPtr characterListPtr = LLPathfindingObjectListPtr(new LLPathfindingCharacterList(getContent())); mCharactersCallback(mRequestId, LLPathfindingManager::kRequestCompleted, characterListPtr); } -void CharactersResponder::error(U32 pStatus, const std::string &pReason) +void CharactersResponder::httpFailure() { - llwarns << "error with request to URL '" << mCapabilityURL << "' because " << pReason << " (statusCode:" << pStatus << ")" << llendl; + LL_WARNS() << dumpResponse() << LL_ENDL; LLPathfindingObjectListPtr characterListPtr = LLPathfindingObjectListPtr(new LLPathfindingCharacterList()); mCharactersCallback(mRequestId, LLPathfindingManager::kRequestError, characterListPtr); diff --git a/indra/newview/llpathfindingmanager.h b/indra/newview/llpathfindingmanager.h index c61ff244fc..3a2d2d0dc1 100644 --- a/indra/newview/llpathfindingmanager.h +++ b/indra/newview/llpathfindingmanager.h @@ -30,7 +30,10 @@ #include #include +#ifndef BOOST_FUNCTION_HPP_INCLUDED #include +#define BOOST_FUNCTION_HPP_INCLUDED +#endif #include #include "llpathfindinglinkset.h" diff --git a/indra/newview/llpathfindingnavmesh.cpp b/indra/newview/llpathfindingnavmesh.cpp index e01dd3a152..0287c07f96 100644 --- a/indra/newview/llpathfindingnavmesh.cpp +++ b/indra/newview/llpathfindingnavmesh.cpp @@ -129,7 +129,7 @@ void LLPathfindingNavMesh::handleNavMeshResult(const LLSD &pContent, U32 pNavMes llassert(embeddedNavMeshVersion == pNavMeshVersion); // stinson 03/13/2012 : does this ever occur? if (embeddedNavMeshVersion != pNavMeshVersion) { - llwarns << "Mismatch between expected and embedded navmesh versions occurred" << llendl; + LL_WARNS() << "Mismatch between expected and embedded navmesh versions occurred" << LL_ENDL; pNavMeshVersion = embeddedNavMeshVersion; } } @@ -148,7 +148,7 @@ void LLPathfindingNavMesh::handleNavMeshResult(const LLSD &pContent, U32 pNavMes U8* pUncompressedNavMeshContainer = unzip_llsdNavMesh( valid, decompBinSize, streamdecomp, binSize ) ; if ( !valid ) { - llwarns << "Unable to decompress the navmesh llsd." << llendl; + LL_WARNS() << "Unable to decompress the navmesh llsd." << LL_ENDL; status = kNavMeshRequestError; } else @@ -165,7 +165,7 @@ void LLPathfindingNavMesh::handleNavMeshResult(const LLSD &pContent, U32 pNavMes } else { - llwarns << "No mesh data received" << llendl; + LL_WARNS() << "No mesh data received" << LL_ENDL; status = kNavMeshRequestError; } setRequestStatus(status); @@ -184,9 +184,8 @@ void LLPathfindingNavMesh::handleNavMeshError() setRequestStatus(kNavMeshRequestError); } -void LLPathfindingNavMesh::handleNavMeshError(U32 pStatus, const std::string &pReason, const std::string &pURL, U32 pNavMeshVersion) +void LLPathfindingNavMesh::handleNavMeshError(U32 pNavMeshVersion) { - llwarns << "error with request to URL '" << pURL << "' because " << pReason << " (statusCode:" << pStatus << ")" << llendl; if (mNavMeshStatus.getVersion() == pNavMeshVersion) { handleNavMeshError(); diff --git a/indra/newview/llpathfindingnavmesh.h b/indra/newview/llpathfindingnavmesh.h index 7a844f54ce..7692a7bf49 100644 --- a/indra/newview/llpathfindingnavmesh.h +++ b/indra/newview/llpathfindingnavmesh.h @@ -30,7 +30,10 @@ #include #include +#ifndef BOOST_FUNCTION_HPP_INCLUDED #include +#define BOOST_FUNCTION_HPP_INCLUDED +#endif #include #include "llpathfindingnavmeshstatus.h" @@ -74,7 +77,7 @@ class LLPathfindingNavMesh void handleNavMeshResult(const LLSD &pContent, U32 pNavMeshVersion); void handleNavMeshNotEnabled(); void handleNavMeshError(); - void handleNavMeshError(U32 pStatus, const std::string &pReason, const std::string &pURL, U32 pNavMeshVersion); + void handleNavMeshError(U32 pNavMeshVersion); protected: diff --git a/indra/newview/llpathfindingobject.h b/indra/newview/llpathfindingobject.h index b8d3ca2364..1c7df6db40 100644 --- a/indra/newview/llpathfindingobject.h +++ b/indra/newview/llpathfindingobject.h @@ -30,7 +30,10 @@ #include #include +#ifndef BOOST_FUNCTION_HPP_INCLUDED #include +#define BOOST_FUNCTION_HPP_INCLUDED +#endif #include #include "llavatarname.h" diff --git a/indra/newview/llphysicsmotion.cpp b/indra/newview/llphysicsmotion.cpp index 6fc0ab438f..5e3360264d 100644 --- a/indra/newview/llphysicsmotion.cpp +++ b/indra/newview/llphysicsmotion.cpp @@ -232,7 +232,7 @@ BOOL LLPhysicsMotion::initialize() mParamDriver = (LLViewerVisualParam*)mCharacter->getVisualParam(mParamDriverName.c_str()); if (mParamDriver == NULL) { - llinfos << "Failure reading in [ " << mParamDriverName << " ]" << llendl; + LL_INFOS() << "Failure reading in [ " << mParamDriverName << " ]" << LL_ENDL; return FALSE; } @@ -314,8 +314,8 @@ void LLPhysicsMotion::getString(std::ostringstream &oss) } } -LLPhysicsMotionController::LLPhysicsMotionController(const LLUUID &id) : - LLMotion(id), +LLPhysicsMotionController::LLPhysicsMotionController(LLUUID const& id, LLMotionController* controller) : + AIMaskedMotion(id, controller, ANIM_AGENT_PHYSICS_MOTION), mCharacter(NULL), mIsDefault(true) { @@ -332,15 +332,6 @@ LLPhysicsMotionController::~LLPhysicsMotionController() } } -BOOL LLPhysicsMotionController::onActivate() -{ - return TRUE; -} - -void LLPhysicsMotionController::onDeactivate() -{ -} - LLMotion::LLMotionInitStatus LLPhysicsMotionController::onInitialize(LLCharacter *character) { mCharacter = character; @@ -889,4 +880,4 @@ void LLPhysicsMotion::reset() mCharacter->setVisualParamWeight((*iter).mParam,(*iter).mParam->getDefaultWeight()); } } -} \ No newline at end of file +} diff --git a/indra/newview/llphysicsmotion.h b/indra/newview/llphysicsmotion.h index 7412c9d880..2ce79b2206 100644 --- a/indra/newview/llphysicsmotion.h +++ b/indra/newview/llphysicsmotion.h @@ -42,14 +42,14 @@ class LLPhysicsMotion; // class LLPhysicsMotion //----------------------------------------------------------------------------- class LLPhysicsMotionController : - public LLMotion + public AIMaskedMotion { public: std::string getString(); // Constructor - LLPhysicsMotionController(const LLUUID &id); + LLPhysicsMotionController(LLUUID const& id, LLMotionController* controller); // Destructor virtual ~LLPhysicsMotionController(); @@ -61,7 +61,7 @@ class LLPhysicsMotionController : // static constructor // all subclasses must implement such a function and register it - static LLMotion *create(const LLUUID &id) { return new LLPhysicsMotionController(id); } + static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLPhysicsMotionController(id, controller); } public: //------------------------------------------------------------------------- @@ -93,19 +93,11 @@ class LLPhysicsMotionController : // must return true to indicate success and be available for activation virtual LLMotionInitStatus onInitialize(LLCharacter *character); - // called when a motion is activated - // must return TRUE to indicate success, or else - // it will be deactivated - virtual BOOL onActivate(); - // called per time step // must return TRUE while it is active, and // must return FALSE when the motion is completed. virtual BOOL onUpdate(F32 time, U8* joint_mask); - // called when a motion is deactivated - virtual void onDeactivate(); - LLCharacter* getCharacter() { return mCharacter; } protected: diff --git a/indra/newview/llprefschat.cpp b/indra/newview/llprefschat.cpp index f62a4d4e9e..f76df16791 100644 --- a/indra/newview/llprefschat.cpp +++ b/indra/newview/llprefschat.cpp @@ -179,7 +179,6 @@ void LLPrefsChatImpl::apply() gSavedSettings.setColor4("BackgroundChatColor", childGetValue("background")); gSavedSettings.setColor4("HTMLLinkColor", childGetValue("links")); - LLTextEditor::setLinkColor(childGetValue("links")); gSavedSettings.setBOOL("ArrowKeysMoveAvatar", childGetValue("arrow_keys_move_avatar_check")); gSavedSettings.setBOOL("ChatShowTimestamps", childGetValue("show_timestamps_check")); diff --git a/indra/newview/llprefsim.cpp b/indra/newview/llprefsim.cpp index 2f7faca756..8023cd1a37 100644 --- a/indra/newview/llprefsim.cpp +++ b/indra/newview/llprefsim.cpp @@ -63,7 +63,7 @@ class LLPrefsIMImpl : public LLPanel void apply(); void cancel(); - void setPersonalInfo(const std::string& visibility, bool im_via_email, const std::string& email); + void setPersonalInfo(const std::string& visibility, bool im_via_email, const std::string& email, bool is_verified); void enableHistory(); static void onClickLogPath(void* user_data); @@ -193,13 +193,6 @@ void LLPrefsIMImpl::apply() if((new_im_via_email != mOriginalIMViaEmail) ||(new_hide_online != mOriginalHideOnlineStatus)) { - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_UpdateUserInfo); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_UserData); - msg->addBOOLFast(_PREHASH_IMViaEMail, new_im_via_email); // This hack is because we are representing several different // possible strings with a single checkbox. Since most users // can only select between 2 values, we represent it as a @@ -212,8 +205,7 @@ void LLPrefsIMImpl::apply() //Update showonline value, otherwise multiple applys won't work mOriginalHideOnlineStatus = new_hide_online; } - msg->addString("DirectoryVisibility", mDirectoryVisibility); - gAgent.sendReliableMessage(); + gAgent.sendAgentUpdateUserInfo(new_im_via_email, mDirectoryVisibility); } } else @@ -227,7 +219,7 @@ void LLPrefsIMImpl::apply() } } -void LLPrefsIMImpl::setPersonalInfo(const std::string& visibility, bool im_via_email, const std::string& email) +void LLPrefsIMImpl::setPersonalInfo(const std::string& visibility, bool im_via_email, const std::string& email, bool is_verified) { mGotPersonalInfo = true; mOriginalIMViaEmail = im_via_email; @@ -254,8 +246,13 @@ void LLPrefsIMImpl::setPersonalInfo(const std::string& visibility, bool im_via_e childSetValue("online_visibility", mOriginalHideOnlineStatus); childSetLabelArg("online_visibility", "[DIR_VIS]", mDirectoryVisibility); - childEnable("send_im_to_email"); - childSetValue("send_im_to_email", im_via_email); + if (auto child = getChildView("send_im_to_email")) + { + child->setValue(im_via_email); + child->setEnabled(is_verified); + if (!is_verified) + child->setToolTip(getString("email_unverified_tooltip")); + } childEnable("log_instant_messages"); childEnable("log_chat"); childEnable("log_instant_messages_timestamp"); @@ -332,9 +329,9 @@ void LLPrefsIM::cancel() impl.cancel(); } -void LLPrefsIM::setPersonalInfo(const std::string& visibility, bool im_via_email, const std::string& email) +void LLPrefsIM::setPersonalInfo(const std::string& visibility, bool im_via_email, const std::string& email, bool is_verified) { - impl.setPersonalInfo(visibility, im_via_email, email); + impl.setPersonalInfo(visibility, im_via_email, email, is_verified); } LLPanel* LLPrefsIM::getPanel() diff --git a/indra/newview/llprefsim.h b/indra/newview/llprefsim.h index 90bf4656a7..7b7b3cefc1 100644 --- a/indra/newview/llprefsim.h +++ b/indra/newview/llprefsim.h @@ -45,7 +45,7 @@ class LLPrefsIM void apply(); void cancel(); - void setPersonalInfo(const std::string& visibility, bool im_via_email, const std::string& email); + void setPersonalInfo(const std::string& visibility, bool im_via_email, const std::string& email, bool is_verified); LLPanel* getPanel(); diff --git a/indra/newview/llprefsvoice.cpp b/indra/newview/llprefsvoice.cpp index 275778de46..ccd5743c74 100644 --- a/indra/newview/llprefsvoice.cpp +++ b/indra/newview/llprefsvoice.cpp @@ -35,8 +35,8 @@ #include "llprefsvoice.h" -#include "floatervoicelicense.h" #include "llcheckboxctrl.h" +#include "llfloatertos.h" #include "llfocusmgr.h" #include "llkeyboard.h" #include "llmodaldialog.h" @@ -53,7 +53,7 @@ class LLVoiceSetKeyDialog : public LLModalDialog BOOL handleKeyHere(KEY key, MASK mask); - static void onCancel(void* user_data); + static void start(LLPrefsVoice* p) { (new LLVoiceSetKeyDialog(p))->startModal(); } private: LLPrefsVoice* mParent; @@ -63,8 +63,11 @@ LLVoiceSetKeyDialog::LLVoiceSetKeyDialog(LLPrefsVoice* parent) : LLModalDialog(LLStringUtil::null, 240, 100), mParent(parent) { LLUICtrlFactory::getInstance()->buildFloater(this, "floater_select_key.xml"); - childSetAction("Cancel", onCancel, this); - childSetFocus("Cancel"); + if (LLUICtrl* ctrl = findChild("Cancel")) + { + ctrl->setCommitCallback(boost::bind(&LLModalDialog::close, this, false)); + ctrl->setFocus(true); + } gFocusMgr.setKeystrokesOnly(TRUE); } @@ -77,7 +80,7 @@ BOOL LLVoiceSetKeyDialog::handleKeyHere(KEY key, MASK mask) { BOOL result = TRUE; - if(key == 'Q' && mask == MASK_CONTROL) + if (key == 'Q' && mask == MASK_CONTROL) { result = FALSE; } @@ -90,13 +93,6 @@ BOOL LLVoiceSetKeyDialog::handleKeyHere(KEY key, MASK mask) return result; } -//static -void LLVoiceSetKeyDialog::onCancel(void* user_data) -{ - LLVoiceSetKeyDialog* self = (LLVoiceSetKeyDialog*)user_data; - self->close(); -} - namespace { void* createDevicePanel(void*) @@ -121,20 +117,13 @@ LLPrefsVoice::~LLPrefsVoice() BOOL LLPrefsVoice::postBuild() { - childSetCommitCallback("enable_voice_check", onCommitEnableVoiceChat, this); - childSetAction("set_voice_hotkey_button", onClickSetKey, this); - childSetAction("set_voice_middlemouse_button", onClickSetMiddleMouse, this); - - BOOL voice_disabled = gSavedSettings.getBOOL("CmdLineDisableVoice"); - childSetVisible("voice_unavailable", voice_disabled); - childSetVisible("enable_voice_check", !voice_disabled); - childSetEnabled("enable_voice_check", !voice_disabled); + getChild("enable_voice_check")->setCommitCallback(boost::bind(&LLPrefsVoice::onCommitEnableVoiceChat, this, _2)); + getChild("set_voice_hotkey_button")->setCommitCallback(boost::bind(LLVoiceSetKeyDialog::start, this)); + getChild("set_voice_middlemouse_button")->setCommitCallback(boost::bind(&LLView::setValue, getChildView("modifier_combo"), "MiddleMouse")); - bool enable = !voice_disabled && gSavedSettings.getBOOL("EnableVoiceChat"); - childSetValue("enable_voice_check", enable); - onCommitEnableVoiceChat(getChild("enable_voice_check"), this); + getChildView("enable_voice_check")->setValue(!gSavedSettings.getBOOL("CmdLineDisableVoice") && gSavedSettings.getBOOL("EnableVoiceChat")); - if (LLCheckBoxCtrl* check = getChild("enable_multivoice_check")) + if (LLCheckBoxCtrl* check = findChild("enable_multivoice_check")) { check->setValue(gSavedSettings.getBOOL("VoiceMultiInstance")); check->setLabel(getString("multivoice_label", LLTrans::getDefaultArgs())); @@ -160,7 +149,7 @@ void LLPrefsVoice::apply() gSavedSettings.setBOOL("LipSyncEnabled", childGetValue("enable_lip_sync_check")); gSavedSettings.setBOOL("VoiceMultiInstance", childGetValue("enable_multivoice_check")); - if (LLPanelVoiceDeviceSettings* voice_device_settings = getChild("device_settings_panel")) + if (LLPanelVoiceDeviceSettings* voice_device_settings = findChild("device_settings_panel")) { voice_device_settings->apply(); } @@ -169,8 +158,9 @@ void LLPrefsVoice::apply() if (enable_voice && !gSavedSettings.getBOOL("VivoxLicenseAccepted")) { // This window enables voice chat if license is accepted - FloaterVoiceLicense::getInstance()->open(); - FloaterVoiceLicense::getInstance()->center(); + auto inst = LLFloaterTOS::show(LLFloaterTOS::TOS_VOICE); + inst->open(); + inst->center(); } else { @@ -180,7 +170,7 @@ void LLPrefsVoice::apply() void LLPrefsVoice::cancel() { - if (LLPanelVoiceDeviceSettings* voice_device_settings = getChild("device_settings_panel")) + if (LLPanelVoiceDeviceSettings* voice_device_settings = findChild("device_settings_panel")) { voice_device_settings->cancel(); } @@ -188,42 +178,23 @@ void LLPrefsVoice::cancel() void LLPrefsVoice::setKey(KEY key) { - childSetValue("modifier_combo", LLKeyboard::stringFromKey(key)); -} - -//static -void LLPrefsVoice::onCommitEnableVoiceChat(LLUICtrl* ctrl, void* user_data) -{ - LLPrefsVoice* self = (LLPrefsVoice*)user_data; - LLCheckBoxCtrl* enable_voice_chat = (LLCheckBoxCtrl*)ctrl; - - bool enable = enable_voice_chat->getValue(); - - self->childSetEnabled("modifier_combo", enable); - self->childSetEnabled("push_to_talk_label", enable); - self->childSetEnabled("voice_call_friends_only_check", enable); - self->childSetEnabled("auto_disengage_mic_check", enable); - self->childSetEnabled("push_to_talk_toggle_check", enable); - self->childSetEnabled("ear_location", enable); - self->childSetEnabled("enable_lip_sync_check", enable); - self->childSetEnabled("set_voice_hotkey_button", enable); - self->childSetEnabled("set_voice_middlemouse_button", enable); - self->childSetEnabled("device_settings_btn", enable); - self->childSetEnabled("device_settings_panel", enable); -} - -//static -void LLPrefsVoice::onClickSetKey(void* user_data) -{ - LLPrefsVoice* self = (LLPrefsVoice*)user_data; - LLVoiceSetKeyDialog* dialog = new LLVoiceSetKeyDialog(self); - dialog->startModal(); + getChildView("modifier_combo")->setValue(LLKeyboard::stringFromKey(key)); } -//static -void LLPrefsVoice::onClickSetMiddleMouse(void* user_data) +void LLPrefsVoice::onCommitEnableVoiceChat(const LLSD& value) { - LLPrefsVoice* self = (LLPrefsVoice*)user_data; - self->childSetValue("modifier_combo", "MiddleMouse"); + bool enable = value.asBoolean(); + + getChildView("modifier_combo")->setEnabled(enable); + getChildView("push_to_talk_label")->setEnabled(enable); + getChildView("voice_call_friends_only_check")->setEnabled(enable); + getChildView("auto_disengage_mic_check")->setEnabled(enable); + getChildView("push_to_talk_toggle_check")->setEnabled(enable); + getChildView("ear_location")->setEnabled(enable); + getChildView("enable_lip_sync_check")->setEnabled(enable); + getChildView("set_voice_hotkey_button")->setEnabled(enable); + getChildView("set_voice_middlemouse_button")->setEnabled(enable); + getChildView("device_settings_btn")->setEnabled(enable); + getChildView("device_settings_panel")->setEnabled(enable); } diff --git a/indra/newview/llprefsvoice.h b/indra/newview/llprefsvoice.h index a1cd8c933e..70ce6a032c 100644 --- a/indra/newview/llprefsvoice.h +++ b/indra/newview/llprefsvoice.h @@ -49,9 +49,7 @@ class LLPrefsVoice : public LLPanel void setKey(KEY key); private: - static void onCommitEnableVoiceChat(LLUICtrl* ctrl, void* user_data); - static void onClickSetKey(void* user_data); - static void onClickSetMiddleMouse(void* user_data); + void onCommitEnableVoiceChat(const LLSD& value); }; #endif // LLPREFSVOICE_H diff --git a/indra/newview/llpreview.cpp b/indra/newview/llpreview.cpp index de4598d155..59cbc06d52 100644 --- a/indra/newview/llpreview.cpp +++ b/indra/newview/llpreview.cpp @@ -201,10 +201,10 @@ void LLPreview::onCommit() if (!item->isComplete()) { // We are attempting to save an item that was never loaded - llwarns << "LLPreview::onCommit() called with mIsComplete == FALSE" + LL_WARNS() << "LLPreview::onCommit() called with mIsComplete == FALSE" << " Type: " << item->getType() << " ID: " << item->getUUID() - << llendl; + << LL_ENDL; return; } @@ -262,15 +262,13 @@ void LLPreview::draw() { mDirty = FALSE; const LLViewerInventoryItem *item = getItem(); - if (item) - { - refreshFromItem(item); - } + refreshFromItem(item); } } void LLPreview::refreshFromItem(const LLInventoryItem* item) { + if (!item) return; setTitle(llformat("%s: %s",getTitleName(),item->getName().c_str())); childSetText("desc",item->getDescription()); @@ -497,13 +495,6 @@ void LLPreview::onDiscardBtn(void* data) self->mForceClose = TRUE; self->close(); - // Delete the item entirely - /* - item->removeFromServer(); - gInventory.deleteObject(item->getUUID()); - gInventory.notifyObservers(); - */ - // Move the item to the trash LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); if (item->getParentUUID() != trash_id) @@ -648,7 +639,7 @@ void LLPreview::setAssetId(const LLUUID& asset_id) LLViewerObject* object = gObjectList.findObject(mObjectUUID); if(NULL == object) { - llwarns << "LLPreview::setAssetId() called on unrecognized object, UUID : " << mObjectUUID << llendl; + LL_WARNS() << "LLPreview::setAssetId() called on unrecognized object, UUID : " << mObjectUUID << LL_ENDL; return; } object->updateViewerInventoryAsset(item, asset_id); diff --git a/indra/newview/llpreview.h b/indra/newview/llpreview.h index 02184af85c..5203ce31fa 100644 --- a/indra/newview/llpreview.h +++ b/indra/newview/llpreview.h @@ -137,6 +137,8 @@ class LLPreview : public LLFloater, LLInventoryObserver // for LLInventoryObserver virtual void changed(U32 mask); BOOL mDirty; + +public: virtual const char *getTitleName() const { return "Preview"; } protected: diff --git a/indra/newview/llpreviewanim.cpp b/indra/newview/llpreviewanim.cpp index 09e2c61cf0..4bbc1e6565 100644 --- a/indra/newview/llpreviewanim.cpp +++ b/indra/newview/llpreviewanim.cpp @@ -256,7 +256,7 @@ void LLPreviewAnim::gotAssetForCopy(LLVFS *vfs, char* buffer = new char[size]; if (buffer == NULL) { - llerrs << "Memory Allocation Failed" << llendl; + LL_ERRS() << "Memory Allocation Failed" << LL_ENDL; return; } @@ -317,7 +317,7 @@ void LLPreviewAnim::onSaveCopyComplete(const LLUUID& asset_uuid, void* user_data } else { - llwarns << "Problem saving animation: " << status << llendl; + LL_WARNS() << "Problem saving animation: " << status << LL_ENDL; LLStringUtil::format_map_t args; args["[REASON]"] = std::string(LLAssetStorage::getErrorString(status)); gViewerWindow->alertXml("CannotUploadReason",args); @@ -390,7 +390,7 @@ void LLPreviewAnim::gotAssetForSave(LLVFS *vfs, char* buffer = new char[size]; if (buffer == NULL) { - llerrs << "Memory Allocation Failed" << llendl; + LL_ERRS() << "Memory Allocation Failed" << LL_ENDL; return; } diff --git a/indra/newview/llpreviewgesture.cpp b/indra/newview/llpreviewgesture.cpp index eb5a759723..a375be2d03 100644 --- a/indra/newview/llpreviewgesture.cpp +++ b/indra/newview/llpreviewgesture.cpp @@ -44,6 +44,7 @@ #include "lldatapacker.h" #include "lldelayedgestureerror.h" #include "llfloatergesture.h" // for some label constants +#include "llflyoutbutton.h" #include "llgesturemgr.h" #include "llinventorydefines.h" #include "llinventoryfunctions.h" @@ -85,10 +86,9 @@ class LLInventoryGestureAvailable : public LLInventoryCompletionObserver void LLInventoryGestureAvailable::done() { - for(uuid_vec_t::iterator it = mComplete.begin(); it != mComplete.end(); ++it) + for(auto id : mComplete) { - LLPreview* preview = LLPreview::find((*it)); - if(preview) + if (auto preview = LLPreview::find(id)) { preview->refresh(); } @@ -97,15 +97,6 @@ void LLInventoryGestureAvailable::done() delete this; } -// Used for sorting -struct SortItemPtrsByName -{ - bool operator()(const LLInventoryItem* i1, const LLInventoryItem* i2) - { - return (LLStringUtil::compareDict(i1->getName(), i2->getName()) < 0); - } -}; - // static LLPreviewGesture* LLPreviewGesture::show(const std::string& title, const LLUUID& item_id, const LLUUID& object_id, BOOL take_focus) { @@ -127,7 +118,7 @@ LLPreviewGesture* LLPreviewGesture::show(const std::string& title, const LLUUID& // Move window to top-left of screen LLMultiFloater* hostp = preview->getHost(); - if (hostp == NULL) + if (hostp == nullptr) { LLRect r = preview->getRect(); LLRect screen = gFloaterView->getRect(); @@ -225,7 +216,7 @@ BOOL LLPreviewGesture::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, } else if (drop) { - LLScrollListItem* line = NULL; + LLScrollListItem* line = nullptr; if (cargo_type == DAD_ANIMATION) { line = addStep( STEP_ANIMATION ); @@ -341,23 +332,23 @@ bool LLPreviewGesture::handleSaveChangesDialog(const LLSD& notification, const L LLPreviewGesture::LLPreviewGesture() : LLPreview("Gesture Preview"), - mTriggerEditor(NULL), - mModifierCombo(NULL), - mKeyCombo(NULL), - mLibraryList(NULL), - mAddBtn(NULL), - mUpBtn(NULL), - mDownBtn(NULL), - mDeleteBtn(NULL), - mStepList(NULL), - mOptionsText(NULL), - mAnimationRadio(NULL), - mAnimationCombo(NULL), - mSoundCombo(NULL), - mChatEditor(NULL), - mSaveBtn(NULL), - mPreviewBtn(NULL), - mPreviewGesture(NULL), + mTriggerEditor(nullptr), + mModifierCombo(nullptr), + mKeyCombo(nullptr), + mLibraryList(nullptr), + mAddBtn(nullptr), + mUpBtn(nullptr), + mDownBtn(nullptr), + mDeleteBtn(nullptr), + mStepList(nullptr), + mOptionsText(nullptr), + mAnimationRadio(nullptr), + mAnimationCombo(nullptr), + mSoundCombo(nullptr), + mChatEditor(nullptr), + mSaveBtn(nullptr), + mPreviewBtn(nullptr), + mPreviewGesture(nullptr), mDirty(FALSE) { } @@ -366,14 +357,11 @@ LLPreviewGesture::LLPreviewGesture() LLPreviewGesture::~LLPreviewGesture() { // Userdata for all steps is a LLGestureStep we need to clean up - std::vector data_list = mStepList->getAllData(); - std::vector::iterator data_itor; - for (data_itor = data_list.begin(); data_itor != data_list.end(); ++data_itor) + for (auto& item : mStepList->getAllData()) { - LLScrollListItem* item = *data_itor; LLGestureStep* step = (LLGestureStep*)item->getUserdata(); delete step; - step = NULL; + step = nullptr; } } @@ -493,17 +481,17 @@ BOOL LLPreviewGesture::postBuild() mWaitTimeEditor = edit; // Buttons at the bottom - check = getChild( "active_check"); + check = getChild("active_check"); check->setCommitCallback(boost::bind(&LLPreviewGesture::onCommitActive,this)); mActiveCheck = check; - btn = getChild( "save_btn"); + btn = getChild("save_btn"); btn->setClickedCallback(boost::bind(&LLPreviewGesture::onClickSave,this)); mSaveBtn = btn; - btn = getChild( "preview_btn"); - btn->setClickedCallback(boost::bind(&LLPreviewGesture::onClickPreview,this)); - mPreviewBtn = btn; + LLFlyoutButton* flyout = getChild("preview_btn"); + flyout->setCommitCallback(boost::bind(&LLPreviewGesture::onClickPreview, this, _2)); + mPreviewBtn = flyout; // Populate the comboboxes @@ -516,9 +504,10 @@ BOOL LLPreviewGesture::postBuild() if (item) { - childSetCommitCallback("desc", LLPreview::onText, this); - childSetText("desc", item->getDescription()); - getChild("desc")->setPrevalidate(&LLLineEditor::prevalidatePrintableNotPipe); + auto desc = getChild("desc"); + desc->setCommitCallback(LLPreview::onText, this); + desc->setValue(item->getDescription()); + desc->setPrevalidate(&LLLineEditor::prevalidatePrintableNotPipe); } return TRUE; @@ -540,7 +529,20 @@ static const std::string valid_key_to_string(KEY key) { std::string skey(1,(char)key); std::string strkey = LLKeyboard::stringFromKey(key); - return ((skey == strkey && key >= ' ' && key <= '~') || (skey != strkey) ) ? strkey : ""; + return ((skey == strkey && key >= ' ' && key <= '~') || (skey != strkey) ) ? strkey : LLStringUtil::null; +} + +void load_and_sort(LLComboBox* combo, const LLViewerInventoryItem::item_array_t& items) +{ + combo->removeall(); + + // Load up the combobox + for (const auto& item : items) + { + combo->add(item->getName(), item->getAssetUUID()); + } + // Sort + combo->sortByName(); } void LLPreviewGesture::addKeys() @@ -548,10 +550,10 @@ void LLPreviewGesture::addKeys() LLComboBox* combo = mKeyCombo; combo->add( NONE_LABEL ); - for (KEY key = ' '; key < KEY_NONE; key++) + for (KEY key = ' '; key < KEY_NONE; ++key) { std::string keystr = valid_key_to_string(key); - if(keystr != "")combo->add( keystr, ADD_BOTTOM ); + if (!keystr.empty()) combo->add( keystr, ADD_BOTTOM ); } combo->setCurrentByIndex(0); } @@ -561,22 +563,7 @@ void LLPreviewGesture::addKeys() void LLPreviewGesture::addAnimations() { LLComboBox* combo = mAnimationCombo; - combo->removeall(); - - std::string none_text = getString("none_text"); - - combo->add(none_text, LLUUID::null); - - // Add all the default (legacy) animations - S32 i; - for (i = 0; i < gUserAnimStatesCount; ++i) - { - // Use the user-readable name - std::string label = LLAnimStateLabels::getStateLabel( gUserAnimStates[i].mName ); - const LLUUID& id = gUserAnimStates[i].mID; - combo->add(label, id); - } // Get all inventory items that are animations LLViewerInventoryCategory::cat_array_t cats; @@ -591,38 +578,21 @@ void LLPreviewGesture::addAnimations() LLInventoryModel::EXCLUDE_TRASH, is_copyable_animation); - // Copy into something we can sort - std::vector animations; + load_and_sort(combo, items); - S32 count = items.count(); - for(i = 0; i < count; ++i) - { - animations.push_back( items.get(i) ); - } - - // Do the sort - std::sort(animations.begin(), animations.end(), SortItemPtrsByName()); - - // And load up the combobox - std::vector::iterator it; - for (it = animations.begin(); it != animations.end(); ++it) + // Add all the default (legacy) animations + for (S32 i = gUserAnimStatesCount - 1; i >= 0; --i) { - LLInventoryItem* item = *it; - - combo->add(item->getName(), item->getAssetUUID(), ADD_BOTTOM); + // Use the user-readable name + const auto& state = gUserAnimStates[i]; + combo->add(LLAnimStateLabels::getStateLabel(state.mName), state.mID, ADD_TOP); } + combo->add(getString("none_text"), LLUUID::null, ADD_TOP); } void LLPreviewGesture::addSounds() { - LLComboBox* combo = mSoundCombo; - combo->removeall(); - - std::string none_text = getString("none_text"); - - combo->add(none_text, LLUUID::null); - // Get all inventory items that are sounds LLViewerInventoryCategory::cat_array_t cats; LLViewerInventoryItem::item_array_t items; @@ -636,27 +606,9 @@ void LLPreviewGesture::addSounds() LLInventoryModel::EXCLUDE_TRASH, is_copyable_sound); - // Copy sounds into something we can sort - std::vector sounds; - - S32 i; - S32 count = items.count(); - for(i = 0; i < count; ++i) - { - sounds.push_back( items.get(i) ); - } - - // Do the sort - std::sort(sounds.begin(), sounds.end(), SortItemPtrsByName()); - - // And load up the combobox - std::vector::iterator it; - for (it = sounds.begin(); it != sounds.end(); ++it) - { - LLInventoryItem* item = *it; - - combo->add(item->getName(), item->getAssetUUID(), ADD_BOTTOM); - } + LLComboBox* combo = mSoundCombo; + load_and_sort(combo, items); + combo->add(getString("none_text"), LLUUID::null, ADD_TOP); } @@ -731,12 +683,12 @@ void LLPreviewGesture::refresh() BOOL have_replace = !replace.empty(); LLScrollListItem* library_item = mLibraryList->getFirstSelected(); - BOOL have_library = (library_item != NULL); + BOOL have_library = (library_item != nullptr); LLScrollListItem* step_item = mStepList->getFirstSelected(); S32 step_index = mStepList->getFirstSelectedIndex(); S32 step_count = mStepList->getItemCount(); - BOOL have_step = (step_item != NULL); + BOOL have_step = (step_item != nullptr); mReplaceText->setEnabled(have_trigger || have_replace); mReplaceEditor->setEnabled(have_trigger || have_replace); @@ -932,11 +884,11 @@ void LLPreviewGesture::onLoadComplete(LLVFS *vfs, } else { - llwarns << "Unable to load gesture" << llendl; + LL_WARNS() << "Unable to load gesture" << LL_ENDL; } delete gesture; - gesture = NULL; + gesture = nullptr; self->mAssetStatus = PREVIEW_ASSET_LOADED; } @@ -954,12 +906,12 @@ void LLPreviewGesture::onLoadComplete(LLVFS *vfs, LLDelayedGestureError::gestureFailedToLoad( *item_idp ); } - llwarns << "Problem loading gesture: " << status << llendl; + LL_WARNS() << "Problem loading gesture: " << status << LL_ENDL; self->mAssetStatus = PREVIEW_ASSET_ERROR; } } delete item_idp; - item_idp = NULL; + item_idp = nullptr; } @@ -1006,7 +958,7 @@ void LLPreviewGesture::loadUIFromGesture(LLMultiGesture* gesture) { LLGestureStep* step = gesture->mSteps[i]; - LLGestureStep* new_step = NULL; + LLGestureStep* new_step = nullptr; switch(step->getType()) { @@ -1080,7 +1032,7 @@ void LLPreviewGesture::saveIfNeeded() { if (!gAssetStorage) { - llwarns << "Can't save gesture, no asset storage system." << llendl; + LL_WARNS() << "Can't save gesture, no asset storage system." << LL_ENDL; return; } @@ -1098,23 +1050,22 @@ void LLPreviewGesture::saveIfNeeded() LLDataPackerAsciiBuffer dp(buffer, max_size); - BOOL ok = gesture->serialize(dp); - - // - //if (dp.getCurrentSize() > 1000) - if(0) - // + bool ok = gesture->serialize(dp); +#if 0 // + if (dp.getCurrentSize() > 1000) { LLNotificationsUtil::add("GestureSaveFailedTooManySteps"); delete gesture; - gesture = NULL; + gesture = nullptr; } else if (!ok) +#endif // + if (!ok) { LLNotificationsUtil::add("GestureSaveFailedTryAgain"); delete gesture; - gesture = NULL; + gesture = nullptr; } else { @@ -1186,7 +1137,7 @@ void LLPreviewGesture::saveIfNeeded() { // we're done with this gesture delete gesture; - gesture = NULL; + gesture = nullptr; } mDirty = FALSE; @@ -1199,7 +1150,7 @@ void LLPreviewGesture::saveIfNeeded() } delete [] buffer; - buffer = NULL; + buffer = nullptr; } @@ -1228,15 +1179,15 @@ void LLPreviewGesture::onSaveComplete(const LLUUID& asset_uuid, void* user_data, } else { - llwarns << "Inventory item for gesture " << info->mItemUUID - << " is no longer in agent inventory." << llendl; + LL_WARNS() << "Inventory item for gesture " << info->mItemUUID + << " is no longer in agent inventory." << LL_ENDL; } } else { // Saving into in-world object inventory LLViewerObject* object = gObjectList.findObject(info->mObjectUUID); - LLViewerInventoryItem* item = NULL; + LLViewerInventoryItem* item = nullptr; if(object) { item = (LLViewerInventoryItem*)object->getInventoryObject(info->mItemUUID); @@ -1264,13 +1215,13 @@ void LLPreviewGesture::onSaveComplete(const LLUUID& asset_uuid, void* user_data, } else { - llwarns << "Problem saving gesture: " << status << llendl; + LL_WARNS() << "Problem saving gesture: " << status << LL_ENDL; LLSD args; args["REASON"] = std::string(LLAssetStorage::getErrorString(status)); LLNotificationsUtil::add("GestureSaveFailedReason", args); } delete info; - info = NULL; + info = nullptr; } @@ -1305,11 +1256,8 @@ LLMultiGesture* LLPreviewGesture::createGesture() LLKeyboard::keyFromString(key_string, &(gesture->mKey)); } - std::vector data_list = mStepList->getAllData(); - std::vector::iterator data_itor; - for (data_itor = data_list.begin(); data_itor != data_list.end(); ++data_itor) + for (auto& item : mStepList->getAllData()) { - LLScrollListItem* item = *data_itor; LLGestureStep* step = (LLGestureStep*)item->getUserdata(); switch(step->getType()) @@ -1365,11 +1313,7 @@ LLMultiGesture* LLPreviewGesture::createGesture() void LLPreviewGesture::updateLabel(LLScrollListItem* item) { LLGestureStep* step = (LLGestureStep*)item->getUserdata(); - - LLScrollListCell* cell = item->getColumn(0); - LLScrollListText* text_cell = (LLScrollListText*)cell; - std::string label = getLabel( step->getLabel()); - text_cell->setText(label); + static_cast(item->getColumn(0))->setText(getLabel(step->getLabel())); } void LLPreviewGesture::onCommitSetDirty() @@ -1517,9 +1461,7 @@ void LLPreviewGesture::onCommitWait() LLLocale locale(LLLocale::USER_LOCALE); F32 wait_seconds = (F32)atof(mWaitTimeEditor->getText().c_str()); - if (wait_seconds < 0.f) wait_seconds = 0.f; - if (wait_seconds > 3600.f) wait_seconds = 3600.f; - wait_step->mWaitSeconds = wait_seconds; + wait_step->mWaitSeconds = llclamp(wait_seconds, 0.f, 3600.f); } // Enable the input area if necessary @@ -1565,7 +1507,7 @@ void LLPreviewGesture::onClickAdd() if( library_item_index >= STEP_EOF ) { - llerrs << "Unknown step type: " << library_text << llendl; + LL_ERRS() << "Unknown step type: " << library_text << LL_ENDL; return; } @@ -1578,7 +1520,7 @@ LLScrollListItem* LLPreviewGesture::addStep( const EStepType step_type ) { // Order of enum EStepType MUST match the library_list element in floater_preview_gesture.xml - LLGestureStep* step = NULL; + LLGestureStep* step = nullptr; switch( step_type) { case STEP_ANIMATION: @@ -1594,14 +1536,15 @@ LLScrollListItem* LLPreviewGesture::addStep( const EStepType step_type ) step = new LLGestureStepWait(); break; default: - llerrs << "Unknown step type: " << (S32)step_type << llendl; - return NULL; + LL_ERRS() << "Unknown step type: " << (S32)step_type << LL_ENDL; + return nullptr; } // Create an enabled item with this step LLSD row; - row["columns"][0]["value"] = getLabel(step->getLabel()); - row["columns"][0]["font"] = "SANSSERIF_SMALL"; + auto& element = row["columns"][0]; + element["value"] = getLabel(step->getLabel()); + element["font"] = "SANSSERIF_SMALL"; LLScrollListItem* step_item = mStepList->addElement(row); step_item->setUserdata(step); @@ -1615,57 +1558,66 @@ LLScrollListItem* LLPreviewGesture::addStep( const EStepType step_type ) } // static -std::string LLPreviewGesture::getLabel(std::vector labels) +std::string LLPreviewGesture::getLabel(const std::vector& v_labels) { - std::vector v_labels = labels ; - std::string result(""); - if( v_labels.size() != 2) { - return result; + return LLStringUtil::null; } - - if(v_labels[0]=="Chat") + + auto result(v_labels[0]); + if (result == "Chat") { - result=LLTrans::getString("Chat Message"); + static const auto chat = LLTrans::getString("Chat Message"); + result = chat; } - else if(v_labels[0]=="Sound") + else if (result == "Sound") { - result=LLTrans::getString("Sound"); + static const auto sound = LLTrans::getString("Sound"); + result = sound; } - else if(v_labels[0]=="Wait") + else if (result == "Wait") { - result=LLTrans::getString("Wait"); + static const auto wait = LLTrans::getString("Wait"); + result = wait; } - else if(v_labels[0]=="AnimFlagStop") + else if (result == "AnimFlagStop") { - result=LLTrans::getString("AnimFlagStop"); + static const auto stop = LLTrans::getString("AnimFlagStop"); + result = stop; } - else if(v_labels[0]=="AnimFlagStart") + else if (result == "AnimFlagStart") { - result=LLTrans::getString("AnimFlagStart"); + static const auto start = LLTrans::getString("AnimFlagStart"); + result = start; } // lets localize action value std::string action = v_labels[1]; if ("None" == action) { - action = LLTrans::getString("GestureActionNone"); + static const auto none = LLTrans::getString("GestureActionNone"); + action = none; } else if ("until animations are done" == action) { //action = LLFloaterReg::getInstance("preview_gesture")->getChild("wait_anim_check")->getLabel(); //Worst. Thing. Ever. We are in a static function. Find any existing gesture preview and grab the label from its 'wait_anim_check' element. - for(preview_map_t::iterator it = LLPreview::sInstances.begin(); it != LLPreview::sInstances.end();++it) + static auto wait_anim = LLStringUtil::null; + if (wait_anim.empty()) { - LLPreviewGesture* pPreview = dynamic_cast(it->second); - if(pPreview) + for(const auto& pair : LLPreview::sInstances) { - pPreview->getChild("wait_anim_check")->getLabel(); - break; + const auto& pPreview(pair.second); + constexpr std::string_view gesture("Gesture"); + if (pPreview && std::string_view(pPreview->getTitleName()) == gesture) + { + wait_anim = pPreview->getChild("wait_anim_check")->getLabel(); + break; + } } } - + action = wait_anim; } result.append(action); return result; @@ -1715,13 +1667,14 @@ void LLPreviewGesture::onClickDelete() void LLPreviewGesture::onCommitActive() { - if (!LLGestureMgr::instance().isGestureActive(mItemUUID)) + auto& inst(LLGestureMgr::instance()); + if (!inst.isGestureActive(mItemUUID)) { - LLGestureMgr::instance().activateGesture(mItemUUID); + inst.activateGesture(mItemUUID); } else { - LLGestureMgr::instance().deactivateGesture(mItemUUID); + inst.deactivateGesture(mItemUUID); } // Make sure the (active) label in the inventory gets updated. @@ -1740,7 +1693,7 @@ void LLPreviewGesture::onClickSave() saveIfNeeded(); } -void LLPreviewGesture::onClickPreview() +void LLPreviewGesture::onClickPreview(bool local) { if (!mPreviewGesture) { @@ -1754,17 +1707,15 @@ void LLPreviewGesture::onClickPreview() mPreviewBtn->setLabel(getString("stop_txt")); // play it, and delete when done - LLGestureMgr::instance().playGesture(mPreviewGesture); - - refresh(); + LLGestureMgr::instance().playGesture(mPreviewGesture, local); } else { // Will call onDonePreview() below LLGestureMgr::instance().stopGesture(mPreviewGesture); - - refresh(); } + + refresh(); } @@ -1774,7 +1725,7 @@ void LLPreviewGesture::onDonePreview(LLMultiGesture* gesture) mPreviewBtn->setLabel(getString("preview_txt")); delete mPreviewGesture; - mPreviewGesture = NULL; + mPreviewGesture = nullptr; refresh(); } diff --git a/indra/newview/llpreviewgesture.h b/indra/newview/llpreviewgesture.h index d4d7228f4e..757d843085 100644 --- a/indra/newview/llpreviewgesture.h +++ b/indra/newview/llpreviewgesture.h @@ -113,7 +113,7 @@ class LLPreviewGesture : public LLPreview // "Sound", "Chat", or "Wait" LLScrollListItem* addStep(const enum EStepType step_type); - static std::string getLabel(std::vector labels); + static std::string getLabel(const std::vector& labels); static void updateLabel(LLScrollListItem* item); void onCommitSetDirty(); @@ -137,7 +137,7 @@ class LLPreviewGesture : public LLPreview void onCommitActive(); void onClickSave(); - void onClickPreview(); + void onClickPreview(bool local); void onDonePreview(LLMultiGesture* gesture); @@ -170,7 +170,7 @@ class LLPreviewGesture : public LLPreview LLCheckBoxCtrl* mActiveCheck; LLButton* mSaveBtn; - LLButton* mPreviewBtn; + class LLFlyoutButton* mPreviewBtn; LLMultiGesture* mPreviewGesture; BOOL mDirty; diff --git a/indra/newview/llpreviewlandmark.cpp b/indra/newview/llpreviewlandmark.cpp index c67f7c13d7..ac70e0ccc9 100644 --- a/indra/newview/llpreviewlandmark.cpp +++ b/indra/newview/llpreviewlandmark.cpp @@ -43,7 +43,6 @@ #include "llagent.h" #include "llbutton.h" -#include "lleconomy.h" #include "llfloaterinventory.h" #include "llfloaterworldmap.h" #include "lliconctrl.h" @@ -63,10 +62,6 @@ //////////////////////////////////////////////////////////////////////////// // LLPreviewLandmark -// static -LLPreviewLandmarkList LLPreviewLandmark::sOrderedInstances; - - LLPreviewLandmark::LLPreviewLandmark(const std::string& name, const LLRect& rect, const std::string& title, @@ -112,18 +107,10 @@ LLPreviewLandmark::LLPreviewLandmark(const std::string& name, translate(rect.mLeft - curRect.mLeft, rect.mTop - curRect.mTop); } */ - LLPreviewLandmark::sOrderedInstances.push_back( this ); } LLPreviewLandmark::~LLPreviewLandmark() { - LLPreviewLandmarkList::iterator this_itr; - this_itr = std::find(LLPreviewLandmark::sOrderedInstances.begin(), - LLPreviewLandmark::sOrderedInstances.end(), this); - if (this_itr != LLPreviewLandmark::sOrderedInstances.end()) - { - LLPreviewLandmark::sOrderedInstances.erase(this_itr); - } } diff --git a/indra/newview/llpreviewlandmark.h b/indra/newview/llpreviewlandmark.h index 5957eb46d4..82e358ed38 100644 --- a/indra/newview/llpreviewlandmark.h +++ b/indra/newview/llpreviewlandmark.h @@ -33,72 +33,43 @@ #ifndef LL_LLPREVIEWLANDMARK_H #define LL_LLPREVIEWLANDMARK_H -#include - -#include "lllandmark.h" - -#include "llfloater.h" -#include "llmap.h" -#include "llstring.h" -#include "lluuid.h" -#include "v3dmath.h" -#include "v4coloru.h" - -#include "llhudtext.h" #include "llpreview.h" class LLIconCtrl; -class LLInventoryItem; -class LLLandmarkList; -class LLLineEditor; -class LLMessageSystem; -class LLPreviewLandmark; class LLPanelPlace; +class LLLandmark; -const S32 PREVIEW_LANDMARK_NUM_COLORS = 6; - -typedef std::deque< LLPreviewLandmark* > LLPreviewLandmarkList; - -class LLPreviewLandmark : public LLPreview +class LLPreviewLandmark final : public LLPreview { public: LLPreviewLandmark(const std::string& name, const LLRect& rect, const std::string& title, const LLUUID& item_uuid, BOOL show_keep_discard = FALSE, - LLViewerInventoryItem* inv_item = NULL); + LLViewerInventoryItem* inv_item = nullptr); virtual ~LLPreviewLandmark(); - /*virtual*/ void draw(); + /*virtual*/ void draw() override; const std::string& getName() const; const LLColor4& getMarkerColor() const; LLVector3d getPositionGlobal() const; - //static S32 getNumInstances() { return LLPreviewLandmark::sOrderedInstances.getLength(); } - //static const LLPreviewLandmark* getFirst() { return LLPreviewLandmark::sOrderedInstances.getFirstData(); } - //static const LLPreviewLandmark* getNext() { return LLPreviewLandmark::sOrderedInstances.getNextData(); } - static void* createPlaceDetail(void* userdata); - /*virtual*/ void loadAsset(); - /*virtual*/ EAssetStatus getAssetStatus(); + /*virtual*/ void loadAsset() override; + /*virtual*/ EAssetStatus getAssetStatus() override; protected: void getDegreesAndDist(F32* degrees, F64* horiz_dist, F64* vert_dist) const; - virtual const char *getTitleName() const { return "Landmark"; } + const char *getTitleName() const override { return "Landmark"; } private: -// void renderBeacon(); -// LLPointer mBeaconText; - LLIconCtrl* mIconLandmark; LLPanelPlace* mPlacePanel; LLLandmark* mLandmark; LLColor4 mMarkerColor; - - static LLPreviewLandmarkList sOrderedInstances; }; #endif diff --git a/indra/newview/llpreviewnotecard.cpp b/indra/newview/llpreviewnotecard.cpp index 7b789fd58f..75afa197f4 100644 --- a/indra/newview/llpreviewnotecard.cpp +++ b/indra/newview/llpreviewnotecard.cpp @@ -45,6 +45,7 @@ #include "llfloatersearchreplace.h" #include "llinventorymodel.h" #include "lllineeditor.h" +#include "llmenugl.h" #include "llnotificationsutil.h" #include "llresmgr.h" #include "roles_constants.h" @@ -159,8 +160,6 @@ LLPreviewNotecard::LLPreviewNotecard(const std::string& name, } initMenu(); - - gAgentCamera.changeCameraToDefault(); } LLPreviewNotecard::~LLPreviewNotecard() @@ -274,7 +273,7 @@ bool LLPreviewNotecard::hasEmbeddedInventory() void LLPreviewNotecard::refreshFromInventory() { - lldebugs << "LLPreviewNotecard::refreshFromInventory()" << llendl; + LL_DEBUGS() << "LLPreviewNotecard::refreshFromInventory()" << LL_ENDL; loadAsset(); } @@ -288,6 +287,8 @@ void LLPreviewNotecard::loadAsset() // request the asset. if (const LLInventoryItem* item = getItem()) { + bool modify = gAgent.allowOperation(PERM_MODIFY, item->getPermissions(), GP_OBJECT_MANIPULATE); + if (modify) editor->setParseHTML(false); // Don't do the url parsing or we'll lose text! if (gAgent.allowOperation(PERM_COPY, item->getPermissions(), GP_OBJECT_MANIPULATE) || gAgent.isGodlike()) @@ -314,7 +315,7 @@ void LLPreviewNotecard::loadAsset() else { // The object that we're trying to look at disappeared, bail. - llwarns << "Can't find object " << mObjectUUID << " associated with notecard." << llendl; + LL_WARNS() << "Can't find object " << mObjectUUID << " associated with notecard." << LL_ENDL; mAssetID.setNull(); editor->setText(getString("no_object")); editor->makePristine(); @@ -346,8 +347,7 @@ void LLPreviewNotecard::loadAsset() editor->setEnabled(FALSE); mAssetStatus = PREVIEW_ASSET_LOADED; } - if(!gAgent.allowOperation(PERM_MODIFY, item->getPermissions(), - GP_OBJECT_MANIPULATE)) + if(!modify) { editor->setEnabled(FALSE); // You can always save in task inventory @@ -372,7 +372,7 @@ void LLPreviewNotecard::onLoadComplete(LLVFS *vfs, LLAssetType::EType type, void* user_data, S32 status, LLExtStat ext_status) { - llinfos << "LLPreviewNotecard::onLoadComplete()" << llendl; + LL_INFOS() << "LLPreviewNotecard::onLoadComplete()" << LL_ENDL; LLUUID* item_id = (LLUUID*)user_data; LLPreviewNotecard* preview = LLPreviewNotecard::getInstance(*item_id); if( preview ) @@ -389,29 +389,28 @@ void LLPreviewNotecard::onLoadComplete(LLVFS *vfs, // put a EOS at the end buffer[file_length] = 0; - + // Singu Note: Set Enabled first, it determines whether or not our text will be linked + const LLInventoryItem* item = preview->getItem(); + BOOL modifiable = item && gAgent.allowOperation(PERM_MODIFY, + item->getPermissions(), GP_OBJECT_MANIPULATE); + preview->setEnabled(modifiable); if (LLViewerTextEditor* previewEditor = preview->findChild("Notecard Editor")) { if ((file_length > 19) && !strncmp(buffer, "Linden text version", 19)) { if (!previewEditor->importBuffer(buffer, file_length+1)) { - llwarns << "Problem importing notecard" << llendl; + LL_WARNS() << "Problem importing notecard" << LL_ENDL; } } else { // Version 0 (just text, doesn't include version number) - previewEditor->setText(LLStringExplicit(buffer)); + previewEditor->setText(LLStringExplicit(buffer), false); } previewEditor->makePristine(); } - - const LLInventoryItem* item = preview->getItem(); - BOOL modifiable = item && gAgent.allowOperation(PERM_MODIFY, - item->getPermissions(), GP_OBJECT_MANIPULATE); - preview->setEnabled(modifiable); delete[] buffer; preview->mAssetStatus = PREVIEW_ASSET_LOADED; } @@ -433,7 +432,7 @@ void LLPreviewNotecard::onLoadComplete(LLVFS *vfs, LLNotificationsUtil::add("UnableToLoadNotecard"); } - llwarns << "Problem loading notecard: " << status << llendl; + LL_WARNS() << "Problem loading notecard: " << status << LL_ENDL; preview->mAssetStatus = PREVIEW_ASSET_ERROR; } } @@ -455,7 +454,7 @@ LLPreviewNotecard* LLPreviewNotecard::getInstance(const LLUUID& item_id) // static void LLPreviewNotecard::onClickSave(void* user_data) { - //llinfos << "LLPreviewNotecard::onBtnSave()" << llendl; + //LL_INFOS() << "LLPreviewNotecard::onBtnSave()" << LL_ENDL; LLPreviewNotecard* preview = (LLPreviewNotecard*)user_data; if(preview) { @@ -520,7 +519,7 @@ bool LLPreviewNotecard::saveIfNeeded(LLInventoryItem* copyitem) { if(!gAssetStorage) { - llwarns << "Not connected to an asset storage system." << llendl; + LL_WARNS() << "Not connected to an asset storage system." << LL_ENDL; return false; } @@ -562,8 +561,8 @@ bool LLPreviewNotecard::saveIfNeeded(LLInventoryItem* copyitem) setEnabled(FALSE); LLSD body; body["item_id"] = mItemUUID; - llinfos << "Saving notecard " << mItemUUID - << " into agent inventory via " << agent_url << llendl; + LL_INFOS() << "Saving notecard " << mItemUUID + << " into agent inventory via " << agent_url << LL_ENDL; LLHTTPClient::post(agent_url, body, new LLUpdateAgentInventoryResponder(body, asset_id, LLAssetType::AT_NOTECARD)); } @@ -575,8 +574,8 @@ bool LLPreviewNotecard::saveIfNeeded(LLInventoryItem* copyitem) LLSD body; body["task_id"] = mObjectUUID; body["item_id"] = mItemUUID; - llinfos << "Saving notecard " << mItemUUID << " into task " - << mObjectUUID << " via " << task_url << llendl; + LL_INFOS() << "Saving notecard " << mItemUUID << " into task " + << mObjectUUID << " via " << task_url << LL_ENDL; LLHTTPClient::post(task_url, body, new LLUpdateTaskInventoryResponder(body, asset_id, LLAssetType::AT_NOTECARD)); } @@ -615,8 +614,8 @@ void LLPreviewNotecard::onSaveComplete(const LLUUID& asset_uuid, void* user_data } else { - llwarns << "Inventory item for script " << info->mItemUUID - << " is no longer in agent inventory." << llendl; + LL_WARNS() << "Inventory item for notecard " << info->mItemUUID + << " is no longer in agent inventory." << LL_ENDL; } } else @@ -657,7 +656,7 @@ void LLPreviewNotecard::onSaveComplete(const LLUUID& asset_uuid, void* user_data } else { - llwarns << "Problem saving notecard: " << status << llendl; + LL_WARNS() << "Problem saving notecard: " << status << LL_ENDL; LLSD args; args["REASON"] = std::string(LLAssetStorage::getErrorString(status)); LLNotificationsUtil::add("SaveNotecardFailReason", args); diff --git a/indra/newview/llpreviewnotecard.h b/indra/newview/llpreviewnotecard.h index 442673c0c7..6ea6e1ba80 100644 --- a/indra/newview/llpreviewnotecard.h +++ b/indra/newview/llpreviewnotecard.h @@ -66,6 +66,7 @@ class LLPreviewNotecard : public LLPreview // llview virtual void draw(); + virtual bool hasAccelerators() const { return true; } virtual BOOL handleKeyHere(KEY key, MASK mask); virtual void setEnabled( BOOL enabled ); virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp index 2f02bcd007..3cd30ce8e1 100644 --- a/indra/newview/llpreviewscript.cpp +++ b/indra/newview/llpreviewscript.cpp @@ -1,11 +1,11 @@ -/** +/** * @file llpreviewscript.cpp * @brief LLPreviewScript class implementation * * $LicenseInfo:firstyear=2002&license=viewergpl$ - * + * * Copyright (c) 2002-2009, Linden Research, Inc. - * + * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab * to you under the terms of the GNU General Public License, version 2.0 @@ -13,17 +13,17 @@ * ("Other License"), formally executed by you and Linden Lab. Terms of * the GPL can be found in doc/GPL-license.txt in this distribution, or * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * + * * There are special exceptions to the terms and conditions of the GPL as * it is applied to this Source Code. View the full text of the exception * in the file doc/FLOSS-exception.txt in this software distribution, or * online at * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * + * * By copying, modifying or distributing this software, you acknowledge * that you have read and understood your obligations described above, * and agree to abide by those obligations. - * + * * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, * COMPLETENESS OR PERFORMANCE. @@ -39,6 +39,7 @@ #include "llbutton.h" #include "llcheckboxctrl.h" #include "llcombobox.h" +#include "llcororesponder.h" #include "lldir.h" #include "llexternaleditor.h" #include "statemachine/aifilepicker.h" @@ -64,23 +65,14 @@ #include "llagent.h" #include "llmenugl.h" #include "roles_constants.h" +#include "llfloatersearchreplace.h" +#include "llfloaterperms.h" #include "llselectmgr.h" #include "llviewerinventory.h" #include "llviewermenu.h" #include "llviewerobject.h" #include "llviewerobjectlist.h" #include "llviewerregion.h" -#include "llkeyboard.h" -#include "llscrollcontainer.h" -#include "llcheckboxctrl.h" -#include "llselectmgr.h" -#include "lltooldraganddrop.h" -#include "llscrolllistctrl.h" -#include "lltextbox.h" -#include "llslider.h" -#include "lldir.h" -#include "llcombobox.h" -#include "llfloatersearchreplace.h" #include "llviewerstats.h" #include "llviewertexteditor.h" #include "llviewerwindow.h" @@ -88,8 +80,9 @@ #include "llmediactrl.h" #include "lluictrlfactory.h" #include "lltrans.h" -#include "llviewercontrol.h" #include "llappviewer.h" +#include "llexperiencecache.h" +#include "llfloaterexperienceprofile.h" #include "llsdserialize.h" @@ -126,13 +119,13 @@ const S32 LINE_COLUMN_HEIGHT = 14; const S32 SCRIPT_EDITOR_MIN_HEIGHT = 2 * SCROLLBAR_SIZE + 2 * LLPANEL_BORDER_WIDTH + 128; -const S32 SCRIPT_MIN_WIDTH = - 2 * SCRIPT_BORDER + - 2 * SCRIPT_BUTTON_WIDTH + +const S32 SCRIPT_MIN_WIDTH = + 2 * SCRIPT_BORDER + + 2 * SCRIPT_BUTTON_WIDTH + SCRIPT_PAD + RESIZE_HANDLE_WIDTH + SCRIPT_PAD; -const S32 SCRIPT_MIN_HEIGHT = +const S32 SCRIPT_MIN_HEIGHT = 2 * SCRIPT_BORDER + 3*(SCRIPT_BUTTON_HEIGHT + SCRIPT_PAD) + LINE_COLUMN_HEIGHT + @@ -149,13 +142,35 @@ static bool have_script_upload_cap(LLUUID& object_id) return object && (! object->getRegion()->getCapability("UpdateScriptTask").empty()); } + +class ExperienceResponder : public LLHTTPClient::ResponderWithResult +{ +public: + ExperienceResponder(const LLHandle& parent) : mParent(parent) + { + } + + LLHandle mParent; + + /*virtual*/ void httpSuccess() + { + LLLiveLSLEditor* parent = mParent.get(); + if (!parent) + return; + + parent->setExperienceIds(getContent()["experience_ids"]); + } + + /*virtual*/ char const* getName() const { return "ExperienceResponder"; } +}; + /// --------------------------------------------------------------------------- /// LLLiveLSLFile /// --------------------------------------------------------------------------- class LLLiveLSLFile : public LLLiveFile { public: - typedef boost::function change_callback_t; + typedef std::function change_callback_t; LLLiveLSLFile(std::string file_path, change_callback_t change_cb); ~LLLiveLSLFile(); @@ -163,16 +178,16 @@ class LLLiveLSLFile : public LLLiveFile void ignoreNextUpdate() { mIgnoreNextUpdate = true; } protected: - /*virtual*/ bool loadFile(); + /*virtual*/ bool loadFile() override; change_callback_t mOnChangeCallback; bool mIgnoreNextUpdate; }; LLLiveLSLFile::LLLiveLSLFile(std::string file_path, change_callback_t change_cb) - : mOnChangeCallback(change_cb) +: LLLiveFile(file_path, 1.0) +, mOnChangeCallback(change_cb) , mIgnoreNextUpdate(false) - , LLLiveFile(file_path, 1.0) { llassert(mOnChangeCallback); } @@ -193,6 +208,188 @@ bool LLLiveLSLFile::loadFile() return mOnChangeCallback(filename()); } +// +#if 0 +/// --------------------------------------------------------------------------- +/// LLFloaterScriptSearch +/// --------------------------------------------------------------------------- +class LLFloaterScriptSearch : public LLFloater +{ +public: + LLFloaterScriptSearch(LLScriptEdCore* editor_core); + ~LLFloaterScriptSearch(); + + /*virtual*/ BOOL postBuild(); + static void show(LLScriptEdCore* editor_core); + static void onBtnSearch(void* userdata); + void handleBtnSearch(); + + static void onBtnReplace(void* userdata); + void handleBtnReplace(); + + static void onBtnReplaceAll(void* userdata); + void handleBtnReplaceAll(); + + LLScriptEdCore* getEditorCore() { return mEditorCore; } + static LLFloaterScriptSearch* getInstance() { return sInstance; } + + virtual bool hasAccelerators() const; + virtual BOOL handleKeyHere(KEY key, MASK mask); + +private: + + LLScriptEdCore* mEditorCore; + static LLFloaterScriptSearch* sInstance; + +protected: + LLLineEditor* mSearchBox; + LLLineEditor* mReplaceBox; + void onSearchBoxCommit(); +}; + +LLFloaterScriptSearch* LLFloaterScriptSearch::sInstance = NULL; + +LLFloaterScriptSearch::LLFloaterScriptSearch(LLScriptEdCore* editor_core) +: LLFloater(LLSD()), + mSearchBox(NULL), + mReplaceBox(NULL), + mEditorCore(editor_core) +{ + buildFromFile("floater_script_search.xml"); + + sInstance = this; + + // find floater in which script panel is embedded + LLView* viewp = (LLView*)editor_core; + while(viewp) + { + LLFloater* floaterp = dynamic_cast(viewp); + if (floaterp) + { + floaterp->addDependentFloater(this); + break; + } + viewp = viewp->getParent(); + } +} + +BOOL LLFloaterScriptSearch::postBuild() +{ + mReplaceBox = getChild("replace_text"); + mSearchBox = getChild("search_text"); + mSearchBox->setCommitCallback(boost::bind(&LLFloaterScriptSearch::onSearchBoxCommit, this)); + mSearchBox->setCommitOnFocusLost(FALSE); + childSetAction("search_btn", onBtnSearch,this); + childSetAction("replace_btn", onBtnReplace,this); + childSetAction("replace_all_btn", onBtnReplaceAll,this); + + setDefaultBtn("search_btn"); + + return TRUE; +} + +//static +void LLFloaterScriptSearch::show(LLScriptEdCore* editor_core) +{ + LLSD::String search_text; + LLSD::String replace_text; + if (sInstance && sInstance->mEditorCore && sInstance->mEditorCore != editor_core) + { + search_text=sInstance->mSearchBox->getValue().asString(); + replace_text=sInstance->mReplaceBox->getValue().asString(); + sInstance->closeFloater(); + delete sInstance; + } + + if (!sInstance) + { + // sInstance will be assigned in the constructor. + new LLFloaterScriptSearch(editor_core); + sInstance->mSearchBox->setValue(search_text); + sInstance->mReplaceBox->setValue(replace_text); + } + + sInstance->openFloater(); +} + +LLFloaterScriptSearch::~LLFloaterScriptSearch() +{ + sInstance = NULL; +} + +// static +void LLFloaterScriptSearch::onBtnSearch(void *userdata) +{ + LLFloaterScriptSearch* self = (LLFloaterScriptSearch*)userdata; + self->handleBtnSearch(); +} + +void LLFloaterScriptSearch::handleBtnSearch() +{ + LLCheckBoxCtrl* caseChk = getChild("case_text"); + mEditorCore->mEditor->selectNext(mSearchBox->getValue().asString(), caseChk->get()); +} + +// static +void LLFloaterScriptSearch::onBtnReplace(void *userdata) +{ + LLFloaterScriptSearch* self = (LLFloaterScriptSearch*)userdata; + self->handleBtnReplace(); +} + +void LLFloaterScriptSearch::handleBtnReplace() +{ + LLCheckBoxCtrl* caseChk = getChild("case_text"); + mEditorCore->mEditor->replaceText(mSearchBox->getValue().asString(), mReplaceBox->getValue().asString(), caseChk->get()); +} + +// static +void LLFloaterScriptSearch::onBtnReplaceAll(void *userdata) +{ + LLFloaterScriptSearch* self = (LLFloaterScriptSearch*)userdata; + self->handleBtnReplaceAll(); +} + +void LLFloaterScriptSearch::handleBtnReplaceAll() +{ + LLCheckBoxCtrl* caseChk = getChild("case_text"); + mEditorCore->mEditor->replaceTextAll(mSearchBox->getValue().asString(), mReplaceBox->getValue().asString(), caseChk->get()); +} + +bool LLFloaterScriptSearch::hasAccelerators() const +{ + if (mEditorCore) + { + return mEditorCore->hasAccelerators(); + } + return FALSE; +} + +BOOL LLFloaterScriptSearch::handleKeyHere(KEY key, MASK mask) +{ + if (mEditorCore) + { + BOOL handled = mEditorCore->handleKeyHere(key, mask); + if (!handled) + { + LLFloater::handleKeyHere(key, mask); + } + } + + return FALSE; +} + +void LLFloaterScriptSearch::onSearchBoxCommit() +{ + if (mEditorCore && mEditorCore->mEditor) + { + LLCheckBoxCtrl* caseChk = getChild("case_text"); + mEditorCore->mEditor->selectNext(mSearchBox->getValue().asString(), caseChk->get()); + } +} +#endif +// + /// --------------------------------------------------------------------------- /// LLScriptEdCore /// --------------------------------------------------------------------------- @@ -219,7 +416,7 @@ void LLScriptEdCore::parseFunctions(const std::string& filename) { LLSDSerialize::fromXMLDocument(function_list, importer); importer.close(); - + for (LLSD::map_const_iterator it = function_list.beginMap(); it != function_list.endMap(); ++it) { LSLFunctionProps fn; @@ -254,9 +451,9 @@ LLScriptEdCore::LLScriptEdCore( mLastHelpToken(NULL), mLiveHelpHistorySize(0), mEnableSave(FALSE), + mHasScriptData(FALSE), mLiveFile(NULL), - mContainer(container), - mHasScriptData(FALSE) + mContainer(container) { setFollowsAll(); setBorderVisible(FALSE); @@ -269,19 +466,79 @@ LLScriptEdCore::~LLScriptEdCore() { deleteBridges(); + // If the search window is up for this editor, close it. +// [SL:KB] - Patch: UI-FloaterSearchReplace +// LLFloaterScriptSearch* script_search = LLFloaterScriptSearch::getInstance(); +// if (script_search && script_search->getEditorCore() == this) +// { +// script_search->closeFloater(); +// delete script_search; +// } +// [/SL:KB] + delete mLiveFile; } +void LLLiveLSLEditor::experienceChanged() +{ + if (mScriptEd->getAssociatedExperience() != mExperiences->getSelectedValue().asUUID()) + { + mScriptEd->enableSave(getIsModifiable()); + //getChildView("Save_btn")->setEnabled(TRUE); + mScriptEd->setAssociatedExperience(mExperiences->getSelectedValue().asUUID()); + updateExperiencePanel(); + } +} + +void LLLiveLSLEditor::onViewProfile(LLUICtrl* ui, void* userdata) +{ + LLLiveLSLEditor* self = (LLLiveLSLEditor*)userdata; + + LLUUID id; + if (self->mExperienceEnabled->get()) + { + id = self->mScriptEd->getAssociatedExperience(); + if (id.notNull()) + { + LLFloaterExperienceProfile::showInstance(id); + } + } + +} + +void LLLiveLSLEditor::onToggleExperience(LLUICtrl* ui, void* userdata) +{ + LLLiveLSLEditor* self = (LLLiveLSLEditor*)userdata; + + LLUUID id; + if (self->mExperienceEnabled->get()) + { + if (self->mScriptEd->getAssociatedExperience().isNull()) + { + id = self->mExperienceIds.beginArray()->asUUID(); + } + } + + if (id != self->mScriptEd->getAssociatedExperience()) + { + self->mScriptEd->enableSave(self->getIsModifiable()); + } + self->mScriptEd->setAssociatedExperience(id); + + self->updateExperiencePanel(); +} + BOOL LLScriptEdCore::postBuild() { mErrorList = getChild("lsl errors"); mFunctions = getChild( "Insert..."); - + childSetCommitCallback("Insert...", &LLScriptEdCore::onBtnInsertFunction, this); mEditor = getChild("Script Editor"); mEditor->setHandleEditKeysDirectly(TRUE); + mEditor->setParseHighlights(TRUE); childSetCommitCallback("lsl errors", &LLScriptEdCore::onErrorList, this); childSetAction("Save_btn", boost::bind(&LLScriptEdCore::doSave,this,FALSE)); @@ -300,25 +557,25 @@ BOOL LLScriptEdCore::postBuild() { std::string name = i->mName; funcs.push_back(name); - + std::string desc_name = "LSLTipText_"; desc_name += name; std::string desc = LLTrans::getString(desc_name); - + F32 sleep_time = i->mSleepTime; if( sleep_time ) { desc += "\n"; - + LLStringUtil::format_map_t args; args["[SLEEP_TIME]"] = llformat("%.1f", sleep_time ); desc += LLTrans::getString("LSLTipSleepTime", args); } - + // A \n linefeed is not part of xml. Let's add one to keep all // the tips one-per-line in strings.xml LLStringUtil::replaceString( desc, "\\n", "\n" ); - + tooltips.push_back(desc); } } @@ -376,7 +633,7 @@ void LLScriptEdCore::initMenu() menuItem = getChild("Save"); menuItem->setMenuCallback(onBtnSave, this); menuItem->setEnabledCallback(hasChanged); - + menuItem = getChild("Revert All Changes"); menuItem->setMenuCallback(onBtnUndoChanges, this); menuItem->setEnabledCallback(hasChanged); @@ -410,8 +667,12 @@ void LLScriptEdCore::initMenu() menuItem->setEnabledCallback(enableDeselectMenu); menuItem = getChild("Search / Replace..."); +// menuItem->setClickCallback(boost::bind(&LLFloaterScriptSearch::show, this)); menuItem->setMenuCallback(onSearchMenu, this); menuItem->setEnabledCallback(NULL); +// [/SL:KB] + + // Singu TODO: Merge LLFloaterGotoLine? menuItem = getChild("Help..."); menuItem->setMenuCallback(onBtnHelp, this); @@ -435,32 +696,40 @@ bool LLScriptEdCore::loadScriptText(const std::string& filename) { if (filename.empty()) { - llwarns << "Empty file name" << llendl; + LL_WARNS() << "Empty file name" << LL_ENDL; return false; } LLFILE* file = LLFile::fopen(filename, "rb"); /*Flawfinder: ignore*/ if (!file) { - llwarns << "Error opening " << filename << llendl; + LL_WARNS() << "Error opening " << filename << LL_ENDL; return false; } // read in the whole file fseek(file, 0L, SEEK_END); - size_t file_length = (size_t) ftell(file); + size_t file_length = ftell(file); fseek(file, 0L, SEEK_SET); - char* buffer = new char[file_length+1]; - size_t nread = fread(buffer, 1, file_length, file); - if (nread < file_length) + if (file_length > 0) { - llwarns << "Short read" << llendl; - } - buffer[nread] = '\0'; - fclose(file); + char* buffer = new char[file_length+1]; + size_t nread = fread(buffer, 1, file_length, file); + if (nread < file_length) + { + LL_WARNS() << "Short read" << LL_ENDL; + } + buffer[nread] = '\0'; + fclose(file); - mEditor->setText(LLStringExplicit(buffer)); - delete[] buffer; + mEditor->setText(LLStringExplicit(buffer)); + delete[] buffer; + } + else + { + LL_WARNS() << "Error opening " << filename << LL_ENDL; + return false; + } return true; } @@ -470,7 +739,7 @@ bool LLScriptEdCore::writeToFile(const std::string& filename) LLFILE* fp = LLFile::fopen(filename, "wb"); if (!fp) { - llwarns << "Unable to write to " << filename << llendl; + LL_WARNS() << "Unable to write to " << filename << LL_ENDL; LLSD row; row["columns"][0]["value"] = LLTrans::getString("CompileQueueProblemWriting"); @@ -482,9 +751,33 @@ bool LLScriptEdCore::writeToFile(const std::string& filename) std::string utf8text = mEditor->getText(); // Special case for a completely empty script - stuff in one space so it can store properly. See SL-46889 - if (utf8text.size() == 0) + if (utf8text.empty()) + { + utf8text.push_back(' '); + } + else // We cut the fat ones down to size { - utf8text = " "; + std::stringstream strm(utf8text); + utf8text.clear(); + bool quote = false; + for (std::string line; std::getline(strm, line);) + { + //if ((std::count(line.begin(), line.end(), '"') % 2) == 0) quote = !quote; // This would work if escaping wasn't a thing + bool backslash = false; + for (const auto& ch : line) + { + switch (ch) + { + case '\\': backslash = !backslash; break; + case '"': if (!backslash) quote = !quote; // Fall through + default: backslash = false; break; + } + } + if (!quote) LLStringUtil::trimTail(line); + if (!utf8text.empty()) utf8text += '\n'; + utf8text += line; + } + if (utf8text.empty()) utf8text.push_back(' '); } fputs(utf8text.c_str(), fp); @@ -604,7 +897,7 @@ void LLScriptEdCore::setHelpPage(const std::string& help_string) { LLFloater* help_floater = mLiveHelpHandle.get(); if (!help_floater) return; - + LLMediaCtrl* web_browser = help_floater->getChild("lsl_guide_html"); if (!web_browser) return; @@ -709,7 +1002,7 @@ bool LLScriptEdCore::handleSaveChangesDialog(const LLSD& notification, const LLS return false; } -// static +// static bool LLScriptEdCore::onHelpWebDialog(const LLSD& notification, const LLSD& response) { S32 option = LLNotificationsUtil::getSelectedOption(notification, response); @@ -725,7 +1018,7 @@ bool LLScriptEdCore::onHelpWebDialog(const LLSD& notification, const LLSD& respo return false; } -// static +// static void LLScriptEdCore::onBtnHelp(void* userdata) { LLSD payload; @@ -733,7 +1026,7 @@ void LLScriptEdCore::onBtnHelp(void* userdata) LLNotificationsUtil::add("WebLaunchLSLGuide", LLSD(), payload, onHelpWebDialog); } -// static +// static void LLScriptEdCore::onBtnDynamicHelp(void* userdata) { LLScriptEdCore* corep = (LLScriptEdCore*)userdata; @@ -762,8 +1055,8 @@ void LLScriptEdCore::onBtnDynamicHelp(void* userdata) LLComboBox* help_combo = live_help_floater->getChild("history_combo"); LLKeywordToken *token; LLKeywords::keyword_iterator_t token_it; - for (token_it = corep->mEditor->keywordsBegin(); - token_it != corep->mEditor->keywordsEnd(); + for (token_it = corep->mEditor->keywordsBegin(); + token_it != corep->mEditor->keywordsEnd(); ++token_it) { token = token_it->second; @@ -778,7 +1071,7 @@ void LLScriptEdCore::onBtnDynamicHelp(void* userdata) corep->updateDynamicHelp(TRUE); } -//static +//static void LLScriptEdCore::onClickBack(void* userdata) { LLScriptEdCore* corep = (LLScriptEdCore*)userdata; @@ -793,7 +1086,7 @@ void LLScriptEdCore::onClickBack(void* userdata) } } -//static +//static void LLScriptEdCore::onClickForward(void* userdata) { LLScriptEdCore* corep = (LLScriptEdCore*)userdata; @@ -819,7 +1112,7 @@ void LLScriptEdCore::onCheckLock(LLUICtrl* ctrl, void* userdata) corep->mLastHelpToken = NULL; } -// static +// static void LLScriptEdCore::onBtnInsertSample(void* userdata) { LLScriptEdCore* self = (LLScriptEdCore*) userdata; @@ -830,7 +1123,7 @@ void LLScriptEdCore::onBtnInsertSample(void* userdata) self->mEditor->insertText(self->mSampleText); } -// static +// static void LLScriptEdCore::onHelpComboCommit(LLUICtrl* ctrl, void* userdata) { LLScriptEdCore* corep = (LLScriptEdCore*)userdata; @@ -849,7 +1142,7 @@ void LLScriptEdCore::onHelpComboCommit(LLUICtrl* ctrl, void* userdata) } } -// static +// static void LLScriptEdCore::onBtnInsertFunction(LLUICtrl *ui, void* userdata) { LLScriptEdCore* self = (LLScriptEdCore*) userdata; @@ -953,7 +1246,7 @@ void LLScriptEdCore::onSearchMenu(void* userdata) } } -// static +// static void LLScriptEdCore::onUndoMenu(void* userdata) { LLScriptEdCore* self = (LLScriptEdCore*)userdata; @@ -961,7 +1254,7 @@ void LLScriptEdCore::onUndoMenu(void* userdata) self->mEditor->undo(); } -// static +// static void LLScriptEdCore::onRedoMenu(void* userdata) { LLScriptEdCore* self = (LLScriptEdCore*)userdata; @@ -969,7 +1262,7 @@ void LLScriptEdCore::onRedoMenu(void* userdata) self->mEditor->redo(); } -// static +// static void LLScriptEdCore::onCutMenu(void* userdata) { LLScriptEdCore* self = (LLScriptEdCore*)userdata; @@ -977,7 +1270,7 @@ void LLScriptEdCore::onCutMenu(void* userdata) self->mEditor->cut(); } -// static +// static void LLScriptEdCore::onCopyMenu(void* userdata) { LLScriptEdCore* self = (LLScriptEdCore*)userdata; @@ -985,7 +1278,7 @@ void LLScriptEdCore::onCopyMenu(void* userdata) self->mEditor->copy(); } -// static +// static void LLScriptEdCore::onPasteMenu(void* userdata) { LLScriptEdCore* self = (LLScriptEdCore*)userdata; @@ -993,7 +1286,7 @@ void LLScriptEdCore::onPasteMenu(void* userdata) self->mEditor->paste(); } -// static +// static void LLScriptEdCore::onSelectAllMenu(void* userdata) { LLScriptEdCore* self = (LLScriptEdCore*)userdata; @@ -1001,7 +1294,7 @@ void LLScriptEdCore::onSelectAllMenu(void* userdata) self->mEditor->selectAll(); } -// static +// static void LLScriptEdCore::onDeselectMenu(void* userdata) { LLScriptEdCore* self = (LLScriptEdCore*)userdata; @@ -1009,7 +1302,7 @@ void LLScriptEdCore::onDeselectMenu(void* userdata) self->mEditor->deselect(); } -// static +// static BOOL LLScriptEdCore::enableUndoMenu(void* userdata) { LLScriptEdCore* self = (LLScriptEdCore*)userdata; @@ -1017,7 +1310,7 @@ BOOL LLScriptEdCore::enableUndoMenu(void* userdata) return self->mEditor->canUndo(); } -// static +// static BOOL LLScriptEdCore::enableRedoMenu(void* userdata) { LLScriptEdCore* self = (LLScriptEdCore*)userdata; @@ -1025,7 +1318,7 @@ BOOL LLScriptEdCore::enableRedoMenu(void* userdata) return self->mEditor->canRedo(); } -// static +// static BOOL LLScriptEdCore::enableCutMenu(void* userdata) { LLScriptEdCore* self = (LLScriptEdCore*)userdata; @@ -1033,7 +1326,7 @@ BOOL LLScriptEdCore::enableCutMenu(void* userdata) return self->mEditor->canCut(); } -// static +// static BOOL LLScriptEdCore::enableCopyMenu(void* userdata) { LLScriptEdCore* self = (LLScriptEdCore*)userdata; @@ -1041,7 +1334,7 @@ BOOL LLScriptEdCore::enableCopyMenu(void* userdata) return self->mEditor->canCopy(); } -// static +// static BOOL LLScriptEdCore::enablePasteMenu(void* userdata) { LLScriptEdCore* self = (LLScriptEdCore*)userdata; @@ -1049,7 +1342,7 @@ BOOL LLScriptEdCore::enablePasteMenu(void* userdata) return self->mEditor->canPaste(); } -// static +// static BOOL LLScriptEdCore::enableSelectAllMenu(void* userdata) { LLScriptEdCore* self = (LLScriptEdCore*)userdata; @@ -1057,7 +1350,7 @@ BOOL LLScriptEdCore::enableSelectAllMenu(void* userdata) return self->mEditor->canSelectAll(); } -// static +// static BOOL LLScriptEdCore::enableDeselectMenu(void* userdata) { LLScriptEdCore* self = (LLScriptEdCore*)userdata; @@ -1081,10 +1374,9 @@ void LLScriptEdCore::onErrorList(LLUICtrl*, void* user_data) LLStringUtil::replaceChar(line, ',',' '); LLStringUtil::replaceChar(line, ')',' '); sscanf(line.c_str(), "%d %d", &row, &column); - //llinfos << "LLScriptEdCore::onErrorList() - " << row << ", " - //<< column << llendl; + //LL_INFOS() << "LLScriptEdCore::onErrorList() - " << row << ", " + //<< column << LL_ENDL; self->mEditor->setCursor(row, column); - self->mEditor->setFocus(TRUE); } } @@ -1130,15 +1422,15 @@ struct LLEntryAndEdCore void LLScriptEdCore::deleteBridges() { - S32 count = mBridges.count(); + S32 count = mBridges.size(); LLEntryAndEdCore* eandc; for(S32 i = 0; i < count; i++) { - eandc = mBridges.get(i); + eandc = mBridges.at(i); delete eandc; mBridges[i] = NULL; } - mBridges.reset(); + mBridges.clear(); } // virtual @@ -1170,6 +1462,153 @@ BOOL LLScriptEdCore::handleKeyHere(KEY key, MASK mask) return FALSE; } +LLUUID LLScriptEdCore::getAssociatedExperience() const +{ + return mAssociatedExperience; +} + +void LLLiveLSLEditor::setExperienceIds(const LLSD& experience_ids) +{ + mExperienceIds = experience_ids; + updateExperiencePanel(); +} + + +void LLLiveLSLEditor::updateExperiencePanel() +{ + if (mScriptEd->getAssociatedExperience().isNull()) + { + mExperienceEnabled->set(FALSE); + mExperiences->setVisible(FALSE); + if (mExperienceIds.size() > 0) + { + mExperienceEnabled->setEnabled(TRUE); + mExperienceEnabled->setToolTip(getString("add_experiences")); + } + else + { + mExperienceEnabled->setEnabled(FALSE); + mExperienceEnabled->setToolTip(getString("no_experiences")); + } + getChild("view_profile")->setVisible(FALSE); + } + else + { + mExperienceEnabled->setToolTip(getString("experience_enabled")); + mExperienceEnabled->setEnabled(getIsModifiable()); + mExperiences->setVisible(TRUE); + mExperienceEnabled->set(TRUE); + getChild("view_profile")->setToolTip(getString("show_experience_profile")); + buildExperienceList(); + } +} + +void LLLiveLSLEditor::buildExperienceList() +{ + mExperiences->clearRows(); + bool foundAssociated = false; + const LLUUID& associated = mScriptEd->getAssociatedExperience(); + LLUUID last; + LLScrollListItem* item; + for(LLSD::array_const_iterator it = mExperienceIds.beginArray(); it != mExperienceIds.endArray(); ++it) + { + LLUUID id = it->asUUID(); + EAddPosition position = ADD_BOTTOM; + if (id == associated) + { + foundAssociated = true; + position = ADD_TOP; + } + + const LLSD& experience = LLExperienceCache::instance().get(id); + if (experience.isUndefined()) + { + mExperiences->add(getString("loading"), id, position); + last = id; + } + else + { + std::string experience_name_string = experience[LLExperienceCache::NAME].asString(); + if (experience_name_string.empty()) + { + experience_name_string = LLTrans::getString("ExperienceNameUntitled"); + } + mExperiences->add(experience_name_string, id, position); + } + } + + if (!foundAssociated) + { + const LLSD& experience = LLExperienceCache::instance().get(associated); + if (experience.isDefined()) + { + std::string experience_name_string = experience[LLExperienceCache::NAME].asString(); + if (experience_name_string.empty()) + { + experience_name_string = LLTrans::getString("ExperienceNameUntitled"); + } + item=mExperiences->add(experience_name_string, associated, ADD_TOP); + } + else + { + item = mExperiences->add(getString("loading"), associated, ADD_TOP); + last = associated; + } + item->setEnabled(FALSE); + } + + if (last.notNull()) + { + mExperiences->setEnabled(FALSE); + LLExperienceCache::instance().get(last, boost::bind(&LLLiveLSLEditor::buildExperienceList, this)); + } + else + { + mExperiences->setEnabled(TRUE); + mExperiences->sortByName(TRUE); + mExperiences->setCurrentByIndex(mExperiences->getCurrentIndex()); + getChild("view_profile")->setVisible(TRUE); + } +} + + +void LLScriptEdCore::setAssociatedExperience(const LLUUID& experience_id) +{ + mAssociatedExperience = experience_id; +} + + + +void LLLiveLSLEditor::requestExperiences() +{ + if (!getIsModifiable()) + { + return; + } + + LLViewerRegion* region = gAgent.getRegion(); + if (region) + { + std::string lookup_url = region->getCapability("GetCreatorExperiences"); + if (!lookup_url.empty()) + { + LLHTTPClient::get(lookup_url, new LLCoroResponder( + boost::bind(&LLLiveLSLEditor::receiveExperienceIds, _1, getDerivedHandle()))); + } + } +} + +/*static*/ +void LLLiveLSLEditor::receiveExperienceIds(const LLCoroResponder& responder, LLHandle hparent) +{ + LLLiveLSLEditor* parent = hparent.get(); + if (!parent) + return; + + parent->setExperienceIds(responder.getContent()["experience_ids"]); +} + + /// --------------------------------------------------------------------------- /// LLScriptEdContainer /// --------------------------------------------------------------------------- @@ -1207,18 +1646,6 @@ bool LLScriptEdContainer::onExternalChange(const std::string& filename) return true; } -// virtual -void LLScriptEdContainer::reshape(S32 width, S32 height, BOOL called_from_parent) -{ - LLPreview::reshape(width, height, called_from_parent); - - if (!isMinimized()) - { - // So that next time you open a script it will have the same height and width (although not the same position). - gSavedSettings.setRect("PreviewScriptRect", getRect()); - } -} - // // virtual BOOL LLScriptEdContainer::canSaveAs() const @@ -1268,7 +1695,7 @@ struct LLScriptSaveInfo //static void* LLPreviewLSL::createScriptEdPanel(void* userdata) { - + LLPreviewLSL *self = (LLPreviewLSL*)userdata; self->mScriptEd = new LLScriptEdCore( @@ -1280,7 +1707,6 @@ void* LLPreviewLSL::createScriptEdPanel(void* userdata) LLPreviewLSL::onSearchReplace, self, 0); - return self->mScriptEd; } @@ -1296,7 +1722,7 @@ LLPreviewLSL::LLPreviewLSL(const std::string& name, const LLRect& rect, const st // virtual BOOL LLPreviewLSL::postBuild() { - const LLInventoryItem* item = getItem(); + const LLInventoryItem* item = getItem(); llassert(item); if (item) @@ -1312,7 +1738,7 @@ BOOL LLPreviewLSL::postBuild() // virtual void LLPreviewLSL::callbackLSLCompileSucceeded() { - llinfos << "LSL Bytecode saved" << llendl; + LL_INFOS() << "LSL Bytecode saved" << LL_ENDL; mScriptEd->mErrorList->setCommentText(LLTrans::getString("CompileSuccessful")); mScriptEd->mErrorList->setCommentText(LLTrans::getString("SaveComplete")); closeIfNeeded(); @@ -1321,7 +1747,7 @@ void LLPreviewLSL::callbackLSLCompileSucceeded() // virtual void LLPreviewLSL::callbackLSLCompileFailed(const LLSD& compile_errors) { - llinfos << "Compile failed!" << llendl; + LL_INFOS() << "Compile failed!" << LL_ENDL; for(LLSD::array_const_iterator line = compile_errors.beginArray(); line < compile_errors.endArray(); @@ -1354,7 +1780,7 @@ void LLPreviewLSL::loadAsset() } if(item) { - BOOL is_copyable = gAgent.allowOperation(PERM_COPY, + BOOL is_copyable = gAgent.allowOperation(PERM_COPY, item->getPermissions(), GP_OBJECT_MANIPULATE); BOOL is_modifiable = gAgent.allowOperation(PERM_MODIFY, item->getPermissions(), GP_OBJECT_MANIPULATE); @@ -1412,7 +1838,7 @@ void LLPreviewLSL::closeIfNeeded() void LLPreviewLSL::onSearchReplace(void* userdata) { LLPreviewLSL* self = (LLPreviewLSL*)userdata; - LLScriptEdCore* sec = self->mScriptEd; + LLScriptEdCore* sec = self->mScriptEd; if (sec && sec->mEditor) { LLFloaterSearchReplace::show(sec->mEditor); @@ -1439,7 +1865,6 @@ void LLPreviewLSL::onSave(void* userdata, BOOL close_after_save) // fails, go ahead and save the text anyway. void LLPreviewLSL::saveIfNeeded(bool sync /*= true*/) { - // llinfos << "LLPreviewLSL::saveIfNeeded()" << llendl; if(!mScriptEd->hasChanged()) { return; @@ -1447,6 +1872,7 @@ void LLPreviewLSL::saveIfNeeded(bool sync /*= true*/) mPendingUploads = 0; mScriptEd->mErrorList->deleteAllItems(); + mScriptEd->mErrorList->setCommentText(""); mScriptEd->mEditor->makePristine(); // save off asset into file @@ -1463,13 +1889,14 @@ void LLPreviewLSL::saveIfNeeded(bool sync /*= true*/) mScriptEd->sync(); } + if (!gAgent.getRegion()) return; const LLInventoryItem *inv_item = getItem(); // save it out to asset server - std::string url = gAgent.getRegion()->getCapability("UpdateScriptAgent"); if(inv_item) { getWindow()->incBusyCount(); mPendingUploads++; + std::string url = gAgent.getRegion()->getCapability("UpdateScriptAgent"); if (!url.empty()) { uploadAssetViaCaps(url, filename, mItemUUID); @@ -1480,12 +1907,6 @@ void LLPreviewLSL::saveIfNeeded(bool sync /*= true*/) mScriptEd->mErrorList->setCommentText(LLTrans::getString("CompileQueueProblemUploading")); LLFile::remove(filename); } -#if 0 //Client side compiling disabled. - else if (gAssetStorage) - { - uploadAssetLegacy(filename, mItemUUID, tid); - } -#endif } } @@ -1493,7 +1914,7 @@ void LLPreviewLSL::uploadAssetViaCaps(const std::string& url, const std::string& filename, const LLUUID& item_id) { - llinfos << "Update Agent Inventory via capability" << llendl; + LL_INFOS() << "Update Agent Inventory via capability" << LL_ENDL; LLSD body; body["item_id"] = item_id; if (gSavedSettings.getBOOL("SaveInventoryScriptsAsMono")) @@ -1507,186 +1928,12 @@ void LLPreviewLSL::uploadAssetViaCaps(const std::string& url, LLHTTPClient::post(url, body, new LLUpdateAgentInventoryResponder(body, filename, LLAssetType::AT_LSL_TEXT)); } -#if 0 //Client side compiling disabled. -void LLPreviewLSL::uploadAssetLegacy(const std::string& filename, - const LLUUID& item_id, - const LLTransactionID& tid) -{ - LLLineEditor* descEditor = getChild("desc"); - LLScriptSaveInfo* info = new LLScriptSaveInfo(item_id, - descEditor->getText(), - tid); - gAssetStorage->storeAssetData(filename, tid, - LLAssetType::AT_LSL_TEXT, - &LLPreviewLSL::onSaveComplete, - info); - - LLAssetID asset_id = tid.makeAssetID(gAgent.getSecureSessionID()); - std::string filepath = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,asset_id.asString()); - std::string dst_filename = llformat("%s.lso", filepath.c_str()); - std::string err_filename = llformat("%s.out", filepath.c_str()); - - const BOOL compile_to_mono = FALSE; - if(!lscript_compile(filename.c_str(), - dst_filename.c_str(), - err_filename.c_str(), - compile_to_mono, - asset_id.asString().c_str(), - gAgent.isGodlike())) - { - llinfos << "Compile failed!" << llendl; - //char command[256]; - //sprintf(command, "type %s\n", err_filename.c_str()); - //system(command); - - // load the error file into the error scrolllist - LLFILE* fp = LLFile::fopen(err_filename, "r"); - if(fp) - { - char buffer[MAX_STRING]; /*Flawfinder: ignore*/ - std::string line; - while(!feof(fp)) - { - if (fgets(buffer, MAX_STRING, fp) == NULL) - { - buffer[0] = '\0'; - } - if(feof(fp)) - { - break; - } - else - { - line.assign(buffer); - LLStringUtil::stripNonprintable(line); - - LLSD row; - row["columns"][0]["value"] = line; - row["columns"][0]["font"] = "OCRA"; - mScriptEd->mErrorList->addElement(row); - } - } - fclose(fp); - mScriptEd->selectFirstError(); - } - } - else - { - llinfos << "Compile worked!" << llendl; - if(gAssetStorage) - { - getWindow()->incBusyCount(); - mPendingUploads++; - LLUUID* this_uuid = new LLUUID(mItemUUID); - gAssetStorage->storeAssetData(dst_filename, - tid, - LLAssetType::AT_LSL_BYTECODE, - &LLPreviewLSL::onSaveBytecodeComplete, - (void**)this_uuid); - } - } - - // get rid of any temp files left lying around - LLFile::remove(filename); - LLFile::remove(err_filename); - LLFile::remove(dst_filename); -} - - -// static -void LLPreviewLSL::onSaveComplete(const LLUUID& asset_uuid, void* user_data, S32 status, LLExtStat ext_status) // StoreAssetData callback (fixed) -{ - LLScriptSaveInfo* info = reinterpret_cast(user_data); - if(0 == status) - { - if (info) - { - const LLViewerInventoryItem* item; - item = (const LLViewerInventoryItem*)gInventory.getItem(info->mItemUUID); - if(item) - { - LLPointer new_item = new LLViewerInventoryItem(item); - new_item->setAssetUUID(asset_uuid); - new_item->setTransactionID(info->mTransactionID); - new_item->updateServer(FALSE); - gInventory.updateItem(new_item); - gInventory.notifyObservers(); - } - else - { - llwarns << "Inventory item for script " << info->mItemUUID - << " is no longer in agent inventory." << llendl; - } - - // Find our window and close it if requested. - LLPreviewLSL* self = static_cast(LLPreview::find(info->mItemUUID)); - if (self) - { - getWindow()->decBusyCount(); - self->mPendingUploads--; - if (self->mPendingUploads <= 0 - && self->mCloseAfterSave) - { - self->close(); - } - } - } - } - else - { - llwarns << "Problem saving script: " << status << llendl; - LLSD args; - args["REASON"] = std::string(LLAssetStorage::getErrorString(status)); - LLNotificationsUtil::add("SaveScriptFailReason", args); - } - delete info; -} - -// static -void LLPreviewLSL::onSaveBytecodeComplete(const LLUUID& asset_uuid, void* user_data, S32 status, LLExtStat ext_status) // StoreAssetData callback (fixed) -{ - LLUUID* instance_uuid = (LLUUID*)user_data; - LLPreviewLSL* self = NULL; - if(instance_uuid) - { - self = static_cast(LLPreview::find(*instance_uuid)); - } - if (0 == status) - { - if (self) - { - LLSD row; - row["columns"][0]["value"] = "Compile successful!"; - row["columns"][0]["font"] = "SANSSERIF_SMALL"; - self->mScriptEd->mErrorList->addElement(row); - - // Find our window and close it if requested. - self->getWindow()->decBusyCount(); - self->mPendingUploads--; - if (self->mPendingUploads <= 0 - && self->mCloseAfterSave) - { - self->close(); - } - } - } - else - { - llwarns << "Problem saving LSL Bytecode (Preview)" << llendl; - LLSD args; - args["REASON"] = std::string(LLAssetStorage::getErrorString(status)); - LLNotificationsUtil::add("SaveBytecodeFailReason", args); - } - delete instance_uuid; -} -#endif - // static void LLPreviewLSL::onLoadComplete( LLVFS *vfs, const LLUUID& asset_uuid, LLAssetType::EType type, void* user_data, S32 status, LLExtStat ext_status) { - lldebugs << "LLPreviewLSL::onLoadComplete: got uuid " << asset_uuid - << llendl; + LL_DEBUGS() << "LLPreviewLSL::onLoadComplete: got uuid " << asset_uuid + << LL_ENDL; LLUUID* item_uuid = (LLUUID*)user_data; LLPreviewLSL* preview = static_cast(LLPreview::find(*item_uuid)); if( preview ) @@ -1710,7 +1957,7 @@ void LLPreviewLSL::onLoadComplete( LLVFS *vfs, const LLUUID& asset_uuid, LLAsset && gAgent.allowOperation(PERM_MODIFY, item->getPermissions(), GP_OBJECT_MANIPULATE)) { - is_modifiable = TRUE; + is_modifiable = TRUE; } preview->mScriptEd->setEnableEditing(is_modifiable); preview->mAssetStatus = PREVIEW_ASSET_LOADED; @@ -1734,7 +1981,7 @@ void LLPreviewLSL::onLoadComplete( LLVFS *vfs, const LLUUID& asset_uuid, LLAsset } preview->mAssetStatus = PREVIEW_ASSET_ERROR; - llwarns << "Problem loading script: " << status << llendl; + LL_WARNS() << "Problem loading script: " << status << LL_ENDL; } } delete item_uuid; @@ -1746,10 +1993,9 @@ void LLPreviewLSL::onLoadComplete( LLVFS *vfs, const LLUUID& asset_uuid, LLAsset /// --------------------------------------------------------------------------- -//static +//static void* LLLiveLSLEditor::createScriptEdPanel(void* userdata) { - LLLiveLSLEditor *self = (LLLiveLSLEditor*)userdata; self->mScriptEd = new LLScriptEdCore( @@ -1761,19 +2007,18 @@ void* LLLiveLSLEditor::createScriptEdPanel(void* userdata) &LLLiveLSLEditor::onSearchReplace, self, 0); - return self->mScriptEd; } LLLiveLSLEditor::LLLiveLSLEditor(const std::string& name, const LLRect& rect, const std::string& title, const LLUUID& object_id, const LLUUID& item_id) : LLScriptEdContainer(name, rect, title, item_id, object_id), + mIsNew(false), mAskedForRunningInfo(FALSE), mHaveRunningInfo(FALSE), mCloseAfterSave(FALSE), mPendingUploads(0), - mIsModifiable(FALSE), - mIsNew(false) + mIsModifiable(FALSE) { mFactoryMap["script ed panel"] = LLCallbackMap(LLLiveLSLEditor::createScriptEdPanel, this); LLUICtrlFactory::getInstance()->buildFloater(this,"floater_live_lsleditor.xml", &getFactoryMap()); @@ -1794,6 +2039,16 @@ BOOL LLLiveLSLEditor::postBuild() mScriptEd->mEditor->makePristine(); mScriptEd->mEditor->setFocus(TRUE); + + mExperiences = getChild("Experiences..."); + mExperiences->setCommitCallback(boost::bind(&LLLiveLSLEditor::experienceChanged, this)); + + mExperienceEnabled = getChild("enable_xp"); + + childSetCommitCallback("enable_xp", onToggleExperience, this); + childSetCommitCallback("view_profile", onViewProfile, this); + + return LLPreview::postBuild(); } @@ -1802,7 +2057,7 @@ void LLLiveLSLEditor::callbackLSLCompileSucceeded(const LLUUID& task_id, const LLUUID& item_id, bool is_script_running) { - lldebugs << "LSL Bytecode saved" << llendl; + LL_DEBUGS() << "LSL Bytecode saved" << LL_ENDL; mScriptEd->mErrorList->setCommentText(LLTrans::getString("CompileSuccessful")); mScriptEd->mErrorList->setCommentText(LLTrans::getString("SaveComplete")); closeIfNeeded(); @@ -1811,7 +2066,7 @@ void LLLiveLSLEditor::callbackLSLCompileSucceeded(const LLUUID& task_id, // virtual void LLLiveLSLEditor::callbackLSLCompileFailed(const LLSD& compile_errors) { - lldebugs << "Compile failed!" << llendl; + LL_DEBUGS() << "Compile failed!" << LL_ENDL; for(LLSD::array_const_iterator line = compile_errors.beginArray(); line < compile_errors.endArray(); line++) @@ -1830,67 +2085,73 @@ void LLLiveLSLEditor::callbackLSLCompileFailed(const LLSD& compile_errors) void LLLiveLSLEditor::loadAsset() { - //llinfos << "LLLiveLSLEditor::loadAsset()" << llendl; + //LL_INFOS() << "LLLiveLSLEditor::loadAsset()" << LL_ENDL; if(!mIsNew) { LLViewerObject* object = gObjectList.findObject(mObjectUUID); if(object) { LLViewerInventoryItem* item = dynamic_cast(object->getInventoryObject(mItemUUID)); - if(item - && (gAgent.allowOperation(PERM_COPY, item->getPermissions(), GP_OBJECT_MANIPULATE) - || gAgent.isGodlike())) - { - mItem = new LLViewerInventoryItem(item); - //llinfos << "asset id " << mItem->getAssetUUID() << llendl; - } - if(!gAgent.isGodlike() - && (item - && (!gAgent.allowOperation(PERM_COPY, item->getPermissions(), GP_OBJECT_MANIPULATE) - || !gAgent.allowOperation(PERM_MODIFY, item->getPermissions(), GP_OBJECT_MANIPULATE)))) + if (item) { - mItem = new LLViewerInventoryItem(item); - mScriptEd->setScriptText(getString("not_allowed"), FALSE); - mScriptEd->mEditor->makePristine(); - mScriptEd->enableSave(FALSE); - mAssetStatus = PREVIEW_ASSET_LOADED; - } - else if(item && mItem.notNull()) - { - // request the text from the object - LLUUID* user_data = new LLUUID(mItemUUID); // ^ mObjectUUID - gAssetStorage->getInvItemAsset(object->getRegion()->getHost(), - gAgent.getID(), - gAgent.getSessionID(), - item->getPermissions().getOwner(), - object->getID(), - item->getUUID(), - item->getAssetUUID(), - item->getType(), - &LLLiveLSLEditor::onLoadComplete, - (void*)user_data, - TRUE); - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_GetScriptRunning); - msg->nextBlockFast(_PREHASH_Script); - msg->addUUIDFast(_PREHASH_ObjectID, mObjectUUID); - msg->addUUIDFast(_PREHASH_ItemID, mItemUUID); - msg->sendReliable(object->getRegion()->getHost()); - mAskedForRunningInfo = TRUE; - mAssetStatus = PREVIEW_ASSET_LOADING; + LLViewerRegion* region = object->getRegion(); + std::string url = std::string(); + if(region) + { + url = region->getCapability("GetMetadata"); + } + LLExperienceCache::instance().fetchAssociatedExperience(item->getParentUUID(), item->getUUID(), url, + boost::bind(&LLLiveLSLEditor::setAssociatedExperience, getDerivedHandle(), _1)); + + bool isGodlike = gAgent.isGodlike(); + bool copyManipulate = gAgent.allowOperation(PERM_COPY, item->getPermissions(), GP_OBJECT_MANIPULATE); + mIsModifiable = gAgent.allowOperation(PERM_MODIFY, item->getPermissions(), GP_OBJECT_MANIPULATE); + + if (!isGodlike && (!copyManipulate || !mIsModifiable)) + { + mItem = new LLViewerInventoryItem(item); + mScriptEd->setScriptText(getString("not_allowed"), FALSE); + mScriptEd->mEditor->makePristine(); + mScriptEd->enableSave(FALSE); + mAssetStatus = PREVIEW_ASSET_LOADED; + } + else if (copyManipulate || isGodlike) + { + mItem = new LLViewerInventoryItem(item); + // request the text from the object + LLUUID* user_data = new LLUUID(mItemUUID); // ^ mObjectUUID + gAssetStorage->getInvItemAsset(object->getRegion()->getHost(), + gAgent.getID(), + gAgent.getSessionID(), + item->getPermissions().getOwner(), + object->getID(), + item->getUUID(), + item->getAssetUUID(), + item->getType(), + &LLLiveLSLEditor::onLoadComplete, + (void*)user_data, + TRUE); + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_GetScriptRunning); + msg->nextBlockFast(_PREHASH_Script); + msg->addUUIDFast(_PREHASH_ObjectID, mObjectUUID); + msg->addUUIDFast(_PREHASH_ItemID, mItemUUID); + msg->sendReliable(object->getRegion()->getHost()); + mAskedForRunningInfo = TRUE; + mAssetStatus = PREVIEW_ASSET_LOADING; + } } - else + + if (mItem.isNull()) { mScriptEd->setScriptText(LLStringUtil::null, FALSE); mScriptEd->mEditor->makePristine(); mAssetStatus = PREVIEW_ASSET_LOADED; + mIsModifiable = FALSE; } - mIsModifiable = item && gAgent.allowOperation(PERM_MODIFY, - item->getPermissions(), - GP_OBJECT_MANIPULATE); - + refreshFromItem(item); // This is commented out, because we don't completely // handle script exports yet. /* @@ -1913,7 +2174,7 @@ void LLLiveLSLEditor::loadAsset() mScriptEd->enableSave(FALSE); LLPermissions perm; perm.init(gAgent.getID(), gAgent.getID(), LLUUID::null, gAgent.getGroupID()); - perm.initMasks(PERM_ALL, PERM_ALL, PERM_NONE, PERM_NONE, PERM_MOVE | PERM_TRANSFER); + perm.initMasks(PERM_ALL, PERM_ALL, LLFloaterPerms::getEveryonePerms("Scripts"), LLFloaterPerms::getGroupPerms("Scripts"), LLFloaterPerms::getNextOwnerPerms("Scripts")); mItem = new LLViewerInventoryItem(mItemUUID, mObjectUUID, perm, @@ -1927,6 +2188,8 @@ void LLLiveLSLEditor::loadAsset() time_corrected()); mAssetStatus = PREVIEW_ASSET_LOADED; } + + requestExperiences(); } // static @@ -1934,8 +2197,8 @@ void LLLiveLSLEditor::onLoadComplete(LLVFS *vfs, const LLUUID& asset_id, LLAssetType::EType type, void* user_data, S32 status, LLExtStat ext_status) { - lldebugs << "LLLiveLSLEditor::onLoadComplete: got uuid " << asset_id - << llendl; + LL_DEBUGS() << "LLLiveLSLEditor::onLoadComplete: got uuid " << asset_id + << LL_ENDL; LLUUID* xored_id = (LLUUID*)user_data; LLLiveLSLEditor* instance = static_cast(LLPreview::find(*xored_id)); @@ -1982,7 +2245,7 @@ void LLLiveLSLEditor::loadScriptText(LLVFS *vfs, const LLUUID &uuid, LLAssetType if (file.getLastBytesRead() != file_length || file_length <= 0) { - llwarns << "Error reading " << uuid << ":" << type << llendl; + LL_WARNS() << "Error reading " << uuid << ":" << type << LL_ENDL; } buffer[file_length] = '\0'; @@ -2053,7 +2316,7 @@ void LLLiveLSLEditor::onReset(void *userdata) } else { - LLNotificationsUtil::add("CouldNotStartStopScript"); + LLNotificationsUtil::add("CouldNotStartStopScript"); } } @@ -2106,6 +2369,7 @@ void LLLiveLSLEditor::draw() // Really ought to put in main window. setTitle(LLTrans::getString("ObjectOutOfRange")); runningCheckbox->setEnabled(FALSE); + mMonoCheckbox->setEnabled(FALSE); // object may have fallen out of range. mHaveRunningInfo = FALSE; } @@ -2118,7 +2382,7 @@ void LLLiveLSLEditor::onSearchReplace(void* userdata) { LLLiveLSLEditor* self = (LLLiveLSLEditor*)userdata; - LLScriptEdCore* sec = self->mScriptEd; + LLScriptEdCore* sec = self->mScriptEd; if (sec && sec->mEditor) { LLFloaterSearchReplace::show(sec->mEditor); @@ -2190,6 +2454,7 @@ void LLLiveLSLEditor::saveIfNeeded(bool sync /*= true*/) mScriptEd->enableSave(FALSE); mScriptEd->mEditor->makePristine(); mScriptEd->mErrorList->deleteAllItems(); + mScriptEd->mErrorList->setCommentText(""); // set up the save on the local machine. mScriptEd->mEditor->makePristine(); @@ -2208,7 +2473,7 @@ void LLLiveLSLEditor::saveIfNeeded(bool sync /*= true*/) { mScriptEd->sync(); } - + // save it out to asset server std::string url = object->getRegion()->getCapability("UpdateScriptTask"); getWindow()->incBusyCount(); @@ -2216,215 +2481,33 @@ void LLLiveLSLEditor::saveIfNeeded(bool sync /*= true*/) BOOL is_running = getChild( "running")->get(); if (!url.empty()) { - uploadAssetViaCaps(url, filename, mObjectUUID, mItemUUID, is_running); + uploadAssetViaCaps(url, filename, mObjectUUID, mItemUUID, is_running, mScriptEd->getAssociatedExperience()); } else { mScriptEd->mErrorList->setCommentText(LLTrans::getString("CompileQueueProblemUploading")); LLFile::remove(filename); } -#if 0 //Client side compiling disabled. - else if (gAssetStorage) - { - uploadAssetLegacy(filename, object, tid, is_running); - } -#endif } void LLLiveLSLEditor::uploadAssetViaCaps(const std::string& url, const std::string& filename, const LLUUID& task_id, const LLUUID& item_id, - BOOL is_running) + BOOL is_running, + const LLUUID& experience_public_id) { - llinfos << "Update Task Inventory via capability " << url << llendl; + LL_INFOS() << "Update Task Inventory via capability " << url << LL_ENDL; LLSD body; body["task_id"] = task_id; body["item_id"] = item_id; body["is_script_running"] = is_running; body["target"] = monoChecked() ? "mono" : "lsl2"; + body["experience"] = experience_public_id; LLHTTPClient::post(url, body, new LLUpdateTaskInventoryResponder(body, filename, LLAssetType::AT_LSL_TEXT)); } -#if 0 //Client side compiling disabled. -void LLLiveLSLEditor::uploadAssetLegacy(const std::string& filename, - LLViewerObject* object, - const LLTransactionID& tid, - BOOL is_running) -{ - LLLiveLSLSaveData* data = new LLLiveLSLSaveData(mObjectUUID, - mItem, - is_running); - gAssetStorage->storeAssetData(filename, tid, - LLAssetType::AT_LSL_TEXT, - &onSaveTextComplete, - (void*)data, - FALSE); - - LLAssetID asset_id = tid.makeAssetID(gAgent.getSecureSessionID()); - std::string filepath = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,asset_id.asString()); - std::string dst_filename = llformat("%s.lso", filepath.c_str()); - std::string err_filename = llformat("%s.out", filepath.c_str()); - - LLFILE *fp; - const BOOL compile_to_mono = FALSE; - if(!lscript_compile(filename.c_str(), - dst_filename.c_str(), - err_filename.c_str(), - compile_to_mono, - asset_id.asString().c_str(), - gAgent.isGodlike())) - { - // load the error file into the error scrolllist - llinfos << "Compile failed!" << llendl; - if(NULL != (fp = LLFile::fopen(err_filename, "r"))) - { - char buffer[MAX_STRING]; /*Flawfinder: ignore*/ - std::string line; - while(!feof(fp)) - { - - if (fgets(buffer, MAX_STRING, fp) == NULL) - { - buffer[0] = '\0'; - } - if(feof(fp)) - { - break; - } - else - { - line.assign(buffer); - LLStringUtil::stripNonprintable(line); - - LLSD row; - row["columns"][0]["value"] = line; - row["columns"][0]["font"] = "OCRA"; - mScriptEd->mErrorList->addElement(row); - } - } - fclose(fp); - mScriptEd->selectFirstError(); - // don't set the asset id, because we want to save the - // script, even though the compile failed. - //mItem->setAssetUUID(LLUUID::null); - object->saveScript(mItem, FALSE, false); - dialog_refresh_all(); - } - } - else - { - llinfos << "Compile worked!" << llendl; - mScriptEd->mErrorList->setCommentText(LLTrans::getString("CompileSuccessfulSaving")); - if(gAssetStorage) - { - llinfos << "LLLiveLSLEditor::saveAsset " - << mItem->getAssetUUID() << llendl; - getWindow()->incBusyCount(); - mPendingUploads++; - LLLiveLSLSaveData* data = NULL; - data = new LLLiveLSLSaveData(mObjectUUID, - mItem, - is_running); - gAssetStorage->storeAssetData(dst_filename, - tid, - LLAssetType::AT_LSL_BYTECODE, - &LLLiveLSLEditor::onSaveBytecodeComplete, - (void*)data); - dialog_refresh_all(); - } - } - - // get rid of any temp files left lying around - LLFile::remove(filename); - LLFile::remove(err_filename); - LLFile::remove(dst_filename); - - // If we successfully saved it, then we should be able to check/uncheck the running box! - LLCheckBoxCtrl* runningCheckbox = getChild( "running"); - runningCheckbox->setLabel(getString("script_running")); - runningCheckbox->setEnabled(TRUE); -} - -void LLLiveLSLEditor::onSaveTextComplete(const LLUUID& asset_uuid, void* user_data, S32 status, LLExtStat ext_status) // StoreAssetData callback (fixed) -{ - LLLiveLSLSaveData* data = (LLLiveLSLSaveData*)user_data; - - if (status) - { - llwarns << "Unable to save text for a script." << llendl; - LLSD args; - args["REASON"] = std::string(LLAssetStorage::getErrorString(status)); - LLNotificationsUtil::add("CompileQueueSaveText", args); - } - else - { - LLLiveLSLEditor* self = static_cast(LLPreview::find(data->mItem->getUUID())); // ^ data->mSaveObjectID - if (self) - { - self->getWindow()->decBusyCount(); - self->mPendingUploads--; - if (self->mPendingUploads <= 0 - && self->mCloseAfterSave) - { - self->close(); - } - } - } - delete data; - data = NULL; -} - - -void LLLiveLSLEditor::onSaveBytecodeComplete(const LLUUID& asset_uuid, void* user_data, S32 status, LLExtStat ext_status) // StoreAssetData callback (fixed) -{ - LLLiveLSLSaveData* data = (LLLiveLSLSaveData*)user_data; - if(!data) - return; - if(0 ==status) - { - llinfos << "LSL Bytecode saved" << llendl; - LLLiveLSLEditor* self = static_cast(LLPreview::find(data->mItem->getUUID())); // ^ data->mSaveObjectID - if(self) - { - // Tell the user that the compile worked. - self->mScriptEd->mErrorList->setCommentText(LLTrans::getString("SaveComplete")); - // close the window if this completes both uploads - self->getWindow()->decBusyCount(); - self->mPendingUploads--; - if (self->mPendingUploads <= 0 - && self->mCloseAfterSave) - { - self->close(); - } - } - LLViewerObject* object = gObjectList.findObject(data->mSaveObjectID); - if(object) - { - object->saveScript(data->mItem, data->mActive, false); - dialog_refresh_all(); - //LLToolDragAndDrop::dropScript(object, ids->first, - // LLAssetType::AT_LSL_TEXT, FALSE); - } - } - else - { - llinfos << "Problem saving LSL Bytecode (Live Editor)" << llendl; - llwarns << "Unable to save a compiled script." << llendl; - - LLSD args; - args["REASON"] = std::string(LLAssetStorage::getErrorString(status)); - LLNotificationsUtil::add("CompileQueueSaveBytecode", args); - } - - std::string filepath = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,asset_uuid.asString()); - std::string dst_filename = llformat("%s.lso", filepath.c_str()); - LLFile::remove(dst_filename); - delete data; -} -#endif - BOOL LLLiveLSLEditor::canClose() { return (mScriptEd->canClose()); @@ -2495,4 +2578,19 @@ BOOL LLLiveLSLEditor::monoChecked() const return mMonoCheckbox->getValue()? TRUE : FALSE; } return FALSE; -} \ No newline at end of file +} + +void LLLiveLSLEditor::setAssociatedExperience(LLHandle editor, const LLSD& experience) +{ + LLLiveLSLEditor* scriptEd = editor.get(); + if (scriptEd) + { + LLUUID id; + if (experience.has(LLExperienceCache::EXPERIENCE_ID)) + { + id = experience[LLExperienceCache::EXPERIENCE_ID].asUUID(); + } + scriptEd->mScriptEd->setAssociatedExperience(id); + scriptEd->updateExperiencePanel(); + } +} diff --git a/indra/newview/llpreviewscript.h b/indra/newview/llpreviewscript.h index ace3f99492..35f6571f4f 100644 --- a/indra/newview/llpreviewscript.h +++ b/indra/newview/llpreviewscript.h @@ -33,7 +33,6 @@ #ifndef LL_LLPREVIEWSCRIPT_H #define LL_LLPREVIEWSCRIPT_H -#include "lldarray.h" #include "llpreview.h" #include "lltabcontainer.h" #include "llinventory.h" @@ -82,8 +81,8 @@ class LLScriptEdCore : public LLPanel void initMenu(); - virtual void draw(); - /*virtual*/ BOOL postBuild(); + void draw() override; + BOOL postBuild() override; BOOL canClose(); void setEnableEditing(bool enable); @@ -105,7 +104,6 @@ class LLScriptEdCore : public LLPanel static void onClickForward(void* userdata); static void onBtnInsertSample(void*); static void onBtnInsertFunction(LLUICtrl*, void*); - // Singu TODO: modernize the menu callbacks and get rid of/update this giant block of static functions static BOOL hasChanged(void* userdata); static void onBtnSave(void*); @@ -128,6 +126,10 @@ class LLScriptEdCore : public LLPanel static BOOL enableSelectAllMenu(void* userdata); static BOOL enableDeselectMenu(void* userdata); + bool hasAccelerators() const override { return true; } + LLUUID getAssociatedExperience() const; + void setAssociatedExperience(const LLUUID& experience_id); + private: static bool onHelpWebDialog(const LLSD& notification, const LLSD& response); static void onBtnHelp(void* userdata); @@ -138,7 +140,7 @@ class LLScriptEdCore : public LLPanel void selectFirstError(); - virtual BOOL handleKeyHere(KEY key, MASK mask); + BOOL handleKeyHere(KEY key, MASK mask) override; void enableSave(BOOL b) {mEnableSave = b;} @@ -160,7 +162,7 @@ class LLScriptEdCore : public LLPanel BOOL mForceClose; LLPanel* mCodePanel; LLScrollListCtrl* mErrorList; - LLDynamicArray mBridges; + std::vector mBridges; LLHandle mLiveHelpHandle; LLKeywordToken* mLastHelpToken; LLFrameTimer mLiveHelpTimer; @@ -168,6 +170,7 @@ class LLScriptEdCore : public LLPanel BOOL mEnableSave; BOOL mHasScriptData; LLLiveLSLFile* mLiveFile; + LLUUID mAssociatedExperience; LLScriptEdContainer* mContainer; // parent view @@ -193,42 +196,37 @@ class LLScriptEdContainer : public LLPreview bool onExternalChange(const std::string& filename); virtual void saveIfNeeded(bool sync = true) = 0; - LLTextEditor* getEditor() { return mScriptEd->mEditor; } - /*virtual*/ const char *getTitleName() const { return "Script"; } - /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + LLTextEditor* getEditor() const { return mScriptEd->mEditor; } + /*virtual*/ const char *getTitleName() const override { return "Script"; } // - /*virtual*/ BOOL canSaveAs() const; - /*virtual*/ void saveAs(); + /*virtual*/ BOOL canSaveAs() const override; + /*virtual*/ void saveAs() override; void saveAs_continued(AIFilePicker* filepicker); // LLScriptEdCore* mScriptEd; }; -// Used to view and edit a LSL from your inventory. -class LLPreviewLSL : public LLScriptEdContainer +// Used to view and edit an LSL script from your inventory. +class LLPreviewLSL final : public LLScriptEdContainer { public: LLPreviewLSL(const std::string& name, const LLRect& rect, const std::string& title, const LLUUID& item_uuid ); virtual void callbackLSLCompileSucceeded(); virtual void callbackLSLCompileFailed(const LLSD& compile_errors); - /*virtual*/ BOOL postBuild(); + /*virtual*/ BOOL postBuild() override; + protected: - virtual BOOL canClose(); + BOOL canClose() override; void closeIfNeeded(); - virtual void loadAsset(); - /*virtual*/ void saveIfNeeded(bool sync = true); + void loadAsset() override; + /*virtual*/ void saveIfNeeded(bool sync = true) override; void uploadAssetViaCaps(const std::string& url, const std::string& filename, const LLUUID& item_id); -#if 0 //Client side compiling disabled. - void uploadAssetLegacy(const std::string& filename, - const LLUUID& item_id, - const LLTransactionID& tid); -#endif static void onSearchReplace(void* userdata); static void onLoad(void* userdata); @@ -237,10 +235,6 @@ class LLPreviewLSL : public LLScriptEdContainer static void onLoadComplete(LLVFS *vfs, const LLUUID& uuid, LLAssetType::EType type, void* user_data, S32 status, LLExtStat ext_status); -#if 0 //Client side compiling disabled. - static void onSaveComplete(const LLUUID& uuid, void* user_data, S32 status, LLExtStat ext_status); - static void onSaveBytecodeComplete(const LLUUID& asset_uuid, void* user_data, S32 status, LLExtStat ext_status); -#endif protected: static void* createScriptEdPanel(void* userdata); @@ -254,8 +248,8 @@ class LLPreviewLSL : public LLScriptEdContainer }; -// Used to view and edit an LSL that is attached to an object. -class LLLiveLSLEditor : public LLScriptEdContainer +// Used to view and edit an LSL script that is attached to an object. +class LLLiveLSLEditor final : public LLScriptEdContainer { friend class LLLiveLSLFile; public: @@ -269,29 +263,35 @@ class LLLiveLSLEditor : public LLScriptEdContainer bool is_script_running); virtual void callbackLSLCompileFailed(const LLSD& compile_errors); - /*virtual*/ BOOL postBuild(); + /*virtual*/ BOOL postBuild() override; void setIsNew() { mIsNew = TRUE; } + static void setAssociatedExperience(LLHandle editor, const LLSD& experience); + static void onToggleExperience(LLUICtrl* ui, void* userdata); + static void onViewProfile(LLUICtrl* ui, void* userdata); + + void setExperienceIds(const LLSD& experience_ids); + void buildExperienceList(); + void updateExperiencePanel(); + void requestExperiences(); + void experienceChanged(); + void addAssociatedExperience(const LLSD& experience); + private: - virtual BOOL canClose(); + BOOL canClose() override; void closeIfNeeded(); - virtual void draw(); + void draw() override; - virtual void loadAsset(); + void loadAsset() override; void loadAsset(BOOL is_new); - /*virtual*/ void saveIfNeeded(bool sync = true); + /*virtual*/ void saveIfNeeded(bool sync = true) override; void uploadAssetViaCaps(const std::string& url, - const std::string& filename, + const std::string& filename, const LLUUID& task_id, const LLUUID& item_id, - BOOL is_running); -#if 0 //Client side compiling disabled. - void uploadAssetLegacy(const std::string& filename, - LLViewerObject* object, - const LLTransactionID& tid, - BOOL is_running); -#endif + BOOL is_running, + const LLUUID& experience_public_id); BOOL monoChecked() const; @@ -302,10 +302,6 @@ class LLLiveLSLEditor : public LLScriptEdContainer static void onLoadComplete(LLVFS *vfs, const LLUUID& asset_uuid, LLAssetType::EType type, void* user_data, S32 status, LLExtStat ext_status); -#if 0 //Client side compiling disabled. - static void onSaveTextComplete(const LLUUID& asset_uuid, void* user_data, S32 status, LLExtStat ext_status); - static void onSaveBytecodeComplete(const LLUUID& asset_uuid, void* user_data, S32 status, LLExtStat ext_status); -#endif static void onRunningCheckboxClicked(LLUICtrl*, void* userdata); static void onReset(void* userdata); @@ -317,6 +313,8 @@ class LLLiveLSLEditor : public LLScriptEdContainer static void onMonoCheckboxClicked(LLUICtrl*, void* userdata); + static void receiveExperienceIds(const struct LLCoroResponder& responder, LLHandle parent); + private: bool mIsNew; //LLUUID mTransmitID; @@ -330,9 +328,16 @@ class LLLiveLSLEditor : public LLScriptEdContainer S32 mPendingUploads; BOOL getIsModifiable() const { return mIsModifiable; } // Evaluated on load assert - + LLCheckBoxCtrl* mMonoCheckbox; BOOL mIsModifiable; + + + LLComboBox* mExperiences; + LLCheckBoxCtrl* mExperienceEnabled; + LLSD mExperienceIds; + + LLHandle mExperienceProfile; }; #endif // LL_LLPREVIEWSCRIPT_H diff --git a/indra/newview/llpreviewsound.cpp b/indra/newview/llpreviewsound.cpp index bdab291532..b3a129e6be 100644 --- a/indra/newview/llpreviewsound.cpp +++ b/indra/newview/llpreviewsound.cpp @@ -60,10 +60,36 @@ const F32 SOUND_GAIN = 1.0f; LLPreviewSound::LLPreviewSound(const std::string& name, const LLRect& rect, const std::string& title, const LLUUID& item_uuid, const LLUUID& object_uuid) : LLPreview( name, rect, title, item_uuid, object_uuid) +, mIsCopyable(false) { LLUICtrlFactory::getInstance()->buildFloater(this,"floater_preview_sound.xml"); + setTitle(title); + + if (!getHost()) + { + LLRect curRect = getRect(); + translate(rect.mLeft - curRect.mLeft, rect.mTop - curRect.mTop); + } +} + +// virtual +BOOL LLPreviewSound::postBuild() +{ + const LLInventoryItem* item = getItem(); + if (item) + { + getChild("desc")->setValue(item->getDescription()); + mIsCopyable = (item->getPermissions().getCreator() == gAgentID); + if (gAudiop) + // + // that thing above doesn't actually start a sound transfer, so I will do it + if (LLAudioSource* asp = gAgentAvatarp->getAudioSource(gAgentID)) + asp->preload(item->getAssetUUID()); // preload the sound + // + } + childSetAction("Sound play btn",&LLPreviewSound::playSound,this); childSetAction("Sound audition btn",&LLPreviewSound::auditionSound,this); // @@ -77,40 +103,10 @@ LLPreviewSound::LLPreviewSound(const std::string& name, const LLRect& rect, cons button = getChild("Sound audition btn"); button->setSoundFlags(LLView::SILENT); - const LLInventoryItem* item = getItem(); - - mIsCopyable = false; - if(item) - { - const LLPermissions& perm = item->getPermissions(); - mIsCopyable = (perm.getCreator() == gAgent.getID()); - } - childSetCommitCallback("desc", LLPreview::onText, this); - childSetText("desc", item->getDescription()); getChild("desc")->setPrevalidate(&LLLineEditor::prevalidatePrintableNotPipe); - - // preload the sound - if(item && gAudiop) - { - gAudiop->preloadSound(item->getAssetUUID()); - // - // that thing above doesn't actually start a sound transfer, so I will do it - //LLAudioSource *asp = new LLAudioSource(gAgent.getID(), gAgent.getID(), F32(1.0f), LLAudioEngine::AUDIO_TYPE_UI); - LLAudioSource *asp = gAgentAvatarp->getAudioSource(gAgent.getID()); - LLAudioData *datap = gAudiop->getAudioData(item->getAssetUUID()); - asp->addAudioData(datap, FALSE); - // - } - - setTitle(title); - - if (!getHost()) - { - LLRect curRect = getRect(); - translate(rect.mLeft - curRect.mLeft, rect.mTop - curRect.mTop); - } + return LLPreview::postBuild(); } // static @@ -218,7 +214,7 @@ void LLPreviewSound::gotAssetForCopy(LLVFS *vfs, char* buffer = new char[size]; if (buffer == NULL) { - llerrs << "Memory Allocation Failed" << llendl; + LL_ERRS() << "Memory Allocation Failed" << LL_ENDL; return; } @@ -276,7 +272,7 @@ void LLPreviewSound::onSaveCopyComplete(const LLUUID& asset_uuid, void* user_dat } else { - llwarns << "Problem saving sound: " << status << llendl; + LL_WARNS() << "Problem saving sound: " << status << LL_ENDL; LLStringUtil::format_map_t args; args["[REASON]"] = std::string(LLAssetStorage::getErrorString(status)); gViewerWindow->alertXml("CannotUploadReason",args); @@ -329,7 +325,7 @@ void LLPreviewSound::gotAssetForSave(LLVFS *vfs, char* buffer = new char[size]; if (buffer == NULL) { - llerrs << "Memory Allocation Failed" << llendl; + LL_ERRS() << "Memory Allocation Failed" << LL_ENDL; return; } diff --git a/indra/newview/llpreviewsound.h b/indra/newview/llpreviewsound.h index 6d8928c977..51a89d9df4 100644 --- a/indra/newview/llpreviewsound.h +++ b/indra/newview/llpreviewsound.h @@ -65,6 +65,7 @@ class LLPreviewSound : public LLPreview // protected: + /*virtual*/ BOOL postBuild(); virtual const char *getTitleName() const { return "Sound"; } // virtual BOOL canSaveAs() const; diff --git a/indra/newview/llpreviewtexture.cpp b/indra/newview/llpreviewtexture.cpp index d2929d7a69..ac2da07816 100644 --- a/indra/newview/llpreviewtexture.cpp +++ b/indra/newview/llpreviewtexture.cpp @@ -36,12 +36,12 @@ #include "llagent.h" #include "llavataractions.h" +#include "llavatarnamecache.h" #include "llbutton.h" #include "llcombobox.h" #include "statemachine/aifilepicker.h" #include "llfloaterinventory.h" -#include "llimagepng.h" -#include "llimagetga.h" +#include "llimage.h" #include "llinventory.h" #include "llnotificationsutil.h" #include "llresmgr.h" @@ -74,8 +74,8 @@ LLPreviewTexture::LLPreviewTexture(const std::string& name, mLoadingFullImage( FALSE ), mShowKeepDiscard(show_keep_discard), mCopyToInv(FALSE), - mIsCopyable(FALSE), - mUpdateDimensions(TRUE), + mIsCopyable(FALSE), + mUpdateDimensions(TRUE), mLastHeight(0), mLastWidth(0), mAspectRatio(0.f), @@ -230,25 +230,17 @@ void LLPreviewTexture::init() childSetText("desc", item->getDescription()); getChild("desc")->setPrevalidate(&LLLineEditor::prevalidatePrintableNotPipe); childSetText("uuid", getItemID().asString()); - childSetText("uploader", getItemCreatorName()); - childSetText("uploadtime", getItemCreationDate()); childSetText("alphanote", LLTrans::getString("LoadingData")); } } - + childSetText("uploader", getItemCreatorName()); + childSetText("uploadtime", getItemCreationDate()); + childSetCommitCallback("combo_aspect_ratio", onAspectRatioCommit, this); LLComboBox* combo = getChild("combo_aspect_ratio"); combo->setCurrentByIndex(0); } -void LLPreviewTexture::callbackLoadAvatarName(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group, void* data) -{ - if (!sInstance) return; - std::ostringstream fullname; - fullname << first << " " << last; - sInstance->childSetText("uploader", fullname.str()); -} - void LLPreviewTexture::draw() { if (mUpdateDimensions) @@ -283,7 +275,8 @@ void LLPreviewTexture::draw() static const LLCachedControl use_rmse_auto_mask("SHUseRMSEAutoMask",false); static const LLCachedControl auto_mask_max_rmse("SHAutoMaskMaxRMSE",.09f); - if (mAlphaMaskResult != mImage->getIsAlphaMask(use_rmse_auto_mask ? auto_mask_max_rmse : -1.f)) + static const LLCachedControl auto_mask_max_mid("SHAutoMaskMaxMid", .25f); + if (mAlphaMaskResult != mImage->getIsAlphaMask(use_rmse_auto_mask ? auto_mask_max_rmse : -1.f, auto_mask_max_mid)) { mAlphaMaskResult = !mAlphaMaskResult; if (!mAlphaMaskResult) @@ -377,27 +370,16 @@ BOOL LLPreviewTexture::canSaveAs() const return mIsCopyable && !mLoadingFullImage && mImage.notNull() && !mImage->isMissingAsset(); } -static bool sPng(false); - // virtual -void LLPreviewTexture::saveAsType(BOOL png) +void LLPreviewTexture::saveAs() { if( mLoadingFullImage ) return; const LLViewerInventoryItem* item = getItem() ; AIFilePicker* filepicker = AIFilePicker::create(); - sPng = png; - if(png) - { - filepicker->open(item ? LLDir::getScrubbedFileName(item->getName()) + ".png" : LLStringUtil::null, FFSAVE_PNG, "", "image"); - filepicker->run(boost::bind(&LLPreviewTexture::saveAs_continued, this, item, filepicker)); - } - else - { - filepicker->open(item ? LLDir::getScrubbedFileName(item->getName()) + ".tga" : LLStringUtil::null, FFSAVE_TGA, "", "image"); - filepicker->run(boost::bind(&LLPreviewTexture::saveAs_continued, this, item, filepicker)); - } + filepicker->open(item ? LLDir::getScrubbedFileName(item->getName()) + ".png" : LLStringUtil::null, FFSAVE_IMAGE, "", "image"); + filepicker->run(boost::bind(&LLPreviewTexture::saveAs_continued, this, item, filepicker)); } void LLPreviewTexture::saveAs_continued(LLViewerInventoryItem const* item, AIFilePicker* filepicker) @@ -446,16 +428,14 @@ void LLPreviewTexture::onFileLoadedForSave(BOOL success, if( self && final && success ) { - //FIXME: There has to be a better way - LLPointer image_png = new LLImagePNG; - LLPointer image_tga = new LLImageTGA; - if( sPng ? !image_png->encode( src, 0.0 ) : !image_tga->encode( src ) ) + LLPointer image = LLImageFormatted::createFromExtension(self->mSaveFileName); + if (!image || !image->encode(src, 0.0)) { LLSD args; args["FILE"] = self->mSaveFileName; LLNotificationsUtil::add("CannotEncodeFile", args); } - else if( sPng ? !image_png->save( self->mSaveFileName ) : !image_tga->save( self->mSaveFileName ) ) + else if (!image->save(self->mSaveFileName)) { LLSD args; args["FILE"] = self->mSaveFileName; @@ -499,17 +479,20 @@ std::string LLPreviewTexture::getItemCreationDate() timeToFormattedString(item->getCreationDate(), gSavedSettings.getString("TimestampFormat"), time); return time; } - return getString("Unknown"); + const LLDate date = mImage->getUploadTime(); + return date.notNull() ? date.toHTTPDateString(gSavedSettings.getString("TimestampFormat")) + : getString("Unknown"); } std::string LLPreviewTexture::getItemCreatorName() { const LLViewerInventoryItem* item = getItem(); - if(item) + const LLUUID& id = item ? item->getCreatorUUID() : mImage->getUploader(); + if (id.notNull()) { std::string name; - gCacheName->getFullName(item->getCreatorUUID(), name); - mCreatorKey = item->getCreatorUUID(); + LLAvatarNameCache::getNSName(id, name); + mCreatorKey = id; return name; } return getString("Unknown"); @@ -590,6 +573,14 @@ void LLPreviewTexture::updateDimensions() } + // Update the width/height display every time + if (mImage->getUploader().notNull()) + { + // Singu Note: This is what Alchemy does, we may need it, but it might help if it didn't load in init. + childSetText("uploader", getItemCreatorName()); + childSetText("uploadtime", getItemCreationDate()); + } + if (!mUserResized) { // clamp texture size to fit within actual size of floater after attempting resize @@ -604,7 +595,7 @@ void LLPreviewTexture::updateDimensions() client_width = getRect().getWidth() - horiz_pad; if (mAspectRatio > 0.f) { - client_height = llround(client_width / mAspectRatio); + client_height = ll_round(client_width / mAspectRatio); } else { @@ -622,7 +613,7 @@ void LLPreviewTexture::updateDimensions() if (client_height > max_height) { client_height = max_height; - client_width = llround(client_height * mAspectRatio); + client_width = ll_round(client_height * mAspectRatio); } } else @@ -699,7 +690,7 @@ void LLPreviewTexture::onAspectRatioCommit(LLUICtrl* ctrl, void* userdata) void LLPreviewTexture::loadAsset() { - mImage = LLViewerTextureManager::getFetchedTexture(mImageID, MIPMAP_TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); + mImage = LLViewerTextureManager::getFetchedTexture(mImageID, FTT_DEFAULT, MIPMAP_TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); mImageOldBoostLevel = mImage->getBoostLevel(); mImage->setBoostLevel(LLGLTexture::BOOST_PREVIEW); mImage->forceToSaveRawImage(0) ; diff --git a/indra/newview/llpreviewtexture.h b/indra/newview/llpreviewtexture.h index 02dc4f94e8..f1ad314c62 100644 --- a/indra/newview/llpreviewtexture.h +++ b/indra/newview/llpreviewtexture.h @@ -63,8 +63,7 @@ class LLPreviewTexture : public LLPreview virtual void draw(); virtual BOOL canSaveAs() const; - virtual void saveAs(){ saveAsType(false); } - void saveAsType(BOOL png); + virtual void saveAs(); void saveAs_continued(LLViewerInventoryItem const* item, AIFilePicker* filepicker); virtual LLUUID getItemID(); virtual std::string getItemCreatorName(); @@ -105,7 +104,6 @@ class LLPreviewTexture : public LLPreview static LLPreviewTexture* sInstance; static void onClickProfile(void* userdata); - static void callbackLoadAvatarName(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group, void* data); // This is stored off in a member variable, because the save-as // button and drag and drop functionality need to know. diff --git a/indra/newview/llproductinforequest.cpp b/indra/newview/llproductinforequest.cpp index 27aeea77e5..284bf000f1 100644 --- a/indra/newview/llproductinforequest.cpp +++ b/indra/newview/llproductinforequest.cpp @@ -46,16 +46,15 @@ class LLProductInfoRequestResponder : public LLHTTPClient::ResponderWithResult { public: //If we get back a normal response, handle it here - /*virtual*/ void result(const LLSD& content) + /*virtual*/ void httpSuccess(void) { - LLProductInfoRequestManager::instance().setSkuDescriptions(content); + LLProductInfoRequestManager::instance().setSkuDescriptions(mContent); } //If we get back an error (not found, etc...), handle it here - /*virtual*/ void error(U32 status, const std::string& reason) + /*virtual*/ void httpFailure(void) { - llwarns << "LLProductInfoRequest::error(" - << status << ": " << reason << ")" << llendl; + LL_WARNS() << "httpFailure: " << dumpResponse() << LL_ENDL; } /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return productInfoRequestResponder_timeout; } @@ -88,7 +87,7 @@ std::string LLProductInfoRequestManager::getDescriptionForSku(const std::string& it != mSkuDescriptions.endArray(); ++it) { - // llwarns << (*it)["sku"].asString() << " = " << (*it)["description"].asString() << llendl; + // LL_WARNS() << (*it)["sku"].asString() << " = " << (*it)["description"].asString() << LL_ENDL; if ((*it)["sku"].asString() == sku) { return (*it)["description"].asString(); diff --git a/indra/newview/llprogressview.cpp b/indra/newview/llprogressview.cpp index cbaa5d47e9..23981e565e 100644 --- a/indra/newview/llprogressview.cpp +++ b/indra/newview/llprogressview.cpp @@ -135,13 +135,6 @@ void LLProgressView::revealIntroPanel() gIdleCallbacks.addFunction(onIdle, this); } -void LLProgressView::abortShowProgress() -{ - mFadeFromLoginTimer.stop(); - LLPanelLogin::close(); - gIdleCallbacks.deleteFunction(onIdle, this); -} - void LLProgressView::setStartupComplete() { mStartupComplete = true; @@ -334,7 +327,7 @@ void LLProgressView::onIdle(void* user_data) self->mFadeFromLoginTimer.getElapsedTimeF32() > FADE_TO_WORLD_TIME) { self->mFadeFromLoginTimer.stop(); - LLPanelLogin::close(); + LLPanelLogin::hide(); // Nothing to do anymore. gIdleCallbacks.deleteFunction(onIdle, user_data); diff --git a/indra/newview/llprogressview.h b/indra/newview/llprogressview.h index 816305efd6..bff970e29d 100644 --- a/indra/newview/llprogressview.h +++ b/indra/newview/llprogressview.h @@ -62,7 +62,6 @@ class LLProgressView : public LLPanel void setMessage(const std::string& msg); void revealIntroPanel(); - void abortShowProgress(); void setStartupComplete(); diff --git a/indra/newview/llregioninfomodel.cpp b/indra/newview/llregioninfomodel.cpp index 3892c87957..b637e8a7ba 100644 --- a/indra/newview/llregioninfomodel.cpp +++ b/indra/newview/llregioninfomodel.cpp @@ -204,11 +204,11 @@ void LLRegionInfoModel::sendEstateOwnerMessage( if (!cur_region) { - llwarns << "Agent region not set" << llendl; + LL_WARNS() << "Agent region not set" << LL_ENDL; return; } - llinfos << "Sending estate request '" << request << "'" << llendl; + LL_INFOS() << "Sending estate request '" << request << "'" << LL_ENDL; msg->newMessage("EstateOwnerMessage"); msg->nextBlockFast(_PREHASH_AgentData); msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); @@ -229,7 +229,7 @@ void LLRegionInfoModel::sendEstateOwnerMessage( std::vector::const_iterator end = strings.end(); for (unsigned i = 0; it != end; ++it, ++i) { - lldebugs << "- [" << i << "] " << (*it) << llendl; + LL_DEBUGS() << "- [" << i << "] " << (*it) << LL_ENDL; msg->nextBlock("ParamList"); msg->addString("Parameter", *it); } diff --git a/indra/newview/llremoteparcelrequest.cpp b/indra/newview/llremoteparcelrequest.cpp index f8fbe5740b..ac76e0d4f9 100644 --- a/indra/newview/llremoteparcelrequest.cpp +++ b/indra/newview/llremoteparcelrequest.cpp @@ -53,9 +53,9 @@ LLRemoteParcelRequestResponder::LLRemoteParcelRequestResponder(LLHandlesetErrorStatus(status, reason); + observer->setErrorStatus(mStatus, mReason); } } diff --git a/indra/newview/llremoteparcelrequest.h b/indra/newview/llremoteparcelrequest.h index 922a77a5b5..ffc4adc118 100644 --- a/indra/newview/llremoteparcelrequest.h +++ b/indra/newview/llremoteparcelrequest.h @@ -49,10 +49,10 @@ class LLRemoteParcelRequestResponder : public LLHTTPClient::ResponderWithResult LLRemoteParcelRequestResponder(LLHandle observer_handle); //If we get back a normal response, handle it here - /*virtual*/ void result(const LLSD& content); + /*virtual*/ void httpSuccess(void); //If we get back an error (not found, etc...), handle it here - /*virtual*/ void error(U32 status, const std::string& reason); + /*virtual*/ void httpFailure(void); /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return remoteParcelRequestResponder_timeout; } /*virtual*/ char const* getName(void) const { return "LLRemoteParcelRequestResponder"; } diff --git a/indra/newview/llsavedlogins.cpp b/indra/newview/llsavedlogins.cpp index 991f1aacfe..afa713b87e 100644 --- a/indra/newview/llsavedlogins.cpp +++ b/indra/newview/llsavedlogins.cpp @@ -224,14 +224,14 @@ LLSavedLogins LLSavedLogins::loadFile(const std::string& filepath) if (file.is_open()) { - llinfos << "Loading login history file at " << filepath << llendl; + LL_INFOS() << "Loading login history file at " << filepath << LL_ENDL; LLSDSerialize::fromXML(data, file); } if (data.isUndefined()) { - llinfos << "Login History File \"" << filepath << "\" is missing, " - "ill-formed, or simply undefined; not loading the file." << llendl; + LL_INFOS() << "Login History File \"" << filepath << "\" is missing, " + "ill-formed, or simply undefined; not loading the file." << LL_ENDL; } else { @@ -241,8 +241,8 @@ LLSavedLogins LLSavedLogins::loadFile(const std::string& filepath) } catch(std::invalid_argument& error) { - llwarns << "Login History File \"" << filepath << "\" is ill-formed (" << - error.what() << "); not loading the file." << llendl; + LL_WARNS() << "Login History File \"" << filepath << "\" is ill-formed (" << + error.what() << "); not loading the file." << LL_ENDL; } } @@ -254,7 +254,7 @@ bool LLSavedLogins::saveFile(const LLSavedLogins& history, const std::string& fi llofstream out(filepath); if (!out.good()) { - llwarns << "Unable to open \"" << filepath << "\" for output." << llendl; + LL_WARNS() << "Unable to open \"" << filepath << "\" for output." << LL_ENDL; return false; } diff --git a/indra/newview/llsavedlogins.h b/indra/newview/llsavedlogins.h index 5461bae8ee..1ca24c132a 100644 --- a/indra/newview/llsavedlogins.h +++ b/indra/newview/llsavedlogins.h @@ -158,7 +158,7 @@ class LLSavedLogins * @brief Deletes a login history entry by looking up its name and grid. * @param firstname First name to find and delete. * @param lastname Last name to find and delete. - * @param grid grif nickname to find and delete. + * @param grid grid nickname to find and delete. */ void deleteEntry(const std::string& firstname, const std::string& lastname, const std::string& grid); /** diff --git a/indra/newview/llscrollingpanelparam.cpp b/indra/newview/llscrollingpanelparam.cpp index 1e208f64d7..edf3ee170b 100644 --- a/indra/newview/llscrollingpanelparam.cpp +++ b/indra/newview/llscrollingpanelparam.cpp @@ -77,10 +77,6 @@ LLScrollingPanelParam::LLScrollingPanelParam( const std::string& name, mHintMin->setAllowsUpdates( FALSE ); mHintMax->setAllowsUpdates( FALSE ); - std::string min_name = LLTrans::getString(param->getMinDisplayName()); - std::string max_name = LLTrans::getString(param->getMaxDisplayName()); - childSetValue("min param text", min_name); - childSetValue("max param text", max_name); mLess = getChild("less"); mLess->setMouseDownCallback( boost::bind(&LLScrollingPanelParam::onHintMouseDown, this, false) ); mLess->setMouseUpCallback( boost::bind(&LLScrollingPanelParam::onHintMouseUp, this, false) ); @@ -93,6 +89,10 @@ LLScrollingPanelParam::LLScrollingPanelParam( const std::string& name, mMore->setHeldDownCallback( boost::bind(&LLScrollingPanelParam::onHintHeldDown, this, true) ); mMore->setHeldDownDelay( PARAM_STEP_TIME_THRESHOLD ); } + mMinText = getChildView("min param text"); + mMinText->setValue(LLTrans::getString(param->getMinDisplayName())); + mMaxText = getChildView("max param text"); + mMaxText->setValue(LLTrans::getString(param->getMaxDisplayName())); setVisible(FALSE); setBorderVisible( FALSE ); @@ -157,9 +157,6 @@ void LLScrollingPanelParam::draw() if(mMore) mMore->setVisible(mHintMax && mHintMax->getVisible()); - // Draw all the children except for the labels - childSetVisible( "min param text", FALSE ); - childSetVisible( "max param text", FALSE ); LLPanel::draw(); // Draw the hints over the "less" and "more" buttons. @@ -191,23 +188,8 @@ void LLScrollingPanelParam::draw() // Draw labels on top of the buttons - childSetVisible( "min param text", TRUE ); - drawChild(getChild("min param text"), BTN_BORDER, BTN_BORDER); - - childSetVisible( "max param text", TRUE ); - drawChild(getChild("max param text"), BTN_BORDER, BTN_BORDER); -} - -// static -void LLScrollingPanelParam::onSliderMouseDown(LLUICtrl* ctrl, void* userdata) -{ -} - -// static -void LLScrollingPanelParam::onSliderMouseUp(LLUICtrl* ctrl, void* userdata) -{ - LLScrollingPanelParam* self = (LLScrollingPanelParam*) userdata; - LLVisualParamHint::requestHintUpdates( self->mHintMin, self->mHintMax ); + drawChild(mMinText, BTN_BORDER, BTN_BORDER, true); + drawChild(mMaxText, BTN_BORDER, BTN_BORDER, true); } void LLScrollingPanelParam::onHintMouseDown( bool max ) @@ -262,17 +244,16 @@ void LLScrollingPanelParam::onHintHeldDown( bool max ) // 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) + if (mSlider) { - if (slider->getMinValue() < new_percent - && new_percent < slider->getMaxValue()) + if (mSlider->getMinValue() < new_percent + && new_percent < mSlider->getMaxValue()) { mWearable->setVisualParamWeight(param->getID(), new_weight, FALSE); mWearable->writeToAvatar(gAgentAvatarp); gAgentAvatarp->updateVisualParams(); - slider->setValue( weightToPercent( new_weight ) ); + mSlider->setValue( weightToPercent( new_weight ) ); } } } @@ -301,15 +282,14 @@ void LLScrollingPanelParam::onHintMouseUp( bool max ) // step a fraction in the negative direction F32 new_weight = current_weight + (range / 10.f); F32 new_percent = weightToPercent(new_weight); - LLSliderCtrl* slider = getChild("param slider"); - if (slider) + if (mSlider) { - if (slider->getMinValue() < new_percent - && new_percent < slider->getMaxValue()) + if (mSlider->getMinValue() < new_percent + && new_percent < mSlider->getMaxValue()) { mWearable->setVisualParamWeight(param->getID(), new_weight, FALSE); mWearable->writeToAvatar(gAgentAvatarp); - slider->setValue( weightToPercent( new_weight ) ); + mSlider->setValue( weightToPercent( new_weight ) ); } } } diff --git a/indra/newview/llscrollingpanelparam.h b/indra/newview/llscrollingpanelparam.h index 8c02e5fa60..bc7d9543e5 100644 --- a/indra/newview/llscrollingpanelparam.h +++ b/indra/newview/llscrollingpanelparam.h @@ -47,9 +47,6 @@ class LLScrollingPanelParam : public LLScrollingPanelParamBase virtual void setVisible( BOOL visible ); virtual void updatePanel(BOOL allow_modify); - static void onSliderMouseDown(LLUICtrl* ctrl, void* userdata); - static void onSliderMouseUp(LLUICtrl* ctrl, void* userdata); - void onHintMouseUp( bool max ); void onHintMouseDown( bool max ); void onHintHeldDown( bool max ); @@ -69,6 +66,8 @@ class LLScrollingPanelParam : public LLScrollingPanelParamBase protected: LLTimer mMouseDownTimer; // timer for how long mouse has been held down on a hint. F32 mLastHeldTime; +private: + LLView *mMinText, *mMaxText; }; diff --git a/indra/newview/llscrollingpanelparambase.cpp b/indra/newview/llscrollingpanelparambase.cpp index 672153d048..8c34e0b6e9 100644 --- a/indra/newview/llscrollingpanelparambase.cpp +++ b/indra/newview/llscrollingpanelparambase.cpp @@ -49,7 +49,7 @@ LLScrollingPanelParamBase::LLScrollingPanelParamBase( const std::string& name, { LLUICtrlFactory::getInstance()->buildPanel(this, "panel_scrolling_param.xml"); //Set up the slider - LLSliderCtrl *slider = getChild("param slider"); + mSlider = getChild("param slider"); //Kill everything that isn't the slider... if(!bVisualHint) @@ -58,7 +58,7 @@ LLScrollingPanelParamBase::LLScrollingPanelParamBase( const std::string& name, child_list_t::const_iterator it; for (it = getChildList()->begin(); it != getChildList()->end(); it++) { - if ((*it) != slider && (*it)->getName() != "panel border") + if ((*it) != mSlider && (*it)->getName() != "panel border") { to_remove.push_back(*it); } @@ -68,14 +68,14 @@ LLScrollingPanelParamBase::LLScrollingPanelParamBase( const std::string& name, removeChild(*it); delete (*it); } - slider->translate(0,/*PARAM_HINT_HEIGHT*/128); + mSlider->translate(0,/*PARAM_HINT_HEIGHT*/128); reshape(getRect().getWidth(),getRect().getHeight()-128); } - slider->setValue(weightToPercent(param->getWeight())); - slider->setLabelArg("[DESC]", param->getDisplayName()); - slider->setEnabled(mAllowModify); - slider->setCommitCallback(boost::bind(&LLScrollingPanelParamBase::onSliderMoved, this, _1)); + mSlider->setValue(weightToPercent(param->getWeight())); + mSlider->setLabelArg("[DESC]", param->getDisplayName()); + mSlider->setEnabled(mAllowModify); + mSlider->setCommitCallback(boost::bind(&LLScrollingPanelParamBase::onSliderMoved, this, _1)); setVisible(FALSE); setBorderVisible( FALSE ); @@ -87,37 +87,25 @@ LLScrollingPanelParamBase::~LLScrollingPanelParamBase() void LLScrollingPanelParamBase::updatePanel(BOOL allow_modify) { - LLViewerVisualParam* param = mParam; - - if(!mWearable) + if (!mWearable) { // not editing a wearable just now, no update necessary return; } - F32 current_weight = mWearable->getVisualParamWeight( param->getID() ); - childSetValue("param slider", weightToPercent( current_weight ) ); + F32 current_weight = mWearable->getVisualParamWeight(mParam->getID()); + mSlider->setValue(weightToPercent(current_weight)); mAllowModify = allow_modify; - childSetEnabled("param slider", mAllowModify); + mSlider->setEnabled(mAllowModify); } void LLScrollingPanelParamBase::onSliderMoved(LLUICtrl* ctrl) { - if(!mParam) - { - return; - } - - if(!mWearable) - { - return; - } - - LLSliderCtrl* slider = (LLSliderCtrl*) ctrl; + if (!mParam || !mWearable) return; F32 current_weight = mWearable->getVisualParamWeight(mParam->getID()); - F32 new_weight = percentToWeight( (F32)slider->getValue().asReal() ); - if (current_weight != new_weight ) + F32 new_weight = percentToWeight(ctrl->getValue().asFloat()); + if (current_weight != new_weight) { mWearable->setVisualParamWeight( mParam->getID(), new_weight, FALSE); mWearable->writeToAvatar(gAgentAvatarp); @@ -127,12 +115,10 @@ void LLScrollingPanelParamBase::onSliderMoved(LLUICtrl* ctrl) F32 LLScrollingPanelParamBase::weightToPercent( F32 weight ) { - LLViewerVisualParam* param = mParam; - return (weight - param->getMinWeight()) / (param->getMaxWeight() - param->getMinWeight()) * 100.f; + return (weight - mParam->getMinWeight()) / (mParam->getMaxWeight() - mParam->getMinWeight()) * 100.f; } F32 LLScrollingPanelParamBase::percentToWeight( F32 percent ) { - LLViewerVisualParam* param = mParam; - return percent / 100.f * (param->getMaxWeight() - param->getMinWeight()) + param->getMinWeight(); + return percent / 100.f * (mParam->getMaxWeight() - mParam->getMinWeight()) + mParam->getMinWeight(); } diff --git a/indra/newview/llscrollingpanelparambase.h b/indra/newview/llscrollingpanelparambase.h index d114f622da..5ffab30538 100644 --- a/indra/newview/llscrollingpanelparambase.h +++ b/indra/newview/llscrollingpanelparambase.h @@ -57,6 +57,7 @@ class LLScrollingPanelParamBase : public LLScrollingPanel protected: BOOL mAllowModify; LLWearable *mWearable; + class LLSliderCtrl* mSlider; }; #endif diff --git a/indra/newview/llsculptidsize.cpp b/indra/newview/llsculptidsize.cpp new file mode 100644 index 0000000000..9edd78bff0 --- /dev/null +++ b/indra/newview/llsculptidsize.cpp @@ -0,0 +1,154 @@ +/** +* @file llsculptidsize.cpp +* @brief LLSculptIDSize class implementation +* +* $LicenseInfo:firstyear=2002&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2010, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#include "llviewerprecompiledheaders.h" +#include "llsculptidsize.h" +#include "llvovolume.h" +#include "lldrawable.h" +#include "llvoavatar.h" +//boost +#include "boost/make_shared.hpp" + +//........... + +extern LLControlGroup gSavedSettings; + +//........... + +typedef std::pair pair_iter_iter_BY_SCULPT_ID_t; + +//........... + +void _nothing_to_do_func(int) { /*nothing todo here because of the size it's a shared member*/ } + +void LLSculptIDSize::inc(const LLDrawable *pdrawable, int sz) +{ + llassert(sz >= 0); + + if (!pdrawable) return; + LLVOVolume* vvol = pdrawable->getVOVolume(); + if (!vvol) return; + if (!vvol->isAttachment()) return; + if (!vvol->getAvatar()) return; + if (vvol->getAvatar()->isSelf()) return; + LLVolume *vol = vvol->getVolume(); + if (!vol) return; + + const LLUUID &sculptId = vol->getParams().getSculptID(); + if (sculptId.isNull()) return; + + unsigned int total_size = 0; + + pair_iter_iter_BY_SCULPT_ID_t itLU = mSizeInfo.get().equal_range(sculptId); + if (itLU.first == itLU.second) + { //register + llassert(mSizeInfo.get().end() == mSizeInfo.get().find(pdrawable)); + mSizeInfo.get().insert(Info(pdrawable, sz, boost::make_shared(sz), sculptId)); + total_size = sz; + } + else + { //update + register + Info &nfo = const_cast(*itLU.first); + //calc new size + total_size = nfo.getSizeSum() + sz; + nfo.mSharedSizeSum->mSizeSum = total_size; + nfo.mSize = sz; + //update size for all LLDrwable in range of sculptId + for (pair_iter_iter_BY_SCULPT_ID_t::first_type it = itLU.first; it != itLU.second; ++it) + { + mSizeInfo.get().modify_key(mSizeInfo.project(it), boost::bind(&_nothing_to_do_func, _1)); + } + + //trying insert the LLDrawable + mSizeInfo.get().insert(Info(pdrawable, sz, nfo.mSharedSizeSum, sculptId)); + } + + static LLCachedControl render_auto_mute_byte_limit(gSavedSettings, "RenderAutoMuteByteLimit", 0U); + + if (0 != render_auto_mute_byte_limit && total_size > render_auto_mute_byte_limit) + { + pair_iter_iter_BY_SCULPT_ID_t it_eqr = mSizeInfo.get().equal_range(sculptId); + for (; it_eqr.first != it_eqr.second; ++it_eqr.first) + { + const Info &i = *it_eqr.first; + LLVOVolume *pVVol = i.mDrawable->getVOVolume(); + if (pVVol + && !pVVol->isDead() + && pVVol->isAttachment() + && !pVVol->getAvatar()->isSelf() + && LLVOVolume::NO_LOD != pVVol->getLOD() + ) + { + addToUnloaded(sculptId); + //immediately + const_cast(i.mDrawable)->unload(); + } + } + } +} + +void LLSculptIDSize::dec(const LLDrawable *pdrawable) +{ + container_BY_DRAWABLE_view::iterator it = mSizeInfo.get().find(pdrawable); + if (mSizeInfo.get().end() == it) return; + + unsigned int size = it->getSizeSum() - it->getSize(); + + if (0 == size) + { + mSizeInfo.get().erase(it->getSculptId()); + } + else + { + Info &nfo = const_cast(*it); + nfo.mSize = 0; + pair_iter_iter_BY_SCULPT_ID_t itLU = mSizeInfo.get().equal_range(it->getSculptId()); + it->mSharedSizeSum->mSizeSum = size; + for (pair_iter_iter_BY_SCULPT_ID_t::first_type it = itLU.first; it != itLU.second; ++it) + { + mSizeInfo.get().modify_key(mSizeInfo.project(it), boost::bind(&_nothing_to_do_func, _1)); + } + } +} + +void LLSculptIDSize::rem(const LLUUID &sculptId) +{ + mSizeInfo.get().erase(sculptId); +} + +void LLSculptIDSize::resetSizeSum(const LLUUID &sculptId) +{ + const pair_iter_iter_BY_SCULPT_ID_t itLU = mSizeInfo.get().equal_range(sculptId); + + if (itLU.first != itLU.second) { + itLU.first->mSharedSizeSum->mSizeSum = 0; + } + + for (pair_iter_iter_BY_SCULPT_ID_t::first_type it = itLU.first, itE = itLU.second; it != itE; ++it) + { + mSizeInfo.get().modify_key(mSizeInfo.project(it), boost::bind(&_nothing_to_do_func, _1)); + } +} diff --git a/indra/newview/llsculptidsize.h b/indra/newview/llsculptidsize.h new file mode 100644 index 0000000000..678155e1d5 --- /dev/null +++ b/indra/newview/llsculptidsize.h @@ -0,0 +1,134 @@ +/** +* @file llsculptidsize.h +* @brief LLSculptIDSize class definition +* +* $LicenseInfo:firstyear=2009&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2010, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#ifndef LL_LLSCULPTIDSIZE_H +#define LL_LLSCULPTIDSIZE_H + +#include "lluuid.h" + +//std +#include +//boost +#include "boost/multi_index_container.hpp" +#include "boost/multi_index/ordered_index.hpp" +#include "boost/multi_index/mem_fun.hpp" + +class LLDrawable; + + +class LLSculptIDSize +{ +public: + struct SizeSum + { + SizeSum(int size) + : mSizeSum(size) + {} + unsigned int mSizeSum; + }; + + struct Info + { + typedef boost::shared_ptr PtrSizeSum; + + Info(const LLDrawable *drawable, int size, PtrSizeSum sizeInfo, LLUUID sculptId) + : mDrawable(drawable) + , mSize(size) + , mSharedSizeSum(sizeInfo) + , mSculptId(sculptId) + {} + + const LLDrawable *mDrawable; + unsigned int mSize; + PtrSizeSum mSharedSizeSum; + LLUUID mSculptId; + + inline const LLDrawable* getPtrLLDrawable() const { return mDrawable; } + inline unsigned int getSize() const { return mSize; } + inline unsigned int getSizeSum() const { return mSharedSizeSum->mSizeSum; } + inline LLUUID getSculptId() const { return mSculptId; } + PtrSizeSum getSizeInfo() { return mSharedSizeSum; } + }; + +public: + //tags + struct tag_BY_DRAWABLE {}; + struct tag_BY_SCULPT_ID {}; + struct tag_BY_SIZE {}; + + //container + typedef boost::multi_index_container < + Info, + boost::multi_index::indexed_by < + boost::multi_index::ordered_unique< boost::multi_index::tag + , boost::multi_index::const_mem_fun + > + , boost::multi_index::ordered_non_unique + , boost::multi_index::const_mem_fun + > + , boost::multi_index::ordered_non_unique < boost::multi_index::tag + , boost::multi_index::const_mem_fun < Info, unsigned int, &Info::getSizeSum > + > + > + > container; + + //views + typedef container::index::type container_BY_DRAWABLE_view; + typedef container::index::type container_BY_SCULPT_ID_view; + typedef container::index::type container_BY_SIZE_view; + +private: + LLSculptIDSize() + {} + +public: + static LLSculptIDSize & instance() + { + static LLSculptIDSize inst; + return inst; + } + +public: + void inc(const LLDrawable *pdrawable, int sz); + void dec(const LLDrawable *pdrawable); + void rem(const LLUUID &sculptId); + + inline void addToUnloaded(const LLUUID &sculptId) { mMarkAsUnloaded.insert(sculptId); } + inline void remFromUnloaded(const LLUUID &sculptId) { mMarkAsUnloaded.erase(sculptId); } + inline bool isUnloaded(const LLUUID &sculptId) const { return mMarkAsUnloaded.end() != mMarkAsUnloaded.find(sculptId); } + inline void clearUnloaded() { mMarkAsUnloaded.clear(); } + + void resetSizeSum(const LLUUID &sculptId); + + inline const container & getSizeInfo() const { return mSizeInfo; } + +private: + container mSizeInfo; + typedef uuid_set_t std_LLUUID; + std_LLUUID mMarkAsUnloaded; +}; + +#endif diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 7bd68ad4a1..2e8a7b1f81 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -1,3 +1,5 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com /** * @file llselectmgr.cpp * @brief A manager for selected objects and faces. @@ -29,11 +31,11 @@ // file include #define LLSELECTMGR_CPP #include "llselectmgr.h" +#include "llmaterialmgr.h" // library includes #include "llcachename.h" #include "lldbstrings.h" -#include "lleconomy.h" #include "llgl.h" #include "llmediaentry.h" #include "llrender.h" @@ -43,6 +45,7 @@ #include "llundo.h" #include "lluuid.h" #include "llvolume.h" +#include "llcontrolavatar.h" #include "message.h" #include "object_flags.h" #include "llquaternion.h" @@ -50,6 +53,7 @@ // viewer includes #include "llagent.h" #include "llagentcamera.h" +#include "llattachmentsmgr.h" #include "llviewerwindow.h" #include "lldrawable.h" #include "llfloaterinspect.h" @@ -65,6 +69,7 @@ #include "llmeshrepository.h" #include "llmutelist.h" #include "llnotificationsutil.h" +#include "llparcel.h" // Rez under Land Group #include "llstatusbar.h" #include "llsurface.h" #include "lltool.h" @@ -80,20 +85,19 @@ #include "llviewermenu.h" #include "llviewerobject.h" #include "llviewerobjectlist.h" +#include "llviewerparcelmgr.h" // Rez under Land Group #include "llviewerregion.h" #include "llviewerstats.h" #include "llvoavatarself.h" #include "llvovolume.h" #include "pipeline.h" #include "llviewershadermgr.h" - -#include "llparcel.h" -#include "llviewerparcelmgr.h" - +#include "llpanelface.h" #include "llglheaders.h" #include "hippogridmanager.h" -// [RLVa:KB] +// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a) +#include "rlvactions.h" #include "rlvhandler.h" // [/RLVa:KB] @@ -191,6 +195,7 @@ LLSelectMgr::LLSelectMgr() mDebugSelectMgr(LLCachedControl( "DebugSelectMgr", false)) { mTEMode = FALSE; + mTextureChannel = LLRender::DIFFUSE_MAP; mLastCameraPos.clearVec(); sHighlightThickness = gSavedSettings.getF32("SelectionHighlightThickness"); @@ -214,7 +219,6 @@ LLSelectMgr::LLSelectMgr() mGridMode = GRID_MODE_WORLD; gSavedSettings.setS32("GridMode", (S32)GRID_MODE_WORLD); - mGridValid = FALSE; mSelectedObjects = new LLObjectSelection(); mHoverObjects = new LLObjectSelection(); @@ -240,6 +244,8 @@ void LLSelectMgr::clearSelections() mHighlightedObjects->deleteAllNodes(); mRectSelectedObjects.clear(); mGridObjects.deleteAllNodes(); + + LLPipeline::setRenderHighlightTextureChannel(LLRender::DIFFUSE_MAP); } void LLSelectMgr::update() @@ -252,7 +258,7 @@ void LLSelectMgr::updateEffects() //keep reference grid objects active struct f : public LLSelectedObjectFunctor { - virtual bool apply(LLViewerObject* object) + bool apply(LLViewerObject* object) override { LLDrawable* drawable = object->mDrawable; if (drawable) @@ -276,7 +282,7 @@ void LLSelectMgr::overrideObjectUpdates() //override any position updates from simulator on objects being edited struct f : public LLSelectedNodeFunctor { - virtual bool apply(LLSelectNode* selectNode) + bool apply(LLSelectNode* selectNode) override { LLViewerObject* object = selectNode->getObject(); if (object && object->permMove() && !object->isPermanentEnforced()) @@ -324,7 +330,7 @@ LLObjectSelectionHandle LLSelectMgr::selectObjectOnly(LLViewerObject* object, S3 return NULL; } - // llinfos << "Adding object to selected object list" << llendl; + // LL_INFOS() << "Adding object to selected object list" << LL_ENDL; // Place it in the list and tag it. // This will refresh dialogs. @@ -366,7 +372,7 @@ LLObjectSelectionHandle LLSelectMgr::selectObjectOnly(LLViewerObject* object, S3 //----------------------------------------------------------------------------- // Select the object, parents and children. //----------------------------------------------------------------------------- -LLObjectSelectionHandle LLSelectMgr::selectObjectAndFamily(LLViewerObject* obj, BOOL add_to_end) +LLObjectSelectionHandle LLSelectMgr::selectObjectAndFamily(LLViewerObject* obj, BOOL add_to_end, BOOL ignore_select_owned) { llassert( obj ); @@ -383,7 +389,7 @@ LLObjectSelectionHandle LLSelectMgr::selectObjectAndFamily(LLViewerObject* obj, return NULL; } - if (!canSelectObject(obj)) + if (!canSelectObject(obj,ignore_select_owned)) { //make_ui_sound("UISndInvalidOp"); return NULL; @@ -521,17 +527,15 @@ BOOL LLSelectMgr::removeObjectFromSelections(const LLUUID &id) { BOOL object_found = FALSE; LLTool *tool = NULL; - if (!gNoRender) - { - tool = LLToolMgr::getInstance()->getCurrentTool(); - // It's possible that the tool is editing an object that is not selected - LLViewerObject* tool_editing_object = tool->getEditingObject(); - if( tool_editing_object && tool_editing_object->mID == id) - { - tool->stopEditing(); - object_found = TRUE; - } + tool = LLToolMgr::getInstance()->getCurrentTool(); + + // It's possible that the tool is editing an object that is not selected + LLViewerObject* tool_editing_object = tool->getEditingObject(); + if( tool_editing_object && tool_editing_object->mID == id) + { + tool->stopEditing(); + object_found = TRUE; } // Iterate through selected objects list and kill the object @@ -647,7 +651,7 @@ bool LLSelectMgr::enableLinkObjects() { struct f : public LLSelectedObjectFunctor { - virtual bool apply(LLViewerObject* object) + bool apply(LLViewerObject* object) override { LLViewerObject *root_object = (object == NULL) ? NULL : object->getRootEdit(); return object->permModify() && !object->isPermanentEnforced() && @@ -658,8 +662,12 @@ bool LLSelectMgr::enableLinkObjects() new_value = LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func, firstonly); } } + if (!LLSelectMgr::getInstance()->getSelection()->checkAnimatedObjectLinkable()) + { + new_value = false; + } // [RLVa:KB] - Checked: 2011-03-19 (RLVa-1.3.0f) | Modified: RLVa-0.2.0g - if ( (new_value) && ((rlv_handler_t::isEnabled()) && (!gRlvHandler.canStand())) ) + if ( (new_value) && ((rlv_handler_t::isEnabled()) && (!RlvActions::canStand())) ) { // Allow only if the avie isn't sitting on any of the selected objects LLObjectSelectionHandle hSel = LLSelectMgr::getInstance()->getSelection(); @@ -681,7 +689,7 @@ bool LLSelectMgr::enableUnlinkObjects() !first_editable_object->isAttachment() && !first_editable_object->isPermanentEnforced() && ((root_object == NULL) || !root_object->isPermanentEnforced()); // [RLVa:KB] - Checked: 2011-03-19 (RLVa-1.3.0f) | Modified: RLVa-0.2.0g - if ( (new_value) && ((rlv_handler_t::isEnabled()) && (!gRlvHandler.canStand())) ) + if ( (new_value) && ((rlv_handler_t::isEnabled()) && (!RlvActions::canStand())) ) { // Allow only if the avie isn't sitting on any of the selected objects LLObjectSelectionHandle hSel = LLSelectMgr::getInstance()->getSelection(); @@ -869,6 +877,10 @@ void LLSelectMgr::addAsIndividual(LLViewerObject *objectp, S32 face, BOOL undoab // check to see if object is already in list LLSelectNode *nodep = mSelectedObjects->findNode(objectp); + // Reset (in anticipation of being set to an appropriate value by panel refresh, if they're up) + // + setTextureChannel(LLRender::DIFFUSE_MAP); + // if not in list, add it if (!nodep) { @@ -907,7 +919,7 @@ void LLSelectMgr::addAsIndividual(LLViewerObject *objectp, S32 face, BOOL undoab } else { - llerrs << "LLSelectMgr::add face " << face << " out-of-range" << llendl; + LL_ERRS() << "LLSelectMgr::add face " << face << " out-of-range" << LL_ENDL; return; } @@ -960,6 +972,10 @@ LLObjectSelectionHandle LLSelectMgr::setHoverObject(LLViewerObject *objectp, S32 iter != objects.end(); ++iter) { LLViewerObject* cur_objectp = *iter; + if(!cur_objectp || cur_objectp->isDead()) + { + continue; + } LLSelectNode* nodep = new LLSelectNode(cur_objectp, FALSE); nodep->selectTE(face, TRUE); mHoverObjects->addNodeAtEnd(nodep); @@ -1202,10 +1218,9 @@ void LLSelectMgr::setGridMode(EGridMode mode) mGridMode = mode; gSavedSettings.setS32("GridMode", mode); updateSelectionCenter(); - mGridValid = FALSE; } -void LLSelectMgr::getGrid(LLVector3& origin, LLQuaternion &rotation, LLVector3 &scale) +void LLSelectMgr::getGrid(LLVector3& origin, LLQuaternion &rotation, LLVector3 &scale, bool for_snap_guides) { mGridObjects.cleanupNodes(); @@ -1230,7 +1245,15 @@ void LLSelectMgr::getGrid(LLVector3& origin, LLQuaternion &rotation, LLVector3 & } else if (mGridMode == GRID_MODE_REF_OBJECT && first_grid_object && first_grid_object->mDrawable.notNull()) { - mGridRotation = first_grid_object->getRenderRotation(); + LLSelectNode *node = mSelectedObjects->findNode(first_grid_object); + if (!for_snap_guides && node) + { + mGridRotation = node->mSavedRotation; + } + else + { + mGridRotation = first_grid_object->getRenderRotation(); + } LLVector4a min_extents(F32_MAX); LLVector4a max_extents(-F32_MAX); @@ -1256,12 +1279,12 @@ void LLSelectMgr::getGrid(LLVector3& origin, LLQuaternion &rotation, LLVector3 & size.setSub(max_extents, min_extents); size.mul(0.5f); - mGridOrigin.set(center.getF32ptr()); LLDrawable* drawable = first_grid_object->mDrawable; if (drawable && drawable->isActive()) { - mGridOrigin = mGridOrigin * first_grid_object->getRenderMatrix(); + first_grid_object->getRenderMatrix().affineTransform(center,center); } + mGridOrigin.set(center.getF32ptr()); mGridScale.set(size.getF32ptr()); } } @@ -1303,7 +1326,6 @@ void LLSelectMgr::getGrid(LLVector3& origin, LLQuaternion &rotation, LLVector3 & origin = mGridOrigin; rotation = mGridRotation; scale = mGridScale; - mGridValid = TRUE; } //----------------------------------------------------------------------------- @@ -1359,7 +1381,7 @@ void LLSelectMgr::remove(LLViewerObject *objectp, S32 te, BOOL undoable) } else { - llerrs << "LLSelectMgr::remove - tried to remove TE " << te << " that wasn't selected" << llendl; + LL_ERRS() << "LLSelectMgr::remove - tried to remove TE " << te << " that wasn't selected" << LL_ENDL; return; } @@ -1382,7 +1404,7 @@ void LLSelectMgr::remove(LLViewerObject *objectp, S32 te, BOOL undoable) else { // ...out of range face - llerrs << "LLSelectMgr::remove - TE " << te << " out of range" << llendl; + LL_ERRS() << "LLSelectMgr::remove - TE " << te << " out of range" << LL_ENDL; } updateSelectionCenter(); @@ -1481,26 +1503,26 @@ void LLSelectMgr::demoteSelectionToIndividuals() //----------------------------------------------------------------------------- void LLSelectMgr::dump() { - llinfos << "Selection Manager: " << mSelectedObjects->getNumNodes() << " items" << llendl; + LL_INFOS() << "Selection Manager: " << mSelectedObjects->getNumNodes() << " items" << LL_ENDL; - llinfos << "TE mode " << mTEMode << llendl; + LL_INFOS() << "TE mode " << mTEMode << LL_ENDL; S32 count = 0; for (LLObjectSelection::iterator iter = getSelection()->begin(); iter != getSelection()->end(); iter++ ) { LLViewerObject* objectp = (*iter)->getObject(); - llinfos << "Object " << count << " type " << LLPrimitive::pCodeToString(objectp->getPCode()) << llendl; - llinfos << " hasLSL " << objectp->flagScripted() << llendl; - llinfos << " hasTouch " << objectp->flagHandleTouch() << llendl; - llinfos << " hasMoney " << objectp->flagTakesMoney() << llendl; - llinfos << " getposition " << objectp->getPosition() << llendl; - llinfos << " getpositionAgent " << objectp->getPositionAgent() << llendl; - llinfos << " getpositionRegion " << objectp->getPositionRegion() << llendl; - llinfos << " getpositionGlobal " << objectp->getPositionGlobal() << llendl; + LL_INFOS() << "Object " << count << " type " << LLPrimitive::pCodeToString(objectp->getPCode()) << LL_ENDL; + LL_INFOS() << " hasLSL " << objectp->flagScripted() << LL_ENDL; + LL_INFOS() << " hasTouch " << objectp->flagHandleTouch() << LL_ENDL; + LL_INFOS() << " hasMoney " << objectp->flagTakesMoney() << LL_ENDL; + LL_INFOS() << " getposition " << objectp->getPosition() << LL_ENDL; + LL_INFOS() << " getpositionAgent " << objectp->getPositionAgent() << LL_ENDL; + LL_INFOS() << " getpositionRegion " << objectp->getPositionRegion() << LL_ENDL; + LL_INFOS() << " getpositionGlobal " << objectp->getPositionGlobal() << LL_ENDL; LLDrawable* drawablep = objectp->mDrawable; - llinfos << " " << (drawablep&& drawablep->isVisible() ? "visible" : "invisible") << llendl; - llinfos << " " << (drawablep&& drawablep->isState(LLDrawable::FORCE_INVISIBLE) ? "force_invisible" : "") << llendl; + LL_INFOS() << " " << (drawablep&& drawablep->isVisible() ? "visible" : "invisible") << LL_ENDL; + LL_INFOS() << " " << (drawablep&& drawablep->isState(LLDrawable::FORCE_INVISIBLE) ? "force_invisible" : "") << LL_ENDL; count++; } @@ -1516,14 +1538,14 @@ void LLSelectMgr::dump() { if (node->isTESelected(te)) { - llinfos << "Object " << objectp << " te " << te << llendl; + LL_INFOS() << "Object " << objectp << " te " << te << LL_ENDL; } } } - llinfos << mHighlightedObjects->getNumNodes() << " objects currently highlighted." << llendl; + LL_INFOS() << mHighlightedObjects->getNumNodes() << " objects currently highlighted." << LL_ENDL; - llinfos << "Center global " << mSelectionCenterGlobal << llendl; + LL_INFOS() << "Center global " << mSelectionCenterGlobal << LL_ENDL; } //----------------------------------------------------------------------------- @@ -1541,7 +1563,7 @@ void LLSelectMgr::cleanup() struct LLSelectMgrSendFunctor : public LLSelectedObjectFunctor { - virtual bool apply(LLViewerObject* object) + bool apply(LLViewerObject* object) override { if (object->permModify()) { @@ -1566,8 +1588,8 @@ void LLSelectMgr::selectionSetImage(const LLUUID& imageid) && !item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID()) && (mSelectedObjects->getNumNodes() > 1) ) { - llwarns << "Attempted to apply no-copy texture to multiple objects" - << llendl; + LL_WARNS() << "Attempted to apply no-copy texture to multiple objects" + << LL_ENDL; return; } // @@ -1576,11 +1598,15 @@ void LLSelectMgr::selectionSetImage(const LLUUID& imageid) struct f : public LLSelectedTEFunctor { - LLViewerInventoryItem* mItem; + LLPointer mItem; LLUUID mImageID; f(LLViewerInventoryItem* item, const LLUUID& id) : mItem(item), mImageID(id) {} - bool apply(LLViewerObject* objectp, S32 te) + bool apply(LLViewerObject* objectp, S32 te) override { + if(objectp && !objectp->permModify()) + { + return false; + } if (mItem) { if (te == -1) // all faces @@ -1611,23 +1637,26 @@ void LLSelectMgr::selectionSetImage(const LLUUID& imageid) } return true; } - } setfunc(item, imageid); + }; + + f setfunc(item, imageid); getSelection()->applyToTEs(&setfunc); struct g : public LLSelectedObjectFunctor { LLViewerInventoryItem* mItem; g(LLViewerInventoryItem* item) : mItem(item) {} - virtual bool apply(LLViewerObject* object) + + bool apply(LLViewerObject* object) override { if (!mItem) { object->sendTEUpdate(); - // 1 particle effect per object // if(!gSavedSettings.getBOOL("DisablePointAtAndBeam")) { // + // 1 particle effect per object LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BEAM, TRUE); effectp->setSourceObject(gAgentAvatarp); effectp->setTargetObject(object); @@ -1652,7 +1681,7 @@ void LLSelectMgr::selectionSetColor(const LLColor4 &color) { LLColor4 mColor; f(const LLColor4& c) : mColor(c) {} - bool apply(LLViewerObject* object, S32 te) + bool apply(LLViewerObject* object, S32 te) override { if (object->permModify()) { @@ -1676,7 +1705,7 @@ void LLSelectMgr::selectionSetColorOnly(const LLColor4 &color) { LLColor4 mColor; f(const LLColor4& c) : mColor(c) {} - bool apply(LLViewerObject* object, S32 te) + bool apply(LLViewerObject* object, S32 te) override { if (object->permModify()) { @@ -1703,7 +1732,7 @@ void LLSelectMgr::selectionSetAlphaOnly(const F32 alpha) { F32 mAlpha; f(const F32& a) : mAlpha(a) {} - bool apply(LLViewerObject* object, S32 te) + bool apply(LLViewerObject* object, S32 te) override { if (object->permModify()) { @@ -1727,7 +1756,7 @@ void LLSelectMgr::selectionRevertColors() { LLObjectSelectionHandle mSelectedObjects; f(LLObjectSelectionHandle sel) : mSelectedObjects(sel) {} - bool apply(LLViewerObject* object, S32 te) + bool apply(LLViewerObject* object, S32 te) override { if (object->permModify()) { @@ -1748,13 +1777,47 @@ void LLSelectMgr::selectionRevertColors() getSelection()->applyToObjects(&sendfunc); } +void LLSelectMgr::selectionRevertShinyColors() +{ + struct f : public LLSelectedTEFunctor + { + LLObjectSelectionHandle mSelectedObjects; + f(LLObjectSelectionHandle sel) : mSelectedObjects(sel) {} + bool apply(LLViewerObject* object, S32 te) override + { + if (object->permModify()) + { + LLSelectNode* nodep = mSelectedObjects->findNode(object); + if (nodep && te < (S32)nodep->mSavedShinyColors.size()) + { + LLColor4 color = nodep->mSavedShinyColors[te]; + // update viewer side color in anticipation of update from simulator + LLMaterialPtr old_mat = object->getTE(te)->getMaterialParams(); + if (!old_mat.isNull()) + { + LLMaterialPtr new_mat = gFloaterTools->getPanelFace()->createDefaultMaterial(old_mat); + new_mat->setSpecularLightColor(color); + object->getTE(te)->setMaterialParams(new_mat); + LLMaterialMgr::getInstance()->put(object->getID(), te, *new_mat); + } + } + } + return true; + } + } setfunc(mSelectedObjects); + getSelection()->applyToTEs(&setfunc); + + LLSelectMgrSendFunctor sendfunc; + getSelection()->applyToObjects(&sendfunc); +} + BOOL LLSelectMgr::selectionRevertTextures() { struct f : public LLSelectedTEFunctor { LLObjectSelectionHandle mSelectedObjects; f(LLObjectSelectionHandle sel) : mSelectedObjects(sel) {} - bool apply(LLViewerObject* object, S32 te) + bool apply(LLViewerObject* object, S32 te) override { if (object->permModify()) { @@ -1794,7 +1857,7 @@ void LLSelectMgr::selectionSetBumpmap(U8 bumpmap) { U8 mBump; f(const U8& b) : mBump(b) {} - bool apply(LLViewerObject* object, S32 te) + bool apply(LLViewerObject* object, S32 te) override { if (object->permModify()) { @@ -1816,7 +1879,7 @@ void LLSelectMgr::selectionSetTexGen(U8 texgen) { U8 mTexgen; f(const U8& t) : mTexgen(t) {} - bool apply(LLViewerObject* object, S32 te) + bool apply(LLViewerObject* object, S32 te) override { if (object->permModify()) { @@ -1839,7 +1902,7 @@ void LLSelectMgr::selectionSetShiny(U8 shiny) { U8 mShiny; f(const U8& t) : mShiny(t) {} - bool apply(LLViewerObject* object, S32 te) + bool apply(LLViewerObject* object, S32 te) override { if (object->permModify()) { @@ -1861,7 +1924,7 @@ void LLSelectMgr::selectionSetFullbright(U8 fullbright) { U8 mFullbright; f(const U8& t) : mFullbright(t) {} - bool apply(LLViewerObject* object, S32 te) + bool apply(LLViewerObject* object, S32 te) override { if (object->permModify()) { @@ -1877,7 +1940,8 @@ void LLSelectMgr::selectionSetFullbright(U8 fullbright) { U8 mFullbright; g(const U8& t) : mFullbright(t) {} - virtual bool apply(LLViewerObject* object) + + bool apply(LLViewerObject* object) override { if (object->permModify()) { @@ -1910,7 +1974,7 @@ void LLSelectMgr::selectionSetMedia(U8 media_type, const LLSD &media_data) U8 mMediaFlags; const LLSD &mMediaData; f(const U8& t, const LLSD& d) : mMediaFlags(t), mMediaData(d) {} - bool apply(LLViewerObject* object, S32 te) + bool apply(LLViewerObject* object, S32 te) override { if (object->permModify()) { @@ -1926,14 +1990,14 @@ void LLSelectMgr::selectionSetMedia(U8 media_type, const LLSD &media_data) llassert(mMediaData.isMap()); const LLTextureEntry *texture_entry = object->getTE(te); if (!mMediaData.isMap() || - (NULL != texture_entry) && !texture_entry->hasMedia() && !mMediaData.has(LLMediaEntry::HOME_URL_KEY)) + ((NULL != texture_entry) && !texture_entry->hasMedia() && !mMediaData.has(LLMediaEntry::HOME_URL_KEY))) { // skip adding/updating media } else { // Add/update media object->setTEMediaFlags(te, mMediaFlags); - LLVOVolume *vo = dynamic_cast(object); + LLVOVolume *vo = object->asVolume(); llassert(NULL != vo); if (NULL != vo) { @@ -1954,12 +2018,12 @@ void LLSelectMgr::selectionSetMedia(U8 media_type, const LLSD &media_data) struct f2 : public LLSelectedObjectFunctor { - virtual bool apply(LLViewerObject* object) + bool apply(LLViewerObject* object) override { if (object->permModify()) { object->sendTEUpdate(); - LLVOVolume *vo = dynamic_cast(object); + LLVOVolume *vo = object->asVolume(); llassert(NULL != vo); // It's okay to skip this object if hasMedia() is false... // the sendTEUpdate() above would remove all media data if it were @@ -1982,7 +2046,7 @@ void LLSelectMgr::selectionSetGlow(F32 glow) { F32 mGlow; f1(F32 glow) : mGlow(glow) {}; - bool apply(LLViewerObject* object, S32 face) + bool apply(LLViewerObject* object, S32 face) override { if (object->permModify()) { @@ -1996,7 +2060,77 @@ void LLSelectMgr::selectionSetGlow(F32 glow) struct f2 : public LLSelectedObjectFunctor { - virtual bool apply(LLViewerObject* object) + bool apply(LLViewerObject* object) override + { + if (object->permModify()) + { + object->sendTEUpdate(); + } + return true; + } + } func2; + mSelectedObjects->applyToObjects( &func2 ); +} + +void LLSelectMgr::selectionSetMaterialParams(LLSelectedTEMaterialFunctor* material_func) +{ + struct f1 : public LLSelectedTEFunctor + { + LLMaterialPtr mMaterial; + f1(LLSelectedTEMaterialFunctor* material_func) : _material_func(material_func) {} + + bool apply(LLViewerObject* object, S32 face) override + { + if (object && object->permModify() && _material_func) + { + LLTextureEntry* tep = object->getTE(face); + if (tep) + { + LLMaterialPtr current_material = tep->getMaterialParams(); + _material_func->apply(object, face, tep, current_material); + } + } + return true; + } + + LLSelectedTEMaterialFunctor* _material_func; + } func1(material_func); + mSelectedObjects->applyToTEs( &func1 ); + + struct f2 : public LLSelectedObjectFunctor + { + bool apply(LLViewerObject* object) override + { + if (object->permModify()) + { + object->sendTEUpdate(); + } + return true; + } + } func2; + mSelectedObjects->applyToObjects( &func2 ); +} + +void LLSelectMgr::selectionRemoveMaterial() +{ + struct f1 : public LLSelectedTEFunctor + { + bool apply(LLViewerObject* object, S32 face) override + { + if (object->permModify()) + { + LL_DEBUGS("Materials") << "Removing material from object " << object->getID() << " face " << face << LL_ENDL; + LLMaterialMgr::getInstance()->remove(object->getID(),face); + object->setTEMaterialParams(face, NULL); + } + return true; + } + } func1; + mSelectedObjects->applyToTEs( &func1 ); + + struct f2 : public LLSelectedObjectFunctor + { + bool apply(LLViewerObject* object) override { if (object->permModify()) { @@ -2037,7 +2171,7 @@ BOOL LLSelectMgr::selectionGetGlow(F32 *glow) F32 lglow = 0.f; struct f1 : public LLSelectedTEGetFunctor { - F32 get(LLViewerObject* object, S32 face) + F32 get(LLViewerObject* object, S32 face) override { return object->getTE(face)->getGlow(); } @@ -2048,13 +2182,15 @@ BOOL LLSelectMgr::selectionGetGlow(F32 *glow) return identical; } + void LLSelectMgr::selectionSetPhysicsType(U8 type) { struct f : public LLSelectedObjectFunctor { U8 mType; f(const U8& t) : mType(t) {} - virtual bool apply(LLViewerObject* object) + + bool apply(LLViewerObject* object) override { if (object->permModify()) { @@ -2073,7 +2209,8 @@ void LLSelectMgr::selectionSetFriction(F32 friction) { F32 mFriction; f(const F32& friction) : mFriction(friction) {} - virtual bool apply(LLViewerObject* object) + + bool apply(LLViewerObject* object) override { if (object->permModify()) { @@ -2092,7 +2229,8 @@ void LLSelectMgr::selectionSetGravity(F32 gravity ) { F32 mGravity; f(const F32& gravity) : mGravity(gravity) {} - virtual bool apply(LLViewerObject* object) + + bool apply(LLViewerObject* object) override { if (object->permModify()) { @@ -2111,7 +2249,8 @@ void LLSelectMgr::selectionSetDensity(F32 density ) { F32 mDensity; f(const F32& density ) : mDensity(density) {} - virtual bool apply(LLViewerObject* object) + + bool apply(LLViewerObject* object) override { if (object->permModify()) { @@ -2130,7 +2269,8 @@ void LLSelectMgr::selectionSetRestitution(F32 restitution) { F32 mRestitution; f(const F32& restitution ) : mRestitution(restitution) {} - virtual bool apply(LLViewerObject* object) + + bool apply(LLViewerObject* object) override { if (object->permModify()) { @@ -2143,6 +2283,7 @@ void LLSelectMgr::selectionSetRestitution(F32 restitution) getSelection()->applyToObjects(&sendfunc); } + //----------------------------------------------------------------------------- // selectionSetMaterial() //----------------------------------------------------------------------------- @@ -2152,7 +2293,8 @@ void LLSelectMgr::selectionSetMaterial(U8 material) { U8 mMaterial; f(const U8& t) : mMaterial(t) {} - virtual bool apply(LLViewerObject* object) + + bool apply(LLViewerObject* object) override { if (object->permModify()) { @@ -2174,7 +2316,8 @@ BOOL LLSelectMgr::selectionAllPCode(LLPCode code) { LLPCode mCode; f(const LLPCode& t) : mCode(t) {} - virtual bool apply(LLViewerObject* object) + + bool apply(LLViewerObject* object) override { if (object->getPCode() != mCode) { @@ -2225,6 +2368,7 @@ void LLSelectMgr::selectionSetIncludeInSearch(bool include_in_search) "ObjectIncludeInSearch", packAgentAndSessionID, packObjectIncludeInSearch, + logNoOp, &include_in_search, SEND_ONLY_ROOTS); } @@ -2244,7 +2388,8 @@ BOOL LLSelectMgr::selectionGetClickAction(U8 *out_action) { U8 mAction; f(const U8& t) : mAction(t) {} - virtual bool apply(LLViewerObject* object) + + bool apply(LLViewerObject* object) override { if ( mAction != object->getClickAction()) { @@ -2263,7 +2408,8 @@ void LLSelectMgr::selectionSetClickAction(U8 action) { U8 mAction; f(const U8& t) : mAction(t) {} - virtual bool apply(LLViewerObject* object) + + bool apply(LLViewerObject* object) override { object->setClickAction(mAction); return true; @@ -2274,6 +2420,7 @@ void LLSelectMgr::selectionSetClickAction(U8 action) sendListToRegions("ObjectClickAction", packAgentAndSessionID, packObjectClickAction, + logNoOp, &action, SEND_INDIVIDUALS); } @@ -2309,7 +2456,7 @@ void LLSelectMgr::sendGodlikeRequest(const std::string& request, const std::stri } else { - sendListToRegions(message_type, packGodlikeHead, packObjectIDAsParam, &data, SEND_ONLY_ROOTS); + sendListToRegions(message_type, packGodlikeHead, packObjectIDAsParam, logNoOp, &data, SEND_ONLY_ROOTS); } } @@ -2337,6 +2484,23 @@ void LLSelectMgr::packGodlikeHead(void* user_data) } } +// static +void LLSelectMgr::logNoOp(LLSelectNode* node, void *) +{ +} + +// static +void LLSelectMgr::logAttachmentRequest(LLSelectNode* node, void *) +{ + LLAttachmentsMgr::instance().onAttachmentRequested(node->mItemID); +} + +// static +void LLSelectMgr::logDetachRequest(LLSelectNode* node, void *) +{ + LLAttachmentsMgr::instance().onDetachRequested(node->mItemID); +} + // static void LLSelectMgr::packObjectIDAsParam(LLSelectNode* node, void *) { @@ -2354,7 +2518,7 @@ void LLSelectMgr::selectionTexScaleAutofit(F32 repeats_per_meter) { F32 mRepeatsPerMeter; f(const F32& t) : mRepeatsPerMeter(t) {} - bool apply(LLViewerObject* object, S32 te) + bool apply(LLViewerObject* object, S32 te) override { if (object->permModify()) @@ -2427,19 +2591,66 @@ void LLSelectMgr::adjustTexturesByScale(BOOL send_to_sim, BOOL stretch) continue; } - LLVector3 scale_ratio = selectNode->mTextureScaleRatios[te_num]; LLVector3 object_scale = object->getScale(); + LLVector3 diffuse_scale_ratio = selectNode->mTextureScaleRatios[te_num]; + + // We like these to track together. NORSPEC-96 + // + LLVector3 normal_scale_ratio = diffuse_scale_ratio; + LLVector3 specular_scale_ratio = diffuse_scale_ratio; // Apply new scale to face if (planar) { - object->setTEScale(te_num, 1.f/object_scale.mV[s_axis]*scale_ratio.mV[s_axis], - 1.f/object_scale.mV[t_axis]*scale_ratio.mV[t_axis]); + F32 diffuse_scale_s = diffuse_scale_ratio.mV[s_axis]/object_scale.mV[s_axis]; + F32 diffuse_scale_t = diffuse_scale_ratio.mV[t_axis]/object_scale.mV[t_axis]; + + F32 normal_scale_s = normal_scale_ratio.mV[s_axis]/object_scale.mV[s_axis]; + F32 normal_scale_t = normal_scale_ratio.mV[t_axis]/object_scale.mV[t_axis]; + + F32 specular_scale_s = specular_scale_ratio.mV[s_axis]/object_scale.mV[s_axis]; + F32 specular_scale_t = specular_scale_ratio.mV[t_axis]/object_scale.mV[t_axis]; + + object->setTEScale(te_num, diffuse_scale_s, diffuse_scale_t); + + LLTextureEntry* tep = object->getTE(te_num); + + if (tep && !tep->getMaterialParams().isNull()) + { + LLMaterialPtr orig = tep->getMaterialParams(); + LLMaterialPtr p = gFloaterTools->getPanelFace()->createDefaultMaterial(orig); + p->setNormalRepeat(normal_scale_s, normal_scale_t); + p->setSpecularRepeat(specular_scale_s, specular_scale_t); + + LLMaterialMgr::getInstance()->put(object->getID(), te_num, *p); + } } else { - object->setTEScale(te_num, scale_ratio.mV[s_axis]*object_scale.mV[s_axis], - scale_ratio.mV[t_axis]*object_scale.mV[t_axis]); + + F32 diffuse_scale_s = diffuse_scale_ratio.mV[s_axis]*object_scale.mV[s_axis]; + F32 diffuse_scale_t = diffuse_scale_ratio.mV[t_axis]*object_scale.mV[t_axis]; + + F32 normal_scale_s = normal_scale_ratio.mV[s_axis]*object_scale.mV[s_axis]; + F32 normal_scale_t = normal_scale_ratio.mV[t_axis]*object_scale.mV[t_axis]; + + F32 specular_scale_s = specular_scale_ratio.mV[s_axis]*object_scale.mV[s_axis]; + F32 specular_scale_t = specular_scale_ratio.mV[t_axis]*object_scale.mV[t_axis]; + + object->setTEScale(te_num, diffuse_scale_s,diffuse_scale_t); + + LLTextureEntry* tep = object->getTE(te_num); + + if (tep && !tep->getMaterialParams().isNull()) + { + LLMaterialPtr orig = tep->getMaterialParams(); + LLMaterialPtr p = gFloaterTools->getPanelFace()->createDefaultMaterial(orig); + + p->setNormalRepeat(normal_scale_s, normal_scale_t); + p->setSpecularRepeat(specular_scale_s, specular_scale_t); + + LLMaterialMgr::getInstance()->put(object->getID(), te_num, *p); + } } send = send_to_sim; } @@ -2557,6 +2768,35 @@ BOOL LLSelectMgr::selectGetRootsModify() return TRUE; } +//----------------------------------------------------------------------------- +// selectGetSameRegion() - return TRUE if all objects are in same region +//----------------------------------------------------------------------------- +BOOL LLSelectMgr::selectGetSameRegion() +{ + if (getSelection()->isEmpty()) + { + return TRUE; + } + LLViewerObject* object = getSelection()->getFirstObject(); + if (!object) + { + return FALSE; + } + LLViewerRegion* current_region = object->getRegion(); + + for (LLObjectSelection::root_iterator iter = getSelection()->root_begin(); + iter != getSelection()->root_end(); iter++) + { + LLSelectNode* node = *iter; + object = node->getObject(); + if (!node->mValid || !object || current_region != object->getRegion()) + { + return FALSE; + } + } + + return TRUE; +} //----------------------------------------------------------------------------- // selectGetNonPermanentEnforced() - return TRUE if all objects are not @@ -2892,7 +3132,6 @@ BOOL LLSelectMgr::selectGetViewableCharacters() return TRUE; } - //----------------------------------------------------------------------------- // selectGetRootsTransfer() - return TRUE if current agent can transfer all // selected root objects. @@ -3401,7 +3640,7 @@ bool LLSelectMgr::confirmDelete(const LLSD& notification, const LLSD& response, S32 option = LLNotification::getSelectedOption(notification, response); if (!handle->getObjectCount()) { - llwarns << "Nothing to delete!" << llendl; + LL_WARNS() << "Nothing to delete!" << LL_ENDL; return false; } @@ -3410,26 +3649,24 @@ bool LLSelectMgr::confirmDelete(const LLSD& notification, const LLSD& response, case 0: { // TODO: Make sure you have delete permissions on all of them. - LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); + const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); // attempt to derez into the trash. - LLDeRezInfo* info = new LLDeRezInfo(DRD_TRASH, trash_id); + LLDeRezInfo info(DRD_TRASH, trash_id); LLSelectMgr::getInstance()->sendListToRegions("DeRezObject", - packDeRezHeader, - packObjectLocalID, - (void*)info, - SEND_ONLY_ROOTS); + packDeRezHeader, + packObjectLocalID, + logNoOp, + (void*) &info, + SEND_ONLY_ROOTS); // VEFFECT: Delete Object - one effect for all deletes - if(!gSavedSettings.getBOOL("DisablePointAtAndBeam")) + if (!gSavedSettings.getBOOL("DisablePointAtAndBeam") && (LLSelectMgr::getInstance()->mSelectedObjects->mSelectType != SELECT_TYPE_HUD)) { - if (LLSelectMgr::getInstance()->mSelectedObjects->mSelectType != SELECT_TYPE_HUD) - { - LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE); - effectp->setPositionGlobal( LLSelectMgr::getInstance()->getSelectionCenterGlobal() ); - effectp->setColor(LLColor4U(gAgent.getEffectColor())); - F32 duration = 0.5f; - duration += LLSelectMgr::getInstance()->mSelectedObjects->getObjectCount() / 64.f; - effectp->setDuration(duration); - } + LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE); + effectp->setPositionGlobal( LLSelectMgr::getInstance()->getSelectionCenterGlobal() ); + effectp->setColor(LLColor4U(gAgent.getEffectColor())); + F32 duration = 0.5f; + duration += LLSelectMgr::getInstance()->mSelectedObjects->getObjectCount() / 64.f; + effectp->setDuration(duration); } gAgentCamera.setLookAt(LOOKAT_TARGET_CLEAR); @@ -3454,6 +3691,7 @@ void LLSelectMgr::selectForceDelete() "ObjectDelete", packDeleteHeader, packObjectLocalID, + logNoOp, (void*)TRUE, SEND_ONLY_ROOTS); } @@ -3627,7 +3865,7 @@ void LLSelectMgr::selectDuplicate(const LLVector3& offset, BOOL select_copy) data.offset = offset; data.flags = (select_copy ? FLAGS_CREATE_SELECTED : 0x0); - sendListToRegions("ObjectDuplicate", packDuplicateHeader, packDuplicate, &data, SEND_ONLY_ROOTS); + sendListToRegions("ObjectDuplicate", packDuplicateHeader, packDuplicate, logNoOp, &data, SEND_ONLY_ROOTS); if (select_copy) { @@ -3682,7 +3920,7 @@ void LLSelectMgr::repeatDuplicate() data.offset = LLVector3::zero; data.flags = 0x0; - sendListToRegions("ObjectDuplicate", packDuplicateHeader, packDuplicate, &data, SEND_ONLY_ROOTS); + sendListToRegions("ObjectDuplicate", packDuplicateHeader, packDuplicate, logNoOp, &data, SEND_ONLY_ROOTS); // move current selection based on delta from duplication position and update duplication position for (LLObjectSelection::root_iterator iter = getSelection()->root_begin(); @@ -3761,7 +3999,7 @@ void LLSelectMgr::selectDuplicateOnRay(const LLVector3 &ray_start_region, data.mFlags = (select_copy ? FLAGS_CREATE_SELECTED : 0x0); sendListToRegions("ObjectDuplicateOnRay", - packDuplicateOnRayHead, packObjectLocalID, &data, SEND_ONLY_ROOTS); + packDuplicateOnRayHead, packObjectLocalID, logNoOp, &data, SEND_ONLY_ROOTS); if (select_copy) { @@ -3779,21 +4017,19 @@ void LLSelectMgr::packDuplicateOnRayHead(void *user_data) msg->nextBlockFast(_PREHASH_AgentData); msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() ); - LLUUID group_id = gAgent.getGroupID(); - // Apply always rez under owned land group setting for objects - // duplicated by shift-dragging or duplicating - if (gSavedSettings.getBOOL("AscentAlwaysRezInGroup")) + // Rez under Land Group + static LLCachedControl AlchemyRezUnderLandGroup(gSavedSettings, "AscentAlwaysRezInGroup"); + LLUUID group_id = gAgent.getGroupID(); + if (AlchemyRezUnderLandGroup) { - LLParcel *parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); - if (gAgent.isInGroup(parcel->getGroupID())) - { - group_id = parcel->getGroupID(); - } - else if (gAgent.isInGroup(parcel->getOwnerID())) - { - group_id = parcel->getOwnerID(); - } + LLParcel* land_parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + // Is the agent in the land group + if (gAgent.isInGroup(land_parcel->getGroupID())) + group_id = land_parcel->getGroupID(); + // Is the agent in the land group (the group owns the land) + else if(gAgent.isInGroup(land_parcel->getOwnerID())) + group_id = land_parcel->getOwnerID(); } msg->addUUIDFast(_PREHASH_GroupID, group_id); @@ -3828,6 +4064,7 @@ void LLSelectMgr::sendMultipleUpdate(U32 type) "MultipleObjectUpdate", packAgentAndSessionID, packMultipleUpdate, + logNoOp, &type, send_type); } @@ -3864,7 +4101,7 @@ void LLSelectMgr::packMultipleUpdate(LLSelectNode* node, void *user_data) } if (type & UPD_SCALE) { - //llinfos << "Sending object scale " << object->getScale() << llendl; + //LL_INFOS() << "Sending object scale " << object->getScale() << LL_ENDL; htonmemcpy(&data[offset], &(object->getScale().mV), MVT_LLVector3, 12); offset += 12; } @@ -3891,7 +4128,7 @@ void LLSelectMgr::sendOwner(const LLUUID& owner_id, data.group_id = group_id; data.override = override; - sendListToRegions("ObjectOwner", packOwnerHead, packObjectLocalID, &data, SEND_ONLY_ROOTS); + sendListToRegions("ObjectOwner", packOwnerHead, packObjectLocalID, logNoOp, &data, SEND_ONLY_ROOTS); } // static @@ -3915,7 +4152,7 @@ void LLSelectMgr::packOwnerHead(void *user_data) void LLSelectMgr::sendGroup(const LLUUID& group_id) { LLUUID local_group_id(group_id); - sendListToRegions("ObjectGroup", packAgentAndSessionAndGroupID, packObjectLocalID, &local_group_id, SEND_ONLY_ROOTS); + sendListToRegions("ObjectGroup", packAgentAndSessionAndGroupID, packObjectLocalID, logNoOp, &local_group_id, SEND_ONLY_ROOTS); } @@ -3939,7 +4176,7 @@ void LLSelectMgr::sendBuy(const LLUUID& buyer_id, const LLUUID& category_id, con LLBuyData buy; buy.mCategoryID = category_id; buy.mSaleInfo = sale_info; - sendListToRegions("ObjectBuy", packAgentGroupAndCatID, packBuyObjectIDs, &buy, SEND_ONLY_ROOTS); + sendListToRegions("ObjectBuy", packAgentGroupAndCatID, packBuyObjectIDs, logNoOp, &buy, SEND_ONLY_ROOTS); } // static @@ -3983,7 +4220,7 @@ void LLSelectMgr::selectionSetObjectPermissions(U8 field, data.mMask = mask; data.mOverride = override; - sendListToRegions("ObjectPermissions", packPermissionsHead, packPermissions, &data, SEND_ONLY_ROOTS); + sendListToRegions("ObjectPermissions", packPermissionsHead, packPermissions, logNoOp, &data, SEND_ONLY_ROOTS); } void LLSelectMgr::packPermissionsHead(void* user_data) @@ -4002,7 +4239,7 @@ void LLSelectMgr::packPermissionsHead(void* user_data) /* void LLSelectMgr::sendSelect() { - llerrs << "Not implemented" << llendl; + LL_ERRS() << "Not implemented" << LL_ENDL; } */ @@ -4026,6 +4263,7 @@ void LLSelectMgr::deselectAll() "ObjectDeselect", packAgentAndSessionID, packObjectLocalID, + logNoOp, NULL, SEND_INDIVIDUALS); @@ -4056,6 +4294,7 @@ void LLSelectMgr::deselectAllForStandingUp() "ObjectDeselect", packAgentAndSessionID, packObjectLocalID, + logNoOp, NULL, SEND_INDIVIDUALS); @@ -4151,9 +4390,9 @@ void LLSelectMgr::deselectAllIfTooFar() { if (mDebugSelectMgr) { - llinfos << "Selection manager: auto-deselecting, select_dist = " << (F32) sqrt(select_dist_sq) << llendl; - llinfos << "agent pos global = " << gAgent.getPositionGlobal() << llendl; - llinfos << "selection pos global = " << selectionCenter << llendl; + LL_INFOS() << "Selection manager: auto-deselecting, select_dist = " << (F32) sqrt(select_dist_sq) << LL_ENDL; + LL_INFOS() << "agent pos global = " << gAgent.getPositionGlobal() << LL_ENDL; + LL_INFOS() << "selection pos global = " << selectionCenter << LL_ENDL; } deselectAll(); @@ -4164,42 +4403,50 @@ void LLSelectMgr::deselectAllIfTooFar() void LLSelectMgr::selectionSetObjectName(const std::string& name) { + std::string name_copy(name); + // we only work correctly if 1 object is selected. - if(mSelectedObjects->getRootObjectCount() == 1) + if(mSelectedObjects->getRootObjectCount() >= 1) // { sendListToRegions("ObjectName", packAgentAndSessionID, packObjectName, - (void*)(new std::string(name)), + logNoOp, + (void*)(&name_copy), SEND_ONLY_ROOTS); } - else if(mSelectedObjects->getObjectCount() == 1) + else if(mSelectedObjects->getObjectCount() >= 1) // { sendListToRegions("ObjectName", packAgentAndSessionID, packObjectName, - (void*)(new std::string(name)), + logNoOp, + (void*)(&name_copy), SEND_INDIVIDUALS); } } void LLSelectMgr::selectionSetObjectDescription(const std::string& desc) { + std::string desc_copy(desc); + // we only work correctly if 1 object is selected. - if(mSelectedObjects->getRootObjectCount() == 1) + if(mSelectedObjects->getRootObjectCount() >= 1) // { sendListToRegions("ObjectDescription", packAgentAndSessionID, packObjectDescription, - (void*)(new std::string(desc)), + logNoOp, + (void*)(&desc_copy), SEND_ONLY_ROOTS); } - else if(mSelectedObjects->getObjectCount() == 1) + else if(mSelectedObjects->getObjectCount() >= 1) // { sendListToRegions("ObjectDescription", packAgentAndSessionID, packObjectDescription, - (void*)(new std::string(desc)), + logNoOp, + (void*)(&desc_copy), SEND_INDIVIDUALS); } } @@ -4212,6 +4459,7 @@ void LLSelectMgr::selectionSetObjectCategory(const LLCategory& category) sendListToRegions("ObjectCategory", packAgentAndSessionID, packObjectCategory, + logNoOp, (void*)(&category), SEND_ONLY_ROOTS); } @@ -4221,6 +4469,7 @@ void LLSelectMgr::selectionSetObjectSaleInfo(const LLSaleInfo& sale_info) sendListToRegions("ObjectSaleInfo", packAgentAndSessionID, packObjectSaleInfo, + logNoOp, (void*)(&sale_info), SEND_ONLY_ROOTS); } @@ -4243,7 +4492,7 @@ void LLSelectMgr::sendAttach(U8 attachment_point, bool replace) if (0 == attachment_point || get_if_there(gAgentAvatarp->mAttachmentPoints, (S32)attachment_point, (LLViewerJointAttachment*)NULL)) { - if ((!replace || attachment_point != 0) && gHippoGridManager->getConnectedGrid()->supportsInvLinks()) + if (!replace || attachment_point != 0) { // If we know the attachment point then we got here by clicking an // "Attach to..." context menu item, so we should add, not replace. @@ -4254,10 +4503,14 @@ void LLSelectMgr::sendAttach(U8 attachment_point, bool replace) "ObjectAttach", packAgentIDAndSessionAndAttachment, packObjectIDAndRotation, + logAttachmentRequest, &attachment_point, SEND_ONLY_ROOTS ); if (!build_mode) { + // After "ObjectAttach" server will unsubscribe us from properties updates + // so either deselect objects or resend selection after attach packet reaches server + // In case of build_mode LLPanelObjectInventory::refresh() will deal with selection deselectAll(); } } @@ -4274,6 +4527,7 @@ void LLSelectMgr::sendDetach() "ObjectDetach", packAgentAndSessionID, packObjectLocalID, + logDetachRequest, NULL, SEND_ONLY_ROOTS ); } @@ -4290,6 +4544,7 @@ void LLSelectMgr::sendDropAttachment() "ObjectDrop", packAgentAndSessionID, packObjectLocalID, + logDetachRequest, NULL, SEND_ONLY_ROOTS); } @@ -4309,6 +4564,7 @@ void LLSelectMgr::sendLink() "ObjectLink", packAgentAndSessionID, packObjectLocalID, + logNoOp, NULL, SEND_ONLY_ROOTS); } @@ -4324,7 +4580,7 @@ void LLSelectMgr::sendDelink() { //on delink, any modifyable object should f() {} - virtual bool apply(LLViewerObject* object) + bool apply(LLViewerObject* object) override { if (object->permModify()) { @@ -4346,6 +4602,7 @@ void LLSelectMgr::sendDelink() "ObjectDelink", packAgentAndSessionID, packObjectLocalID, + logNoOp, NULL, SEND_INDIVIDUALS); } @@ -4398,6 +4655,7 @@ void LLSelectMgr::sendSelect() "ObjectSelect", packAgentAndSessionID, packObjectLocalID, + logNoOp, NULL, SEND_INDIVIDUALS); } @@ -4419,7 +4677,7 @@ void LLSelectMgr::selectionDump() { struct f : public LLSelectedObjectFunctor { - virtual bool apply(LLViewerObject* object) + bool apply(LLViewerObject* object) override { object->dump(); return true; @@ -4432,7 +4690,7 @@ void LLSelectMgr::saveSelectedObjectColors() { struct f : public LLSelectedNodeFunctor { - virtual bool apply(LLSelectNode* node) + bool apply(LLSelectNode* node) override { node->saveColors(); return true; @@ -4441,12 +4699,25 @@ void LLSelectMgr::saveSelectedObjectColors() getSelection()->applyToNodes(&func); } +void LLSelectMgr::saveSelectedShinyColors() +{ + struct f : public LLSelectedNodeFunctor + { + bool apply(LLSelectNode* node) override + { + node->saveShinyColors(); + return true; + } + } func; + getSelection()->applyToNodes(&func); +} + void LLSelectMgr::saveSelectedObjectTextures() { // invalidate current selection so we update saved textures struct f : public LLSelectedNodeFunctor { - virtual bool apply(LLSelectNode* node) + bool apply(LLSelectNode* node) override { node->mValid = FALSE; return true; @@ -4472,8 +4743,10 @@ void LLSelectMgr::saveSelectedObjectTransform(EActionType action_type) struct f : public LLSelectedNodeFunctor { EActionType mActionType; - f(EActionType a) : mActionType(a) {} - virtual bool apply(LLSelectNode* selectNode) + LLSelectMgr* mManager; + f(EActionType a, LLSelectMgr* p) : mActionType(a), mManager(p) {} + + bool apply(LLSelectNode* selectNode) override { LLViewerObject* object = selectNode->getObject(); if (!object) @@ -4519,10 +4792,10 @@ void LLSelectMgr::saveSelectedObjectTransform(EActionType action_type) } selectNode->mSavedScale = object->getScale(); - selectNode->saveTextureScaleRatios(); + selectNode->saveTextureScaleRatios(mManager->mTextureChannel); return true; } - } func(action_type); + } func(action_type, this); getSelection()->applyToNodes(&func); mSavedSelectionBBox = getBBoxOfSelection(); @@ -4533,13 +4806,21 @@ struct LLSelectMgrApplyFlags : public LLSelectedObjectFunctor LLSelectMgrApplyFlags(U32 flags, BOOL state) : mFlags(flags), mState(state) {} U32 mFlags; BOOL mState; - virtual bool apply(LLViewerObject* object) + + bool apply(LLViewerObject* object) override { - if ( object->permModify() && // preemptive permissions check - object->isRoot()) // don't send for child objects + if ( object->permModify()) { - object->setFlags( mFlags, mState); - } + if (object->isRoot()) // don't send for child objects + { + object->setFlags( mFlags, mState); + } + else if (FLAGS_WORLD & mFlags && ((LLViewerObject*)object->getRoot())->isSelected()) + { + // FLAGS_WORLD are shared by all items in linkset + object->setFlagsWithoutUpdate(FLAGS_WORLD & mFlags, mState); + } + }; return true; } }; @@ -4614,23 +4895,19 @@ void LLSelectMgr::packAgentAndSessionAndGroupID(void* user_data) // static void LLSelectMgr::packDuplicateHeader(void* data) { - LLUUID group_id(gAgent.getGroupID()); - - // Apply always rez under owned land group setting for objects - // duplicated by shift-dragging or duplicating - if (gSavedSettings.getBOOL("AscentAlwaysRezInGroup")) + // Rez under Land Group + static LLCachedControl AlchemyRezUnderLandGroup(gSavedSettings, "AscentAlwaysRezInGroup"); + LLUUID group_id = gAgent.getGroupID(); + if (AlchemyRezUnderLandGroup) { - LLParcel *parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); - if (gAgent.isInGroup(parcel->getGroupID())) - { - group_id = parcel->getGroupID(); - } - else if (gAgent.isInGroup(parcel->getOwnerID())) - { - group_id = parcel->getOwnerID(); - } + LLParcel* land_parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + // Is the agent in the land group + if (gAgent.isInGroup(land_parcel->getGroupID())) + group_id = land_parcel->getGroupID(); + // Is the agent in the land group (the group owns the land) + else if(gAgent.isInGroup(land_parcel->getOwnerID())) + group_id = land_parcel->getOwnerID(); } - packAgentAndSessionAndGroupID(&group_id); LLDuplicateData* dup_data = (LLDuplicateData*) data; @@ -4726,7 +5003,6 @@ void LLSelectMgr::packObjectName(LLSelectNode* node, void* user_data) gMessageSystem->addU32Fast(_PREHASH_LocalID, node->getObject()->getLocalID()); gMessageSystem->addStringFast(_PREHASH_Name, *name); } - delete name; } // static @@ -4790,10 +5066,12 @@ void LLSelectMgr::packPermissions(LLSelectNode* node, void *user_data) void LLSelectMgr::sendListToRegions(const std::string& message_name, void (*pack_header)(void *user_data), void (*pack_body)(LLSelectNode* node, void *user_data), + void (*log_func)(LLSelectNode* node, void *user_data), void *user_data, ESendType send_type) { LLSelectNode* node; + LLSelectNode* linkset_root = NULL; LLViewerRegion* last_region; LLViewerRegion* current_region; @@ -4801,10 +5079,12 @@ void LLSelectMgr::sendListToRegions(const std::string& message_name, S32 packets_sent = 0; S32 objects_in_this_packet = 0; + bool link_operation = message_name == "ObjectLink"; + //clear update override data (allow next update through) struct f : public LLSelectedNodeFunctor { - virtual bool apply(LLSelectNode* node) + bool apply(LLSelectNode* node) override { node->mLastPositionLocal.setVec(0,0,0); node->mLastRotation = LLQuaternion(); @@ -4820,7 +5100,8 @@ void LLSelectMgr::sendListToRegions(const std::string& message_name, { std::queue& nodes_to_send; push_all(std::queue& n) : nodes_to_send(n) {} - virtual bool apply(LLSelectNode* node) + + bool apply(LLSelectNode* node) override { if (node->getObject()) { @@ -4834,7 +5115,8 @@ void LLSelectMgr::sendListToRegions(const std::string& message_name, std::queue& nodes_to_send; bool mRoots; push_some(std::queue& n, bool roots) : nodes_to_send(n), mRoots(roots) {} - virtual bool apply(LLSelectNode* node) + + bool apply(LLSelectNode* node) override { if (node->getObject()) { @@ -4877,7 +5159,7 @@ void LLSelectMgr::sendListToRegions(const std::string& message_name, break; default: - llerrs << "Bad send type " << send_type << " passed to SendListToRegions()" << llendl; + LL_ERRS() << "Bad send type " << send_type << " passed to SendListToRegions()" << LL_ENDL; } // bail if nothing selected @@ -4909,8 +5191,16 @@ void LLSelectMgr::sendListToRegions(const std::string& message_name, && (! gMessageSystem->isSendFull(NULL)) && (objects_in_this_packet < MAX_OBJECTS_PER_PACKET)) { + if (link_operation && linkset_root == NULL) + { + // linksets over 254 will be split into multiple messages, + // but we need to provide same root for all messages or we will get separate linksets + linkset_root = node; + } // add another instance of the body of the data (*pack_body)(node, user_data); + // do any related logging + (*log_func)(node, user_data); ++objects_sent; ++objects_in_this_packet; @@ -4935,6 +5225,22 @@ void LLSelectMgr::sendListToRegions(const std::string& message_name, gMessageSystem->newMessage(message_name.c_str()); (*pack_header)(user_data); + if (linkset_root != NULL) + { + if (current_region != last_region) + { + // root should be in one region with the child, reset it + linkset_root = NULL; + } + else + { + // add root instance into new message + (*pack_body)(linkset_root, user_data); + ++objects_sent; + ++objects_in_this_packet; + } + } + // don't move to the next object, we still need to add the // body data. } @@ -4951,7 +5257,7 @@ void LLSelectMgr::sendListToRegions(const std::string& message_name, gMessageSystem->clearMessage(); } - // llinfos << "sendListToRegions " << message_name << " obj " << objects_sent << " pkt " << packets_sent << llendl; + // LL_INFOS() << "sendListToRegions " << message_name << " obj " << objects_sent << " pkt " << packets_sent << LL_ENDL; } @@ -5059,7 +5365,8 @@ void LLSelectMgr::processObjectProperties(LLMessageSystem* msg, void** user_data { LLUUID mID; f(const LLUUID& id) : mID(id) {} - virtual bool apply(LLSelectNode* node) + + bool apply(LLSelectNode* node) override { return (node->getObject() && node->getObject()->mID == mID); } @@ -5068,13 +5375,15 @@ void LLSelectMgr::processObjectProperties(LLMessageSystem* msg, void** user_data if (!node) { - llwarns << "Couldn't find object " << id << " selected." << llendl; + LL_WARNS() << "Couldn't find object " << id << " selected." << LL_ENDL; } else { if (node->mInventorySerial != inv_serial) { - node->getObject()->dirtyInventory(); + if (LLViewerObject* object = node->getObject()) + if (object->getInventorySerial() != inv_serial) // Singu Note: the serial number in the object may be correct. + object->dirtyInventory(); } // save texture data as soon as we get texture perms first time @@ -5136,18 +5445,12 @@ void LLSelectMgr::processObjectProperties(LLMessageSystem* msg, void** user_data node->mInventorySerial = inv_serial; node->mSitName.assign(sit_name); node->mTouchName.assign(touch_name); + if (auto obj = node->getObject()) obj->mOwnerID = owner_id; // Singu Note: Try to get Owner whenever possible } } dialog_refresh_all(); - // silly hack to allow 'save into inventory' - if(gPopupMenuView->getVisible()) - { - gPopupMenuView->setItemEnabled(SAVE_INTO_INVENTORY, - enable_save_into_inventory(NULL)); - } - // hack for left-click buy object LLToolPie::selectionPropertiesReceived(); } @@ -5210,7 +5513,8 @@ void LLSelectMgr::processObjectPropertiesFamily(LLMessageSystem* msg, void** use { LLUUID mID; f(const LLUUID& id) : mID(id) {} - virtual bool apply(LLSelectNode* node) + + bool apply(LLSelectNode* node) override { return (node->getObject() && node->getObject()->mID == mID); } @@ -5279,7 +5583,7 @@ void LLSelectMgr::updateSilhouettes() if (!mSilhouetteImagep) { - mSilhouetteImagep = LLViewerTextureManager::getFetchedTextureFromFile("silhouette.j2c", TRUE, LLGLTexture::BOOST_UI); + mSilhouetteImagep = LLViewerTextureManager::getFetchedTextureFromFile("silhouette.j2c", FTT_LOCAL_FILE, TRUE, LLGLTexture::BOOST_UI); } mHighlightedObjects->cleanupNodes(); @@ -5288,7 +5592,7 @@ void LLSelectMgr::updateSilhouettes() { struct f : public LLSelectedObjectFunctor { - virtual bool apply(LLViewerObject* object) + bool apply(LLViewerObject* object) override { object->setChanged(LLXform::SILHOUETTE); return true; @@ -5554,7 +5858,7 @@ void LLSelectMgr::renderSilhouettes(BOOL for_hud) gGL.getTexUnit(0)->bind(mSilhouetteImagep); LLGLSPipelineSelection gls_select; - LLGLEnable blend(GL_BLEND); + LLGLEnable blend; LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE); if (isAgentAvatarValid() && for_hud) @@ -5582,16 +5886,14 @@ void LLSelectMgr::renderSilhouettes(BOOL for_hud) if (mSelectedObjects->getNumNodes()) { LLUUID inspect_item_id= LLUUID::null; - LLFloaterInspect* inspect_instance = LLFloaterInspect::instanceExists() ? LLFloaterInspect::getInstance() : NULL; + LLFloaterInspect* inspect_instance = LLFloaterInspect::findInstance(); if(inspect_instance && inspect_instance->getVisible()) { inspect_item_id = inspect_instance->getSelectedUUID(); } LLUUID focus_item_id = LLViewerMediaFocus::getInstance()->getFocusedObjectID(); - // //for (S32 pass = 0; pass < 2; pass++) - // { for (LLObjectSelection::iterator iter = mSelectedObjects->begin(); iter != mSelectedObjects->end(); iter++) @@ -5708,6 +6010,7 @@ LLSelectNode::LLSelectNode(LLViewerObject* object, BOOL glow) { selectAllTEs(FALSE); saveColors(); + saveShinyColors(); } LLSelectNode::LLSelectNode(const LLSelectNode& nodep) @@ -5753,6 +6056,11 @@ LLSelectNode::LLSelectNode(const LLSelectNode& nodep) { mSavedColors.push_back(*color_iter); } + mSavedShinyColors.clear(); + for (color_iter = nodep.mSavedShinyColors.begin(); color_iter != nodep.mSavedShinyColors.end(); ++color_iter) + { + mSavedShinyColors.push_back(*color_iter); + } saveTextures(nodep.mSavedTextures); } @@ -5805,6 +6113,11 @@ S32 LLSelectNode::getLastSelectedTE() return mLastTESelected; } +S32 LLSelectNode::getLastOperatedTE() +{ + return mLastTESelected; +} + LLViewerObject* LLSelectNode::getObject() { if (!mObject) @@ -5836,6 +6149,26 @@ void LLSelectNode::saveColors() } } +void LLSelectNode::saveShinyColors() +{ + if (mObject.notNull()) + { + mSavedShinyColors.clear(); + for (S32 i = 0; i < mObject->getNumTEs(); i++) + { + const LLMaterialPtr mat = mObject->getTE(i)->getMaterialParams(); + if (!mat.isNull()) + { + mSavedShinyColors.push_back(LLColor4(mat->getSpecularLightColor())); + } + else + { + mSavedShinyColors.push_back(LLColor4::white); + } + } + } +} + void LLSelectNode::saveTextures(const uuid_vec_t& textures) { if (mObject.notNull()) @@ -5850,36 +6183,42 @@ void LLSelectNode::saveTextures(const uuid_vec_t& textures) } } -void LLSelectNode::saveTextureScaleRatios() +void LLSelectNode::saveTextureScaleRatios(LLRender::eTexIndex index_to_query) { mTextureScaleRatios.clear(); + if (mObject.notNull()) { + LLVector3 scale = mObject->getScale(); + for (U8 i = 0; i < mObject->getNumTEs(); i++) { - F32 s,t; + F32 diffuse_s = 1.0f; + F32 diffuse_t = 1.0f; + + LLVector3 v; const LLTextureEntry* tep = mObject->getTE(i); - tep->getScale(&s,&t); - U32 s_axis = 0; - U32 t_axis = 0; + if (!tep) + continue; + U32 s_axis = VX; + U32 t_axis = VY; LLPrimitive::getTESTAxes(i, &s_axis, &t_axis); - LLVector3 v; - LLVector3 scale = mObject->getScale(); + tep->getScale(&diffuse_s,&diffuse_t); if (tep->getTexGen() == LLTextureEntry::TEX_GEN_PLANAR) { - v.mV[s_axis] = s*scale.mV[s_axis]; - v.mV[t_axis] = t*scale.mV[t_axis]; + v.mV[s_axis] = diffuse_s*scale.mV[s_axis]; + v.mV[t_axis] = diffuse_t*scale.mV[t_axis]; + mTextureScaleRatios.push_back(v); } else { - v.mV[s_axis] = s/scale.mV[s_axis]; - v.mV[t_axis] = t/scale.mV[t_axis]; + v.mV[s_axis] = diffuse_s/scale.mV[s_axis]; + v.mV[t_axis] = diffuse_t/scale.mV[t_axis]; + mTextureScaleRatios.push_back(v); } - - mTextureScaleRatios.push_back(v); } } } @@ -5986,7 +6325,7 @@ void pushWireframe(LLDrawable* drawable) { LLVertexBuffer::unbind(); gGL.pushMatrix(); - gGL.multMatrix((F32*) vobj->getRelativeXform().mMatrix); + gGL.multMatrix(vobj->getRelativeXform()); LLVolume* volume = NULL; @@ -6005,7 +6344,7 @@ void pushWireframe(LLDrawable* drawable) for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i) { const LLVolumeFace& face = volume->getVolumeFace(i); - LLVertexBuffer::drawElements(LLRender::TRIANGLES, face.mPositions, NULL, face.mNumIndices, face.mIndices); + LLVertexBuffer::drawElements(LLRender::TRIANGLES, face.mNumVertices, face.mPositions, NULL, face.mNumIndices, face.mIndices); } } @@ -6043,7 +6382,7 @@ void LLSelectNode::renderOneWireframe(const LLColor4& color) if (drawable->isActive()) { gGL.loadMatrix(gGLModelView); - gGL.multMatrix((F32*) objectp->getRenderMatrix().mMatrix); + gGL.multMatrix(objectp->getRenderMatrix()); } else if (!is_hud_object) { @@ -6053,14 +6392,13 @@ void LLSelectNode::renderOneWireframe(const LLColor4& color) gGL.translatef(trans.mV[0], trans.mV[1], trans.mV[2]); } - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + gGL.setPolygonMode(LLRender::PF_FRONT_AND_BACK, LLRender::PM_LINE); //Singu Note: Diverges from v3. If sRenderHiddenSelections set, draw non-z-culled wireframe, else draw occluded 'thick' wireframe to create an outline. if (LLSelectMgr::sRenderHiddenSelections) // && gFloaterTools && gFloaterTools->getVisible()) { gGL.blendFunc(LLRender::BF_SOURCE_COLOR, LLRender::BF_ONE); LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE, GL_GEQUAL); - if (shader) { gGL.diffuseColor4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], 0.4f); @@ -6068,13 +6406,16 @@ void LLSelectNode::renderOneWireframe(const LLColor4& color) } else { - LLGLEnable fog(GL_FOG); - glFogi(GL_FOG_MODE, GL_LINEAR); - float d = (LLViewerCamera::getInstance()->getPointOfInterest()-LLViewerCamera::getInstance()->getOrigin()).magVec(); - LLColor4 fogCol = color * (F32)llclamp((LLSelectMgr::getInstance()->getSelectionCenterGlobal()-gAgentCamera.getCameraPositionGlobal()).magVec()/(LLSelectMgr::getInstance()->getBBoxOfSelection().getExtentLocal().magVec()*4), 0.0, 1.0); - glFogf(GL_FOG_START, d); - glFogf(GL_FOG_END, d*(1 + (LLViewerCamera::getInstance()->getView() / LLViewerCamera::getInstance()->getDefaultFOV()))); - glFogfv(GL_FOG_COLOR, fogCol.mV); + if (!LLGLSLShader::sNoFixedFunction) + { + LLGLEnable fog; + glFogi(GL_FOG_MODE, GL_LINEAR); + float d = (LLViewerCamera::getInstance()->getPointOfInterest() - LLViewerCamera::getInstance()->getOrigin()).magVec(); + LLColor4 fogCol = color * (F32)llclamp((LLSelectMgr::getInstance()->getSelectionCenterGlobal() - gAgentCamera.getCameraPositionGlobal()).magVec() / (LLSelectMgr::getInstance()->getBBoxOfSelection().getExtentLocal().magVec() * 4), 0.0, 1.0); + glFogf(GL_FOG_START, d); + glFogf(GL_FOG_END, d*(1 + (LLViewerCamera::getInstance()->getView() / LLViewerCamera::getInstance()->getDefaultFOV()))); + glFogfv(GL_FOG_COLOR, fogCol.mV); + } gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); { @@ -6086,18 +6427,19 @@ void LLSelectNode::renderOneWireframe(const LLColor4& color) } else { - LLGLEnable cull_face(GL_CULL_FACE); - LLGLEnable offset(GL_POLYGON_OFFSET_LINE); + LLGLEnable cull_face; + LLGLEnable offset; gGL.setSceneBlendType(LLRender::BT_ALPHA); + gGL.diffuseColor4f(color.mV[VRED]*2, color.mV[VGREEN]*2, color.mV[VBLUE]*2, LLSelectMgr::sHighlightAlpha*2); - glPolygonOffset(3.f, 3.f); - glLineWidth(3.f); + gGL.setPolygonOffset(3.f, 3.f); + gGL.setLineWidth(3.f); pushWireframe(drawable); - glLineWidth(1.f); + gGL.setLineWidth(1.f); } - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + gGL.setPolygonMode(LLRender::PF_FRONT_AND_BACK, LLRender::PM_FILL); gGL.popMatrix(); if (shader) @@ -6164,7 +6506,7 @@ void LLSelectNode::renderOneSilhouette(const LLColor4 &color) if (drawable->isActive()) { - gGL.multMatrix((F32*) objectp->getRenderMatrix().mMatrix); + gGL.multMatrix(objectp->getRenderMatrix()); } LLVolume *volume = objectp->getVolume(); @@ -6190,22 +6532,26 @@ void LLSelectNode::renderOneSilhouette(const LLColor4 &color) { gGL.flush(); gGL.blendFunc(LLRender::BF_SOURCE_COLOR, LLRender::BF_ONE); - LLGLEnable fog(GL_FOG); - glFogi(GL_FOG_MODE, GL_LINEAR); - float d = (LLViewerCamera::getInstance()->getPointOfInterest()-LLViewerCamera::getInstance()->getOrigin()).magVec(); - LLColor4 fogCol = color * (F32)llclamp((LLSelectMgr::getInstance()->getSelectionCenterGlobal()-gAgentCamera.getCameraPositionGlobal()).magVec()/(LLSelectMgr::getInstance()->getBBoxOfSelection().getExtentLocal().magVec()*4), 0.0, 1.0); - glFogf(GL_FOG_START, d); - glFogf(GL_FOG_END, d*(1 + (LLViewerCamera::getInstance()->getView() / LLViewerCamera::getInstance()->getDefaultFOV()))); - glFogfv(GL_FOG_COLOR, fogCol.mV); + if (!LLGLSLShader::sNoFixedFunction) + { + LLGLEnable fog; + glFogi(GL_FOG_MODE, GL_LINEAR); + float d = (LLViewerCamera::getInstance()->getPointOfInterest() - LLViewerCamera::getInstance()->getOrigin()).magVec(); + LLColor4 fogCol = color * (F32)llclamp((LLSelectMgr::getInstance()->getSelectionCenterGlobal() - gAgentCamera.getCameraPositionGlobal()).magVec() / (LLSelectMgr::getInstance()->getBBoxOfSelection().getExtentLocal().magVec() * 4), 0.0, 1.0); + glFogf(GL_FOG_START, d); + glFogf(GL_FOG_END, d*(1 + (LLViewerCamera::getInstance()->getView() / LLViewerCamera::getInstance()->getDefaultFOV()))); + glFogfv(GL_FOG_COLOR, fogCol.mV); + } LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE, GL_GEQUAL); gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); gGL.begin(LLRender::LINES); { + gGL.color4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], 0.4f); + for(S32 i = 0; i < (S32)mSilhouetteVertices.size(); i += 2) { u_coord += u_divisor * LLSelectMgr::sHighlightUScale; - gGL.color4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], 0.4f); gGL.texCoord2f( u_coord, v_coord ); gGL.vertex3fv( mSilhouetteVertices[i].mV); u_coord += u_divisor * LLSelectMgr::sHighlightUScale; @@ -6292,11 +6638,6 @@ void dialog_refresh_all() // and call into this function. Yuck. LLSelectMgr::getInstance()->mUpdateSignal(); - if (gNoRender) - { - return; - } - // *TODO: Eliminate all calls into outside classes below, make those // objects register with the update signal. @@ -6314,7 +6655,7 @@ void dialog_refresh_all() LLFloaterProperties::dirtyAll(); - LLFloaterInspect* inspect_instance = LLFloaterInspect::instanceExists() ? LLFloaterInspect::getInstance() : NULL; + LLFloaterInspect* inspect_instance = LLFloaterInspect::findInstance(); if(inspect_instance) { inspect_instance->dirty(); @@ -6325,7 +6666,7 @@ S32 get_family_count(LLViewerObject *parent) { if (!parent) { - llwarns << "Trying to get_family_count on null parent!" << llendl; + LL_WARNS() << "Trying to get_family_count on null parent!" << LL_ENDL; } S32 count = 1; // for this object LLViewerObject::const_child_list_t& child_list = parent->getChildren(); @@ -6336,11 +6677,11 @@ S32 get_family_count(LLViewerObject *parent) if (!child) { - llwarns << "Family object has NULL child! Show Doug." << llendl; + LL_WARNS() << "Family object has NULL child! Show Doug." << LL_ENDL; } else if (child->isDead()) { - llwarns << "Family object has dead child object. Show Doug." << llendl; + LL_WARNS() << "Family object has dead child object. Show Doug." << LL_ENDL; } else { @@ -6373,7 +6714,6 @@ void LLSelectMgr::updateSelectionCenter() mSelectionCenterGlobal.clearVec(); mShowSelection = FALSE; mSelectionBBox = LLBBox(); - mPauseRequest = NULL; resetAgentHUDZoom(); } @@ -6381,14 +6721,7 @@ void LLSelectMgr::updateSelectionCenter() { mSelectedObjects->mSelectType = getSelectTypeForObject(object); - if (mSelectedObjects->mSelectType == SELECT_TYPE_ATTACHMENT && isAgentAvatarValid()) - { - mPauseRequest = gAgentAvatarp->requestPause(); - } - else - { - mPauseRequest = NULL; - } + if (mSelectedObjects->mSelectType != SELECT_TYPE_HUD && isAgentAvatarValid()) { @@ -6430,6 +6763,7 @@ void LLSelectMgr::updateSelectionCenter() LLVector3 bbox_center_agent = bbox.getCenterAgent(); mSelectionCenterGlobal = gAgent.getPosGlobalFromAgent(bbox_center_agent); mSelectionBBox = bbox; + } if ( !(gAgentID == LLUUID::null)) @@ -6465,6 +6799,67 @@ void LLSelectMgr::updateSelectionCenter() { gEditMenuHandler = NULL; } + + pauseAssociatedAvatars(); +} + +//----------------------------------------------------------------------------- +// pauseAssociatedAvatars +// +// If the selection includes an attachment or an animated object, the +// associated avatars should pause their animations until they are no +// longer selected. +//----------------------------------------------------------------------------- +void LLSelectMgr::pauseAssociatedAvatars() +{ + mPauseRequests.clear(); + + for (LLObjectSelection::iterator iter = mSelectedObjects->begin(); + iter != mSelectedObjects->end(); iter++) + { + LLSelectNode* node = *iter; + LLViewerObject* object = node->getObject(); + if (!object) + continue; + + mSelectedObjects->mSelectType = getSelectTypeForObject(object); + + if (mSelectedObjects->mSelectType == SELECT_TYPE_ATTACHMENT && + isAgentAvatarValid() && object->getParent() != NULL) + { + if (object->isAnimatedObject()) + { + // Is an animated object attachment. + // Pause both the control avatar and the avatar it's attached to. + if (object->getControlAvatar()) + { + object->getControlAvatar()->pauseAllSyncedCharacters(mPauseRequests); + } + LLVOAvatar* avatar = object->getAvatar(); + if (avatar) + { + avatar->pauseAllSyncedCharacters(mPauseRequests); + } + } + else + { + // Is a regular attachment. Pause the avatar it's attached to. + LLVOAvatar* avatar = object->getAvatar(); + if (avatar) + { + avatar->pauseAllSyncedCharacters(mPauseRequests); + } + } + } + else + { + if (object && object->isAnimatedObject() && object->getControlAvatar()) + { + // Is a non-attached animated object. Pause the control avatar. + object->getControlAvatar()->pauseAllSyncedCharacters(mPauseRequests); + } + } + } } void LLSelectMgr::updatePointAt() @@ -6529,7 +6924,7 @@ void LLSelectMgr::undo() { BOOL select_linked_set = !gSavedSettings.getBOOL("EditLinkedParts"); LLUUID group_id(gAgent.getGroupID()); - sendListToRegions("Undo", packAgentAndSessionAndGroupID, packObjectID, &group_id, select_linked_set ? SEND_ONLY_ROOTS : SEND_CHILDREN_FIRST); + sendListToRegions("Undo", packAgentAndSessionAndGroupID, packObjectID, logNoOp, &group_id, select_linked_set ? SEND_ONLY_ROOTS : SEND_CHILDREN_FIRST); } //----------------------------------------------------------------------------- @@ -6547,7 +6942,7 @@ void LLSelectMgr::redo() { BOOL select_linked_set = !gSavedSettings.getBOOL("EditLinkedParts"); LLUUID group_id(gAgent.getGroupID()); - sendListToRegions("Redo", packAgentAndSessionAndGroupID, packObjectID, &group_id, select_linked_set ? SEND_ONLY_ROOTS : SEND_CHILDREN_FIRST); + sendListToRegions("Redo", packAgentAndSessionAndGroupID, packObjectID, logNoOp, &group_id, select_linked_set ? SEND_ONLY_ROOTS : SEND_CHILDREN_FIRST); } //----------------------------------------------------------------------------- @@ -6584,6 +6979,24 @@ void LLSelectMgr::doDelete() selectDelete(); } +// Note: Allow Ctrl-A for select all linked prims +//----------------------------------------------------------------------------- +// canSelectAll() +//----------------------------------------------------------------------------- +BOOL LLSelectMgr::canSelectAll() const +{ + return !mSelectedObjects->isEmpty(); +} + +//----------------------------------------------------------------------------- +// selectAll() +//----------------------------------------------------------------------------- +void LLSelectMgr::selectAll() +{ + promoteSelectionToRoot(); +} +// + //----------------------------------------------------------------------------- // canDeselect() //----------------------------------------------------------------------------- @@ -6644,7 +7057,7 @@ void LLSelectMgr::validateSelection() { struct f : public LLSelectedObjectFunctor { - virtual bool apply(LLViewerObject* object) + bool apply(LLViewerObject* object) override { if (!LLSelectMgr::getInstance()->canSelectObject(object)) { @@ -6656,7 +7069,7 @@ void LLSelectMgr::validateSelection() getSelection()->applyToObjects(&func); } -BOOL LLSelectMgr::canSelectObject(LLViewerObject* object) +BOOL LLSelectMgr::canSelectObject(LLViewerObject* object, BOOL ignore_select_owned) { // Never select dead objects if (!object || object->isDead()) @@ -6669,11 +7082,14 @@ BOOL LLSelectMgr::canSelectObject(LLViewerObject* object) return TRUE; } - if ((gSavedSettings.getBOOL("SelectOwnedOnly") && !object->permYouOwner()) || - (gSavedSettings.getBOOL("SelectMovableOnly") && (!object->permMove() || object->isPermanentEnforced()))) + if(!ignore_select_owned) { - // only select my own objects - return FALSE; + if ((gSavedSettings.getBOOL("SelectOwnedOnly") && !object->permYouOwner()) || + (gSavedSettings.getBOOL("SelectMovableOnly") && (!object->permMove() || object->isPermanentEnforced()))) + { + // only select my own objects + return FALSE; + } } // Can't select orphans @@ -6872,7 +7288,7 @@ F32 LLObjectSelection::getSelectedLinksetCost() LLSelectNode* node = *iter; LLViewerObject* object = node->getObject(); - if (object) + if (object && !object->isAttachment()) { LLViewerObject* root = static_cast(object->getRoot()); if (root) @@ -6947,10 +7363,16 @@ F32 LLObjectSelection::getSelectedObjectStreamingCost(S32* total_bytes, S32* vis if (object) { + cost += object->getStreamingCost(); + S32 bytes = 0; S32 visible = 0; - cost += object->getStreamingCost(&bytes, &visible); - + LLMeshCostData costs; + if (object->getCostData(costs)) + { + bytes = costs.getSizeTotal(); + visible = costs.getSizeByLOD(object->getLOD()); + } if (total_bytes) { *total_bytes += bytes; @@ -6976,7 +7398,9 @@ U32 LLObjectSelection::getSelectedObjectTriangleCount(S32* vcount) if (object) { - count += object->getTriangleCount(vcount); + S32 vt = 0; + count += object->getTriangleCount(&vt); + *vcount += vt; } } @@ -6987,8 +7411,7 @@ S32 LLObjectSelection::getSelectedObjectRenderCost() { S32 cost = 0; LLVOVolume::texture_cost_t textures; - typedef std::set uuid_list_t; - uuid_list_t computed_objects; + uuid_set_t computed_objects; typedef std::list > child_list_t; typedef const child_list_t const_child_list_t; @@ -7011,7 +7434,7 @@ S32 LLObjectSelection::getSelectedObjectRenderCost() ++child_iter) { LLViewerObject* child_obj = *child_iter; - LLVOVolume *child = dynamic_cast( child_obj ); + LLVOVolume *child = child_obj ? child_obj->asVolume() : nullptr; if (child) { cost += child->getRenderCost(textures); @@ -7105,6 +7528,31 @@ bool LLObjectSelection::applyToObjects(LLSelectedObjectFunctor* func) return result; } +bool LLObjectSelection::checkAnimatedObjectEstTris() +{ + F32 est_tris = 0; + F32 max_tris = 0; + S32 anim_count = 0; + for (root_iterator iter = root_begin(); iter != root_end(); ++iter) + { + LLViewerObject* object = (*iter)->getObject(); + if (!object) + continue; + if (object->isAnimatedObject()) + { + anim_count++; + } + est_tris += object->recursiveGetEstTrianglesMax(); + max_tris = llmax((F32)max_tris,(F32)object->getAnimatedObjectMaxTris()); + } + return anim_count==0 || est_tris <= max_tris; +} + +bool LLObjectSelection::checkAnimatedObjectLinkable() +{ + return checkAnimatedObjectEstTris(); +} + bool LLObjectSelection::applyToRootObjects(LLSelectedObjectFunctor* func, bool firstonly) { bool result = firstonly ? false : true; @@ -7361,7 +7809,7 @@ LLSelectNode* LLObjectSelection::getFirstMoveableNode(BOOL get_root_first) { struct f : public LLSelectedNodeFunctor { - bool apply(LLSelectNode* node) + bool apply(LLSelectNode* node) override { LLViewerObject* obj = node->getObject(); return obj && obj->permMove() && !obj->isPermanentEnforced(); @@ -7378,7 +7826,7 @@ LLViewerObject* LLObjectSelection::getFirstCopyableObject(BOOL get_parent) { struct f : public LLSelectedNodeFunctor { - bool apply(LLSelectNode* node) + bool apply(LLSelectNode* node) override { LLViewerObject* obj = node->getObject(); return obj && obj->permCopy() && !obj->isAttachment(); @@ -7397,7 +7845,7 @@ LLViewerObject* LLObjectSelection::getFirstDeleteableObject() struct f : public LLSelectedNodeFunctor { - bool apply(LLSelectNode* node) + bool apply(LLSelectNode* node) override { LLViewerObject* obj = node->getObject(); // you can delete an object if you are the owner @@ -7426,7 +7874,7 @@ LLViewerObject* LLObjectSelection::getFirstEditableObject(BOOL get_parent) { struct f : public LLSelectedNodeFunctor { - bool apply(LLSelectNode* node) + bool apply(LLSelectNode* node) override { LLViewerObject* obj = node->getObject(); return obj && obj->permModify(); @@ -7442,7 +7890,7 @@ LLViewerObject* LLObjectSelection::getFirstMoveableObject(BOOL get_parent) { struct f : public LLSelectedNodeFunctor { - bool apply(LLSelectNode* node) + bool apply(LLSelectNode* node) override { LLViewerObject* obj = node->getObject(); return obj && obj->permMove() && !obj->isPermanentEnforced(); diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h index 22175932f3..5252c5a179 100644 --- a/indra/newview/llselectmgr.h +++ b/indra/newview/llselectmgr.h @@ -49,6 +49,7 @@ #include "llpermissions.h" #include "llcontrol.h" #include "llviewerobject.h" // LLObjectSelection::getSelectedTEValue template +#include "llmaterial.h" #include #include @@ -89,6 +90,12 @@ struct LLSelectedTEFunctor virtual bool apply(LLViewerObject* object, S32 face) = 0; }; +struct LLSelectedTEMaterialFunctor +{ + virtual ~LLSelectedTEMaterialFunctor() {}; + virtual LLMaterialPtr apply(LLViewerObject* object, S32 face, LLTextureEntry* tep, LLMaterialPtr& current_material) = 0; +}; + template struct LLSelectedTEGetFunctor { virtual ~LLSelectedTEGetFunctor() {}; @@ -139,6 +146,7 @@ class LLSelectNode void selectTE(S32 te_index, BOOL selected); BOOL isTESelected(S32 te_index); S32 getLastSelectedTE(); + S32 getLastOperatedTE(); S32 getTESelectMask() { return mTESelectMask; } void renderOneWireframe(const LLColor4& color); void renderOneSilhouette(const LLColor4 &color); @@ -148,8 +156,9 @@ class LLSelectNode void setObject(LLViewerObject* object); // *NOTE: invalidate stored textures and colors when # faces change void saveColors(); + void saveShinyColors(); void saveTextures(const uuid_vec_t& textures); - void saveTextureScaleRatios(); + void saveTextureScaleRatios(LLRender::eTexIndex index_to_query); BOOL allowOperationOnNode(PermissionBit op, U64 group_proxy_power) const; @@ -184,6 +193,7 @@ class LLSelectNode std::string mSitName; U64 mCreationDate; std::vector mSavedColors; + std::vector mSavedShinyColors; uuid_vec_t mSavedTextures; std::vector mTextureScaleRatios; std::vector mSilhouetteVertices; // array of vertices to render silhouette of object @@ -199,6 +209,7 @@ class LLSelectNode class LLObjectSelection : public LLRefCount { friend class LLSelectMgr; + friend class LLSafeHandle; protected: ~LLObjectSelection(); @@ -211,7 +222,7 @@ class LLObjectSelection : public LLRefCount { bool operator()(LLSelectNode* node) { - return (node->getObject() != NULL); + return (node->getObject() != nullptr); } }; typedef boost::filter_iterator iterator; @@ -222,7 +233,7 @@ class LLObjectSelection : public LLRefCount { bool operator()(LLSelectNode* node) { - return (node->getObject() != NULL) && node->mValid; + return (node->getObject() != nullptr) && node->mValid; } }; typedef boost::filter_iterator valid_iterator; @@ -260,8 +271,8 @@ class LLObjectSelection : public LLRefCount BOOL isEmpty() const; - LLSelectNode* getFirstNode(LLSelectedNodeFunctor* func = NULL); - LLSelectNode* getFirstRootNode(LLSelectedNodeFunctor* func = NULL, BOOL non_root_ok = FALSE); + LLSelectNode* getFirstNode(LLSelectedNodeFunctor* func = nullptr); + LLSelectNode* getFirstRootNode(LLSelectedNodeFunctor* func = nullptr, BOOL non_root_ok = FALSE); LLViewerObject* getFirstSelectedObject(LLSelectedNodeFunctor* func, BOOL get_parent = FALSE); LLViewerObject* getFirstObject(); LLViewerObject* getFirstRootObject(BOOL non_root_ok = FALSE); @@ -272,6 +283,8 @@ class LLObjectSelection : public LLRefCount LLViewerObject* getFirstCopyableObject(BOOL get_parent = FALSE); LLViewerObject* getFirstDeleteableObject(); LLViewerObject* getFirstMoveableObject(BOOL get_parent = FALSE); + + /// Return the object that lead to this selection, possible a child LLViewerObject* getPrimaryObject() { return mPrimaryObject; } // iterate through texture entries @@ -289,8 +302,8 @@ class LLObjectSelection : public LLRefCount F32 getSelectedLinksetPhysicsCost(); S32 getSelectedObjectRenderCost(); - F32 getSelectedObjectStreamingCost(S32* total_bytes = NULL, S32* visible_bytes = NULL); - U32 getSelectedObjectTriangleCount(S32* vcount = NULL); + F32 getSelectedObjectStreamingCost(S32* total_bytes = nullptr, S32* visible_bytes = nullptr); + U32 getSelectedObjectTriangleCount(S32* vcount = nullptr); S32 getTECount(); S32 getRootObjectCount(); @@ -302,6 +315,9 @@ class LLObjectSelection : public LLRefCount // returns TRUE is any node is currenly worn as an attachment BOOL isAttachment(); + bool checkAnimatedObjectEstTris(); + bool checkAnimatedObjectLinkable(); + // Apply functors to various subsets of the selected objects // If firstonly is FALSE, returns the AND of all apply() calls. // Else returns TRUE immediately if any apply() call succeeds (i.e. OR with early exit) @@ -311,6 +327,15 @@ class LLObjectSelection : public LLRefCount bool applyToRootNodes(LLSelectedNodeFunctor* func, bool firstonly = false); bool applyToNodes(LLSelectedNodeFunctor* func, bool firstonly = false); + /* + * Used to apply (no-copy) textures to the selected object or + * selected face/faces of the object. + * This method moves (no-copy) texture to the object's inventory + * and doesn't make copy of the texture for each face. + * Then this only texture is used for all selected faces. + */ + void applyNoCopyTextureToTEs(LLViewerInventoryItem* item); + ESelectType getSelectType() const { return mSelectType; } private: @@ -321,10 +346,8 @@ class LLObjectSelection : public LLRefCount void deleteAllNodes(); void cleanupNodes(); - -private: list_t mList; - const LLObjectSelection &operator=(const LLObjectSelection &); + const LLObjectSelection& operator=(const LLObjectSelection&) = delete; LLPointer mPrimaryObject; std::map, LLSelectNode*> mSelectNodeMap; @@ -338,12 +361,16 @@ typedef LLSafeHandle LLObjectSelectionHandle; extern template class LLSelectMgr* LLSingleton::getInstance(); #endif +// For use with getFirstTest() +struct LLSelectGetFirstTest; + class LLSelectMgr : public LLEditMenuHandler, public LLSingleton { public: static BOOL sRectSelectInclusive; // do we need to surround an object to pick it? static BOOL sRenderHiddenSelections; // do we show selection silhouettes that are occluded? static BOOL sRenderLightRadius; // do we show the radius of selected lights? + static F32 sHighlightThickness; static F32 sHighlightUScale; static F32 sHighlightVScale; @@ -370,17 +397,19 @@ class LLSelectMgr : public LLEditMenuHandler, public LLSingleton static void cleanupGlobals(); // LLEditMenuHandler interface - virtual BOOL canUndo() const; - virtual void undo(); + BOOL canUndo() const override; + void undo() override; - virtual BOOL canRedo() const; - virtual void redo(); + BOOL canRedo() const override; + void redo() override; - virtual BOOL canDoDelete() const; - virtual void doDelete(); + BOOL canDoDelete() const override; + void doDelete() override; - virtual void deselect(); - virtual BOOL canDeselect() const; + void selectAll() override; + BOOL canSelectAll() const override; + void deselect() override; + BOOL canDeselect() const override; virtual void duplicate(); virtual BOOL canDuplicate() const; @@ -406,7 +435,7 @@ class LLSelectMgr : public LLEditMenuHandler, public LLSingleton // // *NOTE: You must hold on to the object selection handle, otherwise // the objects will be automatically deselected in 1 frame. - LLObjectSelectionHandle selectObjectAndFamily(LLViewerObject* object, BOOL add_to_end = FALSE); + LLObjectSelectionHandle selectObjectAndFamily(LLViewerObject* object, BOOL add_to_end = FALSE, BOOL ignore_select_owned = FALSE); // For when you want just a child object. LLObjectSelectionHandle selectObjectOnly(LLViewerObject* object, S32 face = SELECT_ALL_TES); @@ -465,11 +494,11 @@ class LLSelectMgr : public LLEditMenuHandler, public LLSingleton //////////////////////////////////////////////////////////////// // Selection accessors //////////////////////////////////////////////////////////////// + LLObjectSelectionHandle getHoverObjects() { return mHoverObjects; } LLObjectSelectionHandle getSelection() { return mSelectedObjects; } // right now this just renders the selection with root/child colors instead of a single color LLObjectSelectionHandle getEditSelection() { convertTransient(); return mSelectedObjects; } LLObjectSelectionHandle getHighlightedObjects() { return mHighlightedObjects; } - LLObjectSelectionHandle getHoverObjects() { return mHoverObjects; } //////////////////////////////////////////////////////////////// // Grid manipulation @@ -478,7 +507,7 @@ class LLSelectMgr : public LLEditMenuHandler, public LLSingleton void clearGridObjects(); void setGridMode(EGridMode mode); EGridMode getGridMode() { return mGridMode; } - void getGrid(LLVector3& origin, LLQuaternion& rotation, LLVector3 &scale); + void getGrid(LLVector3& origin, LLQuaternion& rotation, LLVector3 &scale, bool for_snap_guides = false); BOOL getTEMode() { return mTEMode; } void setTEMode(BOOL b) { mTEMode = b; } @@ -500,8 +529,14 @@ class LLSelectMgr : public LLEditMenuHandler, public LLSingleton //////////////////////////////////////////////////////////////// void saveSelectedObjectTransform(EActionType action_type); void saveSelectedObjectColors(); + void saveSelectedShinyColors(); void saveSelectedObjectTextures(); + // Sets which texture channel to query for scale and rot of display + // and depends on UI state of LLPanelFace when editing + void setTextureChannel(LLRender::eTexIndex texIndex) { mTextureChannel = texIndex; } + LLRender::eTexIndex getTextureChannel() { return mTextureChannel; } + void selectionUpdatePhysics(BOOL use_physics); void selectionUpdateTemporary(BOOL is_temporary); void selectionUpdatePhantom(BOOL is_ghost); @@ -523,6 +558,7 @@ class LLSelectMgr : public LLEditMenuHandler, public LLSingleton void selectionSetColorOnly(const LLColor4 &color); // Set only the RGB channels void selectionSetAlphaOnly(const F32 alpha); // Set only the alpha channel void selectionRevertColors(); + void selectionRevertShinyColors(); BOOL selectionRevertTextures(); void selectionSetBumpmap( U8 bumpmap ); void selectionSetTexGen( U8 texgen ); @@ -532,6 +568,8 @@ class LLSelectMgr : public LLEditMenuHandler, public LLSingleton void selectionSetClickAction(U8 action); void selectionSetIncludeInSearch(bool include_in_search); void selectionSetGlow(const F32 glow); + void selectionSetMaterialParams(LLSelectedTEMaterialFunctor* material_func); + void selectionRemoveMaterial(); void selectionSetObjectPermissions(U8 perm_field, BOOL set, U32 perm_mask, BOOL override = FALSE); void selectionSetObjectName(const std::string& name); @@ -553,7 +591,7 @@ class LLSelectMgr : public LLEditMenuHandler, public LLSingleton void validateSelection(); // returns TRUE if it is possible to select this object - BOOL canSelectObject(LLViewerObject* object); + BOOL canSelectObject(LLViewerObject* object, BOOL ignore_select_owned = FALSE); // Returns TRUE if the viewer has information on all selected objects BOOL selectGetAllRootsValid(); @@ -564,6 +602,9 @@ class LLSelectMgr : public LLEditMenuHandler, public LLSingleton BOOL selectGetRootsModify(); BOOL selectGetModify(); + // returns TRUE if all objects are in same region + BOOL selectGetSameRegion(); + // returns TRUE if is all objects are non-permanent-enforced BOOL selectGetRootsNonPermanentEnforced(); BOOL selectGetNonPermanentEnforced(); @@ -679,6 +720,8 @@ class LLSelectMgr : public LLEditMenuHandler, public LLSingleton LLVector3d getSelectionCenterGlobal() const { return mSelectionCenterGlobal; } void updateSelectionCenter(); + void pauseAssociatedAvatars(); + void resetAgentHUDZoom(); void setAgentHUDZoom(F32 target_zoom, F32 current_zoom); void getAgentHUDZoom(F32 &target_zoom, F32 ¤t_zoom) const; @@ -703,6 +746,7 @@ class LLSelectMgr : public LLEditMenuHandler, public LLSingleton void sendListToRegions( const std::string& message_name, void (*pack_header)(void *user_data), void (*pack_body)(LLSelectNode* node, void *user_data), + void (*log_func)(LLSelectNode* node, void *user_data), void *user_data, ESendType send_type); @@ -738,6 +782,9 @@ class LLSelectMgr : public LLEditMenuHandler, public LLSingleton static void packHingeHead(void *user_data); static void packPermissionsHead(void* user_data); static void packGodlikeHead(void* user_data); + static void logNoOp(LLSelectNode* node, void *user_data); + static void logAttachmentRequest(LLSelectNode* node, void *user_data); + static void logDetachRequest(LLSelectNode* node, void *user_data); static bool confirmDelete(const LLSD& notification, const LLSD& response, LLObjectSelectionHandle handle); public: @@ -758,10 +805,9 @@ class LLSelectMgr : public LLEditMenuHandler, public LLSingleton LLVector3 mGridOrigin; LLVector3 mGridScale; EGridMode mGridMode; - BOOL mGridValid; - BOOL mTEMode; // render te + LLRender::eTexIndex mTextureChannel; // diff, norm, or spec, depending on UI editing mode LLVector3d mSelectionCenterGlobal; LLBBox mSelectionBBox; @@ -774,7 +820,7 @@ class LLSelectMgr : public LLEditMenuHandler, public LLSingleton LLFrameTimer mEffectsTimer; BOOL mForceSelection; - LLAnimPauseRequest mPauseRequest; + std::vector mPauseRequests; // Selected avatar and all synchronized avatars. friend class LLObjectBackup; }; diff --git a/indra/newview/llshareavatarhandler.cpp b/indra/newview/llshareavatarhandler.cpp new file mode 100644 index 0000000000..959556a51e --- /dev/null +++ b/indra/newview/llshareavatarhandler.cpp @@ -0,0 +1,67 @@ +/** + * @file llshareavatarhandler.cpp + * @brief slapp to handle sharing with an avatar + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llcommandhandler.h" +#include "llavataractions.h" +#include "llnotificationsutil.h" +#include "llui.h" + +class LLShareWithAvatarHandler : public LLCommandHandler +{ +public: + // requires trusted browser to trigger + LLShareWithAvatarHandler() : LLCommandHandler("sharewithavatar", UNTRUSTED_THROTTLE) + { + } + + bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web) + { + /*if (!LLUI::sSettingGroups["config"]->getBOOL("EnableAvatarShare")) + { + LLNotificationsUtil::add("NoAvatarShare", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit")); + return true; + }*/ + + //Make sure we have some parameters + if (params.size() == 0) + { + return false; + } + + //Get the ID + LLUUID id; + if (!id.set( params[0], FALSE)) + { + return false; + } + + //instigate share with this avatar + LLAvatarActions::share(id); + return true; + } +}; +LLShareWithAvatarHandler gShareWithAvatar; diff --git a/indra/newview/llskinningutil.cpp b/indra/newview/llskinningutil.cpp new file mode 100644 index 0000000000..7df3211ea2 --- /dev/null +++ b/indra/newview/llskinningutil.cpp @@ -0,0 +1,356 @@ +/** +* @file llskinningutil.cpp +* @brief Functions for mesh object skinning +* @author vir@lindenlab.com +* +* $LicenseInfo:firstyear=2015&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2015, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#include "llviewerprecompiledheaders.h" + +#include "llskinningutil.h" +#include "llvoavatar.h" +#include "llviewercontrol.h" +#include "llmeshrepository.h" + +// static +void LLSkinningUtil::initClass() +{ +} + +U32 LLSkinningUtil::getMaxJointCount() +{ + U32 result = LL_MAX_JOINTS_PER_MESH_OBJECT; + return result; +} + +U32 LLSkinningUtil::getMeshJointCount(const LLMeshSkinInfo *skin) +{ + return llmin((U32)getMaxJointCount(), (U32)skin->mJointNames.size()); +} + +void LLSkinningUtil::scrubInvalidJoints(LLVOAvatar *avatar, LLMeshSkinInfo* skin) +{ + if (skin->mInvalidJointsScrubbed) + { + return; + } + for (U32 j = 0; j < skin->mJointNames.size(); ++j) + { + // Fix invalid names to "mPelvis". Currently meshes with + // invalid names will be blocked on upload, so this is just + // needed for handling of any legacy bad data. + if (!avatar->getJoint(skin->mJointNames[j])) + { + LL_DEBUGS("Avatar") << avatar->getFullname() << " mesh rigged to invalid joint " << skin->mJointNames[j] << LL_ENDL; + LL_WARNS_ONCE("Avatar") << avatar->getFullname() << " mesh rigged to invalid joint" << skin->mJointNames[j] << LL_ENDL; + skin->mJointNames[j] = "mPelvis"; + skin->mJointNumsInitialized = false; // force update after names change. + } + } + skin->mInvalidJointsScrubbed = true; +} + +// static +void LLSkinningUtil::initSkinningMatrixPalette( + LLMatrix4a* mat, + S32 count, + const LLMeshSkinInfo* skin, + LLVOAvatar *avatar, + bool relative_to_avatar) +{ + LLVector4a pos = LLVector4a::getZero(); + if (relative_to_avatar) + { + pos.load3(avatar->getPosition().mV); + pos.mul(-1.f); + } + + initJointNums(const_cast(skin), avatar); + for (U32 j = 0; j < (U32)count; ++j) + { + LLJoint *joint = avatar->getJoint(skin->mJointNums[j]); + if (joint) + { + LLMatrix4a bind; + bind.loadu((F32*)skin->mInvBindMatrix[j].mMatrix); + LLMatrix4a world = joint->getWorldMatrix(); + world.getRow<3>().add(pos); // Append pos into world matrix. + mat[j].setMul(world, bind); + } + else + { + mat[j].loadu((F32*)skin->mInvBindMatrix[j].mMatrix); + // This shouldn't happen - in mesh upload, skinned + // rendering should be disabled unless all joints are + // valid. In other cases of skinned rendering, invalid + // joints should already have been removed during scrubInvalidJoints(). + LL_WARNS_ONCE("Avatar") << avatar->getFullname() + << " rigged to invalid joint name " << skin->mJointNames[j] + << " num " << skin->mJointNums[j] << LL_ENDL; + LL_WARNS_ONCE("Avatar") << avatar->getFullname() + << " avatar build state: isBuilt() " << avatar->isBuilt() + << " mInitFlags " << avatar->mInitFlags << LL_ENDL; + } + } +} + + +void LLSkinningUtil::checkSkinWeights(const LLVector4a* weights, U32 num_vertices, const LLMeshSkinInfo* skin) +{ +#ifndef LL_RELEASE_FOR_DOWNLOAD + const S32 max_joints = skin->mJointNames.size(); + for (U32 j=0; j=0); + llassert(i 0.0f); + } +#endif +} + +void LLSkinningUtil::scrubSkinWeights(LLVector4a* weights, U32 num_vertices, const LLMeshSkinInfo* skin) +{ + const S32 max_joints = skin->mJointNames.size(); + for (U32 j=0; j0.f); + + wght *= 1.f/scale; + } + + for (U32 k = 0; k < 4; k++) + { + F32 w = wght[k]; + + LLMatrix4a src; + src.setMul(mat[idx[k]], w); + + final_mat.add(src); + } + // SL-366 - with weight validation/cleanup code, it should no longer be + // possible to hit the bad scale case. + llassert(valid_weights); +} + +void LLSkinningUtil::initJointNums(LLMeshSkinInfo* skin, LLVOAvatar *avatar) +{ + if (!skin->mJointNumsInitialized) + { + for (U32 j = 0; j < skin->mJointNames.size(); ++j) + { + LLJoint *joint = NULL; + if (skin->mJointNums[j] == -1) + { + joint = avatar->getJoint(skin->mJointNames[j]); + if (joint) + { + skin->mJointNums[j] = joint->getJointNum(); + if (skin->mJointNums[j] < 0) + { + LL_WARNS_ONCE("Avatar") << avatar->getFullname() << " joint has unusual number " << skin->mJointNames[j] << ": " << skin->mJointNums[j] << LL_ENDL; + LL_WARNS_ONCE("Avatar") << avatar->getFullname() << " avatar build state: isBuilt() " << avatar->isBuilt() << " mInitFlags " << avatar->mInitFlags << LL_ENDL; + } + } + else + { + LL_WARNS_ONCE("Avatar") << avatar->getFullname() << " unable to find joint " << skin->mJointNames[j] << LL_ENDL; + LL_WARNS_ONCE("Avatar") << avatar->getFullname() << " avatar build state: isBuilt() " << avatar->isBuilt() << " mInitFlags " << avatar->mInitFlags << LL_ENDL; +#if 0 + dump_avatar_and_skin_state("initJointNums joint not found", avatar, skin); +#endif + } + } + } + skin->mJointNumsInitialized = true; + } +} + +static LLTrace::BlockTimerStatHandle FTM_FACE_RIGGING_INFO("Face Rigging Info"); + +// How many copies of the same code do we need, LL? +void LLSkinningUtil::updateRiggingInfo(const LLMeshSkinInfo* skin, LLVOAvatar *avatar, LLVolumeFace& vol_face) +{ + LL_RECORD_BLOCK_TIME(FTM_FACE_RIGGING_INFO); + + if (vol_face.mJointRiggingInfoTab.needsUpdate()) + { + S32 num_verts = vol_face.mNumVertices; + if (num_verts>0 && vol_face.mWeights && (skin->mJointNames.size()>0)) + { + initJointNums(const_cast(skin), avatar); + if (vol_face.mJointRiggingInfoTab.size()==0) + { + //std::set active_joints; + //S32 active_verts = 0; + vol_face.mJointRiggingInfoTab.resize(LL_CHARACTER_MAX_ANIMATED_JOINTS); + LLJointRiggingInfoTab &rig_info_tab = vol_face.mJointRiggingInfoTab; + LLMatrix4a bind_shape; + bind_shape.loadu(skin->mBindShapeMatrix); + LLMatrix4a matrixPalette[LL_CHARACTER_MAX_ANIMATED_JOINTS]; + for (U32 i = 0; i < llmin(skin->mInvBindMatrix.size(), (size_t)LL_CHARACTER_MAX_ANIMATED_JOINTS); ++i) + { + LLMatrix4a inverse_bind; + inverse_bind.loadu(skin->mInvBindMatrix[i]); + matrixPalette[i].setMul(inverse_bind, bind_shape); + } + for (S32 i=0; i 0.0f) + { + for (U32 k=0; k<4; ++k) + { + wght[k] /= scale; + } + } + for (U32 k=0; k<4; ++k) + { + S32 joint_index = idx[k]; + if (wght[k] > 0.0f) + { + S32 joint_num = skin->mJointNums[joint_index]; + if (joint_num >= 0 && joint_num < LL_CHARACTER_MAX_ANIMATED_JOINTS) + { + rig_info_tab[joint_num].setIsRiggedTo(true); + LLVector4a pos_joint_space; + matrixPalette[joint_index].affineTransform(pos, pos_joint_space); + pos_joint_space.mul(wght[k]); + LLVector4a *extents = rig_info_tab[joint_num].getRiggedExtents(); + update_min_max(extents[0], extents[1], pos_joint_space); + } + } + } + } + //LL_DEBUGS("RigSpammish") << "built rigging info for vf " << &vol_face + // << " num_verts " << vol_face.mNumVertices + // << " active joints " << active_joints.size() + // << " active verts " << active_verts + // << LL_ENDL; + vol_face.mJointRiggingInfoTab.setNeedsUpdate(false); + } + } + if (vol_face.mJointRiggingInfoTab.size()!=0) + { + LL_DEBUGS("RigSpammish") << "we have rigging info for vf " << &vol_face + << " num_verts " << vol_face.mNumVertices << LL_ENDL; + } + else + { + LL_DEBUGS("RigSpammish") << "no rigging info for vf " << &vol_face + << " num_verts " << vol_face.mNumVertices << LL_ENDL; + } + + } +} + +// This is used for extracting rotation from a bind shape matrix that +// already has scales baked in +LLQuaternion LLSkinningUtil::getUnscaledQuaternion(const LLMatrix4& mat4) +{ + LLMatrix3 bind_mat = mat4.getMat3(); + for (auto i = 0; i < 3; i++) + { + F32 len = 0.0f; + for (auto j = 0; j < 3; j++) + { + len += bind_mat.mMatrix[i][j] * bind_mat.mMatrix[i][j]; + } + if (len > 0.0f) + { + len = sqrt(len); + for (auto j = 0; j < 3; j++) + { + bind_mat.mMatrix[i][j] /= len; + } + } + } + bind_mat.invert(); + LLQuaternion bind_rot = bind_mat.quaternion(); + bind_rot.normalize(); + return bind_rot; +} diff --git a/indra/newview/llskinningutil.h b/indra/newview/llskinningutil.h new file mode 100644 index 0000000000..fd4643febb --- /dev/null +++ b/indra/newview/llskinningutil.h @@ -0,0 +1,50 @@ +/** +* @file llskinningutil.h +* @brief Functions for mesh object skinning +* @author vir@lindenlab.com +* +* $LicenseInfo:firstyear=2015&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2015, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ +#ifndef LLSKINNINGUTIL_H +#define LLSKINNINGUTIL_H + +class LLVOAvatar; +class LLMeshSkinInfo; +class LLMatrix4a; +class LLVolumeFace; + +namespace LLSkinningUtil +{ + void initClass(); + U32 getMaxJointCount(); + U32 getMeshJointCount(const LLMeshSkinInfo *skin); + void scrubInvalidJoints(LLVOAvatar *avatar, LLMeshSkinInfo* skin); + void initSkinningMatrixPalette(LLMatrix4a* mat, S32 count, const LLMeshSkinInfo* skin, LLVOAvatar *avatar, bool relative_to_avatar = false); + void checkSkinWeights(const LLVector4a* weights, U32 num_vertices, const LLMeshSkinInfo* skin); + void scrubSkinWeights(LLVector4a* weights, U32 num_vertices, const LLMeshSkinInfo* skin); + void getPerVertexSkinMatrix(const F32* weights, LLMatrix4a* mat, bool handle_bad_scale, LLMatrix4a& final_mat, U32 max_joints); + void initJointNums(LLMeshSkinInfo* skin, LLVOAvatar *avatar); + void updateRiggingInfo(const LLMeshSkinInfo* skin, LLVOAvatar *avatar, LLVolumeFace& vol_face); + LLQuaternion getUnscaledQuaternion(const LLMatrix4& mat4); +}; + +#endif diff --git a/indra/newview/llsky.cpp b/indra/newview/llsky.cpp index de99cb86fa..b223acf78a 100644 --- a/indra/newview/llsky.cpp +++ b/indra/newview/llsky.cpp @@ -287,38 +287,38 @@ LLColor4U LLSky::getFadeColor() const void LLSky::init(const LLVector3 &sun_direction) { - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); + LLGLStateValidator::checkStates(); + LLGLStateValidator::checkTextureChannels(); mVOWLSkyp = static_cast(gObjectList.createObjectViewer(LLViewerObject::LL_VO_WL_SKY, NULL)); mVOWLSkyp->initSunDirection(sun_direction, LLVector3::zero); gPipeline.createObject(mVOWLSkyp.get()); - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); + LLGLStateValidator::checkStates(); + LLGLStateValidator::checkTextureChannels(); mVOSkyp = (LLVOSky *)gObjectList.createObjectViewer(LLViewerObject::LL_VO_SKY, NULL); - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); + LLGLStateValidator::checkStates(); + LLGLStateValidator::checkTextureChannels(); mVOSkyp->initSunDirection(sun_direction, LLVector3()); - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); + LLGLStateValidator::checkStates(); + LLGLStateValidator::checkTextureChannels(); gPipeline.createObject((LLViewerObject *)mVOSkyp); - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); + LLGLStateValidator::checkStates(); + LLGLStateValidator::checkTextureChannels(); mVOGroundp = (LLVOGround*)gObjectList.createObjectViewer(LLViewerObject::LL_VO_GROUND, NULL); LLVOGround *groundp = mVOGroundp; gPipeline.createObject((LLViewerObject *)groundp); - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - + LLGLStateValidator::checkStates(); + LLGLStateValidator::checkTextureChannels(); + gSky.setFogRatio(gSavedSettings.getF32("RenderFogRatio")); //////////////////////////// @@ -330,8 +330,8 @@ void LLSky::init(const LLVector3 &sun_direction) // Get the parameters. mSunDefaultPosition = gSavedSettings.getVector3("SkySunDefaultPosition"); - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); + //LLGLStateValidator::checkStates(); + //LLGLStateValidator::checkTextureChannels(); if (gSavedSettings.getBOOL("SkyOverrideSimSunPosition") || mOverrideSimSunPosition) { @@ -342,8 +342,8 @@ void LLSky::init(const LLVector3 &sun_direction) setSunDirection(sun_direction, LLVector3(0.f, 0.f, 0.f)); } - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); + //LLGLStateValidator::checkStates(); + //LLGLStateValidator::checkTextureChannels(); mUpdatedThisFrame = TRUE; } diff --git a/indra/newview/llslurl.cpp b/indra/newview/llslurl.cpp index 3f1b194c55..03f67b41de 100644 --- a/indra/newview/llslurl.cpp +++ b/indra/newview/llslurl.cpp @@ -1,5 +1,7 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com /** - * @file llurlsimstring.cpp (was llsimurlstring.cpp) + * @file llslurl.cpp (was llsimurlstring.cpp) * @brief Handles "SLURL fragments" like Ahern/123/45 for * startup processing, login screen, prefs, etc. * @@ -35,6 +37,7 @@ #include "llfiltersd2xmlrpc.h" #include "curl/curl.h" #include "hippogridmanager.h" +#include "llworldmap.h" // Variable size regions const char* LLSLURL::SLURL_HTTP_SCHEME = "http"; const char* LLSLURL::SLURL_HTTPS_SCHEME = "https"; @@ -47,7 +50,8 @@ const char* LLSLURL::SLURL_COM = "slurl.com"; const char* LLSLURL::WWW_SLURL_COM = "www.slurl.com"; const char* LLSLURL::MAPS_SECONDLIFE_COM = "maps.secondlife.com"; -const char* LLSLURL::SLURL_X_GRID_LOCATION_INFO_SCHEME = "x-grid-location-info"; +const char* LLSLURL::SLURL_X_GRID_INFO_SCHEME = "x-grid-info"; +const char* LLSLURL::SLURL_X_GRID_LOCATION_INFO_SCHEME = "x-grid-location-info"; // <- deprecated! const char* LLSLURL::SLURL_APP_PATH = "app"; const char* LLSLURL::SLURL_REGION_PATH = "region"; const char* LLSLURL::SIM_LOCATION_HOME = "home"; @@ -57,8 +61,8 @@ const std::string MAIN_GRID_SLURL_BASE = "http://maps.secondlife.com/secondlife/ const std::string SYSTEM_GRID_APP_SLURL_BASE = "secondlife:///app"; const char* SYSTEM_GRID_SLURL_BASE = "secondlife://%s/secondlife/"; -const char* DEFAULT_SLURL_BASE = "https://%s/region/"; -const char* DEFAULT_APP_SLURL_BASE = "x-grid-location-info://%s/app"; +const char* DEFAULT_SLURL_BASE = "x-grid-info://%s/region/"; +const char* DEFAULT_APP_SLURL_BASE = "x-grid-info://%s/app"; #define MAINGRID "secondlife" // resolve a simstring from a slurl @@ -213,7 +217,8 @@ LLSLURL::LLSLURL(const std::string& slurl) } 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)) + (slurl_uri.scheme() == LLSLURL::SLURL_X_GRID_INFO_SCHEME) || + (slurl_uri.scheme() == LLSLURL::SLURL_X_GRID_LOCATION_INFO_SCHEME)) // deprecated legacy { // We're dealing with either a Standalone style slurl or slurl.com slurl if ((slurl_uri.hostName() == LLSLURL::SLURL_COM) || @@ -238,7 +243,7 @@ LLSLURL::LLSLURL(const std::string& slurl) // 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(); + mGrid = slurl_uri.hostNameAndPort(); } if (path_array.size() == 0) { @@ -265,7 +270,7 @@ LLSLURL::LLSLURL(const std::string& slurl) } else { - // not a valid https/http/x-grid-location-info slurl, so it'll likely just be a URL + // not a valid https/http/x-grid-info slurl, so it'll likely just be a URL return; } } @@ -303,7 +308,14 @@ LLSLURL::LLSLURL(const std::string& slurl) // 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 @@ -312,11 +324,11 @@ LLSLURL::LLSLURL(const std::string& slurl) 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) || + (mPosition[VX] > 8192.f) || (F32(mPosition[VY]) < 0.f) || - (mPosition[VY] > REGION_WIDTH_METERS) || + (mPosition[VY] > 8192.f) || (F32(mPosition[VZ]) < 0.f) || - (mPosition[VZ] > 8192.f/*REGION_HEIGHT_METERS*/)) + (mPosition[VZ] > 8192.f)) { mType = INVALID; return; @@ -355,9 +367,9 @@ LLSLURL::LLSLURL(const std::string& grid, { mGrid = grid; mRegion = region; - S32 x = llround( (F32)fmod( position[VX], (F32)REGION_WIDTH_METERS ) ); - S32 y = llround( (F32)fmod( position[VY], (F32)REGION_WIDTH_METERS ) ); - S32 z = llround( (F32)position[VZ] ); + S32 x = ll_round( (F32)position[VX] ); + S32 y = ll_round( (F32)position[VY] ); + S32 z = ll_round( (F32)position[VZ] ); mType = LOCATION; mPosition = LLVector3(x, y, z); } @@ -377,10 +389,14 @@ LLSLURL::LLSLURL(const std::string& grid, const LLVector3d& global_position) { HippoGridInfo* gridp = gHippoGridManager->getGrid(grid); + LLVector3 pos(global_position); + if (LLSimInfo* sim = LLWorldMap::getInstance()->simInfoFromPosGlobal(global_position)) // Variable size regions, we need to fmod against their proper dimensions, not 256 + { + pos[VX] = fmod(pos[VX], sim->getSizeX()); + pos[VY] = fmod(pos[VY], sim->getSizeY()); + } *this = LLSLURL(gridp ? gridp->getGridNick() : gHippoGridManager->getDefaultGridNick(), - region, LLVector3(global_position.mdV[VX], - global_position.mdV[VY], - global_position.mdV[VZ])); + region, pos); } // create a slurl from a global position @@ -412,9 +428,9 @@ std::string LLSLURL::getSLURLString() const case LOCATION: { // lookup the grid - S32 x = llround( (F32)mPosition[VX] ); - S32 y = llround( (F32)mPosition[VY] ); - S32 z = llround( (F32)mPosition[VZ] ); + 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) + //Singu TODO: Implement LLHippoGridMgr::getSLURLBase some day. For now it's hardcoded. std::string fixed_slurl; @@ -439,9 +455,9 @@ std::string LLSLURL::getSLURLString() const app_url << SYSTEM_GRID_APP_SLURL_BASE << "/" << mAppCmd; else app_url << llformat(DEFAULT_APP_SLURL_BASE, gHippoGridManager->getCurrentGridNick().c_str()) << "/" << mAppCmd; - for(LLSD::array_const_iterator i = mAppPath.beginArray(); + for(auto i = mAppPath.beginArray(); i != mAppPath.endArray(); - i++) + ++i) { app_url << "/" << i->asString(); } @@ -466,9 +482,9 @@ std::string LLSLURL::getLoginString() const case LOCATION: unescaped_start << "uri:" << mRegion << "&" - << llround(mPosition[0]) << "&" - << llround(mPosition[1]) << "&" - << llround(mPosition[2]); + << ll_round(mPosition[0]) << "&" + << ll_round(mPosition[1]) << "&" + << ll_round(mPosition[2]); break; case HOME_LOCATION: unescaped_start << "home"; @@ -512,9 +528,9 @@ std::string LLSLURL::getLocationString() const { return llformat("%s/%d/%d/%d", mRegion.c_str(), - (int)llround(mPosition[0]), - (int)llround(mPosition[1]), - (int)llround(mPosition[2])); + (int)ll_round(mPosition[0]), + (int)ll_round(mPosition[1]), + (int)ll_round(mPosition[2])); } // static diff --git a/indra/newview/llslurl.h b/indra/newview/llslurl.h index b86cf7949b..3beff26c74 100644 --- a/indra/newview/llslurl.h +++ b/indra/newview/llslurl.h @@ -44,6 +44,7 @@ class LLSLURL static const char* WWW_SLURL_COM; static const char* SECONDLIFE_COM; static const char* MAPS_SECONDLIFE_COM; + static const char* SLURL_X_GRID_INFO_SCHEME; static const char* SLURL_X_GRID_LOCATION_INFO_SCHEME; static LLSLURL START_LOCATION; static const char* SIM_LOCATION_HOME; diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index 3ae95d6c01..97decd6fea 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -45,6 +45,7 @@ #include "llvolumeoctree.h" #include "llviewercamera.h" #include "llface.h" +#include "llfloaterinspect.h" #include "llfloatertools.h" #include "llviewercontrol.h" #include "llviewerregion.h" @@ -58,31 +59,18 @@ #include "llvolumemgr.h" #include "llglslshader.h" #include "llviewershadermgr.h" +#include "llcontrolavatar.h" -static LLFastTimer::DeclareTimer FTM_FRUSTUM_CULL("Frustum Culling"); -static LLFastTimer::DeclareTimer FTM_CULL_REBOUND("Cull Rebound"); - -const F32 SG_OCCLUSION_FUDGE = 0.25f; -#define SG_DISCARD_TOLERANCE 0.01f - -#if LL_OCTREE_PARANOIA_CHECK -#define assert_octree_valid(x) x->validate() -#define assert_states_valid(x) ((LLSpatialGroup*) x->mSpatialPartition->mOctree->getListener(0))->checkStates() -#else -#define assert_octree_valid(x) -#define assert_states_valid(x) -#endif +static LLTrace::BlockTimerStatHandle FTM_FRUSTUM_CULL("Frustum Culling"); +static LLTrace::BlockTimerStatHandle FTM_CULL_REBOUND("Cull Rebound"); extern bool gShiftFrame; static U32 sZombieGroups = 0; U32 LLSpatialGroup::sNodeCount = 0; -#define LL_TRACK_PENDING_OCCLUSION_QUERIES 0 - -std::set LLSpatialGroup::sPendingQueries; - U32 gOctreeMaxCapacity; +float gOctreeMinSize; U32 gOctreeReserveCapacity; BOOL LLSpatialGroup::sNoDelete = FALSE; @@ -90,47 +78,7 @@ BOOL LLSpatialGroup::sNoDelete = FALSE; static F32 sLastMaxTexPriority = 1.f; static F32 sCurMaxTexPriority = 1.f; -class LLOcclusionQueryPool : public LLGLNamePool -{ -public: - LLOcclusionQueryPool() - { - mCurQuery = 1; - } - -protected: - - std::queue mAvailableName; //Use queue, because this usage is FIFO, which queue is desgined for - GLuint mCurQuery; - - virtual GLuint allocateName() - { - GLuint ret = 0; - - if (!mAvailableName.empty()) - { - ret = mAvailableName.front(); - mAvailableName.pop(); - } - else - { - ret = mCurQuery++; - } - - return ret; - } - - virtual void releaseName(GLuint name) - { -#if LL_TRACK_PENDING_OCCLUSION_QUERIES - LLSpatialGroup::sPendingQueries.erase(name); -#endif - //llassert(std::find(mAvailableName.begin(), mAvailableName.end(), name) == mAvailableName.end()); - mAvailableName.push(name); - } -}; - -static LLOcclusionQueryPool sQueryPool; +BOOL LLSpatialPartition::sTeleportRequested = FALSE; //BOOL LLSpatialPartition::sFreezeState = FALSE; @@ -141,190 +89,11 @@ void sg_assert(BOOL expr) #if LL_OCTREE_PARANOIA_CHECK if (!expr) { - llerrs << "Octree invalid!" << llendl; + LL_ERRS() << "Octree invalid!" << LL_ENDL; } #endif } -S32 AABBSphereIntersect(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &rad) -{ - return AABBSphereIntersectR2(min, max, origin, rad*rad); -} - -S32 AABBSphereIntersectR2(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &r) -{ - F32 d = 0.f; - F32 t; - - if ((min-origin).magVecSquared() < r && - (max-origin).magVecSquared() < r) - { - return 2; - } - - for (U32 i = 0; i < 3; i++) - { - if (origin.mV[i] < min.mV[i]) - { - t = min.mV[i] - origin.mV[i]; - d += t*t; - } - else if (origin.mV[i] > max.mV[i]) - { - t = origin.mV[i] - max.mV[i]; - d += t*t; - } - - if (d > r) - { - return 0; - } - } - - return 1; -} - - -S32 AABBSphereIntersect(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &rad) -{ - return AABBSphereIntersectR2(min, max, origin, rad*rad); -} - -S32 AABBSphereIntersectR2(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &r) -{ - F32 d = 0.f; - F32 t; - - LLVector4a origina; - origina.load3(origin.mV); - - LLVector4a v; - v.setSub(min, origina); - - if (v.dot3(v) < r) - { - v.setSub(max, origina); - if (v.dot3(v) < r) - { - return 2; - } - } - - - for (U32 i = 0; i < 3; i++) - { - if (origin.mV[i] < min[i]) - { - t = min[i] - origin.mV[i]; - d += t*t; - } - else if (origin.mV[i] > max[i]) - { - t = origin.mV[i] - max[i]; - d += t*t; - } - - if (d > r) - { - return 0; - } - } - - return 1; -} - - -typedef enum -{ - b000 = 0x00, - b001 = 0x01, - b010 = 0x02, - b011 = 0x03, - b100 = 0x04, - b101 = 0x05, - b110 = 0x06, - b111 = 0x07, -} eLoveTheBits; - -//contact Runitai Linden for a copy of the SL object used to write this table -//basically, you give the table a bitmask of the look-at vector to a node and it -//gives you a triangle fan index array -static U16 sOcclusionIndices[] = -{ - //000 - b111, b110, b010, b011, b001, b101, b100, b110, - //001 - b011, b010, b000, b001, b101, b111, b110, b010, - //010 - b101, b100, b110, b111, b011, b001, b000, b100, - //011 - b001, b000, b100, b101, b111, b011, b010, b000, - //100 - b110, b000, b010, b011, b111, b101, b100, b000, - //101 - b010, b100, b000, b001, b011, b111, b110, b100, - //110 - b100, b010, b110, b111, b101, b001, b000, b010, - //111 - b000, b110, b100, b101, b001, b011, b010, b110, -}; - -U32 get_box_fan_indices(LLCamera* camera, const LLVector4a& center) -{ - LLVector4a origin; - origin.load3(camera->getOrigin().mV); - - S32 cypher = center.greaterThan(origin).getGatheredBits() & 0x7; - - return cypher*8; -} - -U8* get_box_fan_indices_ptr(LLCamera* camera, const LLVector4a& center) -{ - LLVector4a origin; - origin.load3(camera->getOrigin().mV); - - S32 cypher = center.greaterThan(origin).getGatheredBits() & 0x7; - - return (U8*) (sOcclusionIndices+cypher*8); -} - -//create a vertex buffer for efficiently rendering cubes -LLVertexBuffer* ll_create_cube_vb(U32 type_mask, U32 usage) -{ - LLVertexBuffer* ret = new LLVertexBuffer(type_mask, usage); - - ret->allocateBuffer(8, 64, true); - - LLStrider pos; - LLStrider idx; - - ret->getVertexStrider(pos); - ret->getIndexStrider(idx); - - pos[0] = LLVector3(-1,-1,-1); - pos[1] = LLVector3(-1,-1, 1); - pos[2] = LLVector3(-1, 1,-1); - pos[3] = LLVector3(-1, 1, 1); - pos[4] = LLVector3( 1,-1,-1); - pos[5] = LLVector3( 1,-1, 1); - pos[6] = LLVector3( 1, 1,-1); - pos[7] = LLVector3( 1, 1, 1); - - for (U32 i = 0; i < 64; i++) - { - idx[i] = sOcclusionIndices[i]; - } - - ret->flush(); - - return ret; -} - -static LLFastTimer::DeclareTimer FTM_BUILD_OCCLUSION("Build Occlusion"); - -BOOL earlyFail(LLCamera* camera, LLSpatialGroup* group); - //returns: // 0 if sphere and AABB are not intersecting // 1 if they are @@ -358,31 +127,20 @@ LLSpatialGroup::~LLSpatialGroup() { /*if (sNoDelete) { - llerrs << "Illegal deletion of LLSpatialGroup!" << llendl; + LL_ERRS() << "Illegal deletion of LLSpatialGroup!" << LL_ENDL; }*/ if (gDebugGL) { gPipeline.checkReferences(this); } - if (isState(DEAD)) + if (hasState((LLSpatialGroup::eSpatialState)DEAD)) { sZombieGroups--; } sNodeCount--; - if (gGLManager.mHasOcclusionQuery) - { - for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; ++i) - { - if (mOcclusionQuery[i]) - { - sQueryPool.release(mOcclusionQuery[i]); - } - } - } - clearDrawMap(); } @@ -393,22 +151,7 @@ void LLSpatialGroup::clearDrawMap() BOOL LLSpatialGroup::isHUDGroup() { - return mSpatialPartition && mSpatialPartition->isHUDPartition() ; -} - -BOOL LLSpatialGroup::isRecentlyVisible() const -{ - return (LLDrawable::getCurrentFrame() - mVisible[LLViewerCamera::sCurCameraID]) < LLDrawable::getMinVisFrameRange() ; -} - -BOOL LLSpatialGroup::isVisible() const -{ - return mVisible[LLViewerCamera::sCurCameraID] >= LLDrawable::getCurrentFrame() ? TRUE : FALSE; -} - -void LLSpatialGroup::setVisible() -{ - mVisible[LLViewerCamera::sCurCameraID] = LLDrawable::getCurrentFrame(); + return getSpatialPartition() && getSpatialPartition()->isHUDPartition() ; } void LLSpatialGroup::validate() @@ -432,7 +175,7 @@ void LLSpatialGroup::validate() sg_assert(drawable->getSpatialGroup() == this); if (drawable->getSpatialBridge()) { - sg_assert(drawable->getSpatialBridge() == mSpatialPartition->asBridge()); + sg_assert(drawable->getSpatialBridge() == getSpatialPartition()->asBridge()); } /*if (drawable->isSpatialBridge()) @@ -440,7 +183,7 @@ void LLSpatialGroup::validate() LLSpatialPartition* part = drawable->asPartition(); if (!part) { - llerrs << "Drawable reports it is a spatial bridge but not a partition." << llendl; + LL_ERRS() << "Drawable reports it is a spatial bridge but not a partition." << LL_ENDL; } LLSpatialGroup* group = (LLSpatialGroup*) part->mOctree->getListener(0); group->validate(); @@ -472,14 +215,6 @@ void LLSpatialGroup::validate() #endif } -void LLSpatialGroup::checkStates() -{ -#if LL_OCTREE_PARANOIA_CHECK - LLOctreeStateCheck checker; - checker.traverse(mOctreeNode); -#endif -} - void LLSpatialGroup::validateDrawMap() { #if LL_OCTREE_PARANOIA_CHECK @@ -503,12 +238,12 @@ BOOL LLSpatialGroup::updateInGroup(LLDrawable *drawablep, BOOL immediate) OctreeNode* parent = mOctreeNode->getOctParent(); if (mOctreeNode->isInside(drawablep->getPositionGroup()) && - (mOctreeNode->contains(drawablep) || + (mOctreeNode->contains(drawablep->getEntry()) || (drawablep->getBinRadius() > mOctreeNode->getSize()[0] && parent && parent->getElementCount() >= gOctreeMaxCapacity))) { unbound(); - setState(OBJECT_DIRTY); + setState((LLSpatialGroup::eSpatialState)OBJECT_DIRTY); //setState(GEOM_DIRTY); return TRUE; } @@ -517,16 +252,15 @@ BOOL LLSpatialGroup::updateInGroup(LLDrawable *drawablep, BOOL immediate) } -BOOL LLSpatialGroup::addObject(LLDrawable *drawablep, BOOL add_all, BOOL from_octree) +BOOL LLSpatialGroup::addObject(LLDrawable *drawablep) { - if (!from_octree) + if(!drawablep) { - mOctreeNode->insert(drawablep); + return FALSE; } - else { - drawablep->setSpatialGroup(this); - setState(OBJECT_DIRTY | GEOM_DIRTY); + drawablep->setGroup(this); + setState(LLSpatialGroup::eSpatialState(OBJECT_DIRTY | GEOM_DIRTY)); setOcclusionState(LLSpatialGroup::DISCARD_QUERY, LLSpatialGroup::STATE_MODE_ALL_CAMERAS); gPipeline.markRebuild(this, TRUE); if (drawablep->isSpatialBridge()) @@ -546,9 +280,9 @@ void LLSpatialGroup::rebuildGeom() { if (!isDead()) { - mSpatialPartition->rebuildGeom(this); + getSpatialPartition()->rebuildGeom(this); - if (isState(LLSpatialGroup::MESH_DIRTY)) + if (hasState(LLSpatialGroup::MESH_DIRTY)) { gPipeline.markMeshDirty(this); } @@ -559,18 +293,18 @@ void LLSpatialGroup::rebuildMesh() { if (!isDead()) { - mSpatialPartition->rebuildMesh(this); + getSpatialPartition()->rebuildMesh(this); } } -static LLFastTimer::DeclareTimer FTM_REBUILD_VBO("VBO Rebuilt"); -static LLFastTimer::DeclareTimer FTM_ADD_GEOMETRY_COUNT("Add Geometry"); -static LLFastTimer::DeclareTimer FTM_CREATE_VB("Create VB"); -static LLFastTimer::DeclareTimer FTM_GET_GEOMETRY("Get Geometry"); +static LLTrace::BlockTimerStatHandle FTM_REBUILD_VBO("VBO Rebuilt"); +static LLTrace::BlockTimerStatHandle FTM_ADD_GEOMETRY_COUNT("Add Geometry"); +static LLTrace::BlockTimerStatHandle FTM_CREATE_VB("Create VB"); +static LLTrace::BlockTimerStatHandle FTM_GET_GEOMETRY("Get Geometry"); void LLSpatialPartition::rebuildGeom(LLSpatialGroup* group) { - if (group->isDead() || !group->isState(LLSpatialGroup::GEOM_DIRTY)) + if (group->isDead() || !group->hasState(LLSpatialGroup::GEOM_DIRTY)) { return; } @@ -581,7 +315,7 @@ void LLSpatialPartition::rebuildGeom(LLSpatialGroup* group) group->mLastUpdateViewAngle = group->mViewAngle; } - LLFastTimer ftm(FTM_REBUILD_VBO); + LL_RECORD_BLOCK_TIME(FTM_REBUILD_VBO); group->clearDrawMap(); @@ -590,14 +324,14 @@ void LLSpatialPartition::rebuildGeom(LLSpatialGroup* group) U32 vertex_count = 0; { - LLFastTimer t(FTM_ADD_GEOMETRY_COUNT); + LL_RECORD_BLOCK_TIME(FTM_ADD_GEOMETRY_COUNT); addGeometryCount(group, vertex_count, index_count); } if (vertex_count > 0 && index_count > 0) { //create vertex buffer containing volume geometry for this node { - LLFastTimer t(FTM_CREATE_VB); + LL_RECORD_BLOCK_TIME(FTM_CREATE_VB); group->mBuilt = 1.f; if (group->mVertexBuffer.isNull() || !group->mVertexBuffer->isWriteable() || @@ -615,156 +349,46 @@ void LLSpatialPartition::rebuildGeom(LLSpatialGroup* group) } { - LLFastTimer t(FTM_GET_GEOMETRY); + LL_RECORD_BLOCK_TIME(FTM_GET_GEOMETRY); getGeometry(group); } } else { group->mVertexBuffer = NULL; - group->mBufferMap.clear(); + group->mBufferVec.clear(); } group->mLastUpdateTime = gFrameTimeSeconds; group->clearState(LLSpatialGroup::GEOM_DIRTY); } -void LLSpatialPartition::rebuildMesh(LLSpatialGroup* group) -{ - -} - -BOOL LLSpatialGroup::boundObjects(BOOL empty, LLVector4a& minOut, LLVector4a& maxOut) -{ - const OctreeNode* node = mOctreeNode; - - if (node->isEmpty()) - { //don't do anything if there are no objects - if (empty && mOctreeNode->getParent()) - { //only root is allowed to be empty - OCT_ERRS << "Empty leaf found in octree." << llendl; - } - return FALSE; - } - - LLVector4a& newMin = mObjectExtents[0]; - LLVector4a& newMax = mObjectExtents[1]; - - if (isState(OBJECT_DIRTY)) - { //calculate new bounding box - clearState(OBJECT_DIRTY); - - //initialize bounding box to first element - OctreeNode::const_element_iter i = node->getDataBegin(); - LLDrawable* drawablep = *i; - const LLVector4a* minMax = drawablep->getSpatialExtents(); - - newMin = minMax[0]; - newMax = minMax[1]; - - for (++i; i != node->getDataEnd(); ++i) - { - drawablep = *i; - minMax = drawablep->getSpatialExtents(); - - update_min_max(newMin, newMax, minMax[0]); - update_min_max(newMin, newMax, minMax[1]); - - //bin up the object - /*for (U32 i = 0; i < 3; i++) - { - if (minMax[0].mV[i] < newMin.mV[i]) - { - newMin.mV[i] = minMax[0].mV[i]; - } - if (minMax[1].mV[i] > newMax.mV[i]) - { - newMax.mV[i] = minMax[1].mV[i]; - } - }*/ - } - - mObjectBounds[0].setAdd(newMin, newMax); - mObjectBounds[0].mul(0.5f); - mObjectBounds[1].setSub(newMax, newMin); - mObjectBounds[1].mul(0.5f); - } - - if (empty) - { - minOut = newMin; - maxOut = newMax; - } - else - { - minOut.setMin(minOut, newMin); - maxOut.setMax(maxOut, newMax); - } - - return TRUE; -} -void LLSpatialGroup::unbound() +void LLSpatialPartition::rebuildMesh(LLSpatialGroup* group) { - if (isState(DIRTY)) - { - return; - } - setState(DIRTY); - - //all the parent nodes need to rebound this child - if (mOctreeNode) - { - OctreeNode* parent = (OctreeNode*) mOctreeNode->getParent(); - while (parent != NULL) - { - LLSpatialGroup* group = (LLSpatialGroup*) parent->getListener(0); - if (group->isState(DIRTY)) - { - return; - } - - group->setState(DIRTY); - parent = (OctreeNode*) parent->getParent(); - } - } } LLSpatialGroup* LLSpatialGroup::getParent() { - if (isDead()) - { - return NULL; - } + return (LLSpatialGroup*)LLViewerOctreeGroup::getParent(); +} - if(!mOctreeNode) +BOOL LLSpatialGroup::removeObject(LLDrawable *drawablep, BOOL from_octree) { - return NULL; - } - OctreeNode* parent = mOctreeNode->getOctParent(); - - if (parent) + if(!drawablep) { - return (LLSpatialGroup*) parent->getListener(0); + return FALSE; } - return NULL; -} - -BOOL LLSpatialGroup::removeObject(LLDrawable *drawablep, BOOL from_octree) -{ unbound(); if (mOctreeNode && !from_octree) { - if (!mOctreeNode->remove(drawablep)) - { - OCT_ERRS << "Could not remove drawable from spatial group" << llendl; - } + drawablep->setGroup(NULL); } else { - drawablep->setSpatialGroup(NULL); + drawablep->setGroup(NULL); setState(GEOM_DIRTY); gPipeline.markRebuild(this, TRUE); @@ -801,22 +425,23 @@ void LLSpatialGroup::shift(const LLVector4a &offset) mObjectExtents[0].add(offset); mObjectExtents[1].add(offset); - if (!mSpatialPartition->mRenderByGroup && - mSpatialPartition->mPartitionType != LLViewerRegion::PARTITION_TREE && - mSpatialPartition->mPartitionType != LLViewerRegion::PARTITION_TERRAIN && - mSpatialPartition->mPartitionType != LLViewerRegion::PARTITION_BRIDGE) + if (!getSpatialPartition()->mRenderByGroup && + getSpatialPartition()->mPartitionType != LLViewerRegion::PARTITION_TREE && + getSpatialPartition()->mPartitionType != LLViewerRegion::PARTITION_TERRAIN && + getSpatialPartition()->mPartitionType != LLViewerRegion::PARTITION_ATTACHMENT && + getSpatialPartition()->mPartitionType != LLViewerRegion::PARTITION_BRIDGE) { setState(GEOM_DIRTY); gPipeline.markRebuild(this, TRUE); } } -class LLSpatialSetState : public LLSpatialGroup::OctreeTraveler +class LLSpatialSetState : public OctreeTraveler { public: LLSpatialGroup::eSpatialState mState; LLSpatialSetState(LLSpatialGroup::eSpatialState state) : mState(state) { } - virtual void visit(const LLSpatialGroup::OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->setState(mState); } + virtual void visit(const OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->setState(mState); } }; class LLSpatialSetStateDiff : public LLSpatialSetState @@ -824,26 +449,17 @@ class LLSpatialSetStateDiff : public LLSpatialSetState public: LLSpatialSetStateDiff(LLSpatialGroup::eSpatialState state) : LLSpatialSetState(state) { } - virtual void traverse(const LLSpatialGroup::OctreeNode* n) + virtual void traverse(const OctreeNode* n) { LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0); - if (!group->isState(mState)) + if (!group->hasState(mState)) { - LLSpatialGroup::OctreeTraveler::traverse(n); + OctreeTraveler::traverse(n); } } }; -void LLSpatialGroup::setState(eSpatialState state) -{ -// if (LLSpatialPartition::sFreezeState) -// return; - mState |= state; - - llassert(state <= LLSpatialGroup::STATE_MASK); -} - void LLSpatialGroup::setState(eSpatialState state, S32 mode) { llassert(state <= LLSpatialGroup::STATE_MASK); @@ -867,12 +483,12 @@ void LLSpatialGroup::setState(eSpatialState state, S32 mode) } } -class LLSpatialClearState : public LLSpatialGroup::OctreeTraveler +class LLSpatialClearState : public OctreeTraveler { public: LLSpatialGroup::eSpatialState mState; LLSpatialClearState(LLSpatialGroup::eSpatialState state) : mState(state) { } - virtual void visit(const LLSpatialGroup::OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->clearState(mState); } + virtual void visit(const OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->clearState(mState); } }; class LLSpatialClearStateDiff : public LLSpatialClearState @@ -880,24 +496,17 @@ class LLSpatialClearStateDiff : public LLSpatialClearState public: LLSpatialClearStateDiff(LLSpatialGroup::eSpatialState state) : LLSpatialClearState(state) { } - virtual void traverse(const LLSpatialGroup::OctreeNode* n) + virtual void traverse(const OctreeNode* n) { LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0); - if (group->isState(mState)) + if (group->hasState(mState)) { - LLSpatialGroup::OctreeTraveler::traverse(n); + OctreeTraveler::traverse(n); } } }; -void LLSpatialGroup::clearState(eSpatialState state) -{ - llassert(state <= LLSpatialGroup::STATE_MASK); - - mState &= ~state; -} - void LLSpatialGroup::clearState(eSpatialState state, S32 mode) { llassert(state <= LLSpatialGroup::STATE_MASK); @@ -921,144 +530,15 @@ void LLSpatialGroup::clearState(eSpatialState state, S32 mode) } } -BOOL LLSpatialGroup::isState(eSpatialState state) const -{ - llassert(state <= LLSpatialGroup::STATE_MASK); - - return mState & state ? TRUE : FALSE; -} - -//===================================== -// Occlusion State Set/Clear -//===================================== -class LLSpatialSetOcclusionState : public LLSpatialGroup::OctreeTraveler -{ -public: - LLSpatialGroup::eOcclusionState mState; - LLSpatialSetOcclusionState(LLSpatialGroup::eOcclusionState state) : mState(state) { } - virtual void visit(const LLSpatialGroup::OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->setOcclusionState(mState); } -}; - -class LLSpatialSetOcclusionStateDiff : public LLSpatialSetOcclusionState -{ -public: - LLSpatialSetOcclusionStateDiff(LLSpatialGroup::eOcclusionState state) : LLSpatialSetOcclusionState(state) { } - - virtual void traverse(const LLSpatialGroup::OctreeNode* n) - { - LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0); - - if (!group->isOcclusionState(mState)) - { - LLSpatialGroup::OctreeTraveler::traverse(n); - } - } -}; - - -void LLSpatialGroup::setOcclusionState(eOcclusionState state, S32 mode) -{ - if (mode > STATE_MODE_SINGLE) - { - if (mode == STATE_MODE_DIFF) - { - LLSpatialSetOcclusionStateDiff setter(state); - setter.traverse(mOctreeNode); - } - else if (mode == STATE_MODE_BRANCH) - { - LLSpatialSetOcclusionState setter(state); - setter.traverse(mOctreeNode); - } - else - { - for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++) - { - mOcclusionState[i] |= state; - - if ((state & DISCARD_QUERY) && mOcclusionQuery[i]) - { - sQueryPool.release(mOcclusionQuery[i]); - mOcclusionQuery[i] = 0; - } - } - } - } - else - { - mOcclusionState[LLViewerCamera::sCurCameraID] |= state; - if ((state & DISCARD_QUERY) && mOcclusionQuery[LLViewerCamera::sCurCameraID]) - { - sQueryPool.release(mOcclusionQuery[LLViewerCamera::sCurCameraID]); - mOcclusionQuery[LLViewerCamera::sCurCameraID] = 0; - } - } -} - -class LLSpatialClearOcclusionState : public LLSpatialGroup::OctreeTraveler -{ -public: - LLSpatialGroup::eOcclusionState mState; - - LLSpatialClearOcclusionState(LLSpatialGroup::eOcclusionState state) : mState(state) { } - virtual void visit(const LLSpatialGroup::OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->clearOcclusionState(mState); } -}; - -class LLSpatialClearOcclusionStateDiff : public LLSpatialClearOcclusionState -{ -public: - LLSpatialClearOcclusionStateDiff(LLSpatialGroup::eOcclusionState state) : LLSpatialClearOcclusionState(state) { } - - virtual void traverse(const LLSpatialGroup::OctreeNode* n) - { - LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0); - - if (group->isOcclusionState(mState)) - { - LLSpatialGroup::OctreeTraveler::traverse(n); - } - } -}; - -void LLSpatialGroup::clearOcclusionState(eOcclusionState state, S32 mode) -{ - if (mode > STATE_MODE_SINGLE) - { - if (mode == STATE_MODE_DIFF) - { - LLSpatialClearOcclusionStateDiff clearer(state); - clearer.traverse(mOctreeNode); - } - else if (mode == STATE_MODE_BRANCH) - { - LLSpatialClearOcclusionState clearer(state); - clearer.traverse(mOctreeNode); - } - else - { - for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++) - { - mOcclusionState[i] &= ~state; - } - } - } - else - { - mOcclusionState[LLViewerCamera::sCurCameraID] &= ~state; - } -} //====================================== // Octree Listener Implementation //====================================== -LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) : +LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) : LLOcclusionCullingGroup(node, part), mObjectBoxSize(1.f), - mState(0), mGeometryBytes(0), mSurfaceArea(0.f), mBuilt(0.f), - mOctreeNode(node), - mSpatialPartition(part), mVertexBuffer(NULL), mBufferUsage(part->mBufferUsage), mDistance(0.f), @@ -1072,32 +552,11 @@ LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) : mViewAngle.splat(0.f); mLastUpdateViewAngle.splat(-1.f); - mExtents[0] = mExtents[1] = mObjectBounds[0] = mObjectBounds[1] = - mObjectExtents[0] = mObjectExtents[1] = mViewAngle; sg_assert(mOctreeNode->getListenerCount() == 0); - mOctreeNode->addListener(this); - setState(SG_INITIAL_STATE_MASK); + setState(LLSpatialGroup::eSpatialState(SG_INITIAL_STATE_MASK)); gPipeline.markRebuild(this, TRUE); - mBounds[0] = node->getCenter(); - mBounds[1] = node->getSize(); - - part->mLODSeed = (part->mLODSeed+1)%part->mLODPeriod; - mLODHash = part->mLODSeed; - - OctreeNode* oct_parent = node->getOctParent(); - - LLSpatialGroup* parent = oct_parent ? (LLSpatialGroup*) oct_parent->getListener(0) : NULL; - - for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++) - { - mOcclusionQuery[i] = 0; - mOcclusionIssued[i] = 0; - mOcclusionState[i] = parent ? SG_STATE_INHERIT_MASK & parent->mOcclusionState[i] : 0; - mVisible[i] = 0; - } - mRadius = 1; mPixelArea = 1024.f; } @@ -1106,7 +565,7 @@ void LLSpatialGroup::updateDistance(LLCamera &camera) { if (LLViewerCamera::sCurCameraID != LLViewerCamera::CAMERA_WORLD) { - llwarns << "Attempted to update distance for camera other than world camera!" << llendl; + LL_WARNS() << "Attempted to update distance for camera other than world camera!" << LL_ENDL; return; } @@ -1116,17 +575,17 @@ void LLSpatialGroup::updateDistance(LLCamera &camera) } #if !LL_RELEASE_FOR_DOWNLOAD - if (isState(LLSpatialGroup::OBJECT_DIRTY)) + if (hasState(LLSpatialGroup::eSpatialState(OBJECT_DIRTY))) { - llerrs << "Spatial group dirty on distance update." << llendl; + LL_ERRS() << "Spatial group dirty on distance update." << LL_ENDL; } #endif - if (!isEmpty() /*&& !LLSpatialPartition::sFreezeState*/) + if (!isEmpty()) { - mRadius = mSpatialPartition->mRenderByGroup ? mObjectBounds[1].getLength3().getF32() : + mRadius = getSpatialPartition()->mRenderByGroup ? mObjectBounds[1].getLength3().getF32() : (F32) mOctreeNode->getSize().getLength3().getF32(); - mDistance = mSpatialPartition->calcDistance(this, camera); - mPixelArea = mSpatialPartition->calcPixelArea(this, camera); + mDistance = getSpatialPartition()->calcDistance(this, camera); + mPixelArea = getSpatialPartition()->calcPixelArea(this, camera); } } @@ -1147,9 +606,9 @@ F32 LLSpatialPartition::calcDistance(LLSpatialGroup* group, LLCamera& camera) dist = eye.getLength3().getF32(); eye.normalize3fast(); - if (!group->isState(LLSpatialGroup::ALPHA_DIRTY)) + if (!group->hasState(LLSpatialGroup::ALPHA_DIRTY)) { - if (!group->mSpatialPartition->isBridge()) + if (!group->getSpatialPartition()->isBridge()) { LLVector4a view_angle = eye; @@ -1218,23 +677,18 @@ F32 LLSpatialGroup::getUpdateUrgency() const } } -BOOL LLSpatialGroup::needsUpdate() -{ - return (LLDrawable::getCurrentFrame()%mSpatialPartition->mLODPeriod == mLODHash) ? TRUE : FALSE; -} - BOOL LLSpatialGroup::changeLOD() { - if (isState(ALPHA_DIRTY | OBJECT_DIRTY)) + if (hasState(LLSpatialGroup::eSpatialState(ALPHA_DIRTY | OBJECT_DIRTY))) { ///a rebuild is going to happen, update distance and LoD return TRUE; } - if (mSpatialPartition->mSlopRatio > 0.f) + if (getSpatialPartition()->mSlopRatio > 0.f) { F32 ratio = (mDistance - mLastUpdateDistance)/(llmax(mLastUpdateDistance, mRadius)); - if (fabsf(ratio) >= mSpatialPartition->mSlopRatio) + if (fabsf(ratio) >= getSpatialPartition()->mSlopRatio) { return TRUE; } @@ -1253,71 +707,56 @@ BOOL LLSpatialGroup::changeLOD() return FALSE; } -void LLSpatialGroup::handleInsertion(const TreeNode* node, LLDrawable* drawablep) +void LLSpatialGroup::handleInsertion(const TreeNode* node, LLViewerOctreeEntry* entry) { - addObject(drawablep, FALSE, TRUE); + addObject((LLDrawable*)entry->getDrawable()); unbound(); - setState(OBJECT_DIRTY); + setState(LLSpatialGroup::eSpatialState(OBJECT_DIRTY)); } -void LLSpatialGroup::handleRemoval(const TreeNode* node, LLDrawable* drawable) +void LLSpatialGroup::handleRemoval(const TreeNode* node, LLViewerOctreeEntry* entry) { - removeObject(drawable, TRUE); - setState(OBJECT_DIRTY); + removeObject((LLDrawable*)entry->getDrawable(), TRUE); + LLViewerOctreeGroup::handleRemoval(node, entry); } void LLSpatialGroup::handleDestruction(const TreeNode* node) { - setState(DEAD); - - {OctreeGuard guard(mOctreeNode); - for (element_iter i = getDataBegin(); i != getDataEnd(); ++i) + if(isDead()) { - LLDrawable* drawable = *i; - if (drawable->getSpatialGroup() == this) - { - drawable->setSpatialGroup(NULL); - } - } + return; } - - //clean up avatar attachment stats - LLSpatialBridge* bridge = mSpatialPartition->asBridge(); - if (bridge) + setState(LLSpatialGroup::eSpatialState(DEAD)); + + for (element_iter i = getDataBegin(); i != getDataEnd(); ++i) { - if (bridge->mAvatar.notNull()) + LLViewerOctreeEntry* entry = *i; + + if (entry->getGroup() == this) { - bridge->mAvatar->mAttachmentGeometryBytes -= mGeometryBytes; - bridge->mAvatar->mAttachmentSurfaceArea -= mSurfaceArea; + if(entry->hasDrawable()) + { + ((LLDrawable*)entry->getDrawable())->setGroup(NULL); + } } } - + clearDrawMap(); mVertexBuffer = NULL; - mBufferMap.clear(); + mBufferVec.clear(); sZombieGroups++; mOctreeNode = NULL; } -void LLSpatialGroup::handleStateChange(const TreeNode* node) -{ - //drop bounding box upon state change - if (mOctreeNode != node) - { - mOctreeNode = (OctreeNode*) node; - } - unbound(); -} - void LLSpatialGroup::handleChildAddition(const OctreeNode* parent, OctreeNode* child) { if (child->getListenerCount() == 0) { - new LLSpatialGroup(child, mSpatialPartition); + LLPointer tmp = new LLSpatialGroup(child, getSpatialPartition()); } else { - OCT_ERRS << "LLSpatialGroup redundancy detected." << llendl; + OCT_ERRS << "LLSpatialGroup redundancy detected." << LL_ENDL; } unbound(); @@ -1325,332 +764,41 @@ void LLSpatialGroup::handleChildAddition(const OctreeNode* parent, OctreeNode* c assert_states_valid(this); } -void LLSpatialGroup::handleChildRemoval(const OctreeNode* parent, const OctreeNode* child) -{ - unbound(); -} - void LLSpatialGroup::destroyGL(bool keep_occlusion) { setState(LLSpatialGroup::GEOM_DIRTY | LLSpatialGroup::IMAGE_DIRTY); - if (!keep_occlusion) - { //going to need a rebuild - gPipeline.markRebuild(this, TRUE); - } - - mLastUpdateTime = gFrameTimeSeconds; - mVertexBuffer = NULL; - mBufferMap.clear(); - - clearDrawMap(); - - if (!keep_occlusion) - { - for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++) - { - if (mOcclusionQuery[i]) - { - sQueryPool.release(mOcclusionQuery[i]); - mOcclusionQuery[i] = 0; - } - } - } - - - OctreeGuard guard(mOctreeNode); - for (LLSpatialGroup::element_iter i = getDataBegin(); i != getDataEnd(); ++i) - { - LLDrawable* drawable = *i; - for (S32 j = 0; j < drawable->getNumFaces(); j++) - { - LLFace* facep = drawable->getFace(j); - if (facep) - { - facep->clearVertexBuffer(); - } - } - } -} - -BOOL LLSpatialGroup::rebound() -{ - if (!isState(DIRTY)) - { //return TRUE if we're not empty - return TRUE; - } - - if (mOctreeNode->getChildCount() == 1 && mOctreeNode->getElementCount() == 0) - { - LLSpatialGroup* group = (LLSpatialGroup*) mOctreeNode->getChild(0)->getListener(0); - group->rebound(); - - //copy single child's bounding box - mBounds[0] = group->mBounds[0]; - mBounds[1] = group->mBounds[1]; - mExtents[0] = group->mExtents[0]; - mExtents[1] = group->mExtents[1]; - - group->setState(SKIP_FRUSTUM_CHECK); - } - else if (mOctreeNode->isLeaf()) - { //copy object bounding box if this is a leaf - boundObjects(TRUE, mExtents[0], mExtents[1]); - mBounds[0] = mObjectBounds[0]; - mBounds[1] = mObjectBounds[1]; - } - else - { - LLVector4a& newMin = mExtents[0]; - LLVector4a& newMax = mExtents[1]; - LLSpatialGroup* group = (LLSpatialGroup*) mOctreeNode->getChild(0)->getListener(0); - group->clearState(SKIP_FRUSTUM_CHECK); - group->rebound(); - //initialize to first child - newMin = group->mExtents[0]; - newMax = group->mExtents[1]; - - //first, rebound children - for (U32 i = 1; i < mOctreeNode->getChildCount(); i++) - { - group = (LLSpatialGroup*) mOctreeNode->getChild(i)->getListener(0); - group->clearState(SKIP_FRUSTUM_CHECK); - group->rebound(); - const LLVector4a& max = group->mExtents[1]; - const LLVector4a& min = group->mExtents[0]; - - newMax.setMax(newMax, max); - newMin.setMin(newMin, min); - } - - boundObjects(FALSE, newMin, newMax); - - mBounds[0].setAdd(newMin, newMax); - mBounds[0].mul(0.5f); - mBounds[1].setSub(newMax, newMin); - mBounds[1].mul(0.5f); - } - - clearState(DIRTY); - - return TRUE; -} - -static LLFastTimer::DeclareTimer FTM_OCCLUSION_READBACK("Readback Occlusion"); -static LLFastTimer::DeclareTimer FTM_OCCLUSION_WAIT("Occlusion Wait"); - -void LLSpatialGroup::checkOcclusion() -{ - if (LLPipeline::sUseOcclusion > 1) - { - LLFastTimer t(FTM_OCCLUSION_READBACK); - LLSpatialGroup* parent = getParent(); - if (parent && parent->isOcclusionState(LLSpatialGroup::OCCLUDED)) - { //if the parent has been marked as occluded, the child is implicitly occluded - clearOcclusionState(QUERY_PENDING | DISCARD_QUERY); - } - else if (isOcclusionState(QUERY_PENDING)) - { //otherwise, if a query is pending, read it back - - GLuint available = 0; - if (mOcclusionQuery[LLViewerCamera::sCurCameraID]) - { - glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_AVAILABLE_ARB, &available); - - static LLCachedControl wait_for_query("RenderSynchronousOcclusion", true); - - if (wait_for_query && mOcclusionIssued[LLViewerCamera::sCurCameraID] < gFrameCount) - { //query was issued last frame, wait until it's available - S32 max_loop = 1024; - LLFastTimer t(FTM_OCCLUSION_WAIT); - while (!available && max_loop-- > 0) - { - F32 max_time = llmin(gFrameIntervalSeconds*10.f, 1.f); - //do some usefu work while we wait - LLAppViewer::getTextureCache()->update(max_time); // unpauses the texture cache thread - LLAppViewer::getImageDecodeThread()->update(max_time); // unpauses the image thread - LLAppViewer::getTextureFetch()->update(max_time); // unpauses the texture fetch thread - - glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_AVAILABLE_ARB, &available); - } - } - } - else - { - available = 1; - } - - if (available) - { //result is available, read it back, otherwise wait until next frame - GLuint res = 1; - if (!isOcclusionState(DISCARD_QUERY) && mOcclusionQuery[LLViewerCamera::sCurCameraID]) - { - glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_ARB, &res); -#if LL_TRACK_PENDING_OCCLUSION_QUERIES - sPendingQueries.erase(mOcclusionQuery[LLViewerCamera::sCurCameraID]); -#endif - } - else if (mOcclusionQuery[LLViewerCamera::sCurCameraID]) - { //delete the query to avoid holding onto hundreds of pending queries - sQueryPool.release(mOcclusionQuery[LLViewerCamera::sCurCameraID]); - mOcclusionQuery[LLViewerCamera::sCurCameraID] = 0; - } - - if (isOcclusionState(DISCARD_QUERY)) - { - res = 2; - } - - if (res > 0) - { - assert_states_valid(this); - clearOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF); - assert_states_valid(this); - } - else - { - assert_states_valid(this); - setOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF); - assert_states_valid(this); - } - - clearOcclusionState(QUERY_PENDING | DISCARD_QUERY); - } - } - else if (mSpatialPartition->isOcclusionEnabled() && isOcclusionState(LLSpatialGroup::OCCLUDED)) - { //check occlusion has been issued for occluded node that has not had a query issued - assert_states_valid(this); - clearOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF); - assert_states_valid(this); - } + if (!keep_occlusion) + { //going to need a rebuild + gPipeline.markRebuild(this, TRUE); } -} -static LLFastTimer::DeclareTimer FTM_PUSH_OCCLUSION_VERTS("Push Occlusion"); -static LLFastTimer::DeclareTimer FTM_SET_OCCLUSION_STATE("Occlusion State"); -static LLFastTimer::DeclareTimer FTM_OCCLUSION_EARLY_FAIL("Occlusion Early Fail"); -static LLFastTimer::DeclareTimer FTM_OCCLUSION_ALLOCATE("Allocate"); -static LLFastTimer::DeclareTimer FTM_OCCLUSION_BUILD("Build"); -static LLFastTimer::DeclareTimer FTM_OCCLUSION_BEGIN_QUERY("Begin Query"); -static LLFastTimer::DeclareTimer FTM_OCCLUSION_END_QUERY("End Query"); -static LLFastTimer::DeclareTimer FTM_OCCLUSION_SET_BUFFER("Set Buffer"); -static LLFastTimer::DeclareTimer FTM_OCCLUSION_DRAW_WATER("Draw Water"); -static LLFastTimer::DeclareTimer FTM_OCCLUSION_DRAW("Draw"); + mLastUpdateTime = gFrameTimeSeconds; + mVertexBuffer = NULL; + mBufferVec.clear(); + + clearDrawMap(); + if (!keep_occlusion) + { + releaseOcclusionQueryObjectNames(); + } -void LLSpatialGroup::doOcclusion(LLCamera* camera) -{ - if (mSpatialPartition->isOcclusionEnabled() && LLPipeline::sUseOcclusion > 1) + OctreeGuard guard(mOctreeNode); + for (LLSpatialGroup::element_iter i = getDataBegin(); i != getDataEnd(); ++i) { - //static const LLCachedControl render_water_void_culling("RenderWaterVoidCulling", TRUE); - // Don't cull hole/edge water, unless RenderWaterVoidCulling is set and we have the GL_ARB_depth_clamp extension. - //if ((mSpatialPartition->mDrawableType == LLDrawPool::POOL_VOIDWATER && !gGLManager.mHasDepthClamp) || - // earlyFail(camera, this)) - if (earlyFail(camera, this)) //Returns true if camera is inside this spatial group. + LLDrawable* drawable = (LLDrawable*)(*i)->getDrawable(); + if(!drawable) { - LLFastTimer t(FTM_OCCLUSION_EARLY_FAIL); - setOcclusionState(LLSpatialGroup::DISCARD_QUERY); - assert_states_valid(this); - clearOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF); - assert_states_valid(this); + continue; } - else + for (S32 j = 0; j < drawable->getNumFaces(); j++) { - if (!isOcclusionState(QUERY_PENDING) || isOcclusionState(DISCARD_QUERY)) + LLFace* facep = drawable->getFace(j); + if (facep) { - { //no query pending, or previous query to be discarded - LLFastTimer t(FTM_RENDER_OCCLUSION); - - if (!mOcclusionQuery[LLViewerCamera::sCurCameraID]) - { - LLFastTimer t(FTM_OCCLUSION_ALLOCATE); - mOcclusionQuery[LLViewerCamera::sCurCameraID] = sQueryPool.allocate(); - } - - // Depth clamp all water to avoid it being culled as a result of being - // behind the far clip plane, and in the case of edge water to avoid - // it being culled while still visible. - bool const use_depth_clamp = gGLManager.mHasDepthClamp && - (mSpatialPartition->mDrawableType == LLDrawPool::POOL_WATER || - mSpatialPartition->mDrawableType == LLDrawPool::POOL_VOIDWATER); - - LLGLEnable clamp(use_depth_clamp ? GL_DEPTH_CLAMP : 0); - -#if !LL_DARWIN - U32 mode = gGLManager.mHasOcclusionQuery2 ? GL_ANY_SAMPLES_PASSED : GL_SAMPLES_PASSED_ARB; -#else - U32 mode = GL_SAMPLES_PASSED_ARB; -#endif - -#if LL_TRACK_PENDING_OCCLUSION_QUERIES - sPendingQueries.insert(mOcclusionQuery[LLViewerCamera::sCurCameraID]); -#endif - - { - LLFastTimer t(FTM_PUSH_OCCLUSION_VERTS); - - //store which frame this query was issued on - mOcclusionIssued[LLViewerCamera::sCurCameraID] = gFrameCount; - - { - LLFastTimer t(FTM_OCCLUSION_BEGIN_QUERY); - glBeginQueryARB(mode, mOcclusionQuery[LLViewerCamera::sCurCameraID]); - } - - LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; - llassert(shader); - - shader->uniform3fv(LLShaderMgr::BOX_CENTER, 1, mBounds[0].getF32ptr()); - //static LLVector4a fudge(SG_OCCLUSION_FUDGE); - static LLCachedControl vel("SHOcclusionFudge",SG_OCCLUSION_FUDGE); - LLVector4a fudge(SG_OCCLUSION_FUDGE); - static LLVector4a bounds; - bounds.setAdd(fudge,mBounds[1]); - shader->uniform3fv(LLShaderMgr::BOX_SIZE, 1, bounds.getF32ptr()); - - if (!use_depth_clamp && mSpatialPartition->mDrawableType == LLDrawPool::POOL_VOIDWATER) - { - LLFastTimer t(FTM_OCCLUSION_DRAW_WATER); - - LLGLSquashToFarClip squash(glh_get_current_projection(), 1); - if (camera->getOrigin().isExactlyZero()) - { //origin is invalid, draw entire box - gPipeline.mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0); - gPipeline.mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, b111*8); - } - else - { - gPipeline.mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, mBounds[0])); - } - } - else - { - LLFastTimer t(FTM_OCCLUSION_DRAW); - if (camera->getOrigin().isExactlyZero()) - { //origin is invalid, draw entire box - gPipeline.mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0); - gPipeline.mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, b111*8); - } - else - { - gPipeline.mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, mBounds[0])); - } - } - - - { - LLFastTimer t(FTM_OCCLUSION_END_QUERY); - glEndQueryARB(mode); - } - } - } - - { - LLFastTimer t(FTM_SET_OCCLUSION_STATE); - setOcclusionState(LLSpatialGroup::QUERY_PENDING); - clearOcclusionState(LLSpatialGroup::DISCARD_QUERY); - } + facep->clearVertexBuffer(); } } } @@ -1658,34 +806,23 @@ void LLSpatialGroup::doOcclusion(LLCamera* camera) //============================================== -LLSpatialPartition::LLSpatialPartition(U32 data_mask, BOOL render_by_group, U32 buffer_usage) +LLSpatialPartition::LLSpatialPartition(U32 data_mask, BOOL render_by_group, U32 buffer_usage, LLViewerRegion* regionp) : mRenderByGroup(render_by_group), mBridge(NULL) { - mOcclusionEnabled = TRUE; - mDrawableType = 0; + mRegionp = regionp; mPartitionType = LLViewerRegion::PARTITION_NONE; - mLODSeed = 0; - mLODPeriod = 1; mVertexDataMask = data_mask; mBufferUsage = buffer_usage; mDepthMask = FALSE; mSlopRatio = 0.25f; mInfiniteFarClip = FALSE; - LLVector4a center, size; - center.splat(0.f); - size.splat(1.f); - - mOctree = new LLSpatialGroup::OctreeRoot(center,size, - NULL); - new LLSpatialGroup(mOctree, this); + LLPointer tmp = new LLSpatialGroup(mOctree, this); } LLSpatialPartition::~LLSpatialPartition() { - delete mOctree; - mOctree = NULL; } @@ -1696,11 +833,15 @@ LLSpatialGroup *LLSpatialPartition::put(LLDrawable *drawablep, BOOL was_visible) //keep drawable from being garbage collected LLPointer ptr = drawablep; + if(!drawablep->getGroup()) + { assert_octree_valid(mOctree); - mOctree->insert(drawablep); + mOctree->insert(drawablep->getEntry()); assert_octree_valid(mOctree); + } LLSpatialGroup* group = drawablep->getSpatialGroup(); + llassert(group != NULL); if (group && was_visible && group->isOcclusionState(LLSpatialGroup::QUERY_PENDING)) { @@ -1714,15 +855,13 @@ BOOL LLSpatialPartition::remove(LLDrawable *drawablep, LLSpatialGroup *curp) { if (!curp->removeObject(drawablep)) { - OCT_ERRS << "Failed to remove drawable from octree!" << llendl; + OCT_ERRS << "Failed to remove drawable from octree!" << LL_ENDL; } else { - drawablep->setSpatialGroup(NULL); + drawablep->setGroup(NULL); } - drawablep->setSpatialGroup(NULL); - assert_octree_valid(mOctree); return TRUE; @@ -1734,24 +873,24 @@ void LLSpatialPartition::move(LLDrawable *drawablep, LLSpatialGroup *curp, BOOL // who was seeing crashing here. (See VWR-424 reported by Bunny Mayne) if (!drawablep) { - OCT_ERRS << "LLSpatialPartition::move was passed a bad drawable." << llendl; + OCT_ERRS << "LLSpatialPartition::move was passed a bad drawable." << LL_ENDL; return; } BOOL was_visible = curp ? curp->isVisible() : FALSE; - if (curp && curp->mSpatialPartition != this) + if (curp && curp->getSpatialPartition() != this) { //keep drawable from being garbage collected LLPointer ptr = drawablep; - if (curp->mSpatialPartition->remove(drawablep, curp)) + if (curp->getSpatialPartition()->remove(drawablep, curp)) { put(drawablep, was_visible); return; } else { - OCT_ERRS << "Drawable lost between spatial partitions on outbound transition." << llendl; + OCT_ERRS << "Drawable lost between spatial partitions on outbound transition." << LL_ENDL; } } @@ -1766,19 +905,19 @@ void LLSpatialPartition::move(LLDrawable *drawablep, LLSpatialGroup *curp, BOOL LLPointer ptr = drawablep; if (curp && !remove(drawablep, curp)) { - OCT_ERRS << "Move couldn't find existing spatial group!" << llendl; + OCT_ERRS << "Move couldn't find existing spatial group!" << LL_ENDL; } put(drawablep, was_visible); } -class LLSpatialShift : public LLSpatialGroup::OctreeTraveler +class LLSpatialShift : public OctreeTraveler { public: const LLVector4a& mOffset; LLSpatialShift(const LLVector4a& offset) : mOffset(offset) { } - virtual void visit(const LLSpatialGroup::OctreeNode* branch) + virtual void visit(const OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->shift(mOffset); } @@ -1790,17 +929,17 @@ void LLSpatialPartition::shift(const LLVector4a &offset) shifter.traverse(mOctree); } -class LLOctreeCull : public LLSpatialGroup::OctreeTraveler +class LLOctreeCull : public LLViewerOctreeCull { public: - LLOctreeCull(LLCamera* camera) - : mCamera(camera), mRes(0) { } + LLOctreeCull(LLCamera* camera) : LLViewerOctreeCull(camera) {} - virtual bool earlyFail(LLSpatialGroup* group) + virtual bool earlyFail(LLViewerOctreeGroup* base_group) { + LLSpatialGroup* group = (LLSpatialGroup*)base_group; group->checkOcclusion(); - if (group->mOctreeNode->getParent() && //never occlusion cull the root node + if (group->getOctreeNode()->getParent() && //never occlusion cull the root node LLPipeline::sUseOcclusion && //ignore occlusion if disabled group->isOcclusionState(LLSpatialGroup::OCCLUDED)) { @@ -1811,100 +950,36 @@ class LLOctreeCull : public LLSpatialGroup::OctreeTraveler return false; } - virtual void traverse(const LLSpatialGroup::OctreeNode* n) - { - LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0); - - if (earlyFail(group)) - { - return; - } - - if (mRes == 2 || - (mRes && group->isState(LLSpatialGroup::SKIP_FRUSTUM_CHECK))) - { //fully in, just add everything - LLSpatialGroup::OctreeTraveler::traverse(n); - } - else - { - mRes = frustumCheck(group); - - if (mRes) - { //at least partially in, run on down - LLSpatialGroup::OctreeTraveler::traverse(n); - } - - mRes = 0; - } - } - - virtual S32 frustumCheck(const LLSpatialGroup* group) + virtual S32 frustumCheck(const LLViewerOctreeGroup* group) { - S32 res = mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1]); + S32 res = AABBInFrustumNoFarClipGroupBounds(group); if (res != 0) { - res = llmin(res, AABBSphereIntersect(group->mExtents[0], group->mExtents[1], mCamera->getOrigin(), mCamera->mFrustumCornerDist)); + res = llmin(res, AABBSphereIntersectGroupExtents(group)); } return res; } - virtual S32 frustumCheckObjects(const LLSpatialGroup* group) + virtual S32 frustumCheckObjects(const LLViewerOctreeGroup* group) { - S32 res = mCamera->AABBInFrustumNoFarClip(group->mObjectBounds[0], group->mObjectBounds[1]); + S32 res = AABBInFrustumNoFarClipObjectBounds(group); if (res != 0) { - res = llmin(res, AABBSphereIntersect(group->mObjectExtents[0], group->mObjectExtents[1], mCamera->getOrigin(), mCamera->mFrustumCornerDist)); + res = llmin(res, AABBSphereIntersectObjectExtents(group)); } return res; } - virtual bool checkObjects(const LLSpatialGroup::OctreeNode* branch, const LLSpatialGroup* group) - { - if (branch->getElementCount() == 0) //no elements - { - return false; - } - else if (branch->getChildCount() == 0) //leaf state, already checked tightest bounding box - { - return true; - } - else if (mRes == 1 && !frustumCheckObjects(group)) //no objects in frustum - { - return false; - } - - return true; - } - - virtual void preprocess(LLSpatialGroup* group) - { - - } - - virtual void processGroup(LLSpatialGroup* group) + virtual void processGroup(LLViewerOctreeGroup* base_group) { + LLSpatialGroup* group = (LLSpatialGroup*)base_group; if (group->needsUpdate() || - group->mVisible[LLViewerCamera::sCurCameraID] < LLDrawable::getCurrentFrame() - 1) + group->getVisible(LLViewerCamera::sCurCameraID) < LLDrawable::getCurrentFrame() - 1) { group->doOcclusion(mCamera); } gPipeline.markNotCulled(group, *mCamera); } - - virtual void visit(const LLSpatialGroup::OctreeNode* branch) - { - LLSpatialGroup* group = (LLSpatialGroup*) branch->getListener(0); - - preprocess(group); - - if (checkObjects(branch, group)) - { - processGroup(group); - } - } - - LLCamera *mCamera; - S32 mRes; }; class LLOctreeCullNoFarClip : public LLOctreeCull @@ -1913,14 +988,14 @@ class LLOctreeCullNoFarClip : public LLOctreeCull LLOctreeCullNoFarClip(LLCamera* camera) : LLOctreeCull(camera) { } - virtual S32 frustumCheck(const LLSpatialGroup* group) + virtual S32 frustumCheck(const LLViewerOctreeGroup* group) { - return mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1]); + return AABBInFrustumNoFarClipGroupBounds(group); } - virtual S32 frustumCheckObjects(const LLSpatialGroup* group) + virtual S32 frustumCheckObjects(const LLViewerOctreeGroup* group) { - S32 res = mCamera->AABBInFrustumNoFarClip(group->mObjectBounds[0], group->mObjectBounds[1]); + S32 res = AABBInFrustumNoFarClipObjectBounds(group); return res; } }; @@ -1931,14 +1006,14 @@ class LLOctreeCullShadow : public LLOctreeCull LLOctreeCullShadow(LLCamera* camera) : LLOctreeCull(camera) { } - virtual S32 frustumCheck(const LLSpatialGroup* group) + virtual S32 frustumCheck(const LLViewerOctreeGroup* group) { - return mCamera->AABBInFrustum(group->mBounds[0], group->mBounds[1]); + return AABBInFrustumGroupBounds(group); } - virtual S32 frustumCheckObjects(const LLSpatialGroup* group) + virtual S32 frustumCheckObjects(const LLViewerOctreeGroup* group) { - return mCamera->AABBInFrustum(group->mObjectBounds[0], group->mObjectBounds[1]); + return AABBInFrustumObjectBounds(group); } }; @@ -1948,9 +1023,11 @@ class LLOctreeCullVisExtents: public LLOctreeCullShadow LLOctreeCullVisExtents(LLCamera* camera, LLVector4a& min, LLVector4a& max) : LLOctreeCullShadow(camera), mMin(min), mMax(max), mEmpty(TRUE) { } - virtual bool earlyFail(LLSpatialGroup* group) + virtual bool earlyFail(LLViewerOctreeGroup* base_group) { - if (group->mOctreeNode->getParent() && //never occlusion cull the root node + LLSpatialGroup* group = (LLSpatialGroup*)base_group; + + if (group->getOctreeNode()->getParent() && //never occlusion cull the root node LLPipeline::sUseOcclusion && //ignore occlusion if disabled group->isOcclusionState(LLSpatialGroup::OCCLUDED)) { @@ -1960,7 +1037,7 @@ class LLOctreeCullVisExtents: public LLOctreeCullShadow return false; } - virtual void traverse(const LLSpatialGroup::OctreeNode* n) + virtual void traverse(const OctreeNode* n) { LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0); @@ -1969,10 +1046,10 @@ class LLOctreeCullVisExtents: public LLOctreeCullShadow return; } - if ((mRes && group->isState(LLSpatialGroup::SKIP_FRUSTUM_CHECK)) || + if ((mRes && group->hasState(LLSpatialGroup::eSpatialState(LLSpatialGroup::SKIP_FRUSTUM_CHECK))) || mRes == 2) { //don't need to do frustum check - LLSpatialGroup::OctreeTraveler::traverse(n); + OctreeTraveler::traverse(n); } else { @@ -1980,31 +1057,35 @@ class LLOctreeCullVisExtents: public LLOctreeCullShadow if (mRes) { //at least partially in, run on down - LLSpatialGroup::OctreeTraveler::traverse(n); + OctreeTraveler::traverse(n); } mRes = 0; } } - virtual void processGroup(LLSpatialGroup* group) + virtual void processGroup(LLViewerOctreeGroup* base_group) { - llassert(!group->isState(LLSpatialGroup::DIRTY) && !group->isEmpty()); + LLSpatialGroup* group = (LLSpatialGroup*)base_group; + + llassert(!group->hasState(LLSpatialGroup::eSpatialState(LLSpatialGroup::DIRTY)) && !group->isEmpty()); if (mRes < 2) { - if (mCamera->AABBInFrustum(group->mObjectBounds[0], group->mObjectBounds[1]) > 0) + if (AABBInFrustumObjectBounds(group) > 0) { mEmpty = FALSE; - update_min_max(mMin, mMax, group->mObjectExtents[0]); - update_min_max(mMin, mMax, group->mObjectExtents[1]); + const LLVector4a* exts = group->getObjectExtents(); + update_min_max(mMin, mMax, exts[0]); + update_min_max(mMin, mMax, exts[1]); } } else { mEmpty = FALSE; - update_min_max(mMin, mMax, group->mExtents[0]); - update_min_max(mMin, mMax, group->mExtents[1]); + const LLVector4a* exts = group->getExtents(); + update_min_max(mMin, mMax, exts[0]); + update_min_max(mMin, mMax, exts[1]); } } @@ -2019,10 +1100,12 @@ class LLOctreeCullDetectVisible: public LLOctreeCullShadow LLOctreeCullDetectVisible(LLCamera* camera) : LLOctreeCullShadow(camera), mResult(FALSE) { } - virtual bool earlyFail(LLSpatialGroup* group) + virtual bool earlyFail(LLViewerOctreeGroup* base_group) { + LLSpatialGroup* group = (LLSpatialGroup*)base_group; + if (mResult || //already found a node, don't check any more - (group->mOctreeNode->getParent() && //never occlusion cull the root node + (group->getOctreeNode()->getParent() && //never occlusion cull the root node LLPipeline::sUseOcclusion && //ignore occlusion if disabled group->isOcclusionState(LLSpatialGroup::OCCLUDED))) { @@ -2032,9 +1115,9 @@ class LLOctreeCullDetectVisible: public LLOctreeCullShadow return false; } - virtual void processGroup(LLSpatialGroup* group) + virtual void processGroup(LLViewerOctreeGroup* base_group) { - if (group->isVisible()) + if (base_group->isVisible()) { mResult = TRUE; } @@ -2049,18 +1132,21 @@ class LLOctreeSelect : public LLOctreeCull LLOctreeSelect(LLCamera* camera, std::vector* results) : LLOctreeCull(camera), mResults(results) { } - virtual bool earlyFail(LLSpatialGroup* group) { return false; } - virtual void preprocess(LLSpatialGroup* group) { } + virtual bool earlyFail(LLViewerOctreeGroup* group) { return false; } + virtual void preprocess(LLViewerOctreeGroup* group) { } - virtual void processGroup(LLSpatialGroup* group) + virtual void processGroup(LLViewerOctreeGroup* base_group) { - LLSpatialGroup::OctreeNode* branch = group->mOctreeNode; + LLSpatialGroup* group = (LLSpatialGroup*)base_group; + OctreeNode* branch = group->getOctreeNode(); - OctreeGuard guard(branch); - for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getDataBegin(); i != branch->getDataEnd(); ++i) + for (OctreeNode::const_element_iter i = branch->getDataBegin(); i != branch->getDataEnd(); ++i) { - LLDrawable* drawable = *i; - + LLDrawable* drawable = (LLDrawable*)(*i)->getDrawable(); + if(!drawable) + { + continue; + } if (!drawable->isDead()) { if (drawable->isSpatialBridge()) @@ -2173,31 +1259,40 @@ void drawBoxOutline(const LLVector4a& pos, const LLVector4a& size) drawBoxOutline(reinterpret_cast(pos), reinterpret_cast(size)); } -class LLOctreeDirty : public LLOctreeTraveler +class LLOctreeDirty : public OctreeTraveler { public: - virtual void visit(const LLOctreeNode* state) + LLOctreeDirty(bool no_rebuild = false) : mNoRebuild(no_rebuild){} + + virtual void visit(const OctreeNode* state) { LLSpatialGroup* group = (LLSpatialGroup*) state->getListener(0); group->destroyGL(); - {OctreeGuard guard(group->mOctreeNode); + {OctreeGuard guard(group->getOctreeNode()); + if (!mNoRebuild) // Singu note: No need to iterate if not rebuilding... for (LLSpatialGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i) { - LLDrawable* drawable = *i; - if (drawable->getVObj().notNull() && !group->mSpatialPartition->mRenderByGroup) + LLDrawable* drawable = (LLDrawable*)(*i)->getDrawable(); + if(!drawable) + { + continue; + } + if (!mNoRebuild && drawable->getVObj().notNull() && !group->getSpatialPartition()->mRenderByGroup) { gPipeline.markRebuild(drawable, LLDrawable::REBUILD_ALL, TRUE); } } - } for (LLSpatialGroup::bridge_list_t::iterator i = group->mBridgeList.begin(); i != group->mBridgeList.end(); ++i) { LLSpatialBridge* bridge = *i; traverse(bridge->mOctree); - } + }} } + +private: + BOOL mNoRebuild; }; void LLSpatialPartition::restoreGL() @@ -2206,22 +1301,18 @@ void LLSpatialPartition::restoreGL() void LLSpatialPartition::resetVertexBuffers() { - LLOctreeDirty dirty; + LLOctreeDirty dirty(sTeleportRequested); dirty.traverse(mOctree); } -BOOL LLSpatialPartition::isOcclusionEnabled() -{ - return mOcclusionEnabled || LLPipeline::sUseOcclusion > 2; -} - BOOL LLSpatialPartition::getVisibleExtents(LLCamera& camera, LLVector3& visMin, LLVector3& visMax) { LLVector4a visMina, visMaxa; visMina.load3(visMin.mV); visMaxa.load3(visMax.mV); + { - LLFastTimer ftm(FTM_CULL_REBOUND); + LL_RECORD_BLOCK_TIME(FTM_CULL_REBOUND); LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0); group->rebound(); } @@ -2241,7 +1332,7 @@ BOOL LLSpatialPartition::visibleObjectsInFrustum(LLCamera& camera) return vis.mResult; } -S32 LLSpatialPartition::cull(LLCamera &camera, std::vector* results, BOOL for_select) +S32 LLSpatialPartition::cull(LLCamera &camera, std::vector* results) { #if LL_OCTREE_PARANOIA_CHECK ((LLSpatialGroup*)mOctree->getListener(0))->checkStates(); @@ -2249,7 +1340,7 @@ S32 LLSpatialPartition::cull(LLCamera &camera, std::vector* result { //BOOL temp = sFreezeState; //sFreezeState = FALSE; - LLFastTimer ftm(FTM_CULL_REBOUND); + LL_RECORD_BLOCK_TIME(FTM_CULL_REBOUND); LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0); group->rebound(); //sFreezeState = temp; @@ -2259,27 +1350,41 @@ S32 LLSpatialPartition::cull(LLCamera &camera, std::vector* result ((LLSpatialGroup*)mOctree->getListener(0))->validate(); #endif - - if (for_select) + LLOctreeSelect selecter(&camera, results); + selecter.traverse(mOctree); + + return 0; +} +S32 LLSpatialPartition::cull(LLCamera &camera, bool do_occlusion) +{ +#if LL_OCTREE_PARANOIA_CHECK + ((LLSpatialGroup*)mOctree->getListener(0))->checkStates(); +#endif { - LLOctreeSelect selecter(&camera, results); - selecter.traverse(mOctree); + LL_RECORD_BLOCK_TIME(FTM_CULL_REBOUND); + LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0); + group->rebound(); } - else if (LLPipeline::sShadowRender) + +#if LL_OCTREE_PARANOIA_CHECK + ((LLSpatialGroup*)mOctree->getListener(0))->validate(); +#endif + + if (LLPipeline::sShadowRender) { - LLFastTimer ftm(FTM_FRUSTUM_CULL); + LL_RECORD_BLOCK_TIME(FTM_FRUSTUM_CULL); LLOctreeCullShadow culler(&camera); culler.traverse(mOctree); } else if (mInfiniteFarClip || !LLPipeline::sUseFarClip) { - LLFastTimer ftm(FTM_FRUSTUM_CULL); + LL_RECORD_BLOCK_TIME(FTM_FRUSTUM_CULL); LLOctreeCullNoFarClip culler(&camera); culler.traverse(mOctree); } else { - LLFastTimer ftm(FTM_FRUSTUM_CULL); + LL_RECORD_BLOCK_TIME(FTM_FRUSTUM_CULL); LLOctreeCull culler(&camera); culler.traverse(mOctree); } @@ -2287,49 +1392,6 @@ S32 LLSpatialPartition::cull(LLCamera &camera, std::vector* result return 0; } -BOOL earlyFail(LLCamera* camera, LLSpatialGroup* group) -{ - if (camera->getOrigin().isExactlyZero()) - { - return FALSE; - } - - static LLCachedControl vel("SHOcclusionFudge",SG_OCCLUSION_FUDGE); - LLVector4a fudge(vel*2.f); - - const LLVector4a& c = group->mBounds[0]; - static LLVector4a r; - r.setAdd(group->mBounds[1], fudge); - - /*if (r.magVecSquared() > 1024.0*1024.0) - { - return TRUE; - }*/ - - LLVector4a e; - e.load3(camera->getOrigin().mV); - - LLVector4a min; - min.setSub(c,r); - LLVector4a max; - max.setAdd(c,r); - - S32 lt = e.lessThan(min).getGatheredBits() & 0x7; - if (lt) - { - return FALSE; - } - - S32 gt = e.greaterThan(max).getGatheredBits() & 0x7; - if (gt) - { - return FALSE; - } - - return TRUE; -} - - void pushVerts(LLDrawInfo* params, U32 mask) { LLRenderPass::applyModelMatrix(*params); @@ -2386,7 +1448,7 @@ void pushVerts(LLVolume* volume) for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i) { const LLVolumeFace& face = volume->getVolumeFace(i); - LLVertexBuffer::drawElements(LLRender::TRIANGLES, face.mPositions, NULL, face.mNumIndices, face.mIndices); + LLVertexBuffer::drawElements(LLRender::TRIANGLES, face.mNumVertices, face.mPositions, NULL, face.mNumIndices, face.mIndices); } } @@ -2399,20 +1461,23 @@ void pushBufferVerts(LLVertexBuffer* buffer, U32 mask) } } -void pushBufferVerts(LLSpatialGroup* group, U32 mask) +void pushBufferVerts(LLSpatialGroup* group, U32 mask, bool push_alpha = true) { - if (group->mSpatialPartition->mRenderByGroup) + if (group->getSpatialPartition()->mRenderByGroup) { if (!group->mDrawMap.empty() && !group->mDrawMap.begin()->second.empty()) { LLDrawInfo* params = *(group->mDrawMap.begin()->second.begin()); LLRenderPass::applyModelMatrix(*params); - pushBufferVerts(group->mVertexBuffer, mask); + if (push_alpha) + { + pushBufferVerts(group->mVertexBuffer, mask); + } - for (LLSpatialGroup::buffer_map_t::iterator i = group->mBufferMap.begin(); i != group->mBufferMap.end(); ++i) + for (LLSpatialGroup::buffer_vec_t::iterator i = group->mBufferVec.begin(); i != group->mBufferVec.end(); ++i) { - for (LLSpatialGroup::buffer_texture_map_t::iterator j = i->second.begin(); j != i->second.end(); ++j) + for (LLSpatialGroup::buffer_texture_vec_t::iterator j = i->second.begin(); j != i->second.end(); ++j) { for (LLSpatialGroup::buffer_list_t::iterator k = j->second.begin(); k != j->second.end(); ++k) { @@ -2424,7 +1489,8 @@ void pushBufferVerts(LLSpatialGroup* group, U32 mask) } else { - drawBox(group->mBounds[0], group->mBounds[1]); + const LLVector4a* bounds = group->getBounds(); + drawBox(bounds[0], bounds[1]); } } @@ -2432,7 +1498,7 @@ void pushVertsColorCoded(LLSpatialGroup* group, U32 mask) { LLDrawInfo* params = NULL; - LLColor4 colors[] = { + static LLColor4 colors[] = { LLColor4::green, LLColor4::green1, LLColor4::green2, @@ -2484,20 +1550,24 @@ void renderOctree(LLSpatialGroup* group) if (group->mBufferUsage != GL_STATIC_DRAW_ARB) { LLGLDepthTest gl_depth(FALSE, FALSE); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + gGL.setPolygonMode(LLRender::PF_FRONT_AND_BACK, LLRender::PM_LINE); gGL.diffuseColor4f(1,0,0,group->mBuilt); - gGL.flush(); - glLineWidth(5.f); - drawBoxOutline(group->mObjectBounds[0], group->mObjectBounds[1]); - gGL.flush(); - glLineWidth(1.f); - gGL.flush(); - OctreeGuard guard(group->mOctreeNode); + gGL.setLineWidth(5.f); + + const LLVector4a* bounds = group->getObjectBounds(); + drawBoxOutline(bounds[0], bounds[1]); + gGL.setLineWidth(1.f); + + OctreeGuard guard(group->getOctreeNode()); for (LLSpatialGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i) { - LLDrawable* drawable = *i; - if (!group->mSpatialPartition->isBridge()) + LLDrawable* drawable = (LLDrawable*)(*i)->getDrawable(); + if(!drawable) + { + continue; + } + if (!group->getSpatialPartition()->isBridge()) { gGL.pushMatrix(); LLVector3 trans = drawable->getRegion()->getOriginAgent(); @@ -2529,19 +1599,19 @@ void renderOctree(LLSpatialGroup* group) } } - if (!group->mSpatialPartition->isBridge()) + if (!group->getSpatialPartition()->isBridge()) { gGL.popMatrix(); } } - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + gGL.setPolygonMode(LLRender::PF_FRONT_AND_BACK, LLRender::PM_FILL); gGL.diffuseColor4f(1,1,1,1); } } else { if (group->mBufferUsage == GL_STATIC_DRAW_ARB && !group->isEmpty() - && group->mSpatialPartition->mRenderByGroup) + && group->getSpatialPartition()->mRenderByGroup) { col.setVec(0.8f, 0.4f, 0.1f, 0.1f); } @@ -2554,9 +1624,10 @@ void renderOctree(LLSpatialGroup* group) gGL.diffuseColor4fv(col.mV); LLVector4a fudge; fudge.splat(0.001f); - LLVector4a size = group->mObjectBounds[1]; - size.mul(1.01f); - size.add(fudge); + //const LLVector4a* bounds = group->getObjectBounds(); + //LLVector4a size = bounds[1]; + //size.mul(1.01f); + //size.add(fudge);*/ //{ // LLGLDepthTest depth(GL_TRUE, GL_FALSE); @@ -2572,7 +1643,9 @@ void renderOctree(LLSpatialGroup* group) //drawBoxOutline(group->mObjectBounds[0], group->mObjectBounds[1]); gGL.diffuseColor4f(0,1,1,1); - drawBoxOutline(group->mBounds[0],group->mBounds[1]); + + const LLVector4a* bounds = group->getBounds(); + drawBoxOutline(bounds[0], bounds[1]); //draw bounding box for draw info /*if (group->mSpatialPartition->mRenderByGroup) @@ -2595,17 +1668,17 @@ void renderOctree(LLSpatialGroup* group) }*/ } -// LLSpatialGroup::OctreeNode* node = group->mOctreeNode; +// OctreeNode* node = group->mOctreeNode; // gGL.color4f(0,1,0,1); // drawBoxOutline(LLVector3(node->getCenter()), LLVector3(node->getSize())); } void renderVisibility(LLSpatialGroup* group, LLCamera* camera) { - LLGLEnable blend(GL_BLEND); + LLGLEnable blend; gGL.setSceneBlendType(LLRender::BT_ALPHA); - LLGLEnable cull(GL_CULL_FACE); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + LLGLEnable cull; + gGL.setPolygonMode(LLRender::PF_FRONT_AND_BACK, LLRender::PM_LINE); BOOL render_objects = (!LLPipeline::sUseOcclusion || !group->isOcclusionState(LLSpatialGroup::OCCLUDED)) && group->isVisible() && !group->isEmpty(); @@ -2626,7 +1699,7 @@ void renderVisibility(LLSpatialGroup* group, LLCamera* camera) pushBufferVerts(group, LLVertexBuffer::MAP_VERTEX); } - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + gGL.setPolygonMode(LLRender::PF_FRONT_AND_BACK, LLRender::PM_FILL); if (render_objects) { @@ -2640,11 +1713,11 @@ void renderVisibility(LLSpatialGroup* group, LLCamera* camera) gGL.diffuseColor4f(1.0f, 0.f, 0.f, 0.5f); glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8, GL_UNSIGNED_BYTE, get_box_fan_indices(camera, group->mBounds[0])); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + gGL.setPolygonMode(LLRender::PF_FRONT_AND_BACK, LLRender::PM_LINE); gGL.diffuseColor4f(1.0f, 1.f, 1.f, 1.0f); glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8, GL_UNSIGNED_BYTE, get_box_fan_indices(camera, group->mBounds[0])); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + gGL.setPolygonMode(LLRender::PF_FRONT_AND_BACK, LLRender::PM_FILL); }*/ } } @@ -2671,7 +1744,7 @@ void renderUpdateType(LLDrawable* drawablep) { return; } - LLGLEnable blend(GL_BLEND); + LLGLEnable blend; switch (vobj->getLastUpdateType()) { case OUT_FULL: @@ -2694,7 +1767,7 @@ void renderUpdateType(LLDrawable* drawablep) gGL.diffuseColor4f(0,0,1,0.5f); break; default: - llwarns << "Unknown update_type " << vobj->getLastUpdateType() << llendl; + LL_WARNS() << "Unknown update_type " << vobj->getLastUpdateType() << LL_ENDL; break; }; S32 num_faces = drawablep->getNumFaces(); @@ -2715,7 +1788,7 @@ void renderComplexityDisplay(LLDrawable* drawablep) return; } - LLVOVolume *voVol = dynamic_cast(vobj); + LLVOVolume *voVol = vobj->asVolume();; if (!voVol) { @@ -2764,7 +1837,7 @@ void renderComplexityDisplay(LLDrawable* drawablep) // cap cost ratio at 1.0f in case cost_max is at a low threshold cost_ratio = cost_ratio > 1.0f ? 1.0f : cost_ratio; - LLGLEnable blend(GL_BLEND); + LLGLEnable blend; LLColor4 color; const LLColor4 color_min = gSavedSettings.getColor4("RenderComplexityColorMin"); @@ -2785,7 +1858,7 @@ void renderComplexityDisplay(LLDrawable* drawablep) // don't highlight objects below the threshold if (cost > gSavedSettings.getS32("RenderComplexityThreshold")) { - glColor4f(color[0],color[1],color[2],0.5f); + gGL.diffuseColor4f(color[0],color[1],color[2],0.5f); S32 num_faces = drawablep->getNumFaces(); @@ -2858,7 +1931,28 @@ void renderBoundingBox(LLDrawable* drawable, BOOL set_color = TRUE) gGL.diffuseColor4f(0,0.5f,0,1); break; default: - gGL.diffuseColor4f(1,0,1,1); + LLControlAvatar *cav = dynamic_cast(drawable->getVObj()->asAvatar()); + if (cav) + { + bool has_pos_constraint = (cav->mPositionConstraintFixup != LLVector3()); + bool has_scale_constraint = (cav->mScaleConstraintFixup != 1.0f); + if (has_pos_constraint || has_scale_constraint) + { + gGL.diffuseColor4f(1,0,0,1); + } + else + { + gGL.diffuseColor4f(0,1,0.5,1); + } + } + else if (drawable->getVObj()->asAvatar()) + { + gGL.diffuseColor4f(.5, 0, 1, 1); + } + else + { + gGL.diffuseColor4f(1,0,1,1); // magenta + } break; } } @@ -2871,20 +1965,25 @@ void renderBoundingBox(LLDrawable* drawable, BOOL set_color = TRUE) const LLVector4a* ext; LLVector4a pos, size; - //render face bounding boxes - for (S32 i = 0; i < drawable->getNumFaces(); i++) + static LLCachedControl sh_override_rigged_bounds("SHOverrideRiggedBounds", true); + LLVOVolume* volume = drawable->getVOVolume(); + if (volume && (!sh_override_rigged_bounds || !volume->isAttachment() || !(drawable->isState(LLDrawable::RIGGED) || volume->isRiggedMesh()))) { - LLFace* facep = drawable->getFace(i); - if (facep) + //render face bounding boxes + for (S32 i = 0; i < drawable->getNumFaces(); i++) { - ext = facep->mExtents; + LLFace* facep = drawable->getFace(i); + if (facep) + { + ext = facep->mExtents; - pos.setAdd(ext[0], ext[1]); - pos.mul(0.5f); - size.setSub(ext[1], ext[0]); - size.mul(0.5f); + pos.setAdd(ext[0], ext[1]); + pos.mul(0.5f); + size.setSub(ext[1], ext[0]); + size.mul(0.5f); - drawBoxOutline(pos,size); + drawBoxOutline(pos,size); + } } } @@ -2899,13 +1998,11 @@ void renderBoundingBox(LLDrawable* drawable, BOOL set_color = TRUE) LLViewerObject* vobj = drawable->getVObj(); if (vobj && vobj->onActiveList()) { - gGL.flush(); - glLineWidth(llmax(4.f*sinf(gFrameTimeSeconds*2.f)+1.f, 1.f)); + gGL.setLineWidth(llmax(4.f*sinf(gFrameTimeSeconds*2.f)+1.f, 1.f)); //glLineWidth(4.f*(sinf(gFrameTimeSeconds*2.f)*0.25f+0.75f)); stop_glerror(); drawBoxOutline(pos,size); - gGL.flush(); - glLineWidth(1.f); + gGL.setLineWidth(1.f); } else { @@ -2922,7 +2019,7 @@ void renderNormals(LLDrawable* drawablep) { LLVolume* volume = vol->getVolume(); gGL.pushMatrix(); - gGL.multMatrix((F32*) vol->getRelativeXform().mMatrix); + gGL.multMatrix(vol->getRelativeXform()); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); @@ -2944,9 +2041,9 @@ void renderNormals(LLDrawable* drawablep) gGL.vertex3fv(face.mPositions[j].getF32ptr()); gGL.vertex3fv(p.getF32ptr()); - if (face.mBinormals) + if (face.mTangents) { - n.setMul(face.mBinormals[j], scale); + n.setMul(face.mTangents[j], scale); p.setAdd(face.mPositions[j], n); gGL.diffuseColor4f(0,1,1,1); @@ -3018,14 +2115,14 @@ void render_hull(LLModel::PhysicsMesh& mesh, const LLColor4& color, const LLColo return; gGL.diffuseColor4fv(color.mV); LLVertexBuffer::drawArrays(LLRender::TRIANGLES, mesh.mPositions, mesh.mNormals); - LLGLEnable offset(GL_POLYGON_OFFSET_LINE); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - glPolygonOffset(3.f, 3.f); - glLineWidth(3.f); + LLGLEnable offset; + gGL.setPolygonMode(LLRender::PF_FRONT_AND_BACK, LLRender::PM_LINE); + gGL.setPolygonOffset(3.f, 3.f); + gGL.setLineWidth(3.f); gGL.diffuseColor4fv(line_color.mV); LLVertexBuffer::drawArrays(LLRender::TRIANGLES, mesh.mPositions, mesh.mNormals); - glLineWidth(1.f); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + gGL.setLineWidth(1.f); + gGL.setPolygonMode(LLRender::PF_FRONT_AND_BACK, LLRender::PM_FILL); } void renderPhysicsShape(LLDrawable* drawable, LLVOVolume* volume) @@ -3076,7 +2173,7 @@ void renderPhysicsShape(LLDrawable* drawable, LLVOVolume* volume) LLVector3 size(0.25f,0.25f,0.25f); gGL.pushMatrix(); - gGL.multMatrix((F32*) volume->getRelativeXform().mMatrix); + gGL.multMatrix(volume->getRelativeXform()); if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::USER_MESH) { @@ -3108,10 +2205,10 @@ void renderPhysicsShape(LLDrawable* drawable, LLVOVolume* volume) gGL.diffuseColor4fv(color.mV); LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mPhysicsShapeMesh.mPositions, decomp->mPhysicsShapeMesh.mNormals); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + gGL.setPolygonMode(LLRender::PF_FRONT_AND_BACK, LLRender::PM_LINE); gGL.diffuseColor4fv(line_color.mV); LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mPhysicsShapeMesh.mPositions, decomp->mPhysicsShapeMesh.mNormals); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + gGL.setPolygonMode(LLRender::PF_FRONT_AND_BACK, LLRender::PM_FILL); } else { //no mesh or decomposition, render base hull @@ -3232,18 +2329,18 @@ void renderPhysicsShape(LLDrawable* drawable, LLVOVolume* volume) { //render hull - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + gGL.setPolygonMode(LLRender::PF_FRONT_AND_BACK, LLRender::PM_LINE); gGL.diffuseColor4fv(line_color.mV); LLVertexBuffer::unbind(); llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShader != 0); - LLVertexBuffer::drawElements(LLRender::TRIANGLES, phys_volume->mHullPoints, NULL, phys_volume->mNumHullIndices, phys_volume->mHullIndices); + LLVertexBuffer::drawElements(LLRender::TRIANGLES, phys_volume->mNumHullPoints phys_volume->mHullPoints, NULL, phys_volume->mNumHullIndices, phys_volume->mHullIndices); gGL.diffuseColor4fv(color.mV); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - LLVertexBuffer::drawElements(LLRender::TRIANGLES, phys_volume->mHullPoints, NULL, phys_volume->mNumHullIndices, phys_volume->mHullIndices); + gGL.setPolygonMode(LLRender::PF_FRONT_AND_BACK, LLRender::PM_FILL); + LLVertexBuffer::drawElements(LLRender::TRIANGLES, phys_volume->mNumHullPoints phys_volume->mHullPoints, NULL, phys_volume->mNumHullIndices, phys_volume->mHullIndices); } else @@ -3299,13 +2396,13 @@ void renderPhysicsShape(LLDrawable* drawable, LLVOVolume* volume) S32 detail = get_physics_detail(volume_params, volume->getScale()); LLVolume* phys_volume = LLPrimitive::getVolumeManager()->refVolume(volume_params, detail); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + gGL.setPolygonMode(LLRender::PF_FRONT_AND_BACK, LLRender::PM_LINE); gGL.diffuseColor4fv(line_color.mV); pushVerts(phys_volume); gGL.diffuseColor4fv(color.mV); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + gGL.setPolygonMode(LLRender::PF_FRONT_AND_BACK, LLRender::PM_FILL); pushVerts(phys_volume); LLPrimitive::getVolumeManager()->unrefVolume(phys_volume); } @@ -3318,17 +2415,13 @@ void renderPhysicsShape(LLDrawable* drawable, LLVOVolume* volume) if (phys_volume->mHullPoints && phys_volume->mHullIndices) { - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShader != 0); - LLVertexBuffer::unbind(); - glVertexPointer(3, GL_FLOAT, 16, phys_volume->mHullPoints); + gGL.setPolygonMode(LLRender::PF_FRONT_AND_BACK, LLRender::PM_LINE); gGL.diffuseColor4fv(line_color.mV); - gGL.syncMatrices(); - glDrawElements(GL_TRIANGLES, phys_volume->mNumHullIndices, GL_UNSIGNED_SHORT, phys_volume->mHullIndices); - + LLVertexBuffer::drawElements(LLRender::TRIANGLES, phys_volume->mNumHullPoints, phys_volume->mHullPoints, NULL, phys_volume->mNumHullIndices, phys_volume->mHullIndices); + + gGL.setPolygonMode(LLRender::PF_FRONT_AND_BACK, LLRender::PM_FILL); gGL.diffuseColor4fv(color.mV); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glDrawElements(GL_TRIANGLES, phys_volume->mNumHullIndices, GL_UNSIGNED_SHORT, phys_volume->mHullIndices); + LLVertexBuffer::drawElements(LLRender::TRIANGLES, phys_volume->mNumHullPoints, phys_volume->mHullPoints, NULL, phys_volume->mNumHullIndices, phys_volume->mHullIndices); } else { @@ -3344,7 +2437,7 @@ void renderPhysicsShape(LLDrawable* drawable, LLVOVolume* volume) } else { - llerrs << "Unhandled type" << llendl; + LL_ERRS() << "Unhandled type" << LL_ENDL; } gGL.popMatrix(); @@ -3352,55 +2445,75 @@ void renderPhysicsShape(LLDrawable* drawable, LLVOVolume* volume) void renderPhysicsShapes(LLSpatialGroup* group) { - OctreeGuard guard(group->mOctreeNode); - for (LLSpatialGroup::OctreeNode::const_element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i) + OctreeGuard guard(group->getOctreeNode()); + for (OctreeNode::const_element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i) { - LLDrawable* drawable = *i; - LLVOVolume* volume = drawable->getVOVolume(); - if (volume && !volume->isAttachment() && volume->getPhysicsShapeType() != LLViewerObject::PHYSICS_SHAPE_NONE ) + LLDrawable* drawable = (LLDrawable*)(*i)->getDrawable(); + if (!drawable) + { + continue; + } + + if (drawable->isSpatialBridge()) { - if (!group->mSpatialPartition->isBridge()) + LLSpatialBridge* bridge = drawable->asPartition()->asBridge(); + + if (bridge) { gGL.pushMatrix(); - LLVector3 trans = drawable->getRegion()->getOriginAgent(); - gGL.translatef(trans.mV[0], trans.mV[1], trans.mV[2]); - renderPhysicsShape(drawable, volume); + gGL.multMatrix(bridge->mDrawable->getRenderMatrix()); + bridge->renderPhysicsShapes(); gGL.popMatrix(); } - else - { - renderPhysicsShape(drawable, volume); - } } else { - LLViewerObject* object = drawable->getVObj(); - if (object && object->getPCode() == LLViewerObject::LL_VO_SURFACE_PATCH) + LLVOVolume* volume = drawable->getVOVolume(); + if (volume && !volume->isAttachment() && volume->getPhysicsShapeType() != LLViewerObject::PHYSICS_SHAPE_NONE ) { - gGL.pushMatrix(); - gGL.multMatrix((F32*) object->getRegion()->mRenderMatrix.mMatrix); - //push face vertices for terrain - for (S32 i = 0; i < drawable->getNumFaces(); ++i) + if (!group->getSpatialPartition()->isBridge()) { - LLFace* face = drawable->getFace(i); - if (face) + gGL.pushMatrix(); + LLVector3 trans = drawable->getRegion()->getOriginAgent(); + gGL.translatef(trans.mV[0], trans.mV[1], trans.mV[2]); + renderPhysicsShape(drawable, volume); + gGL.popMatrix(); + } + else + { + renderPhysicsShape(drawable, volume); + } + } + else + { + LLViewerObject* object = drawable->getVObj(); + if (object && object->getPCode() == LLViewerObject::LL_VO_SURFACE_PATCH) + { + gGL.pushMatrix(); + gGL.multMatrix(object->getRegion()->mRenderMatrix); + //push face vertices for terrain + for (S32 i = 0; i < drawable->getNumFaces(); ++i) { - LLVertexBuffer* buff = face->getVertexBuffer(); - if (buff) + LLFace* face = drawable->getFace(i); + if (face) { - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + LLVertexBuffer* buff = face->getVertexBuffer(); + if (buff) + { + gGL.setPolygonMode(LLRender::PF_FRONT_AND_BACK, LLRender::PM_LINE); - buff->setBuffer(LLVertexBuffer::MAP_VERTEX); - gGL.diffuseColor3f(0.2f, 0.5f, 0.3f); - buff->draw(LLRender::TRIANGLES, buff->getNumIndices(), 0); + buff->setBuffer(LLVertexBuffer::MAP_VERTEX); + gGL.diffuseColor3f(0.2f, 0.5f, 0.3f); + buff->draw(LLRender::TRIANGLES, buff->getNumIndices(), 0); - gGL.diffuseColor3f(0.2f, 1.f, 0.3f); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - buff->draw(LLRender::TRIANGLES, buff->getNumIndices(), 0); + gGL.diffuseColor3f(0.2f, 1.f, 0.3f); + gGL.setPolygonMode(LLRender::PF_FRONT_AND_BACK, LLRender::PM_FILL); + buff->draw(LLRender::TRIANGLES, buff->getNumIndices(), 0); + } } } + gGL.popMatrix(); } - gGL.popMatrix(); } } } @@ -3418,7 +2531,7 @@ void renderTexturePriority(LLDrawable* drawable) LLVector4 boost_cold(0,0,0,0); LLVector4 boost_hot(0,1,0,1); - LLGLDisable blend(GL_BLEND); + LLGLDisable blend; //LLViewerTexture* imagep = facep->getTexture(); //if (imagep) @@ -3492,22 +2605,22 @@ void renderTextureAnim(LLDrawInfo* params) return; } - LLGLEnable blend(GL_BLEND); + LLGLEnable blend; gGL.diffuseColor4f(1,1,0,0.5f); pushVerts(params, LLVertexBuffer::MAP_VERTEX); } void renderBatchSize(LLDrawInfo* params) { - LLGLEnable offset(GL_POLYGON_OFFSET_FILL); - glPolygonOffset(-1.f, 1.f); + LLGLEnable offset; + gGL.setPolygonOffset(-1.f, 1.f); gGL.diffuseColor4ubv((GLubyte*) &(params->mDebugColor)); pushVerts(params, LLVertexBuffer::MAP_VERTEX); } void renderShadowFrusta(LLDrawInfo* params) { - LLGLEnable blend(GL_BLEND); + LLGLEnable blend; gGL.setSceneBlendType(LLRender::BT_ADD); LLVector4a center; @@ -3551,7 +2664,7 @@ void renderLights(LLDrawable* drawablep) if (drawablep->getNumFaces()) { - LLGLEnable blend(GL_BLEND); + LLGLEnable blend; gGL.diffuseColor4f(0,1,1,0.5f); for (S32 i = 0; i < drawablep->getNumFaces(); i++) @@ -3585,6 +2698,7 @@ void renderLights(LLDrawable* drawablep) } } +LL_ALIGN_PREFIX(16) class LLRenderOctreeRaycast : public LLOctreeTriangleRayIntersect { public: @@ -3633,8 +2747,7 @@ class LLRenderOctreeRaycast : public LLOctreeTriangleRayIntersect if (i == 1) { - gGL.flush(); - glLineWidth(3.f); + gGL.setLineWidth(3.f); } gGL.begin(LLRender::TRIANGLES); @@ -3652,25 +2765,24 @@ class LLRenderOctreeRaycast : public LLOctreeTriangleRayIntersect if (i == 1) { - gGL.flush(); - glLineWidth(1.f); + gGL.setLineWidth(1.f); } } } -}; +} LL_ALIGN_POSTFIX(16); void renderRaycast(LLDrawable* drawablep) { if (drawablep->getNumFaces()) { - LLGLEnable blend(GL_BLEND); + LLGLEnable blend; gGL.diffuseColor4f(0,1,1,0.5f); if (drawablep->getVOVolume()) { - //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + //gGL.setPolygonMode(LLRender::PF_FRONT_AND_BACK, LLRender::PM_LINE); //pushVerts(drawablep->getFace(gDebugRaycastFaceHit), LLVertexBuffer::MAP_VERTEX); - //glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + //gGL.setPolygonMode(LLRender::PF_FRONT_AND_BACK, LLRender::PM_FILL); LLVOVolume* vobj = drawablep->getVOVolume(); LLVolume* volume = vobj->getVolume(); @@ -3692,13 +2804,19 @@ void renderRaycast(LLDrawable* drawablep) gGL.pushMatrix(); gGL.translatef(trans.mV[0], trans.mV[1], trans.mV[2]); - gGL.multMatrix((F32*) vobj->getRelativeXform().mMatrix); + gGL.multMatrix(vobj->getRelativeXform()); - LLVector3 start, end; + LLVector4a start, end; if (transform) { - start = vobj->agentPositionToVolume(gDebugRaycastStart); - end = vobj->agentPositionToVolume(gDebugRaycastEnd); + LLVector3 v_start(gDebugRaycastStart.getF32ptr()); + LLVector3 v_end(gDebugRaycastEnd.getF32ptr()); + + v_start = vobj->agentPositionToVolume(v_start); + v_end = vobj->agentPositionToVolume(v_end); + + start.load3(v_start.mV); + end.load3(v_end.mV); } else { @@ -3706,22 +2824,16 @@ void renderRaycast(LLDrawable* drawablep) end = gDebugRaycastEnd; } - LLVector4a starta, enda; - starta.load3(start.mV); - enda.load3(end.mV); LLVector4a dir; - dir.setSub(enda, starta); + dir.setSub(end, start); gGL.flush(); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + gGL.setPolygonMode(LLRender::PF_FRONT_AND_BACK, LLRender::PM_LINE); { //render face positions - LLVertexBuffer::unbind(); gGL.diffuseColor4f(0,1,1,0.5f); - glVertexPointer(3, GL_FLOAT, sizeof(LLVector4a), face.mPositions); - gGL.syncMatrices(); - glDrawElements(GL_TRIANGLES, face.mNumIndices, GL_UNSIGNED_SHORT, face.mIndices); + LLVertexBuffer::drawElements(LLRender::TRIANGLES, face.mNumVertices, face.mPositions, NULL, face.mNumIndices, face.mIndices); } if (!volume->isUnique()) @@ -3733,12 +2845,13 @@ void renderRaycast(LLDrawable* drawablep) ((LLVolumeFace*) &face)->createOctree(); } - LLRenderOctreeRaycast render(starta, dir, &t); + LLRenderOctreeRaycast render(start, dir, &t); render.traverse(face.mOctree); } + gGL.popMatrix(); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + gGL.setPolygonMode(LLRender::PF_FRONT_AND_BACK, LLRender::PM_FILL); } } } @@ -3757,13 +2870,24 @@ void renderRaycast(LLDrawable* drawablep) // draw intersection point gGL.pushMatrix(); gGL.loadMatrix(gGLModelView); - LLVector3 translate = gDebugRaycastIntersection; + LLVector3 translate(gDebugRaycastIntersection.getF32ptr()); gGL.translatef(translate.mV[0], translate.mV[1], translate.mV[2]); LLCoordFrame orient; - orient.lookDir(gDebugRaycastNormal, gDebugRaycastBinormal); + LLVector4a debug_binormal; + + debug_binormal.setCross3(gDebugRaycastNormal, gDebugRaycastTangent); + debug_binormal.mul(gDebugRaycastTangent.getF32ptr()[3]); + + LLVector3 normal(gDebugRaycastNormal.getF32ptr()); + LLVector3 binormal(debug_binormal.getF32ptr()); + + //LLCoordFrame isn't vectorized, for now. + orient.lookDir(normal, binormal); LLMatrix4 rotation; orient.getRotMatrixToParent(rotation); - gGL.multMatrix((float*)rotation.mMatrix); + LLMatrix4a rotationa; + rotationa.loadu((F32*)rotation.mMatrix); + gGL.multMatrix(rotationa); gGL.diffuseColor4f(1,0,0,0.5f); drawBox(LLVector3(0, 0, 0), LLVector3(0.1f, 0.022f, 0.022f)); @@ -3797,6 +2921,10 @@ void renderAvatarCollisionVolumes(LLVOAvatar* avatar) avatar->renderCollisionVolumes(); } +void renderAvatarBones(LLVOAvatar* avatar) +{ + avatar->renderBones(); +} void renderAgentTarget(LLVOAvatar* avatar) { // render these for self only (why, i don't know) @@ -3810,17 +2938,18 @@ void renderAgentTarget(LLVOAvatar* avatar) } -class LLOctreeRenderNonOccluded : public LLOctreeTraveler +class LLOctreeRenderNonOccluded : public OctreeTraveler { public: LLCamera* mCamera; LLOctreeRenderNonOccluded(LLCamera* camera): mCamera(camera) {} - virtual void traverse(const LLSpatialGroup::OctreeNode* node) + virtual void traverse(const OctreeNode* node) { LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0); - if (!mCamera || mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1])) + const LLVector4a* bounds = group->getBounds(); + if (!mCamera || mCamera->AABBInFrustumNoFarClip(bounds[0], bounds[1])) { node->accept(this); stop_glerror(); @@ -3860,15 +2989,17 @@ class LLOctreeRenderNonOccluded : public LLOctreeTraveler } } - virtual void visit(const LLSpatialGroup::OctreeNode* branch) + virtual void visit(const OctreeNode* branch) { LLSpatialGroup* group = (LLSpatialGroup*) branch->getListener(0); - - if (group->isState(LLSpatialGroup::GEOM_DIRTY) || (mCamera && !mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1]))) + const LLVector4a* bounds = group->getBounds(); + if (group->hasState(LLSpatialGroup::GEOM_DIRTY) || (mCamera && !mCamera->AABBInFrustumNoFarClip(bounds[0], bounds[1]))) { return; } + LLGLDisable stencil; + group->rebuildGeom(); group->rebuildMesh(); @@ -3877,15 +3008,19 @@ class LLOctreeRenderNonOccluded : public LLOctreeTraveler if (!group->isEmpty()) { gGL.diffuseColor3f(0,0,1); - drawBoxOutline(group->mObjectBounds[0], - group->mObjectBounds[1]); + const LLVector4a* obj_bounds = group->getObjectBounds(); + drawBoxOutline(obj_bounds[0], obj_bounds[1]); } } {OctreeGuard guard(branch); - for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getDataBegin(); i != branch->getDataEnd(); ++i) + for (OctreeNode::const_element_iter i = branch->getDataBegin(); i != branch->getDataEnd(); ++i) { - LLDrawable* drawable = *i; + LLDrawable* drawable = (LLDrawable*)(*i)->getDrawable(); + if(!drawable) + { + continue; + } if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BBOXES)) { @@ -3948,11 +3083,16 @@ class LLOctreeRenderNonOccluded : public LLOctreeTraveler renderAvatarCollisionVolumes(avatar); } + if (avatar && gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_AVATAR_JOINTS)) + { + renderAvatarBones(avatar); + } + if (avatar && gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_AGENT_TARGET)) { renderAgentTarget(avatar); } - + if (gDebugGL) { for (U32 i = 0; i < (U32)drawable->getNumFaces(); ++i) @@ -3967,11 +3107,11 @@ class LLOctreeRenderNonOccluded : public LLOctreeTraveler { if (facep->mDrawInfo->mTextureList.size() <= index) { - llerrs << "Face texture index out of bounds." << llendl; + LL_ERRS() << "Face texture index out of bounds." << LL_ENDL; } else if (facep->mDrawInfo->mTextureList[index] != facep->getTexture()) { - llerrs << "Face texture index incorrect." << llendl; + LL_ERRS() << "Face texture index incorrect." << LL_ENDL; } } } @@ -4004,17 +3144,18 @@ class LLOctreeRenderNonOccluded : public LLOctreeTraveler }; -class LLOctreeRenderPhysicsShapes : public LLOctreeTraveler +class LLOctreeRenderPhysicsShapes : public OctreeTraveler { public: LLCamera* mCamera; LLOctreeRenderPhysicsShapes(LLCamera* camera): mCamera(camera) {} - virtual void traverse(const LLSpatialGroup::OctreeNode* node) + virtual void traverse(const OctreeNode* node) { LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0); - if (!mCamera || mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1])) + const LLVector4a* bounds = group->getBounds(); + if (!mCamera || mCamera->AABBInFrustumNoFarClip(bounds[0], bounds[1])) { node->accept(this); stop_glerror(); @@ -4032,23 +3173,24 @@ class LLOctreeRenderPhysicsShapes : public LLOctreeTraveler } } - virtual void visit(const LLSpatialGroup::OctreeNode* branch) + virtual void visit(const OctreeNode* branch) { } }; -class LLOctreePushBBoxVerts : public LLOctreeTraveler +class LLOctreePushBBoxVerts : public OctreeTraveler { public: LLCamera* mCamera; LLOctreePushBBoxVerts(LLCamera* camera): mCamera(camera) {} - virtual void traverse(const LLSpatialGroup::OctreeNode* node) + virtual void traverse(const OctreeNode* node) { LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0); - if (!mCamera || mCamera->AABBInFrustum(group->mBounds[0], group->mBounds[1])) + const LLVector4a* bounds = group->getBounds(); + if (!mCamera || mCamera->AABBInFrustum(bounds[0], bounds[1])) { node->accept(this); @@ -4059,20 +3201,24 @@ class LLOctreePushBBoxVerts : public LLOctreeTraveler } } - virtual void visit(const LLSpatialGroup::OctreeNode* branch) + virtual void visit(const OctreeNode* branch) { LLSpatialGroup* group = (LLSpatialGroup*) branch->getListener(0); - if (group->isState(LLSpatialGroup::GEOM_DIRTY) || (mCamera && !mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1]))) + const LLVector4a* bounds = group->getBounds(); + if (group->hasState(LLSpatialGroup::GEOM_DIRTY) || (mCamera && !mCamera->AABBInFrustumNoFarClip(bounds[0], bounds[1]))) { return; } OctreeGuard guard(branch); - for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getDataBegin(); i != branch->getDataEnd(); ++i) + for (OctreeNode::const_element_iter i = branch->getDataBegin(); i != branch->getDataEnd(); ++i) { - LLDrawable* drawable = *i; - + LLDrawable* drawable = (LLDrawable*)(*i)->getDrawable(); + if(!drawable) + { + continue; + } renderBoundingBox(drawable, FALSE); } } @@ -4084,7 +3230,7 @@ void LLSpatialPartition::renderIntersectingBBoxes(LLCamera* camera) pusher.traverse(mOctree); } -class LLOctreeStateCheck : public LLOctreeTraveler +class LLOctreeStateCheck : public OctreeTraveler { public: U32 mInheritedMask[LLViewerCamera::NUM_CAMERAS]; @@ -4097,7 +3243,7 @@ class LLOctreeStateCheck : public LLOctreeTraveler } } - virtual void traverse(const LLSpatialGroup::OctreeNode* node) + virtual void traverse(const OctreeNode* node) { LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0); @@ -4124,7 +3270,7 @@ class LLOctreeStateCheck : public LLOctreeTraveler } - virtual void visit(const LLOctreeNode* state) + virtual void visit(const OctreeNode* state) { LLSpatialGroup* group = (LLSpatialGroup*) state->getListener(0); @@ -4132,13 +3278,13 @@ class LLOctreeStateCheck : public LLOctreeTraveler { if (mInheritedMask[i] && !(group->mOcclusionState[i] & mInheritedMask[i])) { - llerrs << "Spatial group failed inherited mask test." << llendl; + LL_ERRS() << "Spatial group failed inherited mask test." << LL_ENDL; } } - if (group->isState(LLSpatialGroup::DIRTY)) + if (group->hasState(LLSpatialGroup::eSpatialState(LLSpatialGroup::DIRTY))) { - assert_parent_state(group, LLSpatialGroup::DIRTY); + assert_parent_state(group, LLSpatialGroup::eSpatialState(LLSpatialGroup::DIRTY)); } } @@ -4147,9 +3293,9 @@ class LLOctreeStateCheck : public LLOctreeTraveler LLSpatialGroup* parent = group->getParent(); while (parent) { - if (!parent->isState(state)) + if (!parent->hasState(state)) { - llerrs << "Spatial group failed parent state check." << llendl; + LL_ERRS() << "Spatial group failed parent state check." << LL_ENDL; } parent = parent->getParent(); } @@ -4167,13 +3313,11 @@ void LLSpatialPartition::renderPhysicsShapes() camera = NULL; } - gGL.flush(); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - glLineWidth(3.f); + gGL.setLineWidth(3.f); LLOctreeRenderPhysicsShapes render_physics(camera); render_physics.traverse(mOctree); - gGL.flush(); - glLineWidth(1.f); + gGL.setLineWidth(1.f); } void LLSpatialPartition::renderDebug() @@ -4190,6 +3334,7 @@ void LLSpatialPartition::renderDebug() LLPipeline::RENDER_DEBUG_TEXTURE_ANIM | LLPipeline::RENDER_DEBUG_RAYCAST | LLPipeline::RENDER_DEBUG_AVATAR_VOLUME | + LLPipeline::RENDER_DEBUG_AVATAR_JOINTS | LLPipeline::RENDER_DEBUG_AGENT_TARGET | //LLPipeline::RENDER_DEBUG_BUILD_QUEUE | LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA | @@ -4210,11 +3355,12 @@ void LLSpatialPartition::renderDebug() sCurMaxTexPriority = 0.f; } - LLGLDisable cullface(GL_CULL_FACE); - LLGLEnable blend(GL_BLEND); + LLGLDisable cullface; + LLGLEnable blend; gGL.setSceneBlendType(LLRender::BT_ALPHA); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gPipeline.disableLights(); + LLGLState light_state; + gPipeline.disableLights(light_state); LLSpatialBridge* bridge = asBridge(); LLCamera* camera = LLViewerCamera::getInstance(); @@ -4261,50 +3407,54 @@ BOOL LLSpatialPartition::isVisible(const LLVector3& v) return TRUE; } -class LLOctreeIntersect : public LLSpatialGroup::OctreeTraveler +LL_ALIGN_PREFIX(16) +class LLOctreeIntersect : public LLOctreeTraveler { public: - LLVector3 mStart; - LLVector3 mEnd; + LL_ALIGN_16(LLVector4a mStart); + LL_ALIGN_16(LLVector4a mEnd); + S32 *mFaceHit; - LLVector3 *mIntersection; + LLVector4a *mIntersection; LLVector2 *mTexCoord; - LLVector3 *mNormal; - LLVector3 *mBinormal; + LLVector4a *mNormal; + LLVector4a *mTangent; LLDrawable* mHit; BOOL mPickTransparent; + BOOL mPickRigged; - LLOctreeIntersect(LLVector3 start, LLVector3 end, BOOL pick_transparent, - S32* face_hit, LLVector3* intersection, LLVector2* tex_coord, LLVector3* normal, LLVector3* binormal) + LLOctreeIntersect(const LLVector4a& start, const LLVector4a& end, BOOL pick_transparent, BOOL pick_rigged, + S32* face_hit, LLVector4a* intersection, LLVector2* tex_coord, LLVector4a* normal, LLVector4a* tangent) : mStart(start), mEnd(end), mFaceHit(face_hit), mIntersection(intersection), mTexCoord(tex_coord), mNormal(normal), - mBinormal(binormal), + mTangent(tangent), mHit(NULL), - mPickTransparent(pick_transparent) + mPickTransparent(pick_transparent), + mPickRigged(pick_rigged) { } - virtual void visit(const LLSpatialGroup::OctreeNode* branch) + virtual void visit(const OctreeNode* branch) { OctreeGuard guard(branch); - for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getDataBegin(); i != branch->getDataEnd(); ++i) + for (OctreeNode::const_element_iter i = branch->getDataBegin(); i != branch->getDataEnd(); ++i) { check(*i); } } - virtual LLDrawable* check(const LLSpatialGroup::OctreeNode* node) + virtual LLDrawable* check(const OctreeNode* node) { node->accept(this); OctreeGuard guard(node); for (U32 i = 0; i < node->getChildCount(); i++) { - const LLSpatialGroup::OctreeNode* child = node->getChild(i); + const OctreeNode* child = node->getChild(i); LLVector3 res; LLSpatialGroup* group = (LLSpatialGroup*) child->getListener(0); @@ -4312,26 +3462,23 @@ class LLOctreeIntersect : public LLSpatialGroup::OctreeTraveler LLVector4a size; LLVector4a center; - size = group->mBounds[1]; - center = group->mBounds[0]; + const LLVector4a* bounds = group->getBounds(); + size = bounds[1]; + center = bounds[0]; - LLVector3 local_start = mStart; - LLVector3 local_end = mEnd; + LLVector4a local_start = mStart; + LLVector4a local_end = mEnd; - if (group->mSpatialPartition->isBridge()) + if (group->getSpatialPartition()->isBridge()) { - LLMatrix4 local_matrix = group->mSpatialPartition->asBridge()->mDrawable->getRenderMatrix(); + LLMatrix4a local_matrix = group->getSpatialPartition()->asBridge()->mDrawable->getRenderMatrix(); local_matrix.invert(); - - local_start = mStart * local_matrix; - local_end = mEnd * local_matrix; - } - LLVector4a start, end; - start.load3(local_start.mV); - end.load3(local_end.mV); + local_matrix.affineTransform(mStart, local_start); + local_matrix.affineTransform(mEnd, local_end); + } - if (LLLineSegmentBoxIntersect(start, end, center, size)) + if (LLLineSegmentBoxIntersect(local_start, local_end, center, size)) { check(child); } @@ -4340,8 +3487,10 @@ class LLOctreeIntersect : public LLSpatialGroup::OctreeTraveler return mHit; } - virtual bool check(LLDrawable* drawable) + virtual bool check(LLViewerOctreeEntry* entry) { + LLDrawable* drawable = (LLDrawable*)entry->getDrawable(); + if (!drawable || !gPipeline.hasRenderType(drawable->getRenderType()) || !drawable->isVisible()) { return false; @@ -4362,14 +3511,14 @@ class LLOctreeIntersect : public LLSpatialGroup::OctreeTraveler if (vobj) { - LLVector3 intersection; + LLVector4a intersection; bool skip_check = false; if (vobj->isAvatar()) { LLVOAvatar* avatar = (LLVOAvatar*) vobj; - if (avatar->isSelf() && gFloaterTools->getVisible()) + if (mPickRigged) { - LLViewerObject* hit = avatar->lineSegmentIntersectRiggedAttachments(mStart, mEnd, -1, mPickTransparent, mFaceHit, &intersection, mTexCoord, mNormal, mBinormal); + LLViewerObject* hit = avatar->lineSegmentIntersectRiggedAttachments(mStart, mEnd, -1, mPickTransparent, mPickRigged, mFaceHit, &intersection, mTexCoord, mNormal, mTangent); if (hit) { mEnd = intersection; @@ -4389,7 +3538,7 @@ class LLOctreeIntersect : public LLSpatialGroup::OctreeTraveler } } - if (!skip_check && vobj->lineSegmentIntersect(mStart, mEnd, -1, mPickTransparent, mFaceHit, &intersection, mTexCoord, mNormal, mBinormal)) + if (!skip_check && vobj->lineSegmentIntersect(mStart, mEnd, -1, mPickTransparent, mPickRigged, mFaceHit, &intersection, mTexCoord, mNormal, mTangent)) { mEnd = intersection; // shorten ray so we only find CLOSER hits if (mIntersection) @@ -4404,19 +3553,20 @@ class LLOctreeIntersect : public LLSpatialGroup::OctreeTraveler return false; } -}; +} LL_ALIGN_POSTFIX(16); -LLDrawable* LLSpatialPartition::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, +LLDrawable* LLSpatialPartition::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, BOOL pick_transparent, + BOOL pick_rigged, S32* face_hit, // return the face hit - LLVector3* intersection, // return the intersection point + LLVector4a* intersection, // return the intersection point LLVector2* tex_coord, // return the texture coordinates of the intersection point - LLVector3* normal, // return the surface normal at the intersection point - LLVector3* bi_normal // return the surface bi-normal at the intersection point + LLVector4a* normal, // return the surface normal at the intersection point + LLVector4a* tangent // return the surface tangent at the intersection point ) { - LLOctreeIntersect intersect(start, end, pick_transparent, face_hit, intersection, tex_coord, normal, bi_normal); + LLOctreeIntersect intersect(start, end, pick_transparent, pick_rigged, face_hit, intersection, tex_coord, normal, tangent); LLDrawable* drawable = intersect.check(mOctree); return drawable; @@ -4436,15 +3586,25 @@ LLDrawInfo::LLDrawInfo(U16 start, U16 end, U32 count, U32 offset, mOffset(offset), mFullbright(fullbright), mBump(bump), + mShiny(0), mParticle(particle), mPartSize(part_size), mVSize(0.f), mGroup(NULL), mFace(NULL), mDistance(0.f), - mDrawMode(LLRender::TRIANGLES) -{ - mVertexBuffer->validateRange(mStart, mEnd, mCount, mOffset); + mDrawMode(LLRender::TRIANGLES), + mMaterial(NULL), + mShaderMask(0), + mSpecColor(1.0f, 1.0f, 1.0f, 0.5f), + mBlendFuncSrc(LLRender::BF_SOURCE_ALPHA), + mBlendFuncDst(LLRender::BF_ONE_MINUS_SOURCE_ALPHA), + mHasGlow(FALSE), + mEnvIntensity(0.0f), + mAlphaMaskCutoff(0.5f), + mDiffuseAlphaMode(0) +{ + //mVertexBuffer->validateRange(mStart, mEnd, mCount, mOffset); mDebugColor = (rand() << 16) + rand(); } @@ -4453,7 +3613,7 @@ LLDrawInfo::~LLDrawInfo() { /*if (LLSpatialGroup::sNoDelete) { - llerrs << "LLDrawInfo deleted illegally!" << llendl; + LL_ERRS() << "LLDrawInfo deleted illegally!" << LL_ENDL; }*/ if (mFace) @@ -4499,7 +3659,7 @@ void LLCullResult::assertDrawMapsEmpty() { if (hasRenderMap(i)) { - llerrs << "Stale LLDrawInfo's in LLCullResult!" << llendl; + LL_ERRS() << "Stale LLDrawInfo's in LLCullResult!" << LL_ENDL; } } } diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h index d6e58fdc12..c89126432a 100644 --- a/indra/newview/llspatialpartition.h +++ b/indra/newview/llspatialpartition.h @@ -52,20 +52,15 @@ #define SG_STATE_INHERIT_MASK (OCCLUDED) #define SG_INITIAL_STATE_MASK (DIRTY | GEOM_DIRTY) +class LLViewerOctreePartition; class LLSpatialPartition; class LLSpatialBridge; class LLSpatialGroup; +class LLViewerRegion; -S32 AABBSphereIntersect(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &rad); -S32 AABBSphereIntersectR2(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &radius_squared); - -S32 AABBSphereIntersect(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &rad); -S32 AABBSphereIntersectR2(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &radius_squared); void pushVerts(LLFace* face, U32 mask); -// get index buffer for binary encoded axis vertex buffer given a box at center being viewed by given camera -U32 get_box_fan_indices(LLCamera* camera, const LLVector4a& center); -U8* get_box_fan_indices_ptr(LLCamera* camera, const LLVector4a& center); + class LLDrawInfo : public LLRefCount { @@ -91,7 +86,7 @@ class LLDrawInfo : public LLRefCount const LLDrawInfo& operator=(const LLDrawInfo& rhs) { - llerrs << "Illegal operation!" << llendl; + LL_ERRS() << "Illegal operation!" << LL_ENDL; return *this; } @@ -102,28 +97,42 @@ class LLDrawInfo : public LLRefCount void validate(); - LLVector4a mExtents[2]; + LL_ALIGN_16(LLVector4a mExtents[2]); LLPointer mVertexBuffer; LLPointer mTexture; std::vector > mTextureList; S32 mDebugColor; - const LLMatrix4* mTextureMatrix; - const LLMatrix4* mModelMatrix; + const LLMatrix4a* mTextureMatrix; + const LLMatrix4a* mModelMatrix; U16 mStart; U16 mEnd; U32 mCount; U32 mOffset; BOOL mFullbright; U8 mBump; + U8 mShiny; BOOL mParticle; F32 mPartSize; F32 mVSize; - LLSpatialGroup* mGroup; + LLPointer mGroup; LL_ALIGN_16(LLFace* mFace); //associated face F32 mDistance; U32 mDrawMode; + LLMaterialPtr mMaterial; // If this is null, the following parameters are unused. + LLMaterialID mMaterialID; + U32 mShaderMask; + U32 mBlendFuncSrc; + U32 mBlendFuncDst; + BOOL mHasGlow; + LLPointer mSpecularMap; + LLPointer mNormalMap; + LLVector4 mSpecColor; // XYZ = Specular RGB, W = Specular Exponent + F32 mEnvIntensity; + F32 mAlphaMaskCutoff; + U8 mDiffuseAlphaMode; + struct CompareTexture { @@ -197,13 +206,13 @@ class LLDrawInfo : public LLRefCount }; LL_ALIGN_PREFIX(64) -class LLSpatialGroup : public LLOctreeListener +class LLSpatialGroup : public LLOcclusionCullingGroup { friend class LLSpatialPartition; friend class LLOctreeStateCheck; public: - LLSpatialGroup(const LLSpatialGroup& rhs) + LLSpatialGroup(const LLSpatialGroup& rhs) : LLOcclusionCullingGroup(rhs) { *this = rhs; } @@ -220,11 +229,10 @@ class LLSpatialGroup : public LLOctreeListener const LLSpatialGroup& operator=(const LLSpatialGroup& rhs) { - llerrs << "Illegal operation!" << llendl; + LL_ERRS() << "Illegal operation!" << LL_ENDL; return *this; } - static std::set sPendingQueries; //pending occlusion queries static U32 sNodeCount; static BOOL sNoDelete; //deletion of spatial groups and draw info not allowed if TRUE @@ -233,17 +241,10 @@ class LLSpatialGroup : public LLOctreeListener typedef std::vector > drawmap_elem_t; typedef std::map draw_map_t; typedef std::vector > buffer_list_t; - typedef std::map buffer_texture_map_t; - typedef std::map buffer_map_t; - - typedef LLOctreeListener BaseType; - typedef LLOctreeListener OctreeListener; - typedef LLTreeNode TreeNode; - typedef LLOctreeNode OctreeNode; - typedef LLOctreeRoot OctreeRoot; - typedef LLOctreeTraveler OctreeTraveler; - typedef LLOctreeNode::element_iter element_iter; - typedef LLOctreeNode::element_list element_list; + typedef std::vector > buffer_texture_vec_t; + typedef std::vector > buffer_vec_t; + + struct CompareDistanceGreater { @@ -271,119 +272,59 @@ class LLSpatialGroup : public LLOctreeListener typedef enum { - OCCLUDED = 0x00010000, - QUERY_PENDING = 0x00020000, - ACTIVE_OCCLUSION = 0x00040000, - DISCARD_QUERY = 0x00080000, - EARLY_FAIL = 0x00100000, - } eOcclusionState; - - typedef enum - { - DEAD = 0x00000001, - DIRTY = 0x00000002, - OBJECT_DIRTY = 0x00000004, - GEOM_DIRTY = 0x00000008, - ALPHA_DIRTY = 0x00000010, - SKIP_FRUSTUM_CHECK = 0x00000020, - IN_IMAGE_QUEUE = 0x00000040, - IMAGE_DIRTY = 0x00000080, - MESH_DIRTY = 0x00000100, - NEW_DRAWINFO = 0x00000200, - IN_BUILD_Q1 = 0x00000400, - IN_BUILD_Q2 = 0x00000800, + GEOM_DIRTY = LLViewerOctreeGroup::INVALID_STATE, + ALPHA_DIRTY = (GEOM_DIRTY << 1), + IN_IMAGE_QUEUE = (ALPHA_DIRTY << 1), + IMAGE_DIRTY = (IN_IMAGE_QUEUE << 1), + MESH_DIRTY = (IMAGE_DIRTY << 1), + NEW_DRAWINFO = (MESH_DIRTY << 1), + IN_BUILD_Q1 = (NEW_DRAWINFO << 1), + IN_BUILD_Q2 = (IN_BUILD_Q1 << 1), STATE_MASK = 0x0000FFFF, } eSpatialState; - typedef enum - { - STATE_MODE_SINGLE = 0, //set one node - STATE_MODE_BRANCH, //set entire branch - STATE_MODE_DIFF, //set entire branch as long as current state is different - STATE_MODE_ALL_CAMERAS, //used for occlusion state, set state for all cameras - } eSetStateMode; - LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part); BOOL isHUDGroup() ; - BOOL isDead() { return isState(DEAD); } - BOOL isState(eSpatialState state) const; //Using enum type here and below to force type-safeness. - BOOL isOcclusionState(eOcclusionState state) const { return mOcclusionState[LLViewerCamera::sCurCameraID] & state ? TRUE : FALSE; } - U32 getState() { return mState; } - void setState(eSpatialState state); - void clearState(eSpatialState state); void clearDrawMap(); void validate(); - void checkStates(); void validateDrawMap(); void setState(eSpatialState state, S32 mode); void clearState(eSpatialState state, S32 mode); - - void setOcclusionState(eOcclusionState state, S32 mode = STATE_MODE_SINGLE); - void clearOcclusionState(eOcclusionState state, S32 mode = STATE_MODE_SINGLE); + void clearState(eSpatialState state) {mState &= ~state;} + bool hasState(eSpatialState state) const {return mState & state;} LLSpatialGroup* getParent(); - - BOOL addObject(LLDrawable *drawablep, BOOL add_all = FALSE, BOOL from_octree = FALSE); + BOOL addObject(LLDrawable *drawablep); BOOL removeObject(LLDrawable *drawablep, BOOL from_octree = FALSE); BOOL updateInGroup(LLDrawable *drawablep, BOOL immediate = FALSE); // Update position if it's in the group - BOOL isVisible() const; - BOOL isRecentlyVisible() const; - void setVisible(); void shift(const LLVector4a &offset); - BOOL boundObjects(BOOL empty, LLVector4a& newMin, LLVector4a& newMax); - void unbound(); - BOOL rebound(); - void checkOcclusion(); //read back last occlusion query (if any) - void doOcclusion(LLCamera* camera); //issue occlusion query void destroyGL(bool keep_occlusion = false); void updateDistance(LLCamera& camera); - BOOL needsUpdate(); F32 getUpdateUrgency() const; BOOL changeLOD(); void rebuildGeom(); void rebuildMesh(); + void setState(eSpatialState state) {mState |= state;} void dirtyGeom() { setState(GEOM_DIRTY); } void dirtyMesh() { setState(MESH_DIRTY); } - //octree wrappers to make code more readable - //element_list& getData() { return mOctreeNode->getData(); } //unused - element_iter getDataBegin() { return mOctreeNode->getDataBegin(); } - element_iter getDataEnd() { return mOctreeNode->getDataEnd(); } - bool hasElement(LLDrawable* drawablep) { return std::find(mOctreeNode->getDataBegin(), mOctreeNode->getDataEnd(), drawablep) != mOctreeNode->getDataEnd(); } - U32 getElementCount() const { return mOctreeNode->getElementCount(); } - bool isEmpty() const { return mOctreeNode->isEmpty(); } - void drawObjectBox(LLColor4 col); + LLSpatialPartition* getSpatialPartition() const {return mSpatialPartition;} + //LISTENER FUNCTIONS - virtual void handleInsertion(const TreeNode* node, LLDrawable* face); - virtual void handleRemoval(const TreeNode* node, LLDrawable* face); - virtual void handleDestruction(const TreeNode* node); - virtual void handleStateChange(const TreeNode* node); - virtual void handleChildAddition(const OctreeNode* parent, OctreeNode* child); - virtual void handleChildRemoval(const OctreeNode* parent, const OctreeNode* child); + void handleInsertion(const TreeNode* node, LLViewerOctreeEntry* face) final override; + void handleRemoval(const TreeNode* node, LLViewerOctreeEntry* face) final override; + void handleDestruction(const TreeNode* node) final override; + void handleChildAddition(const OctreeNode* parent, OctreeNode* child) final override; + - typedef enum - { - BOUNDS = 0, - EXTENTS = 2, - OBJECT_BOUNDS = 4, - OBJECT_EXTENTS = 6, - VIEW_ANGLE = 8, - LAST_VIEW_ANGLE = 9, - V4_COUNT = 10 - } eV4Index; - - LL_ALIGN_16(LLVector4a mBounds[2]); // bounding box (center, size) of this node and all its children (tight fit to objects) - LL_ALIGN_16(LLVector4a mExtents[2]); // extents (min, max) of this node and all its children - LL_ALIGN_16(LLVector4a mObjectExtents[2]); // extents (min, max) of objects in this node - LL_ALIGN_16(LLVector4a mObjectBounds[2]); // bounding box (center, size) of objects in this node LL_ALIGN_16(LLVector4a mViewAngle); LL_ALIGN_16(LLVector4a mLastUpdateViewAngle); @@ -392,30 +333,22 @@ class LLSpatialGroup : public LLOctreeListener protected: virtual ~LLSpatialGroup(); - U32 mState; - U32 mOcclusionState[LLViewerCamera::NUM_CAMERAS]; - U32 mOcclusionIssued[LLViewerCamera::NUM_CAMERAS]; - S32 mLODHash; static S32 sLODSeed; public: bridge_list_t mBridgeList; - buffer_map_t mBufferMap; //used by volume buffers to store unique buffers per texture + buffer_vec_t mBufferVec; //used by volume buffers to store unique buffers per texture U32 mGeometryBytes; //used by volumes to track how many bytes of geometry data are in this node F32 mSurfaceArea; //used by volumes to track estimated surface area of geometry in this node F32 mBuilt; - OctreeNode* mOctreeNode; - LLSpatialPartition* mSpatialPartition; - + LLPointer mVertexBuffer; - GLuint mOcclusionQuery[LLViewerCamera::NUM_CAMERAS]; U32 mBufferUsage; draw_map_t mDrawMap; - S32 mVisible[LLViewerCamera::NUM_CAMERAS]; F32 mDistance; F32 mDepth; F32 mLastUpdateDistance; @@ -447,23 +380,24 @@ class LLGeometryManager virtual LLVertexBuffer* createVertexBuffer(U32 type_mask, U32 usage); }; -class LLSpatialPartition: public LLGeometryManager +class LLSpatialPartition: public LLViewerOctreePartition, public LLGeometryManager { public: //static BOOL sFreezeState; //if true, no spatialgroup state updates will be made - LLSpatialPartition(U32 data_mask, BOOL render_by_group, U32 mBufferUsage); + LLSpatialPartition(U32 data_mask, BOOL render_by_group, U32 mBufferUsage, LLViewerRegion* regionp); virtual ~LLSpatialPartition(); LLSpatialGroup *put(LLDrawable *drawablep, BOOL was_visible = FALSE); BOOL remove(LLDrawable *drawablep, LLSpatialGroup *curp); - LLDrawable* lineSegmentIntersect(const LLVector3& start, const LLVector3& end, + LLDrawable* lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, BOOL pick_transparent, + BOOL pick_rigged, S32* face_hit, // return the face hit - LLVector3* intersection = NULL, // return the intersection point + LLVector4a* intersection = NULL, // return the intersection point LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point - LLVector3* normal = NULL, // return the surface normal at the intersection point - LLVector3* bi_normal = NULL // return the surface bi-normal at the intersection point + LLVector4a* normal = NULL, // return the surface normal at the intersection point + LLVector4a* tangent = NULL // return the surface tangent at the intersection point ); @@ -478,7 +412,8 @@ class LLSpatialPartition: public LLGeometryManager virtual void rebuildMesh(LLSpatialGroup* group); BOOL visibleObjectsInFrustum(LLCamera& camera); - S32 cull(LLCamera &camera, std::vector* results = NULL, BOOL for_select = FALSE); // Cull on arbitrary frustum + /*virtual*/ S32 cull(LLCamera &camera, bool do_occlusion=false); // Cull on arbitrary frustum + S32 cull(LLCamera &camera, std::vector* results); // Cull on arbitrary frustum BOOL isVisible(const LLVector3& v); bool isHUDPartition() ; @@ -491,25 +426,21 @@ class LLSpatialPartition: public LLGeometryManager void renderIntersectingBBoxes(LLCamera* camera); void restoreGL(); void resetVertexBuffers(); - BOOL isOcclusionEnabled(); BOOL getVisibleExtents(LLCamera& camera, LLVector3& visMin, LLVector3& visMax); public: - LLSpatialGroup::OctreeNode* mOctree; LLSpatialBridge* mBridge; // NULL for non-LLSpatialBridge instances, otherwise, mBridge == this // use a pointer instead of making "isBridge" and "asBridge" virtual so it's safe // to call asBridge() from the destructor - BOOL mOcclusionEnabled; // if TRUE, occlusion culling is performed + BOOL mInfiniteFarClip; // if TRUE, frustum culling ignores far clip plane U32 mBufferUsage; const BOOL mRenderByGroup; - U32 mLODSeed; - U32 mLODPeriod; //number of frames between LOD updates for a given spatial group (staggered by mLODSeed) U32 mVertexDataMask; F32 mSlopRatio; //percentage distance must change before drawables receive LOD update (default is 0.25); BOOL mDepthMask; //if TRUE, objects in this partition will be written to depth during alpha rendering - U32 mDrawableType; - U32 mPartitionType; + + static BOOL sTeleportRequested; //started to issue a teleport request }; // class for creating bridges between spatial partitions @@ -521,7 +452,7 @@ class LLSpatialBridge : public LLDrawable, public LLSpatialPartition public: typedef std::vector > bridge_vector_t; - LLSpatialBridge(LLDrawable* root, BOOL render_by_group, U32 data_mask); + LLSpatialBridge(LLDrawable* root, BOOL render_by_group, U32 data_mask, LLViewerRegion* regionp); void destroyTree(); @@ -540,7 +471,6 @@ class LLSpatialBridge : public LLDrawable, public LLSpatialPartition virtual LLCamera transformCamera(LLCamera& camera); LLDrawable* mDrawable; - LLPointer mAvatar; }; class LLCullResult @@ -548,7 +478,7 @@ class LLCullResult public: LLCullResult() {} - typedef std::vector sg_list_t; + typedef std::vector > sg_list_t; typedef std::vector drawable_list_t; typedef std::vector bridge_list_t; typedef std::vector drawinfo_list_t; @@ -610,7 +540,7 @@ class LLCullResult class LLWaterPartition : public LLSpatialPartition { public: - LLWaterPartition(); + LLWaterPartition(LLViewerRegion* regionp); virtual void getGeometry(LLSpatialGroup* group) { } virtual void addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32& index_count) { } }; @@ -619,14 +549,14 @@ class LLWaterPartition : public LLSpatialPartition class LLVoidWaterPartition : public LLWaterPartition { public: - LLVoidWaterPartition(); + LLVoidWaterPartition(LLViewerRegion* regionp); }; //spatial partition for terrain (impelmented in LLVOSurfacePatch.cpp) class LLTerrainPartition : public LLSpatialPartition { public: - LLTerrainPartition(); + LLTerrainPartition(LLViewerRegion* regionp); virtual void getGeometry(LLSpatialGroup* group); virtual LLVertexBuffer* createVertexBuffer(U32 type_mask, U32 usage); }; @@ -635,7 +565,7 @@ class LLTerrainPartition : public LLSpatialPartition class LLTreePartition : public LLSpatialPartition { public: - LLTreePartition(); + LLTreePartition(LLViewerRegion* regionp); virtual void getGeometry(LLSpatialGroup* group) { } virtual void addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32& index_count) { } @@ -645,7 +575,7 @@ class LLTreePartition : public LLSpatialPartition class LLParticlePartition : public LLSpatialPartition { public: - LLParticlePartition(); + LLParticlePartition(LLViewerRegion* regionp); virtual void rebuildGeom(LLSpatialGroup* group); virtual void getGeometry(LLSpatialGroup* group); virtual void addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32& index_count); @@ -657,14 +587,14 @@ class LLParticlePartition : public LLSpatialPartition class LLHUDParticlePartition : public LLParticlePartition { public: - LLHUDParticlePartition(); + LLHUDParticlePartition(LLViewerRegion* regionp); }; //spatial partition for grass (implemented in LLVOGrass.cpp) class LLGrassPartition : public LLSpatialPartition { public: - LLGrassPartition(); + LLGrassPartition(LLViewerRegion* regionp); virtual void getGeometry(LLSpatialGroup* group); virtual void addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32& index_count); protected: @@ -676,7 +606,7 @@ class LLGrassPartition : public LLSpatialPartition class LLCloudPartition : public LLParticlePartition { public: - LLCloudPartition(); + LLCloudPartition(LLViewerRegion* regionp); }; #endif @@ -691,19 +621,32 @@ class LLVolumeGeometryManager: public LLGeometryManager DISTANCE_SORT } eSortType; - virtual ~LLVolumeGeometryManager() { } + LLVolumeGeometryManager(); + virtual ~LLVolumeGeometryManager(); virtual void rebuildGeom(LLSpatialGroup* group); virtual void rebuildMesh(LLSpatialGroup* group); virtual void getGeometry(LLSpatialGroup* group); - void genDrawInfo(LLSpatialGroup* group, U32 mask, std::vector& faces, BOOL distance_sort = FALSE, BOOL batch_textures = FALSE); + void genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace** faces, U32 face_count, BOOL distance_sort = FALSE, BOOL batch_textures = FALSE); void registerFace(LLSpatialGroup* group, LLFace* facep, U32 type); +private: + void allocateFaces(U32 pMaxFaceCount); + void freeFaces(); + + static int32_t sInstanceCount; + static LLFace** sFullbrightFaces; + static LLFace** sBumpFaces; + static LLFace** sSimpleFaces; + static LLFace** sNormFaces; + static LLFace** sSpecFaces; + static LLFace** sNormSpecFaces; + static LLFace** sAlphaFaces; }; //spatial partition that uses volume geometry manager (implemented in LLVOVolume.cpp) class LLVolumePartition : public LLSpatialPartition, public LLVolumeGeometryManager { public: - LLVolumePartition(); + LLVolumePartition(LLViewerRegion* regionp); virtual void rebuildGeom(LLSpatialGroup* group) { LLVolumeGeometryManager::rebuildGeom(group); } virtual void getGeometry(LLSpatialGroup* group) { LLVolumeGeometryManager::getGeometry(group); } virtual void rebuildMesh(LLSpatialGroup* group) { LLVolumeGeometryManager::rebuildMesh(group); } @@ -714,17 +657,23 @@ class LLVolumePartition : public LLSpatialPartition, public LLVolumeGeometryMana class LLVolumeBridge : public LLSpatialBridge, public LLVolumeGeometryManager { public: - LLVolumeBridge(LLDrawable* drawable); + LLVolumeBridge(LLDrawable* drawable, LLViewerRegion* regionp); virtual void rebuildGeom(LLSpatialGroup* group) { LLVolumeGeometryManager::rebuildGeom(group); } virtual void getGeometry(LLSpatialGroup* group) { LLVolumeGeometryManager::getGeometry(group); } virtual void rebuildMesh(LLSpatialGroup* group) { LLVolumeGeometryManager::rebuildMesh(group); } virtual void addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32& index_count) { LLVolumeGeometryManager::addGeometryCount(group, vertex_count, index_count); } }; +class LLAttachmentBridge : public LLVolumeBridge +{ +public: + LLAttachmentBridge(LLDrawable* drawable, LLViewerRegion* regionp); +}; + class LLHUDBridge : public LLVolumeBridge { public: - LLHUDBridge(LLDrawable* drawablep); + LLHUDBridge(LLDrawable* drawablep, LLViewerRegion* regionp); virtual void shiftPos(const LLVector4a& vec); virtual F32 calcPixelArea(LLSpatialGroup* group, LLCamera& camera); }; @@ -733,16 +682,23 @@ class LLHUDBridge : public LLVolumeBridge class LLBridgePartition : public LLSpatialPartition { public: - LLBridgePartition(); + LLBridgePartition(LLViewerRegion* regionp); virtual void getGeometry(LLSpatialGroup* group) { } virtual void addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32& index_count) { } }; +//spatial partition that holds nothing but spatial bridges +class LLAttachmentPartition : public LLBridgePartition +{ +public: + LLAttachmentPartition(LLViewerRegion* regionp); +}; + class LLHUDPartition : public LLBridgePartition { public: - LLHUDPartition(); - virtual void shift(const LLVector4a &offset); + LLHUDPartition(LLViewerRegion* regionp); + virtual void shift(const LLVector4a &offset) { } //HUD objects don't shift with region crossing. That would be silly. }; extern const F32 SG_BOX_SIDE; diff --git a/indra/newview/llspeakers.cpp b/indra/newview/llspeakers.cpp index 0f15435dc7..2eb588e7de 100644 --- a/indra/newview/llspeakers.cpp +++ b/indra/newview/llspeakers.cpp @@ -32,6 +32,7 @@ #include "llavatarnamecache.h" #include "llimpanel.h" // For LLFloaterIMPanel #include "llimview.h" +#include "llgroupmgr.h" #include "llsdutil.h" #include "llui.h" #include "llviewerobjectlist.h" @@ -41,37 +42,57 @@ #include "rlvhandler.h" -extern AIHTTPTimeoutPolicy moderationResponder_timeout; - const LLColor4 INACTIVE_COLOR(0.3f, 0.3f, 0.3f, 0.5f); const LLColor4 ACTIVE_COLOR(0.5f, 0.5f, 0.5f, 1.f); -LLSpeaker::LLSpeaker(const LLUUID& id, const std::string& name, const ESpeakerType type) : - mStatus(LLSpeaker::STATUS_TEXT_ONLY), +LLSpeaker::LLSpeaker(const speaker_entry_t& entry) : + mID(entry.id), + mStatus(entry.status), + mType(entry.type), + mIsModerator(entry.moderator != boost::none && *entry.moderator), + mModeratorMutedText(entry.moderator_muted_text != boost::none && *entry.moderator_muted_text), + mModeratorMutedVoice(FALSE), mLastSpokeTime(0.f), mSpeechVolume(0.f), mHasSpoken(FALSE), mHasLeftCurrentCall(FALSE), mDotColor(LLColor4::white), - mID(id), mTyping(FALSE), mSortIndex(0), - mType(type), - mIsModerator(FALSE), - mModeratorMutedVoice(FALSE), - mModeratorMutedText(FALSE) + mDisplayName(entry.name), + mNeedsResort(true) { - // Make sure we also get the display name if SLIM or some other external voice client is used and not whatever is provided. - if ((name.empty() && type == SPEAKER_AGENT) || type == SPEAKER_EXTERNAL) + if (mType == SPEAKER_AGENT) { lookupName(); } - else +} + +void LLSpeaker::update(const speaker_entry_t& entry) +{ + // keep highest priority status (lowest value) instead of overriding current value + setStatus(llmin(mStatus, entry.status)); + if (entry.moderator != boost::none) { - mDisplayName = name; + mIsModerator = *entry.moderator; } -} + if (entry.moderator_muted_text != boost::none) + { + mModeratorMutedText = *entry.moderator_muted_text; + }; + // RN: due to a weird behavior where IMs from attached objects come from the wearer's agent_id + // we need to override speakers that we think are objects when we find out they are really + // residents + if (entry.type == LLSpeaker::SPEAKER_AGENT) + { + mType = LLSpeaker::SPEAKER_AGENT; + lookupName(); + } + + if (mDisplayName.empty()) + setName(entry.name); +} void LLSpeaker::lookupName() { @@ -79,7 +100,7 @@ void LLSpeaker::lookupName() { // [RLVa:KB] - Checked: 2009-07-10 (RLVa-1.0.0g) | Added: RLVa-1.0.0g if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES) && gAgentID != mID) - mDisplayName = RlvStrings::getAnonym(mDisplayName); + setName(RlvStrings::getAnonym(mDisplayName)); else // [/RLVa:KB] LLAvatarNameCache::get(mID, boost::bind(&LLSpeaker::onNameCache, this, _2)); @@ -88,11 +109,11 @@ void LLSpeaker::lookupName() void LLSpeaker::onNameCache(const LLAvatarName& full_name) { - static const LLCachedControl legacy_name("LiruLegacySpeakerNames"); - if (legacy_name) - mDisplayName = gCacheName->cleanFullName(full_name.getLegacyName()); + static const LLCachedControl name_system("SpeakerNameSystem"); + if (!name_system) + setName(gCacheName->cleanFullName(full_name.getLegacyName())); else - LLAvatarNameCache::getPNSName(full_name, mDisplayName); + setName(full_name.getNSName(name_system)); } bool LLSpeaker::isInVoiceChannel() @@ -100,6 +121,19 @@ bool LLSpeaker::isInVoiceChannel() return mStatus <= LLSpeaker::STATUS_VOICE_ACTIVE || mStatus == LLSpeaker::STATUS_MUTED; } +LLSpeakerUpdateSpeakerEvent::LLSpeakerUpdateSpeakerEvent(LLSpeaker* source) +: LLEvent(source, "Speaker update speaker event"), + mSpeakerID (source->mID) +{ +} + +LLSD LLSpeakerUpdateSpeakerEvent::getValue() +{ + LLSD ret; + ret["id"] = mSpeakerID; + return ret; +} + LLSpeakerUpdateModeratorEvent::LLSpeakerUpdateModeratorEvent(LLSpeaker* source) : LLEvent(source, "Speaker add moderator event"), mSpeakerID (source->mID), @@ -189,7 +223,7 @@ BOOL LLSpeakerActionTimer::tick() void LLSpeakerActionTimer::unset() { - mActionCallback = 0; + mActionCallback = nullptr; } LLSpeakersDelayActionsStorage::LLSpeakersDelayActionsStorage(LLSpeakerActionTimer::action_callback_t action_cb, F32 action_delay) @@ -206,7 +240,7 @@ LLSpeakersDelayActionsStorage::~LLSpeakersDelayActionsStorage() void LLSpeakersDelayActionsStorage::setActionTimer(const LLUUID& speaker_id) { bool not_found = true; - if (mActionTimersMap.size() > 0) + if (!mActionTimersMap.empty()) { not_found = mActionTimersMap.find(speaker_id) == mActionTimersMap.end(); } @@ -224,7 +258,7 @@ void LLSpeakersDelayActionsStorage::setActionTimer(const LLUUID& speaker_id) void LLSpeakersDelayActionsStorage::unsetActionTimer(const LLUUID& speaker_id) { - if (mActionTimersMap.size() == 0) return; + if (mActionTimersMap.empty()) return; LLSpeakerActionTimer::action_timer_iter_t it_speaker = mActionTimersMap.find(speaker_id); @@ -257,6 +291,11 @@ bool LLSpeakersDelayActionsStorage::onTimerActionCallback(const LLUUID& speaker_ return true; } +bool LLSpeakersDelayActionsStorage::isTimerStarted(const LLUUID& speaker_id) +{ + return (mActionTimersMap.size() > 0) && (mActionTimersMap.find(speaker_id) != mActionTimersMap.end()); +} + // // ModerationResponder // @@ -269,9 +308,10 @@ class ModerationResponder : public LLHTTPClient::ResponderIgnoreBody mSessionID = session_id; } - /*virtual*/ void error(U32 status, const std::string& reason) +protected: + virtual void httpFailure() { - llwarns << "ModerationResponder error [status:" << status << "]: " << reason << llendl; + LL_WARNS() << dumpResponse() << LL_ENDL; if ( gIMMgr ) { @@ -280,7 +320,7 @@ class ModerationResponder : public LLHTTPClient::ResponderIgnoreBody //403 == you're not a mod //should be disabled if you're not a moderator - if ( 403 == status ) + if ( 403 == mStatus ) { floaterp->showSessionEventError( "mute", @@ -294,7 +334,6 @@ class ModerationResponder : public LLHTTPClient::ResponderIgnoreBody } } } - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return moderationResponder_timeout; } /*virtual*/ char const* getName(void) const { return "ModerationResponder"; } private: @@ -308,8 +347,10 @@ class ModerationResponder : public LLHTTPClient::ResponderIgnoreBody LLSpeakerMgr::LLSpeakerMgr(LLVoiceChannel* channelp) : mVoiceChannel(channelp), mVoiceModerated(false), - mModerateModeHandledFirstTime(false) + mModerateModeHandledFirstTime(false), + mSpeakerListUpdated(false) { + mGetListTime.reset(); static LLUICachedControl remove_delay ("SpeakerParticipantRemoveDelay", 10.0); mSpeakerDelayRemover = new LLSpeakersDelayActionsStorage(boost::bind(&LLSpeakerMgr::removeSpeaker, this, _1), remove_delay); @@ -320,46 +361,42 @@ LLSpeakerMgr::~LLSpeakerMgr() delete mSpeakerDelayRemover; } -LLPointer LLSpeakerMgr::setSpeaker(const LLUUID& id, const std::string& name, LLSpeaker::ESpeakerStatus status, LLSpeaker::ESpeakerType type) +void LLSpeakerMgr::setSpeakers(const std::vector& speakers) +{ + if (!speakers.empty()) + { + fireEvent(new LLOldEvents::LLEvent(this), "batch_begin"); + for (auto entry : speakers) + { + setSpeaker(entry); + } + fireEvent(new LLOldEvents::LLEvent(this), "batch_end"); + } +} + +LLPointer LLSpeakerMgr::setSpeaker(const speaker_entry_t& entry) { - if (id.isNull()) + LLUUID session_id = getSessionID(); + const LLUUID& id = entry.id; + if (id.isNull() || (id == session_id)) { return NULL; } LLPointer speakerp; - if (mSpeakers.find(id) == mSpeakers.end()) + auto it = mSpeakers.find(id); + if (it == mSpeakers.end() || it->second.isNull()) { - speakerp = new LLSpeaker(id, name, type); - speakerp->mStatus = status; - mSpeakers.insert(std::make_pair(speakerp->mID, speakerp)); - mSpeakersSorted.push_back(speakerp); - LL_DEBUGS("Speakers") << "Added speaker " << id << llendl; - fireEvent(new LLSpeakerListChangeEvent(this, speakerp->mID), "add"); + mSpeakersSorted.emplace_back(new LLSpeaker(entry)); + mSpeakers.emplace(id, mSpeakersSorted.back()); + fireEvent(new LLSpeakerListChangeEvent(this, id), "add"); } else { - speakerp = findSpeaker(id); - if (speakerp.notNull()) - { - // keep highest priority status (lowest value) instead of overriding current value - speakerp->mStatus = llmin(speakerp->mStatus, status); - // RN: due to a weird behavior where IMs from attached objects come from the wearer's agent_id - // we need to override speakers that we think are objects when we find out they are really - // residents - if (type == LLSpeaker::SPEAKER_AGENT) - { - speakerp->mType = LLSpeaker::SPEAKER_AGENT; - speakerp->lookupName(); - } - } - else - { - LL_WARNS("Speakers") << "Speaker " << id << " not found" << llendl; - } + it->second->update(entry); } - mSpeakerDelayRemover->unsetActionTimer(speakerp->mID); + mSpeakerDelayRemover->unsetActionTimer(entry.id); return speakerp; } @@ -397,8 +434,8 @@ void LLSpeakerMgr::update(BOOL resort_ok) return; } - LLColor4 speaking_color = gSavedSettings.getColor4("SpeakingColor"); - LLColor4 overdriven_color = gSavedSettings.getColor4("OverdrivenColor"); + static const LLCachedControl speaking_color(gSavedSettings, "SpeakingColor"); + static const LLCachedControl overdriven_color(gSavedSettings, "OverdrivenColor"); if(resort_ok) // only allow list changes when user is not interacting with it { @@ -407,35 +444,37 @@ void LLSpeakerMgr::update(BOOL resort_ok) // update status of all current speakers BOOL voice_channel_active = (!mVoiceChannel && LLVoiceClient::getInstance()->inProximalChannel()) || (mVoiceChannel && mVoiceChannel->isActive()); - for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); speaker_it++) + bool re_sort = false; + for (auto& speaker : mSpeakers) { - LLUUID speaker_id = speaker_it->first; - LLSpeaker* speakerp = speaker_it->second; + LLUUID speaker_id = speaker.first; + LLSpeaker* speakerp = speaker.second; if (voice_channel_active && LLVoiceClient::getInstance()->getVoiceEnabled(speaker_id)) { speakerp->mSpeechVolume = LLVoiceClient::getInstance()->getCurrentPower(speaker_id); - BOOL moderator_muted_voice = LLVoiceClient::getInstance()->getIsModeratorMuted(speaker_id); + bool moderator_muted_voice = LLVoiceClient::getInstance()->getIsModeratorMuted(speaker_id); if (moderator_muted_voice != speakerp->mModeratorMutedVoice) { speakerp->mModeratorMutedVoice = moderator_muted_voice; - LL_DEBUGS("Speakers") << (speakerp->mModeratorMutedVoice? "Muted" : "Umuted") << " speaker " << speaker_id<< llendl; + LL_DEBUGS("Speakers") << (speakerp->mModeratorMutedVoice? "Muted" : "Umuted") << " speaker " << speaker_id<< LL_ENDL; speakerp->fireEvent(new LLSpeakerVoiceModerationEvent(speakerp)); } if (LLVoiceClient::getInstance()->getOnMuteList(speaker_id) || speakerp->mModeratorMutedVoice) { - speakerp->mStatus = LLSpeaker::STATUS_MUTED; + speakerp->setStatus(LLSpeaker::STATUS_MUTED); } else if (LLVoiceClient::getInstance()->getIsSpeaking(speaker_id)) { // reset inactivity expiration if (speakerp->mStatus != LLSpeaker::STATUS_SPEAKING) { - speakerp->mLastSpokeTime = mSpeechTimer.getElapsedTimeF32(); + speakerp->setSpokenTime(mSpeechTimer.getElapsedTimeF32()); speakerp->mHasSpoken = TRUE; + fireEvent(new LLSpeakerUpdateSpeakerEvent(speakerp), "update_speaker"); } - speakerp->mStatus = LLSpeaker::STATUS_SPEAKING; + speakerp->setStatus(LLSpeaker::STATUS_SPEAKING); // interpolate between active color and full speaking color based on power of speech output speakerp->mDotColor = speaking_color; if (speakerp->mSpeechVolume > LLVoiceClient::OVERDRIVEN_POWER_LEVEL) @@ -451,12 +490,12 @@ void LLSpeakerMgr::update(BOOL resort_ok) if (speakerp->mHasSpoken) { // have spoken once, not currently speaking - speakerp->mStatus = LLSpeaker::STATUS_HAS_SPOKEN; + speakerp->setStatus(LLSpeaker::STATUS_HAS_SPOKEN); } else { // default state for being in voice channel - speakerp->mStatus = LLSpeaker::STATUS_VOICE_ACTIVE; + speakerp->setStatus(LLSpeaker::STATUS_VOICE_ACTIVE); } } } @@ -470,39 +509,49 @@ void LLSpeakerMgr::update(BOOL resort_ok) } else { - speakerp->mStatus = LLSpeaker::STATUS_TEXT_ONLY; + speakerp->setStatus(LLSpeaker::STATUS_TEXT_ONLY); speakerp->mSpeechVolume = 0.f; speakerp->mDotColor = ACTIVE_COLOR; } } + if (speakerp->mNeedsResort) + { + re_sort = true; + speakerp->mNeedsResort = false; + } } - if(resort_ok) // only allow list changes when user is not interacting with it + if (resort_ok && re_sort) // only allow list changes when user is not interacting with it { // sort by status then time last spoken std::sort(mSpeakersSorted.begin(), mSpeakersSorted.end(), LLSortRecentSpeakers()); - } - // for recent speakers who are not currently speaking, show "recent" color dot for most recent - // fading to "active" color + // for recent speakers who are not currently speaking, show "recent" color dot for most recent + // fading to "active" color - S32 recent_speaker_count = 0; - S32 sort_index = 0; - speaker_list_t::iterator sorted_speaker_it; - for(sorted_speaker_it = mSpeakersSorted.begin(); - sorted_speaker_it != mSpeakersSorted.end(); ++sorted_speaker_it) - { - LLPointer speakerp = *sorted_speaker_it; + bool index_changed = false; + S32 recent_speaker_count = 0; + S32 sort_index = 0; + for (auto speakerp : mSpeakersSorted) + { + // color code recent speakers who are not currently speaking + if (speakerp->mStatus == LLSpeaker::STATUS_HAS_SPOKEN) + { + speakerp->mDotColor = lerp(speaking_color, ACTIVE_COLOR, clamp_rescale((F32)recent_speaker_count, -2.f, 3.f, 0.f, 1.f)); + recent_speaker_count++; + } - // color code recent speakers who are not currently speaking - if (speakerp->mStatus == LLSpeaker::STATUS_HAS_SPOKEN) + // stuff sort ordinal into speaker so the ui can sort by this value + if (speakerp->mSortIndex != sort_index++) + { + speakerp->mSortIndex = sort_index-1; + index_changed = true; + } + } + if (index_changed) { - speakerp->mDotColor = lerp(speaking_color, ACTIVE_COLOR, clamp_rescale((F32)recent_speaker_count, -2.f, 3.f, 0.f, 1.f)); - recent_speaker_count++; + fireEvent(new LLOldEvents::LLEvent(this), "update_sorting"); } - - // stuff sort ordinal into speaker so the ui can sort by this value - speakerp->mSortIndex = sort_index++; } } @@ -511,24 +560,107 @@ void LLSpeakerMgr::updateSpeakerList() // Are we bound to the currently active voice channel? if ((!mVoiceChannel && LLVoiceClient::getInstance()->inProximalChannel()) || (mVoiceChannel && mVoiceChannel->isActive())) { - std::set participants; + uuid_set_t participants; LLVoiceClient::getInstance()->getParticipantList(participants); // If we are, add all voice client participants to our list of known speakers - for (std::set::iterator participant_it = participants.begin(); participant_it != participants.end(); ++participant_it) + std::vector speakers; + speakers.reserve(participants.size()); + for (auto participant : participants) { - setSpeaker(*participant_it, - LLVoiceClient::getInstance()->getDisplayName(*participant_it), - LLSpeaker::STATUS_VOICE_ACTIVE, - (LLVoiceClient::getInstance()->isParticipantAvatar(*participant_it)?LLSpeaker::SPEAKER_AGENT:LLSpeaker::SPEAKER_EXTERNAL)); + speakers.emplace_back(participant, + (LLVoiceClient::getInstance()->isParticipantAvatar(participant) ? LLSpeaker::SPEAKER_AGENT : LLSpeaker::SPEAKER_EXTERNAL), + LLSpeaker::STATUS_VOICE_ACTIVE, + boost::none, + boost::none, + LLVoiceClient::getInstance()->getDisplayName(participant)); } + setSpeakers(speakers); } + else + { + // If not, check if the list is empty, except if it's Nearby Chat (session_id NULL). + LLUUID const& session_id = getSessionID(); + if (!session_id.isNull() && !mSpeakerListUpdated) + { + // If the list is empty, we update it with whatever we have locally so that it doesn't stay empty too long. + // *TODO: Fix the server side code that sometimes forgets to send back the list of participants after a chat started. + // (IOW, fix why we get no ChatterBoxSessionAgentListUpdates message after the initial ChatterBoxSessionStartReply) + /* Singu TODO: LLIMModel::LLIMSession + LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(session_id); + if (session->isGroupSessionType() && (mSpeakers.size() <= 1)) + */ + LLFloaterIMPanel* floater = gIMMgr->findFloaterBySession(session_id); + if (floater && floater->getSessionType() == LLFloaterIMPanel::GROUP_SESSION && (mSpeakers.size() <= 1)) + { + const F32 load_group_timeout = gSavedSettings.getF32("ChatLoadGroupTimeout"); + // For groups, we need to hit the group manager. + // Note: The session uuid and the group uuid are actually one and the same. If that was to change, this will fail. + LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(session_id); + if (!gdatap && (mGetListTime.getElapsedTimeF32() >= load_group_timeout)) + { + // Request the data the first time around + LLGroupMgr::getInstance()->sendCapGroupMembersRequest(session_id); + } + else if (gdatap && gdatap->isMemberDataComplete() && !gdatap->mMembers.empty()) + { + std::vector speakers; + speakers.reserve(gdatap->mMembers.size()); + + // Add group members when we get the complete list (note: can take a while before we get that list) + LLGroupMgrGroupData::member_list_t::iterator member_it = gdatap->mMembers.begin(); + while (member_it != gdatap->mMembers.end()) + { + LLGroupMemberData* member = member_it->second; + LLUUID id = member_it->first; + // Add only members who are online and not already in the list + const std::string& localized_online(); + if ((member->getOnlineStatus() == localized_online()) && (mSpeakers.find(id) == mSpeakers.end())) + { + speakers.emplace_back( + id, + LLSpeaker::SPEAKER_AGENT, + LLSpeaker::STATUS_VOICE_ACTIVE, + (member->getAgentPowers() & GP_SESSION_MODERATOR) == GP_SESSION_MODERATOR); + } + ++member_it; + } + setSpeakers(speakers); + mSpeakerListUpdated = true; + } + } + else if (floater && mSpeakers.empty()) + { + // For all other session type (ad-hoc, P2P, avaline), we use the initial participants targets list + for (const auto& target_id : floater->mInitialTargetIDs) + { + // Add buddies if they are on line, add any other avatar. + if (!LLAvatarTracker::instance().isBuddy(target_id) || LLAvatarTracker::instance().isBuddyOnline( + target_id)) + { + setSpeaker({target_id, LLSpeaker::SPEAKER_AGENT, LLSpeaker::STATUS_VOICE_ACTIVE }); + } + } + mSpeakerListUpdated = true; + } + else + { + // The list has been updated the normal way (i.e. by a ChatterBoxSessionAgentListUpdates received from the server) + mSpeakerListUpdated = true; + } + } + } + // Always add the current agent (it has to be there...). Will do nothing if already there. + setSpeaker({ gAgentID, LLSpeaker::SPEAKER_AGENT, LLSpeaker::STATUS_VOICE_ACTIVE }); } -void LLSpeakerMgr::setSpeakerNotInChannel(LLSpeaker* speakerp) +void LLSpeakerMgr::setSpeakerNotInChannel(LLPointer speakerp) { - speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL; - speakerp->mDotColor = INACTIVE_COLOR; - mSpeakerDelayRemover->setActionTimer(speakerp->mID); + if (speakerp.notNull()) + { + speakerp->setStatus(LLSpeaker::STATUS_NOT_IN_CHANNEL); + speakerp->mDotColor = INACTIVE_COLOR; + mSpeakerDelayRemover->setActionTimer(speakerp->mID); + } } bool LLSpeakerMgr::removeSpeaker(const LLUUID& speaker_id) @@ -546,7 +678,7 @@ bool LLSpeakerMgr::removeSpeaker(const LLUUID& speaker_id) } } - LL_DEBUGS("Speakers") << "Removed speaker " << speaker_id << llendl; + LL_DEBUGS("Speakers") << "Removed speaker " << speaker_id << LL_ENDL; fireEvent(new LLSpeakerListChangeEvent(this, speaker_id), "remove"); update(TRUE); @@ -557,12 +689,12 @@ bool LLSpeakerMgr::removeSpeaker(const LLUUID& speaker_id) LLPointer LLSpeakerMgr::findSpeaker(const LLUUID& speaker_id) { //In some conditions map causes crash if it is empty(Windows only), adding check (EK) - if (mSpeakers.size() == 0) - return NULL; + if (mSpeakers.empty()) + return nullptr; speaker_map_t::iterator found_it = mSpeakers.find(speaker_id); if (found_it == mSpeakers.end()) { - return NULL; + return nullptr; } return found_it->second; } @@ -570,9 +702,9 @@ LLPointer LLSpeakerMgr::findSpeaker(const LLUUID& speaker_id) void LLSpeakerMgr::getSpeakerList(speaker_list_t* speaker_list, BOOL include_text) { speaker_list->clear(); - for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); ++speaker_it) + for (auto& speaker : mSpeakers) { - LLPointer speakerp = speaker_it->second; + LLPointer speakerp = speaker.second; // what about text only muted or inactive? if (include_text || speakerp->mStatus != LLSpeaker::STATUS_TEXT_ONLY) { @@ -581,11 +713,15 @@ void LLSpeakerMgr::getSpeakerList(speaker_list_t* speaker_list, BOOL include_tex } } -const LLUUID LLSpeakerMgr::getSessionID() +const LLUUID LLSpeakerMgr::getSessionID() const { return mVoiceChannel->getSessionID(); } +bool LLSpeakerMgr::isSpeakerToBeRemoved(const LLUUID& speaker_id) const +{ + return mSpeakerDelayRemover && mSpeakerDelayRemover->isTimerStarted(speaker_id); +} void LLSpeakerMgr::setSpeakerTyping(const LLUUID& speaker_id, BOOL typing) { @@ -602,12 +738,13 @@ void LLSpeakerMgr::speakerChatted(const LLUUID& speaker_id) LLPointer speakerp = findSpeaker(speaker_id); if (speakerp.notNull()) { - speakerp->mLastSpokeTime = mSpeechTimer.getElapsedTimeF32(); + speakerp->setSpokenTime(mSpeechTimer.getElapsedTimeF32()); speakerp->mHasSpoken = TRUE; + fireEvent(new LLSpeakerUpdateSpeakerEvent(speakerp), "update_speaker"); } } -BOOL LLSpeakerMgr::isVoiceActive() +BOOL LLSpeakerMgr::isVoiceActive() const { // mVoiceChannel = NULL means current voice channel, whatever it is return LLVoiceClient::getInstance()->voiceEnabled() && mVoiceChannel && mVoiceChannel->isActive(); @@ -636,89 +773,76 @@ void LLIMSpeakerMgr::setSpeakers(const LLSD& speakers) { if ( !speakers.isMap() ) return; + std::vector speakerentries; if ( speakers.has("agent_info") && speakers["agent_info"].isMap() ) { - LLSD::map_const_iterator speaker_it; - for(speaker_it = speakers["agent_info"].beginMap(); - speaker_it != speakers["agent_info"].endMap(); - ++speaker_it) + for (const auto& speaker : speakers["agent_info"].map()) { - LLUUID agent_id(speaker_it->first); - - LLPointer speakerp = setSpeaker( - agent_id, - LLStringUtil::null, - LLSpeaker::STATUS_TEXT_ONLY); - - if ( speaker_it->second.isMap() ) + boost::optional moderator; + boost::optional moderator_muted; + if (speaker.second.isMap()) { - BOOL is_moderator = speakerp->mIsModerator; - speakerp->mIsModerator = speaker_it->second["is_moderator"]; - speakerp->mModeratorMutedText = - speaker_it->second["mutes"]["text"]; - // Fire event only if moderator changed - if ( is_moderator != speakerp->mIsModerator ) - { - LL_DEBUGS("Speakers") << "Speaker " << agent_id << (is_moderator ? "is now" : "no longer is") << " a moderator" << llendl; - fireEvent(new LLSpeakerUpdateModeratorEvent(speakerp), "update_moderator"); - } + moderator = speaker.second["is_moderator"]; + moderator_muted = speaker.second["mutes"]["text"]; } + speakerentries.emplace_back( + LLUUID(speaker.first), + LLSpeaker::SPEAKER_AGENT, + LLSpeaker::STATUS_TEXT_ONLY, + moderator, + moderator_muted + ); } } else if ( speakers.has("agents" ) && speakers["agents"].isArray() ) { //older, more decprecated way. Need here for //using older version of servers - LLSD::array_const_iterator speaker_it; - for(speaker_it = speakers["agents"].beginArray(); - speaker_it != speakers["agents"].endArray(); - ++speaker_it) + for (auto const& entry : speakers["agents"].array()) { - const LLUUID agent_id = (*speaker_it).asUUID(); - - LLPointer speakerp = setSpeaker( - agent_id, - LLStringUtil::null, - LLSpeaker::STATUS_TEXT_ONLY); + speakerentries.emplace_back(entry.asUUID()); } } + LLSpeakerMgr::setSpeakers(speakerentries); } void LLIMSpeakerMgr::updateSpeakers(const LLSD& update) { if ( !update.isMap() ) return; + std::vector speakerentries; if ( update.has("agent_updates") && update["agent_updates"].isMap() ) { - LLSD::map_const_iterator update_it; - for( - update_it = update["agent_updates"].beginMap(); - update_it != update["agent_updates"].endMap(); - ++update_it) + for (const auto& update_it : update["agent_updates"].map()) { - LLUUID agent_id(update_it->first); + LLUUID agent_id(update_it.first); LLPointer speakerp = findSpeaker(agent_id); - LLSD agent_data = update_it->second; + bool new_speaker = false; + boost::optional moderator; + boost::optional moderator_muted_text; + LLSD agent_data = update_it.second; if (agent_data.isMap() && agent_data.has("transition")) { - if (agent_data["transition"].asString() == "LEAVE" && speakerp.notNull()) + if (agent_data["transition"].asString() == "LEAVE") { setSpeakerNotInChannel(speakerp); } else if (agent_data["transition"].asString() == "ENTER") { // add or update speaker - speakerp = setSpeaker(agent_id); + new_speaker = true; } else { - llwarns << "bad membership list update " << ll_print_sd(agent_data["transition"]) << llendl; + LL_WARNS() << "bad membership list update from 'agent_updates' for agent " << agent_id << ", transition " << ll_print_sd(agent_data["transition"]) << LL_ENDL; } } - - if (speakerp.isNull()) continue; + if (speakerp.isNull() && !new_speaker) + { + continue; + } // should have a valid speaker from this point on if (agent_data.isMap() && agent_data.has("info")) @@ -727,62 +851,54 @@ void LLIMSpeakerMgr::updateSpeakers(const LLSD& update) if (agent_info.has("is_moderator")) { - BOOL is_moderator = speakerp->mIsModerator; - speakerp->mIsModerator = agent_info["is_moderator"]; - // Fire event only if moderator changed - if ( is_moderator != speakerp->mIsModerator ) - { - LL_DEBUGS("Speakers") << "Speaker " << agent_id << (is_moderator ? "is now" : "no longer is") << " a moderator" << llendl; - fireEvent(new LLSpeakerUpdateModeratorEvent(speakerp), "update_moderator"); - } + moderator = agent_info["is_moderator"]; } - if (agent_info.has("mutes")) { - speakerp->mModeratorMutedText = agent_info["mutes"]["text"]; + moderator_muted_text = agent_info["mutes"]["text"]; } } + speakerentries.emplace_back( + agent_id, + LLSpeaker::SPEAKER_AGENT, + LLSpeaker::STATUS_TEXT_ONLY, + moderator, + moderator_muted_text + ); } } else if ( update.has("updates") && update["updates"].isMap() ) { - LLSD::map_const_iterator update_it; - for ( - update_it = update["updates"].beginMap(); - update_it != update["updates"].endMap(); - ++update_it) + for (const auto& update_it : update["updates"].map()) { - LLUUID agent_id(update_it->first); + LLUUID agent_id(update_it.first); LLPointer speakerp = findSpeaker(agent_id); - std::string agent_transition = update_it->second.asString(); - if (agent_transition == "LEAVE" && speakerp.notNull()) + std::string agent_transition = update_it.second.asString(); + if (agent_transition == "LEAVE") { setSpeakerNotInChannel(speakerp); } else if ( agent_transition == "ENTER") { // add or update speaker - speakerp = setSpeaker(agent_id); + speakerentries.emplace_back(agent_id); } else { - llwarns << "bad membership list update " - << agent_transition << llendl; + LL_WARNS() << "bad membership list update from 'updates' for agent " << agent_id << ", transition " << agent_transition << LL_ENDL; } } } + LLSpeakerMgr::setSpeakers(speakerentries); } -/*prep# - virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content) - llwarns << "ModerationResponder error [status:" << status << "]: " << content << llendl; - */ + void LLIMSpeakerMgr::toggleAllowTextChat(const LLUUID& speaker_id) { LLPointer speakerp = findSpeaker(speaker_id); if (!speakerp) return; - std::string url = gAgent.getRegion()->getCapability("ChatSessionRequest"); + std::string url = gAgent.getRegionCapability("ChatSessionRequest"); LLSD data; data["method"] = "mute update"; data["session-id"] = getSessionID(); @@ -807,7 +923,7 @@ void LLIMSpeakerMgr::moderateVoiceParticipant(const LLUUID& avatar_id, bool unmu // do not send voice moderation changes for avatars not in voice channel if (!is_in_voice) return; - std::string url = gAgent.getRegion()->getCapability("ChatSessionRequest"); + std::string url = gAgent.getRegionCapability("ChatSessionRequest"); LLSD data; data["method"] = "mute update"; data["session-id"] = getSessionID(); @@ -847,7 +963,7 @@ void LLIMSpeakerMgr::processSessionUpdate(const LLSD& session_update) void LLIMSpeakerMgr::moderateVoiceSession(const LLUUID& session_id, bool disallow_voice) { - std::string url = gAgent.getRegion()->getCapability("ChatSessionRequest"); + std::string url = gAgent.getRegionCapability("ChatSessionRequest"); LLSD data; data["method"] = "session update"; data["session-id"] = session_id; @@ -863,13 +979,13 @@ void LLIMSpeakerMgr::moderateVoiceSession(const LLUUID& session_id, bool disallo void LLIMSpeakerMgr::forceVoiceModeratedMode(bool should_be_muted) { - for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); ++speaker_it) + for (auto& speaker : mSpeakers) { - LLUUID speaker_id = speaker_it->first; - LLSpeaker* speakerp = speaker_it->second; + LLUUID speaker_id = speaker.first; + LLSpeaker* speakerp = speaker.second; // participant does not match requested state - if (should_be_muted != (bool)speakerp->mModeratorMutedVoice) + if (should_be_muted != static_cast(speakerp->mModeratorMutedVoice)) { moderateVoiceParticipant(speaker_id, !should_be_muted); } @@ -887,12 +1003,13 @@ LLActiveSpeakerMgr::LLActiveSpeakerMgr() : LLSpeakerMgr(NULL) void LLActiveSpeakerMgr::updateSpeakerList() { // point to whatever the current voice channel is + const auto old_channel = mVoiceChannel; mVoiceChannel = LLVoiceChannel::getCurrentVoiceChannel(); // always populate from active voice channel - if (LLVoiceChannel::getCurrentVoiceChannel() != mVoiceChannel) //MA: seems this is always false + if (mVoiceChannel != old_channel) //Singu Note: Don't let this always be false. { - LL_DEBUGS("Speakers") << "Removed all speakers" << llendl; + LL_DEBUGS("Speakers") << "Removed all speakers" << LL_ENDL; fireEvent(new LLSpeakerListChangeEvent(this, LLUUID::null), "clear"); mSpeakers.clear(); mSpeakersSorted.clear(); @@ -902,10 +1019,9 @@ void LLActiveSpeakerMgr::updateSpeakerList() LLSpeakerMgr::updateSpeakerList(); // clean up text only speakers - for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); ++speaker_it) + for (auto& speaker : mSpeakers) { - LLUUID speaker_id = speaker_it->first; - LLSpeaker* speakerp = speaker_it->second; + LLSpeaker* speakerp = speaker.second; if (speakerp->mStatus == LLSpeaker::STATUS_TEXT_ONLY) { // automatically flag text only speakers for removal @@ -941,22 +1057,24 @@ void LLLocalSpeakerMgr::updateSpeakerList() // pick up non-voice speakers in chat range uuid_vec_t avatar_ids; - std::vector positions; - LLWorld::getInstance()->getAvatars(&avatar_ids, &positions, gAgent.getPositionGlobal(), CHAT_NORMAL_RADIUS); - for(U32 i=0; igetAvatars(&avatar_ids, nullptr, gAgent.getPositionGlobal(), CHAT_NORMAL_RADIUS); + std::vector speakers; + speakers.reserve(avatar_ids.size()); + for (const auto& id : avatar_ids) { - setSpeaker(avatar_ids[i]); + speakers.emplace_back(id); } + setSpeakers(speakers); // check if text only speakers have moved out of chat range - for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); ++speaker_it) + for (auto& speaker : mSpeakers) { - LLUUID speaker_id = speaker_it->first; - LLSpeaker* speakerp = speaker_it->second; - if (speakerp->mStatus == LLSpeaker::STATUS_TEXT_ONLY) + LLUUID speaker_id = speaker.first; + LLPointer speakerp = speaker.second; + if (speakerp.notNull() && speakerp->mStatus == LLSpeaker::STATUS_TEXT_ONLY) { LLVOAvatar* avatarp = gObjectList.findAvatar(speaker_id); - if (!avatarp || dist_vec_squared(avatarp->getPositionAgent(), gAgent.getPositionAgent()) > CHAT_NORMAL_RADIUS_SQUARED) + if (!avatarp || dist_vec_squared(avatarp->getPositionAgent(), gAgent.getPositionAgent()) > CHAT_NORMAL_RADIUS * CHAT_NORMAL_RADIUS) { setSpeakerNotInChannel(speakerp); } diff --git a/indra/newview/llspeakers.h b/indra/newview/llspeakers.h index 1d58d1b1dc..e28cd9a203 100644 --- a/indra/newview/llspeakers.h +++ b/indra/newview/llspeakers.h @@ -36,7 +36,7 @@ class LLSpeakerMgr; class LLVoiceChannel; // data for a given participant in a voice channel -class LLSpeaker : public LLRefCount, public LLOldEvents::LLObservable, public LLHandleProvider, public boost::signals2::trackable +class LLSpeaker final : public LLRefCount, public LLOldEvents::LLObservable, public LLHandleProvider, public boost::signals2::trackable { public: typedef enum e_speaker_type @@ -56,60 +56,118 @@ class LLSpeaker : public LLRefCount, public LLOldEvents::LLObservable, public LL STATUS_MUTED } ESpeakerStatus; - - LLSpeaker(const LLUUID& id, const std::string& name = LLStringUtil::null, const ESpeakerType type = SPEAKER_AGENT); - ~LLSpeaker() {}; + struct speaker_entry_t + { + speaker_entry_t(const LLUUID& id, + LLSpeaker::ESpeakerType type = ESpeakerType::SPEAKER_AGENT, + LLSpeaker::ESpeakerStatus status = ESpeakerStatus::STATUS_TEXT_ONLY, + const boost::optional moderator = boost::none, + const boost::optional moderator_muted_text = boost::none, + std::string name = std::string()) : + id(id), + type(type), + status(status), + moderator(moderator), + moderator_muted_text(moderator_muted_text), + name(name) + {} + const LLUUID id; + const LLSpeaker::ESpeakerType type; + const LLSpeaker::ESpeakerStatus status; + const boost::optional moderator; + const boost::optional moderator_muted_text; + const std::string name; + }; + + LLSpeaker(const speaker_entry_t& entry); + ~LLSpeaker() = default; + void update(const speaker_entry_t& entry); void lookupName(); void onNameCache(const LLAvatarName& full_name); bool isInVoiceChannel(); + void setStatus(ESpeakerStatus status) + { + if (status != mStatus) + { + mStatus = status; + mNeedsResort = true; + } + } + void setName(const std::string& name) + { + if (name != mDisplayName) + { + mDisplayName = name; + mNeedsResort = true; + } + } + void setSpokenTime(F32 time) + { + if (mLastSpokeTime != time) + { + mLastSpokeTime = time; + mNeedsResort = true; + } + } + + LLUUID mID; ESpeakerStatus mStatus; // current activity status in speech group + ESpeakerType mType : 2; + bool mIsModerator : 1; + bool mModeratorMutedVoice : 1; + bool mModeratorMutedText : 1; + bool mHasSpoken : 1; // has this speaker said anything this session? + bool mHasLeftCurrentCall : 1; // has this speaker left the current voice call? + bool mTyping : 1; F32 mLastSpokeTime; // timestamp when this speaker last spoke F32 mSpeechVolume; // current speech amplitude (timea average rms amplitude?) std::string mDisplayName; // cache user name for this speaker - BOOL mHasSpoken; // has this speaker said anything this session? - BOOL mHasLeftCurrentCall; // has this speaker left the current voice call? LLColor4 mDotColor; - LLUUID mID; - BOOL mTyping; + bool mNeedsResort; S32 mSortIndex; - ESpeakerType mType; - BOOL mIsModerator; - BOOL mModeratorMutedVoice; - BOOL mModeratorMutedText; }; -class LLSpeakerUpdateModeratorEvent : public LLOldEvents::LLEvent +class LLSpeakerUpdateSpeakerEvent final : public LLOldEvents::LLEvent +{ +public: + LLSpeakerUpdateSpeakerEvent(LLSpeaker* source); + /*virtual*/ LLSD getValue() override; +private: + const LLUUID& mSpeakerID; +}; + +class LLSpeakerUpdateModeratorEvent final : public LLOldEvents::LLEvent { public: LLSpeakerUpdateModeratorEvent(LLSpeaker* source); - /*virtual*/ LLSD getValue(); + /*virtual*/ LLSD getValue() override; private: const LLUUID& mSpeakerID; BOOL mIsModerator; }; -class LLSpeakerTextModerationEvent : public LLOldEvents::LLEvent +class LLSpeakerTextModerationEvent final : public LLOldEvents::LLEvent { public: LLSpeakerTextModerationEvent(LLSpeaker* source); - /*virtual*/ LLSD getValue(); + /*virtual*/ LLSD getValue() override; }; -class LLSpeakerVoiceModerationEvent : public LLOldEvents::LLEvent +class LLSpeakerVoiceModerationEvent final : public LLOldEvents::LLEvent { public: LLSpeakerVoiceModerationEvent(LLSpeaker* source); - /*virtual*/ LLSD getValue(); + /*virtual*/ LLSD getValue() override; }; -class LLSpeakerListChangeEvent : public LLOldEvents::LLEvent +class LLSpeakerListChangeEvent final : public LLOldEvents::LLEvent { public: LLSpeakerListChangeEvent(LLSpeakerMgr* source, const LLUUID& speaker_id); - /*virtual*/ LLSD getValue(); + /*virtual*/ LLSD getValue() override; private: const LLUUID& mSpeakerID; @@ -125,10 +183,10 @@ class LLSpeakerListChangeEvent : public LLOldEvents::LLEvent * Otherwise it should be deleted manually in place where it is used. * If action callback is not set timer will tick only once and deleted. */ -class LLSpeakerActionTimer : public LLEventTimer +class LLSpeakerActionTimer final : public LLEventTimer { public: - typedef boost::function action_callback_t; + typedef std::function action_callback_t; typedef std::map action_timers_map_t; typedef action_timers_map_t::value_type action_value_t; typedef action_timers_map_t::const_iterator action_timer_const_iter_t; @@ -142,14 +200,14 @@ class LLSpeakerActionTimer : public LLEventTimer * @param speaker_id - LLUUID of speaker which will be passed into action callback. */ LLSpeakerActionTimer(action_callback_t action_cb, F32 action_period, const LLUUID& speaker_id); - virtual ~LLSpeakerActionTimer() {}; + virtual ~LLSpeakerActionTimer() = default; /** * Implements timer "tick". * * If action callback is not specified returns true. Instance will be deleted by LLEventTimer::updateClass(). */ - virtual BOOL tick(); + BOOL tick() override; /** * Clears the callback. @@ -186,6 +244,8 @@ class LLSpeakersDelayActionsStorage void unsetActionTimer(const LLUUID& speaker_id); void removeAllTimers(); + + bool isTimerStarted(const LLUUID& speaker_id); private: /** * Callback of the each instance of LLSpeakerActionTimer. @@ -212,6 +272,8 @@ class LLSpeakerMgr : public LLOldEvents::LLObservable LOG_CLASS(LLSpeakerMgr); public: + typedef LLSpeaker::speaker_entry_t speaker_entry_t; + LLSpeakerMgr(LLVoiceChannel* channelp); virtual ~LLSpeakerMgr(); @@ -219,17 +281,17 @@ class LLSpeakerMgr : public LLOldEvents::LLObservable void update(BOOL resort_ok); void setSpeakerTyping(const LLUUID& speaker_id, BOOL typing); void speakerChatted(const LLUUID& speaker_id); - LLPointer setSpeaker(const LLUUID& id, - const std::string& name = LLStringUtil::null, - LLSpeaker::ESpeakerStatus status = LLSpeaker::STATUS_TEXT_ONLY, - LLSpeaker::ESpeakerType = LLSpeaker::SPEAKER_AGENT); - BOOL isVoiceActive(); + void setSpeakers(const std::vector& speakers); + LLPointer setSpeaker(const speaker_entry_t& speakers); + + BOOL isVoiceActive() const; typedef std::vector > speaker_list_t; void getSpeakerList(speaker_list_t* speaker_list, BOOL include_text); LLVoiceChannel* getVoiceChannel() { return mVoiceChannel; } - const LLUUID getSessionID(); + const LLUUID getSessionID() const; + bool isSpeakerToBeRemoved(const LLUUID& speaker_id) const; /** * Removes avaline speaker. @@ -248,11 +310,13 @@ class LLSpeakerMgr : public LLOldEvents::LLObservable protected: virtual void updateSpeakerList(); - void setSpeakerNotInChannel(LLSpeaker* speackerp); + void setSpeakerNotInChannel(LLPointer speackerp); bool removeSpeaker(const LLUUID& speaker_id); typedef std::map > speaker_map_t; speaker_map_t mSpeakers; + bool mSpeakerListUpdated; + LLTimer mGetListTime; speaker_list_t mSpeakersSorted; LLFrameTimer mSpeechTimer; @@ -272,7 +336,7 @@ class LLSpeakerMgr : public LLOldEvents::LLObservable bool mModerateModeHandledFirstTime; }; -class LLIMSpeakerMgr : public LLSpeakerMgr +class LLIMSpeakerMgr final : public LLSpeakerMgr { LOG_CLASS(LLIMSpeakerMgr); @@ -312,7 +376,7 @@ class LLIMSpeakerMgr : public LLSpeakerMgr void processSessionUpdate(const LLSD& session_update); protected: - virtual void updateSpeakerList(); + void updateSpeakerList() override; void moderateVoiceSession(const LLUUID& session_id, bool disallow_voice); @@ -323,24 +387,24 @@ class LLIMSpeakerMgr : public LLSpeakerMgr }; -class LLActiveSpeakerMgr : public LLSpeakerMgr, public LLSingleton +class LLActiveSpeakerMgr final : public LLSpeakerMgr, public LLSingleton { LOG_CLASS(LLActiveSpeakerMgr); public: LLActiveSpeakerMgr(); protected: - virtual void updateSpeakerList(); + void updateSpeakerList() override; }; -class LLLocalSpeakerMgr : public LLSpeakerMgr, public LLSingleton +class LLLocalSpeakerMgr final : public LLSpeakerMgr, public LLSingleton { LOG_CLASS(LLLocalSpeakerMgr); public: LLLocalSpeakerMgr(); ~LLLocalSpeakerMgr (); protected: - virtual void updateSpeakerList(); + void updateSpeakerList() override; }; #endif // LL_LLSPEAKERS_H diff --git a/indra/newview/llsrv.cpp b/indra/newview/llsrv.cpp index e39ddc907e..4fd6a542c4 100644 --- a/indra/newview/llsrv.cpp +++ b/indra/newview/llsrv.cpp @@ -41,7 +41,7 @@ struct Responder : public LLAres::UriRewriteResponder void rewriteResult(const std::vector &uris) { for (size_t i = 0; i < uris.size(); i++) { - llinfos << "[" << i << "] " << uris[i] << llendl; + LL_INFOS() << "[" << i << "] " << uris[i] << LL_ENDL; } mUris = uris; } diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 53f4386451..862d6d3098 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -44,25 +44,23 @@ #include "llviewermedia_streamingaudio.h" #include "llaudioengine.h" -#if LL_FMODEX -# include "llaudioengine_fmodex.h" -#endif - -#if LL_FMOD -# include "llaudioengine_fmod.h" +#ifdef LL_FMODSTUDIO +# include "llaudioengine_fmodstudio.h" #endif #ifdef LL_OPENAL #include "llaudioengine_openal.h" #endif +#include "aosystem.h" #include "hippogridmanager.h" #include "hippolimits.h" -#include "floaterao.h" #include "statemachine/aifilepicker.h" +#include "lfsimfeaturehandler.h" #include "llares.h" #include "llavatarnamecache.h" +#include "llexperiencecache.h" #include "lllandmark.h" #include "llcachename.h" #include "lldir.h" @@ -88,7 +86,7 @@ #include "lltexteditor.h" #include "llurlentry.h" #include "lluserrelations.h" -#include "sgversion.h" +#include "llversioninfo.h" #include "llviewercontrol.h" #include "llvfs.h" #include "llxorcipher.h" // saved password, MAC address @@ -97,6 +95,7 @@ #include "v3math.h" #include "llagent.h" +#include "llagentbenefits.h" #include "llagentcamera.h" #include "llagentwearables.h" #include "llagentpilot.h" @@ -115,9 +114,11 @@ #include "llfeaturemanager.h" #include "llfirstuse.h" #include "llfloateractivespeakers.h" +#include "llfloateravatar.h" #include "llfloaterbeacons.h" #include "llfloatercamera.h" #include "llfloaterchat.h" +#include "llfloaterdestinations.h" #include "llfloatergesture.h" #include "llfloaterhud.h" #include "llfloaterinventory.h" @@ -140,6 +141,7 @@ #include "llkeyboard.h" #include "llloginhandler.h" // gLoginHandler, SLURL support #include "llpanellogin.h" +#include "llmediafilter.h" #include "llmutelist.h" #include "llnotify.h" #include "llpanelavatar.h" @@ -203,8 +205,7 @@ #include "llweb.h" #include "llvoiceclient.h" #include "llnamelistctrl.h" -#include "llnamebox.h" -#include "llnameeditor.h" +#include "llnameui.h" #include "llwlparammanager.h" #include "llwaterparammanager.h" #include "llagentlanguage.h" @@ -216,18 +217,20 @@ #include "generichandlers.h" // +#include "floaterlocalassetbrowse.h" #include "llpanellogin.h" //#include "llfloateravatars.h" //#include "llactivation.h" #include "wlfPanel_AdvSettings.h" //Lower right Windlight and Rendering options #include "lldaycyclemanager.h" #include "llfloaterblacklist.h" +#include "scriptcounter.h" #include "shfloatermediaticker.h" +#include "shupdatechecker.h" #include "llpacketring.h" // #include "llpathfindingmanager.h" -#include "llevents.h" #include "lgghunspell_wrapper.h" @@ -235,6 +238,8 @@ #include "rlvhandler.h" // [/RLVa:KB] +#include "llevents.h" +#include "llexperiencelog.h" #if LL_WINDOWS #include "llwindebug.h" #include "lldxhardware.h" @@ -282,6 +287,7 @@ static LLHost gFirstSim; static std::string gFirstSimSeedCap; static LLVector3 gAgentStartLookAt(1.0f, 0.f, 0.f); static std::string gAgentStartLocation = "safe"; +static bool mBenefitsSuccessfullyInit = false; boost::scoped_ptr LLStartUp::sStateWatcher(new LLEventStream("StartupState")); @@ -291,8 +297,7 @@ boost::scoped_ptr LLStartUp::sPhases(new LLViewerStats: // local function declaration // -void login_show(LLSavedLogins const& saved_logins); -void login_callback(S32 option, void* userdata); +void login_show(); void show_first_run_dialog(); bool first_run_dialog_callback(const LLSD& notification, const LLSD& response); void set_startup_status(const F32 frac, const std::string& string, const std::string& msg); @@ -309,19 +314,28 @@ void init_start_screen(S32 location_id); void release_start_screen(); void reset_login(); void apply_udp_blacklist(const std::string& csv); -bool process_login_success_response(std::string &password); +// Aurora Sim +//bool process_login_success_response(std::string& password); +bool process_login_success_response(std::string& password, U32& first_sim_size_x, U32& first_sim_size_y); +// Aurora Sim +void on_benefits_failed_callback(const LLSD& notification, const LLSD& response); void transition_back_to_login_panel(const std::string& emsg); void callback_cache_name(const LLUUID& id, const std::string& full_name, bool is_group) { - LLNameBox::refreshAll(id, full_name, is_group); - LLNameEditor::refreshAll(id, full_name, is_group); + LLNameUI::refreshAll(id, full_name); // TODO: Actually be intelligent about the refresh. // For now, just brute force refresh the dialogs. dialog_refresh_all(); } +void simfeature_debug_update(const std::string& val, const std::string& setting) +{ + //if (!val.empty()) // Singu Note: Should we only update the setting if not empty? + gSavedSettings.setString(setting, val); +} + // // exported functionality // @@ -366,12 +380,114 @@ void update_texture_fetch() gTextureList.updateImages(0.10f); } +void set_flags_and_update_appearance() +{ + LLAppearanceMgr::instance().setAttachmentInvLinkEnable(true); + LLAppearanceMgr::instance().updateAppearanceFromCOF(true, true, no_op); +} + + void hooked_process_sound_trigger(LLMessageSystem *msg, void **) { process_sound_trigger(msg,NULL); LLFloaterAvatarList::sound_trigger_hook(msg,NULL); } +void convert_legacy_settings() +{ + // Convert legacy settings to new ones here. + if (!gSavedPerAccountSettings.getBOOL("DefaultUploadPermissionsConverted")) + { + gSavedSettings.setBOOL("UploadsEveryoneCopy", gSavedSettings.getBOOL("EveryoneCopy")); + bool val = gSavedPerAccountSettings.getBOOL("EveryoneExport"); + gSavedPerAccountSettings.setBOOL("UploadsEveryoneExport", val); + gSavedPerAccountSettings.setBOOL("ObjectsEveryoneExport", val); + val = gSavedSettings.getBOOL("NextOwnerCopy"); + gSavedSettings.setBOOL("UploadsNextOwnerCopy", val); + gSavedSettings.setBOOL("ObjectsNextOwnerCopy", val); + val = gSavedSettings.getBOOL("NextOwnerModify"); + gSavedSettings.setBOOL("UploadsNextOwnerModify", val); + gSavedSettings.setBOOL("ObjectsNextOwnerModify", val); + val = gSavedSettings.getBOOL("NextOwnerTransfer"); + gSavedSettings.setBOOL("UploadsNextOwnerTransfer", val); + gSavedSettings.setBOOL("ObjectsNextOwnerTransfer", val); + val = gSavedSettings.getBOOL("NextOwnerTransfer"); + gSavedSettings.setBOOL("UploadsShareWithGroup", gSavedSettings.getBOOL("ShareWithGroup")); + gSavedPerAccountSettings.setBOOL("DefaultUploadPermissionsConverted", true); + } +} + +void init_audio() +{ + if (FALSE == gSavedSettings.getBOOL("NoAudio")) + { + gAudiop = NULL; + +#ifdef LL_FMODSTUDIO + if (!gAudiop +#if !LL_WINDOWS + && NULL == getenv("LL_BAD_FMODSTUDIO_DRIVER") +#endif // !LL_WINDOWS + ) + { + gAudiop = (LLAudioEngine *) new LLAudioEngine_FMODSTUDIO(gSavedSettings.getBOOL("SHEnableFMODExProfiler"), gSavedSettings.getBOOL("SHEnableFMODEXVerboseDebugging")); + } +#endif + +#ifdef LL_OPENAL + if (!gAudiop +#if !LL_WINDOWS + && NULL == getenv("LL_BAD_OPENAL_DRIVER") +#endif // !LL_WINDOWS + ) + { + gAudiop = (LLAudioEngine *) new LLAudioEngine_OpenAL(); + } +#endif + + if (gAudiop) + { +#if LL_WINDOWS + // FMOD on Windows needs the window handle to stop playing audio + // when window is minimized. JC + void* window_handle = (HWND)gViewerWindow->getPlatformWindow(); +#else + void* window_handle = NULL; +#endif + bool init = gAudiop->init(kAUDIO_NUM_SOURCES, window_handle); + if(init) + { + gAudiop->setMuted(TRUE); + if(gSavedSettings.getBOOL("AllowLargeSounds")) + gAudiop->setAllowLargeSounds(true); + } + else + { + LL_WARNS("AppInit") << "Unable to initialize audio engine" << LL_ENDL; + delete gAudiop; + gAudiop = NULL; + } + + if (gAudiop) + { + // if the audio engine hasn't set up its own preferred handler for streaming audio then set up the generic streaming audio implementation which uses media plugins + if (NULL == gAudiop->getStreamingAudioImpl()) + { + LL_INFOS("AppInit") << "Using media plugins to render streaming audio" << LL_ENDL; + gAudiop->setStreamingAudioImpl(new LLStreamingAudio_MediaPlugins()); + } + // Unmute audio if desired and setup volumes. + // This is a not-uncommon crash site, so surround it with + // llinfos output to aid diagnosis. + LL_INFOS("AppInit") << "Doing first audio_update_volume..." << LL_ENDL; + audio_update_volume(false); + LL_INFOS("AppInit") << "Done first audio_update_volume." << LL_ENDL; + } + } + } + LL_INFOS("AppInit") << "Audio Engine Initialized." << LL_ENDL; +} + // Returns false to skip other idle processing. Should only return // true when all initialization done. bool idle_startup() @@ -397,6 +513,10 @@ bool idle_startup() static std::vector requested_options; static std::string redirect_uri; +// Aurora Sim + static U32 first_sim_size_x = 256; + static U32 first_sim_size_y = 256; +// Aurora Sim static LLVector3 initial_sun_direction(1.f, 0.f, 0.f); static LLVector3 agent_start_position_region(10.f, 10.f, 10.f); // default for when no space server @@ -522,21 +642,34 @@ bool idle_startup() // LL_DEBUGS("AppInit") << "Initializing messaging system..." << LL_ENDL; - std::string message_template_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"message_template.msg"); + auto app_settings_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, LLStringUtil::null); + std::string message_template_path = gDirUtilp->add(app_settings_path, "message_template.msg"); LLFILE* found_template = NULL; found_template = LLFile::fopen(message_template_path, "r"); /* Flawfinder: ignore */ + if (!found_template) + { + app_settings_path = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, #if LL_WINDOWS - // On the windows dev builds, unpackaged, the message_template.msg + // On the windows dev builds, unpackaged, the message_template.msg // file will be located in: // indra/build-vc**/newview//app_settings. - if (!found_template) - { - message_template_path = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "app_settings", "message_template.msg"); - found_template = LLFile::fopen(message_template_path.c_str(), "r"); /* Flawfinder: ignore */ - } + "app_settings" + #elif LL_DARWIN + // On Mac dev builds, message_template.msg lives in: + // indra/build-*/newview//Second Life/Contents/Resources/app_settings + "../Resources/app_settings" + #else // LL_LINUX and other + // On the linux dev builds, the message_template.msg + // file will be located in: + // indra/build-linux**/newview/packaged/app_settings. + "../app_settings" #endif + , LLStringUtil::null); + message_template_path = gDirUtilp->add(app_settings_path, "message_template.msg"); + found_template = LLFile::fopen(message_template_path.c_str(), "r"); /* Flawfinder: ignore */ + } if (found_template) { @@ -562,9 +695,9 @@ bool idle_startup() if(!start_messaging_system( message_template_path, port, - gVersionMajor, - gVersionMinor, - gVersionPatch, + LLVersionInfo::getMajor(), + LLVersionInfo::getMinor(), + LLVersionInfo::getPatch(), FALSE, std::string(), responder, @@ -577,22 +710,8 @@ bool idle_startup() LLAppViewer::instance()->earlyExit("LoginFailedNoNetwork", LLSD().with("DIAGNOSTIC", diagnostic)); } - #if LL_WINDOWS - // On the windows dev builds, unpackaged, the message.xml file will - // be located in indra/build-vc**/newview//app_settings. - std::string message_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"message.xml"); - - if (!LLFile::isfile(message_path.c_str())) - { - LLMessageConfig::initClass("viewer", gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "app_settings", "")); - } - else - { - LLMessageConfig::initClass("viewer", gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "")); - } - #else - LLMessageConfig::initClass("viewer", gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "")); - #endif + // Take into account dev checkout status on all platforms, by using app_settings_path ~Liru + LLMessageConfig::initClass("viewer", app_settings_path); } else @@ -668,85 +787,6 @@ bool idle_startup() //------------------------------------------------- AIFilePicker::loadFile("filepicker_contexts.xml"); - - //------------------------------------------------- - // Init audio, which may be needed for prefs dialog - // or audio cues in connection UI. - //------------------------------------------------- - - if (FALSE == gSavedSettings.getBOOL("NoAudio")) - { - gAudiop = NULL; - -#ifdef LL_FMODEX - if (!gAudiop -#if !LL_WINDOWS - && NULL == getenv("LL_BAD_FMODEX_DRIVER") -#endif // !LL_WINDOWS - ) - { - gAudiop = (LLAudioEngine *) new LLAudioEngine_FMODEX(gSavedSettings.getBOOL("SHEnableFMODExProfiler"),gSavedSettings.getBOOL("SHEnableFMODEXVerboseDebugging")); - } -#endif - -#ifdef LL_OPENAL - if (!gAudiop -#if !LL_WINDOWS - && NULL == getenv("LL_BAD_OPENAL_DRIVER") -#endif // !LL_WINDOWS - ) - { - gAudiop = (LLAudioEngine *) new LLAudioEngine_OpenAL(); - } -#endif - -#ifdef LL_FMOD - if (!gAudiop -#if !LL_WINDOWS - && NULL == getenv("LL_BAD_FMOD_DRIVER") -#endif // !LL_WINDOWS - ) - { - gAudiop = (LLAudioEngine *) new LLAudioEngine_FMOD(); - } -#endif - - if (gAudiop) - { -#if LL_WINDOWS - // FMOD on Windows needs the window handle to stop playing audio - // when window is minimized. JC - void* window_handle = (HWND)gViewerWindow->getPlatformWindow(); -#else - void* window_handle = NULL; -#endif - bool init = gAudiop->init(kAUDIO_NUM_SOURCES, window_handle); - if(init) - { - gAudiop->setMuted(TRUE); - if(gSavedSettings.getBOOL("AllowLargeSounds")) - gAudiop->setAllowLargeSounds(true); - } - else - { - LL_WARNS("AppInit") << "Unable to initialize audio engine" << LL_ENDL; - delete gAudiop; - gAudiop = NULL; - } - - if (gAudiop) - { - // if the audio engine hasn't set up its own preferred handler for streaming audio then set up the generic streaming audio implementation which uses media plugins - if (NULL == gAudiop->getStreamingAudioImpl()) - { - LL_INFOS("AppInit") << "Using media plugins to render streaming audio" << LL_ENDL; - gAudiop->setStreamingAudioImpl(new LLStreamingAudio_MediaPlugins()); - } - } - } - } - - LL_INFOS("AppInit") << "Audio Engine Initialized." << LL_ENDL; if (LLTimer::knownBadTimer()) { @@ -794,6 +834,7 @@ bool idle_startup() firstname = gSavedSettings.getString("FirstName"); lastname = gSavedSettings.getString("LastName"); password = LLStartUp::loadPasswordFromDisk(); + gSavedSettings.setBOOL("RememberName", true); gSavedSettings.setBOOL("RememberPassword", TRUE); show_connect_box = false; @@ -811,6 +852,7 @@ bool idle_startup() // Go to the next startup state LLStartUp::setStartupState( STATE_BROWSER_INIT ); + check_for_updates(); return FALSE; } @@ -819,7 +861,7 @@ bool idle_startup() { LL_DEBUGS("AppInit") << "STATE_BROWSER_INIT" << LL_ENDL; //std::string msg = LLTrans::getString("LoginInitializingBrowser"); - //set_startup_status(0.03f, msg.c_str(), gAgent.mMOTD.c_str()); + //set_startup_status(0.03f, msg.c_str(), gAgent.mMOTD); display_startup(); // LLViewerMedia::initBrowser(); LLStartUp::setStartupState( STATE_LOGIN_SHOW ); @@ -850,6 +892,8 @@ bool idle_startup() LLToolMgr::getInstance()->initTools(); display_startup(); + // Load local textures now, maybe someone wants to use them in UI (why?) + LocalAssetBrowser::instance(); // // Quickly get something onscreen to look at. gViewerWindow->initWorldUI(); display_startup(); @@ -872,26 +916,17 @@ bool idle_startup() gViewerWindow->setShowProgress(FALSE); display_startup(); - // Load login history - std::string login_hist_filepath = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "saved_logins_sg2.xml"); - LLSavedLogins login_history = LLSavedLogins::loadFile(login_hist_filepath); - display_startup(); - // Show the login dialog. - login_show(login_history); + login_show(); display_startup(); - if (login_history.size() > 0) - { - LLPanelLogin::setFields(*login_history.getEntries().rbegin()); - display_startup(); - } - else + static bool sSetFields(LLPanelLogin::getLoginHistory().size() > 0); // If there were no entries to be loaded, use what's available + if (!sSetFields) { LLPanelLogin::setFields(firstname, lastname, password); + sSetFields = true; // Never reset the fields again! display_startup(); LLPanelLogin::giveFocus(); } - gSavedSettings.setBOOL("FirstRunThisInstall", FALSE); @@ -913,7 +948,11 @@ bool idle_startup() display_startup(); // Push our window frontmost - gViewerWindow->getWindow()->show(); + // Singu Note: Actually, don't! But flash the window to let the user know + auto& window(*gViewerWindow->getWindow()); + window.show(false); + if (gSavedSettings.getBOOL("LiruFlashWhenMinimized")) // No, we're not minimized, but if you flash my bar, I will give you the biggest SIGSEGV ~Liru <3 + window.flashIcon(5.f); display_startup(); // DEV-16927. The following code removes errant keystrokes that happen while the window is being @@ -967,7 +1006,7 @@ bool idle_startup() { // TODO if not use viewer auth // Load all the name information out of the login view - LLPanelLogin::getFields(&firstname, &lastname, &password); + LLPanelLogin::getFields(firstname, lastname, password); // end TODO // HACK: Try to make not jump on login @@ -978,8 +1017,6 @@ bool idle_startup() { gSavedSettings.setString("FirstName", firstname); gSavedSettings.setString("LastName", lastname); - if (!gSavedSettings.controlExists("RememberLogin")) gSavedSettings.declareBOOL("RememberLogin", false, "Remember login", false); - gSavedSettings.setBOOL("RememberLogin", LLPanelLogin::getRememberLogin()); LL_INFOS("AppInit") << "Attempting login as: " << firstname << " " << lastname << LL_ENDL; gDebugInfo["LoginName"] = firstname + " " + lastname; @@ -1039,6 +1076,8 @@ bool idle_startup() gSavedPerAccountSettings.setU32("LastLogoff", time_corrected()); } + convert_legacy_settings(); + //Default the path if one isn't set. if (gSavedPerAccountSettings.getString("InstantMessageLogPath").empty()) { @@ -1052,27 +1091,12 @@ bool idle_startup() } //Get these logs out of my newview root directory, PLEASE. - if (gHippoGridManager->getCurrentGrid()->isSecondLife()) - { - gDirUtilp->setPerAccountChatLogsDir(LLStringUtil::null, - gSavedSettings.getString("FirstName"), gSavedSettings.getString("LastName") ); - } - else - { - gDirUtilp->setPerAccountChatLogsDir(gHippoGridManager->getConnectedGrid()->getGridNick(), - gSavedSettings.getString("FirstName"), gSavedSettings.getString("LastName") ); - } + gDirUtilp->setPerAccountChatLogsDir(gHippoGridManager->getCurrentGrid()->isSecondLife() ? LLStringUtil::null : gHippoGridManager->getConnectedGrid()->getGridNick(), + gSavedSettings.getString("FirstName"), gSavedSettings.getString("LastName")); LLFile::mkdir(gDirUtilp->getChatLogsDir()); LLFile::mkdir(gDirUtilp->getPerAccountChatLogsDir()); - // NaCl - Antispam - U32 antispam_time = gSavedSettings.getU32("_NACL_AntiSpamTime"); - U32 antispam_amount = gSavedSettings.getU32("_NACL_AntiSpamAmount"); - NACLAntiSpamRegistry::registerQueues(antispam_time, antispam_amount); - gSavedSettings.getControl("_NACL_AntiSpamGlobalQueue")->getSignal()->connect(boost::bind(&NACLAntiSpamRegistry::handleNaclAntiSpamGlobalQueueChanged, _2)); - gSavedSettings.getControl("_NACL_AntiSpamTime")->getSignal()->connect(boost::bind(&NACLAntiSpamRegistry::handleNaclAntiSpamTimeChanged, _2)); - gSavedSettings.getControl("_NACL_AntiSpamAmount")->getSignal()->connect(boost::bind(&NACLAntiSpamRegistry::handleNaclAntiSpamAmountChanged, _2)); - // NaCl End + NACLAntiSpamRegistry::startup(); // NaCl - Antispam //good a place as any to create user windlight directories std::string user_windlight_path_name(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight", "")); @@ -1101,14 +1125,9 @@ bool idle_startup() //LLPanelLogin::close(); } - //For HTML parsing in text boxes. - LLTextEditor::setLinkColor( gSavedSettings.getColor4("HTMLLinkColor") ); - // Load URL History File LLURLHistory::loadFile("url_history.xml"); - // Load media plugin cookies - LLViewerMedia::loadCookieFile(); - + //------------------------------------------------- // Handle startup progress screen //------------------------------------------------- @@ -1229,6 +1248,10 @@ bool idle_startup() requested_options.push_back("tutorial_setting"); requested_options.push_back("login-flags"); requested_options.push_back("global-textures"); + // Opensim requested options + requested_options.push_back("avatar_picker_url"); + requested_options.push_back("destination_guide_url"); + // if(gSavedSettings.getBOOL("ConnectAsGod")) { gSavedSettings.setBOOL("UseDebugMenus", TRUE); @@ -1243,7 +1266,7 @@ bool idle_startup() if (STATE_XMLRPC_LEGACY_LOGIN == LLStartUp::getStartupState()) { - lldebugs << "STATE_XMLRPC_LEGACY_LOGIN" << llendl; + LL_DEBUGS() << "STATE_XMLRPC_LEGACY_LOGIN" << LL_ENDL; progress += 0.02f; display_startup(); @@ -1286,7 +1309,7 @@ bool idle_startup() grid_uri = redirect_uri; //redirect_uri.clear(); //Should this be cleared immediately after consumption? Doing this will break retrying on http error. - llinfos << "Authenticating with " << grid_uri << llendl; + LL_INFOS() << "Authenticating with " << grid_uri << LL_ENDL; // Always write curl I/O debug info for the login attempt. Debug(gCurlIo = dc::curl.is_on() && !dc::curlio.is_on(); if (gCurlIo) dc::curlio.on()); @@ -1398,9 +1421,9 @@ bool idle_startup() message_response = response["message"].asString(); message_id = response["message_id"].asString(); { - std::stringstream dump_str; - dump_str << response; - llinfos << dump_str.str() << llendl; + std::stringstream dump_str; + dump_str << response; + LL_DEBUGS("AppInit") << dump_str.str() << LL_ENDL; } if(login_response == "true") @@ -1408,6 +1431,7 @@ bool idle_startup() // Yay, login! successful_login = true; Debug(if (gCurlIo) dc::curlio.off()); // Login succeeded: restore dc::curlio to original state. + LLPanelLogin::close(); // Singu Note: Actually destroy the login panel here, otherwise user interaction gets lost upon failed login. } else if(login_response == "indeterminate") { @@ -1543,15 +1567,25 @@ bool idle_startup() if (successful_login) { // unpack login data needed by the application - if(process_login_success_response(password)) + if (process_login_success_response(password, first_sim_size_x, first_sim_size_y)) { std::string name = firstname; - if (!gHippoGridManager->getCurrentGrid()->isSecondLife() || + bool secondlife(gHippoGridManager->getCurrentGrid()->isSecondLife()); + if (!secondlife || !boost::algorithm::iequals(lastname, "Resident")) { - name += " " + lastname; + name += ' ' + lastname; } + if (gSavedSettings.getBOOL("LiruGridInTitle")) gWindowTitle += "- " + gHippoGridManager->getCurrentGrid()->getGridName() + ' '; gViewerWindow->getWindow()->setTitle(gWindowTitle += "- " + name); + + if (!secondlife) + { + LFSimFeatureHandler& inst(LFSimFeatureHandler::instance()); + inst.setDestinationGuideURLCallback(boost::bind(simfeature_debug_update, _1, "DestinationGuideURL")); + inst.setSearchURLCallback(boost::bind(simfeature_debug_update, _1, "SearchURL")); + } + // Pass the user information to the voice chat server interface. LLVoiceClient::getInstance()->userAuthorized(name, gAgentID); // create the default proximal channel @@ -1563,7 +1597,7 @@ bool idle_startup() if (gNoRender) { LL_WARNS("AppInit") << "Bad login - missing return values" << LL_ENDL; - LL_WARNS("AppInit") << emsg << LL_ENDL; + LL_WARNS("AppInit") << emsg.str() << LL_ENDL; exit(0); } // Bounce back to the login screen. @@ -1579,7 +1613,7 @@ bool idle_startup() if (gNoRender) { LL_WARNS("AppInit") << "Failed to login!" << LL_ENDL; - LL_WARNS("AppInit") << emsg << LL_ENDL; + LL_WARNS("AppInit") << emsg.str() << LL_ENDL; exit(0); } // Bounce back to the login screen. @@ -1661,6 +1695,9 @@ bool idle_startup() gAgent.initOriginGlobal(from_region_handle(gFirstSimHandle)); display_startup(); +// Aurora Sim + LLWorld::getInstance()->setRegionSize(first_sim_size_x, first_sim_size_y); +// Aurora Sim LLWorld::getInstance()->addRegion(gFirstSimHandle, gFirstSim); display_startup(); @@ -1677,6 +1714,9 @@ bool idle_startup() // object is created. I think this must be done after setting the region. JC gAgent.setPositionAgent(agent_start_position_region); + display_startup(); + LLStartUp::initExperiences(); + display_startup(); LLStartUp::setStartupState( STATE_MULTIMEDIA_INIT ); return FALSE; @@ -1690,6 +1730,7 @@ bool idle_startup() if (STATE_MULTIMEDIA_INIT == LLStartUp::getStartupState()) { LLStartUp::multimediaInit(); + LLMediaFilter::getInstance(); LLStartUp::setStartupState( STATE_FONT_INIT ); display_startup(); return FALSE; @@ -1753,45 +1794,6 @@ bool idle_startup() LLRect window(0, gViewerWindow->getWindowHeight(), gViewerWindow->getWindowWidth(), 0); gViewerWindow->adjustControlRectanglesForFirstUse(window); - if (gSavedSettings.getBOOL("ShowMiniMap")) - { - LLFloaterMap::showInstance(); - } - if (gSavedSettings.getBOOL("ShowRadar")) - { - LLFloaterAvatarList::showInstance(); - } - // - else if (gSavedSettings.getBOOL("RadarKeepOpen")) - { - LLFloaterAvatarList::getInstance()->close(); - } - if (gSavedSettings.getBOOL("SHShowMediaTicker")) - { - SHFloaterMediaTicker::showInstance(); - } - // - if (gSavedSettings.getBOOL("ShowCameraControls")) - { - LLFloaterCamera::showInstance(); - } - if (gSavedSettings.getBOOL("ShowMovementControls")) - { - LLFloaterMove::showInstance(); - } - - if (gSavedSettings.getBOOL("ShowActiveSpeakers")) - { - LLFloaterActiveSpeakers::showInstance(); - } - - if (gSavedSettings.getBOOL("ShowBeaconsFloater")) - { - LLFloaterBeacons::showInstance(); - } - - - if (!gNoRender) { //Set up cloud rendertypes. Passed argument is unused. @@ -1835,6 +1837,7 @@ bool idle_startup() display_startup(); LLStartUp::initNameCache(); + LLLogChat::initializeIDMap(); // Name cache loaded, create a happy mappy display_startup(); // update the voice settings *after* gCacheName initialization @@ -1911,13 +1914,13 @@ bool idle_startup() { LL_DEBUGS("AppInit") << "Initializing sky..." << LL_ENDL; // Initialize all of the viewer object classes for the first time (doing things like texture fetches. - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); + LLGLStateValidator::checkStates(); + LLGLStateValidator::checkTextureChannels(); gSky.init(initial_sun_direction); - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); + LLGLStateValidator::checkStates(); + LLGLStateValidator::checkTextureChannels(); } display_startup(); @@ -1959,7 +1962,7 @@ bool idle_startup() gFirstSim, MAX_TIMEOUT_COUNT, FALSE, - TIMEOUT_SECONDS, + F32Seconds(TIMEOUT_SECONDS), use_circuit_callback, NULL); @@ -2010,7 +2013,7 @@ bool idle_startup() send_complete_agent_movement(regionp->getHost()); gAssetStorage->setUpstream(regionp->getHost()); gCacheName->setUpstream(regionp->getHost()); - msg->newMessageFast(_PREHASH_EconomyDataRequest); + if (!mBenefitsSuccessfullyInit) msg->newMessageFast(_PREHASH_EconomyDataRequest); gAgent.sendReliableMessage(); } display_startup(); @@ -2230,49 +2233,54 @@ bool idle_startup() // This method MUST be called before gInventory.findCategoryUUIDForType because of // gInventory.mIsAgentInvUsable is set to true in the gInventory.buildParentChildMap. gInventory.buildParentChildMap(); - display_startup(); + gInventory.createCommonSystemCategories(); - /*llinfos << "Setting Inventory changed mask and notifying observers" << llendl; + // It's debatable whether this flag is a good idea - sets all + // bits, and in general it isn't true that inventory + // initialization generates all types of changes. Maybe add an + // INITIALIZE mask bit instead? gInventory.addChangedMask(LLInventoryObserver::ALL, LLUUID::null); - gInventory.notifyObservers();*/ + gInventory.notifyObservers(); + display_startup(); + //all categories loaded. lets create "My Favorites" category gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE,true); // set up callbacks - llinfos << "Registering Callbacks" << llendl; + LL_INFOS() << "Registering Callbacks" << LL_ENDL; LLMessageSystem* msg = gMessageSystem; - llinfos << " Inventory" << llendl; + LL_INFOS() << " Inventory" << LL_ENDL; LLInventoryModel::registerCallbacks(msg); - llinfos << " AvatarTracker" << llendl; + LL_INFOS() << " AvatarTracker" << LL_ENDL; LLAvatarTracker::instance().registerCallbacks(msg); - llinfos << " Landmark" << llendl; + LL_INFOS() << " Landmark" << LL_ENDL; LLLandmark::registerCallbacks(msg); display_startup(); // request mute list - llinfos << "Requesting Mute List" << llendl; + LL_INFOS() << "Requesting Mute List" << LL_ENDL; LLMuteList::getInstance()->requestFromServer(gAgent.getID()); display_startup(); // Get L$ and ownership credit information - llinfos << "Requesting Money Balance" << llendl; + LL_INFOS() << "Requesting Money Balance" << LL_ENDL; LLStatusBar::sendMoneyBalanceRequest(); display_startup(); // request all group information - llinfos << "Requesting Agent Data" << llendl; + LL_INFOS() << "Requesting Agent Data" << LL_ENDL; gAgent.sendAgentDataUpdateRequest(); display_startup(); bool shown_at_exit = gSavedSettings.getBOOL("ShowInventory"); // Create the inventory views - llinfos << "Creating Inventory Views" << llendl; - LLInventoryView::showAgentInventory(); + LL_INFOS() << "Creating Inventory Views" << LL_ENDL; + LLPanelMainInventory::showAgentInventory(); display_startup(); // Hide the inventory if it wasn't shown at exit if(!shown_at_exit) { - LLInventoryView::toggleVisibility(NULL); + LLPanelMainInventory::toggleVisibility(NULL); } display_startup(); @@ -2326,6 +2334,12 @@ bool idle_startup() } display_startup(); + + // *TODO : Uncomment that line once the whole grid migrated to SLM and suppress it from LLAgent::handleTeleportFinished() (llagent.cpp) + //check_merchant_status(); + + display_startup(); + // We're successfully logged in. gSavedSettings.setBOOL("FirstLoginThisInstall", FALSE); @@ -2346,7 +2360,7 @@ bool idle_startup() if (!gNoRender) { - // JC: Initializing audio requests many sounds for download. + //Now that we're loading the world, initialize the audio engine. init_audio(); display_startup(); @@ -2389,6 +2403,51 @@ bool idle_startup() gDisplaySwapBuffers = TRUE; display_startup(); + if (gSavedSettings.getBOOL("ShowMiniMap")) + { + LLFloaterMap::showInstance(); + } + if (gSavedSettings.getBOOL("ShowRadar")) + { + LLFloaterAvatarList::showInstance(); + } + // + else if (gSavedSettings.getBOOL("RadarKeepOpen")) + { + LLFloaterAvatarList::getInstance()->close(); + } + if (gSavedSettings.getBOOL("SHShowMediaTicker")) + { + SHFloaterMediaTicker::showInstance(); + } + // + if (gSavedSettings.getBOOL("ShowCameraControls")) + { + LLFloaterCamera::showInstance(); + } + if (gSavedSettings.getBOOL("ShowMovementControls")) + { + LLFloaterMove::showInstance(); + } + + if (gSavedSettings.getBOOL("ShowActiveSpeakers")) + { + LLFloaterActiveSpeakers::showInstance(); + } + + if (gSavedSettings.getBOOL("ShowBeaconsFloater")) + { + LLFloaterBeacons::showInstance(); + } + if (gSavedSettings.getBOOL("ShowAvatarFloater")) + { + LLFloaterAvatar::showInstance(); + } + if (gSavedSettings.getBOOL("DestinationGuideShown")) + { + LLFloaterDestinations::showInstance(); + } + LLMessageSystem* msg = gMessageSystem; msg->setHandlerFuncFast(_PREHASH_SoundTrigger, hooked_process_sound_trigger); msg->setHandlerFuncFast(_PREHASH_PreloadSound, process_preload_sound); @@ -2425,7 +2484,7 @@ bool idle_startup() // thus, do not show this alert. if (!gAgent.isFirstLogin()) { - llinfos << "gAgentStartLocation : " << gAgentStartLocation << llendl; + LL_INFOS() << "gAgentStartLocation : " << gAgentStartLocation << LL_ENDL; LLSLURL start_slurl = LLStartUp::getStartSLURL(); LL_DEBUGS("AppInit") << "start slurl "< 1.f) && isAgentAvatarValid()) - || (timeout_frac > 3.f)) + if ((timeout_frac > 1.f) && isAgentAvatarValid()) { LLStartUp::setStartupState( STATE_WEARABLES_WAIT ); } + else if (timeout_frac > 10.f) + { + // If we exceed the wait above while isAgentAvatarValid is + // not true yet, we will change startup state and + // eventually (once avatar does get created) wind up at + // the gender chooser. This should occur only in very + // unusual circumstances, so set the timeout fairly high + // to minimize mistaken hits here. + LL_WARNS() << "Wait for valid avatar state exceeded " + << timeout.getElapsedTimeF32() << " will invoke gender chooser" << LL_ENDL; + LLStartUp::setStartupState( STATE_WEARABLES_WAIT ); + } else { update_texture_fetch(); @@ -2525,6 +2604,8 @@ bool idle_startup() LLViewerShaderMgr::instance()->setShaders(); display_startup(); } + //Precache UI sounds. + precache_audio(); } return TRUE; @@ -2537,11 +2618,11 @@ bool idle_startup() const F32 wearables_time = wearables_timer.getElapsedTimeF32(); const F32 MAX_WEARABLES_TIME = 10.f; - if (!gAgent.isGenderChosen() && isAgentAvatarValid()) + if (!gAgent.isOutfitChosen() && isAgentAvatarValid()) { - // No point in waiting for clothing, we don't even - // know what gender we are. Pop a dialog to ask and - // proceed to draw the world. JC + // No point in waiting for clothing, we don't even know + // what outfit we want. Pop up a gender chooser dialog to + // ask and proceed to draw the world. JC // // *NOTE: We might hit this case even if we have an // initial outfit, but if the load hasn't started @@ -2569,7 +2650,7 @@ bool idle_startup() if (isAgentAvatarValid() && gAgentAvatarp->isFullyLoaded()) { - //llinfos << "avatar fully loaded" << llendl; + LL_DEBUGS("Avatar") << "avatar fully loaded" << LL_ENDL; LLStartUp::setStartupState( STATE_CLEANUP ); return TRUE; } @@ -2580,7 +2661,7 @@ bool idle_startup() if ( gAgentWearables.areWearablesLoaded() ) { // We have our clothing, proceed. - //llinfos << "wearables loaded" << llendl; + LL_DEBUGS("Avatar") << "wearables loaded" << LL_ENDL; LLStartUp::setStartupState( STATE_CLEANUP ); return TRUE; } @@ -2590,17 +2671,21 @@ bool idle_startup() update_texture_fetch(); display_startup(); set_startup_status(0.9f + 0.1f * wearables_time / MAX_WEARABLES_TIME, - LLTrans::getString("LoginDownloadingClothing").c_str(), - gAgent.mMOTD.c_str()); + LLTrans::getString("LoginDownloadingClothing"), + gAgent.mMOTD); display_startup(); return TRUE; } if (STATE_CLEANUP == LLStartUp::getStartupState()) { - set_startup_status(1.0, "", ""); + set_startup_status(1.0, LLStringUtil::null, LLStringUtil::null); display_startup(); - LLViewerParcelMedia::loadDomainFilterList(); + + if (!mBenefitsSuccessfullyInit && gHippoGridManager->getConnectedGrid()->isSecondLife()) + { + LLNotificationsUtil::add("FailedToGetBenefits", LLSD(), LLSD(), boost::bind(on_benefits_failed_callback, _1, _2)); + } // Let the map know about the inventory. LLFloaterWorldMap* floater_world_map = gFloaterWorldMap; @@ -2611,16 +2696,13 @@ bool idle_startup() } // Start the AO now that settings have loaded and login successful -- MC - if (!gAOInvTimer) - { - gAOInvTimer = new AOInvTimer(); - } + AOSystem::start(); gViewerWindow->showCursor(); gViewerWindow->getWindow()->resetBusyCount(); gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW); LL_DEBUGS("AppInit") << "Done releasing bitmap" << LL_ENDL; - + //gViewerWindow->revealIntroPanel(); gViewerWindow->setStartupComplete(); gViewerWindow->setProgressCancelButtonVisible(FALSE); display_startup(); @@ -2667,13 +2749,8 @@ bool idle_startup() gSavedSettings.setF32("RenderFarClip", 32.0f); } - // Unmute audio if desired and setup volumes. - // Unmute audio if desired and setup volumes. - // This is a not-uncommon crash site, so surround it with - // llinfos output to aid diagnosis. - LL_INFOS("AppInit") << "Doing first audio_update_volume..." << LL_ENDL; - audio_update_volume(); - LL_INFOS("AppInit") << "Done first audio_update_volume." << LL_ENDL; + //Agent avatar is ready. Create the listener. + audio_update_listener(); // reset keyboard focus to sane state of pointing at world gFocusMgr.setKeyboardFocus(NULL); @@ -2703,59 +2780,17 @@ bool idle_startup() // local function definition // -void login_show(LLSavedLogins const& saved_logins) +void login_show() { LL_INFOS("AppInit") << "Initializing Login Screen" << LL_ENDL; // This creates the LLPanelLogin instance. - LLPanelLogin::show( gViewerWindow->getVirtualWindowRect(), - login_callback, NULL ); - - // Now that the LLPanelLogin instance is created, - // store the login history there. - LLPanelLogin::setLoginHistory(saved_logins); + LLPanelLogin::show(); // UI textures have been previously loaded in doPreloadImages() } -// Callback for when login screen is closed. Option 0 = connect, option 1 = quit. -void login_callback(S32 option, void *userdata) -{ - const S32 CONNECT_OPTION = 0; - const S32 QUIT_OPTION = 1; - - if (CONNECT_OPTION == option) - { - LLStartUp::setStartupState( STATE_LOGIN_CLEANUP ); - return; - } - else if (QUIT_OPTION == option) - { - // Make sure we don't save the password if the user is trying to clear it. - std::string first, last, password; - LLPanelLogin::getFields(&first, &last, &password); - if (!gSavedSettings.getBOOL("RememberPassword")) - { - // turn off the setting and write out to disk - gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile") , TRUE ); - } - - // Next iteration through main loop should shut down the app cleanly. - LLAppViewer::instance()->userQuit(); - - if (LLAppViewer::instance()->quitRequested()) - { - LLPanelLogin::close(); - } - return; - } - else - { - LL_WARNS("AppInit") << "Unknown login button clicked" << LL_ENDL; - } -} - // static std::string LLStartUp::loadPasswordFromDisk() @@ -2872,7 +2907,7 @@ bool first_run_dialog_callback(const LLSD& notification, const LLSD& response) if (!url.empty()) { LLWeb::loadURL(url); } else { - llwarns << "Account creation URL is empty" << llendl; + LL_WARNS() << "Account creation URL is empty" << LL_ENDL; } } @@ -2976,6 +3011,12 @@ void pass_processObjectPropertiesFamily(LLMessageSystem *msg, void**) JCFloaterAreaSearch::processObjectPropertiesFamily(msg, NULL); } +void process_script_running_reply(LLMessageSystem* msg, void** v) +{ + LLLiveLSLEditor::processScriptRunningReply(msg, v); + ScriptCounter::processScriptRunningReply(msg); +} + void register_viewer_callbacks(LLMessageSystem* msg) { msg->setHandlerFuncFast(_PREHASH_LayerData, process_layer_data ); @@ -3008,6 +3049,7 @@ void register_viewer_callbacks(LLMessageSystem* msg) msg->setHandlerFuncFast(_PREHASH_NameValuePair, process_name_value); msg->setHandlerFuncFast(_PREHASH_RemoveNameValuePair, process_remove_name_value); msg->setHandlerFuncFast(_PREHASH_AvatarAnimation, process_avatar_animation); + msg->setHandlerFuncFast(_PREHASH_ObjectAnimation, process_object_animation); msg->setHandlerFuncFast(_PREHASH_AvatarAppearance, process_avatar_appearance); msg->setHandlerFunc("AgentCachedTextureResponse", LLAgent::processAgentCachedTextureResponse); msg->setHandlerFunc("RebakeAvatarTextures", LLVOAvatarSelf::processRebakeAvatarTextures); @@ -3026,8 +3068,7 @@ void register_viewer_callbacks(LLMessageSystem* msg) msg->setHandlerFuncFast(_PREHASH_CoarseLocationUpdate, LLWorld::processCoarseUpdate, NULL); msg->setHandlerFuncFast(_PREHASH_ReplyTaskInventory, LLViewerObject::processTaskInv, NULL); msg->setHandlerFuncFast(_PREHASH_DerezContainer, process_derez_container, NULL); - msg->setHandlerFuncFast(_PREHASH_ScriptRunningReply, - &LLLiveLSLEditor::processScriptRunningReply); + msg->setHandlerFuncFast(_PREHASH_ScriptRunningReply, process_script_running_reply); msg->setHandlerFuncFast(_PREHASH_DeRezAck, process_derez_ack); @@ -3084,9 +3125,6 @@ void register_viewer_callbacks(LLMessageSystem* msg) // msg->setHandlerFuncFast(_PREHASH_ReputationIndividualReply, // LLFloaterRate::processReputationIndividualReply); - msg->setHandlerFuncFast(_PREHASH_AgentWearablesUpdate, - LLAgentWearables::processAgentInitialWearablesUpdate ); - msg->setHandlerFunc("ScriptControlChange", LLAgent::processScriptControlChange ); @@ -3208,7 +3246,7 @@ bool callback_choose_gender(const LLSD& notification, const LLSD& response) void LLStartUp::loadInitialOutfit( const std::string& outfit_folder_name, const std::string& gender_name ) { - lldebugs << "starting" << llendl; + LL_DEBUGS() << "starting" << LL_ENDL; // Not going through the processAgentInitialWearables path, so need to set this here. LLAppearanceMgr::instance().setAttachmentInvLinkEnable(true); @@ -3218,18 +3256,18 @@ void LLStartUp::loadInitialOutfit( const std::string& outfit_folder_name, ESex gender; if (gender_name == "male") { - lldebugs << "male" << llendl; + LL_DEBUGS() << "male" << LL_ENDL; gender = SEX_MALE; } else { - lldebugs << "female" << llendl; + LL_DEBUGS() << "female" << LL_ENDL; gender = SEX_FEMALE; } if (!isAgentAvatarValid()) { - llwarns << "Trying to load an initial outfit for an invalid agent avatar" << llendl; + LL_WARNS() << "Trying to load an initial outfit for an invalid agent avatar" << LL_ENDL; return; } @@ -3242,39 +3280,43 @@ void LLStartUp::loadInitialOutfit( const std::string& outfit_folder_name, outfit_folder_name); if (cat_id.isNull()) { - lldebugs << "standard wearables" << llendl; + LL_DEBUGS() << "standard wearables" << LL_ENDL; gAgentWearables.createStandardWearables(); } else { + // FIXME SH-3860 - this creates a race condition, where COF + // changes (base outfit link added) after appearance update + // request has been submitted. sWearablesLoadedCon = gAgentWearables.addLoadedCallback(LLStartUp::saveInitialOutfit); bool do_copy = true; bool do_append = false; LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id); - LLAppearanceMgr::instance().wearInventoryCategory(cat, do_copy, do_append); - lldebugs << "initial outfit category id: " << cat_id << llendl; + // Need to fetch cof contents before we can wear. + callAfterCategoryFetch(LLAppearanceMgr::instance().getCOF(), + boost::bind(&LLAppearanceMgr::wearInventoryCategory, LLAppearanceMgr::getInstance(), cat, do_copy, do_append)); + LL_DEBUGS() << "initial outfit category id: " << cat_id << LL_ENDL; } - // This is really misnamed -- it means we have started loading - // an outfit/shape that will give the avatar a gender eventually. JC - gAgent.setGenderChosen(TRUE); + gAgent.setOutfitChosen(TRUE); + gAgentWearables.sendDummyAgentWearablesUpdate(); } //static void LLStartUp::saveInitialOutfit() { if (sInitialOutfit.empty()) { - lldebugs << "sInitialOutfit is empty" << llendl; + LL_DEBUGS() << "sInitialOutfit is empty" << LL_ENDL; return; } if (sWearablesLoadedCon.connected()) { - lldebugs << "sWearablesLoadedCon is connected, disconnecting" << llendl; + LL_DEBUGS("Avatar") << "sWearablesLoadedCon is connected, disconnecting" << LL_ENDL; sWearablesLoadedCon.disconnect(); } - lldebugs << "calling makeNewOutfitLinks( \"" << sInitialOutfit << "\" )" << llendl; + LL_DEBUGS("Avatar") << "calling makeNewOutfitLinks( \"" << sInitialOutfit << "\" )" << LL_ENDL; LLAppearanceMgr::getInstance()->makeNewOutfitLinks(sInitialOutfit,false); } @@ -3488,10 +3530,20 @@ void LLStartUp::initNameCache() // Start cache in not-running state until we figure out if we have // capabilities for display name lookup - LLAvatarNameCache::initClass(false); S32 phoenix_name_system = gSavedSettings.getS32("PhoenixNameSystem"); - if(phoenix_name_system <= 0 || phoenix_name_system > 2) LLAvatarNameCache::setUseDisplayNames(false); - else LLAvatarNameCache::setUseDisplayNames(true); + LLAvatarNameCache::initClass(false, gSavedSettings.getBOOL("UsePeopleAPI")); + LLAvatarNameCache::setUseDisplayNames(phoenix_name_system > 0 && phoenix_name_system < 4); + LLAvatarNameCache::setUseUsernames(!phoenix_name_system || phoenix_name_system == 1 || phoenix_name_system == 3); +} + + +void LLStartUp::initExperiences() +{ + // Should trigger loading the cache. + LLExperienceCache::instance().setCapabilityQuery( + boost::bind(&LLAgent::getRegionCapability, &gAgent, _1)); + + LLExperienceLog::instance().initialize(); } void LLStartUp::cleanupNameCache() @@ -3499,7 +3551,7 @@ void LLStartUp::cleanupNameCache() LLAvatarNameCache::cleanupClass(); delete gCacheName; - gCacheName = NULL; + gCacheName = nullptr; } bool LLStartUp::dispatchURL() @@ -3833,7 +3885,7 @@ void apply_udp_blacklist(const std::string& csv) } std::string item(csv, start, comma-start); - lldebugs << "udp_blacklist " << item << llendl; + LL_DEBUGS() << "udp_blacklist " << item << LL_ENDL; gMessageSystem->banUdpMessage(item); start = comma + 1; @@ -3843,10 +3895,70 @@ void apply_udp_blacklist(const std::string& csv) } -bool process_login_success_response(std::string& password) +void on_benefits_failed_callback(const LLSD& notification, const LLSD& response) +{ + LL_WARNS("Benefits") << "Failed to load benefits information" << LL_ENDL; +} + +bool init_benefits(LLSD& response) +{ + bool succ = true; + + std::string package_name = response["account_type"].asString(); + const LLSD& benefits_sd = response["account_level_benefits"]; + if (!LLAgentBenefitsMgr::init(package_name, benefits_sd) || + !LLAgentBenefitsMgr::initCurrent(package_name, benefits_sd)) + { + succ = false; + } + else + { + LL_DEBUGS("Benefits") << "Initialized current benefits, level " << package_name << " from " << benefits_sd << LL_ENDL; + } + const LLSD& packages_sd = response["premium_packages"]; + for(LLSD::map_const_iterator package_iter = packages_sd.beginMap(); + package_iter != packages_sd.endMap(); + ++package_iter) + { + std::string package_name = package_iter->first; + const LLSD& benefits_sd = package_iter->second["benefits"]; + if (LLAgentBenefitsMgr::init(package_name, benefits_sd)) + { + LL_DEBUGS("Benefits") << "Initialized benefits for package " << package_name << " from " << benefits_sd << LL_ENDL; + } + else + { + LL_WARNS("Benefits") << "Failed init for package " << package_name << " from " << benefits_sd << LL_ENDL; + succ = false; + } + } + + if (!LLAgentBenefitsMgr::has("Base")) + { + LL_WARNS("Benefits") << "Benefits info did not include required package Base" << LL_ENDL; + succ = false; + } + if (!LLAgentBenefitsMgr::has("Premium")) + { + LL_WARNS("Benefits") << "Benefits info did not include required package Premium" << LL_ENDL; + succ = false; + } + + // FIXME PREMIUM - for testing if login does not yet provide Premium Plus. Should be removed thereafter. + //if (succ && !LLAgentBenefitsMgr::has("Premium Plus")) + //{ + // LLAgentBenefitsMgr::init("Premium Plus", packages_sd["Premium"]["benefits"]); + // llassert(LLAgentBenefitsMgr::has("Premium Plus")); + //} + return succ; +} + +bool process_login_success_response(std::string& password, U32& first_sim_size_x, U32& first_sim_size_y) { LLSD response = LLUserAuth::getInstance()->getResponse(); + mBenefitsSuccessfullyInit = init_benefits(response); + std::string text(response["udp_blacklist"]); if(!text.empty()) { @@ -3909,7 +4021,7 @@ bool process_login_success_response(std::string& password) LLSavedLogins history_data = LLSavedLogins::loadFile(history_file); std::string grid_name = gHippoGridManager->getConnectedGrid()->getGridName(); history_data.deleteEntry(firstname, lastname, grid_name); - if (gSavedSettings.getBOOL("RememberLogin")) + if (gSavedSettings.getBOOL("RememberName")) { LLSavedLoginEntry login_entry(firstname, lastname, password, grid_name); history_data.addEntry(login_entry); @@ -3941,17 +4053,6 @@ bool process_login_success_response(std::string& password) gSavedSettings.setU32("PreferredMaturity", preferredMaturity); } - // During the AO transition, this flag will be true. Then the flag will - // go away. After the AO transition, this code and all the code that - // uses it can be deleted. - text = response["ao_transition"].asString(); - if (!text.empty()) - { - if (text == "1") - { - gAgent.setAOTransition(); - } - } text = response["start_location"].asString(); if(!text.empty()) @@ -3983,7 +4084,15 @@ bool process_login_success_response(std::string& password) U32 region_y = strtoul(region_y_str.c_str(), NULL, 10); gFirstSimHandle = to_region_handle(region_x, region_y); } - + +// Aurora Sim + text = response["region_size_x"].asString(); + if (!text.empty()) LLViewerParcelMgr::getInstance()->init(first_sim_size_x = atoi(text.c_str())); + // Patrick Sapinski commented here on 2/10/2011 that y is currently unused and major refactor is required - Liru (11/6/2013) + text = response["region_size_y"].asString(); + if (!text.empty()) first_sim_size_y = atoi(text.c_str()); +// Aurora Sim + const std::string look_at_str = response["look_at"]; if (!look_at_str.empty()) { @@ -4052,7 +4161,11 @@ bool process_login_success_response(std::string& password) flag = login_flags["gendered"].asString(); if(flag == "Y") { - gAgent.setGenderChosen(TRUE); + // We don't care about this flag anymore; now base whether + // outfit is chosen on COF contents, initial outfit + // requested and available, etc. + + //gAgent.setGenderChosen(TRUE); } flag = login_flags["daylight_savings"].asString(); @@ -4068,13 +4181,15 @@ bool process_login_success_response(std::string& password) LLWorldMap::gotMapServerURL(true); } - if(gHippoGridManager->getConnectedGrid()->isOpenSimulator()) + auto& grid = *gHippoGridManager->getConnectedGrid(); + bool opensim = !grid.isSecondLife(); + if (opensim) { std::string web_profile_url = response["web_profile_url"]; //if(!web_profile_url.empty()) // Singu Note: We're using this to check if this grid supports web profiles at all, so set empty if empty. gSavedSettings.setString("WebProfileURL", web_profile_url); } - else if(!gHippoGridManager->getConnectedGrid()->isInProductionGrid()) + else if(!grid.isInProductionGrid()) { gSavedSettings.setString("WebProfileURL", "https://my-demo.secondlife.com/[AGENT_NAME]"); } @@ -4123,69 +4238,79 @@ bool process_login_success_response(std::string& password) gCloudTextureID = id; } #endif - // set the location of the Agent Appearance service, from which we can request - // avatar baked textures if they are supported by the current region - std::string agent_appearance_url = response["agent_appearance_service"]; - if (!agent_appearance_url.empty()) - { - gSavedSettings.setString("AgentAppearanceServiceURL", agent_appearance_url); - } + } + + // set the location of the Agent Appearance service, from which we can request + // avatar baked textures if they are supported by the current region + std::string agent_appearance_url = response["agent_appearance_service"]; + if (!agent_appearance_url.empty()) + { + gSavedSettings.setString("AgentAppearanceServiceURL", agent_appearance_url); } // Override grid info with anything sent in the login response std::string tmp = response["gridname"].asString(); - if (!tmp.empty()) gHippoGridManager->getConnectedGrid()->setGridName(tmp); + if (!tmp.empty()) grid.setGridName(tmp); tmp = response["loginuri"].asString(); - if (!tmp.empty()) gHippoGridManager->getConnectedGrid()->setLoginUri(tmp); + if (!tmp.empty()) grid.setLoginUri(tmp); tmp = response["welcome"].asString(); - if (!tmp.empty()) gHippoGridManager->getConnectedGrid()->setLoginPage(tmp); + if (!tmp.empty()) grid.setLoginPage(tmp); tmp = response["loginpage"].asString(); - if (!tmp.empty()) gHippoGridManager->getConnectedGrid()->setLoginPage(tmp); + if (!tmp.empty()) grid.setLoginPage(tmp); tmp = response["economy"].asString(); - if (!tmp.empty()) gHippoGridManager->getConnectedGrid()->setHelperUri(tmp); + if (!tmp.empty()) grid.setHelperUri(tmp); tmp = response["helperuri"].asString(); - if (!tmp.empty()) gHippoGridManager->getConnectedGrid()->setHelperUri(tmp); + if (!tmp.empty()) grid.setHelperUri(tmp); tmp = response["about"].asString(); - if (!tmp.empty()) gHippoGridManager->getConnectedGrid()->setWebSite(tmp); + if (!tmp.empty()) grid.setWebSite(tmp); tmp = response["website"].asString(); - if (!tmp.empty()) gHippoGridManager->getConnectedGrid()->setWebSite(tmp); + if (!tmp.empty()) grid.setWebSite(tmp); tmp = response["help"].asString(); - if (!tmp.empty()) gHippoGridManager->getConnectedGrid()->setSupportUrl(tmp); + if (!tmp.empty()) grid.setSupportUrl(tmp); tmp = response["support"].asString(); - if (!tmp.empty()) gHippoGridManager->getConnectedGrid()->setSupportUrl(tmp); + if (!tmp.empty()) grid.setSupportUrl(tmp); tmp = response["register"].asString(); - if (!tmp.empty()) gHippoGridManager->getConnectedGrid()->setRegisterUrl(tmp); + if (!tmp.empty()) grid.setRegisterUrl(tmp); tmp = response["account"].asString(); - if (!tmp.empty()) gHippoGridManager->getConnectedGrid()->setRegisterUrl(tmp); + if (!tmp.empty()) grid.setRegisterUrl(tmp); tmp = response["password"].asString(); - if (!tmp.empty()) gHippoGridManager->getConnectedGrid()->setPasswordUrl(tmp); + if (!tmp.empty()) grid.setPasswordUrl(tmp); tmp = response["search"].asString(); - if (!tmp.empty()) gHippoGridManager->getConnectedGrid()->setSearchUrl(tmp); - if (gHippoGridManager->getConnectedGrid()->isOpenSimulator()) gSavedSettings.setString("SearchURL", tmp); // Singu Note: For web search purposes, always set this setting + if (!tmp.empty()) grid.setSearchUrl(tmp); + else if (opensim) tmp = grid.getSearchUrl(); // Fallback from grid info response for setting + if (opensim) + { + gSavedSettings.setString("SearchURL", tmp); // Singu Note: For web search purposes, always set this setting + tmp = response["avatar_picker_url"].asString(); + gSavedSettings.setString("AvatarPickerURL", tmp); + gMenuBarView->getChildView("Avatar Picker")->setVisible(!tmp.empty()); + gSavedSettings.setString("DestinationGuideURL", response["destination_guide_url"].asString()); + tmp = response["classified_fee"].asString(); + grid.setClassifiedFee(tmp.empty() ? 0 : atoi(tmp.c_str())); + } tmp = response["currency"].asString(); if (!tmp.empty()) { LLTrans::setDefaultArg("[CURRENCY]", tmp); - gHippoGridManager->getConnectedGrid()->setCurrencySymbol(tmp); + grid.setCurrencySymbol(tmp); } tmp = response["currency_text"].asString(); if (!tmp.empty()) { LLTrans::setDefaultArg("[CURRENCY_TEXT]", tmp); - gHippoGridManager->getConnectedGrid()->setCurrencyText(tmp); + grid.setCurrencyText(tmp); } tmp = response["real_currency"].asString(); - if (!tmp.empty()) gHippoGridManager->getConnectedGrid()->setRealCurrencySymbol(tmp); + if (!tmp.empty()) grid.setRealCurrencySymbol(tmp); tmp = response["directory_fee"].asString(); - if (!tmp.empty()) gHippoGridManager->getConnectedGrid()->setDirectoryFee(atoi(tmp.c_str())); - tmp = response["max_groups"].asString(); - if (!tmp.empty()) gHippoGridManager->getConnectedGrid()->setMaxAgentGroups(atoi(tmp.c_str())); - tmp = response["max-agent-groups"].asString(); - if (!tmp.empty()) gHippoGridManager->getConnectedGrid()->setMaxAgentGroups(atoi(tmp.c_str())); + if (!tmp.empty()) grid.setDirectoryFee(atoi(tmp.c_str())); + if (mBenefitsSuccessfullyInit) tmp = response["VoiceConnector"].asString(); - if (!tmp.empty()) gHippoGridManager->getConnectedGrid()->setVoiceConnector(tmp); + if (!tmp.empty()) grid.setVoiceConnector(tmp); tmp = response["upc_supported"].asString(); - if (!tmp.empty()) gHippoGridManager->getConnectedGrid()->setUPCSupported(true); + if (!tmp.empty()) grid.setUPCSupported(true); + if (opensim && !mBenefitsSuccessfullyInit) + LLAgentBenefitsMgr::instance().initNonSL(response); gHippoGridManager->saveFile(); gHippoLimits->setLimits(); @@ -4218,3 +4343,4 @@ void transition_back_to_login_panel(const std::string& emsg) reset_login(); // calls LLStartUp::setStartupState( STATE_LOGIN_SHOW ); gSavedSettings.setBOOL("AutoLogin", FALSE); } + diff --git a/indra/newview/llstartup.h b/indra/newview/llstartup.h index f53d9d5b04..88cdac5e6b 100644 --- a/indra/newview/llstartup.h +++ b/indra/newview/llstartup.h @@ -104,6 +104,7 @@ class LLStartUp static void fontInit(); static void initNameCache(); + static void initExperiences(); static void cleanupNameCache(); @@ -138,6 +139,7 @@ class LLStartUp static bool startLLProxy(); // Initialize the SOCKS 5 proxy static LLViewerStats::PhaseMap& getPhases() { return *sPhases; } + static LLEventPump& getStateEventPump() { return *sStateWatcher; } private: static LLSLURL sStartSLURL; diff --git a/indra/newview/llstatusbar.cpp b/indra/newview/llstatusbar.cpp index fcec44e4b9..4dbb92f1ce 100644 --- a/indra/newview/llstatusbar.cpp +++ b/indra/newview/llstatusbar.cpp @@ -38,15 +38,14 @@ #include "llagent.h" #include "llbutton.h" #include "llcommandhandler.h" -#include "llenvmanager.h" #include "llfloaterbuycurrency.h" #include "llfloaterchat.h" #include "llfloaterinventory.h" -#include "llfloaterlagmeter.h" #include "llfloaterland.h" #include "llfloaterregioninfo.h" #include "llfloaterscriptdebug.h" #include "llfloatersearch.h" +#include "llfloaterstats.h" #include "llhudicon.h" #include "llkeyboard.h" #include "lllineeditor.h" @@ -57,6 +56,7 @@ #include "llpathfindingnavmeshstatus.h" #include "llimview.h" #include "lltextbox.h" +#include "lltrans.h" #include "llui.h" #include "llviewerparceloverlay.h" #include "llviewerregion.h" @@ -93,9 +93,11 @@ #include #include "hippogridmanager.h" +#include "lfsimfeaturehandler.h" // [RLVa:KB] -#include "rlvhandler.h" +#include "rlvactions.h" +#include "rlvcommon.h" // [/RLVa:KB] // @@ -118,20 +120,11 @@ const F32 ICON_TIMER_EXPIRY = 3.f; // How long the balance and health icons sho const F32 ICON_FLASH_FREQUENCY = 2.f; const S32 TEXT_HEIGHT = 18; -static void onClickParcelInfo(void*); -static void onClickBalance(void*); -static void onClickBuyCurrency(void*); -static void onClickHealth(void*); -static void onClickFly(void*); -static void onClickPush(void*); -static void onClickVoice(void*); -static void onClickBuild(void*); -static void onClickPFDirty(void*); -static void onClickPFDisabled(void*); -static void onClickSeeAV(void*); -static void onClickScripts(void*); -static void onClickBuyLand(void*); -static void onClickScriptDebug(void*); +static void onClickParcelInfo(); +static bool rebakeRegionCallback(const LLSD& n, const LLSD& r); +static void pf_dirty_click() { LLNotificationsUtil::add("PathfindingDirty", LLSD(), LLSD(), rebakeRegionCallback); } +static void onClickScripts(); +static void onClickSearch(const std::string& query); std::vector LLStatusBar::sDays; std::vector LLStatusBar::sMonths; @@ -154,6 +147,12 @@ class LLDispatchUPCBalance : public LLDispatchHandler static LLDispatchUPCBalance sDispatchUPCBalance; +static void toggle_time_value() +{ + LLControlVariable* control = gSavedSettings.getControl("LiruLocalTime"); + control->set(!control->get()); +} + LLStatusBar::LLStatusBar(const std::string& name, const LLRect& rect) : LLPanel(name, LLRect(), FALSE), // not mouse opaque mBalance(0), @@ -195,39 +194,55 @@ mIsNavMeshDirty(false) mTextHealth = getChild("HealthText" ); mTextTime = getChild("TimeText" ); + mTextTime->setClickedCallback(boost::bind(toggle_time_value)); if (!mUPCSupported) mTextUPC->setVisible(false); - childSetAction("scriptout", onClickScriptDebug, this); - childSetAction("health", onClickHealth, this); - childSetAction("no_fly", onClickFly, this); - childSetAction("buyland", onClickBuyLand, this ); - childSetAction("buycurrency", onClickBuyCurrency, this ); - childSetAction("no_build", onClickBuild, this ); - childSetAction("pf_dirty", onClickPFDirty, this); - childSetAction("pf_disabled", onClickPFDisabled, this); - childSetAction("status_SeeAV", onClickSeeAV, this ); - childSetAction("no_scripts", onClickScripts, this ); - childSetAction("restrictpush", onClickPush, this ); - childSetAction("status_no_voice", onClickVoice, this ); - - childSetCommitCallback("search_editor", onCommitSearch, this); - childSetAction("search_btn", onClickSearch, this); - - childSetVisible("search_editor", gSavedSettings.getBOOL("ShowSearchBar")); - childSetVisible("search_btn", gSavedSettings.getBOOL("ShowSearchBar")); - childSetVisible("menubar_search_bevel_bg", gSavedSettings.getBOOL("ShowSearchBar")); - - childSetActionTextbox("ParcelNameText", onClickParcelInfo ); - childSetActionTextbox("BalanceText", onClickBalance ); + mScriptOut = getChild("scriptout"); + mScriptOut->setCommitCallback(boost::bind(LLFloaterScriptDebug::show, LLUUID::null)); + mHealthV = getChild("health"); + mHealthV->setCommitCallback(boost::bind(LLNotificationsUtil::add, "NotSafe")); + mNoFly = getChild("no_fly"); + mNoFly->setCommitCallback(boost::bind(LLNotificationsUtil::add, "NoFly")); + mBuyLand = getChild("buyland"); + mBuyLand->setCommitCallback(boost::bind(&LLViewerParcelMgr::startBuyLand, boost::bind(LLViewerParcelMgr::getInstance), 0)); + mBuyCurrency = getChild("buycurrency"); + mBuyCurrency->setCommitCallback(boost::bind(LLFloaterBuyCurrency::buyCurrency)); + mNoBuild = getChild("no_build"); + mNoBuild->setCommitCallback(boost::bind(LLNotificationsUtil::add, "NoBuild")); + mPFDirty = getChild("pf_dirty"); + mPFDirty->setCommitCallback(boost::bind(pf_dirty_click)); + mPFDisabled = getChild("pf_disabled"); + mPFDisabled->setCommitCallback(boost::bind(LLNotificationsUtil::add, "DynamicPathfindingDisabled")); + mStatusSeeAV = getChild("status_SeeAV"); + mStatusSeeAV->setCommitCallback(boost::bind(LLNotificationsUtil::add, "SeeAvatars")); + mNoScripts = getChild("no_scripts"); + mNoScripts->setCommitCallback(boost::bind(onClickScripts)); + mRestrictPush = getChild("restrictpush"); + mRestrictPush->setCommitCallback(boost::bind(LLNotificationsUtil::add, "PushRestricted")); + mStatusNoVoice = getChild("status_no_voice"); + mStatusNoVoice->setCommitCallback(boost::bind(LLNotificationsUtil::add, "NoVoice")); + + mSearchEditor = getChild("search_editor"); + mSearchEditor->setCommitCallback(boost::bind(onClickSearch, _2)); + mSearchBtn = getChild("search_btn"); + mSearchBtn->setCommitCallback(boost::bind(onClickSearch, boost::bind(&LLView::getValue, mSearchEditor))); + + bool show_search(gSavedSettings.getBOOL("ShowSearchBar")); + mSearchEditor->setVisible(show_search); + mSearchBtn->setVisible(show_search); + mSearchBevel = getChildView("menubar_search_bevel_bg"); + mSearchBevel->setVisible(show_search); + + mTextParcelName->setClickedCallback(boost::bind(onClickParcelInfo)); + mTextBalance->setClickedCallback(boost::bind(LLStatusBar::sendMoneyBalanceRequest, true)); // TODO: Disable buying currency when connected to non-SL grids // that don't support currency yet -- MC - LLButton* buybtn = getChild("buycurrency"); - buybtn->setLabelArg("[CURRENCY]", gHippoGridManager->getConnectedGrid()->getCurrencySymbol()); + mBuyCurrency->setLabelArg("[CURRENCY]", gHippoGridManager->getConnectedGrid()->getCurrencySymbol()); - mRegionCrossingSlot = LLEnvManagerNew::getInstance()->setRegionChangeCallback(boost::bind(&LLStatusBar::createNavMeshStatusListenerForCurrentRegion, this)); + mRegionCrossingSlot = gAgent.addRegionChangedCallback(boost::bind(&LLStatusBar::createNavMeshStatusListenerForCurrentRegion, this)); createNavMeshStatusListenerForCurrentRegion(); // Adding Net Stat Graph @@ -261,8 +276,8 @@ mIsNavMeshDirty(false) mSGPacketLoss->mPerSec = FALSE; addChild(mSGPacketLoss); - childSetActionTextbox("stat_btn", onClickStatGraph); - + mStatBtn = getChild("stat_btn"); + mStatBtn->setClickedCallback(boost::bind(LLFloaterStats::toggleInstance, LLSD())); } LLStatusBar::~LLStatusBar() @@ -314,23 +329,29 @@ void LLStatusBar::refresh() mSGBandwidth->setThreshold(1, bwtotal); mSGBandwidth->setThreshold(2, bwtotal); - // *TODO: Localize / translate time + // Singu Note: Use system's time if the user desires, otherwise use server time + static const LLCachedControl show_local_time("LiruLocalTime"); // Get current UTC time, adjusted for the user's clock // being off. - time_t utc_time; - utc_time = time_corrected(); + time_t utc_time = show_local_time ? time(NULL) : time_corrected(); // There's only one internal tm buffer. struct tm* internal_time; // Convert to Pacific, based on server's opinion of whether // it's daylight savings time there. - internal_time = utc_to_pacific_time(utc_time, gPacificDaylightTime); + internal_time = show_local_time ? std::localtime(&utc_time) : utc_to_pacific_time(utc_time, gPacificDaylightTime); + static const LLCachedControl short_time_fmt(gSavedSettings, "ShortTimeFormat"); std::string t; - timeStructToFormattedString(internal_time, gSavedSettings.getString("ShortTimeFormat"), t); - if (gPacificDaylightTime) + timeStructToFormattedString(internal_time, short_time_fmt, t); + if (show_local_time) + { + static const std::string local(" " + getString("Local")); + t += local; + } + else if (gPacificDaylightTime) { t += " PDT"; } @@ -340,8 +361,9 @@ void LLStatusBar::refresh() } mTextTime->setText(t); + static const LLCachedControl long_date_fmt(gSavedSettings, "LongDateFormat"); std::string date; - timeStructToFormattedString(internal_time, gSavedSettings.getString("LongDateFormat"), date); + timeStructToFormattedString(internal_time, long_date_fmt, date); mTextTime->setToolTip(date); LLRect r; @@ -349,8 +371,6 @@ void LLStatusBar::refresh() S32 x = MENU_RIGHT + MENU_PARCEL_SPACING; S32 y = 0; - bool search_visible = gSavedSettings.getBOOL("ShowSearchBar"); - // reshape menu bar to its content's width if (MENU_RIGHT != gMenuBarView->getRect().getWidth()) { @@ -360,40 +380,30 @@ void LLStatusBar::refresh() LLViewerRegion *region = gAgent.getRegion(); LLParcel *parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); - LLRect buttonRect; - if (LLHUDIcon::iconsNearby()) { - childGetRect( "scriptout", buttonRect ); + const LLRect& buttonRect = mScriptOut->getRect(); r.setOriginAndSize( x, y, buttonRect.getWidth(), buttonRect.getHeight()); - childSetRect("scriptout",r); - childSetVisible("scriptout", true); + mScriptOut->setRect(r); + mScriptOut->setVisible(true); x += buttonRect.getWidth(); } else { - childSetVisible("scriptout", false); + mScriptOut->setVisible(false); } if ((region && region->getAllowDamage()) || (parcel && parcel->getAllowDamage()) ) { // set visibility based on flashing - if( mHealthTimer->hasExpired() ) - { - childSetVisible("health", true); - } - else - { - BOOL flash = S32(mHealthTimer->getElapsedSeconds() * ICON_FLASH_FREQUENCY) & 1; - childSetVisible("health", flash); - } + mHealthV->setVisible(mHealthTimer->hasExpired() || S32(mHealthTimer->getElapsedSeconds() * ICON_FLASH_FREQUENCY) & 1); mTextHealth->setVisible(TRUE); // Health - childGetRect( "health", buttonRect ); + const LLRect& buttonRect = mHealthV->getRect(); r.setOriginAndSize( x, y, buttonRect.getWidth(), buttonRect.getHeight()); - childSetRect("health", r); + mHealthV->setRect(r); x += buttonRect.getWidth(); const S32 health_width = S32( LLFontGL::getFontSansSerifSmall()->getWidth(std::string("100%")) ); @@ -404,7 +414,7 @@ void LLStatusBar::refresh() else { // invisible if region doesn't allow damage - childSetVisible("health", false); + mHealthV->setVisible(false); mTextHealth->setVisible(FALSE); } @@ -412,168 +422,134 @@ void LLStatusBar::refresh() (parcel && !parcel->getAllowFly()) ) { // No Fly Zone - childGetRect( "no_fly", buttonRect ); - childSetVisible( "no_fly", true ); + mNoFly->setVisible(true); + const LLRect& buttonRect(mNoFly->getRect()); r.setOriginAndSize( x, y, buttonRect.getWidth(), buttonRect.getHeight()); - childSetRect( "no_fly", r ); + mNoFly->setRect(r); x += buttonRect.getWidth(); } else { // Fly Zone - childSetVisible("no_fly", false); + mNoFly->setVisible(false); } - BOOL no_build = parcel && !parcel->getAllowModify(); - if (no_build) + if (parcel && !parcel->getAllowModify()) { - childSetVisible("no_build", TRUE); - childGetRect( "no_build", buttonRect ); // No Build Zone + mNoBuild->setVisible(true); + const LLRect& buttonRect(mNoBuild->getRect()); r.setOriginAndSize( x, y, buttonRect.getWidth(), buttonRect.getHeight()); - childSetRect( "no_build", r ); + mNoBuild->setRect(r); x += buttonRect.getWidth(); } else { - childSetVisible("no_build", FALSE); + mNoBuild->setVisible(false); } - BOOL no_scripts = FALSE; - if((region + if ((region && (region->getRegionFlag(REGION_FLAGS_SKIP_SCRIPTS) || region->getRegionFlag(REGION_FLAGS_ESTATE_SKIP_SCRIPTS))) || (parcel && !parcel->getAllowOtherScripts())) - { - no_scripts = TRUE; - } - if (no_scripts) { // No scripts - childSetVisible("no_scripts", TRUE); - childGetRect( "no_scripts", buttonRect ); + mNoScripts->setVisible(true); + const LLRect& buttonRect(mNoScripts->getRect()); r.setOriginAndSize( x, y, buttonRect.getWidth(), buttonRect.getHeight()); - childSetRect( "no_scripts", r ); + mNoScripts->setRect(r); x += buttonRect.getWidth(); } else { // Yes scripts - childSetVisible("no_scripts", FALSE); + mNoScripts->setVisible(false); } - BOOL no_region_push = (region && region->getRestrictPushObject()); - BOOL no_push = no_region_push || (parcel && parcel->getRestrictPushObject()); - if (no_push) + if ((region && region->getRestrictPushObject()) || (parcel && parcel->getRestrictPushObject())) { - childSetVisible("restrictpush", TRUE); - childGetRect( "restrictpush", buttonRect ); + mRestrictPush->setVisible(true); + const LLRect& buttonRect(mRestrictPush->getRect()); r.setOriginAndSize( x, y, buttonRect.getWidth(), buttonRect.getHeight()); - childSetRect( "restrictpush", r ); + mRestrictPush->setRect(r); x += buttonRect.getWidth(); } else { - childSetVisible("restrictpush", FALSE); + mRestrictPush->setVisible(false); } - BOOL have_voice = parcel && parcel->getParcelFlagAllowVoice(); - if (have_voice) + if (parcel && parcel->getParcelFlagAllowVoice()) { - childSetVisible("status_no_voice", FALSE); + mStatusNoVoice->setVisible(false); } else { - childSetVisible("status_no_voice", TRUE); - childGetRect( "status_no_voice", buttonRect ); + mStatusNoVoice->setVisible(true); + const LLRect& buttonRect(mStatusNoVoice->getRect()); r.setOriginAndSize( x, y, buttonRect.getWidth(), buttonRect.getHeight()); - childSetRect( "status_no_voice", r ); + mStatusNoVoice->setRect(r); x += buttonRect.getWidth(); } - bool no_see_avs = parcel && !parcel->getSeeAVs(); - childSetVisible("status_SeeAV", no_see_avs); - if (no_see_avs) + if (parcel && !parcel->getSeeAVs()) { - childGetRect( "status_SeeAV", buttonRect ); + mStatusSeeAV->setVisible(true); + const LLRect& buttonRect(mStatusSeeAV->getRect()); r.setOriginAndSize( x, y, buttonRect.getWidth(), buttonRect.getHeight()); - childSetRect( "status_SeeAV", r ); + mStatusSeeAV->setRect(r); x += buttonRect.getWidth(); } + else mStatusSeeAV->setVisible(false); if (region) { bool pf_disabled = !region->dynamicPathfindingEnabled(); - getChild("pf_dirty")->setVisible(!pf_disabled && mIsNavMeshDirty); - getChild("pf_disabled")->setVisible(pf_disabled); - const std::string pf_icon = pf_disabled ? "pf_disabled" : mIsNavMeshDirty ? "pf_dirty" : ""; - if (!pf_icon.empty()) + mPFDirty->setVisible(!pf_disabled && mIsNavMeshDirty); + mPFDisabled->setVisible(pf_disabled); + if (LLView* pf_icon = pf_disabled ? mPFDisabled : mIsNavMeshDirty ? mPFDirty : NULL) { x += 6; - childGetRect(pf_icon, buttonRect); + const LLRect& buttonRect(pf_icon->getRect()); r.setOriginAndSize(x, y, buttonRect.getWidth(), buttonRect.getHeight()); - childSetRect(pf_icon, r); + pf_icon->setRect(r); x += buttonRect.getWidth(); } } - BOOL canBuyLand = parcel - && !parcel->isPublic() - && LLViewerParcelMgr::getInstance()->canAgentBuyParcel(parcel, false); - childSetVisible("buyland", canBuyLand); - if (canBuyLand) + if (parcel && !parcel->isPublic() && LLViewerParcelMgr::getInstance()->canAgentBuyParcel(parcel, false)) { + mBuyLand->setVisible(true); //HACK: layout tweak until this is all xml x += 9; - childGetRect( "buyland", buttonRect ); + const LLRect& buttonRect(mBuyLand->getRect()); r.setOriginAndSize( x, y, buttonRect.getWidth(), buttonRect.getHeight()); - childSetRect( "buyland", r ); + mBuyLand->setRect(r); x += buttonRect.getWidth(); } + else mBuyLand->setVisible(false); std::string location_name; - if (region) + if (region && parcel) { - const LLVector3& agent_pos_region = gAgent.getPositionAgent(); - S32 pos_x = lltrunc( agent_pos_region.mV[VX] ); - S32 pos_y = lltrunc( agent_pos_region.mV[VY] ); - S32 pos_z = lltrunc( agent_pos_region.mV[VZ] ); - - // Round the numbers based on the velocity - LLVector3 agent_velocity = gAgent.getVelocity(); - F32 velocity_mag_sq = agent_velocity.magVecSquared(); - - const F32 FLY_CUTOFF = 6.f; // meters/sec - const F32 FLY_CUTOFF_SQ = FLY_CUTOFF * FLY_CUTOFF; - const F32 WALK_CUTOFF = 1.5f; // meters/sec - const F32 WALK_CUTOFF_SQ = WALK_CUTOFF * WALK_CUTOFF; - - if (velocity_mag_sq > FLY_CUTOFF_SQ) - { - pos_x -= pos_x % 4; - pos_y -= pos_y % 4; - } - else if (velocity_mag_sq > WALK_CUTOFF_SQ) +// [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0a) | Modified: RLVa-1.0.0a + if (RlvActions::hasBehaviour(RLV_BHVR_SHOWLOC)) { - pos_x -= pos_x % 2; - pos_y -= pos_y % 2; - } - - if (parcel) - { - if (!LLAgentUI::buildLocationString(location_name, LLAgentUI::LOCATION_FORMAT_FULL)) - { - location_name = "???"; - } + location_name = llformat("%s (%s) - %s", + RlvStrings::getString(RLV_STRING_HIDDEN_REGION).c_str(), region->getSimAccessString().c_str(), + RlvStrings::getString(RLV_STRING_HIDDEN).c_str()); } else +// [/RLVa:KB] + if (!LLAgentUI::buildLocationString(location_name, LLAgentUI::LOCATION_FORMAT_FULL)) + location_name = "???"; + else { - location_name = region->getName() - + llformat(" %d, %d, %d (%s)", - pos_x, pos_y, pos_z, - region->getSimAccessString().c_str()); + const std::string& grid(LFSimFeatureHandler::instance().gridName()); + if (!grid.empty()) location_name += ", " + grid; } - static LLCachedControl show_channel("ShowSimChannel"); + + static const LLCachedControl show_channel("ShowSimChannel"); if (show_channel && !gLastVersionChannel.empty()) location_name += " - " + gLastVersionChannel; } else @@ -582,70 +558,58 @@ void LLStatusBar::refresh() location_name = "(Unknown)"; } -// [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0a) | Modified: RLVa-1.0.0a - if ( (region) && (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) ) // region == NULL if we lose our connection to the grid - { - location_name = llformat("%s (%s) - %s", - RlvStrings::getString(RLV_STRING_HIDDEN_REGION).c_str(), region->getSimAccessString().c_str(), - RlvStrings::getString(RLV_STRING_HIDDEN).c_str()); - } -// [/RLVa:KB] - mTextParcelName->setText(location_name); - - // x = right edge // loop through: stat graphs, search btn, search text editor, money, buy money, clock // adjust rect // finally adjust parcel name rect S32 new_right = getRect().getWidth(); + static const LLCachedControl search_visible(gSavedSettings, "ShowSearchBar"); if (search_visible) { - childGetRect("search_btn", r); - //r.translate( new_right - r.mRight, 0); - //childSetRect("search_btn", r); - new_right -= r.getWidth(); - - childGetRect("search_editor", r); - //r.translate( new_right - r.mRight, 0); - //childSetRect("search_editor", r); - new_right -= r.getWidth() + 6; + new_right -= mSearchBtn->getRect().getWidth(); + new_right -= mSearchEditor->getRect().getWidth() + 6; } else { - childGetRect("stat_btn", r); + r = mStatBtn->getRect(); r.translate( new_right - r.mRight, 0); - childSetRect("stat_btn", r); + mStatBtn->setRect(r); new_right -= r.getWidth() + 6; } + // Set search bar visibility + mSearchEditor->setVisible(search_visible); + mSearchBtn->setVisible(search_visible); + mSearchBevel->setVisible(search_visible); + mSGBandwidth->setVisible(! search_visible); + mSGPacketLoss->setVisible(! search_visible); + mStatBtn->setEnabled(!search_visible); + // Set rects of money, buy money, time if (mUPCSupported) { - childGetRect("UPCText", r); + r = mTextUPC->getRect(); r.translate( new_right - r.mRight, 0); - childSetRect("UPCText", r); + mTextUPC->setRect(r); new_right -= r.getWidth() - 18; } - childGetRect("BalanceText", r); + r = mTextBalance->getRect(); r.translate( new_right - r.mRight, 0); - childSetRect("BalanceText", r); + mTextBalance->setRect(r); new_right -= r.getWidth() - 18; - childGetRect("buycurrency", r); + r = mBuyCurrency->getRect(); r.translate( new_right - r.mRight, 0); - childSetRect("buycurrency", r); + mBuyCurrency->setRect(r); new_right -= r.getWidth() + 6; - childGetRect("TimeText", r); - // mTextTime->getTextPixelWidth(); + r = mTextTime->getRect(); r.translate( new_right - r.mRight, 0); - childSetRect("TimeText", r); - // new_right -= r.getWidth() + MENU_PARCEL_SPACING; - + mTextTime->setRect(r); // Adjust region name and parcel name x += 8; @@ -653,14 +617,6 @@ void LLStatusBar::refresh() const S32 PARCEL_RIGHT = llmin(mTextTime->getRect().mLeft, mTextParcelName->getTextPixelWidth() + x + 5); r.set(x+4, getRect().getHeight() - 2, PARCEL_RIGHT, 0); mTextParcelName->setRect(r); - - // Set search bar visibility - childSetVisible("search_editor", search_visible); - childSetVisible("search_btn", search_visible); - childSetVisible("menubar_search_bevel_bg", search_visible); - mSGBandwidth->setVisible(! search_visible); - mSGPacketLoss->setVisible(! search_visible); - childSetEnabled("stat_btn", ! search_visible); } void LLStatusBar::setVisibleForMouselook(bool visible) @@ -669,9 +625,9 @@ void LLStatusBar::setVisibleForMouselook(bool visible) if (mUPCSupported) mTextUPC->setVisible(visible); mTextTime->setVisible(visible); - childSetVisible("buycurrency", visible); - childSetVisible("search_editor", visible); - childSetVisible("search_btn", visible); + mBuyCurrency->setVisible(visible); + mSearchEditor->setVisible(visible); + mSearchBtn->setVisible(visible); mSGBandwidth->setVisible(visible); mSGPacketLoss->setVisible(visible); setBackgroundVisible(visible); @@ -717,8 +673,10 @@ void LLStatusBar::setUPC(S32 upc) } // static -void LLStatusBar::sendMoneyBalanceRequest() +void LLStatusBar::sendMoneyBalanceRequest(bool from_user) { + void cmdline_printchat(const std::string& message); + if (from_user) cmdline_printchat(LLTrans::getString("refreshing balance")); LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_MoneyBalanceRequest); msg->nextBlockFast(_PREHASH_AgentData); @@ -732,7 +690,7 @@ void LLStatusBar::sendMoneyBalanceRequest() void LLStatusBar::setHealth(S32 health) { - //llinfos << "Setting health to: " << buffer << llendl; + //LL_INFOS() << "Setting health to: " << buffer << LL_ENDL; mTextHealth->setText(llformat("%d%%", health)); if( mHealth > health ) @@ -798,53 +756,12 @@ S32 LLStatusBar::getSquareMetersLeft() const return mSquareMetersCredit - mSquareMetersCommitted; } -static void onClickParcelInfo(void* data) +static void onClickParcelInfo() { LLViewerParcelMgr::getInstance()->selectParcelAt(gAgent.getPositionGlobal()); - LLFloaterLand::showInstance(); } -static void onClickBalance(void* data) -{ - onClickBuyCurrency(data); -} - -static void onClickBuyCurrency(void* data) -{ - LLFloaterBuyCurrency::buyCurrency(); -} - -static void onClickHealth(void* ) -{ - LLNotificationsUtil::add("NotSafe"); -} - -static void onClickScriptDebug(void*) -{ - LLFloaterScriptDebug::show(LLUUID::null); -} - -static void onClickFly(void* ) -{ - LLNotificationsUtil::add("NoFly"); -} - -static void onClickPush(void* ) -{ - LLNotificationsUtil::add("PushRestricted"); -} - -static void onClickVoice(void* ) -{ - LLNotificationsUtil::add("NoVoice"); -} - -static void onClickBuild(void*) -{ - LLNotificationsUtil::add("NoBuild"); -} - static bool rebakeRegionCallback(const LLSD& n, const LLSD& r) { if(!LLNotificationsUtil::getSelectedOption(n, r)) //0 is Yes @@ -855,16 +772,6 @@ static bool rebakeRegionCallback(const LLSD& n, const LLSD& r) return false; } -static void onClickPFDirty(void*) -{ - LLNotificationsUtil::add("PathfindingDirty", LLSD(), LLSD(), rebakeRegionCallback); -} - -static void onClickPFDisabled(void*) -{ - LLNotificationsUtil::add("DynamicPathfindingDisabled"); -} - void LLStatusBar::createNavMeshStatusListenerForCurrentRegion() { if (mNavMeshSlot.connected()) @@ -886,12 +793,7 @@ void LLStatusBar::onNavMeshStatusChange(const LLPathfindingNavMeshStatus &pNavMe refresh(); } -static void onClickSeeAV(void*) -{ - LLNotificationsUtil::add("SeeAvatars"); -} - -static void onClickScripts(void*) +static void onClickScripts() { LLViewerRegion* region = gAgent.getRegion(); if(region && region->getRegionFlag(REGION_FLAGS_ESTATE_SKIP_SCRIPTS)) @@ -908,18 +810,6 @@ static void onClickScripts(void*) } } -static void onClickBuyLand(void*) -{ -// [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0a) - if ( (rlv_handler_t::isEnabled()) && (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) ) - { - return; - } -// [/RLVa:KB] - LLViewerParcelMgr::getInstance()->selectParcelAt(gAgent.getPositionGlobal()); - LLViewerParcelMgr::getInstance()->startBuyLand(); -} - // sets the static variables necessary for the date void LLStatusBar::setupDate() { @@ -983,28 +873,13 @@ void LLStatusBar::setupDate() } } -// static -void LLStatusBar::onCommitSearch(LLUICtrl*, void* data) -{ - // committing is the same as clicking "search" - onClickSearch(data); -} - -// static -void LLStatusBar::onClickSearch(void* data) +static void onClickSearch(const std::string& query) { - LLStatusBar* self = (LLStatusBar*)data; LLFloaterSearch::SearchQuery search; - search.query = self->childGetText("search_editor"); + search.query = query; LLFloaterSearch::showInstance(search); } -// static -void LLStatusBar::onClickStatGraph(void* data) -{ - LLFloaterLagMeter::showInstance(); -} - BOOL can_afford_transaction(S32 cost) { return((cost <= 0)||((gStatusBar) && (gStatusBar->getBalance() >=cost))); @@ -1023,7 +898,7 @@ class LLBalanceHandler : public LLCommandHandler if (tokens.size() == 1 && tokens[0].asString() == "request") { - LLStatusBar::sendMoneyBalanceRequest(); + LLStatusBar::sendMoneyBalanceRequest(true); return true; } return false; diff --git a/indra/newview/llstatusbar.h b/indra/newview/llstatusbar.h index b24913ef31..3acf9998f1 100644 --- a/indra/newview/llstatusbar.h +++ b/indra/newview/llstatusbar.h @@ -66,7 +66,7 @@ class LLStatusBar void creditBalance(S32 credit); // Request the latest currency balance from the server - static void sendMoneyBalanceRequest(); + static void sendMoneyBalanceRequest(bool from_user = false); void setHealth(S32 percent); @@ -90,10 +90,6 @@ class LLStatusBar // simple method to setup the part that holds the date void setupDate(); - static void onCommitSearch(LLUICtrl*, void* data); - static void onClickSearch(void* data); - static void onClickStatGraph(void* data); - void onRegionBoundaryCrossed(); void createNavMeshStatusListenerForCurrentRegion(); void onNavMeshStatusChange(const LLPathfindingNavMeshStatus &pNavMeshStatus); @@ -111,6 +107,23 @@ class LLStatusBar LLButton *mBtnBuyCurrency; + LLUICtrl* mScriptOut; + LLUICtrl* mHealthV; + LLUICtrl* mNoFly; + LLUICtrl* mBuyLand; + LLUICtrl* mBuyCurrency; + LLUICtrl* mNoBuild; + LLUICtrl* mPFDirty; + LLUICtrl* mPFDisabled; + LLUICtrl* mStatusSeeAV; + LLUICtrl* mNoScripts; + LLUICtrl* mRestrictPush; + LLUICtrl* mStatusNoVoice; + LLUICtrl* mSearchEditor; + LLUICtrl* mSearchBtn; + LLView* mSearchBevel; + LLTextBox* mStatBtn; + S32 mBalance; S32 mUPC; S32 mHealth; diff --git a/indra/newview/llstylemap.cpp b/indra/newview/llstylemap.cpp index a0c64505e1..fb6dad7a23 100644 --- a/indra/newview/llstylemap.cpp +++ b/indra/newview/llstylemap.cpp @@ -33,6 +33,7 @@ #include "llviewerprecompiledheaders.h" #include "llstylemap.h" +#include "llavataractions.h" LLStyleMap::LLStyleMap() { @@ -58,9 +59,8 @@ const LLStyleSP &LLStyleMap::lookupAgent(const LLUUID &source) LLStyleSP style(new LLStyle); if (source.notNull()) { - style->setColor(gSavedSettings.getColor4("HTMLLinkColor")); - std::string link = llformat("secondlife:///app/agent/%s/about",source.asString().c_str()); - style->setLinkHREF(link); + style->setColor(gSavedSettings.getColor4("HTMLAgentColor")); + style->setLinkHREF(LLAvatarActions::getSLURL(source)); } (*this)[source] = style; } @@ -77,7 +77,7 @@ const LLStyleSP &LLStyleMap::lookup(const LLUUID& id, const std::string& link) LLStyleSP style(new LLStyle); if (id.notNull() && !link.empty()) { - style->setColor(gSavedSettings.getColor4("HTMLLinkColor")); + style->setColor(gSavedSettings.getColor4("HTMLAgentColor")); style->setLinkHREF(link); } else @@ -102,6 +102,6 @@ void LLStyleMap::update() { LLStyleSP &style = iter->second; // Update the link color in case it has been changed. - style->setColor(gSavedSettings.getColor4("HTMLLinkColor")); + style->setColor(gSavedSettings.getColor4("HTMLAgentColor")); } } diff --git a/indra/newview/llsurface.cpp b/indra/newview/llsurface.cpp index ca4c37effc..81dd368037 100644 --- a/indra/newview/llsurface.cpp +++ b/indra/newview/llsurface.cpp @@ -49,11 +49,11 @@ #include "pipeline.h" #include "llviewerregion.h" #include "llvlcomposition.h" -#include "noise.h" #include "llviewercamera.h" #include "llglheaders.h" #include "lldrawpoolterrain.h" #include "lldrawable.h" +#include "hippogridmanager.h" extern LLPipeline gPipeline; extern bool gShiftFrame; @@ -72,7 +72,6 @@ LLSurface::LLSurface(U32 type, LLViewerRegion *regionp) : mGridsPerEdge(0), mOOGridsPerEdge(0.f), mPatchesPerEdge(0), - mNumberOfPatches(0), mType(type), mDetailTextureScale(0.f), mOriginGlobal(0.0, 0.0, 0.0), @@ -87,9 +86,6 @@ LLSurface::LLSurface(U32 type, LLViewerRegion *regionp) : mSurfaceZ = NULL; mNorm = NULL; - // Patch data - mPatchList = NULL; - // One of each for each camera mVisiblePatchCount = 0; @@ -120,13 +116,12 @@ LLSurface::~LLSurface() mGridsPerEdge = 0; mGridsPerPatchEdge = 0; mPatchesPerEdge = 0; - mNumberOfPatches = 0; destroyPatchData(); LLDrawPoolTerrain *poolp = (LLDrawPoolTerrain*) gPipeline.findPool(LLDrawPool::POOL_TERRAIN, mSTexturep); if (!poolp) { - llwarns << "No pool for terrain on destruction!" << llendl; + LL_WARNS() << "No pool for terrain on destruction!" << LL_ENDL; } else if (poolp->mReferences.empty()) { @@ -143,7 +138,7 @@ LLSurface::~LLSurface() } else { - llerrs << "Terrain pool not empty!" << llendl; + LL_ERRS() << "Terrain pool not empty!" << LL_ENDL; } } @@ -168,10 +163,12 @@ void LLSurface::create(const S32 grids_per_edge, mGridsPerEdge = grids_per_edge + 1; // Add 1 for the east and north buffer mOOGridsPerEdge = 1.f / mGridsPerEdge; mGridsPerPatchEdge = grids_per_patch_edge; - mPatchesPerEdge = (mGridsPerEdge - 1) / mGridsPerPatchEdge; - mNumberOfPatches = mPatchesPerEdge * mPatchesPerEdge; - mMetersPerGrid = width / ((F32)(mGridsPerEdge - 1)); - mMetersPerEdge = mMetersPerGrid * (mGridsPerEdge - 1); + mPatchesPerEdge = grids_per_edge / mGridsPerPatchEdge; + mMetersPerGrid = width / (F32)grids_per_edge; + mMetersPerEdge = mMetersPerGrid * grids_per_edge; +// Aurora Sim + sTextureSize = width; +// Aurora Sim mOriginGlobal.setVec(origin_global); @@ -295,8 +292,11 @@ void LLSurface::initTextures() mWaterObjp = (LLVOWater *)gObjectList.createObjectViewer(LLViewerObject::LL_VO_WATER, mRegionp); gPipeline.createObject(mWaterObjp); LLVector3d water_pos_global = from_region_handle(mRegionp->getHandle()); - water_pos_global += LLVector3d(128.0, 128.0, DEFAULT_WATER_HEIGHT); +// Aurora Sim + //water_pos_global += LLVector3d(128.0, 128.0, DEFAULT_WATER_HEIGHT); // region doesn't have a valid water height yet + water_pos_global += LLVector3d(mRegionp->getWidth()/2, mRegionp->getWidth()/2, DEFAULT_WATER_HEIGHT); mWaterObjp->setPositionGlobal(water_pos_global); +// Aurora Sim } } @@ -305,14 +305,13 @@ void LLSurface::setOriginGlobal(const LLVector3d &origin_global) { LLVector3d new_origin_global; mOriginGlobal = origin_global; - LLSurfacePatch *patchp; S32 i, j; // Need to update the southwest corners of the patches for (j=0; jgetOriginGlobal(); @@ -325,8 +324,12 @@ void LLSurface::setOriginGlobal(const LLVector3d &origin_global) // Hack! if (mWaterObjp.notNull() && mWaterObjp->mDrawable.notNull()) { - const F64 x = origin_global.mdV[VX] + 128.0; - const F64 y = origin_global.mdV[VY] + 128.0; +// Aurora Sim + //const F64 x = origin_global.mdV[VX] + 128.0; + //const F64 y = origin_global.mdV[VY] + 128.0; + const F64 x = origin_global.mdV[VX] + (F64)mRegionp->getWidth()/2; + const F64 y = origin_global.mdV[VY] + (F64)mRegionp->getWidth()/2; +// Aurora Sim const F64 z = mWaterObjp->getPositionGlobal().mdV[VZ]; LLVector3d water_origin_global(x, y, z); @@ -360,220 +363,154 @@ void LLSurface::getNeighboringRegionsStatus( std::vector& regions ) } } -void LLSurface::connectNeighbor(LLSurface *neighborp, U32 direction) +void LLSurface::connectNeighbor(LLSurface* neighborp, U32 direction) { - S32 i; - LLSurfacePatch *patchp, *neighbor_patchp; - - mNeighbors[direction] = neighborp; - neighborp->mNeighbors[gDirOpposite[direction]] = this; - - // Connect patches - if (NORTHEAST == direction) - { - patchp = getPatch(mPatchesPerEdge - 1, mPatchesPerEdge - 1); - neighbor_patchp = neighborp->getPatch(0, 0); - - patchp->connectNeighbor(neighbor_patchp, direction); - neighbor_patchp->connectNeighbor(patchp, gDirOpposite[direction]); - - patchp->updateNorthEdge(); // Only update one of north or east. - patchp->dirtyZ(); - } - else if (NORTHWEST == direction) + // Constraints: + // - Regions width must equal height + // - Region width divisible by mGridsPerPatchEdge (16) + // - Region can only neighbor one other per side and coner (8 total, N, S, E, W, NW, NE, SW, SE) + // - Non-power-of-2 regions should work here, but the rest of the viewer code will probably choke on them. + + surface_patch_ref patchp, neighbor_patchp; + if (mNeighbors[direction] == neighborp) { - patchp = getPatch(0, mPatchesPerEdge - 1); - neighbor_patchp = neighborp->getPatch(mPatchesPerEdge - 1, 0); - - patchp->connectNeighbor(neighbor_patchp, direction); - neighbor_patchp->connectNeighbor(patchp, gDirOpposite[direction]); + return; } - else if (SOUTHWEST == direction) + if (mNeighbors[direction]) { - patchp = getPatch(0, 0); - neighbor_patchp = neighborp->getPatch(mPatchesPerEdge - 1, mPatchesPerEdge - 1); - - patchp->connectNeighbor(neighbor_patchp, direction); - neighbor_patchp->connectNeighbor(patchp, gDirOpposite[direction]); - - neighbor_patchp->updateNorthEdge(); // Only update one of north or east. - neighbor_patchp->dirtyZ(); + mNeighbors[direction]->disconnectNeighbor(this, gDirOpposite[direction]); } - else if (SOUTHEAST == direction) - { - patchp = getPatch(mPatchesPerEdge - 1, 0); - neighbor_patchp = neighborp->getPatch(0, mPatchesPerEdge - 1); - - patchp->connectNeighbor(neighbor_patchp, direction); - neighbor_patchp->connectNeighbor(patchp, gDirOpposite[direction]); - } - else if (EAST == direction) - { - // Do east/west connections, first - for (i = 0; i < (S32)mPatchesPerEdge; i++) - { - patchp = getPatch(mPatchesPerEdge - 1, i); - neighbor_patchp = neighborp->getPatch(0, i); - - patchp->connectNeighbor(neighbor_patchp, direction); - neighbor_patchp->connectNeighbor(patchp, gDirOpposite[direction]); - - patchp->updateEastEdge(); - patchp->dirtyZ(); - } - - // Now do northeast/southwest connections - for (i = 0; i < (S32)mPatchesPerEdge - 1; i++) - { - patchp = getPatch(mPatchesPerEdge - 1, i); - neighbor_patchp = neighborp->getPatch(0, i+1); + mNeighbors[direction] = neighborp; - patchp->connectNeighbor(neighbor_patchp, NORTHEAST); - neighbor_patchp->connectNeighbor(patchp, SOUTHWEST); - } - // Now do southeast/northwest connections - for (i = 1; i < (S32)mPatchesPerEdge; i++) - { - patchp = getPatch(mPatchesPerEdge - 1, i); - neighbor_patchp = neighborp->getPatch(0, i-1); + const S32 max_idx = mPatchesPerEdge - 1; + const S32 neighbor_max_idx = neighborp->mPatchesPerEdge - 1; - patchp->connectNeighbor(neighbor_patchp, SOUTHEAST); - neighbor_patchp->connectNeighbor(patchp, NORTHWEST); - } - } - else if (NORTH == direction) + // Connect patches + if (direction >= 4) { - // Do north/south connections, first - for (i = 0; i < (S32)mPatchesPerEdge; i++) + // Corner stitch + S32 patches[4][2] = { + {max_idx, max_idx}, //NORTHEAST + {0, max_idx}, //NORTHWEST + {0, 0}, //SOUTHWEST + {max_idx, 0}, //SOUTHEAST + }; + const S32* p = patches[direction - 4]; + surface_patch_ref patchp = getPatch(p[0], p[1]); + patchp->connectNeighbor(neighborp->getPatch(max_idx - p[0], max_idx - p[1]), direction); + if (NORTHEAST == direction) { - patchp = getPatch(i, mPatchesPerEdge - 1); - neighbor_patchp = neighborp->getPatch(i, 0); - - patchp->connectNeighbor(neighbor_patchp, direction); - neighbor_patchp->connectNeighbor(patchp, gDirOpposite[direction]); - - patchp->updateNorthEdge(); - patchp->dirtyZ(); - } - - // Do northeast/southwest connections - for (i = 0; i < (S32)mPatchesPerEdge - 1; i++) - { - patchp = getPatch(i, mPatchesPerEdge - 1); - neighbor_patchp = neighborp->getPatch(i+1, 0); - - patchp->connectNeighbor(neighbor_patchp, NORTHEAST); - neighbor_patchp->connectNeighbor(patchp, SOUTHWEST); - } - // Do southeast/northwest connections - for (i = 1; i < (S32)mPatchesPerEdge; i++) - { - patchp = getPatch(i, mPatchesPerEdge - 1); - neighbor_patchp = neighborp->getPatch(i-1, 0); - - patchp->connectNeighbor(neighbor_patchp, NORTHWEST); - neighbor_patchp->connectNeighbor(patchp, SOUTHEAST); + patchp->updateNorthEdge(); // Only update one of north or east. + if (patchp->dirtyZ()) + { + dirtySurfacePatch(patchp); + } } - } - else if (WEST == direction) +} + else { - // Do east/west connections, first - for (i = 0; i < mPatchesPerEdge; i++) - { - patchp = getPatch(0, i); - neighbor_patchp = neighborp->getPatch(mPatchesPerEdge - 1, i); - - patchp->connectNeighbor(neighbor_patchp, direction); - neighbor_patchp->connectNeighbor(patchp, gDirOpposite[direction]); - - neighbor_patchp->updateEastEdge(); - neighbor_patchp->dirtyZ(); - } - - // Now do northeast/southwest connections - for (i = 1; i < mPatchesPerEdge; i++) - { - patchp = getPatch(0, i); - neighbor_patchp = neighborp->getPatch(mPatchesPerEdge - 1, i - 1); - - patchp->connectNeighbor(neighbor_patchp, SOUTHWEST); - neighbor_patchp->connectNeighbor(patchp, NORTHEAST); - } - - // Now do northwest/southeast connections - for (i = 0; i < mPatchesPerEdge - 1; i++) + // Edge stitch + // Aurora complicates this logic. + U32 pos[2][2] = { {0,0},{0,0} }; + from_region_handle(mRegionp->getHandle(), &pos[0][0], &pos[0][1]); + from_region_handle(neighborp->getRegion()->getHandle(), &pos[1][0], &pos[1][1]); + S32 width[2] = { (S32)mRegionp->getWidth(), (S32)neighborp->getRegion()->getWidth() }; + U32 mins[2] = { llmax(pos[0][0], pos[1][0]), llmax(pos[0][1], pos[1][1]) }; + U32 maxs[2] = { llmin(pos[0][0] + width[0], pos[1][0] + width[1]), llmin(pos[0][1] + width[0], pos[1][1] + width[1]) }; + S32 start[2][2] = { + {S32((mins[0] - pos[0][0]) / mGridsPerPatchEdge) - 1, S32((mins[1] - pos[0][1]) / mGridsPerPatchEdge) - 1}, + {S32((mins[0] - pos[1][0]) / neighborp->mGridsPerPatchEdge) - 1,S32((mins[1] - pos[1][1]) / neighborp->mGridsPerPatchEdge) - 1} + }; + + S32 end[2] = { llmin(S32((maxs[0] - pos[0][0]) / mGridsPerPatchEdge), max_idx), llmin(S32((maxs[1] - pos[0][1]) / mGridsPerPatchEdge), max_idx) }; + const U32& neighbor_direction = gDirOpposite[direction]; + S32 stride[4][4][2] = { + {{0, 1}, {max_idx, 0}, {neighbor_max_idx, 0}, {NORTHEAST, SOUTHEAST}}, //EAST + {{1, 0}, {0, max_idx}, {0, neighbor_max_idx}, {NORTHEAST, NORTHWEST} }, //NORTH + {{0, 1}, {0, 0}, {0, 0}, {NORTHWEST, SOUTHWEST}}, //WEST + {{1, 0}, {0, 0}, {0, 0}, {SOUTHEAST, SOUTHWEST}} //SOUTH + }; + const S32 offs[2][2] = { + {stride[direction][0][0], stride[direction][0][1]}, + {stride[neighbor_direction][0][0], stride[neighbor_direction][0][1]} + }; + + S32 x[2], y[2]; + x[0] = stride[direction][1][0] + offs[0][0] * start[0][0]; + y[0] = stride[direction][1][1] + offs[0][1] * start[0][1]; + x[1] = stride[neighbor_direction][2][0] + offs[1][0] * start[1][0]; + y[1] = stride[neighbor_direction][2][1] + offs[1][1] * start[1][1]; + + for ( + x[0] = stride[direction][1][0] + offs[0][0] * start[0][0], + y[0] = stride[direction][1][1] + offs[0][1] * start[0][1], + x[1] = stride[neighbor_direction][2][0] + offs[1][0] * start[1][0], + y[1] = stride[neighbor_direction][2][1] + offs[1][1] * start[1][1]; + (!offs[0][0] || x[0] <= end[0]) && (!offs[0][1] || (y[0] <= end[1])); + x[0] += offs[0][0], y[0] += offs[0][1], + x[1] += offs[1][0], y[1] += offs[1][1]) { - patchp = getPatch(0, i); - neighbor_patchp = neighborp->getPatch(mPatchesPerEdge - 1, i + 1); - - patchp->connectNeighbor(neighbor_patchp, NORTHWEST); - neighbor_patchp->connectNeighbor(patchp, SOUTHEAST); + if (x[0] < 0 || y[0] < 0) { + continue; + } + surface_patch_ref patchp = getPatch(x[0], y[0]); + // diagonal stitch 1 + if ((offs[1][0] > 0 && x[1] > 0) || (offs[1][1] > 0 && y[1] > 0)) + { + patchp->connectNeighbor(neighborp->getPatch(x[1] - offs[1][0], y[1] - offs[1][1]), stride[direction][3][1]); + } + // edge stitch + if (x[1] >= 0 && y[1] >= 0 && x[1] <= neighbor_max_idx && y[1] <= neighbor_max_idx) + { + patchp->connectNeighbor(neighborp->getPatch(x[1], y[1]), direction); + } + // diagonal stitch 2 + if (x[1] + offs[1][0] <= neighbor_max_idx && y[1] + offs[1][1] <= neighbor_max_idx) + { + patchp->connectNeighbor(neighborp->getPatch(x[1] + offs[1][0], y[1] + offs[1][1]), stride[direction][3][0]); + } + if (direction == EAST) + { + patchp->updateEastEdge(); + if (patchp->dirtyZ()) + { + dirtySurfacePatch(patchp); + } + } + else if (direction == NORTH) + { + patchp->updateNorthEdge(); + if (patchp->dirtyZ()) + { + dirtySurfacePatch(patchp); + } + } } } - else if (SOUTH == direction) - { - // Do north/south connections, first - for (i = 0; i < mPatchesPerEdge; i++) - { - patchp = getPatch(i, 0); - neighbor_patchp = neighborp->getPatch(i, mPatchesPerEdge - 1); - - patchp->connectNeighbor(neighbor_patchp, direction); - neighbor_patchp->connectNeighbor(patchp, gDirOpposite[direction]); - - neighbor_patchp->updateNorthEdge(); - neighbor_patchp->dirtyZ(); - } - - // Now do northeast/southwest connections - for (i = 1; i < mPatchesPerEdge; i++) - { - patchp = getPatch(i, 0); - neighbor_patchp = neighborp->getPatch(i - 1, mPatchesPerEdge - 1); - - patchp->connectNeighbor(neighbor_patchp, SOUTHWEST); - neighbor_patchp->connectNeighbor(patchp, NORTHEAST); - } - // Now do northeast/southwest connections - for (i = 0; i < mPatchesPerEdge - 1; i++) - { - patchp = getPatch(i, 0); - neighbor_patchp = neighborp->getPatch(i + 1, mPatchesPerEdge - 1); - - patchp->connectNeighbor(neighbor_patchp, SOUTHEAST); - neighbor_patchp->connectNeighbor(patchp, NORTHWEST); - } - } } -void LLSurface::disconnectNeighbor(LLSurface *surfacep) +void LLSurface::disconnectNeighbor(LLSurface* surfacep, U32 direction) { - S32 i; - for (i = 0; i < 8; i++) + if (surfacep && surfacep == mNeighbors[direction]) { - if (surfacep == mNeighbors[i]) + mNeighbors[direction] = NULL; + for (auto& patchp : mPatchList) { - mNeighbors[i] = NULL; + patchp->disconnectNeighbor(surfacep); } } - - // Iterate through surface patches, removing any connectivity to removed surface. - for (i = 0; i < mNumberOfPatches; i++) - { - (mPatchList + i)->disconnectNeighbor(surfacep); - } } void LLSurface::disconnectAllNeighbors() { - S32 i; - for (i = 0; i < 8; i++) + for (size_t i = 0; i < mNeighbors.size(); ++i) { - if (mNeighbors[i]) + auto& neighbor = mNeighbors[i]; + if (neighbor) { - mNeighbors[i]->disconnectNeighbor(this); - mNeighbors[i] = NULL; + neighbor->disconnectNeighbor(this, gDirOpposite[i]); + neighbor = NULL; } } } @@ -629,13 +566,9 @@ void LLSurface::updatePatchVisibilities(LLAgent &agent) LLVector3 pos_region = mRegionp->getPosRegionFromGlobal(gAgentCamera.getCameraPositionGlobal()); - LLSurfacePatch *patchp; - mVisiblePatchCount = 0; - for (S32 i=0; iupdateVisibility(); if (patchp->getVisible()) { @@ -659,19 +592,29 @@ BOOL LLSurface::idleUpdate(F32 max_update_time) // If the Z height data has changed, we need to rebuild our // property line vertex arrays. - if (mDirtyPatchList.size() > 0) + if (!mDirtyPatchList.empty()) { getRegion()->dirtyHeights(); } // Always call updateNormals() / updateVerticalStats() // every frame to avoid artifacts - for(std::set::iterator iter = mDirtyPatchList.begin(); - iter != mDirtyPatchList.end(); ) + for (auto it = mDirtyPatchList.cbegin(); it != mDirtyPatchList.cend();) { - std::set::iterator curiter = iter++; - LLSurfacePatch *patchp = *curiter; - patchp->updateNormals(); + if (it->second.expired()) + { + LL_WARNS() << "Expired dirty patch detected. Side " << it->first << LL_ENDL; + } + surface_patch_ref patchp = it->second.lock(); + if (!patchp) + { + it = mDirtyPatchList.erase(it); + continue; + } + if (patchp->updateNormals()) + { + patchp->getSurface()->dirtySurfacePatch(patchp); + } patchp->updateVerticalStats(); if (max_update_time == 0.f || update_timer.getElapsedTimeF32() < max_update_time) { @@ -679,9 +622,11 @@ BOOL LLSurface::idleUpdate(F32 max_update_time) { did_update = TRUE; patchp->clearDirty(); - mDirtyPatchList.erase(curiter); + it = mDirtyPatchList.erase(it); + continue; } } + ++it; } return did_update; } @@ -692,7 +637,6 @@ void LLSurface::decompressDCTPatch(LLBitPack &bitpack, LLGroupHeader *gopp, BOOL LLPatchHeader ph; S32 j, i; S32 patch[LARGE_PATCH_SIZE*LARGE_PATCH_SIZE]; - LLSurfacePatch *patchp; init_patch_decompressor(gopp->patch_size); gopp->stride = mGridsPerEdge; @@ -700,18 +644,33 @@ void LLSurface::decompressDCTPatch(LLBitPack &bitpack, LLGroupHeader *gopp, BOOL while (1) { - decode_patch_header(bitpack, &ph); +// Aurora Sim + //decode_patch_header(bitpack, &ph); + decode_patch_header(bitpack, &ph, b_large_patch); +// Aurora Sim if (ph.quant_wbits == END_OF_PATCHES) { break; } - i = ph.patchids >> 5; - j = ph.patchids & 0x1F; +// Aurora Sim + //i = ph.patchids >> 5; + //j = ph.patchids & 0x1F; + if (b_large_patch) + { + i = ph.patchids >> 16; //x + j = ph.patchids & 0xFFFF; //y + } + else + { + i = ph.patchids >> 5; //x + j = ph.patchids & 0x1F; //y + } +// Aurora Sim if ((i >= mPatchesPerEdge) || (j >= mPatchesPerEdge)) { - llwarns << "Received invalid terrain packet - patch header patch ID incorrect!" + LL_WARNS() << "Received invalid terrain packet - patch header patch ID incorrect!" << " patches per edge " << mPatchesPerEdge << " i " << i << " j " << j @@ -719,13 +678,12 @@ void LLSurface::decompressDCTPatch(LLBitPack &bitpack, LLGroupHeader *gopp, BOOL << " range " << (S32)ph.range << " quant_wbits " << (S32)ph.quant_wbits << " patchids " << (S32)ph.patchids - << llendl; + << LL_ENDL; LLAppViewer::instance()->badNetworkHandler(); return; } - patchp = &mPatchList[j*mPatchesPerEdge + i]; - + const surface_patch_ref& patchp = mPatchList[j * mPatchesPerEdge + i]; decode_patch(bitpack, patch); decompress_patch(patchp->getDataZ(), patch, &ph); @@ -733,22 +691,26 @@ void LLSurface::decompressDCTPatch(LLBitPack &bitpack, LLGroupHeader *gopp, BOOL // Update edges for neighbors. Need to guarantee that this gets done before we generate vertical stats. patchp->updateNorthEdge(); patchp->updateEastEdge(); - if (patchp->getNeighborPatch(WEST)) + LLSurfacePatch* neighborPatch; + if (neighborPatch = patchp->getNeighborPatch(WEST)) { - patchp->getNeighborPatch(WEST)->updateEastEdge(); + neighborPatch->updateEastEdge(); } - if (patchp->getNeighborPatch(SOUTHWEST)) + if (neighborPatch = patchp->getNeighborPatch(SOUTHWEST)) { - patchp->getNeighborPatch(SOUTHWEST)->updateEastEdge(); - patchp->getNeighborPatch(SOUTHWEST)->updateNorthEdge(); + neighborPatch->updateEastEdge(); + neighborPatch->updateNorthEdge(); } - if (patchp->getNeighborPatch(SOUTH)) + if (neighborPatch = patchp->getNeighborPatch(SOUTH)) { - patchp->getNeighborPatch(SOUTH)->updateNorthEdge(); + neighborPatch->updateNorthEdge(); } // Dirty patch statistics, and flag that the patch has data. - patchp->dirtyZ(); + if (patchp->dirtyZ()) + { + dirtySurfacePatch(patchp); + } patchp->setHasReceivedData(); } } @@ -901,8 +863,13 @@ LLVector3 LLSurface::resolveNormalGlobal(const LLVector3d& pos_global) const } -LLSurfacePatch *LLSurface::resolvePatchRegion(const F32 x, const F32 y) const +const surface_patch_ref& LLSurface::resolvePatchRegion(const F32 x, const F32 y) const { + if (mPatchList.empty()) { + LL_WARNS() << "No patches for current region!" << LL_ENDL; + static surface_patch_ref empty; + return empty; + } // x and y should be region-local coordinates. // If x and y are outside of the surface, then the returned // index will be for the nearest boundary patch. @@ -953,29 +920,24 @@ LLSurfacePatch *LLSurface::resolvePatchRegion(const F32 x, const F32 y) const // *NOTE: Super paranoia code follows. S32 index = i + j * mPatchesPerEdge; - if((index < 0) || (index >= mNumberOfPatches)) + if((index < 0) || (index >= mPatchList.size())) { - if(0 == mNumberOfPatches) - { - llwarns << "No patches for current region!" << llendl; - return NULL; - } S32 old_index = index; - index = llclamp(old_index, 0, (mNumberOfPatches - 1)); - llwarns << "Clamping out of range patch index " << old_index - << " to " << index << llendl; + index = llclamp(old_index, 0, ((S32)mPatchList.size() - 1)); + LL_WARNS() << "Clamping out of range patch index " << old_index + << " to " << index << LL_ENDL; } - return &(mPatchList[index]); + return mPatchList[index]; } -LLSurfacePatch *LLSurface::resolvePatchRegion(const LLVector3 &pos_region) const +const surface_patch_ref& LLSurface::resolvePatchRegion(const LLVector3 &pos_region) const { return resolvePatchRegion(pos_region.mV[VX], pos_region.mV[VY]); } -LLSurfacePatch *LLSurface::resolvePatchGlobal(const LLVector3d &pos_global) const +const surface_patch_ref& LLSurface::resolvePatchGlobal(const LLVector3d &pos_global) const { llassert(mRegionp); LLVector3 pos_region = mRegionp->getPosRegionFromGlobal(pos_global); @@ -1004,37 +966,28 @@ void LLSurface::createPatchData() // Assumes mGridsPerEdge, mGridsPerPatchEdge, and mPatchesPerEdge have been properly set // TODO -- check for create() called when surface is not empty S32 i, j; - LLSurfacePatch *patchp; // Allocate memory - mPatchList = new LLSurfacePatch[mNumberOfPatches]; - - // One of each for each camera - mVisiblePatchCount = mNumberOfPatches; - - for (j=0; jsetSurface(this); - } + mPatchList[i] = std::make_shared(this, i); } + // One of each for each camera + mVisiblePatchCount = mPatchList.size(); + for (j=0; jmHasReceivedData = FALSE; - patchp->mSTexUpdate = TRUE; + const auto& patchp = getPatch(i, j); S32 data_offset = i * mGridsPerPatchEdge + j * mGridsPerPatchEdge * mGridsPerEdge; patchp->setDataZ(mSurfaceZ + data_offset); patchp->setDataNorm(mNorm + data_offset); - // We make each patch point to its neighbors so we can do resolution checking // when butting up different resolutions. Patches that don't have neighbors // somewhere will point to NULL on that side. @@ -1123,9 +1076,7 @@ void LLSurface::createPatchData() void LLSurface::destroyPatchData() { // Delete all of the cached patch data for these patches. - - delete [] mPatchList; - mPatchList = NULL; + mPatchList.clear(); mVisiblePatchCount = 0; } @@ -1148,36 +1099,50 @@ U32 LLSurface::getRenderStride(const U32 render_level) const } -LLSurfacePatch *LLSurface::getPatch(const S32 x, const S32 y) const +const surface_patch_ref& LLSurface::getPatch(const S32 x, const S32 y) const { + static surface_patch_ref empty(nullptr); if ((x < 0) || (x >= mPatchesPerEdge)) { - llerrs << "Asking for patch out of bounds" << llendl; - return NULL; + LL_WARNS() << "Asking for patch out of bounds" << LL_ENDL; + return empty; } if ((y < 0) || (y >= mPatchesPerEdge)) { - llerrs << "Asking for patch out of bounds" << llendl; - return NULL; + LL_WARNS() << "Asking for patch out of bounds" << LL_ENDL; + return empty; } - return mPatchList + x + y*mPatchesPerEdge; + return mPatchList[x + y*mPatchesPerEdge]; } void LLSurface::dirtyAllPatches() { - S32 i; - for (i = 0; i < mNumberOfPatches; i++) + for (auto& patchp : mPatchList) { - mPatchList[i].dirtyZ(); + if (patchp->dirtyZ()) + { + dirtySurfacePatch(patchp); + } } } -void LLSurface::dirtySurfacePatch(LLSurfacePatch *patchp) +void LLSurface::dirtySurfacePatch(const surface_patch_ref& patchp) { + if (!patchp) + { + return; + } + // Put surface patch on dirty surface patch list - mDirtyPatchList.insert(patchp); + if (std::find_if(mDirtyPatchList.begin(), mDirtyPatchList.end(), + [&patchp](std::pair >& entry) -> bool { + return entry.second.lock().get() == patchp.get(); + }) == mDirtyPatchList.end()) + { + mDirtyPatchList.push_back(std::make_pair(patchp->getSide(), patchp)); + } } @@ -1196,7 +1161,7 @@ void LLSurface::setWaterHeight(F32 height) } else { - llwarns << "LLSurface::setWaterHeight with no water object!" << llendl; + LL_WARNS() << "LLSurface::setWaterHeight with no water object!" << LL_ENDL; } } @@ -1229,15 +1194,18 @@ BOOL LLSurface::generateWaterTexture(const F32 x, const F32 y, LLPointer raw = new LLImageRaw(tex_width, tex_height, tex_comps); U8 *rawp = raw->getData(); - F32 scale = 256.f * getMetersPerGrid() / (F32)tex_width; +// Aurora Sim + //F32 scale = 256.f * getMetersPerGrid() / (F32)tex_width; + F32 scale = getRegion()->getWidth() * getMetersPerGrid() / (F32)tex_width; +// Aurora Sim F32 scale_inv = 1.f / scale; S32 x_begin, y_begin, x_end, y_end; - x_begin = llround(x * scale_inv); - y_begin = llround(y * scale_inv); - x_end = llround((x + width) * scale_inv); - y_end = llround((y + width) * scale_inv); + x_begin = ll_round(x * scale_inv); + y_begin = ll_round(y * scale_inv); + x_end = ll_round((x + width) * scale_inv); + y_end = ll_round((y + width) * scale_inv); if (x_end > tex_width) { @@ -1285,9 +1253,9 @@ BOOL LLSurface::generateWaterTexture(const F32 x, const F32 y, // Want non-linear curve for transparency gradient coloru = MAX_WATER_COLOR; const F32 frac = 1.f - 2.f/(2.f - (height - WATER_HEIGHT)); - S32 alpha = 64 + llround((255-64)*frac); + S32 alpha = 64 + ll_round((255-64)*frac); - alpha = llmin(llround((F32)MAX_WATER_COLOR.mV[3]), alpha); + alpha = llmin(ll_round((F32)MAX_WATER_COLOR.mV[3]), alpha); alpha = llmax(64, alpha); coloru.mV[3] = alpha; diff --git a/indra/newview/llsurface.h b/indra/newview/llsurface.h index a693f69439..abc7785ad3 100644 --- a/indra/newview/llsurface.h +++ b/indra/newview/llsurface.h @@ -60,9 +60,12 @@ static const S32 ONE_LESS_THAN_NEIGHBOR = -1; const S32 ABOVE_WATERLINE_ALPHA = 32; // The alpha of water when the land elevation is above the waterline. class LLViewerRegion; -class LLSurfacePatch; class LLBitPack; class LLGroupHeader; +class LLSurfacePatch; + +typedef std::shared_ptr surface_patch_ref; +typedef std::weak_ptr surface_patch_weak_ref; class LLSurface { @@ -82,9 +85,12 @@ class LLSurface void setOriginGlobal(const LLVector3d &origin_global); void connectNeighbor(LLSurface *neighborp, U32 direction); - void disconnectNeighbor(LLSurface *neighborp); + void disconnectNeighbor(LLSurface *neighborp, U32 direction); void disconnectAllNeighbors(); +// Aurora Sim + void rebuildWater(); +// Aurora Sim virtual void decompressDCTPatch(LLBitPack &bitpack, LLGroupHeader *gopp, BOOL b_large_patch); virtual void updatePatchVisibilities(LLAgent &agent); @@ -108,9 +114,9 @@ class LLSurface F32 resolveHeightGlobal(const LLVector3d &position_global) const; LLVector3 resolveNormalGlobal(const LLVector3d& v) const; // Returns normal to surface - LLSurfacePatch *resolvePatchRegion(const F32 x, const F32 y) const; - LLSurfacePatch *resolvePatchRegion(const LLVector3 &position_region) const; - LLSurfacePatch *resolvePatchGlobal(const LLVector3d &position_global) const; + const surface_patch_ref& resolvePatchRegion(const F32 x, const F32 y) const; + const surface_patch_ref& resolvePatchRegion(const LLVector3 &position_region) const; + const surface_patch_ref& resolvePatchGlobal(const LLVector3d &position_global) const; // Update methods (called during idle, normally) BOOL idleUpdate(F32 max_update_time); @@ -133,7 +139,7 @@ class LLSurface void dirtyAllPatches(); // Use this to dirty all patches when changing terrain parameters - void dirtySurfacePatch(LLSurfacePatch *patchp); + void dirtySurfacePatch(const surface_patch_ref& patchp); LLVOWater *getWaterObj() { return mWaterObjp; } static void setTextureSize(const S32 texture_size); @@ -152,8 +158,6 @@ class LLSurface F32 mOOGridsPerEdge; // Inverse of grids per edge S32 mPatchesPerEdge; // Number of patches on one side of a region - S32 mNumberOfPatches; // Total number of patches - // Each surface points at 8 neighbors (or NULL) // +---+---+---+ @@ -163,7 +167,7 @@ class LLSurface // +---+---+---+ // |SW | S | SE| // +---+---+---+ - LLSurface *mNeighbors[8]; // Adjacent patches + std::array mNeighbors; // Adjacent patches U32 mType; // Useful for identifying derived classes @@ -188,11 +192,11 @@ class LLSurface //F32 updateTexture(LLSurfacePatch *ppatch); - LLSurfacePatch *getPatch(const S32 x, const S32 y) const; + const surface_patch_ref& getPatch(const S32 x, const S32 y) const; protected: LLVector3d mOriginGlobal; // In absolute frame - LLSurfacePatch *mPatchList; // Array of all patches + std::vector< surface_patch_ref > mPatchList; // Array of all patches // Array of grid data, mGridsPerEdge * mGridsPerEdge F32 *mSurfaceZ; @@ -200,7 +204,7 @@ class LLSurface // Array of grid normals, mGridsPerEdge * mGridsPerEdge LLVector3 *mNorm; - std::set mDirtyPatchList; + std::vector< std::pair > mDirtyPatchList; // The textures should never be directly initialized - use the setter methods! diff --git a/indra/newview/llsurfacepatch.cpp b/indra/newview/llsurfacepatch.cpp index 3ebea883c8..c999fff22f 100644 --- a/indra/newview/llsurfacepatch.cpp +++ b/indra/newview/llsurfacepatch.cpp @@ -41,15 +41,15 @@ #include "llviewerregion.h" #include "llvlcomposition.h" #include "lldrawpool.h" -#include "noise.h" +#include "llperlin.h" extern bool gShiftFrame; -extern U64 gFrameTime; +extern U64MicrosecondsImplicit gFrameTime; extern LLPipeline gPipeline; -LLSurfacePatch::LLSurfacePatch() : - mHasReceivedData(FALSE), - mSTexUpdate(FALSE), +LLSurfacePatch::LLSurfacePatch(LLSurface* surface, U32 side) +: mHasReceivedData(FALSE), + mSTexUpdate(TRUE), mDirty(FALSE), mDirtyZStats(TRUE), mHeightsGenerated(FALSE), @@ -70,17 +70,12 @@ LLSurfacePatch::LLSurfacePatch() : // set to non-zero values by higher classes. mConnectedEdge(NO_EDGE), mLastUpdateTime(0), - mSurfacep(NULL) -{ - S32 i; - for (i = 0; i < 8; i++) - { - setNeighborPatch(i, NULL); - } - for (i = 0; i < 9; i++) - { - mNormalsInvalid[i] = TRUE; - } + mSurfacep(NULL), + mNeighborPatches{ 0,0,0,0,0,0,0,0 }, + mNormalsInvalid{ 1,1,1,1,1,1,1,1,1 }, + mSide(side) +{ + setSurface(surface); } @@ -90,7 +85,7 @@ LLSurfacePatch::~LLSurfacePatch() } -void LLSurfacePatch::dirty() +bool LLSurfacePatch::dirty() { // These are outside of the loop in case we're still waiting for a dirty from the // texture being updated... @@ -100,7 +95,7 @@ void LLSurfacePatch::dirty() } else { - llwarns << "No viewer object for this surface patch!" << llendl; + LL_WARNS() << "No viewer object for this surface patch!" << LL_ENDL; } mDirtyZStats = TRUE; @@ -109,8 +104,9 @@ void LLSurfacePatch::dirty() if (!mDirty) { mDirty = TRUE; - mSurfacep->dirtySurfacePatch(this); + return true; } + return false; } @@ -133,45 +129,31 @@ void LLSurfacePatch::disconnectNeighbor(LLSurface *surfacep) U32 i; for (i = 0; i < 8; i++) { - if (getNeighborPatch(i)) + const auto& patch = getNeighborPatch(i); + if (patch) { - if (getNeighborPatch(i)->mSurfacep == surfacep) + if (patch->mSurfacep == surfacep) { + if (EAST == i) + { + mConnectedEdge &= EAST_EDGE; + } + else if (NORTH == i) + { + mConnectedEdge &= NORTH_EDGE; + } + else if (WEST == i) + { + mConnectedEdge &= WEST_EDGE; + } + else if (SOUTH == i) + { + mConnectedEdge &= SOUTH_EDGE; + } setNeighborPatch(i, NULL); - mNormalsInvalid[i] = TRUE; } } } - - // Clean up connected edges - if (getNeighborPatch(EAST)) - { - if (getNeighborPatch(EAST)->mSurfacep == surfacep) - { - mConnectedEdge &= ~EAST_EDGE; - } - } - if (getNeighborPatch(NORTH)) - { - if (getNeighborPatch(NORTH)->mSurfacep == surfacep) - { - mConnectedEdge &= ~NORTH_EDGE; - } - } - if (getNeighborPatch(WEST)) - { - if (getNeighborPatch(WEST)->mSurfacep == surfacep) - { - mConnectedEdge &= ~WEST_EDGE; - } - } - if (getNeighborPatch(SOUTH)) - { - if (getNeighborPatch(SOUTH)->mSurfacep == surfacep) - { - mConnectedEdge &= ~SOUTH_EDGE; - } - } } LLVector3 LLSurfacePatch::getPointAgent(const U32 x, const U32 y) const @@ -230,12 +212,11 @@ void LLSurfacePatch::eval(const U32 x, const U32 y, const U32 stride, LLVector3 const F32 xyScale = 4.9215f*7.f; //0.93284f; const F32 xyScaleInv = (1.f / xyScale)*(0.2222222222f); - F32 vec[3] = { - (F32)fmod((F32)(mOriginGlobal.mdV[0] + x)*xyScaleInv, 256.f), - (F32)fmod((F32)(mOriginGlobal.mdV[1] + y)*xyScaleInv, 256.f), - 0.f - }; - F32 rand_val = llclamp(noise2(vec)* 0.75f + 0.5f, 0.f, 1.f); + LLVector2 vec( + (F32)fmod((F32)(mOriginGlobal.mdV[0] + x)*xyScaleInv, 256.f), // Added (F32) for proper array initialization + (F32)fmod((F32)(mOriginGlobal.mdV[1] + y)*xyScaleInv, 256.f) // Added (F32) for proper array initialization + ); + F32 rand_val = llclamp(LLPerlinNoise::noise(vec)* 0.75f + 0.5f, 0.f, 1.f); tex1->mV[1] = rand_val; @@ -249,18 +230,26 @@ void LLSurfacePatch::calcNormal(const U32 x, const U32 y, const U32 stride) const F32 mpg = mSurfacep->getMetersPerGrid() * stride; - S32 poffsets[2][2][2]; +// Aurora Sim +// Singu Note: poffsets gets an extra space each for surface stride (tag clutter removed) + //S32 poffsets[2][2][2]; + S32 poffsets[2][2][3]; poffsets[0][0][0] = x - stride; poffsets[0][0][1] = y - stride; + poffsets[0][0][2] = surface_stride; poffsets[0][1][0] = x - stride; poffsets[0][1][1] = y + stride; + poffsets[0][1][2] = surface_stride; poffsets[1][0][0] = x + stride; poffsets[1][0][1] = y - stride; + poffsets[1][0][2] = surface_stride; poffsets[1][1][0] = x + stride; poffsets[1][1][1] = y + stride; + poffsets[1][1][2] = surface_stride; +// Aurora Sim const LLSurfacePatch *ppatches[2][2]; @@ -276,52 +265,65 @@ void LLSurfacePatch::calcNormal(const U32 x, const U32 y, const U32 stride) { for (j = 0; j < 2; j++) { + LLSurfacePatch* patch; if (poffsets[i][j][0] < 0) { - if (!ppatches[i][j]->getNeighborPatch(WEST)) + if (patch = ppatches[i][j]->getNeighborPatch(WEST)) { - poffsets[i][j][0] = 0; + // Aurora Sim + ppatches[i][j] = patch; + poffsets[i][j][0] += patch_width; + poffsets[i][j][2] = patch->getSurface()->getGridsPerEdge(); +// Aurora Sim } else { - poffsets[i][j][0] += patch_width; - ppatches[i][j] = ppatches[i][j]->getNeighborPatch(WEST); + poffsets[i][j][0] = 0; } } if (poffsets[i][j][1] < 0) { - if (!ppatches[i][j]->getNeighborPatch(SOUTH)) + if (patch = ppatches[i][j]->getNeighborPatch(SOUTH)) { - poffsets[i][j][1] = 0; +// Aurora Sim + ppatches[i][j] = patch; + poffsets[i][j][1] += patch_width; + poffsets[i][j][2] = patch->getSurface()->getGridsPerEdge(); +// CR> Aurora Sim } else { - poffsets[i][j][1] += patch_width; - ppatches[i][j] = ppatches[i][j]->getNeighborPatch(SOUTH); + poffsets[i][j][1] = 0; } } if (poffsets[i][j][0] >= (S32)patch_width) { - if (!ppatches[i][j]->getNeighborPatch(EAST)) + if (patch = ppatches[i][j]->getNeighborPatch(EAST)) { - poffsets[i][j][0] = patch_width - 1; +// Aurora Sim + ppatches[i][j] = patch; + poffsets[i][j][0] -= patch_width; + poffsets[i][j][2] = patch->getSurface()->getGridsPerEdge(); +// Aurora Sim } else { - poffsets[i][j][0] -= patch_width; - ppatches[i][j] = ppatches[i][j]->getNeighborPatch(EAST); + poffsets[i][j][0] = patch_width - 1; } } if (poffsets[i][j][1] >= (S32)patch_width) { - if (!ppatches[i][j]->getNeighborPatch(NORTH)) + if (patch = ppatches[i][j]->getNeighborPatch(NORTH)) { - poffsets[i][j][1] = patch_width - 1; +// Aurora Sim + ppatches[i][j] = patch; + poffsets[i][j][1] -= patch_width; + poffsets[i][j][2] = patch->getSurface()->getGridsPerEdge(); +// Aurora Sim } else { - poffsets[i][j][1] -= patch_width; - ppatches[i][j] = ppatches[i][j]->getNeighborPatch(NORTH); + poffsets[i][j][1] = patch_width - 1; } } } @@ -330,19 +332,22 @@ void LLSurfacePatch::calcNormal(const U32 x, const U32 y, const U32 stride) LLVector3 p00(-mpg,-mpg, *(ppatches[0][0]->mDataZ + poffsets[0][0][0] - + poffsets[0][0][1]*surface_stride)); +// Aurora Sim +// Singu Note: multiply the y poffsets by its own surface stride (tag clutter removed) + + poffsets[0][0][1]*poffsets[0][0][2])); LLVector3 p01(-mpg,+mpg, *(ppatches[0][1]->mDataZ + poffsets[0][1][0] - + poffsets[0][1][1]*surface_stride)); + + poffsets[0][1][1]*poffsets[0][1][2])); LLVector3 p10(+mpg,-mpg, *(ppatches[1][0]->mDataZ + poffsets[1][0][0] - + poffsets[1][0][1]*surface_stride)); + + poffsets[1][0][1]*poffsets[1][0][2])); LLVector3 p11(+mpg,+mpg, *(ppatches[1][1]->mDataZ + poffsets[1][1][0] - + poffsets[1][1][1]*surface_stride)); + + poffsets[1][1][1]*poffsets[1][1][2])); +// Aurora Sim LLVector3 c1 = p11 - p00; LLVector3 c2 = p01 - p10; @@ -452,11 +457,11 @@ void LLSurfacePatch::updateVerticalStats() } -void LLSurfacePatch::updateNormals() +bool LLSurfacePatch::updateNormals() { if (mSurfacep->mType == 'w') { - return; + return false; } U32 grids_per_patch_edge = mSurfacep->getGridsPerPatchEdge(); U32 grids_per_edge = mSurfacep->getGridsPerEdge(); @@ -493,6 +498,15 @@ void LLSurfacePatch::updateNormals() // update the west edge if (mNormalsInvalid[NORTHWEST] || mNormalsInvalid[WEST] || mNormalsInvalid[SOUTHWEST]) { + LLSurfacePatch* northwest_patchp = getNeighborPatch(NORTHWEST); + LLSurfacePatch* north_patchp = getNeighborPatch(NORTH); +// Aurora Sim + if (!north_patchp && northwest_patchp && northwest_patchp->getHasReceivedData()) + { + *(mDataZ + grids_per_patch_edge*grids_per_edge) = *(northwest_patchp->mDataZ + grids_per_patch_edge); + } +// Aurora Sim + for (j = 0; j < grids_per_patch_edge; j++) { calcNormal(0, j, 2); @@ -504,6 +518,15 @@ void LLSurfacePatch::updateNormals() // update the south edge if (mNormalsInvalid[SOUTHWEST] || mNormalsInvalid[SOUTH] || mNormalsInvalid[SOUTHEAST]) { + LLSurfacePatch* southeast_patchp = getNeighborPatch(SOUTHEAST); + LLSurfacePatch* east_patchp = getNeighborPatch(EAST); +// Aurora Sim + if (!east_patchp && southeast_patchp && southeast_patchp->getHasReceivedData()) + { + *(mDataZ + grids_per_patch_edge) = *(southeast_patchp->mDataZ + grids_per_patch_edge * southeast_patchp->getSurface()->getGridsPerEdge()); + } +// Aurora Sim + for (i = 0; i < grids_per_patch_edge; i++) { calcNormal(i, 0, 2); @@ -516,11 +539,14 @@ void LLSurfacePatch::updateNormals() // we'll want to do different things. if (mNormalsInvalid[NORTHEAST]) { - if (!getNeighborPatch(NORTHEAST)) + LLSurfacePatch* northeast_patchp = getNeighborPatch(NORTHEAST); + LLSurfacePatch* north_patchp = getNeighborPatch(NORTH); + LLSurfacePatch* east_patchp = getNeighborPatch(EAST); + if (!northeast_patchp) { - if (!getNeighborPatch(NORTH)) + if (!north_patchp) { - if (!getNeighborPatch(EAST)) + if (!east_patchp) { // No north or east neighbors. Pull from the diagonal in your own patch. *(mDataZ + grids_per_patch_edge + grids_per_patch_edge*grids_per_edge) = @@ -528,11 +554,14 @@ void LLSurfacePatch::updateNormals() } else { - if (getNeighborPatch(EAST)->getHasReceivedData()) + if (east_patchp->getHasReceivedData()) { // East, but not north. Pull from your east neighbor's northwest point. *(mDataZ + grids_per_patch_edge + grids_per_patch_edge*grids_per_edge) = - *(getNeighborPatch(EAST)->mDataZ + (grids_per_patch_edge - 1)*grids_per_edge); +// Aurora Sim + //*(getNeighborPatch(EAST)->mDataZ + (grids_per_patch_edge - 1)*grids_per_edge); + *(east_patchp->mDataZ + (east_patchp->getSurface()->getGridsPerPatchEdge() - 1)* east_patchp->getSurface()->getGridsPerEdge()); +// Aurora Sim } else { @@ -544,7 +573,7 @@ void LLSurfacePatch::updateNormals() else { // We have a north. - if (getNeighborPatch(EAST)) + if (east_patchp) { // North and east neighbors, but not northeast. // Pull from diagonal in your own patch. @@ -553,11 +582,14 @@ void LLSurfacePatch::updateNormals() } else { - if (getNeighborPatch(NORTH)->getHasReceivedData()) + if (north_patchp->getHasReceivedData()) { // North, but not east. Pull from your north neighbor's southeast corner. *(mDataZ + grids_per_patch_edge + grids_per_patch_edge*grids_per_edge) = - *(getNeighborPatch(NORTH)->mDataZ + (grids_per_patch_edge - 1)); +// Aurora Sim + //*(getNeighborPatch(NORTH)->mDataZ + (grids_per_patch_edge - 1)); + *(north_patchp->mDataZ + (north_patchp->getSurface()->getGridsPerPatchEdge() - 1)); +// Aurora Sim } else { @@ -567,15 +599,26 @@ void LLSurfacePatch::updateNormals() } } } - else if (getNeighborPatch(NORTHEAST)->mSurfacep != mSurfacep) + else if (northeast_patchp->mSurfacep != mSurfacep) { if ( - (!getNeighborPatch(NORTH) || (getNeighborPatch(NORTH)->mSurfacep != mSurfacep)) + (!north_patchp || (north_patchp->mSurfacep != mSurfacep)) && - (!getNeighborPatch(EAST) || (getNeighborPatch(EAST)->mSurfacep != mSurfacep))) + (!east_patchp || (east_patchp->mSurfacep != mSurfacep))) { +// Aurora Sim + U32 own_xpos, own_ypos, neighbor_xpos, neighbor_ypos; + S32 own_offset = 0, neighbor_offset = 0; + from_region_handle(mSurfacep->getRegion()->getHandle(), &own_xpos, &own_ypos); + from_region_handle(northeast_patchp->mSurfacep->getRegion()->getHandle(), &neighbor_xpos, &neighbor_ypos); + if (own_ypos >= neighbor_ypos) + neighbor_offset = own_ypos - neighbor_ypos; + else + own_offset = neighbor_ypos - own_ypos; + *(mDataZ + grids_per_patch_edge + grids_per_patch_edge*grids_per_edge) = - *(getNeighborPatch(NORTHEAST)->mDataZ); + *(northeast_patchp->mDataZ + (grids_per_edge + neighbor_offset - own_offset - 1) * northeast_patchp->getSurface()->getGridsPerEdge()); +// Aurora Sim } } else @@ -603,23 +646,24 @@ void LLSurfacePatch::updateNormals() dirty_patch = TRUE; } - if (dirty_patch) - { - mSurfacep->dirtySurfacePatch(this); - } - for (i = 0; i < 9; i++) { mNormalsInvalid[i] = FALSE; } + + return dirty_patch; } void LLSurfacePatch::updateEastEdge() { U32 grids_per_patch_edge = mSurfacep->getGridsPerPatchEdge(); U32 grids_per_edge = mSurfacep->getGridsPerEdge(); +// Aurora Sim + U32 grids_per_edge_east = grids_per_edge; - U32 j, k; + //U32 j, k; + U32 j, k, h; +// Aurora Sim F32 *west_surface, *east_surface; if (!getNeighborPatch(EAST)) @@ -631,6 +675,9 @@ void LLSurfacePatch::updateEastEdge() { west_surface = mDataZ + grids_per_patch_edge; east_surface = getNeighborPatch(EAST)->mDataZ; +// Aurora Sim + grids_per_edge_east = getNeighborPatch(EAST)->getSurface()->getGridsPerEdge(); +// Aurora Sim } else { @@ -642,7 +689,11 @@ void LLSurfacePatch::updateEastEdge() for (j=0; j < grids_per_patch_edge; j++) { k = j * grids_per_edge; - *(west_surface + k) = *(east_surface + k); // update buffer Z +// Aurora Sim + h = j * grids_per_edge_east; + *(west_surface + k) = *(east_surface + h); // update buffer Z + //*(west_surface + k) = *(east_surface + k); // update buffer Z +// Aurora Sim } } @@ -655,7 +706,8 @@ void LLSurfacePatch::updateNorthEdge() U32 i; F32 *south_surface, *north_surface; - if (!getNeighborPatch(NORTH)) + LLSurfacePatch* patchp = getNeighborPatch(NORTH); + if (!patchp) { south_surface = mDataZ + grids_per_patch_edge*grids_per_edge; north_surface = mDataZ + (grids_per_patch_edge - 1) * grids_per_edge; @@ -663,7 +715,7 @@ void LLSurfacePatch::updateNorthEdge() else if (mConnectedEdge & NORTH_EDGE) { south_surface = mDataZ + grids_per_patch_edge*grids_per_edge; - north_surface = getNeighborPatch(NORTH)->mDataZ; + north_surface = patchp->mDataZ; } else { @@ -671,13 +723,12 @@ void LLSurfacePatch::updateNorthEdge() } // Update patchp's north edge ... - for (i=0; igetMetersPerGrid(); F32 grids_per_patch_edge = (F32)getSurface()->getGridsPerPatchEdge(); - if ((!getNeighborPatch(EAST) || getNeighborPatch(EAST)->getHasReceivedData()) - && (!getNeighborPatch(WEST) || getNeighborPatch(WEST)->getHasReceivedData()) - && (!getNeighborPatch(SOUTH) || getNeighborPatch(SOUTH)->getHasReceivedData()) - && (!getNeighborPatch(NORTH) || getNeighborPatch(NORTH)->getHasReceivedData())) + LLSurfacePatch* patchp; + if ((!(patchp = getNeighborPatch(EAST)) || patchp->getHasReceivedData()) + && (!(patchp = getNeighborPatch(WEST)) || patchp->getHasReceivedData()) + && (!(patchp = getNeighborPatch(SOUTH)) || patchp->getHasReceivedData()) + && (!(patchp = getNeighborPatch(NORTH)) || patchp->getHasReceivedData())) { LLViewerRegion *regionp = getSurface()->getRegion(); LLVector3d origin_region = getOriginGlobal() - getSurface()->getOriginGlobal(); @@ -750,7 +802,7 @@ void LLSurfacePatch::updateGL() } } -void LLSurfacePatch::dirtyZ() +bool LLSurfacePatch::dirtyZ() { mSTexUpdate = TRUE; @@ -764,20 +816,36 @@ void LLSurfacePatch::dirtyZ() // Invalidate normals in this and neighboring patches for (i = 0; i < 8; i++) { - if (getNeighborPatch(i)) + if (mNeighborPatches[i] == nullptr) + { + continue; + } + if (mNeighborPatches[i]->expired()) + { + LL_WARNS() << "Expired neighbor patch detected. Side " << i << LL_ENDL; + delete mNeighborPatches[i]; + mNeighborPatches[i] = nullptr; + continue; + } + const surface_patch_ref& patchp = mNeighborPatches[i]->lock(); + if (patchp) { - getNeighborPatch(i)->mNormalsInvalid[gDirOpposite[i]] = TRUE; - getNeighborPatch(i)->dirty(); + patchp->mNormalsInvalid[gDirOpposite[i]] = TRUE; + if (patchp->dirty()) + { + patchp->getSurface()->dirtySurfacePatch(patchp); + } if (i < 4) { - getNeighborPatch(i)->mNormalsInvalid[gDirAdjacent[gDirOpposite[i]][0]] = TRUE; - getNeighborPatch(i)->mNormalsInvalid[gDirAdjacent[gDirOpposite[i]][1]] = TRUE; + patchp->mNormalsInvalid[gDirAdjacent[gDirOpposite[i]][0]] = TRUE; + patchp->mNormalsInvalid[gDirAdjacent[gDirOpposite[i]][1]] = TRUE; } } } - dirty(); mLastUpdateTime = gFrameTime; + + return dirty(); } @@ -814,34 +882,29 @@ void LLSurfacePatch::setOriginGlobal(const LLVector3d &origin_global) } -void LLSurfacePatch::connectNeighbor(LLSurfacePatch *neighbor_patchp, const U32 direction) +void LLSurfacePatch::connectNeighbor(const surface_patch_ref& neighbor_patchp, const U32 direction) { llassert(neighbor_patchp); + if (!neighbor_patchp) return; mNormalsInvalid[direction] = TRUE; - neighbor_patchp->mNormalsInvalid[gDirOpposite[direction]] = TRUE; setNeighborPatch(direction, neighbor_patchp); - neighbor_patchp->setNeighborPatch(gDirOpposite[direction], this); if (EAST == direction) { mConnectedEdge |= EAST_EDGE; - neighbor_patchp->mConnectedEdge |= WEST_EDGE; } else if (NORTH == direction) { mConnectedEdge |= NORTH_EDGE; - neighbor_patchp->mConnectedEdge |= SOUTH_EDGE; } else if (WEST == direction) { mConnectedEdge |= WEST_EDGE; - neighbor_patchp->mConnectedEdge |= EAST_EDGE; } else if (SOUTH == direction) { mConnectedEdge |= SOUTH_EDGE; - neighbor_patchp->mConnectedEdge |= NORTH_EDGE; } } @@ -899,13 +962,14 @@ void LLSurfacePatch::updateVisibility() if (mVObjp) { mVObjp->dirtyGeom(); - if (getNeighborPatch(WEST)) + LLSurfacePatch* patchp; + if (patchp = getNeighborPatch(WEST)) { - getNeighborPatch(WEST)->mVObjp->dirtyGeom(); + patchp->mVObjp->dirtyGeom(); } - if (getNeighborPatch(SOUTH)) + if (patchp = getNeighborPatch(SOUTH)) { - getNeighborPatch(SOUTH)->mVObjp->dirtyGeom(); + patchp->mVObjp->dirtyGeom(); } } } @@ -1010,9 +1074,21 @@ F32 LLSurfacePatch::getMaxComposition() const return mMaxComposition; } -void LLSurfacePatch::setNeighborPatch(const U32 direction, LLSurfacePatch *neighborp) +void LLSurfacePatch::setNeighborPatch(const U32 direction, const surface_patch_ref& neighborp) { - mNeighborPatches[direction] = neighborp; + if (!neighborp) + { + delete mNeighborPatches[direction]; + mNeighborPatches[direction] = nullptr; + } + else + { + if (mNeighborPatches[direction] == nullptr) + { + mNeighborPatches[direction] = new surface_patch_weak_ref(); + } + *mNeighborPatches[direction] = neighborp; + } mNormalsInvalid[direction] = TRUE; if (direction < 4) { @@ -1023,7 +1099,15 @@ void LLSurfacePatch::setNeighborPatch(const U32 direction, LLSurfacePatch *neigh LLSurfacePatch *LLSurfacePatch::getNeighborPatch(const U32 direction) const { - return mNeighborPatches[direction]; + if (mNeighborPatches[direction] == nullptr) + { + return nullptr; + } + else if (mNeighborPatches[direction]->expired()) + { + LL_WARNS() << "Expired neighbor patch detected. Side " << direction << LL_ENDL; + } + return mNeighborPatches[direction]->lock().get(); } void LLSurfacePatch::clearVObj() diff --git a/indra/newview/llsurfacepatch.h b/indra/newview/llsurfacepatch.h index ebfb64c1d8..8d6447e7f9 100644 --- a/indra/newview/llsurfacepatch.h +++ b/indra/newview/llsurfacepatch.h @@ -43,6 +43,10 @@ class LLVector2; class LLColor4U; class LLAgent; +class LLSurfacePatch; +typedef std::shared_ptr surface_patch_ref; +typedef std::weak_ptr surface_patch_weak_ref; + // A patch shouldn't know about its visibility since that really depends on the // camera that is looking (or not looking) at it. So, anything about a patch // that is specific to a camera should be in the class below. @@ -64,26 +68,23 @@ class LLPatchVisibilityInfo -class LLSurfacePatch +class LLSurfacePatch { public: - LLSurfacePatch(); + LLSurfacePatch(LLSurface* surface, U32 side); ~LLSurfacePatch(); - void reset(const U32 id); - void connectNeighbor(LLSurfacePatch *neighborp, const U32 direction); + void connectNeighbor(const surface_patch_ref& neighbor_patchp, const U32 direction); void disconnectNeighbor(LLSurface *surfacep); - void setNeighborPatch(const U32 direction, LLSurfacePatch *neighborp); + void setNeighborPatch(const U32 direction, const surface_patch_ref& neighborp); LLSurfacePatch *getNeighborPatch(const U32 direction) const; - void colorPatch(const U8 r, const U8 g, const U8 b); - BOOL updateTexture(); void updateVerticalStats(); void updateCompositionStats(); - void updateNormals(); + bool updateNormals(); void updateEastEdge(); void updateNorthEdge(); @@ -92,7 +93,7 @@ class LLSurfacePatch void updateVisibility(); void updateGL(); - void dirtyZ(); // Dirty the z values of this patch + bool dirtyZ(); // Dirty the z values of this patch void setHasReceivedData(); BOOL getHasReceivedData() const; @@ -139,17 +140,19 @@ class LLSurfacePatch void setDataNorm(LLVector3 *data_norm) { mDataNorm = data_norm; } F32 *getDataZ() const { return mDataZ; } - void dirty(); // Mark this surface patch as dirty... + bool dirty(); // Mark this surface patch as dirty... void clearDirty() { mDirty = FALSE; } void clearVObj(); + U32 getSide() const { return mSide; } + public: BOOL mHasReceivedData; // has the patch EVER received height data? BOOL mSTexUpdate; // Does the surface texture need to be updated? protected: - LLSurfacePatch *mNeighborPatches[8]; // Adjacent patches + std::weak_ptr* mNeighborPatches[8]; // Adjacent patches BOOL mNormalsInvalid[9]; // Which normals are invalid BOOL mDirty; @@ -184,6 +187,8 @@ class LLSurfacePatch // of LLSurface that is "connected" to another LLSurface U64 mLastUpdateTime; // Time patch was last updated + U32 mSide; // Side relative to parent surface. + LLSurface *mSurfacep; // Pointer to "parent" surface }; diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp index 051c3e4c81..077b6a8c7c 100644 --- a/indra/newview/lltexturecache.cpp +++ b/indra/newview/lltexturecache.cpp @@ -51,6 +51,8 @@ const S32 TEXTURE_CACHE_ENTRY_SIZE = FIRST_PACKET_SIZE;//1024; const F32 TEXTURE_CACHE_PURGE_AMOUNT = .20f; // % amount to reduce the cache by when it exceeds its limit const F32 TEXTURE_CACHE_LRU_SIZE = .10f; // % amount for LRU list (low overhead to regenerate) +static std::queue sgDelayedPurgeQueue; + class LLTextureCacheWorker : public LLWorkerClass { friend class LLTextureCache; @@ -189,7 +191,7 @@ bool LLTextureCacheLocalFileWorker::doRead() if (mImageFormat == IMG_CODEC_INVALID) { -// llwarns << "Unrecognized file extension " << extension << " for local texture " << mFileName << llendl; +// LL_WARNS() << "Unrecognized file extension " << extension << " for local texture " << mFileName << LL_ENDL; mDataSize = 0; // no data return true; } @@ -230,9 +232,9 @@ bool LLTextureCacheLocalFileWorker::doRead() { if (mBytesRead != mBytesToRead) { -// llwarns << "Error reading file from local cache: " << local_filename +// LL_WARNS() << "Error reading file from local cache: " << local_filename // << " Bytes: " << mDataSize << " Offset: " << mOffset -// << " / " << mDataSize << llendl; +// << " / " << mDataSize << LL_ENDL; mDataSize = 0; // failed FREE_MEM(LLImageBase::getPrivatePool(), mReadData); mReadData = NULL; @@ -255,9 +257,9 @@ bool LLTextureCacheLocalFileWorker::doRead() if (bytes_read != mDataSize) { -// llwarns << "Error reading file from local cache: " << mFileName +// LL_WARNS() << "Error reading file from local cache: " << mFileName // << " Bytes: " << mDataSize << " Offset: " << mOffset -// << " / " << mDataSize << llendl; +// << " / " << mDataSize << LL_ENDL; mDataSize = 0; FREE_MEM(LLImageBase::getPrivatePool(), mReadData); mReadData = NULL; @@ -373,25 +375,25 @@ bool LLTextureCacheRemoteWorker::doRead() if (!done && (mState == LOCAL)) { llassert(local_size != 0); // we're assuming there is a non empty local file here... - if (!mDataSize || mDataSize > local_size - mOffset) + if (!mDataSize || mDataSize > local_size/* - mOffset*/) { - mDataSize = local_size - mOffset; + mDataSize = local_size/* - mOffset*/; } // Allocate read buffer mReadData = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), mDataSize); S32 bytes_read = LLAPRFile::readEx(local_filename, mReadData, mOffset, mDataSize); if (bytes_read != mDataSize) { - llwarns << "Error reading file from local cache: " << local_filename + LL_WARNS() << "Error reading file from local cache: " << local_filename << " Bytes: " << mDataSize << " Offset: " << mOffset - << " / " << mDataSize << llendl; + << " / " << mDataSize << LL_ENDL; mDataSize = 0; FREE_MEM(LLImageBase::getPrivatePool(), mReadData); mReadData = NULL; } else { - //llinfos << "texture " << mID.asString() << " found in local_assets" << llendl; + //LL_INFOS() << "texture " << mID.asString() << " found in local_assets" << LL_ENDL; mImageSize = local_size; mImageLocal = TRUE; } @@ -433,9 +435,9 @@ bool LLTextureCacheRemoteWorker::doRead() S32 bytes_read = LLAPRFile::readEx(mCache->mHeaderDataFileName, mReadData, offset, size); if (bytes_read != size) { - llwarns << "LLTextureCacheWorker: " << mID + LL_WARNS() << "LLTextureCacheWorker: " << mID << " incorrect number of bytes read from header: " << bytes_read - << " / " << size << llendl; + << " / " << size << LL_ENDL; FREE_MEM(LLImageBase::getPrivatePool(), mReadData); mReadData = NULL; mDataSize = -1; // failed @@ -503,7 +505,7 @@ bool LLTextureCacheRemoteWorker::doRead() { LL_DEBUGS("TextureCache") << "LLTextureCacheWorker: " << mID << " incorrect number of bytes read from body: " << bytes_read - << " / " << file_size << llendl; + << " / " << file_size << LL_ENDL; FREE_MEM(LLImageBase::getPrivatePool(), mReadData); mReadData = NULL; mDataSize = -1; // failed @@ -514,7 +516,7 @@ bool LLTextureCacheRemoteWorker::doRead() { // No body, we're done. mDataSize = llmax(TEXTURE_CACHE_ENTRY_SIZE - mOffset, 0); - lldebugs << "No body file for: " << filename << llendl; + LL_DEBUGS() << "No body file for: " << filename << LL_ENDL; } // Nothing else to do at that point... done = true; @@ -564,8 +566,8 @@ bool LLTextureCacheRemoteWorker::doWrite() if (idx < 0) { - llwarns << "LLTextureCacheWorker: " << mID - << " Unable to create header entry for writing!" << llendl; + LL_WARNS() << "LLTextureCacheWorker: " << mID + << " Unable to create header entry for writing!" << LL_ENDL; mDataSize = -1; // failed done = true; } @@ -610,8 +612,8 @@ bool LLTextureCacheRemoteWorker::doWrite() if (bytes_written <= 0) { - llwarns << "LLTextureCacheWorker: " << mID - << " Unable to write header entry!" << llendl; + LL_WARNS() << "LLTextureCacheWorker: " << mID + << " Unable to write header entry!" << LL_ENDL; mDataSize = -1; // failed done = true; } @@ -637,15 +639,15 @@ bool LLTextureCacheRemoteWorker::doWrite() { // build the cache file name from the UUID std::string filename = mCache->getTextureFileName(mID); -// llinfos << "Writing Body: " << filename << " Bytes: " << file_offset+file_size << llendl; +// LL_INFOS() << "Writing Body: " << filename << " Bytes: " << file_offset+file_size << LL_ENDL; S32 bytes_written = LLAPRFile::writeEx( filename, mWriteData + TEXTURE_CACHE_ENTRY_SIZE, 0, file_size); if (bytes_written <= 0) { - llwarns << "LLTextureCacheWorker: " << mID + LL_WARNS() << "LLTextureCacheWorker: " << mID << " incorrect number of bytes written to body: " << bytes_written - << " / " << file_size << llendl; + << " / " << file_size << LL_ENDL; mDataSize = -1; // failed done = true; } @@ -929,17 +931,17 @@ void LLTextureCache::setReadOnly(BOOL read_only) } //called in the main thread. -S64 LLTextureCache::initCache(ELLPath location, S64 max_size, BOOL texture_cache_mismatch) +U64 LLTextureCache::initCache(ELLPath location, U64 max_size, BOOL texture_cache_mismatch) { llassert_always(getPending() == 0); //should not start accessing the texture cache before initialized. - S64 header_size = (max_size * 2) / 10; - S64 max_entries = header_size / TEXTURE_CACHE_ENTRY_SIZE; - sCacheMaxEntries = (S32)(llmin((S64)sCacheMaxEntries, max_entries)); + U64 header_size = (max_size * 2) / 10; + U32 max_entries = header_size / TEXTURE_CACHE_ENTRY_SIZE; + sCacheMaxEntries = (llmin(sCacheMaxEntries, max_entries)); header_size = sCacheMaxEntries * TEXTURE_CACHE_ENTRY_SIZE; max_size -= header_size; if (sCacheMaxTexturesSize > 0) - sCacheMaxTexturesSize = llmin(sCacheMaxTexturesSize, max_size); + sCacheMaxTexturesSize = (U32)llmin((U64)sCacheMaxTexturesSize, max_size); else sCacheMaxTexturesSize = max_size; max_size -= sCacheMaxTexturesSize; @@ -1062,9 +1064,9 @@ S32 LLTextureCache::openAndReadEntry(const LLUUID& id, Entry& entry, bool create else { // Look for a still valid entry in the LRU - for (std::set::iterator iter2 = mLRU.begin(); iter2 != mLRU.end();) + for (auto iter2 = mLRU.begin(); iter2 != mLRU.end();) { - std::set::iterator curiter2 = iter2++; + auto curiter2 = iter2++; LLUUID oldid = *curiter2; // Erase entry from LRU regardless mLRU.erase(curiter2); @@ -1105,7 +1107,7 @@ S32 LLTextureCache::openAndReadEntry(const LLUUID& id, Entry& entry, bool create } if(entry.mImageSize <= entry.mBodySize)//it happens on 64-bit systems, do not know why { - llwarns << "corrupted entry: " << id << " entry image size: " << entry.mImageSize << " entry body size: " << entry.mBodySize << llendl; + LL_WARNS() << "corrupted entry: " << id << " entry image size: " << entry.mImageSize << " entry body size: " << entry.mBodySize << LL_ENDL; //erase this entry and the cached texture from the cache. std::string tex_filename = getTextureFileName(id); @@ -1273,13 +1275,13 @@ U32 LLTextureCache::openAndReadEntries(std::vector& entries) S32 bytes_read = aprfile->read((void*)(&entry), (S32)sizeof(Entry)); if (bytes_read < sizeof(Entry)) { - llwarns << "Corrupted header entries, failed at " << idx << " / " << num_entries << llendl; + LL_WARNS() << "Corrupted header entries, failed at " << idx << " / " << num_entries << LL_ENDL; closeHeaderEntriesFile(); purgeAllTextures(false); return 0; } entries.push_back(entry); -// llinfos << "ENTRY: " << entry.mTime << " TEX: " << entry.mID << " IDX: " << idx << " Size: " << entry.mImageSize << llendl; +// LL_INFOS() << "ENTRY: " << entry.mTime << " TEX: " << entry.mID << " IDX: " << idx << " Size: " << entry.mImageSize << LL_ENDL; if(entry.mImageSize > entry.mBodySize) { mHeaderIDMap[entry.mID] = idx; @@ -1303,14 +1305,12 @@ void LLTextureCache::writeEntriesAndClose(const std::vector& entries) if (!mReadOnly) { LLAPRFile* aprfile = openHeaderEntriesFile(false, (S32)sizeof(EntriesInfo)); - for (S32 idx=0; idxwrite((void*)(entries.data()), write_size); + if (bytes_written != write_size) { - S32 bytes_written = aprfile->write((void*)(&entries[idx]), (S32)sizeof(Entry)); - if(bytes_written != sizeof(Entry)) - { - clearCorruptedCache(); //clear the cache. - return; - } + clearCorruptedCache(); //clear the cache. + return; } closeHeaderEntriesFile(); } @@ -1409,7 +1409,7 @@ void LLTextureCache::readHeaderCache() if (entry.mBodySize > entry.mImageSize) { // Shouldn't happen, failsafe only - llwarns << "Bad entry: " << i << ": " << entry.mID << ": BodySize: " << entry.mBodySize << llendl; + LL_WARNS() << "Bad entry: " << i << ": " << entry.mID << ": BodySize: " << entry.mBodySize << LL_ENDL; purge_list.insert(i); } } @@ -1420,7 +1420,7 @@ void LLTextureCache::readHeaderCache() // Special case: cache size was reduced, need to remove entries // Note: After we prune entries, we will call this again and create the LRU U32 entries_to_purge = (num_entries - empty_entries) - sCacheMaxEntries; - llinfos << "Texture Cache Entries: " << num_entries << " Max: " << sCacheMaxEntries << " Empty: " << empty_entries << " Purging: " << entries_to_purge << llendl; + LL_INFOS() << "Texture Cache Entries: " << num_entries << " Max: " << sCacheMaxEntries << " Empty: " << empty_entries << " Purging: " << entries_to_purge << LL_ENDL; // We can exit the following loop with the given condition, since if we'd reach the end of the lru set we'd have: // purge_list.size() = lru.size() = num_entries - empty_entries = entries_to_purge + sCacheMaxEntries >= entries_to_purge // So, it's certain that iter will never reach lru.end() first. @@ -1437,7 +1437,7 @@ void LLTextureCache::readHeaderCache() for (std::set::iterator iter = lru.begin(); iter != lru.end(); ++iter) { mLRU.insert(entries[iter->second].mID); -// llinfos << "LRU: " << iter->first << " : " << iter->second << llendl; +// LL_INFOS() << "LRU: " << iter->first << " : " << iter->second << LL_ENDL; if (--lru_entries <= 0) break; } @@ -1483,7 +1483,7 @@ void LLTextureCache::readHeaderCache() //the header mutex is locked before calling this. void LLTextureCache::clearCorruptedCache() { - llwarns << "the texture cache is corrupted, need to be cleared." << llendl; + LL_WARNS() << "the texture cache is corrupted, need to be cleared." << LL_ENDL; closeHeaderEntriesFile();//close possible file handler purgeAllTextures(false); //clear the cache. @@ -1513,7 +1513,7 @@ void LLTextureCache::purgeAllTextures(bool purge_directories) for (S32 i=0; i<16; i++) { std::string dirname = mTexturesDirName + delem + subdirs[i]; - llinfos << "Deleting files in directory: " << dirname << llendl; + LL_INFOS() << "Deleting files in directory: " << dirname << LL_ENDL; gDirUtilp->deleteFilesInDir(dirname, mask); if (purge_directories) { @@ -1538,7 +1538,21 @@ void LLTextureCache::purgeAllTextures(bool purge_directories) mHeaderEntriesInfo.mEntries = 0; writeEntriesHeader(); - llinfos << "The entire texture cache is cleared." << llendl; + LL_INFOS() << "The entire texture cache is cleared." << LL_ENDL; +} + +void LLTextureCache::performDelayedPurge() +{ + LLMutexLock lock(&mHeaderMutex); + while(!sgDelayedPurgeQueue.empty()) + { + removeFromCache(sgDelayedPurgeQueue.front()); + sgDelayedPurgeQueue.pop(); + if (mTexturesSizeTotal < sCacheMaxTexturesSize) + { + break; + } + } } void LLTextureCache::purgeTextures(bool validate) @@ -1556,7 +1570,10 @@ void LLTextureCache::purgeTextures(bool validate) LLMutexLock lock(&mHeaderMutex); - llinfos << "TEXTURE CACHE: Purging." << llendl; + LL_INFOS() << "TEXTURE CACHE: Purging." << LL_ENDL; + + std::queue empty; + std::swap(sgDelayedPurgeQueue, empty); // Read the entries list std::vector entries; @@ -1567,8 +1584,8 @@ void LLTextureCache::purgeTextures(bool validate) } // Use mTexturesSizeMap to collect UUIDs of textures with bodies - typedef std::set > time_idx_set_t; - std::set > time_idx_set; + typedef std::vector > time_idx_set_t; + time_idx_set_t time_idx_set; for (size_map_t::iterator iter1 = mTexturesSizeMap.begin(); iter1 != mTexturesSizeMap.end(); ++iter1) { @@ -1578,15 +1595,17 @@ void LLTextureCache::purgeTextures(bool validate) if (iter2 != mHeaderIDMap.end()) { S32 idx = iter2->second; - time_idx_set.insert(std::make_pair(entries[idx].mTime, idx)); -// llinfos << "TIME: " << entries[idx].mTime << " TEX: " << entries[idx].mID << " IDX: " << idx << " Size: " << entries[idx].mImageSize << llendl; + time_idx_set.push_back(std::make_pair(entries[idx].mTime, idx)); +// LL_INFOS() << "TIME: " << entries[idx].mTime << " TEX: " << entries[idx].mID << " IDX: " << idx << " Size: " << entries[idx].mImageSize << LL_ENDL; } else { - llerrs << "mTexturesSizeMap / mHeaderIDMap corrupted." << llendl ; + LL_ERRS() << "mTexturesSizeMap / mHeaderIDMap corrupted." << LL_ENDL ; } } } + + std::sort(time_idx_set.begin(), time_idx_set.end()); // Validate 1/256th of the files on startup U32 validate_idx = 0; @@ -1637,7 +1656,14 @@ void LLTextureCache::purgeTextures(bool validate) purge_count++; LL_DEBUGS("TextureCache") << "PURGING: " << filename << LL_ENDL; cache_size -= entries[idx].mBodySize; - removeEntry(idx, entries[idx], filename) ; + if(validate) + { + removeEntry(idx, entries[idx], filename); + } + else + { + sgDelayedPurgeQueue.push(entries[idx].mID); + } } } @@ -1652,7 +1678,7 @@ void LLTextureCache::purgeTextures(bool validate) << " PURGED: " << purge_count << " ENTRIES: " << num_entries << " CACHE SIZE: " << mTexturesSizeTotal / (1024 * 1024) << " MB" - << llendl; + << LL_ENDL; } ////////////////////////////////////////////////////////////////////////////// @@ -1791,7 +1817,7 @@ LLTextureCache::handle_t LLTextureCache::writeToCache(const LLUUID& id, U32 prio delete responder; return LLWorkerThread::nullHandle(); } - if (mDoPurge) + if (sgDelayedPurgeQueue.empty() && mDoPurge) { // NOTE: This may cause an occasional hiccup, // but it really needs to be done on the control thread @@ -1799,6 +1825,7 @@ LLTextureCache::handle_t LLTextureCache::writeToCache(const LLUUID& id, U32 prio purgeTextures(false); mDoPurge = FALSE; } + performDelayedPurge(); LLMutexLock lock(&mWorkersMutex); LLTextureCacheWorker* worker = new LLTextureCacheRemoteWorker(this, priority, id, data, datasize, 0, @@ -1891,7 +1918,7 @@ void LLTextureCache::removeEntry(S32 idx, Entry& entry, std::string& filename) bool LLTextureCache::removeFromCache(const LLUUID& id) { - //llwarns << "Removing texture from cache: " << id << llendl; + //LL_WARNS() << "Removing texture from cache: " << id << LL_ENDL; bool ret = false; if (!mReadOnly) { diff --git a/indra/newview/lltexturecache.h b/indra/newview/lltexturecache.h index ac6ac0227b..49b2eabc24 100644 --- a/indra/newview/lltexturecache.h +++ b/indra/newview/lltexturecache.h @@ -105,7 +105,7 @@ class LLTextureCache : public LLWorkerThread void purgeCache(ELLPath location); void setReadOnly(BOOL read_only) ; - S64 initCache(ELLPath location, S64 maxsize, BOOL texture_cache_mismatch); + U64 initCache(ELLPath location, U64 maxsize, BOOL texture_cache_mismatch); handle_t readFromCache(const std::string& local_filename, const LLUUID& id, U32 priority, S32 offset, S32 size, ReadResponder* responder); @@ -129,8 +129,8 @@ class LLTextureCache : public LLWorkerThread // debug S32 getNumReads() { return mReaders.size(); } S32 getNumWrites() { return mWriters.size(); } - S64 getUsage() { return mTexturesSizeTotal; } - S64 getMaxUsage() { return sCacheMaxTexturesSize; } + S64Bytes getUsage() { return S64Bytes(mTexturesSizeTotal); } + S64Bytes getMaxUsage() { return S64Bytes(sCacheMaxTexturesSize); } U32 getEntries() { return mHeaderEntriesInfo.mEntries; } U32 getMaxEntries() { return sCacheMaxEntries; }; BOOL isInCache(const LLUUID& id) ; @@ -146,6 +146,7 @@ class LLTextureCache : public LLWorkerThread void setDirNames(ELLPath location); void readHeaderCache(); void clearCorruptedCache(); + void performDelayedPurge(); void purgeAllTextures(bool purge_directories); void purgeTextures(bool validate); LLAPRFile* openHeaderEntriesFile(bool readonly, S32 offset); @@ -192,7 +193,7 @@ class LLTextureCache : public LLWorkerThread std::string mHeaderDataFileName; EntriesInfo mHeaderEntriesInfo; std::set mFreeList; // deleted entries - std::set mLRU; + uuid_set_t mLRU; typedef std::map id_map_t; id_map_t mHeaderIDMap; @@ -201,7 +202,7 @@ class LLTextureCache : public LLWorkerThread typedef std::map size_map_t; size_map_t mTexturesSizeMap; S64 mTexturesSizeTotal; - LLAtomic32 mDoPurge; + LLAtomic32 mDoPurge; typedef std::map idx_entry_map_t; idx_entry_map_t mUpdatedEntryMap; diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index ca53a8f6c7..192f2bc9f2 100644 --- a/indra/newview/lltexturectrl.cpp +++ b/indra/newview/lltexturectrl.cpp @@ -60,14 +60,16 @@ #include "llscrollcontainer.h" #include "lltoolmgr.h" #include "lltoolpipette.h" - -#include "lltool.h" +#include "llglheaders.h" +#include "llselectmgr.h" +#include "lltrans.h" +#include "lluictrlfactory.h" #include "llviewerwindow.h" #include "llviewerobject.h" #include "llviewercontrol.h" -#include "llglheaders.h" -#include "lluictrlfactory.h" -#include "lltrans.h" + +#include "llavatarappearancedefines.h" + // #include "llmenugl.h" // @@ -141,6 +143,8 @@ class LLFloaterTexturePicker : public LLFloater // New functions void setImageID( const LLUUID& image_asset_id); + const LLUUID& getWhiteImageAssetID() const { return mWhiteImageAssetID; } + void setWhiteImageAssetID(const LLUUID& id) { mWhiteImageAssetID = id; } void updateImageStats(); const LLUUID& getAssetID() { return mImageAssetID; } const LLUUID& findItemID(const LLUUID& asset_id, BOOL copyable_only); @@ -158,6 +162,9 @@ class LLFloaterTexturePicker : public LLFloater void updateFilterPermMask(); void commitIfImmediateSet(); + void setCanApply(bool can_preview, bool can_apply); + void setTextureSelectedCallback(texture_selected_callback cb) {mTextureSelectedCallback = cb;} + static void onBtnSetToDefault( void* userdata ); static void onBtnSelect( void* userdata ); static void onBtnCancel( void* userdata ); @@ -172,6 +179,7 @@ class LLFloaterTexturePicker : public LLFloater void onSelectionChange(const std::deque &items, BOOL user_action); static void onShowFolders(LLUICtrl* ctrl, void* userdata); static void onApplyImmediateCheck(LLUICtrl* ctrl, void* userdata); + void onBakeTextureSelect(const LLSD& val); void onFilterEdit(const std::string& filter_string ); void onTextureSelect( const LLTextureEntry& te ); @@ -217,9 +225,13 @@ class LLFloaterTexturePicker : public LLFloater BOOL mCanApplyImmediately; BOOL mNoCopyTextureSelected; F32 mContextConeOpacity; - LLSaveFolderState mSavedFolderState; BOOL mSelectedItemPinned; LLScrollListCtrl* mLocalScrollCtrl; // tag: vaa emerald local_asset_browser + +private: + bool mCanApply; + bool mCanPreview; + texture_selected_callback mTextureSelectedCallback; }; LLFloaterTexturePicker::LLFloaterTexturePicker( @@ -254,15 +266,15 @@ LLFloaterTexturePicker::LLFloaterTexturePicker( mDnDFilterPermMask(dnd_filter_perm_mask), mNonImmediateFilterPermMask(non_immediate_filter_perm_mask), mContextConeOpacity(0.f), - mSelectedItemPinned(FALSE) + mSelectedItemPinned(FALSE), + mCanApply(true), + mCanPreview(true) { mCanApplyImmediately = can_apply_immediately; LLUICtrlFactory::getInstance()->buildFloater(this,"floater_texture_ctrl.xml"); setCanMinimize(FALSE); - - mSavedFolderState.setApply(FALSE); } LLFloaterTexturePicker::~LLFloaterTexturePicker() @@ -276,22 +288,42 @@ void LLFloaterTexturePicker::setImageID(const LLUUID& image_id) mNoCopyTextureSelected = FALSE; mIsDirty = TRUE; mImageAssetID = image_id; - LLUUID item_id = findItemID(mImageAssetID, FALSE); - if (item_id.isNull()) + + std::string tab; + if (LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::isBakedImageId(mImageAssetID)) + { + tab = "bake"; + getChild("l_bake_use_texture_combo_box")->selectByID(mImageAssetID); + } + /* TODO: Figure out how to select local asset if in use? + // tag: vaa emerald local_asset_browser [begin] + else if (mLocalScrollCtrl->selectByID(mImageAssetID)) { - mInventoryPanel->clearSelection(); + tab = "local_tab"; } + // tag: vaa emerald local_asset_browser [end] + */ else { - LLInventoryItem* itemp = gInventory.getItem(image_id); - if (itemp && !itemp->getPermissions().allowCopyBy(gAgent.getID())) + LLUUID item_id = findItemID(mImageAssetID, FALSE); + if (item_id.isNull()) { - // no copy texture - getChild("apply_immediate_check")->setValue(FALSE); - mNoCopyTextureSelected = TRUE; + mInventoryPanel->getRootFolder()->clearSelection(); + } + else + { + tab = "server_tab"; + LLInventoryItem* itemp = gInventory.getItem(image_id); + if (itemp && !itemp->getPermissions().allowCopyBy(gAgent.getID())) + { + // no copy texture + getChild("apply_immediate_check")->setValue(FALSE); + mNoCopyTextureSelected = TRUE; + } + mInventoryPanel->setSelection(item_id, TAKE_FOCUS_NO); } - mInventoryPanel->setSelection(item_id, TAKE_FOCUS_NO); } + if (!tab.empty()) getChild("actions_tab_container")->selectTabByName(tab); } } @@ -353,7 +385,9 @@ BOOL LLFloaterTexturePicker::handleDragAndDrop( { BOOL handled = FALSE; - if (cargo_type == DAD_TEXTURE) + bool is_mesh = cargo_type == DAD_MESH; + + if ((cargo_type == DAD_TEXTURE) || is_mesh) { LLInventoryItem *item = (LLInventoryItem *)cargo_data; @@ -373,6 +407,9 @@ BOOL LLFloaterTexturePicker::handleDragAndDrop( { if (drop) { + // FIRE-8298: Apply now checkbox has no effect + setCanApply(true, true); + // setImageID( item->getAssetUUID() ); commitIfImmediateSet(); } @@ -390,7 +427,7 @@ BOOL LLFloaterTexturePicker::handleDragAndDrop( } handled = TRUE; - lldebugst(LLERR_USER_INPUT) << "dragAndDrop handled by LLFloaterTexturePicker " << getName() << llendl; + LL_DEBUGS("UserInput") << "dragAndDrop handled by LLFloaterTexturePicker " << getName() << LL_ENDL; return handled; } @@ -543,6 +580,8 @@ BOOL LLFloaterTexturePicker::postBuild() // update permission filter once UI is fully initialized updateFilterPermMask(); LLToolPipette::getInstance()->setToolSelectCallback(boost::bind(&LLFloaterTexturePicker::onTextureSelect, this, _1)); + + getChild("l_bake_use_texture_combo_box")->setCommitCallback(boost::bind(&LLFloaterTexturePicker::onBakeTextureSelect, this, _2)); return TRUE; } @@ -558,37 +597,29 @@ void LLFloaterTexturePicker::draw() if (gFocusMgr.childHasKeyboardFocus(this) && mOwner->isInVisibleChain() && mContextConeOpacity > 0.001f) { gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - LLGLEnable(GL_CULL_FACE); - gGL.begin(LLRender::QUADS); + LLGLEnable clip; + gGL.begin(LLRender::TRIANGLE_STRIP); { - gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity); - gGL.vertex2i(owner_rect.mLeft, owner_rect.mTop); - gGL.vertex2i(owner_rect.mRight, owner_rect.mTop); - gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity); - gGL.vertex2i(local_rect.mRight, local_rect.mTop); - gGL.vertex2i(local_rect.mLeft, local_rect.mTop); - gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity); gGL.vertex2i(local_rect.mLeft, local_rect.mTop); - gGL.vertex2i(local_rect.mLeft, local_rect.mBottom); gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity); - gGL.vertex2i(owner_rect.mLeft, owner_rect.mBottom); gGL.vertex2i(owner_rect.mLeft, owner_rect.mTop); - gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity); - gGL.vertex2i(local_rect.mRight, local_rect.mBottom); gGL.vertex2i(local_rect.mRight, local_rect.mTop); gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity); gGL.vertex2i(owner_rect.mRight, owner_rect.mTop); - gGL.vertex2i(owner_rect.mRight, owner_rect.mBottom); - - gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity); - gGL.vertex2i(local_rect.mLeft, local_rect.mBottom); gGL.vertex2i(local_rect.mRight, local_rect.mBottom); gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity); gGL.vertex2i(owner_rect.mRight, owner_rect.mBottom); + gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity); + gGL.vertex2i(local_rect.mLeft, local_rect.mBottom); + gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity); gGL.vertex2i(owner_rect.mLeft, owner_rect.mBottom); + gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_OUT_ALPHA * mContextConeOpacity); + gGL.vertex2i(local_rect.mLeft, local_rect.mTop); + gGL.color4f(0.f, 0.f, 0.f, CONTEXT_CONE_IN_ALPHA * mContextConeOpacity); + gGL.vertex2i(owner_rect.mLeft, owner_rect.mTop); } gGL.end(); } @@ -596,18 +627,18 @@ void LLFloaterTexturePicker::draw() if (gFocusMgr.childHasMouseCapture(getDragHandle())) { - mContextConeOpacity = lerp(mContextConeOpacity, gSavedSettings.getF32("PickerContextOpacity"), LLCriticalDamp::getInterpolant(CONTEXT_FADE_TIME)); + mContextConeOpacity = lerp(mContextConeOpacity, gSavedSettings.getF32("PickerContextOpacity"), LLSmoothInterpolation::getInterpolant(CONTEXT_FADE_TIME)); } else { - mContextConeOpacity = lerp(mContextConeOpacity, 0.f, LLCriticalDamp::getInterpolant(CONTEXT_FADE_TIME)); + mContextConeOpacity = lerp(mContextConeOpacity, 0.f, LLSmoothInterpolation::getInterpolant(CONTEXT_FADE_TIME)); } updateImageStats(); // if we're inactive, gray out "apply immediate" checkbox getChildView("show_folders_check")->setEnabled(mActive && mCanApplyImmediately && !mNoCopyTextureSelected); - getChildView("Select")->setEnabled(mActive); + getChildView("Select")->setEnabled(mActive && mCanApply); getChildView("Pipette")->setEnabled(mActive); getChild("Pipette")->setValue(LLToolMgr::getInstance()->getCurrentTool() == LLToolPipette::getInstance()); @@ -617,14 +648,32 @@ void LLFloaterTexturePicker::draw() //BOOL allow_copy = FALSE; if( mOwner ) { - mTexturep = NULL; + mTexturep = nullptr; if(mImageAssetID.notNull()) { - mTexturep = LLViewerTextureManager::getFetchedTexture(mImageAssetID, MIPMAP_YES, LLGLTexture::BOOST_PREVIEW); + LLPointer texture = NULL; + + if (LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::isBakedImageId(mImageAssetID)) + { + LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); + if (obj) + { + LLViewerTexture* viewerTexture = obj->getBakedTextureForMagicId(mImageAssetID); + texture = viewerTexture ? dynamic_cast(viewerTexture) : NULL; + } + } + + if (texture.isNull()) + { + texture = LLViewerTextureManager::getFetchedTexture(mImageAssetID); + } + + mTexturep = texture; + mTexturep->setBoostLevel(LLGLTexture::BOOST_PREVIEW); } else if (!mFallbackImageName.empty()) { - mTexturep = LLViewerTextureManager::getFetchedTextureFromFile(mFallbackImageName, MIPMAP_YES, LLGLTexture::BOOST_PREVIEW); + mTexturep = LLViewerTextureManager::getFetchedTextureFromFile(mFallbackImageName, FTT_LOCAL_FILE, MIPMAP_YES, LLGLTexture::BOOST_PREVIEW); } if (mTentativeLabel) @@ -689,11 +738,10 @@ void LLFloaterTexturePicker::draw() LLFolderView* folder_view = mInventoryPanel->getRootFolder(); if (!folder_view) return; - LLInventoryFilter* filter = folder_view->getFilter(); - if (!filter) return; + LLInventoryFilter& filter = folder_view->getFilter(); - bool is_filter_active = folder_view->getCompletedFilterGeneration() < filter->getCurrentGeneration() && - filter->isNotDefault(); + bool is_filter_active = folder_view->getCompletedFilterGeneration() < filter.getCurrentGeneration() && + filter.isNotDefault(); // After inventory panel filter is applied we have to update // constraint rect for the selected item because of folder view @@ -734,10 +782,10 @@ const LLUUID& LLFloaterTexturePicker::findItemID(const LLUUID& asset_id, BOOL co LLInventoryModel::INCLUDE_TRASH, asset_id_matches); - if (items.count()) + if (items.size()) { // search for copyable version first - for (S32 i = 0; i < items.count(); i++) + for (U32 i = 0; i < items.size(); i++) { LLInventoryItem* itemp = items[i]; LLPermissions item_permissions = itemp->getPermissions(); @@ -768,8 +816,10 @@ PermissionMask LLFloaterTexturePicker::getFilterPermMask() void LLFloaterTexturePicker::commitIfImmediateSet() { - bool apply_immediate = getChild("apply_immediate_check")->getValue().asBoolean(); - if (!mNoCopyTextureSelected && mOwner && apply_immediate) + // FIRE-8298: Apply now checkbox has no effect + //if (!mNoCopyTextureSelected && mOwner && mCanApply) + if (!mNoCopyTextureSelected && mOwner && mCanApply && mCanPreview) + // { mOwner->onFloaterCommit(LLTextureCtrl::TEXTURE_CHANGE); } @@ -779,6 +829,7 @@ void LLFloaterTexturePicker::commitIfImmediateSet() void LLFloaterTexturePicker::onBtnSetToDefault(void* userdata) { LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata; + self->setCanApply(true, true); if (self->mOwner) { self->setImageID( self->mOwner->getDefaultImageAssetID() ); @@ -790,6 +841,7 @@ void LLFloaterTexturePicker::onBtnSetToDefault(void* userdata) void LLFloaterTexturePicker::onBtnWhite(void* userdata) { LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata; + self->setCanApply(true, true); self->setImageID( self->mWhiteImageAssetID ); self->commitIfImmediateSet(); } @@ -798,6 +850,7 @@ void LLFloaterTexturePicker::onBtnWhite(void* userdata) void LLFloaterTexturePicker::onBtnNone(void* userdata) { LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata; + self->setCanApply(true, true); self->setImageID( LLUUID::null ); self->commitIfImmediateSet(); } @@ -806,6 +859,7 @@ void LLFloaterTexturePicker::onBtnNone(void* userdata) void LLFloaterTexturePicker::onBtnInvisible(void* userdata) { LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata; + self->setCanApply(true, true); self->setImageID(self->mInvisibleImageAssetID); self->commitIfImmediateSet(); } @@ -815,6 +869,7 @@ void LLFloaterTexturePicker::onBtnInvisible(void* userdata) void LLFloaterTexturePicker::onBtnAlpha(void* userdata) { LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata; + self->setCanApply(true, true); self->setImageID(self->mAlphaImageAssetID); self->commitIfImmediateSet(); } @@ -909,7 +964,7 @@ void LLFloaterTexturePicker::onBtnBrowser(void *userdata) // reacts to user clicking a valid field in the local scroll list. void LLFloaterTexturePicker::onLocalScrollCommit() { - LLUUID id(mLocalScrollCtrl->getSelectedItemLabel(LOCALLIST_COL_ID)); + LLUUID id(mLocalScrollCtrl->getStringUUIDSelectedItem()); mOwner->setImageAssetID(id); if (childGetValue("apply_immediate_check").asBoolean()) @@ -959,6 +1014,10 @@ void LLFloaterTexturePicker::onSelectionChange(const std::deque if (itemp->getPermissions().getMaskOwner() & PERM_ALL) childSetValue("texture_uuid", mImageAssetID); @@ -970,9 +1029,12 @@ void LLFloaterTexturePicker::onSelectionChange(const std::deque FIRE-8298: Apply now checkbox has no effect + setCanApply(true, true); + // mImageAssetID = itemp->getAssetUUID(); mIsDirty = TRUE; - if (user_action) + if (user_action && mCanPreview) { // only commit intentional selections, not implicit ones commitIfImmediateSet(); @@ -1004,48 +1066,51 @@ void LLFloaterTexturePicker::onApplyImmediateCheck(LLUICtrl* ctrl, void *user_da LLCheckBoxCtrl* check_box = (LLCheckBoxCtrl*)ctrl; gSavedSettings.setBOOL("ApplyTextureImmediately", check_box->get()); - + // FIRE-8298: Apply now checkbox has no effect + picker->setCanApply(true, true); + // picker->updateFilterPermMask(); picker->commitIfImmediateSet(); } +void LLFloaterTexturePicker::onBakeTextureSelect(const LLSD& val) +{ + LLUUID imageID = val.asUUID(); + + setImageID(imageID); + + if (mCanPreview) + { + // only commit intentional selections, not implicit ones + commitIfImmediateSet(); + } +} + void LLFloaterTexturePicker::updateFilterPermMask() { //mInventoryPanel->setFilterPermMask( getFilterPermMask() ); Commented out due to no-copy texture loss. } -void LLFloaterTexturePicker::onFilterEdit(const std::string& search_string ) +void LLFloaterTexturePicker::setCanApply(bool can_preview, bool can_apply) { - std::string upper_case_search_string = search_string; - LLStringUtil::toUpper(upper_case_search_string); - - if (upper_case_search_string.empty()) - { - if (mInventoryPanel->getFilterSubString().empty()) - { - // current filter and new filter empty, do nothing - return; - } + getChildRef("Select").setEnabled(can_apply); + getChildRef("preview_disabled").setVisible(!can_preview); + getChildRef("apply_immediate_check").setVisible(can_preview); - mSavedFolderState.setApply(TRUE); - mInventoryPanel->getRootFolder()->applyFunctorRecursively(mSavedFolderState); - // add folder with current item to list of previously opened folders - LLOpenFoldersWithSelection opener; - mInventoryPanel->getRootFolder()->applyFunctorRecursively(opener); - mInventoryPanel->getRootFolder()->scrollToShowSelection(); + mCanApply = can_apply; + mCanPreview = can_preview ? gSavedSettings.getBOOL("ApplyTextureImmediately") : false; +} - } - else if (mInventoryPanel->getFilterSubString().empty()) +void LLFloaterTexturePicker::onFilterEdit(const std::string& search_string ) +{ + if (!mInventoryPanel) { - // first letter in search term, save existing folder open state - if (!mInventoryPanel->getRootFolder()->isFilterModified()) - { - mSavedFolderState.setApply(FALSE); - mInventoryPanel->getRootFolder()->applyFunctorRecursively(mSavedFolderState); - } + return; } - mInventoryPanel->setFilterSubString(upper_case_search_string); + // set new filter string + // Internally handles saving/restoring folder states. + mInventoryPanel->setFilterSubString(search_string); } void LLFloaterTexturePicker::onTextureSelect( const LLTextureEntry& te ) @@ -1054,6 +1119,9 @@ void LLFloaterTexturePicker::onTextureSelect( const LLTextureEntry& te ) if (inventory_item_id.notNull()) { LLToolPipette::getInstance()->setResult(TRUE, ""); + // FIRE-8298: Apply now checkbox has no effect + setCanApply(true, true); + // setImageID(te.getID()); mNoCopyTextureSelected = FALSE; @@ -1094,6 +1162,7 @@ LLTextureCtrl::LLTextureCtrl( mDragCallback(NULL), mDropCallback(NULL), mOnCancelCallback(NULL), + mOnCloseCallback(NULL), mOnSelectCallback(NULL), mBorderColor( gColors.getColor("DefaultHighlightLight") ), mImageAssetID( image_id ), @@ -1120,7 +1189,7 @@ LLTextureCtrl::LLTextureCtrl( S32 image_top = getRect().getHeight(); S32 image_bottom = BTN_HEIGHT_SMALL; S32 image_middle = (image_top + image_bottom) / 2; - S32 line_height = llround(LLFontGL::getFontSansSerifSmall()->getLineHeight()); + S32 line_height = ll_round(LLFontGL::getFontSansSerifSmall()->getLineHeight()); mTentativeLabel = new LLTextBox( std::string("Multiple"), LLRect( @@ -1221,6 +1290,19 @@ void LLTextureCtrl::setShowLoadingPlaceholder(BOOL showLoadingPlaceholder) mShowLoadingPlaceholder = showLoadingPlaceholder; } +// Singu Note: These two functions exist to work like their upstream counterparts +void LLTextureCtrl::setBlankImageAssetID(const LLUUID& id) +{ + if (LLFloaterTexturePicker* floater = dynamic_cast(mFloaterHandle.get())) + floater->setWhiteImageAssetID(id); +} +const LLUUID& LLTextureCtrl::getBlankImageAssetID() const +{ + if (LLFloaterTexturePicker* floater = dynamic_cast(mFloaterHandle.get())) + return floater->getWhiteImageAssetID(); + return LLUUID::null; +} + void LLTextureCtrl::setCaption(const std::string& caption) { mCaption->setText( caption ); @@ -1236,6 +1318,15 @@ void LLTextureCtrl::setCanApplyImmediately(BOOL b) } } +void LLTextureCtrl::setCanApply(bool can_preview, bool can_apply) +{ + LLFloaterTexturePicker* floaterp = dynamic_cast(mFloaterHandle.get()); + if( floaterp ) + { + floaterp->setCanApply(can_preview, can_apply); + } +} + void LLTextureCtrl::setVisible( BOOL visible ) { if( !visible ) @@ -1270,7 +1361,7 @@ void LLTextureCtrl::setEnabled( BOOL enabled ) mCaption->setEnabled( enabled ); mEnable = enabled; - LLView::setEnabled( enabled ); + //LLView::setEnabled( enabled ); // } void LLTextureCtrl::setValid(BOOL valid ) @@ -1341,6 +1432,12 @@ void LLTextureCtrl::showPicker(BOOL take_focus) mFloaterHandle = floaterp->getHandle(); + LLFloaterTexturePicker* texture_floaterp = dynamic_cast(floaterp); + if (texture_floaterp && mOnTextureSelectedCallback) + { + texture_floaterp->setTextureSelectedCallback(mOnTextureSelectedCallback); + } + gFloaterView->getParentFloater(this)->addDependentFloater(floaterp); floaterp->open(); /* Flawfinder: ignore */ } @@ -1374,9 +1471,10 @@ BOOL LLTextureCtrl::handleMouseDown(S32 x, S32 y, MASK mask) // if(!mEnable) return FALSE; - BOOL handled = LLUICtrl::handleMouseDown( x, y , mask ); + const auto clicked_picture = mBorder->parentPointInView(x, y); + BOOL handled = (mCaption->getText().empty() || clicked_picture) && LLUICtrl::handleMouseDown( x, y , mask ); - if (!handled && mBorder->parentPointInView(x, y)) + if (!handled && clicked_picture) { showPicker(FALSE); //grab textures first... @@ -1395,6 +1493,10 @@ void LLTextureCtrl::onFloaterClose() if (floaterp) { + if (mOnCloseCallback) + { + mOnCloseCallback(this,LLSD()); + } floaterp->setOwner(NULL); mLastFloaterLeftTop.set( floaterp->getRect().mLeft, floaterp->getRect().mTop ); } @@ -1413,9 +1515,9 @@ void LLTextureCtrl::onFloaterCommit(ETexturePickOp op) { setTentative( FALSE ); mImageItemID = floaterp->findItemID(floaterp->getAssetID(), FALSE); - lldebugs << "mImageItemID: " << mImageItemID << llendl; + LL_DEBUGS() << "mImageItemID: " << mImageItemID << LL_ENDL; mImageAssetID = floaterp->getAssetID(); - lldebugs << "mImageAssetID: " << mImageAssetID << llendl; + LL_DEBUGS() << "mImageAssetID: " << mImageAssetID << LL_ENDL; if (op == TEXTURE_SELECT && mOnSelectCallback) { mOnSelectCallback( this, LLSD() ); @@ -1466,6 +1568,16 @@ void LLTextureCtrl::onFloaterCommit(ETexturePickOp op, LLUUID id) // tag: vaa emerald local_asset_browser [end] +void LLTextureCtrl::setOnTextureSelectedCallback(texture_selected_callback cb) +{ + mOnTextureSelectedCallback = cb; + LLFloaterTexturePicker* floaterp = dynamic_cast(mFloaterHandle.get()); + if (floaterp) + { + floaterp->setTextureSelectedCallback(cb); + } +} + void LLTextureCtrl::setImageAssetID( const LLUUID& asset_id ) { if( mImageAssetID != asset_id ) @@ -1515,7 +1627,7 @@ BOOL LLTextureCtrl::handleDragAndDrop(S32 x, S32 y, MASK mask, } handled = TRUE; - lldebugst(LLERR_USER_INPUT) << "dragAndDrop handled by LLTextureCtrl " << getName() << llendl; + LL_DEBUGS("UserInput") << "dragAndDrop handled by LLTextureCtrl " << getName() << LL_ENDL; return handled; } @@ -1526,21 +1638,40 @@ void LLTextureCtrl::draw() if (!mValid) { - mTexturep = NULL; + mTexturep = nullptr; } else if (!mImageAssetID.isNull()) { - mTexturep = LLViewerTextureManager::getFetchedTexture(mImageAssetID, MIPMAP_YES,LLGLTexture::BOOST_PREVIEW, LLViewerTexture::LOD_TEXTURE); - mTexturep->forceToSaveRawImage(0) ; + LLPointer texture = NULL; + + if (LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::isBakedImageId(mImageAssetID)) + { + LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); + if (obj) + { + LLViewerTexture* viewerTexture = obj->getBakedTextureForMagicId(mImageAssetID); + texture = viewerTexture ? dynamic_cast(viewerTexture) : NULL; + } + } + + if (texture.isNull()) + { + texture = LLViewerTextureManager::getFetchedTexture(mImageAssetID, FTT_DEFAULT, MIPMAP_YES, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); + } + + texture->setBoostLevel(LLGLTexture::BOOST_PREVIEW); + texture->forceToSaveRawImage(0) ; + + mTexturep = texture; } else if (!mFallbackImageName.empty()) { // Show fallback image. - mTexturep = LLViewerTextureManager::getFetchedTextureFromFile(mFallbackImageName, MIPMAP_YES,LLGLTexture::BOOST_PREVIEW, LLViewerTexture::LOD_TEXTURE); + mTexturep = LLViewerTextureManager::getFetchedTextureFromFile(mFallbackImageName, FTT_LOCAL_FILE, MIPMAP_YES,LLGLTexture::BOOST_PREVIEW, LLViewerTexture::LOD_TEXTURE); } else // mImageAssetID == LLUUID::null { - mTexturep = NULL; + mTexturep = nullptr; } // Border @@ -1638,6 +1769,7 @@ BOOL LLTextureCtrl::doDrop(LLInventoryItem* item) // no callback installed, so just set the image ids and carry on. setImageAssetID( item->getAssetUUID() ); mImageItemID = item->getUUID(); + mDirty = true; return TRUE; } diff --git a/indra/newview/lltexturectrl.h b/indra/newview/lltexturectrl.h index 27afeba3d5..5d43dfdf0f 100644 --- a/indra/newview/lltexturectrl.h +++ b/indra/newview/lltexturectrl.h @@ -48,6 +48,7 @@ class LLViewerFetchedTexture; // used for setting drag & drop callbacks. typedef boost::function drag_n_drop_callback; +typedef boost::function texture_selected_callback; ////////////////////////////////////////////////////////////////////////////////////////// @@ -79,7 +80,6 @@ class LLTextureCtrl static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); - virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, void *cargo_data, EAcceptance *accept, @@ -124,12 +124,17 @@ class LLTextureCtrl const std::string& getDefaultImageName() const { return mDefaultImageName; } + void setBlankImageAssetID(const LLUUID& id); + const LLUUID& getBlankImageAssetID() const; + void setFallbackImageName( const std::string& name ) { mFallbackImageName = name; } const std::string& getFallbackImageName() const { return mFallbackImageName; } void setCaption(const std::string& caption); void setCanApplyImmediately(BOOL b); + void setCanApply(bool can_preview, bool can_apply); + void setImmediateFilterPermMask(PermissionMask mask) { mImmediateFilterPermMask = mask; } void setDnDFilterPermMask(PermissionMask mask) @@ -145,6 +150,8 @@ class LLTextureCtrl void onFloaterCommit(ETexturePickOp op); void onFloaterCommit(ETexturePickOp op, LLUUID id); // tag: vaa emerald local_asset_browser + bool canChange() { return mEnable; } // + // This call is returned when a drag is detected. Your callback // should return TRUE if the drag is acceptable. void setDragCallback(drag_n_drop_callback cb) { mDragCallback = cb; } @@ -155,11 +162,18 @@ class LLTextureCtrl void setDropCallback(drag_n_drop_callback cb) { mDropCallback = cb; } void setOnCancelCallback(commit_callback_t cb) { mOnCancelCallback = cb; } - + void setOnCloseCallback(commit_callback_t cb) { mOnCloseCallback = cb; } void setOnSelectCallback(commit_callback_t cb) { mOnSelectCallback = cb; } + /* + * callback for changing texture selection in inventory list of texture floater + */ + void setOnTextureSelectedCallback(texture_selected_callback cb); + void setShowLoadingPlaceholder(BOOL showLoadingPlaceholder); + LLViewerFetchedTexture* getTexture() { return mTexturep; } + static void handleClickOpenTexture(void* userdata); static void handleClickCopyAssetID(void* userdata); @@ -172,6 +186,8 @@ class LLTextureCtrl drag_n_drop_callback mDropCallback; commit_callback_t mOnCancelCallback; commit_callback_t mOnSelectCallback; + commit_callback_t mOnCloseCallback; + texture_selected_callback mOnTextureSelectedCallback; LLPointer mTexturep; LLColor4 mBorderColor; LLUUID mImageItemID; diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index cdc31ae431..6983336428 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -60,8 +60,12 @@ #include "llstartup.h" #include "llsdserialize.h" #include "llbuffer.h" +#include "llhttpretrypolicy.h" #include "hippogridmanager.h" +#include +#include + class AIHTTPTimeoutPolicy; extern AIHTTPTimeoutPolicy HTTPGetResponder_timeout; extern AIHTTPTimeoutPolicy lcl_responder_timeout; @@ -71,6 +75,9 @@ LLStat LLTextureFetch::sCacheHitRate("texture_cache_hits", 128); LLStat LLTextureFetch::sCacheReadLatency("texture_cache_read_latency", 128); ////////////////////////////////////////////////////////////////////////////// +// Log scope +static const char * const LOG_TXT = "Texture"; + class LLTextureFetchWorker : public LLWorkerClass { friend class LLTextureFetch; @@ -164,7 +171,8 @@ class LLTextureFetchWorker : public LLWorkerClass ~LLTextureFetchWorker(); // void relese() { --mActiveCount; } - S32 callbackHttpGet(const LLChannelDescriptors& channels, + S32 callbackHttpGet(U32 offset, U32 length, + const LLChannelDescriptors& channels, const LLHTTPClient::ResponderBase::buffer_ptr_t& buffer, bool partial, bool success); void callbackCacheRead(bool success, LLImageFormatted* image, @@ -186,7 +194,8 @@ class LLTextureFetchWorker : public LLWorkerClass LLTextureFetch & getFetcher() { return *mFetcher; } protected: - LLTextureFetchWorker(LLTextureFetch* fetcher, const std::string& url, const LLUUID& id, const LLHost& host, + LLTextureFetchWorker(LLTextureFetch* fetcher, FTType f_type, + const std::string& url, const LLUUID& id, const LLHost& host, F32 priority, S32 discard, S32 size); private: @@ -224,6 +233,8 @@ class LLTextureFetchWorker : public LLWorkerClass CACHE_POST, LOAD_FROM_NETWORK, LOAD_FROM_SIMULATOR, + SEND_UDP_REQ, + WAIT_UDP_REQ, SEND_HTTP_REQ, WAIT_HTTP_REQ, DECODE_IMAGE, @@ -246,11 +257,13 @@ class LLTextureFetchWorker : public LLWorkerClass }; static const char* sStateDescs[]; e_state mState; + void setState(e_state new_state); e_write_to_cache_state mWriteToCacheState; LLTextureFetch* mFetcher; LLPointer mFormattedImage; - LLPointer mRawImage; - LLPointer mAuxImage; + LLPointer mRawImage, + mAuxImage; + const FTType mFTType; LLUUID mID; LLHost mHost; std::string mUrl; @@ -259,23 +272,23 @@ class LLTextureFetchWorker : public LLWorkerClass F32 mImagePriority; U32 mWorkPriority; F32 mRequestedPriority; - S32 mDesiredDiscard; - S32 mSimRequestedDiscard; - S32 mRequestedDiscard; - S32 mLoadedDiscard; - S32 mDecodedDiscard; - LLFrameTimer mRequestedTimer; - LLFrameTimer mFetchTimer; + S32 mDesiredDiscard, + mSimRequestedDiscard, + mRequestedDiscard, + mLoadedDiscard, + mDecodedDiscard; + LLFrameTimer mRequestedTimer, + mFetchTimer; LLTimer mCacheReadTimer; F32 mCacheReadTime; - LLTextureCache::handle_t mCacheReadHandle; - LLTextureCache::handle_t mCacheWriteHandle; + LLTextureCache::handle_t mCacheReadHandle, + mCacheWriteHandle; std::vector mHttpBuffer; - S32 mRequestedSize; - S32 mRequestedOffset; - S32 mDesiredSize; - S32 mFileSize; - S32 mCachedSize; + S32 mRequestedSize, + mRequestedOffset, + mDesiredSize, + mFileSize, + mCachedSize; e_request_state mSentRequest; handle_t mDecodeHandle; BOOL mLoaded; @@ -284,8 +297,8 @@ class LLTextureFetchWorker : public LLWorkerClass BOOL mNeedsAux; BOOL mHaveAllData; BOOL mInLocalCache; - bool mCanUseHTTP ; - bool mCanUseNET ; //can get from asset server. + bool mCanUseHTTP, + mCanUseNET ; //can get from asset server. S32 mHTTPFailCount; S32 mRetryAttempt; S32 mActiveCount; @@ -296,9 +309,12 @@ class LLTextureFetchWorker : public LLWorkerClass LLMutex mWorkMutex; struct PacketData { - PacketData(U8* data, S32 size) { mData = data; mSize = size; } + PacketData(U8* data, S32 size) + : mData(data), mSize(size) + {} ~PacketData() { clearData(); } void clearData() { delete[] mData; mData = NULL; } + U8* mData; U32 mSize; }; @@ -309,9 +325,11 @@ class LLTextureFetchWorker : public LLWorkerClass U8 mImageCodec; LLViewerAssetStats::duration_t mMetricsStartTime; + U32 mHttpReplySize, // Actual received data size + mHttpReplyOffset; // Actual received data offset // State history - U32 mCacheReadCount; - U32 mCacheWriteCount; + U32 mCacheReadCount, + mCacheWriteCount; }; ////////////////////////////////////////////////////////////////////////////// @@ -319,112 +337,168 @@ class HTTPGetResponder : public LLHTTPClient::ResponderWithCompleted { LOG_CLASS(HTTPGetResponder); public: - HTTPGetResponder(LLTextureFetch* fetcher, const LLUUID& id, U64 startTime, S32 requestedSize, U32 offset, bool redir) + HTTPGetResponder( FTType f_type, LLTextureFetch* fetcher, const LLUUID& id, U64 startTime, S32 requestedSize, U32 offset) : mFetcher(fetcher) , mID(id) - , mStartTime(startTime) + , mMetricsStartTime(startTime) , mRequestedSize(requestedSize) , mRequestedOffset(offset) - , mFollowRedir(redir) + , mReplyOffset(0) + , mReplyLength(0) + , mReplyFullLength(0) + , mFTType(f_type) { + mFetchRetryPolicy = new LLAdaptiveRetryPolicy(10.0,3600.0,2.0,10); } ~HTTPGetResponder() { } -#if 0 //Apparently, SL never sends content-range and instead sends transfer-encoding: chunked, so disabling for now /*virtual*/ bool needsHeaders(void) const { return true; } - /*virtual*/ void completedHeaders(U32 status, std::string const& reason, AIHTTPReceivedHeaders const& headers) { - llinfos << "Texture fetch HTTP status: " << status << llendl; - llinfos << "Texture fetch headers: " << headers << llendl; - //example: Content-Range: 1000-3979/3980 Content-Length: 2980 - static const boost::regex pattern("\\w*bytes\\w+(\\d+)-(\\d+)/(\\d+)"); + /*virtual*/ void completedHeaders(void) { + LL_DEBUGS("Texture") << "HTTP HEADERS COMPLETE: " << mID << LL_ENDL; + std::string rangehdr; - if (headers.getFirstValue("content-range", rangehdr)){ - llinfos << "Have content-range header" < tokens; + boost::split(tokens,rangehdr,boost::is_any_of(" -/")); + if(tokens.size() == 4 && !stricmp(tokens[0].c_str(),"bytes")) + { + U32 first(0), last(0), len(0); + try + { + first = boost::lexical_cast(tokens[1].c_str()); + last = boost::lexical_cast(tokens[2].c_str()); + } + catch( boost::bad_lexical_cast& ) + { + return; + } + if(tokens[3] != "*") + { + try + { + len = boost::lexical_cast(tokens[3].c_str()); + } + catch( boost::bad_lexical_cast& ) + { + len = 0; + } + } + if(first <= last && (!len || last < len)) + { + mReplyOffset = first; + mReplyLength = last - first + 1; + mReplyFullLength = len; + LL_DEBUGS("Texture") << " mReplyOffset=" << mReplyOffset << " mReplyLength=" << mReplyLength << " mReplyFullLength=" << mReplyFullLength << LL_ENDL; + } } } } -#endif - /*virtual*/ void completedRaw(U32 status, const std::string& reason, - const LLChannelDescriptors& channels, - const buffer_ptr_t& buffer) + /*virtual*/ void completedRaw(LLChannelDescriptors const& channels, + buffer_ptr_t const& buffer) { static LLCachedControl log_to_viewer_log(gSavedSettings,"LogTextureDownloadsToViewerLog"); static LLCachedControl log_to_sim(gSavedSettings,"LogTextureDownloadsToSimulator"); static LLCachedControl log_texture_traffic(gSavedSettings,"LogTextureNetworkTraffic") ; - + if (log_to_viewer_log || log_to_sim) { - mFetcher->mTextureInfo.setRequestStartTime(mID, mStartTime); - U64 timeNow = LLTimer::getTotalTime(); + mFetcher->mTextureInfo.setRequestStartTime(mID, mMetricsStartTime); mFetcher->mTextureInfo.setRequestType(mID, LLTextureInfoDetails::REQUEST_TYPE_HTTP); mFetcher->mTextureInfo.setRequestSize(mID, mRequestedSize); mFetcher->mTextureInfo.setRequestOffset(mID, mRequestedOffset); - mFetcher->mTextureInfo.setRequestCompleteTimeAndLog(mID, timeNow); + mFetcher->mTextureInfo.setRequestCompleteTimeAndLog(mID, LLTimer::getTotalTime()); } LL_DEBUGS("Texture") << "HTTP COMPLETE: " << mID << LL_ENDL; LLTextureFetchWorker* worker = mFetcher->getWorker(mID); if (worker) { + worker->lockWorkMutex(); bool success = false; bool partial = false; - if (HTTP_OK <= status && status < HTTP_MULTIPLE_CHOICES) + if (HTTP_OK <= mStatus && mStatus < HTTP_MULTIPLE_CHOICES) { + mFetchRetryPolicy->onSuccess(); success = true; - if (HTTP_PARTIAL_CONTENT == status) // partial information + if (HTTP_PARTIAL_CONTENT == mStatus) // partial information { partial = true; } } if (!success) { - worker->setGetStatus(status, reason); -// llwarns << "CURL GET FAILED, status:" << status << " reason:" << reason << llendl; + if(mFTType == FTT_SERVER_BAKE) + { + mFetchRetryPolicy->onFailure(getStatus(), getResponseHeaders()); + F32 retry_after; + if (mFetchRetryPolicy->shouldRetry(retry_after)) + { + LL_INFOS(LOG_TXT) << mID << " will retry after " << retry_after << " seconds, resetting state to LOAD_FROM_NETWORK" << LL_ENDL; + mFetcher->removeFromHTTPQueue(mID, 0); + worker->setGetStatus(mStatus, mReason); + worker->setState(LLTextureFetchWorker::LOAD_FROM_NETWORK); + worker->unlockWorkMutex(); + return; + } + } + worker->setGetStatus(mStatus, mReason); + if (mFTType != FTT_MAP_TILE) // missing map tiles are normal, don't complain about them. + { + LL_WARNS(LOG_TXT) << "CURL GET FAILED, status:" << mStatus + << " reason: " << mReason << LL_ENDL; + } } - S32 data_size = worker->callbackHttpGet(channels, buffer, partial, success); + S32BytesImplicit data_size = worker->callbackHttpGet(mReplyOffset, mReplyLength, channels, buffer, partial, success); if(log_texture_traffic && data_size > 0) { - LLViewerTexture* tex = LLViewerTextureManager::findTexture(mID) ; - if(tex) + // one worker per multiple textures + std::vector textures; + LLViewerTextureManager::findTextures(mID, textures); + std::vector::iterator iter = textures.begin(); + while (iter != textures.end()) { - gTotalTextureBytesPerBoostLevel[tex->getBoostLevel()] += data_size ; + LLViewerTexture* tex = *iter++; + if (tex) + { + gTotalTextureBytesPerBoostLevel[tex->getBoostLevel()] += data_size; + } } } mFetcher->removeFromHTTPQueue(mID, data_size); worker->recordTextureDone(true); + worker->unlockWorkMutex(); } else { mFetcher->removeFromHTTPQueue(mID); - llwarns << "Worker not found: " << mID << llendl; + LL_WARNS() << "Worker not found: " << mID << LL_ENDL; } } - /*virtual*/ bool followRedir() const { return mFollowRedir; } /*virtual*/ AICapabilityType capability_type(void) const { return cap_texture; } /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return HTTPGetResponder_timeout; } /*virtual*/ char const* getName(void) const { return "HTTPGetResponder"; } private: + LLTextureFetch* mFetcher; LLUUID mID; - U64 mStartTime; + const FTType mFTType; + LLPointer mFetchRetryPolicy; + U64 mMetricsStartTime; S32 mRequestedSize; U32 mRequestedOffset; - bool mFollowRedir; + U32 mReplyOffset; + U32 mReplyLength; + U32 mReplyFullLength; + }; ////////////////////////////////////////////////////////////////////////////// @@ -449,7 +523,7 @@ class SGHostBlackList{ } //should make a functor. if i cared. static void cleanup() { - std::remove_if(blacklist.begin(), blacklist.end(), is_obsolete); + (void)std::remove_if(blacklist.begin(), blacklist.end(), is_obsolete); } static iter find(std::string host) { @@ -468,7 +542,7 @@ class SGHostBlackList{ } static void add(std::string url, float timeout, U32 reason) { - llwarns << "Requested adding to blacklist: " << url << llendl; + LL_WARNS() << "Requested adding to blacklist: " << url << LL_ENDL; BlackListEntry entry; entry.host = url.substr(0, url.rfind("/")); if (entry.host.empty()) return; @@ -482,10 +556,10 @@ class SGHostBlackList{ if (entry.errorCount > MAX_ERRORCOUNT) { std::string s; microsecondsToTimecodeString(entry.timeUntil, s); - llwarns << "Blacklisting address " << entry.host + LL_WARNS() << "Blacklisting address " << entry.host << "is blacklisted for " << timeout << " seconds because of error " << reason - << llendl; + << LL_ENDL; } } else blacklist.push_back(entry); @@ -727,13 +801,15 @@ const char* LLTextureFetchWorker::sStateDescs[] = { "CACHE_POST", "LOAD_FROM_NETWORK", "LOAD_FROM_SIMULATOR", + "SEND_UDP_REQ", + "WAIT_UDP_REQ", "SEND_HTTP_REQ", "WAIT_HTTP_REQ", "DECODE_IMAGE", "DECODE_IMAGE_UPDATE", "WRITE_TO_CACHE", "WAIT_ON_WRITE", - "DONE", + "DONE" }; // static @@ -742,6 +818,7 @@ volatile bool LLTextureFetch::svMetricsDataBreak(true); // Start with a data bre // called from MAIN THREAD LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher, + FTType f_type, // Fetched image type const std::string& url, // Optional URL const LLUUID& id, // Image UUID const LLHost& host, // Simulator host @@ -752,6 +829,7 @@ LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher, mState(INIT), mWriteToCacheState(NOT_WRITE), mFetcher(fetcher), + mFTType(f_type), mID(id), mHost(host), mUrl(url), @@ -789,10 +867,12 @@ LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher, mTotalPackets(0), mImageCodec(IMG_CODEC_INVALID), mMetricsStartTime(0), + mHttpReplySize(0U), + mHttpReplyOffset(0U), mCacheReadCount(0U), mCacheWriteCount(0U) { - mCanUseNET = mUrl.empty() ; + mCanUseNET = mUrl.empty(); // Necessary for precached UUID textures, regardless of grid. if (!mCanUseNET) { @@ -807,7 +887,7 @@ LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher, calcWorkPriority(); mType = host.isOk() ? LLImageBase::TYPE_AVATAR_BAKE : LLImageBase::TYPE_NORMAL; - //llinfos << "Create: " << mID << " mHost:" << host << " Discard=" << discard << " URL:"<< mUrl << llendl; + //LL_INFOS() << "Create: " << mID << " mHost:" << host << " Discard=" << discard << " URL:"<< mUrl << LL_ENDL; if (!mFetcher->mDebugPause) { U32 work_priority = mWorkPriority | LLWorkerThread::PRIORITY_HIGH; @@ -818,10 +898,10 @@ LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher, LLTextureFetchWorker::~LLTextureFetchWorker() { -// llinfos << "Destroy: " << mID +// LL_INFOS() << "Destroy: " << mID // << " Decoded=" << mDecodedDiscard // << " Requested=" << mRequestedDiscard -// << " Desired=" << mDesiredDiscard << llendl; +// << " Desired=" << mDesiredDiscard << LL_ENDL; llassert_always(!haveWork()); lockWorkMutex(); if (mCacheReadHandle != LLTextureCache::nullHandle() && mFetcher->mTextureCache) @@ -861,7 +941,7 @@ void LLTextureFetchWorker::setupPacketData() mFirstPacket = (data_size - FIRST_PACKET_SIZE) / MAX_IMG_PACKET_SIZE + 1; if (FIRST_PACKET_SIZE + (mFirstPacket-1) * MAX_IMG_PACKET_SIZE != data_size) { - llwarns << "Bad CACHED TEXTURE size: " << data_size << " removing." << llendl; + LL_WARNS(LOG_TXT) << "Bad CACHED TEXTURE size: " << data_size << " removing." << LL_ENDL; removeFromCache(); resetFormattedData(); clearPackets(); @@ -918,7 +998,7 @@ void LLTextureFetchWorker::setDesiredDiscard(S32 discard, S32 size) mDesiredSize = llmax(mDesiredSize, TEXTURE_CACHE_ENTRY_SIZE); if ((prioritize && mState == INIT) || mState == DONE) { - mState = INIT; + setState(INIT); U32 work_priority = mWorkPriority | LLWorkerThread::PRIORITY_HIGH; setPriority(work_priority); } @@ -944,6 +1024,8 @@ void LLTextureFetchWorker::resetFormattedData() { mFormattedImage->deleteData(); } + mHttpReplySize = 0; + mHttpReplyOffset = 0; mHaveAllData = FALSE; } @@ -969,14 +1051,16 @@ bool LLTextureFetchWorker::doWork(S32 param) } if(mImagePriority < F_ALMOST_ZERO) { - if (mState == INIT || mState == LOAD_FROM_NETWORK || mState == LOAD_FROM_SIMULATOR) + if (mState == INIT || mState == LOAD_FROM_NETWORK/* || mState == LOAD_FROM_SIMULATOR*/) //If we've already sent out requests.. might as well continue. { + LL_DEBUGS(LOG_TXT) << mID << " abort: mImagePriority < F_ALMOST_ZERO" << LL_ENDL; return true; // abort } } if(mState > CACHE_POST && !mCanUseNET && !mCanUseHTTP) { //nowhere to get data, abort. + LL_WARNS(LOG_TXT) << mID << " abort, nowhere to get data" << LL_ENDL; return true ; } @@ -999,8 +1083,8 @@ bool LLTextureFetchWorker::doWork(S32 param) if(gAssetStorage && std::find(gAssetStorage->mBlackListedAsset.begin(), gAssetStorage->mBlackListedAsset.end(),mID) != gAssetStorage->mBlackListedAsset.end()) { - llinfos << "Blacklisted asset " << mID.asString() << " was trying to be accessed!!!!!!" << llendl; - mState = DONE; + LL_INFOS() << "Blacklisted asset " << mID.asString() << " was trying to be accessed!!!!!!" << LL_ENDL; + setState(DONE); return true; } @@ -1017,13 +1101,15 @@ bool LLTextureFetchWorker::doWork(S32 param) mDecoded = FALSE; mWritten = FALSE; std::vector().swap(mHttpBuffer); + mHttpReplySize = 0; + mHttpReplyOffset = 0; mHaveAllData = FALSE; clearPackets(); // TODO: Shouldn't be necessary mCacheReadHandle = LLTextureCache::nullHandle(); mCacheWriteHandle = LLTextureCache::nullHandle(); - mState = LOAD_FROM_TEXTURE_CACHE; + setState(LOAD_FROM_TEXTURE_CACHE); mDesiredSize = llmax(mDesiredSize, TEXTURE_CACHE_ENTRY_SIZE); // min desired size is TEXTURE_CACHE_ENTRY_SIZE - LL_DEBUGS("Texture") << mID << ": Priority: " << llformat("%8.0f",mImagePriority) + LL_DEBUGS(LOG_TXT) << mID << ": Priority: " << llformat("%8.0f",mImagePriority) << " Desired Discard: " << mDesiredDiscard << " Desired Size: " << mDesiredSize << LL_ENDL; // fall through } @@ -1037,7 +1123,7 @@ bool LLTextureFetchWorker::doWork(S32 param) S32 size = mDesiredSize - offset; if (size <= 0) { - mState = CACHE_POST; + setState(CACHE_POST); return false; } mFileSize = 0; @@ -1055,7 +1141,7 @@ bool LLTextureFetchWorker::doWork(S32 param) offset, size, responder); mCacheReadTimer.reset(); } - else if (mUrl.empty()) + else if ((mUrl.empty() || mFTType==FTT_SERVER_BAKE)) { setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it @@ -1070,15 +1156,15 @@ bool LLTextureFetchWorker::doWork(S32 param) if (!(mUrl.compare(0, 7, "http://") == 0)) { // *TODO:?remove this warning - llwarns << "Unknown URL Type: " << mUrl << llendl; + LL_WARNS() << "Unknown URL Type: " << mUrl << LL_ENDL; } setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); - mState = SEND_HTTP_REQ; + setState(SEND_HTTP_REQ); } else { setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); - mState = LOAD_FROM_NETWORK; + setState(LOAD_FROM_NETWORK); } } @@ -1088,7 +1174,7 @@ bool LLTextureFetchWorker::doWork(S32 param) if (mFetcher->mTextureCache->readComplete(mCacheReadHandle, false)) { mCacheReadHandle = LLTextureCache::nullHandle(); - mState = CACHE_POST; + setState(CACHE_POST); // fall through } else @@ -1096,6 +1182,7 @@ bool LLTextureFetchWorker::doWork(S32 param) // //This should never happen // + LL_DEBUGS(LOG_TXT) << mID << " this should never happen" << LL_ENDL; return false; } } @@ -1114,9 +1201,14 @@ bool LLTextureFetchWorker::doWork(S32 param) // we have enough data, decode it llassert_always(mFormattedImage->getDataSize() > 0); mLoadedDiscard = mDesiredDiscard; - mState = DECODE_IMAGE; + if (mLoadedDiscard < 0) + { + LL_WARNS(LOG_TXT) << mID << " mLoadedDiscard is " << mLoadedDiscard + << ", should be >=0" << LL_ENDL; + } + setState(DECODE_IMAGE); mWriteToCacheState = NOT_WRITE ; - LL_DEBUGS("Texture") << mID << ": Cached. Bytes: " << mFormattedImage->getDataSize() + LL_DEBUGS(LOG_TXT) << mID << ": Cached. Bytes: " << mFormattedImage->getDataSize() << " Size: " << llformat("%dx%d",mFormattedImage->getWidth(),mFormattedImage->getHeight()) << " Desired Discard: " << mDesiredDiscard << " Desired Size: " << mDesiredSize << LL_ENDL; LLTextureFetch::sCacheHitRate.addValue(100.f); @@ -1126,13 +1218,14 @@ bool LLTextureFetchWorker::doWork(S32 param) if (mUrl.compare(0, 7, "file://") == 0) { // failed to load local file, we're done. + LL_WARNS(LOG_TXT) << mID << ": abort, failed to load local file " << mUrl << LL_ENDL; return true; } // need more data else { - LL_DEBUGS("Texture") << mID << ": Not in Cache" << LL_ENDL; - mState = LOAD_FROM_NETWORK; + LL_DEBUGS(LOG_TXT) << mID << ": Not in Cache" << LL_ENDL; + setState(LOAD_FROM_NETWORK); } // fall through @@ -1143,9 +1236,10 @@ bool LLTextureFetchWorker::doWork(S32 param) if (mState == LOAD_FROM_NETWORK) { static LLCachedControl use_http(gSavedSettings,"ImagePipelineUseHTTP"); + bool is_sl = gHippoGridManager->getConnectedGrid()->isSecondLife(); // if (mHost != LLHost::invalid) use_http = false; - if (use_http && mCanUseHTTP && mUrl.empty()) // get http url. + if ((is_sl || use_http) && mCanUseHTTP && mUrl.empty()) // get http url. { LLViewerRegion* region = NULL; if (mHost == LLHost::invalid) @@ -1155,31 +1249,44 @@ bool LLTextureFetchWorker::doWork(S32 param) if (region) { - std::string http_url = region->getHttpUrl() ; + std::string http_url = region->getViewerAssetUrl(); + if (http_url.empty()) http_url = region->getCapability("GetTexture"); if (!http_url.empty()) { + if (mFTType != FTT_DEFAULT) + { + LL_WARNS(LOG_TXT) << "trying to seek a non-default texture on the sim. Bad! mFTType: " << mFTType << LL_ENDL; + } mUrl = http_url + "/?texture_id=" + mID.asString().c_str(); + LL_DEBUGS(LOG_TXT) << "Texture URL: " << mUrl << LL_ENDL; mWriteToCacheState = CAN_WRITE ; //because this texture has a fixed texture id. mPerServicePtr = AIPerService::instance(AIPerService::extract_canonical_servicename(http_url)); } else { mCanUseHTTP = false ; + LL_DEBUGS(LOG_TXT) << "Texture not available via HTTP: empty URL." << LL_ENDL; } } else { // This will happen if not logged in or if a region does not have HTTP Texture enabled - //llwarns << "Region not found for host: " << mHost << llendl; + //LL_WARNS() << "Region not found for host: " << mHost << LL_ENDL; + LL_DEBUGS(LOG_TXT) << "Texture not available via HTTP: no region " << mUrl << LL_ENDL; mCanUseHTTP = false; } } + else if (mFTType == FTT_SERVER_BAKE) + { + mWriteToCacheState = CAN_WRITE; + } if (!mUrl.empty() && SGHostBlackList::isBlacklisted(mUrl)){ + LL_DEBUGS("Texture") << mID << "Blacklisted" << LL_ENDL; mCanUseHTTP = false; } if (mCanUseHTTP && !mUrl.empty()) { - mState = LLTextureFetchWorker::SEND_HTTP_REQ; + setState(SEND_HTTP_REQ); setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); if(mWriteToCacheState != NOT_WRITE) { @@ -1187,19 +1294,20 @@ bool LLTextureFetchWorker::doWork(S32 param) } // don't return, fall through to next state } - else if (mSentRequest == UNSENT && mCanUseNET) + else if (!mCanUseNET) { - // Add this to the network queue and sit here. - // LLTextureFetch::update() will send off a request which will change our state - mWriteToCacheState = CAN_WRITE ; - mRequestedSize = mDesiredSize; - mRequestedDiscard = mDesiredDiscard; - mSentRequest = QUEUED; - mFetcher->addToNetworkQueue(this); - recordTextureStart(false); - setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); - - return false; + LL_WARNS(LOG_TXT) << mID << "Unable to retrieve texture via HTTP and UDP unavailable (probable 404): " << mUrl << LL_ENDL; + return true; + } + else if (mSentRequest == UNSENT) + { + LL_DEBUGS("Texture") << mID << " moving to UDP fetch. mSentRequest=" << mSentRequest << " mCanUseNET = " << mCanUseNET << LL_ENDL; + setState(SEND_UDP_REQ); + setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); + if(mWriteToCacheState != NOT_WRITE) + { + mWriteToCacheState = CAN_WRITE ; + } } else { @@ -1207,12 +1315,15 @@ bool LLTextureFetchWorker::doWork(S32 param) //llassert_always(mFetcher->mNetworkQueue.find(mID) != mFetcher->mNetworkQueue.end()); // Make certain this is in the network queue //mFetcher->addToNetworkQueue(this); + //recordTextureStart(false); //setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); + + LL_WARNS("Texture") << mID << " does this happen? mSentRequest=" << mSentRequest << " mCanUseNET = " << mCanUseNET << LL_ENDL; return false; } } - if (mState == LOAD_FROM_SIMULATOR) + if (mState == LOAD_FROM_SIMULATOR) //UDP. From LLTextureFetch::receiveImageHeader or LLTextureFetch::receiveImagePacket { if (mFormattedImage.isNull()) { @@ -1220,124 +1331,169 @@ bool LLTextureFetchWorker::doWork(S32 param) } if (processSimulatorPackets()) { - LL_DEBUGS("Texture") << mID << ": Loaded from Sim. Bytes: " << mFormattedImage->getDataSize() << LL_ENDL; + LL_DEBUGS(LOG_TXT) << mID << ": Loaded from Sim. Bytes: " << mFormattedImage->getDataSize() << LL_ENDL; mFetcher->removeFromNetworkQueue(this, false); if (mFormattedImage.isNull() || !mFormattedImage->getDataSize()) { // processSimulatorPackets() failed -// llwarns << "processSimulatorPackets() failed to load buffer" << llendl; +// LL_WARNS() << "processSimulatorPackets() failed to load buffer" << LL_ENDL; + LL_WARNS(LOG_TXT) << mID << " processSimulatorPackets() failed to load buffer" << LL_ENDL; return true; // failed } setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); - mState = DECODE_IMAGE; + if (mLoadedDiscard < 0) + { + LL_WARNS(LOG_TXT) << mID << " mLoadedDiscard is " << mLoadedDiscard + << ", should be >=0" << LL_ENDL; + } + setState(DECODE_IMAGE); + llassert_always(strstr(mUrl.c_str(), "map.secondlife") == NULL); mWriteToCacheState = SHOULD_WRITE; recordTextureDone(false); } else { - mFetcher->addToNetworkQueue(this); // failsafe - setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); - recordTextureStart(false); + llassert(mFetcher->mNetworkQueue.find(mID) != mFetcher->mNetworkQueue.end()); + //mFetcher->addToNetworkQueue(this); // failsafe + //setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); + //recordTextureStart(false); } return false; } + + if (mState == SEND_UDP_REQ) + { + if (! mCanUseNET) + { + LL_WARNS("Texture") << mID << " abort: SEND_UDP_REQ but !mCanUseNet" << LL_ENDL; + return true ; //abort + } + + LL_DEBUGS("Texture") << mID << " sending to UDP fetch. mSentRequest=" << mSentRequest << " mCanUseNET = " << mCanUseNET << LL_ENDL; + + mRequestedSize = mDesiredSize; + mRequestedDiscard = mDesiredDiscard; + mSentRequest = QUEUED; + mFetcher->addToNetworkQueue(this); + recordTextureStart(false); + setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); + setState(WAIT_UDP_REQ); + } + + if (mState == WAIT_UDP_REQ) + { + //do nothing. + if (! mCanUseNET) + { + LL_WARNS("Texture") << mID << " abort: SEND_UDP_REQ but !mCanUseNet" << LL_ENDL; + return true ; //abort + } + llassert(mFetcher->mNetworkQueue.find(mID) != mFetcher->mNetworkQueue.end()); + //Should migrate to LOAD_FROM_SIMULATOR upon receipt of data. + } if (mState == SEND_HTTP_REQ) { - if(mCanUseHTTP) + if (! mCanUseHTTP) + { + LL_WARNS(LOG_TXT) << mID << " abort: SEND_HTTP_REQ but !mCanUseHTTP" << LL_ENDL; + return true ; //abort + } + S32 cur_size = 0; + if (mFormattedImage.notNull()) { - S32 cur_size = 0; - if (mFormattedImage.notNull()) + cur_size = mFormattedImage->getDataSize(); // amount of data we already have + if (mFormattedImage->getDiscardLevel() == 0) { - cur_size = mFormattedImage->getDataSize(); // amount of data we already have - if (mFormattedImage->getDiscardLevel() == 0) + // Already have all data. + mFetcher->removeFromNetworkQueue(this, false); // Note sure this is necessary, but it's what the old did --Aleric + if (cur_size > 0) { - // Already have all data. - mFetcher->removeFromNetworkQueue(this, false); // Note sure this is necessary, but it's what the old did --Aleric - if(cur_size > 0) + // We already have all the data, just decode it + mLoadedDiscard = mFormattedImage->getDiscardLevel(); + setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); + if (mLoadedDiscard < 0) { - // We already have all the data, just decode it - mLoadedDiscard = mFormattedImage->getDiscardLevel(); - mState = DECODE_IMAGE; - return false; + LL_WARNS(LOG_TXT) << mID << " mLoadedDiscard is " << mLoadedDiscard + << ", should be >=0" << LL_ENDL; } - else - { + setState(DECODE_IMAGE); + return false; + } + else + { + LL_WARNS(LOG_TXT) << mID << " SEND_HTTP_REQ abort: cur_size " << cur_size << " <=0" << LL_ENDL; return true ; //abort. - } } } + } - // Let AICurl decide if we can process more HTTP requests at the moment or not. - - // AIPerService::approveHTTPRequestFor returns approvement for ONE request. - // This object keeps track of whether or not that is honored. - LLPointer approved = AIPerService::approveHTTPRequestFor(mPerServicePtr, cap_texture); - if (!approved) - { - return false ; //wait. - } - - mFetcher->removeFromNetworkQueue(this, false); + // Let AICurl decide if we can process more HTTP requests at the moment or not. - mRequestedSize = mDesiredSize - cur_size; - mRequestedDiscard = mDesiredDiscard; - mRequestedOffset = cur_size; + // AIPerService::approveHTTPRequestFor returns approvement for ONE request. + // This object keeps track of whether or not that is honored. + LLPointer approved = AIPerService::approveHTTPRequestFor(mPerServicePtr, cap_texture); + if (!approved) + { + return false ; //wait. + } - bool res = false; - if (!mUrl.empty()) - { - mLoaded = FALSE; - mGetStatus = 0; - mGetReason.clear(); - LL_DEBUGS("Texture") << "HTTP GET: " << mID << " Offset: " << mRequestedOffset - << " Bytes: " << mRequestedSize - << LL_ENDL; - setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); - mState = WAIT_HTTP_REQ; + mFetcher->removeFromNetworkQueue(this, false); - mFetcher->addToHTTPQueue(mID); + mRequestedSize = mDesiredSize; + mRequestedDiscard = mDesiredDiscard; + mRequestedSize -= cur_size; + mRequestedOffset = cur_size; - if(mRequestedOffset>0) - { - // Texture fetching often issues 'speculative' loads that - // start beyond the end of the actual asset. Some cache/web - // systems, e.g. Varnish, will respond to this not with a - // 416 but with a 200 and the entire asset in the response - // body. By ensuring that we always have a partially - // satisfiable Range request, we avoid that hit to the network. - // We just have to deal with the overlapping data which is made - // somewhat harder by the fact that grid services don't necessarily - // return the Content-Range header on 206 responses. *Sigh* - mRequestedSize++; - mRequestedOffset--; - } - - // Will call callbackHttpGet when curl request completes - AIHTTPHeaders headers("Accept", "image/x-j2c"); - // Call LLHTTPClient::request directly instead of LLHTTPClient::getByteRange, because we want to pass a NULL AIEngine. - if (mRequestedOffset > 0 || mRequestedSize > 0) - { - headers.addHeader("Range", llformat("bytes=%d-%d", mRequestedOffset, mRequestedOffset + mRequestedSize - 1)); - } - LLHTTPClient::request(mUrl, LLHTTPClient::HTTP_GET, NULL, - new HTTPGetResponder(mFetcher, mID, LLTimer::getTotalTime(), mRequestedSize, mRequestedOffset, true), - headers, approved/*,*/ DEBUG_CURLIO_PARAM(debug_off), keep_alive, no_does_authentication, allow_compressed_reply, NULL, 0, NULL); - res = true; - } - if (!res) - { - llwarns << "HTTP GET request failed for " << mID << llendl; - resetFormattedData(); - ++mHTTPFailCount; - return true; // failed - } - // fall through + if (mRequestedOffset) + { + // Texture fetching often issues 'speculative' loads that + // start beyond the end of the actual asset. Some cache/web + // systems, e.g. Varnish, will respond to this not with a + // 416 but with a 200 and the entire asset in the response + // body. By ensuring that we always have a partially + // satisfiable Range request, we avoid that hit to the network. + // We just have to deal with the overlapping data which is made + // somewhat harder by the fact that grid services don't necessarily + // return the Content-Range header on 206 responses. *Sigh* + mRequestedOffset -= 1; + mRequestedSize += 1; } - else //can not use http fetch. + + if (mUrl.empty()) { - return true ; //abort + LL_WARNS() << "HTTP GET request failed for " << mID << LL_ENDL; + resetFormattedData(); + ++mHTTPFailCount; + return true; // failed } + + mRequestedTimer.reset(); + mLoaded = FALSE; + mGetStatus = 0; + mGetReason.clear(); + LL_DEBUGS(LOG_TXT) << "HTTP GET: " << mID << " Offset: " << mRequestedOffset + << " Bytes: " << mRequestedSize + << LL_ENDL; + // Will call callbackHttpGet when curl request completes + AIHTTPHeaders headers("Accept", "image/x-j2c"); + // Call LLHTTPClient::request directly instead of LLHTTPClient::getByteRange, because we want to pass a NULL AIEngine. + if (mRequestedOffset > 0 || mRequestedSize > 0) + { + int const range_end = mRequestedOffset + mRequestedSize - 1; + char const* const range_format = (range_end >= HTTP_REQUESTS_RANGE_END_MAX) ? "bytes=%d-" : "bytes=%d-%d"; + headers.addHeader("Range", llformat(range_format, mRequestedOffset, range_end)); + } + LLHTTPClient::request(mUrl, LLHTTPClient::HTTP_GET, NULL, + new HTTPGetResponder( mFTType, mFetcher, mID, LLTimer::getTotalTime(), mRequestedSize, mRequestedOffset), + headers, approved/*,*/ DEBUG_CURLIO_PARAM(debug_off), keep_alive, no_does_authentication, allow_compressed_reply, NULL, 0, NULL); + + mFetcher->addToHTTPQueue(mID); + recordTextureStart(true); + setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); + setState(WAIT_HTTP_REQ); + + // fall through } if (mState == WAIT_HTTP_REQ) @@ -1348,34 +1504,107 @@ bool LLTextureFetchWorker::doWork(S32 param) if (mRequestedSize < 0) { S32 max_attempts; + switch(mGetStatus) + { +#define HTTP_CASE(name) case name: LL_DEBUGS("TexDebug") << mID << " status = " << mGetStatus << " (" << #name << ")" << " Failcount = " << mHTTPFailCount << LL_ENDL; break; + HTTP_CASE(HTTP_CONTINUE) + HTTP_CASE(HTTP_SWITCHING_PROTOCOLS) + HTTP_CASE(HTTP_OK) + HTTP_CASE(HTTP_CREATED) + HTTP_CASE(HTTP_ACCEPTED) + HTTP_CASE(HTTP_NON_AUTHORITATIVE_INFORMATION) + HTTP_CASE(HTTP_NO_CONTENT) + HTTP_CASE(HTTP_RESET_CONTENT) + HTTP_CASE(HTTP_PARTIAL_CONTENT) + HTTP_CASE(HTTP_MULTIPLE_CHOICES) + HTTP_CASE(HTTP_MOVED_PERMANENTLY) + HTTP_CASE(HTTP_FOUND) + HTTP_CASE(HTTP_SEE_OTHER) + HTTP_CASE(HTTP_NOT_MODIFIED) + HTTP_CASE(HTTP_USE_PROXY) + HTTP_CASE(HTTP_TEMPORARY_REDIRECT) + HTTP_CASE(HTTP_BAD_REQUEST) + HTTP_CASE(HTTP_UNAUTHORIZED) + HTTP_CASE(HTTP_PAYMENT_REQUIRED) + HTTP_CASE(HTTP_FORBIDDEN) + HTTP_CASE(HTTP_NOT_FOUND) + HTTP_CASE(HTTP_METHOD_NOT_ALLOWED) + HTTP_CASE(HTTP_NOT_ACCEPTABLE) + HTTP_CASE(HTTP_PROXY_AUTHENTICATION_REQUIRED) + HTTP_CASE(HTTP_REQUEST_TIME_OUT) + HTTP_CASE(HTTP_CONFLICT) + HTTP_CASE(HTTP_GONE) + HTTP_CASE(HTTP_LENGTH_REQUIRED) + HTTP_CASE(HTTP_PRECONDITION_FAILED) + HTTP_CASE(HTTP_REQUEST_ENTITY_TOO_LARGE) + HTTP_CASE(HTTP_REQUEST_URI_TOO_LARGE) + HTTP_CASE(HTTP_UNSUPPORTED_MEDIA_TYPE) + HTTP_CASE(HTTP_REQUESTED_RANGE_NOT_SATISFIABLE) + HTTP_CASE(HTTP_EXPECTATION_FAILED) + HTTP_CASE(HTTP_INTERNAL_SERVER_ERROR) + HTTP_CASE(HTTP_NOT_IMPLEMENTED) + HTTP_CASE(HTTP_BAD_GATEWAY) + HTTP_CASE(HTTP_SERVICE_UNAVAILABLE) + HTTP_CASE(HTTP_GATEWAY_TIME_OUT) + HTTP_CASE(HTTP_VERSION_NOT_SUPPORTED) + HTTP_CASE(HTTP_INTERNAL_ERROR_LOW_SPEED) + HTTP_CASE(HTTP_INTERNAL_ERROR_CURL_LOCKUP) + HTTP_CASE(HTTP_INTERNAL_ERROR_CURL_BADSOCKET) + HTTP_CASE(HTTP_INTERNAL_ERROR_CURL_TIMEOUT) + HTTP_CASE(HTTP_INTERNAL_ERROR_CURL_OTHER) + HTTP_CASE(HTTP_INTERNAL_ERROR_OTHER) + default: + LL_DEBUGS("TexDebug") << mID << " status = " << mGetStatus << " (?)" << " Failcount = " << mHTTPFailCount << LL_ENDL; break; + } + if (mGetStatus == HTTP_NOT_FOUND || mGetStatus == HTTP_INTERNAL_ERROR_CURL_TIMEOUT || mGetStatus == HTTP_INTERNAL_ERROR_LOW_SPEED) { mHTTPFailCount = max_attempts = 1; // Don't retry if(mGetStatus == HTTP_NOT_FOUND) - llwarns << "Texture missing from server (404): " << mUrl << llendl; + { + if (mFTType != FTT_MAP_TILE) + { + LL_WARNS(LOG_TXT) << "Texture missing from server (404): " << mUrl << LL_ENDL; + } + + if(mWriteToCacheState == NOT_WRITE) //map tiles + { + resetFormattedData(); + setState(DONE); + if (mFTType != FTT_MAP_TILE) + { + LL_WARNS(LOG_TXT) << mID << " abort: WAIT_HTTP_REQ not found" << LL_ENDL; + } + return true; // failed, means no map tile on the empty region. + } + } else if (mGetStatus == HTTP_INTERNAL_ERROR_CURL_TIMEOUT || mGetStatus == HTTP_INTERNAL_ERROR_LOW_SPEED) { if (mGetStatus == HTTP_INTERNAL_ERROR_CURL_TIMEOUT) { - llwarns << "No response from server (HTTP_INTERNAL_ERROR_CURL_TIMEOUT): " << mUrl << llendl; + LL_WARNS() << "No response from server (HTTP_INTERNAL_ERROR_CURL_TIMEOUT): " << mUrl << LL_ENDL; } else { - llwarns << "Slow response from server (HTTP_INTERNAL_ERROR_LOW_SPEED): " << mUrl << llendl; + LL_WARNS() << "Slow response from server (HTTP_INTERNAL_ERROR_LOW_SPEED): " << mUrl << LL_ENDL; } SGHostBlackList::add(mUrl, 60.0, mGetStatus); } //roll back to try UDP if(mCanUseNET) { + LL_DEBUGS("TexDebug") << mID << " falling back to udp mSentRequest=" << mSentRequest << " mCanUseNET = " << mCanUseNET << LL_ENDL; resetFormattedData(); - mState = INIT ; + setState(INIT); mCanUseHTTP = false ; + mUrl.clear(); setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); + LL_DEBUGS("TexDebug") << mID << " .. mSentRequest=" << mSentRequest << " mCanUseNET = " << mCanUseNET << LL_ENDL; return false ; } else { + LL_INFOS("Texture") << mID << " aborted. no udp fallback" << LL_ENDL; // UDP is not an option, we are dead resetFormattedData(); return true; // failed @@ -1390,83 +1619,112 @@ bool LLTextureFetchWorker::doWork(S32 param) max_attempts = mHTTPFailCount+1; // Keep retrying LL_INFOS_ONCE("Texture") << "Texture server busy (503): " << mUrl << LL_ENDL; } + else if (mGetStatus == HTTP_REQUESTED_RANGE_NOT_SATISFIABLE) + { + // Allowed, we'll accept whatever data we have as complete. + mHaveAllData = TRUE; + max_attempts = mHTTPFailCount+1; + } else { const S32 HTTP_MAX_RETRY_COUNT = 3; max_attempts = HTTP_MAX_RETRY_COUNT + 1; ++mHTTPFailCount; - llinfos << "HTTP GET failed for: " << mUrl + LL_INFOS() << "HTTP GET failed for: " << mUrl << " Status: " << mGetStatus << " Reason: '" << mGetReason << "'" - << " Attempt:" << mHTTPFailCount+1 << "/" << max_attempts << llendl; + << " Attempt:" << mHTTPFailCount+1 << "/" << max_attempts << LL_ENDL; } if (mHTTPFailCount >= max_attempts) { + if (mFTType != FTT_SERVER_BAKE) + { + mUrl.clear(); + } // Make max_attempts attempt at decoding what data we have, // then bail forever on this image if (cur_size > 0 && (mHTTPFailCount < (max_attempts+1)) ) { // Use available data mLoadedDiscard = mFormattedImage->getDiscardLevel(); - mState = DECODE_IMAGE; - return false; - } - else + setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); + if (mLoadedDiscard < 0) { - //roll back to try UDP - if(mCanUseNET) - { - resetFormattedData(); - mState = INIT ; - mCanUseHTTP = false ; - setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); - return false ; - } - else - { - // UDP is not an option, we are dead - resetFormattedData(); - mState = DONE; - return true; // failed - } + LL_WARNS(LOG_TXT) << mID << " mLoadedDiscard is " << mLoadedDiscard + << ", should be >=0" << LL_ENDL; } + setState(DECODE_IMAGE); + return false; + } + else + { + //roll back to try UDP + if(mCanUseNET) + { + LL_DEBUGS("TexDebug") << mID << " falling back to udp (2)" << LL_ENDL; + resetFormattedData(); + setState(INIT); + mCanUseHTTP = false ; + setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); + return false ; + } + else + { + // UDP is not an option, we are dead + resetFormattedData(); + setState(DONE); + LL_WARNS(LOG_TXT) << mID << " abort: fail harder" << LL_ENDL; + return true; // failed + } } + } else { - mState = SEND_HTTP_REQ; + setState(SEND_HTTP_REQ); return false; // retry } } + // Clear the url since we're done with the fetch + // Note: mUrl is used to check is fetching is required so failure to clear it will force an http fetch + // next time the texture is requested, even if the data have already been fetched. + if(mWriteToCacheState != NOT_WRITE && mFTType != FTT_SERVER_BAKE) + { + // Why do we want to keep url if NOT_WRITE - is this a proxy for map tiles? + mUrl.clear(); + } + if(mHttpBuffer.empty())//no data received. { //abort. - mState = DONE; + setState(DONE); + LL_WARNS(LOG_TXT) << mID << " abort: no data received" << LL_ENDL; return true; } - S32 total_size(cur_size + mRequestedSize); + S32 append_size(mHttpBuffer.size()); + S32 total_size(cur_size + append_size); S32 src_offset(0); - - if(mRequestedOffset && mRequestedOffset != cur_size) + llassert_always(append_size == mRequestedSize); + if (mHttpReplyOffset && mHttpReplyOffset != cur_size) { // In case of a partial response, our offset may // not be trivially contiguous with the data we have. // Get back into alignment. - if (mRequestedOffset > cur_size) + if ((S32)mHttpReplyOffset > cur_size) { - LL_WARNS("Texture") << "Partial HTTP response produces break in image data for texture " + LL_WARNS(LOG_TXT) << "Partial HTTP response produces break in image data for texture " << mID << ". Aborting load." << LL_ENDL; - mState = DONE; + setState(DONE); return true; } - src_offset = cur_size - mRequestedOffset; + src_offset = cur_size - mHttpReplyOffset; + append_size -= src_offset; total_size -= src_offset; - mRequestedSize -= src_offset; // Make requested values reflect useful part + mRequestedSize -= src_offset; // Make requested values reflect useful part mRequestedOffset += src_offset; } - llassert(total_size == cur_size + mRequestedSize); if (mFormattedImage.isNull()) { @@ -1478,8 +1736,8 @@ bool LLTextureFetchWorker::doWork(S32 param) mFormattedImage = new LLImageJ2C; // default } } - - if (mHaveAllData && mRequestedDiscard == 0) //the image file is fully loaded. + + if (mHaveAllData) //the image file is fully loaded. { mFileSize = total_size; } @@ -1493,16 +1751,24 @@ bool LLTextureFetchWorker::doWork(S32 param) { memcpy(buffer, mFormattedImage->getData(), cur_size); } - if (mRequestedSize > 0) + if (append_size > 0) { - memcpy(buffer + mRequestedOffset, &mHttpBuffer[src_offset], mRequestedSize); // append + memcpy(buffer + cur_size, &mHttpBuffer[src_offset], append_size); } // NOTE: setData releases current data and owns new data (buffer) mFormattedImage->setData(buffer, total_size); // delete temp data std::vector().swap(mHttpBuffer); + mHttpReplySize = 0; + mHttpReplyOffset = 0; + mLoadedDiscard = mRequestedDiscard; - mState = DECODE_IMAGE; + if (mLoadedDiscard < 0) + { + LL_WARNS(LOG_TXT) << mID << " mLoadedDiscard is " << mLoadedDiscard + << ", should be >=0" << LL_ENDL; + } + setState(DECODE_IMAGE); if(mWriteToCacheState != NOT_WRITE) { mWriteToCacheState = SHOULD_WRITE ; @@ -1525,31 +1791,34 @@ bool LLTextureFetchWorker::doWork(S32 param) if (textures_decode_disabled) { // for debug use, don't decode - mState = DONE; + setState(DONE); return true; } if (mDesiredDiscard < 0) { // We aborted, don't decode - mState = DONE; + setState(DONE); + LL_DEBUGS(LOG_TXT) << mID << " DECODE_IMAGE abort: desired discard " << mDesiredDiscard << "<0" << LL_ENDL; return true; } if (mFormattedImage->getDataSize() <= 0) { - //llerrs << "Decode entered with invalid mFormattedImage. ID = " << mID << llendl; + LL_WARNS(LOG_TXT) << "Decode entered with invalid mFormattedImage. ID = " << mID << LL_ENDL; //abort, don't decode - mState = DONE; + setState(DONE); + LL_DEBUGS(LOG_TXT) << mID << " DECODE_IMAGE abort: (mFormattedImage->getDataSize() <= 0)" << LL_ENDL; return true; } if (mLoadedDiscard < 0) { - //llerrs << "Decode entered with invalid mLoadedDiscard. ID = " << mID << llendl; + LL_WARNS(LOG_TXT) << "Decode entered with invalid mLoadedDiscard. ID = " << mID << LL_ENDL; //abort, don't decode - mState = DONE; + setState(DONE); + LL_DEBUGS(LOG_TXT) << mID << " DECODE_IMAGE abort: mLoadedDiscard < 0" << LL_ENDL; return true; } @@ -1559,8 +1828,9 @@ bool LLTextureFetchWorker::doWork(S32 param) S32 discard = mHaveAllData ? 0 : mLoadedDiscard; U32 image_priority = LLWorkerThread::PRIORITY_NORMAL | mWorkPriority; mDecoded = FALSE; - mState = DECODE_IMAGE_UPDATE; - LL_DEBUGS("Texture") << mID << ": Decoding. Bytes: " << mFormattedImage->getDataSize() << " Discard: " << discard + setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); + setState(DECODE_IMAGE_UPDATE); + LL_DEBUGS(LOG_TXT) << mID << ": Decoding. Bytes: " << mFormattedImage->getDataSize() << " Discard: " << discard << " All Data: " << mHaveAllData << LL_ENDL; mDecodeHandle = mFetcher->mImageDecodeThread->decodeImage(mFormattedImage, image_priority, discard, mNeedsAux, new DecodeResponder(mFetcher, mID, this)); @@ -1573,31 +1843,31 @@ bool LLTextureFetchWorker::doWork(S32 param) { if (mDecodedDiscard < 0) { - LL_DEBUGS("Texture") << mID << ": Failed to Decode." << LL_ENDL; + LL_DEBUGS(LOG_TXT) << mID << ": Failed to Decode." << LL_ENDL; if (mCachedSize > 0 && !mInLocalCache && mRetryAttempt == 0) { // Cache file should be deleted, try again -// llwarns << mID << ": Decode of cached file failed (removed), retrying" << llendl; + LL_WARNS(LOG_TXT) << mID << ": Decode of cached file failed (removed), retrying" << LL_ENDL; llassert_always(mDecodeHandle == 0); mFormattedImage = NULL; ++mRetryAttempt; setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); - mState = INIT; + setState(INIT); return false; } else { -// llwarns << "UNABLE TO LOAD TEXTURE: " << mID << " RETRIES: " << mRetryAttempt << llendl; - mState = DONE; // failed +// LL_WARNS() << "UNABLE TO LOAD TEXTURE: " << mID << " RETRIES: " << mRetryAttempt << LL_ENDL; + setState(DONE); // failed } } else { llassert_always(mRawImage.notNull()); - LL_DEBUGS("Texture") << mID << ": Decoded. Discard: " << mDecodedDiscard + LL_DEBUGS(LOG_TXT) << mID << ": Decoded. Discard: " << mDecodedDiscard << " Raw Image: " << llformat("%dx%d",mRawImage->getWidth(),mRawImage->getHeight()) << LL_ENDL; setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); - mState = WRITE_TO_CACHE; + setState(WRITE_TO_CACHE); } // fall through } @@ -1613,7 +1883,7 @@ bool LLTextureFetchWorker::doWork(S32 param) { // If we're in a local cache or we didn't actually receive any new data, // or we failed to load anything, skip - mState = DONE; + setState(DONE); return false; } S32 datasize = mFormattedImage->getDataSize(); @@ -1632,7 +1902,7 @@ bool LLTextureFetchWorker::doWork(S32 param) setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it U32 cache_priority = mWorkPriority; mWritten = FALSE; - mState = WAIT_ON_WRITE; + setState(WAIT_ON_WRITE); ++mCacheWriteCount; CacheWriteResponder* responder = new CacheWriteResponder(mFetcher, mID); mCacheWriteHandle = mFetcher->mTextureCache->writeToCache(mID, cache_priority, @@ -1645,7 +1915,7 @@ bool LLTextureFetchWorker::doWork(S32 param) { if (writeToCacheComplete()) { - mState = DONE; + setState(DONE); // fall through } else @@ -1666,7 +1936,10 @@ bool LLTextureFetchWorker::doWork(S32 param) if (mDecodedDiscard >= 0 && mDesiredDiscard < mDecodedDiscard) { // More data was requested, return to INIT - mState = INIT; + setState(INIT); + LL_DEBUGS(LOG_TXT) << mID << " more data requested, returning to INIT: " + << " mDecodedDiscard " << mDecodedDiscard << ">= 0 && mDesiredDiscard " << mDesiredDiscard + << "<" << " mDecodedDiscard " << mDecodedDiscard << LL_ENDL; setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); return false; } @@ -1818,23 +2091,22 @@ bool LLTextureFetchWorker::processSimulatorPackets() ////////////////////////////////////////////////////////////////////////////// -S32 LLTextureFetchWorker::callbackHttpGet(const LLChannelDescriptors& channels, +S32 LLTextureFetchWorker::callbackHttpGet(U32 offset, U32 length, + const LLChannelDescriptors& channels, const LLHTTPClient::ResponderBase::buffer_ptr_t& buffer, bool partial, bool success) { S32 data_size = 0 ; - LLMutexLock lock(&mWorkMutex); - if (mState != WAIT_HTTP_REQ) { - llwarns << "callbackHttpGet for unrequested fetch worker: " << mID - << " req=" << mSentRequest << " state= " << mState << llendl; + LL_WARNS(LOG_TXT) << "callbackHttpGet for unrequested fetch worker: " << mID + << " req=" << mSentRequest << " state= " << mState << LL_ENDL; return data_size; } if (mLoaded) { - llwarns << "Duplicate callback for " << mID.asString() << llendl; + LL_WARNS(LOG_TXT) << "Duplicate callback for " << mID.asString() << LL_ENDL; return data_size; // ignore duplicate callback } if (success) @@ -1842,7 +2114,7 @@ S32 LLTextureFetchWorker::callbackHttpGet(const LLChannelDescriptors& channels, // get length of stream: data_size = buffer->countAfter(channels.in(), NULL); - LL_DEBUGS("Texture") << "HTTP RECEIVED: " << mID.asString() << " Bytes: " << data_size << LL_ENDL; + LL_DEBUGS(LOG_TXT) << "HTTP RECEIVED: " << mID.asString() << " Bytes: " << data_size << LL_ENDL; if (data_size > 0) { LLViewerStatsRecorder::instance().textureFetch(data_size); @@ -1850,16 +2122,52 @@ S32 LLTextureFetchWorker::callbackHttpGet(const LLChannelDescriptors& channels, llassert(mHttpBuffer.empty()); mHttpBuffer.resize(data_size); buffer->readAfter(channels.in(), NULL, &mHttpBuffer[0], data_size); - if (data_size < mRequestedSize && mRequestedDiscard == 0) + + if (partial) + { + if (! offset && ! length) + { + // This is the case where we receive a 206 status but + // there wasn't a useful Content-Range header in the response. + // This could be because it was badly formatted but is more + // likely due to capabilities services which scrub headers + // from responses. Assume we got what we asked for... + mHttpReplySize = data_size; + mHttpReplyOffset = mRequestedOffset; + } + else + { + mHttpReplySize = length; + mHttpReplyOffset = offset; + } + } + + if (! partial) + { + // Response indicates this is the entire asset regardless + // of our asking for a byte range. Mark it so and drop + // any partial data we might have so that the current + // response body becomes the entire dataset. + if (data_size <= mRequestedOffset) + { + LL_WARNS(LOG_TXT) << "Fetched entire texture " << mID + << " when it was expected to be marked complete. mImageSize: " + << mFileSize << " datasize: " << mFormattedImage->getDataSize() + << LL_ENDL; + } + mHaveAllData = TRUE; + llassert_always(mDecodeHandle == 0); + mFormattedImage = NULL; // discard any previous data we had + } + else if (data_size < mRequestedSize/* && mRequestedDiscard == 0*/) { mHaveAllData = TRUE; } else if (data_size > mRequestedSize) { // *TODO: This shouldn't be happening any more - llwarns << "data_size = " << data_size << " > requested: " << mRequestedSize << llendl; + LL_WARNS(LOG_TXT) << "data_size = " << data_size << " > requested: " << mRequestedSize << LL_ENDL; mHaveAllData = TRUE; - mRequestedOffset = 0; llassert_always(mDecodeHandle == 0); mFormattedImage = NULL; // discard any previous data we had } @@ -1891,7 +2199,7 @@ void LLTextureFetchWorker::callbackCacheRead(bool success, LLImageFormatted* ima LLMutexLock lock(&mWorkMutex); if (mState != LOAD_FROM_TEXTURE_CACHE) { -// llwarns << "Read callback for " << mID << " with state = " << mState << llendl; +// LL_WARNS() << "Read callback for " << mID << " with state = " << mState << LL_ENDL; return; } if (success) @@ -1915,7 +2223,7 @@ void LLTextureFetchWorker::callbackCacheWrite(bool success) LLMutexLock lock(&mWorkMutex); if (mState != WAIT_ON_WRITE) { -// llwarns << "Write callback for " << mID << " with state = " << mState << llendl; +// LL_WARNS() << "Write callback for " << mID << " with state = " << mState << LL_ENDL; return; } mWritten = TRUE; @@ -1933,7 +2241,7 @@ void LLTextureFetchWorker::callbackDecoded(bool success, LLImageRaw* raw, LLImag } if (mState != DECODE_IMAGE_UPDATE) { -// llwarns << "Decode callback for " << mID << " with state = " << mState << llendl; +// LL_WARNS() << "Decode callback for " << mID << " with state = " << mState << LL_ENDL; mDecodeHandle = 0; return; } @@ -1946,24 +2254,24 @@ void LLTextureFetchWorker::callbackDecoded(bool success, LLImageRaw* raw, LLImag mRawImage = raw; mAuxImage = aux; mDecodedDiscard = mFormattedImage->getDiscardLevel(); - LL_DEBUGS("Texture") << mID << ": Decode Finished. Discard: " << mDecodedDiscard + LL_DEBUGS(LOG_TXT) << mID << ": Decode Finished. Discard: " << mDecodedDiscard << " Raw Image: " << llformat("%dx%d",mRawImage->getWidth(),mRawImage->getHeight()) << LL_ENDL; } else { if (mFormattedImage.notNull()) { - LL_WARNS("Texture") << "DECODE FAILED: id = " << mID << ", Discard = " << (S32)mFormattedImage->getDiscardLevel() << LL_ENDL; + LL_WARNS(LOG_TXT) << "DECODE FAILED: id = " << mID << ", Discard = " << (S32)mFormattedImage->getDiscardLevel() << LL_ENDL; } else { - LL_WARNS("Texture") << "DECODE FAILED: id = " << mID << ", mFormattedImage is Null!" << LL_ENDL; + LL_WARNS(LOG_TXT) << "DECODE FAILED: id = " << mID << ", mFormattedImage is Null!" << LL_ENDL; } removeFromCache(); mDecodedDiscard = -1; // Redundant, here for clarity and paranoia } mDecoded = TRUE; -// llinfos << mID << " : DECODE COMPLETE " << llendl; +// LL_INFOS() << mID << " : DECODE COMPLETE " << LL_ENDL; setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); mCacheReadTime = mCacheReadTimer.getElapsedTimeF32(); } @@ -1995,7 +2303,7 @@ bool LLTextureFetchWorker::writeToCacheComplete() // Threads: Ttf void LLTextureFetchWorker::recordTextureStart(bool is_http) { - if (! mMetricsStartTime) + if (! mMetricsStartTime.value()) { mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp(); } @@ -2008,13 +2316,13 @@ void LLTextureFetchWorker::recordTextureStart(bool is_http) // Threads: Ttf void LLTextureFetchWorker::recordTextureDone(bool is_http) { - if (mMetricsStartTime) + if (mMetricsStartTime.value()) { LLViewerAssetStatsFF::record_response_thread1(LLViewerAssetType::AT_TEXTURE, is_http, LLImageBase::TYPE_AVATAR_BAKE == mType, LLViewerAssetStatsFF::get_timestamp() - mMetricsStartTime); - mMetricsStartTime = 0; + mMetricsStartTime = (U32Seconds)0; } LLViewerAssetStatsFF::record_dequeue_thread1(LLViewerAssetType::AT_TEXTURE, is_http, @@ -2038,32 +2346,41 @@ LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* image mTotalCacheReadCount(0U), mTotalCacheWriteCount(0U) { - mTextureInfo.setUpLogging(gSavedSettings.getBOOL("LogTextureDownloadsToViewerLog"), gSavedSettings.getBOOL("LogTextureDownloadsToSimulator"), gSavedSettings.getU32("TextureLoggingThreshold")); + mTextureInfo.setUpLogging(gSavedSettings.getBOOL("LogTextureDownloadsToViewerLog"), gSavedSettings.getBOOL("LogTextureDownloadsToSimulator"), U32Bytes(gSavedSettings.getU32("TextureLoggingThreshold"))); } LLTextureFetch::~LLTextureFetch() { clearDeleteList() ; + while (! mCommands.empty()) + { + TFRequest * req(mCommands.front()); + mCommands.pop_front(); + delete req; + } // ~LLQueuedThread() called here } -bool LLTextureFetch::createRequest(const std::string& url, const LLUUID& id, const LLHost& host, F32 priority, +bool LLTextureFetch::createRequest(FTType f_type, const std::string& url, const LLUUID& id, const LLHost& host, F32 priority, S32 w, S32 h, S32 c, S32 desired_discard, bool needs_aux, bool can_use_http) { if (mDebugPause) { return false; } - - LLTextureFetchWorker* worker = getWorker(id); + if (f_type == FTT_SERVER_BAKE) + { + LL_DEBUGS("Avatar") << " requesting " << id << " " << w << "x" << h << " discard " << desired_discard << " type " << f_type << LL_ENDL; + } + LLTextureFetchWorker* worker = getWorker(id) ; if (worker) { if (worker->mHost != host) { - llwarns << "LLTextureFetch::createRequest " << id << " called with multiple hosts: " - << host << " != " << worker->mHost << llendl; + LL_WARNS(LOG_TXT) << "LLTextureFetch::createRequest " << id << " called with multiple hosts: " + << host << " != " << worker->mHost << LL_ENDL; removeRequest(worker, true); worker = NULL; return false; @@ -2072,10 +2389,23 @@ bool LLTextureFetch::createRequest(const std::string& url, const LLUUID& id, con S32 desired_size; std::string exten = gDirUtilp->getExtension(url); - if (!url.empty() && (!exten.empty() && LLImageBase::getCodecFromExtension(exten) != IMG_CODEC_J2C)) + //if (f_type == FTT_SERVER_BAKE) + if ((f_type == FTT_SERVER_BAKE) && !url.empty() && !exten.empty() && (LLImageBase::getCodecFromExtension(exten) != IMG_CODEC_J2C)) + { + // SH-4030: This case should be redundant with the following one, just + // breaking it out here to clarify that it's intended behavior. + llassert(!url.empty() && (!exten.empty() && LLImageBase::getCodecFromExtension(exten) != IMG_CODEC_J2C)); + + // Do full requests for baked textures to reduce interim blurring. + LL_DEBUGS(LOG_TXT) << "full request for " << id << " texture is FTT_SERVER_BAKE" << LL_ENDL; + desired_size = MAX_IMAGE_DATA_SIZE; + desired_discard = 0; + } + else if (!url.empty() && (!exten.empty() && LLImageBase::getCodecFromExtension(exten) != IMG_CODEC_J2C)) { + LL_DEBUGS(LOG_TXT) << "full request for " << id << " exten is not J2C: " << exten << LL_ENDL; // Only do partial requests for J2C at the moment - //llinfos << "Merov : LLTextureFetch::createRequest(), blocking fetch on " << url << llendl; + //LL_INFOS() << "Merov : LLTextureFetch::createRequest(), blocking fetch on " << url << LL_ENDL; desired_size = MAX_IMAGE_DATA_SIZE; desired_discard = 0; } @@ -2115,8 +2445,8 @@ bool LLTextureFetch::createRequest(const std::string& url, const LLUUID& id, con worker->setCanUseHTTP(can_use_http) ; if (!worker->haveWork()) { - worker->mState = LLTextureFetchWorker::INIT; - worker->unlockWorkMutex(); + worker->setState(LLTextureFetchWorker::INIT); + worker->unlockWorkMutex(); // -Mw worker->addWork(0, LLWorkerThread::PRIORITY_HIGH | worker->mWorkPriority); } else @@ -2126,7 +2456,7 @@ bool LLTextureFetch::createRequest(const std::string& url, const LLUUID& id, con } else { - worker = new LLTextureFetchWorker(this, url, id, host, priority, desired_discard, desired_size); + worker = new LLTextureFetchWorker(this, f_type, url, id, host, priority, desired_discard, desired_size); lockQueue() ; mRequestMap[id] = worker; unlockQueue() ; @@ -2137,8 +2467,9 @@ bool LLTextureFetch::createRequest(const std::string& url, const LLUUID& id, con worker->setCanUseHTTP(can_use_http) ; worker->unlockWorkMutex(); } - - //llinfos << "REQUESTED: " << id << " Discard: " << desired_discard << llendl; + + LL_DEBUGS(LOG_TXT) << "REQUESTED: " << id << " f_type " << fttype_to_string(f_type) + << " Discard: " << desired_discard << " size " << desired_size << LL_ENDL; return true; } @@ -2241,6 +2572,17 @@ S32 LLTextureFetch::getNumRequests() return size ; } +// Threads: T* +S32 LLTextureFetch::getNumHTTPRequests() +{ + mNetworkQueueMutex.lock(); // +Mfq + S32 size = (S32)mHTTPTextureQueue.size(); + mNetworkQueueMutex.unlock(); // -Mfq + + return size; +} + +// Threads: T* U32 LLTextureFetch::getTotalNumHTTPRequests() { mNetworkQueueMutex.lock() ; @@ -2286,7 +2628,7 @@ bool LLTextureFetch::getRequestFinished(const LLUUID& id, S32& discard_level, // Should only happen if we set mDebugPause... if (!mDebugPause) { -// llwarns << "Adding work for inactive worker: " << id << llendl; +// LL_WARNS() << "Adding work for inactive worker: " << id << LL_ENDL; worker->addWork(0, LLWorkerThread::PRIORITY_HIGH | worker->mWorkPriority); } } @@ -2353,8 +2695,9 @@ S32 LLTextureFetch::getPending() LLMutexLock lock(&mQueueMutex); res = mRequestQueue.size(); - } - unlockData(); + res += mCommands.size(); + } // -Mfq + unlockData(); // -Ct return res; } @@ -2445,10 +2788,10 @@ void LLTextureFetch::startThread() // Threads: Ttf void LLTextureFetch::endThread() { - LL_INFOS("Texture") << "CacheReads: " << mTotalCacheReadCount - << ", CacheWrites: " << mTotalCacheWriteCount - << ", TotalHTTPReq: " << getTotalNumHTTPRequests() - << LL_ENDL; + LL_INFOS(LOG_TXT) << "CacheReads: " << mTotalCacheReadCount + << ", CacheWrites: " << mTotalCacheWriteCount + << ", TotalHTTPReq: " << getTotalNumHTTPRequests() + << LL_ENDL; } // Threads: Ttf @@ -2473,7 +2816,7 @@ void LLTextureFetch::threadedUpdate() S32 q = mCurlGetRequest->getQueued(); if (q > 0) { - llinfos << "Queued gets: " << q << llendl; + LL_INFOS(LOG_TXT) << "Queued gets: " << q << LL_ENDL; info_timer.reset(); } } @@ -2520,11 +2863,12 @@ void LLTextureFetch::sendRequestListToSimulators() mNetworkQueue.erase(curiter); continue; } - if ((req->mState != LLTextureFetchWorker::LOAD_FROM_NETWORK) && + if ((req->mState != LLTextureFetchWorker::SEND_UDP_REQ) && + (req->mState != LLTextureFetchWorker::WAIT_UDP_REQ) && //Workers remain in the queue. May be re-requested upon timeout. (req->mState != LLTextureFetchWorker::LOAD_FROM_SIMULATOR)) { // We already received our URL, remove from the queue - llwarns << "Worker: " << req->mID << " in mNetworkQueue but in wrong state: " << req->mState << llendl; + LL_WARNS(LOG_TXT) << "Worker: " << req->mID << " in mNetworkQueue but in wrong state: " << req->mState << LL_ENDL; mNetworkQueue.erase(curiter); continue; } @@ -2592,8 +2936,8 @@ void LLTextureFetch::sendRequestListToSimulators() gMessageSystem->addF32Fast(_PREHASH_DownloadPriority, req->mImagePriority); gMessageSystem->addU32Fast(_PREHASH_Packet, packet); gMessageSystem->addU8Fast(_PREHASH_Type, req->mType); -// llinfos << "IMAGE REQUEST: " << req->mID << " Discard: " << req->mDesiredDiscard -// << " Packet: " << packet << " Priority: " << req->mImagePriority << llendl; +// LL_INFOS() << "IMAGE REQUEST: " << req->mID << " Discard: " << req->mDesiredDiscard +// << " Packet: " << packet << " Priority: " << req->mImagePriority << LL_ENDL; static LLCachedControl log_to_viewer_log(gSavedSettings,"LogTextureDownloadsToViewerLog"); static LLCachedControl log_to_sim(gSavedSettings,"LogTextureDownloadsToSimulator"); @@ -2614,7 +2958,7 @@ void LLTextureFetch::sendRequestListToSimulators() sim_request_count++; if (sim_request_count >= IMAGES_PER_REQUEST) { -// llinfos << "REQUESTING " << sim_request_count << " IMAGES FROM HOST: " << host.getIPString() << llendl; +// LL_INFOS() << "REQUESTING " << sim_request_count << " IMAGES FROM HOST: " << host.getIPString() << LL_ENDL; gMessageSystem->sendSemiReliable(host, NULL, NULL); sim_request_count = 0; @@ -2623,7 +2967,7 @@ void LLTextureFetch::sendRequestListToSimulators() } if (gMessageSystem && sim_request_count > 0 && sim_request_count < IMAGES_PER_REQUEST) { -// llinfos << "REQUESTING " << sim_request_count << " IMAGES FROM HOST: " << host.getIPString() << llendl; +// LL_INFOS() << "REQUESTING " << sim_request_count << " IMAGES FROM HOST: " << host.getIPString() << LL_ENDL; gMessageSystem->sendSemiReliable(host, NULL, NULL); sim_request_count = 0; } @@ -2659,7 +3003,7 @@ void LLTextureFetch::sendRequestListToSimulators() gMessageSystem->addF32Fast(_PREHASH_DownloadPriority, 0); gMessageSystem->addU32Fast(_PREHASH_Packet, 0); gMessageSystem->addU8Fast(_PREHASH_Type, 0); -// llinfos << "CANCELING IMAGE REQUEST: " << (*iter2) << llendl; +// LL_INFOS() << "CANCELING IMAGE REQUEST: " << (*iter2) << LL_ENDL; request_count++; if (request_count >= IMAGES_PER_REQUEST) @@ -2685,12 +3029,12 @@ bool LLTextureFetchWorker::insertPacket(S32 index, U8* data, S32 size) mRequestedTimer.reset(); if (index >= mTotalPackets) { -// llwarns << "Received Image Packet " << index << " > max: " << mTotalPackets << " for image: " << mID << llendl; +// LL_WARNS() << "Received Image Packet " << index << " > max: " << mTotalPackets << " for image: " << mID << LL_ENDL; return false; } if (index > 0 && index < mTotalPackets-1 && size != MAX_IMG_PACKET_SIZE) { -// llwarns << "Received bad sized packet: " << index << ", " << size << " != " << MAX_IMG_PACKET_SIZE << " for image: " << mID << llendl; +// LL_WARNS() << "Received bad sized packet: " << index << ", " << size << " != " << MAX_IMG_PACKET_SIZE << " for image: " << mID << LL_ENDL; return false; } @@ -2700,7 +3044,7 @@ bool LLTextureFetchWorker::insertPacket(S32 index, U8* data, S32 size) } else if (mPackets[index] != NULL) { -// llwarns << "Received duplicate packet: " << index << " for image: " << mID << llendl; +// LL_WARNS() << "Received duplicate packet: " << index << " for image: " << mID << LL_ENDL; return false; } @@ -2712,6 +3056,34 @@ bool LLTextureFetchWorker::insertPacket(S32 index, U8* data, S32 size) return true; } +void LLTextureFetchWorker::setState(e_state new_state) +{ + /* + static const char* e_state_name[] = + { + "INVALID", + "INIT", + "LOAD_FROM_TEXTURE_CACHE", + "CACHE_POST", + "LOAD_FROM_NETWORK", + "LOAD_FROM_SIMULATOR", + "SEND_UDP_REQ", + "WAIT_UDP_REQ", + "SEND_HTTP_REQ", + "WAIT_HTTP_REQ", + "DECODE_IMAGE", + "DECODE_IMAGE_UPDATE", + "WRITE_TO_CACHE", + "WAIT_ON_WRITE", + "DONE" + }; + */ + //if(mState != new_state) + // LL_INFOS("Texture") << "id: " << mID << " disc: " << mDesiredDiscard << " sz: " << mDesiredSize << " state: " << e_state_name[mState] << " => " << e_state_name[new_state] << LL_ENDL; + mState = new_state; +} + +// Threads: T* bool LLTextureFetch::receiveImageHeader(const LLHost& host, const LLUUID& id, U8 codec, U16 packets, U32 totalbytes, U16 data_size, U8* data) { @@ -2722,26 +3094,26 @@ bool LLTextureFetch::receiveImageHeader(const LLHost& host, const LLUUID& id, U8 if (!worker) { -// llwarns << "Received header for non active worker: " << id << llendl; +// LL_WARNS() << "Received header for non active worker: " << id << LL_ENDL; res = false; } - else if (worker->mState != LLTextureFetchWorker::LOAD_FROM_NETWORK || + else if (worker->mState != LLTextureFetchWorker::WAIT_UDP_REQ || worker->mSentRequest != LLTextureFetchWorker::SENT_SIM) { -// llwarns << "receiveImageHeader for worker: " << id +// LL_WARNS() << "receiveImageHeader for worker: " << id // << " in state: " << LLTextureFetchWorker::sStateDescs[worker->mState] -// << " sent: " << worker->mSentRequest << llendl; +// << " sent: " << worker->mSentRequest << LL_ENDL; res = false; } else if (worker->mLastPacket != -1) { // check to see if we've gotten this packet before -// llwarns << "Received duplicate header for: " << id << llendl; +// LL_WARNS() << "Received duplicate header for: " << id << LL_ENDL; res = false; } else if (!data_size) { -// llwarns << "Img: " << id << ":" << " Empty Image Header" << llendl; +// LL_WARNS() << "Img: " << id << ":" << " Empty Image Header" << LL_ENDL; res = false; } if (!res) @@ -2762,14 +3134,14 @@ bool LLTextureFetch::receiveImageHeader(const LLHost& host, const LLUUID& id, U8 // Copy header data into image object worker->mImageCodec = codec; worker->mTotalPackets = packets; - worker->mFileSize = (S32)totalbytes; - llassert_always(totalbytes > 0); - llassert_always(data_size == FIRST_PACKET_SIZE || data_size == worker->mFileSize); - res = worker->insertPacket(0, data, data_size); - worker->setPriority(LLWorkerThread::PRIORITY_HIGH | worker->mWorkPriority); - worker->mState = LLTextureFetchWorker::LOAD_FROM_SIMULATOR; - worker->unlockWorkMutex(); - return res; + worker->mFileSize = (S32)totalbytes; + llassert_always(totalbytes > 0); + llassert_always(data_size == FIRST_PACKET_SIZE || data_size == worker->mFileSize); + res = worker->insertPacket(0, data, data_size); + worker->setPriority(LLWorkerThread::PRIORITY_HIGH | worker->mWorkPriority); + worker->setState(LLTextureFetchWorker::LOAD_FROM_SIMULATOR); + worker->unlockWorkMutex(); // -Mw + return res; } bool LLTextureFetch::receiveImagePacket(const LLHost& host, const LLUUID& id, U16 packet_num, U16 data_size, U8* data) @@ -2781,17 +3153,17 @@ bool LLTextureFetch::receiveImagePacket(const LLHost& host, const LLUUID& id, U1 if (!worker) { -// llwarns << "Received packet " << packet_num << " for non active worker: " << id << llendl; +// LL_WARNS() << "Received packet " << packet_num << " for non active worker: " << id << LL_ENDL; res = false; } else if (worker->mLastPacket == -1) { -// llwarns << "Received packet " << packet_num << " before header for: " << id << llendl; +// LL_WARNS() << "Received packet " << packet_num << " before header for: " << id << LL_ENDL; res = false; } else if (!data_size) { -// llwarns << "Img: " << id << ":" << " Empty Image Header" << llendl; +// LL_WARNS() << "Img: " << id << ":" << " Empty Image Header" << LL_ENDL; res = false; } if (!res) @@ -2812,15 +3184,15 @@ bool LLTextureFetch::receiveImagePacket(const LLHost& host, const LLUUID& id, U1 res = worker->insertPacket(packet_num, data, data_size); if ((worker->mState == LLTextureFetchWorker::LOAD_FROM_SIMULATOR) || - (worker->mState == LLTextureFetchWorker::LOAD_FROM_NETWORK)) + (worker->mState == LLTextureFetchWorker::WAIT_UDP_REQ)) { worker->setPriority(LLWorkerThread::PRIORITY_HIGH | worker->mWorkPriority); - worker->mState = LLTextureFetchWorker::LOAD_FROM_SIMULATOR; + worker->setState(LLTextureFetchWorker::LOAD_FROM_SIMULATOR); } else { -// llwarns << "receiveImagePacket " << packet_num << "/" << worker->mLastPacket << " for worker: " << id -// << " in state: " << LLTextureFetchWorker::sStateDescs[worker->mState] << llendl; +// LL_WARNS() << "receiveImagePacket " << packet_num << "/" << worker->mLastPacket << " for worker: " << id +// << " in state: " << LLTextureFetchWorker::sStateDescs[worker->mState] << LL_ENDL; removeFromNetworkQueue(worker, true); // failsafe } @@ -2831,7 +3203,7 @@ bool LLTextureFetch::receiveImagePacket(const LLHost& host, const LLUUID& id, U1 if (log_to_viewer_log || log_to_sim) { - U64 timeNow = LLTimer::getTotalTime(); + U64Microseconds timeNow = LLTimer::getTotalTime(); mTextureInfo.setRequestSize(id, worker->mFileSize); mTextureInfo.setRequestCompleteTimeAndLog(id, timeNow); } @@ -2909,25 +3281,25 @@ S32 LLTextureFetch::getFetchState(const LLUUID& id, F32& data_progress_p, F32& r void LLTextureFetch::dump() { - llinfos << "LLTextureFetch REQUESTS:" << llendl; + LL_INFOS(LOG_TXT) << "LLTextureFetch REQUESTS:" << LL_ENDL; for (request_queue_t::iterator iter = mRequestQueue.begin(); iter != mRequestQueue.end(); ++iter) { LLQueuedThread::QueuedRequest* qreq = *iter; LLWorkerThread::WorkRequest* wreq = (LLWorkerThread::WorkRequest*)qreq; LLTextureFetchWorker* worker = (LLTextureFetchWorker*)wreq->getWorkerClass(); - llinfos << " ID: " << worker->mID + LL_INFOS(LOG_TXT) << " ID: " << worker->mID << " PRI: " << llformat("0x%08x",wreq->getPriority()) << " STATE: " << worker->sStateDescs[worker->mState] - << llendl; + << LL_ENDL; } - llinfos << "LLTextureFetch ACTIVE_HTTP:" << llendl; + LL_INFOS(LOG_TXT) << "LLTextureFetch ACTIVE_HTTP:" << LL_ENDL; for (queue_t::const_iterator iter(mHTTPTextureQueue.begin()); mHTTPTextureQueue.end() != iter; ++iter) { - llinfos << " ID: " << (*iter) << llendl; + LL_INFOS(LOG_TXT) << " ID: " << (*iter) << LL_ENDL; } } @@ -3003,7 +3375,7 @@ LLTextureFetch::TFRequest * LLTextureFetch::cmdDequeue() if (! mCommands.empty()) { ret = mCommands.front(); - mCommands.erase(mCommands.begin()); + mCommands.pop_front(); } unlockQueue(); // -Mfq @@ -3045,17 +3417,17 @@ class AssetReportHandler : public LLHTTPClient::ResponderWithCompleted public: // Threads: Ttf - /*virtual*/ virtual void completed(U32 status, std::string const& reason, LLSD const& content) + /*virtual*/ virtual void httpCompleted(void) { - if (status) + if (mStatus) { - LL_WARNS("Texture") << "Successfully delivered asset metrics to grid." + LL_DEBUGS("Texture") << "Successfully delivered asset metrics to grid." << LL_ENDL; } else { LL_WARNS("Texture") << "Error delivering asset metrics to grid. Reason: " - << status << LL_ENDL; + << mStatus << LL_ENDL; } } diff --git a/indra/newview/lltexturefetch.h b/indra/newview/lltexturefetch.h index 4062c310a3..58dcadf96e 100644 --- a/indra/newview/lltexturefetch.h +++ b/indra/newview/lltexturefetch.h @@ -43,6 +43,7 @@ #include "lltextureinfo.h" #include "llapr.h" #include "llstat.h" +#include "llviewertexture.h" class LLViewerTexture; class LLTextureFetchWorker; @@ -68,7 +69,7 @@ class LLTextureFetch : public LLWorkerThread void shutDownTextureCacheThread() ; //called in the main thread after the TextureCacheThread shuts down. void shutDownImageDecodeThread() ; //called in the main thread after the ImageDecodeThread shuts down. - bool createRequest(const std::string& url, const LLUUID& id, const LLHost& host, F32 priority, + bool createRequest(FTType f_type, const std::string& url, const LLUUID& id, const LLHost& host, F32 priority, S32 w, S32 h, S32 c, S32 discard, bool needs_aux, bool can_use_http); void deleteRequest(const LLUUID& id, bool cancel); void deleteAllRequests(); @@ -84,8 +85,14 @@ class LLTextureFetch : public LLWorkerThread S32 getFetchState(const LLUUID& id, F32& decode_progress_p, F32& requested_priority_p, U32& fetch_priority_p, F32& fetch_dtime_p, F32& request_dtime_p, bool& can_use_http); void dump(); - S32 getNumRequests() ; - U32 getTotalNumHTTPRequests() ; + // Threads: T* + S32 getNumRequests(); + + // Threads: T* + S32 getNumHTTPRequests(); + + // Threads: T* + U32 getTotalNumHTTPRequests(); // Public for access by callbacks S32 getPending(); @@ -156,10 +163,10 @@ class LLTextureFetch : public LLWorkerThread map_t mRequestMap; // Set of requests that require network data - typedef std::set queue_t; + typedef uuid_set_t queue_t; queue_t mNetworkQueue; queue_t mHTTPTextureQueue; - typedef std::map > cancel_queue_t; + typedef std::map cancel_queue_t; cancel_queue_t mCancelQueue; LLTextureInfo mTextureInfo; @@ -170,7 +177,7 @@ class LLTextureFetch : public LLWorkerThread // is logically tied to LLQueuedThread's list of // QueuedRequest instances and so must be covered by the // same locks. - typedef std::vector command_queue_t; + typedef std::deque command_queue_t; command_queue_t mCommands; // If true, modifies some behaviors that help with QA tasks. diff --git a/indra/newview/lltextureinfo.cpp b/indra/newview/lltextureinfo.cpp index 672a36a8bd..e115021d30 100644 --- a/indra/newview/lltextureinfo.cpp +++ b/indra/newview/lltextureinfo.cpp @@ -44,17 +44,17 @@ LLTextureInfo::LLTextureInfo() : mTextureDownloadsStarted(0), mTextureDownloadsCompleted(0), mTextureDownloadProtocol("NONE"), - mTextureLogThreshold(100 * 1024), + mTextureLogThreshold(LLUnits::Kilobytes::fromValue(100)), mCurrentStatsBundleStartTime(0) { mTextures.clear(); } -void LLTextureInfo::setUpLogging(bool writeToViewerLog, bool sendToSim, U32 textureLogThreshold) +void LLTextureInfo::setUpLogging(bool writeToViewerLog, bool sendToSim, U32Bytes textureLogThreshold) { mLogTextureDownloadsToViewerLog = writeToViewerLog; mLogTextureDownloadsToSimulator = sendToSim; - mTextureLogThreshold = textureLogThreshold; + mTextureLogThreshold = U32Bytes(textureLogThreshold); } LLTextureInfo::~LLTextureInfo() @@ -82,15 +82,7 @@ U32 LLTextureInfo::getTextureInfoMapSize() bool LLTextureInfo::has(const LLUUID& id) { - std::map::iterator iterator = mTextures.find(id); - if (iterator == mTextures.end()) - { - return false; - } - else - { - return true; - } + return mTextures.end() != mTextures.find(id); } void LLTextureInfo::setRequestStartTime(const LLUUID& id, U64 startTime) @@ -99,7 +91,7 @@ void LLTextureInfo::setRequestStartTime(const LLUUID& id, U64 startTime) { addRequest(id); } - mTextures[id]->mStartTime = startTime; + mTextures[id]->mStartTime = (U64Microseconds)startTime; mTextureDownloadsStarted++; } @@ -109,7 +101,7 @@ void LLTextureInfo::setRequestSize(const LLUUID& id, U32 size) { addRequest(id); } - mTextures[id]->mSize = size; + mTextures[id]->mSize = (U32Bytes)size; } void LLTextureInfo::setRequestOffset(const LLUUID& id, U32 offset) @@ -130,16 +122,19 @@ void LLTextureInfo::setRequestType(const LLUUID& id, LLTextureInfoDetails::LLReq mTextures[id]->mType = type; } -void LLTextureInfo::setRequestCompleteTimeAndLog(const LLUUID& id, U64 completeTime) +void LLTextureInfo::setRequestCompleteTimeAndLog(const LLUUID& id, U64Microseconds completeTime) { if (!has(id)) { addRequest(id); } - mTextures[id]->mCompleteTime = completeTime; + + LLTextureInfoDetails& details = *mTextures[id]; + + details.mCompleteTime = completeTime; std::string protocol = "NONE"; - switch(mTextures[id]->mType) + switch(details.mType) { case LLTextureInfoDetails::REQUEST_TYPE_HTTP: protocol = "HTTP"; @@ -156,21 +151,21 @@ void LLTextureInfo::setRequestCompleteTimeAndLog(const LLUUID& id, U64 completeT if (mLogTextureDownloadsToViewerLog) { - llinfos << "texture=" << id - << " start=" << mTextures[id]->mStartTime - << " end=" << mTextures[id]->mCompleteTime - << " size=" << mTextures[id]->mSize - << " offset=" << mTextures[id]->mOffset - << " length_in_ms=" << (mTextures[id]->mCompleteTime - mTextures[id]->mStartTime) / 1000 - << " protocol=" << protocol - << llendl; + LL_INFOS() << "texture=" << id + << " start=" << details.mStartTime + << " end=" << details.mCompleteTime + << " size=" << details.mSize + << " offset=" << details.mOffset + << " length=" << U32Milliseconds(details.mCompleteTime - details.mStartTime) + << " protocol=" << protocol + << LL_ENDL; } if(mLogTextureDownloadsToSimulator) { - S32 texture_stats_upload_threshold = mTextureLogThreshold; - mTotalBytes += mTextures[id]->mSize; - mTotalMilliseconds += mTextures[id]->mCompleteTime - mTextures[id]->mStartTime; + U32Bytes texture_stats_upload_threshold = mTextureLogThreshold; + mTotalBytes += details.mSize; + mTotalMilliseconds += details.mCompleteTime - details.mStartTime; mTextureDownloadsCompleted++; mTextureDownloadProtocol = protocol; if (mTotalBytes >= texture_stats_upload_threshold) @@ -194,18 +189,15 @@ void LLTextureInfo::setRequestCompleteTimeAndLog(const LLUUID& id, U64 completeT LLSD LLTextureInfo::getAverages() { LLSD averagedTextureData; - S32 averageDownloadRate; - if(mTotalMilliseconds == 0) + S32 averageDownloadRate = 0; + unsigned int download_time = mTotalMilliseconds.valueInUnits(); + if (0 != download_time) { - averageDownloadRate = 0; - } - else - { - averageDownloadRate = (mTotalBytes * 8) / mTotalMilliseconds; + averageDownloadRate = mTotalBytes.valueInUnits() / download_time; } averagedTextureData["bits_per_second"] = averageDownloadRate; - averagedTextureData["bytes_downloaded"] = mTotalBytes; + averagedTextureData["bytes_downloaded"] = (LLSD::Integer)mTotalBytes.valueInUnits(); averagedTextureData["texture_downloads_started"] = mTextureDownloadsStarted; averagedTextureData["texture_downloads_completed"] = mTextureDownloadsCompleted; averagedTextureData["transport"] = mTextureDownloadProtocol; @@ -215,19 +207,19 @@ LLSD LLTextureInfo::getAverages() void LLTextureInfo::resetTextureStatistics() { - mTotalMilliseconds = 0; - mTotalBytes = 0; + mTotalMilliseconds = U32Milliseconds(0); + mTotalBytes = U32Bytes(0); mTextureDownloadsStarted = 0; mTextureDownloadsCompleted = 0; mTextureDownloadProtocol = "NONE"; mCurrentStatsBundleStartTime = LLTimer::getTotalTime(); } -U32 LLTextureInfo::getRequestStartTime(const LLUUID& id) +U32Microseconds LLTextureInfo::getRequestStartTime(const LLUUID& id) { if (!has(id)) { - return 0; + return U32Microseconds(0); } else { @@ -236,11 +228,11 @@ U32 LLTextureInfo::getRequestStartTime(const LLUUID& id) } } -U32 LLTextureInfo::getRequestSize(const LLUUID& id) +U32Bytes LLTextureInfo::getRequestSize(const LLUUID& id) { if (!has(id)) { - return 0; + return U32Bytes(0); } else { @@ -275,11 +267,11 @@ LLTextureInfoDetails::LLRequestType LLTextureInfo::getRequestType(const LLUUID& } } -U32 LLTextureInfo::getRequestCompleteTime(const LLUUID& id) +U32Microseconds LLTextureInfo::getRequestCompleteTime(const LLUUID& id) { if (!has(id)) { - return 0; + return U32Microseconds(0); } else { diff --git a/indra/newview/lltextureinfo.h b/indra/newview/lltextureinfo.h index 71b0ea431f..2c9c494c04 100644 --- a/indra/newview/lltextureinfo.h +++ b/indra/newview/lltextureinfo.h @@ -43,18 +43,18 @@ class LLTextureInfo LLTextureInfo(); ~LLTextureInfo(); - void setUpLogging(bool writeToViewerLog, bool sendToSim, U32 textureLogThreshold); + void setUpLogging(bool writeToViewerLog, bool sendToSim, U32Bytes textureLogThreshold); bool has(const LLUUID& id); void setRequestStartTime(const LLUUID& id, U64 startTime); void setRequestSize(const LLUUID& id, U32 size); void setRequestOffset(const LLUUID& id, U32 offset); void setRequestType(const LLUUID& id, LLTextureInfoDetails::LLRequestType type); - void setRequestCompleteTimeAndLog(const LLUUID& id, U64 completeTime); - U32 getRequestStartTime(const LLUUID& id); - U32 getRequestSize(const LLUUID& id); + void setRequestCompleteTimeAndLog(const LLUUID& id, U64Microseconds completeTime); + U32Microseconds getRequestStartTime(const LLUUID& id); + U32Bytes getRequestSize(const LLUUID& id); U32 getRequestOffset(const LLUUID& id); LLTextureInfoDetails::LLRequestType getRequestType(const LLUUID& id); - U32 getRequestCompleteTime(const LLUUID& id); + U32Microseconds getRequestCompleteTime(const LLUUID& id); void resetTextureStatistics(); U32 getTextureInfoMapSize(); LLSD getAverages(); @@ -66,15 +66,15 @@ class LLTextureInfo LLSD mAverages; - bool mLogTextureDownloadsToViewerLog; - bool mLogTextureDownloadsToSimulator; - S32 mTotalBytes; - S32 mTotalMilliseconds; + bool mLogTextureDownloadsToViewerLog, + mLogTextureDownloadsToSimulator; + U32Bytes mTotalBytes; + U32Milliseconds mTotalMilliseconds; S32 mTextureDownloadsStarted; S32 mTextureDownloadsCompleted; std::string mTextureDownloadProtocol; - U32 mTextureLogThreshold; // in bytes - U64 mCurrentStatsBundleStartTime; + U32Bytes mTextureLogThreshold; // in bytes + U64Microseconds mCurrentStatsBundleStartTime; }; #endif // LL_LLTEXTUREINFO_H diff --git a/indra/newview/lltextureinfodetails.cpp b/indra/newview/lltextureinfodetails.cpp index f6ef47a2ee..d0c5f1e3a8 100644 --- a/indra/newview/lltextureinfodetails.cpp +++ b/indra/newview/lltextureinfodetails.cpp @@ -34,7 +34,9 @@ #include "lltextureinfodetails.h" -LLTextureInfoDetails::LLTextureInfoDetails() : mStartTime(0), mCompleteTime(0), mSize(0), mType(REQUEST_TYPE_NONE), mOffset(0) +LLTextureInfoDetails::LLTextureInfoDetails() +: mType(REQUEST_TYPE_NONE), + mOffset(0) { } diff --git a/indra/newview/lltextureinfodetails.h b/indra/newview/lltextureinfodetails.h index 091fa01a3d..ef8f74ae8c 100644 --- a/indra/newview/lltextureinfodetails.h +++ b/indra/newview/lltextureinfodetails.h @@ -34,10 +34,10 @@ #define LL_LLTEXTUREINFODETAILS_H #include "lluuid.h" +#include "llunits.h" -class LLTextureInfoDetails +struct LLTextureInfoDetails { -public: enum LLRequestType { REQUEST_TYPE_NONE, @@ -45,11 +45,11 @@ class LLTextureInfoDetails REQUEST_TYPE_UDP }; - U32 mStartTime; - U32 mCompleteTime; - U32 mOffset; - U32 mSize; - LLRequestType mType; + U32Microseconds mStartTime, + mCompleteTime; + U32 mOffset; + U32Bytes mSize; + LLRequestType mType; LLTextureInfoDetails(); }; diff --git a/indra/newview/lltexturestats.cpp b/indra/newview/lltexturestats.cpp index c91bfd4df2..519779d3b0 100644 --- a/indra/newview/lltexturestats.cpp +++ b/indra/newview/lltexturestats.cpp @@ -55,7 +55,7 @@ void send_texture_stats_to_sim(const LLSD &texture_stats) std::string texture_cap_url = gAgent.getRegion()->getCapability("TextureStats"); LLTextureStatsUploader tsu; - llinfos << "uploading texture stats data to simulator" << llendl; + LL_INFOS() << "uploading texture stats data to simulator" << LL_ENDL; tsu.uploadStatsToSimulator(texture_cap_url, texture_stats); } diff --git a/indra/newview/lltexturestatsuploader.cpp b/indra/newview/lltexturestatsuploader.cpp index 7f14a42541..e620b7ea96 100644 --- a/indra/newview/lltexturestatsuploader.cpp +++ b/indra/newview/lltexturestatsuploader.cpp @@ -51,10 +51,10 @@ void LLTextureStatsUploader::uploadStatsToSimulator(const std::string texture_ca } else { - llinfos << "Not sending texture stats: " + LL_INFOS() << "Not sending texture stats: " << texture_stats << " as there is no cap url." - << llendl; + << LL_ENDL; } } diff --git a/indra/newview/lltextureview.cpp b/indra/newview/lltextureview.cpp index 70c6d0b5e2..c2f924bc0b 100644 --- a/indra/newview/lltextureview.cpp +++ b/indra/newview/lltextureview.cpp @@ -81,7 +81,7 @@ static std::string title_string1a("Tex UUID Area DDis(Req) DecodePri(Fetch) static std::string title_string1b("Tex UUID Area DDis(Req) Fetch(DecodePri) [download] pk/max"); static std::string title_string2("State"); static std::string title_string3("Pkt Bnd"); -static std::string title_string4(" W x H (Dis) Mem"); +static std::string title_string4(" W x H (Dis) Mem Type"); static S32 title_x1 = 0; static S32 title_x2 = 460; @@ -182,7 +182,7 @@ void LLTextureBar::draw() { color = LLColor4::green4; } - else if (mImagep->getBoostLevel() > LLGLTexture::BOOST_NONE) + else if (mImagep->getBoostLevel() > LLGLTexture::BOOST_ALM) { color = LLColor4::magenta; } @@ -211,6 +211,9 @@ void LLTextureBar::draw() std::string uuid_str; mImagep->mID.toString(uuid_str); uuid_str = uuid_str.substr(0,7); + + std::string vsstr = llformat("%f",mImagep->mMaxVirtualSize); + std::string dpstr = llformat("%f",mImagep->getDecodePriority()); if (mTextureView->mOrderFetch) { tex_str = llformat("%s %7.0f %d(%d) 0x%08x(%8.0f)", @@ -223,14 +226,14 @@ void LLTextureBar::draw() } else { - tex_str = llformat("%s %7.0f %d(%d) %8.0f(0x%08x) %1.2f", + tex_str = llformat("%s %7.0f %d(%d) %8.0f(0x%08x) %3d%%", uuid_str.c_str(), mImagep->mMaxVirtualSize, mImagep->mDesiredDiscardLevel, mImagep->mRequestedDiscardLevel, mImagep->getDecodePriority(), mImagep->mFetchPriority, - mImagep->mDownloadProgress); + llfloor(mImagep->mDownloadProgress*100.f)); } LLFontGL::getFontMonospace()->renderUTF8(tex_str, 0, title_x1, getRect().getHeight(), @@ -239,12 +242,14 @@ void LLTextureBar::draw() // State // Hack: mirrored from lltexturefetch.cpp struct { const std::string desc; LLColor4 color; } fetch_state_desc[] = { - { "---", LLColor4::red }, // INVALID + { "-?-", LLColor4::red }, // INVALID { "INI", LLColor4::white }, // INIT { "DSK", LLColor4::cyan }, // LOAD_FROM_TEXTURE_CACHE { "DSK", LLColor4::blue }, // CACHE_POST { "NET", LLColor4::green }, // LOAD_FROM_NETWORK { "SIM", LLColor4::green }, // LOAD_FROM_SIMULATOR + { "REQ", LLColor4::magenta },// SEND_UDP_REQ + { "UDP", LLColor4::cyan }, // WAIT_UDP_REQ { "REQ", LLColor4::yellow },// SEND_HTTP_REQ { "HTP", LLColor4::green }, // WAIT_HTTP_REQ { "DEC", LLColor4::yellow },// DECODE_IMAGE @@ -252,12 +257,12 @@ void LLTextureBar::draw() { "WRT", LLColor4::purple },// WRITE_TO_CACHE { "WRT", LLColor4::orange },// WAIT_ON_WRITE { "END", LLColor4::red }, // DONE -#define LAST_STATE 12 +#define LAST_STATE 14 { "CRE", LLColor4::magenta }, // LAST_STATE+1 { "FUL", LLColor4::green }, // LAST_STATE+2 { "BAD", LLColor4::red }, // LAST_STATE+3 { "MIS", LLColor4::red }, // LAST_STATE+4 - { "---", LLColor4::white }, // LAST_STATE+5 + { "-!-", LLColor4::white }, // LAST_STATE+5 }; const S32 fetch_state_desc_size = (S32)LL_ARRAY_SIZE(fetch_state_desc); S32 state = @@ -370,8 +375,39 @@ void LLTextureBar::draw() // draw the image size at the end { - std::string num_str = llformat("%3dx%3d (%d) %7d", mImagep->getWidth(), mImagep->getHeight(), - mImagep->getDiscardLevel(), mImagep->hasGLTexture() ? mImagep->getTextureMemory() : 0); + std::string boost_lvl("UNKNOWN"); + switch(mImagep->getBoostLevel()) + { +#define BOOST_LVL(type) case LLGLTexture::BOOST_##type: boost_lvl="B_"#type; break; +#define CAT_LVL(type) case LLGLTexture::type: boost_lvl=#type; break; + BOOST_LVL(NONE) + BOOST_LVL(AVATAR_BAKED) + BOOST_LVL(AVATAR) + BOOST_LVL(CLOUDS) + BOOST_LVL(SCULPTED) + BOOST_LVL(HIGH) + BOOST_LVL(BUMP) + BOOST_LVL(TERRAIN) + BOOST_LVL(SELECTED) + BOOST_LVL(AVATAR_BAKED_SELF) + BOOST_LVL(AVATAR_SELF) + BOOST_LVL(SUPER_HIGH) + BOOST_LVL(HUD) + BOOST_LVL(ICON) + BOOST_LVL(UI) + BOOST_LVL(PREVIEW) + BOOST_LVL(MAP) + BOOST_LVL(MAP_VISIBLE) + CAT_LVL(LOCAL) + CAT_LVL(AVATAR_SCRATCH_TEX) + CAT_LVL(DYNAMIC_TEX) + CAT_LVL(MEDIA) + CAT_LVL(OTHER) + CAT_LVL(MAX_GL_IMAGE_CATEGORY) + default:; + }; + std::string num_str = llformat("%4dx%4d (%+d) %7d %s", mImagep->getWidth(), mImagep->getHeight(), + mImagep->getDiscardLevel(), mImagep->hasGLTexture() ? mImagep->getTextureMemory().value() : 0, boost_lvl.c_str()); LLFontGL::getFontMonospace()->renderUTF8(num_str, 0, title_x4, getRect().getHeight(), color, LLFontGL::LEFT, LLFontGL::TOP); } @@ -528,18 +564,18 @@ class LLGLTexMemBar : public LLView void LLGLTexMemBar::draw() { - S32 bound_mem = BYTES_TO_MEGA_BYTES(LLViewerTexture::sBoundTextureMemoryInBytes); - S32 max_bound_mem = LLViewerTexture::sMaxBoundTextureMemInMegaBytes; - S32 total_mem = BYTES_TO_MEGA_BYTES(LLViewerTexture::sTotalTextureMemoryInBytes); - S32 max_total_mem = LLViewerTexture::sMaxTotalTextureMemInMegaBytes; + S32Megabytes bound_mem = LLViewerTexture::sBoundTextureMemory; + S32Megabytes max_bound_mem = LLViewerTexture::sMaxBoundTextureMemory; + S32Megabytes total_mem = LLViewerTexture::sTotalTextureMemory; + S32Megabytes max_total_mem = LLViewerTexture::sMaxTotalTextureMem; F32 discard_bias = LLViewerTexture::sDesiredDiscardBias; - F32 cache_usage = (F32)BYTES_TO_MEGA_BYTES(LLAppViewer::getTextureCache()->getUsage()) ; - F32 cache_max_usage = (F32)BYTES_TO_MEGA_BYTES(LLAppViewer::getTextureCache()->getMaxUsage()) ; - S32 line_height = (S32)(LLFontGL::getFontMonospace()->getLineHeight() + .5f); - S32 v_offset = 0; - F32 total_texture_downloaded = (F32)gTotalTextureBytes / (1024 * 1024); - F32 total_object_downloaded = (F32)gTotalObjectBytes / (1024 * 1024); - U32 total_http_requests = LLAppViewer::getTextureFetch()->getTotalNumHTTPRequests() ; + F32 cache_usage = LLAppViewer::getTextureCache()->getUsage().valueInUnits(); + F32 cache_max_usage = LLAppViewer::getTextureCache()->getMaxUsage().valueInUnits(); + S32 line_height = LLFontGL::getFontMonospace()->getLineHeight(); + S32 v_offset = 0;//(S32)((texture_bar_height + 2.2f) * mTextureView->mNumTextureBars + 2.0f); + F32Bytes total_texture_downloaded = gTotalTextureData; + F32Bytes total_object_downloaded = gTotalObjectData; + U32 total_http_requests = LLAppViewer::getTextureFetch()->getTotalNumHTTPRequests(); //---------------------------------------------------------------------------- LLGLSUIDefault gls_ui; LLColor4 text_color(1.f, 1.f, 1.f, 0.75f); @@ -547,18 +583,18 @@ void LLGLTexMemBar::draw() std::string text = ""; - S32 global_raw_memory; + S64 global_raw_memory; { - global_raw_memory = *AIAccess(LLImageRaw::sGlobalRawMemory); + global_raw_memory = *AIAccess(LLImageRaw::sGlobalRawMemory); } - text = llformat("GL Tot: %d/%d MB Bound: %d/%d MB FBO: %d MB Raw Tot: %d MB Bias: %.2f Cache: %.1f/%.1f MB Net Tot Tex: %.1f MB Tot Obj: %.1f MB Tot Htp: %d", - total_mem, - max_total_mem, - bound_mem, - max_bound_mem, + text = llformat("GL Tot: %d/%d MB Bound: %d/%d MB FBO: %d MB Raw Tot: %lld MB Bias: %.2f Cache: %.1f/%.1f MB Net Tot Tex: %.1f MB Tot Obj: %.1f MB Tot Htp: %d", + total_mem.value(), + max_total_mem.value(), + bound_mem.value(), + max_bound_mem.value(), LLRenderTarget::sBytesAllocated/(1024*1024), global_raw_memory >> 20, discard_bias, - cache_usage, cache_max_usage, total_texture_downloaded, total_object_downloaded, total_http_requests); + cache_usage, cache_max_usage, total_texture_downloaded.valueInUnits(), total_object_downloaded.valueInUnits(), total_http_requests); //, cache_entries, cache_max_entries LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, v_offset + line_height*3, @@ -793,7 +829,7 @@ LLTextureView::~LLTextureView() typedef std::pair decode_pair_t; struct compare_decode_pair { - bool operator()(const decode_pair_t& a, const decode_pair_t& b) + bool operator()(const decode_pair_t& a, const decode_pair_t& b) const { return a.first > b.first; } @@ -837,7 +873,7 @@ void LLTextureView::draw() if (mPrintList) { - llinfos << "ID\tMEM\tBOOST\tPRI\tWIDTH\tHEIGHT\tDISCARD" << llendl; + LL_INFOS() << "ID\tMEM\tBOOST\tPRI\tWIDTH\tHEIGHT\tDISCARD" << LL_ENDL; } for (LLViewerTextureList::image_priority_list_t::iterator iter = gTextureList.mImageList.begin(); @@ -854,15 +890,15 @@ void LLTextureView::draw() if (mPrintList) { - S32 tex_mem = imagep->hasGLTexture() ? imagep->getTextureMemory() : 0 ; - llinfos << imagep->getID() + S32 tex_mem = imagep->hasGLTexture() ? imagep->getTextureMemory().value() : 0 ; + LL_INFOS() << imagep->getID() << "\t" << tex_mem << "\t" << imagep->getBoostLevel() << "\t" << imagep->getDecodePriority() << "\t" << imagep->getWidth() << "\t" << imagep->getHeight() << "\t" << cur_discard - << llendl; + << LL_ENDL; } if (imagep->getID() == LLAppViewer::getTextureFetch()->mDebugID) @@ -1281,7 +1317,7 @@ void LLTextureSizeView::drawTextureCategoryGraph() for(U32 i = 0 ; i < mTextureSizeBar.size() ; i++) { U32 k = LLViewerTexture::getIndexFromCategory(i) ; - mTextureSizeBar[i]->setTop(LLImageGL::sTextureMemByCategory[k] >> 20, LLImageGL::sTextureMemByCategoryBound[k] >> 20, size_bar_scale) ; + mTextureSizeBar[i]->setTop(LLImageGL::sTextureMemByCategory[k].value() >> 20, LLImageGL::sTextureMemByCategoryBound[k].value() >> 20, size_bar_scale) ; mTextureSizeBar[i]->draw() ; } LLImageGL::resetCurTexSizebar(); @@ -1299,7 +1335,7 @@ F32 LLTextureSizeView::drawTextureCategoryDistributionGraph() S32 count = 0 ; for(U32 i = 0 ; i < LLImageGL::sTextureMemByCategory.size() ; i++) { - S32 tmp = LLImageGL::sTextureMemByCategory[i] >> 20 ; + S32 tmp = LLImageGL::sTextureMemByCategory[i].value() >> 20 ; if(tmp > count) { count = tmp ; diff --git a/indra/newview/lltool.cpp b/indra/newview/lltool.cpp index 0740fc38be..90a4a04344 100644 --- a/indra/newview/lltool.cpp +++ b/indra/newview/lltool.cpp @@ -61,7 +61,7 @@ LLTool::~LLTool() { if( hasMouseCapture() ) { - llwarns << "Tool deleted holding mouse capture. Mouse capture removed." << llendl; + LL_WARNS() << "Tool deleted holding mouse capture. Mouse capture removed." << LL_ENDL; gFocusMgr.removeMouseCaptureWithoutCallback( this ); } } @@ -86,10 +86,10 @@ BOOL LLTool::handleMouseDown(S32 x, S32 y, MASK mask) { if (gDebugClicks) { - llinfos << "LLTool left mouse down" << llendl; + LL_INFOS() << "LLTool left mouse down" << LL_ENDL; } // by default, didn't handle it - // llinfos << "LLTool::handleMouseDown" << llendl; + // LL_INFOS() << "LLTool::handleMouseDown" << LL_ENDL; gAgent.setControlFlags(AGENT_CONTROL_LBUTTON_DOWN); return TRUE; } @@ -98,10 +98,10 @@ BOOL LLTool::handleMouseUp(S32 x, S32 y, MASK mask) { if (gDebugClicks) { - llinfos << "LLTool left mouse up" << llendl; + LL_INFOS() << "LLTool left mouse up" << LL_ENDL; } // by default, didn't handle it - // llinfos << "LLTool::handleMouseUp" << llendl; + // LL_INFOS() << "LLTool::handleMouseUp" << LL_ENDL; gAgent.setControlFlags(AGENT_CONTROL_LBUTTON_UP); return TRUE; } @@ -109,7 +109,7 @@ BOOL LLTool::handleMouseUp(S32 x, S32 y, MASK mask) BOOL LLTool::handleHover(S32 x, S32 y, MASK mask) { gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW); - lldebugst(LLERR_USER_INPUT) << "hover handled by a tool" << llendl; + LL_DEBUGS("UserInput") << "hover handled by a tool" << LL_ENDL; // by default, do nothing, say we handled it return TRUE; } @@ -117,13 +117,13 @@ BOOL LLTool::handleHover(S32 x, S32 y, MASK mask) BOOL LLTool::handleScrollWheel(S32 x, S32 y, S32 clicks) { // by default, didn't handle it - // llinfos << "LLTool::handleScrollWheel" << llendl; + // LL_INFOS() << "LLTool::handleScrollWheel" << LL_ENDL; return FALSE; } BOOL LLTool::handleDoubleClick(S32 x,S32 y,MASK mask) { - // llinfos << "LLTool::handleDoubleClick" << llendl; + // LL_INFOS() << "LLTool::handleDoubleClick" << LL_ENDL; // by default, pretend it's a left click return FALSE; } @@ -131,35 +131,35 @@ BOOL LLTool::handleDoubleClick(S32 x,S32 y,MASK mask) BOOL LLTool::handleRightMouseDown(S32 x,S32 y,MASK mask) { // by default, didn't handle it - // llinfos << "LLTool::handleRightMouseDown" << llendl; + // LL_INFOS() << "LLTool::handleRightMouseDown" << LL_ENDL; return FALSE; } BOOL LLTool::handleRightMouseUp(S32 x, S32 y, MASK mask) { // by default, didn't handle it - // llinfos << "LLTool::handleRightMouseDown" << llendl; + // LL_INFOS() << "LLTool::handleRightMouseDown" << LL_ENDL; return FALSE; } BOOL LLTool::handleMiddleMouseDown(S32 x,S32 y,MASK mask) { // by default, didn't handle it - // llinfos << "LLTool::handleMiddleMouseDown" << llendl; + // LL_INFOS() << "LLTool::handleMiddleMouseDown" << LL_ENDL; return FALSE; } BOOL LLTool::handleMiddleMouseUp(S32 x, S32 y, MASK mask) { // by default, didn't handle it - // llinfos << "LLTool::handleMiddleMouseUp" << llendl; + // LL_INFOS() << "LLTool::handleMiddleMouseUp" << LL_ENDL; return FALSE; } BOOL LLTool::handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_rect_screen) { // by default, didn't handle it - // llinfos << "LLTool::handleToolTip" << llendl; + // LL_INFOS() << "LLTool::handleToolTip" << LL_ENDL; return FALSE; } @@ -197,9 +197,11 @@ LLTool* LLTool::getOverrideTool(MASK mask) { return NULL; } - if (mask & MASK_ALT) { - return LLToolCamera::getInstance(); + if (mask & MASK_ALT) + { + return LLToolCamera::getInstance(); + } } return NULL; } diff --git a/indra/newview/lltool.h b/indra/newview/lltool.h index 3fec2c8e85..d9f7af4db0 100644 --- a/indra/newview/lltool.h +++ b/indra/newview/lltool.h @@ -45,7 +45,7 @@ class LLView; class LLPanel; class LLTool -: public LLMouseHandler +: public LLMouseHandler, public LLThreadSafeRefCount { public: LLTool( const std::string& name, LLToolComposite* composite = NULL ); diff --git a/indra/newview/lltoolbar.cpp b/indra/newview/lltoolbar.cpp index 985d27f154..fb1e9601a7 100644 --- a/indra/newview/lltoolbar.cpp +++ b/indra/newview/lltoolbar.cpp @@ -35,29 +35,21 @@ #include "lltoolbar.h" -#include "llbutton.h" #include "llflyoutbutton.h" #include "llscrolllistitem.h" -#include "llui.h" #include "llagent.h" #include "llagentcamera.h" -#include "llagentwearables.h" -#include "llfirstuse.h" -#include "llviewerparcelmgr.h" -#include "llfloateravatarlist.h" #include "llfloaterchat.h" #include "llfloaterchatterbox.h" -#include "llfloatercustomize.h" #include "llfloaterfriends.h" #include "llfloaterinventory.h" #include "llfloatermute.h" -#include "llfloatersnapshot.h" #include "llimpanel.h" #include "llimview.h" -#include "llmenucommands.h" -#include "lltoolmgr.h" #include "lltoolgrab.h" +#include "lltoolmgr.h" +#include "llviewerparcelmgr.h" #include "llvoavatarself.h" // [RLVa:KB] @@ -66,24 +58,30 @@ #if LL_DARWIN - #include "llresizehandle.h" - #include "llviewerwindow.h" +#include "llresizehandle.h" +#include "llviewerwindow.h" - // This class draws like an LLResizeHandle but has no interactivity. - // It's just there to provide a cue to the user that the lower right corner of the window functions as a resize handle. - class LLFakeResizeHandle : public LLResizeHandle - { - public: - LLFakeResizeHandle(const LLResizeHandle::Params& p) - : LLResizeHandle(p) - { - } +// This class draws like an LLResizeHandle but has no interactivity. +// It's just there to provide a cue to the user that the lower right corner of the window functions as a resize handle. +class LLFakeResizeHandle : public LLResizeHandle +{ +public: + LLFakeResizeHandle(const LLResizeHandle::Params& p) : LLResizeHandle(p) {} - virtual BOOL handleHover(S32 x, S32 y, MASK mask) { return FALSE; }; - virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask) { return FALSE; }; - virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask) { return FALSE; }; + virtual BOOL handleHover(S32 x, S32 y, MASK mask) { return false; } + virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask) { return false; } + virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask) { return false; } + virtual void reshape(S32 width, S32 height, BOOL called_from_parent) + { + // Only when running in windowed mode on the Mac, leave room for a resize widget on the right edge of the bar. + if (gViewerWindow->getWindow()->getFullscreen()) + return setVisible(false); - }; + setVisible(true); + const F32 wide(gViewerWindow->getWindowWidth() + 2); + setRect(LLRect(wide - RESIZE_HANDLE_WIDTH, RESIZE_HANDLE_HEIGHT, wide, 0)); + } +}; #endif // LL_DARWIN @@ -102,90 +100,44 @@ F32 LLToolBar::sInventoryAutoOpenTime = 1.f; // // Functions // +void show_floater(const std::string& floater_name); +void show_inv_floater(const LLSD& userdata, const std::string& field); +void show_web_floater(const std::string& type); LLToolBar::LLToolBar() : LLLayoutPanel() -#if LL_DARWIN - , mResizeHandle(NULL) -#endif // LL_DARWIN { setIsChrome(TRUE); setFocusRoot(TRUE); + mCommitCallbackRegistrar.add("ShowFloater", boost::bind(show_floater, _2)); + mCommitCallbackRegistrar.add("ShowInvFloater.ID", boost::bind(show_inv_floater, _2, "id")); + mCommitCallbackRegistrar.add("ShowInvFloater.Name", boost::bind(show_inv_floater, _2, "name")); + mCommitCallbackRegistrar.add("ShowInvFloater.Type", boost::bind(show_inv_floater, _2, "type")); + mCommitCallbackRegistrar.add("ShowWebFloater", boost::bind(show_web_floater, _2)); } BOOL LLToolBar::postBuild() { - childSetCommitCallback("communicate_btn", onClickCommunicate, this); - - childSetAction("chat_btn", onClickChat, this); - childSetControlName("chat_btn", "ChatVisible"); - - //childSetAction("appearance_btn", onClickAppearance, this); - //childSetControlName("appearance_btn", ""); - - childSetAction("radar_list_btn", onClickRadarList, this); - childSetControlName("radar_list_btn", "ShowRadar"); - - childSetAction("fly_btn", onClickFly, this); - childSetControlName("fly_btn", "FlyBtnState"); - - //childSetAction("sit_btn", onClickSit, this); - //childSetControlName("sit_btn", "SitBtnState"); - - childSetAction("snapshot_btn", onClickSnapshot, this); - childSetControlName("snapshot_btn", "SnapshotBtnState"); - - childSetAction("directory_btn", onClickDirectory, this); - childSetControlName("directory_btn", "ShowDirectory"); - - childSetAction("build_btn", onClickBuild, this); - childSetControlName("build_btn", "BuildBtnState"); - - childSetAction("radar_btn", onClickRadar, this); - childSetControlName("radar_btn", "ShowMiniMap"); - - childSetAction("map_btn", onClickMap, this); - childSetControlName("map_btn", "ShowWorldMap"); - - childSetAction("inventory_btn", onClickInventory, this); - childSetControlName("inventory_btn", "ShowInventory"); - mCommunicateBtn.connect(this, "communicate_btn"); + mCommunicateBtn->setCommitCallback(boost::bind(&LLToolBar::onClickCommunicate, this, _2)); mFlyBtn.connect(this, "fly_btn"); mBuildBtn.connect(this, "build_btn"); mMapBtn.connect(this, "map_btn"); mRadarBtn.connect(this, "radar_btn"); mInventoryBtn.connect(this, "inventory_btn"); - for (child_list_const_iter_t child_iter = getChildList()->begin(); - child_iter != getChildList()->end(); ++child_iter) - { - LLView *view = *child_iter; - LLButton* buttonp = dynamic_cast(view); - if(buttonp) - { - buttonp->setSoundFlags(LLView::SILENT); - } - } - #if LL_DARWIN - if(mResizeHandle == NULL) - { - LLResizeHandle::Params p; - p.rect(LLRect(0, 0, RESIZE_HANDLE_WIDTH, RESIZE_HANDLE_HEIGHT)); - p.name(std::string("")); - p.min_width(RESIZE_HANDLE_WIDTH); - p.min_height(RESIZE_HANDLE_HEIGHT); - p.corner(LLResizeHandle::RIGHT_BOTTOM); - mResizeHandle = new LLFakeResizeHandle(p); this->addChildInBack(mResizeHandle); - LLLayoutStack* toolbar_stack = getChild("toolbar_stack"); - toolbar_stack->reshape(toolbar_stack->getRect().getWidth() - RESIZE_HANDLE_WIDTH, toolbar_stack->getRect().getHeight()); - } + LLResizeHandle::Params p; + p.rect(LLRect(0, 0, RESIZE_HANDLE_WIDTH, RESIZE_HANDLE_HEIGHT)); + p.name(std::string("")); + p.min_width(RESIZE_HANDLE_WIDTH); + p.min_height(RESIZE_HANDLE_HEIGHT); + p.corner(LLResizeHandle::RIGHT_BOTTOM); + addChildInBack(new LLFakeResizeHandle(p)); + reshape(getRect().getWidth(), getRect().getHeight()); #endif // LL_DARWIN - layoutButtons(); - return TRUE; } @@ -201,126 +153,62 @@ BOOL LLToolBar::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EAcceptance* accept, std::string& tooltip_msg) { - LLButton* inventory_btn = getChild("inventory_btn"); - if (!inventory_btn) return FALSE; + LLButton* inventory_btn = mInventoryBtn; + if (!inventory_btn || !inventory_btn->getVisible()) return FALSE; - LLInventoryView* active_inventory = LLInventoryView::getActiveInventory(); + LLPanelMainInventory* active_inventory = LLPanelMainInventory::getActiveInventory(); - if(active_inventory && active_inventory->getVisible()) + if (active_inventory && active_inventory->getVisible()) { - mInventoryAutoOpen = FALSE; + mInventoryAutoOpenTimer.stop(); } else if (inventory_btn->getRect().pointInRect(x, y)) { - if (mInventoryAutoOpen) + if (mInventoryAutoOpenTimer.getStarted()) { if (!(active_inventory && active_inventory->getVisible()) && mInventoryAutoOpenTimer.getElapsedTimeF32() > sInventoryAutoOpenTime) { - LLInventoryView::showAgentInventory(); + LLPanelMainInventory::showAgentInventory(); } } else { - mInventoryAutoOpen = TRUE; - mInventoryAutoOpenTimer.reset(); + mInventoryAutoOpenTimer.start(); } } return LLPanel::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); } -// static -void LLToolBar::toggle(void*) -{ - BOOL show = gSavedSettings.getBOOL("ShowToolBar"); - gSavedSettings.setBOOL("ShowToolBar", !show); - gToolBar->setVisible(!show); -} - - -// static -BOOL LLToolBar::visible(void*) -{ - return gToolBar->getVisible(); -} - - -void LLToolBar::layoutButtons() -{ -#if LL_DARWIN - const S32 FUDGE_WIDTH_OF_SCREEN = 4; - S32 width = gViewerWindow->getWindowWidth() + FUDGE_WIDTH_OF_SCREEN; - S32 pad = 2; - - // this function may be called before postBuild(), in which case mResizeHandle won't have been set up yet. - if(mResizeHandle != NULL) - { - if(!gViewerWindow->getWindow()->getFullscreen()) - { - // Only when running in windowed mode on the Mac, leave room for a resize widget on the right edge of the bar. - width -= RESIZE_HANDLE_WIDTH; - - LLRect r; - r.mLeft = width - pad; - r.mBottom = 0; - r.mRight = r.mLeft + RESIZE_HANDLE_WIDTH; - r.mTop = r.mBottom + RESIZE_HANDLE_HEIGHT; - mResizeHandle->setRect(r); - mResizeHandle->setVisible(TRUE); - } - else - { - mResizeHandle->setVisible(FALSE); - } - } -#endif // LL_DARWIN -} - - -// virtual -void LLToolBar::reshape(S32 width, S32 height, BOOL called_from_parent) -{ - LLPanel::reshape(width, height, called_from_parent); - - layoutButtons(); -} - // Per-frame updates of visibility void LLToolBar::refresh() { - if(!isAgentAvatarValid()) - return; - - static LLCachedControl show("ShowToolBar", true); - static LLCachedControl ascent_build_always_enabled("AscentBuildAlwaysEnabled", true); - BOOL mouselook = gAgentCamera.cameraMouselook(); - setVisible(show && !mouselook); - - BOOL sitting = FALSE; - static LLCachedControl continue_flying_on_unsit("LiruContinueFlyingOnUnsit"); - if (continue_flying_on_unsit) - { - sitting = false; - } - else if (gAgentAvatarp) + static const LLCachedControl show_toolbar("ShowToolBar", true); + bool show = show_toolbar; + if (show && gAgentCamera.cameraMouselook()) { - sitting = gAgentAvatarp->isSitting(); + static const LLCachedControl hidden("LiruMouselookHidesToolbar"); + show = !hidden; } + setVisible(show); + if (!show) return; // Everything below this point manipulates visible UI, anyway + + updateCommunicateList(); + + if (!isAgentAvatarValid()) return; - mFlyBtn->setEnabled((gAgent.canFly() || gAgent.getFlying()) && !sitting ); - mBuildBtn->setEnabled((LLViewerParcelMgr::getInstance()->allowAgentBuild() || ascent_build_always_enabled)); + static const LLCachedControl continue_flying_on_unsit("LiruContinueFlyingOnUnsit"); + mFlyBtn->setEnabled((gAgent.canFly() || gAgent.getFlying()) && (continue_flying_on_unsit || !gAgentAvatarp->isSitting())); + static const LLCachedControl ascent_build_always_enabled("AscentBuildAlwaysEnabled", true); + mBuildBtn->setEnabled(ascent_build_always_enabled || LLViewerParcelMgr::getInstance()->allowAgentBuild()); // Check to see if we're in build mode - BOOL build_mode = LLToolMgr::getInstance()->inEdit(); // And not just clicking on a scripted object - if (LLToolGrab::getInstance()->getHideBuildHighlight()) - { - build_mode = FALSE; - } + bool build_mode = LLToolMgr::getInstance()->inEdit() && !LLToolGrab::getInstance()->getHideBuildHighlight(); static LLCachedControl build_btn_state("BuildBtnState",false); - if(build_btn_state!=(bool)build_mode) + if (build_btn_state != build_mode) build_btn_state = build_mode; // [RLVa:KB] - Version: 1.23.4 | Checked: 2009-07-10 (RLVa-1.0.0g) @@ -332,68 +220,45 @@ void LLToolBar::refresh() mBuildBtn->setEnabled(!(gRlvHandler.hasBehaviour(RLV_BHVR_REZ) && gRlvHandler.hasBehaviour(RLV_BHVR_EDIT))); mMapBtn->setEnabled(!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWWORLDMAP)); - mRadarBtn->setEnabled(!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWMINIMAP) && !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)); + mRadarBtn->setEnabled(!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWMINIMAP)); mInventoryBtn->setEnabled(!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWINV)); } // [/RLVa:KB] +} - if (isInVisibleChain()) - { - updateCommunicateList(); - } +void bold_if_equal(const LLFloater* f1, const LLFloater* f2, LLScrollListItem* itemp) +{ + if (f1 != f2) return; + static_cast(itemp->getColumn(0))->setFontStyle(LLFontGL::BOLD); } void LLToolBar::updateCommunicateList() { - LLFlyoutButton* communicate_button = mCommunicateBtn; - LLSD selected = communicate_button->getValue(); + if (!mCommunicateBtn->getVisible()) return; - communicate_button->removeall(); + LLSD selected = mCommunicateBtn->getValue(); - LLFloater* frontmost_floater = LLFloaterChatterBox::getInstance()->getActiveFloater(); - LLScrollListItem* itemp = NULL; + mCommunicateBtn->removeall(); - itemp = communicate_button->add(LLFloaterMyFriends::getInstance()->getShortTitle(), LLSD("contacts"), ADD_TOP); - if (LLFloaterMyFriends::getInstance() == frontmost_floater) - { - ((LLScrollListText*)itemp->getColumn(0))->setFontStyle(LLFontGL::BOLD); - // make sure current tab is selected in list - if (selected.isUndefined()) - { - selected = itemp->getValue(); - } - } - itemp = communicate_button->add(LLFloaterChat::getInstance()->getShortTitle(), LLSD("local chat"), ADD_TOP); - if (LLFloaterChat::getInstance() == frontmost_floater) - { - ((LLScrollListText*)itemp->getColumn(0))->setFontStyle(LLFontGL::BOLD); - if (selected.isUndefined()) - { - selected = itemp->getValue(); - } - } - communicate_button->addSeparator(ADD_TOP); - communicate_button->add(getString("Redock Windows"), LLSD("redock"), ADD_TOP); - communicate_button->addSeparator(ADD_TOP); - communicate_button->add(LLFloaterMute::getInstance()->getShortTitle(), LLSD("mute list"), ADD_TOP); - - std::set >::const_iterator floater_handle_it; - - if (gIMMgr->getIMFloaterHandles().size() > 0) - { - communicate_button->addSeparator(ADD_TOP); - } + const LLFloater* frontmost_floater = LLFloaterChatterBox::getInstance()->getActiveFloater(); + bold_if_equal(LLFloaterMyFriends::getInstance(), frontmost_floater, mCommunicateBtn->add(LLFloaterMyFriends::getInstance()->getShortTitle(), LLSD("contacts"), ADD_TOP)); + bold_if_equal(LLFloaterChat::getInstance(), frontmost_floater, mCommunicateBtn->add(LLFloaterChat::getInstance()->getShortTitle(), LLSD("local chat"), ADD_TOP)); + mCommunicateBtn->addSeparator(ADD_TOP); + static const auto redock = getString("Redock Windows"); + mCommunicateBtn->add(redock, LLSD("redock"), ADD_TOP); + mCommunicateBtn->addSeparator(ADD_TOP); + bold_if_equal(LLFloaterMute::getInstance(), frontmost_floater, mCommunicateBtn->add(LLFloaterMute::getInstance()->getShortTitle(), LLSD("mute list"), ADD_TOP)); - for(floater_handle_it = gIMMgr->getIMFloaterHandles().begin(); floater_handle_it != gIMMgr->getIMFloaterHandles().end(); ++floater_handle_it) + if (gIMMgr->getIMFloaterHandles().size() > 0) mCommunicateBtn->addSeparator(ADD_TOP); + for(const auto& handle : gIMMgr->getIMFloaterHandles()) { - LLFloaterIMPanel* im_floaterp = (LLFloaterIMPanel*)floater_handle_it->get(); - if (im_floaterp) + if (LLFloaterIMPanel* im_floaterp = (LLFloaterIMPanel*)handle.get()) { - static LLCachedControl show_counts("ShowUnreadIMsCounts", true); - S32 count = im_floaterp->getNumUnreadMessages(); + const S32 count = im_floaterp->getNumUnreadMessages(); std::string floater_title; - if (count > 0) floater_title = "*"; + if (count > 0) floater_title = '*'; floater_title.append(im_floaterp->getShortTitle()); + static const LLCachedControl show_counts("ShowUnreadIMsCounts", true); if (show_counts && count > 0) { floater_title += " - "; @@ -401,39 +266,29 @@ void LLToolBar::updateCommunicateList() { LLStringUtil::format_map_t args; args["COUNT"] = llformat("%d", count); - floater_title += getString("IMs", args); + static LLUIString ims = getString("IMs"); + ims.setArgList(args); + floater_title += ims.getString(); } else { - floater_title += getString("IM"); - } - } - - itemp = communicate_button->add(floater_title, im_floaterp->getSessionID(), ADD_TOP); - if (im_floaterp == frontmost_floater) - { - ((LLScrollListText*)itemp->getColumn(0))->setFontStyle(LLFontGL::BOLD); - if (selected.isUndefined()) - { - selected = itemp->getValue(); + static const auto im = getString("IM"); + floater_title += im; } } + bold_if_equal(im_floaterp, frontmost_floater, mCommunicateBtn->add(floater_title, im_floaterp->getSessionID(), ADD_TOP)); } } - communicate_button->setToggleState(gSavedSettings.getBOOL("ShowCommunicate")); - communicate_button->setValue(selected); + static const LLCachedControl show_comm("ShowCommunicate", true); + mCommunicateBtn->setToggleState(show_comm); + if (!selected.isUndefined()) mCommunicateBtn->setValue(selected); } // static -void LLToolBar::onClickCommunicate(LLUICtrl* ctrl, void* user_data) +void LLToolBar::onClickCommunicate(const LLSD& selected_option) { - LLToolBar* toolbar = (LLToolBar*)user_data; - LLFlyoutButton* communicate_button = toolbar->getChild("communicate_btn"); - - LLSD selected_option = communicate_button->getValue(); - if (selected_option.asString() == "contacts") { LLFloaterMyFriends::showInstance(); @@ -484,104 +339,3 @@ void LLToolBar::onClickCommunicate(LLUICtrl* ctrl, void* user_data) LLFloaterChatterBox::showInstance(selected_option); } } - - -// static -void LLToolBar::onClickChat(void* user_data) -{ - handle_chat(NULL); -} - -// static -void LLToolBar::onClickAppearance(void*) -{ - if (gAgentWearables.areWearablesLoaded()) - { - LLFloaterCustomize::show(); - } -} - -// static -void LLToolBar::onClickRadarList(void*) -{ - LLFloaterAvatarList::toggle(0); -} - - -// static -void LLToolBar::onClickFly(void*) -{ - gAgent.toggleFlying(); -} - - -// static -void LLToolBar::onClickSit(void*) -{ - if (!(gAgent.getControlFlags() & AGENT_CONTROL_SIT_ON_GROUND)) - { - // sit down - gAgent.setFlying(FALSE); - gAgent.setControlFlags(AGENT_CONTROL_SIT_ON_GROUND); - - // Might be first sit - LLFirstUse::useSit(); - } - else - { -// [RLVa:KB] - Checked: 2009-07-10 (RLVa-1.0.0g) - // NOTE-RLVa: dead code? - if (gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) - { - return; - } -// [/RLVa:KB] - - // stand up - gAgent.setFlying(FALSE); - gAgent.setControlFlags(AGENT_CONTROL_STAND_UP); - } -} - - -// static -void LLToolBar::onClickSnapshot(void*) -{ - LLFloaterSnapshot::show (0); -} - - -// static -void LLToolBar::onClickDirectory(void*) -{ - handle_find(NULL); -} - - -// static -void LLToolBar::onClickBuild(void*) -{ - LLToolMgr::getInstance()->toggleBuildMode(); -} - - -// static -void LLToolBar::onClickRadar(void*) -{ - handle_mini_map(NULL); -} - - -// static -void LLToolBar::onClickMap(void*) -{ - handle_map(NULL); -} - - -// static -void LLToolBar::onClickInventory(void*) -{ - handle_inventory(NULL); -} - diff --git a/indra/newview/lltoolbar.h b/indra/newview/lltoolbar.h index 28fcba9df1..958c0b4bc2 100644 --- a/indra/newview/lltoolbar.h +++ b/indra/newview/lltoolbar.h @@ -41,10 +41,6 @@ // "Constants" loaded from settings.xml at start time extern S32 TOOL_BAR_HEIGHT; -#if LL_DARWIN - class LLFakeResizeHandle; -#endif // LL_DARWIN - class LLFlyoutButton; class LLToolBar @@ -62,44 +58,20 @@ class LLToolBar EAcceptance* accept, std::string& tooltip_msg); - /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); - - static void toggle(void*); - static BOOL visible(void*); - - // Move buttons to appropriate locations based on rect. - void layoutButtons(); - // Per-frame refresh call void refresh(); // callbacks - static void onClickCommunicate(LLUICtrl*, void*); - static void onClickChat(void* data); - static void onClickAppearance(void* data); - static void onClickFly(void*); - static void onClickSit(void*); - static void onClickSnapshot(void* data); - static void onClickDirectory(void* data); - static void onClickBuild(void* data); - static void onClickRadar(void* data); - static void onClickMap(void* data); - static void onClickInventory(void* data); - static void onClickRadarList(void* data); + void onClickCommunicate(const LLSD& selected); static F32 sInventoryAutoOpenTime; private: void updateCommunicateList(); - private: - BOOL mInventoryAutoOpen; LLFrameTimer mInventoryAutoOpenTimer; S32 mNumUnreadIMs; -#if LL_DARWIN - LLFakeResizeHandle *mResizeHandle; -#endif // LL_DARWIN CachedUICtrl mCommunicateBtn; CachedUICtrl mFlyBtn; diff --git a/indra/newview/lltoolbrush.cpp b/indra/newview/lltoolbrush.cpp index c3f2593c41..79a9d6c6c8 100644 --- a/indra/newview/lltoolbrush.cpp +++ b/indra/newview/lltoolbrush.cpp @@ -59,7 +59,7 @@ #include "llworld.h" #include "llappviewer.h" #include "llparcel.h" - +#include "roles_constants.h" #include "llglheaders.h" const std::string REGION_BLOCKS_TERRAFORM_MSG = "This region does not allow terraforming.\n" @@ -164,10 +164,10 @@ void LLToolBrushLand::modifyLandAtPointGlobal(const LLVector3d &pos_global, //if(!is_changed) continue; // Now to update the patch information so it will redraw correctly. - LLSurfacePatch *patchp= land.resolvePatchRegion(pos_region); - if (patchp) + auto& patchp = land.resolvePatchRegion(pos_region); + if (patchp && patchp->dirtyZ()) { - patchp->dirtyZ(); + patchp->getSurface()->dirtySurfacePatch(patchp); } // Also force the property lines to update, normals to recompute, etc. @@ -246,9 +246,9 @@ void LLToolBrushLand::modifyLandInSelectionGlobal() iter != mLastAffectedRegions.end(); ++iter) { LLViewerRegion* regionp = *iter; - if (!canTerraform(regionp)) + if (!canTerraformRegion(regionp)) { - alertNoTerraform(regionp); + alertNoTerraformRegion(regionp); return; } } @@ -305,10 +305,10 @@ void LLToolBrushLand::modifyLandInSelectionGlobal() //if(!is_changed) continue; // Now to update the patch information so it will redraw correctly. - LLSurfacePatch *patchp= land.resolvePatchRegion(min_region); - if (patchp) + auto& patchp = land.resolvePatchRegion(min_region); + if (patchp && patchp->dirtyZ()) { - patchp->dirtyZ(); + patchp->getSurface()->dirtySurfacePatch(patchp); } // Also force the property lines to update, normals to recompute, etc. @@ -383,12 +383,19 @@ BOOL LLToolBrushLand::handleMouseDown(S32 x, S32 y, MASK mask) LLRegionPosition region_position( spot ); LLViewerRegion* regionp = region_position.getRegion(); - if (!canTerraform(regionp)) + if (!canTerraformRegion(regionp)) { - alertNoTerraform(regionp); + alertNoTerraformRegion(regionp); return TRUE; } + static bool alerted(false); // Don't spam this + if (!alerted && !canTerraformParcel(regionp)) + { + alertNoTerraformParcel(); + alerted = true; + } + LLVector3 pos_region = region_position.getPositionRegion(); U32 grids = regionp->getLand().mGridsPerEdge; S32 i = llclamp( (S32)pos_region.mV[VX], 0, (S32)grids ); @@ -408,13 +415,23 @@ BOOL LLToolBrushLand::handleMouseDown(S32 x, S32 y, MASK mask) BOOL LLToolBrushLand::handleHover( S32 x, S32 y, MASK mask ) { - lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolBrushLand (" + LL_DEBUGS("UserInput") << "hover handled by LLToolBrushLand (" << (hasMouseCapture() ? "active":"inactive") - << ")" << llendl; + << ")" << LL_ENDL; mMouseX = x; mMouseY = y; mGotHover = TRUE; gViewerWindow->getWindow()->setCursor(UI_CURSOR_TOOLLAND); + + LLVector3d spot; + if (gViewerWindow->mousePointOnLandGlobal(mMouseX, mMouseY, &spot)) + { + + spot.mdV[VX] = floor( spot.mdV[VX] + 0.5 ); + spot.mdV[VY] = floor( spot.mdV[VY] + 0.5 ); + + LLViewerParcelMgr::getInstance()->setHoverParcel(spot); + } return TRUE; } @@ -463,7 +480,7 @@ void LLToolBrushLand::render() { if(mGotHover) { - //llinfos << "LLToolBrushLand::render()" << llendl; + //LL_INFOS() << "LLToolBrushLand::render()" << LL_ENDL; LLVector3d spot; if(gViewerWindow->mousePointOnLandGlobal(mMouseX, mMouseY, &spot)) { @@ -660,7 +677,7 @@ void LLToolBrushLand::redo() }*/ // static -bool LLToolBrushLand::canTerraform(LLViewerRegion* regionp) const +bool LLToolBrushLand::canTerraformRegion(LLViewerRegion* regionp) const { if (!regionp) return false; if (regionp->canManageEstate()) return true; @@ -668,7 +685,22 @@ bool LLToolBrushLand::canTerraform(LLViewerRegion* regionp) const } // static -void LLToolBrushLand::alertNoTerraform(LLViewerRegion* regionp) +bool LLToolBrushLand::canTerraformParcel(LLViewerRegion* regionp) const +{ + LLParcel* selected_parcel = LLViewerParcelMgr::getInstance()->getHoverParcel(); + bool is_terraform_allowed = false; + if (selected_parcel) + { + BOOL owner_release = LLViewerParcelMgr::isParcelOwnedByAgent(selected_parcel, GP_LAND_ALLOW_EDIT_LAND); + is_terraform_allowed = (selected_parcel->getAllowTerraform() || gAgent.canManageEstate() || (selected_parcel->getOwnerID() == regionp->getOwner()) || owner_release); + } + + return is_terraform_allowed; +} + + +// static +void LLToolBrushLand::alertNoTerraformRegion(LLViewerRegion* regionp) { if (!regionp) return; @@ -678,6 +710,19 @@ void LLToolBrushLand::alertNoTerraform(LLViewerRegion* regionp) } +// static +void LLToolBrushLand::alertNoTerraformParcel() +{ + LLParcel* selected_parcel = LLViewerParcelMgr::getInstance()->getHoverParcel(); + if (selected_parcel) + { + LLSD args; + args["PARCEL"] = selected_parcel->getName(); + LLNotificationsUtil::add("ParcelNoTerraforming", args); + } + +} + ///============================================================================ /// Local function definitions ///============================================================================ diff --git a/indra/newview/lltoolbrush.h b/indra/newview/lltoolbrush.h index fca275aa4d..6aeea35b28 100644 --- a/indra/newview/lltoolbrush.h +++ b/indra/newview/lltoolbrush.h @@ -2,31 +2,25 @@ * @file lltoolbrush.h * @brief toolbrush class header file * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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$ */ @@ -87,10 +81,14 @@ class LLToolBrushLand : public LLTool, public LLEditMenuHandler, public LLSingle const LLVector3& pos_world); // Does region allow terraform, or are we a god? - bool canTerraform(LLViewerRegion* regionp) const; + bool canTerraformRegion(LLViewerRegion* regionp) const; + + bool canTerraformParcel(LLViewerRegion* regionp) const; // Modal dialog that you can't terraform the region - void alertNoTerraform(LLViewerRegion* regionp); + void alertNoTerraformRegion(LLViewerRegion* regionp); + + void alertNoTerraformParcel(); protected: F32 mStartingZ; diff --git a/indra/newview/lltoolcomp.cpp b/indra/newview/lltoolcomp.cpp index 2a79e0c32d..b628851bbd 100644 --- a/indra/newview/lltoolcomp.cpp +++ b/indra/newview/lltoolcomp.cpp @@ -2,31 +2,25 @@ * @file lltoolcomp.cpp * @brief Composite tools * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -55,7 +49,6 @@ #include "llagent.h" #include "llagentcamera.h" #include "llfloatertools.h" -#include "qtoolalign.h" #include "llviewercontrol.h" #include "llviewercamera.h" @@ -68,7 +61,7 @@ extern LLControlGroup gSavedSettings; // we use this in various places instead of NULL -static LLTool* sNullTool = new LLTool(std::string("null"), NULL); +static LLPointer sNullTool(new LLTool(std::string("null"), NULL)); //----------------------------------------------------------------------- // LLToolComposite @@ -79,7 +72,7 @@ void LLToolComposite::setCurrentTool( LLTool* new_tool ) if( mCur != new_tool ) { if(new_tool) - lldebugs << "Current Tool: " << new_tool->getName() << llendl; + LL_DEBUGS() << "Current Tool: " << new_tool->getName() << LL_ENDL; if( mSelected ) { mCur->handleDeselect(); @@ -135,12 +128,20 @@ void LLToolComposite::handleSelect() mSelected = TRUE; } +void LLToolComposite::handleDeselect() +{ + mCur->handleDeselect(); + mCur = mDefault; + mSelected = FALSE; +} + //---------------------------------------------------------------------------- // LLToolCompInspect //---------------------------------------------------------------------------- LLToolCompInspect::LLToolCompInspect() -: LLToolComposite(std::string("Inspect")) +: LLToolComposite(std::string("Inspect")), + mIsToolCameraActive(FALSE) { mSelectRect = new LLToolSelectRect(this); mDefault = mSelectRect; @@ -155,42 +156,87 @@ LLToolCompInspect::~LLToolCompInspect() BOOL LLToolCompInspect::handleMouseDown(S32 x, S32 y, MASK mask) { - mMouseDown = TRUE; - gViewerWindow->pickAsync(x, y, mask, pickCallback); - return TRUE; + BOOL handled = FALSE; + + if (mCur == LLToolCamera::getInstance()) + { + handled = mCur->handleMouseDown(x, y, mask); + } + else + { + mMouseDown = TRUE; + gViewerWindow->pickAsync(x, y, mask, pickCallback, FALSE, TRUE); + handled = TRUE; + } + + return handled; +} + +BOOL LLToolCompInspect::handleMouseUp(S32 x, S32 y, MASK mask) +{ + BOOL handled = LLToolComposite::handleMouseUp(x, y, mask); + mIsToolCameraActive = getCurrentTool() == LLToolCamera::getInstance(); + return handled; } void LLToolCompInspect::pickCallback(const LLPickInfo& pick_info) { LLViewerObject* hit_obj = pick_info.getObject(); + LLToolCompInspect* tool_inspectp = LLToolCompInspect::getInstance(); - if (!LLToolCompInspect::getInstance()->mMouseDown) + if (!tool_inspectp->mMouseDown) { // fast click on object, but mouse is already up...just do select - LLToolCompInspect::getInstance()->mSelectRect->handleObjectSelection(pick_info, gSavedSettings.getBOOL("EditLinkedParts"), FALSE); + tool_inspectp->mSelectRect->handleObjectSelection(pick_info, gSavedSettings.getBOOL("EditLinkedParts"), FALSE); return; } - if( hit_obj ) - { - if (LLSelectMgr::getInstance()->getSelection()->getObjectCount()) - { - LLEditMenuHandler::gEditMenuHandler = LLSelectMgr::getInstance(); - } - LLToolCompInspect::getInstance()->setCurrentTool( LLToolCompInspect::getInstance()->mSelectRect ); - LLToolCompInspect::getInstance()->mSelectRect->handlePick( pick_info ); + LLSelectMgr* mgr_selectp = LLSelectMgr::getInstance(); + if (hit_obj && mgr_selectp->getSelection()->getObjectCount()) { + LLEditMenuHandler::gEditMenuHandler = mgr_selectp; + } + + tool_inspectp->setCurrentTool( tool_inspectp->mSelectRect ); + tool_inspectp->mIsToolCameraActive = FALSE; + tool_inspectp->mSelectRect->handlePick( pick_info ); +} + +BOOL LLToolCompInspect::handleDoubleClick(S32 x, S32 y, MASK mask) +{ + return TRUE; +} + +BOOL LLToolCompInspect::handleKey(KEY key, MASK mask) +{ + BOOL handled = FALSE; + if(KEY_ALT == key) + { + setCurrentTool(LLToolCamera::getInstance()); + mIsToolCameraActive = TRUE; + handled = TRUE; } else { - LLToolCompInspect::getInstance()->setCurrentTool( LLToolCompInspect::getInstance()->mSelectRect ); - LLToolCompInspect::getInstance()->mSelectRect->handlePick( pick_info ); + handled = LLToolComposite::handleKey(key, mask); } + + return handled; } -BOOL LLToolCompInspect::handleDoubleClick(S32 x, S32 y, MASK mask) +void LLToolCompInspect::onMouseCaptureLost() { - return TRUE; + LLToolComposite::onMouseCaptureLost(); + mIsToolCameraActive = FALSE; +} + +void LLToolCompInspect::keyUp(KEY key, MASK mask) +{ + if (KEY_ALT == key && mCur == LLToolCamera::getInstance()) + { + setCurrentTool(mDefault); + mIsToolCameraActive = FALSE; + } } //---------------------------------------------------------------------------- @@ -229,7 +275,7 @@ BOOL LLToolCompTranslate::handleHover(S32 x, S32 y, MASK mask) BOOL LLToolCompTranslate::handleMouseDown(S32 x, S32 y, MASK mask) { mMouseDown = TRUE; - gViewerWindow->pickAsync(x, y, mask, pickCallback, TRUE); + gViewerWindow->pickAsync(x, y, mask, pickCallback, TRUE, TRUE); return TRUE; } @@ -283,20 +329,13 @@ BOOL LLToolCompTranslate::handleMouseUp(S32 x, S32 y, MASK mask) LLTool* LLToolCompTranslate::getOverrideTool(MASK mask) { - if (gKeyboard->getKeyDown('A') && mask & MASK_CONTROL) + if (mask == MASK_CONTROL) { - return QToolAlign::getInstance(); + return LLToolCompRotate::getInstance(); } - else + else if (mask == (MASK_CONTROL | MASK_SHIFT)) { - if (mask == MASK_CONTROL) - { - return LLToolCompRotate::getInstance(); - } - else if (mask == (MASK_CONTROL | MASK_SHIFT)) - { - return LLToolCompScale::getInstance(); - } + return LLToolCompScale::getInstance(); } return LLToolComposite::getOverrideTool(mask); } @@ -360,7 +399,7 @@ BOOL LLToolCompScale::handleHover(S32 x, S32 y, MASK mask) BOOL LLToolCompScale::handleMouseDown(S32 x, S32 y, MASK mask) { mMouseDown = TRUE; - gViewerWindow->pickAsync(x, y, mask, pickCallback); + gViewerWindow->pickAsync(x, y, mask, pickCallback, FALSE, TRUE); return TRUE; } @@ -409,14 +448,11 @@ BOOL LLToolCompScale::handleMouseUp(S32 x, S32 y, MASK mask) LLTool* LLToolCompScale::getOverrideTool(MASK mask) { - if (gKeyboard->getKeyDown('A') && mask & MASK_CONTROL) - { - return QToolAlign::getInstance(); - } - else if (mask == MASK_CONTROL) + if (mask == MASK_CONTROL) { return LLToolCompRotate::getInstance(); } + return LLToolComposite::getOverrideTool(mask); } @@ -428,7 +464,6 @@ BOOL LLToolCompScale::handleDoubleClick(S32 x, S32 y, MASK mask) // You should already have an object selected from the mousedown. // If so, show its properties gFloaterTools->showPanel(LLFloaterTools::PANEL_CONTENTS); - //gBuildView->setPropertiesPanelOpen(TRUE); return TRUE; } else @@ -480,7 +515,7 @@ BOOL LLToolCompCreate::handleMouseDown(S32 x, S32 y, MASK mask) if ( (mask == MASK_SHIFT) || (mask == MASK_CONTROL) ) { - gViewerWindow->pickAsync(x, y, mask, pickCallback); + gViewerWindow->pickAsync(x, y, mask, pickCallback, FALSE, TRUE); handled = TRUE; } else @@ -564,7 +599,7 @@ BOOL LLToolCompRotate::handleHover(S32 x, S32 y, MASK mask) BOOL LLToolCompRotate::handleMouseDown(S32 x, S32 y, MASK mask) { mMouseDown = TRUE; - gViewerWindow->pickAsync(x, y, mask, pickCallback); + gViewerWindow->pickAsync(x, y, mask, pickCallback, FALSE, TRUE); return TRUE; } @@ -612,11 +647,7 @@ BOOL LLToolCompRotate::handleMouseUp(S32 x, S32 y, MASK mask) LLTool* LLToolCompRotate::getOverrideTool(MASK mask) { - if (gKeyboard->getKeyDown('A') && mask & MASK_CONTROL) - { - return QToolAlign::getInstance(); - } - else if (mask == (MASK_CONTROL | MASK_SHIFT)) + if (mask == (MASK_CONTROL | MASK_SHIFT)) { return LLToolCompScale::getInstance(); } @@ -630,7 +661,6 @@ BOOL LLToolCompRotate::handleDoubleClick(S32 x, S32 y, MASK mask) // You should already have an object selected from the mousedown. // If so, show its properties gFloaterTools->showPanel(LLFloaterTools::PANEL_CONTENTS); - //gBuildView->setPropertiesPanelOpen(TRUE); return TRUE; } else @@ -659,6 +689,7 @@ void LLToolCompRotate::render() LLToolCompGun::LLToolCompGun() : LLToolComposite(std::string("Mouselook")) + , mMenuShown(false), mTimerFOV(), mOriginalFOV(), mStartFOV(), mTargetFOV() { mGun = new LLToolGun(this); mGrab = new LLToolGrab(this); @@ -666,6 +697,8 @@ LLToolCompGun::LLToolCompGun() setCurrentTool(mGun); mDefault = mGun; + + mTimerFOV.stop(); } @@ -682,11 +715,50 @@ LLToolCompGun::~LLToolCompGun() mNull = NULL; } +BOOL LLToolCompGun::handleMouseDown(S32 x, S32 y, MASK mask) +{ + // if the left button is grabbed, don't put up the pie menu + if (gAgent.leftButtonGrabbed()) + { + gAgent.setControlFlags(AGENT_CONTROL_ML_LBUTTON_DOWN); + return FALSE; + } + + // On mousedown, start grabbing + gGrabTransientTool = this; + LLToolMgr::getInstance()->getCurrentToolset()->selectTool( (LLTool*) mGrab ); + + return LLToolGrab::getInstance()->handleMouseDown(x, y, mask); +} + +BOOL LLToolCompGun::handleMouseUp(S32 x, S32 y, MASK mask) +{ + gAgent.setControlFlags(AGENT_CONTROL_ML_LBUTTON_UP); + setCurrentTool( (LLTool*) mGun ); + return TRUE; +} + +BOOL LLToolCompGun::handleDoubleClick(S32 x, S32 y, MASK mask) +{ + // if the left button is grabbed, don't put up the pie menu + if (gAgent.leftButtonGrabbed()) + { + gAgent.setControlFlags(AGENT_CONTROL_ML_LBUTTON_DOWN); + return FALSE; + } + + // On mousedown, start grabbing + gGrabTransientTool = this; + LLToolMgr::getInstance()->getCurrentToolset()->selectTool( (LLTool*) mGrab ); + + return LLToolGrab::getInstance()->handleDoubleClick(x, y, mask); +} + BOOL LLToolCompGun::handleHover(S32 x, S32 y, MASK mask) { // *NOTE: This hack is here to make mouselook kick in again after // item selected from context menu. - if ( mCur == mNull && !gPopupMenuView->getVisible() ) + if (mCur == mNull) { LLSelectMgr::getInstance()->deselectAll(); setCurrentTool( (LLTool*) mGrab ); @@ -717,63 +789,45 @@ BOOL LLToolCompGun::handleHover(S32 x, S32 y, MASK mask) return TRUE; } - -BOOL LLToolCompGun::handleMouseDown(S32 x, S32 y, MASK mask) -{ - // if the left button is grabbed, don't put up the pie menu - if (gAgent.leftButtonGrabbed()) +BOOL LLToolCompGun::handleRightMouseDown(S32 x, S32 y, MASK mask) +{ + // Singu Note: Beware the alt-click menu + if (gSavedSettings.getBOOL("LiruMouselookMenu") && mask & MASK_ALT) { - gAgent.setControlFlags(AGENT_CONTROL_ML_LBUTTON_DOWN); - return FALSE; + mMenuShown = true; + return false; } - // On mousedown, start grabbing - gGrabTransientTool = this; - LLToolMgr::getInstance()->getCurrentToolset()->selectTool( (LLTool*) mGrab ); - - return LLToolGrab::getInstance()->handleMouseDown(x, y, mask); -} - - -BOOL LLToolCompGun::handleDoubleClick(S32 x, S32 y, MASK mask) -{ - // if the left button is grabbed, don't put up the pie menu - if (gAgent.leftButtonGrabbed()) + LLViewerCamera& cam(LLViewerCamera::instance()); + if (!mTimerFOV.getStarted()) { - gAgent.setControlFlags(AGENT_CONTROL_ML_LBUTTON_DOWN); - return FALSE; + mStartFOV = cam.getAndSaveDefaultFOV(); + mOriginalFOV = mStartFOV; } + else mStartFOV = cam.getDefaultFOV(); - // On mousedown, start grabbing - gGrabTransientTool = this; - LLToolMgr::getInstance()->getCurrentToolset()->selectTool( (LLTool*) mGrab ); + mTargetFOV = gSavedSettings.getF32("ExodusAlternativeFOV"); + gSavedSettings.getBOOL("LiruMouselookInstantZoom") ? cam.setDefaultFOV(mTargetFOV) : mTimerFOV.start(); + cam.mSavedFOVLoaded = false; - return LLToolGrab::getInstance()->handleDoubleClick(x, y, mask); + return TRUE; } - -BOOL LLToolCompGun::handleRightMouseDown(S32 x, S32 y, MASK mask) +BOOL LLToolCompGun::handleRightMouseUp(S32 x, S32 y, MASK mask) { - /* JC - suppress context menu 8/29/2002 - - // On right mouse, go through some convoluted steps to - // make the build menu appear. - setCurrentTool( (LLTool*) mNull ); - - // This should return FALSE, meaning the context menu will - // be shown. - return FALSE; - */ - - // Returning true will suppress the context menu - return TRUE; -} + // Singu Note: Beware the alt-click menu + if (mMenuShown) + { + mMenuShown = false; + return LLToolComposite::handleRightMouseUp(x, y, mask); + } + LLViewerCamera& cam(LLViewerCamera::instance()); + mStartFOV = cam.getDefaultFOV(); + mTargetFOV = mOriginalFOV; + gSavedSettings.getBOOL("LiruMouselookInstantZoom") ? cam.setDefaultFOV(mTargetFOV) : mTimerFOV.start(); + cam.mSavedFOVLoaded = false; -BOOL LLToolCompGun::handleMouseUp(S32 x, S32 y, MASK mask) -{ - gAgent.setControlFlags(AGENT_CONTROL_ML_LBUTTON_UP); - setCurrentTool( (LLTool*) mGun ); return TRUE; } @@ -796,30 +850,58 @@ void LLToolCompGun::handleSelect() void LLToolCompGun::handleDeselect() { LLToolComposite::handleDeselect(); + if (mTimerFOV.getStarted()) // Note: Load Default FOV if we were zooming in + { + LLViewerCamera::getInstance()->loadDefaultFOV(); + } setMouseCapture(FALSE); } BOOL LLToolCompGun::handleScrollWheel(S32 x, S32 y, S32 clicks) { - //::MOYMOD:: - if(gSavedSettings.getBOOL("zmm_isinml") == 1) + if (gViewerWindow->getRightMouseDown()) { - if(clicks > 0) - { - gSavedSettings.setF32("zmm_mlfov", gSavedSettings.getF32("zmm_mlfov") / 1.1); - } - else if(clicks < 0) - { - gSavedSettings.setF32("zmm_mlfov", gSavedSettings.getF32("zmm_mlfov") * 1.1); - } - LLViewerCamera::getInstance()->setDefaultFOV(gSavedSettings.getF32("zmm_deffov") / gSavedSettings.getF32("zmm_mlfov")); - return TRUE; - } - if (clicks > 0) + LLViewerCamera& cam(LLViewerCamera::instance()); + mStartFOV = cam.getDefaultFOV(); + + gSavedSettings.setF32( + "ExodusAlternativeFOV", + mTargetFOV = clicks > 0 ? + llclamp(mTargetFOV += (0.05f * clicks), 0.1f, 3.0f) : + llclamp(mTargetFOV -= (0.05f * -clicks), 0.1f, 3.0f) + ); + + if (gSavedSettings.getBOOL("LiruMouselookInstantZoom")) + cam.setDefaultFOV(mTargetFOV); + else + mTimerFOV.start(); + cam.mSavedFOVLoaded = false; + } + else if (clicks > 0) { gAgentCamera.changeCameraToDefault(); - } return TRUE; } + +void LLToolCompGun::draw() +{ + if (mTimerFOV.getStarted()) + { + LLViewerCamera& cam(LLViewerCamera::instance()); + if (!cam.mSavedFOVLoaded && mStartFOV != mTargetFOV) + { + F32 timer = mTimerFOV.getElapsedTimeF32(); + + if (timer > 0.15f) + { + cam.setDefaultFOV(mTargetFOV); + mTimerFOV.stop(); + } + else cam.setDefaultFOV(lerp(mStartFOV, mTargetFOV, timer * 6.66f)); + } + else mTimerFOV.stop(); + } + LLToolComposite::draw(); +} diff --git a/indra/newview/lltoolcomp.h b/indra/newview/lltoolcomp.h index 81ed0ba8e4..20485e3e0c 100644 --- a/indra/newview/lltoolcomp.h +++ b/indra/newview/lltoolcomp.h @@ -2,31 +2,25 @@ * @file lltoolcomp.h * @brief Composite tools * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -68,7 +62,7 @@ class LLToolComposite : public LLTool virtual BOOL clipMouseWhenDown() { return mCur->clipMouseWhenDown(); } virtual void handleSelect(); - virtual void handleDeselect() { mCur->handleDeselect(); mCur = mDefault; mSelected = FALSE; } + virtual void handleDeselect(); virtual void render() { mCur->render(); } virtual void draw() { mCur->draw(); } @@ -84,9 +78,10 @@ class LLToolComposite : public LLTool { mCur->localPointToScreen(local_x, local_y, screen_x, screen_y); } BOOL isSelecting(); + LLTool* getCurrentTool() { return mCur; } + protected: void setCurrentTool( LLTool* new_tool ); - LLTool* getCurrentTool() { return mCur; } // In hover handler, call this to auto-switch tools void setToolFromMask( MASK mask, LLTool *normal ); @@ -114,9 +109,18 @@ class LLToolCompInspect : public LLToolComposite, public LLSingleton LLToolCompGun(); virtual ~LLToolCompGun(); + virtual void draw(); + // Overridden from LLToolComposite - virtual BOOL handleHover(S32 x, S32 y, MASK mask); virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); + virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask); + virtual BOOL handleHover(S32 x, S32 y, MASK mask); virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); - virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); + virtual BOOL handleRightMouseUp(S32 x, S32 y, MASK mask); virtual BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); virtual void onMouseCaptureLost(); virtual void handleSelect(); @@ -235,6 +242,13 @@ class LLToolCompGun : public LLToolComposite, public LLSingleton LLToolGun* mGun; LLToolGrab* mGrab; LLTool* mNull; + +private: + bool mMenuShown; + LLTimer mTimerFOV; + F32 mOriginalFOV, + mStartFOV, + mTargetFOV; }; diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp index a97711e4ec..0bd9170679 100644 --- a/indra/newview/lltooldraganddrop.cpp +++ b/indra/newview/lltooldraganddrop.cpp @@ -31,26 +31,19 @@ */ #include "llviewerprecompiledheaders.h" - -#include "message.h" #include "lltooldraganddrop.h" +// library headers #include "llnotificationsutil.h" - -#include "llinstantmessage.h" -#include "lldir.h" - +// project headers #include "llagent.h" #include "llagentcamera.h" #include "llagentwearables.h" #include "llappearancemgr.h" #include "lldictionary.h" -#include "llviewercontrol.h" #include "llfirstuse.h" -#include "llfloater.h" -#include "llfloaterinventory.h" +#include "llfloateravatarpicker.h" #include "llfloatertools.h" -#include "llfocusmgr.h" #include "llgesturemgr.h" #include "llgiveinventory.h" #include "llhudmanager.h" @@ -59,41 +52,26 @@ #include "llinventorybridge.h" #include "llinventorydefines.h" #include "llinventoryfunctions.h" -#include "llinventorypanel.h" -#include "llmutelist.h" -#include "llnotify.h" +#include "llparcel.h" // Rez under Land Group #include "llpreviewnotecard.h" +#include "llrootview.h" #include "llselectmgr.h" #include "lltoolmgr.h" #include "lltrans.h" -#include "llui.h" -#include "llviewertexturelist.h" -#include "llviewerinventory.h" -#include "llviewerobject.h" #include "llviewerobjectlist.h" +#include "llviewerparcelmgr.h" // Rez under Land Group #include "llviewerregion.h" #include "llviewerstats.h" #include "llviewerwindow.h" #include "llvoavatarself.h" -#include "llvolume.h" #include "llworld.h" -#include "object_flags.h" -// -#include "llappviewer.h" // System Folders -#include "llparcel.h" // always rez -#include "llviewerparcelmgr.h" // always rez -// - -// [RLVa:KB] - Checked: 2010-03-04 (RLVa-1.2.0a) +#include "llpanelface.h" + +// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1) #include "rlvhandler.h" #include "rlvlocks.h" // [/RLVa:KB] -// MAX ITEMS is based on (sizeof(uuid)+2) * count must be < MTUBYTES -// or 18 * count < 1200 => count < 1200/18 => 66. I've cut it down a -// bit from there to give some pad. -const S32 MAX_ITEMS = 42; - // syntactic sugar #define callMemberFunction(object,ptrToMember) ((object).*(ptrToMember)) @@ -209,7 +187,7 @@ class LLCategoryFireAndForget : public LLInventoryFetchComboObserver virtual void done() { /* no-op: it's fire n forget right? */ - lldebugs << "LLCategoryFireAndForget::done()" << llendl; + LL_DEBUGS() << "LLCategoryFireAndForget::done()" << LL_ENDL; } }; @@ -290,10 +268,10 @@ void LLCategoryDropDescendentsObserver::done() LLInventoryModel::EXCLUDE_TRASH); } - S32 count = items.count(); + S32 count = items.size(); if(count) { - std::set unique_ids; + uuid_set_t unique_ids; for(S32 i = 0; i < count; ++i) { unique_ids.insert(items.get(i)->getUUID()); @@ -302,9 +280,9 @@ void LLCategoryDropDescendentsObserver::done() std::back_insert_iterator copier(ids); std::copy(unique_ids.begin(), unique_ids.end(), copier); LLCategoryDropObserver* dropper; - dropper = new LLCategoryDropObserver(mObjectID, mSource); - dropper->fetchItems(ids); - if(dropper->isEverythingComplete()) + dropper = new LLCategoryDropObserver(ids, mObjectID, mSource); + dropper->startFetch(); + if (dropper->isDone()) { dropper->done(); } @@ -368,14 +346,15 @@ LLToolDragAndDrop::LLDragAndDropDictionary::LLDragAndDropDictionary() }; LLToolDragAndDrop::LLToolDragAndDrop() -: LLTool(std::string("draganddrop"), NULL), - mDragStartX(0), - mDragStartY(0), - mSource(SOURCE_AGENT), - mCursor(UI_CURSOR_NO), - mLastAccept(ACCEPT_NO), - mDrop(FALSE), - mCurItemIndex(0) +: LLTool(std::string("draganddrop"), NULL), + mCargoCount(0), + mDragStartX(0), + mDragStartY(0), + mSource(SOURCE_AGENT), + mCursor(UI_CURSOR_NO), + mLastAccept(ACCEPT_NO), + mDrop(FALSE), + mCurItemIndex(0) { } @@ -388,9 +367,12 @@ void LLToolDragAndDrop::setDragStart(S32 x, S32 y) BOOL LLToolDragAndDrop::isOverThreshold(S32 x,S32 y) { - const S32 MIN_MANHATTAN_DIST = 3; - S32 manhattan_dist = llabs( x - mDragStartX ) + llabs( y - mDragStartY ); - return manhattan_dist >= MIN_MANHATTAN_DIST; + static LLCachedControl drag_and_drop_threshold(gSavedSettings,"DragAndDropDistanceThreshold", 3); + + S32 mouse_delta_x = x - mDragStartX; + S32 mouse_delta_y = y - mDragStartY; + + return (mouse_delta_x * mouse_delta_x) + (mouse_delta_y * mouse_delta_y) > drag_and_drop_threshold * drag_and_drop_threshold; } void LLToolDragAndDrop::beginDrag(EDragAndDropType type, @@ -401,7 +383,7 @@ void LLToolDragAndDrop::beginDrag(EDragAndDropType type, { if(type == DAD_NONE) { - llwarns << "Attempted to start drag without a cargo type" << llendl; + LL_WARNS() << "Attempted to start drag without a cargo type" << LL_ENDL; return; } mCargoTypes.clear(); @@ -438,16 +420,16 @@ void LLToolDragAndDrop::beginDrag(EDragAndDropType type, items, LLInventoryModel::EXCLUDE_TRASH, is_not_preferred); - S32 count = cats.count(); + S32 count = cats.size(); S32 i; for(i = 0; i < count; ++i) { - folder_ids.push_back(cats.get(i)->getUUID()); + folder_ids.push_back(cats.at(i)->getUUID()); } - count = items.count(); + count = items.size(); for(i = 0; i < count; ++i) { - item_ids.push_back(items.get(i)->getUUID()); + item_ids.push_back(items.at(i)->getUUID()); } if(!folder_ids.empty() || !item_ids.empty()) { @@ -473,7 +455,7 @@ void LLToolDragAndDrop::beginMultiDrag( { if(DAD_NONE == *types_it) { - llwarns << "Attempted to start drag without a cargo type" << llendl; + LL_WARNS() << "Attempted to start drag without a cargo type" << LL_ENDL; return; } } @@ -490,7 +472,7 @@ void LLToolDragAndDrop::beginMultiDrag( // find categories (i.e. inventory folders) in the cargo. LLInventoryCategory* cat = NULL; S32 count = llmin(cargo_ids.size(), types.size()); - std::set cat_ids; + uuid_set_t cat_ids; for(S32 i = 0; i < count; ++i) { cat = gInventory.getCategory(cargo_ids[i]); @@ -509,7 +491,7 @@ void LLToolDragAndDrop::beginMultiDrag( items, LLInventoryModel::EXCLUDE_TRASH, is_not_preferred); - S32 cat_count = cats.count(); + S32 cat_count = cats.size(); for(S32 i = 0; i < cat_count; ++i) { cat_ids.insert(cat->getUUID()); @@ -529,6 +511,7 @@ void LLToolDragAndDrop::beginMultiDrag( void LLToolDragAndDrop::endDrag() { + mEndDragSignal(); LLSelectMgr::getInstance()->unhighlightAll(); setMouseCapture(FALSE); } @@ -585,6 +568,8 @@ ECursorType LLToolDragAndDrop::acceptanceToCursor( EAcceptance acceptance ) mCursor = UI_CURSOR_NOLOCKED; break; + + case ACCEPT_NO: mCursor = UI_CURSOR_NO; break; @@ -627,7 +612,7 @@ BOOL LLToolDragAndDrop::handleHover( S32 x, S32 y, MASK mask ) ECursorType cursor = acceptanceToCursor(acceptance); gViewerWindow->getWindow()->setCursor( cursor ); - lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolDragAndDrop" << llendl; + LL_DEBUGS("UserInput") << "hover handled by LLToolDragAndDrop" << LL_ENDL; return TRUE; } @@ -679,33 +664,41 @@ void LLToolDragAndDrop::dragOrDrop( S32 x, S32 y, MASK mask, BOOL drop, sOperationId++; } + // For people drag and drop we don't need an actual inventory object, + // instead we need the current cargo id, which should be a person id. + bool is_uuid_dragged = (mSource == SOURCE_PEOPLE); + if(top_view) { handled = TRUE; for (mCurItemIndex = 0; mCurItemIndex < (S32)mCargoIDs.size(); mCurItemIndex++) { - LLInventoryObject* cargo = locateInventory(item, cat); + S32 local_x, local_y; + top_view->screenPointToLocal( x, y, &local_x, &local_y ); + EAcceptance item_acceptance = ACCEPT_NO; + LLInventoryObject* cargo = locateInventory(item, cat); if (cargo) { - S32 local_x, local_y; - top_view->screenPointToLocal( x, y, &local_x, &local_y ); - EAcceptance item_acceptance = ACCEPT_NO; handled = handled && top_view->handleDragAndDrop(local_x, local_y, mask, FALSE, mCargoTypes[mCurItemIndex], (void*)cargo, &item_acceptance, mToolTipMsg); - if (handled) - { - // use sort order to determine priority of acceptance - *acceptance = (EAcceptance)llmin((U32)item_acceptance, (U32)*acceptance); - } } - else + else if (is_uuid_dragged) + { + handled = handled && top_view->handleDragAndDrop(local_x, local_y, mask, FALSE, + mCargoTypes[mCurItemIndex], + (void*)&mCargoIDs[mCurItemIndex], + &item_acceptance, + mToolTipMsg); + } + if (handled) { - return; + // use sort order to determine priority of acceptance + *acceptance = (EAcceptance)llmin((U32)item_acceptance, (U32)*acceptance); } } @@ -722,20 +715,27 @@ void LLToolDragAndDrop::dragOrDrop( S32 x, S32 y, MASK mask, BOOL drop, for (mCurItemIndex = 0; mCurItemIndex < (S32)mCargoIDs.size(); mCurItemIndex++) { - LLInventoryObject* cargo = locateInventory(item, cat); + S32 local_x, local_y; + EAcceptance item_acceptance; + top_view->screenPointToLocal( x, y, &local_x, &local_y ); + LLInventoryObject* cargo = locateInventory(item, cat); if (cargo) { - S32 local_x, local_y; - - EAcceptance item_acceptance; - top_view->screenPointToLocal( x, y, &local_x, &local_y ); handled = handled && top_view->handleDragAndDrop(local_x, local_y, mask, TRUE, mCargoTypes[mCurItemIndex], (void*)cargo, &item_acceptance, mToolTipMsg); } + else if (is_uuid_dragged) + { + handled = handled && top_view->handleDragAndDrop(local_x, local_y, mask, FALSE, + mCargoTypes[mCurItemIndex], + (void*)&mCargoIDs[mCurItemIndex], + &item_acceptance, + mToolTipMsg); + } } } if (handled) @@ -752,20 +752,27 @@ void LLToolDragAndDrop::dragOrDrop( S32 x, S32 y, MASK mask, BOOL drop, for (mCurItemIndex = 0; mCurItemIndex < (S32)mCargoIDs.size(); mCurItemIndex++) { + EAcceptance item_acceptance = ACCEPT_NO; + LLInventoryObject* cargo = locateInventory(item, cat); - if (!cargo) + // fix for EXT-3191 + if (cargo) { - handled = FALSE; - break; + handled = handled && root_view->handleDragAndDrop(x, y, mask, FALSE, + mCargoTypes[mCurItemIndex], + (void*)cargo, + &item_acceptance, + mToolTipMsg); + } + else if (is_uuid_dragged) + { + handled = handled && root_view->handleDragAndDrop(x, y, mask, FALSE, + mCargoTypes[mCurItemIndex], + (void*)&mCargoIDs[mCurItemIndex], + &item_acceptance, + mToolTipMsg); } - - EAcceptance item_acceptance = ACCEPT_NO; - handled = handled && root_view->handleDragAndDrop(x, y, mask, FALSE, - mCargoTypes[mCurItemIndex], - (void*)cargo, - &item_acceptance, - mToolTipMsg); if (handled) { // use sort order to determine priority of acceptance @@ -785,17 +792,25 @@ void LLToolDragAndDrop::dragOrDrop( S32 x, S32 y, MASK mask, BOOL drop, for (mCurItemIndex = 0; mCurItemIndex < (S32)mCargoIDs.size(); mCurItemIndex++) { - LLInventoryObject* cargo = locateInventory(item, cat); + EAcceptance item_acceptance; + LLInventoryObject* cargo = locateInventory(item, cat); if (cargo) { - EAcceptance item_acceptance; handled = handled && root_view->handleDragAndDrop(x, y, mask, TRUE, mCargoTypes[mCurItemIndex], (void*)cargo, &item_acceptance, mToolTipMsg); } + else if (is_uuid_dragged) + { + handled = handled && root_view->handleDragAndDrop(x, y, mask, TRUE, + mCargoTypes[mCurItemIndex], + (void*)&mCargoIDs[mCurItemIndex], + &item_acceptance, + mToolTipMsg); + } } } @@ -807,8 +822,9 @@ void LLToolDragAndDrop::dragOrDrop( S32 x, S32 y, MASK mask, BOOL drop, if ( !handled ) { + // *TODO: Suppress the "outbox" case once "marketplace" is used everywhere for everyone // Disallow drag and drop to 3D from the outbox - const LLUUID outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false, false); + const LLUUID outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false); if (outbox_id.notNull()) { for (S32 item_index = 0; item_index < (S32)mCargoIDs.size(); item_index++) @@ -821,7 +837,21 @@ void LLToolDragAndDrop::dragOrDrop( S32 x, S32 y, MASK mask, BOOL drop, } } } - + // Disallow drag and drop to 3D from the marketplace + const LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS, false); + if (marketplacelistings_id.notNull()) + { + for (S32 item_index = 0; item_index < (S32)mCargoIDs.size(); item_index++) + { + if (gInventory.isObjectDescendentOf(mCargoIDs[item_index], outbox_id)) + { + *acceptance = ACCEPT_NO; + mToolTipMsg = LLTrans::getString("TooltipOutboxDragToWorld"); + return; + } + } + } + dragOrDrop3D( x, y, mask, drop, acceptance ); } } @@ -832,12 +862,12 @@ void LLToolDragAndDrop::dragOrDrop3D( S32 x, S32 y, MASK mask, BOOL drop, EAccep if (mDrop) { // don't allow drag and drop onto transparent objects - pick(gViewerWindow->pickImmediate(x, y, FALSE)); + pick(gViewerWindow->pickImmediate(x, y, FALSE, FALSE)); } else { // don't allow drag and drop onto transparent objects - gViewerWindow->pickAsync(x, y, mask, pickCallback, FALSE); + gViewerWindow->pickAsync(x, y, mask, pickCallback, FALSE, FALSE); } *acceptance = mLastAccept; @@ -934,8 +964,7 @@ void LLToolDragAndDrop::pick(const LLPickInfo& pick_info) const S32 item_index = mCurItemIndex; const EDragAndDropType dad_type = mCargoTypes[item_index]; // Call the right implementation function - (U32)callMemberFunction(*this, - LLDragAndDropDictionary::instance().get(dad_type, target)) + callMemberFunction(*this, LLDragAndDropDictionary::instance().get(dad_type, target)) (hit_obj, hit_face, pick_info.mKeyMask, TRUE); } } @@ -981,11 +1010,14 @@ BOOL LLToolDragAndDrop::handleDropTextureProtections(LLViewerObject* hit_obj, return TRUE; } - // In case the inventory has not been updated (e.g. due to some recent operation - // causing a dirty inventory), stall the user while fetching the inventory. - if (hit_obj->isInventoryDirty()) + // In case the inventory has not been loaded (e.g. due to some recent operation + // causing a dirty inventory) and we can do an update, stall the user + // while fetching the inventory. + // + // Fetch if inventory is dirty and listener is present (otherwise we will not receive update) + if (hit_obj->isInventoryDirty() && hit_obj->hasInventoryListeners()) { - hit_obj->fetchInventoryFromServer(); + hit_obj->requestInventory(); LLSD args; args["ERROR_MESSAGE"] = "Unable to add texture.\nPlease wait a few seconds and try again."; LLNotificationsUtil::add("ErrorMessage", args); @@ -1030,7 +1062,7 @@ BOOL LLToolDragAndDrop::handleDropTextureProtections(LLViewerObject* hit_obj, } else { - llwarns << "Unable to find source object." << llendl; + LL_WARNS() << "Unable to find source object." << LL_ENDL; return FALSE; } } @@ -1065,10 +1097,12 @@ BOOL LLToolDragAndDrop::handleDropTextureProtections(LLViewerObject* hit_obj, { hit_obj->updateInventory(new_item, TASK_INVENTORY_ITEM_KEY, true); } - // Force the object to update its refetch its inventory so it has this texture. - hit_obj->fetchInventoryFromServer(); + // Force the object to update and refetch its inventory so it has this texture. + hit_obj->dirtyInventory(); + hit_obj->requestInventory(); // TODO: Check to see if adding the item was successful; if not, then - // we should return false here. + // we should return false here. This will requre a separate listener + // since without listener, we have no way to receive update } return TRUE; } @@ -1080,7 +1114,7 @@ void LLToolDragAndDrop::dropTextureAllFaces(LLViewerObject* hit_obj, { if (!item) { - llwarns << "LLToolDragAndDrop::dropTextureAllFaces no texture item." << llendl; + LL_WARNS() << "LLToolDragAndDrop::dropTextureAllFaces no texture item." << LL_ENDL; return; } LLUUID asset_id = item->getAssetUUID(); @@ -1113,7 +1147,7 @@ void LLToolDragAndDrop::dropMesh(LLViewerObject* hit_obj, { if (!item) { - llwarns << "no inventory item." << llendl; + LL_WARNS() << "no inventory item." << LL_ENDL; return; } LLUUID asset_id = item->getAssetUUID(); @@ -1124,8 +1158,7 @@ void LLToolDragAndDrop::dropMesh(LLViewerObject* hit_obj, } LLSculptParams sculpt_params; - sculpt_params.setSculptTexture(asset_id); - sculpt_params.setSculptType(LL_SCULPT_TYPE_MESH); + sculpt_params.setSculptTexture(asset_id, LL_SCULPT_TYPE_MESH); hit_obj->setParameterEntry(LLNetworkData::PARAMS_SCULPT, sculpt_params, TRUE); dialog_refresh_all(); @@ -1150,7 +1183,7 @@ void LLToolDragAndDrop::dropTextureOneFace(LLViewerObject* hit_obj, if (hit_face == -1) return; if (!item) { - llwarns << "LLToolDragAndDrop::dropTextureOneFace no texture item." << llendl; + LL_WARNS() << "LLToolDragAndDrop::dropTextureOneFace no texture item." << LL_ENDL; return; } LLUUID asset_id = item->getAssetUUID(); @@ -1162,10 +1195,57 @@ void LLToolDragAndDrop::dropTextureOneFace(LLViewerObject* hit_obj, // update viewer side image in anticipation of update from simulator //LLViewerTexture* image = LLViewerTextureManager::getFetchedTexture(asset_id); LLViewerStats::getInstance()->incStat(LLViewerStats::ST_EDIT_TEXTURE_COUNT ); - //hit_obj->setTEImage(hit_face, image); - hit_obj->setTETexture(hit_face, asset_id); //Singu note: setTETexture will allow the real id to be passed to LLPrimitive::setTETexture, - // even if it's null. setTEImage would actually pass down IMG_DEFAULT under such a case, - // which we don't want. + + LLTextureEntry* tep = hit_obj ? (hit_obj->getTE(hit_face)) : NULL; + + LLPanelFace* panel_face = gFloaterTools->getPanelFace(); + + if (gFloaterTools->getVisible() && panel_face) + { + switch (LLSelectMgr::getInstance()->getTextureChannel()) + { + + case 0: + default: + { + //hit_obj->setTEImage(hit_face, image); + hit_obj->setTETexture(hit_face, asset_id); //Singu note: setTETexture will allow the real id to be passed to LLPrimitive::setTETexture, + // even if it's null. setTEImage would actually pass down IMG_DEFAULT under such a case, + // which we don't want. + } + break; + + case 1: + { + LLMaterialPtr old_mat = tep->getMaterialParams(); + LLMaterialPtr new_mat = panel_face->createDefaultMaterial(old_mat); + new_mat->setNormalID(asset_id); + tep->setMaterialParams(new_mat); + hit_obj->setTENormalMap(hit_face, asset_id); + LLMaterialMgr::getInstance()->put(hit_obj->getID(), hit_face, *new_mat); + } + break; + + case 2: + { + LLMaterialPtr old_mat = tep->getMaterialParams(); + LLMaterialPtr new_mat = panel_face->createDefaultMaterial(old_mat); + new_mat->setSpecularID(asset_id); + tep->setMaterialParams(new_mat); + hit_obj->setTESpecularMap(hit_face, asset_id); + LLMaterialMgr::getInstance()->put(hit_obj->getID(), hit_face, *new_mat); + } + break; + } + } + else if (hit_obj) + { + //hit_obj->setTEImage(hit_face, image); + hit_obj->setTETexture(hit_face, asset_id); //Singu note: setTETexture will allow the real id to be passed to LLPrimitive::setTETexture, + // even if it's null. setTEImage would actually pass down IMG_DEFAULT under such a case, + // which we don't want. + } + dialog_refresh_all(); // send the update to the simulator @@ -1184,8 +1264,8 @@ void LLToolDragAndDrop::dropScript(LLViewerObject* hit_obj, if((SOURCE_WORLD == LLToolDragAndDrop::getInstance()->mSource) || (SOURCE_NOTECARD == LLToolDragAndDrop::getInstance()->mSource)) { - llwarns << "Call to LLToolDragAndDrop::dropScript() from world" - << " or notecard." << llendl; + LL_WARNS() << "Call to LLToolDragAndDrop::dropScript() from world" + << " or notecard." << LL_ENDL; return; } if(hit_obj && item) @@ -1212,7 +1292,7 @@ void LLToolDragAndDrop::dropScript(LLViewerObject* hit_obj, } else { - llwarns << "Unable to find source object." << llendl; + LL_WARNS() << "Unable to find source object." << LL_ENDL; return; } } @@ -1243,7 +1323,7 @@ void LLToolDragAndDrop::dropObject(LLViewerObject* raycast_target, LLViewerRegion* regionp = LLWorld::getInstance()->getRegionFromPosGlobal(mLastHitPos); if (!regionp) { - llwarns << "Couldn't find region to rez object" << llendl; + LL_WARNS() << "Couldn't find region to rez object" << LL_ENDL; return; } @@ -1256,7 +1336,7 @@ void LLToolDragAndDrop::dropObject(LLViewerObject* raycast_target, } // [/RLVa:KB] - //llinfos << "Rezzing object" << llendl; + //LL_INFOS() << "Rezzing object" << LL_ENDL; make_ui_sound("UISndObjectRezIn"); LLViewerInventoryItem* item; LLViewerInventoryCategory* cat; @@ -1333,19 +1413,21 @@ void LLToolDragAndDrop::dropObject(LLViewerObject* raycast_target, msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - // Alway rez objects as land group if available. - if (gSavedSettings.getBOOL("AscentAlwaysRezInGroup")) - { - LLParcel *parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); - if(gAgent.isInGroup(parcel->getGroupID())) - msg->addUUIDFast(_PREHASH_GroupID, parcel->getGroupID()); - else if(gAgent.isInGroup(parcel->getOwnerID())) - msg->addUUIDFast(_PREHASH_GroupID, parcel->getOwnerID()); - else - msg->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID()); + // Rez under Land Group + static LLCachedControl AlchemyRezUnderLandGroup(gSavedSettings, "AscentAlwaysRezInGroup"); + LLUUID group_id = gAgent.getGroupID(); + if (AlchemyRezUnderLandGroup) + { + LLParcel* land_parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + // Is the agent in the land group + if (gAgent.isInGroup(land_parcel->getGroupID())) + group_id = land_parcel->getGroupID(); + // Is the agent in the land group (the group owns the land) + else if (gAgent.isInGroup(land_parcel->getOwnerID())) + group_id = land_parcel->getOwnerID(); } - else - msg->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID()); + + msg->addUUIDFast(_PREHASH_GroupID, group_id); msg->nextBlock("RezData"); // if it's being rezzed from task inventory, we need to enable @@ -1408,6 +1490,7 @@ void LLToolDragAndDrop::dropObject(LLViewerObject* raycast_target, gInventory.deleteObject(item->getUUID()); gInventory.notifyObservers(); } + // if (gSavedSettings.getBOOL("BroadcastViewerEffects")) { @@ -1421,6 +1504,7 @@ void LLToolDragAndDrop::dropObject(LLViewerObject* raycast_target, // } // + LLViewerStats::getInstance()->incStat(LLViewerStats::ST_REZ_COUNT); } @@ -1434,8 +1518,8 @@ void LLToolDragAndDrop::dropInventory(LLViewerObject* hit_obj, if((SOURCE_WORLD == LLToolDragAndDrop::getInstance()->mSource) || (SOURCE_NOTECARD == LLToolDragAndDrop::getInstance()->mSource)) { - llwarns << "Call to LLToolDragAndDrop::dropInventory() from world" - << " or notecard." << llendl; + LL_WARNS() << "Call to LLToolDragAndDrop::dropInventory() from world" + << " or notecard." << LL_ENDL; return; } @@ -1465,7 +1549,7 @@ void LLToolDragAndDrop::dropInventory(LLViewerObject* hit_obj, } else { - llwarns << "Unable to find source object." << llendl; + LL_WARNS() << "Unable to find source object." << LL_ENDL; return; } } @@ -1476,6 +1560,7 @@ void LLToolDragAndDrop::dropInventory(LLViewerObject* hit_obj, // *FIX: only show this if panel not expanded? gFloaterTools->showPanel(LLFloaterTools::PANEL_CONTENTS); } + // if (gSavedSettings.getBOOL("BroadcastViewerEffects")) { @@ -1492,18 +1577,6 @@ void LLToolDragAndDrop::dropInventory(LLViewerObject* hit_obj, gFloaterTools->dirty(); } -struct LLGiveInventoryInfo -{ - LLUUID mToAgentID; - LLUUID mInventoryObjectID; - LLUUID mIMSessionID; - LLGiveInventoryInfo(const LLUUID& to_agent, const LLUUID& obj_id, const LLUUID &im_session_id = LLUUID::null) : - mToAgentID(to_agent), - mInventoryObjectID(obj_id), - mIMSessionID(im_session_id) - {} -}; - // accessor that looks at permissions, copyability, and names of // inventory items to determine if a drop would be ok. EAcceptance LLToolDragAndDrop::willObjectAcceptInventory(LLViewerObject* obj, LLInventoryItem* item) @@ -1512,9 +1585,7 @@ EAcceptance LLToolDragAndDrop::willObjectAcceptInventory(LLViewerObject* obj, LL if(!item || !obj) return ACCEPT_NO; // HACK: downcast LLViewerInventoryItem* vitem = (LLViewerInventoryItem*)item; - if(!vitem->isFinished()) return ACCEPT_NO; - if (vitem->getIsLinkType()) return ACCEPT_NO; // No giving away links // deny attempts to drop from an object onto itself. This is to @@ -1550,7 +1621,7 @@ EAcceptance LLToolDragAndDrop::willObjectAcceptInventory(LLViewerObject* obj, LL case LLAssetType::AT_CALLINGCARD: // Calling Cards in object are disabled for now // because of incomplete LSL support. See STORM-1117. - return ACCEPT_NO; + //return ACCEPT_NO; default: break; } @@ -1563,7 +1634,7 @@ EAcceptance LLToolDragAndDrop::willObjectAcceptInventory(LLViewerObject* obj, LL transfer = TRUE; } BOOL volume = (LL_PCODE_VOLUME == obj->getPCode()); - BOOL attached = obj->isAttachment(); + BOOL attached = false; // No longer necessary. BOOL unrestricted = ((perm.getMaskBase() & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED) ? TRUE : FALSE; // [RLVa:KB] - Checked: 2010-03-31 (RLVa-1.2.0c) | Modified: RLVa-1.0.0c @@ -1598,12 +1669,87 @@ EAcceptance LLToolDragAndDrop::willObjectAcceptInventory(LLViewerObject* obj, LL } +static void give_inventory_cb(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + // if Cancel pressed + if (option == 1) + { + return; + } + + LLSD payload = notification["payload"]; + const LLUUID& session_id = payload["session_id"]; + const LLUUID& agent_id = payload["agent_id"]; + LLViewerInventoryItem * inv_item = gInventory.getItem(payload["item_id"]); + LLViewerInventoryCategory * inv_cat = gInventory.getCategory(payload["item_id"]); + if (NULL == inv_item && NULL == inv_cat) + { + llassert( FALSE ); + return; + } + bool successfully_shared; + if (inv_item) + { + successfully_shared = LLGiveInventory::doGiveInventoryItem(agent_id, inv_item, session_id); + } + else + { + successfully_shared = LLGiveInventory::doGiveInventoryCategory(agent_id, inv_cat, session_id); + } + if (successfully_shared) + { + if ("avatarpicker" == payload["d&d_dest"].asString()) + { + if (LLFloaterAvatarPicker::instanceExists()) + LLFloaterAvatarPicker::getInstance()->close(); + } + LLNotificationsUtil::add("ItemsShared"); + } +} + +static void show_object_sharing_confirmation(const std::string name, + LLInventoryObject* inv_item, + const LLSD& dest, + const LLUUID& dest_agent, + const LLUUID& session_id = LLUUID::null) +{ + if (!inv_item) + { + llassert(NULL != inv_item); + return; + } + LLSD substitutions; + substitutions["RESIDENTS"] = name; + substitutions["ITEMS"] = inv_item->getName(); + LLSD payload; + payload["agent_id"] = dest_agent; + payload["item_id"] = inv_item->getUUID(); + payload["session_id"] = session_id; + payload["d&d_dest"] = dest.asString(); + LLNotificationsUtil::add("ShareItemsConfirmation", substitutions, payload, &give_inventory_cb); +} + +static void get_name_cb(const LLUUID& id, + const std::string& full_name, + LLInventoryObject* inv_obj, + const LLSD& dest, + const LLUUID& dest_agent) +{ + show_object_sharing_confirmation(full_name, + inv_obj, + dest, + id, + LLUUID::null); +} + // function used as drag-and-drop handler for simple agent give inventory requests //static bool LLToolDragAndDrop::handleGiveDragAndDrop(LLUUID dest_agent, LLUUID session_id, BOOL drop, EDragAndDropType cargo_type, void* cargo_data, - EAcceptance* accept) + EAcceptance* accept, + const LLSD& dest) { // check the type switch(cargo_type) @@ -1619,6 +1765,7 @@ bool LLToolDragAndDrop::handleGiveDragAndDrop(LLUUID dest_agent, LLUUID session_ case DAD_ANIMATION: case DAD_GESTURE: case DAD_CALLINGCARD: + case DAD_MESH: { LLViewerInventoryItem* inv_item = (LLViewerInventoryItem*)cargo_data; if(gInventory.getItem(inv_item->getUUID()) @@ -1680,14 +1827,14 @@ bool LLToolDragAndDrop::handleGiveDragAndDrop(LLUUID dest_agent, LLUUID session_ EAcceptance LLToolDragAndDrop::dad3dNULL( LLViewerObject*, S32, MASK, BOOL) { - lldebugs << "LLToolDragAndDrop::dad3dNULL()" << llendl; + LL_DEBUGS() << "LLToolDragAndDrop::dad3dNULL()" << LL_ENDL; return ACCEPT_NO; } EAcceptance LLToolDragAndDrop::dad3dRezAttachmentFromInv( LLViewerObject* obj, S32 face, MASK mask, BOOL drop) { - lldebugs << "LLToolDragAndDrop::dad3dRezAttachmentFromInv()" << llendl; + LL_DEBUGS() << "LLToolDragAndDrop::dad3dRezAttachmentFromInv()" << LL_ENDL; // must be in the user's inventory if(mSource != SOURCE_AGENT && mSource != SOURCE_LIBRARY) { @@ -1707,13 +1854,13 @@ EAcceptance LLToolDragAndDrop::dad3dRezAttachmentFromInv( } // must not be already wearing it - // - //LLVOAvatar* my_avatar = gAgentAvatarp; - //if( !my_avatar || my_avatar->isWearingAttachment( item->getUUID() ) ) - //{ - // return ACCEPT_NO; - //} - // + /* + LLVOAvatarSelf* avatar = gAgentAvatarp; + if( !avatar || avatar->isWearingAttachment(item->getUUID()) ) + { + return ACCEPT_NO; + } + */ const LLUUID &outbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OUTBOX, false); if(gInventory.isObjectDescendentOf(item->getUUID(), outbox_id)) @@ -1736,7 +1883,7 @@ EAcceptance LLToolDragAndDrop::dad3dRezAttachmentFromInv( // LLPointer cb = new RezAttachmentCallback(0); // [SL:KB] - Patch: Appearance-DnDWear | Checked: 2010-09-28 (Catznip-3.0.0a) | Added: Catznip-2.2.0a // Make this behave consistent with dad3dWearItem - LLPointer cb = new LLBoostFuncInventoryCallback(boost::bind(&rez_attachment_cb, _1, (LLViewerJointAttachment*)0, !(mask & MASK_CONTROL))); + LLPointer cb = new LLBoostFuncInventoryCallback(boost::bind(&rez_attachment_cb, _1, (LLViewerJointAttachment*)0, fReplace)); // [/SL:KB] copy_inventory_item( gAgent.getID(), @@ -1775,19 +1922,20 @@ EAcceptance LLToolDragAndDrop::dad3dRezObjectOnLand( return dad3dRezFromObjectOnLand(obj, face, mask, drop); } - lldebugs << "LLToolDragAndDrop::dad3dRezObjectOnLand()" << llendl; + LL_DEBUGS() << "LLToolDragAndDrop::dad3dRezObjectOnLand()" << LL_ENDL; LLViewerInventoryItem* item; LLViewerInventoryCategory* cat; locateInventory(item, cat); if (!item || !item->isFinished()) return ACCEPT_NO; - // - //LLVOAvatar* my_avatar = gAgentAvatarp; - //if( !my_avatar || my_avatar->isWearingAttachment( item->getUUID() ) ) - //{ - // return ACCEPT_NO; - //} - // + /* + LLVOAvatarSelf* my_avatar = gAgentAvatarp; + if( !my_avatar || my_avatar->isWearingAttachment( item->getUUID() ) ) + { + return ACCEPT_NO; + } + */ + EAcceptance accept; BOOL remove_inventory; @@ -1851,18 +1999,18 @@ EAcceptance LLToolDragAndDrop::dad3dRezObjectOnObject( return dad3dRezFromObjectOnObject(obj, face, mask, drop); } - lldebugs << "LLToolDragAndDrop::dad3dRezObjectOnObject()" << llendl; + LL_DEBUGS() << "LLToolDragAndDrop::dad3dRezObjectOnObject()" << LL_ENDL; LLViewerInventoryItem* item; LLViewerInventoryCategory* cat; locateInventory(item, cat); if(!item || !item->isFinished()) return ACCEPT_NO; - // - //LLVOAvatar* my_avatar = gAgentAvatarp; - //if( !my_avatar || my_avatar->isWearingAttachment( item->getUUID() ) ) - //{ - // return ACCEPT_NO; - //} - // + /* + LLVOAvatarSelf* my_avatar = gAgentAvatarp; + if( !my_avatar || my_avatar->isWearingAttachment( item->getUUID() ) ) + { + return ACCEPT_NO; + } + */ if((mask & MASK_CONTROL)) { @@ -1925,7 +2073,7 @@ EAcceptance LLToolDragAndDrop::dad3dRezObjectOnObject( EAcceptance LLToolDragAndDrop::dad3dRezScript( LLViewerObject* obj, S32 face, MASK mask, BOOL drop) { - lldebugs << "LLToolDragAndDrop::dad3dRezScript()" << llendl; + LL_DEBUGS() << "LLToolDragAndDrop::dad3dRezScript()" << LL_ENDL; // *HACK: In order to resolve SL-22177, we need to block drags // from notecards and objects onto other objects. @@ -1963,25 +2111,22 @@ EAcceptance LLToolDragAndDrop::dad3dRezScript( EAcceptance LLToolDragAndDrop::dad3dApplyToObject( LLViewerObject* obj, S32 face, MASK mask, BOOL drop, EDragAndDropType cargo_type) { - lldebugs << "LLToolDragAndDrop::dad3dApplyToObject()" << llendl; + LL_DEBUGS() << "LLToolDragAndDrop::dad3dApplyToObject()" << LL_ENDL; - // + /* // Fuck this - // *HACK: In order to resolve SL-22177, we need to block drags // from notecards and objects onto other objects. - //if((SOURCE_WORLD == mSource) || (SOURCE_NOTECARD == mSource)) - //{ - // return ACCEPT_NO; - //} - // + if((SOURCE_WORLD == mSource) || (SOURCE_NOTECARD == mSource)) + { + return ACCEPT_NO; + } + */ LLViewerInventoryItem* item; LLViewerInventoryCategory* cat; locateInventory(item, cat); - if(!item || !item->isFinished()) return ACCEPT_NO; - EAcceptance rv = willObjectAcceptInventory(obj, item); if((mask & MASK_CONTROL)) { @@ -2020,7 +2165,7 @@ EAcceptance LLToolDragAndDrop::dad3dApplyToObject( } else { - llwarns << "unsupported asset type" << llendl; + LL_WARNS() << "unsupported asset type" << LL_ENDL; } // VEFFECT: SetTexture @@ -2053,7 +2198,7 @@ EAcceptance LLToolDragAndDrop::dad3dMeshObject( EAcceptance LLToolDragAndDrop::dad3dTextureSelf( LLViewerObject* obj, S32 face, MASK mask, BOOL drop) { - lldebugs << "LLToolDragAndDrop::dad3dTextureAvatar()" << llendl; + LL_DEBUGS() << "LLToolDragAndDrop::dad3dTextureAvatar()" << LL_ENDL; if(drop) { if( !(mask & MASK_SHIFT) ) @@ -2068,7 +2213,7 @@ EAcceptance LLToolDragAndDrop::dad3dTextureSelf( EAcceptance LLToolDragAndDrop::dad3dWearItem( LLViewerObject* obj, S32 face, MASK mask, BOOL drop) { - lldebugs << "LLToolDragAndDrop::dad3dWearItem()" << llendl; + LL_DEBUGS() << "LLToolDragAndDrop::dad3dWearItem()" << LL_ENDL; LLViewerInventoryItem* item; LLViewerInventoryCategory* cat; locateInventory(item, cat); @@ -2120,7 +2265,7 @@ EAcceptance LLToolDragAndDrop::dad3dWearItem( EAcceptance LLToolDragAndDrop::dad3dActivateGesture( LLViewerObject* obj, S32 face, MASK mask, BOOL drop) { - lldebugs << "LLToolDragAndDrop::dad3dActivateGesture()" << llendl; + LL_DEBUGS() << "LLToolDragAndDrop::dad3dActivateGesture()" << LL_ENDL; LLViewerInventoryItem* item; LLViewerInventoryCategory* cat; locateInventory(item, cat); @@ -2169,7 +2314,7 @@ EAcceptance LLToolDragAndDrop::dad3dActivateGesture( EAcceptance LLToolDragAndDrop::dad3dWearCategory( LLViewerObject* obj, S32 face, MASK mask, BOOL drop) { - lldebugs << "LLToolDragAndDrop::dad3dWearCategory()" << llendl; + LL_DEBUGS() << "LLToolDragAndDrop::dad3dWearCategory()" << LL_ENDL; LLViewerInventoryItem* item; LLViewerInventoryCategory* category; locateInventory(item, category); @@ -2226,7 +2371,7 @@ EAcceptance LLToolDragAndDrop::dad3dWearCategory( EAcceptance LLToolDragAndDrop::dad3dUpdateInventory( LLViewerObject* obj, S32 face, MASK mask, BOOL drop) { - lldebugs << "LLToolDragAndDrop::dadUpdateInventory()" << llendl; + LL_DEBUGS() << "LLToolDragAndDrop::dadUpdateInventory()" << LL_ENDL; // *HACK: In order to resolve SL-22177, we need to block drags // from notecards and objects onto other objects. @@ -2266,10 +2411,10 @@ BOOL LLToolDragAndDrop::dadUpdateInventory(LLViewerObject* obj, BOOL drop) EAcceptance LLToolDragAndDrop::dad3dUpdateInventoryCategory( LLViewerObject* obj, S32 face, MASK mask, BOOL drop) { - lldebugs << "LLToolDragAndDrop::dad3dUpdateInventoryCategory()" << llendl; + LL_DEBUGS() << "LLToolDragAndDrop::dad3dUpdateInventoryCategory()" << LL_ENDL; if (obj == NULL) { - llwarns << "obj is NULL; aborting func with ACCEPT_NO" << llendl; + LL_WARNS() << "obj is NULL; aborting func with ACCEPT_NO" << LL_ENDL; return ACCEPT_NO; } @@ -2299,10 +2444,10 @@ EAcceptance LLToolDragAndDrop::dad3dUpdateInventoryCategory( items, LLInventoryModel::EXCLUDE_TRASH, droppable); - cats.put(cat); + cats.push_back(cat); if(droppable.countNoCopy() > 0) { - llwarns << "*** Need to confirm this step" << llendl; + LL_WARNS() << "*** Need to confirm this step" << LL_ENDL; } LLViewerObject* root_object = obj; if (obj->getParent()) @@ -2325,7 +2470,7 @@ EAcceptance LLToolDragAndDrop::dad3dUpdateInventoryCategory( rv = gInventory.isCategoryComplete(cat->getUUID()) ? ACCEPT_YES_MULTI : ACCEPT_NO; if(rv < ACCEPT_YES_SINGLE) { - lldebugs << "Category " << cat->getUUID() << "is not complete." << llendl; + LL_DEBUGS() << "Category " << cat->getUUID() << "is not complete." << LL_ENDL; break; } } @@ -2347,13 +2492,13 @@ EAcceptance LLToolDragAndDrop::dad3dUpdateInventoryCategory( rv = willObjectAcceptInventory(root_object, item); if (rv < ACCEPT_YES_COPY_SINGLE) { - lldebugs << "Object will not accept " << item->getUUID() << llendl; + LL_DEBUGS() << "Object will not accept " << item->getUUID() << LL_ENDL; break; } } } - // if every item is accepted, go ahead and send it on. + // If every item is accepted, send it on if(drop && (ACCEPT_YES_COPY_SINGLE <= rv)) { uuid_vec_t ids; @@ -2388,7 +2533,7 @@ BOOL LLToolDragAndDrop::dadUpdateInventoryCategory(LLViewerObject* obj, EAcceptance LLToolDragAndDrop::dad3dGiveInventoryObject( LLViewerObject* obj, S32 face, MASK mask, BOOL drop) { - lldebugs << "LLToolDragAndDrop::dad3dGiveInventoryObject()" << llendl; + LL_DEBUGS() << "LLToolDragAndDrop::dad3dGiveInventoryObject()" << LL_ENDL; // item has to be in agent inventory. if(mSource != SOURCE_AGENT) return ACCEPT_NO; @@ -2404,11 +2549,13 @@ EAcceptance LLToolDragAndDrop::dad3dGiveInventoryObject( return ACCEPT_NO; } LLVOAvatarSelf* avatar = gAgentAvatarp; + /* if(avatar && avatar->isWearingAttachment( item->getUUID() ) ) { // You can't give objects that are attached to you return ACCEPT_NO; } + */ if( obj && avatar ) { if(drop) @@ -2426,7 +2573,7 @@ EAcceptance LLToolDragAndDrop::dad3dGiveInventoryObject( EAcceptance LLToolDragAndDrop::dad3dGiveInventory( LLViewerObject* obj, S32 face, MASK mask, BOOL drop) { - lldebugs << "LLToolDragAndDrop::dad3dGiveInventory()" << llendl; + LL_DEBUGS() << "LLToolDragAndDrop::dad3dGiveInventory()" << LL_ENDL; // item has to be in agent inventory. if(mSource != SOURCE_AGENT) return ACCEPT_NO; LLViewerInventoryItem* item; @@ -2449,7 +2596,7 @@ EAcceptance LLToolDragAndDrop::dad3dGiveInventory( EAcceptance LLToolDragAndDrop::dad3dGiveInventoryCategory( LLViewerObject* obj, S32 face, MASK mask, BOOL drop) { - lldebugs << "LLToolDragAndDrop::dad3dGiveInventoryCategory()" << llendl; + LL_DEBUGS() << "LLToolDragAndDrop::dad3dGiveInventoryCategory()" << LL_ENDL; if(drop && obj) { LLViewerInventoryItem* item; @@ -2467,7 +2614,7 @@ EAcceptance LLToolDragAndDrop::dad3dGiveInventoryCategory( EAcceptance LLToolDragAndDrop::dad3dRezFromObjectOnLand( LLViewerObject* obj, S32 face, MASK mask, BOOL drop) { - lldebugs << "LLToolDragAndDrop::dad3dRezFromObjectOnLand()" << llendl; + LL_DEBUGS() << "LLToolDragAndDrop::dad3dRezFromObjectOnLand()" << LL_ENDL; LLViewerInventoryItem* item = NULL; LLViewerInventoryCategory* cat = NULL; locateInventory(item, cat); @@ -2488,7 +2635,7 @@ EAcceptance LLToolDragAndDrop::dad3dRezFromObjectOnLand( EAcceptance LLToolDragAndDrop::dad3dRezFromObjectOnObject( LLViewerObject* obj, S32 face, MASK mask, BOOL drop) { - lldebugs << "LLToolDragAndDrop::dad3dRezFromObjectOnObject()" << llendl; + LL_DEBUGS() << "LLToolDragAndDrop::dad3dRezFromObjectOnObject()" << LL_ENDL; LLViewerInventoryItem* item; LLViewerInventoryCategory* cat; locateInventory(item, cat); @@ -2525,7 +2672,7 @@ EAcceptance LLToolDragAndDrop::dad3dCategoryOnLand( { return ACCEPT_NO; /* - lldebugs << "LLToolDragAndDrop::dad3dCategoryOnLand()" << llendl; + LL_DEBUGS() << "LLToolDragAndDrop::dad3dCategoryOnLand()" << LL_ENDL; LLInventoryItem* item; LLInventoryCategory* cat; locateInventory(item, cat); @@ -2541,7 +2688,7 @@ EAcceptance LLToolDragAndDrop::dad3dCategoryOnLand( items, LLInventoryModel::EXCLUDE_TRASH, droppable); - if(items.count() > 0) + if(items.size() > 0) { rv = ACCEPT_YES_SINGLE; } @@ -2563,19 +2710,19 @@ EAcceptance LLToolDragAndDrop::dad3dAssetOnLand( { return ACCEPT_NO; /* - lldebugs << "LLToolDragAndDrop::dad3dAssetOnLand()" << llendl; + LL_DEBUGS() << "LLToolDragAndDrop::dad3dAssetOnLand()" << LL_ENDL; LLViewerInventoryCategory::cat_array_t cats; LLViewerInventoryItem::item_array_t items; LLViewerInventoryItem::item_array_t copyable_items; locateMultipleInventory(items, cats); - if(!items.count()) return ACCEPT_NO; + if(!items.size()) return ACCEPT_NO; EAcceptance rv = ACCEPT_NO; - for (S32 i = 0; i < items.count(); i++) + for (S32 i = 0; i < items.size(); i++) { LLInventoryItem* item = items[i]; if(item->getPermissions().allowCopyBy(gAgent.getID())) { - copyable_items.put(item); + copyable_items.push_back(item); rv = ACCEPT_YES_SINGLE; } } @@ -2595,7 +2742,13 @@ LLInventoryObject* LLToolDragAndDrop::locateInventory( { item = NULL; cat = NULL; - if(mCargoIDs.empty()) return NULL; + + if (mCargoIDs.empty() + || (mSource == SOURCE_PEOPLE)) ///< There is no inventory item for people drag and drop. + { + return NULL; + } + if((mSource == SOURCE_AGENT) || (mSource == SOURCE_LIBRARY)) { // The object should be in user inventory. @@ -2621,7 +2774,7 @@ LLInventoryObject* LLToolDragAndDrop::locateInventory( } else if(mSource == SOURCE_NOTECARD) { - LLPreviewNotecard* preview = dynamic_cast(LLPreview::find(mSourceID)); + LLPreviewNotecard* preview = static_cast(LLPreview::find(mSourceID)); if(preview) { item = (LLViewerInventoryItem*)preview->getDragItem(); @@ -2636,21 +2789,21 @@ LLInventoryObject* LLToolDragAndDrop::locateInventory( LLInventoryObject* LLToolDragAndDrop::locateMultipleInventory(LLViewerInventoryCategory::cat_array_t& cats, LLViewerInventoryItem::item_array_t& items) { - if(mCargoIDs.count() == 0) return NULL; + if(mCargoIDs.size() == 0) return NULL; if((mSource == SOURCE_AGENT) || (mSource == SOURCE_LIBRARY)) { // The object should be in user inventory. - for (S32 i = 0; i < mCargoIDs.count(); i++) + for (S32 i = 0; i < mCargoIDs.size(); i++) { LLInventoryItem* item = gInventory.getItem(mCargoIDs[i]); if (item) { - items.put(item); + items.push_back(item); } LLInventoryCategory* category = gInventory.getCategory(mCargoIDs[i]); if (category) { - cats.put(category); + cats.push_back(category); } } } @@ -2664,23 +2817,23 @@ LLInventoryObject* LLToolDragAndDrop::locateMultipleInventory(LLViewerInventoryC || (mCargoType == DAD_ROOT_CATEGORY)) { // The object should be in user inventory. - for (S32 i = 0; i < mCargoIDs.count(); i++) + for (S32 i = 0; i < mCargoIDs.size(); i++) { LLInventoryCategory* category = (LLInventoryCategory*)obj->getInventoryObject(mCargoIDs[i]); if (category) { - cats.put(category); + cats.push_back(category); } } } else { - for (S32 i = 0; i < mCargoIDs.count(); i++) + for (S32 i = 0; i < mCargoIDs.size(); i++) { LLInventoryItem* item = (LLInventoryItem*)obj->getInventoryObject(mCargoIDs[i]); if (item) { - items.put(item); + items.push_back(item); } } } @@ -2692,18 +2845,18 @@ LLInventoryObject* LLToolDragAndDrop::locateMultipleInventory(LLViewerInventoryC card = (LLPreviewNotecard*)LLPreview::find(mSourceID); if(card) { - items.put((LLInventoryItem*)card->getDragItem()); + items.push_back((LLInventoryItem*)card->getDragItem()); } } - if(items.count()) return items[0]; - if(cats.count()) return cats[0]; + if(items.size()) return items[0]; + if(cats.size()) return cats[0]; return NULL; } */ // void LLToolDragAndDrop::createContainer(LLViewerInventoryItem::item_array_t &items, const char* preferred_name ) // { -// llwarns << "LLToolDragAndDrop::createContainer()" << llendl; +// LL_WARNS() << "LLToolDragAndDrop::createContainer()" << LL_ENDL; // return; // } diff --git a/indra/newview/lltooldraganddrop.h b/indra/newview/lltooldraganddrop.h index 0e073a5834..4d5cacb31b 100644 --- a/indra/newview/lltooldraganddrop.h +++ b/indra/newview/lltooldraganddrop.h @@ -33,12 +33,11 @@ #ifndef LL_TOOLDRAGANDDROP_H #define LL_TOOLDRAGANDDROP_H +#include "lldictionary.h" #include "lltool.h" #include "llview.h" #include "lluuid.h" -#include "stdenums.h" #include "llassetstorage.h" -#include "lldarray.h" #include "llpermissions.h" #include "llwindow.h" #include "llviewerinventory.h" @@ -51,6 +50,8 @@ class LLPickInfo; class LLToolDragAndDrop : public LLTool, public LLSingleton { public: + typedef boost::signals2::signal enddrag_signal_t; + LLToolDragAndDrop(); // overridden from LLTool @@ -69,7 +70,9 @@ class LLToolDragAndDrop : public LLTool, public LLSingleton SOURCE_AGENT, SOURCE_WORLD, SOURCE_NOTECARD, - SOURCE_LIBRARY + SOURCE_LIBRARY, + SOURCE_VIEWER, + SOURCE_PEOPLE }; void beginDrag(EDragAndDropType type, @@ -87,9 +90,23 @@ class LLToolDragAndDrop : public LLTool, public LLSingleton const LLUUID& getObjectID() const { return mObjectID; } EAcceptance getLastAccept() { return mLastAccept; } + boost::signals2::connection setEndDragCallback( const enddrag_signal_t::slot_type& cb ) { return mEndDragSignal.connect(cb); } + + void setCargoCount(U32 count) { mCargoCount = count; } + void resetCargoCount() { mCargoCount = 0; } + U32 getCargoCount() const { return (mCargoCount > 0) ? mCargoCount : mCargoIDs.size(); } + S32 getCargoIndex() const { return mCurItemIndex; } + uuid_vec_t::size_type getCargoIDsCount() const { return mCargoIDs.size(); } static S32 getOperationId() { return sOperationId; } + // deal with permissions of object, etc. returns TRUE if drop can + // proceed, otherwise FALSE. + static BOOL handleDropTextureProtections(LLViewerObject* hit_obj, + LLInventoryItem* item, + LLToolDragAndDrop::ESource source, + const LLUUID& src_id); + protected: enum EDropTarget { @@ -101,6 +118,7 @@ class LLToolDragAndDrop : public LLTool, public LLSingleton DT_COUNT = 5 }; +protected: // dragOrDrop3dImpl points to a member of LLToolDragAndDrop that // takes parameters (LLViewerObject* obj, S32 face, MASK, BOOL // drop) and returns a BOOL if drop is ok @@ -111,11 +129,14 @@ class LLToolDragAndDrop : public LLTool, public LLSingleton EAcceptance* acceptance); void dragOrDrop3D(S32 x, S32 y, MASK mask, BOOL drop, EAcceptance* acceptance); + static void pickCallback(const LLPickInfo& pick_info); void pick(const LLPickInfo& pick_info); protected: + U32 mCargoCount; + S32 mDragStartX; S32 mDragStartY; @@ -136,6 +157,9 @@ class LLToolDragAndDrop : public LLTool, public LLSingleton BOOL mDrop; S32 mCurItemIndex; std::string mToolTipMsg; + std::string mCustomMsg; + + enddrag_signal_t mEndDragSignal; protected: // 3d drop functions. these call down into the static functions @@ -210,13 +234,6 @@ class LLToolDragAndDrop : public LLTool, public LLSingleton // inventory items to determine if a drop would be ok. static EAcceptance willObjectAcceptInventory(LLViewerObject* obj, LLInventoryItem* item); - // deal with permissions of object, etc. returns TRUE if drop can - // proceed, otherwise FALSE. - static BOOL handleDropTextureProtections(LLViewerObject* hit_obj, - LLInventoryItem* item, - LLToolDragAndDrop::ESource source, - const LLUUID& src_id); - public: // helper functions static BOOL isInventoryDropAcceptable(LLViewerObject* obj, LLInventoryItem* item) { return (ACCEPT_YES_COPY_SINGLE <= willObjectAcceptInventory(obj, item)); } @@ -254,7 +271,8 @@ class LLToolDragAndDrop : public LLTool, public LLSingleton static bool handleGiveDragAndDrop(LLUUID agent, LLUUID session, BOOL drop, EDragAndDropType cargo_type, void* cargo_data, - EAcceptance* accept); + EAcceptance* accept, + const LLSD& dest = LLSD()); // Classes used for determining 3d drag and drop types. private: diff --git a/indra/newview/lltoolface.cpp b/indra/newview/lltoolface.cpp index 4b5f19eba0..721ed2842f 100644 --- a/indra/newview/lltoolface.cpp +++ b/indra/newview/lltoolface.cpp @@ -87,7 +87,7 @@ BOOL LLToolFace::handleDoubleClick(S32 x, S32 y, MASK mask) BOOL LLToolFace::handleMouseDown(S32 x, S32 y, MASK mask) { - gViewerWindow->pickAsync(x, y, mask, pickCallback); + gViewerWindow->pickAsync(x, y, mask, pickCallback, TRUE, TRUE); return TRUE; } diff --git a/indra/newview/lltoolfocus.cpp b/indra/newview/lltoolfocus.cpp index 568d20c231..d9d80fa4d0 100644 --- a/indra/newview/lltoolfocus.cpp +++ b/indra/newview/lltoolfocus.cpp @@ -45,6 +45,7 @@ #include "llagentcamera.h" #include "llbutton.h" #include "llviewercontrol.h" +#include "llviewerkeyboard.h" #include "lldrawable.h" #include "llhoverview.h" #include "llhudmanager.h" @@ -58,6 +59,7 @@ #include "llvoavatarself.h" #include "llmorphview.h" #include "llfloatercustomize.h" +#include "rlvhandler.h" // [RLVa:LF] - camunlock // Globals BOOL gCameraBtnZoom = TRUE; @@ -129,7 +131,9 @@ BOOL LLToolCamera::handleMouseDown(S32 x, S32 y, MASK mask) gViewerWindow->hideCursor(); - gViewerWindow->pickAsync(x, y, mask, pickCallback); + bool pick_rigged = gFloaterTools && gFloaterTools->getVisible(); + + gViewerWindow->pickAsync(x, y, mask, pickCallback, /*BOOL pick_transparent*/ FALSE, pick_rigged, /*BOOL pick_unselectable*/ TRUE); // don't steal focus from UI return FALSE; } @@ -199,6 +203,8 @@ void LLToolCamera::pickCallback(const LLPickInfo& pick_info) else if (pick_info.mKeyMask & MASK_ALT || (LLToolMgr::getInstance()->getCurrentTool()->getName() == "Camera")) { + if (gRlvHandler.hasBehaviour(RLV_BHVR_CAMUNLOCK)) return; // [RLVa:LF] - camunlock + LLViewerObject* hit_obj = pick_info.getObject(); if (hit_obj) { @@ -315,6 +321,11 @@ BOOL LLToolCamera::handleMouseUp(S32 x, S32 y, MASK mask) BOOL LLToolCamera::handleHover(S32 x, S32 y, MASK mask) { + if (gViewerWindow->getRightMouseDown()) + { + agent_push_forward(KEYSTATE_LEVEL); + } + S32 dx = gViewerWindow->getCurrentMouseDX(); S32 dy = gViewerWindow->getCurrentMouseDY(); @@ -338,7 +349,7 @@ BOOL LLToolCamera::handleHover(S32 x, S32 y, MASK mask) { if (!mValidClickPoint) { - lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolFocus [invalid point]" << llendl; + LL_DEBUGS("UserInput") << "hover handled by LLToolFocus [invalid point]" << LL_ENDL; gViewerWindow->setCursor(UI_CURSOR_NO); gViewerWindow->showCursor(); return TRUE; @@ -365,7 +376,7 @@ BOOL LLToolCamera::handleHover(S32 x, S32 y, MASK mask) gViewerWindow->moveCursorToCenter(); } - lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolFocus [active]" << llendl; + LL_DEBUGS("UserInput") << "hover handled by LLToolFocus [active]" << LL_ENDL; } else if ( gCameraBtnPan || mask == MASK_PAN || @@ -393,7 +404,7 @@ BOOL LLToolCamera::handleHover(S32 x, S32 y, MASK mask) gViewerWindow->moveCursorToCenter(); } - lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolPan" << llendl; + LL_DEBUGS("UserInput") << "hover handled by LLToolPan" << LL_ENDL; } else if (gCameraBtnZoom) { @@ -425,7 +436,7 @@ BOOL LLToolCamera::handleHover(S32 x, S32 y, MASK mask) gViewerWindow->moveCursorToCenter(); } - lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolZoom" << llendl; + LL_DEBUGS("UserInput") << "hover handled by LLToolZoom" << LL_ENDL; } } @@ -449,8 +460,34 @@ BOOL LLToolCamera::handleHover(S32 x, S32 y, MASK mask) return TRUE; } +BOOL LLToolCamera::handleRightMouseDown(S32 x, S32 y, MASK mask) +{ + if(mMouseSteering) + { + agent_push_forward(KEYSTATE_DOWN); + return TRUE; + } + else + { + return FALSE; + } +} + +BOOL LLToolCamera::handleRightMouseUp(S32 x, S32 y, MASK mask) +{ + if (mMouseSteering) + { + agent_push_forward(KEYSTATE_UP); + return TRUE; + } + else + { + return FALSE; + } +} void LLToolCamera::onMouseCaptureLost() { releaseMouse(); + if (gViewerWindow->getRightMouseDown()) agent_push_forward(KEYSTATE_UP); } diff --git a/indra/newview/lltoolfocus.h b/indra/newview/lltoolfocus.h index 023cc26389..96a58bb4e9 100644 --- a/indra/newview/lltoolfocus.h +++ b/indra/newview/lltoolfocus.h @@ -47,6 +47,8 @@ class LLToolCamera virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); virtual BOOL handleHover(S32 x, S32 y, MASK mask); + virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); + virtual BOOL handleRightMouseUp(S32 x, S32 y, MASK mask); virtual void onMouseCaptureLost(); diff --git a/indra/newview/lltoolgrab.cpp b/indra/newview/lltoolgrab.cpp index 22684899f7..267b34761a 100644 --- a/indra/newview/lltoolgrab.cpp +++ b/indra/newview/lltoolgrab.cpp @@ -122,7 +122,7 @@ BOOL LLToolGrab::handleDoubleClick(S32 x, S32 y, MASK mask) { if (gDebugClicks) { - llinfos << "LLToolGrab handleDoubleClick (becoming mouseDown)" << llendl; + LL_INFOS() << "LLToolGrab handleDoubleClick (becoming mouseDown)" << LL_ENDL; } return FALSE; @@ -132,7 +132,7 @@ BOOL LLToolGrab::handleMouseDown(S32 x, S32 y, MASK mask) { if (gDebugClicks) { - llinfos << "LLToolGrab handleMouseDown" << llendl; + LL_INFOS() << "LLToolGrab handleMouseDown" << LL_ENDL; } // call the base class to propogate info to sim @@ -141,7 +141,7 @@ BOOL LLToolGrab::handleMouseDown(S32 x, S32 y, MASK mask) if (!gAgent.leftButtonGrabbed()) { // can grab transparent objects (how touch event propagates, scripters rely on this) - gViewerWindow->pickAsync(x, y, mask, pickCallback, TRUE, TRUE); + gViewerWindow->pickAsync(x, y, mask, pickCallback, TRUE, FALSE, FALSE, TRUE); } return TRUE; } @@ -187,12 +187,12 @@ BOOL LLToolGrab::handleObjectHit(const LLPickInfo& info) if (gDebugClicks) { - llinfos << "LLToolGrab handleObjectHit " << info.mMousePt.mX << "," << info.mMousePt.mY << llendl; + LL_INFOS() << "LLToolGrab handleObjectHit " << info.mMousePt.mX << "," << info.mMousePt.mY << LL_ENDL; } if (NULL == objectp) // unexpected { - llwarns << "objectp was NULL; returning FALSE" << llendl; + LL_WARNS() << "objectp was NULL; returning FALSE" << LL_ENDL; return FALSE; } @@ -403,7 +403,7 @@ void LLToolGrab::startGrab() mDragStartPointGlobal = grab_start_global; mDragStartFromCamera = grab_start_global - gAgentCamera.getCameraPositionGlobal(); - send_ObjectGrab_message(objectp, mGrabPick, grab_offset); + send_ObjectGrab_message(objectp, true, &mGrabPick, grab_offset); mGrabOffsetFromCenterInitial = grab_offset; mGrabHiddenOffsetFromCamera = mDragStartFromCamera; @@ -735,7 +735,7 @@ void LLToolGrab::handleHoverActive(S32 x, S32 y, MASK mask) gViewerWindow->hideCursor(); gViewerWindow->setCursor(UI_CURSOR_ARROW); - lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolGrab (active) [cursor hidden]" << llendl; + LL_DEBUGS("UserInput") << "hover handled by LLToolGrab (active) [cursor hidden]" << LL_ENDL; } @@ -921,7 +921,7 @@ void LLToolGrab::handleHoverInactive(S32 x, S32 y, MASK mask) } // JC - TODO - change cursor based on gGrabBtnVertical, gGrabBtnSpin - lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolGrab (inactive-not over editable object)" << llendl; + LL_DEBUGS("UserInput") << "hover handled by LLToolGrab (inactive-not over editable object)" << LL_ENDL; gViewerWindow->setCursor(UI_CURSOR_TOOLGRAB); } @@ -931,7 +931,7 @@ void LLToolGrab::handleHoverFailed(S32 x, S32 y, MASK mask) if( GRAB_NOOBJECT == mMode ) { gViewerWindow->setCursor(UI_CURSOR_NO); - lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolGrab (not on object)" << llendl; + LL_DEBUGS("UserInput") << "hover handled by LLToolGrab (not on object)" << LL_ENDL; } else { @@ -944,13 +944,13 @@ void LLToolGrab::handleHoverFailed(S32 x, S32 y, MASK mask) { case GRAB_LOCKED: gViewerWindow->setCursor(UI_CURSOR_GRABLOCKED); - lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolGrab (grab failed, no move permission)" << llendl; + LL_DEBUGS("UserInput") << "hover handled by LLToolGrab (grab failed, no move permission)" << LL_ENDL; break; // Non physical now handled by handleHoverActive - CRO // case GRAB_NONPHYSICAL: // gViewerWindow->setCursor(UI_CURSOR_ARROW); -// lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolGrab (grab failed, nonphysical)" << llendl; +// LL_DEBUGS("UserInput") << "hover handled by LLToolGrab (grab failed, nonphysical)" << LL_ENDL; // break; default: llassert(0); @@ -959,7 +959,7 @@ void LLToolGrab::handleHoverFailed(S32 x, S32 y, MASK mask) else { gViewerWindow->setCursor(UI_CURSOR_ARROW); - lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolGrab (grab failed but within slop)" << llendl; + LL_DEBUGS("UserInput") << "hover handled by LLToolGrab (grab failed but within slop)" << LL_ENDL; } } } @@ -1079,7 +1079,7 @@ void LLToolGrab::stopGrab() case GRAB_ACTIVE_CENTER: case GRAB_NONPHYSICAL: case GRAB_LOCKED: - send_ObjectDeGrab_message(objectp, pick); + send_ObjectGrab_message(objectp, false, &pick); mVerticalDragging = FALSE; break; @@ -1133,64 +1133,45 @@ LLVector3d LLToolGrab::getGrabPointGlobal() } -void send_ObjectGrab_message(LLViewerObject* object, const LLPickInfo & pick, const LLVector3 &grab_offset) +void send_ObjectGrab_message(LLViewerObject* object, bool grab, const LLPickInfo* const pick, const LLVector3 &grab_offset) { if (!object) return; LLMessageSystem *msg = gMessageSystem; - msg->newMessageFast(_PREHASH_ObjectGrab); + msg->newMessageFast(grab ? _PREHASH_ObjectGrab : _PREHASH_ObjectDeGrab); msg->nextBlockFast( _PREHASH_AgentData); msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); msg->nextBlockFast( _PREHASH_ObjectData); msg->addU32Fast( _PREHASH_LocalID, object->mLocalID); - msg->addVector3Fast(_PREHASH_GrabOffset, grab_offset); - msg->nextBlock("SurfaceInfo"); - msg->addVector3("UVCoord", LLVector3(pick.mUVCoords)); - msg->addVector3("STCoord", LLVector3(pick.mSTCoords)); - msg->addS32Fast(_PREHASH_FaceIndex, pick.mObjectFace); - msg->addVector3("Position", pick.mIntersection); - msg->addVector3("Normal", pick.mNormal); - msg->addVector3("Binormal", pick.mBinormal); + if (grab) msg->addVector3Fast(_PREHASH_GrabOffset, grab_offset); + if (pick) + { + msg->nextBlock("SurfaceInfo"); + msg->addVector3("UVCoord", LLVector3(pick->mUVCoords)); + msg->addVector3("STCoord", LLVector3(pick->mSTCoords)); + msg->addS32Fast(_PREHASH_FaceIndex, pick->mObjectFace); + msg->addVector3("Position", pick->mIntersection); + msg->addVector3("Normal", pick->mNormal); + msg->addVector3("Binormal", pick->mBinormal); + } msg->sendMessage( object->getRegion()->getHost()); /* Diagnostic code - llinfos << "mUVCoords: " << pick.mUVCoords - << ", mSTCoords: " << pick.mSTCoords - << ", mObjectFace: " << pick.mObjectFace - << ", mIntersection: " << pick.mIntersection - << ", mNormal: " << pick.mNormal - << ", mBinormal: " << pick.mBinormal - << llendl; - - llinfos << "Avatar pos: " << gAgent.getPositionAgent() << llendl; - llinfos << "Object pos: " << object->getPosition() << llendl; - */ -} - - -void send_ObjectDeGrab_message(LLViewerObject* object, const LLPickInfo & pick) -{ - if (!object) return; - - LLMessageSystem *msg = gMessageSystem; + if (pick) + { + LL_INFOS() << "mUVCoords: " << pick->mUVCoords + << ", mSTCoords: " << pick->mSTCoords + << ", mObjectFace: " << pick->mObjectFace + << ", mIntersection: " << pick->mIntersection + << ", mNormal: " << pick->mNormal + << ", mBinormal: " << pick->mBinormal + << LL_ENDL; + } - msg->newMessageFast(_PREHASH_ObjectDeGrab); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_ObjectData); - msg->addU32Fast(_PREHASH_LocalID, object->mLocalID); - msg->nextBlock("SurfaceInfo"); - msg->addVector3("UVCoord", LLVector3(pick.mUVCoords)); - msg->addVector3("STCoord", LLVector3(pick.mSTCoords)); - msg->addS32Fast(_PREHASH_FaceIndex, pick.mObjectFace); - msg->addVector3("Position", pick.mIntersection); - msg->addVector3("Normal", pick.mNormal); - msg->addVector3("Binormal", pick.mBinormal); - msg->sendMessage(object->getRegion()->getHost()); + LL_INFOS() << "Avatar pos: " << gAgent.getPositionAgent() << LL_ENDL; + LL_INFOS() << "Object pos: " << object->getPosition() << LL_ENDL; + */ } - - diff --git a/indra/newview/lltoolgrab.h b/indra/newview/lltoolgrab.h index d5c99a43fc..98f5fdd913 100644 --- a/indra/newview/lltoolgrab.h +++ b/indra/newview/lltoolgrab.h @@ -41,9 +41,7 @@ class LLPickInfo; // Message utilities -void send_ObjectGrab_message(LLViewerObject* object, const LLPickInfo & pick, const LLVector3 &grab_offset); -void send_ObjectDeGrab_message(LLViewerObject* object, const LLPickInfo & pick); - +void send_ObjectGrab_message(LLViewerObject* object, bool grab, const LLPickInfo* const pick = nullptr, const LLVector3& grab_offset = LLVector3::zero); class LLToolGrab : public LLTool, public LLSingleton diff --git a/indra/newview/lltoolgun.cpp b/indra/newview/lltoolgun.cpp index 1eedb7b22b..f0f3ebb24e 100644 --- a/indra/newview/lltoolgun.cpp +++ b/indra/newview/lltoolgun.cpp @@ -48,22 +48,35 @@ #include "llhudmanager.h" #include "lltoolmgr.h" #include "lltoolgrab.h" - +#include "lluiimage.h" // Linden library includes #include "llwindow.h" // setMouseClipping() +bool getCustomColorRLV(const LLUUID& id, LLColor4& color, LLViewerRegion* parent_estate, bool name_restricted); +#include "llavatarnamecache.h" +#include "llworld.h" +#include "rlvhandler.h" + LLToolGun::LLToolGun( LLToolComposite* composite ) : LLTool( std::string("gun"), composite ), mIsSelected(FALSE) { + mCrosshairp = LLUI::getUIImage("UIImgCrosshairsUUID"); // - UI Caching } void LLToolGun::handleSelect() { - gViewerWindow->hideCursor(); - gViewerWindow->moveCursorToCenter(); - gViewerWindow->getWindow()->setMouseClipping(TRUE); - mIsSelected = TRUE; +// [RLVa:KB] - Checked: 2014-02-24 (RLVa-1.4.10) + if (gFocusMgr.getAppHasFocus()) + { +// [/RLVa:KB] + gViewerWindow->hideCursor(); + gViewerWindow->moveCursorToCenter(); + gViewerWindow->getWindow()->setMouseClipping(TRUE); + mIsSelected = TRUE; +// [RLVa:KB] - Checked: 2014-02-24 (RLVa-1.4.10) + } +// [/RLVa:KB] } void LLToolGun::handleDeselect() @@ -88,8 +101,8 @@ BOOL LLToolGun::handleHover(S32 x, S32 y, MASK mask) { const F32 NOMINAL_MOUSE_SENSITIVITY = 0.0025f; - F32 mouse_sensitivity = gSavedSettings.getF32("MouseSensitivity"); - mouse_sensitivity = clamp_rescale(mouse_sensitivity, 0.f, 15.f, 0.5f, 2.75f) * NOMINAL_MOUSE_SENSITIVITY; + static LLCachedControl mouse_sensitivity_setting(gSavedSettings, "MouseSensitivity"); + F32 mouse_sensitivity = clamp_rescale(mouse_sensitivity_setting, 0.f, 15.f, 0.5f, 2.75f) * NOMINAL_MOUSE_SENSITIVITY; // ...move the view with the mouse @@ -100,18 +113,21 @@ BOOL LLToolGun::handleHover(S32 x, S32 y, MASK mask) if (dx != 0 || dy != 0) { // ...actually moved off center - if (gSavedSettings.getBOOL("InvertMouse")) + const F32 fov = LLViewerCamera::getInstance()->getView() / DEFAULT_FIELD_OF_VIEW; + static LLCachedControl invert_mouse(gSavedSettings, "InvertMouse"); + if (invert_mouse) { - gAgent.pitch(mouse_sensitivity * -dy); + gAgent.pitch(mouse_sensitivity * fov * -dy); } else { - gAgent.pitch(mouse_sensitivity * dy); + gAgent.pitch(mouse_sensitivity * fov * dy); } LLVector3 skyward = gAgent.getReferenceUpVector(); - gAgent.rotate(mouse_sensitivity * dx, skyward.mV[VX], skyward.mV[VY], skyward.mV[VZ]); + gAgent.rotate(mouse_sensitivity * fov * dx, skyward.mV[VX], skyward.mV[VY], skyward.mV[VZ]); - if (gSavedSettings.getBOOL("MouseSun")) + static LLCachedControl mouse_sun(gSavedSettings, "MouseSun"); + if (mouse_sun) { gSky.setSunDirection(LLViewerCamera::getInstance()->getAtAxis(), LLVector3(0.f, 0.f, 0.f)); gSky.setOverrideSun(TRUE); @@ -122,11 +138,11 @@ BOOL LLToolGun::handleHover(S32 x, S32 y, MASK mask) gViewerWindow->hideCursor(); } - lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolGun (mouselook)" << llendl; + LL_DEBUGS("UserInput") << "hover handled by LLToolGun (mouselook)" << LL_ENDL; } else { - lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolGun (not mouselook)" << llendl; + LL_DEBUGS("UserInput") << "hover handled by LLToolGun (not mouselook)" << LL_ENDL; } // HACK to avoid assert: error checking system makes sure that the cursor is set during every handleHover. This is actually a no-op since the cursor is hidden. @@ -137,11 +153,60 @@ BOOL LLToolGun::handleHover(S32 x, S32 y, MASK mask) void LLToolGun::draw() { - if( gSavedSettings.getBOOL("ShowCrosshairs") ) + static LLCachedControl show_crosshairs(gSavedSettings, "ShowCrosshairs"); + static LLCachedControl show_iff(gSavedSettings, "AlchemyMouselookIFF", true); + static LLCachedControl iff_range(gSavedSettings, "AlchemyMouselookIFFRange", 380.f); + if (show_crosshairs) { - LLUIImagePtr crosshair = LLUI::getUIImage("UIImgCrosshairsUUID"); - crosshair->draw( - ( gViewerWindow->getWorldViewRectScaled().getWidth() - crosshair->getWidth() ) / 2, - ( gViewerWindow->getWorldViewRectScaled().getHeight() - crosshair->getHeight() ) / 2); + const S32 windowWidth = gViewerWindow->getWorldViewRectScaled().getWidth(); + const S32 windowHeight = gViewerWindow->getWorldViewRectScaled().getHeight(); + static const LLCachedControl color("LiruCrosshairColor"); + LLColor4 targetColor = color; + targetColor.mV[VALPHA] = 0.5f; + if (show_iff && !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWMINIMAP)) + { + LLVector3d myPosition = gAgentCamera.getCameraPositionGlobal(); + LLQuaternion myRotation = LLViewerCamera::getInstance()->getQuaternion(); + myRotation.set(-myRotation.mQ[VX], -myRotation.mQ[VY], -myRotation.mQ[VZ], myRotation.mQ[VW]); + + bool no_names(gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS)); + bool name_restricted = no_names || gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES); + + LLWorld::pos_map_t positions; + LLWorld& world(LLWorld::instance()); + world.getAvatars(&positions, gAgent.getPositionGlobal(), name_restricted && gRlvHandler.hasBehaviour(RLV_BHVR_CAMAVDIST) ? llmin(iff_range(), gRlvHandler.camPole(RLV_BHVR_CAMAVDIST)) : iff_range); + for (LLWorld::pos_map_t::const_iterator iter = positions.cbegin(), iter_end = positions.cend(); iter != iter_end; ++iter) + { + const LLUUID& id = iter->first; + const LLVector3d& targetPosition = iter->second; + if (id == gAgentID || targetPosition.isNull()) + { + continue; + } + + LLVector3d magicVector = (targetPosition - myPosition) * myRotation; + magicVector.setVec(-magicVector.mdV[VY], magicVector.mdV[VZ], magicVector.mdV[VX]); + if (magicVector.mdV[VX] > -0.75 && magicVector.mdV[VX] < 0.75 && magicVector.mdV[VZ] > 0.0 && magicVector.mdV[VY] > -1.5 && magicVector.mdV[VY] < 1.5) // Do not fuck with these, cheater. :( + { + LLAvatarName avatarName; + if (!no_names) + LLAvatarNameCache::get(id, &avatarName); + getCustomColorRLV(id, targetColor, world.getRegionFromPosGlobal(targetPosition), name_restricted); + const std::string name(no_names ? LLStringUtil::null : name_restricted ? RlvStrings::getAnonym(avatarName.getNSName()) : avatarName.getNSName()); + targetColor.mV[VALPHA] = 0.5f; + LLFontGL::getFontSansSerifBold()->renderUTF8( + llformat("%s : %.2fm", name.c_str(), (targetPosition - myPosition).magVec()), + 0, (windowWidth / 2.f), (windowHeight / 2.f) - 25.f, targetColor, + LLFontGL::HCENTER, LLFontGL::TOP, LLFontGL::BOLD, LLFontGL::NO_SHADOW + ); + + break; + } + } + } + + mCrosshairp->draw( + (windowWidth - mCrosshairp->getWidth() ) / 2, + (windowHeight - mCrosshairp->getHeight() ) / 2, targetColor); } } diff --git a/indra/newview/lltoolgun.h b/indra/newview/lltoolgun.h index 4644e686b7..e15a88f477 100644 --- a/indra/newview/lltoolgun.h +++ b/indra/newview/lltoolgun.h @@ -54,6 +54,9 @@ class LLToolGun : public LLTool virtual BOOL clipMouseWhenDown() { return FALSE; } private: BOOL mIsSelected; + + // - UI Caching + LLUIImagePtr mCrosshairp; }; #endif diff --git a/indra/newview/lltoolmgr.cpp b/indra/newview/lltoolmgr.cpp index 716edd7dde..3b927ff710 100644 --- a/indra/newview/lltoolmgr.cpp +++ b/indra/newview/lltoolmgr.cpp @@ -36,6 +36,7 @@ #include "llfirstuse.h" // tools and manipulators +#include "llfloaterinspect.h" #include "lltool.h" #include "llmanipscale.h" #include "llselectmgr.h" @@ -55,8 +56,6 @@ #include "llagent.h" #include "llagentcamera.h" #include "llviewercontrol.h" -#include "llmemberlistener.h" -#include "llevent.h" #include "llviewerjoystick.h" #include "llviewermenu.h" #include "llviewerparcelmgr.h" @@ -77,24 +76,6 @@ LLToolset* gFaceEditToolset = NULL; ///////////////////////////////////////////////////// // LLToolMgr -class LLViewBuildMode : public LLMemberListener -{ - bool handleEvent(LLPointer event, const LLSD& userdata) - { - LLToolMgr::getInstance()->toggleBuildMode(); - return true; - } -}; -class LLViewCheckBuildMode : public LLMemberListener -{ - bool handleEvent(LLPointer event, const LLSD& userdata) - { - bool new_value = LLToolMgr::getInstance()->inEdit(); - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); - return true; - } -}; - LLToolMgr::LLToolMgr() : mBaseTool(NULL), @@ -112,14 +93,8 @@ LLToolMgr::LLToolMgr() // gLandToolset = new LLToolset("Land"); gMouselookToolset = new LLToolset("MouseLook"); gFaceEditToolset = new LLToolset("FaceEdit"); -} - -void LLToolMgr::initMenu(std::vector > >& menu_list) -{ - menu_list.push_back(new LLViewBuildMode()); - menu_list.back()->registerListener(gMenuHolder, "View.BuildMode"); - menu_list.push_back(new LLViewCheckBuildMode()); - menu_list.back()->registerListener(gMenuHolder, "View.CheckBuildMode"); + gMouselookToolset->setShowFloaterTools(false); + gFaceEditToolset->setShowFloaterTools(false); } void LLToolMgr::initTools() @@ -141,8 +116,6 @@ void LLToolMgr::initTools() gBasicToolset->addTool( LLToolCompInspect::getInstance() ); gFaceEditToolset->addTool( LLToolCamera::getInstance() ); - // In case focus was lost before we got here - clearSavedTool(); // On startup, use "select" tool setCurrentToolset(gBasicToolset); @@ -184,7 +157,7 @@ void LLToolMgr::setCurrentToolset(LLToolset* current) { mSelectedTool->handleDeselect(); } - lldebugs << "Current tool set: " << current->getName() << llendl; + LL_DEBUGS() << "Current tool set: " << current->getName() << LL_ENDL; mCurrentToolset = current; // select first tool of new toolset only if toolset changed mCurrentToolset->selectFirstTool(); @@ -201,7 +174,7 @@ LLToolset* LLToolMgr::getCurrentToolset() void LLToolMgr::setCurrentTool( LLTool* tool ) { if(tool && mBaseTool!=tool) - lldebugs << "Current Tool: " << tool->getName() << llendl; + LL_DEBUGS() << "Current Tool: " << tool->getName() << LL_ENDL; if (mTransientTool) { mTransientTool = NULL; @@ -251,7 +224,19 @@ LLTool* LLToolMgr::getCurrentTool() } if (cur_tool) { - cur_tool->handleSelect(); + if (LLToolCompInspect::getInstance()->isToolCameraActive() + && prev_tool == LLToolCamera::getInstance() + && cur_tool == LLToolPie::getInstance()) + { + if (LLFloaterInspect::instanceVisible()) + { + setTransientTool(LLToolCompInspect::getInstance()); + } + } + else + { + cur_tool->handleSelect(); + } } } @@ -283,24 +268,7 @@ bool LLToolMgr::canEdit() void LLToolMgr::toggleBuildMode() { - if (inBuildMode()) - { - if (gSavedSettings.getBOOL("EditCameraMovement")) - { - // just reset the view, will pull us out of edit mode - handle_reset_view(); - } - else - { - // manually disable edit mode, but do not affect the camera - gAgentCamera.resetView(false); - gFloaterTools->close(); - gViewerWindow->showCursor(); - } - // avoid spurious avatar movements pulling out of edit mode - LLViewerJoystick::getInstance()->setNeedsReset(); - } - else + if (!inBuildMode()) { ECameraMode camMode = gAgentCamera.getCameraMode(); if (CAMERA_MODE_MOUSELOOK == camMode || CAMERA_MODE_CUSTOMIZE_AVATAR == camMode) @@ -349,7 +317,30 @@ void LLToolMgr::toggleBuildMode() // avoid spurious avatar movements LLViewerJoystick::getInstance()->setNeedsReset(); + if (gFocusMgr.getKeyboardFocus()) gFloaterTools->setFocus(true); // Focus isn't on the world, give it to the build tools. + } + else if (gFloaterTools->getVisible() && !gFloaterTools->hasFocus() && gFocusMgr.getKeyboardFocus()) // Build tools is open, but not the focused floater, give it focus. + { + gFloaterTools->setFocus(true); + } + else + { + if (gSavedSettings.getBOOL("EditCameraMovement")) + { + // just reset the view, will pull us out of edit mode + handle_reset_view(); + } + else + { + // manually disable edit mode, but do not affect the camera + gAgentCamera.resetView(false); + gFloaterTools->close(); + gViewerWindow->showCursor(); + } + // avoid spurious avatar movements pulling out of edit mode + LLViewerJoystick::getInstance()->setNeedsReset(); } + } bool LLToolMgr::inBuildMode() @@ -392,7 +383,7 @@ void LLToolMgr::clearTransientTool() mTransientTool = NULL; if (!mBaseTool) { - llwarns << "mBaseTool is NULL" << llendl; + LL_WARNS() << "mBaseTool is NULL" << LL_ENDL; } } updateToolStatus(); diff --git a/indra/newview/lltoolmgr.h b/indra/newview/lltoolmgr.h index 31a481b17c..c2a18ccb9a 100644 --- a/indra/newview/lltoolmgr.h +++ b/indra/newview/lltoolmgr.h @@ -35,11 +35,8 @@ #include "llkeyboard.h" -#include "llmemberlistener.h" - class LLTool; class LLToolset; -class LLView; // Key bindings for common operations const MASK MASK_VERTICAL = MASK_CONTROL; @@ -55,8 +52,6 @@ class LLToolMgr : public LLSingleton LLToolMgr(); ~LLToolMgr(); - void initMenu(std::vector > >& menu_list); - // Must be called after gSavedSettings set up. void initTools(); @@ -100,7 +95,7 @@ class LLToolMgr : public LLSingleton class LLToolset { public: - LLToolset(const char *name) : mSelectedTool(NULL), mName(name) {} + LLToolset(const char* name) : mSelectedTool(NULL), mName(name), mIsShowFloaterTools(true) {} LLTool* getSelectedTool() { return mSelectedTool; } @@ -116,12 +111,16 @@ class LLToolset BOOL isToolSelected( S32 index ); + void setShowFloaterTools(bool pShowFloaterTools) {mIsShowFloaterTools = pShowFloaterTools;}; + bool isShowFloaterTools() const {return mIsShowFloaterTools;}; const char* getName() const {return mName;} + protected: const char* mName; LLTool* mSelectedTool; typedef std::vector tool_list_t; tool_list_t mToolList; + bool mIsShowFloaterTools; }; // Globals diff --git a/indra/newview/lltoolmorph.cpp b/indra/newview/lltoolmorph.cpp index 9acc349713..e2f88b107d 100644 --- a/indra/newview/lltoolmorph.cpp +++ b/indra/newview/lltoolmorph.cpp @@ -276,16 +276,16 @@ void LLVisualParamHint::draw() gGL.color4f(1.f, 1.f, 1.f, 1.f); LLGLSUIDefault gls_ui; - gGL.begin(LLRender::QUADS); + gGL.begin(LLRender::TRIANGLE_STRIP); { gGL.texCoord2i(0, 1); gGL.vertex2i(0, mFullHeight); gGL.texCoord2i(0, 0); gGL.vertex2i(0, 0); - gGL.texCoord2i(1, 0); - gGL.vertex2i(mFullWidth, 0); gGL.texCoord2i(1, 1); gGL.vertex2i(mFullWidth, mFullHeight); + gGL.texCoord2i(1, 0); + gGL.vertex2i(mFullWidth, 0); } gGL.end(); diff --git a/indra/newview/lltoolmorph.h b/indra/newview/lltoolmorph.h index 950a3ab11a..a3f557a465 100644 --- a/indra/newview/lltoolmorph.h +++ b/indra/newview/lltoolmorph.h @@ -65,6 +65,16 @@ class LLVisualParamHint : public LLViewerDynamicTexture LLWearable *wearable, F32 param_weight); + void* operator new(size_t size) + { + return ll_aligned_malloc_16(size); + } + + void operator delete(void* ptr) + { + ll_aligned_free_16(ptr); + } + /*virtual*/ S8 getType() const ; BOOL needsRender(); @@ -110,6 +120,17 @@ class LLVisualParamReset : public LLViewerDynamicTexture /*virtual */ ~LLVisualParamReset(){} public: LLVisualParamReset(); + + void* operator new(size_t size) + { + return ll_aligned_malloc_16(size); + } + + void operator delete(void* ptr) + { + ll_aligned_free_16(ptr); + } + /*virtual */ BOOL render(); /*virtual*/ S8 getType() const ; diff --git a/indra/newview/lltoolobjpicker.cpp b/indra/newview/lltoolobjpicker.cpp index db150bbedf..1ef7c11988 100644 --- a/indra/newview/lltoolobjpicker.cpp +++ b/indra/newview/lltoolobjpicker.cpp @@ -82,7 +82,7 @@ BOOL LLToolObjPicker::handleMouseDown(S32 x, S32 y, MASK mask) } else { - llwarns << "PickerTool doesn't have mouse capture on mouseDown" << llendl; + LL_WARNS() << "PickerTool doesn't have mouse capture on mouseDown" << LL_ENDL; } } @@ -115,7 +115,7 @@ BOOL LLToolObjPicker::handleMouseUp(S32 x, S32 y, MASK mask) } else { - llwarns << "PickerTool doesn't have mouse capture on mouseUp" << llendl; + LL_WARNS() << "PickerTool doesn't have mouse capture on mouseUp" << LL_ENDL; } return handled; } diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp index e3dce440d0..0f24ca9435 100644 --- a/indra/newview/lltoolpie.cpp +++ b/indra/newview/lltoolpie.cpp @@ -107,9 +107,11 @@ BOOL LLToolPie::handleMouseDown(S32 x, S32 y, MASK mask) mMouseOutsideSlop = FALSE; mMouseDownX = x; mMouseDownY = y; - - //left mouse down always picks transparent - mPick = gViewerWindow->pickImmediate(x, y, TRUE); + //LLTimer pick_timer; + BOOL pick_rigged = true; //gSavedSettings.getBOOL("AnimatedObjectsAllowLeftClick"); + //left mouse down always picks transparent (but see handleMouseUp) + mPick = gViewerWindow->pickImmediate(x, y, TRUE, pick_rigged); + //LL_INFOS() << "pick_rigged is " << (S32) pick_rigged << " pick time elapsed " << pick_timer.getElapsedTimeF32() << LL_ENDL; mPick.mKeyMask = mask; mMouseButtonDown = true; @@ -124,13 +126,17 @@ BOOL LLToolPie::handleMouseDown(S32 x, S32 y, MASK mask) BOOL LLToolPie::handleRightMouseDown(S32 x, S32 y, MASK mask) { // don't pick transparent so users can't "pay" transparent objects - mPick = gViewerWindow->pickImmediate(x, y, FALSE); + mPick = gViewerWindow->pickImmediate(x, y, + /*BOOL pick_transparent*/ FALSE, + /*BOOL pick_rigged*/ mask != MASK_SHIFT, + /*BOOL pick_particle*/ TRUE); mPick.mKeyMask = mask; // claim not handled so UI focus stays same - - handleRightClickPick(); - + if (gAgentCamera.getCameraMode() != CAMERA_MODE_MOUSELOOK || gSavedSettings.getBOOL("LiruMouselookMenu")) + { + handleRightClickPick(); + } return FALSE; } @@ -375,7 +381,7 @@ BOOL LLToolPie::handleLeftClickPick() } object = (LLViewerObject*)object->getParent(); } - if (object && object == gAgentAvatarp && !gSavedSettings.getBOOL("ClickToWalk")) + if (object && object == gAgentAvatarp /*&& gSavedSettings.getBOOL("ClickToWalk")*/) { // we left clicked on avatar, switch to focus mode mMouseButtonDown = false; @@ -407,7 +413,7 @@ BOOL LLToolPie::handleLeftClickPick() LLToolSelect::handleObjectSelection(mPick, FALSE, TRUE); // Spawn pie menu - LLTool::handleRightMouseDown(x, y, mask); + handleRightMouseDown(x, y, mask); return TRUE; } @@ -472,7 +478,11 @@ ECursorType LLToolPie::cursorFromObject(LLViewerObject* object) case CLICK_ACTION_BUY: if ( mClickActionBuyEnabled ) { - cursor = UI_CURSOR_TOOLBUY; + LLSelectNode* node = LLSelectMgr::getInstance()->getHoverNode(); + if (!node || node->mSaleInfo.isForSale()) + { + cursor = UI_CURSOR_TOOLBUY; + } } break; case CLICK_ACTION_OPEN: @@ -523,7 +533,7 @@ void LLToolPie::walkToClickedLocation() mAutoPilotDestination->setDuration(3.f); */ - handle_go_to(); + handle_go_to(mPick.mPosGlobal); } // When we get object properties after left-clicking on an object @@ -559,7 +569,7 @@ void LLToolPie::selectionPropertiesReceived() case CLICK_ACTION_PAY: if ( LLToolPie::getInstance()->mClickActionPayEnabled ) { - handle_give_money_dialog(); + handle_give_money_dialog(selected_object); } break; case CLICK_ACTION_OPEN: @@ -575,9 +585,11 @@ void LLToolPie::selectionPropertiesReceived() BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask) { - mHoverPick = gViewerWindow->pickImmediate(x, y, FALSE); + BOOL pick_rigged = false; + mHoverPick = gViewerWindow->pickImmediate(x, y, FALSE, pick_rigged); LLViewerObject *parent = NULL; LLViewerObject *object = mHoverPick.getObject(); + //LLSelectMgr::getInstance()->setHoverObject(object, mHoverPick.mObjectFace); // Singu TODO: remove llhoverview.cpp // [RLVa:KB] - Checked: 2010-03-11 (RLVa-1.2.0e) | Modified: RLVa-1.1.0l // Block all special click action cursors when: // - @fartouch=n restricted and the object is out of range @@ -599,6 +611,7 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask) if (handleMediaHover(mHoverPick)) { // cursor set by media object + LL_DEBUGS("UserInput") << "hover handled by LLToolPie (inactive)" << LL_ENDL; } else if (!mMouseOutsideSlop && mMouseButtonDown @@ -626,7 +639,7 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask) else { // perform a separate pick that detects transparent objects since they respond to 1-click actions - LLPickInfo click_action_pick = gViewerWindow->pickImmediate(x, y, TRUE); + LLPickInfo click_action_pick = gViewerWindow->pickImmediate(x, y, TRUE, pick_rigged); LLViewerObject* click_action_object = click_action_pick.getObject(); @@ -634,6 +647,7 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask) { ECursorType cursor = cursorFromObject(click_action_object); gViewerWindow->setCursor(cursor); + LL_DEBUGS("UserInput") << "hover handled by LLToolPie (inactive)" << LL_ENDL; } // [RLVa:KB] - Checked: 2010-03-11 (RLVa-1.2.0e) | Added: RLVa-1.1.0l else if ( (object) && (rlv_handler_t::isEnabled()) && (!gRlvHandler.canTouch(object)) ) @@ -646,22 +660,23 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask) || (parent && !parent->isAvatar() && parent->flagUsePhysics())) { gViewerWindow->setCursor(UI_CURSOR_TOOLGRAB); + LL_DEBUGS("UserInput") << "hover handled by LLToolPie (inactive)" << LL_ENDL; } else if ( (object && object->flagHandleTouch()) || (parent && parent->flagHandleTouch())) { gViewerWindow->setCursor(UI_CURSOR_HAND); + LL_DEBUGS("UserInput") << "hover handled by LLToolPie (inactive)" << LL_ENDL; } else { gViewerWindow->setCursor(UI_CURSOR_ARROW); + LL_DEBUGS("UserInput") << "hover handled by LLToolPie (inactive)" << LL_ENDL; } } if(!object) { - //gViewerWindow->setCursor(UI_CURSOR_ARROW); - // We need to clear media hover flag LLViewerMediaFocus::getInstance()->clearHover(); } @@ -687,50 +702,53 @@ BOOL LLToolPie::handleMouseUp(S32 x, S32 y, MASK mask) && gAgentAvatarp && !gAgentAvatarp->isSitting() && !mBlockClickToWalk // another behavior hasn't cancelled click to walk - && !mPick.mPosGlobal.isExactlyZero() // valid coordinates for pick - && (mPick.mPickType == LLPickInfo::PICK_LAND // we clicked on land - || mPick.mObjectID.notNull())) // or on an object + ) { - // handle special cases of steering picks - LLViewerObject* avatar_object = mPick.getObject(); - - // get pointer to avatar - while (avatar_object && !avatar_object->isAvatar()) - { - avatar_object = (LLViewerObject*)avatar_object->getParent(); - } + // We may be doing click to walk, but we don't want to use a target on + // a transparent object because the user thought they were clicking on + // whatever they were seeing through it, so recompute what was clicked on + // ignoring transparent objects + LLPickInfo savedPick = mPick; + mPick = gViewerWindow->pickImmediate(savedPick.mMousePt.mX, savedPick.mMousePt.mY, + FALSE /* ignore transparent */, + FALSE /* ignore rigged */, + FALSE /* ignore particles */); + LLViewerObject* objp = mPick.getObject(); + bool is_in_world = mPick.mObjectID.notNull() && objp && !objp->isHUDAttachment(); // We clicked on a non-hud object + bool is_land = mPick.mPickType == LLPickInfo::PICK_LAND; // or on land + bool pos_non_zero = !mPick.mPosGlobal.isExactlyZero(); // valid coordinates for pick + if (pos_non_zero && (is_land || is_in_world)) + { + // get pointer to avatar + while (objp && !objp->isAvatar()) + { + objp = (LLViewerObject*) objp->getParent(); + } - if (avatar_object && ((LLVOAvatar*)avatar_object)->isSelf()) - { - const F64 SELF_CLICK_WALK_DISTANCE = 3.0; - // pretend we picked some point a bit in front of avatar - mPick.mPosGlobal = gAgent.getPositionGlobal() + LLVector3d(LLViewerCamera::instance().getAtAxis()) * SELF_CLICK_WALK_DISTANCE; - } - gAgentCamera.setFocusOnAvatar(TRUE, TRUE); - walkToClickedLocation(); + if (objp && ((LLVOAvatar*) objp)->isSelf()) + { + const F64 SELF_CLICK_WALK_DISTANCE = 3.0; + // pretend we picked some point a bit in front of avatar + mPick.mPosGlobal = gAgent.getPositionGlobal() + LLVector3d(LLViewerCamera::instance().getAtAxis()) * SELF_CLICK_WALK_DISTANCE; + } + gAgentCamera.setFocusOnAvatar(TRUE, TRUE); + walkToClickedLocation(); + //LLFirstUse::notMoving(false); - return TRUE; - } - else - { - switch(click_action) - { - case CLICK_ACTION_BUY: - case CLICK_ACTION_PAY: - case CLICK_ACTION_OPEN: - // Because these actions open UI dialogs, we won't change - // the cursor again until the next hover and GL pick over - // the world. Keep the cursor an arrow, assuming that - // after the user moves off the UI, they won't be on the - // same object anymore. - gViewerWindow->setCursor(UI_CURSOR_ARROW); - // Make sure the hover-picked object is ignored. - gHoverView->resetLastHoverObject(); - break; - default: - break; + return TRUE; } + else + { + LL_DEBUGS("maint5901") << "walk target was " + << (mPick.mPosGlobal.isExactlyZero() ? "zero" : "not zero") + << ", pick type was " << (mPick.mPickType == LLPickInfo::PICK_LAND ? "land" : "not land") + << ", pick object was " << mPick.mObjectID + << LL_ENDL; + // we didn't click to walk, so restore the original target + mPick = savedPick; + } } + gViewerWindow->setCursor(UI_CURSOR_ARROW); if (hasMouseCapture()) { setMouseCapture(FALSE); @@ -745,8 +763,7 @@ BOOL LLToolPie::handleMouseUp(S32 x, S32 y, MASK mask) void LLToolPie::stopClickToWalk() { - mPick.mPosGlobal = gAgent.getPositionGlobal(); - handle_go_to(); + handle_go_to(gAgent.getPositionGlobal()); /* Singu TODO: llhudeffectblob if(mAutoPilotDestination) { @@ -759,20 +776,31 @@ BOOL LLToolPie::handleDoubleClick(S32 x, S32 y, MASK mask) { if (gDebugClicks) { - llinfos << "LLToolPie handleDoubleClick (becoming mouseDown)" << llendl; + LL_INFOS() << "LLToolPie handleDoubleClick (becoming mouseDown)" << LL_ENDL; } - if (gSavedSettings.getBOOL("DoubleClickAutoPilot")) - { - if ((mPick.mPickType == LLPickInfo::PICK_LAND && !mPick.mPosGlobal.isExactlyZero()) || - (mPick.mObjectID.notNull() && !mPick.mPosGlobal.isExactlyZero())) - { - walkToClickedLocation(); - return TRUE; - } - } - else if (gSavedSettings.getBOOL("DoubleClickTeleport")) + if (handleMediaDblClick(mPick)) + { + return TRUE; + } + + bool dbl_click_autoplt = gSavedSettings.getBOOL("DoubleClickAutoPilot"); + bool dbl_click_teleport = gSavedSettings.getBOOL("DoubleClickTeleport"); + + if (dbl_click_autoplt || dbl_click_teleport) { + // Save the original pick + LLPickInfo savedPick = mPick; + + // We may be doing double click to walk or a double click teleport, but + // we don't want to use a target on a transparent object because the user + // thought they were clicking on whatever they were seeing through it, so + // recompute what was clicked on ignoring transparent objects + mPick = gViewerWindow->pickImmediate(savedPick.mMousePt.mX, savedPick.mMousePt.mY, + FALSE /* ignore transparent */, + FALSE /* ignore rigged */, + FALSE /* ignore particles */); + LLViewerObject* objp = mPick.getObject(); LLViewerObject* parentp = objp ? objp->getRootEdit() : NULL; @@ -780,15 +808,43 @@ BOOL LLToolPie::handleDoubleClick(S32 x, S32 y, MASK mask) bool is_land = mPick.mPickType == LLPickInfo::PICK_LAND; bool pos_non_zero = !mPick.mPosGlobal.isExactlyZero(); bool has_touch_handler = (objp && objp->flagHandleTouch()) || (parentp && parentp->flagHandleTouch()); - bool has_click_action = final_click_action(objp); - - if (pos_non_zero && (is_land || (is_in_world && !has_touch_handler && !has_click_action))) + bool no_click_action = final_click_action(objp) == CLICK_ACTION_NONE; + if (pos_non_zero && (is_land || (is_in_world && !has_touch_handler && no_click_action))) { - LLVector3d pos = mPick.mPosGlobal; - pos.mdV[VZ] += gAgentAvatarp->getPelvisToFoot(); - gAgent.teleportViaLocationLookAt(pos); - return TRUE; + if (dbl_click_autoplt + && !gAgent.getFlying() // don't auto-navigate while flying until that works + && isAgentAvatarValid() + && !gAgentAvatarp->isSitting() + ) + { + // get pointer to avatar + while (objp && !objp->isAvatar()) + { + objp = (LLViewerObject*) objp->getParent(); + } + + if (objp && ((LLVOAvatar*) objp)->isSelf()) + { + const F64 SELF_CLICK_WALK_DISTANCE = 3.0; + // pretend we picked some point a bit in front of avatar + mPick.mPosGlobal = gAgent.getPositionGlobal() + LLVector3d(LLViewerCamera::instance().getAtAxis()) * SELF_CLICK_WALK_DISTANCE; + } + gAgentCamera.setFocusOnAvatar(TRUE, TRUE); + walkToClickedLocation(); + //LLFirstUse::notMoving(false); + return TRUE; + } + else if (dbl_click_teleport) + { + LLVector3d pos = mPick.mPosGlobal; + pos.mdV[VZ] += gAgentAvatarp->getPelvisToFoot(); + gAgent.teleportViaLocationLookAt(pos); + return TRUE; + } } + + // restore the original pick for any other purpose + mPick = savedPick; } return FALSE; @@ -813,7 +869,8 @@ void LLToolPie::handleDeselect() LLTool* LLToolPie::getOverrideTool(MASK mask) { - if (gSavedSettings.getBOOL("EnableGrab")) + static LLCachedControl enable_grab(gSavedSettings, "EnableGrab", true); + if (enable_grab) { if (mask == MASK_CONTROL) { @@ -891,56 +948,110 @@ static void handle_click_action_play() bool LLToolPie::handleMediaClick(const LLPickInfo& pick) { - //FIXME: how do we handle object in different parcel than us? - LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); - LLPointer objectp = pick.getObject(); - - - if (!parcel || - objectp.isNull() || - pick.mObjectFace < 0 || - pick.mObjectFace >= objectp->getNumTEs()) - { - LLViewerMediaFocus::getInstance()->clearFocus(); - - return false; - } - - // Does this face have media? - const LLTextureEntry* tep = objectp->getTE(pick.mObjectFace); - if(!tep) - return false; - - LLMediaEntry* mep = (tep->hasMedia()) ? tep->getMediaData() : NULL; - if(!mep) - return false; - - viewer_media_t media_impl = LLViewerMedia::getMediaImplFromTextureID(mep->getMediaID()); - - if (gSavedSettings.getBOOL("MediaOnAPrimUI")) - { - if (!LLViewerMediaFocus::getInstance()->isFocusedOnFace(pick.getObject(), pick.mObjectFace) || media_impl.isNull()) - { - // It's okay to give this a null impl - LLViewerMediaFocus::getInstance()->setFocusFace(pick.getObject(), pick.mObjectFace, media_impl, pick.mNormal); - } - else - { - // Make sure keyboard focus is set to the media focus object. - gFocusMgr.setKeyboardFocus(LLViewerMediaFocus::getInstance()); - LLEditMenuHandler::gEditMenuHandler = LLViewerMediaFocus::instance().getFocusedMediaImpl(); - - media_impl->mouseDown(pick.mUVCoords, gKeyboard->currentMask(TRUE)); - mMediaMouseCaptureID = mep->getMediaID(); - setMouseCapture(TRUE); // This object will send a mouse-up to the media when it loses capture. - } - - return true; - } - - LLViewerMediaFocus::getInstance()->clearFocus(); + //FIXME: how do we handle object in different parcel than us? + LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + LLPointer objectp = pick.getObject(); + + + if (!parcel || + objectp.isNull() || + pick.mObjectFace < 0 || + pick.mObjectFace >= objectp->getNumTEs()) + { + LLViewerMediaFocus::getInstance()->clearFocus(); + + return false; + } + + // Does this face have media? + const LLTextureEntry* tep = objectp->getTE(pick.mObjectFace); + if (!tep) + return false; + + LLMediaEntry* mep = (tep->hasMedia()) ? tep->getMediaData() : NULL; + if (!mep) + return false; + + viewer_media_t media_impl = LLViewerMedia::getMediaImplFromTextureID(mep->getMediaID()); + + if (gSavedSettings.getBOOL("MediaOnAPrimUI")) + { + if (!LLViewerMediaFocus::getInstance()->isFocusedOnFace(pick.getObject(), pick.mObjectFace) || media_impl.isNull()) + { + // It's okay to give this a null impl + LLViewerMediaFocus::getInstance()->setFocusFace(pick.getObject(), pick.mObjectFace, media_impl, pick.mNormal); + } + else + { + // Make sure keyboard focus is set to the media focus object. + gFocusMgr.setKeyboardFocus(LLViewerMediaFocus::getInstance()); + LLEditMenuHandler::gEditMenuHandler = LLViewerMediaFocus::instance().getFocusedMediaImpl(); + + media_impl->mouseDown(pick.mUVCoords, gKeyboard->currentMask(TRUE)); + mMediaMouseCaptureID = mep->getMediaID(); + setMouseCapture(TRUE); // This object will send a mouse-up to the media when it loses capture. + } + + return true; + } + + LLViewerMediaFocus::getInstance()->clearFocus(); + + return false; +} - return false; +bool LLToolPie::handleMediaDblClick(const LLPickInfo& pick) +{ + //FIXME: how do we handle object in different parcel than us? + LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + LLPointer objectp = pick.getObject(); + + + if (!parcel || + objectp.isNull() || + pick.mObjectFace < 0 || + pick.mObjectFace >= objectp->getNumTEs()) + { + LLViewerMediaFocus::getInstance()->clearFocus(); + + return false; + } + + // Does this face have media? + const LLTextureEntry* tep = objectp->getTE(pick.mObjectFace); + if (!tep) + return false; + + LLMediaEntry* mep = (tep->hasMedia()) ? tep->getMediaData() : NULL; + if (!mep) + return false; + + viewer_media_t media_impl = LLViewerMedia::getMediaImplFromTextureID(mep->getMediaID()); + + if (gSavedSettings.getBOOL("MediaOnAPrimUI")) + { + if (!LLViewerMediaFocus::getInstance()->isFocusedOnFace(pick.getObject(), pick.mObjectFace) || media_impl.isNull()) + { + // It's okay to give this a null impl + LLViewerMediaFocus::getInstance()->setFocusFace(pick.getObject(), pick.mObjectFace, media_impl, pick.mNormal); + } + else + { + // Make sure keyboard focus is set to the media focus object. + gFocusMgr.setKeyboardFocus(LLViewerMediaFocus::getInstance()); + LLEditMenuHandler::gEditMenuHandler = LLViewerMediaFocus::instance().getFocusedMediaImpl(); + + media_impl->mouseDoubleClick(pick.mUVCoords, gKeyboard->currentMask(TRUE)); + mMediaMouseCaptureID = mep->getMediaID(); + setMouseCapture(TRUE); // This object will send a mouse-up to the media when it loses capture. + } + + return true; + } + + LLViewerMediaFocus::getInstance()->clearFocus(); + + return false; } bool LLToolPie::handleMediaHover(const LLPickInfo& pick) @@ -951,7 +1062,7 @@ bool LLToolPie::handleMediaHover(const LLPickInfo& pick) LLPointer objectp = pick.getObject(); - // Early out cases. Must clear mouse over media focus flag + // Early out cases. Must clear media hover. // did not hit an object or did not hit a valid face if ( objectp.isNull() || pick.mObjectFace < 0 || @@ -1092,9 +1203,6 @@ BOOL LLToolPie::handleRightClickPick() // didn't click in any UI object, so must have clicked in the world LLViewerObject *object = mPick.getObject(); - LLViewerObject *parent = NULL; - if(object) - parent = object->getRootEdit(); // Can't ignore children here. LLToolSelect::handleObjectSelection(mPick, FALSE, TRUE); @@ -1104,7 +1212,7 @@ BOOL LLToolPie::handleRightClickPick() { LLParcelSelectionHandle selection = LLViewerParcelMgr::getInstance()->selectParcelAt( mPick.mPosGlobal ); gMenuHolder->setParcelSelection(selection); - gPieLand->show(x, y, true); + gPieLand->show(x, y); showVisualContextMenuEffect(); @@ -1118,7 +1226,7 @@ BOOL LLToolPie::handleRightClickPick() return TRUE ; } - gPieSelf->show(x, y, true); + gPieSelf->show(x, y); } else if (object) { @@ -1162,11 +1270,11 @@ BOOL LLToolPie::handleRightClickPick() // [/RLVa:KB] /*if (is_other_attachment) { - gPieAttachmentOther->show(x, y, true); + gPieAttachmentOther->show(x, y); } else*/ { - gPieAvatar->show(x, y, true); + gPieAvatar->show(x, y); } // [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Modified: RLVa-1.1.0l } @@ -1178,7 +1286,7 @@ BOOL LLToolPie::handleRightClickPick() } else if (object->isAttachment()) { - gPieAttachment->show(x, y, true); + gPieAttachment->show(x, y); } else { @@ -1207,7 +1315,7 @@ BOOL LLToolPie::handleRightClickPick() { // [/RLVa:KB] gMenuHolder->childSetText("Object Mute", mute_msg); - gPieObject->show(x, y, true); + gPieObject->show(x, y); showVisualContextMenuEffect(); // [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.el) | Modified: RLVa-1.1.0l @@ -1227,9 +1335,11 @@ BOOL LLToolPie::handleRightClickPick() void LLToolPie::showVisualContextMenuEffect() { - // - if (gSavedSettings.getBOOL("DisablePointAtAndBeam")) return; - // + if (gSavedSettings.getBOOL("DisablePointAtAndBeam")) + { + return; + } + // VEFFECT: ShowPie LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_SPHERE, TRUE); effectp->setPositionGlobal(mPick.mPosGlobal); @@ -1274,6 +1384,7 @@ bool intersect_ray_with_sphere( const LLVector3& ray_pt, const LLVector3& ray_di void LLToolPie::startCameraSteering() { + //LLFirstUse::notMoving(false); mMouseOutsideSlop = true; mBlockClickToWalk = true; @@ -1381,7 +1492,7 @@ void LLToolPie::steerCameraWithMouse(S32 x, S32 y) { old_yaw_angle = F_PI_BY_TWO + asinf(pick_distance_from_rotation_center / camera_distance_from_rotation_center); - if (mouse_ray * rotation_frame.getLeftAxis() < 0.f) + if (old_mouse_ray * rotation_frame.getLeftAxis() < 0.f) { old_yaw_angle *= -1.f; } diff --git a/indra/newview/lltoolpie.h b/indra/newview/lltoolpie.h index 5f3c75c3b3..ffae5b9457 100644 --- a/indra/newview/lltoolpie.h +++ b/indra/newview/lltoolpie.h @@ -89,6 +89,7 @@ class LLToolPie : public LLTool, public LLSingleton ECursorType cursorFromObject(LLViewerObject* object); bool handleMediaClick(const LLPickInfo& info); + bool handleMediaDblClick(const LLPickInfo& info); bool handleMediaHover(const LLPickInfo& info); bool handleMediaMouseUp(); diff --git a/indra/newview/lltoolpipette.cpp b/indra/newview/lltoolpipette.cpp index 878ed0f9a9..c327a39084 100644 --- a/indra/newview/lltoolpipette.cpp +++ b/indra/newview/lltoolpipette.cpp @@ -67,7 +67,7 @@ BOOL LLToolPipette::handleMouseDown(S32 x, S32 y, MASK mask) mSuccess = TRUE; mTooltipMsg.clear(); setMouseCapture(TRUE); - gViewerWindow->pickAsync(x, y, mask, pickCallback); + gViewerWindow->pickAsync(x, y, mask, pickCallback, FALSE, TRUE); return TRUE; } diff --git a/indra/newview/lltoolplacer.cpp b/indra/newview/lltoolplacer.cpp index 3d36b1fbbe..1c225398c1 100644 --- a/indra/newview/lltoolplacer.cpp +++ b/indra/newview/lltoolplacer.cpp @@ -95,7 +95,7 @@ BOOL LLToolPlacer::raycastForNewObjPos( S32 x, S32 y, LLViewerObject** hit_obj, // Viewer-side pick to find the right sim to create the object on. // First find the surface the object will be created on. - LLPickInfo pick = gViewerWindow->pickImmediate(x, y, FALSE); + LLPickInfo pick = gViewerWindow->pickImmediate(x, y, FALSE, TRUE); // Note: use the frontmost non-flora version because (a) plants usually have lots of alpha and (b) pants' Havok // representations (if any) are NOT the same as their viewer representation. @@ -150,7 +150,7 @@ BOOL LLToolPlacer::raycastForNewObjPos( S32 x, S32 y, LLViewerObject** hit_obj, LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromPosGlobal(surface_pos_global); if (!regionp) { - llwarns << "Trying to add object outside of all known regions!" << llendl; + LL_WARNS() << "Trying to add object outside of all known regions!" << LL_ENDL; return FALSE; } @@ -213,7 +213,7 @@ BOOL LLToolPlacer::addObject( LLPCode pcode, S32 x, S32 y, U8 use_physics ) if (NULL == regionp) { - llwarns << "regionp was NULL; aborting function." << llendl; + LL_WARNS() << "regionp was NULL; aborting function." << LL_ENDL; return FALSE; } @@ -593,7 +593,7 @@ BOOL LLToolPlacer::placeObject(S32 x, S32 y, MASK mask) BOOL LLToolPlacer::handleHover(S32 x, S32 y, MASK mask) { - lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolPlacer" << llendl; + LL_DEBUGS("UserInput") << "hover handled by LLToolPlacer" << LL_ENDL; gViewerWindow->getWindow()->setCursor(UI_CURSOR_TOOLCREATE); return TRUE; } diff --git a/indra/newview/lltoolselect.cpp b/indra/newview/lltoolselect.cpp index 39cd470f31..4b53f057de 100644 --- a/indra/newview/lltoolselect.cpp +++ b/indra/newview/lltoolselect.cpp @@ -69,7 +69,8 @@ LLToolSelect::LLToolSelect( LLToolComposite* composite ) BOOL LLToolSelect::handleMouseDown(S32 x, S32 y, MASK mask) { // do immediate pick query - mPick = gViewerWindow->pickImmediate(x, y, TRUE); + BOOL pick_rigged = true; //gSavedSettings.getBOOL("AnimatedObjectsAllowLeftClick"); + mPick = gViewerWindow->pickImmediate(x, y, TRUE, pick_rigged); // Pass mousedown to agent LLTool::handleMouseDown(x, y, mask); @@ -215,7 +216,7 @@ LLObjectSelectionHandle LLToolSelect::handleObjectSelection(const LLPickInfo& pi LLSelectMgr::getInstance()->setAgentHUDZoom(target_zoom, current_zoom); } - if (!gAgentCamera.getFocusOnAvatar() && // if camera not glued to avatar + if (gSavedSettings.getBOOL("RightClickTurnsAvatar") && !gAgentCamera.getFocusOnAvatar() && // if camera not glued to avatar LLVOAvatar::findAvatarFromAttachment(object) != gAgentAvatarp && // and it's not one of your attachments object != gAgentAvatarp) // and it's not you { diff --git a/indra/newview/lltoolselect.h b/indra/newview/lltoolselect.h index 37f28ccc7f..4d7606ec29 100644 --- a/indra/newview/lltoolselect.h +++ b/indra/newview/lltoolselect.h @@ -2,31 +2,25 @@ * @file lltoolselect.h * @brief LLToolSelect class header file * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -40,7 +34,7 @@ class LLObjectSelection; -class LLToolSelect : public LLTool, public LLSingleton +class LLToolSelect : public LLTool { public: LLToolSelect( LLToolComposite* composite ); diff --git a/indra/newview/lltoolselectland.cpp b/indra/newview/lltoolselectland.cpp index 0c66378285..ec7d3fc430 100644 --- a/indra/newview/lltoolselectland.cpp +++ b/indra/newview/lltoolselectland.cpp @@ -175,13 +175,13 @@ BOOL LLToolSelectLand::handleHover(S32 x, S32 y, MASK mask) roundXY(mWestSouthBottom); roundXY(mEastNorthTop); - lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolSelectLand (active, land)" << llendl; + LL_DEBUGS("UserInput") << "hover handled by LLToolSelectLand (active, land)" << LL_ENDL; gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW); } else { mDragEndValid = FALSE; - lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolSelectLand (active, no land)" << llendl; + LL_DEBUGS("UserInput") << "hover handled by LLToolSelectLand (active, no land)" << LL_ENDL; gViewerWindow->getWindow()->setCursor(UI_CURSOR_NO); } @@ -190,13 +190,13 @@ BOOL LLToolSelectLand::handleHover(S32 x, S32 y, MASK mask) } else { - lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolSelectLand (active, in slop)" << llendl; + LL_DEBUGS("UserInput") << "hover handled by LLToolSelectLand (active, in slop)" << LL_ENDL; gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW); } } else { - lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolSelectLand (inactive)" << llendl; + LL_DEBUGS("UserInput") << "hover handled by LLToolSelectLand (inactive)" << LL_ENDL; gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW); } @@ -226,8 +226,8 @@ void LLToolSelectLand::handleDeselect() void LLToolSelectLand::roundXY(LLVector3d &vec) { - vec.mdV[VX] = llround( vec.mdV[VX], (F64)PARCEL_GRID_STEP_METERS ); - vec.mdV[VY] = llround( vec.mdV[VY], (F64)PARCEL_GRID_STEP_METERS ); + vec.mdV[VX] = ll_round( vec.mdV[VX], (F64)PARCEL_GRID_STEP_METERS ); + vec.mdV[VY] = ll_round( vec.mdV[VY], (F64)PARCEL_GRID_STEP_METERS ); } diff --git a/indra/newview/lltoolselectrect.cpp b/indra/newview/lltoolselectrect.cpp index f57820afd1..17c9efabca 100644 --- a/indra/newview/lltoolselectrect.cpp +++ b/indra/newview/lltoolselectrect.cpp @@ -38,7 +38,6 @@ // Library includes #include "llgl.h" #include "llrender.h" -#include "lldarray.h" // Viewer includes #include "llviewercontrol.h" @@ -79,7 +78,8 @@ void dialog_refresh_all(void); BOOL LLToolSelectRect::handleMouseDown(S32 x, S32 y, MASK mask) { - handlePick(gViewerWindow->pickImmediate(x, y, TRUE)); + BOOL pick_rigged = true; //gSavedSettings.getBOOL("AnimatedObjectsAllowLeftClick"); + handlePick(gViewerWindow->pickImmediate(x, y, TRUE /* pick_transparent */, pick_rigged)); LLTool::handleMouseDown(x, y, mask); @@ -152,11 +152,11 @@ BOOL LLToolSelectRect::handleHover(S32 x, S32 y, MASK mask) return LLToolSelect::handleHover(x, y, mask); } - lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolSelectRect (active)" << llendl; + LL_DEBUGS("UserInput") << "hover handled by LLToolSelectRect (active)" << LL_ENDL; } else { - lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolSelectRect (inactive)" << llendl; + LL_DEBUGS("UserInput") << "hover handled by LLToolSelectRect (inactive)" << LL_ENDL; } gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW); diff --git a/indra/newview/lltoolselectrect.h b/indra/newview/lltoolselectrect.h index e794897958..00d774b219 100644 --- a/indra/newview/lltoolselectrect.h +++ b/indra/newview/lltoolselectrect.h @@ -2,31 +2,25 @@ * @file lltoolselectrect.h * @brief A tool to select multiple objects with a screen-space rectangle. * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/newview/lltoolview.cpp b/indra/newview/lltoolview.cpp index 20240e79ba..716faf546e 100644 --- a/indra/newview/lltoolview.cpp +++ b/indra/newview/lltoolview.cpp @@ -184,7 +184,7 @@ LLToolContainer* LLToolView::findToolContainer( LLTool *tool ) return contain; } } - llerrs << "LLToolView::findToolContainer - tool not found" << llendl; + LL_ERRS() << "LLToolView::findToolContainer - tool not found" << LL_ENDL; return NULL; } diff --git a/indra/newview/lltracker.cpp b/indra/newview/lltracker.cpp index 24dc163832..53abe129ea 100644 --- a/indra/newview/lltracker.cpp +++ b/indra/newview/lltracker.cpp @@ -33,8 +33,6 @@ #include "llviewerprecompiledheaders.h" // library includes -#include "llcoord.h" -#include "lldarray.h" #include "llfontgl.h" #include "llgl.h" #include "llrender.h" @@ -273,7 +271,7 @@ void LLTracker::render3D() // instance()->mBeaconText, av_tracker.getName() ); // [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0a) | Added: RLVa-1.0.0a renderBeacon( av_tracker.getGlobalPos(), gTrackColor, instance()->mBeaconText, - (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) ? av_tracker.getName() : RlvStrings::getString(RLV_STRING_HIDDEN)); + (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES) && !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS)) ? av_tracker.getName() : RlvStrings::getString(RLV_STRING_HIDDEN)); // [/RLVa:KB] } } @@ -427,7 +425,7 @@ const std::string& LLTracker::getTrackedLocationName() return instance()->mTrackedLocationName; } -F32 pulse_func(F32 t, F32 z) +F32 pulse_func(F32 t, F32 z, bool down) { if (!LLTracker::sCheesyBeacon) { @@ -435,7 +433,14 @@ F32 pulse_func(F32 t, F32 z) } t *= F_PI; - z -= t*64.f - 256.f; + if (down) + { + z += t*64.f - 256.f; + } + else + { + z -= t*64.f - 256.f; + } F32 a = cosf(z*F_PI/512.f)*10.0f; a = llmax(a, 9.9f); @@ -489,6 +494,74 @@ void draw_shockwave(F32 center_z, F32 t, S32 steps, LLColor4 color) gGL.end(); } +void draw_beacon(LLVector3 pos_agent, bool down, LLColor4 fogged_color, F32 dist) +{ + const U32 BEACON_VERTS = 256; + F32 step; + + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.pushMatrix(); + + if (down) + { + gGL.translatef(pos_agent.mV[0], pos_agent.mV[1], pos_agent.mV[2]); + draw_shockwave(1024.f, gRenderStartTime.getElapsedTimeF32(), 32, fogged_color); + step = (8192.0f - pos_agent.mV[2]) / BEACON_VERTS; + } + else + { + gGL.translatef(pos_agent.mV[0], pos_agent.mV[1], 0); + step = pos_agent[2] / BEACON_VERTS; + } + + gGL.color4fv(fogged_color.mV); + + LLVector3 x_axis = LLViewerCamera::getInstance()->getLeftAxis(); + F32 t = gRenderStartTime.getElapsedTimeF32(); + F32 dr = dist/LLViewerCamera::getInstance()->getFar(); + + for (U32 i = 0; i < BEACON_VERTS; i++) + { + F32 x = x_axis.mV[0]; + F32 y = x_axis.mV[1]; + + F32 z = i * step; + F32 z_next = (i+1)*step; + + F32 a = pulse_func(t, z, down); + F32 an = pulse_func(t, z_next, down); + + LLColor4 c_col = fogged_color + LLColor4(a,a,a,a); + LLColor4 col_next = fogged_color + LLColor4(an,an,an,an); + LLColor4 col_edge = fogged_color * LLColor4(a,a,a,0.0f); + LLColor4 col_edge_next = fogged_color * LLColor4(an,an,an,0.0f); + + a *= 2.f; + a += 1.0f+dr; + + an *= 2.f; + an += 1.0f+dr; + + gGL.begin(LLRender::TRIANGLE_STRIP); + gGL.color4fv(col_edge.mV); + gGL.vertex3f(-x*a, -y*a, z); + gGL.color4fv(col_edge_next.mV); + gGL.vertex3f(-x*an, -y*an, z_next); + + gGL.color4fv(c_col.mV); + gGL.vertex3f(0, 0, z); + gGL.color4fv(col_next.mV); + gGL.vertex3f(0, 0, z_next); + + gGL.color4fv(col_edge.mV); + gGL.vertex3f(x*a,y*a,z); + gGL.color4fv(col_edge_next.mV); + gGL.vertex3f(x*an,y*an,z_next); + + gGL.end(); + } + gGL.popMatrix(); +} // static void LLTracker::renderBeacon(LLVector3d pos_global, @@ -496,6 +569,7 @@ void LLTracker::renderBeacon(LLVector3d pos_global, LLHUDText* hud_textp, const std::string& label ) { + const LLColor4& color_under(LLColor4::blue); sCheesyBeacon = gSavedSettings.getBOOL("CheesyBeacon"); LLVector3d to_vec = pos_global - gAgentCamera.getCameraPositionGlobal(); @@ -512,75 +586,21 @@ void LLTracker::renderBeacon(LLVector3d pos_global, } LLColor4 fogged_color = color_frac * color + (1 - color_frac)*gSky.getFogColor(); + LLColor4 fogged_color_under = color_frac * color_under + (1 - color_frac) * gSky.getFogColor(); F32 FADE_DIST = 3.f; fogged_color.mV[3] = llmax(0.2f, llmin(0.5f,(dist-FADE_DIST)/FADE_DIST)); + fogged_color_under.mV[3] = llmax(0.2f, llmin(0.5f,(dist-FADE_DIST)/FADE_DIST)); LLVector3 pos_agent = gAgent.getPosAgentFromGlobal(pos_global); LLGLSTracker gls_tracker; // default+ CULL_FACE + LIGHTING + GL_BLEND + GL_ALPHA_TEST gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - LLGLDisable cull_face(GL_CULL_FACE); + LLGLDisable cull_face; LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE); - - gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.pushMatrix(); - { - gGL.translatef(pos_agent.mV[0], pos_agent.mV[1], pos_agent.mV[2]); - - draw_shockwave(1024.f, gRenderStartTime.getElapsedTimeF32(), 32, fogged_color); - - gGL.color4fv(fogged_color.mV); - const U32 BEACON_VERTS = 256; - const F32 step = 1024.0f/BEACON_VERTS; - - LLVector3 x_axis = LLViewerCamera::getInstance()->getLeftAxis(); - F32 t = gRenderStartTime.getElapsedTimeF32(); - F32 dr = dist/LLViewerCamera::getInstance()->getFar(); - - for (U32 i = 0; i < BEACON_VERTS; i++) - { - F32 x = x_axis.mV[0]; - F32 y = x_axis.mV[1]; - - F32 z = i * step; - F32 z_next = (i+1)*step; - - F32 a = pulse_func(t, z); - F32 an = pulse_func(t, z_next); - - LLColor4 c_col = fogged_color + LLColor4(a,a,a,a); - LLColor4 col_next = fogged_color + LLColor4(an,an,an,an); - LLColor4 col_edge = fogged_color * LLColor4(a,a,a,0.0f); - LLColor4 col_edge_next = fogged_color * LLColor4(an,an,an,0.0f); - - a *= 2.f; - a += 1.0f+dr; - - an *= 2.f; - an += 1.0f+dr; - - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.color4fv(col_edge.mV); - gGL.vertex3f(-x*a, -y*a, z); - gGL.color4fv(col_edge_next.mV); - gGL.vertex3f(-x*an, -y*an, z_next); - - gGL.color4fv(c_col.mV); - gGL.vertex3f(0, 0, z); - gGL.color4fv(col_next.mV); - gGL.vertex3f(0, 0, z_next); - - gGL.color4fv(col_edge.mV); - gGL.vertex3f(x*a,y*a,z); - gGL.color4fv(col_edge_next.mV); - gGL.vertex3f(x*an,y*an,z_next); - - gGL.end(); - } - } - gGL.popMatrix(); + draw_beacon(pos_agent, true, fogged_color, dist); + draw_beacon(pos_agent, false, fogged_color_under, dist); std::string text; text = llformat( "%.0f m", to_vec.magVec()); @@ -798,7 +818,7 @@ void LLTracker::cacheLandmarkPosition() } else { - llwarns << "LLTracker couldn't find home pos" << llendl; + LL_WARNS() << "LLTracker couldn't find home pos" << LL_ENDL; mTrackedLandmarkAssetID.setNull(); mTrackedLandmarkItemID.setNull(); } diff --git a/indra/newview/lltracker.h b/indra/newview/lltracker.h index f7009ae205..1dc56ceed0 100644 --- a/indra/newview/lltracker.h +++ b/indra/newview/lltracker.h @@ -39,7 +39,6 @@ #ifndef LL_LLTRACKER_H #define LL_LLTRACKER_H -#include "lldarray.h" #include "llmemory.h" #include "llstring.h" #include "lluuid.h" @@ -144,8 +143,8 @@ class LLTracker std::string mTrackedLandmarkName; LLUUID mTrackedLandmarkAssetID; LLUUID mTrackedLandmarkItemID; - LLDynamicArray mLandmarkAssetIDList; - LLDynamicArray mLandmarkItemIDList; + uuid_vec_t mLandmarkAssetIDList; + uuid_vec_t mLandmarkItemIDList; BOOL mHasReachedLandmark; BOOL mHasLandmarkPosition; BOOL mLandmarkHasBeenVisited; diff --git a/indra/newview/lltranslate.cpp b/indra/newview/lltranslate.cpp index 833926afe5..b639c75855 100644 --- a/indra/newview/lltranslate.cpp +++ b/indra/newview/lltranslate.cpp @@ -35,7 +35,7 @@ #include "llbufferstream.h" #include "lltranslate.h" #include "llui.h" -#include "sgversion.h" +#include "llversioninfo.h" #include "llweb.h" // @@ -64,9 +64,12 @@ void LLTranslate::translateMessage(LLHTTPClient::ResponderPtr &result, const std std::string url; getTranslateUrl(url, fromLang, toLang, mesg); -// - std::string user_agent = gCurrentVersion; -// + std::string user_agent = llformat("%s %d.%d.%d (%d)", + LLVersionInfo::getChannel().c_str(), + LLVersionInfo::getMajor(), + LLVersionInfo::getMinor(), + LLVersionInfo::getPatch(), + LLVersionInfo::getBuild()); if (m_Header.empty()) { diff --git a/indra/newview/lltranslate.h b/indra/newview/lltranslate.h index 769afc378a..f5638b6e2a 100644 --- a/indra/newview/lltranslate.h +++ b/indra/newview/lltranslate.h @@ -60,17 +60,15 @@ public : { } - /*virtual*/ void error(U32 status, const std::string& reason) + /*virtual*/ void httpFailure(void) { LL_WARNS("Translate") << "URL Request error: " << reason << LL_ENDL; handleFailure(); } /*virtual*/ void completedRaw( - U32 status, - const std::string& reason, - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) + LLChannelDescriptors const& channels, + LLIOPipe::buffer_ptr_t const& buffer) { LLBufferStream istr(channels, buffer.get()); diff --git a/indra/newview/lluiavatar.cpp b/indra/newview/lluiavatar.cpp new file mode 100644 index 0000000000..e4e266c92a --- /dev/null +++ b/indra/newview/lluiavatar.cpp @@ -0,0 +1,61 @@ +/** + * @file lluiavatar.cpp + * @brief Implementation for special dummy avatar used in some UI views + * + * $LicenseInfo:firstyear=2017&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2017, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "lluiavatar.h" +#include "llagent.h" // Get state values from here +#include "llviewerobjectlist.h" +#include "pipeline.h" +#include "llanimationstates.h" +#include "llviewercontrol.h" +#include "llmeshrepository.h" +#include "llviewerregion.h" + +LLUIAvatar::LLUIAvatar(const LLUUID& id, const LLPCode pcode, LLViewerRegion* regionp) : + LLVOAvatar(id, pcode, regionp) +{ + mIsDummy = TRUE; + mIsUIAvatar = true; +} + +// virtual +LLUIAvatar::~LLUIAvatar() +{ +} + +// virtual +void LLUIAvatar::initInstance() +{ + LLVOAvatar::initInstance(); + + createDrawable( &gPipeline ); + setPositionAgent(LLVector3::zero); + slamPosition(); + updateJointLODs(); + updateGeometry(mDrawable); + + mInitFlags |= 1<<3; +} diff --git a/indra/newview/lluiavatar.h b/indra/newview/lluiavatar.h new file mode 100644 index 0000000000..bcdffedef2 --- /dev/null +++ b/indra/newview/lluiavatar.h @@ -0,0 +1,44 @@ +/** + * @file lluiavatar.h + * @brief Special dummy avatar used in some UI views + * + * $LicenseInfo:firstyear=2017&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2017, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_UIAVATAR_H +#define LL_UIAVATAR_H + +#include "llvoavatar.h" +#include "llvovolume.h" + +class LLUIAvatar: + public LLVOAvatar +{ + LOG_CLASS(LLUIAvatar); + +public: + LLUIAvatar(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp); + virtual void initInstance(); // Called after construction to initialize the class. + virtual ~LLUIAvatar(); +}; + +#endif //LL_CONTROLAVATAR_H diff --git a/indra/newview/lluploaddialog.cpp b/indra/newview/lluploaddialog.cpp index a4f758ff82..a6c3f42dcd 100644 --- a/indra/newview/lluploaddialog.cpp +++ b/indra/newview/lluploaddialog.cpp @@ -112,7 +112,7 @@ void LLUploadDialog::setMessage( const std::string& msg) //strcpy(temp_msg,"Uploading...\n\n"); if (temp_msg == NULL) { - llerrs << "Memory Allocation Failed" << llendl; + LL_ERRS() << "Memory Allocation Failed" << LL_ENDL; return; } diff --git a/indra/newview/lluploadfloaterobservers.cpp b/indra/newview/lluploadfloaterobservers.cpp index c8aef6585f..066f3923ef 100644 --- a/indra/newview/lluploadfloaterobservers.cpp +++ b/indra/newview/lluploadfloaterobservers.cpp @@ -39,25 +39,24 @@ LLUploadModelPremissionsResponder::LLUploadModelPremissionsResponder(const LLHan { } -void LLUploadModelPremissionsResponder::error(U32 status, const std::string& reason) +void LLUploadModelPremissionsResponder::httpFailure(void) { - llwarns << "LLUploadModelPremissionsResponder::error(" - << status << ": " << reason << ")" << llendl; + LL_WARNS() << "httpFailure: " << dumpResponse() << LL_ENDL; LLUploadPermissionsObserver* observer = mObserverHandle.get(); if (observer) { - observer->setPermissonsErrorStatus(status, reason); + observer->setPermissonsErrorStatus(mStatus, mReason); } } -void LLUploadModelPremissionsResponder::result(const LLSD& content) +void LLUploadModelPremissionsResponder::httpSuccess(void) { LLUploadPermissionsObserver* observer = mObserverHandle.get(); if (observer) { - observer->onPermissionsReceived(content); + observer->onPermissionsReceived(mContent); } } diff --git a/indra/newview/lluploadfloaterobservers.h b/indra/newview/lluploadfloaterobservers.h index 0ddba6735e..a417b9a989 100644 --- a/indra/newview/lluploadfloaterobservers.h +++ b/indra/newview/lluploadfloaterobservers.h @@ -104,8 +104,8 @@ class LLUploadModelPremissionsResponder : public LLHTTPClient::ResponderWithResu LLUploadModelPremissionsResponder(const LLHandle& observer); - /*virtual*/ void error(U32 status, const std::string& reason); - /*virtual*/ void result(const LLSD& content); + /*virtual*/ void httpFailure(void); + /*virtual*/ void httpSuccess(void); /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return uploadModelPremissionsResponder_timeout; } /*virtual*/ char const* getName(void) const { return "LLUploadModelPremissionsResponder"; } diff --git a/indra/newview/llurl.cpp b/indra/newview/llurl.cpp index 83a5839a93..6dbdeae953 100644 --- a/indra/newview/llurl.cpp +++ b/indra/newview/llurl.cpp @@ -132,13 +132,13 @@ void LLURL::init(const char * url) strncpy(mPath,leftover_url, LL_MAX_PATH -1); /* Flawfinder: ignore */ mPath[LL_MAX_PATH -1] = '\0'; -// llinfos << url << " decomposed into: " << llendl; -// llinfos << " URI : <" << mURI << ">" << llendl; -// llinfos << " Auth: <" << mAuthority << ">" << llendl; -// llinfos << " Path: <" << mPath << ">" << llendl; -// llinfos << " File: <" << mFilename << ">" << llendl; -// llinfos << " Ext : <" << mExtension << ">" << llendl; -// llinfos << " Tag : <" << mTag << ">" << llendl; +// LL_INFOS() << url << " decomposed into: " << LL_ENDL; +// LL_INFOS() << " URI : <" << mURI << ">" << LL_ENDL; +// LL_INFOS() << " Auth: <" << mAuthority << ">" << LL_ENDL; +// LL_INFOS() << " Path: <" << mPath << ">" << LL_ENDL; +// LL_INFOS() << " File: <" << mFilename << ">" << LL_ENDL; +// LL_INFOS() << " Ext : <" << mExtension << ">" << LL_ENDL; +// LL_INFOS() << " Tag : <" << mTag << ">" << LL_ENDL; } void LLURL::cleanup() diff --git a/indra/newview/llurldispatcher.cpp b/indra/newview/llurldispatcher.cpp index dcf955cef2..eb976171d1 100644 --- a/indra/newview/llurldispatcher.cpp +++ b/indra/newview/llurldispatcher.cpp @@ -51,6 +51,7 @@ #include "hippogridmanager.h" // library includes +#include "llnotifications.h" #include "llnotificationsutil.h" #include "llsd.h" @@ -143,7 +144,7 @@ bool LLURLDispatcherImpl::dispatch(const LLSLURL& slurl, bool LLURLDispatcherImpl::dispatchRightClick(const LLSLURL& slurl) { const bool right_click = true; - LLMediaCtrl* web = NULL; + LLMediaCtrl* web = nullptr; const bool trusted_browser = false; return dispatchCore(slurl, "clicked", right_click, web, trusted_browser); } @@ -155,7 +156,7 @@ bool LLURLDispatcherImpl::dispatchApp(const LLSLURL& slurl, LLMediaCtrl* web, bool trusted_browser) { - llinfos << "cmd: " << slurl.getAppCmd() << " path: " << slurl.getAppPath() << " query: " << slurl.getAppQuery() << llendl; + LL_INFOS() << "cmd: " << slurl.getAppCmd() << " path: " << slurl.getAppPath() << " query: " << slurl.getAppQuery() << LL_ENDL; const LLSD& query_map = LLURI::queryMap(slurl.getAppQuery()); bool handled = LLCommandDispatcher::dispatch( slurl.getAppCmd(), slurl.getAppPath(), query_map, web, nav_type, trusted_browser); @@ -186,11 +187,18 @@ bool LLURLDispatcherImpl::dispatchRegion(const LLSLURL& slurl, const std::string LLPanelLogin::setLocation(slurl); return true; } + LLSLURL _slurl = slurl; + const std::string& grid = slurl.getGrid(); + const std::string& current_grid = gHippoGridManager->getCurrentGrid()->getGridName(); + if (grid != current_grid) + { + _slurl = LLSLURL(llformat("%s:%s", grid.c_str(), slurl.getRegion().c_str()), slurl.getPosition()); + } // Request a region handle by name LLWorldMapMessage::getInstance()->sendNamedRegionRequest(slurl.getRegion(), LLURLDispatcherImpl::regionNameCallback, - slurl.getSLURLString(), + _slurl.getSLURLString(), LLUI::sConfigGroup->getBOOL("SLURLTeleportDirectly")); // don't teleport return true; } @@ -262,17 +270,19 @@ void LLURLDispatcherImpl::regionHandleCallback(U64 region_handle, const LLSLURL& //--------------------------------------------------------------------------- // Teleportation links are handled here because they are tightly coupled -// to URL parsing and sim-fragment parsing +// to SLURL parsing and sim-fragment parsing + class LLTeleportHandler : public LLCommandHandler { public: // Teleport requests *must* come from a trusted browser // inside the app, otherwise a malicious web page could // cause a constant teleport loop. JC - LLTeleportHandler() : LLCommandHandler("teleport", UNTRUSTED_BLOCK) { } + LLTeleportHandler() : LLCommandHandler("teleport", UNTRUSTED_THROTTLE) { } + bool handle(const LLSD& tokens, const LLSD& query_map, - LLMediaCtrl* web) + LLMediaCtrl* web) override { // construct a "normal" SLURL, resolve the region to // a global position, and teleport to it @@ -285,19 +295,51 @@ class LLTeleportHandler : public LLCommandHandler tokens[2].asReal(), tokens[3].asReal()); } - + // Region names may be %20 escaped. - std::string region_name = LLURI::unescape(tokens[0]); + LLSD args; + args["LOCATION"] = region_name; + + LLSD payload; + payload["region_name"] = region_name; + payload["callback_url"] = LLSLURL(region_name, coords).getSLURLString(); + + LLNotificationsUtil::add("TeleportViaSLAPP", args, payload); + return true; + } + + static void teleport_via_slapp(std::string region_name, std::string callback_url) + { + LLWorldMapMessage::getInstance()->sendNamedRegionRequest(region_name, LLURLDispatcherImpl::regionHandleCallback, - LLSLURL(region_name, coords).getSLURLString(), + callback_url, true); // teleport - return true; } + + static bool teleport_via_slapp_callback(const LLSD& notification, const LLSD& response) + { + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + + std::string region_name = notification["payload"]["region_name"].asString(); + std::string callback_url = notification["payload"]["callback_url"].asString(); + + if (option == 0) + { + teleport_via_slapp(region_name, callback_url); + return true; + } + + return false; + } + }; LLTeleportHandler gTeleportHandler; +static LLNotificationFunctorRegistration open_landmark_callback_reg("TeleportViaSLAPP", LLTeleportHandler::teleport_via_slapp_callback); + + //--------------------------------------------------------------------------- @@ -317,7 +359,7 @@ bool LLURLDispatcher::dispatchRightClick(const std::string& slurl) } // static -bool LLURLDispatcher::dispatchFromTextEditor(const std::string& slurl) +bool LLURLDispatcher::dispatchFromTextEditor(const std::string& slurl, bool trusted_content) { // *NOTE: Text editors are considered sources of trusted URLs // in order to make avatar profile links in chat history work. @@ -325,9 +367,9 @@ bool LLURLDispatcher::dispatchFromTextEditor(const std::string& slurl) // receiving resident will see it and must affirmatively // click on it. // *TODO: Make this trust model more refined. JC - const bool trusted_browser = true; - LLMediaCtrl* web = NULL; - return LLURLDispatcherImpl::dispatch(LLSLURL(slurl), "clicked", web, trusted_browser); + + LLMediaCtrl* web = nullptr; + return LLURLDispatcherImpl::dispatch(LLSLURL(slurl), "clicked", web, trusted_content); } diff --git a/indra/newview/llurldispatcher.h b/indra/newview/llurldispatcher.h index 82e1d3152d..9b05260af1 100644 --- a/indra/newview/llurldispatcher.h +++ b/indra/newview/llurldispatcher.h @@ -2,36 +2,29 @@ * @file llurldispatcher.h * @brief Central registry for all SL URL handlers * - * $LicenseInfo:firstyear=2007&license=viewergpl$ - * - * Copyright (c) 2007-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2010&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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 LLURLDISPATCHER_H #define LLURLDISPATCHER_H - class LLMediaCtrl; @@ -49,6 +42,8 @@ class LLURLDispatcher // secondlife://RegionName/123/45/67/ // secondlife:///app/agent/3d6181b0-6a4b-97ef-18d8-722652995cf1/show // sl://app/foo/bar + // @param nav_type + // type of navigation type (see LLQtWebKit::LLWebPage::acceptNavigationRequest) // @param web // Pointer to LLMediaCtrl sending URL, can be NULL // @param trusted_browser @@ -58,7 +53,7 @@ class LLURLDispatcher static bool dispatchRightClick(const std::string& slurl); - static bool dispatchFromTextEditor(const std::string& slurl); + static bool dispatchFromTextEditor(const std::string& slurl, bool trusted_content); }; #endif diff --git a/indra/newview/llurlhistory.cpp b/indra/newview/llurlhistory.cpp index 876ce02d46..183cd0b717 100644 --- a/indra/newview/llurlhistory.cpp +++ b/indra/newview/llurlhistory.cpp @@ -54,15 +54,15 @@ bool LLURLHistory::loadFile(const std::string& filename) if (file.is_open()) { - llinfos << "Loading history.xml file at " << temp_str + filename << llendl; + LL_INFOS() << "Loading history.xml file at " << temp_str + filename << LL_ENDL; LLSDSerialize::fromXML(data, file); } if (data.isUndefined()) { - llinfos << "file missing, ill-formed, " + LL_INFOS() << "file missing, ill-formed, " "or simply undefined; not changing the" - " file" << llendl; + " file" << LL_ENDL; sHistorySD = LLSD(); return false; } @@ -77,7 +77,7 @@ bool LLURLHistory::saveFile(const std::string& filename) std::string temp_str = gDirUtilp->getLindenUserDir(true); if( temp_str.empty() ) { - llinfos << "Can't save URL history - no user directory set yet." << llendl; + LL_INFOS() << "Can't save URL history - no user directory set yet." << LL_ENDL; return false; } @@ -85,7 +85,7 @@ bool LLURLHistory::saveFile(const std::string& filename) llofstream out(temp_str); if (!out.good()) { - llwarns << "Unable to open " << filename << " for output." << llendl; + LL_WARNS() << "Unable to open " << filename << " for output." << LL_ENDL; return false; } @@ -106,39 +106,6 @@ LLSD LLURLHistory::getURLHistory(const std::string& collection) return LLSD(); } -// OGPX : static function that appends unique values to existing collection. -// returns true if appended, else false. -BOOL LLURLHistory::appendToURLCollection(const std::string& collection, const std::string& url) -{ - if (!url.empty()) - { - BOOL found_current_url = FALSE; - // make room for the new url if needed - // always append to the end and remove from the front so you have the most recent. - if (sHistorySD[collection].size() >= MAX_URL_COUNT) - { - sHistorySD[collection].erase(0); - } - - LLSD::array_iterator iter_history = sHistorySD[collection].beginArray(); - LLSD::array_iterator iter_end = sHistorySD[collection].endArray(); - for (; iter_history != iter_end; ++iter_history) - { - if ((*iter_history).asString() == url) - { - found_current_url = TRUE; - } - } - if (!found_current_url ) - { - sHistorySD[collection].append(LLSD(url)); - LLURLHistory::limitSize(collection); - //llinfos << " appending XX" << url << "XX urlcollection: " << LLSDOStreamer(sHistorySD) << llendl; - return TRUE; // value was unique, needed to be inserted - } - } - return FALSE; // value was empty or already in the collection -} // static void LLURLHistory::addURL(const std::string& collection, const std::string& url) { diff --git a/indra/newview/llurlhistory.h b/indra/newview/llurlhistory.h index 1c7e6637cb..2b9d414296 100644 --- a/indra/newview/llurlhistory.h +++ b/indra/newview/llurlhistory.h @@ -49,9 +49,6 @@ class LLURLHistory static LLSD getURLHistory(const std::string& collection); static void addURL(const std::string& collection, const std::string& url); - // OGPX appends url to a collection if it doesn't already exist in the collection. - // this is used in the collection of region URIs that are saved per region - static BOOL appendToURLCollection(const std::string& collection, const std::string& url); static void removeURL(const std::string& collection, const std::string& url); static void clear(const std::string& collection); diff --git a/indra/newview/llurlwhitelist.cpp b/indra/newview/llurlwhitelist.cpp index 46bc9276c1..03fbe8916e 100644 --- a/indra/newview/llurlwhitelist.cpp +++ b/indra/newview/llurlwhitelist.cpp @@ -123,7 +123,7 @@ bool LLUrlWhiteList::save () if (resolvedFilename.empty()) { - llinfos << "No per-user dir for saving URL whitelist - presumably not logged in yet. Skipping." << llendl; + LL_INFOS() << "No per-user dir for saving URL whitelist - presumably not logged in yet. Skipping." << LL_ENDL; return false; } diff --git a/indra/newview/lluserauth.cpp b/indra/newview/lluserauth.cpp index a0791989e2..a2f0ea9e00 100644 --- a/indra/newview/lluserauth.cpp +++ b/indra/newview/lluserauth.cpp @@ -38,9 +38,8 @@ #include #include "lldir.h" -#include "sgversion.h" +#include "llversioninfo.h" #include "llappviewer.h" -#include "llviewerbuild.h" #include "llviewercontrol.h" #include "llxmlrpcresponder.h" #include "llsdutil.h" @@ -58,16 +57,14 @@ // Don't define PLATFORM_STRING for unknown platforms - they need // to get added to the login cgi script, so we want this to cause an // error if we get compiled for a different platform. -// *FIX: This is misreporting on linux. Change this so that linux is -// in fact reporting linux. -#if LL_WINDOWS || LL_LINUX -static const char* PLATFORM_STRING = "Win"; +#if LL_WINDOWS +static const char* PLATFORM_STRING = "win"; #elif LL_DARWIN -static const char* PLATFORM_STRING = "Mac"; +static const char* PLATFORM_STRING = "mac"; #elif LL_LINUX -static const char* PLATFORM_STRING = "Lnx"; +static const char* PLATFORM_STRING = "lnx"; #elif LL_SOLARIS -static const char* PLATFORM_STRING = "Sol"; +static const char* PLATFORM_STRING = "sol"; #else #error("Unknown platform defined!") #endif @@ -107,7 +104,7 @@ void LLUserAuth::authenticate( const std::string& hashed_mac, const std::string& hashed_volume_serial) { - LL_INFOS2("AppInit", "Authentication") << "Authenticating: " << firstname << " " << lastname << ", " + LL_INFOS("AppInit", "Authentication") << "Authenticating: " << firstname << " " << lastname << ", " << /*dpasswd.c_str() <<*/ LL_ENDL; std::ostringstream option_str; option_str << "Options: "; @@ -115,7 +112,7 @@ void LLUserAuth::authenticate( std::copy(requested_options.begin(), requested_options.end(), appender); option_str << "END"; - LL_INFOS2("AppInit", "Authentication") << option_str.str() << LL_ENDL; + LL_INFOS("AppInit", "Authentication") << option_str.str() << LL_ENDL; mAuthResponse = E_NO_RESPONSE_YET; //mDownloadTimer.reset(); @@ -131,9 +128,10 @@ void LLUserAuth::authenticate( XMLRPC_VectorAppendString(params, "last", lastname.c_str(), 0); XMLRPC_VectorAppendString(params, "web_login_key", web_login_key.getString().c_str(), 0); XMLRPC_VectorAppendString(params, "start", start.c_str(), 0); - XMLRPC_VectorAppendString(params, "version", gCurrentVersion.c_str(), 0); // Includes channel name - XMLRPC_VectorAppendString(params, "channel", gVersionChannel, 0); + XMLRPC_VectorAppendString(params, "version", LLVersionInfo::getChannelAndVersion().c_str(), 0); // Includes channel name + XMLRPC_VectorAppendString(params, "channel", LLVersionInfo::getChannel().c_str(), 0); XMLRPC_VectorAppendString(params, "platform", PLATFORM_STRING, 0); + XMLRPC_VectorAppendString(params, "platform_version", LLAppViewer::instance()->getOSInfo().getOSVersionString().c_str(), 0); XMLRPC_VectorAppendString(params, "mac", hashed_mac.c_str(), 0); // A bit of security through obscurity: id0 is volume_serial @@ -169,7 +167,7 @@ void LLUserAuth::authenticate( mResponder = new XMLRPCResponder; LLHTTPClient::postXMLRPC(auth_uri, request, mResponder); - LL_INFOS2("AppInit", "Authentication") << "LLUserAuth::authenticate: uri=" << auth_uri << LL_ENDL; + LL_INFOS("AppInit", "Authentication") << "LLUserAuth::authenticate: uri=" << auth_uri << LL_ENDL; } @@ -193,7 +191,7 @@ void LLUserAuth::authenticate( { std::string dpasswd("$1$"); dpasswd.append(passwd); - LL_INFOS2("AppInit", "Authentication") << "Authenticating: " << firstname << " " << lastname << ", " + LL_INFOS("AppInit", "Authentication") << "Authenticating: " << firstname << " " << lastname << ", " << /*dpasswd.c_str() <<*/ LL_ENDL; std::ostringstream option_str; option_str << "Options: "; @@ -201,7 +199,7 @@ void LLUserAuth::authenticate( std::copy(requested_options.begin(), requested_options.end(), appender); option_str << "END"; - LL_INFOS2("AppInit", "Authentication") << option_str.str().c_str() << LL_ENDL; + LL_INFOS("AppInit", "Authentication") << option_str.str().c_str() << LL_ENDL; mAuthResponse = E_NO_RESPONSE_YET; //mDownloadTimer.reset(); @@ -217,9 +215,19 @@ void LLUserAuth::authenticate( XMLRPC_VectorAppendString(params, "last", lastname.c_str(), 0); XMLRPC_VectorAppendString(params, "passwd", dpasswd.c_str(), 0); XMLRPC_VectorAppendString(params, "start", start.c_str(), 0); - XMLRPC_VectorAppendString(params, "version", gCurrentVersion.c_str(), 0); // Includes channel name - XMLRPC_VectorAppendString(params, "channel", gVersionChannel, 0); + XMLRPC_VectorAppendString(params, "version", LLVersionInfo::getVersion().c_str(), 0); + // Singu Note: At the request of Linden Lab we change channel sent to the login server in the following way: + // * If channel is "Singularity" we change it to "Singularity Release", due to their statistics system + // not being able to distinguish just the release version + // * We append "64" to channel name on 64-bit for systems for the LL stats system to be able to produce independent + // crash statistics depending on the architecture + std::string chan(LLVersionInfo::getChannel()); +#if defined(_WIN64) || defined(__x86_64__) + chan += " 64"; +#endif + XMLRPC_VectorAppendString(params, "channel", chan.c_str(), 0); XMLRPC_VectorAppendString(params, "platform", PLATFORM_STRING, 0); + XMLRPC_VectorAppendString(params, "platform_version", LLAppViewer::instance()->getOSInfo().getOSVersionString().c_str(), 0); XMLRPC_VectorAppendString(params, "mac", hashed_mac.c_str(), 0); // A bit of security through obscurity: id0 is volume_serial @@ -258,7 +266,7 @@ void LLUserAuth::authenticate( mResponder = new XMLRPCResponder; LLHTTPClient::postXMLRPC(auth_uri, request, mResponder); - LL_INFOS2("AppInit", "Authentication") << "LLUserAuth::authenticate: uri=" << auth_uri << LL_ENDL; + LL_INFOS("AppInit", "Authentication") << "LLUserAuth::authenticate: uri=" << auth_uri << LL_ENDL; } @@ -281,10 +289,15 @@ LLUserAuth::UserAuthcode LLUserAuth::authResponse() } mLastTransferRateBPS = mResponder->transferRate(); - mErrorMessage = mResponder->reason(); + mErrorMessage = mResponder->getReason(); // if curl was ok, parse the download area. CURLcode result = mResponder->result_code(); + if (is_internal_http_error(mResponder->getStatus())) + { + // result can be a meaningless CURLE_OK in the case of an internal error. + result = CURLE_FAILED_INIT; // Just some random error to get the default case below. + } switch (result) { case CURLE_OK: @@ -307,7 +320,7 @@ LLUserAuth::UserAuthcode LLUserAuth::authResponse() break; } - LL_INFOS2("AppInit", "Authentication") << "Processed response: " << result << LL_ENDL; + LL_INFOS("AppInit", "Authentication") << "Processed response: " << result << LL_ENDL; // We're done with this data. mResponder = NULL; @@ -325,7 +338,7 @@ LLUserAuth::UserAuthcode LLUserAuth::parseResponse() XMLRPC_REQUEST response = mResponder->response(); if(!response) { - U32 status = mResponder->http_status(); + U32 status = mResponder->getStatus(); // Is it an HTTP error? if (!(200 <= status && status < 400)) { @@ -341,7 +354,7 @@ LLUserAuth::UserAuthcode LLUserAuth::parseResponse() XMLRPC_VALUE param = XMLRPC_RequestGetData(response); if (! param) { - lldebugs << "Response contains no data" << LL_ENDL; + LL_DEBUGS() << "Response contains no data" << LL_ENDL; return rv; } @@ -358,24 +371,24 @@ LLSD LLUserAuth::parseValues(UserAuthcode &auth_code, const std::string& key_pfx current = XMLRPC_VectorNext(param)) { std::string key(XMLRPC_GetValueID(current)); - lldebugs << "key: " << key_pfx << key << llendl; + LL_DEBUGS() << "key: " << key_pfx << key << LL_ENDL; XMLRPC_VALUE_TYPE_EASY type = XMLRPC_GetValueTypeEasy(current); if(xmlrpc_type_string == type) { LLSD::String val(XMLRPC_GetValueString(current)); - lldebugs << "val: " << val << llendl; + LL_DEBUGS() << "val: " << val << LL_ENDL; responses.insert(key,val); } else if(xmlrpc_type_int == type) { LLSD::Integer val(XMLRPC_GetValueInt(current)); - lldebugs << "val: " << val << llendl; + LL_DEBUGS() << "val: " << val << LL_ENDL; responses.insert(key,val); } else if (xmlrpc_type_double == type) { LLSD::Real val(XMLRPC_GetValueDouble(current)); - lldebugs << "val: " << val << llendl; + LL_DEBUGS() << "val: " << val << LL_ENDL; responses.insert(key,val); } else if(xmlrpc_type_array == type) @@ -412,7 +425,7 @@ LLSD LLUserAuth::parseValues(UserAuthcode &auth_code, const std::string& key_pfx else { // whoops - unrecognized type - llwarns << "Unhandled xmlrpc type " << type << " for key " + LL_WARNS() << "Unhandled xmlrpc type " << type << " for key " << key_pfx << key << LL_ENDL; responses.insert(key, STRINGIZE("')); auth_code = E_UNHANDLED_ERROR; diff --git a/indra/newview/llversioninfo.cpp b/indra/newview/llversioninfo.cpp new file mode 100644 index 0000000000..765f107362 --- /dev/null +++ b/indra/newview/llversioninfo.cpp @@ -0,0 +1,179 @@ +/** + * @file llversioninfo.cpp + * @brief Routines to access the viewer version and build information + * @author Martin Reddy + * + * $LicenseInfo:firstyear=2009&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include +#include +#include "llversioninfo.h" +#include + +#if ! defined(LL_VIEWER_CHANNEL) \ + || ! defined(LL_VIEWER_VERSION_MAJOR) \ + || ! defined(LL_VIEWER_VERSION_MINOR) \ + || ! defined(LL_VIEWER_VERSION_PATCH) \ + || ! defined(LL_VIEWER_VERSION_BUILD) + #error "Channel or Version information is undefined" +#endif + +// +// Set the version numbers in indra/VIEWER_VERSION +// + +//static +S32 LLVersionInfo::getMajor() +{ + return LL_VIEWER_VERSION_MAJOR; +} + +//static +S32 LLVersionInfo::getMinor() +{ + return LL_VIEWER_VERSION_MINOR; +} + +//static +S32 LLVersionInfo::getPatch() +{ + return LL_VIEWER_VERSION_PATCH; +} + +//static +S32 LLVersionInfo::getBuild() +{ + return LL_VIEWER_VERSION_BUILD; +} + +//static +const std::string &LLVersionInfo::getVersion() +{ + static std::string version(""); + if (version.empty()) + { + std::ostringstream stream; + stream << LLVersionInfo::getShortVersion() << "." << LLVersionInfo::getBuild(); + // cache the version string + version = stream.str(); + } + return version; +} + +//static +const std::string &LLVersionInfo::getShortVersion() +{ + static std::string short_version(""); + if(short_version.empty()) + { + // cache the version string + std::ostringstream stream; + stream << LL_VIEWER_VERSION_MAJOR << "." + << LL_VIEWER_VERSION_MINOR << "." + << LL_VIEWER_VERSION_PATCH; + short_version = stream.str(); + } + return short_version; +} + +namespace +{ + /// Storage of the channel name the viewer is using. + // The channel name is set by hardcoded constant, + // or by calling LLVersionInfo::resetChannel() + std::string sWorkingChannelName(LL_VIEWER_CHANNEL); + + // Storage for the "version and channel" string. + // This will get reset too. + std::string sVersionChannel(""); +} + +//static +const std::string &LLVersionInfo::getChannelAndVersion() +{ + if (sVersionChannel.empty()) + { + // cache the version string + sVersionChannel = LLVersionInfo::getChannel() + " " + LLVersionInfo::getVersion(); + } + + return sVersionChannel; +} + +//static +const std::string &LLVersionInfo::getChannel() +{ + return sWorkingChannelName; +} + +void LLVersionInfo::resetChannel(const std::string& channel) +{ + sWorkingChannelName = channel; + sVersionChannel.clear(); // Reset version and channel string til next use. +} + +//static +LLVersionInfo::ViewerMaturity LLVersionInfo::getViewerMaturity() +{ + ViewerMaturity maturity; + + std::string channel = getChannel(); + + static const boost::regex is_test_channel("\\bTest\\b"); + static const boost::regex is_alpha_channel("\\bAlpha\\b"); + static const boost::regex is_beta_channel("\\bBeta\\b"); + static const boost::regex is_project_channel("\\bProject\\b"); + static const boost::regex is_release_channel("\\bRelease\\b"); + + if (boost::regex_search(channel, is_release_channel)) + { + maturity = RELEASE_VIEWER; + } + else if (boost::regex_search(channel, is_beta_channel)) + { + maturity = BETA_VIEWER; + } + else if (boost::regex_search(channel, is_alpha_channel)) + { + maturity = ALPHA_VIEWER; + } + else if (boost::regex_search(channel, is_project_channel)) + { + maturity = PROJECT_VIEWER; + } + else if (boost::regex_search(channel, is_test_channel)) + { + maturity = TEST_VIEWER; + } + else + { + LL_WARNS() << "Channel '" << channel + << "' does not follow naming convention, assuming Test" + << LL_ENDL; + maturity = TEST_VIEWER; + } + return maturity; +} + + diff --git a/indra/newview/llversioninfo.h b/indra/newview/llversioninfo.h new file mode 100644 index 0000000000..049b6056b8 --- /dev/null +++ b/indra/newview/llversioninfo.h @@ -0,0 +1,83 @@ +/** + * @file llversioninfo.h + * @brief Routines to access the viewer version and build information + * @author Martin Reddy + * + * $LicenseInfo:firstyear=2009&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLVERSIONINFO_H +#define LL_LLVERSIONINFO_H + +#include +#include "stdtypes.h" + +/// +/// This API provides version information for the viewer. This +/// includes access to the major, minor, patch, and build integer +/// values, as well as human-readable string representations. All +/// viewer code that wants to query the current version should +/// use this API. +/// +class LLVersionInfo +{ +public: + /// return the major verion number as an integer + static S32 getMajor(); + + /// return the minor verion number as an integer + static S32 getMinor(); + + /// return the patch verion number as an integer + static S32 getPatch(); + + /// return the build number as an integer + static S32 getBuild(); + + /// return the full viewer version as a string like "2.0.0.200030" + static const std::string &getVersion(); + + /// return the viewer version as a string like "2.0.0" + static const std::string &getShortVersion(); + + /// return the viewer version and channel as a string + /// like "Second Life Release 2.0.0.200030" + static const std::string &getChannelAndVersion(); + + /// return the channel name, e.g. "Second Life" + static const std::string &getChannel(); + + /// reset the channel name used by the viewer. + static void resetChannel(const std::string& channel); + + typedef enum + { + TEST_VIEWER, + PROJECT_VIEWER, + ALPHA_VIEWER, + BETA_VIEWER, + RELEASE_VIEWER + } ViewerMaturity; + static ViewerMaturity getViewerMaturity(); +}; + +#endif diff --git a/indra/newview/llviewchildren.cpp b/indra/newview/llviewchildren.cpp index 1a66b24891..842ffc7f9a 100644 --- a/indra/newview/llviewchildren.cpp +++ b/indra/newview/llviewchildren.cpp @@ -94,10 +94,10 @@ void LLViewChildren::setBadge(const std::string& id, Badge badge, bool visible) switch (badge) { default: - case BADGE_OK: child->setImage(std::string("badge_ok.j2c")); break; - case BADGE_NOTE: child->setImage(std::string("badge_note.j2c")); break; - case BADGE_WARN: child->setImage(std::string("badge_warn.j2c")); break; - case BADGE_ERROR: child->setImage(std::string("badge_error.j2c")); break; + case BADGE_OK: child->setValue(std::string("badge_ok.j2c")); break; + case BADGE_NOTE: child->setValue(std::string("badge_note.j2c")); break; + case BADGE_WARN: child->setValue(std::string("badge_warn.j2c")); break; + case BADGE_ERROR: child->setValue(std::string("badge_error.j2c")); break; } } } diff --git a/indra/newview/llviewerassetstats.cpp b/indra/newview/llviewerassetstats.cpp index ed768eb093..7e41b4bddc 100644 --- a/indra/newview/llviewerassetstats.cpp +++ b/indra/newview/llviewerassetstats.cpp @@ -110,7 +110,7 @@ LLViewerAssetStats::PerRegionStats::reset() } mFPS.reset(); - mTotalTime = 0; + mTotalTime = U64Microseconds(0); mStartTimestamp = LLViewerAssetStatsFF::get_timestamp(); } @@ -315,9 +315,9 @@ LLViewerAssetStats::asLLSD(bool compact_output) slot[enq_tag] = LLSD(S32(stats.mRequests[i].mEnqueued.getCount())); slot[deq_tag] = LLSD(S32(stats.mRequests[i].mDequeued.getCount())); slot[rcnt_tag] = LLSD(S32(stats.mRequests[i].mResponse.getCount())); - slot[rmin_tag] = LLSD(F64(stats.mRequests[i].mResponse.getMin() * 1.0e-6)); - slot[rmax_tag] = LLSD(F64(stats.mRequests[i].mResponse.getMax() * 1.0e-6)); - slot[rmean_tag] = LLSD(F64(stats.mRequests[i].mResponse.getMean() * 1.0e-6)); + slot[rmin_tag] = LLSD(F64(stats.mRequests[i].mResponse.getMin().valueInUnits())); + slot[rmax_tag] = LLSD(F64(stats.mRequests[i].mResponse.getMax().valueInUnits())); + slot[rmean_tag] = LLSD(F64(stats.mRequests[i].mResponse.getMean().valueInUnits())); } } @@ -334,13 +334,13 @@ LLViewerAssetStats::asLLSD(bool compact_output) grid_from_region_handle(it->first, &grid_x, &grid_y); reg_stat["grid_x"] = LLSD::Integer(grid_x); reg_stat["grid_y"] = LLSD::Integer(grid_y); - reg_stat["duration"] = LLSD::Real(stats.mTotalTime * 1.0e-6); + reg_stat["duration"] = LLSD::Real(stats.mTotalTime.valueInUnits()); regions.append(reg_stat); } LLSD ret = LLSD::emptyMap(); ret["regions"] = regions; - ret["duration"] = LLSD::Real((now - mResetTimestamp) * 1.0e-6); + ret["duration"] = LLSD::Real((now - mResetTimestamp).valueInUnits()); return ret; } @@ -524,88 +524,31 @@ asset_type_to_category(const LLViewerAssetType::EType at, bool with_http, bool i // - gestures // - everything else. // - llassert_always(50 == LLViewerAssetType::AT_COUNT); // Multiple asset definitions are floating around so this requires some // maintenance and attention. - static const LLViewerAssetStats::EViewerAssetCategories asset_to_bin_map[LLViewerAssetType::AT_COUNT] = - { - LLViewerAssetStats::EVACTextureTempHTTPGet, // (0) AT_TEXTURE - LLViewerAssetStats::EVACSoundUDPGet, // AT_SOUND - LLViewerAssetStats::EVACOtherGet, // AT_CALLINGCARD - LLViewerAssetStats::EVACOtherGet, // AT_LANDMARK - LLViewerAssetStats::EVACOtherGet, // AT_SCRIPT - LLViewerAssetStats::EVACWearableUDPGet, // AT_CLOTHING - LLViewerAssetStats::EVACOtherGet, // AT_OBJECT - LLViewerAssetStats::EVACOtherGet, // AT_NOTECARD - LLViewerAssetStats::EVACOtherGet, // AT_CATEGORY - LLViewerAssetStats::EVACOtherGet, // AT_ROOT_CATEGORY - LLViewerAssetStats::EVACOtherGet, // (10) AT_LSL_TEXT - LLViewerAssetStats::EVACOtherGet, // AT_LSL_BYTECODE - LLViewerAssetStats::EVACOtherGet, // AT_TEXTURE_TGA - LLViewerAssetStats::EVACWearableUDPGet, // AT_BODYPART - LLViewerAssetStats::EVACOtherGet, // AT_TRASH - LLViewerAssetStats::EVACOtherGet, // AT_SNAPSHOT_CATEGORY - LLViewerAssetStats::EVACOtherGet, // AT_LOST_AND_FOUND - LLViewerAssetStats::EVACSoundUDPGet, // AT_SOUND_WAV - LLViewerAssetStats::EVACOtherGet, // AT_IMAGE_TGA - LLViewerAssetStats::EVACOtherGet, // AT_IMAGE_JPEG - LLViewerAssetStats::EVACGestureUDPGet, // (20) AT_ANIMATION - LLViewerAssetStats::EVACGestureUDPGet, // AT_GESTURE - LLViewerAssetStats::EVACOtherGet, // AT_SIMSTATE - LLViewerAssetStats::EVACOtherGet, // AT_FAVORITE - LLViewerAssetStats::EVACOtherGet, // AT_LINK - LLViewerAssetStats::EVACOtherGet, // AT_LINK_FOLDER - LLViewerAssetStats::EVACOtherGet, // - LLViewerAssetStats::EVACOtherGet, // - LLViewerAssetStats::EVACOtherGet, // - LLViewerAssetStats::EVACOtherGet, // - LLViewerAssetStats::EVACOtherGet, // (30) - LLViewerAssetStats::EVACOtherGet, // - LLViewerAssetStats::EVACOtherGet, // - LLViewerAssetStats::EVACOtherGet, // - LLViewerAssetStats::EVACOtherGet, // - LLViewerAssetStats::EVACOtherGet, // - LLViewerAssetStats::EVACOtherGet, // - LLViewerAssetStats::EVACOtherGet, // - LLViewerAssetStats::EVACOtherGet, // - LLViewerAssetStats::EVACOtherGet, // - LLViewerAssetStats::EVACOtherGet, // (40) - LLViewerAssetStats::EVACOtherGet, // - LLViewerAssetStats::EVACOtherGet, // - LLViewerAssetStats::EVACOtherGet, // - LLViewerAssetStats::EVACOtherGet, // - LLViewerAssetStats::EVACOtherGet, // - LLViewerAssetStats::EVACOtherGet, // - LLViewerAssetStats::EVACOtherGet, // - LLViewerAssetStats::EVACOtherGet, // - LLViewerAssetStats::EVACOtherGet, // AT_MESH - // (50) - }; - - if (at < 0 || at >= LLViewerAssetType::AT_COUNT) + switch (at) { + case LLAssetType::AT_TEXTURE: + return is_temp ? with_http ? LLViewerAssetStats::EVACTextureTempHTTPGet : LLViewerAssetStats::EVACTextureTempUDPGet + : with_http ? LLViewerAssetStats::EVACTextureTempHTTPGet : LLViewerAssetStats::EVACTextureNonTempUDPGet; + break; + case LLAssetType::AT_SOUND: + case LLAssetType::AT_SOUND_WAV: + return LLViewerAssetStats::EVACSoundUDPGet; + break; + case LLAssetType::AT_CLOTHING: + case LLAssetType::AT_BODYPART: + return LLViewerAssetStats::EVACWearableUDPGet; + break; + case LLAssetType::AT_ANIMATION: + case LLAssetType::AT_GESTURE: + return LLViewerAssetStats::EVACGestureUDPGet; + break; + case LLAssetType::AT_LANDMARK: + default: return LLViewerAssetStats::EVACOtherGet; + break; } - LLViewerAssetStats::EViewerAssetCategories ret(asset_to_bin_map[at]); - if (LLViewerAssetStats::EVACTextureTempHTTPGet == ret) - { - // Indexed with [is_temp][with_http] - static const LLViewerAssetStats::EViewerAssetCategories texture_bin_map[2][2] = - { - { - LLViewerAssetStats::EVACTextureNonTempUDPGet, - LLViewerAssetStats::EVACTextureNonTempHTTPGet, - }, - { - LLViewerAssetStats::EVACTextureTempUDPGet, - LLViewerAssetStats::EVACTextureTempHTTPGet, - } - }; - - ret = texture_bin_map[is_temp][with_http]; - } - return ret; } - } // anonymous namespace diff --git a/indra/newview/llviewerassetstats.h b/indra/newview/llviewerassetstats.h index 3381c01ed5..a1091daa1f 100644 --- a/indra/newview/llviewerassetstats.h +++ b/indra/newview/llviewerassetstats.h @@ -94,7 +94,7 @@ class LLViewerAssetStats * for compatibility with the pre-existing timestamp on the texture * fetcher class, LLTextureFetch. */ - typedef U64 duration_t; +typedef U64Microseconds duration_t; /** * Type for the region identifier used in stats. Currently uses diff --git a/indra/newview/llviewerassetstorage.cpp b/indra/newview/llviewerassetstorage.cpp index b0e9593acb..7b6a6dd0cc 100644 --- a/indra/newview/llviewerassetstorage.cpp +++ b/indra/newview/llviewerassetstorage.cpp @@ -33,9 +33,12 @@ #include "message.h" #include "llagent.h" +#include "llviewerregion.h" + #include "lltransfersourceasset.h" #include "lltransfertargetvfile.h" #include "llviewerassetstats.h" +#include "llworld.h" ///---------------------------------------------------------------------------- /// LLViewerAssetRequest @@ -51,9 +54,10 @@ class LLViewerAssetRequest : public LLAssetRequest { public: - LLViewerAssetRequest(const LLUUID &uuid, const LLAssetType::EType type) + LLViewerAssetRequest(const LLUUID &uuid, const LLAssetType::EType type, bool with_http) : LLAssetRequest(uuid, type), - mMetricsStartTime(0) + mMetricsStartTime(0), + mWithHTTP(with_http) { } @@ -66,23 +70,30 @@ class LLViewerAssetRequest : public LLAssetRequest recordMetrics(); } + LLBaseDownloadRequest* getCopy() + { + return new LLViewerAssetRequest(*this); + } + bool operator==(const LLViewerAssetRequest& rhs) const { return mUUID == rhs.mUUID && mType == rhs.mType && mWithHTTP == rhs.mWithHTTP; } + protected: void recordMetrics() { - if (mMetricsStartTime) + if (mMetricsStartTime.value()) { // Okay, it appears this request was used for useful things. Record // the expected dequeue and duration of request processing. - LLViewerAssetStatsFF::record_dequeue_main(mType, false, false); - LLViewerAssetStatsFF::record_response_main(mType, false, false, + LLViewerAssetStatsFF::record_dequeue_main(mType, mWithHTTP, false); + LLViewerAssetStatsFF::record_response_main(mType, mWithHTTP, false, (LLViewerAssetStatsFF::get_timestamp() - mMetricsStartTime)); - mMetricsStartTime = 0; + mMetricsStartTime = (U32Seconds)0; } } public: LLViewerAssetStats::duration_t mMetricsStartTime; + bool mWithHTTP; }; ///---------------------------------------------------------------------------- @@ -113,11 +124,11 @@ void LLViewerAssetStorage::storeAssetData( bool is_priority, bool store_local, bool user_waiting, - F64 timeout) + F64Seconds timeout) { LLAssetID asset_id = tid.makeAssetID(gAgent.getSecureSessionID()); LL_DEBUGS("AssetStorage") << "LLViewerAssetStorage::storeAssetData (legacy) " << tid << ":" << LLAssetType::lookup(asset_type) - << " ASSET_ID: " << asset_id << llendl; + << " ASSET_ID: " << asset_id << LL_ENDL; if (mUpstreamHost.isOk()) { @@ -130,7 +141,6 @@ void LLViewerAssetStorage::storeAssetData( LLVFile vfile(mVFS, asset_id, asset_type, LLVFile::READ); S32 asset_size = vfile.getSize(); - LLAssetRequest *req = new LLAssetRequest(asset_id, asset_type); req->mUpCallback = callback; req->mUserData = user_data; @@ -138,7 +148,7 @@ void LLViewerAssetStorage::storeAssetData( if (asset_size < 1) { // This can happen if there's a bug in our code or if the VFS has been corrupted. - llwarns << "LLViewerAssetStorage::storeAssetData() Data _should_ already be in the VFS, but it's not! " << asset_id << llendl; + LL_WARNS("AssetStorage") << "LLViewerAssetStorage::storeAssetData() Data _should_ already be in the VFS, but it's not! " << asset_id << LL_ENDL; // LLAssetStorage metric: Zero size VFS reportMetric( asset_id, asset_type, LLStringUtil::null, LLUUID::null, 0, MR_ZERO_SIZE, __FILE__, __LINE__, "The file didn't exist or was zero length (VFS - can't tell which)" ); @@ -175,11 +185,11 @@ void LLViewerAssetStorage::storeAssetData( if( bytes_read == asset_size ) { req->mDataSentInFirstPacket = TRUE; - //llinfos << "LLViewerAssetStorage::createAsset sending data in first packet" << llendl; + //LL_INFOS() << "LLViewerAssetStorage::createAsset sending data in first packet" << LL_ENDL; } else { - llwarns << "Probable corruption in VFS file, aborting store asset data" << llendl; + LL_WARNS("AssetStorage") << "Probable corruption in VFS file, aborting store asset data" << LL_ENDL; // LLAssetStorage metric: VFS corrupt - bogus size reportMetric( asset_id, asset_type, LLStringUtil::null, LLUUID::null, asset_size, MR_VFS_CORRUPTION, __FILE__, __LINE__, "VFS corruption" ); @@ -208,7 +218,7 @@ void LLViewerAssetStorage::storeAssetData( } else { - llwarns << "AssetStorage: attempt to upload non-existent vfile " << asset_id << ":" << LLAssetType::lookup(asset_type) << llendl; + LL_WARNS("AssetStorage") << "AssetStorage: attempt to upload non-existent vfile " << asset_id << ":" << LLAssetType::lookup(asset_type) << LL_ENDL; // LLAssetStorage metric: Zero size VFS reportMetric( asset_id, asset_type, LLStringUtil::null, LLUUID::null, 0, MR_ZERO_SIZE, __FILE__, __LINE__, "The file didn't exist or was zero length (VFS - can't tell which)" ); if (callback) @@ -219,7 +229,7 @@ void LLViewerAssetStorage::storeAssetData( } else { - llwarns << "Attempt to move asset store request upstream w/o valid upstream provider" << llendl; + LL_WARNS("AssetStorage") << "Attempt to move asset store request upstream w/o valid upstream provider" << LL_ENDL; // LLAssetStorage metric: Upstream provider dead reportMetric( asset_id, asset_type, LLStringUtil::null, LLUUID::null, 0, MR_NO_UPSTREAM, __FILE__, __LINE__, "No upstream provider" ); if (callback) @@ -238,20 +248,20 @@ void LLViewerAssetStorage::storeAssetData( bool temp_file, bool is_priority, bool user_waiting, - F64 timeout) + F64Seconds timeout) { if(filename.empty()) { // LLAssetStorage metric: no filename reportMetric( LLUUID::null, asset_type, LLStringUtil::null, LLUUID::null, 0, MR_VFS_CORRUPTION, __FILE__, __LINE__, "Filename missing" ); - llerrs << "No filename specified" << llendl; + LL_ERRS() << "No filename specified" << LL_ENDL; return; } LLAssetID asset_id = tid.makeAssetID(gAgent.getSecureSessionID()); - LL_DEBUGS("AssetStorage") << "LLViewerAssetStorage::storeAssetData (legacy)" << asset_id << ":" << LLAssetType::lookup(asset_type) << llendl; + LL_DEBUGS("AssetStorage") << "LLViewerAssetStorage::storeAssetData (legacy)" << asset_id << ":" << LLAssetType::lookup(asset_type) << LL_ENDL; - LL_DEBUGS("AssetStorage") << "ASSET_ID: " << asset_id << llendl; + LL_DEBUGS("AssetStorage") << "ASSET_ID: " << asset_id << LL_ENDL; S32 size = 0; LLFILE* fp = LLFile::fopen(filename, "rb"); @@ -302,6 +312,7 @@ void LLViewerAssetStorage::storeAssetData( { // LLAssetStorage metric: Zero size reportMetric( asset_id, asset_type, filename, LLUUID::null, 0, MR_ZERO_SIZE, __FILE__, __LINE__, "The file was zero length" ); + fclose(fp); } else { @@ -342,10 +353,24 @@ void LLViewerAssetStorage::_queueDataRequest( BOOL duplicate, BOOL is_priority) { + queueRequestUDP(uuid, atype, callback, user_data, duplicate, is_priority); +} +void LLViewerAssetStorage::queueRequestUDP( + const LLUUID& uuid, + LLAssetType::EType atype, + LLGetAssetCallback callback, + void *user_data, + BOOL duplicate, + BOOL is_priority) +{ + LL_DEBUGS("ViewerAsset") << "Request asset via HTTP " << uuid << " type " << LLAssetType::lookup(atype) << LL_ENDL; + if (mUpstreamHost.isOk()) { - // stash the callback info so we can find it after we get the response message - LLViewerAssetRequest *req = new LLViewerAssetRequest(uuid, atype); + const auto region = gAgent.getRegion(); + // Fallback on UDP if we have no cap or haven't received caps. This means missing some UDP-only region assets before caps received, but that's better for HTTP only. + bool with_http = !region || !region->capabilitiesReceived() || !region->getViewerAssetUrl().empty(); + LLViewerAssetRequest *req = new LLViewerAssetRequest(uuid, atype, with_http); req->mDownCallback = callback; req->mUserData = user_data; req->mIsPriority = is_priority; @@ -355,32 +380,39 @@ void LLViewerAssetStorage::_queueDataRequest( // are piggy-backing and will artificially lower averages. req->mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp(); } - mPendingDownloads.push_back(req); + // This is the same as the current UDP logic - don't re-request a duplicate. if (!duplicate) { - // send request message to our upstream data provider - // Create a new asset transfer. - LLTransferSourceParamsAsset spa; - spa.setAsset(uuid, atype); - - // Set our destination file, and the completion callback. - LLTransferTargetParamsVFile tpvf; - tpvf.setAsset(uuid, atype); - tpvf.setCallback(downloadCompleteCallback, req); - - LL_DEBUGS("AssetStorage") << "Starting transfer for " << uuid << llendl; - LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(mUpstreamHost, LLTCT_ASSET); - ttcp->requestTransfer(spa, tpvf, 100.f + (is_priority ? 1.f : 0.f)); - - LLViewerAssetStatsFF::record_enqueue_main(atype, false, false); + bool is_temp = false; + LLViewerAssetStatsFF::record_enqueue_main(atype, with_http, is_temp); + if (!with_http) // maintain this code for older grids + { + // send request message to our upstream data provider + // Create a new asset transfer. + LLTransferSourceParamsAsset spa; + spa.setAsset(uuid, atype); + + // Set our destination file, and the completion callback. + LLTransferTargetParamsVFile tpvf; + tpvf.setAsset(uuid, atype); + tpvf.setCallback(downloadCompleteCallback, *req); + + LL_DEBUGS("AssetStorage") << "Starting transfer for " << uuid << LL_ENDL; + LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(mUpstreamHost, LLTCT_ASSET); + ttcp->requestTransfer(spa, tpvf, 100.f + (is_priority ? 1.f : 0.f)); + } + else + { + LLViewerAssetStorage::assetRequestCoro(req, uuid, atype, callback, user_data); + } } } else { // uh-oh, we shouldn't have gotten here - llwarns << "Attempt to move asset data request upstream w/o valid upstream provider" << llendl; + LL_WARNS() << "Attempt to move asset data request upstream w/o valid upstream provider" << LL_ENDL; if (callback) { callback(mVFS, uuid, atype, user_data, LL_ERR_CIRCUIT_GONE, LL_EXSTAT_NO_UPSTREAM); @@ -388,3 +420,138 @@ void LLViewerAssetStorage::_queueDataRequest( } } +extern AIHTTPTimeoutPolicy HTTPGetResponder_timeout; +class LLViewerAssetResponder : public LLHTTPClient::ResponderWithCompleted +{ +public: + LLViewerAssetResponder(const LLUUID& id, LLAssetType::EType type) : LLHTTPClient::ResponderWithCompleted() + , uuid(id), atype(type) + {} +private: + LLUUID uuid; + LLAssetType::EType atype; + + void completedRaw(LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) override + { + if (LLApp::isQuitting()) + { + // Bail out if result arrives after shutdown has been started. + return; + } + + LL_DEBUGS("ViewerAsset") << "request succeeded, url " << mURL << LL_ENDL; + + S32 result_code = LL_ERR_NOERR; + LLExtStat ext_status = LL_EXSTAT_NONE; + + if (!isGoodStatus(mStatus)) + { + LL_DEBUGS("ViewerAsset") << "request failed, status " << mStatus << LL_ENDL; + result_code = LL_ERR_ASSET_REQUEST_FAILED; + ext_status = LL_EXSTAT_NONE; + } + else + { + std::string raw; + decode_raw_body(channels, buffer, raw); + + S32 size = raw.size(); + if (size > 0) + { + // This create-then-rename flow is modeled on + // LLTransferTargetVFile, which is what was used in the UDP + // case. + LLUUID temp_id; + temp_id.generate(); + LLVFile vf(gAssetStorage->mVFS, temp_id, atype, LLVFile::WRITE); + vf.setMaxSize(size); + if (!vf.write((const U8*)raw.data(), size)) + { + // TODO asset-http: handle error + LL_WARNS("ViewerAsset") << "Failure in vf.write()" << LL_ENDL; + result_code = LL_ERR_ASSET_REQUEST_FAILED; + ext_status = LL_EXSTAT_VFS_CORRUPT; + } + else if (!vf.rename(uuid, atype)) + { + LL_WARNS("ViewerAsset") << "rename failed" << LL_ENDL; + result_code = LL_ERR_ASSET_REQUEST_FAILED; + ext_status = LL_EXSTAT_VFS_CORRUPT; + } + } + else + { + // TODO asset-http: handle invalid size case + LL_WARNS("ViewerAsset") << "bad size" << LL_ENDL; + result_code = LL_ERR_ASSET_REQUEST_FAILED; + ext_status = LL_EXSTAT_NONE; + } + } + + // Clean up pending downloads and trigger callbacks + gAssetStorage->removeAndCallbackPendingDownloads(uuid, atype, uuid, atype, result_code, ext_status); + } + AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy() const override { return HTTPGetResponder_timeout; } + char const* getName() const override { return "assetRequestCoro"; } +}; + +void LLViewerAssetStorage::capsRecvForRegion(const LLUUID& uuid, LLAssetType::EType atype, const LLUUID& region_id) +{ + LLViewerRegion *regionp = LLWorld::instance().getRegionFromID(region_id); + if (!regionp) + { + LL_WARNS("ViewerAsset") << "region not found for region_id " << region_id << LL_ENDL; + } + else + { + mViewerAssetUrl = regionp->getViewerAssetUrl(); + } + + LL_WARNS_ONCE("ViewerAsset") << "capsRecv got event" << LL_ENDL; + LL_WARNS_ONCE("ViewerAsset") << "region " << gAgent.getRegion() << " mViewerAssetUrl " << mViewerAssetUrl << LL_ENDL; + if (mViewerAssetUrl.empty()) + { + LL_WARNS_ONCE("ViewerAsset") << "asset request fails: caps received but no viewer asset cap found" << LL_ENDL; + auto result_code = LL_ERR_ASSET_REQUEST_FAILED; + auto ext_status = LL_EXSTAT_NONE; + removeAndCallbackPendingDownloads(uuid, atype, uuid, atype, result_code, ext_status); + return; + } + std::string url = getAssetURL(mViewerAssetUrl, uuid,atype); + LL_DEBUGS("ViewerAsset") << "request url: " << url << LL_ENDL; + + LLHTTPClient::get(url, new LLViewerAssetResponder(uuid, atype)); +} + +void LLViewerAssetStorage::assetRequestCoro( + LLViewerAssetRequest *req, + const LLUUID uuid, + LLAssetType::EType atype, + LLGetAssetCallback callback, + void *user_data) +{ + if (!gAgent.getRegion()) + { + LL_WARNS_ONCE("ViewerAsset") << "Asset request fails: no region set" << LL_ENDL; + auto result_code = LL_ERR_ASSET_REQUEST_FAILED; + auto ext_status = LL_EXSTAT_NONE; + removeAndCallbackPendingDownloads(uuid, atype, uuid, atype, result_code, ext_status); + return; + } + else if (!gAgent.getRegion()->capabilitiesReceived()) + { + LL_WARNS_ONCE("ViewerAsset") << "Waiting for capabilities" << LL_ENDL; + + gAgent.getRegion()->setCapabilitiesReceivedCallback( + boost::bind(&LLViewerAssetStorage::capsRecvForRegion, this, uuid, atype, _1)); + } + else capsRecvForRegion(uuid, atype, gAgent.getRegion()->getRegionID()); +} + +std::string LLViewerAssetStorage::getAssetURL(const std::string& cap_url, const LLUUID& uuid, LLAssetType::EType atype) +{ + std::string type_name = LLAssetType::lookup(atype); + std::string url = cap_url + "/?" + type_name + "_id=" + uuid.asString(); + return url; +} + diff --git a/indra/newview/llviewerassetstorage.h b/indra/newview/llviewerassetstorage.h index ca9b9943fa..75b2d87666 100644 --- a/indra/newview/llviewerassetstorage.h +++ b/indra/newview/llviewerassetstorage.h @@ -32,6 +32,8 @@ class LLVFile; +class LLViewerAssetRequest; + class LLViewerAssetStorage : public LLAssetStorage { public: @@ -41,7 +43,6 @@ class LLViewerAssetStorage : public LLAssetStorage LLViewerAssetStorage(LLMessageSystem *msg, LLXferManager *xfer, LLVFS *vfs, LLVFS *static_vfs); - using LLAssetStorage::storeAssetData; virtual void storeAssetData( const LLTransactionID& tid, LLAssetType::EType atype, @@ -51,7 +52,7 @@ class LLViewerAssetStorage : public LLAssetStorage bool is_priority = false, bool store_local = false, bool user_waiting=FALSE, - F64 timeout=LL_ASSET_STORAGE_TIMEOUT); + F64Seconds timeout=LL_ASSET_STORAGE_TIMEOUT); virtual void storeAssetData( const std::string& filename, @@ -62,18 +63,35 @@ class LLViewerAssetStorage : public LLAssetStorage bool temp_file = false, bool is_priority = false, bool user_waiting=FALSE, - F64 timeout=LL_ASSET_STORAGE_TIMEOUT); + F64Seconds timeout=LL_ASSET_STORAGE_TIMEOUT); protected: - using LLAssetStorage::_queueDataRequest; - // virtual void _queueDataRequest(const LLUUID& uuid, LLAssetType::EType type, - void (*callback) (LLVFS *vfs, const LLUUID&, LLAssetType::EType, void *, S32, LLExtStat), + LLGetAssetCallback callback, void *user_data, BOOL duplicate, BOOL is_priority); + + void queueRequestUDP(const LLUUID& uuid, + LLAssetType::EType type, + LLGetAssetCallback callback, + void *user_data, + BOOL duplicate, + BOOL is_priority); + + void capsRecvForRegion(const LLUUID& uuid, LLAssetType::EType atype, const LLUUID& region_id); + + void assetRequestCoro(LLViewerAssetRequest *req, + const LLUUID uuid, + LLAssetType::EType atype, + LLGetAssetCallback callback, + void *user_data); + + std::string getAssetURL(const std::string& cap_url, const LLUUID& uuid, LLAssetType::EType atype); + + std::string mViewerAssetUrl; }; #endif diff --git a/indra/newview/llviewerassettype.cpp b/indra/newview/llviewerassettype.cpp index 3eee608820..b98767b1b9 100644 --- a/indra/newview/llviewerassettype.cpp +++ b/indra/newview/llviewerassettype.cpp @@ -88,7 +88,10 @@ LLViewerAssetDictionary::LLViewerAssetDictionary() addEntry(LLViewerAssetType::AT_MESH, new ViewerAssetEntry(DAD_MESH)); + addEntry(LLViewerAssetType::AT_UNKNOWN, new ViewerAssetEntry(DAD_NONE)); + addEntry(LLViewerAssetType::AT_NONE, new ViewerAssetEntry(DAD_NONE)); + addEntry(LLViewerAssetType::AT_SETTINGS, new ViewerAssetEntry(DAD_NONE)); }; EDragAndDropType LLViewerAssetType::lookupDragAndDropType(EType asset_type) diff --git a/indra/newview/llvieweraudio.cpp b/indra/newview/llvieweraudio.cpp index fd8915e842..603150f99e 100644 --- a/indra/newview/llvieweraudio.cpp +++ b/indra/newview/llvieweraudio.cpp @@ -46,28 +46,15 @@ ///////////////////////////////////////////////////////// -void init_audio() +void precache_audio() { - if (!gAudiop) - { - llwarns << "Failed to create an appropriate Audio Engine" << llendl; + static bool already_precached = false; + if(already_precached) return; - } - LLVector3d lpos_global = gAgentCamera.getCameraPositionGlobal(); - LLVector3 lpos_global_f; - - lpos_global_f.setVec(lpos_global); - - gAudiop->setListener(lpos_global_f, - LLVector3::zero, // LLViewerCamera::getInstance()->getVelocity(), // !!! BUG need to replace this with smoothed velocity! - LLViewerCamera::getInstance()->getUpAxis(), - LLViewerCamera::getInstance()->getAtAxis()); - -// load up our initial set of sounds we'll want so they're in memory and ready to be played + already_precached = true; - BOOL mute_audio = gSavedSettings.getBOOL("MuteAudio"); - - if (!mute_audio && FALSE == gSavedSettings.getBOOL("NoPreload")) + // load up our initial set of sounds we'll want so they're in memory and ready to be played + if (gAudiop && !gSavedSettings.getBOOL("MuteAudio") && !gSavedSettings.getBOOL("NoPreload")) { gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndAlert"))); gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndBadKeystroke"))); @@ -109,12 +96,11 @@ void init_audio() gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndTyping"))); gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndWindowClose"))); gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndWindowOpen"))); + gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndRestart"))); } - - audio_update_volume(true); } -void audio_update_volume(bool force_update) +void audio_update_volume( bool wind_fade ) { static const LLCachedControl master_volume("AudioLevelMaster",1.0); static const LLCachedControl audio_level_sfx("AudioLevelSFX",1.0); @@ -154,11 +140,6 @@ void audio_update_volume(bool force_update) gAudiop->setRolloffFactor( audio_level_underwater_rolloff ); gAudiop->setMuted(mute_audio); - - if (force_update) - { - audio_update_wind(true); - } // handle secondary gains gAudiop->setSecondaryGain(LLAudioEngine::AUDIO_TYPE_SFX, @@ -167,6 +148,8 @@ void audio_update_volume(bool force_update) mute_ui ? 0.f : audio_level_ui); gAudiop->setSecondaryGain(LLAudioEngine::AUDIO_TYPE_AMBIENT, mute_ambient ? 0.f : audio_level_ambient); + + audio_update_wind(wind_fade); } // Streaming Music @@ -217,17 +200,23 @@ void audio_update_listener() } } -void audio_update_wind(bool force_update) +void audio_update_wind(bool fade) { #ifdef kAUDIO_ENABLE_WIND - if(gAgent.getRegion()) + if(gAgent.getRegion() && gAudiop) { // Scale down the contribution of weather-simulation wind to the // ambient wind noise. Wind velocity averages 3.5 m/s, with gusts to 7 m/s // whereas steady-state avatar walk velocity is only 3.2 m/s. // Without this the world feels desolate on first login when you are // standing still. - static LLCachedControl wind_level("AudioLevelWind", 0.5f); + + static LLCachedControl wind_level("AudioLevelWind", 0.5f); + static LLCachedControl mute_audio("MuteAudio", false); + static LLCachedControl mute_ambient("MuteAmbient", false); + static LLCachedControl audio_level_master("AudioLevelMaster", 1.f); + static LLCachedControl audio_level_ambient("AudioLevelAmbient", 1.f); + LLVector3 scaled_wind_vec = gWindVec * wind_level; // Mix in the avatar's motion, subtract because when you walk north, @@ -240,30 +229,29 @@ void audio_update_wind(bool force_update) // don't use the setter setMaxWindGain() because we don't // want to screw up the fade-in on startup by setting actual source gain // outside the fade-in. - F32 master_volume = gSavedSettings.getBOOL("MuteAudio") ? 0.f : gSavedSettings.getF32("AudioLevelMaster"); - F32 ambient_volume = gSavedSettings.getBOOL("MuteAmbient") ? 0.f : gSavedSettings.getF32("AudioLevelAmbient"); + F32 master_volume = mute_audio ? 0.f : audio_level_master; + F32 ambient_volume = mute_ambient ? 0.f : audio_level_ambient; F32 max_wind_volume = master_volume * ambient_volume; const F32 WIND_SOUND_TRANSITION_TIME = 2.f; - // amount to change volume this frame - F32 volume_delta = (LLFrameTimer::getFrameDeltaTimeF32() / WIND_SOUND_TRANSITION_TIME) * max_wind_volume; - if (force_update) + + F32 volume_delta = 1.f; + + if(fade) { - // initialize wind volume (force_update) by using large volume_delta - // which is sufficient to completely turn off or turn on wind noise - volume_delta = 1.f; + // amount to change volume this frame + volume_delta = (LLFrameTimer::getFrameDeltaTimeF32() / WIND_SOUND_TRANSITION_TIME) * max_wind_volume; } - static LLCachedControl MuteWind("MuteWind"); - static LLCachedControl ContinueFlying("LiruContinueFlyingOnUnsit"); - // mute wind entirely when the user asked or when the user is seated, but flying - if (MuteWind || (ContinueFlying && gAgentAvatarp&& gAgentAvatarp->isSitting())) + static LLCachedControl MuteWind(gSavedSettings, "MuteWind", false); + static LLCachedControl ContinueFlying(gSavedSettings, "LiruContinueFlyingOnUnsit", false); + // mute wind entirely when the user asked or when the user is seated, but flying or just when the user is under water + if (!gAgentAvatarp || MuteWind || (ContinueFlying && gAgentAvatarp->isSitting()) || gAgentAvatarp->mBelowWater) { - // volume decreases by itself gAudiop->mMaxWindGain = 0.f; } // mute wind when not /*flying*/ in air - else if /*(gAgent.getFlying())*/ (gAgentAvatarp && gAgentAvatarp->mInAir) + else if (/*gAgent.getFlying()*/gAgentAvatarp->mInAir) { // volume increases by volume_delta, up to no more than max_wind_volume gAudiop->mMaxWindGain = llmin(gAudiop->mMaxWindGain + volume_delta, max_wind_volume); diff --git a/indra/newview/llvieweraudio.h b/indra/newview/llvieweraudio.h index a80f030479..7e08024c1a 100644 --- a/indra/newview/llvieweraudio.h +++ b/indra/newview/llvieweraudio.h @@ -39,9 +39,9 @@ #define kAUDIO_NUM_BUFFERS 30 #define kAUDIO_NUM_SOURCES 30 -void init_audio(); -void audio_update_volume(bool force_update = true); +void precache_audio(); +void audio_update_volume(bool wind_fade = true); void audio_update_listener(); -void audio_update_wind(bool force_update = true); +void audio_update_wind(bool fade); #endif //LL_VIEWER_H diff --git a/indra/newview/llviewerbuild.h b/indra/newview/llviewerbuild.h deleted file mode 100644 index b02bdece5b..0000000000 --- a/indra/newview/llviewerbuild.h +++ /dev/null @@ -1,37 +0,0 @@ -/** - * @file llviewerbuild.h - * @brief Sets viewer build number - * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#include "sgversion.h" - -// Set the build number in indra/llcommon/llversionviewer.h! - -const S32 LL_VIEWER_BUILD = gVersionBuild; diff --git a/indra/newview/llviewercamera.cpp b/indra/newview/llviewercamera.cpp index 9266dc434b..92f6421a76 100644 --- a/indra/newview/llviewercamera.cpp +++ b/indra/newview/llviewercamera.cpp @@ -2,41 +2,34 @@ * @file llviewercamera.cpp * @brief LLViewerCamera class implementation * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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 "llviewercamera.h" - #include "llagent.h" #include "llagentcamera.h" -#include "llmatrix4a.h" + #include "llviewercontrol.h" #include "llviewerobjectlist.h" #include "llviewerregion.h" @@ -60,59 +53,13 @@ // System includes #include // for setprecision -U32 LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD; - -//glu pick matrix implementation borrowed from Mesa3D -glh::matrix4f gl_pick_matrix(GLfloat x, GLfloat y, GLfloat width, GLfloat height, GLint* viewport) -{ - GLfloat m[16]; - GLfloat sx, sy; - GLfloat tx, ty; - - sx = viewport[2] / width; - sy = viewport[3] / height; - tx = (viewport[2] + 2.f * (viewport[0] - x)) / width; - ty = (viewport[3] + 2.f * (viewport[1] - y)) / height; - - #define M(row,col) m[col*4+row] - M(0,0) = sx; M(0,1) = 0.f; M(0,2) = 0.f; M(0,3) = tx; - M(1,0) = 0.f; M(1,1) = sy; M(1,2) = 0.f; M(1,3) = ty; - M(2,0) = 0.f; M(2,1) = 0.f; M(2,2) = 1.f; M(2,3) = 0.f; - M(3,0) = 0.f; M(3,1) = 0.f; M(3,2) = 0.f; M(3,3) = 1.f; - #undef M - - return glh::matrix4f(m); -} - -glh::matrix4f gl_perspective(GLfloat fovy, GLfloat aspect, GLfloat zNear, GLfloat zFar) -{ - GLfloat f = 1.f/tanf(DEG_TO_RAD*fovy/2.f); - - return glh::matrix4f(f/aspect, 0, 0, 0, - 0, f, 0, 0, - 0, 0, (zFar+zNear)/(zNear-zFar), (2.f*zFar*zNear)/(zNear-zFar), - 0, 0, -1.f, 0); -} - -glh::matrix4f gl_lookat(LLVector3 eye, LLVector3 center, LLVector3 up) -{ - LLVector3 f = center-eye; - f.normVec(); - up.normVec(); - LLVector3 s = f % up; - LLVector3 u = s % f; - - return glh::matrix4f(s[0], s[1], s[2], 0, - u[0], u[1], u[2], 0, - -f[0], -f[1], -f[2], 0, - 0, 0, 0, 1); - -} +LLViewerCamera::eCameraID LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD; LLViewerCamera::LLViewerCamera() : LLCamera() { calcProjection(getFar()); mCameraFOVDefault = DEFAULT_FIELD_OF_VIEW; + mSavedFOVDefault = DEFAULT_FIELD_OF_VIEW; // mCosHalfCameraFOV = cosf(mCameraFOVDefault * 0.5f); mPixelMeterRatio = 0.f; mScreenPixelArea = 0; @@ -177,37 +124,26 @@ void LLViewerCamera::updateCameraLocation(const LLVector3 ¢er, mScreenPixelArea =(S32)((F32)getViewHeightInPixels() * ((F32)getViewHeightInPixels() * getAspect())); } -const LLMatrix4 &LLViewerCamera::getProjection() const +const LLMatrix4a &LLViewerCamera::getProjection() const { calcProjection(getFar()); return mProjectionMatrix; } -const LLMatrix4 &LLViewerCamera::getModelview() const +const LLMatrix4a &LLViewerCamera::getModelview() const { - LLMatrix4 cfr(OGL_TO_CFR_ROTATION); - getMatrixToLocal(mModelviewMatrix); - mModelviewMatrix *= cfr; + LLMatrix4 modelview; + getMatrixToLocal(modelview); + LLMatrix4a modelviewa; + modelviewa.loadu((F32*)modelview.mMatrix); + mModelviewMatrix.setMul(OGL_TO_CFR_ROTATION,modelviewa); return mModelviewMatrix; } void LLViewerCamera::calcProjection(const F32 far_distance) const { - F32 fov_y, z_far, z_near, aspect, f; - fov_y = getView(); - z_far = far_distance; - z_near = getNear(); - aspect = getAspect(); - - f = 1/tan(fov_y*0.5f); - - mProjectionMatrix.setZero(); - mProjectionMatrix.mMatrix[0][0] = f/aspect; - mProjectionMatrix.mMatrix[1][1] = f; - mProjectionMatrix.mMatrix[2][2] = (z_far + z_near)/(z_near - z_far); - mProjectionMatrix.mMatrix[3][2] = (2*z_far*z_near)/(z_near - z_far); - mProjectionMatrix.mMatrix[2][3] = -1; + mProjectionMatrix = gGL.genPersp( getView()*RAD_TO_DEG, getAspect(), getNear(), far_distance ); } // Sets up opengl state for 3D drawing. If for selection, also @@ -218,59 +154,33 @@ void LLViewerCamera::calcProjection(const F32 far_distance) const //static void LLViewerCamera::updateFrustumPlanes(LLCamera& camera, BOOL ortho, BOOL zflip, BOOL no_hacks) { - GLint* viewport = (GLint*) gGLViewport; - F64 model[16]; - F64 proj[16]; - - for (U32 i = 0; i < 16; i++) - { - model[i] = (F64) gGLModelView[i]; - proj[i] = (F64) gGLProjection[i]; - } - - GLdouble objX,objY,objZ; - LLVector3 frust[8]; + const LLRect& view_port = gGLViewport; + if (no_hacks) { - gluUnProject(viewport[0],viewport[1],0,model,proj,viewport,&objX,&objY,&objZ); - frust[0].setVec((F32)objX,(F32)objY,(F32)objZ); - gluUnProject(viewport[0]+viewport[2],viewport[1],0,model,proj,viewport,&objX,&objY,&objZ); - frust[1].setVec((F32)objX,(F32)objY,(F32)objZ); - gluUnProject(viewport[0]+viewport[2],viewport[1]+viewport[3],0,model,proj,viewport,&objX,&objY,&objZ); - frust[2].setVec((F32)objX,(F32)objY,(F32)objZ); - gluUnProject(viewport[0],viewport[1]+viewport[3],0,model,proj,viewport,&objX,&objY,&objZ); - frust[3].setVec((F32)objX,(F32)objY,(F32)objZ); - - gluUnProject(viewport[0],viewport[1],1,model,proj,viewport,&objX,&objY,&objZ); - frust[4].setVec((F32)objX,(F32)objY,(F32)objZ); - gluUnProject(viewport[0]+viewport[2],viewport[1],1,model,proj,viewport,&objX,&objY,&objZ); - frust[5].setVec((F32)objX,(F32)objY,(F32)objZ); - gluUnProject(viewport[0]+viewport[2],viewport[1]+viewport[3],1,model,proj,viewport,&objX,&objY,&objZ); - frust[6].setVec((F32)objX,(F32)objY,(F32)objZ); - gluUnProject(viewport[0],viewport[1]+viewport[3],1,model,proj,viewport,&objX,&objY,&objZ); - frust[7].setVec((F32)objX,(F32)objY,(F32)objZ); + gGL.unprojectf(LLVector3(view_port.mLeft,view_port.mBottom,0.f),gGLModelView,gGLProjection,view_port,frust[0]); + gGL.unprojectf(LLVector3(view_port.mRight,view_port.mBottom,0.f),gGLModelView,gGLProjection,view_port,frust[1]); + gGL.unprojectf(LLVector3(view_port.mRight,view_port.mTop,0.f),gGLModelView,gGLProjection,view_port,frust[2]); + gGL.unprojectf(LLVector3(view_port.mLeft,view_port.mTop,0.f),gGLModelView,gGLProjection,view_port,frust[3]); + + gGL.unprojectf(LLVector3(view_port.mLeft,view_port.mBottom,1.f),gGLModelView,gGLProjection,view_port,frust[4]); + gGL.unprojectf(LLVector3(view_port.mRight,view_port.mBottom,1.f),gGLModelView,gGLProjection,view_port,frust[5]); + gGL.unprojectf(LLVector3(view_port.mRight,view_port.mTop,1.f),gGLModelView,gGLProjection,view_port,frust[6]); + gGL.unprojectf(LLVector3(view_port.mLeft,view_port.mTop,1.f),gGLModelView,gGLProjection,view_port,frust[7]); } else if (zflip) { - gluUnProject(viewport[0],viewport[1]+viewport[3],0,model,proj,viewport,&objX,&objY,&objZ); - frust[0].setVec((F32)objX,(F32)objY,(F32)objZ); - gluUnProject(viewport[0]+viewport[2],viewport[1]+viewport[3],0,model,proj,viewport,&objX,&objY,&objZ); - frust[1].setVec((F32)objX,(F32)objY,(F32)objZ); - gluUnProject(viewport[0]+viewport[2],viewport[1],0,model,proj,viewport,&objX,&objY,&objZ); - frust[2].setVec((F32)objX,(F32)objY,(F32)objZ); - gluUnProject(viewport[0],viewport[1],0,model,proj,viewport,&objX,&objY,&objZ); - frust[3].setVec((F32)objX,(F32)objY,(F32)objZ); - - gluUnProject(viewport[0],viewport[1]+viewport[3],1,model,proj,viewport,&objX,&objY,&objZ); - frust[4].setVec((F32)objX,(F32)objY,(F32)objZ); - gluUnProject(viewport[0]+viewport[2],viewport[1]+viewport[3],1,model,proj,viewport,&objX,&objY,&objZ); - frust[5].setVec((F32)objX,(F32)objY,(F32)objZ); - gluUnProject(viewport[0]+viewport[2],viewport[1],1,model,proj,viewport,&objX,&objY,&objZ); - frust[6].setVec((F32)objX,(F32)objY,(F32)objZ); - gluUnProject(viewport[0],viewport[1],1,model,proj,viewport,&objX,&objY,&objZ); - frust[7].setVec((F32)objX,(F32)objY,(F32)objZ); + gGL.unprojectf(LLVector3(view_port.mLeft,view_port.mTop,0.f),gGLModelView,gGLProjection,view_port,frust[0]); + gGL.unprojectf(LLVector3(view_port.mRight,view_port.mTop,0.f),gGLModelView,gGLProjection,view_port,frust[1]); + gGL.unprojectf(LLVector3(view_port.mRight,view_port.mBottom,0.f),gGLModelView,gGLProjection,view_port,frust[2]); + gGL.unprojectf(LLVector3(view_port.mLeft,view_port.mBottom,0.f),gGLModelView,gGLProjection,view_port,frust[3]); + + gGL.unprojectf(LLVector3(view_port.mLeft,view_port.mTop,1.f),gGLModelView,gGLProjection,view_port,frust[4]); + gGL.unprojectf(LLVector3(view_port.mRight,view_port.mTop,1.f),gGLModelView,gGLProjection,view_port,frust[5]); + gGL.unprojectf(LLVector3(view_port.mRight,view_port.mBottom,1.f),gGLModelView,gGLProjection,view_port,frust[6]); + gGL.unprojectf(LLVector3(view_port.mLeft,view_port.mBottom,1.f),gGLModelView,gGLProjection,view_port,frust[7]); for (U32 i = 0; i < 4; i++) { @@ -281,14 +191,10 @@ void LLViewerCamera::updateFrustumPlanes(LLCamera& camera, BOOL ortho, BOOL zfli } else { - gluUnProject(viewport[0],viewport[1],0,model,proj,viewport,&objX,&objY,&objZ); - frust[0].setVec((F32)objX,(F32)objY,(F32)objZ); - gluUnProject(viewport[0]+viewport[2],viewport[1],0,model,proj,viewport,&objX,&objY,&objZ); - frust[1].setVec((F32)objX,(F32)objY,(F32)objZ); - gluUnProject(viewport[0]+viewport[2],viewport[1]+viewport[3],0,model,proj,viewport,&objX,&objY,&objZ); - frust[2].setVec((F32)objX,(F32)objY,(F32)objZ); - gluUnProject(viewport[0],viewport[1]+viewport[3],0,model,proj,viewport,&objX,&objY,&objZ); - frust[3].setVec((F32)objX,(F32)objY,(F32)objZ); + gGL.unprojectf(LLVector3(view_port.mLeft,view_port.mBottom,0.f),gGLModelView,gGLProjection,view_port,frust[0]); + gGL.unprojectf(LLVector3(view_port.mRight,view_port.mBottom,0.f),gGLModelView,gGLProjection,view_port,frust[1]); + gGL.unprojectf(LLVector3(view_port.mRight,view_port.mTop,0.f),gGLModelView,gGLProjection,view_port,frust[2]); + gGL.unprojectf(LLVector3(view_port.mLeft,view_port.mTop,0.f),gGLModelView,gGLProjection,view_port,frust[3]); if (ortho) { @@ -335,20 +241,24 @@ void LLViewerCamera::setPerspective(BOOL for_selection, gGL.matrixMode( LLRender::MM_PROJECTION ); gGL.loadIdentity(); - glh::matrix4f proj_mat; + LLMatrix4a proj_mat; + proj_mat.setIdentity(); if (for_selection) { // make a tiny little viewport // anything drawn into this viewport will be "selected" - GLint viewport[4]; - viewport[0] = gViewerWindow->getWorldViewRectRaw().mLeft; - viewport[1] = gViewerWindow->getWorldViewRectRaw().mBottom; - viewport[2] = gViewerWindow->getWorldViewRectRaw().getWidth(); - viewport[3] = gViewerWindow->getWorldViewRectRaw().getHeight(); + const LLRect& rect = gViewerWindow->getWorldViewRectRaw(); - proj_mat = gl_pick_matrix(x+width/2.f, y_from_bot+height/2.f, (GLfloat) width, (GLfloat) height, viewport); + const F32 scale_x = rect.getWidth() / F32(width); + const F32 scale_y = rect.getHeight() / F32(height); + const F32 trans_x = scale_x + (2.f * (rect.mLeft - x)) / F32(width) - 1.f; + const F32 trans_y = scale_y + (2.f * (rect.mBottom - y_from_bot)) / F32(height) - 1.f; + + //Generate a pick matrix + proj_mat.applyScale_affine(scale_x, scale_y, 1.f); + proj_mat.setTranslate_affine(LLVector3(trans_x, trans_y, 0.f)); if (limit_select_distance) { @@ -370,11 +280,8 @@ void LLViewerCamera::setPerspective(BOOL for_selection, { z_far = MAX_FAR_CLIP; } - glViewport(x, y_from_bot, width, height); - gGLViewport[0] = x; - gGLViewport[1] = y_from_bot; - gGLViewport[2] = width; - gGLViewport[3] = height; + gGLViewport.set(x, y_from_bot + height, x + width, y_from_bot); + gGL.setViewport(gGLViewport); } if (mZoomFactor > 1.f) @@ -382,37 +289,28 @@ void LLViewerCamera::setPerspective(BOOL for_selection, float offset = mZoomFactor - 1.f; int pos_y = mZoomSubregion / llceil(mZoomFactor); int pos_x = mZoomSubregion - (pos_y*llceil(mZoomFactor)); - glh::matrix4f translate; - translate.set_translate(glh::vec3f(offset - (F32)pos_x * 2.f, offset - (F32)pos_y * 2.f, 0.f)); - glh::matrix4f scale; - scale.set_scale(glh::vec3f(mZoomFactor, mZoomFactor, 1.f)); - proj_mat = scale*proj_mat; - proj_mat = translate*proj_mat; + proj_mat.applyTranslation_affine(offset - (F32)pos_x * 2.f, offset - (F32)pos_y * 2.f, 0.f); + proj_mat.applyScale_affine(mZoomFactor,mZoomFactor,1.f); } calcProjection(z_far); // Update the projection matrix cache - proj_mat *= gl_perspective(fov_y,aspect,z_near,z_far); - - gGL.loadMatrix(proj_mat.m); - - for (U32 i = 0; i < 16; i++) - { - gGLProjection[i] = proj_mat.m[i]; - } + proj_mat.mul(gGL.genPersp(fov_y,aspect,z_near,z_far)); + + gGL.loadMatrix(proj_mat); + + gGLProjection = proj_mat; gGL.matrixMode(LLRender::MM_MODELVIEW ); - glh::matrix4f modelview((GLfloat*) OGL_TO_CFR_ROTATION); - - GLfloat ogl_matrix[16]; + LLMatrix4a ogl_matrix; + getOpenGLTransform(ogl_matrix.getF32ptr()); - getOpenGLTransform(ogl_matrix); - - modelview *= glh::matrix4f(ogl_matrix); + LLMatrix4a modelview; + modelview.setMul(OGL_TO_CFR_ROTATION, ogl_matrix); - gGL.loadMatrix(modelview.m); + gGL.loadMatrix(modelview); if (for_selection && (width > 1 || height > 1)) { @@ -431,10 +329,7 @@ void LLViewerCamera::setPerspective(BOOL for_selection, { // Save GL matrices for access elsewhere in code, especially project_world_to_screen //glGetDoublev(GL_MODELVIEW_MATRIX, gGLModelView); - for (U32 i = 0; i < 16; i++) - { - gGLModelView[i] = modelview.m[i]; - } + glh_set_current_modelview(modelview); } updateFrustumPlanes(*this); @@ -448,89 +343,14 @@ void LLViewerCamera::setPerspective(BOOL for_selection, }*/ } - // Uses the last GL matrices set in set_perspective to project a point from // screen coordinates to the agent's region. void LLViewerCamera::projectScreenToPosAgent(const S32 screen_x, const S32 screen_y, LLVector3* pos_agent) const { - GLdouble x, y, z; - - F64 mdlv[16]; - F64 proj[16]; - - for (U32 i = 0; i < 16; i++) - { - mdlv[i] = (F64) gGLModelView[i]; - proj[i] = (F64) gGLProjection[i]; - } - - gluUnProject( - GLdouble(screen_x), GLdouble(screen_y), 0.0, - mdlv, proj, (GLint*)gGLViewport, - &x, - &y, - &z ); - pos_agent->setVec( (F32)x, (F32)y, (F32)z ); -} - -//Based off of http://www.opengl.org/wiki/GluProject_and_gluUnProject_code -int glProjectf(const LLVector3& object, const F32* modelview, const F32* projection, const LLRect& viewport, LLVector3& windowCoordinate) -{ - const LLVector4a obj_vector(object.mV[VX],object.mV[VY],object.mV[VZ]); - LLVector4a temp_matrix; - - const LLMatrix4a &view_matrix=*(LLMatrix4a*)modelview; - const LLMatrix4a &proj_matrix=*(LLMatrix4a*)projection; - - view_matrix.affineTransform(obj_vector, temp_matrix); - - //Passing temp_matrix as v and res is safe. res not altered until after all other calculations - proj_matrix.rotate4(temp_matrix, temp_matrix); - - if(temp_matrix[VW]==0.0) - return 0; - - temp_matrix.div(temp_matrix[VW]); - - //Map x, y to range 0-1 - temp_matrix.mul(.5f); - temp_matrix.add(.5f); - - //Window coordinates - windowCoordinate[0]=temp_matrix[VX]*viewport.getWidth()+viewport.mLeft; - windowCoordinate[1]=temp_matrix[VY]*viewport.getHeight()+viewport.mBottom; - //This is only correct when glDepthRange(0.0, 1.0) - windowCoordinate[2]=temp_matrix[VZ]; - - return 1; -} - -void MultiplyMatrices4by4OpenGL_FLOAT(LLMatrix4a& dest_matrix, const LLMatrix4a& input_matrix1, const LLMatrix4a& input_matrix2) -{ - input_matrix1.rotate4(input_matrix2.mMatrix[VX],dest_matrix.mMatrix[VX]); - input_matrix1.rotate4(input_matrix2.mMatrix[VY],dest_matrix.mMatrix[VY]); - input_matrix1.rotate4(input_matrix2.mMatrix[VZ],dest_matrix.mMatrix[VZ]); - input_matrix1.rotate4(input_matrix2.mMatrix[VW],dest_matrix.mMatrix[VW]); - - //Those four lines do this: - /* - result[0]=matrix1[0]*matrix2[0]+matrix1[4]*matrix2[1]+matrix1[8]*matrix2[2]+matrix1[12]*matrix2[3]; - result[1]=matrix1[1]*matrix2[0]+matrix1[5]*matrix2[1]+matrix1[9]*matrix2[2]+matrix1[13]*matrix2[3]; - result[2]=matrix1[2]*matrix2[0]+matrix1[6]*matrix2[1]+matrix1[10]*matrix2[2]+matrix1[14]*matrix2[3]; - result[3]=matrix1[3]*matrix2[0]+matrix1[7]*matrix2[1]+matrix1[11]*matrix2[2]+matrix1[15]*matrix2[3]; - result[4]=matrix1[0]*matrix2[4]+matrix1[4]*matrix2[5]+matrix1[8]*matrix2[6]+matrix1[12]*matrix2[7]; - result[5]=matrix1[1]*matrix2[4]+matrix1[5]*matrix2[5]+matrix1[9]*matrix2[6]+matrix1[13]*matrix2[7]; - result[6]=matrix1[2]*matrix2[4]+matrix1[6]*matrix2[5]+matrix1[10]*matrix2[6]+matrix1[14]*matrix2[7]; - result[7]=matrix1[3]*matrix2[4]+matrix1[7]*matrix2[5]+matrix1[11]*matrix2[6]+matrix1[15]*matrix2[7]; - result[8]=matrix1[0]*matrix2[8]+matrix1[4]*matrix2[9]+matrix1[8]*matrix2[10]+matrix1[12]*matrix2[11]; - result[9]=matrix1[1]*matrix2[8]+matrix1[5]*matrix2[9]+matrix1[9]*matrix2[10]+matrix1[13]*matrix2[11]; - result[10]=matrix1[2]*matrix2[8]+matrix1[6]*matrix2[9]+matrix1[10]*matrix2[10]+matrix1[14]*matrix2[11]; - result[11]=matrix1[3]*matrix2[8]+matrix1[7]*matrix2[9]+matrix1[11]*matrix2[10]+matrix1[15]*matrix2[11]; - result[12]=matrix1[0]*matrix2[12]+matrix1[4]*matrix2[13]+matrix1[8]*matrix2[14]+matrix1[12]*matrix2[15]; - result[13]=matrix1[1]*matrix2[12]+matrix1[5]*matrix2[13]+matrix1[9]*matrix2[14]+matrix1[13]*matrix2[15]; - result[14]=matrix1[2]*matrix2[12]+matrix1[6]*matrix2[13]+matrix1[10]*matrix2[14]+matrix1[14]*matrix2[15]; - result[15]=matrix1[3]*matrix2[12]+ matrix1[7]*matrix2[13]+matrix1[11]*matrix2[14]+matrix1[15]*matrix2[15]; - */ + gGL.unprojectf( + LLVector3(screen_x,screen_y,0.f), + gGLModelView, gGLProjection, gGLViewport, + *pos_agent ); } // Uses the last GL matrices set in set_perspective to project a point from @@ -558,7 +378,7 @@ BOOL LLViewerCamera::projectPosAgentToScreen(const LLVector3 &pos_agent, LLCoord const LLRect& world_view_rect = gViewerWindow->getWorldViewRectRaw(); - if (GL_TRUE == glProjectf(pos_agent, gGLModelView, gGLProjection, world_view_rect, window_coordinates)) + if (gGL.projectf(pos_agent, gGLModelView, gGLProjection, world_view_rect, window_coordinates)) { F32 &x = window_coordinates.mV[VX]; F32 &y = window_coordinates.mV[VY]; @@ -658,7 +478,7 @@ BOOL LLViewerCamera::projectPosAgentToScreenEdge(const LLVector3 &pos_agent, const LLRect& world_view_rect = gViewerWindow->getWorldViewRectRaw(); LLVector3 window_coordinates; - if (GL_TRUE == glProjectf(pos_agent, gGLModelView, gGLProjection, world_view_rect, window_coordinates)) + if (gGL.projectf(pos_agent, gGLModelView, gGLProjection, world_view_rect, window_coordinates)) { F32 &x = window_coordinates.mV[VX]; F32 &y = window_coordinates.mV[VY]; @@ -853,14 +673,12 @@ BOOL LLViewerCamera::areVertsVisible(LLViewerObject* volumep, BOOL all_verts) LLVOVolume* vo_volume = (LLVOVolume*) volumep; vo_volume->updateRelativeXform(); - LLMatrix4 mat = vo_volume->getRelativeXform(); LLMatrix4 render_mat(vo_volume->getRenderRotation(), LLVector4(vo_volume->getRenderPosition())); LLMatrix4a render_mata; render_mata.loadu(render_mat); - LLMatrix4a mata; - mata.loadu(mat); + const LLMatrix4a& mata = vo_volume->getRelativeXform();; num_faces = volume->getNumVolumeFaces(); for (i = 0; i < num_faces; i++) @@ -894,11 +712,17 @@ BOOL LLViewerCamera::areVertsVisible(LLViewerObject* volumep, BOOL all_verts) // changes local camera and broadcasts change /* virtual */ void LLViewerCamera::setView(F32 vertical_fov_rads) { - F32 old_fov = LLViewerCamera::getInstance()->getView(); + F32 old_fov = getView(); // cap the FoV vertical_fov_rads = llclamp(vertical_fov_rads, getMinView(), getMaxView()); +// RLVa:LF - @camzoommax + if (gRlvHandler.hasBehaviour(RLV_BHVR_CAMZOOMMAX)) + vertical_fov_rads = llmin(vertical_fov_rads, gRlvHandler.camPole(RLV_BHVR_CAMZOOMMAX)); + if (gRlvHandler.hasBehaviour(RLV_BHVR_CAMZOOMMIN)) + vertical_fov_rads = llmax(vertical_fov_rads, gRlvHandler.camPole(RLV_BHVR_CAMZOOMMIN)); + if (vertical_fov_rads == old_fov) return; // send the new value to the simulator @@ -927,6 +751,16 @@ void LLViewerCamera::setDefaultFOV(F32 vertical_fov_rads) mCosHalfCameraFOV = cosf(mCameraFOVDefault * 0.5f); } +// +void LLViewerCamera::loadDefaultFOV() +{ + if (mSavedFOVLoaded) return; + setView(mSavedFOVDefault); + mSavedFOVLoaded = true; + mCameraFOVDefault = mSavedFOVDefault; + mCosHalfCameraFOV = cosf(mCameraFOVDefault * 0.5f); +} +// // static void LLViewerCamera::updateCameraAngle( void* user_data, const LLSD& value) diff --git a/indra/newview/llviewercamera.h b/indra/newview/llviewercamera.h index 82d88bc3d6..6e39df9036 100644 --- a/indra/newview/llviewercamera.h +++ b/indra/newview/llviewercamera.h @@ -2,31 +2,25 @@ * @file llviewercamera.h * @brief LLViewerCamera class header file * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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$ */ @@ -38,16 +32,17 @@ #include "llstat.h" #include "lltimer.h" #include "m4math.h" +#include "llmatrix4a.h" #include "llcoord.h" class LLViewerObject; // This rotation matrix moves the default OpenGL reference frame // (-Z at, Y up) to Cory's favorite reference frame (X at, Z up) -const F32 OGL_TO_CFR_ROTATION[16] = { 0.f, 0.f, -1.f, 0.f, // -Z becomes X - -1.f, 0.f, 0.f, 0.f, // -X becomes Y - 0.f, 1.f, 0.f, 0.f, // Y becomes Z - 0.f, 0.f, 0.f, 1.f }; +static LL_ALIGN_16(const LLMatrix4a) OGL_TO_CFR_ROTATION(LLVector4a( 0.f, 0.f, -1.f, 0.f), // -Z becomes X + LLVector4a(-1.f, 0.f, 0.f, 0.f), // -X becomes Y + LLVector4a( 0.f, 1.f, 0.f, 0.f), // Y becomes Z + LLVector4a( 0.f, 0.f, 0.f, 1.f) ); const BOOL FOR_SELECTION = TRUE; const BOOL NOT_FOR_SELECTION = FALSE; @@ -82,7 +77,7 @@ class LLViewerCamera : public LLCamera, public LLSingleton NUM_CAMERAS } eCameraID; - static U32 sCurCameraID; + static LLViewerCamera::eCameraID sCurCameraID; LLViewerCamera(); @@ -94,8 +89,8 @@ class LLViewerCamera : public LLCamera, public LLSingleton static void updateCameraAngle(void* user_data, const LLSD& value); void setPerspective(BOOL for_selection, S32 x, S32 y_from_bot, S32 width, S32 height, BOOL limit_select_distance, F32 z_near = 0, F32 z_far = 0); - const LLMatrix4 &getProjection() const; - const LLMatrix4 &getModelview() const; + const LLMatrix4a &getProjection() const; + const LLMatrix4a &getModelview() const; // Warning! These assume the current global matrices are correct void projectScreenToPosAgent(const S32 screen_x, const S32 screen_y, LLVector3* pos_agent ) const; @@ -118,6 +113,11 @@ class LLViewerCamera : public LLCamera, public LLSingleton void setDefaultFOV(F32 fov) ; F32 getDefaultFOV() { return mCameraFOVDefault; } + bool mSavedFOVLoaded; // + F32 getAndSaveDefaultFOV() { mSavedFOVLoaded = false; return mSavedFOVDefault = mCameraFOVDefault; } // + void setAndSaveDefaultFOV(F32 fov) { setDefaultFOV(mSavedFOVDefault = fov); } // + void loadDefaultFOV(); // + BOOL cameraUnderWater() const; const LLVector3 &getPointOfInterest() { return mLastPointOfInterest; } @@ -138,9 +138,10 @@ class LLViewerCamera : public LLCamera, public LLSingleton F32 mAverageSpeed ; F32 mAverageAngularSpeed ; - mutable LLMatrix4 mProjectionMatrix; // Cache of perspective matrix - mutable LLMatrix4 mModelviewMatrix; + mutable LLMatrix4a mProjectionMatrix; // Cache of perspective matrix + mutable LLMatrix4a mModelviewMatrix; F32 mCameraFOVDefault; + F32 mSavedFOVDefault; // F32 mCosHalfCameraFOV; LLVector3 mLastPointOfInterest; F32 mPixelMeterRatio; // Divide by distance from camera to get pixels per meter at that distance. diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index 8fd959cf2d..e1a7a04ef0 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -70,20 +70,22 @@ #include "llnotify.h" #include "llkeyboard.h" #include "llerrorcontrol.h" -#include "sgversion.h" #include "llappviewer.h" #include "llvosurfacepatch.h" #include "llvowlsky.h" #include "llworldmapview.h" #include "llnetmap.h" #include "llrender.h" -#include "llfloaterchat.h" +#include "lldrawpoolwlsky.h" +#include "llwlparammanager.h" #include "aistatemachine.h" #include "aithreadsafe.h" #include "lldrawpoolbump.h" #include "aicurl.h" #include "aihttptimeoutpolicy.h" +void load_default_bindings(bool zqsd); + #ifdef TOGGLE_HACKED_GODLIKE_VIEWER BOOL gHackGodmode = FALSE; #endif @@ -92,10 +94,8 @@ AIThreadSafeDC gSettings; LLControlGroup gSavedSettings("Global"); // saved at end of session LLControlGroup gSavedPerAccountSettings("PerAccount"); // saved at end of session LLControlGroup gColors("Colors"); // saved at end of session -LLControlGroup gCrashSettings("CrashSettings"); // saved at end of session std::string gLastRunVersion; -std::string gCurrentVersion; extern BOOL gResizeScreenTexture; extern BOOL gDebugGL; @@ -137,6 +137,16 @@ bool handleStateMachineMaxTimeChanged(const LLSD& newvalue) return true; } +extern bool sInwlfPanelUpdate; +static bool handleAvatarHoverOffsetChanged(const LLSD& newvalue) +{ + if (!sInwlfPanelUpdate && isAgentAvatarValid()) + { + gAgentAvatarp->setHoverIfRegionEnabled(); + } + return true; +} + static bool handleSetShaderChanged(const LLSD& newvalue) { // changing shader level may invalidate existing cached bump maps, as the shader type determines the format of the bump map it expects - clear and repopulate the bump cache @@ -204,6 +214,11 @@ bool handleRenderAvatarComplexityLimitChanged(const LLSD& newvalue) bool handleRenderTransparentWaterChanged(const LLSD& newvalue) { + if (gPipeline.isInit()) //If water is opaque then distortion/reflection fbos will not be needed. + { + gPipeline.releaseGLBuffers(); + gPipeline.createGLBuffers(); + } LLWorld::getInstance()->updateWaterObjects(); return true; } @@ -294,7 +309,7 @@ static bool handleGammaChanged(const LLSD& newvalue) // Only save it if it's changed if (!gViewerWindow->getWindow()->setGamma(gamma)) { - llwarns << "setGamma failed!" << llendl; + LL_WARNS() << "setGamma failed!" << LL_ENDL; } } @@ -319,7 +334,7 @@ static bool handleMaxPartCountChanged(const LLSD& newvalue) static bool handleVideoMemoryChanged(const LLSD& newvalue) { - gTextureList.updateMaxResidentTexMem(newvalue.asInteger()); + gTextureList.updateMaxResidentTexMem(S32Megabytes(newvalue.asInteger())); return true; } @@ -355,7 +370,7 @@ static bool handleChatPersistTimeChanged(const LLSD& newvalue) static void handleAudioVolumeChanged(const LLSD& newvalue) { - audio_update_volume(true); + audio_update_volume(false); } static bool handleJoystickChanged(const LLSD& newvalue) @@ -439,6 +454,7 @@ static bool handleRepartition(const LLSD&) if (gPipeline.isInit()) { gOctreeMaxCapacity = gSavedSettings.getU32("OctreeMaxNodeCapacity"); + gOctreeMinSize = gSavedSettings.getF32("OctreeMinimumNodeSize"); gOctreeReserveCapacity = llmin(gSavedSettings.getU32("OctreeReserveNodeCapacity"),U32(512)); gObjectList.repartitionObjects(); } @@ -453,23 +469,15 @@ static bool handleRenderDynamicLODChanged(const LLSD& newvalue) static bool handleRenderLocalLightsChanged(const LLSD& newvalue) { - gPipeline.setLightingDetail(-1); + gPipeline.updateLocalLightingEnabled(); return true; } static bool handleRenderDeferredChanged(const LLSD& newvalue) { - bool can_defer = LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred"); - bool old_deferred = !newvalue.asBoolean() && can_defer; - LLRenderTarget::sUseFBO = (newvalue.asBoolean() && can_defer) || gSavedSettings.getBOOL("RenderUseFBO"); if (gPipeline.isInit()) { - LLPipeline::refreshCachedSettings(); - gPipeline.updateRenderDeferred(); - gPipeline.releaseGLBuffers(); - gPipeline.createGLBuffers(); - gPipeline.resetVertexBuffers(); - if (old_deferred != newvalue.asBoolean()) + if (LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred")) { LLViewerShaderMgr::instance()->setShaders(); } @@ -479,13 +487,11 @@ static bool handleRenderDeferredChanged(const LLSD& newvalue) static bool handleRenderUseFBOChanged(const LLSD& newvalue) { - bool can_defer = LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred"); - LLRenderTarget::sUseFBO = newvalue.asBoolean() || (gSavedSettings.getBOOL("RenderDeferred") && can_defer); + LLRenderTarget::sUseFBO = newvalue.asBoolean() || LLPipeline::sRenderDeferred; if (gPipeline.isInit()) { gPipeline.releaseGLBuffers(); gPipeline.createGLBuffers(); - gPipeline.resetVertexBuffers(); } return true; } @@ -563,7 +569,7 @@ bool handleVelocityInterpolate(const LLSD& newvalue) msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); gAgent.sendReliableMessage(); - llinfos << "Velocity Interpolation On" << llendl; + LL_INFOS() << "Velocity Interpolation On" << LL_ENDL; } else { @@ -572,19 +578,45 @@ bool handleVelocityInterpolate(const LLSD& newvalue) msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); gAgent.sendReliableMessage(); - llinfos << "Velocity Interpolation Off" << llendl; + LL_INFOS() << "Velocity Interpolation Off" << LL_ENDL; } return true; } -bool handleTranslateChatPrefsChanged(const LLSD& newvalue) +bool handleWindlightCloudChanged(const LLSD& new_value) { - LLFloaterChat* floaterp = LLFloaterChat::getInstance(); + std::string cloudNoiseFilename(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight/clouds", new_value.asString())); + if (!gDirUtilp->fileExists(cloudNoiseFilename)) + { + cloudNoiseFilename = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight/clouds", "Default.tga"); + } + LL_INFOS() << "loading WindLight cloud noise from " << cloudNoiseFilename << LL_ENDL; + + LLPointer cloudNoiseFile(LLImageFormatted::createFromExtension(cloudNoiseFilename)); - if(floaterp) + if (cloudNoiseFile.isNull()) { - // update "translate chat" pref in "Local Chat" floater - floaterp->updateSettings(); + LL_WARNS() << "Error: Failed to load cloud noise image " << cloudNoiseFilename << LL_ENDL; + return true; + } + + if (cloudNoiseFile->load(cloudNoiseFilename)) + { + LLDrawPoolWLSky::sCloudNoiseRawImage = new LLImageRaw(); + + if (cloudNoiseFile->decode(LLDrawPoolWLSky::sCloudNoiseRawImage, 0.0f)) + { + //debug use + LL_DEBUGS() << "cloud noise raw image width: " << LLDrawPoolWLSky::sCloudNoiseRawImage->getWidth() << " : height: " << LLDrawPoolWLSky::sCloudNoiseRawImage->getHeight() << " : components: " << + (S32) LLDrawPoolWLSky::sCloudNoiseRawImage->getComponents() << " : data size: " << LLDrawPoolWLSky::sCloudNoiseRawImage->getDataSize() << LL_ENDL; + llassert_always(LLDrawPoolWLSky::sCloudNoiseRawImage->getData()); + + LLDrawPoolWLSky::sCloudNoiseTexture = LLViewerTextureManager::getLocalTexture(LLDrawPoolWLSky::sCloudNoiseRawImage.get(), TRUE); + } + else + { + LLDrawPoolWLSky::sCloudNoiseRawImage = NULL; + } } return true; } @@ -605,7 +637,7 @@ bool handleCloudSettingsChanged(const LLSD& newvalue) bool handleAscentAvatarModifier(const LLSD& newvalue) { - llinfos << "Calling gAgent.sendAgentSetAppearance() because AscentAvatar*Modifier changed." << llendl; + LL_INFOS() << "Calling gAgent.sendAgentSetAppearance() because AscentAvatar*Modifier changed." << LL_ENDL; gAgent.sendAgentSetAppearance(); return true; } @@ -614,13 +646,15 @@ bool handleAscentAvatarModifier(const LLSD& newvalue) static bool handlePhoenixNameSystemChanged(const LLSD& newvalue) { S32 dnval = (S32)newvalue.asInteger(); - if (dnval <= 0 || dnval > 2) LLAvatarNameCache::setUseDisplayNames(false); + if (dnval <= 0 || dnval > 3) LLAvatarNameCache::setUseDisplayNames(false); else LLAvatarNameCache::setUseDisplayNames(true); LLVOAvatar::invalidateNameTags(); return true; } // [/Ansariel: Display name support] +bool handleUpdateFriends() { LLAvatarTracker::instance().updateFriends(); return true; } + static bool handleAllowLargeSounds(const LLSD& newvalue) { if(gAudiop) @@ -628,7 +662,28 @@ static bool handleAllowLargeSounds(const LLSD& newvalue) return true; } +enum DCAction { AUTOPILOT, TELEPORT }; +static void handleDoubleClickActionChanged(const DCAction& action, const LLSD& newvalue) +{ + // Doubleclick actions - there can be only one + if (newvalue.asBoolean()) + { + if (action == AUTOPILOT) + gSavedSettings.setBOOL("DoubleClickTeleport", false); + else + gSavedSettings.setBOOL("DoubleClickAutoPilot", false); + } +} + +void handleHighResChanged(const LLSD& val) +{ + if (val) // High Res Snapshot active, must uncheck RenderUIInSnapshot + gSavedSettings.setBOOL("RenderUIInSnapshot", false); +} + +void handleRenderAutoMuteByteLimitChanged(const LLSD& new_value); //////////////////////////////////////////////////////////////////////////// + void settings_setup_listeners() { gSavedSettings.getControl("FirstPersonAvatarVisible")->getSignal()->connect(boost::bind(&handleRenderAvatarMouselookChanged, _2)); @@ -638,11 +693,12 @@ void settings_setup_listeners() gSavedSettings.getControl("OctreeStaticObjectSizeFactor")->getSignal()->connect(boost::bind(&handleRepartition, _2)); gSavedSettings.getControl("OctreeDistanceFactor")->getSignal()->connect(boost::bind(&handleRepartition, _2)); gSavedSettings.getControl("OctreeMaxNodeCapacity")->getSignal()->connect(boost::bind(&handleRepartition, _2)); + gSavedSettings.getControl("OctreeMinimumNodeSize")->getSignal()->connect(boost::bind(&handleRepartition, _2)); gSavedSettings.getControl("OctreeReserveNodeCapacity")->getSignal()->connect(boost::bind(&handleRepartition, _2)); gSavedSettings.getControl("OctreeAlphaDistanceFactor")->getSignal()->connect(boost::bind(&handleRepartition, _2)); gSavedSettings.getControl("OctreeAttachmentSizeFactor")->getSignal()->connect(boost::bind(&handleRepartition, _2)); gSavedSettings.getControl("RenderMaxTextureIndex")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2)); - //gSavedSettings.getControl("RenderAnimateTrees")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2)); + gSavedSettings.getControl("RenderAnimateTrees")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2)); gSavedSettings.getControl("RenderAvatarVP")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2)); gSavedSettings.getControl("VertexShaderEnable")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2)); gSavedSettings.getControl("RenderDepthOfField")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2)); @@ -679,6 +735,8 @@ void settings_setup_listeners() gSavedSettings.getControl("RenderAutoMaskAlphaNonDeferred")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2)); gSavedSettings.getControl("SHUseRMSEAutoMask")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2)); gSavedSettings.getControl("SHAutoMaskMaxRMSE")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2)); + gSavedSettings.getControl("SHAutoMaskMaxMid")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2)); + gSavedSettings.getControl("SHAltBatching")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2)); gSavedSettings.getControl("RenderObjectBump")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2)); gSavedSettings.getControl("RenderMaxVBOSize")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2)); //See LL jira VWR-3258 comment section. Implemented by LL in 2.1 -Shyotl @@ -693,6 +751,7 @@ void settings_setup_listeners() gSavedSettings.getControl("RenderDeferred")->getSignal()->connect(boost::bind(&handleRenderDeferredChanged, _2)); gSavedSettings.getControl("RenderShadowDetail")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2)); gSavedSettings.getControl("RenderDeferredSSAO")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2)); + gSavedSettings.getControl("SHRenderSSAOResolutionScale")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2)); gSavedSettings.getControl("RenderDepthOfField")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2)); gSavedSettings.getControl("RenderPerformanceTest")->getSignal()->connect(boost::bind(&handleRenderPerfTestChanged, _2)); gSavedSettings.getControl("TextureMemory")->getSignal()->connect(boost::bind(&handleVideoMemoryChanged, _2)); @@ -783,13 +842,14 @@ void settings_setup_listeners() gSavedSettings.getControl("AudioLevelMic")->getSignal()->connect(boost::bind(&handleVoiceClientPrefsChanged, _2)); gSavedSettings.getControl("LipSyncEnabled")->getSignal()->connect(boost::bind(&handleVoiceClientPrefsChanged, _2)); gSavedSettings.getControl("VelocityInterpolate")->getSignal()->connect(boost::bind(&handleVelocityInterpolate, _2)); - gSavedSettings.getControl("TranslateChat")->getSignal()->connect(boost::bind(&handleTranslateChatPrefsChanged, _2)); gSavedSettings.getControl("StateMachineMaxTime")->getSignal()->connect(boost::bind(&handleStateMachineMaxTimeChanged, _2)); gSavedSettings.getControl("CloudsEnabled")->getSignal()->connect(boost::bind(&handleCloudSettingsChanged, _2)); gSavedSettings.getControl("SkyUseClassicClouds")->getSignal()->connect(boost::bind(&handleCloudSettingsChanged, _2)); gSavedSettings.getControl("RenderTransparentWater")->getSignal()->connect(boost::bind(&handleRenderTransparentWaterChanged, _2)); - + gSavedSettings.getControl("AlchemyWLCloudTexture")->getSignal()->connect(boost::bind(&handleWindlightCloudChanged, _2)); + gSavedSettings.getControl("RenderAutoMuteByteLimit")->getSignal()->connect(boost::bind(&handleRenderAutoMuteByteLimitChanged, _2)); + gSavedPerAccountSettings.getControl("AvatarHoverOffsetZ")->getCommitSignal()->connect(boost::bind(&handleAvatarHoverOffsetChanged, _2)); gSavedSettings.getControl("AscentAvatarXModifier")->getSignal()->connect(boost::bind(&handleAscentAvatarModifier, _2)); gSavedSettings.getControl("AscentAvatarYModifier")->getSignal()->connect(boost::bind(&handleAscentAvatarModifier, _2)); gSavedSettings.getControl("AscentAvatarZModifier")->getSignal()->connect(boost::bind(&handleAscentAvatarModifier, _2)); @@ -816,8 +876,14 @@ void settings_setup_listeners() // [Ansariel: Display name support] gSavedSettings.getControl("PhoenixNameSystem")->getSignal()->connect(boost::bind(&handlePhoenixNameSystemChanged, _2)); // [/Ansariel: Display name support] + gSavedSettings.getControl("LiruShowLastNameResident")->getSignal()->connect(boost::bind(handlePhoenixNameSystemChanged, _2)); + gSavedSettings.getControl("FriendNameSystem")->getSignal()->connect(boost::bind(handleUpdateFriends)); gSavedSettings.getControl("AllowLargeSounds")->getSignal()->connect(boost::bind(&handleAllowLargeSounds, _2)); + gSavedSettings.getControl("LiruUseZQSDKeys")->getSignal()->connect(boost::bind(load_default_bindings, _2)); + gSavedSettings.getControl("DoubleClickAutoPilot")->getSignal()->connect(boost::bind(handleDoubleClickActionChanged, AUTOPILOT, _2)); + gSavedSettings.getControl("DoubleClickTeleport")->getSignal()->connect(boost::bind(handleDoubleClickActionChanged, TELEPORT, _2)); + gSavedSettings.getControl("HighResSnapshot")->getSignal()->connect(boost::bind(&handleHighResChanged, _2)); } void onCommitControlSetting_gSavedSettings(LLUICtrl* ctrl, void* name) diff --git a/indra/newview/llviewercontrol.h b/indra/newview/llviewercontrol.h index d8bdf3670b..203c5cfb34 100644 --- a/indra/newview/llviewercontrol.h +++ b/indra/newview/llviewercontrol.h @@ -62,13 +62,8 @@ void create_graphics_group(LLControlGroup& group); // Read-only extern LLControlGroup gColors; -// Saved at end of session -extern LLControlGroup gCrashSettings; - // Set after settings loaded extern std::string gLastRunVersion; -extern std::string gCurrentVersion; - bool handleCloudSettingsChanged(const LLSD& newvalue); diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index addf01e9e9..6d694ca3bb 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -81,6 +81,7 @@ #include "llviewerregion.h" #include "lldrawpoolwater.h" #include "lldrawpoolbump.h" +#include "lldrawpoolavatar.h" #include "llwlparammanager.h" #include "llwaterparammanager.h" #include "llpostprocess.h" @@ -146,22 +147,22 @@ void display_startup() // Required for HTML update in login screen static S32 frame_count = 0; - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); + LLGLStateValidator::checkStates(); + LLGLStateValidator::checkTextureChannels(); if (frame_count++ > 1) // make sure we have rendered a frame first { LLViewerDynamicTexture::updateAllInstances(); } - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); + LLGLStateValidator::checkStates(); + LLGLStateValidator::checkTextureChannels(); gViewerWindow->updateUI(); // Fix ui flicker. + gGL.syncContextState(); glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); LLGLSUIDefault gls_ui; - gPipeline.disableLights(); gViewerWindow->setup2DRender(); gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); @@ -172,16 +173,17 @@ void display_startup() LLVertexBuffer::unbind(); - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); + LLGLStateValidator::checkStates(); + LLGLStateValidator::checkTextureChannels(); gViewerWindow->getWindow()->swapBuffers(); + gGL.syncContextState(); glClear(GL_DEPTH_BUFFER_BIT); } void display_update_camera(bool tiling=false) { - llpushcallstacks; + LL_PUSH_CALLSTACKS(); // TODO: cut draw distance down if customizing avatar? // TODO: cut draw distance on per-parcel basis? @@ -225,8 +227,8 @@ void display_stats() if (fps_log_freq > 0.f && gRecentFPSTime.getElapsedTimeF32() >= fps_log_freq) { F32 fps = gRecentFrameCount / fps_log_freq; - llinfos << llformat("FPS: %.02f", fps) << llendl; - llinfos << llformat("VBO: %d glVBO: %d", LLVertexBuffer::sCount, LLVertexBuffer::sGLCount) << llendl; + LL_INFOS() << llformat("FPS: %.02f", fps) << LL_ENDL; + LL_INFOS() << llformat("VBO: %d glVBO: %d", LLVertexBuffer::sCount, LLVertexBuffer::sGLCount) << LL_ENDL; #ifdef LL_OCTREE_STATS OctreeStats::getInstance()->dump(); #endif @@ -236,33 +238,53 @@ void display_stats() F32 mem_log_freq = gSavedSettings.getF32("MemoryLogFrequency"); if (mem_log_freq > 0.f && gRecentMemoryTime.getElapsedTimeF32() >= mem_log_freq) { - gMemoryAllocated = LLMemory::getCurrentRSS(); - U32 memory = (U32)(gMemoryAllocated / (1024*1024)); - llinfos << llformat("MEMORY: %d MB", memory) << llendl; - llinfos << "THREADS: "<< LLThread::getCount() << llendl; - llinfos << "MALLOC: " << SGMemStat::getPrintableStat() <getWindow()->getFullscreen() && (!gViewerWindow->getWindow() || !gViewerWindow->getWindow()->getVisible() || !gFocusMgr.getAppHasFocus())) + { + return; + }*/ + gViewerWindow->checkSettings(); + LLVBOPool::deleteReleasedBuffers(); + + for (auto avatar : LLCharacter::sInstances) + { + LLVOAvatar* avatarp = dynamic_cast(avatar); + if (!avatarp) continue; + if (avatarp->isDead()) continue; + avatarp->clearRiggedMatrixCache(); + } + sCurCacheHit = 0; if (gWindowResized) { //skip render on frames where window has been resized gGL.flush(); + gGL.syncContextState(); glClear(GL_COLOR_BUFFER_BIT); gViewerWindow->getWindow()->swapBuffers(); LLPipeline::refreshCachedSettings(); @@ -290,12 +312,13 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot, boo LLVertexBuffer::unbind(); - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); + LLGLStateValidator::checkStates(); + LLGLStateValidator::checkTextureChannels(); stop_glerror(); - gPipeline.disableLights(); + LLGLState light_state; + gPipeline.disableLights(light_state); //reset vertex buffers if needed gPipeline.doResetVertexBuffers(); @@ -323,23 +346,16 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot, boo stop_glerror(); return; } - - gViewerWindow->checkSettings(); - - if(gWindowResized) //Singu Note: gViewerWindow->checkSettings() can call LLViewerWindow::reshape(). If it has then skip this frame. - { - return; - } { - LLFastTimer ftm(FTM_PICK); + LL_RECORD_BLOCK_TIME(FTM_PICK); LLAppViewer::instance()->pingMainloopTimeout("Display:Pick"); gViewerWindow->performPick(); } LLAppViewer::instance()->pingMainloopTimeout("Display:CheckStates"); - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); + LLGLStateValidator::checkStates(); + LLGLStateValidator::checkTextureChannels(); ////////////////////////////////////////////////////////// // @@ -634,10 +650,11 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot, boo if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_DYNAMIC_TEXTURES)) { LLAppViewer::instance()->pingMainloopTimeout("Display:DynamicTextures"); - LLFastTimer t(FTM_UPDATE_TEXTURES); + LL_RECORD_BLOCK_TIME(FTM_UPDATE_TEXTURES); if (LLViewerDynamicTexture::updateAllInstances()) { gGL.setColorMask(true, true); + gGL.syncContextState(); glClear(GL_DEPTH_BUFFER_BIT); } } @@ -677,7 +694,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot, boo const F32 max_geom_update_time = 0.005f*10.f*gFrameIntervalSeconds; // 50 ms/second update time gPipeline.createObjects(max_geom_update_time); gPipeline.processPartitionQ(); - gPipeline.updateGeom(max_geom_update_time); + gPipeline.updateGeom(max_geom_update_time, *LLViewerCamera::getInstance()); stop_glerror(); gPipeline.updateGL(); stop_glerror(); @@ -719,20 +736,21 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot, boo } gDepthDirty = FALSE; - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - LLGLState::checkClientArrays(); + LLGLStateValidator::checkStates(); + LLGLStateValidator::checkTextureChannels(); + LLGLStateValidator::checkClientArrays(); static LLCullResult result; LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD; + LLPipeline::sUnderWaterRender = LLViewerCamera::getInstance()->cameraUnderWater() ? TRUE : FALSE; gPipeline.updateCull(*LLViewerCamera::getInstance(), result, water_clip); stop_glerror(); - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - LLGLState::checkClientArrays(); + LLGLStateValidator::checkStates(); + LLGLStateValidator::checkTextureChannels(); + LLGLStateValidator::checkClientArrays(); - BOOL to_texture = gPipeline.canUseVertexShaders() && + BOOL to_texture = LLGLSLShader::sNoFixedFunction && LLPipeline::sRenderGlow; LLAppViewer::instance()->pingMainloopTimeout("Display:Swap"); @@ -748,9 +766,9 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot, boo gGL.setColorMask(true, true); glClearColor(0,0,0,0); - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - LLGLState::checkClientArrays(); + LLGLStateValidator::checkStates(); + LLGLStateValidator::checkTextureChannels(); + LLGLStateValidator::checkClientArrays(); if (!for_snapshot || LLPipeline::sRenderDeferred) { @@ -762,13 +780,13 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot, boo LLVertexBuffer::unbind(); - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - LLGLState::checkClientArrays(); + LLGLStateValidator::checkStates(); + LLGLStateValidator::checkTextureChannels(); + LLGLStateValidator::checkClientArrays(); - glh::matrix4f proj = glh_get_current_projection(); - glh::matrix4f mod = glh_get_current_modelview(); - glViewport(0,0,512,512); + const LLMatrix4a saved_proj = glh_get_current_projection(); + const LLMatrix4a saved_mod = glh_get_current_modelview(); + gGL.setViewport(0,0,512,512); LLVOAvatar::updateFreezeCounter() ; if(!LLPipeline::sMemAllocationThrottled) @@ -776,24 +794,25 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot, boo LLVOAvatar::updateImpostors(); } - glh_set_current_projection(proj); - glh_set_current_modelview(mod); + glh_set_current_projection(saved_proj); + glh_set_current_modelview(saved_mod); gGL.matrixMode(LLRender::MM_PROJECTION); - gGL.loadMatrix(proj.m); + gGL.loadMatrix(saved_proj); gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.loadMatrix(mod.m); + gGL.loadMatrix(saved_mod); gViewerWindow->setup3DViewport(); - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - LLGLState::checkClientArrays(); + LLGLStateValidator::checkStates(); + LLGLStateValidator::checkTextureChannels(); + LLGLStateValidator::checkClientArrays(); } + gGL.syncContextState(); glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); } - LLGLState::checkStates(); - LLGLState::checkClientArrays(); + LLGLStateValidator::checkStates(); + LLGLStateValidator::checkClientArrays(); //if (!for_snapshot) { @@ -802,8 +821,8 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot, boo gPipeline.renderPhysicsDisplay(); } - LLGLState::checkStates(); - LLGLState::checkClientArrays(); + LLGLStateValidator::checkStates(); + LLGLStateValidator::checkClientArrays(); ////////////////////////////////////// // @@ -814,41 +833,41 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot, boo // Doing this here gives hardware occlusion queries extra time to complete LLAppViewer::instance()->pingMainloopTimeout("Display:UpdateImages"); LLError::LLCallStacks::clear() ; - llpushcallstacks ; + LL_PUSH_CALLSTACKS(); gFrameStats.start(LLFrameStats::IMAGE_UPDATE); { - LLFastTimer t(FTM_IMAGE_UPDATE); + LL_RECORD_BLOCK_TIME(FTM_IMAGE_UPDATE); { - LLFastTimer t(FTM_IMAGE_UPDATE_CLASS); + LL_RECORD_BLOCK_TIME(FTM_IMAGE_UPDATE_CLASS); LLViewerTexture::updateClass(LLViewerCamera::getInstance()->getVelocityStat()->getMean(), LLViewerCamera::getInstance()->getAngularVelocityStat()->getMean()); } { - LLFastTimer t(FTM_IMAGE_UPDATE_BUMP); + LL_RECORD_BLOCK_TIME(FTM_IMAGE_UPDATE_BUMP); gBumpImageList.updateImages(); // must be called before gTextureList version so that it's textures are thrown out first. } { - LLFastTimer t(FTM_IMAGE_UPDATE_LIST); + LL_RECORD_BLOCK_TIME(FTM_IMAGE_UPDATE_LIST); F32 max_image_decode_time = 0.050f*gFrameIntervalSeconds; // 50 ms/second decode time max_image_decode_time = llclamp(max_image_decode_time, 0.002f, 0.005f ); // min 2ms/frame, max 5ms/frame) gTextureList.updateImages(max_image_decode_time); } /*{ - LLFastTimer t(FTM_IMAGE_UPDATE_DELETE); + LL_RECORD_BLOCK_TIME(FTM_IMAGE_UPDATE_DELETE); //remove dead textures from GL LLImageGL::deleteDeadTextures(); stop_glerror(); }*/ } - llpushcallstacks ; - LLGLState::checkStates(); - LLGLState::checkClientArrays(); + LL_PUSH_CALLSTACKS(); + LLGLStateValidator::checkStates(); + LLGLStateValidator::checkClientArrays(); /////////////////////////////////// // @@ -878,14 +897,14 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot, boo } } - LLGLState::checkStates(); - LLGLState::checkClientArrays(); + LLGLStateValidator::checkStates(); + LLGLStateValidator::checkClientArrays(); LLPipeline::sUseOcclusion = occlusion; { LLAppViewer::instance()->pingMainloopTimeout("Display:Sky"); - LLFastTimer t(FTM_UPDATE_SKY); + LL_RECORD_BLOCK_TIME(FTM_UPDATE_SKY); gSky.updateSky(); } @@ -895,10 +914,13 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot, boo // [/RLVa:KB] { glClearColor(0.5f, 0.5f, 0.5f, 0.f); + gGL.syncContextState(); glClear(GL_COLOR_BUFFER_BIT); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + gGL.setPolygonMode(LLRender::PF_FRONT_AND_BACK, LLRender::PM_LINE); } + LLVBOPool::deleteReleasedBuffers(); + LLAppViewer::instance()->pingMainloopTimeout("Display:RenderStart"); //// render frontmost floater opaque for occlusion culling purposes @@ -940,8 +962,8 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot, boo LLPipeline::sUnderWaterRender = LLViewerCamera::getInstance()->cameraUnderWater() ? TRUE : FALSE; - LLGLState::checkStates(); - LLGLState::checkClientArrays(); + LLGLStateValidator::checkStates(); + LLGLStateValidator::checkClientArrays(); stop_glerror(); @@ -949,7 +971,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot, boo { gGL.setColorMask(true, true); - if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender) + if (LLPipeline::sRenderDeferred) { gPipeline.mDeferredScreen.bindTarget(); glClearColor(1,0,1,1); @@ -958,7 +980,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot, boo else { gPipeline.mScreen.bindTarget(); - if (LLPipeline::sUnderWaterRender && !gPipeline.canUseWindLightShaders()) + if (LLPipeline::sUnderWaterRender) { const LLColor4 &col = LLDrawPoolWater::sWaterFogColor; glClearColor(col.mV[0], col.mV[1], col.mV[2], 0.f); @@ -997,11 +1019,11 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot, boo gGL.loadIdentity(); gGL.color4fv( LLColor4::white.mV ); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gGL.begin( LLRender::QUADS ); + gGL.begin( LLRender::TRIANGLE_STRIP ); gGL.vertex3f(rect.mLeft, rect.mTop,0.f); gGL.vertex3f(rect.mLeft, rect.mBottom,0.f); + gGL.vertex3f(rect.mRight, rect.mTop, 0.f); gGL.vertex3f(rect.mRight, rect.mBottom,0.f); - gGL.vertex3f(rect.mRight, rect.mTop,0.f); gGL.end(); gGL.matrixMode(LLRender::MM_PROJECTION); @@ -1016,7 +1038,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot, boo if (render_depth_pre_pass && LLGLSLShader::sNoFixedFunction) { LLGLDepthTest depth(GL_TRUE, GL_TRUE); - LLGLEnable cull_face(GL_CULL_FACE); + LLGLEnable cull_face; gGL.setColorMask(false, false); U32 types[] = { @@ -1035,7 +1057,9 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot, boo } gGL.setColorMask(true, false); - if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender) + LLGLEnable lighting; + LLGLEnable normalize; + if (LLPipeline::sRenderDeferred) { gPipeline.renderGeomDeferred(*LLViewerCamera::getInstance()); } @@ -1048,12 +1072,9 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot, boo //store this frame's modelview matrix for use //when rendering next frame's occlusion queries - for (U32 i = 0; i < 16; i++) - { - gGLPreviousModelView[i] = gGLLastModelView[i]; - gGLLastModelView[i] = gGLModelView[i]; - gGLLastProjection[i] = gGLProjection[i]; - } + gGLPreviousModelView = gGLLastModelView; + gGLLastModelView = gGLModelView; + gGLLastProjection = gGLProjection; stop_glerror(); } @@ -1071,7 +1092,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot, boo if (to_texture) { - if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender) + if (LLPipeline::sRenderDeferred) { gPipeline.mDeferredScreen.flush(); if(gPipeline.mDeferredScreen.getFBO()) @@ -1098,7 +1119,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot, boo } //gGL.flush(); - if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender) + if (LLPipeline::sRenderDeferred) { gPipeline.renderDeferredLighting(); } @@ -1108,7 +1129,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot, boo LLAppViewer::instance()->pingMainloopTimeout("Display:RenderUI"); if (!for_snapshot || LLPipeline::sRenderDeferred) { - LLFastTimer t(FTM_RENDER_UI); + LL_RECORD_BLOCK_TIME(FTM_RENDER_UI); gFrameStats.start(LLFrameStats::RENDER_UI); render_ui(); } @@ -1136,6 +1157,8 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot, boo LLAppViewer::instance()->pingMainloopTimeout("Display:Done"); gShiftFrame = false; + + LLVBOPool::deleteReleasedBuffers(); } void render_hud_attachments() @@ -1145,8 +1168,8 @@ void render_hud_attachments() gGL.matrixMode(LLRender::MM_MODELVIEW); gGL.pushMatrix(); - glh::matrix4f current_proj = glh_get_current_projection(); - glh::matrix4f current_mod = glh_get_current_modelview(); + const LLMatrix4a saved_proj = glh_get_current_projection(); + const LLMatrix4a saved_mod = glh_get_current_modelview(); // clamp target zoom level to reasonable values // gAgentCamera.mHUDTargetZoom = llclamp(gAgentCamera.mHUDTargetZoom, 0.1f, 1.f); @@ -1154,10 +1177,11 @@ void render_hud_attachments() gAgentCamera.mHUDTargetZoom = llclamp(gAgentCamera.mHUDTargetZoom, (!gRlvAttachmentLocks.hasLockedHUD()) ? 0.1f : 0.85f, 1.f); // [/RLVa:KB] // smoothly interpolate current zoom level - gAgentCamera.mHUDCurZoom = lerp(gAgentCamera.mHUDCurZoom, gAgentCamera.mHUDTargetZoom, LLCriticalDamp::getInterpolant(0.03f)); + gAgentCamera.mHUDCurZoom = lerp(gAgentCamera.mHUDCurZoom, gAgentCamera.mHUDTargetZoom, LLSmoothInterpolation::getInterpolant(0.03f)); if (LLPipeline::sShowHUDAttachments && !gDisconnected && setup_hud_matrices()) { + LLPipeline::sRenderingHUDs = TRUE; LLCamera hud_cam = *LLViewerCamera::getInstance(); hud_cam.setOrigin(-1.f,0,0); hud_cam.setAxes(LLVector3(1,0,0), LLVector3(0,1,0), LLVector3(0,0,1)); @@ -1203,16 +1227,17 @@ void render_hud_attachments() gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_SIMPLE); gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_VOLUME); gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_ALPHA); + gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_ALPHA_MASK); + gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_FULLBRIGHT_ALPHA_MASK); gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_FULLBRIGHT); gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_ALPHA); gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK); gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_BUMP); + gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_MATERIAL); gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT); gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK); gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY); gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_SHINY); - gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_INVISIBLE); - gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY); gPipeline.stateSort(hud_cam, result); @@ -1231,14 +1256,15 @@ void render_hud_attachments() gPipeline.toggleRenderDebugFeature((void*) LLPipeline::RENDER_DEBUG_FEATURE_UI); } LLPipeline::sUseOcclusion = use_occlusion; + LLPipeline::sRenderingHUDs = FALSE; } gGL.matrixMode(LLRender::MM_PROJECTION); gGL.popMatrix(); gGL.matrixMode(LLRender::MM_MODELVIEW); gGL.popMatrix(); - glh_set_current_projection(current_proj); - glh_set_current_modelview(current_mod); + glh_set_current_projection(saved_proj); + glh_set_current_modelview(saved_mod); } LLRect get_whole_screen_region() @@ -1251,8 +1277,8 @@ LLRect get_whole_screen_region() if (zoom_factor > 1.f) { S32 num_horizontal_tiles = llceil(zoom_factor); - S32 tile_width = llround((F32)gViewerWindow->getWorldViewWidthScaled() / zoom_factor); - S32 tile_height = llround((F32)gViewerWindow->getWorldViewHeightScaled() / zoom_factor); + S32 tile_width = ll_round((F32)gViewerWindow->getWorldViewWidthScaled() / zoom_factor); + S32 tile_height = ll_round((F32)gViewerWindow->getWorldViewHeightScaled() / zoom_factor); int tile_y = sub_region / num_horizontal_tiles; int tile_x = sub_region - (tile_y * num_horizontal_tiles); @@ -1261,7 +1287,7 @@ LLRect get_whole_screen_region() return whole_screen; } -bool get_hud_matrices(const LLRect& screen_region, glh::matrix4f &proj, glh::matrix4f &model) +bool get_hud_matrices(const LLRect& screen_region, LLMatrix4a &proj, LLMatrix4a &model) { if (isAgentAvatarValid() && gAgentAvatarp->hasHUDAttachment()) { @@ -1269,28 +1295,24 @@ bool get_hud_matrices(const LLRect& screen_region, glh::matrix4f &proj, glh::mat LLBBox hud_bbox = gAgentAvatarp->getHUDBBox(); F32 hud_depth = llmax(1.f, hud_bbox.getExtentLocal().mV[VX] * 1.1f); - proj = gl_ortho(-0.5f * LLViewerCamera::getInstance()->getAspect(), 0.5f * LLViewerCamera::getInstance()->getAspect(), -0.5f, 0.5f, 0.f, hud_depth); - proj.element(2,2) = -0.01f; - + proj = gGL.genOrtho(-0.5f * LLViewerCamera::getInstance()->getAspect(), 0.5f * LLViewerCamera::getInstance()->getAspect(), -0.5f, 0.5f, 0.f, hud_depth); + proj.getRow<2>().copyComponent<2>(LLVector4a(-0.01f)); + F32 aspect_ratio = LLViewerCamera::getInstance()->getAspect(); - glh::matrix4f mat; F32 scale_x = (F32)gViewerWindow->getWorldViewWidthScaled() / (F32)screen_region.getWidth(); F32 scale_y = (F32)gViewerWindow->getWorldViewHeightScaled() / (F32)screen_region.getHeight(); - mat.set_scale(glh::vec3f(scale_x, scale_y, 1.f)); - mat.set_translate( - glh::vec3f(clamp_rescale((F32)(screen_region.getCenterX() - screen_region.mLeft), 0.f, (F32)gViewerWindow->getWorldViewWidthScaled(), 0.5f * scale_x * aspect_ratio, -0.5f * scale_x * aspect_ratio), - clamp_rescale((F32)(screen_region.getCenterY() - screen_region.mBottom), 0.f, (F32)gViewerWindow->getWorldViewHeightScaled(), 0.5f * scale_y, -0.5f * scale_y), - 0.f)); - proj *= mat; - - glh::matrix4f tmp_model((GLfloat*) OGL_TO_CFR_ROTATION); - - mat.set_scale(glh::vec3f(zoom_level, zoom_level, zoom_level)); - mat.set_translate(glh::vec3f(-hud_bbox.getCenterLocal().mV[VX] + (hud_depth * 0.5f), 0.f, 0.f)); - - tmp_model *= mat; - model = tmp_model; + + proj.applyTranslation_affine( + clamp_rescale((F32)(screen_region.getCenterX() - screen_region.mLeft), 0.f, (F32)gViewerWindow->getWorldViewWidthScaled(), 0.5f * scale_x * aspect_ratio, -0.5f * scale_x * aspect_ratio), + clamp_rescale((F32)(screen_region.getCenterY() - screen_region.mBottom), 0.f, (F32)gViewerWindow->getWorldViewHeightScaled(), 0.5f * scale_y, -0.5f * scale_y), + 0.f); + proj.applyScale_affine(scale_x, scale_y, 1.f); + + model = OGL_TO_CFR_ROTATION; + model.applyTranslation_affine(LLVector3(-hud_bbox.getCenterLocal().mV[VX] + (hud_depth * 0.5f), 0.f, 0.f)); + model.applyScale_affine(zoom_level); + return TRUE; } else @@ -1299,7 +1321,7 @@ bool get_hud_matrices(const LLRect& screen_region, glh::matrix4f &proj, glh::mat } } -bool get_hud_matrices(glh::matrix4f &proj, glh::matrix4f &model) +bool get_hud_matrices(LLMatrix4a &proj, LLMatrix4a &model) { LLRect whole_screen = get_whole_screen_region(); return get_hud_matrices(whole_screen, proj, model); @@ -1313,38 +1335,38 @@ BOOL setup_hud_matrices() BOOL setup_hud_matrices(const LLRect& screen_region) { - glh::matrix4f proj, model; + LLMatrix4a proj, model; bool result = get_hud_matrices(screen_region, proj, model); if (!result) return result; - + // set up transform to keep HUD objects in front of camera gGL.matrixMode(LLRender::MM_PROJECTION); - gGL.loadMatrix(proj.m); + gGL.loadMatrix(proj); glh_set_current_projection(proj); gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.loadMatrix(model.m); + gGL.loadMatrix(model); glh_set_current_modelview(model); return TRUE; } -static LLFastTimer::DeclareTimer FTM_SWAP("Swap"); +static LLTrace::BlockTimerStatHandle FTM_SWAP("Swap"); void render_ui(F32 zoom_factor, int subfield, bool tiling) { - LLGLState::checkStates(); + LLGLStateValidator::checkStates(); - glh::matrix4f saved_view = glh_get_current_modelview(); + const LLMatrix4a saved_view = glh_get_current_modelview(); if (!gSnapshot) { gGL.pushMatrix(); gGL.loadMatrix(gGLLastModelView); - glh_set_current_modelview(glh_copy_matrix(gGLLastModelView)); + glh_set_current_modelview(gGLLastModelView); } { - BOOL to_texture = gPipeline.canUseVertexShaders() && + BOOL to_texture = LLGLSLShader::sNoFixedFunction && LLPipeline::sRenderGlow; if (to_texture) @@ -1352,7 +1374,7 @@ void render_ui(F32 zoom_factor, int subfield, bool tiling) gPipeline.renderBloom(gSnapshot, zoom_factor, subfield, tiling); } - if(gPipeline.canUseVertexShaders()) + if (LLGLSLShader::sNoFixedFunction) { LLPostProcess::getInstance()->renderEffects(gViewerWindow->getWindowDisplayWidth(), gViewerWindow->getWindowDisplayHeight()); } @@ -1363,20 +1385,17 @@ void render_ui(F32 zoom_factor, int subfield, bool tiling) LLGLSDefault gls_default; LLGLSUIDefault gls_ui; - { - gPipeline.disableLights(); - } { gGL.color4f(1,1,1,1); if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI)) { - LLFastTimer t(FTM_RENDER_UI); + LL_RECORD_BLOCK_TIME(FTM_RENDER_UI); if (!gDisconnected) { render_ui_3d(); - LLGLState::checkStates(); + LLGLStateValidator::checkStates(); } else { @@ -1384,7 +1403,7 @@ void render_ui(F32 zoom_factor, int subfield, bool tiling) } render_ui_2d(); - LLGLState::checkStates(); + LLGLStateValidator::checkStates(); } gGL.flush(); @@ -1405,7 +1424,7 @@ void render_ui(F32 zoom_factor, int subfield, bool tiling) if (gDisplaySwapBuffers) { - LLFastTimer t(FTM_SWAP); + LL_RECORD_BLOCK_TIME(FTM_SWAP); gViewerWindow->getWindow()->swapBuffers(); } gDisplaySwapBuffers = TRUE; @@ -1526,7 +1545,7 @@ void render_ui_2d() // Render 2D UI elements that overlay the world (no z compare) // Disable wireframe mode below here, as this is HUD/menus - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + gGL.setPolygonMode(LLRender::PF_FRONT_AND_BACK, LLRender::PM_FILL); // Menu overlays, HUD, etc gViewerWindow->setup2DRender(); @@ -1540,8 +1559,8 @@ void render_ui_2d() int pos_y = sub_region / llceil(zoom_factor); int pos_x = sub_region - (pos_y*llceil(zoom_factor)); // offset for this tile - LLFontGL::sCurOrigin.mX -= llround((F32)gViewerWindow->getWindowWidthScaled() * (F32)pos_x / zoom_factor); - LLFontGL::sCurOrigin.mY -= llround((F32)gViewerWindow->getWindowHeightScaled() * (F32)pos_y / zoom_factor); + LLFontGL::sCurOrigin.mX -= ll_round((F32)gViewerWindow->getWindowWidthScaled() * (F32)pos_x / zoom_factor); + LLFontGL::sCurOrigin.mY -= ll_round((F32)gViewerWindow->getWindowHeightScaled() * (F32)pos_y / zoom_factor); } stop_glerror(); @@ -1572,15 +1591,9 @@ void render_ui_2d() void render_disconnected_background() { - if (LLGLSLShader::sNoFixedFunction) - { - gUIProgram.bind(); - } - - gGL.color4f(1,1,1,1); if (!gDisconnectedImagep && gDisconnected) { - llinfos << "Loading last bitmap..." << llendl; + LL_INFOS() << "Loading last bitmap..." << LL_ENDL; std::string temp_str; temp_str = gDirUtilp->getLindenUserDir() + gDirUtilp->getDirDelimiter() + SCREEN_LAST_FILENAME; @@ -1588,14 +1601,14 @@ void render_disconnected_background() LLPointer image_bmp = new LLImageBMP; if( !image_bmp->load(temp_str) ) { - //llinfos << "Bitmap load failed" << llendl; + //LL_INFOS() << "Bitmap load failed" << LL_ENDL; return; } LLPointer raw = new LLImageRaw; if (!image_bmp->decode(raw, 0.0f)) { - llinfos << "Bitmap decode failed" << llendl; + LL_INFOS() << "Bitmap decode failed" << LL_ENDL; gDisconnectedImagep = NULL; return; } @@ -1619,7 +1632,6 @@ void render_disconnected_background() raw->expandToPowerOfTwo(); gDisconnectedImagep = LLViewerTextureManager::getLocalTexture(raw.get(), FALSE ); gStartTexture = gDisconnectedImagep; - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); } // Make sure the progress view always fills the entire window. @@ -1628,6 +1640,10 @@ void render_disconnected_background() if (gDisconnectedImagep) { + if (LLGLSLShader::sNoFixedFunction) + { + gUIProgram.bind(); + } LLGLSUIDefault gls_ui; gViewerWindow->setup2DRender(); gGL.pushMatrix(); @@ -1644,14 +1660,12 @@ void render_disconnected_background() gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); } gGL.popMatrix(); + gGL.flush(); + if (LLGLSLShader::sNoFixedFunction) + { + gUIProgram.unbind(); + } } - gGL.flush(); - - if (LLGLSLShader::sNoFixedFunction) - { - gUIProgram.unbind(); - } - } void display_cleanup() diff --git a/indra/newview/llviewerdisplayname.cpp b/indra/newview/llviewerdisplayname.cpp index 54ac54fd22..1e559072a3 100644 --- a/indra/newview/llviewerdisplayname.cpp +++ b/indra/newview/llviewerdisplayname.cpp @@ -40,9 +40,6 @@ #include "llnotificationsutil.h" #include "llui.h" // getLanguage() -class AIHTTPTimeoutPolicy; -extern AIHTTPTimeoutPolicy setDisplayNameResponder_timeout; - namespace LLViewerDisplayName { // Fired when viewer receives server response to display name change @@ -56,26 +53,25 @@ namespace LLViewerDisplayName sNameChangedSignal.connect(cb); } + void doNothing() { } } -class LLSetDisplayNameResponder : public LLHTTPClient::ResponderIgnoreBody +class LLSetDisplayNameResponder final : public LLHTTPClient::ResponderIgnoreBody { -public: + LOG_CLASS(LLSetDisplayNameResponder); +private: // only care about errors - /*virtual*/ void error(U32 status, const std::string& reason) + void httpFailure() override { - LLViewerDisplayName::sSetDisplayNameSignal(false, "", LLSD()); + LLViewerDisplayName::sSetDisplayNameSignal(false, LLStringUtil::null, LLSD()); LLViewerDisplayName::sSetDisplayNameSignal.disconnect_all_slots(); } - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return setDisplayNameResponder_timeout; } - /*virtual*/ char const* getName(void) const { return "LLSetDisplayNameResponder"; } + char const* getName() const override { return "LLSetDisplayNameResponder"; } }; void LLViewerDisplayName::set(const std::string& display_name, const set_name_slot_t& slot) { - // TODO: simple validation here - LLViewerRegion* region = gAgent.getRegion(); llassert(region); std::string cap_url = region->getCapability("SetDisplayName"); @@ -94,7 +90,7 @@ void LLViewerDisplayName::set(const std::string& display_name, const set_name_sl // Our display name will be in cache before the viewer's UI is available // to request a change, so we can use direct lookup without callback. LLAvatarName av_name; - if (!LLAvatarNameCache::get( gAgent.getID(), &av_name)) + if (!LLAvatarNameCache::get(gAgent.getID(), &av_name)) { slot(false, "name unavailable", LLSD()); return; @@ -102,11 +98,9 @@ void LLViewerDisplayName::set(const std::string& display_name, const set_name_sl // People API expects array of [ "old value", "new value" ] LLSD change_array = LLSD::emptyArray(); - change_array.append(av_name.mDisplayName); + change_array.append(av_name.getDisplayName()); change_array.append(display_name); - llinfos << "Set name POST to " << cap_url << llendl; - // Record our caller for when the server sends back a reply sSetDisplayNameSignal.connect(slot); @@ -118,35 +112,35 @@ void LLViewerDisplayName::set(const std::string& display_name, const set_name_sl LLHTTPClient::post(cap_url, body, new LLSetDisplayNameResponder, headers); } -class LLSetDisplayNameReply : public LLHTTPNode +class LLSetDisplayNameReply final : public LLHTTPNode { LOG_CLASS(LLSetDisplayNameReply); public: /*virtual*/ void post( LLHTTPNode::ResponsePtr response, const LLSD& context, - const LLSD& input) const + const LLSD& input) const override { LLSD body = input["body"]; S32 status = body["status"].asInteger(); - bool success = (status == 200); + bool success = (status == HTTP_OK); std::string reason = body["reason"].asString(); LLSD content = body["content"]; - llinfos << "status " << status << " reason " << reason << llendl; + LL_INFOS() << "status " << status << " reason " << reason << LL_ENDL; // If viewer's concept of display name is out-of-date, the set request // will fail with 409 Conflict. If that happens, fetch up-to-date // name information. - if (status == 409) + if (status == HTTP_CONFLICT) { LLUUID agent_id = gAgent.getID(); // Flush stale data LLAvatarNameCache::erase( agent_id ); - // Queue request for new data - LLAvatarName ignored; - LLAvatarNameCache::get( agent_id, &ignored ); + // Queue request for new data: nothing to do on callback though... + // Note: no need to disconnect the callback as it never gets out of scope + LLAvatarNameCache::get(agent_id, boost::bind(&LLViewerDisplayName::doNothing)); // Kill name tag, as it is wrong LLVOAvatar::invalidateNameTag( agent_id ); } @@ -158,13 +152,12 @@ class LLSetDisplayNameReply : public LLHTTPNode }; -class LLDisplayNameUpdate : public LLHTTPNode +class LLDisplayNameUpdate final : public LLHTTPNode { - /*virtual*/ void post( LLHTTPNode::ResponsePtr response, const LLSD& context, - const LLSD& input) const + const LLSD& input) const override { LLSD body = input["body"]; LLUUID agent_id = body["agent_id"]; @@ -176,16 +169,17 @@ class LLDisplayNameUpdate : public LLHTTPNode LLAvatarName av_name; av_name.fromLLSD( name_data ); - llinfos << "name-update now " << LLDate::now() + LL_INFOS() << "name-update now " << LLDate::now() << " next_update " << LLDate(av_name.mNextUpdate) - << llendl; + << LL_ENDL; // Name expiration time may be provided in headers, or we may use a // default value // *TODO: get actual headers out of ResponsePtr //LLSD headers = response->mHeaders; + AIHTTPReceivedHeaders headers; av_name.mExpires = - LLAvatarNameCache::nameExpirationFromHeaders(AIHTTPReceivedHeaders()); + LLAvatarNameCache::nameExpirationFromHeaders(headers); LLAvatarNameCache::insert(agent_id, av_name); @@ -196,8 +190,8 @@ class LLDisplayNameUpdate : public LLHTTPNode { LLSD args; args["OLD_NAME"] = old_display_name; - args["SLID"] = av_name.mUsername; - args["NEW_NAME"] = av_name.mDisplayName; + args["SLID"] = "secondlife:///app/agent/" + agent_id.asString() + "/username"; + args["NEW_NAME"] = av_name.getDisplayName(); LLNotificationsUtil::add("DisplayNameUpdate", args); } if (agent_id == gAgent.getID()) @@ -214,4 +208,3 @@ LLHTTPRegistration LLHTTPRegistration gHTTPRegistrationMessageDisplayNameUpdate( "/message/DisplayNameUpdate"); - diff --git a/indra/newview/llviewerfoldertype.cpp b/indra/newview/llviewerfoldertype.cpp index a779b617b9..11809193b1 100644 --- a/indra/newview/llviewerfoldertype.cpp +++ b/indra/newview/llviewerfoldertype.cpp @@ -27,6 +27,7 @@ #include "llviewerprecompiledheaders.h" #include "llviewerfoldertype.h" +#include "llcontrol.h" #include "lldictionary.h" #include "llmemory.h" #include "llvisualparam.h" @@ -131,12 +132,18 @@ LLViewerFolderDictionary::LLViewerFolderDictionary() addEntry(LLFolderType::FT_OUTFIT, new ViewerFolderEntry("New Outfit", "inv_folder_outfit.tga", "inv_folder_outfit.tga", TRUE, false)); addEntry(LLFolderType::FT_MY_OUTFITS, new ViewerFolderEntry("My Outfits", "inv_folder_outfit.tga", "inv_folder_outfit.tga", TRUE, false)); addEntry(LLFolderType::FT_MESH, new ViewerFolderEntry("Meshes", "inv_folder_mesh.tga", "inv_folder_mesh.tga", FALSE, false)); - - addEntry(LLFolderType::FT_INBOX, new ViewerFolderEntry("Inbox", "inv_folder_inbox.tga", "inv_folder_inbox.tga", FALSE, false)); - addEntry(LLFolderType::FT_OUTBOX, new ViewerFolderEntry("Outbox", "inv_folder_outbox.tga", "inv_folder_outbox.tga", FALSE, false)); + + //bool boxes_invisible = !gSavedSettings.getBOOL("InventoryOutboxMakeVisible"); + addEntry(LLFolderType::FT_INBOX, new ViewerFolderEntry("Received Items", "inv_folder_inbox.tga", "inv_folder_inbox.tga", FALSE, false)); + addEntry(LLFolderType::FT_OUTBOX, new ViewerFolderEntry("Merchant Outbox", "inv_folder_outbox.tga", "inv_folder_outbox.tga", FALSE, true)); addEntry(LLFolderType::FT_BASIC_ROOT, new ViewerFolderEntry("Basic Root", "inv_folder_plain_open.tga", "inv_folder_plain_closed.tga", FALSE, false)); - + + addEntry(LLFolderType::FT_MARKETPLACE_LISTINGS, new ViewerFolderEntry("Marketplace Listings", "inv_folder_plain_open.tga", "inv_folder_plain_closed.tga", FALSE, true)); + addEntry(LLFolderType::FT_MARKETPLACE_STOCK, new ViewerFolderEntry("New Stock", "Inv_StockFolderOpen", "Inv_StockFolderClosed", FALSE, false, "default")); + addEntry(LLFolderType::FT_MARKETPLACE_VERSION, new ViewerFolderEntry("New Version", "Inv_VersionFolderOpen", "Inv_VersionFolderClosed", FALSE, false, "default")); + addEntry(LLFolderType::FT_SUITCASE, new ViewerFolderEntry("My Suitcase", "inv_folder_plain_open.tga", "inv_folder_plain_closed.tga", FALSE, false)); + addEntry(LLFolderType::FT_NONE, new ViewerFolderEntry("New Folder", "inv_folder_plain_open.tga", "inv_folder_plain_closed.tga", FALSE, false, "default")); #if SUPPORT_ENSEMBLES @@ -155,7 +162,7 @@ bool LLViewerFolderDictionary::initEnsemblesFromFile() LLXmlTree folder_def; if (!folder_def.parseFile(xml_filename)) { - llerrs << "Failed to parse folders file " << xml_filename << llendl; + LL_ERRS() << "Failed to parse folders file " << xml_filename << LL_ENDL; return false; } @@ -166,7 +173,7 @@ bool LLViewerFolderDictionary::initEnsemblesFromFile() { if (!ensemble->hasName("ensemble")) { - llwarns << "Invalid ensemble definition node " << ensemble->getName() << llendl; + LL_WARNS() << "Invalid ensemble definition node " << ensemble->getName() << LL_ENDL; continue; } @@ -174,14 +181,14 @@ bool LLViewerFolderDictionary::initEnsemblesFromFile() static LLStdStringHandle ensemble_num_string = LLXmlTree::addAttributeString("foldertype_num"); if (!ensemble->getFastAttributeS32(ensemble_num_string, ensemble_type)) { - llwarns << "No ensemble type defined" << llendl; + LL_WARNS() << "No ensemble type defined" << LL_ENDL; continue; } if (ensemble_type < S32(LLFolderType::FT_ENSEMBLE_START) || ensemble_type > S32(LLFolderType::FT_ENSEMBLE_END)) { - llwarns << "Exceeded maximum ensemble index" << LLFolderType::FT_ENSEMBLE_END << llendl; + LL_WARNS() << "Exceeded maximum ensemble index" << LLFolderType::FT_ENSEMBLE_END << LL_ENDL; break; } @@ -189,7 +196,7 @@ bool LLViewerFolderDictionary::initEnsemblesFromFile() static LLStdStringHandle xui_name_string = LLXmlTree::addAttributeString("xui_name"); if (!ensemble->getFastAttributeString(xui_name_string, xui_name)) { - llwarns << "No xui name defined" << llendl; + LL_WARNS() << "No xui name defined" << LL_ENDL; continue; } @@ -197,7 +204,7 @@ bool LLViewerFolderDictionary::initEnsemblesFromFile() static LLStdStringHandle icon_name_string = LLXmlTree::addAttributeString("icon_name"); if (!ensemble->getFastAttributeString(icon_name_string, icon_name)) { - llwarns << "No ensemble icon name defined" << llendl; + LL_WARNS() << "No ensemble icon name defined" << LL_ENDL; continue; } diff --git a/indra/newview/llviewergenericmessage.cpp b/indra/newview/llviewergenericmessage.cpp index c4675e7bb0..cc1aca7e5b 100644 --- a/indra/newview/llviewergenericmessage.cpp +++ b/indra/newview/llviewergenericmessage.cpp @@ -105,7 +105,7 @@ void process_generic_message(LLMessageSystem* msg, void**) } else if (agent_id != gAgent.getID()) { - llwarns << "GenericMessage for wrong agent " << agent_id << llendl; + LL_WARNS() << "GenericMessage for wrong agent " << agent_id << LL_ENDL; return; } else @@ -117,8 +117,8 @@ void process_generic_message(LLMessageSystem* msg, void**) if(!gGenericDispatcher.dispatch(request, invoice, strings)) { - llwarns << "GenericMessage " << request << " failed to dispatch" - << llendl; + LL_WARNS() << "GenericMessage " << request << " failed to dispatch" + << LL_ENDL; } } } diff --git a/indra/newview/llviewergesture.cpp b/indra/newview/llviewergesture.cpp index 65cee0e5e9..80b76fe9a1 100644 --- a/indra/newview/llviewergesture.cpp +++ b/indra/newview/llviewergesture.cpp @@ -209,13 +209,13 @@ void LLViewerGestureList::xferCallback(void *data, S32 size, void** /*user_data* if (end - buffer > size) { - llerrs << "Read off of end of array, error in serialization" << llendl; + LL_ERRS() << "Read off of end of array, error in serialization" << LL_ENDL; } gGestureList.mIsLoaded = TRUE; } else { - llwarns << "Unable to load gesture list!" << llendl; + LL_WARNS() << "Unable to load gesture list!" << LL_ENDL; } } diff --git a/indra/newview/llviewergesture.h b/indra/newview/llviewergesture.h index de7288ca06..4bbf7596d9 100644 --- a/indra/newview/llviewergesture.h +++ b/indra/newview/llviewergesture.h @@ -35,7 +35,6 @@ #include "lluuid.h" #include "llstring.h" -#include "lldarray.h" #include "llgesture.h" class LLMessageSystem; diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index de52941d10..db781e6b51 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -4,7 +4,7 @@ * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. + * Copyright (C) 2014, 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 @@ -31,6 +31,7 @@ #include "llsdserialize.h" #include "message.h" +#include "llaisapi.h" #include "llagent.h" #include "llagentcamera.h" #include "llagentwearables.h" @@ -43,12 +44,14 @@ #include "llinventorymodel.h" #include "llinventorymodelbackgroundfetch.h" #include "llgesturemgr.h" +#include "llinventoryclipboard.h" #include "llinventorybridge.h" #include "llinventorypanel.h" #include "llfloaterinventory.h" +#include "llfloaterperms.h" +#include "lllandmarkactions.h" -#include "lllandmark.h" #include "llviewerassettype.h" #include "llviewerregion.h" #include "llviewerobjectlist.h" @@ -59,24 +62,66 @@ #include "llcommandhandler.h" #include "llviewermessage.h" #include "llavatarnamecache.h" +#include "llfavoritesbar.h" + +#include "llsdutil.h" #include "llfloatercustomize.h" // #include "llappviewer.h" // System Folders +bool use_http_inventory(); // UseHTTPInventory replacement // +// [RLVa:KB] - Checked: 2014-11-02 (RLVa-1.4.11) +#include "rlvcommon.h" +// [/RLVa:KB] -// Two do-nothing ops for use in callbacks. +// do-nothing ops for use in callbacks. void no_op_inventory_func(const LLUUID&) {} +void no_op_llsd_func(const LLSD&) {} void no_op() {} +static const char * const LOG_INV("Inventory"); +static const char * const LOG_LOCAL("InventoryLocalize"); +static const char * const LOG_NOTECARD("copy_inventory_from_notecard"); + +#if 1 +// *TODO$: LLInventoryCallback should be deprecated to conform to the new boost::bind/coroutine model. +// temp code in transition +void doInventoryCb(LLPointer cb, LLUUID id) +{ + if (cb.notNull()) + cb->fire(id); +} +#endif + ///---------------------------------------------------------------------------- /// Helper class to store special inventory item names and their localized values. ///---------------------------------------------------------------------------- -class LLLocalizedInventoryItemsDictionary : public LLSingleton +class LLLocalizedInventoryItemsDictionary final : public LLSingleton { public: std::map mInventoryItemsDict; + /** + * Finds passed name in dictionary and replaces it with found localized value. + * + * @param object_name - string to be localized. + * @return true if passed name was found and localized, false otherwise. + */ + bool localizeInventoryObjectName(std::string& object_name) + { + LL_DEBUGS(LOG_LOCAL) << "Searching for localization: " << object_name << LL_ENDL; + + std::map::const_iterator dictionary_iter = mInventoryItemsDict.find(object_name); + + bool found = dictionary_iter != mInventoryItemsDict.end(); + if(found) + { + object_name = dictionary_iter->second; + LL_DEBUGS(LOG_LOCAL) << "Found, new name is: " << object_name << LL_ENDL; + } + return found; + } LLLocalizedInventoryItemsDictionary() { mInventoryItemsDict["New Shape"] = LLTrans::getString("New Shape"); @@ -94,6 +139,7 @@ class LLLocalizedInventoryItemsDictionary : public LLSingleton::const_iterator dictionary_iter = mInventoryItemsDict.find(object_name); - - bool found = dictionary_iter != mInventoryItemsDict.end(); - if(found) - { - object_name = dictionary_iter->second; - LL_DEBUGS("InventoryLocalize") << "Found, new name is: " << object_name << LL_ENDL; - } - return found; - } }; @@ -249,8 +274,8 @@ LLViewerInventoryItem::LLViewerInventoryItem(const LLViewerInventoryItem* other) // //if (!mIsComplete) //{ - // llwarns << "LLViewerInventoryItem copy constructor for incomplete item" - // << mUUID << llendl; + // LL_WARNS() << "LLViewerInventoryItem copy constructor for incomplete item" + // << mUUID << LL_ENDL; //} } @@ -291,75 +316,85 @@ void LLViewerInventoryItem::cloneViewerItem(LLPointer& ne } } -void LLViewerInventoryItem::removeFromServer() -{ - lldebugs << "Removing inventory item " << mUUID << " from server." - << llendl; - - LLInventoryModel::LLCategoryUpdate up(mParentUUID, -1); - gInventory.accountForUpdate(up); - - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_RemoveInventoryItem); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_InventoryData); - msg->addUUIDFast(_PREHASH_ItemID, mUUID); - gAgent.sendReliableMessage(); -} - void LLViewerInventoryItem::updateServer(BOOL is_new) const { if(getWearableType() == LLWearableType::WT_UNKNOWN) { - llwarns << "LLViewerInventoryItem::updateServer() - for item with unknown wearable type" - << llendl; + LL_WARNS() << "LLViewerInventoryItem::updateServer() - for item with unknown wearable type" + << LL_ENDL; return; } if(!mIsComplete) { // *FIX: deal with this better. - llwarns << "LLViewerInventoryItem::updateServer() - for incomplete item" - << llendl; + // If we're crashing here then the UI is incorrectly enabled. + LL_ERRS(LOG_INV) << "LLViewerInventoryItem::updateServer() - for incomplete item" + << LL_ENDL; LLNotificationsUtil::add("IncompleteInventoryItem"); return; } if(gAgent.getID() != mPermissions.getOwner()) { // *FIX: deal with this better. - llwarns << "LLViewerInventoryItem::updateServer() - for unowned item" - << llendl; + LL_WARNS(LOG_INV) << "LLViewerInventoryItem::updateServer() - for unowned item " + << ll_pretty_print_sd(this->asLLSD()) + << LL_ENDL; return; } LLInventoryModel::LLCategoryUpdate up(mParentUUID, is_new ? 1 : 0); gInventory.accountForUpdate(up); - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_UpdateInventoryItem); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->addUUIDFast(_PREHASH_TransactionID, mTransactionID); - msg->nextBlockFast(_PREHASH_InventoryData); - msg->addU32Fast(_PREHASH_CallbackID, 0); - packMessage(msg); - gAgent.sendReliableMessage(); + if (AISAPI::isAvailable()) + { + LLSD updates = asLLSD(); + // Replace asset_id and/or shadow_id with transaction_id (hash_id) + if (updates.has("asset_id")) + { + updates.erase("asset_id"); + if(getTransactionID().notNull()) + { + updates["hash_id"] = getTransactionID(); + } + } + if (updates.has("shadow_id")) + { + updates.erase("shadow_id"); + if(getTransactionID().notNull()) + { + updates["hash_id"] = getTransactionID(); + } + } + AISAPI::completion_t cr = boost::bind(&doInventoryCb, (LLPointer)NULL, _1); + AISAPI::UpdateItem(getUUID(), updates, cr); + } + else + { + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_UpdateInventoryItem); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addUUIDFast(_PREHASH_TransactionID, mTransactionID); + msg->nextBlockFast(_PREHASH_InventoryData); + msg->addU32Fast(_PREHASH_CallbackID, 0); + packMessage(msg); + gAgent.sendReliableMessage(); + } } void LLViewerInventoryItem::fetchFromServer(void) const { - if(!mIsComplete) + if (!mIsComplete) { - std::string url; + std::string url; - if (gSavedSettings.getBOOL("UseHTTPInventory")) + if (use_http_inventory()) { LLViewerRegion* region = gAgent.getRegion(); // we have to check region. It can be null after region was destroyed. See EXT-245 if (region) { - if(gAgent.getID() != mPermissions.getOwner()) + if (gAgent.getID() != mPermissions.getOwner()) { url = region->getCapability("FetchLib2"); } @@ -370,18 +405,18 @@ void LLViewerInventoryItem::fetchFromServer(void) const } else { - llwarns << "Agent Region is absent" << llendl; + LL_WARNS(LOG_INV) << "Agent Region is absent" << LL_ENDL; } } if (!url.empty()) { LLSD body; - body["agent_id"] = gAgent.getID(); - body["items"][0]["owner_id"] = mPermissions.getOwner(); - body["items"][0]["item_id"] = mUUID; + body["agent_id"] = gAgent.getID(); + body["items"][0]["owner_id"] = mPermissions.getOwner(); + body["items"][0]["item_id"] = mUUID; - LLHTTPClient::post(url, body, new LLInventoryModel::fetchInventoryResponder(body)); + LLHTTPClient::post(url, body, new LLInventoryModel::FetchItemHttpHandler(body)); } else { @@ -396,15 +431,10 @@ void LLViewerInventoryItem::fetchFromServer(void) const gAgent.sendReliableMessage(); } } - else - { - // *FIX: this can be removed after a bit. - llwarns << "request to fetch complete item" << llendl; - } } // virtual -BOOL LLViewerInventoryItem::unpackMessage(LLSD item) +BOOL LLViewerInventoryItem::unpackMessage(const LLSD& item) { BOOL rv = LLInventoryItem::fromLLSD(item); @@ -429,7 +459,7 @@ void LLViewerInventoryItem::setTransactionID(const LLTransactionID& transaction_ { mTransactionID = transaction_id; } -// virtual + void LLViewerInventoryItem::packMessage(LLMessageSystem* msg) const { msg->addUUIDFast(_PREHASH_ItemID, mUUID); @@ -448,6 +478,7 @@ void LLViewerInventoryItem::packMessage(LLMessageSystem* msg) const U32 crc = getCRC32(); msg->addU32Fast(_PREHASH_CRC, crc); } + // virtual BOOL LLViewerInventoryItem::importFile(LLFILE* fp) { @@ -559,6 +590,15 @@ void LLViewerInventoryCategory::copyViewerCategory(const LLViewerInventoryCatego } +void LLViewerInventoryCategory::packMessage(LLMessageSystem* msg) const +{ + msg->addUUIDFast(_PREHASH_FolderID, mUUID); + msg->addUUIDFast(_PREHASH_ParentID, mParentUUID); + S8 type = static_cast(mPreferredType); + msg->addS8Fast(_PREHASH_Type, type); + msg->addStringFast(_PREHASH_Name, mName); +} + void LLViewerInventoryCategory::updateParentOnServer(BOOL restamp) const { LLMessageSystem* msg = gMessageSystem; @@ -583,44 +623,36 @@ void LLViewerInventoryCategory::updateServer(BOOL is_new) const LLNotificationsUtil::add("CannotModifyProtectedCategories"); return; } + if (AISAPI::isAvailable()) + { + LLSD new_llsd = asLLSD(); + AISAPI::completion_t cr = boost::bind(&doInventoryCb, LLPointer(NULL), _1); + AISAPI::UpdateCategory(getUUID(), new_llsd, cr); + } + else + { + LLInventoryModel::LLCategoryUpdate up(mParentUUID, is_new ? 1 : 0); + gInventory.accountForUpdate(up); - LLInventoryModel::LLCategoryUpdate up(mParentUUID, is_new ? 1 : 0); - gInventory.accountForUpdate(up); - - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_UpdateInventoryFolder); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_FolderData); - packMessage(msg); - gAgent.sendReliableMessage(); + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_UpdateInventoryFolder); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_FolderData); + packMessage(msg); + gAgent.sendReliableMessage(); + } } -void LLViewerInventoryCategory::removeFromServer( void ) +S32 LLViewerInventoryCategory::getVersion() const { - llinfos << "Removing inventory category " << mUUID << " from server." - << llendl; - // communicate that change with the server. -#ifndef DELETE_SYSTEM_FOLDERS - if(LLFolderType::lookupIsProtectedType(mPreferredType)) - { - LLNotificationsUtil::add("CannotRemoveProtectedCategories"); - return; - } -#endif - - LLInventoryModel::LLCategoryUpdate up(mParentUUID, -1); - gInventory.accountForUpdate(up); + return mVersion; +} - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_RemoveInventoryFolder); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_FolderData); - msg->addUUIDFast(_PREHASH_FolderID, mUUID); - gAgent.sendReliableMessage(); +void LLViewerInventoryCategory::setVersion(S32 version) +{ + mVersion = version; } bool LLViewerInventoryCategory::fetch() @@ -629,7 +661,7 @@ bool LLViewerInventoryCategory::fetch() (!mDescendentsRequested.getStarted() || mDescendentsRequested.hasExpired())) //Expired check prevents multiple downloads. { - LL_DEBUGS("InventoryFetch") << "Fetching category children: " << mName << ", UUID: " << mUUID << LL_ENDL; + LL_DEBUGS(LOG_INV) << "Fetching category children: " << mName << ", UUID: " << mUUID << LL_ENDL; const F32 FETCH_TIMER_EXPIRY = 10.0f; mDescendentsRequested.start(FETCH_TIMER_EXPIRY); @@ -653,15 +685,18 @@ bool LLViewerInventoryCategory::fetch() } else { - llwarns << "agent region is null" << llendl; + LL_WARNS(LOG_INV) << "agent region is null" << LL_ENDL; } - if (!url.empty()) //Capability found. Build up LLSD and use it. + if (!url.empty() && use_http_inventory()) //Capability found and HTTP inventory enabled. Build up LLSD and use it. { LLInventoryModelBackgroundFetch::instance().start(mUUID, false); } else - { //Deprecated, but if we don't have a capability, use the old system. - llinfos << "FetchInventoryDescendents2 capability not found. Using deprecated UDP message." << llendl; + { //We don't have a capability or the use of HTTP inventory is disabled, use the old system. + if (use_http_inventory()) + { + LL_INFOS(LOG_INV) << "FetchInventoryDescendents2 capability not found. Using deprecated UDP message." << LL_ENDL; + } LLMessageSystem* msg = gMessageSystem; msg->newMessage("FetchInventoryDescendents"); msg->nextBlock("AgentData"); @@ -681,6 +716,19 @@ bool LLViewerInventoryCategory::fetch() return false; } +S32 LLViewerInventoryCategory::getViewerDescendentCount() const +{ + LLInventoryModel::cat_array_t* cats; + LLInventoryModel::item_array_t* items; + gInventory.getDirectDescendentsOf(getUUID(), cats, items); + S32 descendents_actual = 0; + if(cats && items) + { + descendents_actual = cats->size() + items->size(); + } + return descendents_actual; +} + bool LLViewerInventoryCategory::importFileLocal(LLFILE* fp) { // *NOTE: This buffer size is hard coded into scanf() below. @@ -743,8 +791,8 @@ bool LLViewerInventoryCategory::importFileLocal(LLFILE* fp) } else { - llwarns << "unknown keyword '" << keyword - << "' in inventory import category " << mUUID << llendl; + LL_WARNS(LOG_INV) << "unknown keyword '" << keyword + << "' in inventory import category " << mUUID << LL_ENDL; } } return true; @@ -768,6 +816,36 @@ bool LLViewerInventoryCategory::exportFileLocal(LLFILE* fp) const return true; } +bool LLViewerInventoryCategory::acceptItem(LLInventoryItem* inv_item) +{ + if (!inv_item) + { + return false; + } + + // Only stock folders have limitation on which item they will accept + bool accept = true; + if (getPreferredType() == LLFolderType::FT_MARKETPLACE_STOCK) + { + // If the item is copyable (i.e. non stock) do not accept the drop in a stock folder + if (inv_item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID())) + { + accept = false; + } + else + { + LLInventoryModel::cat_array_t* cat_array; + LLInventoryModel::item_array_t* item_array; + gInventory.getDirectDescendentsOf(getUUID(),cat_array,item_array); + // Destination stock folder must be empty OR types of incoming and existing items must be identical and have the same permissions + accept = (item_array->empty() || + ((item_array->at(0)->getInventoryType() == inv_item->getInventoryType()) && + (item_array->at(0)->getPermissions().getMaskNextOwner() == inv_item->getPermissions().getMaskNextOwner()))); + } + } + return accept; +} + void LLViewerInventoryCategory::determineFolderType() { /* Do NOT uncomment this code. This is for future 2.1 support of ensembles. @@ -824,18 +902,33 @@ void LLViewerInventoryCategory::changeType(LLFolderType::EType new_folder_type) const LLUUID &folder_id = getUUID(); const LLUUID &parent_id = getParentUUID(); const std::string &name = getName(); - - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_UpdateInventoryFolder); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_FolderData); - msg->addUUIDFast(_PREHASH_FolderID, folder_id); - msg->addUUIDFast(_PREHASH_ParentID, parent_id); - msg->addS8Fast(_PREHASH_Type, new_folder_type); - msg->addStringFast(_PREHASH_Name, name); - gAgent.sendReliableMessage(); + if (AISAPI::isAvailable()) + { + LLPointer new_cat = new LLViewerInventoryCategory(folder_id, + parent_id, + new_folder_type, + name, + gAgent.getID()); + + + LLSD new_llsd = new_cat->asLLSD(); + AISAPI::completion_t cr = boost::bind(&doInventoryCb, (LLPointer) NULL, _1); + AISAPI::UpdateCategory(folder_id, new_llsd, cr); + } + else + { + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_UpdateInventoryFolder); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_FolderData); + msg->addUUIDFast(_PREHASH_FolderID, folder_id); + msg->addUUIDFast(_PREHASH_ParentID, parent_id); + msg->addS8Fast(_PREHASH_Type, new_folder_type); + msg->addStringFast(_PREHASH_Name, name); + gAgent.sendReliableMessage(); + } setPreferredType(new_folder_type); gInventory.addChangedMask(LLInventoryObserver::LABEL, folder_id); @@ -846,6 +939,21 @@ void LLViewerInventoryCategory::localizeName() LLLocalizedInventoryItemsDictionary::getInstance()->localizeInventoryObjectName(mName); } +// virtual +BOOL LLViewerInventoryCategory::unpackMessage(const LLSD& category) +{ + BOOL rv = LLInventoryCategory::fromLLSD(category); + localizeName(); + return rv; +} + +// virtual +void LLViewerInventoryCategory::unpackMessage(LLMessageSystem* msg, const char* block, S32 block_num) +{ + LLInventoryCategory::unpackMessage(msg, block, block_num); + localizeName(); +} + ///---------------------------------------------------------------------------- /// Local function definitions ///---------------------------------------------------------------------------- @@ -857,7 +965,7 @@ LLInventoryCallbackManager::LLInventoryCallbackManager() : { if( sInstance != NULL ) { - llwarns << "LLInventoryCallbackManager::LLInventoryCallbackManager: unexpected multiple instances" << llendl; + LL_WARNS(LOG_INV) << "LLInventoryCallbackManager::LLInventoryCallbackManager: unexpected multiple instances" << LL_ENDL; return; } sInstance = this; @@ -867,7 +975,7 @@ LLInventoryCallbackManager::~LLInventoryCallbackManager() { if( sInstance != this ) { - llwarns << "LLInventoryCallbackManager::~LLInventoryCallbackManager: unexpected multiple instances" << llendl; + LL_WARNS(LOG_INV) << "LLInventoryCallbackManager::~LLInventoryCallbackManager: unexpected multiple instances" << LL_ENDL; return; } sInstance = NULL; @@ -878,10 +986,10 @@ void LLInventoryCallbackManager::destroyClass() { if (sInstance) { - for (callback_map_t::iterator it = sInstance->mMap.begin(), end_it = sInstance->mMap.end(); it != end_it; ++it) + for (auto& it : sInstance->mMap) { // drop LLPointer reference to callback - it->second = NULL; + it.second = NULL; } sInstance->mMap.clear(); } @@ -917,7 +1025,7 @@ void LLInventoryCallbackManager::fire(U32 callback_id, const LLUUID& item_id) } //void rez_attachment_cb(const LLUUID& inv_item, LLViewerJointAttachment *attachmentp) -// [SL:KB] - Patch: Appearance-DnDWear | Checked: 2010-09-28 (Catznip-3.0.0a) | Added: Catznip-2.2.0a +// [SL:KB] - Patch: Appearance-DnDWear | Checked: 2010-09-28 (Catznip-3.4) void rez_attachment_cb(const LLUUID& inv_item, LLViewerJointAttachment *attachmentp, bool replace) // [/SL:KB] { @@ -927,10 +1035,10 @@ void rez_attachment_cb(const LLUUID& inv_item, LLViewerJointAttachment *attachme LLViewerInventoryItem *item = gInventory.getItem(inv_item); if (item) { -// rez_attachment(item, attachmentp); -// [SL:KB] - Patch: Appearance-DnDWear | Checked: 2010-09-28 (Catznip-3.0.0a) | Added: Catznip-2.2.0a +// [SL:KB] - Patch: Appearance-DnDWear | Checked: 2010-09-28 (Catznip-3.4) rez_attachment(item, attachmentp, replace); // [/SL:KB] +// rez_attachment(item, attachmentp); } } @@ -947,31 +1055,77 @@ void activate_gesture_cb(const LLUUID& inv_item) LLGestureMgr::instance().activateGesture(inv_item); } -void create_gesture_cb(const LLUUID& inv_item) +void set_default_permissions(LLViewerInventoryItem* item, std::string perm_type) { - if (inv_item.isNull()) - return; + llassert(item); + LLPermissions perm = item->getPermissions(); + if (perm.getMaskEveryone() != LLFloaterPerms::getEveryonePerms(perm_type) + || perm.getMaskGroup() != LLFloaterPerms::getGroupPerms(perm_type)) + { + perm.setMaskEveryone(LLFloaterPerms::getEveryonePerms(perm_type)); + perm.setMaskGroup(LLFloaterPerms::getGroupPerms(perm_type)); - LLGestureMgr::instance().activateGesture(inv_item); - - LLViewerInventoryItem* item = gInventory.getItem(inv_item); - if (!item) return; - gInventory.updateItem(item); - gInventory.notifyObservers(); + item->setPermissions(perm); + + item->updateServer(FALSE); + } +} + +void create_script_cb(const LLUUID& inv_item) +{ + if (!inv_item.isNull()) + { + LLViewerInventoryItem* item = gInventory.getItem(inv_item); + if (item) + { + set_default_permissions(item, "Scripts"); + + // item was just created, update even if permissions did not changed + gInventory.updateItem(item); + gInventory.notifyObservers(); + } + } +} - if(!LLPreview::show(inv_item,FALSE)) +void create_gesture_cb(const LLUUID& inv_item) +{ + if (!inv_item.isNull()) { - LLPreviewGesture* preview = LLPreviewGesture::show(std::string("Gesture: ") + item->getName(), inv_item, LLUUID::null); - // Force to be entirely onscreen. - gFloaterView->adjustToFitScreen(preview, FALSE); + LLGestureMgr::instance().activateGesture(inv_item); + + LLViewerInventoryItem* item = gInventory.getItem(inv_item); + if (item) + { + set_default_permissions(item, "Gestures"); + + gInventory.updateItem(item); + gInventory.notifyObservers(); + + + if (!LLPreview::show(inv_item,FALSE)) + { + LLPreviewGesture* preview = LLPreviewGesture::show(std::string("Gesture: ") + item->getName(), inv_item, LLUUID::null); + // Force to be entirely onscreen. + gFloaterView->adjustToFitScreen(preview, FALSE); + } + } } } -void AddFavoriteLandmarkCallback::fire(const LLUUID& inv_item_id) + +void create_notecard_cb(const LLUUID& inv_item) { - if (mTargetLandmarkId.isNull()) return; + if (!inv_item.isNull()) + { + LLViewerInventoryItem* item = gInventory.getItem(inv_item); + if (item) + { + set_default_permissions(item, "Notecards"); - //gInventory.rearrangeFavoriteLandmarks(inv_item_id, mTargetLandmarkId); // MULTI-WEARABLES TODO + gInventory.updateItem(item); + gInventory.notifyObservers(); + } + } } LLInventoryCallbackManager gInventoryCallbacks; @@ -1025,10 +1179,10 @@ void create_inventory_item(const LLUUID& agent_id, const LLUUID& session_id, void create_inventory_callingcard(const LLUUID& avatar_id, const LLUUID& parent /*= LLUUID::null*/, LLPointer cb/*=NULL*/) { std::string item_desc = avatar_id.asString(); - std::string item_name; - gCacheName->getFullName(avatar_id, item_name); + LLAvatarName av_name; + LLAvatarNameCache::get(avatar_id, &av_name); create_inventory_item(gAgent.getID(), gAgent.getSessionID(), - parent, LLTransactionID::tnull, item_name, item_desc, LLAssetType::AT_CALLINGCARD, + parent, LLTransactionID::tnull, av_name.getLegacyName(), item_desc, LLAssetType::AT_CALLINGCARD, LLInventoryType::IT_CALLINGCARD, NOT_WEARABLE, PERM_MOVE | PERM_TRANSFER, cb); } @@ -1054,70 +1208,146 @@ void copy_inventory_item( gAgent.sendReliableMessage(); } -void link_inventory_item( - const LLUUID& agent_id, - const LLUUID& item_id, - const LLUUID& parent_id, - const std::string& new_name, - const std::string& new_description, - const LLAssetType::EType asset_type, - LLPointer cb) +// Create link to single inventory object. +void link_inventory_object(const LLUUID& category, + LLConstPointer baseobj, + LLPointer cb) { - const LLInventoryObject *baseobj = gInventory.getObject(item_id); if (!baseobj) { - llwarns << "attempt to link to unknown item, linked-to-item's itemID " << item_id << llendl; - return; - } - if (baseobj && baseobj->getIsLinkType()) - { - llwarns << "attempt to create a link to a link, linked-to-item's itemID " << item_id << llendl; + LL_WARNS(LOG_INV) << "Attempt to link to non-existent object" << LL_ENDL; return; } - if (baseobj && !LLAssetType::lookupCanLink(baseobj->getType())) - { - // Fail if item can be found but is of a type that can't be linked. - // Arguably should fail if the item can't be found too, but that could - // be a larger behavioral change. - llwarns << "attempt to link an unlinkable item, type = " << baseobj->getActualType() << llendl; - return; - } - - LLUUID transaction_id; - LLInventoryType::EType inv_type = LLInventoryType::IT_NONE; - if (dynamic_cast(baseobj)) - { - inv_type = LLInventoryType::IT_CATEGORY; - } - else + LLInventoryObject::const_object_list_t obj_array; + obj_array.push_back(baseobj); + link_inventory_array(category, obj_array, cb); +} + +void link_inventory_object(const LLUUID& category, + const LLUUID& id, + LLPointer cb) +{ + LLConstPointer baseobj = gInventory.getObject(id); + link_inventory_object(category, baseobj, cb); +} + +// Create links to all listed inventory objects. +void link_inventory_array(const LLUUID& category, + LLInventoryObject::const_object_list_t& baseobj_array, + LLPointer cb) +{ +#ifndef LL_RELEASE_FOR_DOWNLOAD + const LLViewerInventoryCategory *cat = gInventory.getCategory(category); + const std::string cat_name = cat ? cat->getName() : "CAT NOT FOUND"; +#endif + LLInventoryObject::const_object_list_t::const_iterator it = baseobj_array.begin(); + LLInventoryObject::const_object_list_t::const_iterator end = baseobj_array.end(); + LLSD links = LLSD::emptyArray(); + for (; it != end; ++it) { - const LLViewerInventoryItem *baseitem = dynamic_cast(baseobj); - if (baseitem) + const LLInventoryObject* baseobj = *it; + if (!baseobj) + { + LL_WARNS(LOG_INV) << "attempt to link to unknown object" << LL_ENDL; + continue; + } + + if (!LLAssetType::lookupCanLink(baseobj->getType())) + { + // Fail if item can be found but is of a type that can't be linked. + // Arguably should fail if the item can't be found too, but that could + // be a larger behavioral change. + LL_WARNS(LOG_INV) << "attempt to link an unlinkable object, type = " << baseobj->getActualType() << LL_ENDL; + continue; + } + + LLInventoryType::EType inv_type = LLInventoryType::IT_NONE; + LLAssetType::EType asset_type = LLAssetType::AT_NONE; + std::string new_desc; + LLUUID linkee_id; + if (dynamic_cast(baseobj)) + { + inv_type = LLInventoryType::IT_CATEGORY; + asset_type = LLAssetType::AT_LINK_FOLDER; + linkee_id = baseobj->getUUID(); + } + else { - inv_type = baseitem->getInventoryType(); + const LLViewerInventoryItem *baseitem = dynamic_cast(baseobj); + if (baseitem) + { + inv_type = baseitem->getInventoryType(); + new_desc = baseitem->getActualDescription(); + switch (baseitem->getActualType()) + { + case LLAssetType::AT_LINK: + case LLAssetType::AT_LINK_FOLDER: + linkee_id = baseobj->getLinkedUUID(); + asset_type = baseitem->getActualType(); + break; + default: + linkee_id = baseobj->getUUID(); + asset_type = LLAssetType::AT_LINK; + break; + } + } + else + { + LL_WARNS(LOG_INV) << "could not convert object into an item or category: " << baseobj->getUUID() << LL_ENDL; + continue; + } } + + LLSD link = LLSD::emptyMap(); + link["linked_id"] = linkee_id; + link["type"] = (S8)asset_type; + link["inv_type"] = (S8)inv_type; + link["name"] = baseobj->getName(); + link["desc"] = new_desc; + links.append(link); + +#ifndef LL_RELEASE_FOR_DOWNLOAD + LL_DEBUGS(LOG_INV) << "Linking Object [ name:" << baseobj->getName() + << " UUID:" << baseobj->getUUID() + << " ] into Category [ name:" << cat_name + << " UUID:" << category << " ] " << LL_ENDL; +#endif } - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_LinkInventoryItem); - msg->nextBlock(_PREHASH_AgentData); + if (AISAPI::isAvailable()) { - msg->addUUIDFast(_PREHASH_AgentID, agent_id); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + LLSD new_inventory = LLSD::emptyMap(); + new_inventory["links"] = links; + AISAPI::completion_t cr = boost::bind(&doInventoryCb, cb, _1); + AISAPI::CreateInventory(category, new_inventory, cr); } - msg->nextBlock(_PREHASH_InventoryBlock); + else { - msg->addU32Fast(_PREHASH_CallbackID, gInventoryCallbacks.registerCB(cb)); - msg->addUUIDFast(_PREHASH_FolderID, parent_id); - msg->addUUIDFast(_PREHASH_TransactionID, transaction_id); - msg->addUUIDFast(_PREHASH_OldItemID, item_id); - msg->addS8Fast(_PREHASH_Type, (S8)asset_type); - msg->addS8Fast(_PREHASH_InvType, (S8)inv_type); - msg->addStringFast(_PREHASH_Name, new_name); - msg->addStringFast(_PREHASH_Description, new_description); + LLMessageSystem* msg = gMessageSystem; + for (LLSD::array_iterator iter = links.beginArray(); iter != links.endArray(); ++iter ) + { + msg->newMessageFast(_PREHASH_LinkInventoryItem); + msg->nextBlock(_PREHASH_AgentData); + { + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + } + msg->nextBlock(_PREHASH_InventoryBlock); + { + LLSD link = (*iter); + msg->addU32Fast(_PREHASH_CallbackID, gInventoryCallbacks.registerCB(cb)); + msg->addUUIDFast(_PREHASH_FolderID, category); + msg->addUUIDFast(_PREHASH_TransactionID, LLUUID::null); + msg->addUUIDFast(_PREHASH_OldItemID, link["linked_id"].asUUID()); + msg->addS8Fast(_PREHASH_Type, link["type"].asInteger()); + msg->addS8Fast(_PREHASH_InvType, link["inv_type"].asInteger()); + msg->addStringFast(_PREHASH_Name, link["name"].asString()); + msg->addStringFast(_PREHASH_Description, link["desc"].asString()); + } + gAgent.sendReliableMessage(); + } } - gAgent.sendReliableMessage(); } void move_inventory_item( @@ -1141,11 +1371,410 @@ void move_inventory_item( gAgent.sendReliableMessage(); } -const LLUUID get_folder_by_itemtype(const LLInventoryItem *src) +// Should call this with an update_item that's been copied and +// modified from an original source item, rather than modifying the +// source item directly. +void update_inventory_item( + LLViewerInventoryItem *update_item, + LLPointer cb) { - LLUUID retval = LLUUID::null; - - if (src) + const LLUUID& item_id = update_item->getUUID(); + if (AISAPI::isAvailable()) + { + LLSD updates = update_item->asLLSD(); + // Replace asset_id and/or shadow_id with transaction_id (hash_id) + if (updates.has("asset_id")) + { + updates.erase("asset_id"); + if (update_item->getTransactionID().notNull()) + { + updates["hash_id"] = update_item->getTransactionID(); + } + } + if (updates.has("shadow_id")) + { + updates.erase("shadow_id"); + if (update_item->getTransactionID().notNull()) + { + updates["hash_id"] = update_item->getTransactionID(); + } + } + AISAPI::completion_t cr = boost::bind(&doInventoryCb, cb, _1); + AISAPI::UpdateItem(item_id, updates, cr); + } + else + { + LLPointer obj = gInventory.getItem(item_id); + LL_DEBUGS(LOG_INV) << "item_id: [" << item_id << "] name " << (update_item ? update_item->getName() : "(NOT FOUND)") << LL_ENDL; + if(obj) + { + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_UpdateInventoryItem); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addUUIDFast(_PREHASH_TransactionID, update_item->getTransactionID()); + msg->nextBlockFast(_PREHASH_InventoryData); + msg->addU32Fast(_PREHASH_CallbackID, 0); + update_item->packMessage(msg); + gAgent.sendReliableMessage(); + + LLInventoryModel::LLCategoryUpdate up(update_item->getParentUUID(), 0); + gInventory.accountForUpdate(up); + gInventory.updateItem(update_item); + if (cb) + { + cb->fire(item_id); + } + } + } +} + +// Note this only supports updating an existing item. Goes through AISv3 +// code path where available. Not all uses of item->updateServer() can +// easily be switched to this paradigm. +void update_inventory_item( + const LLUUID& item_id, + const LLSD& updates, + LLPointer cb) +{ + if (AISAPI::isAvailable()) + { + AISAPI::completion_t cr = boost::bind(&doInventoryCb, cb, _1); + AISAPI::UpdateItem(item_id, updates, cr); + } + else + { + LLPointer obj = gInventory.getItem(item_id); + LL_DEBUGS(LOG_INV) << "item_id: [" << item_id << "] name " << (obj ? obj->getName() : "(NOT FOUND)") << LL_ENDL; + if(obj) + { + LLPointer new_item(new LLViewerInventoryItem); + new_item->copyViewerItem(obj); + new_item->fromLLSD(updates,false); + + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_UpdateInventoryItem); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addUUIDFast(_PREHASH_TransactionID, new_item->getTransactionID()); + msg->nextBlockFast(_PREHASH_InventoryData); + msg->addU32Fast(_PREHASH_CallbackID, 0); + new_item->packMessage(msg); + gAgent.sendReliableMessage(); + + LLInventoryModel::LLCategoryUpdate up(new_item->getParentUUID(), 0); + gInventory.accountForUpdate(up); + gInventory.updateItem(new_item); + if (cb) + { + cb->fire(item_id); + } + } + } +} + +void update_inventory_category( + const LLUUID& cat_id, + const LLSD& updates, + LLPointer cb) +{ + LLPointer obj = gInventory.getCategory(cat_id); + LL_DEBUGS(LOG_INV) << "cat_id: [" << cat_id << "] name " << (obj ? obj->getName() : "(NOT FOUND)") << LL_ENDL; + if(obj) + { + if (LLFolderType::lookupIsProtectedType(obj->getPreferredType())) + { + LLNotificationsUtil::add("CannotModifyProtectedCategories"); + return; + } + + LLPointer new_cat = new LLViewerInventoryCategory(obj); + new_cat->fromLLSD(updates); + if (AISAPI::isAvailable()) + { + LLSD new_llsd = new_cat->asLLSD(); + AISAPI::completion_t cr = boost::bind(&doInventoryCb, cb, _1); + AISAPI::UpdateCategory(cat_id, new_llsd, cr); + } + else // no cap + { + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_UpdateInventoryFolder); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_FolderData); + new_cat->packMessage(msg); + gAgent.sendReliableMessage(); + + LLInventoryModel::LLCategoryUpdate up(new_cat->getParentUUID(), 0); + gInventory.accountForUpdate(up); + gInventory.updateCategory(new_cat); + if (cb) + { + cb->fire(cat_id); + } + } + } +} + +void remove_inventory_items( + LLInventoryObject::object_list_t& items_to_kill, + LLPointer cb + ) +{ + for (auto& it : items_to_kill) + { + remove_inventory_item(it, cb); + } +} + +void remove_inventory_item( + const LLUUID& item_id, + LLPointer cb, + bool immediate_delete) +{ + LLPointer obj = gInventory.getItem(item_id); + if (obj) + { + remove_inventory_item(obj, cb, immediate_delete); + } + else + { + LL_DEBUGS(LOG_INV) << "item_id: [" << item_id << "] name " << "(NOT FOUND)" << LL_ENDL; + } +} + +void remove_inventory_item( + LLPointer obj, + LLPointer cb, + bool immediate_delete) +{ + if(obj) + { + const LLUUID item_id(obj->getUUID()); + LL_DEBUGS(LOG_INV) << "item_id: [" << item_id << "] name " << obj->getName() << LL_ENDL; + if (AISAPI::isAvailable()) + { + AISAPI::completion_t cr = (cb) ? boost::bind(&doInventoryCb, cb, _1) : AISAPI::completion_t(); + AISAPI::RemoveItem(item_id, cr); + + if (immediate_delete) + { + gInventory.onObjectDeletedFromServer(item_id); + } + } + else // no cap + { + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_RemoveInventoryItem); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_InventoryData); + msg->addUUIDFast(_PREHASH_ItemID, item_id); + gAgent.sendReliableMessage(); + + // Update inventory and call callback immediately since + // message-based system has no callback mechanism (!) + gInventory.onObjectDeletedFromServer(item_id); + if (cb) + { + cb->fire(item_id); + } + } + } + else + { + // *TODO: Clean up callback? + LL_WARNS(LOG_INV) << "remove_inventory_item called for invalid or nonexistent item." << LL_ENDL; + } +} + +class LLRemoveCategoryOnDestroy: public LLInventoryCallback +{ +public: + LLRemoveCategoryOnDestroy(const LLUUID& cat_id, LLPointer cb): + mID(cat_id), + mCB(cb) + { + } + /* virtual */ void fire(const LLUUID& item_id) override {} + ~LLRemoveCategoryOnDestroy() + { + LLInventoryModel::EHasChildren children = gInventory.categoryHasChildren(mID); + if(children != LLInventoryModel::CHILDREN_NO) + { + LL_WARNS(LOG_INV) << "remove descendents failed, cannot remove category " << LL_ENDL; + } + else + { + remove_inventory_category(mID, mCB); + } + } +private: + LLUUID mID; + LLPointer mCB; +}; + +void remove_inventory_category( + const LLUUID& cat_id, + LLPointer cb) +{ + LL_DEBUGS(LOG_INV) << "cat_id: [" << cat_id << "] " << LL_ENDL; + LLPointer obj = gInventory.getCategory(cat_id); + if(obj) + { + if (!gInventory.isCategoryComplete(cat_id)) + { + LL_WARNS() << "Removing (purging) incomplete category " << obj->getName() << LL_ENDL; + } + if(LLFolderType::lookupIsProtectedType(obj->getPreferredType())) + { + LLNotificationsUtil::add("CannotRemoveProtectedCategories"); + return; + } + if (AISAPI::isAvailable()) + { + AISAPI::completion_t cr = boost::bind(&doInventoryCb, cb, _1); + AISAPI::RemoveCategory(cat_id, cr); + } + else // no cap + { + // RemoveInventoryFolder does not remove children, so must + // clear descendents first. + LLInventoryModel::EHasChildren children = gInventory.categoryHasChildren(cat_id); + if(children != LLInventoryModel::CHILDREN_NO) + { + LL_DEBUGS(LOG_INV) << "Will purge descendents first before deleting category " << cat_id << LL_ENDL; + LLPointer wrap_cb = new LLRemoveCategoryOnDestroy(cat_id, cb); + purge_descendents_of(cat_id, wrap_cb); + return; + } + + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_RemoveInventoryFolder); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_FolderData); + msg->addUUIDFast(_PREHASH_FolderID, cat_id); + gAgent.sendReliableMessage(); + + // Update inventory and call callback immediately since + // message-based system has no callback mechanism (!) + gInventory.onObjectDeletedFromServer(cat_id); + if (cb) + { + cb->fire(cat_id); + } + } + } + else + { + LL_WARNS(LOG_INV) << "remove_inventory_category called for invalid or nonexistent item " << cat_id << LL_ENDL; + } +} + +void remove_inventory_object( + const LLUUID& object_id, + LLPointer cb) +{ + if (gInventory.getCategory(object_id)) + { + remove_inventory_category(object_id, cb); + } + else + { + remove_inventory_item(object_id, cb); + } +} + +// This is a method which collects the descendents of the id +// provided. If the category is not found, no action is +// taken. This method goes through the long winded process of +// cancelling any calling cards, removing server representation of +// folders, items, etc in a fairly efficient manner. +void purge_descendents_of(const LLUUID& id, LLPointer cb) +{ + LLInventoryModel::EHasChildren children = gInventory.categoryHasChildren(id); + if(children == LLInventoryModel::CHILDREN_NO) + { + LL_DEBUGS(LOG_INV) << "No descendents to purge for " << id << LL_ENDL; + return; + } + LLPointer cat = gInventory.getCategory(id); + if (cat.notNull()) + { + if (LLInventoryClipboard::instance().hasContents() && LLInventoryClipboard::instance().isCutMode()) + { + // Something on the clipboard is in "cut mode" and needs to be preserved + LL_DEBUGS(LOG_INV) << "purge_descendents_of clipboard case " << cat->getName() + << " iterate and purge non hidden items" << LL_ENDL; + LLInventoryModel::cat_array_t* categories; + LLInventoryModel::item_array_t* items; + // Get the list of direct descendants in tha categoy passed as argument + gInventory.getDirectDescendentsOf(id, categories, items); + uuid_vec_t list_uuids; + // Make a unique list with all the UUIDs of the direct descendants (items and categories are not treated differently) + // Note: we need to do that shallow copy as purging things will invalidate the categories or items lists + for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin(); it != categories->end(); ++it) + { + list_uuids.push_back((*it)->getUUID()); + } + for (LLInventoryModel::item_array_t::const_iterator it = items->begin(); it != items->end(); ++it) + { + list_uuids.push_back((*it)->getUUID()); + } + // Iterate through the list and only purge the UUIDs that are not on the clipboard + for (auto it = list_uuids.begin(); it != list_uuids.end(); ++it) + { + if (!LLInventoryClipboard::instance().isOnClipboard(*it)) + { + remove_inventory_object(*it, NULL); + } + } + } + else + { + if (AISAPI::isAvailable()) + { + AISAPI::completion_t cr = (cb) ? boost::bind(&doInventoryCb, cb, _1) : AISAPI::completion_t(); + AISAPI::PurgeDescendents(id, cr); + } + else // no cap + { + // Fast purge + LL_DEBUGS(LOG_INV) << "purge_descendents_of fast case " << cat->getName() << LL_ENDL; + + // send it upstream + LLMessageSystem* msg = gMessageSystem; + msg->newMessage("PurgeInventoryDescendents"); + msg->nextBlock("AgentData"); + msg->addUUID("AgentID", gAgent.getID()); + msg->addUUID("SessionID", gAgent.getSessionID()); + msg->nextBlock("InventoryData"); + msg->addUUID("FolderID", id); + gAgent.sendReliableMessage(); + + // Update model immediately because there is no callback mechanism. + gInventory.onDescendentsPurgedFromServer(id); + if (cb) + { + cb->fire(id); + } + } + } + } +} + +const LLUUID get_folder_by_itemtype(const LLInventoryItem *src) +{ + LLUUID retval = LLUUID::null; + + if (src) { retval = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(src->getType())); } @@ -1161,9 +1790,9 @@ void copy_inventory_from_notecard(const LLUUID& destination_id, { if (NULL == src) { - LL_WARNS("copy_inventory_from_notecard") << "Null pointer to item was passed for object_id " - << object_id << " and notecard_inv_id " - << notecard_inv_id << LL_ENDL; + LL_WARNS(LOG_NOTECARD) << "Null pointer to item was passed for object_id " + << object_id << " and notecard_inv_id " + << notecard_inv_id << LL_ENDL; return; } @@ -1183,9 +1812,9 @@ void copy_inventory_from_notecard(const LLUUID& destination_id, if (! viewer_region) { - LL_WARNS("copy_inventory_from_notecard") << "Can't find region from object_id " - << object_id << " or gAgent" - << LL_ENDL; + LL_WARNS(LOG_NOTECARD) << "Can't find region from object_id " + << object_id << " or gAgent" + << LL_ENDL; return; } @@ -1193,8 +1822,8 @@ void copy_inventory_from_notecard(const LLUUID& destination_id, std::string url = viewer_region->getCapability("CopyInventoryFromNotecard"); if (url.empty()) { - LL_WARNS("copy_inventory_from_notecard") << "There is no 'CopyInventoryFromNotecard' capability" - << " for region: " << viewer_region->getName() + LL_WARNS(LOG_NOTECARD) << "There is no 'CopyInventoryFromNotecard' capability" + << " for region: " << viewer_region->getName() << LL_ENDL; return; } @@ -1222,23 +1851,171 @@ void create_new_item(const std::string& name, LLViewerAssetType::generateDescriptionFor(asset_type, desc); next_owner_perm = (next_owner_perm) ? next_owner_perm : PERM_MOVE | PERM_TRANSFER; - - if (inv_type == LLInventoryType::IT_GESTURE) + LLPointer cb = nullptr; + + switch (inv_type) { - LLPointer cb = new LLBoostFuncInventoryCallback(create_gesture_cb); - create_inventory_item(gAgent.getID(), gAgent.getSessionID(), - parent_id, LLTransactionID::tnull, name, desc, asset_type, inv_type, - NOT_WEARABLE, next_owner_perm, cb); + case LLInventoryType::IT_LSL: + { + cb = new LLBoostFuncInventoryCallback(create_script_cb); + next_owner_perm = LLFloaterPerms::getNextOwnerPerms("Scripts"); + break; + } + + case LLInventoryType::IT_GESTURE: + { + cb = new LLBoostFuncInventoryCallback(create_gesture_cb); + next_owner_perm = LLFloaterPerms::getNextOwnerPerms("Gestures"); + break; + } + + case LLInventoryType::IT_NOTECARD: + { + cb = new LLBoostFuncInventoryCallback(create_notecard_cb); + next_owner_perm = LLFloaterPerms::getNextOwnerPerms("Notecards"); + break; + } + default: + break; } - else + + create_inventory_item(gAgent.getID(), + gAgent.getSessionID(), + parent_id, + LLTransactionID::tnull, + name, + desc, + asset_type, + inv_type, + NOT_WEARABLE, + next_owner_perm, + cb); +} + +// [RLVa:KB] - Checked: 2014-11-02 (RLVa-1.4.11) +void sync_inventory_folder(const LLUUID& folder_id, const LLInventoryModel::item_array_t& items, LLInventoryModel::item_array_t& items_to_add, LLInventoryModel::item_array_t& items_to_remove) +{ + LLInventoryModel::item_array_t curItems, newItems = items; + + // Grab the current contents + LLInventoryModel::cat_array_t cats; + gInventory.collectDescendents(folder_id, cats, curItems, LLInventoryModel::EXCLUDE_TRASH); + + // Purge everything in curItems that isn't part of newItems + for (LLInventoryModel::item_array_t::const_iterator itCurItem = curItems.begin(); itCurItem != curItems.end(); ++itCurItem) { - LLPointer cb = NULL; - create_inventory_item(gAgent.getID(), gAgent.getSessionID(), - parent_id, LLTransactionID::tnull, name, desc, asset_type, inv_type, - NOT_WEARABLE, next_owner_perm, cb); + LLViewerInventoryItem* pItem = *itCurItem; + if (std::find_if(newItems.begin(), newItems.end(), RlvPredIsEqualOrLinkedItem(pItem)) == newItems.end()) + { + // Item doesn't exist in newItems => purge (if it's a link) + if ( (pItem->getIsLinkType()) && + (LLAssetType::AT_LINK_FOLDER != pItem->getActualType()) && + (items_to_remove.end() == std::find(items_to_remove.begin(), items_to_remove.end(), pItem)) ) + { + items_to_remove.push_back(pItem); + } + } + else + { + // Item exists in newItems => remove *all* occurances in newItems (removes duplicate COF links to this item as well) + newItems.erase(std::remove_if(newItems.begin(), newItems.end(), RlvPredIsEqualOrLinkedItem(pItem)), newItems.end()); + } } - -} + + // Whatever remains in newItems will need to have a link created + for (LLInventoryModel::item_array_t::const_iterator itNewItem = newItems.begin(); itNewItem != newItems.end(); ++itNewItem) + { + LLViewerInventoryItem* pItem = *itNewItem; + if (items_to_add.end() == std::find(items_to_add.begin(), items_to_add.end(), pItem)) + items_to_add.push_back(pItem); + } +} + +void link_inventory_items(const LLUUID& folder_id, const LLInventoryModel::item_array_t& items, LLPointer cb) +{ + for (LLInventoryModel::item_array_t::const_iterator itItem = items.begin(); itItem != items.end(); ++itItem) + { + const LLViewerInventoryItem* pItem = *itItem; + link_inventory_object(folder_id, pItem, cb); + } +} + +void remove_inventory_items(const LLInventoryModel::item_array_t& items, LLPointer cb) +{ + for (LLInventoryModel::item_array_t::const_iterator itItem = items.begin(); itItem != items.end(); ++itItem) + { + const LLViewerInventoryItem* pItem = *itItem; + if (pItem->getIsLinkType()) + remove_inventory_item(pItem->getUUID(), cb); + } +} +// [/RLVa:KB] + +void slam_inventory_folder(const LLUUID& folder_id, + const LLSD& contents, + LLPointer cb) +{ + if (AISAPI::isAvailable()) + { + LL_DEBUGS(LOG_INV) << "using AISv3 to slam folder, id " << folder_id + << " new contents: " << ll_pretty_print_sd(contents) << LL_ENDL; + + AISAPI::completion_t cr = boost::bind(&doInventoryCb, cb, _1); + AISAPI::SlamFolder(folder_id, contents, cr); + } + else // no cap + { +// [RLVa:KB] - Checked: 2014-11-02 (RLVa-1.4.11) + LL_DEBUGS(LOG_INV) << "using item-by-item calls to slam folder, id " << folder_id + << " new contents: " << ll_pretty_print_sd(contents) << LL_ENDL; + + LLInventoryModel::item_array_t items; + for (LLSD::array_const_iterator itItem = contents.beginArray(); itItem != contents.endArray(); ++itItem) + { + LLViewerInventoryItem* pItem = new LLViewerInventoryItem; + pItem->fromLLSD(*itItem); + items.push_back(pItem); + } + + LLInventoryModel::item_array_t items_to_add, items_to_remove; + sync_inventory_folder(folder_id, items, items_to_add, items_to_remove); + + link_inventory_items(folder_id, items_to_add, cb); + remove_inventory_items(items_to_remove, cb); +// [/RLVa:KB] +// LL_DEBUGS(LOG_INV) << "using item-by-item calls to slam folder, id " << folder_id +// << " new contents: " << ll_pretty_print_sd(contents) << LL_ENDL; +// for (LLSD::array_const_iterator it = contents.beginArray(); +// it != contents.endArray(); +// ++it) +// { +// const LLSD& item_contents = *it; +// LLViewerInventoryItem *item = new LLViewerInventoryItem; +// item->fromLLSD(item_contents); +// link_inventory_object(folder_id, item, cb); +// } +// remove_folder_contents(folder_id,false,cb); + } +} + +void remove_folder_contents(const LLUUID& category, bool keep_outfit_links, + LLPointer cb) +{ + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + gInventory.collectDescendents(category, cats, items, + LLInventoryModel::EXCLUDE_TRASH); + for (auto& i : items) + { + LLViewerInventoryItem *item = i; + if (keep_outfit_links && (item->getActualType() == LLAssetType::AT_LINK_FOLDER)) + continue; + if (item->getIsLinkType()) + { + remove_inventory_item(item->getUUID(), cb); + } + } +} const std::string NEW_LSL_NAME = "New Script"; // *TODO:Translate? (probably not) const std::string NEW_NOTECARD_NAME = "New Note"; // *TODO:Translate? (probably not) @@ -1278,7 +2055,7 @@ const std::string NEW_GESTURE_NAME = "New Gesture"; // *TODO:Translate? (probabl parent_id, LLAssetType::AT_LSL_TEXT, LLInventoryType::IT_LSL, - PERM_MOVE | PERM_TRANSFER); + PERM_MOVE | PERM_TRANSFER); // overridden in create_new_item } else if ("notecard" == type_name) { @@ -1287,7 +2064,7 @@ const std::string NEW_GESTURE_NAME = "New Gesture"; // *TODO:Translate? (probabl parent_id, LLAssetType::AT_NOTECARD, LLInventoryType::IT_NOTECARD, - PERM_ALL); + PERM_ALL); // overridden in create_new_item } else if ("gesture" == type_name) { @@ -1296,7 +2073,7 @@ const std::string NEW_GESTURE_NAME = "New Gesture"; // *TODO:Translate? (probabl parent_id, LLAssetType::AT_GESTURE, LLInventoryType::IT_GESTURE, - PERM_ALL); + PERM_ALL); // overridden in create_new_item } else { @@ -1309,7 +2086,7 @@ const std::string NEW_GESTURE_NAME = "New Gesture"; // *TODO:Translate? (probabl } else { - llwarns << "Can't create unrecognized type " << type_name << llendl; + LL_WARNS(LOG_INV) << "Can't create unrecognized type " << type_name << LL_ENDL; } } root->setNeedsAutoRename(TRUE); @@ -1386,326 +2163,21 @@ const std::string& LLViewerInventoryItem::getName() const return LLInventoryItem::getName(); } -#if 0 -/** - * Class to store sorting order of favorites landmarks in a local file. EXT-3985. - * It replaced previously implemented solution to store sort index in landmark's name as a "@" prefix. - * Data are stored in user home directory. - */ -class LLFavoritesOrderStorage : public LLSingleton - , public LLDestroyClass -{ -public: - /** - * Sets sort index for specified with LLUUID favorite landmark - */ - void setSortIndex(const LLUUID& inv_item_id, S32 sort_index); - - /** - * Gets sort index for specified with LLUUID favorite landmark - */ - S32 getSortIndex(const LLUUID& inv_item_id); - void removeSortIndex(const LLUUID& inv_item_id); - - void getSLURL(const LLUUID& asset_id); - - /** - * Implementation of LLDestroyClass. Calls cleanup() instance method. - * - * It is important this callback is called before gInventory is cleaned. - * For now it is called from LLAppViewer::cleanup() -> LLAppViewer::disconnectViewer(), - * Inventory is cleaned later from LLAppViewer::cleanup() after LLAppViewer::disconnectViewer() is called. - * @see cleanup() - */ - static void destroyClass(); - - const static S32 NO_INDEX; -private: - friend class LLSingleton; - LLFavoritesOrderStorage() : mIsDirty(false) { load(); } - ~LLFavoritesOrderStorage() { save(); } - - /** - * Removes sort indexes for items which are not in Favorites bar for now. - */ - void cleanup(); - - const static std::string SORTING_DATA_FILE_NAME; - - void load(); - void save(); - - void saveFavoritesSLURLs(); - - // Remove record of current user's favorites from file on disk. - void removeFavoritesRecordOfUser(); - - void onLandmarkLoaded(const LLUUID& asset_id, LLLandmark* landmark); - void storeFavoriteSLURL(const LLUUID& asset_id, std::string& slurl); - - typedef std::map sort_index_map_t; - sort_index_map_t mSortIndexes; - - typedef std::map slurls_map_t; - slurls_map_t mSLURLs; - - bool mIsDirty; - - struct IsNotInFavorites - { - IsNotInFavorites(const LLInventoryModel::item_array_t& items) - : mFavoriteItems(items) - { - - } - - /** - * Returns true if specified item is not found among inventory items - */ - bool operator()(const sort_index_map_t::value_type& id_index_pair) const - { - LLPointer item = gInventory.getItem(id_index_pair.first); - if (item.isNull()) return true; - - LLInventoryModel::item_array_t::const_iterator found_it = - std::find(mFavoriteItems.begin(), mFavoriteItems.end(), item); - - return found_it == mFavoriteItems.end(); - } - private: - LLInventoryModel::item_array_t mFavoriteItems; - }; - -}; - -const std::string LLFavoritesOrderStorage::SORTING_DATA_FILE_NAME = "landmarks_sorting.xml"; -const S32 LLFavoritesOrderStorage::NO_INDEX = -1; - -void LLFavoritesOrderStorage::setSortIndex(const LLUUID& inv_item_id, S32 sort_index) -{ - mSortIndexes[inv_item_id] = sort_index; - mIsDirty = true; -} - -S32 LLFavoritesOrderStorage::getSortIndex(const LLUUID& inv_item_id) -{ - sort_index_map_t::const_iterator it = mSortIndexes.find(inv_item_id); - if (it != mSortIndexes.end()) - { - return it->second; - } - return NO_INDEX; -} - -void LLFavoritesOrderStorage::removeSortIndex(const LLUUID& inv_item_id) -{ - mSortIndexes.erase(inv_item_id); - mIsDirty = true; -} - -void LLFavoritesOrderStorage::getSLURL(const LLUUID& asset_id) -{ - slurls_map_t::iterator slurl_iter = mSLURLs.find(asset_id); - if (slurl_iter != mSLURLs.end()) return; // SLURL for current landmark is already cached - - LLLandmark* lm = gLandmarkList.getAsset(asset_id, - boost::bind(&LLFavoritesOrderStorage::onLandmarkLoaded, this, asset_id, _1)); - if (lm) - { - onLandmarkLoaded(asset_id, lm); - } -} - -// static -void LLFavoritesOrderStorage::destroyClass() -{ - LLFavoritesOrderStorage::instance().cleanup(); - if (gSavedPerAccountSettings.getBOOL("ShowFavoritesOnLogin")) - { - LLFavoritesOrderStorage::instance().saveFavoritesSLURLs(); - } - else - { - LLFavoritesOrderStorage::instance().removeFavoritesRecordOfUser(); - } -} - -void LLFavoritesOrderStorage::load() -{ - // load per-resident sorting information - std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, SORTING_DATA_FILE_NAME); - - LLSD settings_llsd; - llifstream file; - file.open(filename); - if (file.is_open()) - { - LLSDSerialize::fromXML(settings_llsd, file); - } - - for (LLSD::map_const_iterator iter = settings_llsd.beginMap(); - iter != settings_llsd.endMap(); ++iter) - { - mSortIndexes.insert(std::make_pair(LLUUID(iter->first), (S32)iter->second.asInteger())); - } -} - -void LLFavoritesOrderStorage::saveFavoritesSLURLs() -{ - // Do not change the file if we are not logged in yet. - if (!LLLoginInstance::getInstance()->authSuccess()) return; - - std::string user_dir = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""); - if (user_dir.empty()) return; - - std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "stored_favorites.xml"); - llifstream in_file; - in_file.open(filename); - LLSD fav_llsd; - if (in_file.is_open()) - { - LLSDSerialize::fromXML(fav_llsd, in_file); - } - - const LLUUID fav_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE); - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - gInventory.collectDescendents(fav_id, cats, items, LLInventoryModel::EXCLUDE_TRASH); - - LLSD user_llsd; - for (LLInventoryModel::item_array_t::iterator it = items.begin(); it != items.end(); it++) - { - LLSD value; - value["name"] = (*it)->getName(); - value["asset_id"] = (*it)->getAssetUUID(); - - slurls_map_t::iterator slurl_iter = mSLURLs.find(value["asset_id"]); - if (slurl_iter != mSLURLs.end()) - { - value["slurl"] = slurl_iter->second; - user_llsd[(*it)->getSortField()] = value; - } - } - - LLAvatarName av_name; - LLAvatarNameCache::get( gAgentID, &av_name ); - fav_llsd[av_name.getLegacyName()] = user_llsd; - - llofstream file; - file.open(filename); - LLSDSerialize::toPrettyXML(fav_llsd, file); -} - -void LLFavoritesOrderStorage::removeFavoritesRecordOfUser() -{ - std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "stored_favorites.xml"); - LLSD fav_llsd; - llifstream file; - file.open(filename); - if (!file.is_open()) return; - LLSDSerialize::fromXML(fav_llsd, file); - - LLAvatarName av_name; - LLAvatarNameCache::get( gAgentID, &av_name ); - if (fav_llsd.has(av_name.getLegacyName())) - { - fav_llsd.erase(av_name.getLegacyName()); - } - - llofstream out_file; - out_file.open(filename); - LLSDSerialize::toPrettyXML(fav_llsd, out_file); - -} - -void LLFavoritesOrderStorage::onLandmarkLoaded(const LLUUID& asset_id, LLLandmark* landmark) -{ - if (!landmark) return; - - LLVector3d pos_global; - if (!landmark->getGlobalPos(pos_global)) - { - // If global position was unknown on first getGlobalPos() call - // it should be set for the subsequent calls. - landmark->getGlobalPos(pos_global); - } - - if (!pos_global.isExactlyZero()) - { - LLLandmarkActions::getSLURLfromPosGlobal(pos_global, - boost::bind(&LLFavoritesOrderStorage::storeFavoriteSLURL, this, asset_id, _1)); - } -} - -void LLFavoritesOrderStorage::storeFavoriteSLURL(const LLUUID& asset_id, std::string& slurl) -{ - mSLURLs[asset_id] = slurl; -} - -void LLFavoritesOrderStorage::save() -{ - // nothing to save if clean - if (!mIsDirty) return; - - // If we quit from the login screen we will not have an SL account - // name. Don't try to save, otherwise we'll dump a file in - // C:\Program Files\SecondLife\ or similar. JC - std::string user_dir = gDirUtilp->getLindenUserDir(); - if (!user_dir.empty()) - { - std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, SORTING_DATA_FILE_NAME); - LLSD settings_llsd; - - for(sort_index_map_t::const_iterator iter = mSortIndexes.begin(); iter != mSortIndexes.end(); ++iter) - { - settings_llsd[iter->first.asString()] = iter->second; - } - - llofstream file; - file.open(filename); - LLSDSerialize::toPrettyXML(settings_llsd, file); - } -} - -void LLFavoritesOrderStorage::cleanup() -{ - // nothing to clean - if (!mIsDirty) return; - - const LLUUID fav_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE); - LLInventoryModel::cat_array_t cats; - LLInventoryModel::item_array_t items; - gInventory.collectDescendents(fav_id, cats, items, LLInventoryModel::EXCLUDE_TRASH); - - IsNotInFavorites is_not_in_fav(items); - - sort_index_map_t aTempMap; - //copy unremoved values from mSortIndexes to aTempMap - std::remove_copy_if(mSortIndexes.begin(), mSortIndexes.end(), - inserter(aTempMap, aTempMap.begin()), - is_not_in_fav); - - //Swap the contents of mSortIndexes and aTempMap - mSortIndexes.swap(aTempMap); -} - - S32 LLViewerInventoryItem::getSortField() const { return LLFavoritesOrderStorage::instance().getSortIndex(mUUID); } -void LLViewerInventoryItem::setSortField(S32 sortField) -{ - LLFavoritesOrderStorage::instance().setSortIndex(mUUID, sortField); - getSLURL(); -} +//void LLViewerInventoryItem::setSortField(S32 sortField) +//{ +// LLFavoritesOrderStorage::instance().setSortIndex(mUUID, sortField); +// getSLURL(); +//} void LLViewerInventoryItem::getSLURL() { LLFavoritesOrderStorage::instance().getSLURL(mAssetUUID); } -#endif const LLPermissions& LLViewerInventoryItem::getPermissions() const { @@ -1780,17 +2252,17 @@ LLWearableType::EType LLViewerInventoryItem::getWearableType() const { return LLWearableType::WT_INVALID; } - return LLWearableType::EType(getFlags() & LLInventoryItemFlags::II_FLAGS_WEARABLES_MASK); + return LLWearableType::inventoryFlagsToWearableType(getFlags()); } void LLViewerInventoryItem::setWearableType(LLWearableType::EType type) { if (getWearableType() != LLWearableType::WT_UNKNOWN) { - llwarns << "Calling LLViewerInventoryItem::setWearableType for item that does not have an unknown wearable type!?" << llendl; + LL_WARNS() << "Calling LLViewerInventoryItem::setWearableType for item that does not have an unknown wearable type!?" << LL_ENDL; return; } - mFlags = (mFlags & ~LLInventoryItemFlags::II_FLAGS_WEARABLES_MASK) | type; + mFlags = (mFlags & ~LLInventoryItemFlags::II_FLAGS_SUBTYPE_MASK) | type; } time_t LLViewerInventoryItem::getCreationDate() const @@ -1803,6 +2275,33 @@ U32 LLViewerInventoryItem::getCRC32() const return LLInventoryItem::getCRC32(); } +// *TODO: mantipov: should be removed with LMSortPrefix patch in llinventorymodel.cpp, EXT-3985 +static char getSeparator() { return '@'; } +BOOL LLViewerInventoryItem::extractSortFieldAndDisplayName(const std::string& name, S32* sortField, std::string* displayName) +{ + const char separator = getSeparator(); + const std::string::size_type separatorPos = name.find(separator, 0); + + BOOL result = FALSE; + + if (separatorPos < std::string::npos) + { + if (sortField) + { + *sortField = std::stoi(name.substr(0, separatorPos)); + } + + if (displayName) + { + *displayName = name.substr(separatorPos + 1, std::string::npos); + } + + result = TRUE; + } + + return result; +} + // This returns true if the item that this item points to // doesn't exist in memory (i.e. LLInventoryModel). The baseitem // might still be in the database but just not loaded yet. @@ -1821,7 +2320,7 @@ LLViewerInventoryItem *LLViewerInventoryItem::getLinkedItem() const LLViewerInventoryItem *linked_item = gInventory.getItem(mAssetUUID); if (linked_item && linked_item->getIsLinkType()) { - llwarns << "Warning: Accessing link to link" << llendl; + LL_WARNS(LOG_INV) << "Warning: Accessing link to link" << LL_ENDL; return NULL; } return linked_item; @@ -1874,9 +2373,9 @@ PermissionMask LLViewerInventoryItem::getPermissionMask() const //---------- -void LLViewerInventoryItem::onCallingCardNameLookup(const LLUUID& id, const std::string& name, bool is_group) +void LLViewerInventoryItem::onCallingCardNameLookup(const LLUUID& id, const LLAvatarName& name) { - rename(name); + rename(name.getLegacyName()); gInventory.addChangedMask(LLInventoryObserver::LABEL, getUUID()); gInventory.notifyObservers(); } @@ -1885,9 +2384,10 @@ class LLRegenerateLinkCollector : public LLInventoryCollectFunctor { public: LLRegenerateLinkCollector(const LLViewerInventoryItem *target_item) : mTargetItem(target_item) {} - virtual ~LLRegenerateLinkCollector() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item) + virtual ~LLRegenerateLinkCollector() = default; + + bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item) override { if (item) { @@ -1915,12 +2415,10 @@ LLUUID find_possible_item_for_regeneration(const LLViewerInventoryItem *target_i items, LLInventoryModel::EXCLUDE_TRASH, candidate_matches); - for (LLViewerInventoryItem::item_array_t::const_iterator item_iter = items.begin(); - item_iter != items.end(); - ++item_iter) + for (const LLViewerInventoryItem* item : items) { - const LLViewerInventoryItem *item = (*item_iter); - if (true) return item->getUUID(); + if(item) + return item->getUUID(); } return LLUUID::null; } @@ -1940,11 +2438,9 @@ BOOL LLViewerInventoryItem::regenerateLink() items, LLInventoryModel::EXCLUDE_TRASH, asset_id_matches); - for (LLViewerInventoryItem::item_array_t::iterator item_iter = items.begin(); - item_iter != items.end(); - item_iter++) + for (auto& item_iter : items) { - LLViewerInventoryItem *item = (*item_iter); + LLViewerInventoryItem *item = item_iter; item->setAssetUUID(target_item_id); item->updateServer(FALSE); gInventory.addChangedMask(LLInventoryObserver::REBUILD, item->getUUID()); diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h index a8c833947c..e24beb89ab 100644 --- a/indra/newview/llviewerinventory.h +++ b/indra/newview/llviewerinventory.h @@ -42,6 +42,7 @@ class LLFolderView; class LLFolderBridge; class LLViewerInventoryCategory; +class LLAvatarName; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLViewerInventoryItem @@ -50,30 +51,35 @@ class LLViewerInventoryCategory; // their inventory. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLViewerInventoryItem : public LLInventoryItem, public boost::signals2::trackable +class LLViewerInventoryItem final : public LLInventoryItem, public boost::signals2::trackable { public: - typedef LLDynamicArray > item_array_t; + typedef std::vector > item_array_t; protected: ~LLViewerInventoryItem( void ); // ref counted public: - virtual LLAssetType::EType getType() const; - virtual const LLUUID& getAssetUUID() const; + LLAssetType::EType getType() const override; + const LLUUID& getAssetUUID() const override; virtual const LLUUID& getProtectedAssetUUID() const; // returns LLUUID::null if current agent does not have permission to expose this asset's UUID to the user - virtual const std::string& getName() const; - virtual const LLPermissions& getPermissions() const; + const std::string& getName() const override; + virtual S32 getSortField() const; + //virtual void setSortField(S32 sortField); + virtual void getSLURL(); //Caches SLURL for landmark. //*TODO: Find a better way to do it and remove this method from here. + const LLPermissions& getPermissions() const override; virtual const bool getIsFullPerm() const; // 'fullperm' in the popular sense: modify-ok & copy-ok & transfer-ok, no special god rules applied - virtual const LLUUID& getCreatorUUID() const; - virtual const std::string& getDescription() const; - virtual const LLSaleInfo& getSaleInfo() const; - virtual LLInventoryType::EType getInventoryType() const; + const LLUUID& getCreatorUUID() const override; + const std::string& getDescription() const override; + const LLSaleInfo& getSaleInfo() const override; + LLInventoryType::EType getInventoryType() const override; virtual bool isWearableType() const; virtual LLWearableType::EType getWearableType() const; - virtual U32 getFlags() const; - virtual time_t getCreationDate() const; - virtual U32 getCRC32() const; // really more of a checksum. + U32 getFlags() const override; + time_t getCreationDate() const override; + U32 getCRC32() const override; // really more of a checksum. + + static BOOL extractSortFieldAndDisplayName(const std::string& name, S32* sortField, std::string* displayName); // construct a complete viewer inventory item LLViewerInventoryItem(const LLUUID& uuid, const LLUUID& parent_uuid, @@ -107,7 +113,7 @@ class LLViewerInventoryItem : public LLInventoryItem, public boost::signals2::tr LLViewerInventoryItem(const LLInventoryItem* other); void copyViewerItem(const LLViewerInventoryItem* other); - /*virtual*/ void copyItem(const LLInventoryItem* other); + /*virtual*/ void copyItem(const LLInventoryItem* other) override; // construct a new clone of this item - it creates a new viewer // inventory item using the copy constructor, and returns it. @@ -115,16 +121,15 @@ class LLViewerInventoryItem : public LLInventoryItem, public boost::signals2::tr void cloneViewerItem(LLPointer& newitem) const; // virtual methods - virtual void removeFromServer( void ); - virtual void updateParentOnServer(BOOL restamp) const; - virtual void updateServer(BOOL is_new) const; + void updateParentOnServer(BOOL restamp) const override; + void updateServer(BOOL is_new) const override; void fetchFromServer(void) const; - //virtual void packMessage(LLMessageSystem* msg) const; - virtual BOOL unpackMessage(LLMessageSystem* msg, const char* block, S32 block_num = 0); - virtual BOOL unpackMessage(LLSD item); - virtual BOOL importFile(LLFILE* fp); - virtual BOOL importLegacyStream(std::istream& input_stream); + void packMessage(LLMessageSystem* msg) const override; + BOOL unpackMessage(LLMessageSystem* msg, const char* block, S32 block_num = 0) override; + virtual BOOL unpackMessage(const LLSD& item); + BOOL importFile(LLFILE* fp) override; + BOOL importLegacyStream(std::istream& input_stream) override; // file handling on the viewer. These are not meant for anything // other than cacheing. @@ -137,7 +142,6 @@ class LLViewerInventoryItem : public LLInventoryItem, public boost::signals2::tr void setComplete(BOOL complete) { mIsComplete = complete; } //void updateAssetOnServer() const; - virtual void packMessage(LLMessageSystem* msg) const; virtual void setTransactionID(const LLTransactionID& transaction_id); struct comparePointers { @@ -157,7 +161,7 @@ class LLViewerInventoryItem : public LLInventoryItem, public boost::signals2::tr PermissionMask getPermissionMask() const; // callback - void onCallingCardNameLookup(const LLUUID& id, const std::string& name, bool is_group); + void onCallingCardNameLookup(const LLUUID& id, const LLAvatarName& name); // If this is a broken link, try to fix it and any other identical link. BOOL regenerateLink(); @@ -181,10 +185,10 @@ class LLViewerInventoryItem : public LLInventoryItem, public boost::signals2::tr // new ones as needed. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLViewerInventoryCategory : public LLInventoryCategory +class LLViewerInventoryCategory final : public LLInventoryCategory { public: - typedef LLDynamicArray > cat_array_t; + typedef std::vector > cat_array_t; protected: ~LLViewerInventoryCategory(); @@ -201,16 +205,17 @@ class LLViewerInventoryCategory : public LLInventoryCategory LLViewerInventoryCategory(const LLViewerInventoryCategory* other); void copyViewerCategory(const LLViewerInventoryCategory* other); - virtual void removeFromServer(); - virtual void updateParentOnServer(BOOL restamp_children) const; - virtual void updateServer(BOOL is_new) const; + void updateParentOnServer(BOOL restamp_children) const override; + void updateServer(BOOL is_new) const override; + + void packMessage(LLMessageSystem* msg) const override; const LLUUID& getOwnerID() const { return mOwnerID; } // Version handling enum { VERSION_UNKNOWN = -1, VERSION_INITIAL = 1 }; - S32 getVersion() const { return mVersion; } - void setVersion(S32 version) { mVersion = version; } + S32 getVersion() const; + void setVersion(S32 version); // Returns true if a fetch was issued. bool fetch(); @@ -221,6 +226,8 @@ class LLViewerInventoryCategory : public LLInventoryCategory enum { DESCENDENT_COUNT_UNKNOWN = -1 }; S32 getDescendentCount() const { return mDescendentCount; } void setDescendentCount(S32 descendents) { mDescendentCount = descendents; } + // How many descendents do we currently have information for in the InventoryModel? + S32 getViewerDescendentCount() const; // file handling on the viewer. These are not meant for anything // other than caching. @@ -228,6 +235,11 @@ class LLViewerInventoryCategory : public LLInventoryCategory bool importFileLocal(LLFILE* fp); void determineFolderType(); void changeType(LLFolderType::EType new_folder_type); + void unpackMessage(LLMessageSystem* msg, const char* block, S32 block_num = 0) override; + virtual BOOL unpackMessage(const LLSD& category); + + // returns true if the category object will accept the incoming item + bool acceptItem(LLInventoryItem* inv_item); private: friend class LLInventoryModel; @@ -248,39 +260,41 @@ class LLInventoryCallback : public LLRefCount class LLViewerJointAttachment; -//void rez_attachment_cb(const LLUUID& inv_item, LLViewerJointAttachment *attachmentp); -// [SL:KB] - Patch: Appearance-DnDWear | Checked: 2010-09-28 (Catznip-3.0.0a) | Added: Catznip-2.2.0a -void rez_attachment_cb(const LLUUID& inv_item, LLViewerJointAttachment *attachmentp, bool replace); +// [SL:KB] - Patch: Appearance-DnDWear | Checked: 2010-09-28 (Catznip-3.4) +void rez_attachment_cb(const LLUUID& inv_item, LLViewerJointAttachment *attachmentp, bool replace = false); // [/SL:KB] +//void rez_attachment_cb(const LLUUID& inv_item, LLViewerJointAttachment *attachmentp); void activate_gesture_cb(const LLUUID& inv_item); void create_gesture_cb(const LLUUID& inv_item); -class AddFavoriteLandmarkCallback : public LLInventoryCallback +class AddFavoriteLandmarkCallback final : public LLInventoryCallback { public: AddFavoriteLandmarkCallback() : mTargetLandmarkId(LLUUID::null) {} void setTargetLandmarkId(const LLUUID& target_uuid) { mTargetLandmarkId = target_uuid; } private: - void fire(const LLUUID& inv_item); + void fire(const LLUUID& inv_item) override; LLUUID mTargetLandmarkId; }; -typedef boost::function inventory_func_type; -void no_op_inventory_func(const LLUUID&); // A do-nothing inventory_func +typedef std::function inventory_func_type; +typedef std::function llsd_func_type; +typedef std::function nullary_func_type; -typedef boost::function nullary_func_type; +void no_op_inventory_func(const LLUUID&); // A do-nothing inventory_func +void no_op_llsd_func(const LLSD&); // likewise for LLSD void no_op(); // A do-nothing nullary func. // Shim between inventory callback and boost function/callable -class LLBoostFuncInventoryCallback: public LLInventoryCallback +class LLBoostFuncInventoryCallback : public LLInventoryCallback { public: - LLBoostFuncInventoryCallback(inventory_func_type fire_func, + LLBoostFuncInventoryCallback(inventory_func_type fire_func = no_op_inventory_func, nullary_func_type destroy_func = no_op): mFireFunc(fire_func), mDestroyFunc(destroy_func) @@ -288,7 +302,7 @@ class LLBoostFuncInventoryCallback: public LLInventoryCallback } // virtual - void fire(const LLUUID& item_id) + void fire(const LLUUID& item_id) override { mFireFunc(item_id); } @@ -354,14 +368,16 @@ void copy_inventory_item( const std::string& new_name, LLPointer cb); -void link_inventory_item( - const LLUUID& agent_id, - const LLUUID& item_id, - const LLUUID& parent_id, - const std::string& new_name, - const std::string& new_description, - const LLAssetType::EType asset_type, - LLPointer cb); +// utility functions for inventory linking. +void link_inventory_object(const LLUUID& category, + LLConstPointer baseobj, + LLPointer cb); +void link_inventory_object(const LLUUID& category, + const LLUUID& id, + LLPointer cb); +void link_inventory_array(const LLUUID& category, + LLInventoryObject::const_object_list_t& baseobj_array, + LLPointer cb); void move_inventory_item( const LLUUID& agent_id, @@ -371,6 +387,46 @@ void move_inventory_item( const std::string& new_name, LLPointer cb); +void update_inventory_item( + LLViewerInventoryItem *update_item, + LLPointer cb); + +void update_inventory_item( + const LLUUID& item_id, + const LLSD& updates, + LLPointer cb); + +void update_inventory_category( + const LLUUID& cat_id, + const LLSD& updates, + LLPointer cb); + +void remove_inventory_items( + LLInventoryObject::object_list_t& items, + LLPointer cb); + +void remove_inventory_item( + LLPointer obj, + LLPointer cb, + bool immediate_delete = false); + +void remove_inventory_item( + const LLUUID& item_id, + LLPointer cb, + bool immediate_delete = false); + +void remove_inventory_category( + const LLUUID& cat_id, + LLPointer cb); + +void remove_inventory_object( + const LLUUID& object_id, + LLPointer cb); + +void purge_descendents_of( + const LLUUID& cat_id, + LLPointer cb); + const LLUUID get_folder_by_itemtype(const LLInventoryItem *src); void copy_inventory_from_notecard(const LLUUID& destination_id, @@ -385,4 +441,11 @@ void menu_create_inventory_item(LLFolderView* root, const LLSD& userdata, const LLUUID& default_parent_uuid = LLUUID::null); +void slam_inventory_folder(const LLUUID& folder_id, + const LLSD& contents, + LLPointer cb); + +void remove_folder_contents(const LLUUID& folder_id, bool keep_outfit_links, + LLPointer cb); + #endif // LL_LLVIEWERINVENTORY_H diff --git a/indra/newview/llviewerjoint.cpp b/indra/newview/llviewerjoint.cpp index e46299f9d2..47f967a352 100644 --- a/indra/newview/llviewerjoint.cpp +++ b/indra/newview/llviewerjoint.cpp @@ -48,14 +48,13 @@ LLViewerJoint::LLViewerJoint() : LLAvatarJoint() { } -LLViewerJoint::LLViewerJoint(const std::string &name, LLJoint *parent) : - LLAvatarJoint(name, parent) -{ } - LLViewerJoint::LLViewerJoint(S32 joint_num) : LLAvatarJoint(joint_num) { } +LLViewerJoint::LLViewerJoint(const std::string &name, LLJoint *parent) : + LLAvatarJoint(name, parent) +{ } //----------------------------------------------------------------------------- // ~LLViewerJoint() @@ -99,7 +98,7 @@ U32 LLViewerJoint::render( F32 pixelArea, BOOL first_pass, BOOL is_dummy ) if ((pixelArea > MIN_PIXEL_AREA_3PASS_HAIR)) { // render all three passes - LLGLDisable cull(GL_CULL_FACE); + LLGLDisable cull; // first pass renders without writing to the z buffer { LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE); @@ -146,6 +145,8 @@ U32 LLViewerJoint::render( F32 pixelArea, BOOL first_pass, BOOL is_dummy ) iter != mChildren.end(); ++iter) { LLAvatarJoint* joint = dynamic_cast(*iter); + if (!joint) + continue; F32 jointLOD = joint->getLOD(); if (pixelArea >= jointLOD || sDisableLOD) { diff --git a/indra/newview/llviewerjoint.h b/indra/newview/llviewerjoint.h index fd262b6e80..1ec87ee41d 100644 --- a/indra/newview/llviewerjoint.h +++ b/indra/newview/llviewerjoint.h @@ -49,6 +49,16 @@ class LLViewerJoint : LLViewerJoint(const std::string &name, LLJoint *parent = NULL); virtual ~LLViewerJoint(); + void* operator new(size_t size) + { + return ll_aligned_malloc_16(size); + } + + void operator delete(void* ptr) + { + ll_aligned_free_16(ptr); + } + // Render character hierarchy. // Traverses the entire joint hierarchy, setting up // transforms and calling the drawShape(). diff --git a/indra/newview/llviewerjointattachment.cpp b/indra/newview/llviewerjointattachment.cpp index 52abedded5..1b118ec63a 100644 --- a/indra/newview/llviewerjointattachment.cpp +++ b/indra/newview/llviewerjointattachment.cpp @@ -83,15 +83,15 @@ U32 LLViewerJointAttachment::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_ { if (LLVOAvatar::sShowAttachmentPoints) { - LLGLDisable cull_face(GL_CULL_FACE); + LLGLDisable cull_face; gGL.color4f(1.f, 1.f, 1.f, 1.f); - gGL.begin(LLRender::QUADS); + gGL.begin(LLRender::TRIANGLE_STRIP); { gGL.vertex3f(-0.1f, 0.1f, 0.f); gGL.vertex3f(-0.1f, -0.1f, 0.f); - gGL.vertex3f(0.1f, -0.1f, 0.f); gGL.vertex3f(0.1f, 0.1f, 0.f); + gGL.vertex3f(0.1f, -0.1f, 0.f); }gGL.end(); } return 0; @@ -171,8 +171,8 @@ BOOL LLViewerJointAttachment::addObject(LLViewerObject* object) // Same object reattached if (isObjectAttached(object)) { - llinfos << "(same object re-attached)" << llendl; - LL_INFOS("Attachment") << object->getID() << " ("<getAttachmentPointName()<<") OBJECT re-attached" << llendl; + LL_INFOS() << "(same object re-attached)" << LL_ENDL; + LL_INFOS("Attachment") << object->getID() << " ("<getAttachmentPointName()<<") OBJECT re-attached" << LL_ENDL; removeObject(object); // Pass through anyway to let setupDrawable() // re-connect object to the joint correctly @@ -186,8 +186,8 @@ BOOL LLViewerJointAttachment::addObject(LLViewerObject* object) // Request detach, and kill the object in the meantime. if (getAttachedObject(object->getAttachmentItemID())) { - llinfos << "(same object re-attached)" << llendl; - LL_INFOS("Attachment") << object->getID() << " ("<getAttachmentPointName()<<") ITEM re-attached" << llendl; + LL_INFOS() << "(same object re-attached)" << LL_ENDL; + LL_INFOS("Attachment") << object->getID() << " ("<getAttachmentPointName()<<") ITEM re-attached" << LL_ENDL; object->markDead(); // If this happens to be attached to self, then detach. @@ -239,7 +239,7 @@ void LLViewerJointAttachment::removeObject(LLViewerObject *object) } if (iter == mAttachedObjects.end()) { - llwarns << "Could not find object to detach" << llendl; + LL_WARNS() << "Could not find object to detach" << LL_ENDL; return; } @@ -361,6 +361,25 @@ void LLViewerJointAttachment::setOriginalPosition(LLVector3& position) setPosition(position); } +//----------------------------------------------------------------------------- +// getNumAnimatedObjects() +//----------------------------------------------------------------------------- +S32 LLViewerJointAttachment::getNumAnimatedObjects() const +{ + S32 count = 0; + for (attachedobjs_vec_t::const_iterator iter = mAttachedObjects.begin(); + iter != mAttachedObjects.end(); + ++iter) + { + const LLViewerObject *attached_object = *iter; + if (attached_object->isAnimatedObject()) + { + count++; + } + } + return count; +} + //----------------------------------------------------------------------------- // clampObjectPosition() //----------------------------------------------------------------------------- diff --git a/indra/newview/llviewerjointattachment.h b/indra/newview/llviewerjointattachment.h index 9addafaee1..20eb429570 100644 --- a/indra/newview/llviewerjointattachment.h +++ b/indra/newview/llviewerjointattachment.h @@ -47,6 +47,16 @@ class LLViewerJointAttachment : LLViewerJointAttachment(); virtual ~LLViewerJointAttachment(); + void* operator new(size_t size) + { + return ll_aligned_malloc_16(size); + } + + void operator delete(void* ptr) + { + ll_aligned_free_16(ptr); + } + //virtual U32 render( F32 pixelArea ); // Returns triangle count // Returns true if this object is transparent. @@ -77,6 +87,7 @@ class LLViewerJointAttachment : S32 getGroup() const { return mGroup; } S32 getPieSlice() const { return mPieSlice; } S32 getNumObjects() const { return mAttachedObjects.size(); } + S32 getNumAnimatedObjects() const; void clampObjectPosition(); diff --git a/indra/newview/llviewerjointmesh.cpp b/indra/newview/llviewerjointmesh.cpp index 1184cf73c1..549a67757b 100644 --- a/indra/newview/llviewerjointmesh.cpp +++ b/indra/newview/llviewerjointmesh.cpp @@ -110,29 +110,30 @@ static LLVector4 gJointPivot[32]; //----------------------------------------------------------------------------- void LLViewerJointMesh::uploadJointMatrices() { - S32 joint_num; + U32 joint_num; LLPolyMesh *reference_mesh = mMesh->getReferenceMesh(); LLDrawPool *poolp = mFace ? mFace->getPool() : NULL; BOOL hardware_skinning = (poolp && poolp->getVertexShaderLevel() > 0) ? TRUE : FALSE; //calculate joint matrices - for (joint_num = 0; joint_num < reference_mesh->mJointRenderData.count(); joint_num++) + for (joint_num = 0; joint_num < reference_mesh->mJointRenderData.size(); joint_num++) { - LLMatrix4 joint_mat = *reference_mesh->mJointRenderData[joint_num]->mWorldMatrix; + LLMatrix4a joint_mat = *reference_mesh->mJointRenderData[joint_num]->mWorldMatrix; if (hardware_skinning) { - joint_mat *= LLDrawPoolAvatar::getModelView(); + joint_mat.setMul(LLDrawPoolAvatar::getModelView(),joint_mat); + //joint_mat *= LLDrawPoolAvatar::getModelView(); } - gJointMatUnaligned[joint_num] = joint_mat; - gJointRotUnaligned[joint_num] = joint_mat.getMat3(); + gJointMatUnaligned[joint_num] = LLMatrix4(joint_mat.getF32ptr()); + gJointRotUnaligned[joint_num] = gJointMatUnaligned[joint_num].getMat3(); } BOOL last_pivot_uploaded = FALSE; S32 j = 0; //upload joint pivots - for (joint_num = 0; joint_num < reference_mesh->mJointRenderData.count(); joint_num++) + for (joint_num = 0; joint_num < reference_mesh->mJointRenderData.size(); joint_num++) { LLSkinJoint *sj = reference_mesh->mJointRenderData[joint_num]->mSkinJoint; if (sj) @@ -172,7 +173,7 @@ void LLViewerJointMesh::uploadJointMatrices() GLfloat mat[45*4]; memset(mat, 0, sizeof(GLfloat)*45*4); - for (joint_num = 0; joint_num < reference_mesh->mJointRenderData.count(); joint_num++) + for (joint_num = 0; joint_num < reference_mesh->mJointRenderData.size(); joint_num++) { gJointMatUnaligned[joint_num].transpose(); @@ -193,7 +194,7 @@ void LLViewerJointMesh::uploadJointMatrices() else { //load gJointMatUnaligned into gJointMatAligned - for (joint_num = 0; joint_num < reference_mesh->mJointRenderData.count(); ++joint_num) + for (joint_num = 0; joint_num < reference_mesh->mJointRenderData.size(); ++joint_num) { gJointMatAligned[joint_num].loadu(gJointMatUnaligned[joint_num]); } @@ -254,7 +255,6 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy) //---------------------------------------------------------------- llassert( !(mTexture.notNull() && mLayerSet) ); // mutually exclusive - LLTexUnit::eTextureAddressMode old_mode = LLTexUnit::TAM_WRAP; LLViewerTexLayerSet *layerset = dynamic_cast(mLayerSet); if (mTestImageName) { @@ -283,7 +283,7 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy) static const LLCachedControl render_unloaded_avatar("RenderUnloadedAvatar", false); if (!render_unloaded_avatar) { - llwarns << "Layerset without composite" << llendl; + LL_WARNS() << "Layerset without composite" << LL_ENDL; } gGL.getTexUnit(diffuse_channel)->bind(LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT)); } @@ -291,19 +291,13 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy) else if ( !is_dummy && mTexture.notNull() ) { - if(mTexture->hasGLTexture()) - { - old_mode = mTexture->getAddressMode(); - } gGL.getTexUnit(diffuse_channel)->bind(mTexture); - gGL.getTexUnit(diffuse_channel)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); } else { gGL.getTexUnit(diffuse_channel)->bind(LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT)); } - - + U32 mask = sRenderMask; U32 start = mMesh->mFaceVertexOffset; @@ -334,8 +328,7 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy) else { gGL.pushMatrix(); - LLMatrix4 jointToWorld = getWorldMatrix(); - gGL.multMatrix((GLfloat*)jointToWorld.mMatrix); + gGL.multMatrix(getWorldMatrix()); buff->setBuffer(mask); buff->drawRange(LLRender::TRIANGLES, start, end, count, offset); gGL.popMatrix(); @@ -349,12 +342,6 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy) gGL.getTexUnit(diffuse_channel)->setTextureBlendType(LLTexUnit::TB_MULT); } - if (mTexture.notNull() && !is_dummy) - { - gGL.getTexUnit(diffuse_channel)->bind(mTexture); - gGL.getTexUnit(diffuse_channel)->setTextureAddressMode(old_mode); - } - return triangle_count; } @@ -384,7 +371,7 @@ void LLViewerJointMesh::updateFaceSizes(U32 &num_vertices, U32& num_indices, F32 //----------------------------------------------------------------------------- // updateFaceData() //----------------------------------------------------------------------------- -static LLFastTimer::DeclareTimer FTM_AVATAR_FACE("Avatar Face"); +static LLTrace::BlockTimerStatHandle FTM_AVATAR_FACE("Avatar Face"); void LLViewerJointMesh::updateFaceData(LLFace *face, F32 pixel_area, BOOL damp_wind, bool terse_update) { @@ -407,13 +394,13 @@ void LLViewerJointMesh::updateFaceData(LLFace *face, F32 pixel_area, BOOL damp_w } - LLFastTimer t(FTM_AVATAR_FACE); + LL_RECORD_BLOCK_TIME(FTM_AVATAR_FACE); LLStrider verticesp; LLStrider normalsp; LLStrider tex_coordsp; LLStrider vertex_weightsp; - LLStrider clothing_weightsp; + LLStrider clothing_weightsp; LLStrider indicesp; // Copy data into the faces from the polymesh data. @@ -559,7 +546,7 @@ void LLViewerJointMesh::dump() { if (mValid) { - llinfos << "Usable LOD " << mName << llendl; + LL_INFOS() << "Usable LOD " << mName << LL_ENDL; } } diff --git a/indra/newview/llviewerjointmesh.h b/indra/newview/llviewerjointmesh.h index c5b872edeb..017a7fe110 100644 --- a/indra/newview/llviewerjointmesh.h +++ b/indra/newview/llviewerjointmesh.h @@ -50,6 +50,16 @@ class LLViewerJointMesh : public LLAvatarJointMesh, public LLViewerJoint // Destructor virtual ~LLViewerJointMesh(); + void* operator new(size_t size) + { + return ll_aligned_malloc_16(size); + } + + void operator delete(void* ptr) + { + ll_aligned_free_16(ptr); + } + // Render time method to upload batches of joint matrices void uploadJointMatrices(); diff --git a/indra/newview/llviewerjoystick.cpp b/indra/newview/llviewerjoystick.cpp index 36099abe8d..1dec470624 100644 --- a/indra/newview/llviewerjoystick.cpp +++ b/indra/newview/llviewerjoystick.cpp @@ -2,31 +2,25 @@ * @file llviewerjoystick.cpp * @brief Joystick / NDOF device functionality. * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -42,37 +36,111 @@ #include "lltoolmgr.h" #include "llselectmgr.h" #include "llviewermenu.h" +#include "llvoavatarself.h" // Singu Note: For toggle sit. #include "llagent.h" #include "llagentcamera.h" #include "llfocusmgr.h" +#include "rlvhandler.h" +#include +#include // ---------------------------------------------------------------------------- // Constants -#define X_I 1 -#define Y_I 2 -#define Z_I 0 -#define RX_I 4 -#define RY_I 5 -#define RZ_I 3 - -// flycam translations in build mode should be reduced -const F32 BUILDMODE_FLYCAM_T_SCALE = 3.f; +constexpr auto X_I = 1; +constexpr auto Y_I = 2; +constexpr auto Z_I = 0; +constexpr auto RX_I = 4; +constexpr auto RY_I = 5; +constexpr auto RZ_I = 3; // minimum time after setting away state before coming back -const F32 MIN_AFK_TIME = 2.f; +constexpr F32 MIN_AFK_TIME = 2.f; F32 LLViewerJoystick::sLastDelta[] = {0,0,0,0,0,0,0}; F32 LLViewerJoystick::sDelta[] = {0,0,0,0,0,0,0}; +// Note: Save the type of controller +enum EControllerType { NONE, SPACE_NAV, XBOX, DS3, UNKNOWN }; +static EControllerType sType = NONE; + +// Control cursor instead of avatar? +bool sControlCursor = false; + +enum XBoxKeys +{ + XBOX_A_KEY = 0, + XBOX_B_KEY, + XBOX_X_KEY, + XBOX_Y_KEY, + XBOX_L_BUMP_KEY, + XBOX_R_BUMP_KEY, + XBOX_BACK_KEY, + XBOX_START_KEY, + XBOX_L_STICK_CLICK, + XBOX_R_STICK_CLICK +}; + +bool isOUYA(const std::string& desc) { return desc.find("OUYA") != std::string::npos; } + +bool isXboxLike(const std::string& desc) +{ + return boost::algorithm::icontains(desc, "xbox") || isOUYA(desc); +} + +bool isDS3Like(const std::string& desc) +{ + return desc.find("MotioninJoy") != std::string::npos; +} + +enum DS3Keys +{ + DS3_TRIANGLE_KEY = 0, + DS3_CIRCLE_KEY, + DS3_X_KEY, + DS3_SQUARE_KEY, + DS3_L1_KEY, + DS3_R1_KEY, + DS3_L2_KEY, + DS3_R2_KEY, + DS3_SELECT_KEY, + DS3_L_STICK_CLICK, + DS3_R_STICK_CLICK, + DS3_START_KEY, + DS3_LOGO_KEY +}; + +void set_joystick_type(const S32& type) +{ + switch (type) + { + case 0: sType = SPACE_NAV; break; + case 1: case 2: sType = XBOX; break; + case 3: sType = DS3; break; + default: sType = UNKNOWN; break; + } +} + +S32 get_joystick_type() +{ + switch (sType) + { + case SPACE_NAV: return 0; + case XBOX: return isOUYA(LLViewerJoystick::getInstance()->getDescription()) ? 1 : 2; + case DS3: return 3; + default: return -1; // sType == NONE || sType == UNKNOWN + } +} +// + // These constants specify the maximum absolute value coming in from the device. // HACK ALERT! the value of MAX_JOYSTICK_INPUT_VALUE is not arbitrary as it // should be. It has to be equal to 3000 because the SpaceNavigator on Windows // refuses to respond to the DirectInput SetProperty call; it always returns // values in the [-3000, 3000] range. -#define MAX_SPACENAVIGATOR_INPUT 3000.0f -#define MAX_JOYSTICK_INPUT_VALUE MAX_SPACENAVIGATOR_INPUT +constexpr auto MAX_SPACENAVIGATOR_INPUT = 3000.0f; +constexpr auto MAX_JOYSTICK_INPUT_VALUE = MAX_SPACENAVIGATOR_INPUT; // ----------------------------------------------------------------------------- void LLViewerJoystick::updateEnabled(bool autoenable) @@ -119,7 +187,7 @@ NDOF_HotPlugResult LLViewerJoystick::HotPlugAddCallback(NDOF_Device *dev) LLViewerJoystick* joystick(LLViewerJoystick::getInstance()); if (joystick->mDriverState == JDS_UNINITIALIZED) { - llinfos << "HotPlugAddCallback: will use device:" << llendl; + LL_INFOS() << "HotPlugAddCallback: will use device:" << LL_ENDL; ndof_dump(dev); joystick->mNdofDev = dev; joystick->mDriverState = JDS_INITIALIZED; @@ -137,8 +205,8 @@ void LLViewerJoystick::HotPlugRemovalCallback(NDOF_Device *dev) LLViewerJoystick* joystick(LLViewerJoystick::getInstance()); if (joystick->mNdofDev == dev) { - llinfos << "HotPlugRemovalCallback: joystick->mNdofDev=" - << joystick->mNdofDev << "; removed device:" << llendl; + LL_INFOS() << "HotPlugRemovalCallback: joystick->mNdofDev=" + << joystick->mNdofDev << "; removed device:" << LL_ENDL; ndof_dump(dev); joystick->mDriverState = JDS_UNINITIALIZED; } @@ -163,7 +231,7 @@ LLViewerJoystick::LLViewerJoystick() memset(mBtn, 0, sizeof(mBtn)); // factor in bandwidth? bandwidth = gViewerStats->mKBitStat - mPerfScale = 4000.f / gSysCPU.getMHz(); + mPerfScale = 4000.f / gSysCPU.getMHz(); // hmm. why? } // ----------------------------------------------------------------------------- @@ -227,7 +295,7 @@ void LLViewerJoystick::init(bool autoenable) if (ndof_init_first(mNdofDev, NULL)) { mDriverState = JDS_UNINITIALIZED; - llwarns << "ndof_init_first FAILED" << llendl; + LL_WARNS() << "ndof_init_first FAILED" << LL_ENDL; } else { @@ -247,11 +315,14 @@ void LLViewerJoystick::init(bool autoenable) } updateEnabled(autoenable); + const std::string desc(getDescription()); if (mDriverState == JDS_INITIALIZED) { + sControlCursor = false; // A Joystick device is plugged in if (isLikeSpaceNavigator()) { + sType = SPACE_NAV; // It's a space navigator, we have defaults for it. if (gSavedSettings.getString("JoystickInitialized") != "SpaceNavigator") { @@ -260,19 +331,52 @@ void LLViewerJoystick::init(bool autoenable) gSavedSettings.setString("JoystickInitialized", "SpaceNavigator"); } } + else if (isXboxLike(desc)) + { + sType = XBOX; + // It's an Xbox controller, we have defaults for it. + bool ouya(isOUYA(desc)); + std::string controller = ouya ? "OUYA" : "XboxController"; + if (gSavedSettings.getString("JoystickInitialized") != controller) + { + // Only set the defaults if we haven't already (in case they were overridden) + setSNDefaults(ouya ? 1 : 2); + gSavedSettings.setString("JoystickInitialized", controller); + } + } + else if (isDS3Like(desc)) + { + sType = DS3; + // It's a DS3 controller, we have defaults for it. + if (gSavedSettings.getString("JoystickInitialized") != "DualShock3") + { + // Only set the defaults if we haven't already (in case they were overridden) + setSNDefaults(3); + gSavedSettings.setString("JoystickInitialized", "DualShock3"); + } + } else { - // It's not a Space Navigator + // It's not a Space Navigator, 360 controller, or DualShock 3 + sType = UNKNOWN; gSavedSettings.setString("JoystickInitialized", "UnknownDevice"); } } else { // No device connected, don't change any settings + sType = NONE; } - llinfos << "ndof: mDriverState=" << mDriverState << "; mNdofDev=" - << mNdofDev << "; libinit=" << libinit << llendl; + LL_INFOS() << "ndof: mDriverState=" << mDriverState << "; mNdofDev=" + << mNdofDev << "; libinit=" << libinit << LL_ENDL; + + // + if (mDriverState == JDS_INITIALIZED) + { + LL_INFOS() << "Joystick = " << desc << LL_ENDL; + } + // #endif } @@ -282,8 +386,8 @@ void LLViewerJoystick::terminate() #if LIB_NDOF ndof_libcleanup(); - llinfos << "Terminated connection with NDOF device." << llendl; - + LL_INFOS() << "Terminated connection with NDOF device." << LL_ENDL; + mDriverState = JDS_UNINITIALIZED; #endif } @@ -421,14 +525,96 @@ void LLViewerJoystick::agentFly(F32 inc) } // ----------------------------------------------------------------------------- -void LLViewerJoystick::agentRotate(F32 pitch_inc, F32 yaw_inc) +void LLViewerJoystick::agentPitch(F32 pitch_inc) { - LLQuaternion new_rot; - pitch_inc = gAgent.clampPitchToLimits(-pitch_inc); - const LLQuaternion qx(pitch_inc, gAgent.getLeftAxis()); - const LLQuaternion qy(-yaw_inc, gAgent.getReferenceUpVector()); - new_rot.setQuat(qx * qy); - gAgent.rotate(new_rot); + if (pitch_inc < 0) + { + gAgent.setControlFlags(AGENT_CONTROL_PITCH_POS); + } + else if (pitch_inc > 0) + { + gAgent.setControlFlags(AGENT_CONTROL_PITCH_NEG); + } + + gAgent.pitch(-pitch_inc); +} + +// ----------------------------------------------------------------------------- +void LLViewerJoystick::agentYaw(F32 yaw_inc) +{ + // Cannot steer some vehicles in mouselook if the script grabs the controls + if (gAgentCamera.cameraMouselook() && !gSavedSettings.getBOOL("JoystickMouselookYaw")) + { + gAgent.rotate(-yaw_inc, gAgent.getReferenceUpVector()); + } + else + { + if (yaw_inc < 0) + { + gAgent.setControlFlags(AGENT_CONTROL_YAW_POS); + } + else if (yaw_inc > 0) + { + gAgent.setControlFlags(AGENT_CONTROL_YAW_NEG); + } + + gAgent.yaw(-yaw_inc); + } +} + +S32 linear_ramp(const F32& inc, const F32& prev_inc) +{ + // Start out linear for fine control but then ramp up more quickly for faster movement. + F32 nudge = inc > F_APPROXIMATELY_ZERO ? 1.f : -1.f; + F32 linear = inc + prev_inc; + F32 square = 0.f; + if (abs(linear) > 0.2f) + { + square = linear + (0.2f * -nudge); + square *= abs(square); + } + + return nudge + linear * 25.f + square * 300.f; +} + +void LLViewerJoystick::cursorSlide(F32 inc) +{ + static F32 prev_inc = 0.f; // Smooth a little. + if (!is_approx_zero(inc)) + { + S32 x, y; + LLUI::getMousePositionScreen(&x, &y); + x = llclamp(x + linear_ramp(inc, prev_inc), 0, gViewerWindow->getWindowWidthRaw()); + LLUI::setMousePositionScreen(x, y); + } + prev_inc = inc; +} + +void LLViewerJoystick::cursorPush(F32 inc) +{ + static F32 prev_inc = 0.f; // Smooth a little. + if (!is_approx_zero(inc)) + { + S32 x, y; + LLUI::getMousePositionScreen(&x, &y); + y = llclamp(y + linear_ramp(inc, prev_inc), 0, gViewerWindow->getWindowHeightRaw()); + LLUI::setMousePositionScreen(x, y); + } + prev_inc = inc; +} + +void LLViewerJoystick::cursorZoom(F32 inc) +{ + if (!is_approx_zero(inc)) + { + static U8 count = 0; + ++count; + if (count == 3) // Slow down the zoom in/out. + { + gViewerWindow->handleScrollWheel(inc > F_APPROXIMATELY_ZERO ? 1 : -1); + count = 0; + } + } } // ----------------------------------------------------------------------------- @@ -589,25 +775,54 @@ void LLViewerJoystick::moveAvatar(bool reset) gSavedSettings.getS32("JoystickAxis5") }; - if (reset || mResetFlag) + if (!sControlCursor) { - resetDeltas(axis); - if (reset) + if (reset || mResetFlag) { - // Note: moving the agent triggers agent camera mode; - // don't do this every time we set mResetFlag (e.g. because we gained focus) - gAgent.moveAt(0, true); + resetDeltas(axis); + if (reset) + { + // Note: moving the agent triggers agent camera mode; + // don't do this every time we set mResetFlag (e.g. because we gained focus) + gAgent.moveAt(0, true); + } + return; } - return; } bool is_zero = true; + static bool button_held = false; - if (mBtn[1] == 1) + if (mBtn[sType == XBOX ? XBOX_L_STICK_CLICK : sType == DS3 ? DS3_L_STICK_CLICK : 1] == 1) { - agentJump(); + // If AutomaticFly is enabled, then button1 merely causes a + // jump (as the up/down axis already controls flying) if on the + // ground, or cease flight if already flying. + // If AutomaticFly is disabled, then button1 toggles flying. + if (gSavedSettings.getBOOL("AutomaticFly")) + { + if (!gAgent.getFlying()) + { + gAgent.moveUp(1); + } + else if (!button_held) + { + button_held = true; + gAgent.setFlying(FALSE); + } + } + else if (!button_held) + { + button_held = true; + gAgent.setFlying(!gAgent.getFlying()); + } + is_zero = false; } + else + { + button_held = false; + } F32 axis_scale[] = { @@ -719,7 +934,15 @@ void LLViewerJoystick::moveAvatar(bool reset) } sDelta[RX_I] += (cur_delta[RX_I] - sDelta[RX_I]) * time * feather; sDelta[RY_I] += (cur_delta[RY_I] - sDelta[RY_I]) * time * feather; - + + if (sControlCursor) + { + cursorSlide(sDelta[X_I]); // left / right + cursorPush(-sDelta[Z_I]); // up / down + cursorZoom(sDelta[RX_I]); // mousewheel + return; + } + handleRun((F32) sqrt(sDelta[Z_I]*sDelta[Z_I] + sDelta[X_I]*sDelta[X_I])); // Allow forward/backward movement some priority @@ -765,11 +988,13 @@ void LLViewerJoystick::moveAvatar(bool reset) { if (gAgent.getFlying()) { - agentRotate(eff_rx, eff_ry); + agentPitch(eff_rx); + agentYaw(eff_ry); } else { - agentRotate(eff_rx, 2.f * eff_ry); + agentPitch(eff_rx); + agentYaw(2.f * eff_ry); } } } @@ -778,7 +1003,8 @@ void LLViewerJoystick::moveAvatar(bool reset) agentSlide(sDelta[X_I]); // move sideways agentFly(sDelta[Y_I]); // up/down & crouch agentPush(sDelta[Z_I]); // forward/back - agentRotate(sDelta[RX_I], sDelta[RY_I]); // pitch & turn + agentPitch(sDelta[RX_I]); // pitch + agentYaw(sDelta[RY_I]); // turn } } @@ -874,14 +1100,15 @@ void LLViewerJoystick::moveFlycam(bool reset) cur_delta[i] = llmin(cur_delta[i]+dead_zone[i], 0.f); } - // we need smaller camera movements in build mode + // We may want to scale camera movements up or down in build mode. // NOTE: this needs to remain after the deadzone calculation, otherwise // we have issues with flycam "jumping" when the build dialog is opened/closed -Nyx if (in_build_mode) { if (i == X_I || i == Y_I || i == Z_I) { - cur_delta[i] /= BUILDMODE_FLYCAM_T_SCALE; + static LLCachedControl build_mode_scale(gSavedSettings,"FlycamBuildModeScale", 1.0); + cur_delta[i] *= build_mode_scale; } } @@ -948,7 +1175,8 @@ void LLViewerJoystick::moveFlycam(bool reset) // ----------------------------------------------------------------------------- bool LLViewerJoystick::toggleFlycam() { - if (!gSavedSettings.getBOOL("JoystickEnabled") || !gSavedSettings.getBOOL("JoystickFlycamEnabled")) + if (gRlvHandler.hasBehaviour(RLV_BHVR_CAMDISTMAX) || gRlvHandler.hasBehaviour(RLV_BHVR_CAMUNLOCK) // [RLVa:LF] - @camdistmax and @camunlock mean no going away! + || !gSavedSettings.getBOOL("JoystickEnabled") || !gSavedSettings.getBOOL("JoystickFlycamEnabled")) { mOverrideCamera = false; return false; @@ -976,15 +1204,16 @@ bool LLViewerJoystick::toggleFlycam() } else { - // we are in build mode, exiting from the flycam mode: since we are - // going to keep the flycam POV for the main camera until the avatar - // moves, we need to track this situation. + // Exiting from the flycam mode: since we are going to keep the flycam POV for + // the main camera until the avatar moves, we need to track this situation. setCameraNeedsUpdate(false); setNeedsReset(true); } return true; } +bool toggleCursor() { sControlCursor = !sControlCursor; return true; } + void LLViewerJoystick::scanJoystick() { if (mDriverState != JDS_INITIALIZED || !gSavedSettings.getBOOL("JoystickEnabled")) @@ -1000,20 +1229,131 @@ void LLViewerJoystick::scanJoystick() updateStatus(); static long toggle_flycam = 0; + static bool toggle_cursor = false; + + // Xbox 360 support + if (sType == XBOX || sType == DS3) + { + bool ds3 = sType == DS3; + // Special command keys ... + // - Back = toggle flycam + U8 key = ds3 ? (U8)DS3_SELECT_KEY : (U8)XBOX_BACK_KEY; + if (mBtn[key] == 1) + { + if (!toggle_flycam) toggle_flycam = toggleFlycam(); + } + else + { + toggle_flycam = false; + } + + // - Start = toggle cursor/camera control + key = ds3 ? (U8)DS3_START_KEY : (U8)XBOX_START_KEY; + if (mBtn[key] == 1) + { + if (!toggle_cursor) toggle_cursor = toggleCursor(); + } + else + { + toggle_cursor = false; + } - if (mBtn[0] == 1) - { - if (mBtn[0] != toggle_flycam) + // Toggle mouselook ... + static bool right_stick_click_down = false; + key = ds3 ? (U8)DS3_R_STICK_CLICK : (U8)XBOX_R_STICK_CLICK; + if (!!mBtn[key] != right_stick_click_down) { - toggle_flycam = toggleFlycam() ? 1 : 0; + if (right_stick_click_down = mBtn[key]) // Note: Setting, not comparing. + gAgentCamera.cameraMouselook() ? gAgentCamera.changeCameraToDefault() : gAgentCamera.changeCameraToMouselook(); + } + + MASK mask = gKeyboard->currentMask(TRUE); + // Esc + static bool esc_down = false; + key = ds3 ? (U8)DS3_TRIANGLE_KEY : (U8)XBOX_Y_KEY; + if (!!mBtn[key] != esc_down) + { + esc_down = mBtn[key]; + (gKeyboard->*(esc_down ? &LLKeyboard::handleTranslatedKeyDown : &LLKeyboard::handleTranslatedKeyDown))(KEY_ESCAPE, mask); + } + + // Alt + static bool alt_down = false; + key = ds3 ? (U8)DS3_X_KEY : (U8)XBOX_A_KEY; + if (!!mBtn[key] != alt_down) + { + gKeyboard->setControllerKey(KEY_ALT, alt_down = mBtn[key]); + } + + // Ctrl + static bool ctrl_down = false; + key = ds3 ? (U8)DS3_SQUARE_KEY : (U8)XBOX_X_KEY; + if (!!mBtn[key] != ctrl_down) + { + gKeyboard->setControllerKey(KEY_CONTROL, ctrl_down = mBtn[key]); + } + + // Shift + static bool shift_down = false; + key = ds3 ? (U8)DS3_CIRCLE_KEY : (U8)XBOX_B_KEY; + if (!!mBtn[key] != shift_down) + { + gKeyboard->setControllerKey(KEY_SHIFT, shift_down = mBtn[key]); + } + + // Mouse clicks ... + LLCoordGL coord; + LLUI::getMousePositionScreen(&coord.mX, &coord.mY); + static bool m1_down = false; + static F32 last_m1 = 0; + key = ds3 ? (U8)DS3_L1_KEY : (U8)XBOX_L_BUMP_KEY; + if (!!mBtn[key] != m1_down) + { + m1_down = mBtn[key]; + (gViewerWindow->*(m1_down ? &LLViewerWindow::handleMouseDown : &LLViewerWindow::handleMouseUp))(gViewerWindow->getWindow(), coord, mask); + if (m1_down && gFrameTimeSeconds-last_m1 == 0.5f) + gViewerWindow->handleDoubleClick(gViewerWindow->getWindow(), coord, mask); + last_m1 = gFrameTimeSeconds; + } + static bool m2_down = false; + key = ds3 ? (U8)DS3_R1_KEY : (U8)XBOX_R_BUMP_KEY; + if (!!mBtn[key] != m2_down) + { + m2_down = mBtn[key]; + (gViewerWindow->*(m2_down ? &LLViewerWindow::handleRightMouseDown : &LLViewerWindow::handleRightMouseUp))(gViewerWindow->getWindow(), coord, mask); + } + + if (ds3) // Yay bonus keys~ + { + static bool sit_down = false; + if (!!mBtn[DS3_LOGO_KEY] != sit_down) + { + if (sit_down = mBtn[DS3_LOGO_KEY]) + (gAgentAvatarp && gAgentAvatarp->isSitting()) ? gAgent.standUp() : gAgent.sitDown(); + } + /* Singu TODO: What should these be? + DS3_L2_KEY + DS3_R2_KEY + */ } } else + // { - toggle_flycam = 0; + if (mBtn[0] == 1) + { + if (mBtn[0] != toggle_flycam) + { + toggle_flycam = toggleFlycam() ? 1 : 0; + } + } + else + { + toggle_flycam = 0; + } } - if (!mOverrideCamera && !(LLToolMgr::getInstance()->inBuildMode() && gSavedSettings.getBOOL("JoystickBuildEnabled"))) + if (sControlCursor || (!mOverrideCamera && !(LLToolMgr::getInstance()->inBuildMode() && gSavedSettings.getBOOL("JoystickBuildEnabled")))) { moveAvatar(); } @@ -1028,6 +1368,11 @@ std::string LLViewerJoystick::getDescription() { res = ll_safe_string(mNdofDev->product); } + + // + // Tidy up description of Xbox controllers. + res = boost::regex_replace(res, boost::regex("^Controller \\((.*)\\)$", boost::regex::perl), "$1"); + // #endif return res; } @@ -1046,7 +1391,7 @@ bool LLViewerJoystick::isLikeSpaceNavigator() const } // ----------------------------------------------------------------------------- -void LLViewerJoystick::setSNDefaults() +void LLViewerJoystick::setSNDefaults(S32 type) { #if LL_DARWIN || LL_LINUX const float platformScale = 20.f; @@ -1058,63 +1403,78 @@ void LLViewerJoystick::setSNDefaults() const float platformScaleAvXZ = 2.f; const bool is_3d_cursor = true; #endif - + + set_joystick_type(type); // Breaks resetting to default but allows declaring a new identity and button config for the controller //gViewerWindow->alertXml("CacheWillClear"); - llinfos << "restoring SpaceNavigator defaults..." << llendl; + const bool ouya = type == 1; + const bool xbox = ouya || type == 2; + const bool ds3 = type == 3; + LL_INFOS() << "restoring " << (xbox ? ouya ? "OUYA Game Controller" : "Xbox Controller" : ds3 ? "Dual Shock 3" : "SpaceNavigator") << " defaults..." << LL_ENDL; + + /* + Axis 0: Left Thumbstick Horizontal + Axis 1: Left Thumbstick Vertical + Axis 2: Left and Right triggers (Analog) + Axis 3: Right Thumbstick Horizontal + Axis 4: Left Thumbstick Vertical + Axis 5: Unused + Syntax/Format: + Debug setting InternalMapping,Jostick Axis (see above) */ gSavedSettings.setS32("JoystickAxis0", 1); // z (at) - gSavedSettings.setS32("JoystickAxis1", 0); // x (slide) - gSavedSettings.setS32("JoystickAxis2", 2); // y (up) - gSavedSettings.setS32("JoystickAxis3", 4); // pitch - gSavedSettings.setS32("JoystickAxis4", 3); // roll - gSavedSettings.setS32("JoystickAxis5", 5); // yaw - gSavedSettings.setS32("JoystickAxis6", -1); + gSavedSettings.setS32("JoystickAxis1", ouya ? 3 : 0); // x (slide) + gSavedSettings.setS32("JoystickAxis2", ouya ? 4 : ds3 ? 3 : 2); // y (up) + gSavedSettings.setS32("JoystickAxis3", xbox ? ouya ? 3 : -1 : 4); // roll + gSavedSettings.setS32("JoystickAxis4", xbox ? 4 : ds3 ? 5 : 3); // pitch + gSavedSettings.setS32("JoystickAxis5", xbox ? ouya ? 0 : 3 : ds3 ? 2 : 5); // yaw + gSavedSettings.setS32("JoystickAxis6", ouya ? 5 : -1); - gSavedSettings.setBOOL("Cursor3D", is_3d_cursor); + const bool game = xbox || ds3; // All game controllers are relatively the same + gSavedSettings.setBOOL("Cursor3D", !game && is_3d_cursor); gSavedSettings.setBOOL("AutoLeveling", true); gSavedSettings.setBOOL("ZoomDirect", false); - gSavedSettings.setF32("AvatarAxisScale0", 1.f * platformScaleAvXZ); - gSavedSettings.setF32("AvatarAxisScale1", 1.f * platformScaleAvXZ); - gSavedSettings.setF32("AvatarAxisScale2", 1.f); - gSavedSettings.setF32("AvatarAxisScale4", .1f * platformScale); - gSavedSettings.setF32("AvatarAxisScale5", .1f * platformScale); - gSavedSettings.setF32("AvatarAxisScale3", 0.f * platformScale); - gSavedSettings.setF32("BuildAxisScale1", .3f * platformScale); - gSavedSettings.setF32("BuildAxisScale2", .3f * platformScale); - gSavedSettings.setF32("BuildAxisScale0", .3f * platformScale); - gSavedSettings.setF32("BuildAxisScale4", .3f * platformScale); - gSavedSettings.setF32("BuildAxisScale5", .3f * platformScale); - gSavedSettings.setF32("BuildAxisScale3", .3f * platformScale); - gSavedSettings.setF32("FlycamAxisScale1", 2.f * platformScale); - gSavedSettings.setF32("FlycamAxisScale2", 2.f * platformScale); - gSavedSettings.setF32("FlycamAxisScale0", 2.1f * platformScale); - gSavedSettings.setF32("FlycamAxisScale4", .1f * platformScale); - gSavedSettings.setF32("FlycamAxisScale5", .15f * platformScale); - gSavedSettings.setF32("FlycamAxisScale3", 0.f * platformScale); - gSavedSettings.setF32("FlycamAxisScale6", 0.f * platformScale); + gSavedSettings.setF32("AvatarAxisScale0", (xbox ? 0.43f : ds3 ? 0.215f : 1.f) * platformScaleAvXZ); + gSavedSettings.setF32("AvatarAxisScale1", (xbox ? 0.43f : ds3 ? 0.215f : 1.f) * platformScaleAvXZ); + gSavedSettings.setF32("AvatarAxisScale2", xbox ? 0.43f : ds3 ? -0.43f : 1.f); + gSavedSettings.setF32("AvatarAxisScale4", ds3 ? 0.215f * platformScaleAvXZ : ((xbox ? 4.f : .1f) * platformScale)); + gSavedSettings.setF32("AvatarAxisScale5", ds3 ? 0.215f * platformScaleAvXZ : ((xbox ? 4.f : .1f) * platformScale)); + gSavedSettings.setF32("AvatarAxisScale3", (game ? 4.f : 0.f) * platformScale); + gSavedSettings.setF32("BuildAxisScale1", (game ? ouya ? 20.f : 0.8f : .3f) * platformScale); + gSavedSettings.setF32("BuildAxisScale2", (xbox ? ouya ? 20.f : 0.8f : ds3 ? -0.8f : .3f) * platformScale); + gSavedSettings.setF32("BuildAxisScale0", (game ? ouya ? 50.f : 1.6f : .3f) * platformScale); + gSavedSettings.setF32("BuildAxisScale4", (game ? ouya ? 1.8f : 1.f : .3f) * platformScale); + gSavedSettings.setF32("BuildAxisScale5", (game ? 2.f : .3f) * platformScale); + gSavedSettings.setF32("BuildAxisScale3", (game ? ouya ? -6.f : 1.f : .3f) * platformScale); + gSavedSettings.setF32("FlycamAxisScale1", (game ? ouya ? 20.f : 16.f : 2.f) * platformScale); + gSavedSettings.setF32("FlycamAxisScale2", (game ? ouya ? 20.f : 16.f : ds3 ? -16.f : 2.f) * platformScale); + gSavedSettings.setF32("FlycamAxisScale0", (game ? ouya ? 50.f : 25.f : 2.1f) * platformScale); // Z Scale + gSavedSettings.setF32("FlycamAxisScale4", (game ? ouya ? 1.80 : -4.f : .1f) * platformScale); + gSavedSettings.setF32("FlycamAxisScale5", (game ? 4.f : .15f) * platformScale); + gSavedSettings.setF32("FlycamAxisScale3", (xbox ? 4.f : ds3 ? 6.f : 0.f) * platformScale); + gSavedSettings.setF32("FlycamAxisScale6", (game ? 4.f : 0.f) * platformScale); - gSavedSettings.setF32("AvatarAxisDeadZone0", .1f); - gSavedSettings.setF32("AvatarAxisDeadZone1", .1f); - gSavedSettings.setF32("AvatarAxisDeadZone2", .1f); - gSavedSettings.setF32("AvatarAxisDeadZone3", 1.f); - gSavedSettings.setF32("AvatarAxisDeadZone4", .02f); - gSavedSettings.setF32("AvatarAxisDeadZone5", .01f); - gSavedSettings.setF32("BuildAxisDeadZone0", .01f); - gSavedSettings.setF32("BuildAxisDeadZone1", .01f); - gSavedSettings.setF32("BuildAxisDeadZone2", .01f); - gSavedSettings.setF32("BuildAxisDeadZone3", .01f); - gSavedSettings.setF32("BuildAxisDeadZone4", .01f); - gSavedSettings.setF32("BuildAxisDeadZone5", .01f); - gSavedSettings.setF32("FlycamAxisDeadZone0", .01f); - gSavedSettings.setF32("FlycamAxisDeadZone1", .01f); - gSavedSettings.setF32("FlycamAxisDeadZone2", .01f); - gSavedSettings.setF32("FlycamAxisDeadZone3", .01f); - gSavedSettings.setF32("FlycamAxisDeadZone4", .01f); - gSavedSettings.setF32("FlycamAxisDeadZone5", .01f); - gSavedSettings.setF32("FlycamAxisDeadZone6", 1.f); + gSavedSettings.setF32("AvatarAxisDeadZone0", game ? .2f : .1f); + gSavedSettings.setF32("AvatarAxisDeadZone1", game ? .2f : .1f); + gSavedSettings.setF32("AvatarAxisDeadZone2", game ? .2f : .1f); + gSavedSettings.setF32("AvatarAxisDeadZone3", game ? .2f : 1.f); + gSavedSettings.setF32("AvatarAxisDeadZone4", game ? .2f : .02f); + gSavedSettings.setF32("AvatarAxisDeadZone5", game ? .2f : .01f); + gSavedSettings.setF32("BuildAxisDeadZone0", game ? .02f : .01f); + gSavedSettings.setF32("BuildAxisDeadZone1", game ? .02f : .01f); + gSavedSettings.setF32("BuildAxisDeadZone2", game ? .02f : .01f); + gSavedSettings.setF32("BuildAxisDeadZone3", game ? .02f : .01f); + gSavedSettings.setF32("BuildAxisDeadZone4", game ? .02f : .01f); + gSavedSettings.setF32("BuildAxisDeadZone5", game ? .02f : .01f); + gSavedSettings.setF32("FlycamAxisDeadZone0", game ? .2f : .01f); + gSavedSettings.setF32("FlycamAxisDeadZone1", game ? .2f : .01f); + gSavedSettings.setF32("FlycamAxisDeadZone2", game ? .2f : .01f); + gSavedSettings.setF32("FlycamAxisDeadZone3", game ? .1f : .01f); + gSavedSettings.setF32("FlycamAxisDeadZone4", game ? .25f : .01f); + gSavedSettings.setF32("FlycamAxisDeadZone5", game ? .25f : .01f); + gSavedSettings.setF32("FlycamAxisDeadZone6", game ? .2f : 1.f); - gSavedSettings.setF32("AvatarFeathering", 6.f); + gSavedSettings.setF32("AvatarFeathering", game ? 3.f : 6.f); gSavedSettings.setF32("BuildFeathering", 12.f); - gSavedSettings.setF32("FlycamFeathering", 5.f); + gSavedSettings.setF32("FlycamFeathering", game ? 1.f : 5.f); } diff --git a/indra/newview/llviewerjoystick.h b/indra/newview/llviewerjoystick.h index 6be9db3313..058821bcd5 100644 --- a/indra/newview/llviewerjoystick.h +++ b/indra/newview/llviewerjoystick.h @@ -2,31 +2,25 @@ * @file llviewerjoystick.h * @brief Viewer joystick / NDOF device functionality. * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -56,6 +50,8 @@ class LLViewerJoystick : public LLSingleton virtual ~LLViewerJoystick(); void init(bool autoenable); + void terminate(); + void updateStatus(); void scanJoystick(); void moveObjects(bool reset = false); @@ -71,18 +67,23 @@ class LLViewerJoystick : public LLSingleton bool getOverrideCamera() { return mOverrideCamera; } void setOverrideCamera(bool val); bool toggleFlycam(); - void setSNDefaults(); + void setSNDefaults(S32 type = 0); std::string getDescription(); protected: void updateEnabled(bool autoenable); - void terminate(); void handleRun(F32 inc); void agentSlide(F32 inc); void agentPush(F32 inc); void agentFly(F32 inc); - void agentRotate(F32 pitch_inc, F32 turn_inc); + void agentPitch(F32 pitch_inc); + void agentYaw(F32 yaw_inc); void agentJump(); + // + void cursorSlide(F32 inc); + void cursorPush(F32 inc); + void cursorZoom(F32 inc); + // void resetDeltas(S32 axis[]); #if LIB_NDOF static NDOF_HotPlugResult HotPlugAddCallback(NDOF_Device *dev); diff --git a/indra/newview/llviewerkeyboard.cpp b/indra/newview/llviewerkeyboard.cpp index 1c8b3b6298..271d555ba6 100644 --- a/indra/newview/llviewerkeyboard.cpp +++ b/indra/newview/llviewerkeyboard.cpp @@ -45,7 +45,9 @@ #include "lltoolfocus.h" #include "llviewerwindow.h" #include "llvoavatarself.h" -#include "lllslconstants.h" +#include "llxuiparser.h" + +void handle_reset_view(); // // Constants @@ -57,22 +59,25 @@ const F32 FLY_FRAMES = 4; const F32 NUDGE_TIME = 0.25f; // in seconds const S32 NUDGE_FRAMES = 2; const F32 ORBIT_NUDGE_RATE = 0.05f; // fraction of normal speed -const F32 YAW_NUDGE_RATE = 0.05f; // fraction of normal speed -LLViewerKeyboard gViewerKeyboard; +struct LLKeyboardActionRegistry +: public LLRegistrySingleton, LLKeyboardActionRegistry> +{ +}; -bool isCrouch = false; //Shouldn't start crouched. +LLViewerKeyboard gViewerKeyboard; void agent_jump( EKeystate s ) { if( KEYSTATE_UP == s ) return; + static LLCachedControl sAutomaticFly(gSavedSettings, "AutomaticFly"); F32 time = gKeyboard->getCurKeyElapsedTime(); - S32 frame_count = llround(gKeyboard->getCurKeyElapsedFrameCount()); - isCrouch = false; + S32 frame_count = ll_round(gKeyboard->getCurKeyElapsedFrameCount()); + if( time < FLY_TIME || frame_count <= FLY_FRAMES || gAgent.upGrabbed() - || !gSavedSettings.getBOOL("AutomaticFly")) + || !sAutomaticFly()) { gAgent.moveUp(1); } @@ -82,40 +87,50 @@ void agent_jump( EKeystate s ) gAgent.moveUp(1); } } + void agent_toggle_down( EKeystate s ) { - if(KEYSTATE_UP == s) return; - - gAgent.moveUp(-1); - if(KEYSTATE_DOWN == s && !gAgent.getFlying() && gSavedSettings.getBOOL("SGShiftCrouchToggle")) + if (KEYSTATE_UP == s) return; + + static LLCachedControl sCrouchToggle(gSavedSettings, "SGShiftCrouchToggle"); + if (KEYSTATE_DOWN == s + && !gAgent.getFlying() + && sCrouchToggle()) { - isCrouch = !isCrouch; + gAgent.toggleCrouch(); } + gAgent.moveUp(-1); } void agent_push_down( EKeystate s ) { - if( KEYSTATE_UP == s ) return; + if( KEYSTATE_UP == s ) return; gAgent.moveUp(-1); - isCrouch = false; +} + +static void agent_check_temporary_run(LLAgent::EDoubleTapRunMode mode) +{ +// if (gAgent.mDoubleTapRunMode == mode && +// gAgent.getRunning() && +// !gAgent.getAlwaysRun()) +// { +// // Turn off temporary running. +// gAgent.clearRunning(); +// gAgent.sendWalkRun(gAgent.getRunning()); +// } +// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i + if ( (gAgent.mDoubleTapRunMode == mode) && (gAgent.getTempRun()) ) + gAgent.clearTempRun(); +// [/RLVa:KB] } static void agent_handle_doubletap_run(EKeystate s, LLAgent::EDoubleTapRunMode mode) { if (KEYSTATE_UP == s) { -// if (gAgent.mDoubleTapRunMode == mode && -// gAgent.getRunning() && -// !gAgent.getAlwaysRun()) -// { -// // Turn off temporary running. -// gAgent.clearRunning(); -// gAgent.sendWalkRun(gAgent.getRunning()); -// } -// [RLVa:KB] - Checked: 2011-05-11 (RLVa-1.3.0i) | Added: RLVa-1.3.0i - if ( (gAgent.mDoubleTapRunMode == mode) && (gAgent.getTempRun()) ) - gAgent.clearTempRun(); -// [/RLVa:KB] + // Note: in case shift is already released, slide left/right run + // will be released in agent_turn_left()/agent_turn_right() + agent_check_temporary_run(mode); } else if (gSavedSettings.getBOOL("AllowTapTapHoldRun") && KEYSTATE_DOWN == s && @@ -145,7 +160,7 @@ static void agent_push_forwardbackward( EKeystate s, S32 direction, LLAgent::EDo if (KEYSTATE_UP == s) return; F32 time = gKeyboard->getCurKeyElapsedTime(); - S32 frame_count = llround(gKeyboard->getCurKeyElapsedFrameCount()); + S32 frame_count = ll_round(gKeyboard->getCurKeyElapsedFrameCount()); if( time < NUDGE_TIME || frame_count <= NUDGE_FRAMES) { @@ -173,7 +188,7 @@ static void agent_slide_leftright( EKeystate s, S32 direction, LLAgent::EDoubleT agent_handle_doubletap_run(s, mode); if( KEYSTATE_UP == s ) return; F32 time = gKeyboard->getCurKeyElapsedTime(); - S32 frame_count = llround(gKeyboard->getCurKeyElapsedFrameCount()); + S32 frame_count = ll_round(gKeyboard->getCurKeyElapsedFrameCount()); if( time < NUDGE_TIME || frame_count <= NUDGE_FRAMES) { @@ -205,7 +220,10 @@ void agent_turn_left( EKeystate s ) } else { - if (KEYSTATE_UP == s) return; + if (KEYSTATE_UP == s) + { + return; + } F32 time = gKeyboard->getCurKeyElapsedTime(); gAgent.moveYaw( LLFloaterMove::getYawRate( time ) ); } @@ -220,7 +238,10 @@ void agent_turn_right( EKeystate s ) } else { - if (KEYSTATE_UP == s) return; + if (KEYSTATE_UP == s) + { + return; + } F32 time = gKeyboard->getCurKeyElapsedTime(); gAgent.moveYaw( -LLFloaterMove::getYawRate( time ) ); } @@ -246,8 +267,7 @@ void agent_toggle_fly( EKeystate s ) // Only catch the edge if (KEYSTATE_DOWN == s ) { - gAgent.toggleFlying(); - isCrouch = false; + LLAgent::toggleFlying(); } } @@ -257,7 +277,7 @@ F32 get_orbit_rate() if( time < NUDGE_TIME ) { F32 rate = ORBIT_NUDGE_RATE + time * (1 - ORBIT_NUDGE_RATE)/ NUDGE_TIME; - //llinfos << rate << llendl; + //LL_INFOS() << rate << LL_ENDL; return rate; } else @@ -522,76 +542,85 @@ void stop_moving( EKeystate s ) void start_chat( EKeystate s ) { + if (LLAppViewer::instance()->quitRequested()) + { + return; // can't talk, gotta go, kthxbye! + } + // start chat - gChatBar->startChat(NULL); + LLChatBar::startChat(NULL); } void start_gesture( EKeystate s ) { + if (LLAppViewer::instance()->quitRequested()) + { + return; // can't talk, gotta go, kthxbye! + } + LLUICtrl* focus_ctrlp = dynamic_cast(gFocusMgr.getKeyboardFocus()); if (KEYSTATE_UP == s && ! (focus_ctrlp && focus_ctrlp->acceptsTextInput())) { - if (gChatBar->getCurrentChat().empty()) + if (gChatBar && gChatBar->getCurrentChat().empty()) { // No existing chat in chat editor, insert '/' - gChatBar->startChat("/"); + LLChatBar::startChat("/"); } else { // Don't overwrite existing text in chat editor - gChatBar->startChat(NULL); + LLChatBar::startChat(NULL); } } } -void bind_keyboard_functions() -{ - gViewerKeyboard.bindNamedFunction("jump", agent_jump); - gViewerKeyboard.bindNamedFunction("push_down", agent_push_down); - gViewerKeyboard.bindNamedFunction("push_forward", agent_push_forward); - gViewerKeyboard.bindNamedFunction("push_backward", agent_push_backward); - gViewerKeyboard.bindNamedFunction("look_up", agent_look_up); - gViewerKeyboard.bindNamedFunction("look_down", agent_look_down); - gViewerKeyboard.bindNamedFunction("toggle_down", agent_toggle_down); - gViewerKeyboard.bindNamedFunction("toggle_fly", agent_toggle_fly); - gViewerKeyboard.bindNamedFunction("turn_left", agent_turn_left); - gViewerKeyboard.bindNamedFunction("turn_right", agent_turn_right); - gViewerKeyboard.bindNamedFunction("slide_left", agent_slide_left); - gViewerKeyboard.bindNamedFunction("slide_right", agent_slide_right); - gViewerKeyboard.bindNamedFunction("spin_around_ccw", camera_spin_around_ccw); - gViewerKeyboard.bindNamedFunction("spin_around_cw", camera_spin_around_cw); - gViewerKeyboard.bindNamedFunction("spin_around_ccw_sitting", camera_spin_around_ccw_sitting); - gViewerKeyboard.bindNamedFunction("spin_around_cw_sitting", camera_spin_around_cw_sitting); - gViewerKeyboard.bindNamedFunction("spin_over", camera_spin_over); - gViewerKeyboard.bindNamedFunction("spin_under", camera_spin_under); - gViewerKeyboard.bindNamedFunction("spin_over_sitting", camera_spin_over_sitting); - gViewerKeyboard.bindNamedFunction("spin_under_sitting", camera_spin_under_sitting); - gViewerKeyboard.bindNamedFunction("move_forward", camera_move_forward); - gViewerKeyboard.bindNamedFunction("move_backward", camera_move_backward); - gViewerKeyboard.bindNamedFunction("move_forward_sitting", camera_move_forward_sitting); - gViewerKeyboard.bindNamedFunction("move_backward_sitting", camera_move_backward_sitting); - gViewerKeyboard.bindNamedFunction("pan_up", camera_pan_up); - gViewerKeyboard.bindNamedFunction("pan_down", camera_pan_down); - gViewerKeyboard.bindNamedFunction("pan_left", camera_pan_left); - gViewerKeyboard.bindNamedFunction("pan_right", camera_pan_right); - gViewerKeyboard.bindNamedFunction("pan_in", camera_pan_in); - gViewerKeyboard.bindNamedFunction("pan_out", camera_pan_out); - gViewerKeyboard.bindNamedFunction("move_forward_fast", camera_move_forward_fast); - gViewerKeyboard.bindNamedFunction("move_backward_fast", camera_move_backward_fast); - gViewerKeyboard.bindNamedFunction("edit_avatar_spin_ccw", edit_avatar_spin_ccw); - gViewerKeyboard.bindNamedFunction("edit_avatar_spin_cw", edit_avatar_spin_cw); - gViewerKeyboard.bindNamedFunction("edit_avatar_spin_over", edit_avatar_spin_over); - gViewerKeyboard.bindNamedFunction("edit_avatar_spin_under", edit_avatar_spin_under); - gViewerKeyboard.bindNamedFunction("edit_avatar_move_forward", edit_avatar_move_forward); - gViewerKeyboard.bindNamedFunction("edit_avatar_move_backward", edit_avatar_move_backward); - gViewerKeyboard.bindNamedFunction("stop_moving", stop_moving); - gViewerKeyboard.bindNamedFunction("start_chat", start_chat); - gViewerKeyboard.bindNamedFunction("start_gesture", start_gesture); -} - -LLViewerKeyboard::LLViewerKeyboard() : - mNamedFunctionCount(0) +#define REGISTER_KEYBOARD_ACTION(KEY, ACTION) LLREGISTER_STATIC(LLKeyboardActionRegistry, KEY, ACTION); +REGISTER_KEYBOARD_ACTION("jump", agent_jump); +REGISTER_KEYBOARD_ACTION("push_down", agent_push_down); +REGISTER_KEYBOARD_ACTION("toggle_down", agent_toggle_down); +REGISTER_KEYBOARD_ACTION("push_forward", agent_push_forward); +REGISTER_KEYBOARD_ACTION("push_backward", agent_push_backward); +REGISTER_KEYBOARD_ACTION("look_up", agent_look_up); +REGISTER_KEYBOARD_ACTION("look_down", agent_look_down); +REGISTER_KEYBOARD_ACTION("toggle_fly", agent_toggle_fly); +REGISTER_KEYBOARD_ACTION("turn_left", agent_turn_left); +REGISTER_KEYBOARD_ACTION("turn_right", agent_turn_right); +REGISTER_KEYBOARD_ACTION("slide_left", agent_slide_left); +REGISTER_KEYBOARD_ACTION("slide_right", agent_slide_right); +REGISTER_KEYBOARD_ACTION("spin_around_ccw", camera_spin_around_ccw); +REGISTER_KEYBOARD_ACTION("spin_around_cw", camera_spin_around_cw); +REGISTER_KEYBOARD_ACTION("spin_around_ccw_sitting", camera_spin_around_ccw_sitting); +REGISTER_KEYBOARD_ACTION("spin_around_cw_sitting", camera_spin_around_cw_sitting); +REGISTER_KEYBOARD_ACTION("spin_over", camera_spin_over); +REGISTER_KEYBOARD_ACTION("spin_under", camera_spin_under); +REGISTER_KEYBOARD_ACTION("spin_over_sitting", camera_spin_over_sitting); +REGISTER_KEYBOARD_ACTION("spin_under_sitting", camera_spin_under_sitting); +REGISTER_KEYBOARD_ACTION("move_forward", camera_move_forward); +REGISTER_KEYBOARD_ACTION("move_backward", camera_move_backward); +REGISTER_KEYBOARD_ACTION("move_forward_sitting", camera_move_forward_sitting); +REGISTER_KEYBOARD_ACTION("move_backward_sitting", camera_move_backward_sitting); +REGISTER_KEYBOARD_ACTION("pan_up", camera_pan_up); +REGISTER_KEYBOARD_ACTION("pan_down", camera_pan_down); +REGISTER_KEYBOARD_ACTION("pan_left", camera_pan_left); +REGISTER_KEYBOARD_ACTION("pan_right", camera_pan_right); +REGISTER_KEYBOARD_ACTION("pan_in", camera_pan_in); +REGISTER_KEYBOARD_ACTION("pan_out", camera_pan_out); +REGISTER_KEYBOARD_ACTION("move_forward_fast", camera_move_forward_fast); +REGISTER_KEYBOARD_ACTION("move_backward_fast", camera_move_backward_fast); +REGISTER_KEYBOARD_ACTION("edit_avatar_spin_ccw", edit_avatar_spin_ccw); +REGISTER_KEYBOARD_ACTION("edit_avatar_spin_cw", edit_avatar_spin_cw); +REGISTER_KEYBOARD_ACTION("edit_avatar_spin_over", edit_avatar_spin_over); +REGISTER_KEYBOARD_ACTION("edit_avatar_spin_under", edit_avatar_spin_under); +REGISTER_KEYBOARD_ACTION("edit_avatar_move_forward", edit_avatar_move_forward); +REGISTER_KEYBOARD_ACTION("edit_avatar_move_backward", edit_avatar_move_backward); +REGISTER_KEYBOARD_ACTION("stop_moving", stop_moving); +REGISTER_KEYBOARD_ACTION("start_chat", start_chat); +REGISTER_KEYBOARD_ACTION("start_gesture", start_gesture); +REGISTER_KEYBOARD_ACTION("reset_camera", boost::bind(handle_reset_view)); +#undef REGISTER_KEYBOARD_ACTION + +LLViewerKeyboard::LLViewerKeyboard() { for (S32 i = 0; i < MODE_COUNT; i++) { @@ -609,16 +638,6 @@ LLViewerKeyboard::LLViewerKeyboard() : } } - -void LLViewerKeyboard::bindNamedFunction(const std::string& name, LLKeyFunc func) -{ - S32 i = mNamedFunctionCount; - mNamedFunctions[i].mName = name; - mNamedFunctions[i].mFunction = func; - mNamedFunctionCount++; -} - - BOOL LLViewerKeyboard::modeFromString(const std::string& string, S32 *mode) { if (string == "FIRST_PERSON") @@ -672,27 +691,35 @@ BOOL LLViewerKeyboard::handleKey(KEY translated_key, MASK translated_mask, BOOL return FALSE; } - lldebugst(LLERR_USER_INPUT) << "keydown -" << translated_key << "-" << llendl; + LL_DEBUGS("UserInput") << "keydown -" << translated_key << "-" << LL_ENDL; // skip skipped keys if(mKeysSkippedByUI.find(translated_key) != mKeysSkippedByUI.end()) { mKeyHandledByUI[translated_key] = FALSE; + LL_INFOS("Keyboard Handling") << "Key wasn't handled by UI!" << LL_ENDL; } else { // it is sufficient to set this value once per call to handlekey // without clearing it, as it is only used in the subsequent call to scanKey mKeyHandledByUI[translated_key] = gViewerWindow->handleKey(translated_key, translated_mask); + // mKeyHandledByUI is not what you think ... this indicates whether the UI has handled this keypress yet (any keypress) + // NOT whether some UI shortcut wishes to handle the keypress + } return mKeyHandledByUI[translated_key]; } - +BOOL LLViewerKeyboard::handleKeyUp(KEY translated_key, MASK translated_mask) +{ + return gViewerWindow->handleKeyUp(translated_key, translated_mask); +} BOOL LLViewerKeyboard::bindKey(const S32 mode, const KEY key, const MASK mask, const std::string& function_name) { - S32 i,index; - void (*function)(EKeystate keystate) = NULL; + S32 index; + typedef std::function function_t; + function_t function; std::string name; // Allow remapping of F2-F12 @@ -715,18 +742,16 @@ BOOL LLViewerKeyboard::bindKey(const S32 mode, const KEY key, const MASK mask, c } // Not remapped, look for a function - for (i = 0; i < mNamedFunctionCount; i++) + + function_t* result = LLKeyboardActionRegistry::getValue(function_name); + if (result) { - if (function_name == mNamedFunctions[i].mName) - { - function = mNamedFunctions[i].mFunction; - name = mNamedFunctions[i].mName; - } + function = *result; } if (!function) { - llerrs << "Can't bind key to function " << function_name << ", no function with this name found" << llendl; + LL_ERRS() << "Can't bind key to function " << function_name << ", no function with this name found" << LL_ENDL; return FALSE; } @@ -739,19 +764,18 @@ BOOL LLViewerKeyboard::bindKey(const S32 mode, const KEY key, const MASK mask, c if (index >= MAX_KEY_BINDINGS) { - llerrs << "LLKeyboard::bindKey() - too many keys for mode " << mode << llendl; + LL_ERRS() << "LLKeyboard::bindKey() - too many keys for mode " << mode << LL_ENDL; return FALSE; } if (mode >= MODE_COUNT) { - llerror("LLKeyboard::bindKey() - unknown mode passed", mode); + LL_ERRS() << "LLKeyboard::bindKey() - unknown mode passed" << mode << LL_ENDL; return FALSE; } mBindings[mode][index].mKey = key; mBindings[mode][index].mMask = mask; -// mBindings[mode][index].mName = name; mBindings[mode][index].mFunction = function; if (index == mBindingCount[mode]) @@ -760,6 +784,61 @@ BOOL LLViewerKeyboard::bindKey(const S32 mode, const KEY key, const MASK mask, c return TRUE; } +LLViewerKeyboard::KeyBinding::KeyBinding() +: key("key"), + mask("mask"), + command("command") +{} + +LLViewerKeyboard::KeyMode::KeyMode(EKeyboardMode _mode) +: bindings("binding"), + mode(_mode) +{} + +LLViewerKeyboard::Keys::Keys() +: first_person("first_person", KeyMode(MODE_FIRST_PERSON)), + third_person("third_person", KeyMode(MODE_THIRD_PERSON)), + edit("edit", KeyMode(MODE_EDIT)), + sitting("sitting", KeyMode(MODE_SITTING)), + edit_avatar("edit_avatar", KeyMode(MODE_EDIT_AVATAR)) +{} + +S32 LLViewerKeyboard::loadBindingsXML(const std::string& filename) +{ + S32 binding_count = 0; + Keys keys; + LLSimpleXUIParser parser; + + if (parser.readXUI(filename, keys) + && keys.validateBlock()) + { + binding_count += loadBindingMode(keys.first_person); + binding_count += loadBindingMode(keys.third_person); + binding_count += loadBindingMode(keys.edit); + binding_count += loadBindingMode(keys.sitting); + binding_count += loadBindingMode(keys.edit_avatar); + } + return binding_count; +} + +S32 LLViewerKeyboard::loadBindingMode(const LLViewerKeyboard::KeyMode& keymode) +{ + S32 binding_count = 0; + for (LLInitParam::ParamIterator::const_iterator it = keymode.bindings.begin(), + end_it = keymode.bindings.end(); + it != end_it; + ++it) + { + KEY key; + MASK mask; + LLKeyboard::keyFromString(it->key, &key); + LLKeyboard::maskFromString(it->mask, &mask); + bindKey(keymode.mode, key, mask, it->command); + binding_count++; + } + + return binding_count; +} S32 LLViewerKeyboard::loadBindings(const std::string& filename) { @@ -780,7 +859,7 @@ S32 LLViewerKeyboard::loadBindings(const std::string& filename) if(filename.empty()) { - llerrs << " No filename specified" << llendl; + LL_ERRS() << " No filename specified" << LL_ENDL; return 0; } @@ -812,35 +891,35 @@ S32 LLViewerKeyboard::loadBindings(const std::string& filename) if (tokens_read == EOF) { - llinfos << "Unexpected end-of-file at line " << line_count << " of key binding file " << filename << llendl; + LL_INFOS() << "Unexpected end-of-file at line " << line_count << " of key binding file " << filename << LL_ENDL; fclose(fp); return 0; } else if (tokens_read < 4) { - llinfos << "Can't read line " << line_count << " of key binding file " << filename << llendl; + LL_INFOS() << "Can't read line " << line_count << " of key binding file " << filename << LL_ENDL; continue; } // convert mode if (!modeFromString(mode_string, &mode)) { - llinfos << "Unknown mode on line " << line_count << " of key binding file " << filename << llendl; - llinfos << "Mode must be one of FIRST_PERSON, THIRD_PERSON, EDIT, EDIT_AVATAR" << llendl; + LL_INFOS() << "Unknown mode on line " << line_count << " of key binding file " << filename << LL_ENDL; + LL_INFOS() << "Mode must be one of FIRST_PERSON, THIRD_PERSON, EDIT, EDIT_AVATAR" << LL_ENDL; continue; } // convert key if (!LLKeyboard::keyFromString(key_string, &key)) { - llinfos << "Can't interpret key on line " << line_count << " of key binding file " << filename << llendl; + LL_INFOS() << "Can't interpret key on line " << line_count << " of key binding file " << filename << LL_ENDL; continue; } // convert mask if (!LLKeyboard::maskFromString(mask_string, &mask)) { - llinfos << "Can't interpret mask on line " << line_count << " of key binding file " << filename << llendl; + LL_INFOS() << "Can't interpret mask on line " << line_count << " of key binding file " << filename << LL_ENDL; continue; } @@ -856,6 +935,14 @@ S32 LLViewerKeyboard::loadBindings(const std::string& filename) return binding_count; } +void LLViewerKeyboard::unloadBindings() +{ + for (S32 mode = 0; mode < MODE_COUNT; ++mode) + { + mRemapKeys[mode].clear(); + mBindingCount[mode] = 0; + } +} EKeyboardMode LLViewerKeyboard::getMode() { @@ -908,18 +995,18 @@ void LLViewerKeyboard::scanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_lev if (key_down && !repeat) { // ...key went down this frame, call function - (*binding[i].mFunction)( KEYSTATE_DOWN ); + binding[i].mFunction( KEYSTATE_DOWN ); } else if (key_up) { // ...key went down this frame, call function - (*binding[i].mFunction)( KEYSTATE_UP ); + binding[i].mFunction( KEYSTATE_UP ); } else if (key_level) { // ...key held down from previous frame // Not windows, just call the function. - (*binding[i].mFunction)( KEYSTATE_LEVEL ); + binding[i].mFunction( KEYSTATE_LEVEL ); }//if }//if }//for diff --git a/indra/newview/llviewerkeyboard.h b/indra/newview/llviewerkeyboard.h index b52b738bd4..bcc937f498 100644 --- a/indra/newview/llviewerkeyboard.h +++ b/indra/newview/llviewerkeyboard.h @@ -2,31 +2,25 @@ * @file llviewerkeyboard.h * @brief LLViewerKeyboard class header file * - * $LicenseInfo:firstyear=2005&license=viewergpl$ - * - * Copyright (c) 2005-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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$ */ @@ -34,6 +28,7 @@ #define LL_LLVIEWERKEYBOARD_H #include "llkeyboard.h" // For EKeystate +#include "llinitparam.h" const S32 MAX_NAMED_FUNCTIONS = 100; const S32 MAX_KEY_BINDINGS = 128; // was 60 @@ -61,26 +56,53 @@ typedef enum e_keyboard_mode void bind_keyboard_functions(); - class LLViewerKeyboard { public: + struct KeyBinding : public LLInitParam::Block + { + Mandatory key, + mask, + command; + + KeyBinding(); + }; + + struct KeyMode : public LLInitParam::Block + { + Multiple bindings; + EKeyboardMode mode; + KeyMode(EKeyboardMode mode); + }; + + struct Keys : public LLInitParam::Block + { + Optional first_person, + third_person, + edit, + sitting, + edit_avatar; + + Keys(); + }; + LLViewerKeyboard(); BOOL handleKey(KEY key, MASK mask, BOOL repeated); - - void bindNamedFunction(const std::string& name, LLKeyFunc func); + BOOL handleKeyUp(KEY key, MASK mask); S32 loadBindings(const std::string& filename); // returns number bound, 0 on error + S32 loadBindingsXML(const std::string& filename); // returns number bound, 0 on error + void unloadBindings(); EKeyboardMode getMode(); BOOL modeFromString(const std::string& string, S32 *mode); // False on failure void scanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level); -protected: + +private: + S32 loadBindingMode(const LLViewerKeyboard::KeyMode& keymode); BOOL bindKey(const S32 mode, const KEY key, const MASK mask, const std::string& function_name); - S32 mNamedFunctionCount; - LLNamedFunction mNamedFunctions[MAX_NAMED_FUNCTIONS]; // Hold all the ugly stuff torn out to make LLKeyboard non-viewer-specific here S32 mBindingCount[MODE_COUNT]; @@ -93,5 +115,6 @@ class LLViewerKeyboard }; extern LLViewerKeyboard gViewerKeyboard; -extern bool isCrouch; +void agent_push_forward(EKeystate s); + #endif // LL_LLVIEWERKEYBOARD_H diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 6b3aa2a21c..06047dcf69 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -32,9 +32,6 @@ #include "llviewerprecompiledheaders.h" -#include "llviewermedia.h" - - #include "llviewermedia.h" #include "llagent.h" @@ -45,12 +42,14 @@ #include "lldir.h" #include "lldiriterator.h" #include "llevent.h" // LLSimpleListener +#include "aifilepicker.h" +#include "llfloaterdestinations.h" #include "llfloaterwebcontent.h" // for handling window close requests and geometry change requests in media browser windows. #include "llfocusmgr.h" -#include "llhttpclient.h" #include "llkeyboard.h" #include "llmarketplacefunctions.h" #include "llmediaentry.h" +#include "llmenugl.h" #include "llmimetypes.h" #include "llmutelist.h" #include "llnotifications.h" @@ -58,7 +57,6 @@ #include "llpanelprofile.h" #include "llparcel.h" #include "llpluginclassmedia.h" -#include "llplugincookiestore.h" #include "llurldispatcher.h" #include "lluuid.h" #include "llvieweraudio.h" @@ -77,13 +75,10 @@ #include "llwebprofile.h" #include "llwindow.h" #include "llvieweraudio.h" +#include "llhttpclient.h" -#include "aifilepicker.h" #include "llstartup.h" -#include // for SkinFolder listener -#include - std::string getProfileURL(const std::string& agent_name); /*static*/ const char* LLViewerMedia::AUTO_PLAY_MEDIA_SETTING = "ParcelMediaAutoPlayEnable"; @@ -93,11 +88,6 @@ std::string getProfileURL(const std::string& agent_name); /*static*/ const char* LLViewerMedia::SHOW_MEDIA_OUTSIDE_PARCEL_SETTING = "MediaShowOutsideParcel"; -class AIHTTPTimeoutPolicy; -extern AIHTTPTimeoutPolicy mimeDiscoveryResponder_timeout; -extern AIHTTPTimeoutPolicy viewerMediaOpenIDResponder_timeout; -extern AIHTTPTimeoutPolicy viewerMediaWebProfileResponder_timeout; - // Move this to its own file. LLViewerMediaEventEmitter::~LLViewerMediaEventEmitter() @@ -176,47 +166,70 @@ class LLMimeDiscoveryResponder : public LLHTTPClient::ResponderHeadersOnly { LOG_CLASS(LLMimeDiscoveryResponder); public: - LLMimeDiscoveryResponder(viewer_media_t media_impl, std::string const& default_mime_type) + LLMimeDiscoveryResponder( viewer_media_t media_impl) : mMediaImpl(media_impl), - mDefaultMimeType(default_mime_type), mInitialized(false) { - if(mMediaImpl->mMimeTypeProbe != NULL) + if(mMediaImpl->mMimeProbe) { - llerrs << "impl already has an outstanding responder" << llendl; + LL_ERRS() << "impl already has an outstanding responder" << LL_ENDL; } - mMediaImpl->mMimeTypeProbe = this; + mMediaImpl->mMimeProbe = this; } - ~LLMimeDiscoveryResponder() - { - disconnectOwner(); - } + ~LLMimeDiscoveryResponder() { disconnectOwner(); } - /*virtual*/ void completedHeaders(U32 status, std::string const& reason, AIHTTPReceivedHeaders const& headers) - { - if ((200 <= status && status < 300) || status == 405) // Using HEAD may result in a 405 METHOD NOT ALLOWED, but still have the right Content-Type header. - { - std::string media_type; - if (headers.getFirstValue("content-type", media_type)) - { - std::string::size_type idx1 = media_type.find_first_of(";"); - std::string mime_type = media_type.substr(0, idx1); - completeAny(status, mime_type); - return; - } - if (200 <= status && status < 300) +private: + /* virtual */ void completedHeaders() + { + if (!isGoodStatus(mStatus)) + { + LL_WARNS() << dumpResponse() + << " [headers:" << getResponseHeaders() << "]" << LL_ENDL; + } + std::string media_type; + std::string::size_type idx1 = media_type.find_first_of(";"); + std::string mime_type = media_type.substr(0, idx1); + + LL_DEBUGS() << "status is " << getStatus() << ", media type \"" << media_type << "\"" << LL_ENDL; + + // 2xx status codes indicate success. + // Most 4xx status codes are successful enough for our purposes. + // 499 is the error code for host not found, timeout, etc. + // 500 means "Internal Server error" but we decided it's okay to + // accept this and go past it in the MIME type probe + // 302 means the resource can be found temporarily in a different place - added this for join.secondlife.com + // 499 is a code specifc to join.secondlife.com apparently safe to ignore +// if( ((status >= 200) && (status < 300)) || +// ((status >= 400) && (status < 499)) || +// (status == 500) || +// (status == 302) || +// (status == 499) +// ) + // We now no longer check the error code returned from the probe. + // If we have a mime type, use it. If not, default to the web plugin and let it handle error reporting. + //if(1) + { + // The probe was successful. + if(mime_type.empty()) { - llwarns << "LLMimeDiscoveryResponder::completedHeaders: OK HTTP status (" << status << ") but no Content-Type! Received headers: " << headers << llendl; + // Some sites don't return any content-type header at all. + // Treat an empty mime type as text/html. + mime_type = "text/html"; } } - llwarns << "LLMimeDiscoveryResponder::completedHeaders: Got status " << status << ". Using default mime-type: " << mDefaultMimeType << llendl; - completeAny(status, mDefaultMimeType); - } + //else + //{ + // LL_WARNS() << "responder failed with status " << dumpResponse() << LL_ENDL; + // + // if(mMediaImpl) + // { + // mMediaImpl->mMediaSourceFailed = true; + // } + // return; + //} - void completeAny(U32 status, const std::string& mime_type) - { // the call to initializeMedia may disconnect the responder, which will clear mMediaImpl. // Make a local copy so we can call loadURI() afterwards. LLViewerMediaImpl *impl = mMediaImpl; @@ -232,8 +245,7 @@ LOG_CLASS(LLMimeDiscoveryResponder); } } - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return mimeDiscoveryResponder_timeout; } - +public: /*virtual*/ char const* getName(void) const { return "LLMimeDiscoveryResponder"; } void cancelRequest() { @@ -245,20 +257,19 @@ LOG_CLASS(LLMimeDiscoveryResponder); { if(mMediaImpl) { - if(mMediaImpl->mMimeTypeProbe != this) + if(mMediaImpl->mMimeProbe != this) { - llerrs << "internal error: mMediaImpl->mMimeTypeProbe != this" << llendl; + LL_ERRS() << "internal error: mMediaImpl->mMimeProbe != this" << LL_ENDL; } - mMediaImpl->mMimeTypeProbe = NULL; + mMediaImpl->mMimeProbe = nullptr; } - mMediaImpl = NULL; + mMediaImpl = nullptr; } public: - viewer_media_t mMediaImpl; - std::string mDefaultMimeType; + LLViewerMediaImpl *mMediaImpl; bool mInitialized; }; @@ -274,92 +285,75 @@ LOG_CLASS(LLViewerMediaOpenIDResponder); { } - /*virtual*/ bool needsHeaders(void) const { return true; } - - /*virtual*/ void completedHeaders(U32 status, std::string const& reason, AIHTTPReceivedHeaders const& headers) - { - LL_DEBUGS("MediaAuth") << "status = " << status << ", reason = " << reason << LL_ENDL; - LL_DEBUGS("MediaAuth") << headers << LL_ENDL; - LLViewerMedia::openIDCookieResponse(get_cookie("agni_sl_session_id")); - } - - /*virtual*/ void completedRaw( - U32 status, - const std::string& reason, + /* virtual */ void completedRaw( const LLChannelDescriptors& channels, const LLIOPipe::buffer_ptr_t& buffer) { - // This is just here to disable the default behavior (attempting to parse the response as llsd). - // We don't care about the content of the response, only the set-cookie header. + // We don't care about the content of the response, only the Set-Cookie header. + LL_DEBUGS("MediaAuth") << dumpResponse() + << " [headers:" << getResponseHeaders() << "]" << LL_ENDL; + std::string cookie; + getResponseHeaders().getFirstValue("set-cookie", cookie); + + // *TODO: What about bad status codes? Does this destroy previous cookies? + LLViewerMedia::openIDCookieResponse(cookie); } - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return viewerMediaOpenIDResponder_timeout; } /*virtual*/ char const* getName(void) const { return "LLViewerMediaOpenIDResponder"; } + /*virtual*/ bool needsHeaders(void) const { return true; } }; class LLViewerMediaWebProfileResponder : public LLHTTPClient::ResponderWithCompleted { LOG_CLASS(LLViewerMediaWebProfileResponder); public: - LLViewerMediaWebProfileResponder(std::string host) : mHost(host) { } - ~LLViewerMediaWebProfileResponder() { } + LLViewerMediaWebProfileResponder(std::string host) + { + mHost = host; + } - /*virtual*/ bool followRedir(void) const { return true; } - /*virtual*/ bool needsHeaders(void) const { return true; } + ~LLViewerMediaWebProfileResponder() + { + } - /*virtual*/ void completedHeaders(U32 status, std::string const& reason, AIHTTPReceivedHeaders const& headers) + void completedRaw( + const LLChannelDescriptors& channels, + const LLIOPipe::buffer_ptr_t& buffer) { - LL_INFOS("MediaAuth") << "status = " << status << ", reason = " << reason << LL_ENDL; - LL_INFOS("MediaAuth") << headers << LL_ENDL; + // We don't care about the content of the response, only the set-cookie header. + LL_WARNS("MediaAuth") << dumpResponse() + << " [headers:" << getResponseHeaders() << "]" << LL_ENDL; + + AIHTTPReceivedHeaders stripped_content = getResponseHeaders(); + LL_WARNS("MediaAuth") << stripped_content << LL_ENDL; - bool found = false; AIHTTPReceivedHeaders::range_type cookies; - if (headers.getValues("set-cookie", cookies)) + if (mReceivedHeaders.getValues("set-cookie", cookies)) { for (AIHTTPReceivedHeaders::iterator_type cookie = cookies.first; cookie != cookies.second; ++cookie) { - LLViewerMedia::getCookieStore()->setCookiesFromHost(cookie->second, mHost); - - std::string key = cookie->second.substr(0, cookie->second.find('=')); - if (key == "_my_secondlife_session") - { - // Set cookie for snapshot publishing. - std::string auth_cookie = cookie->second.substr(0, cookie->second.find(";")); // strip path - LL_INFOS("MediaAuth") << "Setting openID auth cookie \"" << auth_cookie << "\"." << LL_ENDL; - LLWebProfile::setAuthCookie(auth_cookie); - found = true; - break; - } + // *TODO: What about bad status codes? Does this destroy previous cookies? + if (cookie->second.substr(0, cookie->second.find('=')) == "_my_secondlife_session") + { + // Set cookie for snapshot publishing. + std::string auth_cookie = cookie->second.substr(0, cookie->second.find(";")); // strip path + LLWebProfile::setAuthCookie(auth_cookie); + break; + } } } - if (!found) - { - llwarns << "LLViewerMediaWebProfileResponder did not receive a session ID cookie \"_my_secondlife_session\"! OpenID authentications will fail!" << llendl; - } - } - - /*virtual*/ void completedRaw( - U32 status, - const std::string& reason, - const LLChannelDescriptors& channels, - const LLIOPipe::buffer_ptr_t& buffer) - { - // This is just here to disable the default behavior (attempting to parse the response as llsd). - // We don't care about the content of the response, only the set-cookie header. } - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return viewerMediaWebProfileResponder_timeout; } - /*virtual*/ char const* getName(void) const { return "LLViewerMediaWebProfileResponder"; } + /*virtual*/ char const* getName() const { return "LLViewerMediaWebProfileResponder"; } + /*virtual*/ bool needsHeaders() const { return true; } -private: std::string mHost; }; -LLPluginCookieStore *LLViewerMedia::sCookieStore = NULL; LLURL LLViewerMedia::sOpenIDURL; std::string LLViewerMedia::sOpenIDCookie; -LLPluginClassMedia* LLViewerMedia::sSpareBrowserMediaSource = NULL; +LLPluginClassMedia* LLViewerMedia::sSpareBrowserMediaSource = nullptr; static LLViewerMedia::impl_list sViewerMediaImplList; static LLViewerMedia::impl_id_map sViewerMediaTextureIDMap; static LLTimer sMediaCreateTimer; @@ -370,8 +364,6 @@ static LLUUID sOnlyAudibleTextureID = LLUUID::null; static F64 sLowestLoadableImplInterest = 0.0f; static bool sAnyMediaShowing = false; static boost::signals2::connection sTeleportFinishConnection; -static std::string sUpdatedCookies; -static const char *PLUGIN_COOKIE_FILE_NAME = "plugin_cookies.txt"; ////////////////////////////////////////////////////////////////////////////////////////// static void add_media_impl(LLViewerMediaImpl* media) @@ -431,6 +423,7 @@ viewer_media_t LLViewerMedia::newMediaImpl( media_impl->mMediaAutoScale = media_auto_scale; media_impl->mMediaLoop = media_loop; } + media_impl->setPageZoomFactor(media_impl->mZoomFactor); return media_impl; } @@ -440,10 +433,10 @@ viewer_media_t LLViewerMedia::updateMediaImpl(LLMediaEntry* media_entry, const s // Try to find media with the same media ID viewer_media_t media_impl = getMediaImplFromTextureID(media_entry->getMediaID()); - lldebugs << "called, current URL is \"" << media_entry->getCurrentURL() + LL_DEBUGS() << "called, current URL is \"" << media_entry->getCurrentURL() << "\", previous URL is \"" << previous_url << "\", update_from_self is " << (update_from_self?"true":"false") - << llendl; + << LL_ENDL; bool was_loaded = false; bool needs_navigate = false; @@ -476,7 +469,7 @@ viewer_media_t LLViewerMedia::updateMediaImpl(LLMediaEntry* media_entry, const s // The current media URL is now empty. Unload the media source. media_impl->unload(); - lldebugs << "Unloading media instance (new current URL is empty)." << llendl; + LL_DEBUGS() << "Unloading media instance (new current URL is empty)." << LL_ENDL; } } else @@ -490,9 +483,9 @@ viewer_media_t LLViewerMedia::updateMediaImpl(LLMediaEntry* media_entry, const s needs_navigate = url_changed; } - lldebugs << "was_loaded is " << (was_loaded?"true":"false") + LL_DEBUGS() << "was_loaded is " << (was_loaded?"true":"false") << ", auto_play is " << (auto_play?"true":"false") - << ", needs_navigate is " << (needs_navigate?"true":"false") << llendl; + << ", needs_navigate is " << (needs_navigate?"true":"false") << LL_ENDL; } } else @@ -518,7 +511,7 @@ viewer_media_t LLViewerMedia::updateMediaImpl(LLMediaEntry* media_entry, const s if(needs_navigate) { media_impl->navigateTo(media_impl->mMediaEntryURL, "", true, true); - lldebugs << "navigating to URL " << media_impl->mMediaEntryURL << llendl; + LL_DEBUGS() << "navigating to URL " << media_impl->mMediaEntryURL << LL_ENDL; } else if(!media_impl->mMediaURL.empty() && (media_impl->mMediaURL != media_impl->mMediaEntryURL)) { @@ -528,7 +521,7 @@ viewer_media_t LLViewerMedia::updateMediaImpl(LLMediaEntry* media_entry, const s // If this causes a navigate at some point (such as after a reload), it should be considered server-driven so it isn't broadcast. media_impl->mNavigateServerRequest = true; - lldebugs << "updating URL in the media impl to " << media_impl->mMediaEntryURL << llendl; + LL_DEBUGS() << "updating URL in the media impl to " << media_impl->mMediaEntryURL << LL_ENDL; } } @@ -576,7 +569,7 @@ std::string LLViewerMedia::getCurrentUserAgent() codec << "C64 Basic V2"; //codec << ViewerVersion::getImpMajorVersion() << "." << ViewerVersion::getImpMinorVersion() << "." << ViewerVersion::getImpPatchVersion() << " " << ViewerVersion::getImpTestVersion(); //codec << " (" << channel << "; " << skin_name << " skin)"; -// llinfos << codec.str() << llendl; +// LL_INFOS() << codec.str() << LL_ENDL; return codec.str(); } @@ -694,7 +687,7 @@ bool LLViewerMedia::isInterestingEnough(const LLVOVolume *object, const F64 &obj } else { - lldebugs << "object interest = " << object_interest << ", lowest loadable = " << sLowestLoadableImplInterest << llendl; + LL_DEBUGS() << "object interest = " << object_interest << ", lowest loadable = " << sLowestLoadableImplInterest << LL_ENDL; if(object_interest >= sLowestLoadableImplInterest) result = true; } @@ -792,39 +785,34 @@ static bool proximity_comparitor(const LLViewerMediaImpl* i1, const LLViewerMedi } } -static LLFastTimer::DeclareTimer FTM_MEDIA_UPDATE("Update Media"); -static LLFastTimer::DeclareTimer FTM_MEDIA_SPARE_IDLE("Spare Idle"); -static LLFastTimer::DeclareTimer FTM_MEDIA_UPDATE_INTEREST("Update/Interest"); -static LLFastTimer::DeclareTimer FTM_MEDIA_SORT("Sort"); -static LLFastTimer::DeclareTimer FTM_MEDIA_SORT2("Sort 2"); -static LLFastTimer::DeclareTimer FTM_MEDIA_MISC("Misc"); +static LLTrace::BlockTimerStatHandle FTM_MEDIA_UPDATE("Update Media"); +static LLTrace::BlockTimerStatHandle FTM_MEDIA_SPARE_IDLE("Spare Idle"); +static LLTrace::BlockTimerStatHandle FTM_MEDIA_UPDATE_INTEREST("Update/Interest"); +static LLTrace::BlockTimerStatHandle FTM_MEDIA_SORT("Sort"); +static LLTrace::BlockTimerStatHandle FTM_MEDIA_SORT2("Sort 2"); +static LLTrace::BlockTimerStatHandle FTM_MEDIA_MISC("Misc"); ////////////////////////////////////////////////////////////////////////////////////////// // static void LLViewerMedia::updateMedia(void *dummy_arg) { - LLFastTimer t1(FTM_MEDIA_UPDATE); + LL_RECORD_BLOCK_TIME(FTM_MEDIA_UPDATE); // Enable/disable the plugin read thread - LLPluginProcessParent::setUseReadThread(gSavedSettings.getBOOL("PluginUseReadThread")); + static LLCachedControl pluginUseReadThread(gSavedSettings, "PluginUseReadThread"); + LLPluginProcessParent::setUseReadThread(pluginUseReadThread); // HACK: we always try to keep a spare running webkit plugin around to improve launch times. createSpareBrowserMediaSource(); sAnyMediaShowing = false; - sUpdatedCookies = getCookieStore()->getChangedCookies(); - if(!sUpdatedCookies.empty()) - { - lldebugs << "updated cookies will be sent to all loaded plugins: " << llendl; - lldebugs << sUpdatedCookies << llendl; - } impl_list::iterator iter = sViewerMediaImplList.begin(); impl_list::iterator end = sViewerMediaImplList.end(); { - LLFastTimer t(FTM_MEDIA_UPDATE_INTEREST); + LL_RECORD_BLOCK_TIME(FTM_MEDIA_UPDATE_INTEREST); for(; iter != end;) { LLViewerMediaImpl* pimpl = *iter++; @@ -836,12 +824,12 @@ void LLViewerMedia::updateMedia(void *dummy_arg) // Let the spare media source actually launch if(sSpareBrowserMediaSource) { - LLFastTimer t(FTM_MEDIA_SPARE_IDLE); + LL_RECORD_BLOCK_TIME(FTM_MEDIA_SPARE_IDLE); sSpareBrowserMediaSource->idle(); } { - LLFastTimer t(FTM_MEDIA_SORT); + LL_RECORD_BLOCK_TIME(FTM_MEDIA_SORT); // Sort the static instance list using our interest criteria sViewerMediaImplList.sort(priorityComparitor); } @@ -857,12 +845,12 @@ void LLViewerMedia::updateMedia(void *dummy_arg) std::vector proximity_order; - bool inworld_media_enabled = gSavedSettings.getBOOL("AudioStreamingMedia"); - bool inworld_audio_enabled = gSavedSettings.getBOOL("AudioStreamingMusic"); - U32 max_instances = gSavedSettings.getU32("PluginInstancesTotal"); - U32 max_normal = gSavedSettings.getU32("PluginInstancesNormal"); - U32 max_low = gSavedSettings.getU32("PluginInstancesLow"); - F32 max_cpu = gSavedSettings.getF32("PluginInstancesCPULimit"); + static LLCachedControl inworld_media_enabled(gSavedSettings, "AudioStreamingMedia"); + static LLCachedControl inworld_audio_enabled(gSavedSettings, "AudioStreamingMusic"); + static LLCachedControl max_instances(gSavedSettings, "PluginInstancesTotal"); + static LLCachedControl max_normal(gSavedSettings, "PluginInstancesNormal"); + static LLCachedControl max_low(gSavedSettings, "PluginInstancesLow"); + static LLCachedControl max_cpu(gSavedSettings, "PluginInstancesCPULimit"); // Setting max_cpu to 0.0 disables CPU usage checking. bool check_cpu_usage = (max_cpu != 0.0f); @@ -873,7 +861,7 @@ void LLViewerMedia::updateMedia(void *dummy_arg) // If max_normal + max_low is less than max_instances, things will tend to get unloaded instead of being set to slideshow. { - LLFastTimer t(FTM_MEDIA_MISC); + LL_RECORD_BLOCK_TIME(FTM_MEDIA_MISC); for(; iter != end; iter++) { LLViewerMediaImpl* pimpl = *iter; @@ -949,7 +937,7 @@ void LLViewerMedia::updateMedia(void *dummy_arg) { F32 approximate_interest_dimension = (F32) sqrt(pimpl->getInterest()); - pimpl->setLowPrioritySizeLimit(llround(approximate_interest_dimension)); + pimpl->setLowPrioritySizeLimit(ll_round(approximate_interest_dimension)); } } else @@ -1034,14 +1022,15 @@ void LLViewerMedia::updateMedia(void *dummy_arg) } } - if(gSavedSettings.getBOOL("MediaPerformanceManagerDebug")) + static LLCachedControl mediaPerformanceManager(gSavedSettings, "MediaPerformanceManagerDebug"); + if(mediaPerformanceManager) { // Give impls the same ordering as the priority list // they're already in the right order for this. } else { - LLFastTimer t(FTM_MEDIA_SORT2); + LL_RECORD_BLOCK_TIME(FTM_MEDIA_SORT2); // Use a distance-based sort for proximity values. std::stable_sort(proximity_order.begin(), proximity_order.end(), proximity_comparitor); } @@ -1052,7 +1041,7 @@ void LLViewerMedia::updateMedia(void *dummy_arg) proximity_order[i]->mProximity = i; } - LL_DEBUGS("PluginPriority") << "Total reported CPU usage is " << total_cpu << llendl; + LL_DEBUGS("PluginPriority") << "Total reported CPU usage is " << total_cpu << LL_ENDL; } @@ -1132,7 +1121,7 @@ bool LLViewerMedia::isParcelAudioPlaying() return (LLViewerMedia::hasParcelAudio() && gAudiop && LLAudioEngine::AUDIO_PLAYING == gAudiop->isInternetStreamPlaying()); } -bool LLViewerMedia::onAuthSubmit(const LLSD& notification, const LLSD& response) +void LLViewerMedia::onAuthSubmit(const LLSD& notification, const LLSD& response) { LLViewerMediaImpl *impl = LLViewerMedia::getMediaImplFromTextureID(notification["payload"]["media_id"]); if(impl) @@ -1150,7 +1139,6 @@ bool LLViewerMedia::onAuthSubmit(const LLSD& notification, const LLSD& response) } } } - return false; } ///////////////////////////////////////////////////////////////////////////////////////// @@ -1169,63 +1157,6 @@ void LLViewerMedia::clearAllCookies() plugin->clear_cookies(); } } - - // Clear all cookies from the cookie store - getCookieStore()->setAllCookies(""); - - // FIXME: this may not be sufficient, since the on-disk cookie file won't get written until some browser instance exits cleanly. - // It also won't clear cookies for other accounts, or for any account if we're not logged in, and won't do anything at all if there are no webkit plugins loaded. - // Until such time as we can centralize cookie storage, the following hack should cover these cases: - - // HACK: Look for cookie files in all possible places and delete them. - // NOTE: this assumes knowledge of what happens inside the webkit plugin (it's what adds 'browser_profile' to the path and names the cookie file) - - // Places that cookie files can be: - // /browser_profile/cookies - // /first_last/browser_profile/cookies (note that there may be any number of these!) - // /first_last/plugin_cookies.txt (note that there may be any number of these!) - - std::string base_dir = gDirUtilp->getOSUserAppDir() + gDirUtilp->getDirDelimiter(); - std::string target; - std::string filename; - - lldebugs << "base dir = " << base_dir << llendl; - - // The non-logged-in version is easy - target = base_dir; - target += "browser_profile"; - target += gDirUtilp->getDirDelimiter(); - target += "cookies"; - lldebugs << "target = " << target << llendl; - if(LLFile::isfile(target)) - { - LLFile::remove(target); - } - - // the hard part: iterate over all user directories and delete the cookie file from each one - LLDirIterator dir_iter(base_dir, "*_*"); - while (dir_iter.next(filename)) - { - target = gDirUtilp->add(base_dir, filename); - gDirUtilp->append(target, "browser_profile"); - gDirUtilp->append(target, "cookies"); - lldebugs << "target = " << target << llendl; - if(LLFile::isfile(target)) - { - LLFile::remove(target); - } - - // Other accounts may have new-style cookie files too -- delete them as well - target = gDirUtilp->add(base_dir, filename); - gDirUtilp->append(target, PLUGIN_COOKIE_FILE_NAME); - lldebugs << "target = " << target << llendl; - if(LLFile::isfile(target)) - { - LLFile::remove(target); - } - } - - // If we have an OpenID cookie, re-add it to the cookie store. setOpenIDCookie(); } @@ -1256,7 +1187,7 @@ void LLViewerMedia::setCookiesEnabled(bool enabled) LLPluginClassMedia* plugin = pimpl->getMediaPlugin(); if(plugin) { - plugin->enable_cookies(enabled); + plugin->cookies_enabled(enabled); } } } @@ -1274,7 +1205,7 @@ void LLViewerMedia::setProxyConfig(bool enable, const std::string &host, int por LLPluginClassMedia* plugin = pimpl->getMediaPlugin(); if(plugin) { - plugin->proxy_setup(enable, host, port); + //pimpl->mMediaSource->proxy_setup(enable, host, port); } } } @@ -1282,203 +1213,137 @@ void LLViewerMedia::setProxyConfig(bool enable, const std::string &host, int por ///////////////////////////////////////////////////////////////////////////////////////// // static ///////////////////////////////////////////////////////////////////////////////////////// -// static -LLPluginCookieStore *LLViewerMedia::getCookieStore() +//// static + +AIHTTPHeaders LLViewerMedia::getHeaders() { - if(sCookieStore == NULL) - { - sCookieStore = new LLPluginCookieStore; - } - - return sCookieStore; + AIHTTPHeaders headers; + headers.addHeader("Accept", "*/*"); + // *TODO: Should this be 'application/llsd+xml' ? + // *TODO: Should this even be set at all? This header is only not overridden in 'GET' methods. + headers.addHeader("Content-Type", "application/xml"); + headers.addHeader("Cookie", sOpenIDCookie); + headers.addHeader("User-Agent", getCurrentUserAgent()); + + return headers; } ///////////////////////////////////////////////////////////////////////////////////////// // static -void LLViewerMedia::loadCookieFile() +bool LLViewerMedia::parseRawCookie(const std::string raw_cookie, std::string& name, std::string& value, std::string& path, bool& httponly, bool& secure) { - // build filename for each user - std::string resolved_filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, PLUGIN_COOKIE_FILE_NAME); - - if (resolved_filename.empty()) + std::size_t name_pos = raw_cookie.find_first_of('='); + if (name_pos != std::string::npos) { - llinfos << "can't get path to plugin cookie file - probably not logged in yet." << llendl; - return; - } - - // open the file for reading - llifstream file(resolved_filename); - if (!file.is_open()) - { - llwarns << "can't load plugin cookies from file \"" << PLUGIN_COOKIE_FILE_NAME << "\"" << llendl; - return; - } - - getCookieStore()->readAllCookies(file, true); - - file.close(); - - // send the clear_cookies message to all loaded plugins - impl_list::iterator iter = sViewerMediaImplList.begin(); - impl_list::iterator end = sViewerMediaImplList.end(); - for (; iter != end; iter++) - { - LLViewerMediaImpl* pimpl = *iter; - LLPluginClassMedia* plugin = pimpl->getMediaPlugin(); - if(plugin) + name = raw_cookie.substr(0, name_pos); + std::size_t value_pos = raw_cookie.find_first_of(';', name_pos); + if (value_pos != std::string::npos) { - plugin->clear_cookies(); + value = raw_cookie.substr(name_pos + 1, value_pos - name_pos - 1); + path = "/"; // assume root path for now + + httponly = true; // hard coded for now + secure = true; + + return true; } } - - // If we have an OpenID cookie, re-add it to the cookie store. - setOpenIDCookie(); -} + return false; +} -///////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::saveCookieFile() +void LLViewerMedia::setOpenIDCookie() { - // build filename for each user - std::string resolved_filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, PLUGIN_COOKIE_FILE_NAME); - - if (resolved_filename.empty()) + if(!sOpenIDCookie.empty()) { - llinfos << "can't get path to plugin cookie file - probably not logged in yet." << llendl; - return; - } + if (gSavedSettings.getString("WebProfileURL").empty()) return; + std::string profileUrl = getProfileURL(""); - // open a file for writing - llofstream file (resolved_filename); - if (!file.is_open()) - { - llwarns << "can't open plugin cookie file \"" << PLUGIN_COOKIE_FILE_NAME << "\" for writing" << llendl; - return; + getOpenIDCookieCoro(profileUrl); } - - getCookieStore()->writePersistentCookies(file); - - file.close(); } -///////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::addCookie(const std::string &name, const std::string &value, const std::string &domain, const LLDate &expires, const std::string &path, bool secure) +/*static*/ +void LLViewerMedia::getOpenIDCookieCoro(std::string url) { - std::stringstream cookie; - - cookie << name << "=" << LLPluginCookieStore::quoteString(value); - - if(expires.notNull()) - { - cookie << "; expires=" << expires.asRFC1123(); + // The LLURL can give me the 'authority', which is of the form: [username[:password]@]hostname[:port] + // We want just the hostname for the cookie code, but LLURL doesn't seem to have a way to extract that. + // We therefore do it here. + std::string authority = sOpenIDURL.mAuthority; + std::string::size_type hostStart = authority.find('@'); + if(hostStart == std::string::npos) + { // no username/password + hostStart = 0; + } + else + { // Hostname starts after the @. + // (If the hostname part is empty, this may put host_start at the end of the string. In that case, it will end up passing through an empty hostname, which is correct.) + ++hostStart; + } + std::string::size_type hostEnd = authority.rfind(':'); + if((hostEnd == std::string::npos) || (hostEnd < hostStart)) + { // no port + hostEnd = authority.size(); } - - cookie << "; domain=" << domain; - cookie << "; path=" << path; - - if(secure) + if (url.length()) { - cookie << "; secure"; + LLMediaCtrl* media_instance = LLFloaterDestinations::getInstance()->getChild("destination_guide_contents"); + if (media_instance) + { + std::string cookie_host = authority.substr(hostStart, hostEnd - hostStart); + std::string cookie_name = ""; + std::string cookie_value = ""; + std::string cookie_path = ""; + bool httponly = true; + bool secure = true; + if (parseRawCookie(sOpenIDCookie, cookie_name, cookie_value, cookie_path, httponly, secure) && + media_instance->getMediaPlugin()) + { + // MAINT-5711 - inexplicably, the CEF setCookie function will no longer set the cookie if the + // url and domain are not the same. This used to be my.sl.com and id.sl.com respectively and worked. + // For now, we use the URL for the OpenID POST request since it will have the same authority + // as the domain field. + // (Feels like there must be a less dirty way to construct a URL from component LLURL parts) + // MAINT-6392 - Rider: Do not change, however, the original URI requested, since it is used further + // down. + std::string cefUrl(std::string(sOpenIDURL.mURI) + "://" + std::string(sOpenIDURL.mAuthority)); + + media_instance->getMediaPlugin()->setCookie(cefUrl, cookie_name, cookie_value, cookie_host, cookie_path, httponly, secure); + } + } } - - getCookieStore()->setCookies(cookie.str()); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::addSessionCookie(const std::string &name, const std::string &value, const std::string &domain, const std::string &path, bool secure) -{ - // A session cookie just has a NULL date. - addCookie(name, value, domain, LLDate(), path, secure); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::removeCookie(const std::string &name, const std::string &domain, const std::string &path ) -{ - // To remove a cookie, add one with the same name, domain, and path that expires in the past. - - addCookie(name, "", domain, LLDate(LLDate::now().secondsSinceEpoch() - 1.0), path); -} - + + // Note: Rider: MAINT-6392 - Some viewer code requires access to the my.sl.com openid cookie for such + // actions as posting snapshots to the feed. This is handled through HTTPCore rather than CEF and so + // we must learn to SHARE the cookies. -AIHTTPHeaders LLViewerMedia::getHeaders() -{ + // Do a web profile get so we can store the cookie AIHTTPHeaders headers; headers.addHeader("Accept", "*/*"); - headers.addHeader("Content-Type", "application/xml"); headers.addHeader("Cookie", sOpenIDCookie); headers.addHeader("User-Agent", getCurrentUserAgent()); - return headers; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::setOpenIDCookie() -{ - if(!sOpenIDCookie.empty()) - { - // The LLURL can give me the 'authority', which is of the form: [username[:password]@]hostname[:port] - // We want just the hostname for the cookie code, but LLURL doesn't seem to have a way to extract that. - // We therefore do it here. - std::string authority = sOpenIDURL.mAuthority; - std::string::size_type host_start = authority.find('@'); - if(host_start == std::string::npos) - { - // no username/password - host_start = 0; - } - else - { - // Hostname starts after the @. - // (If the hostname part is empty, this may put host_start at the end of the string. In that case, it will end up passing through an empty hostname, which is correct.) - ++host_start; - } - std::string::size_type host_end = authority.rfind(':'); - if((host_end == std::string::npos) || (host_end < host_start)) - { - // no port - host_end = authority.size(); - } - - getCookieStore()->setCookiesFromHost(sOpenIDCookie, authority.substr(host_start, host_end - host_start)); - - // Does grid supports web profiles at all? - if (!gSavedSettings.getString("WebProfileURL").empty()) - { - // Do a web profile get so we can store the cookie - AIHTTPHeaders headers; - headers.addHeader("Accept", "*/*"); - headers.addHeader("Cookie", sOpenIDCookie); - headers.addHeader("User-Agent", getCurrentUserAgent()); - - std::string profile_url = getProfileURL(""); - LLURL raw_profile_url( profile_url.c_str() ); + LLURL raw_profile_url(url.data()); - LL_DEBUGS("MediaAuth") << "Requesting " << profile_url << llendl; - LL_DEBUGS("MediaAuth") << "sOpenIDCookie = [" << sOpenIDCookie << "]" << llendl; - LLHTTPClient::get(profile_url, - new LLViewerMediaWebProfileResponder(raw_profile_url.getAuthority()), - headers); - } - } + LL_DEBUGS("MediaAuth") << "Requesting " << url << LL_ENDL; + LL_DEBUGS("MediaAuth") << "sOpenIDCookie = [" << sOpenIDCookie << "]" << LL_ENDL; + LLHTTPClient::get(url, + new LLViewerMediaWebProfileResponder(raw_profile_url.getAuthority()), + headers); } ///////////////////////////////////////////////////////////////////////////////////////// // static -void LLViewerMedia::openIDSetup(const std::string &openid_url, const std::string &openid_token) +void LLViewerMedia::openIDSetup(const std::string &openidUrl, const std::string &openidToken) { - LL_DEBUGS("MediaAuth") << "url = \"" << openid_url << "\", token = \"" << openid_token << "\"" << LL_ENDL; + LL_DEBUGS("MediaAuth") << "url = \"" << openidUrl << "\", token = \"" << openidToken << "\"" << LL_ENDL; // post the token to the url // the responder will need to extract the cookie(s). // Save the OpenID URL for later -- we may need the host when adding the cookie. - sOpenIDURL.init(openid_url.c_str()); + sOpenIDURL.init(openidUrl.c_str()); // We shouldn't ever do this twice, but just in case this code gets repurposed later, clear existing cookies. sOpenIDCookie.clear(); @@ -1490,13 +1355,13 @@ void LLViewerMedia::openIDSetup(const std::string &openid_url, const std::string headers.addHeader("Content-Type", "application/x-www-form-urlencoded"); // postRaw() takes ownership of the buffer and releases it later, so we need to allocate a new buffer here. - size_t size = openid_token.size(); - char* data = new char[size]; - memcpy(data, openid_token.data(), size); + size_t size = openidToken.size(); + U8* data = new U8[size]; + memcpy(data, openidToken.data(), size); LLHTTPClient::postRaw( - openid_url, - data, + openidUrl, + data, size, new LLViewerMediaOpenIDResponder(), headers); @@ -1552,6 +1417,9 @@ void LLViewerMedia::proxyWindowClosed(const std::string &uuid) // static void LLViewerMedia::createSpareBrowserMediaSource() { + static bool failedLoading = false; + if (failedLoading) return; + // If we don't have a spare browser media source, create one. // However, if PluginAttachDebuggerToPlugins is set then don't spawn a spare // SLPlugin process in order to not be confused by an unrelated gdb terminal @@ -1561,7 +1429,8 @@ void LLViewerMedia::createSpareBrowserMediaSource() // The null owner will keep the browser plugin from fully initializing // (specifically, it keeps LLPluginClassMedia from negotiating a size change, // which keeps MediaPluginWebkit::initBrowserWindow from doing anything until we have some necessary data, like the background color) - sSpareBrowserMediaSource = LLViewerMediaImpl::newSourceFromMediaType("text/html", NULL, 0, 0); + sSpareBrowserMediaSource = LLViewerMediaImpl::newSourceFromMediaType("text/html", nullptr, 0, 0, 1.0); + if (!sSpareBrowserMediaSource) failedLoading = true; } } @@ -1570,7 +1439,7 @@ void LLViewerMedia::createSpareBrowserMediaSource() LLPluginClassMedia* LLViewerMedia::getSpareBrowserMediaSource() { LLPluginClassMedia* result = sSpareBrowserMediaSource; - sSpareBrowserMediaSource = NULL; + sSpareBrowserMediaSource = nullptr; return result; }; @@ -1616,7 +1485,7 @@ std::string LLViewerMedia::getParcelAudioURL() // static void LLViewerMedia::initClass() { - gIdleCallbacks.addFunction(LLViewerMedia::updateMedia, NULL); + gIdleCallbacks.addFunction(LLViewerMedia::updateMedia, nullptr); sTeleportFinishConnection = LLViewerParcelMgr::getInstance()-> setTeleportFinishedCallback(boost::bind(&LLViewerMedia::onTeleportFinished)); } @@ -1625,8 +1494,13 @@ void LLViewerMedia::initClass() // static void LLViewerMedia::cleanupClass() { - gIdleCallbacks.deleteFunction(LLViewerMedia::updateMedia, NULL); + gIdleCallbacks.deleteFunction(LLViewerMedia::updateMedia, nullptr); sTeleportFinishConnection.disconnect(); + if (sSpareBrowserMediaSource != nullptr) + { + delete sSpareBrowserMediaSource; + sSpareBrowserMediaSource = nullptr; + } } ////////////////////////////////////////////////////////////////////////////////////////// @@ -1635,6 +1509,8 @@ void LLViewerMedia::onTeleportFinished() { // On teleport, clear this setting (i.e. set it to true) gSavedSettings.setBOOL("MediaTentativeAutoPlay", true); + + LLViewerMediaImpl::sMimeTypesFailed.clear(); } @@ -1646,6 +1522,7 @@ void LLViewerMedia::setOnlyAudibleMediaTextureID(const LLUUID& texture_id) sForceUpdate = true; } +std::vector LLViewerMediaImpl::sMimeTypesFailed; ////////////////////////////////////////////////////////////////////////////////////////// // LLViewerMediaImpl ////////////////////////////////////////////////////////////////////////////////////////// @@ -1655,6 +1532,7 @@ LLViewerMediaImpl::LLViewerMediaImpl( const LLUUID& texture_id, U8 media_auto_scale, U8 media_loop) : + mZoomFactor(1.0), mMovieImageHasMips(false), mMediaWidth(media_width), mMediaHeight(media_height), @@ -1675,6 +1553,7 @@ LLViewerMediaImpl::LLViewerMediaImpl( const LLUUID& texture_id, mNavigateServerRequest(false), mMediaSourceFailed(false), mRequestedVolume(1.0f), + mPreviousVolume(1.0f), mIsMuted(false), mNeedsMuteCheck(false), mPreviousMediaState(MEDIA_NONE), @@ -1683,16 +1562,16 @@ LLViewerMediaImpl::LLViewerMediaImpl( const LLUUID& texture_id, mIsParcelMedia(false), mProximity(-1), mProximityDistance(0.0f), - mMimeTypeProbe(NULL), mMediaAutoPlay(false), mInNearbyMediaList(false), mClearCache(false), mBackgroundColor(LLColor4::white), mNavigateSuspended(false), mNavigateSuspendedDeferred(false), - mIsUpdated(false), mTrustedBrowser(false), - mZoomFactor(1.0) + mCleanBrowser(false), + mIsUpdated(false), + mMimeProbe(nullptr) { // Set up the mute list observer if it hasn't been set up already. @@ -1748,17 +1627,11 @@ bool LLViewerMediaImpl::initializeMedia(const std::string& mime_type) { bool mimeTypeChanged = (mMimeType != mime_type); bool pluginChanged = (LLMIMETypes::implType(mCurrentMimeType) != LLMIMETypes::implType(mime_type)); + if(!mPluginBase || pluginChanged) { - if(! initializePlugin(mime_type)) - { - /*LL_WARNS("Plugin") << "plugin intialization failed for mime type: " << mime_type << LL_ENDL; - LLSD args; - args["MIME_TYPE"] = mime_type; - LLNotificationsUtil::add("NoPlugin", args); - - return false;*/ - } + // We don't have a plugin at all, or the new mime type is handled by a different plugin than the old mime type. + (void)initializePlugin(mime_type); } else if(mimeTypeChanged) { @@ -1766,8 +1639,7 @@ bool LLViewerMediaImpl::initializeMedia(const std::string& mime_type) mMimeType = mime_type; } - // play(); - return (mPluginBase != NULL); + return (mPluginBase != nullptr); } ////////////////////////////////////////////////////////////////////////////////////////// @@ -1812,7 +1684,6 @@ void LLViewerMediaImpl::destroyMediaSource() mPluginBase->setDeleteOK(true) ; destroyPlugin(); } - } ////////////////////////////////////////////////////////////////////////////////////////// @@ -1823,14 +1694,16 @@ void LLViewerMediaImpl::setMediaType(const std::string& media_type) ////////////////////////////////////////////////////////////////////////////////////////// /*static*/ -LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_type, LLPluginClassMediaOwner *owner /* may be NULL */, S32 default_width, S32 default_height, const std::string target) +LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_type, LLPluginClassMediaOwner *owner /* may be NULL */, S32 default_width, S32 default_height, F64 zoom_factor, const std::string target, bool clean_browser) { std::string plugin_basename = LLMIMETypes::implType(media_type); - LLPluginClassMedia* media_source = NULL; + LLPluginClassMedia* media_source = nullptr; // HACK: we always try to keep a spare running webkit plugin around to improve launch times. // If a spare was already created before PluginAttachDebuggerToPlugins was set, don't use it. - if(plugin_basename == "media_plugin_webkit" && !gSavedSettings.getBOOL("PluginAttachDebuggerToPlugins")) + // Do not use a spare if launching with full viewer control (e.g. Facebook, Twitter and few others) + if ((plugin_basename == "media_plugin_cef") && + !gSavedSettings.getBOOL("PluginAttachDebuggerToPlugins") && !clean_browser) { media_source = LLViewerMedia::getSpareBrowserMediaSource(); if(media_source) @@ -1838,11 +1711,12 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_ media_source->setOwner(owner); media_source->setTarget(target); media_source->setSize(default_width, default_height); + media_source->setZoomFactor(zoom_factor); + media_source->set_page_zoom_factor(zoom_factor); return media_source; } } - if(plugin_basename.empty()) { LL_WARNS_ONCE("Media") << "Couldn't find plugin for media type " << media_type << LL_ENDL; @@ -1851,20 +1725,25 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_ { std::string launcher_name = gDirUtilp->getLLPluginLauncher(); std::string plugin_name = gDirUtilp->getLLPluginFilename(plugin_basename); - std::string user_data_path = gDirUtilp->getOSUserAppDir(); - user_data_path += gDirUtilp->getDirDelimiter(); + + std::string user_data_path_cache = gDirUtilp->getCacheDir(false); + user_data_path_cache += gDirUtilp->getDirDelimiter(); + + std::string user_data_path_cookies = gDirUtilp->getOSUserAppDir(); + user_data_path_cookies += gDirUtilp->getDirDelimiter(); + + std::string user_data_path_cef_log = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "cef_log.txt"); // Fix for EXT-5960 - make browser profile specific to user (cache, cookies etc.) // If the linden username returned is blank, that can only mean we are // at the login page displaying login Web page or Web browser test via Develop menu. // In this case we just use whatever gDirUtilp->getOSUserAppDir() gives us (this // is what we always used before this change) - std::string linden_user_dir = gDirUtilp->getLindenUserDir(true); + std::string linden_user_dir = gDirUtilp->getLindenUserDir(); if ( ! linden_user_dir.empty() ) { - // gDirUtilp->getLindenUserDir() is whole path, not just Linden name - user_data_path = linden_user_dir; - user_data_path += gDirUtilp->getDirDelimiter(); + user_data_path_cookies = linden_user_dir; + user_data_path_cookies += gDirUtilp->getDirDelimiter(); }; // See if the plugin executable exists @@ -1872,34 +1751,39 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_ if(LLFile::stat(launcher_name, &s)) { LL_WARNS_ONCE("Media") << "Couldn't find launcher at " << launcher_name << LL_ENDL; - llassert(false); // Fail in debugging mode. } else if(LLFile::stat(plugin_name, &s)) { LL_WARNS_ONCE("Media") << "Couldn't find plugin at " << plugin_name << LL_ENDL; - llassert(false); // Fail in debugging mode. } else { media_source = new LLPluginClassMedia(owner); + media_source->proxy_setup(gSavedSettings.getBOOL("BrowserProxyEnabled"), gSavedSettings.getS32("BrowserProxyType"), + gSavedSettings.getString("BrowserProxyAddress"), gSavedSettings.getS32("BrowserProxyPort"), + gSavedSettings.getString("BrowserProxyUsername"), gSavedSettings.getString("BrowserProxyPassword")); media_source->setSize(default_width, default_height); - media_source->setUserDataPath(user_data_path); + media_source->setUserDataPath(user_data_path_cache, user_data_path_cookies, user_data_path_cef_log); media_source->setLanguageCode(LLUI::getLanguage()); + media_source->setZoomFactor(zoom_factor); // collect 'cookies enabled' setting from prefs and send to embedded browser bool cookies_enabled = gSavedSettings.getBOOL( "CookiesEnabled" ); - media_source->enable_cookies( cookies_enabled ); + media_source->cookies_enabled( cookies_enabled || clean_browser); // collect 'plugins enabled' setting from prefs and send to embedded browser bool plugins_enabled = gSavedSettings.getBOOL( "BrowserPluginsEnabled" ); - media_source->setPluginsEnabled( plugins_enabled ); + media_source->setPluginsEnabled( plugins_enabled || clean_browser); // collect 'javascript enabled' setting from prefs and send to embedded browser bool javascript_enabled = gSavedSettings.getBOOL( "BrowserJavascriptEnabled" ); - media_source->setJavascriptEnabled( javascript_enabled ); + media_source->setJavascriptEnabled( javascript_enabled || clean_browser); bool media_plugin_debugging_enabled = gSavedSettings.getBOOL("MediaPluginDebugging"); - media_source->enableMediaPluginDebugging( media_plugin_debugging_enabled ); + media_source->enableMediaPluginDebugging( media_plugin_debugging_enabled || clean_browser); + + // need to set agent string here before instance created + media_source->setBrowserUserAgent(LLViewerMedia::getCurrentUserAgent()); media_source->setTarget(target); @@ -1917,22 +1801,30 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_ } LL_WARNS_ONCE("Plugin") << "plugin initialization failed for mime type: " << media_type << LL_ENDL; - LLSD args; - args["MIME_TYPE"] = media_type; - LLNotificationsUtil::add("NoPlugin", args); - return NULL; + if(gAgent.isInitialized()) + { + if (std::find(sMimeTypesFailed.begin(), sMimeTypesFailed.end(), media_type) == sMimeTypesFailed.end()) + { + LLSD args; + args["MIME_TYPE"] = media_type; + LLNotificationsUtil::add("NoPlugin", args); + sMimeTypesFailed.push_back(media_type); + } + } + return nullptr; } ////////////////////////////////////////////////////////////////////////////////////////// bool LLViewerMediaImpl::initializePlugin(const std::string& media_type) { - LLPluginClassMedia* plugin = getMediaPlugin(); - if (plugin) + LLPluginClassMedia* mMediaSource = getMediaPlugin(); + if(mMediaSource) { // Save the previous media source's last set size before destroying it. - mMediaWidth = plugin->getSetWidth(); - mMediaHeight = plugin->getSetHeight(); + mMediaWidth = mMediaSource->getSetWidth(); + mMediaHeight = mMediaSource->getSetHeight(); + mZoomFactor = mMediaSource->getZoomFactor(); } // Always delete the old media impl first. @@ -1955,7 +1847,7 @@ bool LLViewerMediaImpl::initializePlugin(const std::string& media_type) // Save the MIME type that really caused the plugin to load mCurrentMimeType = mMimeType; - LLPluginClassMedia* media_source = newSourceFromMediaType(mMimeType, this, mMediaWidth, mMediaHeight, mTarget); + LLPluginClassMedia* media_source = newSourceFromMediaType(mMimeType, this, mMediaWidth, mMediaHeight, mZoomFactor, mTarget, mCleanBrowser); if (media_source) { @@ -1975,27 +1867,17 @@ bool LLViewerMediaImpl::initializePlugin(const std::string& media_type) // Qt/WebKit loads from your system location. // Note: This needs the new CA.pem file with the Equifax Secure Certificate Authority // cert at the bottom: (MIIDIDCCAomgAwIBAgIENd70zzANBg) - std::string ca_path = gDirUtilp->getExpandedFilename( LL_PATH_APP_SETTINGS, "CA.pem" ); + std::string ca_path = gDirUtilp->getExpandedFilename( LL_PATH_APP_SETTINGS, "ca-bundle.crt" ); media_source->addCertificateFilePath( ca_path ); - media_source->proxy_setup(gSavedSettings.getBOOL("BrowserProxyEnabled"), gSavedSettings.getString("BrowserProxyAddress"), gSavedSettings.getS32("BrowserProxyPort")); + media_source->proxy_setup(gSavedSettings.getBOOL("BrowserProxyEnabled"), gSavedSettings.getS32("BrowserProxyType"), gSavedSettings.getString("BrowserProxyAddress"), gSavedSettings.getS32("BrowserProxyPort"), + gSavedSettings.getString("BrowserProxyUsername"), gSavedSettings.getString("BrowserProxyPassword")); if(mClearCache) { mClearCache = false; media_source->clear_cache(); } - - // TODO: Only send cookies to plugins that need them - // Ideally, the plugin should tell us whether it handles cookies or not -- either via the init response or through a separate message. - // Due to the ordering of messages, it's possible we wouldn't get that information back in time to send cookies before sending a navigate message, - // which could cause odd race conditions. - std::string all_cookies = LLViewerMedia::getCookieStore()->getAllCookies(); - lldebugs << "setting cookies: " << all_cookies << llendl; - if(!all_cookies.empty()) - { - media_source->set_cookies(all_cookies); - } mPluginBase = media_source; mPluginBase->setDeleteOK(false) ; @@ -2013,8 +1895,8 @@ bool LLViewerMediaImpl::initializePlugin(const std::string& media_type) ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::loadURI() { - LLPluginClassMedia* plugin = getMediaPlugin(); - if(plugin) + LLPluginClassMedia* mMediaSource = getMediaPlugin(); + if(mMediaSource) { // trim whitespace from front and back of URL - fixes EXT-5363 LLStringUtil::trim( mMediaURL ); @@ -2034,10 +1916,14 @@ void LLViewerMediaImpl::loadURI() "<>#%" ";/?:@&=", false); - llinfos << "Asking media source to load URI: " << uri << llendl; - - - plugin->loadURI( uri ); + { + // Do not log the query parts + LLURI u(uri); + std::string sanitized_uri = (u.query().empty() ? uri : u.scheme() + "://" + u.authority() + u.path()); + LL_INFOS() << "Asking media source to load URI: " << sanitized_uri << LL_ENDL; + } + + mMediaSource->loadURI( uri ); // A non-zero mPreviousMediaTime means that either this media was previously unloaded by the priority code while playing/paused, // or a seek happened before the media loaded. In either case, seek to the saved time. @@ -2063,14 +1949,16 @@ void LLViewerMediaImpl::loadURI() } } } + +////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::setSize(int width, int height) { - LLPluginClassMedia* plugin = getMediaPlugin(); + LLPluginClassMedia* mMediaSource = getMediaPlugin(); mMediaWidth = width; mMediaHeight = height; - if (plugin) + if (mMediaSource) { - plugin->setSize(width, height); + mMediaSource->setSize(width, height); } } @@ -2089,10 +1977,10 @@ void LLViewerMediaImpl::hideNotification() ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::play() { - LLPluginClassMedia* plugin = getMediaPlugin(); + LLPluginClassMedia* mMediaSource = getMediaPlugin(); // If the media source isn't there, try to initialize it and load an URL. - if (!plugin) + if(mMediaSource == nullptr) { if(!initializeMedia(mMimeType)) { @@ -2111,10 +1999,10 @@ void LLViewerMediaImpl::play() ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::stop() { - LLPluginClassMedia* plugin = getMediaPlugin(); - if (plugin) + LLPluginClassMedia* mMediaSource = getMediaPlugin(); + if(mMediaSource) { - plugin->stop(); + mMediaSource->stop(); // destroyMediaSource(); } } @@ -2122,10 +2010,10 @@ void LLViewerMediaImpl::stop() ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::pause() { - LLPluginClassMedia* plugin = getMediaPlugin(); - if (plugin) + LLPluginClassMedia* mMediaSource = getMediaPlugin(); + if(mMediaSource) { - plugin->pause(); + mMediaSource->pause(); } else { @@ -2136,10 +2024,10 @@ void LLViewerMediaImpl::pause() ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::start() { - LLPluginClassMedia* plugin = getMediaPlugin(); - if (plugin) + LLPluginClassMedia* mMediaSource = getMediaPlugin(); + if(mMediaSource) { - plugin->start(); + mMediaSource->start(); } else { @@ -2150,10 +2038,10 @@ void LLViewerMediaImpl::start() ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::seek(F32 time) { - LLPluginClassMedia* plugin = getMediaPlugin(); - if (plugin) + LLPluginClassMedia* mMediaSource = getMediaPlugin(); + if(mMediaSource) { - plugin->seek(time); + mMediaSource->seek(time); } else { @@ -2165,17 +2053,17 @@ void LLViewerMediaImpl::seek(F32 time) ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::skipBack(F32 step_scale) { - LLPluginClassMedia* plugin = getMediaPlugin(); - if(plugin) + LLPluginClassMedia* mMediaSource = getMediaPlugin(); + if(mMediaSource) { - if(plugin->pluginSupportsMediaTime()) + if(mMediaSource->pluginSupportsMediaTime()) { - F64 back_step = plugin->getCurrentTime() - (plugin->getDuration()*step_scale); + F64 back_step = mMediaSource->getCurrentTime() - (mMediaSource->getDuration()*step_scale); if(back_step < 0.0) { back_step = 0.0; } - plugin->seek(back_step); + mMediaSource->seek(back_step); } } } @@ -2183,17 +2071,17 @@ void LLViewerMediaImpl::skipBack(F32 step_scale) ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::skipForward(F32 step_scale) { - LLPluginClassMedia* plugin = getMediaPlugin(); - if(plugin) + LLPluginClassMedia* mMediaSource = getMediaPlugin(); + if(mMediaSource) { - if(plugin->pluginSupportsMediaTime()) + if(mMediaSource->pluginSupportsMediaTime()) { - F64 forward_step = plugin->getCurrentTime() + (plugin->getDuration()*step_scale); - if(forward_step > plugin->getDuration()) + F64 forward_step = mMediaSource->getCurrentTime() + (mMediaSource->getDuration()*step_scale); + if(forward_step > mMediaSource->getDuration()) { - forward_step = plugin->getDuration(); + forward_step = mMediaSource->getDuration(); } - plugin->seek(forward_step); + mMediaSource->seek(forward_step); } } } @@ -2205,27 +2093,44 @@ void LLViewerMediaImpl::setVolume(F32 volume) updateVolume(); } +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::setMute(bool mute) +{ + if (mute) + { + mPreviousVolume = mRequestedVolume; + setVolume(0.0); + } + else + { + setVolume(mPreviousVolume); + } +} + ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::updateVolume() { - LLPluginClassMedia* plugin = getMediaPlugin(); - if(plugin) + LLPluginClassMedia* mMediaSource = getMediaPlugin(); + if(mMediaSource) { // always scale the volume by the global media volume F32 volume = mRequestedVolume * LLViewerMedia::getVolume(); if (mProximityCamera > 0) { - if (mProximityCamera > gSavedSettings.getF32("MediaRollOffMax")) + static LLCachedControl sMediaRollOffMax(gSavedSettings, "MediaRollOffMax", 30.f); + static LLCachedControl sMediaRollOffMin(gSavedSettings, "MediaRollOffMin", 5.f); + static LLCachedControl sMediaRollOffRate(gSavedSettings, "MediaRollOffRate", 0.125f); + if (mProximityCamera > sMediaRollOffMax) { volume = 0; } - else if (mProximityCamera > gSavedSettings.getF32("MediaRollOffMin")) + else if (mProximityCamera > sMediaRollOffMin) { // attenuated_volume = 1 / (roll_off_rate * (d - min))^2 // the +1 is there so that for distance 0 the volume stays the same - F64 adjusted_distance = mProximityCamera - gSavedSettings.getF32("MediaRollOffMin"); - F64 attenuation = 1.0 + (gSavedSettings.getF32("MediaRollOffRate") * adjusted_distance); + F64 adjusted_distance = mProximityCamera - sMediaRollOffMin; + F64 attenuation = 1.0 + (sMediaRollOffRate * adjusted_distance); attenuation = 1.0 / (attenuation * attenuation); // the attenuation multiplier should never be more than one since that would increase volume volume = volume * llmin(1.0, attenuation); @@ -2234,11 +2139,11 @@ void LLViewerMediaImpl::updateVolume() if (sOnlyAudibleTextureID == LLUUID::null || sOnlyAudibleTextureID == mTextureId) { - plugin->setVolume(volume); + mMediaSource->setVolume(volume); } else { - plugin->setVolume(0.0f); + mMediaSource->setVolume(0.0f); } } } @@ -2248,21 +2153,23 @@ F32 LLViewerMediaImpl::getVolume() { return mRequestedVolume; } + +////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::focus(bool focus) { mHasFocus = focus; - LLPluginClassMedia* plugin = getMediaPlugin(); - if (plugin) + LLPluginClassMedia* mMediaSource = getMediaPlugin(); + if (mMediaSource) { // call focus just for the hell of it, even though this apopears to be a nop - plugin->focus(focus); + mMediaSource->focus(focus); if (focus) { // spoof a mouse click to *actually* pass focus // Don't do this anymore -- it actually clicks through now. -// plugin->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOWN, 1, 1, 0); -// plugin->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, 1, 1, 0); +// mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOWN, 1, 1, 0); +// mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, 1, 1, 0); } } } @@ -2287,10 +2194,10 @@ std::string LLViewerMediaImpl::getCurrentMediaURL() ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::clearCache() { - LLPluginClassMedia* plugin = getMediaPlugin(); - if(plugin) + LLPluginClassMedia* mMediaSource = getMediaPlugin(); + if(mMediaSource) { - plugin->clear_cache(); + mMediaSource->clear_cache(); } else { @@ -2302,59 +2209,61 @@ void LLViewerMediaImpl::clearCache() ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::setPageZoomFactor( double factor ) { - LLPluginClassMedia* plugin = getMediaPlugin(); - if(plugin && factor != mZoomFactor) + LLPluginClassMedia* mMediaSource = getMediaPlugin(); + if(mMediaSource && factor != mZoomFactor) { mZoomFactor = factor; - plugin->set_page_zoom_factor( factor ); + mMediaSource->set_page_zoom_factor( factor ); } } ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::mouseDown(S32 x, S32 y, MASK mask, S32 button) { - LLPluginClassMedia* plugin = getMediaPlugin(); + LLPluginClassMedia* mMediaSource = getMediaPlugin(); scaleMouse(&x, &y); mLastMouseX = x; mLastMouseY = y; - if (plugin) +// LL_INFOS() << "mouse down (" << x << ", " << y << ")" << LL_ENDL; + if (mMediaSource) { - plugin->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOWN, button, x, y, mask); + mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOWN, button, x, y, mask); } } ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::mouseUp(S32 x, S32 y, MASK mask, S32 button) { - LLPluginClassMedia* plugin = getMediaPlugin(); + LLPluginClassMedia* mMediaSource = getMediaPlugin(); scaleMouse(&x, &y); mLastMouseX = x; mLastMouseY = y; - if (plugin) +// LL_INFOS() << "mouse up (" << x << ", " << y << ")" << LL_ENDL; + if (mMediaSource) { - plugin->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, button, x, y, mask); + mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, button, x, y, mask); } } ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::mouseMove(S32 x, S32 y, MASK mask) { - LLPluginClassMedia* plugin = getMediaPlugin(); + LLPluginClassMedia* mMediaSource = getMediaPlugin(); scaleMouse(&x, &y); mLastMouseX = x; mLastMouseY = y; - if (plugin) +// LL_INFOS() << "mouse move (" << x << ", " << y << ")" << LL_ENDL; + if (mMediaSource) { - plugin->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_MOVE, 0, x, y, mask); + mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_MOVE, 0, x, y, mask); } } - ////////////////////////////////////////////////////////////////////////////////////////// //static void LLViewerMediaImpl::scaleTextureCoords(const LLVector2& texture_coords, S32 *x, S32 *y) { - LLPluginClassMedia* plugin = getMediaPlugin(); + LLPluginClassMedia* mMediaSource = getMediaPlugin(); F32 texture_x = texture_coords.mV[VX]; F32 texture_y = texture_coords.mV[VY]; @@ -2368,18 +2277,18 @@ void LLViewerMediaImpl::scaleTextureCoords(const LLVector2& texture_coords, S32 texture_y = 1.0 + texture_y; // scale x and y to texel units. - *x = llround(texture_x * plugin->getTextureWidth()); - *y = llround((1.0f - texture_y) * plugin->getTextureHeight()); + *x = ll_round(texture_x * mMediaSource->getTextureWidth()); + *y = ll_round((1.0f - texture_y) * mMediaSource->getTextureHeight()); // Adjust for the difference between the actual texture height and the amount of the texture in use. - *y -= (plugin->getTextureHeight() - plugin->getHeight()); + *y -= (mMediaSource->getTextureHeight() - mMediaSource->getHeight()); } ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::mouseDown(const LLVector2& texture_coords, MASK mask, S32 button) { - LLPluginClassMedia* plugin = getMediaPlugin(); - if(plugin) + LLPluginClassMedia* mMediaSource = getMediaPlugin(); + if(mMediaSource) { S32 x, y; scaleTextureCoords(texture_coords, &x, &y); @@ -2390,8 +2299,8 @@ void LLViewerMediaImpl::mouseDown(const LLVector2& texture_coords, MASK mask, S3 void LLViewerMediaImpl::mouseUp(const LLVector2& texture_coords, MASK mask, S32 button) { - LLPluginClassMedia* plugin = getMediaPlugin(); - if(plugin) + LLPluginClassMedia* mMediaSource = getMediaPlugin(); + if(mMediaSource) { S32 x, y; scaleTextureCoords(texture_coords, &x, &y); @@ -2402,8 +2311,8 @@ void LLViewerMediaImpl::mouseUp(const LLVector2& texture_coords, MASK mask, S32 void LLViewerMediaImpl::mouseMove(const LLVector2& texture_coords, MASK mask) { - LLPluginClassMedia* plugin = getMediaPlugin(); - if(plugin) + LLPluginClassMedia* mMediaSource = getMediaPlugin(); + if(mMediaSource) { S32 x, y; scaleTextureCoords(texture_coords, &x, &y); @@ -2412,39 +2321,51 @@ void LLViewerMediaImpl::mouseMove(const LLVector2& texture_coords, MASK mask) } } +void LLViewerMediaImpl::mouseDoubleClick(const LLVector2& texture_coords, MASK mask) +{ + LLPluginClassMedia* mMediaSource = getMediaPlugin(); + if (mMediaSource) + { + S32 x, y; + scaleTextureCoords(texture_coords, &x, &y); + + mouseDoubleClick(x, y, mask); + } +} + ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::mouseDoubleClick(S32 x, S32 y, MASK mask, S32 button) { - LLPluginClassMedia* plugin = getMediaPlugin(); + LLPluginClassMedia* mMediaSource = getMediaPlugin(); scaleMouse(&x, &y); mLastMouseX = x; mLastMouseY = y; - if (plugin) + if (mMediaSource) { - plugin->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOUBLE_CLICK, button, x, y, mask); + mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOUBLE_CLICK, button, x, y, mask); } } ////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::scrollWheel(S32 x, S32 y, MASK mask) +void LLViewerMediaImpl::scrollWheel(S32 x, S32 y, S32 scroll_x, S32 scroll_y, MASK mask) { - LLPluginClassMedia* plugin = getMediaPlugin(); + LLPluginClassMedia* mMediaSource = getMediaPlugin(); scaleMouse(&x, &y); mLastMouseX = x; mLastMouseY = y; - if (plugin) + if (mMediaSource) { - plugin->scrollEvent(x, y, mask); + mMediaSource->scrollEvent(x, y, scroll_x, scroll_y, mask); } } ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::onMouseCaptureLost() { - LLPluginClassMedia* plugin = getMediaPlugin(); - if (plugin) + LLPluginClassMedia* mMediaSource = getMediaPlugin(); + if (mMediaSource) { - plugin->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, 0, mLastMouseX, mLastMouseY, 0); + mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, 0, mLastMouseX, mLastMouseY, 0); } } @@ -2468,11 +2389,11 @@ void LLViewerMediaImpl::updateJavascriptObject() { static LLFrameTimer timer ; - LLPluginClassMedia* plugin = getMediaPlugin(); - if ( plugin ) + LLPluginClassMedia* mMediaSource = getMediaPlugin(); + if ( mMediaSource ) { // flag to expose this information to internal browser or not. - bool enable = gSavedSettings.getBOOL("BrowserEnableJSObject"); + static LLCachedControl enable(gSavedSettings, "BrowserEnableJSObject", false); if(!enable) { @@ -2485,7 +2406,7 @@ void LLViewerMediaImpl::updateJavascriptObject() } timer.reset() ; - plugin->jsEnableObject( enable ); + mMediaSource->jsEnableObject( enable ); // these values are only menaingful after login so don't set them before //bool logged_in = LLLoginInstance::getInstance()->authSuccess(); @@ -2497,20 +2418,20 @@ void LLViewerMediaImpl::updateJavascriptObject() double x = agent_pos.mV[ VX ]; double y = agent_pos.mV[ VY ]; double z = agent_pos.mV[ VZ ]; - plugin->jsAgentLocationEvent( x, y, z ); + mMediaSource->jsAgentLocationEvent( x, y, z ); // current location within the grid LLVector3d agent_pos_global = gAgent.getLastPositionGlobal(); double global_x = agent_pos_global.mdV[ VX ]; double global_y = agent_pos_global.mdV[ VY ]; double global_z = agent_pos_global.mdV[ VZ ]; - plugin->jsAgentGlobalLocationEvent( global_x, global_y, global_z ); + mMediaSource->jsAgentGlobalLocationEvent( global_x, global_y, global_z ); // current agent orientation double rotation = atan2( gAgent.getAtAxis().mV[VX], gAgent.getAtAxis().mV[VY] ); double angle = rotation * RAD_TO_DEG; if ( angle < 0.0f ) angle = 360.0f + angle; // TODO: has to be a better way to get orientation! - plugin->jsAgentOrientationEvent( angle ); + mMediaSource->jsAgentOrientationEvent( angle ); // current region agent is in std::string region_name(""); @@ -2519,29 +2440,31 @@ void LLViewerMediaImpl::updateJavascriptObject() { region_name = region->getName(); }; - plugin->jsAgentRegionEvent( region_name ); + mMediaSource->jsAgentRegionEvent( region_name ); } // language code the viewer is set to - plugin->jsAgentLanguageEvent( LLUI::getLanguage() ); + mMediaSource->jsAgentLanguageEvent( LLUI::getLanguage() ); // maturity setting the agent has selected if ( gAgent.prefersAdult() ) - plugin->jsAgentMaturityEvent( "GMA" ); // Adult means see adult, mature and general content + mMediaSource->jsAgentMaturityEvent( "GMA" ); // Adult means see adult, mature and general content else if ( gAgent.prefersMature() ) - plugin->jsAgentMaturityEvent( "GM" ); // Mature means see mature and general content + mMediaSource->jsAgentMaturityEvent( "GM" ); // Mature means see mature and general content else if ( gAgent.prefersPG() ) - plugin->jsAgentMaturityEvent( "G" ); // PG means only see General content + mMediaSource->jsAgentMaturityEvent( "G" ); // PG means only see General content } } + +////////////////////////////////////////////////////////////////////////////////////////// const std::string& LLViewerMediaImpl::getName() const { - LLPluginClassMedia* plugin = getMediaPlugin(); - if (plugin) + LLPluginClassMedia* mMediaSource = getMediaPlugin(); + if (mMediaSource) { - return plugin->getMediaName(); + return mMediaSource->getMediaName(); } return LLStringUtil::null; @@ -2550,20 +2473,20 @@ const std::string& LLViewerMediaImpl::getName() const ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::navigateBack() { - LLPluginClassMedia* plugin = getMediaPlugin(); - if (plugin) + LLPluginClassMedia* mMediaSource = getMediaPlugin(); + if (mMediaSource) { - plugin->browse_back(); + mMediaSource->browse_back(); } } ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::navigateForward() { - LLPluginClassMedia* plugin = getMediaPlugin(); - if (plugin) + LLPluginClassMedia* mMediaSource = getMediaPlugin(); + if (mMediaSource) { - plugin->browse_forward(); + mMediaSource->browse_forward(); } } @@ -2593,8 +2516,14 @@ void LLViewerMediaImpl::unload() } ////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mime_type, bool rediscover_type, bool server_request) +void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mime_type, bool rediscover_type, bool server_request, bool clean_browser) { + if (url.empty()) + { + LL_WARNS() << "Calling LLViewerMediaImpl::navigateTo with empty url" << LL_ENDL; + return; + } + cancelMimeTypeProbe(); if(mMediaURL != url) @@ -2606,6 +2535,7 @@ void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mi // Always set the current URL and MIME type. mMediaURL = url; mMimeType = mime_type; + mCleanBrowser = clean_browser; // Clear the current media URL, since it will no longer be correct. mCurrentMediaURL.clear(); @@ -2622,7 +2552,12 @@ void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mi if(mPriority == PRIORITY_UNLOADED) { // Helpful to have media urls in log file. Shouldn't be spammy. - llinfos << "NOT LOADING media id= " << mTextureId << " url=" << url << " mime_type=" << mime_type << llendl; + { + // Do not log the query parts + LLURI u(url); + std::string sanitized_url = (u.query().empty() ? url : u.scheme() + "://" + u.authority() + u.path()); + LL_INFOS() << "NOT LOADING media id= " << mTextureId << " url=" << sanitized_url << ", mime_type=" << mime_type << LL_ENDL; + } // This impl should not be loaded at this time. LL_DEBUGS("PluginPriority") << this << "Not loading (PRIORITY_UNLOADED)" << LL_ENDL; @@ -2637,18 +2572,29 @@ void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mi void LLViewerMediaImpl::navigateInternal() { // Helpful to have media urls in log file. Shouldn't be spammy. - llinfos << "media id= " << mTextureId << " url=" << mMediaURL << " mime_type=" << mMimeType << llendl; + { + // Do not log the query parts + LLURI u(mMediaURL); + std::string sanitized_url = (u.query().empty() ? mMediaURL : u.scheme() + "://" + u.authority() + u.path()); + LL_INFOS() << "media id= " << mTextureId << " url=" << sanitized_url << ", mime_type=" << mMimeType << LL_ENDL; + } + + if (mMediaURL.empty()) + { + LL_WARNS() << "Calling LLViewerMediaImpl::navigateInternal() with empty mMediaURL" << LL_ENDL; + return; + } if(mNavigateSuspended) { - llwarns << "Deferring navigate." << llendl; + LL_WARNS() << "Deferring navigate." << LL_ENDL; mNavigateSuspendedDeferred = true; return; } - if(mMimeTypeProbe != NULL) + if(mMimeProbe != nullptr) { - llwarns << "MIME type probe already in progress -- bailing out." << llendl; + LL_WARNS() << "MIME type probe already in progress -- bailing out." << LL_ENDL; return; } @@ -2689,16 +2635,20 @@ void LLViewerMediaImpl::navigateInternal() // which is really not what we want. AIHTTPHeaders headers; headers.addHeader("Accept", "*/*"); + // Allow cookies in the response, to prevent a redirect loop when accessing join.secondlife.com headers.addHeader("Cookie", ""); - LLHTTPClient::getHeaderOnly( mMediaURL, new LLMimeDiscoveryResponder(this, "text/html"), headers); + LLHTTPClient::getHeaderOnly( mMediaURL, new LLMimeDiscoveryResponder(this), headers); } else if("data" == scheme || "file" == scheme || "about" == scheme) { - // FIXME: figure out how to really discover the type for these schemes - // We use "data" internally for a text/html url for loading the login screen - if(initializeMedia("text/html")) + if ("blank" != uri.hostName()) { - loadURI(); + // FIXME: figure out how to really discover the type for these schemes + // We use "data" internally for a text/html url for loading the login screen + if(initializeMedia("text/html")) + { + loadURI(); + } } } else @@ -2723,66 +2673,97 @@ void LLViewerMediaImpl::navigateInternal() ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::navigateStop() { - LLPluginClassMedia* plugin = getMediaPlugin(); - if (plugin) + LLPluginClassMedia* mMediaSource = getMediaPlugin(); + if(mMediaSource) { - plugin->browse_stop(); + mMediaSource->browse_stop(); } - } ////////////////////////////////////////////////////////////////////////////////////////// bool LLViewerMediaImpl::handleKeyHere(KEY key, MASK mask) { bool result = false; - LLPluginClassMedia* plugin = getMediaPlugin(); + LLPluginClassMedia* mMediaSource = getMediaPlugin(); - if (plugin) + if (mMediaSource) { - // FIXME: THIS IS SO WRONG. - // Menu keys should be handled by the menu system and not passed to UI elements, but this is how LLTextEditor and LLLineEditor do it... - if( MASK_CONTROL & mask ) + switch (mask) { - if( 'C' == key ) - { - plugin->copy(); - result = true; - } - else - if( 'V' == key ) + case MASK_CONTROL: + { + result = true; // Avoid redundant code, set false for default. + switch(key) { - plugin->paste(); - result = true; + // FIXME: THIS IS SO WRONG. + // Menu keys should be handled by the menu system and not passed to UI elements, but this is how LLTextEditor and LLLineEditor do it... + case KEY_LEFT: case KEY_RIGHT: case KEY_HOME: case KEY_END: break; + + case 'C': mMediaSource->copy(); break; + case 'V': mMediaSource->paste(); break; + case 'X': mMediaSource->cut(); break; + case '=': setPageZoomFactor(mZoomFactor + .1); break; + case '-': setPageZoomFactor(mZoomFactor - .1); break; + case '0': setPageZoomFactor(1.0); break; + + default: result = false; break; } - else - if( 'X' == key ) + break; + } + case MASK_SHIFT|MASK_CONTROL: + if (key == 'I') { - plugin->cut(); + mMediaSource->showWebInspector(true); result = true; } + break; } - + + // Singu Note: At the very least, let's allow the login menu to function + extern LLMenuBarGL* gLoginMenuBarView; + result = result || (gLoginMenuBarView && gLoginMenuBarView->getVisible() && gLoginMenuBarView->handleAcceleratorKey(key, mask)); + if(!result) { - LLSD native_key_data = gViewerWindow->getWindow()->getNativeKeyData(); - - result = plugin->keyEvent(LLPluginClassMedia::KEY_EVENT_DOWN ,key, mask, native_key_data); - // Since the viewer internal event dispatching doesn't give us key-up events, simulate one here. - (void)plugin->keyEvent(LLPluginClassMedia::KEY_EVENT_UP ,key, mask, native_key_data); + result = mMediaSource->keyEvent(LLPluginClassMedia::KEY_EVENT_DOWN, key, mask, native_key_data); } } - + return result; } +////////////////////////////////////////////////////////////////////////////////////////// +bool LLViewerMediaImpl::handleKeyUpHere(KEY key, MASK mask) +{ + bool result = false; + LLPluginClassMedia* mMediaSource = getMediaPlugin(); + + if (mMediaSource) + { + // FIXME: THIS IS SO WRONG. + // Menu keys should be handled by the menu system and not passed to UI elements, but this is how LLTextEditor and LLLineEditor do it... + if (MASK_CONTROL & mask && key != KEY_LEFT && key != KEY_RIGHT && key != KEY_HOME && key != KEY_END) + { + result = true; + } + + if (!result) + { + LLSD native_key_data = gViewerWindow->getWindow()->getNativeKeyData(); + result = mMediaSource->keyEvent(LLPluginClassMedia::KEY_EVENT_UP, key, mask, native_key_data); + } + } + + return result; +} ////////////////////////////////////////////////////////////////////////////////////////// bool LLViewerMediaImpl::handleUnicodeCharHere(llwchar uni_char) { bool result = false; - LLPluginClassMedia* plugin = getMediaPlugin(); + LLPluginClassMedia* mMediaSource = getMediaPlugin(); - if (plugin) + if (mMediaSource) { // only accept 'printable' characters, sigh... if (uni_char >= 32 // discard 'control' characters @@ -2790,7 +2771,7 @@ bool LLViewerMediaImpl::handleUnicodeCharHere(llwchar uni_char) { LLSD native_key_data = gViewerWindow->getWindow()->getNativeKeyData(); - plugin->textInput(wstring_to_utf8str(LLWString(1, uni_char)), gKeyboard->currentMask(FALSE), native_key_data); + mMediaSource->textInput(wstring_to_utf8str(LLWString(1, uni_char)), gKeyboard->currentMask(FALSE), native_key_data); } } @@ -2800,11 +2781,11 @@ bool LLViewerMediaImpl::handleUnicodeCharHere(llwchar uni_char) ////////////////////////////////////////////////////////////////////////////////////////// bool LLViewerMediaImpl::canNavigateForward() { - bool result = false; - LLPluginClassMedia* plugin = getMediaPlugin(); - if (plugin) + BOOL result = FALSE; + LLPluginClassMedia* mMediaSource = getMediaPlugin(); + if (mMediaSource) { - result = plugin->getHistoryForwardAvailable(); + result = mMediaSource->getHistoryForwardAvailable(); } return result; } @@ -2812,28 +2793,26 @@ bool LLViewerMediaImpl::canNavigateForward() ////////////////////////////////////////////////////////////////////////////////////////// bool LLViewerMediaImpl::canNavigateBack() { - bool result = false; - LLPluginClassMedia* plugin = getMediaPlugin(); - if (plugin) + BOOL result = FALSE; + LLPluginClassMedia* mMediaSource = getMediaPlugin(); + if (mMediaSource) { - result = plugin->getHistoryBackAvailable(); + result = mMediaSource->getHistoryBackAvailable(); } return result; } ////////////////////////////////////////////////////////////////////////////////////////// -static LLFastTimer::DeclareTimer FTM_MEDIA_DO_UPDATE("Do Update"); -static LLFastTimer::DeclareTimer FTM_MEDIA_GET_DATA("Get Data"); -static LLFastTimer::DeclareTimer FTM_MEDIA_SET_SUBIMAGE("Set Subimage"); +static LLTrace::BlockTimerStatHandle FTM_MEDIA_DO_UPDATE("Do Update"); +static LLTrace::BlockTimerStatHandle FTM_MEDIA_GET_DATA("Get Data"); +static LLTrace::BlockTimerStatHandle FTM_MEDIA_SET_SUBIMAGE("Set Subimage"); void LLViewerMediaImpl::update() { - LLFastTimer t(FTM_MEDIA_DO_UPDATE); - - LLPluginClassMedia* plugin = getMediaPlugin(); - - if(plugin == NULL) + LL_RECORD_BLOCK_TIME(FTM_MEDIA_DO_UPDATE); + LLPluginClassMedia* mMediaSource = getMediaPlugin(); + if(mMediaSource == nullptr) { if(mPriority == PRIORITY_UNLOADED) { @@ -2843,7 +2822,7 @@ void LLViewerMediaImpl::update() { // Don't load new instances that are at PRIORITY_SLIDESHOW or below. They're just kept around to preserve state. } - else if(mMimeTypeProbe != NULL) + else if(mMimeProbe != nullptr) { // this media source is doing a MIME type probe -- don't try loading it again. } @@ -2868,17 +2847,10 @@ void LLViewerMediaImpl::update() // TODO: this is updated every frame - is this bad? updateJavascriptObject(); - - // If we didn't just create the impl, it may need to get cookie updates. - if(!sUpdatedCookies.empty()) - { - // TODO: Only send cookies to plugins that need them - plugin->set_cookies(sUpdatedCookies); - } } - if(plugin == NULL) + if(mMediaSource == nullptr) { return; } @@ -2886,24 +2858,24 @@ void LLViewerMediaImpl::update() // Make sure a navigate doesn't happen during the idle -- it can cause mMediaSource to get destroyed, which can cause a crash. setNavigateSuspended(true); - plugin->idle(); + mMediaSource->idle(); setNavigateSuspended(false); - plugin = getMediaPlugin(); - if(plugin == NULL) + mMediaSource = getMediaPlugin(); + if(mMediaSource == nullptr) { return; } - if (plugin->isPluginExited()) + if(mMediaSource->isPluginExited()) { resetPreviousMediaState(); destroyMediaSource(); return; } - if (!plugin->textureValid()) + if(!mMediaSource->textureValid()) { return; } @@ -2922,7 +2894,7 @@ void LLViewerMediaImpl::update() // Since we're updating this texture, we know it's playing. Tell the texture to do its replacement magic so it gets rendered. placeholder_image->setPlaying(TRUE); - if (plugin->getDirty(&dirty_rect)) + if(mMediaSource->getDirty(&dirty_rect)) { // Constrain the dirty rect to be inside the texture S32 x_pos = llmax(dirty_rect.mLeft, 0); @@ -2933,32 +2905,35 @@ void LLViewerMediaImpl::update() if(width > 0 && height > 0) { - U8* data = NULL; + U8* data = nullptr; { - LLFastTimer t(FTM_MEDIA_GET_DATA); - data = plugin->getBitsData(); + LL_RECORD_BLOCK_TIME(FTM_MEDIA_GET_DATA); + data = mMediaSource->getBitsData(); } + if(data != NULL) + { // Offset the pixels pointer to match x_pos and y_pos - data += ( x_pos * plugin->getTextureDepth() * plugin->getBitsWidth() ); - data += ( y_pos * plugin->getTextureDepth() ); + data += ( x_pos * mMediaSource->getTextureDepth() * mMediaSource->getBitsWidth() ); + data += ( y_pos * mMediaSource->getTextureDepth() ); { - LLFastTimer t(FTM_MEDIA_SET_SUBIMAGE); + LL_RECORD_BLOCK_TIME(FTM_MEDIA_SET_SUBIMAGE); placeholder_image->setSubImage( data, - plugin->getBitsWidth(), - plugin->getBitsHeight(), + mMediaSource->getBitsWidth(), + mMediaSource->getBitsHeight(), x_pos, y_pos, width, height, - TRUE); // force a fast update (i.e. don't call analyzeAlpha, etc.) + TRUE); // + } } } - plugin->resetDirty(); + mMediaSource->resetDirty(); } } } @@ -2976,27 +2951,27 @@ LLViewerMediaTexture* LLViewerMediaImpl::updatePlaceholderImage() if(mTextureId.isNull()) { // The code that created this instance will read from the plugin's bits. - return NULL; + return nullptr; } LLViewerMediaTexture* placeholder_image = LLViewerTextureManager::getMediaTexture( mTextureId ); - LLPluginClassMedia* plugin = getMediaPlugin(); + LLPluginClassMedia* mMediaSource = getMediaPlugin(); if (mNeedsNewTexture || placeholder_image->getUseMipMaps() - || (placeholder_image->getWidth() != plugin->getTextureWidth()) - || (placeholder_image->getHeight() != plugin->getTextureHeight()) - || (mTextureUsedWidth != plugin->getWidth()) - || (mTextureUsedHeight != plugin->getHeight()) + || (placeholder_image->getWidth() != mMediaSource->getTextureWidth()) + || (placeholder_image->getHeight() != mMediaSource->getTextureHeight()) + || (mTextureUsedWidth != mMediaSource->getWidth()) + || (mTextureUsedHeight != mMediaSource->getHeight()) ) { LL_DEBUGS("Media") << "initializing media placeholder" << LL_ENDL; LL_DEBUGS("Media") << "movie image id " << mTextureId << LL_ENDL; - int texture_width = plugin->getTextureWidth(); - int texture_height = plugin->getTextureHeight(); - int texture_depth = plugin->getTextureDepth(); + int texture_width = mMediaSource->getTextureWidth(); + int texture_height = mMediaSource->getTextureHeight(); + int texture_depth = mMediaSource->getTextureDepth(); // MEDIAOPT: check to see if size actually changed before doing work placeholder_image->destroyGLTexture(); @@ -3012,16 +2987,13 @@ LLViewerMediaTexture* LLViewerMediaImpl::updatePlaceholderImage() int discard_level = 0; // ask media source for correct GL image format constants - placeholder_image->setExplicitFormat(plugin->getTextureFormatInternal(), - plugin->getTextureFormatPrimary(), - plugin->getTextureFormatType(), - plugin->getTextureFormatSwapBytes()); + placeholder_image->setExplicitFormat(mMediaSource->getTextureFormatInternal(), + mMediaSource->getTextureFormatPrimary(), + mMediaSource->getTextureFormatType(), + mMediaSource->getTextureFormatSwapBytes()); placeholder_image->createGLTexture(discard_level, raw); - // placeholder_image->setExplicitFormat() - //placeholder_image->setUseMipMaps(FALSE); - // MEDIAOPT: set this dynamically on play/stop // FIXME // placeholder_image->mIsMediaTexture = true; @@ -3029,8 +3001,8 @@ LLViewerMediaTexture* LLViewerMediaImpl::updatePlaceholderImage() // If the amount of the texture being drawn by the media goes down in either width or height, // recreate the texture to avoid leaving parts of the old image behind. - mTextureUsedWidth = plugin->getWidth(); - mTextureUsedHeight = plugin->getHeight(); + mTextureUsedWidth = mMediaSource->getWidth(); + mTextureUsedHeight = mMediaSource->getHeight(); } return placeholder_image; @@ -3046,17 +3018,18 @@ LLUUID LLViewerMediaImpl::getMediaTextureID() const ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::setVisible(bool visible) { - LLPluginClassMedia* plugin = getMediaPlugin(); + LLPluginClassMedia* mMediaSource = getMediaPlugin(); mVisible = visible; if(mVisible) { - if(plugin && plugin->isPluginExited()) + if(mMediaSource && mMediaSource->isPluginExited()) { destroyMediaSource(); - plugin = NULL; + mMediaSource = NULL; } - if(!plugin) + + if(!mMediaSource) { createMediaSource(); } @@ -3083,15 +3056,17 @@ void LLViewerMediaImpl::scaleMouse(S32 *mouse_x, S32 *mouse_y) #endif } + + ////////////////////////////////////////////////////////////////////////////////////////// bool LLViewerMediaImpl::isMediaTimeBased() { bool result = false; - LLPluginClassMedia* plugin = getMediaPlugin(); + LLPluginClassMedia* mMediaSource = getMediaPlugin(); - if(plugin) + if(mMediaSource) { - result = plugin->pluginSupportsMediaTime(); + result = mMediaSource->pluginSupportsMediaTime(); } return result; @@ -3101,11 +3076,11 @@ bool LLViewerMediaImpl::isMediaTimeBased() bool LLViewerMediaImpl::isMediaPlaying() { bool result = false; - LLPluginClassMedia* plugin = getMediaPlugin(); + LLPluginClassMedia* mMediaSource = getMediaPlugin(); - if(plugin) + if(mMediaSource) { - EMediaStatus status = plugin->getStatus(); + EMediaStatus status = mMediaSource->getStatus(); if(status == MEDIA_PLAYING || status == MEDIA_LOADING) result = true; } @@ -3116,11 +3091,11 @@ bool LLViewerMediaImpl::isMediaPlaying() bool LLViewerMediaImpl::isMediaPaused() { bool result = false; - LLPluginClassMedia* plugin = getMediaPlugin(); + LLPluginClassMedia* mMediaSource = getMediaPlugin(); - if(plugin) + if(mMediaSource) { - if(plugin->getStatus() == MEDIA_PAUSED) + if(mMediaSource->getStatus() == MEDIA_PAUSED) result = true; } @@ -3177,13 +3152,13 @@ bool LLViewerMediaImpl::isForcedUnloaded() const { return true; } - + // If this media's class is not supposed to be shown, unload if (!shouldShowBasedOnClass()) { return true; } - + return false; } @@ -3196,32 +3171,25 @@ bool LLViewerMediaImpl::isPlayable() const // All of the forced-unloaded criteria also imply not playable. return false; } - + if(hasMedia()) { // Anything that's already playing is, by definition, playable. return true; } - + if(!mMediaURL.empty()) { // If something has navigated the instance, it's ready to be played. return true; } - + return false; } static void handle_pick_file_request_continued(LLPluginClassMedia* plugin, AIFilePicker* filepicker) { - std::string response; - - if(filepicker->hasFilename()) - { - response = filepicker->getFilename(); - } - - plugin->sendPickFileResponse(response); + plugin->sendPickFileResponse(filepicker->hasFilename() ? filepicker->getFilenames() : std::vector()); } ////////////////////////////////////////////////////////////////////////////////////////// @@ -3235,7 +3203,7 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla LL_DEBUGS("Media") << "MEDIA_EVENT_CLICK_LINK_NOFOLLOW, uri is: " << plugin->getClickURL() << LL_ENDL; std::string url = plugin->getClickURL(); std::string nav_type = plugin->getClickNavType(); - LLURLDispatcher::dispatch(url, nav_type, NULL, mTrustedBrowser); + LLURLDispatcher::dispatch(url, nav_type, nullptr, mTrustedBrowser); } break; case MEDIA_EVENT_CLICK_LINK_HREF: @@ -3295,6 +3263,13 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla } break; + case LLViewerMediaObserver::MEDIA_EVENT_FILE_DOWNLOAD: + { + //llinfos << "Media event - file download requested - filename is " << self->getFileDownloadFilename() << llendl; + LLNotificationsUtil::add("MediaFileDownloadUnsupported"); + } + break; + case LLViewerMediaObserver::MEDIA_EVENT_NAVIGATE_BEGIN: { LL_DEBUGS("Media") << "MEDIA_EVENT_NAVIGATE_BEGIN, uri is: " << plugin->getNavigateURI() << LL_ENDL; @@ -3393,7 +3368,6 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla } break; - case LLViewerMediaObserver::MEDIA_EVENT_AUTH_REQUEST: { LLNotification::Params auth_request_params("AuthRequest"); @@ -3415,7 +3389,7 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla { std::string uuid = plugin->getClickUUID(); - llinfos << "MEDIA_EVENT_CLOSE_REQUEST for uuid " << uuid << llendl; + LL_INFOS() << "MEDIA_EVENT_CLOSE_REQUEST for uuid " << uuid << LL_ENDL; if(uuid.empty()) { @@ -3434,7 +3408,7 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla { std::string uuid = plugin->getClickUUID(); - llinfos << "MEDIA_EVENT_GEOMETRY_CHANGE for uuid " << uuid << llendl; + LL_INFOS() << "MEDIA_EVENT_GEOMETRY_CHANGE for uuid " << uuid << LL_ENDL; if(uuid.empty()) { @@ -3449,6 +3423,32 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla } break; + case MEDIA_EVENT_DEBUG_MESSAGE: + { + std::string level = plugin->getDebugMessageLevel(); + if (level == "debug") + { + LL_DEBUGS("Media") << plugin->getDebugMessageText() << LL_ENDL; + } + else if (level == "info") + { + LL_INFOS("Media") << plugin->getDebugMessageText() << LL_ENDL; + } + else if (level == "warn") + { + LL_WARNS("Media") << plugin->getDebugMessageText() << LL_ENDL; + } + else if (level == "error") + { + LL_ERRS("Media") << plugin->getDebugMessageText() << LL_ENDL; + } + else + { + LL_INFOS("Media") << plugin->getDebugMessageText() << LL_ENDL; + } + }; + break; + default: break; } @@ -3462,9 +3462,46 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla //////////////////////////////////////////////////////////////////////////////// // virtual -void LLViewerMediaImpl::handleCookieSet(LLPluginClassMedia* self, const std::string &cookie) +void +LLViewerMediaImpl::undo() +{ + LLPluginClassMedia* mMediaSource = getMediaPlugin(); + if (mMediaSource) + mMediaSource->undo(); +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +BOOL +LLViewerMediaImpl::canUndo() const { - LLViewerMedia::getCookieStore()->setCookies(cookie); + LLPluginClassMedia* mMediaSource = getMediaPlugin(); + if (mMediaSource) + return mMediaSource->canUndo(); + else + return FALSE; +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +void +LLViewerMediaImpl::redo() +{ + LLPluginClassMedia* mMediaSource = getMediaPlugin(); + if (mMediaSource) + mMediaSource->redo(); +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +BOOL +LLViewerMediaImpl::canRedo() const +{ + LLPluginClassMedia* mMediaSource = getMediaPlugin(); + if (mMediaSource) + return mMediaSource->canRedo(); + else + return FALSE; } //////////////////////////////////////////////////////////////////////////////// @@ -3472,9 +3509,9 @@ void LLViewerMediaImpl::handleCookieSet(LLPluginClassMedia* self, const std::str void LLViewerMediaImpl::cut() { - LLPluginClassMedia* plugin = getMediaPlugin(); - if (plugin) - plugin->cut(); + LLPluginClassMedia* mMediaSource = getMediaPlugin(); + if (mMediaSource) + mMediaSource->cut(); } //////////////////////////////////////////////////////////////////////////////// @@ -3482,9 +3519,9 @@ LLViewerMediaImpl::cut() BOOL LLViewerMediaImpl::canCut() const { - LLPluginClassMedia* plugin = getMediaPlugin(); - if (plugin) - return plugin->canCut(); + LLPluginClassMedia* mMediaSource = getMediaPlugin(); + if (mMediaSource) + return mMediaSource->canCut(); else return FALSE; } @@ -3492,11 +3529,11 @@ LLViewerMediaImpl::canCut() const //////////////////////////////////////////////////////////////////////////////// // virtual void -LLViewerMediaImpl::copy() +LLViewerMediaImpl::copy() const { - LLPluginClassMedia* plugin = getMediaPlugin(); - if (plugin) - plugin->copy(); + LLPluginClassMedia* mMediaSource = getMediaPlugin(); + if (mMediaSource) + mMediaSource->copy(); } //////////////////////////////////////////////////////////////////////////////// @@ -3504,9 +3541,9 @@ LLViewerMediaImpl::copy() BOOL LLViewerMediaImpl::canCopy() const { - LLPluginClassMedia* plugin = getMediaPlugin(); - if (plugin) - return plugin->canCopy(); + LLPluginClassMedia* mMediaSource = getMediaPlugin(); + if (mMediaSource) + return mMediaSource->canCopy(); else return FALSE; } @@ -3516,9 +3553,9 @@ LLViewerMediaImpl::canCopy() const void LLViewerMediaImpl::paste() { - LLPluginClassMedia* plugin = getMediaPlugin(); - if (plugin) - plugin->paste(); + LLPluginClassMedia* mMediaSource = getMediaPlugin(); + if (mMediaSource) + mMediaSource->paste(); } //////////////////////////////////////////////////////////////////////////////// @@ -3526,9 +3563,53 @@ LLViewerMediaImpl::paste() BOOL LLViewerMediaImpl::canPaste() const { - LLPluginClassMedia* plugin = getMediaPlugin(); - if (plugin) - return plugin->canPaste(); + LLPluginClassMedia* mMediaSource = getMediaPlugin(); + if (mMediaSource) + return mMediaSource->canPaste(); + else + return FALSE; +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +void +LLViewerMediaImpl::doDelete() +{ + LLPluginClassMedia* mMediaSource = getMediaPlugin(); + if (mMediaSource) + mMediaSource->doDelete(); +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +BOOL +LLViewerMediaImpl::canDoDelete() const +{ + LLPluginClassMedia* mMediaSource = getMediaPlugin(); + if (mMediaSource) + return mMediaSource->canDoDelete(); + else + return FALSE; +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +void +LLViewerMediaImpl::selectAll() +{ + LLPluginClassMedia* mMediaSource = getMediaPlugin(); + if (mMediaSource) + mMediaSource->selectAll(); +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +BOOL +LLViewerMediaImpl::canSelectAll() const +{ + LLPluginClassMedia* mMediaSource = getMediaPlugin(); + if (mMediaSource) + return mMediaSource->canSelectAll(); else return FALSE; } @@ -3543,14 +3624,14 @@ BOOL LLViewerMediaImpl::isUpdated() return mIsUpdated ; } -static LLFastTimer::DeclareTimer FTM_MEDIA_CALCULATE_INTEREST("Calculate Interest"); +static LLTrace::BlockTimerStatHandle FTM_MEDIA_CALCULATE_INTEREST("Calculate Interest"); void LLViewerMediaImpl::calculateInterest() { - LLFastTimer t(FTM_MEDIA_CALCULATE_INTEREST); + LL_RECORD_BLOCK_TIME(FTM_MEDIA_CALCULATE_INTEREST); LLViewerMediaTexture* texture = LLViewerTextureManager::findMediaTexture( mTextureId ); - if(texture != NULL) + if(texture != nullptr) { mInterest = texture->getMaxVirtualSize(); } @@ -3623,11 +3704,11 @@ F64 LLViewerMediaImpl::getApproximateTextureInterest() { F64 result = 0.0f; - LLPluginClassMedia* plugin = getMediaPlugin(); - if(plugin) + LLPluginClassMedia* mMediaSource = getMediaPlugin(); + if(mMediaSource) { - result = plugin->getFullWidth(); - result *= plugin->getFullHeight(); + result = mMediaSource->getFullWidth(); + result *= mMediaSource->getFullHeight(); } else { @@ -3664,21 +3745,21 @@ void LLViewerMediaImpl::setBackgroundColor(LLColor4 color) { mBackgroundColor = color; - LLPluginClassMedia* plugin = getMediaPlugin(); - if(plugin) + LLPluginClassMedia* mMediaSource = getMediaPlugin(); + if(mMediaSource) { - plugin->setBackgroundColor(mBackgroundColor); + mMediaSource->setBackgroundColor(mBackgroundColor); } }; F64 LLViewerMediaImpl::getCPUUsage() const { F64 result = 0.0f; - LLPluginClassMedia* plugin = getMediaPlugin(); + LLPluginClassMedia* mMediaSource = getMediaPlugin(); - if(plugin) + if(mMediaSource) { - result = plugin->getCPUUsage(); + result = mMediaSource->getCPUUsage(); } return result; @@ -3711,29 +3792,28 @@ void LLViewerMediaImpl::setPriority(EPriority priority) mPriority = priority; - LLPluginClassMedia* plugin = getMediaPlugin(); - + LLPluginClassMedia* mMediaSource = getMediaPlugin(); if(priority == PRIORITY_UNLOADED) { - if(plugin) + if(mMediaSource) { // Need to unload the media source // First, save off previous media state - mPreviousMediaState = plugin->getStatus(); - mPreviousMediaTime = plugin->getCurrentTime(); + mPreviousMediaState = mMediaSource->getStatus(); + mPreviousMediaTime = mMediaSource->getCurrentTime(); destroyMediaSource(); - plugin = NULL; + mMediaSource = NULL; } } - if(plugin) + if(mMediaSource) { if(mPriority >= PRIORITY_LOW) - plugin->setPriority((LLPluginClassBasic::EPriority)((U32)mPriority-((U32)PRIORITY_LOW-1))); + mMediaSource->setPriority((LLPluginClassBasic::EPriority)((U32)mPriority-((U32)PRIORITY_LOW-1))); else - plugin->setPriority(LLPluginClassBasic::PRIORITY_SLEEP); + mMediaSource->setPriority(LLPluginClassBasic::PRIORITY_SLEEP); } // NOTE: loading (or reloading) media sources whose priority has risen above PRIORITY_UNLOADED is done in update(). @@ -3741,10 +3821,10 @@ void LLViewerMediaImpl::setPriority(EPriority priority) void LLViewerMediaImpl::setLowPrioritySizeLimit(int size) { - LLPluginClassMedia* plugin = getMediaPlugin(); - if(plugin) + LLPluginClassMedia* mMediaSource = getMediaPlugin(); + if(mMediaSource) { - plugin->setLowPrioritySizeLimit(size); + mMediaSource->setLowPrioritySizeLimit(size); } } @@ -3754,16 +3834,16 @@ void LLViewerMediaImpl::setNavState(EMediaNavState state) switch (state) { - case MEDIANAVSTATE_NONE: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_NONE" << llendl; break; - case MEDIANAVSTATE_BEGUN: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_BEGUN" << llendl; break; - case MEDIANAVSTATE_FIRST_LOCATION_CHANGED: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_FIRST_LOCATION_CHANGED" << llendl; break; - case MEDIANAVSTATE_FIRST_LOCATION_CHANGED_SPURIOUS: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_FIRST_LOCATION_CHANGED_SPURIOUS" << llendl; break; - case MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED" << llendl; break; - case MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED_SPURIOUS: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED_SPURIOUS" << llendl; break; - case MEDIANAVSTATE_SERVER_SENT: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_SERVER_SENT" << llendl; break; - case MEDIANAVSTATE_SERVER_BEGUN: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_SERVER_BEGUN" << llendl; break; - case MEDIANAVSTATE_SERVER_FIRST_LOCATION_CHANGED: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_SERVER_FIRST_LOCATION_CHANGED" << llendl; break; - case MEDIANAVSTATE_SERVER_COMPLETE_BEFORE_LOCATION_CHANGED: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_SERVER_COMPLETE_BEFORE_LOCATION_CHANGED" << llendl; break; + case MEDIANAVSTATE_NONE: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_NONE" << LL_ENDL; break; + case MEDIANAVSTATE_BEGUN: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_BEGUN" << LL_ENDL; break; + case MEDIANAVSTATE_FIRST_LOCATION_CHANGED: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_FIRST_LOCATION_CHANGED" << LL_ENDL; break; + case MEDIANAVSTATE_FIRST_LOCATION_CHANGED_SPURIOUS: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_FIRST_LOCATION_CHANGED_SPURIOUS" << LL_ENDL; break; + case MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED" << LL_ENDL; break; + case MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED_SPURIOUS: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_COMPLETE_BEFORE_LOCATION_CHANGED_SPURIOUS" << LL_ENDL; break; + case MEDIANAVSTATE_SERVER_SENT: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_SERVER_SENT" << LL_ENDL; break; + case MEDIANAVSTATE_SERVER_BEGUN: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_SERVER_BEGUN" << LL_ENDL; break; + case MEDIANAVSTATE_SERVER_FIRST_LOCATION_CHANGED: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_SERVER_FIRST_LOCATION_CHANGED" << LL_ENDL; break; + case MEDIANAVSTATE_SERVER_COMPLETE_BEFORE_LOCATION_CHANGED: LL_DEBUGS("Media") << "Setting nav state to MEDIANAVSTATE_SERVER_COMPLETE_BEFORE_LOCATION_CHANGED" << LL_ENDL; break; } } @@ -3786,16 +3866,16 @@ void LLViewerMediaImpl::setNavigateSuspended(bool suspend) void LLViewerMediaImpl::cancelMimeTypeProbe() { - if(mMimeTypeProbe != NULL) + if(mMimeProbe) { // There doesn't seem to be a way to actually cancel an outstanding request. // Simulate it by telling the LLMimeDiscoveryResponder not to write back any results. - mMimeTypeProbe->cancelRequest(); + mMimeProbe->cancelRequest(); - // The above should already have set mMimeTypeProbe to NULL. - if(mMimeTypeProbe != NULL) + // The above should already have set mMimeProbe to nullptr. + if (mMimeProbe) { - llerrs << "internal error: mMimeTypeProbe is not NULL after cancelling request." << llendl; + LL_ERRS() << "internal error: mMimeProbe is not nullptr after cancelling request." << LL_ENDL; } } } @@ -3828,7 +3908,7 @@ const std::list< LLVOVolume* >* LLViewerMediaImpl::getObjectList() const LLVOVolume *LLViewerMediaImpl::getSomeObject() { - LLVOVolume *result = NULL; + LLVOVolume *result = nullptr; std::list< LLVOVolume* >::iterator iter = mObjectList.begin() ; if(iter != mObjectList.end()) @@ -3865,16 +3945,10 @@ bool LLViewerMediaImpl::isAutoPlayable() const static const LLCachedControl media_tentative_auto_play("MediaTentativeAutoPlay",false); static const LLCachedControl auto_play_parcel_media(LLViewerMedia::AUTO_PLAY_MEDIA_SETTING,false); static const LLCachedControl auto_play_prim_media(LLViewerMedia::AUTO_PLAY_PRIM_MEDIA_SETTING,false); - if(mMediaAutoPlay && media_tentative_auto_play) - { - if(getUsedInUI()) - return true; - else if(isParcelMedia() && auto_play_parcel_media) - return true; - else if(auto_play_prim_media) - return true; - } - return false; + return mMediaAutoPlay && media_tentative_auto_play && + (getUsedInUI() + || (isParcelMedia() && auto_play_parcel_media) + || auto_play_prim_media); } ////////////////////////////////////////////////////////////////////////////////////////// @@ -3887,10 +3961,10 @@ bool LLViewerMediaImpl::shouldShowBasedOnClass() const bool attached_to_another_avatar = isAttachedToAnotherAvatar(); bool inside_parcel = isInAgentParcel(); - // llinfos << " hasFocus = " << hasFocus() << + // LL_INFOS() << " hasFocus = " << hasFocus() << // " others = " << (attached_to_another_avatar && gSavedSettings.getBOOL(LLViewerMedia::SHOW_MEDIA_ON_OTHERS_SETTING)) << // " within = " << (inside_parcel && gSavedSettings.getBOOL(LLViewerMedia::SHOW_MEDIA_WITHIN_PARCEL_SETTING)) << - // " outside = " << (!inside_parcel && gSavedSettings.getBOOL(LLViewerMedia::SHOW_MEDIA_OUTSIDE_PARCEL_SETTING)) << llendl; + // " outside = " << (!inside_parcel && gSavedSettings.getBOOL(LLViewerMedia::SHOW_MEDIA_OUTSIDE_PARCEL_SETTING)) << LL_ENDL; // If it has focus, we should show it // This is incorrect, and causes EXT-6750 (disabled attachment media still plays) @@ -3900,18 +3974,18 @@ bool LLViewerMediaImpl::shouldShowBasedOnClass() const // If it is attached to an avatar and the pref is off, we shouldn't show it if (attached_to_another_avatar) { - static LLCachedControl show_media_on_others(gSavedSettings, LLViewerMedia::SHOW_MEDIA_ON_OTHERS_SETTING); + static LLCachedControl show_media_on_others(gSavedSettings, LLViewerMedia::SHOW_MEDIA_ON_OTHERS_SETTING, false); return show_media_on_others; } if (inside_parcel) { - static LLCachedControl show_media_within_parcel(gSavedSettings, LLViewerMedia::SHOW_MEDIA_WITHIN_PARCEL_SETTING); + static LLCachedControl show_media_within_parcel(gSavedSettings, LLViewerMedia::SHOW_MEDIA_WITHIN_PARCEL_SETTING, true); return show_media_within_parcel; } else { - static LLCachedControl show_media_outside_parcel(gSavedSettings, LLViewerMedia::SHOW_MEDIA_OUTSIDE_PARCEL_SETTING); + static LLCachedControl show_media_outside_parcel(gSavedSettings, LLViewerMedia::SHOW_MEDIA_OUTSIDE_PARCEL_SETTING, true); return show_media_outside_parcel; } @@ -3944,13 +4018,13 @@ bool LLViewerMediaImpl::isObjectAttachedToAnotherAvatar(LLVOVolume *obj) bool result = false; LLXform *xform = obj; // Walk up parent chain - while (NULL != xform) + while (nullptr != xform) { LLViewerObject *object = dynamic_cast (xform); - if (NULL != object) + if (nullptr != object) { LLVOAvatar *avatar = object->asAvatar(); - if ((NULL != avatar) && (avatar != gAgentAvatarp)) + if ((nullptr != avatar) && (avatar != gAgentAvatarp)) { result = true; break; diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h index 902d7ae0f6..224225498d 100644 --- a/indra/newview/llviewermedia.h +++ b/indra/newview/llviewermedia.h @@ -2,31 +2,25 @@ * @file llviewermedia.h * @brief Client interface to the media engine * - * $LicenseInfo:firstyear=2007&license=viewergpl$ - * - * Copyright (c) 2007-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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$ */ @@ -46,7 +40,6 @@ #include "llnotificationptr.h" #include "llurl.h" - #include "llviewerpluginmanager.h" class LLViewerMediaImpl; @@ -55,8 +48,6 @@ class LLViewerMediaTexture; class LLMediaEntry; class LLVOVolume; class LLMimeDiscoveryResponder; -class LLPluginCookieStore; -class AIHTTPHeaders; typedef LLPointer viewer_media_t; /////////////////////////////////////////////////////////////////////////////// @@ -92,6 +83,7 @@ class LLViewerMedia typedef std::list impl_list; typedef std::map impl_id_map; + // Special case early init for just web browser component // so we can show login screen. See .cpp file for details. JC @@ -111,10 +103,14 @@ class LLViewerMedia // Is any media currently "showing"? Includes Parcel Media. Does not include media in the UI. static bool isAnyMediaShowing(); + // Shows if any media is playing, counts visible non time based media as playing. Does not include media in the UI. + static bool isAnyMediaPlaying(); // Set all media enabled or disabled, depending on val. Does not include media in the UI. static void setAllMediaEnabled(bool val); + // Set all media paused(stopped for non time based) or playing, depending on val. Does not include media in the UI. + static void setAllMediaPaused(bool val); - static void updateMedia(void* dummy_arg = NULL); + static void updateMedia(void* dummy_arg = nullptr); static void initClass(); static void cleanupClass(); @@ -137,7 +133,7 @@ class LLViewerMedia static bool isParcelMediaPlaying(); static bool isParcelAudioPlaying(); - static bool onAuthSubmit(const LLSD& notification, const LLSD& response); + static void onAuthSubmit(const LLSD& notification, const LLSD& response); // Clear all cookies for all plugins static void clearAllCookies(); @@ -151,13 +147,6 @@ class LLViewerMedia // Set the proxy config for all loaded plugins static void setProxyConfig(bool enable, const std::string &host, int port); - static LLPluginCookieStore *getCookieStore(); - static void loadCookieFile(); - static void saveCookieFile(); - static void addCookie(const std::string &name, const std::string &value, const std::string &domain, const LLDate &expires, const std::string &path = std::string("/"), bool secure = false ); - static void addSessionCookie(const std::string &name, const std::string &value, const std::string &domain, const std::string &path = std::string("/"), bool secure = false ); - static void removeCookie(const std::string &name, const std::string &domain, const std::string &path = std::string("/") ); - static void openIDSetup(const std::string &openid_url, const std::string &openid_token); static void openIDCookieResponse(const std::string &cookie); @@ -169,13 +158,15 @@ class LLViewerMedia static void setOnlyAudibleMediaTextureID(const LLUUID& texture_id); - static AIHTTPHeaders getHeaders(); + static class AIHTTPHeaders getHeaders(); private: + static bool parseRawCookie(const std::string raw_cookie, std::string& name, std::string& value, std::string& path, bool& httponly, bool& secure); static void setOpenIDCookie(); static void onTeleportFinished(); - - static LLPluginCookieStore *sCookieStore; + + static void getOpenIDCookieCoro(std::string url); + static LLURL sOpenIDURL; static std::string sOpenIDCookie; static LLPluginClassMedia* sSpareBrowserMediaSource; @@ -201,7 +192,7 @@ class LLViewerMediaImpl ~LLViewerMediaImpl(); // Override inherited version from LLViewerMediaEventEmitter - virtual void emitEvent(LLPluginClassMedia* self, LLViewerMediaObserver::EMediaEvent event); + void emitEvent(LLPluginClassMedia* self, LLViewerMediaObserver::EMediaEvent event) override; void createMediaSource(); void destroyMediaSource(); @@ -223,6 +214,7 @@ class LLViewerMediaImpl void skipBack(F32 step_scale); void skipForward(F32 step_scale); void setVolume(F32 volume); + void setMute(bool mute); void updateVolume(); F32 getVolume(); void focus(bool focus); @@ -234,8 +226,9 @@ class LLViewerMediaImpl void mouseDown(const LLVector2& texture_coords, MASK mask, S32 button = 0); void mouseUp(const LLVector2& texture_coords, MASK mask, S32 button = 0); void mouseMove(const LLVector2& texture_coords, MASK mask); - void mouseDoubleClick(S32 x,S32 y, MASK mask, S32 button = 0); - void scrollWheel(S32 x, S32 y, MASK mask); + void mouseDoubleClick(const LLVector2& texture_coords, MASK mask); + void mouseDoubleClick(S32 x, S32 y, MASK mask, S32 button = 0); + void scrollWheel(S32 x, S32 y, S32 scroll_x, S32 scroll_y, MASK mask); void mouseCapture(); void navigateBack(); @@ -243,10 +236,11 @@ class LLViewerMediaImpl void navigateReload(); void navigateHome(); void unload(); - void navigateTo(const std::string& url, const std::string& mime_type = "", bool rediscover_type = false, bool server_request = false); + void navigateTo(const std::string& url, const std::string& mime_type = "", bool rediscover_type = false, bool server_request = false, bool clean_browser = false); void navigateInternal(); void navigateStop(); bool handleKeyHere(KEY key, MASK mask); + bool handleKeyUpHere(KEY key, MASK mask); bool handleUnicodeCharHere(llwchar uni_char); bool canNavigateForward(); bool canNavigateBack(); @@ -257,6 +251,7 @@ class LLViewerMediaImpl void setHomeURL(const std::string& home_url, const std::string& mime_type = LLStringUtil::null) { mHomeURL = home_url; mHomeMimeType = mime_type;}; void clearCache(); void setPageZoomFactor( double factor ); + double getPageZoomFactor() {return mZoomFactor;} std::string getMimeType() { return mMimeType; } void scaleMouse(S32 *mouse_x, S32 *mouse_y); void scaleTextureCoords(const LLVector2& texture_coords, S32 *x, S32 *y); @@ -298,7 +293,7 @@ class LLViewerMediaImpl void setTarget(const std::string& target) { mTarget = target; } // utility function to create a ready-to-use media instance from a desired media type. - static LLPluginClassMedia* newSourceFromMediaType(std::string media_type, LLPluginClassMediaOwner *owner /* may be NULL */, S32 default_width, S32 default_height, const std::string target = LLStringUtil::null); + static LLPluginClassMedia* newSourceFromMediaType(std::string media_type, LLPluginClassMediaOwner *owner /* may be NULL */, S32 default_width, S32 default_height, F64 zoom_factor, const std::string target = LLStringUtil::null, bool clean_browser = false); // Internally set our desired browser user agent string, including // the Second Life version and skin name. Used because we can @@ -310,40 +305,51 @@ class LLViewerMediaImpl static bool handleSkinCurrentChanged(const LLSD& newvalue); // need these to handle mouseup... - /*virtual*/ void onMouseCaptureLost(); - /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask); + /*virtual*/ void onMouseCaptureLost() override; + /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask) override; // Grr... the only thing I want as an LLMouseHandler are the onMouseCaptureLost and handleMouseUp calls. // Sadly, these are all pure virtual, so I have to supply implementations here: - /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask) { return FALSE; }; - /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask) { return FALSE; }; - /*virtual*/ BOOL handleScrollWheel(S32 x, S32 y, S32 clicks) { return FALSE; }; - /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask) { return FALSE; }; - /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask) { return FALSE; }; - /*virtual*/ BOOL handleRightMouseUp(S32 x, S32 y, MASK mask) { return FALSE; }; - /*virtual*/ BOOL handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_rect_screen) { return FALSE; }; - /*virtual*/ BOOL handleMiddleMouseDown(S32 x, S32 y, MASK mask) { return FALSE; }; - /*virtual*/ BOOL handleMiddleMouseUp(S32 x, S32 y, MASK mask) {return FALSE; }; - /*virtual*/ const std::string& getName() const; - /*virtual*/ BOOL isView() const { return FALSE; }; - - /*virtual*/ void screenPointToLocal(S32 screen_x, S32 screen_y, S32* local_x, S32* local_y) const {}; - /*virtual*/ void localPointToScreen(S32 local_x, S32 local_y, S32* screen_x, S32* screen_y) const {}; - /*virtual*/ BOOL hasMouseCapture() { return gFocusMgr.getMouseCapture() == this; }; + /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask) override { return FALSE; }; + /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask) override { return FALSE; }; + /*virtual*/ BOOL handleScrollWheel(S32 x, S32 y, S32 clicks) override { return FALSE; }; + /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask) override { return FALSE; }; + /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask) override { return FALSE; }; + /*virtual*/ BOOL handleRightMouseUp(S32 x, S32 y, MASK mask) override { return FALSE; }; + /*virtual*/ BOOL handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_rect_screen) override { return FALSE; }; + /*virtual*/ BOOL handleMiddleMouseDown(S32 x, S32 y, MASK mask) override { return FALSE; }; + /*virtual*/ BOOL handleMiddleMouseUp(S32 x, S32 y, MASK mask) override {return FALSE; }; + /*virtual*/ const std::string& getName() const override; + /*virtual*/ BOOL isView() const override { return FALSE; }; + + /*virtual*/ void screenPointToLocal(S32 screen_x, S32 screen_y, S32* local_x, S32* local_y) const override {}; + /*virtual*/ void localPointToScreen(S32 local_x, S32 local_y, S32* screen_x, S32* screen_y) const override {}; + /*virtual*/ BOOL hasMouseCapture() override { return gFocusMgr.getMouseCapture() == this; }; // Inherited from LLPluginClassMediaOwner - /*virtual*/ void handleMediaEvent(LLPluginClassMedia* plugin, LLPluginClassMediaOwner::EMediaEvent); - /*virtual*/ void handleCookieSet(LLPluginClassMedia* self, const std::string &cookie); + /*virtual*/ void handleMediaEvent(LLPluginClassMedia* plugin, LLPluginClassMediaOwner::EMediaEvent) override; // LLEditMenuHandler overrides - /*virtual*/ void cut(); - /*virtual*/ BOOL canCut() const; + /*virtual*/ void undo() override; + /*virtual*/ BOOL canUndo() const override; + + /*virtual*/ void redo() override; + /*virtual*/ BOOL canRedo() const override; + + /*virtual*/ void cut() override; + /*virtual*/ BOOL canCut() const override; - /*virtual*/ void copy(); - /*virtual*/ BOOL canCopy() const; + /*virtual*/ void copy() const override final; + /*virtual*/ BOOL canCopy() const override; - /*virtual*/ void paste(); - /*virtual*/ BOOL canPaste() const; + /*virtual*/ void paste() override; + /*virtual*/ BOOL canPaste() const override; + + /*virtual*/ void doDelete() override; + /*virtual*/ BOOL canDoDelete() const override; + + /*virtual*/ void selectAll() override; + /*virtual*/ BOOL canSelectAll() const override; void addObject(LLVOVolume* obj) ; void removeObject(LLVOVolume* obj) ; @@ -463,6 +469,7 @@ class LLViewerMediaImpl bool mNavigateServerRequest; bool mMediaSourceFailed; F32 mRequestedVolume; + F32 mPreviousVolume; bool mIsMuted; bool mNeedsMuteCheck; int mPreviousMediaState; @@ -472,7 +479,6 @@ class LLViewerMediaImpl S32 mProximity; F64 mProximityDistance; F64 mProximityCamera; - LLMimeDiscoveryResponder *mMimeTypeProbe; bool mMediaAutoPlay; std::string mMediaEntryURL; bool mInNearbyMediaList; // used by LLPanelNearbyMedia::refreshList() for performance reasons @@ -483,11 +489,15 @@ class LLViewerMediaImpl bool mTrustedBrowser; std::string mTarget; LLNotificationPtr mNotification; + bool mCleanBrowser; // force the creation of a clean browsing target with full options enabled + static std::vector sMimeTypesFailed; private: BOOL mIsUpdated ; std::list< LLVOVolume* > mObjectList ; + LLMimeDiscoveryResponder* mMimeProbe; + private: LLViewerMediaTexture *updatePlaceholderImage(); }; diff --git a/indra/newview/llviewermedia_streamingaudio.cpp b/indra/newview/llviewermedia_streamingaudio.cpp index de7bfc7675..5e72ab3480 100644 --- a/indra/newview/llviewermedia_streamingaudio.cpp +++ b/indra/newview/llviewermedia_streamingaudio.cpp @@ -64,20 +64,20 @@ void LLStreamingAudio_MediaPlugins::start(const std::string& url) if (!mMediaPlugin) // lazy-init the underlying media plugin { mMediaPlugin = initializeMedia("audio/mpeg"); // assumes that whatever media implementation supports mp3 also supports vorbis. - llinfos << "streaming audio mMediaPlugin is now " << mMediaPlugin << llendl; + LL_INFOS() << "streaming audio mMediaPlugin is now " << mMediaPlugin << LL_ENDL; } if(!mMediaPlugin) return; if (!url.empty()) { - llinfos << "Starting internet stream: " << url << llendl; + LL_INFOS() << "Starting internet stream: " << url << LL_ENDL; mURL = url; mMediaPlugin->loadURI ( url ); mMediaPlugin->start(); - llinfos << "Playing stream..." << llendl; + LL_INFOS() << "Playing stream..." << LL_ENDL; } else { - llinfos << "setting stream to NULL"<< llendl; + LL_INFOS() << "setting stream to NULL"<< LL_ENDL; mURL.clear(); mMediaPlugin->stop(); } @@ -85,7 +85,7 @@ void LLStreamingAudio_MediaPlugins::start(const std::string& url) void LLStreamingAudio_MediaPlugins::stop() { - llinfos << "Stopping internet stream." << llendl; + LL_INFOS() << "Stopping internet stream." << LL_ENDL; if(mMediaPlugin) { mMediaPlugin->stop(); @@ -101,12 +101,12 @@ void LLStreamingAudio_MediaPlugins::pause(int pause) if(pause) { - llinfos << "Pausing internet stream." << llendl; + LL_INFOS() << "Pausing internet stream." << LL_ENDL; mMediaPlugin->pause(); } else { - llinfos << "Unpausing internet stream." << llendl; + LL_INFOS() << "Unpausing internet stream." << LL_ENDL; mMediaPlugin->start(); } } @@ -162,7 +162,7 @@ LLPluginClassMedia* LLStreamingAudio_MediaPlugins::initializeMedia(const std::st { LLPluginClassMediaOwner* owner = NULL; S32 default_size = 1; // audio-only - be minimal, doesn't matter - LLPluginClassMedia* media_source = LLViewerMediaImpl::newSourceFromMediaType(media_type, owner, default_size, default_size); + LLPluginClassMedia* media_source = LLViewerMediaImpl::newSourceFromMediaType(media_type, owner, default_size, default_size, 1.0); if (media_source) { diff --git a/indra/newview/llviewermediafocus.cpp b/indra/newview/llviewermediafocus.cpp index 91a2dfafc2..e3b02acd4e 100644 --- a/indra/newview/llviewermediafocus.cpp +++ b/indra/newview/llviewermediafocus.cpp @@ -107,7 +107,7 @@ void LLViewerMediaFocus::setFocusFace(LLPointer objectp, S32 fac else { // This should never happen. - llwarns << "Can't find media entry for focused face" << llendl; + LL_WARNS() << "Can't find media entry for focused face" << LL_ENDL; } media_impl->focus(true); @@ -222,7 +222,7 @@ void LLViewerMediaFocus::setCameraZoom(LLViewerObject* object, LLVector3 normal, F32 aspect_ratio = getBBoxAspectRatio(bbox, normal, &height, &width, &depth); F32 camera_aspect = LLViewerCamera::getInstance()->getAspect(); - lldebugs << "normal = " << normal << ", aspect_ratio = " << aspect_ratio << ", camera_aspect = " << camera_aspect << llendl; + LL_DEBUGS() << "normal = " << normal << ", aspect_ratio = " << aspect_ratio << ", camera_aspect = " << camera_aspect << LL_ENDL; // We will normally use the side of the volume aligned with the short side of the screen (i.e. the height for // a screen in a landscape aspect ratio), however there is an edge case where the aspect ratio of the object is @@ -240,14 +240,14 @@ void LLViewerMediaFocus::setCameraZoom(LLViewerObject* object, LLVector3 normal, angle_of_view = llmax(0.1f, LLViewerCamera::getInstance()->getView() * LLViewerCamera::getInstance()->getAspect()); distance = width * 0.5 * padding_factor / tan(angle_of_view * 0.5f ); - lldebugs << "using width (" << width << "), angle_of_view = " << angle_of_view << ", distance = " << distance << llendl; + LL_DEBUGS() << "using width (" << width << "), angle_of_view = " << angle_of_view << ", distance = " << distance << LL_ENDL; } else { angle_of_view = llmax(0.1f, LLViewerCamera::getInstance()->getView()); distance = height * 0.5 * padding_factor / tan(angle_of_view * 0.5f ); - lldebugs << "using height (" << height << "), angle_of_view = " << angle_of_view << ", distance = " << distance << llendl; + LL_DEBUGS() << "using height (" << height << "), angle_of_view = " << angle_of_view << ", distance = " << distance << LL_ENDL; } distance += depth * 0.5; @@ -351,6 +351,18 @@ BOOL LLViewerMediaFocus::handleKey(KEY key, MASK mask, BOOL called_from_parent) return true; } +BOOL LLViewerMediaFocus::handleKeyUp(KEY key, MASK mask, BOOL called_from_parent) +{ + LLViewerMediaImpl* media_impl = getFocusedMediaImpl(); + if (media_impl) + { + media_impl->handleKeyUpHere(key, mask); + } + return true; +} + + + BOOL LLViewerMediaFocus::handleUnicodeChar(llwchar uni_char, BOOL called_from_parent) { LLViewerMediaImpl* media_impl = getFocusedMediaImpl(); @@ -364,12 +376,7 @@ BOOL LLViewerMediaFocus::handleScrollWheel(S32 x, S32 y, S32 clicks) LLViewerMediaImpl* media_impl = getFocusedMediaImpl(); if(media_impl && media_impl->hasMedia()) { - // the scrollEvent() API's x and y are not the same as handleScrollWheel's x and y. - // The latter is the position of the mouse at the time of the event - // The former is the 'scroll amount' in x and y, respectively. - // All we have for 'scroll amount' here is 'clicks'. - // We're also not passed the keyboard modifier mask, but we can get that from gKeyboard. - media_impl->getMediaPlugin()->scrollEvent(0, clicks, gKeyboard->currentMask(TRUE)); + media_impl->scrollWheel(x, y, 0, clicks, gKeyboard->currentMask(TRUE)); retval = TRUE; } return retval; @@ -434,7 +441,6 @@ void LLViewerMediaFocus::update() { mMediaControls.get()->setMediaFace(NULL, 0, NULL); } - } } @@ -452,7 +458,7 @@ F32 LLViewerMediaFocus::getBBoxAspectRatio(const LLBBox& bbox, const LLVector3& F32 dot1 = 0.f; F32 dot2 = 0.f; - lldebugs << "bounding box local size = " << bbox_max << ", local_normal = " << local_normal << llendl; + LL_DEBUGS() << "bounding box local size = " << bbox_max << ", local_normal = " << local_normal << LL_ENDL; // The largest component of the localized normal vector is the depth component // meaning that the other two are the legs of the rectangle. @@ -465,21 +471,21 @@ F32 LLViewerMediaFocus::getBBoxAspectRatio(const LLBBox& bbox, const LLVector3& if(XgtY && XgtZ) { - lldebugs << "x component of normal is longest, using y and z" << llendl; + LL_DEBUGS() << "x component of normal is longest, using y and z" << LL_ENDL; comp1.mV[VY] = bbox_max.mV[VY]; comp2.mV[VZ] = bbox_max.mV[VZ]; *depth = bbox_max.mV[VX]; } else if(!XgtY && YgtZ) { - lldebugs << "y component of normal is longest, using x and z" << llendl; + LL_DEBUGS() << "y component of normal is longest, using x and z" << LL_ENDL; comp1.mV[VX] = bbox_max.mV[VX]; comp2.mV[VZ] = bbox_max.mV[VZ]; *depth = bbox_max.mV[VY]; } else { - lldebugs << "z component of normal is longest, using x and y" << llendl; + LL_DEBUGS() << "z component of normal is longest, using x and y" << LL_ENDL; comp1.mV[VX] = bbox_max.mV[VX]; comp2.mV[VY] = bbox_max.mV[VY]; *depth = bbox_max.mV[VZ]; @@ -493,19 +499,19 @@ F32 LLViewerMediaFocus::getBBoxAspectRatio(const LLBBox& bbox, const LLVector3& *height = comp1.length(); *width = comp2.length(); - lldebugs << "comp1 = " << comp1 << ", height = " << *height << llendl; - lldebugs << "comp2 = " << comp2 << ", width = " << *width << llendl; + LL_DEBUGS() << "comp1 = " << comp1 << ", height = " << *height << LL_ENDL; + LL_DEBUGS() << "comp2 = " << comp2 << ", width = " << *width << LL_ENDL; } else { *height = comp2.length(); *width = comp1.length(); - lldebugs << "comp2 = " << comp2 << ", height = " << *height << llendl; - lldebugs << "comp1 = " << comp1 << ", width = " << *width << llendl; + LL_DEBUGS() << "comp2 = " << comp2 << ", height = " << *height << LL_ENDL; + LL_DEBUGS() << "comp1 = " << comp1 << ", width = " << *width << LL_ENDL; } - lldebugs << "returning " << (*width / *height) << llendl; + LL_DEBUGS() << "returning " << (*width / *height) << LL_ENDL; // Return the aspect ratio. return *width / *height; @@ -560,7 +566,7 @@ void LLViewerMediaFocus::focusZoomOnMedia(LLUUID media_id) if(normal.isNull()) { // If that didn't work, use the inverse of the camera "look at" axis, which should keep the camera pointed in the same direction. -// llinfos << "approximate face normal invalid, using camera direction." << llendl; +// LL_INFOS() << "approximate face normal invalid, using camera direction." << LL_ENDL; normal = LLViewerCamera::getInstance()->getAtAxis(); normal *= (F32)-1.0f; } @@ -603,3 +609,13 @@ LLUUID LLViewerMediaFocus::getControlsMediaID() return LLUUID::null; } + +bool LLViewerMediaFocus::wantsKeyUpKeyDown() const +{ + return true; +} + +bool LLViewerMediaFocus::wantsReturnKey() const +{ + return true; +} diff --git a/indra/newview/llviewermediafocus.h b/indra/newview/llviewermediafocus.h index f03dd8751e..0b2a64868e 100644 --- a/indra/newview/llviewermediafocus.h +++ b/indra/newview/llviewermediafocus.h @@ -56,6 +56,7 @@ class LLViewerMediaFocus : /*virtual*/ bool getFocus(); /*virtual*/ BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); + /*virtual*/ BOOL handleKeyUp(KEY key, MASK mask, BOOL called_from_parent); /*virtual*/ BOOL handleUnicodeChar(llwchar uni_char, BOOL called_from_parent); BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); @@ -87,6 +88,10 @@ class LLViewerMediaFocus : // Return the ID of the media instance the controls are currently attached to (either focus or hover). LLUUID getControlsMediaID(); + // The MoaP object wants keyup and keydown events. Overridden to return true. + virtual bool wantsKeyUpKeyDown() const; + virtual bool wantsReturnKey() const; + protected: /*virtual*/ void onFocusReceived(); /*virtual*/ void onFocusLost(); diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 9bb50d85da..c28ef2fcc1 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -34,107 +34,81 @@ #include "llviewermenu.h" // linden library includes +#include "lfidbearer.h" #include "llanimationstates.h" // For ANIM_AGENT_AWAY #include "llavatarnamecache.h" // IDEVO +#include "llexperiencecache.h" #include "llinventorypanel.h" #include "llnotifications.h" #include "llnotificationsutil.h" #include "llfeaturemanager.h" #include "llsecondlifeurls.h" +#include "llurlaction.h" // -#include "llfloaterexploreanimations.h" -#include "llfloaterexploresounds.h" #include "llfloaterblacklist.h" // #include "statemachine/aifilepicker.h" // newview includes +#include "lffloaterinvpanel.h" +#include "lfsimfeaturehandler.h" #include "llagent.h" +#include "llagentbenefits.h" #include "llagentcamera.h" #include "llappearancemgr.h" #include "llagentwearables.h" -#include "jcfloaterareasearch.h" -#include "lfsimfeaturehandler.h" - #include "llagentpilot.h" +#include "llavatarpropertiesprocessor.h" +#include "llcallingcard.h" #include "llcompilequeue.h" #include "llconsole.h" #include "lldebugview.h" #include "llenvmanager.h" #include "llfirstuse.h" -#include "llfloaterabout.h" -#include "llfloateractivespeakers.h" #include "llfloateravatarlist.h" #include "llfloateravatartextures.h" -#include "llfloaterbeacons.h" -#include "llfloaterbuildoptions.h" -#include "llfloaterbump.h" #include "llfloaterbuy.h" #include "llfloaterbuycontents.h" #include "llfloaterbuycurrency.h" #include "llfloaterbuyland.h" #include "llfloaterchat.h" #include "llfloatercustomize.h" -#include "llfloaterdaycycle.h" #include "llfloaterdirectory.h" #include "llfloatereditui.h" -#include "llfloaterchatterbox.h" +#include "llfloaterexperienceprofile.h" +#include "llfloaterexperiences.h" #include "llfloaterfonttest.h" -#include "llfloatergesture.h" #include "llfloatergodtools.h" #include "llfloaterhtmlcurrency.h" -#include "llfloaterhud.h" -#include "llfloaterinspect.h" -#include "llfloaterinventory.h" -#include "llfloaterlagmeter.h" #include "llfloaterland.h" -#include "llfloaterlandholdings.h" -#include "llfloatermap.h" +#include "llfloatermarketplacelistings.h" #include "llfloatermute.h" #include "llfloateropenobject.h" -#include "llfloateroutbox.h" #include "llfloaterpathfindingcharacters.h" #include "llfloaterpathfindinglinksets.h" -#include "llfloaterperms.h" -#include "llfloaterpostprocess.h" -#include "llfloaterpreference.h" #include "llfloaterregiondebugconsole.h" #include "llfloaterregioninfo.h" #include "llfloaterreporter.h" -#include "llfloaterscriptdebug.h" -#include "llfloaterscriptlimits.h" #include "llfloatersettingsdebug.h" - -#include "llfloaterenvsettings.h" -#include "llfloaterstats.h" -#include "llfloaterteleporthistory.h" #include "llfloatertest.h" #include "llfloatertools.h" -#include "llfloatervoiceeffect.h" -#include "llfloaterwater.h" -#include "llfloaterwebcontent.h" -#include "llfloaterwindlight.h" #include "llfloaterworldmap.h" #include "llfloatermemleak.h" #include "llframestats.h" -#include "llgivemoney.h" #include "llavataractions.h" +#include "llgivemoney.h" +#include "llgroupactions.h" #include "llgroupmgr.h" #include "llhoverview.h" #include "llhudeffecttrail.h" #include "llhudmanager.h" -#include "llimview.h" -#include "llinventorybridge.h" -#include "llinventorydefines.h" #include "llinventoryfunctions.h" -#include "llmakeoutfitdialog.h" +#include "llmarketplacefunctions.h" #include "llmimetypes.h" -#include "llmenucommands.h" #include "llmenuoptionpathfindingrebakenavmesh.h" -#include "llmoveview.h" #include "llmutelist.h" #include "llnotify.h" -#include "llpanellogin.h" +#include "llpanelexperiences.h" #include "llparcel.h" #include "llregioninfomodel.h" #include "llselectmgr.h" @@ -142,33 +116,31 @@ #include "lltextureview.h" #include "lltoolbar.h" #include "lltoolcomp.h" +#include "lltoolgrab.h" #include "lltoolmgr.h" #include "lltoolpie.h" #include "lltoolselectland.h" +#include "lltrans.h" #include "lluictrlfactory.h" -#include "lluserauth.h" #include "llvelocitybar.h" #include "llviewercamera.h" #include "llviewergenericmessage.h" +#include "llviewerjoystick.h" #include "llviewertexturelist.h" // gTextureList #include "llviewermenufile.h" // init_menu_file() #include "llviewermessage.h" #include "llviewernetwork.h" #include "llviewerobjectlist.h" #include "llviewerparcelmgr.h" -#include "llviewerstats.h" #include "llvoavatarself.h" #include "llworld.h" #include "llworldmap.h" #include "pipeline.h" -#include "llviewerjoystick.h" -#include "llwaterparammanager.h" -#include "llwlanimator.h" -#include "llwlparammanager.h" -#include "llfloatercamera.h" #include "llfloaternotificationsconsole.h" // +#include "jcfloaterareasearch.h" +#include "lltexteditor.h" // Initialize the text editor menu listeners in here #include "llfloatermessagelog.h" #include "shfloatermediaticker.h" #include "llpacketring.h" @@ -176,21 +148,15 @@ // #include "scriptcounter.h" -#include "llfloaterdisplayname.h" -#include "floaterao.h" -#include "slfloatermediafilter.h" #include "llviewerobjectbackup.h" #include "llagentui.h" -#include "lltoolgrab.h" #include "llpathfindingmanager.h" -#include #include "lltexturecache.h" #include "llvovolume.h" #include "hippogridmanager.h" - -void toggle_search_floater(); +#include "wlfPanel_AdvSettings.h" using namespace LLOldEvents; using namespace LLAvatarAppearanceDefines; @@ -206,9 +172,10 @@ void init_debug_rendering_menu(LLMenuGL* menu); void init_debug_ui_menu(LLMenuGL* menu); void init_debug_xui_menu(LLMenuGL* menu); void init_debug_avatar_menu(LLMenuGL* menu); -// [RLVa:KB] +// [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a) +#include "rlvactions.h" #include "rlvhandler.h" -#include "rlvfloaterbehaviour.h" +#include "rlvfloaters.h" #include "rlvlocks.h" void init_debug_rlva_menu(LLMenuGL* menu); // [/RLVa:KB] @@ -242,39 +209,37 @@ extern AIHTTPView* gHttpView; // Globals // -LLMenuBarGL *gMenuBarView = NULL; -LLViewerMenuHolderGL *gMenuHolder = NULL; -LLMenuGL *gPopupMenuView = NULL; -LLMenuBarGL *gLoginMenuBarView = NULL; +LLMenuBarGL *gMenuBarView = nullptr; +LLViewerMenuHolderGL *gMenuHolder = nullptr; +LLMenuBarGL *gLoginMenuBarView = nullptr; // Pie menus -LLPieMenu *gPieSelf = NULL; -LLPieMenu *gPieAvatar = NULL; -LLPieMenu *gPieObject = NULL; -LLPieMenu *gPieAttachment = NULL; -LLPieMenu *gPieLand = NULL; +LLContextMenu *gPieSelf = nullptr; +LLContextMenu *gPieAvatar = nullptr; +LLContextMenu *gPieObject = nullptr; +LLContextMenu *gPieAttachment = nullptr; +LLContextMenu *gPieLand = nullptr; // local constants const std::string CLIENT_MENU_NAME("Advanced"); const std::string SERVER_MENU_NAME("Admin"); -const std::string SAVE_INTO_INVENTORY("Save Object Back to My Inventory"); const std::string SAVE_INTO_TASK_INVENTORY("Save Object Back to Object Contents"); -LLMenuGL* gAttachSubMenu = NULL; -LLMenuGL* gDetachSubMenu = NULL; -LLMenuGL* gTakeOffClothes = NULL; -LLMenuGL* gMeshesAndMorphsMenu = NULL; -LLPieMenu* gPieRate = NULL; -LLPieMenu* gAttachScreenPieMenu = NULL; -LLPieMenu* gAttachPieMenu = NULL; -LLPieMenu* gAttachBodyPartPieMenus[8]; -LLPieMenu* gDetachPieMenu = NULL; -LLPieMenu* gDetachScreenPieMenu = NULL; -LLPieMenu* gDetachBodyPartPieMenus[8]; - -LLMenuItemCallGL* gAFKMenu = NULL; -LLMenuItemCallGL* gBusyMenu = NULL; +LLMenuGL* gAttachSubMenu = nullptr; +LLMenuGL* gDetachSubMenu = nullptr; +LLMenuGL* gTakeOffClothes = nullptr; +LLMenuGL* gMeshesAndMorphsMenu = nullptr; +LLContextMenu* gPieRate = nullptr; +LLContextMenu* gAttachScreenPieMenu = nullptr; +LLContextMenu* gAttachPieMenu = nullptr; +LLContextMenu* gAttachPieMenu2 = nullptr; +LLContextMenu* gDetachPieMenu = nullptr; +LLContextMenu* gDetachPieMenu2 = nullptr; +LLContextMenu* gDetachScreenPieMenu = nullptr; + +LLMenuItemCallGL* gAFKMenu = nullptr; +LLMenuItemCallGL* gBusyMenu = nullptr; typedef LLMemberListener view_listener_t; @@ -380,10 +345,6 @@ void set_current_pose(std::string anim) gAgent.sendAnimationRequest(current_pose, ANIM_REQUEST_START); gAgent.sendAgentSetAppearance(); } -void handle_pose_stand(void*) -{ - set_current_pose("038fcec9-5ebd-8a8e-0e2e-6e71a0a1ac53"); -} void handle_pose_stand_stop(void*) { if (on_pose_stand) @@ -394,24 +355,14 @@ void handle_pose_stand_stop(void*) gAgent.sendAgentSetAppearance(); } } -void cleanup_pose_stand(void) +void cleanup_pose_stand() { - handle_pose_stand_stop(NULL); + handle_pose_stand_stop(nullptr); } -void handle_toggle_pose(void* userdata) { - if(current_pose.isNull()) - handle_pose_stand(userdata); - else - handle_pose_stand_stop(userdata); -} - -BOOL handle_check_pose(void* userdata) { - return current_pose.notNull(); -} +BOOL handle_check_pose(void* userdata) { return current_pose.notNull(); } -void handle_close_all_notifications(void*); void handle_open_message_log(void*); // @@ -496,6 +447,7 @@ void handle_morph_load_obj(void*); void handle_debug_avatar_textures(void*); void handle_dump_region_object_cache(void*); +void menu_toggle_double_click_control(void*); BOOL menu_ui_enabled(void *user_data); BOOL menu_check_control( void* user_data); void menu_toggle_variable( void* user_data ); @@ -504,7 +456,6 @@ BOOL enable_land_selected( void* ); BOOL enable_more_than_one_selected(void* ); BOOL enable_selection_you_own_all(void*); BOOL enable_selection_you_own_one(void*); -BOOL enable_save_into_inventory(void*); BOOL enable_save_into_task_inventory(void*); BOOL enable_detach(const LLSD& = LLSD()); @@ -519,21 +470,25 @@ void region_change(); void parse_simulator_features(); void custom_selected(void* user_data); + +void advanced_toggle_wireframe(void*); +BOOL advanced_check_wireframe(void*); + void reset_vertex_buffers(void *user_data) { gPipeline.clearRebuildGroups(); gPipeline.resetVertexBuffers(); } -class LLMenuParcelObserver : public LLParcelObserver +class LLMenuParcelObserver final : public LLParcelObserver { public: LLMenuParcelObserver(); ~LLMenuParcelObserver(); - virtual void changed(); + void changed() override; }; -static LLMenuParcelObserver* gMenuParcelObserver = NULL; +static LLMenuParcelObserver* gMenuParcelObserver = nullptr; LLMenuParcelObserver::LLMenuParcelObserver() { @@ -547,9 +502,9 @@ LLMenuParcelObserver::~LLMenuParcelObserver() void LLMenuParcelObserver::changed() { - gMenuHolder->childSetEnabled("Land Buy Pass", LLPanelLandGeneral::enableBuyPass(NULL)); + gMenuHolder->childSetEnabled("Land Buy Pass", LLPanelLandGeneral::enableBuyPass(nullptr)); - BOOL buyable = enable_buy_land(NULL); + BOOL buyable = enable_buy_land(nullptr); gMenuHolder->childSetEnabled("Land Buy", buyable); gMenuHolder->childSetEnabled("Buy Land...", buyable); } @@ -601,6 +556,76 @@ void set_underclothes_menu_options() static std::vector > sMenus; +void build_pie_menus() +{ + if (gPieSelf) delete gPieSelf; + gPieSelf = LLUICtrlFactory::getInstance()->buildContextMenu("menu_pie_self.xml", gMenuHolder); + + // TomY TODO: what shall we do about these? + gDetachScreenPieMenu = gMenuHolder->getChild("Object Detach HUD", true); + gDetachPieMenu = gMenuHolder->getChild("Object Detach", true); + gDetachPieMenu2 = gMenuHolder->getChild("Object Detach More", true); + + if (gPieAvatar) delete gPieAvatar; + gPieAvatar = LLUICtrlFactory::getInstance()->buildContextMenu("menu_pie_avatar.xml", gMenuHolder); + + if (gPieObject) delete gPieObject; + gPieObject = LLUICtrlFactory::getInstance()->buildContextMenu("menu_pie_object.xml", gMenuHolder); + + gAttachScreenPieMenu = gMenuHolder->getChild("Object Attach HUD"); + gAttachPieMenu = gMenuHolder->getChild("Object Attach"); + gAttachPieMenu2 = gMenuHolder->getChild("Object Attach More"); + gPieRate = gMenuHolder->getChild("Rate Menu"); + + if (gPieAttachment) delete gPieAttachment; + gPieAttachment = LLUICtrlFactory::getInstance()->buildContextMenu("menu_pie_attachment.xml", gMenuHolder); + + if (gPieLand) delete gPieLand; + gPieLand = LLUICtrlFactory::getInstance()->buildContextMenu("menu_pie_land.xml", gMenuHolder); +} + +void rebuild_context_menus() +{ + llassert_always(gMenuHolder); + if (!gMenuHolder) return; // This should never happen, if it does, don't do anything, menus haven't been built yet or were destroyed. + gMenuHolder->hideMenus(); + build_pie_menus(); + if (!gAgentAvatarp) return; // The agent's avatar isn't here yet, don't bother with the dynamic attach/detach submenus. + gAgentAvatarp->buildContextMenus(); +} + +void set_merchant_SLM_menu() +{ + // DD-170 : SLM Alpha and Beta program : for the moment, we always show the SLM menu and + // tools so that all merchants can try out the UI, even if not migrated. + // *TODO : Keep SLM UI hidden for non migrated merchant in released viewer + gMenuHolder->getChild("MarketplaceListings")->setVisible(TRUE); + gToolBar->getChild("marketplace_listings_btn")->setEnabled(true); +} + +void check_merchant_status(bool force) +{ + if (!gSavedSettings.getBOOL("InventoryOutboxDisplayBoth")) + { + if (force) + { + // Reset the SLM status: we actually want to check again, that's the point of calling check_merchant_status() + LLMarketplaceData::instance().setSLMStatus(MarketplaceStatusCodes::MARKET_PLACE_NOT_INITIALIZED); + } + // Hide SLM related menu item + gMenuHolder->getChild("MarketplaceListings")->setVisible(FALSE); + + // Also disable the toolbar button for Marketplace Listings + gToolBar->getChild("marketplace_listings_btn")->setEnabled(false); + + if (!gAgent.getRegionCapability("DirectDelivery").empty()) + { + // Launch an SLM test connection to get the merchant status + LLMarketplaceData::instance().initializeSLM(boost::bind(&set_merchant_SLM_menu)); + } + } +} + void init_menus() { S32 top = gViewerWindow->getRootView()->getRect().getHeight(); @@ -619,52 +644,18 @@ void init_menus() // Initialize actions initialize_menus(); - /// - /// Popup menu - /// - /// The popup menu is now populated by the show_context_menu() - /// method. - - gPopupMenuView = new LLMenuGL( "Popup" ); - gPopupMenuView->setVisible( FALSE ); - gMenuHolder->addChild( gPopupMenuView ); - /// /// Pie menus /// - gPieSelf = LLUICtrlFactory::getInstance()->buildPieMenu("menu_pie_self.xml", gMenuHolder); - - // TomY TODO: what shall we do about these? - gDetachScreenPieMenu = gMenuHolder->getChild("Object Detach HUD", true); - gDetachPieMenu = gMenuHolder->getChild("Object Detach", true); - - gPieAvatar = LLUICtrlFactory::getInstance()->buildPieMenu("menu_pie_avatar.xml", gMenuHolder); + build_pie_menus(); + gSavedSettings.getControl("LiruUseContextMenus")->getSignal()->connect(boost::bind(rebuild_context_menus)); - gPieObject = LLUICtrlFactory::getInstance()->buildPieMenu("menu_pie_object.xml", gMenuHolder); - - gAttachScreenPieMenu = gMenuHolder->getChild("Object Attach HUD"); - gAttachPieMenu = gMenuHolder->getChild("Object Attach"); - gPieRate = gMenuHolder->getChild("Rate Menu"); - - gPieAttachment = LLUICtrlFactory::getInstance()->buildPieMenu("menu_pie_attachment.xml", gMenuHolder); - - gPieLand = LLUICtrlFactory::getInstance()->buildPieMenu("menu_pie_land.xml", gMenuHolder); /// /// set up the colors /// LLColor4 color; - LLColor4 pie_color = gColors.getColor("PieMenuBgColor"); - gPieSelf->setBackgroundColor( pie_color ); - gPieAvatar->setBackgroundColor( pie_color ); - gPieObject->setBackgroundColor( pie_color ); - gPieAttachment->setBackgroundColor( pie_color ); - gPieLand->setBackgroundColor( pie_color ); - - color = gColors.getColor( "MenuPopupBgColor" ); - gPopupMenuView->setBackgroundColor( color ); - // If we are not in production, use a different color to make it apparent. if (LLViewerLogin::getInstance()->isInProductionGrid()) { @@ -690,15 +681,15 @@ void init_menus() gViewerWindow->setMenuBackgroundColor(false, LLViewerLogin::getInstance()->isInProductionGrid()); - // Assume L$10 for now, the server will tell us the real cost at login - const std::string upload_cost("10"); - std::string fee = gHippoGridManager->getConnectedGrid()->getCurrencySymbol() + "10"; - gMenuHolder->childSetLabelArg("Upload Image", "[UPLOADFEE]", fee); - gMenuHolder->childSetLabelArg("Upload Sound", "[UPLOADFEE]", fee); - gMenuHolder->childSetLabelArg("Upload Animation", "[UPLOADFEE]", fee); - gMenuHolder->childSetLabelArg("Bulk Upload", "[UPLOADFEE]", fee); - gMenuHolder->childSetLabelArg("Buy and Sell L$...", "[CURRENCY]", - gHippoGridManager->getConnectedGrid()->getCurrencySymbol()); + std::string symbol = gHippoGridManager->getConnectedGrid()->getCurrencySymbol(); + auto& benefits = LLAgentBenefitsMgr::current(); + const std::string texture_upload_cost_str = symbol + fmt::to_string(benefits.getTextureUploadCost()); + const std::string sound_upload_cost_str = symbol + fmt::to_string(benefits.getSoundUploadCost()); + const std::string animation_upload_cost_str = symbol + fmt::to_string(benefits.getAnimationUploadCost()); + gMenuHolder->childSetLabelArg("Upload Image", "[UPLOADFEE]", texture_upload_cost_str); + gMenuHolder->childSetLabelArg("Upload Sound", "[UPLOADFEE]", sound_upload_cost_str); + gMenuHolder->childSetLabelArg("Upload Animation", "[UPLOADFEE]", animation_upload_cost_str); + gMenuHolder->childSetLabelArg("Buy and Sell L$...", "[CURRENCY]", symbol); gAFKMenu = gMenuBarView->getChild("Set Away", TRUE); gBusyMenu = gMenuBarView->getChild("Set Busy", TRUE); @@ -710,13 +701,13 @@ void init_menus() /*LLMenuGL* sub = new LLMenuGL("Pose Stand..."); menu->addChild(sub); - sub->addChild(new LLMenuItemCallGL( "Legs Together Arms Out", &handle_pose_stand_ltao, NULL)); - sub->addChild(new LLMenuItemCallGL( "Legs Together Arms Half", &handle_pose_stand_ltah, NULL)); - sub->addChild(new LLMenuItemCallGL( "Legs Together Arms Down", &handle_pose_stand_ltad, NULL)); - sub->addChild(new LLMenuItemCallGL( "Legs Out Arms Up", &handle_pose_stand_loau, NULL)); - sub->addChild(new LLMenuItemCallGL( "Legs Out Arms Out", &handle_pose_stand_loao, NULL)); - sub->addChild(new LLMenuItemCallGL( "Legs Half Arms Out", &handle_pose_stand_lhao, NULL)); - sub->addChild(new LLMenuItemCallGL( "Stop Pose Stand", &handle_pose_stand_stop, NULL)); + sub->addChild(new LLMenuItemCallGL( "Legs Together Arms Out", &handle_pose_stand_ltao, nullptr)); + sub->addChild(new LLMenuItemCallGL( "Legs Together Arms Half", &handle_pose_stand_ltah, nullptr)); + sub->addChild(new LLMenuItemCallGL( "Legs Together Arms Down", &handle_pose_stand_ltad, nullptr)); + sub->addChild(new LLMenuItemCallGL( "Legs Out Arms Up", &handle_pose_stand_loau, nullptr)); + sub->addChild(new LLMenuItemCallGL( "Legs Out Arms Out", &handle_pose_stand_loao, nullptr)); + sub->addChild(new LLMenuItemCallGL( "Legs Half Arms Out", &handle_pose_stand_lhao, nullptr)); + sub->addChild(new LLMenuItemCallGL( "Stop Pose Stand", &handle_pose_stand_stop, nullptr)); // ------------------------------------------------------*/ // TomY TODO convert these two @@ -747,7 +738,10 @@ void init_menus() menu = new LLMenuGL(CLIENT_MENU_NAME); menu->setCanTearOff(FALSE); - menu->addChild(new LLMenuItemCallGL("Debug Settings...", handle_singleton_toggle, NULL, NULL)); + menu->addChild(new LLMenuItemCallGL("Debug Settings...", handle_singleton_toggle, nullptr, nullptr)); + // Debugging view for unified notifications: CTRL-SHIFT-5 + menu->addChild(new LLMenuItemCallGL("Notifications Console...", handle_show_notifications_console, nullptr, nullptr, '5', MASK_CONTROL|MASK_SHIFT)); + menu->addChild(new LLMenuItemCallGL("Load from XML...", handle_load_from_xml)); gLoginMenuBarView->addChild(menu); menu->updateParent(LLMenuGL::sMenuContainer); @@ -763,6 +757,9 @@ void init_menus() gMenuHolder->addChild(gLoginMenuBarView); + // Singu Note: Initialize common ScrollListMenus here + LFIDBearer::buildMenus(); + LLView* ins = gMenuBarView->getChildView("insert_world", true, false); ins->setVisible(false); ins = gMenuBarView->getChildView("insert_agent", true, false); @@ -775,14 +772,14 @@ void init_menus() ins = gMenuBarView->getChildView("insert_admin", true, false); ins->setVisible(false);*/ - LLEnvManagerNew::instance().setRegionChangeCallback(®ion_change); + gAgent.addRegionChangedCallback(®ion_change); } void init_client_menu(LLMenuGL* menu) { - LLMenuGL* sub_menu = NULL; + LLMenuGL* sub_menu = nullptr; { @@ -792,20 +789,20 @@ void init_client_menu(LLMenuGL* menu) menu->addChild(sub); sub->addChild(new LLMenuItemCheckGL("Frame Console", &toggle_visibility, - NULL, + nullptr, &get_visibility, (void*)gDebugView->mFrameStatView, '2', MASK_CONTROL|MASK_SHIFT ) ); sub->addChild(new LLMenuItemCheckGL("Texture Console", &toggle_visibility, - NULL, + nullptr, &get_visibility, (void*)gTextureView, '3', MASK_CONTROL|MASK_SHIFT ) ); LLView* debugview = gDebugView->mDebugConsolep; sub->addChild(new LLMenuItemCheckGL("Debug Console", &toggle_visibility, - NULL, + nullptr, &get_visibility, debugview, '4', MASK_CONTROL|MASK_SHIFT ) ); @@ -814,30 +811,30 @@ void init_client_menu(LLMenuGL* menu) { sub->addChild(new LLMenuItemCheckGL("Texture Size Console", &toggle_visibility, - NULL, + nullptr, &get_visibility, (void*)gTextureSizeView, '5', MASK_CONTROL|MASK_SHIFT ) ); sub->addChild(new LLMenuItemCheckGL("Texture Category Console", &toggle_visibility, - NULL, + nullptr, &get_visibility, (void*)gTextureCategoryView, '6', MASK_CONTROL|MASK_SHIFT ) ); } sub->addChild(new LLMenuItemCheckGL("HTTP Console", - &AIHTTPView::toggle_visibility, - NULL, + &toggle_visibility, + nullptr, &get_visibility, (void*)gHttpView, '7', MASK_CONTROL|MASK_SHIFT ) ); - sub->addChild(new LLMenuItemCheckGL("Region Debug Console", handle_singleton_toggle, NULL, handle_singleton_check,NULL,'`', MASK_CONTROL|MASK_SHIFT)); + sub->addChild(new LLMenuItemCheckGL("Region Debug Console", handle_singleton_toggle, nullptr, handle_singleton_check,nullptr,'`', MASK_CONTROL|MASK_SHIFT)); sub->addChild(new LLMenuItemCheckGL("Fast Timers", &toggle_visibility, - NULL, + nullptr, &get_visibility, (void*)gDebugView->mFastTimerView, '9', MASK_CONTROL|MASK_SHIFT ) ); @@ -846,25 +843,25 @@ void init_client_menu(LLMenuGL* menu) // Debugging view for unified notifications sub->addChild(new LLMenuItemCallGL("Notifications Console...", - &handle_show_notifications_console, NULL, NULL, '5', MASK_CONTROL|MASK_SHIFT )); + &handle_show_notifications_console, nullptr, nullptr, '5', MASK_CONTROL|MASK_SHIFT )); sub->addSeparator(); sub->addChild(new LLMenuItemCallGL("Region Info to Debug Console", - &handle_region_dump_settings, NULL)); + &handle_region_dump_settings, nullptr)); sub->addChild(new LLMenuItemCallGL("Group Info to Debug Console", - &handle_dump_group_info, NULL, NULL)); + &handle_dump_group_info, nullptr, nullptr)); sub->addChild(new LLMenuItemCallGL("Capabilities Info to Debug Console", - &handle_dump_capabilities_info, NULL, NULL)); + &handle_dump_capabilities_info, nullptr, nullptr)); sub->createJumpKeys(); } // neither of these works particularly well at the moment /*menu->addChild(new LLMenuItemCallGL( "Reload UI XML", &reload_ui, - NULL, NULL) );*/ + nullptr, nullptr) );*/ /*menu->addChild(new LLMenuItemCallGL("Reload settings/colors", - &handle_reload_settings, NULL, NULL));*/ + &handle_reload_settings, nullptr, nullptr));*/ menu->addChild(new LLMenuItemCallGL("Reload personal setting overrides", &reload_personal_settings_overrides)); @@ -873,7 +870,7 @@ void init_client_menu(LLMenuGL* menu) sub_menu->setCanTearOff(TRUE); sub_menu->addChild(new LLMenuItemCheckGL("Velocity", &toggle_visibility, - NULL, + nullptr, &get_visibility, (void*)gVelocityBar)); @@ -888,25 +885,25 @@ void init_client_menu(LLMenuGL* menu) menu->addChild(new LLMenuItemCheckGL( "High-res Snapshot", &menu_toggle_control, - NULL, + nullptr, &menu_check_control, (void*)"HighResSnapshot")); menu->addChild(new LLMenuItemCheckGL( "Quiet Snapshots to Disk", &menu_toggle_control, - NULL, + nullptr, &menu_check_control, (void*)"QuietSnapshotsToDisk")); menu->addChild(new LLMenuItemCheckGL("Show Mouselook Crosshairs", &menu_toggle_control, - NULL, + nullptr, &menu_check_control, (void*)"ShowCrosshairs")); menu->addChild(new LLMenuItemCheckGL("Debug Permissions", &menu_toggle_control, - NULL, + nullptr, &menu_check_control, (void*)"DebugPermissions")); @@ -918,7 +915,7 @@ void init_client_menu(LLMenuGL* menu) { menu->addChild(new LLMenuItemCheckGL("Hacked Godmode", &handle_toggle_hacked_godmode, - NULL, + nullptr, &check_toggle_hacked_godmode, (void*)"HackedGodmode")); } @@ -927,7 +924,7 @@ void init_client_menu(LLMenuGL* menu) menu->addChild(new LLMenuItemCallGL("Clear Group Cache", LLGroupMgr::debugClearAllGroups)); - menu->addChild(new LLMenuItemCheckGL("Use Web Map Tiles", menu_toggle_control, NULL, menu_check_control, (void*)"UseWebMapTiles")); + menu->addChild(new LLMenuItemCheckGL("Use Web Map Tiles", menu_toggle_control, nullptr, menu_check_control, (void*)"UseWebMapTiles")); menu->addSeparator(); @@ -942,15 +939,13 @@ void init_client_menu(LLMenuGL* menu) menu->addChild(sub_menu); // [RLVa:KB] - Checked: 2009-07-08 (RLVa-1.0.0e) | Modified: RLVa-0.2.1b | OK - #ifdef RLV_ADVANCED_MENU - sub_menu = new LLMenuGL("RLVa Embedded"); - init_debug_rlva_menu(sub_menu); - menu->addChild(sub_menu); - // Top Level Menu as well - sub_menu = new LLMenuGL("RLVa Main"); - init_debug_rlva_menu(sub_menu); - gMenuBarView->addChild(sub_menu); - #endif // RLV_ADVANCED_MENU + sub_menu = new LLMenuGL("RLVa Embedded"); + init_debug_rlva_menu(sub_menu); + menu->addChild(sub_menu); + // Top Level Menu as well + sub_menu = new LLMenuGL("RLVa Main"); + init_debug_rlva_menu(sub_menu); + gMenuBarView->addChild(sub_menu); // [/RLVa:KB] sub_menu = new LLMenuGL("UI"); @@ -969,67 +964,67 @@ void init_client_menu(LLMenuGL* menu) menu->addChild(sub_menu); { - LLMenuGL* sub = NULL; + LLMenuGL* sub = nullptr; sub = new LLMenuGL("Network"); sub->setCanTearOff(TRUE); - sub->addChild(new LLMenuItemCallGL( "Message Log", &handle_open_message_log, NULL)); + sub->addChild(new LLMenuItemCallGL("Message Log", handle_open_message_log, nullptr)); sub->addChild(new LLMenuItemCallGL("Enable Message Log", - &handle_viewer_enable_message_log, NULL)); + &handle_viewer_enable_message_log, nullptr)); sub->addChild(new LLMenuItemCallGL("Disable Message Log", - &handle_viewer_disable_message_log, NULL)); + &handle_viewer_disable_message_log, nullptr)); sub->addSeparator(); sub->addChild(new LLMenuItemCheckGL("Velocity Interpolate Objects", &velocity_interpolate, - NULL, + nullptr, &menu_check_control, (void*)"VelocityInterpolate")); sub->addChild(new LLMenuItemCheckGL("Ping Interpolate Object Positions", &menu_toggle_control, - NULL, + nullptr, &menu_check_control, (void*)"PingInterpolate")); sub->addSeparator(); sub->addChild(new LLMenuItemCallGL("Drop a Packet", - &drop_packet, NULL, NULL, + &drop_packet, nullptr, nullptr, 'L', MASK_ALT | MASK_CONTROL)); menu->addChild( sub ); sub->createJumpKeys(); } { - LLMenuGL* sub = NULL; + LLMenuGL* sub = nullptr; sub = new LLMenuGL("Recorder"); sub->setCanTearOff(TRUE); - sub->addChild(new LLMenuItemCheckGL("Full Session Logging", &menu_toggle_control, NULL, &menu_check_control, (void*)"StatsSessionTrackFrameStats")); + sub->addChild(new LLMenuItemCheckGL("Full Session Logging", &menu_toggle_control, nullptr, &menu_check_control, (void*)"StatsSessionTrackFrameStats")); - sub->addChild(new LLMenuItemCallGL("Start Logging", &LLFrameStats::startLogging, NULL)); - sub->addChild(new LLMenuItemCallGL("Stop Logging", &LLFrameStats::stopLogging, NULL)); - sub->addChild(new LLMenuItemCallGL("Log 10 Seconds", &LLFrameStats::timedLogging10, NULL)); - sub->addChild(new LLMenuItemCallGL("Log 30 Seconds", &LLFrameStats::timedLogging30, NULL)); - sub->addChild(new LLMenuItemCallGL("Log 60 Seconds", &LLFrameStats::timedLogging60, NULL)); + sub->addChild(new LLMenuItemCallGL("Start Logging", &LLFrameStats::startLogging, nullptr)); + sub->addChild(new LLMenuItemCallGL("Stop Logging", &LLFrameStats::stopLogging, nullptr)); + sub->addChild(new LLMenuItemCallGL("Log 10 Seconds", &LLFrameStats::timedLogging10, nullptr)); + sub->addChild(new LLMenuItemCallGL("Log 30 Seconds", &LLFrameStats::timedLogging30, nullptr)); + sub->addChild(new LLMenuItemCallGL("Log 60 Seconds", &LLFrameStats::timedLogging60, nullptr)); sub->addSeparator(); - sub->addChild(new LLMenuItemCallGL("Start Playback", &LLAgentPilot::startPlayback, NULL)); - sub->addChild(new LLMenuItemCallGL("Stop Playback", &LLAgentPilot::stopPlayback, NULL)); + sub->addChild(new LLMenuItemCallGL("Start Playback", &LLAgentPilot::startPlayback, nullptr)); + sub->addChild(new LLMenuItemCallGL("Stop Playback", &LLAgentPilot::stopPlayback, nullptr)); sub->addChild(new LLMenuItemToggleGL("Loop Playback", &LLAgentPilot::sLoop) ); - sub->addChild(new LLMenuItemCallGL("Start Record", &LLAgentPilot::startRecord, NULL)); - sub->addChild(new LLMenuItemCallGL("Stop Record", &LLAgentPilot::saveRecord, NULL)); + sub->addChild(new LLMenuItemCallGL("Start Record", &LLAgentPilot::startRecord, nullptr)); + sub->addChild(new LLMenuItemCallGL("Stop Record", &LLAgentPilot::saveRecord, nullptr)); menu->addChild( sub ); sub->createJumpKeys(); } { - LLMenuGL* sub = NULL; + LLMenuGL* sub = nullptr; sub = new LLMenuGL("Media"); sub->setCanTearOff(TRUE); sub->addChild(new LLMenuItemCallGL("Reload MIME types", &LLMIMETypes::reload)); - sub->addChild(new LLMenuItemCallGL("Web Browser Test", &handle_web_browser_test, NULL, NULL, KEY_F1)); + sub->addChild(new LLMenuItemCallGL("Web Browser Test", &handle_web_browser_test, nullptr, nullptr, KEY_F1)); menu->addChild( sub ); sub->createJumpKeys(); } @@ -1042,29 +1037,29 @@ void init_client_menu(LLMenuGL* menu) menu->addSeparator(); menu->addChild(new LLMenuItemCallGL("Compress Images...", - &handle_compress_image, NULL, NULL)); + &handle_compress_image, nullptr, nullptr)); menu->addChild(new LLMenuItemCheckGL("Limit Select Distance", &menu_toggle_control, - NULL, + nullptr, &menu_check_control, (void*)"LimitSelectDistance")); menu->addChild(new LLMenuItemCheckGL("Disable Camera Constraints", &menu_toggle_control, - NULL, + nullptr, &menu_check_control, (void*)"DisableCameraConstraints")); menu->addChild(new LLMenuItemCheckGL("Mouse Smoothing", &menu_toggle_control, - NULL, + nullptr, &menu_check_control, (void*) "MouseSmooth")); // Singu Note: When this menu is xml, handle this above, with the other insertion points { - LLMenuItemCallGL* item = new LLMenuItemCallGL("insert_advanced", NULL); + LLMenuItemCallGL* item = new LLMenuItemCallGL("insert_advanced", nullptr); item->setVisible(false); menu->addChild(item); } @@ -1072,24 +1067,22 @@ void init_client_menu(LLMenuGL* menu) menu->addChild(new LLMenuItemCheckGL( "Console Window", &menu_toggle_control, - NULL, + nullptr, &menu_check_control, (void*)"ShowConsoleWindow")); // [RLVa:KB] - Checked: 2009-07-08 (RLVa-1.0.0e) | Modified: RLVa-1.0.0e | OK - #ifdef RLV_ADVANCED_TOGGLE_RLVA - if (gSavedSettings.controlExists(RLV_SETTING_MAIN)) - menu->addChild(new LLMenuItemCheckGL("RestrainedLove API", &rlvMenuToggleEnabled, NULL, &rlvMenuCheckEnabled, NULL)); - #endif // RLV_ADVANCED_TOGGLE_RLVA + if (gSavedSettings.controlExists(RLV_SETTING_MAIN)) + menu->addChild(new LLMenuItemCheckGL("RestrainedLove API", &rlvMenuToggleEnabled, nullptr, &rlvMenuCheckEnabled, nullptr)); // [/RLVa:KB] if(gSavedSettings.getBOOL("QAMode")) { - LLMenuGL* sub = NULL; + LLMenuGL* sub = nullptr; sub = new LLMenuGL("Debugging"); sub->setCanTearOff(TRUE); #if LL_WINDOWS - sub->addChild(new LLMenuItemCallGL("Force Breakpoint", &force_error_breakpoint, NULL, NULL, 'B', MASK_CONTROL | MASK_ALT)); + sub->addChild(new LLMenuItemCallGL("Force Breakpoint", &force_error_breakpoint, nullptr, nullptr, 'B', MASK_CONTROL | MASK_ALT)); #endif sub->addChild(new LLMenuItemCallGL("Force LLError And Crash", &force_error_llerror)); sub->addChild(new LLMenuItemCallGL("Force Bad Memory Access", &force_error_bad_memory_access)); @@ -1103,18 +1096,18 @@ void init_client_menu(LLMenuGL* menu) menu->addChild(new LLMenuItemCheckGL( "Output Debug Minidump", &menu_toggle_control, - NULL, + nullptr, &menu_check_control, (void*)"SaveMinidump")); - menu->addChild(new LLMenuItemCallGL("Debug Settings...", handle_singleton_toggle, NULL, NULL)); - menu->addChild(new LLMenuItemCheckGL("View Admin Options", &handle_admin_override_toggle, NULL, &check_admin_override, NULL, 'V', MASK_CONTROL | MASK_ALT)); + menu->addChild(new LLMenuItemCallGL("Debug Settings...", handle_singleton_toggle, nullptr, nullptr)); + menu->addChild(new LLMenuItemCheckGL("View Admin Options", &handle_admin_override_toggle, nullptr, &check_admin_override, nullptr, 'V', MASK_CONTROL | MASK_ALT)); menu->addChild(new LLMenuItemCallGL("Request Admin Status", - &handle_god_mode, NULL, NULL, 'G', MASK_ALT | MASK_CONTROL)); + &handle_god_mode, nullptr, nullptr, 'G', MASK_ALT | MASK_CONTROL)); menu->addChild(new LLMenuItemCallGL("Leave Admin Status", - &handle_leave_god_mode, NULL, NULL, 'G', MASK_ALT | MASK_SHIFT | MASK_CONTROL)); + &handle_leave_god_mode, nullptr, nullptr, 'G', MASK_ALT | MASK_SHIFT | MASK_CONTROL)); menu->createJumpKeys(); } @@ -1124,25 +1117,25 @@ void init_debug_world_menu(LLMenuGL* menu) /* REMOVE mouse move sun from menu options menu->addChild(new LLMenuItemCheckGL("Mouse Moves Sun", &menu_toggle_control, - NULL, + nullptr, &menu_check_control, (void*)"MouseSun", 'M', MASK_CONTROL|MASK_ALT)); */ menu->addChild(new LLMenuItemCheckGL("Sim Sun Override", &menu_toggle_control, - NULL, + nullptr, &menu_check_control, (void*)"SkyOverrideSimSunPosition")); menu->addChild(new LLMenuItemCallGL("Dump Scripted Camera", - &handle_dump_followcam, NULL, NULL)); + &handle_dump_followcam, nullptr, nullptr)); menu->addChild(new LLMenuItemCheckGL("Fixed Weather", &menu_toggle_control, - NULL, + nullptr, &menu_check_control, (void*)"FixedWeather")); menu->addChild(new LLMenuItemCallGL("Dump Region Object Cache", - &handle_dump_region_object_cache, NULL, NULL)); + &handle_dump_region_object_cache, nullptr, nullptr)); menu->createJumpKeys(); } @@ -1168,9 +1161,9 @@ static void handle_export_menus_to_xml_continued(AIFilePicker* filepicker) void init_debug_ui_menu(LLMenuGL* menu) { - menu->addChild(new LLMenuItemCheckGL("Rotate Mini-Map", menu_toggle_control, NULL, menu_check_control, (void*)"MiniMapRotate")); - menu->addChild(new LLMenuItemCheckGL("Use default system color picker", menu_toggle_control, NULL, menu_check_control, (void*)"UseDefaultColorPicker")); - menu->addChild(new LLMenuItemCheckGL("Show search panel in overlay bar", menu_toggle_control, NULL, menu_check_control, (void*)"ShowSearchBar")); + menu->addChild(new LLMenuItemCheckGL("Rotate Mini-Map", menu_toggle_control, nullptr, menu_check_control, (void*)"MiniMapRotate")); + menu->addChild(new LLMenuItemCheckGL("Use default system color picker", menu_toggle_control, nullptr, menu_check_control, (void*)"UseDefaultColorPicker")); + menu->addChild(new LLMenuItemCheckGL("Show search panel in overlay bar", menu_toggle_control, nullptr, menu_check_control, (void*)"ShowSearchBar")); menu->addSeparator(); // commented out until work is complete: DEV-32268 @@ -1178,32 +1171,33 @@ void init_debug_ui_menu(LLMenuGL* menu) menu->addChild(new LLMenuItemCallGL("Editable UI", &edit_ui)); menu->addChild(new LLMenuItemCallGL( "Dump SelectMgr", &dump_select_mgr)); menu->addChild(new LLMenuItemCallGL( "Dump Inventory", &dump_inventory)); - menu->addChild(new LLMenuItemCallGL( "Dump Focus Holder", &handle_dump_focus, NULL, NULL, 'F', MASK_ALT | MASK_CONTROL)); - menu->addChild(new LLMenuItemCallGL( "Print Selected Object Info", &print_object_info, NULL, NULL, 'P', MASK_CONTROL|MASK_SHIFT )); - menu->addChild(new LLMenuItemCallGL( "Print Agent Info", &print_agent_nvpairs, NULL, NULL, 'P', MASK_SHIFT )); - menu->addChild(new LLMenuItemCallGL( "Memory Stats", &output_statistics, NULL, NULL, 'M', MASK_SHIFT | MASK_ALT | MASK_CONTROL)); + menu->addChild(new LLMenuItemCallGL( "Dump Focus Holder", &handle_dump_focus, nullptr, nullptr, 'F', MASK_ALT | MASK_CONTROL)); + menu->addChild(new LLMenuItemCallGL( "Print Selected Object Info", &print_object_info, nullptr, nullptr, 'P', MASK_CONTROL|MASK_SHIFT )); + menu->addChild(new LLMenuItemCallGL( "Print Agent Info", &print_agent_nvpairs, nullptr, nullptr, 'P', MASK_SHIFT )); + menu->addChild(new LLMenuItemCallGL( "Memory Stats", &output_statistics, nullptr, nullptr, 'M', MASK_SHIFT | MASK_ALT | MASK_CONTROL)); menu->addChild(new LLMenuItemCheckGL("Double-Click Auto-Pilot", - menu_toggle_control, NULL, menu_check_control, + menu_toggle_double_click_control, nullptr, menu_check_control, (void*)"DoubleClickAutoPilot")); // add for double click teleport support menu->addChild(new LLMenuItemCheckGL("Double-Click Teleport", - menu_toggle_control, NULL, menu_check_control, + menu_toggle_double_click_control, nullptr, menu_check_control, (void*)"DoubleClickTeleport")); menu->addSeparator(); -// menu->addChild(new LLMenuItemCallGL( "Print Packets Lost", &print_packets_lost, NULL, NULL, 'L', MASK_SHIFT )); - menu->addChild(new LLMenuItemCheckGL("Debug SelectMgr", menu_toggle_control, NULL, menu_check_control, (void*)"DebugSelectMgr")); +// menu->addChild(new LLMenuItemCallGL( "Print Packets Lost", &print_packets_lost, nullptr, nullptr, 'L', MASK_SHIFT )); + menu->addChild(new LLMenuItemCheckGL("Debug SelectMgr", menu_toggle_control, nullptr, menu_check_control, (void*)"DebugSelectMgr")); menu->addChild(new LLMenuItemToggleGL("Debug Clicks", &gDebugClicks)); menu->addChild(new LLMenuItemToggleGL("Debug Views", &LLView::sDebugRects)); - menu->addChild(new LLMenuItemCheckGL("Show Name Tooltips", toggle_show_xui_names, NULL, check_show_xui_names, NULL)); + menu->addChild(new LLMenuItemCheckGL("Show Name Tooltips", toggle_show_xui_names, nullptr, check_show_xui_names, nullptr)); menu->addChild(new LLMenuItemToggleGL("Debug Mouse Events", &LLView::sDebugMouseHandling)); menu->addChild(new LLMenuItemToggleGL("Debug Keys", &LLView::sDebugKeys)); menu->addChild(new LLMenuItemToggleGL("Debug WindowProc", &gDebugWindowProc)); menu->addChild(new LLMenuItemToggleGL("Debug Text Editor Tips", &gDebugTextEditorTips)); menu->addSeparator(); - menu->addChild(new LLMenuItemCheckGL("Show Time", menu_toggle_control, NULL, menu_check_control, (void*)"DebugShowTime")); - menu->addChild(new LLMenuItemCheckGL("Show Render Info", menu_toggle_control, NULL, menu_check_control, (void*)"DebugShowRenderInfo")); - menu->addChild(new LLMenuItemCheckGL("Show Matrices", menu_toggle_control, NULL, menu_check_control, (void*)"DebugShowRenderMatrices")); - menu->addChild(new LLMenuItemCheckGL("Show Color Under Cursor", menu_toggle_control, NULL, menu_check_control, (void*)"DebugShowColor")); + menu->addChild(new LLMenuItemCheckGL("Show Time", menu_toggle_control, nullptr, menu_check_control, (void*)"DebugShowTime")); + menu->addChild(new LLMenuItemCheckGL("Show Render Info", menu_toggle_control, nullptr, menu_check_control, (void*)"DebugShowRenderInfo")); + menu->addChild(new LLMenuItemCheckGL("Show Matrices", menu_toggle_control, nullptr, menu_check_control, (void*)"DebugShowRenderMatrices")); + menu->addChild(new LLMenuItemCheckGL("Show Color Under Cursor", menu_toggle_control, nullptr, menu_check_control, (void*)"DebugShowColor")); + menu->addChild(new LLMenuItemCheckGL("Show FPS", menu_toggle_control, nullptr, menu_check_control, (void*)"SLBShowFPS")); menu->createJumpKeys(); } @@ -1217,16 +1211,16 @@ void init_debug_xui_menu(LLMenuGL* menu) menu->addChild(new LLMenuItemCallGL("Load from XML...", handle_load_from_xml)); // //menu->addChild(new LLMenuItemCallGL("Save to XML...", handle_save_to_xml)); - menu->addChild(new LLMenuItemCallGL("Save to XML...", handle_save_to_xml, NULL, NULL, 'X', MASK_CONTROL | MASK_ALT | MASK_SHIFT)); + menu->addChild(new LLMenuItemCallGL("Save to XML...", handle_save_to_xml, nullptr, nullptr, 'X', MASK_CONTROL | MASK_ALT | MASK_SHIFT)); // - menu->addChild(new LLMenuItemCheckGL("Show XUI Names", toggle_show_xui_names, NULL, check_show_xui_names, NULL)); + menu->addChild(new LLMenuItemCheckGL("Show XUI Names", toggle_show_xui_names, nullptr, check_show_xui_names, nullptr)); menu->createJumpKeys(); } void init_debug_rendering_menu(LLMenuGL* menu) { - LLMenuGL* sub_menu = NULL; + LLMenuGL* sub_menu = nullptr; /////////////////////////// // @@ -1237,43 +1231,43 @@ void init_debug_rendering_menu(LLMenuGL* menu) menu->addChild(sub_menu); sub_menu->addChild(new LLMenuItemCheckGL("Simple", - &LLPipeline::toggleRenderTypeControl, NULL, + &LLPipeline::toggleRenderTypeControl, nullptr, &LLPipeline::hasRenderTypeControl, (void*)LLPipeline::RENDER_TYPE_SIMPLE, '1', MASK_CONTROL|MASK_ALT|MASK_SHIFT)); sub_menu->addChild(new LLMenuItemCheckGL("Alpha", - &LLPipeline::toggleRenderTypeControl, NULL, + &LLPipeline::toggleRenderTypeControl, nullptr, &LLPipeline::hasRenderTypeControl, (void*)LLPipeline::RENDER_TYPE_ALPHA, '2', MASK_CONTROL|MASK_ALT|MASK_SHIFT)); sub_menu->addChild(new LLMenuItemCheckGL("Tree", - &LLPipeline::toggleRenderTypeControl, NULL, + &LLPipeline::toggleRenderTypeControl, nullptr, &LLPipeline::hasRenderTypeControl, (void*)LLPipeline::RENDER_TYPE_TREE, '3', MASK_CONTROL|MASK_ALT|MASK_SHIFT)); sub_menu->addChild(new LLMenuItemCheckGL("Character", - &LLPipeline::toggleRenderTypeControl, NULL, + &LLPipeline::toggleRenderTypeControl, nullptr, &LLPipeline::hasRenderTypeControl, (void*)LLPipeline::RENDER_TYPE_AVATAR, '4', MASK_CONTROL|MASK_ALT|MASK_SHIFT)); sub_menu->addChild(new LLMenuItemCheckGL("SurfacePatch", - &LLPipeline::toggleRenderTypeControl, NULL, + &LLPipeline::toggleRenderTypeControl, nullptr, &LLPipeline::hasRenderTypeControl, (void*)LLPipeline::RENDER_TYPE_TERRAIN, '5', MASK_CONTROL|MASK_ALT|MASK_SHIFT)); sub_menu->addChild(new LLMenuItemCheckGL("Sky", - &LLPipeline::toggleRenderTypeControl, NULL, + &LLPipeline::toggleRenderTypeControl, nullptr, &LLPipeline::hasRenderTypeControl, (void*)LLPipeline::RENDER_TYPE_SKY, '6', MASK_CONTROL|MASK_ALT|MASK_SHIFT)); sub_menu->addChild(new LLMenuItemCheckGL("Water", - &LLPipeline::toggleRenderTypeControl, NULL, + &LLPipeline::toggleRenderTypeControl, nullptr, &LLPipeline::hasRenderTypeControl, (void*)LLPipeline::RENDER_TYPE_WATER, '7', MASK_CONTROL|MASK_ALT|MASK_SHIFT)); sub_menu->addChild(new LLMenuItemCheckGL("Ground", - &LLPipeline::toggleRenderTypeControl, NULL, + &LLPipeline::toggleRenderTypeControl, nullptr, &LLPipeline::hasRenderTypeControl, (void*)LLPipeline::RENDER_TYPE_GROUND, '8', MASK_CONTROL|MASK_ALT|MASK_SHIFT)); sub_menu->addChild(new LLMenuItemCheckGL("Volume", - &LLPipeline::toggleRenderTypeControl, NULL, + &LLPipeline::toggleRenderTypeControl, nullptr, &LLPipeline::hasRenderTypeControl, (void*)LLPipeline::RENDER_TYPE_VOLUME, '9', MASK_CONTROL|MASK_ALT|MASK_SHIFT)); sub_menu->addChild(new LLMenuItemCheckGL("Grass", - &LLPipeline::toggleRenderTypeControl, NULL, + &LLPipeline::toggleRenderTypeControl, nullptr, &LLPipeline::hasRenderTypeControl, (void*)LLPipeline::RENDER_TYPE_GRASS, '0', MASK_CONTROL|MASK_ALT|MASK_SHIFT)); //NOTE: Using a static variable, as an unsigned long long cannot fit in the space of a pointer. Pass pointer to callbacks @@ -1283,15 +1277,15 @@ void init_debug_rendering_menu(LLMenuGL* menu) #endif ); sub_menu->addChild(new LLMenuItemCheckGL("Clouds", //This clobbers skyuseclassicclouds, but.. big deal. - &LLPipeline::toggleRenderPairedTypeControl, NULL, + &LLPipeline::toggleRenderPairedTypeControl, nullptr, &LLPipeline::hasRenderPairedTypeControl, (void*)&cloud_flags, '-', MASK_CONTROL|MASK_ALT| MASK_SHIFT)); sub_menu->addChild(new LLMenuItemCheckGL("Particles", - &LLPipeline::toggleRenderTypeControl, NULL, + &LLPipeline::toggleRenderTypeControl, nullptr, &LLPipeline::hasRenderTypeControl, (void*)LLPipeline::RENDER_TYPE_PARTICLES, '=', MASK_CONTROL|MASK_ALT|MASK_SHIFT)); sub_menu->addChild(new LLMenuItemCheckGL("Bump", - &LLPipeline::toggleRenderTypeControl, NULL, + &LLPipeline::toggleRenderTypeControl, nullptr, &LLPipeline::hasRenderTypeControl, (void*)LLPipeline::RENDER_TYPE_BUMP, '\\', MASK_CONTROL|MASK_ALT|MASK_SHIFT)); sub_menu->createJumpKeys(); @@ -1304,35 +1298,35 @@ void init_debug_rendering_menu(LLMenuGL* menu) #define MODIFIER MASK_ALT #endif sub_menu->addChild(new LLMenuItemCheckGL("UI", - &LLPipeline::toggleRenderDebugFeature, NULL, + &LLPipeline::toggleRenderDebugFeature, nullptr, &LLPipeline::toggleRenderDebugFeatureControl, (void*)LLPipeline::RENDER_DEBUG_FEATURE_UI, KEY_F1, MODIFIER|MASK_CONTROL)); sub_menu->addChild(new LLMenuItemCheckGL("Selected", - &LLPipeline::toggleRenderDebugFeature, NULL, + &LLPipeline::toggleRenderDebugFeature, nullptr, &LLPipeline::toggleRenderDebugFeatureControl, (void*)LLPipeline::RENDER_DEBUG_FEATURE_SELECTED, KEY_F2, MODIFIER|MASK_CONTROL)); sub_menu->addChild(new LLMenuItemCheckGL("Highlighted", - &LLPipeline::toggleRenderDebugFeature, NULL, + &LLPipeline::toggleRenderDebugFeature, nullptr, &LLPipeline::toggleRenderDebugFeatureControl, (void*)LLPipeline::RENDER_DEBUG_FEATURE_HIGHLIGHTED, KEY_F3, MODIFIER|MASK_CONTROL)); sub_menu->addChild(new LLMenuItemCheckGL("Dynamic Textures", - &LLPipeline::toggleRenderDebugFeature, NULL, + &LLPipeline::toggleRenderDebugFeature, nullptr, &LLPipeline::toggleRenderDebugFeatureControl, (void*)LLPipeline::RENDER_DEBUG_FEATURE_DYNAMIC_TEXTURES, KEY_F4, MODIFIER|MASK_CONTROL)); sub_menu->addChild(new LLMenuItemCheckGL( "Foot Shadows", - &LLPipeline::toggleRenderDebugFeature, NULL, + &LLPipeline::toggleRenderDebugFeature, nullptr, &LLPipeline::toggleRenderDebugFeatureControl, (void*)LLPipeline::RENDER_DEBUG_FEATURE_FOOT_SHADOWS, KEY_F5, MODIFIER|MASK_CONTROL)); sub_menu->addChild(new LLMenuItemCheckGL("Fog", - &LLPipeline::toggleRenderDebugFeature, NULL, + &LLPipeline::toggleRenderDebugFeature, nullptr, &LLPipeline::toggleRenderDebugFeatureControl, (void*)LLPipeline::RENDER_DEBUG_FEATURE_FOG, KEY_F6, MODIFIER|MASK_CONTROL)); sub_menu->addChild(new LLMenuItemCheckGL("Test FRInfo", - &LLPipeline::toggleRenderDebugFeature, NULL, + &LLPipeline::toggleRenderDebugFeature, nullptr, &LLPipeline::toggleRenderDebugFeatureControl, (void*)LLPipeline::RENDER_DEBUG_FEATURE_FR_INFO, KEY_F8, MODIFIER|MASK_CONTROL)); sub_menu->addChild(new LLMenuItemCheckGL( "Flexible Objects", - &LLPipeline::toggleRenderDebugFeature, NULL, + &LLPipeline::toggleRenderDebugFeature, nullptr, &LLPipeline::toggleRenderDebugFeatureControl, (void*)LLPipeline::RENDER_DEBUG_FEATURE_FLEXIBLE, KEY_F9, MODIFIER|MASK_CONTROL)); sub_menu->createJumpKeys(); @@ -1345,79 +1339,79 @@ void init_debug_rendering_menu(LLMenuGL* menu) sub_menu->setCanTearOff(TRUE); menu->addChild(sub_menu); - sub_menu->addChild(new LLMenuItemCheckGL("Verify", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Verify", &LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_VERIFY)); - sub_menu->addChild(new LLMenuItemCheckGL("BBoxes", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("BBoxes", &LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_BBOXES)); - sub_menu->addChild(new LLMenuItemCheckGL("Points", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Points", &LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_POINTS)); - sub_menu->addChild(new LLMenuItemCheckGL("Octree", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Octree", &LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_OCTREE)); - sub_menu->addChild(new LLMenuItemCheckGL("Shadow Frusta", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Shadow Frusta", &LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA)); - sub_menu->addChild(new LLMenuItemCheckGL("Occlusion", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Occlusion", &LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_OCCLUSION)); - sub_menu->addChild(new LLMenuItemCheckGL("Render Batches", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Render Batches", &LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_BATCH_SIZE)); - sub_menu->addChild(new LLMenuItemCheckGL("Animated Textures", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Animated Textures", &LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_TEXTURE_ANIM)); - sub_menu->addChild(new LLMenuItemCheckGL("Texture Priority", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Texture Priority", &LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY)); - sub_menu->addChild(new LLMenuItemCheckGL("Avatar Rendering Cost", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Avatar Rendering Cost", &LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_SHAME, 'C', MASK_CONTROL|MASK_ALT|MASK_SHIFT)); - sub_menu->addChild(new LLMenuItemCheckGL("Texture Area (sqrt(A))",&LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Texture Area (sqrt(A))",&LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_TEXTURE_AREA)); - sub_menu->addChild(new LLMenuItemCheckGL("Face Area (sqrt(A))",&LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Face Area (sqrt(A))",&LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_FACE_AREA)); - sub_menu->addChild(new LLMenuItemCheckGL("Lights", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Lights", &LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_LIGHTS)); - sub_menu->addChild(new LLMenuItemCheckGL("Particles", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Particles", &LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_PARTICLES)); - sub_menu->addChild(new LLMenuItemCheckGL("Composition", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Composition", &LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_COMPOSITION)); - sub_menu->addChild(new LLMenuItemCheckGL("Glow",&LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Glow",&LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_GLOW)); - sub_menu->addChild(new LLMenuItemCheckGL("Raycasting", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Raycasting", &LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_RAYCAST)); - sub_menu->addChild(new LLMenuItemCheckGL("Sculpt", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Sculpt", &LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_SCULPTED)); - sub_menu->addChild(new LLMenuItemCheckGL("Build Queue", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Build Queue", &LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_BUILD_QUEUE)); - sub_menu->addChild(new LLMenuItemCheckGL("Update Types", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Update Types", &LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_UPDATE_TYPE)); - sub_menu->addChild(new LLMenuItemCheckGL("Physics Shapes", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Physics Shapes", &LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_PHYSICS_SHAPES)); - sub_menu->addChild(new LLMenuItemCheckGL("Normals", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Normals", &LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_NORMALS)); - sub_menu->addChild(new LLMenuItemCheckGL("LOD Info", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("LOD Info", &LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_LOD_INFO)); - sub_menu->addChild(new LLMenuItemCheckGL("Wind Vectors", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Wind Vectors", &LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_WIND_VECTORS)); - sub_menu->addChild(new LLMenuItemCheckGL("Complexity", &LLPipeline::toggleRenderDebug, NULL, + sub_menu->addChild(new LLMenuItemCheckGL("Complexity", &LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_RENDER_COMPLEXITY)); @@ -1426,7 +1420,7 @@ void init_debug_rendering_menu(LLMenuGL* menu) sub_menu->addChild(new LLMenuItemCheckGL("Camera Offset", &menu_toggle_control, - NULL, + nullptr, &menu_check_control, (void*)"CameraOffset")); @@ -1441,74 +1435,68 @@ void init_debug_rendering_menu(LLMenuGL* menu) menu->addChild( sub_menu ); menu->addSeparator(); - menu->addChild(new LLMenuItemCheckGL("Axes", menu_toggle_control, NULL, menu_check_control, (void*)"ShowAxes")); + menu->addChild(new LLMenuItemCheckGL("Axes", menu_toggle_control, nullptr, menu_check_control, (void*)"ShowAxes")); menu->addSeparator(); - menu->addChild(new LLMenuItemCheckGL("Hide Selected", menu_toggle_control, NULL, menu_check_control, (void*)"HideSelectedObjects")); + menu->addChild(new LLMenuItemCheckGL("Hide Selected", menu_toggle_control, nullptr, menu_check_control, (void*)"HideSelectedObjects")); menu->addSeparator(); - menu->addChild(new LLMenuItemCheckGL("Tangent Basis", menu_toggle_control, NULL, menu_check_control, (void*)"ShowTangentBasis")); - menu->addChild(new LLMenuItemCallGL("Selected Texture Info", handle_selected_texture_info, NULL, NULL, 'T', MASK_CONTROL|MASK_SHIFT|MASK_ALT)); - //menu->addChild(new LLMenuItemCallGL("Dump Image List", handle_dump_image_list, NULL, NULL, 'I', MASK_CONTROL|MASK_SHIFT)); + menu->addChild(new LLMenuItemCheckGL("Tangent Basis", menu_toggle_control, nullptr, menu_check_control, (void*)"ShowTangentBasis")); + menu->addChild(new LLMenuItemCallGL("Selected Texture Info", handle_selected_texture_info, nullptr, nullptr, 'T', MASK_CONTROL|MASK_SHIFT|MASK_ALT)); + //menu->addChild(new LLMenuItemCallGL("Dump Image List", handle_dump_image_list, nullptr, nullptr, 'I', MASK_CONTROL|MASK_SHIFT)); - menu->addChild(new LLMenuItemToggleGL("Wireframe", &gUseWireframe, - 'R', MASK_CONTROL|MASK_SHIFT)); + menu->addChild(new LLMenuItemCheckGL("Wireframe", advanced_toggle_wireframe, nullptr, advanced_check_wireframe, nullptr, 'R', MASK_CONTROL|MASK_SHIFT)); LLMenuItemCheckGL* item; - item = new LLMenuItemCheckGL("Object-Object Occlusion", menu_toggle_control, NULL, menu_check_control, (void*)"UseOcclusion", 'O', MASK_CONTROL|MASK_SHIFT); + item = new LLMenuItemCheckGL("Object-Object Occlusion", menu_toggle_control, nullptr, menu_check_control, (void*)"UseOcclusion", 'O', MASK_CONTROL|MASK_SHIFT); item->setEnabled(gGLManager.mHasOcclusionQuery && LLFeatureManager::getInstance()->isFeatureAvailable("UseOcclusion")); menu->addChild(item); - item = new LLMenuItemCheckGL("Debug GL", menu_toggle_control, NULL, menu_check_control, (void*)"RenderDebugGL"); + item = new LLMenuItemCheckGL("Debug GL", menu_toggle_control, nullptr, menu_check_control, (void*)"RenderDebugGL"); menu->addChild(item); - item = new LLMenuItemCheckGL("Debug Pipeline", menu_toggle_control, NULL, menu_check_control, (void*)"RenderDebugPipeline"); + item = new LLMenuItemCheckGL("Debug Pipeline", menu_toggle_control, nullptr, menu_check_control, (void*)"RenderDebugPipeline"); menu->addChild(item); - item = new LLMenuItemCheckGL("Automatic Alpha Masks (non-deferred)", menu_toggle_control, NULL, menu_check_control, (void*)"RenderAutoMaskAlphaNonDeferred"); + item = new LLMenuItemCheckGL("Automatic Alpha Masks (non-deferred)", menu_toggle_control, nullptr, menu_check_control, (void*)"RenderAutoMaskAlphaNonDeferred"); menu->addChild(item); - item = new LLMenuItemCheckGL("Automatic Alpha Masks (deferred)", menu_toggle_control, NULL, menu_check_control, (void*)"RenderAutoMaskAlphaDeferred"); + item = new LLMenuItemCheckGL("Automatic Alpha Masks (deferred)", menu_toggle_control, nullptr, menu_check_control, (void*)"RenderAutoMaskAlphaDeferred"); menu->addChild(item); - item = new LLMenuItemCheckGL("Aggressive Alpha Masking", menu_toggle_control, NULL, menu_check_control, (void*)"SHUseRMSEAutoMask"); + item = new LLMenuItemCheckGL("Aggressive Alpha Masking", menu_toggle_control, nullptr, menu_check_control, (void*)"SHUseRMSEAutoMask"); menu->addChild(item); - menu->addChild(new LLMenuItemCallGL("Rebuild Vertex Buffers", reset_vertex_buffers, NULL, NULL, 'V', MASK_CONTROL | MASK_SHIFT)); + menu->addChild(new LLMenuItemCallGL("Rebuild Vertex Buffers", reset_vertex_buffers, nullptr, nullptr, 'V', MASK_CONTROL | MASK_SHIFT)); - item = new LLMenuItemCheckGL("Animate Textures", menu_toggle_control, NULL, menu_check_control, (void*)"AnimateTextures"); + item = new LLMenuItemCheckGL("Animate Trees", menu_toggle_control, nullptr, menu_check_control, (void*)"RenderAnimateTrees"); + menu->addChild(item); + + item = new LLMenuItemCheckGL("Animate Textures", menu_toggle_control, nullptr, menu_check_control, (void*)"AnimateTextures"); menu->addChild(item); - item = new LLMenuItemCheckGL("Disable Textures", menu_toggle_control, NULL, menu_check_control, (void*)"TextureDisable"); + item = new LLMenuItemCheckGL("Disable Textures", menu_toggle_control, nullptr, menu_check_control, (void*)"TextureDisable"); menu->addChild(item); - item = new LLMenuItemCheckGL("HTTP Get Textures", menu_toggle_control, NULL, menu_check_control, (void*)"ImagePipelineUseHTTP"); + item = new LLMenuItemCheckGL("HTTP Get Textures", menu_toggle_control, nullptr, menu_check_control, (void*)"ImagePipelineUseHTTP"); menu->addChild(item); - item = new LLMenuItemCheckGL("Run Multiple Threads", menu_toggle_control, NULL, menu_check_control, (void*)"RunMultipleThreads"); + item = new LLMenuItemCheckGL("Run Multiple Threads", menu_toggle_control, nullptr, menu_check_control, (void*)"RunMultipleThreads"); menu->addChild(item); - item = new LLMenuItemCheckGL("Cheesy Beacon", menu_toggle_control, NULL, menu_check_control, (void*)"CheesyBeacon"); + item = new LLMenuItemCheckGL("Cheesy Beacon", menu_toggle_control, nullptr, menu_check_control, (void*)"CheesyBeacon"); menu->addChild(item); - item = new LLMenuItemCheckGL("Attached Lights", menu_toggle_attached_lights, NULL, menu_check_control, (void*)"RenderAttachedLights"); + item = new LLMenuItemCheckGL("Attached Lights", menu_toggle_attached_lights, nullptr, menu_check_control, (void*)"RenderAttachedLights"); menu->addChild(item); - item = new LLMenuItemCheckGL("Attached Particles", menu_toggle_attached_particles, NULL, menu_check_control, (void*)"RenderAttachedParticles"); + item = new LLMenuItemCheckGL("Attached Particles", menu_toggle_attached_particles, nullptr, menu_check_control, (void*)"RenderAttachedParticles"); menu->addChild(item); - item = new LLMenuItemCheckGL("Audit Texture", menu_toggle_control, NULL, menu_check_control, (void*)"AuditTexture"); + item = new LLMenuItemCheckGL("Audit Texture", menu_toggle_control, nullptr, menu_check_control, (void*)"AuditTexture"); menu->addChild(item); -#ifndef LL_RELEASE_FOR_DOWNLOAD menu->addSeparator(); - menu->addChild(new LLMenuItemCallGL("Memory Leaking Simulation", LLFloaterMemLeak::show, NULL, NULL)); -#else - if(gSavedSettings.getBOOL("QAMode")) - { - menu->addSeparator(); - menu->addChild(new LLMenuItemCallGL("Memory Leaking Simulation", LLFloaterMemLeak::show, NULL, NULL)); - } -#endif + menu->addChild(new LLMenuItemCallGL("Memory Leaking Simulation", LLFloaterMemLeak::show, nullptr, nullptr)); menu->createJumpKeys(); } @@ -1517,13 +1505,13 @@ void init_debug_avatar_menu(LLMenuGL* menu) { LLMenuGL* sub_menu = new LLMenuGL("Character Tests"); sub_menu->setCanTearOff(TRUE); - sub_menu->addChild(new LLMenuItemCheckGL("Go Away/AFK When Idle", menu_toggle_control, NULL, menu_check_control, (void*)"AllowIdleAFK")); + sub_menu->addChild(new LLMenuItemCheckGL("Go Away/AFK When Idle", menu_toggle_control, nullptr, menu_check_control, (void*)"AllowIdleAFK")); sub_menu->addChild(new LLMenuItemCallGL("Appearance To XML", &handle_dump_archetype_xml)); // HACK for easy testing of avatar geometry sub_menu->addChild(new LLMenuItemCallGL( "Toggle Character Geometry", - &handle_god_request_avatar_geometry, &is_god_customer_service, NULL)); + &handle_god_request_avatar_geometry, &is_god_customer_service, nullptr)); sub_menu->addChild(new LLMenuItemCallGL("Test Male", handle_test_male)); @@ -1533,19 +1521,19 @@ void init_debug_avatar_menu(LLMenuGL* menu) sub_menu->addChild(new LLMenuItemCallGL("Toggle PG", handle_toggle_pg)); - sub_menu->addChild(new LLMenuItemCheckGL("Allow Select Avatar", menu_toggle_control, NULL, menu_check_control, (void*)"AllowSelectAvatar")); + sub_menu->addChild(new LLMenuItemCheckGL("Allow Select Avatar", menu_toggle_control, nullptr, menu_check_control, (void*)"AllowSelectAvatar")); sub_menu->createJumpKeys(); menu->addChild(sub_menu); - menu->addChild(new LLMenuItemCheckGL("Tap-Tap-Hold To Run", menu_toggle_control, NULL, menu_check_control, (void*)"AllowTapTapHoldRun")); - menu->addChild(new LLMenuItemCallGL("Force Params to Default", &LLAgent::clearVisualParams, NULL)); - menu->addChild(new LLMenuItemCallGL("Reload Vertex Shader", &reload_vertex_shader, NULL)); + menu->addChild(new LLMenuItemCheckGL("Tap-Tap-Hold To Run", menu_toggle_control, nullptr, menu_check_control, (void*)"AllowTapTapHoldRun")); + menu->addChild(new LLMenuItemCallGL("Force Params to Default", &LLAgent::clearVisualParams, nullptr)); + menu->addChild(new LLMenuItemCallGL("Reload Vertex Shader", &reload_vertex_shader, nullptr)); menu->addChild(new LLMenuItemToggleGL("Animation Info", &LLVOAvatar::sShowAnimationDebug)); - menu->addChild(new LLMenuItemCallGL("Slow Motion Animations", &slow_mo_animations, NULL)); + menu->addChild(new LLMenuItemCallGL("Slow Motion Animations", &slow_mo_animations, nullptr)); LLMenuItemCheckGL* item; - item = new LLMenuItemCheckGL("Show Look At", menu_toggle_control, NULL, menu_check_control, (void*)"AscentShowLookAt"); + item = new LLMenuItemCheckGL("Show Look At", menu_toggle_control, nullptr, menu_check_control, (void*)"AscentShowLookAt"); menu->addChild(item); menu->addChild(new LLMenuItemToggleGL("Show Point At", &LLHUDEffectPointAt::sDebugPointAt)); @@ -1556,23 +1544,27 @@ void init_debug_avatar_menu(LLMenuGL* menu) //diabling collision plane due to DEV-14477 -brad //menu->addChild(new LLMenuItemToggleGL("Show Collision Plane", &LLVOAvatar::sShowFootPlane)); menu->addChild(new LLMenuItemCheckGL("Show Collision Skeleton", - &LLPipeline::toggleRenderDebug, NULL, + &LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_AVATAR_VOLUME)); + menu->addChild(new LLMenuItemCheckGL("Show Avatar Joints", + &LLPipeline::toggleRenderDebug, nullptr, + &LLPipeline::toggleRenderDebugControl, + (void*)LLPipeline::RENDER_DEBUG_AVATAR_JOINTS)); menu->addChild(new LLMenuItemCheckGL("Display Agent Target", - &LLPipeline::toggleRenderDebug, NULL, + &LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_AGENT_TARGET)); menu->addChild(new LLMenuItemCheckGL("Attachment Bytes", - &LLPipeline::toggleRenderDebug, NULL, + &LLPipeline::toggleRenderDebug, nullptr, &LLPipeline::toggleRenderDebugControl, (void*)LLPipeline::RENDER_DEBUG_ATTACHMENT_BYTES)); menu->addChild(new LLMenuItemToggleGL( "Debug Rotation", &LLVOAvatar::sDebugAvatarRotation)); menu->addChild(new LLMenuItemCallGL("Dump Attachments", handle_dump_attachments)); menu->addChild(new LLMenuItemCallGL("Rebake Textures", handle_rebake_textures)); #ifndef LL_RELEASE_FOR_DOWNLOAD - menu->addChild(new LLMenuItemCallGL("Debug Avatar Textures", handle_debug_avatar_textures, NULL, NULL, 'A', MASK_SHIFT|MASK_CONTROL|MASK_ALT)); - menu->addChild(new LLMenuItemCallGL("Dump Local Textures", handle_dump_avatar_local_textures, NULL, NULL, 'M', MASK_SHIFT|MASK_ALT )); + menu->addChild(new LLMenuItemCallGL("Debug Avatar Textures", handle_debug_avatar_textures, nullptr, nullptr, 'A', MASK_SHIFT|MASK_CONTROL|MASK_ALT)); + menu->addChild(new LLMenuItemCallGL("Dump Local Textures", handle_dump_avatar_local_textures, nullptr, nullptr, 'M', MASK_SHIFT|MASK_ALT )); #endif gMeshesAndMorphsMenu = new LLMenuGL("Meshes and Morphs"); @@ -1593,43 +1585,39 @@ void init_debug_rlva_menu(LLMenuGL* menu) pDbgMenu->setCanTearOff(TRUE); if (gSavedSettings.controlExists(RLV_SETTING_DEBUG)) - pDbgMenu->addChild(new LLMenuItemCheckGL("Show Debug Messages", menu_toggle_control, NULL, menu_check_control, (void*)RLV_SETTING_DEBUG)); + pDbgMenu->addChild(new LLMenuItemCheckGL("Show Debug Messages", menu_toggle_control, nullptr, menu_check_control, (void*)RLV_SETTING_DEBUG)); pDbgMenu->addSeparator(); if (gSavedSettings.controlExists(RLV_SETTING_ENABLELEGACYNAMING)) - pDbgMenu->addChild(new LLMenuItemCheckGL("Enable Legacy Naming", menu_toggle_control, NULL, menu_check_control, (void*)RLV_SETTING_ENABLELEGACYNAMING)); + pDbgMenu->addChild(new LLMenuItemCheckGL("Enable Legacy Naming", menu_toggle_control, nullptr, menu_check_control, (void*)RLV_SETTING_ENABLELEGACYNAMING)); if (gSavedSettings.controlExists(RLV_SETTING_SHAREDINVAUTORENAME)) - pDbgMenu->addChild(new LLMenuItemCheckGL("Rename Shared Items on Wear", menu_toggle_control, NULL, menu_check_control, (void*)RLV_SETTING_SHAREDINVAUTORENAME)); + pDbgMenu->addChild(new LLMenuItemCheckGL("Rename Shared Items on Wear", menu_toggle_control, nullptr, menu_check_control, (void*)RLV_SETTING_SHAREDINVAUTORENAME)); menu->addChild(pDbgMenu); menu->addSeparator(); } if (gSavedSettings.controlExists(RLV_SETTING_ENABLESHAREDWEAR)) - menu->addChild(new LLMenuItemCheckGL("Enable Shared Wear", menu_toggle_control, NULL, menu_check_control, (void*)RLV_SETTING_ENABLESHAREDWEAR)); + menu->addChild(new LLMenuItemCheckGL("Enable Shared Wear", menu_toggle_control, nullptr, menu_check_control, (void*)RLV_SETTING_ENABLESHAREDWEAR)); menu->addSeparator(); - #ifdef RLV_EXTENSION_HIDELOCKED - if ( (gSavedSettings.controlExists(RLV_SETTING_HIDELOCKEDLAYER)) && - (gSavedSettings.controlExists(RLV_SETTING_HIDELOCKEDATTACH)) ) - { - menu->addChild(new LLMenuItemCheckGL("Hide Locked Layers", menu_toggle_control, NULL, menu_check_control, (void*)RLV_SETTING_HIDELOCKEDLAYER)); - menu->addChild(new LLMenuItemCheckGL("Hide Locked Attachments", menu_toggle_control, NULL, menu_check_control, (void*)RLV_SETTING_HIDELOCKEDATTACH)); - //sub_menu->addChild(new LLMenuItemToggleGL("Hide locked inventory", &rlv_handler_t::fHideLockedInventory)); - menu->addSeparator(); - } - #endif // RLV_EXTENSION_HIDELOCKED + if ( (gSavedSettings.controlExists(RLV_SETTING_HIDELOCKEDLAYER)) && + (gSavedSettings.controlExists(RLV_SETTING_HIDELOCKEDATTACH)) ) + { + menu->addChild(new LLMenuItemCheckGL("Hide Locked Layers", menu_toggle_control, nullptr, menu_check_control, (void*)RLV_SETTING_HIDELOCKEDLAYER)); + menu->addChild(new LLMenuItemCheckGL("Hide Locked Attachments", menu_toggle_control, nullptr, menu_check_control, (void*)RLV_SETTING_HIDELOCKEDATTACH)); + //sub_menu->addChild(new LLMenuItemToggleGL("Hide locked inventory", &rlv_handler_t::fHideLockedInventory)); + menu->addSeparator(); + } if (gSavedSettings.controlExists(RLV_SETTING_FORBIDGIVETORLV)) - menu->addChild(new LLMenuItemCheckGL("Forbid Give to #RLV", menu_toggle_control, NULL, menu_check_control, (void*)RLV_SETTING_FORBIDGIVETORLV)); + menu->addChild(new LLMenuItemCheckGL("Forbid Give to #RLV", menu_toggle_control, nullptr, menu_check_control, (void*)RLV_SETTING_FORBIDGIVETORLV)); if (gSavedSettings.controlExists(RLV_SETTING_ENABLELEGACYNAMING)) - menu->addChild(new LLMenuItemCheckGL("Show Name Tags", menu_toggle_control, NULL, menu_check_control, (void*)RLV_SETTING_SHOWNAMETAGS)); + menu->addChild(new LLMenuItemCheckGL("Show Name Tags", menu_toggle_control, nullptr, menu_check_control, (void*)RLV_SETTING_SHOWNAMETAGS)); menu->addSeparator(); - #ifdef RLV_EXTENSION_FLOATER_RESTRICTIONS - // TODO-RLVa: figure out a way to tell if floater_rlv_behaviour.xml exists - menu->addChild(new LLMenuItemCheckGL("Restrictions...", &RlvFloaterBehaviours::toggle, NULL, &RlvFloaterBehaviours::visible, NULL)); - menu->addChild(new LLMenuItemCheckGL("Locks...", &RlvFloaterLocks::toggle, NULL, &RlvFloaterLocks::visible, NULL)); - #endif // RLV_EXTENSION_FLOATER_RESTRICTIONS + menu->addChild(new LLMenuItemCheckGL("Restrictions...", &RlvFloaterBehaviours::toggle, nullptr, &RlvFloaterBehaviours::visible, nullptr)); + menu->addChild(new LLMenuItemCheckGL("Locks...", &RlvFloaterLocks::toggle, nullptr, &RlvFloaterLocks::visible, nullptr)); + menu->addChild(new LLMenuItemCheckGL("Strings...", &RlvFloaterStrings::toggle, nullptr, &RlvFloaterStrings::visible, nullptr)); } // [/RLVa:KB] @@ -1640,18 +1628,18 @@ void init_server_menu(LLMenuGL* menu) menu->addChild(sub); sub->addChild(new LLMenuItemCallGL( "Take Copy", - &force_take_copy, &is_god_customer_service, NULL, + &force_take_copy, &is_god_customer_service, nullptr, 'O', MASK_SHIFT | MASK_ALT | MASK_CONTROL)); #ifdef _CORY_TESTING sub->addChild(new LLMenuItemCallGL( "Export Copy", - &force_export_copy, NULL, NULL)); + &force_export_copy, nullptr, nullptr)); sub->addChild(new LLMenuItemCallGL( "Import Geometry", - &force_import_geometry, NULL, NULL)); + &force_import_geometry, nullptr, nullptr)); #endif //sub->addChild(new LLMenuItemCallGL( "Force Public", - // &handle_object_owner_none, NULL, NULL)); + // &handle_object_owner_none, nullptr, nullptr)); //sub->addChild(new LLMenuItemCallGL( "Force Ownership/Permissive", - // &handle_object_owner_self_and_permissive, NULL, NULL, 'K', MASK_SHIFT | MASK_ALT | MASK_CONTROL)); + // &handle_object_owner_self_and_permissive, nullptr, nullptr, 'K', MASK_SHIFT | MASK_ALT | MASK_CONTROL)); sub->addChild(new LLMenuItemCallGL( "Force Owner To Me", &handle_object_owner_self, &is_god_customer_service)); sub->addChild(new LLMenuItemCallGL( "Force Owner Permissive", @@ -1659,11 +1647,11 @@ void init_server_menu(LLMenuGL* menu) //sub->addChild(new LLMenuItemCallGL( "Force Totally Permissive", // &handle_object_permissive)); sub->addChild(new LLMenuItemCallGL( "Delete", - &handle_force_delete, &is_god_customer_service, NULL, KEY_DELETE, MASK_SHIFT | MASK_ALT | MASK_CONTROL)); + &handle_force_delete, &is_god_customer_service, nullptr, KEY_DELETE, MASK_SHIFT | MASK_ALT | MASK_CONTROL)); sub->addChild(new LLMenuItemCallGL( "Lock", - &handle_object_lock, &is_god_customer_service, NULL, 'L', MASK_SHIFT | MASK_ALT | MASK_CONTROL)); + &handle_object_lock, &is_god_customer_service, nullptr, 'L', MASK_SHIFT | MASK_ALT | MASK_CONTROL)); sub->addChild(new LLMenuItemCallGL( "Get Asset IDs", - &handle_object_asset_ids, &is_god_customer_service, NULL, 'I', MASK_SHIFT | MASK_ALT | MASK_CONTROL)); + &handle_object_asset_ids, &is_god_customer_service, nullptr, 'I', MASK_SHIFT | MASK_ALT | MASK_CONTROL)); sub->createJumpKeys(); } { @@ -1672,10 +1660,10 @@ void init_server_menu(LLMenuGL* menu) sub->addChild(new LLMenuItemCallGL("Owner To Me", &handle_force_parcel_owner_to_me, - &is_god_customer_service, NULL)); + &is_god_customer_service, nullptr)); sub->addChild(new LLMenuItemCallGL("Set to Linden Content", &handle_force_parcel_to_content, - &is_god_customer_service, NULL)); + &is_god_customer_service, nullptr)); sub->addSeparator(); sub->addChild(new LLMenuItemCallGL("Claim Public Land", &handle_claim_public_land, &is_god_customer_service)); @@ -1687,14 +1675,14 @@ void init_server_menu(LLMenuGL* menu) menu->addChild(sub); sub->addChild(new LLMenuItemCallGL("Dump Temp Asset Data", &handle_region_dump_temp_asset_data, - &is_god_customer_service, NULL)); + &is_god_customer_service, nullptr)); sub->createJumpKeys(); } menu->addChild(new LLMenuItemCallGL( "God Tools...", - &LLFloaterGodTools::show, &enable_god_basic, NULL)); + &LLFloaterGodTools::show, &enable_god_basic, nullptr)); { - LLMenuItemCallGL* item = new LLMenuItemCallGL("insert_admin", NULL); + LLMenuItemCallGL* item = new LLMenuItemCallGL("insert_admin", nullptr); item->setVisible(false); menu->addChild(item); } @@ -1702,42 +1690,83 @@ void init_server_menu(LLMenuGL* menu) menu->addSeparator(); menu->addChild(new LLMenuItemCallGL("Save Region State", - &LLPanelRegionTools::onSaveState, &is_god_customer_service, NULL)); + &LLPanelRegionTools::onSaveState, &is_god_customer_service, nullptr)); menu->createJumpKeys(); } +////////////////////// +// TOGGLE WIREFRAME // +////////////////////// + +/* +class LLAdvancedToggleWireframe final : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) override +*/ + void advanced_toggle_wireframe(void*) + { +// [RLVa:KB] - Checked: 2013-05-11 (RLVa-1.4.9) + bool fRlvBlockWireframe = gRlvAttachmentLocks.hasLockedHUD(); + if ( (!gUseWireframe) && (fRlvBlockWireframe) ) + { + RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_WIREFRAME); + } + gUseWireframe = (!gUseWireframe) && (!fRlvBlockWireframe); +// [/RLVa:KB] +// gUseWireframe = !(gUseWireframe); +// gWindowResized = TRUE; // Singu Note: We don't use this (yet?) + + LLPipeline::updateRenderDeferred(); + gPipeline.resetVertexBuffers(); +// return true; + } +/* +}; + +class LLAdvancedCheckWireframe final : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) override +*/ + BOOL advanced_check_wireframe(void*) + { + bool new_value = gUseWireframe; + return new_value; + } +//}; + + //----------------------------------------------------------------------------- // cleanup_menus() //----------------------------------------------------------------------------- void cleanup_menus() { delete gMenuParcelObserver; - gMenuParcelObserver = NULL; + gMenuParcelObserver = nullptr; delete gPieSelf; - gPieSelf = NULL; + gPieSelf = nullptr; delete gPieAvatar; - gPieAvatar = NULL; + gPieAvatar = nullptr; delete gPieObject; - gPieObject = NULL; + gPieObject = nullptr; delete gPieAttachment; - gPieAttachment = NULL; + gPieAttachment = nullptr; delete gPieLand; - gPieLand = NULL; + gPieLand = nullptr; delete gMenuBarView; - gMenuBarView = NULL; + gMenuBarView = nullptr; - delete gPopupMenuView; - gPopupMenuView = NULL; + delete gLoginMenuBarView; + gLoginMenuBarView = nullptr; delete gMenuHolder; - gMenuHolder = NULL; + gMenuHolder = nullptr; sMenus.clear(); } @@ -1746,9 +1775,9 @@ void cleanup_menus() // Object pie menu //----------------------------------------------------------------------------- -class LLObjectReportAbuse : public view_listener_t +class LLObjectReportAbuse final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); if (objectp) @@ -1760,9 +1789,9 @@ class LLObjectReportAbuse : public view_listener_t }; // Enabled it you clicked an object -class LLObjectEnableReportAbuse : public view_listener_t +class LLObjectEnableReportAbuse final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = LLSelectMgr::getInstance()->getSelection()->getObjectCount() != 0; gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); @@ -1770,25 +1799,22 @@ class LLObjectEnableReportAbuse : public view_listener_t } }; -class LLObjectTouch : public view_listener_t +class LLObjectTouch final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - handle_object_touch(); + handle_object_touch(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(), &LLToolPie::getInstance()->getPick()); return true; } }; -void handle_object_touch() +void handle_object_touch(LLViewerObject* object, const LLPickInfo* const pick) { - LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); if (!object) return; - LLPickInfo pick = LLToolPie::getInstance()->getPick(); - // [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Modified: RLVa-1.1.0l // NOTE: fallback code since we really shouldn't be getting an active selection if we can't touch this - if ( (rlv_handler_t::isEnabled()) && (!gRlvHandler.canTouch(object, pick.mObjectOffset)) ) + if ( (rlv_handler_t::isEnabled()) && (!gRlvHandler.canTouch(object, pick ? pick->mObjectOffset : LLVector3::zero)) ) { RLV_ASSERT(false); return; @@ -1798,28 +1824,30 @@ void handle_object_touch() // *NOTE: Hope the packets arrive safely and in order or else // there will be some problems. // *TODO: Just fix this bad assumption. - send_ObjectGrab_message(object, pick, LLVector3::zero); - send_ObjectDeGrab_message(object, pick); + send_ObjectGrab_message(object, true, pick); + send_ObjectGrab_message(object, false, pick); } - -bool enable_object_touch(const LLSD& userdata) +bool enable_object_touch(LLViewerObject* obj, const LLVector3& offset = LLVector3::zero) { - LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - bool new_value = obj && obj->flagHandleTouch(); // [RLVa:KB] - Checked: 2010-11-12 (RLVa-1.2.1g) | Added: RLVa-1.2.1g - if ( (rlv_handler_t::isEnabled()) && (new_value) ) + if (new_value && rlv_handler_t::isEnabled()) { // RELEASE-RLVa: [RLVa-1.2.1] Make sure this stays in sync with handle_object_touch() - new_value = gRlvHandler.canTouch(obj, LLToolPie::getInstance()->getPick().mObjectOffset); + new_value = gRlvHandler.canTouch(obj, offset); } // [/RLVa:KB] + return new_value; +} +bool enable_object_touch(const LLSD& userdata) +{ std::string touch_text; // Update label based on the node touch name if available. - LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); + auto selection = LLSelectMgr::getInstance()->getSelection(); + LLSelectNode* node = selection->getFirstRootNode(); if (node && node->mValid && !node->mTouchName.empty()) { touch_text = node->mTouchName; @@ -1831,13 +1859,14 @@ bool enable_object_touch(const LLSD& userdata) gMenuHolder->childSetText("Object Touch", touch_text); gMenuHolder->childSetText("Attachment Object Touch", touch_text); - return new_value; + + return enable_object_touch(selection->getPrimaryObject(), LLToolPie::getInstance()->getPick().mObjectOffset); }; // One object must have touch sensor -class LLObjectEnableTouch : public view_listener_t +class LLObjectEnableTouch final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { gMenuHolder->findControl(userdata["control"].asString())->setValue(enable_object_touch(userdata)); return true; @@ -1866,9 +1895,9 @@ void handle_object_open() // LLFloaterOpenObject::show(); } -class LLObjectOpen : public view_listener_t +class LLObjectOpen final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { handle_object_open(); return true; @@ -1888,9 +1917,9 @@ bool enable_object_open() return root->allowOpen(); } -class LLObjectEnableOpen : public view_listener_t +class LLObjectEnableOpen final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { gMenuHolder->findControl(userdata["control"].asString())->setValue(enable_object_open()); @@ -1898,18 +1927,18 @@ class LLObjectEnableOpen : public view_listener_t } }; -class LLViewJoystickFlycam : public view_listener_t +class LLViewJoystickFlycam final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { handle_toggle_flycam(); return true; } }; -class LLViewCheckJoystickFlycam : public view_listener_t +class LLViewCheckJoystickFlycam final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = LLViewerJoystick::getInstance()->getOverrideCamera(); gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); @@ -1917,32 +1946,15 @@ class LLViewCheckJoystickFlycam : public view_listener_t } }; -class LLViewCommunicate : public view_listener_t -{ - bool handleEvent(LLPointer event, const LLSD& userdata) - { - static LLCachedControl only_comm("CommunicateSpecificShortcut"); - if (!only_comm && LLFloaterChatterBox::getInstance()->getFloaterCount() == 0) - { - LLFloaterMyFriends::toggleInstance(); - } - else - { - LLFloaterChatterBox::toggleInstance(); - } - return true; - } -}; - void handle_toggle_flycam() { LLViewerJoystick::getInstance()->toggleFlycam(); } -class LLObjectBuild : public view_listener_t +class LLObjectBuild final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { if (gAgentCamera.getFocusOnAvatar() && !LLToolMgr::getInstance()->inEdit() && gSavedSettings.getBOOL("EditCameraMovement") ) { @@ -1982,7 +1994,7 @@ void handle_object_edit() { LLObjectSelectionHandle hSel = LLSelectMgr::getInstance()->getSelection(); RlvSelectIsEditable f; - if ((hSel.notNull()) && ((hSel->getFirstRootNode(&f, TRUE)) != NULL)) + if ((hSel.notNull()) && ((hSel->getFirstRootNode(&f, TRUE)) != nullptr)) return; // Can't edit any object under @edit=n } else if ( (gRlvHandler.hasBehaviour(RLV_BHVR_FARTOUCH)) && @@ -2034,9 +2046,9 @@ void handle_object_edit() return; } -class LLObjectEdit : public view_listener_t +class LLObjectEdit final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { handle_object_edit(); return true; @@ -2061,94 +2073,94 @@ void handle_attachment_edit(const LLUUID& idItem) } // [/SL:KB] -class LLObjectInspect : public view_listener_t +bool add_object_to_blacklist( const LLUUID& id, const std::string& entry_name ) { - bool handleEvent(LLPointer event, const LLSD& userdata) + // ...don't kill the avatar + if (id != gAgentID) { - LLFloaterInspect::showInstance(); + LLSD indata; + indata["entry_type"] = LLAssetType::AT_OBJECT; + indata["entry_name"] = entry_name; + indata["entry_agent"] = gAgentID; + + LLFloaterBlacklist::addEntry(id, indata); + LLViewerObject *objectp = gObjectList.findObject(id); + if (objectp) + { + gObjectList.killObject(objectp); + } return true; } -}; + return false; +} // Derenderizer. Originally by Phox. -class LLObjectDerender : public view_listener_t +class LLObjectDerender final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLViewerObject* slct = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); if(!slct)return true; LLUUID id = slct->getID(); - LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); - LLUUID root_key; - //delivers null in linked parts if used as getFirstRootNode() - LLSelectNode* node = selection->getFirstRootNode(NULL,TRUE); - - /*this works for derendering entire object if child is selected - - LLSelectNode* node = selection->getFirstNode(); - //Delivers node even when linked parts, but only first node - - LLViewerObject* obj = node->getObject(); - LLViewerObject* parent = (LLViewerObject*)obj->getParent();*/ - if(node) - { - root_key = node->getObject()->getID(); - llinfos << "Derender node has key " << root_key << llendl; - } - else - { - llinfos << "Derender node is null " << llendl; - } - - LLViewerRegion* cur_region = gAgent.getRegion(); + bool added = false; std::string entry_name; if (slct->isAvatar()) { LLNameValue* firstname = slct->getNVPair("FirstName"); LLNameValue* lastname = slct->getNVPair("LastName"); entry_name = llformat("Derendered: (AV) %s %s",firstname->getString(),lastname->getString()); + added |= add_object_to_blacklist(id, entry_name); } else { - if (root_key.isNull()) + LLViewerRegion* cur_region = gAgent.getRegion(); + + std::list nodes; + for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin(); + iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++) { - return true; + nodes.push_back(*iter); } - id = root_key; - if (!node->mName.empty()) + if (nodes.empty()) { - if(cur_region) - entry_name = llformat("Derendered: %s in region %s",node->mName.c_str(),cur_region->getName().c_str()); - else - entry_name = llformat("Derendered: %s",node->mName.c_str()); + nodes.push_back(LLSelectMgr::getInstance()->getSelection()->getFirstNode()); } - else + + for( auto node : nodes ) { - if(cur_region) - entry_name = llformat("Derendered: (unknown object) in region %s",cur_region->getName().c_str()); + if (node) + { + id = node->getObject()->getID(); + } + if (id.isNull()) + { + continue; + } + LL_INFOS() << "Derender node has key " << id << LL_ENDL; + if (!node->mName.empty()) + { + if (cur_region) + entry_name = llformat("Derendered: %s in region %s", node->mName.c_str(), cur_region->getName().c_str()); + else + entry_name = llformat("Derendered: %s", node->mName.c_str()); + } else - entry_name = "Derendered: (unknown object)"; + { + if (cur_region) + entry_name = llformat("Derendered: (unknown object) in region %s", cur_region->getName().c_str()); + else + entry_name = "Derendered: (unknown object)"; + } + added |= add_object_to_blacklist(id, entry_name); } } - // ...don't kill the avatar - if (id != gAgentID) + if (added) { - LLSD indata; - indata["entry_type"] = 6; //AT_TEXTURE - indata["entry_name"] = entry_name; - indata["entry_agent"] = gAgentID; - - LLFloaterBlacklist::addEntry(id,indata); LLSelectMgr::getInstance()->deselectAll(); - LLViewerObject *objectp = gObjectList.findObject(id); - if (objectp) - { - gObjectList.killObject(objectp); - } } return true; } @@ -2167,12 +2179,12 @@ class LLTextureReloader { LLAppViewer::getTextureCache()->removeFromCache(id); img->forceRefetch(); - for (S32 i = 0; i < img->getNumVolumes(); ++i) + for (S32 i = 0; i < img->getNumVolumes(LLRender::SCULPT_TEX); ++i) { - LLVOVolume* volume = (*(img->getVolumeList()))[i]; + LLVOVolume* volume = (*(img->getVolumeList(LLRender::SCULPT_TEX)))[i]; if (volume && volume->isSculpted()) { - LLSculptParams *sculpt_params = (LLSculptParams *)volume->getParameterEntry(LLNetworkData::PARAMS_SCULPT); + const LLSculptParams *sculpt_params = volume->getSculptParams(); if(sculpt_params->getSculptTexture() == id) volume->notifyMeshLoaded(); } @@ -2209,7 +2221,7 @@ void reload_objects(LLTextureReloader& texture_list, LLViewerObject::const_child if(object->isSculpted() && !object->isMesh()) { - LLSculptParams *sculpt_params = (LLSculptParams *)object->getParameterEntry(LLNetworkData::PARAMS_SCULPT); + const LLSculptParams *sculpt_params = object->getSculptParams(); if(sculpt_params) { texture_list.addTexture(LLViewerTextureManager::getFetchedTexture(sculpt_params->getSculptTexture())); @@ -2219,8 +2231,17 @@ void reload_objects(LLTextureReloader& texture_list, LLViewerObject::const_child for (U8 i = 0; i < object->getNumTEs(); i++) { texture_list.addTexture(object->getTEImage(i)); + const LLTextureEntry* te = object->getTE(i); + if (LLMaterial* mat = te ? te->getMaterialParams().get() : nullptr) + { + if (mat->getSpecularID().notNull()) + texture_list.addTexture(LLViewerTextureManager::getFetchedTexture(mat->getSpecularID())); + if (mat->getNormalID().notNull()) + texture_list.addTexture(LLViewerTextureManager::getFetchedTexture(mat->getNormalID())); + } } + if(recurse) { reload_objects(texture_list,object->getChildren(), true); @@ -2228,9 +2249,9 @@ void reload_objects(LLTextureReloader& texture_list, LLViewerObject::const_child } } -class LLAvatarReloadTextures : public view_listener_t +class LLAvatarReloadTextures final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); if(avatar) @@ -2261,9 +2282,9 @@ class LLAvatarReloadTextures : public view_listener_t return true; } }; -class LLObjectReloadTextures : public view_listener_t +class LLObjectReloadTextures final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLViewerObject::vobj_list_t object_list; @@ -2283,9 +2304,9 @@ class LLObjectReloadTextures : public view_listener_t //--------------------------------------------------------------------------- // Land pie menu //--------------------------------------------------------------------------- -class LLLandBuild : public view_listener_t +class LLLandBuild final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLViewerParcelMgr::getInstance()->deselectLand(); @@ -2315,20 +2336,20 @@ class LLLandBuild : public view_listener_t } }; -class LLLandBuyPass : public view_listener_t +class LLLandBuyPass final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLPanelLandGeneral::onClickBuyPass((void *)FALSE); return true; } }; -class LLLandEnableBuyPass : public view_listener_t +class LLLandEnableBuyPass final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - bool new_value = LLPanelLandGeneral::enableBuyPass(NULL); + bool new_value = LLPanelLandGeneral::enableBuyPass(nullptr); gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); return true; } @@ -2389,16 +2410,16 @@ bool enable_object_edit() { LLObjectSelectionHandle hSel = LLSelectMgr::getInstance()->getSelection(); RlvSelectIsEditable f; - enable = (hSel.notNull()) && ((hSel->getFirstRootNode(&f, TRUE)) == NULL); + enable = (hSel.notNull()) && ((hSel->getFirstRootNode(&f, TRUE)) == nullptr); // [/RLVa:KB] } return enable; } -class LLEnableEdit : public view_listener_t +class LLEnableEdit final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { gMenuHolder->findControl(userdata["control"].asString())->setValue(enable_object_edit()); return true; @@ -2411,17 +2432,17 @@ bool enable_object_select_in_pathfinding_linksets() return LLPathfindingManager::getInstance()->isPathfindingEnabledForCurrentRegion() && LLSelectMgr::getInstance()->selectGetEditableLinksets(); } -class LLObjectEnablePFLinksetsSelected : public view_listener_t +class LLObjectEnablePFLinksetsSelected final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { return enable_object_select_in_pathfinding_linksets(); } }; -class LLObjectPFCharactersSelected : public view_listener_t +class LLObjectPFCharactersSelected final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLFloaterPathfindingCharacters::openCharactersWithSelectedObjects(); return true; @@ -2433,26 +2454,26 @@ bool enable_object_select_in_pathfinding_characters() return LLPathfindingManager::getInstance()->isPathfindingEnabledForCurrentRegion() && LLSelectMgr::getInstance()->selectGetViewableCharacters(); } -class LLObjectEnablePFCharactersSelected : public view_listener_t +class LLObjectEnablePFCharactersSelected final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { return enable_object_select_in_pathfinding_characters(); } }; -class LLSelfRemoveAllAttachments : public view_listener_t +class LLSelfRemoveAllAttachments final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLAppearanceMgr::instance().removeAllAttachmentsFromAvatar(); return true; } }; -class LLSelfEnableRemoveAllAttachments : public view_listener_t +class LLSelfEnableRemoveAllAttachments final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = false; if (isAgentAvatarValid()) @@ -2477,9 +2498,9 @@ class LLSelfEnableRemoveAllAttachments : public view_listener_t } }; -class LLSelfVisibleScriptInfo : public view_listener_t +class LLSelfVisibleScriptInfo final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { if (LLViewerRegion* region = gAgent.getRegion()) gMenuHolder->findControl(userdata["control"].asString())->setValue(!region->getCapability("AttachmentResources").empty()); @@ -2496,15 +2517,22 @@ BOOL enable_has_attachments(void*) //--------------------------------------------------------------------------- // Avatar pie menu //--------------------------------------------------------------------------- -//void handle_follow(void *userdata) -//{ -// // follow a given avatar by ID -// LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); -// if (objectp) -// { -// gAgent.startFollowPilot(objectp->getID()); -// } -//} + +class LLObjectFollow final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + // follow a given avatar by ID + LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (objectp) + { + if (auto av = objectp->getAvatarAncestor()) // Follow the avatar, not a control avatar or an attachment, if possible + objectp = av; + gAgent.startFollowPilot(objectp->getID(), true, gSavedSettings.getF32("SinguFollowDistance")); + } + return true; + } +}; bool enable_object_mute() { @@ -2520,7 +2548,7 @@ bool enable_object_mute() bool is_self = avatar->isSelf(); // return !is_linden && !is_self; // [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) | Added: RLVa-1.2.1b - return !is_linden && !is_self && !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES); + return !is_linden && !is_self && !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES) && !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS); // [/RLVa:KB] } else @@ -2531,18 +2559,18 @@ bool enable_object_mute() } } -class LLObjectEnableMute : public view_listener_t +class LLObjectEnableMute final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { gMenuHolder->findControl(userdata["control"].asString())->setValue(enable_object_mute()); return true; } }; -class LLObjectMute : public view_listener_t +class LLObjectMute final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); if (!object) return true; @@ -2554,7 +2582,7 @@ class LLObjectMute : public view_listener_t if (avatar) { // [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) | Added: RLVa-1.0.0e - if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES) || gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS)) return true; // [/RLVa:KB] id = avatar->getID(); @@ -2592,7 +2620,7 @@ class LLObjectMute : public view_listener_t else { LLMuteList::getInstance()->add(mute); - LLFloaterMute::showInstance(); + LLFloaterMute::showInstance()->selectMute(mute.mID);; } return true; @@ -2600,20 +2628,20 @@ class LLObjectMute : public view_listener_t }; // -class LLObjectEnableCopyUUID : public view_listener_t +class LLObjectEnableCopyUUID final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - bool new_value = (object != NULL); + bool new_value = (object != nullptr); gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); return true; } }; -class LLObjectCopyUUID : public view_listener_t +class LLObjectCopyUUID final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); if(object) @@ -2624,9 +2652,9 @@ class LLObjectCopyUUID : public view_listener_t } }; -class LLObjectData : public view_listener_t +class LLObjectData final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); if(object) @@ -2653,9 +2681,19 @@ class LLObjectData : public view_listener_t } }; -class LLCanIHasKillEmAll : public view_listener_t +class LLSyncAnimations final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + void resync_anims(); + resync_anims(); + return false; + } +}; + +class LLCanIHasKillEmAll final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLViewerObject* objpos = LLSelectMgr::getInstance()->getSelection()->getFirstRootObject(); bool new_value = false; @@ -2671,9 +2709,9 @@ class LLCanIHasKillEmAll : public view_listener_t } }; -class LLOHGOD : public view_listener_t +class LLOHGOD final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLViewerObject* objpos = LLSelectMgr::getInstance()->getSelection()->getFirstRootObject(); bool new_value = false; @@ -2690,9 +2728,9 @@ class LLOHGOD : public view_listener_t } }; -class LLPowerfulWizard : public view_listener_t +class LLPowerfulWizard final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLViewerObject* objpos = LLSelectMgr::getInstance()->getSelection()->getFirstRootObject(); if(objpos) @@ -2726,9 +2764,9 @@ class LLPowerfulWizard : public view_listener_t } }; -class LLKillEmAll : public view_listener_t +class LLKillEmAll final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { // Originally by SimmanFederal // Moved here by a big fat fuckin dog. @@ -2768,9 +2806,9 @@ class LLKillEmAll : public view_listener_t } }; -class LLObjectMeasure : public view_listener_t +class LLObjectMeasure final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { static LLVector3 startMeasurePoint = LLVector3::zero; static bool startpoint_set = false; @@ -2797,7 +2835,7 @@ class LLObjectMeasure : public view_listener_t LLFloaterChat::addChat(chat); LLStringUtil::format_map_t args; - args["[DIST]"] = boost::lexical_cast(dist_vec(startMeasurePoint, position)); + args["[DIST]"] = fmt::to_string(dist_vec(startMeasurePoint, position)); chat.mText = LLTrans::getString("MeasuredDistance", args); startpoint_set = false; @@ -2807,72 +2845,68 @@ class LLObjectMeasure : public view_listener_t } }; -class LLObjectPFLinksetsSelected : public view_listener_t +class LLObjectPFLinksetsSelected final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLFloaterPathfindingLinksets::openLinksetsWithSelectedObjects(); return true; } }; -class LLAvatarAnims : public view_listener_t -{ - bool handleEvent(LLPointer event, const LLSD& userdata) - { - LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); - if(avatar) - { - new LLFloaterExploreAnimations(avatar->getID()); //temporary - } - return true; - } -}; - // -bool handle_go_to() +void simulator_autopilot(const LLVector3d& pos) { - // try simulator autopilot std::vector strings; std::string val; - LLVector3d pos = LLToolPie::getInstance()->getPick().mPosGlobal; - val = llformat("%g", pos.mdV[VX]); + val = llformat("%.9g", pos.mdV[VX]); strings.push_back(val); - val = llformat("%g", pos.mdV[VY]); + val = llformat("%.9g", pos.mdV[VY]); strings.push_back(val); - val = llformat("%g", pos.mdV[VZ]); + val = llformat("%.9g", pos.mdV[VZ]); strings.push_back(val); send_generic_message("autopilot", strings); +} + +void handle_go_to(const LLVector3d& pos) +{ + gAgent.stopAutoPilot(true); // Go To cancels viewer autopilot + + // try simulator autopilot + simulator_autopilot(pos); LLViewerParcelMgr::getInstance()->deselectLand(); - if (isAgentAvatarValid() && !gSavedSettings.getBOOL("AutoPilotLocksCamera")) - { - gAgentCamera.setFocusGlobal(gAgentCamera.getFocusTargetGlobal(), gAgentAvatarp->getID()); - } - else + if (gSavedSettings.getBOOL("SinguMotionResetsCamera")) { - // Snap camera back to behind avatar - gAgentCamera.setFocusOnAvatar(TRUE, ANIMATE); + if (!gSavedSettings.getBOOL("AutoPilotLocksCamera")) + { + gAgentCamera.setFocusGlobal(gAgentCamera.getFocusTargetGlobal(), gAgentID); + } + else + { + // Snap camera back to behind avatar + gAgentCamera.setFocusOnAvatar(TRUE, ANIMATE); + } } // Could be first use LLFirstUse::useGoTo(); - return true; } -class LLGoToObject : public view_listener_t +class LLGoToObject final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - return handle_go_to(); + handle_go_to(LLToolPie::instance().getPick().mPosGlobal); + return true; } }; -class LLAvatarReportAbuse : public view_listener_t +class LLAvatarReportAbuse final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); if(avatar) @@ -2887,62 +2921,56 @@ class LLAvatarReportAbuse : public view_listener_t // Object backup //--------------------------------------------------------------------------- -class LLObjectEnableExport : public view_listener_t +class LLObjectEnableExport final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - LLPermissions perms; - bool new_value = LLSelectMgr::getInstance()->selectGetPermissions(perms) && perms.isOwned(); // At least one object, accumulated permissions of all objects. ExportPolicy export_policy = LFSimFeatureHandler::instance().exportPolicy(); - if (new_value && !(export_policy == ep_export_bit && (perms.getMaskEveryone() & PERM_EXPORT))) // No need to call allowExportBy if PERM_EXPORT is set on (all) root objects. + bool can_export_any = false; + LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); + for (LLObjectSelection::iterator node = selection->begin(); node != selection->end(); ++node) { - bool can_export_any = false; - LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); - for (LLObjectSelection::iterator node = selection->begin(); node != selection->end(); ++node) + if ((*node)->mPermissions->allowExportBy(gAgent.getID(), export_policy)) { - if ((*node)->mPermissions->allowExportBy(gAgent.getID(), export_policy)) - { - can_export_any = true; - break; - } + can_export_any = true; + break; } - new_value = can_export_any; } - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); + gMenuHolder->findControl(userdata["control"].asString())->setValue(can_export_any); return true; } }; -class LLObjectExport : public view_listener_t +class LLObjectExport final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLObjectBackup::getInstance()->exportObject(); return true; } }; -class LLObjectEnableImport : public view_listener_t +class LLObjectEnableImport final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { gMenuHolder->findControl(userdata["control"].asString())->setValue(TRUE); return true; } }; -class LLObjectImport : public view_listener_t +class LLObjectImport final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLObjectBackup::getInstance()->importObject(FALSE); return true; } }; -class LLObjectImportUpload : public view_listener_t +class LLObjectImportUpload final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLObjectBackup::getInstance()->importObject(TRUE); return true; @@ -2952,6 +2980,7 @@ class LLObjectImportUpload : public view_listener_t //--------------------------------------------------------------------------- // Parcel freeze, eject, etc. //--------------------------------------------------------------------------- +void send_freeze(const LLUUID& avatar_id, bool freeze); bool callback_freeze(const LLSD& notification, const LLSD& response) { LLUUID avatar_id = notification["payload"]["avatar_id"].asUUID(); @@ -2959,27 +2988,7 @@ bool callback_freeze(const LLSD& notification, const LLSD& response) if (0 == option || 1 == option) { - U32 flags = KICK_FLAGS_FREEZE; - if (1 == option) - { - // unfreeze - flags |= KICK_FLAGS_UNFREEZE; - } - - LLMessageSystem* msg = gMessageSystem; - LLVOAvatar* avatarp = gObjectList.findAvatar(avatar_id); - - if (avatarp && avatarp->getRegion()) - { - msg->newMessage("FreezeUser"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID()); - msg->addUUID("SessionID", gAgent.getSessionID()); - msg->nextBlock("Data"); - msg->addUUID("TargetID", avatar_id ); - msg->addU32("Flags", flags ); - msg->sendReliable( avatarp->getRegion()->getHost() ); - } + send_freeze(avatar_id, !option); } return false; } @@ -2988,7 +2997,7 @@ bool callback_freeze(const LLSD& notification, const LLSD& response) void handle_avatar_freeze(const LLSD& avatar_id) { // Use avatar_id if available, otherwise default to right-click avatar - LLVOAvatar* avatar = NULL; + LLVOAvatar* avatar = nullptr; if (avatar_id.asUUID().notNull()) { avatar = find_avatar_from_object(avatar_id.asUUID()); @@ -3010,7 +3019,7 @@ void handle_avatar_freeze(const LLSD& avatar_id) LLSD args; // args["AVATAR_NAME"] = fullname; // [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.0.0e - args["AVATAR_NAME"] = (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) ? fullname : RlvStrings::getAnonym(fullname); + args["AVATAR_NAME"] = (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES) && !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS)) ? fullname : RlvStrings::getAnonym(fullname); // [/RLVa:KB] LLNotificationsUtil::add("FreezeAvatarFullname", args, @@ -3027,73 +3036,74 @@ void handle_avatar_freeze(const LLSD& avatar_id) } } -class LLAvatarFreeze : public view_listener_t +class LLAvatarFreeze final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { handle_avatar_freeze(LLUUID::null); return true; } }; -class LLScriptCount : public view_listener_t +void do_script_count(bool del, LLViewerObject* object = nullptr) { - bool handleEvent(LLPointer event, const LLSD& userdata) + if (object || (object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject())) { - if (LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()) - { - ScriptCounter* sc = new ScriptCounter(false, object); - sc->requestInventories(); - // sc will destroy itself - } + if (ScriptCounter::getInstance(object->getID())) return; + ScriptCounter* sc = new ScriptCounter(del, object); + sc->requestInventories(); + // sc will destroy itself + } +} + +class LLScriptCount final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + do_script_count(false, userdata["data"].asString() == "agent" ? gAgentAvatarp : nullptr); return true; } }; -class LLScriptDelete : public view_listener_t +class LLScriptDelete final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - if (LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()) - { - ScriptCounter* sc = new ScriptCounter(true, object); - sc->requestInventories(); - // sc will destroy itself - } + do_script_count(true); return true; } }; -class LLObjectVisibleScriptCount : public view_listener_t +class LLObjectVisibleScriptCount final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - bool new_value = (object != NULL); + LLViewerObject* object = userdata["data"].asString() == "agent" ? gAgentAvatarp : LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + bool new_value = (object != nullptr); gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); return true; } }; -class LLObjectEnableScriptDelete : public view_listener_t +class LLObjectEnableScriptDelete final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - bool new_value = (object != NULL); + auto objects = LLSelectMgr::getInstance()->getSelection(); + LLViewerObject* object = objects->getPrimaryObject(); + bool new_value = (object != nullptr); if(new_value) - for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin(); - iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++) + for (LLObjectSelection::root_iterator iter = objects->root_begin(); + iter != objects->root_end(); iter++) { LLSelectNode* selectNode = *iter; LLViewerObject* object = selectNode->getObject(); - if(object) - if(!object->permModify()) - { - new_value=false; - break; - } + if (object && !object->permModify()) + { + new_value=false; + break; + } } gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); @@ -3101,18 +3111,18 @@ class LLObjectEnableScriptDelete : public view_listener_t } }; -class LLAvatarVisibleDebug : public view_listener_t +class LLAvatarVisibleDebug final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { gMenuHolder->findControl(userdata["control"].asString())->setValue(gAgent.isGodlike()); return true; } }; -class LLAvatarDebug : public view_listener_t +class LLAvatarDebug final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { if (isAgentAvatarValid()) { @@ -3180,7 +3190,7 @@ bool callback_eject(const LLSD& notification, const LLSD& response) void handle_avatar_eject(const LLSD& avatar_id) { // Use avatar_id if available, otherwise default to right-click avatar - LLVOAvatar* avatar = NULL; + LLVOAvatar* avatar = nullptr; if (avatar_id.asUUID().notNull()) { avatar = find_avatar_from_object(avatar_id.asUUID()); @@ -3208,7 +3218,7 @@ void handle_avatar_eject(const LLSD& avatar_id) LLSD args; // args["AVATAR_NAME"] = fullname; // [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.0.0e - args["AVATAR_NAME"] = (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) ? fullname : RlvStrings::getAnonym(fullname); + args["AVATAR_NAME"] = (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES) && !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS)) ? fullname : RlvStrings::getAnonym(fullname); // [/RLVa:KB] LLNotificationsUtil::add("EjectAvatarFullname", args, @@ -3231,7 +3241,7 @@ void handle_avatar_eject(const LLSD& avatar_id) LLSD args; // args["AVATAR_NAME"] = fullname; // [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.0.0e - args["AVATAR_NAME"] = (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) ? fullname : RlvStrings::getAnonym(fullname); + args["AVATAR_NAME"] = (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES) && !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS)) ? fullname : RlvStrings::getAnonym(fullname); // [/RLVa:KB] LLNotificationsUtil::add("EjectAvatarFullnameNoBan", args, @@ -3249,9 +3259,9 @@ void handle_avatar_eject(const LLSD& avatar_id) } } -class LLAvatarEject : public view_listener_t +class LLAvatarEject final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { handle_avatar_eject(LLUUID::null); return true; @@ -3259,9 +3269,9 @@ class LLAvatarEject : public view_listener_t }; -class LLAvatarCopyUUID : public view_listener_t +class LLAvatarCopyUUID final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); if(!avatar) return true; @@ -3271,9 +3281,9 @@ class LLAvatarCopyUUID : public view_listener_t } }; -class LLAvatarClientUUID : public view_listener_t +class LLAvatarClientUUID final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); if(!avatar) return true; @@ -3286,7 +3296,7 @@ class LLAvatarClientUUID : public view_listener_t bool enable_freeze_eject(const LLSD& avatar_id) { // Use avatar_id if available, otherwise default to right-click avatar - LLVOAvatar* avatar = NULL; + LLVOAvatar* avatar = nullptr; if (avatar_id.asUUID().notNull()) { avatar = find_avatar_from_object(avatar_id.asUUID()); @@ -3317,44 +3327,48 @@ bool enable_freeze_eject(const LLSD& avatar_id) return new_value; } -class LLAvatarEnableFreezeEject : public view_listener_t +class LLAvatarEnableFreezeEject final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { gMenuHolder->findControl(userdata["control"].asString())->setValue(enable_freeze_eject(LLUUID::null)); return true; } }; -class LLAvatarGiveCard : public view_listener_t +class LLAvatarGiveCard final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - llinfos << "handle_give_card()" << llendl; + LL_INFOS() << "handle_give_card()" << LL_ENDL; LLViewerObject* dest = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); -// if(dest && dest->isAvatar()) -// [RLVa:KB] - Checked: 2010-06-04 (RLVa-1.2.0d) | Modified: RLVa-1.2.0d | OK - if ( (dest && dest->isAvatar()) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) ) -// [/RLVa:KB] + if (dest && dest->isAvatar()) { bool found_name = false; LLSD args; - LLSD old_args; - LLNameValue* nvfirst = dest->getNVPair("FirstName"); - LLNameValue* nvlast = dest->getNVPair("LastName"); - if(nvfirst && nvlast) +// [RLVa:KB] - Checked: 2010-06-04 (RLVa-1.2.0d) | Modified: RLVa-1.2.0d | OK + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES) || gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS)) { - args["NAME"] = std::string(nvfirst->getString()) + " " + nvlast->getString(); - old_args["NAME"] = std::string(nvfirst->getString()) + " " + nvlast->getString(); + args["NAME"] = RlvStrings::getString(RLV_STRING_HIDDEN); found_name = true; } - LLViewerRegion* region = dest->getRegion(); + else +// [/RLVa:KB] + { + LLNameValue* nvfirst = dest->getNVPair("FirstName"); + LLNameValue* nvlast = dest->getNVPair("LastName"); + if (nvfirst && nvlast) + { + args["NAME"] = std::string(nvfirst->getString()) + " " + nvlast->getString(); + found_name = true; + } + } LLHost dest_host; - if(region) + if (LLViewerRegion* region = dest->getRegion()) { dest_host = region->getHost(); } - if(found_name && dest_host.isOk()) + if (found_name && dest_host.isOk()) { LLMessageSystem* msg = gMessageSystem; msg->newMessage("OfferCallingCard"); @@ -3371,7 +3385,7 @@ class LLAvatarGiveCard : public view_listener_t } else { - LLNotificationsUtil::add("CantOfferCallingCard", old_args); + LLNotificationsUtil::add("CantOfferCallingCard", args); } } return true; @@ -3423,7 +3437,7 @@ bool enable_buy_object() // In order to buy, there must only be 1 purchaseable object in // the selection manager. if(LLSelectMgr::getInstance()->getSelection()->getRootObjectCount() != 1) return false; - LLViewerObject* obj = NULL; + LLViewerObject* obj = nullptr; LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); if(node) { @@ -3442,9 +3456,9 @@ bool enable_buy_object() } -class LLObjectEnableBuy : public view_listener_t +class LLObjectEnableBuy final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = enable_buy_object(); gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); @@ -3500,7 +3514,7 @@ void handle_buy_contents(LLSaleInfo sale_info) void handle_region_dump_temp_asset_data(void*) { - llinfos << "Dumping temporary asset data to simulator logs" << llendl; + LL_INFOS() << "Dumping temporary asset data to simulator logs" << LL_ENDL; std::vector strings; LLUUID invoice; send_generic_message("dumptempassetdata", strings, invoice); @@ -3508,7 +3522,7 @@ void handle_region_dump_temp_asset_data(void*) void handle_region_clear_temp_asset_data(void*) { - llinfos << "Clearing temporary asset data" << llendl; + LL_INFOS() << "Clearing temporary asset data" << LL_ENDL; std::vector strings; LLUUID invoice; send_generic_message("cleartempassetdata", strings, invoice); @@ -3519,14 +3533,14 @@ void handle_region_dump_settings(void*) LLViewerRegion* regionp = gAgent.getRegion(); if (regionp) { - llinfos << "Damage: " << (regionp->getAllowDamage() ? "on" : "off") << llendl; - llinfos << "Landmark: " << (regionp->getAllowLandmark() ? "on" : "off") << llendl; - llinfos << "SetHome: " << (regionp->getAllowSetHome() ? "on" : "off") << llendl; - llinfos << "ResetHome: " << (regionp->getResetHomeOnTeleport() ? "on" : "off") << llendl; - llinfos << "SunFixed: " << (regionp->getSunFixed() ? "on" : "off") << llendl; - llinfos << "BlockFly: " << (regionp->getBlockFly() ? "on" : "off") << llendl; - llinfos << "AllowP2P: " << (regionp->getAllowDirectTeleport() ? "on" : "off") << llendl; - llinfos << "Water: " << (regionp->getWaterHeight()) << llendl; + LL_INFOS() << "Damage: " << (regionp->getAllowDamage() ? "on" : "off") << LL_ENDL; + LL_INFOS() << "Landmark: " << (regionp->getAllowLandmark() ? "on" : "off") << LL_ENDL; + LL_INFOS() << "SetHome: " << (regionp->getAllowSetHome() ? "on" : "off") << LL_ENDL; + LL_INFOS() << "ResetHome: " << (regionp->getResetHomeOnTeleport() ? "on" : "off") << LL_ENDL; + LL_INFOS() << "SunFixed: " << (regionp->getSunFixed() ? "on" : "off") << LL_ENDL; + LL_INFOS() << "BlockFly: " << (regionp->getBlockFly() ? "on" : "off") << LL_ENDL; + LL_INFOS() << "AllowP2P: " << (regionp->getAllowDirectTeleport() ? "on" : "off") << LL_ENDL; + LL_INFOS() << "Water: " << (regionp->getWaterHeight()) << LL_ENDL; } } @@ -3562,13 +3576,14 @@ void handle_dump_focus(void *) { LLUICtrl *ctrl = dynamic_cast(gFocusMgr.getKeyboardFocus()); - llinfos << "Keyboard focus " << (ctrl ? ctrl->getName() : "(none)") << llendl; + LL_INFOS() << "Keyboard focus " << (ctrl ? ctrl->getName() : "(none)") << LL_ENDL; } -class LLSelfSitOrStand : public view_listener_t +class LLSelfSitOrStand final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { + gAgent.stopAutoPilot(true); if (gAgentAvatarp && gAgentAvatarp->isSitting()) { gAgent.standUp(); @@ -3600,9 +3615,9 @@ bool enable_sitdown_self() // return isAgentAvatarValid() && !gAgentAvatarp->isSitting() && !gAgent.getFlying(); } -class LLSelfEnableSitOrStand : public view_listener_t +class LLSelfEnableSitOrStand final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { std::string label; std::string sit_text; @@ -3658,7 +3673,6 @@ void set_god_level(U8 god_level) { U8 old_god_level = gAgent.getGodLevel(); gAgent.setGodLevel( god_level ); - gIMMgr->refresh(); LLViewerParcelMgr::getInstance()->notifyObservers(); // Some classifieds change visibility on god mode @@ -3719,7 +3733,7 @@ void process_grant_godlike_powers(LLMessageSystem* msg, void**) } else { - llwarns << "Grant godlike for wrong agent " << agent_id << llendl; + LL_WARNS() << "Grant godlike for wrong agent " << agent_id << LL_ENDL; } } @@ -3730,18 +3744,7 @@ void handle_open_message_log(void*) LLFloaterMessageLog::show(); } -void handle_close_all_notifications(void*) -{ - LLView::child_list_t child_list(*(gNotifyBoxView->getChildList())); - for(LLView::child_list_iter_t iter = child_list.begin(); - iter != child_list.end(); - iter++) - { - gNotifyBoxView->removeChild(*iter); - } -} - -void handle_fake_away_status(void*) +void handle_fake_away_status(void*) { bool fake_away = gSavedSettings.getBOOL("FakeAway"); gAgent.sendAnimationRequest(ANIM_AGENT_AWAY, fake_away ? ANIM_REQUEST_STOP : ANIM_REQUEST_START); @@ -3751,7 +3754,7 @@ void handle_fake_away_status(void*) // /* -class LLHaveCallingcard : public LLInventoryCollectFunctor +class LLHaveCallingcard final : public LLInventoryCollectFunctor { public: LLHaveCallingcard(const LLUUID& agent_id); @@ -3797,14 +3800,14 @@ BOOL is_agent_mappable(const LLUUID& agent_id) // Enable a menu item when you don't have someone's card. -class LLAvatarEnableAddFriend : public view_listener_t +class LLAvatarEnableAddFriend final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLVOAvatar* avatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); // bool new_value = avatar && !LLAvatarActions::isFriend(avatar->getID()); // [RLVa:KB] - Checked: 2010-04-20 (RLVa-1.2.0f) | Modified: RLVa-1.2.0f - bool new_value = avatar && !LLAvatarActions::isFriend(avatar->getID()) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)); + bool new_value = avatar && !LLAvatarActions::isFriend(avatar->getID()) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES) && !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS)); // [/RLVa:KB] gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); return true; @@ -3836,9 +3839,9 @@ void request_friendship(const LLUUID& dest_id) } -class LLEditEnableCustomizeAvatar : public view_listener_t +class LLEditEnableCustomizeAvatar final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = (gAgentAvatarp && gAgentAvatarp->isFullyLoaded() && @@ -3849,14 +3852,13 @@ class LLEditEnableCustomizeAvatar : public view_listener_t }; -class LLEditEnableChangeDisplayname : public view_listener_t +class LLEditEnableChangeDisplayname final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) - { - bool new_value = LLAvatarNameCache::useDisplayNames(); - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); - return true; - } + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + gMenuHolder->findControl(userdata["control"].asString())->setValue(LLAvatarName::useDisplayNames()); + return true; + } }; bool is_object_sittable() @@ -3884,28 +3886,14 @@ bool is_object_sittable() } -// only works on pie menu -void handle_object_sit_or_stand() +void handle_object_sit(LLViewerObject* object, const LLVector3& offset = LLVector3::zero) { - LLPickInfo pick = LLToolPie::getInstance()->getPick(); - LLViewerObject *object = pick.getObject();; - if (!object || pick.mPickType == LLPickInfo::PICK_FLORA) - { - return; - } - - if (sitting_on_selection()) - { - gAgent.standUp(); - return; - } - // get object selection offset // if (object && object->getPCode() == LL_PCODE_VOLUME) // [RLVa:KB] - Checked: 2010-03-06 (RLVa-1.2.0c) | Modified: RLVa-1.2.0c if ( (object && object->getPCode() == LL_PCODE_VOLUME) && - ((!rlv_handler_t::isEnabled()) || (gRlvHandler.canSit(object, pick.mObjectOffset))) ) + ((!rlv_handler_t::isEnabled()) || (gRlvHandler.canSit(object, offset))) ) // [/RLVa:KB] { // [RLVa:KB] - Checked: 2010-08-29 (RLVa-1.2.1c) | Added: RLVa-1.2.1c @@ -3926,15 +3914,36 @@ void handle_object_sit_or_stand() gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); gMessageSystem->nextBlockFast(_PREHASH_TargetObject); gMessageSystem->addUUIDFast(_PREHASH_TargetID, object->mID); - gMessageSystem->addVector3Fast(_PREHASH_Offset, pick.mObjectOffset); + gMessageSystem->addVector3Fast(_PREHASH_Offset, offset); object->getRegion()->sendReliableMessage(); } } -class LLObjectSitOrStand : public view_listener_t +// only works on pie menu +void handle_object_sit_or_stand() +{ + LLPickInfo pick = LLToolPie::getInstance()->getPick(); + LLViewerObject *object = pick.getObject();; + if (!object || pick.mPickType == LLPickInfo::PICK_FLORA) + { + return; + } + + gAgent.stopAutoPilot(true); + + if (sitting_on_selection()) + { + gAgent.standUp(); + return; + } + + handle_object_sit(object, pick.mObjectOffset); +} + +class LLObjectSitOrStand final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { handle_object_sit_or_stand(); return true; @@ -3954,12 +3963,12 @@ void near_sit_down_point(BOOL success, void *) } } -class LLLandSit : public view_listener_t +class LLLandSit final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { // [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.2.1f - if ( (rlv_handler_t::isEnabled()) && ((!gRlvHandler.canStand()) || (gRlvHandler.hasBehaviour(RLV_BHVR_SIT))) ) + if ( (rlv_handler_t::isEnabled()) && ((!RlvActions::canStand()) || (gRlvHandler.hasBehaviour(RLV_BHVR_SIT))) ) return true; // [/RLVa:KB] @@ -3977,45 +3986,35 @@ class LLLandSit : public view_listener_t { target_rot = gAgent.getFrameAgent().getQuaternion(); } - gAgent.startAutoPilotGlobal(posGlobal, "Sit", &target_rot, near_sit_down_point, NULL, 0.7f); + gAgent.startAutoPilotGlobal(posGlobal, "Sit", &target_rot, near_sit_down_point, nullptr, 0.7f); return true; } }; -class LLCreateLandmarkCallback : public LLInventoryCallback +class LLCreateLandmarkCallback final : public LLInventoryCallback { public: - /*virtual*/ void fire(const LLUUID& inv_item) + void fire(const LLUUID& inv_item) override { - llinfos << "Created landmark with inventory id " << inv_item - << llendl; + LL_INFOS() << "Created landmark with inventory id " << inv_item + << LL_ENDL; } }; -class LLWorldFly : public view_listener_t +class LLWorldFly final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { gAgent.toggleFlying(); return true; } }; -class LLWorldEnableFly : public view_listener_t +class LLWorldEnableFly final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - BOOL sitting = FALSE; - static LLCachedControl continue_flying_on_unsit("LiruContinueFlyingOnUnsit"); - if (continue_flying_on_unsit) - { - sitting = false; - } - else if (gAgentAvatarp) - { - sitting = gAgentAvatarp->isSitting(); - } - gMenuHolder->findControl(userdata["control"].asString())->setValue(!sitting); + gMenuHolder->findControl(userdata["control"].asString())->setValue(gAgent.enableFlying()); return true; } }; @@ -4053,7 +4052,7 @@ void velocity_interpolate( void* data ) msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); gAgent.sendReliableMessage(); - llinfos << "Velocity Interpolation On" << llendl; + LL_INFOS() << "Velocity Interpolation On" << LL_ENDL; } else { @@ -4062,7 +4061,7 @@ void velocity_interpolate( void* data ) msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); gAgent.sendReliableMessage(); - llinfos << "Velocity Interpolation Off" << llendl; + LL_INFOS() << "Velocity Interpolation Off" << LL_ENDL; } // BUG this is a hack because of the change in menu behavior. The // old menu system would automatically change a control's value, @@ -4096,13 +4095,18 @@ void handle_reset_view() } else { + if (gAgent.getAutoPilot()) + { + gAgent.stopAutoPilot(true); + } + reset_view_final( true ); } } -class LLViewResetView : public view_listener_t +class LLViewResetView final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { handle_reset_view(); return true; @@ -4117,52 +4121,64 @@ void reset_view_final( BOOL proceed ) return; } + if (gRlvHandler.hasBehaviour(RLV_BHVR_CAMDISTMAX) && gRlvHandler.camPole(RLV_BHVR_CAMDISTMAX) <= 0) return; // RLVa:LF - Trapped in mouselook; avoid extra work (and potential glitches) + + if (!gViewerWindow->getLeftMouseDown() && gAgentCamera.cameraThirdPerson() && gSavedSettings.getBOOL("ResetViewTurnsAvatar") && !gSavedSettings.getBOOL("FreezeTime")) + { + gAgentCamera.setFocusOnAvatar(TRUE, ANIMATE); + } + gAgentCamera.switchCameraPreset(CAMERA_PRESET_REAR_VIEW); + if (wlfPanel_AdvSettings::instanceExists()) // Fix up the buttons on the wlf panel to match the preset switch + { + wlfPanel_AdvSettings& inst(wlfPanel_AdvSettings::instance()); + if (inst.isExpanded()) + { + inst.getChildView("Rear")->setValue(true); + inst.getChildView("Front")->setValue(false); + inst.getChildView("Group")->setValue(false); + } + } gAgentCamera.resetView(TRUE, TRUE); gAgentCamera.setLookAt(LOOKAT_TARGET_CLEAR); + if (gSavedSettings.getBOOL("SinguMotionResetsCameraReset")) + gSavedSettings.setBOOL("SinguMotionResetsCamera", true); if(gAgentCamera.cameraCustomizeAvatar() && LLFloaterCustomize::instanceExists()) LLFloaterCustomize::getInstance()->close(); } -class LLViewLookAtLastChatter : public view_listener_t +class LLViewResetPresetAngles final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - gAgentCamera.lookAtLastChat(); + gAgentCamera.resetPresetOffsets(); return true; } }; -class LLViewMouselook : public view_listener_t +class LLViewLookAtLastChatter final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - if (!gAgentCamera.cameraMouselook()) - { - gAgentCamera.changeCameraToMouselook(); - } - else - { - gAgentCamera.changeCameraToDefault(); - } + gAgentCamera.lookAtLastChat(); return true; } }; -class LLViewFullscreen : public view_listener_t +class LLViewFullscreen final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { gViewerWindow->toggleFullscreen(TRUE); return true; } }; -class LLViewDefaultUISize : public view_listener_t +class LLViewDefaultUISize final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { gSavedSettings.setF32("UIScaleFactor", 1.0f); gSavedSettings.setBOOL("UIAutoScale", FALSE); @@ -4171,9 +4187,9 @@ class LLViewDefaultUISize : public view_listener_t } }; -class LLEditDuplicate : public view_listener_t +class LLEditDuplicate final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { // [RLVa:KB] - Checked: 2009-07-05 (RLVa-1.0.0b) if ( (rlv_handler_t::isEnabled()) && (gRlvHandler.hasBehaviour(RLV_BHVR_REZ)) && @@ -4191,9 +4207,9 @@ class LLEditDuplicate : public view_listener_t } }; -class LLEditEnableDuplicate : public view_listener_t +class LLEditEnableDuplicate final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canDuplicate(); // [RLVa:KB] - Checked: 2009-07-05 (RLVa-1.0.0b) @@ -4210,13 +4226,14 @@ class LLEditEnableDuplicate : public view_listener_t void handle_duplicate_in_place(void*) { - llinfos << "handle_duplicate_in_place" << llendl; + LL_INFOS() << "handle_duplicate_in_place" << LL_ENDL; LLVector3 offset(0.f, 0.f, 0.f); LLSelectMgr::getInstance()->selectDuplicate(offset, TRUE); } /* dead code 30-apr-2008 +#include "llviewerstats.h" void handle_deed_object_to_group(void*) { LLUUID group_id; @@ -4369,7 +4386,6 @@ void handle_claim_public_land(void*) void handle_dump_archetype_xml(void *) { - std::string emptyname; LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); if (!avatar) @@ -4389,7 +4405,7 @@ void handle_dump_archetype_xml_continued(LLVOAvatar* avatar, AIFilePicker* filep { if (!filepicker->hasFilename()) { - llwarns << "No file" << llendl; + LL_WARNS() << "No file" << LL_ENDL; return; } avatar->dumpArchetypeXML_cont(filepicker->getFilename(), false); @@ -4408,7 +4424,7 @@ static bool get_derezzable_objects( EDeRezDestination dest, std::string& error, LLViewerRegion*& first_region, - LLDynamicArray* derez_objectsp, + std::vector* derez_objectsp, bool only_check = false) { bool found = false; @@ -4451,7 +4467,7 @@ static bool get_derezzable_objects( && dest != DRD_RETURN_TO_OWNER) { // this object is an asset container, derez its contents, not it - llwarns << "Attempt to derez deprecated AssetContainer object type not supported." << llendl; + LL_WARNS() << "Attempt to derez deprecated AssetContainer object type not supported." << LL_ENDL; /* object->requestInventory(container_inventory_arrived, (void *)(BOOL)(DRD_TAKE_INTO_AGENT_INVENTORY == dest)); @@ -4472,7 +4488,10 @@ static bool get_derezzable_objects( break; case DRD_RETURN_TO_OWNER: - can_derez_current = TRUE; + if(!object->isAttachment()) + { + can_derez_current = TRUE; + } break; default: @@ -4493,7 +4512,7 @@ static bool get_derezzable_objects( break; if (derez_objectsp) - derez_objectsp->put(object); + derez_objectsp->push_back(object); } } @@ -4503,9 +4522,9 @@ static bool get_derezzable_objects( static bool can_derez(EDeRezDestination dest) { - LLViewerRegion* first_region = NULL; + LLViewerRegion* first_region = nullptr; std::string error; - return get_derezzable_objects(dest, error, first_region, NULL, true); + return get_derezzable_objects(dest, error, first_region, nullptr, true); } static void derez_objects( @@ -4513,16 +4532,16 @@ static void derez_objects( const LLUUID& dest_id, LLViewerRegion*& first_region, std::string& error, - LLDynamicArray* objectsp) + std::vector* objectsp) { - LLDynamicArray derez_objects; + std::vector derez_objects; if (!objectsp) // if objects to derez not specified { // get them from selection if (!get_derezzable_objects(dest, error, first_region, &derez_objects, false)) { - llwarns << "No objects to derez" << llendl; + LL_WARNS() << "No objects to derez" << LL_ENDL; return; } @@ -4542,13 +4561,13 @@ static void derez_objects( // satisfy anybody. const S32 MAX_ROOTS_PER_PACKET = 250; const S32 MAX_PACKET_COUNT = 254; - F32 packets = ceil((F32)objectsp->count() / (F32)MAX_ROOTS_PER_PACKET); + F32 packets = ceil((F32)objectsp->size() / (F32)MAX_ROOTS_PER_PACKET); if(packets > (F32)MAX_PACKET_COUNT) { error = "AcquireErrorTooManyObjects"; } - if(error.empty() && objectsp->count() > 0) + if(error.empty() && objectsp->size() > 0) { U8 d = (U8)dest; LLUUID tid; @@ -4573,24 +4592,20 @@ static void derez_objects( msg->addU8Fast(_PREHASH_PacketCount, packet_count); msg->addU8Fast(_PREHASH_PacketNumber, packet_number); objects_in_packet = 0; - while((object_index < objectsp->count()) + while((object_index < (S32)objectsp->size()) && (objects_in_packet++ < MAX_ROOTS_PER_PACKET)) { - LLViewerObject* object = objectsp->get(object_index++); + LLViewerObject* object = objectsp->at(object_index++); msg->nextBlockFast(_PREHASH_ObjectData); msg->addU32Fast(_PREHASH_ObjectLocalID, object->getLocalID()); - // if(!gSavedSettings.getBOOL("DisablePointAtAndBeam")) { - // // VEFFECT: DerezObject LLHUDEffectSpiral* effectp = (LLHUDEffectSpiral*)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE); effectp->setPositionGlobal(object->getPositionGlobal()); effectp->setColor(LLColor4U(gAgent.getEffectColor())); - // } - // } msg->sendReliable(first_region->getHost()); } @@ -4611,14 +4626,14 @@ static void derez_objects( static void derez_objects(EDeRezDestination dest, const LLUUID& dest_id) { - LLViewerRegion* first_region = NULL; + LLViewerRegion* first_region = nullptr; std::string error; - derez_objects(dest, dest_id, first_region, error, NULL); + derez_objects(dest, dest_id, first_region, error, nullptr); } -class LLToolsTakeCopy : public view_listener_t +class LLToolsTakeCopy final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { handle_take_copy(); return true; @@ -4630,12 +4645,12 @@ void handle_take_copy() if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return; // [RLVa:KB] - Checked: 2010-03-07 (RLVa-1.2.0c) | Modified: RLVa-1.2.0a - if ( (rlv_handler_t::isEnabled()) && (!gRlvHandler.canStand()) ) + if ( (rlv_handler_t::isEnabled()) && (!RlvActions::canStand()) ) { // Allow only if the avie isn't sitting on any of the selected objects LLObjectSelectionHandle hSel = LLSelectMgr::getInstance()->getSelection(); RlvSelectIsSittingOn f(gAgentAvatarp); - if ( (hSel.notNull()) && (hSel->getFirstRootNode(&f, TRUE) != NULL) ) + if ( (hSel.notNull()) && (hSel->getFirstRootNode(&f, TRUE) != nullptr) ) return; } // [/RLVa:KB] @@ -4645,13 +4660,13 @@ void handle_take_copy() } // You can return an object to its owner if it is on your land. -class LLObjectReturn : public view_listener_t +class LLObjectReturn final : public view_listener_t { public: - LLObjectReturn() : mFirstRegion(NULL) {} + LLObjectReturn() : mFirstRegion(nullptr) {} private: - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return true; // [RLVa:KB] - Checked: 2010-03-24 (RLVa-1.4.0a) | Modified: RLVa-1.0.0b @@ -4678,16 +4693,16 @@ class LLObjectReturn : public view_listener_t mReturnableObjects.clear(); mError.clear(); - mFirstRegion = NULL; + mFirstRegion = nullptr; // drop reference to current selection - mObjectSelection = NULL; + mObjectSelection = nullptr; return false; } LLObjectSelectionHandle mObjectSelection; - LLDynamicArray mReturnableObjects; + std::vector mReturnableObjects; std::string mError; LLViewerRegion* mFirstRegion; }; @@ -4695,9 +4710,9 @@ class LLObjectReturn : public view_listener_t // Allow return to owner if one or more of the selected items is // over land you own. -class LLObjectEnableReturn : public view_listener_t +class LLObjectEnableReturn final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) { @@ -4789,7 +4804,7 @@ void handle_take() // such a location and it is not in the trash or library if(!gInventory.getCategory(category_id)) { - // nope, set to NULL. + // nope, set to nullptr. category_id.setNull(); } if(category_id.notNull()) @@ -4930,9 +4945,9 @@ void handle_buy_or_take() } } -class LLToolsBuyOrTake : public view_listener_t +class LLToolsBuyOrTake final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { handle_buy_or_take(); return true; @@ -4944,9 +4959,9 @@ bool visible_take_object() return !is_selection_buy_not_take() && enable_take(); } -class LLToolsEnableBuyOrTake : public view_listener_t +class LLToolsEnableBuyOrTake final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool is_buy = is_selection_buy_not_take(); bool new_value = is_buy ? enable_buy_object() : enable_take(); @@ -5035,7 +5050,7 @@ bool callback_show_buy_currency(const LLSD& notification, const LLSD& response) S32 option = LLNotification::getSelectedOption(notification, response); if (0 == option) { - llinfos << "Loading page " << BUY_CURRENCY_URL << llendl; + LL_INFOS() << "Loading page " << BUY_CURRENCY_URL << LL_ENDL; LLWeb::loadURL(BUY_CURRENCY_URL); } return false; @@ -5047,14 +5062,14 @@ void show_buy_currency(const char* extra) // Don't show currency web page for branded clients. std::ostringstream mesg; - if (extra != NULL) + if (extra != nullptr) { mesg << extra << "\n \n"; } mesg << "Go to " << BUY_CURRENCY_URL << "\nfor information on purchasing currency?"; LLSD args; - if (extra != NULL) + if (extra != nullptr) { args["EXTRA"] = extra; } @@ -5080,9 +5095,9 @@ void handle_buy() } } -class LLObjectBuy : public view_listener_t +class LLObjectBuy final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { handle_buy(); return true; @@ -5129,11 +5144,12 @@ BOOL sitting_on_selection() return (gAgentAvatarp->isSitting() && gAgentAvatarp->getRoot() == root_object); } -class LLToolsSaveToInventory : public view_listener_t +class LLToolsSaveToInventory final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - if(enable_save_into_inventory(NULL)) + bool enable_save_into_inventory(); + if(enable_save_into_inventory()) { derez_objects(DRD_SAVE_INTO_AGENT_INVENTORY, LLUUID::null); } @@ -5141,9 +5157,9 @@ class LLToolsSaveToInventory : public view_listener_t } }; -class LLToolsSaveToObjectInventory : public view_listener_t +class LLToolsSaveToObjectInventory final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); if(node && (node->mValid) && (!node->mFromTaskID.isNull())) @@ -5155,27 +5171,27 @@ class LLToolsSaveToObjectInventory : public view_listener_t } }; -class LLToolsEnablePathfinding : public view_listener_t +class LLToolsEnablePathfinding final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - return (LLPathfindingManager::getInstance() != NULL) && LLPathfindingManager::getInstance()->isPathfindingEnabledForCurrentRegion(); + return (LLPathfindingManager::getInstance() != nullptr) && LLPathfindingManager::getInstance()->isPathfindingEnabledForCurrentRegion(); } }; -class LLToolsEnablePathfindingView : public view_listener_t +class LLToolsEnablePathfindingView final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - return (LLPathfindingManager::getInstance() != NULL) && LLPathfindingManager::getInstance()->isPathfindingEnabledForCurrentRegion() && LLPathfindingManager::getInstance()->isPathfindingViewEnabled(); + return (LLPathfindingManager::getInstance() != nullptr) && LLPathfindingManager::getInstance()->isPathfindingEnabledForCurrentRegion() && LLPathfindingManager::getInstance()->isPathfindingViewEnabled(); } }; -class LLToolsDoPathfindingRebakeRegion : public view_listener_t +class LLToolsDoPathfindingRebakeRegion final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - bool hasPathfinding = (LLPathfindingManager::getInstance() != NULL); + bool hasPathfinding = (LLPathfindingManager::getInstance() != nullptr); if (hasPathfinding) { @@ -5186,13 +5202,13 @@ class LLToolsDoPathfindingRebakeRegion : public view_listener_t } }; -class LLToolsEnablePathfindingRebakeRegion : public view_listener_t +class LLToolsEnablePathfindingRebakeRegion final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool returnValue = false; - if (LLPathfindingManager::getInstance() != NULL) + if (LLPathfindingManager::getInstance() != nullptr) { LLMenuOptionPathfindingRebakeNavmesh *rebakeInstance = LLMenuOptionPathfindingRebakeNavmesh::getInstance(); returnValue = (rebakeInstance->canRebakeRegion() && @@ -5204,9 +5220,9 @@ class LLToolsEnablePathfindingRebakeRegion : public view_listener_t }; // Round the position of all root objects to the grid -class LLToolsSnapObjectXY : public view_listener_t +class LLToolsSnapObjectXY final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { F64 snap_size = (F64)gSavedSettings.getF32("GridResolution"); @@ -5251,9 +5267,9 @@ class LLToolsSnapObjectXY : public view_listener_t }; // Determine if the option to cycle between linked prims is shown -class LLToolsEnableSelectNextPart : public view_listener_t +class LLToolsEnableSelectNextPart final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = (gSavedSettings.getBOOL("EditLinkedParts") && !LLSelectMgr::getInstance()->getSelection()->isEmpty()); @@ -5265,9 +5281,9 @@ class LLToolsEnableSelectNextPart : public view_listener_t // Cycle selection through linked children in selected object. // FIXME: Order of children list is not always the same as sim's idea of link order. This may confuse // resis. Need link position added to sim messages to address this. -class LLToolsSelectNextPart : public view_listener_t +class LLToolsSelectNextPart final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { S32 object_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount(); if (gSavedSettings.getBOOL("EditLinkedParts") && object_count) @@ -5279,7 +5295,7 @@ class LLToolsSelectNextPart : public view_listener_t bool prev = (userdata.asString() == "previous"); bool ifwd = (userdata.asString() == "includenext"); bool iprev = (userdata.asString() == "includeprevious"); - LLViewerObject* to_select = NULL; + LLViewerObject* to_select = nullptr; LLViewerObject::child_list_t children = selected->getRootEdit()->getChildren(); children.push_front(selected->getRootEdit()); // need root in the list too @@ -5326,7 +5342,7 @@ class LLToolsSelectNextPart : public view_listener_t { if (gFocusMgr.childHasKeyboardFocus(gFloaterTools)) { - gFocusMgr.setKeyboardFocus(NULL); // force edit toolbox to commit any changes + gFocusMgr.setKeyboardFocus(nullptr); // force edit toolbox to commit any changes } if (fwd || prev) { @@ -5349,9 +5365,9 @@ class LLToolsSelectNextPart : public view_listener_t // otherwise. this allows the handle_link method to more finely check // the selection and give an error message when the uer has a // reasonable expectation for the link to work, but it will fail. -class LLToolsEnableLink : public view_listener_t +class LLToolsEnableLink final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = LLSelectMgr::getInstance()->enableLinkObjects(); gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); @@ -5359,17 +5375,17 @@ class LLToolsEnableLink : public view_listener_t } }; -class LLToolsLink : public view_listener_t +class LLToolsLink final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { return LLSelectMgr::getInstance()->linkObjects(); } }; -class LLToolsEnableUnlink : public view_listener_t +class LLToolsEnableUnlink final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = LLSelectMgr::getInstance()->enableUnlinkObjects(); gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); @@ -5377,9 +5393,9 @@ class LLToolsEnableUnlink : public view_listener_t } }; -class LLToolsUnlink : public view_listener_t +class LLToolsUnlink final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLSelectMgr::getInstance()->unlinkObjects(); return true; @@ -5387,18 +5403,18 @@ class LLToolsUnlink : public view_listener_t }; -class LLToolsStopAllAnimations : public view_listener_t +class LLToolsStopAllAnimations final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { gAgent.stopCurrentAnimations(); return true; } }; -class LLToolsReleaseKeys : public view_listener_t +class LLToolsReleaseKeys final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { // [RLVa:KB] - Checked: 2010-04-19 (RLVa-1.2.0f) | Modified: RLVa-1.0.5a | OK if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedAttachmentPoint(RLV_LOCK_REMOVE)) ) @@ -5410,9 +5426,9 @@ class LLToolsReleaseKeys : public view_listener_t } }; -class LLToolsEnableReleaseKeys : public view_listener_t +class LLToolsEnableReleaseKeys final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { // [RLVa:KB] - Checked: 2010-04-19 (RLVa-1.2.0f) | Modified: RLVa-1.0.5a gMenuHolder->findControl(userdata["control"].asString())->setValue(gAgent.anyControlGrabbed() && @@ -5424,9 +5440,9 @@ class LLToolsEnableReleaseKeys : public view_listener_t }; -class LLEditEnableCut : public view_listener_t +class LLEditEnableCut final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canCut(); gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); @@ -5434,9 +5450,9 @@ class LLEditEnableCut : public view_listener_t } }; -class LLEditCut : public view_listener_t +class LLEditCut final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { if( LLEditMenuHandler::gEditMenuHandler ) { @@ -5446,9 +5462,9 @@ class LLEditCut : public view_listener_t } }; -class LLEditEnableCopy : public view_listener_t +class LLEditEnableCopy final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canCopy(); gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); @@ -5456,9 +5472,9 @@ class LLEditEnableCopy : public view_listener_t } }; -class LLEditCopy : public view_listener_t +class LLEditCopy final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { if( LLEditMenuHandler::gEditMenuHandler ) { @@ -5468,9 +5484,9 @@ class LLEditCopy : public view_listener_t } }; -class LLEditEnablePaste : public view_listener_t +class LLEditEnablePaste final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canPaste(); gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); @@ -5478,9 +5494,9 @@ class LLEditEnablePaste : public view_listener_t } }; -class LLEditPaste : public view_listener_t +class LLEditPaste final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { if( LLEditMenuHandler::gEditMenuHandler ) { @@ -5490,9 +5506,9 @@ class LLEditPaste : public view_listener_t } }; -class LLEditEnableDelete : public view_listener_t +class LLEditEnableDelete final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canDoDelete(); @@ -5509,9 +5525,9 @@ class LLEditEnableDelete : public view_listener_t } }; -class LLEditDelete : public view_listener_t +class LLEditDelete final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { // [RLVa:KB] - Checked: 2009-07-05 (RLVa-1.0.0b) // NOTE: we want to disable delete on objects but not disable delete on text @@ -5534,7 +5550,7 @@ class LLEditDelete : public view_listener_t // When deleting an object we may not actually be done // Keep selection so we know what to delete when confirmation is needed about the delete - gPieObject->hide(TRUE); + gPieObject->hide(); return true; } }; @@ -5545,9 +5561,9 @@ bool enable_object_return() (gAgent.isGodlike() || can_derez(DRD_RETURN_TO_OWNER))); } -class LLObjectEnableDelete : public view_listener_t +class LLObjectEnableDelete final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { gMenuHolder->findControl(userdata["control"].asString())->setValue(enable_object_delete()); return true; @@ -5575,29 +5591,20 @@ bool enable_object_delete() return new_value; } -class LLEditSearch : public view_listener_t -{ - bool handleEvent(LLPointer event, const LLSD& userdata) - { - toggle_search_floater(); - return true; - } -}; - class LLObjectsReturnPackage { public: - LLObjectsReturnPackage() : mObjectSelection(), mReturnableObjects(), mError(), mFirstRegion(NULL) {}; + LLObjectsReturnPackage() : mObjectSelection(), mReturnableObjects(), mError(), mFirstRegion(nullptr) {}; ~LLObjectsReturnPackage() { mObjectSelection.clear(); mReturnableObjects.clear(); mError.clear(); - mFirstRegion = NULL; + mFirstRegion = nullptr; }; LLObjectSelectionHandle mObjectSelection; - LLDynamicArray mReturnableObjects; + std::vector mReturnableObjects; std::string mError; LLViewerRegion *mFirstRegion; }; @@ -5627,9 +5634,9 @@ void handle_object_return() } } -class LLObjectDelete : public view_listener_t +class LLObjectDelete final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { // [RLVa:KB] - Checked: 2009-07-05 (RLVa-1.0.0b) if ( (rlv_handler_t::isEnabled()) && (!rlvCanDeleteOrReturn()) ) @@ -5654,7 +5661,7 @@ void handle_object_delete() // When deleting an object we may not actually be done // Keep selection so we know what to delete when confirmation is needed about the delete - gPieObject->hide(TRUE); + gPieObject->hide(); return; } @@ -5663,9 +5670,9 @@ void handle_force_delete(void*) LLSelectMgr::getInstance()->selectForceDelete(); } -class LLViewEnableJoystickFlycam : public view_listener_t +class LLViewEnableJoystickFlycam final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = (gSavedSettings.getBOOL("JoystickEnabled") && gSavedSettings.getBOOL("JoystickFlycamEnabled")); gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); @@ -5673,9 +5680,9 @@ class LLViewEnableJoystickFlycam : public view_listener_t } }; -class LLViewEnableLastChatter : public view_listener_t +class LLViewEnableLastChatter final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { // *TODO: add check that last chatter is in range bool new_value = (gAgentCamera.cameraThirdPerson() && gAgent.getLastChatter().notNull()); @@ -5684,18 +5691,9 @@ class LLViewEnableLastChatter : public view_listener_t } }; -class LLViewToggleRadar: public view_listener_t -{ - bool handleEvent(LLPointer event, const LLSD& userdata) - { - LLFloaterAvatarList::toggle(0); - return true; - } -}; - -class LLEditEnableDeselect : public view_listener_t +class LLEditEnableDeselect final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canDeselect(); gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); @@ -5703,9 +5701,9 @@ class LLEditEnableDeselect : public view_listener_t } }; -class LLEditDeselect : public view_listener_t +class LLEditDeselect final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { if( LLEditMenuHandler::gEditMenuHandler ) { @@ -5715,9 +5713,9 @@ class LLEditDeselect : public view_listener_t } }; -class LLEditEnableSelectAll : public view_listener_t +class LLEditEnableSelectAll final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canSelectAll(); gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); @@ -5726,9 +5724,9 @@ class LLEditEnableSelectAll : public view_listener_t }; -class LLEditSelectAll : public view_listener_t +class LLEditSelectAll final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { if( LLEditMenuHandler::gEditMenuHandler ) { @@ -5739,9 +5737,9 @@ class LLEditSelectAll : public view_listener_t }; -class LLEditEnableUndo : public view_listener_t +class LLEditEnableUndo final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canUndo(); gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); @@ -5749,9 +5747,9 @@ class LLEditEnableUndo : public view_listener_t } }; -class LLEditUndo : public view_listener_t +class LLEditUndo final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { if( LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canUndo() ) { @@ -5761,9 +5759,9 @@ class LLEditUndo : public view_listener_t } }; -class LLEditEnableRedo : public view_listener_t +class LLEditEnableRedo final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canRedo(); gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); @@ -5771,9 +5769,9 @@ class LLEditEnableRedo : public view_listener_t } }; -class LLEditRedo : public view_listener_t +class LLEditRedo final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { if( LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canRedo() ) { @@ -5794,7 +5792,7 @@ void print_agent_nvpairs(void*) { LLViewerObject *objectp; - llinfos << "Agent Name Value Pairs" << llendl; + LL_INFOS() << "Agent Name Value Pairs" << LL_ENDL; objectp = gAgentAvatarp; if (objectp) @@ -5803,10 +5801,10 @@ void print_agent_nvpairs(void*) } else { - llinfos << "Can't find agent object" << llendl; + LL_INFOS() << "Can't find agent object" << LL_ENDL; } - llinfos << "Camera at " << gAgentCamera.getCameraPositionGlobal() << llendl; + LL_INFOS() << "Camera at " << gAgentCamera.getCameraPositionGlobal() << LL_ENDL; } void show_debug_menus() @@ -5847,7 +5845,7 @@ void toggle_debug_menus(void*) // LLUUID gExporterRequestID; // std::string gExportDirectory; -// LLUploadDialog *gExportDialog = NULL; +// LLUploadDialog *gExportDialog = nullptr; // void handle_export_selected( void * ) // { @@ -5856,7 +5854,7 @@ void toggle_debug_menus(void*) // { // return; // } -// llinfos << "Exporting selected objects:" << llendl; +// LL_INFOS() << "Exporting selected objects:" << LL_ENDL; // gExporterRequestID.generate(); // gExportDirectory = ""; @@ -5875,7 +5873,7 @@ void toggle_debug_menus(void*) // LLViewerObject* object = node->getObject(); // msg->nextBlockFast(_PREHASH_ObjectData); // msg->addUUIDFast(_PREHASH_ObjectID, object->getID()); -// llinfos << "Object: " << object->getID() << llendl; +// LL_INFOS() << "Object: " << object->getID() << LL_ENDL; // } // msg->sendReliable(gAgent.getRegion()->getHost()); @@ -5894,15 +5892,15 @@ void handle_reload_settings(void*) gSavedSettings.resetToDefaults(); gSavedSettings.loadFromFile(gSavedSettings.getString("ClientSettingsFile")); - llinfos << "Loading colors from colors.xml" << llendl; + LL_INFOS() << "Loading colors from colors.xml" << LL_ENDL; std::string color_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"colors.xml"); gColors.resetToDefaults(); gColors.loadFromFileLegacy(color_file, FALSE, TYPE_COL4U); } -class LLWorldSetHomeLocation : public view_listener_t +class LLWorldSetHomeLocation final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { // we just send the message and let the server check for failure cases // server will echo back a "Home position set." alert if it succeeds @@ -5912,80 +5910,42 @@ class LLWorldSetHomeLocation : public view_listener_t } }; -class LLWorldTeleportHome : public view_listener_t +class LLWorldTeleportHome final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { gAgent.teleportHome(); return true; } }; -class LLWorldAlwaysRun : public view_listener_t -{ - bool handleEvent(LLPointer event, const LLSD& userdata) - { - // as well as altering the default walk-vs-run state, - // we also change the *current* walk-vs-run state. - if (gAgent.getAlwaysRun()) - { - gAgent.clearAlwaysRun(); -// gAgent.clearRunning(); - } - else - { - gAgent.setAlwaysRun(); -// gAgent.setRunning(); - } - - // tell the simulator. -// gAgent.sendWalkRun(gAgent.getAlwaysRun()); - - return true; - } -}; - -class LLWorldCheckAlwaysRun : public view_listener_t +void toggle_sit() { - bool handleEvent(LLPointer event, const LLSD& userdata) - { - bool new_value = gAgent.getAlwaysRun(); - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); - return true; - } -}; + if (!gAgentAvatarp) return; + gAgent.setControlFlags(gAgentAvatarp->isSitting() ? AGENT_CONTROL_STAND_UP : AGENT_CONTROL_SIT_ON_GROUND); +} -class LLWorldSitOnGround : public view_listener_t +class LLWorldSitOnGround final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - if (gAgentAvatarp) - { - if(!gAgentAvatarp->isSitting()) - { - gAgent.setControlFlags(AGENT_CONTROL_SIT_ON_GROUND); - } - else - { - gAgent.setControlFlags(AGENT_CONTROL_STAND_UP); - } - } + toggle_sit(); return true; } }; -class LLWorldFakeAway : public view_listener_t +class LLWorldFakeAway final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - handle_fake_away_status(NULL); + handle_fake_away_status(nullptr); return true; } }; -class LLWorldEnableSitOnGround : public view_listener_t +class LLWorldEnableSitOnGround final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = (gAgentAvatarp); gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); @@ -5993,9 +5953,9 @@ class LLWorldEnableSitOnGround : public view_listener_t } }; -class LLWorldSetAway : public view_listener_t +class LLWorldSetAway final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { if (gAgent.getAFK()) { @@ -6009,26 +5969,21 @@ class LLWorldSetAway : public view_listener_t } }; -class LLWorldSetBusy : public view_listener_t +class LLWorldSetBusy final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - if (gAgent.getBusy()) - { - gAgent.clearBusy(); - } - else - { - gAgent.setBusy(); + bool busy = !gAgent.isDoNotDisturb(); + gAgent.setDoNotDisturb(busy); + if (busy) LLNotificationsUtil::add("BusyModeSet"); - } return true; } }; -class LLWorldCreateLandmark : public view_listener_t +class LLWorldCreateLandmark final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { // [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.4.5) | Added: RLVa-1.0.0 if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) @@ -6038,13 +5993,13 @@ class LLWorldCreateLandmark : public view_listener_t LLViewerRegion* agent_region = gAgent.getRegion(); if(!agent_region) { - llwarns << "No agent region" << llendl; + LL_WARNS() << "No agent region" << LL_ENDL; return true; } LLParcel* agent_parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); if (!agent_parcel) { - llwarns << "No agent parcel" << llendl; + LL_WARNS() << "No agent parcel" << LL_ENDL; return true; } if (!agent_parcel->getAllowLandmark() @@ -6061,7 +6016,7 @@ class LLWorldCreateLandmark : public view_listener_t create_inventory_item(gAgent.getID(), gAgent.getSessionID(), folder_id, LLTransactionID::tnull, - pos_string, pos_string, // name, desc + pos_string, agent_parcel->getDesc(), // name, desc, // name, desc LLAssetType::AT_LANDMARK, LLInventoryType::IT_LANDMARK, NOT_WEARABLE, PERM_ALL, @@ -6070,9 +6025,9 @@ class LLWorldCreateLandmark : public view_listener_t } }; -class LLToolsLookAtSelection : public view_listener_t +class LLToolsLookAtSelection final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { handle_look_at_selection(userdata); return true; @@ -6117,14 +6072,14 @@ void handle_look_at_selection(const LLSD& param) } } -class LLAvatarInviteToGroup : public view_listener_t +class LLAvatarInviteToGroup final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); // if(avatar) // [RLVa:KB] - Checked: 2010-06-04 (RLVa-1.2.0d) | Added: RLVa-1.2.0d - if ( (avatar) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) ) + if ( (avatar) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES) && !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS)) ) // [/RLVa:KB] { LLAvatarActions::inviteToGroup(avatar->getID()); @@ -6133,14 +6088,14 @@ class LLAvatarInviteToGroup : public view_listener_t } }; -class LLAvatarAddFriend : public view_listener_t +class LLAvatarAddFriend final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); // if(avatar && !LLAvatarActions::isFriend(avatar->getID())) // [RLVa:KB] - Checked: 2010-04-20 (RLVa-1.2.0f) | Modified: RLVa-1.2.0f - if ( (avatar && !LLAvatarActions::isFriend(avatar->getID())) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) ) + if ( (avatar && !LLAvatarActions::isFriend(avatar->getID())) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES) && !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS)) ) // [/RLVa:KB] { request_friendship(avatar->getID()); @@ -6149,16 +6104,51 @@ class LLAvatarAddFriend : public view_listener_t } }; -bool complete_give_money(const LLSD& notification, const LLSD& response, LLObjectSelectionHandle selection) +class LLAvatarResetSkeleton final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + LLVOAvatar* avatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); + if (avatar) + { + avatar->resetSkeleton(false); + } + return true; + } +}; + +class LLAvatarEnableResetSkeleton final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + LLVOAvatar* avatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); + return avatar != nullptr; + } +}; + + +class LLAvatarResetSkeletonAndAnimations final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + LLVOAvatar* avatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); + if (avatar) + { + avatar->resetSkeleton(true); + } + return true; + } + +}; + +bool complete_give_money(const LLSD& notification, const LLSD& response, LLViewerObject* objectp) { S32 option = LLNotification::getSelectedOption(notification, response); if (option == 0) { - gAgent.clearBusy(); + gAgent.setDoNotDisturb(false); } - LLViewerObject* objectp = selection->getPrimaryObject(); - // Show avatar's name if paying attachment if (objectp && objectp->isAttachment()) { @@ -6185,12 +6175,12 @@ bool complete_give_money(const LLSD& notification, const LLSD& response, LLObjec return false; } -void handle_give_money_dialog() +void handle_give_money_dialog(LLViewerObject* obj) { LLNotification::Params params("BusyModePay"); - params.functor(boost::bind(complete_give_money, _1, _2, LLSelectMgr::getInstance()->getSelection())); + params.functor(boost::bind(complete_give_money, _1, _2, obj)); - if (gAgent.getBusy()) + if (gAgent.isDoNotDisturb()) { // warn users of being in busy mode during a transaction LLNotifications::instance().add(params); @@ -6201,11 +6191,11 @@ void handle_give_money_dialog() } } -class LLPayObject : public view_listener_t +class LLPayObject final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - handle_give_money_dialog(); + handle_give_money_dialog(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); return true; } }; @@ -6214,15 +6204,14 @@ bool enable_pay_avatar() { LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); LLVOAvatar* avatar = find_avatar_from_object(obj); -// return (avatar != NULL); +// return (avatar != nullptr); // [RLVa:KB] - Checked: 2010-08-25 (RLVa-1.2.1b) | Added: RLVa-1.2.1b - return (avatar != NULL) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)); + return (avatar != nullptr) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES) && !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS)); // [/RLVa:KB] } -bool enable_pay_object() +bool enable_pay_object(LLViewerObject* object) { - LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); if( object ) { LLViewerObject *parent = (LLViewerObject *)object->getParent(); @@ -6239,7 +6228,7 @@ bool enable_object_stand_up() // 'Object Stand Up' menu item is enabled when agent is sitting on selection // return sitting_on_selection(); // [RLVa:KB] - Checked: 2010-07-24 (RLVa-1.2.0g) | Added: RLVa-1.2.0g - return sitting_on_selection() && ( (!rlv_handler_t::isEnabled()) || (gRlvHandler.canStand()) ); + return sitting_on_selection() && ( (!rlv_handler_t::isEnabled()) || (RlvActions::canStand()) ); // [/RLVa:KB] } @@ -6281,9 +6270,9 @@ bool enable_object_sit(/*LLUICtrl* ctrl*/) return !sitting_on_sel && is_object_sittable(); } -class LLObjectEnableSitOrStand : public view_listener_t +class LLObjectEnableSitOrStand final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value; @@ -6324,11 +6313,11 @@ class LLObjectEnableSitOrStand : public view_listener_t } }; -class LLEnablePayObject : public view_listener_t +class LLEnablePayObject final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - gMenuHolder->findControl(userdata["control"].asString())->setValue(enable_pay_avatar() || enable_pay_object()); + gMenuHolder->findControl(userdata["control"].asString())->setValue(enable_pay_avatar() || enable_pay_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject())); return true; } }; @@ -6364,160 +6353,23 @@ void handle_viewer_disable_message_log(void*) gMessageSystem->stopLogging(); } -struct MenuFloaterDict : public LLSingleton -{ - typedef std::map, boost::function > > menu_floater_map_t; - menu_floater_map_t mEntries; - MenuFloaterDict() - { - registerFloater("about", boost::bind(&LLFloaterAbout::show,(void*)NULL)); - //registerFloater("about region", boost::bind(&LLFloaterRegionInfo::showInstance,LLSD())); - registerFloater("buy currency", boost::bind(&LLFloaterBuyCurrency::buyCurrency)); - registerFloater("displayname", boost::bind(&LLFloaterDisplayName::show)); - //registerFloater("friends", boost::bind(&LLFloaterMyFriends::toggleInstance,0), boost::bind(&LLFloaterMyFriends::instanceVisible,0)); - registerFloater("gestures", boost::bind(&LLFloaterGesture::toggleVisibility), boost::bind(&LLFloaterGesture::instanceVisible)); - registerFloater("grid options", boost::bind(&LLFloaterBuildOptions::show,(void*)NULL)); - registerFloater("help tutorial",boost::bind(&LLFloaterHUD::showHUD)); - registerFloater("im", boost::bind(&LLFloaterChatterBox::toggleInstance,LLSD()), boost::bind(&LLFloaterMyFriends::instanceVisible,0)); - //registerFloater("lag meter", boost::bind(&LLFloaterLagMeter::showInstance,LLSD())); - registerFloater("my land", boost::bind(&LLFloaterLandHoldings::show,(void*)NULL)); - registerFloater("preferences", boost::bind(&LLFloaterPreference::show,(void*)NULL)); - registerFloater("script errors",boost::bind(&LLFloaterScriptDebug::show,LLUUID::null)); - //registerFloater("script info", boost::bind(&LLFloaterScriptLimits::showInstance,LLSD())); - // Phoenix: Wolfspirit: Enabled Show Floater out of viewer menu - registerFloater("toolbar", boost::bind(&LLToolBar::toggle,(void*)NULL), boost::bind(&LLToolBar::visible,(void*)NULL)); - registerFloater("world map", boost::bind(&LLFloaterWorldMap::toggle)); - registerFloater("sound_explorer", boost::bind(&LLFloaterExploreSounds::toggle), boost::bind(&LLFloaterExploreSounds::visible)); - registerFloater("asset_blacklist", boost::bind(&LLFloaterBlacklist::toggle), boost::bind(&LLFloaterBlacklist::visible)); - - registerFloater ("about land"); - registerFloater ("about region"); - registerFloater ("active speakers"); - registerFloater ("areasearch"); - registerFloater ("beacons"); - registerFloater ("camera controls"); - registerFloater ("chat history"); - registerFloater ("communicate"); - registerFloater ("friends",0); - registerFloater ("lag meter"); - registerFloater ("media filter"); - registerFloater ("mini map"); - registerFloater ("movement controls"); - registerFloater ("mute list"); - registerFloater ("outbox"); - registerFloater ("perm prefs"); - registerFloater ("script info"); - registerFloater ("stat bar"); - registerFloater ("teleport history"); - registerFloater ("voice effect"); - registerFloater ("pathfinding_characters"); - registerFloater ("pathfinding_linksets"); - - } - void registerFloater(const std::string& name, boost::function show, boost::function visible = NULL) - { - mEntries.insert( std::make_pair( name, std::make_pair( show, visible ) ) ); - } - template - void registerFloater(const std::string& name, const LLSD& key = LLSD()) - { - registerFloater(name, boost::bind(&T::toggleInstance,key), boost::bind(&T::instanceVisible,key)); - } - -}; - // TomY TODO: Move! -class LLShowFloater : public view_listener_t +void show_floater(const std::string& floater_name); +class LLShowFloater final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - std::string floater_name = userdata.asString(); - if (floater_name.empty()) return false; - MenuFloaterDict::menu_floater_map_t::iterator it = MenuFloaterDict::instance().mEntries.find(floater_name); - if(it != MenuFloaterDict::instance().mEntries.end() && it->second.first != NULL) - { - it->second.first(); - } - else if (floater_name == "appearance") - { - if (gAgentWearables.areWearablesLoaded()) - { - LLFloaterCustomize::show(); - } - } - else if (floater_name == "outfit") - { - new LLMakeOutfitDialog(false); - } - else if (floater_name == "inventory") - { - LLInventoryView::toggleVisibility(NULL); - } - else if (floater_name == "buy land") - { -// [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0a) - if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) - { - return true; - } -// [/RLVa:KB] - if (LLViewerParcelMgr::getInstance()->selectionEmpty()) - { - LLViewerParcelMgr::getInstance()->selectParcelAt(gAgent.getPositionGlobal()); - } - LLViewerParcelMgr::getInstance()->startBuyLand(); - } - - //Singu TODO: Re-implement f1 help. - /*else if (floater_name == "help f1") - { - llinfos << "Spawning HTML help window" << llendl; - gViewerHtmlHelp.show(); - }*/ - - else if (floater_name == "complaint reporter") - { - // Prevent menu from appearing in screen shot. - gMenuHolder->hideMenus(); - LLFloaterReporter::showFromMenu(COMPLAINT_REPORT); - } - else if (floater_name == "mean events") - { - if (!gNoRender) - { - LLFloaterBump::show(NULL); - } - } - else // Simple codeless floater - { - LLFloater* floater = LLUICtrlFactory::getInstance()->getBuiltFloater(floater_name); - if (floater) - gFloaterView->bringToFront(floater); - else - LLUICtrlFactory::getInstance()->buildFloater(new LLFloater(), floater_name); - } + show_floater(userdata.asString()); return true; } }; -class LLFloaterVisible : public view_listener_t +bool floater_visible(const std::string& floater_name); +class LLFloaterVisible final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - std::string control_name = userdata["control"].asString(); - std::string floater_name = userdata["data"].asString(); - bool new_value = false; - MenuFloaterDict::menu_floater_map_t::iterator it = MenuFloaterDict::instance().mEntries.find(floater_name); - if(it != MenuFloaterDict::instance().mEntries.end() && it->second.second != NULL) - { - new_value = it->second.second(); - } - else if (floater_name == "inventory") - { - LLInventoryView* iv = LLInventoryView::getActiveInventory(); - new_value = (NULL != iv && TRUE == iv->getVisible()); - } - gMenuHolder->findControl(control_name)->setValue(new_value); + gMenuHolder->findControl(userdata["control"].asString())->setValue(floater_visible(userdata["data"].asString())); return true; } }; @@ -6533,9 +6385,9 @@ bool callback_show_url(const LLSD& notification, const LLSD& response) return false; } -class LLPromptShowURL : public view_listener_t +class LLPromptShowURL final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { std::string param = userdata.asString(); std::string::size_type offset = param.find(","); @@ -6557,7 +6409,7 @@ class LLPromptShowURL : public view_listener_t } else { - llinfos << "PromptShowURL invalid parameters! Expecting \"ALERT,URL\"." << llendl; + LL_INFOS() << "PromptShowURL invalid parameters! Expecting \"ALERT,URL\"." << LL_ENDL; } return true; } @@ -6573,9 +6425,9 @@ bool callback_show_file(const LLSD& notification, const LLSD& response) return false; } -class LLPromptShowFile : public view_listener_t +class LLPromptShowFile final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { std::string param = userdata.asString(); std::string::size_type offset = param.find(","); @@ -6590,15 +6442,15 @@ class LLPromptShowFile : public view_listener_t } else { - llinfos << "PromptShowFile invalid parameters! Expecting \"ALERT,FILE\"." << llendl; + LL_INFOS() << "PromptShowFile invalid parameters! Expecting \"ALERT,FILE\"." << LL_ENDL; } return true; } }; -class LLShowAgentProfile : public view_listener_t +class LLShowAgentProfile final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLUUID agent_id; if (userdata.asString() == "agent") @@ -6621,7 +6473,7 @@ class LLShowAgentProfile : public view_listener_t LLVOAvatar* avatar = find_avatar_from_object(agent_id); // if (avatar) // [RLVa:KB] - Checked: 2010-06-04 (RLVa-1.2.0d) | Modified: RLVa-1.2.0d - if ( (avatar) && ((!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) || (gAgent.getID() == agent_id)) ) + if ( (avatar) && ((!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES) && !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS)) || (gAgent.getID() == agent_id)) ) // [/RLVa:KB] { LLAvatarActions::showProfile(avatar->getID()); @@ -6630,18 +6482,9 @@ class LLShowAgentProfile : public view_listener_t } }; -class LLShowAgentGroups : public view_listener_t -{ - bool handleEvent(LLPointer event, const LLSD& userdata) - { - LLFloaterMyFriends::toggleInstance(1); - return true; - } -}; - -class LLLandEdit : public view_listener_t +class LLLandEdit final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { // [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0b) if ( (rlv_handler_t::isEnabled()) && (gRlvHandler.hasBehaviour(RLV_BHVR_EDIT)) ) @@ -6676,9 +6519,9 @@ class LLLandEdit : public view_listener_t } }; -class LLWorldEnableBuyLand : public view_listener_t +class LLWorldEnableBuyLand final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = LLViewerParcelMgr::getInstance()->canAgentBuyParcel( LLViewerParcelMgr::getInstance()->selectionEmpty() @@ -6696,24 +6539,33 @@ BOOL enable_buy_land(void*) LLViewerParcelMgr::getInstance()->getParcelSelection()->getParcel(), false); } +class LLWorldVisibleDestinations final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + bool visible(!LFSimFeatureHandler::instance().destinationGuideURL().empty()); + gMenuHolder->findControl(userdata["control"].asString())->setValue(visible); + return visible; + } +}; -class LLObjectAttachToAvatar : public view_listener_t +class LLObjectAttachToAvatar final : public view_listener_t { public: LLObjectAttachToAvatar(bool replace) : mReplace(replace) {} static void setObjectSelection(LLObjectSelectionHandle selection) { sObjectSelection = selection; } private: - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { setObjectSelection(LLSelectMgr::getInstance()->getSelection()); LLViewerObject* selectedObject = sObjectSelection->getFirstRootObject(); if (selectedObject) { S32 index = userdata.asInteger(); - LLViewerJointAttachment* attachment_point = NULL; + LLViewerJointAttachment* attachment_point = nullptr; if (index > 0) - attachment_point = get_if_there(gAgentAvatarp->mAttachmentPoints, index, (LLViewerJointAttachment*)NULL); + attachment_point = get_if_there(gAgentAvatarp->mAttachmentPoints, index, (LLViewerJointAttachment*)nullptr); // [RLVa:KB] - Checked: 2010-09-28 (RLVa-1.2.1f) | Modified: RLVa-1.2.1f // RELEASE-RLVa: [SL-2.2.0] If 'index != 0' then the object will be "add attached" [see LLSelectMgr::sendAttach()] @@ -6722,7 +6574,7 @@ class LLObjectAttachToAvatar : public view_listener_t ((index) && ((RLV_WEAR_ADD & gRlvAttachmentLocks.canAttach(attachment_point)) == 0)) || // or non-attachable attachpt (gRlvHandler.hasBehaviour(RLV_BHVR_REZ)) ) ) // Attach on object == "Take" { - setObjectSelection(NULL); // Clear the selection or it'll get stuck + setObjectSelection(nullptr); // Clear the selection or it'll get stuck return true; } // [/RLVa:KB] @@ -6780,7 +6632,7 @@ void LLObjectAttachToAvatar::onNearAttachObject(BOOL success, void *user_data) } LLSelectMgr::getInstance()->sendAttach(attachment_id, cb_data->mReplace); } - LLObjectAttachToAvatar::setObjectSelection(NULL); + LLObjectAttachToAvatar::setObjectSelection(nullptr); delete cb_data; } @@ -6813,7 +6665,7 @@ void LLObjectAttachToAvatar::confirmReplaceAttachment(S32 option, LLViewerJointA // The callback will be called even if avatar fails to get close enough to the object, so we won't get a memory leak. CallbackData* user_data = new CallbackData(attachment_point, mReplace); - gAgent.startAutoPilotGlobal(gAgent.getPosGlobalFromAgent(walkToSpot), "Attach", NULL, onNearAttachObject, user_data, stop_distance); + gAgent.startAutoPilotGlobal(gAgent.getPosGlobalFromAgent(walkToSpot), "Attach", nullptr, onNearAttachObject, user_data, stop_distance); gAgentCamera.clearFocusObject(); } } @@ -6832,7 +6684,7 @@ void callback_attachment_drop(const LLSD& notification, const LLSD& response) if (!object) { - llwarns << "handle_drop_attachment() - no object to drop" << llendl; + LL_WARNS() << "handle_drop_attachment() - no object to drop" << LL_ENDL; return; } @@ -6849,13 +6701,13 @@ void callback_attachment_drop(const LLSD& notification, const LLSD& response) if (!object) { - llwarns << "handle_detach() - no object to detach" << llendl; + LL_WARNS() << "handle_detach() - no object to detach" << LL_ENDL; return; } if (object->isAvatar()) { - llwarns << "Trying to detach avatar from avatar." << llendl; + LL_WARNS() << "Trying to detach avatar from avatar." << LL_ENDL; return; } @@ -6867,9 +6719,9 @@ void callback_attachment_drop(const LLSD& notification, const LLSD& response) return; } -class LLAttachmentDrop : public view_listener_t +class LLAttachmentDrop final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { // [RLVa:KB] - Checked: 2010-03-15 (RLVa-1.2.0e) | Modified: RLVa-1.0.5 if (rlv_handler_t::isEnabled()) @@ -6879,7 +6731,7 @@ class LLAttachmentDrop : public view_listener_t // NOTE: copy/paste of the code in enable_detach() LLObjectSelectionHandle hSelect = LLSelectMgr::getInstance()->getSelection(); RlvSelectHasLockedAttach f; - if ( (hSelect->isAttachment()) && (hSelect->getFirstRootNode(&f, FALSE) != NULL) ) + if ( (hSelect->isAttachment()) && (hSelect->getFirstRootNode(&f, FALSE) != nullptr) ) return true; } if (gRlvHandler.hasBehaviour(RLV_BHVR_REZ)) @@ -6898,7 +6750,7 @@ class LLAttachmentDrop : public view_listener_t } else { - llwarns << "Drop object not found" << llendl; + LL_WARNS() << "Drop object not found" << LL_ENDL; return true; } @@ -6984,16 +6836,16 @@ void detach_label(std::string& label, void* user_data) } } -class LLAttachmentDetach : public view_listener_t +class LLAttachmentDetach final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { // Called when the user clicked on an object attached to them // and selected "Detach". LLViewerObject *object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); if (!object) { - llwarns << "handle_detach() - no object to detach" << llendl; + LL_WARNS() << "handle_detach() - no object to detach" << LL_ENDL; return true; } @@ -7010,13 +6862,13 @@ class LLAttachmentDetach : public view_listener_t if (!object) { - llwarns << "handle_detach() - no object to detach" << llendl; + LL_WARNS() << "handle_detach() - no object to detach" << LL_ENDL; return true; } if (object->isAvatar()) { - llwarns << "Trying to detach avatar from avatar." << llendl; + LL_WARNS() << "Trying to detach avatar from avatar." << LL_ENDL; return true; } @@ -7026,7 +6878,7 @@ class LLAttachmentDetach : public view_listener_t { LLObjectSelectionHandle hSelect = LLSelectMgr::getInstance()->getSelection(); RlvSelectHasLockedAttach f; - if ( (hSelect->isAttachment()) && (hSelect->getFirstRootNode(&f, FALSE) != NULL) ) + if ( (hSelect->isAttachment()) && (hSelect->getFirstRootNode(&f, FALSE) != nullptr) ) return true; } // [/RLVa:KB] @@ -7039,7 +6891,7 @@ class LLAttachmentDetach : public view_listener_t //Adding an observer for a Jira 2422 and needs to be a fetch observer //for Jira 3119 -class LLWornItemFetchedObserver : public LLInventoryFetchItemsObserver +class LLWornItemFetchedObserver final : public LLInventoryFetchItemsObserver { public: LLWornItemFetchedObserver(const LLUUID& worn_item_id) : @@ -7057,9 +6909,9 @@ class LLWornItemFetchedObserver : public LLInventoryFetchItemsObserver }; // You can only drop items on parcels where you can build. -class LLAttachmentEnableDrop : public view_listener_t +class LLAttachmentEnableDrop final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { BOOL can_build = gAgent.isGodlike() || (LLViewerParcelMgr::getInstance()->allowAgentBuild()); @@ -7074,13 +6926,14 @@ class LLAttachmentEnableDrop : public view_listener_t // item is in your inventory LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - LLViewerJointAttachment* attachment = NULL; - LLInventoryItem* item = NULL; + LLViewerJointAttachment* attachment = nullptr; + LLInventoryItem* item = nullptr; - if (object) + // Do not enable drop if all faces of object are not enabled + if (object && LLSelectMgr::getInstance()->getSelection()->contains(object,SELECT_ALL_TES )) { - S32 attachmentID = ATTACHMENT_ID_FROM_STATE(object->getState()); - attachment = get_if_there(gAgentAvatarp->mAttachmentPoints, attachmentID, (LLViewerJointAttachment*)NULL); + S32 attachmentID = ATTACHMENT_ID_FROM_STATE(object->getAttachmentState()); + attachment = get_if_there(gAgentAvatarp->mAttachmentPoints, attachmentID, (LLViewerJointAttachment*)nullptr); if (attachment) { @@ -7142,7 +6995,7 @@ BOOL enable_detach(const LLSD&) { LLObjectSelectionHandle hSelect = LLSelectMgr::getInstance()->getSelection(); RlvSelectHasLockedAttach f; - if ( (hSelect->isAttachment()) && (hSelect->getFirstRootNode(&f, FALSE) != NULL) ) + if ( (hSelect->isAttachment()) && (hSelect->getFirstRootNode(&f, FALSE) != nullptr) ) return FALSE; } // [/RLVa:KB] @@ -7155,9 +7008,9 @@ BOOL enable_detach(const LLSD&) return FALSE; } -class LLAttachmentEnableDetach : public view_listener_t +class LLAttachmentEnableDetach final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = enable_detach(); gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); @@ -7176,8 +7029,8 @@ BOOL object_selected_and_point_valid(void *user_data) // RELEASE-RLVa: look at the caller graph for this function on every new release // -> 1.22.11 and 1.23.4 - // - object_is_wearable() => dead code [user_data == NULL => default attach point => OK!] - // - LLObjectEnableWear::handleEvent() => Rezzed prim / right-click / "Wear" [user_data == NULL => see above] + // - object_is_wearable() => dead code [user_data == nullptr => default attach point => OK!] + // - LLObjectEnableWear::handleEvent() => Rezzed prim / right-click / "Wear" [user_data == nullptr => see above] // - enabler set up in LLVOAvatar::buildCharacter() => Rezzed prim / right-click / "Attach >" [user_data == pAttachPt] // - enabler set up in LLVOAvatar::buildCharacter() => Rezzed prim / Edit menu / "Attach Object" [user_data == pAttachPt] const LLViewerJointAttachment* pAttachPt = (const LLViewerJointAttachment*)user_data; @@ -7213,7 +7066,7 @@ BOOL object_selected_and_point_valid(void *user_data) selection->getFirstRootObject()->permYouOwner() && !selection->getFirstRootObject()->flagObjectPermanent() && !((LLViewerObject*)selection->getFirstRootObject()->getRoot())->isAvatar() && - (selection->getFirstRootObject()->getNVPair("AssetContainer") == NULL); + (selection->getFirstRootObject()->getNVPair("AssetContainer") == nullptr); } @@ -7221,7 +7074,7 @@ BOOL object_selected_and_point_valid(void *user_data) /* BOOL object_is_wearable() { - if (!object_selected_and_point_valid(NULL)) + if (!object_selected_and_point_valid(nullptr)) { return FALSE; } @@ -7246,11 +7099,11 @@ BOOL object_is_wearable() // Also for seeing if object can be attached. See above. -class LLObjectEnableWear : public view_listener_t +class LLObjectEnableWear final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - bool is_wearable = object_selected_and_point_valid(NULL); + bool is_wearable = object_selected_and_point_valid(nullptr); gMenuHolder->findControl(userdata["control"].asString())->setValue(is_wearable); return TRUE; } @@ -7270,14 +7123,14 @@ BOOL object_attached(void *user_data) // return attachment->getNumObjects() > 0; } -class LLAvatarSendIM : public view_listener_t +class LLAvatarSendIM final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); // if(avatar) // [RLVa:KB] - Checked: 2010-06-04 (RLVa-1.2.0d) | Added: RLVa-1.2.0d - if ((avatar) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES))) + if ((avatar) && (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES) && !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS))) // [/RLVa:KB] { LLAvatarActions::startIM(avatar->getID()); @@ -7288,14 +7141,18 @@ class LLAvatarSendIM : public view_listener_t namespace { - struct QueueObjects : public LLSelectedObjectFunctor + struct QueueObjects final : public LLSelectedObjectFunctor { BOOL scripted; BOOL modifiable; LLFloaterScriptQueue* mQueue; QueueObjects(LLFloaterScriptQueue* q) : mQueue(q), scripted(FALSE), modifiable(FALSE) {} - virtual bool apply(LLViewerObject* obj) + bool apply(LLViewerObject* obj) override { + if (!obj) + { + return true; + } scripted = obj->flagScripted(); modifiable = obj->permModify(); @@ -7332,21 +7189,21 @@ void queue_actions(LLFloaterScriptQueue* q, const std::string& msg) } else { - llerrs << "Bad logic." << llendl; + LL_ERRS() << "Bad logic." << LL_ENDL; } } else { if (!q->start()) { - llwarns << "Unexpected script compile failure." << llendl; + LL_WARNS() << "Unexpected script compile failure." << LL_ENDL; } } } -class LLToolsSelectedScriptAction : public view_listener_t +class LLToolsSelectedScriptAction final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { // [RLVa:KB] - Checked: 2010-04-19 (RLVa-1.2.0f) | Modified: RLVa-1.0.5a // We'll allow resetting the scripts of objects on a non-attachable attach point since they wouldn't be able to circumvent anything @@ -7354,13 +7211,13 @@ class LLToolsSelectedScriptAction : public view_listener_t { LLObjectSelectionHandle hSel = LLSelectMgr::getInstance()->getSelection(); RlvSelectHasLockedAttach f; - if ( (hSel->isAttachment()) && (hSel->getFirstNode(&f) != NULL) ) + if ( (hSel->isAttachment()) && (hSel->getFirstNode(&f) != nullptr) ) return true; } // [/RLVa:KB] std::string action = userdata.asString(); - LLFloaterScriptQueue* queue = NULL; + LLFloaterScriptQueue* queue = nullptr; std::string msg; if (action == "compile mono") { @@ -7393,7 +7250,7 @@ class LLToolsSelectedScriptAction : public view_listener_t } else { - llwarns << "Failed to generate LLFloaterScriptQueue with action: " << action << llendl; + LL_WARNS() << "Failed to generate LLFloaterScriptQueue with action: " << action << LL_ENDL; } return true; } @@ -7507,9 +7364,9 @@ void handle_toggle_pg(void*) { gAgent.setTeen( !gAgent.isTeen() ); - LLFloaterWorldMap::reloadIcons(NULL); + LLFloaterWorldMap::reloadIcons(nullptr); - llinfos << "PG status set to " << gAgent.isTeen() << llendl; + LL_INFOS() << "PG status set to " << gAgent.isTeen() << LL_ENDL; } void handle_dump_attachments(void*) @@ -7527,17 +7384,17 @@ void handle_dump_attachments(void*) ++attachment_iter) { LLViewerObject *attached_object = (*attachment_iter); - BOOL visible = (attached_object != NULL && + BOOL visible = (attached_object != nullptr && attached_object->mDrawable.notNull() && !attached_object->mDrawable->isRenderType(0)); LLVector3 pos; if (visible) pos = attached_object->mDrawable->getPosition(); - llinfos << "ATTACHMENT " << key << ": item_id=" << attached_object->getAttachmentItemID() + LL_INFOS() << "ATTACHMENT " << key << ": item_id=" << attached_object->getAttachmentItemID() << (attached_object ? " present " : " absent ") << (visible ? "visible " : "invisible ") << " at " << pos << " and " << (visible ? attached_object->getPosition() : LLVector3::zero) - << llendl; + << LL_ENDL; } } } @@ -7553,42 +7410,38 @@ BOOL menu_ui_enabled(void *user_data) } // TomY TODO DEPRECATE & REMOVE -void menu_toggle_control( void* user_data ) +void menu_toggle_control(void* user_data) { std::string setting(static_cast(user_data)); - BOOL checked = gSavedSettings.getBOOL(setting); - if (setting == "HighResSnapshot" && !checked) - { - // High Res Snapshot active, must uncheck RenderUIInSnapshot - gSavedSettings.setBOOL( "RenderUIInSnapshot", FALSE ); - } - else if (setting == "DoubleClickAutoPilot" && !checked) - { - // Doubleclick actions - there can be only one - gSavedSettings.setBOOL( "DoubleClickTeleport", FALSE ); - } - else if (setting == "DoubleClickTeleport" && !checked) - { - // Doubleclick actions - there can be only one - gSavedSettings.setBOOL( "DoubleClickAutoPilot", FALSE ); - } - gSavedSettings.setBOOL(setting, !checked); + LLControlVariable* control(gSavedSettings.getControl(setting)); + control->set(!control->get()); +} + +void menu_toggle_double_click_control(void* user_data) +{ + std::string setting(static_cast(user_data)); + LLControlVariable* control(gSavedSettings.getControl(setting)); + control->set(!control->get()); } // these are used in the gl menus to set control values, generically. -class LLToggleControl : public view_listener_t +class LLToggleControl final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - std::string control_name = userdata.asString(); - BOOL checked = gSavedSettings.getBOOL( control_name ); - if (control_name == "HighResSnapshot" && !checked) - { - // High Res Snapshot active, must uncheck RenderUIInSnapshot - gSavedSettings.setBOOL( "RenderUIInSnapshot", FALSE ); - } - gSavedSettings.setBOOL( control_name, !checked ); + LLControlVariable* control(gSavedSettings.getControl(userdata.asString())); + control->set(!control->get()); + return true; + } +}; + +class LLTogglePerAccountControl final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + LLControlVariable* control(gSavedPerAccountSettings.getControl(userdata.asString())); + control->set(!control->get()); return true; } }; @@ -7628,9 +7481,9 @@ void menu_toggle_attached_particles(void* user_data) LLPipeline::sRenderAttachedParticles = gSavedSettings.getBOOL("RenderAttachedParticles"); } -class LLSomethingSelected : public view_listener_t +class LLSomethingSelected final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = !(LLSelectMgr::getInstance()->getSelection()->isEmpty()); gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); @@ -7638,9 +7491,9 @@ class LLSomethingSelected : public view_listener_t } }; -class LLSomethingSelectedNoHUD : public view_listener_t +class LLSomethingSelectedNoHUD final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); bool new_value = !(selection->isEmpty()) && !(selection->getSelectType() == SELECT_TYPE_HUD); @@ -7672,21 +7525,21 @@ static bool is_editable_selected() } // [/RLVa:KB] - return (LLSelectMgr::getInstance()->getSelection()->getFirstEditableObject() != NULL); + return (LLSelectMgr::getInstance()->getSelection()->getFirstEditableObject() != nullptr); } -class LLEditableSelected : public view_listener_t +class LLEditableSelected final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { gMenuHolder->findControl(userdata["control"].asString())->setValue(is_editable_selected()); return true; } }; -class LLEditableSelectedMono : public view_listener_t +class LLEditableSelectedMono final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLViewerRegion* region = gAgent.getRegion(); if(region && gMenuHolder && gMenuHolder->findControl(userdata["control"].asString())) @@ -7700,9 +7553,9 @@ class LLEditableSelectedMono : public view_listener_t } }; -class LLToolsEnableTakeCopy : public view_listener_t +class LLToolsEnableTakeCopy final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { gMenuHolder->findControl(userdata["control"].asString())->setValue(enable_object_take_copy()); return true; @@ -7723,9 +7576,9 @@ bool enable_object_take_copy() || !gAgent.isGodlike()) # endif { - struct f : public LLSelectedObjectFunctor + struct f final : public LLSelectedObjectFunctor { - virtual bool apply(LLViewerObject* obj) + bool apply(LLViewerObject* obj) override { // return (!obj->permCopy() || obj->isAttachment()); // [RLVa:KB] - Checked: 2010-04-01 (RLVa-1.2.0c) | Modified: RLVa-1.0.0g @@ -7746,17 +7599,17 @@ bool enable_object_take_copy() } // -class LLToolsEnableAdminDelete : public view_listener_t +class LLToolsEnableAdminDelete final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - return (object != NULL); + return (object != nullptr); } }; -class LLToolsAdminDelete : public view_listener_t +class LLToolsAdminDelete final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLSelectMgr::getInstance()->selectForceDelete(); return true; @@ -7768,9 +7621,9 @@ BOOL enable_selection_you_own_all(void*) { if (LLSelectMgr::getInstance()) { - struct f : public LLSelectedObjectFunctor + struct f final : public LLSelectedObjectFunctor { - virtual bool apply(LLViewerObject* obj) + bool apply(LLViewerObject* obj) override { return (!obj->permYouOwner()); } @@ -7789,9 +7642,9 @@ BOOL enable_selection_you_own_one(void*) { if (LLSelectMgr::getInstance()) { - struct f : public LLSelectedObjectFunctor + struct f final : public LLSelectedObjectFunctor { - virtual bool apply(LLViewerObject* obj) + virtual bool apply(LLViewerObject* obj) override { return (obj->permYouOwner()); } @@ -7806,7 +7659,7 @@ BOOL enable_selection_you_own_one(void*) return TRUE; } -class LLHasAsset : public LLInventoryCollectFunctor +class LLHasAsset final : public LLInventoryCollectFunctor { public: LLHasAsset(const LLUUID& id) : mAssetID(id), mHasAsset(FALSE) {} @@ -7830,11 +7683,11 @@ bool LLHasAsset::operator()(LLInventoryCategory* cat, return FALSE; } -BOOL enable_save_into_inventory(void*) +bool enable_save_into_inventory() { // *TODO: clean this up // find the last root - LLSelectNode* last_node = NULL; + LLSelectNode* last_node = nullptr; for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin(); iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++) { @@ -7854,7 +7707,7 @@ BOOL enable_save_into_inventory(void*) // check all pre-req's for save into inventory. if(last_node && last_node->mValid && !last_node->mItemID.isNull() && (last_node->mPermissions->getOwner() == gAgent.getID()) - && (gInventory.getItem(last_node->mItemID) != NULL)) + && (gInventory.getItem(last_node->mItemID) != nullptr)) { LLViewerObject* obj = last_node->getObject(); if( obj && !obj->isAttachment() ) @@ -7881,20 +7734,20 @@ BOOL enable_save_into_task_inventory(void*) return FALSE; } -class LLToolsEnableSaveToObjectInventory : public view_listener_t +class LLToolsEnableSaveToObjectInventory final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - bool new_value = enable_save_into_task_inventory(NULL); + bool new_value = enable_save_into_task_inventory(nullptr); gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); return true; } }; -class LLViewEnableMouselook : public view_listener_t +class LLViewEnableMouselook final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { // You can't go directly from customize avatar to mouselook. // TODO: write code with appropriate dialogs to handle this transition. @@ -7904,9 +7757,9 @@ class LLViewEnableMouselook : public view_listener_t } }; -class LLToolsEnableToolNotPie : public view_listener_t +class LLToolsEnableToolNotPie final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = ( LLToolMgr::getInstance()->getBaseTool() != LLToolPie::getInstance() ); gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); @@ -7914,9 +7767,9 @@ class LLToolsEnableToolNotPie : public view_listener_t } }; -class LLWorldEnableCreateLandmark : public view_listener_t +class LLWorldEnableCreateLandmark final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = gAgent.isGodlike() || (gAgent.getRegion() && gAgent.getRegion()->getAllowLandmark()); @@ -7928,9 +7781,9 @@ class LLWorldEnableCreateLandmark : public view_listener_t } }; -class LLWorldEnableSetHomeLocation : public view_listener_t +class LLWorldEnableSetHomeLocation final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = gAgent.isGodlike() || (gAgent.getRegion() && gAgent.getRegion()->getAllowSetHome()); @@ -7939,9 +7792,9 @@ class LLWorldEnableSetHomeLocation : public view_listener_t } }; -class LLWorldEnableTeleportHome : public view_listener_t +class LLWorldEnableTeleportHome final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLViewerRegion* regionp = gAgent.getRegion(); bool agent_on_prelude = (regionp && regionp->isPrelude()); @@ -7986,9 +7839,9 @@ BOOL check_show_xui_names(void *) return gSavedSettings.getBOOL("ShowXUINames"); } -class LLToolsSelectOnlyMyObjects : public view_listener_t +class LLToolsSelectOnlyMyObjects final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { BOOL cur_val = gSavedSettings.getBOOL("SelectOwnedOnly"); @@ -7998,9 +7851,9 @@ class LLToolsSelectOnlyMyObjects : public view_listener_t } }; -class LLToolsSelectOnlyMovableObjects : public view_listener_t +class LLToolsSelectOnlyMovableObjects final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { BOOL cur_val = gSavedSettings.getBOOL("SelectMovableOnly"); @@ -8010,9 +7863,9 @@ class LLToolsSelectOnlyMovableObjects : public view_listener_t } }; -class LLToolsSelectBySurrounding : public view_listener_t +class LLToolsSelectBySurrounding final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLSelectMgr::sRectSelectInclusive = !LLSelectMgr::sRectSelectInclusive; @@ -8021,9 +7874,9 @@ class LLToolsSelectBySurrounding : public view_listener_t } }; -class LLToolsShowSelectionHighlights : public view_listener_t +class LLToolsShowSelectionHighlights final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLControlVariable *ctrl = gSavedSettings.getControl("RenderHighlightSelections"); ctrl->setValue(!ctrl->getValue().asBoolean()); @@ -8031,9 +7884,9 @@ class LLToolsShowSelectionHighlights : public view_listener_t } }; -class LLToolsShowHiddenSelection : public view_listener_t +class LLToolsShowHiddenSelection final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { // TomY TODO Merge these LLSelectMgr::sRenderHiddenSelections = !LLSelectMgr::sRenderHiddenSelections; @@ -8043,9 +7896,9 @@ class LLToolsShowHiddenSelection : public view_listener_t } }; -class LLToolsShowSelectionLightRadius : public view_listener_t +class LLToolsShowSelectionLightRadius final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { // TomY TODO merge these LLSelectMgr::sRenderLightRadius = !LLSelectMgr::sRenderLightRadius; @@ -8055,9 +7908,9 @@ class LLToolsShowSelectionLightRadius : public view_listener_t } }; -class LLToolsEditLinkedParts : public view_listener_t +class LLToolsEditLinkedParts final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { BOOL select_individuals = gSavedSettings.getBOOL("EditLinkedParts"); if (select_individuals) @@ -8074,7 +7927,7 @@ class LLToolsEditLinkedParts : public view_listener_t void reload_personal_settings_overrides(void *) { - llinfos << "Loading overrides from " << gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT,"overrides.xml") << llendl; + LL_INFOS() << "Loading overrides from " << gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT,"overrides.xml") << LL_ENDL; gSavedSettings.loadFromFile(gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT,"overrides.xml")); } @@ -8183,11 +8036,10 @@ void init_meshes_and_morphs_menu() lod_menu->addSeparator(); - for(LLPolyMesh::morph_list_t::iterator morph_iter = morph_list.begin(); - morph_iter != morph_list.end(); ++morph_iter) + for(auto& morph : morph_list) { - std::string const& morph_name = morph_iter->first; - LLPolyMorphData* morph_data = morph_iter->second; + std::string const& morph_name = morph.first; + LLPolyMorphData* morph_data = morph.second; action_menu = new LLMenuGL(morph_name); @@ -8217,7 +8069,7 @@ void handle_mesh_save_llm(void* data) if (!mesh_name) { - llwarns << "LPolyMesh::getSharedMeshName returned NULL" << llendl; + LL_WARNS() << "LPolyMesh::getSharedMeshName returned nullptr" << LL_ENDL; return; } @@ -8230,14 +8082,14 @@ static void handle_mesh_save_llm_continued(void* data, AIFilePicker* filepicker) { if (!filepicker->hasFilename()) { - llwarns << "No file" << llendl; + LL_WARNS() << "No file" << LL_ENDL; return; } std::string selected_filename = filepicker->getFilename(); LLPolyMeshSharedData* mesh_shared = (LLPolyMeshSharedData*) data; std::string const* mesh_name = LLPolyMesh::getSharedMeshName(mesh_shared); - llinfos << "Selected " << selected_filename << " for mesh " << *mesh_name <hasFilename()) { - llwarns << "No file" << llendl; + LL_WARNS() << "No file" << LL_ENDL; return; } std::string selected_filename = filepicker->getFilename(); LLPolyMeshSharedData* mesh_shared = (LLPolyMeshSharedData*)data; std::string const* mesh_name = LLPolyMesh::getSharedMeshName(mesh_shared); - llinfos << "Selected " << selected_filename << " for mesh " << *mesh_name <hasFilename()) { - llwarns << "No file" << llendl; + LL_WARNS() << "No file" << LL_ENDL; return; } std::string selected_filename = filepicker->getFilename(); LLPolyMeshSharedData* mesh_shared = (LLPolyMeshSharedData*) data; std::string const* mesh_name = LLPolyMesh::getSharedMeshName(mesh_shared); - llinfos << "Selected " << selected_filename << " for mesh " << *mesh_name <hasFilename()) { - llwarns << "No file" << llendl; + LL_WARNS() << "No file" << LL_ENDL; return; } std::string selected_filename = filepicker->getFilename(); LLPolyMeshSharedData* mesh_shared = (LLPolyMeshSharedData*) data; std::string const* mesh_name = LLPolyMesh::getSharedMeshName(mesh_shared); - llinfos << "Selected " << selected_filename << " for mesh " << *mesh_name <getExpandedFilename(LL_PATH_CHARACTER, ""); @@ -8448,18 +8300,18 @@ static void handle_morph_save_obj_continued(void* data, AIFilePicker* filepicker { if (!filepicker->hasFilename()) { - llwarns << "No file" << llendl; + LL_WARNS() << "No file" << LL_ENDL; return; } std::string selected_filename = filepicker->getFilename(); LLPolyMorphData* morph_data = (LLPolyMorphData*)data; - llinfos << "Selected " << selected_filename << llendl; + LL_INFOS() << "Selected " << selected_filename << LL_ENDL; LLFILE* fp = LLFile::fopen(selected_filename, "wb"); /*Flawfinder: ignore*/ if (!fp) { - llerrs << "can't open: " << selected_filename << llendl; + LL_ERRS() << "can't open: " << selected_filename << LL_ENDL; return; } @@ -8478,11 +8330,11 @@ void handle_morph_load_obj(void* data) if (!mesh_name) { - llwarns << "LPolyMesh::getSharedMeshName returned NULL" << llendl; + LL_WARNS() << "LPolyMesh::getSharedMeshName returned nullptr" << LL_ENDL; return; } - llinfos << "Load morph OBJ " << morph_name << " of mesh " << *mesh_name <open(FFLOAD_ALL, default_path, "mesh_obj"); @@ -8493,23 +8345,23 @@ static void handle_morph_load_obj_continued(void* data, AIFilePicker* filepicker { if(!filepicker->hasFilename()) { - llwarns << "No file" << llendl; + LL_WARNS() << "No file" << LL_ENDL; return; } std::string selected_filename = filepicker->getFilename(); LLPolyMorphData* morph_data = (LLPolyMorphData*) data; LLPolyMeshSharedData* mesh_shared = morph_data->mMesh; - llinfos << "Selected " << selected_filename <isAvatar() ) { - object = NULL; + object = nullptr; } } @@ -8541,7 +8393,7 @@ LLVOAvatar* find_avatar_from_object( LLViewerObject* object ) // Returns a pointer to the avatar give the UUID of the avatar OR of an attachment the avatar is wearing. -// Returns NULL on failure. +// Returns nullptr on failure. LLVOAvatar* find_avatar_from_object( const LLUUID& object_id ) { return find_avatar_from_object( gObjectList.findObject(object_id) ); @@ -8583,14 +8435,14 @@ void force_error_driver_crash(void *) LLAppViewer::instance()->forceErrorDriverCrash(); } -class LLToolsUseSelectionForGrid : public view_listener_t +class LLToolsUseSelectionForGrid final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLSelectMgr::getInstance()->clearGridObjects(); - struct f : public LLSelectedObjectFunctor + struct f final : public LLSelectedObjectFunctor { - virtual bool apply(LLViewerObject* objectp) + bool apply(LLViewerObject* objectp) override { LLSelectMgr::getInstance()->addGridObject(objectp); return true; @@ -8633,8 +8485,8 @@ BOOL LLViewerMenuHolderGL::hideMenus() } // drop pie menu selection - mParcelSelection = NULL; - mObjectSelection = NULL; + mParcelSelection = nullptr; + mObjectSelection = nullptr; if (gMenuBarView) { @@ -8715,7 +8567,7 @@ static void handle_load_from_xml_continued(AIFilePicker* filepicker) void handle_web_browser_test(void*) { - LLWeb::loadURL("http://secondlife.com/app/search/slurls.html"); + LLWeb::loadURLInternal("http://secondlife.com/app/search/slurls.html"); } void handle_buy_currency_test(void*) @@ -8729,7 +8581,7 @@ void handle_buy_currency_test(void*) replace["[LANGUAGE]"] = LLUI::getLanguage(); LLStringUtil::format(url, replace); - llinfos << "buy currency url " << url << llendl; + LL_INFOS() << "buy currency url " << url << LL_ENDL; LLFloaterHtmlCurrency* floater = LLFloaterHtmlCurrency::showInstance(url); // Needed so we can use secondlife:///app/floater/self/close SLURLs @@ -8748,6 +8600,7 @@ void handle_rebake_textures(void*) { LLAppearanceMgr::instance().requestServerAppearanceUpdate(); } + gAgent.setIsCrossingRegion(false); // Attachments getting lost on TP } void toggle_visibility(void* user_data) @@ -8763,18 +8616,18 @@ BOOL get_visibility(void* user_data) } // TomY TODO: Get rid of these? -class LLViewShowHoverTips : public view_listener_t +class LLViewShowHoverTips final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { LLHoverView::sShowHoverTips = !LLHoverView::sShowHoverTips; return true; } }; -class LLViewCheckShowHoverTips : public view_listener_t +class LLViewCheckShowHoverTips final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = LLHoverView::sShowHoverTips; gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); @@ -8783,9 +8636,9 @@ class LLViewCheckShowHoverTips : public view_listener_t }; // TomY TODO: Get rid of these? -class LLViewHighlightTransparent : public view_listener_t +class LLViewHighlightTransparent final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { // [RLVa:KB] - Checked: 2010-04-11 (RLVa-1.2.0e) | Modified: RLVa-1.0.0b | OK if ( (gRlvHandler.hasBehaviour(RLV_BHVR_EDIT)) && (!LLDrawPoolAlpha::sShowDebugAlpha)) @@ -8797,9 +8650,9 @@ class LLViewHighlightTransparent : public view_listener_t } }; -class LLViewCheckHighlightTransparent : public view_listener_t +class LLViewCheckHighlightTransparent final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = LLDrawPoolAlpha::sShowDebugAlpha; gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); @@ -8807,9 +8660,9 @@ class LLViewCheckHighlightTransparent : public view_listener_t } }; -class LLViewToggleRenderType : public view_listener_t +class LLViewToggleRenderType final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { std::string type = userdata.asString(); if (type == "hideparticles") @@ -8820,9 +8673,9 @@ class LLViewToggleRenderType : public view_listener_t } }; -class LLViewCheckRenderType : public view_listener_t +class LLViewCheckRenderType final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { std::string type = userdata["data"].asString(); bool new_value = false; @@ -8835,9 +8688,9 @@ class LLViewCheckRenderType : public view_listener_t } }; -class LLViewShowHUDAttachments : public view_listener_t +class LLViewShowHUDAttachments final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { // [RLVa:KB] - Checked: 2010-04-19 (RLVa-1.2.1a) | Modified: RLVa-1.0.0c if ( (rlv_handler_t::isEnabled()) && (gRlvAttachmentLocks.hasLockedHUD()) && (LLPipeline::sShowHUDAttachments) ) @@ -8849,9 +8702,9 @@ class LLViewShowHUDAttachments : public view_listener_t } }; -class LLViewCheckHUDAttachments : public view_listener_t +class LLViewCheckHUDAttachments final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = LLPipeline::sShowHUDAttachments; gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); @@ -8859,9 +8712,9 @@ class LLViewCheckHUDAttachments : public view_listener_t } }; -class LLEditEnableTakeOff : public view_listener_t +class LLEditEnableTakeOff final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { bool new_value = false; std::string control_name = userdata["control"].asString(); @@ -8881,9 +8734,9 @@ class LLEditEnableTakeOff : public view_listener_t } }; -class LLEditTakeOff : public view_listener_t +class LLEditTakeOff final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { std::string clothing = userdata.asString(); if (clothing == "all") @@ -8921,18 +8774,9 @@ class LLEditTakeOff : public view_listener_t } }; -class LLWorldChat : public view_listener_t +class LLToolsSelectTool final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) - { - handle_chat(NULL); - return true; - } -}; - -class LLToolsSelectTool : public view_listener_t -{ - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { std::string tool_name = userdata.asString(); if (tool_name == "focus") @@ -8960,9 +8804,9 @@ class LLToolsSelectTool : public view_listener_t }; /// WINDLIGHT callbacks -class LLWorldEnvSettings : public view_listener_t +class LLWorldEnvSettings final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { // [RLVa:KB] - Checked: 2010-03-18 (RLVa-1.2.0a) | Modified: RLVa-1.0.0g if (gRlvHandler.hasBehaviour(RLV_BHVR_SETENV)) @@ -8970,22 +8814,6 @@ class LLWorldEnvSettings : public view_listener_t // [/RLVa:KB] std::string tod = userdata.asString(); - - if (tod == "editor") - { - // if not there or is hidden, show it - if( !LLFloaterEnvSettings::isOpen() || - !LLFloaterEnvSettings::instance()->getVisible()) - { - LLFloaterEnvSettings::show(); - } - else - { - // otherwise, close it button acts like a toggle - LLFloaterEnvSettings::instance()->close(); - } - return true; - } if (tod == "sunrise") { @@ -9012,448 +8840,810 @@ class LLWorldEnvSettings : public view_listener_t } }; -/// Water Menu callbacks -class LLWorldWaterSettings : public view_listener_t +class LLWorldEnableEnvSettings final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { -// [RLVa:KB] - Checked: 2009-07-10 (RLVa-1.0.0g) - if (gRlvHandler.hasBehaviour(RLV_BHVR_SETENV)) + bool result = false; + std::string tod = userdata.asString(); + + if (tod == "region") { - return true; + return LLEnvManagerNew::instance().getUseRegionSettings(); } -// [/RLVa:KB] - // if not there or is hidden, show it - if( !LLFloaterWater::isOpen() || - !LLFloaterWater::instance()->getVisible()) { - LLFloaterWater::show(); - - // otherwise, close it button acts like a toggle - } - else + if (LLEnvManagerNew::instance().getUseFixedSky()) { - LLFloaterWater::instance()->close(); + if (tod == "sunrise") + { + result = (LLEnvManagerNew::instance().getSkyPresetName() == "Sunrise"); + } + else if (tod == "noon") + { + result = (LLEnvManagerNew::instance().getSkyPresetName() == "Midday"); + } + else if (tod == "sunset") + { + result = (LLEnvManagerNew::instance().getSkyPresetName() == "Sunset"); + } + else if (tod == "midnight") + { + result = (LLEnvManagerNew::instance().getSkyPresetName() == "Midnight"); + } + else + { + LL_WARNS() << "Unknown item" << LL_ENDL; + } } - return true; + return result; } }; -/// Post-Process callbacks -class LLWorldPostProcess : public view_listener_t +class LLUploadCostCalculator final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - LLFloaterPostProcess::show(); - return true; - } -}; + auto& asset_type_str = userdata["data"].asStringRef(); + S32 upload_cost = -1; + LLView* view; -/// Day Cycle callbacks -class LLWorldDayCycle : public view_listener_t -{ - bool handleEvent(LLPointer event, const LLSD& userdata) - { -// [RLVa:KB] - Checked: 2009-07-10 (RLVa-1.0.0g) - if (gRlvHandler.hasBehaviour(RLV_BHVR_SETENV)) + if (asset_type_str == "texture") { - return true; + upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost(); + view = gMenuHolder->findChild("Upload Image"); } -// [/RLVa:KB] + else if (asset_type_str == "animation") + { + upload_cost = LLAgentBenefitsMgr::current().getAnimationUploadCost(); + view = gMenuHolder->findChild("Upload Animation"); + } + else if (asset_type_str == "sound") + { + upload_cost = LLAgentBenefitsMgr::current().getSoundUploadCost(); + view = gMenuHolder->findChild("Upload Sound"); + } + else + { + LL_WARNS() << "Unable to find upload cost for asset_type_str " << asset_type_str << LL_ENDL; + return true; + } + auto ctrl = gMenuHolder->findControl(userdata["control"].asString()); + ctrl->setValue(gStatusBar && gStatusBar->getBalance() >= upload_cost); + view->setLabelArg("[UPLOADFEE]", gHippoGridManager->getConnectedGrid()->formatFee(upload_cost)); + + return true; + } +}; - LLFloaterDayCycle::show(); +// TPV listeners go below here +class SinguCloseAllDialogs final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + gNotifyBoxView->deleteAllChildren(); return true; } }; +class SinguEnableStreamingAudioDisplay final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + return handle_ticker_enabled(nullptr); + } +}; -class SinguCloseAllDialogs : public view_listener_t +class SinguPoseStand final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - handle_close_all_notifications(NULL); + if (current_pose.isNull()) + set_current_pose("038fcec9-5ebd-8a8e-0e2e-6e71a0a1ac53"); + else + handle_pose_stand_stop(nullptr); return true; } }; -class SinguAnimationOverride : public view_listener_t +class SinguCheckPoseStand final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - LLFloaterAO::show(NULL); + gMenuHolder->findControl(userdata["control"].asString())->setValue(handle_check_pose(nullptr)); + return true; + } +}; +class SinguRebake final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + handle_rebake_textures(nullptr); return true; } }; -class SinguNimble : public view_listener_t +class SinguVisibleDebugConsole final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - gSavedSettings.setBOOL("Nimble", !gSavedSettings.getBOOL("Nimble")); + LLViewerRegion* region = gAgent.getRegion(); + gMenuHolder->findControl(userdata["control"].asString())->setValue(region && !(region->getCapability("SimConsoleAsync").empty() || region->getCapability("SimConsole").empty())); + return true; + } +}; +class SinguUrlAction final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + LLUrlAction::clickAction(userdata.asStringRef(), true); return true; } }; -class SinguCheckNimble : public view_listener_t +void show_inv_floater(const LLSD& userdata, const std::string& field) +{ + LFFloaterInvPanel::toggle(LLSD().with(field, userdata)); +} + +static void visible_inv_floater(const LLSD& userdata, const std::string& field) +{ + gMenuHolder->findControl(userdata["control"].asString())->setValue(!!LFFloaterInvPanel::getInstance(LLSD().with(field, userdata["data"]))); +} + +class ShowInvFloaterID final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - gMenuHolder->findControl(userdata["control"].asString())->setValue(gSavedSettings.getBOOL("Nimble")); + show_inv_floater(userdata, "id"); + return true; + } +}; +class VisibleInvFloaterID final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + visible_inv_floater(userdata, "id"); return true; } }; -class SinguAssetBlacklist : public view_listener_t +class ShowInvFloaterName final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - LLFloaterBlacklist::toggle(); + show_inv_floater(userdata, "name"); + return true; + } +}; +class VisibleInvFloaterName final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + visible_inv_floater(userdata, "name"); return true; } }; -class SinguStreamingAudioDisplay : public view_listener_t +class ShowInvFloaterType final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - handle_ticker_toggle(NULL); + show_inv_floater(userdata, "type"); + return true; + } +}; +class VisibleInvFloaterType final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + visible_inv_floater(userdata, "type"); return true; } }; -class SinguCheckStreamingAudioDisplay : public view_listener_t +void show_web_floater(const std::string& type) { - bool handleEvent(LLPointer event, const LLSD& userdata) + auto p = LLFloaterWebContent::Params(); + if (!type.empty()) p.id = type; + if (type == "marketplace") + { + if (gHippoGridManager->getConnectedGrid()->isSecondLife()) + p.url = "https://marketplace.secondlife.com"; + else if (LLViewerRegion* region = gAgent.getRegion()) + { + LLSD info; + region->getSimulatorFeatures(info); + p.url = info["MarketplaceURL"]; + } + } + else if (!type.empty() && type != "dict web") { - gMenuHolder->findControl(userdata["control"].asString())->setValue(handle_singleton_check(NULL)); + p.url = type; // Simple web floaters with direct urls + } + LLFloaterWebContent::showInstance(type, p); +} +class ShowWebFloater final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + show_web_floater(userdata.asStringRef()); return true; } }; -class SinguEnableStreamingAudioDisplay : public view_listener_t +class VisibleSecondLife final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - return handle_ticker_enabled(NULL); + gMenuHolder->findControl(userdata["control"].asString())->setValue(gHippoGridManager->getCurrentGrid()->isSecondLife()); + return true; } }; -class SinguPoseStand : public view_listener_t +class VisibleNotSecondLife final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - handle_toggle_pose(NULL); + gMenuHolder->findControl(userdata["control"].asString())->setValue(!gHippoGridManager->getConnectedGrid()->isSecondLife()); + return true; + } +}; + +template T* get_focused() +{ + T* t = +#ifdef SHOW_ASSERT + dynamic_cast +#else + static_cast +#endif + (gFocusMgr.getKeyboardFocus()); + llassert(t); // This listener only applies to T + return t; +} + +const JCFloaterAreaSearch::ObjectData* get_obj_data(const LLUUID& id) +{ + auto areasearch = JCFloaterAreaSearch::findInstance(); + return areasearch ? areasearch->getObjectData(id) : nullptr; +} + +const LLUUID& get_obj_owner(const LLUUID& id, const JCFloaterAreaSearch::ObjectData* obj_data = nullptr, const LLViewerObject* objp = nullptr) +{ + if (const auto& obj = objp ? objp : gObjectList.findObject(id)) // Viewer Object is more likely to be up to date + return obj->mOwnerID; + if (const auto& obj = obj_data ? obj_data : get_obj_data(id)) // Fall back on Object Data + return obj->owner_id; + return LLUUID::null; +} + +const std::string get_obj_owner_slurl(const LLUUID& obj_id, const std::string& name = LLStringUtil::null, bool* group_ownedp = nullptr) +{ + bool group_owned; + LLUUID owner; + if (!group_ownedp) + { + if (const auto& obj = gObjectList.findObject(obj_id)) // Viewer Object is more likely to be up to date + { + owner = obj->mOwnerID; + group_owned = obj->flagObjectGroupOwned(); + } + else if (const auto& obj = get_obj_data(obj_id)) // Fall back on Object Data + { + owner = obj->owner_id; + group_owned = owner == obj->group_id; + } + else return name; + } + else + { + owner = get_obj_owner(obj_id); + group_owned = *group_ownedp; + } + return owner.isNull() ? name + : group_owned ? LLGroupActions::getSLURL(owner) + : LLAvatarActions::getSLURL(owner); +} + +const std::string get_obj_slurl(const LLUUID& id, const std::string& name = LLStringUtil::null) +{ + const auto& obj_data = get_obj_data(id); // Needed for object name + const auto& obj = gObjectList.findObject(id); // Has all the other object data + if (!obj_data && !obj && name.empty()) + return name; // Not enough data to show, empty string to show failure, if we had a name we could pair it with the ID at least + + LLSD sdQuery; + + sdQuery["name"] = !name.empty() ? name : + obj_data ? obj_data->name : LLTrans::getString("land_type_unknown"); + + const auto& owner = get_obj_owner(id, obj_data, obj); + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES) && (owner != gAgentID)) + sdQuery["rlv_shownames"] = true; + + sdQuery["owner"] = owner; + sdQuery["group_owned"] = obj ? obj->flagObjectGroupOwned() : obj_data && obj_data->group_id == owner; + if (const auto region = obj ? obj->getRegion() : nullptr) + sdQuery["slurl"] = LLSLURL(region->getName(), obj->getPositionAgent()).getLocationString(); + + return LLSLURL("objectim", id, LLURI::mapToQueryString(sdQuery)).getSLURLString(); +} + +const std::string get_slurl_for(const LLUUID& id, const LFIDBearer::Type& type) +{ + switch (type) + { + case LFIDBearer::GROUP: return LLGroupActions::getSLURL(id); + case LFIDBearer::AVATAR: return LLAvatarActions::getSLURL(id); + case LFIDBearer::OBJECT: return get_obj_slurl(id); + case LFIDBearer::EXPERIENCE: return LLSLURL("experience", id, "profile").getSLURLString(); + default: return LLStringUtil::null; + } +} + +const LLWString get_wslurl_for(const LLUUID& id, const LFIDBearer::Type& type) +{ + return utf8str_to_wstring(get_slurl_for(id, type)); +} + +void copy_profile_uri(const LLUUID& id, const LFIDBearer::Type& type) +{ + gViewerWindow->getWindow()->copyTextToClipboard(get_wslurl_for(id, type)); +} + +class ListEnableAnySelected final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + gMenuHolder->findControl(userdata["control"].asString())->setValue(LFIDBearer::getActiveNumSelected() != 0); return true; } }; -class SinguCheckPoseStand : public view_listener_t +class ListEnableMultipleSelected final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - gMenuHolder->findControl(userdata["control"].asString())->setValue(handle_check_pose(NULL)); + gMenuHolder->findControl(userdata["control"].asString())->setValue(LFIDBearer::getActiveNumSelected() > 1); return true; } }; -class SinguRebake : public view_listener_t +class ListEnableSingleSelected final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - handle_rebake_textures(NULL); + gMenuHolder->findControl(userdata["control"].asString())->setValue(LFIDBearer::getActiveNumSelected() == 1); return true; } }; -class SinguDebugConsole : public view_listener_t +class ListEnableCall final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - handle_singleton_toggle(NULL); + gMenuHolder->findControl(userdata["control"].asString())->setValue(LLAvatarActions::canCall()); return true; } }; -class SinguCheckDebugConsole : public view_listener_t +class ListEnableIsFriend final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - gMenuHolder->findControl(userdata["control"].asString())->setValue(handle_singleton_check(NULL)); + gMenuHolder->findControl(userdata["control"].asString())->setValue(LLAvatarActions::isFriend(LFIDBearer::getActiveSelectedID())); return true; } }; -class SinguVisibleDebugConsole : public view_listener_t +class ListEnableIsNotFriend final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - if (LLViewerRegion* region = gAgent.getRegion()) + gMenuHolder->findControl(userdata["control"].asString())->setValue(!LLAvatarActions::isFriend(LFIDBearer::getActiveSelectedID())); + return true; + } +}; + +class ListEnableUnmute final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + bool are_blocked = false; + for (const auto& id : LFIDBearer::getActiveSelectedIDs()) + if (are_blocked = LLAvatarActions::isBlocked(id)) // If any are blocked, allow unblocking + break; + + gMenuHolder->findControl(userdata["control"].asString())->setValue(are_blocked); + return true; + } +}; + +class ListEnableMute final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + bool blockable = false; + for (const auto& id : LFIDBearer::getActiveSelectedIDs()) { - if (LLView* item = gMenuBarView->getChildView("Region Debug Console", true, false)) - item->setVisible(!(region->getCapability("SimConsoleAsync").empty() || region->getCapability("SimConsole").empty())); + if (!LLAvatarActions::canBlock(id)) // Exit early only when someone is unblockable + { + blockable = false; + break; + } + else if (blockable) // At least one is unblocked, keep looking for unblockables + continue; + + blockable = !LLAvatarActions::isBlocked(id); } + + gMenuHolder->findControl(userdata["control"].asString())->setValue(blockable); return true; } }; -class VisibleNotSecondLife : public view_listener_t +class ListEnableOfferTeleport final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - gMenuHolder->findControl(userdata["control"].asString())->setValue(!gHippoGridManager->getConnectedGrid()->isSecondLife()); + gMenuHolder->findControl(userdata["control"].asString())->setValue(LLAvatarActions::canOfferTeleport(LFIDBearer::getActiveSelectedIDs())); return true; } }; -LLScrollListCtrl* get_focused_list() +class ListVisibleWebProfile final : public view_listener_t { - LLScrollListCtrl* list = dynamic_cast(gFocusMgr.getKeyboardFocus()); - llassert(list); // This listener only applies to lists - return list; -} + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + gMenuHolder->findControl(userdata["control"].asString())->setValue(LFIDBearer::getActiveNumSelected() && !(gSavedSettings.getBOOL("UseWebProfiles") || gSavedSettings.getString("WebProfileURL").empty())); + return true; + } +}; -S32 get_focused_list_num_selected() +void ban_from_group(const uuid_vec_t& ids); +class ListBanFromGroup final : public view_listener_t { - if (LLScrollListCtrl* list = get_focused_list()) - return list->getNumSelected(); - return 0; -} + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + ban_from_group(LFIDBearer::getActiveSelectedIDs()); + return true; + } +}; + +void copy_from_ids(const uuid_vec_t & ids, std::function func); -const LLUUID get_focused_list_id_selected() +uuid_vec_t get_active_owner_ids() { - if (LLScrollListCtrl* list = get_focused_list()) - return list->getStringUUIDSelectedItem(); - return LLUUID::null; + uuid_vec_t ret; + for (const auto& id : LFIDBearer::getActiveSelectedIDs()) + { + const auto& owner_id = get_obj_owner(id); + if (owner_id.notNull()) ret.push_back(owner_id); + } + return ret; } -const uuid_vec_t get_focused_list_ids_selected() +const LLUUID& get_active_owner_id() { - if (LLScrollListCtrl* list = get_focused_list()) - return list->getSelectedIDs(); - return uuid_vec_t(); + return get_obj_owner(LFIDBearer::getActiveSelectedID()); } -class ListEnableAnySelected : public view_listener_t +class ListCopyNames final : public view_listener_t +{ + static std::string getGroupName(const LLUUID& id) + { + std::string ret; + gCacheName->getGroupName(id, ret); + return ret; + } + + static std::string getAvatarName(const LLUUID& id) + { + std::string ret; + LLAvatarNameCache::getNSName(id, ret); + return ret; + } + + static std::string getObjectName(const LLUUID& id) + { + const auto& obj_data = get_obj_data(id); + return obj_data ? obj_data->name : LLStringUtil::null; + } + + static std::string getExperienceName(const LLUUID& id) + { + return LLExperienceCache::instance().get(id)[LLExperienceCache::NAME]; + } + + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + LLWString str; + const auto& type = LFIDBearer::getActiveType(); + bool owner = !userdata.asBoolean(); + copy_from_ids(owner ? get_active_owner_ids() : LFIDBearer::getActiveSelectedIDs(), type == LFIDBearer::GROUP ? getGroupName : + type == LFIDBearer::OBJECT ? owner ? getAvatarName : getObjectName : + type == LFIDBearer::EXPERIENCE ? getExperienceName : + getAvatarName); + if (!str.empty()) LLView::getWindow()->copyTextToClipboard(str); + return true; + } +}; +class ListCopySLURL final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - gMenuHolder->findControl(userdata["control"].asString())->setValue(get_focused_list_num_selected()); + bool owner = !userdata.asBoolean(); + copy_profile_uri(owner ? get_active_owner_id() : LFIDBearer::getActiveSelectedID(), owner ? LFIDBearer::AVATAR : LFIDBearer::getActiveType()); return true; } }; -class ListEnableMultipleSelected : public view_listener_t +const LLUUID& active_owner_or_id(const LLSD& userdata) { - bool handleEvent(LLPointer event, const LLSD& userdata) + return !userdata.asBoolean() ? get_active_owner_id() : LFIDBearer::getActiveSelectedID(); +} + +#define active_owners_or_ids(userdata) !userdata.asBoolean() ? get_active_owner_ids() : LFIDBearer::getActiveSelectedIDs() + +class ListCopyUUIDs final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override { - gMenuHolder->findControl(userdata["control"].asString())->setValue(get_focused_list_num_selected() > 1); + LLAvatarActions::copyUUIDs(active_owners_or_ids(userdata)); return true; } }; -class ListEnableSingleSelected : public view_listener_t +class ListInviteToGroup final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - gMenuHolder->findControl(userdata["control"].asString())->setValue(get_focused_list_num_selected() == 1); + LLAvatarActions::inviteToGroup(active_owners_or_ids(userdata)); return true; } }; -class ListEnableCall : public view_listener_t +class ListOfferTeleport final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - LLScrollListCtrl* list = get_focused_list(); - if (!list) return false; - gMenuHolder->findControl(userdata["control"].asString())->setValue(LLAvatarActions::canCall()); + LLAvatarActions::offerTeleport(active_owners_or_ids(userdata)); return true; } }; -class ListEnableIsFriend : public view_listener_t +class ListPay final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - gMenuHolder->findControl(userdata["control"].asString())->setValue(LLAvatarActions::isFriend(get_focused_list_id_selected())); + LLAvatarActions::pay(active_owner_or_id(userdata)); return true; } }; -class ListEnableIsNotFriend : public view_listener_t +class ListRemoveFriend final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - gMenuHolder->findControl(userdata["control"].asString())->setValue(!LLAvatarActions::isFriend(get_focused_list_id_selected())); + LLAvatarActions::removeFriendDialog(active_owner_or_id(userdata)); return true; } }; -class ListEnableMute : public view_listener_t +class ListRequestFriendship final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - const uuid_vec_t& ids = get_focused_list_ids_selected(); - bool can_block = true; - for (uuid_vec_t::const_iterator it = ids.begin(); can_block && it != ids.end(); ++it) - can_block = LLAvatarActions::canBlock(*it); - gMenuHolder->findControl(userdata["control"].asString())->setValue(can_block); + LLAvatarActions::requestFriendshipDialog(active_owner_or_id(userdata)); return true; } }; -class ListEnableOfferTeleport : public view_listener_t +class ListRequestTeleport final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - gMenuHolder->findControl(userdata["control"].asString())->setValue(LLAvatarActions::canOfferTeleport(get_focused_list_ids_selected())); + LLAvatarActions::teleportRequest(active_owner_or_id(userdata)); return true; } }; -class ListVisibleWebProfile : public view_listener_t +class ListShare final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - gMenuHolder->findControl(userdata["control"].asString())->setValue(get_focused_list_num_selected() && !(gSavedSettings.getBOOL("UseWebProfiles") || gSavedSettings.getString("WebProfileURL").empty())); + LLAvatarActions::share(active_owner_or_id(userdata)); return true; } }; -class ListCopyUUIDs : public view_listener_t +bool can_show_web_profile() +{ + return !gSavedSettings.getString("WebProfileURL").empty(); +} + +void show_log_browser(const LLUUID& id, const LFIDBearer::Type& type); +class ListShowLog final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - LLAvatarActions::copyUUIDs(get_focused_list_ids_selected()); + const auto& type = userdata.asBoolean() ? LFIDBearer::getActiveType() : LFIDBearer::AVATAR; + for (const LLUUID& id : active_owners_or_ids(userdata)) + show_log_browser(id, type); return true; } }; -class ListInviteToGroup : public view_listener_t +class ListShowProfile final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - LLAvatarActions::inviteToGroup(get_focused_list_id_selected()); + switch (LFIDBearer::getActiveType()) + { + case LFIDBearer::AVATAR: LLAvatarActions::showProfiles(LFIDBearer::getActiveSelectedIDs()); break; + case LFIDBearer::GROUP: LLGroupActions::showProfiles(LFIDBearer::getActiveSelectedIDs()); break; + case LFIDBearer::OBJECT: + if (userdata.asBoolean()) + for (const auto& id : LFIDBearer::getActiveSelectedIDs()) LLUrlAction::openURL(get_slurl_for(id, LFIDBearer::OBJECT)); + else // Owners + LLAvatarActions::showProfiles(get_active_owner_ids()); + break; + case LFIDBearer::EXPERIENCE: for (const auto& id : LFIDBearer::getActiveSelectedIDs()) LLFloaterExperienceProfile::showInstance(id); break; + default: break; + } return true; } }; -class ListOfferTeleport : public view_listener_t +class ListShowWebProfile final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - LLAvatarActions::offerTeleport(get_focused_list_ids_selected()); + LLAvatarActions::showProfiles(active_owners_or_ids(userdata), true); return true; } }; -class ListPay : public view_listener_t +class ListStartAdhocCall final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - LLAvatarActions::pay(get_focused_list_id_selected()); + LLAvatarActions::startAdhocCall(active_owners_or_ids(userdata)); return true; } }; -class ListRemoveFriend : public view_listener_t +class ListStartCall final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - LLAvatarActions::removeFriendDialog(get_focused_list_id_selected()); + (LFIDBearer::getActiveType() == LFIDBearer::GROUP ? LLGroupActions::startCall : LLAvatarActions::startCall)(active_owner_or_id(userdata)); return true; } }; -class ListRequestFriendship : public view_listener_t +class ListStartConference final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - LLAvatarActions::requestFriendshipDialog(get_focused_list_id_selected()); + LLAvatarActions::startConference(active_owners_or_ids(userdata)); return true; } }; -class ListRequestTeleport : public view_listener_t +class ListStartIM final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - LLAvatarActions::teleportRequest(get_focused_list_id_selected()); + const auto&& im = LFIDBearer::getActiveType() == LFIDBearer::GROUP ? [](const LLUUID& id) { LLGroupActions::startIM(id); } : LLAvatarActions::startIM; + for (const auto& id : active_owners_or_ids(userdata)) + im(id); return true; } }; -class ListShowProfile : public view_listener_t +const LLVector3d& get_av_pos(const LLUUID& id); +const LLVector3d get_obj_pos(const LLUUID& id) +{ + if (const auto& obj = gObjectList.findObject(id)) + return obj->getPositionGlobal(); + return LLVector3d::zero; +} +static const LLVector3d get_active_pos(const LLSD& userdata) { - bool handleEvent(LLPointer event, const LLSD& userdata) + const auto& id = active_owner_or_id(userdata); + if (userdata.asBoolean() && LFIDBearer::getActiveType() == LFIDBearer::OBJECT) + return get_obj_pos(id); + return get_av_pos(id); +} + +class ListTeleportTo final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override { - LLAvatarActions::showProfiles(get_focused_list_ids_selected()); + const auto& pos = get_active_pos(userdata); + if (!pos.isExactlyZero()) + gAgent.teleportViaLocation(pos); return true; } }; -class ListShowWebProfile : public view_listener_t +class ListStalk final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - LLAvatarActions::showProfiles(get_focused_list_ids_selected(), true); + LLAvatarActions::showOnMap(active_owner_or_id(userdata)); return true; } }; -class ListStartAdhocCall : public view_listener_t +class ListStalkable final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - LLAvatarActions::startAdhocCall(get_focused_list_ids_selected()); + BOOL is_agent_mappable(const LLUUID& agent_id); + const auto& ids = active_owners_or_ids(userdata["data"]); + gMenuHolder->findControl(userdata["control"].asString())->setValue(ids.size() == 1 && is_agent_mappable(ids[0])); return true; } }; -class ListStartCall : public view_listener_t +class ListAbuseReport final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - LLAvatarActions::startCall(get_focused_list_id_selected()); + if (LFIDBearer::getActiveType() == LFIDBearer::EXPERIENCE) + LLFloaterReporter::showFromExperience(LFIDBearer::getActiveSelectedID()); + else + LLFloaterReporter::showFromObject(active_owner_or_id(userdata)); return true; } }; -class ListStartConference : public view_listener_t +void set_experience_permission(const char* perm, const uuid_vec_t& ids) { - bool handleEvent(LLPointer event, const LLSD& userdata) + if (!gAgent.getRegion()) return; + auto& cache = LLExperienceCache::instance(); + for (const auto& id : ids) + cache.setExperiencePermission(id, perm, boost::bind(LLFloaterExperienceProfile::experiencePermissionResults, id, _1)); +} + +class ListExperienceAllow final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override { - LLAvatarActions::startConference(get_focused_list_ids_selected()); + set_experience_permission("Allow", LFIDBearer::getActiveSelectedIDs()); return true; } }; -class ListStartIM : public view_listener_t +class ListExperienceForget final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - LLAvatarActions::startIM(get_focused_list_id_selected()); + if (!gAgent.getRegion()) return true; + auto& cache = LLExperienceCache::instance(); + for (const auto& id : LFIDBearer::getActiveSelectedIDs()) + cache.forgetExperiencePermission(id, boost::bind(LLFloaterExperienceProfile::experiencePermissionResults, id, _1)); return true; } }; -/* Singu TODO: Figure out why this wouldn't work -class ListAbuseReport : public view_listener_t +class ListExperienceBlock final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - LLFloaterReporter::showFromObject(get_focused_list_id_selected()); + set_experience_permission("Block", LFIDBearer::getActiveSelectedIDs()); return true; } }; -*/ // Create the args for administrative notifications used in lists, tossing the selected names into it. LLSD create_args(const uuid_vec_t& ids, const std::string& token) @@ -9473,71 +9663,365 @@ void parcel_mod_notice_callback(const uuid_vec_t& ids, S32 choice, boost::functi cb(*it, choice); } +bool is_nearby(const LLUUID& id); +class ListIsNearby final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + const auto& data = userdata["data"]; + const auto& id = active_owner_or_id(data); + gMenuHolder->findControl(userdata["control"].asString())->setValue((LFIDBearer::getActiveType() == LFIDBearer::OBJECT && data.asBoolean()) ? !!gObjectList.findObject(id) : is_nearby(id)); + return true; + } +}; + +class ListFollow final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + gAgent.startFollowPilot(active_owner_or_id(userdata), true, gSavedSettings.getF32("SinguFollowDistance")); + return true; + } +}; + +class ListGoTo final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + const auto& pos = get_active_pos(userdata); + if (!pos.isExactlyZero()) + handle_go_to(pos); + return true; + } +}; + +void track_av(const LLUUID& id); +class ListTrack final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + track_av(active_owner_or_id(userdata)); + return true; + } +}; + void send_eject(const LLUUID& avatar_id, bool ban); -class ListEject : public view_listener_t +void confirm_eject(const uuid_vec_t& ids) { - bool handleEvent(LLPointer event, const LLSD& userdata) + LLNotificationsUtil::add("EjectAvatarFullname", create_args(ids, "AVATAR_NAME"), LLSD(), boost::bind(parcel_mod_notice_callback, ids, boost::bind(LLNotificationsUtil::getSelectedOption, _1, _2), send_eject)); +} +class ListEject final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override { - const uuid_vec_t& ids = get_focused_list_ids_selected(); - LLNotificationsUtil::add("EjectAvatarFullname", create_args(ids, "AVATAR_NAME"), LLSD(), boost::bind(parcel_mod_notice_callback, ids, boost::bind(LLNotificationsUtil::getSelectedOption, _1, _2), send_eject)); + confirm_eject(active_owners_or_ids(userdata)); return true; } }; void send_freeze(const LLUUID& avatar_id, bool freeze); -class ListFreeze : public view_listener_t +void confirm_freeze(const uuid_vec_t& ids) +{ + LLNotificationsUtil::add("FreezeAvatarFullname", create_args(ids, "AVATAR_NAME"), LLSD(), boost::bind(parcel_mod_notice_callback, ids, boost::bind(LLNotificationsUtil::getSelectedOption, _1, _2), send_freeze)); +} +class ListFreeze final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - const uuid_vec_t& ids = get_focused_list_ids_selected(); - LLNotificationsUtil::add("FreezeAvatarFullname", create_args(ids, "AVATAR_NAME"), LLSD(), boost::bind(parcel_mod_notice_callback, ids, boost::bind(LLNotificationsUtil::getSelectedOption, _1, _2), send_freeze)); + confirm_freeze(active_owners_or_ids(userdata)); return true; } }; -void estate_bulk_eject(const uuid_vec_t& ids, bool ban, S32 zero) +void send_estate_message(const std::string request, const std::vector& strings) { - if (ids.empty() || zero != 0) return; - std::vector strings(2, gAgentID.asString()); // [0] = our agent id - for (uuid_vec_t::const_iterator it = ids.begin(); it != ids.end(); ++it) + LLRegionInfoModel::sendEstateOwnerMessage(gMessageSystem, request, LLFloaterRegionInfo::getLastInvoice(), strings); +} + +void estate_bulk_eject(const uuid_vec_t& ids, bool ban, S32 option) +{ + if (ids.empty() || option == (ban ? 1 : 2)) return; + const bool tphome(option == 1); + const std::string agent(tphome ? gAgentID.asString() : LLStringUtil::null); + std::vector strings; + if (!tphome) strings.reserve(ids.size()); + for (const LLUUID& id : ids) { - LLUUID id(*it); if (id.isNull()) continue; - strings[1] = id.asString(); // [1] = target agent id - - LLRegionInfoModel::sendEstateOwnerMessage(gMessageSystem, "teleporthomeuser", LLFloaterRegionInfo::getLastInvoice(), strings); + const std::string idstr(id.asString()); + if (tphome) + send_estate_message("teleporthomeuser", {agent, idstr}); + else + strings.push_back(idstr); if (ban) - LLPanelEstateInfo::sendEstateAccessDelta(ESTATE_ACCESS_BANNED_AGENT_ADD | ESTATE_ACCESS_ALLOWED_AGENT_REMOVE | ESTATE_ACCESS_NO_REPLY, id); + LLPanelEstateAccess::sendEstateAccessDelta(ESTATE_ACCESS_BANNED_AGENT_ADD | ESTATE_ACCESS_ALLOWED_AGENT_REMOVE | ESTATE_ACCESS_NO_REPLY, id); } + if (!tphome) send_estate_message("kickestate", strings); +} + +void confirm_estate_ban(const uuid_vec_t& ids) +{ + LLNotificationsUtil::add("EstateBanUser", create_args(ids, "EVIL_USER"), LLSD(), boost::bind(estate_bulk_eject, ids, true, boost::bind(LLNotificationsUtil::getSelectedOption, _1, _2))); } +class ListEstateBan final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + confirm_estate_ban(active_owners_or_ids(userdata)); + return true; + } +}; -class ListEstateBan : public view_listener_t +void confirm_estate_kick(const uuid_vec_t& ids) +{ + LLNotificationsUtil::add("EstateKickUser", create_args(ids, "EVIL_USER"), LLSD(), boost::bind(estate_bulk_eject, ids, false, boost::bind(LLNotificationsUtil::getSelectedOption, _1, _2))); +} +class ListEstateEject final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - const uuid_vec_t& ids = get_focused_list_ids_selected(); - LLNotificationsUtil::add("EstateBanUser", create_args(ids, "EVIL_USER"), LLSD(), boost::bind(estate_bulk_eject, ids, true, boost::bind(LLNotificationsUtil::getSelectedOption, _1, _2))); + confirm_estate_kick(active_owners_or_ids(userdata)); return true; } }; -class ListEstateEject : public view_listener_t +class ListToggleMute final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - const uuid_vec_t& ids = get_focused_list_ids_selected(); - LLNotificationsUtil::add("EstateKickUser", create_args(ids, "EVIL_USER"), LLSD(), boost::bind(estate_bulk_eject, ids, false, boost::bind(LLNotificationsUtil::getSelectedOption, _1, _2))); + for (const auto& id : active_owners_or_ids(userdata)) + LLAvatarActions::toggleBlock(id); return true; } }; -class ListToggleMute : public view_listener_t +class ListIsInGroup final : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - const uuid_vec_t& ids = get_focused_list_ids_selected(); - for (uuid_vec_t::const_iterator it = ids.begin(); it != ids.end(); ++it) - LLAvatarActions::toggleBlock(*it); + auto in_group = false; + for (const auto& id : LFIDBearer::getActiveSelectedIDs()) + if (!(in_group = LLGroupActions::isInGroup(id))) + break; + gMenuHolder->findControl(userdata["control"].asString())->setValue(in_group); + return true; + } +}; + +class ListNotInGroup final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + auto in_group = true; + for (const auto& id : LFIDBearer::getActiveSelectedIDs()) + if (in_group = LLGroupActions::isInGroup(id)) + break; + gMenuHolder->findControl(userdata["control"].asString())->setValue(!in_group); + return true; + } +}; + +class ListLeave final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + for (const auto& id : LFIDBearer::getActiveSelectedIDs()) + LLGroupActions::leave(id); + return true; + } +}; + +class ListJoin final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + for (const auto& id : LFIDBearer::getActiveSelectedIDs()) + LLGroupActions::join(id); + return true; + } +}; + +class ListActivate final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + for (const auto& id : LFIDBearer::getActiveSelectedIDs()) + LLGroupActions::activate(id); + return true; + } +}; + +class ListObjectCamTo final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + gAgentCamera.lookAtObject(LFIDBearer::getActiveSelectedID(), false); + return true; + } +}; + +class ListObjectSit final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + gAgent.stopAutoPilot(true); + handle_object_sit(gObjectList.findObject(LFIDBearer::getActiveSelectedID())); + return true; + } +}; + +class ListObjectPay final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + handle_give_money_dialog(gObjectList.findObject(LFIDBearer::getActiveSelectedID())); + return true; + } +}; + +class ListObjectEnablePay final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + const auto& ids = LFIDBearer::getActiveSelectedIDs(); + gMenuHolder->findControl(userdata["control"].asString())->setValue(ids.size() == 1 && enable_pay_object(gObjectList.findObject(ids[0]))); + return true; + } +}; + +void list_for_each_object(std::function func) +{ + for (const auto& id : LFIDBearer::getActiveSelectedIDs()) + if (auto obj = gObjectList.findObject(id)) + func(obj); +} + +class ListObjectTouch final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + list_for_each_object([](LLViewerObject* obj) { if (enable_object_touch(obj)) handle_object_touch(obj); }); + return true; + } +}; + +bool list_has_valid_object(std::function func) +{ + for (const auto& id : LFIDBearer::getActiveSelectedIDs()) + if (func(gObjectList.findObject(id))) + return true; // First is fine enough, we'll use all we can + return false; +} + +// One object must have touch sensor +class ListObjectEnableTouch final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + gMenuHolder->findControl(userdata["control"].asString())->setValue(list_has_valid_object([](LLViewerObject* obj){ return enable_object_touch(obj); })); + return true; + } +}; + +class ListObjectEdit final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + std::vector objs; + auto func = rlv_handler_t::isEnabled() ? static_cast>([&objs](LLViewerObject* obj) { if (gRlvHandler.canEdit(obj)) objs.push_back(obj); }) : [&objs](LLViewerObject* obj) { if (obj) objs.push_back(obj); }; + list_for_each_object(func); + + if (objs.empty()) return true; + + bool new_selection = userdata.asBoolean(); + + auto& selmgr = LLSelectMgr::instance(); + if (new_selection) selmgr.deselectAll(); + + auto selection = new_selection ? nullptr : selmgr.getSelection(); + auto old_primary = selection ? selection->getPrimaryObject() : nullptr; + for (const auto& obj : objs) + selmgr.selectObjectAndFamily(obj, true); + + if (old_primary) selmgr.selectObjectAndFamily(old_primary); + + if (new_selection) handle_object_edit(); + return true; + } +}; + +class ListObjectCanEdit final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + bool new_selection = userdata["data"].asBoolean(); + auto& selmgr = LLSelectMgr::instance(); + auto selection = new_selection ? nullptr : selmgr.getSelection(); + bool has_old_selection = selection && !selection->isEmpty() && !selection->isAttachment(); + auto func = rlv_handler_t::isEnabled() ? static_cast>([](LLViewerObject* obj) { return !!gRlvHandler.canEdit(obj); }) : [](LLViewerObject* obj) { return !!obj; }; + gMenuHolder->findControl(userdata["control"].asString()) + ->setValue((new_selection || has_old_selection) && list_has_valid_object(func)); + return true; + } +}; + +class ListObjectDerender final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + const std::string& unknown = LLTrans::getString("land_type_unknown"); + for (const auto& id : LFIDBearer::getActiveSelectedIDs()) + { + const auto& obj_data = get_obj_data(id); // Needed for object name + add_object_to_blacklist(id, obj_data ? obj_data->name : unknown); + } + + return true; + } +}; + +class MediaCtrlCopyURL final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + get_focused()->onCopyURL(); + return true; + } +}; + +class MediaCtrlWebInspector final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + get_focused()->onOpenWebInspector(); + return true; + } +}; + +class MediaCtrlViewSource final : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + get_focused()->onShowSource(); + return true; + } +}; + +struct MarketplaceViewSortAction final : view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + LLFloaterMarketplaceListings::findInstance()->mPanelListings->onViewSortMenuItemClicked(userdata); + return true; + } +}; + +struct MarketplaceViewSortCheckItem final : view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + gMenuHolder->findControl(userdata["control"].asString()) + ->setValue(LLFloaterMarketplaceListings::findInstance()->mPanelListings->onViewSortMenuItemCheck(userdata["data"])); return true; } }; @@ -9551,16 +10035,17 @@ void addMenu(view_listener_t *menu, const std::string& name) void initialize_menus() { // A parameterized event handler used as ctrl-8/9/0 zoom controls below. - class LLZoomer : public view_listener_t + class LLZoomer final : public view_listener_t { public: // The "mult" parameter says whether "val" is a multiplier or used to set the value. LLZoomer(F32 val, bool mult=true) : mVal(val), mMult(mult) {} - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(LLPointer event, const LLSD& userdata) override { - F32 new_fov_rad = mMult ? LLViewerCamera::getInstance()->getDefaultFOV() * mVal : mVal; - LLViewerCamera::getInstance()->setDefaultFOV(new_fov_rad); - gSavedSettings.setF32("CameraAngle", LLViewerCamera::getInstance()->getView()); // setView may have clamped it. + LLViewerCamera& inst(LLViewerCamera::instance()); + F32 new_fov_rad = mMult ? inst.getDefaultFOV() * mVal : mVal; + inst.setDefaultFOV(new_fov_rad); + gSavedSettings.setF32("CameraAngle", inst.getView()); // setView may have clamped it. return true; } private: @@ -9568,6 +10053,8 @@ void initialize_menus() bool mMult; }; + addMenu(new LLUploadCostCalculator(), "Upload.CalculateCosts"); + // File menu init_menu_file(); @@ -9578,7 +10065,6 @@ void initialize_menus() addMenu(new LLEditCopy(), "Edit.Copy"); addMenu(new LLEditPaste(), "Edit.Paste"); addMenu(new LLEditDelete(), "Edit.Delete"); - addMenu(new LLEditSearch(), "Edit.Search"); addMenu(new LLEditSelectAll(), "Edit.SelectAll"); addMenu(new LLEditDeselect(), "Edit.Deselect"); addMenu(new LLEditDuplicate(), "Edit.Duplicate"); @@ -9598,10 +10084,9 @@ void initialize_menus() addMenu(new LLEditEnableChangeDisplayname(), "Edit.EnableChangeDisplayname"); // View menu - addMenu(new LLViewMouselook(), "View.Mouselook"); addMenu(new LLViewJoystickFlycam(), "View.JoystickFlycam"); - addMenu(new LLViewCommunicate(), "View.Communicate"); addMenu(new LLViewResetView(), "View.ResetView"); + addMenu(new LLViewResetPresetAngles(), "View.ResetPresetAngles"); addMenu(new LLViewLookAtLastChatter(), "View.LookAtLastChatter"); addMenu(new LLViewShowHoverTips(), "View.ShowHoverTips"); addMenu(new LLViewHighlightTransparent(), "View.HighlightTransparent"); @@ -9616,7 +10101,6 @@ void initialize_menus() addMenu(new LLViewEnableMouselook(), "View.EnableMouselook"); addMenu(new LLViewEnableJoystickFlycam(), "View.EnableJoystickFlycam"); addMenu(new LLViewEnableLastChatter(), "View.EnableLastChatter"); - addMenu(new LLViewToggleRadar(), "View.ToggleAvatarList"); addMenu(new LLViewCheckJoystickFlycam(), "View.CheckJoystickFlycam"); addMenu(new LLViewCheckShowHoverTips(), "View.CheckShowHoverTips"); @@ -9625,8 +10109,6 @@ void initialize_menus() addMenu(new LLViewCheckHUDAttachments(), "View.CheckHUDAttachments"); // World menu - addMenu(new LLWorldChat(), "World.Chat"); - addMenu(new LLWorldAlwaysRun(), "World.AlwaysRun"); addMenu(new LLWorldSitOnGround(), "World.SitOnGround"); addMenu(new LLWorldEnableSitOnGround(), "World.EnableSitOnGround"); addMenu(new LLWorldFly(), "World.Fly"); @@ -9642,13 +10124,9 @@ void initialize_menus() addMenu(new LLWorldEnableSetHomeLocation(), "World.EnableSetHomeLocation"); addMenu(new LLWorldEnableTeleportHome(), "World.EnableTeleportHome"); addMenu(new LLWorldEnableBuyLand(), "World.EnableBuyLand"); - - addMenu(new LLWorldCheckAlwaysRun(), "World.CheckAlwaysRun"); - + addMenu(new LLWorldVisibleDestinations(), "World.VisibleDestinations"); (new LLWorldEnvSettings())->registerListener(gMenuHolder, "World.EnvSettings"); - (new LLWorldWaterSettings())->registerListener(gMenuHolder, "World.WaterSettings"); - (new LLWorldPostProcess())->registerListener(gMenuHolder, "World.PostProcess"); - (new LLWorldDayCycle())->registerListener(gMenuHolder, "World.DayCycle"); + (new LLWorldEnableEnvSettings())->registerListener(gMenuHolder, "World.EnableEnvSettings"); // Tools menu @@ -9672,7 +10150,6 @@ void initialize_menus() addMenu(new LLToolsLookAtSelection(), "Tools.LookAtSelection"); addMenu(new LLToolsBuyOrTake(), "Tools.BuyOrTake"); addMenu(new LLToolsTakeCopy(), "Tools.TakeCopy"); - addMenu(new LLToolsTakeCopy(), "Tools.TakeCopy"); // addMenu(new LLToolsEnableAdminDelete(), "Tools.EnableAdminDelete"); @@ -9722,8 +10199,10 @@ void initialize_menus() addMenu(new LLAvatarEject(), "Avatar.Eject"); addMenu(new LLAvatarSendIM(), "Avatar.SendIM"); addMenu(new LLAvatarReportAbuse(), "Avatar.ReportAbuse"); - addMenu(new LLAvatarAnims(),"Avatar.Anims"); addMenu(new LLObjectEnableMute(), "Avatar.EnableMute"); + addMenu(new LLAvatarResetSkeleton(), "Avatar.ResetSkeleton"); + addMenu(new LLAvatarEnableResetSkeleton(), "Avatar.EnableResetSkeleton"); + addMenu(new LLAvatarResetSkeletonAndAnimations(), "Avatar.ResetSkeletonAndAnimations"); addMenu(new LLAvatarEnableAddFriend(), "Avatar.EnableAddFriend"); addMenu(new LLAvatarEnableFreezeEject(), "Avatar.EnableFreezeEject"); addMenu(new LLAvatarCopyUUID(), "Avatar.CopyUUID"); @@ -9749,11 +10228,11 @@ void initialize_menus() addMenu(new LLOHGOD(), "Object.EnableExplode"); add_wave_listeners(); add_dae_listeners(); + addMenu(new LLObjectFollow(), "Object.Follow"); // addMenu(new LLObjectMute(), "Object.Mute"); addMenu(new LLObjectBuy(), "Object.Buy"); addMenu(new LLObjectEdit(), "Object.Edit"); - addMenu(new LLObjectInspect(), "Object.Inspect"); // Visual mute, originally by Phox. addMenu(new LLObjectDerender(), "Object.DERENDER"); addMenu(new LLAvatarReloadTextures(), "Avatar.ReloadTextures"); @@ -9800,8 +10279,8 @@ void initialize_menus() addMenu(new LLShowFloater(), "ShowFloater"); addMenu(new LLPromptShowURL(), "PromptShowURL"); addMenu(new LLShowAgentProfile(), "ShowAgentProfile"); - addMenu(new LLShowAgentGroups(), "ShowAgentGroups"); addMenu(new LLToggleControl(), "ToggleControl"); + addMenu(new LLTogglePerAccountControl(), "TogglePerAccountControl"); addMenu(new LLGoToObject(), "GoToObject"); addMenu(new LLPayObject(), "PayObject"); @@ -9823,18 +10302,22 @@ void initialize_menus() // Singularity menu addMenu(new SinguCloseAllDialogs(), "CloseAllDialogs"); // ---- Fake away handled elsewhere - addMenu(new SinguAnimationOverride(), "AnimationOverride"); - addMenu(new SinguNimble(), "Nimble"); - addMenu(new SinguCheckNimble(), "CheckNimble"); - addMenu(new SinguStreamingAudioDisplay(), "StreamingAudioDisplay"); addMenu(new SinguEnableStreamingAudioDisplay(), "EnableStreamingAudioDisplay"); - addMenu(new SinguCheckStreamingAudioDisplay(), "CheckStreamingAudioDisplay"); addMenu(new SinguPoseStand(), "PoseStand"); addMenu(new SinguCheckPoseStand(), "CheckPoseStand"); addMenu(new SinguRebake(), "Rebake"); - addMenu(new SinguDebugConsole(), "RegionDebugConsole"); - addMenu(new SinguCheckDebugConsole(), "CheckRegionDebugConsole"); addMenu(new SinguVisibleDebugConsole(), "VisibleRegionDebugConsole"); + addMenu(new SinguUrlAction(), "URLAction"); + addMenu(new LLSyncAnimations(), "Tools.ResyncAnimations"); + + addMenu(new ShowInvFloaterID, "ShowInvFloater.ID"); + addMenu(new ShowInvFloaterName, "ShowInvFloater.Name"); + addMenu(new ShowInvFloaterType, "ShowInvFloater.Type"); + addMenu(new VisibleInvFloaterID, "InvFloaterVisible.ID"); + addMenu(new VisibleInvFloaterName, "InvFloaterVisible.Name"); + addMenu(new VisibleInvFloaterType, "InvFloaterVisible.Type"); + + addMenu(new ShowWebFloater, "ShowWebFloater"); // [RLVa:KB] - Checked: 2010-01-18 (RLVa-1.1.0m) | Added: RLVa-1.1.0m | OK if (rlv_handler_t::isEnabled()) @@ -9843,6 +10326,7 @@ void initialize_menus() } // [/RLVa:KB] + addMenu(new VisibleSecondLife(), "VisibleSecondLife"); addMenu(new VisibleNotSecondLife(), "VisibleNotSecondLife"); // List-bound menus @@ -9852,9 +10336,13 @@ void initialize_menus() addMenu(new ListEnableCall(), "List.EnableCall"); addMenu(new ListEnableIsFriend(), "List.EnableIsFriend"); addMenu(new ListEnableIsNotFriend(), "List.EnableIsNotFriend"); + addMenu(new ListEnableUnmute(), "List.EnableUnmute"); addMenu(new ListEnableMute(), "List.EnableMute"); addMenu(new ListEnableOfferTeleport(), "List.EnableOfferTeleport"); addMenu(new ListVisibleWebProfile(), "List.VisibleWebProfile"); + addMenu(new ListBanFromGroup(), "List.BanFromGroup"); + addMenu(new ListCopyNames(), "List.CopyNames"); + addMenu(new ListCopySLURL(), "List.CopySLURL"); addMenu(new ListCopyUUIDs(), "List.CopyUUIDs"); addMenu(new ListInviteToGroup(), "List.InviteToGroup"); addMenu(new ListOfferTeleport(), "List.OfferTeleport"); @@ -9862,30 +10350,82 @@ void initialize_menus() addMenu(new ListRemoveFriend(), "List.RemoveFriend"); addMenu(new ListRequestFriendship(), "List.RequestFriendship"); addMenu(new ListRequestTeleport(), "List.RequestTeleport"); + addMenu(new ListShare(), "List.Share"); + addMenu(new ListShowLog(), "List.ShowLog"); addMenu(new ListShowProfile(), "List.ShowProfile"); addMenu(new ListShowWebProfile(), "List.ShowWebProfile"); addMenu(new ListStartAdhocCall(), "List.StartAdhocCall"); addMenu(new ListStartCall(), "List.StartCall"); addMenu(new ListStartConference(), "List.StartConference"); addMenu(new ListStartIM(), "List.StartIM"); - //addMenu(new ListAbuseReport(), "List.AbuseReport"); + addMenu(new ListStalk, "List.Stalk"); + addMenu(new ListStalkable, "List.Stalkable"); + addMenu(new ListTeleportTo, "List.TeleportTo"); + addMenu(new ListAbuseReport(), "List.AbuseReport"); + addMenu(new ListIsNearby, "List.IsNearby"); + addMenu(new ListFollow, "List.Follow"); + addMenu(new ListGoTo, "List.GoTo"); + addMenu(new ListTrack, "List.Track"); addMenu(new ListEject(), "List.ParcelEject"); addMenu(new ListFreeze(), "List.Freeze"); addMenu(new ListEstateBan(), "List.EstateBan"); addMenu(new ListEstateEject(), "List.EstateEject"); addMenu(new ListToggleMute(), "List.ToggleMute"); + addMenu(new ListIsInGroup, "List.IsInGroup"); + addMenu(new ListNotInGroup, "List.NotInGroup"); + addMenu(new ListLeave, "List.Leave"); + addMenu(new ListJoin, "List.Join"); + addMenu(new ListActivate, "List.Activate"); + addMenu(new ListObjectCamTo, "List.Object.CamTo"); + addMenu(new ListObjectSit, "List.Object.Sit"); + addMenu(new ListObjectPay, "List.Object.Pay"); + addMenu(new ListObjectEnablePay, "List.Object.EnablePay"); + addMenu(new ListObjectTouch, "List.Object.Touch"); + addMenu(new ListObjectEnableTouch, "List.Object.EnableTouch"); + addMenu(new ListObjectEdit, "List.Object.Edit"); + addMenu(new ListObjectCanEdit, "List.Object.CanEdit"); + addMenu(new ListObjectDerender, "List.Object.Derender"); + addMenu(new ListExperienceAllow, "List.Experience.Allow"); + addMenu(new ListExperienceForget, "List.Experience.Forget"); + addMenu(new ListExperienceBlock, "List.Experience.Block"); add_radar_listeners(); - LLToolMgr::getInstance()->initMenu(sMenus); + LLTextEditor::addMenuListeners(); + + // Media Ctrl menus + addMenu(new MediaCtrlCopyURL(), "Copy.PageURL"); + addMenu(new MediaCtrlWebInspector(), "Open.WebInspector"); + addMenu(new MediaCtrlViewSource(), "Open.ViewSource"); + + addMenu(new MarketplaceViewSortAction, "Marketplace.ViewSort.Action"); + addMenu(new MarketplaceViewSortCheckItem, "Marketplace.ViewSort.CheckItem"); + + class LLViewBuildMode final : public view_listener_t + { + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + LLToolMgr::getInstance()->toggleBuildMode(); + return true; + } + }; + class LLViewCheckBuildMode final : public view_listener_t + { + bool handleEvent(LLPointer event, const LLSD& userdata) override + { + gMenuHolder->findControl(userdata["control"].asString())->setValue(LLToolMgr::getInstance()->inEdit()); + return true; + } + }; + addMenu(new LLViewBuildMode(), "View.BuildMode"); + addMenu(new LLViewCheckBuildMode(), "View.CheckBuildMode"); } void region_change() { // Remove current dynamic items - for (custom_menu_item_list_t::iterator i = gCustomMenuItems.begin(); i != gCustomMenuItems.end(); ++i) + for (auto item : gCustomMenuItems) { - LLMenuItemCallGL* item = (*i); item->getParent()->removeChild(item); delete item; } @@ -9894,13 +10434,13 @@ void region_change() LLViewerRegion* regionp = gAgent.getRegion(); if (!regionp) return; - if (regionp->getFeaturesReceived()) + if (regionp->simulatorFeaturesReceived()) { parse_simulator_features(); } else { - regionp->setFeaturesReceivedCallback(boost::bind(&parse_simulator_features)); + regionp->setSimulatorFeaturesReceivedCallback(boost::bind(&parse_simulator_features)); } } @@ -9918,18 +10458,20 @@ void parse_simulator_features() { std::string insertMarker = "insert_" + i->first; - LLView* marker = gMenuBarView->getChildView(insertMarker, true, false); + LLMenuItemGL* marker = gMenuBarView->findChild(insertMarker); if (!marker) continue; LLMenuGL* menu = dynamic_cast(marker->getParent()); if (!menu) continue; + auto it = menu->find(marker); + for (LLSD::map_iterator j = i->second.beginMap(); j != i->second.endMap(); ++j) { LLMenuItemCallGL* custom = new LLMenuItemCallGL(j->second.asString(), j->first, custom_selected); custom->setUserData(custom); gCustomMenuItems.push_back(custom); - menu->addChild(custom, marker); + menu->insert(it, custom); } } } diff --git a/indra/newview/llviewermenu.h b/indra/newview/llviewermenu.h index 6d3c2947f5..35aa889847 100644 --- a/indra/newview/llviewermenu.h +++ b/indra/newview/llviewermenu.h @@ -38,8 +38,10 @@ class LLUICtrl; class LLView; class LLParcelSelection; +class LLPickInfo; class LLObjectSelection; class LLSelectNode; +class LLViewerObject; void pre_init_menus(); void init_menus(); @@ -48,7 +50,6 @@ void cleanup_menus(); void show_debug_menus(); // checks for if menus should be shown first. void show_context_menu( S32 x, S32 y, MASK mask ); void show_build_mode_context_menu(S32 x, S32 y, MASK mask); -BOOL enable_save_into_inventory(void*); void handle_reset_view(); void handle_cut(void*); void handle_copy(void*); @@ -89,13 +90,14 @@ BOOL enable_god_full(void* user_data); BOOL enable_god_liaison(void* user_data); BOOL enable_god_basic(void* user_data); void set_underclothes_menu_options(); +void check_merchant_status(bool force = false); void exchange_callingcard(const LLUUID& dest_id); void handle_gestures(void*); void handle_sit_down(void*); void handle_object_build(void*); -void handle_object_touch(); +void handle_object_touch(LLViewerObject*, const LLPickInfo* const = nullptr); bool enable_object_open(); void handle_object_open(); @@ -133,10 +135,10 @@ void handle_toggle_flycam(); void handle_fake_away_status(void*); void handle_object_sit_or_stand(); -void handle_give_money_dialog(); -bool enable_pay_object(); +void handle_give_money_dialog(LLViewerObject*); +bool enable_pay_object(LLViewerObject*); bool enable_buy_object(); -bool handle_go_to(); +void handle_go_to(const LLVector3d& pos); // Export to XML or Collada void handle_export_selected( void * ); @@ -158,33 +160,30 @@ class LLViewerMenuHolderGL : public LLMenuHolderGL LLSafeHandle mObjectSelection; }; -extern const std::string SAVE_INTO_INVENTORY; - extern LLMenuBarGL* gMenuBarView; //extern LLView* gMenuBarHolder; -extern LLMenuGL* gPopupMenuView; extern LLViewerMenuHolderGL* gMenuHolder; extern LLMenuBarGL* gLoginMenuBarView; // Pie menus -extern LLPieMenu *gPieSelf; -extern LLPieMenu *gPieAvatar; -extern LLPieMenu *gPieObject; -extern LLPieMenu *gPieAttachment; -extern LLPieMenu *gPieLand; -extern LLPieMenu *gPieRate; +extern LLContextMenu *gPieSelf; +extern LLContextMenu *gPieAvatar; +extern LLContextMenu *gPieObject; +extern LLContextMenu *gPieAttachment; +extern LLContextMenu *gPieLand; +extern LLContextMenu *gPieRate; // Needed to build menus when attachment site list available extern LLMenuGL* gAttachSubMenu; extern LLMenuGL* gDetachSubMenu; extern LLMenuGL* gTakeOffClothes; extern LLMenuGL* gMeshesAndMorphsMenu; -extern LLPieMenu* gAttachScreenPieMenu; -extern LLPieMenu* gDetachScreenPieMenu; -extern LLPieMenu* gAttachPieMenu; -extern LLPieMenu* gDetachPieMenu; -extern LLPieMenu* gAttachBodyPartPieMenus[8]; -extern LLPieMenu* gDetachBodyPartPieMenus[8]; +extern LLContextMenu* gAttachScreenPieMenu; +extern LLContextMenu* gDetachScreenPieMenu; +extern LLContextMenu* gAttachPieMenu; +extern LLContextMenu* gDetachPieMenu; +extern LLContextMenu* gAttachPieMenu2; +extern LLContextMenu* gDetachPieMenu2; extern LLMenuItemCallGL* gAFKMenu; extern LLMenuItemCallGL* gBusyMenu; diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index 46cebc7b51..ac35f39672 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -35,6 +35,7 @@ // project includes #include "llagent.h" +#include "llagentbenefits.h" #include "llagentcamera.h" #include "statemachine/aifilepicker.h" #include "llfloaterbvhpreview.h" @@ -62,14 +63,12 @@ #include "lltrans.h" #include "llfloaterbuycurrency.h" // -#include "floaterlocalassetbrowse.h" #include "llassettype.h" #include "llinventorytype.h" // // linden libraries #include "llassetuploadresponders.h" -#include "lleconomy.h" #include "llhttpclient.h" #include "llmemberlistener.h" #include "llnotificationsutil.h" @@ -96,20 +95,26 @@ class LLFileEnableSaveAs : public view_listener_t { bool handleEvent(LLPointer event, const LLSD& userdata) { - bool new_value = gFloaterView->getFrontmost() && - gFloaterView->getFrontmost()->canSaveAs(); - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); - return true; - } -}; - -class LLFileEnableUpload : public view_listener_t -{ - bool handleEvent(LLPointer event, const LLSD& userdata) - { - bool new_value = gStatusBar && LLGlobalEconomy::Singleton::getInstance() && - gStatusBar->getBalance() >= LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(); - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); + LLFloater* frontmost = gFloaterView->getFrontmost(); + if (frontmost && frontmost->hasChild("Save Preview As...", true)) // If we're the tearoff. + { + // Get the next frontmost sibling. + const LLView::child_list_const_iter_t kids_end = gFloaterView->endChild(); + LLView::child_list_const_iter_t kid = std::find(gFloaterView->beginChild(), kids_end, frontmost); + if (kids_end != kid) + { + for (++kid; kid != kids_end; ++kid) + { + LLView* viewp = *kid; + if (viewp->getVisible() && !viewp->isDead()) + { + frontmost = static_cast(viewp); + break; + } + } + } + } + gMenuHolder->findControl(userdata["control"].asString())->setValue(frontmost && frontmost->canSaveAs()); return true; } }; @@ -275,7 +280,7 @@ bool AIFileUpload::is_valid(std::string const& filename, ELoadFilter type) std::string error_msg; if (check_for_invalid_wav_formats(filename,error_msg)) { - llinfos << error_msg << ": " << filename << llendl; + LL_INFOS() << error_msg << ": " << filename << LL_ENDL; LLSD args; args["FILE"] = filename; LLNotificationsUtil::add( error_msg, args ); @@ -393,11 +398,15 @@ class LLFileUploadBulk : public view_listener_t // // Also fix single upload to charge first, then refund // - S32 expected_upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(); - const char* notification_type = expected_upload_cost ? "BulkTemporaryUpload" : "BulkTemporaryUploadFree"; - LLSD args; - args["UPLOADCOST"] = gHippoGridManager->getConnectedGrid()->getUploadFee(); - LLNotificationsUtil::add(notification_type, args, LLSD(), onConfirmBulkUploadTemp); + const auto grid(gHippoGridManager->getConnectedGrid()); + if (grid->isSecondLife()) // For SL, we can't do temp uploads anymore. + { + doBulkUpload(); + } + else + { + LLNotificationsUtil::add("BulkTemporaryUpload", LLSD(), LLSD(), onConfirmBulkUploadTemp); + } return true; } @@ -412,10 +421,15 @@ class LLFileUploadBulk : public view_listener_t else // cancel return false; + doBulkUpload(enabled); + return true; + } + + static void doBulkUpload(bool temp = false) + { AIFilePicker* filepicker = AIFilePicker::create(); filepicker->open(FFLOAD_ALL, "", "openfile", true); - filepicker->run(boost::bind(&LLFileUploadBulk::onConfirmBulkUploadTemp_continued, enabled, filepicker)); - return true; + filepicker->run(boost::bind(&LLFileUploadBulk::onConfirmBulkUploadTemp_continued, temp, filepicker)); } static void onConfirmBulkUploadTemp_continued(bool enabled, AIFilePicker* filepicker) @@ -438,12 +452,22 @@ class LLFileUploadBulk : public view_listener_t std::string display_name = LLStringUtil::null; LLAssetStorage::LLStoreAssetCallback callback = NULL; - S32 expected_upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(); void *userdata = NULL; gSavedSettings.setBOOL("TemporaryUpload", enabled); - upload_new_resource(filename, asset_name, asset_name, 0, LLFolderType::FT_NONE, LLInventoryType::IT_NONE, - LLFloaterPerms::getNextOwnerPerms(), LLFloaterPerms::getGroupPerms(), LLFloaterPerms::getEveryonePerms(), - display_name, callback, expected_upload_cost, userdata); + upload_new_resource( + filename, + asset_name, + asset_name, + 0, + LLFolderType::FT_NONE, + LLInventoryType::EType::IT_NONE, + LLFloaterPerms::getNextOwnerPerms("Uploads"), + LLFloaterPerms::getGroupPerms("Uploads"), + LLFloaterPerms::getEveryonePerms("Uploads"), + display_name, + callback, + 0, + userdata); } } @@ -456,11 +480,11 @@ class LLFileUploadBulk : public view_listener_t void upload_error(const std::string& error_message, const std::string& label, const std::string& filename, const LLSD& args) { - llwarns << error_message << llendl; + LL_WARNS() << error_message << LL_ENDL; LLNotificationsUtil::add(label, args); if(LLFile::remove(filename) == -1) { - lldebugs << "unable to remove temp file" << llendl; + LL_DEBUGS() << "unable to remove temp file" << LL_ENDL; } //AIFIXME? LLFilePicker::instance().reset(); } @@ -517,15 +541,6 @@ class LLFileMinimizeAllWindows : public view_listener_t return true; } }; - -class LLFileLocalAssetBrowser : public view_listener_t -{ - bool handleEvent(LLPointer, const LLSD&) - { - FloaterLocalAssetBrowser::show(0); - return true; - } -}; // class LLFileSavePreview : public view_listener_t @@ -541,33 +556,12 @@ class LLFileSavePreview : public view_listener_t } }; -class LLFileSavePreviewPNG : public view_listener_t -{ - bool handleEvent(LLPointer event, const LLSD& userdata) - { - LLFloater* top = gFloaterView->getFrontmost(); - if (top) - { - top->saveAsType(true); - } - return true; - } -}; - -class LLFileTakeSnapshot : public view_listener_t -{ - bool handleEvent(LLPointer event, const LLSD& userdata) - { - LLFloaterSnapshot::show(NULL); - return true; - } -}; - class LLFileTakeSnapshotToDisk : public view_listener_t { bool handleEvent(LLPointer event, const LLSD& userdata) { LLPointer raw = new LLImageRaw; + raw->enableOverSize(); S32 width = gViewerWindow->getWindowDisplayWidth(); S32 height = gViewerWindow->getWindowDisplayHeight(); @@ -611,7 +605,7 @@ class LLFileTakeSnapshotToDisk : public view_listener_t formatted = new LLImageBMP; break; default: - llwarns << "Unknown Local Snapshot format" << llendl; + LL_WARNS() << "Unknown Local Snapshot format" << LL_ENDL; return true; } @@ -652,8 +646,8 @@ static void handle_compress_image_continued(AIFilePicker* filepicker) std::string const& infile(*filename); std::string outfile = infile + ".j2c"; - llinfos << "Input: " << infile << llendl; - llinfos << "Output: " << outfile << llendl; + LL_INFOS() << "Input: " << infile << LL_ENDL; + LL_INFOS() << "Output: " << outfile << LL_ENDL; BOOL success; @@ -661,11 +655,11 @@ static void handle_compress_image_continued(AIFilePicker* filepicker) if (success) { - llinfos << "Compression complete" << llendl; + LL_INFOS() << "Compression complete" << LL_ENDL; } else { - llinfos << "Compression failed: " << LLImage::getLastError() << llendl; + LL_INFOS() << "Compression failed: " << LLImage::getLastError() << LL_ENDL; } } } @@ -743,7 +737,7 @@ void upload_new_resource(const std::string& src_filename, std::string name, asset_type = LLAssetType::AT_SOUND; // tag it as audio S32 encode_result = 0; - llinfos << "Attempting to encode wav as an ogg file" << llendl; + LL_INFOS() << "Attempting to encode wav as an ogg file" << LL_ENDL; encode_result = encode_vorbis_file(src_filename, filename); created_temp_file = true; @@ -800,8 +794,8 @@ void upload_new_resource(const std::string& src_filename, std::string name, "%254s %254s\n", label, value); - llinfos << "got: " << label << " = " << value - << llendl; + LL_INFOS() << "got: " << label << " = " << value + << LL_ENDL; if (EOF == tokens_read) { @@ -854,7 +848,7 @@ void upload_new_resource(const std::string& src_filename, std::string name, // read in and throw out most of the header except for the type if (fread(buf, header_size, 1, in) != 1) { - llwarns << "Short read" << llendl; + LL_WARNS() << "Short read" << LL_ENDL; } memcpy(&type_num, buf + 16, sizeof(S16)); /* Flawfinder: ignore */ asset_type = (LLAssetType::EType)type_num; @@ -869,7 +863,7 @@ void upload_new_resource(const std::string& src_filename, std::string name, { if (fwrite(buf, 1, readbytes, out) != readbytes) { - llwarns << "Short write" << llendl; + LL_WARNS() << "Short write" << LL_ENDL; } } fclose(out); @@ -887,7 +881,7 @@ void upload_new_resource(const std::string& src_filename, std::string name, } else { - llinfos << "Couldn't open .lin file " << src_filename << llendl; + LL_INFOS() << "Couldn't open .lin file " << src_filename << LL_ENDL; } } else if (exten == "bvh") @@ -902,6 +896,13 @@ void upload_new_resource(const std::string& src_filename, std::string name, asset_type = LLAssetType::AT_ANIMATION; filename = src_filename; } + else if(exten == "lsl" || exten == "gesture" || exten == "notecard") + { + if (exten == "lsl") asset_type = LLAssetType::AT_LSL_TEXT; + else if (exten == "gesture") asset_type = LLAssetType::AT_GESTURE; + else if (exten == "notecard") asset_type = LLAssetType::AT_NOTECARD; + filename = src_filename; + } // else { @@ -910,6 +911,9 @@ void upload_new_resource(const std::string& src_filename, std::string name, error = TRUE;; } + // Now that we've determined the type, figure out the cost + if (!error) LLAgentBenefitsMgr::current().findUploadCost(asset_type, expected_upload_cost); + // gen a new transaction ID for this asset tid.generate(); @@ -949,10 +953,10 @@ void upload_new_resource(const std::string& src_filename, std::string name, // hack to create scripts and gestures if(exten == "lsl" || exten == "gesture" || exten == "notecard") // added notecard Oct 15 2009 { - LLInventoryType::EType inv_type = LLInventoryType::IT_GESTURE; - if(exten == "lsl") inv_type = LLInventoryType::IT_LSL; - else if(exten == "gesture") inv_type = LLInventoryType::IT_GESTURE; - else if(exten == "notecard") inv_type = LLInventoryType::IT_NOTECARD; + LLInventoryType::EType inv_type = LLInventoryType::EType::IT_GESTURE; + if (exten == "lsl") inv_type = LLInventoryType::EType::IT_LSL; + else if(exten == "gesture") inv_type = LLInventoryType::EType::IT_GESTURE; + else if(exten == "notecard") inv_type = LLInventoryType::EType::IT_NOTECARD; create_inventory_item( gAgent.getID(), gAgent.getSessionID(), gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(asset_type)), @@ -973,14 +977,14 @@ void upload_new_resource(const std::string& src_filename, std::string name, } else { - llwarns << error_message << llendl; + LL_WARNS() << error_message << LL_ENDL; LLSD args; args["ERROR_MESSAGE"] = error_message; LLNotificationsUtil::add("ErrorMessage", args); } if (created_temp_file && LLFile::remove(filename) == -1) { - lldebugs << "unable to remove temp file" << llendl; + LL_DEBUGS() << "unable to remove temp file" << LL_ENDL; } } // @@ -992,21 +996,21 @@ void temp_upload_callback(const LLUUID& uuid, void* user_data, S32 result, LLExt { LLUUID item_id; item_id.generate(); - LLPermissions* perms = new LLPermissions(); - perms->set(LLPermissions::DEFAULT); - perms->setOwnerAndGroup(gAgentID, gAgentID, gAgentID, false); + LLPermissions perms; + perms.set(LLPermissions::DEFAULT); + perms.setOwnerAndGroup(gAgentID, gAgentID, gAgentID, false); - perms->setMaskBase(PERM_ALL); - perms->setMaskOwner(PERM_ALL); - perms->setMaskEveryone(PERM_ALL); - perms->setMaskGroup(PERM_ALL); - perms->setMaskNext(PERM_ALL); + perms.setMaskBase(PERM_ALL); + perms.setMaskOwner(PERM_ALL); + perms.setMaskEveryone(PERM_ALL); + perms.setMaskGroup(PERM_ALL); + perms.setMaskNext(PERM_ALL); LLViewerInventoryItem* item = new LLViewerInventoryItem( item_id, gInventory.findCategoryUUIDForType(LLFolderType::FT_TEXTURE), - *perms, + perms, uuid, (LLAssetType::EType)data->mAssetInfo.mType, (LLInventoryType::EType)data->mInventoryType, @@ -1093,7 +1097,7 @@ void upload_done_callback(const LLUUID& uuid, void* user_data, S32 result, LLExt if(is_balance_sufficient) { // Actually add the upload to inventory - llinfos << "Adding " << uuid << " to inventory." << llendl; + LL_INFOS() << "Adding " << uuid << " to inventory." << LL_ENDL; const LLUUID folder_id = gInventory.findCategoryUUIDForType(dest_loc); if(folder_id.notNull()) { @@ -1110,7 +1114,7 @@ void upload_done_callback(const LLUUID& uuid, void* user_data, S32 result, LLExt } else { - llwarns << "Can't find a folder to put it in" << llendl; + LL_WARNS() << "Can't find a folder to put it in" << LL_ENDL; } } } @@ -1191,8 +1195,7 @@ bool upload_new_resource( const std::string& display_name, LLAssetStorage::LLStoreAssetCallback callback, S32 expected_upload_cost, - void *userdata, - void (*callback2)(bool, void*)) + void *userdata) { if(gDisconnected) { @@ -1207,7 +1210,7 @@ bool upload_new_resource( name, display_name, desc); - llinfos << "*** Uploading: " + LL_INFOS() << "*** Uploading: " << "\nType: " << LLAssetType::lookup(asset_type) << "\nUUID: " << uuid << "\nName: " << name @@ -1216,7 +1219,7 @@ bool upload_new_resource( << gInventory.findCategoryUUIDForType(destination_folder_type == LLFolderType::FT_NONE ? LLFolderType::assetTypeToFolderType(asset_type) : destination_folder_type) - << "\nExpected Upload Cost: " << expected_upload_cost << llendl; + << "\nExpected Upload Cost: " << expected_upload_cost << LL_ENDL; std::string url = gAgent.getRegion()->getCapability("NewFileAgentInventory"); // @@ -1225,7 +1228,7 @@ bool upload_new_resource( if (!url.empty() && !temporary) // { - llinfos << "New Agent Inventory via capability" << llendl; + LL_INFOS() << "New Agent Inventory via capability" << LL_ENDL; LLSD body; body["folder_id"] = gInventory.findCategoryUUIDForType((destination_folder_type == LLFolderType::FT_NONE) ? LLFolderType::assetTypeToFolderType(asset_type) : destination_folder_type); @@ -1244,16 +1247,14 @@ bool upload_new_resource( new LLNewAgentInventoryResponder( body, uuid, - asset_type, - callback2, - userdata)); + asset_type)); } else { // if(!temporary) { - llinfos << "NewAgentInventory capability not found, new agent inventory via asset system." << llendl; + LL_INFOS() << "NewAgentInventory capability not found, new agent inventory via asset system." << LL_ENDL; // check for adequate funds // TODO: do this check on the sim if (LLAssetType::AT_SOUND == asset_type || @@ -1267,7 +1268,7 @@ bool upload_new_resource( LLStringUtil::format_map_t args; args["[NAME]"] = name; args["[CURRENCY]"] = gHippoGridManager->getConnectedGrid()->getCurrencySymbol(); - args["[AMOUNT]"] = llformat("%d", expected_upload_cost); + args["[AMOUNT]"] = fmt::to_string(expected_upload_cost); LLFloaterBuyCurrency::buyCurrency( LLTrans::getString("UploadingCosts", args), expected_upload_cost ); return false; } @@ -1308,17 +1309,16 @@ bool upload_new_resource( LLAssetID generate_asset_id_for_new_upload(const LLTransactionID& tid) { - LLAssetID uuid; - if (gDisconnected) { - uuid.setNull(); - } - else - { - uuid = tid.makeAssetID(gAgent.getSecureSessionID()); + LLAssetID rv; + + rv.setNull(); + return rv; } + LLAssetID uuid = tid.makeAssetID(gAgent.getSecureSessionID()); + return uuid; } @@ -1344,7 +1344,7 @@ void assign_defaults_and_show_upload_message(LLAssetType::EType asset_type, const std::string& display_name, std::string& description) { - if (LLInventoryType::IT_NONE == inventory_type) + if (LLInventoryType::EType::IT_NONE == inventory_type) { inventory_type = LLInventoryType::defaultForAssetType(asset_type); } @@ -1381,14 +1381,10 @@ void init_menu_file() (new LLFileEnableCloseAllWindows())->registerListener(gMenuHolder, "File.EnableCloseAllWindows"); // (new LLFileMinimizeAllWindows())->registerListener(gMenuHolder, "File.MinimizeAllWindows"); - (new LLFileLocalAssetBrowser())->registerListener(gMenuHolder, "File.LocalAssetBrowser"); // (new LLFileSavePreview())->registerListener(gMenuHolder, "File.SavePreview"); - (new LLFileSavePreviewPNG())->registerListener(gMenuHolder, "File.SavePreviewPNG"); - (new LLFileTakeSnapshot())->registerListener(gMenuHolder, "File.TakeSnapshot"); (new LLFileTakeSnapshotToDisk())->registerListener(gMenuHolder, "File.TakeSnapshotToDisk"); (new LLFileQuit())->registerListener(gMenuHolder, "File.Quit"); - (new LLFileEnableUpload())->registerListener(gMenuHolder, "File.EnableUpload"); (new LLFileEnableUploadModel())->registerListener(gMenuHolder, "File.EnableUploadModel"); (new LLFileEnableSaveAs())->registerListener(gMenuHolder, "File.EnableSaveAs"); @@ -1402,6 +1398,19 @@ void NewResourceItemCallback::fire(const LLUUID& new_item_id) LLUUID vfile_id = LLUUID(new_item->getDescription()); if(vfile_id.isNull()) return; new_item->setDescription("(No Description)"); + std::string type("Uploads"); + switch(new_item->getInventoryType()) + { + case LLInventoryType::EType::IT_LSL: type = "Scripts"; break; + case LLInventoryType::EType::IT_GESTURE: type = "Gestures"; break; + case LLInventoryType::EType::IT_NOTECARD: type = "Notecard"; break; + default: break; + } + LLPermissions perms = new_item->getPermissions(); + perms.setMaskNext(LLFloaterPerms::getNextOwnerPerms(type)); + perms.setMaskGroup(LLFloaterPerms::getGroupPerms(type)); + perms.setMaskEveryone(LLFloaterPerms::getEveryonePerms(type)); + new_item->setPermissions(perms); new_item->updateServer(FALSE); gInventory.updateItem(new_item); gInventory.notifyObservers(); diff --git a/indra/newview/llviewermenufile.h b/indra/newview/llviewermenufile.h index 65ff1a425b..4eefa6a937 100644 --- a/indra/newview/llviewermenufile.h +++ b/indra/newview/llviewermenufile.h @@ -78,8 +78,7 @@ bool upload_new_resource(const LLTransactionID &tid, const std::string& display_name, LLAssetStorage::LLStoreAssetCallback callback, S32 expected_upload_cost, - void *userdata, - void (*callback2)(bool, void*) = NULL); + void *userdata); // The default callback functions, called when 'callback' == NULL (for normal and temporary uploads). // user_data must be a LLResourceData allocated with new (or NULL). diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 71c7b26192..8d90e1eb49 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -32,14 +32,13 @@ #include "llviewerprecompiledheaders.h" #include "llviewermessage.h" #include -#include #include "llanimationstates.h" #include "llaudioengine.h" #include "llavataractions.h" #include "llavatarnamecache.h" +#include "llcororesponder.h" #include "../lscript/lscript_byteformat.h" //Need LSCRIPTRunTimePermissionBits and SCRIPT_PERMISSION_* -#include "lleconomy.h" #include "llfocusmgr.h" #include "llfollowcamparams.h" #include "llinventorydefines.h" @@ -53,27 +52,33 @@ #include "mean_collision_data.h" #include "llagent.h" +#include "llagentbenefits.h" #include "llagentcamera.h" #include "llcallingcard.h" +#include "llcontrolavatar.h" #include "llfirstuse.h" #include "llfloaterbump.h" #include "llfloaterbuycurrency.h" #include "llfloaterbuyland.h" #include "llfloaterchat.h" +#include "llfloaterexperienceprofile.h" #include "llfloaterland.h" #include "llfloaterregioninfo.h" #include "llfloaterlandholdings.h" #include "llfloatermute.h" #include "llfloaterpostcard.h" #include "llfloaterpreference.h" +#include "llfloaterregionrestarting.h" #include "llfloaterteleporthistory.h" #include "llgroupactions.h" #include "llhudeffecttrail.h" #include "llhudmanager.h" -#include "llimpanel.h" +#include "llimprocessing.h" #include "llinventorybridge.h" #include "llinventorymodel.h" #include "llinventorypanel.h" +#include "lllslconstants.h" +#include "llmarketplacefunctions.h" #include "llmutelist.h" #include "llnotify.h" #include "llnotifications.h" @@ -90,7 +95,6 @@ #include "llspeakers.h" #include "lltrans.h" #include "llviewerfoldertype.h" -#include "llviewergenericmessage.h" #include "llviewermenu.h" #include "llviewerinventory.h" #include "llviewerjoystick.h" @@ -109,26 +113,31 @@ #include "llkeythrottle.h" #include "llagentui.h" #include "llviewerregion.h" +#include "llexperiencecache.h" // [RLVa:KB] - Checked: 2010-03-09 (RLVa-1.2.0a) -#include "llfloateravatarinfo.h" // Checked: 2009-07-08 (RLVa-1.0.0e) +#include "rlvactions.h" #include "rlvhandler.h" #include "rlvinventory.h" #include "rlvui.h" // [/RLVa:KB] +#include + +//#include "llnotificationmanager.h" // +#include "llexperiencecache.h" + #if SHY_MOD //Command handler # include "shcommandhandler.h" #endif //shy_mod #include "hippogridmanager.h" #include "hippolimits.h" -#include "hippofloaterxml.h" -#include "sgversion.h" #include "m7wlinterface.h" #include "llgiveinventory.h" +#include #include #if LL_WINDOWS // For Windows specific error handler @@ -139,12 +148,9 @@ #include "NACLantispam.h" bool can_block(const LLUUID& id); // NaCl - Newline flood protection -#include static const boost::regex NEWLINES("\\n{1}"); // NaCl End -extern AIHTTPTimeoutPolicy authHandler_timeout; - // // Constants // @@ -164,8 +170,8 @@ extern bool gShiftFrame; // function prototypes bool check_offer_throttle(const std::string& from_name, bool check_only); bool check_asset_previewable(const LLAssetType::EType asset_type); -void callbackCacheEstateOwnerName(const LLUUID& id, const LLAvatarName& av_name); static void process_money_balance_reply_extended(LLMessageSystem* msg); +bool handle_trusted_experiences_notification(const LLSD&); //inventory offer throttle globals LLFrameTimer gThrottleTimer; @@ -193,35 +199,83 @@ const std::string SCRIPT_QUESTIONS[SCRIPT_PERMISSION_EOF] = "ScriptReturnObjects" }; -const BOOL SCRIPT_QUESTION_IS_CAUTION[SCRIPT_PERMISSION_EOF] = -{ - TRUE, // ScriptTakeMoney, - FALSE, // ActOnControlInputs - FALSE, // RemapControlInputs - FALSE, // AnimateYourAvatar - FALSE, // AttachToYourAvatar - FALSE, // ReleaseOwnership, - FALSE, // LinkAndDelink, - FALSE, // AddAndRemoveJoints - FALSE, // ChangePermissions - FALSE, // TrackYourCamera, - FALSE, // ControlYourCamera - FALSE, // TeleportYourAgent - FALSE, // JoinAnExperience - FALSE, // SilentlyManageEstateAccess - FALSE, // OverrideYourAnimations - FALSE, // ScriptReturnObjects +constexpr bool SCRIPT_QUESTION_IS_CAUTION[SCRIPT_PERMISSION_EOF] = +{ + true, // ScriptTakeMoney, + false, // ActOnControlInputs + false, // RemapControlInputs + false, // AnimateYourAvatar + false, // AttachToYourAvatar + false, // ReleaseOwnership, + false, // LinkAndDelink, + false, // AddAndRemoveJoints + false, // ChangePermissions + false, // TrackYourCamera, + false, // ControlYourCamera + false, // TeleportYourAgent + false, // JoinAnExperience + false, // SilentlyManageEstateAccess + false, // OverrideYourAnimations + false, // ScriptReturnObjects }; +void accept_friendship_coro(const LLCoroResponder& responder, const LLSD& notification) +{ + const auto& status = responder.getStatus(); + + if (!responder.isGoodStatus(status)) + { + LL_WARNS("Friendship") << "HTTP status " << status << ": " << responder.getReason() << + ". friendship offer accept failed." << LL_ENDL; + } + else + { + { + LLSD payload = notification["payload"]; + LL_DEBUGS("Friendship") << "Adding friend to list" << responder.getContent() << LL_ENDL; + // add friend to recent people list + //LLRecentPeople::instance().add(payload["from_id"]); + + LLNotificationsUtil::add("FriendshipAcceptedByMe", + notification["substitutions"], payload); + } + } +} + +void decline_friendship_coro(const LLCoroResponder& responder, const LLSD& notification, S32 option) +{ + const auto& status = responder.getStatus(); + + if (!responder.isGoodStatus(status)) + { + LL_WARNS("Friendship") << "HTTP status " << status << ": " << responder.getReason() << + ". friendship offer decline failed." << LL_ENDL; + } + else + { + { + const auto& payload = notification["payload"]; + LL_DEBUGS("Friendship") << "Friendship declined" << responder.getContent() << LL_ENDL; + if (option == 1) + { + LLNotificationsUtil::add("FriendshipDeclinedByMe", + notification["substitutions"], payload); + } + else if (option == 2) + { + // start IM session + LLAvatarActions::startIM(payload["from_id"].asUUID()); + } + } + } +} + bool friendship_offer_callback(const LLSD& notification, const LLSD& response) { S32 option = LLNotificationsUtil::getSelectedOption(notification, response); LLMessageSystem* msg = gMessageSystem; const LLSD& payload = notification["payload"]; - // add friend to recent people list - //LLRecentPeople::instance().add(payload["from_id"]); - switch(option) { case 0: @@ -232,40 +286,111 @@ bool friendship_offer_callback(const LLSD& notification, const LLSD& response) const LLUUID fid = gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD); // This will also trigger an onlinenotification if the user is online - msg->newMessageFast(_PREHASH_AcceptFriendship); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_TransactionBlock); - msg->addUUIDFast(_PREHASH_TransactionID, payload["session_id"]); - msg->nextBlockFast(_PREHASH_FolderData); - msg->addUUIDFast(_PREHASH_FolderID, fid); - msg->sendReliable(LLHost(payload["sender"].asString())); + std::string url = gAgent.getRegionCapability("AcceptFriendship"); + LL_DEBUGS("Friendship") << "Cap string: " << url << LL_ENDL; + if (!url.empty() && payload.has("online") && payload["online"].asBoolean() == false) + { + LL_DEBUGS("Friendship") << "Accepting friendship via capability" << LL_ENDL; + url += "?from=" + payload["from_id"].asString(); + url += "&agent_name=\"" + LLURI::escape(gAgentAvatarp->getFullname()) + '"'; + LLHTTPClient::post(url, LLSD(), new LLCoroResponder( + boost::bind(accept_friendship_coro, _1, notification))); + } + else if (payload.has("session_id") && payload["session_id"].asUUID().notNull()) + { + LL_DEBUGS("Friendship") << "Accepting friendship via viewer message" << LL_ENDL; + msg->newMessageFast(_PREHASH_AcceptFriendship); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_TransactionBlock); + msg->addUUIDFast(_PREHASH_TransactionID, payload["session_id"]); + msg->nextBlockFast(_PREHASH_FolderData); + msg->addUUIDFast(_PREHASH_FolderID, fid); + msg->sendReliable(LLHost(payload["sender"].asString())); + + // add friend to recent people list + //LLRecentPeople::instance().add(payload["from_id"]); + LLNotificationsUtil::add("FriendshipAcceptedByMe", + notification["substitutions"], payload); + } + else + { + LL_WARNS("Friendship") << "Failed to accept friendship offer, neither capability nor transaction id are accessible" << LL_ENDL; + } break; } - case 1: + case 1: // Decline + // fall-through + //case 3: // Send IM - decline and start IM session + { // decline // We no longer notify other viewers, but we DO still send // the rejection to the simulator to delete the pending userop. - msg->newMessageFast(_PREHASH_DeclineFriendship); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_TransactionBlock); - msg->addUUIDFast(_PREHASH_TransactionID, payload["session_id"]); - msg->sendReliable(LLHost(payload["sender"].asString())); - break; - case 3: - // profile - LLAvatarActions::showProfile(payload["from_id"]); - LLNotificationsUtil::add(notification["name"], notification["substitutions"], payload); //Respawn! + std::string url = gAgent.getRegionCapability("DeclineFriendship"); + LL_DEBUGS("Friendship") << "Cap string: " << url << LL_ENDL; + if (!url.empty() && payload.has("online") && payload["online"].asBoolean() == false) + { + LL_DEBUGS("Friendship") << "Declining friendship via capability" << LL_ENDL; + url += "?from=" + payload["from_id"].asString(); + LLHTTPClient::del(url, new LLCoroResponder( + boost::bind(decline_friendship_coro, _1, notification, option))); + } + else if (payload.has("session_id") && payload["session_id"].asUUID().notNull()) + { + LL_DEBUGS("Friendship") << "Declining friendship via viewer message" << LL_ENDL; + msg->newMessageFast(_PREHASH_DeclineFriendship); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_TransactionBlock); + msg->addUUIDFast(_PREHASH_TransactionID, payload["session_id"]); + msg->sendReliable(LLHost(payload["sender"].asString())); + + if (option == 1) // due to fall-through + { + LLNotificationsUtil::add("FriendshipDeclinedByMe", + notification["substitutions"], payload); + } + /*else if (option == 3) + { + // start IM session + LLAvatarActions::startIM(payload["from_id"].asUUID()); + }*/ + } + else + { + LL_WARNS("Friendship") << "Failed to decline friendship offer, neither capability nor transaction id are accessible" << LL_ENDL; + } + } default: // close button probably, possibly timed out break; } + // TODO: this set of calls has undesirable behavior under Windows OS (CHUI-985): + // here appears three additional toasts instead one modified + // need investigation and fix + + // LLNotificationFormPtr modified_form(new LLNotificationForm(*notification_ptr->getForm())); + // modified_form->setElementEnabled("Accept", false); + // modified_form->setElementEnabled("Decline", false); + // notification_ptr->updateForm(modified_form); +// [SL:KB] - Patch: UI-Notifications | Checked: 2013-05-09 (Catznip-3.5) +// // Assume that any offer notification with "getCanBeStored() == true" is the result of RLVa routing it to the notifcation syswell +// /*const*/ LLNotificationsUI::LLScreenChannel* pChannel = LLNotificationsUI::LLChannelManager::instance().getNotificationScreenChannel(); +// /*const*/ LLNotificationsUI::LLToast* pToast = (pChannel) ? pChannel->getToastByNotificationID(notification["id"].asUUID()) : NULL; +// if ( (!pToast) || (!pToast->getCanBeStored()) ) +// { +// [/SL:KB] +// notification_ptr->repost(); +// [SL:KB] - Patch: UI-Notifications | Checked: 2013-05-09 (Catznip-3.5) +// } +// [/SL:KB] + return false; } + static LLNotificationFunctorRegistration friendship_offer_callback_reg("OfferFriendship", friendship_offer_callback); static LLNotificationFunctorRegistration friendship_offer_callback_reg_nm("OfferFriendshipNoMessage", friendship_offer_callback); @@ -275,25 +400,25 @@ static LLNotificationFunctorRegistration friendship_offer_callback_reg_nm("Offer void give_money(const LLUUID& uuid, LLViewerRegion* region, S32 amount, BOOL is_group, S32 trx_type, const std::string& desc) { - if(0 == amount || !region) return; + if (0 == amount || !region) return; amount = abs(amount); - LL_INFOS("Messaging") << "give_money(" << uuid << "," << amount << ")"<< LL_ENDL; - if(can_afford_transaction(amount)) + LL_INFOS("Messaging") << "give_money(" << uuid << "," << amount << ")" << LL_ENDL; + if (can_afford_transaction(amount)) { -// gStatusBar->debitBalance(amount); + // gStatusBar->debitBalance(amount); LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_MoneyTransferRequest); msg->nextBlockFast(_PREHASH_AgentData); msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); msg->nextBlockFast(_PREHASH_MoneyData); - msg->addUUIDFast(_PREHASH_SourceID, gAgent.getID() ); + msg->addUUIDFast(_PREHASH_SourceID, gAgent.getID()); msg->addUUIDFast(_PREHASH_DestID, uuid); msg->addU8Fast(_PREHASH_Flags, pack_transaction_flags(FALSE, is_group)); msg->addS32Fast(_PREHASH_Amount, amount); msg->addU8Fast(_PREHASH_AggregatePermNextOwner, (U8)LLAggregatePermissions::AP_EMPTY); msg->addU8Fast(_PREHASH_AggregatePermInventory, (U8)LLAggregatePermissions::AP_EMPTY); - msg->addS32Fast(_PREHASH_TransactionType, trx_type ); + msg->addS32Fast(_PREHASH_TransactionType, trx_type); msg->addStringFast(_PREHASH_Description, desc); msg->sendReliable(region->getHost()); } @@ -325,19 +450,19 @@ void process_logout_reply(LLMessageSystem* msg, void**) msg->getUUID("AgentData", "AgentID", agent_id); LLUUID session_id; msg->getUUID("AgentData", "SessionID", session_id); - if((agent_id != gAgent.getID()) || (session_id != gAgent.getSessionID())) + if ((agent_id != gAgent.getID()) || (session_id != gAgent.getSessionID())) { LL_WARNS("Messaging") << "Bogus Logout Reply" << LL_ENDL; } LLInventoryModel::update_map_t parents; - S32 count = msg->getNumberOfBlocksFast( _PREHASH_InventoryData ); - for(S32 i = 0; i < count; ++i) + S32 count = msg->getNumberOfBlocksFast(_PREHASH_InventoryData); + for (S32 i = 0; i < count; ++i) { LLUUID item_id; msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_ItemID, item_id, i); - if( (1 == count) && item_id.isNull() ) + if ((1 == count) && item_id.isNull()) { // Detect dummy item. Indicates an empty list. break; @@ -346,8 +471,8 @@ void process_logout_reply(LLMessageSystem* msg, void**) // We do not need to track the asset ids, just account for an // updated inventory version. LL_INFOS("Messaging") << "process_logout_reply itemID=" << item_id << LL_ENDL; - LLInventoryItem* item = gInventory.getItem( item_id ); - if( item ) + LLInventoryItem* item = gInventory.getItem(item_id); + if (item) { parents[item->getParentUUID()] = 0; gInventory.addChangedMask(LLInventoryObserver::INTERNAL, item_id); @@ -360,13 +485,15 @@ void process_logout_reply(LLMessageSystem* msg, void**) LLAppViewer::instance()->forceQuit(); } -void process_layer_data(LLMessageSystem *mesgsys, void **user_data) +void process_layer_data(LLMessageSystem* mesgsys, void** user_data) { - LLViewerRegion *regionp = LLWorld::getInstance()->getRegion(mesgsys->getSender()); + LLViewerRegion* regionp = LLWorld::getInstance()->getRegion(mesgsys->getSender()); - if(!regionp || gNoRender) + LL_DEBUGS_ONCE("SceneLoadTiming") << "Received layer data" << LL_ENDL; + + if (!regionp || gNoRender) { - llwarns << "Invalid region for layer data." << llendl; + LL_WARNS() << "Invalid region for layer data." << LL_ENDL; return; } S32 size; @@ -387,9 +514,9 @@ void process_layer_data(LLMessageSystem *mesgsys, void **user_data) << LL_ENDL; return; } - U8 *datap = new U8[size]; + U8* datap = new U8[size]; mesgsys->getBinaryDataFast(_PREHASH_LayerData, _PREHASH_Data, datap, size); - LLVLData *vl_datap = new LLVLData(regionp, type, datap, size); + LLVLData* vl_datap = new LLVLData(regionp, type, datap, size); if (mesgsys->getReceiveCompressedSize()) { gVLManager.addLayerData(vl_datap, mesgsys->getReceiveCompressedSize()); @@ -400,195 +527,9 @@ void process_layer_data(LLMessageSystem *mesgsys, void **user_data) } } -// S32 exported_object_count = 0; -// S32 exported_image_count = 0; -// S32 current_object_count = 0; -// S32 current_image_count = 0; - -// extern LLNotifyBox *gExporterNotify; -// extern LLUUID gExporterRequestID; -// extern std::string gExportDirectory; - -// extern LLUploadDialog *gExportDialog; - -// std::string gExportedFile; - -// std::map gImageChecksums; - -// void export_complete() -// { -// LLUploadDialog::modalUploadFinished(); -// gExporterRequestID.setNull(); -// gExportDirectory = ""; - -// LLFILE* fXML = LLFile::fopen(gExportedFile, "rb"); /* Flawfinder: ignore */ -// fseek(fXML, 0, SEEK_END); -// long length = ftell(fXML); -// fseek(fXML, 0, SEEK_SET); -// U8 *buffer = new U8[length + 1]; -// size_t nread = fread(buffer, 1, length, fXML); -// if (nread < (size_t) length) -// { -// LL_WARNS("Messaging") << "Short read" << LL_ENDL; -// } -// buffer[nread] = '\0'; -// fclose(fXML); - -// char *pos = (char *)buffer; -// while ((pos = strstr(pos+1, ""); - -// if (pos_uuid) -// { -// char image_uuid_str[UUID_STR_SIZE]; /* Flawfinder: ignore */ -// memcpy(image_uuid_str, pos_uuid+2, UUID_STR_SIZE-1); /* Flawfinder: ignore */ -// image_uuid_str[UUID_STR_SIZE-1] = 0; - -// LLUUID image_uuid(image_uuid_str); - -// LL_INFOS("Messaging") << "Found UUID: " << image_uuid << LL_ENDL; - -// std::map::iterator itor = gImageChecksums.find(image_uuid); -// if (itor != gImageChecksums.end()) -// { -// LL_INFOS("Messaging") << "Replacing with checksum: " << itor->second << LL_ENDL; -// if (!itor->second.empty()) -// { -// memcpy(&pos_check[10], itor->second.c_str(), 32); /* Flawfinder: ignore */ -// } -// } -// } -// } -// } - -// LLFILE* fXMLOut = LLFile::fopen(gExportedFile, "wb"); /* Flawfinder: ignore */ -// if (fwrite(buffer, 1, length, fXMLOut) != length) -// { -// LL_WARNS("Messaging") << "Short write" << LL_ENDL; -// } -// fclose(fXMLOut); - -// delete [] buffer; -// } - - -// void exported_item_complete(const LLTSCode status, void *user_data) -// { -// //std::string *filename = (std::string *)user_data; - -// if (status < LLTS_OK) -// { -// LL_WARNS("Messaging") << "Export failed!" << LL_ENDL; -// } -// else -// { -// ++current_object_count; -// if (current_image_count == exported_image_count && current_object_count == exported_object_count) -// { -// LL_INFOS("Messaging") << "*** Export complete ***" << LL_ENDL; - -// export_complete(); -// } -// else -// { -// gExportDialog->setMessage(llformat("Exported %d/%d object files, %d/%d textures.", current_object_count, exported_object_count, current_image_count, exported_image_count)); -// } -// } -// } - -// struct exported_image_info -// { -// LLUUID image_id; -// std::string filename; -// U32 image_num; -// }; - -// void exported_j2c_complete(const LLTSCode status, void *user_data) -// { -// exported_image_info *info = (exported_image_info *)user_data; -// LLUUID image_id = info->image_id; -// U32 image_num = info->image_num; -// std::string filename = info->filename; -// delete info; - -// if (status < LLTS_OK) -// { -// LL_WARNS("Messaging") << "Image download failed!" << LL_ENDL; -// } -// else -// { -// LLFILE* fIn = LLFile::fopen(filename, "rb"); /* Flawfinder: ignore */ -// if (fIn) -// { -// LLPointer ImageUtility = new LLImageJ2C; -// LLPointer TargaUtility = new LLImageTGA; - -// fseek(fIn, 0, SEEK_END); -// S32 length = ftell(fIn); -// fseek(fIn, 0, SEEK_SET); -// U8 *buffer = ImageUtility->allocateData(length); -// if (fread(buffer, 1, length, fIn) != length) -// { -// LL_WARNS("Messaging") << "Short read" << LL_ENDL; -// } -// fclose(fIn); -// LLFile::remove(filename); - -// // Convert to TGA -// LLPointer image = new LLImageRaw(); - -// ImageUtility->updateData(); -// ImageUtility->decode(image, 100000.0f); - -// TargaUtility->encode(image); -// U8 *data = TargaUtility->getData(); -// S32 data_size = TargaUtility->getDataSize(); - -// std::string file_path = gDirUtilp->getDirName(filename); - -// std::string output_file = llformat("%s/image-%03d.tga", file_path.c_str(), image_num);//filename; -// //S32 name_len = output_file.length(); -// //strcpy(&output_file[name_len-3], "tga"); -// LLFILE* fOut = LLFile::fopen(output_file, "wb"); /* Flawfinder: ignore */ -// char md5_hash_string[33]; /* Flawfinder: ignore */ -// strcpy(md5_hash_string, "00000000000000000000000000000000"); /* Flawfinder: ignore */ -// if (fOut) -// { -// if (fwrite(data, 1, data_size, fOut) != data_size) -// { -// LL_WARNS("Messaging") << "Short write" << LL_ENDL; -// } -// fseek(fOut, 0, SEEK_SET); -// fclose(fOut); -// fOut = LLFile::fopen(output_file, "rb"); /* Flawfinder: ignore */ -// LLMD5 my_md5_hash(fOut); -// my_md5_hash.hex_digest(md5_hash_string); -// } - -// gImageChecksums.insert(std::pair(image_id, md5_hash_string)); -// } -// } - -// ++current_image_count; -// if (current_image_count == exported_image_count && current_object_count == exported_object_count) -// { -// LL_INFOS("Messaging") << "*** Export textures complete ***" << LL_ENDL; -// export_complete(); -// } -// else -// { -// gExportDialog->setMessage(llformat("Exported %d/%d object files, %d/%d textures.", current_object_count, exported_object_count, current_image_count, exported_image_count)); -// } -//} - void process_derez_ack(LLMessageSystem*, void**) { - if(gViewerWindow) gViewerWindow->getWindow()->decBusyCount(); + if (gViewerWindow) gViewerWindow->getWindow()->decBusyCount(); } void process_places_reply(LLMessageSystem* msg, void** data) @@ -600,7 +541,7 @@ void process_places_reply(LLMessageSystem* msg, void** data) { LLFloaterLandHoldings::processPlacesReply(msg, data); } - else if(gAgent.isInGroup(query_id)) + else if (gAgent.isInGroup(query_id)) { LLPanelGroupLandMoney::processPlacesReply(msg, data); } @@ -612,7 +553,7 @@ void process_places_reply(LLMessageSystem* msg, void** data) void send_sound_trigger(const LLUUID& sound_id, F32 gain) { - if (sound_id.isNull() || gAgent.getRegion() == NULL) + if (sound_id.isNull() || gAgent.getRegion() == nullptr) { // disconnected agent or zero guids don't get sent (no sound) return; @@ -623,9 +564,9 @@ void send_sound_trigger(const LLUUID& sound_id, F32 gain) msg->nextBlockFast(_PREHASH_SoundData); msg->addUUIDFast(_PREHASH_SoundID, sound_id); // Client untrusted, ids set on sim - msg->addUUIDFast(_PREHASH_OwnerID, LLUUID::null ); - msg->addUUIDFast(_PREHASH_ObjectID, LLUUID::null ); - msg->addUUIDFast(_PREHASH_ParentID, LLUUID::null ); + msg->addUUIDFast(_PREHASH_OwnerID, LLUUID::null); + msg->addUUIDFast(_PREHASH_ObjectID, LLUUID::null); + msg->addUUIDFast(_PREHASH_ParentID, LLUUID::null); msg->addU64Fast(_PREHASH_Handle, gAgent.getRegion()->getHandle()); @@ -636,32 +577,163 @@ void send_sound_trigger(const LLUUID& sound_id, F32 gain) gAgent.sendMessage(); } +static LLSD sSavedGroupInvite; +static LLSD sSavedResponse; + +void response_group_invitation_coro(const LLCoroResponder& responder, const LLUUID& group_id, bool notify_and_update) +{ + const auto& status = responder.getStatus(); + + if (!responder.isGoodStatus(status)) + { + LL_WARNS("GroupInvite") << "HTTP status " << status << ": " << responder.getReason() << + ". Group " << group_id << " invitation response processing failed." << LL_ENDL; + } + else + { + { + LL_DEBUGS("GroupInvite") << "Successfully sent response to group " << group_id << " invitation" << LL_ENDL; + if (notify_and_update) + { + LLNotificationsUtil::add("JoinGroupSuccess"); + gAgent.sendAgentDataUpdateRequest(); + + LLGroupMgr::getInstance()->clearGroupData(group_id); + // refresh the floater for this group, if any. + LLGroupActions::refresh(group_id); + } + } + } +} + +void send_join_group_response(const LLUUID& group_id, const LLUUID& transaction_id, bool accept_invite, S32 fee, bool use_offline_cap, LLSD& payload) +{ + if (accept_invite && fee > 0) + { + // If there is a fee to join this group, make + // sure the user is sure they want to join. + LLSD args; + args["COST"] = llformat("%d", fee); + // Set the fee for next time to 0, so that we don't keep + // asking about a fee. + LLSD next_payload = payload; + next_payload["fee"] = 0; + LLNotificationsUtil::add("JoinGroupCanAfford", + args, + next_payload); + } + else if (use_offline_cap) + { + std::string url; + if (accept_invite) + { + url = gAgent.getRegionCapability("AcceptGroupInvite"); + } + else + { + url = gAgent.getRegionCapability("DeclineGroupInvite"); + } + + if (!url.empty()) + { + LL_DEBUGS("GroupInvite") << "Capability url: " << url << LL_ENDL; + LLSD payload; + payload["group"] = group_id; + LLHTTPClient::post(url, payload, new LLCoroResponder( + boost::bind(response_group_invitation_coro, _1, group_id, accept_invite))); + } + else + { + // if sim has no this cap, we can do nothing - regular request will fail + LL_WARNS("GroupInvite") << "No capability, can't reply to offline invitation!" << LL_ENDL; + } + } + else + { + LL_DEBUGS("GroupInvite") << "Replying to group invite via IM message" << LL_ENDL; + + EInstantMessage type = accept_invite ? IM_GROUP_INVITATION_ACCEPT : IM_GROUP_INVITATION_DECLINE; + + send_improved_im(group_id, + std::string("name"), + std::string("message"), + IM_ONLINE, + type, + transaction_id); + } +} + +void send_join_group_response(const LLUUID& group_id, const LLUUID& transaction_id, bool accept_invite, S32 fee, bool use_offline_cap) +{ + LLSD payload; + if (accept_invite) + { + payload["group_id"] = group_id; + payload["transaction_id"] = transaction_id; + payload["fee"] = fee; + payload["use_offline_cap"] = use_offline_cap; + } + send_join_group_response(group_id, transaction_id, accept_invite, fee, use_offline_cap, payload); +} + bool join_group_response(const LLSD& notification, const LLSD& response) { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + // A bit of variable saving and restoring is used to deal with the case where your group list is full and you + // receive an invitation to another group. The data from that invitation is stored in the sSaved + // variables. If you then drop a group and click on the Join button the stored data is restored and used + // to join the group. + LLSD notification_adjusted = notification; + LLSD response_adjusted = response; + + std::string action = notification["name"]; + + // Storing all the information by group id allows for the rare case of being at your maximum + // group count and receiving more than one invitation. + std::string id = notification_adjusted["payload"]["group_id"].asString(); + + if ("JoinGroup" == action || "JoinGroupCanAfford" == action) + { + sSavedGroupInvite[id] = notification; + sSavedResponse[id] = response; + } + else if ("JoinedTooManyGroupsMember" == action) + { + S32 opt = LLNotificationsUtil::getSelectedOption(notification, response); + if (0 == opt) // Join button pressed + { + notification_adjusted = sSavedGroupInvite[id]; + response_adjusted = sSavedResponse[id]; + } + sSavedGroupInvite.erase(id); + sSavedResponse.erase(id); + } + + S32 option = LLNotificationsUtil::getSelectedOption(notification_adjusted, response_adjusted); bool accept_invite = false; - LLUUID group_id = notification["payload"]["group_id"].asUUID(); - LLUUID transaction_id = notification["payload"]["transaction_id"].asUUID(); - std::string name = notification["payload"]["name"].asString(); - std::string message = notification["payload"]["message"].asString(); - S32 fee = notification["payload"]["fee"].asInteger(); + LLUUID group_id = notification_adjusted["payload"]["group_id"].asUUID(); + LLUUID transaction_id = notification_adjusted["payload"]["transaction_id"].asUUID(); + std::string name = notification_adjusted["payload"]["name"].asString(); + std::string message = notification_adjusted["payload"]["message"].asString(); + S32 fee = notification_adjusted["payload"]["fee"].asInteger(); + U8 use_offline_cap = notification_adjusted["payload"]["use_offline_cap"].asInteger(); if (option == 2 && !group_id.isNull()) { LLGroupActions::show(group_id); LLSD args; args["MESSAGE"] = message; - LLNotificationsUtil::add("JoinGroup", args, notification["payload"]); + LLNotificationsUtil::add("JoinGroup", args, notification_adjusted["payload"]); return false; } - if(option == 0 && !group_id.isNull()) + + if (option == 0 && !group_id.isNull()) { // check for promotion or demotion. - S32 max_groups = gHippoLimits->getMaxAgentGroups(); - if(gAgent.isInGroup(group_id)) ++max_groups; + S32 max_groups = LLAgentBenefitsMgr::current().getGroupMembershipLimit(); + if (gAgent.isInGroup(group_id)) ++max_groups; - if(gAgent.mGroups.count() < max_groups) + if ((S32)gAgent.mGroups.size() < max_groups) { accept_invite = true; } @@ -671,65 +743,32 @@ bool join_group_response(const LLSD& notification, const LLSD& response) args["NAME"] = name; args["INVITE"] = message; LLNotificationsUtil::add("JoinedTooManyGroupsMember", args, notification["payload"]); + return false; } } + send_join_group_response(group_id, transaction_id, accept_invite, fee, use_offline_cap, notification_adjusted["payload"]); - if (accept_invite) - { - // If there is a fee to join this group, make - // sure the user is sure they want to join. - if (fee > 0) - { - LLSD args; - args["COST"] = llformat("%d", fee); - // Set the fee for next time to 0, so that we don't keep - // asking about a fee. - LLSD next_payload = notification["payload"]; - next_payload["fee"] = 0; - LLNotificationsUtil::add("JoinGroupCanAfford", - args, - next_payload); - } - else - { - send_improved_im(group_id, - std::string("name"), - std::string("message"), - IM_ONLINE, - IM_GROUP_INVITATION_ACCEPT, - transaction_id); - } - } - else - { - send_improved_im(group_id, - std::string("name"), - std::string("message"), - IM_ONLINE, - IM_GROUP_INVITATION_DECLINE, - transaction_id); - } + sSavedGroupInvite[id] = LLSD::emptyMap(); + sSavedResponse[id] = LLSD::emptyMap(); return false; } -static void highlight_inventory_objects_in_panel(const std::vector& items, LLInventoryPanel *inventory_panel) +static void highlight_inventory_objects_in_panel(const uuid_vec_t& items, LLInventoryPanel *inventory_panel) { - if (NULL == inventory_panel) return; + if (nullptr == inventory_panel) return; - for (std::vector::const_iterator item_iter = items.begin(); - item_iter != items.end(); - ++item_iter) + for (auto item_id : items) { - const LLUUID& item_id = (*item_iter); - if(!highlight_offered_object(item_id)) + if (!highlight_offered_object(item_id)) { continue; } LLInventoryObject* item = gInventory.getObject(item_id); llassert(item); - if (!item) { + if (!item) + { continue; } @@ -766,14 +805,18 @@ static LLNotificationFunctorRegistration jgr_3("JoinGroupCanAfford", join_group_ //----------------------------------------------------------------------------- // Instant Message //----------------------------------------------------------------------------- -class LLOpenAgentOffer : public LLInventoryFetchItemsObserver +class LLOpenAgentOffer final : public LLInventoryFetchItemsObserver { public: LLOpenAgentOffer(const LLUUID& object_id, const std::string& from_name) : LLInventoryFetchItemsObserver(object_id), - mFromName(from_name) {} - /*virtual*/ void startFetch() + mFromName(from_name) + { + } + + /*virtual*/ + void startFetch() override { for (uuid_vec_t::const_iterator it = mIDs.begin(); it < mIDs.end(); ++it) { @@ -785,12 +828,15 @@ class LLOpenAgentOffer : public LLInventoryFetchItemsObserver } LLInventoryFetchItemsObserver::startFetch(); } - /*virtual*/ void done() + + /*virtual*/ + void done() override { open_inventory_offer(mComplete, mFromName); gInventory.removeObserver(this); delete this; } + private: std::string mFromName; }; @@ -801,19 +847,19 @@ class LLOpenAgentOffer : public LLInventoryFetchItemsObserver * We can't create it each time items are moved because "drop" event is sent separately for each * element even while multi-dragging. We have to have the only instance of the observer. See EXT-4347. */ -class LLViewerInventoryMoveFromWorldObserver : public LLInventoryAddItemByAssetObserver +class LLViewerInventoryMoveFromWorldObserver final : public LLInventoryAddItemByAssetObserver { public: LLViewerInventoryMoveFromWorldObserver() : LLInventoryAddItemByAssetObserver() { - } - void setMoveIntoFolderID(const LLUUID& into_folder_uuid) {mMoveIntoFolderID = into_folder_uuid; } + void setMoveIntoFolderID(const LLUUID& into_folder_uuid) { mMoveIntoFolderID = into_folder_uuid; } private: - /*virtual */void onAssetAdded(const LLUUID& asset_id) + /*virtual */ + void onAssetAdded(const LLUUID& asset_id) override { // Store active Inventory panel. if (LLInventoryPanel::getActiveInventoryPanel()) @@ -834,7 +880,7 @@ class LLViewerInventoryMoveFromWorldObserver : public LLInventoryAddItemByAssetO * Selects added inventory items watched by their Asset UUIDs if selection was not changed since * all items were started to watch (dropped into a folder). */ - void done() + void done() override { LLInventoryPanel* active_panel = dynamic_cast(mActivePanel.get()); @@ -854,7 +900,7 @@ class LLViewerInventoryMoveFromWorldObserver : public LLInventoryAddItemByAssetO { LLInventoryPanel* active_panel = dynamic_cast(mActivePanel.get()); - if (NULL == active_panel) + if (nullptr == active_panel) { return true; } @@ -871,11 +917,11 @@ class LLViewerInventoryMoveFromWorldObserver : public LLInventoryAddItemByAssetO LL_DEBUGS("Inventory_Move") << "Selected firstly: " << mSelectedItems.size() << ", now: " << selected_items.size() << ", difference: " << different_items.size() << LL_ENDL; - return different_items.size() > 0; + return !different_items.empty(); } LLHandle mActivePanel; - typedef std::set selected_items_t; + typedef uuid_set_t selected_items_t; selected_items_t mSelectedItems; /** @@ -893,7 +939,7 @@ class LLViewerInventoryMoveFromWorldObserver : public LLInventoryAddItemByAssetO LLUUID mMoveIntoFolderID; }; -LLViewerInventoryMoveFromWorldObserver* gInventoryMoveObserver = NULL; +LLViewerInventoryMoveFromWorldObserver* gInventoryMoveObserver = nullptr; void set_dad_inventory_item(LLInventoryItem* inv_item, const LLUUID& into_folder_uuid) { @@ -910,7 +956,7 @@ void set_dad_inventory_item(LLInventoryItem* inv_item, const LLUUID& into_folder * Used currently for dragging from inbox to regular inventory folders */ -class LLViewerInventoryMoveObserver : public LLInventoryObserver +class LLViewerInventoryMoveObserver final : public LLInventoryObserver { public: @@ -924,39 +970,37 @@ class LLViewerInventoryMoveObserver : public LLInventoryObserver } } - virtual ~LLViewerInventoryMoveObserver() {} - virtual void changed(U32 mask); + virtual ~LLViewerInventoryMoveObserver() = default; + + void changed(U32 mask) override; private: LLUUID mObjectID; LLHandle mActivePanel; - }; void LLViewerInventoryMoveObserver::changed(U32 mask) { LLInventoryPanel* active_panel = dynamic_cast(mActivePanel.get()); - if (NULL == active_panel) + if (nullptr == active_panel) { gInventory.removeObserver(this); return; } - if((mask & (LLInventoryObserver::STRUCTURE)) != 0) + if ((mask & (STRUCTURE)) != 0) { - const std::set& changed_items = gInventory.getChangedIDs(); + const uuid_set_t& changed_items = gInventory.getChangedIDs(); - std::set::const_iterator id_it = changed_items.begin(); - std::set::const_iterator id_end = changed_items.end(); + auto id_it = changed_items.begin(); + auto id_end = changed_items.end(); for (;id_it != id_end; ++id_it) { if ((*id_it) == mObjectID) { active_panel->clearSelection(); - std::vector items; - items.push_back(mObjectID); - highlight_inventory_objects_in_panel(items, active_panel); + highlight_inventory_objects_in_panel({mObjectID}, active_panel); active_panel->getRootFolder()->scrollToShowSelection(); gInventory.removeObserver(this); @@ -977,12 +1021,18 @@ void set_dad_inbox_object(const LLUUID& object_id) //and it never dies. We do this because we don't know the UUID of //task offers until they are accepted, so we don't wouldn't //know what to watch for, so instead we just watch for all additions. -class LLOpenTaskOffer : public LLInventoryAddedObserver +class LLOpenTaskOffer final : public LLInventoryAddedObserver { protected: - /*virtual*/ void done() + /*virtual*/ + void done() override { - for (uuid_vec_t::iterator it = mAdded.begin(); it != mAdded.end();) + uuid_vec_t added; + for (auto it : gInventory.getAddedIDs()) + { + added.push_back(it); + } + for (uuid_vec_t::iterator it = added.begin(); it != added.end();) { const LLUUID& item_uuid = *it; bool was_moved = false; @@ -1004,40 +1054,46 @@ class LLOpenTaskOffer : public LLInventoryAddedObserver if (was_moved) { - it = mAdded.erase(it); + it = added.erase(it); } else ++it; } - open_inventory_offer(mAdded, ""); - mAdded.clear(); + open_inventory_offer(added, ""); } - }; +}; -class LLOpenTaskGroupOffer : public LLInventoryAddedObserver +class LLOpenTaskGroupOffer final : public LLInventoryAddedObserver { protected: - /*virtual*/ void done() + /*virtual*/ + void done() override { - open_inventory_offer(mAdded, "group_offer"); - mAdded.clear(); + uuid_vec_t added; + for (auto it : gInventory.getAddedIDs()) + { + added.push_back(it); + } + open_inventory_offer(added, "group_offer"); gInventory.removeObserver(this); delete this; } }; //one global instance to bind them -LLOpenTaskOffer* gNewInventoryObserver=NULL; -class LLNewInventoryHintObserver : public LLInventoryAddedObserver +LLOpenTaskOffer* gNewInventoryObserver = nullptr; + +class LLNewInventoryHintObserver final : public LLInventoryAddedObserver { protected: - /*virtual*/ void done() + /*virtual*/ + void done() override { //LLFirstUse::newInventory(); } }; -LLNewInventoryHintObserver* gNewInventoryHintObserver=NULL; +LLNewInventoryHintObserver* gNewInventoryHintObserver = nullptr; void start_new_inventory_observer() { @@ -1054,9 +1110,16 @@ void start_new_inventory_observer() gInventoryMoveObserver = new LLViewerInventoryMoveFromWorldObserver; gInventory.addObserver(gInventoryMoveObserver); } + + if (!gNewInventoryHintObserver) + { + // Observer is deleted by gInventory + gNewInventoryHintObserver = new LLNewInventoryHintObserver(); + gInventory.addObserver(gNewInventoryHintObserver); + } } -class LLDiscardAgentOffer : public LLInventoryFetchItemsObserver +class LLDiscardAgentOffer final : public LLInventoryFetchItemsObserver { LOG_CLASS(LLDiscardAgentOffer); @@ -1064,9 +1127,11 @@ class LLDiscardAgentOffer : public LLInventoryFetchItemsObserver LLDiscardAgentOffer(const LLUUID& folder_id, const LLUUID& object_id) : LLInventoryFetchItemsObserver(object_id), mFolderID(folder_id), - mObjectID(object_id) {} + mObjectID(object_id) + { + } - virtual void done() + void done() override { LL_DEBUGS("Messaging") << "LLDiscardAgentOffer::done()" << LL_ENDL; @@ -1076,7 +1141,7 @@ class LLDiscardAgentOffer : public LLInventoryFetchItemsObserver // So defer moving the item to trash until viewer gets idle (in a moment). // Use removeObject() rather than removeItem() because at this level, // the object could be either an item or a folder. - LLAppViewer::instance()->addOnIdleCallback(boost::bind(&LLInventoryModel::removeObject, &gInventory, mObjectID)); + LLAppViewer::instance()->addOnIdleCallback(std::bind(&LLInventoryModel::removeObject, &gInventory, mObjectID)); gInventory.removeObserver(this); delete this; } @@ -1095,7 +1160,6 @@ bool check_offer_throttle(const std::string& from_name, bool check_only) static U32 throttle_count; static bool throttle_logged; LLChat chat; - std::string log_message; if (!gSavedSettings.getBOOL("ShowNewInventory")) return false; @@ -1105,58 +1169,53 @@ bool check_offer_throttle(const std::string& from_name, bool check_only) return gThrottleTimer.hasExpired(); } - if(gThrottleTimer.checkExpirationAndReset(OFFER_THROTTLE_TIME)) + if (gThrottleTimer.checkExpirationAndReset(OFFER_THROTTLE_TIME)) { LL_DEBUGS("Messaging") << "Throttle Expired" << LL_ENDL; - throttle_count=1; - throttle_logged=false; + throttle_count = 1; + throttle_logged = false; return true; } - else //has not expired + //has not expired + LL_DEBUGS("Messaging") << "Throttle Not Expired, Count: " << throttle_count << LL_ENDL; + // When downloading the initial inventory we get a lot of new items + // coming in and can't tell that from spam. + if (LLStartUp::getStartupState() >= STATE_STARTED + && throttle_count >= OFFER_THROTTLE_MAX_COUNT) { - LL_DEBUGS("Messaging") << "Throttle Not Expired, Count: " << throttle_count << LL_ENDL; - // When downloading the initial inventory we get a lot of new items - // coming in and can't tell that from spam. - if (LLStartUp::getStartupState() >= STATE_STARTED - && throttle_count >= OFFER_THROTTLE_MAX_COUNT) + if (!throttle_logged) { - if (!throttle_logged) - { - // Use the name of the last item giver, who is probably the person - // spamming you. + // Use the name of the last item giver, who is probably the person + // spamming you. - LLStringUtil::format_map_t arg; - std::string log_msg; - std::ostringstream time ; - time<getSecondLifeTitle(); - arg["TIME"] = time.str(); + arg["APP_NAME"] = LLAppViewer::instance()->getSecondLifeTitle(); + arg["TIME"] = time.str(); - if (!from_name.empty()) - { - arg["FROM_NAME"] = from_name; - log_msg = LLTrans::getString("ItemsComingInTooFastFrom", arg); - } - else - { - log_msg = LLTrans::getString("ItemsComingInTooFast", arg); - } + if (!from_name.empty()) + { + arg["FROM_NAME"] = from_name; + log_msg = LLTrans::getString("ItemsComingInTooFastFrom", arg); + } + else + { + log_msg = LLTrans::getString("ItemsComingInTooFast", arg); + } - //this is kinda important, so actually put it on screen - chat.mText = log_msg; - LLFloaterChat::addChat(chat, FALSE, FALSE); + //this is kinda important, so actually put it on screen + chat.mText = log_msg; + LLFloaterChat::addChat(chat, FALSE, FALSE); - throttle_logged=true; - } - return false; - } - else - { - throttle_count++; - return true; + throttle_logged = true; } + return false; } + throttle_count++; + return true; } // Return "true" if we have a preview method for that asset type, "false" otherwise @@ -1172,21 +1231,18 @@ bool check_asset_previewable(const LLAssetType::EType asset_type) void open_inventory_offer(const uuid_vec_t& objects, const std::string& from_name) { - if (gAgent.getBusy()) return; - for (uuid_vec_t::const_iterator obj_iter = objects.begin(); - obj_iter != objects.end(); - ++obj_iter) + if (gAgent.isDoNotDisturb()) return; + for (auto obj_id : objects) { - const LLUUID& obj_id = (*obj_iter); - if(!highlight_offered_object(obj_id)) + if (!highlight_offered_object(obj_id)) { continue; } - const LLInventoryObject *obj = gInventory.getObject(obj_id); + const LLInventoryObject* obj = gInventory.getObject(obj_id); if (!obj) { - llwarns << "Cannot find object [ itemID:" << obj_id << " ] to open." << llendl; + LL_WARNS() << "Cannot find object [ itemID:" << obj_id << " ] to open." << LL_ENDL; continue; } @@ -1235,7 +1291,7 @@ void open_inventory_offer(const uuid_vec_t& objects, const std::string& from_nam //highlight item, if it's not in the trash or lost+found // Don't auto-open the inventory floater - LLInventoryView* view = LLInventoryView::getActiveInventory(); + LLPanelMainInventory* view = LLPanelMainInventory::getActiveInventory(); if(!view) { return; @@ -1252,12 +1308,13 @@ void open_inventory_offer(const uuid_vec_t& objects, const std::string& from_nam if (gSavedSettings.getBOOL("ShowInInventory") && objects.size() == 1 && item != NULL && asset_type != LLAssetType::AT_CALLINGCARD && - item->getInventoryType() != LLInventoryType::IT_ATTACHMENT && + item->getInventoryType() != LLInventoryType::EType::IT_ATTACHMENT && !from_name.empty()) { - LLInventoryView::showAgentInventory(TRUE); + LLPanelMainInventory::showAgentInventory(TRUE); } + if (!gSavedSettings.getBOOL("LiruHighlightNewInventory")) return; //////////////////////////////////////////////////////////////////////////////// // Highlight item LL_DEBUGS("Messaging") << "Highlighting" << obj_id << LL_ENDL; @@ -1271,7 +1328,7 @@ void open_inventory_offer(const uuid_vec_t& objects, const std::string& from_nam bool highlight_offered_object(const LLUUID& obj_id) { const LLInventoryObject* obj = gInventory.getObject(obj_id); - if(!obj) + if (!obj) { LL_WARNS("Messaging") << "Unable to show inventory item: " << obj_id << LL_ENDL; return false; @@ -1280,9 +1337,9 @@ bool highlight_offered_object(const LLUUID& obj_id) //////////////////////////////////////////////////////////////////////////////// // Don't highlight if it's in certain "quiet" folders which don't need UI // notification (e.g. trash, cof, lost-and-found). - if(!gAgent.getAFK()) + if (!gAgent.getAFK()) { - const LLViewerInventoryCategory *parent = gInventory.getFirstNondefaultParent(obj_id); + const LLViewerInventoryCategory* parent = gInventory.getFirstNondefaultParent(obj_id); if (parent) { const LLFolderType::EType parent_type = parent->getPreferredType(); @@ -1306,16 +1363,18 @@ void inventory_offer_mute_callback(const LLUUID& blocked_id, LLMute mute(blocked_id, full_name, mute_type); if (LLMuteList::getInstance()->add(mute)) { - LLFloaterMute::showInstance(); - LLFloaterMute::getInstance()->selectMute(blocked_id); + LLFloaterMute::showInstance()->selectMute(blocked_id); } // purge the message queue of any previously queued inventory offers from the same source. - class OfferMatcher : public LLNotifyBoxView::Matcher + class OfferMatcher final : public LLNotifyBoxView::Matcher { public: - OfferMatcher(const LLUUID& to_block) : blocked_id(to_block) {} - bool matches(const LLNotificationPtr notification) const + OfferMatcher(const LLUUID& to_block) : blocked_id(to_block) + { + } + + bool matches(const LLNotificationPtr notification) const override { if(notification->getName() == "ObjectGiveItem" || notification->getName() == "ObjectGiveItemUnknownUser" @@ -1325,6 +1384,7 @@ void inventory_offer_mute_callback(const LLUUID& blocked_id, } return FALSE; } + private: const LLUUID& blocked_id; }; @@ -1400,6 +1460,8 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& return false; } + chat.mSourceType = CHAT_SOURCE_SYSTEM; // There's a slim potential of a user-editable field being a url here? + LLViewerInventoryCategory* catp = NULL; catp = gInventory.getCategory(mObjectID); LLViewerInventoryItem* itemp = NULL; @@ -1444,8 +1506,8 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& { if (mFromGroup) { - std::string group_name; - if (gCacheName->getGroupName(mFromID, group_name)) + std::string group_name = LLGroupActions::getSLURL(mFromID); + //if (gCacheName->getGroupName(mFromID, group_name)) { from_string = LLTrans::getString("InvOfferAnObjectNamed") + " " + LLTrans::getString("'") + mFromName + LLTrans::getString("'") + " " + LLTrans::getString("InvOfferOwnedByGroup") @@ -1454,35 +1516,38 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedByGroup") + " " + group_name + LLTrans::getString("'") + LLTrans::getString("."); } - else + /*else { from_string = LLTrans::getString("InvOfferAnObjectNamed") + " " + LLTrans::getString("'") + mFromName + LLTrans::getString("'") + " " + LLTrans::getString("InvOfferOwnedByUnknownGroup"); chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedByUnknownGroup") + LLTrans::getString("."); - } + }*/ } else { - std::string full_name; - if (gCacheName->getFullName(mFromID, full_name)) - { + std::string full_name = LLAvatarActions::getSLURL(mFromID); + // [RLVa:KB] - Version: 1.23.4 | Checked: 2009-07-08 (RLVa-1.0.0e) - if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (RlvUtil::isNearbyAgent(mFromID)) ) + if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (RlvUtil::isNearbyAgent(mFromID)) ) + { + if (gCacheName->getFullName(mFromID, full_name)) { full_name = RlvStrings::getAnonym(full_name); } - from_string = LLTrans::getString("InvOfferAnObjectNamed") + " " + LLTrans::getString("'") + mFromName - + LLTrans::getString("'") +" " + LLTrans::getString("InvOfferOwnedBy") + full_name; - chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedBy") + " " + full_name + LLTrans::getString("."); -// [/RLVa:KB] - //from_string = std::string("An object named '") + mFromName + "' owned by " + first_name + " " + last_name; - //chatHistory_string = mFromName + " owned by " + first_name + " " + last_name; + } + + from_string = LLTrans::getString("InvOfferAnObjectNamed") + " " + LLTrans::getString("'") + mFromName + LLTrans::getString("'") + ' '; + chatHistory_string = mFromName + ' '; + if (full_name.empty()) + { + from_string += LLTrans::getString("InvOfferOwnedByUnknownUser"); + chatHistory_string += LLTrans::getString("InvOfferOwnedByUnknownUser") + LLTrans::getString("."); } else +// [/RLVa:KB] { - from_string = LLTrans::getString("InvOfferAnObjectNamed") + " " + LLTrans::getString("'") - + mFromName + LLTrans::getString("'") + " " + LLTrans::getString("InvOfferOwnedByUnknownUser"); - chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedByUnknownUser") + LLTrans::getString("."); + from_string += LLTrans::getString("InvOfferOwnedBy") + full_name; + chatHistory_string += LLTrans::getString("InvOfferOwnedBy") + " " + full_name + LLTrans::getString("."); } } } @@ -1491,9 +1556,9 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& from_string = chatHistory_string = mFromName; } - bool busy = gAgent.getBusy(); + bool busy = gAgent.isDoNotDisturb(); -// [RLVa:KB] - Checked: 2010-09-23 (RLVa-1.2.1e) | Added: RLVa-1.2.1e +// [RLVa:KB] - Checked: 2010-09-23 (RLVa-1.2.1) bool fRlvNotifyAccepted = false; // [/RLVa:KB] switch(button) @@ -1504,25 +1569,23 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& // group_notice_inventory is 1 greater than the offer integer value. // [RLVa:KB] - Checked: 2010-09-23 (RLVa-1.2.1e) | Modified: RLVa-1.2.1e - // Only change the inventory offer's destination folder to the shared root if: + // Only treat the offer as 'Give to #RLV' if: // - the user has enabled the feature // - the inventory offer came from a script (and specifies a folder) // - the name starts with the prefix - mDesc format: '[OBJECTNAME]' ( http://slurl.com/... ) - if ( (rlv_handler_t::isEnabled()) && - (IM_TASK_INVENTORY_OFFERED == mIM) && (LLAssetType::AT_CATEGORY == mType) && (mDesc.find(RLV_PUTINV_PREFIX) == 1) ) + if ( (rlv_handler_t::isEnabled()) && (IM_TASK_INVENTORY_OFFERED == mIM) && (LLAssetType::AT_CATEGORY == mType) && (mDesc.find(RLV_PUTINV_PREFIX) == 1) ) { fRlvNotifyAccepted = true; if (!RlvSettings::getForbidGiveToRLV()) { - const LLViewerInventoryCategory* pRlvRoot = RlvInventory::instance().getSharedRoot(); - if (pRlvRoot) - { - fRlvNotifyAccepted = false; // "accepted_in_rlv" is sent from RlvGiveToRLVTaskOffer *after* we have the folder - mFolderID = pRlvRoot->getUUID(); + const LLUUID& idRlvRoot = RlvInventory::instance().getSharedRootID(); + if (idRlvRoot.notNull()) + mFolderID = idRlvRoot; - RlvGiveToRLVTaskOffer* pOfferObserver = new RlvGiveToRLVTaskOffer(mTransactionID); - gInventory.addObserver(pOfferObserver); - } + fRlvNotifyAccepted = false; // "accepted_in_rlv" is sent from RlvGiveToRLVTaskOffer *after* we have the folder + + RlvGiveToRLVTaskOffer* pOfferObserver = new RlvGiveToRLVTaskOffer(mTransactionID); + gInventory.addObserver(pOfferObserver); } } // [/RLVa:KB] @@ -1535,7 +1598,7 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& // send the message msg->sendReliable(mHost); -// [RLVa:KB] - Checked: 2010-09-23 (RLVa-1.2.1e) | Added: RLVa-1.2.1e +// [RLVa:KB] - Checked: 2010-09-23 (RLVa-1.2.1) if (fRlvNotifyAccepted) { std::string::size_type idxToken = mDesc.find("' ( http://"); @@ -1547,8 +1610,11 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& //don't spam them if they are getting flooded if (check_offer_throttle(mFromName, true)) { - log_message = chatHistory_string + " " + LLTrans::getString("InvOfferGaveYou") + " " + mDesc + LLTrans::getString("."); + log_message = chatHistory_string + ' ' + LLTrans::getString("InvOfferGaveYou") + ' ' + mDesc + LLTrans::getString("."); chat.mText = log_message; + if (mFromObject || !mFromGroup) + chat.mURL = mFromGroup ? LLGroupActions::getSLURL(mFromID) : LLAvatarActions::getSLURL(mFromID); + chat.mFromName = mFromName; LLFloaterChat::addChatHistory(chat); } @@ -1562,9 +1628,8 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& // This is an offer from an agent. In this case, the back // end has already copied the items into your inventory, // so we can fetch it out of our inventory. -// [RLVa:KB] - Checked: 2010-04-18 (RLVa-1.2.0e) | Modified: RLVa-1.2.0e - if ( (rlv_handler_t::isEnabled()) && (!RlvSettings::getForbidGiveToRLV()) && (LLAssetType::AT_CATEGORY == mType) && - (RlvInventory::instance().getSharedRoot()) && (mDesc.find(RLV_PUTINV_PREFIX) == 0) ) +// [RLVa:KB] - Checked: 2010-04-18 (RLVa-1.2.0) + if ( (rlv_handler_t::isEnabled()) && (!RlvSettings::getForbidGiveToRLV()) && (LLAssetType::AT_CATEGORY == mType) && (mDesc.find(RLV_PUTINV_PREFIX) == 0) ) { RlvGiveToRLVAgentOffer* pOfferObserver = new RlvGiveToRLVAgentOffer(mObjectID); pOfferObserver->startFetch(); @@ -1603,6 +1668,34 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& } // end switch (mIM) break; + case -2: // decline silently + { + LLStringUtil::format_map_t args; + args["[DESC]"] = mDesc; + args["[NAME]"] = mFromName; + LLFloaterChat::addChatHistory(LLTrans::getString("InvOfferDeclineSilent", args)); + } + break; + case -1: // accept silently + { + LLOpenAgentOffer* open_agent_offer = new LLOpenAgentOffer(mObjectID, from_string); + open_agent_offer->startFetch(); + if(catp || (itemp && itemp->isFinished())) + { + open_agent_offer->done(); + } + else + { + opener = open_agent_offer; + } + LLStringUtil::format_map_t args; + args["[DESC]"] = mDesc; + args["[NAME]"] = mFromName; + LLFloaterChat::addChatHistory(LLTrans::getString("InvOfferAcceptSilent", args)); + } + + break; + case IOR_BUSY: //Busy falls through to decline. Says to make busy message. busy=TRUE; @@ -1621,26 +1714,29 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& // send the message msg->sendReliable(mHost); -// [RLVa:KB] - Checked: 2010-09-23 (RLVa-1.2.1e) | Added: RLVa-1.2.1e - if ( (rlv_handler_t::isEnabled()) && - (IM_TASK_INVENTORY_OFFERED == mIM) && (LLAssetType::AT_CATEGORY == mType) && (mDesc.find(RLV_PUTINV_PREFIX) == 1) ) + if (!mFromGroup && gSavedSettings.getBOOL("LogInventoryDecline")) { - std::string::size_type idxToken = mDesc.find("' ( http://"); - if (std::string::npos != idxToken) - RlvBehaviourNotifyHandler::instance().sendNotification("declined inv_offer " + mDesc.substr(1, idxToken - 1)); - } +// [RLVa:KB] - Checked: 2010-09-23 (RLVa-1.2.1e) | Added: RLVa-1.2.1e + if ( (rlv_handler_t::isEnabled()) && + (IM_TASK_INVENTORY_OFFERED == mIM) && (LLAssetType::AT_CATEGORY == mType) && (mDesc.find(RLV_PUTINV_PREFIX) == 1) ) + { + std::string::size_type idxToken = mDesc.find("' ( http://"); + if (std::string::npos != idxToken) + RlvBehaviourNotifyHandler::instance().sendNotification("declined inv_offer " + mDesc.substr(1, idxToken - 1)); + } // [/RLVa:KB] - LLStringUtil::format_map_t log_message_args; - log_message_args["[DESC]"] = mDesc; - log_message_args["[NAME]"] = mFromName; - log_message = LLTrans::getString("InvOfferDecline", log_message_args); - chat.mText = log_message; - if( LLMuteList::getInstance()->isMuted(mFromID ) && ! LLMuteList::getInstance()->isLinden(mFromName) ) // muting for SL-42269 - { - chat.mMuted = TRUE; + LLStringUtil::format_map_t log_message_args; + log_message_args["[DESC]"] = mDesc; + log_message_args["[NAME]"] = mFromName; + log_message = LLTrans::getString("InvOfferDecline", log_message_args); + chat.mText = log_message; + if( LLMuteList::getInstance()->isMuted(mFromID ) && ! LLMuteList::getInstance()->isLinden(mFromName) ) // muting for SL-42269 + { + chat.mMuted = TRUE; + } + LLFloaterChat::addChatHistory(chat); } - LLFloaterChat::addChatHistory(chat); // If it's from an agent, we have to fetch the item to throw // it away. If it's from a task or group, just denying the @@ -1661,7 +1757,7 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& } if (busy && (!mFromGroup && !mFromObject)) { - busy_message(msg,mFromID); + send_do_not_disturb_message(msg,mFromID); } break; } @@ -1679,1752 +1775,238 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& return false; } +bool has_spam_bypass(bool is_friend, bool is_owned_by_me) +{ + static LLCachedControl antispam_not_mine(gSavedSettings,"AntiSpamNotMine"); + static LLCachedControl antispam_not_friend(gSavedSettings,"AntiSpamNotFriend"); + return (antispam_not_mine && is_owned_by_me) || (antispam_not_friend && is_friend); +} + bool is_spam_filtered(const EInstantMessage& dialog, bool is_friend, bool is_owned_by_me) { - // First, check the master filter + // First, check that this doesn't bypass. + if (has_spam_bypass(is_friend, is_owned_by_me)) return false; + + // Second, check the master filter static LLCachedControl antispam(gSavedSettings,"_NACL_Antispam"); if (antispam) return true; - // Second, check if this dialog type is even being filtered + // Third, check if this dialog type is even being filtered switch(dialog) { case IM_GROUP_NOTICE: case IM_GROUP_NOTICE_REQUESTED: - if (!gSavedSettings.getBOOL("AntiSpamGroupNotices")) return false; - break; + { + static const LLCachedControl filter("AntiSpamGroupNotices"); + return filter; + } case IM_GROUP_INVITATION: - if (!gSavedSettings.getBOOL("AntiSpamGroupInvites")) return false; - break; + { + static const LLCachedControl filter("AntiSpamGroupInvites"); + return filter; + } case IM_INVENTORY_OFFERED: case IM_TASK_INVENTORY_OFFERED: - if (!gSavedSettings.getBOOL("AntiSpamItemOffers")) return false; - break; + { + static const LLCachedControl filter("AntiSpamItemOffers"); + return filter; + } case IM_FROM_TASK_AS_ALERT: - if (!gSavedSettings.getBOOL("AntiSpamAlerts")) return false; - break; + { + static const LLCachedControl filter("AntiSpamAlerts"); + return filter; + } case IM_LURE_USER: - if (!gSavedSettings.getBOOL("AntiSpamTeleports")) return false; - break; + { + static const LLCachedControl filter("AntiSpamTeleports"); + return filter; + } case IM_TELEPORT_REQUEST: - if (!gSavedSettings.getBOOL("AntiSpamTeleportRequests")) return false; - break; + { + static const LLCachedControl filter("AntiSpamTeleportRequests"); + return filter; + } case IM_FRIENDSHIP_OFFERED: - if (!gSavedSettings.getBOOL("AntiSpamFriendshipOffers")) return false; - break; + { + static const LLCachedControl filter("AntiSpamFriendshipOffers"); + return filter; + } case IM_COUNT: + { // Bit of a hack, we should never get here unless we did this on purpose, though, doesn't matter because we'd do nothing anyway - if (!gSavedSettings.getBOOL("AntiSpamScripts")) return false; - break; + static const LLCachedControl filter( "AntiSpamScripts"); + return filter; + } default: return false; } - - // Third, possibly filtered, check the filter bypasses - static LLCachedControl antispam_not_mine(gSavedSettings,"AntiSpamNotMine"); - if (antispam_not_mine && is_owned_by_me) - return false; - - static LLCachedControl antispam_not_friend(gSavedSettings,"AntiSpamNotFriend"); - if (antispam_not_friend && is_friend) - return false; - - // Last, definitely filter - return true; } -void inventory_offer_handler(LLOfferInfo* info) +bool lure_callback(const LLSD& notification, const LLSD& response) { - // NaCl - Antispam Registry - if (NACLAntiSpamRegistry::checkQueue((U32)NACLAntiSpamRegistry::QUEUE_INVENTORY,info->mFromID)) + S32 option = 0; + if (response.isInteger()) { - delete info; - return; + option = response.asInteger(); } - // NaCl End - //If muted, don't even go through the messaging stuff. Just curtail the offer here. - if (LLMuteList::getInstance()->isMuted(info->mFromID, info->mFromName)) + else { - info->forceResponse(IOR_MUTE); - return; + option = LLNotificationsUtil::getSelectedOption(notification, response); } + + LLUUID from_id = notification["payload"]["from_id"].asUUID(); + LLUUID lure_id = notification["payload"]["lure_id"].asUUID(); + BOOL godlike = notification["payload"]["godlike"].asBoolean(); - // If the user wants to, accept all offers of any kind - if (gSavedSettings.getBOOL("AutoAcceptAllNewInventory")) + switch (option) { - info->forceResponse(IOR_ACCEPT); - return; - } - - // Avoid the Accept/Discard dialog if the user so desires. JC - if (gSavedSettings.getBOOL("AutoAcceptNewInventory") - && (info->mType == LLAssetType::AT_NOTECARD - || info->mType == LLAssetType::AT_LANDMARK - || info->mType == LLAssetType::AT_TEXTURE)) - { - // For certain types, just accept the items into the inventory, - // and possibly open them on receipt depending upon "ShowNewInventory". - info->forceResponse(IOR_ACCEPT); - return; - } - - if (gAgent.getBusy() && info->mIM != IM_TASK_INVENTORY_OFFERED) // busy mode must not affect interaction with objects (STORM-565) - { - // Until throttling is implemented, busy mode should reject inventory instead of silently - // accepting it. SEE SL-39554 - info->forceResponse(IOR_DECLINE); - return; - } - - // Strip any SLURL from the message display. (DEV-2754) - std::string msg = info->mDesc; - int indx = msg.find(" ( http://slurl.com/secondlife/"); - if(indx == std::string::npos) - { - // try to find new slurl host - indx = msg.find(" ( http://maps.secondlife.com/secondlife/"); - } - if(indx >= 0) - { - LLStringUtil::truncate(msg, indx); - } - - LLSD args; - args["[OBJECTNAME]"] = msg; - - LLSD payload; - - // must protect against a NULL return from lookupHumanReadable() - std::string typestr = ll_safe_string(LLAssetType::lookupHumanReadable(info->mType)); - if (!typestr.empty()) - { - // human readable matches string name from strings.xml - // lets get asset type localized name - args["OBJECTTYPE"] = LLTrans::getString(typestr); - } - else - { - LL_WARNS("Messaging") << "LLAssetType::lookupHumanReadable() returned NULL - probably bad asset type: " << info->mType << LL_ENDL; - args["OBJECTTYPE"] = ""; - - // This seems safest, rather than propagating bogosity - LL_WARNS("Messaging") << "Forcing an inventory-decline for probably-bad asset type." << LL_ENDL; - info->forceResponse(IOR_DECLINE); - return; - } - - // Name cache callbacks don't store userdata, so can't save - // off the LLOfferInfo. Argh. - BOOL name_found = FALSE; - payload["from_id"] = info->mFromID; - args["OBJECTFROMNAME"] = info->mFromName; - args["NAME"] = info->mFromName; - if (info->mFromGroup) - { - std::string group_name; - if (gCacheName->getGroupName(info->mFromID, group_name)) - { - args["NAME"] = group_name; - name_found = TRUE; - } - } - else - { - std::string full_name; - if (gCacheName->getFullName(info->mFromID, full_name)) - { -// [RLVa:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a - // Only filter if the object owner is a nearby agent - if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (RlvUtil::isNearbyAgent(info->mFromID)) ) - { - full_name = RlvStrings::getAnonym(full_name); - } -// [/RLVa:KB] - args["NAME"] = full_name; - name_found = TRUE; - } - } - - - LLNotification::Params p("ObjectGiveItem"); - p.substitutions(args).payload(payload).functor(boost::bind(&LLOfferInfo::inventory_offer_callback, info, _1, _2)); - - // Object -> Agent Inventory Offer - if (info->mFromObject) - { - p.name = name_found ? "ObjectGiveItem" : "ObjectGiveItemUnknownUser"; - } - else // Agent -> Agent Inventory Offer - { -// [RLVa:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a - // Only filter if the offer is from a nearby agent and if there's no open IM session (doesn't necessarily have to be focused) - if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (RlvUtil::isNearbyAgent(info->mFromID)) && - (!RlvUIEnabler::hasOpenIM(info->mFromID)) ) - { - args["NAME"] = RlvStrings::getAnonym(info->mFromName); - } -// [/RLVa:KB] - p.name = "UserGiveItem"; - } - - LLNotifications::instance().add(p); -} - - -bool group_vote_callback(const LLSD& notification, const LLSD& response) -{ - LLUUID group_id = notification["payload"]["group_id"].asUUID(); - S32 option = LLNotification::getSelectedOption(notification, response); - switch(option) - { - case 0: - // Vote Now - // Open up the voting tab - LLGroupActions::showTab(group_id, "voting_tab"); - break; - default: - // Vote Later or - // close button - break; - } - return false; -} -static LLNotificationFunctorRegistration group_vote_callback_reg("GroupVote", group_vote_callback); - -bool lure_callback(const LLSD& notification, const LLSD& response) -{ - S32 option = 0; - if (response.isInteger()) - { - option = response.asInteger(); - } - else - { - option = LLNotificationsUtil::getSelectedOption(notification, response); - } - - LLUUID from_id = notification["payload"]["from_id"].asUUID(); - LLUUID lure_id = notification["payload"]["lure_id"].asUUID(); - BOOL godlike = notification["payload"]["godlike"].asBoolean(); - - switch(option) - { - case 0: - { - // accept - gAgent.teleportViaLure(lure_id, godlike); - } - break; - case 3: - // profile - LLAvatarActions::showProfile(from_id); - LLNotificationsUtil::add(notification["name"], notification["substitutions"], notification["payload"]); //Respawn! - break; - case 1: - default: - // decline - send_simple_im(from_id, - LLStringUtil::null, - IM_LURE_DECLINED, - lure_id); - break; - } - return false; -} -static LLNotificationFunctorRegistration lure_callback_reg("TeleportOffered", lure_callback); - -bool goto_url_callback(const LLSD& notification, const LLSD& response) -{ - std::string url = notification["payload"]["url"].asString(); - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if(1 == option) - { - LLWeb::loadURL(url); - } - return false; -} -static LLNotificationFunctorRegistration goto_url_callback_reg("GotoURL", goto_url_callback); -static bool parse_lure_bucket(const std::string& bucket, - U64& region_handle, - LLVector3& pos, - LLVector3& look_at, - U8& region_access) -{ - // tokenize the bucket - typedef boost::tokenizer > tokenizer; - boost::char_separator sep("|", "", boost::keep_empty_tokens); - tokenizer tokens(bucket, sep); - tokenizer::iterator iter = tokens.begin(); - - S32 e[8]; - try - { - for (int i = 0; i < 8 && iter != tokens.end(); ++i) - { - e[i] = boost::lexical_cast((*(iter++)).c_str()); - } - } - catch( boost::bad_lexical_cast& ) - { - LL_WARNS("parse_lure_bucket") - << "Couldn't parse lure bucket with content \"" << bucket << "\"." - << LL_ENDL; - return false; - } - // Grab region access - region_access = SIM_ACCESS_MIN; - if (iter != tokens.end()) - { - std::string access_str((*iter).c_str()); - LLStringUtil::trim(access_str); - if ( access_str == "A" ) - { - region_access = SIM_ACCESS_ADULT; - } - else if ( access_str == "M" ) - { - region_access = SIM_ACCESS_MATURE; - } - else if ( access_str == "PG" ) - { - region_access = SIM_ACCESS_PG; - } - } - - pos.setVec((F32)e[2], (F32)e[3], (F32)e[4]); - look_at.setVec((F32)e[5], (F32)e[6], (F32)e[7]); - - region_handle = to_region_handle(e[0], e[1]); - return true; -} - -// Strip out "Resident" for display, but only if the message came from a user -// (rather than a script) -static std::string clean_name_from_im(const std::string& name, EInstantMessage type) -{ - switch(type) - { - case IM_NOTHING_SPECIAL: - case IM_MESSAGEBOX: - case IM_GROUP_INVITATION: - case IM_INVENTORY_OFFERED: - case IM_INVENTORY_ACCEPTED: - case IM_INVENTORY_DECLINED: - case IM_GROUP_VOTE: - case IM_GROUP_MESSAGE_DEPRECATED: - //IM_TASK_INVENTORY_OFFERED - //IM_TASK_INVENTORY_ACCEPTED - //IM_TASK_INVENTORY_DECLINED - case IM_NEW_USER_DEFAULT: - case IM_SESSION_INVITE: - case IM_SESSION_P2P_INVITE: - case IM_SESSION_GROUP_START: - case IM_SESSION_CONFERENCE_START: - case IM_SESSION_SEND: - case IM_SESSION_LEAVE: - //IM_FROM_TASK - case IM_BUSY_AUTO_RESPONSE: - case IM_CONSOLE_AND_CHAT_HISTORY: - case IM_LURE_USER: - case IM_LURE_ACCEPTED: - case IM_LURE_DECLINED: - case IM_GODLIKE_LURE_USER: - case IM_TELEPORT_REQUEST: - case IM_GROUP_ELECTION_DEPRECATED: - //IM_GOTO_URL - //IM_FROM_TASK_AS_ALERT - case IM_GROUP_NOTICE: - case IM_GROUP_NOTICE_INVENTORY_ACCEPTED: - case IM_GROUP_NOTICE_INVENTORY_DECLINED: - case IM_GROUP_INVITATION_ACCEPT: - case IM_GROUP_INVITATION_DECLINE: - case IM_GROUP_NOTICE_REQUESTED: - case IM_FRIENDSHIP_OFFERED: - case IM_FRIENDSHIP_ACCEPTED: - case IM_FRIENDSHIP_DECLINED_DEPRECATED: - case IM_TYPING_START: - //IM_TYPING_STOP - return LLCacheName::cleanFullName(name); - default: - return name; - } -} - -static std::string clean_name_from_task_im(const std::string& msg, - BOOL from_group) -{ - boost::smatch match; - static const boost::regex returned_exp( - "(.*been returned to your inventory lost and found folder by )(.+)( (from|near).*)"); - if (boost::regex_match(msg, match, returned_exp)) - { - // match objects are 1-based for groups - std::string final = match[1].str(); - std::string name = match[2].str(); - // Don't try to clean up group names - if (!from_group) - { - if (LLAvatarNameCache::useDisplayNames()) - { - // ...just convert to username - final += LLCacheName::buildUsername(name); - } - else - { - // ...strip out legacy "Resident" name - final += LLCacheName::cleanFullName(name); - } - } - final += match[3].str(); - return final; - } - return msg; -} - -void notification_display_name_callback(const LLUUID& id, - const LLAvatarName& av_name, - const std::string& name, - LLSD& substitutions, - const LLSD& payload) -{ - substitutions["NAME"] = av_name.mDisplayName; - LLNotificationsUtil::add(name, substitutions, payload); -} - -// Callback for name resolution of a god/estate message -void god_message_name_cb(const LLAvatarName& av_name, LLChat chat, std::string message) -{ - std::string name; - LLAvatarNameCache::getPNSName(av_name, name); - LLSD args; - args["NAME"] = name; - args["MESSAGE"] = message; - LLNotificationsUtil::add("GodMessage", args); - - // Treat like a system message and put in chat history. - chat.mText = name + ": " + message; - - // Claim to be from a local agent so it doesn't go into console. - LLFloaterChat::addChat(chat, false, true); - -} - -// Replace wild cards in autoresponse messages -std::string replace_wildcards(std::string autoresponse, const LLUUID& id, const std::string& name) -{ - // Add in their legacy name - boost::algorithm::replace_all(autoresponse, "#n", name); - - LLSLURL slurl; - LLAgentUI::buildSLURL(slurl); - - // Add in our location's slurl - boost::algorithm::replace_all(autoresponse, "#r", slurl.getSLURLString()); - - // Add in their display name - LLAvatarName av_name; - boost::algorithm::replace_all(autoresponse, "#d", LLAvatarNameCache::get(id, &av_name) ? av_name.mDisplayName : name); - - if (!isAgentAvatarValid()) return autoresponse; - // Add in idle time - LLStringUtil::format_map_t args; - args["[MINS]"] = boost::lexical_cast(gAgentAvatarp->mIdleTimer.getElapsedTimeF32()/60); - boost::algorithm::replace_all(autoresponse, "#i", LLTrans::getString("IM_autoresponse_minutes", args)); - - return autoresponse; -} - -void process_improved_im(LLMessageSystem *msg, void **user_data) -{ - if (gNoRender) - { - return; - } - LLUUID from_id; - BOOL from_group; - LLUUID to_id; - U8 offline; - U8 d = 0; - LLUUID session_id; - U32 timestamp; - std::string name; - std::string message; - U32 parent_estate_id = 0; - LLUUID region_id; - LLVector3 position; - U8 binary_bucket[MTUBYTES]; - S32 binary_bucket_size; - LLChat chat; - std::string buffer; - - // *TODO: Translate - need to fix the full name to first/last (maybe) - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, from_id); - msg->getBOOLFast(_PREHASH_MessageBlock, _PREHASH_FromGroup, from_group); - msg->getUUIDFast(_PREHASH_MessageBlock, _PREHASH_ToAgentID, to_id); - msg->getU8Fast( _PREHASH_MessageBlock, _PREHASH_Offline, offline); - msg->getU8Fast( _PREHASH_MessageBlock, _PREHASH_Dialog, d); - msg->getUUIDFast(_PREHASH_MessageBlock, _PREHASH_ID, session_id); - msg->getU32Fast( _PREHASH_MessageBlock, _PREHASH_Timestamp, timestamp); - //msg->getData("MessageBlock", "Count", &count); - msg->getStringFast(_PREHASH_MessageBlock, _PREHASH_FromAgentName, name); - msg->getStringFast(_PREHASH_MessageBlock, _PREHASH_Message, message); - // NaCl - Newline flood protection - static LLCachedControl AntiSpamEnabled(gSavedSettings,"AntiSpamEnabled",false); - if (AntiSpamEnabled && can_block(from_id)) - { - static LLCachedControl SpamNewlines(gSavedSettings,"_NACL_AntiSpamNewlines"); - boost::sregex_iterator iter(message.begin(), message.end(), NEWLINES); - if((U32)std::abs(std::distance(iter, boost::sregex_iterator())) > SpamNewlines) - { - NACLAntiSpamRegistry::blockOnQueue((U32)NACLAntiSpamRegistry::QUEUE_IM,from_id); - llinfos << "[antispam] blocked owner due to too many newlines: " << from_id << llendl; - if(gSavedSettings.getBOOL("AntiSpamNotify")) - { - LLSD args; - args["SOURCE"] = from_id.asString(); - args["AMOUNT"] = boost::lexical_cast(SpamNewlines); - LLNotificationsUtil::add("AntiSpamNewlineFlood", args); - } - return; - } - } - // NaCl End - msg->getU32Fast(_PREHASH_MessageBlock, _PREHASH_ParentEstateID, parent_estate_id); - msg->getUUIDFast(_PREHASH_MessageBlock, _PREHASH_RegionID, region_id); - msg->getVector3Fast(_PREHASH_MessageBlock, _PREHASH_Position, position); - msg->getBinaryDataFast( _PREHASH_MessageBlock, _PREHASH_BinaryBucket, binary_bucket, 0, 0, MTUBYTES); - binary_bucket_size = msg->getSizeFast(_PREHASH_MessageBlock, _PREHASH_BinaryBucket); - EInstantMessage dialog = (EInstantMessage)d; - - // NaCl - Antispam Registry - if((dialog != IM_TYPING_START && dialog != IM_TYPING_STOP) - && NACLAntiSpamRegistry::checkQueue((U32)NACLAntiSpamRegistry::QUEUE_IM,from_id)) - return; - // NaCl End - - // make sure that we don't have an empty or all-whitespace name - LLStringUtil::trim(name); - if (name.empty()) - { - name = LLTrans::getString("Unnamed"); - } - - // Preserve the unaltered name for use in group notice mute checking. - std::string original_name = name; - - // IDEVO convert new-style "Resident" names for display - name = clean_name_from_im(name, dialog); - - // - if (region_id.notNull()) - llinfos << "RegionID: " << region_id.asString() << llendl; - // - - BOOL is_busy = gAgent.getBusy(); - BOOL is_muted = LLMuteList::getInstance()->isMuted(from_id, name, LLMute::flagTextChat) - // object IMs contain sender object id in session_id (STORM-1209) - || dialog == IM_FROM_TASK && LLMuteList::getInstance()->isMuted(session_id); - BOOL is_linden = LLMuteList::getInstance()->isLinden(name); - BOOL is_owned_by_me = FALSE; - BOOL is_friend = (LLAvatarTracker::instance().getBuddyInfo(from_id) == NULL) ? false : true; - BOOL accept_im_from_only_friend = gSavedSettings.getBOOL("InstantMessagesFriendsOnly"); - - LLUUID computed_session_id = LLIMMgr::computeSessionID(dialog,from_id); - - chat.mMuted = is_muted && !is_linden; - chat.mFromID = from_id; - chat.mFromName = name; - chat.mSourceType = (from_id.isNull() || (name == std::string(SYSTEM_FROM))) ? CHAT_SOURCE_SYSTEM : CHAT_SOURCE_AGENT; - - if(chat.mSourceType == CHAT_SOURCE_AGENT) - { - LLSD args; - args["NAME"] = name; - } - - LLViewerObject *source = gObjectList.findObject(session_id); //Session ID is probably the wrong thing. - if (source || (source = gObjectList.findObject(from_id))) - { - is_owned_by_me = source->permYouOwner(); - } - - // NaCl - Antispam - if (is_spam_filtered(dialog, is_friend, is_owned_by_me)) return; - // NaCl End - - std::string separator_string(": "); - int message_offset = 0; - - //Handle IRC styled /me messages. - std::string prefix = message.substr(0, 4); - if (prefix == "/me " || prefix == "/me'") - { - chat.mChatStyle = CHAT_STYLE_IRC; - separator_string = ""; - message_offset = 3; - } - - // These bools are here because they would make mess of logic down below in IM_NOTHING_SPECIAL. - bool is_autorespond = !is_muted && (is_friend || !gSavedPerAccountSettings.getBOOL("AutoresponseAnyoneFriendsOnly")) && gSavedPerAccountSettings.getBOOL("AutoresponseAnyone"); - bool is_autorespond_muted = is_muted && gSavedPerAccountSettings.getBOOL("AutoresponseMuted"); - bool is_autorespond_nonfriends = !is_friend && !is_muted && gSavedPerAccountSettings.getBOOL("AutoresponseNonFriends"); - - LLSD args; - switch(dialog) - { - case IM_CONSOLE_AND_CHAT_HISTORY: - args["MESSAGE"] = message; - - // Note: don't put the message in the IM history, even though was sent - // via the IM mechanism. - LLNotificationsUtil::add("SystemMessageTip",args); - break; - - case IM_NOTHING_SPECIAL: - // Don't show dialog, just do IM - if (!gAgent.isGodlike() - && gAgent.getRegion()->isPrelude() - && to_id.isNull() ) - { - // do nothing -- don't distract newbies in - // Prelude with global IMs - } -// [RLVa:KB] - Checked: 2011-05-28 (RLVa-1.4.0a) | Modified: RLVa-1.4.0a - else if ( (rlv_handler_t::isEnabled()) && (offline == IM_ONLINE) && ("@version" == message) && - (!is_muted) && ((!accept_im_from_only_friend) || (is_friend)) ) - { - RlvUtil::sendBusyMessage(from_id, RlvStrings::getVersion(), session_id); - // We won't receive a typing stop message, so do that manually (see comment at the end of LLFloaterIMPanel::sendMsg) - LLPointer im_info = new LLIMInfo(gMessageSystem); - gIMMgr->processIMTypingStop(im_info); - } -// [/RLVa:KB] -// else if (offline == IM_ONLINE && !is_linden && is_busy && name != SYSTEM_FROM) -// [RLVa:KB] - Checked: 2010-11-30 (RLVa-1.3.0c) | Modified: RLVa-1.3.0c - else if ( (offline == IM_ONLINE && !is_linden && is_busy && name != SYSTEM_FROM) && (gRlvHandler.canReceiveIM(from_id)) ) -// [/RLVa:KB] - { - // return a standard "busy" message, but only do it to online IM - // (i.e. not other auto responses and not store-and-forward IM) - if (!gIMMgr->hasSession(session_id) || gSavedPerAccountSettings.getBOOL("AscentInstantMessageResponseRepeat")) - { - // if the user wants to repeat responses over and over or - // if there is not a panel for this conversation (i.e. it is a new IM conversation - // initiated by the other party) then... - if (to_id.notNull()) busy_message(msg, from_id); - } - - // now store incoming IM in chat history - buffer = separator_string + message.substr(message_offset); - - LL_INFOS("Messaging") << "process_improved_im: session_id( " << session_id << " ), from_id( " << from_id << " )" << LL_ENDL; - // add to IM panel, but do not bother the user - gIMMgr->addMessage( - session_id, - from_id, - name, - buffer, - name, - dialog, - parent_estate_id, - region_id, - position, - true); - - // pretend this is chat generated by self, so it does not show up on screen - chat.mText = std::string("IM: ") + name + separator_string + message.substr(message_offset); - LLFloaterChat::addChat(chat, true, true); - } -// else if (to_id.notNull() && offline == IM_ONLINE && !is_linden && (is_autorespond || is_autorespond_nonfriends || is_autorespond_muted) && name != SYSTEM_FROM) -// [RLVa:LF] - Same as above: Checked: 2010-11-30 (RLVa-1.3.0c) | Modified: RLVa-1.3.0c - else if (to_id.notNull() && offline == IM_ONLINE && !is_linden && (is_autorespond || is_autorespond_nonfriends || is_autorespond_muted) && name != SYSTEM_FROM && gRlvHandler.canReceiveIM(from_id)) -// [/RLVa:LF] - { - // now store incoming IM in chat history - - buffer = separator_string + message.substr(message_offset); - - LL_INFOS("Messaging") << "process_improved_im: session_id( " << session_id << " ), from_id( " << from_id << " )" << LL_ENDL; - bool send_autoresponse = !gIMMgr->hasSession(session_id) || gSavedPerAccountSettings.getBOOL("AscentInstantMessageResponseRepeat"); - - // add to IM panel, but do not bother the user - gIMMgr->addMessage( - session_id, - from_id, - name, - buffer, - name, - dialog, - parent_estate_id, - region_id, - position, - true); - - // pretend this is chat generated by self, so it does not show up on screen - chat.mText = std::string("IM: ") + name + separator_string + message.substr(message_offset); - LLFloaterChat::addChat( chat, TRUE, TRUE ); - - // return a standard "busy" message, but only do it to online IM - // (i.e. not other auto responses and not store-and-forward IM) - if (send_autoresponse) - { - // if there is not a panel for this conversation (i.e. it is a new IM conversation - // initiated by the other party) then... - std::string my_name; - LLAgentUI::buildFullname(my_name); - std::string response; - bool show_autoresponded = false; - LLUUID itemid; - if (is_muted) - { - response = gSavedPerAccountSettings.getString("AutoresponseMutedMessage"); - if (gSavedPerAccountSettings.getBOOL("AutoresponseMutedItem")) - itemid = static_cast(gSavedPerAccountSettings.getString("AutoresponseMutedItemID")); - // We don't show that we've responded to mutes - } - else if (is_autorespond_nonfriends) - { - response = gSavedPerAccountSettings.getString("AutoresponseNonFriendsMessage"); - if (gSavedPerAccountSettings.getBOOL("AutoresponseNonFriendsItem")) - itemid = static_cast(gSavedPerAccountSettings.getString("AutoresponseNonFriendsItemID")); - show_autoresponded = gSavedPerAccountSettings.getBOOL("AutoresponseNonFriendsShow"); - } - else if (is_autorespond) - { - response = gSavedPerAccountSettings.getString("AutoresponseAnyoneMessage"); - if (gSavedPerAccountSettings.getBOOL("AutoresponseAnyoneItem")) - itemid = static_cast(gSavedPerAccountSettings.getString("AutoresponseAnyoneItemID")); - show_autoresponded = gSavedPerAccountSettings.getBOOL("AutoresponseAnyoneShow"); - } - pack_instant_message( - gMessageSystem, - gAgentID, - FALSE, - gAgent.getSessionID(), - from_id, - my_name, - replace_wildcards(response, from_id, name), - IM_ONLINE, - IM_BUSY_AUTO_RESPONSE, - session_id); - gAgent.sendReliableMessage(); - - std::string pns_name; - if (!LLAvatarNameCache::getPNSName(from_id, pns_name)) pns_name = name; - if (show_autoresponded) - { - gIMMgr->addMessage(session_id, from_id, name, LLTrans::getString("IM_autoresponded_to") + " " + pns_name); - } - if (LLViewerInventoryItem* item = gInventory.getItem(itemid)) - { - LLGiveInventory::doGiveInventoryItem(from_id, item, computed_session_id); - if (show_autoresponded) - { - gIMMgr->addMessage(computed_session_id, from_id, name, - llformat("%s %s \"%s\"", pns_name.c_str(), LLTrans::getString("IM_autoresponse_sent_item").c_str(), item->getName().c_str())); - } - } - } - // We stored the incoming IM in history before autoresponding, logically. - } - else if (from_id.isNull()) - { - // Messages from "Second Life" ID don't go to IM history - // messages which should be routed to IM window come from a user ID with name=SYSTEM_NAME - chat.mText = name + ": " + message; - LLFloaterChat::addChat(chat, FALSE, FALSE); - } - else if (to_id.isNull()) - { - // Message to everyone from GOD, look up the fullname since - // server always slams name to legacy names - LLAvatarNameCache::get(from_id, boost::bind(god_message_name_cb, _2, chat, message)); - } - else - { - // standard message, not from system - bool mute_im = is_muted; - if(accept_im_from_only_friend&&!is_friend) - { - mute_im = true; - } - -// [RLVa:KB] - Checked: 2010-11-30 (RLVa-1.3.0c) | Modified: RLVa-1.3.0c - // Don't block offline IMs, or IMs from Lindens - if ( (rlv_handler_t::isEnabled()) && (offline != IM_OFFLINE) && (!is_linden) && (!gRlvHandler.canReceiveIM(from_id)) ) - { - if (!mute_im) - RlvUtil::sendBusyMessage(from_id, RlvStrings::getString(RLV_STRING_BLOCKED_RECVIM_REMOTE), session_id); - message = message.substr(0, message_offset) + RlvStrings::getString(RLV_STRING_BLOCKED_RECVIM); - } -// [/RLVa:KB] - - std::string saved; - if(offline == IM_OFFLINE) - { - LLStringUtil::format_map_t args; - args["[LONG_TIMESTAMP]"] = formatted_time(timestamp); - saved = LLTrans::getString("Saved_message", args); - } - buffer = separator_string + saved + message.substr(message_offset); - - LL_INFOS("Messaging") << "process_improved_im: session_id( " << session_id << " ), from_id( " << from_id << " )" << LL_ENDL; - -/* - bool mute_im = is_muted; - if (accept_im_from_only_friend && !is_friend) - { - if (!gIMMgr->isNonFriendSessionNotified(session_id)) - { - std::string message = LLTrans::getString("IM_unblock_only_groups_friends"); - gIMMgr->addMessage(session_id, from_id, name, message); - gIMMgr->addNotifiedNonFriendSessionID(session_id); - } - - mute_im = true; - } -*/ - if (!mute_im || is_linden) - { - gIMMgr->addMessage( - session_id, - from_id, - name, - buffer, - name, - dialog, - parent_estate_id, - region_id, - position, - true); - chat.mText = std::string("IM: ") + name + separator_string + saved + message.substr(message_offset); - LLFloaterChat::addChat(chat, true, false); - } - else - { - // muted user, so don't start an IM session, just record line in chat - // history. Pretend the chat is from a local agent, - // so it will go into the history but not be shown on screen. - chat.mText = buffer; - LLFloaterChat::addChat(chat, true, true); - - // Autoresponse to muted avatars - if (gSavedPerAccountSettings.getBOOL("AutoresponseMuted")) - { - std::string my_name; - LLAgentUI::buildFullname(my_name); - pack_instant_message( - gMessageSystem, - gAgentID, - FALSE, - gAgent.getSessionID(), - from_id, - my_name, - replace_wildcards(gSavedPerAccountSettings.getString("AutoresponseMutedMessage"), from_id, name), - IM_ONLINE, - IM_BUSY_AUTO_RESPONSE, - session_id); - gAgent.sendReliableMessage(); - if (gSavedPerAccountSettings.getBOOL("AutoresponseMutedItem")) - if (LLViewerInventoryItem* item = gInventory.getItem(static_cast(gSavedPerAccountSettings.getString("AutoresponseMutedItemID")))) - LLGiveInventory::doGiveInventoryItem(from_id, item, computed_session_id); - } - } - } - break; - - case IM_TYPING_START: - { - // Don't announce that someone has started messaging, if they're muted or when in busy mode - if (!is_muted && (!accept_im_from_only_friend || is_friend) && !is_busy && !gIMMgr->hasSession(computed_session_id) && gSavedSettings.getBOOL("AscentInstantMessageAnnounceIncoming")) - { - std::string pns_name; - if (!LLAvatarNameCache::getPNSName(from_id, pns_name)) pns_name = name; - - gIMMgr->addMessage( - computed_session_id, - from_id, - name, - llformat("%s ", pns_name.c_str()) + LLTrans::getString("IM_announce_incoming"), - name, - IM_NOTHING_SPECIAL, - parent_estate_id, - region_id, - position, - false); - - // This block is very similar to the one above, but is necessary, since a session is opened to announce incoming message.. - // In order to prevent doubling up on the first response, We neglect to send this if Repeat for each message is on. - if ((is_autorespond_nonfriends || is_autorespond) && !gSavedPerAccountSettings.getBOOL("AscentInstantMessageResponseRepeat")) - { - std::string my_name; - LLAgentUI::buildFullname(my_name); - std::string response; - bool show_autoresponded = false; - LLUUID itemid; - if (is_autorespond_nonfriends) - { - response = gSavedPerAccountSettings.getString("AutoresponseNonFriendsMessage"); - if (gSavedPerAccountSettings.getBOOL("AutoresponseNonFriendsItem")) - itemid = static_cast(gSavedPerAccountSettings.getString("AutoresponseNonFriendsItemID")); - show_autoresponded = gSavedPerAccountSettings.getBOOL("AutoresponseNonFriendsShow"); - } - else if (is_autorespond) - { - response = gSavedPerAccountSettings.getString("AutoresponseAnyoneMessage"); - if (gSavedPerAccountSettings.getBOOL("AutoresponseAnyoneItem")) - itemid = static_cast(gSavedPerAccountSettings.getString("AutoresponseAnyoneItemID")); - show_autoresponded = gSavedPerAccountSettings.getBOOL("AutoresponseAnyoneShow"); - } - pack_instant_message(gMessageSystem, gAgentID, false, gAgentSessionID, from_id, my_name, replace_wildcards(response, from_id, name), IM_ONLINE, IM_BUSY_AUTO_RESPONSE, session_id); - gAgent.sendReliableMessage(); - - if (show_autoresponded) - { - gIMMgr->addMessage(session_id, from_id, name, LLTrans::getString("IM_autoresponded_to") + " " + pns_name); - } - if (LLViewerInventoryItem* item = gInventory.getItem(itemid)) - { - LLGiveInventory::doGiveInventoryItem(from_id, item, computed_session_id); - if (show_autoresponded) - { - gIMMgr->addMessage(computed_session_id, from_id, name, - llformat("%s %s \"%s\"", pns_name.c_str(), LLTrans::getString("IM_autoresponse_sent_item").c_str(), item->getName().c_str())); - } - } - } - } - LLPointer im_info = new LLIMInfo(gMessageSystem); - gIMMgr->processIMTypingStart(im_info); - } - break; - - case IM_TYPING_STOP: - { - LLPointer im_info = new LLIMInfo(gMessageSystem); - gIMMgr->processIMTypingStop(im_info); - } - break; - - case IM_MESSAGEBOX: - { - // This is a block, modeless dialog. - //*TODO: Translate - args["MESSAGE"] = message; - LLNotificationsUtil::add("SystemMessageTip", args); - } - break; - case IM_GROUP_NOTICE: - case IM_GROUP_NOTICE_REQUESTED: - { - LL_INFOS("Messaging") << "Received IM_GROUP_NOTICE message." << LL_ENDL; - // Read the binary bucket for more information. - struct notice_bucket_header_t - { - U8 has_inventory; - U8 asset_type; - LLUUID group_id; - }; - struct notice_bucket_full_t - { - struct notice_bucket_header_t header; - U8 item_name[DB_INV_ITEM_NAME_BUF_SIZE]; - }* notice_bin_bucket; - - // Make sure the binary bucket is big enough to hold the header - // and a null terminated item name. - if ( (binary_bucket_size < (S32)((sizeof(notice_bucket_header_t) + sizeof(U8)))) - || (binary_bucket[binary_bucket_size - 1] != '\0') ) - { - LL_WARNS("Messaging") << "Malformed group notice binary bucket" << LL_ENDL; - break; - } - - // The group notice packet does not have an AgentID. Obtain one from the name cache. - // If last name is "Resident" strip it out so the cache name lookup works. - U32 index = original_name.find(" Resident"); - if (index != std::string::npos) - { - original_name = original_name.substr(0, index); - } - std::string legacy_name = gCacheName->buildLegacyName(original_name); - LLUUID agent_id; - gCacheName->getUUID(legacy_name, agent_id); - - if (agent_id.isNull()) - { - LL_WARNS("Messaging") << "buildLegacyName returned null while processing " << original_name << LL_ENDL; - } - else if (LLMuteList::getInstance()->isMuted(agent_id)) - { - break; - } - - notice_bin_bucket = (struct notice_bucket_full_t*) &binary_bucket[0]; - U8 has_inventory = notice_bin_bucket->header.has_inventory; - U8 asset_type = notice_bin_bucket->header.asset_type; - LLUUID group_id = notice_bin_bucket->header.group_id; - std::string item_name = ll_safe_string((const char*) notice_bin_bucket->item_name); - - // If there is inventory, give the user the inventory offer. - LLOfferInfo* info = NULL; - - if (has_inventory) - { - info = new LLOfferInfo(); - - info->mIM = IM_GROUP_NOTICE; - info->mFromID = from_id; - info->mFromGroup = from_group; - info->mTransactionID = session_id; - info->mType = (LLAssetType::EType) asset_type; - info->mFolderID = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(info->mType)); - std::string from_name; - - from_name += LLTrans::getString("AGroupMemberNamed") + " "; - from_name += name; - - info->mFromName = from_name; - info->mDesc = item_name; - info->mHost = msg->getSender(); - } - - std::string str(message); - - // Tokenize the string. - // TODO: Support escaped tokens ("||" -> "|") - typedef boost::tokenizer > tokenizer; - boost::char_separator sep("|","",boost::keep_empty_tokens); - tokenizer tokens(str, sep); - tokenizer::iterator iter = tokens.begin(); - - std::string subj(*iter++); - std::string mes(*iter++); - - // Send the notification down the new path. - // For requested notices, we don't want to send the popups. - if (dialog != IM_GROUP_NOTICE_REQUESTED) - { - LLSD payload; - payload["subject"] = subj; - payload["message"] = mes; - payload["sender_name"] = name; - payload["group_id"] = group_id; - payload["inventory_name"] = item_name; - payload["inventory_offer"] = info ? info->asLLSD() : LLSD(); - - LLSD args; - args["SUBJECT"] = subj; - args["MESSAGE"] = mes; - LLNotifications::instance().add(LLNotification::Params("GroupNotice").substitutions(args).payload(payload).timestamp(timestamp)); - } - - // Also send down the old path for now. - if (IM_GROUP_NOTICE_REQUESTED == dialog) - { - LLGroupActions::showNotice(subj,mes,group_id,has_inventory,item_name,info); - } - else - { - delete info; - } - } - break; - case IM_GROUP_INVITATION: - { - //if (!is_linden && (is_busy || is_muted)) - if ((is_busy || is_muted)) - { - LLMessageSystem *msg = gMessageSystem; - busy_message(msg,from_id); - } - else - { - LL_INFOS("Messaging") << "Received IM_GROUP_INVITATION message." << LL_ENDL; - // Read the binary bucket for more information. - struct invite_bucket_t - { - S32 membership_fee; - LLUUID role_id; - }* invite_bucket; - - // Make sure the binary bucket is the correct size. - if (binary_bucket_size != sizeof(invite_bucket_t)) - { - LL_WARNS("Messaging") << "Malformed group invite binary bucket" << LL_ENDL; - break; - } - - invite_bucket = (struct invite_bucket_t*) &binary_bucket[0]; - S32 membership_fee = ntohl(invite_bucket->membership_fee); - // NaCl - Antispam - if (membership_fee > 0 && gSavedSettings.getBOOL("AntiSpamGroupFeeInvites")) - return; - // NaCl End - - LLSD payload; - payload["transaction_id"] = session_id; - payload["group_id"] = from_id; - payload["name"] = name; - payload["message"] = message; - payload["fee"] = membership_fee; - - LLSD args; - args["MESSAGE"] = message; - // we shouldn't pass callback functor since it is registered in LLFunctorRegistration - LLNotificationsUtil::add("JoinGroup", args, payload); - } - } - break; - - case IM_INVENTORY_OFFERED: - case IM_TASK_INVENTORY_OFFERED: - // Someone has offered us some inventory. - { - LLOfferInfo* info = new LLOfferInfo; - if (IM_INVENTORY_OFFERED == dialog) - { - struct offer_agent_bucket_t - { - S8 asset_type; - LLUUID object_id; - }* bucketp; - - if (sizeof(offer_agent_bucket_t) != binary_bucket_size) - { - LL_WARNS("Messaging") << "Malformed inventory offer from agent" << LL_ENDL; - delete info; - break; - } - bucketp = (struct offer_agent_bucket_t*) &binary_bucket[0]; - info->mType = (LLAssetType::EType) bucketp->asset_type; - info->mObjectID = bucketp->object_id; - info->mFromObject = FALSE; - } - else // IM_TASK_INVENTORY_OFFERED - { - if (sizeof(S8) != binary_bucket_size) - { - LL_WARNS("Messaging") << "Malformed inventory offer from object" << LL_ENDL; - delete info; - break; - } - info->mType = (LLAssetType::EType) binary_bucket[0]; - info->mObjectID = LLUUID::null; - info->mFromObject = TRUE; - } - - info->mIM = dialog; - info->mFromID = from_id; - info->mFromGroup = from_group; - info->mTransactionID = session_id; - info->mFolderID = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(info->mType)); - - info->mFromName = name; - info->mDesc = message; - info->mHost = msg->getSender(); - //if (((is_busy && !is_owned_by_me) || is_muted)) - if (is_muted) - { - // Prefetch the offered item so that it can be discarded by the appropriate observer. (EXT-4331) - LLInventoryFetchItemsObserver* fetch_item = new LLInventoryFetchItemsObserver(info->mObjectID); - fetch_item->startFetch(); - delete fetch_item; - - // Same as closing window - info->forceResponse(IOR_DECLINE); - } - /* Singu Note: Handle this inside inventory_offer_handler so if the user wants to autoaccept offers, they can while busy. - else if (is_busy && dialog != IM_TASK_INVENTORY_OFFERED) // busy mode must not affect interaction with objects (STORM-565) - { - // Until throttling is implemented, busy mode should reject inventory instead of silently - // accepting it. SEE SL-39554 - info->forceResponse(IOR_DECLINE); - } - */ - else - { - inventory_offer_handler(info); - } - } - break; - - case IM_INVENTORY_ACCEPTED: - { -// args["NAME"] = name; -// [RLVa:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a - // Only anonymize the name if the agent is nearby, there isn't an open IM session to them and their profile isn't open - bool fRlvFilterName = (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (RlvUtil::isNearbyAgent(from_id)) && - (!RlvUIEnabler::hasOpenProfile(from_id)) && (!RlvUIEnabler::hasOpenIM(from_id)); - args["NAME"] = (!fRlvFilterName) ? name : RlvStrings::getAnonym(name); -// [/RLVa:KB] - LLNotificationsUtil::add("InventoryAccepted", args); - break; - } - case IM_INVENTORY_DECLINED: - { -// args["NAME"] = name; -// [RLVa:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a - // Only anonymize the name if the agent is nearby, there isn't an open IM session to them and their profile isn't open - bool fRlvFilterName = (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (RlvUtil::isNearbyAgent(from_id)) && - (!RlvUIEnabler::hasOpenProfile(from_id)) && (!RlvUIEnabler::hasOpenIM(from_id)); - args["NAME"] = (!fRlvFilterName) ? name : RlvStrings::getAnonym(name); -// [/RLVa:KB] - LLNotificationsUtil::add("InventoryDeclined", args); - break; - } - case IM_GROUP_VOTE: - { - LLSD args; - args["NAME"] = name; - args["MESSAGE"] = message; - - LLSD payload; - payload["group_id"] = session_id; - LLNotificationsUtil::add("GroupVote", args, payload); - } - break; - - case IM_GROUP_ELECTION_DEPRECATED: - { - LL_WARNS("Messaging") << "Received IM: IM_GROUP_ELECTION_DEPRECATED" << LL_ENDL; - } - break; - - case IM_SESSION_SEND: - { - if (!is_linden && is_busy) - { - return; - } - - // Only show messages if we have a session open (which - // should happen after you get an "invitation" -// if ( !gIMMgr->hasSession(session_id) ) -// { -// return; -// } -// [RLVa:KB] - Checked: 2010-11-30 (RLVa-1.3.0c) | Modified: RLVa-1.3.0c - LLFloaterIMPanel* pIMFloater = gIMMgr->findFloaterBySession(session_id); - if (!pIMFloater) - { - return; - } - - if ( (gRlvHandler.hasBehaviour(RLV_BHVR_RECVIM)) || (gRlvHandler.hasBehaviour(RLV_BHVR_RECVIMFROM)) ) - { - switch (pIMFloater->mSessionType) - { - case LLFloaterIMPanel::GROUP_SESSION: // Group chat - if ( (from_id != gAgent.getID()) && (!gRlvHandler.canReceiveIM(session_id)) ) - return; - break; - case LLFloaterIMPanel::ADHOC_SESSION: // Conference chat - if ( (from_id != gAgent.getID()) && (!gRlvHandler.canReceiveIM(from_id)) ) - message = RlvStrings::getString(RLV_STRING_BLOCKED_RECVIM); - break; - default: - RLV_ASSERT(false); - return; - } - } -// [/RLVa:KB] - - // standard message, not from system - std::string saved; - if(offline == IM_OFFLINE) - { - LLStringUtil::format_map_t args; - args["[LONG_TIMESTAMP]"] = formatted_time(timestamp); - saved = LLTrans::getString("Saved_message", args); - } - buffer = separator_string + saved + message.substr(message_offset); - gIMMgr->addMessage( - session_id, - from_id, - name, - buffer, - ll_safe_string((char*)binary_bucket), - IM_SESSION_INVITE, - parent_estate_id, - region_id, - position, - true); - - std::string prepend_msg; - if (gAgent.isInGroup(session_id)&& gSavedSettings.getBOOL("OptionShowGroupNameInChatIM")) - { - prepend_msg = "["; - prepend_msg += std::string((char*)binary_bucket); - prepend_msg += "] "; - } - else - { - prepend_msg = std::string("IM: "); - } - chat.mText = prepend_msg + name + separator_string + saved + message.substr(message_offset); - LLFloaterChat::addChat(chat, TRUE, from_id == gAgentID); - } - break; - - case IM_FROM_TASK: - { - if (is_busy && !is_owned_by_me) - { - return; - } - chat.mText = name + separator_string + message.substr(message_offset); - chat.mFromName = name; - - // Build a link to open the object IM info window. - std::string location = ll_safe_string((char*)binary_bucket, binary_bucket_size); - - if (session_id.notNull()) - { - chat.mFromID = session_id; - } - else - { - // This message originated on a region without the updated code for task id and slurl information. - // We just need a unique ID for this object that isn't the owner ID. - // If it is the owner ID it will overwrite the style that contains the link to that owner's profile. - // This isn't ideal - it will make 1 style for all objects owned by the the same person/group. - // This works because the only thing we can really do in this case is show the owner name and link to their profile. - chat.mFromID = from_id ^ gAgent.getSessionID(); - } - - chat.mSourceType = CHAT_SOURCE_OBJECT; - - // To conclude that the source type of message is CHAT_SOURCE_SYSTEM it's not - // enough to check only from name (i.e. fromName = "Second Life"). For example - // source type of messages from objects called "Second Life" should not be CHAT_SOURCE_SYSTEM. - bool chat_from_system = (SYSTEM_FROM == name) && region_id.isNull() && position.isNull(); - if(chat_from_system) - { - // System's UUID is NULL (fixes EXT-4766) - chat.mFromID = LLUUID::null; - chat.mSourceType = CHAT_SOURCE_SYSTEM; - } - - // IDEVO Some messages have embedded resident names - message = clean_name_from_task_im(message, from_group); - - LLSD query_string; - query_string["owner"] = from_id; -// [RLVa:KB] - Checked: 2010-04-22 (RLVa-1.2.0f) | Added: RLVa-1.2.0f - if (rlv_handler_t::isEnabled()) - { - // NOTE: the chat message itself will be filtered in LLNearbyChatHandler::processChat() - if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (!from_group) && (RlvUtil::isNearbyAgent(from_id)) ) - { - query_string["rlv_shownames"] = TRUE; - - RlvUtil::filterNames(name); - chat.mFromName = name; - } - if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) - { - std::string::size_type idxPos = location.find('/'); - if ( (std::string::npos != idxPos) && (RlvUtil::isNearbyRegion(location.substr(0, idxPos))) ) - location = RlvStrings::getString(RLV_STRING_HIDDEN_REGION); - } - } -// [/RLVa:KB] - query_string["slurl"] = location; - query_string["name"] = name; - if (from_group) - { - query_string["groupowned"] = "true"; - } - -// chat.mURL = LLSLURL("objectim", session_id, "").getSLURLString(); -// [SL:KB] - Checked: 2010-11-02 (RLVa-1.2.2a) | Added: RLVa-1.2.2a - chat.mURL = LLSLURL("objectim", session_id, LLURI::mapToQueryString(query_string)).getSLURLString(); -// [/SL:KB] - chat.mText = name + separator_string + message.substr(message_offset); - - // Note: lie to LLFloaterChat::addChat(), pretending that this is NOT an IM, because - // IMs from objects don't open IM sessions. - LLFloaterChat::addChat(chat, FALSE, FALSE); - } - break; - case IM_FROM_TASK_AS_ALERT: - if (is_busy && !is_owned_by_me) - { - return; - } - { - // Construct a viewer alert for this message. - args["NAME"] = name; - args["MESSAGE"] = message; - LLNotificationsUtil::add("ObjectMessage", args); - } - break; - case IM_BUSY_AUTO_RESPONSE: - if (is_muted) - { - LL_DEBUGS("Messaging") << "Ignoring busy response from " << from_id << LL_ENDL; - return; - } - else - { - // TODO: after LLTrans hits release, get "busy response" into translatable file - buffer = llformat("%s (%s): %s", name.c_str(), "busy response", message.substr(message_offset).c_str()); - gIMMgr->addMessage(session_id, from_id, name, buffer); - } - break; - - case IM_LURE_USER: - case IM_TELEPORT_REQUEST: - { -// [RLVa:KB] - Checked: 2010-12-11 (RLVa-1.2.2c) | Added: RLVa-1.2.2c - // If the lure sender is a specific @accepttp exception they will override muted and busy status - bool fRlvSummon = (rlv_handler_t::isEnabled()) && (gRlvHandler.isException(RLV_BHVR_ACCEPTTP, from_id)); -// [/RLVa:KB] - -// if (is_muted) -// [RLVa:KB] - Checked: 2010-12-11 (RLVa-1.2.2c) | Added: RLVa-1.2.2c - if ( (is_muted) && (!fRlvSummon) ) -// [/RLVa:KB] - { - return; - } -// else if (is_busy) -// [RLVa:KB] - Checked: 2010-12-11 (RLVa-1.2.2c) | Added: RLVa-1.2.2c - else if ( (is_busy) && (!fRlvSummon) ) -// [/RLVa:KB] - { - busy_message(msg,from_id); - } - else - { - LLVector3 pos, look_at; - U64 region_handle(0); - U8 region_access(SIM_ACCESS_MIN); - std::string region_info = ll_safe_string((char*)binary_bucket, binary_bucket_size); - std::string region_access_str = LLStringUtil::null; - std::string region_access_icn = LLStringUtil::null; - std::string region_access_lc = LLStringUtil::null; - - bool canUserAccessDstRegion = true; - bool doesUserRequireMaturityIncrease = false; - - // Do not parse the (empty) lure bucket for TELEPORT_REQUEST - if (IM_TELEPORT_REQUEST != dialog && parse_lure_bucket(region_info, region_handle, pos, look_at, region_access)) - { - region_access_str = LLViewerRegion::accessToString(region_access); - region_access_icn = LLViewerRegion::getAccessIcon(region_access); - region_access_lc = region_access_str; - LLStringUtil::toLower(region_access_lc); - - if (!gAgent.isGodlike()) - { - switch (region_access) - { - case SIM_ACCESS_MIN : - case SIM_ACCESS_PG : - break; - case SIM_ACCESS_MATURE : - if (gAgent.isTeen()) - { - canUserAccessDstRegion = false; - } - else if (gAgent.prefersPG()) - { - doesUserRequireMaturityIncrease = true; - } - break; - case SIM_ACCESS_ADULT : - if (!gAgent.isAdult()) - { - canUserAccessDstRegion = false; - } - else if (!gAgent.prefersAdult()) - { - doesUserRequireMaturityIncrease = true; - } - break; - default : - llassert(0); - break; - } - } - } - -// [RLVa:KB] - Checked: 2010-12-11 (RLVa-1.2.2c) | Modified: RLVa-1.2.2c - if (rlv_handler_t::isEnabled()) - { - if (IM_TELEPORT_REQUEST != dialog && !gRlvHandler.canTeleportViaLure(from_id)) - { - RlvUtil::sendBusyMessage(from_id, RlvStrings::getString(RLV_STRING_BLOCKED_TPLURE_REMOTE)); - if (is_busy) - busy_message(msg,from_id); - return; - } - - // Censor lure message if: 1) restricted from receiving IMs from the sender, or 2) @showloc=n restricted - if ( (!gRlvHandler.canReceiveIM(from_id)) || (IM_TELEPORT_REQUEST != dialog && gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) ) - { - message = RlvStrings::getString(RLV_STRING_HIDDEN); - } - } -// [/RLVa:KB] - - LLSD args; - // *TODO: Translate -> [FIRST] [LAST] (maybe) - args["NAME"] = name; - args["MESSAGE"] = message; - args["MATURITY_STR"] = region_access_str; - args["MATURITY_ICON"] = region_access_icn; - args["REGION_CONTENT_MATURITY"] = region_access_lc; - LLSD payload; - payload["from_id"] = from_id; - payload["lure_id"] = session_id; - payload["godlike"] = FALSE; - payload["region_maturity"] = region_access; - //LLNotificationsUtil::add("TeleportOffered", args, payload); - -// [RLVa:KB] - Checked: 2010-12-11 (RLVa-1.2.2c) | Modified: RLVa-1.2.2c - if ( IM_TELEPORT_REQUEST != dialog && (rlv_handler_t::isEnabled()) && ((gRlvHandler.hasBehaviour(RLV_BHVR_ACCEPTTP)) || (fRlvSummon)) ) - { - gRlvHandler.setCanCancelTp(false); - if (is_busy) - busy_message(msg,from_id); - LLNotifications::instance().forceResponse(LLNotification::Params("TeleportOffered").payload(payload), 0); - } - else - { - /* Singu Note: No default constructor for LLNotification::Params - LLNotification::Params params; - if (IM_LURE_USER == dialog) - { - params.name = "TeleportOffered"; - params.functor_name = "TeleportOffered"; - } - else if (IM_TELEPORT_REQUEST == dialog) - { - params.name = "TeleportRequest"; - params.functor_name = "TeleportRequest"; - } - */ - LLNotification::Params params(IM_LURE_USER == dialog ? "TeleportOffered" : "TeleportRequest"); - - params.substitutions = args; - params.payload = payload; - LLNotifications::instance().add(params); - // - if (IM_LURE_USER == dialog) - gAgent.showLureDestination(name, region_handle, pos.mV[VX], pos.mV[VY], pos.mV[VZ]); - // - } -// [/RLVa:KB] - //LLNotificationsUtil::add("TeleportOffered", args, payload); - } - } - break; - - case IM_GODLIKE_LURE_USER: + case 0: { - LLVector3 pos, look_at; - U64 region_handle(0); - U8 region_access(SIM_ACCESS_MIN); - std::string region_info = ll_safe_string((char*)binary_bucket, binary_bucket_size); - std::string region_access_str = LLStringUtil::null; - std::string region_access_icn = LLStringUtil::null; - std::string region_access_lc = LLStringUtil::null; - - bool canUserAccessDstRegion = true; - bool doesUserRequireMaturityIncrease = false; - - if (parse_lure_bucket(region_info, region_handle, pos, look_at, region_access)) - { - region_access_str = LLViewerRegion::accessToString(region_access); - region_access_icn = LLViewerRegion::getAccessIcon(region_access); - region_access_lc = region_access_str; - LLStringUtil::toLower(region_access_lc); - - if (!gAgent.isGodlike()) - { - switch (region_access) - { - case SIM_ACCESS_MIN : - case SIM_ACCESS_PG : - break; - case SIM_ACCESS_MATURE : - if (gAgent.isTeen()) - { - canUserAccessDstRegion = false; - } - else if (gAgent.prefersPG()) - { - doesUserRequireMaturityIncrease = true; - } - break; - case SIM_ACCESS_ADULT : - if (!gAgent.isAdult()) - { - canUserAccessDstRegion = false; - } - else if (!gAgent.prefersAdult()) - { - doesUserRequireMaturityIncrease = true; - } - break; - default : - llassert(0); - break; - } - } - } - - LLSD args; - // *TODO: Translate -> [FIRST] [LAST] (maybe) - args["NAME"] = name; - args["MESSAGE"] = message; - args["MATURITY_STR"] = region_access_str; - args["MATURITY_ICON"] = region_access_icn; - args["REGION_CONTENT_MATURITY"] = region_access_lc; - LLSD payload; - payload["from_id"] = from_id; - payload["lure_id"] = session_id; - payload["godlike"] = TRUE; - payload["region_maturity"] = region_access; - - // do not show a message box, because you're about to be - // teleported. - LLNotifications::instance().forceResponse(LLNotification::Params("TeleportOffered").payload(payload), 0); + // accept + gAgent.teleportViaLure(lure_id, godlike); } break; - - case IM_GOTO_URL: - { - LLSD args; - // n.b. this is for URLs sent by the system, not for - // URLs sent by scripts (i.e. llLoadURL) - if (binary_bucket_size <= 0) - { - LL_WARNS("Messaging") << "bad binary_bucket_size: " - << binary_bucket_size - << " - aborting function." << LL_ENDL; - return; - } - - std::string url; - - url.assign((char*)binary_bucket, binary_bucket_size-1); - args["MESSAGE"] = message; - args["URL"] = url; - LLSD payload; - payload["url"] = url; - LLNotificationsUtil::add("GotoURL", args, payload ); - } + case 1: + default: + // decline + send_simple_im(from_id, + LLStringUtil::null, + IM_LURE_DECLINED, + lure_id); break; + } + return false; +} +static LLNotificationFunctorRegistration lure_callback_reg("TeleportOffered", lure_callback); - case IM_FRIENDSHIP_OFFERED: - { - LLSD payload; - payload["from_id"] = from_id; - payload["session_id"] = session_id;; - payload["online"] = (offline == IM_ONLINE); - payload["sender"] = msg->getSender().getIPandPort(); +bool goto_url_callback(const LLSD& notification, const LLSD& response) +{ + std::string url = notification["payload"]["url"].asString(); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if(1 == option) + { + LLWeb::loadURL(url); + } + return false; +} +static LLNotificationFunctorRegistration goto_url_callback_reg("GotoURL", goto_url_callback); - if (is_busy) - { - busy_message(msg, from_id); - LLNotifications::instance().forceResponse(LLNotification::Params("OfferFriendship").payload(payload), 1); - } - else if (is_muted) - { - LLNotifications::instance().forceResponse(LLNotification::Params("OfferFriendship").payload(payload), 1); - } - else +void process_improved_im(LLMessageSystem *msg, void **user_data) +{ + if (gNoRender) + { + return; + } + LLUUID from_id; + BOOL from_group; + LLUUID to_id; + U8 offline; + U8 d = 0; + LLUUID session_id; + U32 timestamp; + std::string agentName; + std::string message; + U32 parent_estate_id = 0; + LLUUID region_id; + LLVector3 position; + U8 binary_bucket[MTUBYTES]; + S32 binary_bucket_size; + + // *TODO: Translate - need to fix the full name to first/last (maybe) + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, from_id); + msg->getBOOLFast(_PREHASH_MessageBlock, _PREHASH_FromGroup, from_group); + msg->getUUIDFast(_PREHASH_MessageBlock, _PREHASH_ToAgentID, to_id); + msg->getU8Fast(_PREHASH_MessageBlock, _PREHASH_Offline, offline); + msg->getU8Fast(_PREHASH_MessageBlock, _PREHASH_Dialog, d); + msg->getUUIDFast(_PREHASH_MessageBlock, _PREHASH_ID, session_id); + msg->getU32Fast(_PREHASH_MessageBlock, _PREHASH_Timestamp, timestamp); + //msg->getData("MessageBlock", "Count", &count); + msg->getStringFast(_PREHASH_MessageBlock, _PREHASH_FromAgentName, agentName); + msg->getStringFast(_PREHASH_MessageBlock, _PREHASH_Message, message); + // NaCl - Newline flood protection + auto antispam = NACLAntiSpamRegistry::getIfExists(); + if (antispam && can_block(from_id)) + { + static const LLCachedControl SpamNewlines("_NACL_AntiSpamNewlines"); + boost::sregex_iterator iter(message.begin(), message.end(), NEWLINES); + if((U32)std::abs(std::distance(iter, boost::sregex_iterator())) > SpamNewlines) + { + antispam->blockOnQueue(NACLAntiSpamRegistry::QUEUE_IM, from_id); + LL_INFOS() << "[antispam] blocked owner due to too many newlines: " << from_id << LL_ENDL; + if (gSavedSettings.getBOOL("AntiSpamNotify")) { - args["[NAME]"] = name; - if(message.empty()) - { - //support for frienship offers from clients before July 2008 - LLNotificationsUtil::add("OfferFriendshipNoMessage", args, payload); - } - else - { - args["[MESSAGE]"] = message; - LLNotificationsUtil::add("OfferFriendship", args, payload); - } + LLSD args; + args["SOURCE"] = from_id; + args["AMOUNT"] = fmt::to_string(SpamNewlines); + LLNotificationsUtil::add("AntiSpamNewlineFlood", args); } + return; } - break; + } + // NaCl End + msg->getU32Fast(_PREHASH_MessageBlock, _PREHASH_ParentEstateID, parent_estate_id); + msg->getUUIDFast(_PREHASH_MessageBlock, _PREHASH_RegionID, region_id); + msg->getVector3Fast(_PREHASH_MessageBlock, _PREHASH_Position, position); + msg->getBinaryDataFast(_PREHASH_MessageBlock, _PREHASH_BinaryBucket, binary_bucket, 0, 0, MTUBYTES); + binary_bucket_size = msg->getSizeFast(_PREHASH_MessageBlock, _PREHASH_BinaryBucket); + EInstantMessage dialog = (EInstantMessage)d; - case IM_FRIENDSHIP_ACCEPTED: - { - // In the case of an offline IM, the formFriendship() may be extraneous - // as the database should already include the relationship. But it - // doesn't hurt for dupes. - LLAvatarTracker::formFriendship(from_id); - - std::vector strings; - strings.push_back(from_id.asString()); - send_generic_message("requestonlinenotification", strings); - - args["NAME"] = name; - LLSD payload; - payload["from_id"] = from_id; - LLAvatarNameCache::get(from_id, boost::bind(¬ification_display_name_callback, - _1, - _2, - "FriendshipAccepted", - args, - payload)); - } - break; + // NaCl - Antispam Registry + if (antispam && (dialog != IM_TYPING_START && dialog != IM_TYPING_STOP) + && antispam->checkQueue(NACLAntiSpamRegistry::QUEUE_IM, from_id)) + return; + // NaCl End - case IM_FRIENDSHIP_DECLINED_DEPRECATED: - default: - LL_WARNS("Messaging") << "Instant message calling for unknown dialog " - << (S32)dialog << LL_ENDL; - break; - } + LLHost sender = msg->getSender(); - LLWindow* viewer_window = gViewerWindow->getWindow(); - if (viewer_window && viewer_window->getMinimized()) - { - viewer_window->flashIcon(5.f); - } + LLIMProcessing::processNewMessage(from_id, + from_group, + to_id, + offline, + dialog, + session_id, + timestamp, + agentName, + message, + parent_estate_id, + region_id, + position, + binary_bucket, + binary_bucket_size, + sender); } -void busy_message (LLMessageSystem* msg, LLUUID from_id) +void send_do_not_disturb_message(LLMessageSystem* msg, const LLUUID& from_id, const LLUUID& session_id) { - if (gAgent.getBusy()) + if (gAgent.isDoNotDisturb()) { std::string my_name; LLAgentUI::buildFullname(my_name); - std::string from_name; - msg->getStringFast(_PREHASH_MessageBlock, _PREHASH_FromAgentName, from_name); - from_name = LLCacheName::cleanFullName(from_name); + std::string name; + gCacheName->getFullName(from_id, name); std::string response = gSavedPerAccountSettings.getString("BusyModeResponse"); pack_instant_message( - gMessageSystem, + msg, gAgent.getID(), FALSE, gAgent.getSessionID(), from_id, my_name, - replace_wildcards(response, from_id, from_name), + replace_wildcards(response, from_id, name), IM_ONLINE, - IM_BUSY_AUTO_RESPONSE); + IM_BUSY_AUTO_RESPONSE, + session_id); gAgent.sendReliableMessage(); - std::string pns_name; - if (!LLAvatarNameCache::getPNSName(from_id, pns_name)) pns_name = from_name; - LLUUID session_id; - msg->getUUIDFast(_PREHASH_MessageBlock, _PREHASH_ID, session_id); - if (gSavedPerAccountSettings.getBOOL("BusyModeResponseShow")) gIMMgr->addMessage(session_id, from_id, from_name, LLTrans::getString("IM_autoresponded_to") + " " + pns_name); + LLAvatarName av_name; + std::string ns_name = LLAvatarNameCache::get(from_id, &av_name) ? av_name.getNSName() : name; + const auto show = gSavedPerAccountSettings.getBOOL("BusyModeResponseShow"); + if (show) gIMMgr->addMessage(session_id, from_id, name, LLTrans::getString("IM_autoresponded_to") + ' ' + ns_name); if (!gSavedPerAccountSettings.getBOOL("BusyModeResponseItem")) return; // Not sending an item, finished if (LLViewerInventoryItem* item = gInventory.getItem(static_cast(gSavedPerAccountSettings.getString("BusyModeResponseItemID")))) { - U8 d; - msg->getU8Fast(_PREHASH_MessageBlock, _PREHASH_Dialog, d); - LLUUID computed_session_id = LLIMMgr::computeSessionID(static_cast(d), from_id); - LLGiveInventory::doGiveInventoryItem(from_id, item, computed_session_id); - if (gSavedPerAccountSettings.getBOOL("BusyModeResponseShow")) - gIMMgr->addMessage(computed_session_id, from_id, from_name, llformat("%s %s \"%s\"", pns_name.c_str(), LLTrans::getString("IM_autoresponse_sent_item").c_str(), item->getName().c_str())); + LLGiveInventory::doGiveInventoryItem(from_id, item, session_id); + if (show) + gIMMgr->addMessage(session_id, from_id, name, llformat("%s %s \"%s\"", ns_name.c_str(), LLTrans::getString("IM_autoresponse_sent_item").c_str(), item->getName().c_str())); } } } @@ -3433,9 +2015,8 @@ bool callingcard_offer_callback(const LLSD& notification, const LLSD& response) { S32 option = LLNotificationsUtil::getSelectedOption(notification, response); LLUUID fid; - LLUUID from_id; LLMessageSystem* msg = gMessageSystem; - switch(option) + switch (option) { case 0: // accept @@ -3459,7 +2040,7 @@ bool callingcard_offer_callback(const LLSD& notification, const LLSD& response) msg->nextBlockFast(_PREHASH_TransactionBlock); msg->addUUIDFast(_PREHASH_TransactionID, notification["payload"]["transaction_id"].asUUID()); msg->sendReliable(LLHost(notification["payload"]["sender"].asString())); - busy_message(msg, notification["payload"]["source_id"].asUUID()); + send_do_not_disturb_message(msg, notification["payload"]["source_id"].asUUID()); break; default: // close button probably, possibly timed out @@ -3468,6 +2049,7 @@ bool callingcard_offer_callback(const LLSD& notification, const LLSD& response) return false; } + static LLNotificationFunctorRegistration callingcard_offer_cb_reg("OfferCallingCard", callingcard_offer_callback); void process_offer_callingcard(LLMessageSystem* msg, void**) @@ -3483,8 +2065,9 @@ void process_offer_callingcard(LLMessageSystem* msg, void**) msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, source_id); // NaCl - Antispam Registry - if(NACLAntiSpamRegistry::checkQueue((U32)NACLAntiSpamRegistry::QUEUE_CALLING_CARD,source_id)) - return; + if (auto antispam = NACLAntiSpamRegistry::getIfExists()) + if (antispam->checkQueue(NACLAntiSpamRegistry::QUEUE_CALLING_CARD, source_id)) + return; // NaCl End LLUUID tid; @@ -3498,7 +2081,7 @@ void process_offer_callingcard(LLMessageSystem* msg, void**) LLViewerObject* source = gObjectList.findObject(source_id); LLSD args; std::string source_name; - if(source && source->isAvatar()) + if (source && source->isAvatar()) { LLNameValue* nvfirst = source->getNVPair("FirstName"); LLNameValue* nvlast = source->getNVPair("LastName"); @@ -3509,9 +2092,9 @@ void process_offer_callingcard(LLMessageSystem* msg, void**) } } - if(!source_name.empty()) + if (!source_name.empty()) { - if (gAgent.getBusy() + if (gAgent.isDoNotDisturb() || LLMuteList::getInstance()->isMuted(source_id, source_name, LLMute::flagTextChat)) { // automatically decline offer @@ -3540,7 +2123,7 @@ void process_decline_callingcard(LLMessageSystem* msg, void**) } #if 0 // Google translate doesn't work anymore -class ChatTranslationReceiver : public LLTranslate::TranslationReceiver +class ChatTranslationReceiver final : public LLTranslate::TranslationReceiver { public : ChatTranslationReceiver(const std::string &fromLang, const std::string &toLang, LLChat *chat, @@ -3578,7 +2161,7 @@ public : delete m_chat; } - /*virtual*/ char const* getName(void) const { return "ChatTranslationReceiver"; } + char const* getName() const override { return "ChatTranslationReceiver"; } private: LLChat *m_chat; @@ -3586,7 +2169,7 @@ public : }; #endif -void add_floater_chat(const LLChat &chat, const BOOL history) +void add_floater_chat(LLChat &chat, const bool history) { if (history) { @@ -3601,7 +2184,7 @@ void add_floater_chat(const LLChat &chat, const BOOL history) } #if 0 // Google translate doesn't work anymore -void check_translate_chat(const std::string &mesg, LLChat &chat, const BOOL history) +void check_translate_chat(const std::string &mesg, LLChat &chat, const bool history) { const bool translate = LLUI::sConfigGroup->getBOOL("TranslateChat"); @@ -3623,31 +2206,7 @@ void check_translate_chat(const std::string &mesg, LLChat &chat, const BOOL hist } #endif -// defined in llchatbar.cpp, but not declared in any header -void send_chat_from_viewer(std::string utf8_out_text, EChatType type, S32 channel); - -class AuthHandler : public LLHTTPClient::ResponderWithCompleted -{ -protected: - /*virtual*/ void completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) - { - std::string content; - decode_raw_body(status, reason, channels, buffer, content); - if (status == HTTP_OK) - { - send_chat_from_viewer("AUTH:" + content, CHAT_TYPE_WHISPER, 427169570); - } - else - { - llwarns << "Hippo AuthHandler: non-OK HTTP status " << status << " for URL " << mURL << " (" << reason << "). Error body: \"" << content << "\"." << llendl; - } - } - - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return authHandler_timeout; } - /*virtual*/ char const* getName(void) const { return "AuthHandler"; } -}; - -void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) +void process_chat_from_simulator(LLMessageSystem* msg, void** user_data) { LLChat chat; std::string mesg; @@ -3680,6 +2239,8 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) // Object owner for objects msg->getUUID("ChatData", "OwnerID", owner_id); + bool has_owner = owner_id.notNull(); + if (chatter && has_owner) chatter->mOwnerID = owner_id; // Singu Note: Try to get Owner whenever possible msg->getU8Fast(_PREHASH_ChatData, _PREHASH_SourceType, source_temp); chat.mSourceType = (EChatSourceType)source_temp; @@ -3688,9 +2249,10 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) chat.mChatType = (EChatType)type_temp; // NaCL - Antispam Registry - if((chat.mChatType != CHAT_TYPE_START && chat.mChatType != CHAT_TYPE_STOP) //Chat type isn't typing - &&((owner_id.isNull() && NACLAntiSpamRegistry::checkQueue((U32)NACLAntiSpamRegistry::QUEUE_CHAT,from_id)) //Spam from an object? - ||(NACLAntiSpamRegistry::checkQueue((U32)NACLAntiSpamRegistry::QUEUE_CHAT,owner_id)))) //Spam from a resident? + auto antispam = NACLAntiSpamRegistry::getIfExists(); + if (antispam && chat.mChatType != CHAT_TYPE_START && chat.mChatType != CHAT_TYPE_STOP //Chat type isn't typing + && (antispam->checkQueue(NACLAntiSpamRegistry::QUEUE_CHAT, from_id, !has_owner ? LFIDBearer::AVATAR : LFIDBearer::OBJECT) // Spam from an object or avatar? + || (has_owner && (antispam->checkQueue(NACLAntiSpamRegistry::QUEUE_CHAT, owner_id))))) // Spam from a resident? return; // NaCl End @@ -3708,7 +2270,7 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) LLAvatarName av_name; if (LLAvatarNameCache::get(from_id, &av_name)) { - chat.mFromName = av_name.mDisplayName; + chat.mFromName = av_name.getNSName(); } else { @@ -3717,13 +2279,19 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) } else { + // make sure that we don't have an empty or all-whitespace name + LLStringUtil::trim(from_name); + if (from_name.empty()) + { + from_name = LLTrans::getString("Unnamed"); + } chat.mFromName = from_name; } - BOOL is_busy = gAgent.getBusy(); + bool is_do_not_disturb = gAgent.isDoNotDisturb(); - BOOL is_muted = FALSE; - BOOL is_linden = FALSE; + bool is_muted = false; + bool is_linden = false; is_muted = LLMuteList::getInstance()->isMuted( from_id, from_name, @@ -3732,87 +2300,21 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) is_linden = chat.mSourceType != CHAT_SOURCE_OBJECT && LLMuteList::getInstance()->isLinden(from_name); - BOOL is_audible = (CHAT_AUDIBLE_FULLY == chat.mAudible); + msg->getStringFast(_PREHASH_ChatData, _PREHASH_Message, mesg); + + bool handle_obj_auth(const LLUUID& from_id, const std::string& mesg); + if (source_temp == CHAT_SOURCE_OBJECT && type_temp == CHAT_TYPE_OWNER && handle_obj_auth(from_id, mesg)) return; - static std::map sChatObjectAuth; + if (is_muted && (chat.mSourceType == CHAT_SOURCE_OBJECT)) + { + return; + } + BOOL is_audible = (CHAT_AUDIBLE_FULLY == chat.mAudible); // // because I moved it to above //chatter = gObjectList.findObject(from_id); // - - msg->getStringFast(_PREHASH_ChatData, _PREHASH_Message, mesg); - - if ((source_temp == CHAT_SOURCE_OBJECT) && (type_temp == CHAT_TYPE_OWNER) && - (mesg.substr(0, 3) == "># ")) - { - if (mesg.substr(mesg.size()-3, 3) == " #<"){ - // hello from object - if (from_id.isNull()) return; - char buf[200]; - snprintf(buf, 200, "%s v%d.%d.%d", gVersionChannel, gVersionMajor, gVersionMinor, gVersionPatch); - send_chat_from_viewer(buf, CHAT_TYPE_WHISPER, 427169570); - sChatObjectAuth[from_id] = 1; - return; - } - else if (from_id.isNull() || sChatObjectAuth.find(from_id) != sChatObjectAuth.end()) - { - LLUUID key; - if (key.set(mesg.substr(3, 36),false)) - { - // object command found - if (key.isNull() && (mesg.size() == 39)) - { - // clear all nameplates - for (int i=0; i(obj)) - { - avatar->clearNameFromChat(); - } - } - } - else - { - if (key.isNull()) - { - llwarns << "Nameplate from chat on NULL avatar (ignored)" << llendl; - return; - } - LLVOAvatar *avatar = gObjectList.findAvatar(key); - if (!avatar) - { - llwarns << "Nameplate from chat on invalid avatar (ignored)" << llendl; - return; - } - if (mesg.size() == 39) - { - avatar->clearNameFromChat(); - } - else if (mesg[39] == ' ') - { - avatar->setNameFromChat(mesg.substr(40)); - } - } - return; - } - else if (mesg.substr(2, 9) == " floater ") - { - HippoFloaterXml::execute(mesg.substr(11)); - return; - } - else if (mesg.substr(2, 6) == " auth ") - { - std::string authUrl = mesg.substr(8); - authUrl += (authUrl.find('?') != std::string::npos)? "&auth=": "?auth="; - authUrl += gAuthString; - LLHTTPClient::get(authUrl, new AuthHandler); - return; - } - } - } - if (chatter) { chat.mPosAgent = chatter->getPositionAgent(); @@ -3838,7 +2340,7 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) // record last audible utterance if (is_audible - && (is_linden || (!is_muted && !is_busy))) + && (is_linden || (!is_muted && !is_do_not_disturb))) { if (chat.mChatType != CHAT_TYPE_START && chat.mChatType != CHAT_TYPE_STOP) @@ -3849,9 +2351,10 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) is_owned_by_me = chatter->permYouOwner(); } + else is_owned_by_me = owner_id == gAgentID; U32 links_for_chatting_objects = gSavedSettings.getU32("LinksForChattingObjects"); - if (links_for_chatting_objects != 0 && chatter && chat.mSourceType == CHAT_SOURCE_OBJECT && + if (links_for_chatting_objects != 0 /*&& chatter*/ && chat.mSourceType == CHAT_SOURCE_OBJECT && (!is_owned_by_me || links_for_chatting_objects == 2) // [RLVa:KB] && !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES) @@ -3866,13 +2369,16 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) if( !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC) ) // [/RLVa:KB] { + // Fallback on the owner, if the chatter isn't present, lastly use the agent's region at the origin. + const LLViewerObject* obj(chatter ? chatter : gObjectList.findObject(owner_id)); // Compute the object SLURL. - LLVector3 pos = chatter->getPositionRegion(); - S32 x = llround((F32)fmod((F64)pos.mV[VX], (F64)REGION_WIDTH_METERS)); - S32 y = llround((F32)fmod((F64)pos.mV[VY], (F64)REGION_WIDTH_METERS)); - S32 z = llround((F32)pos.mV[VZ]); + LLVector3 pos = obj ? obj->getPositionRegion() : LLVector3::zero; + S32 x = ll_round((F32)fmod((F64)pos.mV[VX], (F64)REGION_WIDTH_METERS)); + S32 y = ll_round((F32)fmod((F64)pos.mV[VY], (F64)REGION_WIDTH_METERS)); + S32 z = ll_round((F32)pos.mV[VZ]); std::ostringstream location; - location << chatter->getRegion()->getName() << "/" << x << "/" << y << "/" << z; + location << (obj ? obj->getRegion() : gAgent.getRegion())->getName() << "/" << x << "/" << y << "/" << z; + if (chatter != obj) location << "?owner_not_object"; query_string["slurl"] = location.str(); } @@ -3884,18 +2390,17 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) if (is_audible) { // NaCl - Newline flood protection - static LLCachedControl AntiSpamEnabled(gSavedSettings,"AntiSpamEnabled",false); - if (AntiSpamEnabled && can_block(from_id)) + if (antispam && can_block(from_id)) { - static LLCachedControl SpamNewlines(gSavedSettings,"_NACL_AntiSpamNewlines"); + static const LLCachedControl SpamNewlines("_NACL_AntiSpamNewlines"); boost::sregex_iterator iter(mesg.begin(), mesg.end(), NEWLINES); if((U32)std::abs(std::distance(iter, boost::sregex_iterator())) > SpamNewlines) { - NACLAntiSpamRegistry::blockOnQueue((U32)NACLAntiSpamRegistry::QUEUE_CHAT,owner_id); + antispam->blockOnQueue(NACLAntiSpamRegistry::QUEUE_CHAT, owner_id); if(gSavedSettings.getBOOL("AntiSpamNotify")) { LLSD args; - args["MESSAGE"] = "Chat: Blocked newline flood from "+owner_id.asString(); + args["MESSAGE"] = "Chat: Blocked newline flood from " + LLAvatarActions::getSLURL(owner_id); LLNotificationsUtil::add("SystemMessageTip", args); } return; @@ -3905,14 +2410,14 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) if (chatter && chatter->isAvatar()) { - if (LLAvatarNameCache::getPNSName(from_id, from_name)) + if (LLAvatarNameCache::getNSName(from_id, from_name)) chat.mFromName = from_name; } BOOL visible_in_chat_bubble = FALSE; std::string verb; - color.setVec(1.f,1.f,1.f,1.f); + color.setVec(1.f, 1.f, 1.f, 1.f); // [RLVa:KB] - Checked: 2010-04-23 (RLVa-1.2.0f) | Modified: RLVa-1.2.0f if ( (rlv_handler_t::isEnabled()) && (CHAT_TYPE_START != chat.mChatType) && (CHAT_TYPE_STOP != chat.mChatType) ) @@ -3922,10 +2427,10 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) // Filtering "rules": // avatar => filter all avie text (unless it's this avie or they're an exemption) - // objects => filter everything except attachments this avie owns (never filter llOwnerSay chat) + // objects => filter everything except attachments this avie owns (never filter llOwnerSay or llRegionSayTo chat) if ( ( (CHAT_SOURCE_AGENT == chat.mSourceType) && (from_id != gAgent.getID()) ) || ( (CHAT_SOURCE_OBJECT == chat.mSourceType) && ((!is_owned_by_me) || (!is_attachment)) && - (CHAT_TYPE_OWNER != chat.mChatType) ) ) + (CHAT_TYPE_OWNER != chat.mChatType) && (CHAT_TYPE_DIRECT != chat.mChatType) ) ) { bool fIsEmote = RlvUtil::isEmote(mesg); if ((!fIsEmote) && @@ -3954,7 +2459,7 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) { RlvUtil::filterNames(chat.mFromName); } - else if (chat.mFromID != gAgent.getID()) + else if (chat.mFromID != gAgentID) { chat.mFromName = RlvStrings::getAnonym(chat.mFromName); chat.mRlvNamesFiltered = TRUE; @@ -3970,10 +2475,8 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) sdQuery["name"] = chat.mFromName; sdQuery["owner"] = owner_id; - /* Singu Note: We don't use this field, seems like part of llinspectremoteobject if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES)) && (!is_owned_by_me) ) sdQuery["rlv_shownames"] = true; - */ const LLViewerRegion* pRegion = LLWorld::getInstance()->getRegionFromPosAgent(chat.mPosAgent); if (pRegion) @@ -3988,9 +2491,9 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) // Look for IRC-style emotes here so chatbubbles work std::string prefix = mesg.substr(0, 4); - if (prefix == "/me " || prefix == "/me'") + if (boost::iequals(prefix, "/me ") || boost::iequals(prefix, "/me'")) // { - chat.mText = from_name; + chat.mText = chat.mFromName; mesg = mesg.substr(3); ircstyle = TRUE; // This block was moved up to allow bubbles with italicized chat @@ -4011,7 +2514,7 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) } return; } - else if (CHAT_TYPE_STOP == chat.mChatType) + if (CHAT_TYPE_STOP == chat.mChatType) { LLLocalSpeakerMgr::getInstance()->setSpeakerTyping(from_id, FALSE); @@ -4029,7 +2532,7 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) LLLocalSpeakerMgr::getInstance()->setSpeakerTyping(from_id, FALSE); static_cast(chatter)->stopTyping(); - if (!is_muted && !is_busy) + if (!is_muted /*&& !is_do_not_disturb*/) { static const LLCachedControl use_chat_bubbles("UseChatBubbles",false); visible_in_chat_bubble = use_chat_bubbles; @@ -4044,7 +2547,7 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) } else { - switch(chat.mChatType) + switch (chat.mChatType) { case CHAT_TYPE_WHISPER: verb = " " + LLTrans::getString("whisper") + " "; @@ -4060,7 +2563,7 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) std::string strExecuted, strFailed, strRetained, *pstr; boost_tokenizer tokens(mesg, boost::char_separator(",", "", boost::drop_empty_tokens)); - for (boost_tokenizer::iterator itToken = tokens.begin(); itToken != tokens.end(); ++itToken) + for (auto itToken = tokens.begin(); itToken != tokens.end(); ++itToken) { std::string strCmd = *itToken; @@ -4163,7 +2666,7 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) break; } - chat.mText = from_name + verb + mesg; + chat.mText = chat.mFromName + verb + mesg; } if (chatter) @@ -4172,7 +2675,7 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) } chat.mMuted = is_muted && !is_linden; - bool only_history = visible_in_chat_bubble || (!is_linden && !is_owned_by_me && is_busy); + bool only_history = visible_in_chat_bubble || (!is_linden && !is_owned_by_me && is_do_not_disturb); #if 0 // Google translate doesn't work anymore if (!chat.mMuted) { @@ -4191,11 +2694,19 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) // of TeleportRequest, then this info is redundant, but if the sim // initiated the teleport (via a script call, being killed, etc.) // then this info is news to us. -void process_teleport_start(LLMessageSystem *msg, void**) +void process_teleport_start(LLMessageSystem* msg, void**) { + // on teleport, don't tell them about destination guide anymore + //LLFirstUse::notUsingDestinationGuide(false); U32 teleport_flags = 0x0; msg->getU32("Info", "TeleportFlags", teleport_flags); + if (gAgent.getTeleportState() == LLAgent::TELEPORT_MOVING) + { + // Race condition? + LL_WARNS("Messaging") << "Got TeleportStart, but teleport already in progress. TeleportFlags=" << teleport_flags << LL_ENDL; + } + LL_DEBUGS("Messaging") << "Got TeleportStart with TeleportFlags=" << teleport_flags << ". gTeleportDisplay: " << gTeleportDisplay << ", gAgent.mTeleportState: " << gAgent.getTeleportState() << LL_ENDL; // if (teleport_flags & TELEPORT_FLAGS_DISABLE_CANCEL) @@ -4213,10 +2724,11 @@ void process_teleport_start(LLMessageSystem *msg, void**) // Freeze the UI and show progress bar // Note: could add data here to differentiate between normal teleport and death. - if( gAgent.getTeleportState() == LLAgent::TELEPORT_NONE ) + if (gAgent.getTeleportState() == LLAgent::TELEPORT_NONE) { gTeleportDisplay = TRUE; - gAgent.setTeleportState( LLAgent::TELEPORT_START ); + gAgent.setTeleportState(LLAgent::TELEPORT_START); + make_ui_sound("UISndTeleportOut"); LL_INFOS("Messaging") << "Teleport initiated by remote TeleportStart message with TeleportFlags: " << teleport_flags << LL_ENDL; @@ -4230,7 +2742,7 @@ void process_teleport_progress(LLMessageSystem* msg, void**) { LLUUID agent_id; msg->getUUID("AgentData", "AgentID", agent_id); - if((gAgent.getID() != agent_id) + if ((gAgent.getID() != agent_id) || (gAgent.getTeleportState() == LLAgent::TELEPORT_NONE)) { LL_WARNS("Messaging") << "Unexpected teleport progress message." << LL_ENDL; @@ -4251,14 +2763,14 @@ void process_teleport_progress(LLMessageSystem* msg, void**) } std::string buffer; msg->getString("Info", "Message", buffer); - LL_DEBUGS("Messaging") << "teleport progress: " << buffer << LL_ENDL; + LL_DEBUGS("Messaging") << "teleport progress: " << buffer << " flags: " << teleport_flags << LL_ENDL; //Sorta hacky...default to using simulator raw messages //if we don't find the coresponding mapping in our progress mappings std::string message = buffer; if (LLAgent::sTeleportProgressMessages.find(buffer) != - LLAgent::sTeleportProgressMessages.end() ) + LLAgent::sTeleportProgressMessages.end()) { message = LLAgent::sTeleportProgressMessages[buffer]; } @@ -4266,13 +2778,15 @@ void process_teleport_progress(LLMessageSystem* msg, void**) gAgent.setTeleportMessage(LLAgent::sTeleportProgressMessages[message]); } -class LLFetchInWelcomeArea : public LLInventoryFetchDescendentsObserver +class LLFetchInWelcomeArea final : public LLInventoryFetchDescendentsObserver { public: - LLFetchInWelcomeArea(const uuid_vec_t &ids) : + LLFetchInWelcomeArea(const uuid_vec_t& ids) : LLInventoryFetchDescendentsObserver(ids) - {} - virtual void done() + { + } + + void done() override { LLIsType is_landmark(LLAssetType::AT_LANDMARK); LLIsType is_card(LLAssetType::AT_CALLINGCARD); @@ -4284,7 +2798,7 @@ class LLFetchInWelcomeArea : public LLInventoryFetchDescendentsObserver uuid_vec_t::iterator it = mComplete.begin(); uuid_vec_t::iterator end = mComplete.end(); - for(; it != end; ++it) + for (; it != end; ++it) { gInventory.collectDescendentsIf( (*it), @@ -4300,15 +2814,15 @@ class LLFetchInWelcomeArea : public LLInventoryFetchDescendentsObserver is_card); } LLSD args; - if ( land_items.count() > 0 ) + if (!land_items.empty()) { // Show notification that they can now teleport to landmarks. Use a random landmark from the inventory - S32 random_land = ll_rand( land_items.count() - 1 ); + S32 random_land = ll_rand(land_items.size() - 1); args["NAME"] = land_items[random_land]->getName(); LLNotificationsUtil::add("TeleportToLandmark",args); } - if ( card_items.count() > 0 ) + if (!card_items.empty()) { // Show notification that they can now contact people. Use a random calling card from the inventory - S32 random_card = ll_rand( card_items.count() - 1 ); + S32 random_card = ll_rand(card_items.size() - 1); args["NAME"] = card_items[random_card]->getName(); LLNotificationsUtil::add("TeleportToPerson",args); } @@ -4319,18 +2833,17 @@ class LLFetchInWelcomeArea : public LLInventoryFetchDescendentsObserver }; - -class LLPostTeleportNotifiers : public LLEventTimer +class LLPostTeleportNotifiers final : public LLEventTimer { public: LLPostTeleportNotifiers(); virtual ~LLPostTeleportNotifiers(); //function to be called at the supplied frequency - virtual BOOL tick(); + BOOL tick() override; }; -LLPostTeleportNotifiers::LLPostTeleportNotifiers() : LLEventTimer( 2.0 ) +LLPostTeleportNotifiers::LLPostTeleportNotifiers() : LLEventTimer(2.0) { }; @@ -4341,21 +2854,21 @@ LLPostTeleportNotifiers::~LLPostTeleportNotifiers() BOOL LLPostTeleportNotifiers::tick() { BOOL all_done = FALSE; - if ( gAgent.getTeleportState() == LLAgent::TELEPORT_NONE ) + if (gAgent.getTeleportState() == LLAgent::TELEPORT_NONE) { // get callingcards and landmarks available to the user arriving. uuid_vec_t folders; const LLUUID callingcard_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD); - if(callingcard_id.notNull()) + if (callingcard_id.notNull()) folders.push_back(callingcard_id); const LLUUID folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK); - if(folder_id.notNull()) + if (folder_id.notNull()) folders.push_back(folder_id); - if(!folders.empty()) + if (!folders.empty()) { LLFetchInWelcomeArea* fetcher = new LLFetchInWelcomeArea(folders); fetcher->startFetch(); - if(fetcher->isFinished()) + if (fetcher->isFinished()) { fetcher->done(); } @@ -4371,7 +2884,6 @@ BOOL LLPostTeleportNotifiers::tick() } - // Teleport notification from the simulator // We're going to pretend to be a new agent void process_teleport_finish(LLMessageSystem* msg, void**) @@ -4388,9 +2900,11 @@ void process_teleport_finish(LLMessageSystem* msg, void**) // Teleport is finished; it can't be cancelled now. gViewerWindow->setProgressCancelButtonVisible(FALSE); + //gPipeline.doResetVertexBuffers(true); // Animesh+ + // Do teleport effect for where you're leaving // VEFFECT: TeleportStart - LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE); + LLHUDEffectSpiral* effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE); effectp->setPositionGlobal(gAgent.getPositionGlobal()); effectp->setColor(LLColor4U(gAgent.getEffectColor())); LLHUDManager::getInstance()->sendEffects(); @@ -4408,13 +2922,13 @@ void process_teleport_finish(LLMessageSystem* msg, void**) msg->getU64Fast(_PREHASH_Info, _PREHASH_RegionHandle, region_handle); U32 teleport_flags; msg->getU32Fast(_PREHASH_Info, _PREHASH_TeleportFlags, teleport_flags); - - + + std::string seedCap; msg->getStringFast(_PREHASH_Info, _PREHASH_SeedCapability, seedCap); // update home location if we are teleporting out of prelude - specific to teleporting to welcome area - if((teleport_flags & TELEPORT_FLAGS_SET_HOME_TO_TARGET) + if ((teleport_flags & TELEPORT_FLAGS_SET_HOME_TO_TARGET) && (!gAgent.isGodlike())) { gAgent.setHomePosRegion(region_handle, pos); @@ -4428,11 +2942,21 @@ void process_teleport_finish(LLMessageSystem* msg, void**) // Viewer trusts the simulator. gMessageSystem->enableCircuit(sim_host, TRUE); + if (!gHippoGridManager->getConnectedGrid()->isSecondLife()) + { + U32 region_size_x = 256; + msg->getU32Fast(_PREHASH_Info, _PREHASH_RegionSizeX, region_size_x); + U32 region_size_y = 256; + msg->getU32Fast(_PREHASH_Info, _PREHASH_RegionSizeY, region_size_y); + LLWorld::getInstance()->setRegionSize(region_size_x, region_size_y); + } LLViewerRegion* regionp = LLWorld::getInstance()->addRegion(region_handle, sim_host); -/* + M7WindlightInterface::getInstance()->receiveReset(); + + /* // send camera update to new region - gAgent.updateCamera(); + gAgentCamera.updateCamera(); // likewise make sure the camera is behind the avatar gAgentCamera.resetView(TRUE); @@ -4450,8 +2974,6 @@ void process_teleport_finish(LLMessageSystem* msg, void**) gCacheName->setUpstream(sim); */ - M7WindlightInterface::getInstance()->receiveReset(); - // Make sure we're standing gAgent.standUp(); @@ -4466,9 +2988,11 @@ void process_teleport_finish(LLMessageSystem* msg, void**) msg->sendReliable(sim_host); send_complete_agent_movement(sim_host); - gAgent.setTeleportState( LLAgent::TELEPORT_MOVING ); + gAgent.setTeleportState(LLAgent::TELEPORT_MOVING); gAgent.setTeleportMessage(LLAgent::sTeleportProgressMessages["contacting"]); + LL_DEBUGS("CrossingCaps") << "Calling setSeedCapability from process_teleport_finish(). Seed cap == " + << seedCap << LL_ENDL; regionp->setSeedCapability(seedCap); // Don't send camera updates to the new region until we're @@ -4483,9 +3007,9 @@ void process_teleport_finish(LLMessageSystem* msg, void**) effectp->setColor(LLColor4U(gAgent.getEffectColor())); LLHUDManager::getInstance()->sendEffects(); -// gTeleportDisplay = TRUE; -// gTeleportDisplayTimer.reset(); -// gViewerWindow->setShowProgress(TRUE); + // gTeleportDisplay = TRUE; + // gTeleportDisplayTimer.reset(); + // gViewerWindow->setShowProgress(TRUE); } // stuff we have to do every time we get an AvatarInitComplete from a sim @@ -4507,7 +3031,7 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); LLUUID session_id; msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_SessionID, session_id); - if((gAgent.getID() != agent_id) || (gAgent.getSessionID() != session_id)) + if ((gAgent.getID() != agent_id) || (gAgent.getSessionID() != session_id)) { LL_WARNS("Messaging") << "Incorrect id in process_agent_movement_complete()" << LL_ENDL; @@ -4551,7 +3075,6 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) << LL_ENDL; LLAppViewer::instance()->forceDisconnect(LLTrans::getString("SentToInvalidRegion")); return; - } LL_INFOS("Messaging") << "Changing home region to " << x << ":" << y << LL_ENDL; @@ -4562,6 +3085,20 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) gAgent.getRegion()->getOriginGlobal()); gAgent.setRegion(regionp); gObjectList.shiftObjects(shift_vector); + // Is this a really long jump? + if (shift_vector.length() > 2048.f * 256.f) + { + regionp->reInitPartitions(); + gAgent.setRegion(regionp); + // Kill objects in the regions we left behind + for (auto r : LLWorld::getInstance()->getRegionList()) + { + if (r != regionp) + { + gObjectList.killObjects(r); + } + } + } gAssetStorage->setUpstream(msg->getSender()); gCacheName->setUpstream(msg->getSender()); gViewerThrottle.sendToSim(); @@ -4569,7 +3106,7 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) bool is_teleport = gAgent.getTeleportState() == LLAgent::TELEPORT_MOVING; - if( is_teleport ) + if (is_teleport) { if (gAgent.getTeleportKeepsLookAt()) { @@ -4582,7 +3119,7 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) gAgentCamera.slamLookAt(look_at); gAgentCamera.updateCamera(); - gAgent.setTeleportState( LLAgent::TELEPORT_START_ARRIVAL ); + gAgent.setTeleportState(LLAgent::TELEPORT_START_ARRIVAL); // set the appearance on teleport since the new sim does not // know what you look like. @@ -4591,7 +3128,6 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) if (isAgentAvatarValid()) { // Chat the "back" SLURL. (DEV-4907) - LLSLURL slurl; gAgent.getTeleportSourceSLURL(slurl); LLChat chat(LLTrans::getString("completed_from") + " " + slurl.getSLURLString()); @@ -4610,9 +3146,9 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) else { // This is initial log-in or a region crossing - gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); + gAgent.setTeleportState(LLAgent::TELEPORT_NONE); - if(LLStartUp::getStartupState() < STATE_STARTED) + if (LLStartUp::getStartupState() < STATE_STARTED) { // This is initial log-in, not a region crossing: // Set the camera looking ahead of the AV so send_agent_update() below // will report the correct location to the server. @@ -4635,7 +3171,7 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) } else if (is_teleport) { - if (!gAgent.getTeleportKeepsLookAt()) + if (!gAgent.getTeleportKeepsLookAt() && look_at.isExactlyZero()) { //look at the beacon LLVector3 global_agent_pos = agent_pos; @@ -4672,15 +3208,9 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) gAgent.setFlying(false/*gAgent.canFly()*/); } - // force simulator to recognize busy state - if (gAgent.getBusy()) - { - gAgent.setBusy(); - } - else - { - gAgent.clearBusy(); - } + // force simulator to recognize do not disturb state + + gAgent.setDoNotDisturb(gAgent.isDoNotDisturb()); if (isAgentAvatarValid()) { @@ -4702,9 +3232,10 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) if (!gLastVersionChannel.empty() && gSavedSettings.getBOOL("SGServerVersionChangedNotification")) { - LLSD payload; - payload["message"] = version_channel; - LLNotificationsUtil::add("ServerVersionChanged", LLSD(), payload); + LLSD args; + args["OLD_VERSION"] = gLastVersionChannel; + args["NEW_VERSION"] = version_channel; + LLNotificationsUtil::add("ServerVersionChanged", args); } gLastVersionChannel = version_channel; @@ -4716,7 +3247,7 @@ void process_crossed_region(LLMessageSystem* msg, void**) msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); LLUUID session_id; msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_SessionID, session_id); - if((gAgent.getID() != agent_id) || (gAgent.getSessionID() != session_id)) + if ((gAgent.getID() != agent_id) || (gAgent.getSessionID() != session_id)) { LL_WARNS("Messaging") << "Incorrect id in process_crossed_region()" << LL_ENDL; @@ -4724,6 +3255,8 @@ void process_crossed_region(LLMessageSystem* msg, void**) } LL_INFOS("Messaging") << "process_crossed_region()" << LL_ENDL; gAgentAvatarp->resetRegionCrossingTimer(); + gAgent.setIsCrossingRegion(false); // Attachments getting lost on TP, region crossing hook + U32 sim_ip; msg->getIPAddrFast(_PREHASH_RegionData, _PREHASH_SimIP, sim_ip); @@ -4738,12 +3271,22 @@ void process_crossed_region(LLMessageSystem* msg, void**) send_complete_agent_movement(sim_host); + if (!gHippoGridManager->getConnectedGrid()->isSecondLife()) + { + U32 region_size_x = 256; + msg->getU32(_PREHASH_RegionData, _PREHASH_RegionSizeX, region_size_x); + U32 region_size_y = 256; + msg->getU32(_PREHASH_RegionData, _PREHASH_RegionSizeY, region_size_y); + LLWorld::getInstance()->setRegionSize(region_size_x, region_size_y); + } LLViewerRegion* regionp = LLWorld::getInstance()->addRegion(region_handle, sim_host); + + LL_DEBUGS("CrossingCaps") << "Calling setSeedCapability from process_crossed_region(). Seed cap == " + << seedCap << LL_ENDL; regionp->setSeedCapability(seedCap); } - // Sends avatar and camera information to simulator. // Sent roughly once per frame, or 20 times per second, whichever is less often @@ -4751,7 +3294,7 @@ const F32 THRESHOLD_HEAD_ROT_QDOT = 0.9997f; // ~= 2.5 degrees -- if its less th const F32 MAX_HEAD_ROT_QDOT = 0.99999f; // ~= 0.5 degrees -- if its greater than this then no need to update head_rot // between these values we delay the updates (but no more than one second) -static LLFastTimer::DeclareTimer FTM_AGENT_UPDATE_SEND("Send Message"); +static LLTrace::BlockTimerStatHandle FTM_AGENT_UPDATE_SEND("Send Message"); void send_agent_update(BOOL force_send, BOOL send_reliable) { @@ -4763,13 +3306,13 @@ void send_agent_update(BOOL force_send, BOOL send_reliable) } // We have already requested to log out. Don't send agent updates. - if(LLAppViewer::instance()->logoutRequestSent()) + if (LLAppViewer::instance()->logoutRequestSent()) { return; } // no region to send update to - if(gAgent.getRegion() == NULL) + if (gAgent.getRegion() == nullptr) { return; } @@ -4779,7 +3322,7 @@ void send_agent_update(BOOL force_send, BOOL send_reliable) // NOTA BENE: This is (intentionally?) using the small angle sine approximation to test for rotation // Plus, there is an extra 0.5 in the mix since the perpendicular between last_camera_at and getAtAxis() bisects cam_rot_change // Thus, we're actually testing against 0.2 degrees - const F32 ROTATION_THRESHOLD = 0.1f * 2.f*F_PI/360.f; // Rotation thresh 0.2 deg, see note above + const F32 ROTATION_THRESHOLD = 0.1f * 2.f * F_PI / 360.f; // Rotation thresh 0.2 deg, see note above const U8 DUP_MSGS = 1; // HACK! number of times to repeat data on motionless agent @@ -4799,7 +3342,7 @@ void send_agent_update(BOOL force_send, BOOL send_reliable) static F32 head_rot_chg = 1.0; static U8 last_flags; - LLMessageSystem *msg = gMessageSystem; + LLMessageSystem* msg = gMessageSystem; LLVector3 camera_pos_agent; // local to avatar's region U8 render_state; @@ -4821,21 +3364,22 @@ void send_agent_update(BOOL force_send, BOOL send_reliable) // trigger a control event. U32 control_flags = gAgent.getControlFlags(); - // - if(gSavedSettings.getBOOL("Nimble")) + // + static LLCachedControl alchemyPrejump(gSavedSettings, "Nimble", false); + if (alchemyPrejump) { control_flags |= AGENT_CONTROL_FINISH_ANIM; } - // + // MASK key_mask = gKeyboard->currentMask(TRUE); if (key_mask & MASK_ALT || key_mask & MASK_CONTROL) { - control_flags &= ~( AGENT_CONTROL_LBUTTON_DOWN | - AGENT_CONTROL_ML_LBUTTON_DOWN ); + control_flags &= ~(AGENT_CONTROL_LBUTTON_DOWN | + AGENT_CONTROL_ML_LBUTTON_DOWN); control_flags |= AGENT_CONTROL_LBUTTON_UP | - AGENT_CONTROL_ML_LBUTTON_UP ; + AGENT_CONTROL_ML_LBUTTON_UP; } control_flag_change = last_control_flags ^ control_flags; @@ -4931,14 +3475,14 @@ void send_agent_update(BOOL force_send, BOOL send_reliable) update_sec = cur_sec; //msg_number = 0; max_update_count = llmax(max_update_count, update_count); - llinfos << "Sent " << update_count << " AgentUpdate messages per second, max is " << max_update_count << llendl; + LL_INFOS() << "Sent " << update_count << " AgentUpdate messages per second, max is " << max_update_count << LL_ENDL; } update_sec = cur_sec; update_count = 0; } */ - LLFastTimer t(FTM_AGENT_UPDATE_SEND); + LL_RECORD_BLOCK_TIME(FTM_AGENT_UPDATE_SEND); // Build the message msg->newMessageFast(_PREHASH_AgentUpdate); msg->nextBlockFast(_PREHASH_AgentData); @@ -4949,10 +3493,10 @@ void send_agent_update(BOOL force_send, BOOL send_reliable) msg->addU8Fast(_PREHASH_State, render_state); msg->addU8Fast(_PREHASH_Flags, flags); -// if (camera_pos_agent.mV[VY] > 255.f) -// { -// LL_INFOS("Messaging") << "Sending camera center " << camera_pos_agent << LL_ENDL; -// } + // if (camera_pos_agent.mV[VY] > 255.f) + // { + // LL_INFOS("Messaging") << "Sending camera center " << camera_pos_agent << LL_ENDL; + // } msg->addVector3Fast(_PREHASH_CameraCenter, camera_pos_agent); msg->addVector3Fast(_PREHASH_CameraAtAxis, LLViewerCamera::getInstance()->getAtAxis()); @@ -4986,7 +3530,7 @@ void send_agent_update(BOOL force_send, BOOL send_reliable) gAgent.sendReliableMessage(); } -// LL_DEBUGS("Messaging") << "agent " << avatar_pos_agent << " cam " << camera_pos_agent << LL_ENDL; + // LL_DEBUGS("Messaging") << "agent " << avatar_pos_agent << " cam " << camera_pos_agent << LL_ENDL; // Copy the old data last_head_rot = head_rotation; @@ -5001,53 +3545,167 @@ void send_agent_update(BOOL force_send, BOOL send_reliable) } +// sounds can arrive before objects, store them for a short time +// Note: this is a workaround for MAINT-4743, real fix would be to make +// server send sound along with object update that creates (rezes) the object +class PostponedSoundData +{ +public: + PostponedSoundData() : + mExpirationTime(0) + {} + PostponedSoundData(const LLUUID &object_id, const LLUUID &sound_id, const LLUUID& owner_id, const F32 gain, const U8 flags); + bool hasExpired() { return LLFrameTimer::getTotalSeconds() > mExpirationTime; } + + LLUUID mObjectId; + LLUUID mSoundId; + LLUUID mOwnerId; + F32 mGain; + U8 mFlags; + static const F64 MAXIMUM_PLAY_DELAY; + +private: + F64 mExpirationTime; //seconds since epoch +}; +const F64 PostponedSoundData::MAXIMUM_PLAY_DELAY = 15.0; +static F64 postponed_sounds_update_expiration = 0.0; +static std::map postponed_sounds; + +void set_attached_sound(LLViewerObject *objectp, const LLUUID &object_id, const LLUUID &sound_id, const LLUUID& owner_id, const F32 gain, const U8 flags) +{ + if (LLMuteList::getInstance()->isMuted(object_id)) return; + + if (LLMuteList::getInstance()->isMuted(owner_id, LLMute::flagObjectSounds)) return; + + // Don't play sounds from a region with maturity above current agent maturity + LLVector3d pos = objectp->getPositionGlobal(); + if (!gAgent.canAccessMaturityAtGlobal(pos)) + { + return; + } + + objectp->setAttachedSound(sound_id, owner_id, gain, flags); +} + +PostponedSoundData::PostponedSoundData(const LLUUID &object_id, const LLUUID &sound_id, const LLUUID& owner_id, const F32 gain, const U8 flags) + : + mObjectId(object_id), + mSoundId(sound_id), + mOwnerId(owner_id), + mGain(gain), + mFlags(flags), + mExpirationTime(LLFrameTimer::getTotalSeconds() + MAXIMUM_PLAY_DELAY) +{ +} + +// static +void update_attached_sounds() +{ + if (postponed_sounds.empty()) + { + return; + } + + std::map::iterator iter = postponed_sounds.begin(); + std::map::iterator end = postponed_sounds.end(); + while (iter != end) + { + std::map::iterator cur_iter = iter++; + PostponedSoundData* data = &cur_iter->second; + if (data->hasExpired()) + { + postponed_sounds.erase(cur_iter); + } + else + { + LLViewerObject *objectp = gObjectList.findObject(data->mObjectId); + if (objectp) + { + set_attached_sound(objectp, data->mObjectId, data->mSoundId, data->mOwnerId, data->mGain, data->mFlags); + postponed_sounds.erase(cur_iter); + } + } + } + postponed_sounds_update_expiration = LLFrameTimer::getTotalSeconds() + 2 * PostponedSoundData::MAXIMUM_PLAY_DELAY; +} + +//static +void clear_expired_postponed_sounds() +{ + if (postponed_sounds_update_expiration > LLFrameTimer::getTotalSeconds()) + { + return; + } + std::map::iterator iter = postponed_sounds.begin(); + std::map::iterator end = postponed_sounds.end(); + while (iter != end) + { + std::map::iterator cur_iter = iter++; + PostponedSoundData* data = &cur_iter->second; + if (data->hasExpired()) + { + postponed_sounds.erase(cur_iter); + } + } + postponed_sounds_update_expiration = LLFrameTimer::getTotalSeconds() + 2 * PostponedSoundData::MAXIMUM_PLAY_DELAY; +} // *TODO: Remove this dependency, or figure out a better way to handle // this hack. -extern U32 gObjectBits; +extern U32Bits gObjectData; -void process_object_update(LLMessageSystem *mesgsys, void **user_data) +void process_object_update(LLMessageSystem* mesgsys, void** user_data) { // Update the data counters if (mesgsys->getReceiveCompressedSize()) { - gObjectBits += mesgsys->getReceiveCompressedSize() * 8; + gObjectData += U32Bytes(mesgsys->getReceiveCompressedSize()); } else { - gObjectBits += mesgsys->getReceiveSize() * 8; + gObjectData += U32Bytes(mesgsys->getReceiveSize()); } // Update the object... + S32 old_num_objects = gObjectList.mNumNewObjects; gObjectList.processObjectUpdate(mesgsys, user_data, OUT_FULL); + if (old_num_objects != gObjectList.mNumNewObjects) + { + update_attached_sounds(); + } } -void process_compressed_object_update(LLMessageSystem *mesgsys, void **user_data) +void process_compressed_object_update(LLMessageSystem* mesgsys, void** user_data) { // Update the data counters if (mesgsys->getReceiveCompressedSize()) { - gObjectBits += mesgsys->getReceiveCompressedSize() * 8; + gObjectData += U32Bytes(mesgsys->getReceiveCompressedSize()); } else { - gObjectBits += mesgsys->getReceiveSize() * 8; + gObjectData += U32Bytes(mesgsys->getReceiveSize()); } // Update the object... + S32 old_num_objects = gObjectList.mNumNewObjects; gObjectList.processCompressedObjectUpdate(mesgsys, user_data, OUT_FULL_COMPRESSED); + if (old_num_objects != gObjectList.mNumNewObjects) + { + update_attached_sounds(); + } } -void process_cached_object_update(LLMessageSystem *mesgsys, void **user_data) +void process_cached_object_update(LLMessageSystem* mesgsys, void** user_data) { // Update the data counters if (mesgsys->getReceiveCompressedSize()) { - gObjectBits += mesgsys->getReceiveCompressedSize() * 8; + gObjectData += U32Bytes(mesgsys->getReceiveCompressedSize()); } else { - gObjectBits += mesgsys->getReceiveSize() * 8; + gObjectData += U32Bytes(mesgsys->getReceiveSize()); } // Update the object... @@ -5055,46 +3713,52 @@ void process_cached_object_update(LLMessageSystem *mesgsys, void **user_data) } -void process_terse_object_update_improved(LLMessageSystem *mesgsys, void **user_data) +void process_terse_object_update_improved(LLMessageSystem* mesgsys, void** user_data) { if (mesgsys->getReceiveCompressedSize()) { - gObjectBits += mesgsys->getReceiveCompressedSize() * 8; + gObjectData += U32Bytes(mesgsys->getReceiveCompressedSize()); } else { - gObjectBits += mesgsys->getReceiveSize() * 8; + gObjectData += U32Bytes(mesgsys->getReceiveSize()); } + S32 old_num_objects = gObjectList.mNumNewObjects; gObjectList.processCompressedObjectUpdate(mesgsys, user_data, OUT_TERSE_IMPROVED); + if (old_num_objects != gObjectList.mNumNewObjects) + { + update_attached_sounds(); + } } -static LLFastTimer::DeclareTimer FTM_PROCESS_OBJECTS("Process Objects"); +static LLTrace::BlockTimerStatHandle FTM_PROCESS_OBJECTS("Process Kill Objects"); - -void process_kill_object(LLMessageSystem *mesgsys, void **user_data) +void process_kill_object(LLMessageSystem* mesgsys, void** user_data) { - LLFastTimer t(FTM_PROCESS_OBJECTS); + LL_RECORD_BLOCK_TIME(FTM_PROCESS_OBJECTS); + + auto agent_region = gAgent.getRegion(); + if (!agent_region) return; LLUUID id; - U32 local_id; - S32 i; - S32 num_objects; - num_objects = mesgsys->getNumberOfBlocksFast(_PREHASH_ObjectData); + U32 ip = mesgsys->getSenderIP(); + U32 port = mesgsys->getSenderPort(); - for (i = 0; i < num_objects; i++) + bool different_region = mesgsys->getSender().getIPandPort() != agent_region->getHost().getIPandPort(); + + S32 num_objects = mesgsys->getNumberOfBlocksFast(_PREHASH_ObjectData); + for (S32 i = 0; i < num_objects; ++i) { + U32 local_id; mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_ID, local_id, i); - LLViewerObjectList::getUUIDFromLocal(id, - local_id, - gMessageSystem->getSenderIP(), - gMessageSystem->getSenderPort()); + LLViewerObjectList::getUUIDFromLocal(id, local_id, ip, port); if (id == LLUUID::null) { LL_DEBUGS("Messaging") << "Unknown kill for local " << local_id << LL_ENDL; - gObjectList.mNumUnknownKills++; + ++gObjectList.mNumUnknownKills; continue; } else @@ -5102,38 +3766,58 @@ void process_kill_object(LLMessageSystem *mesgsys, void **user_data) LL_DEBUGS("Messaging") << "Kill message for local " << local_id << LL_ENDL; } - // ...don't kill the avatar - if (!(id == gAgentID)) + if (id == gAgentID) + { + // never kill our avatar + continue; + } + + LLViewerObject* objectp = gObjectList.findObject(id); + if (objectp) { - LLViewerObject *objectp = gObjectList.findObject(id); - if (objectp) + if (gAgentAvatarp == objectp->getAvatar()) { - // Display green bubble on kill - if ( gShowObjectUpdates ) + if (different_region) { - LLColor4 color(0.f,1.f,0.f,1.f); - gPipeline.addDebugBlip(objectp->getPositionAgent(), color); + LL_WARNS() << "Region other than our own killing our attachments!!" << LL_ENDL; + continue; + } + else if (gAgent.getTeleportState() != LLAgent::TELEPORT_NONE) + { + LL_WARNS() << "Region killing our attachments during teleport!!" << LL_ENDL; + continue; + } + else if (gAgent.isCrossingRegion()) + { + LL_WARNS() << "Region killing our attachments during region cross!!" << LL_ENDL; + continue; } - - // Do the kill - gObjectList.killObject(objectp); } - else + + // Display green bubble on kill + if (gShowObjectUpdates) { - LL_WARNS("Messaging") << "Object in UUID lookup, but not on object list in kill!" << LL_ENDL; - gObjectList.mNumUnknownKills++; + LLColor4 color(0.f, 1.f, 0.f, 1.f); + gPipeline.addDebugBlip(objectp->getPositionAgent(), color); } + + // Do the kill + gObjectList.killObject(objectp); + } + else + { + LL_WARNS("Messaging") << "Object in UUID lookup, but not on object list in kill!" << LL_ENDL; + gObjectList.mNumUnknownKills++; } // We should remove the object from selection after it is marked dead by gObjectList to make LLToolGrab, // which is using the object, release the mouse capture correctly when the object dies. // See LLToolGrab::handleHoverActive() and LLToolGrab::handleHoverNonPhysical(). LLSelectMgr::getInstance()->removeObjectFromSelections(id); - } } -void process_time_synch(LLMessageSystem *mesgsys, void **user_data) +void process_time_synch(LLMessageSystem* mesgsys, void** user_data) { LLVector3 sun_direction; LLVector3 sun_ang_velocity; @@ -5155,7 +3839,7 @@ void process_time_synch(LLMessageSystem *mesgsys, void **user_data) LLWorld::getInstance()->setSpaceTimeUSec(space_time_usec); - LL_DEBUGS("Windlight Sync") << "Sun phase: " << phase << " rad = " << fmodf(phase / F_TWO_PI + 0.25, 1.f) * 24.f << " h" << LL_ENDL; + LL_DEBUGS("WindlightSync") << "Sun phase: " << phase << " rad = " << fmodf(phase / F_TWO_PI + 0.25, 1.f) * 24.f << " h" << LL_ENDL; gSky.setSunPhase(phase); gSky.setSunTargetDirection(sun_direction, sun_ang_velocity); @@ -5165,9 +3849,15 @@ void process_time_synch(LLMessageSystem *mesgsys, void **user_data) } } -void process_sound_trigger(LLMessageSystem *msg, void **) +void process_sound_trigger(LLMessageSystem* msg, void**) { - if (!gAudiop) return; + if (!gAudiop) + { +#if !LL_LINUX + LL_WARNS("AudioEngine") << "LLAudioEngine instance doesn't exist!" << LL_ENDL; +#endif + return; + } U64 region_handle = 0; F32 gain = 0; @@ -5182,18 +3872,19 @@ void process_sound_trigger(LLMessageSystem *msg, void **) msg->getUUIDFast(_PREHASH_SoundData, _PREHASH_ObjectID, object_id); // NaCl - Antispam Registry - static LLCachedControl _NACL_AntiSpamSoundMulti(gSavedSettings,"_NACL_AntiSpamSoundMulti"); - if(owner_id.isNull()) - { - bool bDoSpamCheck=1; - std::string sSound=sound_id.asString(); - for(int i=0;i< COLLISION_SOUNDS_SIZE;i++) - if(COLLISION_SOUNDS[i] == sSound) - bDoSpamCheck=0; - if(bDoSpamCheck) - if(NACLAntiSpamRegistry::checkQueue((U32)NACLAntiSpamRegistry::QUEUE_SOUND,object_id, _NACL_AntiSpamSoundMulti)) return; - } - else if(NACLAntiSpamRegistry::checkQueue((U32)NACLAntiSpamRegistry::QUEUE_SOUND,owner_id, _NACL_AntiSpamSoundMulti)) return; + if (NACLAntiSpamRegistry::instanceExists()) + { + auto& antispam = NACLAntiSpamRegistry::instance(); + static const LLCachedControl _NACL_AntiSpamSoundMulti("_NACL_AntiSpamSoundMulti"); + if (owner_id.isNull()) + { + bool is_collision_sound(const std::string & sound); + if (!is_collision_sound(sound_id.asString()) + && antispam.checkQueue(NACLAntiSpamRegistry::QUEUE_SOUND, object_id, LFIDBearer::OBJECT, _NACL_AntiSpamSoundMulti)) + return; + } + else if (antispam.checkQueue(NACLAntiSpamRegistry::QUEUE_SOUND, owner_id, LFIDBearer::AVATAR, _NACL_AntiSpamSoundMulti)) return; + } // NaCl End msg->getUUIDFast(_PREHASH_SoundData, _PREHASH_ParentID, parent_id); @@ -5225,16 +3916,25 @@ void process_sound_trigger(LLMessageSystem *msg, void **) } // Don't play sounds from a region with maturity above current agent maturity - if( !gAgent.canAccessMaturityInRegion( region_handle ) ) + if (!gAgent.canAccessMaturityInRegion(region_handle)) { return; } // Don't play sounds from gestures if they are not enabled. - if (object_id == owner_id && !gSavedSettings.getBOOL("EnableGestureSounds")) + if (object_id == owner_id) + { + if (!gSavedSettings.getBOOL("EnableGestureSounds")) + { + // Don't mute own gestures, if they're not muted. + if (owner_id != gAgentID || !gSavedSettings.getBOOL("EnableGestureSoundsSelf")) + return; + } + } + else if (!gSavedSettings.getBOOL("EnableNongestureSounds")) { - // Don't mute own gestures, if they're not muted. - if (owner_id != gAgentID || !gSavedSettings.getBOOL("EnableGestureSoundsSelf")) + // Don't mute own non-gestures, if they're not muted. + if (owner_id != gAgentID || !gSavedSettings.getBOOL("EnableNongestureSoundsSelf")) return; } @@ -5244,10 +3944,13 @@ void process_sound_trigger(LLMessageSystem *msg, void **) // } -void process_preload_sound(LLMessageSystem *msg, void **user_data) +void process_preload_sound(LLMessageSystem* msg, void** user_data) { if (!gAudiop) { +#if !LL_LINUX + LL_WARNS("AudioEngine") << "LLAudioEngine instance doesn't exist!" << LL_ENDL; +#endif return; } @@ -5260,24 +3963,26 @@ void process_preload_sound(LLMessageSystem *msg, void **user_data) msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_OwnerID, owner_id); // NaCl - Antispam Registry - static LLCachedControl _NACL_AntiSpamSoundPreloadMulti(gSavedSettings,"_NACL_AntiSpamSoundPreloadMulti"); - if((owner_id.isNull() - && NACLAntiSpamRegistry::checkQueue((U32)NACLAntiSpamRegistry::QUEUE_SOUND_PRELOAD,object_id,_NACL_AntiSpamSoundPreloadMulti)) - || NACLAntiSpamRegistry::checkQueue((U32)NACLAntiSpamRegistry::QUEUE_SOUND_PRELOAD,owner_id,_NACL_AntiSpamSoundPreloadMulti)) - return; + if (NACLAntiSpamRegistry::instanceExists()) + { + auto& antispam = NACLAntiSpamRegistry::instance(); + static const LLCachedControl _NACL_AntiSpamSoundPreloadMulti("_NACL_AntiSpamSoundPreloadMulti"); + if ((owner_id.isNull() + && antispam.checkQueue(NACLAntiSpamRegistry::QUEUE_SOUND_PRELOAD, object_id, LFIDBearer::OBJECT, _NACL_AntiSpamSoundPreloadMulti)) + || antispam.checkQueue(NACLAntiSpamRegistry::QUEUE_SOUND_PRELOAD, owner_id, LFIDBearer::AVATAR, _NACL_AntiSpamSoundPreloadMulti)) + return; + } // NaCl End - LLViewerObject *objectp = gObjectList.findObject(object_id); + LLViewerObject* objectp = gObjectList.findObject(object_id); if (!objectp) return; if (LLMuteList::getInstance()->isMuted(object_id)) return; if (LLMuteList::getInstance()->isMuted(owner_id, LLMute::flagObjectSounds)) return; - LLAudioSource *sourcep = objectp->getAudioSource(owner_id); + LLAudioSource* sourcep = objectp->getAudioSource(owner_id); if (!sourcep) return; - LLAudioData *datap = gAudiop->getAudioData(sound_id); - // Note that I don't actually do any loading of the // audio data into a buffer at this point, as it won't actually // help us out. @@ -5286,12 +3991,12 @@ void process_preload_sound(LLMessageSystem *msg, void **user_data) LLVector3d pos_global = objectp->getPositionGlobal(); if (gAgent.canAccessMaturityAtGlobal(pos_global)) { - // Add audioData starts a transfer internally. - sourcep->addAudioData(datap, FALSE); + // Preload starts a transfer internally. + sourcep->preload(sound_id); } } -void process_attached_sound(LLMessageSystem *msg, void **user_data) +void process_attached_sound(LLMessageSystem* msg, void** user_data) { F32 gain = 0; LLUUID sound_id; @@ -5304,43 +4009,47 @@ void process_attached_sound(LLMessageSystem *msg, void **user_data) msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_OwnerID, owner_id); // NaCl - Antispam Registry - if((owner_id.isNull() - && NACLAntiSpamRegistry::checkQueue((U32)NACLAntiSpamRegistry::QUEUE_SOUND,object_id)) - || NACLAntiSpamRegistry::checkQueue((U32)NACLAntiSpamRegistry::QUEUE_SOUND,owner_id)) - return; + if (NACLAntiSpamRegistry::instanceExists()) + { + auto& antispam = NACLAntiSpamRegistry::instance(); + if ((owner_id.isNull() + && antispam.checkQueue(NACLAntiSpamRegistry::QUEUE_SOUND, object_id, LFIDBearer::OBJECT)) + || antispam.checkQueue(NACLAntiSpamRegistry::QUEUE_SOUND, owner_id)) + return; + } // NaCl End msg->getF32Fast(_PREHASH_DataBlock, _PREHASH_Gain, gain); msg->getU8Fast(_PREHASH_DataBlock, _PREHASH_Flags, flags); LLViewerObject *objectp = gObjectList.findObject(object_id); - if (!objectp) + if (objectp) { - // we don't know about this object, just bail - return; + set_attached_sound(objectp, object_id, sound_id, owner_id, gain, flags); } - - if (LLMuteList::getInstance()->isMuted(object_id)) return; - - if (LLMuteList::getInstance()->isMuted(owner_id, LLMute::flagObjectSounds)) return; - - - // Don't play sounds from a region with maturity above current agent maturity - LLVector3d pos = objectp->getPositionGlobal(); - if( !gAgent.canAccessMaturityAtGlobal(pos) ) + else if (sound_id.notNull()) { - return; + // we don't know about this object yet, probably it has yet to arrive + // std::map for dupplicate prevention. + if (!LLMuteList::getInstance()->isMuted(object_id) && !LLMuteList::getInstance()->isMuted(owner_id, LLMute::flagObjectSounds)) + postponed_sounds[object_id] = (PostponedSoundData(object_id, sound_id, owner_id, gain, flags)); + clear_expired_postponed_sounds(); + } + else + { + std::map::iterator iter = postponed_sounds.find(object_id); + if (iter != postponed_sounds.end()) + { + postponed_sounds.erase(iter); + } } - - objectp->setAttachedSound(sound_id, owner_id, gain, flags); } - void process_attached_sound_gain_change(LLMessageSystem *mesgsys, void **user_data) { F32 gain = 0; LLUUID object_guid; - LLViewerObject *objectp = NULL; + LLViewerObject* objectp = nullptr; mesgsys->getUUIDFast(_PREHASH_DataBlock, _PREHASH_ObjectID, object_guid); @@ -5356,7 +4065,7 @@ void process_attached_sound_gain_change(LLMessageSystem *mesgsys, void **user_da } -void process_health_message(LLMessageSystem *mesgsys, void **user_data) +void process_health_message(LLMessageSystem* mesgsys, void** user_data) { F32 health; @@ -5369,8 +4078,50 @@ void process_health_message(LLMessageSystem *mesgsys, void **user_data) } -void process_sim_stats(LLMessageSystem *msg, void **user_data) -{ +void process_sim_stats(LLMessageSystem* msg, void** user_data) +{ + static LLHost sLastHost; + auto& stats = LLViewerStats::instance(); + if (msg->getSender() != sLastHost) + { + sLastHost = msg->getSender(); + stats.mSimTimeDilation.reset(); + stats.mSimFPS.reset(); + stats.mSimPhysicsFPS.reset(); + stats.mSimAgentUPS.reset(); + stats.mSimFrameMsec.reset(); + stats.mSimNetMsec.reset(); + stats.mSimSimOtherMsec.reset(); + stats.mSimSimPhysicsMsec.reset(); + stats.mSimAgentMsec.reset(); + stats.mSimImagesMsec.reset(); + stats.mSimScriptMsec.reset(); + stats.mSimObjects.reset(); + stats.mSimActiveObjects.reset(); + stats.mSimMainAgents.reset(); + stats.mSimChildAgents.reset(); + stats.mSimActiveScripts.reset(); + stats.mSimScriptEPS.reset(); + stats.mSimInPPS.reset(); + stats.mSimOutPPS.reset(); + stats.mSimPendingDownloads.reset(); + stats.mSimPendingUploads.reset(); + stats.mSimPendingLocalUploads.reset(); + stats.mSimTotalUnackedBytes.reset(); + stats.mPhysicsPinnedTasks.reset(); + stats.mPhysicsLODTasks.reset(); + stats.mSimSimPhysicsStepMsec.reset(); + stats.mSimSimPhysicsShapeUpdateMsec.reset(); + stats.mSimSimPhysicsOtherMsec.reset(); + stats.mPhysicsMemoryAllocated.reset(); + stats.mSimSpareMsec.reset(); + stats.mSimSleepMsec.reset(); + stats.mSimPumpIOMsec.reset(); + stats.mSimPctScriptsRun.reset(); + stats.mSimSimAIStepMsec.reset(); + stats.mSimSimSkippedSilhouetteSteps.reset(); + stats.mSimSimPctSteppedCharacters.reset(); + } S32 count = msg->getNumberOfBlocks("Stat"); for (S32 i = 0; i < count; ++i) { @@ -5381,131 +4132,128 @@ void process_sim_stats(LLMessageSystem *msg, void **user_data) switch (stat_id) { case LL_SIM_STAT_TIME_DILATION: - LLViewerStats::getInstance()->mSimTimeDilation.addValue(stat_value); + stats.mSimTimeDilation.addValue(stat_value); break; case LL_SIM_STAT_FPS: - LLViewerStats::getInstance()->mSimFPS.addValue(stat_value); + stats.mSimFPS.addValue(stat_value); break; case LL_SIM_STAT_PHYSFPS: - LLViewerStats::getInstance()->mSimPhysicsFPS.addValue(stat_value); + stats.mSimPhysicsFPS.addValue(stat_value); break; case LL_SIM_STAT_AGENTUPS: - LLViewerStats::getInstance()->mSimAgentUPS.addValue(stat_value); + stats.mSimAgentUPS.addValue(stat_value); break; case LL_SIM_STAT_FRAMEMS: - LLViewerStats::getInstance()->mSimFrameMsec.addValue(stat_value); + stats.mSimFrameMsec.addValue(stat_value); break; case LL_SIM_STAT_NETMS: - LLViewerStats::getInstance()->mSimNetMsec.addValue(stat_value); + stats.mSimNetMsec.addValue(stat_value); break; case LL_SIM_STAT_SIMOTHERMS: - LLViewerStats::getInstance()->mSimSimOtherMsec.addValue(stat_value); + stats.mSimSimOtherMsec.addValue(stat_value); break; case LL_SIM_STAT_SIMPHYSICSMS: - LLViewerStats::getInstance()->mSimSimPhysicsMsec.addValue(stat_value); + stats.mSimSimPhysicsMsec.addValue(stat_value); break; case LL_SIM_STAT_AGENTMS: - LLViewerStats::getInstance()->mSimAgentMsec.addValue(stat_value); + stats.mSimAgentMsec.addValue(stat_value); break; case LL_SIM_STAT_IMAGESMS: - LLViewerStats::getInstance()->mSimImagesMsec.addValue(stat_value); + stats.mSimImagesMsec.addValue(stat_value); break; case LL_SIM_STAT_SCRIPTMS: - LLViewerStats::getInstance()->mSimScriptMsec.addValue(stat_value); + stats.mSimScriptMsec.addValue(stat_value); break; case LL_SIM_STAT_NUMTASKS: - LLViewerStats::getInstance()->mSimObjects.addValue(stat_value); + stats.mSimObjects.addValue(stat_value); break; case LL_SIM_STAT_NUMTASKSACTIVE: - LLViewerStats::getInstance()->mSimActiveObjects.addValue(stat_value); + stats.mSimActiveObjects.addValue(stat_value); break; case LL_SIM_STAT_NUMAGENTMAIN: - LLViewerStats::getInstance()->mSimMainAgents.addValue(stat_value); + stats.mSimMainAgents.addValue(stat_value); break; case LL_SIM_STAT_NUMAGENTCHILD: - LLViewerStats::getInstance()->mSimChildAgents.addValue(stat_value); + stats.mSimChildAgents.addValue(stat_value); break; case LL_SIM_STAT_NUMSCRIPTSACTIVE: if (gSavedSettings.getBOOL("AscentDisplayTotalScriptJumps")) { - if(abs(stat_value-gSavedSettings.getF32("Ascentnumscripts"))>gSavedSettings.getF32("Ascentnumscriptdiff")) + auto control = gSavedSettings.getControl("Ascentnumscripts"); + const auto& numscripts = control->get().asFloat(); + if(abs(stat_value-numscripts)>gSavedSettings.getF32("Ascentnumscriptdiff")) { - LLChat chat; std::stringstream os; - os << (U32)gSavedSettings.getF32("Ascentnumscripts"); - std::stringstream ns; - ns << (U32)stat_value; - std::stringstream diff; - S32 tdiff = (stat_value-gSavedSettings.getF32("Ascentnumscripts")); - diff << tdiff; - std::string change_type = ""; - if (tdiff > 0) change_type = "+"; - chat.mText = "Total scripts jumped from " + os.str() + " to " + ns.str() + " ("+change_type+diff.str()+")"; - LLFloaterChat::addChat(chat, FALSE,FALSE); + os << (U32)numscripts << " to " << (U32)stat_value << " ("; + const S32 tdiff = stat_value - numscripts; + if (tdiff > 0) os << "+"; + os << tdiff << ')'; + LLChat chat("Total scripts jumped from " + os.str()); + LLFloaterChat::addChat(chat, FALSE, FALSE); } - gSavedSettings.setF32("Ascentnumscripts",stat_value); + control->set(stat_value); } - LLViewerStats::getInstance()->mSimActiveScripts.addValue(stat_value); + stats.mSimActiveScripts.addValue(stat_value); break; case LL_SIM_STAT_SCRIPT_EPS: - LLViewerStats::getInstance()->mSimScriptEPS.addValue(stat_value); + stats.mSimScriptEPS.addValue(stat_value); break; case LL_SIM_STAT_INPPS: - LLViewerStats::getInstance()->mSimInPPS.addValue(stat_value); + stats.mSimInPPS.addValue(stat_value); break; case LL_SIM_STAT_OUTPPS: - LLViewerStats::getInstance()->mSimOutPPS.addValue(stat_value); + stats.mSimOutPPS.addValue(stat_value); break; case LL_SIM_STAT_PENDING_DOWNLOADS: - LLViewerStats::getInstance()->mSimPendingDownloads.addValue(stat_value); + stats.mSimPendingDownloads.addValue(stat_value); break; case LL_SIM_STAT_PENDING_UPLOADS: - LLViewerStats::getInstance()->mSimPendingUploads.addValue(stat_value); + stats.mSimPendingUploads.addValue(stat_value); break; case LL_SIM_STAT_PENDING_LOCAL_UPLOADS: - LLViewerStats::getInstance()->mSimPendingLocalUploads.addValue(stat_value); + stats.mSimPendingLocalUploads.addValue(stat_value); break; case LL_SIM_STAT_TOTAL_UNACKED_BYTES: - LLViewerStats::getInstance()->mSimTotalUnackedBytes.addValue(stat_value / 1024.f); + stats.mSimTotalUnackedBytes.addValue(stat_value / 1024.f); break; case LL_SIM_STAT_PHYSICS_PINNED_TASKS: - LLViewerStats::getInstance()->mPhysicsPinnedTasks.addValue(stat_value); + stats.mPhysicsPinnedTasks.addValue(stat_value); break; case LL_SIM_STAT_PHYSICS_LOD_TASKS: - LLViewerStats::getInstance()->mPhysicsLODTasks.addValue(stat_value); + stats.mPhysicsLODTasks.addValue(stat_value); break; case LL_SIM_STAT_SIMPHYSICSSTEPMS: - LLViewerStats::getInstance()->mSimSimPhysicsStepMsec.addValue(stat_value); + stats.mSimSimPhysicsStepMsec.addValue(stat_value); break; case LL_SIM_STAT_SIMPHYSICSSHAPEMS: - LLViewerStats::getInstance()->mSimSimPhysicsShapeUpdateMsec.addValue(stat_value); + stats.mSimSimPhysicsShapeUpdateMsec.addValue(stat_value); break; case LL_SIM_STAT_SIMPHYSICSOTHERMS: - LLViewerStats::getInstance()->mSimSimPhysicsOtherMsec.addValue(stat_value); + stats.mSimSimPhysicsOtherMsec.addValue(stat_value); break; case LL_SIM_STAT_SIMPHYSICSMEMORY: - LLViewerStats::getInstance()->mPhysicsMemoryAllocated.addValue(stat_value); + stats.mPhysicsMemoryAllocated.addValue(stat_value); break; case LL_SIM_STAT_SIMSPARETIME: - LLViewerStats::getInstance()->mSimSpareMsec.addValue(stat_value); + stats.mSimSpareMsec.addValue(stat_value); break; case LL_SIM_STAT_SIMSLEEPTIME: - LLViewerStats::getInstance()->mSimSleepMsec.addValue(stat_value); + stats.mSimSleepMsec.addValue(stat_value); break; case LL_SIM_STAT_IOPUMPTIME: - LLViewerStats::getInstance()->mSimPumpIOMsec.addValue(stat_value); + stats.mSimPumpIOMsec.addValue(stat_value); break; case LL_SIM_STAT_PCTSCRIPTSRUN: - LLViewerStats::getInstance()->mSimPctScriptsRun.addValue(stat_value); + stats.mSimPctScriptsRun.addValue(stat_value); break; case LL_SIM_STAT_SIMAISTEPTIMEMS: - LLViewerStats::getInstance()->mSimSimAIStepMsec.addValue(stat_value); + stats.mSimSimAIStepMsec.addValue(stat_value); break; case LL_SIM_STAT_SKIPPEDAISILSTEPS_PS: - LLViewerStats::getInstance()->mSimSimSkippedSilhouetteSteps.addValue(stat_value); + stats.mSimSimSkippedSilhouetteSteps.addValue(stat_value); break; case LL_SIM_STAT_PCTSTEPPEDCHARACTERS: - LLViewerStats::getInstance()->mSimSimPctSteppedCharacters.addValue(stat_value); + stats.mSimSimPctSteppedCharacters.addValue(stat_value); break; default: // Used to be a commented out warning. @@ -5514,28 +4262,6 @@ void process_sim_stats(LLMessageSystem *msg, void **user_data) } } - /* - msg->getF32Fast(_PREHASH_Statistics, _PREHASH_PhysicsTimeDilation, time_dilation); - LLViewerStats::getInstance()->mSimTDStat.addValue(time_dilation); - - // Process information - // { CpuUsage F32 } - // { SimMemTotal F32 } - // { SimMemRSS F32 } - // { ProcessUptime F32 } - F32 cpu_usage; - F32 sim_mem_total; - F32 sim_mem_rss; - F32 process_uptime; - msg->getF32Fast(_PREHASH_Statistics, _PREHASH_CpuUsage, cpu_usage); - msg->getF32Fast(_PREHASH_Statistics, _PREHASH_SimMemTotal, sim_mem_total); - msg->getF32Fast(_PREHASH_Statistics, _PREHASH_SimMemRSS, sim_mem_rss); - msg->getF32Fast(_PREHASH_Statistics, _PREHASH_ProcessUptime, process_uptime); - LLViewerStats::getInstance()->mSimCPUUsageStat.addValue(cpu_usage); - LLViewerStats::getInstance()->mSimMemTotalStat.addValue(sim_mem_total); - LLViewerStats::getInstance()->mSimMemRSSStat.addValue(sim_mem_rss); - */ - // // Various hacks that aren't statistics, but are being handled here. // @@ -5570,16 +4296,14 @@ void process_sim_stats(LLMessageSystem *msg, void **user_data) } - -void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data) +void process_avatar_animation(LLMessageSystem* mesgsys, void** user_data) { LLUUID animation_id; LLUUID uuid; S32 anim_sequence_id; - + mesgsys->getUUIDFast(_PREHASH_Sender, _PREHASH_ID, uuid); - //clear animation flags LLVOAvatar* avatarp = gObjectList.findAvatar(uuid); if (!avatarp) @@ -5592,19 +4316,20 @@ void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data) S32 num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_AnimationList); S32 num_source_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_AnimationSourceList); + LL_DEBUGS("Messaging", "Motion") << "Processing " << num_blocks << " Animations" << LL_ENDL; + + //clear animation flags avatarp->mSignaledAnimations.clear(); if (avatarp->isSelf()) { LLUUID object_id; - for( S32 i = 0; i < num_blocks; i++ ) + for (S32 i = 0; i < num_blocks; i++) { mesgsys->getUUIDFast(_PREHASH_AnimationList, _PREHASH_AnimID, animation_id, i); mesgsys->getS32Fast(_PREHASH_AnimationList, _PREHASH_AnimSequenceID, anim_sequence_id, i); - LL_DEBUGS("Messaging") << "Anim sequence ID: " << anim_sequence_id << LL_ENDL; - avatarp->mSignaledAnimations[animation_id] = anim_sequence_id; // *HACK: Disabling flying mode if it has been enabled shortly before the agent @@ -5629,7 +4354,7 @@ void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data) BOOL anim_found = FALSE; LLVOAvatar::AnimSourceIterator anim_it = avatarp->mAnimationSources.find(object_id); - for (;anim_it != avatarp->mAnimationSources.end(); ++anim_it) + for (; anim_it != avatarp->mAnimationSources.end(); ++anim_it) { if (anim_it->second == animation_id) { @@ -5643,12 +4368,20 @@ void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data) avatarp->mAnimationSources.insert(LLVOAvatar::AnimationSourceMap::value_type(object_id, animation_id)); } } + LL_DEBUGS("Messaging", "Motion") << "Anim sequence ID: " << anim_sequence_id + << " Animation id: " << animation_id + << " From block: " << object_id << LL_ENDL; + } + else + { + LL_DEBUGS("Messaging", "Motion") << "Anim sequence ID: " << anim_sequence_id + << " Animation id: " << animation_id << LL_ENDL; } } } else { - for( S32 i = 0; i < num_blocks; i++ ) + for (S32 i = 0; i < num_blocks; i++) { mesgsys->getUUIDFast(_PREHASH_AnimationList, _PREHASH_AnimID, animation_id, i); mesgsys->getS32Fast(_PREHASH_AnimationList, _PREHASH_AnimSequenceID, anim_sequence_id, i); @@ -5656,13 +4389,79 @@ void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data) } } - if (num_blocks) + //if (num_blocks) Singu note: commented out; having blocks or not is totally irrelevant! { avatarp->processAnimationStateChanges(); } } -void process_avatar_appearance(LLMessageSystem *mesgsys, void **user_data) + +void process_object_animation(LLMessageSystem *mesgsys, void **user_data) +{ + LLUUID animation_id; + LLUUID uuid; + S32 anim_sequence_id; + + mesgsys->getUUIDFast(_PREHASH_Sender, _PREHASH_ID, uuid); + + LL_DEBUGS("AnimatedObjectsNotify") << "Received animation state for object " << uuid << LL_ENDL; + + signaled_animation_map_t signaled_anims; + S32 num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_AnimationList); + LL_DEBUGS("AnimatedObjectsNotify") << "processing object animation requests, num_blocks " << num_blocks << " uuid " << uuid << LL_ENDL; + for( S32 i = 0; i < num_blocks; i++ ) + { + mesgsys->getUUIDFast(_PREHASH_AnimationList, _PREHASH_AnimID, animation_id, i); + mesgsys->getS32Fast(_PREHASH_AnimationList, _PREHASH_AnimSequenceID, anim_sequence_id, i); + signaled_anims[animation_id] = anim_sequence_id; + LL_DEBUGS("AnimatedObjectsNotify") << "added signaled_anims animation request for object " + << uuid << " animation id " << animation_id << LL_ENDL; + } + LLObjectSignaledAnimationMap::instance().getMap()[uuid] = signaled_anims; + + LLViewerObject *objp = gObjectList.findObject(uuid); + if (!objp) + { + LL_DEBUGS("AnimatedObjectsNotify") << "Received animation state for unknown object " << uuid << LL_ENDL; + return; + } + + LLVOVolume *volp = objp->asVolume(); + if (!volp) + { + LL_DEBUGS("AnimatedObjectsNotify") << "Received animation state for non-volume object " << uuid << LL_ENDL; + return; + } + + if (!volp->isAnimatedObject()) + { + LL_DEBUGS("AnimatedObjectsNotify") << "Received animation state for non-animated object " << uuid << LL_ENDL; + return; + } + + volp->updateControlAvatar(); + LLControlAvatar *avatarp = volp->getControlAvatar(); + if (!avatarp) + { + LL_DEBUGS("AnimatedObjectsNotify") << "Received animation request for object with no control avatar, ignoring " << uuid << LL_ENDL; + return; + } + + if (!avatarp->mPlaying) + { + avatarp->mPlaying = true; + //if (!avatarp->mRootVolp->isAnySelected()) + { + avatarp->updateVolumeGeom(); + avatarp->mRootVolp->recursiveMarkForUpdate(TRUE); + } + } + + avatarp->updateAnimations(); +} + + +void process_avatar_appearance(LLMessageSystem* mesgsys, void** user_data) { LLUUID uuid; mesgsys->getUUIDFast(_PREHASH_Sender, _PREHASH_ID, uuid); @@ -5670,7 +4469,7 @@ void process_avatar_appearance(LLMessageSystem *mesgsys, void **user_data) LLVOAvatar* avatarp = gObjectList.findAvatar(uuid); if (avatarp) { - avatarp->processAvatarAppearance( mesgsys ); + avatarp->processAvatarAppearance(mesgsys); } else { @@ -5678,15 +4477,19 @@ void process_avatar_appearance(LLMessageSystem *mesgsys, void **user_data) } } -void process_camera_constraint(LLMessageSystem *mesgsys, void **user_data) +void process_camera_constraint(LLMessageSystem* mesgsys, void** user_data) { + static LLCachedControl disableSimConst(gSavedSettings, "AlchemyDisableSimCamConstraint"); + if (disableSimConst) + return; + LLVector4 cameraCollidePlane; mesgsys->getVector4Fast(_PREHASH_CameraCollidePlane, _PREHASH_Plane, cameraCollidePlane); gAgentCamera.setCameraCollidePlane(cameraCollidePlane); } -void near_sit_object(BOOL success, void *data) +void near_sit_object(BOOL success, void* data) { if (success) { @@ -5699,7 +4502,7 @@ void near_sit_object(BOOL success, void *data) } } -void process_avatar_sit_response(LLMessageSystem *mesgsys, void **user_data) +void process_avatar_sit_response(LLMessageSystem* mesgsys, void** user_data) { LLVector3 sitPosition; LLQuaternion sitRotation; @@ -5725,8 +4528,7 @@ void process_avatar_sit_response(LLMessageSystem *mesgsys, void **user_data) // Forcing turning off flying here to prevent flying after pressing "Stand" // to stand up from an object. See EXT-1655. // Unless the user wants to. - static LLCachedControl ContinueFlying("LiruContinueFlyingOnUnsit"); - if (!ContinueFlying) + if (!gSavedSettings.getBOOL("LiruContinueFlyingOnUnsit")) gAgent.setFlying(FALSE); LLViewerObject* object = gObjectList.findObject(sitObjectID); @@ -5739,7 +4541,7 @@ void process_avatar_sit_response(LLMessageSystem *mesgsys, void **user_data) } else { - gAgent.startAutoPilotGlobal(gAgent.getPosGlobalFromAgent(sit_spot), "Sit", &sitRotation, near_sit_object, NULL, 0.5f); + gAgent.startAutoPilotGlobal(gAgent.getPosGlobalFromAgent(sit_spot), "Sit", &sitRotation, near_sit_object, nullptr, 0.5f); } } else @@ -5748,7 +4550,7 @@ void process_avatar_sit_response(LLMessageSystem *mesgsys, void **user_data) } } -void process_clear_follow_cam_properties(LLMessageSystem *mesgsys, void **user_data) +void process_clear_follow_cam_properties(LLMessageSystem* mesgsys, void** user_data) { LLUUID source_id; @@ -5757,7 +4559,7 @@ void process_clear_follow_cam_properties(LLMessageSystem *mesgsys, void **user_d LLFollowCamMgr::removeFollowCamParams(source_id); } -void process_set_follow_cam_properties(LLMessageSystem *mesgsys, void **user_data) +void process_set_follow_cam_properties(LLMessageSystem* mesgsys, void** user_data) { S32 type; F32 value; @@ -5783,7 +4585,7 @@ void process_set_follow_cam_properties(LLMessageSystem *mesgsys, void **user_dat { mesgsys->getS32("CameraProperty", "Type", type, block_index); mesgsys->getF32("CameraProperty", "Value", value, block_index); - switch(type) + switch (type) { case FOLLOWCAM_PITCH: LLFollowCamMgr::setPitch(source_id, value); @@ -5827,27 +4629,27 @@ void process_set_follow_cam_properties(LLMessageSystem *mesgsys, void **user_dat break; case FOLLOWCAM_POSITION_X: settingPosition = true; - position.mV[ 0 ] = value; + position.mV[0] = value; break; case FOLLOWCAM_POSITION_Y: settingPosition = true; - position.mV[ 1 ] = value; + position.mV[1] = value; break; case FOLLOWCAM_POSITION_Z: settingPosition = true; - position.mV[ 2 ] = value; + position.mV[2] = value; break; case FOLLOWCAM_FOCUS_X: settingFocus = true; - focus.mV[ 0 ] = value; + focus.mV[0] = value; break; case FOLLOWCAM_FOCUS_Y: settingFocus = true; - focus.mV[ 1 ] = value; + focus.mV[1] = value; break; case FOLLOWCAM_FOCUS_Z: settingFocus = true; - focus.mV[ 2 ] = value; + focus.mV[2] = value; break; case FOLLOWCAM_POSITION_LOCKED: LLFollowCamMgr::setPositionLocked(source_id, value != 0.f); @@ -5861,24 +4663,25 @@ void process_set_follow_cam_properties(LLMessageSystem *mesgsys, void **user_dat } } - if ( settingPosition ) + if (settingPosition) { LLFollowCamMgr::setPosition(source_id, position); } - if ( settingFocus ) + if (settingFocus) { LLFollowCamMgr::setFocus(source_id, focus); } - if ( settingFocusOffset ) + if (settingFocusOffset) { LLFollowCamMgr::setFocusOffset(source_id, focus_offset); } } + //end Ventrella // Culled from newsim lltask.cpp -void process_name_value(LLMessageSystem *mesgsys, void **user_data) +void process_name_value(LLMessageSystem* mesgsys, void** user_data) { std::string temp_str; LLUUID id; @@ -5904,7 +4707,7 @@ void process_name_value(LLMessageSystem *mesgsys, void **user_data) } } -void process_remove_name_value(LLMessageSystem *mesgsys, void **user_data) +void process_remove_name_value(LLMessageSystem* mesgsys, void** user_data) { std::string temp_str; LLUUID id; @@ -5930,7 +4733,7 @@ void process_remove_name_value(LLMessageSystem *mesgsys, void **user_data) } } -void process_kick_user(LLMessageSystem *msg, void** /*user_data*/) +void process_kick_user(LLMessageSystem* msg, void** /*user_data*/) { std::string message; @@ -5993,7 +4796,7 @@ void process_time_dilation(LLMessageSystem *msg, void **user_data) */ -void process_money_balance_reply( LLMessageSystem* msg, void** ) +void process_money_balance_reply(LLMessageSystem* msg, void**) { S32 balance = 0; S32 credit = 0; @@ -6050,7 +4853,7 @@ void process_money_balance_reply( LLMessageSystem* msg, void** ) // off the beginning. const U32 MAX_LOOKBACK = 30; const S32 POP_FRONT_SIZE = 12; - if(recent.size() > MAX_LOOKBACK) + if (recent.size() > MAX_LOOKBACK) { LL_DEBUGS("Messaging") << "Removing oldest transaction records" << LL_ENDL; recent.erase(recent.begin(), recent.begin() + POP_FRONT_SIZE); @@ -6112,54 +4915,23 @@ static std::string reason_from_transaction_type(S32 transaction_type, case TRANS_CLASSIFIED_CHARGE: return LLTrans::getString("to publish a classified ad"); + case TRANS_GIFT: + // Simulator returns "Payment" if no custom description has been entered + return (item_desc == "Payment" ? std::string() : item_desc); + // These have no reason to display, but are expected and should not // generate warnings - case TRANS_GIFT: case TRANS_PAY_OBJECT: case TRANS_OBJECT_PAYS: return std::string(); default: - llwarns << "Unknown transaction type " - << transaction_type << llendl; + LL_WARNS() << "Unknown transaction type " + << transaction_type << LL_ENDL; return std::string(); } } -static void money_balance_group_notify(const LLUUID& group_id, - const std::string& name, - bool is_group, - std::string message, - LLStringUtil::format_map_t args, - LLSD payload) -{ - bool no_transaction_clutter = gSavedSettings.getBOOL("LiruNoTransactionClutter"); - std::string notification = no_transaction_clutter ? "Payment" : "SystemMessage"; - args["NAME"] = name; - LLSD msg_args; - msg_args["MESSAGE"] = LLTrans::getString(message,args); - LLNotificationsUtil::add(notification,msg_args,payload); - - if (!no_transaction_clutter) LLFloaterChat::addChat(msg_args["MESSAGE"].asString()); // Alerts won't automatically log to chat. -} - -static void money_balance_avatar_notify(const LLUUID& agent_id, - const LLAvatarName& av_name, - std::string message, - LLStringUtil::format_map_t args, - LLSD payload) -{ - bool no_transaction_clutter = gSavedSettings.getBOOL("LiruNoTransactionClutter"); - std::string notification = no_transaction_clutter ? "Payment" : "SystemMessage"; - std::string name; - LLAvatarNameCache::getPNSName(av_name,name); - args["NAME"] = name; - LLSD msg_args; - msg_args["MESSAGE"] = LLTrans::getString(message,args); - LLNotificationsUtil::add(notification,msg_args,payload); - - if (!no_transaction_clutter) LLFloaterChat::addChat(msg_args["MESSAGE"].asString()); // Alerts won't automatically log to chat. -} static void process_money_balance_reply_extended(LLMessageSystem* msg) { // Added in server 1.40 and viewer 2.1, support for localization @@ -6192,6 +4964,8 @@ static void process_money_balance_reply_extended(LLMessageSystem* msg) return; } + if ((U32)amount < gSavedSettings.getU32("LiruShowTransactionThreshold")) return; // Don't show transactions of small amounts the user doesn't care about. + std::string reason = reason_from_transaction_type(transaction_type, item_description); @@ -6207,6 +4981,7 @@ static void process_money_balance_reply_extended(LLMessageSystem* msg) LLSD payload; bool you_paid_someone = (source_id == gAgentID); + std::string gift_suffix = (transaction_type == TRANS_GIFT ? "_gift" : ""); if (you_paid_someone) { is_name_group = is_dest_group; @@ -6215,8 +4990,8 @@ static void process_money_balance_reply_extended(LLMessageSystem* msg) { if (dest_id.notNull()) { - message = success ? "you_paid_ldollars" : - "you_paid_failure_ldollars"; + message = success ? "you_paid_ldollars" + gift_suffix : + "you_paid_failure_ldollars" + gift_suffix; } else { @@ -6247,7 +5022,7 @@ static void process_money_balance_reply_extended(LLMessageSystem* msg) name_id = source_id; if (!reason.empty()) { - message = "paid_you_ldollars"; + message = "paid_you_ldollars" + gift_suffix; } else { @@ -6256,24 +5031,23 @@ static void process_money_balance_reply_extended(LLMessageSystem* msg) // make notification loggable payload["from_id"] = source_id; + + void script_msg_api(const std::string& msg); + if (!is_source_group) script_msg_api(source_id.asString() + ", 7"); } // Despite using SLURLs, wait until the name is available before // showing the notification, otherwise the UI layout is strange and // the user sees a "Loading..." message - if (is_name_group) - { - gCacheName->getGroup(name_id, - boost::bind(&money_balance_group_notify, - _1, _2, _3, message, - args, payload)); - } - else { - LLAvatarNameCache::get(name_id, - boost::bind(&money_balance_avatar_notify, - _1, _2, message, - args, payload)); - } + // Singu Note: Wat? SLURLs resolve over time, not the end of the world. + bool no_transaction_clutter = gSavedSettings.getBOOL("LiruNoTransactionClutter"); + std::string notification = no_transaction_clutter ? "Payment" : "SystemMessage"; + args["NAME"] = is_name_group ? LLGroupActions::getSLURL(name_id) : LLAvatarActions::getSLURL(name_id); + LLSD msg_args; + msg_args["MESSAGE"] = LLTrans::getString(message,args); + LLNotificationsUtil::add(notification,msg_args,payload); + + if (!no_transaction_clutter) LLFloaterChat::addChat(msg_args["MESSAGE"].asString()); // Alerts won't automatically log to chat. } bool handle_prompt_for_maturity_level_change_callback(const LLSD& notification, const LLSD& response) @@ -6313,148 +5087,224 @@ bool handle_prompt_for_maturity_level_change_and_reteleport_callback(const LLSD& // some of the server notifications need special handling. This is where we do that. bool handle_special_notification(std::string notificationID, LLSD& llsdBlock) { - U8 regionAccess = static_cast(llsdBlock["_region_access"].asInteger()); - std::string regionMaturity = LLViewerRegion::accessToString(regionAccess); - LLStringUtil::toLower(regionMaturity); - llsdBlock["REGIONMATURITY"] = regionMaturity; - bool returnValue = false; - LLNotificationPtr maturityLevelNotification; - std::string notifySuffix = "_Notify"; - if (regionAccess == SIM_ACCESS_MATURE) + if (llsdBlock.has("_region_access")) { - if (gAgent.isTeen()) + U8 regionAccess = static_cast(llsdBlock["_region_access"].asInteger()); + std::string regionMaturity = LLViewerRegion::accessToString(regionAccess); + LLStringUtil::toLower(regionMaturity); + llsdBlock["REGIONMATURITY"] = regionMaturity; + LLNotificationPtr maturityLevelNotification; + std::string notifySuffix = "_Notify"; + if (regionAccess == SIM_ACCESS_MATURE) { - gAgent.clearTeleportRequest(); - maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_AdultsOnlyContent", llsdBlock); - returnValue = true; + if (gAgent.isTeen()) + { + gAgent.clearTeleportRequest(); + maturityLevelNotification = LLNotificationsUtil::add(notificationID + "_AdultsOnlyContent", llsdBlock); + returnValue = true; - notifySuffix = "_NotifyAdultsOnly"; + notifySuffix = "_NotifyAdultsOnly"; + } + else if (gAgent.prefersPG()) + { + maturityLevelNotification = LLNotificationsUtil::add(notificationID + "_Change", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); + returnValue = true; + } + else if (LLStringUtil::compareStrings(notificationID, "RegionEntryAccessBlocked") == 0) + { + maturityLevelNotification = LLNotificationsUtil::add(notificationID + "_PreferencesOutOfSync", llsdBlock, llsdBlock); + returnValue = true; + } } - else if (gAgent.prefersPG()) + else if (regionAccess == SIM_ACCESS_ADULT) { - maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_Change", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); - returnValue = true; + if (!gAgent.isAdult()) + { + gAgent.clearTeleportRequest(); + maturityLevelNotification = LLNotificationsUtil::add(notificationID + "_AdultsOnlyContent", llsdBlock); + returnValue = true; + + notifySuffix = "_NotifyAdultsOnly"; + } + else if (gAgent.prefersPG() || gAgent.prefersMature()) + { + maturityLevelNotification = LLNotificationsUtil::add(notificationID + "_Change", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); + returnValue = true; + } + else if (LLStringUtil::compareStrings(notificationID, "RegionEntryAccessBlocked") == 0) + { + maturityLevelNotification = LLNotificationsUtil::add(notificationID + "_PreferencesOutOfSync", llsdBlock, llsdBlock); + returnValue = true; + } } - else if (LLStringUtil::compareStrings(notificationID, "RegionEntryAccessBlocked") == 0) + + if ((maturityLevelNotification == nullptr) || maturityLevelNotification->isIgnored()) { - maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_PreferencesOutOfSync", llsdBlock, llsdBlock); - returnValue = true; + // Given a simple notification if no maturityLevelNotification is set or it is ignore + LLNotificationsUtil::add(notificationID + notifySuffix, llsdBlock); } } - else if (regionAccess == SIM_ACCESS_ADULT) - { - if (!gAgent.isAdult()) - { - gAgent.clearTeleportRequest(); - maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_AdultsOnlyContent", llsdBlock); - returnValue = true; - notifySuffix = "_NotifyAdultsOnly"; - } - else if (gAgent.prefersPG() || gAgent.prefersMature()) + return returnValue; +} + +bool handle_trusted_experiences_notification(const LLSD& llsdBlock) +{ + if (llsdBlock.has("trusted_experiences")) + { + std::ostringstream str; + const LLSD& experiences = llsdBlock["trusted_experiences"]; + LLSD::array_const_iterator it = experiences.beginArray(); + for (/**/; it != experiences.endArray(); ++it) { - maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_Change", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); - returnValue = true; + str << LLSLURL("experience", it->asUUID(), "profile").getSLURLString() << "\n"; } - else if (LLStringUtil::compareStrings(notificationID, "RegionEntryAccessBlocked") == 0) + std::string str_list = str.str(); + if (!str_list.empty()) { - maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_PreferencesOutOfSync", llsdBlock, llsdBlock); - returnValue = true; + LLNotificationsUtil::add("TrustedExperiencesAvailable", LLSD::emptyMap().with("EXPERIENCE_LIST", (LLSD)str_list)); + return true; } } - - if ((maturityLevelNotification == NULL) || maturityLevelNotification->isIgnored()) - { - // Given a simple notification if no maturityLevelNotification is set or it is ignore - LLNotificationsUtil::add(notificationID + notifySuffix, llsdBlock); - } - - return returnValue; + return false; } // some of the server notifications need special handling. This is where we do that. -bool handle_teleport_access_blocked(LLSD& llsdBlock) +bool handle_teleport_access_blocked(LLSD& llsdBlock, const std::string& notificationID, const std::string& defaultMessage) { - std::string notificationID("TeleportEntryAccessBlocked"); - U8 regionAccess = static_cast(llsdBlock["_region_access"].asInteger()); - std::string regionMaturity = LLViewerRegion::accessToString(regionAccess); - LLStringUtil::toLower(regionMaturity); - llsdBlock["REGIONMATURITY"] = regionMaturity; - bool returnValue = false; - LLNotificationPtr maturityLevelNotification; - std::string notifySuffix = "_Notify"; - if (regionAccess == SIM_ACCESS_MATURE) + if (llsdBlock.has("_region_access")) { - if (gAgent.isTeen()) - { - gAgent.clearTeleportRequest(); - maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_AdultsOnlyContent", llsdBlock); - returnValue = true; + U8 regionAccess = static_cast(llsdBlock["_region_access"].asInteger()); + std::string regionMaturity = LLViewerRegion::accessToString(regionAccess); + LLStringUtil::toLower(regionMaturity); + llsdBlock["REGIONMATURITY"] = regionMaturity; - notifySuffix = "_NotifyAdultsOnly"; - } - else if (gAgent.prefersPG()) + LLNotificationPtr tp_failure_notification; + std::string notifySuffix; + + if (notificationID == std::string("TeleportEntryAccessBlocked")) { - if (gAgent.hasRestartableFailedTeleportRequest()) + notifySuffix = "_Notify"; + if (regionAccess == SIM_ACCESS_MATURE) { - maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_ChangeAndReTeleport", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_and_reteleport_callback); - returnValue = true; + if (gAgent.isTeen()) + { + gAgent.clearTeleportRequest(); + tp_failure_notification = LLNotificationsUtil::add(notificationID + "_AdultsOnlyContent", llsdBlock); + returnValue = true; + + notifySuffix = "_NotifyAdultsOnly"; + } + else if (gAgent.prefersPG()) + { + if (gAgent.hasRestartableFailedTeleportRequest()) + { + tp_failure_notification = LLNotificationsUtil::add(notificationID + "_ChangeAndReTeleport", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_and_reteleport_callback); + returnValue = true; + } + else + { + gAgent.clearTeleportRequest(); + tp_failure_notification = LLNotificationsUtil::add(notificationID + "_Change", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); + returnValue = true; + } + } + else + { + gAgent.clearTeleportRequest(); + tp_failure_notification = LLNotificationsUtil::add(notificationID + "_PreferencesOutOfSync", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); + returnValue = true; + } } - else + else if (regionAccess == SIM_ACCESS_ADULT) { - gAgent.clearTeleportRequest(); - maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_Change", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); - returnValue = true; + if (!gAgent.isAdult()) + { + gAgent.clearTeleportRequest(); + tp_failure_notification = LLNotificationsUtil::add(notificationID + "_AdultsOnlyContent", llsdBlock); + returnValue = true; + + notifySuffix = "_NotifyAdultsOnly"; + } + else if (gAgent.prefersPG() || gAgent.prefersMature()) + { + if (gAgent.hasRestartableFailedTeleportRequest()) + { + tp_failure_notification = LLNotificationsUtil::add(notificationID + "_ChangeAndReTeleport", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_and_reteleport_callback); + returnValue = true; + } + else + { + gAgent.clearTeleportRequest(); + tp_failure_notification = LLNotificationsUtil::add(notificationID + "_Change", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); + returnValue = true; + } + } + else + { + gAgent.clearTeleportRequest(); + tp_failure_notification = LLNotificationsUtil::add(notificationID + "_PreferencesOutOfSync", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); + returnValue = true; + } } - } + } // End of special handling for "TeleportEntryAccessBlocked" else - { - gAgent.clearTeleportRequest(); - maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_PreferencesOutOfSync", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); - returnValue = true; - } - } - else if (regionAccess == SIM_ACCESS_ADULT) - { - if (!gAgent.isAdult()) - { + { // Normal case, no message munging gAgent.clearTeleportRequest(); - maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_AdultsOnlyContent", llsdBlock); - returnValue = true; - - notifySuffix = "_NotifyAdultsOnly"; - } - else if (gAgent.prefersPG() || gAgent.prefersMature()) - { - if (gAgent.hasRestartableFailedTeleportRequest()) + if (LLNotificationTemplates::getInstance()->templateExists(notificationID)) { - maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_ChangeAndReTeleport", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_and_reteleport_callback); - returnValue = true; + tp_failure_notification = LLNotificationsUtil::add(notificationID, llsdBlock, llsdBlock); } else { - gAgent.clearTeleportRequest(); - maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_Change", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); - returnValue = true; + llsdBlock["MESSAGE"] = defaultMessage; + tp_failure_notification = LLNotificationsUtil::add("GenericAlertOK", llsdBlock); } + returnValue = true; } - else + + if ((tp_failure_notification == nullptr) || tp_failure_notification->isIgnored()) { - gAgent.clearTeleportRequest(); - maturityLevelNotification = LLNotificationsUtil::add(notificationID+"_PreferencesOutOfSync", llsdBlock, llsdBlock, handle_prompt_for_maturity_level_change_callback); - returnValue = true; + // Given a simple notification if no tp_failure_notification is set or it is ignore + LLNotificationsUtil::add(notificationID + notifySuffix, llsdBlock); } } - if ((maturityLevelNotification == NULL) || maturityLevelNotification->isIgnored()) + handle_trusted_experiences_notification(llsdBlock); + return returnValue; +} + +void home_position_set() +{ + // save the home location image to disk + std::string snap_filename = gDirUtilp->getLindenUserDir(); + snap_filename += gDirUtilp->getDirDelimiter(); + snap_filename += SCREEN_HOME_FILENAME; + gViewerWindow->saveSnapshot(snap_filename, gViewerWindow->getWindowWidthRaw(), gViewerWindow->getWindowHeightRaw(), FALSE, FALSE); +} + +void update_region_restart(const LLSD& llsdBlock) +{ + const U32 seconds = llsdBlock.has("MINUTES") + ? (60U * static_cast(llsdBlock["MINUTES"].asInteger())) + : static_cast(llsdBlock["SECONDS"].asInteger()); + if (LLFloaterRegionRestarting* restarting_floater = LLFloaterRegionRestarting::findInstance()) { - // Given a simple notification if no maturityLevelNotification is set or it is ignore - LLNotificationsUtil::add(notificationID + notifySuffix, llsdBlock); + restarting_floater->updateTime(seconds); + /*if (!restarting_floater->isMinimized()) + restarting_floater->center();*/ + } + else + { + LLSD params; + params["NAME"] = llsdBlock["NAME"]; + params["SECONDS"] = (LLSD::Integer)seconds; + LLFloaterRegionRestarting::showInstance(params); + if (gSavedSettings.getBOOL("LiruRegionRestartMinimized")) + LLFloaterRegionRestarting::findInstance()->setMinimized(true); } - - return returnValue; } bool attempt_standard_notification(LLMessageSystem* msgsystem) @@ -6472,16 +5322,18 @@ bool attempt_standard_notification(LLMessageSystem* msgsystem) std::string llsdRaw; LLSD llsdBlock; - msgsystem->getStringFast(_PREHASH_AlertInfo, _PREHASH_Message, notificationID); msgsystem->getStringFast(_PREHASH_AlertInfo, _PREHASH_ExtraParams, llsdRaw); if (llsdRaw.length()) { std::istringstream llsdData(llsdRaw); if (!LLSDSerialize::deserialize(llsdBlock, llsdData, llsdRaw.length())) { - llwarns << "attempt_standard_notification: Attempted to read notification parameter data into LLSD but failed:" << llsdRaw << llendl; + LL_WARNS() << "attempt_standard_notification: Attempted to read notification parameter data into LLSD but failed:" << llsdRaw << LL_ENDL; } } + + + handle_trusted_experiences_notification(llsdBlock); if ( (notificationID == "RegionEntryAccessBlocked") || @@ -6519,7 +5371,65 @@ bool attempt_standard_notification(LLMessageSystem* msgsystem) return true; } } - + else if (notificationID == "expired_region_handoff" || notificationID == "invalid_region_handoff") // borked region handoff + { + gAgent.setIsCrossingRegion(false); // Attachments getting lost on TP + } + else + // HACK -- handle callbacks for specific alerts. + if (notificationID == "HomePositionSet") + { + home_position_set(); + } + else if (notificationID == "YouDiedAndGotTPHome") + { + LLViewerStats::getInstance()->incStat(LLViewerStats::ST_KILLED_COUNT); + } + else if (notificationID == "RegionRestartMinutes" || + notificationID == "RegionRestartSeconds") + { + update_region_restart(llsdBlock); + LLUI::sAudioCallback(LLUUID(gSavedSettings.getString("UISndRestart"))); + return true; // Floater is enough. + } + else + // Special Marketplace update notification + if (notificationID == "SLM_UPDATE_FOLDER") + { + std::string state = llsdBlock["state"].asString(); + if (state == "deleted") + { + // Perform the deletion viewer side, no alert shown in this case + LLMarketplaceData::instance().deleteListing(llsdBlock["listing_id"].asInteger()); + return true; + } + // In general, no message will be displayed, all we want is to get the listing updated in the marketplace floater + // If getListing() fails though, the message of the alert will be shown by the caller of attempt_standard_notification() + return LLMarketplaceData::instance().getListing(llsdBlock["listing_id"].asInteger()); + } + + // Error Notification can come with and without reason + if (notificationID == "JoinGroupError") + { + if (llsdBlock.has("reason")) + { + LLNotificationsUtil::add("JoinGroupErrorReason", llsdBlock); + return true; + } + if (llsdBlock.has("group_id")) + { + LLGroupData agent_gdatap; + bool is_member = gAgent.getGroupData(llsdBlock["group_id"].asUUID(), agent_gdatap); + if (is_member) + { + LLSD args; + args["reason"] = LLTrans::getString("AlreadyInGroup"); + LLNotificationsUtil::add("JoinGroupErrorReason", args); + return true; + } + } + } + LLNotificationsUtil::add(notificationID, llsdBlock); return true; } @@ -6527,19 +5437,37 @@ bool attempt_standard_notification(LLMessageSystem* msgsystem) } +static void process_special_alert_messages(const std::string& message) +{ + // Do special handling for alert messages. This is a legacy hack, and any actual displayed + // text should be altered in the notifications.xml files. + if (message == "You died and have been teleported to your home location") + { + LLViewerStats::getInstance()->incStat(LLViewerStats::ST_KILLED_COUNT); + } + else if (message == "Home position set.") + { + home_position_set(); + } +} + + void process_agent_alert_message(LLMessageSystem* msgsystem, void** user_data) { // make sure the cursor is back to the usual default since the // alert is probably due to some kind of error. gViewerWindow->getWindow()->resetBusyCount(); + std::string message; + msgsystem->getStringFast(_PREHASH_AlertData, _PREHASH_Message, message); + + process_special_alert_messages(message); + if (!attempt_standard_notification(msgsystem)) { BOOL modal = FALSE; msgsystem->getBOOL("AlertData", "Modal", modal); - std::string buffer; - msgsystem->getStringFast(_PREHASH_AlertData, _PREHASH_Message, buffer); - process_alert_core(buffer, modal); + process_alert_core(message, modal); } } @@ -6548,25 +5476,27 @@ void process_agent_alert_message(LLMessageSystem* msgsystem, void** user_data) // handled by this routine, there is no "Modal" parameter on the message, and // there's no API to tell if a message has the given parameter or not. // So we can't handle the messages with the same handler. -void process_alert_message(LLMessageSystem *msgsystem, void **user_data) +void process_alert_message(LLMessageSystem* msgsystem, void** user_data) { // make sure the cursor is back to the usual default since the // alert is probably due to some kind of error. gViewerWindow->getWindow()->resetBusyCount(); + std::string message; + msgsystem->getStringFast(_PREHASH_AlertData, _PREHASH_Message, message); + process_special_alert_messages(message); + if (!attempt_standard_notification(msgsystem)) { BOOL modal = FALSE; - std::string buffer; - msgsystem->getStringFast(_PREHASH_AlertData, _PREHASH_Message, buffer); - process_alert_core(buffer, modal); + process_alert_core(message, modal); } } -bool handle_not_age_verified_alert(const std::string &pAlertName) +bool handle_not_age_verified_alert(const std::string& pAlertName) { LLNotificationPtr notification = LLNotificationsUtil::add(pAlertName); - if ((notification == NULL) || notification->isIgnored()) + if ((notification == nullptr) || notification->isIgnored()) { LLNotificationsUtil::add(pAlertName + "_Notify"); } @@ -6574,13 +5504,11 @@ bool handle_not_age_verified_alert(const std::string &pAlertName) return true; } -bool handle_special_alerts(const std::string &pAlertName) +bool handle_special_alerts(const std::string& pAlertName) { bool isHandled = false; - if (LLStringUtil::compareStrings(pAlertName, "NotAgeVerified") == 0) { - isHandled = handle_not_age_verified_alert(pAlertName); } @@ -6589,20 +5517,6 @@ bool handle_special_alerts(const std::string &pAlertName) void process_alert_core(const std::string& message, BOOL modal) { - // HACK -- handle callbacks for specific alerts. It also is localized in notifications.xml - if ( message == "You died and have been teleported to your home location") - { - LLViewerStats::getInstance()->incStat(LLViewerStats::ST_KILLED_COUNT); - } - else if( message == "Home position set." ) - { - // save the home location image to disk - std::string snap_filename = gDirUtilp->getLindenUserDir(); - snap_filename += gDirUtilp->getDirDelimiter(); - snap_filename += SCREEN_HOME_FILENAME; - gViewerWindow->saveSnapshot(snap_filename, gViewerWindow->getWindowWidthRaw(), gViewerWindow->getWindowHeightRaw(), FALSE, FALSE); - } - const std::string ALERT_PREFIX("ALERT: "); const std::string NOTIFY_PREFIX("NOTIFY: "); if (message.find(ALERT_PREFIX) == 0) @@ -6627,22 +5541,34 @@ void process_alert_core(const std::string& message, BOOL modal) // System message is important, show in upper-right box not tip std::string text(message.substr(1)); LLSD args; + if (text.substr(0,17) == "RESTART_X_MINUTES") { S32 mins = 0; LLStringUtil::convertToS32(text.substr(18), mins); args["MINUTES"] = llformat("%d",mins); - LLNotificationsUtil::add("RegionRestartMinutes", args); + update_region_restart(args); + //LLNotificationsUtil::add("RegionRestartMinutes", args); // Floater is enough. + LLUI::sAudioCallback(LLUUID(gSavedSettings.getString("UISndRestart"))); } else if (text.substr(0,17) == "RESTART_X_SECONDS") { S32 secs = 0; LLStringUtil::convertToS32(text.substr(18), secs); args["SECONDS"] = llformat("%d",secs); - LLNotificationsUtil::add("RegionRestartSeconds", args); + update_region_restart(args); + //LLNotificationsUtil::add("RegionRestartSeconds", args); // Floater is enough. + LLUI::sAudioCallback(LLUUID(gSavedSettings.getString("UISndRestart"))); } else { + // *NOTE: If the text from the server ever changes this line will need to be adjusted. + std::string restart_cancelled = "Region restart cancelled."; + if (text.substr(0, restart_cancelled.length()) == restart_cancelled) + { + LLFloaterRegionRestarting::hideInstance(); + } + std::string new_msg =LLNotificationTemplates::instance().getGlobalString(text); // [RLVa:KB] - Checked: 2012-02-07 (RLVa-1.4.5) | Added: RLVa-1.4.5 if ( (new_msg == text) && (rlv_handler_t::isEnabled()) ) @@ -6704,17 +5630,17 @@ void process_alert_core(const std::string& message, BOOL modal) mean_collision_list_t gMeanCollisionList; time_t gLastDisplayedTime = 0; -void handle_show_mean_events(void *) +void handle_show_mean_events(void*) { if (gNoRender) { return; } - LLFloaterBump::show(NULL); + LLFloaterBump::show(nullptr); } -void mean_name_callback(const LLUUID &id, const std::string& full_name, bool is_group) +void mean_name_callback(const LLUUID& id, const LLAvatarName& av_name) { if (gNoRender) { @@ -6725,23 +5651,46 @@ void mean_name_callback(const LLUUID &id, const std::string& full_name, bool is_ if (gMeanCollisionList.size() > max_collision_list_size) { mean_collision_list_t::iterator iter = gMeanCollisionList.begin(); - for (U32 i=0; imPerp == id) { - mcd->mFullName = full_name; + mcd->mFullName = av_name.getUserName(); } } } -void process_mean_collision_alert_message(LLMessageSystem *msgsystem, void **user_data) +void chat_mean_collision(const LLUUID& id, const LLAvatarName& avname, const EMeanCollisionType& type, const F32& mag) +{ + LLStringUtil::format_map_t args; + if (type == MEAN_BUMP) + args["ACT"] = LLTrans::getString("bump"); + else if (type == MEAN_LLPUSHOBJECT) + args["ACT"] = LLTrans::getString("llpushobject"); + else if (type == MEAN_SELECTED_OBJECT_COLLIDE) + args["ACT"] = LLTrans::getString("selected_object_collide"); + else if (type == MEAN_SCRIPTED_OBJECT_COLLIDE) + args["ACT"] = LLTrans::getString("scripted_object_collide"); + else if (type == MEAN_PHYSICAL_OBJECT_COLLIDE) + args["ACT"] = LLTrans::getString("physical_object_collide"); + else + return; // How did we get here? I used to know you so well. + const std::string name(avname.getNSName()); + args["NAME"] = name; + args["MAG"] = llformat("%f", mag); + LLChat chat(LLTrans::getString("BumpedYou", args)); + chat.mFromName = name; + chat.mURL = LLAvatarActions::getSLURL(id); + chat.mSourceType = CHAT_SOURCE_SYSTEM; + LLFloaterChat::addChat(chat); +} + +void process_mean_collision_alert_message(LLMessageSystem* msgsystem, void** user_data) { if (gAgent.inPrelude()) { @@ -6770,13 +5719,13 @@ void process_mean_collision_alert_message(LLMessageSystem *msgsystem, void **use msgsystem->getU8Fast(_PREHASH_MeanCollision, _PREHASH_Type, u8type); type = (EMeanCollisionType)u8type; + static const LLCachedControl chat_collision("AnnounceBumps"); + if (chat_collision) LLAvatarNameCache::get(perp, boost::bind(chat_mean_collision, _1, _2, type, mag)); BOOL b_found = FALSE; - for (mean_collision_list_t::iterator iter = gMeanCollisionList.begin(); - iter != gMeanCollisionList.end(); ++iter) + for (auto mcd : gMeanCollisionList) { - LLMeanCollisionData *mcd = *iter; if ((mcd->mPerp == perp) && (mcd->mType == type)) { mcd->mTime = time; @@ -6788,14 +5737,14 @@ void process_mean_collision_alert_message(LLMessageSystem *msgsystem, void **use if (!b_found) { - LLMeanCollisionData *mcd = new LLMeanCollisionData(gAgentID, perp, time, type, mag); + LLMeanCollisionData* mcd = new LLMeanCollisionData(gAgentID, perp, time, type, mag); gMeanCollisionList.push_front(mcd); - gCacheName->get(perp, false, boost::bind(&mean_name_callback, _1, _2, _3)); + LLAvatarNameCache::get(perp, boost::bind(&mean_name_callback, _1, _2)); } } } -void process_frozen_message(LLMessageSystem *msgsystem, void **user_data) +void process_frozen_message(LLMessageSystem* msgsystem, void** user_data) { // make sure the cursor is back to the usual default since the // alert is probably due to some kind of error. @@ -6814,28 +5763,21 @@ void process_frozen_message(LLMessageSystem *msgsystem, void **user_data) } // do some extra stuff once we get our economy data -void process_economy_data(LLMessageSystem *msg, void** /*user_data*/) +void process_economy_data(LLMessageSystem* msg, void** /*user_data*/) { - LLGlobalEconomy::processEconomyData(msg, LLGlobalEconomy::Singleton::getInstance()); - - S32 upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(); - - LL_INFOS_ONCE("Messaging") << "EconomyData message arrived; upload cost is L$" << upload_cost << LL_ENDL; - - std::string fee = gHippoGridManager->getConnectedGrid()->getUploadFee(); - gMenuHolder->childSetLabelArg("Upload Image", "[UPLOADFEE]", fee); - gMenuHolder->childSetLabelArg("Upload Sound", "[UPLOADFEE]", fee); - gMenuHolder->childSetLabelArg("Upload Animation", "[UPLOADFEE]", fee); - gMenuHolder->childSetLabelArg("Bulk Upload", "[UPLOADFEE]", fee); - gMenuHolder->childSetLabelArg("Buy and Sell L$...", "[CURRENCY]", - gHippoGridManager->getConnectedGrid()->getCurrencySymbol()); + auto& grid = *gHippoGridManager->getConnectedGrid(); + if (grid.isSecondLife() || !LLAgentBenefitsMgr::isCurrent("NonSL")) return; // Quick hack to allow other grids benefits management + LLAgentBenefitsMgr::current().processEconomyData(msg); } void notify_cautioned_script_question(const LLSD& notification, const LLSD& response, S32 orig_questions, BOOL granted) { // NaCl - Antispam Registry - LLUUID task_id = notification["payload"]["task_id"].asUUID(); - if(NACLAntiSpamRegistry::checkQueue((U32)NACLAntiSpamRegistry::QUEUE_SCRIPT_DIALOG,task_id)) return; + if (NACLAntiSpamRegistry::instanceExists()) + { + if (NACLAntiSpamRegistry::instance().checkQueue(NACLAntiSpamRegistry::QUEUE_SCRIPT_DIALOG, notification["payload"]["task_id"].asUUID(), LFIDBearer::OBJECT)) + return; + } // NaCl End // only continue if at least some permissions were requested if (orig_questions) @@ -6938,10 +5880,22 @@ void notify_cautioned_script_question(const LLSD& notification, const LLSD& resp } } +void script_question_mute(const LLUUID& item_id, const std::string& object_name); + +void experiencePermissionBlock(LLUUID experience, LLSD result) +{ + LLSD permission; + LLSD data; + permission["permission"] = "Block"; + data[experience.asString()] = permission; + data["experience"] = experience; + LLEventPumps::instance().obtain("experience_permission").post(data); +} + bool script_question_cb(const LLSD& notification, const LLSD& response) { S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - LLMessageSystem *msg = gMessageSystem; + LLMessageSystem* msg = gMessageSystem; S32 orig = notification["payload"]["questions"].asInteger(); S32 new_questions = orig; @@ -6955,6 +5909,12 @@ bool script_question_cb(const LLSD& notification, const LLSD& response) return false; } + LLUUID experience; + if (notification["payload"].has("experience")) + { + experience = notification["payload"]["experience"].asUUID(); + } + // check whether permissions were granted or denied BOOL allowed = TRUE; // the "yes/accept" button is the first button in the template, making it button 0 @@ -6963,7 +5923,17 @@ bool script_question_cb(const LLSD& notification, const LLSD& response) { new_questions = 0; allowed = FALSE; - } + } + else if (experience.notNull()) + { + LLSD permission; + LLSD data; + permission["permission"] = "Allow"; + + data[experience.asString()] = permission; + data["experience"] = experience; + LLEventPumps::instance().obtain("experience_permission").post(data); + } LLUUID task_id = notification["payload"]["task_id"].asUUID(); LLUUID item_id = notification["payload"]["item_id"].asUUID(); @@ -6996,37 +5966,74 @@ bool script_question_cb(const LLSD& notification, const LLSD& response) } // [/RLVa:KB] - if ( response["Mute"] ) // mute + if (response["Mute"]) // mute + { + script_question_mute(task_id, notification["payload"]["object_name"].asString()); + } + if (response["BlockExperience"]) + { + if (experience.notNull()) + { + LLViewerRegion* region = gAgent.getRegion(); + if (!region) + return false; + + LLExperienceCache::instance().setExperiencePermission(experience, std::string("Block"), boost::bind(&experiencePermissionBlock, experience, _1)); + } + } + return false; +} + +void script_question_mute(const LLUUID& task_id, const std::string& object_name) +{ + LLMuteList::getInstance()->add(LLMute(task_id, object_name, LLMute::OBJECT)); + + // purge the message queue of any previously queued requests from the same source. DEV-4879 + class OfferMatcher final : public LLNotifyBoxView::Matcher { - LLMuteList::getInstance()->add(LLMute(item_id, notification["payload"]["object_name"].asString(), LLMute::OBJECT)); + public: + OfferMatcher(const LLUUID& to_block) : blocked_id(to_block) + { + } - // purge the message queue of any previously queued requests from the same source. DEV-4879 - class OfferMatcher : public LLNotifyBoxView::Matcher + bool matches(const LLNotificationPtr notification) const override { - public: - OfferMatcher(const LLUUID& to_block) : blocked_id(to_block) {} - bool matches(const LLNotificationPtr notification) const + if (notification->getName() == "ScriptQuestionCaution" + || notification->getName() == "ScriptQuestion") { - if (notification->getName() == "ScriptQuestionCaution" - || notification->getName() == "ScriptQuestion") - { - return (notification->getPayload()["item_id"].asUUID() == blocked_id); - } - return false; + return (notification->getPayload()["task_id"].asUUID() == blocked_id); } - private: - const LLUUID& blocked_id; - }; - // should do this via the channel - gNotifyBoxView->purgeMessagesMatching(OfferMatcher(item_id)); - } + return false; + } - return false; + private: + const LLUUID& blocked_id; + }; + + // should do this via the channel + gNotifyBoxView->purgeMessagesMatching(OfferMatcher(task_id)); } + static LLNotificationFunctorRegistration script_question_cb_reg_1("ScriptQuestion", script_question_cb); static LLNotificationFunctorRegistration script_question_cb_reg_2("ScriptQuestionCaution", script_question_cb); +static LLNotificationFunctorRegistration script_question_cb_reg_3("ScriptQuestionExperience", script_question_cb); + +void process_script_experience_details(const LLSD& experience_details, LLSD args, LLSD payload) +{ + if (experience_details[LLExperienceCache::PROPERTIES].asInteger() & LLExperienceCache::PROPERTY_GRID) + { + args["GRID_WIDE"] = LLTrans::getString("Grid-Scope"); + } + else + { + args["GRID_WIDE"] = LLTrans::getString("Land-Scope"); + } + args["EXPERIENCE"] = LLSLURL("experience", experience_details[LLExperienceCache::EXPERIENCE_ID].asUUID(), "profile").getSLURLString(); + + LLNotificationsUtil::add("ScriptQuestionExperience", args, payload); +} -void process_script_question(LLMessageSystem *msg, void **user_data) +void process_script_question(LLMessageSystem* msg, void** user_data) { // *TODO: Translate owner name -> [FIRST] [LAST] @@ -7037,22 +6044,32 @@ void process_script_question(LLMessageSystem *msg, void **user_data) S32 questions; std::string object_name; std::string owner_name; + LLUUID experienceid; // taskid -> object key of object requesting permissions - msg->getUUIDFast(_PREHASH_Data, _PREHASH_TaskID, taskid ); + msg->getUUIDFast(_PREHASH_Data, _PREHASH_TaskID, taskid); // itemid -> script asset key of script requesting permissions - msg->getUUIDFast(_PREHASH_Data, _PREHASH_ItemID, itemid ); + msg->getUUIDFast(_PREHASH_Data, _PREHASH_ItemID, itemid); // NaCl - Antispam Registry - if((taskid.isNull() - && NACLAntiSpamRegistry::checkQueue((U32)NACLAntiSpamRegistry::QUEUE_SCRIPT_DIALOG,itemid)) - || NACLAntiSpamRegistry::checkQueue((U32)NACLAntiSpamRegistry::QUEUE_SCRIPT_DIALOG,taskid)) - return; + if (NACLAntiSpamRegistry::instanceExists()) + { + auto& antispam = NACLAntiSpamRegistry::instance(); + if ((taskid.isNull() + && antispam.checkQueue(NACLAntiSpamRegistry::QUEUE_SCRIPT_DIALOG, itemid, LFIDBearer::NONE)) + || antispam.checkQueue(NACLAntiSpamRegistry::QUEUE_SCRIPT_DIALOG, taskid, LFIDBearer::OBJECT)) + return; + } // NaCl End msg->getStringFast(_PREHASH_Data, _PREHASH_ObjectName, object_name); msg->getStringFast(_PREHASH_Data, _PREHASH_ObjectOwner, owner_name); - msg->getS32Fast(_PREHASH_Data, _PREHASH_Questions, questions ); + msg->getS32Fast(_PREHASH_Data, _PREHASH_Questions, questions); + + if (msg->has(_PREHASH_Experience)) + { + msg->getUUIDFast(_PREHASH_Experience, _PREHASH_ExperienceID, experienceid); + } // Special case. If the objects are owned by this agent, throttle per-object instead // of per-owner. It's common for residents to reset a ton of scripts that re-request @@ -7060,11 +6077,11 @@ void process_script_question(LLMessageSystem *msg, void **user_data) // so we'll reuse the same namespace for both throttle types. std::string throttle_name = owner_name; std::string self_name; - LLAgentUI::buildFullname( self_name ); + LLAgentUI::buildFullname(self_name); // NaCl - Antispam if (is_spam_filtered(IM_COUNT, false, owner_name == self_name)) return; // NaCl End - if( owner_name == self_name ) + if (owner_name == self_name) { throttle_name = taskid.getString(); } @@ -7074,7 +6091,7 @@ void process_script_question(LLMessageSystem *msg, void **user_data) // throttle excessive requests from any specific user's scripts typedef LLKeyThrottle LLStringThrottle; - static LLStringThrottle question_throttle( LLREQUEST_PERMISSION_THROTTLE_LIMIT, LLREQUEST_PERMISSION_THROTTLE_INTERVAL ); + static LLStringThrottle question_throttle(LLREQUEST_PERMISSION_THROTTLE_LIMIT, LLREQUEST_PERMISSION_THROTTLE_INTERVAL); switch (question_throttle.noteAction(throttle_name)) { @@ -7095,87 +6112,111 @@ void process_script_question(LLMessageSystem *msg, void **user_data) std::string script_question; if (questions) { - BOOL caution = FALSE; + bool caution = false; S32 count = 0; LLSD args; - args["OBJECTNAME"] = object_name; - args["NAME"] = LLCacheName::cleanFullName(owner_name); - - BOOL has_not_only_debit = questions ^ LSCRIPTRunTimePermissionBits[SCRIPT_PERMISSION_DEBIT]; + const std::string get_obj_slurl(const LLUUID& id, const std::string& name); + const std::string get_obj_owner_slurl(const LLUUID& obj_id, const std::string& name, bool* group_ownedp = nullptr); + args["OBJECTNAME"] = get_obj_slurl(taskid, object_name); + args["NAME"] = get_obj_owner_slurl(taskid, owner_name); + S32 known_questions = 0; + bool has_not_only_debit = questions ^ LSCRIPTRunTimePermissionBits[SCRIPT_PERMISSION_DEBIT]; // check the received permission flags against each permission for (S32 i = 0; i < SCRIPT_PERMISSION_EOF; i++) { if (questions & LSCRIPTRunTimePermissionBits[i]) { count++; - + known_questions |= LSCRIPTRunTimePermissionBits[i]; // check whether permission question should cause special caution dialog caution |= (SCRIPT_QUESTION_IS_CAUTION[i]); if (("ScriptTakeMoney" == SCRIPT_QUESTIONS[i]) && has_not_only_debit) continue; + if (SCRIPT_QUESTIONS[i] == "JoinAnExperience") + { // Some experience only permissions do not have an explicit permission bit. Add them here. + script_question += " " + LLTrans::getString("ForceSitAvatar") + "\n"; + } + script_question += " " + LLTrans::getString(SCRIPT_QUESTIONS[i]) + "\n"; } } + args["QUESTIONS"] = script_question; - LLSD payload; - payload["task_id"] = taskid; - payload["item_id"] = itemid; - payload["sender"] = sender.getIPandPort(); - payload["questions"] = questions; - payload["object_name"] = object_name; - payload["owner_name"] = owner_name; + if (known_questions != questions) + { + // This is in addition to the normal dialog. + // Viewer got a request for not supported/implemented permission + LL_WARNS("Messaging") << "Object \"" << object_name << "\" requested " << script_question + << " permission. Permission is unknown and can't be granted. Item id: " << itemid + << " taskid:" << taskid << LL_ENDL; + } -// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7) - if (rlv_handler_t::isEnabled()) + if (known_questions) { - RlvUtil::filterScriptQuestions(questions, payload); + LLSD payload; + payload["task_id"] = taskid; + payload["item_id"] = itemid; + payload["sender"] = sender.getIPandPort(); + payload["questions"] = known_questions; + payload["object_name"] = object_name; + payload["owner_name"] = owner_name; - if ( (questions) && (gRlvHandler.hasBehaviour(RLV_BHVR_ACCEPTPERMISSION)) ) + // check whether cautions are even enabled or not + const char* notification = "ScriptQuestion"; + +// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7) + if (rlv_handler_t::isEnabled()) { - const LLViewerObject* pObj = gObjectList.findObject(taskid); - if (pObj) + RlvUtil::filterScriptQuestions(questions, payload); + + if ( (questions) && (gRlvHandler.hasBehaviour(RLV_BHVR_ACCEPTPERMISSION)) ) { - if ( (pObj->permYouOwner()) && (!pObj->isAttachment()) ) - { - questions &= ~(LSCRIPTRunTimePermissionBits[SCRIPT_PERMISSION_TAKE_CONTROLS] | - LSCRIPTRunTimePermissionBits[SCRIPT_PERMISSION_ATTACH]); - } - else + const LLViewerObject* pObj = gObjectList.findObject(taskid); + if (pObj) { - questions &= ~(LSCRIPTRunTimePermissionBits[SCRIPT_PERMISSION_TAKE_CONTROLS]); + if ( (pObj->permYouOwner()) && (!pObj->isAttachment()) ) + { + questions &= ~(LSCRIPTRunTimePermissionBits[SCRIPT_PERMISSION_TAKE_CONTROLS] | + LSCRIPTRunTimePermissionBits[SCRIPT_PERMISSION_ATTACH]); + } + else + { + questions &= ~(LSCRIPTRunTimePermissionBits[SCRIPT_PERMISSION_TAKE_CONTROLS]); + } + payload["rlv_notify"] = !pObj->permYouOwner(); } - payload["rlv_notify"] = !pObj->permYouOwner(); } } - } - if ( (!caution) && (!questions) ) - { - LLNotifications::instance().forceResponse( - LLNotification::Params("ScriptQuestion").substitutions(args).payload(payload), 0/*YES*/); - } - else if (gSavedSettings.getBOOL("PermissionsCautionEnabled")) + if ( (!caution) && (!questions) ) + { + LLNotifications::instance().forceResponse( + LLNotification::Params(notification).substitutions(args).payload(payload), 0/*YES*/); + return; + } // [/RLVa:KB] - // check whether cautions are even enabled or not - //if (gSavedSettings.getBOOL("PermissionsCautionEnabled")) - { - // display the caution permissions prompt - LLNotificationsUtil::add(caution ? "ScriptQuestionCaution" : "ScriptQuestion", args, payload); - } - else - { - // fall back to default behavior if cautions are entirely disabled - LLNotificationsUtil::add("ScriptQuestion", args, payload); - } + if (caution && gSavedSettings.getBOOL("PermissionsCautionEnabled")) + { + args["FOOTERTEXT"] = (count > 1) ? LLTrans::getString("AdditionalPermissionsRequestHeader") + '\n' + script_question : LLStringUtil::null; + notification = "ScriptQuestionCaution"; + } + else if (experienceid.notNull()) + { + payload["experience"] = experienceid; + LLExperienceCache::instance().get(experienceid, boost::bind(process_script_experience_details, _1, args, payload)); + return; + } + LLNotificationsUtil::add(notification, args, payload); + } } } -void process_derez_container(LLMessageSystem *msg, void**) +void process_derez_container(LLMessageSystem* msg, void**) { LL_WARNS("Messaging") << "call to deprecated process_derez_container" << LL_ENDL; } @@ -7186,12 +6227,12 @@ void container_inventory_arrived(LLViewerObject* object, void* data) { LL_DEBUGS("Messaging") << "container_inventory_arrived()" << LL_ENDL; - if( gAgentCamera.cameraMouselook() ) + if (gAgentCamera.cameraMouselook()) { gAgentCamera.changeCameraToDefault(); } - LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(); + LLInventoryPanel* active_panel = LLInventoryPanel::getActiveInventoryPanel(); if (inventory->size() > 2) { @@ -7203,7 +6244,7 @@ void container_inventory_arrived(LLViewerObject* object, LLInventoryObject::object_list_t::const_iterator it = inventory->begin(); LLInventoryObject::object_list_t::const_iterator end = inventory->end(); - for ( ; it != end; ++it) + for (; it != end; ++it) { if ((*it)->getType() != LLAssetType::AT_CATEGORY) { @@ -7229,7 +6270,7 @@ void container_inventory_arrived(LLViewerObject* object, } } gInventory.notifyObservers(); - if(active_panel) + if (active_panel) { active_panel->setSelection(cat_id, TAKE_FOCUS_NO); } @@ -7265,7 +6306,7 @@ void container_inventory_arrived(LLViewerObject* object, new_item->updateServer(TRUE); gInventory.updateItem(new_item); gInventory.notifyObservers(); - if(active_panel) + if (active_panel) { active_panel->setSelection(item_id, TAKE_FOCUS_NO); } @@ -7273,7 +6314,7 @@ void container_inventory_arrived(LLViewerObject* object, // we've got the inventory, now delete this object if this was a take BOOL delete_object = (BOOL)(intptr_t)data; - LLViewerRegion *region = gAgent.getRegion(); + LLViewerRegion* region = gAgent.getRegion(); if (delete_object && region) { gMessageSystem->newMessageFast(_PREHASH_ObjectDelete); @@ -7300,10 +6341,10 @@ std::string formatted_time(const time_t& the_time) } -void process_teleport_failed(LLMessageSystem *msg, void**) +void process_teleport_failed(LLMessageSystem* msg, void**) { - std::string reason; - std::string big_reason; + std::string message_id; // Tag from server, like "RegionEntryAccessBlocked" + std::string big_reason; // Actual message to display LLSD args; // Let the interested parties know that teleport failed. @@ -7313,36 +6354,44 @@ void process_teleport_failed(LLMessageSystem *msg, void**) if (msg->has(_PREHASH_AlertInfo) && msg->getSizeFast(_PREHASH_AlertInfo, _PREHASH_Message) > 0) { // Get the message ID - msg->getStringFast(_PREHASH_AlertInfo, _PREHASH_Message, reason); - big_reason = LLAgent::sTeleportErrorMessages[reason]; - if ( big_reason.size() > 0 ) - { // Substitute verbose reason from the local map - args["REASON"] = big_reason; - } - else - { // Nothing found in the map - use what the server returned in the original message block - msg->getStringFast(_PREHASH_Info, _PREHASH_Reason, reason); - args["REASON"] = reason; + msg->getStringFast(_PREHASH_AlertInfo, _PREHASH_Message, message_id); + big_reason = LLAgent::sTeleportErrorMessages[message_id]; + if (big_reason.empty()) + { + // Nothing found in the map - use what the server returned in the original message block + msg->getStringFast(_PREHASH_Info, _PREHASH_Reason, big_reason); } + args["REASON"] = big_reason; LLSD llsd_block; std::string llsd_raw; msg->getStringFast(_PREHASH_AlertInfo, _PREHASH_ExtraParams, llsd_raw); - if (llsd_raw.length()) + if (!llsd_raw.empty()) { std::istringstream llsd_data(llsd_raw); if (!LLSDSerialize::deserialize(llsd_block, llsd_data, llsd_raw.length())) { - llwarns << "process_teleport_failed: Attempted to read alert parameter data into LLSD but failed:" << llsd_raw << llendl; + LL_WARNS() << "process_teleport_failed: Attempted to read alert parameter data into LLSD but failed:" << llsd_raw << LL_ENDL; } else { + if(llsd_block.has("REGION_NAME")) + { + std::string region_name = llsd_block["REGION_NAME"].asString(); + if(!region_name.empty()) + { + LLStringUtil::format_map_t name_args; + name_args["[REGION_NAME]"] = region_name; + LLStringUtil::format(big_reason, name_args); + args["REASON"] = big_reason; + } + } // change notification name in this special case - if (handle_teleport_access_blocked(llsd_block)) + if (handle_teleport_access_blocked(llsd_block, message_id, args["REASON"])) { - if( gAgent.getTeleportState() != LLAgent::TELEPORT_NONE ) + if (gAgent.getTeleportState() != LLAgent::TELEPORT_NONE) { - gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); + gAgent.setTeleportState(LLAgent::TELEPORT_NONE); } return; } @@ -7351,29 +6400,29 @@ void process_teleport_failed(LLMessageSystem *msg, void**) } else - { - msg->getStringFast(_PREHASH_Info, _PREHASH_Reason, reason); + { // Extra message payload not found - use what the simulator sent + msg->getStringFast(_PREHASH_Info, _PREHASH_Reason, message_id); - big_reason = LLAgent::sTeleportErrorMessages[reason]; - if ( big_reason.size() > 0 ) + big_reason = LLAgent::sTeleportErrorMessages[message_id]; + if (!big_reason.empty()) { // Substitute verbose reason from the local map args["REASON"] = big_reason; } else { // Nothing found in the map - use what the server returned - args["REASON"] = reason; + args["REASON"] = message_id; } } LLNotificationsUtil::add("CouldNotTeleportReason", args); - if( gAgent.getTeleportState() != LLAgent::TELEPORT_NONE ) + if (gAgent.getTeleportState() != LLAgent::TELEPORT_NONE) { - gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); + gAgent.setTeleportState(LLAgent::TELEPORT_NONE); } } -void process_teleport_local(LLMessageSystem *msg,void**) +void process_teleport_local(LLMessageSystem* msg, void**) { LLUUID agent_id; msg->getUUIDFast(_PREHASH_Info, _PREHASH_AgentID, agent_id); @@ -7391,9 +6440,9 @@ void process_teleport_local(LLMessageSystem *msg,void**) msg->getVector3Fast(_PREHASH_Info, _PREHASH_LookAt, look_at); msg->getU32Fast(_PREHASH_Info, _PREHASH_TeleportFlags, teleport_flags); - if( gAgent.getTeleportState() != LLAgent::TELEPORT_NONE ) + if (gAgent.getTeleportState() != LLAgent::TELEPORT_NONE) { - if( gAgent.getTeleportState() == LLAgent::TELEPORT_LOCAL ) + if (gAgent.getTeleportState() == LLAgent::TELEPORT_LOCAL) { // To prevent TeleportStart messages re-activating the progress screen right // after tp, keep the teleport state and let progress screen clear it after a short delay @@ -7403,13 +6452,12 @@ void process_teleport_local(LLMessageSystem *msg,void**) } else { - gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); + gAgent.setTeleportState(LLAgent::TELEPORT_NONE); } } - static LLCachedControl fly_after_tp(gSavedSettings, "LiruFlyAfterTeleport"); // Sim tells us whether the new position is off the ground - if (fly_after_tp || (teleport_flags & TELEPORT_FLAGS_IS_FLYING)) + if (teleport_flags & TELEPORT_FLAGS_IS_FLYING || gSavedSettings.getBOOL("LiruFlyAfterTeleport")) { gAgent.setFlying(TRUE); } @@ -7421,7 +6469,7 @@ void process_teleport_local(LLMessageSystem *msg,void**) gAgent.setPositionAgent(pos); gAgentCamera.slamLookAt(look_at); - if ( !(gAgent.getTeleportKeepsLookAt() && LLViewerJoystick::getInstance()->getOverrideCamera()) && gSavedSettings.getBOOL("OptionRotateCamAfterLocalTP")) + if (!(gAgent.getTeleportKeepsLookAt() && LLViewerJoystick::getInstance()->getOverrideCamera()) && gSavedSettings.getBOOL("OptionRotateCamAfterLocalTP")) { gAgentCamera.resetView(TRUE, TRUE); } @@ -7490,7 +6538,7 @@ void send_group_notice(const LLUUID& group_id, } else { - bucket_to_send = (U8*) EMPTY_BINARY_BUCKET; + bucket_to_send = (U8*)EMPTY_BINARY_BUCKET; } @@ -7513,16 +6561,16 @@ void send_lures(const LLSD& notification, const LLSD& response) LLAgentUI::buildSLURL(slurl); text.append("\r\n").append(slurl.getSLURLString()); -// [RLVa:KB] - Checked: 2010-11-30 (RLVa-1.3.0c) | Modified: RLVa-1.3.0c - if ( (gRlvHandler.hasBehaviour(RLV_BHVR_SENDIM)) || (gRlvHandler.hasBehaviour(RLV_BHVR_SENDIMTO)) ) +// [RLVa:KB] - Checked: 2010-11-30 (RLVa-1.3.0) + const std::string& rlv_hidden(RlvStrings::getString(RLV_STRING_HIDDEN)); + if ( (RlvActions::hasBehaviour(RLV_BHVR_SENDIM)) || (RlvActions::hasBehaviour(RLV_BHVR_SENDIMTO)) ) { // Filter the lure message if one of the recipients of the lure can't be sent an IM to - for (LLSD::array_const_iterator it = notification["payload"]["ids"].beginArray(); - it != notification["payload"]["ids"].endArray(); ++it) + for (auto const& entry : notification["payload"]["ids"].array()) { - if (!gRlvHandler.canSendIM(it->asUUID())) + if (!RlvActions::canSendIM(entry.asUUID())) { - text = RlvStrings::getString(RLV_STRING_HIDDEN); + text = rlv_hidden; break; } } @@ -7537,14 +6585,51 @@ void send_lures(const LLSD& notification, const LLSD& response) msg->nextBlockFast(_PREHASH_Info); msg->addU8Fast(_PREHASH_LureType, (U8)0); // sim will fill this in. msg->addStringFast(_PREHASH_Message, text); - for(LLSD::array_const_iterator it = notification["payload"]["ids"].beginArray(); - it != notification["payload"]["ids"].endArray(); - ++it) +// [RLVa:KB] - Checked: 2014-03-31 (Catznip-3.6) + bool fRlvHideName = gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES); + bool fRlvNoNearbyNames = gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS); +// [/RLVa:KB] + for (auto const& entry : notification["payload"]["ids"].array()) { - LLUUID target_id = it->asUUID(); + LLUUID target_id = entry.asUUID(); msg->nextBlockFast(_PREHASH_TargetData); msg->addUUIDFast(_PREHASH_TargetID, target_id); + + // Record the offer. + if (notification["payload"]["ids"].size() < 10) // Singu Note: Do NOT spam chat! + { +// [RLVa:KB] - Checked: 2014-03-31 (Catznip-3.6) + fRlvHideName |= notification["payload"]["rlv_shownames"].asBoolean(); +// [/RLVa:KB] + std::string target_name; + gCacheName->getFullName(target_id, target_name); // for im log filenames + LLSD args; +// [RLVa:KB] - Checked: 2014-03-31 (Catznip-3.6) + if (fRlvNoNearbyNames && RlvUtil::isNearbyAgent(target_id)) + target_name = rlv_hidden; + else if (fRlvHideName) + target_name = RlvStrings::getAnonym(target_name); + else +// [/RLVa:KB] + target_name = LLAvatarActions::getSLURL(target_id); + args["TO_NAME"] = target_name; + + LLSD payload; + + //*TODO please rewrite all keys to the same case, lower or upper + payload["from_id"] = target_id; + payload["SUPPRESS_TOAST"] = true; + LLNotificationsUtil::add("TeleportOfferSent", args, payload); + + /* Singu TODO? +// [RLVa:KB] - Checked: 2014-03-31 (Catznip-3.6) + if (!fRlvHideName) + LLRecentPeople::instance().add(target_id); +// [/RLVa:KB] +// LLRecentPeople::instance().add(target_id); + */ + } } gAgent.sendReliableMessage(); } @@ -7552,7 +6637,7 @@ void send_lures(const LLSD& notification, const LLSD& response) bool handle_lure_callback(const LLSD& notification, const LLSD& response) { static const unsigned OFFER_RECIPIENT_LIMIT = 250; - if(notification["payload"]["ids"].size() > OFFER_RECIPIENT_LIMIT) + if (notification["payload"]["ids"].size() > OFFER_RECIPIENT_LIMIT) { // More than OFFER_RECIPIENT_LIMIT targets will overload the message // producing an llerror. @@ -7565,7 +6650,7 @@ bool handle_lure_callback(const LLSD& notification, const LLSD& response) S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if(0 == option) + if (0 == option) { send_lures(notification, response); } @@ -7575,9 +6660,7 @@ bool handle_lure_callback(const LLSD& notification, const LLSD& response) void handle_lure(const LLUUID& invitee) { - LLDynamicArray ids; - ids.push_back(invitee); - handle_lure(ids); + handle_lure(uuid_vec_t{invitee}); } // Prompt for a message to the invited user. @@ -7589,30 +6672,36 @@ void handle_lure(const uuid_vec_t& ids) LLSD edit_args; // [RLVa:KB] - Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.0.0a - edit_args["REGION"] = - (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) ? gAgent.getRegion()->getName() : RlvStrings::getString(RLV_STRING_HIDDEN); + edit_args["REGION"] = (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) ? gAgent.getRegion()->getName() : RlvStrings::getString(RLV_STRING_HIDDEN); // [/RLVa:KB] - //edit_args["REGION"] = gAgent.getRegion()->getName(); +// edit_args["REGION"] = gAgent.getRegion()->getName(); LLSD payload; - for (uuid_vec_t::const_iterator it = ids.begin(); - it != ids.end(); - ++it) +// [RLVa:KB] - Checked: RLVa-2.0.1 + bool fRlvShouldHideNames = false; + for (const LLUUID& idAgent : ids) { -// [RLVa:KB] - Checked: 2010-04-07 (RLVa-1.2.0d) | Modified: RLVa-1.0.0a // Only allow offering teleports if everyone is a @tplure exception or able to map this avie under @showloc=n if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) { - const LLRelationship* pBuddyInfo = LLAvatarTracker::instance().getBuddyInfo(*it); - if ( (!gRlvHandler.isException(RLV_BHVR_TPLURE, *it, RLV_CHECK_PERMISSIVE)) && + const LLRelationship* pBuddyInfo = LLAvatarTracker::instance().getBuddyInfo(idAgent); + if ( (!gRlvHandler.isException(RLV_BHVR_TPLURE, idAgent, RLV_CHECK_PERMISSIVE)) && ((!pBuddyInfo) || (!pBuddyInfo->isOnline()) || (!pBuddyInfo->isRightGrantedTo(LLRelationship::GRANT_MAP_LOCATION))) ) { return; } } -// [/RLVa:KB] - payload["ids"].append(*it); + fRlvShouldHideNames |= !RlvActions::canShowName(RlvActions::SNC_TELEPORTOFFER); + payload["ids"].append(idAgent); } + payload["rlv_shownames"] = fRlvShouldHideNames; +// [/RLVa:KB] +// for (std::vector::const_iterator it = ids.begin(); +// it != ids.end(); +// ++it) +// { +// payload["ids"].append(*it); +// } if (gAgent.isGodlike()) { LLNotificationsUtil::add("OfferTeleportFromGod", edit_args, payload, handle_lure_callback); @@ -7626,16 +6715,16 @@ void handle_lure(const uuid_vec_t& ids) bool teleport_request_callback(const LLSD& notification, const LLSD& response) { LLUUID from_id = notification["payload"]["from_id"].asUUID(); - if(from_id.isNull()) + if (from_id.isNull()) { - llwarns << "from_id is NULL" << llendl; + LL_WARNS() << "from_id is NULL" << LL_ENDL; return false; } std::string from_name; gCacheName->getFullName(from_id, from_name); - if(LLMuteList::getInstance()->isMuted(from_id) && !LLMuteList::getInstance()->isLinden(from_name)) + if (LLMuteList::getInstance()->isMuted(from_id) && !LLMuteList::getInstance()->isLinden(from_name)) { return false; } @@ -7650,7 +6739,7 @@ bool teleport_request_callback(const LLSD& notification, const LLSD& response) option = LLNotificationsUtil::getSelectedOption(notification, response); } - switch(option) + switch (option) { // Yes case 0: @@ -7665,14 +6754,6 @@ bool teleport_request_callback(const LLSD& notification, const LLSD& response) } break; - // Profile - case 3: - { - LLAvatarActions::showProfile(from_id); - LLNotificationsUtil::add(notification["name"], notification["substitutions"], notification["payload"]); //Respawn! - } - break; - // No case 1: default: @@ -7739,12 +6820,12 @@ void send_places_query(const LLUUID& query_id, gAgent.sendReliableMessage(); } - +// Deprecated in favor of cap "UserInfo" void process_user_info_reply(LLMessageSystem* msg, void**) { LLUUID agent_id; msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); - if(agent_id != gAgent.getID()) + if (agent_id != gAgent.getID()) { LL_WARNS("Messaging") << "process_user_info_reply - " << "wrong agent id." << LL_ENDL; @@ -7755,8 +6836,9 @@ void process_user_info_reply(LLMessageSystem* msg, void**) std::string email; msg->getStringFast(_PREHASH_UserData, _PREHASH_EMail, email); std::string dir_visibility; - msg->getString( "UserData", "DirectoryVisibility", dir_visibility); + msg->getString("UserData", "DirectoryVisibility", dir_visibility); + // For Message based user info information the is_verified is assumed to be false. LLFloaterPreference::updateUserInfo(dir_visibility, im_via_email, email); LLFloaterPostcard::updateUserInfo(email); } @@ -7767,23 +6849,43 @@ void process_user_info_reply(LLMessageSystem* msg, void**) //--------------------------------------------------------------------------- const S32 SCRIPT_DIALOG_MAX_BUTTONS = 12; -const S32 SCRIPT_DIALOG_BUTTON_STR_SIZE = 24; -const S32 SCRIPT_DIALOG_MAX_MESSAGE_SIZE = 512; const char* SCRIPT_DIALOG_HEADER = "Script Dialog:\n"; bool callback_script_dialog(const LLSD& notification, const LLSD& response) { LLNotificationForm form(notification["form"]); - std::string button = LLNotification::getSelectedOptionName(response); + std::string rtn_text; S32 button_idx = LLNotification::getSelectedOption(notification, response); - // Didn't click "Ignore" - if (button_idx != -1) + + if (notification["payload"].has("textbox")) + { + rtn_text = response["message"].asString(); + } + else + { + rtn_text = LLNotification::getSelectedOptionName(response); + } + + // Button -2 = Mute + // Button -1 = Ignore - no processing needed for this button + // Buttons 0 and above = dialog choices + + if (-2 == button_idx) { - if (notification["payload"].has("textbox")) + std::string object_name = notification["payload"]["object_name"].asString(); + LLUUID object_id = notification["payload"]["object_id"].asUUID(); + LLMute mute(object_id, object_name, LLMute::OBJECT); + if (LLMuteList::getInstance()->add(mute)) { - button = response["message"].asString(); + // This call opens the sidebar, displays the block list, and highlights the newly blocked + // object in the list so the user can see that their block click has taken effect. + LLFloaterMute::showInstance()->selectMute(object_id); } + } + + if (0 <= button_idx) + { LLMessageSystem* msg = gMessageSystem; msg->newMessage("ScriptDialogReply"); msg->nextBlock("AgentData"); @@ -7793,12 +6895,13 @@ bool callback_script_dialog(const LLSD& notification, const LLSD& response) msg->addUUID("ObjectID", notification["payload"]["object_id"].asUUID()); msg->addS32("ChatChannel", notification["payload"]["chat_channel"].asInteger()); msg->addS32("ButtonIndex", button_idx); - msg->addString("ButtonLabel", button); + msg->addString("ButtonLabel", rtn_text); msg->sendReliable(LLHost(notification["payload"]["sender"].asString())); } return false; } + static LLNotificationFunctorRegistration callback_script_dialog_reg_1("ScriptDialog", callback_script_dialog); static LLNotificationFunctorRegistration callback_script_dialog_reg_2("ScriptDialogGroup", callback_script_dialog); @@ -7811,24 +6914,32 @@ void process_script_dialog(LLMessageSystem* msg, void**) msg->getUUID("Data", "ObjectID", object_id); // NaCl - Antispam Registry - if(NACLAntiSpamRegistry::checkQueue((U32)NACLAntiSpamRegistry::QUEUE_SCRIPT_DIALOG,object_id)) + auto antispam = NACLAntiSpamRegistry::getIfExists(); + if (antispam && antispam->checkQueue(NACLAntiSpamRegistry::QUEUE_SCRIPT_DIALOG, object_id, LFIDBearer::OBJECT)) return; // NaCl End -// For compability with OS grids first check for presence of extended packet before fetching data. + std::string first_name; + msg->getString("Data", "FirstName", first_name); + bool const is_group = first_name.empty(); + + // For compability with OS grids first check for presence of extended packet before fetching data. LLUUID owner_id; if (gMessageSystem->getNumberOfBlocks("OwnerData") > 0) { msg->getUUID("OwnerData", "OwnerID", owner_id); // NaCl - Antispam Registry - if(NACLAntiSpamRegistry::checkQueue((U32)NACLAntiSpamRegistry::QUEUE_SCRIPT_DIALOG,owner_id)) + if (antispam && antispam->checkQueue(NACLAntiSpamRegistry::QUEUE_SCRIPT_DIALOG, owner_id, is_group ? LFIDBearer::GROUP : LFIDBearer::AVATAR)) return; // NaCl End } + bool has_owner = owner_id.notNull(); + // NaCl - Antispam - if (owner_id.isNull() ? is_spam_filtered(IM_COUNT, LLAvatarActions::isFriend(object_id), object_id == gAgentID) : is_spam_filtered(IM_COUNT, LLAvatarActions::isFriend(owner_id), owner_id == gAgentID)) return; + if (!has_owner ? is_spam_filtered(IM_COUNT, LLAvatarActions::isFriend(object_id), object_id == gAgentID) + : is_spam_filtered(IM_COUNT, LLAvatarActions::isFriend(owner_id), !is_group && owner_id == gAgentID)) return; // NaCl End if (LLMuteList::getInstance()->isMuted(object_id) || LLMuteList::getInstance()->isMuted(owner_id)) @@ -7836,13 +6947,15 @@ void process_script_dialog(LLMessageSystem* msg, void**) return; } + auto chatter = gObjectList.findObject(object_id); + // Singu Note: Try to get Owner whenever possible + if (chatter && has_owner) chatter->mOwnerID = owner_id; + std::string message; - std::string first_name; std::string last_name; std::string object_name; S32 chat_channel; - msg->getString("Data", "FirstName", first_name); msg->getString("Data", "LastName", last_name); msg->getString("Data", "ObjectName", object_name); msg->getString("Data", "Message", message); @@ -7854,57 +6967,72 @@ void process_script_dialog(LLMessageSystem* msg, void**) payload["sender"] = msg->getSender().getIPandPort(); payload["object_id"] = object_id; + payload["object_name"] = object_name; payload["chat_channel"] = chat_channel; // build up custom form S32 button_count = msg->getNumberOfBlocks("Buttons"); if (button_count > SCRIPT_DIALOG_MAX_BUTTONS) { - llwarns << "Too many script dialog buttons - omitting some" << llendl; + LL_WARNS() << "Too many script dialog buttons - omitting some" << LL_ENDL; button_count = SCRIPT_DIALOG_MAX_BUTTONS; } - LLNotificationForm form; - std::string firstbutton; - msg->getString("Buttons", "ButtonLabel", firstbutton, 0); - form.addElement("button", std::string(firstbutton)); bool is_text_box = false; - std::string default_text; - if (firstbutton == "!!llTextBox!!") + LLNotificationForm form; + for (i = 0; i < button_count; i++) { - is_text_box = true; - for (i = 1; i < button_count; i++) - { - std::string tdesc; - msg->getString("Buttons", "ButtonLabel", tdesc, i); - default_text += tdesc; - } + std::string tdesc; + msg->getString("Buttons", "ButtonLabel", tdesc, i); + if (is_text_box = tdesc == TEXTBOX_MAGIC_TOKEN) + break; + form.addElement("button", std::string(tdesc)); } - else + + LLSD query_string; + query_string["owner"] = owner_id; + if (rlv_handler_t::isEnabled() && (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES) || gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS)) && !is_group && RlvUtil::isNearbyAgent(owner_id)) + { + query_string["rlv_shownames"] = true; + } + + if (const auto& obj = chatter ? chatter : gObjectList.findObject(owner_id)) // Fallback on the owner, if the chatter isn't present { - for (i = 1; i < button_count; i++) + auto& slurl = query_string["slurl"]; + const auto& region = obj->getRegion(); + if (rlv_handler_t::isEnabled() && gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC) && LLWorld::instance().isRegionListed(region)) + slurl = RlvStrings::getString(RLV_STRING_HIDDEN_REGION); + else { - std::string tdesc; - msg->getString("Buttons", "ButtonLabel", tdesc, i); - form.addElement("button", std::string(tdesc)); + const auto& pos = obj->getPositionRegion(); + S32 x = ll_round((F32)fmod((F64)pos.mV[VX], (F64)REGION_WIDTH_METERS)); + S32 y = ll_round((F32)fmod((F64)pos.mV[VY], (F64)REGION_WIDTH_METERS)); + S32 z = ll_round((F32)pos.mV[VZ]); + std::ostringstream location; + location << region->getName() << '/' << x << '/' << y << '/' << z; + if (chatter != obj) location << "?owner_not_object"; + slurl = location.str(); } } + query_string["name"] = object_name; + query_string["groupowned"] = is_group; + object_name = LLSLURL("objectim", object_id, LLURI::mapToQueryString(query_string)).getSLURLString(); LLSD args; args["TITLE"] = object_name; - args["MESSAGE"] = message; + args["MESSAGE"] = LLStringUtil::null; + args["SCRIPT_MESSAGE"] = message; args["CHANNEL"] = chat_channel; LLNotificationPtr notification; - bool const is_group = first_name.empty(); char const* name = (is_group && !is_text_box) ? "GROUPNAME" : "NAME"; - args[name] = is_group ? last_name : LLCacheName::buildFullName(first_name, last_name); + args[name] = has_owner ? is_group ? LLGroupActions::getSLURL(owner_id) : LLAvatarActions::getSLURL(owner_id) : + is_group ? last_name : LLCacheName::buildFullName(first_name, last_name); if (is_text_box) { - args["DEFAULT"] = default_text; - payload["textbox"] = "true"; + payload["textbox"] = true; LLNotificationsUtil::add("ScriptTextBoxDialog", args, payload, callback_script_dialog); } - else if (!first_name.empty()) + else if (!is_group) { notification = LLNotifications::instance().add( LLNotification::Params("ScriptDialog").substitutions(args).payload(payload).form_elements(form.asLLSD())); @@ -7932,15 +7060,15 @@ bool callback_load_url(const LLSD& notification, const LLSD& response) return false; } -static LLNotificationFunctorRegistration callback_load_url_reg("LoadWebPage", callback_load_url); +static LLNotificationFunctorRegistration callback_load_url_reg("LoadWebPage", callback_load_url); -// We've got the name of the person who owns the object hurling the url. +// We've got the name of the person or group that owns the object hurling the url. // Display confirmation dialog. void callback_load_url_name(const LLUUID& id, const std::string& full_name, bool is_group) { std::vector::iterator it; - for (it = gLoadUrlList.begin(); it != gLoadUrlList.end(); ) + for (it = gLoadUrlList.begin(); it != gLoadUrlList.end();) { LLSD load_url_info = *it; if (load_url_info["owner_id"].asUUID() == id) @@ -7964,7 +7092,7 @@ void callback_load_url_name(const LLUUID& id, const std::string& full_name, bool } LLSD args; args["URL"] = load_url_info["url"].asString(); - args["MESSAGE"] = load_url_info["message"].asString();; + args["MESSAGE"] = load_url_info["message"].asString(); args["OBJECTNAME"] = load_url_info["object_name"].asString(); args["NAME"] = owner_name; @@ -7977,6 +7105,12 @@ void callback_load_url_name(const LLUUID& id, const std::string& full_name, bool } } +// We've got the name of the person who owns the object hurling the url. +void callback_load_url_avatar_name(const LLUUID& id, const LLAvatarName& av_name) +{ + callback_load_url_name(id, av_name.getUserName(), false); +} + void process_load_url(LLMessageSystem* msg, void**) { LLUUID object_id; @@ -7987,21 +7121,26 @@ void process_load_url(LLMessageSystem* msg, void**) char url[256]; /* Flawfinder: ignore */ msg->getString("Data", "ObjectName", 256, object_name); - msg->getUUID( "Data", "ObjectID", object_id); - msg->getUUID( "Data", "OwnerID", owner_id); + msg->getUUID("Data", "ObjectID", object_id); + msg->getUUID("Data", "OwnerID", owner_id); // NaCl - Antispam - if (owner_id.isNull() ? is_spam_filtered(IM_COUNT, LLAvatarActions::isFriend(object_id), object_id == gAgentID) : is_spam_filtered(IM_COUNT, LLAvatarActions::isFriend(owner_id), owner_id == gAgentID)) return; + if (owner_id.isNull() ? is_spam_filtered(IM_COUNT, LLAvatarActions::isFriend(object_id), object_id == gAgentID) + : is_spam_filtered(IM_COUNT, LLAvatarActions::isFriend(owner_id), owner_id == gAgentID)) return; // NaCl End + msg->getBOOL("Data", "OwnerIsGroup", owner_is_group); // NaCl - Antispam Registry - if((owner_id.isNull() - && NACLAntiSpamRegistry::checkQueue((U32)NACLAntiSpamRegistry::QUEUE_SCRIPT_DIALOG,object_id)) - || NACLAntiSpamRegistry::checkQueue((U32)NACLAntiSpamRegistry::QUEUE_SCRIPT_DIALOG,owner_id)) - return; + if (NACLAntiSpamRegistry::instanceExists()) + { + auto& antispam = NACLAntiSpamRegistry::instance(); + if ((owner_id.isNull() + && antispam.checkQueue(NACLAntiSpamRegistry::QUEUE_SCRIPT_DIALOG, object_id, LFIDBearer::OBJECT)) + || antispam.checkQueue(NACLAntiSpamRegistry::QUEUE_SCRIPT_DIALOG, owner_id, owner_is_group ? LFIDBearer::GROUP : LFIDBearer::AVATAR)) + return; + } // NaCl End - msg->getBOOL( "Data", "OwnerIsGroup", owner_is_group); msg->getString("Data", "Message", 256, message); msg->getString("Data", "URL", 256, url); @@ -8019,15 +7158,21 @@ void process_load_url(LLMessageSystem* msg, void**) if (LLMuteList::getInstance()->isMuted(object_id, object_name) || LLMuteList::getInstance()->isMuted(owner_id)) { - LL_INFOS("Messaging")<<"Ignoring load_url from muted object/owner."<get(owner_id, owner_is_group, - boost::bind(&callback_load_url_name, _1, _2, _3)); + if (owner_is_group) + { + gCacheName->getGroup(owner_id, boost::bind(&callback_load_url_name, _1, _2, _3)); + } + else + { + LLAvatarNameCache::get(owner_id, boost::bind(&callback_load_url_avatar_name, _1, _2)); + } } @@ -8058,7 +7203,7 @@ void process_initiate_download(LLMessageSystem* msg, void**) if (!gXferManager->validateFileForRequest(viewer_filename)) { - llwarns << "SECURITY: Unauthorized download to local file " << viewer_filename << llendl; + LL_WARNS() << "SECURITY: Unauthorized download to local file " << viewer_filename << LL_ENDL; return; } gXferManager->requestFile(viewer_filename, @@ -8095,7 +7240,6 @@ void process_script_teleport_request(LLMessageSystem* msg, void**) // remove above two lines and replace with below line // to re-enable parcel browser for llMapDestination() // LLURLDispatcher::dispatch(LLSLURL::buildSLURL(sim_name, (S32)pos.mV[VX], (S32)pos.mV[VY], (S32)pos.mV[VZ]), FALSE); - } void process_covenant_reply(LLMessageSystem* msg, void**) @@ -8113,7 +7257,10 @@ void process_covenant_reply(LLMessageSystem* msg, void**) LLPanelEstateInfo::updateEstateName(estate_name); LLFloaterBuyLand::updateEstateName(estate_name); - LLAvatarNameCache::get(estate_owner_id, boost::bind(&callbackCacheEstateOwnerName, _1, _2)); + LLPanelEstateCovenant::updateEstateOwnerID(estate_owner_id); + LLPanelLandCovenant::updateEstateOwnerID(estate_owner_id); + LLPanelEstateInfo::updateEstateOwnerID(estate_owner_id); + LLFloaterBuyLand::updateEstateOwnerID(estate_owner_id); // standard message, not from system std::string last_modified; @@ -8123,7 +7270,7 @@ void process_covenant_reply(LLMessageSystem* msg, void**) } else { - last_modified = LLTrans::getString("covenant_modified") + " " + formatted_time((time_t)covenant_timestamp); + last_modified = LLTrans::getString("covenant_modified") + ' ' + formatted_time((time_t)covenant_timestamp); } LLPanelEstateCovenant::updateLastModified(last_modified); @@ -8141,7 +7288,7 @@ void process_covenant_reply(LLMessageSystem* msg, void**) LLAssetType::AT_NOTECARD, ET_Covenant, onCovenantLoadComplete, - NULL, + nullptr, high_priority); } else @@ -8162,45 +7309,28 @@ void process_covenant_reply(LLMessageSystem* msg, void**) } } -void callbackCacheEstateOwnerName(const LLUUID& id, const LLAvatarName& av_name) -{ - std::string name; - LLAvatarNameCache::getPNSName(av_name, name); - - LLPanelEstateCovenant::updateEstateOwnerName(name); - LLPanelLandCovenant::updateEstateOwnerName(name); - LLPanelEstateInfo::updateEstateOwnerName(name); - LLFloaterBuyLand::updateEstateOwnerName(name); -} - -void onCovenantLoadComplete(LLVFS *vfs, +void onCovenantLoadComplete(LLVFS* vfs, const LLUUID& asset_uuid, LLAssetType::EType type, void* user_data, S32 status, LLExtStat ext_status) { LL_DEBUGS("Messaging") << "onCovenantLoadComplete()" << LL_ENDL; std::string covenant_text; - if(0 == status) + if (0 == status) { LLVFile file(vfs, asset_uuid, type, LLVFile::READ); S32 file_length = file.getSize(); - char* buffer = new char[file_length+1]; - if (buffer == NULL) - { - LL_ERRS("Messaging") << "Memory Allocation failed" << LL_ENDL; - return; - } - - file.read((U8*)buffer, file_length); /* Flawfinder: ignore */ + std::vector buffer(file_length + 1); + file.read((U8*)&buffer[0], file_length); // put a EOS at the end - buffer[file_length] = 0; - - if( (file_length > 19) && !strncmp( buffer, "Linden text version", 19 ) ) + buffer[file_length] = '\0'; + + if ((file_length > 19) && !strncmp(&buffer[0], "Linden text version", 19)) { LLViewerTextEditor * editor = new LLViewerTextEditor(std::string("temp"), LLRect(0,0,0,0), file_length+1); - if( !editor->importBuffer( buffer, file_length+1 ) ) + if( !editor->importBuffer( &buffer[0], file_length+1 ) ) { LL_WARNS("Messaging") << "Problem importing estate covenant." << LL_ENDL; covenant_text = "Problem importing estate covenant."; @@ -8217,13 +7347,12 @@ void onCovenantLoadComplete(LLVFS *vfs, LL_WARNS("Messaging") << "Problem importing estate covenant: Covenant file format error." << LL_ENDL; covenant_text = "Problem importing estate covenant: Covenant file format error."; } - delete[] buffer; } else { LLViewerStats::getInstance()->incStat( LLViewerStats::ST_DOWNLOAD_FAILED ); - if( LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status || + if (LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status || LL_ERR_FILE_EMPTY == status) { covenant_text = "Estate covenant notecard is missing from database."; @@ -8251,9 +7380,9 @@ void process_feature_disabled_message(LLMessageSystem* msg, void**) LLUUID agentID; LLUUID transactionID; std::string messageText; - msg->getStringFast(_PREHASH_FailureInfo,_PREHASH_ErrorMessage, messageText,0); - msg->getUUIDFast(_PREHASH_FailureInfo,_PREHASH_AgentID,agentID); - msg->getUUIDFast(_PREHASH_FailureInfo,_PREHASH_TransactionID,transactionID); + msg->getStringFast(_PREHASH_FailureInfo, _PREHASH_ErrorMessage, messageText, 0); + msg->getUUIDFast(_PREHASH_FailureInfo, _PREHASH_AgentID, agentID); + msg->getUUIDFast(_PREHASH_FailureInfo, _PREHASH_TransactionID, transactionID); LL_WARNS("Messaging") << "Blacklisted Feature Response:" << messageText << LL_ENDL; } diff --git a/indra/newview/llviewermessage.h b/indra/newview/llviewermessage.h index a31b7f4860..acfb590b07 100644 --- a/indra/newview/llviewermessage.h +++ b/indra/newview/llviewermessage.h @@ -70,7 +70,11 @@ enum InventoryOfferResponse BOOL can_afford_transaction(S32 cost); void give_money(const LLUUID& uuid, LLViewerRegion* region, S32 amount, BOOL is_group = FALSE, S32 trx_type = TRANS_GIFT, const std::string& desc = LLStringUtil::null); -void busy_message (LLMessageSystem* msg, LLUUID from_id); +void send_join_group_response(const LLUUID& group_id, + const LLUUID& transaction_id, + bool accept_invite, + S32 fee, + bool use_offline_cap); void process_logout_reply(LLMessageSystem* msg, void**); void process_layer_data(LLMessageSystem *mesgsys, void **user_data); @@ -103,6 +107,7 @@ void process_health_message(LLMessageSystem *mesgsys, void **user_data); void process_sim_stats(LLMessageSystem *mesgsys, void **user_data); void process_shooter_agent_hit(LLMessageSystem* msg, void** user_data); void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data); +void process_object_animation(LLMessageSystem *mesgsys, void **user_data); void process_avatar_appearance(LLMessageSystem *mesgsys, void **user_data); void process_camera_constraint(LLMessageSystem *mesgsys, void **user_data); void process_avatar_sit_response(LLMessageSystem *mesgsys, void **user_data); @@ -160,6 +165,8 @@ void send_group_notice(const LLUUID& group_id, const std::string& message, const LLInventoryItem* item); +void send_do_not_disturb_message (LLMessageSystem* msg, const LLUUID& from_id, const LLUUID& session_id = LLUUID::null); + void handle_lure(const LLUUID& invitee); void handle_lure(const uuid_vec_t& ids); @@ -203,7 +210,6 @@ void process_decline_callingcard(LLMessageSystem* msg, void**); // Message system exception prototypes void invalid_message_callback(LLMessageSystem*, void*, EMessageException); - void process_initiate_download(LLMessageSystem* msg, void**); void start_new_inventory_observer(); void open_inventory_offer(const uuid_vec_t& items, const std::string& from_name); diff --git a/indra/newview/llviewernetwork.h b/indra/newview/llviewernetwork.h index bb15fd323c..18a6e0c456 100644 --- a/indra/newview/llviewernetwork.h +++ b/indra/newview/llviewernetwork.h @@ -63,7 +63,7 @@ class LLViewerLogin : public LLSingleton private: //void parseCommandLineURIs(); - bool mNameEditted; // Set if the user edits/sets the First or Last name field. + bool mNameEditted = false; // Set if the user edits/sets the First or Last name field. }; diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 6429b89c71..8deaa7829e 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llviewerobject.cpp * @brief Base class for viewer objects * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -59,6 +59,7 @@ #include "llbbox.h" #include "llbox.h" #include "llcylinder.h" +#include "llcontrolavatar.h" #include "lldrawable.h" #include "llface.h" #include "llfloaterproperties.h" @@ -68,6 +69,7 @@ #include "llselectmgr.h" #include "llrendersphere.h" #include "lltooldraganddrop.h" +#include "lluiavatar.h" #include "llviewercamera.h" #include "llviewertexturelist.h" #include "llviewerinventory.h" @@ -98,7 +100,7 @@ #include "llvowlsky.h" #include "llmanip.h" #include "llmediaentry.h" - +#include "llmeshrepository.h" // [RLVa:KB] #include "rlvhandler.h" #include "rlvlocks.h" @@ -107,7 +109,7 @@ //#define DEBUG_UPDATE_TYPE BOOL LLViewerObject::sVelocityInterpolate = TRUE; -BOOL LLViewerObject::sPingInterpolate = TRUE; +BOOL LLViewerObject::sPingInterpolate = TRUE; U32 LLViewerObject::sNumZombieObjects = 0; S32 LLViewerObject::sNumObjects = 0; @@ -119,18 +121,30 @@ BOOL LLViewerObject::sPulseEnabled(FALSE); BOOL LLViewerObject::sUseSharedDrawables(FALSE); // TRUE // sMaxUpdateInterpolationTime must be greater than sPhaseOutUpdateInterpolationTime -F64 LLViewerObject::sMaxUpdateInterpolationTime = 3.0; // For motion interpolation: after X seconds with no updates, don't predict object motion -F64 LLViewerObject::sPhaseOutUpdateInterpolationTime = 2.0; // For motion interpolation: after Y seconds with no updates, taper off motion prediction +F64Seconds LLViewerObject::sMaxUpdateInterpolationTime(3.0); // For motion interpolation: after X seconds with no updates, don't predict object motion +F64Seconds LLViewerObject::sPhaseOutUpdateInterpolationTime(2.0); // For motion interpolation: after Y seconds with no updates, taper off motion prediction + +std::map LLViewerObject::sObjectDataMap; + +// The maximum size of an object extra parameters binary (packed) block +#define MAX_OBJECT_PARAMS_SIZE 1024 + +// At 45 Hz collisions seem stable and objects seem +// to settle down at a reasonable rate. +// JC 3/18/2003 +const F32 PHYSICS_TIMESTEP = 1.f / 45.f; +const U32 MAX_INV_FILE_READ_FAILS = 25; +const S32 MAX_OBJECT_BINARY_DATA_SIZE = 60 + 16; -static LLFastTimer::DeclareTimer FTM_CREATE_OBJECT("Create Object"); +static LLTrace::BlockTimerStatHandle FTM_CREATE_OBJECT("Create Object"); // static -LLViewerObject *LLViewerObject::createObject(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp) +LLViewerObject *LLViewerObject::createObject(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp, S32 flags) { LLViewerObject *res = NULL; - LLFastTimer t1(FTM_CREATE_OBJECT); - + LL_RECORD_BLOCK_TIME(FTM_CREATE_OBJECT); + switch (pcode) { case LL_PCODE_VOLUME: @@ -143,8 +157,9 @@ LLViewerObject *LLViewerObject::createObject(const LLUUID &id, const LLPCode pco { gAgentAvatarp = new LLVOAvatarSelf(id, pcode, regionp); gAgentAvatarp->initInstance(); + gAgentWearables.setAvatarObject(gAgentAvatarp); } - else + else { if (isAgentAvatarValid()) { @@ -153,9 +168,21 @@ LLViewerObject *LLViewerObject::createObject(const LLUUID &id, const LLPCode pco } res = gAgentAvatarp; } + else if (flags & CO_FLAG_CONTROL_AVATAR) + { + LLControlAvatar *control_avatar = new LLControlAvatar(id, pcode, regionp); + control_avatar->initInstance(); + res = control_avatar; + } + else if (flags & CO_FLAG_UI_AVATAR) + { + LLUIAvatar *ui_avatar = new LLUIAvatar(id, pcode, regionp); + ui_avatar->initInstance(); + res = ui_avatar; + } else { - LLVOAvatar *avatar = new LLVOAvatar(id, pcode, regionp); + LLVOAvatar *avatar = new LLVOAvatar(id, pcode, regionp); avatar->initInstance(); res = avatar; } @@ -164,13 +191,13 @@ LLViewerObject *LLViewerObject::createObject(const LLUUID &id, const LLPCode pco case LL_PCODE_LEGACY_GRASS: res = new LLVOGrass(id, pcode, regionp); break; case LL_PCODE_LEGACY_PART_SYS: -// llwarns << "Creating old part sys!" << llendl; +// LL_WARNS() << "Creating old part sys!" << LL_ENDL; // res = new LLVOPart(id, pcode, regionp); break; res = NULL; break; case LL_PCODE_LEGACY_TREE: res = new LLVOTree(id, pcode, regionp); break; case LL_PCODE_TREE_NEW: -// llwarns << "Creating new tree!" << llendl; +// LL_WARNS() << "Creating new tree!" << LL_ENDL; // res = new LLVOTree(id, pcode, regionp); break; res = NULL; break; #if ENABLE_CLASSIC_CLOUDS @@ -194,7 +221,7 @@ LLViewerObject *LLViewerObject::createObject(const LLUUID &id, const LLPCode pco case LL_VO_WL_SKY: res = new LLVOWLSky(id, pcode, regionp); break; default: - llwarns << "Unknown object pcode " << (S32)pcode << llendl; + LL_WARNS() << "Unknown object pcode " << (S32)pcode << LL_ENDL; res = NULL; break; } return res; @@ -208,6 +235,8 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe mTotalCRC(0), mListIndex(-1), mTEImages(NULL), + mTENormalMaps(NULL), + mTESpecularMaps(NULL), mGLName(0), mbCanSelect(TRUE), mFlags(0), @@ -221,6 +250,9 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe mRenderMedia(FALSE), mBestUpdatePrecision(0), mText(), + + mHudTextColor(LLColor4::white), + mControlAvatar(NULL), mLastInterpUpdateSecs(0.f), mLastMessageUpdateSecs(0.f), mLatestRecvPacketID(0), @@ -231,9 +263,10 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe mPixelArea(1024.f), mInventory(NULL), mInventorySerialNum(0), - mRegionp( regionp ), - mInventoryPending(FALSE), + mInvRequestState(INVENTORY_REQUEST_STOPPED), + mInvRequestXFerId(0), mInventoryDirty(FALSE), + mRegionp(regionp), mDead(FALSE), mOrphaned(FALSE), mUserSelected(FALSE), @@ -241,11 +274,10 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe mOnMap(FALSE), mStatic(FALSE), mNumFaces(0), - mTimeDilation(1.f), mRotTime(0.f), mAngularVelocityRot(), mPreviousRotation(), - mState(0), + mAttachmentState(0), mMedia(NULL), mClickAction(0), mObjectCost(0), @@ -256,7 +288,8 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe mPhysicsShapeUnknown(true), mAttachmentItemID(LLUUID::null), mLastUpdateType(OUT_UNKNOWN), - mLastUpdateCached(FALSE) + mLastUpdateCached(FALSE), + mExtraParameterList(LLNetworkData::PARAMS_MAX >> 4) { if(!is_global) { @@ -302,23 +335,11 @@ LLViewerObject::~LLViewerObject() } // Delete memory associated with extra parameters. - std::map::iterator iter; - for (iter = mExtraParameterList.begin(); iter != mExtraParameterList.end(); ++iter) - { - if(iter->second != NULL) - { - // - // There was a crash here - // - delete iter->second->data; - delete iter->second; - } - } mExtraParameterList.clear(); for_each(mNameValuePairs.begin(), mNameValuePairs.end(), DeletePairedPointer()) ; mNameValuePairs.clear(); - + delete[] mData; mData = NULL; @@ -336,22 +357,64 @@ void LLViewerObject::deleteTEImages() { delete[] mTEImages; mTEImages = NULL; + + if (mTENormalMaps != NULL) + { + delete[] mTENormalMaps; + mTENormalMaps = NULL; + } + + if (mTESpecularMaps != NULL) + { + delete[] mTESpecularMaps; + mTESpecularMaps = NULL; + } } void LLViewerObject::markDead() { if (!mDead) { - //llinfos << "Marking self " << mLocalID << " as dead." << llendl; - + //LL_INFOS() << "Marking self " << mLocalID << " as dead." << LL_ENDL; + + // + if (isSelected()) + { + // This is needed in order to reset mPauseRequest in case this is an attachment. + // Note that using deselectObjectAndFamily here doesn't work because if the + // avatar is sitting on a pose ball then deselectObjectAndFamily tries to + // deselect that pose ball and does NOT include the avatar and attachments + // in this 'family'. That seems a bug to me because it just is very unlogical, + // but ok-- this works too. + LLSelectMgr::getInstance()->deselectObjectOnly(this, FALSE); + } + // + // Root object of this hierarchy unlinks itself. if (getParent()) { ((LLViewerObject *)getParent())->removeChild(this); } + LLUUID mesh_id; + { + LLVOAvatar *av = getAvatar(); + if (av && LLVOAvatar::getRiggedMeshID(this,mesh_id)) + { + // This case is needed for indirectly attached mesh objects. + av->updateAttachmentOverrides(); + } + } + if (getControlAvatar()) + { + unlinkControlAvatar(); + } // Mark itself as dead mDead = TRUE; + if(mRegionp) + { + mRegionp->removeFromCreatedList(getLocalID()); + } gObjectList.cleanupReferences(this); LLViewerObject *childp; @@ -360,13 +423,13 @@ void LLViewerObject::markDead() childp = mChildList.back(); if (childp->getPCode() != LL_PCODE_LEGACY_AVATAR) { - //llinfos << "Marking child " << childp->getLocalID() << " as dead." << llendl; + //LL_INFOS() << "Marking child " << childp->getLocalID() << " as dead." << LL_ENDL; childp->setParent(NULL); // LLViewerObject::markDead 1 childp->markDead(); } else { - // make sure avatar is no longer parented, + // make sure avatar is no longer parented, // so we can properly set it's position childp->setDrawableParent(NULL); ((LLVOAvatar*)childp)->getOffObject(); @@ -430,49 +493,49 @@ void LLViewerObject::markDead() void LLViewerObject::dump() const { - llinfos << "Type: " << pCodeToString(mPrimitiveCode) << llendl; - llinfos << "Drawable: " << (LLDrawable *)mDrawable << llendl; - llinfos << "Update Age: " << LLFrameTimer::getElapsedSeconds() - mLastMessageUpdateSecs << llendl; - - llinfos << "Parent: " << getParent() << llendl; - llinfos << "ID: " << mID << llendl; - llinfos << "LocalID: " << mLocalID << llendl; - llinfos << "PositionRegion: " << getPositionRegion() << llendl; - llinfos << "PositionAgent: " << getPositionAgent() << llendl; - llinfos << "PositionGlobal: " << getPositionGlobal() << llendl; - llinfos << "Velocity: " << getVelocity() << llendl; - if (mDrawable.notNull() && - mDrawable->getNumFaces() && + LL_INFOS() << "Type: " << pCodeToString(mPrimitiveCode) << LL_ENDL; + LL_INFOS() << "Drawable: " << (LLDrawable *)mDrawable << LL_ENDL; + LL_INFOS() << "Update Age: " << LLFrameTimer::getElapsedSeconds() - mLastMessageUpdateSecs << LL_ENDL; + + LL_INFOS() << "Parent: " << getParent() << LL_ENDL; + LL_INFOS() << "ID: " << mID << LL_ENDL; + LL_INFOS() << "LocalID: " << mLocalID << LL_ENDL; + LL_INFOS() << "PositionRegion: " << getPositionRegion() << LL_ENDL; + LL_INFOS() << "PositionAgent: " << getPositionAgent() << LL_ENDL; + LL_INFOS() << "PositionGlobal: " << getPositionGlobal() << LL_ENDL; + LL_INFOS() << "Velocity: " << getVelocity() << LL_ENDL; + if (mDrawable.notNull() && + mDrawable->getNumFaces() && mDrawable->getFace(0)) { LLFacePool *poolp = mDrawable->getFace(0)->getPool(); if (poolp) { - llinfos << "Pool: " << poolp << llendl; - llinfos << "Pool reference count: " << poolp->mReferences.size() << llendl; + LL_INFOS() << "Pool: " << poolp << LL_ENDL; + LL_INFOS() << "Pool reference count: " << poolp->mReferences.size() << LL_ENDL; } } - //llinfos << "BoxTree Min: " << mDrawable->getBox()->getMin() << llendl; - //llinfos << "BoxTree Max: " << mDrawable->getBox()->getMin() << llendl; + //LL_INFOS() << "BoxTree Min: " << mDrawable->getBox()->getMin() << LL_ENDL; + //LL_INFOS() << "BoxTree Max: " << mDrawable->getBox()->getMin() << LL_ENDL; /* - llinfos << "Velocity: " << getVelocity() << llendl; - llinfos << "AnyOwner: " << permAnyOwner() << " YouOwner: " << permYouOwner() << " Edit: " << mPermEdit << llendl; - llinfos << "UsePhysics: " << flagUsePhysics() << " CanSelect " << mbCanSelect << " UserSelected " << mUserSelected << llendl; - llinfos << "AppAngle: " << mAppAngle << llendl; - llinfos << "PixelArea: " << mPixelArea << llendl; + LL_INFOS() << "Velocity: " << getVelocity() << LL_ENDL; + LL_INFOS() << "AnyOwner: " << permAnyOwner() << " YouOwner: " << permYouOwner() << " Edit: " << mPermEdit << LL_ENDL; + LL_INFOS() << "UsePhysics: " << flagUsePhysics() << " CanSelect " << mbCanSelect << " UserSelected " << mUserSelected << LL_ENDL; + LL_INFOS() << "AppAngle: " << mAppAngle << LL_ENDL; + LL_INFOS() << "PixelArea: " << mPixelArea << LL_ENDL; char buffer[1000]; char *key; for (key = mNameValuePairs.getFirstKey(); key; key = mNameValuePairs.getNextKey() ) { mNameValuePairs[key]->printNameValue(buffer); - llinfos << buffer << llendl; + LL_INFOS() << buffer << LL_ENDL; } for (child_list_t::iterator iter = mChildList.begin(); iter != mChildList.end(); iter++) { LLViewerObject* child = *iter; - llinfos << " child " << child->getID() << llendl; + LL_INFOS() << " child " << child->getID() << LL_ENDL; } */ } @@ -483,7 +546,7 @@ void LLViewerObject::printNameValuePairs() const iter != mNameValuePairs.end(); iter++) { LLNameValue* nv = iter->second; - llinfos << nv->printNameValue() << llendl; + LL_INFOS() << nv->printNameValue() << LL_ENDL; } } @@ -497,10 +560,12 @@ void LLViewerObject::initVOClasses() // Don't init anything else in drone mode return; } - llinfos << "Viewer Object size: " << sizeof(LLViewerObject) << llendl; + LL_INFOS() << "Viewer Object size: " << sizeof(LLViewerObject) << LL_ENDL; LLVOGrass::initClass(); LLVOWater::initClass(); LLVOVolume::initClass(); + + initObjectDataMap(); } void LLViewerObject::cleanupVOClasses() @@ -510,6 +575,118 @@ void LLViewerObject::cleanupVOClasses() LLVOTree::cleanupClass(); LLVOAvatar::cleanupClass(); LLVOVolume::cleanupClass(); + + sObjectDataMap.clear(); +} + +//object data map for compressed && !OUT_TERSE_IMPROVED +//static +void LLViewerObject::initObjectDataMap() +{ + U32 count = 0; + + sObjectDataMap["ID"] = count; //full id //LLUUID + count += sizeof(LLUUID); + + sObjectDataMap["LocalID"] = count; //U32 + count += sizeof(U32); + + sObjectDataMap["PCode"] = count; //U8 + count += sizeof(U8); + + sObjectDataMap["State"] = count; //U8 + count += sizeof(U8); + + sObjectDataMap["CRC"] = count; //U32 + count += sizeof(U32); + + sObjectDataMap["Material"] = count; //U8 + count += sizeof(U8); + + sObjectDataMap["ClickAction"] = count; //U8 + count += sizeof(U8); + + sObjectDataMap["Scale"] = count; //LLVector3 + count += sizeof(LLVector3); + + sObjectDataMap["Pos"] = count; //LLVector3 + count += sizeof(LLVector3); + + sObjectDataMap["Rot"] = count; //LLVector3 + count += sizeof(LLVector3); + + sObjectDataMap["SpecialCode"] = count; //U32 + count += sizeof(U32); + + sObjectDataMap["Owner"] = count; //LLUUID + count += sizeof(LLUUID); + + sObjectDataMap["Omega"] = count; //LLVector3, when SpecialCode & 0x80 is set + count += sizeof(LLVector3); + + //ParentID is after Omega if there is Omega, otherwise is after Owner + sObjectDataMap["ParentID"] = count;//U32, when SpecialCode & 0x20 is set + count += sizeof(U32); + + //------- + //The rest items are not included here + //------- +} + +//static +void LLViewerObject::unpackVector3(LLDataPackerBinaryBuffer* dp, LLVector3& value, std::string name) +{ + dp->shift(sObjectDataMap[name]); + dp->unpackVector3(value, name.c_str()); + dp->reset(); +} + +//static +void LLViewerObject::unpackUUID(LLDataPackerBinaryBuffer* dp, LLUUID& value, std::string name) +{ + dp->shift(sObjectDataMap[name]); + dp->unpackUUID(value, name.c_str()); + dp->reset(); +} + +//static +void LLViewerObject::unpackU32(LLDataPackerBinaryBuffer* dp, U32& value, std::string name) +{ + dp->shift(sObjectDataMap[name]); + dp->unpackU32(value, name.c_str()); + dp->reset(); +} + +//static +void LLViewerObject::unpackU8(LLDataPackerBinaryBuffer* dp, U8& value, std::string name) +{ + dp->shift(sObjectDataMap[name]); + dp->unpackU8(value, name.c_str()); + dp->reset(); +} + +//static +U32 LLViewerObject::unpackParentID(LLDataPackerBinaryBuffer* dp, U32& parent_id) +{ + dp->shift(sObjectDataMap["SpecialCode"]); + U32 value; + dp->unpackU32(value, "SpecialCode"); + + parent_id = 0; + if(value & 0x20) + { + S32 offset = sObjectDataMap["ParentID"]; + if(!(value & 0x80)) + { + offset -= sizeof(LLVector3); + } + + dp->shift(offset); + dp->unpackU32(parent_id, "ParentID"); + } + dp->reset(); + + return parent_id; } // Replaces all name value pairs with data from \n delimited list @@ -536,6 +713,37 @@ void LLViewerObject::setNameValueList(const std::string& name_value_list) } } +BOOL LLViewerObject::isAnySelected() const +{ + bool any_selected = isSelected(); + for (child_list_t::const_iterator iter = mChildList.begin(); + iter != mChildList.end(); iter++) + { + const LLViewerObject* child = *iter; + any_selected = any_selected || child->isSelected(); + } + return any_selected; +} + +void LLViewerObject::setSelected(BOOL sel) +{ + mUserSelected = sel; + static const LLCachedControl use_new_target_omega ("UseNewTargetOmegaCode", true); + if(use_new_target_omega) + { + resetRot(); + } + else + { + mRotTime = 0.f; + } + + if (!sel) + { + setAllTESelected(false); + } +} + // This method returns true if the object is over land owned by the // agent. bool LLViewerObject::isReturnable() @@ -544,7 +752,7 @@ bool LLViewerObject::isReturnable() { return false; } - + // [RLVa:KB] - Checked: 2011-05-28 (RLVa-1.4.0a) | Added: RLVa-1.4.0a // Block if: @rez=n restricted and owned by us or a group *or* @unsit=n restricted and being sat on by us if ( (rlv_handler_t::isEnabled()) && @@ -564,19 +772,19 @@ bool LLViewerObject::isReturnable() } bool result = (mRegionp && mRegionp->objectIsReturnable(getPositionRegion(), boxes)) ? 1 : 0; - + if ( !result ) - { + { //Get list of neighboring regions relative to this vo's region std::vector uniqueRegions; mRegionp->getNeighboringRegions( uniqueRegions ); - + //Build aabb's - for root and all children std::vector returnables; typedef std::vector::iterator RegionIt; RegionIt regionStart = uniqueRegions.begin(); RegionIt regionEnd = uniqueRegions.end(); - + for (; regionStart != regionEnd; ++regionStart ) { LLViewerRegion* pTargetRegion = *regionStart; @@ -586,26 +794,26 @@ bool LLViewerObject::isReturnable() //Add it's children for (child_list_t::iterator iter = mChildList.begin(); iter != mChildList.end(); iter++) { - LLViewerObject* pChild = *iter; + LLViewerObject* pChild = *iter; buildReturnablesForChildrenVO( returnables, pChild, pTargetRegion ); } - } - - //TBD#Eventually create a region -> box list map + } + + //TBD#Eventually create a region -> box list map typedef std::vector::iterator ReturnablesIt; ReturnablesIt retCurrentIt = returnables.begin(); ReturnablesIt retEndIt = returnables.end(); - + for ( ; retCurrentIt !=retEndIt; ++retCurrentIt ) { boxes.clear(); LLViewerRegion* pRegion = (*retCurrentIt).pRegion; - boxes.push_back( (*retCurrentIt).box ); + boxes.push_back( (*retCurrentIt).box ); bool retResult = pRegion && pRegion->childrenObjectReturnable( boxes ) && pRegion->canManageEstate(); if ( retResult ) - { + { result = true; break; } @@ -618,11 +826,11 @@ void LLViewerObject::buildReturnablesForChildrenVO( std::vectormChildList.begin(); iter != pChild->mChildList.end(); iter++) { @@ -633,20 +841,20 @@ void LLViewerObject::buildReturnablesForChildrenVO( std::vector& returnables, LLViewerObject* pChild, LLViewerRegion* pTargetRegion ) { - + LLVector3 targetRegionPos; - targetRegionPos.setVec( pChild->getPositionGlobal() ); - - LLBBox childBBox = LLBBox( targetRegionPos, pChild->getRotationRegion(), pChild->getScale() * -0.5f, - pChild->getScale() * 0.5f).getAxisAligned(); - + targetRegionPos.setVec( pChild->getPositionGlobal() ); + + LLBBox childBBox = LLBBox( targetRegionPos, pChild->getRotationRegion(), pChild->getScale() * -0.5f, + pChild->getScale() * 0.5f).getAxisAligned(); + LLVector3 edgeA = targetRegionPos + childBBox.getMinLocal(); LLVector3 edgeB = targetRegionPos + childBBox.getMaxLocal(); - + LLVector3d edgeAd, edgeBd; edgeAd.setVec(edgeA); edgeBd.setVec(edgeB); - + //Only add the box when either of the extents are in a neighboring region if ( pTargetRegion->pointInRegionGlobal( edgeAd ) || pTargetRegion->pointInRegionGlobal( edgeBd ) ) { @@ -675,7 +883,7 @@ BOOL LLViewerObject::setParent(LLViewerObject* parent) { if (mParent != parent) { - LLViewerObject* old_parent = (LLViewerObject*)mParent ; + LLViewerObject* old_parent = (LLViewerObject*)mParent ; BOOL ret = LLPrimitive::setParent(parent); if (ret && old_parent && parent) { @@ -696,7 +904,7 @@ void LLViewerObject::addChild(LLViewerObject *childp) return; } } - + if (!isAvatar()) { // propagate selection properties @@ -706,9 +914,18 @@ void LLViewerObject::addChild(LLViewerObject *childp) if (childp->setParent(this)) { mChildList.push_back(childp); + childp->afterReparent(); } } +void LLViewerObject::onReparent(LLViewerObject *old_parent, LLViewerObject *new_parent) +{ +} + +void LLViewerObject::afterReparent() +{ +} + void LLViewerObject::removeChild(LLViewerObject *childp) { for (child_list_t::iterator i = mChildList.begin(); i != mChildList.end(); ++i) @@ -724,12 +941,12 @@ void LLViewerObject::removeChild(LLViewerObject *childp) if(childp->getParent() == this) { - childp->setParent(NULL); + childp->setParent(NULL); } break; } } - + if (childp->isSelected()) { LLSelectMgr::getInstance()->deselectObjectAndFamily(childp); @@ -816,8 +1033,8 @@ BOOL LLViewerObject::setDrawableParent(LLDrawable* parentp) return FALSE ; } LLDrawable* old_parent = mDrawable->mParent; - mDrawable->mParent = parentp; - + mDrawable->mParent = parentp; + if (parentp && mDrawable->isActive()) { parentp->makeActive(); @@ -839,7 +1056,7 @@ BOOL LLViewerObject::setDrawableParent(LLDrawable* parentp) mDrawable->movePartition(); }*/ } - + return ret; } @@ -867,7 +1084,7 @@ void LLViewerObject::hideExtraDisplayItems( BOOL hidden ) U32 LLViewerObject::checkMediaURL(const std::string &media_url) { - U32 retval = (U32)0x0; + U32 retval = (U32)0x0; if (!mMedia && !media_url.empty()) { retval |= MEDIA_URL_ADDED; @@ -883,23 +1100,41 @@ U32 LLViewerObject::checkMediaURL(const std::string &media_url) retval |= MEDIA_URL_REMOVED; delete mMedia; mMedia = NULL; - } - else if (mMedia->mMediaURL != media_url) // <-- This is an optimization. If they are equal don't bother with below's test. - { - /*if (! (LLTextureEntry::getAgentIDFromMediaVersionString(media_url) == gAgent.getID() && - LLTextureEntry::getVersionFromMediaVersionString(media_url) == - LLTextureEntry::getVersionFromMediaVersionString(mMedia->mMediaURL) + 1)) + } + else if (mMedia->mMediaURL != media_url) // <-- This is an optimization. If they are equal don't bother with below's test. + { + /*if (! (LLTextureEntry::getAgentIDFromMediaVersionString(media_url) == gAgent.getID() && + LLTextureEntry::getVersionFromMediaVersionString(media_url) == + LLTextureEntry::getVersionFromMediaVersionString(mMedia->mMediaURL) + 1)) */ - { - // If the media URL is different and WE were not the one who - // changed it, mark dirty. - retval |= MEDIA_URL_UPDATED; - } - mMedia->mMediaURL = media_url; - mMedia->mPassedWhitelist = FALSE; - } - } - return retval; + { + // If the media URL is different and WE were not the one who + // changed it, mark dirty. + retval |= MEDIA_URL_UPDATED; + } + mMedia->mMediaURL = media_url; + mMedia->mPassedWhitelist = FALSE; + } + } + return retval; +} + +//extract spatial information from object update message +//return parent_id +//static +U32 LLViewerObject::extractSpatialExtents(LLDataPackerBinaryBuffer *dp, LLVector3& pos, LLVector3& scale, LLQuaternion& rot) +{ + U32 parent_id = 0; + LLViewerObject::unpackParentID(dp, parent_id); + + LLViewerObject::unpackVector3(dp, scale, "Scale"); + LLViewerObject::unpackVector3(dp, pos, "Pos"); + + LLVector3 vec; + LLViewerObject::unpackVector3(dp, vec, "Rot"); + rot.unpackFromVector3(vec); + + return parent_id; } U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, @@ -909,23 +1144,24 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, LLDataPacker *dp) { U32 retval = 0x0; - + // If region is removed from the list it is also deleted. if (!LLWorld::instance().isRegionListed(mRegionp)) { - llwarns << "Updating object in an invalid region" << llendl; + LL_WARNS() << "Updating object in an invalid region" << LL_ENDL; return retval; } // Coordinates of objects on simulators are region-local. - U64 region_handle; - mesgsys->getU64Fast(_PREHASH_RegionData, _PREHASH_RegionHandle, region_handle); + U64 region_handle = 0; + if(mesgsys != NULL) { + mesgsys->getU64Fast(_PREHASH_RegionData, _PREHASH_RegionHandle, region_handle); LLViewerRegion* regionp = LLWorld::getInstance()->getRegionFromHandle(region_handle); if(regionp != mRegionp && regionp && mRegionp)//region cross { - //this is the redundant position and region update, but it is necessary in case the viewer misses the following + //this is the redundant position and region update, but it is necessary in case the viewer misses the following //position and region update messages from sim. //this redundant update should not cause any problems. LLVector3 delta_pos = mRegionp->getOriginAgent() - regionp->getOriginAgent(); @@ -934,46 +1170,47 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, } else { + if(regionp != mRegionp) + { + if(mRegionp) + { + mRegionp->removeFromCreatedList(getLocalID()); + } + if(regionp) + { + regionp->addToCreatedList(getLocalID()); + } + } mRegionp = regionp ; } - } - + } + if (!mRegionp) { U32 x, y; from_region_handle(region_handle, &x, &y); - llerrs << "Object has invalid region " << x << ":" << y << "!" << llendl; + LL_ERRS() << "Object has invalid region " << x << ":" << y << "!" << LL_ENDL; return retval; } - U16 time_dilation16; - mesgsys->getU16Fast(_PREHASH_RegionData, _PREHASH_TimeDilation, time_dilation16); - F32 time_dilation = ((F32) time_dilation16) / 65535.f; - mTimeDilation = time_dilation; - mRegionp->setTimeDilation(time_dilation); + F32 time_dilation = 1.f; + if(mesgsys != NULL) + { + U16 time_dilation16; + mesgsys->getU16Fast(_PREHASH_RegionData, _PREHASH_TimeDilation, time_dilation16); + time_dilation = ((F32) time_dilation16) / 65535.f; + mRegionp->setTimeDilation(time_dilation); + } // this will be used to determine if we've really changed position // Use getPosition, not getPositionRegion, since this is what we're comparing directly against. LLVector3 test_pos_parent = getPosition(); - U8 data[60+16]; // This needs to match the largest size below. -#ifdef LL_BIG_ENDIAN - U16 valswizzle[4]; -#endif - U16 *val; - const F32 size = LLWorld::getInstance()->getRegionWidthInMeters(); - const F32 MAX_HEIGHT = LLWorld::getInstance()->getRegionMaxHeight(); - const F32 MIN_HEIGHT = LLWorld::getInstance()->getRegionMinHeight(); - S32 length; - S32 count; S32 this_update_precision = 32; // in bits // Temporaries, because we need to compare w/ previous to set dirty flags... - LLVector3 new_pos_parent; - LLVector3 new_vel; - LLVector3 new_acc; - LLVector3 new_angv; + LLVector3 new_pos_parent, new_vel, new_angv; LLVector3 old_angv = getAngularVelocity(); LLQuaternion new_rot; LLVector3 new_scale = getScale(); @@ -992,6 +1229,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, parent_id = cur_parentp->mLocalID; } + if (!dp) { switch(update_type) @@ -999,8 +1237,10 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, case OUT_FULL: { #ifdef DEBUG_UPDATE_TYPE - llinfos << "Full:" << getID() << llendl; + LL_INFOS() << "Full:" << getID() << LL_ENDL; #endif + processTerseData(mesgsys, user_data, block_num, this_update_precision, new_pos_parent, new_rot, new_angv, test_pos_parent); + //clear cost and linkset cost mCostStale = true; if (isSelected()) @@ -1018,13 +1258,12 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, mesgsys->getUUIDFast(_PREHASH_ObjectData, _PREHASH_Sound, audio_uuid, block_num ); // HACK: Owner id only valid if non-null sound id or particle system mesgsys->getUUIDFast(_PREHASH_ObjectData, _PREHASH_OwnerID, owner_id, block_num ); + if (owner_id.notNull()) mOwnerID = owner_id; // Singu Note: Try to get Owner whenever possible mesgsys->getF32Fast( _PREHASH_ObjectData, _PREHASH_Gain, gain, block_num ); mesgsys->getU8Fast( _PREHASH_ObjectData, _PREHASH_Flags, sound_flags, block_num ); mesgsys->getU8Fast( _PREHASH_ObjectData, _PREHASH_Material, material, block_num ); - mesgsys->getU8Fast( _PREHASH_ObjectData, _PREHASH_ClickAction, click_action, block_num); + mesgsys->getU8Fast( _PREHASH_ObjectData, _PREHASH_ClickAction, click_action, block_num); mesgsys->getVector3Fast(_PREHASH_ObjectData, _PREHASH_Scale, new_scale, block_num ); - length = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_ObjectData); - mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_ObjectData, data, length, block_num); mTotalCRC = crc; @@ -1042,157 +1281,6 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, } setClickAction(click_action); - count = 0; - LLVector4 collision_plane; - - switch(length) - { - case (60 + 16): - // pull out collision normal for avatar - htonmemcpy(collision_plane.mV, &data[count], MVT_LLVector4, sizeof(LLVector4)); - ((LLVOAvatar*)this)->setFootPlane(collision_plane); - count += sizeof(LLVector4); - // fall through - case 60: - this_update_precision = 32; - // this is a terse update - // pos - htonmemcpy(new_pos_parent.mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); - count += sizeof(LLVector3); - // vel - htonmemcpy((void*)getVelocity().mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); - count += sizeof(LLVector3); - // acc - htonmemcpy((void*)getAcceleration().mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); - count += sizeof(LLVector3); - // theta - { - LLVector3 vec; - htonmemcpy(vec.mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); - new_rot.unpackFromVector3(vec); - } - count += sizeof(LLVector3); - // omega - htonmemcpy((void*)new_angv.mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); - if (new_angv.isExactlyZero()) - { - // reset rotation time - resetRot(); - } - setAngularVelocity(new_angv); -#if LL_DARWIN - if (length == 76) - { - setAngularVelocity(LLVector3::zero); - } -#endif - break; - case(32 + 16): - // pull out collision normal for avatar - htonmemcpy(collision_plane.mV, &data[count], MVT_LLVector4, sizeof(LLVector4)); - ((LLVOAvatar*)this)->setFootPlane(collision_plane); - count += sizeof(LLVector4); - // fall through - case 32: - this_update_precision = 16; - test_pos_parent.quantize16(-0.5f*size, 1.5f*size, MIN_HEIGHT, MAX_HEIGHT); - - // This is a terse 16 update, so treat data as an array of U16's. -#ifdef LL_BIG_ENDIAN - htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); - val = valswizzle; -#else - val = (U16 *) &data[count]; -#endif - count += sizeof(U16)*3; - new_pos_parent.mV[VX] = U16_to_F32(val[VX], -0.5f*size, 1.5f*size); - new_pos_parent.mV[VY] = U16_to_F32(val[VY], -0.5f*size, 1.5f*size); - new_pos_parent.mV[VZ] = U16_to_F32(val[VZ], MIN_HEIGHT, MAX_HEIGHT); - -#ifdef LL_BIG_ENDIAN - htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); - val = valswizzle; -#else - val = (U16 *) &data[count]; -#endif - count += sizeof(U16)*3; - setVelocity(LLVector3(U16_to_F32(val[VX], -size, size), - U16_to_F32(val[VY], -size, size), - U16_to_F32(val[VZ], -size, size))); - -#ifdef LL_BIG_ENDIAN - htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); - val = valswizzle; -#else - val = (U16 *) &data[count]; -#endif - count += sizeof(U16)*3; - setAcceleration(LLVector3(U16_to_F32(val[VX], -size, size), - U16_to_F32(val[VY], -size, size), - U16_to_F32(val[VZ], -size, size))); - -#ifdef LL_BIG_ENDIAN - htonmemcpy(valswizzle, &data[count], MVT_U16Quat, 4); - val = valswizzle; -#else - val = (U16 *) &data[count]; -#endif - count += sizeof(U16)*4; - new_rot.mQ[VX] = U16_to_F32(val[VX], -1.f, 1.f); - new_rot.mQ[VY] = U16_to_F32(val[VY], -1.f, 1.f); - new_rot.mQ[VZ] = U16_to_F32(val[VZ], -1.f, 1.f); - new_rot.mQ[VW] = U16_to_F32(val[VW], -1.f, 1.f); - -#ifdef LL_BIG_ENDIAN - htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); - val = valswizzle; -#else - val = (U16 *) &data[count]; -#endif - new_angv.setVec(U16_to_F32(val[VX], -size, size), - U16_to_F32(val[VY], -size, size), - U16_to_F32(val[VZ], -size, size)); - if (new_angv.isExactlyZero()) - { - // reset rotation time - resetRot(); - } - setAngularVelocity(new_angv); - break; - - case 16: - this_update_precision = 8; - test_pos_parent.quantize8(-0.5f*size, 1.5f*size, MIN_HEIGHT, MAX_HEIGHT); - // this is a terse 8 update - new_pos_parent.mV[VX] = U8_to_F32(data[0], -0.5f*size, 1.5f*size); - new_pos_parent.mV[VY] = U8_to_F32(data[1], -0.5f*size, 1.5f*size); - new_pos_parent.mV[VZ] = U8_to_F32(data[2], MIN_HEIGHT, MAX_HEIGHT); - - setVelocity(U8_to_F32(data[3], -size, size), - U8_to_F32(data[4], -size, size), - U8_to_F32(data[5], -size, size) ); - - setAcceleration(U8_to_F32(data[6], -size, size), - U8_to_F32(data[7], -size, size), - U8_to_F32(data[8], -size, size) ); - - new_rot.mQ[VX] = U8_to_F32(data[9], -1.f, 1.f); - new_rot.mQ[VY] = U8_to_F32(data[10], -1.f, 1.f); - new_rot.mQ[VZ] = U8_to_F32(data[11], -1.f, 1.f); - new_rot.mQ[VW] = U8_to_F32(data[12], -1.f, 1.f); - - new_angv.setVec(U8_to_F32(data[13], -size, size), - U8_to_F32(data[14], -size, size), - U8_to_F32(data[15], -size, size) ); - if (new_angv.isExactlyZero()) - { - // reset rotation time - resetRot(); - } - setAngularVelocity(new_angv); - break; - } - //////////////////////////////////////////////////// // // Here we handle data specific to the full message. @@ -1205,8 +1293,8 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, mFlags |= flags; U8 state; - mesgsys->getU8Fast(_PREHASH_ObjectData, _PREHASH_State, state, block_num ); - mState = state; + mesgsys->getU8Fast(_PREHASH_ObjectData, _PREHASH_State, state, block_num); + mAttachmentState = state; // ...new objects that should come in selected need to be added to the selected list mCreateSelected = ((flags & FLAGS_CREATE_SELECTED) != 0); @@ -1248,17 +1336,12 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, // Setup object text if (!mText) { - mText = (LLHUDText *)LLHUDObject::addHUDObject(LLHUDObject::LL_HUD_TEXT); - mText->setFont(LLFontGL::getFontSansSerif()); - mText->setVertAlignment(LLHUDText::ALIGN_VERT_TOP); - mText->setMaxLines(-1); - mText->setSourceObject(this); - mText->setOnHUDAttachment(isHUDAttachment()); + initHudText(); } //Cache for reset on debug infodisplay toggle. mesgsys->getStringFast(_PREHASH_ObjectData, _PREHASH_Text, mHudTextString, block_num ); - + LLColor4U coloru; mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_TextColor, coloru.mV, 4, block_num); @@ -1276,7 +1359,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, mText->setObjectText(mHudTextString); } // [/RLVa:KB] - + setChanged(MOVED | SILHOUETTE); } else if (mText.notNull()) @@ -1287,18 +1370,17 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, std::string media_url; mesgsys->getStringFast(_PREHASH_ObjectData, _PREHASH_MediaURL, media_url, block_num); - retval |= checkMediaURL(media_url); - + retval |= checkMediaURL(media_url); + // // Unpack particle system data // unpackParticleSource(block_num, owner_id); // Mark all extra parameters not used - std::map::iterator iter; - for (iter = mExtraParameterList.begin(); iter != mExtraParameterList.end(); ++iter) + for (auto& entry : mExtraParameterList) { - iter->second->in_use = FALSE; + if (entry.in_use) *entry.in_use = false; } // Unpack extra parameters @@ -1318,19 +1400,20 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, S32 param_size; dp.unpackU16(param_type, "param_type"); dp.unpackBinaryData(param_block, param_size, "param_data"); - //llinfos << "Param type: " << param_type << ", Size: " << param_size << llendl; + //LL_INFOS() << "Param type: " << param_type << ", Size: " << param_size << LL_ENDL; LLDataPackerBinaryBuffer dp2(param_block, param_size); unpackParameterEntry(param_type, &dp2); } delete[] buffer; } - for (iter = mExtraParameterList.begin(); iter != mExtraParameterList.end(); ++iter) + for (size_t i = 0; i < mExtraParameterList.size(); ++i) { - if (!iter->second->in_use) + auto& entry = mExtraParameterList[i]; + if (entry.in_use && !*entry.in_use) { // Send an update message in case it was formerly in use - parameterChanged(iter->first, iter->second->data, FALSE, false); + parameterChanged((i + 1) << 4, entry.data, FALSE, false); } } break; @@ -1339,154 +1422,9 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, case OUT_TERSE_IMPROVED: { #ifdef DEBUG_UPDATE_TYPE - llinfos << "TI:" << getID() << llendl; -#endif - length = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_ObjectData); - mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_ObjectData, data, length, block_num); - count = 0; - LLVector4 collision_plane; - - switch(length) - { - case(60 + 16): - // pull out collision normal for avatar - htonmemcpy(collision_plane.mV, &data[count], MVT_LLVector4, sizeof(LLVector4)); - ((LLVOAvatar*)this)->setFootPlane(collision_plane); - count += sizeof(LLVector4); - // fall through - case 60: - // this is a terse 32 update - // pos - this_update_precision = 32; - htonmemcpy(new_pos_parent.mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); - count += sizeof(LLVector3); - // vel - htonmemcpy((void*)getVelocity().mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); - count += sizeof(LLVector3); - // acc - htonmemcpy((void*)getAcceleration().mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); - count += sizeof(LLVector3); - // theta - { - LLVector3 vec; - htonmemcpy(vec.mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); - new_rot.unpackFromVector3(vec); - } - count += sizeof(LLVector3); - // omega - htonmemcpy((void*)new_angv.mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); - if (new_angv.isExactlyZero()) - { - // reset rotation time - resetRot(); - } - setAngularVelocity(new_angv); -#if LL_DARWIN - if (length == 76) - { - setAngularVelocity(LLVector3::zero); - } -#endif - break; - case(32 + 16): - // pull out collision normal for avatar - htonmemcpy(collision_plane.mV, &data[count], MVT_LLVector4, sizeof(LLVector4)); - ((LLVOAvatar*)this)->setFootPlane(collision_plane); - count += sizeof(LLVector4); - // fall through - case 32: - // this is a terse 16 update - this_update_precision = 16; - test_pos_parent.quantize16(-0.5f*size, 1.5f*size, MIN_HEIGHT, MAX_HEIGHT); - -#ifdef LL_BIG_ENDIAN - htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); - val = valswizzle; -#else - val = (U16 *) &data[count]; -#endif - count += sizeof(U16)*3; - new_pos_parent.mV[VX] = U16_to_F32(val[VX], -0.5f*size, 1.5f*size); - new_pos_parent.mV[VY] = U16_to_F32(val[VY], -0.5f*size, 1.5f*size); - new_pos_parent.mV[VZ] = U16_to_F32(val[VZ], MIN_HEIGHT, MAX_HEIGHT); - -#ifdef LL_BIG_ENDIAN - htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); - val = valswizzle; -#else - val = (U16 *) &data[count]; -#endif - count += sizeof(U16)*3; - setVelocity(U16_to_F32(val[VX], -size, size), - U16_to_F32(val[VY], -size, size), - U16_to_F32(val[VZ], -size, size)); - -#ifdef LL_BIG_ENDIAN - htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); - val = valswizzle; -#else - val = (U16 *) &data[count]; -#endif - count += sizeof(U16)*3; - setAcceleration(U16_to_F32(val[VX], -size, size), - U16_to_F32(val[VY], -size, size), - U16_to_F32(val[VZ], -size, size)); - -#ifdef LL_BIG_ENDIAN - htonmemcpy(valswizzle, &data[count], MVT_U16Quat, 8); - val = valswizzle; -#else - val = (U16 *) &data[count]; -#endif - count += sizeof(U16)*4; - new_rot.mQ[VX] = U16_to_F32(val[VX], -1.f, 1.f); - new_rot.mQ[VY] = U16_to_F32(val[VY], -1.f, 1.f); - new_rot.mQ[VZ] = U16_to_F32(val[VZ], -1.f, 1.f); - new_rot.mQ[VW] = U16_to_F32(val[VW], -1.f, 1.f); - -#ifdef LL_BIG_ENDIAN - htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); - val = valswizzle; -#else - val = (U16 *) &data[count]; + LL_INFOS() << "TI:" << getID() << LL_ENDL; #endif - new_angv.set(U16_to_F32(val[VX], -size, size), - U16_to_F32(val[VY], -size, size), - U16_to_F32(val[VZ], -size, size)); - setAngularVelocity(new_angv); - break; - - case 16: - // this is a terse 8 update - this_update_precision = 8; - test_pos_parent.quantize8(-0.5f*size, 1.5f*size, MIN_HEIGHT, MAX_HEIGHT); - new_pos_parent.mV[VX] = U8_to_F32(data[0], -0.5f*size, 1.5f*size); - new_pos_parent.mV[VY] = U8_to_F32(data[1], -0.5f*size, 1.5f*size); - new_pos_parent.mV[VZ] = U8_to_F32(data[2], MIN_HEIGHT, MAX_HEIGHT); - - setVelocity(U8_to_F32(data[3], -size, size), - U8_to_F32(data[4], -size, size), - U8_to_F32(data[5], -size, size) ); - - setAcceleration(U8_to_F32(data[6], -size, size), - U8_to_F32(data[7], -size, size), - U8_to_F32(data[8], -size, size) ); - - new_rot.mQ[VX] = U8_to_F32(data[9], -1.f, 1.f); - new_rot.mQ[VY] = U8_to_F32(data[10], -1.f, 1.f); - new_rot.mQ[VZ] = U8_to_F32(data[11], -1.f, 1.f); - new_rot.mQ[VW] = U8_to_F32(data[12], -1.f, 1.f); - - new_angv.set(U8_to_F32(data[13], -size, size), - U8_to_F32(data[14], -size, size), - U8_to_F32(data[15], -size, size) ); - setAngularVelocity(new_angv); - break; - } - - U8 state; - mesgsys->getU8Fast(_PREHASH_ObjectData, _PREHASH_State, state, block_num ); - mState = state; + processTerseData(mesgsys, user_data, block_num, this_update_precision, new_pos_parent, new_rot, new_angv, test_pos_parent); break; } @@ -1509,14 +1447,14 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, U8 state; dp->unpackU8(state, "State"); - mState = state; + mAttachmentState = state; switch(update_type) { case OUT_TERSE_IMPROVED: { #ifdef DEBUG_UPDATE_TYPE - llinfos << "CompTI:" << getID() << llendl; + LL_INFOS() << "CompTI:" << getID() << LL_ENDL; #endif U8 value; dp->unpackU8(value, "agent"); @@ -1562,7 +1500,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, case OUT_FULL_CACHED: { #ifdef DEBUG_UPDATE_TYPE - llinfos << "CompFull:" << getID() << llendl; + LL_INFOS() << "CompFull:" << getID() << LL_ENDL; #endif mCostStale = true; @@ -1570,7 +1508,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, { gFloaterTools->dirty(); } - + dp->unpackU32(crc, "CRC"); mTotalCRC = crc; dp->unpackU8(material, "Material"); @@ -1597,6 +1535,8 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, dp->setPassFlags(value); dp->unpackUUID(owner_id, "Owner"); + mOwnerID = owner_id; + if (value & 0x80) { dp->unpackVector3(new_angv, "Omega"); @@ -1673,30 +1613,29 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, mText = NULL; } - std::string media_url; + std::string media_url; if (value & 0x200) { dp->unpackString(media_url, "MediaURL"); } - retval |= checkMediaURL(media_url); + retval |= checkMediaURL(media_url); // - // Unpack particle system data + // Unpack particle system data (legacy) // if (value & 0x8) { - unpackParticleSource(*dp, owner_id); + unpackParticleSource(*dp, owner_id, true); } - else + else if (!(value & 0x400)) { deleteParticleSource(); } - + // Mark all extra parameters not used - std::map::iterator iter; - for (iter = mExtraParameterList.begin(); iter != mExtraParameterList.end(); ++iter) + for (auto& entry : mExtraParameterList) { - iter->second->in_use = FALSE; + if (entry.in_use) *entry.in_use = false; } // Unpack extra params @@ -1709,17 +1648,18 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, S32 param_size; dp->unpackU16(param_type, "param_type"); dp->unpackBinaryData(param_block, param_size, "param_data"); - //llinfos << "Param type: " << param_type << ", Size: " << param_size << llendl; + //LL_INFOS() << "Param type: " << param_type << ", Size: " << param_size << LL_ENDL; LLDataPackerBinaryBuffer dp2(param_block, param_size); unpackParameterEntry(param_type, &dp2); } - for (iter = mExtraParameterList.begin(); iter != mExtraParameterList.end(); ++iter) + for (size_t i = 0; i < mExtraParameterList.size(); ++i) { - if (!iter->second->in_use) + auto& entry = mExtraParameterList[i]; + if (entry.in_use && !*entry.in_use) { // Send an update message in case it was formerly in use - parameterChanged(iter->first, iter->second->data, FALSE, false); + parameterChanged((i + 1) << 4, entry.data, FALSE, false); } } @@ -1747,13 +1687,12 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, // Preload these five flags for every object. // Finer shades require the object to be selected, and the selection manager // stores the extended permission info. - U32 flags; - mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_UpdateFlags, flags, block_num); - // keep local flags and overwrite remote-controlled flags - mFlags = (mFlags & FLAGS_LOCAL) | flags; - - // ...new objects that should come in selected need to be added to the selected list - mCreateSelected = ((flags & FLAGS_CREATE_SELECTED) != 0); + if(mesgsys != NULL) + { + U32 flags; + mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_UpdateFlags, flags, block_num); + loadFlags(flags); + } } break; @@ -1761,7 +1700,6 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, break; } } - // // Fix object parenting. // @@ -1781,10 +1719,21 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, { // No parent now, new parent in message -> attach to that parent if possible LLUUID parent_uuid; - LLViewerObjectList::getUUIDFromLocal(parent_uuid, + + if(mesgsys != NULL) + { + LLViewerObjectList::getUUIDFromLocal(parent_uuid, parent_id, mesgsys->getSenderIP(), mesgsys->getSenderPort()); + } + else + { + LLViewerObjectList::getUUIDFromLocal(parent_uuid, + parent_id, + mRegionp->getHost().getAddress(), + mRegionp->getHost().getPort()); + } LLViewerObject *sent_parentp = gObjectList.findObject(parent_uuid); @@ -1795,11 +1744,11 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, { static std::map state_map; std::map::iterator it = state_map.find(getID()); - + if(it != state_map.end() && (!it->second && sent_parentp)) { it->second = sent_parentp != NULL; - LL_INFOS("Attachment") << getID() << " ("<getParent() == this) { // Try to recover if we attempt to attach a parent to its child - llwarns << "Attempt to attach a parent to it's child: " << this->getID() << " to " << sent_parentp->getID() << llendl; + LL_WARNS() << "Attempt to attach a parent to it's child: " << this->getID() << " to " << sent_parentp->getID() << LL_ENDL; this->removeChild(sent_parentp); sent_parentp->setDrawableParent(NULL); } - + if (sent_parentp && (sent_parentp != this) && !sent_parentp->isDead()) { + if (((LLViewerObject*)sent_parentp)->isAvatar()) + { + //LL_DEBUGS("Avatar") << "ATT got object update for attachment " << LL_ENDL; + } + // // We have a viewer object for the parent, and it's not dead. // Do the actual reparenting here. @@ -1829,7 +1783,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, { if (mDrawable->isDead() || !mDrawable->getVObj()) { - llwarns << "Drawable is dead or no VObj!" << llendl; + LL_WARNS() << "Drawable is dead or no VObj!" << LL_ENDL; sent_parentp->addChild(this); } else @@ -1839,9 +1793,9 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, // Bad, we got a cycle somehow. // Kill both the parent and the child, and // set cache misses for both of them. - llwarns << "Attempting to recover from parenting cycle!" << llendl; - llwarns << "Killing " << sent_parentp->getID() << " and " << getID() << llendl; - llwarns << "Adding to cache miss list" << llendl; + LL_WARNS() << "Attempting to recover from parenting cycle!" << LL_ENDL; + LL_WARNS() << "Killing " << sent_parentp->getID() << " and " << getID() << LL_ENDL; + LL_WARNS() << "Adding to cache miss list" << LL_ENDL; setParent(NULL); sent_parentp->setParent(NULL); getRegion()->addCacheMissFull(getLocalID()); @@ -1854,7 +1808,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, if ( (rlv_handler_t::isEnabled()) && (sent_parentp->isAvatar()) && (sent_parentp->getID() == gAgent.getID()) ) { // Rezzed object that's being worn as an attachment (we're assuming this will be due to llAttachToAvatar()) - S32 idxAttachPt = ATTACHMENT_ID_FROM_STATE(getState()); + S32 idxAttachPt = ATTACHMENT_ID_FROM_STATE(getAttachmentState()); if (gRlvAttachmentLocks.isLockedAttachmentPoint(idxAttachPt, RLV_LOCK_ADD)) { // If this will end up on an "add locked" attachment point then treat the attach as a user action @@ -1881,7 +1835,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, { sent_parentp->addChild(this); } - + // Show particles, icon and HUD hideExtraDisplayItems( FALSE ); @@ -1893,11 +1847,20 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, // No corresponding viewer object for the parent, put the various // pieces on the orphan list. // - + //parent_id - U32 ip = mesgsys->getSenderIP(); - U32 port = mesgsys->getSenderPort(); - + U32 ip, port; + + if(mesgsys != NULL) + { + ip = mesgsys->getSenderIP(); + port = mesgsys->getSenderPort(); + } + else + { + ip = mRegionp->getHost().getAddress(); + port = mRegionp->getHost().getPort(); + } gObjectList.orphanize(this, parent_id, ip, port); // Hide particles, icon and HUD @@ -1918,7 +1881,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, //LLViewerObjectList::getUUIDFromLocal(parent_uuid, parent_id, mesgsys->getSenderIP(), mesgsys->getSenderPort() ); //if (parent_uuid != cur_parentp->getID() ) //{ - // llerrs << "Local ID match but UUID mismatch of viewer object" << llendl; + // LL_ERRS() << "Local ID match but UUID mismatch of viewer object" << LL_ENDL; //} } else @@ -1935,12 +1898,23 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, else { LLUUID parent_uuid; - LLViewerObjectList::getUUIDFromLocal(parent_uuid, + + if(mesgsys != NULL) + { + LLViewerObjectList::getUUIDFromLocal(parent_uuid, parent_id, gMessageSystem->getSenderIP(), gMessageSystem->getSenderPort()); + } + else + { + LLViewerObjectList::getUUIDFromLocal(parent_uuid, + parent_id, + mRegionp->getHost().getAddress(), + mRegionp->getHost().getPort()); + } sent_parentp = gObjectList.findObject(parent_uuid); - + if (isAvatar()) { // This logic is meant to handle the case where a sitting avatar has reached a new sim @@ -1959,8 +1933,18 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, // // Switching parents, but we don't know the new parent. // - U32 ip = mesgsys->getSenderIP(); - U32 port = mesgsys->getSenderPort(); + U32 ip, port; + + if(mesgsys != NULL) + { + ip = mesgsys->getSenderIP(); + port = mesgsys->getSenderPort(); + } + else + { + ip = mRegionp->getHost().getAddress(); + port = mRegionp->getHost().getPort(); + } // We're an orphan, flag things appropriately. gObjectList.orphanize(this, parent_id, ip, port); @@ -1979,9 +1963,9 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, // Bad, we got a cycle somehow. // Kill both the parent and the child, and // set cache misses for both of them. - llwarns << "Attempting to recover from parenting cycle!" << llendl; - llwarns << "Killing " << sent_parentp->getID() << " and " << getID() << llendl; - llwarns << "Adding to cache miss list" << llendl; + LL_WARNS() << "Attempting to recover from parenting cycle!" << LL_ENDL; + LL_WARNS() << "Killing " << sent_parentp->getID() << " and " << getID() << LL_ENDL; + LL_WARNS() << "Adding to cache miss list" << LL_ENDL; setParent(NULL); sent_parentp->setParent(NULL); getRegion()->addCacheMissFull(getLocalID()); @@ -2013,7 +1997,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, // This is probably an object flying across a region boundary, the // object probably ISN'T being reparented, but just got an object // update out of order (child update before parent). - //llinfos << "Don't reparent object handoffs!" << llendl; + //LL_INFOS() << "Don't reparent object handoffs!" << LL_ENDL; remove_parent = false; } } @@ -2044,18 +2028,18 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, new_rot.normQuat(); - if (sPingInterpolate) - { + if (sPingInterpolate && mesgsys != NULL) + { LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(mesgsys->getSender()); if (cdp) { - F32 ping_delay = 0.5f * mTimeDilation * ( ((F32)cdp->getPingDelay()) * 0.001f + gFrameDTClamped); - LLVector3 diff = getVelocity() * ping_delay; + F32 ping_delay = 0.5f * time_dilation * ( ((F32)cdp->getPingDelay().valueInUnits()) + gFrameDTClamped); + LLVector3 diff = getVelocity() * ping_delay; new_pos_parent += diff; } else { - llwarns << "findCircuit() returned NULL; skipping interpolation" << llendl; + LL_WARNS() << "findCircuit() returned NULL; skipping interpolation" << LL_ENDL; } } @@ -2065,18 +2049,20 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, // // - // If we're going to skip this message, why are we + // If we're going to skip this message, why are we // doing all the parenting, etc above? - U32 packet_id = mesgsys->getCurrentRecvPacketID(); - if (packet_id < mLatestRecvPacketID && - mLatestRecvPacketID - packet_id < 65536) + if(mesgsys != NULL) { - //skip application of this message, it's old - return retval; + U32 packet_id = mesgsys->getCurrentRecvPacketID(); + if (packet_id < mLatestRecvPacketID && + mLatestRecvPacketID - packet_id < 65536) + { + //skip application of this message, it's old + return retval; + } + mLatestRecvPacketID = packet_id; } - mLatestRecvPacketID = packet_id; - // Set the change flags for scale if (new_scale != getScale()) { @@ -2098,16 +2084,16 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, ||(this_update_precision > mBestUpdatePrecision)))) { mBestUpdatePrecision = this_update_precision; - + LLVector3 diff = new_pos_parent - test_pos_parent ; F32 mag_sqr = diff.magVecSquared() ; - if(llfinite(mag_sqr)) + if(std::isfinite(mag_sqr)) { setPositionParent(new_pos_parent); } else { - llwarns << "Can not move the object/avatar to an infinite location!" << llendl ; + LL_WARNS() << "Can not move the object/avatar to an infinite location!" << LL_ENDL ; retval |= INVALID_UPDATE ; } @@ -2172,7 +2158,6 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, } } - if ( gShowObjectUpdates ) { LLColor4 color; @@ -2193,7 +2178,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, llassert(accel_mag_sq >= 0.f); llassert(getAngularVelocity().magVecSquared() >= 0.f); - if ((MAG_CUTOFF >= vel_mag_sq) && + if ((MAG_CUTOFF >= vel_mag_sq) && (MAG_CUTOFF >= accel_mag_sq) && (MAG_CUTOFF >= getAngularVelocity().magVecSquared())) { @@ -2217,10 +2202,9 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, // Additionally, if any child is selected, need to update the dialogs and selection // center. BOOL needs_refresh = mUserSelected; - for (child_list_t::iterator iter = mChildList.begin(); - iter != mChildList.end(); iter++) + for (auto& iter : mChildList) { - LLViewerObject* child = *iter; + LLViewerObject* child = iter; needs_refresh = needs_refresh || child->mUserSelected; } @@ -2233,7 +2217,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, // LLSelectMgr::getInstance()->updateSelectionCenter(); dialog_refresh_all(); - } + } // Mark update time as approx. now, with the ping delay. @@ -2248,7 +2232,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, // Don't clear invisibility flag on update if still orphaned! if (mDrawable->isState(LLDrawable::FORCE_INVISIBLE) && !mOrphaned) { -// lldebugs << "Clearing force invisible: " << mID << ":" << getPCodeString() << ":" << getPositionAgent() << llendl; +// LL_DEBUGS() << "Clearing force invisible: " << mID << ":" << getPCodeString() << ":" << getPositionAgent() << LL_ENDL; mDrawable->clearState(LLDrawable::FORCE_INVISIBLE); gPipeline.markRebuild( mDrawable, LLDrawable::REBUILD_ALL, TRUE ); } @@ -2265,91 +2249,280 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, return retval; } +void LLViewerObject::processTerseData(LLMessageSystem *mesgsys, void **user_data, U32 block_num, S32& this_update_precision, LLVector3& new_pos_parent, LLQuaternion& new_rot, LLVector3& new_angv, LLVector3& test_pos_parent) +{ + // Aurora Sim + //const F32 size = LLWorld::getInstance()->getRegionWidthInMeters(); + const F32 size = mRegionp->getWidth(); + // Aurora Sim + const F32 MAX_HEIGHT = LLWorld::getInstance()->getRegionMaxHeight(); + const F32 MIN_HEIGHT = LLWorld::getInstance()->getRegionMinHeight(); + + U8 data[MAX_OBJECT_PARAMS_SIZE]; // This needs to match the largest size below. +#ifdef LL_BIG_ENDIAN + U16 valswizzle[4]; +#endif + U16 *val; + S32 count = 0; + LLVector4 collision_plane; + + S32 length = mesgsys->getSizeFast(_PREHASH_ObjectData, block_num, _PREHASH_ObjectData); + mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_ObjectData, data, length, block_num, MAX_OBJECT_PARAMS_SIZE); + + switch (length) + { + case(60 + 16) : + // pull out collision normal for avatar + htonmemcpy(collision_plane.mV, &data[count], MVT_LLVector4, sizeof(LLVector4)); + ((LLVOAvatar*)this)->setFootPlane(collision_plane); + count += sizeof(LLVector4); + // fall through + case 60: + // this is a terse 32 update + // pos + this_update_precision = 32; + htonmemcpy(new_pos_parent.mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); + count += sizeof(LLVector3); + // vel + htonmemcpy((void*)getVelocity().mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); + count += sizeof(LLVector3); + // acc + htonmemcpy((void*)getAcceleration().mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); + count += sizeof(LLVector3); + // theta + { + LLVector3 vec; + htonmemcpy(vec.mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); + new_rot.unpackFromVector3(vec); + } + count += sizeof(LLVector3); + // omega + htonmemcpy((void*)new_angv.mV, &data[count], MVT_LLVector3, sizeof(LLVector3)); + if (new_angv.isExactlyZero()) + { + // reset rotation time + resetRot(); + } + setAngularVelocity(new_angv); +#if LL_DARWIN + if (length == 76) + { + setAngularVelocity(LLVector3::zero); + } +#endif + break; + case(32 + 16) : + // pull out collision normal for avatar + htonmemcpy(collision_plane.mV, &data[count], MVT_LLVector4, sizeof(LLVector4)); + ((LLVOAvatar*)this)->setFootPlane(collision_plane); + count += sizeof(LLVector4); + // fall through + case 32: + // this is a terse 16 update + this_update_precision = 16; + test_pos_parent.quantize16(-0.5f*size, 1.5f*size, MIN_HEIGHT, MAX_HEIGHT); + +#ifdef LL_BIG_ENDIAN + htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); + val = valswizzle; +#else + val = (U16 *)&data[count]; +#endif + count += sizeof(U16) * 3; + new_pos_parent.mV[VX] = U16_to_F32(val[VX], -0.5f*size, 1.5f*size); + new_pos_parent.mV[VY] = U16_to_F32(val[VY], -0.5f*size, 1.5f*size); + new_pos_parent.mV[VZ] = U16_to_F32(val[VZ], MIN_HEIGHT, MAX_HEIGHT); + +#ifdef LL_BIG_ENDIAN + htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); + val = valswizzle; +#else + val = (U16 *)&data[count]; +#endif + count += sizeof(U16) * 3; + setVelocity(U16_to_F32(val[VX], -size, size), + U16_to_F32(val[VY], -size, size), + U16_to_F32(val[VZ], -size, size)); + +#ifdef LL_BIG_ENDIAN + htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); + val = valswizzle; +#else + val = (U16 *)&data[count]; +#endif + count += sizeof(U16) * 3; + setAcceleration(U16_to_F32(val[VX], -size, size), + U16_to_F32(val[VY], -size, size), + U16_to_F32(val[VZ], -size, size)); + +#ifdef LL_BIG_ENDIAN + htonmemcpy(valswizzle, &data[count], MVT_U16Quat, 8); + val = valswizzle; +#else + val = (U16 *)&data[count]; +#endif + count += sizeof(U16) * 4; + new_rot.mQ[VX] = U16_to_F32(val[VX], -1.f, 1.f); + new_rot.mQ[VY] = U16_to_F32(val[VY], -1.f, 1.f); + new_rot.mQ[VZ] = U16_to_F32(val[VZ], -1.f, 1.f); + new_rot.mQ[VW] = U16_to_F32(val[VW], -1.f, 1.f); + +#ifdef LL_BIG_ENDIAN + htonmemcpy(valswizzle, &data[count], MVT_U16Vec3, 6); + val = valswizzle; +#else + val = (U16 *)&data[count]; +#endif + new_angv.set(U16_to_F32(val[VX], -size, size), + U16_to_F32(val[VY], -size, size), + U16_to_F32(val[VZ], -size, size)); + if (new_angv.isExactlyZero()) + { + // reset rotation time + resetRot(); + } + setAngularVelocity(new_angv); + break; + + case 16: + // this is a terse 8 update + this_update_precision = 8; + test_pos_parent.quantize8(-0.5f*size, 1.5f*size, MIN_HEIGHT, MAX_HEIGHT); + new_pos_parent.mV[VX] = U8_to_F32(data[0], -0.5f*size, 1.5f*size); + new_pos_parent.mV[VY] = U8_to_F32(data[1], -0.5f*size, 1.5f*size); + new_pos_parent.mV[VZ] = U8_to_F32(data[2], MIN_HEIGHT, MAX_HEIGHT); + + setVelocity(U8_to_F32(data[3], -size, size), + U8_to_F32(data[4], -size, size), + U8_to_F32(data[5], -size, size)); + + setAcceleration(U8_to_F32(data[6], -size, size), + U8_to_F32(data[7], -size, size), + U8_to_F32(data[8], -size, size)); + + new_rot.mQ[VX] = U8_to_F32(data[9], -1.f, 1.f); + new_rot.mQ[VY] = U8_to_F32(data[10], -1.f, 1.f); + new_rot.mQ[VZ] = U8_to_F32(data[11], -1.f, 1.f); + new_rot.mQ[VW] = U8_to_F32(data[12], -1.f, 1.f); + + new_angv.set(U8_to_F32(data[13], -size, size), + U8_to_F32(data[14], -size, size), + U8_to_F32(data[15], -size, size)); + if (new_angv.isExactlyZero()) + { + // reset rotation time + resetRot(); + } + setAngularVelocity(new_angv); + break; + default: + break; + } + + U8 state; + mesgsys->getU8Fast(_PREHASH_ObjectData, _PREHASH_State, state, block_num); + mAttachmentState = state; +} + BOOL LLViewerObject::isActive() const { return TRUE; } +//load flags from cache or from message +void LLViewerObject::loadFlags(U32 flags) +{ + if(flags == (U32)(-1)) + { + return; //invalid + } + // keep local flags and overwrite remote-controlled flags + mFlags = (mFlags & FLAGS_LOCAL) | flags; + + // ...new objects that should come in selected need to be added to the selected list + mCreateSelected = ((flags & FLAGS_CREATE_SELECTED) != 0); + return; +} void LLViewerObject::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) { - //static LLFastTimer::DeclareTimer ftm("Viewer Object"); - //LLFastTimer t(ftm); + //static LLTrace::BlockTimerStatHandle ftm("Viewer Object"); + //LL_RECORD_BLOCK_TIME(ftm); if (!mDead) { - // CRO - don't velocity interp linked objects! - // Leviathan - but DO velocity interp joints - if (!mStatic && sVelocityInterpolate && !isSelected()) - { - // calculate dt from last update - F32 dt_raw = (F32)(time - mLastInterpUpdateSecs); - F32 dt = mTimeDilation * dt_raw; + if (!mStatic && sVelocityInterpolate && !isSelected()) + { + // calculate dt from last update + F32 time_dilation = mRegionp ? mRegionp->getTimeDilation() : 1.0f; + F32 dt_raw = ((F64Seconds)time - mLastInterpUpdateSecs).value(); + F32 dt = time_dilation * dt_raw; applyAngularVelocity(dt); if (isAttachment()) - { - mLastInterpUpdateSecs = time; + { + mLastInterpUpdateSecs = (F64Seconds)time; return; + } + else + { // Move object based on it's velocity and rotation + interpolateLinearMotion(time, dt); + } } - else - { // Move object based on it's velocity and rotation - interpolateLinearMotion(time, dt); - } - } - updateDrawable(FALSE); -} + updateDrawable(FALSE); + } } -// Move an object due to idle-time viewer side updates by iterpolating motion -void LLViewerObject::interpolateLinearMotion(const F64 & time, const F32 & dt) +// Move an object due to idle-time viewer side updates by interpolating motion +void LLViewerObject::interpolateLinearMotion(const F64SecondsImplicit& time, const F32SecondsImplicit& dt_seconds) { // linear motion // PHYSICS_TIMESTEP is used below to correct for the fact that the velocity in object // updates represents the average velocity of the last timestep, rather than the final velocity. // the time dilation above should guarantee that dt is never less than PHYSICS_TIMESTEP, theoretically - // + // // *TODO: should also wrap linear accel/velocity in check // to see if object is selected, instead of explicitly - // zeroing it out + // zeroing it out - F64 time_since_last_update = time - mLastMessageUpdateSecs; - if (time_since_last_update <= 0.0 || dt <= 0.f) + F32 dt = dt_seconds; + F64Seconds time_since_last_update = time - mLastMessageUpdateSecs; + if (time_since_last_update <= (F64Seconds)0.0 || dt <= 0.f) { return; } LLVector3 accel = getAcceleration(); LLVector3 vel = getVelocity(); - - if (sMaxUpdateInterpolationTime <= 0.0) + + if (sMaxUpdateInterpolationTime <= (F64Seconds)0.0) { // Old code path ... unbounded, simple interpolation if (!(accel.isExactlyZero() && vel.isExactlyZero())) { - LLVector3 pos = (vel + (0.5f * (dt-PHYSICS_TIMESTEP)) * accel) * dt; - - // region local + LLVector3 pos = (vel + (0.5f * (dt-PHYSICS_TIMESTEP)) * accel) * dt; + + // region local setPositionRegion(pos + getPositionRegion()); - setVelocity(vel + accel*dt); - + setVelocity(vel + accel*dt); + // for objects that are spinning but not translating, make sure to flag them as having moved setChanged(MOVED | SILHOUETTE); } } else if (!accel.isExactlyZero() || !vel.isExactlyZero()) // object is moving { // Object is moving, and hasn't been too long since we got an update from the server - + // Calculate predicted position and velocity - LLVector3 new_pos = (vel + (0.5f * (dt-PHYSICS_TIMESTEP)) * accel) * dt; + LLVector3 new_pos = (vel + (0.5f * (dt-PHYSICS_TIMESTEP)) * accel) * dt; LLVector3 new_v = accel * dt; if (time_since_last_update > sPhaseOutUpdateInterpolationTime && - sPhaseOutUpdateInterpolationTime > 0.0) - { // Haven't seen a viewer update in a while, check to see if the ciruit is still active + sPhaseOutUpdateInterpolationTime > (F64Seconds)0.0) + { // Haven't seen a viewer update in a while, check to see if the circuit is still active if (mRegionp) { // The simulator will NOT send updates if the object continues normally on the path // predicted by the velocity and the acceleration (often gravity) sent to the viewer @@ -2358,19 +2531,19 @@ void LLViewerObject::interpolateLinearMotion(const F64 & time, const F32 & dt) if (cdp) { // Find out how many seconds since last packet arrived on the circuit - F64 time_since_last_packet = LLMessageSystem::getMessageTimeSeconds() - cdp->getLastPacketInTime(); + F64Seconds time_since_last_packet = LLMessageSystem::getMessageTimeSeconds() - cdp->getLastPacketInTime(); if (!cdp->isAlive() || // Circuit is dead or blocked cdp->isBlocked() || // or doesn't seem to be getting any packets (time_since_last_packet > sPhaseOutUpdateInterpolationTime)) { // Start to reduce motion interpolation since we haven't seen a server update in a while - F64 time_since_last_interpolation = time - mLastInterpUpdateSecs; + F64Seconds time_since_last_interpolation = time - mLastInterpUpdateSecs; F64 phase_out = 1.0; if (time_since_last_update > sMaxUpdateInterpolationTime) { // Past the time limit, so stop the object phase_out = 0.0; - //llinfos << "Motion phase out to zero" << llendl; + //LL_INFOS() << "Motion phase out to zero" << LL_ENDL; // Kill angular motion as well. Note - not adding this due to paranoia // about stopping rotation for llTargetOmega objects and not having it restart @@ -2378,15 +2551,15 @@ void LLViewerObject::interpolateLinearMotion(const F64 & time, const F32 & dt) } else if (mLastInterpUpdateSecs - mLastMessageUpdateSecs > sPhaseOutUpdateInterpolationTime) { // Last update was already phased out a bit - phase_out = (sMaxUpdateInterpolationTime - time_since_last_update) / + phase_out = (sMaxUpdateInterpolationTime - time_since_last_update) / (sMaxUpdateInterpolationTime - time_since_last_interpolation); - //llinfos << "Continuing motion phase out of " << (F32) phase_out << llendl; + //LL_INFOS() << "Continuing motion phase out of " << (F32) phase_out << LL_ENDL; } else { // Phase out from full value - phase_out = (sMaxUpdateInterpolationTime - time_since_last_update) / + phase_out = (sMaxUpdateInterpolationTime - time_since_last_update) / (sMaxUpdateInterpolationTime - sPhaseOutUpdateInterpolationTime); - //llinfos << "Starting motion phase out of " << (F32) phase_out << llendl; + //LL_INFOS() << "Starting motion phase out of " << (F32) phase_out << LL_ENDL; } phase_out = llclamp(phase_out, 0.0, 1.0); @@ -2410,7 +2583,7 @@ void LLViewerObject::interpolateLinearMotion(const F64 & time, const F32 & dt) min_height += (0.5f * getScale().mV[VZ]); } else - { // This will put the object underground, but we can't tell if it will stop + { // This will put the object underground, but we can't tell if it will stop // at ground level or not min_height = LLWorld::getInstance()->getMinAllowedZ(this, new_pos_global); } @@ -2430,28 +2603,28 @@ void LLViewerObject::interpolateLinearMotion(const F64 & time, const F32 & dt) LLVector3d clip_pos_global = LLWorld::getInstance()->clipToVisibleRegions(old_pos_global, new_pos_global); if (clip_pos_global != new_pos_global) { // Was clipped, so this means we hit a edge where there is no region to enter - - //llinfos << "Hit empty region edge, clipped predicted position to " << mRegionp->getPosRegionFromGlobal(clip_pos_global) - // << " from " << new_pos << llendl; + + //LL_INFOS() << "Hit empty region edge, clipped predicted position to " << mRegionp->getPosRegionFromGlobal(clip_pos_global) + // << " from " << new_pos << LL_ENDL; new_pos = mRegionp->getPosRegionFromGlobal(clip_pos_global); - + // Stop motion and get server update for bouncing on the edge new_v.clear(); setAcceleration(LLVector3::zero); } else { // Let predicted movement cross into another region - //llinfos << "Predicting region crossing to " << new_pos << llendl; + //LL_INFOS() << "Predicting region crossing to " << new_pos << LL_ENDL; } } // Set new position and velocity setPositionRegion(new_pos); - setVelocity(new_v); - + setVelocity(new_v); + // for objects that are spinning but not translating, make sure to flag them as having moved setChanged(MOVED | SILHOUETTE); - } + } // Update the last time we did anything mLastInterpUpdateSecs = time; @@ -2589,7 +2762,8 @@ void LLViewerObject::saveScript( * XXXPAM Investigate not making this copy. Seems unecessary, but I'm unsure about the * interaction with doUpdateInventory() called below. */ - lldebugs << "LLViewerObject::saveScript() " << item->getUUID() << " " << item->getAssetUUID() << llendl; + LL_DEBUGS() << "LLViewerObject::saveScript() " << item->getUUID() << " " << item->getAssetUUID() << LL_ENDL; + LLPointer task_item = new LLViewerInventoryItem(item->getUUID(), mID, item->getPermissions(), item->getAssetUUID(), item->getType(), @@ -2620,7 +2794,7 @@ void LLViewerObject::saveScript( void LLViewerObject::moveInventory(const LLUUID& folder_id, const LLUUID& item_id) { - lldebugs << "LLViewerObject::moveInventory " << item_id << llendl; + LL_DEBUGS() << "LLViewerObject::moveInventory " << item_id << LL_ENDL; LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_MoveTaskInventory); msg->nextBlockFast(_PREHASH_AgentData); @@ -2654,8 +2828,8 @@ void LLViewerObject::dirtyInventory() mInventory->clear(); // will deref and delete entries delete mInventory; mInventory = NULL; - mInventoryDirty = TRUE; } + mInventoryDirty = TRUE; } void LLViewerObject::registerInventoryListener(LLVOInventoryListener* listener, void* user_data) @@ -2684,36 +2858,52 @@ void LLViewerObject::removeInventoryListener(LLVOInventoryListener* listener) } } +BOOL LLViewerObject::isInventoryPending() +{ + return mInvRequestState != INVENTORY_REQUEST_STOPPED; +} + void LLViewerObject::clearInventoryListeners() { for_each(mInventoryCallbacks.begin(), mInventoryCallbacks.end(), DeletePointer()); mInventoryCallbacks.clear(); } +bool LLViewerObject::hasInventoryListeners() +{ + return !mInventoryCallbacks.empty(); +} + void LLViewerObject::requestInventory() { - mInventoryDirty = FALSE; + if(mInventoryDirty && mInventory && !mInventoryCallbacks.empty()) + { + mInventory->clear(); // will deref and delete entries + delete mInventory; + mInventory = NULL; + } + if(mInventory) { - //mInventory->clear() // will deref and delete it - //delete mInventory; - //mInventory = NULL; + // inventory is either up to date or doesn't has a listener + // if it is dirty, leave it this way in case we gain a listener doInventoryCallback(); } - // throw away duplicate requests else { + // since we are going to request it now + mInventoryDirty = FALSE; + + // Note: throws away duplicate requests fetchInventoryFromServer(); } } void LLViewerObject::fetchInventoryFromServer() { - if (!mInventoryPending) + if (!isInventoryPending()) { delete mInventory; - mInventory = NULL; - mInventoryDirty = FALSE; LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_RequestTaskInventory); msg->nextBlockFast(_PREHASH_AgentData); @@ -2724,25 +2914,259 @@ void LLViewerObject::fetchInventoryFromServer() msg->sendReliable(mRegionp->getHost()); // this will get reset by dirtyInventory or doInventoryCallback - mInventoryPending = TRUE; + mInvRequestState = INVENTORY_REQUEST_PENDING; + } +} + +LLControlAvatar *LLViewerObject::getControlAvatar() +{ + return getRootEdit()->mControlAvatar.get(); +} + +LLControlAvatar *LLViewerObject::getControlAvatar() const +{ + return getRootEdit()->mControlAvatar.get(); +} + +// Manage the control avatar state of a given object. +// Any object can be flagged as animated, but for performance reasons +// we don't want to incur the overhead of managing a control avatar +// unless this would have some user-visible consequence. That is, +// there should be at least one rigged mesh in the linkset. Operations +// that change the state of a linkset, such as linking or unlinking +// prims, can also mean that a control avatar needs to be added or +// removed. At the end, if there is a control avatar, we make sure +// that its animation state is current. +void LLViewerObject::updateControlAvatar() +{ + LLViewerObject *root = getRootEdit(); + bool is_animated_object = root->isAnimatedObject(); + bool has_control_avatar = getControlAvatar(); + if (!is_animated_object && !has_control_avatar) + { + return; + } + + bool should_have_control_avatar = false; + if (is_animated_object) + { + bool any_rigged_mesh = root->isRiggedMesh(); + LLViewerObject::const_child_list_t& child_list = root->getChildren(); + for (const auto& iter : child_list) + { + const LLViewerObject* child = iter; + any_rigged_mesh = any_rigged_mesh || child->isRiggedMesh(); + } + should_have_control_avatar = is_animated_object && any_rigged_mesh; + } + + if (should_have_control_avatar && !has_control_avatar) + { + std::string vobj_name = llformat("Vol%p", root); + LL_DEBUGS("AnimatedObjects") << vobj_name << " calling linkControlAvatar()" << LL_ENDL; + root->linkControlAvatar(); + } + if (!should_have_control_avatar && has_control_avatar) + { + std::string vobj_name = llformat("Vol%p", root); + LL_DEBUGS("AnimatedObjects") << vobj_name << " calling unlinkControlAvatar()" << LL_ENDL; + root->unlinkControlAvatar(); + } + if (getControlAvatar()) + { + getControlAvatar()->updateAnimations(); + if (isSelected()) + { + LLSelectMgr::getInstance()->pauseAssociatedAvatars(); + } + } +} + +void LLViewerObject::print() +{ + if (!mChildList.size()) + return; + LL_INFOS() << "==============" << LL_ENDL; + LL_INFOS() << mID << LL_ENDL; + LL_INFOS() << "isAvatar() " << isAvatar() << LL_ENDL; + LL_INFOS() << " mOwnerID " << mOwnerID << LL_ENDL; + LL_INFOS() << " mRegionp " << std::hex << mRegionp << std::dec << LL_ENDL; + if (mRegionp) + { + LL_INFOS() << " getName() " << mRegionp->getName() << LL_ENDL; + LL_INFOS() << " isAlive() " << mRegionp->isAlive() << LL_ENDL; + } + LL_INFOS() << " mDead " << mDead << LL_ENDL; + LL_INFOS() << " mDrawable " << std::hex << mDrawable.get() << std::dec << LL_ENDL; + if (mDrawable) + { + LL_INFOS() << " isVisible() " << mDrawable->isVisible() << LL_ENDL; + LL_INFOS() << " getRegion() " << std::hex << mDrawable->getRegion() << std::dec << LL_ENDL; + if (mDrawable->getRegion()) + { + LL_INFOS() << " getRegion() " << mDrawable->getRegion()->getName() << LL_ENDL; + } + LL_INFOS() << " isRoot() " << mDrawable->isRoot() << LL_ENDL; + LL_INFOS() << " isDead() " << mDrawable->isDead() << LL_ENDL; + LL_INFOS() << " isNew() " << mDrawable->isNew() << LL_ENDL; + LL_INFOS() << " isUnload() " << mDrawable->isUnload() << LL_ENDL; + LL_INFOS() << " isLight() " << mDrawable->isLight() << LL_ENDL; + LL_INFOS() << " getSpatialGroup() " << mDrawable->getSpatialGroup() << LL_ENDL; + } + LL_INFOS() << " mOrphaned " << mOrphaned << LL_ENDL; + LL_INFOS() << " isAttachment() " << isAttachment() << LL_ENDL; + LL_INFOS() << " isActive() " << isActive() << LL_ENDL; + LL_INFOS() << " isRiggedMesh() " << isRiggedMesh() << LL_ENDL; + LL_INFOS() << " isHUDAttachment() " << isHUDAttachment() << LL_ENDL; + LL_INFOS() << " isMesh() " << isRiggedMesh() << LL_ENDL; + LL_INFOS() << " isParticleSource() " << isRiggedMesh() << LL_ENDL; + LL_INFOS() << " isTempAttachment() " << isTempAttachment() << LL_ENDL; + LL_INFOS() << " getVObjRadius() " << getVObjRadius() << LL_ENDL; + LL_INFOS() << " getNumVertices() " << getNumVertices() << LL_ENDL; + LL_INFOS() << " getNumIndices() " << getNumIndices() << LL_ENDL; + LL_INFOS() << " isAnySelected() " << isAnySelected() << LL_ENDL; + LL_INFOS() << " isFlexible() " << isFlexible() << LL_ENDL; + LL_INFOS() << " isSculpted() " << isSculpted() << LL_ENDL; + LL_INFOS() << " mTotalCRC " << mTotalCRC << LL_ENDL; + LL_INFOS() << " mListIndex " << mListIndex << LL_ENDL; + //LL_INFOS() << " mTEImages " << mTEImages << LL_ENDL; + //LL_INFOS() << " mTENormalMaps " << mTENormalMaps << LL_ENDL; + //LL_INFOS() << " mTESpecularMaps " << mTESpecularMaps << LL_ENDL; + LL_INFOS() << " mGLName " << mGLName << LL_ENDL; + LL_INFOS() << " mbCanSelect " << mbCanSelect << LL_ENDL; + LL_INFOS() << " mFlags" << mFlags << LL_ENDL; + //LL_INFOS() << " mPhysicsShapeType " << mPhysicsShapeType << LL_ENDL; + //LL_INFOS() << " mPhysicsGravity " << mPhysicsGravity << LL_ENDL; + //LL_INFOS() << " mPhysicsFriction " << mPhysicsFriction << LL_ENDL; + //LL_INFOS() << " mPhysicsDensity " << mPhysicsDensity << LL_ENDL; + //LL_INFOS() << " mPhysicsRestitution " << mPhysicsRestitution << LL_ENDL; + //LL_INFOS() << " mCreateSelected " << mCreateSelected << LL_ENDL; + //LL_INFOS() << " mRenderMedia " << mRenderMedia << LL_ENDL; + //LL_INFOS() << " mBestUpdatePrecision " << mBestUpdatePrecision << LL_ENDL; + //LL_INFOS() << " mText" << std::hex << mText.get() << std::dec << LL_ENDL; + //LL_INFOS() << " mHudTextString " << mHudTextString << LL_ENDL; + //LL_INFOS() << " mHudTextColor " << mHudTextColor << LL_ENDL; + //LL_INFOS() << " mIcon" << std::hex << mIcon.get() << std::dec << LL_ENDL; + LL_INFOS() << " mIsNameAttachment " << mIsNameAttachment << LL_ENDL; + LL_INFOS() << " mControlAvatar " << std::hex << mControlAvatar.get() << std::dec << LL_ENDL; + LL_INFOS() << " mChildList.size() " << mChildList.size() << LL_ENDL; + LL_INFOS() << " mLastInterpUpdateSecs " << mLastInterpUpdateSecs << LL_ENDL; + LL_INFOS() << " mLastMessageUpdateSecs " << mLastMessageUpdateSecs << LL_ENDL; + LL_INFOS() << " mLatestRecvPacketID " << mLatestRecvPacketID << LL_ENDL; + //LL_INFOS() << " mData" << std::hex << mData << std::dec << LL_ENDL; + //LL_INFOS() << " mPartSourcep " << std::hex << mPartSourcep.get() << std::dec << LL_ENDL; + //LL_INFOS() << " mAudioSourcep " << std::hex << mAudioSourcep << std::dec << LL_ENDL; + //LL_INFOS() << " mAudioGain " << mAudioGain << LL_ENDL; + LL_INFOS() << " mAppAngle " << mAppAngle << LL_ENDL; + LL_INFOS() << " mPixelArea " << mPixelArea << LL_ENDL; + LL_INFOS() << " mInventory " << mInventory << LL_ENDL; + LL_INFOS() << " mInventorySerialNum " << mInventorySerialNum << LL_ENDL; + LL_INFOS() << " mInvRequestState " << mInvRequestState << LL_ENDL; + LL_INFOS() << " mInvRequestXFerId " << mInvRequestXFerId << LL_ENDL; + LL_INFOS() << " mInventoryDirty " << mInventoryDirty << LL_ENDL; + LL_INFOS() << " mUserSelected " << mUserSelected << LL_ENDL; + LL_INFOS() << " mOnActiveList " << mOnActiveList << LL_ENDL; + LL_INFOS() << " mOnMap" << mOnMap << LL_ENDL; + LL_INFOS() << " mStatic " << mStatic << LL_ENDL; + LL_INFOS() << " mNumFaces " << mNumFaces << LL_ENDL; + LL_INFOS() << " mRotTime " << mRotTime << LL_ENDL; + //LL_INFOS() << " mAngularVelocityRot " << mAngularVelocityRot << LL_ENDL; + //LL_INFOS() << " mPreviousRotation " << mPreviousRotation << LL_ENDL; + LL_INFOS() << " mAttachmentState " << mAttachmentState << LL_ENDL; + LL_INFOS() << " mClickAction " << mClickAction << LL_ENDL; + //LL_INFOS() << " mObjectCost " << mObjectCost << LL_ENDL; + //LL_INFOS() << " mLinksetCost " << mLinksetCost << LL_ENDL; + //LL_INFOS() << " mPhysicsCost " << mPhysicsCost << LL_ENDL; + //LL_INFOS() << " mLinksetPhysicsCost " << mLinksetPhysicsCost << LL_ENDL; + LL_INFOS() << " mCostStale " << mCostStale << LL_ENDL; + LL_INFOS() << " mPhysicsShapeUnknown " << mPhysicsShapeUnknown << LL_ENDL; + LL_INFOS() << " mPositionRegion " << mPositionRegion << LL_ENDL; + LL_INFOS() << " mPositionAgent " << mPositionAgent << LL_ENDL; + LL_INFOS() << " mAttachmentItemID " << mAttachmentItemID << LL_ENDL; + LL_INFOS() << " mLastUpdateType " << mLastUpdateType << LL_ENDL; + LL_INFOS() << " mLastUpdateCached " << mLastUpdateCached << LL_ENDL; + LL_INFOS() << "==============" << LL_ENDL; +} + +void LLViewerObject::linkControlAvatar() +{ + if (!getControlAvatar() && isRootEdit()) + { + LLVOVolume *volp = asVolume(); + if (!volp) + { + LL_WARNS() << "called with null or non-volume object" << LL_ENDL; + return; + } + mControlAvatar = LLControlAvatar::createControlAvatar(volp); + LL_DEBUGS("AnimatedObjects") << volp->getID() + << " created control av for " + << (S32) (1+volp->numChildren()) << " prims" << LL_ENDL; + } + LLControlAvatar *cav = getControlAvatar(); + if (cav) + { + cav->updateAttachmentOverrides(); + if (!cav->mPlaying) + { + cav->mPlaying = true; + //if (!cav->mRootVolp->isAnySelected()) + { + cav->updateVolumeGeom(); + cav->mRootVolp->recursiveMarkForUpdate(TRUE); + } + } + } + else + { + LL_WARNS() << "no control avatar found!" << LL_ENDL; } } +void LLViewerObject::unlinkControlAvatar() +{ + if (getControlAvatar()) + { + getControlAvatar()->updateAttachmentOverrides(); + } + if (isRootEdit()) + { + // This will remove the entire linkset from the control avatar + if (mControlAvatar) + { + mControlAvatar->markForDeath(); + mControlAvatar->mRootVolp = NULL; + mControlAvatar = NULL; + } + } + // For non-root prims, removing from the linkset will + // automatically remove the control avatar connection. +} + +// virtual +bool LLViewerObject::isAnimatedObject() const +{ + return false; +} + struct LLFilenameAndTask { LLUUID mTaskID; std::string mFilename; + + // for sequencing in case of multiple updates + S16 mSerial; #ifdef _DEBUG static S32 sCount; LLFilenameAndTask() { ++sCount; - lldebugs << "Constructing LLFilenameAndTask: " << sCount << llendl; + LL_DEBUGS() << "Constructing LLFilenameAndTask: " << sCount << LL_ENDL; } ~LLFilenameAndTask() { --sCount; - lldebugs << "Destroying LLFilenameAndTask: " << sCount << llendl; + LL_DEBUGS() << "Destroying LLFilenameAndTask: " << sCount << LL_ENDL; } private: LLFilenameAndTask(const LLFilenameAndTask& rhs); @@ -2762,22 +3186,30 @@ void LLViewerObject::processTaskInv(LLMessageSystem* msg, void** user_data) LLViewerObject* object = gObjectList.findObject(task_id); if(!object) { - llwarns << "LLViewerObject::processTaskInv object " - << task_id << " does not exist." << llendl; + LL_WARNS() << "LLViewerObject::processTaskInv object " + << task_id << " does not exist." << LL_ENDL; return; } - msg->getS16Fast(_PREHASH_InventoryData, _PREHASH_Serial, object->mInventorySerialNum); LLFilenameAndTask* ft = new LLFilenameAndTask; ft->mTaskID = task_id; + // we can receive multiple task updates simultaneously, make sure we will not rewrite newer with older update + msg->getS16Fast(_PREHASH_InventoryData, _PREHASH_Serial, ft->mSerial); + + if (ft->mSerial < object->mInventorySerialNum) + { + // viewer did some changes to inventory that were not saved yet. + LL_DEBUGS() << "Task inventory serial might be out of sync, server serial: " << ft->mSerial << " client serial: " << object->mInventorySerialNum << LL_ENDL; + object->mInventorySerialNum = ft->mSerial; + } std::string unclean_filename; msg->getStringFast(_PREHASH_InventoryData, _PREHASH_Filename, unclean_filename); ft->mFilename = LLDir::getScrubbedFileName(unclean_filename); - + if(ft->mFilename.empty()) { - lldebugs << "Task has no inventory" << llendl; + LL_DEBUGS() << "Task has no inventory" << LL_ENDL; // mock up some inventory to make a drop target. if(object->mInventory) { @@ -2796,57 +3228,85 @@ void LLViewerObject::processTaskInv(LLMessageSystem* msg, void** user_data) delete ft; return; } - gXferManager->requestFile(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ft->mFilename), + U64 new_id = gXferManager->requestFile(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ft->mFilename), ft->mFilename, LL_PATH_CACHE, object->mRegionp->getHost(), TRUE, &LLViewerObject::processTaskInvFile, (void**)ft, LLXferManager::HIGH_PRIORITY); + if (object->mInvRequestState == INVENTORY_XFER) + { + if (new_id > 0 && new_id != object->mInvRequestXFerId) + { + // we started new download. + gXferManager->abortRequestById(object->mInvRequestXFerId, -1); + object->mInvRequestXFerId = new_id; + } + } + else + { + object->mInvRequestState = INVENTORY_XFER; + object->mInvRequestXFerId = new_id; + } } void LLViewerObject::processTaskInvFile(void** user_data, S32 error_code, LLExtStat ext_status) { LLFilenameAndTask* ft = (LLFilenameAndTask*)user_data; LLViewerObject* object = NULL; - if(ft && (0 == error_code) && - (object = gObjectList.findObject(ft->mTaskID))) + + if (ft + && (0 == error_code) + && (object = gObjectList.findObject(ft->mTaskID)) + && ft->mSerial >= object->mInventorySerialNum) { - object->loadTaskInvFile(ft->mFilename); + object->mInventorySerialNum = ft->mSerial; + if (object->loadTaskInvFile(ft->mFilename)) + { - LLInventoryObject::object_list_t::iterator it = object->mInventory->begin(); - LLInventoryObject::object_list_t::iterator end = object->mInventory->end(); - std::list& pending_lst = object->mPendingInventoryItemsIDs; + LLInventoryObject::object_list_t::iterator it = object->mInventory->begin(); + LLInventoryObject::object_list_t::iterator end = object->mInventory->end(); + std::list& pending_lst = object->mPendingInventoryItemsIDs; - for (; it != end && pending_lst.size(); ++it) - { - LLViewerInventoryItem* item = dynamic_cast(it->get()); - if(item && item->getType() != LLAssetType::AT_CATEGORY) + for (; it != end && !pending_lst.empty(); ++it) { - std::list::iterator id_it = std::find(pending_lst.begin(), pending_lst.begin(), item->getAssetUUID()); - if (id_it != pending_lst.end()) + LLViewerInventoryItem* item = dynamic_cast(it->get()); + if(item && item->getType() != LLAssetType::AT_CATEGORY) { - pending_lst.erase(id_it); + std::list::iterator id_it = std::find(pending_lst.begin(), pending_lst.end(), item->getAssetUUID()); + if (id_it != pending_lst.end()) + { + pending_lst.erase(id_it); + } } } } + else + { + // MAINT-2597 - crash when trying to edit a no-mod object + // Somehow get an contents inventory response, but with an invalid stream (possibly 0 size?) + // Stated repro was specific to no-mod objects so failing without user interaction should be safe. + LL_WARNS() << "Trying to load invalid task inventory file. Ignoring file contents." << LL_ENDL; + } } else { - // This Occurs When to requests were made, and the first one + // This Occurs When two requests were made, and the first one // has already handled it. - lldebugs << "Problem loading task inventory. Return code: " - << error_code << llendl; + LL_DEBUGS() << "Problem loading task inventory. Return code: " + << error_code << LL_ENDL; } delete ft; } -void LLViewerObject::loadTaskInvFile(const std::string& filename) +BOOL LLViewerObject::loadTaskInvFile(const std::string& filename) { std::string filename_and_local_path = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, filename); - llifstream ifs(filename_and_local_path); + llifstream ifs(filename_and_local_path.c_str()); if(ifs.good()) { + U32 fail_count = 0; char buffer[MAX_STRING]; /* Flawfinder: ignore */ // *NOTE: This buffer size is hard coded into scanf() below. char keyword[MAX_STRING]; /* Flawfinder: ignore */ @@ -2861,8 +3321,14 @@ void LLViewerObject::loadTaskInvFile(const std::string& filename) while(ifs.good()) { ifs.getline(buffer, MAX_STRING); - sscanf(buffer, " %254s", keyword); /* Flawfinder: ignore */ - if(0 == strcmp("inv_item", keyword)) + if (sscanf(buffer, " %254s", keyword) == EOF) /* Flawfinder: ignore */ + { + // Blank file? + LL_WARNS() << "Issue reading from file '" + << filename << "'" << LL_ENDL; + break; + } + else if(0 == strcmp("inv_item", keyword)) { LLPointer inv = new LLViewerInventoryItem; inv->importLegacyStream(ifs); @@ -2872,12 +3338,21 @@ void LLViewerObject::loadTaskInvFile(const std::string& filename) { LLPointer inv = new LLInventoryObject; inv->importLegacyStream(ifs); + inv->rename("Contents"); mInventory->push_front(inv); } + else if (fail_count >= MAX_INV_FILE_READ_FAILS) + { + LL_WARNS() << "Encountered too many unknowns while reading from file: '" + << filename << "'" << LL_ENDL; + break; + } else { - llwarns << "Unknown token in inventory file '" - << keyword << "'" << llendl; + // Is there really a point to continue processing? We already failing to display full inventory + fail_count++; + LL_WARNS_ONCE() << "Unknown token while reading from inventory file. Token: '" + << keyword << "'" << LL_ENDL; } } ifs.close(); @@ -2885,10 +3360,13 @@ void LLViewerObject::loadTaskInvFile(const std::string& filename) } else { - llwarns << "unable to load task inventory: " << filename_and_local_path - << llendl; + LL_WARNS() << "unable to load task inventory: " << filename_and_local_path + << LL_ENDL; + return FALSE; } doInventoryCallback(); + + return TRUE; } void LLViewerObject::doInventoryCallback() @@ -2907,12 +3385,15 @@ void LLViewerObject::doInventoryCallback() } else { - llinfos << "LLViewerObject::doInventoryCallback() deleting bad listener entry." << llendl; + LL_INFOS() << "LLViewerObject::doInventoryCallback() deleting bad listener entry." << LL_ENDL; delete info; mInventoryCallbacks.erase(curiter); } } - mInventoryPending = FALSE; + + // release inventory loading state + mInvRequestXFerId = 0; + mInvRequestState = INVENTORY_REQUEST_STOPPED; } void LLViewerObject::removeInventory(const LLUUID& item_id) @@ -2931,11 +3412,6 @@ void LLViewerObject::removeInventory(const LLUUID& item_id) msg->sendReliable(mRegionp->getHost()); deleteInventoryItem(item_id); ++mInventorySerialNum; - - // The viewer object should not refresh UI since this is a utility - // function. The UI functionality that called this method should - // refresh the views if necessary. - //gBuildView->refresh(); } bool LLViewerObject::isTextureInInventory(LLViewerInventoryItem* item) @@ -3027,7 +3503,7 @@ LLInventoryObject* LLViewerObject::getInventoryObject(const LLUUID& item_id) rv = *it; break; } - } + } } return rv; } @@ -3050,7 +3526,7 @@ void LLViewerObject::getInventoryContents(LLInventoryObject::object_list_t& obje LLInventoryObject* LLViewerObject::getInventoryRoot() { - if (!mInventory || !mInventory->size()) + if (!mInventory || mInventory->empty()) { return NULL; } @@ -3060,7 +3536,7 @@ LLInventoryObject* LLViewerObject::getInventoryRoot() LLViewerInventoryItem* LLViewerObject::getInventoryItemByAsset(const LLUUID& asset_id) { if (mInventoryDirty) - llwarns << "Peforming inventory lookup for object " << mID << " that has dirty inventory!" << llendl; + LL_WARNS() << "Peforming inventory lookup for object " << mID << " that has dirty inventory!" << LL_ENDL; LLViewerInventoryItem* rv = NULL; if(mInventory) @@ -3082,7 +3558,7 @@ LLViewerInventoryItem* LLViewerObject::getInventoryItemByAsset(const LLUUID& ass break; } } - } + } } return rv; } @@ -3105,9 +3581,9 @@ void LLViewerObject::setPixelAreaAndAngle(LLAgent &agent) { //volumes calculate pixel area and angle per face return; } - - LLVector3 viewer_pos_agent = gAgentCamera.getCameraPositionAgent(); - LLVector3 pos_agent = getRenderPosition(); + + const LLVector3& viewer_pos_agent = gAgentCamera.getCameraPositionAgent(); + const LLVector3& pos_agent = getRenderPosition(); F32 dx = viewer_pos_agent.mV[VX] - pos_agent.mV[VX]; F32 dy = viewer_pos_agent.mV[VY] - pos_agent.mV[VY]; @@ -3121,7 +3597,7 @@ void LLViewerObject::setPixelAreaAndAngle(LLAgent &agent) // to try to get a min distance from face, subtract min_scale/2 from the range. // This means we'll load too much detail sometimes, but that's better than not enough // I don't think there's a better way to do this without calculating distance per-poly - F32 range = sqrt(dx*dx + dy*dy + dz*dz) - min_scale/2; + F32 range = sqrt(dx*dx + dy*dy + dz*dz) - min_scale/2.f; LLViewerCamera* camera = LLViewerCamera::getInstance(); if (range < 0.001f || isHUDAttachment()) // range == zero @@ -3161,7 +3637,7 @@ void LLViewerObject::updateGL() void LLViewerObject::updateFaceSize(S32 idx) { - + } LLDrawable* LLViewerObject::createDrawable(LLPipeline *pipeline) @@ -3174,7 +3650,7 @@ void LLViewerObject::setScale(const LLVector3 &scale, BOOL damped) LLPrimitive::setScale(scale); if (mDrawable.notNull()) { - //encompass completely sheared objects by taking + //encompass completely sheared objects by taking //the most extreme point possible (<1,1,0.5>) mDrawable->setRadius(LLVector3(1,1,0.5f).scaleVec(scale).magVec()); updateDrawable(damped); @@ -3218,8 +3694,17 @@ void LLViewerObject::setLinksetCost(F32 cost) { mLinksetCost = cost; mCostStale = false; - - if (isSelected()) + + BOOL needs_refresh = isSelected(); + child_list_t::iterator iter = mChildList.begin(); + while(iter != mChildList.end() && !needs_refresh) + { + LLViewerObject* child = *iter; + needs_refresh = child->isSelected(); + iter++; + } + + if (needs_refresh) { gFloaterTools->dirty(); } @@ -3240,7 +3725,7 @@ void LLViewerObject::setLinksetPhysicsCost(F32 cost) { mLinksetPhysicsCost = cost; mCostStale = false; - + if (isSelected()) { gFloaterTools->dirty(); @@ -3254,7 +3739,7 @@ F32 LLViewerObject::getObjectCost() { gObjectList.updateObjectCost(this); } - + return mObjectCost; } @@ -3274,7 +3759,7 @@ F32 LLViewerObject::getPhysicsCost() { gObjectList.updateObjectCost(this); } - + return mPhysicsCost; } @@ -3288,11 +3773,65 @@ F32 LLViewerObject::getLinksetPhysicsCost() return mLinksetPhysicsCost; } -F32 LLViewerObject::getStreamingCost(S32* bytes, S32* visible_bytes, F32* unscaled_value) const +F32 LLViewerObject::recursiveGetEstTrianglesMax() const +{ + F32 est_tris = getEstTrianglesMax(); + for (const auto& iter : mChildList) + { + const LLViewerObject* child = iter; + if (!child->isAvatar()) + { + est_tris += child->recursiveGetEstTrianglesMax(); + } + } + return est_tris; +} + +S32 LLViewerObject::getAnimatedObjectMaxTris() const +{ + S32 max_tris = 0; + if (gSavedSettings.getBOOL("AnimatedObjectsIgnoreLimits")) + { + max_tris = S32_MAX; + } + else + { + if (gAgent.getRegion()) + { + LLSD features; + gAgent.getRegion()->getSimulatorFeatures(features); + if (features.has("AnimatedObjects")) + { + max_tris = features["AnimatedObjects"]["AnimatedObjectMaxTris"].asInteger(); + } + } + } + return max_tris; +} + +F32 LLViewerObject::getEstTrianglesMax() const +{ + return 0.f; +} + +F32 LLViewerObject::getEstTrianglesStreamingCost() const { return 0.f; } +// virtual +F32 LLViewerObject::getStreamingCost() const +{ + return 0.f; +} + +// virtual +bool LLViewerObject::getCostData(LLMeshCostData& costs) const +{ + costs = LLMeshCostData(); + return false; +} + U32 LLViewerObject::getTriangleCount(S32* vcount) const { return 0; @@ -3303,6 +3842,55 @@ U32 LLViewerObject::getHighLODTriangleCount() return 0; } +U32 LLViewerObject::recursiveGetTriangleCount(S32* vcount) const +{ + S32 total_tris = getTriangleCount(vcount); + LLViewerObject::const_child_list_t& child_list = getChildren(); + for (const auto& iter : child_list) + { + LLViewerObject* childp = iter; + if (childp) + { + total_tris += childp->getTriangleCount(vcount); + } + } + return total_tris; +} + +// This is using the stored surface area for each volume (which +// defaults to 1.0 for the case of everything except a sculpt) and +// then scaling it linearly based on the largest dimension in the +// prim's scale. Should revisit at some point. +F32 LLViewerObject::recursiveGetScaledSurfaceArea() const +{ + F32 area = 0.f; + const LLDrawable* drawable = mDrawable; + if (drawable) + { + const LLVOVolume* volume = drawable->getVOVolume(); + if (volume) + { + if (volume->getVolume()) + { + const LLVector3& scale = volume->getScale(); + area += volume->getVolume()->getSurfaceArea() * llmax(llmax(scale.mV[0], scale.mV[1]), scale.mV[2]); + } + LLViewerObject::const_child_list_t const& children = volume->getChildren(); + for (const auto& child_iter : children) + { + LLViewerObject* child_obj = child_iter; + LLVOVolume *child = child_obj ? child_obj->asVolume() : nullptr; + if (child && child->getVolume()) + { + const LLVector3& scale = child->getScale(); + area += child->getVolume()->getSurfaceArea() * llmax(llmax(scale.mV[0], scale.mV[1]), scale.mV[2]); + } + } + } + } + return area; +} + void LLViewerObject::updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax) { if(mDrawable.isNull()) @@ -3313,7 +3901,7 @@ void LLViewerObject::updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax size.load3(getScale().mV); newMin.setSub(center, size); newMax.setAdd(center, size); - + mDrawable->setPositionGroup(center); } @@ -3326,7 +3914,7 @@ F32 LLViewerObject::getBinRadius() diff.setSub(ext[1], ext[0]); return diff.getLength3().getF32(); } - + return getScale().magVec(); } @@ -3387,16 +3975,16 @@ void LLViewerObject::boostTexturePriority(BOOL boost_children /* = TRUE */) S32 tex_count = getNumTEs(); for (i = 0; i < tex_count; i++) { - getTEImage(i)->setBoostLevel(LLGLTexture::BOOST_SELECTED); + getTEImage(i)->setBoostLevel(LLGLTexture::BOOST_SELECTED); } if (isSculpted() && !isMesh()) { - LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT); + const LLSculptParams *sculpt_params = getSculptParams(); LLUUID sculpt_id = sculpt_params->getSculptTexture(); - LLViewerTextureManager::getFetchedTexture(sculpt_id, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE)->setBoostLevel(LLGLTexture::BOOST_SELECTED); + LLViewerTextureManager::getFetchedTexture(sculpt_id, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE)->setBoostLevel(LLGLTexture::BOOST_SELECTED); } - + if (boost_children) { for (child_list_t::iterator iter = mChildList.begin(); @@ -3467,7 +4055,7 @@ void LLViewerObject::addNVPair(const std::string& data) // char splat[MAX_STRING]; // temp->printNameValue(splat); -// llinfos << "addNVPair " << splat << llendl; +// LL_INFOS() << "addNVPair " << splat << LL_ENDL; name_value_map_t::iterator iter = mNameValuePairs.find(nv->mName); if (iter != mNameValuePairs.end()) @@ -3481,7 +4069,7 @@ void LLViewerObject::addNVPair(const std::string& data) else { delete nv; -// llinfos << "Trying to write to Read Only NVPair " << temp->mName << " in addNVPair()" << llendl; +// LL_INFOS() << "Trying to write to Read Only NVPair " << temp->mName << " in addNVPair()" << LL_ENDL; return; } } @@ -3492,7 +4080,7 @@ BOOL LLViewerObject::removeNVPair(const std::string& name) { char* canonical_name = gNVNameTable.addString(name); - lldebugs << "LLViewerObject::removeNVPair(): " << name << llendl; + LL_DEBUGS() << "LLViewerObject::removeNVPair(): " << name << LL_ENDL; name_value_map_t::iterator iter = mNameValuePairs.find(canonical_name); if (iter != mNameValuePairs.end()) @@ -3505,7 +4093,7 @@ BOOL LLViewerObject::removeNVPair(const std::string& name) gMessageSystem->newMessageFast(_PREHASH_RemoveNameValuePair); gMessageSystem->nextBlockFast(_PREHASH_TaskData); gMessageSystem->addUUIDFast(_PREHASH_ID, mID); - + gMessageSystem->nextBlockFast(_PREHASH_NameValueData); gMessageSystem->addStringFast(_PREHASH_NVPair, buffer); @@ -3518,7 +4106,7 @@ BOOL LLViewerObject::removeNVPair(const std::string& name) } else { - lldebugs << "removeNVPair - No region for object" << llendl; + LL_DEBUGS() << "removeNVPair - No region for object" << LL_ENDL; } } return FALSE; @@ -3563,7 +4151,7 @@ void LLViewerObject::updatePositionCaches() const } const LLVector3d LLViewerObject::getPositionGlobal() const -{ +{ // If region is removed from the list it is also deleted. if(mRegionp && LLWorld::instance().isRegionListed(mRegionp)) { @@ -3572,14 +4160,14 @@ const LLVector3d LLViewerObject::getPositionGlobal() const if (isAttachment()) { position_global = gAgent.getPosGlobalFromAgent(getRenderPosition()); - } + } return position_global; } else { LLVector3d position_global(getPosition()); return position_global; - } + } } const LLVector3 &LLViewerObject::getPositionAgent() const @@ -3635,8 +4223,20 @@ const LLVector3 LLViewerObject::getRenderPosition() const { if (mDrawable.notNull() && mDrawable->isState(LLDrawable::RIGGED)) { + LLControlAvatar *cav = getControlAvatar(); + if (isRoot() && cav) + { + F32 fixup; + if ( cav->hasPelvisFixup( fixup) ) + { + //Apply a pelvis fixup (as defined by the avs skin) + LLVector3 pos = mDrawable->getPositionAgent(); + pos[VZ] += fixup; + return pos; + } + } LLVOAvatar* avatar = getAvatar(); - if (avatar) + if ((avatar) && !getControlAvatar()) { return avatar->getPositionAgent(); } @@ -3660,11 +4260,11 @@ const LLVector3 LLViewerObject::getPivotPositionAgent() const const LLQuaternion LLViewerObject::getRenderRotation() const { LLQuaternion ret; - if (mDrawable.notNull() && mDrawable->isState(LLDrawable::RIGGED)) + if (mDrawable.notNull() && mDrawable->isState(LLDrawable::RIGGED) && !isAnimatedObject()) { return ret; } - + if (mDrawable.isNull() || mDrawable->isStatic()) { ret = getRotationEdit(); @@ -3673,18 +4273,18 @@ const LLQuaternion LLViewerObject::getRenderRotation() const { if (!mDrawable->isRoot()) { - ret = getRotation() * LLQuaternion(mDrawable->getParent()->getWorldMatrix()); + ret = getRotation() * LLQuaternion(LLMatrix4(mDrawable->getParent()->getWorldMatrix().getF32ptr())); } else { - ret = LLQuaternion(mDrawable->getWorldMatrix()); + ret = LLQuaternion(LLMatrix4(mDrawable->getWorldMatrix().getF32ptr())); } } - + return ret; } -const LLMatrix4 LLViewerObject::getRenderMatrix() const +const LLMatrix4a& LLViewerObject::getRenderMatrix() const { return mDrawable->getWorldMatrix(); } @@ -3727,7 +4327,7 @@ void LLViewerObject::setPositionAbsoluteGlobal( const LLVector3d &pos_global, BO new_pos = new_pos * ~parentp->getRotationRegion(); } LLViewerObject::setPosition(new_pos); - + if (mParent && ((LLViewerObject*)mParent)->isAvatar()) { // we have changed the position of an attachment, so we need to clamp it @@ -3764,7 +4364,7 @@ void LLViewerObject::setPosition(const LLVector3 &pos, BOOL damped) { setChanged(TRANSLATED | SILHOUETTE); } - + LLXform::setPosition(pos); updateDrawable(damped); if (isRoot()) @@ -3798,7 +4398,7 @@ void LLViewerObject::setPositionGlobal(const LLVector3d &pos_global, BOOL damped LLQuaternion invRotation = mDrawable->getRotation(); invRotation.transQuat(); - + delta_pos = delta_pos * invRotation; // *FIX: is this right? Shouldn't we be calling the @@ -3869,7 +4469,7 @@ void LLViewerObject::setPositionAgent(const LLVector3 &pos_agent, BOOL damped) setPositionRegion(pos_region, damped); } -// identical to setPositionRegion() except it checks for child-joints +// identical to setPositionRegion() except it checks for child-joints // and doesn't also move the joint-parent // TODO -- implement similar intelligence for joint-parents toward // their joint-children @@ -3888,14 +4488,14 @@ void LLViewerObject::setPositionEdit(const LLVector3 &pos_edit, BOOL damped) LLViewerObject::setPosition(pos_edit, damped); mPositionRegion = pos_edit; mPositionAgent = mRegionp->getPosAgentFromRegion(mPositionRegion); - } + } } LLViewerObject* LLViewerObject::getRootEdit() const { const LLViewerObject* root = this; - while (root->mParent + while (root->mParent && !((LLViewerObject*)root->mParent)->isAvatar()) { root = (LLViewerObject*)root->mParent; @@ -3904,19 +4504,20 @@ LLViewerObject* LLViewerObject::getRootEdit() const } -BOOL LLViewerObject::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, +BOOL LLViewerObject::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, S32 face, BOOL pick_transparent, + BOOL pick_rigged, S32* face_hit, - LLVector3* intersection, + LLVector4a* intersection, LLVector2* tex_coord, - LLVector3* normal, - LLVector3* bi_normal) + LLVector4a* normal, + LLVector4a* tangent) { return false; } -BOOL LLViewerObject::lineSegmentBoundingBox(const LLVector3& start, const LLVector3& end) +BOOL LLViewerObject::lineSegmentBoundingBox(const LLVector4a& start, const LLVector4a& end) { if (mDrawable.isNull() || mDrawable->isDead()) { @@ -3933,11 +4534,7 @@ BOOL LLViewerObject::lineSegmentBoundingBox(const LLVector3& start, const LLVect size.setSub(ext[1], ext[0]); size.mul(0.5f); - LLVector4a starta, enda; - starta.load3(start.mV); - enda.load3(end.mV); - - return LLLineSegmentBoxIntersect(starta, enda, center, size); + return LLLineSegmentBoxIntersect(start, end, center, size); } U8 LLViewerObject::getMediaType() const @@ -4036,25 +4633,39 @@ void LLViewerObject::setNumTEs(const U8 num_tes) { LLPointer *new_images; new_images = new LLPointer[num_tes]; + + LLPointer *new_normmaps; + new_normmaps = new LLPointer[num_tes]; + + LLPointer *new_specmaps; + new_specmaps = new LLPointer[num_tes]; for (i = 0; i < num_tes; i++) { if (i < getNumTEs()) { new_images[i] = mTEImages[i]; + new_normmaps[i] = mTENormalMaps[i]; + new_specmaps[i] = mTESpecularMaps[i]; } else if (getNumTEs()) { new_images[i] = mTEImages[getNumTEs()-1]; + new_normmaps[i] = mTENormalMaps[getNumTEs()-1]; + new_specmaps[i] = mTESpecularMaps[getNumTEs()-1]; } else { new_images[i] = NULL; + new_normmaps[i] = NULL; + new_specmaps[i] = NULL; } } deleteTEImages(); - + mTEImages = new_images; + mTENormalMaps = new_normmaps; + mTESpecularMaps = new_specmaps; } else { @@ -4097,7 +4708,7 @@ void LLViewerObject::sendRotationUpdate() const gMessageSystem->nextBlockFast(_PREHASH_ObjectData); gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, mLocalID); gMessageSystem->addQuatFast(_PREHASH_Rotation, getRotationEdit()); - //llinfos << "Sent rotation " << getRotationEdit() << llendl; + //LL_INFOS() << "Sent rotation " << getRotationEdit() << LL_ENDL; gMessageSystem->sendReliable( regionp->getHost() ); } @@ -4146,23 +4757,111 @@ void LLViewerObject::sendTEUpdate() const msg->sendReliable( regionp->getHost() ); } +LLViewerTexture* LLViewerObject::getBakedTextureForMagicId(const LLUUID& id) +{ + if (!LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::isBakedImageId(id)) + { + return NULL; + } + + LLViewerObject *root = getRootEdit(); + if (root && root->isAnimatedObject()) + { + return LLViewerTextureManager::getFetchedTexture(id, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); + } + + LLVOAvatar* avatar = getAvatar(); + if (avatar) + { + LLAvatarAppearanceDefines::EBakedTextureIndex texIndex = LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::assetIdToBakedTextureIndex(id); + LLViewerTexture* bakedTexture = avatar->getBakedTexture(texIndex); + if (bakedTexture == NULL || bakedTexture->isMissingAsset()) + { + return LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); + } + else + { + return bakedTexture; + } + } + else + { + return LLViewerTextureManager::getFetchedTexture(id, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); + } + +} + +void LLViewerObject::updateAvatarMeshVisibility(const LLUUID& id, const LLUUID& old_id) +{ + if (id == old_id) + { + return; + } + + if (!LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::isBakedImageId(old_id) && !LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::isBakedImageId(id)) + { + return; + } + + LLVOAvatar* avatar = getAvatar(); + if (avatar) + { + avatar->updateMeshVisibility(); + } +} + void LLViewerObject::setTE(const U8 te, const LLTextureEntry &texture_entry) { + LLUUID old_image_id; + if (getTE(te)) + { + old_image_id = getTE(te)->getID(); + } + LLPrimitive::setTE(te, texture_entry); -// This doesn't work, don't get any textures. -// if (mDrawable.notNull() && mDrawable->isVisible()) -// { - const LLUUID& image_id = getTE(te)->getID(); - mTEImages[te] = LLViewerTextureManager::getFetchedTexture(image_id, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); -// } + + const LLUUID& image_id = getTE(te)->getID(); + LLViewerTexture* bakedTexture = getBakedTextureForMagicId(image_id); + mTEImages[te] = bakedTexture ? bakedTexture : LLViewerTextureManager::getFetchedTexture(image_id, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); + + + updateAvatarMeshVisibility(image_id,old_image_id); + + if (getTE(te)->getMaterialParams().notNull()) + { + const LLUUID& norm_id = getTE(te)->getMaterialParams()->getNormalID(); + mTENormalMaps[te] = LLViewerTextureManager::getFetchedTexture(norm_id, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_ALM, LLViewerTexture::LOD_TEXTURE); + + const LLUUID& spec_id = getTE(te)->getMaterialParams()->getSpecularID(); + mTESpecularMaps[te] = LLViewerTextureManager::getFetchedTexture(spec_id, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_ALM, LLViewerTexture::LOD_TEXTURE); + } +} + +void LLViewerObject::refreshBakeTexture() +{ + for (int face_index = 0; face_index < getNumTEs(); face_index++) + { + LLTextureEntry* tex_entry = getTE(face_index); + if (tex_entry && LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::isBakedImageId(tex_entry->getID())) + { + const LLUUID& image_id = tex_entry->getID(); + LLViewerTexture* bakedTexture = getBakedTextureForMagicId(image_id); + changeTEImage(face_index, bakedTexture); + } + } } void LLViewerObject::setTEImage(const U8 te, LLViewerTexture *imagep) { if (mTEImages[te] != imagep) { - mTEImages[te] = imagep; + LLUUID old_image_id = getTE(te) ? getTE(te)->getID() : LLUUID::null; + LLPrimitive::setTETexture(te, imagep->getID()); + + LLViewerTexture* baked_texture = getBakedTextureForMagicId(imagep->getID()); + mTEImages[te] = baked_texture ? baked_texture : imagep; + updateAvatarMeshVisibility(imagep->getID(), old_image_id); setChanged(TEXTURE); if (mDrawable.notNull()) { @@ -4173,13 +4872,18 @@ void LLViewerObject::setTEImage(const U8 te, LLViewerTexture *imagep) S32 LLViewerObject::setTETextureCore(const U8 te, LLViewerTexture *image) { + if (!image) + return 0; + LLUUID old_image_id = getTE(te)->getID(); const LLUUID& uuid = image->getID(); S32 retval = 0; if (uuid != getTE(te)->getID() || uuid == LLUUID::null) { retval = LLPrimitive::setTETexture(te, uuid); - mTEImages[te] = image; + LLViewerTexture* baked_texture = getBakedTextureForMagicId(uuid); + mTEImages[te] = baked_texture ? baked_texture : image; + updateAvatarMeshVisibility(uuid,old_image_id); setChanged(TEXTURE); if (mDrawable.notNull()) { @@ -4189,8 +4893,54 @@ S32 LLViewerObject::setTETextureCore(const U8 te, LLViewerTexture *image) return retval; } +S32 LLViewerObject::setTENormalMapCore(const U8 te, LLViewerTexture *image) +{ + S32 retval = TEM_CHANGE_TEXTURE; + const LLUUID& uuid = image ? image->getID() : LLUUID::null; + if (uuid != getTE(te)->getID() || + uuid == LLUUID::null) + { + LLTextureEntry* tep = getTE(te); + LLMaterial* mat = NULL; + if (tep) + { + mat = tep->getMaterialParams(); + } + + if (mat) + { + mat->setNormalID(uuid); + } + } + changeTENormalMap(te,image); + return retval; +} + +S32 LLViewerObject::setTESpecularMapCore(const U8 te, LLViewerTexture *image) +{ + S32 retval = TEM_CHANGE_TEXTURE; + const LLUUID& uuid = image ? image->getID() : LLUUID::null; + if (uuid != getTE(te)->getID() || + uuid == LLUUID::null) + { + LLTextureEntry* tep = getTE(te); + LLMaterial* mat = NULL; + if (tep) + { + mat = tep->getMaterialParams(); + } + + if (mat) + { + mat->setSpecularID(uuid); + } + } + changeTESpecularMap(te, image); + return retval; +} + //virtual -void LLViewerObject::changeTEImage(S32 index, LLViewerTexture* new_image) +void LLViewerObject::changeTEImage(S32 index, LLViewerTexture* new_image) { if(index < 0 || index >= getNumTEs()) { @@ -4199,14 +4949,46 @@ void LLViewerObject::changeTEImage(S32 index, LLViewerTexture* new_image) mTEImages[index] = new_image ; } +void LLViewerObject::changeTENormalMap(S32 index, LLViewerTexture* new_image) +{ + if(index < 0 || index >= getNumTEs()) + { + return ; + } + mTENormalMaps[index] = new_image ; + refreshMaterials(); +} + +void LLViewerObject::changeTESpecularMap(S32 index, LLViewerTexture* new_image) +{ + if(index < 0 || index >= getNumTEs()) + { + return ; + } + mTESpecularMaps[index] = new_image ; + refreshMaterials(); +} S32 LLViewerObject::setTETexture(const U8 te, const LLUUID& uuid) { // Invalid host == get from the agent's sim LLViewerFetchedTexture *image = LLViewerTextureManager::getFetchedTexture( - uuid, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, LLHost::invalid); + uuid, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, LLHost::invalid); return setTETextureCore(te,image); } +S32 LLViewerObject::setTENormalMap(const U8 te, const LLUUID& uuid) +{ + LLViewerFetchedTexture *image = (uuid == LLUUID::null) ? NULL : LLViewerTextureManager::getFetchedTexture( + uuid, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_ALM, LLViewerTexture::LOD_TEXTURE, 0, 0, LLHost::invalid); + return setTENormalMapCore(te, image); +} + +S32 LLViewerObject::setTESpecularMap(const U8 te, const LLUUID& uuid) +{ + LLViewerFetchedTexture *image = (uuid == LLUUID::null) ? NULL : LLViewerTextureManager::getFetchedTexture( + uuid, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_ALM, LLViewerTexture::LOD_TEXTURE, 0, 0, LLHost::invalid); + return setTESpecularMapCore(te, image); +} S32 LLViewerObject::setTEColor(const U8 te, const LLColor3& color) { @@ -4219,7 +5001,7 @@ S32 LLViewerObject::setTEColor(const U8 te, const LLColor4& color) const LLTextureEntry *tep = getTE(te); if (!tep) { - llwarns << "No texture entry for te " << (S32)te << ", object " << mID << llendl; + LL_WARNS() << "No texture entry for te " << (S32)te << ", object " << mID << LL_ENDL; } else if (color != tep->getColor()) { @@ -4239,7 +5021,7 @@ S32 LLViewerObject::setTEBumpmap(const U8 te, const U8 bump) const LLTextureEntry *tep = getTE(te); if (!tep) { - llwarns << "No texture entry for te " << (S32)te << ", object " << mID << llendl; + LL_WARNS() << "No texture entry for te " << (S32)te << ", object " << mID << LL_ENDL; } else if (bump != tep->getBumpmap()) { @@ -4260,7 +5042,7 @@ S32 LLViewerObject::setTETexGen(const U8 te, const U8 texgen) const LLTextureEntry *tep = getTE(te); if (!tep) { - llwarns << "No texture entry for te " << (S32)te << ", object " << mID << llendl; + LL_WARNS() << "No texture entry for te " << (S32)te << ", object " << mID << LL_ENDL; } else if (texgen != tep->getTexGen()) { @@ -4276,7 +5058,7 @@ S32 LLViewerObject::setTEMediaTexGen(const U8 te, const U8 media) const LLTextureEntry *tep = getTE(te); if (!tep) { - llwarns << "No texture entry for te " << (S32)te << ", object " << mID << llendl; + LL_WARNS() << "No texture entry for te " << (S32)te << ", object " << mID << LL_ENDL; } else if (media != tep->getMediaTexGen()) { @@ -4292,7 +5074,7 @@ S32 LLViewerObject::setTEShiny(const U8 te, const U8 shiny) const LLTextureEntry *tep = getTE(te); if (!tep) { - llwarns << "No texture entry for te " << (S32)te << ", object " << mID << llendl; + LL_WARNS() << "No texture entry for te " << (S32)te << ", object " << mID << LL_ENDL; } else if (shiny != tep->getShiny()) { @@ -4308,7 +5090,7 @@ S32 LLViewerObject::setTEFullbright(const U8 te, const U8 fullbright) const LLTextureEntry *tep = getTE(te); if (!tep) { - llwarns << "No texture entry for te " << (S32)te << ", object " << mID << llendl; + LL_WARNS() << "No texture entry for te " << (S32)te << ", object " << mID << LL_ENDL; } else if (fullbright != tep->getFullbright()) { @@ -4330,7 +5112,7 @@ S32 LLViewerObject::setTEMediaFlags(const U8 te, const U8 media_flags) const LLTextureEntry *tep = getTE(te); if (!tep) { - llwarns << "No texture entry for te " << (S32)te << ", object " << mID << llendl; + LL_WARNS() << "No texture entry for te " << (S32)te << ", object " << mID << LL_ENDL; } else if (media_flags != tep->getMediaFlags()) { @@ -4353,20 +5135,73 @@ S32 LLViewerObject::setTEGlow(const U8 te, const F32 glow) const LLTextureEntry *tep = getTE(te); if (!tep) { - llwarns << "No texture entry for te " << (S32)te << ", object " << mID << llendl; + LL_WARNS() << "No texture entry for te " << (S32)te << ", object " << mID << LL_ENDL; } else if (glow != tep->getGlow()) { - retval = LLPrimitive::setTEGlow(te, glow); - setChanged(TEXTURE); - if (mDrawable.notNull() && retval) - { - gPipeline.markTextured(mDrawable); - } + retval = LLPrimitive::setTEGlow(te, glow); + setChanged(TEXTURE); + if (mDrawable.notNull() && retval) + { + gPipeline.markTextured(mDrawable); + } + } + return retval; +} + +S32 LLViewerObject::setTEMaterialID(const U8 te, const LLMaterialID& pMaterialID) +{ + S32 retval = 0; + const LLTextureEntry *tep = getTE(te); + if (!tep) + { + LL_WARNS("Material") << "No texture entry for te " << (S32)te + << ", object " << mID + << ", material " << pMaterialID + << LL_ENDL; + } + //else if (pMaterialID != tep->getMaterialID()) + { + LL_DEBUGS("Material") << "Changing texture entry for te " << (S32)te + << ", object " << mID + << ", material " << pMaterialID + << LL_ENDL; + retval = LLPrimitive::setTEMaterialID(te, pMaterialID); + refreshMaterials(); + } + return retval; +} + +S32 LLViewerObject::setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams) +{ + S32 retval = 0; + const LLTextureEntry *tep = getTE(te); + if (!tep) + { + LL_WARNS() << "No texture entry for te " << (S32)te << ", object " << mID << LL_ENDL; + return 0; } + + retval = LLPrimitive::setTEMaterialParams(te, pMaterialParams); + LL_DEBUGS("Material") << "Changing material params for te " << (S32)te + << ", object " << mID + << " (" << retval << ")" + << LL_ENDL; + setTENormalMap(te, (pMaterialParams) ? pMaterialParams->getNormalID() : LLUUID::null); + setTESpecularMap(te, (pMaterialParams) ? pMaterialParams->getSpecularID() : LLUUID::null); + + refreshMaterials(); return retval; } +void LLViewerObject::refreshMaterials() +{ + setChanged(TEXTURE); + if (mDrawable.notNull()) + { + gPipeline.markTextured(mDrawable); + } +} S32 LLViewerObject::setTEScale(const U8 te, const F32 s, const F32 t) { @@ -4462,15 +5297,83 @@ LLViewerTexture *LLViewerObject::getTEImage(const U8 face) const } } - llerrs << llformat("Requested Image from invalid face: %d/%d",face,getNumTEs()) << llendl; + LL_ERRS() << llformat("Requested Image from invalid face: %d/%d",face,getNumTEs()) << LL_ENDL; + + return NULL; +} + + +bool LLViewerObject::isImageAlphaBlended(const U8 te) const +{ + LLViewerTexture* image = getTEImage(te); + LLGLenum format = image ? image->getPrimaryFormat() : GL_RGB; + switch (format) + { + case GL_RGBA: + case GL_ALPHA: + { + return true; + } + break; + + case GL_RGB: break; + default: + { + LL_WARNS() << "Unexpected tex format in LLViewerObject::isImageAlphaBlended...returning no alpha." << LL_ENDL; + } + break; + } + + return false; +} + +LLViewerTexture *LLViewerObject::getTENormalMap(const U8 face) const +{ + // llassert(mTEImages); + + if (face < getNumTEs()) + { + LLViewerTexture* image = mTENormalMaps[face]; + if (image) + { + return image; + } + else + { + return (LLViewerTexture*)(LLViewerFetchedTexture::sDefaultImagep); + } + } + + LL_ERRS() << llformat("Requested Image from invalid face: %d/%d",face,getNumTEs()) << LL_ENDL; return NULL; } +LLViewerTexture *LLViewerObject::getTESpecularMap(const U8 face) const +{ + // llassert(mTEImages); + + if (face < getNumTEs()) + { + LLViewerTexture* image = mTESpecularMaps[face]; + if (image) + { + return image; + } + else + { + return (LLViewerTexture*)(LLViewerFetchedTexture::sDefaultImagep); + } + } + + LL_ERRS() << llformat("Requested Image from invalid face: %d/%d",face,getNumTEs()) << LL_ENDL; + + return NULL; +} void LLViewerObject::fitFaceTexture(const U8 face) { - llinfos << "fitFaceTexture not implemented" << llendl; + LL_INFOS() << "fitFaceTexture not implemented" << LL_ENDL; } @@ -4484,7 +5387,7 @@ LLBBox LLViewerObject::getBoundingBoxAgent() const { avatar_parent = (LLViewerObject*)root_edit->getParent(); } - + if (avatar_parent && avatar_parent->isAvatar() && root_edit && root_edit->mDrawable.notNull() && root_edit->mDrawable->getXform()->getParent()) { @@ -4497,7 +5400,7 @@ LLBBox LLViewerObject::getBoundingBoxAgent() const position_agent = getPositionAgent(); rot = getRotationRegion(); } - + return LLBBox( position_agent, rot, getScale() * -0.5f, getScale() * 0.5f ); } @@ -4582,12 +5485,7 @@ void LLViewerObject::setDebugText(const std::string &utf8text) if (!mText) { - mText = (LLHUDText *)LLHUDObject::addHUDObject(LLHUDObject::LL_HUD_TEXT); - mText->setFont(LLFontGL::getFontSansSerif()); - mText->setVertAlignment(LLHUDText::ALIGN_VERT_TOP); - mText->setMaxLines(-1); - mText->setSourceObject(this); - mText->setOnHUDAttachment(isHUDAttachment()); + initHudText(); } mText->setColor(utf8text.empty() ? mHudTextColor : LLColor4::white ); mText->setString(utf8text.empty() ? mHudTextString : utf8text ); @@ -4595,6 +5493,16 @@ void LLViewerObject::setDebugText(const std::string &utf8text) mText->setDoFade(utf8text.empty()); updateText(); } +void LLViewerObject::initHudText() +{ + mText = (LLHUDText *)LLHUDObject::addHUDObject(LLHUDObject::LL_HUD_TEXT); + mText->setFont(LLFontGL::getFontSansSerif()); + mText->setVertAlignment(LLHUDText::ALIGN_VERT_TOP); + mText->setMaxLines(-1); + mText->setSourceObject(this); + mText->setOnHUDAttachment(isHUDAttachment()); +} + // std::string LLViewerObject::getDebugText() { @@ -4628,8 +5536,8 @@ void LLViewerObject::clearIcon() } } -LLViewerObject* LLViewerObject::getSubParent() -{ +LLViewerObject* LLViewerObject::getSubParent() +{ return (LLViewerObject*) getParent(); } @@ -4649,10 +5557,16 @@ void LLViewerObject::updateText() if (!isDead()) { if (mText.notNull()) - { + { + //LLVOAvatar* avatar = getAvatar(); + //if (avatar) + //{ + // mText->setHidden(avatar->isInMuteList()); + //} + LLVector3 up_offset(0,0,0); up_offset.mV[2] = getScale().mV[VZ]*0.6f; - + if (mDrawable.notNull()) { mText->setPositionAgent(getRenderPosition() + up_offset); @@ -4670,6 +5584,34 @@ LLVOAvatar* LLViewerObject::asAvatar() return NULL; } +// virtual +LLVOVolume* LLViewerObject::asVolume() +{ + return nullptr; +} + +// If this object is directly or indirectly parented by an avatar, +// return it. Normally getAvatar() is the correct function to call; +// it will give the avatar used for skinning. The exception is with +// animated objects that are also attachments; in that case, +// getAvatar() will return the control avatar, used for skinning, and +// getAvatarAncestor will return the avatar to which the object is +// attached. +LLVOAvatar* LLViewerObject::getAvatarAncestor() +{ + LLViewerObject *pobj = (LLViewerObject*) getParent(); + while (pobj) + { + LLVOAvatar *av = pobj->asAvatar(); + if (av) + { + return av; + } + pobj = (LLViewerObject*) pobj->getParent(); + } + return NULL; +} + BOOL LLViewerObject::isParticleSource() const { return !mPartSourcep.isNull() && !mPartSourcep->isDead(); @@ -4684,7 +5626,7 @@ void LLViewerObject::setParticleSource(const LLPartSysData& particle_parameters, LLPointer pss = LLViewerPartSourceScript::createPSS(this, particle_parameters); mPartSourcep = pss; - + if (mPartSourcep) { mPartSourcep->setOwnerUUID(owner_id); @@ -4730,7 +5672,7 @@ void LLViewerObject::unpackParticleSource(const S32 block_num, const LLUUID& own // We need to be able to deal with a particle source that hasn't changed, but still got an update! if (pss) { -// llinfos << "Making particle system with owner " << owner_id << llendl; +// LL_INFOS() << "Making particle system with owner " << owner_id << LL_ENDL; pss->setOwnerUUID(owner_id); mPartSourcep = pss; LLViewerPartSim::getInstance()->addPartSource(pss); @@ -4754,7 +5696,7 @@ void LLViewerObject::unpackParticleSource(const S32 block_num, const LLUUID& own } } -void LLViewerObject::unpackParticleSource(LLDataPacker &dp, const LLUUID& owner_id) +void LLViewerObject::unpackParticleSource(LLDataPacker &dp, const LLUUID& owner_id, bool legacy) { if (!mPartSourcep.isNull() && mPartSourcep->isDead()) { @@ -4763,7 +5705,7 @@ void LLViewerObject::unpackParticleSource(LLDataPacker &dp, const LLUUID& owner_ if (mPartSourcep) { // If we've got one already, just update the existing source (or remove it) - if (!LLViewerPartSourceScript::unpackPSS(this, mPartSourcep, dp)) + if (!LLViewerPartSourceScript::unpackPSS(this, mPartSourcep, dp, legacy)) { mPartSourcep->setDead(); mPartSourcep = NULL; @@ -4771,13 +5713,13 @@ void LLViewerObject::unpackParticleSource(LLDataPacker &dp, const LLUUID& owner_ } else { - LLPointer pss = LLViewerPartSourceScript::unpackPSS(this, NULL, dp); + LLPointer pss = LLViewerPartSourceScript::unpackPSS(this, NULL, dp, legacy); //If the owner is muted, don't create the system if(LLMuteList::getInstance()->isMuted(owner_id, LLMute::flagParticles)) return; // We need to be able to deal with a particle source that hasn't changed, but still got an update! if (pss) { -// llinfos << "Making particle system with owner " << owner_id << llendl; +// LL_INFOS() << "Making particle system with owner " << owner_id << LL_ENDL; pss->setOwnerUUID(owner_id); mPartSourcep = pss; LLViewerPartSim::getInstance()->addPartSource(pss); @@ -4816,20 +5758,20 @@ void LLViewerObject::updateDrawable(BOOL force_damped) if (!isChanged(MOVED)) { //most common case, having an empty if case here makes for better branch prediction } - else if (mDrawable.notNull() && + else if (mDrawable.notNull() && !mDrawable->isState(LLDrawable::ON_MOVE_LIST)) { - BOOL damped_motion = + BOOL damped_motion = !isChanged(SHIFTED) && // not shifted between regions this frame and... ( force_damped || // ...forced into damped motion by application logic or... ( !isSelected() && // ...not selected and... ( mDrawable->isRoot() || // ... is root or ... (getParent() && !((LLViewerObject*)getParent())->isSelected())// ... parent is not selected and ... - ) && + ) && getPCode() == LL_PCODE_VOLUME && // ...is a volume object and... getVelocity().isExactlyZero() && // ...is not moving physically and... mDrawable->getGeneration() != -1 // ...was not created this frame. - ) + ) ); gPipeline.markMoved(mDrawable, damped_motion); } @@ -4848,10 +5790,10 @@ void LLViewerObject::setAttachedSound(const LLUUID &audio_uuid, const LLUUID& ow { return; } - + if (audio_uuid.isNull()) { - if (!mAudioSourcep) + if (!mAudioSourcep || (flags & LL_SOUND_FLAG_STOP && !mAudioSourcep->isLoop())) { return; } @@ -4861,12 +5803,12 @@ void LLViewerObject::setAttachedSound(const LLUUID &audio_uuid, const LLUUID& ow // At least, this appears to be how the scripts work. // The attached sound ID is set to NULL to avoid it playing back when the // object rezzes in on non-looping sounds. - //llinfos << "Clearing attached sound " << mAudioSourcep->getCurrentData()->getID() << llendl; + //LL_INFOS() << "Clearing attached sound " << mAudioSourcep->getCurrentData()->getID() << LL_ENDL; gAudiop->cleanupAudioSource(mAudioSourcep); mAudioSourcep = NULL; } else if (flags & LL_SOUND_FLAG_STOP) - { + { // Just shut off the sound mAudioSourcep->play(LLUUID::null); } @@ -4876,21 +5818,21 @@ void LLViewerObject::setAttachedSound(const LLUUID &audio_uuid, const LLUUID& ow && mAudioSourcep && mAudioSourcep->isLoop() && mAudioSourcep->getCurrentData() && mAudioSourcep->getCurrentData()->getID() == audio_uuid) { - //llinfos << "Already playing this sound on a loop, ignoring" << llendl; + //LL_INFOS() << "Already playing this sound on a loop, ignoring" << LL_ENDL; return; } // don't clean up before previous sound is done. Solves: SL-33486 - if ( mAudioSourcep && mAudioSourcep->isDone() ) + if ( mAudioSourcep && mAudioSourcep->isDone() ) { gAudiop->cleanupAudioSource(mAudioSourcep); mAudioSourcep = NULL; } if (mAudioSourcep && mAudioSourcep->isMuted() && - mAudioSourcep->getCurrentData() && mAudioSourcep->getCurrentData()->getID() == audio_uuid) + mAudioSourcep->getCurrentData() && mAudioSourcep->getCurrentData()->getID() == audio_uuid) { - //llinfos << "Already having this sound as muted sound, ignoring" << llendl; + //LL_INFOS() << "Already having this sound as muted sound, ignoring" << LL_ENDL; return; } @@ -4905,15 +5847,11 @@ void LLViewerObject::setAttachedSound(const LLUUID &audio_uuid, const LLUUID& ow mAudioSourcep->setSyncMaster(flags & LL_SOUND_FLAG_SYNC_MASTER); mAudioSourcep->setSyncSlave(flags & LL_SOUND_FLAG_SYNC_SLAVE); mAudioSourcep->setQueueSounds(queue); - if(!queue) // stop any current sound first to avoid "farts of doom" (SL-1541) -MG - { - mAudioSourcep->play(LLUUID::null); - } - + // Play this sound if region maturity permits if( gAgent.canAccessMaturityAtGlobal(this->getPositionGlobal()) ) { - //llinfos << "Playing attached sound " << audio_uuid << llendl; + //LL_INFOS() << "Playing attached sound " << audio_uuid << LL_ENDL; mAudioSourcep->play(audio_uuid); } } @@ -4959,7 +5897,7 @@ bool LLViewerObject::unpackParameterEntry(U16 param_type, LLDataPacker *dp) if (param) { param->data->unpack(*dp); - param->in_use = TRUE; + *param->in_use = TRUE; parameterChanged(param_type, param->data, TRUE, false); return true; } @@ -4972,90 +5910,59 @@ bool LLViewerObject::unpackParameterEntry(U16 param_type, LLDataPacker *dp) LLViewerObject::ExtraParameter* LLViewerObject::createNewParameterEntry(U16 param_type) { LLNetworkData* new_block = NULL; + bool* in_use = NULL; switch (param_type) { - case LLNetworkData::PARAMS_FLEXIBLE: - { - new_block = new LLFlexibleObjectData(); - break; - } - case LLNetworkData::PARAMS_LIGHT: - { - new_block = new LLLightParams(); - break; - } - case LLNetworkData::PARAMS_SCULPT: - { - new_block = new LLSculptParams(); - break; - } - case LLNetworkData::PARAMS_LIGHT_IMAGE: - { - new_block = new LLLightImageParams(); - break; - } - default: - { - llinfos << "Unknown param type. (" << llformat("0x%2x",param_type) << ")" << llendl; - break; - } + case LLNetworkData::PARAMS_FLEXIBLE: + { + new_block = &mFlexibleObjectData; + in_use = &mFlexibleObjectDataInUse; + break; + } + case LLNetworkData::PARAMS_LIGHT: + { + new_block = &mLightParams; + in_use = &mLightParamsInUse; + break; + } + case LLNetworkData::PARAMS_SCULPT: + { + new_block = &mSculptParams; + in_use = &mSculptParamsInUse; + break; + } + case LLNetworkData::PARAMS_LIGHT_IMAGE: + { + new_block = &mLightImageParams; + in_use = &mLightImageParamsInUse; + break; + } + case LLNetworkData::PARAMS_EXTENDED_MESH: + { + new_block = &mExtendedMeshParams; + in_use = &mExtendedMeshParamsInUse; + break; + } + default: + { + LL_INFOS() << "Unknown param type. (" << llformat("0x%2x", param_type) << ")" << LL_ENDL; + break; + } }; + ExtraParameter& entry = mExtraParameterList[U32(param_type >> 4) - 1]; if (new_block) { - ExtraParameter* new_entry = new ExtraParameter; - new_entry->data = new_block; - new_entry->in_use = false; // not in use yet - mExtraParameterList[param_type] = new_entry; - return new_entry; - } - return NULL; -} - -LLViewerObject::ExtraParameter* LLViewerObject::getExtraParameterEntry(U16 param_type) const -{ - std::map::const_iterator itor = mExtraParameterList.find(param_type); - if (itor != mExtraParameterList.end()) - { - return itor->second; - } - return NULL; -} - -LLViewerObject::ExtraParameter* LLViewerObject::getExtraParameterEntryCreate(U16 param_type) -{ - ExtraParameter* param = getExtraParameterEntry(param_type); - if (!param) - { - param = createNewParameterEntry(param_type); - } - return param; -} - -LLNetworkData* LLViewerObject::getParameterEntry(U16 param_type) const -{ - ExtraParameter* param = getExtraParameterEntry(param_type); - if (param) - { - return param->data; - } - else - { - return NULL; - } -} - -BOOL LLViewerObject::getParameterEntryInUse(U16 param_type) const -{ - ExtraParameter* param = getExtraParameterEntry(param_type); - if (param) - { - return param->in_use; + entry.in_use = in_use; + *entry.in_use = false; // not in use yet + entry.data = new_block; + return &entry; } else { - return FALSE; + entry.is_invalid = true; } + return NULL; } bool LLViewerObject::setParameterEntry(U16 param_type, const LLNetworkData& new_value, bool local_origin) @@ -5063,11 +5970,11 @@ bool LLViewerObject::setParameterEntry(U16 param_type, const LLNetworkData& new_ ExtraParameter* param = getExtraParameterEntryCreate(param_type); if (param) { - if (param->in_use && new_value == *(param->data)) + if (*(param->in_use) && new_value == *(param->data)) { return false; } - param->in_use = true; + *param->in_use = true; param->data->copy(new_value); parameterChanged(param_type, param->data, TRUE, local_origin); return true; @@ -5083,22 +5990,28 @@ bool LLViewerObject::setParameterEntry(U16 param_type, const LLNetworkData& new_ // Should always return true. bool LLViewerObject::setParameterEntryInUse(U16 param_type, BOOL in_use, bool local_origin) { - ExtraParameter* param = getExtraParameterEntryCreate(param_type); - if (param && param->in_use != in_use) + if (param_type <= LLNetworkData::PARAMS_MAX) { - param->in_use = in_use; - parameterChanged(param_type, param->data, in_use, local_origin); - return true; + ExtraParameter* param = (in_use ? getExtraParameterEntryCreate(param_type) : &getExtraParameterEntry(param_type)); + if (param && param->data && *param->in_use != (bool)in_use) + { + *param->in_use = in_use; + parameterChanged(param_type, param->data, in_use, local_origin); + return true; + } } return false; } void LLViewerObject::parameterChanged(U16 param_type, bool local_origin) { - ExtraParameter* param = getExtraParameterEntry(param_type); - if (param) + if (param_type <= LLNetworkData::PARAMS_MAX) { - parameterChanged(param_type, param->data, param->in_use, local_origin); + const ExtraParameter& param = getExtraParameterEntry(param_type); + if (param.data) + { + parameterChanged(param_type, param.data, *param.in_use, local_origin); + } } } @@ -5134,7 +6047,7 @@ void LLViewerObject::parameterChanged(U16 param_type, LLNetworkData* data, BOOL } else { - llwarns << "Failed to send object extra parameters: " << param_type << llendl; + LL_WARNS() << "Failed to send object extra parameters: " << param_type << LL_ENDL; } } } @@ -5173,25 +6086,45 @@ void LLViewerObject::clearDrawableState(U32 state, BOOL recursive) } } +BOOL LLViewerObject::isDrawableState(U32 state, BOOL recursive) const +{ + BOOL matches = FALSE; + if (mDrawable) + { + matches = mDrawable->isState(state); + } + if (recursive) + { + for (child_list_t::const_iterator iter = mChildList.begin(); + (iter != mChildList.end()) && matches; iter++) + { + LLViewerObject* child = *iter; + matches &= child->isDrawableState(state, recursive); + } + } + + return matches; +} + //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -// RN: these functions assume a 2-level hierarchy +// RN: these functions assume a 2-level hierarchy //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // Owned by anyone? BOOL LLViewerObject::permAnyOwner() const -{ +{ if (isRootEdit()) { - return flagObjectAnyOwner(); + return flagObjectAnyOwner(); } else { return ((LLViewerObject*)getParent())->permAnyOwner(); } -} +} // Owned by this viewer? BOOL LLViewerObject::permYouOwner() const -{ +{ if (isRootEdit()) { #ifdef HACKED_GODLIKE_VIEWER @@ -5199,12 +6132,12 @@ BOOL LLViewerObject::permYouOwner() const #else # ifdef TOGGLE_HACKED_GODLIKE_VIEWER if (!LLViewerLogin::getInstance()->isInProductionGrid() - && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) + && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) { return TRUE; } # endif - return flagObjectYouOwner(); + return flagObjectYouOwner(); #endif } else @@ -5214,11 +6147,11 @@ BOOL LLViewerObject::permYouOwner() const } // Owned by a group? -BOOL LLViewerObject::permGroupOwner() const -{ +BOOL LLViewerObject::permGroupOwner() const +{ if (isRootEdit()) { - return flagObjectGroupOwned(); + return flagObjectGroupOwned(); } else { @@ -5228,7 +6161,7 @@ BOOL LLViewerObject::permGroupOwner() const // Can the owner edit BOOL LLViewerObject::permOwnerModify() const -{ +{ if (isRootEdit()) { #ifdef HACKED_GODLIKE_VIEWER @@ -5236,12 +6169,12 @@ BOOL LLViewerObject::permOwnerModify() const #else # ifdef TOGGLE_HACKED_GODLIKE_VIEWER if (!LLViewerLogin::getInstance()->isInProductionGrid() - && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) + && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) { return TRUE; } # endif - return flagObjectOwnerModify(); + return flagObjectOwnerModify(); #endif } else @@ -5252,7 +6185,7 @@ BOOL LLViewerObject::permOwnerModify() const // Can edit BOOL LLViewerObject::permModify() const -{ +{ if (isRootEdit()) { #ifdef HACKED_GODLIKE_VIEWER @@ -5260,12 +6193,12 @@ BOOL LLViewerObject::permModify() const #else # ifdef TOGGLE_HACKED_GODLIKE_VIEWER if (!LLViewerLogin::getInstance()->isInProductionGrid() - && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) + && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) { return TRUE; } # endif - return flagObjectModify(); + return flagObjectModify(); #endif } else @@ -5276,7 +6209,7 @@ BOOL LLViewerObject::permModify() const // Can copy BOOL LLViewerObject::permCopy() const -{ +{ if (isRootEdit()) { #ifdef HACKED_GODLIKE_VIEWER @@ -5284,7 +6217,7 @@ BOOL LLViewerObject::permCopy() const #else # ifdef TOGGLE_HACKED_GODLIKE_VIEWER if (!LLViewerLogin::getInstance()->isInProductionGrid() - && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) + && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) { return TRUE; } @@ -5308,12 +6241,12 @@ BOOL LLViewerObject::permMove() const #else # ifdef TOGGLE_HACKED_GODLIKE_VIEWER if (!LLViewerLogin::getInstance()->isInProductionGrid() - && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) + && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) { return TRUE; } # endif - return flagObjectMove(); + return flagObjectMove(); #endif } else @@ -5324,7 +6257,7 @@ BOOL LLViewerObject::permMove() const // Can be transferred BOOL LLViewerObject::permTransfer() const -{ +{ if (isRootEdit()) { #ifdef HACKED_GODLIKE_VIEWER @@ -5332,12 +6265,12 @@ BOOL LLViewerObject::permTransfer() const #else # ifdef TOGGLE_HACKED_GODLIKE_VIEWER if (!LLViewerLogin::getInstance()->isInProductionGrid() - && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) + && (gAgent.getGodLevel() >= GOD_MAINTENANCE)) { return TRUE; } # endif - return flagObjectTransfer(); + return flagObjectTransfer(); #endif } else @@ -5374,6 +6307,17 @@ void LLViewerObject::updateVolume(const LLVolumeParams& volume_params) } } +void LLViewerObject::recursiveMarkForUpdate(BOOL priority) +{ + for (LLViewerObject::child_list_t::iterator iter = mChildList.begin(); + iter != mChildList.end(); iter++) + { + LLViewerObject* child = *iter; + child->markForUpdate(priority); + } + markForUpdate(priority); +} + void LLViewerObject::markForUpdate(BOOL priority) { if (mDrawable.notNull()) @@ -5383,6 +6327,15 @@ void LLViewerObject::markForUpdate(BOOL priority) } } + +void LLViewerObject::markForUnload(BOOL priority) +{ + if (mDrawable.notNull()) + { + gPipeline.markRebuild(mDrawable, LLDrawable::FOR_UNLOAD, priority); + } +} + bool LLViewerObject::isPermanentEnforced() const { return flagObjectPermanent() && (mRegionp != gAgent.getRegion()) && !gAgent.isGodlike(); @@ -5402,9 +6355,20 @@ void LLViewerObject::setRegion(LLViewerRegion *regionp) { if (!regionp) { - llwarns << "viewer object set region to NULL" << llendl; + LL_WARNS() << "viewer object set region to NULL" << LL_ENDL; } - + if(regionp != mRegionp) + { + if(mRegionp) + { + mRegionp->removeFromCreatedList(getLocalID()); + } + if(regionp) + { + regionp->addToCreatedList(getLocalID()); + } + } + mLatestRecvPacketID = 0; mRegionp = regionp; @@ -5414,10 +6378,29 @@ void LLViewerObject::setRegion(LLViewerRegion *regionp) child->setRegion(regionp); } + if (mControlAvatar) + { + mControlAvatar->setRegion(regionp); + } + setChanged(MOVED | SILHOUETTE); updateDrawable(FALSE); } +// virtual +void LLViewerObject::updateRegion(LLViewerRegion *regionp) +{ +// if (regionp) +// { +// F64 now = LLFrameTimer::getElapsedSeconds(); +// LL_INFOS() << "Updating to region " << regionp->getName() +// << ", ms since last update message: " << (F32)((now - mLastMessageUpdateSecs) * 1000.0) +// << ", ms since last interpolation: " << (F32)((now - mLastInterpUpdateSecs) * 1000.0) +// << LL_ENDL; +// } +} + + bool LLViewerObject::specialHoverCursor() const { return flagUsePhysics() @@ -5521,13 +6504,13 @@ void LLViewerObject::setPhysicsRestitution(F32 restitution) } U8 LLViewerObject::getPhysicsShapeType() const -{ +{ if (mPhysicsShapeUnknown) { gObjectList.updatePhysicsFlags(this); } - return mPhysicsShapeType; + return mPhysicsShapeType; } void LLViewerObject::applyAngularVelocity(F32 dt) @@ -5544,7 +6527,7 @@ void LLViewerObject::applyAngularVelocity(F32 dt) angle = omega * dt; ang_vel *= 1.f/omega; - + // calculate the delta increment based on the object's angular velocity dQ.setQuat(angle, ang_vel); @@ -5554,7 +6537,7 @@ void LLViewerObject::applyAngularVelocity(F32 dt) // accumulate the angular velocity rotations to re-apply in the case of an object update mAngularVelocityRot *= dQ; } - + // Just apply the delta increment to the current rotation setRotation(getRotation()*dQ); setChanged(MOVED | SILHOUETTE); @@ -5573,25 +6556,9 @@ void LLViewerObject::resetRot() } } -//virtual -void LLViewerObject::setSelected(BOOL sel) -{ - mUserSelected = sel; - - static const LLCachedControl use_new_target_omega ("UseNewTargetOmegaCode", true); - if(use_new_target_omega) - { - resetRot(); - } - else - { - mRotTime = 0.f; - } -} - U32 LLViewerObject::getPartitionType() const -{ - return LLViewerRegion::PARTITION_NONE; +{ + return LLViewerRegion::PARTITION_NONE; } void LLViewerObject::dirtySpatialGroup(BOOL priority) const @@ -5625,6 +6592,11 @@ F32 LLAlphaObject::getPartSize(S32 idx) return 0.f; } +void LLAlphaObject::getBlendFunc(S32 face, U32& src, U32& dst) +{ + +} + // virtual void LLStaticViewerObject::updateDrawable(BOOL force_damped) { @@ -5650,7 +6622,7 @@ void LLViewerObject::saveUnselectedChildrenPosition(std::vector& posi LLViewerObject* childp = *iter; if (!childp->isSelected() && childp->mDrawable.notNull()) { - positions.push_back(childp->getPositionEdit()); + positions.push_back(childp->getPositionEdit()); } } @@ -5670,15 +6642,15 @@ void LLViewerObject::saveUnselectedChildrenRotation(std::vector& r LLViewerObject* childp = *iter; if (!childp->isSelected() && childp->mDrawable.notNull()) { - rotations.push_back(childp->getRotationEdit()); - } + rotations.push_back(childp->getRotationEdit()); + } } return ; } //counter-rotation -void LLViewerObject::resetChildrenRotationAndPosition(const std::vector& rotations, +void LLViewerObject::resetChildrenRotationAndPosition(const std::vector& rotations, const std::vector& positions) { if(mChildList.empty()) @@ -5699,30 +6671,30 @@ void LLViewerObject::resetChildrenRotationAndPosition(const std::vectorsetRotation(rotations[index] * inv_rotation); childp->setPosition((positions[index] - offset) * inv_rotation); - LLManip::rebuild(childp); + LLManip::rebuild(childp); } else //avatar { LLVector3 reset_pos = (positions[index] - offset) * inv_rotation ; LLQuaternion reset_rot = rotations[index] * inv_rotation ; - ((LLVOAvatar*)childp)->mDrawable->mXform.setPosition(reset_pos); + ((LLVOAvatar*)childp)->mDrawable->mXform.setPosition(reset_pos); ((LLVOAvatar*)childp)->mDrawable->mXform.setRotation(reset_rot) ; - - ((LLVOAvatar*)childp)->mDrawable->getVObj()->setPosition(reset_pos, TRUE); + + ((LLVOAvatar*)childp)->mDrawable->getVObj()->setPosition(reset_pos, TRUE); ((LLVOAvatar*)childp)->mDrawable->getVObj()->setRotation(reset_rot, TRUE) ; - LLManip::rebuild(childp); - } + LLManip::rebuild(childp); + } index++; - } + } } return ; } //counter-translation -void LLViewerObject::resetChildrenPosition(const LLVector3& offset, BOOL simplified) +void LLViewerObject::resetChildrenPosition(const LLVector3& offset, BOOL simplified, BOOL skip_avatar_child) { if(mChildList.empty()) { @@ -5761,24 +6733,31 @@ void LLViewerObject::resetChildrenPosition(const LLVector3& offset, BOOL simplif } else //avatar { - LLVector3 reset_pos = ((LLVOAvatar*)childp)->mDrawable->mXform.getPosition() + child_offset ; + if(!skip_avatar_child) + { + LLVector3 reset_pos = ((LLVOAvatar*)childp)->mDrawable->mXform.getPosition() + child_offset ; - ((LLVOAvatar*)childp)->mDrawable->mXform.setPosition(reset_pos); - ((LLVOAvatar*)childp)->mDrawable->getVObj()->setPosition(reset_pos); - - LLManip::rebuild(childp); - } - } + ((LLVOAvatar*)childp)->mDrawable->mXform.setPosition(reset_pos); + ((LLVOAvatar*)childp)->mDrawable->getVObj()->setPosition(reset_pos); + LLManip::rebuild(childp); + } + } + } } return ; } +// virtual +BOOL LLViewerObject::isTempAttachment() const +{ + return (mID.notNull() && (mID == mAttachmentItemID)); +} // std::string LLViewerObject::getAttachmentPointName() { - S32 point = ATTACHMENT_ID_FROM_STATE(mState); + S32 point = ATTACHMENT_ID_FROM_STATE(mAttachmentState); LLVOAvatar::attachment_map_t::iterator it = gAgentAvatarp->mAttachmentPoints.find(point); if(it != gAgentAvatarp->mAttachmentPoints.end()) { @@ -5837,6 +6816,10 @@ const LLUUID &LLViewerObject::extractAttachmentItemID() //virtual LLVOAvatar* LLViewerObject::getAvatar() const { + if (getControlAvatar()) + { + return getControlAvatar(); + } if (isAttachment()) { LLViewerObject* vobj = (LLViewerObject*) getParent(); @@ -5863,7 +6846,7 @@ class ObjectPhysicsProperties : public LLHTTPNode { LLSD object_data = input["body"]["ObjectData"]; S32 num_entries = object_data.size(); - + for ( S32 i = 0; i < num_entries; i++ ) { LLSD& curr_object_data = object_data[i]; @@ -5896,9 +6879,9 @@ class ObjectPhysicsProperties : public LLHTTPNode node->getObject()->setPhysicsFriction(friction); node->getObject()->setPhysicsDensity(density); node->getObject()->setPhysicsRestitution(restitution); - } + } } - + dialog_refresh_all(); }; }; diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index 5935942b62..e95b25c42a 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -54,27 +54,31 @@ class LLAgent; // TODO: Get rid of this. class LLAudioSource; class LLAudioSourceVO; class LLBBox; -class LLDataPacker; class LLColor4; -class LLFrameTimer; +class LLControlAvatar; +class LLDataPacker; class LLDrawable; +class LLFrameTimer; class LLHost; -class LLWorld; +class LLMessageSystem; class LLNameValue; class LLNetMap; -class LLMessageSystem; class LLPartSysData; -class LLPrimitive; class LLPipeline; +class LLPrimitive; class LLTextureEntry; -class LLViewerTexture; +class LLVOAvatar; +class LLVOInventoryListener; +class LLVOVolume; class LLViewerInventoryItem; class LLViewerObject; +class LLViewerObjectMedia; class LLViewerPartSourceScript; class LLViewerRegion; -class LLViewerObjectMedia; -class LLVOInventoryListener; -class LLVOAvatar; +class LLViewerTexture; +class LLWorld; + +class LLMeshCostData; typedef enum e_object_update_type { @@ -112,18 +116,32 @@ struct PotentialReturnableObject //============================================================================ -class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate +class LLViewerObject +: public LLPrimitive, + public LLRefCount, + public LLGLUpdate { protected: ~LLViewerObject(); // use unref() - // TomY: Provide for a list of extra parameter structures, mapped by structure name +private: struct ExtraParameter { - BOOL in_use; - LLNetworkData *data; + bool is_invalid = false; + bool* in_use = nullptr; + LLNetworkData* data = nullptr; }; - std::map mExtraParameterList; + std::vector mExtraParameterList; + bool mFlexibleObjectDataInUse = false; + bool mLightParamsInUse = false; + bool mSculptParamsInUse = false; + bool mLightImageParamsInUse = false; + bool mExtendedMeshParamsInUse = false; + LLFlexibleObjectData mFlexibleObjectData; + LLLightParams mLightParams; + LLSculptParams mSculptParams; + LLLightImageParams mLightImageParams; + LLExtendedMeshParams mExtendedMeshParams; public: typedef std::list > child_list_t; @@ -133,12 +151,16 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate LLViewerObject(const LLUUID &id, const LLPCode type, LLViewerRegion *regionp, BOOL is_global = FALSE); + virtual void resetVertexBuffers() {} virtual void markDead(); // Mark this object as dead, and clean up its references BOOL isDead() const {return mDead;} BOOL isOrphaned() const { return mOrphaned; } BOOL isParticleSource() const; virtual LLVOAvatar* asAvatar(); + virtual LLVOVolume* asVolume(); + + LLVOAvatar* getAvatarAncestor(); static void initVOClasses(); static void cleanupVOClasses(); @@ -162,12 +184,15 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate INVALID_UPDATE = 0x80000000 }; + static U32 extractSpatialExtents(LLDataPackerBinaryBuffer *dp, LLVector3& pos, LLVector3& scale, LLQuaternion& rot); virtual U32 processUpdateMessage(LLMessageSystem *mesgsys, void **user_data, U32 block_num, const EObjectUpdateType update_type, LLDataPacker *dp); + void processTerseData(LLMessageSystem *mesgsys, void **user_data, U32 block_num, S32& this_update_precision, LLVector3& new_pos_parent, LLQuaternion& new_rot, LLVector3& new_angv, LLVector3& test_pos_parent); + virtual BOOL isActive() const; // Whether this object needs to do an idleUpdate. BOOL onActiveList() const {return mOnActiveList;} @@ -176,6 +201,7 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate virtual BOOL isAttachment() const { return FALSE; } virtual LLVOAvatar* getAvatar() const; //get the avatar this object is attached to, or NULL if object is not an attachment virtual BOOL isHUDAttachment() const { return FALSE; } + virtual BOOL isTempAttachment() const; virtual void updateRadius() {}; virtual F32 getVObjRadius() const; // default implemenation is mDrawable->getRadius() @@ -213,6 +239,7 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate LLViewerRegion* getRegion() const { return mRegionp; } BOOL isSelected() const { return mUserSelected; } + BOOL isAnySelected() const; void setSelected(BOOL sel); const LLUUID &getID() const { return mID; } @@ -224,6 +251,8 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate virtual BOOL isFlexible() const { return FALSE; } virtual BOOL isSculpted() const { return FALSE; } virtual BOOL isMesh() const { return FALSE; } + virtual BOOL isRiggedMesh() const { return FALSE; } + virtual BOOL hasLightTexture() const { return FALSE; } // This method returns true if the object is over land owned by // the agent, one of its groups, or it encroaches and @@ -247,6 +276,8 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate */ virtual BOOL setParent(LLViewerObject* parent); + virtual void onReparent(LLViewerObject *old_parent, LLViewerObject *new_parent); + virtual void afterReparent(); virtual void addChild(LLViewerObject *childp); virtual void removeChild(LLViewerObject *childp); const_child_list_t& getChildren() const { return mChildList; } @@ -262,17 +293,18 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate //detect if given line segment (in agent space) intersects with this viewer object. //returns TRUE if intersection detected and returns information about intersection - virtual BOOL lineSegmentIntersect(const LLVector3& start, const LLVector3& end, + virtual BOOL lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, S32 face = -1, // which face to check, -1 = ALL_SIDES BOOL pick_transparent = FALSE, + BOOL pick_rigged = FALSE, S32* face_hit = NULL, // which face was hit - LLVector3* intersection = NULL, // return the intersection point + LLVector4a* intersection = NULL, // return the intersection point LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point - LLVector3* normal = NULL, // return the surface normal at the intersection point - LLVector3* bi_normal = NULL // return the surface bi-normal at the intersection point + LLVector4a* normal = NULL, // return the surface normal at the intersection point + LLVector4a* tangent = NULL // return the surface tangent at the intersection point ); - virtual BOOL lineSegmentBoundingBox(const LLVector3& start, const LLVector3& end); + virtual BOOL lineSegmentBoundingBox(const LLVector4a& start, const LLVector4a& end); virtual const LLVector3d getPositionGlobal() const; virtual const LLVector3 &getPositionRegion() const; @@ -287,7 +319,7 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate const LLQuaternion getRotationRegion() const; const LLQuaternion getRotationEdit() const; const LLQuaternion getRenderRotation() const; - virtual const LLMatrix4 getRenderMatrix() const; + virtual const LLMatrix4a& getRenderMatrix() const; void setPosition(const LLVector3 &pos, BOOL damped = FALSE); void setPositionGlobal(const LLVector3d &position, BOOL damped = FALSE); @@ -297,7 +329,7 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate void setPositionParent(const LLVector3 &pos_parent, BOOL damped = FALSE); void setPositionAbsoluteGlobal( const LLVector3d &pos_global, BOOL damped = FALSE ); - virtual const LLMatrix4& getWorldMatrix(LLXformMatrix* xform) const { return xform->getWorldMatrix(); } + virtual const LLMatrix4a& getWorldMatrix(LLXformMatrix* xform) const { return xform->getWorldMatrix(); } inline void setRotation(const F32 x, const F32 y, const F32 z, BOOL damped = FALSE); inline void setRotation(const LLQuaternion& quat, BOOL damped = FALSE); @@ -306,7 +338,11 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate /*virtual*/ void setNumTEs(const U8 num_tes); /*virtual*/ void setTE(const U8 te, const LLTextureEntry &texture_entry); /*virtual*/ S32 setTETexture(const U8 te, const LLUUID &uuid); - S32 setTETextureCore(const U8 te, LLViewerTexture *image); + /*virtual*/ S32 setTENormalMap(const U8 te, const LLUUID &uuid); + /*virtual*/ S32 setTESpecularMap(const U8 te, const LLUUID &uuid); + S32 setTETextureCore(const U8 te, LLViewerTexture *image); + S32 setTENormalMapCore(const U8 te, LLViewerTexture *image); + S32 setTESpecularMapCore(const U8 te, LLViewerTexture *image); /*virtual*/ S32 setTEColor(const U8 te, const LLColor3 &color); /*virtual*/ S32 setTEColor(const U8 te, const LLColor4 &color); /*virtual*/ S32 setTEScale(const U8 te, const F32 s, const F32 t); @@ -323,19 +359,41 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate /*virtual*/ S32 setTEFullbright(const U8 te, const U8 fullbright ); /*virtual*/ S32 setTEMediaFlags(const U8 te, const U8 media_flags ); /*virtual*/ S32 setTEGlow(const U8 te, const F32 glow); + /*virtual*/ S32 setTEMaterialID(const U8 te, const LLMaterialID& pMaterialID); + /*virtual*/ S32 setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams); + + // Used by Materials update functions to properly kick off rebuilds + // of VBs etc when materials updates require changes. + // + void refreshMaterials(); + /*virtual*/ BOOL setMaterial(const U8 material); virtual void setTEImage(const U8 te, LLViewerTexture *imagep); // Not derived from LLPrimitive - virtual void changeTEImage(S32 index, LLViewerTexture* new_image) ; + virtual void changeTEImage(S32 index, LLViewerTexture* new_image) ; + virtual void changeTENormalMap(S32 index, LLViewerTexture* new_image) ; + virtual void changeTESpecularMap(S32 index, LLViewerTexture* new_image) ; LLViewerTexture *getTEImage(const U8 te) const; + LLViewerTexture *getTENormalMap(const U8 te) const; + LLViewerTexture *getTESpecularMap(const U8 te) const; + bool isImageAlphaBlended(const U8 te) const; + void fitFaceTexture(const U8 face); void sendTEUpdate() const; // Sends packed representation of all texture entry information virtual void setScale(const LLVector3 &scale, BOOL damped = FALSE); - virtual F32 getStreamingCost(S32* bytes = NULL, S32* visible_bytes = NULL, F32* unscaled_value = NULL) const; + S32 getAnimatedObjectMaxTris() const; + F32 recursiveGetEstTrianglesMax() const; + virtual F32 getEstTrianglesMax() const; + virtual F32 getEstTrianglesStreamingCost() const; + virtual F32 getStreamingCost() const; + virtual bool getCostData(LLMeshCostData& costs) const; virtual U32 getTriangleCount(S32* vcount = NULL) const; virtual U32 getHighLODTriangleCount(); + F32 recursiveGetScaledSurfaceArea() const; + + U32 recursiveGetTriangleCount(S32* vcount = NULL) const; void setObjectCost(F32 cost); F32 getObjectCost(); @@ -353,7 +411,7 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate // U8 getState() { return mState; } // [RLVa:KB] - Checked: 2010-09-26 (RLVa-1.3.0a) | Added: RLVa-1.3.0a - U8 getState() const { return mState; } + U8 getAttachmentState() const { return mAttachmentState; } // [/RLVa:KB] F32 getAppAngle() const { return mAppAngle; } @@ -386,13 +444,17 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate void setCanSelect(BOOL canSelect); void setDebugText(const std::string &utf8text); + void initHudText(); + // std::string getDebugText(); // void setIcon(LLViewerTexture* icon_image); void clearIcon(); - void markForUpdate(BOOL priority); + void recursiveMarkForUpdate(BOOL priority); + virtual void markForUpdate(BOOL priority); + void markForUnload(BOOL priority); void updateVolume(const LLVolumeParams& volume_params); virtual void updateSpatialExtents(LLVector4a& min, LLVector4a& max); virtual F32 getBinRadius(); @@ -405,6 +467,7 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate void setDrawableState(U32 state, BOOL recursive = TRUE); void clearDrawableState(U32 state, BOOL recursive = TRUE); + BOOL isDrawableState(U32 state, BOOL recursive = TRUE) const; // Called when the drawable shifts virtual void onShift(const LLVector4a &shift_vector) { } @@ -419,10 +482,10 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate // viewer object has the inventory stored locally. void registerInventoryListener(LLVOInventoryListener* listener, void* user_data); void removeInventoryListener(LLVOInventoryListener* listener); - BOOL isInventoryPending() { return mInventoryPending; } + BOOL isInventoryPending(); void clearInventoryListeners(); + bool hasInventoryListeners(); void requestInventory(); - void fetchInventoryFromServer(); static void processTaskInv(LLMessageSystem* msg, void** user_data); void removeInventory(const LLUUID& item_id); @@ -495,6 +558,7 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate inline BOOL flagCameraSource() const { return ((mFlags & FLAGS_CAMERA_SOURCE) != 0); } inline BOOL flagCameraDecoupled() const { return ((mFlags & FLAGS_CAMERA_DECOUPLED) != 0); } + inline bool getPhysicsShapeUnknown() const { return mPhysicsShapeUnknown; } U8 getPhysicsShapeType() const; inline F32 getPhysicsGravity() const { return mPhysicsGravity; } inline F32 getPhysicsFriction() const { return mPhysicsFriction; } @@ -514,9 +578,10 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate bool specialHoverCursor() const; // does it have a special hover cursor? void setRegion(LLViewerRegion *regionp); - virtual void updateRegion(LLViewerRegion *regionp) {} + virtual void updateRegion(LLViewerRegion *regionp); void updateFlags(BOOL physics_changed = FALSE); + void loadFlags(U32 flags); //load flags from cache or from message BOOL setFlags(U32 flag, BOOL state); BOOL setFlagsWithoutUpdate(U32 flag, BOOL state); void setPhysicsShapeType(U8 type); @@ -535,10 +600,15 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate virtual void dirtySpatialGroup(BOOL priority = FALSE) const; virtual void dirtyMesh(); - virtual LLNetworkData* getParameterEntry(U16 param_type) const; - virtual bool setParameterEntry(U16 param_type, const LLNetworkData& new_value, bool local_origin); - virtual BOOL getParameterEntryInUse(U16 param_type) const; - virtual bool setParameterEntryInUse(U16 param_type, BOOL in_use, bool local_origin); + const LLFlexibleObjectData* getFlexibleObjectData() const { return mFlexibleObjectDataInUse ? &mFlexibleObjectData : nullptr; } + const LLLightParams* getLightParams() const { return mLightParamsInUse ? &mLightParams : nullptr; } + const LLSculptParams* getSculptParams() const { return mSculptParamsInUse ? &mSculptParams : nullptr; } + const LLLightImageParams* getLightImageParams() const { return mLightImageParamsInUse ? &mLightImageParams : nullptr; } + const LLExtendedMeshParams* getExtendedMeshParams() const { return mExtendedMeshParamsInUse ? &mExtendedMeshParams : nullptr; } + + bool setParameterEntry(U16 param_type, const LLNetworkData& new_value, bool local_origin); + bool setParameterEntryInUse(U16 param_type, BOOL in_use, bool local_origin); + // Called when a parameter is changed virtual void parameterChanged(U16 param_type, bool local_origin); virtual void parameterChanged(U16 param_type, LLNetworkData* data, BOOL in_use, bool local_origin); @@ -546,9 +616,20 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate friend class LLViewerObjectList; friend class LLViewerMediaList; +public: + LLViewerTexture* getBakedTextureForMagicId(const LLUUID& id); + void updateAvatarMeshVisibility(const LLUUID& id, const LLUUID& old_id); + void refreshBakeTexture(); +public: + static void unpackVector3(LLDataPackerBinaryBuffer* dp, LLVector3& value, std::string name); + static void unpackUUID(LLDataPackerBinaryBuffer* dp, LLUUID& value, std::string name); + static void unpackU32(LLDataPackerBinaryBuffer* dp, U32& value, std::string name); + static void unpackU8(LLDataPackerBinaryBuffer* dp, U8& value, std::string name); + static U32 unpackParentID(LLDataPackerBinaryBuffer* dp, U32& parent_id); + public: //counter-translation - void resetChildrenPosition(const LLVector3& offset, BOOL simplified = FALSE) ; + void resetChildrenPosition(const LLVector3& offset, BOOL simplified = FALSE, BOOL skip_avatar_child = FALSE) ; //counter-rotation void resetChildrenRotationAndPosition(const std::vector& rotations, const std::vector& positions) ; @@ -558,18 +639,47 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate private: ExtraParameter* createNewParameterEntry(U16 param_type); - ExtraParameter* getExtraParameterEntry(U16 param_type) const; - ExtraParameter* getExtraParameterEntryCreate(U16 param_type); - bool unpackParameterEntry(U16 param_type, LLDataPacker *dp); + const ExtraParameter& getExtraParameterEntry(U16 param_type) const + { + return mExtraParameterList[U32(param_type >> 4) - 1]; + } + ExtraParameter& getExtraParameterEntry(U16 param_type) + { + return mExtraParameterList[U32(param_type >> 4) - 1]; + } + ExtraParameter* getExtraParameterEntryCreate(U16 param_type) + { + if (param_type <= LLNetworkData::PARAMS_MAX) + { + ExtraParameter& param = getExtraParameterEntry(param_type); + if (!param.is_invalid) + { + if (!param.data) + { + ExtraParameter* new_entry = createNewParameterEntry(param_type); + return new_entry; + } + return ¶m; + } + } + return nullptr; + } + bool unpackParameterEntry(U16 param_type, LLDataPacker* dp); // This function checks to see if the given media URL has changed its version // and the update wasn't due to this agent's last action. U32 checkMediaURL(const std::string &media_url); // Motion prediction between updates - void interpolateLinearMotion(const F64 & time, const F32 & dt); + void interpolateLinearMotion(const F64SecondsImplicit & time, const F32SecondsImplicit & dt); + + static void initObjectDataMap(); + + // forms task inventory request if none are pending + void fetchInventoryFromServer(); public: + void print(); // // Viewer-side only types - use the LL_PCODE_APP mask. // @@ -596,6 +706,7 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate } EPhysicsShapeType; LLUUID mID; + LLUUID mOwnerID; //null if unknown // unique within region, not unique across regions // Local ID = 0 is not used @@ -608,6 +719,8 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate S32 mListIndex; LLPointer *mTEImages; + LLPointer *mTENormalMaps; + LLPointer *mTESpecularMaps; // Selection, picking and rendering variables U32 mGLName; // GL "name" used by selection code @@ -617,6 +730,7 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate // Grabbed from UPDATE_FLAGS U32 mFlags; + static std::map sObjectDataMap; public: // Sent to sim in UPDATE_FLAGS, received in ObjectPhysicsProperties U8 mPhysicsShapeType; @@ -649,6 +763,27 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate static BOOL sUseSharedDrawables; +public: + // Returns mControlAvatar for the edit root prim of this linkset + LLControlAvatar *getControlAvatar(); + LLControlAvatar *getControlAvatar() const; + + // Create or connect to an existing control av as applicable + void linkControlAvatar(); + // Remove any reference to control av for this prim + void unlinkControlAvatar(); + // Link or unlink as needed + void updateControlAvatar(); + + virtual bool isAnimatedObject() const; + + // Flags for createObject + static const S32 CO_FLAG_CONTROL_AVATAR = 1 << 0; + static const S32 CO_FLAG_UI_AVATAR = 1 << 1; + +protected: + LLPointer mControlAvatar; + protected: // delete an item in the inventory, but don't tell the // server. This is used internally by remove, update, and @@ -659,8 +794,7 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate // updateInventory. void doUpdateInventory(LLPointer& item, U8 key, bool is_new); - - static LLViewerObject *createObject(const LLUUID &id, LLPCode pcode, LLViewerRegion *regionp); + static LLViewerObject *createObject(const LLUUID &id, LLPCode pcode, LLViewerRegion *regionp, S32 flags = 0); BOOL setData(const U8 *datap, const U32 data_size); @@ -673,18 +807,16 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate // static void processTaskInvFile(void** user_data, S32 error_code, LLExtStat ext_status); - void loadTaskInvFile(const std::string& filename); + BOOL loadTaskInvFile(const std::string& filename); void doInventoryCallback(); BOOL isOnMap(); void unpackParticleSource(const S32 block_num, const LLUUID& owner_id); - void unpackParticleSource(LLDataPacker &dp, const LLUUID& owner_id); + void unpackParticleSource(LLDataPacker &dp, const LLUUID& owner_id, bool legacy); void deleteParticleSource(); void setParticleSource(const LLPartSysData& particle_parameters, const LLUUID& owner_id); -public: - private: void setNameValueList(const std::string& list); // clears nv pairs and then individually adds \n separated NV pairs from \0 terminated string void deleteTEImages(); // correctly deletes list of images @@ -695,8 +827,8 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate child_list_t mChildList; - F64 mLastInterpUpdateSecs; // Last update for purposes of interpolation - F64 mLastMessageUpdateSecs; // Last update from a message from the simulator + F64Seconds mLastInterpUpdateSecs; // Last update for purposes of interpolation + F64Seconds mLastMessageUpdateSecs; // Last update from a message from the simulator TPACKETID mLatestRecvPacketID; // Latest time stamp on message from simulator // extra data sent from the sim...currently only used for tree species info @@ -727,9 +859,17 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate callback_list_t mInventoryCallbacks; S16 mInventorySerialNum; + enum EInventoryRequestState + { + INVENTORY_REQUEST_STOPPED, + INVENTORY_REQUEST_PENDING, + INVENTORY_XFER + }; + EInventoryRequestState mInvRequestState; + U64 mInvRequestXFerId; + BOOL mInventoryDirty; + LLViewerRegion *mRegionp; // Region that this object belongs to. - BOOL mInventoryPending; - BOOL mInventoryDirty; BOOL mDead; BOOL mOrphaned; // This is an orphaned child BOOL mUserSelected; // Cached user select information @@ -738,12 +878,11 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate BOOL mStatic; // Object doesn't move. S32 mNumFaces; - F32 mTimeDilation; // Time dilation sent with the object. F32 mRotTime; // Amount (in seconds) that object has rotated according to angular velocity (llSetTargetOmega) LLQuaternion mAngularVelocityRot; // accumulated rotation from the angular velocity computations LLQuaternion mPreviousRotation; - U8 mState; // legacy + U8 mAttachmentState; // this encodes the attachment id in a somewhat complex way. 0 if not an attachment. LLViewerObjectMedia* mMedia; // NULL if no media associated U8 mClickAction; F32 mObjectCost; //resource cost of this object or -1 if unknown @@ -764,12 +903,13 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate static S32 sAxisArrowLength; + // These two caches are only correct for non-parented objects right now! mutable LLVector3 mPositionRegion; mutable LLVector3 mPositionAgent; - static void setPhaseOutUpdateInterpolationTime(F32 value) { sPhaseOutUpdateInterpolationTime = (F64) value; } - static void setMaxUpdateInterpolationTime(F32 value) { sMaxUpdateInterpolationTime = (F64) value; } + static void setPhaseOutUpdateInterpolationTime(F32 value) { sPhaseOutUpdateInterpolationTime = (F64Seconds) value; } + static void setMaxUpdateInterpolationTime(F32 value) { sMaxUpdateInterpolationTime = (F64Seconds) value; } static void setVelocityInterpolate(BOOL value) { sVelocityInterpolate = value; } static void setPingInterpolate(BOOL value) { sPingInterpolate = value; } @@ -777,8 +917,8 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate private: static S32 sNumObjects; - static F64 sPhaseOutUpdateInterpolationTime; // For motion interpolation - static F64 sMaxUpdateInterpolationTime; // For motion interpolation + static F64Seconds sPhaseOutUpdateInterpolationTime; // For motion interpolation + static F64Seconds sMaxUpdateInterpolationTime; // For motion interpolation static BOOL sVelocityInterpolate; static BOOL sPingInterpolate; @@ -797,8 +937,13 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate void setLastUpdateType(EObjectUpdateType last_update_type); BOOL getLastUpdateCached() const; void setLastUpdateCached(BOOL last_update_cached); + + virtual void updateRiggingInfo() {} + + LLJointRiggingInfoTab mJointRiggingInfoTab; + private: - LLUUID mAttachmentItemID; // ItemID when item is in user inventory. + LLUUID mAttachmentItemID; // ItemID of the associated object is in user inventory. EObjectUpdateType mLastUpdateType; BOOL mLastUpdateCached; }; @@ -847,8 +992,11 @@ class LLAlphaObject : public LLViewerObject LLStrider& normalsp, LLStrider& texcoordsp, LLStrider& colorsp, + LLStrider& emissivep, LLStrider& indicesp) = 0; + virtual void getBlendFunc(S32 face, U32& src, U32& dst); + F32 mDepth; }; diff --git a/indra/newview/llviewerobjectbackup.cpp b/indra/newview/llviewerobjectbackup.cpp index 98f08007e6..c520909e9b 100644 --- a/indra/newview/llviewerobjectbackup.cpp +++ b/indra/newview/llviewerobjectbackup.cpp @@ -29,93 +29,59 @@ #include "llviewerprecompiledheaders.h" -// system library includes #include #include #include -// linden library includes -#include "indra_constants.h" -#include "llapr.h" #include "llcallbacklist.h" #include "lldir.h" -#include "lleconomy.h" #include "llhttpclient.h" -#include "llimage.h" +#include "llinventorydefines.h" #include "llimagej2c.h" #include "lllfsthread.h" +#include "llnotificationsutil.h" #include "llsdserialize.h" -#include "llsdutil.h" #include "llsdutil_math.h" #include "lltransactiontypes.h" -#include "llinventorydefines.h" +#include "lluictrlfactory.h" +#include "lluploaddialog.h" -// newview includes #include "llagent.h" #include "llappviewer.h" #include "llassetuploadresponders.h" -#include "statemachine/aifilepicker.h" -#include "llfloaterbvhpreview.h" -#include "llfloaterbuycurrency.h" -#include "llfloaterimagepreview.h" -#include "llfloaternamedesc.h" -#include "llfloatersnapshot.h" -#include "llinventorymodel.h" // gInventory #include "llinventoryfunctions.h" -#include "llnotificationsutil.h" -#include "llresourcedata.h" +#include "llinventorymodel.h" // for gInventory +#include "llmaterialmgr.h" #include "llselectmgr.h" -#include "llstatusbar.h" #include "lltexturecache.h" #include "lltoolplacer.h" -#include "lluictrlfactory.h" -#include "lluploaddialog.h" #include "llviewercontrol.h" #include "llviewertexturelist.h" #include "llviewerobjectlist.h" #include "llviewermenu.h" +#include "lfsimfeaturehandler.h" #include "llviewerregion.h" -#include "llviewerstats.h" #include "llviewerwindow.h" -#include "hippogridmanager.h" -#include "lfsimfeaturehandler.h" - -#include "llviewerobjectbackup.h" - -LLObjectBackup* LLObjectBackup::sInstance = NULL; +#include "llviewerobjectbackup.h" // Note: these default textures are initialized with hard coded values to // prevent cheating. When not in SL, the user-configurable values are used // instead (see setDefaultTextures() below). -static LLUUID LL_TEXTURE_PLYWOOD = LLUUID("89556747-24cb-43ed-920b-47caed15465f"); -static LLUUID LL_TEXTURE_BLANK = LLUUID("5748decc-f629-461c-9a36-a35a221fe21f"); -static LLUUID LL_TEXTURE_INVISIBLE = LLUUID("38b86f85-2575-52a9-a531-23108d8da837"); -static LLUUID LL_TEXTURE_TRANSPARENT = LLUUID("8dcd4a48-2d37-4909-9f78-f7a9eb4ef903"); -static LLUUID LL_TEXTURE_MEDIA = LLUUID("8b5fec65-8d8d-9dc5-cda8-8fdf2716e361"); +LLUUID LL_TEXTURE_PLYWOOD = LLUUID("89556747-24cb-43ed-920b-47caed15465f"); +LLUUID LL_TEXTURE_BLANK = LLUUID("5748decc-f629-461c-9a36-a35a221fe21f"); +LLUUID LL_TEXTURE_INVISIBLE = LLUUID("38b86f85-2575-52a9-a531-23108d8da837"); +LLUUID LL_TEXTURE_TRANSPARENT = LLUUID("8dcd4a48-2d37-4909-9f78-f7a9eb4ef903"); +LLUUID LL_TEXTURE_MEDIA = LLUUID("8b5fec65-8d8d-9dc5-cda8-8fdf2716e361"); -void setDefaultTextures() +class ImportObjectResponder: public LLNewAgentInventoryResponder { - if (!gHippoGridManager->getConnectedGrid()->isSecondLife()) - { - // When not in SL (no texture perm check needed), we can get these - // defaults from the user settings... - LL_TEXTURE_PLYWOOD = LLUUID(gSavedSettings.getString("DefaultObjectTexture")); - LL_TEXTURE_BLANK = LLUUID(gSavedSettings.getString("UIImgWhiteUUID")); - if (gSavedSettings.controlExists("UIImgInvisibleUUID")) - { - // This control only exists in the Cool VL Viewer (added by the - // AllowInvisibleTextureInPicker patch) - LL_TEXTURE_INVISIBLE = LLUUID(gSavedSettings.getString("UIImgInvisibleUUID")); - } - } -} +protected: + LOG_CLASS(ImportObjectResponder); -class importResponder : public LLNewAgentInventoryResponder -{ public: - - importResponder(const LLSD& post_data, const LLUUID& vfile_id, LLAssetType::EType asset_type) + ImportObjectResponder(const LLSD& post_data, const LLUUID& vfile_id, + LLAssetType::EType asset_type) : LLNewAgentInventoryResponder(post_data, vfile_id, asset_type) { } @@ -123,10 +89,18 @@ class importResponder : public LLNewAgentInventoryResponder //virtual virtual void uploadComplete(const LLSD& content) { - LL_DEBUGS("ObjectBackup") << "LLNewAgentInventoryResponder::result from capabilities" << LL_ENDL; + LLObjectBackup* self = LLObjectBackup::findInstance(); + if (!self) + { + LL_WARNS() << "Import aborted, LLObjectBackup instance gone !" + << LL_ENDL; + // remove the "Uploading..." message + LLUploadDialog::modalUploadFinished(); + return; + } LLAssetType::EType asset_type = LLAssetType::lookup(mPostData["asset_type"].asString()); - LLInventoryType::EType inventory_type = LLInventoryType::lookup(mPostData["inventory_type"].asString()); + LLInventoryType::EType inv_type = LLInventoryType::lookup(mPostData["inventory_type"].asString()); // Update L$ and ownership credit information // since it probably changed on the server @@ -134,27 +108,24 @@ class importResponder : public LLNewAgentInventoryResponder asset_type == LLAssetType::AT_SOUND || asset_type == LLAssetType::AT_ANIMATION) { - gMessageSystem->newMessageFast(_PREHASH_MoneyBalanceRequest); - gMessageSystem->nextBlockFast(_PREHASH_AgentData); - gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - gMessageSystem->nextBlockFast(_PREHASH_MoneyData); - gMessageSystem->addUUIDFast(_PREHASH_TransactionID, LLUUID::null ); + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_MoneyBalanceRequest); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgentID); + msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID); + msg->nextBlockFast(_PREHASH_MoneyData); + msg->addUUIDFast(_PREHASH_TransactionID, LLUUID::null); gAgent.sendReliableMessage(); - -// LLStringUtil::format_map_t args; -// args["[AMOUNT]"] = llformat("%d",LLGlobalEconomy::Singleton::getInstance()->getPriceUpload()); -// LLNotifyBox::showXml("UploadPayment", args); } // Actually add the upload to viewer inventory - LL_INFOS("ObjectBackup") << "Adding " << content["new_inventory_item"].asUUID() << " " + LL_INFOS() << "Adding " << content["new_inventory_item"].asUUID() << " " << content["new_asset"].asUUID() << " to inventory." << LL_ENDL; if (mPostData["folder_id"].asUUID().notNull()) { LLPermissions perm; U32 next_owner_perm; - perm.init(gAgent.getID(), gAgent.getID(), LLUUID::null, LLUUID::null); + perm.init(gAgentID, gAgentID, LLUUID::null, LLUUID::null); if (mPostData["inventory_type"].asString() == "snapshot") { next_owner_perm = PERM_ALL; @@ -165,13 +136,12 @@ class importResponder : public LLNewAgentInventoryResponder } perm.initMasks(PERM_ALL, PERM_ALL, PERM_NONE, PERM_NONE, next_owner_perm); S32 creation_date_now = time_corrected(); - LLPointer item - = new LLViewerInventoryItem(content["new_inventory_item"].asUUID(), + LLPointer item; + item = new LLViewerInventoryItem(content["new_inventory_item"].asUUID(), mPostData["folder_id"].asUUID(), perm, content["new_asset"].asUUID(), - asset_type, - inventory_type, + asset_type, inv_type, mPostData["name"].asString(), mPostData["description"].asString(), LLSaleInfo::DEFAULT, @@ -182,33 +152,43 @@ class importResponder : public LLNewAgentInventoryResponder } else { - LL_WARNS("ObjectBackup") << "Can't find a folder to put it into" << LL_ENDL; + LL_WARNS() << "Can't find a folder to put it into" << LL_ENDL; } // remove the "Uploading..." message LLUploadDialog::modalUploadFinished(); - LLObjectBackup::getInstance()->updateMap(content["new_asset"].asUUID()); - LLObjectBackup::getInstance()->uploadNextAsset(); + self->updateMap(content["new_asset"].asUUID()); + self->uploadNextAsset(); } /*virtual*/ char const* getName(void) const { return "importResponder"; } }; -class CacheReadResponder : public LLTextureCache::ReadResponder +class BackupCacheReadResponder : public LLTextureCache::ReadResponder { +protected: + LOG_CLASS(BackupCacheReadResponder); + public: - CacheReadResponder(const LLUUID& id, LLImageFormatted* image) + BackupCacheReadResponder(const LLUUID& id, LLImageFormatted* image) : mFormattedImage(image), mID(id) { setImage(image); } - void setData(U8* data, S32 datasize, S32 imagesize, S32 imageformat, BOOL imagelocal) + + void setData(U8* data, S32 datasize, S32 imagesize, S32 imageformat, + BOOL imagelocal) { - if (imageformat == IMG_CODEC_TGA && mFormattedImage->getCodec() == IMG_CODEC_J2C) + LLObjectBackup* self = LLObjectBackup::findInstance(); + if (!self) return; + + if (imageformat == IMG_CODEC_TGA && + mFormattedImage->getCodec() == IMG_CODEC_J2C) { - LL_WARNS("ObjectBackup") << "FAILED: texture " << mID << " is formatted as TGA. Not saving." << LL_ENDL; - LLObjectBackup::getInstance()->mNonExportedTextures |= LLObjectBackup::TEXTURE_BAD_ENCODING; + LL_WARNS() << "FAILED: texture " << mID + << " is formatted as TGA. Not saving." << LL_ENDL; + self->mNonExportedTextures |= LLObjectBackup::TEXTURE_BAD_ENCODING; mFormattedImage = NULL; mImageSize = 0; return; @@ -216,8 +196,20 @@ class CacheReadResponder : public LLTextureCache::ReadResponder if (mFormattedImage.notNull()) { - llassert_always(mFormattedImage->getCodec() == imageformat); - mFormattedImage->appendData(data, datasize); + if (mFormattedImage->getCodec() == imageformat) + { + mFormattedImage->appendData(data, datasize); + } + else + { + LL_WARNS() << "FAILED: texture " << mID + << " is formatted as " << mFormattedImage->getCodec() + << " while expecting " << imageformat + << ". Not saving." << LL_ENDL; + mFormattedImage = NULL; + mImageSize = 0; + return; + } } else { @@ -230,101 +222,113 @@ class CacheReadResponder : public LLTextureCache::ReadResponder virtual void completed(bool success) { + LLObjectBackup* self = LLObjectBackup::findInstance(); + if (!self) + { + LL_WARNS() << "Export aborted, LLObjectBackup instance gone !" + << LL_ENDL; + return; + } + if (success && mFormattedImage.notNull() && mImageSize > 0) { - LL_INFOS("ObjectBackup") << "SUCCESS getting texture " << mID << LL_ENDL; + LL_INFOS() << "SUCCESS getting texture " << mID << LL_ENDL; std::string name; mID.toString(name); - name = LLObjectBackup::getInstance()->getfolder() + "//" + name; - LL_INFOS("ObjectBackup") << "Saving to " << name << LL_ENDL; + name = self->getFolder() + "//" + name; + LL_INFOS() << "Saving to " << name << LL_ENDL; if (!mFormattedImage->save(name)) { - LL_WARNS("ObjectBackup") << "FAILED to save texture " << mID << LL_ENDL; - LLObjectBackup::getInstance()->mNonExportedTextures |= LLObjectBackup::TEXTURE_SAVED_FAILED; + LL_WARNS() << "FAILED to save texture " << mID << LL_ENDL; + self->mNonExportedTextures |= LLObjectBackup::TEXTURE_SAVED_FAILED; } } else { if (!success) { - LL_WARNS("ObjectBackup") << "FAILED to get texture " << mID << LL_ENDL; - LLObjectBackup::getInstance()->mNonExportedTextures |= LLObjectBackup::TEXTURE_MISSING; + LL_WARNS() << "FAILED to get texture " << mID << LL_ENDL; + self->mNonExportedTextures |= LLObjectBackup::TEXTURE_MISSING; } if (mFormattedImage.isNull()) { - LL_WARNS("ObjectBackup") << "FAILED: NULL texture " << mID << LL_ENDL; - LLObjectBackup::getInstance()->mNonExportedTextures |= LLObjectBackup::TEXTURE_IS_NULL; + LL_WARNS() << "FAILED: NULL texture " << mID << LL_ENDL; + self->mNonExportedTextures |= LLObjectBackup::TEXTURE_IS_NULL; } } - LLObjectBackup::getInstance()->mNextTextureReady = true; - //JUST SAY NO TO APR DEADLOCKING - //LLObjectBackup::getInstance()->exportNextTexture(); + self->mCheckNextTexture = true; } + private: LLPointer mFormattedImage; LLUUID mID; }; -LLObjectBackup::LLObjectBackup() -: LLFloater(std::string("Object Backup Floater"), std::string("FloaterObjectBackuptRect"), LLStringUtil::null) -{ - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_object_backup.xml"); - mRunning = false; - mTexturesList.clear(); - mAssetMap.clear(); - mCurrentAsset = LLUUID::null; - mRetexture = false; - close(); -} - -//////////////////////////////////////////////////////////////////////////////// -// -LLObjectBackup* LLObjectBackup::getInstance() +LLObjectBackup::LLObjectBackup(const LLSD&) +: mRunning(false), + mRetexture(false), + mTexturesList(), + mAssetMap(), + mCurrentAsset() { - if (!sInstance) - sInstance = new LLObjectBackup(); - return sInstance; + //buildFromFile("floater_object.xml"); + LLUICtrlFactory::getInstance()->buildFloater(this, + "floater_object_backup.xml", + NULL, false); // Don't open } +//virtual LLObjectBackup::~LLObjectBackup() { - // save position of floater - gSavedSettings.setRect("FloaterObjectBackuptRect", getRect()); - sInstance = NULL; + // Just in case we got closed unexpectedly... + if (gIdleCallbacks.containsFunction(exportWorker)) + { + gIdleCallbacks.deleteFunction(exportWorker); + } } -void LLObjectBackup::draw() +//static +bool LLObjectBackup::confirmCloseCallback(const LLSD& notification, + const LLSD& response) { - LLFloater::draw(); + if (LLNotification::getSelectedOption(notification, response) == 0) + { + LLObjectBackup* self = findInstance(); + if (self) + { + self->destroy(); + } + } + return false; } -void LLObjectBackup::show(bool exporting) +//virtual +void LLObjectBackup::onClose(bool app_quitting) { - // set the title - if (exporting) + // Do not destroy the floater on user close action to avoid getting things + // messed up during import/export. + if (app_quitting) { - setTitle("Object export"); + destroy(); } else { - setTitle("Object import"); + LLNotificationsUtil::add("ConfirmAbortBackup", LLSD(), LLSD(), + confirmCloseCallback); } - mCurObject = 1; - mCurPrim = 0; - mObjects = 0; - mPrims = 0; - mRezCount = 0; - - // make floater appear - setVisibleAndFrontmost(); } -void LLObjectBackup::onClose(bool app_quitting) +void LLObjectBackup::showFloater(bool exporting) { - setVisible(false); - // HACK for fast XML iteration replace with: - // destroy(); + // Set the title + setTitle(getString(exporting ? "export" : "import")); + + mCurObject = 1; + mCurPrim = mObjects = mPrims = mRezCount = 0; + + // Make the floater pop up + setVisibleAndFrontmost(); } void LLObjectBackup::updateExportNumbers() @@ -345,7 +349,8 @@ void LLObjectBackup::updateImportNumbers() if (mRetexture) { - sstr << " Textures uploads remaining : " << mTexturesList.size() << "\n"; + sstr << " Textures uploads remaining : " << mTexturesList.size() + << "\n"; ctrl->setValue(LLSD("Text") = sstr.str()); } else @@ -367,11 +372,11 @@ void LLObjectBackup::updateImportNumbers() void LLObjectBackup::exportObject() { mTexturesList.clear(); + mBadPermsTexturesList.clear(); mLLSD.clear(); mThisGroup.clear(); - setDefaultTextures(); - LLSelectMgr::getInstance()->getSelection()->ref(); + LLSelectMgr::getInstance()->getSelection()->ref(); // Open the file save dialog AIFilePicker* filepicker = AIFilePicker::create(); @@ -384,7 +389,7 @@ void LLObjectBackup::exportObject_continued(AIFilePicker* filepicker) if (!filepicker->hasFilename()) { // User canceled save. - LLSelectMgr::getInstance()->getSelection()->unref(); + LLSelectMgr::getInstance()->getSelection()->unref(); return; } @@ -392,14 +397,33 @@ void LLObjectBackup::exportObject_continued(AIFilePicker* filepicker) mFolder = gDirUtilp->getDirName(mFileName); mNonExportedTextures = TEXTURE_OK; - mExportState = EXPORT_INIT; + mGotExtraPhysics = !gAgent.getRegion()->getCapability("GetObjectPhysicsData").empty(); gIdleCallbacks.addFunction(exportWorker, NULL); } -bool LLObjectBackup::validatePerms(const LLPermissions *item_permissions) +//---------------------------------------------------------------------------// +// Permissions checking functions +//---------------------------------------------------------------------------// + +//static +void LLObjectBackup::setDefaultTextures() +{ + if (LFSimFeatureHandler::instance().exportPolicy() == ep_full_perm) + { + // When not in SL and not in an OpenSIM grid with export permission + // support (i.e. when no texture permission check is needed), we can + // get these defaults from the user settings... + LL_TEXTURE_PLYWOOD = LLUUID(gSavedSettings.getString("DefaultObjectTexture")); + LL_TEXTURE_BLANK = LLUUID(gSavedSettings.getString("UIImgWhiteUUID")); + LL_TEXTURE_INVISIBLE = LLUUID(gSavedSettings.getString("UIImgInvisibleUUID")); + } +} + +//static +bool LLObjectBackup::validatePerms(const LLPermissions* item_permissions) { - return item_permissions->allowExportBy(gAgent.getID(), LFSimFeatureHandler::instance().exportPolicy()); + return item_permissions->allowExportBy(gAgentID, LFSimFeatureHandler::instance().exportPolicy()); } // So far, only Second Life forces TPVs to verify the creator for textures... @@ -411,171 +435,328 @@ bool LLObjectBackup::validatePerms(const LLPermissions *item_permissions) // The "must be creator" stuff also goes against the usage in Linden Lab's own // official viewers, since those allow you to save full perm textures (such as // the textures in the Library), whoever is the actual creator... Go figure ! -LLUUID LLObjectBackup::validateTextureID(LLUUID asset_id) + +//static +bool LLObjectBackup::validateTexturePerms(const LLUUID& asset_id) { - if (!gHippoGridManager->getConnectedGrid()->isSecondLife()) + if (LFSimFeatureHandler::instance().exportPolicy() == ep_full_perm) { - // If we are not in Second Life, don't bother. - return asset_id; + // If we are not in Second Life and we don't have export-permission + // support, don't bother and unconditionally accept the texture export + // (legacy behaviour). + return true; } - LLUUID texture = LL_TEXTURE_PLYWOOD; - if (asset_id == texture || + + if (asset_id == LL_TEXTURE_PLYWOOD || asset_id == LL_TEXTURE_BLANK || asset_id == LL_TEXTURE_INVISIBLE || asset_id == LL_TEXTURE_TRANSPARENT || asset_id == LL_TEXTURE_MEDIA) { // Allow to export a few default SL textures. - return asset_id; + return true; } + LLViewerInventoryCategory::cat_array_t cats; LLViewerInventoryItem::item_array_t items; LLAssetIDMatches asset_id_matches(asset_id); - gInventory.collectDescendentsIf(LLUUID::null, - cats, - items, + gInventory.collectDescendentsIf(LLUUID::null, cats, items, LLInventoryModel::INCLUDE_TRASH, asset_id_matches); - - if (items.count()) + S32 count = items.size(); + if (count > 0) { - for (S32 i = 0; i < items.count(); i++) + for (S32 i = 0; i < count; ++i) { const LLPermissions item_permissions = items[i]->getPermissions(); if (validatePerms(&item_permissions)) { - texture = asset_id; + return true; } } } - if (texture != asset_id) + return false; +} + +LLUUID LLObjectBackup::validateTextureID(const LLUUID& asset_id) +{ + if (mBadPermsTexturesList.count(asset_id)) + { + // We already checked it and know it's bad... + return LL_TEXTURE_PLYWOOD; + } + else if (asset_id.isNull() || validateTexturePerms(asset_id)) + { + return asset_id; + } + else { + mBadPermsTexturesList.insert(asset_id); // Cache bad texture ID mNonExportedTextures |= TEXTURE_BAD_PERM; + LL_WARNS() << "Bad permissions for texture ID: " << asset_id + << " - Texture will not be exported." << LL_ENDL; + return LL_TEXTURE_PLYWOOD; + } +} + +//static +bool LLObjectBackup::validateNode(LLSelectNode* node) +{ + LLPermissions* perms = node->mPermissions; + if (!perms || !validatePerms(perms)) + { + return false; } - return texture; + // Additionally check if this is a sculpt or a mesh object and if yes, if + // we have export permission on the sclupt texture or the mesh object. + LLViewerObject* obj = node->getObject(); + if (!obj) // Paranoia + { + return false; + } + else if (obj->isSculpted()) + { + if (obj->isMesh()) + { + return false; // We can't export mesh from here, anyway. + } + else + { + const LLSculptParams* params = obj->getSculptParams(); + LLUUID sculpt_id = params->getSculptTexture(); + return validateTexturePerms(sculpt_id); + } + } + else + { + return true; + } } +//---------------------------------------------------------------------------// + +//static void LLObjectBackup::exportWorker(void *userdata) { - LLObjectBackup::getInstance()->updateExportNumbers(); + LLObjectBackup* self = findInstance(); + if (!self) + { + gIdleCallbacks.deleteFunction(exportWorker); + LL_WARNS() << "Export process aborted. LLObjectBackup instance gone !" + << LL_ENDL; + LLNotifications::instance().add("ExportAborted"); + return; + } - switch (LLObjectBackup::getInstance()->mExportState) + self->updateExportNumbers(); + + switch (self->mExportState) { case EXPORT_INIT: + { + self->showFloater(true); + //LLSelectMgr::getInstance()->getSelection()->ref(); // Singu Note: Don't do this. + // Fall through to EXPORT_CHECK_PERMS + } + case EXPORT_CHECK_PERMS: + { + struct ff : public LLSelectedNodeFunctor + { + virtual bool apply(LLSelectNode* node) + { + return LLObjectBackup::validateNode(node); + } + } func; + + LLViewerObject* object; + object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (object) { - LLObjectBackup::getInstance()->show(true); - struct ff : public LLSelectedNodeFunctor + if (LLSelectMgr::getInstance()->getSelection()->applyToNodes(&func, false)) + { + self->mExportState = EXPORT_FETCH_PHYSICS; + } + else { - virtual bool apply(LLSelectNode* node) + struct vv : public LLSelectedNodeFunctor { - return LLObjectBackup::getInstance()->validatePerms(node->mPermissions); + virtual bool apply(LLSelectNode* node) + { + return node->mValid; + } + } func2; + + if (LLSelectMgr::getInstance()->getSelection()->applyToNodes(&func2, false)) + { + LL_WARNS() << "Incorrect permission to export" << LL_ENDL; + self->mExportState = EXPORT_FAILED; + LLSelectMgr::getInstance()->getSelection()->unref(); + } + else + { + LL_DEBUGS("ObjectBackup") << "Nodes permissions not yet received, delaying..." + << LL_ENDL; + self->mExportState = EXPORT_CHECK_PERMS; } - } func; + } + } + else + { + self->mExportState = EXPORT_ABORTED; + LLSelectMgr::getInstance()->getSelection()->unref(); + } + break; + } + + case EXPORT_FETCH_PHYSICS: + { + // Don't bother to try and fetch the extra physics flags if we + // don't have sim support for them... + if (!self->mGotExtraPhysics) + { + self->mExportState = EXPORT_STRUCTURE; + break; + } + + struct ff : public LLSelectedNodeFunctor + { + virtual bool apply(LLSelectNode* node) + { + LLViewerObject* object = node->getObject(); + return gObjectList.gotObjectPhysicsFlags(object); + } + } func; + LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (object) + { if (LLSelectMgr::getInstance()->getSelection()->applyToNodes(&func, false)) { - LLObjectBackup::getInstance()->mExportState = EXPORT_STRUCTURE; + self->mExportState = EXPORT_STRUCTURE; } else { - LL_WARNS("ObjectBackup") << "Incorrect permission to export" << LL_ENDL; - LLObjectBackup::getInstance()->mExportState = EXPORT_FAILED; - LLSelectMgr::getInstance()->getSelection()->unref(); + LL_DEBUGS("ObjectBackup") << "Nodes physics not yet received, delaying..." + << LL_ENDL; } } + else + { + self->mExportState = EXPORT_ABORTED; + LLSelectMgr::getInstance()->getSelection()->unref(); + } break; + } case EXPORT_STRUCTURE: + { + struct ff : public LLSelectedObjectFunctor { - struct ff : public LLSelectedObjectFunctor + virtual bool apply(LLViewerObject* object) { - virtual bool apply(LLViewerObject* object) + bool is_attachment = object->isAttachment(); + object->boostTexturePriority(true); + LLViewerObject::child_list_t children = object->getChildren(); + children.push_front(object); //push root onto list + LLObjectBackup* self = findInstance(); + LLSD prim_llsd = self->primsToLLSD(children, + is_attachment); + LLSD stuff; + if (is_attachment) { - bool is_attachment = object->isAttachment(); - object->boostTexturePriority(TRUE); - LLViewerObject::child_list_t children = object->getChildren(); - children.push_front(object); //push root onto list - LLSD prim_llsd = LLObjectBackup::getInstance()->primsToLLSD(children, is_attachment); - LLSD stuff; - if (is_attachment) - { - stuff["root_position"] = object->getPositionEdit().getValue(); - stuff["root_rotation"] = ll_sd_from_quaternion(object->getRotationEdit()); - } - else - { - stuff["root_position"] = object->getPosition().getValue(); - stuff["root_rotation"] = ll_sd_from_quaternion(object->getRotation()); - } - stuff["group_body"] = prim_llsd; - LLObjectBackup::getInstance()->mLLSD["data"].append(stuff); - return true; + stuff["root_position"] = object->getPositionEdit().getValue(); + stuff["root_rotation"] = ll_sd_from_quaternion(object->getRotationEdit()); + } + else + { + stuff["root_position"] = object->getPosition().getValue(); + stuff["root_rotation"] = ll_sd_from_quaternion(object->getRotation()); } - } func; + stuff["group_body"] = prim_llsd; + self->mLLSD["data"].append(stuff); + return true; + } + } func; - LLObjectBackup::getInstance()->mExportState = EXPORT_LLSD; + LLViewerObject* object; + object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); + if (object) + { + self->mExportState = EXPORT_LLSD; LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func, false); - LLSelectMgr::getInstance()->getSelection()->unref(); } + else + { + self->mExportState = EXPORT_ABORTED; + } + LLSelectMgr::getInstance()->getSelection()->unref(); break; + } case EXPORT_TEXTURES: - if (LLObjectBackup::getInstance()->mNextTextureReady == false) + { + if (!self->mCheckNextTexture) + { + // The texture is being fetched. Wait till next idle callback. return; + } - // Ok we got work to do - LLObjectBackup::getInstance()->mNextTextureReady = false; - - if (LLObjectBackup::getInstance()->mTexturesList.empty()) + if (self->mTexturesList.empty()) { - LLObjectBackup::getInstance()->mExportState = EXPORT_DONE; + self->mExportState = EXPORT_DONE; return; } - LLObjectBackup::getInstance()->exportNextTexture(); + // Ok, we got work to do... + self->mCheckNextTexture = false; + self->exportNextTexture(); break; + } case EXPORT_LLSD: - { - // Create a file stream and write to it - llofstream export_file(LLObjectBackup::getInstance()->mFileName); - LLSDSerialize::toPrettyXML(LLObjectBackup::getInstance()->mLLSD, export_file); - export_file.close(); - LLObjectBackup::getInstance()->mNextTextureReady = true; - LLObjectBackup::getInstance()->mExportState = EXPORT_TEXTURES; - } + { + // Create a file stream and write to it + llofstream export_file(self->mFileName); + LLSDSerialize::toPrettyXML(self->mLLSD, export_file); + export_file.close(); + self->mCheckNextTexture = true; + self->mExportState = EXPORT_TEXTURES; break; + } case EXPORT_DONE: + { gIdleCallbacks.deleteFunction(exportWorker); - if (LLObjectBackup::getInstance()->mNonExportedTextures == LLObjectBackup::TEXTURE_OK) + if (self->mNonExportedTextures == LLObjectBackup::TEXTURE_OK) { - LL_INFOS("ObjectBackup") << "Export successful and complete." << LL_ENDL; + LL_INFOS() << "Export successful and complete." << LL_ENDL; LLNotificationsUtil::add("ExportSuccessful"); } else { - LL_INFOS("ObjectBackup") << "Export successful but incomplete: some texture(s) not saved." << LL_ENDL; + LL_INFOS() << "Export successful but incomplete: some texture(s) not saved." + << LL_ENDL; std::string reason; - if (LLObjectBackup::getInstance()->mNonExportedTextures & LLObjectBackup::TEXTURE_BAD_PERM) + U32 error_bits_map = self->mNonExportedTextures; + if (error_bits_map & LLObjectBackup::TEXTURE_BAD_PERM) { reason += "\nBad permissions/creator."; } - if (LLObjectBackup::getInstance()->mNonExportedTextures & LLObjectBackup::TEXTURE_MISSING) + if (error_bits_map & LLObjectBackup::TEXTURE_MISSING) { reason += "\nMissing texture (retrying after full rezzing might work)."; } - if (LLObjectBackup::getInstance()->mNonExportedTextures & LLObjectBackup::TEXTURE_BAD_ENCODING) + if (error_bits_map & LLObjectBackup::TEXTURE_BAD_ENCODING) { reason += "\nBad texture encoding."; } - if (LLObjectBackup::getInstance()->mNonExportedTextures & LLObjectBackup::TEXTURE_IS_NULL) + if (error_bits_map & LLObjectBackup::TEXTURE_IS_NULL) { reason += "\nNull texture."; } - if (LLObjectBackup::getInstance()->mNonExportedTextures & LLObjectBackup::TEXTURE_SAVED_FAILED) + if (error_bits_map & LLObjectBackup::TEXTURE_SAVED_FAILED) { reason += "\nCould not write to disk."; } @@ -583,39 +764,55 @@ void LLObjectBackup::exportWorker(void *userdata) args["REASON"] = reason; LLNotificationsUtil::add("ExportPartial", args); } - LLObjectBackup::getInstance()->close(); + self->destroy(); break; + } case EXPORT_FAILED: + { gIdleCallbacks.deleteFunction(exportWorker); - LL_WARNS("ObjectBackup") << "Export process aborted." << LL_ENDL; + LL_WARNS() << "Export process failed." << LL_ENDL; LLNotificationsUtil::add("ExportFailed"); - LLObjectBackup::getInstance()->close(); + self->destroy(); + break; + } + + case EXPORT_ABORTED: + { + gIdleCallbacks.deleteFunction(exportWorker); + LL_WARNS() << "Export process aborted." << LL_ENDL; + LLNotificationsUtil::add("ExportAborted"); + self->destroy(); break; + } } } -LLSD LLObjectBackup::primsToLLSD(LLViewerObject::child_list_t child_list, bool is_attachment) +LLSD LLObjectBackup::primsToLLSD(LLViewerObject::child_list_t child_list, + bool is_attachment) { LLViewerObject* object; LLSD llsd; char localid[16]; + LLUUID t_id; - for (LLViewerObject::child_list_t::iterator i = child_list.begin(); i != child_list.end(); ++i) + for (LLViewerObject::child_list_t::iterator i = child_list.begin(); + i != child_list.end(); ++i) { object = (*i); LLUUID id = object->getID(); - LL_INFOS("ObjectBackup") << "Exporting prim " << object->getID().asString() << LL_ENDL; + LL_INFOS() << "Exporting prim " << object->getID().asString() << LL_ENDL; - // Create an LLSD object that represents this prim. It will be injected in to the overall LLSD - // tree structure + // Create an LLSD object that represents this prim. It will be injected + // in to the overall LLSD tree structure LLSD prim_llsd; if (!object->isRoot()) { // Parent id - snprintf(localid, sizeof(localid), "%u", object->getSubParent()->getLocalID()); + snprintf(localid, sizeof(localid), "%u", + object->getSubParent()->getLocalID()); prim_llsd["parent"] = localid; } @@ -641,176 +838,253 @@ LLSD LLObjectBackup::primsToLLSD(LLViewerObject::child_list_t child_list, bool i prim_llsd["scale"] = object->getScale().getValue(); // Flags - prim_llsd["shadows"] = FALSE; - prim_llsd["phantom"] = object->flagPhantom(); - prim_llsd["physical"] = object->flagUsePhysics(); + prim_llsd["phantom"] = object->flagPhantom(); // legacy + prim_llsd["physical"] = object->flagUsePhysics(); // legacy + prim_llsd["flags"] = (S32)object->getFlags(); // new way + + // Extra physics flags + if (mGotExtraPhysics) + { + LLSD& physics = prim_llsd["ExtraPhysics"]; + physics["PhysicsShapeType"] = object->getPhysicsShapeType(); + physics["Gravity"] = object->getPhysicsGravity(); + physics["Friction"] = object->getPhysicsFriction(); + physics["Density"] = object->getPhysicsDensity(); + physics["Restitution"] = object->getPhysicsRestitution(); + } + + // Click action + if (S32 action = object->getClickAction()) // Non-zero + prim_llsd["clickaction"] = action; + + // Prim material + prim_llsd["material"] = object->getMaterial(); // Volume params LLVolumeParams params = object->getVolume()->getParams(); prim_llsd["volume"] = params.asLLSD(); // Extra paramsb6fab961-af18-77f8-cf08-f021377a7244 + if (object->isFlexible()) { // Flexible - LLFlexibleObjectData* flex = (LLFlexibleObjectData*)object->getParameterEntry(LLNetworkData::PARAMS_FLEXIBLE); - prim_llsd["flexible"] = flex->asLLSD(); + const LLFlexibleObjectData* flex = object->getFlexibleObjectData(); + if (flex) + { + prim_llsd["flexible"] = flex->asLLSD(); + } } - if (object->getParameterEntryInUse(LLNetworkData::PARAMS_LIGHT)) + + const LLLightParams* light = object->getLightParams(); + if (light) { // Light - LLLightParams* light = (LLLightParams*)object->getParameterEntry(LLNetworkData::PARAMS_LIGHT); prim_llsd["light"] = light->asLLSD(); } - if (object->getParameterEntryInUse(LLNetworkData::PARAMS_SCULPT)) + + const LLLightImageParams* light_param = object->getLightImageParams(); + if (light_param) + { + // Light image + t_id = validateTextureID(light_param->getLightTexture()); + if (mTexturesList.count(t_id) == 0) + { + LL_INFOS() << "Found a light texture, adding to list " << t_id + << LL_ENDL; + mTexturesList.insert(t_id); + } + prim_llsd["light_texture"] = light_param->asLLSD(); + } + + const LLSculptParams* sculpt = object->getSculptParams(); + if (sculpt) { // Sculpt - LLSculptParams* sculpt = (LLSculptParams*)object->getParameterEntry(LLNetworkData::PARAMS_SCULPT); prim_llsd["sculpt"] = sculpt->asLLSD(); - - LLUUID sculpt_texture = sculpt->getSculptTexture(); - if (sculpt_texture == validateTextureID(sculpt_texture)) + if ((sculpt->getSculptType() & LL_SCULPT_TYPE_MASK) != LL_SCULPT_TYPE_MESH) { - bool alreadyseen = false; - std::list::iterator iter; - for (iter = mTexturesList.begin(); iter != mTexturesList.end(); iter++) + LLUUID sculpt_texture = sculpt->getSculptTexture(); + if (sculpt_texture == validateTextureID(sculpt_texture)) { - if ((*iter) == sculpt_texture) - alreadyseen = true; + if (mTexturesList.count(sculpt_texture) == 0) + { + LL_INFOS() << "Found a sculpt texture, adding to list " + << sculpt_texture << LL_ENDL; + mTexturesList.insert(sculpt_texture); + } } - if (alreadyseen == false) + else { - LL_INFOS("ObjectBackup") << "Found a sculpt texture, adding to list " << sculpt_texture << LL_ENDL; - mTexturesList.push_back(sculpt_texture); + LL_WARNS() << "Incorrect permission to export a sculpt texture." + << LL_ENDL; + mExportState = EXPORT_FAILED; } } - else - { - LL_WARNS("ObjectBackup") << "Incorrect permission to export a sculpt texture." << LL_ENDL; - LLObjectBackup::getInstance()->mExportState = EXPORT_FAILED; - } } - // Textures + // Textures and materials LLSD te_llsd; LLSD this_te_llsd; - LLUUID t_id; - U8 te_count = object->getNumTEs(); - for (U8 i = 0; i < te_count; i++) + LLSD te_mat_llsd; + LLSD this_te_mat_llsd; + bool has_materials = false; + for (U8 i = 0, count = object->getNumTEs(); i < count; ++i) { - bool alreadyseen = false; - t_id = validateTextureID(object->getTE(i)->getID()); - this_te_llsd = object->getTE(i)->asLLSD(); + LLTextureEntry* te = object->getTE(i); + if (!te) continue; // Paranoia + + // Normal texture/diffuse map + t_id = validateTextureID(te->getID()); + this_te_llsd = te->asLLSD(); this_te_llsd["imageid"] = t_id; te_llsd.append(this_te_llsd); - // Do not export Linden textures even though they don't taint creation. - if (t_id != LL_TEXTURE_PLYWOOD && - t_id != LL_TEXTURE_BLANK && - t_id != LL_TEXTURE_TRANSPARENT && - t_id != LL_TEXTURE_INVISIBLE && - t_id != LL_TEXTURE_MEDIA) - { - std::list::iterator iter; - for (iter = mTexturesList.begin(); iter != mTexturesList.end(); iter++) + // Do not export non-existent default textures + if (t_id != LL_TEXTURE_BLANK && t_id != LL_TEXTURE_INVISIBLE) + { + if (mTexturesList.count(t_id) == 0) + { + mTexturesList.insert(t_id); + } + } + + // Materials + LLMaterial* mat = te->getMaterialParams().get(); + if (mat) + { + has_materials = true; + this_te_mat_llsd = mat->asLLSD(); + + t_id = validateTextureID(mat->getNormalID()); + this_te_mat_llsd["NormMap"] = t_id; + if (mTexturesList.count(t_id) == 0) { - if ((*iter) == t_id) - alreadyseen = true; + mTexturesList.insert(t_id); } - if (alreadyseen == false) - mTexturesList.push_back(t_id); + + t_id = validateTextureID(mat->getSpecularID()); + this_te_mat_llsd["SpecMap"] = t_id; + if (mTexturesList.count(t_id) == 0) + { + mTexturesList.insert(t_id); + } + + te_mat_llsd.append(this_te_mat_llsd); } } prim_llsd["textures"] = te_llsd; + if (has_materials) + { + prim_llsd["materials"] = te_mat_llsd; + } - // The keys in the primitive maps do not have to be localids, they can be any - // string. We simply use localids because they are a unique identifier + // The keys in the primitive maps do not have to be localids, they can + // be any string. We simply use localids because they are a unique + // identifier snprintf(localid, sizeof(localid), "%u", object->getLocalID()); llsd[(const char*)localid] = prim_llsd; } + updateExportNumbers(); + return llsd; } void LLObjectBackup::exportNextTexture() { - if (mTexturesList.empty()) - { - LL_INFOS("ObjectBackup") << "Finished exporting textures." << LL_ENDL; - return; - } - LLUUID id; - std::list::iterator iter; - iter = mTexturesList.begin(); - + textures_set_t::iterator iter = mTexturesList.begin(); while (true) { + if (mTexturesList.empty()) + { + mCheckNextTexture = true; + LL_INFOS() << "Finished exporting textures." << LL_ENDL; + return; + } if (iter == mTexturesList.end()) { - mNextTextureReady = true; + // Not yet ready, wait and re-check at next idle callback... + mCheckNextTexture = true; return; } - id = (*iter); + id = *iter++; if (id.isNull()) { // NULL texture id: just remove and ignore. - mTexturesList.remove(id); - iter = mTexturesList.begin(); + mTexturesList.erase(id); + LL_DEBUGS("ObjectBackup") << "Null texture UUID found, ignoring." + << LL_ENDL; continue; } - LLViewerTexture* imagep = LLViewerTextureManager::findTexture(id); - if (imagep != NULL) + LLViewerTexture* imagep = LLViewerTextureManager::findFetchedTexture(id, TEX_LIST_STANDARD); + if (imagep) { - S32 cur_discard = imagep->getDiscardLevel(); - if (cur_discard > 0) + if (imagep->getDiscardLevel() > 0) { - if (imagep->getBoostLevel() != LLGLTexture::BOOST_PREVIEW) + // Boost texture loading + imagep->setBoostLevel(LLGLTexture::BOOST_PREVIEW); + LL_DEBUGS("ObjectBackup") << "Boosting texture: " << id + << LL_ENDL; + LLViewerFetchedTexture* tex; + tex = LLViewerTextureManager::staticCastToFetchedTexture(imagep); + if (tex && tex->getDesiredDiscardLevel() > 0) { - // we want to force discard 0: this one does this. - imagep->setBoostLevel(LLGLTexture::BOOST_PREVIEW); + // Set min discard level to 0 + tex->setMinDiscardLevel(0); + LL_DEBUGS("ObjectBackup") << "Min discard level set to 0 for texture: " + << id << LL_ENDL; } } else { + // Texture is ready ! break; } } else { - LL_WARNS("ObjectBackup") << "We *DON'T* have the texture " << id.asString() << LL_ENDL; + LL_WARNS() << "We *DON'T* have the texture " << id << LL_ENDL; mNonExportedTextures |= TEXTURE_MISSING; - mTexturesList.remove(id); - return; + mTexturesList.erase(id); } - iter++; } - mTexturesList.remove(id); + mTexturesList.erase(id); - LL_INFOS("ObjectBackup") << "Requesting texture " << id << LL_ENDL; + LL_INFOS() << "Requesting texture " << id << " from cache." << LL_ENDL; LLImageJ2C* mFormattedImage = new LLImageJ2C; - CacheReadResponder* responder = new CacheReadResponder(id, mFormattedImage); - LLAppViewer::getTextureCache()->readFromCache(id, LLWorkerThread::PRIORITY_HIGH, 0, 999999, responder); + BackupCacheReadResponder* responder; + responder = new BackupCacheReadResponder(id, mFormattedImage); + LLAppViewer::getTextureCache()->readFromCache(id, + LLWorkerThread::PRIORITY_HIGH, + 0, 999999, responder); +} + + +bool is_default_texture(const LLUUID& id) +{ + return id.isNull() || id == LL_TEXTURE_PLYWOOD || id == LL_TEXTURE_BLANK || + id == LL_TEXTURE_INVISIBLE; } void LLObjectBackup::importObject(bool upload) { + mRetexture = upload; mTexturesList.clear(); mAssetMap.clear(); - mCurrentAsset = LLUUID::null; - + mCurrentAsset.setNull(); + + mGotExtraPhysics = !gAgent.getRegion()->getCapability("GetObjectPhysicsData").empty(); + setDefaultTextures(); - - mRetexture = upload; - + // Open the file open dialog AIFilePicker* filepicker = AIFilePicker::create(); filepicker->open(FFLOAD_XML, "", "import"); filepicker->run(boost::bind(&LLObjectBackup::importObject_continued, this, filepicker)); - - return; } void LLObjectBackup::importObject_continued(AIFilePicker* filepicker) @@ -820,22 +1094,27 @@ void LLObjectBackup::importObject_continued(AIFilePicker* filepicker) // User canceled save. return; } - - std::string file_name = filepicker->getFilename(); + + std::string file_name = filepicker->getFilename(); mFolder = gDirUtilp->getDirName(file_name); llifstream import_file(file_name); LLSDSerialize::fromXML(mLLSD, import_file); import_file.close(); - show(false); + if (!mLLSD.has("data")) + { + LLNotificationsUtil::add("ImportFailed"); + destroy(); + return; + } + + showFloater(false); mAgentPos = gAgent.getPositionAgent(); - mAgentRot = LLQuaternion(gAgent.getAtAxis(), gAgent.getLeftAxis(), gAgent.getUpAxis()); + mAgentRot = LLQuaternion(gAgent.getAtAxis(), gAgent.getLeftAxis(), + gAgent.getUpAxis()); // Get the texture map - - LLSD::map_const_iterator prim_it; - LLSD::array_const_iterator prim_arr_it; - + mCurObject = 1; mCurPrim = 1; mObjects = mLLSD["data"].size(); @@ -843,66 +1122,106 @@ void LLObjectBackup::importObject_continued(AIFilePicker* filepicker) mRezCount = 0; updateImportNumbers(); - for (prim_arr_it = mLLSD["data"].beginArray(); prim_arr_it != mLLSD["data"].endArray(); prim_arr_it++) + for (auto const& entry : mLLSD["data"].array()) { - LLSD llsd2 = (*prim_arr_it)["group_body"]; + LLSD llsd2 = entry["group_body"]; - for (prim_it = llsd2.beginMap(); prim_it != llsd2.endMap(); prim_it++) + for (LLSD::map_const_iterator prim_it = llsd2.beginMap(), + prim_end = llsd2.endMap(); + prim_it != prim_end; ++prim_it) { LLSD prim_llsd = llsd2[prim_it->first]; - LLSD::array_iterator text_it; - std::list::iterator iter; - if (prim_llsd.has("sculpt")) { - LLSculptParams* sculpt = new LLSculptParams(); - sculpt->fromLLSD(prim_llsd["sculpt"]); - LLUUID orig = sculpt->getSculptTexture(); - bool alreadyseen = false; - for (iter = mTexturesList.begin(); iter != mTexturesList.end(); iter++) + LLSculptParams sculpt; + sculpt.fromLLSD(prim_llsd["sculpt"]); + if ((sculpt.getSculptType() & LL_SCULPT_TYPE_MASK) != LL_SCULPT_TYPE_MESH) { - if ((*iter) == orig) - alreadyseen = true; + LLUUID orig = sculpt.getSculptTexture(); + if (mTexturesList.count(orig) == 0) + { + LL_INFOS() << "Found a new SCULPT texture to upload " + << orig << LL_ENDL; + mTexturesList.insert(orig); + } } - if (alreadyseen == false) + } + + if (prim_llsd.has("light_texture")) + { + LLLightImageParams lightimg; + lightimg.fromLLSD(prim_llsd["light_texture"]); + LLUUID t_id = lightimg.getLightTexture(); + if (!is_default_texture(t_id) && + mTexturesList.count(t_id) == 0) { - LL_INFOS("ObjectBackup") << "Found a new SCULPT texture to upload " << orig << LL_ENDL; - mTexturesList.push_back(orig); + LL_INFOS() << "Found a new light texture to upload: " << t_id + << LL_ENDL; + mTexturesList.insert(t_id); } } - LLSD te_llsd = prim_llsd["textures"]; - - for (text_it = te_llsd.beginArray(); text_it != te_llsd.endArray(); text_it++) + // Check both for "textures" and "texture" since the second (buggy) + // case has already been seen in some exported prims XML files... + LLSD& te_llsd = prim_llsd.has("textures") ? prim_llsd["textures"] + : prim_llsd["texture"]; + for (LLSD::array_iterator it = te_llsd.beginArray(); + it != te_llsd.endArray(); ++it) { - LLSD the_te = (*text_it); + LLSD the_te = *it; LLTextureEntry te; te.fromLLSD(the_te); - LLUUID id = te.getID(); - if (id != LL_TEXTURE_PLYWOOD && id != LL_TEXTURE_BLANK && id != LL_TEXTURE_INVISIBLE) // Do not upload the default textures - { - bool alreadyseen = false; + LLUUID t_id = te.getID(); + if (!is_default_texture(t_id) && + mTexturesList.count(t_id) == 0) + { + LL_INFOS() << "Found a new texture to upload: " << t_id + << LL_ENDL; + mTexturesList.insert(t_id); + } + } + + if (prim_llsd.has("materials")) + { + LLSD mat_llsd = prim_llsd["materials"]; + for (LLSD::array_iterator it = mat_llsd.beginArray(); + it != mat_llsd.endArray(); ++it) + { + LLSD the_mat = *it; + LLMaterial mat; + mat.fromLLSD(the_mat); - for (iter = mTexturesList.begin(); iter != mTexturesList.end(); iter++) + LLUUID t_id = mat.getNormalID(); + if (!is_default_texture(t_id) && + mTexturesList.count(t_id) == 0) { - if ((*iter) == te.getID()) - alreadyseen = true; + LL_INFOS() << "Found a new normal map to upload: " + << t_id << LL_ENDL; + mTexturesList.insert(t_id); } - if (alreadyseen == false) + + t_id = mat.getSpecularID(); + if (!is_default_texture(t_id) && + mTexturesList.count(t_id) == 0) { - LL_INFOS("ObjectBackup") << "Found a new texture to upload "<< te.getID() << LL_ENDL; - mTexturesList.push_back(te.getID()); + LL_INFOS() << "Found a new specular map to upload: " + << t_id << LL_ENDL; + mTexturesList.insert(t_id); } - } + } } } } - if (mRetexture == TRUE) + if (mRetexture) + { uploadNextAsset(); + } else + { importFirstObject(); + } } LLVector3 LLObjectBackup::offsetAgent(LLVector3 offset) @@ -913,18 +1232,17 @@ LLVector3 LLObjectBackup::offsetAgent(LLVector3 offset) void LLObjectBackup::rezAgentOffset(LLVector3 offset) { // This will break for a sitting agent - LLToolPlacer* mPlacer = new LLToolPlacer(); - mPlacer->setObjectType(LL_PCODE_CUBE); - //LLVector3 pos = offsetAgent(offset); - mPlacer->placeObject((S32)offset.mV[0], (S32)offset.mV[1], MASK_NONE); + LLToolPlacer mPlacer; + mPlacer.setObjectType(LL_PCODE_CUBE); + mPlacer.placeObject((S32)offset.mV[0], (S32)offset.mV[1], MASK_NONE); } void LLObjectBackup::importFirstObject() { mRunning = true; - show(false); + showFloater(false); mGroupPrimImportIter = mLLSD["data"].beginArray(); - mRootRootPos = (*mGroupPrimImportIter)["root_position"]; + mRootRootPos = LLVector3((*mGroupPrimImportIter)["root_position"]); mObjects = mLLSD["data"].size(); mCurObject = 1; importNextObject(); @@ -942,16 +1260,18 @@ void LLObjectBackup::importNextObject() mPrims = mThisGroup.size(); updateImportNumbers(); - LLVector3 lgpos = (*mGroupPrimImportIter)["root_position"]; + LLVector3 lgpos = LLVector3((*mGroupPrimImportIter)["root_position"]); mGroupOffset = lgpos - mRootRootPos; mRootPos = offsetAgent(LLVector3(2.0, 0.0, 0.0)); mRootRot = ll_quaternion_from_sd((*mGroupPrimImportIter)["root_rotation"]); rezAgentOffset(LLVector3(0.0, 2.0, 0.0)); - // Now we must wait for the callback when ViewerObjectList gets the new objects and we have the correct number selected + // Now we must wait for the callback when ViewerObjectList gets the new + // objects and we have the correct number selected } -// This function takes a pointer to a viewerobject and applies the prim definition that prim_llsd has +// This function takes a pointer to a viewerobject and applies the prim +// definition that prim_llsd has void LLObjectBackup::xmlToPrim(LLSD prim_llsd, LLViewerObject* object) { LLUUID id = object->getID(); @@ -968,10 +1288,20 @@ void LLObjectBackup::xmlToPrim(LLSD prim_llsd, LLViewerObject* object) LLSelectMgr::getInstance()->selectionSetObjectDescription(prim_llsd["description"]); } + if (prim_llsd.has("material")) + { + LLSelectMgr::getInstance()->selectionSetMaterial(prim_llsd["material"].asInteger()); + } + + if (prim_llsd.has("clickaction")) + { + LLSelectMgr::getInstance()->selectionSetClickAction(prim_llsd["clickaction"].asInteger()); + } + if (prim_llsd.has("parent")) { //we are not the root node. - LLVector3 pos = prim_llsd["position"]; + LLVector3 pos = LLVector3(prim_llsd["position"]); LLQuaternion rot = ll_quaternion_from_sd(prim_llsd["rotation"]); object->setPositionRegion(pos * mRootRot + mRootPos + mGroupOffset); object->setRotation(rot * mRootRot); @@ -983,19 +1313,43 @@ void LLObjectBackup::xmlToPrim(LLSD prim_llsd, LLViewerObject* object) object->setRotation(rot); } - object->setScale(prim_llsd["scale"]); + object->setScale(LLVector3(prim_llsd["scale"])); - /*if (prim_llsd.has("shadows")) - if (prim_llsd["shadows"].asInteger() == 1) - object->setFlags(FLAGS_CAST_SHADOWS, true);*/ + if (prim_llsd.has("flags")) + { + U32 flags = (U32)prim_llsd["flags"].asInteger(); + object->setFlags(flags, true); + } + else // Kept for backward compatibility + { + /*if (prim_llsd.has("shadows")) + if (prim_llsd["shadows"].asInteger() == 1) + object->setFlags(FLAGS_CAST_SHADOWS, true);*/ - if (prim_llsd.has("phantom")) - if (prim_llsd["phantom"].asInteger() == 1) - object->setFlags(FLAGS_PHANTOM, true); + if (prim_llsd.has("phantom") && prim_llsd["phantom"].asInteger() == 1) + { + object->setFlags(FLAGS_PHANTOM, true); + } - if (prim_llsd.has("physical")) - if (prim_llsd["physical"].asInteger() == 1) + if (prim_llsd.has("physical") && + prim_llsd["physical"].asInteger() == 1) + { object->setFlags(FLAGS_USE_PHYSICS, true); + } + } + + if (mGotExtraPhysics && prim_llsd.has("ExtraPhysics")) + { + const LLSD& physics = prim_llsd["ExtraPhysics"]; + object->setPhysicsShapeType(physics["PhysicsShapeType"].asInteger()); + F32 gravity = physics.has("Gravity") ? physics["Gravity"].asReal() + : physics["GravityMultiplier"].asReal(); + object->setPhysicsGravity(gravity); + object->setPhysicsFriction(physics["Friction"].asReal()); + object->setPhysicsDensity(physics["Density"].asReal()); + object->setPhysicsRestitution(physics["Restitution"].asReal()); + object->updateFlags(true); + } // Volume params LLVolumeParams volume_params = object->getVolume()->getParams(); @@ -1004,60 +1358,98 @@ void LLObjectBackup::xmlToPrim(LLSD prim_llsd, LLViewerObject* object) if (prim_llsd.has("sculpt")) { - LLSculptParams* sculpt = new LLSculptParams(); - sculpt->fromLLSD(prim_llsd["sculpt"]); - - // TODO: check if map is valid and only set texture if map is valid and changes + LLSculptParams sculpt; + sculpt.fromLLSD(prim_llsd["sculpt"]); - if (mAssetMap[sculpt->getSculptTexture()].notNull()) + // TODO: check if map is valid and only set texture if map is valid and + // changes + LLUUID t_id = sculpt.getSculptTexture(); + if (mAssetMap.count(t_id)) { - LLUUID replacment = mAssetMap[sculpt->getSculptTexture()]; - sculpt->setSculptTexture(replacment); + sculpt.setSculptTexture(mAssetMap[t_id], sculpt.getSculptType()); } - object->setParameterEntry(LLNetworkData::PARAMS_SCULPT,(LLNetworkData&)(*sculpt), true); + object->setParameterEntry(LLNetworkData::PARAMS_SCULPT, sculpt, true); } if (prim_llsd.has("light")) { - LLLightParams* light = new LLLightParams(); - light->fromLLSD(prim_llsd["light"]); - object->setParameterEntry(LLNetworkData::PARAMS_LIGHT,(LLNetworkData&)(*light), true); + LLLightParams light; + light.fromLLSD(prim_llsd["light"]); + object->setParameterEntry(LLNetworkData::PARAMS_LIGHT, light, true); + } + if (prim_llsd.has("light_texture")) + { + // Light image + LLLightImageParams lightimg; + lightimg.fromLLSD(prim_llsd["light_texture"]); + LLUUID t_id = lightimg.getLightTexture(); + if (mAssetMap.count(t_id)) + { + lightimg.setLightTexture(mAssetMap[t_id]); + } + object->setParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE, lightimg, + true); } if (prim_llsd.has("flexible")) { - LLFlexibleObjectData* flex = new LLFlexibleObjectData(); - flex->fromLLSD(prim_llsd["flexible"]); - object->setParameterEntry(LLNetworkData::PARAMS_FLEXIBLE,(LLNetworkData&)(*flex), true); + LLFlexibleObjectData flex; + flex.fromLLSD(prim_llsd["flexible"]); + object->setParameterEntry(LLNetworkData::PARAMS_FLEXIBLE, flex, true); } // Textures - LL_INFOS("ObjectBackup") << "Processing textures for prim" << LL_ENDL; - LLSD te_llsd = prim_llsd["textures"]; - LLSD::array_iterator text_it; + // Check both for "textures" and "texture" since the second (buggy) case + // has already been seen in some exported prims XML files... + LL_INFOS() << "Processing textures for prim" << id << LL_ENDL; + LLSD& te_llsd = prim_llsd.has("textures") ? prim_llsd["textures"] + : prim_llsd["texture"]; U8 i = 0; - - for (text_it = te_llsd.beginArray(); text_it != te_llsd.endArray(); text_it++) + for (LLSD::array_iterator it = te_llsd.beginArray(); + it != te_llsd.endArray(); ++it) { - LLSD the_te = (*text_it); + LLSD the_te = *it; LLTextureEntry te; te.fromLLSD(the_te); - - if (mAssetMap[te.getID()].notNull()) + LLUUID t_id = te.getID(); + if (mAssetMap.count(t_id)) { - LLUUID replacment = mAssetMap[te.getID()]; - te.setID(replacment); + te.setID(mAssetMap[t_id]); } object->setTE(i++, te); } + LL_INFOS() << "Textures done !" << LL_ENDL; + + // Materials + if (prim_llsd.has("materials")) + { + LL_INFOS() << "Processing materials for prim " << id << LL_ENDL; + te_llsd = prim_llsd["materials"]; + i = 0; + for (LLSD::array_iterator it = te_llsd.beginArray(); + it != te_llsd.endArray(); ++it) + { + LLSD the_mat = *it; + LLMaterialPtr mat = new LLMaterial(the_mat); + + LLUUID t_id = mat->getNormalID(); + if (id.notNull() && mAssetMap.count(t_id)) + { + mat->setNormalID(mAssetMap[t_id]); + } - LL_INFOS("ObjectBackup") << "Textures done !" << LL_ENDL; + t_id = mat->getSpecularID(); + if (id.notNull() && mAssetMap.count(t_id)) + { + mat->setSpecularID(mAssetMap[t_id]); + } - //bump the iterator now so the callbacks hook together nicely - //if (mPrimImportIter != mThisGroup.endMap()) - // mPrimImportIter++; + LLMaterialMgr::getInstance()->put(id, i++, *mat); + } + LL_INFOS() << "Materials done !" << LL_ENDL; + } object->sendRotationUpdate(); object->sendTEUpdate(); @@ -1067,114 +1459,122 @@ void LLObjectBackup::xmlToPrim(LLSD prim_llsd, LLViewerObject* object) LLSelectMgr::getInstance()->deselectAll(); } -// This is fired when the update packet is processed so we know the prim settings have stuck +// This is fired when the update packet is processed so we know the prim +// settings have stuck +//static void LLObjectBackup::primUpdate(LLViewerObject* object) { - if (!mRunning) - return; - - if (object != NULL) - if (object->mID != mExpectingUpdate) + LLObjectBackup* self = findInstance(); + if (!object || !self || !self->mRunning || + object->mID != self->mExpectingUpdate) + { return; + } - mCurPrim++; - updateImportNumbers(); - mPrimImportIter++; + ++self->mCurPrim; + self->updateImportNumbers(); + ++self->mPrimImportIter; - LLUUID x; - mExpectingUpdate = x.null; + self->mExpectingUpdate.setNull(); - if (mPrimImportIter == mThisGroup.endMap()) + if (self->mPrimImportIter == self->mThisGroup.endMap()) { - LL_INFOS("ObjectBackup") << "Trying to link" << LL_ENDL; + LL_INFOS() << "Trying to link..." << LL_ENDL; - if (mToSelect.size() > 1) + if (self->mToSelect.size() > 1) { - std::reverse(mToSelect.begin(), mToSelect.end()); + std::reverse(self->mToSelect.begin(), self->mToSelect.end()); // Now link LLSelectMgr::getInstance()->deselectAll(); - LLSelectMgr::getInstance()->selectObjectAndFamily(mToSelect, true); + LLSelectMgr::getInstance()->selectObjectAndFamily(self->mToSelect, true); LLSelectMgr::getInstance()->sendLink(); - LLViewerObject* root = mToSelect.back(); - root->setRotation(mRootRot); + LLViewerObject* root = self->mToSelect.back(); + root->setRotation(self->mRootRot); } - mCurObject++; - mGroupPrimImportIter++; - if (mGroupPrimImportIter != mLLSD["data"].endArray()) + ++self->mCurObject; + ++self->mGroupPrimImportIter; + if (self->mGroupPrimImportIter != self->mLLSD["data"].endArray()) { - importNextObject(); + self->importNextObject(); return; } - mRunning = false; - close(); + self->mRunning = false; + self->destroy(); return; } - LLSD prim_llsd = mThisGroup[mPrimImportIter->first]; + LLSD prim_llsd = self->mThisGroup[self->mPrimImportIter->first]; - if (mToSelect.empty()) + if (self->mToSelect.empty()) { - LL_WARNS("ObjectBackup") << "error: ran out of objects to mod." << LL_ENDL; + LL_WARNS() << "error: ran out of objects to mod." << LL_ENDL; + self->mRunning = false; + self->destroy(); return; } - if (mPrimImportIter != mThisGroup.endMap()) + if (self->mPrimImportIter != self->mThisGroup.endMap()) { //rezAgentOffset(LLVector3(1.0, 0.0, 0.0)); - LLSD prim_llsd = mThisGroup[mPrimImportIter->first]; - mProcessIter++; - xmlToPrim(prim_llsd, *mProcessIter); + LLSD prim_llsd =self-> mThisGroup[self->mPrimImportIter->first]; + ++self->mProcessIter; + self->xmlToPrim(prim_llsd, *(self->mProcessIter)); } } // Callback when we rez a new object when the importer is running. -bool LLObjectBackup::newPrim(LLViewerObject* pobject) +//static +void LLObjectBackup::newPrim(LLViewerObject* object) { - if (mRunning) - { - mRezCount++; - mToSelect.push_back(pobject); - updateImportNumbers(); - mPrimImportIter++; + LLObjectBackup* self = findInstance(); + if (!object || !self || !self->mRunning) return; - pobject->setPosition(offsetAgent(LLVector3(0.0, 1.0, 0.0))); - LLSelectMgr::getInstance()->sendMultipleUpdate(UPD_POSITION); + ++self->mRezCount; + self->mToSelect.push_back(object); + self->updateImportNumbers(); + ++self->mPrimImportIter; - if (mPrimImportIter != mThisGroup.endMap()) - { - rezAgentOffset(LLVector3(1.0, 0.0 ,0.0)); - } - else - { - LL_INFOS("ObjectBackup") << "All prims rezzed, moving to build stage" << LL_ENDL; - // Deselecting is required to ensure that the first child prim - // in the link set (which is also the last rezzed prim and thus - // currently selected) will be properly renamed and desced. - LLSelectMgr::getInstance()->deselectAll(); - mPrimImportIter = mThisGroup.beginMap(); - LLSD prim_llsd = mThisGroup[mPrimImportIter->first]; - mProcessIter = mToSelect.begin(); - xmlToPrim(prim_llsd, *mProcessIter); - } + object->setPosition(self->offsetAgent(LLVector3(0.0, 1.0, 0.0))); + LLSelectMgr::getInstance()->sendMultipleUpdate(UPD_POSITION); + + if (self->mPrimImportIter != self->mThisGroup.endMap()) + { + self->rezAgentOffset(LLVector3(1.0, 0.0 ,0.0)); + } + else + { + LL_INFOS() << "All prims rezzed, moving to build stage" << LL_ENDL; + // Deselecting is required to ensure that the first child prim in + // the link set (which is also the last rezzed prim and thus + // currently selected) will be properly renamed and desced. + LLSelectMgr::getInstance()->deselectAll(); + self->mPrimImportIter = self->mThisGroup.beginMap(); + LLSD prim_llsd = self->mThisGroup[self->mPrimImportIter->first]; + self->mProcessIter = self->mToSelect.begin(); + self->xmlToPrim(prim_llsd, *(self->mProcessIter)); } - return true; } void LLObjectBackup::updateMap(LLUUID uploaded_asset) { - if (mCurrentAsset.isNull()) - return; - - LL_INFOS("ObjectBackup") << "Mapping " << mCurrentAsset << " to " << uploaded_asset << LL_ENDL; - mAssetMap.insert(std::pair(mCurrentAsset, uploaded_asset)); + if (mCurrentAsset.notNull()) + { + LL_INFOS() << "Mapping " << mCurrentAsset << " to " << uploaded_asset + << LL_ENDL; + mAssetMap[mCurrentAsset] = uploaded_asset; + } } -void myupload_new_resource(const LLTransactionID &tid, LLAssetType::EType asset_type, - std::string name, std::string desc, S32 compression_info, +void myupload_new_resource(const LLTransactionID &tid, + LLAssetType::EType asset_type, + std::string name, + std::string desc, + S32 compression_info, LLFolderType::EType destination_folder_type, - LLInventoryType::EType inv_type, U32 next_owner_perm, + LLInventoryType::EType inv_type, + U32 next_owner_perm, const std::string& display_name, LLAssetStorage::LLStoreAssetCallback callback, void *userdata) @@ -1187,15 +1587,16 @@ void myupload_new_resource(const LLTransactionID &tid, LLAssetType::EType asset_ LLAssetID uuid = tid.makeAssetID(gAgent.getSecureSessionID()); // At this point, we're ready for the upload. - std::string upload_message = "Uploading...\n\n"; - upload_message.append(display_name); + std::string upload_message = "Uploading texture:\n\n" + display_name; LLUploadDialog::modalUploadDialog(upload_message); std::string url = gAgent.getRegion()->getCapability("NewFileAgentInventory"); if (!url.empty()) { LLSD body; - body["folder_id"] = gInventory.findCategoryUUIDForType((destination_folder_type == LLFolderType::FT_NONE) ? LLFolderType::assetTypeToFolderType(asset_type) : destination_folder_type); + body["folder_id"] = gInventory.findCategoryUUIDForType(destination_folder_type == LLFolderType::FT_NONE ? + LLFolderType::assetTypeToFolderType(asset_type) : + destination_folder_type); body["asset_type"] = LLAssetType::lookup(asset_type); body["inventory_type"] = LLInventoryType::lookup(inv_type); body["name"] = name; @@ -1203,13 +1604,15 @@ void myupload_new_resource(const LLTransactionID &tid, LLAssetType::EType asset_ std::ostringstream llsdxml; LLSDSerialize::toXML(body, llsdxml); - LL_DEBUGS("ObjectBackup") << "posting body to capability: " << llsdxml.str() << LL_ENDL; - //LLHTTPClient::post(url, body, new LLNewAgentInventoryResponder(body, uuid, asset_type)); - LLHTTPClient::post(url, body, new importResponder(body, uuid, asset_type)); + LL_DEBUGS("ObjectBackup") << "posting body to capability: " + << llsdxml.str() << LL_ENDL; + LLHTTPClient::post(url, body, + new ImportObjectResponder(body, uuid, asset_type)); } else { - LL_INFOS("ObjectBackup") << "NewAgentInventory capability not found. Can't upload !" << LL_ENDL; + LL_INFOS() << "NewAgentInventory capability not found. Can't upload !" + << LL_ENDL; } } @@ -1217,20 +1620,19 @@ void LLObjectBackup::uploadNextAsset() { if (mTexturesList.empty()) { - LL_INFOS("ObjectBackup") << "Texture list is empty, moving to rez stage." << LL_ENDL; - mCurrentAsset = LLUUID::null; + LL_INFOS() << "Texture list is empty, moving to rez stage." << LL_ENDL; + mCurrentAsset.setNull(); importFirstObject(); return; } updateImportNumbers(); - std::list::iterator iter; - iter = mTexturesList.begin(); + textures_set_t::iterator iter = mTexturesList.begin(); LLUUID id = *iter; - mTexturesList.pop_front(); + mTexturesList.erase(iter); - LL_INFOS("ObjectBackup") << "Got texture ID " << id << ": trying to upload" << LL_ENDL; + LL_INFOS() << "Got texture ID " << id << ": trying to upload..." << LL_ENDL; mCurrentAsset = id; std::string struid; @@ -1259,12 +1661,13 @@ void LLObjectBackup::uploadNextAsset() } else { - LL_WARNS("ObjectBackup") << "Unable to access output file " << filename << LL_ENDL; + LL_WARNS() << "Unable to access output file " << filename << LL_ENDL; uploadNextAsset(); return; } myupload_new_resource(tid, LLAssetType::AT_TEXTURE, struid, struid, 0, - LLFolderType::FT_TEXTURE, LLInventoryType::defaultForAssetType(LLAssetType::AT_TEXTURE), - 0x0, "Uploaded texture", NULL, NULL); + LLFolderType::FT_TEXTURE, + LLInventoryType::defaultForAssetType(LLAssetType::AT_TEXTURE), + 0x0, struid, NULL, NULL); } diff --git a/indra/newview/llviewerobjectbackup.h b/indra/newview/llviewerobjectbackup.h index 27ae4f2f9b..7c1b136165 100644 --- a/indra/newview/llviewerobjectbackup.h +++ b/indra/newview/llviewerobjectbackup.h @@ -27,89 +27,113 @@ * $/LicenseInfo$ */ +#ifndef LL_LLVIEWEROBJECTBACKUP_H +#define LL_LLVIEWEROBJECTBACKUP_H + +#include +#include +#include + +#include "boost/unordered_map.hpp" +#include "boost/unordered_set.hpp" + +#include "llfloater.h" +#include "statemachine/aifilepicker.h" +#include "lluuid.h" + #include "llviewerinventory.h" +#include "llviewerobject.h" + +class LLSelectNode; +class LLViewerObject; enum export_states { EXPORT_INIT, + EXPORT_CHECK_PERMS, + EXPORT_FETCH_PHYSICS, EXPORT_STRUCTURE, EXPORT_TEXTURES, EXPORT_LLSD, EXPORT_DONE, - EXPORT_FAILED + EXPORT_FAILED, + EXPORT_ABORTED }; -class LLObjectBackup : public LLFloater +class LLObjectBackup : public LLFloater, + public LLFloaterSingleton { -public: - virtual ~LLObjectBackup(); + friend class LLUISingleton >; - // Floater stuff - virtual void show(bool exporting); - virtual void draw(); - virtual void onClose(bool app_quitting); +protected: + LOG_CLASS(LLObjectBackup); - // Static accessor - static LLObjectBackup* getInstance(); +public: + /////////////////////////////////////////////////////////////////////////// + // LLFloater interface - // Export idle callback - static void exportWorker(void *userdata); + /*virtual*/ ~LLObjectBackup(); + /*virtual*/ void onClose(bool app_quitting); + + /////////////////////////////////////////////////////////////////////////// + // Public interface for invoking the object backup feature // Import entry point - void importObject(bool upload=FALSE); + void importObject(bool upload = false); void importObject_continued(AIFilePicker* filepicker); // Export entry point void exportObject(); void exportObject_continued(AIFilePicker* filepicker); + /////////////////////////////////////////////////////////////////////////// + // Public methods used in callbacks, workers and responders + // Update map from texture worker void updateMap(LLUUID uploaded_asset); - // Move to next texture upload + // Move to next texture upload, called by the agent inventory responder void uploadNextAsset(); - // Folder public geter - std::string getfolder() { return mFolder; }; + // Export idle callback + static void exportWorker(void *userdata); - // Prim updated callback - void primUpdate(LLViewerObject* object); + // Prim updated callback, called in llviewerobjectlist.cpp + static void primUpdate(LLViewerObject* object); - // New prim call back - bool newPrim(LLViewerObject* pobject); + // New prim call back, called in llviewerobjectlist.cpp + static void newPrim(LLViewerObject* object); - static const U32 TEXTURE_OK = 0x00; - static const U32 TEXTURE_BAD_PERM = 0x01; - static const U32 TEXTURE_MISSING = 0x02; - static const U32 TEXTURE_BAD_ENCODING = 0x04; - static const U32 TEXTURE_IS_NULL = 0x08; - static const U32 TEXTURE_SAVED_FAILED = 0x10; + // Folder public getter, used by the texture cache responder + std::string getFolder() { return mFolder; } - // Is ready for next texture? - bool mNextTextureReady; - // Export state machine - enum export_states mExportState; + static void setDefaultTextures(); - // Export result flags for textures. - U32 mNonExportedTextures; - - // Is exporting these objects allowed - bool validatePerms(const LLPermissions* item_permissions); + // Permissions checking + static bool validatePerms(const LLPermissions* item_permissions); + static bool validateTexturePerms(const LLUUID& asset_id); + static bool validateNode(LLSelectNode* node); private: - // Static singleton stuff - LLObjectBackup(); - static LLObjectBackup* sInstance; + // Open only via the importObject() and exportObject() methods defined + // above. + LLObjectBackup(const LLSD&); + + void showFloater(bool exporting); + + static bool confirmCloseCallback(const LLSD& notification, + const LLSD& response); // Update the floater with status numbers void updateImportNumbers(); void updateExportNumbers(); // Permissions stuff. - LLUUID validateTextureID(LLUUID asset_id); + LLUUID validateTextureID(const LLUUID& asset_id); // Convert a selection list of objects to LLSD - LLSD primsToLLSD(LLViewerObject::child_list_t child_list, bool is_attachment); + LLSD primsToLLSD(LLViewerObject::child_list_t child_list, + bool is_attachment); // Start the import process void importFirstObject(); @@ -121,21 +145,39 @@ class LLObjectBackup : public LLFloater void exportNextTexture(); // Apply LLSD to object - void xmlToPrim(LLSD prim_llsd, LLViewerObject* pobject); + void xmlToPrim(LLSD prim_llsd, LLViewerObject* object); - // Rez a prim at a given position (note not agent offset X/Y screen for raycast) + // Rez a prim at a given position void rezAgentOffset(LLVector3 offset); // Get an offset from the agent based on rotation and current pos LLVector3 offsetAgent(LLVector3 offset); +public: + // Public static constants, used in callbacks, workers and responders + static const U32 TEXTURE_OK = 0x00; + static const U32 TEXTURE_BAD_PERM = 0x01; + static const U32 TEXTURE_MISSING = 0x02; + static const U32 TEXTURE_BAD_ENCODING = 0x04; + static const U32 TEXTURE_IS_NULL = 0x08; + static const U32 TEXTURE_SAVED_FAILED = 0x10; + + // Export state machine + enum export_states mExportState; + + // Export result flags for textures. + U32 mNonExportedTextures; + + // Set when the region supports the extra physics flags + bool mGotExtraPhysics; + + // Are we ready to check for next texture? + bool mCheckNextTexture; + +private: // Are we active flag bool mRunning; - // File and folder name control - std::string mFileName; - std::string mFolder; - // True if we need to rebase the assets bool mRetexture; @@ -145,37 +187,51 @@ class LLObjectBackup : public LLFloater U32 mPrims; U32 mCurPrim; - // No prims rezed + // Number of rezzed prims U32 mRezCount; - // Rebase map - std::map mAssetMap; + // Root pos and rotation and central root pos for link set + LLVector3 mRootPos; + LLQuaternion mRootRot; + LLVector3 mRootRootPos; + LLVector3 mGroupOffset; + + // Agent inital pos and rot when starting import + LLVector3 mAgentPos; + LLQuaternion mAgentRot; + + LLUUID mCurrentAsset; + LLUUID mExpectingUpdate; + + // Working llsd iterators for objects and linksets + LLSD::map_const_iterator mPrimImportIter; + LLSD::array_const_iterator mGroupPrimImportIter; + + // File and folder name control + std::string mFileName; + std::string mFolder; // Export texture list - std::list mTexturesList; + typedef uuid_set_t textures_set_t; + textures_set_t mTexturesList; + textures_set_t mBadPermsTexturesList; + + // Rebase map + boost::unordered_map mAssetMap; // Import object tracking std::vector mToSelect; std::vector::iterator mProcessIter; // Working LLSD holders - LLUUID mCurrentAsset; LLSD mLLSD; LLSD mThisGroup; - LLUUID mExpectingUpdate; - - // Working llsd itterators for objects and linksets - LLSD::map_const_iterator mPrimImportIter; - LLSD::array_const_iterator mGroupPrimImportIter; - - // Root pos and rotation and central root pos for link set - LLVector3 mRootPos; - LLQuaternion mRootRot; - LLVector3 mRootRootPos; - LLVector3 mGroupOffset; - - // Agent inital pos and rot when starting import - LLVector3 mAgentPos; - LLQuaternion mAgentRot; }; +extern LLUUID LL_TEXTURE_PLYWOOD; +extern LLUUID LL_TEXTURE_BLANK; +extern LLUUID LL_TEXTURE_INVISIBLE; +extern LLUUID LL_TEXTURE_TRANSPARENT; +extern LLUUID LL_TEXTURE_MEDIA; + +#endif // LL_LLVIEWEROBJECTBACKUP_H diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index dfe5db84b4..2437ce618a 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -101,6 +101,15 @@ class AIHTTPTimeoutPolicy; extern AIHTTPTimeoutPolicy objectCostResponder_timeout; extern AIHTTPTimeoutPolicy physicsFlagsResponder_timeout; +// +#include "llimpanel.h" +#include "llimview.h" +LLFloaterIMPanel* find_im_floater(const LLUUID& id) +{ + return gIMMgr->findFloaterBySession(id ^ gAgentID); +} +// + #define CULL_VIS //#define ORPHAN_SPAM //#define IGNORE_DEAD @@ -196,7 +205,7 @@ BOOL LLViewerObjectList::removeFromLocalIDTable(const LLViewerObject* objectp) U64 ipport = (((U64)ip) << 32) | (U64)port; U32 index = sIPAndPortToIndex[ipport]; - // llinfos << "Removing object from table, local ID " << local_id << ", ip " << ip << ":" << port << llendl; + // LL_INFOS() << "Removing object from table, local ID " << local_id << ", ip " << ip << ":" << port << LL_ENDL; U64 indexid = (((U64)index) << 32) | (U64)local_id; @@ -213,8 +222,8 @@ BOOL LLViewerObjectList::removeFromLocalIDTable(const LLViewerObject* objectp) return TRUE; } // UUIDs did not match - this would zap a valid entry, so don't erase it - //llinfos << "Tried to erase entry where id in table (" - // << iter->second << ") did not match object " << object.getID() << llendl; + //LL_INFOS() << "Tried to erase entry where id in table (" + // << iter->second << ") did not match object " << object.getID() << LL_ENDL; } return FALSE ; @@ -239,8 +248,8 @@ void LLViewerObjectList::setUUIDAndLocal(const LLUUID &id, sIndexAndLocalIDToUUID[indexid] = id; - //llinfos << "Adding object to table, full ID " << id - // << ", local ID " << local_id << ", ip " << ip << ":" << port << llendl; + //LL_INFOS() << "Adding object to table, full ID " << id + // << ", local ID " << local_id << ", ip " << ip << ":" << port << LL_ENDL; } S32 gFullObjectUpdates = 0; @@ -272,7 +281,7 @@ void LLViewerObjectList::processUpdateCore(LLViewerObject* objectp, } else { - LLObjectBackup::getInstance()->primUpdate(objectp); + LLObjectBackup::primUpdate(objectp); } @@ -282,7 +291,19 @@ void LLViewerObjectList::processUpdateCore(LLViewerObject* objectp, // RN: this must be called after we have a drawable // (from gPipeline.addObject) // so that the drawable parent is set properly - findOrphans(objectp, msg->getSenderIP(), msg->getSenderPort()); + if(msg != NULL) + { + findOrphans(objectp, msg->getSenderIP(), msg->getSenderPort()); + } + else + { + LLViewerRegion* regionp = objectp->getRegion(); + if(regionp != NULL) + { + findOrphans(objectp, regionp->getHost().getAddress(), regionp->getHost().getPort()); + } + } + if(just_created && objectp && (gImportTracker.getState() == ImportTracker::WAND /*|| @@ -300,8 +321,8 @@ void LLViewerObjectList::processUpdateCore(LLViewerObject* objectp, { if ( LLToolMgr::getInstance()->getCurrentTool() != LLToolPie::getInstance() ) { - // llinfos << "DEBUG selecting " << objectp->mID << " " - // << objectp->mLocalID << llendl; + // LL_INFOS() << "DEBUG selecting " << objectp->mID << " " + // << objectp->mLocalID << LL_ENDL; LLSelectMgr::getInstance()->selectObjectAndFamily(objectp); dialog_refresh_all(); } @@ -310,18 +331,18 @@ void LLViewerObjectList::processUpdateCore(LLViewerObject* objectp, gViewerWindow->getWindow()->decBusyCount(); gViewerWindow->getWindow()->setCursor( UI_CURSOR_ARROW ); - LLObjectBackup::getInstance()->newPrim(objectp); + LLObjectBackup::newPrim(objectp); } } -static LLFastTimer::DeclareTimer FTM_PROCESS_OBJECTS("Process Objects"); +static LLTrace::BlockTimerStatHandle FTM_PROCESS_OBJECTS("Process Objects"); void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, void **user_data, const EObjectUpdateType update_type, bool cached, bool compressed) { - LLFastTimer t(FTM_PROCESS_OBJECTS); + LL_RECORD_BLOCK_TIME(FTM_PROCESS_OBJECTS); LLViewerObject *objectp; S32 num_objects; @@ -339,7 +360,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, // I don't think this case is ever hit. TODO* Test this. if (!cached && !compressed && update_type != OUT_FULL) { - //llinfos << "TEST: !cached && !compressed && update_type != OUT_FULL" << llendl; + //LL_INFOS() << "TEST: !cached && !compressed && update_type != OUT_FULL" << LL_ENDL; gTerseObjectUpdates += num_objects; /* S32 size; @@ -351,7 +372,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, { size = mesgsys->getReceiveSize(); } - llinfos << "Received terse " << num_objects << " in " << size << " byte (" << size/num_objects << ")" << llendl; + LL_INFOS() << "Received terse " << num_objects << " in " << size << " byte (" << size/num_objects << ")" << LL_ENDL; */ } else @@ -367,7 +388,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, size = mesgsys->getReceiveSize(); } - llinfos << "Received " << num_objects << " in " << size << " byte (" << size/num_objects << ")" << llendl; + LL_INFOS() << "Received " << num_objects << " in " << size << " byte (" << size/num_objects << ")" << LL_ENDL; */ gFullObjectUpdates += num_objects; } @@ -378,7 +399,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, if (!regionp) { - llwarns << "Object update from unknown region! " << region_handle << llendl; + LL_WARNS() << "Object update from unknown region! " << region_handle << LL_ENDL; return; } @@ -425,24 +446,20 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, { S32 uncompressed_length = 2048; compressed_dp.reset(); - - U32 flags = 0; - if (update_type != OUT_TERSE_IMPROVED) - { - mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_UpdateFlags, flags, i); - } uncompressed_length = mesgsys->getSizeFast(_PREHASH_ObjectData, i, _PREHASH_Data); - mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_Data, compressed_dpbuffer, 0, i); + mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_Data, compressed_dpbuffer, 0, i, 2048); compressed_dp.assignBuffer(compressed_dpbuffer, uncompressed_length); if (update_type != OUT_TERSE_IMPROVED) // OUT_FULL_COMPRESSED only? { + U32 flags = 0; + mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_UpdateFlags, flags, i); compressed_dp.unpackUUID(fullid, "ID"); compressed_dp.unpackU32(local_id, "LocalID"); compressed_dp.unpackU8(pcode, "PCode"); } - else + else //OUT_TERSE_IMPROVED { compressed_dp.unpackU32(local_id, "LocalID"); getUUIDFromLocal(fullid, @@ -451,7 +468,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, gMessageSystem->getSenderPort()); if (fullid.isNull()) { - // llwarns << "update for unknown localid " << local_id << " host " << gMessageSystem->getSender() << ":" << gMessageSystem->getSenderPort() << llendl; + LL_DEBUGS() << "update for unknown localid " << local_id << " host " << gMessageSystem->getSender() << ":" << gMessageSystem->getSenderPort() << LL_ENDL; mNumUnknownUpdates++; } } @@ -467,7 +484,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, gMessageSystem->getSenderPort()); if (fullid.isNull()) { - // llwarns << "update for unknown localid " << local_id << " host " << gMessageSystem->getSender() << llendl; + // LL_WARNS() << "update for unknown localid " << local_id << " host " << gMessageSystem->getSender() << LL_ENDL; mNumUnknownUpdates++; } } @@ -477,7 +494,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_ID, local_id, i); msg_size += sizeof(LLUUID); msg_size += sizeof(U32); - // llinfos << "Full Update, obj " << local_id << ", global ID" << fullid << "from " << mesgsys->getSender() << llendl; + // LL_INFOS() << "Full Update, obj " << local_id << ", global ID" << fullid << "from " << mesgsys->getSender() << LL_ENDL; } objectp = findObject(fullid); @@ -490,13 +507,13 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, { //if (objectp->getRegion()) //{ - // llinfos << "Local ID change: Removing object from table, local ID " << objectp->mLocalID + // LL_INFOS() << "Local ID change: Removing object from table, local ID " << objectp->mLocalID // << ", id from message " << local_id << ", from " // << LLHost(objectp->getRegion()->getHost().getAddress(), objectp->getRegion()->getHost().getPort()) // << ", full id " << fullid // << ", objects id " << objectp->getID() // << ", regionp " << (U32) regionp << ", object region " << (U32) objectp->getRegion() - // << llendl; + // << LL_ENDL; //} removeFromLocalIDTable(objectp); setUUIDAndLocal(fullid, @@ -521,7 +538,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, { if (update_type == OUT_TERSE_IMPROVED) { - // llinfos << "terse update for an unknown object (compressed):" << fullid << llendl; + // LL_INFOS() << "terse update for an unknown object (compressed):" << fullid << LL_ENDL; recorder.objectUpdateFailure(local_id, update_type, msg_size); continue; } @@ -533,7 +550,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, { if (update_type != OUT_FULL) { - //llinfos << "terse update for an unknown object:" << fullid << llendl; + //LL_INFOS() << "terse update for an unknown object:" << fullid << LL_ENDL; recorder.objectUpdateFailure(local_id, update_type, msg_size); continue; } @@ -546,7 +563,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, if (mDeadObjects.find(fullid) != mDeadObjects.end()) { mNumDeadObjectUpdates++; - //llinfos << "update for a dead object:" << fullid << llendl; + //LL_INFOS() << "update for a dead object:" << fullid << LL_ENDL; recorder.objectUpdateFailure(local_id, update_type, msg_size); continue; } @@ -556,7 +573,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, if(std::find(LLFloaterBlacklist::blacklist_objects.begin(), LLFloaterBlacklist::blacklist_objects.end(),fullid) != LLFloaterBlacklist::blacklist_objects.end()) { - llinfos << "Blacklisted object asset " << fullid.asString() << " blocked." << llendl; + //LL_INFOS() << "Blacklisted object asset " << fullid.asString() << " blocked." << LL_ENDL; continue; } @@ -564,7 +581,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, objectp = createObject(pcode, regionp, fullid, local_id, gMessageSystem->getSender()); if (!objectp) { - llinfos << "createObject failure for object: " << fullid << llendl; + LL_INFOS() << "createObject failure for object: " << fullid << LL_ENDL; recorder.objectUpdateFailure(local_id, update_type, msg_size); continue; } @@ -577,7 +594,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, if (objectp->isDead()) { - llwarns << "Dead object " << objectp->mID << " in UUID map 1!" << llendl; + LL_WARNS() << "Dead object " << objectp->mID << " in UUID map 1!" << LL_ENDL; } bool bCached = false; @@ -729,38 +746,35 @@ class LLObjectCostResponder : public LLHTTPClient::ResponderWithResult void clear_object_list_pending_requests() { // TODO*: No more hard coding - for ( - LLSD::array_iterator iter = mObjectIDs.beginArray(); - iter != mObjectIDs.endArray(); - ++iter) + for (auto const& id : mObjectIDs.array()) { - gObjectList.onObjectCostFetchFailure(iter->asUUID()); + gObjectList.onObjectCostFetchFailure(id.asUUID()); } } - /*virtual*/ void error(U32 statusNum, const std::string& reason) + /*virtual*/ void httpFailure(void) { - llwarns + LL_WARNS() << "Transport error requesting object cost " - << "HTTP status: " << statusNum << ", reason: " - << reason << "." << llendl; + << "HTTP status: " << mStatus << ", reason: " + << mReason << "." << LL_ENDL; // TODO*: Error message to user // For now just clear the request from the pending list clear_object_list_pending_requests(); } - /*virtual*/ void result(const LLSD& content) + /*virtual*/ void httpSuccess(void) { - if ( !content.isMap() || content.has("error") ) + if ( !mContent.isMap() || mContent.has("error") ) { // Improper response or the request had an error, // show an error to the user? - llwarns + LL_WARNS() << "Application level error when fetching object " - << "cost. Message: " << content["error"]["message"].asString() - << ", identifier: " << content["error"]["identifier"].asString() - << llendl; + << "cost. Message: " << mContent["error"]["message"].asString() + << ", identifier: " << mContent["error"]["identifier"].asString() + << LL_ENDL; // TODO*: Adaptively adjust request size if the // service says we've requested too many and retry @@ -772,23 +786,20 @@ class LLObjectCostResponder : public LLHTTPClient::ResponderWithResult // Success, grab the resource cost and linked set costs // for an object if one was returned - for ( - LLSD::array_iterator iter = mObjectIDs.beginArray(); - iter != mObjectIDs.endArray(); - ++iter) + for (auto const& entry : mObjectIDs.array()) { - LLUUID object_id = iter->asUUID(); + LLUUID object_id = entry.asUUID(); // Check to see if the request contains data for the object - if ( content.has(iter->asString()) ) + if ( mContent.has(entry.asString()) ) { F32 link_cost = - content[iter->asString()]["linked_set_resource_cost"].asReal(); + mContent[entry.asString()]["linked_set_resource_cost"].asReal(); F32 object_cost = - content[iter->asString()]["resource_cost"].asReal(); + mContent[entry.asString()]["resource_cost"].asReal(); - F32 physics_cost = content[iter->asString()]["physics_cost"].asReal(); - F32 link_physics_cost = content[iter->asString()]["linked_set_physics_cost"].asReal(); + F32 physics_cost = mContent[entry.asString()]["physics_cost"].asReal(); + F32 link_physics_cost = mContent[entry.asString()]["linked_set_physics_cost"].asReal(); gObjectList.updateObjectCost(object_id, object_cost, link_cost, physics_cost, link_physics_cost); } @@ -820,38 +831,35 @@ class LLPhysicsFlagsResponder : public LLHTTPClient::ResponderWithResult void clear_object_list_pending_requests() { // TODO*: No more hard coding - for ( - LLSD::array_iterator iter = mObjectIDs.beginArray(); - iter != mObjectIDs.endArray(); - ++iter) + for (auto const& id : mObjectIDs.array()) { - gObjectList.onPhysicsFlagsFetchFailure(iter->asUUID()); + gObjectList.onPhysicsFlagsFetchFailure(id.asUUID()); } } - /*virtual*/ void error(U32 statusNum, const std::string& reason) + /*virtual*/ void httpFailure(void) { - llwarns + LL_WARNS() << "Transport error requesting object physics flags " - << "HTTP status: " << statusNum << ", reason: " - << reason << "." << llendl; + << "HTTP status: " << mStatus << ", reason: " + << mReason << "." << LL_ENDL; // TODO*: Error message to user // For now just clear the request from the pending list clear_object_list_pending_requests(); } - /*virtual*/ void result(const LLSD& content) + /*virtual*/ void httpSuccess(void) { - if ( !content.isMap() || content.has("error") ) + if ( !mContent.isMap() || mContent.has("error") ) { // Improper response or the request had an error, // show an error to the user? - llwarns + LL_WARNS() << "Application level error when fetching object " - << "physics flags. Message: " << content["error"]["message"].asString() - << ", identifier: " << content["error"]["identifier"].asString() - << llendl; + << "physics flags. Message: " << mContent["error"]["message"].asString() + << ", identifier: " << mContent["error"]["identifier"].asString() + << LL_ENDL; // TODO*: Adaptively adjust request size if the // service says we've requested too many and retry @@ -863,17 +871,14 @@ class LLPhysicsFlagsResponder : public LLHTTPClient::ResponderWithResult // Success, grab the resource cost and linked set costs // for an object if one was returned - for ( - LLSD::array_iterator iter = mObjectIDs.beginArray(); - iter != mObjectIDs.endArray(); - ++iter) + for (auto const& entry : mObjectIDs.array()) { - LLUUID object_id = iter->asUUID(); + LLUUID object_id = entry.asUUID(); // Check to see if the request contains data for the object - if ( content.has(iter->asString()) ) + if (mContent.has(entry.asString())) { - const LLSD& data = content[iter->asString()]; + const LLSD& data = mContent[entry.asString()]; S32 shape_type = data["PhysicsShapeType"].asInteger(); @@ -920,7 +925,7 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world) phase_out_time < 0.0 || phase_out_time > interp_time) { - llwarns << "Invalid values for InterpolationTime or InterpolationPhaseOut, resetting to defaults" << llendl; + LL_WARNS() << "Invalid values for InterpolationTime or InterpolationPhaseOut, resetting to defaults" << LL_ENDL; interp_time = 3.0f; phase_out_time = 1.0f; } @@ -932,14 +937,14 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world) // update global timer F32 last_time = gFrameTimeSeconds; - U64 time = totalTime(); // this will become the new gFrameTime when the update is done + U64Microseconds time = totalTime(); // this will become the new gFrameTime when the update is done // Time _can_ go backwards, for example if the user changes the system clock. // It doesn't cause any fatal problems (just some oddness with stats), so we shouldn't assert here. // llassert(time > gFrameTime); - F64 time_diff = U64_to_F64(time - gFrameTime)/(F64)SEC_TO_MICROSEC; - gFrameTime = time; - F64 time_since_start = U64_to_F64(gFrameTime - gStartTime)/(F64)SEC_TO_MICROSEC; - gFrameTimeSeconds = (F32)time_since_start; + F64Seconds time_diff = time - gFrameTime; + gFrameTime = time; + F64Seconds time_since_start = gFrameTime - gStartTime; + gFrameTimeSeconds = time_since_start; gFrameIntervalSeconds = gFrameTimeSeconds - last_time; if (gFrameIntervalSeconds < 0.f) @@ -961,10 +966,10 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world) U32 idle_count = 0; - static LLFastTimer::DeclareTimer idle_copy("Idle Copy"); + static LLTrace::BlockTimerStatHandle idle_copy("Idle Copy"); { - LLFastTimer t(idle_copy); + LL_RECORD_BLOCK_TIME(idle_copy); for (std::vector >::iterator active_iter = mActiveObjects.begin(); active_iter != mActiveObjects.end(); active_iter++) @@ -985,7 +990,7 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world) else { // There shouldn't be any NULL pointers in the list, but they have caused // crashes before. This may be idleUpdate() messing with the list. - llwarns << "LLViewerObjectList::update has a NULL objectp" << llendl; + LL_WARNS() << "LLViewerObjectList::update has a NULL objectp" << LL_ENDL; } } } @@ -1024,7 +1029,10 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world) LLVolumeImplFlexible::updateClass(); //update animated textures - LLViewerTextureAnim::updateClass(); + if (gAnimateTextures) + { + LLViewerTextureAnim::updateClass(); + } } @@ -1042,7 +1050,7 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world) // don't factor frames that were paused into the stats if (! mWasPaused) { - LLViewerStats::getInstance()->updateFrameStats(time_diff); + LLViewerStats::getInstance()->updateFrameStats(time_diff.value()); } /* @@ -1117,7 +1125,7 @@ void LLViewerObjectList::fetchObjectCosts() U32 object_index = 0; for ( - std::set::iterator iter = mStaleObjectCost.begin(); + auto iter = mStaleObjectCost.begin(); iter != mStaleObjectCost.end(); ) { @@ -1175,7 +1183,7 @@ void LLViewerObjectList::fetchPhysicsFlags() U32 object_index = 0; for ( - std::set::iterator iter = mStalePhysicsFlags.begin(); + auto iter = mStalePhysicsFlags.begin(); iter != mStalePhysicsFlags.end(); ) { @@ -1216,6 +1224,17 @@ void LLViewerObjectList::fetchPhysicsFlags() } } +bool LLViewerObjectList::gotObjectPhysicsFlags(LLViewerObject* objectp) +{ + // This will insert objectp in mStalePhysicsFlags if needed: + objectp->getPhysicsShapeType(); + // Data has been retrieved if the object is not in either of the + // two lists: + const LLUUID& id = objectp->getID(); + return mPendingPhysicsFlags.count(id) == 0 && + mStalePhysicsFlags.count(id) == 0; +} + void LLViewerObjectList::clearDebugText() { for (vobj_list_t::iterator iter = mObjects.begin(); iter != mObjects.end(); ++iter) @@ -1232,9 +1251,11 @@ void LLViewerObjectList::clearDebugText() void LLViewerObjectList::cleanupReferences(LLViewerObject *objectp) { + bool new_dead_object = true; if (mDeadObjects.find(objectp->mID) != mDeadObjects.end()) { - llinfos << "Object " << objectp->mID << " already on dead list!" << llendl; + LL_INFOS() << "Object " << objectp->mID << " already on dead list!" << LL_ENDL; + new_dead_object = false; } else { @@ -1245,20 +1266,24 @@ void LLViewerObjectList::cleanupReferences(LLViewerObject *objectp) // Remove from object map so noone can look it up. mUUIDObjectMap.erase(objectp->mID); - mUUIDAvatarMap.erase(objectp->mID);//No need to be careful here. + // Use the return value (number of erased elements) to determine if we were an avatar. + if (mUUIDAvatarMap.erase(objectp->mID)) //No need to be careful here. + if (LLFloaterIMPanel* im = find_im_floater(objectp->mID)) + im->removeDynamicFocus(); + // //if (objectp->getRegion()) //{ - // llinfos << "cleanupReferences removing object from table, local ID " << objectp->mLocalID << ", ip " + // LL_INFOS() << "cleanupReferences removing object from table, local ID " << objectp->mLocalID << ", ip " // << objectp->getRegion()->getHost().getAddress() << ":" - // << objectp->getRegion()->getHost().getPort() << llendl; + // << objectp->getRegion()->getHost().getPort() << LL_ENDL; //} removeFromLocalIDTable(objectp); if (objectp->onActiveList()) { - //llinfos << "Removing " << objectp->mID << " " << objectp->getPCodeString() << " from active list in cleanupReferences." << llendl; + //LL_INFOS() << "Removing " << objectp->mID << " " << objectp->getPCodeString() << " from active list in cleanupReferences." << LL_ENDL; objectp->setOnActiveList(FALSE); removeFromActiveList(objectp); } @@ -1272,14 +1297,17 @@ void LLViewerObjectList::cleanupReferences(LLViewerObject *objectp) // Also, not cleaned up removeDrawable(objectp->mDrawable); - mNumDeadObjects++; + if(new_dead_object) + { + mNumDeadObjects++; + } } -static LLFastTimer::DeclareTimer FTM_REMOVE_DRAWABLE("Remove Drawable"); +static LLTrace::BlockTimerStatHandle FTM_REMOVE_DRAWABLE("Remove Drawable"); void LLViewerObjectList::removeDrawable(LLDrawable* drawablep) { - LLFastTimer t(FTM_REMOVE_DRAWABLE); + LL_RECORD_BLOCK_TIME(FTM_REMOVE_DRAWABLE); if (!drawablep) { @@ -1315,16 +1343,11 @@ BOOL LLViewerObjectList::killObject(LLViewerObject *objectp) if (objectp) { - if (objectp->isDead()) - { - // This object is already dead. Don't need to do more. - return TRUE; - } - else - { - objectp->markDead(); - } - + // We are going to cleanup a lot of smart pointers to this object, they might be last, + // and object being NULLed while inside it's own function won't be pretty + // so create a pointer to make sure object will stay alive untill markDead() finishes + LLPointer sp(objectp); + sp->markDead(); // does the right thing if object already dead return TRUE; } return FALSE; @@ -1349,7 +1372,7 @@ void LLViewerObjectList::killObjects(LLViewerRegion *regionp) // Have to clean right away because the region is becoming invalid. cleanDeadObjects(FALSE); - llinfos << "Removed " << count << " objects for region " << regionp->getName() << ". (" << kill_timer.getElapsedTimeF64()*1000.0 << "ms)" << llendl; + LL_INFOS() << "Removed " << count << " objects for region " << regionp->getName() << ". (" << kill_timer.getElapsedTimeF64()*1000.0 << "ms)" << LL_ENDL; } void LLViewerObjectList::killAllObjects() @@ -1370,19 +1393,19 @@ void LLViewerObjectList::killAllObjects() if(!mObjects.empty()) { - llwarns << "LLViewerObjectList::killAllObjects still has entries in mObjects: " << mObjects.size() << llendl; + LL_WARNS() << "LLViewerObjectList::killAllObjects still has entries in mObjects: " << mObjects.size() << LL_ENDL; mObjects.clear(); } if (!mActiveObjects.empty()) { - llwarns << "Some objects still on active object list!" << llendl; + LL_WARNS() << "Some objects still on active object list!" << LL_ENDL; mActiveObjects.clear(); } if (!mMapObjects.empty()) { - llwarns << "Some objects still on map object list!" << llendl; + LL_WARNS() << "Some objects still on map object list!" << LL_ENDL; mMapObjects.clear(); } } @@ -1459,15 +1482,10 @@ void LLViewerObjectList::removeFromActiveList(LLViewerObject* objectp) objectp->setListIndex(-1); - S32 last_index = mActiveObjects.size()-1; - - if (idx != last_index) - { - mActiveObjects[idx] = mActiveObjects[last_index]; - mActiveObjects[idx]->setListIndex(idx); - } + std::vector >::iterator iter = vector_replace_with_last(mActiveObjects, mActiveObjects.begin() + idx); + if(iter != mActiveObjects.end()) + (*iter)->setListIndex(idx); - mActiveObjects.pop_back(); } } @@ -1483,7 +1501,7 @@ void LLViewerObjectList::updateActive(LLViewerObject *objectp) { if (active) { - //llinfos << "Adding " << objectp->mID << " " << objectp->getPCodeString() << " to active list." << llendl; + //LL_INFOS() << "Adding " << objectp->mID << " " << objectp->getPCodeString() << " to active list." << LL_ENDL; S32 idx = objectp->getListIndex(); if (idx <= -1) { @@ -1499,13 +1517,13 @@ void LLViewerObjectList::updateActive(LLViewerObject *objectp) if (idx >= (S32)mActiveObjects.size() || mActiveObjects[idx] != objectp) { - llwarns << "Invalid object list index detected!" << llendl; + LL_WARNS() << "Invalid object list index detected!" << LL_ENDL; } } } else { - //llinfos << "Removing " << objectp->mID << " " << objectp->getPCodeString() << " from active list." << llendl; + //LL_INFOS() << "Removing " << objectp->mID << " " << objectp->getPCodeString() << " from active list." << LL_ENDL; removeFromActiveList(objectp); objectp->setOnActiveList(FALSE); } @@ -1540,7 +1558,7 @@ void LLViewerObjectList::updateObjectCost(const LLUUID& object_id, F32 object_co void LLViewerObjectList::onObjectCostFetchFailure(const LLUUID& object_id) { - //llwarns << "Failed to fetch object cost for object: " << object_id << llendl; + //LL_WARNS() << "Failed to fetch object cost for object: " << object_id << LL_ENDL; mPendingObjectCost.erase(object_id); } @@ -1579,13 +1597,13 @@ void LLViewerObjectList::updatePhysicsProperties(const LLUUID& object_id, void LLViewerObjectList::onPhysicsFlagsFetchFailure(const LLUUID& object_id) { - //llwarns << "Failed to fetch physics flags for object: " << object_id << llendl; + //LL_WARNS() << "Failed to fetch physics flags for object: " << object_id << LL_ENDL; mPendingPhysicsFlags.erase(object_id); } -static LLFastTimer::DeclareTimer FTM_SHIFT_OBJECTS("Shift Objects"); -static LLFastTimer::DeclareTimer FTM_PIPELINE_SHIFT("Pipeline Shift"); -static LLFastTimer::DeclareTimer FTM_REGION_SHIFT("Region Shift"); +static LLTrace::BlockTimerStatHandle FTM_SHIFT_OBJECTS("Shift Objects"); +static LLTrace::BlockTimerStatHandle FTM_PIPELINE_SHIFT("Pipeline Shift"); +static LLTrace::BlockTimerStatHandle FTM_REGION_SHIFT("Region Shift"); void LLViewerObjectList::shiftObjects(const LLVector3 &offset) { @@ -1598,7 +1616,7 @@ void LLViewerObjectList::shiftObjects(const LLVector3 &offset) return; } - LLFastTimer t(FTM_SHIFT_OBJECTS); + LL_RECORD_BLOCK_TIME(FTM_SHIFT_OBJECTS); LLViewerObject *objectp; for (vobj_list_t::iterator iter = mObjects.begin(); iter != mObjects.end(); ++iter) @@ -1617,12 +1635,12 @@ void LLViewerObjectList::shiftObjects(const LLVector3 &offset) } { - LLFastTimer t(FTM_PIPELINE_SHIFT); + LL_RECORD_BLOCK_TIME(FTM_PIPELINE_SHIFT); gPipeline.shiftObjects(offset); } { - LLFastTimer t(FTM_REGION_SHIFT); + LL_RECORD_BLOCK_TIME(FTM_REGION_SHIFT); LLWorld::getInstance()->shiftRegions(offset); } } @@ -1682,7 +1700,7 @@ void LLViewerObjectList::clearAllMapObjectsInRegion(LLViewerRegion* regionp) if(dead_object_list.size() > 0) { - llwarns << "There are " << dead_object_list.size() << " dead objects on the map!" << llendl ; + LL_WARNS() << "There are " << dead_object_list.size() << " dead objects on the map!" << LL_ENDL ; for(std::set::iterator iter = dead_object_list.begin(); iter != dead_object_list.end(); ++iter) { @@ -1691,7 +1709,7 @@ void LLViewerObjectList::clearAllMapObjectsInRegion(LLViewerRegion* regionp) } if(region_object_list.size() > 0) { - llwarns << "There are " << region_object_list.size() << " objects not removed from the deleted region!" << llendl ; + LL_WARNS() << "There are " << region_object_list.size() << " objects not removed from the deleted region!" << LL_ENDL ; for(std::set::iterator iter = region_object_list.begin(); iter != region_object_list.end(); ++iter) { @@ -1714,8 +1732,8 @@ void LLViewerObjectList::renderObjectsForMap(LLNetMap &netmap) F32 max_radius = gSavedSettings.getF32("MiniMapPrimMaxRadius"); - static const F32 MAX_ALTITUDE_ABOVE_SELF = 256.f; - F32 max_altitude = gAgent.getPositionGlobal()[VZ] + MAX_ALTITUDE_ABOVE_SELF; + const F32 agent_altitude(gAgent.getPositionGlobal()[VZ]); + static const LLCachedControl delta("MiniMapPrimMaxAltitudeDelta"); for (vobj_list_t::iterator iter = mMapObjects.begin(); iter != mMapObjects.end(); ++iter) { @@ -1743,6 +1761,10 @@ void LLViewerObjectList::renderObjectsForMap(LLNetMap &netmap) LLColor4U color = above_water_color; if( objectp->permYouOwner() ) { + static const LLCachedControl delta("MiniMapPrimMaxAltitudeDeltaOwn"); + if (delta && static_cast(std::fabs(agent_altitude - pos[VZ])) > delta) + continue; + const F32 MIN_RADIUS_FOR_OWNED_OBJECTS = 2.f; if( approx_radius < MIN_RADIUS_FOR_OWNED_OBJECTS ) { @@ -1772,7 +1794,7 @@ void LLViewerObjectList::renderObjectsForMap(LLNetMap &netmap) } } } - else if ( pos[VZ] > max_altitude ) + else if (delta && static_cast(std::fabs(agent_altitude - pos[VZ])) > delta) { continue; } @@ -1815,7 +1837,7 @@ void LLViewerObjectList::generatePickList(LLCamera &camera) LLSpatialPartition* part = region->getSpatialPartition(i); if (part) { - part->cull(camera, &pick_drawables, TRUE); + part->cull(camera, &pick_drawables); } } } @@ -1951,24 +1973,30 @@ void LLViewerObjectList::resetObjectBeacons() mDebugBeacons.clear(); } -LLViewerObject *LLViewerObjectList::createObjectViewer(const LLPCode pcode, LLViewerRegion *regionp) +LLViewerObject *LLViewerObjectList::createObjectViewer(const LLPCode pcode, LLViewerRegion *regionp, S32 flags) { LLUUID fullid; fullid.generate(); - LLViewerObject *objectp = LLViewerObject::createObject(fullid, pcode, regionp); + LLViewerObject *objectp = LLViewerObject::createObject(fullid, pcode, regionp, flags); if (!objectp) { -// llwarns << "Couldn't create object of type " << LLPrimitive::pCodeToString(pcode) << llendl; +// LL_WARNS() << "Couldn't create object of type " << LLPrimitive::pCodeToString(pcode) << LL_ENDL; return NULL; } - mUUIDObjectMap[fullid] = objectp; + mUUIDObjectMap.insert_or_assign(fullid, objectp); if(objectp->isAvatar()) { LLVOAvatar *pAvatar = dynamic_cast(objectp); if(pAvatar) - mUUIDAvatarMap[fullid] = pAvatar; + { + mUUIDAvatarMap.insert_or_assign(fullid, pAvatar); + // + if (LLFloaterIMPanel* im = find_im_floater(fullid)) + im->addDynamicFocus(); + // + } } mObjects.push_back(objectp); @@ -1979,12 +2007,12 @@ LLViewerObject *LLViewerObjectList::createObjectViewer(const LLPCode pcode, LLVi } -static LLFastTimer::DeclareTimer FTM_CREATE_OBJECT("Create Object"); +static LLTrace::BlockTimerStatHandle FTM_CREATE_OBJECT("Create Object"); LLViewerObject *LLViewerObjectList::createObject(const LLPCode pcode, LLViewerRegion *regionp, const LLUUID &uuid, const U32 local_id, const LLHost &sender) { - LLFastTimer t(FTM_CREATE_OBJECT); + LL_RECORD_BLOCK_TIME(FTM_CREATE_OBJECT); LLUUID fullid; if (uuid == LLUUID::null) @@ -1999,16 +2027,26 @@ LLViewerObject *LLViewerObjectList::createObject(const LLPCode pcode, LLViewerRe LLViewerObject *objectp = LLViewerObject::createObject(fullid, pcode, regionp); if (!objectp) { -// llwarns << "Couldn't create object of type " << LLPrimitive::pCodeToString(pcode) << " id:" << fullid << llendl; +// LL_WARNS() << "Couldn't create object of type " << LLPrimitive::pCodeToString(pcode) << " id:" << fullid << LL_ENDL; return NULL; } + if(regionp) + { + regionp->addToCreatedList(local_id); + } - mUUIDObjectMap[fullid] = objectp; + mUUIDObjectMap.insert_or_assign(fullid, objectp); if(objectp->isAvatar()) { LLVOAvatar *pAvatar = dynamic_cast(objectp); if(pAvatar) - mUUIDAvatarMap[fullid] = pAvatar; + { + mUUIDAvatarMap.insert_or_assign(fullid, pAvatar); + // + if (LLFloaterIMPanel* im = find_im_floater(fullid)) + im->addDynamicFocus(); + // + } } setUUIDAndLocal(fullid, local_id, @@ -2055,7 +2093,7 @@ S32 LLViewerObjectList::findReferences(LLDrawable *drawablep) const void LLViewerObjectList::orphanize(LLViewerObject *childp, U32 parent_id, U32 ip, U32 port) { #ifdef ORPHAN_SPAM - llinfos << "Orphaning object " << childp->getID() << " with parent " << parent_id << llendl; + LL_INFOS() << "Orphaning object " << childp->getID() << " with parent " << parent_id << LL_ENDL; #endif // We're an orphan, flag things appropriately. @@ -2072,7 +2110,7 @@ void LLViewerObjectList::orphanize(LLViewerObject *childp, U32 parent_id, U32 ip // object probably ISN'T being reparented, but just got an object // update out of order (child update before parent). make_invisible = false; - //llinfos << "Don't make object handoffs invisible!" << llendl; + //LL_INFOS() << "Don't make object handoffs invisible!" << LL_ENDL; } } @@ -2109,8 +2147,8 @@ void LLViewerObjectList::findOrphans(LLViewerObject* objectp, U32 ip, U32 port) if (objectp->isDead()) { - llwarns << "Trying to find orphans for dead obj " << objectp->mID - << ":" << objectp->getPCodeString() << llendl; + LL_WARNS() << "Trying to find orphans for dead obj " << objectp->mID + << ":" << objectp->getPCodeString() << LL_ENDL; return; } @@ -2144,16 +2182,16 @@ void LLViewerObjectList::findOrphans(LLViewerObject* objectp, U32 ip, U32 port) { if (childp == objectp) { - llwarns << objectp->mID << " has self as parent, skipping!" - << llendl; + LL_WARNS() << objectp->mID << " has self as parent, skipping!" + << LL_ENDL; continue; } #ifdef ORPHAN_SPAM - llinfos << "Reunited parent " << objectp->mID - << " with child " << childp->mID << llendl; - llinfos << "Glob: " << objectp->getPositionGlobal() << llendl; - llinfos << "Agent: " << objectp->getPositionAgent() << llendl; + LL_INFOS() << "Reunited parent " << objectp->mID + << " with child " << childp->mID << LL_ENDL; + LL_INFOS() << "Glob: " << objectp->getPositionGlobal() << LL_ENDL; + LL_INFOS() << "Agent: " << objectp->getPositionAgent() << LL_ENDL; addDebugBeacon(objectp->getPositionAgent(),""); #endif gPipeline.markMoved(objectp->mDrawable); @@ -2178,7 +2216,7 @@ void LLViewerObjectList::findOrphans(LLViewerObject* objectp, U32 ip, U32 port) } else { - llinfos << "Missing orphan child, removing from list" << llendl; + LL_INFOS() << "Missing orphan child, removing from list" << LL_ENDL; iter = mOrphanChildren.erase(iter); } diff --git a/indra/newview/llviewerobjectlist.h b/indra/newview/llviewerobjectlist.h index c5b6b98f65..6ff21d3e53 100644 --- a/indra/newview/llviewerobjectlist.h +++ b/indra/newview/llviewerobjectlist.h @@ -36,10 +36,11 @@ #include #include +#include "absl/container/flat_hash_map.h" + // common includes #include "llstat.h" #include "llstring.h" -#include "sguuidhash.h" // project includes #include "llviewerobject.h" @@ -49,15 +50,15 @@ class LLCamera; class LLNetMap; class LLDebugBeacon; -const U32 CLOSE_BIN_SIZE = 10; -const U32 NUM_BINS = 128; +constexpr U32 CLOSE_BIN_SIZE = 10; +constexpr U32 NUM_BINS = 128; // GL name = position in object list + GL_NAME_INDEX_OFFSET so that // we can have special numbers like zero. -const U32 GL_NAME_LAND = 0; -const U32 GL_NAME_PARCEL_WALL = 1; +constexpr U32 GL_NAME_LAND = 0; +constexpr U32 GL_NAME_PARCEL_WALL = 1; -const U32 GL_NAME_INDEX_OFFSET = 10; +constexpr U32 GL_NAME_INDEX_OFFSET = 10; class LLViewerObjectList { @@ -75,7 +76,7 @@ class LLViewerObjectList inline LLViewerObject *findObject(const LLUUID &id) const; inline LLVOAvatar *findAvatar(const LLUUID &id) const; - LLViewerObject *createObjectViewer(const LLPCode pcode, LLViewerRegion *regionp); // Create a viewer-side object + LLViewerObject *createObjectViewer(const LLPCode pcode, LLViewerRegion *regionp, S32 flags = 0); // Create a viewer-side object LLViewerObject *createObject(const LLPCode pcode, LLViewerRegion *regionp, const LLUUID &uuid, const U32 local_id, const LLHost &sender); @@ -99,6 +100,8 @@ class LLViewerObjectList void fetchObjectCosts(); void fetchPhysicsFlags(); + bool gotObjectPhysicsFlags(LLViewerObject* objectp); + void updateObjectCost(LLViewerObject* object); void updateObjectCost(const LLUUID& object_id, F32 object_cost, F32 link_cost, F32 physics_cost, F32 link_physics_cost); void onObjectCostFetchFailure(const LLUUID& object_id); @@ -140,6 +143,7 @@ class LLViewerObjectList LLViewerObject *getSelectedObject(const U32 object_id); inline S32 getNumObjects() { return (S32) mObjects.size(); } + inline S32 getNumActiveObjects() { return (S32) mActiveObjects.size(); } void addToMap(LLViewerObject *objectp); void removeFromMap(LLViewerObject *objectp); @@ -215,18 +219,18 @@ class LLViewerObjectList vobj_list_t mMapObjects; - std::set mDeadObjects; + uuid_set_t mDeadObjects; - boost::unordered_map > mUUIDObjectMap; - boost::unordered_map > mUUIDAvatarMap; + absl::flat_hash_map > mUUIDObjectMap; + absl::flat_hash_map > mUUIDAvatarMap; //set of objects that need to update their cost - std::set mStaleObjectCost; - std::set mPendingObjectCost; + uuid_set_t mStaleObjectCost; + uuid_set_t mPendingObjectCost; //set of objects that need to update their physics flags - std::set mStalePhysicsFlags; - std::set mPendingPhysicsFlags; + uuid_set_t mStalePhysicsFlags; + uuid_set_t mPendingPhysicsFlags; std::vector mDebugBeacons; @@ -270,8 +274,8 @@ extern LLViewerObjectList gObjectList; // Inlines inline LLViewerObject *LLViewerObjectList::findObject(const LLUUID &id) const { - boost::unordered_map >::const_iterator iter = mUUIDObjectMap.find(id); - if(iter != mUUIDObjectMap.end()) + auto iter = mUUIDObjectMap.find(id); + if(iter != mUUIDObjectMap.cend()) { return iter->second; } @@ -283,8 +287,8 @@ inline LLViewerObject *LLViewerObjectList::findObject(const LLUUID &id) const inline LLVOAvatar *LLViewerObjectList::findAvatar(const LLUUID &id) const { - boost::unordered_map >::const_iterator iter = mUUIDAvatarMap.find(id); - return (iter != mUUIDAvatarMap.end()) ? iter->second.get() : NULL; + auto iter = mUUIDAvatarMap.find(id); + return (iter != mUUIDAvatarMap.cend()) ? iter->second.get() : NULL; } inline LLViewerObject *LLViewerObjectList::getObject(const S32 index) @@ -293,7 +297,7 @@ inline LLViewerObject *LLViewerObjectList::getObject(const S32 index) objectp = mObjects[index]; if (objectp->isDead()) { - //llwarns << "Dead object " << objectp->mID << " in getObject" << llendl; + //LL_WARNS() << "Dead object " << objectp->mID << " in getObject" << LL_ENDL; return NULL; } return objectp; diff --git a/indra/newview/llvieweroctree.cpp b/indra/newview/llvieweroctree.cpp new file mode 100644 index 0000000000..e810e6c529 --- /dev/null +++ b/indra/newview/llvieweroctree.cpp @@ -0,0 +1,1529 @@ +/** + * @file llvieweroctree.cpp + * @brief LLViewerOctreeGroup class implementation and supporting functions + * + * $LicenseInfo:firstyear=2003&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llvieweroctree.h" +#include "llviewerregion.h" +#include "pipeline.h" +#include "llviewercontrol.h" +#include "llappviewer.h" +#include "llglslshader.h" +#include "llviewershadermgr.h" +#include "lltexturecache.h" +#include "llimageworker.h" +#include "lltexturefetch.h" + +//----------------------------------------------------------------------------------- +//static variables definitions +//----------------------------------------------------------------------------------- +U32 LLViewerOctreeEntryData::sCurVisible = 10; //reserve the low numbers for special use. + +//----------------------------------------------------------------------------------- +//some global functions definitions +//----------------------------------------------------------------------------------- +typedef enum +{ + b000 = 0x00, + b001 = 0x01, + b010 = 0x02, + b011 = 0x03, + b100 = 0x04, + b101 = 0x05, + b110 = 0x06, + b111 = 0x07, +} eLoveTheBits; + +//contact Runitai Linden for a copy of the SL object used to write this table +//basically, you give the table a bitmask of the look-at vector to a node and it +//gives you a triangle fan index array +static U16 sOcclusionIndices[] = +{ + //000 + b111, b110, b010, b011, b001, b101, b100, b110, + //001 + b011, b010, b000, b001, b101, b111, b110, b010, + //010 + b101, b100, b110, b111, b011, b001, b000, b100, + //011 + b001, b000, b100, b101, b111, b011, b010, b000, + //100 + b110, b000, b010, b011, b111, b101, b100, b000, + //101 + b010, b100, b000, b001, b011, b111, b110, b100, + //110 + b100, b010, b110, b111, b101, b001, b000, b010, + //111 + b000, b110, b100, b101, b001, b011, b010, b110, +}; + +U32 get_box_fan_indices(LLCamera* camera, const LLVector4a& center) +{ + LLVector4a origin; + origin.load3(camera->getOrigin().mV); + + S32 cypher = center.greaterThan(origin).getGatheredBits() & 0x7; + + return cypher*8; +} + +U8* get_box_fan_indices_ptr(LLCamera* camera, const LLVector4a& center) +{ + LLVector4a origin; + origin.load3(camera->getOrigin().mV); + + S32 cypher = center.greaterThan(origin).getGatheredBits() & 0x7; + + return (U8*) (sOcclusionIndices+cypher*8); +} + +//create a vertex buffer for efficiently rendering cubes +LLVertexBuffer* ll_create_cube_vb(U32 type_mask, U32 usage) +{ + LLVertexBuffer* ret = new LLVertexBuffer(type_mask, usage); + + ret->allocateBuffer(8, 64, true); + + LLStrider pos; + LLStrider idx; + + ret->getVertexStrider(pos); + ret->getIndexStrider(idx); + + pos[0] = LLVector3(-1,-1,-1); + pos[1] = LLVector3(-1,-1, 1); + pos[2] = LLVector3(-1, 1,-1); + pos[3] = LLVector3(-1, 1, 1); + pos[4] = LLVector3( 1,-1,-1); + pos[5] = LLVector3( 1,-1, 1); + pos[6] = LLVector3( 1, 1,-1); + pos[7] = LLVector3( 1, 1, 1); + + for (U32 i = 0; i < 64; i++) + { + idx[i] = sOcclusionIndices[i]; + } + + ret->flush(); + + return ret; +} + + +#define LL_TRACK_PENDING_OCCLUSION_QUERIES 0 + +const F32 SG_OCCLUSION_FUDGE = 0.25f; +#define SG_DISCARD_TOLERANCE 0.01f + + +S32 AABBSphereIntersect(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &rad) +{ + return AABBSphereIntersectR2(min, max, origin, rad*rad); +} + +S32 AABBSphereIntersectR2(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &r) +{ + F32 d = 0.f; + F32 t; + + if ((min-origin).magVecSquared() < r && + (max-origin).magVecSquared() < r) + { + return 2; + } + + for (U32 i = 0; i < 3; i++) + { + if (origin.mV[i] < min.mV[i]) + { + t = min.mV[i] - origin.mV[i]; + d += t*t; + } + else if (origin.mV[i] > max.mV[i]) + { + t = origin.mV[i] - max.mV[i]; + d += t*t; + } + + if (d > r) + { + return 0; + } + } + + return 1; +} + + +S32 AABBSphereIntersect(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &rad) +{ + return AABBSphereIntersectR2(min, max, origin, rad*rad); +} + +S32 AABBSphereIntersectR2(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &r) +{ + F32 d = 0.f; + F32 t; + + LLVector4a origina; + origina.load3(origin.mV); + + LLVector4a v; + v.setSub(min, origina); + + if (v.dot3(v) < r) + { + v.setSub(max, origina); + if (v.dot3(v) < r) + { + return 2; + } + } + + + for (U32 i = 0; i < 3; i++) + { + if (origin.mV[i] < min[i]) + { + t = min[i] - origin.mV[i]; + d += t*t; + } + else if (origin.mV[i] > max[i]) + { + t = origin.mV[i] - max[i]; + d += t*t; + } + + if (d > r) + { + return 0; + } + } + + return 1; +} + +//----------------------------------------------------------------------------------- +//class LLViewerOctreeEntry definitions +//----------------------------------------------------------------------------------- +LLViewerOctreeEntry::LLViewerOctreeEntry() : + mGroup(NULL), + mBinRadius(0.f), + mBinIndex(-1), + mVisible(0) +{ + mPositionGroup.clear(); + mExtents[0].clear(); + mExtents[1].clear(); + + for(S32 i = 0; i < NUM_DATA_TYPE; i++) + { + mData[i] = NULL; + } +} + +LLViewerOctreeEntry::~LLViewerOctreeEntry() +{ + llassert(!mGroup); +} + +void LLViewerOctreeEntry::addData(LLViewerOctreeEntryData* data) +{ + //llassert(mData[data->getDataType()] == NULL); + llassert(data != NULL); + + mData[data->getDataType()] = data; +} + +void LLViewerOctreeEntry::removeData(LLViewerOctreeEntryData* data) +{ + //llassert(data->getDataType() != LLVOCACHEENTRY); //can not remove VOCache entry + + if(!mData[data->getDataType()]) + { + return; + } + if(mData[data->getDataType()] != data) + { + return; + } + + mData[data->getDataType()] = NULL; + + if(!mGroup.isNull() && !mData[LLDRAWABLE]) + { + mGroup->removeFromGroup(data); + mGroup = NULL; + + llassert(mBinIndex == -1); + } +} + +//called by group handleDestruction() ONLY when group is destroyed by octree. +void LLViewerOctreeEntry::nullGroup() +{ + mGroup = NULL; +} + +void LLViewerOctreeEntry::setGroup(LLViewerOctreeGroup* group) +{ + if(mGroup == group) + { + return; + } + + if(mGroup) + { + LLViewerOctreeGroup* old_group = mGroup; + mGroup = NULL; + old_group->removeFromGroup(this); + + llassert(mBinIndex == -1); + } + + mGroup = group; +} + +//----------------------------------------------------------------------------------- +//class LLViewerOctreeEntryData definitions +//----------------------------------------------------------------------------------- +LLViewerOctreeEntryData::~LLViewerOctreeEntryData() +{ + if(mEntry) + { + mEntry->removeData(this); + } +} + +LLViewerOctreeEntryData::LLViewerOctreeEntryData(LLViewerOctreeEntry::eEntryDataType_t data_type) + : mDataType(data_type), + mEntry(NULL) +{ +} + +//virtual +void LLViewerOctreeEntryData::setOctreeEntry(LLViewerOctreeEntry* entry) +{ + llassert_always(mEntry.isNull()); + + if(mEntry.notNull()) + { + return; + } + + if(!entry) + { + mEntry = new LLViewerOctreeEntry(); + } + else + { + mEntry = entry; + } + mEntry->addData(this); +} + +void LLViewerOctreeEntryData::removeOctreeEntry() +{ + if(mEntry) + { + mEntry->removeData(this); + mEntry = NULL; + } +} + +void LLViewerOctreeEntryData::setSpatialExtents(const LLVector3& min, const LLVector3& max) +{ + mEntry->mExtents[0].load3(min.mV); + mEntry->mExtents[1].load3(max.mV); +} + +void LLViewerOctreeEntryData::setSpatialExtents(const LLVector4a& min, const LLVector4a& max) +{ + mEntry->mExtents[0] = min; + mEntry->mExtents[1] = max; +} + +void LLViewerOctreeEntryData::setPositionGroup(const LLVector4a& pos) +{ + mEntry->mPositionGroup = pos; +} + +const LLVector4a* LLViewerOctreeEntryData::getSpatialExtents() const +{ + return mEntry->getSpatialExtents(); +} +//virtual +void LLViewerOctreeEntryData::setGroup(LLViewerOctreeGroup* group) +{ + mEntry->setGroup(group); +} + +void LLViewerOctreeEntryData::shift(const LLVector4a &shift_vector) +{ + mEntry->mExtents[0].add(shift_vector); + mEntry->mExtents[1].add(shift_vector); + mEntry->mPositionGroup.add(shift_vector); +} + +LLViewerOctreeGroup* LLViewerOctreeEntryData::getGroup()const +{ + return mEntry.notNull() ? mEntry->mGroup : LLPointer(); +} + +const LLVector4a& LLViewerOctreeEntryData::getPositionGroup() const +{ + return mEntry->getPositionGroup(); +} + +//virtual +bool LLViewerOctreeEntryData::isVisible() const +{ + if(mEntry) + { + return mEntry->mVisible == sCurVisible; + } + return false; +} + +//virtual +bool LLViewerOctreeEntryData::isRecentlyVisible() const +{ + if(!mEntry) + { + return false; + } + + if(isVisible()) + { + return true; + } + if(getGroup() && getGroup()->isRecentlyVisible()) + { + setVisible(); + return true; + } + + return false; +} + +void LLViewerOctreeEntryData::setVisible() const +{ + if(mEntry) + { + mEntry->mVisible = sCurVisible; + } +} + +void LLViewerOctreeEntryData::resetVisible() const +{ + if(mEntry) + { + mEntry->mVisible = 0; + } +} +//----------------------------------------------------------------------------------- +//class LLViewerOctreeGroup definitions +//----------------------------------------------------------------------------------- + +LLViewerOctreeGroup::~LLViewerOctreeGroup() +{ + //empty here +} + +LLViewerOctreeGroup::LLViewerOctreeGroup(OctreeNode* node) : + mOctreeNode(node), + mAnyVisible(0), + mState(CLEAN) +{ + LLVector4a tmp; + tmp.splat(0.f); + mExtents[0] = mExtents[1] = mObjectBounds[0] = mObjectBounds[1] = + mObjectExtents[0] = mObjectExtents[1] = tmp; + + mBounds[0] = node->getCenter(); + mBounds[1] = node->getSize(); + + mOctreeNode->addListener(this); + + for (U32 i = 0; i < sizeof(mVisible) / sizeof(mVisible[0]); i++) + { + mVisible[i] = 0; + } +} + +bool LLViewerOctreeGroup::hasElement(LLViewerOctreeEntryData* data) +{ + if(!data->getEntry()) + { + return false; + } + return std::find(getDataBegin(), getDataEnd(), data->getEntry()) != getDataEnd(); +} +bool LLViewerOctreeGroup::removeFromGroup(LLViewerOctreeEntryData* data) +{ + return removeFromGroup(data->getEntry()); +} + +bool LLViewerOctreeGroup::removeFromGroup(LLViewerOctreeEntry* entry) +{ + llassert(entry != NULL); + llassert(!entry->getGroup()); + + if(isDead()) //group is about to be destroyed, not need to double delete the entry. + { + entry->setBinIndex(-1); + return true; + } + + unbound(); + setState(OBJECT_DIRTY); + + if (mOctreeNode) + { + if (!mOctreeNode->remove(entry)) //this could cause *this* pointer to be destroyed, so no more function calls after this. + { + OCT_ERRS << "Could not remove LLVOCacheEntry from LLVOCacheOctreeGroup" << LL_ENDL; + return false; + } + } + + return true; +} + +//virtual +void LLViewerOctreeGroup::unbound() +{ + if (isDirty()) + { + return; + } + + setState(DIRTY); + + //all the parent nodes need to rebound this child + if (mOctreeNode) + { + OctreeNode* parent = (OctreeNode*) mOctreeNode->getParent(); + while (parent != NULL) + { + LLViewerOctreeGroup* group = (LLViewerOctreeGroup*) parent->getListener(0); + if (!group || group->isDirty()) + { + return; + } + + group->setState(DIRTY); + parent = (OctreeNode*) parent->getParent(); + } + } +} + +//virtual +void LLViewerOctreeGroup::rebound() +{ + if (!isDirty()) + { + return; + } + + if (mOctreeNode->getChildCount() == 1 && mOctreeNode->getElementCount() == 0) + { + LLViewerOctreeGroup* group = (LLViewerOctreeGroup*) mOctreeNode->getChild(0)->getListener(0); + group->rebound(); + + //copy single child's bounding box + mBounds[0] = group->mBounds[0]; + mBounds[1] = group->mBounds[1]; + mExtents[0] = group->mExtents[0]; + mExtents[1] = group->mExtents[1]; + + group->setState(SKIP_FRUSTUM_CHECK); + } + else if (mOctreeNode->isLeaf()) + { //copy object bounding box if this is a leaf + boundObjects(TRUE, mExtents[0], mExtents[1]); + mBounds[0] = mObjectBounds[0]; + mBounds[1] = mObjectBounds[1]; + } + else + { + LLVector4a& newMin = mExtents[0]; + LLVector4a& newMax = mExtents[1]; + LLViewerOctreeGroup* group = (LLViewerOctreeGroup*) mOctreeNode->getChild(0)->getListener(0); + group->clearState(SKIP_FRUSTUM_CHECK); + group->rebound(); + //initialize to first child + newMin = group->mExtents[0]; + newMax = group->mExtents[1]; + + //first, rebound children + for (U32 i = 1; i < mOctreeNode->getChildCount(); i++) + { + group = (LLViewerOctreeGroup*) mOctreeNode->getChild(i)->getListener(0); + group->clearState(SKIP_FRUSTUM_CHECK); + group->rebound(); + const LLVector4a& max = group->mExtents[1]; + const LLVector4a& min = group->mExtents[0]; + + newMax.setMax(newMax, max); + newMin.setMin(newMin, min); + } + + boundObjects(FALSE, newMin, newMax); + + mBounds[0].setAdd(newMin, newMax); + mBounds[0].mul(0.5f); + mBounds[1].setSub(newMax, newMin); + mBounds[1].mul(0.5f); + } + + clearState(DIRTY); + + return; +} + +//virtual +void LLViewerOctreeGroup::handleInsertion(const TreeNode* node, LLViewerOctreeEntry* obj) +{ + obj->setGroup(this); + unbound(); + setState(OBJECT_DIRTY); +} + +//virtual +void LLViewerOctreeGroup::handleRemoval(const TreeNode* node, LLViewerOctreeEntry* obj) +{ + unbound(); + setState(OBJECT_DIRTY); + + obj->setGroup(NULL); //this could cause *this* pointer to be destroyed. So no more function calls after this. +} + +//virtual +void LLViewerOctreeGroup::handleDestruction(const TreeNode* node) +{ + for (OctreeNode::element_iter i = mOctreeNode->getDataBegin(); i != mOctreeNode->getDataEnd(); ++i) + { + LLViewerOctreeEntry* obj = *i; + if (obj && obj->getGroup() == this) + { + obj->nullGroup(); + //obj->setGroup(NULL); + } + } + mOctreeNode = NULL; +} + +//virtual +void LLViewerOctreeGroup::handleChildAddition(const OctreeNode* parent, OctreeNode* child) +{ + if (child->getListenerCount() == 0) + { + new LLViewerOctreeGroup(child); + } + else + { + OCT_ERRS << "LLViewerOctreeGroup redundancy detected." << LL_ENDL; + } + + unbound(); + + ((LLViewerOctreeGroup*)child->getListener(0))->unbound(); +} + +//virtual +void LLViewerOctreeGroup::handleChildRemoval(const OctreeNode* parent, const OctreeNode* child) +{ + unbound(); +} + +LLViewerOctreeGroup* LLViewerOctreeGroup::getParent() +{ + if (isDead()) + { + return NULL; + } + + if(!mOctreeNode) + { + return NULL; + } + + OctreeNode* parent = mOctreeNode->getOctParent(); + + if (parent) + { + return (LLViewerOctreeGroup*) parent->getListener(0); + } + + return NULL; +} + +//virtual +bool LLViewerOctreeGroup::boundObjects(BOOL empty, LLVector4a& minOut, LLVector4a& maxOut) +{ + const OctreeNode* node = mOctreeNode; + + if (node->isEmpty()) + { //don't do anything if there are no objects + if (empty && mOctreeNode->getParent()) + { //only root is allowed to be empty + OCT_ERRS << "Empty leaf found in octree." << LL_ENDL; + } + return false; + } + + LLVector4a& newMin = mObjectExtents[0]; + LLVector4a& newMax = mObjectExtents[1]; + + if (hasState(OBJECT_DIRTY)) + { //calculate new bounding box + clearState(OBJECT_DIRTY); + + //initialize bounding box to first element + OctreeNode::const_element_iter i = node->getDataBegin(); + LLViewerOctreeEntry* entry = *i; + const LLVector4a* minMax = entry->getSpatialExtents(); + + newMin = minMax[0]; + newMax = minMax[1]; + + for (++i; i != node->getDataEnd(); ++i) + { + entry = *i; + minMax = entry->getSpatialExtents(); + + update_min_max(newMin, newMax, minMax[0]); + update_min_max(newMin, newMax, minMax[1]); + } + + mObjectBounds[0].setAdd(newMin, newMax); + mObjectBounds[0].mul(0.5f); + mObjectBounds[1].setSub(newMax, newMin); + mObjectBounds[1].mul(0.5f); + } + + if (empty) + { + minOut = newMin; + maxOut = newMax; + } + else + { + minOut.setMin(minOut, newMin); + maxOut.setMax(maxOut, newMax); + } + + return TRUE; +} + +//virtual +BOOL LLViewerOctreeGroup::isVisible() const +{ + return mVisible[LLViewerCamera::sCurCameraID] >= LLViewerOctreeEntryData::getCurrentFrame() ? TRUE : FALSE; +} + +//virtual +BOOL LLViewerOctreeGroup::isRecentlyVisible() const +{ + return FALSE; +} + +void LLViewerOctreeGroup::setVisible() +{ + mVisible[LLViewerCamera::sCurCameraID] = LLViewerOctreeEntryData::getCurrentFrame(); + + if(LLViewerCamera::sCurCameraID < LLViewerCamera::CAMERA_WATER0) + { + mAnyVisible = LLViewerOctreeEntryData::getCurrentFrame(); + } +} + +void LLViewerOctreeGroup::checkStates() +{ +#if LL_OCTREE_PARANOIA_CHECK + LLOctreeStateCheck checker; + checker.traverse(mOctreeNode); +#endif +} + +//------------------------------------------------------------------------------------------- +//occulsion culling functions and classes +//------------------------------------------------------------------------------------------- +std::set LLOcclusionCullingGroup::sPendingQueries; +class LLOcclusionQueryPool : public LLGLNamePool +{ +public: + LLOcclusionQueryPool() + { + } + +protected: + + virtual GLuint allocateName() + { + GLuint ret = 0; + + glGenQueriesARB(1, &ret); + + return ret; + } + + virtual void releaseName(GLuint name) + { +#if LL_TRACK_PENDING_OCCLUSION_QUERIES + LLOcclusionCullingGroup::sPendingQueries.erase(name); +#endif + glDeleteQueriesARB(1, &name); + } +}; + +static LLOcclusionQueryPool sQueryPool; +U32 LLOcclusionCullingGroup::getNewOcclusionQueryObjectName() +{ + return sQueryPool.allocate(); +} + +void LLOcclusionCullingGroup::releaseOcclusionQueryObjectName(U32 name) +{ + sQueryPool.release(name); +} + +//===================================== +// Occlusion State Set/Clear +//===================================== +class LLSpatialSetOcclusionState : public OctreeTraveler +{ +public: + LLOcclusionCullingGroup::eOcclusionState mState; + LLSpatialSetOcclusionState(LLOcclusionCullingGroup::eOcclusionState state) : mState(state) { } + virtual void visit(const OctreeNode* branch) + { + LLOcclusionCullingGroup* group = (LLOcclusionCullingGroup*)branch->getListener(0); + if(group) + { + group->setOcclusionState(mState); + } + } +}; + +class LLSpatialSetOcclusionStateDiff : public LLSpatialSetOcclusionState +{ +public: + LLSpatialSetOcclusionStateDiff(LLOcclusionCullingGroup::eOcclusionState state) : LLSpatialSetOcclusionState(state) { } + + virtual void traverse(const OctreeNode* n) + { + LLOcclusionCullingGroup* group = (LLOcclusionCullingGroup*) n->getListener(0); + + if (group && !group->isOcclusionState(mState)) + { + OctreeTraveler::traverse(n); + } + } +}; + + +LLOcclusionCullingGroup::LLOcclusionCullingGroup(OctreeNode* node, LLSpatialPartition* part) : + LLViewerOctreeGroup(node), + mSpatialPartition(part) +{ + llassert(part); + mSpatialPartition->mGroups.push_back(this); + part->mLODSeed = (part->mLODSeed+1)%part->mLODPeriod; + mLODHash = part->mLODSeed; + + OctreeNode* oct_parent = node->getOctParent(); + LLOcclusionCullingGroup* parent = oct_parent ? (LLOcclusionCullingGroup*) oct_parent->getListener(0) : NULL; + + for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++) + { + mOcclusionQuery[i] = 0; + mOcclusionIssued[i] = 0; + mOcclusionState[i] = parent ? SG_STATE_INHERIT_MASK & parent->mOcclusionState[i] : 0; + mVisible[i] = 0; + } +} + +LLOcclusionCullingGroup::~LLOcclusionCullingGroup() +{ + if (mSpatialPartition) + { + auto it = std::find_if(mSpatialPartition->mGroups.begin(), mSpatialPartition->mGroups.end(), [this](LLOcclusionCullingGroup* rhs) {return rhs == this; }); + llassert(it != mSpatialPartition->mGroups.end()); + if (it != mSpatialPartition->mGroups.end()) + { + mSpatialPartition->mGroups.erase(it); + } + } + releaseOcclusionQueryObjectNames(); +} + +BOOL LLOcclusionCullingGroup::needsUpdate() +{ + return mSpatialPartition && (LLDrawable::getCurrentFrame() % mSpatialPartition->mLODPeriod == mLODHash) ? TRUE : FALSE; +} + +BOOL LLOcclusionCullingGroup::isRecentlyVisible() const +{ + const S32 MIN_VIS_FRAME_RANGE = 2; + return (LLDrawable::getCurrentFrame() - mVisible[LLViewerCamera::sCurCameraID]) < MIN_VIS_FRAME_RANGE ; +} + +BOOL LLOcclusionCullingGroup::isAnyRecentlyVisible() const +{ + const S32 MIN_VIS_FRAME_RANGE = 2; + return (LLDrawable::getCurrentFrame() - mAnyVisible) < MIN_VIS_FRAME_RANGE ; +} + +//virtual +void LLOcclusionCullingGroup::handleChildAddition(const OctreeNode* parent, OctreeNode* child) +{ + if (child->getListenerCount() == 0) + { + new LLOcclusionCullingGroup(child, mSpatialPartition); + } + else + { + OCT_ERRS << "LLOcclusionCullingGroup redundancy detected." << LL_ENDL; + } + + unbound(); + + ((LLViewerOctreeGroup*)child->getListener(0))->unbound(); +} + +void LLOcclusionCullingGroup::releaseOcclusionQueryObjectNames() +{ + if (gGLManager.mHasOcclusionQuery) + { + for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; ++i) + { + if (mOcclusionQuery[i]) + { + releaseOcclusionQueryObjectName(mOcclusionQuery[i]); + mOcclusionQuery[i] = 0; + } + } + } +} + +void LLOcclusionCullingGroup::setOcclusionState(eOcclusionState state, S32 mode) +{ + if (mode > STATE_MODE_SINGLE) + { + if (mode == STATE_MODE_DIFF) + { + LLSpatialSetOcclusionStateDiff setter(state); + setter.traverse(mOctreeNode); + } + else if (mode == STATE_MODE_BRANCH) + { + LLSpatialSetOcclusionState setter(state); + setter.traverse(mOctreeNode); + } + else + { + for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++) + { + mOcclusionState[i] |= state; + + if ((state & DISCARD_QUERY) && mOcclusionQuery[i]) + { + releaseOcclusionQueryObjectName(mOcclusionQuery[i]); + mOcclusionQuery[i] = 0; + } + } + } + } + else + { + mOcclusionState[LLViewerCamera::sCurCameraID] |= state; + if ((state & DISCARD_QUERY) && mOcclusionQuery[LLViewerCamera::sCurCameraID]) + { + releaseOcclusionQueryObjectName(mOcclusionQuery[LLViewerCamera::sCurCameraID]); + mOcclusionQuery[LLViewerCamera::sCurCameraID] = 0; + } + } +} + +class LLSpatialClearOcclusionState : public OctreeTraveler +{ +public: + LLOcclusionCullingGroup::eOcclusionState mState; + + LLSpatialClearOcclusionState(LLOcclusionCullingGroup::eOcclusionState state) : mState(state) { } + virtual void visit(const OctreeNode* branch) + { + LLOcclusionCullingGroup* group = (LLOcclusionCullingGroup*) branch->getListener(0); + if(group) + { + group->clearOcclusionState(mState); + } + } +}; + +class LLSpatialClearOcclusionStateDiff : public LLSpatialClearOcclusionState +{ +public: + LLSpatialClearOcclusionStateDiff(LLOcclusionCullingGroup::eOcclusionState state) : LLSpatialClearOcclusionState(state) { } + + virtual void traverse(const OctreeNode* n) + { + LLOcclusionCullingGroup* group = (LLOcclusionCullingGroup*) n->getListener(0); + + if (group && group->isOcclusionState(mState)) + { + OctreeTraveler::traverse(n); + } + } +}; + +void LLOcclusionCullingGroup::clearOcclusionState(eOcclusionState state, S32 mode) +{ + if (mode > STATE_MODE_SINGLE) + { + if (mode == STATE_MODE_DIFF) + { + LLSpatialClearOcclusionStateDiff clearer(state); + clearer.traverse(mOctreeNode); + } + else if (mode == STATE_MODE_BRANCH) + { + LLSpatialClearOcclusionState clearer(state); + clearer.traverse(mOctreeNode); + } + else + { + for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++) + { + mOcclusionState[i] &= ~state; + } + } + } + else + { + mOcclusionState[LLViewerCamera::sCurCameraID] &= ~state; + } +} + +static LLTrace::BlockTimerStatHandle FTM_OCCLUSION_READBACK("Readback Occlusion"); +static LLTrace::BlockTimerStatHandle FTM_OCCLUSION_WAIT("Occlusion Wait"); + +BOOL LLOcclusionCullingGroup::earlyFail(LLCamera* camera, const LLVector4a* bounds) +{ + if (camera->getOrigin().isExactlyZero()) + { + return FALSE; + } + + static LLCachedControl vel("SHOcclusionFudge",SG_OCCLUSION_FUDGE); + LLVector4a fudge(vel*2.f); + + const LLVector4a& c = bounds[0]; + LLVector4a r; + r.setAdd(bounds[1], fudge); + + /*if (r.magVecSquared() > 1024.0*1024.0) + { + return TRUE; + }*/ + + LLVector4a e; + e.load3(camera->getOrigin().mV); + + LLVector4a min; + min.setSub(c,r); + LLVector4a max; + max.setAdd(c,r); + + S32 lt = e.lessThan(min).getGatheredBits() & 0x7; + if (lt) + { + return FALSE; + } + + S32 gt = e.greaterThan(max).getGatheredBits() & 0x7; + if (gt) + { + return FALSE; + } + + return TRUE; +} + +U32 LLOcclusionCullingGroup::getLastOcclusionIssuedTime() +{ + return mOcclusionIssued[LLViewerCamera::sCurCameraID]; +} + +void LLOcclusionCullingGroup::checkOcclusion() +{ + if (mSpatialPartition == nullptr) + { + return; + } + if (LLPipeline::sUseOcclusion > 1) + { + LL_RECORD_BLOCK_TIME(FTM_OCCLUSION_READBACK); + LLOcclusionCullingGroup* parent = (LLOcclusionCullingGroup*)getParent(); + if (parent && parent->isOcclusionState(LLOcclusionCullingGroup::OCCLUDED)) + { //if the parent has been marked as occluded, the child is implicitly occluded + clearOcclusionState(QUERY_PENDING | DISCARD_QUERY); + } + else if (isOcclusionState(QUERY_PENDING)) + { //otherwise, if a query is pending, read it back + + GLuint available = 0; + if (mOcclusionQuery[LLViewerCamera::sCurCameraID]) + { + glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_AVAILABLE_ARB, &available); + + static LLCachedControl wait_for_query("RenderSynchronousOcclusion", true); + + if (wait_for_query && mOcclusionIssued[LLViewerCamera::sCurCameraID] < gFrameCount) + { //query was issued last frame, wait until it's available + S32 max_loop = 1024; + LL_RECORD_BLOCK_TIME(FTM_OCCLUSION_WAIT); + while (!available && max_loop-- > 0) + { + F32 max_time = llmin(gFrameIntervalSeconds.value()*10.f, 1.f); + //do some usefu work while we wait + LLAppViewer::getTextureCache()->update(max_time); // unpauses the texture cache thread + LLAppViewer::getImageDecodeThread()->update(max_time); // unpauses the image thread + LLAppViewer::getTextureFetch()->update(max_time); // unpauses the texture fetch thread + + glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_AVAILABLE_ARB, &available); + } + } + } + else + { + available = 1; + } + + if (available) + { //result is available, read it back, otherwise wait until next frame + GLuint res = 1; + if (!isOcclusionState(DISCARD_QUERY) && mOcclusionQuery[LLViewerCamera::sCurCameraID]) + { + glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_ARB, &res); +#if LL_TRACK_PENDING_OCCLUSION_QUERIES + sPendingQueries.erase(mOcclusionQuery[LLViewerCamera::sCurCameraID]); +#endif + } + else if (mOcclusionQuery[LLViewerCamera::sCurCameraID]) + { //delete the query to avoid holding onto hundreds of pending queries + releaseOcclusionQueryObjectName(mOcclusionQuery[LLViewerCamera::sCurCameraID]); + mOcclusionQuery[LLViewerCamera::sCurCameraID] = 0; + } + + if (isOcclusionState(DISCARD_QUERY)) + { + res = 2; + } + + if (res > 0) + { + assert_states_valid(this); + clearOcclusionState(LLOcclusionCullingGroup::OCCLUDED, LLOcclusionCullingGroup::STATE_MODE_DIFF); + assert_states_valid(this); + } + else + { + assert_states_valid(this); + + setOcclusionState(LLOcclusionCullingGroup::OCCLUDED, LLOcclusionCullingGroup::STATE_MODE_DIFF); + + assert_states_valid(this); + } + + clearOcclusionState(QUERY_PENDING | DISCARD_QUERY); + } + } + else if (mSpatialPartition->isOcclusionEnabled() && isOcclusionState(LLOcclusionCullingGroup::OCCLUDED)) + { //check occlusion has been issued for occluded node that has not had a query issued + assert_states_valid(this); + clearOcclusionState(LLOcclusionCullingGroup::OCCLUDED, LLOcclusionCullingGroup::STATE_MODE_DIFF); + assert_states_valid(this); + } + } +} + +static LLTrace::BlockTimerStatHandle FTM_PUSH_OCCLUSION_VERTS("Push Occlusion"); +static LLTrace::BlockTimerStatHandle FTM_SET_OCCLUSION_STATE("Occlusion State"); +static LLTrace::BlockTimerStatHandle FTM_OCCLUSION_EARLY_FAIL("Occlusion Early Fail"); +static LLTrace::BlockTimerStatHandle FTM_OCCLUSION_ALLOCATE("Allocate"); +static LLTrace::BlockTimerStatHandle FTM_OCCLUSION_BUILD("Build"); +static LLTrace::BlockTimerStatHandle FTM_OCCLUSION_BEGIN_QUERY("Begin Query"); +static LLTrace::BlockTimerStatHandle FTM_OCCLUSION_END_QUERY("End Query"); +static LLTrace::BlockTimerStatHandle FTM_OCCLUSION_SET_BUFFER("Set Buffer"); +static LLTrace::BlockTimerStatHandle FTM_OCCLUSION_DRAW_WATER("Draw Water"); +static LLTrace::BlockTimerStatHandle FTM_OCCLUSION_DRAW("Draw"); + +void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* shift) +{ + if (mSpatialPartition == nullptr) + { + return; + } + LLGLDisable stencil; + if (mSpatialPartition->isOcclusionEnabled() && LLPipeline::sUseOcclusion > 1) + { + //move mBounds to the agent space if necessary + LLVector4a bounds[2]; + bounds[0] = mBounds[0]; + bounds[1] = mBounds[1]; + if(shift != NULL) + { + bounds[0].add(*shift); + } + + // Don't cull hole/edge water, unless we have the GL_ARB_depth_clamp extension + if (earlyFail(camera, bounds)) + { + LL_RECORD_BLOCK_TIME(FTM_OCCLUSION_EARLY_FAIL); + setOcclusionState(LLOcclusionCullingGroup::DISCARD_QUERY); + assert_states_valid(this); + clearOcclusionState(LLOcclusionCullingGroup::OCCLUDED, LLOcclusionCullingGroup::STATE_MODE_DIFF); + assert_states_valid(this); + } + else + { + if (!isOcclusionState(QUERY_PENDING) || isOcclusionState(DISCARD_QUERY)) + { + { //no query pending, or previous query to be discarded + LL_RECORD_BLOCK_TIME(FTM_RENDER_OCCLUSION); + + if (!mOcclusionQuery[LLViewerCamera::sCurCameraID]) + { + LL_RECORD_BLOCK_TIME(FTM_OCCLUSION_ALLOCATE); + mOcclusionQuery[LLViewerCamera::sCurCameraID] = getNewOcclusionQueryObjectName(); + } + + // Depth clamp all water to avoid it being culled as a result of being + // behind the far clip plane, and in the case of edge water to avoid + // it being culled while still visible. + bool const use_depth_clamp = gGLManager.mHasDepthClamp && + (mSpatialPartition->mDrawableType == LLDrawPool::POOL_WATER || + mSpatialPartition->mDrawableType == LLDrawPool::POOL_VOIDWATER); + + LLGLEnable clamp(use_depth_clamp); + +#if !LL_DARWIN + U32 mode = gGLManager.mHasOcclusionQuery2 ? GL_ANY_SAMPLES_PASSED : GL_SAMPLES_PASSED_ARB; +#else + U32 mode = GL_SAMPLES_PASSED_ARB; +#endif + +#if LL_TRACK_PENDING_OCCLUSION_QUERIES + sPendingQueries.insert(mOcclusionQuery[LLViewerCamera::sCurCameraID]); +#endif + + { + LL_RECORD_BLOCK_TIME(FTM_PUSH_OCCLUSION_VERTS); + + //store which frame this query was issued on + mOcclusionIssued[LLViewerCamera::sCurCameraID] = gFrameCount; + + { + LL_RECORD_BLOCK_TIME(FTM_OCCLUSION_BEGIN_QUERY); + glBeginQueryARB(mode, mOcclusionQuery[LLViewerCamera::sCurCameraID]); + } + + LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; + llassert(shader); + + shader->uniform3fv(LLShaderMgr::BOX_CENTER, 1, bounds[0].getF32ptr()); + //static LLVector4a fudge(SG_OCCLUSION_FUDGE); + static LLCachedControl vel("SHOcclusionFudge",SG_OCCLUSION_FUDGE); + LLVector4a fudge(SG_OCCLUSION_FUDGE); + if (LLDrawPool::POOL_WATER == mSpatialPartition->mDrawableType) + { + fudge.getF32ptr()[2] = 1.f; + } + + static LLVector4a fudged_bounds; + fudged_bounds.setAdd(fudge, bounds[1]); + shader->uniform3fv(LLShaderMgr::BOX_SIZE, 1, fudged_bounds.getF32ptr()); + + if (!use_depth_clamp && mSpatialPartition->mDrawableType == LLDrawPool::POOL_VOIDWATER) + { + LL_RECORD_BLOCK_TIME(FTM_OCCLUSION_DRAW_WATER); + + LLGLSquashToFarClip squash(glh_get_current_projection(), 1); + if (camera->getOrigin().isExactlyZero()) + { //origin is invalid, draw entire box + gPipeline.mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0); + gPipeline.mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, b111*8); + } + else + { + gPipeline.mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, bounds[0])); + } + } + else + { + LL_RECORD_BLOCK_TIME(FTM_OCCLUSION_DRAW); + if (camera->getOrigin().isExactlyZero()) + { //origin is invalid, draw entire box + gPipeline.mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0); + gPipeline.mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, b111*8); + } + else + { + gPipeline.mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, bounds[0])); + } + } + + + { + LL_RECORD_BLOCK_TIME(FTM_OCCLUSION_END_QUERY); + glEndQueryARB(mode); + } + } + } + + { + LL_RECORD_BLOCK_TIME(FTM_SET_OCCLUSION_STATE); + setOcclusionState(LLOcclusionCullingGroup::QUERY_PENDING); + clearOcclusionState(LLOcclusionCullingGroup::DISCARD_QUERY); + } + } + } + } +} +//------------------------------------------------------------------------------------------- +//end of occulsion culling functions and classes +//------------------------------------------------------------------------------------------- + +//----------------------------------------------------------------------------------- +//class LLViewerOctreePartition definitions +//----------------------------------------------------------------------------------- +LLViewerOctreePartition::LLViewerOctreePartition() : + mRegionp(NULL), + mOcclusionEnabled(TRUE), + mDrawableType(0), + mLODSeed(0), + mLODPeriod(1) +{ + LLVector4a center, size; + center.splat(0.f); + size.splat(1.f); + + mOctree = new OctreeRoot(center,size, NULL); +} + +LLViewerOctreePartition::~LLViewerOctreePartition() +{ + llassert(mGroups.empty()); + for (auto& entry : mGroups) + { + entry->mSpatialPartition = nullptr; + } + delete mOctree; + mOctree = NULL; +} + +BOOL LLViewerOctreePartition::isOcclusionEnabled() +{ + return mOcclusionEnabled || LLPipeline::sUseOcclusion > 2; +} + +//----------------------------------------------------------------------------------- +//class LLViewerOctreeCull definitions +//----------------------------------------------------------------------------------- + +//virtual +bool LLViewerOctreeCull::earlyFail(LLViewerOctreeGroup* group) +{ + return false; +} + +//virtual +void LLViewerOctreeCull::traverse(const OctreeNode* n) +{ + LLViewerOctreeGroup* group = (LLViewerOctreeGroup*) n->getListener(0); + + if (earlyFail(group)) + { + return; + } + + if (mRes == 2 || + (mRes && group->hasState(LLViewerOctreeGroup::SKIP_FRUSTUM_CHECK))) + { //fully in, just add everything + OctreeTraveler::traverse(n); + } + else + { + mRes = frustumCheck(group); + + if (mRes) + { //at least partially in, run on down + OctreeTraveler::traverse(n); + } + + mRes = 0; + } +} + +//------------------------------------------ +//agent space group culling +S32 LLViewerOctreeCull::AABBInFrustumNoFarClipGroupBounds(const LLViewerOctreeGroup* group) +{ + return mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1]); +} + +S32 LLViewerOctreeCull::AABBSphereIntersectGroupExtents(const LLViewerOctreeGroup* group) +{ + return AABBSphereIntersect(group->mExtents[0], group->mExtents[1], mCamera->getOrigin(), mCamera->mFrustumCornerDist); +} + +S32 LLViewerOctreeCull::AABBInFrustumGroupBounds(const LLViewerOctreeGroup* group) +{ + return mCamera->AABBInFrustum(group->mBounds[0], group->mBounds[1]); +} +//------------------------------------------ + +//------------------------------------------ +//agent space object set culling +S32 LLViewerOctreeCull::AABBInFrustumNoFarClipObjectBounds(const LLViewerOctreeGroup* group) +{ + return mCamera->AABBInFrustumNoFarClip(group->mObjectBounds[0], group->mObjectBounds[1]); +} + +S32 LLViewerOctreeCull::AABBSphereIntersectObjectExtents(const LLViewerOctreeGroup* group) +{ + return AABBSphereIntersect(group->mObjectExtents[0], group->mObjectExtents[1], mCamera->getOrigin(), mCamera->mFrustumCornerDist); +} + +S32 LLViewerOctreeCull::AABBInFrustumObjectBounds(const LLViewerOctreeGroup* group) +{ + return mCamera->AABBInFrustum(group->mObjectBounds[0], group->mObjectBounds[1]); +} +//------------------------------------------ + +//------------------------------------------ +//local regional space group culling +S32 LLViewerOctreeCull::AABBInRegionFrustumNoFarClipGroupBounds(const LLViewerOctreeGroup* group) +{ + return mCamera->AABBInRegionFrustumNoFarClip(group->mBounds[0], group->mBounds[1]); +} + +S32 LLViewerOctreeCull::AABBInRegionFrustumGroupBounds(const LLViewerOctreeGroup* group) +{ + return mCamera->AABBInRegionFrustum(group->mBounds[0], group->mBounds[1]); +} + +S32 LLViewerOctreeCull::AABBRegionSphereIntersectGroupExtents(const LLViewerOctreeGroup* group, const LLVector3& shift) +{ + return AABBSphereIntersect(group->mExtents[0], group->mExtents[1], mCamera->getOrigin() - shift, mCamera->mFrustumCornerDist); +} +//------------------------------------------ + +//------------------------------------------ +//local regional space object culling +S32 LLViewerOctreeCull::AABBInRegionFrustumObjectBounds(const LLViewerOctreeGroup* group) +{ + return mCamera->AABBInRegionFrustum(group->mObjectBounds[0], group->mObjectBounds[1]); +} + +S32 LLViewerOctreeCull::AABBInRegionFrustumNoFarClipObjectBounds(const LLViewerOctreeGroup* group) +{ + return mCamera->AABBInRegionFrustumNoFarClip(group->mObjectBounds[0], group->mObjectBounds[1]); +} + +S32 LLViewerOctreeCull::AABBRegionSphereIntersectObjectExtents(const LLViewerOctreeGroup* group, const LLVector3& shift) +{ + return AABBSphereIntersect(group->mObjectExtents[0], group->mObjectExtents[1], mCamera->getOrigin() - shift, mCamera->mFrustumCornerDist); +} +//------------------------------------------ +//check if the objects projection large enough + +bool LLViewerOctreeCull::checkProjectionArea(const LLVector4a& center, const LLVector4a& size, const LLVector3& shift, F32 pixel_threshold, F32 near_radius) +{ + LLVector3 local_orig = mCamera->getOrigin() - shift; + LLVector4a origin; + origin.load3(local_orig.mV); + + LLVector4a lookAt; + lookAt.setSub(center, origin); + F32 distance = lookAt.getLength3().getF32(); + if(distance <= near_radius) + { + return true; //always load close-by objects + } + + // treat object as if it were near_radius meters closer than it actually was. + // this allows us to get some temporal coherence on visibility...objects that can be reached quickly will tend to be visible + distance -= near_radius; + + F32 squared_rad = size.dot3(size).getF32(); + return squared_rad / distance > pixel_threshold; +} + +//virtual +bool LLViewerOctreeCull::checkObjects(const OctreeNode* branch, const LLViewerOctreeGroup* group) +{ + if (branch->getElementCount() == 0) //no elements + { + return false; + } + else if (branch->getChildCount() == 0) //leaf state, already checked tightest bounding box + { + return true; + } + else if (mRes == 1 && !frustumCheckObjects(group)) //no objects in frustum + { + return false; + } + + return true; +} + +//virtual +void LLViewerOctreeCull::preprocess(LLViewerOctreeGroup* group) +{ +} + +//virtual +void LLViewerOctreeCull::processGroup(LLViewerOctreeGroup* group) +{ +} + +//virtual +void LLViewerOctreeCull::visit(const OctreeNode* branch) +{ + LLViewerOctreeGroup* group = (LLViewerOctreeGroup*) branch->getListener(0); + + preprocess(group); + + if (checkObjects(branch, group)) + { + processGroup(group); + } +} + diff --git a/indra/newview/llvieweroctree.h b/indra/newview/llvieweroctree.h new file mode 100644 index 0000000000..b1560f23fc --- /dev/null +++ b/indra/newview/llvieweroctree.h @@ -0,0 +1,408 @@ +/** + * @file llvieweroctree.h + * @brief LLViewerObjectOctree.cpp header file, defining all supporting classes. + * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_VIEWEROCTREE_H +#define LL_VIEWEROCTREE_H + +#include +#include + +#include "v2math.h" +#include "v3math.h" +#include "v4math.h" +#include "m4math.h" +#include "llvector4a.h" +#include "llquaternion.h" +#include "lloctree.h" +#include "llviewercamera.h" + +class LLViewerRegion; +class LLViewerOctreeEntryData; +class LLViewerOctreeGroup; +class LLViewerOctreeEntry; +class LLViewerOctreePartition; +class LLSpatialPartition; + +typedef LLOctreeListener OctreeListener; + typedef LLTreeNode TreeNode; + typedef LLOctreeNode OctreeNode; + typedef LLOctreeRoot OctreeRoot; + typedef LLOctreeTraveler OctreeTraveler; + +#if LL_OCTREE_PARANOIA_CHECK +#define assert_octree_valid(x) x->validate() +#define assert_states_valid(x) ((LLViewerOctreeGroup*) x->mSpatialPartition->mOctree->getListener(0))->checkStates() +#else +#define assert_octree_valid(x) +#define assert_states_valid(x) +#endif + +// get index buffer for binary encoded axis vertex buffer given a box at center being viewed by given camera +U32 get_box_fan_indices(LLCamera* camera, const LLVector4a& center); +U8* get_box_fan_indices_ptr(LLCamera* camera, const LLVector4a& center); + +S32 AABBSphereIntersect(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &rad); +S32 AABBSphereIntersectR2(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &radius_squared); + +S32 AABBSphereIntersect(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &rad); +S32 AABBSphereIntersectR2(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &radius_squared); + +class LLViewerOctreeEntry : public LLRefCount +{ + friend class LLViewerOctreeEntryData; + +public: + typedef enum + { + LLDRAWABLE = 0, + LLVOCACHEENTRY, + NUM_DATA_TYPE + }eEntryDataType_t; + +protected: + virtual ~LLViewerOctreeEntry(); + +public: + LLViewerOctreeEntry(); + + void nullGroup(); //called by group handleDestruction() only + void setGroup(LLViewerOctreeGroup* group); + void removeData(LLViewerOctreeEntryData* data); + + LLViewerOctreeEntryData* getDrawable() const {return mData[LLDRAWABLE];} + bool hasDrawable() const {return mData[LLDRAWABLE] != NULL;} + LLViewerOctreeEntryData* getVOCacheEntry() const {return mData[LLVOCACHEENTRY];} + bool hasVOCacheEntry() const {return mData[LLVOCACHEENTRY] != NULL;} + + const LLVector4a* getSpatialExtents() const {return mExtents;} + const LLVector4a& getPositionGroup() const {return mPositionGroup;} + LLViewerOctreeGroup* getGroup()const {return mGroup;} + + F32 getBinRadius() const {return mBinRadius;} + S32 getBinIndex() const {return mBinIndex; } + void setBinIndex(S32 index) const {mBinIndex = index; } + +private: + void addData(LLViewerOctreeEntryData* data); + +private: + LLViewerOctreeEntryData* mData[NUM_DATA_TYPE]; //do not use LLPointer here. + LLPointer mGroup; + + //aligned members + LL_ALIGN_16(LLVector4a mExtents[2]); + LL_ALIGN_16(LLVector4a mPositionGroup); + F32 mBinRadius; + mutable S32 mBinIndex; + mutable U32 mVisible; + +} ;//LL_ALIGN_POSTFIX(16); + +//defines an abstract class for entry data +//LL_ALIGN_PREFIX(16) +class LLViewerOctreeEntryData : public LLRefCount +{ +protected: + virtual ~LLViewerOctreeEntryData(); + +public: + LLViewerOctreeEntryData(const LLViewerOctreeEntryData& rhs) + { + *this = rhs; + } + LLViewerOctreeEntryData(LLViewerOctreeEntry::eEntryDataType_t data_type); + + LLViewerOctreeEntry::eEntryDataType_t getDataType() const {return mDataType;} + LLViewerOctreeEntry* getEntry() {return mEntry;} + + virtual void setOctreeEntry(LLViewerOctreeEntry* entry); + void removeOctreeEntry(); + + F32 getBinRadius() const {return mEntry->getBinRadius();} + const LLVector4a* getSpatialExtents() const; + LLViewerOctreeGroup* getGroup()const; + const LLVector4a& getPositionGroup() const; + + void setBinRadius(F32 rad) {mEntry->mBinRadius = rad;} + void setSpatialExtents(const LLVector3& min, const LLVector3& max); + void setSpatialExtents(const LLVector4a& min, const LLVector4a& max); + void setPositionGroup(const LLVector4a& pos); + + virtual void setGroup(LLViewerOctreeGroup* group); + void shift(const LLVector4a &shift_vector); + + U32 getVisible() const {return mEntry ? mEntry->mVisible : 0;} + void setVisible() const; + void resetVisible() const; + virtual bool isVisible() const; + virtual bool isRecentlyVisible() const; + + static S32 getCurrentFrame() { return sCurVisible; } + +protected: + LLVector4a& getGroupPosition() {return mEntry->mPositionGroup;} + void initVisible(U32 visible) {mEntry->mVisible = visible;} + + static void incrementVisible() {sCurVisible++;} +protected: + LLPointer mEntry; + LLViewerOctreeEntry::eEntryDataType_t mDataType; + static U32 sCurVisible; // Counter for what value of mVisible means currently visible +};//LL_ALIGN_POSTFIX(16); + +class LLViewerOctreeGroup +: public LLOctreeListener +{ + friend class LLViewerOctreeCull; +protected: + virtual ~LLViewerOctreeGroup(); + +public: + enum + { + CLEAN = 0x00000000, + DIRTY = 0x00000001, + OBJECT_DIRTY = 0x00000002, + SKIP_FRUSTUM_CHECK = 0x00000004, + DEAD = 0x00000008, + INVALID_STATE = 0x00000010, + }; + +public: + typedef LLOctreeNode::element_iter element_iter; + typedef LLOctreeNode::element_list element_list; + + LLViewerOctreeGroup(OctreeNode* node); + LLViewerOctreeGroup(const LLViewerOctreeGroup& rhs) + { + *this = rhs; + } + + bool removeFromGroup(LLViewerOctreeEntryData* data); + bool removeFromGroup(LLViewerOctreeEntry* entry); + + virtual void unbound(); + virtual void rebound(); + + BOOL isDead() { return hasState(DEAD); } + + void setVisible(); + BOOL isVisible() const; + virtual BOOL isRecentlyVisible() const; + S32 getVisible(LLViewerCamera::eCameraID id) const {return mVisible[id];} + S32 getAnyVisible() const {return mAnyVisible;} + bool isEmpty() const { return mOctreeNode->isEmpty(); } + + U32 getState() {return mState; } + bool isDirty() const {return mState & DIRTY;} + bool hasState(U32 state) const {return mState & state;} + void setState(U32 state) {mState |= state;} + void clearState(U32 state) {mState &= ~state;} + + //LISTENER FUNCTIONS + void handleInsertion(const TreeNode* node, LLViewerOctreeEntry* obj) override; + void handleRemoval(const TreeNode* node, LLViewerOctreeEntry* obj) override; + void handleDestruction(const TreeNode* node) override; + void handleChildAddition(const OctreeNode* parent, OctreeNode* child) override; + void handleChildRemoval(const OctreeNode* parent, const OctreeNode* child) final override; + + OctreeNode* getOctreeNode() {return mOctreeNode;} + const OctreeNode* getOctreeNode() const { return mOctreeNode; } + LLViewerOctreeGroup* getParent(); + + const LLVector4a* getBounds() const {return mBounds;} + const LLVector4a* getExtents() const {return mExtents;} + const LLVector4a* getObjectBounds() const {return mObjectBounds;} + const LLVector4a* getObjectExtents() const {return mObjectExtents;} + + //octree wrappers to make code more readable + //element_list& getData() { return mOctreeNode->getData(); } + element_iter getDataBegin() { return mOctreeNode->getDataBegin(); } + element_iter getDataEnd() { return mOctreeNode->getDataEnd(); } + U32 getElementCount() const { return mOctreeNode->getElementCount(); } + bool hasElement(LLViewerOctreeEntryData* data); + +protected: + void checkStates(); +private: + virtual bool boundObjects(BOOL empty, LLVector4a& minOut, LLVector4a& maxOut); + +protected: + U32 mState; + OctreeNode* mOctreeNode; + + LL_ALIGN_16(LLVector4a mBounds[2]); // bounding box (center, size) of this node and all its children (tight fit to objects) + LL_ALIGN_16(LLVector4a mObjectBounds[2]); // bounding box (center, size) of objects in this node + LL_ALIGN_16(LLVector4a mExtents[2]); // extents (min, max) of this node and all its children + LL_ALIGN_16(LLVector4a mObjectExtents[2]); // extents (min, max) of objects in this node + + S32 mAnyVisible; //latest visible to any camera + S32 mVisible[LLViewerCamera::NUM_CAMERAS]; + +}; +//octree group which has capability to support occlusion culling +//LL_ALIGN_PREFIX(16) +class LLOcclusionCullingGroup : public LLViewerOctreeGroup +{ +public: + typedef enum + { + OCCLUDED = 0x00010000, + QUERY_PENDING = 0x00020000, + ACTIVE_OCCLUSION = 0x00040000, + DISCARD_QUERY = 0x00080000, + EARLY_FAIL = 0x00100000, + } eOcclusionState; + + typedef enum + { + STATE_MODE_SINGLE = 0, //set one node + STATE_MODE_BRANCH, //set entire branch + STATE_MODE_DIFF, //set entire branch as long as current state is different + STATE_MODE_ALL_CAMERAS, //used for occlusion state, set state for all cameras + } eSetStateMode; + +protected: + virtual ~LLOcclusionCullingGroup(); + +public: + LLOcclusionCullingGroup(OctreeNode* node, LLSpatialPartition* part); + LLOcclusionCullingGroup(const LLOcclusionCullingGroup& rhs) : LLViewerOctreeGroup(rhs) + { + *this = rhs; + } + + bool setState(U32 state) const { return mState & state; } + bool hasState(U32 state) const { return mState & state; } + + void setOcclusionState(eOcclusionState state, S32 mode = STATE_MODE_SINGLE); + void clearOcclusionState(eOcclusionState state, S32 mode = STATE_MODE_SINGLE); + void checkOcclusion(); //read back last occlusion query (if any) + void doOcclusion(LLCamera* camera, const LLVector4a* shift = NULL); //issue occlusion query + BOOL isOcclusionState(eOcclusionState state) const { return mOcclusionState[LLViewerCamera::sCurCameraID] & state ? TRUE : FALSE; } + U32 getOcclusionState() const { return mOcclusionState[LLViewerCamera::sCurCameraID];} + + BOOL needsUpdate(); + U32 getLastOcclusionIssuedTime(); + + //virtual + void handleChildAddition(const OctreeNode* parent, OctreeNode* child) override; + + //virtual + BOOL isRecentlyVisible() const; + //LLViewerOctreePartition* getSpatialPartition()const {return mSpatialPartition;} + BOOL isAnyRecentlyVisible() const; + + static U32 getNewOcclusionQueryObjectName(); + static void releaseOcclusionQueryObjectName(U32 name); + +protected: + void releaseOcclusionQueryObjectNames(); + +private: + BOOL earlyFail(LLCamera* camera, const LLVector4a* bounds); + +protected: + U32 mOcclusionState[LLViewerCamera::NUM_CAMERAS]; + U32 mOcclusionIssued[LLViewerCamera::NUM_CAMERAS]; + + S32 mLODHash; + + friend class LLViewerOctreePartition; + LLSpatialPartition* mSpatialPartition; + U32 mOcclusionQuery[LLViewerCamera::NUM_CAMERAS]; + +public: + static std::set sPendingQueries; //pending occlusion queries +}; + +class LLViewerOctreePartition +{ +public: + LLViewerOctreePartition(); + virtual ~LLViewerOctreePartition(); + + // Cull on arbitrary frustum + virtual S32 cull(LLCamera &camera, bool do_occlusion) = 0; + BOOL isOcclusionEnabled(); + +public: + U32 mPartitionType; + U32 mDrawableType; + OctreeRoot* mOctree; + LLViewerRegion* mRegionp; // the region this partition belongs to. + BOOL mOcclusionEnabled; // if TRUE, occlusion culling is performed + U32 mLODSeed; + U32 mLODPeriod; //number of frames between LOD updates for a given spatial group (staggered by mLODSeed) + std::vector mGroups; +}; + +class LLViewerOctreeCull : public OctreeTraveler +{ +public: + LLViewerOctreeCull(LLCamera* camera) + : mCamera(camera), mRes(0) { } + + virtual void traverse(const OctreeNode* n); + +protected: + virtual bool earlyFail(LLViewerOctreeGroup* group); + + //agent space group cull + S32 AABBInFrustumNoFarClipGroupBounds(const LLViewerOctreeGroup* group); + S32 AABBSphereIntersectGroupExtents(const LLViewerOctreeGroup* group); + S32 AABBInFrustumGroupBounds(const LLViewerOctreeGroup* group); + + //agent space object set cull + S32 AABBInFrustumNoFarClipObjectBounds(const LLViewerOctreeGroup* group); + S32 AABBSphereIntersectObjectExtents(const LLViewerOctreeGroup* group); + S32 AABBInFrustumObjectBounds(const LLViewerOctreeGroup* group); + + //local region space group cull + S32 AABBInRegionFrustumNoFarClipGroupBounds(const LLViewerOctreeGroup* group); + S32 AABBInRegionFrustumGroupBounds(const LLViewerOctreeGroup* group); + S32 AABBRegionSphereIntersectGroupExtents(const LLViewerOctreeGroup* group, const LLVector3& shift); + + //local region space object set cull + S32 AABBInRegionFrustumNoFarClipObjectBounds(const LLViewerOctreeGroup* group); + S32 AABBInRegionFrustumObjectBounds(const LLViewerOctreeGroup* group); + S32 AABBRegionSphereIntersectObjectExtents(const LLViewerOctreeGroup* group, const LLVector3& shift); + + virtual S32 frustumCheck(const LLViewerOctreeGroup* group) = 0; + virtual S32 frustumCheckObjects(const LLViewerOctreeGroup* group) = 0; + + bool checkProjectionArea(const LLVector4a& center, const LLVector4a& size, const LLVector3& shift, F32 pixel_threshold, F32 near_radius); + virtual bool checkObjects(const OctreeNode* branch, const LLViewerOctreeGroup* group); + virtual void preprocess(LLViewerOctreeGroup* group); + virtual void processGroup(LLViewerOctreeGroup* group); + virtual void visit(const OctreeNode* branch); + +protected: + LLCamera *mCamera; + S32 mRes; +}; + +#endif \ No newline at end of file diff --git a/indra/newview/llviewerparcelmedia.cpp b/indra/newview/llviewerparcelmedia.cpp index 0e8e97f3a7..94a48e4eae 100644 --- a/indra/newview/llviewerparcelmedia.cpp +++ b/indra/newview/llviewerparcelmedia.cpp @@ -49,11 +49,11 @@ #include "llviewerwindow.h" #include "llfirstuse.h" #include "llpluginclassmedia.h" +#include "llmediafilter.h" #include "llnotify.h" #include "llsdserialize.h" #include "llaudioengine.h" #include "lloverlaybar.h" -#include "slfloatermediafilter.h" #include "llstreamingaudio.h" // Static Variables @@ -61,12 +61,7 @@ S32 LLViewerParcelMedia::sMediaParcelLocalID = 0; LLUUID LLViewerParcelMedia::sMediaRegionID; viewer_media_t LLViewerParcelMedia::sMediaImpl; -bool LLViewerParcelMedia::sIsUserAction = false; -bool LLViewerParcelMedia::sMediaFilterListLoaded = false; -LLSD LLViewerParcelMedia::sMediaFilterList; -std::set LLViewerParcelMedia::sMediaQueries; -std::set LLViewerParcelMedia::sAllowedMedia; -std::set LLViewerParcelMedia::sDeniedMedia; +F32 LLViewerParcelMedia::sMediaCommandTime = 0; // Local functions bool callback_play_media(const LLSD& notification, const LLSD& response, LLParcel* parcel); @@ -151,7 +146,15 @@ void LLViewerParcelMedia::update(LLParcel* parcel) // Only play if the media types are the same. if(sMediaImpl->getMimeType() == parcel->getMediaType()) { - play(parcel); + if (gSavedSettings.getU32("MediaFilterEnable")) + { + LL_DEBUGS("MediaFilter") << "Filtering media URL: " << parcel->getMediaURL() << LL_ENDL; + LLMediaFilter::getInstance()->filterMediaUrl(parcel); + } + else + { + play(parcel); + } } else @@ -187,9 +190,9 @@ void LLViewerParcelMedia::update(LLParcel* parcel) } // static -void LLViewerParcelMedia::play(LLParcel* parcel, bool filter) +void LLViewerParcelMedia::play(LLParcel* parcel) { - lldebugs << "LLViewerParcelMedia::play" << llendl; + LL_DEBUGS() << "LLViewerParcelMedia::play" << LL_ENDL; if (!parcel) return; @@ -197,17 +200,7 @@ void LLViewerParcelMedia::play(LLParcel* parcel, bool filter) return; std::string media_url = parcel->getMediaURL(); - LLStringUtil::trim(media_url); - - if (!media_url.empty() && gSavedSettings.getBOOL("MediaEnableFilter") && (filter || !allowedMedia(media_url))) - { - // If filtering is needed or in case media_url just changed - // to something we did not yet approve. - LLViewerParcelMediaAutoPlay::playStarted(); - filterMedia(parcel, 0); - return; - } - + std::string media_current_url = parcel->getMediaCurrentURL(); std::string mime_type = parcel->getMediaType(); LLUUID placeholder_texture_id = parcel->getMediaID(); U8 media_auto_scale = parcel->getMediaAutoScale(); @@ -399,13 +392,27 @@ void LLViewerParcelMedia::processParcelMediaCommandMessage( LLMessageSystem *msg // stop if( command == PARCEL_MEDIA_COMMAND_STOP ) { - stop(); + if (!LLMediaFilter::getInstance()->isAlertActive()) + { + stop(); + } + else + { + LLMediaFilter::getInstance()->setQueuedMediaCommand(PARCEL_MEDIA_COMMAND_STOP); + } } else // pause if( command == PARCEL_MEDIA_COMMAND_PAUSE ) { - pause(); + if (!LLMediaFilter::getInstance()->isAlertActive()) + { + pause(); + } + else + { + LLMediaFilter::getInstance()->setQueuedMediaCommand(PARCEL_MEDIA_COMMAND_PAUSE); + } } else // play @@ -419,14 +426,29 @@ void LLViewerParcelMedia::processParcelMediaCommandMessage( LLMessageSystem *msg else { LLParcel *parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); - play(parcel); + if (gSavedSettings.getU32("MediaFilterEnable")) + { + LL_DEBUGS("MediaFilter") << "PARCEL_MEDIA_COMMAND_PLAY: Filtering media URL: " << parcel->getMediaURL() << LL_ENDL; + LLMediaFilter::getInstance()->filterMediaUrl(parcel); + } + else + { + play(parcel); + } } } else // unload if( command == PARCEL_MEDIA_COMMAND_UNLOAD ) { - stop(); + if (!LLMediaFilter::getInstance()->isAlertActive()) + { + stop(); + } + else + { + LLMediaFilter::getInstance()->setQueuedMediaCommand(PARCEL_MEDIA_COMMAND_UNLOAD); + } } } @@ -435,10 +457,26 @@ void LLViewerParcelMedia::processParcelMediaCommandMessage( LLMessageSystem *msg if(sMediaImpl.isNull()) { LLParcel *parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); - play(parcel); + if (gSavedSettings.getU32("MediaFilterEnable")) + { + LL_DEBUGS("MediaFilter") << "PARCEL_MEDIA_COMMAND_TIME: Filtering media URL: " << parcel->getMediaURL() << LL_ENDL; + LLMediaFilter::getInstance()->filterMediaUrl(parcel); + } + else + { + play(parcel); + } } + } + if (!LLMediaFilter::getInstance()->isAlertActive()) + { seek(time); } + else + { + LLMediaFilter::getInstance()->setQueuedMediaCommand(PARCEL_MEDIA_COMMAND_TIME); + sMediaCommandTime = time; + } } ////////////////////////////////////////////////////////////////////////////////////////// @@ -492,7 +530,18 @@ void LLViewerParcelMedia::processParcelMediaUpdate( LLMessageSystem *msg, void * parcel->setMediaAutoScale(media_auto_scale); parcel->setMediaLoop(media_loop); - play(parcel); + if (sMediaImpl.notNull()) + { + if (gSavedSettings.getU32("MediaFilterEnable")) + { + LL_DEBUGS("MediaFilter") << "Parcel media changed. Filtering media URL: " << parcel->getMediaURL() << LL_ENDL; + LLMediaFilter::getInstance()->filterMediaUrl(parcel); + } + else + { + play(parcel); + } + } } } } @@ -512,7 +561,7 @@ void LLViewerParcelMedia::sendMediaNavigateMessage(const std::string& url) } else { - llwarns << "can't get ParcelNavigateMedia capability" << llendl; + LL_WARNS() << "can't get ParcelNavigateMedia capability" << LL_ENDL; } } @@ -623,37 +672,37 @@ void LLViewerParcelMedia::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent case MEDIA_EVENT_CLOSE_REQUEST: { LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CLOSE_REQUEST" << LL_ENDL; - }; + } break; case MEDIA_EVENT_PICK_FILE_REQUEST: { LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_PICK_FILE_REQUEST" << LL_ENDL; - }; + } break; case MEDIA_EVENT_GEOMETRY_CHANGE: { - LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_GEOMETRY_CHANGE" << LL_ENDL; - }; + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_GEOMETRY_CHANGE, uuid is " << self->getClickUUID() << LL_ENDL; + } break; case MEDIA_EVENT_AUTH_REQUEST: { - LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_AUTH_REQUEST" << LL_ENDL; - }; + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_AUTH_REQUEST, url " << self->getAuthURL() << ", realm " << self->getAuthRealm() << LL_ENDL; + } break; case MEDIA_EVENT_LINK_HOVERED: { - LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_LINK_HOVERED" << LL_ENDL; + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_LINK_HOVERED, hover text is: " << self->getHoverText() << LL_ENDL; }; break; default: { LL_WARNS("Media") << "Media event: unknown event type" << LL_ENDL; - }; + } }; } @@ -663,7 +712,14 @@ bool callback_play_media(const LLSD& notification, const LLSD& response, LLParce if (option == 0) { gSavedSettings.setBOOL("AudioStreamingMedia", TRUE); - LLViewerParcelMedia::play(parcel); + if (gSavedSettings.getU32("MediaFilterEnable")) + { + LLMediaFilter::getInstance()->filterMediaUrl(parcel); + } + else + { + LLViewerParcelMedia::play(parcel); + } } else { @@ -694,11 +750,10 @@ void LLViewerParcelMedia::playStreamingMusic(LLParcel* parcel, bool filter) { std::string music_url = parcel->getMusicURL(); LLStringUtil::trim(music_url); - if (!music_url.empty() && gSavedSettings.getBOOL("MediaEnableFilter") && (filter || !allowedMedia(music_url))) + if (gSavedSettings.getU32("MediaFilterEnable")) { - // If filtering is needed or in case music_url just changed - // to something we did not yet approve. - filterMedia(parcel, 1); + LL_DEBUGS("MediaFilter") << "Filtering media URL: " << parcel->getMediaURL() << LL_ENDL; + LLMediaFilter::getInstance()->filterAudioUrl(music_url); } else if (gAudiop) { @@ -726,395 +781,3 @@ void LLViewerParcelMedia::stopStreamingMusic() LLOverlayBar::audioFilterStop(); } } - -bool LLViewerParcelMedia::allowedMedia(std::string media_url) -{ - LLStringUtil::trim(media_url); - std::string domain = extractDomain(media_url); - LLHost host; - host.setHostByName(domain); - std::string ip = host.getIPString(); - if (sAllowedMedia.count(domain) || sAllowedMedia.count(ip)) - { - return true; - } - std::string server; - for (S32 i = 0; i < (S32)sMediaFilterList.size(); i++) - { - server = sMediaFilterList[i]["domain"].asString(); - if (server == domain || server == ip) - { - if (sMediaFilterList[i]["action"].asString() == "allow") - { - return true; - } - else - { - return false; - } - } - } - return false; -} - -void LLViewerParcelMedia::filterMedia(LLParcel* parcel, U32 type) -{ - std::string media_action; - std::string media_url; - std::string domain; - std::string ip; - - if (parcel != LLViewerParcelMgr::getInstance()->getAgentParcel()) - { - // The parcel just changed (may occur right out after a TP) - sIsUserAction = false; - return; - } - - if (type == 0) - { - media_url = parcel->getMediaURL(); - } - else - { - media_url = parcel->getMusicURL(); - } - LLStringUtil::trim(media_url); - - domain = extractDomain(media_url); - - if (sMediaQueries.count(domain) > 0) - { - sIsUserAction = false; - return; - } - - LLHost host; - host.setHostByName(domain); - ip = host.getIPString(); - - if (sIsUserAction) - { - // This was a user manual request to play this media, so give - // it another chance... - sIsUserAction = false; - bool dirty = false; - if (sDeniedMedia.count(domain)) - { - sDeniedMedia.erase(domain); - dirty = true; - } - if (sDeniedMedia.count(ip)) - { - sDeniedMedia.erase(ip); - dirty = true; - } - if (dirty && SLFloaterMediaFilter::findInstance()) - { - SLFloaterMediaFilter::getInstance()->setDirty(); - } - } - - if (media_url.empty()) - { - media_action = "allow"; - } - else if (!sMediaFilterListLoaded || sDeniedMedia.count(domain) || sDeniedMedia.count(ip)) - { - media_action = "ignore"; - } - else if (sAllowedMedia.count(domain) || sAllowedMedia.count(ip)) - { - media_action = "allow"; - } - else - { - std::string server; - for (S32 i = 0; i < (S32)sMediaFilterList.size(); i++) - { - server = sMediaFilterList[i]["domain"].asString(); - if (server == domain || server == ip) - { - media_action = sMediaFilterList[i]["action"].asString(); - break; - } - } - } - - if (media_action == "allow") - { - if (type == 0) - { - play(parcel, false); - } - else - { - playStreamingMusic(parcel, false); - } - return; - } - if (media_action == "ignore") - { - if (type == 1) - { - LLViewerParcelMedia::stopStreamingMusic(); - } - return; - } - - LLSD args; - if (ip != domain && domain.find('/') == std::string::npos) - { - args["DOMAIN"] = domain + " (" + ip + ")"; - } - else - { - args["DOMAIN"] = domain; - } - - if (media_action == "deny") - { - LLNotificationsUtil::add("MediaBlocked", args); - if (type == 1) - { - LLViewerParcelMedia::stopStreamingMusic(); - } - // So to avoid other "blocked" messages later in the session - // for this url should it be requested again by a script. - // We don't add the IP, on purpose (want to show different - // blocks for different domains pointing to the same IP). - sDeniedMedia.insert(domain); - } - else - { - sMediaQueries.insert(domain); - args["URL"] = media_url; - if (type == 0) - { - args["TYPE"] = "media"; - } - else - { - args["TYPE"] = "audio"; - } - LLNotificationsUtil::add("MediaAlert", args, LLSD(), boost::bind(callback_media_alert, _1, _2, parcel, type, domain)); - } -} - -void callback_media_alert(const LLSD ¬ification, const LLSD &response, LLParcel* parcel, U32 type, std::string domain) -{ - S32 option = LLNotification::getSelectedOption(notification, response); - - LLHost host; - host.setHostByName(domain); - std::string ip = host.getIPString(); - - LLSD args; - if (ip != domain && domain.find('/') == std::string::npos) - { - args["DOMAIN"] = domain + " (" + ip + ")"; - } - else - { - args["DOMAIN"] = domain; - } - - if (option == 0 || option == 3) // Allow or Whitelist - { - LLViewerParcelMedia::sAllowedMedia.insert(domain); - if (option == 3) // Whitelist - { - LLSD newmedia; - newmedia["domain"] = domain; - newmedia["action"] = "allow"; - LLViewerParcelMedia::sMediaFilterList.append(newmedia); - if (ip != domain && domain.find('/') == std::string::npos) - { - newmedia["domain"] = ip; - LLViewerParcelMedia::sMediaFilterList.append(newmedia); - } - LLViewerParcelMedia::saveDomainFilterList(); - args["LISTED"] = "whitelisted"; - LLNotificationsUtil::add("MediaListed", args); - } - if (type == 0) - { - LLViewerParcelMedia::play(parcel, false); - } - else - { - LLViewerParcelMedia::playStreamingMusic(parcel, false); - } - } - else - { - if (type == 1) - { - LLViewerParcelMedia::stopStreamingMusic(); - } - else - { - LLViewerParcelMedia::stopStreamingMusic(); - } - if (option == 1 || option == 2) // Deny or Blacklist - { - LLViewerParcelMedia::sDeniedMedia.insert(domain); - if (ip != domain && domain.find('/') == std::string::npos) - { - LLViewerParcelMedia::sDeniedMedia.insert(ip); - } - - if (option == 1) // Deny - { - LLNotificationsUtil::add("MediaBlocked", args); - } - else // Blacklist - { - LLSD newmedia; - newmedia["domain"] = domain; - newmedia["action"] = "deny"; - LLViewerParcelMedia::sMediaFilterList.append(newmedia); - if (ip != domain && domain.find('/') == std::string::npos) - { - newmedia["domain"] = ip; - LLViewerParcelMedia::sMediaFilterList.append(newmedia); - } - LLViewerParcelMedia::saveDomainFilterList(); - args["LISTED"] = "blacklisted"; - LLNotificationsUtil::add("MediaListed", args); - } - } - } - - LLViewerParcelMedia::sMediaQueries.erase(domain); - if (SLFloaterMediaFilter::findInstance()) SLFloaterMediaFilter::getInstance()->setDirty(); -} - -void LLViewerParcelMedia::saveDomainFilterList() -{ - std::string medialist_filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "media_filter.xml"); - - llofstream medialistFile(medialist_filename); - LLSDSerialize::toPrettyXML(sMediaFilterList, medialistFile); - medialistFile.close(); -} - -bool LLViewerParcelMedia::loadDomainFilterList() -{ - sMediaFilterListLoaded = true; - - std::string medialist_filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "media_filter.xml"); - - if (!LLFile::isfile(medialist_filename)) - { - LLSD emptyllsd; - llofstream medialistFile(medialist_filename); - LLSDSerialize::toPrettyXML(emptyllsd, medialistFile); - medialistFile.close(); - } - - if (LLFile::isfile(medialist_filename)) - { - llifstream medialistFile(medialist_filename); - LLSDSerialize::fromXML(sMediaFilterList, medialistFile); - medialistFile.close(); - if (SLFloaterMediaFilter::findInstance()) SLFloaterMediaFilter::getInstance()->setDirty(); - return true; - } - else - { - return false; - } -} - -void LLViewerParcelMedia::clearDomainFilterList() -{ - sMediaFilterList.clear(); - sAllowedMedia.clear(); - sDeniedMedia.clear(); - saveDomainFilterList(); - LLNotificationsUtil::add("MediaFiltersCleared"); - if (SLFloaterMediaFilter::findInstance()) SLFloaterMediaFilter::getInstance()->setDirty(); -} - -std::string LLViewerParcelMedia::extractDomain(std::string url) -{ - static std::string last_region = "@"; - - if (url.empty()) - { - return url; - } - - LLStringUtil::toLower(url); - - size_t pos = url.find("//"); - - if (pos != std::string::npos) - { - size_t count = url.size() - pos + 2; - url = url.substr(pos + 2, count); - } - - // Check that there is at least one slash in the URL and add a trailing - // one if not (for media/audio URLs such as http://mydomain.net) - if (url.find('/') == std::string::npos) - { - url += '/'; - } - - // If there's a user:password@ part, remove it - pos = url.find('@'); - if (pos != std::string::npos && pos < url.find('/')) // if '@' is not before the first '/', then it's not a user:password - { - size_t count = url.size() - pos + 1; - url = url.substr(pos + 1, count); - } - - if (url.find(gAgent.getRegion()->getHost().getHostName()) == 0 || url.find(last_region) == 0) - { - // This must be a scripted object rezzed in the region: - // extend the concept of "domain" to encompass the - // scripted object server id and avoid blocking all other - // objects at once in this region... - - // Get rid of any port number - pos = url.find('/'); // We earlier made sure that there's one - url = gAgent.getRegion()->getHost().getHostName() + url.substr(pos); - - pos = url.find('?'); - if (pos != std::string::npos) - { - // Get rid of any parameter - url = url.substr(0, pos); - } - - pos = url.rfind('/'); - if (pos != std::string::npos) - { - // Get rid of the filename, if any, keeping only the server + path - url = url.substr(0, pos); - } - } - else - { - pos = url.find(':'); - if (pos != std::string::npos && pos < url.find('/')) - { - // Keep anything before the port number and strip the rest off - url = url.substr(0, pos); - } - else - { - pos = url.find('/'); // We earlier made sure that there's one - url = url.substr(0, pos); - } - } - - - // Remember this region, so to cope with requests occuring just after a - // TP out of it. - last_region = gAgent.getRegion()->getHost().getHostName(); - - return url; -} diff --git a/indra/newview/llviewerparcelmedia.h b/indra/newview/llviewerparcelmedia.h index f6c85bf3b6..ff954c37a6 100644 --- a/indra/newview/llviewerparcelmedia.h +++ b/indra/newview/llviewerparcelmedia.h @@ -57,21 +57,13 @@ class LLViewerParcelMedia : public LLViewerMediaObserver // called when the agent's parcel has a new URL, or the agent has // walked on to a new parcel with media - static void play(LLParcel* parcel, bool filter = true); + static void play(LLParcel* parcel); // user clicked play button in media transport controls static void playStreamingMusic(LLParcel* parcel, bool filter = true); // play the parcel music stream static void stopStreamingMusic(); // stop the parcel music stream - static void filterMedia(LLParcel* parcel, U32 type); // type: 0 = media, 1 = streaming music - static bool allowedMedia(std::string media_url); - - static bool loadDomainFilterList(); - static void saveDomainFilterList(); - static void clearDomainFilterList(); - static std::string extractDomain(std::string url); - static void stop(); // user clicked stop button in media transport controls @@ -102,13 +94,9 @@ class LLViewerParcelMedia : public LLViewerMediaObserver static LLUUID sMediaRegionID; // HACK: this will change with Media on a Prim static viewer_media_t sMediaImpl; - - static bool sIsUserAction; - static bool sMediaFilterListLoaded; - static LLSD sMediaFilterList; - static std::set sMediaQueries; - static std::set sAllowedMedia; - static std::set sDeniedMedia; + + // Media Filter + static F32 sMediaCommandTime; }; diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp index 5b7c7f2741..34f038cf1b 100644 --- a/indra/newview/llviewerparcelmgr.cpp +++ b/indra/newview/llviewerparcelmgr.cpp @@ -2,31 +2,25 @@ * @file llviewerparcelmgr.cpp * @brief Viewer-side representation of owned land * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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$ */ @@ -75,6 +69,7 @@ #include "lloverlaybar.h" #include "roles_constants.h" #include "llweb.h" +#include "rlvactions.h" const F32 PARCEL_COLLISION_DRAW_SECS = 1.f; @@ -126,16 +121,18 @@ LLViewerParcelMgr::LLViewerParcelMgr() mHoverRequestResult(0), mHoverWestSouth(), mHoverEastNorth(), + mCollisionRegionHandle(0), + mCollisionUpdateSignal(nullptr), mRenderCollision(FALSE), mRenderSelection(TRUE), mCollisionBanned(0), mCollisionTimer(), mMediaParcelId(0), - mMediaRegionId(0), - mHighlightSegments(NULL), - mCollisionSegments(NULL), - mAgentParcelOverlay(NULL), - mParcelsPerEdge(0) + mHighlightSegments(nullptr), + mCollisionSegments(nullptr), + mAgentParcelOverlay(nullptr), + mParcelsPerEdge(0), + mMediaRegionId(0) { mCurrentParcel = new LLParcel(); mCurrentParcelSelection = new LLParcelSelection(mCurrentParcel); @@ -145,18 +142,21 @@ LLViewerParcelMgr::LLViewerParcelMgr() mHoverParcel = new LLParcel(); mCollisionParcel = new LLParcel(); - mParcelsPerEdge = S32( REGION_WIDTH_METERS / PARCEL_GRID_STEP_METERS ); + mParcelsPerEdge = S32(8192.f / PARCEL_GRID_STEP_METERS); // 8192 is the maximum region size on WhiteCore and solves the audio problem. mHighlightSegments = new U8[(mParcelsPerEdge+1)*(mParcelsPerEdge+1)]; resetSegments(mHighlightSegments); + mCollisionBitmap = new U8[getCollisionBitmapSize()]; + memset(mCollisionBitmap, 0, getCollisionBitmapSize()); + mCollisionSegments = new U8[(mParcelsPerEdge+1)*(mParcelsPerEdge+1)]; resetSegments(mCollisionSegments); // JC: Resolved a merge conflict here, eliminated // mBlockedImage->setAddressMode(LLTexUnit::TAM_WRAP); // because it is done in llviewertexturelist.cpp - mBlockedImage = LLViewerTextureManager::getFetchedTextureFromFile("noentrylines.j2c"); - mPassImage = LLViewerTextureManager::getFetchedTextureFromFile("noentrypasslines.j2c"); + mBlockedImage = LLViewerTextureManager::getFetchedTextureFromFile("world/NoEntryLines.png"); + mPassImage = LLViewerTextureManager::getFetchedTextureFromFile("world/NoEntryPassLines.png"); S32 overlay_size = mParcelsPerEdge * mParcelsPerEdge / PARCEL_OVERLAY_CHUNKS; sPackedOverlay = new U8[overlay_size]; @@ -168,9 +168,14 @@ LLViewerParcelMgr::LLViewerParcelMgr() mAgentParcelOverlay[i] = 0; } + mParcelsPerEdge = S32(REGION_WIDTH_METERS / PARCEL_GRID_STEP_METERS); mTeleportInProgress = TRUE; // the initial parcel update is treated like teleport } +void LLViewerParcelMgr::init(F32 region_size) +{ + mParcelsPerEdge = S32(region_size / PARCEL_GRID_STEP_METERS); +} LLViewerParcelMgr::~LLViewerParcelMgr() { @@ -195,6 +200,9 @@ LLViewerParcelMgr::~LLViewerParcelMgr() delete[] mHighlightSegments; mHighlightSegments = NULL; + delete[] mCollisionBitmap; + mCollisionBitmap = NULL; + delete[] mCollisionSegments; mCollisionSegments = NULL; @@ -210,27 +218,25 @@ LLViewerParcelMgr::~LLViewerParcelMgr() void LLViewerParcelMgr::dump() { - llinfos << "Parcel Manager Dump" << llendl; - llinfos << "mSelected " << S32(mSelected) << llendl; - llinfos << "Selected parcel: " << llendl; - llinfos << mWestSouth << " to " << mEastNorth << llendl; + LL_INFOS() << "Parcel Manager Dump" << LL_ENDL; + LL_INFOS() << "mSelected " << S32(mSelected) << LL_ENDL; + LL_INFOS() << "Selected parcel: " << LL_ENDL; + LL_INFOS() << mWestSouth << " to " << mEastNorth << LL_ENDL; mCurrentParcel->dump(); - llinfos << "banning " << mCurrentParcel->mBanList.size() << llendl; + LL_INFOS() << "banning " << mCurrentParcel->mBanList.size() << LL_ENDL; - access_map_const_iterator cit = mCurrentParcel->mBanList.begin(); - access_map_const_iterator end = mCurrentParcel->mBanList.end(); - for ( ; cit != end; ++cit) + for (const auto& pair : mCurrentParcel->mBanList) { - llinfos << "ban id " << (*cit).first << llendl; + LL_INFOS() << "ban id " << pair.first << LL_ENDL; } - llinfos << "Hover parcel:" << llendl; + LL_INFOS() << "Hover parcel:" << LL_ENDL; mHoverParcel->dump(); - llinfos << "Agent parcel:" << llendl; + LL_INFOS() << "Agent parcel:" << LL_ENDL; mAgentParcel->dump(); } -LLViewerRegion* LLViewerParcelMgr::getSelectionRegion() +LLViewerRegion* LLViewerParcelMgr::getSelectionRegion() const { return LLWorld::getInstance()->getRegionFromPosGlobal( mWestSouth ); } @@ -293,7 +299,7 @@ S32 LLViewerParcelMgr::getSelectedArea() const F64 width = mEastNorth.mdV[VX] - mWestSouth.mdV[VX]; F64 height = mEastNorth.mdV[VY] - mWestSouth.mdV[VY]; F32 area = (F32)(width * height); - rv = llround(area); + rv = ll_round(area); } return rv; } @@ -313,10 +319,10 @@ void LLViewerParcelMgr::writeHighlightSegments(F32 west, F32 south, F32 east, F32 north) { S32 x, y; - S32 min_x = llround( west / PARCEL_GRID_STEP_METERS ); - S32 max_x = llround( east / PARCEL_GRID_STEP_METERS ); - S32 min_y = llround( south / PARCEL_GRID_STEP_METERS ); - S32 max_y = llround( north / PARCEL_GRID_STEP_METERS ); + S32 min_x = ll_round( west / PARCEL_GRID_STEP_METERS ); + S32 max_x = ll_round( east / PARCEL_GRID_STEP_METERS ); + S32 min_y = ll_round( south / PARCEL_GRID_STEP_METERS ); + S32 max_y = ll_round( north / PARCEL_GRID_STEP_METERS ); const S32 STRIDE = mParcelsPerEdge+1; @@ -428,12 +434,12 @@ LLParcelSelectionHandle LLViewerParcelMgr::selectParcelAt(const LLVector3d& pos_ LLVector3d northeast = pos_global; southwest -= LLVector3d( PARCEL_GRID_STEP_METERS/2, PARCEL_GRID_STEP_METERS/2, 0 ); - southwest.mdV[VX] = llround( southwest.mdV[VX], (F64)PARCEL_GRID_STEP_METERS ); - southwest.mdV[VY] = llround( southwest.mdV[VY], (F64)PARCEL_GRID_STEP_METERS ); + southwest.mdV[VX] = ll_round( southwest.mdV[VX], (F64)PARCEL_GRID_STEP_METERS ); + southwest.mdV[VY] = ll_round( southwest.mdV[VY], (F64)PARCEL_GRID_STEP_METERS ); northeast += LLVector3d( PARCEL_GRID_STEP_METERS/2, PARCEL_GRID_STEP_METERS/2, 0 ); - northeast.mdV[VX] = llround( northeast.mdV[VX], (F64)PARCEL_GRID_STEP_METERS ); - northeast.mdV[VY] = llround( northeast.mdV[VY], (F64)PARCEL_GRID_STEP_METERS ); + northeast.mdV[VX] = ll_round( northeast.mdV[VX], (F64)PARCEL_GRID_STEP_METERS ); + northeast.mdV[VY] = ll_round( northeast.mdV[VY], (F64)PARCEL_GRID_STEP_METERS ); // Snap to parcel return selectLand( southwest, northeast, TRUE ); @@ -450,9 +456,9 @@ LLParcelSelectionHandle LLViewerParcelMgr::selectParcelInRectangle() void LLViewerParcelMgr::selectCollisionParcel() { // BUG: Claim to be in the agent's region - mWestSouth = gAgent.getRegion()->getOriginGlobal(); + mWestSouth = getSelectionRegion()->getOriginGlobal(); mEastNorth = mWestSouth; - mEastNorth += LLVector3d(PARCEL_GRID_STEP_METERS, PARCEL_GRID_STEP_METERS, 0.0); + mEastNorth += LLVector3d(getSelectionRegion()->getWidth()/REGION_WIDTH_METERS * PARCEL_GRID_STEP_METERS, getSelectionRegion()->getWidth()/REGION_WIDTH_METERS * PARCEL_GRID_STEP_METERS, 0.0); // BUG: must be in the sim you are in LLMessageSystem *msg = gMessageSystem; @@ -606,13 +612,13 @@ void LLViewerParcelMgr::deselectLand() void LLViewerParcelMgr::addObserver(LLParcelObserver* observer) { - mObservers.put(observer); + mObservers.push_back(observer); } void LLViewerParcelMgr::removeObserver(LLParcelObserver* observer) { - mObservers.removeObj(observer); + vector_replace_with_last(mObservers, observer); } @@ -621,16 +627,16 @@ void LLViewerParcelMgr::removeObserver(LLParcelObserver* observer) // from the list. void LLViewerParcelMgr::notifyObservers() { - LLDynamicArray observers; - S32 count = mObservers.count(); + std::vector observers; + S32 count = mObservers.size(); S32 i; for(i = 0; i < count; ++i) { - observers.put(mObservers.get(i)); + observers.push_back(mObservers.at(i)); } for(i = 0; i < count; ++i) { - observers.get(i)->changed(); + observers.at(i)->changed(); } } @@ -864,8 +870,8 @@ LLParcel* LLViewerParcelMgr::getCollisionParcel() const void LLViewerParcelMgr::render() { - static const LLCachedControl RenderParcelSelection("RenderParcelSelection"); - if (mSelected && mRenderSelection && RenderParcelSelection) + static const LLCachedControl render_parcel_selection(gSavedSettings, "RenderParcelSelection"); + if (mSelected && mRenderSelection && render_parcel_selection) { // Rendering is done in agent-coordinates, so need to supply // an appropriate offset to the render code. @@ -885,8 +891,8 @@ void LLViewerParcelMgr::renderParcelCollision() mRenderCollision = FALSE; } - static const LLCachedControl ShowBanLines("ShowBanLines"); - if (mRenderCollision && ShowBanLines) + static const LLCachedControl render_ban_line(gSavedSettings, "ShowBanLines"); + if (mRenderCollision && render_ban_line) { LLViewerRegion* regionp = gAgent.getRegion(); if (regionp) @@ -909,7 +915,7 @@ void LLViewerParcelMgr::sendParcelAccessListRequest(U32 flags) if (!region) return; LLMessageSystem *msg = gMessageSystem; - + if (flags & AL_BAN) { @@ -919,6 +925,14 @@ void LLViewerParcelMgr::sendParcelAccessListRequest(U32 flags) { mCurrentParcel->mAccessList.clear(); } + if (flags & AL_ALLOW_EXPERIENCE) + { + mCurrentParcel->clearExperienceKeysByType(EXPERIENCE_KEY_TYPE_ALLOWED); + } + if (flags & AL_BLOCK_EXPERIENCE) + { + mCurrentParcel->clearExperienceKeysByType(EXPERIENCE_KEY_TYPE_BLOCKED); + } // Only the headers differ msg->newMessageFast(_PREHASH_ParcelAccessListRequest); @@ -965,7 +979,7 @@ void LLViewerParcelMgr::sendParcelGodForceOwner(const LLUUID& owner_id) return; } - llinfos << "Claiming " << mWestSouth << " to " << mEastNorth << llendl; + LL_INFOS() << "Claiming " << mWestSouth << " to " << mEastNorth << LL_ENDL; // BUG: Only works for the region containing mWestSouthBottom LLVector3d east_north_region_check( mEastNorth ); @@ -988,7 +1002,7 @@ void LLViewerParcelMgr::sendParcelGodForceOwner(const LLUUID& owner_id) return; } - llinfos << "Region " << region->getOriginGlobal() << llendl; + LL_INFOS() << "Region " << region->getOriginGlobal() << LL_ENDL; LLSD payload; payload["owner_id"] = owner_id; @@ -1128,8 +1142,8 @@ LLViewerParcelMgr::ParcelBuyInfo* LLViewerParcelMgr::setupParcelBuy( if (is_claim) { - llinfos << "Claiming " << mWestSouth << " to " << mEastNorth << llendl; - llinfos << "Region " << region->getOriginGlobal() << llendl; + LL_INFOS() << "Claiming " << mWestSouth << " to " << mEastNorth << LL_ENDL; + LL_INFOS() << "Region " << region->getOriginGlobal() << LL_ENDL; // BUG: Only works for the region containing mWestSouthBottom LLVector3d east_north_region_check( mEastNorth ); @@ -1295,11 +1309,14 @@ const std::string& LLViewerParcelMgr::getAgentParcelName() const void LLViewerParcelMgr::sendParcelPropertiesUpdate(LLParcel* parcel, bool use_agent_region) { - if(!parcel) return; + if (!parcel) + return; LLViewerRegion *region = use_agent_region ? gAgent.getRegion() : LLWorld::getInstance()->getRegionFromPosGlobal( mWestSouth ); - if (!region) return; - //llinfos << "found region: " << region->getName() << llendl; + if (!region) + return; + + //LL_INFOS() << "found region: " << region->getName() << LL_ENDL; LLSD body; std::string url = region->getCapability("ParcelPropertiesUpdate"); @@ -1309,8 +1326,9 @@ void LLViewerParcelMgr::sendParcelPropertiesUpdate(LLParcel* parcel, bool use_ag U32 message_flags = 0x01; body["flags"] = ll_sd_from_U32(message_flags); parcel->packMessage(body); - llinfos << "Sending parcel properties update via capability to: " - << url << llendl; + LL_INFOS() << "Sending parcel properties update via capability to: " + << url << LL_ENDL; + LLHTTPClient::post(url, body, new LLHTTPClient::ResponderIgnore); } else @@ -1338,10 +1356,8 @@ void LLViewerParcelMgr::setHoverParcel(const LLVector3d& pos) static U32 last_west, last_south; // only request parcel info when tooltip is shown - if (!gSavedSettings.getBOOL("ShowLandHoverTip")) - { - return; - } + if (!gSavedSettings.getBOOL("ShowLandHoverTip")) return; + // only request parcel info if position has changed outside of the // last parcel grid step U32 west_parcel_step = (U32) floor( pos.mdV[VX] / PARCEL_GRID_STEP_METERS ); @@ -1363,6 +1379,7 @@ void LLViewerParcelMgr::setHoverParcel(const LLVector3d& pos) return; } + // Send a rectangle around the point. // This means the parcel sent back is at least a rectangle around the point, // which is more efficient for public land. Fewer requests are sent. JC @@ -1406,16 +1423,15 @@ void LLViewerParcelMgr::processParcelOverlay(LLMessageSystem *msg, void **user) if (packed_overlay_size <= 0) { - llwarns << "Overlay size " << packed_overlay_size << llendl; + LL_WARNS() << "Overlay size " << packed_overlay_size << LL_ENDL; return; } - S32 parcels_per_edge = LLViewerParcelMgr::getInstance()->mParcelsPerEdge; - S32 expected_size = parcels_per_edge * parcels_per_edge / PARCEL_OVERLAY_CHUNKS; + S32 expected_size = 1024; if (packed_overlay_size != expected_size) { - llwarns << "Got parcel overlay size " << packed_overlay_size - << " expecting " << expected_size << llendl; + LL_WARNS() << "Got parcel overlay size " << packed_overlay_size + << " expecting " << expected_size << LL_ENDL; return; } @@ -1474,6 +1490,11 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use S32 other_clean_time = 0; LLViewerParcelMgr& parcel_mgr = LLViewerParcelMgr::instance(); + LLViewerRegion* msg_region = LLWorld::getInstance()->getRegion(msg->getSender()); + if(msg_region) + parcel_mgr.mParcelsPerEdge = S32(msg_region->getWidth() / PARCEL_GRID_STEP_METERS); + else + parcel_mgr.mParcelsPerEdge = S32(gAgent.getRegion()->getWidth() / PARCEL_GRID_STEP_METERS); msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_RequestResult, request_result ); msg->getS32Fast(_PREHASH_ParcelData, _PREHASH_SequenceID, sequence_id ); @@ -1481,7 +1502,7 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use if (request_result == PARCEL_RESULT_NO_DATA) { // no valid parcel data - llinfos << "no valid parcel data" << llendl; + LL_INFOS() << "no valid parcel data" << LL_ENDL; return; } @@ -1513,9 +1534,9 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use } else { - llinfos << "out of order agent parcel sequence id " << sequence_id + LL_INFOS() << "out of order agent parcel sequence id " << sequence_id << " last good " << parcel_mgr.mAgentParcelSequenceID - << llendl; + << LL_ENDL; return; } @@ -1587,6 +1608,7 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use if (parcel == parcel_mgr.mAgentParcel) { + // new agent parcel S32 bitmap_size = parcel_mgr.mParcelsPerEdge * parcel_mgr.mParcelsPerEdge / 8; @@ -1599,6 +1621,7 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use // Let interesting parties know about agent parcel change. LLViewerParcelMgr* instance = LLViewerParcelMgr::getInstance(); + // Notify anything that wants to know when the agent changes parcels instance->mAgentParcelChangedSignal(); if (instance->mTeleportInProgress) @@ -1677,7 +1700,7 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use } // Request access list information for this land - parcel_mgr.sendParcelAccessListRequest(AL_ACCESS | AL_BAN); + parcel_mgr.sendParcelAccessListRequest(AL_ACCESS | AL_BAN | AL_ALLOW_EXPERIENCE | AL_BLOCK_EXPERIENCE); // Request dwell for this land, if it's not public land. parcel_mgr.mSelectedDwell = DWELL_NAN; @@ -1713,18 +1736,31 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use } - S32 bitmap_size = parcel_mgr.mParcelsPerEdge - * parcel_mgr.mParcelsPerEdge - / 8; - U8* bitmap = new U8[ bitmap_size ]; - msg->getBinaryDataFast(_PREHASH_ParcelData, _PREHASH_Bitmap, bitmap, bitmap_size); +// S32 bitmap_size = parcel_mgr.mParcelsPerEdge +// * parcel_mgr.mParcelsPerEdge +// / 8; +// U8* bitmap = new U8[ bitmap_size ]; +// msg->getBinaryDataFast(_PREHASH_ParcelData, _PREHASH_Bitmap, bitmap, bitmap_size); +// [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-06-20 (Catznip-3.3.0) + msg->getBinaryDataFast(_PREHASH_ParcelData, _PREHASH_Bitmap, parcel_mgr.mCollisionBitmap, parcel_mgr.getCollisionBitmapSize()); +// [/SL:KB] parcel_mgr.resetSegments(parcel_mgr.mCollisionSegments); - parcel_mgr.writeSegmentsFromBitmap( bitmap, parcel_mgr.mCollisionSegments ); +// parcel_mgr.writeSegmentsFromBitmap( bitmap, parcel_mgr.mCollisionSegments ); +// [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-06-20 (Catznip-3.3.0) + parcel_mgr.writeSegmentsFromBitmap(parcel_mgr.mCollisionBitmap, parcel_mgr.mCollisionSegments); +// [/SL:KB] - delete[] bitmap; - bitmap = NULL; +// delete[] bitmap; +// bitmap = NULL; +// [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-06-20 (Catznip-3.3.0) + LLViewerRegion* pRegion = LLWorld::getInstance()->getRegion(msg->getSender()); + parcel_mgr.mCollisionRegionHandle = (pRegion) ? pRegion->getHandle() : 0; + + if (parcel_mgr.mCollisionUpdateSignal) + (*parcel_mgr.mCollisionUpdateSignal)(pRegion); +// [/SL:KB] } else if (sequence_id == HOVERED_PARCEL_SEQ_ID) { @@ -1742,7 +1778,10 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use } else { - // look for music. + // Check for video + LLViewerParcelMedia::update(parcel); + + // Then check for music if (gAudiop) { if (parcel) @@ -1766,20 +1805,23 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use // If there is a new music URL and it's valid, play it. if (music_url.size() > 12) { - if (music_url.substr(0,7) == "http://") + if (music_url.substr(0,7) == "http://" + || music_url.substr(0, 8) == "https://") { optionally_start_music(parcel); } else { - llinfos << "Stopping parcel music (invalid audio stream URL)" << llendl; + LL_INFOS() << "Stopping parcel music (invalid audio stream URL)" << LL_ENDL; // clears the URL + // null value causes fade out gAudiop->startInternetStream(LLStringUtil::null); } } else if (!gAudiop->getInternetStreamURL().empty()) { - llinfos << "Stopping parcel music (parcel stream URL is empty)" << llendl; + LL_INFOS() << "Stopping parcel music (parcel stream URL is empty)" << LL_ENDL; + // null value causes fade out gAudiop->startInternetStream(LLStringUtil::null); } } @@ -1790,9 +1832,6 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use gAudiop->stopInternetStream(); } }//if gAudiop - - // now check for video - LLViewerParcelMedia::update( parcel ); }; } @@ -1800,17 +1839,14 @@ void optionally_start_music(LLParcel* parcel) { if (gSavedSettings.getBOOL("AudioStreamingMusic")) { - - - // Make the user click the start button on the overlay bar. JC - // llinfos << "Starting parcel music " << parcel->getMusicURL() << llendl; + // LL_INFOS() << "Starting parcel music " << parcel->getMusicURL() << LL_ENDL; // now only play music when you enter a new parcel if the control is in PLAY state // changed as part of SL-4878 if (gOverlayBar && gOverlayBar->musicPlaying()) { - LLPanelNearByMedia* nearby_media_panel = LLFloaterNearbyMedia::instanceExists() ? LLFloaterNearbyMedia::getInstance()->getMediaPanel() : NULL; + LLPanelNearByMedia* nearby_media_panel = LLFloaterNearbyMedia::instanceExists() ? LLFloaterNearbyMedia::getInstance()->getMediaPanel() : nullptr; if ((nearby_media_panel && nearby_media_panel->getParcelAudioAutoStart()) || // or they have expressed no opinion in the UI, but have autoplay on... @@ -1818,6 +1854,7 @@ void optionally_start_music(LLParcel* parcel) /*gSavedSettings.getBOOL(LLViewerMedia::AUTO_PLAY_MEDIA_SETTING) &&*/ gSavedSettings.getBOOL("MediaTentativeAutoPlay"))) { + LL_INFOS() << "Starting parcel music " << parcel->getMusicURL() << LL_ENDL; LLViewerParcelMedia::playStreamingMusic(parcel); return; } @@ -1844,8 +1881,8 @@ void LLViewerParcelMgr::processParcelAccessListReply(LLMessageSystem *msg, void if (parcel_id != parcel->getLocalID()) { - llwarns << "processParcelAccessListReply for parcel " << parcel_id - << " which isn't the selected parcel " << parcel->getLocalID()<< llendl; + LL_WARNS_ONCE("") << "processParcelAccessListReply for parcel " << parcel_id + << " which isn't the selected parcel " << parcel->getLocalID()<< LL_ENDL; return; } @@ -1857,6 +1894,14 @@ void LLViewerParcelMgr::processParcelAccessListReply(LLMessageSystem *msg, void { parcel->unpackAccessEntries(msg, &(parcel->mBanList) ); } + else if (message_flags & AL_ALLOW_EXPERIENCE) + { + parcel->unpackExperienceEntries(msg, EXPERIENCE_KEY_TYPE_ALLOWED); + } + else if (message_flags & AL_BLOCK_EXPERIENCE) + { + parcel->unpackExperienceEntries(msg, EXPERIENCE_KEY_TYPE_BLOCKED); + } /*else if (message_flags & AL_RENTER) { parcel->unpackAccessEntries(msg, &(parcel->mRenterList) ); @@ -1891,10 +1936,6 @@ void LLViewerParcelMgr::processParcelDwellReply(LLMessageSystem* msg, void**) void LLViewerParcelMgr::sendParcelAccessListUpdate(U32 which) { - - LLUUID transactionUUID; - transactionUUID.generate(); - if (!mSelected) { return; @@ -1903,125 +1944,95 @@ void LLViewerParcelMgr::sendParcelAccessListUpdate(U32 which) LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal( mWestSouth ); if (!region) return; - LLMessageSystem* msg = gMessageSystem; - LLParcel* parcel = mCurrentParcel; if (!parcel) return; if (which & AL_ACCESS) - { - S32 count = parcel->mAccessList.size(); - S32 num_sections = (S32) ceil(count/PARCEL_MAX_ENTRIES_PER_PACKET); - S32 sequence_id = 1; - BOOL start_message = TRUE; - BOOL initial = TRUE; - - access_map_const_iterator cit = parcel->mAccessList.begin(); - access_map_const_iterator end = parcel->mAccessList.end(); - while ( (cit != end) || initial ) - { - if (start_message) - { - msg->newMessageFast(_PREHASH_ParcelAccessListUpdate); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() ); - msg->nextBlockFast(_PREHASH_Data); - msg->addU32Fast(_PREHASH_Flags, AL_ACCESS); - msg->addS32(_PREHASH_LocalID, parcel->getLocalID() ); - msg->addUUIDFast(_PREHASH_TransactionID, transactionUUID); - msg->addS32Fast(_PREHASH_SequenceID, sequence_id); - msg->addS32Fast(_PREHASH_Sections, num_sections); - start_message = FALSE; - - if (initial && (cit == end)) - { - // pack an empty block if there will be no data - msg->nextBlockFast(_PREHASH_List); - msg->addUUIDFast(_PREHASH_ID, LLUUID::null ); - msg->addS32Fast(_PREHASH_Time, 0 ); - msg->addU32Fast(_PREHASH_Flags, 0 ); - } - - initial = FALSE; - sequence_id++; + { + sendParcelAccessListUpdate(AL_ACCESS, parcel->mAccessList, region, parcel->getLocalID()); + } - } - - while ( (cit != end) && (msg->getCurrentSendTotal() < MTUBYTES)) - { + if (which & AL_BAN) + { + sendParcelAccessListUpdate(AL_BAN, parcel->mBanList, region, parcel->getLocalID()); + } - const LLAccessEntry& entry = (*cit).second; - - msg->nextBlockFast(_PREHASH_List); - msg->addUUIDFast(_PREHASH_ID, entry.mID ); - msg->addS32Fast(_PREHASH_Time, entry.mTime ); - msg->addU32Fast(_PREHASH_Flags, entry.mFlags ); - ++cit; - } + if (which & AL_ALLOW_EXPERIENCE) + { + sendParcelAccessListUpdate(AL_ALLOW_EXPERIENCE, parcel->getExperienceKeysByType(EXPERIENCE_KEY_TYPE_ALLOWED), region, parcel->getLocalID()); + } - start_message = TRUE; - msg->sendReliable( region->getHost() ); - } + if (which & AL_BLOCK_EXPERIENCE) + { + sendParcelAccessListUpdate(AL_BLOCK_EXPERIENCE, parcel->getExperienceKeysByType(EXPERIENCE_KEY_TYPE_BLOCKED), region, parcel->getLocalID()); } +} - if (which & AL_BAN) - { - S32 count = parcel->mBanList.size(); - S32 num_sections = (S32) ceil(count/PARCEL_MAX_ENTRIES_PER_PACKET); - S32 sequence_id = 1; - BOOL start_message = TRUE; - BOOL initial = TRUE; - - access_map_const_iterator cit = parcel->mBanList.begin(); - access_map_const_iterator end = parcel->mBanList.end(); - while ( (cit != end) || initial ) - { - if (start_message) - { - msg->newMessageFast(_PREHASH_ParcelAccessListUpdate); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() ); - msg->nextBlockFast(_PREHASH_Data); - msg->addU32Fast(_PREHASH_Flags, AL_BAN); - msg->addS32(_PREHASH_LocalID, parcel->getLocalID() ); - msg->addUUIDFast(_PREHASH_TransactionID, transactionUUID); - msg->addS32Fast(_PREHASH_SequenceID, sequence_id); - msg->addS32Fast(_PREHASH_Sections, num_sections); - start_message = FALSE; - - if (initial && (cit == end)) - { - // pack an empty block if there will be no data - msg->nextBlockFast(_PREHASH_List); - msg->addUUIDFast(_PREHASH_ID, LLUUID::null ); - msg->addS32Fast(_PREHASH_Time, 0 ); - msg->addU32Fast(_PREHASH_Flags, 0 ); - } +void LLViewerParcelMgr::sendParcelAccessListUpdate(U32 flags, const LLAccessEntry::map& entries, LLViewerRegion* region, S32 parcel_local_id) +{ + S32 count = entries.size(); + S32 num_sections = (S32) ceil(count/PARCEL_MAX_ENTRIES_PER_PACKET); + S32 sequence_id = 1; + BOOL start_message = TRUE; + BOOL initial = TRUE; - initial = FALSE; - sequence_id++; - } - - while ( (cit != end) && (msg->getCurrentSendTotal() < MTUBYTES)) + LLUUID transactionUUID; + transactionUUID.generate(); + + + LLMessageSystem* msg = gMessageSystem; + + LLAccessEntry::map::const_iterator cit = entries.begin(); + LLAccessEntry::map::const_iterator end = entries.end(); + while ( (cit != end) || initial ) + { + if (start_message) + { + msg->newMessageFast(_PREHASH_ParcelAccessListUpdate); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() ); + msg->nextBlockFast(_PREHASH_Data); + msg->addU32Fast(_PREHASH_Flags, flags); + msg->addS32(_PREHASH_LocalID, parcel_local_id); + msg->addUUIDFast(_PREHASH_TransactionID, transactionUUID); + msg->addS32Fast(_PREHASH_SequenceID, sequence_id); + msg->addS32Fast(_PREHASH_Sections, num_sections); + start_message = FALSE; + + if (initial && (cit == end)) { - const LLAccessEntry& entry = (*cit).second; - + // pack an empty block if there will be no data msg->nextBlockFast(_PREHASH_List); - msg->addUUIDFast(_PREHASH_ID, entry.mID ); - msg->addS32Fast(_PREHASH_Time, entry.mTime ); - msg->addU32Fast(_PREHASH_Flags, entry.mFlags ); - ++cit; + msg->addUUIDFast(_PREHASH_ID, LLUUID::null ); + msg->addS32Fast(_PREHASH_Time, 0 ); + msg->addU32Fast(_PREHASH_Flags, 0 ); } - start_message = TRUE; - msg->sendReliable( region->getHost() ); + initial = FALSE; + sequence_id++; + } + + while ( (cit != end) && (msg->getCurrentSendTotal() < MTUBYTES)) + { + + const LLAccessEntry& entry = (*cit).second; + + msg->nextBlockFast(_PREHASH_List); + msg->addUUIDFast(_PREHASH_ID, entry.mID ); + msg->addS32Fast(_PREHASH_Time, entry.mTime ); + msg->addU32Fast(_PREHASH_Flags, entry.mFlags ); + ++cit; + } + + start_message = TRUE; + msg->sendReliable( region->getHost() ); } } + void LLViewerParcelMgr::deedLandToGroup() { std::string group_name; @@ -2180,6 +2191,12 @@ bool LLViewerParcelMgr::canAgentBuyParcel(LLParcel* parcel, bool forGroup) const void LLViewerParcelMgr::startBuyLand(BOOL is_for_group) { +// [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0a) + if (RlvActions::isRlvEnabled() && !RlvActions::canShowLocation()) + return; +// [/RLVa:KB] + if (selectionEmpty()) selectParcelAt(gAgent.getPositionGlobal()); + LLFloaterBuyLand::buyLand(getSelectionRegion(), mCurrentParcelSelection, is_for_group == TRUE); } @@ -2543,3 +2560,10 @@ void LLViewerParcelMgr::onTeleportFailed() { mTeleportFailedSignal(); } + +boost::signals2::connection LLViewerParcelMgr::setCollisionUpdateCallback(const collision_update_signal_t::slot_type & cb) +{ + if (!mCollisionUpdateSignal) + mCollisionUpdateSignal = new collision_update_signal_t(); + return mCollisionUpdateSignal->connect(cb); +} diff --git a/indra/newview/llviewerparcelmgr.h b/indra/newview/llviewerparcelmgr.h index 5ae44e2d0b..fbd829718b 100644 --- a/indra/newview/llviewerparcelmgr.h +++ b/indra/newview/llviewerparcelmgr.h @@ -2,31 +2,25 @@ * @file llviewerparcelmgr.h * @brief Viewer-side representation of owned land * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -34,9 +28,8 @@ #define LL_LLVIEWERPARCELMGR_H #include "v3dmath.h" -#include "lldarray.h" #include "llframetimer.h" -#include "llmemory.h" +#include "llsingleton.h" #include "llparcelselection.h" #include "llui.h" @@ -79,23 +72,24 @@ class LLParcelObserver class LLViewerParcelMgr : public LLSingleton { + friend class LLSingleton; + LLViewerParcelMgr(); + ~LLViewerParcelMgr(); public: - typedef boost::function teleport_finished_callback_t; + typedef std::function teleport_finished_callback_t; typedef boost::signals2::signal teleport_finished_signal_t; - typedef boost::function parcel_changed_callback_t; + typedef std::function parcel_changed_callback_t; typedef boost::signals2::signal parcel_changed_signal_t; - LLViewerParcelMgr(); - ~LLViewerParcelMgr(); - + void init(F32 region_size); static void cleanupGlobals(); BOOL selectionEmpty() const; F32 getSelectionWidth() const { return F32(mEastNorth.mdV[VX] - mWestSouth.mdV[VX]); } F32 getSelectionHeight() const { return F32(mEastNorth.mdV[VY] - mWestSouth.mdV[VY]); } BOOL getSelection(LLVector3d &min, LLVector3d &max) { min = mWestSouth; max = mEastNorth; return !selectionEmpty();} - LLViewerRegion* getSelectionRegion(); + LLViewerRegion* getSelectionRegion() const; F32 getDwelling() const { return mSelectedDwell;} void getDisplayInfo(S32* area, S32* claim, S32* rent, BOOL* for_sale, F32* dwell); @@ -167,6 +161,13 @@ class LLViewerParcelMgr : public LLSingleton LLParcel* getCollisionParcel() const; + const U8* getCollisionBitmap() const { return mCollisionBitmap; } + size_t getCollisionBitmapSize() const { return mParcelsPerEdge * mParcelsPerEdge / 8; } + U64 getCollisionRegionHandle() const { return mCollisionRegionHandle; } + + typedef boost::signals2::signal collision_update_signal_t; + boost::signals2::connection setCollisionUpdateCallback(const collision_update_signal_t::slot_type & cb); + // Can this agent build on the parcel he is on? // Used for parcel property icons in nav bar. bool allowAgentBuild() const; @@ -294,6 +295,8 @@ class LLViewerParcelMgr : public LLSingleton static BOOL isParcelModifiableByAgent(const LLParcel* parcelp, U64 group_proxy_power); private: + static void sendParcelAccessListUpdate(U32 flags, const std::map& entries, LLViewerRegion* region, S32 parcel_local_id); + static void sendParcelExperienceUpdate( const U32 flags, uuid_vec_t experience_ids, LLViewerRegion* region, S32 parcel_local_id ); static bool releaseAlertCB(const LLSD& notification, const LLSD& response); // If the user is claiming land and the current selection @@ -335,7 +338,7 @@ class LLViewerParcelMgr : public LLSingleton LLVector3d mHoverWestSouth; LLVector3d mHoverEastNorth; - LLDynamicArray mObservers; + std::vector mObservers; BOOL mTeleportInProgress; teleport_finished_signal_t mTeleportFinishedSignal; @@ -358,6 +361,9 @@ class LLViewerParcelMgr : public LLSingleton // Watch for pending collisions with a parcel you can't access. // If it's coming, draw the parcel's boundaries. LLParcel* mCollisionParcel; + U8* mCollisionBitmap; + U64 mCollisionRegionHandle; + collision_update_signal_t* mCollisionUpdateSignal; U8* mCollisionSegments; BOOL mRenderCollision; BOOL mRenderSelection; diff --git a/indra/newview/llviewerparceloverlay.cpp b/indra/newview/llviewerparceloverlay.cpp index 42bf3100c7..f2a5de0159 100644 --- a/indra/newview/llviewerparceloverlay.cpp +++ b/indra/newview/llviewerparceloverlay.cpp @@ -2,31 +2,25 @@ * @file llviewerparceloverlay.cpp * @brief LLViewerParcelOverlay class implementation * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -54,11 +48,19 @@ #include "llglheaders.h" #include "pipeline.h" + const U8 OVERLAY_IMG_COMPONENTS = 4; +// [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-06-20 (Catznip-3.3.0) +LLViewerParcelOverlay::update_signal_t* LLViewerParcelOverlay::mUpdateSignal = NULL; +// [/SL:KB] + LLViewerParcelOverlay::LLViewerParcelOverlay(LLViewerRegion* region, F32 region_width_meters) : mRegion( region ), mParcelGridsPerEdge( S32( region_width_meters / PARCEL_GRID_STEP_METERS ) ), +// Aurora Sim + mRegionSize(S32(region_width_meters)), +// Aurora Sim mDirty( FALSE ), mTimeSinceLastUpdate(), mOverlayTextureIdx(-1), @@ -413,7 +415,12 @@ void LLViewerParcelOverlay::uncompressLandOverlay(S32 chunk, U8 *packed_overlay) { // Unpack the message data into the ownership array S32 size = mParcelGridsPerEdge * mParcelGridsPerEdge; - S32 chunk_size = size / PARCEL_OVERLAY_CHUNKS; + +// Aurora Sim + //S32 chunk_size = size / PARCEL_OVERLAY_CHUNKS; + S32 mParcelOverLayChunks = mRegionSize * mRegionSize / (128 * 128); + S32 chunk_size = size / mParcelOverLayChunks; +// Aurora Sim memcpy(mOwnership + chunk*chunk_size, packed_overlay, chunk_size); /*Flawfinder: ignore*/ @@ -437,9 +444,12 @@ void LLViewerParcelOverlay::updatePropertyLines() const LLColor4U auction_coloru = gColors.getColor4("PropertyColorAuction"); // Build into dynamic arrays, then copy into static arrays. - LLDynamicArray new_vertex_array; - LLDynamicArray new_color_array; - LLDynamicArray new_coord_array; + std::vector new_vertex_array; + new_vertex_array.reserve(256); + std::vector new_color_array; + new_color_array.reserve(256); + std::vector new_coord_array; + new_coord_array.reserve(256); U8 overlay = 0; BOOL add_edge = FALSE; @@ -604,7 +614,7 @@ void LLViewerParcelOverlay::updatePropertyLines() // Now copy into static arrays for faster rendering. // Attempt to recycle old arrays if possible to avoid memory // shuffling. - S32 new_vertex_count = new_vertex_array.count(); + S32 new_vertex_count = new_vertex_array.size(); if (!(mVertexArray && mColorArray && new_vertex_count == mVertexCount)) { @@ -628,7 +638,7 @@ void LLViewerParcelOverlay::updatePropertyLines() F32* vertex = mVertexArray; for (i = 0; i < mVertexCount; i++) { - const LLVector3& point = new_vertex_array.get(i); + const LLVector3& point = new_vertex_array.at(i); *vertex = point.mV[VX]; vertex++; *vertex = point.mV[VY]; @@ -640,7 +650,7 @@ void LLViewerParcelOverlay::updatePropertyLines() U8* colorp = mColorArray; for (i = 0; i < mVertexCount; i++) { - const LLColor4U& color = new_color_array.get(i); + const LLColor4U& color = new_color_array.at(i); *colorp = color.mV[VRED]; colorp++; *colorp = color.mV[VGREEN]; @@ -657,9 +667,9 @@ void LLViewerParcelOverlay::updatePropertyLines() void LLViewerParcelOverlay::addPropertyLine( - LLDynamicArray& vertex_array, - LLDynamicArray& color_array, - LLDynamicArray& coord_array, + std::vector& vertex_array, + std::vector& color_array, + std::vector& coord_array, const F32 start_x, const F32 start_y, const U32 edge, const LLColor4U& color) @@ -667,6 +677,10 @@ void LLViewerParcelOverlay::addPropertyLine( LLColor4U underwater( color ); underwater.mV[VALPHA] /= 2; + vertex_array.reserve(16); + color_array.reserve(16); + coord_array.reserve(16); + LLSurface& land = mRegion->getLand(); F32 dx; @@ -707,7 +721,7 @@ void LLViewerParcelOverlay::addPropertyLine( break; default: - llerrs << "Invalid edge in addPropertyLine" << llendl; + LL_ERRS() << "Invalid edge in addPropertyLine" << LL_ENDL; return; } @@ -721,11 +735,11 @@ void LLViewerParcelOverlay::addPropertyLine( // First part, only one vertex outside_z = land.resolveHeightRegion( outside_x, outside_y ); - if (outside_z > 20.f) color_array.put( color ); - else color_array.put( underwater ); + if (outside_z > 20.f) color_array.push_back(color); + else color_array.push_back(underwater); - vertex_array.put( LLVector3(outside_x, outside_y, outside_z) ); - coord_array.put( LLVector2(outside_x - start_x, 0.f) ); + vertex_array.push_back(LLVector3(outside_x, outside_y, outside_z)); + coord_array.push_back(LLVector2(outside_x - start_x, 0.f)); inside_x += dx * LINE_WIDTH; inside_y += dy * LINE_WIDTH; @@ -737,17 +751,17 @@ void LLViewerParcelOverlay::addPropertyLine( inside_z = land.resolveHeightRegion( inside_x, inside_y ); outside_z = land.resolveHeightRegion( outside_x, outside_y ); - if (inside_z > 20.f) color_array.put( color ); - else color_array.put( underwater ); + if (inside_z > 20.f) color_array.push_back(color); + else color_array.push_back(underwater); - if (outside_z > 20.f) color_array.put( color ); - else color_array.put( underwater ); + if (outside_z > 20.f) color_array.push_back(color); + else color_array.push_back(underwater); - vertex_array.put( LLVector3(inside_x, inside_y, inside_z) ); - vertex_array.put( LLVector3(outside_x, outside_y, outside_z) ); + vertex_array.push_back(LLVector3(inside_x, inside_y, inside_z)); + vertex_array.push_back(LLVector3(outside_x, outside_y, outside_z)); - coord_array.put( LLVector2(outside_x - start_x, 1.f) ); - coord_array.put( LLVector2(outside_x - start_x, 0.f) ); + coord_array.push_back(LLVector2(outside_x - start_x, 1.f)); + coord_array.push_back(LLVector2(outside_x - start_x, 0.f)); inside_x += dx * (dx - LINE_WIDTH); inside_y += dy * (dy - LINE_WIDTH); @@ -763,17 +777,17 @@ void LLViewerParcelOverlay::addPropertyLine( inside_z = land.resolveHeightRegion( inside_x, inside_y ); outside_z = land.resolveHeightRegion( outside_x, outside_y ); - if (inside_z > 20.f) color_array.put( color ); - else color_array.put( underwater ); + if (inside_z > 20.f) color_array.push_back(color); + else color_array.push_back(underwater); - if (outside_z > 20.f) color_array.put( color ); - else color_array.put( underwater ); + if (outside_z > 20.f) color_array.push_back(color); + else color_array.push_back(underwater); - vertex_array.put( LLVector3(inside_x, inside_y, inside_z) ); - vertex_array.put( LLVector3(outside_x, outside_y, outside_z) ); + vertex_array.push_back(LLVector3(inside_x, inside_y, inside_z)); + vertex_array.push_back(LLVector3(outside_x, outside_y, outside_z)); - coord_array.put( LLVector2(outside_x - start_x, 1.f) ); - coord_array.put( LLVector2(outside_x - start_x, 0.f) ); + coord_array.push_back(LLVector2(outside_x - start_x, 1.f)); + coord_array.push_back(LLVector2(outside_x - start_x, 0.f)); inside_x += dx; inside_y += dy; @@ -792,17 +806,17 @@ void LLViewerParcelOverlay::addPropertyLine( inside_z = land.resolveHeightRegion( inside_x, inside_y ); outside_z = land.resolveHeightRegion( outside_x, outside_y ); - if (inside_z > 20.f) color_array.put( color ); - else color_array.put( underwater ); + if (inside_z > 20.f) color_array.push_back(color); + else color_array.push_back(underwater); - if (outside_z > 20.f) color_array.put( color ); - else color_array.put( underwater ); + if (outside_z > 20.f) color_array.push_back(color); + else color_array.push_back(underwater); - vertex_array.put( LLVector3(inside_x, inside_y, inside_z) ); - vertex_array.put( LLVector3(outside_x, outside_y, outside_z) ); + vertex_array.push_back(LLVector3(inside_x, inside_y, inside_z)); + vertex_array.push_back(LLVector3(outside_x, outside_y, outside_z)); - coord_array.put( LLVector2(outside_x - start_x, 1.f) ); - coord_array.put( LLVector2(outside_x - start_x, 0.f) ); + coord_array.push_back(LLVector2(outside_x - start_x, 1.f)); + coord_array.push_back(LLVector2(outside_x - start_x, 0.f)); inside_x += dx * LINE_WIDTH; inside_y += dy * LINE_WIDTH; @@ -813,11 +827,11 @@ void LLViewerParcelOverlay::addPropertyLine( // Last edge is not drawn to the edge outside_z = land.resolveHeightRegion( outside_x, outside_y ); - if (outside_z > 20.f) color_array.put( color ); - else color_array.put( underwater ); + if (outside_z > 20.f) color_array.push_back(color); + else color_array.push_back(underwater); - vertex_array.put( LLVector3(outside_x, outside_y, outside_z) ); - coord_array.put( LLVector2(outside_x - start_x, 0.f) ); + vertex_array.push_back(LLVector3(outside_x, outside_y, outside_z)); + coord_array.push_back(LLVector2(outside_x - start_x, 0.f)); } @@ -850,6 +864,10 @@ void LLViewerParcelOverlay::idleUpdate(bool force_update) { updateOverlayTexture(); updatePropertyLines(); +// [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-06-20 (Catznip-3.3.0) + if (mUpdateSignal) + (*mUpdateSignal)(mRegion); +// [/SL:KB] mTimeSinceLastUpdate.reset(); } } @@ -921,6 +939,7 @@ S32 LLViewerParcelOverlay::renderPropertyLines () S32 drawn = 0; F32* vertexp; U8* colorp; + bool render_hidden = LLSelectMgr::sRenderHiddenSelections && gFloaterTools && gFloaterTools->getVisible(); const F32 PROPERTY_LINE_CLIP_DIST_SQUARED = 256.f * 256.f; @@ -962,7 +981,7 @@ S32 LLViewerParcelOverlay::renderPropertyLines () gGL.end(); - if (LLSelectMgr::sRenderHiddenSelections && gFloaterTools && gFloaterTools->getVisible()) + if (render_hidden) { LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_GREATER); @@ -997,3 +1016,12 @@ S32 LLViewerParcelOverlay::renderPropertyLines () return drawn; } + +// [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-06-20 (Catznip-3.3.0) +boost::signals2::connection LLViewerParcelOverlay::setUpdateCallback(const update_signal_t::slot_type & cb) +{ + if (!mUpdateSignal) + mUpdateSignal = new update_signal_t(); + return mUpdateSignal->connect(cb); +} +// [/SL:KB] diff --git a/indra/newview/llviewerparceloverlay.h b/indra/newview/llviewerparceloverlay.h index 794a485e66..9680cd88e3 100644 --- a/indra/newview/llviewerparceloverlay.h +++ b/indra/newview/llviewerparceloverlay.h @@ -2,31 +2,25 @@ * @file llviewerparceloverlay.h * @brief LLViewerParcelOverlay class header file * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -37,7 +31,6 @@ // One of these structures per region. #include "llbbox.h" -#include "lldarray.h" #include "llframetimer.h" #include "lluuid.h" #include "llviewertexture.h" @@ -73,6 +66,9 @@ class LLViewerParcelOverlay : public LLGLUpdate BOOL isBuildCameraAllowed(const LLVector3& pos) const; F32 getOwnedRatio() const; +// [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-06-20 (Catznip-3.3.0) + const U8* getOwnership() const { return mOwnership; } +// [/SL:KB] // Returns the number of vertices drawn S32 renderPropertyLines(); @@ -88,15 +84,20 @@ class LLViewerParcelOverlay : public LLGLUpdate void idleUpdate(bool update_now = false); void updateGL(); +// [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-06-20 (Catznip-3.3.0) + typedef boost::signals2::signal update_signal_t; + static boost::signals2::connection setUpdateCallback(const update_signal_t::slot_type & cb); +// [/SL:KB] + private: // This is in parcel rows and columns, not grid rows and columns // Stored in bottom three bits. U8 ownership(S32 row, S32 col) const { return 0x7 & mOwnership[row * mParcelGridsPerEdge + col]; } - void addPropertyLine(LLDynamicArray& vertex_array, - LLDynamicArray& color_array, - LLDynamicArray& coord_array, + void addPropertyLine(std::vector& vertex_array, + std::vector& color_array, + std::vector& coord_array, const F32 start_x, const F32 start_y, const U32 edge, const LLColor4U& color); @@ -109,6 +110,9 @@ class LLViewerParcelOverlay : public LLGLUpdate LLViewerRegion* mRegion; S32 mParcelGridsPerEdge; +// Aurora Sim + S32 mRegionSize; +// Aurora Sim LLPointer mTexture; LLPointer mImageRaw; @@ -126,6 +130,10 @@ class LLViewerParcelOverlay : public LLGLUpdate S32 mVertexCount; F32* mVertexArray; U8* mColorArray; + +// [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-06-20 (Catznip-3.3.0) + static update_signal_t* mUpdateSignal; +// [/SL:KB] }; #endif diff --git a/indra/newview/llviewerpartsim.cpp b/indra/newview/llviewerpartsim.cpp index 92abe4bf2d..d172cbc7e4 100644 --- a/indra/newview/llviewerpartsim.cpp +++ b/indra/newview/llviewerpartsim.cpp @@ -86,12 +86,31 @@ LLViewerPart::LLViewerPart() : mImagep(NULL) { mPartSourcep = NULL; - + mParent = NULL; + mChild = NULL; ++LLViewerPartSim::sParticleCount2 ; } LLViewerPart::~LLViewerPart() { + if (mPartSourcep.notNull() && mPartSourcep->mLastPart == this) + { + mPartSourcep->mLastPart = NULL; + } + + //patch up holes in the ribbon + if (mParent) + { + llassert(mParent->mChild == this); + mParent->mChild = mChild; + } + + if (mChild) + { + llassert (mChild->mParent == this); + mChild->mParent = mParent; + } + mPartSourcep = NULL; --LLViewerPartSim::sParticleCount2 ; @@ -131,7 +150,7 @@ LLViewerPartGroup::LLViewerPartGroup(const LLVector3 ¢er_agent, const F32 bo if (!mRegionp) { - //llwarns << "No region at position, using agent region!" << llendl; + //LL_WARNS() << "No region at position, using agent region!" << LL_ENDL; mRegionp = gAgent.getRegion(); } mCenterAgent = center_agent; @@ -147,7 +166,11 @@ LLViewerPartGroup::LLViewerPartGroup(const LLVector3 ¢er_agent, const F32 bo } mVOPartGroupp->setViewerPartGroup(this); mVOPartGroupp->setPositionAgent(getCenterAgent()); + + mBoxSide = box_side; + F32 scale = box_side * 0.5f; + mVOPartGroupp->setScale(LLVector3(scale,scale,scale)); //gPipeline.addObject(mVOPartGroupp); @@ -157,8 +180,8 @@ LLViewerPartGroup::LLViewerPartGroup(const LLVector3 ¢er_agent, const F32 bo if (group != NULL) { - LLVector3 center(group->mOctreeNode->getCenter().getF32ptr()); - LLVector3 size(group->mOctreeNode->getSize().getF32ptr()); + LLVector3 center(group->getOctreeNode()->getCenter().getF32ptr()); + LLVector3 size(group->getOctreeNode()->getSize().getF32ptr()); size += LLVector3(0.01f, 0.01f, 0.01f); mMinObjPos = center - size; mMaxObjPos = center + size; @@ -373,6 +396,9 @@ void LLViewerPartGroup::updateParticles(const F32 lastdt) part->mScale += frac*part->mEndScale; } + // Do glow interpolation + part->mGlow.mV[3] = (U8) ll_round(lerp(part->mStartGlow, part->mEndGlow, frac)*255.f); + // Set the last update time to now. part->mLastUpdateTime = cur_time; @@ -380,8 +406,7 @@ void LLViewerPartGroup::updateParticles(const F32 lastdt) // Kill dead particles (either flagged dead, or too old) if ((part->mLastUpdateTime > part->mMaxAge) || (LLViewerPart::LL_PART_DEAD_MASK == part->mFlags)) { - mParticles[i] = mParticles.back() ; - mParticles.pop_back() ; + vector_replace_with_last(mParticles, mParticles.begin() + i); delete part ; } else @@ -391,8 +416,7 @@ void LLViewerPartGroup::updateParticles(const F32 lastdt) { // Transfer particles between groups LLViewerPartSim::getInstance()->put(part) ; - mParticles[i] = mParticles.back() ; - mParticles.pop_back() ; + vector_replace_with_last(mParticles, mParticles.begin() + i); } else { @@ -457,12 +481,12 @@ void LLViewerPartSim::checkParticleCount(U32 size) { if(LLViewerPartSim::sParticleCount2 != LLViewerPartSim::sParticleCount) { - llerrs << "sParticleCount: " << LLViewerPartSim::sParticleCount << " ; sParticleCount2: " << LLViewerPartSim::sParticleCount2 << llendl ; + LL_ERRS() << "sParticleCount: " << LLViewerPartSim::sParticleCount << " ; sParticleCount2: " << LLViewerPartSim::sParticleCount2 << LL_ENDL ; } if(size > (U32)LLViewerPartSim::sParticleCount2) { - llerrs << "curren particle size: " << LLViewerPartSim::sParticleCount2 << " array size: " << size << llendl ; + LL_ERRS() << "curren particle size: " << LLViewerPartSim::sParticleCount2 << " array size: " << size << LL_ENDL ; } } @@ -491,11 +515,16 @@ void LLViewerPartSim::destroyClass() mViewerPartSources.clear(); } +//static BOOL LLViewerPartSim::shouldAddPart() { - if (sParticleCount > PART_THROTTLE_THRESHOLD*sMaxParticleCount) + if (sParticleCount >= MAX_PART_COUNT) { + return FALSE; + } + if (sParticleCount > PART_THROTTLE_THRESHOLD*sMaxParticleCount) + { F32 frac = (F32)sParticleCount/(F32)sMaxParticleCount; frac -= PART_THROTTLE_THRESHOLD; frac *= PART_THROTTLE_RESCALE; @@ -505,7 +534,10 @@ BOOL LLViewerPartSim::shouldAddPart() return FALSE; } } - if (sParticleCount >= MAX_PART_COUNT) + + // Check frame rate, and don't add more if the viewer is really slow + const F32 MIN_FRAME_RATE_FOR_NEW_PARTICLES = 4.f; + if (gFPSClamped < MIN_FRAME_RATE_FOR_NEW_PARTICLES) { return FALSE; } @@ -535,8 +567,8 @@ LLViewerPartGroup *LLViewerPartSim::put(LLViewerPart* part) if (part->mPosAgent.magVecSquared() > MAX_MAG || !part->mPosAgent.isFinite()) { #if 0 && !LL_RELEASE_FOR_DOWNLOAD - llwarns << "LLViewerPartSim::put Part out of range!" << llendl; - llwarns << part->mPosAgent << llendl; + LL_WARNS() << "LLViewerPartSim::put Part out of range!" << LL_ENDL; + LL_WARNS() << part->mPosAgent << LL_ENDL; #endif } else @@ -565,9 +597,9 @@ LLViewerPartGroup *LLViewerPartSim::put(LLViewerPart* part) !(part->mFlags & LLPartData::LL_PART_FOLLOW_VELOCITY_MASK)); if (!groupp->addPart(part)) { - llwarns << "LLViewerPartSim::put - Particle didn't go into its box!" << llendl; - llinfos << groupp->getCenterAgent() << llendl; - llinfos << part->mPosAgent << llendl; + LL_WARNS() << "LLViewerPartSim::put - Particle didn't go into its box!" << LL_ENDL; + LL_INFOS() << groupp->getCenterAgent() << LL_ENDL; + LL_INFOS() << part->mPosAgent << LL_ENDL; mViewerPartGroups.pop_back() ; delete groupp; groupp = NULL ; @@ -615,12 +647,14 @@ void LLViewerPartSim::shift(const LLVector3 &offset) } } -static LLFastTimer::DeclareTimer FTM_SIMULATE_PARTICLES("Simulate Particles"); +static LLTrace::BlockTimerStatHandle FTM_SIMULATE_PARTICLES("Simulate Particles"); void LLViewerPartSim::updateSimulation() { static LLFrameTimer update_timer; + //reset VBO cursor + const F32 dt = llmin(update_timer.getElapsedTimeAndResetF32(), 0.1f); if (!(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_PARTICLES))) @@ -628,7 +662,7 @@ void LLViewerPartSim::updateSimulation() return; } - LLFastTimer ftm(FTM_SIMULATE_PARTICLES); + LL_RECORD_BLOCK_TIME(FTM_SIMULATE_PARTICLES); // Start at a random particle system so the same // particle system doesn't always get first pick at the @@ -639,11 +673,9 @@ void LLViewerPartSim::updateSimulation() S32 count = (S32) mViewerPartSources.size(); S32 start = (S32)ll_frand((F32)count); S32 dir = 1; - S32 deldir = 0; if (ll_frand() > 0.5f) { dir = -1; - deldir = -1; } S32 num_updates = 0; @@ -689,11 +721,9 @@ void LLViewerPartSim::updateSimulation() if (mViewerPartSources[i]->isDead()) { - mViewerPartSources[i] = mViewerPartSources.back(); - mViewerPartSources.pop_back(); - //mViewerPartSources.erase(mViewerPartSources.begin() + i); + vector_replace_with_last(mViewerPartSources, mViewerPartSources.begin() + i); + //mViewerPartSources.erase(it); count--; - i+=deldir; } else { @@ -728,9 +758,8 @@ void LLViewerPartSim::updateSimulation() if (!mViewerPartGroups[i]->getCount()) { delete mViewerPartGroups[i]; - mViewerPartGroups[i] = mViewerPartGroups.back(); - mViewerPartGroups.pop_back(); - //mViewerPartGroups.erase(mViewerPartGroups.begin() + i); + vector_replace_with_last(mViewerPartGroups, mViewerPartGroups.begin() + i); + //mViewerPartGroups.erase(it); i--; count--; } @@ -760,7 +789,7 @@ void LLViewerPartSim::updateSimulation() updatePartBurstRate() ; - //llinfos << "Particles: " << sParticleCount << " Adaptive Rate: " << sParticleAdaptiveRate << llendl; + //LL_INFOS() << "Particles: " << sParticleCount << " Adaptive Rate: " << sParticleAdaptiveRate << LL_ENDL; } void LLViewerPartSim::updatePartBurstRate() @@ -798,7 +827,7 @@ void LLViewerPartSim::addPartSource(LLPointer sourcep) { if (!sourcep) { - llwarns << "Null part source!" << llendl; + LL_WARNS() << "Null part source!" << LL_ENDL; return; } sourcep->setStart() ; @@ -813,15 +842,15 @@ void LLViewerPartSim::removeLastCreatedSource() void LLViewerPartSim::cleanupRegion(LLViewerRegion *regionp) { group_list_t& vec = mViewerPartGroups; - for (group_list_t::size_type i = 0;igetRegion() == regionp) + if ((*it)->getRegion() == regionp) { - delete vec[i]; - vec[i--] = vec.back(); - vec.pop_back(); + delete *it; + it = vector_replace_with_last(vec,it); //i = mViewerPartGroups.erase(iter); } + else ++it; } } diff --git a/indra/newview/llviewerpartsim.h b/indra/newview/llviewerpartsim.h index 7e625f2c0f..08c736a0a8 100644 --- a/indra/newview/llviewerpartsim.h +++ b/indra/newview/llviewerpartsim.h @@ -33,7 +33,6 @@ #ifndef LL_LLVIEWERPARTSIM_H #define LL_LLVIEWERPARTSIM_H -#include "lldarrayptr.h" #include "llframetimer.h" #include "llpointer.h" #include "llpartdata.h" @@ -71,15 +70,22 @@ class LLViewerPart : public LLPartData LLVPCallback mVPCallback; // Callback function for more complicated behaviors LLPointer mPartSourcep; // Particle source used for this object - + + LLViewerPart* mParent; // particle to connect to if this is part of a particle ribbon + LLViewerPart* mChild; // child particle for clean reference destruction // Current particle state (possibly used for rendering) LLPointer mImagep; LLVector3 mPosAgent; LLVector3 mVelocity; LLVector3 mAccel; + LLVector3 mAxis; LLColor4 mColor; LLVector2 mScale; + F32 mStartGlow; + F32 mEndGlow; + LLColor4U mGlow; + static U32 sNextPartID; }; @@ -104,6 +110,9 @@ class LLViewerPartGroup void shift(const LLVector3 &offset); + F32 getBoxRadius() { return mBoxRadius; } + F32 getBoxSide() { return mBoxSide; } + typedef std::vector part_list_t; part_list_t mParticles; @@ -124,6 +133,7 @@ class LLViewerPartGroup protected: LLVector3 mCenterAgent; F32 mBoxRadius; + F32 mBoxSide; LLVector3 mMinObjPos; LLVector3 mMaxObjPos; @@ -148,7 +158,7 @@ class LLViewerPartSim : public LLSingleton void cleanupRegion(LLViewerRegion *regionp); - BOOL shouldAddPart(); // Just decides whether this particle should be added or not (for particle count capping) + static BOOL shouldAddPart(); // Just decides whether this particle should be added or not (for particle count capping) F32 maxRate() // Return maximum particle generation rate { if (sParticleCount >= MAX_PART_COUNT) diff --git a/indra/newview/llviewerpartsource.cpp b/indra/newview/llviewerpartsource.cpp index d712138fdc..34e971dbae 100644 --- a/indra/newview/llviewerpartsource.cpp +++ b/indra/newview/llviewerpartsource.cpp @@ -58,6 +58,8 @@ LLViewerPartSource::LLViewerPartSource(const U32 type) : static U32 id_seed = 0; mID = ++id_seed; + mLastPart = NULL; + mDelay = 0 ; } @@ -73,7 +75,7 @@ void LLViewerPartSource::updatePart(LLViewerPart &part, const F32 dt) void LLViewerPartSource::update(const F32 dt) { - llerrs << "Creating default part source!" << llendl; + LL_ERRS() << "Creating default part source!" << LL_ENDL; } LLUUID LLViewerPartSource::getImageUUID() const @@ -277,6 +279,9 @@ void LLViewerPartSourceScript::update(const F32 dt) continue; } + if (mPartSysData.mPartData.mFlags & LLPartData::LL_PART_RIBBON_MASK && mLastPart && (mLastPart->mPosAgent-mPosAgent).magVec() <= .005f) + continue; //Skip if parent isn't far enough away. + LLViewerPart* part = new LLViewerPart(); part->init(this, mImagep, NULL); @@ -285,6 +290,22 @@ void LLViewerPartSourceScript::update(const F32 dt) { part->mFlags |= LLPartData::LL_PART_HUD; } + + if (part->mFlags & LLPartData::LL_PART_RIBBON_MASK && mLastPart) + { //set previous particle's parent to this particle to chain ribbon together + mLastPart->mParent = part; + part->mChild = mLastPart; + part->mAxis = LLVector3(0,0,1); + + if (mSourceObjectp.notNull()) + { + LLQuaternion rot = mSourceObjectp->getRenderRotation(); + part->mAxis *= rot; + } + } + + mLastPart = part; + part->mMaxAge = mPartSysData.mPartData.mMaxAge; part->mStartColor = mPartSysData.mPartData.mStartColor; part->mEndColor = mPartSysData.mPartData.mEndColor; @@ -296,6 +317,13 @@ void LLViewerPartSourceScript::update(const F32 dt) part->mAccel = mPartSysData.mPartAccel; + part->mBlendFuncDest = mPartSysData.mPartData.mBlendFuncDest; + part->mBlendFuncSource = mPartSysData.mPartData.mBlendFuncSource; + + part->mStartGlow = mPartSysData.mPartData.mStartGlow; + part->mEndGlow = mPartSysData.mPartData.mEndGlow; + part->mGlow = LLColor4U(0, 0, 0, (U8) ll_round(part->mStartGlow*255.f)); + if (mPartSysData.mPattern & LLPartSysData::LL_PART_SRC_PATTERN_DROP) { part->mPosAgent = mPosAgent; @@ -377,7 +405,7 @@ void LLViewerPartSourceScript::update(const F32 dt) { part->mPosAgent = mPosAgent; part->mVelocity.setVec(0.f, 0.f, 0.f); - //llwarns << "Unknown source pattern " << (S32)mPartSysData.mPattern << llendl; + //LL_WARNS() << "Unknown source pattern " << (S32)mPartSysData.mPattern << LL_ENDL; } if (part->mFlags & LLPartData::LL_PART_FOLLOW_SRC_MASK || // SVC-193, VWR-717 @@ -436,28 +464,51 @@ LLPointer LLViewerPartSourceScript::unpackPSS(LLViewer } -LLPointer LLViewerPartSourceScript::unpackPSS(LLViewerObject *source_objp, LLPointer pssp, LLDataPacker &dp) +LLPointer LLViewerPartSourceScript::unpackPSS(LLViewerObject *source_objp, LLPointer pssp, LLDataPacker &dp, bool legacy) { if (!pssp) { LLPointer new_pssp = new LLViewerPartSourceScript(source_objp); - if (!new_pssp->mPartSysData.unpack(dp)) + if (legacy) { - return NULL; + if (!new_pssp->mPartSysData.unpackLegacy(dp)) + { + return NULL; + } } + else + { + if (!new_pssp->mPartSysData.unpack(dp)) + { + return NULL; + } + } + if (new_pssp->mPartSysData.mTargetUUID.notNull()) { LLViewerObject *target_objp = gObjectList.findObject(new_pssp->mPartSysData.mTargetUUID); new_pssp->setTargetObject(target_objp); } + return new_pssp; } else { - if (!pssp->mPartSysData.unpack(dp)) + if (legacy) { - return NULL; + if (!pssp->mPartSysData.unpackLegacy(dp)) + { + return NULL; + } } + else + { + if (!pssp->mPartSysData.unpack(dp)) + { + return NULL; + } + } + if (pssp->mPartSysData.mTargetUUID.notNull()) { LLViewerObject *target_objp = gObjectList.findObject(pssp->mPartSysData.mTargetUUID); @@ -575,6 +626,11 @@ void LLViewerPartSourceSpiral::update(const F32 dt) part->mScale.mV[0] = 0.25f; part->mScale.mV[1] = 0.25f; part->mParameter = ll_frand(F_TWO_PI); + part->mBlendFuncDest = LLRender::BF_ONE_MINUS_SOURCE_ALPHA; + part->mBlendFuncSource = LLRender::BF_SOURCE_ALPHA; + part->mStartGlow = 0.f; + part->mEndGlow = 0.f; + part->mGlow = LLColor4U(0, 0, 0, 0); LLViewerPartSim::getInstance()->addPart(part); } @@ -727,6 +783,12 @@ void LLViewerPartSourceBeam::update(const F32 dt) part->mPosAgent = mPosAgent; part->mVelocity = mTargetPosAgent - mPosAgent; + part->mBlendFuncDest = LLRender::BF_ONE_MINUS_SOURCE_ALPHA; + part->mBlendFuncSource = LLRender::BF_SOURCE_ALPHA; + part->mStartGlow = 0.f; + part->mEndGlow = 0.f; + part->mGlow = LLColor4U(0, 0, 0, 0); + LLViewerPartSim::getInstance()->addPart(part); } } @@ -831,6 +893,12 @@ void LLViewerPartSourceChat::update(const F32 dt) part->mScale.mV[0] = 0.25f; part->mScale.mV[1] = 0.25f; part->mParameter = ll_frand(F_TWO_PI); + part->mBlendFuncDest = LLRender::BF_ONE_MINUS_SOURCE_ALPHA; + part->mBlendFuncSource = LLRender::BF_SOURCE_ALPHA; + part->mStartGlow = 0.f; + part->mEndGlow = 0.f; + part->mGlow = LLColor4U(0, 0, 0, 0); + LLViewerPartSim::getInstance()->addPart(part); } diff --git a/indra/newview/llviewerpartsource.h b/indra/newview/llviewerpartsource.h index 540e30eb19..d05d50d366 100644 --- a/indra/newview/llviewerpartsource.h +++ b/indra/newview/llviewerpartsource.h @@ -82,6 +82,7 @@ class LLViewerPartSource : public LLRefCount LLVector3 mLastUpdatePosAgent; LLPointer mSourceObjectp; U32 mID; + LLViewerPart* mLastPart; //last particle emitted (for making particle ribbons) protected: U32 mType; @@ -120,7 +121,7 @@ class LLViewerPartSourceScript : public LLViewerPartSource // Returns a new particle source to attach to an object... static LLPointer unpackPSS(LLViewerObject *source_objp, LLPointer pssp, const S32 block_num); - static LLPointer unpackPSS(LLViewerObject *source_objp, LLPointer pssp, LLDataPacker &dp); + static LLPointer unpackPSS(LLViewerObject *source_objp, LLPointer pssp, LLDataPacker &dp, bool legacy); static LLPointer createPSS(LLViewerObject *source_objp, const LLPartSysData& particle_parameters); LLViewerTexture *getImage() const { return mImagep; } diff --git a/indra/newview/llviewerprecompiledheaders.h b/indra/newview/llviewerprecompiledheaders.h index f98c6f10f7..44d52371f4 100644 --- a/indra/newview/llviewerprecompiledheaders.h +++ b/indra/newview/llviewerprecompiledheaders.h @@ -41,21 +41,7 @@ #include "linden_common.h" -// We may want to take the windows.h include out, but it used to be in -// linden_common.h, and hence in all the libraries. This is better. JC -#if LL_WINDOWS - // Limit Windows API to small and manageable set. - // If you get undefined symbols, find the appropriate - // Windows header file and include that in your .cpp file. - #define WIN32_LEAN_AND_MEAN - #include - #include -#endif - -// Work around stupid Microsoft STL warning -#ifdef LL_WINDOWS -#pragma warning (disable : 4702) // warning C4702: unreachable code -#endif +#include "llwin32headerslean.h" #include #include @@ -69,34 +55,24 @@ // Library headers from llcommon project: #include "bitpack.h" -#include "lldeleteutils.h" #include "imageids.h" #include "indra_constants.h" #include "llinitparam.h" - -//#include "linden_common.h" -//#include "llpreprocessor.h" #include "llapp.h" #include "llapr.h" #include "llcriticaldamp.h" -#include "lldarray.h" -#include "lldarrayptr.h" #include "lldefs.h" #include "lldepthstack.h" -#include "lldqueueptr.h" #include "llendianswizzle.h" #include "llerror.h" #include "llfasttimer.h" #include "llframetimer.h" -#include "llhash.h" #include "lllocalidhashmap.h" #include "llmap.h" #include "llmemory.h" #include "llnametable.h" #include "llpriqueuemap.h" #include "llprocessor.h" -//#include "llsecondlifeurls.h" -#include "llstack.h" #include "llstat.h" #include "llstl.h" #include "llstring.h" @@ -104,11 +80,8 @@ #include "llsys.h" #include "llthread.h" #include "lltimer.h" -//#include "processor.h" #include "stdenums.h" #include "stdtypes.h" -//#include "string_table.h" -//#include "timer.h" #include "timing.h" #include "u64.h" @@ -150,7 +123,6 @@ #include "llnamevalue.h" #include "llpacketack.h" #include "llpacketbuffer.h" -//#include "llpacketring.h" #include "llpartdata.h" #include "llregionhandle.h" #include "lltaskname.h" @@ -173,7 +145,6 @@ #include "message.h" #include "message_prehash.h" #include "net.h" -//#include "network.h" #include "patch_code.h" #include "patch_dct.h" #include "sound_ids.h" @@ -182,12 +153,8 @@ #include "imageids.h" #include "legacy_object_types.h" #include "llmaterialtable.h" -//#include "llprimitive.h" #include "lltextureanim.h" -//#include "lltextureentry.h" #include "lltreeparams.h" -//#include "llvolume.h" -#include "llvolumemgr.h" #include "material_codes.h" // Library includes from llxml @@ -196,9 +163,6 @@ // Library includes from llvfs #include "llassettype.h" #include "lldir.h" -//#include "lldir_linux.h" -//#include "lldir_mac.h" -//#include "lldir_win32.h" #include "llvfile.h" #include "llvfs.h" diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index 9571837c75..d8291f9d10 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -36,6 +36,7 @@ // linden libraries #include "indra_constants.h" +#include "llaisapi.h" #include "llavatarnamecache.h" // name lookup cap url //#include "llfloaterreg.h" #include "llmath.h" @@ -48,16 +49,20 @@ #include "v3math.h" #include "v4math.h" +#include "lfsimfeaturehandler.h" #include "llagent.h" #include "llagentcamera.h" + +#include "llavatarrenderinfoaccountant.h" #include "llcallingcard.h" #include "llcaphttpsender.h" #include "llcapabilitylistener.h" #include "llcommandhandler.h" #include "lldir.h" #include "lleventpoll.h" +#include "llfloateravatarlist.h" #include "llfloatergodtools.h" -#include "llfloaterreporter.h" +#include "llfloaterperms.h" #include "llfloaterregioninfo.h" #include "llhttpnode.h" #include "llregioninfomodel.h" @@ -66,6 +71,7 @@ #include "lltrans.h" #include "llurldispatcher.h" #include "llviewerobjectlist.h" +#include "llviewerparcelmgr.h" #include "llviewerparceloverlay.h" #include "llviewerstatsrecorder.h" #include "llvlmanager.h" @@ -78,14 +84,15 @@ #include "llviewercontrol.h" #include "llsdserialize.h" +#include "llviewerparcelmgr.h" //Aurora Sim #ifdef LL_WINDOWS #pragma warning(disable:4355) #endif class AIHTTPTimeoutPolicy; extern AIHTTPTimeoutPolicy baseCapabilitiesComplete_timeout; -extern AIHTTPTimeoutPolicy gamingDataReceived_timeout; -extern AIHTTPTimeoutPolicy simulatorFeaturesReceived_timeout; +extern AIHTTPTimeoutPolicy baseCapabilitiesCompleteTracker_timeout; +extern AIHTTPTimeoutPolicy baseFeaturesReceived_timeout; const F32 WATER_TEXTURE_SCALE = 8.f; // Number of times to repeat the water texture across a region const S16 MAX_MAP_DIST = 10; @@ -98,6 +105,21 @@ const S32 MAX_CAP_REQUEST_ATTEMPTS = 30; typedef std::map CapabilityMap; +static void log_capabilities(const CapabilityMap &capmap); + + +namespace +{ + +void newRegionEntry(LLViewerRegion& region) +{ + LL_INFOS("LLViewerRegion") << "Entering region [" << region.getName() << "]" << LL_ENDL; + gDebugInfo["CurrentRegion"] = region.getName(); + LLAppViewer::instance()->writeDebugInfo(); +} + +} // anonymous namespace + class LLViewerRegionImpl { public: LLViewerRegionImpl(LLViewerRegion * region, LLHost const & host) @@ -108,6 +130,7 @@ class LLViewerRegionImpl { mSeedCapMaxAttemptsBeforeLogin(MAX_SEED_CAP_ATTEMPTS_BEFORE_LOGIN), mSeedCapAttempts(0), mHttpResponderID(0), + mLandp(NULL), // I'd prefer to set the LLCapabilityListener name to match the region // name -- it's disappointing that's not available at construction time. // We could instead store an LLCapabilityListener*, making @@ -153,6 +176,7 @@ class LLViewerRegionImpl { LLUUID mCacheID; CapabilityMap mCapabilities; + CapabilityMap mSecondCapabilitiesTracker; LLEventPoll* mEventPoll; @@ -168,7 +192,7 @@ class LLViewerRegionImpl { LLCapabilityListener mCapabilityListener; //spatial partitions for objects in this region - std::vector mObjectPartition; + std::vector mObjectPartition; }; // support for secondlife:///app/region/{REGION} SLapps @@ -214,15 +238,25 @@ class BaseCapabilitiesComplete : public LLHTTPClient::ResponderWithResult { LOG_CLASS(BaseCapabilitiesComplete); public: - BaseCapabilitiesComplete(U64 region_handle, S32 id) + BaseCapabilitiesComplete(U64 region_handle, S32 id) : mRegionHandle(region_handle), mID(id) - { } + { } virtual ~BaseCapabilitiesComplete() { } - /*virtual*/ void error(U32 statusNum, const std::string& reason) + static boost::intrusive_ptr build( U64 region_handle, S32 id ) + { + return boost::intrusive_ptr( + new BaseCapabilitiesComplete(region_handle, id) ); + } + + /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return baseCapabilitiesComplete_timeout; } + /*virtual*/ char const* getName(void) const { return "BaseCapabilitiesComplete"; } + +private: + void httpFailure(void) { - LL_WARNS2("AppInit", "Capabilities") << statusNum << ": " << reason << LL_ENDL; + LL_WARNS("AppInit", "Capabilities") << dumpResponse() << LL_ENDL; LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); if (regionp) { @@ -230,26 +264,34 @@ class BaseCapabilitiesComplete : public LLHTTPClient::ResponderWithResult } } - /*virtual*/ void result(const LLSD& content) + void httpSuccess(void) { LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); if(!regionp) //region was removed { - LL_WARNS2("AppInit", "Capabilities") << "Received results for region that no longer exists!" << LL_ENDL; + LL_WARNS("AppInit", "Capabilities") << "Received results for region that no longer exists!" << LL_ENDL; return ; } if( mID != regionp->getHttpResponderID() ) // region is no longer referring to this responder { - LL_WARNS2("AppInit", "Capabilities") << "Received results for a stale http responder!" << LL_ENDL; + LL_WARNS("AppInit", "Capabilities") << "Received results for a stale http responder!" << LL_ENDL; + regionp->failedSeedCapability(); return ; } + const LLSD& content = getContent(); + if (!content.isMap()) + { + failureResult(400, "Malformed response contents", content); + return; + } LLSD::map_const_iterator iter; for(iter = content.beginMap(); iter != content.endMap(); ++iter) { regionp->setCapability(iter->first, iter->second); - LL_DEBUGS2("AppInit", "Capabilities") << "got capability for " - << iter->first << LL_ENDL; + + LL_DEBUGS("AppInit", "Capabilities") + << "Capability '" << iter->first << "' is '" << iter->second << "'" << LL_ENDL; /* HACK we're waiting for the ServerReleaseNotes */ if (iter->first == "ServerReleaseNotes" && regionp->getReleaseNotesRequested()) @@ -266,18 +308,101 @@ class BaseCapabilitiesComplete : public LLHTTPClient::ResponderWithResult } } - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return baseCapabilitiesComplete_timeout; } - /*virtual*/ char const* getName(void) const { return "BaseCapabilitiesComplete"; } +private: + U64 mRegionHandle; + S32 mID; +}; - static boost::intrusive_ptr build( U64 region_handle, S32 id ) +class BaseCapabilitiesCompleteTracker : public LLHTTPClient::ResponderWithResult +{ + LOG_CLASS(BaseCapabilitiesCompleteTracker); +public: + BaseCapabilitiesCompleteTracker( U64 region_handle) + : mRegionHandle(region_handle) + { } + + virtual ~BaseCapabilitiesCompleteTracker() + { } + + static boost::intrusive_ptr build( U64 region_handle ) { - return boost::intrusive_ptr( - new BaseCapabilitiesComplete(region_handle, id) ); + return boost::intrusive_ptr( + new BaseCapabilitiesCompleteTracker(region_handle)); } + /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return baseCapabilitiesCompleteTracker_timeout; } + /*virtual*/ char const* getName(void) const { return "BaseCapabilitiesCompleteTracker"; } + +private: + /* virtual */ void httpFailure() + { + LL_WARNS() << dumpResponse() << LL_ENDL; + } + + /* virtual */ void httpSuccess() + { + LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); + if( !regionp ) + { + LL_WARNS("AppInit", "Capabilities") << "Received results for region that no longer exists!" << LL_ENDL; + return ; + } + + const LLSD& content = getContent(); + if (!content.isMap()) + { + failureResult(400, "Malformed response contents", content); + return; + } + LLSD::map_const_iterator iter; + for(iter = content.beginMap(); iter != content.endMap(); ++iter) + { + regionp->setCapabilityDebug(iter->first, iter->second); + //LL_INFOS()<<"BaseCapabilitiesCompleteTracker New Caps "<first<<" "<< iter->second<getRegionImpl()->mCapabilities.size() != regionp->getRegionImpl()->mSecondCapabilitiesTracker.size() ) + { + LL_WARNS("AppInit", "Capabilities") + << "Sim sent duplicate base caps that differ in size from what we initially received - most likely content. " + << "mCapabilities == " << regionp->getRegionImpl()->mCapabilities.size() + << " mSecondCapabilitiesTracker == " << regionp->getRegionImpl()->mSecondCapabilitiesTracker.size() + << LL_ENDL; +//#ifdef DEBUG_CAPS_GRANTS + LL_WARNS("AppInit", "Capabilities") + << "Initial Base capabilities: " << LL_ENDL; + + log_capabilities(regionp->getRegionImpl()->mCapabilities); + + LL_WARNS("AppInit", "Capabilities") + << "Latest base capabilities: " << LL_ENDL; + + log_capabilities(regionp->getRegionImpl()->mSecondCapabilitiesTracker); + +//#endif + + if (regionp->getRegionImpl()->mSecondCapabilitiesTracker.size() > regionp->getRegionImpl()->mCapabilities.size() ) + { + // *HACK Since we were granted more base capabilities in this grant request than the initial, replace + // the old with the new. This shouldn't happen i.e. we should always get the same capabilities from a + // sim. The simulator fix from SH-3895 should prevent it from happening, at least in the case of the + // inventory api capability grants. + + // Need to clear a std::map before copying into it because old keys take precedence. + regionp->getRegionImplNC()->mCapabilities.clear(); + regionp->getRegionImplNC()->mCapabilities = regionp->getRegionImpl()->mSecondCapabilitiesTracker; + } + } + else + { + LL_DEBUGS("CrossingCaps") << "Sim sent multiple base cap grants with matching sizes." << LL_ENDL; + } + regionp->getRegionImplNC()->mSecondCapabilitiesTracker.clear(); + } + + private: U64 mRegionHandle; - S32 mID; }; @@ -295,6 +420,8 @@ LLViewerRegion::LLViewerRegion(const U64 &handle, mRegionFlags( REGION_FLAGS_DEFAULT ), mRegionProtocols( 0 ), mSimAccess( SIM_ACCESS_MIN ), + mLastSimAccess( 0 ), + mSimAccessString( "unknown" ), mBillableFactor(1.0), mMaxTasks(DEFAULT_MAX_REGION_WIDE_PRIM_COUNT), mCentralBakeVersion(0), @@ -303,15 +430,21 @@ LLViewerRegion::LLViewerRegion(const U64 &handle, mColoName("unknown"), mProductSKU("unknown"), mProductName("unknown"), - mHttpUrl(""), + mViewerAssetUrl(""), mCacheLoaded(FALSE), mCacheDirty(FALSE), mReleaseNotesRequested(FALSE), mCapabilitiesReceived(false), - mFeaturesReceived(false), - mGamingFlags(0) + mSimulatorFeaturesReceived(false), + mGamingFlags(0), +// Aurora Sim + mWidth(region_width_meters) { - mWidth = region_width_meters; + // Moved this up... -> mWidth = region_width_meters; +// + + mRenderMatrix.setIdentity(); + mImpl->mOriginGlobal = from_region_handle(handle); updateRenderMatrix(); @@ -321,7 +454,10 @@ LLViewerRegion::LLViewerRegion(const U64 &handle, mImpl->mCompositionp = new LLVLComposition(mImpl->mLandp, grids_per_region_edge, - region_width_meters / grids_per_region_edge); +// Aurora Sim + //region_width_meters / grids_per_region_edge); + mWidth / grids_per_region_edge); +// Aurora Sim mImpl->mCompositionp->setSurface(mImpl->mLandp); // Create the surfaces @@ -331,45 +467,67 @@ LLViewerRegion::LLViewerRegion(const U64 &handle, mImpl->mOriginGlobal, mWidth); - mParcelOverlay = new LLViewerParcelOverlay(this, region_width_meters); +// Aurora Sim + //mParcelOverlay = new LLViewerParcelOverlay(this, region_width_meters); + mParcelOverlay = new LLViewerParcelOverlay(this, mWidth); + LLViewerParcelMgr::getInstance()->init(mWidth); +// Aurora Sim setOriginGlobal(from_region_handle(handle)); calculateCenterGlobal(); // Create the object lists initStats(); + initPartitions(); + // If the newly entered region is using server bakes, and our + // current appearance is non-baked, request appearance update from + // server. + setCapabilitiesReceivedCallback(boost::bind(&LLAgent::handleServerBakeRegionTransition, &gAgent, _1)); // Singu TODO: LLAvatarRenderInfoAccountant +} +void LLViewerRegion::initPartitions() +{ //create object partitions //MUST MATCH declaration of eObjectPartitions - mImpl->mObjectPartition.push_back(new LLHUDPartition()); //PARTITION_HUD - mImpl->mObjectPartition.push_back(new LLTerrainPartition()); //PARTITION_TERRAIN - mImpl->mObjectPartition.push_back(new LLVoidWaterPartition()); //PARTITION_VOIDWATER - mImpl->mObjectPartition.push_back(new LLWaterPartition()); //PARTITION_WATER - mImpl->mObjectPartition.push_back(new LLTreePartition()); //PARTITION_TREE - mImpl->mObjectPartition.push_back(new LLParticlePartition()); //PARTITION_PARTICLE + mImpl->mObjectPartition.push_back(new LLHUDPartition(this)); //PARTITION_HUD + mImpl->mObjectPartition.push_back(new LLTerrainPartition(this)); //PARTITION_TERRAIN + mImpl->mObjectPartition.push_back(new LLVoidWaterPartition(this)); //PARTITION_VOIDWATER + mImpl->mObjectPartition.push_back(new LLWaterPartition(this)); //PARTITION_WATER + mImpl->mObjectPartition.push_back(new LLTreePartition(this)); //PARTITION_TREE + mImpl->mObjectPartition.push_back(new LLParticlePartition(this)); //PARTITION_PARTICLE #if ENABLE_CLASSIC_CLOUDS - mImpl->mObjectPartition.push_back(new LLCloudPartition()); //PARTITION_CLOUD + mImpl->mObjectPartition.push_back(new LLCloudPartition(this)); //PARTITION_CLOUD #endif - mImpl->mObjectPartition.push_back(new LLGrassPartition()); //PARTITION_GRASS - mImpl->mObjectPartition.push_back(new LLVolumePartition()); //PARTITION_VOLUME - mImpl->mObjectPartition.push_back(new LLBridgePartition()); //PARTITION_BRIDGE - mImpl->mObjectPartition.push_back(new LLHUDParticlePartition());//PARTITION_HUD_PARTICLE + mImpl->mObjectPartition.push_back(new LLGrassPartition(this)); //PARTITION_GRASS + mImpl->mObjectPartition.push_back(new LLVolumePartition(this)); //PARTITION_VOLUME + mImpl->mObjectPartition.push_back(new LLBridgePartition(this)); //PARTITION_BRIDGE + mImpl->mObjectPartition.push_back(new LLAttachmentPartition(this)); //PARTITION_ATTACHMENT + mImpl->mObjectPartition.push_back(new LLHUDParticlePartition(this));//PARTITION_HUD_PARTICLE mImpl->mObjectPartition.push_back(NULL); //PARTITION_NONE + + mRenderInfoRequestTimer.resetWithExpiry(0.f); // Set timer to be expired + setCapabilitiesReceivedCallback(boost::bind(&LLAvatarRenderInfoAccountant::expireRenderInfoReportTimer, _1)); } +void LLViewerRegion::reInitPartitions() +{ + std::for_each(mImpl->mObjectPartition.begin(), mImpl->mObjectPartition.end(), DeletePointer()); + mImpl->mObjectPartition.clear(); + initPartitions(); +} void LLViewerRegion::initStats() { mImpl->mLastNetUpdate.reset(); mPacketsIn = 0; - mBitsIn = 0; - mLastBitsIn = 0; + mBitsIn = (U32Bits)0; + mLastBitsIn = (U32Bits)0; mLastPacketsIn = 0; mPacketsOut = 0; mLastPacketsOut = 0; mPacketsLost = 0; mLastPacketsLost = 0; - mPingDelay = 0; + mPingDelay = (U32Seconds)0; mAlive = false; // can become false if circuit disconnects } @@ -392,12 +550,17 @@ LLViewerRegion::~LLViewerRegion() delete mImpl->mEventPoll; LLHTTPSender::clearSender(mImpl->mHost); - saveObjectCache(); - std::for_each(mImpl->mObjectPartition.begin(), mImpl->mObjectPartition.end(), DeletePointer()); + saveObjectCache(); + delete mImpl; mImpl = NULL; + +// [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-07-26 (Catznip-3.3) + for (tex_matrix_t::iterator i = mWorldMapTiles.begin(), iend = mWorldMapTiles.end(); i != iend; ++i) + (*i)->setBoostLevel(LLViewerTexture::BOOST_NONE); +// [/SL:KB] } LLEventPump& LLViewerRegion::getCapAPI() const @@ -513,7 +676,7 @@ void LLViewerRegion::setOriginGlobal(const LLVector3d &origin_global) void LLViewerRegion::updateRenderMatrix() { - mRenderMatrix.setTranslation(getOriginAgent()); + mRenderMatrix.setTranslate_affine(getOriginAgent()); } void LLViewerRegion::setTimeDilation(F32 time_dilation) @@ -577,9 +740,15 @@ BOOL LLViewerRegion::canManageEstate() const || gAgent.getID() == getOwner(); } -const std::string LLViewerRegion::getSimAccessString() const +std::string const& LLViewerRegion::getSimAccessString() { - return accessToString(mSimAccess); + // Singu: added a cache because this is called every frame. + if (mLastSimAccess != mSimAccess) + { + mSimAccessString = accessToString(mSimAccess); + mLastSimAccess = mSimAccess; + } + return mSimAccessString; } std::string LLViewerRegion::getLocalizedSimProductName() const @@ -744,11 +913,10 @@ void LLViewerRegion::processRegionInfo(LLMessageSystem* msg, void**) { // send it to 'observers' // *TODO: switch the floaters to using LLRegionInfoModel - llinfos << "Processing region info" << llendl; + LL_INFOS() << "Processing region info" << LL_ENDL; LLRegionInfoModel::instance().update(msg); LLFloaterGodTools::processRegionInfo(msg); LLFloaterRegionInfo::processRegionInfo(msg); - LLFloaterReporter::processRegionInfo(msg); } void LLViewerRegion::setCacheID(const LLUUID& id) @@ -778,6 +946,10 @@ void LLViewerRegion::dirtyHeights() } } +void LLViewerRegion::clearCachedVisibleObjects() +{ +} + BOOL LLViewerRegion::idleUpdate(F32 max_update_time) { // did_update returns TRUE if we did at least one significant update @@ -807,6 +979,7 @@ void LLViewerRegion::forceUpdate() void LLViewerRegion::connectNeighbor(LLViewerRegion *neighborp, U32 direction) { mImpl->mLandp->connectNeighbor(neighborp->mImpl->mLandp, direction); + neighborp->mImpl->mLandp->connectNeighbor(mImpl->mLandp, gDirOpposite[direction]); #if ENABLE_CLASSIC_CLOUDS mCloudLayer.connectNeighbor(&(neighborp->mCloudLayer), direction); #endif @@ -828,11 +1001,13 @@ LLVLComposition * LLViewerRegion::getComposition() const F32 LLViewerRegion::getCompositionXY(const S32 x, const S32 y) const { - if (x >= 256) +// Singu Note: The Aurora Sim patches here were too many to read the code itself, mWidth and getWidth() (-1) replace 256 (255) in this function, only the first and last tags remain +// Aurora Sim + if (x >= mWidth) { - if (y >= 256) + if (y >= mWidth) { - LLVector3d center = getCenterGlobal() + LLVector3d(256.f, 256.f, 0.f); + LLVector3d center = getCenterGlobal() + LLVector3d(mWidth, mWidth, 0.f); LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromPosGlobal(center); if (regionp) { @@ -841,8 +1016,8 @@ F32 LLViewerRegion::getCompositionXY(const S32 x, const S32 y) const // If we're attempting to blend, then we want to make the fractional part of // this region match the fractional of the adjacent. For now, just minimize // the delta. - F32 our_comp = getComposition()->getValueScaled(255, 255); - F32 adj_comp = regionp->getComposition()->getValueScaled(x - 256.f, y - 256.f); + F32 our_comp = getComposition()->getValueScaled(mWidth-1.f, mWidth-1.f); + F32 adj_comp = regionp->getComposition()->getValueScaled(x - regionp->getWidth(), y - regionp->getWidth()); while (llabs(our_comp - adj_comp) >= 1.f) { if (our_comp > adj_comp) @@ -859,7 +1034,7 @@ F32 LLViewerRegion::getCompositionXY(const S32 x, const S32 y) const } else { - LLVector3d center = getCenterGlobal() + LLVector3d(256.f, 0, 0.f); + LLVector3d center = getCenterGlobal() + LLVector3d(mWidth, 0.f, 0.f); LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromPosGlobal(center); if (regionp) { @@ -868,8 +1043,8 @@ F32 LLViewerRegion::getCompositionXY(const S32 x, const S32 y) const // If we're attempting to blend, then we want to make the fractional part of // this region match the fractional of the adjacent. For now, just minimize // the delta. - F32 our_comp = getComposition()->getValueScaled(255.f, (F32)y); - F32 adj_comp = regionp->getComposition()->getValueScaled(x - 256.f, (F32)y); + F32 our_comp = getComposition()->getValueScaled(mWidth-1.f, (F32)y); + F32 adj_comp = regionp->getComposition()->getValueScaled(x - regionp->getWidth(), (F32)y); while (llabs(our_comp - adj_comp) >= 1.f) { if (our_comp > adj_comp) @@ -885,9 +1060,9 @@ F32 LLViewerRegion::getCompositionXY(const S32 x, const S32 y) const } } } - else if (y >= 256) + else if (y >= mWidth) { - LLVector3d center = getCenterGlobal() + LLVector3d(0.f, 256.f, 0.f); + LLVector3d center = getCenterGlobal() + LLVector3d(0.f, mWidth, 0.f); LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromPosGlobal(center); if (regionp) { @@ -896,8 +1071,9 @@ F32 LLViewerRegion::getCompositionXY(const S32 x, const S32 y) const // If we're attempting to blend, then we want to make the fractional part of // this region match the fractional of the adjacent. For now, just minimize // the delta. - F32 our_comp = getComposition()->getValueScaled((F32)x, 255.f); - F32 adj_comp = regionp->getComposition()->getValueScaled((F32)x, y - 256.f); + F32 our_comp = getComposition()->getValueScaled((F32)x, mWidth-1.f); + F32 adj_comp = regionp->getComposition()->getValueScaled((F32)x, y - regionp->getWidth()); +// Aurora Sim while (llabs(our_comp - adj_comp) >= 1.f) { if (our_comp > adj_comp) @@ -975,7 +1151,7 @@ void LLViewerRegion::updateNetStats() mPacketsLost = cdp->getPacketsLost(); mPingDelay = cdp->getPingDelay(); - mBitStat.addValue(mBitsIn - mLastBitsIn); + mBitStat.addValue((mBitsIn - mLastBitsIn).value()); mPacketsStat.addValue(mPacketsIn - mLastPacketsIn); mPacketsLostStat.addValue(mPacketsLost); } @@ -986,7 +1162,7 @@ U32 LLViewerRegion::getPacketsLost() const LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(mImpl->mHost); if (!cdp) { - llinfos << "LLViewerRegion::getPacketsLost couldn't find circuit for " << mImpl->mHost << llendl; + LL_INFOS() << "LLViewerRegion::getPacketsLost couldn't find circuit for " << mImpl->mHost << LL_ENDL; return 0; } else @@ -1054,7 +1230,40 @@ F32 LLViewerRegion::getLandHeightRegion(const LLVector3& region_pos) return mImpl->mLandp->resolveHeightRegion( region_pos ); } -bool LLViewerRegion::isAlive() +// [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-06-20 (Catznip-3.3.0) +const LLViewerRegion::tex_matrix_t& LLViewerRegion::getWorldMapTiles() const +{ + if (mWorldMapTiles.empty()) + { + U32 gridX, gridY; + grid_from_region_handle(mHandle, &gridX, &gridY); + // Singu Note: We must obey the override on certain grids! + std::string simOverrideMap = LFSimFeatureHandler::instance().mapServerURL(); + std::string strImgURL = (simOverrideMap.empty() ? gSavedSettings.getString("MapServerURL") : simOverrideMap) + "map-1-"; + U32 totalX(getWidth()/REGION_WIDTH_U32); + if (!totalX) ++totalX; // If this region is too small, still get an image. + /* TODO: Nonsquare regions? + U32 totalY(getLength()/REGION_WIDTH_U32); + if (!totalY) ++totalY; // If this region is too small, still get an image. + */ + const U32 totalY(totalX); + mWorldMapTiles.reserve(totalX*totalY); + for (U32 x = 0; x != totalX; ++x) + for (U32 y = 0; y != totalY; ++y) + { + LLPointer tex(LLViewerTextureManager::getFetchedTextureFromUrl(strImgURL+llformat("%d-%d-objects.jpg", gridX + x, gridY + y), FTT_MAP_TILE, TRUE, LLViewerTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE)); + mWorldMapTiles.push_back(tex); + tex->setBoostLevel(LLViewerTexture::BOOST_MAP); + } + } + return mWorldMapTiles; +} +// [/SL:KB] + +//bool LLViewerRegion::isAlive() +// [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-06-20 (Catznip-3.3.0) +bool LLViewerRegion::isAlive() const +// [/SL:KB] { return mAlive; } @@ -1099,14 +1308,15 @@ class CoarseLocationUpdate : public LLHTTPNode S32 target_index = input["body"]["Index"][0]["Prey"].asInteger(); S32 you_index = input["body"]["Index"][0]["You" ].asInteger(); - LLDynamicArray* avatar_locs = ®ion->mMapAvatars; - LLDynamicArray* avatar_ids = ®ion->mMapAvatarIDs; - avatar_locs->reset(); - avatar_ids->reset(); + std::vector& avatar_locs = region->mMapAvatars; + uuid_vec_t& avatar_ids = region->mMapAvatarIDs; + std::list map_avids(avatar_ids.begin(), avatar_ids.end()); + avatar_locs.clear(); + avatar_ids.clear(); - //llinfos << "coarse locations agent[0] " << input["body"]["AgentData"][0]["AgentID"].asUUID() << llendl; - //llinfos << "my agent id = " << gAgent.getID() << llendl; - //llinfos << ll_pretty_print_sd(input) << llendl; + //LL_INFOS() << "coarse locations agent[0] " << input["body"]["AgentData"][0]["AgentID"].asUUID() << LL_ENDL; + //LL_INFOS() << "my agent id = " << gAgent.getID() << LL_ENDL; + //LL_INFOS() << ll_pretty_print_sd(input) << LL_ENDL; LLSD locs = input["body"]["Location"], @@ -1142,13 +1352,14 @@ class CoarseLocationUpdate : public LLHTTPNode pos |= y; pos <<= 8; pos |= z; - avatar_locs->put(pos); - //llinfos << "next pos: " << x << "," << y << "," << z << ": " << pos << llendl; + avatar_locs.push_back(pos); + //LL_INFOS() << "next pos: " << x << "," << y << "," << z << ": " << pos << LL_ENDL; if(has_agent_data) // for backwards compatibility with old message format { LLUUID agent_id(agents_it->get("AgentID").asUUID()); - //llinfos << "next agent: " << agent_id.asString() << llendl; - avatar_ids->put(agent_id); + //LL_INFOS() << "next agent: " << agent_id.asString() << LL_ENDL; + avatar_ids.push_back(agent_id); + map_avids.remove(agent_id); } } if (has_agent_data) @@ -1156,6 +1367,12 @@ class CoarseLocationUpdate : public LLHTTPNode agents_it++; } } + if (LLFloaterAvatarList::instanceExists()) + { + LLFloaterAvatarList& inst(LLFloaterAvatarList::instance()); + inst.updateAvatarList(region); + inst.expireAvatarList(map_avids); + } } }; @@ -1168,9 +1385,10 @@ LLHTTPRegistration // the deprecated coarse location handler void LLViewerRegion::updateCoarseLocations(LLMessageSystem* msg) { - //llinfos << "CoarseLocationUpdate" << llendl; - mMapAvatars.reset(); - mMapAvatarIDs.reset(); // only matters in a rare case but it's good to be safe. + //LL_INFOS() << "CoarseLocationUpdate" << LL_ENDL; + std::list map_avids(mMapAvatarIDs.begin(), mMapAvatarIDs.end()); + mMapAvatars.clear(); + mMapAvatarIDs.clear(); // only matters in a rare case but it's good to be safe. U8 x_pos = 0; U8 y_pos = 0; @@ -1196,9 +1414,9 @@ void LLViewerRegion::updateCoarseLocations(LLMessageSystem* msg) msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id, i); } - //llinfos << " object X: " << (S32)x_pos << " Y: " << (S32)y_pos + //LL_INFOS() << " object X: " << (S32)x_pos << " Y: " << (S32)y_pos // << " Z: " << (S32)(z_pos * 4) - // << llendl; + // << LL_ENDL; // treat the target specially for the map if(i == target_index) @@ -1219,13 +1437,20 @@ void LLViewerRegion::updateCoarseLocations(LLMessageSystem* msg) pos |= y_pos; pos <<= 8; pos |= z_pos; - mMapAvatars.put(pos); + mMapAvatars.push_back(pos); if(has_agent_data) { - mMapAvatarIDs.put(agent_id); + mMapAvatarIDs.push_back(agent_id); + map_avids.remove(agent_id); } } } + if (LLFloaterAvatarList::instanceExists()) + { + LLFloaterAvatarList& inst(LLFloaterAvatarList::instance()); + inst.updateAvatarList(this); + inst.expireAvatarList(map_avids); + } } void LLViewerRegion::getInfo(LLSD& info) @@ -1238,7 +1463,102 @@ void LLViewerRegion::getInfo(LLSD& info) info["Region"]["Handle"]["y"] = (LLSD::Integer)y; } -void LLViewerRegion::getSimulatorFeatures(LLSD& sim_features) +class BaseFeaturesReceived : public LLHTTPClient::ResponderWithResult +{ + LOG_CLASS(BaseFeaturesReceived); +public: + BaseFeaturesReceived(const std::string& retry_url, U64 region_handle, const char* classname, boost::function fn, + S32 attempt = 0, S32 max_attempts = MAX_CAP_REQUEST_ATTEMPTS) + : mRetryURL(retry_url), mRegionHandle(region_handle), mAttempt(attempt), mMaxAttempts(max_attempts), mClassName(classname), mFunction(fn) + { } + + + void httpFailure(void) + { + LL_WARNS("AppInit", mClassName) << dumpResponse() << LL_ENDL; + retry(); + } + + void httpSuccess(void) + { + LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); + if (!regionp) //region is removed or responder is not created. + { + LL_WARNS("AppInit", mClassName) + << "Received results for region that no longer exists!" << LL_ENDL; + return; + } + + const LLSD& content = getContent(); + if (!content.isMap()) + { + failureResult(400, "Malformed response contents", content); + return; + } + mFunction(regionp, content); + } + + /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return baseFeaturesReceived_timeout; } + /*virtual*/ char const* getName(void) const { return mClassName; } + +private: + + void retry() + { + if (mAttempt < mMaxAttempts) + { + mAttempt++; + LL_WARNS("AppInit", mClassName) << "Re-trying '" << mRetryURL << "'. Retry #" << mAttempt << LL_ENDL; + LLHTTPClient::get(mRetryURL, new BaseFeaturesReceived(*this)); + } + } + + std::string mRetryURL; + U64 mRegionHandle; + S32 mAttempt; + S32 mMaxAttempts; + const char* mClassName; + boost::function mFunction; +}; + +void LLViewerRegion::requestSimulatorFeatures() +{ + LL_DEBUGS("SimulatorFeatures") << "region " << getName() << " ptr " << this + << " trying to request SimulatorFeatures" << LL_ENDL; + // kick off a request for simulator features + std::string url = getCapability("SimulatorFeatures"); + if (!url.empty()) + { + // kick off a request for simulator features + LLHTTPClient::get(url, new BaseFeaturesReceived(url, getHandle(), "SimulatorFeaturesReceived", &LLViewerRegion::setSimulatorFeatures)); + } + else + { + LL_WARNS("AppInit", "SimulatorFeatures") << "SimulatorFeatures cap not set" << LL_ENDL; + } +} + +boost::signals2::connection LLViewerRegion::setSimulatorFeaturesReceivedCallback(const caps_received_signal_t::slot_type& cb) +{ + return mSimulatorFeaturesReceivedSignal.connect(cb); +} + +void LLViewerRegion::setSimulatorFeaturesReceived(bool received) +{ + mSimulatorFeaturesReceived = received; + if (received) + { + mSimulatorFeaturesReceivedSignal(getRegionID()); + mSimulatorFeaturesReceivedSignal.disconnect_all_slots(); + } +} + +bool LLViewerRegion::simulatorFeaturesReceived() const +{ + return mSimulatorFeaturesReceived; +} + +void LLViewerRegion::getSimulatorFeatures(LLSD& sim_features) const { sim_features = mSimulatorFeatures; } @@ -1248,12 +1568,11 @@ void LLViewerRegion::setSimulatorFeatures(const LLSD& sim_features) std::stringstream str; LLSDSerialize::toPrettyXML(sim_features, str); - llinfos << str.str() << llendl; + LL_INFOS() << "region " << getName() << " " << str.str() << LL_ENDL; mSimulatorFeatures = sim_features; - mFeaturesReceived = true; - mFeaturesReceivedSignal(getRegionID()); - mFeaturesReceivedSignal.disconnect_all_slots(); + setSimulatorFeaturesReceived(true); + } void LLViewerRegion::setGamingData(const LLSD& gaming_data) @@ -1261,7 +1580,7 @@ void LLViewerRegion::setGamingData(const LLSD& gaming_data) mGamingFlags = 0; if (!gaming_data.has("display")) - llerrs << "GamingData Capability requires \"display\"" << llendl; + LL_ERRS() << "GamingData Capability requires \"display\"" << LL_ENDL; if (gaming_data["display"].asBoolean()) mGamingFlags |= REGION_GAMING_PRESENT; if (gaming_data.has("hide_parcel") && gaming_data["hide_parcel"].asBoolean()) @@ -1283,7 +1602,7 @@ void LLViewerRegion::setGamingData(const LLSD& gaming_data) if (gaming_data.has("hide_god_floater") && gaming_data["hide_god_floater"].asBoolean()) mGamingFlags |= REGION_GAMING_HIDE_GOD_FLOATER; - llinfos << "Gaming flags are " << mGamingFlags << llendl; + LL_INFOS() << "Gaming flags are " << mGamingFlags << LL_ENDL; } LLViewerRegion::eCacheUpdateResult LLViewerRegion::cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp) @@ -1328,6 +1647,14 @@ LLViewerRegion::eCacheUpdateResult LLViewerRegion::cacheFullUpdate(LLViewerObjec return result; } +void LLViewerRegion::removeFromCreatedList(U32 local_id) +{ +} + +void LLViewerRegion::addToCreatedList(U32 local_id) +{ +} + // Get data packer for this object, if we have cached data // AND the CRC matches. JC LLDataPacker *LLViewerRegion::getDP(U32 local_id, U32 crc, U8 &cache_miss_type) @@ -1348,16 +1675,16 @@ LLDataPacker *LLViewerRegion::getDP(U32 local_id, U32 crc, U8 &cache_miss_type) } else { - // llinfos << "CRC miss for " << local_id << llendl; + // LL_INFOS() << "CRC miss for " << local_id << LL_ENDL; cache_miss_type = CACHE_MISS_TYPE_CRC; - mCacheMissCRC.put(local_id); + mCacheMissCRC.push_back(local_id); } } else { - // llinfos << "Cache miss for " << local_id << llendl; + // LL_INFOS() << "Cache miss for " << local_id << LL_ENDL; cache_miss_type = CACHE_MISS_TYPE_FULL; - mCacheMissFull.put(local_id); + mCacheMissFull.push_back(local_id); } return NULL; @@ -1365,13 +1692,13 @@ LLDataPacker *LLViewerRegion::getDP(U32 local_id, U32 crc, U8 &cache_miss_type) void LLViewerRegion::addCacheMissFull(const U32 local_id) { - mCacheMissFull.put(local_id); + mCacheMissFull.push_back(local_id); } void LLViewerRegion::requestCacheMisses() { - S32 full_count = mCacheMissFull.count(); - S32 crc_count = mCacheMissCRC.count(); + S32 full_count = mCacheMissFull.size(); + S32 crc_count = mCacheMissCRC.size(); if (full_count == 0 && crc_count == 0) return; LLMessageSystem* msg = gMessageSystem; @@ -1436,11 +1763,11 @@ void LLViewerRegion::requestCacheMisses() { sendReliableMessage(); } - mCacheMissFull.reset(); - mCacheMissCRC.reset(); + mCacheMissFull.clear(); + mCacheMissCRC.clear(); mCacheDirty = TRUE ; - // llinfos << "KILLDEBUG Sent cache miss full " << full_count << " crc " << crc_count << llendl; + // LL_INFOS() << "KILLDEBUG Sent cache miss full " << full_count << " crc " << crc_count << LL_ENDL; LLViewerStatsRecorder::instance().requestCacheMissesEvent(full_count + crc_count); LLViewerStatsRecorder::instance().log(0.2f); } @@ -1473,14 +1800,14 @@ void LLViewerRegion::dumpCache() change_bin[changes]++; } - llinfos << "Count " << mImpl->mCacheMap.size() << llendl; + LL_INFOS() << "Count " << mImpl->mCacheMap.size() << LL_ENDL; for (i = 0; i < BINS; i++) { - llinfos << "Hits " << i << " " << hit_bin[i] << llendl; + LL_INFOS() << "Hits " << i << " " << hit_bin[i] << LL_ENDL; } for (i = 0; i < BINS; i++) { - llinfos << "Changes " << i << " " << change_bin[i] << llendl; + LL_INFOS() << "Changes " << i << " " << change_bin[i] << LL_ENDL; } } @@ -1565,41 +1892,69 @@ void LLViewerRegion::unpackRegionHandshake() { LLUUID tmp_id; + bool changed = false; + + // Get the 4 textures for land msg->getUUID("RegionInfo", "TerrainDetail0", tmp_id); + changed |= (tmp_id != compp->getDetailTextureID(0)); compp->setDetailTextureID(0, tmp_id); + msg->getUUID("RegionInfo", "TerrainDetail1", tmp_id); + changed |= (tmp_id != compp->getDetailTextureID(1)); compp->setDetailTextureID(1, tmp_id); + msg->getUUID("RegionInfo", "TerrainDetail2", tmp_id); + changed |= (tmp_id != compp->getDetailTextureID(2)); compp->setDetailTextureID(2, tmp_id); + msg->getUUID("RegionInfo", "TerrainDetail3", tmp_id); + changed |= (tmp_id != compp->getDetailTextureID(3)); compp->setDetailTextureID(3, tmp_id); + // Get the start altitude and range values for land textures F32 tmp_f32; msg->getF32("RegionInfo", "TerrainStartHeight00", tmp_f32); + changed |= (tmp_f32 != compp->getStartHeight(0)); compp->setStartHeight(0, tmp_f32); + msg->getF32("RegionInfo", "TerrainStartHeight01", tmp_f32); + changed |= (tmp_f32 != compp->getStartHeight(1)); compp->setStartHeight(1, tmp_f32); + msg->getF32("RegionInfo", "TerrainStartHeight10", tmp_f32); + changed |= (tmp_f32 != compp->getStartHeight(2)); compp->setStartHeight(2, tmp_f32); + msg->getF32("RegionInfo", "TerrainStartHeight11", tmp_f32); + changed |= (tmp_f32 != compp->getStartHeight(3)); compp->setStartHeight(3, tmp_f32); + msg->getF32("RegionInfo", "TerrainHeightRange00", tmp_f32); + changed |= (tmp_f32 != compp->getHeightRange(0)); compp->setHeightRange(0, tmp_f32); + msg->getF32("RegionInfo", "TerrainHeightRange01", tmp_f32); + changed |= (tmp_f32 != compp->getHeightRange(1)); compp->setHeightRange(1, tmp_f32); + msg->getF32("RegionInfo", "TerrainHeightRange10", tmp_f32); + changed |= (tmp_f32 != compp->getHeightRange(2)); compp->setHeightRange(2, tmp_f32); + msg->getF32("RegionInfo", "TerrainHeightRange11", tmp_f32); + changed |= (tmp_f32 != compp->getHeightRange(3)); compp->setHeightRange(3, tmp_f32); // If this is an UPDATE (params already ready, we need to regenerate // all of our terrain stuff, by if (compp->getParamsReady()) { - // The following line was commented out in http://hg.secondlife.com/viewer-development/commits/448b02f5b56f9e608952c810df5454f83051a992 - // by davep. However, this is needed to see changes in region/estate texture elevation ranges, and to update the terrain textures after terraforming. - getLand().dirtyAllPatches(); + // Update if the land changed + if (changed) + { + getLand().dirtyAllPatches(); + } } else { @@ -1631,28 +1986,56 @@ void LLViewerRegion::unpackRegionHandshake() void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) { + capabilityNames.append("AbuseCategories"); + capabilityNames.append("AcceptFriendship"); + capabilityNames.append("AcceptGroupInvite"); // ReadOfflineMsgs recieved messages only!!! + capabilityNames.append("AgentPreferences"); capabilityNames.append("AgentState"); capabilityNames.append("AttachmentResources"); //capabilityNames.append("AvatarPickerSearch"); //Display name/SLID lookup (llfloateravatarpicker.cpp) + capabilityNames.append("AvatarRenderInfo"); capabilityNames.append("CharacterProperties"); capabilityNames.append("ChatSessionRequest"); capabilityNames.append("CopyInventoryFromNotecard"); capabilityNames.append("CreateInventoryCategory"); capabilityNames.append("CustomMenuAction"); + capabilityNames.append("DeclineFriendship"); + capabilityNames.append("DeclineGroupInvite"); // ReadOfflineMsgs recieved messages only!!! capabilityNames.append("DispatchRegionInfo"); + capabilityNames.append("DirectDelivery"); capabilityNames.append("EnvironmentSettings"); + capabilityNames.append("EstateAccess"); capabilityNames.append("EstateChangeInfo"); capabilityNames.append("EventQueueGet"); + capabilityNames.append("ExtEnvironment"); capabilityNames.append("FetchLib2"); capabilityNames.append("FetchLibDescendents2"); capabilityNames.append("FetchInventory2"); capabilityNames.append("FetchInventoryDescendents2"); + capabilityNames.append("IncrementCOFVersion"); capabilityNames.append("GamingData"); //Used by certain grids. + AISAPI::getCapNames(capabilityNames); + capabilityNames.append("GetDisplayNames"); + capabilityNames.append("GetExperiences"); + capabilityNames.append("AgentExperiences"); + capabilityNames.append("FindExperienceByName"); + capabilityNames.append("GetExperienceInfo"); + capabilityNames.append("GetAdminExperiences"); + capabilityNames.append("GetCreatorExperiences"); + capabilityNames.append("ExperiencePreferences"); + capabilityNames.append("GroupExperiences"); + capabilityNames.append("UpdateExperience"); + capabilityNames.append("IsExperienceAdmin"); + capabilityNames.append("IsExperienceContributor"); + capabilityNames.append("RegionExperiences"); capabilityNames.append("GetMesh"); + capabilityNames.append("GetMesh2"); + capabilityNames.append("GetMetadata"); capabilityNames.append("GetObjectCost"); capabilityNames.append("GetObjectPhysicsData"); capabilityNames.append("GetTexture"); + capabilityNames.append("GroupAPIv1"); capabilityNames.append("GroupMemberData"); capabilityNames.append("GroupProposalBallot"); capabilityNames.append("HomeLocation"); @@ -1662,6 +2045,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) capabilityNames.append("MeshUploadFlag"); capabilityNames.append("NavMeshGenerationStatus"); capabilityNames.append("NewFileAgentInventory"); + capabilityNames.append("ObjectAnimation"); capabilityNames.append("ObjectMedia"); capabilityNames.append("ObjectMediaNavigate"); capabilityNames.append("ObjectNavMeshProperties"); @@ -1670,10 +2054,11 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) capabilityNames.append("ParcelVoiceInfoRequest"); capabilityNames.append("ProductInfoRequest"); capabilityNames.append("ProvisionVoiceAccountRequest"); + capabilityNames.append("ReadOfflineMsgs"); // Requires to respond reliably: AcceptFriendship, AcceptGroupInvite, DeclineFriendship, DeclineGroupInvite capabilityNames.append("RemoteParcelRequest"); capabilityNames.append("RenderMaterials"); capabilityNames.append("RequestTextureDownload"); - //capabilityNames.append("ResourceCostSelected"); //Object weights (llfloaterobjectweights.cpp) + capabilityNames.append("ResourceCostSelected"); capabilityNames.append("RetrieveNavMeshSrc"); capabilityNames.append("SearchStatRequest"); capabilityNames.append("SearchStatTracking"); @@ -1699,6 +2084,9 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) capabilityNames.append("UpdateScriptAgent"); capabilityNames.append("UpdateScriptTask"); capabilityNames.append("UploadBakedTexture"); + capabilityNames.append("UserInfo"); + capabilityNames.append("ViewerAsset"); + capabilityNames.append("ViewerBenefits"); capabilityNames.append("ViewerMetrics"); capabilityNames.append("ViewerStartAuction"); capabilityNames.append("ViewerStats"); @@ -1711,8 +2099,19 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames) void LLViewerRegion::setSeedCapability(const std::string& url) { if (getCapability("Seed") == url) - { - // llwarns << "Ignoring duplicate seed capability" << llendl; + { + setCapabilityDebug("Seed", url); + LL_DEBUGS("CrossingCaps") << "Received duplicate seed capability, posting to seed " << + url << LL_ENDL; + + // record that we just entered a new region + newRegionEntry(*this); + + //Instead of just returning we build up a second set of seed caps and compare them + //to the "original" seed cap received and determine why there is problem! + LLSD capabilityNames = LLSD::emptyArray(); + mImpl->buildCapabilityNames( capabilityNames ); + LLHTTPClient::post( url, capabilityNames, BaseCapabilitiesCompleteTracker::build(getHandle() )); return; } @@ -1722,10 +2121,12 @@ void LLViewerRegion::setSeedCapability(const std::string& url) mImpl->mCapabilities.clear(); setCapability("Seed", url); + // record that we just entered a new region + newRegionEntry(*this); LLSD capabilityNames = LLSD::emptyArray(); mImpl->buildCapabilityNames(capabilityNames); - llinfos << "posting to seed " << url << llendl; + LL_INFOS() << "posting to seed " << url << LL_ENDL; S32 id = ++mImpl->mHttpResponderID; LLHTTPClient::post(url, capabilityNames, @@ -1744,7 +2145,7 @@ void LLViewerRegion::failedSeedCapability() std::string url = getCapability("Seed"); if ( url.empty() ) { - LL_WARNS2("AppInit", "Capabilities") << "Failed to get seed capabilities, and can not determine url for retries!" << LL_ENDL; + LL_WARNS("AppInit", "Capabilities") << "Failed to get seed capabilities, and can not determine url for retries!" << LL_ENDL; return; } // After a few attempts, continue login. We will keep trying once in-world: @@ -1759,8 +2160,8 @@ void LLViewerRegion::failedSeedCapability() LLSD capabilityNames = LLSD::emptyArray(); mImpl->buildCapabilityNames(capabilityNames); - llinfos << "posting to seed " << url << " (retry " - << mImpl->mSeedCapAttempts << ")" << llendl; + LL_INFOS() << "posting to seed " << url << " (retry " + << mImpl->mSeedCapAttempts << ")" << LL_ENDL; S32 id = ++mImpl->mHttpResponderID; LLHTTPClient::post(url, capabilityNames, @@ -1769,99 +2170,10 @@ void LLViewerRegion::failedSeedCapability() else { // *TODO: Give a user pop-up about this error? - LL_WARNS2("AppInit", "Capabilities") << "Failed to get seed capabilities from '" << url << "' after " << mImpl->mSeedCapAttempts << " attempts. Giving up!" << LL_ENDL; + LL_WARNS("AppInit", "Capabilities") << "Failed to get seed capabilities from '" << url << "' after " << mImpl->mSeedCapAttempts << " attempts. Giving up!" << LL_ENDL; } } -class SimulatorFeaturesReceived : public LLHTTPClient::ResponderWithResult -{ - LOG_CLASS(SimulatorFeaturesReceived); -public: - SimulatorFeaturesReceived(const std::string& retry_url, U64 region_handle, - S32 attempt = 0, S32 max_attempts = MAX_CAP_REQUEST_ATTEMPTS) - : mRetryURL(retry_url), mRegionHandle(region_handle), mAttempt(attempt), mMaxAttempts(max_attempts) - { } - - - /*virtual*/ void error(U32 statusNum, const std::string& reason) - { - LL_WARNS2("AppInit", "SimulatorFeatures") << statusNum << ": " << reason << LL_ENDL; - retry(); - } - - /*virtual*/ void result(const LLSD& content) - { - LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); - if(!regionp) //region is removed or responder is not created. - { - LL_WARNS2("AppInit", "SimulatorFeatures") << "Received results for region that no longer exists!" << LL_ENDL; - return ; - } - - regionp->setSimulatorFeatures(content); - } - - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return simulatorFeaturesReceived_timeout; } - /*virtual*/ char const* getName(void) const { return "SimulatorFeaturesReceived"; } - -private: - void retry() - { - if (mAttempt < mMaxAttempts) - { - mAttempt++; - LL_WARNS2("AppInit", "SimulatorFeatures") << "Re-trying '" << mRetryURL << "'. Retry #" << mAttempt << LL_ENDL; - LLHTTPClient::get(mRetryURL, new SimulatorFeaturesReceived(*this)); - } - } - - std::string mRetryURL; - U64 mRegionHandle; - S32 mAttempt; - S32 mMaxAttempts; -}; - -class GamingDataReceived : public LLHTTPClient::ResponderWithResult -{ - LOG_CLASS(GamingDataReceived); -public: - GamingDataReceived(const std::string& retry_url, U64 region_handle, S32 attempt = 0, S32 max_attempts = MAX_CAP_REQUEST_ATTEMPTS) - : mRetryURL(retry_url), mRegionHandle(region_handle), mAttempt(attempt), mMaxAttempts(max_attempts) - {} - - /*virtual*/ void error(U32 statusNum, const std::string& reason) - { - LL_WARNS2("AppInit", "GamingData") << statusNum << ": " << reason << LL_ENDL; - retry(); - } - - /*virtual*/ void result(const LLSD& content) - { - LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle); - if(regionp) regionp->setGamingData(content); - } - - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return gamingDataReceived_timeout; } - /*virtual*/ char const* getName(void) const { return "GamingDataReceived"; } - -private: - void retry() - { - if (mAttempt < mMaxAttempts) - { - mAttempt++; - LL_WARNS2("AppInit", "GamingData") << "Retrying '" << mRetryURL << "'. Retry #" << mAttempt << LL_ENDL; - LLHTTPClient::get(mRetryURL, new GamingDataReceived(*this)); - } - } - - std::string mRetryURL; - U64 mRegionHandle; - S32 mAttempt; - S32 mMaxAttempts; -}; - - void LLViewerRegion::setCapability(const std::string& name, const std::string& url) { if(name == "EventQueueGet") @@ -1877,27 +2189,61 @@ void LLViewerRegion::setCapability(const std::string& name, const std::string& u else if (name == "SimulatorFeatures") { // although this is not needed later, add it so we can check if the sim supports it at all later - mImpl->mCapabilities[name] = url; - - // kick off a request for simulator features - LLHTTPClient::get(url, new SimulatorFeaturesReceived(url, getHandle())); + mImpl->mCapabilities["SimulatorFeatures"] = url; + requestSimulatorFeatures(); } else if (name == "GamingData") { LLSD gamingRequest = LLSD::emptyMap(); // request settings from simulator - LLHTTPClient::post(url, gamingRequest, new GamingDataReceived(url, getHandle())); + LLHTTPClient::post(url, gamingRequest, new BaseFeaturesReceived(url, getHandle(), "GamingDataReceived", &LLViewerRegion::setGamingData)); } else { mImpl->mCapabilities[name] = url; - if(name == "GetTexture") + if(name == "ViewerAsset") { - mHttpUrl = url ; + /*==============================================================*/ + // The following inserted lines are a hack for testing MAINT-7081, + // which is why the indentation and formatting are left ugly. + const char* VIEWERASSET = getenv("VIEWERASSET"); + if (VIEWERASSET) + { + mImpl->mCapabilities[name] = VIEWERASSET; + mViewerAssetUrl = VIEWERASSET; + } + else + /*==============================================================*/ + mViewerAssetUrl = url; } } } +void LLViewerRegion::setCapabilityDebug(const std::string& name, const std::string& url) +{ + // Continue to not add certain caps, as we do in setCapability. This is so they match up when we check them later. + if ( ! ( name == "EventQueueGet" || name == "UntrustedSimulatorMessage" || name == "SimulatorFeatures" ) ) + { + mImpl->mSecondCapabilitiesTracker[name] = url; + if(name == "ViewerAsset") + { + /*==============================================================*/ + // The following inserted lines are a hack for testing MAINT-7081, + // which is why the indentation and formatting are left ugly. + const char* VIEWERASSET = getenv("VIEWERASSET"); + if (VIEWERASSET) + { + mImpl->mSecondCapabilitiesTracker[name] = VIEWERASSET; + mViewerAssetUrl = VIEWERASSET; + } + else + /*==============================================================*/ + mViewerAssetUrl = url; + } + } + +} + bool LLViewerRegion::isSpecialCapabilityName(const std::string &name) { return name == "EventQueueGet" || name == "UntrustedSimulatorMessage"; @@ -1907,7 +2253,7 @@ std::string LLViewerRegion::getCapability(const std::string& name) const { if (!capabilitiesReceived() && (name!=std::string("Seed")) && (name!=std::string("ObjectMedia"))) { - llwarns << "getCapability("<mCapabilities.find(name); @@ -1919,6 +2265,22 @@ std::string LLViewerRegion::getCapability(const std::string& name) const return iter->second; } +bool LLViewerRegion::isCapabilityAvailable(const std::string& name) const +{ + if (!capabilitiesReceived() && (name!=std::string("Seed")) && (name!=std::string("ObjectMedia"))) + { + LL_WARNS() << "isCapabilityAvailable called before caps received for " << name << LL_ENDL; + } + + CapabilityMap::const_iterator iter = mImpl->mCapabilities.find(name); + if(iter == mImpl->mCapabilities.end()) + { + return false; + } + + return true; +} + bool LLViewerRegion::capabilitiesReceived() const { return mCapabilitiesReceived; @@ -1934,6 +2296,8 @@ void LLViewerRegion::setCapabilitiesReceived(bool received) { mCapabilitiesReceivedSignal(getRegionID()); + LLFloaterPermsDefault::sendInitialPerms(); + // This is a single-shot signal. Forget callbacks to save resources. mCapabilitiesReceivedSignal.disconnect_all_slots(); @@ -1941,9 +2305,9 @@ void LLViewerRegion::setCapabilitiesReceived(bool received) // in consumers by allowing them to expect this signal, regardless. if (getCapability("SimulatorFeatures").empty()) { - mFeaturesReceived = true; - mFeaturesReceivedSignal(getRegionID()); - mFeaturesReceivedSignal.disconnect_all_slots(); + mSimulatorFeaturesReceived = true; + mSimulatorFeaturesReceivedSignal(getRegionID()); + mSimulatorFeaturesReceivedSignal.disconnect_all_slots(); } } } @@ -1961,17 +2325,17 @@ void LLViewerRegion::logActiveCapabilities() const { if (!iter->second.empty()) { - llinfos << iter->first << " URL is " << iter->second << llendl; + LL_INFOS() << iter->first << " URL is " << iter->second << LL_ENDL; } } - llinfos << "Dumped " << count << " entries." << llendl; + LL_INFOS() << "Dumped " << count << " entries." << LL_ENDL; } LLSpatialPartition* LLViewerRegion::getSpatialPartition(U32 type) { if (type < mImpl->mObjectPartition.size()) { - return mImpl->mObjectPartition[type]; + return (LLSpatialPartition*)mImpl->mObjectPartition[type]; } return NULL; } @@ -2010,6 +2374,7 @@ void LLViewerRegion::getNeighboringRegionsStatus( std::vector& regions ) { mImpl->mLandp->getNeighboringRegionsStatus( regions ); } + void LLViewerRegion::showReleaseNotes() { std::string url = this->getCapability("ServerReleaseNotes"); @@ -2043,11 +2408,21 @@ bool LLViewerRegion::meshUploadEnabled() const } } +bool LLViewerRegion::bakesOnMeshEnabled() const +{ + return (mSimulatorFeatures.has("BakesOnMeshEnabled") && + mSimulatorFeatures["BakesOnMeshEnabled"].asBoolean()); +} + bool LLViewerRegion::meshRezEnabled() const { - if (getCapability("SimulatorFeatures").empty()) + if (!capabilitiesReceived()) { - return !getCapability("GetMesh").empty(); + return false; + } + else if (getCapability("SimulatorFeatures").empty()) + { + return !getCapability("GetMesh").empty() || !getCapability("GetMesh2").empty(); } else { @@ -2062,8 +2437,65 @@ bool LLViewerRegion::dynamicPathfindingEnabled() const mSimulatorFeatures["DynamicPathfindingEnabled"].asBoolean()); } -boost::signals2::connection LLViewerRegion::setFeaturesReceivedCallback(const features_received_signal_t::slot_type& cb) +bool LLViewerRegion::avatarHoverHeightEnabled() const { - return mFeaturesReceivedSignal.connect(cb); + return ( mSimulatorFeatures.has("AvatarHoverHeightEnabled") && + mSimulatorFeatures["AvatarHoverHeightEnabled"].asBoolean()); } +/* Static Functions */ +void log_capabilities(const CapabilityMap &capmap) +{ + S32 count = 0; + CapabilityMap::const_iterator iter; + for (iter = capmap.begin(); iter != capmap.end(); ++iter, ++count) + { + if (!iter->second.empty()) + { + LL_INFOS() << "log_capabilities: " << iter->first << " URL is " << iter->second << LL_ENDL; + } + } + LL_INFOS() << "log_capabilities: Dumped " << count << " entries." << LL_ENDL; +} +void LLViewerRegion::resetMaterialsCapThrottle() +{ + F32 requests_per_sec = 1.0f; // original default; + if ( mSimulatorFeatures.has("RenderMaterialsCapability") + && mSimulatorFeatures["RenderMaterialsCapability"].isReal() ) + { + requests_per_sec = mSimulatorFeatures["RenderMaterialsCapability"].asReal(); + if ( requests_per_sec == 0.0f ) + { + requests_per_sec = 1.0f; + LL_WARNS("Materials") + << "region '" << getName() + << "' returned zero for RenderMaterialsCapability; using default " + << requests_per_sec << " per second" + << LL_ENDL; + } + LL_DEBUGS("Materials") << "region '" << getName() + << "' RenderMaterialsCapability " << requests_per_sec + << LL_ENDL; + } + else + { + LL_DEBUGS("Materials") + << "region '" << getName() + << "' did not return RenderMaterialsCapability, using default " + << requests_per_sec << " per second" + << LL_ENDL; + } + + mMaterialsCapThrottleTimer.resetWithExpiry( 1.0f / requests_per_sec ); +} + +U32 LLViewerRegion::getMaxMaterialsPerTransaction() const +{ + U32 max_entries = 50; // original hard coded default + if ( mSimulatorFeatures.has( "MaxMaterialsPerTransaction" ) + && mSimulatorFeatures[ "MaxMaterialsPerTransaction" ].isInteger()) + { + max_entries = mSimulatorFeatures[ "MaxMaterialsPerTransaction" ].asInteger(); + } + return max_entries; +} diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h index e22fc39070..b4fed423b2 100644 --- a/indra/newview/llviewerregion.h +++ b/indra/newview/llviewerregion.h @@ -38,7 +38,6 @@ #include #include -#include "lldarray.h" #include "llwind.h" #include "llcloud.h" #include "llstat.h" @@ -48,12 +47,12 @@ #include "lluuid.h" #include "llweb.h" #include "llcapabilityprovider.h" -#include "m4math.h" // LLMatrix4 +#include "llmatrix4a.h" // LLMatrix4a #include "llhttpclient.h" // Surface id's -#define LAND 1 -#define WATER 2 +//#define LAND 1 +//#define WATER 2 const U32 MAX_OBJECT_CACHE_ENTRIES = 50000; // Region handshake flags @@ -75,8 +74,13 @@ class LLDataPacker; class LLDataPackerBinaryBuffer; class LLHost; class LLBBox; +class LLSpatialGroup; +// [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-07-26 (Catznip-3.3) +class LLViewerTexture; +// [/SL:KB] class LLViewerRegionImpl; +class LLViewerOctreeGroup; class LLViewerRegion: public LLCapabilityProvider // implements this interface { @@ -96,13 +100,13 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface PARTITION_GRASS, PARTITION_VOLUME, PARTITION_BRIDGE, + PARTITION_ATTACHMENT, PARTITION_HUD_PARTICLE, PARTITION_NONE, NUM_PARTITIONS } eObjectPartitions; typedef boost::signals2::signal caps_received_signal_t; - typedef boost::signals2::signal features_received_signal_t; LLViewerRegion(const U64 &handle, const LLHost &host, @@ -111,6 +115,16 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface const F32 region_width_meters); ~LLViewerRegion(); + void* operator new(size_t size) + { + return ll_aligned_malloc_16(size); + } + + void operator delete(void* ptr) + { + ll_aligned_free_16(ptr); + } + // Call this after you have the region name and handle. void loadObjectCache(); void saveObjectCache(); @@ -127,7 +141,7 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface void setAllowSetHome(BOOL b) { setRegionFlag(REGION_FLAGS_ALLOW_SET_HOME, b); } void setResetHomeOnTeleport(BOOL b) { setRegionFlag(REGION_FLAGS_RESET_HOME_ON_TELEPORT, b); } void setSunFixed(BOOL b) { setRegionFlag(REGION_FLAGS_SUN_FIXED, b); } - void setBlockFly(BOOL b) { setRegionFlag(REGION_FLAGS_BLOCK_FLY, b); } + //void setBlockFly(BOOL b) { setRegionFlag(REGION_FLAGS_BLOCK_FLY, b); } Never used void setAllowDirectTeleport(BOOL b) { setRegionFlag(REGION_FLAGS_ALLOW_DIRECT_TELEPORT, b); } @@ -143,7 +157,13 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface inline BOOL getRestrictPushObject() const; inline BOOL getReleaseNotesRequested() const; - bool isAlive(); // can become false if circuit disconnects +// bool isAlive(); // can become false if circuit disconnects +// [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-06-20 (Catznip-3.3.0) + bool isAlive() const; // can become false if circuit disconnects + + typedef std::vector > tex_matrix_t; + const tex_matrix_t& getWorldMapTiles() const; +// [/SL:KB] void setWaterHeight(F32 water_level); F32 getWaterHeight() const; @@ -204,8 +224,8 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface void setSimAccess(U8 sim_access) { mSimAccess = sim_access; } U8 getSimAccess() const { return mSimAccess; } - const std::string getSimAccessString() const; - + std::string const& getSimAccessString(); // Singu note: return reference to mSimAccessString. + // Homestead-related getters; there are no setters as nobody should be // setting them other than the individual message handler which is a member S32 getSimClassID() const { return mClassID; } @@ -254,6 +274,8 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface void failedSeedCapability(); S32 getNumSeedCapRetries(); void setCapability(const std::string& name, const std::string& url); + void setCapabilityDebug(const std::string& name, const std::string& url); + bool isCapabilityAvailable(const std::string& name) const; // implements LLCapabilityProvider virtual std::string getCapability(const std::string& name) const; @@ -265,9 +287,6 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface static bool isSpecialCapabilityName(const std::string &name); void logActiveCapabilities() const; - boost::signals2::connection setFeaturesReceivedCallback(const features_received_signal_t::slot_type& cb); - bool getFeaturesReceived() const { return mFeaturesReceived; } - /// Get LLEventPump on which we listen for capability requests /// (https://wiki.lindenlab.com/wiki/Viewer:Messaging/Messaging_Notes#Capabilities) LLEventPump& getCapAPI() const; @@ -308,12 +327,22 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface bool meshRezEnabled() const; bool meshUploadEnabled() const; - void getSimulatorFeatures(LLSD& info); + bool bakesOnMeshEnabled() const; + + // has region received its simulator features list? Requires an additional query after caps received. + void requestSimulatorFeatures(); + void setSimulatorFeaturesReceived(bool); + bool simulatorFeaturesReceived() const; + boost::signals2::connection setSimulatorFeaturesReceivedCallback(const caps_received_signal_t::slot_type& cb); + + void getSimulatorFeatures(LLSD& info) const; void setSimulatorFeatures(const LLSD& info); bool dynamicPathfindingEnabled() const; + bool avatarHoverHeightEnabled() const; + typedef enum { CACHE_MISS_TYPE_FULL = 0, @@ -335,6 +364,7 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface void requestCacheMisses(); void addCacheMissFull(const U32 local_id); + void clearCachedVisibleObjects(); void dumpCache(); void unpackRegionHandshake(); @@ -344,8 +374,9 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface friend std::ostream& operator<<(std::ostream &s, const LLViewerRegion ®ion); /// implements LLCapabilityProvider - virtual std::string getDescription() const; - std::string getHttpUrl() const { return mHttpUrl ;} + virtual std::string getDescription() const override; + + std::string getViewerAssetUrl() const { return mViewerAssetUrl; } LLSpatialPartition* getSpatialPartition(U32 type); @@ -355,10 +386,20 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface void getNeighboringRegions( std::vector& uniqueRegions ); void getNeighboringRegionsStatus( std::vector& regions ); - + const LLViewerRegionImpl * getRegionImpl() const { return mImpl; } + LLViewerRegionImpl * getRegionImplNC() { return mImpl; } + void setGamingData(const LLSD& info); const U32 getGamingFlags() const { return mGamingFlags; } + + // implements the materials capability throttle + bool materialsCapThrottled() const { return !mMaterialsCapThrottleTimer.hasExpired(); } + void resetMaterialsCapThrottle(); + + U32 getMaxMaterialsPerTransaction() const; + void removeFromCreatedList(U32 local_id); + void addToCreatedList(U32 local_id); public: struct CompareDistance { @@ -369,10 +410,12 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface }; void showReleaseNotes(); + void reInitPartitions(); protected: void disconnectAllNeighbors(); void initStats(); + void initPartitions(); public: LLWind mWind; @@ -385,16 +428,18 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface LLStat mPacketsStat; LLStat mPacketsLostStat; - LLMatrix4 mRenderMatrix; + LL_ALIGN_16(LLMatrix4a mRenderMatrix); // These arrays are maintained in parallel. Ideally they'd be combined into a // single array of an aggrigate data type but for compatibility with the old // messaging system in which the previous message only sends and parses the // positions stored in the first array so they're maintained separately until // we stop supporting the old CoarseLocationUpdate message. - LLDynamicArray mMapAvatars; - LLDynamicArray mMapAvatarIDs; + std::vector mMapAvatars; + uuid_vec_t mMapAvatarIDs; + + LLFrameTimer & getRenderInfoRequestTimer() { return mRenderInfoRequestTimer; }; private: LLViewerRegionImpl * mImpl; @@ -410,19 +455,21 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface BOOL mIsEstateManager; U32 mPacketsIn; - U32 mBitsIn; - U32 mLastBitsIn; + U32Bits mBitsIn, + mLastBitsIn; U32 mLastPacketsIn; U32 mPacketsOut; U32 mLastPacketsOut; S32 mPacketsLost; S32 mLastPacketsLost; - U32 mPingDelay; + U32Milliseconds mPingDelay; F32 mDeltaTime; // Time since last measurement of lastPackets, Bits, etc U64 mRegionFlags; // includes damage flags U64 mRegionProtocols; // protocols supported by this region U8 mSimAccess; + U8 mLastSimAccess; // Singularity extension. + std::string mSimAccessString; // Singularity extension. F32 mBillableFactor; U32 mMaxTasks; // max prim count F32 mCameraDistanceSquared; // updated once per frame @@ -435,7 +482,7 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface std::string mColoName; std::string mProductSKU; std::string mProductName; - std::string mHttpUrl ; + std::string mViewerAssetUrl; // Maps local ids to cache entries. // Regions can have order 10,000 objects, so assume @@ -443,19 +490,26 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface BOOL mCacheLoaded; BOOL mCacheDirty; - LLDynamicArray mCacheMissFull; - LLDynamicArray mCacheMissCRC; + std::vector mCacheMissFull; + std::vector mCacheMissCRC; + +// [SL:KB] - Patch: World-MinimapOverlay | Checked: 2012-07-26 (Catznip-3.3) + mutable tex_matrix_t mWorldMapTiles; +// [/SL:KB] bool mAlive; // can become false if circuit disconnects bool mCapabilitiesReceived; - bool mFeaturesReceived; + bool mSimulatorFeaturesReceived; caps_received_signal_t mCapabilitiesReceivedSignal; - features_received_signal_t mFeaturesReceivedSignal; + caps_received_signal_t mSimulatorFeaturesReceivedSignal; BOOL mReleaseNotesRequested; LLSD mSimulatorFeatures; U32 mGamingFlags; + // the materials capability throttle + LLFrameTimer mMaterialsCapThrottleTimer; + LLFrameTimer mRenderInfoRequestTimer; }; inline BOOL LLViewerRegion::getRegionProtocol(U64 protocol) const diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp index b39fb6e1f0..f1fb1108a2 100644 --- a/indra/newview/llviewershadermgr.cpp +++ b/indra/newview/llviewershadermgr.cpp @@ -33,6 +33,7 @@ #include "llviewerprecompiledheaders.h" + #include "llfeaturemanager.h" #include "llviewershadermgr.h" @@ -46,6 +47,8 @@ #include "llsky.h" #include "llvosky.h" #include "llrender.h" +#include "lljoint.h" +#include "llskinningutil.h" #if LL_DARWIN #include "OpenGL/OpenGL.h" @@ -57,6 +60,13 @@ #define UNIFORM_ERRS LL_ERRS("Shader") #endif +static LLStaticHashedString sTexture0("texture0"); +static LLStaticHashedString sTexture1("texture1"); +static LLStaticHashedString sTex0("tex0"); +static LLStaticHashedString sTex1("tex1"); +static LLStaticHashedString sGlowMap("glowMap"); +static LLStaticHashedString sScreenMap("screenMap"); + // Lots of STL stuff in here, using namespace std to keep things more readable using std::vector; using std::pair; @@ -77,7 +87,7 @@ LLGLSLShader gTransformPositionProgram(LLViewerShaderMgr::SHADER_TRANSFORM); LLGLSLShader gTransformTexCoordProgram(LLViewerShaderMgr::SHADER_TRANSFORM); LLGLSLShader gTransformNormalProgram(LLViewerShaderMgr::SHADER_TRANSFORM); LLGLSLShader gTransformColorProgram(LLViewerShaderMgr::SHADER_TRANSFORM); -LLGLSLShader gTransformBinormalProgram(LLViewerShaderMgr::SHADER_TRANSFORM); +LLGLSLShader gTransformTangentProgram(LLViewerShaderMgr::SHADER_TRANSFORM); //utility shaders LLGLSLShader gOcclusionProgram(LLViewerShaderMgr::SHADER_INTERFACE); @@ -90,62 +100,27 @@ LLGLSLShader gTwoTextureAddProgram(LLViewerShaderMgr::SHADER_INTERFACE); LLGLSLShader gOneTextureNoColorProgram(LLViewerShaderMgr::SHADER_INTERFACE); LLGLSLShader gDebugProgram(LLViewerShaderMgr::SHADER_INTERFACE); LLGLSLShader gClipProgram(LLViewerShaderMgr::SHADER_INTERFACE); +LLGLSLShader gDownsampleDepthProgram(LLViewerShaderMgr::SHADER_INTERFACE); LLGLSLShader gAlphaMaskProgram(LLViewerShaderMgr::SHADER_INTERFACE); LLGLSLShader gUIProgram(LLViewerShaderMgr::SHADER_INTERFACE); LLGLSLShader gSolidColorProgram(LLViewerShaderMgr::SHADER_INTERFACE); //object shaders -LLGLSLShader gObjectSimpleProgram(LLViewerShaderMgr::SHADER_OBJECT); +LLGLSLShaderArray gObjectSimpleProgram[1< gObjectFullbrightProgram[1< gObjectEmissiveProgram[1< gDeferredMultiLightProgram[16]; LLGLSLShader gDeferredSpotLightProgram(LLViewerShaderMgr::SHADER_DEFERRED); //Not in mShaderList LLGLSLShader gDeferredMultiSpotLightProgram(LLViewerShaderMgr::SHADER_DEFERRED); //Not in mShaderList +LLGLSLShader gDeferredSSAOProgram(LLViewerShaderMgr::SHADER_DEFERRED); +LLGLSLShader gDeferredDownsampleDepthNearestProgram(LLViewerShaderMgr::SHADER_DEFERRED); LLGLSLShader gDeferredSunProgram(LLViewerShaderMgr::SHADER_DEFERRED); LLGLSLShader gDeferredBlurLightProgram(LLViewerShaderMgr::SHADER_DEFERRED); LLGLSLShader gDeferredSoftenProgram(LLViewerShaderMgr::SHADER_DEFERRED); +LLGLSLShader gDeferredSoftenWaterProgram(LLViewerShaderMgr::SHADER_DEFERRED); LLGLSLShader gDeferredShadowProgram(LLViewerShaderMgr::SHADER_DEFERRED); //Not in mShaderList LLGLSLShader gDeferredShadowCubeProgram(LLViewerShaderMgr::SHADER_DEFERRED); LLGLSLShader gDeferredShadowAlphaMaskProgram(LLViewerShaderMgr::SHADER_DEFERRED); LLGLSLShader gDeferredAvatarShadowProgram(LLViewerShaderMgr::SHADER_DEFERRED);//Not in mShaderList LLGLSLShader gDeferredAttachmentShadowProgram(LLViewerShaderMgr::SHADER_DEFERRED); LLGLSLShader gDeferredAlphaProgram(LLViewerShaderMgr::SHADER_DEFERRED); //calculatesAtmospherics +LLGLSLShader gDeferredAlphaImpostorProgram(LLViewerShaderMgr::SHADER_DEFERRED); +LLGLSLShader gDeferredAlphaWaterProgram(LLViewerShaderMgr::SHADER_DEFERRED); LLGLSLShader gDeferredFullbrightProgram(LLViewerShaderMgr::SHADER_DEFERRED); +LLGLSLShader gDeferredFullbrightAlphaMaskProgram(LLViewerShaderMgr::SHADER_DEFERRED); +LLGLSLShader gDeferredFullbrightWaterProgram(LLViewerShaderMgr::SHADER_DEFERRED); +LLGLSLShader gDeferredFullbrightAlphaMaskWaterProgram(LLViewerShaderMgr::SHADER_DEFERRED); LLGLSLShader gDeferredEmissiveProgram(LLViewerShaderMgr::SHADER_DEFERRED); LLGLSLShader gDeferredPostProgram(LLViewerShaderMgr::SHADER_DEFERRED); LLGLSLShader gDeferredCoFProgram(LLViewerShaderMgr::SHADER_DEFERRED); LLGLSLShader gDeferredDoFCombineProgram(LLViewerShaderMgr::SHADER_DEFERRED); +LLGLSLShader gDeferredPostGammaCorrectProgram(LLViewerShaderMgr::SHADER_DEFERRED); LLGLSLShader gFXAAProgram(LLViewerShaderMgr::SHADER_DEFERRED); LLGLSLShader gDeferredPostNoDoFProgram(LLViewerShaderMgr::SHADER_DEFERRED); LLGLSLShader gDeferredWLSkyProgram(LLViewerShaderMgr::SHADER_DEFERRED); LLGLSLShader gDeferredWLCloudProgram(LLViewerShaderMgr::SHADER_DEFERRED); LLGLSLShader gDeferredStarProgram(LLViewerShaderMgr::SHADER_DEFERRED); +LLGLSLShader gDeferredFullbrightShinyProgram(LLViewerShaderMgr::SHADER_DEFERRED); +LLGLSLShader gDeferredSkinnedFullbrightShinyProgram(LLViewerShaderMgr::SHADER_DEFERRED); +LLGLSLShader gDeferredSkinnedFullbrightProgram(LLViewerShaderMgr::SHADER_DEFERRED); LLGLSLShader gNormalMapGenProgram(LLViewerShaderMgr::SHADER_DEFERRED); +// Deferred materials shaders +LLGLSLShaderArray gDeferredMaterialProgram[LLMaterial::SHADER_COUNT*2]; +LLGLSLShaderArray gDeferredMaterialWaterProgram[LLMaterial::SHADER_COUNT*2]; + LLViewerShaderMgr::LLViewerShaderMgr() : - mVertexShaderLevel(SHADER_COUNT, 0), - mMaxAvatarShaderLevel(0) + mVertexShaderLevel(SHADER_COUNT, 0) {} LLViewerShaderMgr::~LLViewerShaderMgr() @@ -241,47 +231,6 @@ void LLViewerShaderMgr::initAttribsAndUniforms(void) if (mReservedAttribs.empty()) { LLShaderMgr::initAttribsAndUniforms(); - - mAvatarUniforms.push_back("matrixPalette"); - mAvatarUniforms.push_back("gWindDir"); - mAvatarUniforms.push_back("gSinWaveParams"); - mAvatarUniforms.push_back("gGravity"); - - mWLUniforms.push_back("camPosLocal"); - - mTerrainUniforms.reserve(5); - mTerrainUniforms.push_back("detail_0"); - mTerrainUniforms.push_back("detail_1"); - mTerrainUniforms.push_back("detail_2"); - mTerrainUniforms.push_back("detail_3"); - mTerrainUniforms.push_back("alpha_ramp"); - - mGlowUniforms.push_back("glowDelta"); - mGlowUniforms.push_back("glowStrength"); - - mGlowExtractUniforms.push_back("minLuminance"); - mGlowExtractUniforms.push_back("maxExtractAlpha"); - mGlowExtractUniforms.push_back("lumWeights"); - mGlowExtractUniforms.push_back("warmthWeights"); - mGlowExtractUniforms.push_back("warmthAmount"); - - mShinyUniforms.push_back("origin"); - - mWaterUniforms.reserve(12); - mWaterUniforms.push_back("screenTex"); - mWaterUniforms.push_back("screenDepth"); - mWaterUniforms.push_back("refTex"); - mWaterUniforms.push_back("eyeVec"); - mWaterUniforms.push_back("time"); - mWaterUniforms.push_back("d1"); - mWaterUniforms.push_back("d2"); - mWaterUniforms.push_back("lightDir"); - mWaterUniforms.push_back("specular"); - mWaterUniforms.push_back("lightExp"); - mWaterUniforms.push_back("fogCol"); - mWaterUniforms.push_back("kd"); - mWaterUniforms.push_back("refScale"); - mWaterUniforms.push_back("waterHeight"); } } @@ -291,7 +240,7 @@ void LLViewerShaderMgr::initAttribsAndUniforms(void) S32 LLViewerShaderMgr::getVertexShaderLevel(S32 type) { - return LLPipeline::sDisableShaders ? 0 : mVertexShaderLevel[type]; + return mVertexShaderLevel[type]; } //============================================================================ @@ -307,6 +256,10 @@ void LLViewerShaderMgr::setShaders() return; } + //Since setShaders can be reentrant, be sure to clear out stale shader objects that may be left over from parent call. + unloadShaderObjects(); + unloadShaders(); + LLGLSLShader::sIndexedTextureChannels = llmax(llmin(gGLManager.mNumTextureImageUnits, (S32) gSavedSettings.getU32("RenderMaxTextureIndex")), 1); static const LLCachedControl no_texture_indexing("ShyotlUseLegacyTextureBatching",false); if(no_texture_indexing) @@ -331,24 +284,19 @@ void LLViewerShaderMgr::setShaders() } } - //setup preprocessor definitions - LLShaderMgr::instance()->mDefinitions.clear(); - LLShaderMgr::instance()->mDefinitions["samples"] = llformat("%d", gSavedSettings.getU32("RenderFSAASamples")); - LLShaderMgr::instance()->mDefinitions["NUM_TEX_UNITS"] = llformat("%d", gGLManager.mNumTextureImageUnits); - initAttribsAndUniforms(); gPipeline.releaseGLBuffers(); - if (gSavedSettings.getBOOL("VertexShaderEnable")) - { - LLPipeline::sWaterReflections = gGLManager.mHasCubeMap; - LLPipeline::sRenderGlow = gSavedSettings.getBOOL("RenderGlow"); - LLPipeline::updateRenderDeferred(); - } - else + bool want_shaders = LLFeatureManager::getInstance()->isFeatureAvailable("VertexShaderEnable") && + gSavedSettings.getBOOL("VertexShaderEnable") && + (gGLManager.mGLSLVersionMajor > 1 || gGLManager.mGLSLVersionMinor >= 10); + + bool want_deferred = want_shaders && LLPipeline::isRenderDeferredDesired(); + + if (want_shaders) { - LLPipeline::sRenderGlow = FALSE; - LLPipeline::sWaterReflections = FALSE; + //sRenderGlow needs set as it's referenced in the shader load process. + LLPipeline::sRenderGlow = want_deferred || gSavedSettings.getBOOL("RenderGlow"); } //hack to reset buffers that change behavior with shaders @@ -360,26 +308,16 @@ void LLViewerShaderMgr::setShaders() } // Lighting - gPipeline.setLightingDetail(-1); + gPipeline.updateLocalLightingEnabled(); // Shaders LL_INFOS("ShaderLoading") << "\n~~~~~~~~~~~~~~~~~~\n Loading Shaders:\n~~~~~~~~~~~~~~~~~~" << LL_ENDL; - LL_INFOS("ShaderLoading") << llformat("Using GLSL %d.%d", gGLManager.mGLSLVersionMajor, gGLManager.mGLSLVersionMinor) << llendl; + LL_INFOS("ShaderLoading") << llformat("Using GLSL %d.%d", gGLManager.mGLSLVersionMajor, gGLManager.mGLSLVersionMinor) << LL_ENDL; - for (S32 i = 0; i < SHADER_COUNT; i++) - { - mVertexShaderLevel[i] = 0; - } - mMaxAvatarShaderLevel = 0; - - LLGLSLShader::sNoFixedFunction = false; LLVertexBuffer::unbind(); - if (LLFeatureManager::getInstance()->isFeatureAvailable("VertexShaderEnable") - && (gGLManager.mGLSLVersionMajor > 1 || gGLManager.mGLSLVersionMinor >= 10) - && gSavedSettings.getBOOL("VertexShaderEnable")) + + if (want_shaders) { - //using shaders, disable fixed function - LLGLSLShader::sNoFixedFunction = true; S32 light_class = 2; S32 env_class = 2; S32 obj_class = 2; @@ -389,10 +327,13 @@ void LLViewerShaderMgr::setShaders() S32 deferred_class = 0; S32 transform_class = gGLManager.mHasTransformFeedback ? 1 : 0; - if (LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") && - gSavedSettings.getBOOL("RenderDeferred") && - gSavedSettings.getBOOL("RenderAvatarVP") && - gSavedSettings.getBOOL("WindLightUseAtmosShaders")) + static LLCachedControl use_transform_feedback(gSavedSettings, "RenderUseTransformFeedback"); + if (!use_transform_feedback) + { + transform_class = 0; + } + + if (want_deferred) { if (gSavedSettings.getS32("RenderShadowDetail") > 0) { //shadows @@ -441,9 +382,6 @@ void LLViewerShaderMgr::setShaders() if (loaded) { - gPipeline.mVertexShadersEnabled = TRUE; - gPipeline.mVertexShadersLoaded = 1; - // Load all shaders to set max levels loaded = loadShadersEnvironment(); @@ -469,75 +407,58 @@ void LLViewerShaderMgr::setShaders() if (loaded) { - loaded = loadTransformShaders(); - if(!loaded) //Failed to load. Just wipe all transformfeedback shaders and continue like nothing happened. - { - mVertexShaderLevel[SHADER_TRANSFORM] = 0; - unloadShaderClass(SHADER_TRANSFORM); - loaded = true; - } + loadTransformShaders(); } if (loaded) { // Load max avatar shaders to set the max level - mVertexShaderLevel[SHADER_AVATAR] = 3; - mMaxAvatarShaderLevel = 3; + bool can_skin = want_deferred || (LLFeatureManager::getInstance()->isFeatureAvailable("RenderAvatarVP") && gSavedSettings.getBOOL("RenderAvatarVP")); - if (gSavedSettings.getBOOL("RenderAvatarVP") && loadShadersObject()) + if (can_skin) { //hardware skinning is enabled and rigged attachment shaders loaded correctly - BOOL avatar_cloth = gSavedSettings.getBOOL("RenderAvatarCloth"); - S32 avatar_class = 1; - - // cloth is a class3 shader - if(avatar_cloth) - { - avatar_class = 3; - } // Set the actual level - mVertexShaderLevel[SHADER_AVATAR] = avatar_class; - loadShadersAvatar(); - if (mVertexShaderLevel[SHADER_AVATAR] != avatar_class) + mVertexShaderLevel[SHADER_AVATAR] = gSavedSettings.getBOOL("RenderAvatarCloth") ? 3 : 1; + + if(!loadShadersAvatar() || !loadShadersObject()) { - if (mVertexShaderLevel[SHADER_AVATAR] == 0) - { - gSavedSettings.setBOOL("RenderAvatarVP", FALSE); - } - if(llmax(mVertexShaderLevel[SHADER_AVATAR]-1,0) >= 3) - { - avatar_cloth = true; - } - else - { - avatar_cloth = false; - } - gSavedSettings.setBOOL("RenderAvatarCloth", avatar_cloth); + can_skin = false; + } + else if (mVertexShaderLevel[SHADER_AVATAR] < 3) + { + gSavedSettings.setBOOL("RenderAvatarCloth", false); } } - else + + if (!can_skin) { //hardware skinning not possible, neither is deferred rendering - mVertexShaderLevel[SHADER_AVATAR] = 0; mVertexShaderLevel[SHADER_DEFERRED] = 0; + mVertexShaderLevel[SHADER_AVATAR] = 0; + unloadShaderClass(SHADER_AVATAR); + unloadShaderClass(SHADER_OBJECT); - if (gSavedSettings.getBOOL("RenderAvatarVP")) - { - gSavedSettings.setBOOL("RenderDeferred", FALSE); - gSavedSettings.setBOOL("RenderAvatarCloth", FALSE); - gSavedSettings.setBOOL("RenderAvatarVP", FALSE); - } + want_deferred = false; //Deferred requires skinned shaders. - loadShadersAvatar(); // unloads + gSavedSettings.setBOOL("RenderDeferred", FALSE); + gSavedSettings.setBOOL("RenderAvatarCloth", FALSE); + gSavedSettings.setBOOL("RenderAvatarVP", FALSE); loaded = loadShadersObject(); } } + if (loaded) + { + loaded = loadShadersInterface(); + } + if (!loaded) { //some shader absolutely could not load, try to fall back to a simpler setting if (gSavedSettings.getBOOL("WindLightUseAtmosShaders")) { //disable windlight and try again gSavedSettings.setBOOL("WindLightUseAtmosShaders", FALSE); + gSavedSettings.setBOOL("RenderDeferred", FALSE); reentrance = false; setShaders(); return; @@ -546,46 +467,39 @@ void LLViewerShaderMgr::setShaders() if (gSavedSettings.getBOOL("VertexShaderEnable")) { //disable shaders outright and try again gSavedSettings.setBOOL("VertexShaderEnable", FALSE); + gSavedSettings.setBOOL("RenderDeferred", FALSE); reentrance = false; setShaders(); return; } - } - - if (loaded && !loadShadersDeferred()) - { //everything else succeeded but deferred failed, disable deferred and try again + } + else if (!loadShadersDeferred()) + { gSavedSettings.setBOOL("RenderDeferred", FALSE); reentrance = false; setShaders(); return; } } - else + if (!loaded) { - LLGLSLShader::sNoFixedFunction = false; - gPipeline.mVertexShadersEnabled = FALSE; - gPipeline.mVertexShadersLoaded = 0; - for (S32 i = 0; i < SHADER_COUNT; i++) - mVertexShaderLevel[i] = 0; + llassert_always(!LLRender::sGLCoreProfile); //This is bad... + unloadShaders(); + } + else //Shaders loaded + { + //using shaders, disable fixed function + LLGLSLShader::sNoFixedFunction = true; + LLPipeline::sWaterReflections = gGLManager.mHasCubeMap; + LLPipeline::sRenderDeferred = want_deferred; } //Flag base shader objects for deletion //Don't worry-- they won't be deleted until no programs refrence them. - std::multimap::iterator it = mShaderObjects.begin(); - for(; it!=mShaderObjects.end();++it) - if(it->second.mHandle) - glDeleteObjectARB(it->second.mHandle); - mShaderObjects.clear(); + unloadShaderObjects(); + cleanupShaderSources(); } - else - { - LLGLSLShader::sNoFixedFunction = false; - gPipeline.mVertexShadersEnabled = FALSE; - gPipeline.mVertexShadersLoaded = 0; - for (S32 i = 0; i < SHADER_COUNT; i++) - mVertexShaderLevel[i] = 0; - } - + if (gViewerWindow) { gViewerWindow->setCursor(UI_CURSOR_ARROW); @@ -602,16 +516,20 @@ void LLViewerShaderMgr::setShaders() void LLViewerShaderMgr::unloadShaders() { - //Instead of manually unloading, shaders are now automatically accumulated in a list. - //Simply iterate and unload. - std::vector &shader_list = LLShaderMgr::getGlobalShaderList(); - for(std::vector::iterator it=shader_list.begin();it!=shader_list.end();++it) - (*it)->unload(); + LLShaderMgr::unloadShaders(); for (S32 i = 0; i < SHADER_COUNT; i++) mVertexShaderLevel[i] = 0; - gPipeline.mVertexShadersLoaded = 0; + //Unset all shader-dependent static variables. + LLGLSLShader::sNoFixedFunction = LLRender::sGLCoreProfile; + LLGLSLShader::sIndexedTextureChannels = 1; + LLPipeline::sRenderDeferred = false; + LLPipeline::sWaterReflections = FALSE; + LLPipeline::sRenderGlow = FALSE; + + // Clear sync hashes. If shaders were just turned off then glLight state needs to be resynced. + gGL.resetSyncHashes(); } BOOL LLViewerShaderMgr::loadBasicShaders() @@ -619,9 +537,6 @@ BOOL LLViewerShaderMgr::loadBasicShaders() // Load basic dependency shaders first // All of these have to load for any shaders to function -#if LL_DARWIN // Mac can't currently handle all 8 lights, - S32 sum_lights_class = 2; -#else S32 sum_lights_class = 3; // class one cards will get the lower sum lights @@ -632,14 +547,21 @@ BOOL LLViewerShaderMgr::loadBasicShaders() { sum_lights_class = 2; } -#endif // If we have sun and moon only checked, then only sum those lights. - if (gPipeline.getLightingDetail() == 0) + if (!gPipeline.isLocalLightingEnabled()) { sum_lights_class = 1; } +#if LL_DARWIN + // Work around driver crashes on older Macs when using deferred rendering + // NORSPEC-59 + // + if (gGLManager.mIsMobileGF) + sum_lights_class = 3; +#endif + // Use the feature table to mask out the max light level to use. Also make sure it's at least 1. S32 max_light_class = gSavedSettings.getS32("RenderShaderLightingMaxLevel"); sum_lights_class = llclamp(sum_lights_class, 1, max_light_class); @@ -666,11 +588,15 @@ BOOL LLViewerShaderMgr::loadBasicShaders() } shaders.push_back( make_pair( "objects/nonindexedTextureV.glsl", 1 ) ); + std::map attribs; + attribs["MAX_JOINTS_PER_MESH_OBJECT"] = + fmt::to_string(LLSkinningUtil::getMaxJointCount()); + // We no longer have to bind the shaders to global glhandles, they are automatically added to a map now. for (U32 i = 0; i < shaders.size(); i++) { // Note usage of GL_VERTEX_SHADER_ARB - if (loadShaderFile(shaders[i].first, shaders[i].second, GL_VERTEX_SHADER_ARB) == 0) + if (loadShaderFile(shaders[i].first, shaders[i].second, GL_VERTEX_SHADER_ARB, &attribs) == 0) { return FALSE; } @@ -680,14 +606,7 @@ BOOL LLViewerShaderMgr::loadBasicShaders() // (in order of shader function call depth for reference purposes, deepest level first) shaders.clear(); - S32 ch = 1; - - if (gGLManager.mGLSLVersionMajor > 1 || gGLManager.mGLSLVersionMinor >= 30) - { //use indexed texture rendering for GLSL >= 1.30 - static const LLCachedControl no_texture_indexing("ShyotlUseLegacyTextureBatching",false); - if(!no_texture_indexing) - ch = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1); - } + S32 ch = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1); std::vector index_channels; index_channels.push_back(-1); shaders.push_back( make_pair( "windlight/atmosphericsVarsF.glsl", mVertexShaderLevel[SHADER_WINDLIGHT] ) ); @@ -724,7 +643,7 @@ BOOL LLViewerShaderMgr::loadBasicShaders() for (U32 i = 0; i < shaders.size(); i++) { // Note usage of GL_FRAGMENT_SHADER_ARB - if (loadShaderFile(shaders[i].first, shaders[i].second, GL_FRAGMENT_SHADER_ARB, index_channels[i]) == 0) + if (loadShaderFile(shaders[i].first, shaders[i].second, GL_FRAGMENT_SHADER_ARB, &attribs, index_channels[i]) == 0) { return FALSE; } @@ -756,24 +675,25 @@ BOOL LLViewerShaderMgr::loadShadersEnvironment() gTerrainProgram.mShaderFiles.push_back(make_pair("environment/terrainV.glsl", GL_VERTEX_SHADER_ARB)); gTerrainProgram.mShaderFiles.push_back(make_pair("environment/terrainF.glsl", GL_FRAGMENT_SHADER_ARB)); gTerrainProgram.mShaderLevel = mVertexShaderLevel[SHADER_ENVIRONMENT]; - success = gTerrainProgram.createShader(NULL, &mTerrainUniforms); + success = gTerrainProgram.createShader(NULL, NULL); } if (!success) { mVertexShaderLevel[SHADER_ENVIRONMENT] = 0; - return FALSE; + unloadShaderClass(SHADER_ENVIRONMENT); + } + else + { + LLWorld::getInstance()->updateWaterObjects(); } - LLWorld::getInstance()->updateWaterObjects(); - - return TRUE; + return success; } BOOL LLViewerShaderMgr::loadShadersWater() { BOOL success = TRUE; - BOOL terrainWaterSuccess = TRUE; if (mVertexShaderLevel[SHADER_WATER] == 0) { @@ -792,7 +712,7 @@ BOOL LLViewerShaderMgr::loadShadersWater() gWaterProgram.mShaderFiles.push_back(make_pair("environment/waterV.glsl", GL_VERTEX_SHADER_ARB)); gWaterProgram.mShaderFiles.push_back(make_pair("environment/waterF.glsl", GL_FRAGMENT_SHADER_ARB)); gWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_WATER]; - success = gWaterProgram.createShader(NULL, &mWaterUniforms); + success = gWaterProgram.createShader(NULL, NULL); } if (success) @@ -806,7 +726,7 @@ BOOL LLViewerShaderMgr::loadShadersWater() gUnderWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_WATER]; gUnderWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; - success = gUnderWaterProgram.createShader(NULL, &mWaterUniforms); + success = gUnderWaterProgram.createShader(NULL, NULL); } if (success) @@ -824,33 +744,20 @@ BOOL LLViewerShaderMgr::loadShadersWater() gTerrainWaterProgram.mShaderFiles.push_back(make_pair("environment/terrainWaterF.glsl", GL_FRAGMENT_SHADER_ARB)); gTerrainWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_ENVIRONMENT]; gTerrainWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; - terrainWaterSuccess = gTerrainWaterProgram.createShader(NULL, &mTerrainUniforms); - } - - /// Keep track of water shader levels - if (gWaterProgram.mShaderLevel != mVertexShaderLevel[SHADER_WATER] - || gUnderWaterProgram.mShaderLevel != mVertexShaderLevel[SHADER_WATER]) - { - mVertexShaderLevel[SHADER_WATER] = llmin(gWaterProgram.mShaderLevel, gUnderWaterProgram.mShaderLevel); + success = gTerrainWaterProgram.createShader(NULL, NULL); } if (!success) { mVertexShaderLevel[SHADER_WATER] = 0; - return FALSE; + unloadShaderClass(SHADER_WATER); } - - // if we failed to load the terrain water shaders and we need them (using class2 water), - // then drop down to class1 water. - if (mVertexShaderLevel[SHADER_WATER] > 1 && !terrainWaterSuccess) + else { - mVertexShaderLevel[SHADER_WATER]--; - return loadShadersWater(); + LLWorld::getInstance()->updateWaterObjects(); } - - LLWorld::getInstance()->updateWaterObjects(); - return TRUE; + return success; } BOOL LLViewerShaderMgr::loadShadersEffects() @@ -872,7 +779,7 @@ BOOL LLViewerShaderMgr::loadShadersEffects() gGlowProgram.mShaderFiles.push_back(make_pair("effects/glowV.glsl", GL_VERTEX_SHADER_ARB)); gGlowProgram.mShaderFiles.push_back(make_pair("effects/glowF.glsl", GL_FRAGMENT_SHADER_ARB)); gGlowProgram.mShaderLevel = mVertexShaderLevel[SHADER_EFFECT]; - success = gGlowProgram.createShader(NULL, &mGlowUniforms); + success = gGlowProgram.createShader(NULL, NULL); LLPipeline::sRenderGlow = success; } @@ -883,7 +790,7 @@ BOOL LLViewerShaderMgr::loadShadersEffects() gGlowExtractProgram.mShaderFiles.push_back(make_pair("effects/glowExtractV.glsl", GL_VERTEX_SHADER_ARB)); gGlowExtractProgram.mShaderFiles.push_back(make_pair("effects/glowExtractF.glsl", GL_FRAGMENT_SHADER_ARB)); gGlowExtractProgram.mShaderLevel = mVertexShaderLevel[SHADER_EFFECT]; - success = gGlowExtractProgram.createShader(NULL, &mGlowExtractUniforms); + success = gGlowExtractProgram.createShader(NULL, NULL); LLPipeline::sRenderGlow = success; } } @@ -895,13 +802,16 @@ BOOL LLViewerShaderMgr::loadShadersEffects() //load Color Filter Shader //if (success) { - vector shaderUniforms; - shaderUniforms.reserve(6); - shaderUniforms.push_back("gamma"); - shaderUniforms.push_back("brightness"); - shaderUniforms.push_back("contrast"); - shaderUniforms.push_back("contrastBase"); - shaderUniforms.push_back("saturation"); + static std::vector shaderUniforms; + if(shaderUniforms.empty()) + { + shaderUniforms.reserve(6); + shaderUniforms.push_back(LLStaticHashedString("gamma")); + shaderUniforms.push_back(LLStaticHashedString("brightness")); + shaderUniforms.push_back(LLStaticHashedString("contrast")); + shaderUniforms.push_back(LLStaticHashedString("contrastBase")); + shaderUniforms.push_back(LLStaticHashedString("saturation")); + } gPostColorFilterProgram.mName = "Color Filter Shader (Post)"; gPostColorFilterProgram.mShaderFiles.clear(); @@ -911,18 +821,20 @@ BOOL LLViewerShaderMgr::loadShadersEffects() if(gPostColorFilterProgram.createShader(NULL, &shaderUniforms)) { gPostColorFilterProgram.bind(); - gPostColorFilterProgram.uniform1i("tex0", 0); + gPostColorFilterProgram.uniform1i(sTex0, 0); } } //load Night Vision Shader //if (success) { - vector shaderUniforms; - shaderUniforms.reserve(3); - shaderUniforms.push_back("brightMult"); - shaderUniforms.push_back("noiseStrength"); - + static std::vector shaderUniforms; + if(shaderUniforms.empty()) + { + shaderUniforms.reserve(3); + shaderUniforms.push_back(LLStaticHashedString("brightMult")); + shaderUniforms.push_back(LLStaticHashedString("noiseStrength")); + } gPostNightVisionProgram.mName = "Night Vision Shader (Post)"; gPostNightVisionProgram.mShaderFiles.clear(); gPostNightVisionProgram.mShaderFiles.push_back(make_pair("effects/nightVisionF.glsl", GL_FRAGMENT_SHADER_ARB)); @@ -931,16 +843,19 @@ BOOL LLViewerShaderMgr::loadShadersEffects() if(gPostNightVisionProgram.createShader(NULL, &shaderUniforms)) { gPostNightVisionProgram.bind(); - gPostNightVisionProgram.uniform1i("tex0", 0); - gPostNightVisionProgram.uniform1i("tex1", 1); + gPostNightVisionProgram.uniform1i(sTex0, 0); + gPostNightVisionProgram.uniform1i(sTex1, 1); } } //if (success) { - vector shaderUniforms; - shaderUniforms.reserve(1); - shaderUniforms.push_back("horizontalPass"); + static std::vector shaderUniforms; + if(shaderUniforms.empty()) + { + shaderUniforms.reserve(1); + shaderUniforms.push_back(LLStaticHashedString("horizontalPass")); + } gPostGaussianBlurProgram.mName = "Gaussian Blur Shader (Post)"; gPostGaussianBlurProgram.mShaderFiles.clear(); @@ -950,14 +865,17 @@ BOOL LLViewerShaderMgr::loadShadersEffects() if(gPostGaussianBlurProgram.createShader(NULL, &shaderUniforms)) { gPostGaussianBlurProgram.bind(); - gPostGaussianBlurProgram.uniform1i("tex0", 0); + gPostGaussianBlurProgram.uniform1i(sTex0, 0); } } { - vector shaderUniforms; - shaderUniforms.reserve(1); - shaderUniforms.push_back("layerCount"); + static std::vector shaderUniforms; + if(shaderUniforms.empty()) + { + shaderUniforms.reserve(1); + shaderUniforms.push_back(LLStaticHashedString("layerCount")); + } gPostPosterizeProgram.mName = "Posterize Shader (Post)"; gPostPosterizeProgram.mShaderFiles.clear(); @@ -967,16 +885,18 @@ BOOL LLViewerShaderMgr::loadShadersEffects() if(gPostPosterizeProgram.createShader(NULL, &shaderUniforms)) { gPostPosterizeProgram.bind(); - gPostPosterizeProgram.uniform1i("tex0", 0); + gPostPosterizeProgram.uniform1i(sTex0, 0); } } { - vector shaderUniforms; - shaderUniforms.reserve(3); - shaderUniforms.push_back("inv_proj"); - shaderUniforms.push_back("prev_proj"); - shaderUniforms.push_back("screen_res"); + static std::vector shaderUniforms; + if(shaderUniforms.empty()) + { + shaderUniforms.reserve(3); + shaderUniforms.push_back(LLStaticHashedString("inv_proj")); + shaderUniforms.push_back(LLStaticHashedString("prev_proj")); + } gPostMotionBlurProgram.mName = "Motion Blur Shader (Post)"; gPostMotionBlurProgram.mShaderFiles.clear(); @@ -986,17 +906,19 @@ BOOL LLViewerShaderMgr::loadShadersEffects() if(gPostMotionBlurProgram.createShader(NULL, &shaderUniforms)) { gPostMotionBlurProgram.bind(); - gPostMotionBlurProgram.uniform1i("tex0", 0); - gPostMotionBlurProgram.uniform1i("tex1", 1); + gPostMotionBlurProgram.uniform1i(sTex0, 0); + gPostMotionBlurProgram.uniform1i(sTex1, 1); } } { - vector shaderUniforms; - shaderUniforms.reserve(3); - shaderUniforms.push_back("vignette_darkness"); - shaderUniforms.push_back("vignette_radius"); - shaderUniforms.push_back("screen_res"); + static std::vector shaderUniforms; + if(shaderUniforms.empty()) + { + shaderUniforms.reserve(3); + shaderUniforms.push_back(LLStaticHashedString("vignette_darkness")); + shaderUniforms.push_back(LLStaticHashedString("vignette_radius")); + } gPostVignetteProgram.mName = "Vignette Shader (Post)"; gPostVignetteProgram.mShaderFiles.clear(); @@ -1006,12 +928,18 @@ BOOL LLViewerShaderMgr::loadShadersEffects() if(gPostVignetteProgram.createShader(NULL, &shaderUniforms)) { gPostVignetteProgram.bind(); - gPostVignetteProgram.uniform1i("tex0", 0); + gPostVignetteProgram.uniform1i(sTex0, 0); } } #endif + if (!success) + { + mVertexShaderLevel[SHADER_EFFECT] = 0; + unloadShaderClass(SHADER_EFFECT); + } + return success; } @@ -1026,6 +954,8 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() BOOL success = TRUE; + success = loadShaderFile("deferred/components/utilityFuncF.glsl", mVertexShaderLevel[SHADER_DEFERRED], GL_FRAGMENT_SHADER_ARB); + if (success) { gDeferredDiffuseProgram.mName = "Deferred Diffuse Shader"; @@ -1050,7 +980,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() if (success) { - gDeferredNonIndexedDiffuseAlphaMaskProgram.mName = "Deferred Diffuse Non-Indexed Alpha Mask Shader"; + gDeferredNonIndexedDiffuseAlphaMaskProgram.mName = "Deferred Diffuse Non-Indexed Alpha Mask Colored Shader"; gDeferredNonIndexedDiffuseAlphaMaskProgram.mShaderFiles.clear(); gDeferredNonIndexedDiffuseAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/diffuseV.glsl", GL_VERTEX_SHADER_ARB)); gDeferredNonIndexedDiffuseAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/diffuseAlphaMaskF.glsl", GL_FRAGMENT_SHADER_ARB)); @@ -1068,7 +998,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() success = gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram.createShader(NULL, NULL); } - if (success) + /*if (success) { gDeferredNonIndexedDiffuseProgram.mName = "Non Indexed Deferred Diffuse Shader"; gDeferredNonIndexedDiffuseProgram.mShaderFiles.clear(); @@ -1076,7 +1006,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredNonIndexedDiffuseProgram.mShaderFiles.push_back(make_pair("deferred/diffuseF.glsl", GL_FRAGMENT_SHADER_ARB)); gDeferredNonIndexedDiffuseProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; success = gDeferredNonIndexedDiffuseProgram.createShader(NULL, NULL); - } + }*/ if (success) @@ -1104,20 +1034,19 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() if (success) { gDeferredSkinnedAlphaProgram.mName = "Deferred Skinned Alpha Shader"; - gDeferredSkinnedAlphaProgram.mFeatures.atmosphericHelpers = true; gDeferredSkinnedAlphaProgram.mFeatures.hasObjectSkinning = true; - gDeferredSkinnedAlphaProgram.mFeatures.calculatesAtmospherics = true; - gDeferredSkinnedAlphaProgram.mFeatures.hasGamma = true; - gDeferredSkinnedAlphaProgram.mFeatures.hasAtmospherics = true; gDeferredSkinnedAlphaProgram.mFeatures.calculatesLighting = false; gDeferredSkinnedAlphaProgram.mFeatures.hasLighting = false; gDeferredSkinnedAlphaProgram.mFeatures.isAlphaLighting = true; gDeferredSkinnedAlphaProgram.mFeatures.disableTextureIndex = true; gDeferredSkinnedAlphaProgram.mShaderFiles.clear(); - gDeferredSkinnedAlphaProgram.mShaderFiles.push_back(make_pair("deferred/alphaSkinnedV.glsl", GL_VERTEX_SHADER_ARB)); - gDeferredSkinnedAlphaProgram.mShaderFiles.push_back(make_pair("deferred/alphaNonIndexedF.glsl", GL_FRAGMENT_SHADER_ARB)); + gDeferredSkinnedAlphaProgram.mShaderFiles.push_back(make_pair("deferred/alphaV.glsl", GL_VERTEX_SHADER_ARB)); + gDeferredSkinnedAlphaProgram.mShaderFiles.push_back(make_pair("deferred/alphaF.glsl", GL_FRAGMENT_SHADER_ARB)); gDeferredSkinnedAlphaProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; - + gDeferredSkinnedAlphaProgram.addPermutation("USE_DIFFUSE_TEX", "1"); + gDeferredSkinnedAlphaProgram.addPermutation("HAS_SKIN", "1"); + gDeferredSkinnedAlphaProgram.addPermutation("USE_VERTEX_COLOR", "1"); + gDeferredSkinnedAlphaProgram.addPermutation("HAS_SHADOW", mVertexShaderLevel[SHADER_DEFERRED] > 1 ? "1" : "0"); success = gDeferredSkinnedAlphaProgram.createShader(NULL, NULL); // Hack to include uniforms for lighting without linking in lighting file @@ -1134,7 +1063,100 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredBumpProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; success = gDeferredBumpProgram.createShader(NULL, NULL); } + + gDeferredMaterialProgram[1].mFeatures.hasLighting = false; + gDeferredMaterialProgram[5].mFeatures.hasLighting = false; + gDeferredMaterialProgram[9].mFeatures.hasLighting = false; + gDeferredMaterialProgram[13].mFeatures.hasLighting = false; + gDeferredMaterialProgram[1+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = false; + gDeferredMaterialProgram[5+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = false; + gDeferredMaterialProgram[9+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = false; + gDeferredMaterialProgram[13+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = false; + + gDeferredMaterialWaterProgram[1].mFeatures.hasLighting = false; + gDeferredMaterialWaterProgram[5].mFeatures.hasLighting = false; + gDeferredMaterialWaterProgram[9].mFeatures.hasLighting = false; + gDeferredMaterialWaterProgram[13].mFeatures.hasLighting = false; + gDeferredMaterialWaterProgram[1+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = false; + gDeferredMaterialWaterProgram[5+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = false; + gDeferredMaterialWaterProgram[9+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = false; + gDeferredMaterialWaterProgram[13+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = false; + + for (U32 i = 0; i < LLMaterial::SHADER_COUNT*2; ++i) + { + if (success) + { + gDeferredMaterialProgram[i].mName = llformat("Deferred Material Shader %d", i); + + U32 alpha_mode = i & 0x3; + + gDeferredMaterialProgram[i].mShaderFiles.clear(); + gDeferredMaterialProgram[i].mShaderFiles.push_back(make_pair("deferred/materialV.glsl", GL_VERTEX_SHADER_ARB)); + gDeferredMaterialProgram[i].mShaderFiles.push_back(make_pair("deferred/materialF.glsl", GL_FRAGMENT_SHADER_ARB)); + gDeferredMaterialProgram[i].mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + gDeferredMaterialProgram[i].addPermutation("HAS_NORMAL_MAP", i & 0x8? "1" : "0"); + gDeferredMaterialProgram[i].addPermutation("HAS_SPECULAR_MAP", i & 0x4 ? "1" : "0"); + gDeferredMaterialProgram[i].addPermutation("DIFFUSE_ALPHA_MODE", llformat("%d", alpha_mode)); + gDeferredMaterialProgram[i].addPermutation("HAS_SUN_SHADOW", mVertexShaderLevel[SHADER_DEFERRED] > 1 ? "1" : "0"); + bool has_skin = i & 0x10; + gDeferredMaterialProgram[i].addPermutation("HAS_SKIN",has_skin ? "1" : "0"); + + if (has_skin) + { + gDeferredMaterialProgram[i].mFeatures.hasObjectSkinning = true; + } + success = gDeferredMaterialProgram[i].createShader(NULL, NULL); + } + + if (success) + { + gDeferredMaterialWaterProgram[i].mName = llformat("Deferred Underwater Material Shader %d", i); + + U32 alpha_mode = i & 0x3; + + gDeferredMaterialWaterProgram[i].mShaderFiles.clear(); + gDeferredMaterialWaterProgram[i].mShaderFiles.push_back(make_pair("deferred/materialV.glsl", GL_VERTEX_SHADER_ARB)); + gDeferredMaterialWaterProgram[i].mShaderFiles.push_back(make_pair("deferred/materialF.glsl", GL_FRAGMENT_SHADER_ARB)); + gDeferredMaterialWaterProgram[i].mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + gDeferredMaterialWaterProgram[i].mShaderGroup = LLGLSLShader::SG_WATER; + + gDeferredMaterialWaterProgram[i].addPermutation("HAS_NORMAL_MAP", i & 0x8? "1" : "0"); + gDeferredMaterialWaterProgram[i].addPermutation("HAS_SPECULAR_MAP", i & 0x4 ? "1" : "0"); + gDeferredMaterialWaterProgram[i].addPermutation("DIFFUSE_ALPHA_MODE", llformat("%d", alpha_mode)); + gDeferredMaterialWaterProgram[i].addPermutation("HAS_SUN_SHADOW", mVertexShaderLevel[SHADER_DEFERRED] > 1 ? "1" : "0"); + bool has_skin = i & 0x10; + gDeferredMaterialWaterProgram[i].addPermutation("HAS_SKIN",has_skin ? "1" : "0"); + gDeferredMaterialWaterProgram[i].addPermutation("WATER_FOG","1"); + + if (has_skin) + { + gDeferredMaterialWaterProgram[i].mFeatures.hasObjectSkinning = true; + } + + success = gDeferredMaterialWaterProgram[i].createShader(NULL, NULL);//&mWLUniforms); + } + } + + gDeferredMaterialProgram[1].mFeatures.hasLighting = true; + gDeferredMaterialProgram[5].mFeatures.hasLighting = true; + gDeferredMaterialProgram[9].mFeatures.hasLighting = true; + gDeferredMaterialProgram[13].mFeatures.hasLighting = true; + gDeferredMaterialProgram[1+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = true; + gDeferredMaterialProgram[5+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = true; + gDeferredMaterialProgram[9+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = true; + gDeferredMaterialProgram[13+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = true; + + gDeferredMaterialWaterProgram[1].mFeatures.hasLighting = true; + gDeferredMaterialWaterProgram[5].mFeatures.hasLighting = true; + gDeferredMaterialWaterProgram[9].mFeatures.hasLighting = true; + gDeferredMaterialWaterProgram[13].mFeatures.hasLighting = true; + gDeferredMaterialWaterProgram[1+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = true; + gDeferredMaterialWaterProgram[5+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = true; + gDeferredMaterialWaterProgram[9+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = true; + gDeferredMaterialWaterProgram[13+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = true; + + if (success) { gDeferredTreeProgram.mName = "Deferred Tree Shader"; @@ -1172,17 +1194,22 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredLightProgram.mShaderFiles.push_back(make_pair("deferred/pointLightV.glsl", GL_VERTEX_SHADER_ARB)); gDeferredLightProgram.mShaderFiles.push_back(make_pair("deferred/pointLightF.glsl", GL_FRAGMENT_SHADER_ARB)); gDeferredLightProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + success = gDeferredLightProgram.createShader(NULL, NULL); } + for (U32 i = 0; i < LL_DEFERRED_MULTI_LIGHT_COUNT; i++) + { if (success) { - gDeferredMultiLightProgram.mName = "Deferred MultiLight Shader"; - gDeferredMultiLightProgram.mShaderFiles.clear(); - gDeferredMultiLightProgram.mShaderFiles.push_back(make_pair("deferred/multiPointLightV.glsl", GL_VERTEX_SHADER_ARB)); - gDeferredMultiLightProgram.mShaderFiles.push_back(make_pair("deferred/multiPointLightF.glsl", GL_FRAGMENT_SHADER_ARB)); - gDeferredMultiLightProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; - success = gDeferredMultiLightProgram.createShader(NULL, NULL); + gDeferredMultiLightProgram[i].mName = llformat("Deferred MultiLight Shader %d", i); + gDeferredMultiLightProgram[i].mShaderFiles.clear(); + gDeferredMultiLightProgram[i].mShaderFiles.push_back(make_pair("deferred/multiPointLightV.glsl", GL_VERTEX_SHADER_ARB)); + gDeferredMultiLightProgram[i].mShaderFiles.push_back(make_pair("deferred/multiPointLightF.glsl", GL_FRAGMENT_SHADER_ARB)); + gDeferredMultiLightProgram[i].mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + gDeferredMultiLightProgram[i].addPermutation("LIGHT_COUNT", llformat("%d", i+1)); + success = gDeferredMultiLightProgram[i].createShader(NULL, NULL); + } } if (success) @@ -1208,7 +1235,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() if (success) { std::string fragment; - std::string vertex = "deferred/sunLightV.glsl"; + std::string vertex = "deferred/postDeferredNoTCV.glsl"; if (gSavedSettings.getBOOL("RenderDeferredSSAO")) { @@ -1231,11 +1258,34 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() success = gDeferredSunProgram.createShader(NULL, NULL); } + if(gSavedSettings.getBOOL("RenderDeferredSSAO")) + { + if (success) + { + gDeferredSSAOProgram.mName = "Deferred Ambient Occlusion Shader"; + gDeferredSSAOProgram.mShaderFiles.clear(); + gDeferredSSAOProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredNoTCV.glsl", GL_VERTEX_SHADER_ARB)); + gDeferredSSAOProgram.mShaderFiles.push_back(make_pair("deferred/SSAOF.glsl", GL_FRAGMENT_SHADER_ARB)); + gDeferredSSAOProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + success = gDeferredSSAOProgram.createShader(NULL, NULL); + } + + if (success) + { + gDeferredDownsampleDepthNearestProgram.mName = "Deferred Nearest Downsample Depth Shader"; + gDeferredDownsampleDepthNearestProgram.mShaderFiles.clear(); + gDeferredDownsampleDepthNearestProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredNoTCV.glsl", GL_VERTEX_SHADER_ARB)); + gDeferredDownsampleDepthNearestProgram.mShaderFiles.push_back(make_pair("deferred/downsampleDepthNearestF.glsl", GL_FRAGMENT_SHADER_ARB)); + gDeferredDownsampleDepthNearestProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + success = gDeferredDownsampleDepthNearestProgram.createShader(NULL, NULL); + } + } + if (success) { gDeferredBlurLightProgram.mName = "Deferred Blur Light Shader"; gDeferredBlurLightProgram.mShaderFiles.clear(); - gDeferredBlurLightProgram.mShaderFiles.push_back(make_pair("deferred/blurLightV.glsl", GL_VERTEX_SHADER_ARB)); + gDeferredBlurLightProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredNoTCV.glsl", GL_VERTEX_SHADER_ARB)); gDeferredBlurLightProgram.mShaderFiles.push_back(make_pair("deferred/blurLightF.glsl", GL_FRAGMENT_SHADER_ARB)); gDeferredBlurLightProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; success = gDeferredBlurLightProgram.createShader(NULL, NULL); @@ -1244,11 +1294,8 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() if (success) { gDeferredAlphaProgram.mName = "Deferred Alpha Shader"; - gDeferredAlphaProgram.mFeatures.atmosphericHelpers = true; + gDeferredAlphaProgram.mFeatures.calculatesLighting = false; - gDeferredAlphaProgram.mFeatures.calculatesAtmospherics = true; - gDeferredAlphaProgram.mFeatures.hasGamma = true; - gDeferredAlphaProgram.mFeatures.hasAtmospherics = true; gDeferredAlphaProgram.mFeatures.hasLighting = false; gDeferredAlphaProgram.mFeatures.isAlphaLighting = true; gDeferredAlphaProgram.mFeatures.disableTextureIndex = true; //hack to disable auto-setup of texture channels @@ -1264,6 +1311,9 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredAlphaProgram.mShaderFiles.clear(); gDeferredAlphaProgram.mShaderFiles.push_back(make_pair("deferred/alphaV.glsl", GL_VERTEX_SHADER_ARB)); gDeferredAlphaProgram.mShaderFiles.push_back(make_pair("deferred/alphaF.glsl", GL_FRAGMENT_SHADER_ARB)); + gDeferredAlphaProgram.addPermutation("USE_INDEXED_TEX", "1"); + gDeferredAlphaProgram.addPermutation("HAS_SHADOW", mVertexShaderLevel[SHADER_DEFERRED] > 1 ? "1" : "0"); + gDeferredAlphaProgram.addPermutation("USE_VERTEX_COLOR", "1"); gDeferredAlphaProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; success = gDeferredAlphaProgram.createShader(NULL, NULL); @@ -1273,6 +1323,72 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredAlphaProgram.mFeatures.hasLighting = true; } + if (success) + { + gDeferredAlphaImpostorProgram.mName = "Deferred Alpha Shader"; + + gDeferredAlphaImpostorProgram.mFeatures.calculatesLighting = false; + gDeferredAlphaImpostorProgram.mFeatures.hasLighting = false; + gDeferredAlphaImpostorProgram.mFeatures.isAlphaLighting = true; + gDeferredAlphaImpostorProgram.mFeatures.disableTextureIndex = true; //hack to disable auto-setup of texture channels + if (mVertexShaderLevel[SHADER_DEFERRED] < 1) + { + gDeferredAlphaImpostorProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels; + } + else + { //shave off some texture units for shadow maps + gDeferredAlphaImpostorProgram.mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels - 6, 1); + } + + gDeferredAlphaImpostorProgram.mShaderFiles.clear(); + gDeferredAlphaImpostorProgram.mShaderFiles.push_back(make_pair("deferred/alphaV.glsl", GL_VERTEX_SHADER_ARB)); + gDeferredAlphaImpostorProgram.mShaderFiles.push_back(make_pair("deferred/alphaF.glsl", GL_FRAGMENT_SHADER_ARB)); + gDeferredAlphaImpostorProgram.addPermutation("USE_INDEXED_TEX", "1"); + gDeferredAlphaImpostorProgram.addPermutation("HAS_SHADOW", mVertexShaderLevel[SHADER_DEFERRED] > 1 ? "1" : "0"); + gDeferredAlphaImpostorProgram.addPermutation("USE_VERTEX_COLOR", "1"); + gDeferredAlphaImpostorProgram.addPermutation("FOR_IMPOSTOR", "1"); + + gDeferredAlphaImpostorProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + + success = gDeferredAlphaImpostorProgram.createShader(NULL, NULL); + + // Hack + gDeferredAlphaImpostorProgram.mFeatures.calculatesLighting = true; + gDeferredAlphaImpostorProgram.mFeatures.hasLighting = true; + } + + if (success) + { + gDeferredAlphaWaterProgram.mName = "Deferred Alpha Underwater Shader"; + gDeferredAlphaWaterProgram.mFeatures.calculatesLighting = false; + gDeferredAlphaWaterProgram.mFeatures.hasLighting = false; + gDeferredAlphaWaterProgram.mFeatures.isAlphaLighting = true; + gDeferredAlphaWaterProgram.mFeatures.disableTextureIndex = true; //hack to disable auto-setup of texture channels + if (mVertexShaderLevel[SHADER_DEFERRED] < 1) + { + gDeferredAlphaWaterProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels; + } + else + { //shave off some texture units for shadow maps + gDeferredAlphaWaterProgram.mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels - 6, 1); + } + gDeferredAlphaWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; + gDeferredAlphaWaterProgram.mShaderFiles.clear(); + gDeferredAlphaWaterProgram.mShaderFiles.push_back(make_pair("deferred/alphaV.glsl", GL_VERTEX_SHADER_ARB)); + gDeferredAlphaWaterProgram.mShaderFiles.push_back(make_pair("deferred/alphaF.glsl", GL_FRAGMENT_SHADER_ARB)); + gDeferredAlphaWaterProgram.addPermutation("USE_INDEXED_TEX", "1"); + gDeferredAlphaWaterProgram.addPermutation("WATER_FOG", "1"); + gDeferredAlphaWaterProgram.addPermutation("USE_VERTEX_COLOR", "1"); + gDeferredAlphaWaterProgram.addPermutation("HAS_SHADOW", mVertexShaderLevel[SHADER_DEFERRED] > 1 ? "1" : "0"); + gDeferredAlphaWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + + success = gDeferredAlphaWaterProgram.createShader(NULL, NULL); + + // Hack + gDeferredAlphaWaterProgram.mFeatures.calculatesLighting = true; + gDeferredAlphaWaterProgram.mFeatures.hasLighting = true; + } + if (success) { gDeferredFullbrightProgram.mName = "Deferred Fullbright Shader"; @@ -1287,6 +1403,98 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() success = gDeferredFullbrightProgram.createShader(NULL, NULL); } + if (success) + { + gDeferredFullbrightAlphaMaskProgram.mName = "Deferred Fullbright Alpha Masking Shader"; + gDeferredFullbrightAlphaMaskProgram.mFeatures.calculatesAtmospherics = true; + gDeferredFullbrightAlphaMaskProgram.mFeatures.hasGamma = true; + gDeferredFullbrightAlphaMaskProgram.mFeatures.hasTransport = true; + gDeferredFullbrightAlphaMaskProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels; + gDeferredFullbrightAlphaMaskProgram.mShaderFiles.clear(); + gDeferredFullbrightAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightV.glsl", GL_VERTEX_SHADER_ARB)); + gDeferredFullbrightAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB)); + gDeferredFullbrightAlphaMaskProgram.addPermutation("HAS_ALPHA_MASK","1"); + gDeferredFullbrightAlphaMaskProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + success = gDeferredFullbrightAlphaMaskProgram.createShader(NULL, NULL); + } + + if (success) + { + gDeferredFullbrightWaterProgram.mName = "Deferred Fullbright Underwater Shader"; + gDeferredFullbrightWaterProgram.mFeatures.calculatesAtmospherics = true; + gDeferredFullbrightWaterProgram.mFeatures.hasGamma = true; + gDeferredFullbrightWaterProgram.mFeatures.hasTransport = true; + gDeferredFullbrightWaterProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels; + gDeferredFullbrightWaterProgram.mShaderFiles.clear(); + gDeferredFullbrightWaterProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightV.glsl", GL_VERTEX_SHADER_ARB)); + gDeferredFullbrightWaterProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB)); + gDeferredFullbrightWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + gDeferredFullbrightWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; + gDeferredFullbrightWaterProgram.addPermutation("WATER_FOG","1"); + success = gDeferredFullbrightWaterProgram.createShader(NULL, NULL); + } + + if (success) + { + gDeferredFullbrightAlphaMaskWaterProgram.mName = "Deferred Fullbright Underwater Alpha Masking Shader"; + gDeferredFullbrightAlphaMaskWaterProgram.mFeatures.calculatesAtmospherics = true; + gDeferredFullbrightAlphaMaskWaterProgram.mFeatures.hasGamma = true; + gDeferredFullbrightAlphaMaskWaterProgram.mFeatures.hasTransport = true; + gDeferredFullbrightAlphaMaskWaterProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels; + gDeferredFullbrightAlphaMaskWaterProgram.mShaderFiles.clear(); + gDeferredFullbrightAlphaMaskWaterProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightV.glsl", GL_VERTEX_SHADER_ARB)); + gDeferredFullbrightAlphaMaskWaterProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB)); + gDeferredFullbrightAlphaMaskWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + gDeferredFullbrightAlphaMaskWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; + gDeferredFullbrightAlphaMaskWaterProgram.addPermutation("HAS_ALPHA_MASK","1"); + gDeferredFullbrightAlphaMaskWaterProgram.addPermutation("WATER_FOG","1"); + success = gDeferredFullbrightAlphaMaskWaterProgram.createShader(NULL, NULL); + } + + if (success) + { + gDeferredFullbrightShinyProgram.mName = "Deferred FullbrightShiny Shader"; + gDeferredFullbrightShinyProgram.mFeatures.calculatesAtmospherics = true; + gDeferredFullbrightShinyProgram.mFeatures.hasGamma = true; + gDeferredFullbrightShinyProgram.mFeatures.hasTransport = true; + gDeferredFullbrightShinyProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels-1; + gDeferredFullbrightShinyProgram.mShaderFiles.clear(); + gDeferredFullbrightShinyProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightShinyV.glsl", GL_VERTEX_SHADER_ARB)); + gDeferredFullbrightShinyProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightShinyF.glsl", GL_FRAGMENT_SHADER_ARB)); + gDeferredFullbrightShinyProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + success = gDeferredFullbrightShinyProgram.createShader(NULL, NULL); + } + + if (success) + { + gDeferredSkinnedFullbrightProgram.mName = "Skinned Fullbright Shader"; + gDeferredSkinnedFullbrightProgram.mFeatures.calculatesAtmospherics = true; + gDeferredSkinnedFullbrightProgram.mFeatures.hasGamma = true; + gDeferredSkinnedFullbrightProgram.mFeatures.hasTransport = true; + gDeferredSkinnedFullbrightProgram.mFeatures.hasObjectSkinning = true; + gDeferredSkinnedFullbrightProgram.mFeatures.disableTextureIndex = true; + gDeferredSkinnedFullbrightProgram.mShaderFiles.clear(); + gDeferredSkinnedFullbrightProgram.mShaderFiles.push_back(make_pair("objects/fullbrightSkinnedV.glsl", GL_VERTEX_SHADER_ARB)); + gDeferredSkinnedFullbrightProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB)); + gDeferredSkinnedFullbrightProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; + success = gDeferredSkinnedFullbrightProgram.createShader(NULL, NULL); + } + + if (success) + { + gDeferredSkinnedFullbrightShinyProgram.mName = "Skinned Fullbright Shiny Shader"; + gDeferredSkinnedFullbrightShinyProgram.mFeatures.calculatesAtmospherics = true; + gDeferredSkinnedFullbrightShinyProgram.mFeatures.hasGamma = true; + gDeferredSkinnedFullbrightShinyProgram.mFeatures.hasTransport = true; + gDeferredSkinnedFullbrightShinyProgram.mFeatures.hasObjectSkinning = true; + gDeferredSkinnedFullbrightShinyProgram.mFeatures.disableTextureIndex = true; + gDeferredSkinnedFullbrightShinyProgram.mShaderFiles.clear(); + gDeferredSkinnedFullbrightShinyProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinySkinnedV.glsl", GL_VERTEX_SHADER_ARB)); + gDeferredSkinnedFullbrightShinyProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightShinyF.glsl", GL_FRAGMENT_SHADER_ARB)); + gDeferredSkinnedFullbrightShinyProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; + success = gDeferredSkinnedFullbrightShinyProgram.createShader(NULL, NULL); + } + if (success) { gDeferredEmissiveProgram.mName = "Deferred Emissive Shader"; @@ -1305,23 +1513,35 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() { // load water shader gDeferredWaterProgram.mName = "Deferred Water Shader"; - gDeferredWaterProgram.mFeatures.atmosphericHelpers = true; gDeferredWaterProgram.mFeatures.calculatesAtmospherics = true; - gDeferredWaterProgram.mFeatures.hasAtmospherics = true; gDeferredWaterProgram.mFeatures.hasGamma = true; gDeferredWaterProgram.mFeatures.hasTransport = true; gDeferredWaterProgram.mShaderFiles.clear(); gDeferredWaterProgram.mShaderFiles.push_back(make_pair("deferred/waterV.glsl", GL_VERTEX_SHADER_ARB)); gDeferredWaterProgram.mShaderFiles.push_back(make_pair("deferred/waterF.glsl", GL_FRAGMENT_SHADER_ARB)); gDeferredWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; - success = gDeferredWaterProgram.createShader(NULL, &mWaterUniforms); + success = gDeferredWaterProgram.createShader(NULL, NULL); + } + + if (success) + { + // load water shader + gDeferredUnderWaterProgram.mName = "Deferred Under Water Shader"; + gDeferredUnderWaterProgram.mFeatures.calculatesAtmospherics = true; + gDeferredUnderWaterProgram.mFeatures.hasGamma = true; + gDeferredUnderWaterProgram.mFeatures.hasTransport = true; + gDeferredUnderWaterProgram.mShaderFiles.clear(); + gDeferredUnderWaterProgram.mShaderFiles.push_back(make_pair("deferred/waterV.glsl", GL_VERTEX_SHADER_ARB)); + gDeferredUnderWaterProgram.mShaderFiles.push_back(make_pair("deferred/underWaterF.glsl", GL_FRAGMENT_SHADER_ARB)); + gDeferredUnderWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + success = gDeferredUnderWaterProgram.createShader(NULL, NULL); } if (success) { gDeferredSoftenProgram.mName = "Deferred Soften Shader"; gDeferredSoftenProgram.mShaderFiles.clear(); - gDeferredSoftenProgram.mShaderFiles.push_back(make_pair("deferred/softenLightV.glsl", GL_VERTEX_SHADER_ARB)); + gDeferredSoftenProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredNoTCV.glsl", GL_VERTEX_SHADER_ARB)); gDeferredSoftenProgram.mShaderFiles.push_back(make_pair("deferred/softenLightF.glsl", GL_FRAGMENT_SHADER_ARB)); gDeferredSoftenProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; @@ -1334,6 +1554,25 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() success = gDeferredSoftenProgram.createShader(NULL, NULL); } + if (success) + { + gDeferredSoftenWaterProgram.mName = "Deferred Soften Underwater Shader"; + gDeferredSoftenWaterProgram.mShaderFiles.clear(); + gDeferredSoftenWaterProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredNoTCV.glsl", GL_VERTEX_SHADER_ARB)); + gDeferredSoftenWaterProgram.mShaderFiles.push_back(make_pair("deferred/softenLightF.glsl", GL_FRAGMENT_SHADER_ARB)); + + gDeferredSoftenWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + gDeferredSoftenWaterProgram.addPermutation("WATER_FOG", "1"); + gDeferredSoftenWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; + + if (gSavedSettings.getBOOL("RenderDeferredSSAO")) + { //if using SSAO, take screen space light map into account as if shadows are enabled + gDeferredSoftenWaterProgram.mShaderLevel = llmax(gDeferredSoftenWaterProgram.mShaderLevel, 2); + } + + success = gDeferredSoftenWaterProgram.createShader(NULL, NULL); + } + if (success) { gDeferredShadowProgram.mName = "Deferred Shadow Shader"; @@ -1373,7 +1612,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredAvatarShadowProgram.mShaderFiles.push_back(make_pair("deferred/avatarShadowV.glsl", GL_VERTEX_SHADER_ARB)); gDeferredAvatarShadowProgram.mShaderFiles.push_back(make_pair("deferred/avatarShadowF.glsl", GL_FRAGMENT_SHADER_ARB)); gDeferredAvatarShadowProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; - success = gDeferredAvatarShadowProgram.createShader(NULL, &mAvatarUniforms); + success = gDeferredAvatarShadowProgram.createShader(NULL, NULL); } if (success) @@ -1394,7 +1633,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredTerrainProgram.mShaderFiles.push_back(make_pair("deferred/terrainV.glsl", GL_VERTEX_SHADER_ARB)); gDeferredTerrainProgram.mShaderFiles.push_back(make_pair("deferred/terrainF.glsl", GL_FRAGMENT_SHADER_ARB)); gDeferredTerrainProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; - success = gDeferredTerrainProgram.createShader(NULL, &mTerrainUniforms); + success = gDeferredTerrainProgram.createShader(NULL, NULL); } if (success) @@ -1405,38 +1644,49 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredAvatarProgram.mShaderFiles.push_back(make_pair("deferred/avatarV.glsl", GL_VERTEX_SHADER_ARB)); gDeferredAvatarProgram.mShaderFiles.push_back(make_pair("deferred/avatarF.glsl", GL_FRAGMENT_SHADER_ARB)); gDeferredAvatarProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; - success = gDeferredAvatarProgram.createShader(NULL, &mAvatarUniforms); + success = gDeferredAvatarProgram.createShader(NULL, NULL); } if (success) { gDeferredAvatarAlphaProgram.mName = "Avatar Alpha Shader"; - gDeferredAvatarAlphaProgram.mFeatures.atmosphericHelpers = true; gDeferredAvatarAlphaProgram.mFeatures.hasSkinning = true; gDeferredAvatarAlphaProgram.mFeatures.calculatesLighting = false; - gDeferredAvatarAlphaProgram.mFeatures.calculatesAtmospherics = true; - gDeferredAvatarAlphaProgram.mFeatures.hasGamma = true; - gDeferredAvatarAlphaProgram.mFeatures.hasAtmospherics = true; gDeferredAvatarAlphaProgram.mFeatures.hasLighting = false; gDeferredAvatarAlphaProgram.mFeatures.isAlphaLighting = true; gDeferredAvatarAlphaProgram.mFeatures.disableTextureIndex = true; gDeferredAvatarAlphaProgram.mShaderFiles.clear(); - gDeferredAvatarAlphaProgram.mShaderFiles.push_back(make_pair("deferred/avatarAlphaNoColorV.glsl", GL_VERTEX_SHADER_ARB)); - gDeferredAvatarAlphaProgram.mShaderFiles.push_back(make_pair("deferred/alphaNonIndexedNoColorF.glsl", GL_FRAGMENT_SHADER_ARB)); + gDeferredAvatarAlphaProgram.mShaderFiles.push_back(make_pair("deferred/alphaV.glsl", GL_VERTEX_SHADER_ARB)); + gDeferredAvatarAlphaProgram.mShaderFiles.push_back(make_pair("deferred/alphaF.glsl", GL_FRAGMENT_SHADER_ARB)); + gDeferredAvatarAlphaProgram.addPermutation("USE_DIFFUSE_TEX", "1"); + gDeferredAvatarAlphaProgram.addPermutation("IS_AVATAR_SKIN", "1"); + gDeferredAvatarAlphaProgram.addPermutation("HAS_SHADOW", mVertexShaderLevel[SHADER_DEFERRED] > 1 ? "1" : "0"); gDeferredAvatarAlphaProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; - success = gDeferredAvatarAlphaProgram.createShader(NULL, &mAvatarUniforms); + success = gDeferredAvatarAlphaProgram.createShader(NULL, NULL); gDeferredAvatarAlphaProgram.mFeatures.calculatesLighting = true; gDeferredAvatarAlphaProgram.mFeatures.hasLighting = true; } + + if (success) + { + gDeferredPostGammaCorrectProgram.mName = "Deferred Gamma Correction Post Process"; + gDeferredPostGammaCorrectProgram.mShaderFiles.clear(); + gDeferredPostGammaCorrectProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredNoTCV.glsl", GL_VERTEX_SHADER_ARB)); + gDeferredPostGammaCorrectProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredGammaCorrectF.glsl", GL_FRAGMENT_SHADER_ARB)); + gDeferredPostGammaCorrectProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; + success = gDeferredPostGammaCorrectProgram.createShader(NULL, NULL); + } if (success) { gFXAAProgram.mName = "FXAA Shader"; gFXAAProgram.mShaderFiles.clear(); - gFXAAProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredV.glsl", GL_VERTEX_SHADER_ARB)); + gFXAAProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredNoTCV.glsl", GL_VERTEX_SHADER_ARB)); gFXAAProgram.mShaderFiles.push_back(make_pair("deferred/fxaaF.glsl", GL_FRAGMENT_SHADER_ARB)); + static LLCachedControl fxaaQuality("FXAAQuality", 12); + gFXAAProgram.addPermutation("FXAA_QUALITY_M_PRESET", fmt::to_string(fxaaQuality.get())); gFXAAProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; success = gFXAAProgram.createShader(NULL, NULL); } @@ -1490,7 +1740,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredWLSkyProgram.mShaderFiles.push_back(make_pair("deferred/skyF.glsl", GL_FRAGMENT_SHADER_ARB)); gDeferredWLSkyProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; gDeferredWLSkyProgram.mShaderGroup = LLGLSLShader::SG_SKY; - success = gDeferredWLSkyProgram.createShader(NULL, &mWLUniforms); + success = gDeferredWLSkyProgram.createShader(NULL, NULL); } if (success) @@ -1501,14 +1751,17 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredWLCloudProgram.mShaderFiles.push_back(make_pair("deferred/cloudsF.glsl", GL_FRAGMENT_SHADER_ARB)); gDeferredWLCloudProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED]; gDeferredWLCloudProgram.mShaderGroup = LLGLSLShader::SG_SKY; - success = gDeferredWLCloudProgram.createShader(NULL, &mWLUniforms); + success = gDeferredWLCloudProgram.createShader(NULL, NULL); } if (success) { gDeferredStarProgram.mName = "Deferred Star Program"; - vector shaderUniforms(mWLUniforms); - shaderUniforms.push_back("custom_alpha"); + static std::vector shaderUniforms; + if(shaderUniforms.empty()) + { + shaderUniforms.push_back(LLStaticHashedString("custom_alpha")); + } gDeferredStarProgram.mShaderFiles.clear(); gDeferredStarProgram.mShaderFiles.push_back(make_pair("deferred/starsV.glsl", GL_VERTEX_SHADER_ARB)); gDeferredStarProgram.mShaderFiles.push_back(make_pair("deferred/starsF.glsl", GL_FRAGMENT_SHADER_ARB)); @@ -1528,6 +1781,12 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() success = gNormalMapGenProgram.createShader(NULL, NULL); } + if (!success) + { + mVertexShaderLevel[SHADER_DEFERRED] = 0; + unloadShaderClass(SHADER_DEFERRED); + } + return success; } @@ -1540,22 +1799,6 @@ BOOL LLViewerShaderMgr::loadShadersObject() unloadShaderClass(SHADER_OBJECT); return TRUE; } - - if (success) - { - gObjectSimpleNonIndexedProgram.mName = "Non indexed Shader"; - gObjectSimpleNonIndexedProgram.mFeatures.calculatesLighting = true; - gObjectSimpleNonIndexedProgram.mFeatures.calculatesAtmospherics = true; - gObjectSimpleNonIndexedProgram.mFeatures.hasGamma = true; - gObjectSimpleNonIndexedProgram.mFeatures.hasAtmospherics = true; - gObjectSimpleNonIndexedProgram.mFeatures.hasLighting = true; - gObjectSimpleNonIndexedProgram.mFeatures.disableTextureIndex = true; - gObjectSimpleNonIndexedProgram.mShaderFiles.clear(); - gObjectSimpleNonIndexedProgram.mShaderFiles.push_back(make_pair("objects/simpleV.glsl", GL_VERTEX_SHADER_ARB)); - gObjectSimpleNonIndexedProgram.mShaderFiles.push_back(make_pair("objects/simpleF.glsl", GL_FRAGMENT_SHADER_ARB)); - gObjectSimpleNonIndexedProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; - success = gObjectSimpleNonIndexedProgram.createShader(NULL, NULL); - } if (success) { @@ -1573,24 +1816,6 @@ BOOL LLViewerShaderMgr::loadShadersObject() success = gObjectSimpleNonIndexedTexGenProgram.createShader(NULL, NULL); } - - if (success) - { - gObjectSimpleNonIndexedWaterProgram.mName = "Non indexed Water Shader"; - gObjectSimpleNonIndexedWaterProgram.mFeatures.calculatesLighting = true; - gObjectSimpleNonIndexedWaterProgram.mFeatures.calculatesAtmospherics = true; - gObjectSimpleNonIndexedWaterProgram.mFeatures.hasWaterFog = true; - gObjectSimpleNonIndexedWaterProgram.mFeatures.hasAtmospherics = true; - gObjectSimpleNonIndexedWaterProgram.mFeatures.hasLighting = true; - gObjectSimpleNonIndexedWaterProgram.mFeatures.disableTextureIndex = true; - gObjectSimpleNonIndexedWaterProgram.mShaderFiles.clear(); - gObjectSimpleNonIndexedWaterProgram.mShaderFiles.push_back(make_pair("objects/simpleV.glsl", GL_VERTEX_SHADER_ARB)); - gObjectSimpleNonIndexedWaterProgram.mShaderFiles.push_back(make_pair("objects/simpleWaterF.glsl", GL_FRAGMENT_SHADER_ARB)); - gObjectSimpleNonIndexedWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; - gObjectSimpleNonIndexedWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; - success = gObjectSimpleNonIndexedWaterProgram.createShader(NULL, NULL); - } - if (success) { gObjectSimpleNonIndexedTexGenWaterProgram.mName = "Non indexed tex-gen Water Shader"; @@ -1608,41 +1833,6 @@ BOOL LLViewerShaderMgr::loadShadersObject() success = gObjectSimpleNonIndexedTexGenWaterProgram.createShader(NULL, NULL); } - if (success) - { - gObjectAlphaMaskNonIndexedProgram.mName = "Non indexed alpha mask Shader"; - gObjectAlphaMaskNonIndexedProgram.mFeatures.calculatesLighting = true; - gObjectAlphaMaskNonIndexedProgram.mFeatures.calculatesAtmospherics = true; - gObjectAlphaMaskNonIndexedProgram.mFeatures.hasGamma = true; - gObjectAlphaMaskNonIndexedProgram.mFeatures.hasAtmospherics = true; - gObjectAlphaMaskNonIndexedProgram.mFeatures.hasLighting = true; - gObjectAlphaMaskNonIndexedProgram.mFeatures.disableTextureIndex = true; - gObjectAlphaMaskNonIndexedProgram.mFeatures.hasAlphaMask = true; - gObjectAlphaMaskNonIndexedProgram.mShaderFiles.clear(); - gObjectAlphaMaskNonIndexedProgram.mShaderFiles.push_back(make_pair("objects/simpleNonIndexedV.glsl", GL_VERTEX_SHADER_ARB)); - gObjectAlphaMaskNonIndexedProgram.mShaderFiles.push_back(make_pair("objects/simpleF.glsl", GL_FRAGMENT_SHADER_ARB)); - gObjectAlphaMaskNonIndexedProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; - success = gObjectAlphaMaskNonIndexedProgram.createShader(NULL, NULL); - } - - if (success) - { - gObjectAlphaMaskNonIndexedWaterProgram.mName = "Non indexed alpha mask Water Shader"; - gObjectAlphaMaskNonIndexedWaterProgram.mFeatures.calculatesLighting = true; - gObjectAlphaMaskNonIndexedWaterProgram.mFeatures.calculatesAtmospherics = true; - gObjectAlphaMaskNonIndexedWaterProgram.mFeatures.hasWaterFog = true; - gObjectAlphaMaskNonIndexedWaterProgram.mFeatures.hasAtmospherics = true; - gObjectAlphaMaskNonIndexedWaterProgram.mFeatures.hasLighting = true; - gObjectAlphaMaskNonIndexedWaterProgram.mFeatures.disableTextureIndex = true; - gObjectAlphaMaskNonIndexedWaterProgram.mFeatures.hasAlphaMask = true; - gObjectAlphaMaskNonIndexedWaterProgram.mShaderFiles.clear(); - gObjectAlphaMaskNonIndexedWaterProgram.mShaderFiles.push_back(make_pair("objects/simpleNonIndexedV.glsl", GL_VERTEX_SHADER_ARB)); - gObjectAlphaMaskNonIndexedWaterProgram.mShaderFiles.push_back(make_pair("objects/simpleWaterF.glsl", GL_FRAGMENT_SHADER_ARB)); - gObjectAlphaMaskNonIndexedWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; - gObjectAlphaMaskNonIndexedWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; - success = gObjectAlphaMaskNonIndexedWaterProgram.createShader(NULL, NULL); - } - if (success) { gObjectAlphaMaskNoColorProgram.mName = "No color alpha mask Shader"; @@ -1713,68 +1903,6 @@ BOOL LLViewerShaderMgr::loadShadersObject() success = gTreeWaterProgram.createShader(NULL, NULL); } - if (success) - { - gObjectFullbrightNonIndexedProgram.mName = "Non Indexed Fullbright Shader"; - gObjectFullbrightNonIndexedProgram.mFeatures.calculatesAtmospherics = true; - gObjectFullbrightNonIndexedProgram.mFeatures.hasGamma = true; - gObjectFullbrightNonIndexedProgram.mFeatures.hasTransport = true; - gObjectFullbrightNonIndexedProgram.mFeatures.isFullbright = true; - gObjectFullbrightNonIndexedProgram.mFeatures.disableTextureIndex = true; - gObjectFullbrightNonIndexedProgram.mShaderFiles.clear(); - gObjectFullbrightNonIndexedProgram.mShaderFiles.push_back(make_pair("objects/fullbrightV.glsl", GL_VERTEX_SHADER_ARB)); - gObjectFullbrightNonIndexedProgram.mShaderFiles.push_back(make_pair("objects/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB)); - gObjectFullbrightNonIndexedProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; - success = gObjectFullbrightNonIndexedProgram.createShader(NULL, NULL); - } - - if (success) - { - gObjectFullbrightNonIndexedWaterProgram.mName = "Non Indexed Fullbright Water Shader"; - gObjectFullbrightNonIndexedWaterProgram.mFeatures.calculatesAtmospherics = true; - gObjectFullbrightNonIndexedWaterProgram.mFeatures.isFullbright = true; - gObjectFullbrightNonIndexedWaterProgram.mFeatures.hasWaterFog = true; - gObjectFullbrightNonIndexedWaterProgram.mFeatures.hasTransport = true; - gObjectFullbrightNonIndexedWaterProgram.mFeatures.disableTextureIndex = true; - gObjectFullbrightNonIndexedWaterProgram.mShaderFiles.clear(); - gObjectFullbrightNonIndexedWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightV.glsl", GL_VERTEX_SHADER_ARB)); - gObjectFullbrightNonIndexedWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightWaterF.glsl", GL_FRAGMENT_SHADER_ARB)); - gObjectFullbrightNonIndexedWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; - gObjectFullbrightNonIndexedWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; - success = gObjectFullbrightNonIndexedWaterProgram.createShader(NULL, NULL); - } - - if (success) - { - gObjectEmissiveNonIndexedProgram.mName = "Non Indexed Emissive Shader"; - gObjectEmissiveNonIndexedProgram.mFeatures.calculatesAtmospherics = true; - gObjectEmissiveNonIndexedProgram.mFeatures.hasGamma = true; - gObjectEmissiveNonIndexedProgram.mFeatures.hasTransport = true; - gObjectEmissiveNonIndexedProgram.mFeatures.isFullbright = true; - gObjectEmissiveNonIndexedProgram.mFeatures.disableTextureIndex = true; - gObjectEmissiveNonIndexedProgram.mShaderFiles.clear(); - gObjectEmissiveNonIndexedProgram.mShaderFiles.push_back(make_pair("objects/emissiveV.glsl", GL_VERTEX_SHADER_ARB)); - gObjectEmissiveNonIndexedProgram.mShaderFiles.push_back(make_pair("objects/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB)); - gObjectEmissiveNonIndexedProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; - success = gObjectEmissiveNonIndexedProgram.createShader(NULL, NULL); - } - - if (success) - { - gObjectEmissiveNonIndexedWaterProgram.mName = "Non Indexed Emissive Water Shader"; - gObjectEmissiveNonIndexedWaterProgram.mFeatures.calculatesAtmospherics = true; - gObjectEmissiveNonIndexedWaterProgram.mFeatures.isFullbright = true; - gObjectEmissiveNonIndexedWaterProgram.mFeatures.hasWaterFog = true; - gObjectEmissiveNonIndexedWaterProgram.mFeatures.hasTransport = true; - gObjectEmissiveNonIndexedWaterProgram.mFeatures.disableTextureIndex = true; - gObjectEmissiveNonIndexedWaterProgram.mShaderFiles.clear(); - gObjectEmissiveNonIndexedWaterProgram.mShaderFiles.push_back(make_pair("objects/emissiveV.glsl", GL_VERTEX_SHADER_ARB)); - gObjectEmissiveNonIndexedWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightWaterF.glsl", GL_FRAGMENT_SHADER_ARB)); - gObjectEmissiveNonIndexedWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; - gObjectEmissiveNonIndexedWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; - success = gObjectEmissiveNonIndexedWaterProgram.createShader(NULL, NULL); - } - if (success) { gObjectFullbrightNoColorProgram.mName = "Non Indexed no color Fullbright Shader"; @@ -1806,73 +1934,6 @@ BOOL LLViewerShaderMgr::loadShadersObject() success = gObjectFullbrightNoColorWaterProgram.createShader(NULL, NULL); } - if (success) - { - gObjectShinyNonIndexedProgram.mName = "Non Indexed Shiny Shader"; - gObjectShinyNonIndexedProgram.mFeatures.calculatesAtmospherics = true; - gObjectShinyNonIndexedProgram.mFeatures.calculatesLighting = true; - gObjectShinyNonIndexedProgram.mFeatures.hasGamma = true; - gObjectShinyNonIndexedProgram.mFeatures.hasAtmospherics = true; - gObjectShinyNonIndexedProgram.mFeatures.isShiny = true; - gObjectShinyNonIndexedProgram.mFeatures.disableTextureIndex = true; - gObjectShinyNonIndexedProgram.mShaderFiles.clear(); - gObjectShinyNonIndexedProgram.mShaderFiles.push_back(make_pair("objects/shinyV.glsl", GL_VERTEX_SHADER_ARB)); - gObjectShinyNonIndexedProgram.mShaderFiles.push_back(make_pair("objects/shinyF.glsl", GL_FRAGMENT_SHADER_ARB)); - gObjectShinyNonIndexedProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; - success = gObjectShinyNonIndexedProgram.createShader(NULL, &mShinyUniforms); - } - - if (success) - { - gObjectShinyNonIndexedWaterProgram.mName = "Non Indexed Shiny Water Shader"; - gObjectShinyNonIndexedWaterProgram.mFeatures.calculatesAtmospherics = true; - gObjectShinyNonIndexedWaterProgram.mFeatures.calculatesLighting = true; - gObjectShinyNonIndexedWaterProgram.mFeatures.isShiny = true; - gObjectShinyNonIndexedWaterProgram.mFeatures.hasWaterFog = true; - gObjectShinyNonIndexedWaterProgram.mFeatures.hasAtmospherics = true; - gObjectShinyNonIndexedWaterProgram.mFeatures.disableTextureIndex = true; - gObjectShinyNonIndexedWaterProgram.mShaderFiles.clear(); - gObjectShinyNonIndexedWaterProgram.mShaderFiles.push_back(make_pair("objects/shinyWaterF.glsl", GL_FRAGMENT_SHADER_ARB)); - gObjectShinyNonIndexedWaterProgram.mShaderFiles.push_back(make_pair("objects/shinyV.glsl", GL_VERTEX_SHADER_ARB)); - gObjectShinyNonIndexedWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; - gObjectShinyNonIndexedWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; - success = gObjectShinyNonIndexedWaterProgram.createShader(NULL, &mShinyUniforms); - } - - if (success) - { - gObjectFullbrightShinyNonIndexedProgram.mName = "Non Indexed Fullbright Shiny Shader"; - gObjectFullbrightShinyNonIndexedProgram.mFeatures.calculatesAtmospherics = true; - gObjectFullbrightShinyNonIndexedProgram.mFeatures.isFullbright = true; - gObjectFullbrightShinyNonIndexedProgram.mFeatures.isShiny = true; - gObjectFullbrightShinyNonIndexedProgram.mFeatures.hasGamma = true; - gObjectFullbrightShinyNonIndexedProgram.mFeatures.hasTransport = true; - gObjectFullbrightShinyNonIndexedProgram.mFeatures.disableTextureIndex = true; - gObjectFullbrightShinyNonIndexedProgram.mShaderFiles.clear(); - gObjectFullbrightShinyNonIndexedProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyV.glsl", GL_VERTEX_SHADER_ARB)); - gObjectFullbrightShinyNonIndexedProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyF.glsl", GL_FRAGMENT_SHADER_ARB)); - gObjectFullbrightShinyNonIndexedProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; - success = gObjectFullbrightShinyNonIndexedProgram.createShader(NULL, &mShinyUniforms); - } - - if (success) - { - gObjectFullbrightShinyNonIndexedWaterProgram.mName = "Non Indexed Fullbright Shiny Water Shader"; - gObjectFullbrightShinyNonIndexedWaterProgram.mFeatures.calculatesAtmospherics = true; - gObjectFullbrightShinyNonIndexedWaterProgram.mFeatures.isFullbright = true; - gObjectFullbrightShinyNonIndexedWaterProgram.mFeatures.isShiny = true; - gObjectFullbrightShinyNonIndexedWaterProgram.mFeatures.hasGamma = true; - gObjectFullbrightShinyNonIndexedWaterProgram.mFeatures.hasTransport = true; - gObjectFullbrightShinyNonIndexedWaterProgram.mFeatures.hasWaterFog = true; - gObjectFullbrightShinyNonIndexedWaterProgram.mFeatures.disableTextureIndex = true; - gObjectFullbrightShinyNonIndexedWaterProgram.mShaderFiles.clear(); - gObjectFullbrightShinyNonIndexedWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyV.glsl", GL_VERTEX_SHADER_ARB)); - gObjectFullbrightShinyNonIndexedWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyWaterF.glsl", GL_FRAGMENT_SHADER_ARB)); - gObjectFullbrightShinyNonIndexedWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; - gObjectFullbrightShinyNonIndexedWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; - success = gObjectFullbrightShinyNonIndexedWaterProgram.createShader(NULL, &mShinyUniforms); - } - if (success) { gImpostorProgram.mName = "Impostor Shader"; @@ -1904,37 +1965,112 @@ BOOL LLViewerShaderMgr::loadShadersObject() if (success) { - gObjectSimpleProgram.mName = "Simple Shader"; - gObjectSimpleProgram.mFeatures.calculatesLighting = true; - gObjectSimpleProgram.mFeatures.calculatesAtmospherics = true; - gObjectSimpleProgram.mFeatures.hasGamma = true; - gObjectSimpleProgram.mFeatures.hasAtmospherics = true; - gObjectSimpleProgram.mFeatures.hasLighting = true; - gObjectSimpleProgram.mFeatures.mIndexedTextureChannels = 0; - gObjectSimpleProgram.mShaderFiles.clear(); - gObjectSimpleProgram.mShaderFiles.push_back(make_pair("objects/simpleV.glsl", GL_VERTEX_SHADER_ARB)); - gObjectSimpleProgram.mShaderFiles.push_back(make_pair("objects/simpleF.glsl", GL_FRAGMENT_SHADER_ARB)); - gObjectSimpleProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; - success = gObjectSimpleProgram.createShader(NULL, NULL); - } + for(U32 i = 0; i < (U32)1< 0) - { //load hardware skinned attachment shaders - if (success) - { - gSkinnedObjectSimpleProgram.mName = "Skinned Simple Shader"; - gSkinnedObjectSimpleProgram.mFeatures.calculatesLighting = true; - gSkinnedObjectSimpleProgram.mFeatures.calculatesAtmospherics = true; - gSkinnedObjectSimpleProgram.mFeatures.hasGamma = true; - gSkinnedObjectSimpleProgram.mFeatures.hasAtmospherics = true; - gSkinnedObjectSimpleProgram.mFeatures.hasLighting = true; - gSkinnedObjectSimpleProgram.mFeatures.hasObjectSkinning = true; - gSkinnedObjectSimpleProgram.mFeatures.disableTextureIndex = true; - gSkinnedObjectSimpleProgram.mShaderFiles.clear(); - gSkinnedObjectSimpleProgram.mShaderFiles.push_back(make_pair("objects/simpleSkinnedV.glsl", GL_VERTEX_SHADER_ARB)); - gSkinnedObjectSimpleProgram.mShaderFiles.push_back(make_pair("objects/simpleF.glsl", GL_FRAGMENT_SHADER_ARB)); - gSkinnedObjectSimpleProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; - success = gSkinnedObjectSimpleProgram.createShader(NULL, NULL); - } - - if (success) - { - gSkinnedObjectFullbrightProgram.mName = "Skinned Fullbright Shader"; - gSkinnedObjectFullbrightProgram.mFeatures.calculatesAtmospherics = true; - gSkinnedObjectFullbrightProgram.mFeatures.hasGamma = true; - gSkinnedObjectFullbrightProgram.mFeatures.hasTransport = true; - gSkinnedObjectFullbrightProgram.mFeatures.isFullbright = true; - gSkinnedObjectFullbrightProgram.mFeatures.hasObjectSkinning = true; - gSkinnedObjectFullbrightProgram.mFeatures.disableTextureIndex = true; - gSkinnedObjectFullbrightProgram.mShaderFiles.clear(); - gSkinnedObjectFullbrightProgram.mShaderFiles.push_back(make_pair("objects/fullbrightSkinnedV.glsl", GL_VERTEX_SHADER_ARB)); - gSkinnedObjectFullbrightProgram.mShaderFiles.push_back(make_pair("objects/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB)); - gSkinnedObjectFullbrightProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; - success = gSkinnedObjectFullbrightProgram.createShader(NULL, NULL); - } - - if (success) - { - gSkinnedObjectEmissiveProgram.mName = "Skinned Emissive Shader"; - gSkinnedObjectEmissiveProgram.mFeatures.calculatesAtmospherics = true; - gSkinnedObjectEmissiveProgram.mFeatures.hasGamma = true; - gSkinnedObjectEmissiveProgram.mFeatures.hasTransport = true; - gSkinnedObjectEmissiveProgram.mFeatures.isFullbright = true; - gSkinnedObjectEmissiveProgram.mFeatures.hasObjectSkinning = true; - gSkinnedObjectEmissiveProgram.mFeatures.disableTextureIndex = true; - gSkinnedObjectEmissiveProgram.mShaderFiles.clear(); - gSkinnedObjectEmissiveProgram.mShaderFiles.push_back(make_pair("objects/emissiveSkinnedV.glsl", GL_VERTEX_SHADER_ARB)); - gSkinnedObjectEmissiveProgram.mShaderFiles.push_back(make_pair("objects/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB)); - gSkinnedObjectEmissiveProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; - success = gSkinnedObjectEmissiveProgram.createShader(NULL, NULL); - } - - if (success) - { - gSkinnedObjectEmissiveWaterProgram.mName = "Skinned Emissive Water Shader"; - gSkinnedObjectEmissiveWaterProgram.mFeatures.calculatesAtmospherics = true; - gSkinnedObjectEmissiveWaterProgram.mFeatures.hasGamma = true; - gSkinnedObjectEmissiveWaterProgram.mFeatures.hasTransport = true; - gSkinnedObjectEmissiveWaterProgram.mFeatures.isFullbright = true; - gSkinnedObjectEmissiveWaterProgram.mFeatures.hasObjectSkinning = true; - gSkinnedObjectEmissiveWaterProgram.mFeatures.disableTextureIndex = true; - gSkinnedObjectEmissiveWaterProgram.mFeatures.hasWaterFog = true; - gSkinnedObjectEmissiveWaterProgram.mShaderFiles.clear(); - gSkinnedObjectEmissiveWaterProgram.mShaderFiles.push_back(make_pair("objects/emissiveSkinnedV.glsl", GL_VERTEX_SHADER_ARB)); - gSkinnedObjectEmissiveWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightWaterF.glsl", GL_FRAGMENT_SHADER_ARB)); - gSkinnedObjectEmissiveWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; - success = gSkinnedObjectEmissiveWaterProgram.createShader(NULL, NULL); - } - - if (success) - { - gSkinnedObjectFullbrightShinyProgram.mName = "Skinned Fullbright Shiny Shader"; - gSkinnedObjectFullbrightShinyProgram.mFeatures.calculatesAtmospherics = true; - gSkinnedObjectFullbrightShinyProgram.mFeatures.hasGamma = true; - gSkinnedObjectFullbrightShinyProgram.mFeatures.hasTransport = true; - gSkinnedObjectFullbrightShinyProgram.mFeatures.isShiny = true; - gSkinnedObjectFullbrightShinyProgram.mFeatures.isFullbright = true; - gSkinnedObjectFullbrightShinyProgram.mFeatures.hasObjectSkinning = true; - gSkinnedObjectFullbrightShinyProgram.mFeatures.disableTextureIndex = true; - gSkinnedObjectFullbrightShinyProgram.mShaderFiles.clear(); - gSkinnedObjectFullbrightShinyProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinySkinnedV.glsl", GL_VERTEX_SHADER_ARB)); - gSkinnedObjectFullbrightShinyProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyF.glsl", GL_FRAGMENT_SHADER_ARB)); - gSkinnedObjectFullbrightShinyProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; - success = gSkinnedObjectFullbrightShinyProgram.createShader(NULL, &mShinyUniforms); - } - - if (success) - { - gSkinnedObjectShinySimpleProgram.mName = "Skinned Shiny Simple Shader"; - gSkinnedObjectShinySimpleProgram.mFeatures.calculatesLighting = true; - gSkinnedObjectShinySimpleProgram.mFeatures.calculatesAtmospherics = true; - gSkinnedObjectShinySimpleProgram.mFeatures.hasGamma = true; - gSkinnedObjectShinySimpleProgram.mFeatures.hasAtmospherics = true; - gSkinnedObjectShinySimpleProgram.mFeatures.hasObjectSkinning = true; - gSkinnedObjectShinySimpleProgram.mFeatures.isShiny = true; - gSkinnedObjectShinySimpleProgram.mFeatures.disableTextureIndex = true; - gSkinnedObjectShinySimpleProgram.mShaderFiles.clear(); - gSkinnedObjectShinySimpleProgram.mShaderFiles.push_back(make_pair("objects/shinySimpleSkinnedV.glsl", GL_VERTEX_SHADER_ARB)); - gSkinnedObjectShinySimpleProgram.mShaderFiles.push_back(make_pair("objects/shinyF.glsl", GL_FRAGMENT_SHADER_ARB)); - gSkinnedObjectShinySimpleProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; - success = gSkinnedObjectShinySimpleProgram.createShader(NULL, &mShinyUniforms); - } - - if (success) - { - gSkinnedObjectSimpleWaterProgram.mName = "Skinned Simple Water Shader"; - gSkinnedObjectSimpleWaterProgram.mFeatures.calculatesLighting = true; - gSkinnedObjectSimpleWaterProgram.mFeatures.calculatesAtmospherics = true; - gSkinnedObjectSimpleWaterProgram.mFeatures.hasGamma = true; - gSkinnedObjectSimpleWaterProgram.mFeatures.hasAtmospherics = true; - gSkinnedObjectSimpleWaterProgram.mFeatures.hasLighting = true; - gSkinnedObjectSimpleWaterProgram.mFeatures.disableTextureIndex = true; - gSkinnedObjectSimpleWaterProgram.mFeatures.hasWaterFog = true; - gSkinnedObjectSimpleWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; - gSkinnedObjectSimpleWaterProgram.mFeatures.hasObjectSkinning = true; - gSkinnedObjectSimpleWaterProgram.mFeatures.disableTextureIndex = true; - gSkinnedObjectSimpleWaterProgram.mShaderFiles.clear(); - gSkinnedObjectSimpleWaterProgram.mShaderFiles.push_back(make_pair("objects/simpleSkinnedV.glsl", GL_VERTEX_SHADER_ARB)); - gSkinnedObjectSimpleWaterProgram.mShaderFiles.push_back(make_pair("objects/simpleWaterF.glsl", GL_FRAGMENT_SHADER_ARB)); - gSkinnedObjectSimpleWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; - success = gSkinnedObjectSimpleWaterProgram.createShader(NULL, NULL); - } - - if (success) - { - gSkinnedObjectFullbrightWaterProgram.mName = "Skinned Fullbright Water Shader"; - gSkinnedObjectFullbrightWaterProgram.mFeatures.calculatesAtmospherics = true; - gSkinnedObjectFullbrightWaterProgram.mFeatures.hasGamma = true; - gSkinnedObjectFullbrightWaterProgram.mFeatures.hasTransport = true; - gSkinnedObjectFullbrightWaterProgram.mFeatures.isFullbright = true; - gSkinnedObjectFullbrightWaterProgram.mFeatures.hasObjectSkinning = true; - gSkinnedObjectFullbrightWaterProgram.mFeatures.hasWaterFog = true; - gSkinnedObjectFullbrightWaterProgram.mFeatures.disableTextureIndex = true; - gSkinnedObjectFullbrightWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; - gSkinnedObjectFullbrightWaterProgram.mShaderFiles.clear(); - gSkinnedObjectFullbrightWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightSkinnedV.glsl", GL_VERTEX_SHADER_ARB)); - gSkinnedObjectFullbrightWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightWaterF.glsl", GL_FRAGMENT_SHADER_ARB)); - gSkinnedObjectFullbrightWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; - success = gSkinnedObjectFullbrightWaterProgram.createShader(NULL, NULL); - } - - if (success) - { - gSkinnedObjectFullbrightShinyWaterProgram.mName = "Skinned Fullbright Shiny Water Shader"; - gSkinnedObjectFullbrightShinyWaterProgram.mFeatures.calculatesAtmospherics = true; - gSkinnedObjectFullbrightShinyWaterProgram.mFeatures.hasGamma = true; - gSkinnedObjectFullbrightShinyWaterProgram.mFeatures.hasTransport = true; - gSkinnedObjectFullbrightShinyWaterProgram.mFeatures.isShiny = true; - gSkinnedObjectFullbrightShinyWaterProgram.mFeatures.isFullbright = true; - gSkinnedObjectFullbrightShinyWaterProgram.mFeatures.hasObjectSkinning = true; - gSkinnedObjectFullbrightShinyWaterProgram.mFeatures.hasWaterFog = true; - gSkinnedObjectFullbrightShinyWaterProgram.mFeatures.disableTextureIndex = true; - gSkinnedObjectFullbrightShinyWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; - gSkinnedObjectFullbrightShinyWaterProgram.mShaderFiles.clear(); - gSkinnedObjectFullbrightShinyWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinySkinnedV.glsl", GL_VERTEX_SHADER_ARB)); - gSkinnedObjectFullbrightShinyWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyWaterF.glsl", GL_FRAGMENT_SHADER_ARB)); - gSkinnedObjectFullbrightShinyWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; - success = gSkinnedObjectFullbrightShinyWaterProgram.createShader(NULL, &mShinyUniforms); - } - - if (success) - { - gSkinnedObjectShinySimpleWaterProgram.mName = "Skinned Shiny Simple Water Shader"; - gSkinnedObjectShinySimpleWaterProgram.mFeatures.calculatesLighting = true; - gSkinnedObjectShinySimpleWaterProgram.mFeatures.calculatesAtmospherics = true; - gSkinnedObjectShinySimpleWaterProgram.mFeatures.hasGamma = true; - gSkinnedObjectShinySimpleWaterProgram.mFeatures.hasAtmospherics = true; - gSkinnedObjectShinySimpleWaterProgram.mFeatures.hasObjectSkinning = true; - gSkinnedObjectShinySimpleWaterProgram.mFeatures.isShiny = true; - gSkinnedObjectShinySimpleWaterProgram.mFeatures.hasWaterFog = true; - gSkinnedObjectShinySimpleWaterProgram.mFeatures.disableTextureIndex = true; - gSkinnedObjectShinySimpleWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; - gSkinnedObjectShinySimpleWaterProgram.mShaderFiles.clear(); - gSkinnedObjectShinySimpleWaterProgram.mShaderFiles.push_back(make_pair("objects/shinySimpleSkinnedV.glsl", GL_VERTEX_SHADER_ARB)); - gSkinnedObjectShinySimpleWaterProgram.mShaderFiles.push_back(make_pair("objects/shinyWaterF.glsl", GL_FRAGMENT_SHADER_ARB)); - gSkinnedObjectShinySimpleWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; - success = gSkinnedObjectShinySimpleWaterProgram.createShader(NULL, &mShinyUniforms); - } - } - - if( !success ) + if (!success) { mVertexShaderLevel[SHADER_OBJECT] = 0; - return FALSE; + unloadShaderClass(SHADER_OBJECT); } - return TRUE; + return success; } BOOL LLViewerShaderMgr::loadShadersAvatar() @@ -2370,7 +2128,7 @@ BOOL LLViewerShaderMgr::loadShadersAvatar() gAvatarProgram.mShaderFiles.push_back(make_pair("avatar/avatarV.glsl", GL_VERTEX_SHADER_ARB)); gAvatarProgram.mShaderFiles.push_back(make_pair("avatar/avatarF.glsl", GL_FRAGMENT_SHADER_ARB)); gAvatarProgram.mShaderLevel = mVertexShaderLevel[SHADER_AVATAR]; - success = gAvatarProgram.createShader(NULL, &mAvatarUniforms); + success = gAvatarProgram.createShader(NULL, NULL); if (success) { @@ -2389,54 +2147,17 @@ BOOL LLViewerShaderMgr::loadShadersAvatar() // Note: no cloth under water: gAvatarWaterProgram.mShaderLevel = llmin(mVertexShaderLevel[SHADER_AVATAR], 1); gAvatarWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; - success = gAvatarWaterProgram.createShader(NULL, &mAvatarUniforms); - } - - /// Keep track of avatar levels - if (gAvatarProgram.mShaderLevel != mVertexShaderLevel[SHADER_AVATAR]) - { - mMaxAvatarShaderLevel = mVertexShaderLevel[SHADER_AVATAR] = gAvatarProgram.mShaderLevel; + success = gAvatarWaterProgram.createShader(NULL, NULL); } } - if (success) - { - gAvatarPickProgram.mName = "Avatar Pick Shader"; - gAvatarPickProgram.mFeatures.hasSkinning = true; - gAvatarPickProgram.mFeatures.disableTextureIndex = true; - gAvatarPickProgram.mShaderFiles.clear(); - gAvatarPickProgram.mShaderFiles.push_back(make_pair("avatar/pickAvatarV.glsl", GL_VERTEX_SHADER_ARB)); - gAvatarPickProgram.mShaderFiles.push_back(make_pair("avatar/pickAvatarF.glsl", GL_FRAGMENT_SHADER_ARB)); - gAvatarPickProgram.mShaderLevel = mVertexShaderLevel[SHADER_AVATAR]; - success = gAvatarPickProgram.createShader(NULL, &mAvatarUniforms); - } - - if (success) - { - /*gAvatarEyeballProgram.mName = "Avatar Eyeball Program"; - gAvatarEyeballProgram.mFeatures.calculatesLighting = true; - gAvatarEyeballProgram.mFeatures.isSpecular = true; - gAvatarEyeballProgram.mFeatures.calculatesAtmospherics = true; - gAvatarEyeballProgram.mFeatures.hasGamma = true; - gAvatarEyeballProgram.mFeatures.hasAtmospherics = true; - gAvatarEyeballProgram.mFeatures.hasLighting = true; - gAvatarEyeballProgram.mFeatures.hasAlphaMask = true; - gAvatarEyeballProgram.mFeatures.disableTextureIndex = true; - gAvatarEyeballProgram.mShaderFiles.clear(); - gAvatarEyeballProgram.mShaderFiles.push_back(make_pair("avatar/eyeballV.glsl", GL_VERTEX_SHADER_ARB)); - gAvatarEyeballProgram.mShaderFiles.push_back(make_pair("avatar/eyeballF.glsl", GL_FRAGMENT_SHADER_ARB)); - gAvatarEyeballProgram.mShaderLevel = mVertexShaderLevel[SHADER_AVATAR]; - success = gAvatarEyeballProgram.createShader(NULL, NULL);*/ - } - if( !success ) { mVertexShaderLevel[SHADER_AVATAR] = 0; - mMaxAvatarShaderLevel = 0; - return FALSE; + unloadShaderClass(SHADER_AVATAR); } - return TRUE; + return success; } BOOL LLViewerShaderMgr::loadShadersInterface() @@ -2459,6 +2180,26 @@ BOOL LLViewerShaderMgr::loadShadersInterface() success = gHighlightProgram.createShader(NULL, NULL); } + if (success) + { + gHighlightNormalProgram.mName = "Highlight Normals Shader"; + gHighlightNormalProgram.mShaderFiles.clear(); + gHighlightNormalProgram.mShaderFiles.push_back(make_pair("interface/highlightNormV.glsl", GL_VERTEX_SHADER_ARB)); + gHighlightNormalProgram.mShaderFiles.push_back(make_pair("interface/highlightF.glsl", GL_FRAGMENT_SHADER_ARB)); + gHighlightNormalProgram.mShaderLevel = mVertexShaderLevel[SHADER_INTERFACE]; + success = gHighlightNormalProgram.createShader(NULL, NULL); + } + + if (success) + { + gHighlightSpecularProgram.mName = "Highlight Spec Shader"; + gHighlightSpecularProgram.mShaderFiles.clear(); + gHighlightSpecularProgram.mShaderFiles.push_back(make_pair("interface/highlightSpecV.glsl", GL_VERTEX_SHADER_ARB)); + gHighlightSpecularProgram.mShaderFiles.push_back(make_pair("interface/highlightF.glsl", GL_FRAGMENT_SHADER_ARB)); + gHighlightSpecularProgram.mShaderLevel = mVertexShaderLevel[SHADER_INTERFACE]; + success = gHighlightSpecularProgram.createShader(NULL, NULL); + } + if (success) { gUIProgram.mName = "UI Shader"; @@ -2490,7 +2231,7 @@ BOOL LLViewerShaderMgr::loadShadersInterface() if (success) { gSplatTextureRectProgram.bind(); - gSplatTextureRectProgram.uniform1i("screenMap", 0); + gSplatTextureRectProgram.uniform1i(sScreenMap, 0); gSplatTextureRectProgram.unbind(); } } @@ -2506,8 +2247,8 @@ BOOL LLViewerShaderMgr::loadShadersInterface() if (success) { gGlowCombineProgram.bind(); - gGlowCombineProgram.uniform1i("glowMap", 0); - gGlowCombineProgram.uniform1i("screenMap", 1); + gGlowCombineProgram.uniform1i(sGlowMap, 0); + gGlowCombineProgram.uniform1i(sScreenMap, 1); gGlowCombineProgram.unbind(); } } @@ -2523,8 +2264,8 @@ BOOL LLViewerShaderMgr::loadShadersInterface() if (success) { gGlowCombineFXAAProgram.bind(); - gGlowCombineFXAAProgram.uniform1i("glowMap", 0); - gGlowCombineFXAAProgram.uniform1i("screenMap", 1); + gGlowCombineFXAAProgram.uniform1i(sGlowMap, 0); + gGlowCombineFXAAProgram.uniform1i(sScreenMap, 1); gGlowCombineFXAAProgram.unbind(); } } @@ -2541,8 +2282,8 @@ BOOL LLViewerShaderMgr::loadShadersInterface() if (success) { gTwoTextureAddProgram.bind(); - gTwoTextureAddProgram.uniform1i("tex0", 0); - gTwoTextureAddProgram.uniform1i("tex1", 1); + gTwoTextureAddProgram.uniform1i(sTex0, 0); + gTwoTextureAddProgram.uniform1i(sTex1, 1); } } @@ -2557,7 +2298,7 @@ BOOL LLViewerShaderMgr::loadShadersInterface() if (success) { gOneTextureNoColorProgram.bind(); - gOneTextureNoColorProgram.uniform1i("tex0", 0); + gOneTextureNoColorProgram.uniform1i(sTex0, 0); } } @@ -2577,7 +2318,7 @@ BOOL LLViewerShaderMgr::loadShadersInterface() if (success) { gSolidColorProgram.bind(); - gSolidColorProgram.uniform1i("tex0", 0); + gSolidColorProgram.uniform1i(sTex0, 0); gSolidColorProgram.unbind(); } } @@ -2622,6 +2363,16 @@ BOOL LLViewerShaderMgr::loadShadersInterface() success = gClipProgram.createShader(NULL, NULL); } + if (success) + { + gDownsampleDepthProgram.mName = "DownsampleDepth Shader"; + gDownsampleDepthProgram.mShaderFiles.clear(); + gDownsampleDepthProgram.mShaderFiles.push_back(make_pair("interface/downsampleDepthV.glsl", GL_VERTEX_SHADER_ARB)); + gDownsampleDepthProgram.mShaderFiles.push_back(make_pair("interface/downsampleDepthF.glsl", GL_FRAGMENT_SHADER_ARB)); + gDownsampleDepthProgram.mShaderLevel = mVertexShaderLevel[SHADER_INTERFACE]; + success = gDownsampleDepthProgram.createShader(NULL, NULL); + } + if (success) { gAlphaMaskProgram.mName = "Alpha Mask Shader"; @@ -2632,13 +2383,13 @@ BOOL LLViewerShaderMgr::loadShadersInterface() success = gAlphaMaskProgram.createShader(NULL, NULL); } - if( !success ) + if (!success) { mVertexShaderLevel[SHADER_INTERFACE] = 0; - return FALSE; + unloadShaderClass(SHADER_INTERFACE); } - - return TRUE; + + return success; } BOOL LLViewerShaderMgr::loadShadersWindLight() @@ -2660,7 +2411,7 @@ BOOL LLViewerShaderMgr::loadShadersWindLight() gWLSkyProgram.mShaderFiles.push_back(make_pair("windlight/skyF.glsl", GL_FRAGMENT_SHADER_ARB)); gWLSkyProgram.mShaderLevel = mVertexShaderLevel[SHADER_WINDLIGHT]; gWLSkyProgram.mShaderGroup = LLGLSLShader::SG_SKY; - success = gWLSkyProgram.createShader(NULL, &mWLUniforms); + success = gWLSkyProgram.createShader(NULL, NULL); } if (success) @@ -2672,7 +2423,13 @@ BOOL LLViewerShaderMgr::loadShadersWindLight() gWLCloudProgram.mShaderFiles.push_back(make_pair("windlight/cloudsF.glsl", GL_FRAGMENT_SHADER_ARB)); gWLCloudProgram.mShaderLevel = mVertexShaderLevel[SHADER_WINDLIGHT]; gWLCloudProgram.mShaderGroup = LLGLSLShader::SG_SKY; - success = gWLCloudProgram.createShader(NULL, &mWLUniforms); + success = gWLCloudProgram.createShader(NULL, NULL); + } + + if (!success) + { + mVertexShaderLevel[SHADER_WINDLIGHT] = 0; + unloadShaderClass(SHADER_WINDLIGHT); } return success; @@ -2747,18 +2504,24 @@ BOOL LLViewerShaderMgr::loadTransformShaders() if (success) { - gTransformBinormalProgram.mName = "Binormal Transform Shader"; - gTransformBinormalProgram.mShaderFiles.clear(); - gTransformBinormalProgram.mShaderFiles.push_back(make_pair("transform/binormalV.glsl", GL_VERTEX_SHADER_ARB)); - gTransformBinormalProgram.mShaderLevel = mVertexShaderLevel[SHADER_TRANSFORM]; + gTransformTangentProgram.mName = "Binormal Transform Shader"; + gTransformTangentProgram.mShaderFiles.clear(); + gTransformTangentProgram.mShaderFiles.push_back(make_pair("transform/binormalV.glsl", GL_VERTEX_SHADER_ARB)); + gTransformTangentProgram.mShaderLevel = mVertexShaderLevel[SHADER_TRANSFORM]; const char* varyings[] = { - "binormal_out", + "tangent_out", }; - success = gTransformBinormalProgram.createShader(NULL, NULL, 1, varyings); + success = gTransformTangentProgram.createShader(NULL, NULL, 1, varyings); } + + if (!success) + { + mVertexShaderLevel[SHADER_TRANSFORM] = 0; + unloadShaderClass(SHADER_TRANSFORM); + } return success; } @@ -2774,6 +2537,17 @@ void LLViewerShaderMgr::updateShaderUniforms(LLGLSLShader * shader) LLWaterParamManager::getInstance()->updateShaderUniforms(shader); } +/* virtual */ bool LLViewerShaderMgr::attachClassSharedShaders(LLGLSLShader& shader, S32 shader_class) +{ + switch (shader_class) + { + case LLViewerShaderMgr::SHADER_DEFERRED: + LL_INFOS() << "deferred/components/utilityFuncF.glsl" << LL_ENDL; + return shader.attachObject("deferred/components/utilityFuncF.glsl"); + } + return true; +} + /*static*/ void LLShaderMgr::unloadShaderClass(int shader_class) { std::vector &shader_list = getGlobalShaderList(); diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h index d41fb5f78c..e39380f169 100644 --- a/indra/newview/llviewershadermgr.h +++ b/indra/newview/llviewershadermgr.h @@ -2,31 +2,25 @@ * @file llviewershadermgr.h * @brief Viewer Shader Manager * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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$ */ @@ -34,6 +28,19 @@ #define LL_VIEWER_SHADER_MGR_H #include "llshadermgr.h" +#include "llmaterial.h" + +#define LL_DEFERRED_MULTI_LIGHT_COUNT 16 + +enum +{ + SHD_ALPHA_MASK_BIT = 0, + SHD_WATER_BIT, + SHD_NO_INDEX_BIT, + SHD_SKIN_BIT, + SHD_SHINY_BIT, + SHD_COUNT +}; class LLViewerShaderMgr: public LLShaderMgr { @@ -63,7 +70,6 @@ class LLViewerShaderMgr: public LLShaderMgr BOOL loadTransformShaders(); std::vector mVertexShaderLevel; - S32 mMaxAvatarShaderLevel; enum EShaderClass { @@ -80,57 +86,6 @@ class LLViewerShaderMgr: public LLShaderMgr SHADER_COUNT }; - typedef enum - { - SHINY_ORIGIN = END_RESERVED_UNIFORMS - } eShinyUniforms; - - typedef enum - { - WATER_SCREENTEX = END_RESERVED_UNIFORMS, - WATER_SCREENDEPTH, - WATER_REFTEX, - WATER_EYEVEC, - WATER_TIME, - WATER_WAVE_DIR1, - WATER_WAVE_DIR2, - WATER_LIGHT_DIR, - WATER_SPECULAR, - WATER_SPECULAR_EXP, - WATER_FOGCOLOR, - WATER_FOGDENSITY, - WATER_REFSCALE, - WATER_WATERHEIGHT, - } eWaterUniforms; - - typedef enum - { - WL_CAMPOSLOCAL = END_RESERVED_UNIFORMS, - WL_WATERHEIGHT - } eWLUniforms; - - typedef enum - { - TERRAIN_DETAIL0 = END_RESERVED_UNIFORMS, - TERRAIN_DETAIL1, - TERRAIN_DETAIL2, - TERRAIN_DETAIL3, - TERRAIN_ALPHARAMP - } eTerrainUniforms; - - typedef enum - { - GLOW_DELTA = END_RESERVED_UNIFORMS - } eGlowUniforms; - - typedef enum - { - AVATAR_MATRIX = END_RESERVED_UNIFORMS, - AVATAR_WIND, - AVATAR_SINWAVE, - AVATAR_GRAVITY, - } eAvatarUniforms; - // simple model of forward iterator // http://www.sgi.com/tech/stl/ForwardIterator.html class shader_iter @@ -191,6 +146,8 @@ class LLViewerShaderMgr: public LLShaderMgr /* virtual */ void updateShaderUniforms(LLGLSLShader * shader); // Virtual + /* virtual */ bool attachClassSharedShaders(LLGLSLShader& shader, S32 shader_class); // Virtual + private: std::vector mShinyUniforms; @@ -229,12 +186,21 @@ inline bool operator != (LLViewerShaderMgr::shader_iter const & a, LLViewerShade extern LLVector4 gShinyOrigin; +//For arrays, since default ctor must be used for them. +template +class LLGLSLShaderArray : public LLGLSLShader +{ +public: + LLGLSLShaderArray() : LLGLSLShader(type) {}; +}; + //transform shaders extern LLGLSLShader gTransformPositionProgram; extern LLGLSLShader gTransformTexCoordProgram; extern LLGLSLShader gTransformNormalProgram; extern LLGLSLShader gTransformColorProgram; -extern LLGLSLShader gTransformBinormalProgram; +extern LLGLSLShader gTransformTangentProgram; + //utility shaders extern LLGLSLShader gOcclusionProgram; extern LLGLSLShader gOcclusionCubeProgram; @@ -244,7 +210,7 @@ extern LLGLSLShader gSplatTextureRectProgram; extern LLGLSLShader gGlowCombineFXAAProgram; extern LLGLSLShader gDebugProgram; extern LLGLSLShader gClipProgram; -extern LLGLSLShader gAlphaMaskProgram; +extern LLGLSLShader gDownsampleDepthProgram; //output tex0[tc0] + tex1[tc1] extern LLGLSLShader gTwoTextureAddProgram; @@ -252,31 +218,17 @@ extern LLGLSLShader gTwoTextureAddProgram; extern LLGLSLShader gOneTextureNoColorProgram; //object shaders -extern LLGLSLShader gObjectSimpleProgram; + +extern LLGLSLShaderArray gObjectSimpleProgram[1< gObjectFullbrightProgram[1< gObjectEmissiveProgram[1< gDeferredMultiLightProgram[LL_DEFERRED_MULTI_LIGHT_COUNT]; extern LLGLSLShader gDeferredSpotLightProgram; extern LLGLSLShader gDeferredMultiSpotLightProgram; extern LLGLSLShader gDeferredSunProgram; +extern LLGLSLShader gDeferredSSAOProgram; +extern LLGLSLShader gDeferredDownsampleDepthNearestProgram; extern LLGLSLShader gDeferredBlurLightProgram; extern LLGLSLShader gDeferredAvatarProgram; extern LLGLSLShader gDeferredSoftenProgram; +extern LLGLSLShader gDeferredSoftenWaterProgram; extern LLGLSLShader gDeferredShadowProgram; extern LLGLSLShader gDeferredShadowCubeProgram; extern LLGLSLShader gDeferredShadowAlphaMaskProgram; @@ -364,15 +298,27 @@ extern LLGLSLShader gDeferredCoFProgram; extern LLGLSLShader gDeferredDoFCombineProgram; extern LLGLSLShader gFXAAProgram; extern LLGLSLShader gDeferredPostNoDoFProgram; +extern LLGLSLShader gDeferredPostGammaCorrectProgram; extern LLGLSLShader gDeferredAvatarShadowProgram; extern LLGLSLShader gDeferredAttachmentShadowProgram; extern LLGLSLShader gDeferredAlphaProgram; +extern LLGLSLShader gDeferredAlphaImpostorProgram; extern LLGLSLShader gDeferredFullbrightProgram; +extern LLGLSLShader gDeferredFullbrightAlphaMaskProgram; +extern LLGLSLShader gDeferredAlphaWaterProgram; +extern LLGLSLShader gDeferredFullbrightWaterProgram; +extern LLGLSLShader gDeferredFullbrightAlphaMaskWaterProgram; extern LLGLSLShader gDeferredEmissiveProgram; extern LLGLSLShader gDeferredAvatarAlphaProgram; extern LLGLSLShader gDeferredWLSkyProgram; extern LLGLSLShader gDeferredWLCloudProgram; extern LLGLSLShader gDeferredStarProgram; +extern LLGLSLShader gDeferredFullbrightShinyProgram; +extern LLGLSLShader gDeferredSkinnedFullbrightShinyProgram; +extern LLGLSLShader gDeferredSkinnedFullbrightProgram; extern LLGLSLShader gNormalMapGenProgram; +// Deferred materials shaders +extern LLGLSLShaderArray gDeferredMaterialProgram[LLMaterial::SHADER_COUNT*2]; +extern LLGLSLShaderArray gDeferredMaterialWaterProgram[LLMaterial::SHADER_COUNT*2]; #endif diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp index 4728f0ffd4..15023ff5d5 100644 --- a/indra/newview/llviewerstats.cpp +++ b/indra/newview/llviewerstats.cpp @@ -51,6 +51,7 @@ #include "llagentcamera.h" #include "llviewercontrol.h" #include "llfloaterdirectory.h" +#include "llversioninfo.h" #include "llfloatertools.h" #include "lldebugview.h" #include "llfasttimerview.h" @@ -405,14 +406,14 @@ void LLViewerStats::addToMessage(LLSD &body) const { // TODO: send timer value so dataserver can normalize misc[STAT_INFO[i].mName] = mStats[i]; - llinfos << "STAT: " << STAT_INFO[i].mName << ": " << mStats[i] - << llendl; + LL_INFOS() << "STAT: " << STAT_INFO[i].mName << ": " << mStats[i] + << LL_ENDL; } } body["AgentPositionSnaps"] = mAgentPositionSnaps.getData(); - llinfos << "STAT: AgentPositionSnaps: Mean = " << mAgentPositionSnaps.getMean() << "; StdDev = " << mAgentPositionSnaps.getStdDev() - << "; Count = " << mAgentPositionSnaps.getCount() << llendl; + LL_INFOS() << "STAT: AgentPositionSnaps: Mean = " << mAgentPositionSnaps.getMean() << "; StdDev = " << mAgentPositionSnaps.getStdDev() + << "; Count = " << mAgentPositionSnaps.getCount() << LL_ENDL; } // static @@ -443,29 +444,29 @@ void reset_statistics() void output_statistics(void*) { - S32 global_raw_memory; + S64 global_raw_memory; { - global_raw_memory = *AIAccess(LLImageRaw::sGlobalRawMemory); + global_raw_memory = *AIAccess(LLImageRaw::sGlobalRawMemory); } - llinfos << "Number of orphans: " << gObjectList.getOrphanCount() << llendl; - llinfos << "Number of dead objects: " << gObjectList.mNumDeadObjects << llendl; - llinfos << "Num images: " << gTextureList.getNumImages() << llendl; - llinfos << "Texture usage: " << LLImageGL::sGlobalTextureMemoryInBytes << llendl; - llinfos << "Texture working set: " << LLImageGL::sBoundTextureMemoryInBytes << llendl; - llinfos << "Raw usage: " << global_raw_memory << llendl; - llinfos << "Formatted usage: " << LLImageFormatted::sGlobalFormattedMemory << llendl; - llinfos << "Zombie Viewer Objects: " << LLViewerObject::getNumZombieObjects() << llendl; - llinfos << "Number of lights: " << gPipeline.getLightCount() << llendl; + LL_INFOS() << "Number of orphans: " << gObjectList.getOrphanCount() << LL_ENDL; + LL_INFOS() << "Number of dead objects: " << gObjectList.mNumDeadObjects << LL_ENDL; + LL_INFOS() << "Num images: " << gTextureList.getNumImages() << LL_ENDL; + LL_INFOS() << "Texture usage: " << LLImageGL::sGlobalTextureMemory.value() << LL_ENDL; + LL_INFOS() << "Texture working set: " << LLImageGL::sBoundTextureMemory.value() << LL_ENDL; + LL_INFOS() << "Raw usage: " << global_raw_memory << LL_ENDL; + LL_INFOS() << "Formatted usage: " << LLImageFormatted::sGlobalFormattedMemory << LL_ENDL; + LL_INFOS() << "Zombie Viewer Objects: " << LLViewerObject::getNumZombieObjects() << LL_ENDL; + LL_INFOS() << "Number of lights: " << gPipeline.getLightCount() << LL_ENDL; - llinfos << "Memory Usage:" << llendl; - llinfos << "--------------------------------" << llendl; - llinfos << "Pipeline:" << llendl; - llinfos << llendl; + LL_INFOS() << "Memory Usage:" << LL_ENDL; + LL_INFOS() << "--------------------------------" << LL_ENDL; + LL_INFOS() << "Pipeline:" << LL_ENDL; + LL_INFOS() << LL_ENDL; #if LL_SMARTHEAP - llinfos << "--------------------------------" << llendl; + LL_INFOS() << "--------------------------------" << LL_ENDL; { - llinfos << "sizeof(LLVOVolume) = " << sizeof(LLVOVolume) << llendl; + LL_INFOS() << "sizeof(LLVOVolume) = " << sizeof(LLVOVolume) << LL_ENDL; U32 total_pool_size = 0; U32 total_used_size = 0; @@ -476,35 +477,35 @@ void output_statistics(void*) pool_status != MEM_POOL_END; pool_status = MemPoolNext( &pool_info, 1 ) ) { - llinfos << "Pool #" << pool_num << llendl; + LL_INFOS() << "Pool #" << pool_num << LL_ENDL; if( MEM_POOL_OK != pool_status ) { - llwarns << "Pool not ok" << llendl; + LL_WARNS() << "Pool not ok" << LL_ENDL; continue; } - llinfos << "Pool blockSizeFS " << pool_info.blockSizeFS + LL_INFOS() << "Pool blockSizeFS " << pool_info.blockSizeFS << " pageSize " << pool_info.pageSize - << llendl; + << LL_ENDL; U32 pool_count = MemPoolCount(pool_info.pool); - llinfos << "Blocks " << pool_count << llendl; + LL_INFOS() << "Blocks " << pool_count << LL_ENDL; U32 pool_size = MemPoolSize( pool_info.pool ); if( pool_size == MEM_ERROR_RET ) { - llinfos << "MemPoolSize() failed (" << pool_num << ")" << llendl; + LL_INFOS() << "MemPoolSize() failed (" << pool_num << ")" << LL_ENDL; } else { - llinfos << "MemPool Size " << pool_size / 1024 << "K" << llendl; + LL_INFOS() << "MemPool Size " << pool_size / 1024 << "K" << LL_ENDL; } total_pool_size += pool_size; if( !MemPoolLock( pool_info.pool ) ) { - llinfos << "MemPoolLock failed (" << pool_num << ") " << llendl; + LL_INFOS() << "MemPoolLock failed (" << pool_num << ") " << LL_ENDL; continue; } @@ -521,29 +522,28 @@ void output_statistics(void*) MemPoolUnlock( pool_info.pool ); - llinfos << "MemPool Used " << used_size/1024 << "K" << llendl; + LL_INFOS() << "MemPool Used " << used_size/1024 << "K" << LL_ENDL; total_used_size += used_size; pool_num++; } - llinfos << "Total Pool Size " << total_pool_size/1024 << "K" << llendl; - llinfos << "Total Used Size " << total_used_size/1024 << "K" << llendl; + LL_INFOS() << "Total Pool Size " << total_pool_size/1024 << "K" << LL_ENDL; + LL_INFOS() << "Total Used Size " << total_used_size/1024 << "K" << LL_ENDL; } #endif - llinfos << "--------------------------------" << llendl; - llinfos << "Avatar Memory (partly overlaps with above stats):" << llendl; + LL_INFOS() << "--------------------------------" << LL_ENDL; + LL_INFOS() << "Avatar Memory (partly overlaps with above stats):" << LL_ENDL; LLTexLayerStaticImageList::getInstance()->dumpByteCount(); - LLVOAvatarSelf::dumpScratchTextureByteCount(); LLViewerTexLayerSetBuffer::dumpTotalByteCount(); LLVOAvatarSelf::dumpTotalLocalTextureByteCount(); LLTexLayerParamAlpha::dumpCacheByteCount(); LLVOAvatar::dumpBakedStatus(); - llinfos << llendl; + LL_INFOS() << LL_ENDL; - llinfos << "Object counts:" << llendl; + LL_INFOS() << "Object counts:" << LL_ENDL; S32 i; S32 obj_counts[256]; // S32 app_angles[256]; @@ -563,25 +563,31 @@ void output_statistics(void*) { if (obj_counts[i]) { - llinfos << LLPrimitive::pCodeToString(i) << ":" << obj_counts[i] << llendl; + LL_INFOS() << LLPrimitive::pCodeToString(i) << ":" << obj_counts[i] << LL_ENDL; } } } -U32 gTotalLandIn = 0, gTotalLandOut = 0; -U32 gTotalWaterIn = 0, gTotalWaterOut = 0; +U32 gTotalLandIn = 0, + gTotalLandOut = 0, + gTotalWaterIn = 0, + gTotalWaterOut = 0; -F32 gAveLandCompression = 0.f, gAveWaterCompression = 0.f; -F32 gBestLandCompression = 1.f, gBestWaterCompression = 1.f; -F32 gWorstLandCompression = 0.f, gWorstWaterCompression = 0.f; +F32 gAveLandCompression = 0.f, + gAveWaterCompression = 0.f, + gBestLandCompression = 1.f, + gBestWaterCompression = 1.f, + gWorstLandCompression = 0.f, + gWorstWaterCompression = 0.f; - - -U32 gTotalWorldBytes = 0, gTotalObjectBytes = 0, gTotalTextureBytes = 0, gSimPingCount = 0; -U32 gObjectBits = 0; -F32 gAvgSimPing = 0.f; -U32 gTotalTextureBytesPerBoostLevel[LLGLTexture::MAX_GL_IMAGE_CATEGORY] = {0}; +U32Bytes gTotalWorldData, + gTotalObjectData, + gTotalTextureData; +U32 gSimPingCount = 0; +U32Bits gObjectData; +F32Milliseconds gAvgSimPing(0.f); +U32Bytes gTotalTextureBytesPerBoostLevel[LLGLTexture::MAX_GL_IMAGE_CATEGORY] = {U32Bytes(0)}; extern U32 gVisCompared; extern U32 gVisTested; @@ -590,8 +596,8 @@ LLFrameTimer gTextureTimer; void update_statistics() { - gTotalWorldBytes += gVLManager.getTotalBytes(); - gTotalObjectBytes += gObjectBits / 8; + gTotalWorldData += U32Bytes(gVLManager.getTotalBytes()); + gTotalObjectData += gObjectData; LLViewerStats& stats = LLViewerStats::instance(); @@ -612,7 +618,7 @@ void update_statistics() } } stats.setStat(LLViewerStats::ST_ENABLE_VBO, (F64)gSavedSettings.getBOOL("RenderVBOEnable")); - stats.setStat(LLViewerStats::ST_LIGHTING_DETAIL, (F64)gPipeline.getLightingDetail()); + stats.setStat(LLViewerStats::ST_LIGHTING_DETAIL, (F64)gPipeline.isLocalLightingEnabled()); stats.setStat(LLViewerStats::ST_DRAW_DIST, (F64)gSavedSettings.getF32("RenderFarClip")); stats.setStat(LLViewerStats::ST_CHAT_BUBBLES, (F64)gSavedSettings.getBOOL("UseChatBubbles")); #if 0 // 1.9.2 @@ -632,8 +638,8 @@ void update_statistics() LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(gAgent.getRegion()->getHost()); if (cdp) { - stats.mSimPingStat.addValue(cdp->getPingDelay()); - gAvgSimPing = ((gAvgSimPing * (F32)gSimPingCount) + (F32)(cdp->getPingDelay())) / ((F32)gSimPingCount + 1); + stats.mSimPingStat.addValue(cdp->getPingDelay().value()); + gAvgSimPing = ((gAvgSimPing * gSimPingCount) + cdp->getPingDelay()) / (gSimPingCount + 1); gSimPingCount++; } else @@ -642,11 +648,11 @@ void update_statistics() } stats.mFPSStat.addValue(1); - F32 layer_bits = (F32)(gVLManager.getLandBits() + gVLManager.getWindBits() + gVLManager.getCloudBits()); - stats.mLayersKBitStat.addValue(layer_bits/1024.f); - stats.mObjectKBitStat.addValue(gObjectBits/1024.f); + F64Bits layer_bits = F64Bits(gVLManager.getLandBits() + gVLManager.getWindBits() + gVLManager.getCloudBits()); + stats.mLayersKBitStat.addValue((F32)layer_bits.valueInUnits()); + stats.mObjectKBitStat.addValue(gObjectData.valueInUnits()); stats.mVFSPendingOperations.addValue(LLVFile::getVFSThread()->getPending()); - stats.mAssetKBitStat.addValue(gTransferManager.getTransferBitsIn(LLTCT_ASSET)/1024.f); + stats.mAssetKBitStat.addValue(gTransferManager.getTransferBitsIn(LLTCT_ASSET) / 1024); gTransferManager.resetTransferBitsIn(LLTCT_ASSET); if (LLAppViewer::getTextureFetch()->getNumRequests() == 0) @@ -674,7 +680,7 @@ void update_statistics() // Reset all of these values. gVLManager.resetBitCounts(); - gObjectBits = 0; + gObjectData = (U32Bytes)0; // gDecodedBits = 0; // Only update texture stats periodically so that they are less noisy @@ -684,10 +690,10 @@ void update_statistics() if (texture_stats_timer.getElapsedTimeF32() >= texture_stats_freq) { stats.mHTTPTextureKBitStat.addValue(AICurlInterface::getHTTPBandwidth()/125.f); - stats.mUDPTextureKBitStat.addValue(LLViewerTextureList::sTextureBits/1024.f); + stats.mUDPTextureKBitStat.addValue(LLViewerTextureList::sTextureBits.valueInUnits()); stats.mTexturePacketsStat.addValue(LLViewerTextureList::sTexturePackets); - gTotalTextureBytes += LLViewerTextureList::sTextureBits / 8; - LLViewerTextureList::sTextureBits = 0; + gTotalTextureData += U32Bits(LLViewerTextureList::sTextureBits); + LLViewerTextureList::sTextureBits = U32Bits(0); LLViewerTextureList::sTexturePackets = 0; texture_stats_timer.reset(); } @@ -709,15 +715,15 @@ class ViewerStatsResponder : public LLHTTPClient::ResponderWithResult public: ViewerStatsResponder() { } - /*virtual*/ void error(U32 statusNum, const std::string& reason) + /*virtual*/ void httpFailure(void) { - llinfos << "ViewerStatsResponder::error " << statusNum << " " - << reason << llendl; + LL_INFOS() << "ViewerStatsResponder::error " << mStatus << " " + << mReason << LL_ENDL; } - /*virtual*/ void result(const LLSD& content) + /*virtual*/ void httpSuccess(void) { - llinfos << "ViewerStatsResponder::result" << llendl; + LL_INFOS() << "ViewerStatsResponder::result" << LL_ENDL; } /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return viewerStatsResponder_timeout; } @@ -750,7 +756,7 @@ void send_stats() std::string url = gAgent.getRegion()->getCapability("ViewerStats"); if (url.empty()) { - llwarns << "Could not get ViewerStats capability" << llendl; + LL_WARNS() << "Could not get ViewerStats capability" << LL_ENDL; return; } @@ -780,7 +786,7 @@ void send_stats() // send fps only for time app spends in foreground agent["fps"] = (F32)gForegroundFrameCount / gForegroundTime.getElapsedTimeF32(); - agent["version"] = gCurrentVersion; + agent["version"] = LLVersionInfo::getChannelAndVersion(); std::string language = LLUI::getLanguage(); agent["language"] = language; @@ -791,14 +797,14 @@ void send_stats() gSimFrames = (F32) gFrameCount; agent["agents_in_view"] = LLVOAvatar::sNumVisibleAvatars; - agent["ping"] = gAvgSimPing; + agent["ping"] = gAvgSimPing.value(); agent["meters_traveled"] = gAgent.getDistanceTraveled(); agent["regions_visited"] = gAgent.getRegionsVisited(); agent["mem_use"] = LLMemory::getCurrentRSS() / 1024.0; LLSD &system = body["system"]; - system["ram"] = (S32) gSysMemory.getPhysicalMemoryKB(); + system["ram"] = (S32) gSysMemory.getPhysicalMemoryKB().value(); system["os"] = LLAppViewer::instance()->getOSInfo().getOSStringSimple(); system["cpu"] = gSysCPU.getCPUString(); unsigned char MACAddress[MAC_ADDRESS_BYTES]; @@ -822,9 +828,9 @@ void send_stats() LLSD &download = body["downloads"]; - download["world_kbytes"] = gTotalWorldBytes / 1024.0; - download["object_kbytes"] = gTotalObjectBytes / 1024.0; - download["texture_kbytes"] = gTotalTextureBytes / 1024.0; + download["world_kbytes"] = F64Kilobytes(gTotalWorldData).value(); + download["object_kbytes"] = F64Kilobytes(gTotalObjectData).value(); + download["texture_kbytes"] = F64Kilobytes(gTotalTextureData).value(); download["mesh_kbytes"] = LLMeshRepository::sBytesReceived/1024.0; LLSD &in = body["stats"]["net"]["in"]; @@ -875,16 +881,20 @@ void send_stats() F32 grey_time = LLVOAvatar::sGreyTime * 1000.f / gFrameTimeSeconds; misc["int_2"] = LLSD::Integer(grey_time); // Steve: 1.22 - llinfos << "Misc Stats: int_1: " << misc["int_1"] << " int_2: " << misc["int_2"] << llendl; - llinfos << "Misc Stats: string_1: " << misc["string_1"] << " string_2: " << misc["string_2"] << llendl; + LL_INFOS() << "Misc Stats: int_1: " << misc["int_1"] << " int_2: " << misc["int_2"] << LL_ENDL; + LL_INFOS() << "Misc Stats: string_1: " << misc["string_1"] << " string_2: " << misc["string_2"] << LL_ENDL; - body["DisplayNamesEnabled"] = gSavedSettings.getS32("PhoenixNameSystem") == 1 || gSavedSettings.getS32("PhoenixNameSystem") == 2; - body["DisplayNamesShowUsername"] = gSavedSettings.getS32("PhoenixNameSystem") == 1; + const S32 namesys = gSavedSettings.getS32("PhoenixNameSystem"); + body["DisplayNamesEnabled"] = namesys > 0 && namesys < 4; + body["DisplayNamesShowUsername"] = namesys == 1 || namesys == 3; body["MinimalSkin"] = false; LLViewerStats::getInstance()->addToMessage(body); - LLHTTPClient::post(url, body, new ViewerStatsResponder); + + LL_INFOS("LogViewerStatsPacket") << "Sending viewer statistics: " << body << LL_ENDL; + LLHTTPClient::post(url, body, new ViewerStatsResponder()); + } LLViewerStats::PhaseMap::PhaseMap() @@ -906,7 +916,7 @@ LLTimer& LLViewerStats::PhaseMap::getPhaseTimer(const std::string& phase_name) void LLViewerStats::PhaseMap::startPhase(const std::string& phase_name) { LLTimer& timer = getPhaseTimer(phase_name); - lldebugs << "startPhase " << phase_name << llendl; + LL_DEBUGS() << "startPhase " << phase_name << LL_ENDL; timer.start(); } @@ -940,7 +950,7 @@ bool LLViewerStats::PhaseMap::getPhaseValues(const std::string& phase_name, F32& void LLViewerStats::PhaseMap::clearPhases() { - lldebugs << "clearPhases" << llendl; + LL_DEBUGS() << "clearPhases" << LL_ENDL; mPhaseMap.clear(); } diff --git a/indra/newview/llviewerstats.h b/indra/newview/llviewerstats.h index f6300d1e27..90b75a8668 100644 --- a/indra/newview/llviewerstats.h +++ b/indra/newview/llviewerstats.h @@ -321,7 +321,7 @@ void update_statistics(); void send_stats(); extern LLFrameTimer gTextureTimer; -extern U32 gTotalTextureBytes; -extern U32 gTotalObjectBytes; -extern U32 gTotalTextureBytesPerBoostLevel[] ; +extern U32Bytes gTotalTextureData; +extern U32Bytes gTotalObjectData; +extern U32Bytes gTotalTextureBytesPerBoostLevel[] ; #endif // LL_LLVIEWERSTATS_H diff --git a/indra/newview/llviewerstatsrecorder.cpp b/indra/newview/llviewerstatsrecorder.cpp index 91e485d01b..8ce0657f82 100644 --- a/indra/newview/llviewerstatsrecorder.cpp +++ b/indra/newview/llviewerstatsrecorder.cpp @@ -49,7 +49,7 @@ LLViewerStatsRecorder::LLViewerStatsRecorder() : { if (NULL != sInstance) { - llerrs << "Attempted to create multiple instances of LLViewerStatsRecorder!" << llendl; + LL_ERRS() << "Attempted to create multiple instances of LLViewerStatsRecorder!" << LL_ENDL; } sInstance = this; clearStats(); @@ -132,7 +132,7 @@ void LLViewerStatsRecorder::recordObjectUpdateEvent(U32 local_id, const EObjectU mObjectCacheHitSize += msg_size; break; default: - llwarns << "Unknown update_type" << llendl; + LL_WARNS() << "Unknown update_type" << LL_ENDL; break; }; } @@ -154,7 +154,7 @@ void LLViewerStatsRecorder::recordCacheFullUpdate(U32 local_id, const EObjectUpd mObjectCacheUpdateReplacements++; break; default: - llwarns << "Unknown update_result type" << llendl; + LL_WARNS() << "Unknown update_result type" << LL_ENDL; break; }; } @@ -172,7 +172,7 @@ void LLViewerStatsRecorder::writeToLog( F32 interval ) if ( delta_time < interval || total_objects == 0) return; mLastSnapshotTime = LLTimer::getTotalSeconds(); - lldebugs << "ILX: " + LL_DEBUGS() << "ILX: " << mObjectCacheHitCount << " hits, " << mObjectCacheMissFullCount << " full misses, " << mObjectCacheMissCrcCount << " crc misses, " @@ -185,7 +185,7 @@ void LLViewerStatsRecorder::writeToLog( F32 interval ) << mObjectCacheUpdateAdds << " cache update adds, " << mObjectCacheUpdateReplacements << " cache update replacements, " << mObjectUpdateFailures << " update failures" - << llendl; + << LL_ENDL; if (mObjectCacheFile == NULL) { @@ -220,7 +220,7 @@ void LLViewerStatsRecorder::writeToLog( F32 interval ) } else { - llwarns << "Couldn't open " << STATS_FILE_NAME << " for logging." << llendl; + LL_WARNS() << "Couldn't open " << STATS_FILE_NAME << " for logging." << LL_ENDL; return; } } diff --git a/indra/newview/llviewertexlayer.cpp b/indra/newview/llviewertexlayer.cpp index cbf32eb438..4e31d561a8 100644 --- a/indra/newview/llviewertexlayer.cpp +++ b/indra/newview/llviewertexlayer.cpp @@ -76,7 +76,7 @@ LLViewerTexLayerSetBuffer::LLViewerTexLayerSetBuffer(LLTexLayerSet* const owner, S32 width, S32 height) : // ORDER_LAST => must render these after the hints are created. LLTexLayerSetBuffer(owner), - LLViewerDynamicTexture( width, height, 4, LLViewerDynamicTexture::ORDER_LAST, TRUE ), + LLViewerDynamicTexture( width, height, 4, LLViewerDynamicTexture::ORDER_LAST, FALSE ), mUploadPending(FALSE), // Not used for any logic here, just to sync sending of updates mNeedsUpload(FALSE), mNumLowresUploads(0), @@ -120,7 +120,7 @@ void LLViewerTexLayerSetBuffer::destroyGLTexture() // static void LLViewerTexLayerSetBuffer::dumpTotalByteCount() { - llinfos << "Composite System GL Buffers: " << (LLViewerTexLayerSetBuffer::sGLByteCount/1024) << "KB" << llendl; + LL_INFOS() << "Composite System GL Buffers: " << (LLViewerTexLayerSetBuffer::sGLByteCount/1024) << "KB" << LL_ENDL; } void LLViewerTexLayerSetBuffer::requestUpdate() @@ -234,7 +234,7 @@ void LLViewerTexLayerSetBuffer::midRenderTexLayerSet(BOOL success) { if (!success) { - llinfos << "Failed attempt to bake " << mTexLayerSet->getBodyRegionName() << llendl; + LL_INFOS() << "Failed attempt to bake " << mTexLayerSet->getBodyRegionName() << LL_ENDL; mUploadPending = FALSE; } else @@ -361,12 +361,57 @@ BOOL LLViewerTexLayerSetBuffer::requestUpdateImmediate() return result; } +class LLSendTexLayerResponder : public LLAssetUploadResponder +{ + LOG_CLASS(LLSendTexLayerResponder); +public: + LLSendTexLayerResponder(const LLSD& post_data, const LLUUID& vfile_id, LLAssetType::EType asset_type, LLBakedUploadData * baked_upload_data) + : LLAssetUploadResponder(post_data, vfile_id, asset_type) + , mBakedUploadData(baked_upload_data) + {} + + ~LLSendTexLayerResponder() + { + // mBakedUploadData is normally deleted by calls to LLViewerTexLayerSetBuffer::onTextureUploadComplete() below + if (mBakedUploadData) + { // ...but delete it in the case where uploadComplete() is never called + delete mBakedUploadData; + mBakedUploadData = NULL; + } + } + + // Baked texture upload completed + /*virtual*/ void uploadComplete(const LLSD& content) + { + const std::string& result = content["state"]; + const LLUUID& new_id = content["new_asset"]; + + LL_INFOS() << "result: " << result << " new_id: " << new_id << LL_ENDL; + LLViewerTexLayerSetBuffer::onTextureUploadComplete(new_id, (void*) mBakedUploadData, (result == "complete" && mBakedUploadData) ? 0 : -1, LL_EXSTAT_NONE); + mBakedUploadData = NULL; // deleted in onTextureUploadComplete() + } + + /*virtual*/ void httpFailure() + { + LL_INFOS() << dumpResponse() << LL_ENDL; + + // Invoke the original callback with an error result + LLViewerTexLayerSetBuffer::onTextureUploadComplete(LLUUID::null, (void*) mBakedUploadData, -1, LL_EXSTAT_NONE); + mBakedUploadData = NULL; // deleted in onTextureUploadComplete() + } + + /*virtual*/ char const* getName() const { return "LLSendTexLayerResponder"; } + +private: + LLBakedUploadData* mBakedUploadData; +}; + // Create the baked texture, send it out to the server, then wait for it to come // back so we can switch to using it. void LLViewerTexLayerSetBuffer::doUpload() { LLViewerTexLayerSet* layer_set = getViewerTexLayerSet(); - llinfos << "Uploading baked " << layer_set->getBodyRegionName() << llendl; + LL_INFOS() << "Uploading baked " << layer_set->getBodyRegionName() << LL_ENDL; LLViewerStats::getInstance()->incStat(LLViewerStats::ST_TEX_BAKES); // Don't need caches since we're baked now. (note: we won't *really* be baked @@ -449,7 +494,7 @@ void LLViewerTexLayerSetBuffer::doUpload() LLSD body = LLSD::emptyMap(); // The responder will call LLViewerTexLayerSetBuffer::onTextureUploadComplete() LLHTTPClient::post(url, body, new LLSendTexLayerResponder(body, mUploadID, LLAssetType::AT_TEXTURE, baked_upload_data)); - llinfos << "Baked texture upload via capability of " << mUploadID << " to " << url << llendl; + LL_INFOS() << "Baked texture upload via capability of " << mUploadID << " to " << url << LL_ENDL; } else { @@ -460,7 +505,7 @@ void LLViewerTexLayerSetBuffer::doUpload() TRUE, // temp_file TRUE, // is_priority TRUE); // store_local - llinfos << "Baked texture upload via Asset Store." << llendl; + LL_INFOS() << "Baked texture upload via Asset Store." << LL_ENDL; } if (highest_lod) @@ -497,7 +542,7 @@ void LLViewerTexLayerSetBuffer::doUpload() mUploadPending = FALSE; LLVFile file(gVFS, asset_id, LLAssetType::AT_TEXTURE, LLVFile::WRITE); file.remove(); - llinfos << "Unable to create baked upload file (reason: corrupted)." << llendl; + LL_INFOS() << "Unable to create baked upload file (reason: corrupted)." << LL_ENDL; } } } @@ -505,7 +550,7 @@ void LLViewerTexLayerSetBuffer::doUpload() { // The VFS write file operation failed. mUploadPending = FALSE; - llinfos << "Unable to create baked upload file (reason: failed to write file)" << llendl; + LL_INFOS() << "Unable to create baked upload file (reason: failed to write file)" << LL_ENDL; } delete [] baked_color_data; @@ -587,14 +632,14 @@ void LLViewerTexLayerSetBuffer::onTextureUploadComplete(const LLUUID& uuid, LLAvatarAppearanceDefines::ETextureIndex baked_te = gAgentAvatarp->getBakedTE(layerset_buffer->getViewerTexLayerSet()); // Update baked texture info with the new UUID U64 now = LLFrameTimer::getTotalTime(); // Record starting time - llinfos << "Baked" << resolution << "texture upload for " << name << " took " << (S32)((now - baked_upload_data->mStartTime) / 1000) << " ms" << llendl; + LL_INFOS() << "Baked" << resolution << "texture upload for " << name << " took " << (S32)((now - baked_upload_data->mStartTime) / 1000) << " ms" << LL_ENDL; gAgentAvatarp->setNewBakedTexture(baked_te, uuid); } else { ++failures; S32 max_attempts = baked_upload_data->mIsHighestRes ? BAKE_UPLOAD_ATTEMPTS : 1; // only retry final bakes - llwarns << "Baked" << resolution << "texture upload for " << name << " failed (attempt " << failures << "/" << max_attempts << ")" << llendl; + LL_WARNS() << "Baked" << resolution << "texture upload for " << name << " failed (attempt " << failures << "/" << max_attempts << ")" << LL_ENDL; if (failures < max_attempts) { layerset_buffer->mUploadFailCount = failures; @@ -605,7 +650,7 @@ void LLViewerTexLayerSetBuffer::onTextureUploadComplete(const LLUUID& uuid, } else { - llinfos << "Received baked texture out of date, ignored." << llendl; + LL_INFOS() << "Received baked texture out of date, ignored." << LL_ENDL; } gAgentAvatarp->dirtyMesh(); @@ -617,7 +662,7 @@ void LLViewerTexLayerSetBuffer::onTextureUploadComplete(const LLUUID& uuid, // and rebake it at some point in the future (after login?)), // or this response to upload is out of date, in which case a // current response should be on the way or already processed. - llwarns << "Baked upload failed" << llendl; + LL_WARNS() << "Baked upload failed" << LL_ENDL; } delete baked_upload_data; @@ -694,7 +739,7 @@ void LLViewerTexLayerSet::createComposite() // Composite other avatars at reduced resolution if( !mAvatarAppearance->isSelf() ) { - llerrs << "composites should not be created for non-self avatars!" << llendl; + LL_ERRS() << "composites should not be created for non-self avatars!" << LL_ENDL; } mComposite = new LLViewerTexLayerSetBuffer( this, width, height ); } diff --git a/indra/newview/llviewertexlayer.h b/indra/newview/llviewertexlayer.h index 959c883da8..d732a87bb9 100644 --- a/indra/newview/llviewertexlayer.h +++ b/indra/newview/llviewertexlayer.h @@ -79,6 +79,16 @@ class LLViewerTexLayerSetBuffer : public LLTexLayerSetBuffer, public LLViewerDyn LLViewerTexLayerSetBuffer(LLTexLayerSet* const owner, S32 width, S32 height); virtual ~LLViewerTexLayerSetBuffer(); + void* operator new(size_t size) + { + return ll_aligned_malloc_16(size); + } + + void operator delete(void* ptr) + { + ll_aligned_free_16(ptr); + } + public: /*virtual*/ S8 getType() const; BOOL isInitialized(void) const; diff --git a/indra/newview/llviewertexteditor.cpp b/indra/newview/llviewertexteditor.cpp index 9704fe2cb8..3c9ce82e76 100644 --- a/indra/newview/llviewertexteditor.cpp +++ b/indra/newview/llviewertexteditor.cpp @@ -94,7 +94,7 @@ class LLEmbeddedNotecardOpener : public LLInventoryCallback LLInventoryItem* item = gInventory.getItem(inv_item); if(!item) { - llwarns << "Item add reported, but not found in inventory!: " << inv_item << llendl; + LL_WARNS() << "Item add reported, but not found in inventory!: " << inv_item << LL_ENDL; } else { @@ -308,7 +308,7 @@ llwchar LLEmbeddedItems::getEmbeddedCharFromIndex(S32 index) { if (index >= (S32)mEmbeddedIndexedChars.size()) { - llwarns << "No item for embedded char " << index << " using LL_UNKNOWN_CHAR" << llendl; + LL_WARNS() << "No item for embedded char " << index << " using LL_UNKNOWN_CHAR" << LL_ENDL; return LL_UNKNOWN_CHAR; } return mEmbeddedIndexedChars[index]; @@ -364,7 +364,7 @@ S32 LLEmbeddedItems::getIndexFromEmbeddedChar(llwchar wch) } else { - llwarns << "Embedded char " << wch << " not found, using 0" << llendl; + LL_WARNS() << "Embedded char " << wch << " not found, using 0" << LL_ENDL; return 0; } } @@ -441,7 +441,9 @@ void LLEmbeddedItems::bindEmbeddedChars( const LLFontGL* font ) const case LLAssetType::AT_BODYPART: img_name = "inv_item_skin.tga"; break; case LLAssetType::AT_ANIMATION: img_name = "inv_item_animation.tga";break; case LLAssetType::AT_GESTURE: img_name = "inv_item_gesture.tga"; break; - default: llassert(0); continue; + case LLAssetType::AT_MESH: img_name = "Inv_Mesh"; break; + case LLAssetType::AT_SETTINGS: img_name = "Inv_Settings"; break; + default: img_name = "Inv_Invalid"; break; // use the Inv_Invalid icon for undefined object types (see MAINT-3981) } LLUIImagePtr image = LLUI::getUIImage(img_name); @@ -578,34 +580,20 @@ LLViewerTextEditor::LLViewerTextEditor(const std::string& name, S32 max_length, const std::string& default_text, const LLFontGL* font, - BOOL allow_embedded_items) - : LLTextEditor(name, rect, max_length, default_text, font, allow_embedded_items), + BOOL allow_embedded_items, + bool parse_html) + : LLTextEditor(name, rect, max_length, default_text, font, allow_embedded_items, parse_html), mDragItemChar(0), mDragItemSaved(FALSE), mInventoryCallback(new LLEmbeddedNotecardOpener) { mEmbeddedItemList = new LLEmbeddedItems(this); mInventoryCallback->setEditor(this); - - // *TODO: Add right click menus for SLURLs - // Build the right click menu - // make the popup menu available - - //LLMenuGL* menu = LLUICtrlFactory::getInstance()->buildMenu("menu_slurl.xml", this); - //if (!menu) - //{ - // menu = new LLMenuGL(LLStringUtil::null); - //} - //menu->setBackgroundColor(gColors.getColor("MenuPopupBgColor")); - //// menu->setVisible(FALSE); - //mPopupMenuHandle = menu->getHandle(); } LLViewerTextEditor::~LLViewerTextEditor() { delete mEmbeddedItemList; - - // The inventory callback may still be in use by gInventoryCallbackManager... // so set its reference to this to null. mInventoryCallback->setEditor(NULL); @@ -672,6 +660,7 @@ BOOL LLViewerTextEditor::handleToolTip(S32 x, S32 y, std::string& msg, LLRect* s return TRUE; } +// Singu TODO: This is mostly duplicated from LLTextEditor BOOL LLViewerTextEditor::handleMouseDown(S32 x, S32 y, MASK mask) { BOOL handled = FALSE; @@ -794,114 +783,28 @@ BOOL LLViewerTextEditor::handleHover(S32 x, S32 y, MASK mask) { BOOL handled = FALSE; - if (!mDragItem) + if (!mIsSelecting && mDragItem && hasMouseCapture()) { - // leave hover segment active during drag and drop - mHoverSegment = NULL; - } - if(hasMouseCapture() ) - { - if( mIsSelecting ) - { - if (x != mLastSelectionX || y != mLastSelectionY) - { - mLastSelectionX = x; - mLastSelectionY = y; - } - - if( y > getTextRect().mTop ) - { - mScrollbar->setDocPos( mScrollbar->getDocPos() - 1 ); - } - else - if( y < getTextRect().mBottom ) - { - mScrollbar->setDocPos( mScrollbar->getDocPos() + 1 ); - } - - setCursorAtLocalPos( x, y, TRUE ); - mSelectionEnd = mCursorPos; - - updateScrollFromCursor(); - getWindow()->setCursor(UI_CURSOR_IBEAM); - } - else if( mDragItem ) + S32 screen_x; + S32 screen_y; + localPointToScreen(x, y, &screen_x, &screen_y ); + if( LLToolDragAndDrop::getInstance()->isOverThreshold( screen_x, screen_y ) ) { - S32 screen_x; - S32 screen_y; - localPointToScreen(x, y, &screen_x, &screen_y ); - if( LLToolDragAndDrop::getInstance()->isOverThreshold( screen_x, screen_y ) ) - { - LLToolDragAndDrop::getInstance()->beginDrag( - LLViewerAssetType::lookupDragAndDropType( mDragItem->getType() ), - mDragItem->getUUID(), - LLToolDragAndDrop::SOURCE_NOTECARD, - getSourceID(), mObjectID); + LLToolDragAndDrop::getInstance()->beginDrag( + LLViewerAssetType::lookupDragAndDropType( mDragItem->getType() ), + mDragItem->getUUID(), + LLToolDragAndDrop::SOURCE_NOTECARD, + getSourceID(), mObjectID); - return LLToolDragAndDrop::getInstance()->handleHover( x, y, mask ); - } - getWindow()->setCursor(UI_CURSOR_HAND); + return LLToolDragAndDrop::getInstance()->handleHover( x, y, mask ); } + getWindow()->setCursor(UI_CURSOR_HAND); - lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (active)" << llendl; + LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (active)" << LL_ENDL; handled = TRUE; } - if( !handled ) - { - // Pass to children - handled = LLView::childrenHandleHover(x, y, mask) != NULL; - } - - if( handled ) - { - // Delay cursor flashing - resetKeystrokeTimer(); - } - - // Opaque - if( !handled && mTakesNonScrollClicks) - { - // Check to see if we're over an HTML-style link - if( !mSegments.empty() ) - { - LLTextSegment* cur_segment = getSegmentAtLocalPos( x, y ); - if( cur_segment ) - { - if(cur_segment->getStyle()->isLink()) - { - lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (over link, inactive)" << llendl; - getWindow()->setCursor(UI_CURSOR_HAND); - handled = TRUE; - } - else - if(cur_segment->getStyle()->getIsEmbeddedItem()) - { - lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (over embedded item, inactive)" << llendl; - getWindow()->setCursor(UI_CURSOR_HAND); - //getWindow()->setCursor(UI_CURSOR_ARROW); - handled = TRUE; - } - mHoverSegment = cur_segment; - } - } - - if( !handled ) - { - lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (inactive)" << llendl; - if (!mScrollbar->getVisible() || x < getRect().getWidth() - SCROLLBAR_SIZE) - { - getWindow()->setCursor(UI_CURSOR_IBEAM); - } - else - { - getWindow()->setCursor(UI_CURSOR_ARROW); - } - handled = TRUE; - } - } - - return handled; + return handled || LLTextEditor::handleHover(x, y, mask); } @@ -945,125 +848,36 @@ BOOL LLViewerTextEditor::handleMouseUp(S32 x, S32 y, MASK mask) BOOL LLViewerTextEditor::handleRightMouseDown(S32 x, S32 y, MASK mask) { - BOOL handled = childrenHandleRightMouseDown(x, y, mask) != NULL; - if(!handled)handled = LLTextEditor::handleRightMouseDown(x, y, mask); - - // *TODO: Add right click menus for SLURLs -// if(! handled) -// { -// const LLTextSegment* cur_segment = getSegmentAtLocalPos( x, y ); -// if( cur_segment ) -// { -// if(cur_segment->getStyle()->isLink()) -// { -// handled = TRUE; -// mHTML = cur_segment->getStyle()->getLinkHREF(); -// } -// } -// } -// LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get(); -// if(handled && menu && mParseHTML && mHTML.length() > 0) -// { -// menu->setVisible(TRUE); -// menu->arrange(); -// menu->updateParent(LLMenuGL::sMenuContainer); -// LLMenuGL::showPopup(this, menu, x, y); -// mHTML = ""; -// } -// else -// { -// if(menu && menu->getVisible()) -// { -// menu->setVisible(FALSE); -// } -// } - return handled; + return childrenHandleRightMouseDown(x, y, mask) != NULL || LLTextEditor::handleRightMouseDown(x, y, mask); } BOOL LLViewerTextEditor::handleMiddleMouseDown(S32 x, S32 y, MASK mask) { - BOOL handled = FALSE; - handled = childrenHandleMiddleMouseDown(x, y, mask) != NULL; - if (!handled) - { - handled = LLTextEditor::handleMiddleMouseDown(x, y, mask); - } - return handled; + return childrenHandleMiddleMouseDown(x, y, mask) != NULL || LLTextEditor::handleMiddleMouseDown(x, y, mask); } BOOL LLViewerTextEditor::handleMiddleMouseUp(S32 x, S32 y, MASK mask) { - BOOL handled = childrenHandleMiddleMouseUp(x, y, mask) != NULL; - - return handled; + return childrenHandleMiddleMouseUp(x, y, mask) != NULL || LLTextEditor::handleMiddleMouseUp(x, y, mask); } BOOL LLViewerTextEditor::handleDoubleClick(S32 x, S32 y, MASK mask) { - BOOL handled = FALSE; - - // let scrollbar have first dibs - handled = LLView::childrenHandleDoubleClick(x, y, mask) != NULL; - - if( !handled && mTakesNonScrollClicks) + if (mTakesNonScrollClicks && allowsEmbeddedItems()) { - if( allowsEmbeddedItems() ) + const LLTextSegment* cur_segment = getSegmentAtLocalPos(x, y); + if (cur_segment && cur_segment->getStyle()->getIsEmbeddedItem()) { - const LLTextSegment* cur_segment = getSegmentAtLocalPos( x, y ); - if( cur_segment && cur_segment->getStyle()->getIsEmbeddedItem() ) - { - if( openEmbeddedItemAtPos( cur_segment->getStart() ) ) - { - deselect(); - setFocus( FALSE ); - return TRUE; - } - } - } - - - setCursorAtLocalPos( x, y, FALSE ); - deselect(); - - const LLWString &text = getWText(); - - if( isPartOfWord( text[mCursorPos] ) ) - { - // Select word the cursor is over - while ((mCursorPos > 0) && isPartOfWord(text[mCursorPos-1])) - { - mCursorPos--; - } - startSelection(); - - while ((mCursorPos < (S32)text.length()) && isPartOfWord( text[mCursorPos] ) ) + if( openEmbeddedItemAtPos(cur_segment->getStart())) { - mCursorPos++; + deselect(); + setFocus(FALSE); + return TRUE; } - - mSelectionEnd = mCursorPos; } - else if ((mCursorPos < (S32)text.length()) && !iswspace( text[mCursorPos]) ) - { - // Select the character the cursor is over - startSelection(); - mCursorPos++; - mSelectionEnd = mCursorPos; - } - - // We don't want handleMouseUp() to "finish" the selection (and thereby - // set mSelectionEnd to where the mouse is), so we finish the selection here. - mIsSelecting = FALSE; - - // delay cursor flashing - resetKeystrokeTimer(); - - // take selection to 'primary' clipboard - updatePrimary(); - - handled = TRUE; } - return handled; + + return LLTextEditor::handleDoubleClick(x, y, mask); } @@ -1198,7 +1012,7 @@ BOOL LLViewerTextEditor::handleDragAndDrop(S32 x, S32 y, MASK mask, } handled = TRUE; - lldebugst(LLERR_USER_INPUT) << "dragAndDrop handled by LLViewerTextEditor " << getName() << llendl; + LL_DEBUGS("UserInput") << "dragAndDrop handled by LLViewerTextEditor " << getName() << LL_ENDL; } return handled; @@ -1243,7 +1057,6 @@ void LLViewerTextEditor::setEmbeddedText(const std::string& instr) std::string LLViewerTextEditor::getEmbeddedText() { -#if 1 // New version (Version 2) mEmbeddedItemList->copyUsedCharsToIndexed(); LLWString outtextw; @@ -1259,26 +1072,6 @@ std::string LLViewerTextEditor::getEmbeddedText() } std::string outtext = wstring_to_utf8str(outtextw); return outtext; -#else - // Old version (Version 1) - mEmbeddedItemList->copyUsedCharsToIndexed(); - std::string outtext; - for (S32 i=0; i<(S32)mWText.size(); i++) - { - llwchar wch = mWText[i]; - if( wch >= FIRST_EMBEDDED_CHAR && wch <= LAST_EMBEDDED_CHAR ) - { - S32 index = mEmbeddedItemList->getIndexFromEmbeddedChar(wch); - wch = 0x80 | index % 128; - } - else if (wch >= 0x80) - { - wch = LL_UNKNOWN_CHAR; - } - outtext.push_back((U8)wch); - } - return outtext; -#endif } std::string LLViewerTextEditor::appendTime(bool prepend_newline) @@ -1644,15 +1437,8 @@ LLView* LLViewerTextEditor::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlF LLFontGL* font = LLView::selectFont(node); - // std::string text = node->getValue(); std::string text = node->getTextContents().substr(0, max_text_length - 1); - if (text.size() > max_text_length) - { - // Erase everything from max_text_length on. - text.erase(max_text_length); - } - LLViewerTextEditor* text_editor = new LLViewerTextEditor("text_editor", rect, max_text_length, @@ -1674,15 +1460,18 @@ LLView* LLViewerTextEditor::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlF node->getAttributeBOOL("hide_border", hide_border); text_editor->setBorderVisible(!hide_border); - BOOL parse_html = text_editor->mParseHTML; + BOOL parse_html = true; node->getAttributeBOOL("allow_html", parse_html); text_editor->setParseHTML(parse_html); - text_editor->setParseHighlights(TRUE); + BOOL commit_on_focus_lost = FALSE; + node->getAttributeBOOL("commit_on_focus_lost",commit_on_focus_lost); + text_editor->setCommitOnFocusLost(commit_on_focus_lost); + text_editor->initFromXML(node, parent); // add text after all parameters have been set - text_editor->appendStyledText(text, FALSE, FALSE); + text_editor->appendText(text, FALSE, FALSE); return text_editor; } diff --git a/indra/newview/llviewertexteditor.h b/indra/newview/llviewertexteditor.h index 702b97ca11..9b5edcc882 100644 --- a/indra/newview/llviewertexteditor.h +++ b/indra/newview/llviewertexteditor.h @@ -39,7 +39,7 @@ // // Classes // -class LLViewerTextEditor : public LLTextEditor +class LLViewerTextEditor final : public LLTextEditor { public: @@ -48,7 +48,8 @@ class LLViewerTextEditor : public LLTextEditor S32 max_length, const std::string& default_text = std::string(), const LLFontGL* glfont = NULL, - BOOL allow_embedded_items = FALSE); + BOOL allow_embedded_items = FALSE, + bool parse_html = false); virtual ~LLViewerTextEditor(); diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 19681d38e9..b299f36e46 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -55,15 +55,19 @@ #include "llappviewer.h" #include "llface.h" #include "llviewercamera.h" -//#include "lltextureatlas.h" -//#include "lltextureatlasmanager.h" #include "lltextureentry.h" #include "lltexturemanagerbridge.h" #include "llmediaentry.h" #include "llvovolume.h" #include "llviewermedia.h" +#include "lltexturecache.h" /////////////////////////////////////////////////////////////////////////////// +// extern +const S32Megabytes gMinVideoRam(32); +const S32Megabytes gMaxVideoRam(2048*4); // Bump to 8 gibibyte. + + // statics LLPointer LLViewerTexture::sNullImagep = NULL; LLPointer LLViewerTexture::sBlackImagep = NULL; @@ -71,9 +75,10 @@ LLPointer LLViewerFetchedTexture::sMissingAssetImagep = LLPointer LLViewerFetchedTexture::sWhiteImagep = NULL; LLPointer LLViewerFetchedTexture::sDefaultImagep = NULL; LLPointer LLViewerFetchedTexture::sSmokeImagep = NULL; -LLViewerMediaTexture::media_map_t LLViewerMediaTexture::sMediaMap ; +LLPointer LLViewerFetchedTexture::sFlatNormalImagep = NULL; +LLViewerMediaTexture::media_map_t LLViewerMediaTexture::sMediaMap; #if 0 -LLTexturePipelineTester* LLViewerTextureManager::sTesterp = NULL ; +LLTexturePipelineTester* LLViewerTextureManager::sTesterp = NULL; #endif const std::string sTesterName("TextureTester"); @@ -83,22 +88,23 @@ S32 LLViewerTexture::sAuxCount = 0; LLFrameTimer LLViewerTexture::sEvaluationTimer; F32 LLViewerTexture::sDesiredDiscardBias = 0.f; F32 LLViewerTexture::sDesiredDiscardScale = 1.1f; -S32 LLViewerTexture::sBoundTextureMemoryInBytes = 0; -S32 LLViewerTexture::sTotalTextureMemoryInBytes = 0; -S32 LLViewerTexture::sMaxBoundTextureMemInMegaBytes = 0; -S32 LLViewerTexture::sMaxTotalTextureMemInMegaBytes = 0; -S32 LLViewerTexture::sMaxDesiredTextureMemInBytes = 0 ; -S8 LLViewerTexture::sCameraMovingDiscardBias = 0 ; -F32 LLViewerTexture::sCameraMovingBias = 0.0f ; -S32 LLViewerTexture::sMaxSculptRez = 128 ; //max sculpt image size -const S32 MAX_CACHED_RAW_IMAGE_AREA = 64 * 64 ; -const S32 MAX_CACHED_RAW_SCULPT_IMAGE_AREA = LLViewerTexture::sMaxSculptRez * LLViewerTexture::sMaxSculptRez ; -const S32 MAX_CACHED_RAW_TERRAIN_IMAGE_AREA = 128 * 128 ; -S32 LLViewerTexture::sMinLargeImageSize = 65536 ; //256 * 256. -S32 LLViewerTexture::sMaxSmallImageSize = MAX_CACHED_RAW_IMAGE_AREA ; -BOOL LLViewerTexture::sFreezeImageScalingDown = FALSE ; -F32 LLViewerTexture::sCurrentTime = 0.0f ; -//BOOL LLViewerTexture::sUseTextureAtlas = FALSE ; +S64Bytes LLViewerTexture::sBoundTextureMemory; +S64Bytes LLViewerTexture::sTotalTextureMemory; +S32Megabytes LLViewerTexture::sMaxBoundTextureMemory; +S32Megabytes LLViewerTexture::sMaxTotalTextureMem; +S64Bytes LLViewerTexture::sMaxDesiredTextureMem; +S32 LLViewerTexture::sCameraMovingDiscardBias = 0; +F32 LLViewerTexture::sCameraMovingBias = 0.0f; +S32 LLViewerTexture::sMaxSculptRez = 128; //max sculpt image size +const S32 MAX_CACHED_RAW_IMAGE_AREA = 64 * 64; +const S32 MAX_CACHED_RAW_SCULPT_IMAGE_AREA = LLViewerTexture::sMaxSculptRez * LLViewerTexture::sMaxSculptRez; +const S32 MAX_CACHED_RAW_TERRAIN_IMAGE_AREA = 128 * 128; +const S32 DEFAULT_ICON_DIMENTIONS = 32; +S32 LLViewerTexture::sMinLargeImageSize = 65536; //256 * 256. +S32 LLViewerTexture::sMaxSmallImageSize = MAX_CACHED_RAW_IMAGE_AREA; +BOOL LLViewerTexture::sFreezeImageScalingDown = FALSE; +F32 LLViewerTexture::sCurrentTime = 0.0f; +//BOOL LLViewerTexture::sUseTextureAtlas = FALSE; F32 LLViewerTexture::sTexelPixelRatio = 1.0f; LLViewerTexture::EDebugTexels LLViewerTexture::sDebugTexelsMode = LLViewerTexture::DEBUG_TEXELS_OFF; @@ -107,6 +113,8 @@ const F32 desired_discard_bias_min = -2.0f; // -max number of levels to improve const F32 desired_discard_bias_max = (F32)MAX_DISCARD_LEVEL; // max number of levels to reduce image quality by const F64 log_2 = log(2.0); +const U32 DESIRED_NORMAL_TEXTURE_SIZE = (U32)LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT; + //---------------------------------------------------------------------------------------------- //namespace: LLViewerTextureAccess //---------------------------------------------------------------------------------------------- @@ -128,7 +136,7 @@ LLLoadedCallbackEntry::LLLoadedCallbackEntry(loaded_callback_func cb, { if(mSourceCallbackList) { - mSourceCallbackList->insert(target->getID()); + mSourceCallbackList->insert(LLTextureKey(target->getID(), (ETexListType)target->getTextureListType())); } } @@ -140,7 +148,7 @@ void LLLoadedCallbackEntry::removeTexture(LLViewerFetchedTexture* tex) { if(mSourceCallbackList) { - mSourceCallbackList->erase(tex->getID()) ; + mSourceCallbackList->erase(LLTextureKey(tex->getID(), (ETexListType)tex->getTextureListType())); } } @@ -153,118 +161,134 @@ void LLLoadedCallbackEntry::cleanUpCallbackList(LLLoadedCallbackEntry::source_ca for(LLLoadedCallbackEntry::source_callback_list_t::iterator iter = callback_list->begin(); iter != callback_list->end(); ++iter) { - LLViewerFetchedTexture* tex = gTextureList.findImage(*iter) ; + LLViewerFetchedTexture* tex = gTextureList.findImage(*iter); if(tex) { - tex->deleteCallbackEntry(callback_list) ; + tex->deleteCallbackEntry(callback_list); } } - callback_list->clear() ; + callback_list->clear(); } } LLViewerMediaTexture* LLViewerTextureManager::createMediaTexture(const LLUUID &media_id, BOOL usemipmaps, LLImageGL* gl_image) { - return new LLViewerMediaTexture(media_id, usemipmaps, gl_image) ; + return new LLViewerMediaTexture(media_id, usemipmaps, gl_image); } - -LLViewerTexture* LLViewerTextureManager::findTexture(const LLUUID& id) + +void LLViewerTextureManager::findFetchedTextures(const LLUUID& id, std::vector &output) { - LLViewerTexture* tex ; - //search fetched texture list - tex = gTextureList.findImage(id) ; - - //search media texture list - if(!tex) - { - tex = LLViewerTextureManager::findMediaTexture(id) ; - } - return tex ; + return gTextureList.findTexturesByID(id, output); +} + +void LLViewerTextureManager::findTextures(const LLUUID& id, std::vector &output) +{ + std::vector fetched_output; + gTextureList.findTexturesByID(id, fetched_output); + std::vector::iterator iter = fetched_output.begin(); + while (iter != fetched_output.end()) + { + output.push_back(*iter); + iter++; + } + + //search media texture list + if (output.empty()) + { + LLViewerTexture* tex; + tex = LLViewerTextureManager::findMediaTexture(id); + if (tex) + { + output.push_back(tex); + } + } + } -LLViewerFetchedTexture* LLViewerTextureManager::findFetchedTexture(const LLUUID& id) +LLViewerFetchedTexture* LLViewerTextureManager::findFetchedTexture(const LLUUID& id, S32 tex_type) { - return gTextureList.findImage(id); + return gTextureList.findImage(id, (ETexListType)tex_type); } LLViewerMediaTexture* LLViewerTextureManager::findMediaTexture(const LLUUID &media_id) { - return LLViewerMediaTexture::findMediaTexture(media_id) ; + return LLViewerMediaTexture::findMediaTexture(media_id); } LLViewerMediaTexture* LLViewerTextureManager::getMediaTexture(const LLUUID& id, BOOL usemipmaps, LLImageGL* gl_image) { - LLViewerMediaTexture* tex = LLViewerMediaTexture::findMediaTexture(id) ; + LLViewerMediaTexture* tex = LLViewerMediaTexture::findMediaTexture(id); if(!tex) { - tex = LLViewerTextureManager::createMediaTexture(id, usemipmaps, gl_image) ; + tex = LLViewerTextureManager::createMediaTexture(id, usemipmaps, gl_image); } - tex->initVirtualSize() ; + tex->initVirtualSize(); - return tex ; + return tex; } LLViewerFetchedTexture* LLViewerTextureManager::staticCastToFetchedTexture(LLTexture* tex, BOOL report_error) { if(!tex) { - return NULL ; + return NULL; } - S8 type = tex->getType() ; + S8 type = tex->getType(); if(type == LLViewerTexture::FETCHED_TEXTURE || type == LLViewerTexture::LOD_TEXTURE) { - return static_cast(tex) ; + return static_cast(tex); } if(report_error) { - llerrs << "not a fetched texture type: " << type << llendl ; + LL_ERRS() << "not a fetched texture type: " << type << LL_ENDL; } - return NULL ; + return NULL; } LLPointer LLViewerTextureManager::getLocalTexture(BOOL usemipmaps, BOOL generate_gl_tex) { - LLPointer tex = new LLViewerTexture(usemipmaps) ; + LLPointer tex = new LLViewerTexture(usemipmaps); if(generate_gl_tex) { - tex->generateGLTexture() ; - tex->setCategory(LLGLTexture::LOCAL) ; + tex->generateGLTexture(); + tex->setCategory(LLGLTexture::LOCAL); } - return tex ; + return tex; } LLPointer LLViewerTextureManager::getLocalTexture(const LLUUID& id, BOOL usemipmaps, BOOL generate_gl_tex) { - LLPointer tex = new LLViewerTexture(id, usemipmaps) ; + LLPointer tex = new LLViewerTexture(id, usemipmaps); if(generate_gl_tex) { - tex->generateGLTexture() ; - tex->setCategory(LLGLTexture::LOCAL) ; + tex->generateGLTexture(); + tex->setCategory(LLGLTexture::LOCAL); } - return tex ; + return tex; } LLPointer LLViewerTextureManager::getLocalTexture(const LLImageRaw* raw, BOOL usemipmaps) { - LLPointer tex = new LLViewerTexture(raw, usemipmaps) ; - tex->setCategory(LLGLTexture::LOCAL) ; - return tex ; + LLPointer tex = new LLViewerTexture(raw, usemipmaps); + tex->setCategory(LLGLTexture::LOCAL); + return tex; } LLPointer LLViewerTextureManager::getLocalTexture(const U32 width, const U32 height, const U8 components, BOOL usemipmaps, BOOL generate_gl_tex) { - LLPointer tex = new LLViewerTexture(width, height, components, usemipmaps) ; + LLPointer tex = new LLViewerTexture(width, height, components, usemipmaps); if(generate_gl_tex) { - tex->generateGLTexture() ; - tex->setCategory(LLGLTexture::LOCAL) ; + tex->generateGLTexture(); + tex->setCategory(LLGLTexture::LOCAL); } - return tex ; + return tex; } LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTexture( const LLUUID &image_id, + FTType f_type, BOOL usemipmaps, LLViewerTexture::EBoostLevel boost_priority, S8 texture_type, @@ -272,11 +296,12 @@ LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTexture( LLGLenum primary_format, LLHost request_from_host) { - return gTextureList.getImage(image_id, usemipmaps, boost_priority, texture_type, internal_format, primary_format, request_from_host) ; + return gTextureList.getImage(image_id, f_type, usemipmaps, boost_priority, texture_type, internal_format, primary_format, request_from_host); } LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTextureFromFile( const std::string& filename, + FTType f_type, BOOL usemipmaps, LLViewerTexture::EBoostLevel boost_priority, S8 texture_type, @@ -284,11 +309,12 @@ LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTextureFromFile( LLGLenum primary_format, const LLUUID& force_id) { - return gTextureList.getImageFromFile(filename, usemipmaps, boost_priority, texture_type, internal_format, primary_format, force_id) ; + return gTextureList.getImageFromFile(filename, f_type, usemipmaps, boost_priority, texture_type, internal_format, primary_format, force_id); } //static LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTextureFromUrl(const std::string& url, + FTType f_type, BOOL usemipmaps, LLViewerTexture::EBoostLevel boost_priority, S8 texture_type, @@ -297,12 +323,12 @@ LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTextureFromUrl(const s const LLUUID& force_id ) { - return gTextureList.getImageFromUrl(url, usemipmaps, boost_priority, texture_type, internal_format, primary_format, force_id) ; + return gTextureList.getImageFromUrl(url, f_type, usemipmaps, boost_priority, texture_type, internal_format, primary_format, force_id); } -LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTextureFromHost(const LLUUID& image_id, LLHost host) +LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTextureFromHost(const LLUUID& image_id, FTType f_type, LLHost host) { - return gTextureList.getImageFromHost(image_id, host) ; + return gTextureList.getImageFromHost(image_id, f_type, host); } // Create a bridge to the viewer texture manager. @@ -330,15 +356,15 @@ void LLViewerTextureManager::init() { LLPointer raw = new LLImageRaw(1,1,3); raw->clear(0x77, 0x77, 0x77, 0xFF); - LLViewerTexture::sNullImagep = LLViewerTextureManager::getLocalTexture(raw.get(), TRUE) ; + LLViewerTexture::sNullImagep = LLViewerTextureManager::getLocalTexture(raw.get(), TRUE); } const S32 dim = 128; LLPointer image_raw = new LLImageRaw(dim,dim,3); U8* data = image_raw->getData(); - memset(data, 0, dim * dim * 3) ; - LLViewerTexture::sBlackImagep = LLViewerTextureManager::getLocalTexture(image_raw.get(), TRUE) ; + memset(data, 0, dim * dim * 3); + LLViewerTexture::sBlackImagep = LLViewerTextureManager::getLocalTexture(image_raw.get(), TRUE); #if 1 LLPointer imagep = LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT); @@ -367,18 +393,18 @@ void LLViewerTextureManager::init() } imagep->createGLTexture(0, image_raw); //cache the raw image - imagep->setCachedRawImage(0, image_raw) ; + imagep->setCachedRawImage(0, image_raw); image_raw = NULL; #else - LLViewerFetchedTexture::sDefaultImagep = LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT, TRUE, LLGLTexture::BOOST_UI); + LLViewerFetchedTexture::sDefaultImagep = LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_UI); #endif LLViewerFetchedTexture::sDefaultImagep->dontDiscard(); - LLViewerFetchedTexture::sDefaultImagep->setCategory(LLGLTexture::OTHER) ; + LLViewerFetchedTexture::sDefaultImagep->setCategory(LLGLTexture::OTHER); - LLViewerFetchedTexture::sSmokeImagep = LLViewerTextureManager::getFetchedTexture(IMG_SMOKE, TRUE, LLGLTexture::BOOST_UI); - LLViewerFetchedTexture::sSmokeImagep->setNoDelete() ; + LLViewerFetchedTexture::sSmokeImagep = LLViewerTextureManager::getFetchedTexture(IMG_SMOKE, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_UI); + LLViewerFetchedTexture::sSmokeImagep->setNoDelete(); - LLViewerTexture::initClass() ; + LLViewerTexture::initClass(); // Create a texture manager bridge. gTextureManagerBridgep = new LLViewerTextureManagerBridge(); @@ -386,7 +412,7 @@ void LLViewerTextureManager::init() #if 0 if (LLMetricPerformanceTesterBasic::isMetricLogRequested(sTesterName) && !LLMetricPerformanceTesterBasic::getTester(sTesterName)) { - sTesterp = new LLTexturePipelineTester() ; + sTesterp = new LLTexturePipelineTester(); if (!sTesterp->isValid()) { delete sTesterp; @@ -401,15 +427,16 @@ void LLViewerTextureManager::cleanup() stop_glerror(); delete gTextureManagerBridgep; - LLImageGL::sDefaultGLTexture = NULL ; + LLImageGL::sDefaultGLTexture = NULL; LLViewerTexture::sNullImagep = NULL; LLViewerTexture::sBlackImagep = NULL; LLViewerFetchedTexture::sDefaultImagep = NULL; LLViewerFetchedTexture::sSmokeImagep = NULL; LLViewerFetchedTexture::sMissingAssetImagep = NULL; LLViewerFetchedTexture::sWhiteImagep = NULL; + LLViewerFetchedTexture::sFlatNormalImagep = NULL; - LLViewerMediaTexture::cleanUpClass() ; + LLViewerMediaTexture::cleanUpClass(); } //---------------------------------------------------------------------------------------------- @@ -419,11 +446,11 @@ void LLViewerTextureManager::cleanup() // static void LLViewerTexture::initClass() { - LLImageGL::sDefaultGLTexture = LLViewerFetchedTexture::sDefaultImagep->getGLTexture() ; + LLImageGL::sDefaultGLTexture = LLViewerFetchedTexture::sDefaultImagep->getGLTexture(); sTexelPixelRatio = gSavedSettings.getF32("TexelPixelRatio"); if(gAuditTexture) { - LLImageGL::setHighlightTexture(LLViewerTexture::OTHER) ; + LLImageGL::setHighlightTexture(LLViewerTexture::OTHER); } } @@ -435,40 +462,41 @@ const S32 min_non_tex_system_mem = (128<<20); // 128 MB F32 texmem_lower_bound_scale = 0.85f; F32 texmem_middle_bound_scale = 0.925f; -static LLFastTimer::DeclareTimer FTM_TEXTURE_MEMORY_CHECK("Memory Check"); +static LLTrace::BlockTimerStatHandle FTM_TEXTURE_MEMORY_CHECK("Memory Check"); //static bool LLViewerTexture::isMemoryForTextureLow() { - const F32 WAIT_TIME = 1.0f ; //second - static LLFrameTimer timer ; + const F32 WAIT_TIME = 1.0f; //second + static LLFrameTimer timer; if(timer.getElapsedTimeF32() < WAIT_TIME) //call this once per second. { return false; } - timer.reset() ; + timer.reset(); + + LL_RECORD_BLOCK_TIME(FTM_TEXTURE_MEMORY_CHECK); - LLFastTimer t(FTM_TEXTURE_MEMORY_CHECK); - const static S32 MIN_FREE_TEXTURE_MEMORY = 5 ; //MB - const static S32 MIN_FREE_MAIN_MEMORy = 100 ; //MB + static const S32Megabytes MIN_FREE_TEXTURE_MEMORY(20); //MB + static const S32Megabytes MIN_FREE_MAIN_MEMORY(100); //MB - bool low_mem = false ; + bool low_mem = false; if (gGLManager.mHasATIMemInfo) { S32 meminfo[4]; glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, meminfo); - if(meminfo[0] / 1024 < MIN_FREE_TEXTURE_MEMORY) + if((S32Megabytes)meminfo[0] < MIN_FREE_TEXTURE_MEMORY) { - low_mem = true ; + low_mem = true; } if(!low_mem) //check main memory, only works for windows. { - LLMemory::updateMemoryInfo() ; - if(LLMemory::getAvailableMemKB() / 1024 < MIN_FREE_MAIN_MEMORy) + LLMemory::updateMemoryInfo(); + if(LLMemory::getAvailableMemKB() < MIN_FREE_TEXTURE_MEMORY) { - low_mem = true ; + low_mem = true; } } } @@ -480,47 +508,47 @@ bool LLViewerTexture::isMemoryForTextureLow() if(free_memory / 1024 < MIN_FREE_TEXTURE_MEMORY) { - low_mem = true ; + low_mem = true; } } #endif - return low_mem ; + return low_mem; } -static LLFastTimer::DeclareTimer FTM_TEXTURE_UPDATE_MEDIA("Media"); +static LLTrace::BlockTimerStatHandle FTM_TEXTURE_UPDATE_MEDIA("Media"); #if 0 -static LLFastTimer::DeclareTimer FTM_TEXTURE_UPDATE_TEST("Test"); +static LLTrace::BlockTimerStatHandle FTM_TEXTURE_UPDATE_TEST("Test"); #endif //static void LLViewerTexture::updateClass(const F32 velocity, const F32 angular_velocity) { - sCurrentTime = gFrameTimeSeconds ; + sCurrentTime = gFrameTimeSeconds; #if 0 LLTexturePipelineTester* tester = (LLTexturePipelineTester*)LLMetricPerformanceTesterBasic::getTester(sTesterName); if (tester) { - LLFastTimer t(FTM_TEXTURE_UPDATE_TEST); - tester->update() ; + LL_RECORD_BLOCK_TIME(FTM_TEXTURE_UPDATE_TEST); + tester->update(); } #endif { - LLFastTimer t(FTM_TEXTURE_UPDATE_MEDIA); - LLViewerMediaTexture::updateClass() ; + LL_RECORD_BLOCK_TIME(FTM_TEXTURE_UPDATE_MEDIA); + LLViewerMediaTexture::updateClass(); } - sBoundTextureMemoryInBytes = LLImageGL::sBoundTextureMemoryInBytes;//in bytes - sTotalTextureMemoryInBytes = LLImageGL::sGlobalTextureMemoryInBytes;//in bytes - sMaxBoundTextureMemInMegaBytes = gTextureList.getMaxResidentTexMem();//in MB - sMaxTotalTextureMemInMegaBytes = gTextureList.getMaxTotalTextureMem() ;//in MB - sMaxDesiredTextureMemInBytes = MEGA_BYTES_TO_BYTES(sMaxTotalTextureMemInMegaBytes) ; //in Bytes, by default and when total used texture memory is small. + sBoundTextureMemory = LLImageGL::sBoundTextureMemory; + sTotalTextureMemory = LLImageGL::sGlobalTextureMemory; + sMaxBoundTextureMemory = gTextureList.getMaxResidentTexMem(); + sMaxTotalTextureMem = gTextureList.getMaxTotalTextureMem(); + sMaxDesiredTextureMem = sMaxTotalTextureMem; //in Bytes, by default and when total used texture memory is small. - if (BYTES_TO_MEGA_BYTES(sBoundTextureMemoryInBytes) >= sMaxBoundTextureMemInMegaBytes || - BYTES_TO_MEGA_BYTES(sTotalTextureMemoryInBytes) >= sMaxTotalTextureMemInMegaBytes) + if (sBoundTextureMemory >= sMaxBoundTextureMemory || + sTotalTextureMemory >= sMaxTotalTextureMem) { - //when texture memory overflows, lower down the threashold to release the textures more aggressively. - sMaxDesiredTextureMemInBytes = llmin((S32)(sMaxDesiredTextureMemInBytes * 0.75f) , MEGA_BYTES_TO_BYTES(MAX_VIDEO_RAM_IN_MEGA_BYTES)) ;//512 MB + //when texture memory overflows, lower down the threshold to release the textures more aggressively. + sMaxDesiredTextureMem = llmin(F64Bytes(sMaxDesiredTextureMem) * 0.75f, F64Bytes(gMaxVideoRam)); // If we are using more texture memory than we should, // scale up the desired discard level @@ -536,8 +564,8 @@ void LLViewerTexture::updateClass(const F32 velocity, const F32 angular_velocity sEvaluationTimer.reset(); } else if (sDesiredDiscardBias > 0.0f && - BYTES_TO_MEGA_BYTES(sBoundTextureMemoryInBytes) < sMaxBoundTextureMemInMegaBytes * texmem_lower_bound_scale && - BYTES_TO_MEGA_BYTES(sTotalTextureMemoryInBytes) < sMaxTotalTextureMemInMegaBytes * texmem_lower_bound_scale) + sBoundTextureMemory < sMaxBoundTextureMemory * texmem_lower_bound_scale && + sTotalTextureMemory < sMaxTotalTextureMem * texmem_lower_bound_scale) { // If we are using less texture memory than we should, // scale down the desired discard level @@ -548,23 +576,22 @@ void LLViewerTexture::updateClass(const F32 velocity, const F32 angular_velocity } } sDesiredDiscardBias = llclamp(sDesiredDiscardBias, desired_discard_bias_min, desired_discard_bias_max); - //LLViewerTexture::sUseTextureAtlas = gSavedSettings.getBOOL("EnableTextureAtlas") ; - F32 camera_moving_speed = LLViewerCamera::getInstance()->getAverageSpeed() ; + F32 camera_moving_speed = LLViewerCamera::getInstance()->getAverageSpeed(); F32 camera_angular_speed = LLViewerCamera::getInstance()->getAverageAngularSpeed(); sCameraMovingBias = llmax(0.2f * camera_moving_speed, 2.0f * camera_angular_speed - 1); - sCameraMovingDiscardBias = (S8)(sCameraMovingBias); + sCameraMovingDiscardBias = sCameraMovingBias; - LLViewerTexture::sFreezeImageScalingDown = (BYTES_TO_MEGA_BYTES(sBoundTextureMemoryInBytes) < 0.75f * sMaxBoundTextureMemInMegaBytes * texmem_middle_bound_scale) && - (BYTES_TO_MEGA_BYTES(sTotalTextureMemoryInBytes) < 0.75f * sMaxTotalTextureMemInMegaBytes * texmem_middle_bound_scale) ; + LLViewerTexture::sFreezeImageScalingDown = (sBoundTextureMemory < 0.75f * sMaxBoundTextureMemory * texmem_middle_bound_scale) && + (sTotalTextureMemory < 0.75f * sMaxTotalTextureMem * texmem_middle_bound_scale); } //end of static functions //------------------------------------------------------------------------------------------- const U32 LLViewerTexture::sCurrentFileVersion = 1; -LLViewerTexture::LLViewerTexture(BOOL usemipmaps) : - LLGLTexture(usemipmaps) +LLViewerTexture::LLViewerTexture(BOOL usemipmaps, bool allow_compression) : + LLGLTexture(usemipmaps, allow_compression) { init(true); @@ -572,8 +599,8 @@ LLViewerTexture::LLViewerTexture(BOOL usemipmaps) : sImageCount++; } -LLViewerTexture::LLViewerTexture(const LLUUID& id, BOOL usemipmaps) : - LLGLTexture(usemipmaps), +LLViewerTexture::LLViewerTexture(const LLUUID& id, BOOL usemipmaps, bool allow_compression) : + LLGLTexture(usemipmaps, allow_compression), mID(id) { init(true); @@ -581,8 +608,8 @@ LLViewerTexture::LLViewerTexture(const LLUUID& id, BOOL usemipmaps) : sImageCount++; } -LLViewerTexture::LLViewerTexture(const U32 width, const U32 height, const U8 components, BOOL usemipmaps) : - LLGLTexture(width, height, components, usemipmaps) +LLViewerTexture::LLViewerTexture(const U32 width, const U32 height, const U8 components, BOOL usemipmaps, bool allow_compression) : + LLGLTexture(width, height, components, usemipmaps, allow_compression) { init(true); @@ -590,8 +617,8 @@ LLViewerTexture::LLViewerTexture(const U32 width, const U32 height, const U8 com sImageCount++; } -LLViewerTexture::LLViewerTexture(const LLImageRaw* raw, BOOL usemipmaps) : - LLGLTexture(raw, usemipmaps) +LLViewerTexture::LLViewerTexture(const LLImageRaw* raw, BOOL usemipmaps, bool allow_compression) : + LLGLTexture(raw, usemipmaps, allow_compression) { init(true); @@ -601,6 +628,7 @@ LLViewerTexture::LLViewerTexture(const LLImageRaw* raw, BOOL usemipmaps) : LLViewerTexture::~LLViewerTexture() { + // LL_DEBUGS("Avatar") << mID << LL_ENDL; cleanup(); sImageCount--; } @@ -608,37 +636,99 @@ LLViewerTexture::~LLViewerTexture() // virtual void LLViewerTexture::init(bool firstinit) { + mSelectedTime = 0.f; mMaxVirtualSize = 0.f; - mNeedsGLTexture = FALSE ; + mNeedsGLTexture = FALSE; mMaxVirtualSizeResetInterval = 1; - mMaxVirtualSizeResetCounter = mMaxVirtualSizeResetInterval ; - mAdditionalDecodePriority = 0.f ; - mParcelMedia = NULL ; - mNumFaces = 0 ; - mNumVolumes = 0; - mFaceList.clear() ; - mVolumeList.clear(); + mMaxVirtualSizeResetCounter = mMaxVirtualSizeResetInterval; + mAdditionalDecodePriority = 0.f; + mParcelMedia = NULL; + + memset(&mNumVolumes, 0, sizeof(U32)* LLRender::NUM_VOLUME_TEXTURE_CHANNELS); + mFaceList[LLRender::DIFFUSE_MAP].clear(); + mFaceList[LLRender::NORMAL_MAP].clear(); + mFaceList[LLRender::SPECULAR_MAP].clear(); + mNumFaces[LLRender::DIFFUSE_MAP] = + mNumFaces[LLRender::NORMAL_MAP] = + mNumFaces[LLRender::SPECULAR_MAP] = 0; + + mVolumeList[LLRender::LIGHT_TEX].clear(); + mVolumeList[LLRender::SCULPT_TEX].clear(); } //virtual S8 LLViewerTexture::getType() const { - return LLViewerTexture::LOCAL_TEXTURE ; + return LLViewerTexture::LOCAL_TEXTURE; } void LLViewerTexture::cleanup() { - mFaceList.clear() ; - mVolumeList.clear(); + notifyAboutMissingAsset(); + + mFaceList[LLRender::DIFFUSE_MAP].clear(); + mFaceList[LLRender::NORMAL_MAP].clear(); + mFaceList[LLRender::SPECULAR_MAP].clear(); + mVolumeList[LLRender::LIGHT_TEX].clear(); + mVolumeList[LLRender::SCULPT_TEX].clear(); +} + +void LLViewerTexture::notifyAboutCreatingTexture() +{ + for(U32 ch = 0; ch < LLRender::NUM_TEXTURE_CHANNELS; ++ch) + { + for(U32 f = 0; f < mNumFaces[ch]; f++) + { + mFaceList[ch][f]->notifyAboutCreatingTexture(this); + } + } } +void LLViewerTexture::notifyAboutMissingAsset() +{ + for(U32 ch = 0; ch < LLRender::NUM_TEXTURE_CHANNELS; ++ch) + { + for(U32 f = 0; f < mNumFaces[ch]; f++) + { + mFaceList[ch][f]->notifyAboutMissingAsset(this); + } + } +} + +// virtual void LLViewerTexture::dump() { LLGLTexture::dump(); - llinfos << "LLViewerTexture" + LL_INFOS() << "LLViewerTexture" << " mID " << mID - << llendl; + << LL_ENDL; +} + +void LLViewerTexture::setBoostLevel(S32 level) +{ + if(mBoostLevel != level) + { + mBoostLevel = level; + if(mBoostLevel != LLViewerTexture::BOOST_NONE && + mBoostLevel != LLViewerTexture::BOOST_ALM && + mBoostLevel != LLViewerTexture::BOOST_SELECTED && + mBoostLevel != LLViewerTexture::BOOST_ICON) + { + setNoDelete(); + } + } + + if (mBoostLevel == LLViewerTexture::BOOST_SELECTED) + { + mSelectedTime = gFrameTimeSeconds; + } + +} + +bool LLViewerTexture::isActiveFetching() +{ + return false; } bool LLViewerTexture::bindDefaultImage(S32 stage) @@ -653,22 +743,22 @@ bool LLViewerTexture::bindDefaultImage(S32 stage) } if (!res && LLViewerTexture::sNullImagep.notNull() && (this != LLViewerTexture::sNullImagep)) { - res = gGL.getTexUnit(stage)->bind(LLViewerTexture::sNullImagep) ; + res = gGL.getTexUnit(stage)->bind(LLViewerTexture::sNullImagep); } if (!res) { - llwarns << "LLViewerTexture::bindDefaultImage failed." << llendl; + LL_WARNS() << "LLViewerTexture::bindDefaultImage failed." << LL_ENDL; } stop_glerror(); //check if there is cached raw image and switch to it if possible - switchToCachedImage() ; + switchToCachedImage(); #if 0 LLTexturePipelineTester* tester = (LLTexturePipelineTester*)LLMetricPerformanceTesterBasic::getTester(sTesterName); if (tester) { - tester->updateGrayTextureBinding() ; + tester->updateGrayTextureBinding(); } #endif return res; @@ -689,17 +779,17 @@ void LLViewerTexture::addTextureStats(F32 virtual_size, BOOL needs_gltexture) co { if(needs_gltexture) { - mNeedsGLTexture = TRUE ; + mNeedsGLTexture = TRUE; } virtual_size *= sTexelPixelRatio; if(!mMaxVirtualSizeResetCounter) { //flag to reset the values because the old values are used. - resetMaxVirtualSizeResetCounter() ; + resetMaxVirtualSizeResetCounter(); mMaxVirtualSize = virtual_size; - mAdditionalDecodePriority = 0.f ; - mNeedsGLTexture = needs_gltexture ; + mAdditionalDecodePriority = 0.f; + mNeedsGLTexture = needs_gltexture; } else if (virtual_size > mMaxVirtualSize) { @@ -709,15 +799,15 @@ void LLViewerTexture::addTextureStats(F32 virtual_size, BOOL needs_gltexture) co void LLViewerTexture::resetTextureStats() { - mMaxVirtualSize = 0.0f ; - mAdditionalDecodePriority = 0.f ; - mMaxVirtualSizeResetCounter = 0 ; + mMaxVirtualSize = 0.0f; + mAdditionalDecodePriority = 0.f; + mMaxVirtualSizeResetCounter = 0; } //virtual F32 LLViewerTexture::getMaxVirtualSize() { - return mMaxVirtualSize ; + return mMaxVirtualSize; } //virtual @@ -727,123 +817,156 @@ void LLViewerTexture::setKnownDrawSize(S32 width, S32 height) } //virtual -void LLViewerTexture::addFace(LLFace* facep) +void LLViewerTexture::addFace(U32 ch, LLFace* facep) { - if(mNumFaces >= mFaceList.size()) + llassert(ch < LLRender::NUM_TEXTURE_CHANNELS); + + if(mNumFaces[ch] >= mFaceList[ch].size()) { - mFaceList.resize(2 * mNumFaces + 1) ; + mFaceList[ch].resize(2 * mNumFaces[ch] + 1); } - mFaceList[mNumFaces] = facep ; - facep->setIndexInTex(mNumFaces) ; - mNumFaces++ ; - mLastFaceListUpdateTimer.reset() ; + mFaceList[ch][mNumFaces[ch]] = facep; + facep->setIndexInTex(ch, mNumFaces[ch]); + mNumFaces[ch]++; + mLastFaceListUpdateTimer.reset(); } //virtual -void LLViewerTexture::removeFace(LLFace* facep) +void LLViewerTexture::removeFace(U32 ch, LLFace* facep) { - if(mNumFaces > 1) + if (ch >= LLRender::NUM_TEXTURE_CHANNELS) // Suppress Linux warning, this should NEVER happen! { - S32 index = facep->getIndexInTex() ; - mFaceList[index] = mFaceList[--mNumFaces] ; - mFaceList[index]->setIndexInTex(index) ; + LL_ERRS() << ch << " >= LLRender::NUM_TEXTURE_CHANNELS!!!" << LL_ENDL; + return; + } + + if(mNumFaces[ch] > 1) + { + S32 index = facep->getIndexInTex(ch); + llassert(index < (S32)mFaceList[ch].size()); + llassert(index < (S32)mNumFaces[ch]); + mFaceList[ch][index] = mFaceList[ch][--mNumFaces[ch]]; + mFaceList[ch][index]->setIndexInTex(ch, index); } else { - mFaceList.clear() ; - mNumFaces = 0 ; + mFaceList[ch].clear(); + mNumFaces[ch] = 0; + } + mLastFaceListUpdateTimer.reset(); +} + +S32 LLViewerTexture::getTotalNumFaces() const +{ + S32 ret = 0; + + for (U32 i = 0; i < LLRender::NUM_TEXTURE_CHANNELS; ++i) + { + ret += mNumFaces[i]; } - mLastFaceListUpdateTimer.reset() ; + + return ret; } -S32 LLViewerTexture::getNumFaces() const +S32 LLViewerTexture::getNumFaces(U32 ch) const { - return mNumFaces ; + llassert(ch < LLRender::NUM_TEXTURE_CHANNELS); + return mNumFaces[ch]; } //virtual -void LLViewerTexture::addVolume(LLVOVolume* volumep) +void LLViewerTexture::addVolume(U32 ch, LLVOVolume* volumep) { - if( mNumVolumes >= mVolumeList.size()) + if (mNumVolumes[ch] >= mVolumeList[ch].size()) { - mVolumeList.resize(2 * mNumVolumes + 1) ; + mVolumeList[ch].resize(2 * mNumVolumes[ch] + 1); } - mVolumeList[mNumVolumes] = volumep ; - volumep->setIndexInTex(mNumVolumes) ; - mNumVolumes++ ; - mLastVolumeListUpdateTimer.reset() ; + mVolumeList[ch][mNumVolumes[ch]] = volumep; + volumep->setIndexInTex(ch, mNumVolumes[ch]); + mNumVolumes[ch]++; + mLastVolumeListUpdateTimer.reset(); } //virtual -void LLViewerTexture::removeVolume(LLVOVolume* volumep) +void LLViewerTexture::removeVolume(U32 ch, LLVOVolume* volumep) { - if(mNumVolumes > 1) + if (mNumVolumes[ch] > 1) { - S32 index = volumep->getIndexInTex() ; - mVolumeList[index] = mVolumeList[--mNumVolumes] ; - mVolumeList[index]->setIndexInTex(index) ; + S32 index = volumep->getIndexInTex(ch); + llassert(index < (S32)mVolumeList[ch].size()); + llassert(index < (S32)mNumVolumes[ch]); + mVolumeList[ch][index] = mVolumeList[ch][--mNumVolumes[ch]]; + mVolumeList[ch][index]->setIndexInTex(ch, index); } else { - mVolumeList.clear() ; - mNumVolumes = 0 ; + mVolumeList[ch].clear(); + mNumVolumes[ch] = 0; } - mLastVolumeListUpdateTimer.reset() ; + mLastVolumeListUpdateTimer.reset(); } -S32 LLViewerTexture::getNumVolumes() const +S32 LLViewerTexture::getNumVolumes(U32 ch) const { - return mNumVolumes ; + return mNumVolumes[ch]; } void LLViewerTexture::reorganizeFaceList() { static const F32 MAX_WAIT_TIME = 20.f; // seconds - static const U32 MAX_EXTRA_BUFFER_SIZE = 4 ; + static const U32 MAX_EXTRA_BUFFER_SIZE = 4; - if(mNumFaces + MAX_EXTRA_BUFFER_SIZE > mFaceList.size()) + if(mLastFaceListUpdateTimer.getElapsedTimeF32() < MAX_WAIT_TIME) { - return ; + return; } - if(mLastFaceListUpdateTimer.getElapsedTimeF32() < MAX_WAIT_TIME) + for (U32 i = 0; i < LLRender::NUM_TEXTURE_CHANNELS; ++i) { - return ; - } + if(mNumFaces[i] + MAX_EXTRA_BUFFER_SIZE > mFaceList[i].size()) + { + return; + } - mLastFaceListUpdateTimer.reset() ; - mFaceList.erase(mFaceList.begin() + mNumFaces, mFaceList.end()); + mFaceList[i].erase(mFaceList[i].begin() + mNumFaces[i], mFaceList[i].end()); + } + + mLastFaceListUpdateTimer.reset(); } void LLViewerTexture::reorganizeVolumeList() { static const F32 MAX_WAIT_TIME = 20.f; // seconds - static const U32 MAX_EXTRA_BUFFER_SIZE = 4 ; + static const U32 MAX_EXTRA_BUFFER_SIZE = 4; + - if(mNumVolumes + MAX_EXTRA_BUFFER_SIZE > mVolumeList.size()) + for (U32 i = 0; i < LLRender::NUM_VOLUME_TEXTURE_CHANNELS; ++i) { - return ; + if (mNumVolumes[i] + MAX_EXTRA_BUFFER_SIZE > mVolumeList[i].size()) + { + return; + } } if(mLastVolumeListUpdateTimer.getElapsedTimeF32() < MAX_WAIT_TIME) { - return ; + return; } - mLastVolumeListUpdateTimer.reset() ; - mVolumeList.erase(mVolumeList.begin() + mNumVolumes, mVolumeList.end()); + mLastVolumeListUpdateTimer.reset(); + for (U32 i = 0; i < LLRender::NUM_VOLUME_TEXTURE_CHANNELS; ++i) + { + mVolumeList[i].erase(mVolumeList[i].begin() + mNumVolumes[i], mVolumeList[i].end()); + } } - - //virtual void LLViewerTexture::switchToCachedImage() { //nothing here. } - //virtual void LLViewerTexture::setCachedRawImage(S32 discard_level, LLImageRaw* imageraw) { @@ -852,7 +975,7 @@ void LLViewerTexture::setCachedRawImage(S32 discard_level, LLImageRaw* imageraw) BOOL LLViewerTexture::isLargeImage() { - return (S32)mTexelsPerImage > LLViewerTexture::sMinLargeImageSize ; + return (S32)mTexelsPerImage > LLViewerTexture::sMinLargeImageSize; } //virtual @@ -862,7 +985,7 @@ void LLViewerTexture::updateBindStatsForTester() LLTexturePipelineTester* tester = (LLTexturePipelineTester*)LLMetricPerformanceTesterBasic::getTester(sTesterName); if (tester) { - tester->updateTextureBindingStats(this) ; + tester->updateTextureBindingStats(this); } #endif } @@ -871,41 +994,71 @@ void LLViewerTexture::updateBindStatsForTester() //end of LLViewerTexture //---------------------------------------------------------------------------------------------- +const std::string& fttype_to_string(const FTType& fttype) +{ + static const std::string ftt_unknown("FTT_UNKNOWN"); + static const std::string ftt_default("FTT_DEFAULT"); + static const std::string ftt_server_bake("FTT_SERVER_BAKE"); + static const std::string ftt_host_bake("FTT_HOST_BAKE"); + static const std::string ftt_map_tile("FTT_MAP_TILE"); + static const std::string ftt_local_file("FTT_LOCAL_FILE"); + static const std::string ftt_error("FTT_ERROR"); + switch(fttype) + { + case FTT_UNKNOWN: return ftt_unknown; break; + case FTT_DEFAULT: return ftt_default; break; + case FTT_SERVER_BAKE: return ftt_server_bake; break; + case FTT_HOST_BAKE: return ftt_host_bake; break; + case FTT_MAP_TILE: return ftt_map_tile; break; + case FTT_LOCAL_FILE: return ftt_local_file; break; + } + return ftt_error; +} + //---------------------------------------------------------------------------------------------- //start of LLViewerFetchedTexture //---------------------------------------------------------------------------------------------- -LLViewerFetchedTexture::LLViewerFetchedTexture(const LLUUID& id, const LLHost& host, BOOL usemipmaps) - : LLViewerTexture(id, usemipmaps), - mTargetHost(host) +LLViewerFetchedTexture::LLViewerFetchedTexture(const LLUUID& id, FTType f_type, const LLHost& host, BOOL usemipmaps) + : LLViewerTexture(id, usemipmaps, f_type == FTT_DEFAULT || f_type == FTT_MAP_TILE), + mTargetHost(host), mFTType(f_type) { - init(TRUE) ; - generateGLTexture() ; + init(TRUE); + if (mFTType == FTT_HOST_BAKE) + { + LL_WARNS() << "Unsupported fetch type " << mFTType << LL_ENDL; + } + generateGLTexture(); + mGLTexturep->setNeedsAlphaAndPickMask(TRUE); } -LLViewerFetchedTexture::LLViewerFetchedTexture(const LLImageRaw* raw, BOOL usemipmaps) - : LLViewerTexture(raw, usemipmaps) +LLViewerFetchedTexture::LLViewerFetchedTexture(const LLImageRaw* raw, FTType f_type, BOOL usemipmaps) + : LLViewerTexture(raw, usemipmaps, f_type == FTT_DEFAULT || f_type == FTT_MAP_TILE), + mFTType(f_type) { - init(TRUE) ; + init(TRUE); + mGLTexturep->setNeedsAlphaAndPickMask(TRUE); } -LLViewerFetchedTexture::LLViewerFetchedTexture(const std::string& url, const LLUUID& id, BOOL usemipmaps) - : LLViewerTexture(id, usemipmaps), - mUrl(url) +LLViewerFetchedTexture::LLViewerFetchedTexture(const std::string& url, FTType f_type, const LLUUID& id, BOOL usemipmaps) + : LLViewerTexture(id, usemipmaps, f_type == FTT_DEFAULT || f_type == FTT_MAP_TILE), + mUrl(url), mFTType(f_type) { - init(TRUE) ; - generateGLTexture() ; + init(TRUE); + generateGLTexture(); + mGLTexturep->setNeedsAlphaAndPickMask(TRUE); } void LLViewerFetchedTexture::init(bool firstinit) { mOrigWidth = 0; mOrigHeight = 0; + mHasAux = FALSE; mNeedsAux = FALSE; mRequestedDiscardLevel = -1; mRequestedDownloadPriority = 0.f; mFullyLoaded = FALSE; - mCanUseHTTP = true ; + mCanUseHTTP = true; mDesiredDiscardLevel = MAX_DISCARD_LEVEL + 1; mMinDesiredDiscardLevel = MAX_DISCARD_LEVEL + 1; @@ -913,7 +1066,7 @@ void LLViewerFetchedTexture::init(bool firstinit) mKnownDrawWidth = 0; mKnownDrawHeight = 0; - mKnownDrawSizeChanged = FALSE ; + mKnownDrawSizeChanged = FALSE; if (firstinit) { @@ -926,7 +1079,7 @@ void LLViewerFetchedTexture::init(bool firstinit) mIsMissingAsset = FALSE; mLoadedCallbackDesiredDiscardLevel = S8_MAX; - mPauseLoadedCallBacks = TRUE ; + mPauseLoadedCallBacks = FALSE; mNeedsCreateTexture = FALSE; @@ -941,23 +1094,24 @@ void LLViewerFetchedTexture::init(bool firstinit) mDownloadProgress = 0.f; mFetchDeltaTime = 999999.f; mRequestDeltaTime = 0.f; - mForSculpt = FALSE ; - mIsFetched = FALSE ; + mForSculpt = FALSE; + mIsFetched = FALSE; if(!firstinit && mCachedRawImage.notNull()) mCachedRawImage->setInCache(false); - mCachedRawImage = NULL ; - mCachedRawDiscardLevel = -1 ; - mCachedRawImageReady = FALSE ; + mCachedRawImage = NULL; + mCachedRawDiscardLevel = -1; + mCachedRawImageReady = FALSE; - mSavedRawImage = NULL ; - mForceToSaveRawImage = FALSE ; - mSaveRawImage = FALSE ; - mSavedRawDiscardLevel = -1 ; - mDesiredSavedRawDiscardLevel = -1 ; - mLastReferencedSavedRawImageTime = 0.0f ; - mKeptSavedRawImageTime = 0.f ; + mSavedRawImage = NULL; + mForceToSaveRawImage = FALSE; + mSaveRawImage = FALSE; + mSavedRawDiscardLevel = -1; + mDesiredSavedRawDiscardLevel = -1; + mLastReferencedSavedRawImageTime = 0.0f; + mKeptSavedRawImageTime = 0.f; mLastCallBackActiveTime = 0.f; + mForceCallbackFetch = FALSE; } LLViewerFetchedTexture::~LLViewerFetchedTexture() @@ -975,7 +1129,12 @@ LLViewerFetchedTexture::~LLViewerFetchedTexture() //virtual S8 LLViewerFetchedTexture::getType() const { - return LLViewerTexture::FETCHED_TEXTURE ; + return LLViewerTexture::FETCHED_TEXTURE; +} + +FTType LLViewerFetchedTexture::getFTType() const +{ + return mFTType; } void LLViewerFetchedTexture::cleanup() @@ -987,7 +1146,7 @@ void LLViewerFetchedTexture::cleanup() // We never finished loading the image. Indicate failure. // Note: this allows mLoadedCallbackUserData to be cleaned up. entryp->mCallback( FALSE, this, NULL, NULL, 0, TRUE, entryp->mUserData ); - entryp->removeTexture(this) ; + entryp->removeTexture(this); delete entryp; } mLoadedCallbackList.clear(); @@ -997,10 +1156,10 @@ void LLViewerFetchedTexture::cleanup() destroyRawImage(); if(mCachedRawImage.notNull()) mCachedRawImage->setInCache(false); - mCachedRawImage = NULL ; - mCachedRawDiscardLevel = -1 ; - mCachedRawImageReady = FALSE ; - mSavedRawImage = NULL ; + mCachedRawImage = NULL; + mCachedRawDiscardLevel = -1; + mCachedRawImageReady = FALSE; + mSavedRawImage = NULL; mSavedRawDiscardLevel = -1; } @@ -1030,43 +1189,43 @@ void LLViewerFetchedTexture::forceRefetch() void LLViewerFetchedTexture::setForSculpt() { - static const S32 MAX_INTERVAL = 8 ; //frames + static const S32 MAX_INTERVAL = 8; //frames - mForSculpt = TRUE ; + mForSculpt = TRUE; if(isForSculptOnly() && hasGLTexture() && !getBoundRecently()) { - destroyGLTexture() ; //sculpt image does not need gl texture. + destroyGLTexture(); //sculpt image does not need gl texture. mTextureState = ACTIVE; } - checkCachedRawSculptImage() ; - setMaxVirtualSizeResetInterval(MAX_INTERVAL) ; + checkCachedRawSculptImage(); + setMaxVirtualSizeResetInterval(MAX_INTERVAL); } BOOL LLViewerFetchedTexture::isForSculptOnly() const { - return mForSculpt && !mNeedsGLTexture ; + return mForSculpt && !mNeedsGLTexture; } BOOL LLViewerFetchedTexture::isDeleted() { - return mTextureState == DELETED ; + return mTextureState == DELETED; } BOOL LLViewerFetchedTexture::isInactive() { - return mTextureState == INACTIVE ; + return mTextureState == INACTIVE; } BOOL LLViewerFetchedTexture::isDeletionCandidate() { - return mTextureState == DELETION_CANDIDATE ; + return mTextureState == DELETION_CANDIDATE; } void LLViewerFetchedTexture::setDeletionCandidate() { if(mGLTexturep.notNull() && mGLTexturep->getTexName() && (mTextureState == INACTIVE)) { - mTextureState = DELETION_CANDIDATE ; + mTextureState = DELETION_CANDIDATE; } } @@ -1075,7 +1234,7 @@ void LLViewerFetchedTexture::setInactive() { if(mTextureState == ACTIVE && mGLTexturep.notNull() && mGLTexturep->getTexName() && !mGLTexturep->getBoundRecently()) { - mTextureState = INACTIVE ; + mTextureState = INACTIVE; } } @@ -1092,84 +1251,86 @@ void LLViewerFetchedTexture::dump() { LLViewerTexture::dump(); - llinfos << "Dump : " << mID + LL_INFOS() << "Dump : " << mID << ", mIsMissingAsset = " << (S32)mIsMissingAsset << ", mFullWidth = " << (S32)mFullWidth << ", mFullHeight = " << (S32)mFullHeight << ", mOrigWidth = " << (S32)mOrigWidth << ", mOrigHeight = " << (S32)mOrigHeight - << llendl; - llinfos << " : " + << LL_ENDL; + LL_INFOS() << " : " << " mFullyLoaded = " << (S32)mFullyLoaded << ", mFetchState = " << (S32)mFetchState << ", mFetchPriority = " << (S32)mFetchPriority << ", mDownloadProgress = " << (F32)mDownloadProgress - << llendl; - llinfos << " : " + << LL_ENDL; + LL_INFOS() << " : " << " mHasFetcher = " << (S32)mHasFetcher << ", mIsFetching = " << (S32)mIsFetching << ", mIsFetched = " << (S32)mIsFetched << ", mBoostLevel = " << (S32)mBoostLevel - << llendl; + << LL_ENDL; } /////////////////////////////////////////////////////////////////////////////// // ONLY called from LLViewerFetchedTextureList void LLViewerFetchedTexture::destroyTexture() { - if(LLImageGL::sGlobalTextureMemoryInBytes < sMaxDesiredTextureMemInBytes * 0.95f)//not ready to release unused memory. + if(LLImageGL::sGlobalTextureMemory < sMaxDesiredTextureMem * 0.95f)//not ready to release unused memory. { return ; } if (mNeedsCreateTexture)//return if in the process of generating a new texture. { - return ; + return; } - - destroyGLTexture() ; - mFullyLoaded = FALSE ; + + //LL_DEBUGS("Avatar") << mID << LL_ENDL; + destroyGLTexture(); + mFullyLoaded = FALSE; } void LLViewerFetchedTexture::addToCreateTexture() { - bool force_update = false ; + bool force_update = false; if (getComponents() != mRawImage->getComponents()) { // We've changed the number of components, so we need to move any // objects using this pool to a different pool. mComponents = mRawImage->getComponents(); - mGLTexturep->setComponents(mComponents) ; - force_update = true ; + mGLTexturep->setComponents(mComponents); + force_update = true; - for(U32 i = 0 ; i < mNumFaces ; i++) + for (U32 j = 0; j < LLRender::NUM_TEXTURE_CHANNELS; ++j) { - LLFace* facep = mFaceList[i]; - if(facep) + llassert(mNumFaces[j] <= mFaceList[j].size()); + + for(U32 i = 0; i < mNumFaces[j]; i++) { - facep->dirtyTexture() ; + mFaceList[j][i]->dirtyTexture(); } } //discard the cached raw image and the saved raw image - mCachedRawImageReady = FALSE ; - mCachedRawDiscardLevel = -1 ; + mCachedRawImageReady = FALSE; + mCachedRawDiscardLevel = -1; if(mCachedRawImage.notNull()) mCachedRawImage->setInCache(false); - mCachedRawImage = NULL ; - mSavedRawDiscardLevel = -1 ; - mSavedRawImage = NULL ; + mCachedRawImage = NULL; + mSavedRawDiscardLevel = -1; + mSavedRawImage = NULL; } if(isForSculptOnly()) { //just update some variables, not to create a real GL texture. - createGLTexture(mRawDiscardLevel, mRawImage, 0, FALSE) ; - mNeedsCreateTexture = FALSE ; + createGLTexture(mRawDiscardLevel, mRawImage, nullptr, FALSE); + mNeedsCreateTexture = FALSE; destroyRawImage(); } else if(!force_update && getDiscardLevel() > -1 && getDiscardLevel() <= mRawDiscardLevel) { - mNeedsCreateTexture = FALSE ; + mNeedsCreateTexture = FALSE; destroyRawImage(); } else @@ -1189,11 +1350,11 @@ void LLViewerFetchedTexture::addToCreateTexture() //scale it down to size >= LLViewerTexture::sMinLargeImageSize if(w * h > LLViewerTexture::sMinLargeImageSize) { - S32 d_level = llmin(mRequestedDiscardLevel, (S32)mDesiredDiscardLevel) - mRawDiscardLevel ; + S32 d_level = llmin(mRequestedDiscardLevel, (S32)mDesiredDiscardLevel) - mRawDiscardLevel; if(d_level > 0) { - S32 i = 0 ; + S32 i = 0; while((d_level > 0) && ((w >> i) * (h >> i) > LLViewerTexture::sMinLargeImageSize)) { i++; @@ -1201,14 +1362,19 @@ void LLViewerFetchedTexture::addToCreateTexture() } if(i > 0) { - mRawDiscardLevel += i ; + mRawDiscardLevel += i; if(mRawDiscardLevel >= getDiscardLevel() && getDiscardLevel() > 0) { - mNeedsCreateTexture = FALSE ; + mNeedsCreateTexture = FALSE; destroyRawImage(); - return ; + return; + } + + { + //make a duplicate in case somebody else is using this raw image + mRawImage = mRawImage->duplicate(); + mRawImage->scale(w >> i, h >> i); } - mRawImage->scale(w >> i, h >> i) ; } } } @@ -1217,95 +1383,135 @@ void LLViewerFetchedTexture::addToCreateTexture() mNeedsCreateTexture = TRUE; gTextureList.mCreateTextureList.insert(this); } - return ; + return; } // ONLY called from LLViewerTextureList -BOOL LLViewerFetchedTexture::createTexture(S32 usename/*= 0*/) +BOOL LLViewerFetchedTexture::createTexture(LLImageGL::GLTextureName* usename) { if (!mNeedsCreateTexture) { destroyRawImage(); return FALSE; } - mNeedsCreateTexture = FALSE; + mNeedsCreateTexture = FALSE; if (mRawImage.isNull()) { - llerrs << "LLViewerTexture trying to create texture with no Raw Image" << llendl; + LL_WARNS() << "LLViewerTexture trying to create texture with no Raw Image" << LL_ENDL; } -// llinfos << llformat("IMAGE Creating (%d) [%d x %d] Bytes: %d ", +// LL_INFOS() << llformat("IMAGE Creating (%d) [%d x %d] Bytes: %d ", // mRawDiscardLevel, // mRawImage->getWidth(), mRawImage->getHeight(),mRawImage->getDataSize()) -// << mID.getString() << llendl; +// << mID.getString() << LL_ENDL; BOOL res = TRUE; - if (!gNoRender) + + // store original size only for locally-sourced images + if (mUrl.compare(0, 7, "file://") == 0) { - // store original size only for locally-sourced images - if (mUrl.compare(0, 7, "file://") == 0) - { - mOrigWidth = mRawImage->getWidth(); - mOrigHeight = mRawImage->getHeight(); + mOrigWidth = mRawImage->getWidth(); + mOrigHeight = mRawImage->getHeight(); - if (mBoostLevel == BOOST_PREVIEW) - { - mRawImage->biasedScaleToPowerOfTwo(1024); - } - else - { // leave black border, do not scale image content - mRawImage->expandToPowerOfTwo(MAX_IMAGE_SIZE, FALSE); - } - - mFullWidth = mRawImage->getWidth(); - mFullHeight = mRawImage->getHeight(); - setTexelsPerImage(); + if (mBoostLevel == BOOST_PREVIEW) + { + mRawImage->biasedScaleToPowerOfTwo(1024); } else - { - mOrigWidth = mFullWidth; - mOrigHeight = mFullHeight; + { // leave black border, do not scale image content + mRawImage->expandToPowerOfTwo(MAX_IMAGE_SIZE, FALSE); } - - bool size_okay = true; - U32 raw_width = mRawImage->getWidth() << mRawDiscardLevel; - U32 raw_height = mRawImage->getHeight() << mRawDiscardLevel; - if( raw_width > MAX_IMAGE_SIZE || raw_height > MAX_IMAGE_SIZE ) - { - llinfos << "Width or height is greater than " << MAX_IMAGE_SIZE << ": (" << raw_width << "," << raw_height << ")" << llendl; - size_okay = false; - } - - if (!LLImageGL::checkSize(mRawImage->getWidth(), mRawImage->getHeight())) - { - // A non power-of-two image was uploaded (through a non standard client) - llinfos << "Non power of two width or height: (" << mRawImage->getWidth() << "," << mRawImage->getHeight() << ")" << llendl; - size_okay = false; - } - - if( !size_okay ) + mFullWidth = mRawImage->getWidth(); + mFullHeight = mRawImage->getHeight(); + setTexelsPerImage(); + } + else + { + mOrigWidth = mFullWidth; + mOrigHeight = mFullHeight; + } + + if (!mRawImage->mComment.empty()) + { + // a is for uploader + // z is for time + // K is the whole thing (just coz) + std::string comment = mRawImage->getComment(); + mComment['K'] = comment; + size_t position = 0; + size_t length = comment.length(); + while (position < length) { - // An inappropriately-sized image was uploaded (through a non standard client) - // We treat these images as missing assets which causes them to - // be renderd as 'missing image' and to stop requesting data - setIsMissingAsset(); - destroyRawImage(); - return FALSE; + std::size_t equals_position = comment.find('=', position); + if (equals_position != std::string::npos) + { + S8 type = comment.at(equals_position - 1); + position = comment.find('&', position); + if (position != std::string::npos) + { + mComment[type] = comment.substr(equals_position + 1, position - (equals_position + 1)); + position++; + } + else + { + mComment[type] = comment.substr(equals_position + 1, length - (equals_position + 1)); + } + } + else + { + position = equals_position; + } } - - //if(!(res = insertToAtlas())) - //{ - res = mGLTexturep->createGLTexture(mRawDiscardLevel, mRawImage, usename, TRUE, mBoostLevel); - //resetFaceAtlas() ; - //} - setActive() ; } + bool size_okay = true; + + S32 discard_level = mRawDiscardLevel; + if (mRawDiscardLevel < 0) + { + LL_DEBUGS() << "Negative raw discard level when creating image: " << mRawDiscardLevel << LL_ENDL; + discard_level = 0; + } + + U32 raw_width = mRawImage->getWidth() << discard_level; + U32 raw_height = mRawImage->getHeight() << discard_level; + + if( raw_width > MAX_IMAGE_SIZE || raw_height > MAX_IMAGE_SIZE ) + { + LL_INFOS() << "Width or height is greater than " << MAX_IMAGE_SIZE << ": (" << raw_width << "," << raw_height << ")" << LL_ENDL; + size_okay = false; + } + + if (!LLImageGL::checkSize(mRawImage->getWidth(), mRawImage->getHeight())) + { + // A non power-of-two image was uploaded (through a non standard client) + LL_INFOS() << "Non power of two width or height: (" << mRawImage->getWidth() << "," << mRawImage->getHeight() << ")" << LL_ENDL; + size_okay = false; + } + + if( !size_okay ) + { + // An inappropriately-sized image was uploaded (through a non standard client) + // We treat these images as missing assets which causes them to + // be renderd as 'missing image' and to stop requesting data + LL_WARNS() << "!size_ok, setting as missing" << LL_ENDL; + setIsMissingAsset(); + destroyRawImage(); + return FALSE; + } + + res = mGLTexturep->createGLTexture(mRawDiscardLevel, mRawImage, usename, TRUE, mBoostLevel); + + notifyAboutCreatingTexture(); + + setActive(); + if (!needsToSaveRawImage()) { mNeedsAux = FALSE; destroyRawImage(); } + return res; } @@ -1315,11 +1521,11 @@ void LLViewerFetchedTexture::setKnownDrawSize(S32 width, S32 height) { if(mKnownDrawWidth < width || mKnownDrawHeight < height) { - mKnownDrawWidth = llmax(mKnownDrawWidth, width) ; - mKnownDrawHeight = llmax(mKnownDrawHeight, height) ; + mKnownDrawWidth = llmax(mKnownDrawWidth, width); + mKnownDrawHeight = llmax(mKnownDrawHeight, height); - mKnownDrawSizeChanged = TRUE ; - mFullyLoaded = FALSE ; + mKnownDrawSizeChanged = TRUE; + mFullyLoaded = FALSE; } addTextureStats((F32)(mKnownDrawWidth * mKnownDrawHeight)); } @@ -1331,29 +1537,45 @@ void LLViewerFetchedTexture::processTextureStats() { if(mDesiredDiscardLevel > mMinDesiredDiscardLevel)//need to load more { - mDesiredDiscardLevel = llmin(mDesiredDiscardLevel, mMinDesiredDiscardLevel) ; - mFullyLoaded = FALSE ; + mDesiredDiscardLevel = llmin(mDesiredDiscardLevel, mMinDesiredDiscardLevel); + mFullyLoaded = FALSE; } } else { - updateVirtualSize() ; + updateVirtualSize(); - static LLCachedControl textures_fullres(gSavedSettings,"TextureLoadFullRes"); + static LLCachedControl textures_fullres(gSavedSettings,"TextureLoadFullRes", false); if (textures_fullres) { mDesiredDiscardLevel = 0; } + else if (!LLPipeline::sRenderDeferred && mBoostLevel == LLGLTexture::BOOST_ALM) + { + mDesiredDiscardLevel = MAX_DISCARD_LEVEL + 1; + } + else if (mDontDiscard && mBoostLevel == LLGLTexture::BOOST_ICON) + { + if (mFullWidth > MAX_IMAGE_SIZE_DEFAULT || mFullHeight > MAX_IMAGE_SIZE_DEFAULT) + { + mDesiredDiscardLevel = 1; // MAX_IMAGE_SIZE_DEFAULT = 1024 and max size ever is 2048 + } + else + { + mDesiredDiscardLevel = 0; + } + } else if(!mFullWidth || !mFullHeight) { - mDesiredDiscardLevel = llmin(getMaxDiscardLevel(), (S32)mLoadedCallbackDesiredDiscardLevel) ; + mDesiredDiscardLevel = llmin(getMaxDiscardLevel(), (S32)mLoadedCallbackDesiredDiscardLevel); } else { + U32 desired_size = MAX_IMAGE_SIZE_DEFAULT; // MAX_IMAGE_SIZE_DEFAULT = 1024 and max size ever is 2048 if(!mKnownDrawWidth || !mKnownDrawHeight || mFullWidth <= mKnownDrawWidth || mFullHeight <= mKnownDrawHeight) { - if (mFullWidth > MAX_IMAGE_SIZE_DEFAULT || mFullHeight > MAX_IMAGE_SIZE_DEFAULT) + if ((U32)mFullWidth > desired_size || (U32)mFullHeight > desired_size) { mDesiredDiscardLevel = 1; // MAX_IMAGE_SIZE_DEFAULT = 1024 and max size ever is 2048 } @@ -1365,36 +1587,36 @@ void LLViewerFetchedTexture::processTextureStats() else if(mKnownDrawSizeChanged)//known draw size is set { mDesiredDiscardLevel = (S8)llmin(log((F32)mFullWidth / mKnownDrawWidth) / log_2, - log((F32)mFullHeight / mKnownDrawHeight) / log_2) ; - mDesiredDiscardLevel = llclamp(mDesiredDiscardLevel, (S8)0, (S8)getMaxDiscardLevel()) ; - mDesiredDiscardLevel = llmin(mDesiredDiscardLevel, mMinDesiredDiscardLevel) ; + log((F32)mFullHeight / mKnownDrawHeight) / log_2); + mDesiredDiscardLevel = llclamp(mDesiredDiscardLevel, (S8)0, (S8)getMaxDiscardLevel()); + mDesiredDiscardLevel = llmin(mDesiredDiscardLevel, mMinDesiredDiscardLevel); } - mKnownDrawSizeChanged = FALSE ; + mKnownDrawSizeChanged = FALSE; if(getDiscardLevel() >= 0 && (getDiscardLevel() <= mDesiredDiscardLevel)) { - mFullyLoaded = TRUE ; + mFullyLoaded = TRUE; } } } if(mForceToSaveRawImage && mDesiredSavedRawDiscardLevel >= 0) //force to refetch the texture. { - mDesiredDiscardLevel = llmin(mDesiredDiscardLevel, (S8)mDesiredSavedRawDiscardLevel) ; + mDesiredDiscardLevel = llmin(mDesiredDiscardLevel, (S8)mDesiredSavedRawDiscardLevel); if(getDiscardLevel() < 0 || getDiscardLevel() > mDesiredDiscardLevel) { - mFullyLoaded = FALSE ; + mFullyLoaded = FALSE; } } } -const F32 MAX_PRIORITY_PIXEL = 999.f ; //pixel area -const F32 PRIORITY_BOOST_LEVEL_FACTOR = 1000.f ; //boost level -const F32 PRIORITY_DELTA_DISCARD_LEVEL_FACTOR = 100000.f ; //delta discard -const S32 MAX_DELTA_DISCARD_LEVEL_FOR_PRIORITY = 4 ; -const F32 PRIORITY_ADDITIONAL_FACTOR = 1000000.f ; //additional -const S32 MAX_ADDITIONAL_LEVEL_FOR_PRIORITY = 8 ; -const F32 PRIORITY_BOOST_HIGH_FACTOR = 10000000.f ;//boost high +const F32 MAX_PRIORITY_PIXEL = 999.f; //pixel area +const F32 PRIORITY_BOOST_LEVEL_FACTOR = 1000.f; //boost level +const F32 PRIORITY_DELTA_DISCARD_LEVEL_FACTOR = 100000.f; //delta discard +const S32 MAX_DELTA_DISCARD_LEVEL_FOR_PRIORITY = 4; +const F32 PRIORITY_ADDITIONAL_FACTOR = 1000000.f; //additional +const S32 MAX_ADDITIONAL_LEVEL_FOR_PRIORITY = 8; +const F32 PRIORITY_BOOST_HIGH_FACTOR = 10000000.f;//boost high F32 LLViewerFetchedTexture::calcDecodePriority() { #ifndef LL_RELEASE_FOR_DOWNLOAD @@ -1410,7 +1632,7 @@ F32 LLViewerFetchedTexture::calcDecodePriority() } if(mFullyLoaded && !mForceToSaveRawImage)//already loaded for static texture { - return -1.0f ; //alreay fetched + return -1.0f; //alreay fetched } S32 cur_discard = getCurrentDiscardLevelForFetching(); @@ -1425,7 +1647,7 @@ F32 LLViewerFetchedTexture::calcDecodePriority() } else if(mDesiredDiscardLevel >= cur_discard && cur_discard > -1) { - priority = -2.0f ; + priority = -2.0f; } else if(mCachedRawDiscardLevel > -1 && mDesiredDiscardLevel >= mCachedRawDiscardLevel) { @@ -1462,7 +1684,7 @@ F32 LLViewerFetchedTexture::calcDecodePriority() S32 ddiscard = MAX_DISCARD_LEVEL - (S32)desired; ddiscard = llclamp(ddiscard, 0, MAX_DELTA_DISCARD_LEVEL_FOR_PRIORITY); priority = (ddiscard + 1) * PRIORITY_DELTA_DISCARD_LEVEL_FACTOR; - setAdditionalDecodePriority(1.0f) ;//boost the textures without any data so far. + setAdditionalDecodePriority(0.1f);//boost the textures without any data so far. } else if ((mMinDiscardLevel > 0) && (cur_discard <= mMinDiscardLevel)) { @@ -1497,13 +1719,13 @@ F32 LLViewerFetchedTexture::calcDecodePriority() // [10,000,000] + [1,000,000-9,000,000] + [100,000-500,000] + [1-20,000] + [0-999] if (priority > 0.0f) { - bool large_enough = mCachedRawImageReady && ((S32)mTexelsPerImage > sMinLargeImageSize) ; + bool large_enough = mCachedRawImageReady && ((S32)mTexelsPerImage > sMinLargeImageSize); if(large_enough) { //Note: //to give small, low-priority textures some chance to be fetched, //cut the priority in half if the texture size is larger than 256 * 256 and has a 64*64 ready. - priority *= 0.5f ; + priority *= 0.5f; } pixel_priority = llclamp(pixel_priority, 0.0f, MAX_PRIORITY_PIXEL); @@ -1522,7 +1744,7 @@ F32 LLViewerFetchedTexture::calcDecodePriority() //Note: //to give small, low-priority textures some chance to be fetched, //if high priority texture has a 64*64 ready, lower its fetching priority. - setAdditionalDecodePriority(0.5f) ; + setAdditionalDecodePriority(0.5f); } else { @@ -1539,7 +1761,7 @@ F32 LLViewerFetchedTexture::calcDecodePriority() //Note: //to give small, low-priority textures some chance to be fetched, //cut the additional priority to a quarter if the texture size is larger than 256 * 256 and has a 64*64 ready. - additional *= 0.25f ; + additional *= 0.25f; } priority += additional; } @@ -1554,9 +1776,9 @@ F32 LLViewerFetchedTexture::maxDecodePriority() PRIORITY_ADDITIONAL_FACTOR * (MAX_ADDITIONAL_LEVEL_FOR_PRIORITY + 1) + //additional (view dependent factors) PRIORITY_DELTA_DISCARD_LEVEL_FACTOR * (MAX_DELTA_DISCARD_LEVEL_FOR_PRIORITY + 1) + //delta discard PRIORITY_BOOST_LEVEL_FACTOR * (BOOST_MAX_LEVEL - 1) + //boost level - MAX_PRIORITY_PIXEL + 1.0f ; //pixel area. + MAX_PRIORITY_PIXEL + 1.0f; //pixel area. - return max_priority ; + return max_priority; } //============================================================================ @@ -1569,7 +1791,7 @@ void LLViewerFetchedTexture::setDecodePriority(F32 priority) if(mDecodePriority < F_ALMOST_ZERO) { - mStopFetchingTimer.reset() ; + mStopFetchingTimer.reset(); } } @@ -1586,43 +1808,90 @@ void LLViewerFetchedTexture::updateVirtualSize() { if(!mMaxVirtualSizeResetCounter) { - addTextureStats(0.f, FALSE) ;//reset + addTextureStats(0.f, FALSE);//reset } - for(U32 i = 0 ; i < mNumFaces ; i++) - { - LLFace* facep = mFaceList[i] ; - if(facep && facep->getDrawable() && facep->getDrawable()->isRecentlyVisible()) - { - addTextureStats(facep->getVirtualSize()) ; - setAdditionalDecodePriority(facep->getImportanceToCamera()) ; + for (U32 ch = 0; ch < LLRender::NUM_TEXTURE_CHANNELS; ++ch) + { + llassert(mNumFaces[ch] <= mFaceList[ch].size()); + + for(U32 i = 0; i < mNumFaces[ch]; i++) + { + LLFace* facep = mFaceList[ch][i]; + if( facep ) + { + LLDrawable* drawable = facep->getDrawable(); + if (drawable) + { + if(drawable->isRecentlyVisible()) + { + if ((getBoostLevel() == LLViewerTexture::BOOST_NONE || getBoostLevel() == LLViewerTexture::BOOST_ALM) + && drawable->getVObj() + && drawable->getVObj()->isSelected()) + { + setBoostLevel(LLViewerTexture::BOOST_SELECTED); + } + addTextureStats(facep->getVirtualSize()); + setAdditionalDecodePriority(facep->getImportanceToCamera()); + } + } + } } } + //reset whether or not a face was selected after 10 seconds + const F32 SELECTION_RESET_TIME = 10.f; + + if (getBoostLevel() == LLViewerTexture::BOOST_SELECTED && + gFrameTimeSeconds - mSelectedTime > SELECTION_RESET_TIME) + { + setBoostLevel(LLViewerTexture::BOOST_NONE); + } if(mMaxVirtualSizeResetCounter > 0) { mMaxVirtualSizeResetCounter--; } - reorganizeFaceList() ; + reorganizeFaceList(); reorganizeVolumeList(); } S32 LLViewerFetchedTexture::getCurrentDiscardLevelForFetching() { - S32 current_discard = getDiscardLevel() ; + S32 current_discard = getDiscardLevel(); if(mForceToSaveRawImage) { if(mSavedRawDiscardLevel < 0 || current_discard < 0) { - current_discard = -1 ; + current_discard = -1; } else { - current_discard = llmax(current_discard, mSavedRawDiscardLevel) ; + current_discard = llmax(current_discard, mSavedRawDiscardLevel); } } - return current_discard ; + return current_discard; +} + +bool LLViewerFetchedTexture::setDebugFetching(S32 debug_level) +{ + if(debug_level < 0) + { + mInDebug = FALSE; + return false; + } + mInDebug = TRUE; + + mDesiredDiscardLevel = debug_level; + + return true; +} + +bool LLViewerFetchedTexture::isActiveFetching() +{ + static LLCachedControl monitor_enabled(gSavedSettings,"DebugShowTextureInfo"); + + return mFetchState > 7 && mFetchState < 10 && monitor_enabled; //in state of WAIT_HTTP_REQ or DECODE_IMAGE. } bool LLViewerFetchedTexture::updateFetch() @@ -1630,9 +1899,10 @@ bool LLViewerFetchedTexture::updateFetch() static LLCachedControl textures_decode_disabled(gSavedSettings,"TextureDecodeDisabled"); static LLCachedControl sCameraMotionThreshold(gSavedSettings,"TextureCameraMotionThreshold"); static LLCachedControl sCameraMotionBoost(gSavedSettings,"TextureCameraMotionBoost"); - if(textures_decode_disabled) + if(textures_decode_disabled || + (gUseWireframe && mBoostLevel < LLGLTexture::BOOST_AVATAR_BAKED_SELF)) // don't fetch the surface textures in wireframe mode { - return false ; + return false; } mFetchState = 0; @@ -1655,7 +1925,7 @@ bool LLViewerFetchedTexture::updateFetch() } if (mIsMissingAsset) { - llassert_always(!mHasFetcher); + llassert(!mHasFetcher); return false; // skip } if (!mLoadedCallbackList.empty() && mRawImage.notNull()) @@ -1663,7 +1933,7 @@ bool LLViewerFetchedTexture::updateFetch() return false; // process any raw image data in callbacks before replacing } - S32 current_discard = getCurrentDiscardLevelForFetching() ; + S32 current_discard = getCurrentDiscardLevelForFetching(); S32 desired_discard = getDesiredDiscardLevel(); F32 decode_priority = getDecodePriority(); decode_priority = llclamp(decode_priority, 0.0f, maxDecodePriority()); @@ -1677,11 +1947,15 @@ bool LLViewerFetchedTexture::updateFetch() if (mAuxRawImage.notNull()) sAuxCount--; bool finished = LLAppViewer::getTextureFetch()->getRequestFinished(getID(), fetch_discard, mRawImage, mAuxRawImage); if (mRawImage.notNull()) sRawCount++; - if (mAuxRawImage.notNull()) sAuxCount++; + if (mAuxRawImage.notNull()) + { + mHasAux = TRUE; + sAuxCount++; + } if (finished) { mIsFetching = FALSE; - mLastPacketTimer.reset() ; + mLastPacketTimer.reset(); } else { @@ -1696,8 +1970,8 @@ bool LLViewerFetchedTexture::updateFetch() LLTexturePipelineTester* tester = (LLTexturePipelineTester*)LLMetricPerformanceTesterBasic::getTester(sTesterName); if (tester) { - mIsFetched = TRUE ; - tester->updateTextureLoadingStats(this, mRawImage, LLAppViewer::getTextureFetch()->isFromLocalCache(mID)) ; + mIsFetched = TRUE; + tester->updateTextureLoadingStats(this, mRawImage, LLAppViewer::getTextureFetch()->isFromLocalCache(mID)); } #endif mRawDiscardLevel = fetch_discard; @@ -1712,18 +1986,30 @@ bool LLViewerFetchedTexture::updateFetch() { //discard all oversized textures. destroyRawImage(); + LL_WARNS() << "oversize, setting as missing" << LL_ENDL; setIsMissingAsset(); - mRawDiscardLevel = INVALID_DISCARD_LEVEL ; - mIsFetching = FALSE ; + mRawDiscardLevel = INVALID_DISCARD_LEVEL; + mIsFetching = FALSE; mLastPacketTimer.reset(); } else { mIsRawImageValid = TRUE; - addToCreateTexture() ; + addToCreateTexture(); + } + + if (mBoostLevel == LLGLTexture::BOOST_ICON) + { + S32 expected_width = mKnownDrawWidth > 0 ? mKnownDrawWidth : DEFAULT_ICON_DIMENTIONS; + S32 expected_height = mKnownDrawHeight > 0 ? mKnownDrawHeight : DEFAULT_ICON_DIMENTIONS; + if (mRawImage && (mRawImage->getWidth() > expected_width || mRawImage->getHeight() > expected_height)) + { + // scale oversized icon, no need to give more work to gl + mRawImage->scale(expected_width, expected_height); + } } - return TRUE ; + return TRUE; } else { @@ -1739,16 +2025,33 @@ bool LLViewerFetchedTexture::updateFetch() if ((decode_priority > 0) && (mRawDiscardLevel < 0 || mRawDiscardLevel == INVALID_DISCARD_LEVEL)) { // We finished but received no data - if (current_discard < 0) + if (getDiscardLevel() < 0) { + if (getFTType() != FTT_MAP_TILE) + { + LL_WARNS() << mID + << " Fetch failure, setting as missing, decode_priority " << decode_priority + << " mRawDiscardLevel " << mRawDiscardLevel + << " current_discard " << current_discard + << LL_ENDL; + } setIsMissingAsset(); desired_discard = -1; } else { - //llwarns << mID << ": Setting min discard to " << current_discard << llendl; - mMinDiscardLevel = current_discard; - desired_discard = current_discard; + //LL_WARNS() << mID << ": Setting min discard to " << current_discard << LL_ENDL; + if(current_discard >= 0) + { + mMinDiscardLevel = current_discard; + desired_discard = current_discard; + } + else + { + S32 dis_level = getDiscardLevel(); + mMinDiscardLevel = dis_level; + desired_discard = dis_level; + } } destroyRawImage(); } @@ -1764,13 +2067,13 @@ bool LLViewerFetchedTexture::updateFetch() // // Useful debugging code for undesired deprioritization of textures. // if (decode_priority <= 0.0f && desired_discard >= 0 && desired_discard < current_discard) // { -// llinfos << "Calling updateRequestPriority() with decode_priority = 0.0f" << llendl; +// LL_INFOS() << "Calling updateRequestPriority() with decode_priority = 0.0f" << LL_ENDL; // calcDecodePriority(); // } - static const F32 MAX_HOLD_TIME = 5.0f ; //seconds to wait before canceling fecthing if decode_priority is 0.f. + static const F32 MAX_HOLD_TIME = 5.0f; //seconds to wait before canceling fecthing if decode_priority is 0.f. if(decode_priority > 0.0f || mStopFetchingTimer.getElapsedTimeF32() > MAX_HOLD_TIME) { - mStopFetchingTimer.reset() ; + mStopFetchingTimer.reset(); LLAppViewer::getTextureFetch()->updateRequestPriority(mID, decode_priority); } } @@ -1781,6 +2084,10 @@ bool LLViewerFetchedTexture::updateFetch() { make_request = false; } + else if(mDesiredDiscardLevel > getMaxDiscardLevel()) + { + make_request = false; + } else if (mNeedsCreateTexture || mIsMissingAsset) { make_request = false; @@ -1789,15 +2096,24 @@ bool LLViewerFetchedTexture::updateFetch() { make_request = false; } + else if(mCachedRawImage.notNull() // can be empty + && mCachedRawImageReady + && (current_discard < 0 || current_discard > mCachedRawDiscardLevel)) + { + make_request = false; + switchToCachedImage(); //use the cached raw data first + } //else if (!isJustBound() && mCachedRawImageReady) //{ // make_request = false; //} - if(make_request) + if (make_request) { - //load the texture progressively. - S32 delta_level = (mBoostLevel > LLGLTexture::BOOST_NONE) ? 2 : 1 ; + // Load the texture progressively: we try not to rush to the desired discard too fast. + // If the camera is not moving, we do not tweak the discard level notch by notch but go to the desired discard with larger boosted steps + // This mitigates the "textures stay blurry" problem when loading while not killing the texture memory while moving around + S32 delta_level = (mBoostLevel > LLGLTexture::BOOST_ALM) ? 2 : 1; if (current_discard < 0) { desired_discard = llmax(desired_discard, getMaxDiscardLevel() - delta_level); @@ -1837,7 +2153,7 @@ bool LLViewerFetchedTexture::updateFetch() c = mComponents; } - static const LLCachedControl override_tex_discard_level("TextureDiscardLevel"); + static LLCachedControl override_tex_discard_level(gSavedSettings, "TextureDiscardLevel"); if (override_tex_discard_level != 0) { desired_discard = override_tex_discard_level; @@ -1845,7 +2161,7 @@ bool LLViewerFetchedTexture::updateFetch() // bypass texturefetch directly by pulling from LLTextureCache bool fetch_request_created = false; - fetch_request_created = LLAppViewer::getTextureFetch()->createRequest(mUrl, getID(),getTargetHost(), decode_priority, + fetch_request_created = LLAppViewer::getTextureFetch()->createRequest(mFTType, mUrl, getID(), getTargetHost(), decode_priority, w, h, c, desired_discard, needsAux(), mCanUseHTTP); if (fetch_request_created) @@ -1862,52 +2178,92 @@ bool LLViewerFetchedTexture::updateFetch() } else if (mHasFetcher && !mIsFetching) { - // Only delete requests that haven't receeived any network data for a while + // Only delete requests that haven't received any network data + // for a while. Note - this is the normal mechanism for + // deleting requests, not just a place to handle timeouts. const F32 FETCH_IDLE_TIME = 5.f; if (mLastPacketTimer.getElapsedTimeF32() > FETCH_IDLE_TIME) { -// llinfos << "Deleting request: " << getID() << " Discard: " << current_discard << " <= min:" << mMinDiscardLevel << " or priority == 0: " << decode_priority << llendl; + LL_DEBUGS("Texture") << "exceeded idle time " << FETCH_IDLE_TIME << ", deleting request: " << getID() << LL_ENDL; LLAppViewer::getTextureFetch()->deleteRequest(getID(), true); mHasFetcher = FALSE; } } - - llassert_always(mRawImage.notNull() || (!mNeedsCreateTexture && !mIsRawImageValid)); + + llassert(mRawImage.notNull() || (!mNeedsCreateTexture && !mIsRawImageValid)); return mIsFetching ? true : false; } +void LLViewerFetchedTexture::clearFetchedResults() +{ + if(mNeedsCreateTexture || mIsFetching) + { + return; + } + + cleanup(); + destroyGLTexture(); + + if(getDiscardLevel() >= 0) //sculpty texture, force to invalidate + { + mGLTexturep->forceToInvalidateGLTexture(); + } +} + void LLViewerFetchedTexture::forceToDeleteRequest() { if (mHasFetcher) { - LLAppViewer::getTextureFetch()->deleteRequest(getID(), true); + //LLAppViewer::getTextureFetch()->deleteRequest(getID(), true); mHasFetcher = FALSE; - mIsFetching = FALSE ; - resetTextureStats(); + mIsFetching = FALSE; } + + resetTextureStats(); + + mDesiredDiscardLevel = getMaxDiscardLevel() + 1; //defer LLAppViewer::getTextureFetch()->deleteRequest to updateFetch? } -void LLViewerFetchedTexture::setIsMissingAsset() +void LLViewerFetchedTexture::setIsMissingAsset(BOOL is_missing) { - if (mUrl.empty()) + if (is_missing == mIsMissingAsset) { - llwarns << mID << ": Marking image as missing" << llendl; + return; } - else + if (is_missing) { - llwarns << mUrl << ": Marking image as missing" << llendl; + notifyAboutMissingAsset(); + + if (mUrl.empty()) + { + LL_WARNS() << mID << ": Marking image as missing" << LL_ENDL; + } + else + { + // This may or may not be an error - it is normal to have no + // map tile on an empty region, but bad if we're failing on a + // server bake texture. + if (getFTType() != FTT_MAP_TILE) + { + LL_WARNS() << mUrl << ": Marking image as missing" << LL_ENDL; + } + } + if (mHasFetcher) + { + LLAppViewer::getTextureFetch()->deleteRequest(getID(), true); + mHasFetcher = FALSE; + mIsFetching = FALSE; + mLastPacketTimer.reset(); + mFetchState = 0; + mFetchPriority = 0; + } } - if (mHasFetcher) + else { - LLAppViewer::getTextureFetch()->deleteRequest(getID(), true); - mHasFetcher = FALSE; - mIsFetching = FALSE; - mLastPacketTimer.reset(); - mFetchState = 0; - mFetchPriority = 0; + LL_INFOS() << mID << ": un-flagging missing asset" << LL_ENDL; } - mIsMissingAsset = TRUE; + mIsMissingAsset = is_missing; } void LLViewerFetchedTexture::setLoadedCallback( loaded_callback_func loaded_callback, @@ -1925,34 +2281,51 @@ void LLViewerFetchedTexture::setLoadedCallback( loaded_callback_func loaded_call } else { - mLoadedCallbackDesiredDiscardLevel = llmin(mLoadedCallbackDesiredDiscardLevel, (S8)discard_level) ; + mLoadedCallbackDesiredDiscardLevel = llmin(mLoadedCallbackDesiredDiscardLevel, (S8)discard_level); } - if(mPauseLoadedCallBacks && !pause) + if(mPauseLoadedCallBacks) + { + if(!pause) + { + unpauseLoadedCallbacks(src_callback_list); + } + } + else if(pause) { - unpauseLoadedCallbacks(src_callback_list) ; + pauseLoadedCallbacks(src_callback_list); } + LLLoadedCallbackEntry* entryp = new LLLoadedCallbackEntry(loaded_callback, discard_level, keep_imageraw, userdata, src_callback_list, this, pause); mLoadedCallbackList.push_back(entryp); mNeedsAux |= needs_aux; if(keep_imageraw) { - mSaveRawImage = TRUE ; + mSaveRawImage = TRUE; } if (mNeedsAux && mAuxRawImage.isNull() && getDiscardLevel() >= 0) { - // We need aux data, but we've already loaded the image, and it didn't have any - llwarns << "No aux data available for callback for image:" << getID() << llendl; + if(mHasAux) + { + //trigger a refetch + forceToRefetchTexture(); + } + else + { + // We need aux data, but we've already loaded the image, and it didn't have any + LL_WARNS() << "No aux data available for callback for image:" << getID() << LL_ENDL; + } } mLastCallBackActiveTime = sCurrentTime ; + mLastReferencedSavedRawImageTime = sCurrentTime; } void LLViewerFetchedTexture::clearCallbackEntryList() { if(mLoadedCallbackList.empty()) { - return ; + return; } for(callback_list_t::iterator iter = mLoadedCallbackList.begin(); @@ -1963,29 +2336,29 @@ void LLViewerFetchedTexture::clearCallbackEntryList() // We never finished loading the image. Indicate failure. // Note: this allows mLoadedCallbackUserData to be cleaned up. entryp->mCallback(FALSE, this, NULL, NULL, 0, TRUE, entryp->mUserData); - iter = mLoadedCallbackList.erase(iter) ; + iter = mLoadedCallbackList.erase(iter); delete entryp; } gTextureList.mCallbackList.erase(this); - mLoadedCallbackDesiredDiscardLevel = S8_MAX ; + mLoadedCallbackDesiredDiscardLevel = S8_MAX; if(needsToSaveRawImage()) { - destroySavedRawImage() ; + destroySavedRawImage(); } - return ; + return; } void LLViewerFetchedTexture::deleteCallbackEntry(const LLLoadedCallbackEntry::source_callback_list_t* callback_list) { if(mLoadedCallbackList.empty() || !callback_list) { - return ; + return; } - S32 desired_discard = S8_MAX ; - S32 desired_raw_discard = INVALID_DISCARD_LEVEL ; + S32 desired_discard = S8_MAX; + S32 desired_raw_discard = INVALID_DISCARD_LEVEL; for(callback_list_t::iterator iter = mLoadedCallbackList.begin(); iter != mLoadedCallbackList.end(); ) { @@ -1995,17 +2368,17 @@ void LLViewerFetchedTexture::deleteCallbackEntry(const LLLoadedCallbackEntry::so // We never finished loading the image. Indicate failure. // Note: this allows mLoadedCallbackUserData to be cleaned up. entryp->mCallback(FALSE, this, NULL, NULL, 0, TRUE, entryp->mUserData); - iter = mLoadedCallbackList.erase(iter) ; + iter = mLoadedCallbackList.erase(iter); delete entryp; } else { ++iter; - desired_discard = llmin(desired_discard, entryp->mDesiredDiscard) ; + desired_discard = llmin(desired_discard, entryp->mDesiredDiscard); if(entryp->mNeedsImageRaw) { - desired_raw_discard = llmin(desired_raw_discard, entryp->mDesiredDiscard) ; + desired_raw_discard = llmin(desired_raw_discard, entryp->mDesiredDiscard); } } } @@ -2018,18 +2391,18 @@ void LLViewerFetchedTexture::deleteCallbackEntry(const LLLoadedCallbackEntry::so if(needsToSaveRawImage()) { - destroySavedRawImage() ; + destroySavedRawImage(); } } else if(needsToSaveRawImage() && mBoostLevel != LLGLTexture::BOOST_PREVIEW) { if(desired_raw_discard != INVALID_DISCARD_LEVEL) { - mDesiredSavedRawDiscardLevel = desired_raw_discard ; + mDesiredSavedRawDiscardLevel = desired_raw_discard; } else { - destroySavedRawImage() ; + destroySavedRawImage(); } } } @@ -2038,29 +2411,30 @@ void LLViewerFetchedTexture::unpauseLoadedCallbacks(const LLLoadedCallbackEntry: { if(!callback_list) { - mPauseLoadedCallBacks = FALSE ; - return ; + mPauseLoadedCallBacks = FALSE; + return; } - BOOL need_raw = FALSE ; + BOOL need_raw = FALSE; for(callback_list_t::iterator iter = mLoadedCallbackList.begin(); iter != mLoadedCallbackList.end(); ) { LLLoadedCallbackEntry *entryp = *iter++; if(entryp->mSourceCallbackList == callback_list) { - entryp->mPaused = FALSE ; + entryp->mPaused = FALSE; if(entryp->mNeedsImageRaw) { - need_raw = TRUE ; + need_raw = TRUE; } } } mPauseLoadedCallBacks = FALSE ; mLastCallBackActiveTime = sCurrentTime ; + mForceCallbackFetch = TRUE; if(need_raw) { - mSaveRawImage = TRUE ; + mSaveRawImage = TRUE; } } @@ -2068,10 +2442,10 @@ void LLViewerFetchedTexture::pauseLoadedCallbacks(const LLLoadedCallbackEntry::s { if(!callback_list) { - return ; + return; } - bool paused = true ; + bool paused = true; for(callback_list_t::iterator iter = mLoadedCallbackList.begin(); iter != mLoadedCallbackList.end(); ) @@ -2079,25 +2453,26 @@ void LLViewerFetchedTexture::pauseLoadedCallbacks(const LLLoadedCallbackEntry::s LLLoadedCallbackEntry *entryp = *iter++; if(entryp->mSourceCallbackList == callback_list) { - entryp->mPaused = TRUE ; + entryp->mPaused = TRUE; } else if(!entryp->mPaused) { - paused = false ; + paused = false; } } if(paused) { - mPauseLoadedCallBacks = TRUE ;//when set, loaded callback is paused. + mPauseLoadedCallBacks = TRUE;//when set, loaded callback is paused. resetTextureStats(); - mSaveRawImage = FALSE ; + mSaveRawImage = FALSE; } } bool LLViewerFetchedTexture::doLoadedCallbacks() { - static const F32 MAX_INACTIVE_TIME = 120.f ; //seconds + static const F32 MAX_INACTIVE_TIME = 900.f ; //seconds + static const F32 MAX_IDLE_WAIT_TIME = 5.f ; //seconds if (mNeedsCreateTexture) { @@ -2110,6 +2485,15 @@ bool LLViewerFetchedTexture::doLoadedCallbacks() } if(sCurrentTime - mLastCallBackActiveTime > MAX_INACTIVE_TIME && !mIsFetching) { + if (mFTType == FTT_SERVER_BAKE) + { + //output some debug info + LL_INFOS() << "baked texture: " << mID << "clears all call backs due to inactivity." << LL_ENDL; + LL_INFOS() << mUrl << LL_ENDL; + LL_INFOS() << "current discard: " << getDiscardLevel() << " current discard for fetch: " << getCurrentDiscardLevelForFetching() << + " Desired discard: " << getDesiredDiscardLevel() << "decode Pri: " << getDecodePriority() << LL_ENDL; + } + clearCallbackEntryList() ; //remove all callbacks. return false ; } @@ -2118,6 +2502,13 @@ bool LLViewerFetchedTexture::doLoadedCallbacks() if (isMissingAsset()) { + if (mFTType == FTT_SERVER_BAKE) + { + //output some debug info + LL_INFOS() << "baked texture: " << mID << "is missing." << LL_ENDL; + LL_INFOS() << mUrl << LL_ENDL; + } + for(callback_list_t::iterator iter = mLoadedCallbackList.begin(); iter != mLoadedCallbackList.end(); ) { @@ -2131,7 +2522,7 @@ bool LLViewerFetchedTexture::doLoadedCallbacks() // Remove ourself from the global list of textures with callbacks gTextureList.mCallbackList.erase(this); - return false ; + return false; } S32 gl_discard = getDiscardLevel(); @@ -2238,7 +2629,7 @@ bool LLViewerFetchedTexture::doLoadedCallbacks() if (run_raw_callbacks && mIsRawImageValid && (mRawDiscardLevel <= getMaxDiscardLevel())) { // Do callbacks which require raw image data. - //llinfos << "doLoadedCallbacks raw for " << getID() << llendl; + //LL_INFOS() << "doLoadedCallbacks raw for " << getID() << LL_ENDL; // Call each party interested in the raw data. for(callback_list_t::iterator iter = mLoadedCallbackList.begin(); @@ -2252,15 +2643,15 @@ bool LLViewerFetchedTexture::doLoadedCallbacks() // to satisfy the interested party, then this is the last time that // we're going to call them. - mLastCallBackActiveTime = sCurrentTime ; + mLastCallBackActiveTime = sCurrentTime; //llassert_always(mRawImage.notNull()); if(mNeedsAux && mAuxRawImage.isNull()) { - llwarns << "Raw Image with no Aux Data for callback" << llendl; + LL_WARNS() << "Raw Image with no Aux Data for callback" << LL_ENDL; } BOOL final = mRawDiscardLevel <= entryp->mDesiredDiscard ? TRUE : FALSE; - //llinfos << "Running callback for " << getID() << llendl; - //llinfos << mRawImage->getWidth() << "x" << mRawImage->getHeight() << llendl; + //LL_INFOS() << "Running callback for " << getID() << LL_ENDL; + //LL_INFOS() << mRawImage->getWidth() << "x" << mRawImage->getHeight() << LL_ENDL; entryp->mLastUsedDiscard = mRawDiscardLevel; entryp->mCallback(TRUE, this, mRawImage, mAuxRawImage, mRawDiscardLevel, final, entryp->mUserData); if (final) @@ -2278,7 +2669,7 @@ bool LLViewerFetchedTexture::doLoadedCallbacks() // if (run_gl_callbacks && (gl_discard <= getMaxDiscardLevel())) { - //llinfos << "doLoadedCallbacks GL for " << getID() << llendl; + //LL_INFOS() << "doLoadedCallbacks GL for " << getID() << LL_ENDL; // Call the callbacks interested in GL data. for(callback_list_t::iterator iter = mLoadedCallbackList.begin(); @@ -2288,7 +2679,7 @@ bool LLViewerFetchedTexture::doLoadedCallbacks() LLLoadedCallbackEntry *entryp = *curiter; if (!entryp->mNeedsImageRaw && (entryp->mLastUsedDiscard > gl_discard)) { - mLastCallBackActiveTime = sCurrentTime ; + mLastCallBackActiveTime = sCurrentTime; BOOL final = gl_discard <= entryp->mDesiredDiscard ? TRUE : FALSE; entryp->mLastUsedDiscard = gl_discard; entryp->mCallback(TRUE, this, NULL, NULL, gl_discard, final, entryp->mUserData); @@ -2302,6 +2693,9 @@ bool LLViewerFetchedTexture::doLoadedCallbacks() } } + // Done with any raw image data at this point (will be re-created if we still have callbacks) + destroyRawImage(); + // // If we have no callbacks, take us off of the image callback list. // @@ -2309,10 +2703,12 @@ bool LLViewerFetchedTexture::doLoadedCallbacks() { gTextureList.mCallbackList.erase(this); } - - // Done with any raw image data at this point (will be re-created if we still have callbacks) - destroyRawImage(); - + else if(!res && mForceCallbackFetch && sCurrentTime - mLastCallBackActiveTime > MAX_IDLE_WAIT_TIME && !mIsFetching) + { + //wait for long enough but no fetching request issued, force one. + forceToRefetchTexture(mLoadedCallbackDesiredDiscardLevel, 5.f); + mForceCallbackFetch = FALSE; //fire once. + } return res; } @@ -2322,66 +2718,66 @@ void LLViewerFetchedTexture::forceImmediateUpdate() //only immediately update a deleted texture which is now being re-used. if(!isDeleted()) { - return ; + return; } //if already called forceImmediateUpdate() if(mInImageList && mDecodePriority == LLViewerFetchedTexture::maxDecodePriority()) { - return ; + return; } - gTextureList.forceImmediateUpdate(this) ; - return ; + gTextureList.forceImmediateUpdate(this); + return; } LLImageRaw* LLViewerFetchedTexture::reloadRawImage(S8 discard_level) { - llassert_always(mGLTexturep.notNull()) ; + llassert_always(mGLTexturep.notNull()); llassert_always(discard_level >= 0); llassert_always(mComponents > 0); if (mRawImage.notNull()) { //mRawImage is in use by somebody else, do not delete it. - return NULL ; + return NULL; } if(mSavedRawDiscardLevel >= 0 && mSavedRawDiscardLevel <= discard_level) { - if(mSavedRawDiscardLevel != discard_level) + if (mSavedRawDiscardLevel != discard_level && mBoostLevel != BOOST_ICON) { - mRawImage = new LLImageRaw(getWidth(discard_level), getHeight(discard_level), getComponents()) ; - mRawImage->copy(getSavedRawImage()) ; + mRawImage = new LLImageRaw(getWidth(discard_level), getHeight(discard_level), getComponents()); + mRawImage->copy(getSavedRawImage()); } else { - mRawImage = getSavedRawImage() ; + mRawImage = getSavedRawImage(); } - mRawDiscardLevel = discard_level ; + mRawDiscardLevel = discard_level; } else { //force to fetch raw image again if cached raw image is not good enough. if(mCachedRawDiscardLevel > discard_level) { - mRawImage = mCachedRawImage ; + mRawImage = mCachedRawImage; mRawDiscardLevel = mCachedRawDiscardLevel; } else //cached raw image is good enough, copy it. { if(mCachedRawDiscardLevel != discard_level) { - mRawImage = new LLImageRaw(getWidth(discard_level), getHeight(discard_level), getComponents()) ; - mRawImage->copy(mCachedRawImage) ; + mRawImage = new LLImageRaw(getWidth(discard_level), getHeight(discard_level), getComponents()); + mRawImage->copy(mCachedRawImage); } else { - mRawImage = mCachedRawImage ; + mRawImage = mCachedRawImage; } - mRawDiscardLevel = discard_level ; + mRawDiscardLevel = discard_level; } } - mIsRawImageValid = TRUE ; + mIsRawImageValid = TRUE; sRawCount++; return mRawImage; @@ -2389,12 +2785,12 @@ LLImageRaw* LLViewerFetchedTexture::reloadRawImage(S8 discard_level) bool LLViewerFetchedTexture::needsToSaveRawImage() { - return mForceToSaveRawImage || mSaveRawImage ; + return mForceToSaveRawImage || mSaveRawImage; } void LLViewerFetchedTexture::destroyRawImage() { - if (mAuxRawImage.notNull()) + if (mAuxRawImage.notNull() && !needsToSaveRawImage()) { sAuxCount--; mAuxRawImage = NULL; @@ -2408,9 +2804,9 @@ void LLViewerFetchedTexture::destroyRawImage() { if(needsToSaveRawImage()) { - saveRawImage() ; + saveRawImage(); } - setCachedRawImage() ; + setCachedRawImage(); } mRawImage = NULL; @@ -2426,19 +2822,19 @@ void LLViewerFetchedTexture::switchToCachedImage() { if(mCachedRawImage.notNull()) { - mRawImage = mCachedRawImage ; + mRawImage = mCachedRawImage; if (getComponents() != mRawImage->getComponents()) { // We've changed the number of components, so we need to move any // objects using this pool to a different pool. mComponents = mRawImage->getComponents(); - mGLTexturep->setComponents(mComponents) ; + mGLTexturep->setComponents(mComponents); gTextureList.dirtyImage(this); } mIsRawImageValid = TRUE; - mRawDiscardLevel = mCachedRawDiscardLevel ; + mRawDiscardLevel = mCachedRawDiscardLevel; gTextureList.mCreateTextureList.insert(this); mNeedsCreateTexture = TRUE; } @@ -2452,11 +2848,28 @@ void LLViewerFetchedTexture::setCachedRawImage(S32 discard_level, LLImageRaw* im { if(mCachedRawImage.notNull()) mCachedRawImage->setInCache(false); - mCachedRawImage = imageraw ; + if (mBoostLevel == LLGLTexture::BOOST_ICON) + { + S32 expected_width = mKnownDrawWidth > 0 ? mKnownDrawWidth : DEFAULT_ICON_DIMENTIONS; + S32 expected_height = mKnownDrawHeight > 0 ? mKnownDrawHeight : DEFAULT_ICON_DIMENTIONS; + if (mRawImage->getWidth() > expected_width || mRawImage->getHeight() > expected_height) + { + mCachedRawImage = new LLImageRaw(expected_width, expected_height, imageraw->getComponents()); + mCachedRawImage->copyScaled(imageraw); + } + else + { + mCachedRawImage = imageraw; + } + } + else + { + mCachedRawImage = imageraw; + } if(mCachedRawImage.notNull()) mCachedRawImage->setInCache(true); - mCachedRawDiscardLevel = discard_level ; - mCachedRawImageReady = TRUE ; + mCachedRawDiscardLevel = discard_level; + mCachedRawImageReady = TRUE; } } @@ -2464,65 +2877,69 @@ void LLViewerFetchedTexture::setCachedRawImage() { if(mRawImage == mCachedRawImage) { - return ; + return; } if(!mIsRawImageValid) { - return ; + return; } if(mCachedRawImageReady) { - return ; + return; } if(mCachedRawDiscardLevel < 0 || mCachedRawDiscardLevel > mRawDiscardLevel) { - S32 i = 0 ; - S32 w = mRawImage->getWidth() ; - S32 h = mRawImage->getHeight() ; + S32 i = 0; + S32 w = mRawImage->getWidth(); + S32 h = mRawImage->getHeight(); - S32 max_size = MAX_CACHED_RAW_IMAGE_AREA ; + S32 max_size = MAX_CACHED_RAW_IMAGE_AREA; if(LLGLTexture::BOOST_TERRAIN == mBoostLevel) { - max_size = MAX_CACHED_RAW_TERRAIN_IMAGE_AREA ; + max_size = MAX_CACHED_RAW_TERRAIN_IMAGE_AREA; } if(mForSculpt) { - max_size = MAX_CACHED_RAW_SCULPT_IMAGE_AREA ; - mCachedRawImageReady = !mRawDiscardLevel ; + max_size = MAX_CACHED_RAW_SCULPT_IMAGE_AREA; + mCachedRawImageReady = !mRawDiscardLevel; } else { - mCachedRawImageReady = (!mRawDiscardLevel || ((w * h) >= max_size)) ; + mCachedRawImageReady = (!mRawDiscardLevel || ((w * h) >= max_size)); } while(((w >> i) * (h >> i)) > max_size) { - ++i ; + ++i; } if(i) { if(!(w >> i) || !(h >> i)) { - --i ; + --i; } if (mRawImage->getComponents() == 5) { - llwarns << "IMP-582: Trying to scale an image (" << mID << ") with 5 components!" << llendl; + LL_WARNS() << "IMP-582: Trying to scale an image (" << mID << ") with 5 components!" << LL_ENDL; mIsRawImageValid = 0; return; } - mRawImage->scale(w >> i, h >> i) ; + { + //make a duplicate in case somebody else is using this raw image + mRawImage = mRawImage->duplicate(); + mRawImage->scale(w >> i, h >> i); + } } if(mCachedRawImage.notNull()) mCachedRawImage->setInCache(false); - mCachedRawImage = mRawImage ; + mCachedRawImage = mRawImage; if(mCachedRawImage.notNull()) mCachedRawImage->setInCache(true); - mRawDiscardLevel += i ; - mCachedRawDiscardLevel = mRawDiscardLevel ; + mRawDiscardLevel += i; + mCachedRawDiscardLevel = mRawDiscardLevel; } } @@ -2532,11 +2949,11 @@ void LLViewerFetchedTexture::checkCachedRawSculptImage() { if(getDiscardLevel() != 0) { - mCachedRawImageReady = FALSE ; + mCachedRawImageReady = FALSE; } else if(isForSculptOnly()) { - resetTextureStats() ; //do not update this image any more. + resetTextureStats(); //do not update this image any more. } } } @@ -2545,52 +2962,87 @@ void LLViewerFetchedTexture::saveRawImage() { if(mRawImage.isNull() || mRawImage == mSavedRawImage || (mSavedRawDiscardLevel >= 0 && mSavedRawDiscardLevel <= mRawDiscardLevel)) { - return ; + return; } // This shouldn't happen, but it did on Snowglobe 1.5. Better safe than sorry? if (!mRawImage->getData()) { - llwarns << "mRawImage->getData() returns NULL" << llendl; + LL_WARNS() << "mRawImage->getData() returns NULL" << LL_ENDL; return; } - mSavedRawDiscardLevel = mRawDiscardLevel ; - mSavedRawImage = new LLImageRaw(mRawImage->getData(), mRawImage->getWidth(), mRawImage->getHeight(), mRawImage->getComponents()) ; + mSavedRawDiscardLevel = mRawDiscardLevel; + if (mBoostLevel == LLGLTexture::BOOST_ICON) + { + S32 expected_width = mKnownDrawWidth > 0 ? mKnownDrawWidth : DEFAULT_ICON_DIMENTIONS; + S32 expected_height = mKnownDrawHeight > 0 ? mKnownDrawHeight : DEFAULT_ICON_DIMENTIONS; + if (mRawImage->getWidth() > expected_width || mRawImage->getHeight() > expected_height) + { + mSavedRawImage = new LLImageRaw(expected_width, expected_height, mRawImage->getComponents()); + mSavedRawImage->copyScaled(mRawImage); + } + else + { + mSavedRawImage = new LLImageRaw(mRawImage->getData(), mRawImage->getWidth(), mRawImage->getHeight(), mRawImage->getComponents()); + } + } + else + { + mSavedRawImage = new LLImageRaw(mRawImage->getData(), mRawImage->getWidth(), mRawImage->getHeight(), mRawImage->getComponents()); + } if(mForceToSaveRawImage && mSavedRawDiscardLevel <= mDesiredSavedRawDiscardLevel) { - mForceToSaveRawImage = FALSE ; + mForceToSaveRawImage = FALSE; + } + + mLastReferencedSavedRawImageTime = sCurrentTime; +} + +//force to refetch the texture to the discard level +void LLViewerFetchedTexture::forceToRefetchTexture(S32 desired_discard, F32 kept_time) +{ + if(mForceToSaveRawImage) + { + desired_discard = llmin(desired_discard, mDesiredSavedRawDiscardLevel); + kept_time = llmax(kept_time, mKeptSavedRawImageTime); } + //trigger a new fetch. + mForceToSaveRawImage = TRUE ; + mDesiredSavedRawDiscardLevel = desired_discard ; + mKeptSavedRawImageTime = kept_time ; mLastReferencedSavedRawImageTime = sCurrentTime ; + mSavedRawImage = NULL ; + mSavedRawDiscardLevel = -1 ; } void LLViewerFetchedTexture::forceToSaveRawImage(S32 desired_discard, F32 kept_time) { - mKeptSavedRawImageTime = kept_time ; - mLastReferencedSavedRawImageTime = sCurrentTime ; + mKeptSavedRawImageTime = kept_time; + mLastReferencedSavedRawImageTime = sCurrentTime; if(mSavedRawDiscardLevel > -1 && mSavedRawDiscardLevel <= desired_discard) { - return ; //raw imge is ready. + return; //raw imge is ready. } if(!mForceToSaveRawImage || mDesiredSavedRawDiscardLevel < 0 || mDesiredSavedRawDiscardLevel > desired_discard) { - mForceToSaveRawImage = TRUE ; - mDesiredSavedRawDiscardLevel = desired_discard ; + mForceToSaveRawImage = TRUE; + mDesiredSavedRawDiscardLevel = desired_discard; //copy from the cached raw image if exists. if(mCachedRawImage.notNull() && mRawImage.isNull() ) { - mRawImage = mCachedRawImage ; - mRawDiscardLevel = mCachedRawDiscardLevel ; + mRawImage = mCachedRawImage; + mRawDiscardLevel = mCachedRawDiscardLevel; - saveRawImage() ; + saveRawImage(); - mRawImage = NULL ; - mRawDiscardLevel = INVALID_DISCARD_LEVEL ; + mRawImage = NULL; + mRawDiscardLevel = INVALID_DISCARD_LEVEL; } } } @@ -2598,13 +3050,13 @@ void LLViewerFetchedTexture::destroySavedRawImage() { if(mLastReferencedSavedRawImageTime < mKeptSavedRawImageTime) { - return ; //keep the saved raw image. + return; //keep the saved raw image. } - mForceToSaveRawImage = FALSE ; - mSaveRawImage = FALSE ; + mForceToSaveRawImage = FALSE; + mSaveRawImage = FALSE; - clearCallbackEntryList() ; + clearCallbackEntryList(); mSavedRawImage = NULL ; mForceToSaveRawImage = FALSE ; @@ -2613,208 +3065,53 @@ void LLViewerFetchedTexture::destroySavedRawImage() mDesiredSavedRawDiscardLevel = -1 ; mLastReferencedSavedRawImageTime = 0.0f ; mKeptSavedRawImageTime = 0.f ; + + if(mAuxRawImage.notNull()) + { + sAuxCount--; + mAuxRawImage = NULL; + } } LLImageRaw* LLViewerFetchedTexture::getSavedRawImage() { - mLastReferencedSavedRawImageTime = sCurrentTime ; + mLastReferencedSavedRawImageTime = sCurrentTime; - return mSavedRawImage ; + return mSavedRawImage; } BOOL LLViewerFetchedTexture::hasSavedRawImage() const { - return mSavedRawImage.notNull() ; + return mSavedRawImage.notNull(); } F32 LLViewerFetchedTexture::getElapsedLastReferencedSavedRawImageTime() const { - return sCurrentTime - mLastReferencedSavedRawImageTime ; + return sCurrentTime - mLastReferencedSavedRawImageTime; } -//---------------------------------------------------------------------------------------------- -//atlasing -//---------------------------------------------------------------------------------------------- -/*void LLViewerFetchedTexture::resetFaceAtlas() + +LLUUID LLViewerFetchedTexture::getUploader() { - //Nothing should be done here. + return (mComment.find('a') != mComment.end()) ? LLUUID(mComment['a']) : LLUUID::null; } -//invalidate all atlas slots for this image. -void LLViewerFetchedTexture::invalidateAtlas(BOOL rebuild_geom) +LLDate LLViewerFetchedTexture::getUploadTime() { - for(U32 i = 0 ; i < mNumFaces ; i++) + if (mComment.find('z') != mComment.end()) { - LLFace* facep = mFaceList[i] ; - facep->removeAtlas() ; - if(rebuild_geom && facep->getDrawable() && facep->getDrawable()->getSpatialGroup()) - { - facep->getDrawable()->getSpatialGroup()->setState(LLSpatialGroup::GEOM_DIRTY); - } + struct tm t = {}; + sscanf(mComment['z'].c_str(), "%4d%2d%2d%2d%2d%2d", + &t.tm_year, &t.tm_mon, &t.tm_mday, &t.tm_hour, &t.tm_min, &t.tm_sec); + std::string iso_date = llformat("%d-%d-%dT%d:%d:%dZ", t.tm_year, t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec); + return LLDate(iso_date); } + return LLDate(); } -BOOL LLViewerFetchedTexture::insertToAtlas() +std::string LLViewerFetchedTexture::getComment() { - if(!LLViewerTexture::sUseTextureAtlas) - { - return FALSE ; - } - if(getNumFaces() < 1) - { - return FALSE ; - } - if(mGLTexturep->getDiscardLevelInAtlas() > 0 && mRawDiscardLevel >= mGLTexturep->getDiscardLevelInAtlas()) - { - return FALSE ; - } - if(!LLTextureAtlasManager::getInstance()->canAddToAtlas(mRawImage->getWidth(), mRawImage->getHeight(), mRawImage->getComponents(), mGLTexturep->getTexTarget())) - { - return FALSE ; - } - - BOOL ret = TRUE ;//if ret is set to false, will generate a gl texture for this image. - S32 raw_w = mRawImage->getWidth() ; - S32 raw_h = mRawImage->getHeight() ; - F32 xscale = 1.0f, yscale = 1.0f ; - LLPointer slot_infop; - LLTextureAtlasSlot* cur_slotp ;//no need to be smart pointer. - LLSpatialGroup* groupp ; - LLFace* facep; - - //if the atlas slot pointers for some faces are null, process them later. - ll_face_list_t waiting_list ; - for(U32 i = 0 ; i < mNumFaces ; i++) - { - { - facep = mFaceList[i] ; - - //face can not use atlas. - if(!facep->canUseAtlas()) - { - if(facep->getAtlasInfo()) - { - facep->removeAtlas() ; - } - ret = FALSE ; - continue ; - } - - //the atlas slot is updated - slot_infop = facep->getAtlasInfo() ; - groupp = facep->getDrawable()->getSpatialGroup() ; - - if(slot_infop) - { - if(slot_infop->getSpatialGroup() != groupp) - { - if((cur_slotp = groupp->getCurUpdatingSlot(this))) //switch slot - { - facep->setAtlasInfo(cur_slotp) ; - facep->setAtlasInUse(TRUE) ; - continue ; - } - else //do not forget to update slot_infop->getSpatialGroup(). - { - LLSpatialGroup* gp = slot_infop->getSpatialGroup() ; - gp->setCurUpdatingTime(gFrameCount) ; - gp->setCurUpdatingTexture(this) ; - gp->setCurUpdatingSlot(slot_infop) ; - } - } - else //same group - { - if(gFrameCount && slot_infop->getUpdatedTime() == gFrameCount)//slot is just updated - { - facep->setAtlasInUse(TRUE) ; - continue ; - } - } - } - else - { - //if the slot is null, wait to process them later. - waiting_list.push_back(facep) ; - continue ; - } - - //---------- - //insert to atlas - if(!slot_infop->getAtlas()->insertSubTexture(mGLTexturep, mRawDiscardLevel, mRawImage, slot_infop->getSlotCol(), slot_infop->getSlotRow())) - { - - //the texture does not qualify to add to atlas, do not bother to try for other faces. - //invalidateAtlas(); - return FALSE ; - } - - //update texture scale - slot_infop->getAtlas()->getTexCoordScale(raw_w, raw_h, xscale, yscale) ; - slot_infop->setTexCoordScale(xscale, yscale) ; - slot_infop->setValid() ; - slot_infop->setUpdatedTime(gFrameCount) ; - - //update spatial group atlas info - groupp->setCurUpdatingTime(gFrameCount) ; - groupp->setCurUpdatingTexture(this) ; - groupp->setCurUpdatingSlot(slot_infop) ; - - //make the face to switch to the atlas. - facep->setAtlasInUse(TRUE) ; - } - } - - //process the waiting_list - for(ll_face_list_t::iterator iter = waiting_list.begin(); iter != waiting_list.end(); ++iter) - { - facep = (LLFace*)*iter ; - groupp = facep->getDrawable()->getSpatialGroup() ; - - //check if this texture already inserted to atlas for this group - if((cur_slotp = groupp->getCurUpdatingSlot(this))) - { - facep->setAtlasInfo(cur_slotp) ; - facep->setAtlasInUse(TRUE) ; - continue ; - } - - //need to reserve a slot from atlas - slot_infop = LLTextureAtlasManager::getInstance()->reserveAtlasSlot(llmax(mFullWidth, mFullHeight), getComponents(), groupp, this) ; - - facep->setAtlasInfo(slot_infop) ; - - groupp->setCurUpdatingTime(gFrameCount) ; - groupp->setCurUpdatingTexture(this) ; - groupp->setCurUpdatingSlot(slot_infop) ; - - //slot allocation failed. - if(!slot_infop || !slot_infop->getAtlas()) - { - ret = FALSE ; - facep->setAtlasInUse(FALSE) ; - continue ; - } - - //insert to atlas - if(!slot_infop->getAtlas()->insertSubTexture(mGLTexturep, mRawDiscardLevel, mRawImage, slot_infop->getSlotCol(), slot_infop->getSlotRow())) - { - //the texture does not qualify to add to atlas, do not bother to try for other faces. - ret = FALSE ; - //invalidateAtlas(); - break ; - } - - //update texture scale - slot_infop->getAtlas()->getTexCoordScale(raw_w, raw_h, xscale, yscale) ; - slot_infop->setTexCoordScale(xscale, yscale) ; - slot_infop->setValid() ; - slot_infop->setUpdatedTime(gFrameCount) ; - - //make the face to switch to the atlas. - facep->setAtlasInUse(TRUE) ; - } - - return ret ; -}*/ + return (mComment.find('K') != mComment.end()) ? mComment['K'] : LLStringUtil::null; +} //---------------------------------------------------------------------------------------------- //end of LLViewerFetchedTexture @@ -2823,16 +3120,16 @@ BOOL LLViewerFetchedTexture::insertToAtlas() //---------------------------------------------------------------------------------------------- //start of LLViewerLODTexture //---------------------------------------------------------------------------------------------- -LLViewerLODTexture::LLViewerLODTexture(const LLUUID& id, const LLHost& host, BOOL usemipmaps) - : LLViewerFetchedTexture(id, host, usemipmaps) +LLViewerLODTexture::LLViewerLODTexture(const LLUUID& id, FTType f_type, const LLHost& host, BOOL usemipmaps) + : LLViewerFetchedTexture(id, f_type, host, usemipmaps) { - init(TRUE) ; + init(TRUE); } -LLViewerLODTexture::LLViewerLODTexture(const std::string& url, const LLUUID& id, BOOL usemipmaps) - : LLViewerFetchedTexture(url, id, usemipmaps) +LLViewerLODTexture::LLViewerLODTexture(const std::string& url, FTType f_type, const LLUUID& id, BOOL usemipmaps) + : LLViewerFetchedTexture(url, f_type, id, usemipmaps) { - init(TRUE) ; + init(TRUE); } void LLViewerLODTexture::init(bool firstinit) @@ -2845,21 +3142,21 @@ void LLViewerLODTexture::init(bool firstinit) //virtual S8 LLViewerLODTexture::getType() const { - return LLViewerTexture::LOD_TEXTURE ; + return LLViewerTexture::LOD_TEXTURE; } BOOL LLViewerLODTexture::isUpdateFrozen() { - return LLViewerTexture::sFreezeImageScalingDown && !getDiscardLevel() ; + return LLViewerTexture::sFreezeImageScalingDown && !getDiscardLevel(); } // This is gauranteed to get called periodically for every texture //virtual void LLViewerLODTexture::processTextureStats() { - updateVirtualSize() ; + updateVirtualSize(); - static LLCachedControl textures_fullres(gSavedSettings,"TextureLoadFullRes"); + static LLCachedControl textures_fullres(gSavedSettings,"TextureLoadFullRes", false); if (textures_fullres) { @@ -2872,6 +3169,10 @@ void LLViewerLODTexture::processTextureStats() if (mFullWidth > MAX_IMAGE_SIZE_DEFAULT || mFullHeight > MAX_IMAGE_SIZE_DEFAULT) mDesiredDiscardLevel = 1; // MAX_IMAGE_SIZE_DEFAULT = 1024 and max size ever is 2048 } + else if (!LLPipeline::sRenderDeferred && mBoostLevel == LLGLTexture::BOOST_ALM) + { + mDesiredDiscardLevel = MAX_DISCARD_LEVEL + 1; + } else if (mBoostLevel < LLGLTexture::BOOST_HIGH && mMaxVirtualSize <= 10.f) { // If the image has not been significantly visible in a while, we don't want it @@ -2879,7 +3180,7 @@ void LLViewerLODTexture::processTextureStats() } else if (!mFullWidth || !mFullHeight) { - mDesiredDiscardLevel = getMaxDiscardLevel() ; + mDesiredDiscardLevel = getMaxDiscardLevel(); } else { @@ -2894,6 +3195,7 @@ void LLViewerLODTexture::processTextureStats() if (mKnownDrawWidth && mKnownDrawHeight) { S32 draw_texels = mKnownDrawWidth * mKnownDrawHeight; + draw_texels = llclamp(draw_texels, MIN_IMAGE_AREA, MAX_IMAGE_AREA); // Use log_4 because we're in square-pixel space, so an image // with twice the width and twice the height will have mTexelsPerImage @@ -2905,7 +3207,7 @@ void LLViewerLODTexture::processTextureStats() if(isLargeImage() && !isJustBound() && mAdditionalDecodePriority < 0.3f) { //if is a big image and not being used recently, nor close to the view point, do not load hi-res data. - mMaxVirtualSize = llmin(mMaxVirtualSize, (F32)LLViewerTexture::sMinLargeImageSize) ; + mMaxVirtualSize = llmin(mMaxVirtualSize, (F32)LLViewerTexture::sMinLargeImageSize); } if ((mCalculatedDiscardLevel >= 0.f) && @@ -2926,13 +3228,18 @@ void LLViewerLODTexture::processTextureStats() { discard_level += sDesiredDiscardBias; discard_level *= sDesiredDiscardScale; // scale - discard_level += sCameraMovingDiscardBias ; + discard_level += sCameraMovingDiscardBias; } discard_level = floorf(discard_level); F32 min_discard = 0.f; - if (mFullWidth > MAX_IMAGE_SIZE_DEFAULT || mFullHeight > MAX_IMAGE_SIZE_DEFAULT) - min_discard = 1.f; // MAX_IMAGE_SIZE_DEFAULT = 1024 and max size ever is 2048 + U32 desired_size = MAX_IMAGE_SIZE_DEFAULT; // MAX_IMAGE_SIZE_DEFAULT = 1024 and max size ever is 2048 + if (mBoostLevel <= LLGLTexture::BOOST_SCULPTED) + { + desired_size = DESIRED_NORMAL_TEXTURE_SIZE; + } + if ((U32)mFullWidth > desired_size || (U32)mFullHeight > desired_size) + min_discard = 1.f; discard_level = llclamp(discard_level, min_discard, (F32)MAX_DISCARD_LEVEL); @@ -2954,32 +3261,32 @@ void LLViewerLODTexture::processTextureStats() if(desired_discard_bias_max <= sDesiredDiscardBias && !mForceToSaveRawImage) { //needs to release texture memory urgently - scaleDown() ; + scaleDown(); } // Limit the amount of GL memory bound each frame - else if ( BYTES_TO_MEGA_BYTES(sBoundTextureMemoryInBytes) > sMaxBoundTextureMemInMegaBytes * texmem_middle_bound_scale && + else if ( sBoundTextureMemory > sMaxBoundTextureMemory * texmem_middle_bound_scale && (!getBoundRecently() || mDesiredDiscardLevel >= mCachedRawDiscardLevel)) { - scaleDown() ; + scaleDown(); } // Only allow GL to have 2x the video card memory - else if ( BYTES_TO_MEGA_BYTES(sTotalTextureMemoryInBytes) > sMaxTotalTextureMemInMegaBytes*texmem_middle_bound_scale && + else if ( sTotalTextureMemory > sMaxTotalTextureMem * texmem_middle_bound_scale && (!getBoundRecently() || mDesiredDiscardLevel >= mCachedRawDiscardLevel)) { - scaleDown() ; + scaleDown(); } } } if(mForceToSaveRawImage && mDesiredSavedRawDiscardLevel >= 0) { - mDesiredDiscardLevel = llmin(mDesiredDiscardLevel, (S8)mDesiredSavedRawDiscardLevel) ; + mDesiredDiscardLevel = llmin(mDesiredDiscardLevel, (S8)mDesiredSavedRawDiscardLevel); } else if(LLPipeline::sMemAllocationThrottled)//release memory of large textures by decrease their resolutions. { if(scaleDown()) { - mDesiredDiscardLevel = mCachedRawDiscardLevel ; + mDesiredDiscardLevel = mCachedRawDiscardLevel; } } } @@ -2988,18 +3295,18 @@ bool LLViewerLODTexture::scaleDown() { if(hasGLTexture() && mCachedRawDiscardLevel > getDiscardLevel()) { - switchToCachedImage() ; + switchToCachedImage(); #if 0 LLTexturePipelineTester* tester = (LLTexturePipelineTester*)LLMetricPerformanceTesterBasic::getTester(sTesterName); if (tester) { - tester->setStablizingTime() ; + tester->setStablizingTime(); } #endif - return true ; + return true; } - return false ; + return false; } //---------------------------------------------------------------------------------------------- //end of LLViewerLODTexture @@ -3011,14 +3318,14 @@ bool LLViewerLODTexture::scaleDown() //static void LLViewerMediaTexture::updateClass() { - static const F32 MAX_INACTIVE_TIME = 30.f ; + static const F32 MAX_INACTIVE_TIME = 30.f; #if 0 //force to play media. - gSavedSettings.setBOOL("AudioStreamingMedia", true) ; + gSavedSettings.setBOOL("AudioStreamingMedia", true); #endif - for(media_map_t::iterator iter = sMediaMap.begin() ; iter != sMediaMap.end(); ) + for(media_map_t::iterator iter = sMediaMap.begin(); iter != sMediaMap.end(); ) { LLViewerMediaTexture* mediap = iter->second; @@ -3029,29 +3336,29 @@ void LLViewerMediaTexture::updateClass() // if(mediap->getLastReferencedTimer()->getElapsedTimeF32() > MAX_INACTIVE_TIME) { - media_map_t::iterator cur = iter++ ; - sMediaMap.erase(cur) ; - continue ; + media_map_t::iterator cur = iter++; + sMediaMap.erase(cur); + continue; } } - ++iter ; + ++iter; } } //static void LLViewerMediaTexture::removeMediaImplFromTexture(const LLUUID& media_id) { - LLViewerMediaTexture* media_tex = findMediaTexture(media_id) ; + LLViewerMediaTexture* media_tex = findMediaTexture(media_id); if(media_tex) { - media_tex->invalidateMediaImpl() ; + media_tex->invalidateMediaImpl(); } } //static void LLViewerMediaTexture::cleanUpClass() { - sMediaMap.clear() ; + sMediaMap.clear(); } //static @@ -3063,9 +3370,9 @@ LLViewerMediaTexture* LLViewerMediaTexture::findMediaTexture(const LLUUID& media return NULL; } - LLViewerMediaTexture* media_tex = iter->second ; - media_tex->setMediaImpl() ; - media_tex->getLastReferencedTimer()->reset() ; + LLViewerMediaTexture* media_tex = iter->second; + media_tex->setMediaImpl(); + media_tex->getLastReferencedTimer()->reset(); return media_tex; } @@ -3077,48 +3384,48 @@ LLViewerMediaTexture::LLViewerMediaTexture(const LLUUID& id, BOOL usemipmaps, LL { sMediaMap.insert(std::make_pair(id, this)); - mGLTexturep = gl_image ; + mGLTexturep = gl_image; if(mGLTexturep.isNull()) { - generateGLTexture() ; + generateGLTexture(); } mGLTexturep->setAllowCompression(false); - mGLTexturep->setNeedsAlphaAndPickMask(FALSE) ; + mGLTexturep->setNeedsAlphaAndPickMask(FALSE); - mIsPlaying = FALSE ; + mIsPlaying = FALSE; - setMediaImpl() ; + setMediaImpl(); - setCategory(LLGLTexture::MEDIA) ; + setCategory(LLGLTexture::MEDIA); - LLViewerTexture* tex = gTextureList.findImage(mID) ; + LLViewerTexture* tex = gTextureList.findImage(mID, TEX_LIST_STANDARD); if(tex) //this media is a parcel media for tex. { - tex->setParcelMedia(this) ; + tex->setParcelMedia(this); } } //virtual LLViewerMediaTexture::~LLViewerMediaTexture() { - LLViewerTexture* tex = gTextureList.findImage(mID) ; + LLViewerTexture* tex = gTextureList.findImage(mID, TEX_LIST_STANDARD); if(tex) //this media is a parcel media for tex. { - tex->setParcelMedia(NULL) ; + tex->setParcelMedia(NULL); } } void LLViewerMediaTexture::reinit(BOOL usemipmaps /* = TRUE */) { - llassert(mGLTexturep.notNull()) ; + llassert(mGLTexturep.notNull()); - mUseMipMaps = usemipmaps ; - getLastReferencedTimer()->reset() ; - mGLTexturep->setUseMipMaps(mUseMipMaps) ; - mGLTexturep->setNeedsAlphaAndPickMask(FALSE) ; + mUseMipMaps = usemipmaps; + getLastReferencedTimer()->reset(); + mGLTexturep->setUseMipMaps(mUseMipMaps); + mGLTexturep->setNeedsAlphaAndPickMask(FALSE); } void LLViewerMediaTexture::setUseMipMaps(BOOL mipmap) @@ -3127,26 +3434,26 @@ void LLViewerMediaTexture::setUseMipMaps(BOOL mipmap) if(mGLTexturep.notNull()) { - mGLTexturep->setUseMipMaps(mipmap) ; + mGLTexturep->setUseMipMaps(mipmap); } } //virtual S8 LLViewerMediaTexture::getType() const { - return LLViewerTexture::MEDIA_TEXTURE ; + return LLViewerTexture::MEDIA_TEXTURE; } void LLViewerMediaTexture::invalidateMediaImpl() { - mMediaImplp = NULL ; + mMediaImplp = NULL; } void LLViewerMediaTexture::setMediaImpl() { if(!mMediaImplp) { - mMediaImplp = LLViewerMedia::getMediaImplFromTextureID(mID) ; + mMediaImplp = LLViewerMedia::getMediaImplFromTextureID(mID); } } @@ -3155,68 +3462,71 @@ void LLViewerMediaTexture::setMediaImpl() // because it does not check the face validity after the current frame. BOOL LLViewerMediaTexture::findFaces() { - mMediaFaceList.clear() ; + mMediaFaceList.clear(); - BOOL ret = TRUE ; + BOOL ret = TRUE; - LLViewerTexture* tex = gTextureList.findImage(mID) ; + LLViewerTexture* tex = gTextureList.findImage(mID, TEX_LIST_STANDARD); if(tex) //this media is a parcel media for tex. { - const ll_face_list_t* face_list = tex->getFaceList() ; - U32 end = tex->getNumFaces() ; - for(U32 i = 0 ; i < end ; i++) + for (U32 ch = 0; ch < LLRender::NUM_TEXTURE_CHANNELS; ++ch) { - mMediaFaceList.push_back((*face_list)[i]) ; + const ll_face_list_t* face_list = tex->getFaceList(ch); + U32 end = tex->getNumFaces(ch); + for(U32 i = 0; i < end; i++) + { + mMediaFaceList.push_back((*face_list)[i]); + } } } if(!mMediaImplp) { - return TRUE ; + return TRUE; } //for media on a face. - const std::list< LLVOVolume* >* obj_list = mMediaImplp->getObjectList() ; - std::list< LLVOVolume* >::const_iterator iter = obj_list->begin() ; + const std::list< LLVOVolume* >* obj_list = mMediaImplp->getObjectList(); + std::list< LLVOVolume* >::const_iterator iter = obj_list->begin(); for(; iter != obj_list->end(); ++iter) { - LLVOVolume* obj = *iter ; + LLVOVolume* obj = *iter; if(obj->mDrawable.isNull()) { - ret = FALSE ; - continue ; + ret = FALSE; + continue; } - S32 face_id = -1 ; - S32 num_faces = obj->mDrawable->getNumFaces() ; + S32 face_id = -1; + S32 num_faces = obj->mDrawable->getNumFaces(); while((face_id = obj->getFaceIndexWithMediaImpl(mMediaImplp, face_id)) > -1 && face_id < num_faces) { - LLFace* facep = obj->mDrawable->getFace(face_id) ; + LLFace* facep = obj->mDrawable->getFace(face_id); if(facep) { - mMediaFaceList.push_back(facep) ; + mMediaFaceList.push_back(facep); } else { - ret = FALSE ; + ret = FALSE; } } } - return ret ; + return ret; } void LLViewerMediaTexture::initVirtualSize() { if(mIsPlaying) { - return ; + return; } - findFaces() ; + findFaces(); for(std::list< LLFace* >::iterator iter = mMediaFaceList.begin(); iter!= mMediaFaceList.end(); ++iter) { - addTextureStats((*iter)->getVirtualSize()) ; + addTextureStats((*iter)->getVirtualSize()); } } @@ -3224,77 +3534,77 @@ void LLViewerMediaTexture::addMediaToFace(LLFace* facep) { if(facep) { - facep->setHasMedia(true) ; + facep->setHasMedia(true); } if(!mIsPlaying) { - return ; //no need to add the face because the media is not in playing. + return; //no need to add the face because the media is not in playing. } - switchTexture(facep) ; + switchTexture(LLRender::DIFFUSE_MAP, facep); } void LLViewerMediaTexture::removeMediaFromFace(LLFace* facep) { if(!facep) { - return ; + return; } - facep->setHasMedia(false) ; + facep->setHasMedia(false); if(!mIsPlaying) { - return ; //no need to remove the face because the media is not in playing. + return; //no need to remove the face because the media is not in playing. } - mIsPlaying = FALSE ; //set to remove the media from the face. - switchTexture(facep) ; - mIsPlaying = TRUE ; //set the flag back. + mIsPlaying = FALSE; //set to remove the media from the face. + switchTexture(LLRender::DIFFUSE_MAP, facep); + mIsPlaying = TRUE; //set the flag back. - if(getNumFaces() < 1) //no face referencing to this media + if(getTotalNumFaces() < 1) //no face referencing to this media { - stopPlaying() ; + stopPlaying(); } } //virtual -void LLViewerMediaTexture::addFace(LLFace* facep) +void LLViewerMediaTexture::addFace(U32 ch, LLFace* facep) { - LLViewerTexture::addFace(facep) ; + LLViewerTexture::addFace(ch, facep); - const LLTextureEntry* te = facep->getTextureEntry() ; + const LLTextureEntry* te = facep->getTextureEntry(); if(te && te->getID().notNull()) { - LLViewerTexture* tex = gTextureList.findImage(te->getID()) ; + LLViewerTexture* tex = gTextureList.findImage(te->getID(), TEX_LIST_STANDARD); if(tex) { - mTextureList.push_back(tex) ;//increase the reference number by one for tex to avoid deleting it. - return ; + mTextureList.push_back(tex);//increase the reference number by one for tex to avoid deleting it. + return; } } //check if it is a parcel media if(facep->getTexture() && facep->getTexture() != this && facep->getTexture()->getID() == mID) { - mTextureList.push_back(facep->getTexture()) ; //a parcel media. - return ; + mTextureList.push_back(facep->getTexture()); //a parcel media. + return; } if(te && te->getID().notNull()) //should have a texture { - llerrs << "The face does not have a valid texture before media texture." << llendl ; + LL_ERRS() << "The face does not have a valid texture before media texture." << LL_ENDL; } } //virtual -void LLViewerMediaTexture::removeFace(LLFace* facep) +void LLViewerMediaTexture::removeFace(U32 ch, LLFace* facep) { - LLViewerTexture::removeFace(facep) ; + LLViewerTexture::removeFace(ch, facep); - const LLTextureEntry* te = facep->getTextureEntry() ; + const LLTextureEntry* te = facep->getTextureEntry(); if(te && te->getID().notNull()) { - LLViewerTexture* tex = gTextureList.findImage(te->getID()) ; + LLViewerTexture* tex = gTextureList.findImage(te->getID(), TEX_LIST_STANDARD); if(tex) { for(std::list< LLPointer >::iterator iter = mTextureList.begin(); @@ -3302,41 +3612,52 @@ void LLViewerMediaTexture::removeFace(LLFace* facep) { if(*iter == tex) { - mTextureList.erase(iter) ; //decrease the reference number for tex by one. - return ; + mTextureList.erase(iter); //decrease the reference number for tex by one. + return; } } - // - //we have some trouble here: the texture of the face is changed. - //we need to find the former texture, and remove it from the list to avoid memory leaking. - if(!mNumFaces) + std::vector te_list; + + for (U32 ch = 0; ch < 3; ++ch) { - mTextureList.clear() ; - return ; + // + //we have some trouble here: the texture of the face is changed. + //we need to find the former texture, and remove it from the list to avoid memory leaking. + + llassert(mNumFaces[ch] <= mFaceList[ch].size()); + + for(U32 j = 0; j < mNumFaces[ch]; j++) + { + te_list.push_back(mFaceList[ch][j]->getTextureEntry());//all textures are in use. + } } - S32 end = getNumFaces() ; - std::vector te_list(end) ; - S32 i = 0 ; - for(U32 j = 0 ; j < mNumFaces ; j++) + + if (te_list.empty()) { - te_list[i++] = mFaceList[j]->getTextureEntry() ;//all textures are in use. + mTextureList.clear(); + return; } + + S32 end = te_list.size(); + for(std::list< LLPointer >::iterator iter = mTextureList.begin(); iter != mTextureList.end(); ++iter) { - for(i = 0 ; i < end ; i++) + S32 i = 0; + + for(i = 0; i < end; i++) { if(te_list[i] && te_list[i]->getID() == (*iter)->getID())//the texture is in use. { - te_list[i] = NULL ; - break ; + te_list[i] = NULL; + break; } } if(i == end) //no hit for this texture, remove it. { - mTextureList.erase(iter) ; //decrease the reference number for tex by one. - return ; + mTextureList.erase(iter); //decrease the reference number for tex by one. + return; } } } @@ -3348,14 +3669,14 @@ void LLViewerMediaTexture::removeFace(LLFace* facep) { if((*iter)->getID() == mID) { - mTextureList.erase(iter) ; //decrease the reference number for tex by one. - return ; + mTextureList.erase(iter); //decrease the reference number for tex by one. + return; } } if(te && te->getID().notNull()) //should have a texture { - llerrs << "mTextureList texture reference number is corrupted." << llendl ; + LL_ERRS() << "mTextureList texture reference number is corrupted. Texture id: " << te->getID() << " List size: " << (U32)mTextureList.size() << LL_ENDL; } } @@ -3364,12 +3685,12 @@ void LLViewerMediaTexture::stopPlaying() // Don't stop the media impl playing here -- this breaks non-inworld media (login screen, search, and media browser). // if(mMediaImplp) // { -// mMediaImplp->stop() ; +// mMediaImplp->stop(); // } - mIsPlaying = FALSE ; + mIsPlaying = FALSE; } -void LLViewerMediaTexture::switchTexture(LLFace* facep) +void LLViewerMediaTexture::switchTexture(U32 ch, LLFace* facep) { if(facep) { @@ -3379,29 +3700,29 @@ void LLViewerMediaTexture::switchTexture(LLFace* facep) { if(mID == facep->getTexture()->getID()) //this is a parcel media { - return ; //let the prim media win. + return; //let the prim media win. } } if(mIsPlaying) //old textures switch to the media texture { - facep->switchTexture(this) ; + facep->switchTexture(ch, this); } else //switch to old textures. { - const LLTextureEntry* te = facep->getTextureEntry() ; + const LLTextureEntry* te = facep->getTextureEntry(); if(te) { - LLViewerTexture* tex = te->getID().notNull() ? gTextureList.findImage(te->getID()) : NULL ; + LLViewerTexture* tex = te->getID().notNull() ? gTextureList.findImage(te->getID(), TEX_LIST_STANDARD) : NULL; if(!tex && te->getID() != mID)//try parcel media. { - tex = gTextureList.findImage(mID) ; + tex = gTextureList.findImage(mID, TEX_LIST_STANDARD); } if(!tex) { - tex = LLViewerFetchedTexture::sDefaultImagep ; + tex = LLViewerFetchedTexture::sDefaultImagep; } - facep->switchTexture(tex) ; + facep->switchTexture(ch, tex); } } } @@ -3411,46 +3732,49 @@ void LLViewerMediaTexture::setPlaying(BOOL playing) { if(!mMediaImplp) { - return ; + return; } if(!playing && !mIsPlaying) { - return ; //media is already off + return; //media is already off } if(playing == mIsPlaying && !mMediaImplp->isUpdated()) { - return ; //nothing has changed since last time. + return; //nothing has changed since last time. } - mIsPlaying = playing ; + mIsPlaying = playing; if(mIsPlaying) //is about to play this media { if(findFaces()) { //about to update all faces. - mMediaImplp->setUpdated(FALSE) ; + mMediaImplp->setUpdated(FALSE); } if(mMediaFaceList.empty())//no face pointing to this media { - stopPlaying() ; - return ; + stopPlaying(); + return; } for(std::list< LLFace* >::iterator iter = mMediaFaceList.begin(); iter!= mMediaFaceList.end(); ++iter) { - switchTexture(*iter) ; + switchTexture(LLRender::DIFFUSE_MAP, *iter); } } else //stop playing this media { - for(U32 i = mNumFaces ; i ; i--) + U32 ch = LLRender::DIFFUSE_MAP; + + llassert(mNumFaces[ch] <= mFaceList[ch].size()); + for(U32 i = mNumFaces[ch]; i; i--) { - switchTexture(mFaceList[i - 1]) ; //current face could be removed in this function. + switchTexture(ch, mFaceList[ch][i - 1]); //current face could be removed in this function. } } - return ; + return; } //virtual @@ -3458,38 +3782,42 @@ F32 LLViewerMediaTexture::getMaxVirtualSize() { if(LLFrameTimer::getFrameCount() == mUpdateVirtualSizeTime) { - return mMaxVirtualSize ; + return mMaxVirtualSize; } - mUpdateVirtualSizeTime = LLFrameTimer::getFrameCount() ; + mUpdateVirtualSizeTime = LLFrameTimer::getFrameCount(); if(!mMaxVirtualSizeResetCounter) { - addTextureStats(0.f, FALSE) ;//reset + addTextureStats(0.f, FALSE);//reset } if(mIsPlaying) //media is playing { - for(U32 i = 0 ; i < mNumFaces ; i++) + for (U32 ch = 0; ch < LLRender::NUM_TEXTURE_CHANNELS; ++ch) { - LLFace* facep = mFaceList[i] ; - if(facep->getDrawable()->isRecentlyVisible()) + llassert(mNumFaces[ch] <= mFaceList[ch].size()); + for(U32 i = 0; i < mNumFaces[ch]; i++) { - addTextureStats(facep->getVirtualSize()) ; - } - } + LLFace* facep = mFaceList[ch][i]; + if(facep->getDrawable()->isRecentlyVisible()) + { + addTextureStats(facep->getVirtualSize()); + } + } + } } else //media is not in playing { - findFaces() ; + findFaces(); if(!mMediaFaceList.empty()) { for(std::list< LLFace* >::iterator iter = mMediaFaceList.begin(); iter!= mMediaFaceList.end(); ++iter) { - LLFace* facep = *iter ; + LLFace* facep = *iter; if(facep->getDrawable()->isRecentlyVisible()) { - addTextureStats(facep->getVirtualSize()) ; + addTextureStats(facep->getVirtualSize()); } } } @@ -3499,10 +3827,10 @@ F32 LLViewerMediaTexture::getMaxVirtualSize() { mMaxVirtualSizeResetCounter--; } - reorganizeFaceList() ; + reorganizeFaceList(); reorganizeVolumeList(); - return mMaxVirtualSize ; + return mMaxVirtualSize; } //---------------------------------------------------------------------------------------------- //end of LLViewerMediaTexture @@ -3514,252 +3842,252 @@ F32 LLViewerMediaTexture::getMaxVirtualSize() #if 0 LLTexturePipelineTester::LLTexturePipelineTester() : LLMetricPerformanceTesterWithSession(sTesterName) { - addMetric("TotalBytesLoaded") ; - addMetric("TotalBytesLoadedFromCache") ; - addMetric("TotalBytesLoadedForLargeImage") ; - addMetric("TotalBytesLoadedForSculpties") ; - addMetric("StartFetchingTime") ; - addMetric("TotalGrayTime") ; - addMetric("TotalStablizingTime") ; - addMetric("StartTimeLoadingSculpties") ; - addMetric("EndTimeLoadingSculpties") ; - - addMetric("Time") ; - addMetric("TotalBytesBound") ; - addMetric("TotalBytesBoundForLargeImage") ; - addMetric("PercentageBytesBound") ; + addMetric("TotalBytesLoaded"); + addMetric("TotalBytesLoadedFromCache"); + addMetric("TotalBytesLoadedForLargeImage"); + addMetric("TotalBytesLoadedForSculpties"); + addMetric("StartFetchingTime"); + addMetric("TotalGrayTime"); + addMetric("TotalStablizingTime"); + addMetric("StartTimeLoadingSculpties"); + addMetric("EndTimeLoadingSculpties"); + + addMetric("Time"); + addMetric("TotalBytesBound"); + addMetric("TotalBytesBoundForLargeImage"); + addMetric("PercentageBytesBound"); - mTotalBytesLoaded = 0 ; - mTotalBytesLoadedFromCache = 0 ; - mTotalBytesLoadedForLargeImage = 0 ; - mTotalBytesLoadedForSculpties = 0 ; + mTotalBytesLoaded = (S32Bytes)0; + mTotalBytesLoadedFromCache = (S32Bytes)0; + mTotalBytesLoadedForLargeImage = (S32Bytes)0; + mTotalBytesLoadedForSculpties = (S32Bytes)0; - reset() ; + reset(); } LLTexturePipelineTester::~LLTexturePipelineTester() { - LLViewerTextureManager::sTesterp = NULL ; + LLViewerTextureManager::sTesterp = NULL; } void LLTexturePipelineTester::update() { - mLastTotalBytesUsed = mTotalBytesUsed ; - mLastTotalBytesUsedForLargeImage = mTotalBytesUsedForLargeImage ; - mTotalBytesUsed = 0 ; - mTotalBytesUsedForLargeImage = 0 ; + mLastTotalBytesUsed = mTotalBytesUsed; + mLastTotalBytesUsedForLargeImage = mTotalBytesUsedForLargeImage; + mTotalBytesUsed = (S32Bytes)0; + mTotalBytesUsedForLargeImage = (S32Bytes)0; if(LLAppViewer::getTextureFetch()->getNumRequests() > 0) //fetching list is not empty { if(mPause) { //start a new fetching session - reset() ; - mStartFetchingTime = LLImageGL::sLastFrameTime ; - mPause = FALSE ; + reset(); + mStartFetchingTime = LLImageGL::sLastFrameTime; + mPause = FALSE; } //update total gray time if(mUsingDefaultTexture) { - mUsingDefaultTexture = FALSE ; - mTotalGrayTime = LLImageGL::sLastFrameTime - mStartFetchingTime ; + mUsingDefaultTexture = FALSE; + mTotalGrayTime = LLImageGL::sLastFrameTime - mStartFetchingTime; } //update the stablizing timer. - updateStablizingTime() ; + updateStablizingTime(); - outputTestResults() ; + outputTestResults(); } else if(!mPause) { //stop the current fetching session - mPause = TRUE ; - outputTestResults() ; - reset() ; + mPause = TRUE; + outputTestResults(); + reset(); } } void LLTexturePipelineTester::reset() { - mPause = TRUE ; + mPause = TRUE; - mUsingDefaultTexture = FALSE ; - mStartStablizingTime = 0.0f ; - mEndStablizingTime = 0.0f ; + mUsingDefaultTexture = FALSE; + mStartStablizingTime = 0.0f; + mEndStablizingTime = 0.0f; - mTotalBytesUsed = 0 ; - mTotalBytesUsedForLargeImage = 0 ; - mLastTotalBytesUsed = 0 ; - mLastTotalBytesUsedForLargeImage = 0 ; + mTotalBytesUsed = (S32Bytes)0; + mTotalBytesUsedForLargeImage = (S32Bytes)0; + mLastTotalBytesUsed = (S32Bytes)0; + mLastTotalBytesUsedForLargeImage = (S32Bytes)0; - mStartFetchingTime = 0.0f ; + mStartFetchingTime = 0.0f; - mTotalGrayTime = 0.0f ; - mTotalStablizingTime = 0.0f ; + mTotalGrayTime = 0.0f; + mTotalStablizingTime = 0.0f; - mStartTimeLoadingSculpties = 1.0f ; - mEndTimeLoadingSculpties = 0.0f ; + mStartTimeLoadingSculpties = 1.0f; + mEndTimeLoadingSculpties = 0.0f; } //virtual void LLTexturePipelineTester::outputTestRecord(LLSD *sd) { std::string currentLabel = getCurrentLabelName(); - (*sd)[currentLabel]["TotalBytesLoaded"] = (LLSD::Integer)mTotalBytesLoaded ; - (*sd)[currentLabel]["TotalBytesLoadedFromCache"] = (LLSD::Integer)mTotalBytesLoadedFromCache ; - (*sd)[currentLabel]["TotalBytesLoadedForLargeImage"] = (LLSD::Integer)mTotalBytesLoadedForLargeImage ; - (*sd)[currentLabel]["TotalBytesLoadedForSculpties"] = (LLSD::Integer)mTotalBytesLoadedForSculpties ; + (*sd)[currentLabel]["TotalBytesLoaded"] = (LLSD::Integer)mTotalBytesLoaded.value(); + (*sd)[currentLabel]["TotalBytesLoadedFromCache"] = (LLSD::Integer)mTotalBytesLoadedFromCache.value(); + (*sd)[currentLabel]["TotalBytesLoadedForLargeImage"] = (LLSD::Integer)mTotalBytesLoadedForLargeImage.value(); + (*sd)[currentLabel]["TotalBytesLoadedForSculpties"] = (LLSD::Integer)mTotalBytesLoadedForSculpties.value(); - (*sd)[currentLabel]["StartFetchingTime"] = (LLSD::Real)mStartFetchingTime ; - (*sd)[currentLabel]["TotalGrayTime"] = (LLSD::Real)mTotalGrayTime ; - (*sd)[currentLabel]["TotalStablizingTime"] = (LLSD::Real)mTotalStablizingTime ; + (*sd)[currentLabel]["StartFetchingTime"] = (LLSD::Real)mStartFetchingTime; + (*sd)[currentLabel]["TotalGrayTime"] = (LLSD::Real)mTotalGrayTime; + (*sd)[currentLabel]["TotalStablizingTime"] = (LLSD::Real)mTotalStablizingTime; - (*sd)[currentLabel]["StartTimeLoadingSculpties"] = (LLSD::Real)mStartTimeLoadingSculpties ; - (*sd)[currentLabel]["EndTimeLoadingSculpties"] = (LLSD::Real)mEndTimeLoadingSculpties ; + (*sd)[currentLabel]["StartTimeLoadingSculpties"] = (LLSD::Real)mStartTimeLoadingSculpties; + (*sd)[currentLabel]["EndTimeLoadingSculpties"] = (LLSD::Real)mEndTimeLoadingSculpties; - (*sd)[currentLabel]["Time"] = LLImageGL::sLastFrameTime ; - (*sd)[currentLabel]["TotalBytesBound"] = (LLSD::Integer)mLastTotalBytesUsed ; - (*sd)[currentLabel]["TotalBytesBoundForLargeImage"] = (LLSD::Integer)mLastTotalBytesUsedForLargeImage ; - (*sd)[currentLabel]["PercentageBytesBound"] = (LLSD::Real)(100.f * mLastTotalBytesUsed / mTotalBytesLoaded) ; + (*sd)[currentLabel]["Time"] = LLImageGL::sLastFrameTime; + (*sd)[currentLabel]["TotalBytesBound"] = (LLSD::Integer)mLastTotalBytesUsed.value(); + (*sd)[currentLabel]["TotalBytesBoundForLargeImage"] = (LLSD::Integer)mLastTotalBytesUsedForLargeImage.value(); + (*sd)[currentLabel]["PercentageBytesBound"] = (LLSD::Real)(100.f * mLastTotalBytesUsed / mTotalBytesLoaded); } void LLTexturePipelineTester::updateTextureBindingStats(const LLViewerTexture* imagep) { - U32 mem_size = (U32)imagep->getTextureMemory() ; - mTotalBytesUsed += mem_size ; + U32Bytes mem_size = imagep->getTextureMemory(); + mTotalBytesUsed += mem_size; - if(MIN_LARGE_IMAGE_AREA <= (U32)(mem_size / (U32)imagep->getComponents())) + if(MIN_LARGE_IMAGE_AREA <= (U32)(mem_size.value() / (U32)imagep->getComponents())) { - mTotalBytesUsedForLargeImage += mem_size ; + mTotalBytesUsedForLargeImage += mem_size; } } void LLTexturePipelineTester::updateTextureLoadingStats(const LLViewerFetchedTexture* imagep, const LLImageRaw* raw_imagep, BOOL from_cache) { - U32 data_size = (U32)raw_imagep->getDataSize() ; - mTotalBytesLoaded += data_size ; + U32Bytes data_size = (U32Bytes)raw_imagep->getDataSize(); + mTotalBytesLoaded += data_size; if(from_cache) { - mTotalBytesLoadedFromCache += data_size ; + mTotalBytesLoadedFromCache += data_size; } - if(MIN_LARGE_IMAGE_AREA <= (U32)(data_size / (U32)raw_imagep->getComponents())) + if(MIN_LARGE_IMAGE_AREA <= (U32)(data_size.value() / (U32)raw_imagep->getComponents())) { - mTotalBytesLoadedForLargeImage += data_size ; + mTotalBytesLoadedForLargeImage += data_size; } if(imagep->forSculpt()) { - mTotalBytesLoadedForSculpties += data_size ; + mTotalBytesLoadedForSculpties += data_size; if(mStartTimeLoadingSculpties > mEndTimeLoadingSculpties) { - mStartTimeLoadingSculpties = LLImageGL::sLastFrameTime ; + mStartTimeLoadingSculpties = LLImageGL::sLastFrameTime; } - mEndTimeLoadingSculpties = LLImageGL::sLastFrameTime ; + mEndTimeLoadingSculpties = LLImageGL::sLastFrameTime; } } void LLTexturePipelineTester::updateGrayTextureBinding() { - mUsingDefaultTexture = TRUE ; + mUsingDefaultTexture = TRUE; } void LLTexturePipelineTester::setStablizingTime() { if(mStartStablizingTime <= mStartFetchingTime) { - mStartStablizingTime = LLImageGL::sLastFrameTime ; + mStartStablizingTime = LLImageGL::sLastFrameTime; } - mEndStablizingTime = LLImageGL::sLastFrameTime ; + mEndStablizingTime = LLImageGL::sLastFrameTime; } void LLTexturePipelineTester::updateStablizingTime() { if(mStartStablizingTime > mStartFetchingTime) { - F32 t = mEndStablizingTime - mStartStablizingTime ; + F32 t = mEndStablizingTime - mStartStablizingTime; if(t > F_ALMOST_ZERO && (t - mTotalStablizingTime) < F_ALMOST_ZERO) { //already stablized - mTotalStablizingTime = LLImageGL::sLastFrameTime - mStartStablizingTime ; + mTotalStablizingTime = LLImageGL::sLastFrameTime - mStartStablizingTime; //cancel the timer - mStartStablizingTime = 0.f ; - mEndStablizingTime = 0.f ; + mStartStablizingTime = 0.f; + mEndStablizingTime = 0.f; } else { - mTotalStablizingTime = t ; + mTotalStablizingTime = t; } } - mTotalStablizingTime = 0.f ; + mTotalStablizingTime = 0.f; } //virtual void LLTexturePipelineTester::compareTestSessions(std::ofstream* os) { - LLTexturePipelineTester::LLTextureTestSession* base_sessionp = dynamic_cast(mBaseSessionp) ; - LLTexturePipelineTester::LLTextureTestSession* current_sessionp = dynamic_cast(mCurrentSessionp) ; + LLTexturePipelineTester::LLTextureTestSession* base_sessionp = dynamic_cast(mBaseSessionp); + LLTexturePipelineTester::LLTextureTestSession* current_sessionp = dynamic_cast(mCurrentSessionp); if(!base_sessionp || !current_sessionp) { - llerrs << "type of test session does not match!" << llendl ; + LL_ERRS() << "type of test session does not match!" << LL_ENDL; } //compare and output the comparison - *os << llformat("%s\n", getTesterName().c_str()) ; - *os << llformat("AggregateResults\n") ; + *os << llformat("%s\n", getTesterName().c_str()); + *os << llformat("AggregateResults\n"); - compareTestResults(os, "TotalFetchingTime", base_sessionp->mTotalFetchingTime, current_sessionp->mTotalFetchingTime) ; - compareTestResults(os, "TotalGrayTime", base_sessionp->mTotalGrayTime, current_sessionp->mTotalGrayTime) ; + compareTestResults(os, "TotalFetchingTime", base_sessionp->mTotalFetchingTime, current_sessionp->mTotalFetchingTime); + compareTestResults(os, "TotalGrayTime", base_sessionp->mTotalGrayTime, current_sessionp->mTotalGrayTime); compareTestResults(os, "TotalStablizingTime", base_sessionp->mTotalStablizingTime, current_sessionp->mTotalStablizingTime); - compareTestResults(os, "StartTimeLoadingSculpties", base_sessionp->mStartTimeLoadingSculpties, current_sessionp->mStartTimeLoadingSculpties) ; - compareTestResults(os, "TotalTimeLoadingSculpties", base_sessionp->mTotalTimeLoadingSculpties, current_sessionp->mTotalTimeLoadingSculpties) ; + compareTestResults(os, "StartTimeLoadingSculpties", base_sessionp->mStartTimeLoadingSculpties, current_sessionp->mStartTimeLoadingSculpties); + compareTestResults(os, "TotalTimeLoadingSculpties", base_sessionp->mTotalTimeLoadingSculpties, current_sessionp->mTotalTimeLoadingSculpties); - compareTestResults(os, "TotalBytesLoaded", base_sessionp->mTotalBytesLoaded, current_sessionp->mTotalBytesLoaded) ; - compareTestResults(os, "TotalBytesLoadedFromCache", base_sessionp->mTotalBytesLoadedFromCache, current_sessionp->mTotalBytesLoadedFromCache) ; - compareTestResults(os, "TotalBytesLoadedForLargeImage", base_sessionp->mTotalBytesLoadedForLargeImage, current_sessionp->mTotalBytesLoadedForLargeImage) ; - compareTestResults(os, "TotalBytesLoadedForSculpties", base_sessionp->mTotalBytesLoadedForSculpties, current_sessionp->mTotalBytesLoadedForSculpties) ; + compareTestResults(os, "TotalBytesLoaded", base_sessionp->mTotalBytesLoaded, current_sessionp->mTotalBytesLoaded); + compareTestResults(os, "TotalBytesLoadedFromCache", base_sessionp->mTotalBytesLoadedFromCache, current_sessionp->mTotalBytesLoadedFromCache); + compareTestResults(os, "TotalBytesLoadedForLargeImage", base_sessionp->mTotalBytesLoadedForLargeImage, current_sessionp->mTotalBytesLoadedForLargeImage); + compareTestResults(os, "TotalBytesLoadedForSculpties", base_sessionp->mTotalBytesLoadedForSculpties, current_sessionp->mTotalBytesLoadedForSculpties); - *os << llformat("InstantResults\n") ; - S32 size = llmin(base_sessionp->mInstantPerformanceListCounter, current_sessionp->mInstantPerformanceListCounter) ; - for(S32 i = 0 ; i < size ; i++) + *os << llformat("InstantResults\n"); + S32 size = llmin(base_sessionp->mInstantPerformanceListCounter, current_sessionp->mInstantPerformanceListCounter); + for(S32 i = 0; i < size; i++) { - *os << llformat("Time(B-T)-%.4f-%.4f\n", base_sessionp->mInstantPerformanceList[i].mTime, current_sessionp->mInstantPerformanceList[i].mTime) ; + *os << llformat("Time(B-T)-%.4f-%.4f\n", base_sessionp->mInstantPerformanceList[i].mTime, current_sessionp->mInstantPerformanceList[i].mTime); compareTestResults(os, "AverageBytesUsedPerSecond", base_sessionp->mInstantPerformanceList[i].mAverageBytesUsedPerSecond, - current_sessionp->mInstantPerformanceList[i].mAverageBytesUsedPerSecond) ; + current_sessionp->mInstantPerformanceList[i].mAverageBytesUsedPerSecond); compareTestResults(os, "AverageBytesUsedForLargeImagePerSecond", base_sessionp->mInstantPerformanceList[i].mAverageBytesUsedForLargeImagePerSecond, - current_sessionp->mInstantPerformanceList[i].mAverageBytesUsedForLargeImagePerSecond) ; + current_sessionp->mInstantPerformanceList[i].mAverageBytesUsedForLargeImagePerSecond); compareTestResults(os, "AveragePercentageBytesUsedPerSecond", base_sessionp->mInstantPerformanceList[i].mAveragePercentageBytesUsedPerSecond, - current_sessionp->mInstantPerformanceList[i].mAveragePercentageBytesUsedPerSecond) ; + current_sessionp->mInstantPerformanceList[i].mAveragePercentageBytesUsedPerSecond); } if(size < base_sessionp->mInstantPerformanceListCounter) { - for(S32 i = size ; i < base_sessionp->mInstantPerformanceListCounter ; i++) + for(S32 i = size; i < base_sessionp->mInstantPerformanceListCounter; i++) { - *os << llformat("Time(B-T)-%.4f- \n", base_sessionp->mInstantPerformanceList[i].mTime) ; + *os << llformat("Time(B-T)-%.4f- \n", base_sessionp->mInstantPerformanceList[i].mTime); - *os << llformat(", AverageBytesUsedPerSecond, %d, N/A \n", base_sessionp->mInstantPerformanceList[i].mAverageBytesUsedPerSecond) ; - *os << llformat(", AverageBytesUsedForLargeImagePerSecond, %d, N/A \n", base_sessionp->mInstantPerformanceList[i].mAverageBytesUsedForLargeImagePerSecond) ; - *os << llformat(", AveragePercentageBytesUsedPerSecond, %.4f, N/A \n", base_sessionp->mInstantPerformanceList[i].mAveragePercentageBytesUsedPerSecond) ; + *os << llformat(", AverageBytesUsedPerSecond, %d, N/A \n", base_sessionp->mInstantPerformanceList[i].mAverageBytesUsedPerSecond); + *os << llformat(", AverageBytesUsedForLargeImagePerSecond, %d, N/A \n", base_sessionp->mInstantPerformanceList[i].mAverageBytesUsedForLargeImagePerSecond); + *os << llformat(", AveragePercentageBytesUsedPerSecond, %.4f, N/A \n", base_sessionp->mInstantPerformanceList[i].mAveragePercentageBytesUsedPerSecond); } } else if(size < current_sessionp->mInstantPerformanceListCounter) { - for(S32 i = size ; i < current_sessionp->mInstantPerformanceListCounter ; i++) + for(S32 i = size; i < current_sessionp->mInstantPerformanceListCounter; i++) { - *os << llformat("Time(B-T)- -%.4f\n", current_sessionp->mInstantPerformanceList[i].mTime) ; + *os << llformat("Time(B-T)- -%.4f\n", current_sessionp->mInstantPerformanceList[i].mTime); - *os << llformat(", AverageBytesUsedPerSecond, N/A, %d\n", current_sessionp->mInstantPerformanceList[i].mAverageBytesUsedPerSecond) ; - *os << llformat(", AverageBytesUsedForLargeImagePerSecond, N/A, %d\n", current_sessionp->mInstantPerformanceList[i].mAverageBytesUsedForLargeImagePerSecond) ; - *os << llformat(", AveragePercentageBytesUsedPerSecond, N/A, %.4f\n", current_sessionp->mInstantPerformanceList[i].mAveragePercentageBytesUsedPerSecond) ; + *os << llformat(", AverageBytesUsedPerSecond, N/A, %d\n", current_sessionp->mInstantPerformanceList[i].mAverageBytesUsedPerSecond); + *os << llformat(", AverageBytesUsedForLargeImagePerSecond, N/A, %d\n", current_sessionp->mInstantPerformanceList[i].mAverageBytesUsedForLargeImagePerSecond); + *os << llformat(", AveragePercentageBytesUsedPerSecond, N/A, %.4f\n", current_sessionp->mInstantPerformanceList[i].mAveragePercentageBytesUsedPerSecond); } } } @@ -3767,144 +4095,144 @@ void LLTexturePipelineTester::compareTestSessions(std::ofstream* os) //virtual LLMetricPerformanceTesterWithSession::LLTestSession* LLTexturePipelineTester::loadTestSession(LLSD* log) { - LLTexturePipelineTester::LLTextureTestSession* sessionp = new LLTexturePipelineTester::LLTextureTestSession() ; + LLTexturePipelineTester::LLTextureTestSession* sessionp = new LLTexturePipelineTester::LLTextureTestSession(); if(!sessionp) { - return NULL ; + return NULL; } - F32 total_fetching_time = 0.f ; - F32 total_gray_time = 0.f ; - F32 total_stablizing_time = 0.f ; - F32 total_loading_sculpties_time = 0.f ; - - F32 start_fetching_time = -1.f ; - F32 start_fetching_sculpties_time = 0.f ; - - F32 last_time = 0.0f ; - S32 frame_count = 0 ; - - sessionp->mInstantPerformanceListCounter = 0 ; - sessionp->mInstantPerformanceList.resize(128) ; - sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAverageBytesUsedPerSecond = 0 ; - sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAverageBytesUsedForLargeImagePerSecond = 0 ; - sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAveragePercentageBytesUsedPerSecond = 0.f ; - sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mTime = 0.f ; + F32 total_fetching_time = 0.f; + F32 total_gray_time = 0.f; + F32 total_stablizing_time = 0.f; + F32 total_loading_sculpties_time = 0.f; + + F32 start_fetching_time = -1.f; + F32 start_fetching_sculpties_time = 0.f; + + F32 last_time = 0.0f; + S32 frame_count = 0; + + sessionp->mInstantPerformanceListCounter = 0; + sessionp->mInstantPerformanceList.resize(128); + sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAverageBytesUsedPerSecond = 0; + sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAverageBytesUsedForLargeImagePerSecond = 0; + sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAveragePercentageBytesUsedPerSecond = 0.f; + sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mTime = 0.f; //load a session std::string currentLabel = getCurrentLabelName(); - BOOL in_log = (*log).has(currentLabel) ; + BOOL in_log = (*log).has(currentLabel); while (in_log) { - LLSD::String label = currentLabel ; + LLSD::String label = currentLabel; if(sessionp->mInstantPerformanceListCounter >= (S32)sessionp->mInstantPerformanceList.size()) { - sessionp->mInstantPerformanceList.resize(sessionp->mInstantPerformanceListCounter + 128) ; + sessionp->mInstantPerformanceList.resize(sessionp->mInstantPerformanceListCounter + 128); } //time - F32 start_time = (*log)[label]["StartFetchingTime"].asReal() ; - F32 cur_time = (*log)[label]["Time"].asReal() ; + F32 start_time = (*log)[label]["StartFetchingTime"].asReal(); + F32 cur_time = (*log)[label]["Time"].asReal(); if(start_time - start_fetching_time > F_ALMOST_ZERO) //fetching has paused for a while { - sessionp->mTotalFetchingTime += total_fetching_time ; - sessionp->mTotalGrayTime += total_gray_time ; - sessionp->mTotalStablizingTime += total_stablizing_time ; - - sessionp->mStartTimeLoadingSculpties = start_fetching_sculpties_time ; - sessionp->mTotalTimeLoadingSculpties += total_loading_sculpties_time ; - - start_fetching_time = start_time ; - total_fetching_time = 0.0f ; - total_gray_time = 0.f ; - total_stablizing_time = 0.f ; - total_loading_sculpties_time = 0.f ; + sessionp->mTotalFetchingTime += total_fetching_time; + sessionp->mTotalGrayTime += total_gray_time; + sessionp->mTotalStablizingTime += total_stablizing_time; + + sessionp->mStartTimeLoadingSculpties = start_fetching_sculpties_time; + sessionp->mTotalTimeLoadingSculpties += total_loading_sculpties_time; + + start_fetching_time = start_time; + total_fetching_time = 0.0f; + total_gray_time = 0.f; + total_stablizing_time = 0.f; + total_loading_sculpties_time = 0.f; } else { - total_fetching_time = cur_time - start_time ; - total_gray_time = (*log)[label]["TotalGrayTime"].asReal() ; - total_stablizing_time = (*log)[label]["TotalStablizingTime"].asReal() ; + total_fetching_time = cur_time - start_time; + total_gray_time = (*log)[label]["TotalGrayTime"].asReal(); + total_stablizing_time = (*log)[label]["TotalStablizingTime"].asReal(); - total_loading_sculpties_time = (*log)[label]["EndTimeLoadingSculpties"].asReal() - (*log)[label]["StartTimeLoadingSculpties"].asReal() ; + total_loading_sculpties_time = (*log)[label]["EndTimeLoadingSculpties"].asReal() - (*log)[label]["StartTimeLoadingSculpties"].asReal(); if(start_fetching_sculpties_time < 0.f && total_loading_sculpties_time > 0.f) { - start_fetching_sculpties_time = (*log)[label]["StartTimeLoadingSculpties"].asReal() ; + start_fetching_sculpties_time = (*log)[label]["StartTimeLoadingSculpties"].asReal(); } } //total loaded bytes - sessionp->mTotalBytesLoaded = (*log)[label]["TotalBytesLoaded"].asInteger() ; - sessionp->mTotalBytesLoadedFromCache = (*log)[label]["TotalBytesLoadedFromCache"].asInteger() ; - sessionp->mTotalBytesLoadedForLargeImage = (*log)[label]["TotalBytesLoadedForLargeImage"].asInteger() ; - sessionp->mTotalBytesLoadedForSculpties = (*log)[label]["TotalBytesLoadedForSculpties"].asInteger() ; + sessionp->mTotalBytesLoaded = (*log)[label]["TotalBytesLoaded"].asInteger(); + sessionp->mTotalBytesLoadedFromCache = (*log)[label]["TotalBytesLoadedFromCache"].asInteger(); + sessionp->mTotalBytesLoadedForLargeImage = (*log)[label]["TotalBytesLoadedForLargeImage"].asInteger(); + sessionp->mTotalBytesLoadedForSculpties = (*log)[label]["TotalBytesLoadedForSculpties"].asInteger(); //instant metrics sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAverageBytesUsedPerSecond += - (*log)[label]["TotalBytesBound"].asInteger() ; + (*log)[label]["TotalBytesBound"].asInteger(); sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAverageBytesUsedForLargeImagePerSecond += - (*log)[label]["TotalBytesBoundForLargeImage"].asInteger() ; + (*log)[label]["TotalBytesBoundForLargeImage"].asInteger(); sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAveragePercentageBytesUsedPerSecond += - (*log)[label]["PercentageBytesBound"].asReal() ; - frame_count++ ; + (*log)[label]["PercentageBytesBound"].asReal(); + frame_count++; if(cur_time - last_time >= 1.0f) { - sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAverageBytesUsedPerSecond /= frame_count ; - sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAverageBytesUsedForLargeImagePerSecond /= frame_count ; - sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAveragePercentageBytesUsedPerSecond /= frame_count ; - sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mTime = last_time ; - - frame_count = 0 ; - last_time = cur_time ; - sessionp->mInstantPerformanceListCounter++ ; - sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAverageBytesUsedPerSecond = 0 ; - sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAverageBytesUsedForLargeImagePerSecond = 0 ; - sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAveragePercentageBytesUsedPerSecond = 0.f ; - sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mTime = 0.f ; + sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAverageBytesUsedPerSecond /= frame_count; + sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAverageBytesUsedForLargeImagePerSecond /= frame_count; + sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAveragePercentageBytesUsedPerSecond /= frame_count; + sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mTime = last_time; + + frame_count = 0; + last_time = cur_time; + sessionp->mInstantPerformanceListCounter++; + sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAverageBytesUsedPerSecond = 0; + sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAverageBytesUsedForLargeImagePerSecond = 0; + sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAveragePercentageBytesUsedPerSecond = 0.f; + sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mTime = 0.f; } // Next label - incrementCurrentCount() ; + incrementCurrentCount(); currentLabel = getCurrentLabelName(); - in_log = (*log).has(currentLabel) ; + in_log = (*log).has(currentLabel); } - sessionp->mTotalFetchingTime += total_fetching_time ; - sessionp->mTotalGrayTime += total_gray_time ; - sessionp->mTotalStablizingTime += total_stablizing_time ; + sessionp->mTotalFetchingTime += total_fetching_time; + sessionp->mTotalGrayTime += total_gray_time; + sessionp->mTotalStablizingTime += total_stablizing_time; if(sessionp->mStartTimeLoadingSculpties < 0.f) { - sessionp->mStartTimeLoadingSculpties = start_fetching_sculpties_time ; + sessionp->mStartTimeLoadingSculpties = start_fetching_sculpties_time; } - sessionp->mTotalTimeLoadingSculpties += total_loading_sculpties_time ; + sessionp->mTotalTimeLoadingSculpties += total_loading_sculpties_time; return sessionp; } LLTexturePipelineTester::LLTextureTestSession::LLTextureTestSession() { - reset() ; + reset(); } LLTexturePipelineTester::LLTextureTestSession::~LLTextureTestSession() { } void LLTexturePipelineTester::LLTextureTestSession::reset() { - mTotalFetchingTime = 0.0f ; + mTotalFetchingTime = 0.0f; - mTotalGrayTime = 0.0f ; - mTotalStablizingTime = 0.0f ; + mTotalGrayTime = 0.0f; + mTotalStablizingTime = 0.0f; - mStartTimeLoadingSculpties = 0.0f ; - mTotalTimeLoadingSculpties = 0.0f ; + mStartTimeLoadingSculpties = 0.0f; + mTotalTimeLoadingSculpties = 0.0f; - mTotalBytesLoaded = 0 ; - mTotalBytesLoadedFromCache = 0 ; - mTotalBytesLoadedForLargeImage = 0 ; - mTotalBytesLoadedForSculpties = 0 ; + mTotalBytesLoaded = 0; + mTotalBytesLoadedFromCache = 0; + mTotalBytesLoadedForLargeImage = 0; + mTotalBytesLoadedForSculpties = 0; - mInstantPerformanceListCounter = 0 ; + mInstantPerformanceListCounter = 0; } #endif //0 //---------------------------------------------------------------------------------------------- diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h index b378f578d7..0a68570598 100644 --- a/indra/newview/llviewertexture.h +++ b/indra/newview/llviewertexture.h @@ -36,14 +36,15 @@ #if 0 #include "llmetricperformancetester.h" #endif +#include "llface.h" #include #include -#define MIN_VIDEO_RAM_IN_MEGA_BYTES 32 -#define MAX_VIDEO_RAM_IN_MEGA_BYTES 512 // 512MB max for performance reasons. +extern const S32Megabytes gMinVideoRam; +extern const S32Megabytes gMaxVideoRam; + -class LLFace; class LLImageGL ; class LLImageRaw; class LLViewerObject; @@ -59,11 +60,13 @@ class LLVFile; class LLMessageSystem; class LLViewerMediaImpl ; class LLVOVolume ; +class LLFace ; //But llface.h is already included...(?) +struct LLTextureKey; class LLLoadedCallbackEntry { public: - typedef std::set< LLUUID > source_callback_list_t; + typedef std::set< LLTextureKey > source_callback_list_t; public: LLLoadedCallbackEntry(loaded_callback_func cb, @@ -117,10 +120,10 @@ class LLViewerTexture : public LLGLTexture static void initClass(); static void updateClass(const F32 velocity, const F32 angular_velocity) ; - LLViewerTexture(BOOL usemipmaps = TRUE); - LLViewerTexture(const LLUUID& id, BOOL usemipmaps) ; - LLViewerTexture(const LLImageRaw* raw, BOOL usemipmaps) ; - LLViewerTexture(const U32 width, const U32 height, const U8 components, BOOL usemipmaps) ; + LLViewerTexture(BOOL usemipmaps = TRUE, bool allow_compression = false); + LLViewerTexture(const LLUUID& id, BOOL usemipmaps, bool allow_compression = false) ; + LLViewerTexture(const LLImageRaw* raw, BOOL usemipmaps, bool allow_compression = false) ; + LLViewerTexture(const U32 width, const U32 height, const U8 components, BOOL usemipmaps, bool allow_compression = false) ; void setNeedsAlphaAndPickMask(BOOL need_mask) { if(mGLTexturep)mGLTexturep->setNeedsAlphaAndPickMask(need_mask); } @@ -130,10 +133,14 @@ class LLViewerTexture : public LLGLTexture /*virtual*/ bool bindDefaultImage(const S32 stage = 0) ; /*virtual*/ void forceImmediateUpdate() ; + /*virtual*/ bool isActiveFetching(); /*virtual*/ const LLUUID& getID() const { return mID; } - //void setBoostLevel(S32 level); + void setID(const LLUUID& id) { mID = id; } // Edit for local assets to cut down on reloads, be sure to remove from wherever this has been added first. + void setBoostLevel(S32 level); S32 getBoostLevel() { return mBoostLevel; } + void setTextureListType(S32 tex_type) { mTextureListType = tex_type; } + S32 getTextureListType() { return mTextureListType; } void addTextureStats(F32 virtual_size, BOOL needs_gltexture = TRUE) const; void resetTextureStats(); @@ -145,17 +152,20 @@ class LLViewerTexture : public LLGLTexture LLFrameTimer* getLastReferencedTimer() {return &mLastReferencedTimer ;} + S32 getFullWidth() const { return mFullWidth; } + S32 getFullHeight() const { return mFullHeight; } /*virtual*/ void setKnownDrawSize(S32 width, S32 height); - virtual void addFace(LLFace* facep) ; - virtual void removeFace(LLFace* facep) ; - S32 getNumFaces() const; - const ll_face_list_t* getFaceList() const {return &mFaceList;} + virtual void addFace(U32 channel, LLFace* facep) ; + virtual void removeFace(U32 channel, LLFace* facep) ; + S32 getTotalNumFaces() const; + S32 getNumFaces(U32 ch) const; + const ll_face_list_t* getFaceList(U32 channel) const {llassert(channel < LLRender::NUM_TEXTURE_CHANNELS); return &mFaceList[channel];} - virtual void addVolume(LLVOVolume* volumep); - virtual void removeVolume(LLVOVolume* volumep); - S32 getNumVolumes() const; - const ll_volume_list_t* getVolumeList() const { return &mVolumeList; } + virtual void addVolume(U32 channel, LLVOVolume* volumep); + virtual void removeVolume(U32 channel, LLVOVolume* volumep); + S32 getNumVolumes(U32 channel) const; + const ll_volume_list_t* getVolumeList(U32 channel) const { return &mVolumeList[channel]; } virtual void setCachedRawImage(S32 discard_level, LLImageRaw* imageraw) ; @@ -171,6 +181,10 @@ class LLViewerTexture : public LLGLTexture void init(bool firstinit) ; void reorganizeFaceList() ; void reorganizeVolumeList() ; + + void notifyAboutMissingAsset(); + void notifyAboutCreatingTexture(); + private: friend class LLBumpImageList; friend class LLUIImageList; @@ -181,19 +195,21 @@ class LLViewerTexture : public LLGLTexture static bool isMemoryForTextureLow() ; protected: LLUUID mID; + S32 mTextureListType; // along with mID identifies where to search for this texture in TextureList + F32 mSelectedTime; // time texture was last selected mutable F32 mMaxVirtualSize; // The largest virtual size of the image, in pixels - how much data to we need? mutable S32 mMaxVirtualSizeResetCounter ; mutable S32 mMaxVirtualSizeResetInterval; mutable F32 mAdditionalDecodePriority; // priority add to mDecodePriority. LLFrameTimer mLastReferencedTimer; - ll_face_list_t mFaceList ; //reverse pointer pointing to the faces using this image as texture - U32 mNumFaces ; + ll_face_list_t mFaceList[LLRender::NUM_TEXTURE_CHANNELS]; //reverse pointer pointing to the faces using this image as texture + U32 mNumFaces[LLRender::NUM_TEXTURE_CHANNELS]; LLFrameTimer mLastFaceListUpdateTimer ; - ll_volume_list_t mVolumeList; - U32 mNumVolumes; + ll_volume_list_t mVolumeList[LLRender::NUM_VOLUME_TEXTURE_CHANNELS]; + U32 mNumVolumes[LLRender::NUM_VOLUME_TEXTURE_CHANNELS]; LLFrameTimer mLastVolumeListUpdateTimer; //do not use LLPointer here. @@ -208,12 +224,12 @@ class LLViewerTexture : public LLGLTexture static LLFrameTimer sEvaluationTimer; static F32 sDesiredDiscardBias; static F32 sDesiredDiscardScale; - static S32 sBoundTextureMemoryInBytes; - static S32 sTotalTextureMemoryInBytes; - static S32 sMaxBoundTextureMemInMegaBytes; - static S32 sMaxTotalTextureMemInMegaBytes; - static S32 sMaxDesiredTextureMemInBytes ; - static S8 sCameraMovingDiscardBias; + static S64Bytes sBoundTextureMemory; + static S64Bytes sTotalTextureMemory; + static S32Megabytes sMaxBoundTextureMemory; + static S32Megabytes sMaxTotalTextureMem; + static S64Bytes sMaxDesiredTextureMem ; + static S32 sCameraMovingDiscardBias; static F32 sCameraMovingBias; static S32 sMaxSculptRez ; static S32 sMinLargeImageSize ; @@ -237,6 +253,18 @@ class LLViewerTexture : public LLGLTexture }; +enum FTType +{ + FTT_UNKNOWN = -1, + FTT_DEFAULT = 0, // standard texture fetched by id. + FTT_SERVER_BAKE, // texture produced by appearance service and fetched from there. + FTT_HOST_BAKE, // old-style baked texture uploaded by viewer and fetched from avatar's host. + FTT_MAP_TILE, // tiles are fetched from map server directly. + FTT_LOCAL_FILE // fetch directly from a local file. +}; + +const std::string& fttype_to_string(const FTType& fttype); + // //textures are managed in gTextureList. //raw image data is fetched from remote or local cache @@ -250,9 +278,9 @@ class LLViewerFetchedTexture : public LLViewerTexture protected: /*virtual*/ ~LLViewerFetchedTexture(); public: - LLViewerFetchedTexture(const LLUUID& id, const LLHost& host = LLHost::invalid, BOOL usemipmaps = TRUE); - LLViewerFetchedTexture(const LLImageRaw* raw, BOOL usemipmaps); - LLViewerFetchedTexture(const std::string& url, const LLUUID& id, BOOL usemipmaps = TRUE); + LLViewerFetchedTexture(const LLUUID& id, FTType f_type, const LLHost& host = LLHost::invalid, BOOL usemipmaps = TRUE); + LLViewerFetchedTexture(const LLImageRaw* raw, FTType f_type, BOOL usemipmaps); + LLViewerFetchedTexture(const std::string& url, FTType f_type, const LLUUID& id, BOOL usemipmaps = TRUE); public: static F32 maxDecodePriority(); @@ -277,6 +305,7 @@ class LLViewerFetchedTexture : public LLViewerTexture public: /*virtual*/ S8 getType() const ; + FTType getFTType() const; /*virtual*/ void forceImmediateUpdate() ; /*virtual*/ void dump() ; @@ -295,7 +324,7 @@ class LLViewerFetchedTexture : public LLViewerTexture void addToCreateTexture(); // ONLY call from LLViewerTextureList - BOOL createTexture(S32 usename = 0); + BOOL createTexture(LLImageGL::GLTextureName* usename = nullptr); void destroyTexture() ; virtual void processTextureStats() ; @@ -322,13 +351,17 @@ class LLViewerFetchedTexture : public LLViewerTexture void setMinDiscardLevel(S32 discard) { mMinDesiredDiscardLevel = llmin(mMinDesiredDiscardLevel,(S8)discard); } bool updateFetch(); + bool setDebugFetching(S32 debug_level); + bool isInDebug() {return mInDebug;} + void clearFetchedResults(); //clear all fetched results, for debug use. + // Override the computation of discard levels if we know the exact output // size of the image. Used for UI textures to not decode, even if we have // more data. /*virtual*/ void setKnownDrawSize(S32 width, S32 height); - void setIsMissingAsset(); + void setIsMissingAsset(BOOL is_missing = true); /*virtual*/ BOOL isMissingAsset() const { return mIsMissingAsset; } // returns dimensions of original image for local files (before power of two scaling) @@ -371,6 +404,7 @@ class LLViewerFetchedTexture : public LLViewerTexture BOOL isCachedRawImageReady() const {return mCachedRawImageReady ;} BOOL isRawImageValid()const { return mIsRawImageValid ; } void forceToSaveRawImage(S32 desired_discard = 0, F32 kept_time = 0.f) ; + void forceToRefetchTexture(S32 desired_discard = 0, F32 kept_time = 60.f); /*virtual*/ void setCachedRawImage(S32 discard_level, LLImageRaw* imageraw) ; void destroySavedRawImage() ; LLImageRaw* getSavedRawImage() ; @@ -383,6 +417,11 @@ class LLViewerFetchedTexture : public LLViewerTexture void forceToDeleteRequest(); void forceRefetch(); + /*virtual*/bool isActiveFetching(); //is actively in fetching by the fetching pipeline. + + LLUUID getUploader(); + LLDate getUploadTime(); + std::string getComment(); protected: /*virtual*/ void switchToCachedImage(); @@ -403,6 +442,8 @@ class LLViewerFetchedTexture : public LLViewerTexture private: BOOL mFullyLoaded; + BOOL mInDebug; + BOOL mForceCallbackFetch; protected: std::string mLocalFileName; @@ -430,12 +471,14 @@ class LLViewerFetchedTexture : public LLViewerTexture S8 mMinDesiredDiscardLevel; // The minimum discard level we'd like to have S8 mNeedsAux; // We need to decode the auxiliary channels + S8 mHasAux; // We have aux channels S8 mDecodingAux; // Are we decoding high components S8 mIsRawImageValid; S8 mHasFetcher; // We've made a fecth request S8 mIsFetching; // Fetch request is active bool mCanUseHTTP ; //This texture can be fetched through http if true. - + + const FTType mFTType; // What category of image is this - map tile, server bake, etc? mutable S8 mIsMissingAsset; // True if we know that there is no image asset with this image id in the database. typedef std::list callback_list_t; @@ -477,12 +520,15 @@ class LLViewerFetchedTexture : public LLViewerTexture BOOL mForSculpt ; //a flag if the texture is used as sculpt data. BOOL mIsFetched ; //is loaded from remote or from cache, not generated locally. + + std::map mComment; public: static LLPointer sMissingAssetImagep; // Texture to show for an image asset that is not in the database static LLPointer sWhiteImagep; // Texture to show NOTHING (whiteness) static LLPointer sDefaultImagep; // "Default" texture for error cases, the only case of fetched texture which is generated in local. static LLPointer sSmokeImagep; // Old "Default" translucent texture + static LLPointer sFlatNormalImagep; // Flat normal map denoting no bumpiness on a surface }; // @@ -495,8 +541,8 @@ class LLViewerLODTexture : public LLViewerFetchedTexture /*virtual*/ ~LLViewerLODTexture(){} public: - LLViewerLODTexture(const LLUUID& id, const LLHost& host = LLHost::invalid, BOOL usemipmaps = TRUE); - LLViewerLODTexture(const std::string& url, const LLUUID& id, BOOL usemipmaps = TRUE); + LLViewerLODTexture(const LLUUID& id, FTType f_type, const LLHost& host = LLHost::invalid, BOOL usemipmaps = TRUE); + LLViewerLODTexture(const std::string& url, FTType f_type, const LLUUID& id, BOOL usemipmaps = TRUE); /*virtual*/ S8 getType() const; // Process image stats to determine priority/quality requirements. @@ -540,12 +586,12 @@ class LLViewerMediaTexture : public LLViewerTexture void addMediaToFace(LLFace* facep) ; void removeMediaFromFace(LLFace* facep) ; - /*virtual*/ void addFace(LLFace* facep) ; - /*virtual*/ void removeFace(LLFace* facep) ; + /*virtual*/ void addFace(U32 ch, LLFace* facep) ; + /*virtual*/ void removeFace(U32 ch, LLFace* facep) ; /*virtual*/ F32 getMaxVirtualSize() ; private: - void switchTexture(LLFace* facep) ; + void switchTexture(U32 ch, LLFace* facep) ; BOOL findFaces() ; void stopPlaying() ; @@ -562,7 +608,7 @@ class LLViewerMediaTexture : public LLViewerTexture LLViewerMediaImpl* mMediaImplp ; BOOL mIsPlaying ; - U32 mUpdateVirtualSizeTime ; + U64 mUpdateVirtualSizeTime ; public: static void updateClass() ; @@ -595,8 +641,9 @@ class LLViewerTextureManager // //"find-texture" just check if the texture exists, if yes, return it, otherwise return null. // - static LLViewerTexture* findTexture(const LLUUID& id) ; - static LLViewerFetchedTexture* findFetchedTexture(const LLUUID& id) ; + static void findFetchedTextures(const LLUUID& id, std::vector &output); + static void findTextures(const LLUUID& id, std::vector &output); + static LLViewerFetchedTexture* findFetchedTexture(const LLUUID& id, S32 tex_type); static LLViewerMediaTexture* findMediaTexture(const LLUUID& id) ; static LLViewerMediaTexture* createMediaTexture(const LLUUID& id, BOOL usemipmaps = TRUE, LLImageGL* gl_image = NULL) ; @@ -612,6 +659,7 @@ class LLViewerTextureManager static LLPointer getLocalTexture(const U32 width, const U32 height, const U8 components, BOOL usemipmaps, BOOL generate_gl_tex = TRUE) ; static LLViewerFetchedTexture* getFetchedTexture(const LLUUID &image_id, + FTType f_type = FTT_DEFAULT, BOOL usemipmap = TRUE, LLViewerTexture::EBoostLevel boost_priority = LLGLTexture::BOOST_NONE, // Get the requested level immediately upon creation. S8 texture_type = LLViewerTexture::FETCHED_TEXTURE, @@ -621,6 +669,7 @@ class LLViewerTextureManager ); static LLViewerFetchedTexture* getFetchedTextureFromFile(const std::string& filename, + FTType f_type = FTT_LOCAL_FILE, BOOL usemipmap = TRUE, LLViewerTexture::EBoostLevel boost_priority = LLGLTexture::BOOST_NONE, S8 texture_type = LLViewerTexture::FETCHED_TEXTURE, @@ -630,6 +679,7 @@ class LLViewerTextureManager ); static LLViewerFetchedTexture* getFetchedTextureFromUrl(const std::string& url, + FTType f_type, BOOL usemipmap = TRUE, LLViewerTexture::EBoostLevel boost_priority = LLGLTexture::BOOST_NONE, S8 texture_type = LLViewerTexture::FETCHED_TEXTURE, @@ -638,7 +688,7 @@ class LLViewerTextureManager const LLUUID& force_id = LLUUID::null ); - static LLViewerFetchedTexture* getFetchedTextureFromHost(const LLUUID& image_id, LLHost host) ; + static LLViewerFetchedTexture* getFetchedTextureFromHost(const LLUUID& image_id, FTType f_type, LLHost host) ; static void init() ; static void cleanup() ; @@ -676,18 +726,18 @@ class LLTexturePipelineTester : public LLMetricPerformanceTesterWithSession private: BOOL mUsingDefaultTexture; //if set, some textures are still gray. - U32 mTotalBytesUsed ; //total bytes of textures bound/used for the current frame. - U32 mTotalBytesUsedForLargeImage ; //total bytes of textures bound/used for the current frame for images larger than 256 * 256. - U32 mLastTotalBytesUsed ; //total bytes of textures bound/used for the previous frame. - U32 mLastTotalBytesUsedForLargeImage ; //total bytes of textures bound/used for the previous frame for images larger than 256 * 256. + U32Bytes mTotalBytesUsed ; //total bytes of textures bound/used for the current frame. + U32Bytes mTotalBytesUsedForLargeImage ; //total bytes of textures bound/used for the current frame for images larger than 256 * 256. + U32Bytes mLastTotalBytesUsed ; //total bytes of textures bound/used for the previous frame. + U32Bytes mLastTotalBytesUsedForLargeImage ; //total bytes of textures bound/used for the previous frame for images larger than 256 * 256. // //data size // - U32 mTotalBytesLoaded ; //total bytes fetched by texture pipeline - U32 mTotalBytesLoadedFromCache ; //total bytes fetched by texture pipeline from local cache - U32 mTotalBytesLoadedForLargeImage ; //total bytes fetched by texture pipeline for images larger than 256 * 256. - U32 mTotalBytesLoadedForSculpties ; //total bytes fetched by texture pipeline for sculpties + U32Bytes mTotalBytesLoaded ; //total bytes fetched by texture pipeline + U32Bytes mTotalBytesLoadedFromCache ; //total bytes fetched by texture pipeline from local cache + U32Bytes mTotalBytesLoadedForLargeImage ; //total bytes fetched by texture pipeline for images larger than 256 * 256. + U32Bytes mTotalBytesLoadedForSculpties ; //total bytes fetched by texture pipeline for sculpties // //time diff --git a/indra/newview/llviewertextureanim.cpp b/indra/newview/llviewertextureanim.cpp index 2b364851a7..c91e997e09 100644 --- a/indra/newview/llviewertextureanim.cpp +++ b/indra/newview/llviewertextureanim.cpp @@ -49,15 +49,10 @@ LLViewerTextureAnim::LLViewerTextureAnim(LLVOVolume* vobj) : LLTextureAnim() LLViewerTextureAnim::~LLViewerTextureAnim() { - S32 end_idx = sInstanceList.size()-1; - - if (end_idx != mInstanceIndex) - { - sInstanceList[mInstanceIndex] = sInstanceList[end_idx]; - sInstanceList[mInstanceIndex]->mInstanceIndex = mInstanceIndex; - } - - sInstanceList.pop_back(); + std::vector::iterator it(sInstanceList.begin() + mInstanceIndex); + std::vector::iterator iter = vector_replace_with_last(sInstanceList, it); + if(iter != sInstanceList.end()) + (*iter)->mInstanceIndex = mInstanceIndex; } void LLViewerTextureAnim::reset() @@ -179,7 +174,7 @@ S32 LLViewerTextureAnim::animateTextures(F32 &off_s, F32 &off_t, if (!(mMode & SMOOTH)) { - frame_counter = (F32)llround(frame_counter); + frame_counter = (F32)ll_round(frame_counter); } // diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index 298640e747..5bcd717b6e 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -64,23 +64,43 @@ #include "llviewerstats.h" #include "pipeline.h" #include "llappviewer.h" +#include "llxuiparser.h" #include "llagent.h" #include "llviewerdisplay.h" +#include "llviewerwindow.h" +#include "llprogressview.h" #include "llflexibleobject.h" //////////////////////////////////////////////////////////////////////////// void (*LLViewerTextureList::sUUIDCallback)(void **, const LLUUID&) = NULL; -U32 LLViewerTextureList::sTextureBits = 0; +U32Bits LLViewerTextureList::sTextureBits(0); U32 LLViewerTextureList::sTexturePackets = 0; S32 LLViewerTextureList::sNumImages = 0; LLViewerTextureList gTextureList; -static LLFastTimer::DeclareTimer FTM_PROCESS_IMAGES("Process Images"); +static LLTrace::BlockTimerStatHandle FTM_PROCESS_IMAGES("Process Images"); + +ETexListType get_element_type(S32 priority) +{ + return (priority == LLViewerFetchedTexture::BOOST_ICON) ? TEX_LIST_SCALE : TEX_LIST_STANDARD; +} /////////////////////////////////////////////////////////////////////////////// +LLTextureKey::LLTextureKey() +: textureId(LLUUID::null), +textureType(TEX_LIST_STANDARD) +{ +} + +LLTextureKey::LLTextureKey(LLUUID id, ETexListType tex_type) +: textureId(id), textureType(tex_type) +{ +} + +/////////////////////////////////////////////////////////////////////////////// LLViewerTextureList::LLViewerTextureList() : mForceResetTextureStats(FALSE), mUpdateStats(FALSE), @@ -95,8 +115,8 @@ void LLViewerTextureList::init() mInitialized = TRUE ; sNumImages = 0; mUpdateStats = TRUE; - mMaxResidentTexMemInMegaBytes = 0; - mMaxTotalTextureMemInMegaBytes = 0 ; + mMaxResidentTexMemInMegaBytes = (U32Bytes)0; + mMaxTotalTextureMemInMegaBytes = (U32Bytes)0; if (gNoRender) { // Don't initialize GL stuff if we're not rendering. @@ -104,7 +124,7 @@ void LLViewerTextureList::init() } // Update how much texture RAM we're allowed to use. - updateMaxResidentTexMem(0); // 0 = use current + updateMaxResidentTexMem(S32Megabytes(0)); // 0 = use current doPreloadImages(); } @@ -117,15 +137,17 @@ void LLViewerTextureList::doPreloadImages() llassert_always(mInitialized) ; llassert_always(mImageList.empty()) ; llassert_always(mUUIDMap.empty()) ; + llassert_always(mUUIDDict.empty()); // Set the "missing asset" image - LLViewerFetchedTexture::sMissingAssetImagep = LLViewerTextureManager::getFetchedTextureFromFile("missing_asset.tga", MIPMAP_NO, LLViewerFetchedTexture::BOOST_UI); + LLViewerFetchedTexture::sMissingAssetImagep = LLViewerTextureManager::getFetchedTextureFromFile("missing_asset.tga", FTT_LOCAL_FILE, MIPMAP_NO, LLViewerFetchedTexture::BOOST_UI); // Set the "white" image - LLViewerFetchedTexture::sWhiteImagep = LLViewerTextureManager::getFetchedTextureFromFile("white.tga", MIPMAP_NO, LLViewerFetchedTexture::BOOST_UI); + LLViewerFetchedTexture::sWhiteImagep = LLViewerTextureManager::getFetchedTextureFromFile("white.tga", FTT_LOCAL_FILE, MIPMAP_NO, LLViewerFetchedTexture::BOOST_UI); LLTexUnit::sWhiteTexture = LLViewerFetchedTexture::sWhiteImagep->getTexName(); LLUIImageList* image_list = LLUIImageList::getInstance(); + LLViewerFetchedTexture::sFlatNormalImagep = LLViewerTextureManager::getFetchedTextureFromFile("flatnormal.tga", FTT_LOCAL_FILE, MIPMAP_NO, LLViewerFetchedTexture::BOOST_BUMP); image_list->initFromFile(); // turn off clamping and bilinear filtering for uv picking images @@ -137,42 +159,56 @@ void LLViewerTextureList::doPreloadImages() //uv_test->setMipFilterNearest(TRUE, TRUE); // prefetch specific UUIDs - LLViewerTextureManager::getFetchedTexture(IMG_SHOT, TRUE); - LLViewerTextureManager::getFetchedTexture(IMG_SMOKE_POOF, TRUE); - LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTextureFromFile("silhouette.j2c", MIPMAP_YES, LLViewerFetchedTexture::BOOST_UI); + LLViewerTextureManager::getFetchedTexture(IMG_SHOT); + LLViewerTextureManager::getFetchedTexture(IMG_SMOKE_POOF); + LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTextureFromFile("silhouette.j2c", FTT_LOCAL_FILE, MIPMAP_YES, LLViewerFetchedTexture::BOOST_UI); if (image) { image->setAddressMode(LLTexUnit::TAM_WRAP); mImagePreloads.insert(image); } - image = LLViewerTextureManager::getFetchedTextureFromFile("noentrylines.j2c"/*"world/NoEntryLines.png"*/, MIPMAP_YES, LLViewerFetchedTexture::BOOST_UI); + image = LLViewerTextureManager::getFetchedTextureFromFile("world/NoEntryLines.png", FTT_LOCAL_FILE, MIPMAP_YES, LLViewerFetchedTexture::BOOST_UI); if (image) { image->setAddressMode(LLTexUnit::TAM_WRAP); mImagePreloads.insert(image); } - image = LLViewerTextureManager::getFetchedTextureFromFile("noentrypasslines.j2c"/*"world/NoEntryPassLines.png"*/, MIPMAP_YES, LLViewerFetchedTexture::BOOST_UI); + image = LLViewerTextureManager::getFetchedTextureFromFile("world/NoEntryPassLines.png", FTT_LOCAL_FILE, MIPMAP_YES, LLViewerFetchedTexture::BOOST_UI); if (image) { image->setAddressMode(LLTexUnit::TAM_WRAP); mImagePreloads.insert(image); } - image = LLViewerTextureManager::getFetchedTexture(DEFAULT_WATER_NORMAL, MIPMAP_YES, LLViewerFetchedTexture::BOOST_UI); + image = LLViewerTextureManager::getFetchedTexture(DEFAULT_WATER_NORMAL, FTT_DEFAULT, MIPMAP_YES, LLViewerFetchedTexture::BOOST_UI); if (image) { image->setAddressMode(LLTexUnit::TAM_WRAP); mImagePreloads.insert(image); } - image = LLViewerTextureManager::getFetchedTextureFromFile("transparent.j2c", MIPMAP_YES, LLViewerFetchedTexture::BOOST_UI, LLViewerTexture::FETCHED_TEXTURE, + image = LLViewerTextureManager::getFetchedTextureFromFile("transparent.j2c", FTT_LOCAL_FILE, MIPMAP_YES, LLViewerFetchedTexture::BOOST_UI, LLViewerTexture::FETCHED_TEXTURE, 0,0,LLUUID("8dcd4a48-2d37-4909-9f78-f7a9eb4ef903")); if (image) { image->setAddressMode(LLTexUnit::TAM_WRAP); mImagePreloads.insert(image); } + image = LLViewerTextureManager::getFetchedTextureFromFile("transparent.j2c", FTT_LOCAL_FILE, MIPMAP_YES, LLViewerFetchedTexture::BOOST_UI, LLViewerTexture::FETCHED_TEXTURE, + 0,0,LLUUID("e97cf410-8e61-7005-ec06-629eba4cd1fb")); + if (image) + { + image->setAddressMode(LLTexUnit::TAM_WRAP); + mImagePreloads.insert(image); + } + image = LLViewerTextureManager::getFetchedTextureFromFile("transparent.j2c", FTT_LOCAL_FILE, MIPMAP_YES, LLViewerFetchedTexture::BOOST_UI, LLViewerTexture::FETCHED_TEXTURE, + 0,0,LLUUID("38b86f85-2575-52a9-a531-23108d8da837")); + if (image) + { + image->setAddressMode(LLTexUnit::TAM_WRAP); + mImagePreloads.insert(image); + } //Hideous hack to set filtering and address modes without messing with our texture classes. { - LLPointer temp_image = image_list->getUIImage("checkerboard.tga",LLViewerFetchedTexture::BOOST_UI); + LLPointer temp_image = image_list->getUIImage("checkerboard.tga", LLViewerFetchedTexture::BOOST_UI); if(temp_image.notNull() && temp_image->getImage().notNull()) { LLViewerTexture *tex = (LLViewerTexture*)temp_image->getImage().get(); @@ -185,7 +221,7 @@ void LLViewerTextureList::doPreloadImages() static std::string get_texture_list_name() { - return std::string("texture_list_") + gSavedSettings.getString("LoginLocation") + ".xml"; + return gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "texture_list_" + gSavedSettings.getString("LoginLocation") + ".xml"); } void LLViewerTextureList::doPrefetchImages() @@ -198,13 +234,22 @@ void LLViewerTextureList::doPrefetchImages() // Pre-fetch textures from last logout LLSD imagelist; - std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, get_texture_list_name()); + std::string filename = get_texture_list_name(); llifstream file; - file.open(filename); + file.open(filename.c_str()); if (file.is_open()) { - LLSDSerialize::fromXML(imagelist, file); - } + if ( ! LLSDSerialize::fromXML(imagelist, file) ) + { + file.close(); + LL_WARNS() << "XML parse error reading texture list '" << filename << "'" << LL_ENDL; + LL_WARNS() << "Removing invalid texture list '" << filename << "'" << LL_ENDL; + LLFile::remove(filename); + return; + } + file.close(); + } + S32 texture_count = 0; for (LLSD::array_iterator iter = imagelist.beginArray(); iter != imagelist.endArray(); ++iter) { @@ -215,13 +260,15 @@ void LLViewerTextureList::doPrefetchImages() if(LLViewerTexture::FETCHED_TEXTURE == texture_type || LLViewerTexture::LOD_TEXTURE == texture_type) { - LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture(uuid, MIPMAP_TRUE, LLGLTexture::BOOST_NONE, texture_type); + LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture(uuid, FTT_DEFAULT, MIPMAP_TRUE, LLGLTexture::BOOST_NONE, texture_type); if (image) { + texture_count += 1; image->addTextureStats((F32)pixel_area); } } } + LL_DEBUGS() << "fetched " << texture_count << " images from " << filename << LL_ENDL; } /////////////////////////////////////////////////////////////////////////////// @@ -242,11 +289,17 @@ void LLViewerTextureList::shutdown() iter != mImageList.end(); ++iter) { LLViewerFetchedTexture* image = *iter; + if (!(image->getType() == LLViewerTexture::FETCHED_TEXTURE || image->getType() == LLViewerTexture::LOD_TEXTURE) || + image->getFTType() != FTT_DEFAULT || + image->getID() == IMG_DEFAULT) + { + continue; + } if (!image->hasGLTexture() || !image->getUseDiscard() || - image->needsAux() || - image->getTargetHost() != LLHost::invalid || - !image->getUrl().empty() + image->needsAux()// || + //image->getTargetHost() != LLHost::invalid || + //!image->getUrl().empty() ) { continue; // avoid UI, baked, and other special images @@ -281,7 +334,7 @@ void LLViewerTextureList::shutdown() if (count > 0 && !gDirUtilp->getLindenUserDir(true).empty()) { - std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, get_texture_list_name()); + std::string filename = get_texture_list_name(); llofstream file; file.open(filename); LLSDSerialize::toPrettyXML(imagelist, file); @@ -297,6 +350,7 @@ void LLViewerTextureList::shutdown() mCreateTextureList.clear(); mUUIDMap.clear(); + mUUIDDict.clear(); mImageList.clear(); @@ -305,23 +359,24 @@ void LLViewerTextureList::shutdown() void LLViewerTextureList::dump() { - llinfos << "LLViewerTextureList::dump()" << llendl; + LL_INFOS() << "LLViewerTextureList::dump()" << LL_ENDL; for (image_priority_list_t::iterator it = mImageList.begin(); it != mImageList.end(); ++it) { LLViewerFetchedTexture* image = *it; - llinfos << "priority " << image->getDecodePriority() + LL_INFOS() << "priority " << image->getDecodePriority() << " boost " << image->getBoostLevel() << " size " << image->getWidth() << "x" << image->getHeight() << " discard " << image->getDiscardLevel() << " desired " << image->getDesiredDiscardLevel() << " http://asset.siva.lindenlab.com/" << image->getID() << ".texture" - << llendl; + << LL_ENDL; } } void LLViewerTextureList::destroyGL(BOOL save_state) { + clearFetchingRequests(); LLImageGL::destroyGL(save_state); } @@ -341,6 +396,7 @@ void LLViewerTextureList::restoreGL() /////////////////////////////////////////////////////////////////////////////// LLViewerFetchedTexture* LLViewerTextureList::getImageFromFile(const std::string& filename, + FTType f_type, BOOL usemipmaps, LLViewerTexture::EBoostLevel boost_priority, S8 texture_type, @@ -353,19 +409,29 @@ LLViewerFetchedTexture* LLViewerTextureList::getImageFromFile(const std::string& return NULL ; } - std::string full_path = gDirUtilp->findSkinnedFilename("textures", filename); - if (full_path.empty()) + // Singu Note: Detect if we were given a full path already, require being over a certain size, so we have more than just a path + bool full = filename.size() > +#ifdef LL_WINDOWS + 3 && filename.substr(1, 2) == ":\\"; // Drive letter comes first +#else + 1 && filename.front() == '/'; // delim is root +#endif + + std::string full_path = full ? filename : gDirUtilp->findSkinnedFilename("textures", filename); + if (full_path.empty() || (full && !gDirUtilp->fileExists(full_path))) { - llwarns << "Failed to find local image file: " << filename << llendl; - return LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT, TRUE, LLGLTexture::BOOST_UI); + LL_WARNS() << "Failed to find local image file: " << filename << LL_ENDL; + LLViewerTexture::EBoostLevel priority = LLGLTexture::BOOST_UI; + return LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT, FTT_DEFAULT, TRUE, priority); } std::string url = "file://" + full_path; - return getImageFromUrl(url, usemipmaps, boost_priority, texture_type, internal_format, primary_format, force_id); + return getImageFromUrl(url, f_type, usemipmaps, boost_priority, texture_type, internal_format, primary_format, force_id); } LLViewerFetchedTexture* LLViewerTextureList::getImageFromUrl(const std::string& url, + FTType f_type, BOOL usemipmaps, LLViewerTexture::EBoostLevel boost_priority, S8 texture_type, @@ -382,7 +448,7 @@ LLViewerFetchedTexture* LLViewerTextureList::getImageFromUrl(const std::string& { // Never mind that this ignores image_set_id; // getImage() will handle that later. - return LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT, TRUE, LLGLTexture::BOOST_UI); + return LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_UI); } // generate UUID based on hash of filename @@ -396,14 +462,14 @@ LLViewerFetchedTexture* LLViewerTextureList::getImageFromUrl(const std::string& new_id.generate(url); } - LLPointer imagep = findImage(new_id); + LLPointer imagep = findImage(new_id, get_element_type(boost_priority)); if (!imagep.isNull()) { LLViewerFetchedTexture *texture = imagep.get(); if (texture->getUrl().empty()) { - llwarns << "Requested texture " << new_id << " already exists but does not have a URL" << llendl; + LL_WARNS() << "Requested texture " << new_id << " already exists but does not have a URL" << LL_ENDL; } else if (texture->getUrl() != url) { @@ -411,7 +477,7 @@ LLViewerFetchedTexture* LLViewerTextureList::getImageFromUrl(const std::string& // e.g. could be two avatars wearing the same outfit. LL_DEBUGS("Avatar") << "Requested texture " << new_id << " already exists with a different url, requested: " << url - << " current: " << texture->getUrl() << llendl; + << " current: " << texture->getUrl() << LL_ENDL; } } @@ -420,13 +486,13 @@ LLViewerFetchedTexture* LLViewerTextureList::getImageFromUrl(const std::string& switch(texture_type) { case LLViewerTexture::FETCHED_TEXTURE: - imagep = new LLViewerFetchedTexture(url, new_id, usemipmaps); + imagep = new LLViewerFetchedTexture(url, f_type, new_id, usemipmaps); break ; case LLViewerTexture::LOD_TEXTURE: - imagep = new LLViewerLODTexture(url, new_id, usemipmaps); + imagep = new LLViewerLODTexture(url, f_type, new_id, usemipmaps); break ; default: - llerrs << "Invalid texture type " << texture_type << llendl ; + LL_ERRS() << "Invalid texture type " << texture_type << LL_ENDL ; } if (internal_format && primary_format) @@ -434,15 +500,21 @@ LLViewerFetchedTexture* LLViewerTextureList::getImageFromUrl(const std::string& imagep->setExplicitFormat(internal_format, primary_format); } - addImage(imagep); - + addImage(imagep, get_element_type(boost_priority)); + if (boost_priority != 0) { - if (boost_priority == LLViewerFetchedTexture::BOOST_UI || - boost_priority == LLViewerFetchedTexture::BOOST_ICON) + if (boost_priority == LLViewerFetchedTexture::BOOST_UI) { imagep->dontDiscard(); } + if (boost_priority == LLViewerFetchedTexture::BOOST_ICON) + { + // Agent and group Icons are downloadable content, nothing manages + // icon deletion yet, so they should not persist + imagep->dontDiscard(); + imagep->forceActive(); + } imagep->setBoostLevel(boost_priority); } } @@ -453,7 +525,8 @@ LLViewerFetchedTexture* LLViewerTextureList::getImageFromUrl(const std::string& } -LLViewerFetchedTexture* LLViewerTextureList::getImage(const LLUUID &image_id, +LLViewerFetchedTexture* LLViewerTextureList::getImage(const LLUUID &image_id, + FTType f_type, BOOL usemipmaps, LLViewerTexture::EBoostLevel boost_priority, S8 texture_type, @@ -472,30 +545,40 @@ LLViewerFetchedTexture* LLViewerTextureList::getImage(const LLUUID &image_id, if ((&image_id == NULL) || image_id.isNull()) { - return (LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT, TRUE, LLGLTexture::BOOST_UI)); + return (LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_UI)); } - LLPointer imagep = findImage(image_id); + LLPointer imagep = findImage(image_id, get_element_type(boost_priority)); if (!imagep.isNull()) { + if (boost_priority != LLViewerTexture::BOOST_ALM && imagep->getBoostLevel() == LLViewerTexture::BOOST_ALM) + { + // Workaround: we need BOOST_ALM texture for something, 'rise' to NONE + imagep->setBoostLevel(LLViewerTexture::BOOST_NONE); + } + LLViewerFetchedTexture *texture = imagep.get(); if (request_from_host.isOk() && !texture->getTargetHost().isOk()) { - llwarns << "Requested texture " << image_id << " already exists but does not have a host" << llendl; + LL_WARNS() << "Requested texture " << image_id << " already exists but does not have a host" << LL_ENDL; } else if (request_from_host.isOk() && texture->getTargetHost().isOk() && request_from_host != texture->getTargetHost()) { - llwarns << "Requested texture " << image_id << " already exists with a different target host, requested: " - << request_from_host << " current: " << texture->getTargetHost() << llendl; + LL_WARNS() << "Requested texture " << image_id << " already exists with a different target host, requested: " + << request_from_host << " current: " << texture->getTargetHost() << LL_ENDL; + } + if (f_type != FTT_DEFAULT && imagep->getFTType() != f_type) + { + LL_WARNS() << "FTType mismatch: requested " << f_type << " image has " << imagep->getFTType() << LL_ENDL; } } if (imagep.isNull()) { - imagep = createImage(image_id, usemipmaps, boost_priority, texture_type, internal_format, primary_format, request_from_host) ; + imagep = createImage(image_id, f_type, usemipmaps, boost_priority, texture_type, internal_format, primary_format, request_from_host) ; } imagep->setGLTextureCreated(true); @@ -505,6 +588,7 @@ LLViewerFetchedTexture* LLViewerTextureList::getImage(const LLUUID &image_id, //when this function is called, there is no such texture in the gTextureList with image_id. LLViewerFetchedTexture* LLViewerTextureList::createImage(const LLUUID &image_id, + FTType f_type, BOOL usemipmaps, LLViewerTexture::EBoostLevel boost_priority, S8 texture_type, @@ -516,28 +600,34 @@ LLViewerFetchedTexture* LLViewerTextureList::createImage(const LLUUID &image_id, switch(texture_type) { case LLViewerTexture::FETCHED_TEXTURE: - imagep = new LLViewerFetchedTexture(image_id, request_from_host, usemipmaps); + imagep = new LLViewerFetchedTexture(image_id, f_type, request_from_host, usemipmaps); break ; case LLViewerTexture::LOD_TEXTURE: - imagep = new LLViewerLODTexture(image_id, request_from_host, usemipmaps); + imagep = new LLViewerLODTexture(image_id, f_type, request_from_host, usemipmaps); break ; default: - llerrs << "Invalid texture type " << texture_type << llendl ; + LL_ERRS() << "Invalid texture type " << texture_type << LL_ENDL ; } if (internal_format && primary_format) { imagep->setExplicitFormat(internal_format, primary_format); } - - addImage(imagep); + + addImage(imagep, get_element_type(boost_priority)); if (boost_priority != 0) { - if (boost_priority == LLViewerFetchedTexture::BOOST_UI || - boost_priority == LLViewerFetchedTexture::BOOST_ICON) + if (boost_priority == LLViewerFetchedTexture::BOOST_UI) + { + imagep->dontDiscard(); + } + if (boost_priority == LLViewerFetchedTexture::BOOST_ICON) { + // Agent and group Icons are downloadable content, nothing manages + // icon deletion yet, so they should not persist. imagep->dontDiscard(); + imagep->forceActive(); } imagep->setBoostLevel(boost_priority); } @@ -552,12 +642,29 @@ LLViewerFetchedTexture* LLViewerTextureList::createImage(const LLUUID &image_id, return imagep ; } -LLViewerFetchedTexture *LLViewerTextureList::findImage(const LLUUID &image_id) +void LLViewerTextureList::findTexturesByID(const LLUUID &image_id, std::vector &output) { - uuid_map_t::iterator iter = mUUIDMap.find(image_id); - if(iter == mUUIDMap.end()) + LLTextureKey search_key(image_id, TEX_LIST_STANDARD); + uuid_map_t::iterator iter = mUUIDMap.lower_bound(search_key); + while (iter != mUUIDMap.end() && iter->first.textureId == image_id) + { + output.push_back(iter->second); + iter++; + } +} + +LLViewerFetchedTexture *LLViewerTextureList::findImage(const LLTextureKey &search_key) +{ + // Singu note: Reworked hotspot + const auto& iter = mUUIDDict.find(search_key); + if(iter == mUUIDDict.end()) return NULL; - return iter->second; + return iter->second; +} + +LLViewerFetchedTexture *LLViewerTextureList::findImage(const LLUUID &image_id, ETexListType tex_type) +{ + return findImage(LLTextureKey(image_id, tex_type)); } void LLViewerTextureList::addImageToList(LLViewerFetchedTexture *image) @@ -566,15 +673,17 @@ void LLViewerTextureList::addImageToList(LLViewerFetchedTexture *image) llassert_always(mInitialized) ; llassert(image); if (image->isInImageList()) - { - llerrs << "LLViewerTextureList::addImageToList - Image already in list" << llendl; + { // Flag is already set? + LL_WARNS() << "LLViewerTextureList::addImageToList - image " << image->getID() << " already in list" << LL_ENDL; } - if((mImageList.insert(image)).second != true) + else { - llerrs << "Error happens when insert image to mImageList!" << llendl ; + if((mImageList.insert(image)).second != true) + { + LL_WARNS() << "Error happens when insert image " << image->getID() << " into mImageList!" << LL_ENDL ; + } + image->setInImageList(TRUE) ; } - - image->setInImageList(TRUE) ; } void LLViewerTextureList::removeImageFromList(LLViewerFetchedTexture *image) @@ -582,45 +691,74 @@ void LLViewerTextureList::removeImageFromList(LLViewerFetchedTexture *image) assert_main_thread(); llassert_always(mInitialized) ; llassert(image); - if (!image->isInImageList()) + + S32 count = 0; + if (image->isInImageList()) { - llinfos << "RefCount: " << image->getNumRefs() << llendl ; - uuid_map_t::iterator iter = mUUIDMap.find(image->getID()); - if(iter == mUUIDMap.end() || iter->second != image) + count = mImageList.erase(image) ; + if(count != 1) + { + LL_INFOS() << "Image " << image->getID() + << " had mInImageList set but mImageList.erase() returned " << count + << LL_ENDL; + } + } + else + { // Something is wrong, image is expected in list or callers should check first + LL_INFOS() << "Calling removeImageFromList() for " << image->getID() + << " but doesn't have mInImageList set" + << " ref count is " << image->getNumRefs() + << LL_ENDL; + const auto& iter = mUUIDDict.find(LLTextureKey(image->getID(), (ETexListType)image->getTextureListType())); + if(iter == mUUIDDict.end()) { - llinfos << "Image is not in mUUIDMap!" << llendl ; + LL_INFOS() << "Image " << image->getID() << " is also not in mUUIDMap!" << LL_ENDL ; } - llerrs << "LLViewerTextureList::removeImageFromList - Image not in list" << llendl; + else if (iter->second != image) + { + LL_INFOS() << "Image " << image->getID() << " was in mUUIDMap but with different pointer" << LL_ENDL ; } - - S32 count = mImageList.erase(image) ; - if(count != 1) + else { - llinfos << image->getID() << llendl ; - llerrs << "Error happens when remove image from mImageList: " << count << llendl ; + LL_INFOS() << "Image " << image->getID() << " was in mUUIDMap with same pointer" << LL_ENDL ; + } + count = mImageList.erase(image) ; + if(count != 0) + { // it was in the list already? + LL_WARNS() << "Image " << image->getID() + << " had mInImageList false but mImageList.erase() returned " << count + << LL_ENDL; + } } image->setInImageList(FALSE) ; } -void LLViewerTextureList::addImage(LLViewerFetchedTexture *new_image) +void LLViewerTextureList::addImage(LLViewerFetchedTexture *new_image, ETexListType tex_type) { if (!new_image) { - llwarning("No image to add to image list", 0); + LL_WARNS() << "No image to add to image list" << LL_ENDL; return; } LLUUID image_id = new_image->getID(); + LLTextureKey key(image_id, tex_type); - LLViewerFetchedTexture *image = findImage(image_id); + LLViewerFetchedTexture *image = findImage(key); if (image) { - llwarns << "Image with ID " << image_id << " already in list" << llendl; + LL_INFOS() << "Image with ID " << image_id << " already in list" << LL_ENDL; } sNumImages++; addImageToList(new_image); - mUUIDMap[image_id] = new_image; + auto ret_pair = mUUIDMap.emplace(key, new_image); + if (!ret_pair.second) + { + ret_pair.first->second = new_image; + } + mUUIDDict.insert_or_assign(key, new_image); + new_image->setTextureListType(tex_type); } @@ -633,7 +771,9 @@ void LLViewerTextureList::deleteImage(LLViewerFetchedTexture *image) mCallbackList.erase(image); } - llverify(mUUIDMap.erase(image->getID()) == 1); + const LLTextureKey key(image->getID(), (ETexListType)image->getTextureListType()); + llverify(mUUIDMap.erase(key) == 1); + llverify(mUUIDDict.erase(key) == 1); sNumImages--; removeImageFromList(image); } @@ -650,13 +790,13 @@ void LLViewerTextureList::dirtyImage(LLViewerFetchedTexture *image) } //////////////////////////////////////////////////////////////////////////// -static LLFastTimer::DeclareTimer FTM_IMAGE_MARK_DIRTY("Dirty Images"); -static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE_PRIORITIES("Prioritize"); -static LLFastTimer::DeclareTimer FTM_IMAGE_CALLBACKS("Callbacks"); -static LLFastTimer::DeclareTimer FTM_IMAGE_FETCH("Fetch"); -static LLFastTimer::DeclareTimer FTM_IMAGE_CREATE("Create"); -static LLFastTimer::DeclareTimer FTM_IMAGE_STATS("Stats"); -static LLFastTimer::DeclareTimer FTM_IMAGE_MEDIA("Media"); +static LLTrace::BlockTimerStatHandle FTM_IMAGE_MARK_DIRTY("Dirty Images"); +static LLTrace::BlockTimerStatHandle FTM_IMAGE_UPDATE_PRIORITIES("Prioritize"); +static LLTrace::BlockTimerStatHandle FTM_IMAGE_CALLBACKS("Callbacks"); +static LLTrace::BlockTimerStatHandle FTM_IMAGE_FETCH("Fetch"); +static LLTrace::BlockTimerStatHandle FTM_IMAGE_CREATE("Create"); +static LLTrace::BlockTimerStatHandle FTM_IMAGE_STATS("Stats"); +static LLTrace::BlockTimerStatHandle FTM_IMAGE_MEDIA("Media"); void LLViewerTextureList::updateImages(F32 max_time) { @@ -673,7 +813,7 @@ void LLViewerTextureList::updateImages(F32 max_time) { if(!cleared) { - llinfos << "Flushing upon teleport." << llendl; + //LL_INFOS() << "flushing upon teleport." << LL_ENDL; clearFetchingRequests(); //gPipeline.clearRebuildGroups() really doesn't belong here... but since it is here, do a few other needed things too. gPipeline.clearRebuildGroups(); @@ -685,45 +825,45 @@ void LLViewerTextureList::updateImages(F32 max_time) } cleared = FALSE; - S32 global_raw_memory; + S64 global_raw_memory; { - global_raw_memory = *AIAccess(LLImageRaw::sGlobalRawMemory); + global_raw_memory = *AIAccess(LLImageRaw::sGlobalRawMemory); } LLViewerStats::getInstance()->mNumImagesStat.addValue(sNumImages); LLViewerStats::getInstance()->mNumRawImagesStat.addValue(LLImageRaw::sRawImageCount); - LLViewerStats::getInstance()->mGLTexMemStat.addValue((F32)BYTES_TO_MEGA_BYTES(LLImageGL::sGlobalTextureMemoryInBytes)); - LLViewerStats::getInstance()->mGLBoundMemStat.addValue((F32)BYTES_TO_MEGA_BYTES(LLImageGL::sBoundTextureMemoryInBytes)); + LLViewerStats::getInstance()->mGLTexMemStat.addValue((F32)LLImageGL::sGlobalTextureMemory.valueInUnits()); + LLViewerStats::getInstance()->mGLBoundMemStat.addValue((F32)LLImageGL::sBoundTextureMemory.valueInUnits()); LLViewerStats::getInstance()->mRawMemStat.addValue((F32)BYTES_TO_MEGA_BYTES(global_raw_memory)); LLViewerStats::getInstance()->mFormattedMemStat.addValue((F32)BYTES_TO_MEGA_BYTES(LLImageFormatted::sGlobalFormattedMemory)); { - LLFastTimer t(FTM_IMAGE_UPDATE_PRIORITIES); + LL_RECORD_BLOCK_TIME(FTM_IMAGE_UPDATE_PRIORITIES); updateImagesDecodePriorities(); } F32 total_max_time = max_time; { - LLFastTimer t(FTM_IMAGE_FETCH); + LL_RECORD_BLOCK_TIME(FTM_IMAGE_FETCH); max_time -= updateImagesFetchTextures(max_time); } { - LLFastTimer t(FTM_IMAGE_CREATE); + LL_RECORD_BLOCK_TIME(FTM_IMAGE_CREATE); max_time = llmax(max_time, total_max_time*.50f); // at least 50% of max_time max_time -= updateImagesCreateTextures(max_time); } if (!mDirtyTextureList.empty()) { - LLFastTimer t(FTM_IMAGE_MARK_DIRTY); + LL_RECORD_BLOCK_TIME(FTM_IMAGE_MARK_DIRTY); gPipeline.dirtyPoolObjectTextures(mDirtyTextureList); mDirtyTextureList.clear(); } { - LLFastTimer t(FTM_IMAGE_CALLBACKS); + LL_RECORD_BLOCK_TIME(FTM_IMAGE_CALLBACKS); bool didone = false; for (image_list_t::iterator iter = mCallbackList.begin(); iter != mCallbackList.end(); ) @@ -744,7 +884,7 @@ void LLViewerTextureList::updateImages(F32 max_time) } { - LLFastTimer t(FTM_IMAGE_STATS); + LL_RECORD_BLOCK_TIME(FTM_IMAGE_STATS); updateImagesUpdateStats(); } } @@ -770,31 +910,38 @@ void LLViewerTextureList::updateImagesDecodePriorities() { // Update the decode priority for N images each frame { + F32 lazy_flush_timeout = 30.f; // stop decoding + F32 max_inactive_time = 20.f; // actually delete + S32 min_refs = 3; // 1 for mImageList, 1 for mUUIDMap, 1 for local reference + + //reset imagep->getLastReferencedTimer() when screen is showing the progress view to avoid removing pre-fetched textures too soon. + bool reset_timer = gViewerWindow->getProgressView()->getVisible(); + static const S32 MAX_PRIO_UPDATES = gSavedSettings.getS32("TextureFetchUpdatePriorities"); // default: 32 const size_t max_update_count = llmin((S32) (MAX_PRIO_UPDATES*MAX_PRIO_UPDATES*gFrameIntervalSeconds) + 1, MAX_PRIO_UPDATES); S32 update_counter = llmin(max_update_count, mUUIDMap.size()); - uuid_map_t::iterator iter = mUUIDMap.upper_bound(mLastUpdateUUID); + uuid_map_t::iterator iter = mUUIDMap.upper_bound(mLastUpdateKey); while ((update_counter-- > 0) && !mUUIDMap.empty()) { if (iter == mUUIDMap.end()) { iter = mUUIDMap.begin(); } - mLastUpdateUUID = iter->first; + mLastUpdateKey = iter->first; LLPointer imagep = iter->second; ++iter; // safe to incrament now // // Flush formatted images using a lazy flush // - const F32 LAZY_FLUSH_TIMEOUT = 30.f; // stop decoding - const F32 MAX_INACTIVE_TIME = 50.f; // actually delete - S32 min_refs = 3; // 1 for mImageList, 1 for mUUIDMap, 1 for local reference - S32 num_refs = imagep->getNumRefs(); if (num_refs == min_refs) { - if (imagep->getLastReferencedTimer()->getElapsedTimeF32() > LAZY_FLUSH_TIMEOUT) + if(reset_timer) + { + imagep->getLastReferencedTimer()->reset(); + } + else if (imagep->getLastReferencedTimer()->getElapsedTimeF32() > lazy_flush_timeout) { // Remove the unused image from the image list deleteImage(imagep); @@ -806,7 +953,7 @@ void LLViewerTextureList::updateImagesDecodePriorities() { if(imagep->hasSavedRawImage()) { - if(imagep->getElapsedLastReferencedSavedRawImageTime() > MAX_INACTIVE_TIME) + if(imagep->getElapsedLastReferencedSavedRawImageTime() > max_inactive_time) { imagep->destroySavedRawImage() ; } @@ -823,7 +970,11 @@ void LLViewerTextureList::updateImagesDecodePriorities() } else if(imagep->isInactive()) { - if (imagep->getLastReferencedTimer()->getElapsedTimeF32() > MAX_INACTIVE_TIME) + if(reset_timer) + { + imagep->getLastReferencedTimer()->reset(); + } + else if (imagep->getLastReferencedTimer()->getElapsedTimeF32() > max_inactive_time) { imagep->setDeletionCandidate() ; } @@ -875,11 +1026,11 @@ void LLViewerTextureList::updateImagesDecodePriorities() if (type_from_host == LLImageBase::TYPE_NORMAL && type_from_boost == LLImageBase::TYPE_AVATAR_BAKE) { - llwarns << "TAT: get_image_type() type_from_host doesn't match type_from_boost" + LL_WARNS() << "TAT: get_image_type() type_from_host doesn't match type_from_boost" << " host " << target_host << " boost " << imagep->getBoostLevel() << " imageid " << imagep->getID() - << llendl; + << LL_ENDL; imagep->dump(); } return type_from_host; @@ -894,7 +1045,7 @@ F32 LLViewerTextureList::updateImagesCreateTextures(F32 max_time) // Create GL textures for all textures that need them (images which have been // decoded, but haven't been pushed into GL). // - LLFastTimer t(FTM_IMAGE_CREATE); + LL_RECORD_BLOCK_TIME(FTM_IMAGE_CREATE); LLTimer create_timer; image_list_t::iterator enditer = mCreateTextureList.begin(); @@ -945,12 +1096,10 @@ F32 LLViewerTextureList::updateImagesFetchTextures(F32 max_time) static const bool SKIP_LOW_PRIO = gSavedSettings.getBOOL("TextureFetchUpdateSkipLowPriority"); // default: false size_t max_priority_count = llmin((S32) (MAX_HIGH_PRIO_COUNT*MAX_HIGH_PRIO_COUNT*gFrameIntervalSeconds)+1, MAX_HIGH_PRIO_COUNT); - //Old: size_t max_priority_count = llmin((S32) (MAX_HIGH_PRIO_COUNT*40.f*gFrameIntervalSeconds)+1, MAX_HIGH_PRIO_COUNT); max_priority_count = llmin(max_priority_count, mImageList.size()); size_t total_update_count = mUUIDMap.size(); size_t max_update_count = llmin((S32) (MAX_UPDATE_COUNT*MAX_UPDATE_COUNT*gFrameIntervalSeconds)+1, MAX_UPDATE_COUNT); - //Old: size_t max_priority_count = llmin((S32) (MAX_UPDATE_COUNT*40.f*gFrameIntervalSeconds)+1, MAX_UPDATE_COUNT); max_update_count = llmin(max_update_count, total_update_count); // MAX_HIGH_PRIO_COUNT high priority entries @@ -970,7 +1119,7 @@ F32 LLViewerTextureList::updateImagesFetchTextures(F32 max_time) update_counter = max_update_count; if(update_counter > 0) { - uuid_map_t::iterator iter2 = mUUIDMap.upper_bound(mLastFetchUUID); + uuid_map_t::iterator iter2 = mUUIDMap.upper_bound(mLastFetchKey); while ((update_counter > 0) && (total_update_count > 0)) { if (iter2 == mUUIDMap.end()) @@ -1000,7 +1149,7 @@ F32 LLViewerTextureList::updateImagesFetchTextures(F32 max_time) fetch_count += (imagep->updateFetch() ? 1 : 0); if (min_count <= (S32)min_update_count) { - mLastFetchUUID = imagep->getID(); + mLastFetchKey = LLTextureKey(imagep->getID(), (ETexListType)imagep->getTextureListType()); } if ((min_count-- <= 0) && (image_op_timer.getElapsedTimeF32() > max_time)) { @@ -1124,13 +1273,13 @@ BOOL LLViewerTextureList::createUploadFile(const std::string& filename, if (compressedImage.isNull()) { LLImage::setLastError("Couldn't convert the image to jpeg2000."); - llinfos << "Couldn't convert to j2c, file : " << filename << llendl; + LL_INFOS() << "Couldn't convert to j2c, file : " << filename << LL_ENDL; return FALSE; } if (!compressedImage->save(out_filename)) { LLImage::setLastError("Couldn't create the jpeg2000 image for upload."); - llinfos << "Couldn't create output file : " << out_filename << llendl; + LL_INFOS() << "Couldn't create output file : " << out_filename << LL_ENDL; return FALSE; } return verifyUploadFile(out_filename, codec); @@ -1148,7 +1297,7 @@ BOOL LLViewerTextureList::verifyUploadFile(const std::string& out_filename, cons if (!integrity_test->loadAndValidate( out_filename )) { LLImage::setLastError(std::string("The ") + ((codec == IMG_CODEC_J2C) ? "" : "created ") + "jpeg2000 image is corrupt: " + LLImage::getLastError()); - llinfos << "Image file : " << out_filename << " is corrupt" << llendl; + LL_INFOS() << "Image file : " << out_filename << " is corrupt" << LL_ENDL; return FALSE; } if (codec == IMG_CODEC_J2C) @@ -1188,13 +1337,13 @@ LLPointer LLViewerTextureList::convertToUploadFile(LLPointer LLViewerTextureList::convertToUploadFile(LLPointer 2000) - return 128; - else if (system_ram > 1000) - return 64; - else - return MIN_VIDEO_RAM_IN_MEGA_BYTES; + S32Megabytes system_ram = gSysMemory.getPhysicalMemoryKB(); + //LL_INFOS() << system_ram << LL_ENDL; + //min texture mem sets to 64M if total physical mem is more than 1.5GB + return (system_ram > S32Megabytes(1500)) ? S32Megabytes(64) : gMinVideoRam ; } //static // Returns max setting for TextureMemory (in MB) -S32 LLViewerTextureList::getMaxVideoRamSetting(bool get_recommended) +S32Megabytes LLViewerTextureList::getMaxVideoRamSetting(bool get_recommended, float mem_multiplier) { - S32 max_texmem; +#if LL_LINUX + if (gGLManager.mIsIntel && gGLManager.mGLVersion >= 3.f && !gGLManager.mVRAM) + { + gGLManager.mVRAM = 512; + } +#endif + S32Megabytes max_texmem; if (gGLManager.mVRAM != 0) { // Treat any card with < 32 MB (shudder) as having 32 MB // - it's going to be swapping constantly regardless - S32 max_vram = gGLManager.mVRAM; + S32Megabytes max_vram(gGLManager.mVRAM); max_vram = llmax(max_vram, getMinVideoRamSetting()); max_texmem = max_vram; if (!get_recommended) @@ -1231,80 +1383,75 @@ S32 LLViewerTextureList::getMaxVideoRamSetting(bool get_recommended) } else { - if (get_recommended) - max_texmem = 128; + if (!get_recommended) + { + max_texmem = S32Megabytes(512); + } + else if (gSavedSettings.getBOOL("NoHardwareProbe")) //did not do hardware detection at startup + { + max_texmem = S32Megabytes(512); + } else - max_texmem = 512; - llwarns << "VRAM amount not detected, defaulting to " << max_texmem << " MB" << llendl; + { + max_texmem = S32Megabytes(128); + } + + LL_WARNS() << "VRAM amount not detected, defaulting to " << max_texmem << " MB" << LL_ENDL; } - S32 system_ram = (S32)BYTES_TO_MEGA_BYTES(gSysMemory.getPhysicalMemoryClamped()); // In MB - //llinfos << "*** DETECTED " << system_ram << " MB of system memory." << llendl; + S32Megabytes system_ram = gSysMemory.getPhysicalMemoryKB(); // In MB + LL_INFOS() << "get_recommended: " << get_recommended << LL_ENDL; + LL_INFOS() << "system_ram: " << system_ram << LL_ENDL; + LL_INFOS() << "max_texmem: " << max_texmem << LL_ENDL; if (get_recommended) - max_texmem = llmin(max_texmem, (S32)(system_ram/2)); + max_texmem = llmin(S32Megabytes(max_texmem * .7f), system_ram/2); else - max_texmem = llmin(max_texmem, (S32)(system_ram)); - - max_texmem = llclamp(max_texmem, getMinVideoRamSetting(), MAX_VIDEO_RAM_IN_MEGA_BYTES); + max_texmem = llmin(max_texmem, system_ram); + + // limit the texture memory to a multiple of the default if we've found some cards to behave poorly otherwise + max_texmem = llmin(max_texmem, (S32Megabytes) (mem_multiplier * max_texmem)); + + max_texmem = llclamp(max_texmem, getMinVideoRamSetting(), gMaxVideoRam); return max_texmem; } -const S32 VIDEO_CARD_FRAMEBUFFER_MEM = 12; // MB -const S32 MIN_MEM_FOR_NON_TEXTURE = 512 ; //MB -void LLViewerTextureList::updateMaxResidentTexMem(S32 mem) +const S32Megabytes VIDEO_CARD_FRAMEBUFFER_MEM_MIN(12); +const S32Megabytes VIDEO_CARD_FRAMEBUFFER_MEM_MAX(512); +const S32Megabytes MIN_MEM_FOR_NON_TEXTURE(16); +void LLViewerTextureList::updateMaxResidentTexMem(S32Megabytes mem) { // Initialize the image pipeline VRAM settings - S32 cur_mem = gSavedSettings.getS32("TextureMemory"); - F32 mem_multiplier = gSavedSettings.getF32("RenderTextureMemoryMultiple"); - S32 default_mem = getMaxVideoRamSetting(true); // recommended default + const S32Megabytes cur_mem(gSavedSettings.getS32("TextureMemory")); + const F32 mem_multiplier = gSavedSettings.getF32("RenderTextureMemoryMultiple"); + const S32Megabytes default_mem = getMaxVideoRamSetting(true, mem_multiplier); // recommended default + const S32Megabytes max_mem = getMaxVideoRamSetting(false, mem_multiplier); + const S32Megabytes min_mem = getMinVideoRamSetting(); + if (mem == 0) { - mem = cur_mem > 0 ? cur_mem : default_mem; + mem = cur_mem > (S32Bytes)0 ? cur_mem : default_mem; } else if (mem < 0) { mem = default_mem; } - // limit the texture memory to a multiple of the default if we've found some cards to behave poorly otherwise - mem = llmin(mem, (S32) (mem_multiplier * (F32) default_mem)); - - mem = llclamp(mem, getMinVideoRamSetting(), getMaxVideoRamSetting()); - if (mem != cur_mem) + S32Megabytes reported_mem = llclamp(mem, min_mem, max_mem); + if (reported_mem != cur_mem) { - gSavedSettings.setS32("TextureMemory", mem); + gSavedSettings.setS32("TextureMemory", reported_mem.value()); return; //listener will re-enter this function } - // TODO: set available resident texture mem based on use by other subsystems - // currently max(12MB, VRAM/4) assumed... - - S32 vb_mem = mem; - S32 fb_mem = llmax(VIDEO_CARD_FRAMEBUFFER_MEM, vb_mem/4); - mMaxResidentTexMemInMegaBytes = (vb_mem - fb_mem) ; //in MB - - mMaxTotalTextureMemInMegaBytes = mMaxResidentTexMemInMegaBytes * 2; - if (mMaxResidentTexMemInMegaBytes > 640) - { - mMaxTotalTextureMemInMegaBytes -= (mMaxResidentTexMemInMegaBytes >> 2); - } - - //system mem - S32 system_ram = (S32)BYTES_TO_MEGA_BYTES(gSysMemory.getPhysicalMemoryClamped()); // In MB + S32Megabytes fb_mem = llmin(llmax(VIDEO_CARD_FRAMEBUFFER_MEM_MIN, mem / 4), VIDEO_CARD_FRAMEBUFFER_MEM_MAX); // 25% for framebuffers. + S32Megabytes misc_mem = llmax(MIN_MEM_FOR_NON_TEXTURE, mem / 5); // 20% for misc. - //minimum memory reserved for non-texture use. - //if system_raw >= 1GB, reserve at least 512MB for non-texture use; - //otherwise reserve half of the system_ram for non-texture use. - S32 min_non_texture_mem = llmin(system_ram / 2, MIN_MEM_FOR_NON_TEXTURE) ; + mMaxTotalTextureMemInMegaBytes = llmin(mem - misc_mem, max_mem); + mMaxResidentTexMemInMegaBytes = llmin(mem - misc_mem - fb_mem, max_mem); - if (mMaxTotalTextureMemInMegaBytes > system_ram - min_non_texture_mem) - { - mMaxTotalTextureMemInMegaBytes = system_ram - min_non_texture_mem ; - } - - llinfos << "Total Video Memory set to: " << vb_mem << " MB" << llendl; - llinfos << "Available Texture Memory set to: " << (vb_mem - fb_mem) << " MB" << llendl; + LL_INFOS() << "Available Texture Memory set to: " << mMaxResidentTexMemInMegaBytes << LL_ENDL; + LL_INFOS() << "Total Texture Memory set to: " << mMaxTotalTextureMemInMegaBytes << LL_ENDL; } /////////////////////////////////////////////////////////////////////////////// @@ -1314,7 +1461,7 @@ void LLViewerTextureList::receiveImageHeader(LLMessageSystem *msg, void **user_d { static LLCachedControl log_texture_traffic(gSavedSettings,"LogTextureNetworkTraffic") ; - LLFastTimer t(FTM_PROCESS_IMAGES); + LL_RECORD_BLOCK_TIME(FTM_PROCESS_IMAGES); // Receive image header, copy into image object and decompresses // if this is a one-packet image. @@ -1324,17 +1471,17 @@ void LLViewerTextureList::receiveImageHeader(LLMessageSystem *msg, void **user_d char ip_string[256]; u32_to_ip_string(msg->getSenderIP(),ip_string); - U32 received_size ; + U32Bytes received_size ; if (msg->getReceiveCompressedSize()) { - received_size = msg->getReceiveCompressedSize() ; + received_size = (U32Bytes)msg->getReceiveCompressedSize() ; } else { - received_size = msg->getReceiveSize() ; + received_size = (U32Bytes)msg->getReceiveSize() ; } // Only used for statistics and texture console. - gTextureList.sTextureBits += received_size * 8; + gTextureList.sTextureBits += received_size; gTextureList.sTexturePackets++; U8 codec; @@ -1354,8 +1501,8 @@ void LLViewerTextureList::receiveImageHeader(LLMessageSystem *msg, void **user_d { // msg->getSizeFast() is probably trying to tell us there // was an error. - llerrs << "image header chunk size was negative: " - << data_size << llendl; + LL_ERRS() << "image header chunk size was negative: " + << data_size << LL_ENDL; return; } @@ -1363,7 +1510,7 @@ void LLViewerTextureList::receiveImageHeader(LLMessageSystem *msg, void **user_d U8 *data = new U8[data_size]; msg->getBinaryDataFast(_PREHASH_ImageData, _PREHASH_Data, data, data_size); - LLViewerFetchedTexture *image = LLViewerTextureManager::getFetchedTexture(id, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); + LLViewerFetchedTexture *image = LLViewerTextureManager::getFetchedTexture(id, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); if (!image) { delete [] data; @@ -1387,7 +1534,7 @@ void LLViewerTextureList::receiveImagePacket(LLMessageSystem *msg, void **user_d { static LLCachedControl log_texture_traffic(gSavedSettings,"LogTextureNetworkTraffic") ; - LLFastTimer t(FTM_PROCESS_IMAGES); + LL_RECORD_BLOCK_TIME(FTM_PROCESS_IMAGES); // Receives image packet, copy into image object, // checks if all packets received, decompresses if so. @@ -1398,16 +1545,16 @@ void LLViewerTextureList::receiveImagePacket(LLMessageSystem *msg, void **user_d char ip_string[256]; u32_to_ip_string(msg->getSenderIP(),ip_string); - U32 received_size ; + U32Bytes received_size ; if (msg->getReceiveCompressedSize()) { - received_size = msg->getReceiveCompressedSize() ; + received_size = (U32Bytes)msg->getReceiveCompressedSize() ; } else { - received_size = msg->getReceiveSize() ; + received_size = (U32Bytes)msg->getReceiveSize() ; } - gTextureList.sTextureBits += received_size * 8; + gTextureList.sTextureBits += received_size; gTextureList.sTexturePackets++; //llprintline("Start decode, image header..."); @@ -1423,19 +1570,19 @@ void LLViewerTextureList::receiveImagePacket(LLMessageSystem *msg, void **user_d { // msg->getSizeFast() is probably trying to tell us there // was an error. - llerrs << "image data chunk size was negative: " - << data_size << llendl; + LL_ERRS() << "image data chunk size was negative: " + << data_size << LL_ENDL; return; } if (data_size > MTUBYTES) { - llerrs << "image data chunk too large: " << data_size << " bytes" << llendl; + LL_ERRS() << "image data chunk too large: " << data_size << " bytes" << LL_ENDL; return; } U8 *data = new U8[data_size]; msg->getBinaryDataFast(_PREHASH_ImageData, _PREHASH_Data, data, data_size); - LLViewerFetchedTexture *image = LLViewerTextureManager::getFetchedTexture(id, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); + LLViewerFetchedTexture *image = LLViewerTextureManager::getFetchedTexture(id, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); if (!image) { delete [] data; @@ -1459,35 +1606,26 @@ void LLViewerTextureList::receiveImagePacket(LLMessageSystem *msg, void **user_d // static void LLViewerTextureList::processImageNotInDatabase(LLMessageSystem *msg,void **user_data) { - LLFastTimer t(FTM_PROCESS_IMAGES); + LL_RECORD_BLOCK_TIME(FTM_PROCESS_IMAGES); LLUUID image_id; msg->getUUIDFast(_PREHASH_ImageID, _PREHASH_ID, image_id); - LLViewerFetchedTexture* image = gTextureList.findImage( image_id ); + LLViewerFetchedTexture* image = gTextureList.findImage( image_id, TEX_LIST_STANDARD); if( image ) { + LL_WARNS() << "Image not in db" << LL_ENDL; image->setIsMissingAsset(); } -} - -/////////////////////////////////////////////////////////////////////////////// -//static -const U32 SIXTEEN_MEG = 0x1000000; -S32 LLViewerTextureList::calcMaxTextureRAM() -{ - // Decide the maximum amount of RAM we should allow the user to allocate to texture cache - LLMemoryInfo memory_info; - U32 available_memory = memory_info.getPhysicalMemoryClamped(); - - clamp_rescale((F32)available_memory, - (F32)(SIXTEEN_MEG * 16), - (F32)U32_MAX, - (F32)(SIXTEEN_MEG * 4), - (F32)(U32_MAX >> 1)); - return available_memory; + image = gTextureList.findImage(image_id, TEX_LIST_SCALE); + if (image) + { + LL_WARNS() << "Icon not in db" << LL_ENDL; + image->setIsMissingAsset(); + } } + /////////////////////////////////////////////////////////////////////////////// // explicitly cleanup resources, as this is a singleton class with process @@ -1533,28 +1671,31 @@ LLUIImagePtr LLUIImageList::getUIImage(const std::string& image_name, S32 priori } LLUIImagePtr LLUIImageList::loadUIImageByName(const std::string& name, const std::string& filename, - BOOL use_mips, const LLRect& scale_rect, const LLRect& clip_rect, LLViewerTexture::EBoostLevel boost_priority ) + BOOL use_mips, const LLRect& scale_rect, const LLRect& clip_rect, LLViewerTexture::EBoostLevel boost_priority, + LLUIImage::EScaleStyle scale_style) { if (boost_priority == LLGLTexture::BOOST_NONE) { boost_priority = LLGLTexture::BOOST_UI; } - LLViewerFetchedTexture* imagep = LLViewerTextureManager::getFetchedTextureFromFile(filename, MIPMAP_NO, boost_priority); - return loadUIImage(imagep, name, use_mips, scale_rect, clip_rect); + LLViewerFetchedTexture* imagep = LLViewerTextureManager::getFetchedTextureFromFile(filename, FTT_LOCAL_FILE, MIPMAP_NO, boost_priority); + return loadUIImage(imagep, name, use_mips, scale_rect, clip_rect, scale_style); } LLUIImagePtr LLUIImageList::loadUIImageByID(const LLUUID& id, - BOOL use_mips, const LLRect& scale_rect, const LLRect& clip_rect, LLViewerTexture::EBoostLevel boost_priority) + BOOL use_mips, const LLRect& scale_rect, const LLRect& clip_rect, LLViewerTexture::EBoostLevel boost_priority, + LLUIImage::EScaleStyle scale_style) { if (boost_priority == LLGLTexture::BOOST_NONE) { boost_priority = LLGLTexture::BOOST_UI; } - LLViewerFetchedTexture* imagep = LLViewerTextureManager::getFetchedTexture(id, MIPMAP_NO, boost_priority); - return loadUIImage(imagep, id.asString(), use_mips, scale_rect, clip_rect); + LLViewerFetchedTexture* imagep = LLViewerTextureManager::getFetchedTexture(id, FTT_DEFAULT, MIPMAP_NO, boost_priority); + return loadUIImage(imagep, id.asString(), use_mips, scale_rect, clip_rect, scale_style); } -LLUIImagePtr LLUIImageList::loadUIImage(LLViewerFetchedTexture* imagep, const std::string& name, BOOL use_mips, const LLRect& scale_rect, const LLRect& clip_rect) +LLUIImagePtr LLUIImageList::loadUIImage(LLViewerFetchedTexture* imagep, const std::string& name, BOOL use_mips, const LLRect& scale_rect, const LLRect& clip_rect, + LLUIImage::EScaleStyle scale_style) { if (!imagep) return NULL; @@ -1563,12 +1704,18 @@ LLUIImagePtr LLUIImageList::loadUIImage(LLViewerFetchedTexture* imagep, const st //don't compress UI images imagep->getGLTexture()->setAllowCompression(false); - //all UI images are non-deletable - imagep->setNoDelete(); - LLUIImagePtr new_imagep = new LLUIImage(name, imagep); - mUIImages.insert(std::make_pair(name, new_imagep)); - mUITextureList.push_back(imagep); + new_imagep->setScaleStyle(scale_style); + + if (imagep->getBoostLevel() != LLGLTexture::BOOST_ICON && + imagep->getBoostLevel() != LLGLTexture::BOOST_PREVIEW) + { + // Don't add downloadable content into this list + // all UI images are non-deletable and list does not support deletion + imagep->setNoDelete(); + mUIImages.insert(std::make_pair(name, new_imagep)); + mUITextureList.push_back(imagep); + } //Note: //Some other textures such as ICON also through this flow to be fetched. @@ -1585,17 +1732,17 @@ LLUIImagePtr LLUIImageList::loadUIImage(LLViewerFetchedTexture* imagep, const st return new_imagep; } -LLUIImagePtr LLUIImageList::preloadUIImage(const std::string& name, const std::string& filename, BOOL use_mips, const LLRect& scale_rect, const LLRect& clip_rect) +LLUIImagePtr LLUIImageList::preloadUIImage(const std::string& name, const std::string& filename, BOOL use_mips, const LLRect& scale_rect, const LLRect& clip_rect, LLUIImage::EScaleStyle scale_style) { // look for existing image uuid_ui_image_map_t::iterator found_it = mUIImages.find(name); if (found_it != mUIImages.end()) { // image already loaded! - llerrs << "UI Image " << name << " already loaded." << llendl; + LL_ERRS() << "UI Image " << name << " already loaded." << LL_ENDL; } - return loadUIImageByName(name, filename, use_mips, scale_rect, clip_rect); + return loadUIImageByName(name, filename, use_mips, scale_rect, clip_rect, LLGLTexture::BOOST_UI, scale_style); } //static @@ -1655,20 +1802,37 @@ void LLUIImageList::onUIImageLoaded( BOOL success, LLViewerFetchedTexture *src_v } } -/*struct UIImageDeclaration : public LLInitParam::Block +namespace LLInitParam { - Mandatory name; - Optional file_name; - Optional preload; - Optional scale; - Optional use_mips; + template<> + struct TypeValues : public TypeValuesHelper + { + static void declareValues() + { + declare("scale_inner", LLUIImage::SCALE_INNER); + declare("scale_outer", LLUIImage::SCALE_OUTER); + } + }; +} + +struct UIImageDeclaration : public LLInitParam::Block +{ + Mandatory name; + Optional file_name; + Optional preload; + Optional scale; + Optional clip; + Optional use_mips; + Optional scale_type; UIImageDeclaration() : name("name"), file_name("file_name"), preload("preload", false), scale("scale"), - use_mips("use_mips", false) + clip("clip"), + use_mips("use_mips", false), + scale_type("scale_type", LLUIImage::SCALE_INNER) {} }; @@ -1685,49 +1849,43 @@ struct UIImageDeclarations : public LLInitParam::Block bool LLUIImageList::initFromFile() { - // construct path to canonical textures.xml in default skin dir - std::string base_file_path = gDirUtilp->getExpandedFilename(LL_PATH_SKINS, "default", "textures", "textures.xml"); + // Look for textures.xml in all the right places. Pass + // constraint=LLDir::ALL_SKINS because we want to overlay textures.xml + // from all the skins directories. + std::vector textures_paths = + gDirUtilp->findSkinnedFilenames(LLDir::TEXTURES, "textures.xml", LLDir::ALL_SKINS); + std::vector::const_iterator pi(textures_paths.begin()), pend(textures_paths.end()); + if (pi == pend) + { + LL_WARNS() << "No textures.xml found in skins directories" << LL_ENDL; + return false; + } + // The first (most generic) file gets special validations LLXMLNodePtr root; - - if (!LLXMLNode::parseFile(base_file_path, root, NULL)) + if (!LLXMLNode::parseFile(*pi, root, NULL)) { - llwarns << "Unable to parse UI image list file " << base_file_path << llendl; + LL_WARNS() << "Unable to parse UI image list file " << *pi << LL_ENDL; return false; } if (!root->hasAttribute("version")) { - llwarns << "No valid version number in UI image list file " << base_file_path << llendl; + LL_WARNS() << "No valid version number in UI image list file " << *pi << LL_ENDL; return false; } UIImageDeclarations images; LLXUIParser parser; - parser.readXUI(root, images, base_file_path); + parser.readXUI(root, images, *pi); - // add components defined in current skin - std::string skin_update_path = gDirUtilp->getSkinDir() - + gDirUtilp->getDirDelimiter() - + "textures" - + gDirUtilp->getDirDelimiter() - + "textures.xml"; - LLXMLNodePtr update_root; - if (skin_update_path != base_file_path - && LLXMLNode::parseFile(skin_update_path, update_root, NULL)) + // add components defined in the rest of the skin paths + while (++pi != pend) { - parser.readXUI(update_root, images, skin_update_path); - } - - // add components defined in user override of current skin - skin_update_path = gDirUtilp->getUserSkinDir() - + gDirUtilp->getDirDelimiter() - + "textures" - + gDirUtilp->getDirDelimiter() - + "textures.xml"; - if (skin_update_path != base_file_path - && LLXMLNode::parseFile(skin_update_path, update_root, NULL)) - { - parser.readXUI(update_root, images, skin_update_path); + LLXMLNodePtr update_root; + if (LLXMLNode::parseFile(*pi, update_root, NULL)) + { + parser.readXUI(update_root, images, *pi); + } } if (!images.validateBlock()) return false; @@ -1762,7 +1920,7 @@ bool LLUIImageList::initFromFile() { continue; } - preloadUIImage(image.name, file_name, image.use_mips, image.scale); + preloadUIImage(image.name, file_name, image.use_mips, image.scale, image.clip, image.scale_type); } if (cur_pass == PASS_DECODE_NOW && !gSavedSettings.getBOOL("NoPreload")) @@ -1771,115 +1929,6 @@ bool LLUIImageList::initFromFile() } } return true; -}*/ -bool LLUIImageList::initFromFile() -{ - // construct path to canonical textures.xml in default skin dir - std::string base_file_path = gDirUtilp->getExpandedFilename(LL_PATH_SKINS, "default", "textures", "textures.xml"); - - LLXMLNodePtr root; - - if (!LLXMLNode::parseFile(base_file_path, root, NULL)) - { - llwarns << "Unable to parse UI image list file " << base_file_path << llendl; - return false; - } - - if (!root->hasAttribute("version")) - { - llwarns << "No valid version number in UI image list file " << base_file_path << llendl; - return false; - } - - std::vector paths; - // path to current selected skin - paths.push_back(gDirUtilp->getSkinDir() - + gDirUtilp->getDirDelimiter() - + "textures" - + gDirUtilp->getDirDelimiter() - + "textures.xml"); - // path to user overrides on current skin - paths.push_back(gDirUtilp->getUserSkinDir() - + gDirUtilp->getDirDelimiter() - + "textures" - + gDirUtilp->getDirDelimiter() - + "textures.xml"); - - // apply skinned xml files incrementally - for(std::vector::iterator path_it = paths.begin(); - path_it != paths.end(); - ++path_it) - { - // don't reapply base file to itself - if (!path_it->empty() && (*path_it) != base_file_path) - { - LLXMLNodePtr update_root; - if (LLXMLNode::parseFile(*path_it, update_root, NULL)) - { - LLXMLNode::updateNode(root, update_root); - } - } - } - - enum - { - PASS_DECODE_NOW, - PASS_DECODE_LATER, - NUM_PASSES - }; - - for (S32 pass = PASS_DECODE_NOW; pass < NUM_PASSES; pass++) - { - LLXMLNodePtr child_nodep = root->getFirstChild(); - while(child_nodep.notNull()) - { - std::string image_name; - child_nodep->getAttributeString("name", image_name); - - std::string file_name = image_name; - LLRect scale_rect; - BOOL use_mip_maps = FALSE; - - BOOL preload = FALSE; - child_nodep->getAttributeBOOL("preload", preload); - - // load high priority textures on first pass (to kick off decode) - if (preload) - { - if (pass == PASS_DECODE_LATER) - { - child_nodep = child_nodep->getNextSibling(); - continue; - } - } - else - { - if (pass == PASS_DECODE_NOW) - { - child_nodep = child_nodep->getNextSibling(); - continue; - } - } - - child_nodep->getAttributeString("file_name", file_name); - child_nodep->getAttributeBOOL("use_mips", use_mip_maps); - - child_nodep->getAttributeS32("scale_left", scale_rect.mLeft); - child_nodep->getAttributeS32("scale_right", scale_rect.mRight); - child_nodep->getAttributeS32("scale_bottom", scale_rect.mBottom); - child_nodep->getAttributeS32("scale_top", scale_rect.mTop); - - preloadUIImage(image_name, file_name, use_mip_maps, scale_rect, LLRectBase::null); - - child_nodep = child_nodep->getNextSibling(); - } - - if (pass == PASS_DECODE_NOW && !gSavedSettings.getBOOL("NoPreload")) - { - gTextureList.decodeAllImages(10.f); // decode preloaded images - } - } - return true; } diff --git a/indra/newview/llviewertexturelist.h b/indra/newview/llviewertexturelist.h index 57d6bc91de..fd2e4a8668 100644 --- a/indra/newview/llviewertexturelist.h +++ b/indra/newview/llviewertexturelist.h @@ -35,6 +35,9 @@ #include "llui.h" #include #include +#include + +#include "absl/container/flat_hash_map.h" const U32 LL_IMAGE_REZ_LOSSLESS_CUTOFF = 128; @@ -59,19 +62,54 @@ typedef void (*LLImageCallback)(BOOL success, BOOL final, void* userdata); +enum ETexListType +{ + TEX_LIST_STANDARD = 0, + TEX_LIST_SCALE +}; + +struct LLTextureKey +{ + LLTextureKey(); + LLTextureKey(LLUUID id, ETexListType tex_type); + LLUUID textureId; + ETexListType textureType; + + friend bool operator == (const LLTextureKey& lhs, const LLTextureKey& rhs) { + return lhs.textureId == rhs.textureId && lhs.textureType == rhs.textureType; + } + + friend bool operator<(const LLTextureKey& key1, const LLTextureKey& key2) + { + if (key1.textureId != key2.textureId) + { + return key1.textureId < key2.textureId; + } + else + { + return key1.textureType < key2.textureType; + } + } + template + friend H AbslHashValue(H h, const LLTextureKey& key) { + return H::combine(std::move(h), key.textureId, key.textureType); + } +}; + class LLViewerTextureList { LOG_CLASS(LLViewerTextureList); friend class LLTextureView; friend class LLViewerTextureManager; + friend class LocalBitmap; + friend class LocalAssetBrowser; public: static BOOL createUploadFile(const std::string& filename, const std::string& out_filename, const U8 codec); static BOOL verifyUploadFile(const std::string& out_filename, const U8 codec); static LLPointer convertToUploadFile(LLPointer raw_image); static void processImageNotInDatabase( LLMessageSystem *msg, void **user_data ); - static S32 calcMaxTextureRAM(); static void receiveImageHeader(LLMessageSystem *msg, void **user_data); static void receiveImagePacket(LLMessageSystem *msg, void **user_data); @@ -86,7 +124,9 @@ class LLViewerTextureList void restoreGL(); BOOL isInitialized() const {return mInitialized;} - LLViewerFetchedTexture *findImage(const LLUUID &image_id); + void findTexturesByID(const LLUUID &image_id, std::vector &output); + LLViewerFetchedTexture *findImage(const LLUUID &image_id, ETexListType tex_type); + LLViewerFetchedTexture *findImage(const LLTextureKey &search_key); void dirtyImage(LLViewerFetchedTexture *image); @@ -101,19 +141,19 @@ class LLViewerTextureList void setUpdateStats(BOOL b) { mUpdateStats = b; } - S32 getMaxResidentTexMem() const { return mMaxResidentTexMemInMegaBytes; } - S32 getMaxTotalTextureMem() const { return mMaxTotalTextureMemInMegaBytes;} + S32Megabytes getMaxResidentTexMem() const { return mMaxResidentTexMemInMegaBytes; } + S32Megabytes getMaxTotalTextureMem() const { return mMaxTotalTextureMemInMegaBytes;} S32 getNumImages() { return mImageList.size(); } - void updateMaxResidentTexMem(S32 mem); + void updateMaxResidentTexMem(S32Megabytes mem); void doPreloadImages(); void doPrefetchImages(); void clearFetchingRequests(); - static S32 getMinVideoRamSetting(); - static S32 getMaxVideoRamSetting(bool get_recommended = false); + static S32Megabytes getMinVideoRamSetting(); + static S32Megabytes getMaxVideoRamSetting(bool get_recommended, float mem_multiplier); private: void updateImagesDecodePriorities(); @@ -121,15 +161,14 @@ class LLViewerTextureList F32 updateImagesFetchTextures(F32 max_time); void updateImagesUpdateStats(); -public: - void addImage(LLViewerFetchedTexture *image); + void addImage(LLViewerFetchedTexture *image, ETexListType tex_type); void deleteImage(LLViewerFetchedTexture *image); -private: void addImageToList(LLViewerFetchedTexture *image); void removeImageFromList(LLViewerFetchedTexture *image); LLViewerFetchedTexture * getImage(const LLUUID &image_id, + FTType f_type = FTT_DEFAULT, BOOL usemipmap = TRUE, LLViewerTexture::EBoostLevel boost_priority = LLGLTexture::BOOST_NONE, // Get the requested level immediately upon creation. S8 texture_type = LLViewerTexture::FETCHED_TEXTURE, @@ -139,6 +178,7 @@ class LLViewerTextureList ); LLViewerFetchedTexture * getImageFromFile(const std::string& filename, + FTType f_type = FTT_LOCAL_FILE, BOOL usemipmap = TRUE, LLViewerTexture::EBoostLevel boost_priority = LLGLTexture::BOOST_NONE, // Get the requested level immediately upon creation. S8 texture_type = LLViewerTexture::FETCHED_TEXTURE, @@ -148,6 +188,7 @@ class LLViewerTextureList ); LLViewerFetchedTexture* getImageFromUrl(const std::string& url, + FTType f_type, BOOL usemipmap = TRUE, LLViewerTexture::EBoostLevel boost_priority = LLGLTexture::BOOST_NONE, // Get the requested level immediately upon creation. S8 texture_type = LLViewerTexture::FETCHED_TEXTURE, @@ -157,6 +198,7 @@ class LLViewerTextureList ); LLViewerFetchedTexture* createImage(const LLUUID &image_id, + FTType f_type, BOOL usemipmap = TRUE, LLViewerTexture::EBoostLevel boost_priority = LLGLTexture::BOOST_NONE, // Get the requested level immediately upon creation. S8 texture_type = LLViewerTexture::FETCHED_TEXTURE, @@ -167,8 +209,8 @@ class LLViewerTextureList // Request image from a specific host, used for baked avatar textures. // Implemented in header in case someone changes default params above. JC - LLViewerFetchedTexture* getImageFromHost(const LLUUID& image_id, LLHost host) - { return getImage(image_id, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, host); } + LLViewerFetchedTexture* getImageFromHost(const LLUUID& image_id, FTType f_type, LLHost host) + { return getImage(image_id, f_type, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, host); } public: typedef std::set > image_list_t; @@ -182,10 +224,12 @@ class LLViewerTextureList BOOL mForceResetTextureStats; private: - typedef std::map< LLUUID, LLPointer > uuid_map_t; + typedef std::map< LLTextureKey, LLPointer > uuid_map_t; uuid_map_t mUUIDMap; - LLUUID mLastUpdateUUID; - LLUUID mLastFetchUUID; + typedef absl::flat_hash_map< LLTextureKey, LLViewerFetchedTexture* > uuid_dict_t; + uuid_dict_t mUUIDDict; + LLTextureKey mLastUpdateKey; + LLTextureKey mLastFetchKey; typedef std::set, LLViewerFetchedTexture::Compare> image_priority_list_t; image_priority_list_t mImageList; @@ -195,12 +239,12 @@ class LLViewerTextureList BOOL mInitialized ; BOOL mUpdateStats; - S32 mMaxResidentTexMemInMegaBytes; - S32 mMaxTotalTextureMemInMegaBytes; + S32Megabytes mMaxResidentTexMemInMegaBytes; + S32Megabytes mMaxTotalTextureMemInMegaBytes; LLFrameTimer mForceDecodeTimer; public: - static U32 sTextureBits; + static U32Bits sTextureBits; static U32 sTexturePackets; private: @@ -218,20 +262,22 @@ class LLUIImageList : public LLImageProviderInterface, public LLSingleton preloadUIImage(const std::string& name, const std::string& filename, BOOL use_mips, const LLRect& scale_rect, const LLRect& clip_rect); + LLPointer preloadUIImage(const std::string& name, const std::string& filename, BOOL use_mips, const LLRect& scale_rect, const LLRect& clip_rect, LLUIImage::EScaleStyle stype); static void onUIImageLoaded( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* userdata ); private: LLPointer loadUIImageByName(const std::string& name, const std::string& filename, BOOL use_mips = FALSE, const LLRect& scale_rect = LLRect::null, const LLRect& clip_rect = LLRect::null, - LLViewerTexture::EBoostLevel boost_priority = LLGLTexture::BOOST_UI); + LLViewerTexture::EBoostLevel boost_priority = LLGLTexture::BOOST_UI, + LLUIImage::EScaleStyle = LLUIImage::SCALE_INNER); LLPointer loadUIImageByID(const LLUUID& id, BOOL use_mips = FALSE, const LLRect& scale_rect = LLRect::null, const LLRect& clip_rect = LLRect::null, - LLViewerTexture::EBoostLevel boost_priority = LLGLTexture::BOOST_UI); + LLViewerTexture::EBoostLevel boost_priority = LLGLTexture::BOOST_UI, + LLUIImage::EScaleStyle = LLUIImage::SCALE_INNER); - LLPointer loadUIImage(LLViewerFetchedTexture* imagep, const std::string& name, BOOL use_mips = FALSE, const LLRect& scale_rect = LLRect::null, const LLRect& clip_rect = LLRect::null); + LLPointer loadUIImage(LLViewerFetchedTexture* imagep, const std::string& name, BOOL use_mips = FALSE, const LLRect& scale_rect = LLRect::null, const LLRect& clip_rect = LLRect::null, LLUIImage::EScaleStyle = LLUIImage::SCALE_INNER); struct LLUIImageLoadData diff --git a/indra/newview/llviewerthrottle.cpp b/indra/newview/llviewerthrottle.cpp index 73065c5c00..8684668dca 100644 --- a/indra/newview/llviewerthrottle.cpp +++ b/indra/newview/llviewerthrottle.cpp @@ -52,7 +52,7 @@ const F32 MAX_FRACTIONAL = 1.5f; const F32 MIN_FRACTIONAL = 0.2f; const F32 MIN_BANDWIDTH = 50.f; -const F32 MAX_BANDWIDTH = 1500.f; +const F32 MAX_BANDWIDTH = 5000.f; const F32 STEP_FRACTIONAL = 0.1f; const F32 TIGHTEN_THROTTLE_THRESHOLD = 3.0f; // packet loss % per s const F32 EASE_THROTTLE_THRESHOLD = 0.5f; // packet loss % per s @@ -152,7 +152,7 @@ LLViewerThrottleGroup LLViewerThrottleGroup::operator-(const LLViewerThrottleGro void LLViewerThrottleGroup::sendToSim() const { - llinfos << "Sending throttle settings, total BW " << mThrottleTotal << llendl; + LL_INFOS() << "Sending throttle settings, total BW " << mThrottleTotal << LL_ENDL; LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_AgentThrottle); @@ -321,7 +321,7 @@ void LLViewerThrottle::updateDynamicThrottle() mCurrentBandwidth = mMaxBandwidth * mThrottleFrac; mCurrent = getThrottleGroup(mCurrentBandwidth / 1024.0f); mCurrent.sendToSim(); - llinfos << "Tightening network throttle to " << mCurrentBandwidth << llendl; + LL_INFOS() << "Tightening network throttle to " << mCurrentBandwidth << LL_ENDL; } else if (LLViewerStats::getInstance()->mPacketsLostPercentStat.getMean() <= EASE_THROTTLE_THRESHOLD) { @@ -334,6 +334,6 @@ void LLViewerThrottle::updateDynamicThrottle() mCurrentBandwidth = mMaxBandwidth * mThrottleFrac; mCurrent = getThrottleGroup(mCurrentBandwidth/1024.0f); mCurrent.sendToSim(); - llinfos << "Easing network throttle to " << mCurrentBandwidth << llendl; + LL_INFOS() << "Easing network throttle to " << mCurrentBandwidth << LL_ENDL; } } diff --git a/indra/newview/llviewerwearable.cpp b/indra/newview/llviewerwearable.cpp index bdd03c0ebd..1297ca9de4 100644 --- a/indra/newview/llviewerwearable.cpp +++ b/indra/newview/llviewerwearable.cpp @@ -40,6 +40,9 @@ #include "llviewerregion.h" #include "llinventoryobserver.h" #include "llinventoryfunctions.h" +#include "lllocaltextureobject.h" +#include "llpaneleditwearable.h" +#include "aixmllindengenepool.h" using namespace LLAvatarAppearanceDefines; @@ -104,7 +107,7 @@ LLWearable::EImportResult LLViewerWearable::importStream( std::istream& input_st { // Shouldn't really log the asset id for security reasons, but // we need it in this case. - llwarns << "Bad Wearable asset header: " << mAssetID << llendl; + LL_WARNS() << "Bad Wearable asset header: " << mAssetID << LL_ENDL; //gVFS->dumpMap(); return result; } @@ -127,39 +130,25 @@ LLWearable::EImportResult LLViewerWearable::importStream( std::istream& input_st LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture( textureid ); if(gSavedSettings.getBOOL("DebugAvatarLocalTexLoadedTime")) { - image->setLoadedCallback(LLVOAvatarSelf::debugOnTimingLocalTexLoaded,0,TRUE,FALSE, new LLVOAvatarSelf::LLAvatarTexData(textureid, (LLAvatarAppearanceDefines::ETextureIndex)te), NULL); + image->setLoadedCallback(LLVOAvatarSelf::debugOnTimingLocalTexLoaded,0,TRUE,FALSE, new LLVOAvatarSelf::LLAvatarTexData(textureid, (LLAvatarAppearanceDefines::ETextureIndex)te), nullptr); } } return result; } -extern void dump_visual_param(LLAPRFile& file, LLVisualParam const* viewer_param, F32 value); - -void LLViewerWearable::archetypeExport(LLAPRFile& file) const +AIArchetype LLViewerWearable::getArchetype() const { - apr_file_t* fp = file.getFileHandle(); - - std::string path; - append_path_short(mItemID, path); - apr_file_printf(fp, " \n", - LLXMLNode::escapeXML(path).c_str(), - LLXMLNode::escapeXML(mName).c_str(), - LLXMLNode::escapeXML(mDescription).c_str()); - + AIArchetype archetype(this); for (visual_param_index_map_t::const_iterator iter = mVisualParamIndexMap.begin(); iter != mVisualParamIndexMap.end(); ++iter) { - LLVisualParam const* param = iter->second; - dump_visual_param(file, param, param->getWeight()); + archetype.add(AIVisualParamIDValuePair(iter->second)); } for (te_map_t::const_iterator iter = mTEMap.begin(); iter != mTEMap.end(); ++iter) { - S32 te = iter->first; - LLUUID const& image_id = iter->second->getID(); - apr_file_printf(fp, " \n", te, image_id.asString().c_str()); + archetype.add(AITextureIDUUIDPair(iter->first, iter->second->getID())); } - - apr_file_printf(fp, "\n"); + return archetype; } // Avatar parameter and texture definitions can change over time. @@ -171,7 +160,7 @@ BOOL LLViewerWearable::isOldVersion() const if( LLWearable::sCurrentDefinitionVersion < mDefinitionVersion ) { - llwarns << "Wearable asset has newer version (" << mDefinitionVersion << ") than XML (" << LLWearable::sCurrentDefinitionVersion << ")" << llendl; + LL_WARNS() << "Wearable asset has newer version (" << mDefinitionVersion << ") than XML (" << LLWearable::sCurrentDefinitionVersion << ")" << LL_ENDL; llassert(0); } @@ -246,10 +235,9 @@ BOOL LLViewerWearable::isDirty() const U8 a = F32_to_U8( saved_weight, param->getMinWeight(), param->getMaxWeight() ); U8 b = F32_to_U8( current_weight, param->getMinWeight(), param->getMaxWeight() ); - if( a != b ) { - //llwarns << "param ID " << param->getID() << " was changed." << llendl; + //LL_WARNS() << "param ID " << param->getID() << " was changed." << LL_ENDL; return TRUE; } } @@ -328,8 +316,8 @@ void LLViewerWearable::setTexturesToDefaults() const LLUUID LLViewerWearable::getDefaultTextureImageID(ETextureIndex index) const { const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = LLAvatarAppearanceDictionary::getInstance()->getTexture(index); - const std::string &default_image_name = texture_dict->mDefaultImageName; - if (default_image_name == "") + const std::string &default_image_name = texture_dict ? texture_dict->mDefaultImageName : ""; + if (default_image_name.empty()) { return IMG_DEFAULT_AVATAR; } @@ -344,22 +332,13 @@ const LLUUID LLViewerWearable::getDefaultTextureImageID(ETextureIndex index) con //virtual void LLViewerWearable::writeToAvatar(LLAvatarAppearance *avatarp) { - LLVOAvatarSelf* viewer_avatar = dynamic_cast(avatarp); + if (!avatarp || !avatarp->isSelf() || !avatarp->isValid()) return; + LLVOAvatarSelf* viewer_avatar = static_cast(avatarp); if (!avatarp || !viewer_avatar) return; if (!viewer_avatar->isValid()) return; -#if 0 - // FIXME DRANO - kludgy way to avoid overwriting avatar state from wearables. - // Ideally would avoid calling this func in the first place. - if (viewer_avatar->isUsingServerBakes() && - !viewer_avatar->isUsingLocalAppearance()) - { - return; - } -#endif - ESex old_sex = avatarp->getSex(); LLWearable::writeToAvatar(avatarp); @@ -380,7 +359,7 @@ void LLViewerWearable::writeToAvatar(LLAvatarAppearance *avatarp) { image_id = getDefaultTextureImageID((ETextureIndex) te); } - LLViewerTexture* image = LLViewerTextureManager::getFetchedTexture( image_id, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE ); + LLViewerTexture* image = LLViewerTextureManager::getFetchedTexture( image_id, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE ); // MULTI-WEARABLE: assume index 0 will be used when writing to avatar. TODO: eliminate the need for this. viewer_avatar->setLocalTextureTE(te, image, 0); } @@ -396,7 +375,7 @@ void LLViewerWearable::writeToAvatar(LLAvatarAppearance *avatarp) // Updates the user's avatar's appearance, replacing this wearables' parameters and textures with default values. // static -void LLViewerWearable::removeFromAvatar( LLWearableType::EType type, BOOL upload_bake ) +void LLViewerWearable::removeFromAvatar( LLWearableType::EType type, bool upload_bake ) { if (!isAgentAvatarValid()) return; @@ -470,7 +449,7 @@ void LLViewerWearable::copyDataFrom(const LLViewerWearable* src) { te_map_t::const_iterator iter = src->mTEMap.find(te); LLUUID image_id; - LLViewerFetchedTexture *image = NULL; + LLViewerFetchedTexture *image = nullptr; if(iter != src->mTEMap.end()) { image = dynamic_cast (src->getLocalTextureObject(te)->getImage()); @@ -503,13 +482,6 @@ void LLViewerWearable::setItemID(const LLUUID& item_id) void LLViewerWearable::revertValues() { -#if 0 - // DRANO avoid overwrite when not in local appearance - if (isAgentAvatarValid() && gAgentAvatarp->isUsingServerBakes() && !gAgentAvatarp->isUsingLocalAppearance()) - { - return; - } -#endif LLWearable::revertValues(); @@ -518,7 +490,7 @@ void LLViewerWearable::revertValues() { panel->updateScrollingPanelList(); }*/ - if( LLFloaterCustomize::instanceExists() && gAgentWearables.getWearableIndex(this)==0 ) + if (LLFloaterCustomize::instanceExists() && LLFloaterCustomize::getInstance()->getCurrentWearablePanel()->getWearable() == this) LLFloaterCustomize::getInstance()->updateScrollingPanelList(); } @@ -533,7 +505,7 @@ void LLViewerWearable::saveValues() panel->updateScrollingPanelList(); }*/ - if( LLFloaterCustomize::instanceExists() && gAgentWearables.getWearableIndex(this)==0) + if (LLFloaterCustomize::instanceExists() && LLFloaterCustomize::getInstance()->getCurrentWearablePanel()->getWearable() == this) LLFloaterCustomize::getInstance()->updateScrollingPanelList(); } @@ -607,25 +579,14 @@ struct LLWearableSaveData void LLViewerWearable::saveNewAsset() const { -// llinfos << "LLViewerWearable::saveNewAsset() type: " << getTypeName() << llendl; - //llinfos << *this << llendl; +// LL_INFOS() << "LLViewerWearable::saveNewAsset() type: " << getTypeName() << LL_ENDL; + //LL_INFOS() << *this << LL_ENDL; const std::string filename = asset_id_to_filename(mAssetID); - LLFILE* fp = LLFile::fopen(filename, "wb"); /* Flawfinder: ignore */ - BOOL successful_save = FALSE; - if(fp && exportFile(fp)) - { - successful_save = TRUE; - } - if(fp) - { - fclose(fp); - fp = NULL; - } - if(!successful_save) + if(! exportFile(filename)) { std::string buffer = llformat("Unable to save '%s' to wearable file.", mName.c_str()); - llwarns << buffer << llendl; + LL_WARNS() << buffer << LL_ENDL; LLSD args; args["NAME"] = mName; @@ -636,28 +597,29 @@ void LLViewerWearable::saveNewAsset() const // save it out to database if( gAssetStorage ) { - /* - std::string url = gAgent.getRegion()->getCapability("NewAgentInventory"); +#if 0 + const std::string url = gAgent.getRegion()->getCapability("NewFileAgentInventory"); if (!url.empty()) { - llinfos << "Update Agent Inventory via capability" << llendl; + LL_INFOS() << "Update Agent Inventory via capability" << LL_ENDL; LLSD body; - body["folder_id"] = gInventory.findCategoryUUIDForType(LLFolderType::assetToFolderType(getAssetType())); + body["folder_id"] = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(getAssetType())); body["asset_type"] = LLAssetType::lookup(getAssetType()); body["inventory_type"] = LLInventoryType::lookup(LLInventoryType::IT_WEARABLE); body["name"] = getName(); body["description"] = getDescription(); - LLHTTPClient::post(url, body, new LLNewAgentInventoryResponder(body, filename)); + LLHTTPClient::post(url, body, new LLNewAgentInventoryResponder(body, filename, + getAssetType())); } else +#endif // 0 { - } - */ - LLWearableSaveData* data = new LLWearableSaveData; - data->mType = mType; - gAssetStorage->storeAssetData(filename, mTransactionID, getAssetType(), + LLWearableSaveData* data = new LLWearableSaveData; + data->mType = mType; + gAssetStorage->storeAssetData(filename, mTransactionID, getAssetType(), &LLViewerWearable::onSaveNewAssetComplete, (void*)data); + } } } @@ -669,12 +631,12 @@ void LLViewerWearable::onSaveNewAssetComplete(const LLUUID& new_asset_id, void* if(0 == status) { // Success - llinfos << "Saved wearable " << type_name << llendl; + LL_INFOS() << "Saved wearable " << type_name << LL_ENDL; } else { std::string buffer = llformat("Unable to save %s to central asset store.", type_name.c_str()); - llwarns << buffer << " Status: " << status << llendl; + LL_WARNS() << buffer << " Status: " << status << LL_ENDL; LLSD args; args["NAME"] = type_name; LLNotificationsUtil::add("CannotSaveToAssetStore", args); @@ -698,21 +660,19 @@ std::ostream& operator<<(std::ostream &s, const LLViewerWearable &w) //w.mSaleInfo s << " Params:" << "\n"; - for (LLWearable::visual_param_index_map_t::const_iterator iter = w.mVisualParamIndexMap.begin(); - iter != w.mVisualParamIndexMap.end(); ++iter) + for (const auto& iter : w.mVisualParamIndexMap) { - S32 param_id = iter->first; - LLVisualParam *wearable_param = iter->second; + S32 param_id = iter.first; + LLVisualParam *wearable_param = iter.second; F32 param_weight = wearable_param->getWeight(); s << " " << param_id << " " << param_weight << "\n"; } s << " Textures:" << "\n"; - for (LLViewerWearable::te_map_t::const_iterator iter = w.mTEMap.begin(); - iter != w.mTEMap.end(); ++iter) + for (const auto& iter : w.mTEMap) { - S32 te = iter->first; - const LLUUID& image_id = iter->second->getID(); + S32 te = iter.first; + const LLUUID& image_id = iter.second->getID(); s << " " << te << " " << image_id << "\n"; } return s; diff --git a/indra/newview/llviewerwearable.h b/indra/newview/llviewerwearable.h index 660594d26e..94f70fefae 100644 --- a/indra/newview/llviewerwearable.h +++ b/indra/newview/llviewerwearable.h @@ -62,13 +62,14 @@ class LLViewerWearable : public LLWearable BOOL isOldVersion() const; /*virtual*/ void writeToAvatar(LLAvatarAppearance *avatarp); - void removeFromAvatar( BOOL upload_bake ) { LLViewerWearable::removeFromAvatar( mType, upload_bake ); } - static void removeFromAvatar( LLWearableType::EType type, BOOL upload_bake ); + void removeFromAvatar( bool upload_bake = false ) { LLViewerWearable::removeFromAvatar( mType, upload_bake ); } + static void removeFromAvatar( LLWearableType::EType type, bool upload_bake = false); /*virtual*/ EImportResult importStream( std::istream& input_stream, LLAvatarAppearance* avatarp ); - void archetypeExport(LLAPRFile& file) const; - + // Singu extension. + class AIArchetype getArchetype() const; + void setParamsToDefaults(); void setTexturesToDefaults(); diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 3e57959b47..b3ca313cf3 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -60,6 +60,7 @@ #include "llaudioengine.h" // mute on minimize #include "llassetstorage.h" #include "llfontgl.h" +#include "llfontfreetype.h" #include "llmousehandler.h" #include "llrect.h" #include "llsky.h" @@ -179,6 +180,7 @@ #include "llviewernetwork.h" #include "llpostprocess.h" #include "llwearablelist.h" +#include "llfloaterinspect.h" #include "llnotifications.h" #include "llnotificationsutil.h" @@ -186,6 +188,7 @@ #include "llfloaternotificationsconsole.h" #include "llpanelnearbymedia.h" +#include "llmessagetemplate.h" // [RLVa:KB] #include "rlvhandler.h" @@ -218,13 +221,15 @@ BOOL gShowOverlayTitle = FALSE; BOOL gPickTransparent = TRUE; LLViewerObject* gDebugRaycastObject = NULL; -LLVector3 gDebugRaycastIntersection; -LLVector2 gDebugRaycastTexCoord; -LLVector3 gDebugRaycastNormal; -LLVector3 gDebugRaycastBinormal; -S32 gDebugRaycastFaceHit; -LLVector3 gDebugRaycastStart; -LLVector3 gDebugRaycastEnd; +LLVOPartGroup* gDebugRaycastParticle = NULL; +LLVector4a gDebugRaycastIntersection; +LLVector4a gDebugRaycastParticleIntersection; +LLVector2 gDebugRaycastTexCoord; +LLVector4a gDebugRaycastNormal; +LLVector4a gDebugRaycastTangent; +S32 gDebugRaycastFaceHit; +LLVector4a gDebugRaycastStart; +LLVector4a gDebugRaycastEnd; // HUD display lines in lower right BOOL gDisplayWindInfo = FALSE; @@ -242,7 +247,7 @@ const F32 MIN_AFK_TIME = 2.f; // minimum time after setting away state before co const F32 MAX_FAST_FRAME_TIME = 0.5f; const F32 FAST_FRAME_INCREMENT = 0.1f; -const F32 MIN_DISPLAY_SCALE = 0.75f; +const F32 MIN_DISPLAY_SCALE = 0.5f; std::string LLViewerWindow::sSnapshotBaseName; std::string LLViewerWindow::sSnapshotDir; @@ -258,7 +263,7 @@ extern void toggle_debug_menus(void*); // LLDebugText // -extern std::map > > sTextureMaskMap; +//extern std::map > > sTextureMaskMap; class LLDebugText { @@ -309,6 +314,13 @@ class LLDebugText U32 ypos = 64; const U32 y_inc = 20; + static const LLCachedControl slb_show_fps("SLBShowFPS"); + if (slb_show_fps) + { + addText(xpos+280, ypos+5, llformat("FPS %3.1f", LLViewerStats::getInstance()->mFPSStat.getMeanPerSec())); + ypos += y_inc; + } + static const LLCachedControl debug_show_time("DebugShowTime"); if (debug_show_time) { @@ -339,16 +351,16 @@ class LLDebugText LLViewerObject* obj1 = nodep ? nodep->getObject() : NULL; LLViewerObject* obj2 = handle ? handle->getPrimaryObject() : NULL; LLViewerObject* obj = obj1 ? obj1 : obj2; - //llinfos << std::hex << obj1 << " " << obj2 << std::dec << llendl; + //LL_INFOS() << std::hex << obj1 << " " << obj2 << std::dec << LL_ENDL; if(obj) { S32 te = nodep ? nodep->getLastSelectedTE() : -1; - if(te > 0) + if(te >= 0) { LLViewerTexture* imagep = obj->getTEImage(te); if(imagep && imagep != (LLViewerTexture*)LLViewerFetchedTexture::sDefaultImagep.get()) { - LLGLuint tex = imagep->getTexName(); + /*LLGLuint tex = imagep->getTexName(); std::map > >::iterator it = sTextureMaskMap.find(tex); if(it != sTextureMaskMap.end()) { @@ -357,10 +369,11 @@ class LLDebugText { addText(xpos, ypos, llformat(" %s: %s", it2->first.c_str(), it2->second.c_str())); ypos += y_inc; } - } + }*/ static const LLCachedControl use_rmse_auto_mask("SHUseRMSEAutoMask",false); static const LLCachedControl auto_mask_max_rmse("SHAutoMaskMaxRMSE",.09f); - addText(xpos, ypos, llformat("Mask: %s", imagep->getIsAlphaMask(use_rmse_auto_mask ? auto_mask_max_rmse : -1.f) ? "TRUE":"FALSE")); ypos += y_inc; + static const LLCachedControl auto_mask_max_mid("SHAutoMaskMaxMid", .25f); + addText(xpos, ypos, llformat("Mask: %s", imagep->getIsAlphaMask(use_rmse_auto_mask ? auto_mask_max_rmse : -1.f, auto_mask_max_mid) ? "TRUE":"FALSE")); ypos += y_inc; addText(xpos, ypos, llformat("ID: %s", imagep->getID().asString().c_str())); ypos += y_inc; } } @@ -372,7 +385,7 @@ class LLDebugText static const LLCachedControl debug_show_memory("DebugShowMemory"); if (debug_show_memory) { - addText(xpos, ypos, llformat("Memory: %d (KB)", LLMemory::getWorkingSetSize() / 1024)); + addText(xpos, ypos, llformat("Memory: %d (KB)", LLMemory::getCurrentRSS() / 1024)); ypos += y_inc; } #endif @@ -464,7 +477,7 @@ class LLDebugText static const LLCachedControl debug_show_render_info("DebugShowRenderInfo"); if (debug_show_render_info) { - if (gPipeline.getUseVertexShaders() == 0) + if (!LLGLSLShader::sNoFixedFunction) { addText(xpos, ypos, "Shaders Disabled"); ypos += y_inc; @@ -495,7 +508,7 @@ class LLDebugText //show streaming cost/triangle count of known prims in current region OR selection //Note: This is SUPER slow - { + /*{ F32 cost = 0.f; S32 count = 0; S32 vcount = 0; @@ -544,7 +557,7 @@ class LLDebugText count/1000.f, vcount/1000.f, visible_bytes/1024.f, total_bytes/1024.f, object_count)); ypos += y_inc; - } + }*/ addText(xpos, ypos, llformat("%d MB Index Data (%d MB Pooled, %d KIndices)", LLVertexBuffer::sAllocatedIndexBytes/(1024*1024), LLVBOPool::sIndexBytesPooled/(1024*1024), LLVertexBuffer::sIndexCount/1024)); ypos += y_inc; @@ -643,7 +656,7 @@ class LLDebugText } } } - for(std::set::iterator it = gObjectList.mDeadObjects.begin();it!=gObjectList.mDeadObjects.end();++it) + for(auto it = gObjectList.mDeadObjects.begin();it!=gObjectList.mDeadObjects.end();++it) { LLViewerObject *obj = gObjectList.findObject(*it); if(obj && obj->isAvatar()) @@ -673,7 +686,7 @@ class LLDebugText LLMeshRepository::sHTTPRetryCount)); ypos += y_inc; - addText(xpos, ypos, llformat("%d/%d Mesh LOD Pending/Processing", LLMeshRepository::sLODPending, LLMeshRepository::sLODProcessing)); + addText(xpos, ypos, llformat("%d/%d Mesh LOD Pending/Processing", LLMeshRepository::sLODPending, (U32)LLMeshRepository::sLODProcessing)); ypos += y_inc; addText(xpos, ypos, llformat("%.3f/%.3f MB Mesh Cache Read/Write ", LLMeshRepository::sCacheBytesRead/(1024.f*1024.f), LLMeshRepository::sCacheBytesWritten/(1024.f*1024.f))); @@ -681,39 +694,48 @@ class LLDebugText ypos += y_inc; } + addText(xpos, ypos, llformat("%d/%d bytes allocted to messages", sMsgDataAllocSize, sMsgdataAllocCount)); + LLVertexBuffer::sBindCount = LLImageGL::sBindCount = LLVertexBuffer::sSetCount = LLImageGL::sUniqueCount = gPipeline.mNumVisibleNodes = LLPipeline::sVisibleLightCount = 0; } + + sMsgDataAllocSize = 0; + sMsgdataAllocCount = 0; + static const LLCachedControl debug_show_render_matrices("DebugShowRenderMatrices"); if (debug_show_render_matrices) { - addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLProjection[12], gGLProjection[13], gGLProjection[14], gGLProjection[15])); + F32* m = gGLProjection.getF32ptr(); + + addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", m[12], m[13], m[14], m[15])); ypos += y_inc; - addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLProjection[8], gGLProjection[9], gGLProjection[10], gGLProjection[11])); + addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", m[8], m[9], m[10], m[11])); ypos += y_inc; - addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLProjection[4], gGLProjection[5], gGLProjection[6], gGLProjection[7])); + addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", m[4], m[5], m[6], m[7])); ypos += y_inc; - addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLProjection[0], gGLProjection[1], gGLProjection[2], gGLProjection[3])); + addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", m[0], m[1], m[2], m[3])); ypos += y_inc; addText(xpos, ypos, "Projection Matrix"); ypos += y_inc; + m = gGLModelView.getF32ptr(); - addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLModelView[12], gGLModelView[13], gGLModelView[14], gGLModelView[15])); + addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", m[12], m[13], m[14], m[15])); ypos += y_inc; - addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLModelView[8], gGLModelView[9], gGLModelView[10], gGLModelView[11])); + addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", m[8], m[9], m[10], m[11])); ypos += y_inc; - addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLModelView[4], gGLModelView[5], gGLModelView[6], gGLModelView[7])); + addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", m[4], m[5], m[6], m[7])); ypos += y_inc; - addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLModelView[0], gGLModelView[1], gGLModelView[2], gGLModelView[3])); + addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", m[0], m[1], m[2], m[3])); ypos += y_inc; addText(xpos, ypos, "View Matrix"); @@ -835,8 +857,8 @@ BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK BOOL handled = FALSE; S32 x = pos.mX; S32 y = pos.mY; - x = llround((F32)x / mDisplayScale.mV[VX]); - y = llround((F32)y / mDisplayScale.mV[VY]); + x = ll_round((F32)x / mDisplayScale.mV[VX]); + y = ll_round((F32)y / mDisplayScale.mV[VY]); if (down) { @@ -877,7 +899,7 @@ BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK if (gDebugClicks) { - llinfos << "ViewerWindow " << buttonname << " mouse " << buttonstatestr << " at " << x << "," << y << llendl; + LL_INFOS() << "ViewerWindow " << buttonname << " mouse " << buttonstatestr << " at " << x << "," << y << LL_ENDL; } // Make sure we get a corresponding mouseup event, even if the mouse leaves the window @@ -920,7 +942,7 @@ BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK mouse_captor->screenPointToLocal( x, y, &local_x, &local_y ); if (LLView::sDebugMouseHandling) { - llinfos << buttonname << " Mouse " << buttonstatestr << " handled by captor " << mouse_captor->getName() << llendl; + LL_INFOS() << buttonname << " Mouse " << buttonstatestr << " handled by captor " << mouse_captor->getName() << LL_ENDL; } return mouse_captor->handleAnyMouseClick(local_x, local_y, mask, clicktype, down); } @@ -958,13 +980,13 @@ BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK { if (LLView::sDebugMouseHandling) { - llinfos << buttonname << " Mouse " << buttonstatestr << " " << LLView::sMouseHandlerMessage << llendl; + LL_INFOS() << buttonname << " Mouse " << buttonstatestr << " " << LLView::sMouseHandlerMessage << LL_ENDL; } return TRUE; } else if (LLView::sDebugMouseHandling) { - llinfos << buttonname << " Mouse " << buttonstatestr << " not handled by view" << llendl; + LL_INFOS() << buttonname << " Mouse " << buttonstatestr << " not handled by view" << LL_ENDL; } // Do not allow tool manager to handle mouseclicks if we have disconnected @@ -1008,22 +1030,10 @@ BOOL LLViewerWindow::handleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask) BOOL LLViewerWindow::handleRightMouseDown(LLWindow *window, LLCoordGL pos, MASK mask) { - //From Phoenix - // Singu TODO: Change these from debug settings to externs? - gSavedSettings.setBOOL("zmm_rightmousedown", true); - if (gAgentCamera.cameraMouselook() && !gSavedSettings.getBOOL("zmm_isinml")) - { - llinfos << "zmmisinml set to true" << llendl; - gSavedSettings.setBOOL("zmm_isinml", true); - F32 deffov = LLViewerCamera::getInstance()->getDefaultFOV(); - gSavedSettings.setF32("zmm_deffov", deffov); - LLViewerCamera::getInstance()->setDefaultFOV(deffov/gSavedSettings.getF32("zmm_mlfov")); - } - S32 x = pos.mX; S32 y = pos.mY; - x = llround((F32)x / mDisplayScale.mV[VX]); - y = llround((F32)y / mDisplayScale.mV[VY]); + x = ll_round((F32)x / mDisplayScale.mV[VX]); + y = ll_round((F32)y / mDisplayScale.mV[VY]); LLView::sMouseHandlerMessage.clear(); @@ -1034,7 +1044,7 @@ BOOL LLViewerWindow::handleRightMouseDown(LLWindow *window, LLCoordGL pos, MASK // *HACK: this should be rolled into the composite tool logic, not // hardcoded at the top level. - if (CAMERA_MODE_CUSTOMIZE_AVATAR != gAgentCamera.getCameraMode() && LLToolMgr::getInstance()->getCurrentTool() != LLToolPie::getInstance()) + if (CAMERA_MODE_CUSTOMIZE_AVATAR != gAgentCamera.getCameraMode() && LLToolMgr::getInstance()->getCurrentTool() != LLToolPie::getInstance() && gAgent.isInitialized()) { // If the current tool didn't process the click, we should show // the pie menu. This can be done by passing the event to the pie @@ -1048,14 +1058,6 @@ BOOL LLViewerWindow::handleRightMouseDown(LLWindow *window, LLCoordGL pos, MASK BOOL LLViewerWindow::handleRightMouseUp(LLWindow *window, LLCoordGL pos, MASK mask) { - gSavedSettings.setBOOL("zmm_rightmousedown", false); - if(gSavedSettings.getBOOL("zmm_isinml")==1) - { - llinfos << "zmmisinml set to false" << llendl; - gSavedSettings.setBOOL("zmm_isinml",0); - LLViewerCamera::getInstance()->setDefaultFOV(gSavedSettings.getF32("zmm_deffov")); - } - BOOL down = FALSE; return handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_RIGHT,down); } @@ -1104,15 +1106,18 @@ LLWindowCallbacks::DragNDropResult LLViewerWindow::handleDragNDrop( LLWindow *wi if (prim_media_dnd_enabled) { - LLPickInfo pick_info = pickImmediate( pos.mX, pos.mY, TRUE /*BOOL pick_transparent*/ ); + LLPickInfo pick_info = pickImmediate( pos.mX, pos.mY, + TRUE /* pick_transparent */, + FALSE /* pick_rigged */); LLUUID object_id = pick_info.getObjectID(); S32 object_face = pick_info.mObjectFace; std::string url = data; - lldebugs << "Object: picked at " << pos.mX << ", " << pos.mY << " - face = " << object_face << " - URL = " << url << llendl; + LL_DEBUGS() << "Object: picked at " << pos.mX << ", " << pos.mY << " - face = " << object_face << " - URL = " << url << LL_ENDL; - LLVOVolume *obj = dynamic_cast(static_cast(pick_info.getObject())); + LLViewerObject* vobjp = static_cast(pick_info.getObject()); + LLVOVolume *obj = vobjp ? vobjp->asVolume() : nullptr; if (obj && !obj->getRegion()->getCapability("ObjectMedia").empty()) { @@ -1229,8 +1234,8 @@ void LLViewerWindow::handleMouseMove(LLWindow *window, LLCoordGL pos, MASK mask S32 x = pos.mX; S32 y = pos.mY; - x = llround((F32)x / mDisplayScale.mV[VX]); - y = llround((F32)y / mDisplayScale.mV[VY]); + x = ll_round((F32)x / mDisplayScale.mV[VX]); + y = ll_round((F32)y / mDisplayScale.mV[VY]); mMouseInWindow = TRUE; @@ -1371,7 +1376,11 @@ BOOL LLViewerWindow::handleTranslatedKeyDown(KEY key, MASK mask, BOOL repeated) // it's all entered/processed. if (key == KEY_RETURN && mask == MASK_NONE) { - return FALSE; + // RIDER: although, at times some of the controlls (in particular the CEF viewer + // would like to know about the KEYDOWN for an enter key... so ask and pass it along. + LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus(); + if (keyboard_focus && !keyboard_focus->wantsReturnKey()) + return FALSE; } return gViewerKeyboard.handleKey(key, mask, repeated); @@ -1382,14 +1391,20 @@ BOOL LLViewerWindow::handleTranslatedKeyUp(KEY key, MASK mask) // Let the voice chat code check for its PTT key. Note that this never affects event processing. LLVoiceClient::getInstance()->keyUp(key, mask); - return FALSE; -} + // Let the inspect tool code check for ALT key to set LLToolSelectRect active instead LLToolCamera + LLToolCompInspect * tool_inspectp = LLToolCompInspect::getInstance(); + if (LLToolMgr::getInstance()->getCurrentTool() == tool_inspectp) + { + tool_inspectp->keyUp(key, mask); + } + return gViewerKeyboard.handleKeyUp(key, mask); +} void LLViewerWindow::handleScanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level) { LLViewerJoystick::getInstance()->setCameraNeedsUpdate(true); - return gViewerKeyboard.scanKey(key, key_down, key_up, key_level); + gViewerKeyboard.scanKey(key, key_down, key_up, key_level); } @@ -1397,6 +1412,9 @@ void LLViewerWindow::handleScanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key BOOL LLViewerWindow::handleActivate(LLWindow *window, BOOL activated) { + if (mActive == (bool)activated) { + return TRUE; + } if (activated) { mActive = true; @@ -1404,12 +1422,13 @@ BOOL LLViewerWindow::handleActivate(LLWindow *window, BOOL activated) gAgent.clearAFK(); if (mWindow->getFullscreen() && !mIgnoreActivate) { - if (!LLApp::isExiting() ) + // Opengl doesn't need torn down when alt tabbing. + /*if (!LLApp::isExiting() ) { if (LLStartUp::getStartupState() >= STATE_STARTED) { // if we're in world, show a progress bar to hide reloading of textures - llinfos << "Restoring GL during activate" << llendl; + LL_INFOS() << "Restoring GL during activate" << LL_ENDL; restoreGL(LLTrans::getString("ProgressRestoring")); } else @@ -1418,14 +1437,14 @@ BOOL LLViewerWindow::handleActivate(LLWindow *window, BOOL activated) restoreGL(); } } - else + else*/ { - llwarns << "Activating while quitting" << llendl; + LL_WARNS() << "Activating while quitting" << LL_ENDL; } } // Unmute audio - audio_update_volume(); + audio_update_volume(false); } else { @@ -1444,13 +1463,14 @@ BOOL LLViewerWindow::handleActivate(LLWindow *window, BOOL activated) send_agent_pause(); - if (mWindow->getFullscreen() && !mIgnoreActivate) + // Opengl doesn't need torn down when alt tabbing. + /*if (mWindow->getFullscreen() && !mIgnoreActivate) { - llinfos << "Stopping GL during deactivation" << llendl; + LL_INFOS() << "Stopping GL during deactivation" << LL_ENDL; stopGL(); - } + }*/ // Mute audio - audio_update_volume(); + audio_update_volume(false); } return TRUE; } @@ -1488,12 +1508,8 @@ BOOL LLViewerWindow::handlePaint(LLWindow *window, S32 x, S32 y, S32 width, S //SetBKColor(hdc, RGB(255, 255, 255)); FillRect(hdc, &wnd_rect, CreateSolidBrush(RGB(255, 255, 255))); - std::string name_str; - gAgent.getName(name_str); - std::string temp_str; - temp_str = llformat( "%s FPS %3.1f Phy FPS %2.1f Time Dil %1.3f", /* Flawfinder: ignore */ - name_str.c_str(), + temp_str = llformat( "FPS %3.1f Phy FPS %2.1f Time Dil %1.3f", /* Flawfinder: ignore */ LLViewerStats::getInstance()->mFPSStat.getMeanPerSec(), LLViewerStats::getInstance()->mSimPhysicsFPS.getPrev(0), LLViewerStats::getInstance()->mSimTimeDilation.getPrev(0)); @@ -1571,6 +1587,22 @@ BOOL LLViewerWindow::handleDeviceChange(LLWindow *window) return FALSE; } +bool LLViewerWindow::handleDPIScaleChange(LLWindow *window, float xDPIScale, float yDPIScale, U32 width, U32 height) +{ + LL_INFOS() << "handleDPIScaleChange" << LL_ENDL; + if (mDPIScaleX != xDPIScale || mDPIScaleY != yDPIScale) + { + LL_INFOS() << "handleDPIScaleChange APPLY" << LL_ENDL; + mDPIScaleX = xDPIScale; + mDPIScaleY = yDPIScale; + if (!mWindow->getFullscreen()) { + reshape(width ? width : getWindowWidthRaw(), height ? height : getWindowHeightRaw()); + return true; + } + } + return false; +} + void LLViewerWindow::handlePingWatchdog(LLWindow *window, const char * msg) { LLAppViewer::instance()->pingMainloopTimeout(msg); @@ -1609,6 +1641,17 @@ std::string LLViewerWindow::translateString(const char* tag, return LLTrans::getString( std::string(tag), args_copy); } +static const std::string font_dir() +{ + return gDirUtilp->getExecutableDir() + #if LL_DARWIN + + "/../Resources" + #elif !defined(LL_WINDOWS) + + "/.." + #endif + ; +} + // // Classes // @@ -1634,12 +1677,13 @@ LLViewerWindow::LLViewerWindow( mHideCursorPermanent( FALSE ), mCursorHidden(FALSE), mIgnoreActivate( FALSE ), - mHoverPick(), mResDirty(false), //mStatesDirty(false), //Singu Note: No longer needed. State update is now in restoreGL. mIsFullscreenChecked(false), mCurrResolutionIndex(0), - mProgressView(NULL) + mProgressView(NULL), + mDPIScaleX(1.f), + mDPIScaleY(1.f) { LLNotificationChannel::buildChannel("VW_alerts", "Visible", LLNotificationFilters::filterBy(&LLNotification::getType, "alert")); LLNotificationChannel::buildChannel("VW_alertmodal", "Visible", LLNotificationFilters::filterBy(&LLNotification::getType, "alertmodal")); @@ -1652,15 +1696,17 @@ LLViewerWindow::LLViewerWindow( LLViewerWindow::sMovieBaseName = "SLmovie"; resetSnapshotLoc(); + S32 vsync_mode = gSavedSettings.getS32("SHRenderVsyncMode"); + // create window mWindow = LLWindowManager::createWindow(this, title, name, x, y, width, height, 0, fullscreen, gNoRender, - gSavedSettings.getBOOL("DisableVerticalSync"), + vsync_mode, !gNoRender, ignore_pixel_depth, - gSavedSettings.getBOOL("RenderUseFBO") ? 0 : gSavedSettings.getU32("RenderFSAASamples")); //don't use window level anti-aliasing if FBOs are enabled + LLRenderTarget::sUseFBO ? 0 : gSavedSettings.getU32("RenderFSAASamples")); //don't use window level anti-aliasing if FBOs are enabled if (!LLViewerShaderMgr::sInitialized) { //immediately initialize shaders @@ -1672,14 +1718,14 @@ LLViewerWindow::LLViewerWindow( { LLSplashScreen::update(LLTrans::getString("StartupRequireDriverUpdate")); - LL_WARNS("Window") << "Failed to create window, to be shutting Down, be sure your graphics driver is updated." << llendl ; + LL_WARNS("Window") << "Failed to create window, to be shutting Down, be sure your graphics driver is updated." << LL_ENDL ; ms_sleep(5000) ; //wait for 5 seconds. LLSplashScreen::update(LLTrans::getString("ShuttingDown")); #if LL_LINUX || LL_SOLARIS - llwarns << "Unable to create window, be sure screen is set at 32-bit color and your graphics driver is configured correctly. See README-linux.txt or README-solaris.txt for further information." - << llendl; + LL_WARNS() << "Unable to create window, be sure screen is set at 32-bit color and your graphics driver is configured correctly. See README-linux.txt or README-solaris.txt for further information." + << LL_ENDL; #else LL_WARNS("Window") << "Unable to create window, be sure screen is set at 32-bit color in Control Panels->Display->Settings" << LL_ENDL; @@ -1699,24 +1745,23 @@ LLViewerWindow::LLViewerWindow( if(fullscreen && ( scr.mX!=width || scr.mY!=height)) { - llwarns << "Fullscreen has forced us in to a different resolution now using "<getPixelAspectRatio(), 1.f), llmax(mWindow->getPixelAspectRatio(), 1.f)); - mDisplayScale *= ui_scale_factor; + mDisplayScale.scaleVec(getUIScale()); + LLUI::setScaleFactor(mDisplayScale); { LLCoordWindow size; mWindow->getSize(&size); mWindowRectRaw.set(0, size.mY, size.mX, 0); - mWindowRectScaled.set(0, llround((F32)size.mY / mDisplayScale.mV[VY]), llround((F32)size.mX / mDisplayScale.mV[VX]), 0); + mWindowRectScaled.set(0, ll_round((F32)size.mY / mDisplayScale.mV[VY]), ll_round((F32)size.mX / mDisplayScale.mV[VX]), 0); } LLFontManager::initClass(); @@ -1737,7 +1782,6 @@ LLViewerWindow::LLViewerWindow( } LLVertexBuffer::initClass(gSavedSettings.getBOOL("RenderVBOEnable"), gSavedSettings.getBOOL("RenderVBOMappingDisable")); LL_INFOS("RenderInit") << "LLVertexBuffer initialization done." << LL_ENDL ; - gGL.init() ; LLImageGL::initClass(LLViewerTexture::MAX_GL_IMAGE_CATEGORY) ; if (LLFeatureManager::getInstance()->isSafe() @@ -1775,8 +1819,7 @@ LLViewerWindow::LLViewerWindow( LLFontGL::initClass( gSavedSettings.getF32("FontScreenDPI"), mDisplayScale.mV[VX], mDisplayScale.mV[VY], - gDirUtilp->getAppRODataDir(), - LLUICtrlFactory::getXUIPaths()); + font_dir()); } // Create container for all sub-views LLView::Params rvp; @@ -1801,6 +1844,8 @@ LLViewerWindow::LLViewerWindow( mDebugText = new LLDebugText(this); + mWindow->postInitialized(); + } void LLViewerWindow::initGLDefaults() @@ -2036,8 +2081,6 @@ void LLViewerWindow::adjustRectanglesForFirstUse(const LLRect& window) adjust_rect_top_right("FloaterMiniMapRect", window); - adjust_rect_top_right("FloaterLagMeter", window); - adjust_rect_top_left("FloaterBuildOptionsRect", window); adjust_rect_bottom_left("FloaterActiveSpeakersRect", window); @@ -2220,17 +2263,17 @@ void LLViewerWindow::shutdownViews() { gMorphView->setVisible(FALSE); } - llinfos << "Global views cleaned." << llendl ; + LL_INFOS() << "Global views cleaned." << LL_ENDL ; // DEV-40930: Clear sModalStack. Otherwise, any LLModalDialog left open // will crump with LL_ERRS. LLModalDialog::shutdownModals(); - llinfos << "LLModalDialog shut down." << llendl; + LL_INFOS() << "LLModalDialog shut down." << LL_ENDL; // Delete all child views. delete mRootView; mRootView = NULL; - llinfos << "RootView deleted." << llendl ; + LL_INFOS() << "RootView deleted." << LL_ENDL ; if(LLMenuOptionPathfindingRebakeNavmesh::instanceExists()) LLMenuOptionPathfindingRebakeNavmesh::getInstance()->quit(); @@ -2264,12 +2307,12 @@ void LLViewerWindow::shutdownGL() gSky.cleanup(); stop_glerror(); - llinfos << "Cleaning up pipeline" << llendl; + LL_INFOS() << "Cleaning up pipeline" << LL_ENDL; gPipeline.cleanup(); stop_glerror(); //MUST clean up pipeline before cleaning up wearables - llinfos << "Cleaning up wearables" << llendl; + LL_INFOS() << "Cleaning up wearables" << LL_ENDL; LLWearableList::instance().cleanup() ; gTextureList.shutdown(); @@ -2283,12 +2326,12 @@ void LLViewerWindow::shutdownGL() LLViewerTextureManager::cleanup() ; LLImageGL::cleanupClass() ; - llinfos << "All textures and llimagegl images are destroyed!" << llendl ; + LL_INFOS() << "All textures and llimagegl images are destroyed!" << LL_ENDL ; - llinfos << "Cleaning up select manager" << llendl; + LL_INFOS() << "Cleaning up select manager" << LL_ENDL; LLSelectMgr::getInstance()->cleanup(); - llinfos << "Stopping GL during shutdown" << llendl; + LL_INFOS() << "Stopping GL during shutdown" << LL_ENDL; if (!gNoRender) { stopGL(FALSE); @@ -2299,13 +2342,13 @@ void LLViewerWindow::shutdownGL() LLVertexBuffer::cleanupClass(); - llinfos << "LLVertexBuffer cleaned." << llendl ; + LL_INFOS() << "LLVertexBuffer cleaned." << LL_ENDL ; } // shutdownViews() and shutdownGL() need to be called first LLViewerWindow::~LLViewerWindow() { - llinfos << "Destroying Window" << llendl; + LL_INFOS() << "Destroying Window" << LL_ENDL; destroyWindow(); delete mDebugText; @@ -2365,7 +2408,7 @@ void LLViewerWindow::reshape(S32 width, S32 height) // reshape messages. We don't care about these, and we // don't want to send messages because the message system // may have been destructed. - if (!LLApp::isExiting()) + if (!LLApp::isExiting()/* && !gGLManager.mIsDisabled*/) { if (gNoRender) { @@ -2373,7 +2416,7 @@ void LLViewerWindow::reshape(S32 width, S32 height) } gWindowResized = TRUE; - glViewport(0, 0, width, height ); + gGL.setViewport(0, 0, width, height ); if (height > 0) { @@ -2398,14 +2441,15 @@ void LLViewerWindow::reshape(S32 width, S32 height) LLUI::setScaleFactor(mDisplayScale); // update our window rectangle - mWindowRectScaled.mRight = mWindowRectScaled.mLeft + llround((F32)width / mDisplayScale.mV[VX]); - mWindowRectScaled.mTop = mWindowRectScaled.mBottom + llround((F32)height / mDisplayScale.mV[VY]); + mWindowRectScaled.mRight = mWindowRectScaled.mLeft + ll_round((F32)width / mDisplayScale.mV[VX]); + mWindowRectScaled.mTop = mWindowRectScaled.mBottom + ll_round((F32)height / mDisplayScale.mV[VY]); setup2DViewport(); // Inform lower views of the change // round up when converting coordinates to make sure there are no gaps at edge of window LLView::sForceReshape = display_scale_changed; + if (/*display_scale_changed && */gSavedSettings.getBOOL("LiruResizeRootWithScreen")) // Singu Note: Nasty hack to keep floaters from repositioning on window resize. mRootView->reshape(llceil((F32)width / mDisplayScale.mV[VX]), llceil((F32)height / mDisplayScale.mV[VY])); LLView::sForceReshape = FALSE; @@ -2536,8 +2580,6 @@ void LLViewerWindow::draw() LLView::sIsDrawing = TRUE; #endif stop_glerror(); - - LLUI::setLineWidth(1.f); LLUI::setLineWidth(1.f); // Reset any left-over transforms @@ -2559,8 +2601,8 @@ void LLViewerWindow::draw() microsecondsToTimecodeString(gFrameTime,text); const LLFontGL* font = LLFontGL::getFontSansSerif(); font->renderUTF8(text, 0, - llround((getWindowWidthScaled()/2)-100.f), - llround((getWindowHeightScaled()-60.f)), + ll_round((getWindowWidthScaled()/2)-100.f), + ll_round((getWindowHeightScaled()-60.f)), LLColor4( 1.f, 1.f, 1.f, 1.f ), LLFontGL::LEFT, LLFontGL::TOP); } @@ -2600,7 +2642,8 @@ void LLViewerWindow::draw() // Draw tool specific overlay on world LLToolMgr::getInstance()->getCurrentTool()->draw(); - if( gAgentCamera.cameraMouselook() ) + static LLCachedControl drawMouselookInst(gSavedSettings, "AlchemyMouselookInstructions", true); + if (drawMouselookInst && (gAgentCamera.cameraMouselook())) { drawMouselookInstructions(); stop_glerror(); @@ -2660,7 +2703,7 @@ void LLViewerWindow::draw() const S32 DIST_FROM_TOP = 20; LLFontGL::getFontSansSerifBig()->renderUTF8( mOverlayTitle, 0, - llround( getWindowWidthScaled() * 0.5f), + ll_round( getWindowWidthScaled() * 0.5f), getWindowHeightScaled() - DIST_FROM_TOP, LLColor4(1, 1, 1, 0.4f), LLFontGL::HCENTER, LLFontGL::TOP); @@ -2680,6 +2723,46 @@ void LLViewerWindow::draw() #endif } +// Takes a single keyup event, usually when UI is visible +BOOL LLViewerWindow::handleKeyUp(KEY key, MASK mask) +{ + LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus(); + + if (keyboard_focus + && !(mask & (MASK_CONTROL | MASK_ALT)) + && !gFocusMgr.getKeystrokesOnly()) + { + // We have keyboard focus, and it's not an accelerator + if (keyboard_focus && keyboard_focus->wantsKeyUpKeyDown()) + { + return keyboard_focus->handleKeyUp(key, mask, FALSE); + } + else if (key < 0x80) + { + // Not a special key, so likely (we hope) to generate a character. Let it fall through to character handler first. + return (gFocusMgr.getKeyboardFocus() != NULL); + } + } + + if (keyboard_focus) + { + if (keyboard_focus->handleKeyUp(key, mask, FALSE)) + { + LL_DEBUGS() << "LLviewerWindow::handleKeyUp - in 'traverse up' - no loops seen... just called keyboard_focus->handleKeyUp an it returned true" << LL_ENDL; + //LLViewerEventRecorder::instance().logKeyEvent(key, mask); + return TRUE; + } + else { + LL_DEBUGS() << "LLviewerWindow::handleKeyUp - in 'traverse up' - no loops seen... just called keyboard_focus->handleKeyUp an it returned FALSE" << LL_ENDL; + } + } + + // don't pass keys on to world when something in ui has focus + return gFocusMgr.childHasKeyboardFocus(mRootView) + || LLMenuGL::getKeyboardMode() + || (gMenuBarView && gMenuBarView->getHighlightedItem() && gMenuBarView->getHighlightedItem()->isActive()); +} + // Takes a single keydown event, usually when UI is visible BOOL LLViewerWindow::handleKey(KEY key, MASK mask) { @@ -2698,7 +2781,11 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask) && !gFocusMgr.getKeystrokesOnly()) { // We have keyboard focus, and it's not an accelerator - if (key < 0x80) + if (gFocusMgr.getKeyboardFocus() && gFocusMgr.getKeyboardFocus()->wantsKeyUpKeyDown()) + { + return gFocusMgr.getKeyboardFocus()->handleKey(key, mask, FALSE ); + } + else if (key < 0x80) { // Not a special key, so likely (we hope) to generate a character. Let it fall through to character handler first. return (gFocusMgr.getKeyboardFocus() != NULL); @@ -2706,12 +2793,9 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask) } // HACK look for UI editing keys - if (LLView::sEditingUI) + if (LLView::sEditingUI && LLFloaterEditUI::processKeystroke(key, mask)) { - if (LLFloaterEditUI::processKeystroke(key, mask)) - { - return TRUE; - } + return TRUE; } // Explicit hack for debug menu. @@ -2719,68 +2803,78 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask) (MASK_CONTROL & mask) && ('D' == key || 'd' == key)) { - toggle_debug_menus(NULL); + if (gSavedSettings.getBOOL("LiruUseAdvancedMenuShortcut")) + toggle_debug_menus(NULL); } - // Explicit hack for debug menu. - //Singu note: We do not use the ForceShowGrid setting. Grid selection should always be visible. - /*if ((mask == (MASK_SHIFT | MASK_CONTROL)) && - ('G' == key || 'g' == key)) - { - if (LLStartUp::getStartupState() < STATE_LOGIN_CLEANUP) //on splash page - { - BOOL visible = ! gSavedSettings.getBOOL("ForceShowGrid"); - gSavedSettings.setBOOL("ForceShowGrid", visible); - - // Initialize visibility (and don't force visibility - use prefs) - LLPanelLogin::updateLocationSelectorsVisibility(); - } - }*/ - - // Debugging view for unified notifications: CTRL-SHIFT-5 - // *FIXME: Having this special-cased right here (just so this can be invoked from the login screen) sucks. - if ((MASK_SHIFT & mask) - && (!(MASK_ALT & mask)) - && (MASK_CONTROL & mask) - && ('5' == key)) + // handle shift-escape key (reset camera view) + if (key == KEY_ESCAPE && mask == MASK_SHIFT) { - LLFloaterNotificationConsole::showInstance(); + handle_reset_view(); return TRUE; } - // handle shift-escape key (reset camera view) - if (key == KEY_ESCAPE && mask == MASK_SHIFT) + // let menus handle navigation keys for navigation + if ((gMenuBarView && gMenuBarView->handleKey(key, mask, TRUE)) + || (gLoginMenuBarView && gLoginMenuBarView->handleKey(key, mask, TRUE)) + || (gMenuHolder && gMenuHolder->handleKey(key, mask, TRUE))) { - handle_reset_view(); return TRUE; } - // handle escape key - //if (key == KEY_ESCAPE && mask == MASK_NONE) - //{ + LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus(); - // *TODO: get this to play well with mouselook and hidden - // cursor modes, etc, and re-enable. - //if (gFocusMgr.getMouseCapture()) - //{ - // gFocusMgr.setMouseCapture(NULL); - // return TRUE; - //} - //} + // give menus a chance to handle modified (Ctrl, Alt) shortcut keys before current focus + // as long as focus isn't locked + if (mask & (MASK_CONTROL | MASK_ALT) && !gFocusMgr.focusLocked()) + { + // Check the current floater's menu first, if it has one. + if (gFocusMgr.keyboardFocusHasAccelerators() + && keyboard_focus + && keyboard_focus->handleKey(key,mask,FALSE)) + { + return TRUE; + } - // let menus handle navigation keys - if (gMenuBarView && gMenuBarView->handleKey(key, mask, TRUE)) + /* Singu Note: This caused a bug where the menu ate keys before parents of keyboard_focus for some reason, breaking multifloaters usage of ctrl-w to close their selected child floater + if ((gMenuBarView && gMenuBarView->handleAcceleratorKey(key, mask)) + || (gLoginMenuBarView && gLoginMenuBarView->handleAcceleratorKey(key, mask))) + { + return TRUE; + } + */ + } + + // give floaters first chance to handle TAB key + // so frontmost floater gets focus + // if nothing has focus, go to first or last UI element as appropriate + if (key == KEY_TAB && (mask & MASK_CONTROL || gFocusMgr.getKeyboardFocus() == NULL)) { + if (gMenuHolder) gMenuHolder->hideMenus(); + + // if CTRL-tabbing (and not just TAB with no focus), go into window cycle mode + gFloaterView->setCycleMode((mask & MASK_CONTROL) != 0); + + // do CTRL-TAB and CTRL-SHIFT-TAB logic + if (mask & MASK_SHIFT) + { + mRootView->focusPrevRoot(); + } + else + { + mRootView->focusNextRoot(); + } return TRUE; } - // let menus handle navigation keys - if (gLoginMenuBarView && gLoginMenuBarView->handleKey(key, mask, TRUE)) + /* Singu TODO: gEditMenu? + // hidden edit menu for cut/copy/paste + if (gEditMenu && gEditMenu->handleAcceleratorKey(key, mask)) { return TRUE; } + */ // Traverses up the hierarchy - LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus(); if( keyboard_focus ) { // arrow keys move avatar while chatting hack @@ -2791,10 +2885,13 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask) if (gChatBar->getCurrentChat().empty() || gSavedSettings.getBOOL("ArrowKeysMoveAvatar")) { - // Singu Note: We do this differently from LL to preserve the Ctrl- behavior in the chatbar + /* Singu Note: We do this differently from LL to preserve the Ctrl- behavior in the chatbar, and we don't need alt because we're not CHUI // let Control-Up and Control-Down through for chat line history, - //if (!(key == KEY_UP && mask == MASK_CONTROL) - // && !(key == KEY_DOWN && mask == MASK_CONTROL)) + if (!(key == KEY_UP && mask == MASK_CONTROL) + && !(key == KEY_DOWN && mask == MASK_CONTROL) + && !(key == KEY_UP && mask == MASK_ALT) + && !(key == KEY_DOWN && mask == MASK_ALT)) + */ { switch(key) { @@ -2816,6 +2913,7 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask) } } } + if (keyboard_focus->handleKey(key, mask, FALSE)) { return TRUE; @@ -2840,43 +2938,20 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask) return TRUE; } - // Topmost view gets a chance before the hierarchy - // *FIX: get rid of this? - //LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl(); - //if (top_ctrl) - //{ - // if( top_ctrl->handleKey( key, mask, TRUE ) ) - // { - // return TRUE; - // } - //} - - // give floaters first chance to handle TAB key - // so frontmost floater gets focus - if (key == KEY_TAB) + // If "Pressing letter keys starts local chat" option is selected, we are not in mouselook, + // no view has keyboard focus, this is a printable character key (and no modifier key is + // pressed except shift), then give focus to nearby chat (STORM-560) + if (gSavedSettings.getBOOL("LetterKeysFocusChatBar") && !gAgentCamera.cameraMouselook() && + !keyboard_focus && key < 0x80 && (mask == MASK_NONE || mask == MASK_SHIFT)) { - // if nothing has focus, go to first or last UI element as appropriate - if (mask & MASK_CONTROL || gFocusMgr.getKeyboardFocus() == NULL) { - if (gMenuHolder) gMenuHolder->hideMenus(); - - // if CTRL-tabbing (and not just TAB with no focus), go into window cycle mode - gFloaterView->setCycleMode((mask & MASK_CONTROL) != 0); - - // do CTRL-TAB and CTRL-SHIFT-TAB logic - if (mask & MASK_SHIFT) - { - mRootView->focusPrevRoot(); - } - else - { - mRootView->focusNextRoot(); - } + // passing NULL here, character will be added later when it is handled by character handler. + LLChatBar::startChat(NULL); return TRUE; } } - - // give menus a chance to handle keys + + // give menus a chance to handle unmodified accelerator keys if ((gMenuBarView && gMenuBarView->handleAcceleratorKey(key, mask)) ||(gLoginMenuBarView && gLoginMenuBarView->handleAcceleratorKey(key, mask))) { @@ -2953,7 +3028,7 @@ void LLViewerWindow::handleScrollWheel(S32 clicks) mouse_captor->handleScrollWheel(local_x, local_y, clicks); if (LLView::sDebugMouseHandling) { - llinfos << "Scroll Wheel handled by captor " << mouse_captor->getName() << llendl; + LL_INFOS() << "Scroll Wheel handled by captor " << mouse_captor->getName() << LL_ENDL; } return; } @@ -2971,13 +3046,13 @@ void LLViewerWindow::handleScrollWheel(S32 clicks) { if (LLView::sDebugMouseHandling) { - llinfos << "Scroll Wheel" << LLView::sMouseHandlerMessage << llendl; + LL_INFOS() << "Scroll Wheel" << LLView::sMouseHandlerMessage << LL_ENDL; } return; } else if (LLView::sDebugMouseHandling) { - llinfos << "Scroll Wheel not handled by view" << llendl; + LL_INFOS() << "Scroll Wheel not handled by view" << LL_ENDL; } // Zoom the camera in and out behavior @@ -3016,8 +3091,8 @@ void LLViewerWindow::moveCursorToCenter() // event processing. void LLViewerWindow::updateUI() { - static LLFastTimer::DeclareTimer ftm("Update UI"); - LLFastTimer t(ftm); + static LLTrace::BlockTimerStatHandle ftm("Update UI"); + LL_RECORD_BLOCK_TIME(ftm); static std::string last_handle_msg; // animate layout stacks so we have up to date rect for world view @@ -3033,14 +3108,15 @@ void LLViewerWindow::updateUI() if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RAYCAST)) { gDebugRaycastFaceHit = -1; - gDebugRaycastObject = cursorIntersect(-1, -1, 512.f, NULL, -1, FALSE, + gDebugRaycastObject = cursorIntersect(-1, -1, 512.f, NULL, -1, FALSE, FALSE, &gDebugRaycastFaceHit, &gDebugRaycastIntersection, &gDebugRaycastTexCoord, &gDebugRaycastNormal, - &gDebugRaycastBinormal, + &gDebugRaycastTangent, &gDebugRaycastStart, &gDebugRaycastEnd); + gDebugRaycastParticle = gPipeline.lineSegmentIntersectParticle(gDebugRaycastStart, gDebugRaycastEnd, &gDebugRaycastParticleIntersection, NULL); } updateMouseDelta(); @@ -3183,6 +3259,7 @@ void LLViewerWindow::updateUI() // only handle hover events when UI is enabled // if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI)) + if (mMouseInWindow) { if( mouse_captor ) @@ -3194,12 +3271,12 @@ void LLViewerWindow::updateUI() handled = mouse_captor->handleHover(local_x, local_y, mask); if (LLView::sDebugMouseHandling) { - llinfos << "Hover handled by captor " << mouse_captor->getName() << llendl; + LL_INFOS() << "Hover handled by captor " << mouse_captor->getName() << LL_ENDL; } if( !handled ) { - lldebugst(LLERR_USER_INPUT) << "hover not handled by mouse captor" << llendl; + LL_DEBUGS("UserInput") << "hover not handled by mouse captor" << LL_ENDL; } } else @@ -3220,7 +3297,7 @@ void LLViewerWindow::updateUI() if (LLView::sDebugMouseHandling && LLView::sMouseHandlerMessage != last_handle_msg) { last_handle_msg = LLView::sMouseHandlerMessage; - llinfos << "Hover" << LLView::sMouseHandlerMessage << llendl; + LL_INFOS() << "Hover" << LLView::sMouseHandlerMessage << LL_ENDL; } handled = TRUE; } @@ -3229,14 +3306,14 @@ void LLViewerWindow::updateUI() if (last_handle_msg != LLStringUtil::null) { last_handle_msg.clear(); - llinfos << "Hover not handled by view" << llendl; + LL_INFOS() << "Hover not handled by view" << LL_ENDL; } } } if( !handled ) { - lldebugst(LLERR_USER_INPUT) << "hover not handled by top view or root" << llendl; + LL_DEBUGS("UserInput") << "hover not handled by top view or root" << LL_ENDL; } } @@ -3337,40 +3414,9 @@ void LLViewerWindow::updateUI() { LLSelectMgr::getInstance()->deselectUnused(); } - - // per frame picking - for tooltips and changing cursor over interactive objects - static S32 previous_x = -1; - static S32 previous_y = -1; - static BOOL mouse_moved_since_pick = FALSE; - - if ((previous_x != x) || (previous_y != y)) - mouse_moved_since_pick = TRUE; - - static const LLCachedControl picks_moving("PicksPerSecondMouseMoving",5.f); - static const LLCachedControl picks_stationary("PicksPerSecondMouseStationary",0.f); - if( !getCursorHidden() - // When in-world media is in focus, pick every frame so that browser mouse-overs, dragging scrollbars, etc. work properly. - && (LLViewerMediaFocus::getInstance()->getFocus() - || ((mouse_moved_since_pick) && (picks_moving > 0.0) && (mPickTimer.getElapsedTimeF32() > 1.0f / picks_moving)) - || ((!mouse_moved_since_pick) && (picks_stationary > 0.0) && (mPickTimer.getElapsedTimeF32() > 1.0f / picks_stationary)))) - { - mouse_moved_since_pick = FALSE; - mPickTimer.reset(); - pickAsync(getCurrentMouseX(), getCurrentMouseY(), mask, hoverPickCallback, TRUE, TRUE); - } - - previous_x = x; - previous_y = y; - return; } -/* static */ -void LLViewerWindow::hoverPickCallback(const LLPickInfo& pick_info) -{ - gViewerWindow->mHoverPick = pick_info; -} - void LLViewerWindow::updateLayout() { static const LLCachedControl freeze_time("FreezeTime",0); @@ -3397,10 +3443,8 @@ void LLViewerWindow::updateLayout() || (tool != LLToolPie::getInstance() // not default tool && tool != LLToolCompGun::getInstance() // not coming out of mouselook && !suppress_toolbox // not override in third person - && LLToolMgr::getInstance()->getCurrentToolset() != gFaceEditToolset // not special mode - && LLToolMgr::getInstance()->getCurrentToolset() != gMouselookToolset + && LLToolMgr::getInstance()->getCurrentToolset()->isShowFloaterTools() && (!captor || dynamic_cast(captor) != NULL))) // not dragging - { // Force floater tools to be visible (unless minimized) if (!gFloaterTools->getVisible()) @@ -3437,7 +3481,7 @@ void LLViewerWindow::updateLayout() } // Update rectangles for the various toolbars - if (gOverlayBar && gNotifyBoxView && gConsole && gToolBar && gHUDView) + if (gOverlayBar && gNotifyBoxView && gToolBar && gHUDView) { LLRect bar_rect(-1, STATUS_BAR_HEIGHT, getWindowWidth()+1, -1); @@ -3487,10 +3531,13 @@ void LLViewerWindow::updateLayout() { gFloaterView->setSnapOffsetBottom(0); } + } - // Always update console + // Always update console + if (gConsole) + { LLRect console_rect = getChatConsoleRect(); - console_rect.mBottom = gHUDView->getRect().mBottom + getChatConsoleBottomPad(); + if (gHUDView) console_rect.mBottom = gHUDView->getRect().mBottom + getChatConsoleBottomPad(); gConsole->reshape(console_rect.getWidth(), console_rect.getHeight()); gConsole->setRect(console_rect); } @@ -3501,7 +3548,7 @@ void LLViewerWindow::updateLayout() && gFocusMgr.getKeyboardFocus() == NULL && gChatBar->isInVisibleChain()) { - gChatBar->startChat(NULL); + LLChatBar::startChat(NULL); } } @@ -3534,10 +3581,10 @@ void LLViewerWindow::updateMouseDelta() static F32 fdy = 0.f; F32 amount = 16.f; - fdx = fdx + ((F32) dx - fdx) * llmin(gFrameIntervalSeconds*amount,1.f); - fdy = fdy + ((F32) dy - fdy) * llmin(gFrameIntervalSeconds*amount,1.f); + fdx = fdx + ((F32) dx - fdx) * llmin(gFrameIntervalSeconds.value()*amount,1.f); + fdy = fdy + ((F32) dy - fdy) * llmin(gFrameIntervalSeconds.value()*amount,1.f); - mCurrentMouseDelta.set(llround(fdx), llround(fdy)); + mCurrentMouseDelta.set(ll_round(fdx), ll_round(fdy)); mouse_vel.setVec(fdx,fdy); } else @@ -3590,6 +3637,7 @@ void LLViewerWindow::updateKeyboardFocus() cur_focus->focusFirstItem(); } } + // last ditch force of edit menu to selection manager if (LLEditMenuHandler::gEditMenuHandler == NULL && LLSelectMgr::getInstance()->getSelection()->getObjectCount()) { @@ -3628,6 +3676,7 @@ void LLViewerWindow::saveLastMouse(const LLCoordGL &point) { // Store last mouse location. // If mouse leaves window, pretend last point was on edge of window + if (point.mX < 0) { mCurrentMousePoint.mX = 0; @@ -3710,8 +3759,8 @@ void LLViewerWindow::renderSelections( BOOL for_gl_pick, BOOL pick_parcel_walls, if (LLSelectMgr::sRenderLightRadius && LLToolMgr::getInstance()->inEdit()) { gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - LLGLEnable gls_blend(GL_BLEND); - LLGLEnable gls_cull(GL_CULL_FACE); + LLGLEnable gls_blend; + LLGLEnable gls_cull; LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE); gGL.matrixMode(LLRender::MM_MODELVIEW); gGL.pushMatrix(); @@ -3872,17 +3921,24 @@ BOOL LLViewerWindow::clickPointOnSurfaceGlobal(const S32 x, const S32 y, LLViewe if (!intersect) { point_global = clickPointInWorldGlobal(x, y, objectp); - llinfos << "approx intersection at " << (objectp->getPositionGlobal() - point_global) << llendl; + LL_INFOS() << "approx intersection at " << (objectp->getPositionGlobal() - point_global) << LL_ENDL; } else { - llinfos << "good intersection at " << (objectp->getPositionGlobal() - point_global) << llendl; + LL_INFOS() << "good intersection at " << (objectp->getPositionGlobal() - point_global) << LL_ENDL; } return intersect; } -void LLViewerWindow::pickAsync(S32 x, S32 y_from_bot, MASK mask, void (*callback)(const LLPickInfo& info), BOOL pick_transparent, BOOL get_surface_info) +void LLViewerWindow::pickAsync( S32 x, + S32 y_from_bot, + MASK mask, + void (*callback)(const LLPickInfo& info), + BOOL pick_transparent, + BOOL pick_rigged, + BOOL pick_unselectable, + BOOL get_surface_info) { if (gNoRender) { @@ -3897,8 +3953,7 @@ void LLViewerWindow::pickAsync(S32 x, S32 y_from_bot, MASK mask, void (*callback // "Show Debug Alpha" means no object actually transparent pick_transparent = TRUE; } - - LLPickInfo pick_info(LLCoordGL(x, y_from_bot), mask, pick_transparent, get_surface_info, callback); + LLPickInfo pick_info(LLCoordGL(x, y_from_bot), mask, pick_transparent, pick_rigged, FALSE, get_surface_info, pick_unselectable, callback); schedulePick(pick_info); } @@ -3917,6 +3972,8 @@ void LLViewerWindow::schedulePick(LLPickInfo& pick_info) mPicks.push_back(pick_info); // delay further event processing until we receive results of pick + // only do this for async picks so that handleMouseUp won't be called + // until the pick triggered in handleMouseDown has been processed, for example mWindow->delayInputProcessing(); } @@ -3928,6 +3985,11 @@ void LLViewerWindow::performPick() return; } + if (!gFocusMgr.getAppHasFocus()) + { + return; + } + if (!mPicks.empty()) { std::vector::iterator pick_it; @@ -3957,13 +4019,18 @@ void LLViewerWindow::returnEmptyPicks() } // Performs the GL object/land pick. -LLPickInfo LLViewerWindow::pickImmediate(S32 x, S32 y_from_bot, BOOL pick_transparent) +LLPickInfo LLViewerWindow::pickImmediate(S32 x, S32 y_from_bot, BOOL pick_transparent, BOOL pick_rigged, BOOL pick_particle) { if (gNoRender) { return LLPickInfo(); } + if (!gFocusMgr.getAppHasFocus()) + { + return LLPickInfo(); + } + // push back pick info object BOOL in_build_mode = gFloaterTools && gFloaterTools->getVisible(); if (in_build_mode || LLDrawPoolAlpha::sShowDebugAlpha) @@ -3972,17 +4039,16 @@ LLPickInfo LLViewerWindow::pickImmediate(S32 x, S32 y_from_bot, BOOL pick_trans // "Show Debug Alpha" means no object actually transparent pick_transparent = TRUE; } - // shortcut queueing in mPicks and just update mLastPick in place MASK key_mask = gKeyboard->currentMask(TRUE); - mLastPick = LLPickInfo(LLCoordGL(x, y_from_bot), key_mask, pick_transparent, TRUE, NULL); + mLastPick = LLPickInfo(LLCoordGL(x, y_from_bot), key_mask, pick_transparent, pick_rigged, pick_particle, TRUE, FALSE, NULL); mLastPick.fetchResults(); return mLastPick; } LLHUDIcon* LLViewerWindow::cursorIntersectIcon(S32 mouse_x, S32 mouse_y, F32 depth, - LLVector3* intersection) + LLVector4a* intersection) { S32 x = mouse_x; S32 y = mouse_y; @@ -3994,27 +4060,31 @@ LLHUDIcon* LLViewerWindow::cursorIntersectIcon(S32 mouse_x, S32 mouse_y, F32 dep } // world coordinates of mouse + // VECTORIZE THIS LLVector3 mouse_direction_global = mouseDirectionGlobal(x,y); LLVector3 mouse_point_global = LLViewerCamera::getInstance()->getOrigin(); LLVector3 mouse_world_start = mouse_point_global; LLVector3 mouse_world_end = mouse_point_global + mouse_direction_global * depth; - return LLHUDIcon::lineSegmentIntersectAll(mouse_world_start, mouse_world_end, intersection); - + LLVector4a start, end; + start.load3(mouse_world_start.mV); + end.load3(mouse_world_end.mV); + return LLHUDIcon::lineSegmentIntersectAll(start, end, intersection); } LLViewerObject* LLViewerWindow::cursorIntersect(S32 mouse_x, S32 mouse_y, F32 depth, LLViewerObject *this_object, S32 this_face, BOOL pick_transparent, + BOOL pick_rigged, S32* face_hit, - LLVector3 *intersection, + LLVector4a *intersection, LLVector2 *uv, - LLVector3 *normal, - LLVector3 *binormal, - LLVector3* start, - LLVector3* end) + LLVector4a *normal, + LLVector4a *tangent, + LLVector4a* start, + LLVector4a* end) { S32 x = mouse_x; S32 y = mouse_y; @@ -4049,17 +4119,27 @@ LLViewerObject* LLViewerWindow::cursorIntersect(S32 mouse_x, S32 mouse_y, F32 de if (!LLViewerJoystick::getInstance()->getOverrideCamera()) { //always set raycast intersection to mouse_world_end unless //flycam is on (for DoF effect) - gDebugRaycastIntersection = mouse_world_end; + gDebugRaycastIntersection.load3(mouse_world_end.mV); } + LLVector4a mw_start; + mw_start.load3(mouse_world_start.mV); + LLVector4a mw_end; + mw_end.load3(mouse_world_end.mV); + + LLVector4a mh_start; + mh_start.load3(mouse_hud_start.mV); + LLVector4a mh_end; + mh_end.load3(mouse_hud_end.mV); + if (start) { - *start = mouse_world_start; + *start = mw_start; } if (end) { - *end = mouse_world_end; + *end = mw_end; } LLViewerObject* found = NULL; @@ -4068,25 +4148,25 @@ LLViewerObject* LLViewerWindow::cursorIntersect(S32 mouse_x, S32 mouse_y, F32 de { if (this_object->isHUDAttachment()) // is a HUD object? { - if (this_object->lineSegmentIntersect(mouse_hud_start, mouse_hud_end, this_face, pick_transparent, - face_hit, intersection, uv, normal, binormal)) + if (this_object->lineSegmentIntersect(mh_start, mh_end, this_face, pick_transparent, pick_rigged, + face_hit, intersection, uv, normal, tangent)) { found = this_object; } - } + } else // is a world object { - if (this_object->lineSegmentIntersect(mouse_world_start, mouse_world_end, this_face, pick_transparent, - face_hit, intersection, uv, normal, binormal)) + if (this_object->lineSegmentIntersect(mw_start, mw_end, this_face, pick_transparent, pick_rigged, + face_hit, intersection, uv, normal, tangent)) { found = this_object; } - } - } + } + } else // check ALL objects { - found = gPipeline.lineSegmentIntersectInHUD(mouse_hud_start, mouse_hud_end, pick_transparent, - face_hit, intersection, uv, normal, binormal); + found = gPipeline.lineSegmentIntersectInHUD(mh_start, mh_end, pick_transparent, + face_hit, intersection, uv, normal, tangent); // [RLVa:KB] - Checked: 2009-12-28 (RLVa-1.1.0k) | Modified: RLVa-1.1.0k if ( (rlv_handler_t::isEnabled()) && (LLToolCamera::getInstance()->hasMouseCapture()) && (gKeyboard->currentMask(TRUE) & MASK_ALT) ) @@ -4097,8 +4177,13 @@ LLViewerObject* LLViewerWindow::cursorIntersect(S32 mouse_x, S32 mouse_y, F32 de if (!found) // if not found in HUD, look in world: { - found = gPipeline.lineSegmentIntersectInWorld(mouse_world_start, mouse_world_end, pick_transparent, - face_hit, intersection, uv, normal, binormal); + found = gPipeline.lineSegmentIntersectInWorld(mw_start, mw_end, pick_transparent, pick_rigged, + face_hit, intersection, uv, normal, tangent); + + if (found && !pick_transparent) + { + gDebugRaycastIntersection = *intersection; + } // [RLVa:KB] - Checked: 2010-01-02 (RLVa-1.1.0l) | Added: RLVa-1.1.0l #ifdef RLV_EXTENSION_CMD_INTERACT @@ -4118,6 +4203,10 @@ LLViewerObject* LLViewerWindow::cursorIntersect(S32 mouse_x, S32 mouse_y, F32 de } #endif // RLV_EXTENSION_CMD_INTERACT // [/RLVa:KB] + if (found && !pick_transparent) + { + gDebugRaycastIntersection = *intersection; + } } } @@ -4233,7 +4322,7 @@ BOOL LLViewerWindow::mousePointOnPlaneGlobal(LLVector3d& point, const S32 x, con // Returns global position -BOOL LLViewerWindow::mousePointOnLandGlobal(const S32 x, const S32 y, LLVector3d *land_position_global) +BOOL LLViewerWindow::mousePointOnLandGlobal(const S32 x, const S32 y, LLVector3d *land_position_global, BOOL ignore_distance) { LLVector3 mouse_direction_global = mouseDirectionGlobal(x,y); F32 mouse_dir_scale; @@ -4242,6 +4331,7 @@ BOOL LLViewerWindow::mousePointOnLandGlobal(const S32 x, const S32 y, LLVector3d F32 land_z; const F32 FIRST_PASS_STEP = 1.0f; // meters const F32 SECOND_PASS_STEP = 0.1f; // meters + const F32 draw_distance = ignore_distance ? MAX_FAR_CLIP : (gAgentCamera.mDrawDistance * 4); LLVector3d camera_pos_global; camera_pos_global = gAgentCamera.getCameraPositionGlobal(); @@ -4249,7 +4339,7 @@ BOOL LLViewerWindow::mousePointOnLandGlobal(const S32 x, const S32 y, LLVector3d LLVector3 probe_point_region; // walk forwards to find the point - for (mouse_dir_scale = FIRST_PASS_STEP; mouse_dir_scale < gAgentCamera.mDrawDistance; mouse_dir_scale += FIRST_PASS_STEP) + for (mouse_dir_scale = FIRST_PASS_STEP; mouse_dir_scale < draw_distance; mouse_dir_scale += FIRST_PASS_STEP) { LLVector3d mouse_direction_global_d; mouse_direction_global_d.setVec(mouse_direction_global * mouse_dir_scale); @@ -4268,13 +4358,13 @@ BOOL LLViewerWindow::mousePointOnLandGlobal(const S32 x, const S32 y, LLVector3d S32 grids_per_edge = (S32) regionp->getLand().mGridsPerEdge; if ((i >= grids_per_edge) || (j >= grids_per_edge)) { - //llinfos << "LLViewerWindow::mousePointOnLand probe_point is out of region" << llendl; + //LL_INFOS() << "LLViewerWindow::mousePointOnLand probe_point is out of region" << LL_ENDL; continue; } land_z = regionp->getLand().resolveHeightRegion(probe_point_region); - //llinfos << "mousePointOnLand initial z " << land_z << llendl; + //LL_INFOS() << "mousePointOnLand initial z " << land_z << LL_ENDL; if (probe_point_region.mV[VZ] < land_z) { @@ -4315,7 +4405,7 @@ BOOL LLViewerWindow::mousePointOnLandGlobal(const S32 x, const S32 y, LLVector3d j = (S32) (local_probe_point.mV[VY]/regionp->getLand().getMetersPerGrid()); if ((i >= regionp->getLand().mGridsPerEdge) || (j >= regionp->getLand().mGridsPerEdge)) { - // llinfos << "LLViewerWindow::mousePointOnLand probe_point is out of region" << llendl; + // LL_INFOS() << "LLViewerWindow::mousePointOnLand probe_point is out of region" << LL_ENDL; continue; } land_z = regionp->getLand().mSurfaceZ[ i + j * (regionp->getLand().mGridsPerEdge) ]; @@ -4323,7 +4413,7 @@ BOOL LLViewerWindow::mousePointOnLandGlobal(const S32 x, const S32 y, LLVector3d land_z = regionp->getLand().resolveHeightRegion(probe_point_region); - //llinfos << "mousePointOnLand refine z " << land_z << llendl; + //LL_INFOS() << "mousePointOnLand refine z " << land_z << LL_ENDL; if (probe_point_region.mV[VZ] < land_z) { @@ -4453,17 +4543,23 @@ void LLViewerWindow::movieSize(S32 new_width, S32 new_height) BORDERHEIGHT = size.mY- y; LLCoordScreen new_size(new_width + BORDERWIDTH, new_height + BORDERHEIGHT); - BOOL disable_sync = gSavedSettings.getBOOL("DisableVerticalSync"); + + S32 vsync_mode = gSavedSettings.getS32("SHRenderVsyncMode"); + if(vsync_mode == -1 && !gGLManager.mHasAdaptiveVsync) + { + vsync_mode = 0; //Disable vsync if adaptive is desired yet isn't supported. + } + if (gViewerWindow->getWindow()->getFullscreen()) { - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); + LLGLStateValidator::checkStates(); + LLGLStateValidator::checkTextureChannels(); gViewerWindow->changeDisplaySettings(FALSE, new_size, - disable_sync, + vsync_mode, TRUE); - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); + LLGLStateValidator::checkStates(); + LLGLStateValidator::checkTextureChannels(); } else { @@ -4474,7 +4570,7 @@ void LLViewerWindow::movieSize(S32 new_width, S32 new_height) BOOL LLViewerWindow::saveSnapshot( const std::string& filepath, S32 image_width, S32 image_height, BOOL show_ui, BOOL do_rebuild, ESnapshotType type) { - llinfos << "Saving snapshot to: " << filepath << llendl; + LL_INFOS() << "Saving snapshot to: " << filepath << LL_ENDL; LLPointer raw = new LLImageRaw; BOOL success = rawSnapshot(raw, image_width, image_height, (F32)image_width / image_height, show_ui, do_rebuild); @@ -4489,12 +4585,12 @@ BOOL LLViewerWindow::saveSnapshot( const std::string& filepath, S32 image_width, } else { - llwarns << "Unable to encode bmp snapshot" << llendl; + LL_WARNS() << "Unable to encode bmp snapshot" << LL_ENDL; } } else { - llwarns << "Unable to capture raw snapshot" << llendl; + LL_WARNS() << "Unable to capture raw snapshot" << LL_ENDL; } return success; @@ -4673,7 +4769,7 @@ bool LLViewerWindow::rawRawSnapshot(LLImageRaw *raw, { if(!LLMemory::tryToAlloc(NULL, image_width * image_height * 3)) { - llwarns << "No enough memory to take the snapshot with size (w : h): " << image_width << " : " << image_height << llendl ; + LL_WARNS() << "No enough memory to take the snapshot with size (w : h): " << image_width << " : " << image_height << LL_ENDL ; return false; //there is no enough memory for taking this snapshot. } } @@ -4681,6 +4777,7 @@ bool LLViewerWindow::rawRawSnapshot(LLImageRaw *raw, // PRE SNAPSHOT gDisplaySwapBuffers = FALSE; + gGL.syncContextState(); glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); setCursor(UI_CURSOR_WAIT); @@ -4743,7 +4840,9 @@ bool LLViewerWindow::rawRawSnapshot(LLImageRaw *raw, S32 original_width = 0; S32 original_height = 0; bool reset_deferred = false; + LLRenderTarget scratch_space; + if ((image_width > window_width || image_height > window_height) && LLPipeline::sRenderDeferred && !show_ui) { if (scratch_space.allocate(image_width, image_height, GL_RGBA, true, true)) @@ -4793,10 +4892,10 @@ bool LLViewerWindow::rawRawSnapshot(LLImageRaw *raw, // However, if the buffer turns out to be too large, then clamp it to max_size. scale_factor = llmin(max_size / snapshot_width, max_size / snapshot_height)) // Clamp { - image_buffer_x = llround(unscaled_image_buffer_x * scale_factor); - image_buffer_y = llround(unscaled_image_buffer_y * scale_factor); - S32 image_size_x = llround(snapshot_width * scale_factor); - S32 image_size_y = llround(snapshot_width * scale_factor); + image_buffer_x = ll_round(unscaled_image_buffer_x * scale_factor); + image_buffer_y = ll_round(unscaled_image_buffer_y * scale_factor); + S32 image_size_x = ll_round(snapshot_width * scale_factor); + S32 image_size_y = ll_round(snapshot_width * scale_factor); if (llmax(image_size_x, image_size_y) > max_size && // Boundary check to avoid memory overflow. internal_scale <= 1.f && !reset_deferred) // SHY_MOD: If supersampling... Don't care about max_size. { @@ -4959,6 +5058,7 @@ bool LLViewerWindow::rawRawSnapshot(LLImageRaw *raw, LLHUDObject::reshapeAll(); } + setCursor(UI_CURSOR_ARROW); if (do_rebuild) @@ -5039,44 +5139,52 @@ void LLViewerWindow::destroyWindow() void LLViewerWindow::drawMouselookInstructions() { - static const F32 INSTRUCTIONS_OPAQUE_TIME = 10.f; - static const F32 INSTRUCTIONS_FADE_TIME = 5.f; - - F32 mouselook_duration = gAgentCamera.getMouseLookDuration(); - if( mouselook_duration >= (INSTRUCTIONS_OPAQUE_TIME+INSTRUCTIONS_OPAQUE_TIME) ) - return; - - F32 alpha = 1.f; - - if( mouselook_duration > INSTRUCTIONS_OPAQUE_TIME) //instructions are fading - { - alpha = (F32) sqrt(1.f-pow(((mouselook_duration-INSTRUCTIONS_OPAQUE_TIME)/INSTRUCTIONS_FADE_TIME),2.f)); - } - + // // Draw instructions for mouselook ("Press ESC to leave Mouselook" in a box at the top of the screen.) - const std::string instructions = LLTrans::getString("LeaveMouselook"); - const LLFontGL* font = LLResMgr::getInstance()->getRes( LLFONT_SANSSERIF ); - - const S32 INSTRUCTIONS_PAD = 5; - LLRect instructions_rect; - instructions_rect.setLeftTopAndSize( - INSTRUCTIONS_PAD, - getWindowHeight() - INSTRUCTIONS_PAD, - font->getWidth( instructions ) + 2 * INSTRUCTIONS_PAD, - llround(font->getLineHeight() + 2 * INSTRUCTIONS_PAD)); - - { - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gGL.color4f( 0.9f, 0.9f, 0.9f, alpha ); - gl_rect_2d( instructions_rect ); - } - - font->renderUTF8( - instructions, 0, - instructions_rect.mLeft + INSTRUCTIONS_PAD, - instructions_rect.mTop - INSTRUCTIONS_PAD, - LLColor4( 0.0f, 0.0f, 0.0f, alpha ), - LLFontGL::LEFT, LLFontGL::TOP); + const LLFontGL* font = LLFontGL::getFontSansSerifBig(); + + //to be on top of Bottom bar when it is opened + const S32 INSTRUCTIONS_PAD = getWorldViewRectScaled().mTop - 15; + const S32 text_pos_start = getWorldViewRectScaled().getCenterX() - 150; + if (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) + { + const LLVector3& vec = gAgent.getPositionAgent(); + font->renderUTF8( + llformat("X: %.2f", vec.mV[VX]), 0, + text_pos_start, + INSTRUCTIONS_PAD, + LLColor4(1.0f, 0.5f, 0.5f, 0.5), + LLFontGL::HCENTER, LLFontGL::TOP, + LLFontGL::BOLD, LLFontGL::DROP_SHADOW_SOFT); + font->renderUTF8( + llformat("Y: %.2f", vec.mV[VY]), 0, + text_pos_start + 100, + INSTRUCTIONS_PAD, + LLColor4(0.5f, 1.0f, 0.5f, 0.5), + LLFontGL::HCENTER, LLFontGL::TOP, + LLFontGL::BOLD, LLFontGL::DROP_SHADOW_SOFT); + font->renderUTF8( + llformat("Z: %.2f", vec.mV[VZ]), 0, + text_pos_start + 200, + INSTRUCTIONS_PAD, + LLColor4(0.5f, 0.5f, 1.0f, 0.5), + LLFontGL::HCENTER, LLFontGL::TOP, + LLFontGL::BOLD, LLFontGL::DROP_SHADOW_SOFT); + } + const LLViewerParcelMgr& vpm = LLViewerParcelMgr::instance(); + const bool allow_damage = vpm.allowAgentDamage(gAgent.getRegion(), vpm.getAgentParcel()); + if (allow_damage) + { + const S32 health = gStatusBar ? gStatusBar->getHealth() : -1; + font->renderUTF8( + llformat("HP: %d%%", health), 0, + text_pos_start + 300, + INSTRUCTIONS_PAD, + LLColor4(1.0f, 1.0f, 1.0f, 0.5), + LLFontGL::HCENTER, LLFontGL::TOP, + LLFontGL::BOLD, LLFontGL::DROP_SHADOW_SOFT); + } + // } void* LLViewerWindow::getPlatformWindow() const @@ -5122,11 +5230,10 @@ void LLViewerWindow::setup2DRender() void LLViewerWindow::setup2DViewport(S32 x_offset, S32 y_offset) { - gGLViewport[0] = mWindowRectRaw.mLeft + x_offset; - gGLViewport[1] = mWindowRectRaw.mBottom + y_offset; - gGLViewport[2] = mWindowRectRaw.getWidth(); - gGLViewport[3] = mWindowRectRaw.getHeight(); - glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]); + gGLViewport = mWindowRectRaw; + gGLViewport.translate(x_offset, y_offset); + gGL.setViewport(gGLViewport); + gGL.setScissor(gGLViewport); } @@ -5139,11 +5246,10 @@ void LLViewerWindow::setup3DRender() void LLViewerWindow::setup3DViewport(S32 x_offset, S32 y_offset) { - gGLViewport[0] = getWindowRectRaw().mLeft + x_offset; - gGLViewport[1] = getWindowRectRaw().mBottom + y_offset; - gGLViewport[2] = getWindowRectRaw().getWidth(); - gGLViewport[3] = getWindowRectRaw().getHeight(); - glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]); + gGLViewport = mWindowRectRaw; + gGLViewport.translate(x_offset, y_offset); + gGL.setViewport(gGLViewport); + gGL.setScissor(gGLViewport); } void LLViewerWindow::revealIntroPanel() @@ -5154,14 +5260,6 @@ void LLViewerWindow::revealIntroPanel() } } -void LLViewerWindow::abortShowProgress() -{ - if (mProgressView) - { - mProgressView->abortShowProgress(); - } -} - void LLViewerWindow::setShowProgress(const BOOL show) { if (mProgressView) @@ -5223,21 +5321,22 @@ LLProgressView *LLViewerWindow::getProgressView() const void LLViewerWindow::dumpState() { - llinfos << "LLViewerWindow Active " << S32(mActive) << llendl; - llinfos << "mWindow visible " << S32(mWindow->getVisible()) + LL_INFOS() << "LLViewerWindow Active " << S32(mActive) << LL_ENDL; + LL_INFOS() << "mWindow visible " << S32(mWindow->getVisible()) << " minimized " << S32(mWindow->getMinimized()) - << llendl; + << LL_ENDL; } void LLViewerWindow::stopGL(BOOL save_state) { + stop_glerror(); //Note: --bao //if not necessary, do not change the order of the function calls in this function. //if change something, make sure it will not break anything. //especially be careful to put anything behind gTextureList.destroyGL(save_state); if (!gGLManager.mIsDisabled) { - llinfos << "Shutting down GL..." << llendl; + LL_INFOS() << "Shutting down GL..." << LL_ENDL; // Pause texture decode threads (will get unpaused during main loop) LLAppViewer::getTextureCache()->pause(); @@ -5260,6 +5359,7 @@ void LLViewerWindow::stopGL(BOOL save_state) stop_glerror(); LLVOPartGroup::destroyGL(); + stop_glerror(); LLViewerDynamicTexture::destroyGL(); stop_glerror(); @@ -5268,8 +5368,10 @@ void LLViewerWindow::stopGL(BOOL save_state) { gPipeline.destroyGL(); } + stop_glerror(); gBox.cleanupGL(); + stop_glerror(); if(LLPostProcess::instanceExists()) { @@ -5278,43 +5380,78 @@ void LLViewerWindow::stopGL(BOOL save_state) gTextureList.destroyGL(save_state); stop_glerror(); + gGL.destroyGL(); + stop_glerror(); gGLManager.mIsDisabled = TRUE; stop_glerror(); + + LLVertexBuffer::cleanupClass(); + + stop_glerror(); - llinfos << "Remaining allocated texture memory: " << LLImageGL::sGlobalTextureMemoryInBytes << " bytes" << llendl; + LL_INFOS() << "Remaining allocated texture memory: " << LLImageGL::sGlobalTextureMemory << " bytes" << LL_ENDL; } } -void LLViewerWindow::restoreGL(const std::string& progress_message) +void LLViewerWindow::restoreGLState() +{ + gGL.init(); + stop_glerror(); + initGLDefaults(); + stop_glerror(); + gGL.refreshState(); //Singu Note: Call immediately. Cached states may have prevented initGLDefaults from actually applying changes. + stop_glerror(); + LLGLStateValidator::restoreGL(); + stop_glerror(); +} + +void LLViewerWindow::restoreGL(bool full_restore, const std::string& progress_message) { //Note: --bao //if not necessary, do not change the order of the function calls in this function. //if change something, make sure it will not break anything. //especially, be careful to put something before gTextureList.restoreGL(); + if (!gGLManager.mIsDisabled && !full_restore) + { + LL_INFOS() << "Restoring GL state..." << LL_ENDL; + restoreGLState(); + gPipeline.releaseOcclusionBuffers(); // Occlusion handles must be invalidated + return; + } if (gGLManager.mIsDisabled) { - llinfos << "Restoring GL..." << llendl; + stop_glerror(); + LL_INFOS() << "Restoring GL..." << LL_ENDL; gGLManager.mIsDisabled = FALSE; - initGLDefaults(); - gGL.refreshState(); //Singu Note: Call immediately. Cached states may have prevented initGLDefaults from actually applying changes. - LLGLState::restoreGL(); + restoreGLState(); + gTextureList.restoreGL(); + stop_glerror(); // for future support of non-square pixels, and fonts that are properly stretched //LLFontGL::destroyDefaultFonts(); initFonts(); + stop_glerror(); gSky.restoreGL(); + stop_glerror(); gPipeline.restoreGL(); + stop_glerror(); LLDrawPoolWater::restoreGL(); + stop_glerror(); LLManipTranslate::restoreGL(); + stop_glerror(); gBumpImageList.restoreGL(); + stop_glerror(); LLViewerDynamicTexture::restoreGL(); + stop_glerror(); LLVOAvatar::restoreGL(); + stop_glerror(); LLVOPartGroup::restoreGL(); + stop_glerror(); gResizeScreenTexture = TRUE; gWindowResized = TRUE; @@ -5331,13 +5468,14 @@ void LLViewerWindow::restoreGL(const std::string& progress_message) setShowProgress(TRUE); setProgressString(progress_message); } - llinfos << "...Restoring GL done" << llendl; + LL_INFOS() << "...Restoring GL done" << LL_ENDL; if(!LLAppViewer::instance()->restoreErrorTrap()) { - llwarns << " Someone took over my signal/exception handler (post restoreGL)!" << llendl; + LL_WARNS() << " Someone took over my signal/exception handler (post restoreGL)!" << LL_ENDL; } - + stop_glerror(); } + } void LLViewerWindow::initFonts(F32 zoom_factor) @@ -5350,8 +5488,8 @@ void LLViewerWindow::initFonts(F32 zoom_factor) LLFontGL::initClass( gSavedSettings.getF32("FontScreenDPI"), mDisplayScale.mV[VX] * zoom_factor, mDisplayScale.mV[VY] * zoom_factor, - gDirUtilp->getAppRODataDir(), - LLUICtrlFactory::getXUIPaths()); + font_dir()); + // Force font reloads, which can be very slow LLFontGL::loadDefaultFonts(); } void LLViewerWindow::toggleFullscreen(BOOL show_progress) @@ -5397,7 +5535,7 @@ BOOL LLViewerWindow::checkSettings() { //Singu Note: Don't do the following. //setShaders is already called in restoreGL(), and gGL.refreshState() is too as to maintain blend states. - //This maintaining of blend states is needed for LLGLState::checkStates() to not error out. + //This maintaining of blend states is needed for LLGLStateValidator::checkStates() to not error out. /*if (mStatesDirty) { gGL.refreshState(); @@ -5431,6 +5569,9 @@ BOOL LLViewerWindow::checkSettings() BOOL is_fullscreen = mWindow->getFullscreen(); if(mWantFullscreen) { + if (mWindow->getMinimized()) { + return FALSE; + } LLCoordScreen screen_size; LLCoordScreen desired_screen_size(gSavedSettings.getS32("FullScreenWidth"), gSavedSettings.getS32("FullScreenHeight")); @@ -5444,14 +5585,21 @@ BOOL LLViewerWindow::checkSettings() return FALSE; } - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); + LLGLStateValidator::checkStates(); + LLGLStateValidator::checkTextureChannels(); + + S32 vsync_mode = gSavedSettings.getS32("SHRenderVsyncMode"); + if(vsync_mode == -1 && !gGLManager.mHasAdaptiveVsync) + { + vsync_mode = 0; //Disable vsync if adaptive is desired yet isn't supported. + } + changeDisplaySettings(TRUE, desired_screen_size, - gSavedSettings.getBOOL("DisableVerticalSync"), + vsync_mode, mShowFullscreenProgress); - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); + LLGLStateValidator::checkStates(); + LLGLStateValidator::checkTextureChannels(); return TRUE; } } @@ -5460,15 +5608,15 @@ BOOL LLViewerWindow::checkSettings() if(is_fullscreen) { // Changing to windowed mode. - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); + LLGLStateValidator::checkStates(); + LLGLStateValidator::checkTextureChannels(); changeDisplaySettings(FALSE, LLCoordScreen(gSavedSettings.getS32("WindowWidth"), gSavedSettings.getS32("WindowHeight")), TRUE, mShowFullscreenProgress); - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); + LLGLStateValidator::checkStates(); + LLGLStateValidator::checkTextureChannels(); return TRUE; } } @@ -5477,21 +5625,21 @@ BOOL LLViewerWindow::checkSettings() void LLViewerWindow::restartDisplay(BOOL show_progress_bar) { - llinfos << "Restaring GL" << llendl; + LL_INFOS() << "Restaring GL" << LL_ENDL; stopGL(); if (show_progress_bar) { - restoreGL(LLTrans::getString("ProgressChangingResolution")); + restoreGL(true, LLTrans::getString("ProgressChangingResolution")); } else { - restoreGL(); + restoreGL(true); } } -BOOL LLViewerWindow::changeDisplaySettings(BOOL fullscreen, LLCoordScreen size, BOOL disable_vsync, BOOL show_progress_bar) +BOOL LLViewerWindow::changeDisplaySettings(BOOL fullscreen, LLCoordScreen size, const S32 vsync_mode, BOOL show_progress_bar) { - BOOL was_maximized = gSavedSettings.getBOOL("WindowMaximized"); + BOOL was_maximized = mWindow->getMaximized(); mWantFullscreen = fullscreen; mShowFullscreenProgress = show_progress_bar; gSavedSettings.setBOOL("FullScreen", mWantFullscreen); @@ -5506,8 +5654,9 @@ BOOL LLViewerWindow::changeDisplaySettings(BOOL fullscreen, LLCoordScreen size, return TRUE; } - U32 fsaa = gSavedSettings.getU32("RenderFSAASamples"); + U32 fsaa = LLRenderTarget::sUseFBO ? 0 : gSavedSettings.getU32("RenderFSAASamples"); //don't use window level anti-aliasing if FBOs are enabled U32 old_fsaa = mWindow->getFSAASamples(); + // going from windowed to windowed if (!old_fullscreen && !fullscreen) { @@ -5517,7 +5666,7 @@ BOOL LLViewerWindow::changeDisplaySettings(BOOL fullscreen, LLCoordScreen size, mWindow->setSize(size); } - if (fsaa == old_fsaa) + if (fsaa == old_fsaa && vsync_mode == mWindow->getVsyncMode()) { return TRUE; } @@ -5531,8 +5680,8 @@ BOOL LLViewerWindow::changeDisplaySettings(BOOL fullscreen, LLCoordScreen size, LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus(); send_agent_pause(); - llinfos << "Stopping GL during changeDisplaySettings" << llendl; - stopGL(); + LL_INFOS() << "Stopping GL during changeDisplaySettings" << LL_ENDL; + //stopGL(); mIgnoreActivate = TRUE; LLCoordScreen old_size; LLCoordScreen old_pos; @@ -5556,13 +5705,20 @@ BOOL LLViewerWindow::changeDisplaySettings(BOOL fullscreen, LLCoordScreen size, } mWindow->setFSAASamples(fsaa); + mWindow->setVsyncMode(vsync_mode); - result_first_try = mWindow->switchContext(fullscreen, size, disable_vsync, &new_pos); + auto stopfn = [this]() { this->stopGL(); }; + auto restoreFn = [this, show_progress_bar](bool full_restore) { + LL_INFOS() << "Restoring GL during resolution change" << LL_ENDL; + this->restoreGL(full_restore, show_progress_bar ? LLTrans::getString("ProgressChangingResolution") : ""); + }; + + result_first_try = mWindow->switchContext(fullscreen, size, vsync_mode, stopfn, restoreFn, &new_pos); if (!result_first_try) { // try to switch back mWindow->setFSAASamples(old_fsaa); - result_second_try = mWindow->switchContext(old_fullscreen, old_size, disable_vsync, &new_pos); + result_second_try = mWindow->switchContext(old_fullscreen, old_size, vsync_mode, stopfn, restoreFn, &new_pos); if (!result_second_try) { @@ -5574,16 +5730,6 @@ BOOL LLViewerWindow::changeDisplaySettings(BOOL fullscreen, LLCoordScreen size, } send_agent_resume(); - llinfos << "Restoring GL during resolution change" << llendl; - if (show_progress_bar) - { - restoreGL(LLTrans::getString("ProgressChangingResolution")); - } - else - { - restoreGL(); - } - if (!result_first_try) { LLSD args; @@ -5651,17 +5797,17 @@ F32 LLViewerWindow::getDisplayAspectRatio() const void LLViewerWindow::calcDisplayScale() { - F32 ui_scale_factor = gSavedSettings.getF32("UIScaleFactor"); + LLVector2 ui_scale_factor = getUIScale(); LLVector2 display_scale; display_scale.setVec(llmax(1.f / mWindow->getPixelAspectRatio(), 1.f), llmax(mWindow->getPixelAspectRatio(), 1.f)); if(mWindow->getFullscreen()) { F32 height_normalization = gSavedSettings.getBOOL("UIAutoScale") ? ((F32)mWindowRectRaw.getHeight() / display_scale.mV[VY]) / 768.f : 1.f; - display_scale *= (ui_scale_factor * height_normalization); + display_scale.scaleVec(ui_scale_factor * height_normalization); } else { - display_scale *= ui_scale_factor; + display_scale.scaleVec(ui_scale_factor); } // limit minimum display scale @@ -5672,13 +5818,13 @@ void LLViewerWindow::calcDisplayScale() if (mWindow->getFullscreen()) { - display_scale.mV[0] = llround(display_scale.mV[0], 2.0f/(F32) mWindowRectRaw.getWidth()); - display_scale.mV[1] = llround(display_scale.mV[1], 2.0f/(F32) mWindowRectRaw.getHeight()); + display_scale.mV[0] = ll_round(display_scale.mV[0], 2.0f/(F32) mWindowRectRaw.getWidth()); + display_scale.mV[1] = ll_round(display_scale.mV[1], 2.0f/(F32) mWindowRectRaw.getHeight()); } if (display_scale != mDisplayScale) { - llinfos << "Setting display scale to " << display_scale << llendl; + LL_INFOS() << "Setting display scale to " << display_scale << LL_ENDL; mDisplayScale = display_scale; // Init default fonts @@ -5686,6 +5832,19 @@ void LLViewerWindow::calcDisplayScale() } } +LLVector2 LLViewerWindow::getUIScale() const +{ + static LLCachedControl ui_scale_factor("UIScaleFactor"); + if (mWindow->getFullscreen()) + { + return LLVector2(ui_scale_factor, ui_scale_factor); + } + else + { + return LLVector2(mDPIScaleX * ui_scale_factor, mDPIScaleY * ui_scale_factor); + } +} + S32 LLViewerWindow::getChatConsoleBottomPad() { static const LLCachedControl user_offset("ConsoleBottomOffset"); @@ -5736,7 +5895,7 @@ bool LLViewerWindow::onAlert(const LLSD& notify) if (gNoRender) { - llinfos << "Alert: " << notification->getName() << llendl; + LL_INFOS() << "Alert: " << notification->getName() << LL_ENDL; notification->respond(LLSD::emptyMap()); LLNotifications::instance().cancel(notification); return false; @@ -5815,17 +5974,23 @@ LLPickInfo::LLPickInfo() mXYCoords(-1, -1), mIntersection(), mNormal(), + mTangent(), mBinormal(), mHUDIcon(NULL), - mPickTransparent(FALSE) + mPickTransparent(FALSE), + mPickRigged(FALSE), + mPickParticle(FALSE) { } LLPickInfo::LLPickInfo(const LLCoordGL& mouse_pos, MASK keyboard_mask, - BOOL pick_transparent, - BOOL pick_uv_coords, - void (*pick_callback)(const LLPickInfo& pick_info)) + BOOL pick_transparent, + BOOL pick_rigged, + BOOL pick_particle, + BOOL pick_uv_coords, + BOOL pick_unselectable, + void (*pick_callback)(const LLPickInfo& pick_info)) : mMousePt(mouse_pos), mKeyMask(keyboard_mask), mPickCallback(pick_callback), @@ -5836,9 +6001,13 @@ LLPickInfo::LLPickInfo(const LLCoordGL& mouse_pos, mSTCoords(-1.f, -1.f), mXYCoords(-1, -1), mNormal(), + mTangent(), mBinormal(), mHUDIcon(NULL), - mPickTransparent(pick_transparent) + mPickTransparent(pick_transparent), + mPickRigged(pick_rigged), + mPickParticle(pick_particle), + mPickUnselectable(pick_unselectable) { } @@ -5846,31 +6015,55 @@ void LLPickInfo::fetchResults() { S32 face_hit = -1; - LLVector3 intersection, normal, binormal; + LLVector4a intersection, normal; + LLVector4a tangent; + LLVector2 uv; LLHUDIcon* hit_icon = gViewerWindow->cursorIntersectIcon(mMousePt.mX, mMousePt.mY, 512.f, &intersection); + LLVector4a origin; + origin.load3(LLViewerCamera::getInstance()->getOrigin().mV); F32 icon_dist = 0.f; + LLVector4a start; + LLVector4a end; + LLVector4a particle_end; if (hit_icon) { - icon_dist = (LLViewerCamera::getInstance()->getOrigin()-intersection).magVec(); + LLVector4a delta; + delta.setSub(intersection, origin); + icon_dist = delta.getLength3().getF32(); } + LLViewerObject* hit_object = gViewerWindow->cursorIntersect(mMousePt.mX, mMousePt.mY, 512.f, - NULL, -1, mPickTransparent, &face_hit, - &intersection, &uv, &normal, &binormal); + NULL, -1, mPickTransparent, mPickRigged, &face_hit, + &intersection, &uv, &normal, &tangent, &start, &end); mPickPt = mMousePt; U32 te_offset = face_hit > -1 ? face_hit : 0; - //unproject relative clicked coordinate from window coordinate using GL - + if (mPickParticle) + { //get the end point of line segement to use for particle raycast + if (hit_object) + { + particle_end = intersection; + } + else + { + particle_end = end; + } + } + LLViewerObject* objectp = hit_object; + + LLVector4a delta; + delta.setSub(origin, intersection); + if (hit_icon && (!objectp || - icon_dist < (LLViewerCamera::getInstance()->getOrigin()-intersection).magVec())) + icon_dist < delta.getLength3().getF32())) { // was this name referring to a hud icon? mHUDIcon = hit_icon; @@ -5887,7 +6080,7 @@ void LLPickInfo::fetchResults() // put global position into land_pos LLVector3d land_pos; - if (!gViewerWindow->mousePointOnLandGlobal(mPickPt.mX, mPickPt.mY, &land_pos)) + if (!gViewerWindow->mousePointOnLandGlobal(mPickPt.mX, mPickPt.mY, &land_pos, mPickUnselectable)) { // The selected point is beyond the draw distance or is otherwise // not selectable. Return before calling mPickCallback(). @@ -5907,11 +6100,16 @@ void LLPickInfo::fetchResults() { mPickType = PICK_OBJECT; } - mObjectOffset = gAgentCamera.calcFocusOffset(objectp, intersection, mPickPt.mX, mPickPt.mY); + + LLVector3 v_intersection(intersection.getF32ptr()); + + mObjectOffset = gAgentCamera.calcFocusOffset(objectp, v_intersection, mPickPt.mX, mPickPt.mY); mObjectID = objectp->mID; mObjectFace = (te_offset == NO_FACE) ? -1 : (S32)te_offset; - mPosGlobal = gAgent.getPosGlobalFromAgent(intersection); + + + mPosGlobal = gAgent.getPosGlobalFromAgent(v_intersection); if (mWantSurfaceInfo) { @@ -5920,6 +6118,18 @@ void LLPickInfo::fetchResults() } } + if (mPickParticle) + { //search for closest particle to click origin out to intersection point + S32 part_face = -1; + + LLVOPartGroup* group = gPipeline.lineSegmentIntersectParticle(start, particle_end, NULL, &part_face); + if (group) + { + mParticleOwnerID = group->getPartOwner(part_face); + mParticleSourceID = group->getPartSource(part_face); + } + } + if (mPickCallback) { mPickCallback(*this); @@ -5939,8 +6149,8 @@ void LLPickInfo::updateXYCoords() LLPointer imagep = LLViewerTextureManager::getFetchedTexture(tep->getID()); if(mUVCoords.mV[VX] >= 0.f && mUVCoords.mV[VY] >= 0.f && imagep.notNull()) { - mXYCoords.mX = llround(mUVCoords.mV[VX] * (F32)imagep->getWidth()); - mXYCoords.mY = llround((1.f - mUVCoords.mV[VY]) * (F32)imagep->getHeight()); + mXYCoords.mX = ll_round(mUVCoords.mV[VX] * (F32)imagep->getWidth()); + mXYCoords.mY = ll_round((1.f - mUVCoords.mV[VY]) * (F32)imagep->getHeight()); } } } @@ -5955,18 +6165,27 @@ void LLPickInfo::getSurfaceInfo() mIntersection = LLVector3(0,0,0); mNormal = LLVector3(0,0,0); mBinormal = LLVector3(0,0,0); + mTangent = LLVector4(0,0,0,0); + LLVector4a tangent; + LLVector4a intersection; + LLVector4a normal; + + tangent.clear(); + normal.clear(); + intersection.clear(); + LLViewerObject* objectp = getObject(); if (objectp) { - if (gViewerWindow->cursorIntersect(llround((F32)mMousePt.mX), llround((F32)mMousePt.mY), 1024.f, - objectp, -1, mPickTransparent, + if (gViewerWindow->cursorIntersect(ll_round((F32)mMousePt.mX), ll_round((F32)mMousePt.mY), 1024.f, + objectp, -1, mPickTransparent, mPickRigged, &mObjectFace, - &mIntersection, + &intersection, &mSTCoords, - &mNormal, - &mBinormal)) + &normal, + &tangent)) { // if we succeeded with the intersect above, compute the texture coordinates: @@ -5975,10 +6194,26 @@ void LLPickInfo::getSurfaceInfo() LLFace* facep = objectp->mDrawable->getFace(mObjectFace); if (facep) { - mUVCoords = facep->surfaceToTexture(mSTCoords, mIntersection, mNormal); + mUVCoords = facep->surfaceToTexture(mSTCoords, intersection, normal); } } + mIntersection.set(intersection.getF32ptr()); + mNormal.set(normal.getF32ptr()); + mTangent.set(tangent.getF32ptr()); + + //extrapoloate binormal from normal and tangent + + LLVector4a binormal; + binormal.setCross3(normal, tangent); + binormal.mul(tangent.getF32ptr()[3]); + + mBinormal.set(binormal.getF32ptr()); + + mBinormal.normalize(); + mNormal.normalize(); + mTangent.normalize(); + // and XY coords: updateXYCoords(); @@ -6002,8 +6237,8 @@ LLVector2 LLPickInfo::pickUV() objectp->mDrawable.notNull() && objectp->getPCode() == LL_PCODE_VOLUME && mObjectFace < objectp->mDrawable->getNumFaces()) { - S32 scaled_x = llround((F32)mPickPt.mX * gViewerWindow->getDisplayScale().mV[VX]); - S32 scaled_y = llround((F32)mPickPt.mY * gViewerWindow->getDisplayScale().mV[VY]); + S32 scaled_x = ll_round((F32)mPickPt.mX * gViewerWindow->getDisplayScale().mV[VX]); + S32 scaled_y = ll_round((F32)mPickPt.mY * gViewerWindow->getDisplayScale().mV[VY]); const S32 UV_PICK_WIDTH = 5; const S32 UV_PICK_HALF_WIDTH = (UV_PICK_WIDTH - 1) / 2; U8 uv_pick_buffer[UV_PICK_WIDTH * UV_PICK_WIDTH * 4]; diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index ed80a12530..c47efb95cb 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -88,7 +88,10 @@ class LLPickInfo LLPickInfo(const LLCoordGL& mouse_pos, MASK keyboard_mask, BOOL pick_transparent, + BOOL pick_rigged, + BOOL pick_particle, BOOL pick_surface_info, + BOOL pick_unselectable, void (*pick_callback)(const LLPickInfo& pick_info)); void fetchResults(); @@ -108,6 +111,8 @@ class LLPickInfo LLVector3d mPosGlobal; LLVector3 mObjectOffset; LLUUID mObjectID; + LLUUID mParticleOwnerID; + LLUUID mParticleSourceID; S32 mObjectFace; LLHUDIcon* mHUDIcon; LLVector3 mIntersection; @@ -115,8 +120,12 @@ class LLPickInfo LLVector2 mSTCoords; LLCoordScreen mXYCoords; LLVector3 mNormal; + LLVector4 mTangent; LLVector3 mBinormal; BOOL mPickTransparent; + BOOL mPickRigged; + BOOL mPickParticle; + BOOL mPickUnselectable; void getSurfaceInfo(); private: @@ -180,6 +189,7 @@ class LLViewerWindow : public LLWindowCallbacks /*virtual*/ void handleDataCopy(LLWindow *window, S32 data_type, void *data); /*virtual*/ BOOL handleTimerEvent(LLWindow *window); /*virtual*/ BOOL handleDeviceChange(LLWindow *window); + /*virtual*/ bool handleDPIScaleChange(LLWindow *window, float xDPIScale, float yDPIScale, U32 width = 0, U32 height = 0); /*virtual*/ void handlePingWatchdog(LLWindow *window, const char * msg); /*virtual*/ void handlePauseWatchdog(LLWindow *window); @@ -240,7 +250,6 @@ class LLViewerWindow : public LLWindowCallbacks BOOL getRightMouseDown() const { return mRightMouseDown; } const LLPickInfo& getLastPick() const { return mLastPick; } - const LLPickInfo& getHoverPick() const { return mHoverPick; } void setup2DViewport(S32 x_offset = 0, S32 y_offset = 0); void setup3DViewport(S32 x_offset = 0, S32 y_offset = 0); @@ -291,6 +300,7 @@ class LLViewerWindow : public LLWindowCallbacks void updateKeyboardFocus(); BOOL handleKey(KEY key, MASK mask); + BOOL handleKeyUp(KEY key, MASK mask); void handleScrollWheel (S32 clicks); // Hide normal UI when a logon fails, re-show everything when logon is attempted again @@ -341,25 +351,32 @@ class LLViewerWindow : public LLWindowCallbacks void returnEmptyPicks(); - void pickAsync(S32 x, S32 y_from_bot, MASK mask, void (*callback)(const LLPickInfo& pick_info), - BOOL pick_transparent = FALSE, BOOL get_surface_info = FALSE); - LLPickInfo pickImmediate(S32 x, S32 y, BOOL pick_transparent); + void pickAsync( S32 x, + S32 y_from_bot, + MASK mask, + void (*callback)(const LLPickInfo& pick_info), + BOOL pick_transparent = FALSE, + BOOL pick_rigged = FALSE, + BOOL pick_unselectable = FALSE, + BOOL get_surface_info = FALSE); + LLPickInfo pickImmediate(S32 x, S32 y, BOOL pick_transparent, BOOL pick_rigged = FALSE, BOOL pick_particle = FALSE); static void hoverPickCallback(const LLPickInfo& pick_info); LLHUDIcon* cursorIntersectIcon(S32 mouse_x, S32 mouse_y, F32 depth, - LLVector3* intersection); + LLVector4a* intersection); LLViewerObject* cursorIntersect(S32 mouse_x = -1, S32 mouse_y = -1, F32 depth = 512.f, LLViewerObject *this_object = NULL, S32 this_face = -1, BOOL pick_transparent = FALSE, + BOOL pick_rigged = FALSE, S32* face_hit = NULL, - LLVector3 *intersection = NULL, + LLVector4a *intersection = NULL, LLVector2 *uv = NULL, - LLVector3 *normal = NULL, - LLVector3 *binormal = NULL, - LLVector3* start = NULL, - LLVector3* end = NULL); + LLVector4a *normal = NULL, + LLVector4a *tangent = NULL, + LLVector4a* start = NULL, + LLVector4a* end = NULL); // Returns a pointer to the last object hit @@ -370,7 +387,7 @@ class LLViewerWindow : public LLWindowCallbacks //const LLVector3d& lastNonFloraObjectHitOffset(); // mousePointOnLand() returns true if found point - BOOL mousePointOnLandGlobal(const S32 x, const S32 y, LLVector3d *land_pos_global); + BOOL mousePointOnLandGlobal(const S32 x, const S32 y, LLVector3d *land_pos_global, BOOL ignore_distance = FALSE); BOOL mousePointOnPlaneGlobal(LLVector3d& point, const S32 x, const S32 y, const LLVector3d &plane_point, const LLVector3 &plane_normal); LLVector3d clickPointInWorldGlobal(const S32 x, const S32 y_from_bot, LLViewerObject* clicked_object) const; BOOL clickPointOnSurfaceGlobal(const S32 x, const S32 y, LLViewerObject *objectp, LLVector3d &point_global) const; @@ -385,21 +402,23 @@ class LLViewerWindow : public LLWindowCallbacks void requestResolutionUpdate(bool fullscreen_checked); BOOL checkSettings(); void restartDisplay(BOOL show_progress_bar); - BOOL changeDisplaySettings(BOOL fullscreen, LLCoordScreen size, BOOL disable_vsync, BOOL show_progress_bar); + BOOL changeDisplaySettings(BOOL fullscreen, LLCoordScreen size, const S32 vsync_mode, BOOL show_progress_bar); BOOL getIgnoreDestroyWindow() { return mIgnoreActivate; } F32 getDisplayAspectRatio() const; const LLVector2& getDisplayScale() const { return mDisplayScale; } void calcDisplayScale(); + LLVector2 getUIScale() const; + private: bool shouldShowToolTipFor(LLMouseHandler *mh); static bool onAlert(const LLSD& notify); - void switchToolByMask(MASK mask); void destroyWindow(); void drawMouselookInstructions(); void stopGL(BOOL save_state = TRUE); - void restoreGL(const std::string& progress_message = LLStringUtil::null); + void restoreGLState(); + void restoreGL(bool full_restore, const std::string& progress_message = LLStringUtil::null); void initFonts(F32 zoom_factor = 1.f); void schedulePick(LLPickInfo& pick_info); S32 getChatConsoleBottomPad(); // Vertical padding for child console rect, varied by bottom clutter @@ -444,7 +463,6 @@ class LLViewerWindow : public LLWindowCallbacks BOOL mHideCursorPermanent; // true during drags, mouselook BOOL mCursorHidden; LLPickInfo mLastPick; - LLPickInfo mHoverPick; std::vector mPicks; LLRect mPickScreenRegion; // area of frame buffer for rendering pick frames (generally follows mouse to avoid going offscreen) LLTimer mPickTimer; // timer for scheduling n picks per second @@ -462,6 +480,9 @@ class LLViewerWindow : public LLWindowCallbacks bool mIsFullscreenChecked; // Did the user check the fullscreen checkbox in the display settings U32 mCurrResolutionIndex; + float mDPIScaleX; + float mDPIScaleY; + protected: static std::string sSnapshotBaseName; static std::string sSnapshotDir; @@ -509,13 +530,13 @@ extern LLFrameTimer gAwayTimer; // tracks time before setting the avatar awa extern LLFrameTimer gAwayTriggerTimer; // how long the avatar has been away extern LLViewerObject* gDebugRaycastObject; -extern LLVector3 gDebugRaycastIntersection; +extern LLVector4a gDebugRaycastIntersection; extern LLVector2 gDebugRaycastTexCoord; -extern LLVector3 gDebugRaycastNormal; -extern LLVector3 gDebugRaycastBinormal; +extern LLVector4a gDebugRaycastNormal; +extern LLVector4a gDebugRaycastTangent; extern S32 gDebugRaycastFaceHit; -extern LLVector3 gDebugRaycastStart; -extern LLVector3 gDebugRaycastEnd; +extern LLVector4a gDebugRaycastStart; +extern LLVector4a gDebugRaycastEnd; extern BOOL gDisplayCameraPos; extern BOOL gDisplayWindInfo; diff --git a/indra/newview/llvlcomposition.cpp b/indra/newview/llvlcomposition.cpp index 8954a2da2f..a91732c798 100644 --- a/indra/newview/llvlcomposition.cpp +++ b/indra/newview/llvlcomposition.cpp @@ -42,7 +42,7 @@ #include "llviewertexture.h" #include "llviewertexturelist.h" #include "llviewerregion.h" -#include "noise.h" +#include "llperlin.h" #include "llregionhandle.h" // for from_region_handle #include "llviewercontrol.h" @@ -133,10 +133,10 @@ BOOL LLVLComposition::generateHeights(const F32 x, const F32 y, S32 x_begin, y_begin, x_end, y_end; - x_begin = llround( x * mScaleInv ); - y_begin = llround( y * mScaleInv ); - x_end = llround( (x + width) * mScaleInv ); - y_end = llround( (y + width) * mScaleInv ); + x_begin = ll_round( x * mScaleInv ); + y_begin = ll_round( y * mScaleInv ); + x_end = ll_round( (x + width) * mScaleInv ); + y_end = ll_round( (y + width) * mScaleInv ); if (x_end > mWidth) { @@ -152,7 +152,7 @@ BOOL LLVLComposition::generateHeights(const F32 x, const F32 y, // For perlin noise generation... const F32 slope_squared = 1.5f*1.5f; const F32 xyScale = 4.9215f; //0.93284f; - const F32 zScale = 4; //0.92165f; + //const F32 zScale = 4; //0.92165f; //Unused const F32 z_offset = 0.f; const F32 noise_magnitude = 2.f; // Degree to which noise modulates composition layer (versus // simple height) @@ -162,18 +162,18 @@ BOOL LLVLComposition::generateHeights(const F32 x, const F32 y, const S32 NUM_TEXTURES = 4; const F32 xyScaleInv = (1.f / xyScale); - const F32 zScaleInv = (1.f / zScale); + //const F32 zScaleInv = (1.f / zScale); //Unused - const F32 inv_width = 1.f/mWidth; +// Aurora Sim + //const F32 inv_width = 1.f/mWidth; + const F32 inv_width = 1.f/(F32)mWidth; +// Aurora Sim // OK, for now, just have the composition value equal the height at the point. for (S32 j = y_begin; j < y_end; j++) { for (S32 i = x_begin; i < x_end; i++) { - - F32 vec[3]; - F32 vec1[3]; F32 twiddle; // Bilinearly interpolate the start height and height range of the textures @@ -193,18 +193,18 @@ BOOL LLVLComposition::generateHeights(const F32 x, const F32 y, F32 height = mSurfacep->resolveHeightRegion(location) + z_offset; // Step 0: Measure the exact height at this texel - vec[0] = (F32)(origin_global.mdV[VX]+location.mV[VX])*xyScaleInv; // Adjust to non-integer lattice - vec[1] = (F32)(origin_global.mdV[VY]+location.mV[VY])*xyScaleInv; - vec[2] = height*zScaleInv; + + // Adjust to non - integer lattice + LLVector2 vec = (LLVector2(LLVector3(origin_global)) + LLVector2(location)); + vec *= xyScaleInv; + //vec[VZ] = height*zScaleInv; //Unused. + // // Choose material value by adding to the exact height a random value // - vec1[0] = vec[0]*(0.2222222222f); - vec1[1] = vec[1]*(0.2222222222f); - vec1[2] = vec[2]*(0.2222222222f); - twiddle = noise2(vec1)*6.5f; // Low freq component for large divisions + twiddle = LLPerlinNoise::noise(vec*0.2222222222f)*6.5f; // Low freq component for large divisions - twiddle += turbulence2(vec, 2)*slope_squared; // High frequency component + twiddle += LLPerlinNoise::turbulence(vec, 2.f)*slope_squared; // High frequency component twiddle *= noise_magnitude; F32 scaled_noisy_height = (height + twiddle - start_height) * F32(NUM_TEXTURES) / height_range; @@ -297,7 +297,7 @@ BOOL LLVLComposition::generateTexture(const F32 x, const F32 y, { mDetailTextures[i]->destroyRawImage() ; } - lldebugs << "cached raw data for terrain detail texture is not ready yet: " << mDetailTextures[i]->getID() << llendl; + LL_DEBUGS() << "cached raw data for terrain detail texture is not ready yet: " << mDetailTextures[i]->getID() << LL_ENDL; return FALSE; } @@ -328,17 +328,17 @@ BOOL LLVLComposition::generateTexture(const F32 x, const F32 y, S32 x_begin, y_begin, x_end, y_end; x_begin = (S32)(x * mScaleInv); y_begin = (S32)(y * mScaleInv); - x_end = llround( (x + width) * mScaleInv ); - y_end = llround( (y + width) * mScaleInv ); + x_end = ll_round( (x + width) * mScaleInv ); + y_end = ll_round( (y + width) * mScaleInv ); if (x_end > mWidth) { - llwarns << "x end > width" << llendl; + LL_WARNS() << "x end > width" << LL_ENDL; x_end = mWidth; } if (y_end > mWidth) { - llwarns << "y end > width" << llendl; + LL_WARNS() << "y end > width" << LL_ENDL; y_end = mWidth; } @@ -368,7 +368,7 @@ BOOL LLVLComposition::generateTexture(const F32 x, const F32 y, if (tex_comps != st_comps) { - llwarns << "Base texture comps != input texture comps" << llendl; + LL_WARNS() << "Base texture comps != input texture comps" << LL_ENDL; return FALSE; } @@ -426,8 +426,8 @@ BOOL LLVLComposition::generateTexture(const F32 x, const F32 y, if (st_offset >= st_data_size[tex0] || st_offset >= st_data_size[tex1]) { // SJB: This shouldn't be happening, but does... Rounding error? - //llwarns << "offset 0 [" << tex0 << "] =" << st_offset << " >= size=" << st_data_size[tex0] << llendl; - //llwarns << "offset 1 [" << tex1 << "] =" << st_offset << " >= size=" << st_data_size[tex1] << llendl; + //LL_WARNS() << "offset 0 [" << tex0 << "] =" << st_offset << " >= size=" << st_data_size[tex0] << LL_ENDL; + //LL_WARNS() << "offset 1 [" << tex1 << "] =" << st_offset << " >= size=" << st_data_size[tex1] << LL_ENDL; } else { diff --git a/indra/newview/llvlmanager.cpp b/indra/newview/llvlmanager.cpp index 88afc9cc34..f3dd91ab51 100644 --- a/indra/newview/llvlmanager.cpp +++ b/indra/newview/llvlmanager.cpp @@ -42,51 +42,60 @@ #include "llframetimer.h" #include "llsurface.h" -LLVLManager gVLManager; +const char LAND_LAYER_CODE = 'L'; +const char WATER_LAYER_CODE = 'W'; +const char WIND_LAYER_CODE = '7'; +const char CLOUD_LAYER_CODE = '8'; + +const char WHITECORE_LAND_LAYER_CODE = 'M'; +const char WHITECORE_WATER_LAYER_CODE = 'X'; +const char WHITECORE_WIND_LAYER_CODE = '9'; +const char WHITECORE_CLOUD_LAYER_CODE = ':'; -// Extended land layer for Aurora Sim -const char AURORA_LAND_LAYER_CODE = 'M'; -const char AURORA_WIND_LAYER_CODE = '9'; -const char AURORA_CLOUD_LAYER_CODE = ':'; +LLVLManager gVLManager; LLVLManager::~LLVLManager() { - S32 i; - for (i = 0; i < mPacketData.count(); i++) + U32 i; + for (i = 0; i < mPacketData.size(); i++) { delete mPacketData[i]; } - mPacketData.reset(); + mPacketData.clear(); } void LLVLManager::addLayerData(LLVLData *vl_datap, const S32 mesg_size) { - if (LAND_LAYER_CODE == vl_datap->mType || AURORA_LAND_LAYER_CODE == vl_datap->mType) + if (LAND_LAYER_CODE == vl_datap->mType || WHITECORE_LAND_LAYER_CODE == vl_datap->mType) { mLandBits += mesg_size * 8; } - else if (WIND_LAYER_CODE == vl_datap->mType || AURORA_WIND_LAYER_CODE == vl_datap->mType) + else if (WATER_LAYER_CODE == vl_datap->mType || WHITECORE_WATER_LAYER_CODE == vl_datap->mType) + { + mWaterBits += mesg_size * 8; + } + else if (WIND_LAYER_CODE == vl_datap->mType || WHITECORE_WIND_LAYER_CODE == vl_datap->mType) { mWindBits += mesg_size * 8; } - else if (CLOUD_LAYER_CODE == vl_datap->mType || AURORA_CLOUD_LAYER_CODE == vl_datap->mType) + else if (CLOUD_LAYER_CODE == vl_datap->mType || WHITECORE_CLOUD_LAYER_CODE == vl_datap->mType) { mCloudBits += mesg_size * 8; } else { - llerrs << "Unknown layer type!" << (S32)vl_datap->mType << llendl; + LL_ERRS() << "Unknown layer type!" << (S32)vl_datap->mType << LL_ENDL; } - mPacketData.put(vl_datap); + mPacketData.push_back(vl_datap); } void LLVLManager::unpackData(const S32 num_packets) { static LLFrameTimer decode_timer; - S32 i; - for (i = 0; i < mPacketData.count(); i++) + U32 i; + for (i = 0; i < mPacketData.size(); i++) { LLVLData *datap = mPacketData[i]; @@ -98,16 +107,16 @@ void LLVLManager::unpackData(const S32 num_packets) { datap->mRegionp->getLand().decompressDCTPatch(bit_pack, &goph, FALSE); } - else if (AURORA_LAND_LAYER_CODE == datap->mType) + else if (WHITECORE_LAND_LAYER_CODE == datap->mType) { datap->mRegionp->getLand().decompressDCTPatch(bit_pack, &goph, TRUE); } - else if (WIND_LAYER_CODE == datap->mType || AURORA_WIND_LAYER_CODE == datap->mType) + else if (WIND_LAYER_CODE == datap->mType || WHITECORE_WIND_LAYER_CODE == datap->mType) { datap->mRegionp->mWind.decompress(bit_pack, &goph); } - else if (CLOUD_LAYER_CODE == datap->mType || AURORA_CLOUD_LAYER_CODE == datap->mType) + else if (CLOUD_LAYER_CODE == datap->mType || WHITECORE_CLOUD_LAYER_CODE == datap->mType) { #if ENABLE_CLASSIC_CLOUDS datap->mRegionp->mCloudLayer.decompress(bit_pack, &goph); @@ -115,11 +124,11 @@ void LLVLManager::unpackData(const S32 num_packets) } } - for (i = 0; i < mPacketData.count(); i++) + for (i = 0; i < mPacketData.size(); i++) { delete mPacketData[i]; } - mPacketData.reset(); + mPacketData.clear(); } @@ -143,6 +152,11 @@ S32 LLVLManager::getCloudBits() const return mCloudBits; } +S32 LLVLManager::getWaterBits() const +{ + return mWaterBits; +} + S32 LLVLManager::getTotalBytes() const { return mLandBits + mWindBits + mCloudBits; @@ -150,13 +164,13 @@ S32 LLVLManager::getTotalBytes() const void LLVLManager::cleanupData(LLViewerRegion *regionp) { - S32 cur = 0; - while (cur < mPacketData.count()) + U32 cur = 0; + while (cur < mPacketData.size()) { if (mPacketData[cur]->mRegionp == regionp) { delete mPacketData[cur]; - mPacketData.remove(cur); + mPacketData.erase(mPacketData.begin() + cur); } else { @@ -176,6 +190,6 @@ LLVLData::LLVLData(LLViewerRegion *regionp, const S8 type, U8 *data, const S32 s LLVLData::~LLVLData() { delete [] mData; - mData = NULL; - mRegionp = NULL; + mData = nullptr; + mRegionp = nullptr; } diff --git a/indra/newview/llvlmanager.h b/indra/newview/llvlmanager.h index 9d64d6f24b..03d26d0db1 100644 --- a/indra/newview/llvlmanager.h +++ b/indra/newview/llvlmanager.h @@ -36,7 +36,6 @@ // This class manages the data coming in for viewer layers from the network. #include "stdtypes.h" -#include "lldarray.h" class LLVLData; class LLViewerRegion; @@ -55,16 +54,18 @@ class LLVLManager S32 getLandBits() const; S32 getWindBits() const; S32 getCloudBits() const; + S32 getWaterBits() const; void resetBitCounts(); void cleanupData(LLViewerRegion *regionp); protected: - LLDynamicArray mPacketData; + std::vector mPacketData; U32 mLandBits; U32 mWindBits; U32 mCloudBits; + U32 mWaterBits; }; class LLVLData @@ -74,10 +75,10 @@ class LLVLData const S8 type, U8 *data, const S32 size); ~LLVLData(); - S8 mType; + LLViewerRegion *mRegionp; U8 *mData; + S8 mType; S32 mSize; - LLViewerRegion *mRegionp; }; extern LLVLManager gVLManager; diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 9f7ad95fd5..b4a25bd166 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -24,12 +24,6 @@ * $/LicenseInfo$ */ -#if LL_MSVC -// disable warning about boost::lexical_cast returning uninitialized data -// when it fails to parse the string -#pragma warning (disable:4701) -#endif - #include "llviewerprecompiledheaders.h" #include "llvoavatar.h" @@ -38,15 +32,18 @@ #include #include "llaudioengine.h" -#include "noise.h" +#include "llperlin.h" #include "raytrace.h" #include "llagent.h" // Get state values from here +#include "llagentbenefits.h" #include "llagentcamera.h" #include "llagentwearables.h" #include "llanimationstates.h" +#include "llavataractions.h" #include "llavatarnamecache.h" #include "llavatarpropertiesprocessor.h" +#include "llcontrolavatar.h" #include "llphysicsmotion.h" #include "llviewercontrol.h" #include "lldrawpoolavatar.h" @@ -88,6 +85,7 @@ #include "llviewermenu.h" #include "llviewerobjectlist.h" #include "llviewerparcelmgr.h" +#include "llviewerregion.h" #include "llviewershadermgr.h" #include "llviewerstats.h" #include "llviewerwearable.h" @@ -106,46 +104,149 @@ #include "llvoicevisualizer.h" // Ventrella #include "llsdserialize.h" //For the client definitions +#include "aosystem.h" #include "llcachename.h" -#include "floaterao.h" #include "llsdutil.h" +#include "llskinningutil.h" + #include "llfloaterexploreanimations.h" -#include "aihttptimeoutpolicy.h" +#include "aixmllindengenepool.h" #include "llavatarname.h" +#include "../lscript/lscript_byteformat.h" #include "hippogridmanager.h" +#include "llrendersphere.h" + // [RLVa:KB] - Checked: 2010-04-01 (RLVa-1.2.0c) #include "rlvhandler.h" // [/RLVa:KB] -#if LL_MSVC -// disable boost::lexical_cast warning -#pragma warning (disable:4702) +#include + +#if LL_DARWIN +size_t strnlen(const char *s, size_t n) +{ + const char *p = (const char *)memchr(s, 0, n); + return(p ? p-s : n); +} #endif -#include -#include +extern U32 JOINT_COUNT_REQUIRED_FOR_FULLRIG; + +const F32 MAX_HOVER_Z = 2.0; +const F32 MIN_HOVER_Z = -2.0; + +const F32 MIN_ATTACHMENT_COMPLEXITY = 0.f; +const F32 DEFAULT_MAX_ATTACHMENT_COMPLEXITY = 1.0e6f; using namespace LLAvatarAppearanceDefines; //----------------------------------------------------------------------------- // Global constants //----------------------------------------------------------------------------- -const LLUUID ANIM_AGENT_BODY_NOISE = LLUUID("9aa8b0a6-0c6f-9518-c7c3-4f41f2c001ad"); //"body_noise" -const LLUUID ANIM_AGENT_BREATHE_ROT = LLUUID("4c5a103e-b830-2f1c-16bc-224aa0ad5bc8"); //"breathe_rot" -const LLUUID ANIM_AGENT_EDITING = LLUUID("2a8eba1d-a7f8-5596-d44a-b4977bf8c8bb"); //"editing" -const LLUUID ANIM_AGENT_EYE = LLUUID("5c780ea8-1cd1-c463-a128-48c023f6fbea"); //"eye" -const LLUUID ANIM_AGENT_FLY_ADJUST = LLUUID("db95561f-f1b0-9f9a-7224-b12f71af126e"); //"fly_adjust" -const LLUUID ANIM_AGENT_HAND_MOTION = LLUUID("ce986325-0ba7-6e6e-cc24-b17c4b795578"); //"hand_motion" -const LLUUID ANIM_AGENT_HEAD_ROT = LLUUID("e6e8d1dd-e643-fff7-b238-c6b4b056a68d"); //"head_rot" -const LLUUID ANIM_AGENT_PELVIS_FIX = LLUUID("0c5dd2a2-514d-8893-d44d-05beffad208b"); //"pelvis_fix" -const LLUUID ANIM_AGENT_TARGET = LLUUID("0e4896cb-fba4-926c-f355-8720189d5b55"); //"target" -const LLUUID ANIM_AGENT_WALK_ADJUST = LLUUID("829bc85b-02fc-ec41-be2e-74cc6dd7215d"); //"walk_adjust" -const LLUUID ANIM_AGENT_PHYSICS_MOTION = LLUUID("7360e029-3cb8-ebc4-863e-212df440d987"); //"physics_motion" +const LLUUID ANIM_AGENT_BODY_NOISE_ID = LLUUID("9aa8b0a6-0c6f-9518-c7c3-4f41f2c001ad"); //"body_noise" +const LLUUID ANIM_AGENT_BREATHE_ROT_ID = LLUUID("4c5a103e-b830-2f1c-16bc-224aa0ad5bc8"); //"breathe_rot" +const LLUUID ANIM_AGENT_EDITING_ID = LLUUID("2a8eba1d-a7f8-5596-d44a-b4977bf8c8bb"); //"editing" +const LLUUID ANIM_AGENT_EYE_ID = LLUUID("5c780ea8-1cd1-c463-a128-48c023f6fbea"); //"eye" +const LLUUID ANIM_AGENT_FLY_ADJUST_ID = LLUUID("db95561f-f1b0-9f9a-7224-b12f71af126e"); //"fly_adjust" +const LLUUID ANIM_AGENT_HAND_MOTION_ID = LLUUID("ce986325-0ba7-6e6e-cc24-b17c4b795578"); //"hand_motion" +const LLUUID ANIM_AGENT_HEAD_ROT_ID = LLUUID("e6e8d1dd-e643-fff7-b238-c6b4b056a68d"); //"head_rot" +const LLUUID ANIM_AGENT_PELVIS_FIX_ID = LLUUID("0c5dd2a2-514d-8893-d44d-05beffad208b"); //"pelvis_fix" +const LLUUID ANIM_AGENT_TARGET_ID = LLUUID("0e4896cb-fba4-926c-f355-8720189d5b55"); //"target" +const LLUUID ANIM_AGENT_WALK_ADJUST_ID = LLUUID("829bc85b-02fc-ec41-be2e-74cc6dd7215d"); //"walk_adjust" +const LLUUID ANIM_AGENT_PHYSICS_MOTION_ID = LLUUID("7360e029-3cb8-ebc4-863e-212df440d987"); //"physics_motion" + +// +// This must be in the same order as ANIM_AGENT_BODY_NOISE through ANIM_AGENT_WALK_ADJUST (see llmotion.h)! +static LLUUID const* lookup[] = { + &ANIM_AGENT_BODY_NOISE_ID, + &ANIM_AGENT_BREATHE_ROT_ID, + &ANIM_AGENT_PHYSICS_MOTION_ID, + &ANIM_AGENT_EDITING_ID, + &ANIM_AGENT_EYE_ID, + &ANIM_AGENT_FLY_ADJUST_ID, + &ANIM_AGENT_HAND_MOTION_ID, + &ANIM_AGENT_HEAD_ROT_ID, + &ANIM_AGENT_PELVIS_FIX_ID, + &ANIM_AGENT_TARGET_ID, + &ANIM_AGENT_WALK_ADJUST_ID +}; + +LLUUID const& mask2ID(U32 bit) +{ + int const lookupsize = sizeof(lookup) / sizeof(LLUUID const*); + int i = lookupsize - 1; + U32 mask = 1 << i; + for(;;) + { + if (bit == mask) + { + return *lookup[i]; + } + --i; + mask >>= 1; + llassert_always(i >= 0); + } +} + +#ifdef CWDEBUG +static char const* strlookup[] = { + "ANIM_AGENT_BODY_NOISE", + "ANIM_AGENT_BREATHE_ROT", + "ANIM_AGENT_PHYSICS_MOTION", + "ANIM_AGENT_EDITING", + "ANIM_AGENT_EYE", + "ANIM_AGENT_FLY_ADJUST", + "ANIM_AGENT_HAND_MOTION", + "ANIM_AGENT_HEAD_ROT", + "ANIM_AGENT_PELVIS_FIX", + "ANIM_AGENT_TARGET", + "ANIM_AGENT_WALK_ADJUST" +}; + +char const* mask2str(U32 bit) +{ + int const lookupsize = sizeof(lookup) / sizeof(LLUUID const*); + int i = lookupsize - 1; + U32 mask = 1 << i; + do + { + if (bit == mask) + { + return strlookup[i]; + } + --i; + mask >>= 1; + } + while(i >= 0); + return ""; +} +#endif + +// stopMotion(ANIM_AGENT_WALK_ADJUST) is called every frame, and for every avatar on the radar. +// That can be like 1000 times per second, so... speed that up a bit and lets not lookup the same LLUUID 1000 times +// per second in a std::map. Added the rest of the animations while I was at it. +void LLVOAvatar::startMotion(U32 bit, F32 time_offset) +{ + if (!isMotionActive(bit)) + { + mMotionController.disable_syncing(); // Don't attempt to synchronize AIMaskedMotion. + startMotion(mask2ID(bit), time_offset); + mMotionController.enable_syncing(); + } +} +void LLVOAvatar::stopMotion(U32 bit, BOOL stop_immediate) +{ + if (isMotionActive(bit)) + { + stopMotion(mask2ID(bit), stop_immediate); + } +} +// //----------------------------------------------------------------------------- // Constants @@ -187,6 +288,9 @@ const F32 HEAD_MOVEMENT_AVG_TIME = 0.9f; const S32 MORPH_MASK_REQUESTED_DISCARD = 0; +const F32 MAX_STANDOFF_FROM_ORIGIN = 3; +const F32 MAX_STANDOFF_DISTANCE_CHANGE = 32; + // Discard level at which to switch to baked textures // Should probably be 4 or 3, but didn't want to change it while change other logic - SJB const S32 SWITCH_TO_BAKED_DISCARD = 5; @@ -206,6 +310,14 @@ const S32 MAX_BUBBLE_CHAT_LENGTH = DB_CHAT_MSG_STR_LEN; const S32 MAX_BUBBLE_CHAT_UTTERANCES = 12; const F32 CHAT_FADE_TIME = 8.0; const F32 BUBBLE_CHAT_TIME = CHAT_FADE_TIME * 3.f; +const F32 NAMETAG_UPDATE_THRESHOLD = 0.3f; +const F32 NAMETAG_VERTICAL_SCREEN_OFFSET = 25.f; +const F32 NAMETAG_VERT_OFFSET_WEIGHT = 0.17f; + +const U32 LLVOAvatar::VISUAL_COMPLEXITY_UNKNOWN = 0; +const F64 HUD_OVERSIZED_TEXTURE_DATA_SIZE = 1024 * 1024; + +#define SLOW_ATTACHMENT_LIST 0 //Singu note: FADE and ALWAYS are swapped around from LL's source to match our preference panel. // Changing the "RenderName" order would cause confusion when 'always' setting suddenly gets @@ -242,16 +354,35 @@ struct LLTextureMaskData ** **/ +struct LLAppearanceMessageContents: public LLRefCount +{ + LLAppearanceMessageContents(): + mAppearanceVersion(-1), + mParamAppearanceVersion(-1), + mCOFVersion(LLViewerInventoryCategory::VERSION_UNKNOWN) + { + } + LLTEContents mTEContents; + S32 mAppearanceVersion; + S32 mParamAppearanceVersion; + S32 mCOFVersion; + // For future use: + //U32 appearance_flags = 0; + std::vector mParamWeights; + std::vector mParams; + LLVector3 mHoverOffset; + bool mHoverOffsetWasSet; +}; //----------------------------------------------------------------------------- // class LLBodyNoiseMotion //----------------------------------------------------------------------------- class LLBodyNoiseMotion : - public LLMotion + public AIMaskedMotion { public: // Constructor - LLBodyNoiseMotion(const LLUUID &id) - : LLMotion(id) + LLBodyNoiseMotion(LLUUID const& id, LLMotionController* controller) + : AIMaskedMotion(id, controller, ANIM_AGENT_BODY_NOISE) { mName = "body_noise"; mTorsoState = new LLJointState; @@ -266,7 +397,7 @@ class LLBodyNoiseMotion : //------------------------------------------------------------------------- // static constructor // all subclasses must implement such a function and register it - static LLMotion *create(const LLUUID &id) { return new LLBodyNoiseMotion(id); } + static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLBodyNoiseMotion(id, controller); } public: //------------------------------------------------------------------------- @@ -309,24 +440,13 @@ class LLBodyNoiseMotion : return STATUS_SUCCESS; } - // called when a motion is activated - // must return TRUE to indicate success, or else - // it will be deactivated - virtual BOOL onActivate() { return TRUE; } - // called per time step // must return TRUE while it is active, and // must return FALSE when the motion is completed. virtual BOOL onUpdate(F32 time, U8* joint_mask) { - F32 nx[2]; - nx[0]=time*TORSO_NOISE_SPEED; - nx[1]=0.0f; - F32 ny[2]; - ny[0]=0.0f; - ny[1]=time*TORSO_NOISE_SPEED; - F32 noiseX = noise2(nx); - F32 noiseY = noise2(ny); + F32 noiseX = LLPerlinNoise::noise(LLVector2(time*TORSO_NOISE_SPEED, 0)); + F32 noiseY = LLPerlinNoise::noise(LLVector2(0, time*TORSO_NOISE_SPEED)); F32 rx = TORSO_NOISE_AMOUNT * DEG_TO_RAD * noiseX / 0.42f; F32 ry = TORSO_NOISE_AMOUNT * DEG_TO_RAD * noiseY / 0.42f; @@ -337,9 +457,6 @@ class LLBodyNoiseMotion : return TRUE; } - // called when a motion is deactivated - virtual void onDeactivate() {} - private: //------------------------------------------------------------------------- // joint states to be animated @@ -351,12 +468,12 @@ class LLBodyNoiseMotion : // class LLBreatheMotionRot //----------------------------------------------------------------------------- class LLBreatheMotionRot : - public LLMotion + public AIMaskedMotion { public: // Constructor - LLBreatheMotionRot(const LLUUID &id) : - LLMotion(id), + LLBreatheMotionRot(LLUUID const& id, LLMotionController* controller) : + AIMaskedMotion(id, controller, ANIM_AGENT_BREATHE_ROT), mBreatheRate(1.f), mCharacter(NULL) { @@ -373,7 +490,7 @@ class LLBreatheMotionRot : //------------------------------------------------------------------------- // static constructor // all subclasses must implement such a function and register it - static LLMotion *create(const LLUUID &id) { return new LLBreatheMotionRot(id); } + static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLBreatheMotionRot(id, controller); } public: //------------------------------------------------------------------------- @@ -426,11 +543,6 @@ class LLBreatheMotionRot : } } - // called when a motion is activated - // must return TRUE to indicate success, or else - // it will be deactivated - virtual BOOL onActivate() { return TRUE; } - // called per time step // must return TRUE while it is active, and // must return FALSE when the motion is completed. @@ -445,9 +557,6 @@ class LLBreatheMotionRot : return TRUE; } - // called when a motion is deactivated - virtual void onDeactivate() {} - private: //------------------------------------------------------------------------- // joint states to be animated @@ -461,12 +570,12 @@ class LLBreatheMotionRot : // class LLPelvisFixMotion //----------------------------------------------------------------------------- class LLPelvisFixMotion : - public LLMotion + public AIMaskedMotion { public: // Constructor - LLPelvisFixMotion(const LLUUID &id) - : LLMotion(id), mCharacter(NULL) + LLPelvisFixMotion(LLUUID const& id, LLMotionController* controller) + : AIMaskedMotion(id, controller, ANIM_AGENT_PELVIS_FIX), mCharacter(NULL) { mName = "pelvis_fix"; @@ -482,7 +591,7 @@ class LLPelvisFixMotion : //------------------------------------------------------------------------- // static constructor // all subclasses must implement such a function and register it - static LLMotion *create(const LLUUID& id) { return new LLPelvisFixMotion(id); } + static LLMotion* create(LLUUID const& id, LLMotionController* controller) { return new LLPelvisFixMotion(id, controller); } public: //------------------------------------------------------------------------- @@ -527,11 +636,6 @@ class LLPelvisFixMotion : return STATUS_SUCCESS; } - // called when a motion is activated - // must return TRUE to indicate success, or else - // it will be deactivated - virtual BOOL onActivate() { return TRUE; } - // called per time step // must return TRUE while it is active, and // must return FALSE when the motion is completed. @@ -542,9 +646,6 @@ class LLPelvisFixMotion : return TRUE; } - // called when a motion is deactivated - virtual void onDeactivate() {} - private: //------------------------------------------------------------------------- // joint states to be animated @@ -564,6 +665,7 @@ SHClientTagMgr::SHClientTagMgr() gSavedSettings.getControl("AscentEstateOwnerColor")->getSignal()->connect(boost::bind(&LLVOAvatar::invalidateNameTags)); gSavedSettings.getControl("AscentFriendColor")->getSignal()->connect(boost::bind(&LLVOAvatar::invalidateNameTags)); gSavedSettings.getControl("AscentMutedColor")->getSignal()->connect(boost::bind(&LLVOAvatar::invalidateNameTags)); + gSavedSettings.getControl("SLBDisplayClientTagOnNewLine")->getSignal()->connect(boost::bind(&LLVOAvatar::invalidateNameTags)); //Following group of settings all actually manipulate the tag cache for agent avatar. Even if the tag system is 'disabled', we still allow an //entry to exist for the agent avatar. @@ -640,7 +742,7 @@ bool SHClientTagMgr::parseDefinitions() mClientDefinitions.clear(); for (LLSD::map_const_iterator it = client_list.beginMap(); it != client_list.endMap(); ++it) { - llinfos << it->first << llendl; + LL_INFOS() << it->first << LL_ENDL; LLUUID id; if(id.set(it->first,false)) { @@ -655,9 +757,9 @@ bool SHClientTagMgr::parseDefinitions() color *= 1.f/(mult+1.f); info.insert("color", color.getValue()); } - llinfos << info["name"] << " : " << info["id"] << llendl; + LL_INFOS() << info["name"] << " : " << info["id"] << LL_ENDL; mClientDefinitions[id]=info; - llinfos << mClientDefinitions.size() << llendl; + LL_INFOS() << mClientDefinitions.size() << LL_ENDL; } } if(getIsEnabled()) @@ -721,16 +823,12 @@ const LLSD SHClientTagMgr::generateClientTag(const LLVOAvatar* pAvatar) const if(pAvatar->isFullyLoaded() && pTextureEntry->getGlow() > 0.0) { - ///llinfos << "Using new client identifier." << llendl; - U8 tag_buffer[UUID_BYTES+1]; - memset(&tag_buffer, 0, UUID_BYTES); - memcpy(&tag_buffer[0], &id.mData, UUID_BYTES); - tag_buffer[UUID_BYTES] = 0; - U32 tag_len = llmin((S32)strlen((const char*)&tag_buffer[0]), UUID_BYTES); - std::string client((char*)&tag_buffer[0], tag_len); + ///LL_INFOS() << "Using new client identifier." << LL_ENDL; + U32 tag_len = strnlen((const char*)&id.mData[0], UUID_BYTES); + std::string client((const char*)&id.mData[0], tag_len); LLStringFn::replace_ascii_controlchars(client, LL_UNKNOWN_CHAR); LLSD info; - info.insert("name", std::string((char*)&tag_buffer[0], tag_len)); + info.insert("name", client); info.insert("color", pTextureEntry->getColor().getValue()); return info; } @@ -838,46 +936,55 @@ const LLUUID SHClientTagMgr::getClientID(const LLVOAvatar* pAvatar) const } return tag.asUUID(); } +bool getColorFor(const LLUUID& id, LLViewerRegion* parent_estate, LLColor4& color, bool name_restricted = false) +{ + static const LLCachedControl ascent_linden_color("AscentLindenColor"); + static const LLCachedControl ascent_estate_owner_color("AscentEstateOwnerColor" ); + static const LLCachedControl ascent_friend_color("AscentFriendColor"); + static const LLCachedControl ascent_muted_color("AscentMutedColor"); + //Lindens are always more Linden than your friend, make that take precedence + if (LLMuteList::getInstance()->isLinden(id)) + color = ascent_linden_color; + //check if they are an estate owner at their current position + else if (parent_estate && parent_estate->isAlive() && id.notNull() && id == parent_estate->getOwner()) + color = ascent_estate_owner_color; + //without these dots, SL would suck. + else if (!name_restricted && LLAvatarTracker::instance().isBuddy(id)) + color = ascent_friend_color; + //big fat jerkface who is probably a jerk, display them as such. + else if (LLMuteList::getInstance()->isMuted(id)) + color = ascent_muted_color; + else + return false; + return true; +} +bool mm_getMarkerColor(const LLUUID&, LLColor4&); +bool getCustomColor(const LLUUID& id, LLColor4& color, LLViewerRegion* parent_estate) +{ + return mm_getMarkerColor(id, color) || getColorFor(id, parent_estate, color); +} +bool getCustomColorRLV(const LLUUID& id, LLColor4& color, LLViewerRegion* parent_estate, bool name_restricted) +{ + return mm_getMarkerColor(id, color) || getColorFor(id, parent_estate, color, name_restricted); +} bool SHClientTagMgr::getClientColor(const LLVOAvatar* pAvatar, bool check_status, LLColor4& color) const { + const LLUUID& id(pAvatar->getID()); + if (mm_getMarkerColor(id, color)) return true; static const LLCachedControl ascent_use_status_colors("AscentUseStatusColors",true); static const LLCachedControl ascent_show_self_tag_color("AscentShowSelfTagColor"); static const LLCachedControl ascent_show_others_tag_color("AscentShowOthersTagColor"); - if(check_status && ascent_use_status_colors && !pAvatar->isSelf()) + if (check_status && ascent_use_status_colors && !pAvatar->isSelf()) { - LLViewerRegion* parent_estate = LLWorld::getInstance()->getRegionFromPosGlobal(pAvatar->getPositionGlobal()); - if(LLMuteList::getInstance()->isLinden(pAvatar->getFullname())) - { - static const LLCachedControl ascent_linden_color( "AscentLindenColor" ); - color = ascent_linden_color.get(); - return true; - } - else if(pAvatar->getID().notNull() && parent_estate && parent_estate->isAlive() && pAvatar->getID() == parent_estate->getOwner()) - { - static const LLCachedControl ascent_estate_owner_color( "AscentEstateOwnerColor" ); - color = ascent_estate_owner_color.get(); - return true; - } - else if(LLAvatarTracker::instance().isBuddy(pAvatar->getID())) - { - static const LLCachedControl ascent_friend_color( "AscentFriendColor" ); - color = ascent_friend_color.get(); - return true; - } - else if(LLMuteList::getInstance()->isMuted(pAvatar->getID())) - { - static const LLCachedControl ascent_muted_color( "AscentMutedColor" ); - color = ascent_muted_color.get(); + if (getColorFor(id, pAvatar->getRegion(), color, false)) return true; - } } std::map::const_iterator it; LLSD tag; if( - ((pAvatar->isSelf() && ascent_show_self_tag_color) || - (!pAvatar->isSelf() && ascent_show_others_tag_color)) && - (it = mAvatarTags.find(pAvatar->getID()))!=mAvatarTags.end() && + (pAvatar->isSelf() ? ascent_show_self_tag_color : ascent_show_others_tag_color) && + (it = mAvatarTags.find(id))!=mAvatarTags.end() && (tag = it->second.get("color")).isDefined()) { color.setValue(tag); @@ -923,28 +1030,27 @@ const LLUUID LLVOAvatar::sStepSounds[LL_MCODE_END] = S32 LLVOAvatar::sRenderName = RENDER_NAME_ALWAYS; bool LLVOAvatar::sRenderGroupTitles = true; S32 LLVOAvatar::sNumVisibleChatBubbles = 0; -BOOL LLVOAvatar::sDebugInvisible = FALSE; -BOOL LLVOAvatar::sShowAttachmentPoints = FALSE; -BOOL LLVOAvatar::sShowAnimationDebug = FALSE; -BOOL LLVOAvatar::sShowFootPlane = FALSE; -BOOL LLVOAvatar::sVisibleInFirstPerson = FALSE; +BOOL LLVOAvatar::sDebugInvisible = false; +bool LLVOAvatar::sShowAttachmentPoints = false; +BOOL LLVOAvatar::sShowAnimationDebug = false; +bool LLVOAvatar::sShowFootPlane = false; +bool LLVOAvatar::sVisibleInFirstPerson = false; F32 LLVOAvatar::sLODFactor = 1.f; F32 LLVOAvatar::sPhysicsLODFactor = 1.f; -BOOL LLVOAvatar::sUseImpostors = FALSE; -BOOL LLVOAvatar::sJointDebug = FALSE; +bool LLVOAvatar::sUseImpostors = false; +BOOL LLVOAvatar::sJointDebug = false; F32 LLVOAvatar::sUnbakedTime = 0.f; F32 LLVOAvatar::sUnbakedUpdateTime = 0.f; F32 LLVOAvatar::sGreyTime = 0.f; F32 LLVOAvatar::sGreyUpdateTime = 0.f; //Move to LLVOAvatarSelf -BOOL LLVOAvatar::sDebugAvatarRotation = FALSE; +BOOL LLVOAvatar::sDebugAvatarRotation = false; //----------------------------------------------------------------------------- // Helper functions //----------------------------------------------------------------------------- static F32 calc_bouncy_animation(F32 x); -static U32 calc_shame(LLVOVolume* volume, std::set &textures); //----------------------------------------------------------------------------- // LLVOAvatar() @@ -955,8 +1061,10 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, LLAvatarAppearance(&gAgentWearables), LLViewerObject(id, pcode, regionp), mSpecialRenderMode(0), - mAttachmentGeometryBytes(0), mAttachmentSurfaceArea(0.f), + mAttachmentVisibleTriangleCount(0), + mAttachmentEstTriangleCount(0.f), + mReportedVisualComplexity(VISUAL_COMPLEXITY_UNKNOWN), mTurning(FALSE), mFreezeTimeLangolier(false), mFreezeTimeDead(false), @@ -966,6 +1074,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, mTyping(FALSE), mMeshValid(FALSE), mVisible(FALSE), + mLastImpostorUpdateFrameTime(0.f), mWindFreq(0.f), mRipplePhase( 0.f ), mBelowWater(FALSE), @@ -988,35 +1097,42 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, mNeedsSkin(FALSE), mLastSkinTime(0.f), mUpdatePeriod(1), + mVisualComplexityStale(true), mFirstFullyVisible(TRUE), mFullyLoaded(FALSE), mPreviousFullyLoaded(FALSE), mFullyLoadedInitialized(FALSE), + mVisualComplexity(0), mSupportsAlphaLayers(FALSE), mLoadedCallbacksPaused(FALSE), - mHasPelvisOffset( FALSE ), mLastRezzedStatus(-1), mIsEditingAppearance(FALSE), mUseLocalAppearance(FALSE), - mUseServerBakes(FALSE), // FIXME DRANO consider using boost::optional, defaulting to unknown. + mUseServerBakes(FALSE), + mLastUpdateRequestCOFVersion(-1), + mLastUpdateReceivedCOFVersion(-1), + mIsControlAvatar(false), + mIsUIAvatar(false), + mEnableDefaultMotions(true), // mHasPhysicsParameters( false ), mIdleMinute(0), mCCSChatTextOverride(false) // { - mAttachedObjectsVector.reserve(MAX_AGENT_ATTACHMENTS); + mAttachedObjectsVector.reserve(38); static LLCachedControl const freeze_time("FreezeTime", false); mFreezeTimeLangolier = freeze_time; //VTResume(); // VTune + setHoverOffset(LLVector3(0.0, 0.0, 0.0)); // mVoiceVisualizer is created by the hud effects manager and uses the HUD Effects pipeline const bool needsSendToSim = false; // currently, this HUD effect doesn't need to pack and unpack data to do its job mVoiceVisualizer = ( LLVoiceVisualizer *)LLHUDManager::getInstance()->createViewerEffect( LLHUDObject::LL_HUD_EFFECT_VOICE_VISUALIZER, needsSendToSim ); - lldebugs << "LLVOAvatar Constructor (0x" << this << ") id:" << mID << llendl; + LL_DEBUGS("Avatar","Message") << "LLVOAvatar Constructor (0x" << this << ") id:" << mID << LL_ENDL; mPelvisp = NULL; @@ -1032,6 +1148,8 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, mNeedsImpostorUpdate = TRUE; mNeedsAnimUpdate = TRUE; + mNeedsExtentUpdate = true; + mImpostorDistance = 0; mImpostorPixelArea = 0; @@ -1064,16 +1182,20 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, mRuthTimer.reset(); mRuthDebugTimer.reset(); mDebugExistenceTimer.reset(); - mPelvisOffset = LLVector3(0.0f,0.0f,0.0f); - mLastPelvisToFoot = 0.0f; - mPelvisFixup = 0.0f; - mLastPelvisFixup = 0.0f; + mLastAppearanceMessageTimer.reset(); } std::string LLVOAvatar::avString() const { - std::string viz_string = LLVOAvatar::rezStatusToString(getRezzedStatus()); - return " Avatar '" + getFullname() + "' " + viz_string + " "; + if (isControlAvatar()) + { + return getFullname(); + } + else + { + std::string viz_string = LLVOAvatar::rezStatusToString(getRezzedStatus()); + return " Avatar '" + getFullname() + "' " + viz_string + " "; + } } void LLVOAvatar::debugAvatarRezTime(std::string notification_name, std::string comment) @@ -1084,7 +1206,7 @@ void LLVOAvatar::debugAvatarRezTime(std::string notification_name, std::string c << "RuthTimer " << (U32)mRuthDebugTimer.getElapsedTimeF32() << " Notification " << notification_name << " : " << comment - << llendl; + << LL_ENDL; if (gSavedSettings.getBOOL("DebugAvatarRezTime")) { @@ -1095,6 +1217,10 @@ void LLVOAvatar::debugAvatarRezTime(std::string notification_name, std::string c LLNotificationsUtil::add(notification_name,args); } } + +//------------------------------------------------------------------------ +// LLVOAvatar::~LLVOAvatar() +//------------------------------------------------------------------------ LLVOAvatar::~LLVOAvatar() { //App teardown is a mess. Avatar destruction can be unpredictable due to all potential refs to the smartptr. @@ -1113,10 +1239,9 @@ LLVOAvatar::~LLVOAvatar() //logPendingPhases(); - lldebugs << "LLVOAvatar Destructor (0x" << this << ") id:" << mID << llendl; + LL_DEBUGS("Avatar") << "LLVOAvatar Destructor (0x" << this << ") id:" << mID << LL_ENDL; std::for_each(mAttachmentPoints.begin(), mAttachmentPoints.end(), DeletePairedPointer()); - //mAttachmentPoints.clear(); mDead = TRUE; @@ -1127,7 +1252,7 @@ LLVOAvatar::~LLVOAvatar() SHClientTagMgr::instance().clearAvatarTag(this); - lldebugs << "LLVOAvatar Destructor end" << llendl; + LL_DEBUGS() << "LLVOAvatar Destructor end" << LL_ENDL; } void LLVOAvatar::markDead() @@ -1152,7 +1277,6 @@ void LLVOAvatar::markDead() logPendingPhases(); LLViewerObject::markDead(); - } @@ -1164,7 +1288,8 @@ BOOL LLVOAvatar::isFullyBaked() for (U32 i = 0; i < mBakedTextureDatas.size(); i++) { if (!isTextureDefined(mBakedTextureDatas[i].mTextureIndex) - && ( (i != BAKED_SKIRT) || isWearingWearableType(LLWearableType::WT_SKIRT) ) ) + && ( (i != BAKED_SKIRT) || isWearingWearableType(LLWearableType::WT_SKIRT) ) + && (i != BAKED_LEFT_ARM) && (i != BAKED_LEFT_LEG) && (i != BAKED_AUX1) && (i != BAKED_AUX2) && (i != BAKED_AUX3) ) { return FALSE; } @@ -1174,7 +1299,7 @@ BOOL LLVOAvatar::isFullyBaked() BOOL LLVOAvatar::isFullyTextured() const { - for (U32 i = 0; i < (U32)mMeshLOD.size(); i++) + for (U32 i = 0; i < mMeshLOD.size(); i++) { LLAvatarJoint* joint = mMeshLOD[i]; if (i==MESH_ID_SKIRT && !isWearingWearableType(LLWearableType::WT_SKIRT)) @@ -1235,11 +1360,7 @@ void LLVOAvatar::deleteLayerSetCaches(bool clearAll) mBakedTextureDatas[i].mTexLayerSet->deleteCaches(); } } - if (mBakedTextureDatas[i].mMaskTexName) - { - LLImageGL::deleteTextures(LLTexUnit::TT_TEXTURE, 0, -1, 1, (GLuint*)&(mBakedTextureDatas[i].mMaskTexName)); - mBakedTextureDatas[i].mMaskTexName = 0 ; - } + mBakedTextureDatas[i].mMaskTexName.reset(); } } @@ -1277,10 +1398,11 @@ void LLVOAvatar::getNearbyRezzedStats(std::vector& counts) iter != LLCharacter::sInstances.end(); ++iter) { LLVOAvatar* inst = (LLVOAvatar*) *iter; - if (!inst) - continue; - S32 rez_status = inst->getRezzedStatus(); - counts[rez_status]++; + if (inst) + { + S32 rez_status = inst->getRezzedStatus(); + counts[rez_status]++; + } } } @@ -1289,8 +1411,8 @@ std::string LLVOAvatar::rezStatusToString(S32 rez_status) { if (rez_status==0) return "cloud"; if (rez_status==1) return "gray"; - if (rez_status==2) return "textured"; - if (rez_status==3) return "textured_and_downloaded"; + if (rez_status==2) return "downloading"; + if (rez_status==3) return "full"; return "unknown"; } @@ -1303,54 +1425,54 @@ void LLVOAvatar::dumpBakedStatus() iter != LLCharacter::sInstances.end(); ++iter) { LLVOAvatar* inst = (LLVOAvatar*) *iter; - llinfos << "Avatar "; + LL_INFOS() << "Avatar "; LLNameValue* firstname = inst->getNVPair("FirstName"); LLNameValue* lastname = inst->getNVPair("LastName"); if( firstname ) { - llcont << firstname->getString(); + LL_CONT << firstname->getString(); } if( lastname ) { - llcont << " " << lastname->getString(); + LL_CONT << " " << lastname->getString(); } - llcont << " " << inst->mID; + LL_CONT << " " << inst->mID; if( inst->isDead() ) { - llcont << " DEAD ("<< inst->getNumRefs() << " refs)"; + LL_CONT << " DEAD ("<< inst->getNumRefs() << " refs)"; } if( inst->isSelf() ) { - llcont << " (self)"; + LL_CONT << " (self)"; } F64 dist_to_camera = (inst->getPositionGlobal() - camera_pos_global).length(); - llcont << " " << dist_to_camera << "m "; + LL_CONT << " " << dist_to_camera << "m "; - llcont << " " << inst->mPixelArea << " pixels"; + LL_CONT << " " << inst->mPixelArea << " pixels"; if( inst->isVisible() ) { - llcont << " (visible)"; + LL_CONT << " (visible)"; } else { - llcont << " (not visible)"; + LL_CONT << " (not visible)"; } if( inst->isFullyBaked() ) { - llcont << " Baked"; + LL_CONT << " Baked"; } else { - llcont << " Unbaked ("; + LL_CONT << " Unbaked ("; for (LLAvatarAppearanceDictionary::BakedTextures::const_iterator iter = LLAvatarAppearanceDictionary::getInstance()->getBakedTextures().begin(); iter != LLAvatarAppearanceDictionary::getInstance()->getBakedTextures().end(); @@ -1360,16 +1482,16 @@ void LLVOAvatar::dumpBakedStatus() const ETextureIndex index = baked_dict->mTextureIndex; if (!inst->isTextureDefined(index)) { - llcont << " " << LLAvatarAppearanceDictionary::getInstance()->getTexture(index)->mName; + LL_CONT << " " << (LLAvatarAppearanceDictionary::getInstance()->getTexture(index) ? LLAvatarAppearanceDictionary::getInstance()->getTexture(index)->mName : ""); } } - llcont << " ) " << inst->getUnbakedPixelAreaRank(); + LL_CONT << " ) " << inst->getUnbakedPixelAreaRank(); if( inst->isCulled() ) { - llcont << " culled"; + LL_CONT << " culled"; } } - llcont << llendl; + LL_CONT << LL_ENDL; } } @@ -1402,6 +1524,7 @@ void LLVOAvatar::resetImpostors() { LLVOAvatar* avatar = (LLVOAvatar*) *iter; avatar->mImpostor.release(); + avatar->mNeedsImpostorUpdate = TRUE; } } @@ -1410,7 +1533,7 @@ void LLVOAvatar::deleteCachedImages(bool clearAll) { if (LLViewerTexLayerSet::sHasCaches) { - lldebugs << "Deleting layer set caches" << llendl; + LL_DEBUGS() << "Deleting layer set caches" << LL_ENDL; for (std::vector::iterator iter = LLCharacter::sInstances.begin(); iter != LLCharacter::sInstances.end(); ++iter) { @@ -1419,7 +1542,6 @@ void LLVOAvatar::deleteCachedImages(bool clearAll) } LLViewerTexLayerSet::sHasCaches = FALSE; } - LLVOAvatarSelf::deleteScratchTextures(); LLTexLayerStaticImageList::getInstance()->deleteCachedImages(); } @@ -1430,19 +1552,21 @@ void LLVOAvatar::deleteCachedImages(bool clearAll) //------------------------------------------------------------------------ void LLVOAvatar::initClass() { - gAnimLibrary.animStateSetString(ANIM_AGENT_BODY_NOISE,"body_noise"); - gAnimLibrary.animStateSetString(ANIM_AGENT_BREATHE_ROT,"breathe_rot"); - gAnimLibrary.animStateSetString(ANIM_AGENT_PHYSICS_MOTION,"physics_motion"); - gAnimLibrary.animStateSetString(ANIM_AGENT_EDITING,"editing"); - gAnimLibrary.animStateSetString(ANIM_AGENT_EYE,"eye"); - gAnimLibrary.animStateSetString(ANIM_AGENT_FLY_ADJUST,"fly_adjust"); - gAnimLibrary.animStateSetString(ANIM_AGENT_HAND_MOTION,"hand_motion"); - gAnimLibrary.animStateSetString(ANIM_AGENT_HEAD_ROT,"head_rot"); - gAnimLibrary.animStateSetString(ANIM_AGENT_PELVIS_FIX,"pelvis_fix"); - gAnimLibrary.animStateSetString(ANIM_AGENT_TARGET,"target"); - gAnimLibrary.animStateSetString(ANIM_AGENT_WALK_ADJUST,"walk_adjust"); + gAnimLibrary.animStateSetString(ANIM_AGENT_BODY_NOISE_ID,"body_noise"); + gAnimLibrary.animStateSetString(ANIM_AGENT_BREATHE_ROT_ID,"breathe_rot"); + gAnimLibrary.animStateSetString(ANIM_AGENT_PHYSICS_MOTION_ID,"physics_motion"); + gAnimLibrary.animStateSetString(ANIM_AGENT_EDITING_ID,"editing"); + gAnimLibrary.animStateSetString(ANIM_AGENT_EYE_ID,"eye"); + gAnimLibrary.animStateSetString(ANIM_AGENT_FLY_ADJUST_ID,"fly_adjust"); + gAnimLibrary.animStateSetString(ANIM_AGENT_HAND_MOTION_ID,"hand_motion"); + gAnimLibrary.animStateSetString(ANIM_AGENT_HEAD_ROT_ID,"head_rot"); + gAnimLibrary.animStateSetString(ANIM_AGENT_PELVIS_FIX_ID,"pelvis_fix"); + gAnimLibrary.animStateSetString(ANIM_AGENT_TARGET_ID,"target"); + gAnimLibrary.animStateSetString(ANIM_AGENT_WALK_ADJUST_ID,"walk_adjust"); SHClientTagMgr::instance(); //Instantiate. Parse. Will fetch a new tag file if AscentUpdateTagsOnLoad is true. + + LLControlAvatar::sRegionChangedSlot = gAgent.addRegionChangedCallback(&LLControlAvatar::onRegionChanged); } @@ -1451,7 +1575,7 @@ void LLVOAvatar::cleanupClass() } // virtual -void LLVOAvatar::initInstance(void) +void LLVOAvatar::initInstance() { //------------------------------------------------------------------------- // register motions @@ -1459,7 +1583,7 @@ void LLVOAvatar::initInstance(void) if (LLCharacter::sInstances.size() == 1) { LLKeyframeMotion::setVFS(gStaticVFS); - registerMotion( ANIM_AGENT_BUSY, LLNullMotion::create ); + registerMotion(ANIM_AGENT_DO_NOT_DISTURB, LLNullMotion::create ); registerMotion( ANIM_AGENT_CROUCH, LLKeyframeStandMotion::create ); registerMotion( ANIM_AGENT_CROUCHWALK, LLKeyframeWalkMotion::create ); registerMotion( ANIM_AGENT_EXPRESS_AFRAID, LLEmote::create ); @@ -1498,28 +1622,23 @@ void LLVOAvatar::initInstance(void) registerMotion( ANIM_AGENT_WALK_NEW, LLKeyframeWalkMotion::create ); //v2 // motions without a start/stop bit - registerMotion( ANIM_AGENT_BODY_NOISE, LLBodyNoiseMotion::create ); - registerMotion( ANIM_AGENT_BREATHE_ROT, LLBreatheMotionRot::create ); - registerMotion( ANIM_AGENT_PHYSICS_MOTION, LLPhysicsMotionController::create ); - registerMotion( ANIM_AGENT_EDITING, LLEditingMotion::create ); - registerMotion( ANIM_AGENT_EYE, LLEyeMotion::create ); - registerMotion( ANIM_AGENT_FLY_ADJUST, LLFlyAdjustMotion::create ); - registerMotion( ANIM_AGENT_HAND_MOTION, LLHandMotion::create ); - registerMotion( ANIM_AGENT_HEAD_ROT, LLHeadRotMotion::create ); - registerMotion( ANIM_AGENT_PELVIS_FIX, LLPelvisFixMotion::create ); + registerMotion( ANIM_AGENT_BODY_NOISE_ID, LLBodyNoiseMotion::create ); + registerMotion( ANIM_AGENT_BREATHE_ROT_ID, LLBreatheMotionRot::create ); + registerMotion( ANIM_AGENT_PHYSICS_MOTION_ID, LLPhysicsMotionController::create ); + registerMotion( ANIM_AGENT_EDITING_ID, LLEditingMotion::create ); + registerMotion( ANIM_AGENT_EYE_ID, LLEyeMotion::create ); + //registerMotion( ANIM_AGENT_FEMALE_WALK, LLKeyframeWalkMotion::create ); + registerMotion( ANIM_AGENT_FLY_ADJUST_ID, LLFlyAdjustMotion::create ); + registerMotion( ANIM_AGENT_HAND_MOTION_ID, LLHandMotion::create ); + registerMotion( ANIM_AGENT_HEAD_ROT_ID, LLHeadRotMotion::create ); + registerMotion( ANIM_AGENT_PELVIS_FIX_ID, LLPelvisFixMotion::create ); registerMotion( ANIM_AGENT_SIT_FEMALE, LLKeyframeMotion::create ); - registerMotion( ANIM_AGENT_TARGET, LLTargetingMotion::create ); - registerMotion( ANIM_AGENT_WALK_ADJUST, LLWalkAdjustMotion::create ); - + registerMotion( ANIM_AGENT_TARGET_ID, LLTargetingMotion::create ); + registerMotion( ANIM_AGENT_WALK_ADJUST_ID, LLWalkAdjustMotion::create ); } LLAvatarAppearance::initInstance(); - if (gNoRender) - { - return; - } - // preload specific motions here createMotion( ANIM_AGENT_CUSTOMIZE); createMotion( ANIM_AGENT_CUSTOMIZE_DONE); @@ -1527,6 +1646,8 @@ void LLVOAvatar::initInstance(void) //VTPause(); // VTune mVoiceVisualizer->setVoiceEnabled( LLVoiceClient::getInstance()->getVoiceEnabled( mID ) ); + + mInitFlags |= 1<<1; } // virtual @@ -1555,27 +1676,32 @@ LLTexLayerSet* LLVOAvatar::createTexLayerSet() const LLVector3 LLVOAvatar::getRenderPosition() const { + if (mDrawable.isNull() || mDrawable->getGeneration() < 0) { return getPositionAgent(); } - else if (isRoot() || !mDrawable->getParent()) + else if (isRoot()/* || !mDrawable->getParent()*/) // Animesh- { - if ( !mHasPelvisOffset ) - { - return mDrawable->getPositionAgent(); - } - else + F32 fixup; + if ( hasPelvisFixup( fixup) ) { //Apply a pelvis fixup (as defined by the avs skin) LLVector3 pos = mDrawable->getPositionAgent(); - pos[VZ] += mPelvisFixup; + pos[VZ] += fixup; return pos; } + else + { + return mDrawable->getPositionAgent(); + } } else { - return getPosition() * mDrawable->getParent()->getRenderMatrix(); + LLVector4a pos; + pos.load3(getPosition().mV); + mDrawable->getParent()->getRenderMatrix().affineTransform(pos,pos); + return LLVector3(pos.getF32ptr()); } } @@ -1593,6 +1719,29 @@ void LLVOAvatar::onShift(const LLVector4a& shift_vector) void LLVOAvatar::updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax) { + if (mDrawable.isNull()) + { + return; + } + + if (mNeedsExtentUpdate) + { + calculateSpatialExtents(newMin,newMax); + mLastAnimExtents[0].set(newMin.getF32ptr()); + mLastAnimExtents[1].set(newMax.getF32ptr()); + mLastAnimBasePos = mPelvisp->getWorldPosition(); + mNeedsExtentUpdate = false; + } + else + { + LLVector3 new_base_pos = mPelvisp->getWorldPosition(); + LLVector3 shift = new_base_pos-mLastAnimBasePos; + mLastAnimExtents[0] += shift; + mLastAnimExtents[1] += shift; + mLastAnimBasePos = new_base_pos; + + } + if (isImpostor() && !needsImpostorUpdate()) { LLVector3 delta = getRenderPosition() - @@ -1603,9 +1752,8 @@ void LLVOAvatar::updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax) } else { - getSpatialExtents(newMin,newMax); - mLastAnimExtents[0].set(newMin.getF32ptr()); - mLastAnimExtents[1].set(newMax.getF32ptr()); + newMin.load3(mLastAnimExtents[0].mV); + newMax.load3(mLastAnimExtents[1].mV); LLVector4a pos_group; pos_group.setAdd(newMin,newMax); pos_group.mul(0.5f); @@ -1614,85 +1762,139 @@ void LLVOAvatar::updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax) } } -void LLVOAvatar::getSpatialExtents(LLVector4a& newMin, LLVector4a& newMax) -{ - static const LLCachedControl control_derender_huge_attachments("DerenderHugeAttachments", true); - static const LLCachedControl control_max_attachment_span("MaxAttachmentSpan", 5.0f * DEFAULT_MAX_PRIM_SCALE); - LLVector4a buffer(0.25f); - LLVector4a pos; - pos.load3(getRenderPosition().mV); - newMin.setSub(pos, buffer); - newMax.setAdd(pos, buffer); +static LLTrace::BlockTimerStatHandle FTM_AVATAR_EXTENT_UPDATE("Av Upd Extent"); - float max_attachment_span = llmax(DEFAULT_MAX_PRIM_SCALE, control_max_attachment_span); +void LLVOAvatar::calculateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax) +{ - //stretch bounding box by joint positions - for (polymesh_map_t::iterator i = mPolyMeshes.begin(); i != mPolyMeshes.end(); ++i) - { - LLPolyMesh* mesh = i->second; - for (S32 joint_num = 0; joint_num < mesh->mJointRenderData.count(); joint_num++) - { - LLVector4a trans; - trans.load3( mesh->mJointRenderData[joint_num]->mWorldMatrix->getTranslation().mV); - update_min_max(newMin, newMax, trans); - } - } - - LLVector4a center, size; - center.setAdd(newMin, newMax); - center.mul(0.5f); + LL_RECORD_BLOCK_TIME(FTM_AVATAR_EXTENT_UPDATE); - size.setSub(newMax,newMin); - size.mul(0.5f); - - mPixelArea = LLPipeline::calcPixelArea(center, size, *LLViewerCamera::getInstance()); + static const LLCachedControl control_derender_huge_attachments("DerenderHugeAttachments", true); + static const LLCachedControl box_detail("AvatarBoundingBoxComplexity"); + // FIXME the update_min_max function used below assumes there is a + // known starting point, but in general there isn't. Ideally the + // box update logic should be modified to handle the no-point-yet + // case. For most models, starting with the pelvis is safe though. + LLVector3 zero_pos; + LLVector4a pos; + if (dist_vec(zero_pos, mPelvisp->getWorldPosition())<0.001) + { + // Don't use pelvis until av initialized + pos.load3(getRenderPosition().mV); + } + else + { + pos.load3(mPelvisp->getWorldPosition().mV); + } + newMin = pos; + newMax = pos; + + //stretch bounding box by joint positions. Doing this for + //control avs, where the polymeshes aren't maintained or + //displayed, can give inaccurate boxes due to joints stuck at (0,0,0). + if ((box_detail >= 1) && !isControlAvatar()) + { + for (polymesh_map_t::iterator i = mPolyMeshes.begin(); i != mPolyMeshes.end(); ++i) + { + LLPolyMesh* mesh = i->second; + for (const auto& joint : mesh->mJointRenderData) + { + static const LLVector4Logical mask = _mm_load_ps((F32*)&S_V4LOGICAL_MASK_TABLE[3 * 4]); + LLVector4a trans; + trans.setSelectWithMask(mask, _mm_setzero_ps(), joint->mWorldMatrix->getRow<3>()); + update_min_max(newMin, newMax, trans); + } + } + } + + // Pad bounding box for starting joint, plus polymesh if + // applicable. Subsequent calcs should be accurate enough to not + // need padding. + LLVector4a padding(0.25); + newMin.sub(padding); + newMax.add(padding); + static std::vector removal; - //stretch bounding box by attachments - for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); - iter != mAttachmentPoints.end(); - ++iter) + //stretch bounding box by static attachments + if (box_detail >= 2) { - LLViewerJointAttachment* attachment = iter->second; - - if (!attachment->getValid()) + + float max_attachment_span = get_default_max_prim_scale() * 5.0f; +#if SLOW_ATTACHMENT_LIST + for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); + ++iter) { - continue ; - } + LLViewerJointAttachment* attachment = iter->second; - for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); - attachment_iter != attachment->mAttachedObjects.end(); - ++attachment_iter) - { - const LLViewerObject* attached_object = (*attachment_iter); - if (attached_object && !attached_object->isHUDAttachment()) + if (attachment->getValid()) { - LLDrawable* drawable = attached_object->mDrawable; - if (drawable && !drawable->isState(LLDrawable::RIGGED)) + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) { - LLSpatialBridge* bridge = drawable->getSpatialBridge(); - if (bridge) + // Don't we need to look at children of attached_object as well? + const LLViewerObject* attached_object = (*attachment_iter); +#else + for(auto& iter : mAttachedObjectsVector) + {{{ + LLViewerJointAttachment* attachment = iter.second; + if (!attachment->getValid()) + continue; + const LLViewerObject* attached_object = iter.first; +#endif + if (attached_object && !attached_object->isHUDAttachment()) { - const LLVector4a* ext = bridge->getSpatialExtents(); - LLVector4a distance; - distance.setSub(ext[1], ext[0]); - LLVector4a max_span(max_attachment_span); - - S32 lt = distance.lessThan(max_span).getGatheredBits() & 0x7; - - // Only add the prim to spatial extents calculations if it isn't a megaprim. - // max_attachment_span calculated at the start of the function - // (currently 5 times our max prim size) - if (lt == 0x7) + const LLVOVolume *vol = dynamic_cast(attached_object); + if (vol && vol->isAnimatedObject()) + { + // Animated objects already have a bounding box in their control av, use that. + // Could lag by a frame if there's no guarantee on order of processing for avatars. + LLControlAvatar *cav = vol->getControlAvatar(); + if (cav) + { + LLVector4a cav_min; + cav_min.load3(cav->mLastAnimExtents[0].mV); + LLVector4a cav_max; + cav_max.load3(cav->mLastAnimExtents[1].mV); + update_min_max(newMin,newMax,cav_min); + update_min_max(newMin,newMax,cav_max); + continue; + } + } + if (vol && vol->isRiggedMesh()) { - update_min_max(newMin,newMax,ext[0]); - update_min_max(newMin,newMax,ext[1]); + continue; } - else if(control_derender_huge_attachments) + LLDrawable* drawable = attached_object->mDrawable; + if (drawable && !drawable->isState(LLDrawable::RIGGED)) { - removal.push_back((LLViewerObject *)attached_object); + LLSpatialBridge* bridge = drawable->getSpatialBridge(); + if (bridge) + { + const LLVector4a* ext = bridge->getSpatialExtents(); + LLVector4a distance; + distance.setSub(ext[1], ext[0]); + LLVector4a max_span(max_attachment_span); + + S32 lt = distance.lessThan(max_span).getGatheredBits() & 0x7; + + // Only add the prim to spatial extents calculations if it isn't a megaprim. + // max_attachment_span calculated at the start of the function + // (currently 5 times our max prim size) + if (lt == 0x7) + { + update_min_max(newMin,newMax,ext[0]); + update_min_max(newMin,newMax,ext[1]); + } + else if(control_derender_huge_attachments) + { + removal.push_back((LLViewerObject *)attached_object); + } + } } } } @@ -1710,10 +1912,87 @@ void LLVOAvatar::getSpatialExtents(LLVector4a& newMin, LLVector4a& newMax) removal.clear(); } - //pad bounding box - - newMin.sub(buffer); - newMax.add(buffer); + // Stretch bounding box by rigged mesh joint boxes + if (box_detail>=3 && gMeshRepo.meshRezEnabled()) + { + updateRiggingInfo(); + for (S32 joint_num = 0; joint_num < LL_CHARACTER_MAX_ANIMATED_JOINTS; joint_num++) + { + LLJoint *joint = getJoint(joint_num); + LLJointRiggingInfo *rig_info = NULL; + if (joint_num < mJointRiggingInfoTab.size()) + { + rig_info = &mJointRiggingInfoTab[joint_num]; + } + + if (joint && rig_info && rig_info->isRiggedTo()) + { + LLViewerJointAttachment *as_joint_attach = dynamic_cast(joint); + if (as_joint_attach && as_joint_attach->getIsHUDAttachment()) + { + // Ignore bounding box of HUD joints + continue; + } + const LLMatrix4a& mat = joint->getWorldMatrix(); + LLVector4a new_extents[2]; + matMulBoundBox(mat, rig_info->getRiggedExtents(), new_extents); + update_min_max(newMin, newMax, new_extents[0]); + update_min_max(newMin, newMax, new_extents[1]); + //if (isSelf()) + //{ + // LL_INFOS() << joint->getName() << " extents " << new_extents[0] << "," << new_extents[1] << LL_ENDL; + // LL_INFOS() << joint->getName() << " av box is " << newMin << "," << newMax << LL_ENDL; + //} + } + } + } + + // Update pixel area + LLVector4a center, size; + center.setAdd(newMin, newMax); + center.mul(0.5f); + + size.setSub(newMax,newMin); + size.mul(0.5f); + + mPixelArea = LLPipeline::calcPixelArea(center, size, *LLViewerCamera::getInstance()); +} + +void render_sphere_and_line(const LLVector3& begin_pos, const LLVector3& end_pos, F32 sphere_scale, const LLVector3& occ_color, const LLVector3& visible_color) +{ + // Unoccluded bone portions + LLGLDepthTest normal_depth(GL_TRUE); + + // Draw line segment for unoccluded joint + gGL.diffuseColor3f(visible_color[0], visible_color[1], visible_color[2]); + + gGL.begin(LLRender::LINES); + gGL.vertex3fv(begin_pos.mV); + gGL.vertex3fv(end_pos.mV); + gGL.end(); + + + // Draw sphere representing joint pos + gGL.pushMatrix(); + gGL.scalef(sphere_scale, sphere_scale, sphere_scale); + gSphere.renderGGL(); + gGL.popMatrix(); + + LLGLDepthTest depth_under(GL_TRUE, GL_FALSE, GL_GREATER); + + // Occluded bone portions + gGL.diffuseColor3f(occ_color[0], occ_color[1], occ_color[2]); + + gGL.begin(LLRender::LINES); + gGL.vertex3fv(begin_pos.mV); + gGL.vertex3fv(end_pos.mV); + gGL.end(); + + // Draw sphere representing joint pos + gGL.pushMatrix(); + gGL.scalef(sphere_scale, sphere_scale, sphere_scale); + gSphere.renderGGL(); + gGL.popMatrix(); } //----------------------------------------------------------------------------- @@ -1721,69 +2000,272 @@ void LLVOAvatar::getSpatialExtents(LLVector4a& newMin, LLVector4a& newMax) //----------------------------------------------------------------------------- void LLVOAvatar::renderCollisionVolumes() { + std::ostringstream ostr; LLGLDepthTest gls_depth(GL_FALSE); - for (S32 i = 0; i < mNumCollisionVolumes; i++) + for (size_t i = 0; i < mCollisionVolumes.size(); i++) { - mCollisionVolumes[i].renderCollision(); + ostr << mCollisionVolumes[i]->getName() << ", "; + LLAvatarJointCollisionVolume& collision_volume = *mCollisionVolumes[i]; + + collision_volume.updateWorldMatrix(); + + gGL.pushMatrix(); + gGL.multMatrix( collision_volume.getXform()->getWorldMatrix() ); + + LLVector3 begin_pos(0,0,0); + LLVector3 end_pos(collision_volume.getEnd()); + static F32 sphere_scale = 1.0f; + static F32 center_dot_scale = 0.05f; + + static LLVector3 BLUE(0.0f, 0.0f, 1.0f); + static LLVector3 PASTEL_BLUE(0.5f, 0.5f, 1.0f); + static LLVector3 RED(1.0f, 0.0f, 0.0f); + static LLVector3 PASTEL_RED(1.0f, 0.5f, 0.5f); + static LLVector3 WHITE(1.0f, 1.0f, 1.0f); + + + LLVector3 cv_color_occluded; + LLVector3 cv_color_visible; + LLVector3 dot_color_occluded(WHITE); + LLVector3 dot_color_visible(WHITE); + if (isControlAvatar()) + { + cv_color_occluded = RED; + cv_color_visible = PASTEL_RED; + } + else + { + cv_color_occluded = BLUE; + cv_color_visible = PASTEL_BLUE; + } + render_sphere_and_line(begin_pos, end_pos, sphere_scale, cv_color_occluded, cv_color_visible); + render_sphere_and_line(begin_pos, end_pos, center_dot_scale, dot_color_occluded, dot_color_visible); + + gGL.popMatrix(); } if (mNameText.notNull()) { - LLVector3 unused; - mNameText->lineSegmentIntersect(LLVector3(0,0,0), LLVector3(0,0,1), unused, TRUE); + LLVector4a unused; + + mNameText->lineSegmentIntersect(unused, unused, unused, TRUE); + } + + mDebugText.clear(); + addDebugText(ostr.str()); +} + +void LLVOAvatar::renderBones() +{ + LLGLEnable blend; + + avatar_joint_list_t::iterator iter = mSkeleton.begin(); + avatar_joint_list_t::iterator end = mSkeleton.end(); + + // For bones with position overrides defined + static LLVector3 OVERRIDE_COLOR_OCCLUDED(1.0f, 0.0f, 0.0f); + static LLVector3 OVERRIDE_COLOR_VISIBLE(0.5f, 0.5f, 0.5f); + // For bones which are rigged to by at least one attachment + static LLVector3 RIGGED_COLOR_OCCLUDED(0.0f, 1.0f, 1.0f); + static LLVector3 RIGGED_COLOR_VISIBLE(0.5f, 0.5f, 0.5f); + // For bones not otherwise colored + static LLVector3 OTHER_COLOR_OCCLUDED(0.0f, 1.0f, 0.0f); + static LLVector3 OTHER_COLOR_VISIBLE(0.5f, 0.5f, 0.5f); + + static F32 SPHERE_SCALEF = 0.001f; + + for (; iter != end; ++iter) + { + LLJoint* jointp = *iter; + if (!jointp) + { + continue; + } + + jointp->updateWorldMatrix(); + + LLVector3 occ_color, visible_color; + + LLVector3 pos; + LLUUID mesh_id; + if (jointp->hasAttachmentPosOverride(pos,mesh_id)) + { + occ_color = OVERRIDE_COLOR_OCCLUDED; + visible_color = OVERRIDE_COLOR_VISIBLE; + } + else + { + if (jointIsRiggedTo(jointp)) + { + occ_color = RIGGED_COLOR_OCCLUDED; + visible_color = RIGGED_COLOR_VISIBLE; + } + else + { + occ_color = OTHER_COLOR_OCCLUDED; + visible_color = OTHER_COLOR_VISIBLE; + } + } + LLVector3 begin_pos(0,0,0); + LLVector3 end_pos(jointp->getEnd()); + + F32 sphere_scale = SPHERE_SCALEF; + + gGL.pushMatrix(); + gGL.multMatrix( jointp->getXform()->getWorldMatrix() ); + + render_sphere_and_line(begin_pos, end_pos, sphere_scale, occ_color, visible_color); + + gGL.popMatrix(); + } +} + +void LLVOAvatar::renderJoints() +{ + std::ostringstream ostr; + std::ostringstream nullstr; + + for (joint_map_t::iterator iter = mJointMap.begin(); iter != mJointMap.end(); ++iter) + { + LLJoint* jointp = iter->second; + if (!jointp) + { + nullstr << iter->first << " is NULL" << std::endl; + continue; + } + + ostr << jointp->getName() << ", "; + + jointp->updateWorldMatrix(); + + gGL.pushMatrix(); + gGL.multMatrix(jointp->getXform()->getWorldMatrix()); + + gGL.diffuseColor3f( 1.f, 0.f, 1.f ); + + gGL.begin(LLRender::LINES); + + LLVector3 v[] = + { + LLVector3(1,0,0), + LLVector3(-1,0,0), + LLVector3(0,1,0), + LLVector3(0,-1,0), + + LLVector3(0,0,-1), + LLVector3(0,0,1), + }; + + //sides + gGL.vertex3fv(v[0].mV); + gGL.vertex3fv(v[2].mV); + + gGL.vertex3fv(v[0].mV); + gGL.vertex3fv(v[3].mV); + + gGL.vertex3fv(v[1].mV); + gGL.vertex3fv(v[2].mV); + + gGL.vertex3fv(v[1].mV); + gGL.vertex3fv(v[3].mV); + + + //top + gGL.vertex3fv(v[0].mV); + gGL.vertex3fv(v[4].mV); + + gGL.vertex3fv(v[1].mV); + gGL.vertex3fv(v[4].mV); + + gGL.vertex3fv(v[2].mV); + gGL.vertex3fv(v[4].mV); + + gGL.vertex3fv(v[3].mV); + gGL.vertex3fv(v[4].mV); + + + //bottom + gGL.vertex3fv(v[0].mV); + gGL.vertex3fv(v[5].mV); + + gGL.vertex3fv(v[1].mV); + gGL.vertex3fv(v[5].mV); + + gGL.vertex3fv(v[2].mV); + gGL.vertex3fv(v[5].mV); + + gGL.vertex3fv(v[3].mV); + gGL.vertex3fv(v[5].mV); + + gGL.end(); + + gGL.popMatrix(); } + + mDebugText.clear(); + addDebugText(ostr.str()); + addDebugText(nullstr.str()); } -BOOL LLVOAvatar::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, + +BOOL LLVOAvatar::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, S32 face, BOOL pick_transparent, + BOOL pick_rigged, S32* face_hit, - LLVector3* intersection, + LLVector4a* intersection, LLVector2* tex_coord, - LLVector3* normal, - LLVector3* bi_normal) + LLVector4a* normal, + LLVector4a* tangent) { if ((isSelf() && !gAgent.needsRenderAvatar()) || !LLPipeline::sPickAvatar) { return FALSE; } + + if (isControlAvatar()) + { + return FALSE; + } + if (lineSegmentBoundingBox(start, end)) { - for (S32 i = 0; i < mNumCollisionVolumes; ++i) + for (S32 i = 0; i < (S32)mCollisionVolumes.size(); ++i) { - mCollisionVolumes[i].updateWorldMatrix(); + mCollisionVolumes[i]->updateWorldMatrix(); - glh::matrix4f mat((F32*) mCollisionVolumes[i].getXform()->getWorldMatrix().mMatrix); - glh::matrix4f inverse = mat.inverse(); - glh::matrix4f norm_mat = inverse.transpose(); + const LLMatrix4a& mat = mCollisionVolumes[i]->getXform()->getWorldMatrix(); + LLMatrix4a inverse = mat; + inverse.invert(); + LLMatrix4a norm_mat = inverse; + norm_mat.transpose(); - glh::vec3f p1(start.mV); - glh::vec3f p2(end.mV); - inverse.mult_matrix_vec(p1); - inverse.mult_matrix_vec(p2); + LLVector4a p1, p2; + inverse.affineTransform(start,p1); //Might need to use perspectiveTransform here. + inverse.affineTransform(end,p2); LLVector3 position; LLVector3 norm; - if (linesegment_sphere(LLVector3(p1.v), LLVector3(p2.v), LLVector3(0,0,0), 1.f, position, norm)) + if (linesegment_sphere(LLVector3(p1.getF32ptr()), LLVector3(p2.getF32ptr()), LLVector3(0,0,0), 1.f, position, norm)) { - glh::vec3f res_pos(position.mV); - mat.mult_matrix_vec(res_pos); - - norm.normalize(); - glh::vec3f res_norm(norm.mV); - norm_mat.mult_matrix_dir(res_norm); - if (intersection) { - *intersection = LLVector3(res_pos.v); + LLVector4a res_pos; + res_pos.load3(position.mV); + mat.affineTransform(res_pos,res_pos); + *intersection = res_pos; } if (normal) { - *normal = LLVector3(res_norm.v); + LLVector4a res_norm; + res_norm.load3(norm.mV); + res_norm.normalize3fast(); + norm_mat.perspectiveTransform(res_norm,res_norm); + *normal = res_norm; } return TRUE; @@ -1792,6 +2274,7 @@ BOOL LLVOAvatar::lineSegmentIntersect(const LLVector3& start, const LLVector3& e if (isSelf()) { +#if SLOW_ATTACHMENT_LIST for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); iter != mAttachmentPoints.end(); ++iter) @@ -1803,6 +2286,12 @@ BOOL LLVOAvatar::lineSegmentIntersect(const LLVector3& start, const LLVector3& e ++attachment_iter) { LLViewerObject* attached_object = (*attachment_iter); +#else + for(auto& iter : mAttachedObjectsVector) + {{ + const LLViewerJointAttachment* attachment = iter.second; + const LLViewerObject* attached_object = iter.first; +#endif if (attached_object && !attached_object->isDead() && attachment->getValid()) { @@ -1817,7 +2306,9 @@ BOOL LLVOAvatar::lineSegmentIntersect(const LLVector3& start, const LLVector3& e } } - LLVector3 position; + + + LLVector4a position; if (mNameText.notNull() && mNameText->lineSegmentIntersect(start, end, position)) { if (intersection) @@ -1831,18 +2322,17 @@ BOOL LLVOAvatar::lineSegmentIntersect(const LLVector3& start, const LLVector3& e return FALSE; } -LLViewerObject* LLVOAvatar::lineSegmentIntersectRiggedAttachments(const LLVector3& start, const LLVector3& end, +LLViewerObject* LLVOAvatar::lineSegmentIntersectRiggedAttachments(const LLVector4a& start, const LLVector4a& end, S32 face, BOOL pick_transparent, + BOOL pick_rigged, S32* face_hit, - LLVector3* intersection, + LLVector4a* intersection, LLVector2* tex_coord, - LLVector3* normal, - LLVector3* bi_normal) + LLVector4a* normal, + LLVector4a* tangent) { - static const LLCachedControl allow_mesh_picking("SGAllowRiggedMeshSelection"); - - if (!allow_mesh_picking || (isSelf() && !gAgent.needsRenderAvatar())) + if (isSelf() && !gAgent.needsRenderAvatar()) { return NULL; } @@ -1851,9 +2341,10 @@ LLViewerObject* LLVOAvatar::lineSegmentIntersectRiggedAttachments(const LLVector if (lineSegmentBoundingBox(start, end)) { - LLVector3 local_end = end; - LLVector3 local_intersection; - + LLVector4a local_end = end; + LLVector4a local_intersection; + +#if SLOW_ATTACHMENT_LIST for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); iter != mAttachmentPoints.end(); ++iter) @@ -1865,8 +2356,13 @@ LLViewerObject* LLVOAvatar::lineSegmentIntersectRiggedAttachments(const LLVector ++attachment_iter) { LLViewerObject* attached_object = (*attachment_iter); - - if (attached_object->lineSegmentIntersect(start, local_end, face, pick_transparent, face_hit, &local_intersection, tex_coord, normal, bi_normal)) +#else + for(auto& iter : mAttachedObjectsVector) + {{ + LLViewerObject* attached_object = iter.first; +#endif + + if (attached_object->lineSegmentIntersect(start, local_end, face, pick_transparent, pick_rigged, face_hit, &local_intersection, tex_coord, normal, tangent)) { local_end = local_intersection; if (intersection) @@ -1936,18 +2432,22 @@ void LLVOAvatar::buildCharacter() // If we don't have the Ooh morph, use the Kiss morph if (!mOohMorph) { - llwarns << "Missing 'Ooh' morph for lipsync, using fallback." << llendl; + LL_WARNS() << "Missing 'Ooh' morph for lipsync, using fallback." << LL_ENDL; mOohMorph = getVisualParam( "Express_Kiss" ); } // If we don't have the Aah morph, use the Open Mouth morph if (!mAahMorph) { - llwarns << "Missing 'Aah' morph for lipsync, using fallback." << llendl; + LL_WARNS() << "Missing 'Aah' morph for lipsync, using fallback." << LL_ENDL; mAahMorph = getVisualParam( "Express_Open_Mouth" ); } - startDefaultMotions(); + // Currently disabled for control avatars (animated objects), enabled for all others. + if (mEnableDefaultMotions) + { + startDefaultMotions(); + } //------------------------------------------------------------------------- // restart any currently active motions @@ -1960,19 +2460,147 @@ void LLVOAvatar::buildCharacter() mMeshValid = TRUE; } +//----------------------------------------------------------------------------- +// resetVisualParams() +//----------------------------------------------------------------------------- +void LLVOAvatar::resetVisualParams() +{ + // Skeletal params + { + LLAvatarXmlInfo::skeletal_distortion_info_list_t::iterator iter; + for (iter = sAvatarXmlInfo->mSkeletalDistortionInfoList.begin(); + iter != sAvatarXmlInfo->mSkeletalDistortionInfoList.end(); + ++iter) + { + LLPolySkeletalDistortionInfo *info = (LLPolySkeletalDistortionInfo*)*iter; + LLPolySkeletalDistortion *param = dynamic_cast(getVisualParam(info->getID())); + *param = LLPolySkeletalDistortion(this); + llassert(param); + if (!param->setInfo(info)) + { + llassert(false); + } + } + } + + // Driver parameters + for (LLAvatarXmlInfo::driver_info_list_t::iterator iter = sAvatarXmlInfo->mDriverInfoList.begin(); + iter != sAvatarXmlInfo->mDriverInfoList.end(); + ++iter) + { + LLDriverParamInfo *info = *iter; + LLDriverParam *param = dynamic_cast(getVisualParam(info->getID())); + LLDriverParam::entry_list_t driven_list = param->getDrivenList(); + *param = LLDriverParam(this); + llassert(param); + if (!param->setInfo(info)) + { + llassert(false); + } + param->setDrivenList(driven_list); + } +} + +//----------------------------------------------------------------------------- +// resetSkeleton() +//----------------------------------------------------------------------------- +void LLVOAvatar::resetSkeleton(bool reset_animations) +{ + LL_DEBUGS("Avatar") << avString() << " reset starts" << LL_ENDL; + if (!isControlAvatar() && !mLastProcessedAppearance) + { + LL_WARNS() << "Can't reset avatar; no appearance message has been received yet." << LL_ENDL; + return; + } + + // Save mPelvis state + //LLVector3 pelvis_pos = getJoint("mPelvis")->getPosition(); + //LLQuaternion pelvis_rot = getJoint("mPelvis")->getRotation(); + + // Clear all attachment pos and scale overrides + clearAttachmentOverrides(); + + // Note that we call buildSkeleton twice in this function. The first time is + // just to get the right scale for the collision volumes, because + // this will be used in setting the mJointScales for the + // LLPolySkeletalDistortions of which the CVs are children. + if( !buildSkeleton(sAvatarSkeletonInfo) ) + { + LL_ERRS() << "Error resetting skeleton" << LL_ENDL; + } + + // Reset some params to default state, without propagating changes downstream. + resetVisualParams(); + + // Now we have to reset the skeleton again, because its state + // got clobbered by the resetVisualParams() calls + // above. + if( !buildSkeleton(sAvatarSkeletonInfo) ) + { + LL_ERRS() << "Error resetting skeleton" << LL_ENDL; + } + + // Reset attachment points (buildSkeleton only does bones and CVs) + bool ignore_hud_joints = true; + initAttachmentPoints(ignore_hud_joints); + + // Fix up collision volumes + for (LLVisualParam *param = getFirstVisualParam(); + param; + param = getNextVisualParam()) + { + LLPolyMorphTarget *poly_morph = dynamic_cast(param); + if (poly_morph) + { + // This is a kludgy way to correct for the fact that the + // collision volumes have been reset out from under the + // poly morph sliders. + F32 delta_weight = poly_morph->getLastWeight() - poly_morph->getDefaultWeight(); + poly_morph->applyVolumeChanges(delta_weight); + } + } + + // Reset tweakable params to preserved state + if (mLastProcessedAppearance) + { + bool slam_params = true; + applyParsedAppearanceMessage(*mLastProcessedAppearance, slam_params); + } + updateVisualParams(); + + // Restore attachment pos overrides + updateAttachmentOverrides(); + + // Animations + if (reset_animations) + { + if (isSelf()) + { + // This is equivalent to "Stop Animating Me". Will reset + // all animations and propagate the changes to other + // viewers. + gAgent.stopCurrentAnimations(); + } + else + { + // Local viewer-side reset for non-self avatars. + resetAnimations(); + } + } + + LL_DEBUGS("Avatar") << avString() << " reset ends" << LL_ENDL; +} //----------------------------------------------------------------------------- // releaseMeshData() //----------------------------------------------------------------------------- void LLVOAvatar::releaseMeshData() { - if (sInstances.size() < AVATAR_RELEASE_THRESHOLD || mIsDummy) + if (sInstances.size() < AVATAR_RELEASE_THRESHOLD || isUIAvatar()) { return; } - //llinfos << "Releasing" << llendl; - // cleanup mesh data for (avatar_joint_list_t::iterator iter = mMeshLOD.begin(); iter != mMeshLOD.end(); @@ -2020,8 +2648,12 @@ void LLVOAvatar::releaseMeshData() void LLVOAvatar::restoreMeshData() { llassert(!isSelf()); + if (mDrawable.isNull()) + { + return; + } - //llinfos << "Restoring" << llendl; + //LL_INFOS() << "Restoring" << LL_ENDL; mMeshValid = TRUE; updateJointLODs(); @@ -2132,7 +2764,7 @@ void LLVOAvatar::updateMeshData() // the case of more than one avatar in the pool (thus > 0 instead of >= 0) if (facep->getGeomIndex() > 0) { - llerrs << "non-zero geom index: " << facep->getGeomIndex() << " in LLVOAvatar::restoreMeshData" << llendl; + LL_ERRS() << "non-zero geom index: " << facep->getGeomIndex() << " in LLVOAvatar::restoreMeshData" << LL_ENDL; } for(S32 k = j ; k < part_index ; k++) @@ -2210,24 +2842,29 @@ LLViewerFetchedTexture *LLVOAvatar::getBakedTextureImage(const U8 te, const LLUU uuid == IMG_INVISIBLE) { // Should already exist, don't need to find it on sim or baked-texture host. - result = gTextureList.findImage(uuid); + result = gTextureList.findImage(uuid, TEX_LIST_STANDARD); } if (!result) { const std::string url = getImageURL(te,uuid); + if (!url.empty()) { - LL_DEBUGS("Avatar") << avString() << "from URL " << url << llendl; + LL_DEBUGS("Avatar") << avString() << "get server-bake image from URL " << url << LL_ENDL; result = LLViewerTextureManager::getFetchedTextureFromUrl( - url, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, uuid); + url, FTT_SERVER_BAKE, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, uuid); + if (result->isMissingAsset()) + { + result->setIsMissingAsset(false); + } } else { - LL_DEBUGS("Avatar") << avString() << "from host " << uuid << llendl; + LL_DEBUGS("Avatar") << avString() << "from host " << uuid << LL_ENDL; LLHost host = getObjectHost(); result = LLViewerTextureManager::getFetchedTexture( - uuid, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, host); + uuid, FTT_SERVER_BAKE, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, host); } } return result; @@ -2249,13 +2886,17 @@ S32 LLVOAvatar::setTETexture(const U8 te, const LLUUID& uuid) static LLFastTimer::DeclareTimer FTM_AVATAR_UPDATE("Avatar Update"); static LLFastTimer::DeclareTimer FTM_JOINT_UPDATE("Update Joints"); +static LLFastTimer::DeclareTimer FTM_CHARACTER_UPDATE("Character Update"); +static LLFastTimer::DeclareTimer FTM_BASE_UPDATE("Base Update"); +static LLFastTimer::DeclareTimer FTM_MISC_UPDATE("Misc Update"); +static LLFastTimer::DeclareTimer FTM_DETAIL_UPDATE("Detail Update"); //------------------------------------------------------------------------ // LLVOAvatar::dumpAnimationState() //------------------------------------------------------------------------ void LLVOAvatar::dumpAnimationState() { - llinfos << "==============================================" << llendl; + LL_INFOS() << "==============================================" << LL_ENDL; for (LLVOAvatar::AnimIterator it = mSignaledAnimations.begin(); it != mSignaledAnimations.end(); ++it) { LLUUID id = it->first; @@ -2264,7 +2905,7 @@ void LLVOAvatar::dumpAnimationState() { playtag = "*"; } - llinfos << gAnimLibrary.animationName(id) << playtag << llendl; + LL_INFOS() << gAnimLibrary.animationName(id) << playtag << LL_ENDL; } for (LLVOAvatar::AnimIterator it = mPlayingAnimations.begin(); it != mPlayingAnimations.end(); ++it) { @@ -2272,7 +2913,7 @@ void LLVOAvatar::dumpAnimationState() bool is_signaled = mSignaledAnimations.find(id) != mSignaledAnimations.end(); if (!is_signaled) { - llinfos << gAnimLibrary.animationName(id) << "!S" << llendl; + LL_INFOS() << gAnimLibrary.animationName(id) << "!S" << LL_ENDL; } } } @@ -2282,11 +2923,11 @@ void LLVOAvatar::dumpAnimationState() //------------------------------------------------------------------------ void LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) { - LLFastTimer t(FTM_AVATAR_UPDATE); + LL_RECORD_BLOCK_TIME(FTM_AVATAR_UPDATE); if (isDead()) { - llinfos << "Warning! Idle on dead avatar" << llendl; + LL_INFOS() << "Warning! Idle on dead avatar" << LL_ENDL; return; } @@ -2295,6 +2936,18 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) return; } + // Update should be happening max once per frame. + const S32 upd_freq = 4; // force update every upd_freq frames. + if ((mLastAnimExtents[0]==LLVector3())|| + (mLastAnimExtents[1])==LLVector3()) + { + mNeedsExtentUpdate = true; + } + else + { + mNeedsExtentUpdate = ((LLDrawable::getCurrentFrame()+mID.mData[0])%upd_freq==0); + } + checkTextureLoading() ; // force immediate pixel area update on avatars using last frames data (before drawable or camera updates) @@ -2303,9 +2956,9 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) // force asynchronous drawable update if(mDrawable.notNull() && !gNoRender) { - LLFastTimer t(FTM_JOINT_UPDATE); + LL_RECORD_BLOCK_TIME(FTM_JOINT_UPDATE); - if (mIsSitting && getParent()) + if (isSitting() && getParent()) { LLViewerObject *root_object = (LLViewerObject*)getRoot(); LLDrawable* drawablep = root_object->mDrawable; @@ -2334,7 +2987,10 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) if (isSelf()) { - LLViewerObject::idleUpdate(agent, world, time); + { + LL_RECORD_BLOCK_TIME(FTM_BASE_UPDATE); + LLViewerObject::idleUpdate(agent, world, time); + } // trigger fidget anims if (isAnyAnimationSignaled(AGENT_STAND_ANIMS, NUM_AGENT_STAND_ANIMS)) @@ -2346,7 +3002,10 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) { // Should override the idleUpdate stuff and leave out the angular update part. LLQuaternion rotation = getRotation(); - LLViewerObject::idleUpdate(agent, world, time); + { + LL_RECORD_BLOCK_TIME(FTM_BASE_UPDATE); + LLViewerObject::idleUpdate(agent, world, time); + } setRotation(rotation); } @@ -2355,9 +3014,12 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) // animate the character // store off last frame's root position to be consistent with camera position - LLVector3 root_pos_last = mRoot->getWorldPosition(); - bool detailed_update = updateCharacter(agent); - + mLastRootPos = mRoot->getWorldPosition(); + bool detailed_update; + { + LL_RECORD_BLOCK_TIME(FTM_CHARACTER_UPDATE); + detailed_update = updateCharacter(agent); + } if (gNoRender) { return; @@ -2367,19 +3029,21 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) bool voice_enabled = (visualizers_in_calls || LLVoiceClient::getInstance()->inProximalChannel()) && LLVoiceClient::getInstance()->getVoiceEnabled(mID); - idleUpdateVoiceVisualizer( voice_enabled ); - idleUpdateMisc( detailed_update ); + LL_RECORD_BLOCK_TIME(FTM_MISC_UPDATE); + idleUpdateVoiceVisualizer(voice_enabled); + idleUpdateMisc(detailed_update); idleUpdateAppearanceAnimation(); if (detailed_update) { - idleUpdateLipSync( voice_enabled ); + LL_RECORD_BLOCK_TIME(FTM_DETAIL_UPDATE); + idleUpdateLipSync(voice_enabled); idleUpdateLoadingEffect(); idleUpdateBelowWater(); // wind effect uses this idleUpdateWindEffect(); } - idleUpdateNameTag( root_pos_last ); - idleUpdateRenderCost(); + idleUpdateNameTag(mLastRootPos); + idleUpdateRenderComplexity(); } void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled) @@ -2394,6 +3058,11 @@ void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled) render_visualizer = false; } } + else if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS) || (gRlvHandler.hasBehaviour(RLV_BHVR_CAMAVDIST) && (gAgent.getPosGlobalFromAgent(getCharacterPosition()) - gAgent.getPosGlobalFromAgent(gAgentAvatarp->getRenderPosition())).magVec() > gRlvHandler.camPole(RLV_BHVR_CAMAVDIST))) // RLVa:LF - You get nothing now! + { + render_visualizer = false; + } + mVoiceVisualizer->setVoiceEnabled(render_visualizer); @@ -2421,7 +3090,7 @@ void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled) if ( mCurrentGesticulationLevel == 0 ) { gestureString = "/voicelevel1"; } else if ( mCurrentGesticulationLevel == 1 ) { gestureString = "/voicelevel2"; } else if ( mCurrentGesticulationLevel == 2 ) { gestureString = "/voicelevel3"; } - else { llinfos << "oops - CurrentGesticulationLevel can be only 0, 1, or 2" << llendl; } + else { LL_INFOS() << "oops - CurrentGesticulationLevel can be only 0, 1, or 2" << LL_ENDL; } // this is the call that Karl S. created for triggering gestures from within the code. LLGestureMgr::instance().triggerAndReviseString( gestureString ); @@ -2477,7 +3146,7 @@ void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled) // (the following version uses a tweak of "mHeadOffset" which handle sitting vs. standing) //-------------------------------------------------------------------------------------------- - if ( mIsSitting ) + if ( isSitting() ) { LLVector3 headOffset = LLVector3( 0.0f, 0.0f, mHeadOffset.mV[2] ); mVoiceVisualizer->setVoiceSourceWorldPosition( mRoot->getWorldPosition() + headOffset ); @@ -2498,7 +3167,7 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update) { if (LLVOAvatar::sJointDebug) { - llinfos << getFullname() << ": joint touches: " << LLJoint::sNumTouches << " updates: " << LLJoint::sNumUpdates << llendl; + LL_INFOS() << getFullname() << ": joint touches: " << LLJoint::sNumTouches << " updates: " << LLJoint::sNumUpdates << LL_ENDL; } LLJoint::sNumUpdates = 0; @@ -2509,8 +3178,9 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update) // update attachments positions if (detailed_update || !sUseImpostors) { - LLFastTimer t(FTM_ATTACHMENT_UPDATE); - /*for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); + LL_RECORD_BLOCK_TIME(FTM_ATTACHMENT_UPDATE); +#if SLOW_ATTACHMENT_LIST + for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); iter != mAttachmentPoints.end(); ++iter) { @@ -2520,16 +3190,18 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update) attachment_iter != attachment->mAttachedObjects.end(); ++attachment_iter) { - LLViewerObject* attached_object = (*attachment_iter);*/ - std::vector >::iterator attachment_iter = mAttachedObjectsVector.begin(); - for(;attachment_iter!=mAttachedObjectsVector.end();++attachment_iter) + LLViewerObject* attached_object = (*attachment_iter); +#else + for(auto& iter : mAttachedObjectsVector) {{ - LLViewerJointAttachment* attachment = attachment_iter->second; - LLViewerObject* attached_object = attachment_iter->first; - BOOL visibleAttachment = visible || (attached_object && attached_object->mDrawable.notNull() && - !(attached_object->mDrawable->getSpatialBridge() && - attached_object->mDrawable->getSpatialBridge()->getRadius() < 2.0)); + LLViewerJointAttachment* attachment = iter.second; + LLViewerObject* attached_object = iter.first; +#endif + BOOL visibleAttachment = visible || (attached_object && + !(attached_object->mDrawable->getSpatialBridge() && + attached_object->mDrawable->getSpatialBridge()->getRadius() < 2.0)); + if (visibleAttachment && attached_object && !attached_object->isDead() && attachment->getValid()) { // if selecting any attachments, update all of them as non-damped @@ -2586,8 +3258,10 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update) } else { - //VECTORIZE THIS - getSpatialExtents(ext[0], ext[1]); + ext[0].load3(mLastAnimExtents[0].mV); + ext[1].load3(mLastAnimExtents[1].mV); + // Expensive. Just call this once per frame, in updateSpatialExtents(); + //calculateSpatialExtents(ext[0], ext[1]); LLVector4a diff; diff.setSub(ext[1], mImpostorExtents[1]); if (diff.getLength3().getF32() > 0.05f) @@ -2605,7 +3279,8 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update) } } } - if(mDrawable) + + if (mDrawable.notNull()) { mDrawable->movePartition(); @@ -2733,19 +3408,22 @@ void LLVOAvatar::idleUpdateLoadingEffect() // update visibility when avatar is partially loaded if (updateIsFullyLoaded()) // changed? { - if (isFullyLoaded() && mFirstFullyVisible && isSelf()) - { - LL_INFOS("Avatar") << avString() << "self isFullyLoaded, mFirstFullyVisible" << LL_ENDL; - mFirstFullyVisible = FALSE; - LLAppearanceMgr::instance().onFirstFullyVisible(); - } - if (isFullyLoaded() && mFirstFullyVisible && !isSelf()) - { - LL_INFOS("Avatar") << avString() << "other isFullyLoaded, mFirstFullyVisible" << LL_ENDL; - mFirstFullyVisible = FALSE; - } if (isFullyLoaded()) { + if (mFirstFullyVisible) + { + mFirstFullyVisible = FALSE; + if (isSelf()) + { + LL_INFOS("Avatar") << avString() << "self isFullyLoaded, mFirstFullyVisible" << LL_ENDL; + LLAppearanceMgr::instance().onFirstFullyVisible(); + } + else + { + LL_INFOS("Avatar") << avString() << "other isFullyLoaded, mFirstFullyVisible" << LL_ENDL; + } + } + deleteParticleSource(); updateLOD(); } @@ -2778,7 +3456,7 @@ void LLVOAvatar::idleUpdateLoadingEffect() LLPartData::LL_PART_EMISSIVE_MASK | // LLPartData::LL_PART_FOLLOW_SRC_MASK | LLPartData::LL_PART_TARGET_POS_MASK ); - if (!isTooComplex()) // do not generate particles for overly-complex avatars + if (!mIsDummy && !isTooComplex()) { setParticleSource(particle_parameters, getID()); } @@ -2798,7 +3476,7 @@ void LLVOAvatar::idleUpdateWindEffect() LLVector3 velocity = getVelocity(); F32 speed = velocity.length(); //RN: velocity varies too much frame to frame for this to work - mRippleAccel.clearVec();//lerp(mRippleAccel, (velocity - mLastVel) * time_delta, LLCriticalDamp::getInterpolant(0.02f)); + mRippleAccel.clearVec();//lerp(mRippleAccel, (velocity - mLastVel) * time_delta, LLSmoothInterpolation::getInterpolant(0.02f)); mLastVel = velocity; LLVector4 wind; wind.setVec(getRegion()->mWind.getVelocityNoisy(getPositionAgent(), 4.f) - velocity); @@ -2821,15 +3499,15 @@ void LLVOAvatar::idleUpdateWindEffect() F32 interp; if (wind.mV[VW] > mWindVec.mV[VW]) { - interp = LLCriticalDamp::getInterpolant(0.2f); + interp = LLSmoothInterpolation::getInterpolant(0.2f); } else { - interp = LLCriticalDamp::getInterpolant(0.4f); + interp = LLSmoothInterpolation::getInterpolant(0.4f); } mWindVec = lerp(mWindVec, wind, interp); - F32 wind_freq = hover_strength + llclamp(8.f + (speed * 0.7f) + (noise1(mRipplePhase) * 4.f), 8.f, 25.f); + F32 wind_freq = hover_strength + llclamp(8.f + (speed * 0.7f) + (LLPerlinNoise::noise(mRipplePhase) * 4.f), 8.f, 25.f); mWindFreq = lerp(mWindFreq, wind_freq, interp); if (mBelowWater) @@ -2838,9 +3516,9 @@ void LLVOAvatar::idleUpdateWindEffect() } mRipplePhase += (time_delta * mWindFreq); - if (mRipplePhase > F_TWO_PI) + if (mRipplePhase > 256.f) { - mRipplePhase = fmodf(mRipplePhase, F_TWO_PI); + mRipplePhase = fmodf(mRipplePhase, 256.f); } } } @@ -2864,6 +3542,13 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) static const LLCachedControl render_name_hide_self("RenderNameHideSelf",false); static const LLCachedControl allow_nameplate_override ("CCSAllowNameplateOverride", true); // [RLVa:KB] - Checked: 2010-04-04 (RLVa-1.2.2a) | Added: RLVa-0.2.0b + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS)) + return; // No tags + if (gRlvHandler.hasBehaviour(RLV_BHVR_CAMAVDIST) && (gAgent.getPosGlobalFromAgent(getCharacterPosition()) - gAgent.getPosGlobalFromAgent(gAgentAvatarp->getRenderPosition())).magVec() > gRlvHandler.camPole(RLV_BHVR_CAMAVDIST)) + { + clearNameTag(); // Dynamically remove this avatar's tag + return; + } bool fRlvShowNames = gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES); // [/RLVa:KB] BOOL visible_avatar = isVisible() || mNeedsAnimUpdate; @@ -2975,7 +3660,7 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) } LLVector3 name_position = idleUpdateNameTagPosition(root_pos_last); - mNameText->setPositionAgent(name_position); + mNameText->setPositionAgent(name_position); idleCCSUpdateAttachmentText(render_name); idleUpdateNameTagText(new_name); idleUpdateNameTagAlpha(new_name, alpha); @@ -3060,15 +3745,23 @@ void LLVOAvatar::idleUpdateNameTagText(BOOL new_name) LLNameValue *title = getNVPair("Title"); LLNameValue* firstname = getNVPair("FirstName"); LLNameValue* lastname = getNVPair("LastName"); + static const LLCachedControl display_client_new_line("SLBDisplayClientTagOnNewLine"); // Avatars must have a first and last name if (!firstname || !lastname) return; // [RLVa:KB] - Checked: 2010-10-31 (RLVa-1.2.2a) | Added: RLVa-1.2.2a + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS)) + return; // No tags + if (gRlvHandler.hasBehaviour(RLV_BHVR_CAMAVDIST) && (gAgent.getPosGlobalFromAgent(getCharacterPosition()) - gAgent.getPosGlobalFromAgent(gAgentAvatarp->getRenderPosition())).magVec() > gRlvHandler.camPole(RLV_BHVR_CAMAVDIST)) + { + clearNameTag(); // Dynamically remove this avatar's tag + return; + } bool fRlvShowNames = gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMES); // [/RLVa:KB] bool is_away = mSignaledAnimations.find(ANIM_AGENT_AWAY) != mSignaledAnimations.end(); - bool is_busy = mSignaledAnimations.find(ANIM_AGENT_BUSY) != mSignaledAnimations.end(); + bool is_busy = mSignaledAnimations.find(ANIM_AGENT_DO_NOT_DISTURB) != mSignaledAnimations.end(); bool is_appearance = mSignaledAnimations.find(ANIM_AGENT_CUSTOMIZE) != mSignaledAnimations.end(); bool is_muted; if (isSelf()) @@ -3178,10 +3871,10 @@ void LLVOAvatar::idleUpdateNameTagText(BOOL new_name) // LLFontGL::getFontSansSerifSmall()); } - // On SecondLife we can take a shortcut through getPNSName, which will strip out Resident + // On SecondLife we can take a shortcut through getNSName, which will strip out Resident if (gHippoGridManager->getConnectedGrid()->isSecondLife()) { - if (!LLAvatarNameCache::getPNSName(getID(), firstnameText)) + if (!LLAvatarNameCache::getNSName(getID(), firstnameText)) { // ...call this function back when the name arrives and force a rebuild LLAvatarNameCache::get(getID(), boost::bind(&LLVOAvatar::clearNameTag, this)); @@ -3200,9 +3893,9 @@ void LLVOAvatar::idleUpdateNameTagText(BOOL new_name) static const LLCachedControl phoenix_name_system("PhoenixNameSystem", 0); - bool show_display_names = phoenix_name_system == 1 || phoenix_name_system == 2; + bool show_display_names = phoenix_name_system > 0 || phoenix_name_system < 4; bool show_usernames = phoenix_name_system != 2; - if (show_display_names && LLAvatarNameCache::useDisplayNames()) + if (show_display_names && LLAvatarName::useDisplayNames()) { LLAvatarName av_name; if (!LLAvatarNameCache::get(getID(), &av_name)) @@ -3220,22 +3913,21 @@ void LLVOAvatar::idleUpdateNameTagText(BOOL new_name) // Might be blank if name not available yet, that's OK if (show_display_names) { - firstnameText=av_name.mDisplayName; //Defer for later formatting - //addNameTagLine(av_name.mDisplayName, name_tag_color, LLFontGL::NORMAL, + firstnameText = phoenix_name_system == 3 ? av_name.getUserName() : av_name.getDisplayName(); //Defer for later formatting + //addNameTagLine(av_name.getDisplayName(), name_tag_color, LLFontGL::NORMAL, // LLFontGL::getFontSansSerif()); } // Suppress SLID display if display name matches exactly (ugh) - if (show_usernames && !av_name.mIsDisplayNameDefault && !av_name.mUsername.empty()) + if (show_usernames && !av_name.isDisplayNameDefault()) { firstnameText.push_back(' '); firstnameText.push_back('('); - firstnameText.append(av_name.mUsername); //Defer for later formatting + firstnameText.append(phoenix_name_system == 3 ? av_name.getDisplayName() : av_name.getAccountName()); //Defer for later formatting firstnameText.push_back(')'); // *HACK: Desaturate the color //LLColor4 username_color = name_tag_color * 0.83f; - //nameText=av_name.mUsername; - //addNameTagLine(av_name.mUsername, username_color, LLFontGL::NORMAL, - //LLFontGL::getFontSansSerifSmall()); + //addNameTagLine(av_name.getUserName(), username_color, LLFontGL::NORMAL, + // LLFontGL::getFontSansSerifSmall()); } // [RLVa:KB] - Checked: 2010-10-31 (RLVa-1.2.2a) | Modified: RLVa-1.2.2a } @@ -3282,7 +3974,12 @@ void LLVOAvatar::idleUpdateNameTagText(BOOL new_name) else if(allow_nameplate_override && !mCCSAttachmentText.empty()) tag_format=mCCSAttachmentText; else - tag_format=sRenderGroupTitles ? "%g\n%f %l %t" : "%f %l %t"; + { + if(!display_client_new_line) + tag_format=sRenderGroupTitles ? "%g\n%f %l %t" : "%f %l %t"; + else + tag_format=sRenderGroupTitles ? "%g\n%f %l\n%t" : "%f %l\n%t"; + } // replace first name, last name and title typedef boost::tokenizer > tokenizer; @@ -3445,10 +4142,7 @@ void LLVOAvatar::clearNameTag() //static void LLVOAvatar::invalidateNameTag(const LLUUID& agent_id) { - LLViewerObject* obj = gObjectList.findObject(agent_id); - if (!obj) return; - - LLVOAvatar* avatar = dynamic_cast(obj); + LLVOAvatar* avatar = gObjectList.findAvatar(agent_id); if (!avatar) return; avatar->clearNameTag(); @@ -3465,7 +4159,6 @@ void LLVOAvatar::invalidateNameTags() if (avatar->isDead()) continue; avatar->clearNameTag(); - } } @@ -3473,24 +4166,38 @@ void LLVOAvatar::invalidateNameTags() LLVector3 LLVOAvatar::idleUpdateNameTagPosition(const LLVector3& root_pos_last) { LLQuaternion root_rot = mRoot->getWorldRotation(); + LLQuaternion inv_root_rot = ~root_rot; LLVector3 pixel_right_vec; LLVector3 pixel_up_vec; LLViewerCamera::getInstance()->getPixelVectors(root_pos_last, pixel_up_vec, pixel_right_vec); LLVector3 camera_to_av = root_pos_last - LLViewerCamera::getInstance()->getOrigin(); camera_to_av.normalize(); - LLVector3 local_camera_at = camera_to_av * ~root_rot; + LLVector3 local_camera_at = camera_to_av * inv_root_rot; LLVector3 local_camera_up = camera_to_av % LLViewerCamera::getInstance()->getLeftAxis(); local_camera_up.normalize(); - local_camera_up = local_camera_up * ~root_rot; + local_camera_up = local_camera_up * inv_root_rot; + + + // position is based on head position, does not require mAvatarOffset here. - Nyx + LLVector3 avatar_ellipsoid(mBodySize.mV[VX] * 0.4f, + mBodySize.mV[VY] * 0.4f, + mBodySize.mV[VZ] * NAMETAG_VERT_OFFSET_WEIGHT); + + local_camera_up.scaleVec(avatar_ellipsoid); + local_camera_at.scaleVec(avatar_ellipsoid); - local_camera_up.scaleVec((mBodySize + mAvatarOffset) * 0.5f); - local_camera_at.scaleVec((mBodySize + mAvatarOffset) * 0.5f); + LLVector3 head_offset = (mHeadp->getLastWorldPosition() - mRoot->getLastWorldPosition()) * inv_root_rot; + + if (dist_vec(head_offset, mTargetRootToHeadOffset) > NAMETAG_UPDATE_THRESHOLD) + { + mTargetRootToHeadOffset = head_offset; + } + + mCurRootToHeadOffset = lerp(mCurRootToHeadOffset, mTargetRootToHeadOffset, LLSmoothInterpolation::getInterpolant(0.2f)); - LLVector3 name_position = mRoot->getWorldPosition(); - name_position[VZ] -= mPelvisToFoot; - name_position[VZ] += ((mBodySize[VZ] + mAvatarOffset[VZ])* 0.55f); + LLVector3 name_position = mRoot->getLastWorldPosition() + (mCurRootToHeadOffset * root_rot); name_position += (local_camera_up * root_rot) - (projected_vec(local_camera_at * root_rot, camera_to_av)); - name_position += pixel_up_vec * 15.f; + name_position += pixel_up_vec * NAMETAG_VERTICAL_SCREEN_OFFSET; return name_position; } @@ -3518,13 +4225,11 @@ LLColor4 LLVOAvatar::getNameTagColor(bool is_friend) static const LLCachedControl avatar_name_color(gColors,"AvatarNameColor",LLColor4(LLColor4U(251, 175, 93, 255)) ); return avatar_name_color; } - /*else if (LLAvatarNameCache::useDisplayNames()) + /*else if (LLAvatarName::useDisplayNames()) { - // ...color based on whether username "matches" a computed display - // name + // ...color based on whether username "matches" a computed display name LLAvatarName av_name; - if (LLAvatarNameCache::get(getID(), &av_name) - && av_name.mIsDisplayNameDefault) + if (LLAvatarNameCache::get(getID(), &av_name) && av_name.isDisplayNameDefault()) { color_name = "NameTagMatch"; } @@ -3547,7 +4252,11 @@ void LLVOAvatar::idleUpdateBelowWater() F32 water_height; water_height = getRegion()->getWaterHeight(); + BOOL old_below = mBelowWater; mBelowWater = avatar_height < water_height; + if (old_below != mBelowWater) + if (auto ao = AOSystem::getIfExists()) + ao->toggleSwim(mBelowWater); } void LLVOAvatar::slamPosition() @@ -3564,14 +4273,17 @@ void LLVOAvatar::slamPosition() bool LLVOAvatar::isVisuallyMuted() const { - if(isSelf())return false; - static LLCachedControl max_attachment_bytes(gSavedSettings, "RenderAutoMuteByteLimit"); - static LLCachedControl max_attachment_area(gSavedSettings, "RenderAutoMuteSurfaceAreaLimit"); - - return LLMuteList::getInstance()->isMuted(getID()) || - (mAttachmentGeometryBytes > max_attachment_bytes && max_attachment_bytes > 0) || - (mAttachmentSurfaceArea > max_attachment_area && max_attachment_area > 0.f) || - isLangolier(); + if (!isSelf()) + { + static const LLCachedControl show_muted(gSavedSettings, "LiruLegacyDisplayMuteds", false); + return (!show_muted && LLMuteList::getInstance()->isMuted(getID()) || +// [RLVa:LF] - RLV 2.9 camavdist + (gRlvHandler.hasBehaviour(RLV_BHVR_CAMAVDIST) && (gAgent.getPosGlobalFromAgent(const_cast(*this).getCharacterPosition()) - gAgent.getPosGlobalFromAgent(gAgentAvatarp->getRenderPosition())).magVec() > gRlvHandler.camPole(RLV_BHVR_CAMAVDIST)) || +// [/RLVa:LF] + isLangolier() || + isTooComplex()); + } + return false; } void LLVOAvatar::resetFreezeTime() @@ -3584,204 +4296,546 @@ void LLVOAvatar::resetFreezeTime() } } -//------------------------------------------------------------------------ -// updateCharacter() -// called on both your avatar and other avatars -//------------------------------------------------------------------------ -BOOL LLVOAvatar::updateCharacter(LLAgent &agent) + +void LLVOAvatar::updateAppearanceMessageDebugText() { - // Frozen! - if (areAnimationsPaused()) + S32 central_bake_version = -1; + LLViewerRegion* region = getRegion(); + if (region) + { + central_bake_version = getRegion()->getCentralBakeVersion(); + } + bool all_baked_downloaded = allBakedTexturesCompletelyDownloaded(); + bool all_local_downloaded = allLocalTexturesCompletelyDownloaded(); + std::string debug_line = llformat("%s%s - mLocal: %d, mEdit: %d, mUSB: %d, CBV: %d", + isSelf() ? (all_local_downloaded ? "L" : "l") : "-", + all_baked_downloaded ? "B" : "b", + mUseLocalAppearance, mIsEditingAppearance, + mUseServerBakes, central_bake_version); + std::string origin_string = bakedTextureOriginInfo(); + debug_line += " [" + origin_string + "]"; + S32 curr_cof_version = LLAppearanceMgr::instance().getCOFVersion(); + S32 last_request_cof_version = mLastUpdateRequestCOFVersion; + S32 last_received_cof_version = mLastUpdateReceivedCOFVersion; + if (isSelf()) { - updateMotions(LLCharacter::NORMAL_UPDATE); // This is necessary to get unpaused again. - return FALSE; + debug_line += llformat(" - cof: %d req: %d rcv:%d", + curr_cof_version, last_request_cof_version, last_received_cof_version); + } + else + { + debug_line += llformat(" - cof rcv:%d", last_received_cof_version); + } + debug_line += llformat(" bsz-z: %.3f", mBodySize[2]); + if (mAvatarOffset[2] != 0.0f) + { + debug_line += llformat("avofs-z: %.3f", mAvatarOffset[2]); + } + bool hover_enabled = region && region->avatarHoverHeightEnabled(); + debug_line += hover_enabled ? " H" : " h"; + const LLVector3& hover_offset = getHoverOffset(); + if (hover_offset[2] != 0.0) + { + debug_line += llformat(" hov_z: %.3f", hover_offset[2]); + debug_line += llformat(" %s", (isSitting() ? "S" : "T")); + debug_line += llformat("%s", (isMotionActive(ANIM_AGENT_SIT_GROUND_CONSTRAINED) ? "G" : "-")); + } + LLVector3 ankle_right_pos_agent = mFootRightp->getWorldPosition(); + LLVector3 normal; + LLVector3 ankle_right_ground_agent = ankle_right_pos_agent; + resolveHeightAgent(ankle_right_pos_agent, ankle_right_ground_agent, normal); + F32 rightElev = llmax(-0.2f, ankle_right_pos_agent.mV[VZ] - ankle_right_ground_agent.mV[VZ]); + debug_line += llformat(" relev %.3f", rightElev); + + LLVector3 root_pos = mRoot->getPosition(); + LLVector3 pelvis_pos = mPelvisp->getPosition(); + debug_line += llformat(" rp %.3f pp %.3f", root_pos[2], pelvis_pos[2]); + + S32 is_visible = (S32) isVisible(); + S32 is_m_visible = (S32) mVisible; + debug_line += llformat(" v %d/%d", is_visible, is_m_visible); + F32 elapsed = mLastAppearanceMessageTimer.getElapsedTimeF32(); + static const char *elapsed_chars = "Xx*..."; + U32 bucket = U32(elapsed*2); + if (bucket < strlen(elapsed_chars)) + { + debug_line += llformat(" %c", elapsed_chars[bucket]); } + addDebugText(debug_line); +} - // clear debug text - mDebugText.clear(); +LLViewerInventoryItem* getObjectInventoryItem(LLViewerObject *vobj, LLUUID asset_id) +{ + LLViewerInventoryItem *item = NULL; - if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage")) + if (vobj) { - S32 central_bake_version = -1; - if (getRegion()) - { - central_bake_version = getRegion()->getCentralBakeVersion(); - } - bool all_baked_downloaded = allBakedTexturesCompletelyDownloaded(); - bool all_local_downloaded = allLocalTexturesCompletelyDownloaded(); - std::string debug_line = llformat("%s%s - mLocal: %d, mEdit: %d, mUSB: %d, CBV: %d", - isSelf() ? (all_local_downloaded ? "L" : "l") : "-", - all_baked_downloaded ? "B" : "b", - mUseLocalAppearance, mIsEditingAppearance, - mUseServerBakes, central_bake_version); - std::string origin_string = bakedTextureOriginInfo(); - debug_line += " [" + origin_string + "]"; - if (isSelf()) + if (vobj->getInventorySerial() <= 0) { - S32 curr_cof_version = LLAppearanceMgr::instance().getCOFVersion(); - S32 last_request_cof_version = LLAppearanceMgr::instance().getLastUpdateRequestCOFVersion(); - S32 last_received_cof_version = LLAppearanceMgr::instance().getLastAppearanceUpdateCOFVersion(); - debug_line += llformat(" - cof: %d req: %d rcv:%d", - curr_cof_version, last_request_cof_version, last_received_cof_version); + vobj->requestInventory(); } - addDebugText(debug_line); - } - if (gSavedSettings.getBOOL("DebugAvatarCompositeBaked")) - { - if (!mBakedTextureDebugText.empty()) - addDebugText(mBakedTextureDebugText); + item = vobj->getInventoryItemByAsset(asset_id); } + return item; +} - if (LLVOAvatar::sShowAnimationDebug) +LLViewerInventoryItem* recursiveGetObjectInventoryItem(LLViewerObject *vobj, LLUUID asset_id) +{ + LLViewerInventoryItem *item = getObjectInventoryItem(vobj, asset_id); + if (!item) { - for (LLMotionController::motion_list_t::iterator iter = mMotionController.getActiveMotions().begin(); - iter != mMotionController.getActiveMotions().end(); ++iter) + LLViewerObject::const_child_list_t& children = vobj->getChildren(); + for (LLViewerObject::const_child_list_t::const_iterator it = children.begin(); + it != children.end(); ++it) { - LLMotion* motionp = *iter; - if (motionp->getMinPixelArea() < getPixelArea()) + LLViewerObject *childp = *it; + item = getObjectInventoryItem(childp, asset_id); + if (item) { - std::string output; - if (motionp->getName().empty()) - { - output = llformat("%s - %d", - motionp->getID().asString().c_str(), - (U32)motionp->getPriority()); - } - else - { - output = llformat("%s - %d", - motionp->getName().c_str(), - (U32)motionp->getPriority()); - } - addDebugText(output); + break; } } } + return item; +} - if (gNoRender) +void LLVOAvatar::updateAnimationDebugText() +{ + addDebugText(llformat("at=%.1f", mMotionController.getAnimTime())); + for (LLMotionController::motion_list_t::iterator iter = mMotionController.getActiveMotions().begin(); + iter != mMotionController.getActiveMotions().end(); ++iter) { - // Hack if we're running drones... - if (isSelf()) + LLMotion* motionp = *iter; + if (motionp->getMinPixelArea() < getPixelArea()) { - gAgent.setPositionAgent(getPositionAgent()); + std::string output; + std::string motion_name = motionp->getName(); + if (motion_name.empty()) + { + if (isControlAvatar()) + { + LLControlAvatar *control_av = dynamic_cast(this); + // Try to get name from inventory of associated object + LLVOVolume *volp = control_av->mRootVolp; + LLViewerInventoryItem *item = recursiveGetObjectInventoryItem(volp, motionp->getID()); + if (item) + { + motion_name = item->getName(); + } + } + } + if (motion_name.empty()) + { + std::string name; + name = motionp->getID().asString(); + output = llformat("%s - %d", + name.c_str(), + (U32)motionp->getPriority()); + } + else + { + output = llformat("%s - %d", + motion_name.c_str(), + (U32)motionp->getPriority()); + } + if (motionp->server()) + { +#ifdef SHOW_ASSERT + output += llformat(" rt=%.1f r=%d s=0x%xl", motionp->getRuntime(), motionp->mReadyEvents, motionp->server()); +#else + output += llformat(" rt=%.1f s=0x%xl", motionp->getRuntime(), motionp->server()); +#endif + } + addDebugText(output); } - return FALSE; } +} +void LLVOAvatar::updateDebugText() +{ + // Leave mDebugText uncleared here, in case a derived class has added some state first - LLVector3d root_pos_global; - - if (!mIsBuilt) + if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage")) { - return FALSE; + updateAppearanceMessageDebugText(); } - BOOL visible = isVisible(); - - // For fading out the names above heads, only let the timer - // run if we're visible. - if (mDrawable.notNull() && !visible) + if (gSavedSettings.getBOOL("DebugAvatarCompositeBaked")) { - mTimeVisible.reset(); + if (!mBakedTextureDebugText.empty()) + addDebugText(mBakedTextureDebugText); } - - //-------------------------------------------------------------------- - // the rest should only be done occasionally for far away avatars - //-------------------------------------------------------------------- - - if (visible && (!isSelf() || isVisuallyMuted()) && !mIsDummy && sUseImpostors && !mNeedsAnimUpdate && !sFreezeCounter) + // Develop -> Avatar -> Animation Info + if (LLVOAvatar::sShowAnimationDebug) { - const LLVector4a* ext = mDrawable->getSpatialExtents(); - LLVector4a size; - size.setSub(ext[1],ext[0]); - F32 mag = size.getLength3().getF32()*0.5f; - - - F32 impostor_area = 256.f*512.f*(8.125f - LLVOAvatar::sLODFactor*8.f); - if (isVisuallyMuted()) - { // muted avatars update at 16 hz - mUpdatePeriod = 16; - } - else if (mVisibilityRank <= LLVOAvatar::sMaxVisible || - mDrawable->mDistanceWRTCamera < 1.f + mag) - { //first 25% of max visible avatars are not impostored - //also, don't impostor avatars whose bounding box may be penetrating the - //impostor camera near clip plane - mUpdatePeriod = 1; - } - else if (mVisibilityRank > LLVOAvatar::sMaxVisible * 4) - { //background avatars are REALLY slow updating impostors - mUpdatePeriod = 16; - } - else if (mVisibilityRank > LLVOAvatar::sMaxVisible * 3) - { //back 25% of max visible avatars are slow updating impostors - mUpdatePeriod = 8; - } - else if (mImpostorPixelArea <= impostor_area) - { // stuff in between gets an update period based on pixel area - mUpdatePeriod = llclamp((S32) sqrtf(impostor_area*4.f/mImpostorPixelArea), 2, 8); - } - else - { - //nearby avatars, update the impostors more frequently. - mUpdatePeriod = 4; - } + updateAnimationDebugText(); + } - visible = (LLDrawable::getCurrentFrame()+mID.mData[0])%mUpdatePeriod == 0 ? TRUE : FALSE; + if (!mDebugText.size() && mText.notNull()) + { + mText->markDead(); + mText = NULL; } - else + else if (mDebugText.size()) { - mUpdatePeriod = 1; + setDebugText(mDebugText); } + mDebugText.clear(); +} - // don't early out for your own avatar, as we rely on your animations playing reliably - // for example, the "turn around" animation when entering customize avatar needs to trigger - // even when your avatar is offscreen - if (!visible && !isSelf()) +//------------------------------------------------------------------------ +// updateFootstepSounds +// Factored out from updateCharacter() +// Generate footstep sounds when feet hit the ground +//------------------------------------------------------------------------ +void LLVOAvatar::updateFootstepSounds() +{ + if (mIsDummy) { - updateMotions(LLCharacter::HIDDEN_UPDATE); - return FALSE; + return; } - // change animation time quanta based on avatar render load - if (!isSelf() && !mIsDummy) + //------------------------------------------------------------------------- + // Find the ground under each foot, these are used for a variety + // of things that follow + //------------------------------------------------------------------------- + LLVector3 ankle_left_pos_agent = mFootLeftp->getWorldPosition(); + LLVector3 ankle_right_pos_agent = mFootRightp->getWorldPosition(); + + LLVector3 ankle_left_ground_agent = ankle_left_pos_agent; + LLVector3 ankle_right_ground_agent = ankle_right_pos_agent; + LLVector3 normal; + resolveHeightAgent(ankle_left_pos_agent, ankle_left_ground_agent, normal); + resolveHeightAgent(ankle_right_pos_agent, ankle_right_ground_agent, normal); + + F32 leftElev = llmax(-0.2f, ankle_left_pos_agent.mV[VZ] - ankle_left_ground_agent.mV[VZ]); + F32 rightElev = llmax(-0.2f, ankle_right_pos_agent.mV[VZ] - ankle_right_ground_agent.mV[VZ]); + + if (!isSitting()) { - F32 time_quantum = clamp_rescale((F32)sInstances.size(), 10.f, 35.f, 0.f, 0.25f); - F32 pixel_area_scale = clamp_rescale(mPixelArea, 100, 5000, 1.f, 0.f); - F32 time_step = time_quantum * pixel_area_scale; - if (time_step != 0.f) + //------------------------------------------------------------------------- + // Figure out which foot is on ground + //------------------------------------------------------------------------- + if (!mInAir) { - // disable walk motion servo controller as it doesn't work with motion timesteps - stopMotion(ANIM_AGENT_WALK_ADJUST); - removeAnimationData("Walk Speed"); + if ((leftElev < 0.0f) || (rightElev < 0.0f)) + { + ankle_left_pos_agent = mFootLeftp->getWorldPosition(); + ankle_right_pos_agent = mFootRightp->getWorldPosition(); + leftElev = ankle_left_pos_agent.mV[VZ] - ankle_left_ground_agent.mV[VZ]; + rightElev = ankle_right_pos_agent.mV[VZ] - ankle_right_ground_agent.mV[VZ]; + } } - mMotionController.setTimeStep(time_step); -// llinfos << "Setting timestep to " << time_quantum * pixel_area_scale << llendl; } + + //------------------------------------------------------------------------- + // Generate footstep sounds when feet hit the ground + //------------------------------------------------------------------------- + const LLUUID AGENT_FOOTSTEP_ANIMS[] = {ANIM_AGENT_WALK, ANIM_AGENT_RUN, ANIM_AGENT_LAND}; + const S32 NUM_AGENT_FOOTSTEP_ANIMS = LL_ARRAY_SIZE(AGENT_FOOTSTEP_ANIMS); - if (getParent() && !mIsSitting) + if ( gAudiop && isAnyAnimationSignaled(AGENT_FOOTSTEP_ANIMS, NUM_AGENT_FOOTSTEP_ANIMS) ) { - sitOnObject((LLViewerObject*)getParent()); + BOOL playSound = FALSE; + LLVector3 foot_pos_agent; + + BOOL onGroundLeft = (leftElev <= 0.05f); + BOOL onGroundRight = (rightElev <= 0.05f); + + // did left foot hit the ground? + if ( onGroundLeft && !mWasOnGroundLeft ) + { + foot_pos_agent = ankle_left_pos_agent; + playSound = TRUE; + } + + // did right foot hit the ground? + if ( onGroundRight && !mWasOnGroundRight ) + { + foot_pos_agent = ankle_right_pos_agent; + playSound = TRUE; + } + + mWasOnGroundLeft = onGroundLeft; + mWasOnGroundRight = onGroundRight; + + if ( playSound ) + { + const F32 STEP_VOLUME = 0.5f; + const LLUUID& step_sound_id = getStepSound(); + + LLVector3d foot_pos_global = gAgent.getPosGlobalFromAgent(foot_pos_agent); + + if (LLViewerParcelMgr::getInstance()->canHearSound(foot_pos_global) + && !LLMuteList::getInstance()->isMuted(getID(), LLMute::flagObjectSounds)) + { + gAudiop->triggerSound(step_sound_id, getID(), STEP_VOLUME, LLAudioEngine::AUDIO_TYPE_AMBIENT, foot_pos_global); + } + } } - else if (!getParent() && mIsSitting && !isMotionActive(ANIM_AGENT_SIT_GROUND_CONSTRAINED)) +} + +//------------------------------------------------------------------------ +// computeUpdatePeriod() +// Factored out from updateCharacter() +// Set new value for mUpdatePeriod based on distance and various other factors. +//------------------------------------------------------------------------ +void LLVOAvatar::computeUpdatePeriod() +{ + bool visually_muted = isVisuallyMuted(); + if (mDrawable.notNull() + && isVisible() + && (!isSelf() || visually_muted) + && !isUIAvatar() + && sUseImpostors + && !mNeedsAnimUpdate + && !sFreezeCounter) { - getOffObject(); + const LLVector4a* ext = mDrawable->getSpatialExtents(); + LLVector4a size; + size.setSub(ext[1],ext[0]); + F32 mag = size.getLength3().getF32()*0.5f; + + + F32 impostor_area = 256.f*512.f*(8.125f - LLVOAvatar::sLODFactor*8.f); + if (visually_muted) + { // visually muted avatars update at 16 hz + mUpdatePeriod = 16; + } + else if (! shouldImpostor() + || mDrawable->mDistanceWRTCamera < 1.f + mag) + { // first 25% of max visible avatars are not impostored + // also, don't impostor avatars whose bounding box may be penetrating the + // impostor camera near clip plane + mUpdatePeriod = 1; + } + else if ( shouldImpostor(4) ) + { //background avatars are REALLY slow updating impostors + mUpdatePeriod = 16; + } + else if ( shouldImpostor(3) ) + { //back 25% of max visible avatars are slow updating impostors + mUpdatePeriod = 8; + } + else if (mImpostorPixelArea <= impostor_area) + { // stuff in between gets an update period based on pixel area + mUpdatePeriod = llclamp((S32) sqrtf(impostor_area*4.f/mImpostorPixelArea), 2, 8); + } + else + { + //nearby avatars, update the impostors more frequently. + mUpdatePeriod = 4; + } + } + else + { + mUpdatePeriod = 1; } +} - //-------------------------------------------------------------------- - // create local variables in world coords for region position values - //-------------------------------------------------------------------- - F32 speed; - LLVector3 normal; +//------------------------------------------------------------------------ +// updateOrientation() +// Factored out from updateCharacter() +// This is used by updateCharacter() to update the avatar's orientation: +// - updates mTurning state +// - updates rotation of the mRoot joint in the skeleton +// - for self, calls setControlFlags() to notify the simulator about any turns +//------------------------------------------------------------------------ +void LLVOAvatar::updateOrientation(LLAgent& agent, F32 speed, F32 delta_time) +{ + LLQuaternion iQ; + LLVector3 upDir( 0.0f, 0.0f, 1.0f ); + + // Compute a forward direction vector derived from the primitive rotation + // and the velocity vector. When walking or jumping, don't let body deviate + // more than 90 from the view, if necessary, flip the velocity vector. - LLVector3 xyVel = getVelocity(); - xyVel.mV[VZ] = 0.0f; - speed = xyVel.length(); + LLVector3 primDir; + if (isSelf()) + { + primDir = agent.getAtAxis() - projected_vec(agent.getAtAxis(), agent.getReferenceUpVector()); + primDir.normalize(); + } + else + { + primDir = getRotation().getMatrix3().getFwdRow(); + } + LLVector3 velDir = getVelocity(); + velDir.normalize(); + static LLCachedControl TurnAround("TurnAroundWhenWalkingBackwards"); + if (!TurnAround && (mSignaledAnimations.find(ANIM_AGENT_WALK) != mSignaledAnimations.end())) + { + F32 vpD = velDir * primDir; + if (vpD < -0.5f) + { + velDir *= -1.0f; + } + } + LLVector3 fwdDir = lerp(primDir, velDir, clamp_rescale(speed, 0.5f, 2.0f, 0.0f, 1.0f)); + if (isSelf() && gAgentCamera.cameraMouselook()) + { + // make sure fwdDir stays in same general direction as primdir + if (gAgent.getFlying()) + { + fwdDir = LLViewerCamera::getInstance()->getAtAxis(); + } + else + { + LLVector3 at_axis = LLViewerCamera::getInstance()->getAtAxis(); + LLVector3 up_vector = gAgent.getReferenceUpVector(); + at_axis -= up_vector * (at_axis * up_vector); + at_axis.normalize(); + + F32 dot = fwdDir * at_axis; + if (dot < 0.f) + { + fwdDir -= 2.f * at_axis * dot; + fwdDir.normalize(); + } + } + + } + + LLQuaternion root_rotation = LLMatrix4(mRoot->getWorldMatrix().getF32ptr()).quaternion(); + F32 root_roll, root_pitch, root_yaw; + root_rotation.getEulerAngles(&root_roll, &root_pitch, &root_yaw); + + if (sDebugAvatarRotation) + { + LL_INFOS() << "root_roll " << RAD_TO_DEG * root_roll + << " root_pitch " << RAD_TO_DEG * root_pitch + << " root_yaw " << RAD_TO_DEG * root_yaw + << LL_ENDL; + } + + // When moving very slow, the pelvis is allowed to deviate from the + // forward direction to allow it to hold it's position while the torso + // and head turn. Once in motion, it must conform however. + BOOL self_in_mouselook = isSelf() && gAgentCamera.cameraMouselook(); + + LLVector3 pelvisDir( mRoot->getWorldMatrix().getRow().getF32ptr() ); + + static const LLCachedControl s_pelvis_rot_threshold_slow(gSavedSettings, "AvatarRotateThresholdSlow", 60.0); + static const LLCachedControl s_pelvis_rot_threshold_fast(gSavedSettings, "AvatarRotateThresholdFast", 2.0); + static const LLCachedControl useRealisticMouselook("UseRealisticMouselook"); + F32 pelvis_rot_threshold = clamp_rescale(speed, 0.1f, 1.0f, useRealisticMouselook ? s_pelvis_rot_threshold_slow * 2 : s_pelvis_rot_threshold_slow, s_pelvis_rot_threshold_fast); + + if (self_in_mouselook && !useRealisticMouselook) + { + pelvis_rot_threshold *= MOUSELOOK_PELVIS_FOLLOW_FACTOR; + } + pelvis_rot_threshold *= DEG_TO_RAD; + + F32 angle = angle_between( pelvisDir, fwdDir ); - if (!(mIsSitting && getParent())) + // The avatar's root is allowed to have a yaw that deviates widely + // from the forward direction, but if roll or pitch are off even + // a little bit we need to correct the rotation. + if(root_roll < 1.f * DEG_TO_RAD + && root_pitch < 5.f * DEG_TO_RAD) { + // smaller correction vector means pelvis follows prim direction more closely + if (!mTurning && angle > pelvis_rot_threshold*0.75f) + { + mTurning = TRUE; + } + + // use tighter threshold when turning + if (mTurning) + { + pelvis_rot_threshold *= 0.4f; + } + + // am I done turning? + if (angle < pelvis_rot_threshold) + { + mTurning = FALSE; + } + + LLVector3 correction_vector = (pelvisDir - fwdDir) * clamp_rescale(angle, pelvis_rot_threshold*0.75f, pelvis_rot_threshold, 1.0f, 0.0f); + fwdDir += correction_vector; + } + else + { + mTurning = FALSE; + } + + // Now compute the full world space rotation for the whole body (wQv) + LLVector3 leftDir = upDir % fwdDir; + leftDir.normalize(); + fwdDir = leftDir % upDir; + LLQuaternion wQv( fwdDir, leftDir, upDir ); + + if (isSelf() && mTurning) + { + if ((fwdDir % pelvisDir) * upDir > 0.f) + { + gAgent.setControlFlags(AGENT_CONTROL_TURN_RIGHT); + } + else + { + gAgent.setControlFlags(AGENT_CONTROL_TURN_LEFT); + } + } + + // Set the root rotation, but do so incrementally so that it + // lags in time by some fixed amount. + //F32 u = LLSmoothInterpolation::getInterpolant(PELVIS_LAG); + F32 pelvis_lag_time = 0.f; + if (self_in_mouselook) + { + pelvis_lag_time = PELVIS_LAG_MOUSELOOK; + } + else if (mInAir) + { + pelvis_lag_time = PELVIS_LAG_FLYING; + // increase pelvis lag time when moving slowly + pelvis_lag_time *= clamp_rescale(mSpeedAccum, 0.f, 15.f, 3.f, 1.f); + } + else + { + pelvis_lag_time = PELVIS_LAG_WALKING; + } + +F32 u = llclamp((delta_time / pelvis_lag_time), 0.0f, 1.0f); + + mRoot->setWorldRotation( slerp(u, mRoot->getWorldRotation(), wQv) ); +} + +//------------------------------------------------------------------------ +// updateTimeStep() +// Factored out from updateCharacter(). +// +// Updates the time step used by the motion controller, based on area +// and avatar count criteria. This will also stop the +// ANIM_AGENT_WALK_ADJUST animation under some circumstances. +// ------------------------------------------------------------------------ +void LLVOAvatar::updateTimeStep() +{ + if (!isSelf() && !isUIAvatar()) // ie, non-self avatars, and animated objects will be affected. + { + F32 time_quantum = clamp_rescale((F32)sInstances.size(), 10.f, 35.f, 0.f, 0.25f); + F32 pixel_area_scale = clamp_rescale(mPixelArea, 100, 5000, 1.f, 0.f); + F32 time_step = time_quantum * pixel_area_scale; + if (time_step != 0.f) + { + // disable walk motion servo controller as it doesn't work with motion timesteps + stopMotion(ANIM_AGENT_WALK_ADJUST); + removeAnimationData("Walk Speed"); + } + mMotionController.setTimeStep(time_step); + } +} + +void LLVOAvatar::updateRootPositionAndRotation(LLAgent& agent, F32 speed, bool was_sit_ground_constrained) +{ + if (!(isSitting() && getParent())) + { + // This case includes all configurations except sitting on an + // object, so does include ground sit. + //-------------------------------------------------------------------- // get timing info // handle initial condition case @@ -3799,9 +4853,9 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent) //-------------------------------------------------------------------- // dont' let dT get larger than 1/5th of a second //-------------------------------------------------------------------- - F32 deltaTime = animation_time - mTimeLast; + F32 delta_time = animation_time - mTimeLast; - deltaTime = llclamp( deltaTime, DELTA_TIME_MIN, DELTA_TIME_MAX ); + delta_time = llclamp( delta_time, DELTA_TIME_MIN, DELTA_TIME_MAX ); mTimeLast = animation_time; mSpeedAccum = (mSpeedAccum * 0.95f) + (speed * 0.05f); @@ -3820,7 +4874,7 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent) root_pos = gAgent.getPosGlobalFromAgent(getRenderPosition()); root_pos.mdV[VZ] += getVisualParamWeight(AVATAR_HOVER); - + LLVector3 normal; resolveHeightGlobal(root_pos, ground_under_pelvis, normal); F32 foot_to_ground = (F32) (root_pos.mdV[VZ] - mPelvisToFoot - ground_under_pelvis.mdV[VZ]); BOOL in_air = ((!LLWorld::getInstance()->getRegionFromPosGlobal(ground_under_pelvis)) || @@ -3832,304 +4886,231 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent) } mInAir = in_air; + // SL-402: with the ability to animate the position of joints + // that affect the body size calculation, computed body size + // can get stale much more easily. Simplest fix is to update + // it frequently. + // SL-427: this appears to be too frequent, moving to only do on animation state change. + //computeBodySize(); + // correct for the fact that the pelvis is not necessarily the center // of the agent's physical representation root_pos.mdV[VZ] -= (0.5f * mBodySize.mV[VZ]) - mPelvisToFoot; - - LLVector3 newPosition = gAgent.getPosAgentFromGlobal(root_pos); + if (!isSitting() && !was_sit_ground_constrained) + { + root_pos += LLVector3d(getHoverOffset()); + } - if (newPosition != mRoot->getXform()->getWorldPosition()) - { - mRoot->touch(); - mRoot->setWorldPosition( newPosition ); // regular update + LLControlAvatar *cav = asControlAvatar(); + if (cav) + { + // SL-1350: Moved to LLDrawable::updateXform() + cav->matchVolumeTransform(); } + else + { + LLVector3 newPosition = gAgent.getPosAgentFromGlobal(root_pos); + if (newPosition != mRoot->getXform()->getWorldPosition()) + { + mRoot->touch(); + mRoot->setWorldPosition( newPosition ); // regular update + } + } //-------------------------------------------------------------------- // Propagate viewer object rotation to root of avatar //-------------------------------------------------------------------- - if (!isAnyAnimationSignaled(AGENT_NO_ROTATE_ANIMS, NUM_AGENT_NO_ROTATE_ANIMS)) + if (!isControlAvatar() && !isAnyAnimationSignaled(AGENT_NO_ROTATE_ANIMS, NUM_AGENT_NO_ROTATE_ANIMS)) { - LLQuaternion iQ; - LLVector3 upDir( 0.0f, 0.0f, 1.0f ); - - // Compute a forward direction vector derived from the primitive rotation - // and the velocity vector. When walking or jumping, don't let body deviate - // more than 90 from the view, if necessary, flip the velocity vector. - - LLVector3 primDir; - if (isSelf()) - { - primDir = agent.getAtAxis() - projected_vec(agent.getAtAxis(), agent.getReferenceUpVector()); - primDir.normalize(); - } - else - { - primDir = getRotation().getMatrix3().getFwdRow(); - } - LLVector3 velDir = getVelocity(); - velDir.normalize(); - static LLCachedControl TurnAround("TurnAroundWhenWalkingBackwards"); - if (!TurnAround && (mSignaledAnimations.find(ANIM_AGENT_WALK) != mSignaledAnimations.end())) - { - F32 vpD = velDir * primDir; - if (vpD < -0.5f) - { - velDir *= -1.0f; - } - } - LLVector3 fwdDir = lerp(primDir, velDir, clamp_rescale(speed, 0.5f, 2.0f, 0.0f, 1.0f)); - if (isSelf() && gAgentCamera.cameraMouselook()) - { - // make sure fwdDir stays in same general direction as primdir - if (gAgent.getFlying()) - { - fwdDir = LLViewerCamera::getInstance()->getAtAxis(); - } - else - { - LLVector3 at_axis = LLViewerCamera::getInstance()->getAtAxis(); - LLVector3 up_vector = gAgent.getReferenceUpVector(); - at_axis -= up_vector * (at_axis * up_vector); - at_axis.normalize(); - - F32 dot = fwdDir * at_axis; - if (dot < 0.f) - { - fwdDir -= 2.f * at_axis * dot; - fwdDir.normalize(); - } - } - - } - - LLQuaternion root_rotation = mRoot->getWorldMatrix().quaternion(); - F32 root_roll, root_pitch, root_yaw; - root_rotation.getEulerAngles(&root_roll, &root_pitch, &root_yaw); - - if (sDebugAvatarRotation) - { - llinfos << "root_roll " << RAD_TO_DEG * root_roll - << " root_pitch " << RAD_TO_DEG * root_pitch - << " root_yaw " << RAD_TO_DEG * root_yaw - << llendl; - } - - // When moving very slow, the pelvis is allowed to deviate from the - // forward direction to allow it to hold it's position while the torso - // and head turn. Once in motion, it must conform however. - BOOL self_in_mouselook = isSelf() && gAgentCamera.cameraMouselook(); - - LLVector3 pelvisDir( mRoot->getWorldMatrix().getFwdRow4().mV ); - - static const LLCachedControl s_pelvis_rot_threshold_slow(gSavedSettings, "AvatarRotateThresholdSlow"); - static const LLCachedControl s_pelvis_rot_threshold_fast(gSavedSettings, "AvatarRotateThresholdFast"); - - F32 pelvis_rot_threshold = clamp_rescale(speed, 0.1f, 1.0f, s_pelvis_rot_threshold_slow, s_pelvis_rot_threshold_fast); - - if (self_in_mouselook) - { - pelvis_rot_threshold *= MOUSELOOK_PELVIS_FOLLOW_FACTOR; - } - pelvis_rot_threshold *= DEG_TO_RAD; - - F32 angle = angle_between( pelvisDir, fwdDir ); - - // The avatar's root is allowed to have a yaw that deviates widely - // from the forward direction, but if roll or pitch are off even - // a little bit we need to correct the rotation. - if(root_roll < 1.f * DEG_TO_RAD - && root_pitch < 5.f * DEG_TO_RAD) - { - // smaller correction vector means pelvis follows prim direction more closely - if (!mTurning && angle > pelvis_rot_threshold*0.75f) - { - mTurning = TRUE; - } - - // use tighter threshold when turning - if (mTurning) - { - pelvis_rot_threshold *= 0.4f; - } - - // am I done turning? - if (angle < pelvis_rot_threshold) - { - mTurning = FALSE; - } - - LLVector3 correction_vector = (pelvisDir - fwdDir) * clamp_rescale(angle, pelvis_rot_threshold*0.75f, pelvis_rot_threshold, 1.0f, 0.0f); - fwdDir += correction_vector; - } - else - { - mTurning = FALSE; - } - - // Now compute the full world space rotation for the whole body (wQv) - LLVector3 leftDir = upDir % fwdDir; - leftDir.normalize(); - fwdDir = leftDir % upDir; - LLQuaternion wQv( fwdDir, leftDir, upDir ); - - if (isSelf() && mTurning) - { - if ((fwdDir % pelvisDir) * upDir > 0.f) - { - gAgent.setControlFlags(AGENT_CONTROL_TURN_RIGHT); - } - else - { - gAgent.setControlFlags(AGENT_CONTROL_TURN_LEFT); - } - } - - // Set the root rotation, but do so incrementally so that it - // lags in time by some fixed amount. - //F32 u = LLCriticalDamp::getInterpolant(PELVIS_LAG); - F32 pelvis_lag_time = 0.f; - if (self_in_mouselook) - { - pelvis_lag_time = PELVIS_LAG_MOUSELOOK; - } - else if (mInAir) - { - pelvis_lag_time = PELVIS_LAG_FLYING; - // increase pelvis lag time when moving slowly - pelvis_lag_time *= clamp_rescale(mSpeedAccum, 0.f, 15.f, 3.f, 1.f); - } - else - { - pelvis_lag_time = PELVIS_LAG_WALKING; - } - - F32 u = llclamp((deltaTime / pelvis_lag_time), 0.0f, 1.0f); - - mRoot->setWorldRotation( slerp(u, mRoot->getWorldRotation(), wQv) ); - + // Rotation fixups for avatars in motion. + // Skip for animated objects. + updateOrientation(agent, speed, delta_time); } } else if (mDrawable.notNull()) { - mRoot->setPosition(mDrawable->getPosition()); - mRoot->setRotation(mDrawable->getRotation()); + LLVector3 pos = mDrawable->getPosition(); + const LLQuaternion& rot = mDrawable->getRotation(); + pos += getHoverOffset() * rot; + mRoot->setPosition(pos); + mRoot->setRotation(rot); } - - //------------------------------------------------------------------------- - // Update character motions - //------------------------------------------------------------------------- - // store data relevant to motions - mSpeed = speed; - - // update animations - if (mSpecialRenderMode == 1) // Animation Preview - updateMotions(LLCharacter::FORCE_UPDATE); - else - updateMotions(LLCharacter::NORMAL_UPDATE); - - // update head position - updateHeadOffset(); - - //------------------------------------------------------------------------- - // Find the ground under each foot, these are used for a variety - // of things that follow - //------------------------------------------------------------------------- - LLVector3 ankle_left_pos_agent = mFootLeftp->getWorldPosition(); - LLVector3 ankle_right_pos_agent = mFootRightp->getWorldPosition(); - - LLVector3 ankle_left_ground_agent = ankle_left_pos_agent; - LLVector3 ankle_right_ground_agent = ankle_right_pos_agent; - resolveHeightAgent(ankle_left_pos_agent, ankle_left_ground_agent, normal); - resolveHeightAgent(ankle_right_pos_agent, ankle_right_ground_agent, normal); - - F32 leftElev = llmax(-0.2f, ankle_left_pos_agent.mV[VZ] - ankle_left_ground_agent.mV[VZ]); - F32 rightElev = llmax(-0.2f, ankle_right_pos_agent.mV[VZ] - ankle_right_ground_agent.mV[VZ]); +} - if (!mIsSitting) +//------------------------------------------------------------------------ +// updateCharacter() +// +// This is called for all avatars, so there are 4 possible situations: +// +// 1) Avatar is your own. In this case the class is LLVOAvatarSelf, +// isSelf() is true, and agent specifies the corresponding agent +// information for you. In all the other cases, agent is irrelevant +// and it would be less confusing if it were null or something. +// +// 2) Avatar is controlled by another resident. Class is LLVOAvatar, +// and isSelf() is false. +// +// 3) Avatar is the controller for an animated object. Class is +// LLControlAvatar and mIsDummy is true. Avatar is a purely +// viewer-side entity with no representation on the simulator. +// +// 4) Avatar is a UI avatar used in some areas of the UI, such as when +// previewing uploaded animations. Class is LLUIAvatar, and mIsDummy +// is true. Avatar is purely viewer-side with no representation on the +// simulator. +// +//------------------------------------------------------------------------ +BOOL LLVOAvatar::updateCharacter(LLAgent &agent) +{ + // Frozen! + if (areAnimationsPaused()) { - //------------------------------------------------------------------------- - // Figure out which foot is on ground - //------------------------------------------------------------------------- - if (!mInAir) - { - if ((leftElev < 0.0f) || (rightElev < 0.0f)) - { - ankle_left_pos_agent = mFootLeftp->getWorldPosition(); - ankle_right_pos_agent = mFootRightp->getWorldPosition(); - leftElev = ankle_left_pos_agent.mV[VZ] - ankle_left_ground_agent.mV[VZ]; - rightElev = ankle_right_pos_agent.mV[VZ] - ankle_right_ground_agent.mV[VZ]; - } - } + updateMotions(LLCharacter::NORMAL_UPDATE); // This is necessary to get unpaused again. + return FALSE; } - //------------------------------------------------------------------------- - // Generate footstep sounds when feet hit the ground - //------------------------------------------------------------------------- - const LLUUID AGENT_FOOTSTEP_ANIMS[] = {ANIM_AGENT_WALK, ANIM_AGENT_RUN, ANIM_AGENT_LAND}; - const S32 NUM_AGENT_FOOTSTEP_ANIMS = LL_ARRAY_SIZE(AGENT_FOOTSTEP_ANIMS); - - if ( gAudiop && isAnyAnimationSignaled(AGENT_FOOTSTEP_ANIMS, NUM_AGENT_FOOTSTEP_ANIMS) ) + updateDebugText(); + + if (gNoRender) { - BOOL playSound = FALSE; - LLVector3 foot_pos_agent; - - BOOL onGroundLeft = (leftElev <= 0.05f); - BOOL onGroundRight = (rightElev <= 0.05f); - - // did left foot hit the ground? - if ( onGroundLeft && !mWasOnGroundLeft ) + // Hack if we're running drones... + if (isSelf()) { - foot_pos_agent = ankle_left_pos_agent; - playSound = TRUE; + gAgent.setPositionAgent(getPositionAgent()); } + return FALSE; + } - // did right foot hit the ground? - if ( onGroundRight && !mWasOnGroundRight ) - { - foot_pos_agent = ankle_right_pos_agent; - playSound = TRUE; - } + if (!mIsBuilt) + { + return FALSE; + } - mWasOnGroundLeft = onGroundLeft; - mWasOnGroundRight = onGroundRight; + bool visible = isVisible(); + bool is_control_avatar = isControlAvatar(); // capture state to simplify tracing + bool is_attachment = false; + if (is_control_avatar) + { + LLControlAvatar *cav = asControlAvatar(); + is_attachment = cav && cav->mRootVolp && cav->mRootVolp->isAttachment(); // For attached animated objects + } - if ( playSound ) - { -// F32 gain = clamp_rescale( mSpeedAccum, -// AUDIO_STEP_LO_SPEED, AUDIO_STEP_HI_SPEED, -// AUDIO_STEP_LO_GAIN, AUDIO_STEP_HI_GAIN ); + // For fading out the names above heads, only let the timer + // run if we're visible. + if (mDrawable.notNull() && !visible) + { + mTimeVisible.reset(); + } - const F32 STEP_VOLUME = 0.5f; - const LLUUID& step_sound_id = getStepSound(); + //-------------------------------------------------------------------- + // The rest should only be done occasionally for far away avatars. + // Set mUpdatePeriod and visible based on distance and other criteria. + //-------------------------------------------------------------------- + computeUpdatePeriod(); + visible = (LLDrawable::getCurrentFrame()+mID.mData[0])%mUpdatePeriod == 0 ? TRUE : FALSE; - LLVector3d foot_pos_global = gAgent.getPosGlobalFromAgent(foot_pos_agent); + //-------------------------------------------------------------------- + + // don't early out for your own avatar, as we rely on your animations playing reliably + // for example, the "turn around" animation when entering customize avatar needs to trigger + // even when your avatar is offscreen + if (!visible && !isSelf()) + { + updateMotions(LLCharacter::HIDDEN_UPDATE); + return FALSE; + } - if (LLViewerParcelMgr::getInstance()->canHearSound(foot_pos_global) - && !LLMuteList::getInstance()->isMuted(getID(), LLMute::flagObjectSounds)) - { - gAudiop->triggerSound(step_sound_id, getID(), STEP_VOLUME, LLAudioEngine::AUDIO_TYPE_AMBIENT, foot_pos_global); - } + // change animation time quanta based on avatar render load + //updateTimeStep(); + if (getParent() && !isSitting()) + { + sitOnObject((LLViewerObject*)getParent()); + } + else if (!getParent() && isSitting() && !isMotionActive(ANIM_AGENT_SIT_GROUND_CONSTRAINED)) + { + getOffObject(); + // + //Singu note: this appears to be a safety catch: + // when getParent() is NULL and we're not playing ANIM_AGENT_SIT_GROUND_CONSTRAINED then we aren't sitting! + // The previous call existed in an attempt to fix this inconsistent state by standing up from an object. + // However, since getParent() is NULL that function would crash! + // Since we never got crash reports regarding to this, that apparently never happened, except, I discovered + // today, when you are ground sitting and then LLMotionController::deleteAllMotions or + // LLMotionController::deactivateAllMotions is called, which seems to only happen when previewing an + // to-be-uploaded animation on your own avatar (while ground sitting). + // Hence, we DO need this safety net but not for standing up from an object but for standing up from the ground. + // I fixed the crash in getOffObject(), so it's ok to call that. In order to make things consistent with + // the server we need to actually stand up though, or we can't move anymore afterwards. + if (isSelf()) + { + gAgent.setControlFlags(AGENT_CONTROL_STAND_UP); } + // } - mRoot->updateWorldMatrixChildren(); + //-------------------------------------------------------------------- + // create local variables in world coords for region position values + //-------------------------------------------------------------------- + LLVector3 xyVel = getVelocity(); + xyVel.mV[VZ] = 0.0f; + F32 speed = xyVel.length(); + // remembering the value here prevents a display glitch if the + // animation gets toggled during this update. + bool was_sit_ground_constrained = isMotionActive(ANIM_AGENT_SIT_GROUND_CONSTRAINED); - if (!mDebugText.size() && mText.notNull()) + //-------------------------------------------------------------------- + // This does a bunch of state updating, including figuring out + // whether av is in the air, setting mRoot position and rotation + // In some cases, calls updateOrientation() for a lot of the + // work + // -------------------------------------------------------------------- + updateRootPositionAndRotation(agent, speed, was_sit_ground_constrained); + + //------------------------------------------------------------------------- + // Update character motions + //------------------------------------------------------------------------- + // store data relevant to motions + mSpeed = speed; + + // update animations + if (mSpecialRenderMode == 1) // Animation Preview { - mText->markDead(); - mText = NULL; + updateMotions(LLCharacter::FORCE_UPDATE); } - else if (mDebugText.size()) + else { - setDebugText(mDebugText); + updateMotions(LLCharacter::NORMAL_UPDATE); + } + + // Special handling for sitting on ground. + if (!getParent() && (isSitting() || was_sit_ground_constrained)) + { + F32 off_z = LLVector3d(getHoverOffset()).mdV[VZ]; + if (off_z != 0.0) + { + LLVector3 pos = mRoot->getWorldPosition(); + pos.mV[VZ] += off_z; + mRoot->touch(); + mRoot->setWorldPosition(pos); + } } + // update head position + updateHeadOffset(); + + // Generate footstep sounds when feet hit the ground + updateFootstepSounds(); + + // Update child joints as needed. + mRoot->updateWorldMatrixChildren(); + //mesh vertices need to be reskinned mNeedsSkin = TRUE; return TRUE; } + //----------------------------------------------------------------------------- // updateHeadOffset() //----------------------------------------------------------------------------- @@ -4144,50 +5125,24 @@ void LLVOAvatar::updateHeadOffset() { midEyePt = midEyePt * ~mDrawable->getWorldRotation(); } - if (mIsSitting) + if (isSitting()) { - mHeadOffset = midEyePt; + mHeadOffset = midEyePt; } else { F32 u = llmax(0.f, HEAD_MOVEMENT_AVG_TIME - (1.f / gFPSClamped)); - mHeadOffset = lerp(midEyePt, mHeadOffset, u); - } -} -//------------------------------------------------------------------------ -// setPelvisOffset -//------------------------------------------------------------------------ -void LLVOAvatar::setPelvisOffset( bool hasOffset, const LLVector3& offsetAmount, F32 pelvisFixup ) -{ - mHasPelvisOffset = hasOffset; - if ( mHasPelvisOffset ) - { - //Store off last pelvis to foot value - mLastPelvisToFoot = mPelvisToFoot; - mPelvisOffset = offsetAmount; - mLastPelvisFixup = mPelvisFixup; - mPelvisFixup = pelvisFixup; + mHeadOffset = lerp(midEyePt, mHeadOffset, u); } } //------------------------------------------------------------------------ // postPelvisSetRecalc //------------------------------------------------------------------------ -void LLVOAvatar::postPelvisSetRecalc( void ) -{ - computeBodySize(); - mRoot->touch(); - mRoot->updateWorldMatrixChildren(); - dirtyMesh(); - updateHeadOffset(); -} -//------------------------------------------------------------------------ -// pelisPoke -//------------------------------------------------------------------------ -void LLVOAvatar::setPelvisOffset( F32 pelvisFixupAmount ) -{ - mHasPelvisOffset = true; - mLastPelvisFixup = mPelvisFixup; - mPelvisFixup = pelvisFixupAmount; +void LLVOAvatar::postPelvisSetRecalc() +{ + mRoot->updateWorldMatrixChildren(); + computeBodySize(); + dirtyMesh(2); } //------------------------------------------------------------------------ // updateVisibility() @@ -4198,7 +5153,7 @@ void LLVOAvatar::updateVisibility() if (mIsDummy) { - visible = TRUE; + visible = FALSE; } else if (mDrawable.isNull()) { @@ -4215,14 +5170,14 @@ void LLVOAvatar::updateVisibility() visible = FALSE; } - if(isSelf()) + if (isSelf()) { if (!gAgentWearables.areWearablesLoaded()) { visible = FALSE; } } - else if( !mFirstAppearanceMessageReceived ) + else if (!mFirstAppearanceMessageReceived) { visible = FALSE; } @@ -4236,61 +5191,71 @@ void LLVOAvatar::updateVisibility() } else { - llinfos << "Avatar " << this << " updating visiblity" << llendl; + LL_INFOS() << "Avatar " << this << " updating visiblity" << LL_ENDL; } if (visible) { - llinfos << "Visible" << llendl; + LL_INFOS() << "Visible" << LL_ENDL; } else { - llinfos << "Not visible" << llendl; + LL_INFOS() << "Not visible" << LL_ENDL; } /*if (avatar_in_frustum) { - llinfos << "Avatar in frustum" << llendl; + LL_INFOS() << "Avatar in frustum" << LL_ENDL; } else { - llinfos << "Avatar not in frustum" << llendl; + LL_INFOS() << "Avatar not in frustum" << LL_ENDL; }*/ /*if (LLViewerCamera::getInstance()->sphereInFrustum(sel_pos_agent, 2.0f)) { - llinfos << "Sel pos visible" << llendl; + LL_INFOS() << "Sel pos visible" << LL_ENDL; } if (LLViewerCamera::getInstance()->sphereInFrustum(wrist_right_pos_agent, 0.2f)) { - llinfos << "Wrist pos visible" << llendl; + LL_INFOS() << "Wrist pos visible" << LL_ENDL; } if (LLViewerCamera::getInstance()->sphereInFrustum(getPositionAgent(), getMaxScale()*2.f)) { - llinfos << "Agent visible" << llendl; + LL_INFOS() << "Agent visible" << LL_ENDL; }*/ - llinfos << "PA: " << getPositionAgent() << llendl; - /*llinfos << "SPA: " << sel_pos_agent << llendl; - llinfos << "WPA: " << wrist_right_pos_agent << llendl;*/ - for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); - iter != mAttachmentPoints.end(); - ++iter) + LL_INFOS() << "PA: " << getPositionAgent() << LL_ENDL; + /*LL_INFOS() << "SPA: " << sel_pos_agent << LL_ENDL; + LL_INFOS() << "WPA: " << wrist_right_pos_agent << LL_ENDL;*/ + + +#if SLOW_ATTACHMENT_LIST + for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); + ++iter) { LLViewerJointAttachment* attachment = iter->second; for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); - attachment_iter != attachment->mAttachedObjects.end(); - ++attachment_iter) + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) { if (LLViewerObject *attached_object = (*attachment_iter)) +#else + for (auto& iter : mAttachedObjectsVector) + {{ + const LLViewerObject *attached_object = iter.first; + const LLViewerJointAttachment *attachment = iter.second; + if (attachment) +#endif { - if (attached_object->mDrawable->isVisible()) + if (attached_object && attached_object->mDrawable->isVisible()) { - llinfos << attachment->getName() << " visible" << llendl; + LL_INFOS() << attachment->getName() << " visible" << LL_ENDL; } else { - llinfos << attachment->getName() << " not visible at " << mDrawable->getWorldPosition() << " and radius " << mDrawable->getRadius() << llendl; + LL_INFOS() << attachment->getName() << " not visible at " << mDrawable->getWorldPosition() << " and radius " << mDrawable->getRadius() << LL_ENDL; } } } @@ -4312,17 +5277,11 @@ void LLVOAvatar::updateVisibility() } else { - if (mMeshValid && mMeshInvisibleTime.getElapsedTimeF32() > TIME_BEFORE_MESH_CLEANUP) + if (mMeshValid && + (isControlAvatar() || mMeshInvisibleTime.getElapsedTimeF32() > TIME_BEFORE_MESH_CLEANUP)) { releaseMeshData(); } - // this breaks off-screen chat bubbles - //if (mNameText) - //{ - // mNameText->markDead(); - // mNameText = NULL; - // sNumVisibleChatBubbles--; - //} } mVisible = visible; @@ -4350,6 +5309,11 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass) return num_indices; } + if (mDrawable.isNull()) + { + return num_indices; + } + LLFace* face = mDrawable->getFace(0); bool needs_rebuild = !face || !face->getVertexBuffer() || mDrawable->isState(LLDrawable::REBUILD_GEOMETRY); @@ -4437,19 +5401,19 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass) } else { - llinfos << "Avatar " << this << " in render" << llendl; + LL_INFOS() << "Avatar " << this << " in render" << LL_ENDL; } if (!mIsBuilt) { - llinfos << "Not built!" << llendl; + LL_INFOS() << "Not built!" << LL_ENDL; } else if (!gAgent.needsRenderAvatar()) { - llinfos << "Doesn't need avatar render!" << llendl; + LL_INFOS() << "Doesn't need avatar render!" << LL_ENDL; } else { - llinfos << "Rendering!" << llendl; + LL_INFOS() << "Rendering!" << LL_ENDL; } } @@ -4510,7 +5474,7 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass) { bool is_muted = LLPipeline::sImpostorRender && isVisuallyMuted(); //Disable masking and also disable alpha in LLViewerJoint::render const bool should_alpha_mask = !is_muted && shouldAlphaMask(); - LLGLState test(GL_ALPHA_TEST, should_alpha_mask); + LLGLState test(should_alpha_mask); if (should_alpha_mask && !LLGLSLShader::sNoFixedFunction) { @@ -4522,7 +5486,7 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass) { if (!isSelf() || gAgent.needsRenderHead() || LLPipeline::sShadowRender) { - if (isTextureVisible(TEX_HEAD_BAKED) || mIsDummy) + if (isTextureVisible(TEX_HEAD_BAKED) || isUIAvatar()) { LLViewerJoint* head_mesh = getViewerJoint(MESH_ID_HEAD); if (head_mesh) @@ -4532,7 +5496,7 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass) first_pass = FALSE; } } - if (isTextureVisible(TEX_UPPER_BAKED) || mIsDummy) + if (isTextureVisible(TEX_UPPER_BAKED) || isUIAvatar()) { LLViewerJoint* upper_mesh = getViewerJoint(MESH_ID_UPPER_BODY); if (upper_mesh) @@ -4542,7 +5506,7 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass) first_pass = FALSE; } - if (isTextureVisible(TEX_LOWER_BAKED) || mIsDummy) + if (isTextureVisible(TEX_LOWER_BAKED) || isUIAvatar()) { LLViewerJoint* lower_mesh = getViewerJoint(MESH_ID_LOWER_BODY); if (lower_mesh) @@ -4560,17 +5524,13 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass) if (!LLDrawPoolAvatar::sSkipTransparent || LLPipeline::sImpostorRender) { - LLGLState blend(GL_BLEND, !mIsDummy); - LLGLState test(GL_ALPHA_TEST, !mIsDummy); + LLGLState blend(!mIsDummy); + LLGLState test(!mIsDummy); num_indices += renderTransparent(first_pass); } } - - LLViewerJointMesh::sRenderPass = AVATAR_RENDER_PASS_SINGLE; - - //llinfos << "Avatar render: " << render_timer.getElapsedTimeF32() << llendl; - //render_stat.addValue(render_timer.getElapsedTimeF32()*1000.f); + LLViewerJointMesh::sRenderPass = AVATAR_RENDER_PASS_SINGLE; return num_indices; } @@ -4578,7 +5538,7 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass) U32 LLVOAvatar::renderTransparent(BOOL first_pass) { U32 num_indices = 0; - if( isWearingWearableType( LLWearableType::WT_SKIRT ) && (mIsDummy || isTextureVisible(TEX_SKIRT_BAKED)) ) + if( isWearingWearableType( LLWearableType::WT_SKIRT ) && (isUIAvatar() || isTextureVisible(TEX_SKIRT_BAKED)) ) { gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.25f); LLViewerJoint* skirt_mesh = getViewerJoint(MESH_ID_SKIRT); @@ -4606,10 +5566,19 @@ U32 LLVOAvatar::renderTransparent(BOOL first_pass) } first_pass = FALSE; } - // Can't test for baked hair being defined, since that won't always be the case (not all viewers send baked hair) - // TODO: 1.25 will be able to switch this logic back to calling isTextureVisible(); - if ((getImage(TEX_HAIR_BAKED, 0) && - getImage(TEX_HAIR_BAKED, 0)->getID() != IMG_INVISIBLE) || LLDrawPoolAlpha::sShowDebugAlpha) + bool show_hair = false; + if (isControlAvatar()) + { + show_hair = isTextureVisible(TEX_HAIR_BAKED); + } + else + { + // Can't test for baked hair being defined, since that won't always be the case (not all viewers send baked hair) + // TODO: 1.25 will be able to switch this logic back to calling isTextureVisible(); + auto image = getImage(TEX_HAIR_BAKED, 0); + show_hair = LLDrawPoolAlpha::sShowDebugAlpha || (image && image->getID() != IMG_INVISIBLE); + } + if (show_hair) { LLViewerJoint* hair_mesh = getViewerJoint(MESH_ID_HAIR); if (hair_mesh) @@ -4650,14 +5619,14 @@ U32 LLVOAvatar::renderRigid() } const bool should_alpha_mask = shouldAlphaMask(); - LLGLState test(GL_ALPHA_TEST, should_alpha_mask); + LLGLState test(should_alpha_mask); if (should_alpha_mask && !LLGLSLShader::sNoFixedFunction) { gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f); } - if (isTextureVisible(TEX_EYES_BAKED) || mIsDummy) + if (isTextureVisible(TEX_EYES_BAKED) || isUIAvatar()) { LLViewerJoint* eyeball_left = getViewerJoint(MESH_ID_EYEBALL_LEFT); LLViewerJoint* eyeball_right = getViewerJoint(MESH_ID_EYEBALL_RIGHT); @@ -4717,7 +5686,7 @@ U32 LLVOAvatar::renderRigid() LLGLDepthTest test(GL_TRUE, GL_FALSE); //render foot shadows - LLGLEnable blend(GL_BLEND); + LLGLEnable blend; gGL.getTexUnit(0)->bind(mShadowImagep.get(), TRUE); gGL.diffuseColor4fv(mShadow0Facep->getRenderColor().mV); mShadow0Facep->renderIndexed(foot_mask); @@ -4743,31 +5712,31 @@ U32 LLVOAvatar::renderImpostor(LLColor4U color, S32 diffuse_channel) left *= mImpostorDim.mV[0]; up *= mImpostorDim.mV[1]; - LLGLEnable test(GL_ALPHA_TEST); + LLGLEnable test; gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.f); gGL.color4ubv(color.mV); gGL.getTexUnit(diffuse_channel)->bind(&mImpostor); - gGL.begin(LLRender::QUADS); + gGL.begin(LLRender::TRIANGLE_STRIP); gGL.texCoord2f(0,0); gGL.vertex3fv((pos+left-up).mV); gGL.texCoord2f(1,0); gGL.vertex3fv((pos-left-up).mV); + gGL.texCoord2f(0, 1); + gGL.vertex3fv((pos + left + up).mV); gGL.texCoord2f(1,1); gGL.vertex3fv((pos-left+up).mV); - gGL.texCoord2f(0,1); - gGL.vertex3fv((pos+left+up).mV); gGL.end(); gGL.flush(); return 6; } -bool LLVOAvatar::allTexturesCompletelyDownloaded(std::set& ids) const +bool LLVOAvatar::allTexturesCompletelyDownloaded(uuid_set_t& ids) const { - for (std::set::const_iterator it = ids.begin(); it != ids.end(); ++it) + for (auto it = ids.begin(); it != ids.end(); ++it) { - LLViewerFetchedTexture *imagep = gTextureList.findImage(*it); + LLViewerFetchedTexture *imagep = gTextureList.findImage(*it, TEX_LIST_STANDARD); if (imagep && imagep->getDiscardLevel()!=0) { return false; @@ -4778,14 +5747,14 @@ bool LLVOAvatar::allTexturesCompletelyDownloaded(std::set& ids) const bool LLVOAvatar::allLocalTexturesCompletelyDownloaded() const { - std::set local_ids; + uuid_set_t local_ids; collectLocalTextureUUIDs(local_ids); return allTexturesCompletelyDownloaded(local_ids); } bool LLVOAvatar::allBakedTexturesCompletelyDownloaded() const { - std::set baked_ids; + uuid_set_t baked_ids; collectBakedTextureUUIDs(baked_ids); return allTexturesCompletelyDownloaded(baked_ids); } @@ -4797,11 +5766,11 @@ void LLVOAvatar::bakedTextureOriginCounts(S32 &sb_count, // server-bake, has ori { sb_count = host_count = both_count = neither_count = 0; - std::set baked_ids; + uuid_set_t baked_ids; collectBakedTextureUUIDs(baked_ids); - for (std::set::const_iterator it = baked_ids.begin(); it != baked_ids.end(); ++it) + for (auto it = baked_ids.begin(); it != baked_ids.end(); ++it) { - LLViewerFetchedTexture *imagep = gTextureList.findImage(*it); + LLViewerFetchedTexture *imagep = gTextureList.findImage(*it, TEX_LIST_STANDARD); bool has_url = false, has_host = false; if (!imagep->getUrl().empty()) { @@ -4821,12 +5790,12 @@ void LLVOAvatar::bakedTextureOriginCounts(S32 &sb_count, // server-bake, has ori std::string LLVOAvatar::bakedTextureOriginInfo() { std::string result; - - std::set baked_ids; + + uuid_set_t baked_ids; collectBakedTextureUUIDs(baked_ids); - for (std::set::const_iterator it = baked_ids.begin(); it != baked_ids.end(); ++it) + for (auto it = baked_ids.begin(); it != baked_ids.end(); ++it) { - LLViewerFetchedTexture *imagep = gTextureList.findImage(*it); + LLViewerFetchedTexture *imagep = gTextureList.findImage(*it, TEX_LIST_STANDARD); bool has_url = false, has_host = false; if (!imagep->getUrl().empty()) { @@ -4836,20 +5805,26 @@ std::string LLVOAvatar::bakedTextureOriginInfo() { has_host = true; } - if (has_url && !has_host) result += "u"; // server-bake texture with url - else if (has_host && !has_url) result += "h"; // old-style texture on sim - else if (has_host && has_url) result += "?"; // both origins? - else if (!has_host && !has_url) result += "n"; // no origin? + S32 discard = imagep->getDiscardLevel(); + if (has_url && !has_host) result += discard ? "u" : "U"; // server-bake texture with url + else if (has_host && !has_url) result += discard ? "h" : "H"; // old-style texture on sim + else if (has_host && has_url) result += discard ? "x" : "X"; // both origins? + else if (!has_host && !has_url) result += discard ? "n" : "N"; // no origin? + if (discard != 0) + { + result += llformat("(%d/%d)",discard,imagep->getDesiredDiscardLevel()); + } } + return result; } -S32 LLVOAvatar::totalTextureMemForUUIDS(std::set& ids) +S32Bytes LLVOAvatar::totalTextureMemForUUIDS(uuid_set_t& ids) { - S32 result = 0; - for (std::set::const_iterator it = ids.begin(); it != ids.end(); ++it) + S32Bytes result(0); + for (auto it = ids.begin(); it != ids.end(); ++it) { - LLViewerFetchedTexture *imagep = gTextureList.findImage(*it); + LLViewerFetchedTexture *imagep = gTextureList.findImage(*it, TEX_LIST_STANDARD); if (imagep) { result += imagep->getTextureMemory(); @@ -4858,7 +5833,7 @@ S32 LLVOAvatar::totalTextureMemForUUIDS(std::set& ids) return result; } -void LLVOAvatar::collectLocalTextureUUIDs(std::set& ids) const +void LLVOAvatar::collectLocalTextureUUIDs(uuid_set_t& ids) const { for (U32 texture_index = 0; texture_index < getNumTEs(); texture_index++) { @@ -4872,7 +5847,7 @@ void LLVOAvatar::collectLocalTextureUUIDs(std::set& ids) const if (imagep) { const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = LLAvatarAppearanceDictionary::getInstance()->getTexture((ETextureIndex)texture_index); - if (texture_dict->mIsLocalTexture) + if (texture_dict && texture_dict->mIsLocalTexture) { ids.insert(imagep->getID()); } @@ -4884,7 +5859,7 @@ void LLVOAvatar::collectLocalTextureUUIDs(std::set& ids) const ids.erase(IMG_INVISIBLE); } -void LLVOAvatar::collectBakedTextureUUIDs(std::set& ids) const +void LLVOAvatar::collectBakedTextureUUIDs(uuid_set_t& ids) const { for (U32 texture_index = 0; texture_index < getNumTEs(); texture_index++) { @@ -4903,7 +5878,7 @@ void LLVOAvatar::collectBakedTextureUUIDs(std::set& ids) const ids.erase(IMG_INVISIBLE); } -void LLVOAvatar::collectTextureUUIDs(std::set& ids) +void LLVOAvatar::collectTextureUUIDs(uuid_set_t& ids) { collectLocalTextureUUIDs(ids); collectBakedTextureUUIDs(ids); @@ -4911,33 +5886,33 @@ void LLVOAvatar::collectTextureUUIDs(std::set& ids) void LLVOAvatar::releaseOldTextures() { - S32 current_texture_mem = 0; + S32Bytes current_texture_mem; // Any textures that we used to be using but are no longer using should no longer be flagged as "NO_DELETE" - std::set baked_texture_ids; + uuid_set_t baked_texture_ids; collectBakedTextureUUIDs(baked_texture_ids); - S32 new_baked_mem = totalTextureMemForUUIDS(baked_texture_ids); + S32Bytes new_baked_mem = totalTextureMemForUUIDS(baked_texture_ids); - std::set local_texture_ids; + uuid_set_t local_texture_ids; collectLocalTextureUUIDs(local_texture_ids); //S32 new_local_mem = totalTextureMemForUUIDS(local_texture_ids); - std::set new_texture_ids; + uuid_set_t new_texture_ids; new_texture_ids.insert(baked_texture_ids.begin(),baked_texture_ids.end()); new_texture_ids.insert(local_texture_ids.begin(),local_texture_ids.end()); - S32 new_total_mem = totalTextureMemForUUIDS(new_texture_ids); + S32Bytes new_total_mem = totalTextureMemForUUIDS(new_texture_ids); //S32 old_total_mem = totalTextureMemForUUIDS(mTextureIDs); - //LL_DEBUGS("Avatar") << getFullname() << " old_total_mem: " << old_total_mem << " new_total_mem (L/B): " << new_total_mem << " (" << new_local_mem <<", " << new_baked_mem << ")" << llendl; + //LL_DEBUGS("Avatar") << getFullname() << " old_total_mem: " << old_total_mem << " new_total_mem (L/B): " << new_total_mem << " (" << new_local_mem <<", " << new_baked_mem << ")" << LL_ENDL; if (!isSelf() && new_total_mem > new_baked_mem) { - llwarns << "extra local textures stored for non-self av" << llendl; + LL_WARNS() << "extra local textures stored for non-self av" << LL_ENDL; } - for (std::set::iterator it = mTextureIDs.begin(); it != mTextureIDs.end(); ++it) + for (auto it = mTextureIDs.begin(); it != mTextureIDs.end(); ++it) { if (new_texture_ids.find(*it) == new_texture_ids.end()) { - LLViewerFetchedTexture *imagep = gTextureList.findImage(*it); + LLViewerFetchedTexture *imagep = gTextureList.findImage(*it, TEX_LIST_STANDARD); if (imagep) { current_texture_mem += imagep->getTextureMemory(); @@ -4959,13 +5934,15 @@ void LLVOAvatar::releaseOldTextures() mTextureIDs = new_texture_ids; } +static LLFastTimer::DeclareTimer FTM_TEXTURE_UPDATE("Update Textures"); void LLVOAvatar::updateTextures() { + LL_RECORD_BLOCK_TIME(FTM_TEXTURE_UPDATE); releaseOldTextures(); BOOL render_avatar = TRUE; - if (mIsDummy || gNoRender) + if (mIsDummy) { return; } @@ -4985,6 +5962,7 @@ void LLVOAvatar::updateTextures() } std::vector layer_baked; + // GL NOT ACTIVE HERE - *TODO for (U32 i = 0; i < mBakedTextureDatas.size(); i++) { layer_baked.push_back(isTextureDefined(mBakedTextureDatas[i].mTextureIndex)); @@ -5018,7 +5996,7 @@ void LLVOAvatar::updateTextures() } else { - llwarns << "getTE( " << texture_index << " ) returned 0" <getTexture((ETextureIndex)texture_index); - const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex; - if (texture_dict->mIsLocalTexture) + const EBakedTextureIndex baked_index = texture_dict ? texture_dict->mBakedTextureIndex : EBakedTextureIndex::BAKED_NUM_INDICES; + if (texture_dict && texture_dict->mIsLocalTexture) { addLocalTextureStats((ETextureIndex)texture_index, imagep, texel_area_ratio, render_avatar, mBakedTextureDatas[baked_index].mIsUsed); } @@ -5049,7 +6027,7 @@ void LLVOAvatar::updateTextures() LL_WARNS_ONCE("Texture") << "LLVOAvatar::updateTextures No host for texture " << imagep->getID() << " for avatar " << (isSelf() ? "" : getID().asString()) - << " on host " << getRegion()->getHost() << llendl; + << " on host " << getRegion()->getHost() << LL_ENDL; } addBakedTextureStats( imagep, mPixelArea, texel_area_ratio, boost_level ); @@ -5071,7 +6049,7 @@ void LLVOAvatar::addLocalTextureStats( ETextureIndex idx, LLViewerFetchedTexture } const S32 MAX_TEXTURE_UPDATE_INTERVAL = 64 ; //need to call updateTextures() at least every 32 frames. -const S32 MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL = S32_MAX ; //frames +const S32 MAX_TEXTURE_VIRTUAL_SIZE_RESET_INTERVAL = S32_MAX ; //frames void LLVOAvatar::checkTextureLoading() { static const F32 MAX_INVISIBLE_WAITING_TIME = 15.f ; //seconds @@ -5134,7 +6112,7 @@ const F32 ADDITIONAL_PRI = 0.5f; void LLVOAvatar::addBakedTextureStats( LLViewerFetchedTexture* imagep, F32 pixel_area, F32 texel_area_ratio, S32 boost_level) { //Note: - //if this function is not called for the last MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL frames, + //if this function is not called for the last MAX_TEXTURE_VIRTUAL_SIZE_RESET_INTERVAL frames, //the texture pipeline will stop fetching this texture. imagep->resetTextureStats(); @@ -5142,7 +6120,7 @@ void LLVOAvatar::addBakedTextureStats( LLViewerFetchedTexture* imagep, F32 pixel // Once server messaging is in place, we should call setCanUseHTTP(false) for old style // appearance requests imagep->setCanUseHTTP(true); - imagep->setMaxVirtualSizeResetInterval(MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL); + imagep->setMaxVirtualSizeResetInterval(MAX_TEXTURE_VIRTUAL_SIZE_RESET_INTERVAL); imagep->resetMaxVirtualSizeResetCounter() ; mMaxPixelArea = llmax(pixel_area, mMaxPixelArea); @@ -5189,18 +6167,19 @@ const std::string LLVOAvatar::getImageURL(const U8 te, const LLUUID &uuid) std::string url = ""; if (isUsingServerBakes()) { - if (gSavedSettings.getString("AgentAppearanceServiceURL").empty()) + const std::string& appearance_service_url = LLAppearanceMgr::instance().getAppearanceServiceURL(); + if (appearance_service_url.empty()) { // Probably a server-side issue if we get here: - llwarns << "AgentAppearanceServiceURL not set - Baked texture requests will fail" << llendl; + LL_WARNS() << "AgentAppearanceServiceURL not set - Baked texture requests will fail" << LL_ENDL; return url; } const LLAvatarAppearanceDictionary::TextureEntry* texture_entry = LLAvatarAppearanceDictionary::getInstance()->getTexture((ETextureIndex)te); if (texture_entry != NULL) { - url = gSavedSettings.getString("AgentAppearanceServiceURL") + "texture/" + getID().asString() + "/" + texture_entry->mDefaultImageName + "/" + uuid.asString(); - //llinfos << "baked texture url: " << url << llendl; + url = appearance_service_url + "texture/" + getID().asString() + "/" + texture_entry->mDefaultImageName + "/" + uuid.asString(); + //LL_INFOS() << "baked texture url: " << url << LL_ENDL; } } return url; @@ -5250,7 +6229,7 @@ void LLVOAvatar::resolveHeightGlobal(const LLVector3d &inPos, LLVector3d &outPos LLVector3 relativePos = gAgent.getPosAgentFromGlobal(outPos) - obj->getPositionAgent(); LLVector3 linearComponent = angularVelocity % relativePos; -// llinfos << "Linear Component of Rotation Velocity " << linearComponent << llendl; +// LL_INFOS() << "Linear Component of Rotation Velocity " << linearComponent << LL_ENDL; mStepObjectVelocity = obj->getVelocity() + linearComponent; } } @@ -5275,17 +6254,18 @@ const LLUUID& LLVOAvatar::getStepSound() const //----------------------------------------------------------------------------- void LLVOAvatar::processAnimationStateChanges() { - if (gNoRender) return; - if ( isAnyAnimationSignaled(AGENT_WALK_ANIMS, NUM_AGENT_WALK_ANIMS) ) { startMotion(ANIM_AGENT_WALK_ADJUST); stopMotion(ANIM_AGENT_FLY_ADJUST); } - else if (mInAir && !mIsSitting) + else if (mInAir && !isSitting()) { stopMotion(ANIM_AGENT_WALK_ADJUST); - startMotion(ANIM_AGENT_FLY_ADJUST); + if (mEnableDefaultMotions) + { + startMotion(ANIM_AGENT_FLY_ADJUST); + } } else { @@ -5295,16 +6275,23 @@ void LLVOAvatar::processAnimationStateChanges() if ( isAnyAnimationSignaled(AGENT_GUN_AIM_ANIMS, NUM_AGENT_GUN_AIM_ANIMS) ) { - startMotion(ANIM_AGENT_TARGET); + if (mEnableDefaultMotions) + { + startMotion(ANIM_AGENT_TARGET); + } stopMotion(ANIM_AGENT_BODY_NOISE); } else { stopMotion(ANIM_AGENT_TARGET); - startMotion(ANIM_AGENT_BODY_NOISE); + if (mEnableDefaultMotions) + { + startMotion(ANIM_AGENT_BODY_NOISE); + } } // clear all current animations + auto ao = isSelf() ? AOSystem::getIfExists() : nullptr; // AO is only for ME AnimIterator anim_it; for (anim_it = mPlayingAnimations.begin(); anim_it != mPlayingAnimations.end();) { @@ -5313,20 +6300,13 @@ void LLVOAvatar::processAnimationStateChanges() // playing, but not signaled, so stop if (found_anim == mSignaledAnimations.end()) { - - if (isSelf()) - { - if ((gSavedSettings.getBOOL("AOEnabled")) && LLFloaterAO::stopMotion(anim_it->first, FALSE)) // if the AO replaced this anim serverside then stop it serverside - { -// return TRUE; //no local stop needed - } - } + if (ao) ao->stopMotion(anim_it->first); // if the AO replaced this anim serverside then stop it serverside processSingleAnimationStateChange(anim_it->first, FALSE); // - LLFloaterExploreAnimations::stopAnim(getID(), anim_it->first); + LLFloaterExploreAnimations::processAnim(getID(), anim_it->first, false); // - mPlayingAnimations.erase(anim_it++); + anim_it = mPlayingAnimations.erase(anim_it); continue; } @@ -5342,14 +6322,11 @@ void LLVOAvatar::processAnimationStateChanges() if (found_anim == mPlayingAnimations.end() || found_anim->second != anim_it->second) { // - LLFloaterExploreAnimations::startAnim(getID(), anim_it->first); + LLFloaterExploreAnimations::processAnim(getID(), anim_it->first, true); // if (processSingleAnimationStateChange(anim_it->first, TRUE)) { - if (isSelf() && gSavedSettings.getBOOL("AOEnabled")) // AO is only for ME - { - LLFloaterAO::startMotion(anim_it->first, 0,FALSE); // AO overrides the anim if needed - } + if (ao) ao->startMotion(anim_it->first); // AO overrides the anim if needed mPlayingAnimations[anim_it->first] = anim_it->second; ++anim_it; @@ -5387,12 +6364,17 @@ void LLVOAvatar::processAnimationStateChanges() //----------------------------------------------------------------------------- BOOL LLVOAvatar::processSingleAnimationStateChange( const LLUUID& anim_id, BOOL start ) { + // SL-402, SL-427 - we need to update body size often enough to + // keep appearances in sync, but not so often that animations + // cause constant jiggling of the body or camera. Possible + // compromise is to do it on animation changes: + computeBodySize(); + BOOL result = FALSE; if ( start ) // start animation { static LLCachedControl play_typing_sound("PlayTypingSound"); - static LLCachedControl announce_snapshots("AnnounceSnapshots"); if (anim_id == ANIM_AGENT_TYPE && play_typing_sound) { if (gAudiop) @@ -5422,14 +6404,15 @@ BOOL LLVOAvatar::processSingleAnimationStateChange( const LLUUID& anim_id, BOOL else if(anim_id == ANIM_AGENT_SNAPSHOT) { mIdleTimer.reset(); // Snapshot, not idle + static LLCachedControl announce_snapshots("AnnounceSnapshots"); if (announce_snapshots) { std::string name; - LLAvatarNameCache::getPNSName(mID, name); + LLAvatarNameCache::getNSName(mID, name); LLChat chat; chat.mFromName = name; - chat.mText = name + " " + LLTrans::getString("took_a_snapshot") + "."; - chat.mURL = llformat("secondlife:///app/agent/%s/about",mID.asString().c_str()); + chat.mText = name + ' ' + LLTrans::getString("took_a_snapshot") + '.'; + chat.mURL = LLAvatarActions::getSLURL(mID); chat.mSourceType = CHAT_SOURCE_SYSTEM; LLFloaterChat::addChat(chat); } @@ -5442,7 +6425,7 @@ BOOL LLVOAvatar::processSingleAnimationStateChange( const LLUUID& anim_id, BOOL } else { - llwarns << "Failed to start motion!" << llendl; + LL_WARNS() << "Failed to start motion!" << LL_ENDL; } } else //stop animation @@ -5451,6 +6434,12 @@ BOOL LLVOAvatar::processSingleAnimationStateChange( const LLUUID& anim_id, BOOL { sitDown(FALSE); } + if ((anim_id == ANIM_AGENT_DO_NOT_DISTURB) && gAgent.isDoNotDisturb()) + { + // re-assert DND tag animation + gAgent.sendAnimationRequest(ANIM_AGENT_DO_NOT_DISTURB, ANIM_REQUEST_START); + return result; + } stopMotion(anim_id); result = TRUE; } @@ -5508,8 +6497,7 @@ std::string LLVOAvatar::getIdleTime(bool is_away, bool is_busy, bool is_appearan args["[MINUTES]"]=(LLSD::Integer)minutes; return LLTrans::getString("AvatarIdle", args); } - else - return std::string(); + return ""; } // Override selectively based on avatar sex and whether we're using new @@ -5555,6 +6543,11 @@ LLUUID LLVOAvatar::remapMotionID(const LLUUID& id) if (use_new_walk_run) result = ANIM_AGENT_RUN_NEW; } + // keeps in sync with setSex() related code (viewer controls sit's sex) + else if (id == ANIM_AGENT_SIT_FEMALE) + { + result = ANIM_AGENT_SIT; + } } @@ -5578,141 +6571,589 @@ BOOL LLVOAvatar::startMotion(const LLUUID& id, F32 time_offset) return TRUE; } - lldebugs << "motion requested " << id.asString() << " " << gAnimLibrary.animationName(id) << llendl; + LL_DEBUGS() << "motion requested " << id.asString() << " " << gAnimLibrary.animationName(id) << LL_ENDL; LLUUID remap_id = remapMotionID(id); if (remap_id != id) { - lldebugs << "motion resultant " << remap_id.asString() << " " << gAnimLibrary.animationName(remap_id) << llendl; + LL_DEBUGS() << "motion resultant " << remap_id.asString() << " " << gAnimLibrary.animationName(remap_id) << LL_ENDL; } if (isSelf() && remap_id == ANIM_AGENT_AWAY) { gAgent.setAFK(); } - - return LLCharacter::startMotion(remap_id, time_offset); + + return LLCharacter::startMotion(remap_id, time_offset); +} + +//----------------------------------------------------------------------------- +// stopMotion() +//----------------------------------------------------------------------------- +BOOL LLVOAvatar::stopMotion(const LLUUID& id, BOOL stop_immediate) +{ + LL_DEBUGS() << "motion requested " << id.asString() << " " << gAnimLibrary.animationName(id) << LL_ENDL; + + LLUUID remap_id = remapMotionID(id); + + if (remap_id != id) + { + LL_DEBUGS() << "motion resultant " << remap_id.asString() << " " << gAnimLibrary.animationName(remap_id) << LL_ENDL; + } + + if (isSelf()) + { + gAgent.onAnimStop(remap_id); + } + + return LLCharacter::stopMotion(remap_id, stop_immediate); +} + +//----------------------------------------------------------------------------- +// hasMotionFromSource() +//----------------------------------------------------------------------------- +// virtual +bool LLVOAvatar::hasMotionFromSource(const LLUUID& source_id) +{ + return false; +} + +//----------------------------------------------------------------------------- +// stopMotionFromSource() +//----------------------------------------------------------------------------- +// virtual +void LLVOAvatar::stopMotionFromSource(const LLUUID& source_id) +{ +} + +//----------------------------------------------------------------------------- +// addDebugText() +//----------------------------------------------------------------------------- +void LLVOAvatar::addDebugText(const std::string& text) +{ + mDebugText.append(1, '\n'); + mDebugText.append(text); +} + +//----------------------------------------------------------------------------- +// getID() +//----------------------------------------------------------------------------- +const LLUUID& LLVOAvatar::getID() const +{ + return mID; +} + +//----------------------------------------------------------------------------- +// getJoint() +//----------------------------------------------------------------------------- +// RN: avatar joints are multi-rooted to include screen-based attachments +LLJoint *LLVOAvatar::getJoint( const std::string &name ) +{ + joint_map_t::iterator iter = std::find_if(mJointMap.begin(), mJointMap.end(), [&name](joint_map_t::value_type &pair) { return strcmp(name.c_str(), pair.first) == 0; }); + + LLJoint* jointp = NULL; + + if (iter == mJointMap.end() || iter->second == NULL) + { //search for joint and cache found joint in lookup table + jointp = mRoot->findJoint(name); + joint_map_t::value_type entry; + strncpy(entry.first, name.c_str(), sizeof(entry.first)); + entry.second = jointp; + mJointMap.emplace_back(entry); + } + else + { //return cached pointer + jointp = iter->second; + } + + return jointp; +} + +LLJoint *LLVOAvatar::getJoint( S32 joint_num ) +{ + LLJoint *pJoint = NULL; + S32 collision_start = mNumBones; + S32 attachment_start = mNumBones + mCollisionVolumes.size(); + if (joint_num>=attachment_start) + { + // Attachment IDs start at 1 + S32 attachment_id = joint_num - attachment_start + 1; + attachment_map_t::iterator iter = mAttachmentPoints.find(attachment_id); + if (iter != mAttachmentPoints.end()) + { + pJoint = iter->second; + } + } + else if (joint_num>=collision_start) + { + S32 collision_id = joint_num-collision_start; + pJoint = mCollisionVolumes[collision_id]; + } + else if (joint_num>=0) + { + pJoint = mSkeleton[joint_num]; + } + llassert(!pJoint || pJoint->getJointNum() == joint_num); + return pJoint; +} + +//----------------------------------------------------------------------------- +// getRiggedMeshID +// +// If viewer object is a rigged mesh, set the mesh id and return true. +// Otherwise, null out the id and return false. +//----------------------------------------------------------------------------- +// static +bool LLVOAvatar::getRiggedMeshID(LLViewerObject* pVO, LLUUID& mesh_id) +{ + mesh_id.setNull(); + + //If a VO has a skin that we'll reset the joint positions to their default + if ( pVO && pVO->mDrawable ) + { + LLVOVolume* pVObj = pVO->mDrawable->getVOVolume(); + if ( pVObj ) + { + const LLMeshSkinInfo* pSkinData = pVObj->getSkinInfo(); + if (pSkinData + && pSkinData->mJointNames.size() > JOINT_COUNT_REQUIRED_FOR_FULLRIG // full rig + && pSkinData->mAlternateBindMatrix.size() > 0 ) + { + mesh_id = pSkinData->mMeshID; + return true; + } + } + } + return false; +} + +bool LLVOAvatar::jointIsRiggedTo(const LLJoint *joint) const +{ + if (joint) + { + const LLJointRiggingInfoTab& tab = mJointRiggingInfoTab; + S32 joint_num = joint->getJointNum(); + if (joint_num < tab.size() && tab[joint_num].isRiggedTo()) + { + return true; + } + } + return false; +} + +void LLVOAvatar::clearAttachmentOverrides() +{ + for (S32 i=0; iclearAttachmentPosOverrides(); + pJoint->clearAttachmentScaleOverrides(); + } + } + + if (mPelvisFixups.count()>0) + { + mPelvisFixups.clear(); + LLJoint* pJointPelvis = getJoint("mPelvis"); + if (pJointPelvis) + { + pJointPelvis->setPosition( LLVector3( 0.0f, 0.0f, 0.0f) ); + } + postPelvisSetRecalc(); + } + + mActiveOverrideMeshes.clear(); + onActiveOverrideMeshesChanged(); +} + +//----------------------------------------------------------------------------- +// rebuildAttachmentOverrides +//----------------------------------------------------------------------------- +void LLVOAvatar::rebuildAttachmentOverrides() +{ + clearAttachmentOverrides(); + + // Handle the case that we're resetting the skeleton of an animated object. + LLControlAvatar *control_av = asControlAvatar(); + if (control_av) + { + LLVOVolume *volp = control_av->mRootVolp; + if (volp) + { + LL_DEBUGS("Avatar") << volp->getID() << " adding attachment overrides for root vol, prim count " + << (S32) (1+volp->numChildren()) << LL_ENDL; + addAttachmentOverridesForObject(volp); + } + } + + // Attached objects +#if SLOW_ATTACHMENT_LIST + for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); + ++iter) + { + LLViewerJointAttachment *attachment_pt = (*iter).second; + if (attachment_pt) + { + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator at_it = attachment_pt->mAttachedObjects.begin(); + at_it != attachment_pt->mAttachedObjects.end(); ++at_it) + { + LLViewerObject *vo = *at_it; +#else + for(auto& iter : mAttachedObjectsVector) + {{{ + LLViewerObject *vo = iter.first; +#endif + // Attached animated objects affect joints in their control + // avs, not the avs to which they are attached. + if (vo && !vo->isAnimatedObject()) + { + addAttachmentOverridesForObject(vo); + } + } + } + } +} + +//----------------------------------------------------------------------------- +// updateAttachmentOverrides +// +// This is intended to give the same results as +// rebuildAttachmentOverrides(), while avoiding redundant work. +// ----------------------------------------------------------------------------- +void LLVOAvatar::updateAttachmentOverrides() +{ + LL_DEBUGS("AnimatedObjects") << "updating" << LL_ENDL; + + uuid_set_t meshes_seen; + + // Handle the case that we're updating the skeleton of an animated object. + LLControlAvatar *control_av = asControlAvatar(); + if (control_av) + { + LLVOVolume *volp = control_av->mRootVolp; + if (volp) + { + LL_DEBUGS("Avatar") << volp->getID() << " adding attachment overrides for root vol, prim count " + << (S32) (1+volp->numChildren()) << LL_ENDL; + addAttachmentOverridesForObject(volp, &meshes_seen); + } + } + + // Attached objects +#if SLOW_ATTACHMENT_LIST + for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); + ++iter) + { + LLViewerJointAttachment *attachment_pt = (*iter).second; + if (attachment_pt) + { + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator at_it = attachment_pt->mAttachedObjects.begin(); + at_it != attachment_pt->mAttachedObjects.end(); ++at_it) + { + LLViewerObject *vo = *at_it; +#else + for(auto& iter : mAttachedObjectsVector) + {{{ + LLViewerObject *vo = iter.first; +#endif + // Attached animated objects affect joints in their control + // avs, not the avs to which they are attached. + if (!vo->isAnimatedObject()) + { + addAttachmentOverridesForObject(vo, &meshes_seen); + } + } + } + } + // Remove meshes that are no longer present on the skeleton + + // have to work with a copy because removeAttachmentOverrides() will change mActiveOverrideMeshes. + uuid_set_t active_override_meshes = mActiveOverrideMeshes; + for (auto it = active_override_meshes.begin(); it != active_override_meshes.end(); ++it) + { + if (meshes_seen.find(*it) == meshes_seen.end()) + { + removeAttachmentOverridesForObject(*it); + } + } +} +// addAttachmentPosOverridesForObject +//----------------------------------------------------------------------------- +void LLVOAvatar::addAttachmentOverridesForObject(LLViewerObject *vo, uuid_set_t* meshes_seen, bool recursive) +{ + if (vo->getAvatar() != this && vo->getAvatarAncestor() != this) + { + LL_WARNS("Avatar") << "called with invalid avatar" << LL_ENDL; + return; + } + + LL_DEBUGS("AnimatedObjects") << "adding" << LL_ENDL; + + // Process all children + if (recursive) + { + LLViewerObject::const_child_list_t& children = vo->getChildren(); + for (LLViewerObject::const_child_list_t::const_iterator it = children.begin(); + it != children.end(); ++it) + { + LLViewerObject *childp = *it; + addAttachmentOverridesForObject(childp, meshes_seen, true); + } + } + + LLVOVolume *vobj = vo->asVolume(); + if (vobj && vobj->isRiggedMesh() && + vobj->getVolume() && vobj->getVolume()->isMeshAssetLoaded() && gMeshRepo.meshRezEnabled()) + { + bool pelvisGotSet = false; + const LLMeshSkinInfo* pSkinData = vobj->getSkinInfo(); + const U32 bindCnt = pSkinData->mAlternateBindMatrix.size(); + const U32 jointCnt = pSkinData->mJointNames.size(); + if ((bindCnt > 0) && (bindCnt != jointCnt)) + { + LL_WARNS_ONCE() << "invalid mesh, bindCnt " << bindCnt << "!= jointCnt " << jointCnt << ", joint overrides will be ignored." << LL_ENDL; + } + if ((bindCnt > 0) && (bindCnt == jointCnt)) + { + const F32 pelvisZOffset = pSkinData->mPelvisOffset; + const LLUUID& mesh_id = pSkinData->mMeshID; + + if (meshes_seen) + { + meshes_seen->insert(mesh_id); + } + bool mesh_overrides_loaded = (mActiveOverrideMeshes.find(mesh_id) != mActiveOverrideMeshes.end()); + bool fullRig = (jointCnt>=JOINT_COUNT_REQUIRED_FOR_FULLRIG) ? true : false; + if ( fullRig && !mesh_overrides_loaded ) + { + for ( U32 i=0; imJointNames[i].c_str(); + LLJoint* pJoint = getJoint( lookingForJoint ); + if ( pJoint ) + { + const LLVector3& jointPos = pSkinData->mAlternateBindMatrix[i].getTranslation(); + if (pJoint->aboveJointPosThreshold(jointPos)) + { + bool override_changed; + pJoint->addAttachmentPosOverride( jointPos, mesh_id, avString(), override_changed ); + + if (override_changed) + { + //If joint is a pelvis then handle old/new pelvis to foot values + if ( lookingForJoint == "mPelvis" ) + { + pelvisGotSet = true; + } + } + if (pSkinData->mLockScaleIfJointPosition) + { + // Note that unlike positions, there's no threshold check here, + // just a lock at the default value. + pJoint->addAttachmentScaleOverride(pJoint->getDefaultScale(), mesh_id, avString()); + } + } + } + } + if (pelvisZOffset != 0.0F) + { + F32 pelvis_fixup_before; + bool has_fixup_before = hasPelvisFixup(pelvis_fixup_before); + addPelvisFixup( pelvisZOffset, mesh_id ); + F32 pelvis_fixup_after; + hasPelvisFixup(pelvis_fixup_after); // Don't have to check bool here because we just added it... + if (!has_fixup_before || (pelvis_fixup_before != pelvis_fixup_after)) + { + pelvisGotSet = true; + } + + } + mActiveOverrideMeshes.insert(mesh_id); + onActiveOverrideMeshesChanged(); + } + } + //Rebuild body data if we altered joints/pelvis + if (pelvisGotSet) + { + postPelvisSetRecalc(); + } + } } //----------------------------------------------------------------------------- -// stopMotion() +// getAttachmentOverrideNames //----------------------------------------------------------------------------- -BOOL LLVOAvatar::stopMotion(const LLUUID& id, BOOL stop_immediate) +void LLVOAvatar::getAttachmentOverrideNames(std::set& pos_names, std::set& scale_names) const { - lldebugs << "motion requested " << id.asString() << " " << gAnimLibrary.animationName(id) << llendl; + LLVector3 pos; + LLVector3 scale; + LLUUID mesh_id; - LLUUID remap_id = remapMotionID(id); - - if (remap_id != id) + // Bones + for (avatar_joint_list_t::const_iterator iter = mSkeleton.begin(); + iter != mSkeleton.end(); ++iter) { - lldebugs << "motion resultant " << remap_id.asString() << " " << gAnimLibrary.animationName(remap_id) << llendl; + const LLJoint* pJoint = (*iter); + if (pJoint && pJoint->hasAttachmentPosOverride(pos,mesh_id)) + { + pos_names.insert(pJoint->getName()); + } + if (pJoint && pJoint->hasAttachmentScaleOverride(scale,mesh_id)) + { + scale_names.insert(pJoint->getName()); + } } - if (isSelf()) + // Attachment points + for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); + ++iter) { - gAgent.onAnimStop(remap_id); - } - - return LLCharacter::stopMotion(remap_id, stop_immediate); -} - -//----------------------------------------------------------------------------- -// stopMotionFromSource() -//----------------------------------------------------------------------------- -// virtual -void LLVOAvatar::stopMotionFromSource(const LLUUID& source_id) -{ -} - -//----------------------------------------------------------------------------- -// addDebugText() -//----------------------------------------------------------------------------- -void LLVOAvatar::addDebugText(const std::string& text) -{ - mDebugText.append(1, '\n'); - mDebugText.append(text); -} + const LLViewerJointAttachment *attachment_pt = (*iter).second; + if (attachment_pt && attachment_pt->hasAttachmentPosOverride(pos,mesh_id)) + { + pos_names.insert(attachment_pt->getName()); + } + // Attachment points don't have scales. + } + +} + +//----------------------------------------------------------------------------- +// showAttachmentOverrides +//----------------------------------------------------------------------------- +void LLVOAvatar::showAttachmentOverrides(bool verbose) const +{ + std::set pos_names, scale_names; + getAttachmentOverrideNames(pos_names, scale_names); + if (pos_names.size()) + { + std::stringstream ss; + std::copy(pos_names.begin(), pos_names.end(), std::ostream_iterator(ss, ",")); + LL_INFOS() << getFullname() << " attachment positions defined for joints: " << ss.str() << "\n" << LL_ENDL; + } + else + { + LL_DEBUGS("Avatar") << getFullname() << " no attachment positions defined for any joints" << "\n" << LL_ENDL; + } + if (scale_names.size()) + { + std::stringstream ss; + std::copy(scale_names.begin(), scale_names.end(), std::ostream_iterator(ss, ",")); + LL_INFOS() << getFullname() << " attachment scales defined for joints: " << ss.str() << "\n" << LL_ENDL; + } + else + { + LL_INFOS() << getFullname() << " no attachment scales defined for any joints" << "\n" << LL_ENDL; + } + + if (!verbose) + { + return; + } + + LLVector3 pos, scale; + LLUUID mesh_id; + S32 count = 0; + + // Bones + for (avatar_joint_list_t::const_iterator iter = mSkeleton.begin(); + iter != mSkeleton.end(); ++iter) + { + const LLJoint* pJoint = (*iter); + if (pJoint && pJoint->hasAttachmentPosOverride(pos,mesh_id)) + { + pJoint->showAttachmentPosOverrides(getFullname()); + count++; + } + if (pJoint && pJoint->hasAttachmentScaleOverride(scale,mesh_id)) + { + pJoint->showAttachmentScaleOverrides(getFullname()); + count++; + } + } + + // Attachment points + for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); + ++iter) + { + const LLViewerJointAttachment *attachment_pt = (*iter).second; + if (attachment_pt && attachment_pt->hasAttachmentPosOverride(pos,mesh_id)) + { + attachment_pt->showAttachmentPosOverrides(getFullname()); + count++; + } + } -//----------------------------------------------------------------------------- -// getID() -//----------------------------------------------------------------------------- -const LLUUID& LLVOAvatar::getID() const -{ - return mID; + if (count) + { + LL_DEBUGS("Avatar") << avString() << " end of pos, scale overrides" << LL_ENDL; + LL_DEBUGS("Avatar") << "=================================" << LL_ENDL; + } } //----------------------------------------------------------------------------- -// getJoint() +// removeAttachmentOverridesForObject //----------------------------------------------------------------------------- -// RN: avatar joints are multi-rooted to include screen-based attachments -LLJoint *LLVOAvatar::getJoint( const std::string &name ) +void LLVOAvatar::removeAttachmentOverridesForObject(LLViewerObject *vo) { - joint_map_t::iterator iter = mJointMap.find(name); - - LLJoint* jointp = NULL; - - if (iter == mJointMap.end() || iter->second == NULL) - { //search for joint and cache found joint in lookup table - jointp = mRoot->findJoint(name); - mJointMap[name] = jointp; - } - else - { //return cached pointer - jointp = iter->second; + if (vo->getAvatar() != this && vo->getAvatarAncestor() != this) + { + LL_WARNS("Avatar") << "called with invalid avatar" << LL_ENDL; + return; } - - return jointp; -} - -//----------------------------------------------------------------------------- -// resetSpecificJointPosition -//----------------------------------------------------------------------------- -void LLVOAvatar::resetSpecificJointPosition( const std::string& name ) -{ - LLJoint* pJoint = mRoot->findJoint( name ); - - if ( pJoint && pJoint->doesJointNeedToBeReset() ) + + // Process all children + LLViewerObject::const_child_list_t& children = vo->getChildren(); + for (LLViewerObject::const_child_list_t::const_iterator it = children.begin(); + it != children.end(); ++it) { - pJoint->restoreOldXform(); - pJoint->setId( LLUUID::null ); - //If we're reseting the pelvis position make sure not to apply offset - if ( name == "mPelvis" ) - { - mHasPelvisOffset = false; - } + LLViewerObject *childp = *it; + removeAttachmentOverridesForObject(childp); } - else + + // Process self. + LLUUID mesh_id; + if (getRiggedMeshID(vo,mesh_id)) { - llinfos<<"Did not find "<< name.c_str()<doesJointNeedToBeReset() ) +void LLVOAvatar::removeAttachmentOverridesForObject(const LLUUID& mesh_id) +{ + LLJoint* pJointPelvis = getJoint("mPelvis"); + const std::string av_string = avString(); + for (S32 joint_num = 0; joint_num < LL_CHARACTER_MAX_ANIMATED_JOINTS; joint_num++) + { + LLJoint *pJoint = getJoint(joint_num); + if ( pJoint ) + { + bool dummy; // unused + pJoint->removeAttachmentPosOverride(mesh_id, av_string, dummy); + pJoint->removeAttachmentScaleOverride(mesh_id, av_string); + } + if ( pJoint && pJoint == pJointPelvis) { - pJoint->setId( LLUUID::null ); - //restore joints to default positions, however skip over the pelvis - // *TODO: How does this pointer check skip over pelvis? - if ( pJoint ) - { - pJoint->restoreOldXform(); - } - } - } - //make sure we don't apply the joint offset - mHasPelvisOffset = false; - mPelvisFixup = mLastPelvisFixup; - postPelvisSetRecalc(); + removePelvisFixup( mesh_id ); + // SL-315 + pJoint->setPosition( LLVector3( 0.0f, 0.0f, 0.0f) ); + } + } + + postPelvisSetRecalc(); + + mActiveOverrideMeshes.erase(mesh_id); + onActiveOverrideMeshesChanged(); } //----------------------------------------------------------------------------- // getCharacterPosition() @@ -5764,7 +7205,7 @@ void LLVOAvatar::getGround(const LLVector3 &in_pos_agent, LLVector3 &out_pos_age LLVector3d z_vec(0.0f, 0.0f, 1.0f); LLVector3d p0_global, p1_global; - if (gNoRender || mIsDummy) + if (isUIAvatar()) { outNorm.setVec(z_vec); out_pos_agent = in_pos_agent; @@ -5784,7 +7225,7 @@ void LLVOAvatar::getGround(const LLVector3 &in_pos_agent, LLVector3 &out_pos_age //----------------------------------------------------------------------------- F32 LLVOAvatar::getTimeDilation() { - return mTimeDilation; + return mRegionp ? mRegionp->getTimeDilation() : 1.f; } @@ -5793,7 +7234,7 @@ F32 LLVOAvatar::getTimeDilation() //----------------------------------------------------------------------------- F32 LLVOAvatar::getPixelArea() const { - if (mIsDummy) + if (isUIAvatar()) { return 100000.f; } @@ -5838,84 +7279,104 @@ BOOL LLVOAvatar::loadSkeletonNode () { return FALSE; } + + bool ignore_hud_joints = false; + initAttachmentPoints(ignore_hud_joints); + + return TRUE; +} - // ATTACHMENTS +//----------------------------------------------------------------------------- +// initAttachmentPoints(): creates attachment points if needed, sets state based on avatar_lad.xml. +//----------------------------------------------------------------------------- +void LLVOAvatar::initAttachmentPoints(bool ignore_hud_joints) +{ + LLAvatarXmlInfo::attachment_info_list_t::iterator iter; + for (iter = sAvatarXmlInfo->mAttachmentInfoList.begin(); + iter != sAvatarXmlInfo->mAttachmentInfoList.end(); + ++iter) { - LLAvatarXmlInfo::attachment_info_list_t::iterator iter; - for (iter = sAvatarXmlInfo->mAttachmentInfoList.begin(); - iter != sAvatarXmlInfo->mAttachmentInfoList.end(); - ++iter) + LLAvatarXmlInfo::LLAvatarAttachmentInfo *info = *iter; + if (info->mIsHUDAttachment && (!isSelf() || ignore_hud_joints)) { - LLAvatarXmlInfo::LLAvatarAttachmentInfo *info = *iter; - if (!isSelf() && info->mJointName == "mScreen") - { //don't process screen joint for other avatars - continue; - } + //don't process hud joint for other avatars, or when doing a skeleton reset. + continue; + } + + S32 attachmentID = info->mAttachmentID; + if (attachmentID < 1 || attachmentID > 255) + { + LL_WARNS() << "Attachment point out of range [1-255]: " << attachmentID << " on attachment point " << info->mName << LL_ENDL; + continue; + } - LLViewerJointAttachment* attachment = new LLViewerJointAttachment(); + LLViewerJointAttachment* attachment = NULL; + bool newly_created = false; + if (mAttachmentPoints.find(attachmentID) == mAttachmentPoints.end()) + { + attachment = new LLViewerJointAttachment(); + newly_created = true; + } + else + { + attachment = mAttachmentPoints[attachmentID]; + } - attachment->setName(info->mName); - LLJoint *parentJoint = getJoint(info->mJointName); - if (!parentJoint) + attachment->setName(info->mName); + LLJoint *parent_joint = getJoint(info->mJointName); + if (!parent_joint) + { + // If the intended parent for attachment point is unavailable, avatar_lad.xml is corrupt. + LL_WARNS() << "No parent joint by name " << info->mJointName << " found for attachment point " << info->mName << LL_ENDL; + if( newly_created ) { - llwarns << "No parent joint by name " << info->mJointName << " found for attachment point " << info->mName << llendl; delete attachment; - continue; - } - - if (info->mHasPosition) - { - attachment->setOriginalPosition(info->mPosition); } + continue; + } - if (info->mHasRotation) - { - LLQuaternion rotation; - rotation.setQuat(info->mRotationEuler.mV[VX] * DEG_TO_RAD, - info->mRotationEuler.mV[VY] * DEG_TO_RAD, - info->mRotationEuler.mV[VZ] * DEG_TO_RAD); - attachment->setRotation(rotation); - } + if (info->mHasPosition) + { + attachment->setOriginalPosition(info->mPosition); + attachment->setDefaultPosition(info->mPosition); + } - int group = info->mGroup; - if (group >= 0) - { - if (group < 0 || group >= 9) - { - llwarns << "Invalid group number (" << group << ") for attachment point " << info->mName << llendl; - } - else - { - attachment->setGroup(group); - } - } + if (info->mHasRotation) + { + LLQuaternion rotation; + rotation.setQuat(info->mRotationEuler.mV[VX] * DEG_TO_RAD, + info->mRotationEuler.mV[VY] * DEG_TO_RAD, + info->mRotationEuler.mV[VZ] * DEG_TO_RAD); + attachment->setRotation(rotation); + } - S32 attachmentID = info->mAttachmentID; - if (attachmentID < 1 || attachmentID > 255) + int group = info->mGroup; + if (group >= 0) + { + if (group < 0 || group >= NUM_ATTACHMENT_GROUPS ) { - llwarns << "Attachment point out of range [1-255]: " << attachmentID << " on attachment point " << info->mName << llendl; - delete attachment; - continue; + LL_WARNS() << "Invalid group number (" << group << ") for attachment point " << info->mName << LL_ENDL; } - if (mAttachmentPoints.find(attachmentID) != mAttachmentPoints.end()) + else { - llwarns << "Attachment point redefined with id " << attachmentID << " on attachment point " << info->mName << llendl; - delete attachment; - continue; + attachment->setGroup(group); } + } - attachment->setPieSlice(info->mPieMenuSlice); - attachment->setVisibleInFirstPerson(info->mVisibleFirstPerson); - attachment->setIsHUDAttachment(info->mIsHUDAttachment); + attachment->setPieSlice(info->mPieMenuSlice); + attachment->setVisibleInFirstPerson(info->mVisibleFirstPerson); + attachment->setIsHUDAttachment(info->mIsHUDAttachment); + // attachment can potentially be animated, needs a number. + attachment->setJointNum(mNumBones + mCollisionVolumes.size() + attachmentID - 1); + if (newly_created) + { mAttachmentPoints[attachmentID] = attachment; // now add attachment joint - parentJoint->addChild(attachment); + parent_joint->addChild(attachment); } } - - return TRUE; } //----------------------------------------------------------------------------- @@ -5923,13 +7384,27 @@ BOOL LLVOAvatar::loadSkeletonNode () //----------------------------------------------------------------------------- void LLVOAvatar::updateVisualParams() { - if (gNoRender) + ESex avatar_sex = (getVisualParamWeight("male") > 0.5f) ? SEX_MALE : SEX_FEMALE; + if (getSex() != avatar_sex) { - return; + if (mIsSitting && findMotion(avatar_sex == SEX_MALE ? ANIM_AGENT_SIT_FEMALE : ANIM_AGENT_SIT) != NULL) + { + // In some cases of gender change server changes sit motion with motion message, + // but in case of some avatars (legacy?) there is no update from server side, + // likely because server doesn't know about difference between motions + // (female and male sit ids are same server side, so it is likely unaware that it + // need to send update) + // Make sure motion is up to date + stopMotion(ANIM_AGENT_SIT); + setSex(avatar_sex); + startMotion(ANIM_AGENT_SIT); + } + else + { + setSex(avatar_sex); + } } - setSex( (getVisualParamWeight( "male" ) > 0.5f) ? SEX_MALE : SEX_FEMALE ); - LLCharacter::updateVisualParams(); if (mLastSkeletonSerialNum != mSkeletonSerialNum) @@ -5942,7 +7417,6 @@ void LLVOAvatar::updateVisualParams() dirtyMesh(); updateHeadOffset(); } - //----------------------------------------------------------------------------- // isActive() //----------------------------------------------------------------------------- @@ -5954,8 +7428,10 @@ BOOL LLVOAvatar::isActive() const //----------------------------------------------------------------------------- // setPixelAreaAndAngle() //----------------------------------------------------------------------------- +static LLFastTimer::DeclareTimer FTM_PIXEL_AREA("Pixel Area"); void LLVOAvatar::setPixelAreaAndAngle(LLAgent &agent) { + LL_RECORD_BLOCK_TIME(FTM_PIXEL_AREA); if (mDrawable.isNull()) { return; @@ -6001,7 +7477,6 @@ BOOL LLVOAvatar::updateJointLODs() F32 avatar_num_factor = clamp_rescale((F32)sNumVisibleAvatars, 8, 25, 1.f, avatar_num_min_factor); F32 area_scale = 0.16f; - { if (isSelf()) { if(gAgentCamera.cameraCustomizeAvatar() || gAgentCamera.cameraMouselook()) @@ -6036,7 +7511,6 @@ BOOL LLVOAvatar::updateJointLODs() dirtyMesh(2); return TRUE; } - } return FALSE; } @@ -6079,7 +7553,7 @@ void LLVOAvatar::updateGL() static LLFastTimer::DeclareTimer FTM_UPDATE_AVATAR("Update Avatar"); BOOL LLVOAvatar::updateGeometry(LLDrawable *drawable) { - LLFastTimer ftm(FTM_UPDATE_AVATAR); + LL_RECORD_BLOCK_TIME(FTM_UPDATE_AVATAR); if (!(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_AVATAR))) { return TRUE; @@ -6092,7 +7566,7 @@ BOOL LLVOAvatar::updateGeometry(LLDrawable *drawable) if (!drawable) { - llerrs << "LLVOAvatar::updateGeometry() called with NULL drawable" << llendl; + LL_ERRS() << "LLVOAvatar::updateGeometry() called with NULL drawable" << LL_ENDL; } return TRUE; @@ -6101,7 +7575,7 @@ BOOL LLVOAvatar::updateGeometry(LLDrawable *drawable) //----------------------------------------------------------------------------- // updateSexDependentLayerSets() //----------------------------------------------------------------------------- -void LLVOAvatar::updateSexDependentLayerSets( BOOL upload_bake ) +void LLVOAvatar::updateSexDependentLayerSets( bool upload_bake ) { invalidateComposite( mBakedTextureDatas[BAKED_HEAD].mTexLayerSet, upload_bake ); invalidateComposite( mBakedTextureDatas[BAKED_UPPER].mTexLayerSet, upload_bake ); @@ -6162,22 +7636,29 @@ BOOL LLVOAvatar::setParent(LLViewerObject* parent) void LLVOAvatar::addChild(LLViewerObject *childp) { childp->extractAttachmentItemID(); // find the inventory item this object is associated with. + if (isSelf()) + { + const LLUUID& item_id = childp->getAttachmentItemID(); + LLViewerInventoryItem *item = gInventory.getItem(item_id); + LL_DEBUGS("Avatar") << "ATT attachment child added " << (item ? item->getName() : "UNKNOWN") << " id " << item_id << LL_ENDL; + + } + LLViewerObject::addChild(childp); if (childp->mDrawable) { - if(isSelf()) + if (!attachObject(childp)) { - LL_INFOS("Attachment") << childp->getID() << " ("<getAttachmentPointName()<<") attached." << llendl; - llassert(std::find(mPendingAttachment.begin(), mPendingAttachment.end(), childp) == mPendingAttachment.end()); + LL_WARNS() << "ATT addChild() failed for " + << childp->getID() + << " item " << childp->getAttachmentItemID() + << LL_ENDL; + // MAINT-3312 backout + // mPendingAttachment.push_back(childp); } - attachObject(childp); } else { - if(isSelf()) - { - LL_INFOS("Attachment") << childp->getID() << " ("<getAttachmentPointName()<<") pending." << llendl; - } mPendingAttachment.push_back(childp); } } @@ -6187,30 +7668,19 @@ void LLVOAvatar::removeChild(LLViewerObject *childp) LLViewerObject::removeChild(childp); if (!detachObject(childp)) { - llwarns << "Calling detach on non-attached object " << llendl; - } -} - -namespace -{ - boost::signals2::connection sDetachBridgeConnection; - void detach_bridge(const LLViewerObject* obj, const LLViewerObject* bridge) - { - if (obj != bridge) return; - sDetachBridgeConnection.disconnect(); - LLVOAvatarSelf::detachAttachmentIntoInventory(obj->getAttachmentItemID()); + LL_WARNS() << "Calling detach on non-attached object " << LL_ENDL; } } LLViewerJointAttachment* LLVOAvatar::getTargetAttachmentPoint(LLViewerObject* viewer_object) { - S32 attachmentID = ATTACHMENT_ID_FROM_STATE(viewer_object->getState()); + S32 attachmentID = ATTACHMENT_ID_FROM_STATE(viewer_object->getAttachmentState()); // This should never happen unless the server didn't process the attachment point // correctly, but putting this check in here to be safe. if (attachmentID & ATTACHMENT_ADD) { - llwarns << "Got an attachment with ATTACHMENT_ADD mask, removing ( attach pt:" << attachmentID << " )" << llendl; + LL_WARNS() << "Got an attachment with ATTACHMENT_ADD mask, removing ( attach pt:" << attachmentID << " )" << LL_ENDL; attachmentID &= ~ATTACHMENT_ADD; } @@ -6218,19 +7688,27 @@ LLViewerJointAttachment* LLVOAvatar::getTargetAttachmentPoint(LLViewerObject* vi if (!attachment) { - llwarns << "Object attachment point invalid: " << attachmentID << llendl; - if (isSelf() && attachmentID == 127 && gSavedSettings.getBOOL("SGDetachBridge")) + LL_WARNS() << "Object attachment point invalid: " << attachmentID + << " trying to use 1 (chest)" + << LL_ENDL; + + attachment = get_if_there(mAttachmentPoints, 1, (LLViewerJointAttachment*)NULL); // Arbitrary using 1 (chest) + if (attachment) { - llinfos << "Bridge detected! detaching" << llendl; - sDetachBridgeConnection = gAgentAvatarp->setAttachmentCallback(boost::bind(detach_bridge, _1, viewer_object)); + LL_WARNS() << "Object attachment point invalid: " << attachmentID + << " on object " << viewer_object->getID() + << " attachment item " << viewer_object->getAttachmentItemID() + << " falling back to 1 (chest)" + << LL_ENDL; + } + else + { + LL_WARNS() << "Object attachment point invalid: " << attachmentID + << " on object " << viewer_object->getID() + << " attachment item " << viewer_object->getAttachmentItemID() + << "Unable to use fallback attachment point 1 (chest)" + << LL_ENDL; } -// attachment = get_if_there(mAttachmentPoints, 1, (LLViewerJointAttachment*)NULL); // Arbitrary using 1 (chest) -// [SL:KB] - Patch: Appearance-LegacyMultiAttachment | Checked: 2010-08-28 (Catznip-2.2.0a) | Added: Catznip2.1.2a - S32 idxAttachPt = 1; - if ( (!isSelf()) && (gSavedSettings.getBOOL("LegacyMultiAttachmentSupport")) && (attachmentID > 38) && (attachmentID <= 68) ) - idxAttachPt = attachmentID - 38; - attachment = get_if_there(mAttachmentPoints, idxAttachPt, (LLViewerJointAttachment*)NULL); -// [/SL:KB] } return attachment; @@ -6241,12 +7719,37 @@ LLViewerJointAttachment* LLVOAvatar::getTargetAttachmentPoint(LLViewerObject* vi //----------------------------------------------------------------------------- const LLViewerJointAttachment *LLVOAvatar::attachObject(LLViewerObject *viewer_object) { + if (isSelf()) + { + const LLUUID& item_id = viewer_object->getAttachmentItemID(); + LLViewerInventoryItem *item = gInventory.getItem(item_id); + LL_DEBUGS("Avatar") << "ATT attaching object " + << (item ? item->getName() : "UNKNOWN") << " id " << item_id << LL_ENDL; + } LLViewerJointAttachment* attachment = getTargetAttachmentPoint(viewer_object); if (!attachment || !attachment->addObject(viewer_object)) { + const LLUUID& item_id = viewer_object->getAttachmentItemID(); + LLViewerInventoryItem *item = gInventory.getItem(item_id); + LL_WARNS("Avatar") << "ATT attach failed " + << (item ? item->getName() : "UNKNOWN") << " id " << item_id << LL_ENDL; return 0; } + + // The object can already exist in the vector if it was attached while was already attached (causing a re-attach). + std::pair const val(viewer_object, attachment); + if (std::find(mAttachedObjectsVector.begin(), mAttachedObjectsVector.end(), val) == mAttachedObjectsVector.end()) + { + mAttachedObjectsVector.push_back(val); + } + + if (!viewer_object->isAnimatedObject()) + { + updateAttachmentOverrides(); + } + + updateVisualComplexity(); if (viewer_object->isSelected()) { @@ -6254,7 +7757,20 @@ const LLViewerJointAttachment *LLVOAvatar::attachObject(LLViewerObject *viewer_o LLSelectMgr::getInstance()->updatePointAt(); } - mAttachedObjectsVector.push_back(std::make_pair(viewer_object,attachment)); + viewer_object->refreshBakeTexture(); + + + LLViewerObject::const_child_list_t& child_list = viewer_object->getChildren(); + for (const auto& iter : child_list) + { + LLViewerObject* objectp = iter; + if (objectp) + { + objectp->refreshBakeTexture(); + } + } + + updateMeshVisibility(); return attachment; } @@ -6277,19 +7793,47 @@ U32 LLVOAvatar::getNumAttachments() const //----------------------------------------------------------------------------- // canAttachMoreObjects() +// Returns true if we can attach more objects. //----------------------------------------------------------------------------- -BOOL LLVOAvatar::canAttachMoreObjects() const +BOOL LLVOAvatar::canAttachMoreObjects(U32 n) const { - return (getNumAttachments() < MAX_AGENT_ATTACHMENTS); + return (getNumAttachments() + n) <= (U32)LLAgentBenefitsMgr::current().getAttachmentLimit(); } //----------------------------------------------------------------------------- -// canAttachMoreObjects() -// Returns true if we can attach more objects. +// getNumAnimatedObjectAttachments() //----------------------------------------------------------------------------- -BOOL LLVOAvatar::canAttachMoreObjects(U32 n) const +U32 LLVOAvatar::getNumAnimatedObjectAttachments() const +{ + U32 num_attachments = 0; + for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); + ++iter) + { + const LLViewerJointAttachment *attachment_pt = (*iter).second; + num_attachments += attachment_pt->getNumAnimatedObjects(); + } + return num_attachments; +} + +//----------------------------------------------------------------------------- +// getMaxAnimatedObjectAttachments() +// Gets from simulator feature if available, otherwise 0. +//----------------------------------------------------------------------------- +U32 LLVOAvatar::getMaxAnimatedObjectAttachments() const +{ + if (gSavedSettings.getBOOL("AnimatedObjectsIgnoreLimits")) + return U32_MAX; + return LLAgentBenefitsMgr::current().getAnimatedObjectLimit(); +} + +//----------------------------------------------------------------------------- +// canAttachMoreAnimatedObjects() +// Returns true if we can attach more animated objects. +//----------------------------------------------------------------------------- +BOOL LLVOAvatar::canAttachMoreAnimatedObjects(U32 n) const { - return (getNumAttachments() + n) <= MAX_AGENT_ATTACHMENTS; + return (getNumAnimatedObjectAttachments() + n) <= getMaxAnimatedObjectAttachments(); } //----------------------------------------------------------------------------- @@ -6301,17 +7845,29 @@ void LLVOAvatar::lazyAttach() for (U32 i = 0; i < mPendingAttachment.size(); i++) { - if (mPendingAttachment[i]->mDrawable) + LLPointer cur_attachment = mPendingAttachment[i]; + if (cur_attachment->mDrawable) { - if(isSelf()) + if (isSelf()) { - LL_INFOS("Attachment") << mPendingAttachment[i]->getID() << " ("<getAttachmentPointName()<<") done pending. attached." << llendl; + const LLUUID& item_id = cur_attachment->getAttachmentItemID(); + LLViewerInventoryItem *item = gInventory.getItem(item_id); + LL_DEBUGS("Avatar") << "ATT attaching object " + << (item ? item->getName() : "UNKNOWN") << " id " << item_id << LL_ENDL; + } + if (!attachObject(cur_attachment)) + { // Drop it + LL_WARNS() << "attachObject() failed for " + << cur_attachment->getID() + << " item " << cur_attachment->getAttachmentItemID() + << LL_ENDL; + // MAINT-3312 backout + //still_pending.push_back(cur_attachment); } - attachObject(mPendingAttachment[i]); } else { - still_pending.push_back(mPendingAttachment[i]); + still_pending.push_back(cur_attachment); } } @@ -6320,6 +7876,7 @@ void LLVOAvatar::lazyAttach() void LLVOAvatar::resetHUDAttachments() { +#if SLOW_ATTACHMENT_LIST for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); iter != mAttachmentPoints.end(); ++iter) @@ -6332,6 +7889,14 @@ void LLVOAvatar::resetHUDAttachments() ++attachment_iter) { const LLViewerObject* attached_object = (*attachment_iter); +#else + for(auto& iter : mAttachedObjectsVector) + {{{ + const LLViewerJointAttachment* attachment = iter.second; + if (!attachment->getIsHUDAttachment()) + continue; + const LLViewerObject* attached_object = iter.first; +#endif if (attached_object && attached_object->mDrawable.notNull()) { gPipeline.markMoved(attached_object->mDrawable); @@ -6343,6 +7908,7 @@ void LLVOAvatar::resetHUDAttachments() void LLVOAvatar::rebuildRiggedAttachments( void ) { +#if SLOW_ATTACHMENT_LIST for ( attachment_map_t::iterator iter = mAttachmentPoints.begin(); iter != mAttachmentPoints.end(); ++iter ) { LLViewerJointAttachment* pAttachment = iter->second; @@ -6352,6 +7918,12 @@ void LLVOAvatar::rebuildRiggedAttachments( void ) attachmentIter != attachmentIterEnd; ++attachmentIter) { const LLViewerObject* pAttachedObject = *attachmentIter; +#else + for(auto& iter : mAttachedObjectsVector) + {{ + const LLViewerObject* pAttachedObject = iter.first; + const LLViewerJointAttachment* pAttachment = iter.second; +#endif if ( pAttachment && pAttachedObject->mDrawable.notNull() ) { gPipeline.markRebuild(pAttachedObject->mDrawable); @@ -6364,42 +7936,25 @@ void LLVOAvatar::rebuildRiggedAttachments( void ) //----------------------------------------------------------------------------- void LLVOAvatar::cleanupAttachedMesh( LLViewerObject* pVO ) { - //If a VO has a skin that we'll reset the joint positions to their default - if ( pVO && pVO->mDrawable ) + LLUUID mesh_id; + if (getRiggedMeshID(pVO, mesh_id)) { - LLVOVolume* pVObj = pVO->mDrawable->getVOVolume(); - if ( pVObj ) + //resetJointsOnDetach(mesh_id); + if ( gAgentCamera.cameraCustomizeAvatar() ) { - const LLMeshSkinInfo* pSkinData = gMeshRepo.getSkinInfo( pVObj->getVolume()->getParams().getSculptID(), pVObj ); - if ( pSkinData ) - { - const int jointCnt = pSkinData->mJointNames.size(); - bool fullRig = ( jointCnt>=20 ) ? true : false; - if ( fullRig ) - { - const int bindCnt = pSkinData->mAlternateBindMatrix.size(); - if ( bindCnt > 0 ) - { - LLVOAvatar::resetJointPositionsToDefault(); - //Need to handle the repositioning of the cam, updating rig data etc during outfit editing - //This handles the case where we detach a replacement rig. - if ( gAgentCamera.cameraCustomizeAvatar() ) - { - gAgent.unpauseAnimation(); - //Still want to refocus on head bone - gAgentCamera.changeCameraToCustomizeAvatar(); - } - } - } - } + gAgent.unpauseAnimation(); + //Still want to refocus on head bone + gAgentCamera.changeCameraToCustomizeAvatar(); } - } + } } + //----------------------------------------------------------------------------- // detachObject() //----------------------------------------------------------------------------- BOOL LLVOAvatar::detachObject(LLViewerObject *viewer_object) { + for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); iter != mAttachmentPoints.end(); ++iter) @@ -6408,16 +7963,31 @@ BOOL LLVOAvatar::detachObject(LLViewerObject *viewer_object) if (attachment->isObjectAttached(viewer_object)) { + updateVisualComplexity(); + vector_replace_with_last(mAttachedObjectsVector,std::make_pair(viewer_object,attachment)); + bool is_animated_object = viewer_object->isAnimatedObject(); cleanupAttachedMesh( viewer_object ); + attachment->removeObject(viewer_object); - std::vector >::iterator it = std::find(mAttachedObjectsVector.begin(),mAttachedObjectsVector.end(),std::make_pair(viewer_object,attachment)); - if(it != mAttachedObjectsVector.end()) + if (!is_animated_object) { - (*it) = mAttachedObjectsVector.back(); - mAttachedObjectsVector.pop_back(); + updateAttachmentOverrides(); } + viewer_object->refreshBakeTexture(); + + LLViewerObject::const_child_list_t& child_list = viewer_object->getChildren(); + for (const auto& iter1 : child_list) + { + LLViewerObject* objectp = iter1; + if (objectp) + { + objectp->refreshBakeTexture(); + } + } + + updateMeshVisibility(); - lldebugs << "Detaching object " << viewer_object->mID << " from " << attachment->getName() << llendl; + LL_DEBUGS() << "Detaching object " << viewer_object->mID << " from " << attachment->getName() << LL_ENDL; return TRUE; } } @@ -6437,12 +8007,10 @@ BOOL LLVOAvatar::detachObject(LLViewerObject *viewer_object) //----------------------------------------------------------------------------- void LLVOAvatar::sitDown(BOOL bSitting) { - if (mIsSitting != bSitting) mIdleTimer.reset(); // Sitting changed, not idle + if (isSitting() != bSitting) mIdleTimer.reset(); // Sitting changed, not idle mIsSitting = bSitting; if (isSelf()) { - LLFloaterAO::ChangeStand(); - // [RLVa:KB] - Checked: 2010-08-29 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c if (rlv_handler_t::isEnabled()) { @@ -6532,9 +8100,18 @@ void LLVOAvatar::getOffObject() LLVector3 cur_position_world = mDrawable->getWorldPosition(); LLQuaternion cur_rotation_world = mDrawable->getWorldRotation(); + if (mLastRootPos.length() >= MAX_STANDOFF_FROM_ORIGIN + && (cur_position_world.length() < MAX_STANDOFF_FROM_ORIGIN + || dist_vec(cur_position_world, mLastRootPos) > MAX_STANDOFF_DISTANCE_CHANGE)) + { + // Most likely drawable got updated too early or some updates were missed - we got relative position to non-existing parent + // restore coordinates from cache + cur_position_world = mLastRootPos; + } + // set *local* position based on last *world* position, since we're unparenting the avatar mDrawable->mXform.setPosition(cur_position_world); - mDrawable->mXform.setRotation(cur_rotation_world); + mDrawable->mXform.setRotation(cur_rotation_world); gPipeline.markMoved(mDrawable, TRUE); @@ -6545,7 +8122,10 @@ void LLVOAvatar::getOffObject() mRoot->setRotation(cur_rotation_world); mRoot->getXform()->update(); + if (mEnableDefaultMotions) + { startMotion(ANIM_AGENT_BODY_NOISE); + } if (isSelf()) { @@ -6557,23 +8137,13 @@ void LLVOAvatar::getOffObject() at_axis.mV[VZ] = 0.f; at_axis.normalize(); gAgent.resetAxes(at_axis); - - //reset orientation -// mRoot.setRotation(avWorldRot); gAgentCamera.setThirdPersonHeadOffset(LLVector3(0.f, 0.f, 1.f)); - gAgentCamera.setSitCamera(LLUUID::null); - if (!sit_object->permYouOwner() && gSavedSettings.getBOOL("RevokePermsOnStandUp")) + if (sit_object && !sit_object->permYouOwner() && gSavedSettings.getBOOL("RevokePermsOnStandUp")) { - gMessageSystem->newMessageFast(_PREHASH_RevokePermissions); - gMessageSystem->nextBlockFast(_PREHASH_AgentData); - gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - gMessageSystem->nextBlockFast(_PREHASH_Data); - gMessageSystem->addUUIDFast(_PREHASH_ObjectID, sit_object->getID()); - gMessageSystem->addU32Fast(_PREHASH_ObjectPermissions, 0xFFFFFFFF); - gAgent.sendReliableMessage(); + U32 permissions = LSCRIPTRunTimePermissionBits[SCRIPT_PERMISSION_TRIGGER_ANIMATION] | LSCRIPTRunTimePermissionBits[SCRIPT_PERMISSION_OVERRIDE_ANIMATIONS]; + gAgent.sendRevokePermissions(sit_object->getID(), permissions); } } } @@ -6627,9 +8197,6 @@ BOOL LLVOAvatar::isWearingWearableType(LLWearableType::EType type) const break; // Do nothing } - /* switch(type) - case LLWearableType::WT_SHIRT: - indicator_te = TEX_UPPER_SHIRT; */ for (LLAvatarAppearanceDictionary::Textures::const_iterator tex_iter = LLAvatarAppearanceDictionary::getInstance()->getTextures().begin(); tex_iter != LLAvatarAppearanceDictionary::getInstance()->getTextures().end(); ++tex_iter) @@ -6691,21 +8258,33 @@ LLViewerObject* LLVOAvatar::getWornAttachment( const LLUUID& inv_item_id ) return NULL; } -const std::string LLVOAvatar::getAttachedPointName(const LLUUID& inv_item_id) -{ - const LLUUID& base_inv_item_id = gInventory.getLinkedItemID(inv_item_id); - for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); - iter != mAttachmentPoints.end(); ) +LLViewerObject * LLVOAvatar::findAttachmentByID( const LLUUID & target_id ) const +{ +#if SLOW_ATTACHMENT_LIST + for(attachment_map_t::const_iterator attachment_points_iter = mAttachmentPoints.begin(); + attachment_points_iter != mAttachmentPoints.end(); + ++attachment_points_iter) { - attachment_map_t::iterator curiter = iter++; - LLViewerJointAttachment* attachment = curiter->second; - if (attachment->getAttachedObject(base_inv_item_id)) + LLViewerJointAttachment* attachment = attachment_points_iter->second; + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) { - return attachment->getName(); + LLViewerObject *attached_object = (*attachment_iter); +#else + for(auto& iter : mAttachedObjectsVector) + {{ + LLViewerObject* attached_object = iter.first; +#endif + if (attached_object && + attached_object->getID() == target_id) + { + return attached_object; + } } } - return LLStringUtil::null; + return NULL; } // virtual @@ -6718,7 +8297,7 @@ void LLVOAvatar::invalidateAll() } // virtual -void LLVOAvatar::onGlobalColorChanged(const LLTexGlobalColor* global_color, BOOL upload_bake ) +void LLVOAvatar::onGlobalColorChanged(const LLTexGlobalColor* global_color, bool upload_bake ) { if (global_color == mTexSkinColor) { @@ -6750,39 +8329,45 @@ void LLVOAvatar::onGlobalColorChanged(const LLTexGlobalColor* global_color, BOOL } else if (global_color == mTexEyeColor) { -// llinfos << "invalidateComposite cause: onGlobalColorChanged( eyecolor )" << llendl; +// LL_INFOS() << "invalidateComposite cause: onGlobalColorChanged( eyecolor )" << LL_ENDL; invalidateComposite( mBakedTextureDatas[BAKED_EYES].mTexLayerSet, upload_bake ); } updateMeshTextures(); } +// virtual +bool LLVOAvatar::shouldRenderRigged() const +{ + return true; +} + +// FIXME: We have an mVisible member, set in updateVisibility(), but this +// function doesn't return it! isVisible() and mVisible are used +// different places for different purposes. mVisible seems to be more +// related to whether the actual avatar mesh is shown, and isVisible() +// to whether anything about the avatar is displayed in the scene. +// Maybe better naming could make this clearer? BOOL LLVOAvatar::isVisible() const { return mDrawable.notNull() + && (!mOrphaned || isSelf()) && (mDrawable->isVisible() || mIsDummy); } // Determine if we have enough avatar data to render BOOL LLVOAvatar::getIsCloud() const { - // Do we have a shape? - if ((const_cast(this))->visualParamWeightsAreDefault()) - { - return TRUE; - } - - if (!isTextureDefined(TEX_LOWER_BAKED) || - !isTextureDefined(TEX_UPPER_BAKED) || - !isTextureDefined(TEX_HEAD_BAKED)) + if (mIsDummy) { - return TRUE; + return false; } - if (isTooComplex()) - { - return TRUE; - } - return FALSE; + return ( ((const_cast(this))->visualParamWeightsAreDefault())// Do we have a shape? + || ( !isTextureDefined(TEX_LOWER_BAKED) + || !isTextureDefined(TEX_UPPER_BAKED) + || !isTextureDefined(TEX_HEAD_BAKED) + ) + ); } void LLVOAvatar::updateRezzedStatusTimers() @@ -6803,6 +8388,7 @@ void LLVOAvatar::updateRezzedStatusTimers() for (S32 i = 1; i < 4; i++) { startPhase("load_" + LLVOAvatar::rezStatusToString(i)); + startPhase("first_load_" + LLVOAvatar::rezStatusToString(i)); } } if (rez_status < mLastRezzedStatus) @@ -6819,6 +8405,7 @@ void LLVOAvatar::updateRezzedStatusTimers() for (S32 i = llmax(mLastRezzedStatus+1,1); i <= rez_status; i++) { stopPhase("load_" + LLVOAvatar::rezStatusToString(i)); + stopPhase("first_load_" + LLVOAvatar::rezStatusToString(i), false); } if (rez_status == 3) { @@ -6826,9 +8413,10 @@ void LLVOAvatar::updateRezzedStatusTimers() selfStopPhase("update_appearance_from_cof"); selfStopPhase("wear_inventory_category", false); selfStopPhase("process_initial_wearables_update", false); + + updateVisualComplexity(); } } - mLastRezzedStatus = rez_status; } } @@ -6840,24 +8428,27 @@ void LLVOAvatar::clearPhases() void LLVOAvatar::startPhase(const std::string& phase_name) { - F32 elapsed; - bool completed; - if (getPhases().getPhaseValues(phase_name, elapsed, completed)) + F32 elapsed = 0.0; + bool completed = false; + bool found = getPhases().getPhaseValues(phase_name, elapsed, completed); + //LL_DEBUGS("Avatar") << avString() << " phase state " << phase_name + // << " found " << found << " elapsed " << elapsed << " completed " << completed << LL_ENDL; + if (found) { if (!completed) { - LL_DEBUGS("Avatar") << avString() << "no-op, start when started already for " << phase_name << llendl; + LL_DEBUGS("Avatar") << avString() << "no-op, start when started already for " << phase_name << LL_ENDL; return; } } - LL_DEBUGS("Avatar") << "started phase " << phase_name << llendl; + LL_DEBUGS("Avatar") << "started phase " << phase_name << LL_ENDL; getPhases().startPhase(phase_name); } void LLVOAvatar::stopPhase(const std::string& phase_name, bool err_check) { - F32 elapsed; - bool completed; + F32 elapsed = 0.0; + bool completed = false; if (getPhases().getPhaseValues(phase_name, elapsed, completed)) { if (!completed) @@ -6865,13 +8456,13 @@ void LLVOAvatar::stopPhase(const std::string& phase_name, bool err_check) getPhases().stopPhase(phase_name); completed = true; logMetricsTimerRecord(phase_name, elapsed, completed); - LL_DEBUGS("Avatar") << avString() << "stopped phase " << phase_name << " elapsed " << elapsed << llendl; + LL_DEBUGS("Avatar") << avString() << "stopped phase " << phase_name << " elapsed " << elapsed << LL_ENDL; } else { if (err_check) { - LL_DEBUGS("Avatar") << "no-op, stop when stopped already for " << phase_name << llendl; + LL_DEBUGS("Avatar") << "no-op, stop when stopped already for " << phase_name << LL_ENDL; } } } @@ -6879,13 +8470,18 @@ void LLVOAvatar::stopPhase(const std::string& phase_name, bool err_check) { if (err_check) { - LL_DEBUGS("Avatar") << "no-op, stop when not started for " << phase_name << llendl; + LL_DEBUGS("Avatar") << "no-op, stop when not started for " << phase_name << LL_ENDL; } } } void LLVOAvatar::logPendingPhases() { + if (!isAgentAvatarValid()) + { + return; + } + for (LLViewerStats::phase_map_t::iterator it = getPhases().begin(); it != getPhases().end(); ++it) @@ -6920,6 +8516,11 @@ void LLVOAvatar::logPendingPhasesAllAvatars() void LLVOAvatar::logMetricsTimerRecord(const std::string& phase_name, F32 elapsed, bool completed) { + if (!isAgentAvatarValid()) + { + return; + } + LLSD record; record["timer_name"] = phase_name; record["avatar_id"] = getID(); @@ -6935,14 +8536,7 @@ void LLVOAvatar::logMetricsTimerRecord(const std::string& phase_name, F32 elapse record["grid_y"] = LLSD::Integer(grid_y); record["is_using_server_bakes"] = ((bool) isUsingServerBakes()); record["is_self"] = isSelf(); - - -#if 0 // verbose logging - std::ostringstream ostr; - ostr << LLSDNotationStreamer(record); - LL_DEBUGS("Avatar") << "record\n" << ostr.str() << llendl; -#endif - + if (isAgentAvatarValid()) { gAgentAvatarp->addMetricsTimerRecord(record); @@ -7020,26 +8614,44 @@ BOOL LLVOAvatar::processFullyLoadedChange(bool loading) BOOL LLVOAvatar::isFullyLoaded() const { - static LLCachedControl const render_unloaded_avatar("RenderUnloadedAvatar", false); + static const LLCachedControl render_unloaded_avatar("RenderUnloadedAvatar", false); -// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2010-09-22 (Catznip-2.2.0a) | Added: Catznip-2.2.0a +// [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2010-09-22 (Catznip-2.2) // Changes to LLAppearanceMgr::updateAppearanceFromCOF() expect this function to actually return mFullyLoaded for gAgentAvatarp - if ( (!isSelf()) && render_unloaded_avatar ) - return TRUE; - else - return mFullyLoaded; + return (render_unloaded_avatar && !isSelf()) ||(mFullyLoaded); // [/SL:KB] +// return (render_unloaded_avatar || mFullyLoaded); } bool LLVOAvatar::isTooComplex() const { - static const LLCachedControl render_avatar_complexity_limit("RenderAvatarComplexityLimit",0); - if (render_avatar_complexity_limit > 0 && mVisualComplexity >= render_avatar_complexity_limit) + static const LLCachedControl always_render_friends("AlwaysRenderFriends", 0); + bool too_complex; + // 'AlwaysRenderFriends' == 0, or an animesh, falls through to the complexity limits, if not self. Self is always rendered. + // 1 always render friends, 2 render only friends, 3 render only self + if (isSelf() || (always_render_friends && always_render_friends != 3 && !isControlAvatar() && LLAvatarTracker::instance().isBuddy(getID()))) { - return true; + too_complex = false; + } + else if (always_render_friends >= 2 && !isControlAvatar()) + { + too_complex = true; + } + else + { + // Determine if visually muted or not + static LLCachedControl max_render_cost(gSavedSettings, "RenderAvatarMaxComplexity", 0U); + static LLCachedControl max_attachment_area(gSavedSettings, "RenderAutoMuteSurfaceAreaLimit", 1000.0f); + // If the user has chosen unlimited max complexity, we also disregard max attachment area + // so that unlimited will completely disable the overly complex impostor rendering + // yes, this leaves them vulnerable to griefing objects... their choice + too_complex = ( max_render_cost > 0 + && (mVisualComplexity > max_render_cost + || (max_attachment_area > 0.0f && mAttachmentSurfaceArea > max_attachment_area) + )); } - return false; + return too_complex; } @@ -7051,9 +8663,12 @@ LLMotion* LLVOAvatar::findMotion(const LLUUID& id) const return mMotionController.findMotion(id); } +// This is a semi-deprecated debugging tool - meshes will not show as +// colorized if using deferred rendering. void LLVOAvatar::debugColorizeSubMeshes(U32 i, const LLColor4& color) { - if (gSavedSettings.getBOOL("DebugAvatarCompositeBaked")) + static LLCachedControl debug_avatar_comp_baked(gSavedSettings, "DebugAvatarCompositeBaked"); + if (debug_avatar_comp_baked) { avatar_joint_mesh_list_t::iterator iter = mBakedTextureDatas[i].mJointMeshes.begin(); avatar_joint_mesh_list_t::iterator end = mBakedTextureDatas[i].mJointMeshes.end(); @@ -7062,13 +8677,115 @@ void LLVOAvatar::debugColorizeSubMeshes(U32 i, const LLColor4& color) LLAvatarJointMesh* mesh = (*iter); if (mesh) { + mesh->setColor(color); + } + } + } +} + + +//----------------------------------------------------------------------------- +// updateMeshVisibility() +// Hide the mesh joints if attachments are using baked textures +//----------------------------------------------------------------------------- +void LLVOAvatar::updateMeshVisibility() +{ + bool bake_flag[BAKED_NUM_INDICES]; + memset(bake_flag, 0, BAKED_NUM_INDICES*sizeof(bool)); + + for (auto& attachment_point : mAttachmentPoints) + { + LLViewerJointAttachment* attachment = attachment_point.second; + if (attachment) + { + for (auto objectp : attachment->mAttachedObjects) + { + if (objectp) { - mesh->setColor(color); + for (int face_index = 0; face_index < objectp->getNumTEs(); face_index++) + { + LLTextureEntry* tex_entry = objectp->getTE(face_index); + bake_flag[BAKED_HEAD] |= (tex_entry->getID() == IMG_USE_BAKED_HEAD); + bake_flag[BAKED_EYES] |= (tex_entry->getID() == IMG_USE_BAKED_EYES); + bake_flag[BAKED_HAIR] |= (tex_entry->getID() == IMG_USE_BAKED_HAIR); + bake_flag[BAKED_LOWER] |= (tex_entry->getID() == IMG_USE_BAKED_LOWER); + bake_flag[BAKED_UPPER] |= (tex_entry->getID() == IMG_USE_BAKED_UPPER); + bake_flag[BAKED_SKIRT] |= (tex_entry->getID() == IMG_USE_BAKED_SKIRT); + bake_flag[BAKED_LEFT_ARM] |= (tex_entry->getID() == IMG_USE_BAKED_LEFTARM); + bake_flag[BAKED_LEFT_LEG] |= (tex_entry->getID() == IMG_USE_BAKED_LEFTLEG); + bake_flag[BAKED_AUX1] |= (tex_entry->getID() == IMG_USE_BAKED_AUX1); + bake_flag[BAKED_AUX2] |= (tex_entry->getID() == IMG_USE_BAKED_AUX2); + bake_flag[BAKED_AUX3] |= (tex_entry->getID() == IMG_USE_BAKED_AUX3); + } + } + + LLViewerObject::const_child_list_t& child_list = objectp->getChildren(); + for (const auto& iter1 : child_list) + { + LLViewerObject* objectchild = iter1; + if (objectchild) + { + for (int face_index = 0; face_index < objectchild->getNumTEs(); face_index++) + { + LLTextureEntry* tex_entry = objectchild->getTE(face_index); + bake_flag[BAKED_HEAD] |= (tex_entry->getID() == IMG_USE_BAKED_HEAD); + bake_flag[BAKED_EYES] |= (tex_entry->getID() == IMG_USE_BAKED_EYES); + bake_flag[BAKED_HAIR] |= (tex_entry->getID() == IMG_USE_BAKED_HAIR); + bake_flag[BAKED_LOWER] |= (tex_entry->getID() == IMG_USE_BAKED_LOWER); + bake_flag[BAKED_UPPER] |= (tex_entry->getID() == IMG_USE_BAKED_UPPER); + bake_flag[BAKED_SKIRT] |= (tex_entry->getID() == IMG_USE_BAKED_SKIRT); + bake_flag[BAKED_LEFT_ARM] |= (tex_entry->getID() == IMG_USE_BAKED_LEFTARM); + bake_flag[BAKED_LEFT_LEG] |= (tex_entry->getID() == IMG_USE_BAKED_LEFTLEG); + bake_flag[BAKED_AUX1] |= (tex_entry->getID() == IMG_USE_BAKED_AUX1); + bake_flag[BAKED_AUX2] |= (tex_entry->getID() == IMG_USE_BAKED_AUX2); + bake_flag[BAKED_AUX3] |= (tex_entry->getID() == IMG_USE_BAKED_AUX3); + } + } } } } } + + //LL_INFOS() << "head " << bake_flag[BAKED_HEAD] << "eyes " << bake_flag[BAKED_EYES] << "hair " << bake_flag[BAKED_HAIR] << "lower " << bake_flag[BAKED_LOWER] << "upper " << bake_flag[BAKED_UPPER] << "skirt " << bake_flag[BAKED_SKIRT] << LL_ENDL; + + for (size_t i = 0; i < mMeshLOD.size(); i++) + { + LLAvatarJoint* joint = mMeshLOD[i]; + if (i == MESH_ID_HAIR) + { + joint->setVisible(!bake_flag[BAKED_HAIR], TRUE); + } + else if (i == MESH_ID_HEAD) + { + joint->setVisible(!bake_flag[BAKED_HEAD], TRUE); + } + else if (i == MESH_ID_SKIRT) + { + joint->setVisible(!bake_flag[BAKED_SKIRT], TRUE); + } + else if (i == MESH_ID_UPPER_BODY) + { + joint->setVisible(!bake_flag[BAKED_UPPER], TRUE); + } + else if (i == MESH_ID_LOWER_BODY) + { + joint->setVisible(!bake_flag[BAKED_LOWER], TRUE); + } + else if (i == MESH_ID_EYEBALL_LEFT) + { + joint->setVisible(!bake_flag[BAKED_EYES], TRUE); + } + else if (i == MESH_ID_EYEBALL_RIGHT) + { + joint->setVisible(!bake_flag[BAKED_EYES], TRUE); + } + else if (i == MESH_ID_EYELASH) + { + joint->setVisible(!bake_flag[BAKED_HEAD], TRUE); + } + } } + //----------------------------------------------------------------------------- // updateMeshTextures() // Uses the current TE values to set the meshes' and layersets' textures. @@ -7078,8 +8795,7 @@ void LLVOAvatar::updateMeshTextures() { static S32 update_counter = 0; mBakedTextureDebugText.clear(); - // llinfos << "updateMeshTextures" << llendl; - if (gNoRender) return; + // if user has never specified a texture, assign the default for (U32 i=0; i < getNumTEs(); i++) { @@ -7175,7 +8891,7 @@ void LLVOAvatar::updateMeshTextures() const std::string url = getImageURL(te, mBakedTextureDatas[i].mLastTextureID); if (!url.empty()) { - baked_img = LLViewerTextureManager::getFetchedTextureFromUrl(url, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, mBakedTextureDatas[i].mLastTextureID); + baked_img = LLViewerTextureManager::getFetchedTextureFromUrl(url, FTT_HOST_BAKE, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, mBakedTextureDatas[i].mLastTextureID); } else { @@ -7183,10 +8899,10 @@ void LLVOAvatar::updateMeshTextures() const LLHost target_host = getObjectHost(); if (!target_host.isOk()) { - llwarns << "updateMeshTextures: invalid host for object: " << getID() << llendl; + LL_WARNS() << "updateMeshTextures: invalid host for object: " << getID() << LL_ENDL; } - baked_img = LLViewerTextureManager::getFetchedTextureFromHost( mBakedTextureDatas[i].mLastTextureID, target_host ); + baked_img = LLViewerTextureManager::getFetchedTextureFromHost( mBakedTextureDatas[i].mLastTextureID, FTT_HOST_BAKE, target_host ); } llassert(baked_img == existing_baked_img); @@ -7216,6 +8932,8 @@ void LLVOAvatar::updateMeshTextures() // we'll consider it loaded and use it (rather than // doing compositing). useBakedTexture( baked_img->getID() ); + mLoadedCallbacksPaused |= !isVisible(); + checkTextureLoading(); } else { @@ -7228,6 +8946,10 @@ void LLVOAvatar::updateMeshTextures() } baked_img->setLoadedCallback(onBakedTextureLoaded, SWITCH_TO_BAKED_DISCARD, FALSE, FALSE, new LLUUID( mID ), src_callback_list, paused ); + + // this could add paused texture callbacks + mLoadedCallbacksPaused |= paused; + checkTextureLoading(); } } else if (layerset && isUsingLocalAppearance()) @@ -7258,7 +8980,7 @@ void LLVOAvatar::updateMeshTextures() // set texture and color of hair manually if we are not using a baked image. // This can happen while loading hair for yourself, or for clients that did not // bake a hair texture. Still needed for yourself after 1.22 is depricated. - if (!is_layer_baked[BAKED_HAIR] || isEditingAppearance()) + if (!is_layer_baked[BAKED_HAIR]) { const LLColor4 color = mTexHairColor ? mTexHairColor->getColor() : LLColor4(1,1,1,1); LLViewerTexture* hair_img = getImage( TEX_HAIR, 0 ); @@ -7296,7 +9018,39 @@ void LLVOAvatar::updateMeshTextures() } } } - removeMissingBakedTextures(); + + // removeMissingBakedTextures() will call back into this rountine if something is removed, and can blow up the stack + static bool call_remove_missing = true; + if (call_remove_missing) + { + call_remove_missing = false; + removeMissingBakedTextures(); // May call back into this function if anything is removed + call_remove_missing = true; + } + + //refresh bakes on any attached objects + for (auto& attachment_point : mAttachmentPoints) + { + LLViewerJointAttachment* attachment = attachment_point.second; + + for (auto attached_object : attachment->mAttachedObjects) + { + if (attached_object && !attached_object->isDead()) + { + attached_object->refreshBakeTexture(); + + LLViewerObject::const_child_list_t& child_list = attached_object->getChildren(); + for (const auto& iter : child_list) + { + LLViewerObject* objectp = iter; + if (objectp && !objectp->isDead()) + { + objectp->refreshBakeTexture(); + } + } + } + } + } } // virtual @@ -7367,7 +9121,7 @@ void LLVOAvatar::applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_com { if (index >= BAKED_NUM_INDICES) { - llwarns << "invalid baked texture index passed to applyMorphMask" << llendl; + LL_WARNS() << "invalid baked texture index passed to applyMorphMask" << LL_ENDL; return; } @@ -7383,7 +9137,6 @@ void LLVOAvatar::applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_com } } - // returns TRUE if morph masks are present and not valid for a given baked texture, FALSE otherwise BOOL LLVOAvatar::morphMaskNeedsUpdate(LLAvatarAppearanceDefines::EBakedTextureIndex index) { @@ -7525,6 +9278,7 @@ BOOL LLVOAvatar::hasHUDAttachment() const LLBBox LLVOAvatar::getHUDBBox() const { LLBBox bbox; +#if SLOW_ATTACHMENT_LIST for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin(); iter != mAttachmentPoints.end(); ++iter) @@ -7537,9 +9291,17 @@ LLBBox LLVOAvatar::getHUDBBox() const ++attachment_iter) { const LLViewerObject* attached_object = (*attachment_iter); +#else + for(auto& iter : mAttachedObjectsVector) + {{{ + const LLViewerJointAttachment* attachment = iter.second; + if (!attachment || !attachment->getIsHUDAttachment()) + continue; + const LLViewerObject* attached_object = iter.first; +#endif if (attached_object == NULL) { - llwarns << "HUD attached object is NULL!" << llendl; + LL_WARNS() << "HUD attached object is NULL!" << LL_ENDL; continue; } // initialize bounding box to contain identity orientation and center point for attached object @@ -7566,7 +9328,7 @@ LLBBox LLVOAvatar::getHUDBBox() const //----------------------------------------------------------------------------- void LLVOAvatar::onFirstTEMessageReceived() { - LL_INFOS("Avatar") << avString() << LL_ENDL; + LL_DEBUGS("Avatar") << avString() << LL_ENDL; if( !mFirstTEMessageReceived ) { mFirstTEMessageReceived = TRUE; @@ -7598,6 +9360,9 @@ void LLVOAvatar::onFirstTEMessageReceived() LL_DEBUGS("Avatar") << avString() << "layer_baked, setting onInitialBakedTextureLoaded as callback" << LL_ENDL; image->setLoadedCallback( onInitialBakedTextureLoaded, MAX_DISCARD_LEVEL, FALSE, FALSE, new LLUUID( mID ), src_callback_list, paused ); + + // this could add paused texture callbacks + mLoadedCallbacksPaused |= paused; } } @@ -7628,50 +9393,33 @@ bool LLVOAvatar::visualParamWeightsAreDefault() // we have to not care whether skirt weights are default, if we're not actually wearing a skirt (is_wearing_skirt || !is_skirt_param)) { - //llinfos << "param '" << param->getName() << "'=" << param->getWeight() << " which differs from default=" << param->getDefaultWeight() << llendl; + //LL_INFOS() << "param '" << param->getName() << "'=" << param->getWeight() << " which differs from default=" << param->getDefaultWeight() << LL_ENDL; rtn = false; break; } } } - //llinfos << "params are default ? " << int(rtn) << llendl; + //LL_INFOS() << "params are default ? " << int(rtn) << LL_ENDL; return rtn; } -void dump_visual_param(LLAPRFile& file, LLVisualParam const* viewer_param, F32 value) +void dump_visual_param(apr_file_t* file, LLVisualParam const* viewer_param, F32 value) { - std::string type_string = "unknown"; - if (dynamic_cast(viewer_param)) - type_string = "param_alpha"; - if (dynamic_cast(viewer_param)) - type_string = "param_color"; - if (dynamic_cast(viewer_param)) - type_string = "param_driver"; - if (dynamic_cast(viewer_param)) - type_string = "param_morph"; - if (dynamic_cast(viewer_param)) - type_string = "param_skeleton"; - S32 wtype = -1; - LLViewerVisualParam const* vparam = dynamic_cast(viewer_param); - if (vparam) - { - wtype = vparam->getWearableType(); - } S32 u8_value = F32_to_U8(value,viewer_param->getMinWeight(),viewer_param->getMaxWeight()); - apr_file_printf(file.getFileHandle(), " \n", - viewer_param->getID(), viewer_param->getName().c_str(), value, u8_value, type_string.c_str(), - LLWearableType::getTypeName(LLWearableType::EType(wtype)).c_str() -// param_location_name(vparam->getParamLocation()).c_str() - ); + apr_file_printf(file, " \n", + viewer_param->getID(), viewer_param->getName().c_str(), value, u8_value, viewer_param->getTypeString(), + viewer_param->getDumpWearableTypeName().c_str()); } + void LLVOAvatar::dumpAppearanceMsgParams( const std::string& dump_prefix, - const std::vector& params_for_dump, - const LLTEContents& tec) + const LLAppearanceMessageContents& contents) { std::string outfilename = get_sequential_numbered_file_name(dump_prefix,".xml"); + const std::vector& params_for_dump = contents.mParamWeights; + const LLTEContents& tec = contents.mTEContents; LLAPRFile outfile; std::string fullpath = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,outfilename); @@ -7683,48 +9431,40 @@ void LLVOAvatar::dumpAppearanceMsgParams( const std::string& dump_prefix, } else { - LL_DEBUGS("Avatar") << "dumping appearance message to " << fullpath << llendl; + LL_DEBUGS("Avatar") << "dumping appearance message to " << fullpath << LL_ENDL; } + apr_file_printf(file, "
    \n"); + apr_file_printf(file, "\t\t\n", contents.mCOFVersion); + apr_file_printf(file, "\t\t\n", contents.mAppearanceVersion); + apr_file_printf(file, "
    \n"); + apr_file_printf(file, "\n\n"); LLVisualParam* param = getFirstVisualParam(); - for (S32 i = 0; i < (S32)params_for_dump.size(); i++) + for (const auto& param_for_dump : params_for_dump) { - while( param && (param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE) ) // should not be any of group VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT + while( param && ((param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE) && + (param->getGroup() != VISUAL_PARAM_GROUP_TRANSMIT_NOT_TWEAKABLE)) ) // should not be any of group VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT { param = getNextVisualParam(); } LLViewerVisualParam* viewer_param = (LLViewerVisualParam*)param; - F32 value = params_for_dump[i]; - dump_visual_param(outfile, viewer_param, value); + F32 value = param_for_dump; + dump_visual_param(file, viewer_param, value); param = getNextVisualParam(); } + apr_file_printf(file, "\n"); + + apr_file_printf(file, "\n\n"); for (U32 i = 0; i < tec.face_count; i++) { std::string uuid_str; ((LLUUID*)tec.image_data)[i].toString(uuid_str); apr_file_printf( file, "\t\t\n", i, uuid_str.c_str()); } + apr_file_printf(file, "\n"); } -struct LLAppearanceMessageContents -{ - LLAppearanceMessageContents(): - mAppearanceVersion(-1), - mParamAppearanceVersion(-1), - mCOFVersion(LLViewerInventoryCategory::VERSION_UNKNOWN) - { - } - LLTEContents mTEContents; - S32 mAppearanceVersion; - S32 mParamAppearanceVersion; - S32 mCOFVersion; - // For future use: - //U32 appearance_flags = 0; - std::vector mParamWeights; - std::vector mParams; -}; - void LLVOAvatar::parseAppearanceMessage(LLMessageSystem* mesgsys, LLAppearanceMessageContents& contents) { parseTEMessage(mesgsys, _PREHASH_ObjectData, -1, contents.mTEContents); @@ -7735,12 +9475,23 @@ void LLVOAvatar::parseAppearanceMessage(LLMessageSystem* mesgsys, LLAppearanceMe U8 av_u8; mesgsys->getU8Fast(_PREHASH_AppearanceData, _PREHASH_AppearanceVersion, av_u8, 0); contents.mAppearanceVersion = av_u8; - llinfos << "appversion set by AppearanceData field: " << contents.mAppearanceVersion << llendl; + LL_DEBUGS("Avatar") << "appversion set by AppearanceData field: " << contents.mAppearanceVersion << LL_ENDL; mesgsys->getS32Fast(_PREHASH_AppearanceData, _PREHASH_CofVersion, contents.mCOFVersion, 0); // For future use: //mesgsys->getU32Fast(_PREHASH_AppearanceData, _PREHASH_Flags, appearance_flags, 0); } + // Parse the AppearanceHover field, if any. + contents.mHoverOffsetWasSet = false; + if (mesgsys->has(_PREHASH_AppearanceHover)) + { + LLVector3 hover; + mesgsys->getVector3Fast(_PREHASH_AppearanceHover, _PREHASH_HoverHeight, hover); + LL_DEBUGS("Avatar") << avString() << " hover received " << hover.mV[ VX ] << "," << hover.mV[ VY ] << "," << hover.mV[ VZ ] << LL_ENDL; + contents.mHoverOffset = hover; + contents.mHoverOffsetWasSet = true; + } + // Parse visual params, if any. S32 num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_VisualParam); bool drop_visual_params_debug = gSavedSettings.getBOOL("BlockSomeAvatarAppearanceVisualParams") && (ll_rand(2) == 0); // pretend that ~12% of AvatarAppearance messages arrived without a VisualParam block, for testing @@ -7752,13 +9503,14 @@ void LLVOAvatar::parseAppearanceMessage(LLMessageSystem* mesgsys, LLAppearanceMe llassert(param); // if this ever fires, we should do the same as when num_blocks<=1 if (!param) { - llwarns << "No visual params!" << llendl; + LL_WARNS() << "No visual params!" << LL_ENDL; } else { for( S32 i = 0; i < num_blocks; i++ ) { - while( param && (param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE) ) // should not be any of group VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT + while( param && ((param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE) && + (param->getGroup() != VISUAL_PARAM_GROUP_TRANSMIT_NOT_TWEAKABLE)) ) // should not be any of group VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT { param = getNextVisualParam(); } @@ -7779,21 +9531,22 @@ void LLVOAvatar::parseAppearanceMessage(LLMessageSystem* mesgsys, LLAppearanceMe } } - const S32 expected_tweakable_count = getVisualParamCountInGroup(VISUAL_PARAM_GROUP_TWEAKABLE); // don't worry about VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT + const S32 expected_tweakable_count = getVisualParamCountInGroup(VISUAL_PARAM_GROUP_TWEAKABLE) + + getVisualParamCountInGroup(VISUAL_PARAM_GROUP_TRANSMIT_NOT_TWEAKABLE); // don't worry about VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT if (num_blocks != expected_tweakable_count) { - llinfos << "Number of params in AvatarAppearance msg (" << num_blocks << ") does not match number of tweakable params in avatar xml file (" << expected_tweakable_count << "). Processing what we can. object: " << getID() << llendl; + LL_DEBUGS("Avatar") << "Number of params in AvatarAppearance msg (" << num_blocks << ") does not match number of tweakable params in avatar xml file (" << expected_tweakable_count << "). Processing what we can. object: " << getID() << LL_ENDL; } } else { if (drop_visual_params_debug) { - llinfos << "Debug-faked lack of parameters on AvatarAppearance for object: " << getID() << llendl; + LL_INFOS() << "Debug-faked lack of parameters on AvatarAppearance for object: " << getID() << LL_ENDL; } else { - llinfos << "AvatarAppearance msg received without any parameters, object: " << getID() << llendl; + LL_DEBUGS("Avatar") << "AvatarAppearance msg received without any parameters, object: " << getID() << LL_ENDL; } } @@ -7804,9 +9557,8 @@ void LLVOAvatar::parseAppearanceMessage(LLMessageSystem* mesgsys, LLAppearanceMe if (it != contents.mParams.end()) { S32 index = it - contents.mParams.begin(); - llinfos << "index: " << index << llendl; - contents.mParamAppearanceVersion = llround(contents.mParamWeights[index]); - LL_DEBUGS("Avatar") << "appversion req by appearance_version param: " << contents.mParamAppearanceVersion << llendl; + contents.mParamAppearanceVersion = ll_round(contents.mParamWeights[index]); + LL_DEBUGS("Avatar") << "appversion req by appearance_version param: " << contents.mParamAppearanceVersion << LL_ENDL; } } } @@ -7819,25 +9571,25 @@ bool resolve_appearance_version(const LLAppearanceMessageContents& contents, S32 (contents.mParamAppearanceVersion >= 0) && (contents.mAppearanceVersion != contents.mParamAppearanceVersion)) { - llwarns << "inconsistent appearance_version settings - field: " << - contents.mAppearanceVersion << ", param: " << contents.mParamAppearanceVersion << llendl; + LL_WARNS() << "inconsistent appearance_version settings - field: " << + contents.mAppearanceVersion << ", param: " << contents.mParamAppearanceVersion << LL_ENDL; return false; } if (contents.mParamAppearanceVersion >= 0) // use visual param if available. { appearance_version = contents.mParamAppearanceVersion; } - if (contents.mAppearanceVersion >= 0) + else if (contents.mAppearanceVersion > 0) { appearance_version = contents.mAppearanceVersion; } - if (appearance_version < 0) // still not set, go with 0. + else // still not set, go with 1. { - appearance_version = 0; + appearance_version = 1; } LL_DEBUGS("Avatar") << "appearance version info - field " << contents.mAppearanceVersion << " param: " << contents.mParamAppearanceVersion - << " final: " << appearance_version << llendl; + << " final: " << appearance_version << LL_ENDL; return true; } @@ -7846,107 +9598,132 @@ bool resolve_appearance_version(const LLAppearanceMessageContents& contents, S32 //----------------------------------------------------------------------------- void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) { - LL_DEBUGS("Avatar") << "starts" << llendl; + static S32 largestSelfCOFSeen(LLViewerInventoryCategory::VERSION_UNKNOWN); + LL_DEBUGS("Avatar") << "starts" << LL_ENDL; bool enable_verbose_dumps = gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"); std::string dump_prefix = getFullname() + "_" + (isSelf()?"s":"o") + "_"; - //if (enable_verbose_dumps) { dumpArchetypeXML(dump_prefix + "process_start"); } if (gSavedSettings.getBOOL("BlockAvatarAppearanceMessages")) { - llwarns << "Blocking AvatarAppearance message" << llendl; + LL_WARNS() << "Blocking AvatarAppearance message" << LL_ENDL; return; } - ESex old_sex = getSex(); + mLastAppearanceMessageTimer.reset(); - LLAppearanceMessageContents contents; - parseAppearanceMessage(mesgsys, contents); + LLPointer contents(new LLAppearanceMessageContents); + parseAppearanceMessage(mesgsys, *contents); if (enable_verbose_dumps) { - dumpAppearanceMsgParams(dump_prefix + "appearance_msg", contents.mParamWeights, contents.mTEContents); + dumpAppearanceMsgParams(dump_prefix + "appearance_msg", *contents); } S32 appearance_version; - if (!resolve_appearance_version(contents, appearance_version)) + if (!resolve_appearance_version(*contents, appearance_version)) + { + LL_WARNS() << "bad appearance version info, discarding" << LL_ENDL; + return; + } + llassert(appearance_version > 0); + if (appearance_version > 1) { - llwarns << "bad appearance version info, discarding" << llendl; + LL_WARNS() << "unsupported appearance version " << appearance_version << ", discarding appearance message" << LL_ENDL; return; } - S32 this_update_cof_version = contents.mCOFVersion; - S32 last_update_request_cof_version = LLAppearanceMgr::instance().mLastUpdateRequestCOFVersion; + + S32 thisAppearanceVersion(contents->mCOFVersion); // Only now that we have result of appearance_version can we decide whether to bail out. if( isSelf() ) { - LL_DEBUGS("Avatar") << "this_update_cof_version " << this_update_cof_version - << " last_update_request_cof_version " << last_update_request_cof_version - << " my_cof_version " << LLAppearanceMgr::instance().getCOFVersion() << llendl; + LL_DEBUGS("Avatar") << "thisAppearanceVersion " << thisAppearanceVersion + << " mLastUpdateRequestCOFVersion " << mLastUpdateRequestCOFVersion + << " my_cof_version " << LLAppearanceMgr::instance().getCOFVersion() << LL_ENDL; - LLAppearanceMgr::instance().setLastAppearanceUpdateCOFVersion(this_update_cof_version); - - if (getRegion() && (getRegion()->getCentralBakeVersion()==0)) - { - llwarns << avString() << "Received AvatarAppearance message for self in non-server-bake region" << llendl; - } - if( mFirstTEMessageReceived && (appearance_version == 0)) + if (largestSelfCOFSeen > thisAppearanceVersion) { + LL_WARNS("Avatar") << "Already processed appearance for COF version " << + largestSelfCOFSeen << ", discarding appearance with COF " << thisAppearanceVersion << LL_ENDL; return; } + largestSelfCOFSeen = thisAppearanceVersion; + } else { - LL_DEBUGS("Avatar") << "appearance message received" << llendl; - } - - if (gNoRender) - { - return; + LL_DEBUGS("Avatar") << "appearance message received" << LL_ENDL; } // Check for stale update. if (isSelf() && (appearance_version>0) - && (this_update_cof_version < last_update_request_cof_version)) + && (thisAppearanceVersion < mLastUpdateRequestCOFVersion)) { - llwarns << "Stale appearance update, wanted version " << last_update_request_cof_version - << ", got " << this_update_cof_version << llendl; + LL_WARNS() << "Stale appearance update, wanted version " << mLastUpdateRequestCOFVersion + << ", got " << thisAppearanceVersion << LL_ENDL; return; } if (isSelf() && isEditingAppearance()) { - llinfos << "ignoring appearance message while in appearance edit" << llendl; + LL_DEBUGS("Avatar") << "ignoring appearance message while in appearance edit" << LL_ENDL; return; } - S32 num_params = contents.mParamWeights.size(); + // SUNSHINE CLEANUP - is this case OK now? + S32 num_params = contents->mParamWeights.size(); if (num_params <= 1) { // In this case, we have no reliable basis for knowing // appearance version, which may cause us to look for baked // textures in the wrong place and flag them as missing // assets. - llinfos << "ignoring appearance message due to lack of params" << llendl; + LL_DEBUGS("Avatar") << "ignoring appearance message due to lack of params" << LL_ENDL; return; } + // No backsies zone - if we get here, the message should be valid and usable, will be processed. + LL_INFOS("Avatar") << "Processing appearance message version " << thisAppearanceVersion << LL_ENDL; setIsUsingServerBakes(appearance_version > 0); - - applyParsedTEMessage(contents.mTEContents); + + // Note: + // RequestAgentUpdateAppearanceResponder::onRequestRequested() + // assumes that cof version is only updated with server-bake + // appearance messages. + mLastUpdateReceivedCOFVersion = thisAppearanceVersion; SHClientTagMgr::instance().updateAvatarTag(this); + mLastProcessedAppearance = contents; + + bool slam_params = false; + applyParsedAppearanceMessage(*contents, slam_params); +} + +void LLVOAvatar::applyParsedAppearanceMessage(LLAppearanceMessageContents& contents, bool slam_params) +{ + S32 num_params = contents.mParamWeights.size(); + ESex old_sex = getSex(); -// dumpAvatarTEs( "POST processAvatarAppearance()" ); + if (applyParsedTEMessage(contents.mTEContents) > 0 && isChanged(TEXTURE)) + { + updateVisualComplexity(); + } // prevent the overwriting of valid baked textures with invalid baked textures for (U8 baked_index = 0; baked_index < mBakedTextureDatas.size(); baked_index++) { if (!isTextureDefined(mBakedTextureDatas[baked_index].mTextureIndex) && mBakedTextureDatas[baked_index].mLastTextureID != IMG_DEFAULT - && baked_index != BAKED_SKIRT) + && baked_index != BAKED_SKIRT && baked_index != BAKED_LEFT_ARM && baked_index != BAKED_LEFT_LEG && baked_index != BAKED_AUX1 && baked_index != BAKED_AUX2 && baked_index != BAKED_AUX3) { + LL_DEBUGS("Avatar") << avString() << " baked_index " << (S32) baked_index << " using mLastTextureID " << mBakedTextureDatas[baked_index].mLastTextureID << LL_ENDL; setTEImage(mBakedTextureDatas[baked_index].mTextureIndex, - LLViewerTextureManager::getFetchedTexture(mBakedTextureDatas[baked_index].mLastTextureID, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE)); + LLViewerTextureManager::getFetchedTexture(mBakedTextureDatas[baked_index].mLastTextureID, FTT_HOST_BAKE, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE)); + } + else + { + LL_DEBUGS("Avatar") << avString() << " baked_index " << (S32) baked_index << " using texture id " + << getTE(mBakedTextureDatas[baked_index].mTextureIndex)->getID() << LL_ENDL; } } @@ -7956,7 +9733,7 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) BOOL is_first_appearance_message = !mFirstAppearanceMessageReceived; mFirstAppearanceMessageReceived = TRUE; - LL_INFOS("Avatar") << avString() << "processAvatarAppearance start " << mID + LL_DEBUGS("Avatar") << avString() << "processAvatarAppearance start " << mID << " first? " << is_first_appearance_message << " self? " << isSelf() << LL_ENDL; if (is_first_appearance_message ) @@ -7975,22 +9752,24 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) LL_DEBUGS("Avatar") << avString() << " handle visual params, num_params " << num_params << LL_ENDL; BOOL params_changed = FALSE; BOOL interp_params = FALSE; + S32 params_changed_count = 0; for( S32 i = 0; i < num_params; i++ ) { LLVisualParam* param = contents.mParams[i]; F32 newWeight = contents.mParamWeights[i]; - if(param->getID() == 10000) - { + if (!mHasPhysicsParameters && param->getID() == 10000) mHasPhysicsParameters = true; - } - if (is_first_appearance_message || (param->getWeight() != newWeight)) + if (slam_params || is_first_appearance_message || (param->getWeight() != newWeight)) { params_changed = TRUE; - if(is_first_appearance_message) + params_changed_count++; + + if(is_first_appearance_message || slam_params ) { + //LL_DEBUGS("Avatar") << "param slam " << i << " " << newWeight << LL_ENDL; param->setWeight(newWeight, FALSE); } else @@ -8000,12 +9779,14 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) } } } - const S32 expected_tweakable_count = getVisualParamCountInGroup(VISUAL_PARAM_GROUP_TWEAKABLE); // don't worry about VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT + const S32 expected_tweakable_count = getVisualParamCountInGroup(VISUAL_PARAM_GROUP_TWEAKABLE) + + getVisualParamCountInGroup(VISUAL_PARAM_GROUP_TRANSMIT_NOT_TWEAKABLE); // don't worry about VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT if (num_params != expected_tweakable_count) { - llinfos << "Number of params in AvatarAppearance msg (" << num_params << ") does not match number of tweakable params in avatar xml file (" << expected_tweakable_count << "). Processing what we can. object: " << getID() << llendl; + LL_DEBUGS("Avatar") << "Number of params in AvatarAppearance msg (" << num_params << ") does not match number of tweakable params in avatar xml file (" << expected_tweakable_count << "). Processing what we can. object: " << getID() << LL_ENDL; } + LL_DEBUGS("Avatar") << "Changed " << params_changed_count << " params" << LL_ENDL; if (params_changed) { if (interp_params) @@ -8033,17 +9814,33 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) if (visualParamWeightsAreDefault() && mRuthTimer.getElapsedTimeF32() > LOADING_TIMEOUT_SECONDS) { // re-request appearance, hoping that it comes back with a shape next time - llinfos << "Re-requesting AvatarAppearance for object: " << getID() << llendl; + LL_INFOS() << "Re-requesting AvatarAppearance for object: " << getID() << LL_ENDL; LLAvatarPropertiesProcessor::getInstance()->sendAvatarTexturesRequest(getID()); mRuthTimer.reset(); } else { - llinfos << "That's okay, we already have a non-default shape for object: " << getID() << llendl; + LL_INFOS() << "That's okay, we already have a non-default shape for object: " << getID() << LL_ENDL; // we don't really care. } } + if (contents.mHoverOffsetWasSet && !isSelf()) + { + // Got an update for some other avatar + // Ignore updates for self, because we have a more authoritative value in the preferences. + setHoverOffset(contents.mHoverOffset); + LL_INFOS("Avatar") << avString() << "setting hover from message" << contents.mHoverOffset[2] << LL_ENDL; + } + + if (!contents.mHoverOffsetWasSet && !isSelf()) + { + // If we don't get a value at all, we are presumably in a + // region that does not support hover height. + LL_WARNS() << avString() << "zeroing hover because not defined in appearance message" << LL_ENDL; + setHoverOffset(LLVector3(0.0, 0.0, 0.0)); + } + setCompositeUpdatesEnabled( TRUE ); // If all of the avatars are completely baked, release the global image caches to conserve memory. @@ -8055,35 +9852,66 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) } updateMeshTextures(); - //if (enable_verbose_dumps) dumpArchetypeXML(dump_prefix + "process_end"); + updateMeshVisibility(); +} + +LLViewerTexture* LLVOAvatar::getBakedTexture(const U8 te) +{ + if (te < 0 || te >= BAKED_NUM_INDICES) + { + return NULL; + } + + BOOL is_layer_baked = isTextureDefined(mBakedTextureDatas[te].mTextureIndex); + + LLViewerTexLayerSet* layerset = NULL; + layerset = getTexLayerSet(te); + + + if (!isEditingAppearance() && is_layer_baked) + { + LLViewerFetchedTexture* baked_img = LLViewerTextureManager::staticCastToFetchedTexture(getImage(mBakedTextureDatas[te].mTextureIndex, 0), TRUE); + return baked_img; + } + else if (layerset && isEditingAppearance()) + { + layerset->createComposite(); + layerset->setUpdatesEnabled(TRUE); + + return layerset->getViewerComposite(); + } + + return NULL; } // static -void LLVOAvatar::getAnimLabels( LLDynamicArray* labels ) +void LLVOAvatar::getAnimLabels( std::vector* labels ) { S32 i; + labels->reserve(gUserAnimStatesCount); for( i = 0; i < gUserAnimStatesCount; i++ ) { - labels->put( LLAnimStateLabels::getStateLabel( gUserAnimStates[i].mName ) ); + labels->push_back( LLAnimStateLabels::getStateLabel( gUserAnimStates[i].mName ) ); } // Special case to trigger away (AFK) state - labels->put( "Away From Keyboard" ); + labels->push_back( "Away From Keyboard" ); } // static -void LLVOAvatar::getAnimNames( LLDynamicArray* names ) +void LLVOAvatar::getAnimNames( std::vector* names ) { S32 i; + names->reserve(gUserAnimStatesCount); for( i = 0; i < gUserAnimStatesCount; i++ ) { - names->put( std::string(gUserAnimStates[i].mName) ); + names->push_back( std::string(gUserAnimStates[i].mName) ); } // Special case to trigger away (AFK) state - names->put( "enter_away_from_keyboard_state" ); + names->push_back( "enter_away_from_keyboard_state" ); } // static @@ -8091,7 +9919,7 @@ void LLVOAvatar::onBakedTextureMasksLoaded( BOOL success, LLViewerFetchedTexture { if (!userdata) return; - //llinfos << "onBakedTextureMasksLoaded: " << src_vi->getID() << llendl; + //LL_INFOS() << "onBakedTextureMasksLoaded: " << src_vi->getID() << LL_ENDL; const LLUUID id = src_vi->getID(); LLTextureMaskData* maskData = (LLTextureMaskData*) userdata; @@ -8105,15 +9933,14 @@ void LLVOAvatar::onBakedTextureMasksLoaded( BOOL success, LLViewerFetchedTexture { if (!aux_src->getData()) { - llwarns << "No auxiliary source data for onBakedTextureMasksLoaded" << llendl; + LL_WARNS() << "No auxiliary source (morph mask) data for image id " << id << LL_ENDL; return; } - U32 gl_name; - LLImageGL::generateTextures(LLTexUnit::TT_TEXTURE, GL_ALPHA8, 1, &gl_name ); + auto gl_name = LLImageGL::createTextureName(); stop_glerror(); - gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, gl_name); + gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, gl_name->getTexName()); stop_glerror(); LLImageGL::setManualImage( @@ -8126,7 +9953,7 @@ void LLVOAvatar::onBakedTextureMasksLoaded( BOOL success, LLViewerFetchedTexture /* if( id == head_baked->getID() ) if (self->mBakedTextureDatas[BAKED_HEAD].mTexLayerSet) - //llinfos << "onBakedTextureMasksLoaded for head " << id << " discard = " << discard_level << llendl; + //LL_INFOS() << "onBakedTextureMasksLoaded for head " << id << " discard = " << discard_level << LL_ENDL; self->mBakedTextureDatas[BAKED_HEAD].mTexLayerSet->applyMorphMask(aux_src->getData(), aux_src->getWidth(), aux_src->getHeight(), 1); maskData->mLastDiscardLevel = discard_level; */ BOOL found_texture_id = false; @@ -8145,10 +9972,6 @@ void LLVOAvatar::onBakedTextureMasksLoaded( BOOL success, LLViewerFetchedTexture const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex; self->applyMorphMask(aux_src->getData(), aux_src->getWidth(), aux_src->getHeight(), 1, baked_index); maskData->mLastDiscardLevel = discard_level; - if (self->mBakedTextureDatas[baked_index].mMaskTexName) - { - LLImageGL::deleteTextures(LLTexUnit::TT_TEXTURE, 0, -1, 1, &(self->mBakedTextureDatas[baked_index].mMaskTexName)); - } self->mBakedTextureDatas[baked_index].mMaskTexName = gl_name; found_texture_id = true; break; @@ -8157,7 +9980,7 @@ void LLVOAvatar::onBakedTextureMasksLoaded( BOOL success, LLViewerFetchedTexture } if (!found_texture_id) { - llinfos << "onBakedTextureMasksLoaded(): unexpected image id: " << id << llendl; + LL_INFOS() << "unexpected image id: " << id << LL_ENDL; } self->dirtyMesh(); } @@ -8165,7 +9988,7 @@ void LLVOAvatar::onBakedTextureMasksLoaded( BOOL success, LLViewerFetchedTexture { // this can happen when someone uses an old baked texture possibly provided by // viewer-side baked texture caching - llwarns << "Masks loaded callback but NO aux source!" << llendl; + LL_WARNS() << "Masks loaded callback but NO aux source, id " << id << LL_ENDL; } } @@ -8236,14 +10059,14 @@ void LLVOAvatar::useBakedTexture( const LLUUID& id ) LLViewerTexture* image_baked = getImage( mBakedTextureDatas[i].mTextureIndex, 0 ); if (id == image_baked->getID()) { - LL_DEBUGS("Avatar") << avString() << " i " << i << " id " << id << LL_ENDL; + //LL_DEBUGS("Avatar") << avString() << " i " << i << " id " << id << LL_ENDL; mBakedTextureDatas[i].mIsLoaded = true; mBakedTextureDatas[i].mLastTextureID = id; mBakedTextureDatas[i].mIsUsed = true; if (isUsingLocalAppearance()) { - llinfos << "not changing to baked texture while isUsingLocalAppearance" << llendl; + LL_INFOS() << "not changing to baked texture while isUsingLocalAppearance" << LL_ENDL; } else { @@ -8309,142 +10132,141 @@ std::string get_sequential_numbered_file_name(const std::string& prefix, return outfilename; } -void LLVOAvatar::dumpArchetypeXML(const std::string& prefix, bool group_by_wearables ) +void dump_sequential_xml(const std::string outprefix, const LLSD& content) { - std::string outprefix(prefix); - if (outprefix.empty()) - { - outprefix = getFullname() + (isSelf()?"_s":"_o"); - } std::string outfilename = get_sequential_numbered_file_name(outprefix,".xml"); - std::string fullpath = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,outfilename); - dumpArchetypeXML_cont(fullpath, group_by_wearables); + std::ofstream ofs(fullpath.c_str(), std::ios_base::out); + ofs << LLSDOStreamer(content, LLSDFormatter::OPTIONS_PRETTY); + LL_DEBUGS("Avatar") << "results saved to: " << fullpath << LL_ENDL; } -// metaversion 1.0 -// =============== -// -// Added as child of : -// -// -// -// Optionally, as child of , the following node may appear: -// -// -// -// Furthermore, metaversion 1.0 and higher allow the occurance of one or more blocks. -// If this is used then it is strongly advised to use one per wearable, so that -// the the node makes sense (it then refers to the wearable of that ). -// -// The reason for this clumsy way to link wearable to extra meta data is to stay -// compatible with the older format (no metaversion). -// -//static -void LLVOAvatar::dumpArchetypeXML_header(LLAPRFile& file, std::string const& archetype_name) -{ - apr_file_t* fp = file.getFileHandle(); - apr_file_printf(fp, "\n"); - apr_file_printf(fp, "\n"); - apr_file_printf(fp, " \n", - LLXMLNode::escapeXML(gHippoGridManager->getConnectedGrid()->getGridNick()).c_str(), - LLDate::now().asString().c_str()); - apr_file_printf(fp, " \n", archetype_name.c_str()); -} -//static -void LLVOAvatar::dumpArchetypeXML_footer(LLAPRFile& file) +void LLVOAvatar::getSortedJointNames(S32 joint_type, std::vector& result) const { - apr_file_t* fp = file.getFileHandle(); - apr_file_printf(fp, " \n"); - apr_file_printf(fp, "\n"); + result.clear(); + if (joint_type==0) + { + avatar_joint_list_t::const_iterator iter = mSkeleton.begin(); + avatar_joint_list_t::const_iterator end = mSkeleton.end(); + for (; iter != end; ++iter) + { + LLJoint* pJoint = (*iter); + result.push_back(pJoint->getName()); + } + } + else if (joint_type==1) + { + for (const auto& pJoint : mCollisionVolumes) + { + result.push_back(pJoint->getName()); + } + } + else if (joint_type==2) + { + for (LLVOAvatar::attachment_map_t::const_iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); ++iter) + { + LLViewerJointAttachment* pJoint = iter->second; + if (!pJoint) continue; + result.push_back(pJoint->getName()); + } + } + std::sort(result.begin(), result.end()); } -void LLVOAvatar::dumpArchetypeXML_cont(std::string const& fullpath, bool group_by_wearables) +void LLVOAvatar::dumpArchetypeXML(const std::string& prefix, bool group_by_wearables ) { - LLAPRFile outfile; - outfile.open(fullpath, LL_APR_WB ); - apr_file_t* file = outfile.getFileHandle(); - if (!file) - { - return; - } - else - { - llinfos << "xmlfile write handle obtained : " << fullpath << llendl; - } - - LLVOAvatar::dumpArchetypeXML_header(outfile); - - if (group_by_wearables) - { - for (S32 type = LLWearableType::WT_SHAPE; type < LLWearableType::WT_COUNT; type++) - { - const std::string& wearable_name = LLWearableType::getTypeName((LLWearableType::EType)type); - apr_file_printf( file, "\n\t\t\n", wearable_name.c_str() ); - - for (LLVisualParam* param = getFirstVisualParam(); param; param = getNextVisualParam()) - { - LLViewerVisualParam* viewer_param = (LLViewerVisualParam*)param; - if( (viewer_param->getWearableType() == type) && - (viewer_param->isTweakable() ) ) - { - dump_visual_param(outfile, viewer_param, viewer_param->getWeight()); - } - } - - for (U8 te = 0; te < TEX_NUM_INDICES; te++) - { - if (LLAvatarAppearanceDictionary::getTEWearableType((ETextureIndex)te) == type) - { - // MULTIPLE_WEARABLES: extend to multiple wearables? - LLViewerTexture* te_image = getImage((ETextureIndex)te, 0); - if( te_image ) - { - std::string uuid_str; - te_image->getID().toString( uuid_str ); - apr_file_printf( file, "\t\t\n", te, uuid_str.c_str()); - } - } - } - } - } - else - { - // Just dump all params sequentially. - for (LLVisualParam* param = getFirstVisualParam(); param; param = getNextVisualParam()) - { - LLViewerVisualParam* viewer_param = (LLViewerVisualParam*)param; - dump_visual_param(outfile, viewer_param, viewer_param->getWeight()); - } - - for (U8 te = 0; te < TEX_NUM_INDICES; te++) - { - { - // MULTIPLE_WEARABLES: extend to multiple wearables? - LLViewerTexture* te_image = getImage((ETextureIndex)te, 0); - if( te_image ) - { - std::string uuid_str; - te_image->getID().toString( uuid_str ); - apr_file_printf( file, "\t\t\n", te, uuid_str.c_str()); - } - } - } - + std::string outprefix(prefix); + if (outprefix.empty()) + { + outprefix = getFullname() + (isSelf()?"_s":"_o"); } + std::string outfilename = get_sequential_numbered_file_name(outprefix,".xml"); + + std::string fullpath = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,outfilename); + dumpArchetypeXML_cont(fullpath, group_by_wearables); +} - LLVOAvatar::dumpArchetypeXML_footer(outfile); - - bool ultra_verbose = false; - if (isSelf() && ultra_verbose) +void LLVOAvatar::dumpArchetypeXML_cont(std::string const& fullpath, bool group_by_wearables) +{ + try + { + AIXMLLindenGenepool linden_genepool(fullpath); + + if (group_by_wearables) + { + for (S32 type = LLWearableType::WT_SHAPE; type < LLWearableType::WT_COUNT; type++) + { + AIArchetype archetype((LLWearableType::EType)type); + + for (LLVisualParam* param = getFirstVisualParam(); param; param = getNextVisualParam()) + { + LLViewerVisualParam* viewer_param = (LLViewerVisualParam*)param; + if( (viewer_param->getWearableType() == type) && + (viewer_param->isTweakable() ) ) + { + archetype.add(AIVisualParamIDValuePair(param)); + } + } + + for (U8 te = 0; te < TEX_NUM_INDICES; te++) + { + if (LLAvatarAppearanceDictionary::getTEWearableType((ETextureIndex)te) == type) + { + // MULTIPLE_WEARABLES: extend to multiple wearables? + LLViewerTexture* te_image = getImage((ETextureIndex)te, 0); + if( te_image ) + { + archetype.add(AITextureIDUUIDPair(te, te_image->getID())); + } + } + } + + linden_genepool.child(archetype); + } + } + else + { + // Just dump all params sequentially. + AIArchetype archetype; // Legacy: Type is set to WT_NONE and will result in . + + for (LLVisualParam* param = getFirstVisualParam(); param; param = getNextVisualParam()) + { + archetype.add(AIVisualParamIDValuePair(param)); + } + + for (U8 te = 0; te < TEX_NUM_INDICES; te++) + { + { + // MULTIPLE_WEARABLES: extend to multiple wearables? + LLViewerTexture* te_image = getImage((ETextureIndex)te, 0); + if( te_image ) + { + archetype.add(AITextureIDUUIDPair(te, te_image->getID())); + } + } + } + + linden_genepool.child(archetype); + } + +#if 0 // Wasn't used anyway. + bool ultra_verbose = false; + if (isSelf() && ultra_verbose) + { + // show the cloned params inside the wearables as well. + gAgentAvatarp->dumpWearableInfo(outfile); + } +#endif + } + catch (AIAlert::Error const& error) { - // show the cloned params inside the wearables as well. - gAgentAvatarp->dumpWearableInfo(outfile); + AIAlert::add_modal("AIXMLdumpArchetypeXMLError", AIArgs("[FILE]", fullpath), error); } - // File will close when handle goes out of scope } + void LLVOAvatar::setVisibilityRank(U32 rank) { if (mDrawable.isNull() || mDrawable->isDead()) @@ -8509,7 +10331,7 @@ void LLVOAvatar::cullAvatarsByPixelArea() if (inst->mCulled != culled) { inst->mCulled = culled; - lldebugs << "avatar " << inst->getID() << (culled ? " start culled" : " start not culled" ) << llendl; + LL_DEBUGS() << "avatar " << inst->getID() << (culled ? " start culled" : " start not culled" ) << LL_ENDL; inst->updateMeshTextures(); } @@ -8530,14 +10352,14 @@ void LLVOAvatar::cullAvatarsByPixelArea() if (gFrameTimeSeconds != sUnbakedUpdateTime) // only update once per frame { sUnbakedUpdateTime = gFrameTimeSeconds; - sUnbakedTime += gFrameIntervalSeconds; + sUnbakedTime += gFrameIntervalSeconds.value(); } if (grey_avatars > 0) { if (gFrameTimeSeconds != sGreyUpdateTime) // only update once per frame { sGreyUpdateTime = gFrameTimeSeconds; - sGreyTime += gFrameIntervalSeconds; + sGreyTime += gFrameIntervalSeconds.value(); } } } @@ -8553,16 +10375,6 @@ void LLVOAvatar::startAppearanceAnimation() } } -//virtual -void LLVOAvatar::bodySizeChanged() -{ - if (isSelf() && !LLAppearanceMgr::instance().isInUpdateAppearanceFromCOF()) - { // notify simulator of change in size - // but not if we are in the middle of updating appearance - gAgent.sendAgentSetAppearance(); - } -} - BOOL LLVOAvatar::isUsingServerBakes() const { #if 1 @@ -8573,7 +10385,7 @@ BOOL LLVOAvatar::isUsingServerBakes() const F32 expect_wt = mUseServerBakes ? 1.0 : 0.0; if (!is_approx_equal(wt,expect_wt)) { - llwarns << "wt " << wt << " differs from expected " << expect_wt << llendl; + LL_WARNS() << "wt " << wt << " differs from expected " << expect_wt << LL_ENDL; } #endif @@ -8599,6 +10411,7 @@ void LLVOAvatar::updateRegion(LLViewerRegion *regionp) LLViewerObject::updateRegion(regionp); } +// virtual std::string LLVOAvatar::getFullname() const { std::string name; @@ -8645,7 +10458,12 @@ void LLVOAvatar::updateFreezeCounter(S32 counter) BOOL LLVOAvatar::updateLOD() { - if (isImpostor()) + if (mDrawable.isNull()) + { + return FALSE; + } + + if (isImpostor() && 0 != mDrawable->getNumFaces() && mDrawable->getFace(0)->hasGeometry()) { return TRUE; } @@ -8670,24 +10488,227 @@ BOOL LLVOAvatar::updateLOD() return res; } -void LLVOAvatar::updateLODRiggedAttachments( void ) +void LLVOAvatar::updateLODRiggedAttachments() { updateLOD(); rebuildRiggedAttachments(); } + +void showRigInfoTabExtents(LLVOAvatar *avatar, LLJointRiggingInfoTab& tab, S32& count_rigged, S32& count_box) +{ + count_rigged = count_box = 0; + LLVector4a zero_vec; + zero_vec.clear(); + for (S32 i=0; igetJoint(i); + LL_DEBUGS("RigSpam") << "joint " << i << " name " << joint->getName() << " box " + << tab[i].getRiggedExtents()[0] << ", " << tab[i].getRiggedExtents()[1] << LL_ENDL; + if ((!tab[i].getRiggedExtents()[0].equals3(zero_vec)) || + (!tab[i].getRiggedExtents()[1].equals3(zero_vec))) + { + count_box++; + } + } + } +} + +void LLVOAvatar::getAssociatedVolumes(std::vector& volumes) +{ +#if SLOW_ATTACHMENT_LIST + for ( LLVOAvatar::attachment_map_t::iterator iter = mAttachmentPoints.begin(); iter != mAttachmentPoints.end(); ++iter ) + { + LLViewerJointAttachment* attachment = iter->second; + LLViewerJointAttachment::attachedobjs_vec_t::iterator attach_end = attachment->mAttachedObjects.end(); + + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attach_iter = attachment->mAttachedObjects.begin(); + attach_iter != attach_end; ++attach_iter) + { + LLViewerObject* attached_object = *attach_iter; +#else + for(auto& iter : mAttachedObjectsVector) + {{ + LLViewerObject* attached_object = iter.first; +#endif + LLVOVolume *volume = attached_object->asVolume(); + if (volume) + { + volumes.push_back(volume); + if (volume->isAnimatedObject()) + { + // For animated object attachment, don't need + // the children. Will just get bounding box + // from the control avatar. + continue; + } + } + LLViewerObject::const_child_list_t& children = attached_object->getChildren(); + for (LLViewerObject* childp : children) + { + if (!childp) + continue; + + LLVOVolume *volume = childp->asVolume(); + if (volume) + { + volumes.push_back(volume); + } + } + } + } + + LLControlAvatar *control_av = asControlAvatar(); + if (control_av) + { + LLVOVolume *volp = control_av->mRootVolp; + if (volp) + { + volumes.push_back(volp); + LLViewerObject::const_child_list_t& children = volp->getChildren(); + for (LLViewerObject* childp : children) + { + LLVOVolume *volume = childp ? childp->asVolume() : nullptr; + if (volume) + { + volumes.push_back(volume); + } + } + } + } +} + +static LLTrace::BlockTimerStatHandle FTM_AVATAR_RIGGING_INFO_UPDATE("Av Upd Rig Info"); +static LLTrace::BlockTimerStatHandle FTM_AVATAR_RIGGING_KEY_UPDATE("Av Upd Rig Key"); +static LLTrace::BlockTimerStatHandle FTM_AVATAR_RIGGING_AVOL_UPDATE("Av Upd Avol"); + +// virtual +void LLVOAvatar::updateRiggingInfo() +{ + LL_RECORD_BLOCK_TIME(FTM_AVATAR_RIGGING_INFO_UPDATE); + + LL_DEBUGS("RigSpammish") << getFullname() << " updating rig tab" << LL_ENDL; + + std::vector volumes; + + { + LL_RECORD_BLOCK_TIME(FTM_AVATAR_RIGGING_AVOL_UPDATE); + getAssociatedVolumes(volumes); + } + + std::map curr_rigging_info_key; + { + LL_RECORD_BLOCK_TIME(FTM_AVATAR_RIGGING_KEY_UPDATE); + // Get current rigging info key + for (std::vector::iterator it = volumes.begin(); it != volumes.end(); ++it) + { + LLVOVolume *vol = *it; + if (vol->isRiggedMesh() && vol->getVolume() && vol->getVolume()->isMeshAssetLoaded()) + { + const LLUUID& mesh_id = vol->getVolume()->getParams().getSculptID(); + S32 max_lod = llmax(vol->getLOD(), vol->mLastRiggingInfoLOD); + curr_rigging_info_key[mesh_id] = max_lod; + } + } + + // Check for key change, which indicates some change in volume composition or LOD. + if (curr_rigging_info_key == mLastRiggingInfoKey) + { + return; + } + } + + // Something changed. Update. + mLastRiggingInfoKey = curr_rigging_info_key; + mJointRiggingInfoTab.clear(); + for (std::vector::iterator it = volumes.begin(); it != volumes.end(); ++it) + { + LLVOVolume *vol = *it; + vol->updateRiggingInfo(); + mJointRiggingInfoTab.merge(vol->mJointRiggingInfoTab); + } + + //LL_INFOS() << "done update rig count is " << countRigInfoTab(mJointRiggingInfoTab) << LL_ENDL; + LL_DEBUGS("RigSpammish") << getFullname() << " after update rig tab:" << LL_ENDL; + S32 joint_count, box_count; + showRigInfoTabExtents(this, mJointRiggingInfoTab, joint_count, box_count); + LL_DEBUGS("RigSpammish") << "uses " << joint_count << " joints " << " nonzero boxes: " << box_count << LL_ENDL; +} + +void LLVOAvatar::updateSoftwareSkinnedVertices(const LLMeshSkinInfo* skin, const LLVector4a* weight, const LLVolumeFace& vol_face, LLVertexBuffer *buffer) +{ + //perform software vertex skinning for this face + LLStrider position; + LLStrider normal; + + bool has_normal = buffer->hasDataType(LLVertexBuffer::TYPE_NORMAL); + buffer->getVertexStrider(position); + + if (has_normal) + { + buffer->getNormalStrider(normal); + } + + LLVector4a* pos = (LLVector4a*) position.get(); + + LLVector4a* norm = has_normal ? (LLVector4a*) normal.get() : NULL; + + //build matrix palette + LLMatrix4a mat[LL_MAX_JOINTS_PER_MESH_OBJECT]; + U32 count = LLSkinningUtil::getMeshJointCount(skin); + LLSkinningUtil::initSkinningMatrixPalette(mat, count, skin, this, true); + LLSkinningUtil::checkSkinWeights(weight, buffer->getNumVerts(), skin); + + LLMatrix4a bind_shape_matrix; + bind_shape_matrix.loadu(skin->mBindShapeMatrix); + + LLVector4a av_pos; + av_pos.load3(getPosition().mV); + + const U32 max_joints = LLSkinningUtil::getMaxJointCount(); + for (U32 j = 0; j < (U32)buffer->getNumVerts(); ++j) + { + LLMatrix4a final_mat; + LLSkinningUtil::getPerVertexSkinMatrix(weight[j].getF32ptr(), mat, false, final_mat, max_joints); + + LLVector4a& v = vol_face.mPositions[j]; + + LLVector4a t; + bind_shape_matrix.affineTransform(v, t); + final_mat.affineTransform(t, pos[j]); + + pos[j].add(av_pos); // Algorithm tweaked to stop hosing up normals. + + if (norm) + { + LLVector4a& n = vol_face.mNormals[j]; + final_mat.invert(); + final_mat.transpose(); + final_mat.affineTransform(n, norm[j]); + } + } +} + +void LLVOAvatar::onActiveOverrideMeshesChanged() +{ + mJointRiggingInfoTab.setNeedsUpdate(true); +} + U32 LLVOAvatar::getPartitionType() const { // Avatars merely exist as drawables in the bridge partition - return LLViewerRegion::PARTITION_BRIDGE; + return LLViewerRegion::PARTITION_ATTACHMENT; } //static void LLVOAvatar::updateImpostors() { - LLCharacter::sAllowInstancesChange = FALSE ; - - for (std::vector::iterator iter = LLCharacter::sInstances.begin(); - iter != LLCharacter::sInstances.end(); ++iter) + LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD; + std::vector instances_copy = LLCharacter::sInstances; + for (std::vector::iterator iter = instances_copy.begin(); + iter != instances_copy.end(); ++iter) { LLVOAvatar* avatar = (LLVOAvatar*) *iter; if (!avatar->isDead() && avatar->needsImpostorUpdate() && avatar->isVisible() && avatar->isImpostor()) @@ -8695,8 +10716,6 @@ void LLVOAvatar::updateImpostors() gPipeline.generateImpostor(avatar); } } - - LLCharacter::sAllowInstancesChange = TRUE ; } BOOL LLVOAvatar::isImpostor() const @@ -8704,6 +10723,10 @@ BOOL LLVOAvatar::isImpostor() const return (isVisuallyMuted() || (sUseImpostors && mUpdatePeriod >= IMPOSTOR_PERIOD)) ? TRUE : FALSE; } +BOOL LLVOAvatar::shouldImpostor(const U32 rank_factor) const +{ + return (!isSelf() && sUseImpostors && mVisibilityRank > (sMaxVisible * rank_factor)); +} BOOL LLVOAvatar::needsImpostorUpdate() const { @@ -8744,140 +10767,323 @@ void LLVOAvatar::getImpostorValues(LLVector4a* extents, LLVector3& angle, F32& d angle.mV[2] = da; } -void LLVOAvatar::idleUpdateRenderCost() + +void LLVOAvatar::idleUpdateRenderComplexity() { - if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHAME)) + if (isControlAvatar()) { - return; + LLControlAvatar *cav = asControlAvatar(); + bool is_attachment = cav && cav->mRootVolp && cav->mRootVolp->isAttachment(); // For attached animated objects + if (is_attachment) + { + // ARC for animated object attachments is accounted with the avatar they're attached to. + return; + } } - F32 red, green; + if (mComplexityTimer.getElapsedTimeF32() > 5.f) + { + // Render Complexity + calculateUpdateRenderComplexity(); // Update mVisualComplexity if needed + mComplexityTimer.start(); + } - static LLCachedControl UseOldARC(gSavedSettings, "LiruSensibleARC", true); - if(UseOldARC) + if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHAME)) { - U32 shame = 1; + std::string info_line; + F32 red_level; + F32 green_level; + LLColor4 info_color; + LLFontGL::StyleFlags info_style; + + if ( !mText ) + { + initHudText(); + mText->setFadeDistance(20.0, 5.0); // limit clutter in large crowds + } + else + { + mText->clearString(); // clear debug text + } - std::set textures; + /* + * NOTE: the logic for whether or not each of the values below + * controls muting MUST match that in the isVisuallyMuted and isTooComplex methods. + */ - /*attachment_map_t::const_iterator iter; - for (iter = mAttachmentPoints.begin(); - iter != mAttachmentPoints.end(); - ++iter) + static LLCachedControl max_render_cost(gSavedSettings, "RenderAvatarMaxComplexity", 0); + info_line = llformat("%d Complexity", mVisualComplexity); + + if (max_render_cost != 0) // zero means don't care, so don't bother coloring based on this { - LLViewerJointAttachment* attachment = iter->second; - for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); - attachment_iter != attachment->mAttachedObjects.end(); - ++attachment_iter) + green_level = 1.f-llclamp(((F32) mVisualComplexity-(F32)max_render_cost)/(F32)max_render_cost, 0.f, 1.f); + red_level = llmin((F32) mVisualComplexity/(F32)max_render_cost, 1.f); + info_color.set(red_level, green_level, 0.0, 1.0); + info_style = ( mVisualComplexity > max_render_cost + ? LLFontGL::BOLD : LLFontGL::NORMAL ); + } + else + { + info_color.set(LLColor4::grey); + info_style = LLFontGL::NORMAL; + } + mText->addLine(info_line, info_color, info_style); + + // Visual rank + info_line = llformat("%d rank", mVisibilityRank); + // Use grey for imposters, white for normal rendering or no impostors + info_color.set(isImpostor() ? LLColor4::grey : (isControlAvatar() ? LLColor4::yellow : LLColor4::white)); + info_style = LLFontGL::NORMAL; + mText->addLine(info_line, info_color, info_style); + + // Triangle count + mText->addLine(std::string("VisTris ") + LLStringOps::getReadableNumber(mAttachmentVisibleTriangleCount), + info_color, info_style); + mText->addLine(std::string("EstMaxTris ") + LLStringOps::getReadableNumber(mAttachmentEstTriangleCount), + info_color, info_style); + + // Attachment Surface Area + static LLCachedControl max_attachment_area(gSavedSettings, "RenderAutoMuteSurfaceAreaLimit", 1000.0f); + info_line = llformat("%.0f m^2", mAttachmentSurfaceArea); + + if (max_render_cost != 0 && max_attachment_area != 0) // zero means don't care, so don't bother coloring based on this + { + green_level = 1.f-llclamp((mAttachmentSurfaceArea-max_attachment_area)/max_attachment_area, 0.f, 1.f); + red_level = llmin(mAttachmentSurfaceArea/max_attachment_area, 1.f); + info_color.set(red_level, green_level, 0.0, 1.0); + info_style = ( mAttachmentSurfaceArea > max_attachment_area + ? LLFontGL::BOLD : LLFontGL::NORMAL ); + + } + else + { + info_color.set(LLColor4::grey); + info_style = LLFontGL::NORMAL; + } + + mText->addLine(info_line, info_color, info_style); + + updateText(); // corrects position + } +} + +void LLVOAvatar::updateVisualComplexity() +{ + LL_DEBUGS("AvatarRender") << "avatar " << getID() << " appearance changed" << LL_ENDL; + // Set the cache time to in the past so it's updated ASAP + mVisualComplexityStale = true; +} + +// Account for the complexity of a single top-level object associated +// with an avatar. This will be either an attached object or an animated +// object. +void LLVOAvatar::accountRenderComplexityForObject( + const LLViewerObject *attached_object, + const F32 max_attachment_complexity, + LLVOVolume::texture_cost_t& textures, + U32& cost/*, + hud_complexity_list_t& hud_complexity_list*/) +{ + if (attached_object && !attached_object->isHUDAttachment()) + { + mAttachmentVisibleTriangleCount += attached_object->recursiveGetTriangleCount(); + mAttachmentEstTriangleCount += attached_object->recursiveGetEstTrianglesMax(); + mAttachmentSurfaceArea += attached_object->recursiveGetScaledSurfaceArea(); + + textures.clear(); + const LLDrawable* drawable = attached_object->mDrawable; + if (drawable) + { + const LLVOVolume* volume = drawable->getVOVolume(); + if (volume) { - const LLViewerObject* object = (*attachment_iter);*/ - std::vector >::iterator attachment_iter = mAttachedObjectsVector.begin(); - for(;attachment_iter!=mAttachedObjectsVector.end();++attachment_iter) - {{ - const LLViewerObject* object = attachment_iter->first; - if (object && !object->isHUDAttachment()) + F32 attachment_total_cost = 0; + F32 attachment_volume_cost = 0; + F32 attachment_texture_cost = 0; + F32 attachment_children_cost = 0; + const F32 animated_object_attachment_surcharge = 1000; + + if (attached_object->isAnimatedObject()) { - LLDrawable* drawable = object->mDrawable; - if (drawable) + attachment_volume_cost += animated_object_attachment_surcharge; + } + attachment_volume_cost += volume->getRenderCost(textures); + + const_child_list_t children = volume->getChildren(); + for (const_child_list_t::const_iterator child_iter = children.begin(); + child_iter != children.end(); + ++child_iter) + { + LLViewerObject* child_obj = *child_iter; + LLVOVolume *child = child_obj ? child_obj->asVolume() : nullptr; + if (child) { - shame += 10; - LLVOVolume* volume = drawable->getVOVolume(); - if (volume) - { - shame += calc_shame(volume, textures); - } + attachment_children_cost += child->getRenderCost(textures); } } + + for (LLVOVolume::texture_cost_t::iterator volume_texture = textures.begin(); + volume_texture != textures.end(); + ++volume_texture) + { + // add the cost of each individual texture in the linkset + attachment_texture_cost += volume_texture->second; + } + attachment_total_cost = attachment_volume_cost + attachment_texture_cost + attachment_children_cost; + LL_DEBUGS("ARCdetail") << "Attachment costs " << attached_object->getAttachmentItemID() + << " total: " << attachment_total_cost + << ", volume: " << attachment_volume_cost + << ", textures: " << attachment_texture_cost + << ", " << volume->numChildren() + << " children: " << attachment_children_cost + << LL_ENDL; + // Limit attachment complexity to avoid signed integer flipping of the wearer's ACI + cost += (U32)llclamp(attachment_total_cost, MIN_ATTACHMENT_COMPLEXITY, max_attachment_complexity); } } - - shame += textures.size() * 5; - - setDebugText(llformat("%d", shame)); - green = 1.f-llclamp(((F32) shame-1024.f)/1024.f, 0.f, 1.f); - red = llmin((F32) shame/1024.f, 1.f); } - else + if (isSelf() + && attached_object + && attached_object->isHUDAttachment() + && !attached_object->isTempAttachment() + && attached_object->mDrawable) { - static const U32 ARC_BODY_PART_COST = 200; - static const LLCachedControl ARC_LIMIT("LiruNewARCLimit", 20000); + textures.clear(); + + mAttachmentSurfaceArea += attached_object->recursiveGetScaledSurfaceArea(); + +#if 0 + const LLVOVolume* volume = attached_object->mDrawable->getVOVolume(); + if (volume) + { + + LLHUDComplexity hud_object_complexity; + hud_object_complexity.objectName = attached_object->getAttachmentItemName(); + hud_object_complexity.objectId = attached_object->getAttachmentItemID(); + std::string joint_name; + gAgentAvatarp->getAttachedPointName(attached_object->getAttachmentItemID(), joint_name); + hud_object_complexity.jointName = joint_name; + // get cost and individual textures + hud_object_complexity.objectsCost += volume->getRenderCost(textures); + hud_object_complexity.objectsCount++; + + LLViewerObject::const_child_list_t& child_list = attached_object->getChildren(); + for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); + iter != child_list.end(); ++iter) + { + LLViewerObject* childp = *iter; + const LLVOVolume* chld_volume = childp ? childp->asVolume() : nullptr; + if (chld_volume) + { + // get cost and individual textures + hud_object_complexity.objectsCost += chld_volume->getRenderCost(textures); + hud_object_complexity.objectsCount++; + } + } - static std::set all_textures; + hud_object_complexity.texturesCount += textures.size(); - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_ATTACHMENT_BYTES)) - { //set debug text to attachment geometry bytes here so render cost will override - setDebugText(llformat("%.1f KB, %.2f m^2", mAttachmentGeometryBytes/1024.f, mAttachmentSurfaceArea)); + for (LLVOVolume::texture_cost_t::iterator volume_texture = textures.begin(); + volume_texture != textures.end(); + ++volume_texture) + { + // add the cost of each individual texture (ignores duplicates) + hud_object_complexity.texturesCost += volume_texture->second; + LLViewerFetchedTexture *tex = LLViewerTextureManager::getFetchedTexture(volume_texture->first); + if (tex) + { + // Note: Texture memory might be incorect since texture might be still loading. + hud_object_complexity.texturesMemoryTotal += tex->getTextureMemory(); + if (tex->getOriginalHeight() * tex->getOriginalWidth() >= HUD_OVERSIZED_TEXTURE_DATA_SIZE) + { + hud_object_complexity.largeTexturesCount++; + } + } + } + hud_complexity_list.push_back(hud_object_complexity); } +#endif + } +} + +// Calculations for mVisualComplexity value +void LLVOAvatar::calculateUpdateRenderComplexity() +{ + /***************************************************************** + * This calculation should not be modified by third party viewers, + * since it is used to limit rendering and should be uniform for + * everyone. If you have suggested improvements, submit them to + * the official viewer for consideration. + *****************************************************************/ + static const U32 COMPLEXITY_BODY_PART_COST = 200; + static LLCachedControl max_complexity_setting(gSavedSettings,"MaxAttachmentComplexity"); + F32 max_attachment_complexity = max_complexity_setting; + max_attachment_complexity = llmax(max_attachment_complexity, DEFAULT_MAX_ATTACHMENT_COMPLEXITY); - U32 cost = 0; + // Diagnostic list of all textures on our avatar + static uuid_set_t all_textures; + + if (mVisualComplexityStale) + { + U32 cost = VISUAL_COMPLEXITY_UNKNOWN; LLVOVolume::texture_cost_t textures; + //hud_complexity_list_t hud_complexity_list; for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++) { - const LLAvatarAppearanceDictionary::BakedEntry *baked_dict = LLAvatarAppearanceDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)baked_index); + const LLAvatarAppearanceDictionary::BakedEntry *baked_dict + = LLAvatarAppearanceDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)baked_index); ETextureIndex tex_index = baked_dict->mTextureIndex; if ((tex_index != TEX_SKIRT_BAKED) || (isWearingWearableType(LLWearableType::WT_SKIRT))) { if (isTextureVisible(tex_index)) { - cost +=ARC_BODY_PART_COST; + cost +=COMPLEXITY_BODY_PART_COST; } } } + LL_DEBUGS("ARCdetail") << "Avatar body parts complexity: " << cost << LL_ENDL; + mAttachmentVisibleTriangleCount = 0; + mAttachmentEstTriangleCount = 0.f; + mAttachmentSurfaceArea = 0.f; - /*for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin(); - iter != mAttachmentPoints.end(); - ++iter) + // A standalone animated object needs to be accounted for + // using its associated volume. Attached animated objects + // will be covered by the subsequent loop over attachments. + LLControlAvatar *control_av = asControlAvatar(); + if (control_av) { - LLViewerJointAttachment* attachment = iter->second; + LLVOVolume *volp = control_av->mRootVolp; + if (volp && !volp->isAttachment()) + { + accountRenderComplexityForObject(volp, max_attachment_complexity, + textures, cost/*, hud_complexity_list*/); + } + } + + // Account for complexity of all attachments. +#if SLOW_ATTACHMENT_LIST + for (attachment_map_t::const_iterator attachment_point = mAttachmentPoints.begin(); + attachment_point != mAttachmentPoints.end(); + ++attachment_point) + { + LLViewerJointAttachment* attachment = attachment_point->second; for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); attachment_iter != attachment->mAttachedObjects.end(); ++attachment_iter) { - const LLViewerObject* attached_object = (*attachment_iter);*/ - std::vector >::iterator attachment_iter = mAttachedObjectsVector.begin(); - for(;attachment_iter!=mAttachedObjectsVector.end();++attachment_iter) + const LLViewerObject* attached_object = (*attachment_iter); +#else + for(auto& iter : mAttachedObjectsVector) {{ - const LLViewerObject* attached_object = attachment_iter->first; - if (attached_object && !attached_object->isHUDAttachment()) - { - textures.clear(); - const LLDrawable* drawable = attached_object->mDrawable; - if (drawable) - { - const LLVOVolume* volume = drawable->getVOVolume(); - if (volume) - { - cost += volume->getRenderCost(textures); - - const_child_list_t children = volume->getChildren(); - for (const_child_list_t::const_iterator child_iter = children.begin(); - child_iter != children.end(); - ++child_iter) - { - LLViewerObject* child_obj = *child_iter; - LLVOVolume *child = dynamic_cast( child_obj ); - if (child) - { - cost += child->getRenderCost(textures); - } - } - - for (LLVOVolume::texture_cost_t::iterator iter = textures.begin(); iter != textures.end(); ++iter) - { - // add the cost of each individual texture in the linkset - cost += iter->second; - } - } - } - } + const LLViewerObject* attached_object = iter.first; +#endif + accountRenderComplexityForObject(attached_object, max_attachment_complexity, + textures, cost/*, hud_complexity_list*/); } - } - - // Diagnostic output to identify all avatar-related textures. // Does not affect rendering cost calculation. // Could be wrapped in a debug option if output becomes problematic. @@ -8887,12 +11093,11 @@ void LLVOAvatar::idleUpdateRenderCost() for (LLVOVolume::texture_cost_t::iterator it = textures.begin(); it != textures.end(); ++it) { LLUUID image_id = it->first; - if( image_id.isNull() || image_id == IMG_DEFAULT || image_id == IMG_DEFAULT_AVATAR) - continue; - if (all_textures.find(image_id) == all_textures.end()) + if( ! (image_id.isNull() || image_id == IMG_DEFAULT || image_id == IMG_DEFAULT_AVATAR) + && (all_textures.find(image_id) == all_textures.end())) { // attachment texture not previously seen. - llinfos << "attachment_texture: " << image_id.asString() << llendl; + LL_DEBUGS("ARCdetail") << "attachment_texture: " << image_id.asString() << LL_ENDL; all_textures.insert(image_id); } } @@ -8912,34 +11117,32 @@ void LLVOAvatar::idleUpdateRenderCost() continue; if (all_textures.find(image_id) == all_textures.end()) { - llinfos << "local_texture: " << texture_dict->mName << ": " << image_id << llendl; + LL_DEBUGS("ARCdetail") << "local_texture: " << texture_dict->mName << ": " << image_id << LL_ENDL; all_textures.insert(image_id); } } } - - std::string viz_string = LLVOAvatar::rezStatusToString(getRezzedStatus()); - setDebugText(llformat("%s %d", viz_string.c_str(), cost)); mVisualComplexity = cost; - green = 1.f-llclamp(((F32) cost-(F32)ARC_LIMIT)/(F32)ARC_LIMIT, 0.f, 1.f); - red = llmin((F32) cost/(F32)ARC_LIMIT, 1.f); + mVisualComplexityStale = false; } - mText->setColor(LLColor4(red,green,0,1)); + } // static BOOL LLVOAvatar::isIndexLocalTexture(ETextureIndex index) { - if (index < 0 || index >= TEX_NUM_INDICES) return false; - return LLAvatarAppearanceDictionary::getInstance()->getTexture(index)->mIsLocalTexture; + return (index < 0 || index >= TEX_NUM_INDICES) + ? false + : LLAvatarAppearanceDictionary::getInstance()->getTexture(index)->mIsLocalTexture; } // static BOOL LLVOAvatar::isIndexBakedTexture(ETextureIndex index) { - if (index < 0 || index >= TEX_NUM_INDICES) return false; - return LLAvatarAppearanceDictionary::getInstance()->getTexture(index)->mIsBakedTexture; + return (index < 0 || index >= TEX_NUM_INDICES) + ? false + : LLAvatarAppearanceDictionary::getInstance()->getTexture(index)->mIsBakedTexture; } const std::string LLVOAvatar::getBakedStatusForPrintout() const @@ -8992,7 +11195,7 @@ BOOL LLVOAvatar::isTextureDefined(LLAvatarAppearanceDefines::ETextureIndex te, U if( !getImage( te, index ) ) { - llwarns << "getImage( " << te << ", " << index << " ) returned 0" << llendl; + LL_WARNS() << "getImage( " << te << ", " << index << " ) returned 0" << LL_ENDL; return FALSE; } @@ -9023,107 +11226,3 @@ BOOL LLVOAvatar::isTextureVisible(LLAvatarAppearanceDefines::ETextureIndex type, return FALSE; } -U32 calc_shame(LLVOVolume* volume, std::set &textures) -{ - if (!volume) - { - return 0; - } - - U32 shame = 0; - - U32 invisi = 0; - U32 shiny = 0; - U32 glow = 0; - U32 alpha = 0; - U32 flexi = 0; - U32 animtex = 0; - U32 particles = 0; - U32 scale = 0; - U32 bump = 0; - U32 planar = 0; - - const LLVector3& sc = volume->getScale(); - scale += (U32) sc.mV[0] + (U32) sc.mV[1] + (U32) sc.mV[2]; - - if (volume->isFlexible()) - { - flexi = 1; - } - if (volume->isParticleSource()) - { - particles = 1; - } - - LLDrawable* drawablep = volume->mDrawable; - - if (volume->isSculpted()) - { - LLSculptParams *sculpt_params = (LLSculptParams *) volume->getParameterEntry(LLNetworkData::PARAMS_SCULPT); - LLUUID sculpt_id = sculpt_params->getSculptTexture(); - textures.insert(sculpt_id); - } - - for (S32 i = 0; i < drawablep->getNumFaces(); ++i) - { - LLFace* face = drawablep->getFace(i); - const LLTextureEntry* te = face->getTextureEntry(); - LLViewerTexture* img = face->getTexture(); - - textures.insert(img->getID()); - - if (face->getPoolType() == LLDrawPool::POOL_ALPHA) - { - alpha++; - } - else if (img->getPrimaryFormat() == GL_ALPHA) - { - invisi = 1; - } - - if (te) - { - if (te->getBumpmap()) - { - bump = 1; - } - if (te->getShiny()) - { - shiny = 1; - } - if (te->getGlow() > 0.f) - { - glow = 1; - } - if (face->mTextureMatrix != NULL) - { - animtex++; - } - if (te->getTexGen()) - { - planar++; - } - } - } - - shame += invisi + shiny + glow + alpha*4 + flexi*8 + animtex*4 + particles*16+bump*4+scale+planar; - - LLViewerObject::const_child_list_t& child_list = volume->getChildren(); - for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); - iter != child_list.end(); iter++) - { - LLViewerObject* child_objectp = *iter; - LLDrawable* child_drawablep = child_objectp->mDrawable; - if (child_drawablep) - { - LLVOVolume* child_volumep = child_drawablep->getVOVolume(); - if (child_volumep) - { - shame += calc_shame(child_volumep, textures); - } - } - } - - return shame; -} - diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 11b5c1be66..d285274998 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -50,10 +50,14 @@ #include "lldriverparam.h" #include "llviewertexlayer.h" #include "material_codes.h" // LL_MCODE_END +#include "llrigginginfo.h" #include "llviewerstats.h" - +#include "llvovolume.h" #include "llavatarname.h" +// +#if 0 +// Hide these: should be using the bit masks everywhere. extern const LLUUID ANIM_AGENT_BODY_NOISE; extern const LLUUID ANIM_AGENT_BREATHE_ROT; extern const LLUUID ANIM_AGENT_PHYSICS_MOTION; @@ -65,6 +69,8 @@ extern const LLUUID ANIM_AGENT_HEAD_ROT; extern const LLUUID ANIM_AGENT_PELVIS_FIX; extern const LLUUID ANIM_AGENT_TARGET; extern const LLUUID ANIM_AGENT_WALK_ADJUST; +#endif +// class LLAPRFile; class LLViewerWearable; @@ -74,6 +80,9 @@ class LLHUDEffectSpiral; class LLTexGlobalColor; class LLViewerJoint; struct LLAppearanceMessageContents; +class LLMeshSkinInfo; +class LLViewerJointMesh; +class LLControlAvatar; class SHClientTagMgr : public LLSingleton, public boost::signals2::trackable { @@ -176,17 +185,18 @@ class LLVOAvatar : /*virtual*/ BOOL updateLOD(); BOOL updateJointLODs(); void updateLODRiggedAttachments( void ); + void updateSoftwareSkinnedVertices(const LLMeshSkinInfo* skin, const LLVector4a* weight, const LLVolumeFace& vol_face, LLVertexBuffer *buffer); /*virtual*/ BOOL isActive() const; // Whether this object needs to do an idleUpdate. - S32 totalTextureMemForUUIDS(std::set& ids); - bool allTexturesCompletelyDownloaded(std::set& ids) const; + S32Bytes totalTextureMemForUUIDS(uuid_set_t& ids); + bool allTexturesCompletelyDownloaded(uuid_set_t& ids) const; bool allLocalTexturesCompletelyDownloaded() const; bool allBakedTexturesCompletelyDownloaded() const; void bakedTextureOriginCounts(S32 &sb_count, S32 &host_count, S32 &both_count, S32 &neither_count); std::string bakedTextureOriginInfo(); - void collectLocalTextureUUIDs(std::set& ids) const; - void collectBakedTextureUUIDs(std::set& ids) const; - void collectTextureUUIDs(std::set& ids); + void collectLocalTextureUUIDs(uuid_set_t& ids) const; + void collectBakedTextureUUIDs(uuid_set_t& ids) const; + void collectTextureUUIDs(uuid_set_t& ids); void releaseOldTextures(); /*virtual*/ void updateTextures(); LLViewerFetchedTexture* getBakedTextureImage(const U8 te, const LLUUID& uuid); @@ -200,23 +210,26 @@ class LLVOAvatar : /*virtual*/ void setPixelAreaAndAngle(LLAgent &agent); /*virtual*/ void updateRegion(LLViewerRegion *regionp); /*virtual*/ void updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax); - /*virtual*/ void getSpatialExtents(LLVector4a& newMin, LLVector4a& newMax); - /*virtual*/ BOOL lineSegmentIntersect(const LLVector3& start, const LLVector3& end, + void calculateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax); + /*virtual*/ BOOL lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, S32 face = -1, // which face to check, -1 = ALL_SIDES BOOL pick_transparent = FALSE, + BOOL pick_rigged = FALSE, S32* face_hit = NULL, // which face was hit - LLVector3* intersection = NULL, // return the intersection point + LLVector4a* intersection = NULL, // return the intersection point LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point - LLVector3* normal = NULL, // return the surface normal at the intersection point - LLVector3* bi_normal = NULL); // return the surface bi-normal at the intersection point - LLViewerObject* lineSegmentIntersectRiggedAttachments(const LLVector3& start, const LLVector3& end, + LLVector4a* normal = NULL, // return the surface normal at the intersection point + LLVector4a* tangent = NULL); // return the surface tangent at the intersection point + virtual LLViewerObject* lineSegmentIntersectRiggedAttachments( + const LLVector4a& start, const LLVector4a& end, S32 face = -1, // which face to check, -1 = ALL_SIDES BOOL pick_transparent = FALSE, + BOOL pick_rigged = FALSE, S32* face_hit = NULL, // which face was hit - LLVector3* intersection = NULL, // return the intersection point + LLVector4a* intersection = NULL, // return the intersection point LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point - LLVector3* normal = NULL, // return the surface normal at the intersection point - LLVector3* bi_normal = NULL); // return the surface bi-normal at the intersection point + LLVector4a* normal = NULL, // return the surface normal at the intersection point + LLVector4a* tangent = NULL); // return the surface tangent at the intersection point //-------------------------------------------------------------------- // LLCharacter interface and related @@ -230,6 +243,11 @@ class LLVOAvatar : /*virtual*/ LLUUID remapMotionID(const LLUUID& id); /*virtual*/ BOOL startMotion(const LLUUID& id, F32 time_offset = 0.f); /*virtual*/ BOOL stopMotion(const LLUUID& id, BOOL stop_immediate = FALSE); + // + void startMotion(U32 bit, F32 start_offset = 0.f); + void stopMotion(U32 bit, BOOL stop_immediate = FALSE); + // + virtual bool hasMotionFromSource(const LLUUID& source_id); virtual void stopMotionFromSource(const LLUUID& source_id); virtual void requestStopMotion(LLMotion* motion); LLMotion* findMotion(const LLUUID& id) const; @@ -237,10 +255,29 @@ class LLVOAvatar : void dumpAnimationState(); virtual LLJoint* getJoint(const std::string &name); + LLJoint* getJoint(S32 num); - void resetJointPositionsToDefault( void ); - void resetSpecificJointPosition( const std::string& name ); + void addAttachmentOverridesForObject(LLViewerObject *vo, uuid_set_t* meshes_seen = NULL, bool recursive = true); + void removeAttachmentOverridesForObject(const LLUUID& mesh_id); + void removeAttachmentOverridesForObject(LLViewerObject *vo); + bool jointIsRiggedTo(const LLJoint *joint) const; + void clearAttachmentOverrides(); + void rebuildAttachmentOverrides(); + void updateAttachmentOverrides(); + void showAttachmentOverrides(bool verbose = false) const; + void getAttachmentOverrideNames( std::set& pos_names, + std::set& scale_names) const; + + void getAssociatedVolumes(std::vector& volumes); + + // virtual + void updateRiggingInfo(); + // This encodes mesh id and LOD, so we can see whether display is up-to-date. + std::map mLastRiggingInfoKey; + uuid_set_t mActiveOverrideMeshes; + virtual void onActiveOverrideMeshesChanged(); + /*virtual*/ const LLUUID& getID() const; /*virtual*/ void addDebugText(const std::string& text); /*virtual*/ F32 getTimeDilation(); @@ -263,6 +300,9 @@ class LLVOAvatar : public: virtual bool isSelf() const { return false; } // True if this avatar is for this viewer's agent + bool isControlAvatar() const { return mIsControlAvatar; } // True if this avatar is a control av (no associated user) + virtual LLControlAvatar* asControlAvatar() { return nullptr; } + bool isUIAvatar() const { return mIsUIAvatar; } // True if this avatar is a supplemental av used in some UI views (no associated user) private: //aligned members LL_ALIGN_16(LLVector4a mImpostorExtents[2]); @@ -273,7 +313,16 @@ class LLVOAvatar : // Updates //-------------------------------------------------------------------- public: + void updateAppearanceMessageDebugText(); + void updateAnimationDebugText(); + virtual void updateDebugText(); virtual BOOL updateCharacter(LLAgent &agent); + void updateFootstepSounds(); + void computeUpdatePeriod(); + void updateOrientation(LLAgent &agent, F32 speed, F32 delta_time); + void updateTimeStep(); + void updateRootPositionAndRotation(LLAgent &agent, F32 speed, bool was_sit_ground_constrained); + void idleUpdateVoiceVisualizer(bool voice_enabled); void idleUpdateMisc(bool detailed_update); virtual void idleUpdateAppearanceAnimation(); @@ -290,7 +339,26 @@ class LLVOAvatar : // force all name tags to rebuild, useful when display names turned on/off static void invalidateNameTags(); void addNameTagLine(const std::string& line, const LLColor4& color, S32 style, const LLFontGL* font); - void idleUpdateRenderCost(); + void idleUpdateRenderComplexity(); + void accountRenderComplexityForObject(const LLViewerObject *attached_object, + const F32 max_attachment_complexity, + LLVOVolume::texture_cost_t& textures, + U32& cost/*, + hud_complexity_list_t& hud_complexity_list*/); + void calculateUpdateRenderComplexity(); + static const U32 VISUAL_COMPLEXITY_UNKNOWN; + void updateVisualComplexity(); + + U32 getVisualComplexity() { return mVisualComplexity; }; // Numbers calculated here by rendering AV + F32 getAttachmentSurfaceArea() { return mAttachmentSurfaceArea; }; // estimated surface area of attachments + + U32 getReportedVisualComplexity() { return mReportedVisualComplexity; }; // Numbers as reported by the SL server + void setReportedVisualComplexity(S32 value) { mReportedVisualComplexity = value; }; + + S32 getUpdatePeriod() { return mUpdatePeriod; }; + + static void updateImpostorRendering(U32 newMaxNonImpostorsValue); + void idleUpdateBelowWater(); //-------------------------------------------------------------------- @@ -302,13 +370,13 @@ class LLVOAvatar : static U32 sMaxVisible; //(affected by control "RenderAvatarMaxVisible") static F32 sRenderDistance; //distance at which avatars will render. static BOOL sShowAnimationDebug; // show animation debug info - static BOOL sUseImpostors; //use impostors for far away avatars - static BOOL sShowFootPlane; // show foot collision plane reported by server - static BOOL sVisibleInFirstPerson; + static bool sUseImpostors; //use impostors for far away avatars + static bool sShowFootPlane; // show foot collision plane reported by server + static bool sVisibleInFirstPerson; static S32 sNumLODChangesThisFrame; static S32 sNumVisibleChatBubbles; static BOOL sDebugInvisible; - static BOOL sShowAttachmentPoints; + static bool sShowAttachmentPoints; static F32 sLODFactor; // user-settable LOD factor static F32 sPhysicsLODFactor; // user-settable physics LOD factor static BOOL sJointDebug; // output total number of joints being touched for each avatar @@ -337,6 +405,7 @@ class LLVOAvatar : S32 mLastRezzedStatus; + void startPhase(const std::string& phase_name); void stopPhase(const std::string& phase_name, bool err_check = true); void clearPhases(); @@ -350,13 +419,13 @@ class LLVOAvatar : BOOL processFullyLoadedChange(bool loading); void updateRuthTimer(bool loading); F32 calcMorphAmount(); + private: BOOL mFirstFullyVisible; BOOL mFullyLoaded; BOOL mPreviousFullyLoaded; BOOL mFullyLoadedInitialized; S32 mFullyLoadedFrameCounter; - S32 mVisualComplexity; LLFrameTimer mFullyLoadedTimer; LLFrameTimer mRuthTimer; bool mFreezeTimeLangolier; // True when this avatar was created during snapshot FreezeTime mode, and that mode is still active. @@ -383,19 +452,16 @@ class LLVOAvatar : /*virtual*/ LLAvatarJointMesh* createAvatarJointMesh(); // Returns LLViewerJointMesh public: void updateHeadOffset(); - void setPelvisOffset( bool hasOffset, const LLVector3& translation, F32 offset ) ; - bool hasPelvisOffset( void ) { return mHasPelvisOffset; } void postPelvisSetRecalc( void ); - void setPelvisOffset( F32 pelvixFixupAmount ); /*virtual*/ BOOL loadSkeletonNode(); + void initAttachmentPoints(bool ignore_hud_joints = false); /*virtual*/ void buildCharacter(); + void resetVisualParams(); + void resetSkeleton(bool reset_animations); - bool mHasPelvisOffset; - LLVector3 mPelvisOffset; - F32 mLastPelvisToFoot; - F32 mPelvisFixup; - F32 mLastPelvisFixup; + LLVector3 mCurRootToHeadOffset; + LLVector3 mTargetRootToHeadOffset; S32 mLastSkeletonSerialNum; @@ -420,14 +486,16 @@ class LLVOAvatar : U32 renderSkinnedAttachments(); U32 renderTransparent(BOOL first_pass); void renderCollisionVolumes(); + void renderBones(); + void renderJoints(); static void deleteCachedImages(bool clearAll=true); static void destroyGL(); static void restoreGL(); S32 mSpecialRenderMode; // special lighting - U32 mAttachmentGeometryBytes; //number of bytes in attached geometry - F32 mAttachmentSurfaceArea; //estimated surface area of attachments - private: + F32 mAttachmentSurfaceArea; //estimated surface area of attachments + U32 mAttachmentVisibleTriangleCount; + F32 mAttachmentEstTriangleCount; bool shouldAlphaMask(); BOOL mNeedsSkin; // avatar has been animated and verts have not been updated @@ -436,6 +504,19 @@ class LLVOAvatar : S32 mUpdatePeriod; S32 mNumInitFaces; //number of faces generated when creating the avatar drawable, does not inculde splitted faces due to long vertex buffer. + // the isTooComplex method uses these mutable values to avoid recalculating too frequently + mutable U32 mVisualComplexity; + mutable bool mVisualComplexityStale; + U32 mReportedVisualComplexity; // from other viewers through the simulator + + //-------------------------------------------------------------------- + // animated object status + //-------------------------------------------------------------------- +public: + bool mIsControlAvatar; + bool mIsUIAvatar; + bool mEnableDefaultMotions; + //-------------------------------------------------------------------- // Morph masks //-------------------------------------------------------------------- @@ -448,7 +529,7 @@ class LLVOAvatar : // Global colors //-------------------------------------------------------------------- public: - /*virtual*/void onGlobalColorChanged(const LLTexGlobalColor* global_color, BOOL upload_bake); + /*virtual*/void onGlobalColorChanged(const LLTexGlobalColor* global_color, bool upload_bake = false); //-------------------------------------------------------------------- // Visibility @@ -474,8 +555,9 @@ class LLVOAvatar : // Impostors //-------------------------------------------------------------------- public: - BOOL isImpostor() const; - BOOL needsImpostorUpdate() const; + virtual BOOL isImpostor() const; + BOOL shouldImpostor(const U32 rank_factor = 1) const; + BOOL needsImpostorUpdate() const; const LLVector3& getImpostorOffset() const; const LLVector2& getImpostorDim() const; void getImpostorValues(LLVector4a* extents, LLVector3& angle, F32& distance) const; @@ -485,14 +567,20 @@ class LLVOAvatar : static void updateImpostors(); LLRenderTarget mImpostor; BOOL mNeedsImpostorUpdate; + F32SecondsImplicit mLastImpostorUpdateFrameTime; + const LLVector3* getLastAnimExtents() const { return mLastAnimExtents; } + void setNeedsExtentUpdate(bool val) { mNeedsExtentUpdate = val; } + private: LLVector3 mImpostorOffset; LLVector2 mImpostorDim; BOOL mNeedsAnimUpdate; + bool mNeedsExtentUpdate; LLVector3 mImpostorAngle; F32 mImpostorDistance; F32 mImpostorPixelArea; LLVector3 mLastAnimExtents[2]; + LLVector3 mLastAnimBasePos; //-------------------------------------------------------------------- // Wind rippling in clothes @@ -573,7 +661,7 @@ class LLVOAvatar : LLLoadedCallbackEntry::source_callback_list_t mCallbackTextureList ; BOOL mLoadedCallbacksPaused; - std::set mTextureIDs; + uuid_set_t mTextureIDs; //-------------------------------------------------------------------- // Local Textures //-------------------------------------------------------------------- @@ -643,9 +731,12 @@ class LLVOAvatar : public: void debugColorizeSubMeshes(U32 i, const LLColor4& color); virtual void updateMeshTextures(); - void updateSexDependentLayerSets(BOOL upload_bake); + void updateSexDependentLayerSets(bool upload_bake = false); virtual void dirtyMesh(); // Dirty the avatar mesh void updateMeshData(); + void updateMeshVisibility(); + LLViewerTexture* getBakedTexture(const U8 te); + protected: void releaseMeshData(); virtual void restoreMeshData(); @@ -671,12 +762,14 @@ class LLVOAvatar : ** APPEARANCE **/ + LLPointer mLastProcessedAppearance; + public: void parseAppearanceMessage(LLMessageSystem* mesgsys, LLAppearanceMessageContents& msg); void processAvatarAppearance(LLMessageSystem* mesgsys); + void applyParsedAppearanceMessage(LLAppearanceMessageContents& contents, bool slam_params); void hideSkirt(); void startAppearanceAnimation(); - /*virtual*/ void bodySizeChanged(); //-------------------------------------------------------------------- // Appearance morphing @@ -714,6 +807,7 @@ class LLVOAvatar : //-------------------------------------------------------------------- public: BOOL isVisible() const; + virtual bool shouldRenderRigged() const; void setVisibilityRank(U32 rank); U32 getVisibilityRank() const { return mVisibilityRank; } // unused static S32 sNumVisibleAvatars; // Number of instances of this class @@ -733,11 +827,14 @@ class LLVOAvatar : void clampAttachmentPositions(); virtual const LLViewerJointAttachment* attachObject(LLViewerObject *viewer_object); virtual BOOL detachObject(LLViewerObject *viewer_object); + static bool getRiggedMeshID( LLViewerObject* pVO, LLUUID& mesh_id ); void cleanupAttachedMesh( LLViewerObject* pVO ); static LLVOAvatar* findAvatarFromAttachment(LLViewerObject* obj); /*virtual*/ BOOL isWearingWearableType(LLWearableType::EType type ) const; -protected: + LLViewerObject * findAttachmentByID( const LLUUID & target_id ) const; LLViewerJointAttachment* getTargetAttachmentPoint(LLViewerObject* viewer_object); + +protected: void lazyAttach(); void rebuildRiggedAttachments( void ); @@ -759,11 +856,12 @@ class LLVOAvatar : BOOL hasHUDAttachment() const; LLBBox getHUDBBox() const; void resetHUDAttachments(); - BOOL canAttachMoreObjects() const; - BOOL canAttachMoreObjects(U32 n) const; + BOOL canAttachMoreObjects(U32 n=1) const; + U32 getMaxAnimatedObjectAttachments() const; + BOOL canAttachMoreAnimatedObjects(U32 n=1) const; protected: U32 getNumAttachments() const; // O(N), not O(1) - + U32 getNumAnimatedObjectAttachments() const; // O(N), not O(1) //-------------------------------------------------------------------- // Old/nonstandard/Agent-only functions //-------------------------------------------------------------------- @@ -771,7 +869,6 @@ class LLVOAvatar : BOOL isWearingAttachment( const LLUUID& inv_item_id ); LLViewerObject* getWornAttachment( const LLUUID& inv_item_id ); - const std::string getAttachedPointName(const LLUUID& inv_item_id); /** Wearables ** ** @@ -893,6 +990,8 @@ class LLVOAvatar : private: // set this property only with LLVOAvatar::sitDown method BOOL mIsSitting; + // position backup in case of missing data + LLVector3 mLastRootPos; /** Hierarchy ** ** @@ -904,11 +1003,11 @@ class LLVOAvatar : **/ public: - /*virtual*/ std::string getFullname() const; // Returns "FirstName LastName" + std::string getFullname() const; // Returns "FirstName LastName" std::string avString() const; // Frequently used string in log messages "Avatar '* labels); - static void getAnimNames(LLDynamicArray* names); + static void getAnimLabels(std::vector* labels); + static void getAnimNames(std::vector* names); private: std::string mNameString; // UTF-8 title + name + status std::string mTitle; @@ -987,13 +1086,13 @@ class LLVOAvatar : // General //-------------------------------------------------------------------- public: + void getSortedJointNames(S32 joint_type, std::vector& result) const; static void dumpArchetypeXML_header(LLAPRFile& file, std::string const& archetype_name = "???"); static void dumpArchetypeXML_footer(LLAPRFile& file); void dumpArchetypeXML(const std::string& prefix, bool group_by_wearables = false); void dumpArchetypeXML_cont(std::string const& fullpath, bool group_by_wearables); void dumpAppearanceMsgParams( const std::string& dump_prefix, - const std::vector& paramsForDump, - const LLTEContents& tec); + const LLAppearanceMessageContents& contents); static void dumpBakedStatus(); const std::string getBakedStatusForPrintout() const; void dumpAvatarTEs(const std::string& context) const; @@ -1023,6 +1122,18 @@ class LLVOAvatar : protected: LLFrameTimer mRuthDebugTimer; // For tracking how long it takes for av to rez LLFrameTimer mDebugExistenceTimer; // Debugging for how long the avatar has been in memory. + LLFrameTimer mLastAppearanceMessageTimer; // Time since last appearance message received. + + //-------------------------------------------------------------------- + // COF monitoring + //-------------------------------------------------------------------- + +public: + // COF version of last viewer-initiated appearance update request. For non-self avs, this will remain at default. + S32 mLastUpdateRequestCOFVersion; + + // COF version of last appearance message received for this av. + S32 mLastUpdateReceivedCOFVersion; /** Diagnostics ** ** @@ -1039,6 +1150,21 @@ class LLVOAvatar : /** Support classes ** ** *******************************************************************************/ + +public: + typedef std::array rigged_matrix_array_t; + typedef std::vector > > rigged_transformation_cache_t; + rigged_transformation_cache_t& getRiggedMatrixCache() + { + return mRiggedMatrixDataCache; + } + void clearRiggedMatrixCache() + { + mRiggedMatrixDataCache.clear(); + } +private: + rigged_transformation_cache_t mRiggedMatrixDataCache; + // //Avatar idle timer @@ -1049,6 +1175,8 @@ class LLVOAvatar : private: S32 mIdleMinute; + LLTimer mComplexityTimer; + //CCS Nametag public: void setNameFromChat(const std::string &text); @@ -1062,8 +1190,15 @@ class LLVOAvatar : // }; // LLVOAvatar - extern const F32 SELF_ADDITIONAL_PRI; -extern const S32 MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL; +extern const S32 MAX_TEXTURE_VIRTUAL_SIZE_RESET_INTERVAL; + +extern const F32 MAX_HOVER_Z; +extern const F32 MIN_HOVER_Z; + +constexpr U32 NUM_ATTACHMENT_GROUPS = 24; + +void dump_sequential_xml(const std::string outprefix, const LLSD& content); #endif // LL_VOAVATAR_H + diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index 63ac07e0db..29d31f0902 100644 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -24,11 +24,6 @@ * $/LicenseInfo$ */ -#if LL_MSVC -// disable warning about boost::lexical_cast returning uninitialized data -// when it fails to parse the string -#pragma warning (disable:4701) -#endif #include "llviewerprecompiledheaders.h" @@ -43,6 +38,7 @@ #include "llhudeffecttrail.h" #include "llhudmanager.h" #include "llinventoryfunctions.h" +#include "lllocaltextureobject.h" #include "llnotificationsutil.h" #include "llselectmgr.h" #include "lltoolgrab.h" // for needsRenderBeam @@ -54,6 +50,7 @@ #include "llviewermedia.h" #include "llviewermenu.h" #include "llviewerobjectlist.h" +#include "llviewerparcelmgr.h" #include "llviewerstats.h" #include "llviewerregion.h" #include "llviewertexlayer.h" @@ -68,12 +65,6 @@ #include "rlvlocks.h" // [/RLVa:KB] -#if LL_MSVC -// disable boost::lexical_cast warning -#pragma warning (disable:4702) -#endif - -#include LLPointer gAgentAvatarp = NULL; @@ -146,15 +137,6 @@ struct LocalTextureData ** ** *********************************************************************************/ - -//----------------------------------------------------------------------------- -// Static Data -//----------------------------------------------------------------------------- -S32 LLVOAvatarSelf::sScratchTexBytes = 0; -LLMap< LLGLenum, LLGLuint*> LLVOAvatarSelf::sScratchTexNames; -LLMap< LLGLenum, F32*> LLVOAvatarSelf::sScratchTexLastBindTime; - - /********************************************************************************* ** ** ** Begin LLVOAvatarSelf Constructor routines @@ -171,7 +153,10 @@ LLVOAvatarSelf::LLVOAvatarSelf(const LLUUID& id, mScreenp(NULL), mLastRegionHandle(0), mRegionCrossingCount(0), - mInitialBakesLoaded(false) + //mInitialBakesLoaded(false), + // Value outside legal range, so will always be a mismatch the + // first time through. + mLastHoverOffsetSent(LLVector3(0.0f, 0.0f, -999.0f)) { gAgentWearables.setAvatarObject(this); gAgentCamera.setAvatarObject(this); @@ -180,7 +165,9 @@ LLVOAvatarSelf::LLVOAvatarSelf(const LLUUID& id, SHClientTagMgr::instance().updateAvatarTag(this); //No TE update messages for self. Force update here. - lldebugs << "Marking avatar as self " << id << llendl; + mTeleportFinishedSlot = LLViewerParcelMgr::getInstance()->setTeleportFinishedCallback(boost::bind(&LLVOAvatarSelf::handleTeleportFinished, this)); + + LL_DEBUGS() << "Marking avatar as self " << id << LL_ENDL; } // Called periodically for diagnostics, return true when done. @@ -209,7 +196,7 @@ bool check_for_unsupported_baked_appearance() return true; gAgentAvatarp->checkForUnsupportedServerBakeAppearance(); - return false; + return LLApp::isExiting(); } void force_bake_all_textures() @@ -227,7 +214,7 @@ void LLVOAvatarSelf::initInstance() // adds attachment points to mScreen among other things LLVOAvatar::initInstance(); - llinfos << "Self avatar object created. Starting timer." << llendl; + LL_INFOS() << "Self avatar object created. Starting timer." << LL_ENDL; mDebugSelfLoadTimer.reset(); // clear all times to -1 for debugging for (U32 i =0; i < LLAvatarAppearanceDefines::TEX_NUM_INDICES; ++i) @@ -252,13 +239,73 @@ void LLVOAvatarSelf::initInstance() status &= buildMenus(); if (!status) { - llerrs << "Unable to load user's avatar" << llendl; + LL_ERRS() << "Unable to load user's avatar" << LL_ENDL; return; } + setHoverIfRegionEnabled(); + //doPeriodically(output_self_av_texture_diagnostics, 30.0); doPeriodically(update_avatar_rez_metrics, 5.0); doPeriodically(check_for_unsupported_baked_appearance, 120.0); + doPeriodically(boost::bind(&LLVOAvatarSelf::checkStuckAppearance, this), 30.0); + + mInitFlags |= 1<<2; +} + +void LLVOAvatarSelf::setHoverIfRegionEnabled(bool send_update) +{ + LLViewerRegion* region = getRegion(); + if (region && region->simulatorFeaturesReceived()) + { + if (region->avatarHoverHeightEnabled()) + { + F32 hover_z = gSavedPerAccountSettings.getF32("AvatarHoverOffsetZ"); + setHoverOffset(LLVector3(0.0, 0.0, llclamp(hover_z, MIN_HOVER_Z, MAX_HOVER_Z))); + LL_INFOS("Avatar") << avString() << " set hover height from debug setting " << hover_z << LL_ENDL; + } + else + { + setHoverOffset(LLVector3(0.0, 0.0, 0.0)); + LL_INFOS("Avatar") << avString() << " zeroing hover height, region does not support" << LL_ENDL; + } + } + else + { + LL_INFOS("Avatar") << avString() << " region or simulator features not known, no change on hover" << LL_ENDL; + if (region) + { + region->setSimulatorFeaturesReceivedCallback(boost::bind(&LLVOAvatarSelf::onSimulatorFeaturesReceived, this, _1)); + } + } +} + +bool LLVOAvatarSelf::checkStuckAppearance() +{ + if (!gAgentAvatarp->isUsingServerBakes()) + return false; + const F32 CONDITIONAL_UNSTICK_INTERVAL = 300.0; + const F32 UNCONDITIONAL_UNSTICK_INTERVAL = 600.0; + + if (gAgentWearables.isCOFChangeInProgress()) + { + LL_DEBUGS("Avatar") << "checking for stuck appearance" << LL_ENDL; + F32 change_time = gAgentWearables.getCOFChangeTime(); + LL_DEBUGS("Avatar") << "change in progress for " << change_time << " seconds" << LL_ENDL; + S32 active_hp = LLAppearanceMgr::instance().countActiveHoldingPatterns(); + LL_DEBUGS("Avatar") << "active holding patterns " << active_hp << " seconds" << LL_ENDL; + S32 active_copies = LLAppearanceMgr::instance().getActiveCopyOperations(); + LL_DEBUGS("Avatar") << "active copy operations " << active_copies << LL_ENDL; + + if ((change_time > CONDITIONAL_UNSTICK_INTERVAL && active_copies == 0) || + (change_time > UNCONDITIONAL_UNSTICK_INTERVAL)) + { + gAgentWearables.notifyLoadingFinished(); + } + } + + // Return false to continue running check periodically. + return LLApp::isExiting(); } // virtual @@ -272,7 +319,7 @@ void LLVOAvatarSelf::markDead() { BOOL success = LLVOAvatar::loadAvatar(); - // set all parameters sotred directly in the avatar to have + // set all parameters stored directly in the avatar to have // the isSelfParam to be TRUE - this is used to prevent // them from being animated or trigger accidental rebakes // when we copy params from the wearable to the base avatar. @@ -296,7 +343,7 @@ BOOL LLVOAvatarSelf::loadAvatarSelf() // avatar_skeleton.xml if (!buildSkeletonSelf(sAvatarSkeletonInfo)) { - llwarns << "avatar file: buildSkeleton() failed" << llendl; + LL_WARNS() << "avatar file: buildSkeleton() failed" << LL_ENDL; return FALSE; } @@ -323,121 +370,136 @@ BOOL LLVOAvatarSelf::buildMenus() //------------------------------------------------------------------------- // build the attach and detach menus //------------------------------------------------------------------------- - if(gNoRender) - return TRUE; - gAttachBodyPartPieMenus[0] = NULL; - gAttachBodyPartPieMenus[1] = new LLPieMenu(LLTrans::getString("BodyPartsRightArm") + " >"); - gAttachBodyPartPieMenus[2] = new LLPieMenu(LLTrans::getString("BodyPartsHead") + " >"); - gAttachBodyPartPieMenus[3] = new LLPieMenu(LLTrans::getString("BodyPartsLeftArm") + " >"); - gAttachBodyPartPieMenus[4] = NULL; - gAttachBodyPartPieMenus[5] = new LLPieMenu(LLTrans::getString("BodyPartsLeftLeg") + " >"); - gAttachBodyPartPieMenus[6] = new LLPieMenu(LLTrans::getString("BodyPartsTorso") + " >"); - gAttachBodyPartPieMenus[7] = new LLPieMenu(LLTrans::getString("BodyPartsRightLeg") + " >"); - - gDetachBodyPartPieMenus[0] = NULL; - gDetachBodyPartPieMenus[1] = new LLPieMenu(LLTrans::getString("BodyPartsRightArm") + " >"); - gDetachBodyPartPieMenus[2] = new LLPieMenu(LLTrans::getString("BodyPartsHead") + " >"); - gDetachBodyPartPieMenus[3] = new LLPieMenu(LLTrans::getString("BodyPartsLeftArm") + " >"); - gDetachBodyPartPieMenus[4] = NULL; - gDetachBodyPartPieMenus[5] = new LLPieMenu(LLTrans::getString("BodyPartsLeftLeg") + " >"); - gDetachBodyPartPieMenus[6] = new LLPieMenu(LLTrans::getString("BodyPartsTorso") + " >"); - gDetachBodyPartPieMenus[7] = new LLPieMenu(LLTrans::getString("BodyPartsRightLeg") + " >"); - - for (S32 i = 0; i < 8; i++) - { - if (gAttachBodyPartPieMenus[i]) - { - gAttachPieMenu->appendPieMenu( gAttachBodyPartPieMenus[i] ); - } - else - { - BOOL attachment_found = FALSE; - for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); - iter != mAttachmentPoints.end(); - ++iter) - { - LLViewerJointAttachment* attachment = iter->second; - if (attachment->getGroup() == i) - { - LLMenuItemCallGL* item; -// [RLVa:KB] - Checked: 2009-07-06 (RLVa-1.0.0c) - // We need the userdata param to disable options in this pie menu later on (Left Hand / Right Hand option) - item = new LLMenuItemCallGL(attachment->getName(), - NULL, - object_selected_and_point_valid, attachment); -// [/RLVa:KB] -// item = new LLMenuItemCallGL(attachment->getName(), -// NULL, -// object_selected_and_point_valid); - item->addListener(gMenuHolder->getListenerByName("Object.AttachToAvatar"), "on_click", iter->first); - - gAttachPieMenu->addChild(item); + buildContextMenus(); - attachment_found = TRUE; - break; + init_meshes_and_morphs_menu(); - } + return TRUE; +} + +// Convenience function to create context or pie menu with label +static LLContextMenu* make_part_menu(const std::string& label, bool context) +{ + return context ? new LLContextMenu(label) : new LLPieMenu(label + " >"); +} + +void LLVOAvatarSelf::buildContextMenus() +{ + bool context(gSavedSettings.getBOOL("LiruUseContextMenus")); + + struct EntryData + { + const char * subMenu; + LLContextMenu* attachMenu; + LLContextMenu* detachMenu; + } entries[NUM_ATTACHMENT_GROUPS] = { + { nullptr, gAttachPieMenu, gDetachPieMenu }, //Group 0 = Right Hand + { "BodyPartsRightArm", gAttachPieMenu, gDetachPieMenu }, + { "BodyPartsHead", gAttachPieMenu, gDetachPieMenu }, + { "BodyPartsLeftArm", gAttachPieMenu, gDetachPieMenu }, + { nullptr, gAttachPieMenu, gDetachPieMenu }, //Group 4 = Left Hand + { "BodyPartsLeftLeg", gAttachPieMenu, gDetachPieMenu }, + { "BodyPartsTorso", gAttachPieMenu, gDetachPieMenu }, + { "BodyPartsRightLeg", gAttachPieMenu, gDetachPieMenu }, + + // BENTO + { nullptr, gAttachPieMenu2, gDetachPieMenu2 }, // Group 8 = Right Ring Finger + { nullptr, gAttachPieMenu2, gDetachPieMenu2 }, // Group 9 = Right Wing + { "BodyPartsHead", gAttachPieMenu2, gDetachPieMenu2 }, + { nullptr, gAttachPieMenu2, gDetachPieMenu2 }, // Group 11 = Left Wing + { nullptr, gAttachPieMenu2, gDetachPieMenu2 }, // Group 12 = Left Ring Finger + { nullptr, gAttachPieMenu2, gDetachPieMenu2 }, // Group 13 = Left Hind Foot + { "BodyPartsWaist", gAttachPieMenu2, gDetachPieMenu2 }, + { nullptr, gAttachPieMenu2, gDetachPieMenu2 }, // Group 15 = Right Hind Foot + + // HUD + { nullptr, gAttachScreenPieMenu, gDetachScreenPieMenu }, // Group 16 = Center 2 + { nullptr, gAttachScreenPieMenu, gDetachScreenPieMenu }, // Group 17 = Top Right + { nullptr, gAttachScreenPieMenu, gDetachScreenPieMenu }, // Group 18 = Top + { nullptr, gAttachScreenPieMenu, gDetachScreenPieMenu }, // Group 19 = Top Left + { nullptr, gAttachScreenPieMenu, gDetachScreenPieMenu }, // Group 20 = Center + { nullptr, gAttachScreenPieMenu, gDetachScreenPieMenu }, // Group 21 = Bottom Left + { nullptr, gAttachScreenPieMenu, gDetachScreenPieMenu }, // Group 22 = Bottom + { nullptr, gAttachScreenPieMenu, gDetachScreenPieMenu } // Group 23 = Bottom Right + }; + + for (S32 group = 0; group < NUM_ATTACHMENT_GROUPS; group++) + { + LLContextMenu* attach_menu = entries[group].attachMenu; + LLContextMenu* detach_menu = entries[group].detachMenu; + + if (attach_menu && detach_menu) + { + if (entries[group].subMenu != nullptr) + { + std::string label = LLTrans::getString(entries[group].subMenu); + LLContextMenu* new_menu = make_part_menu(label, context); // Attach + attach_menu->appendContextSubMenu(new_menu); + attach_menu = new_menu; + new_menu = make_part_menu(label, context); // Detach + detach_menu->appendContextSubMenu(new_menu); + detach_menu = new_menu; } - if (!attachment_found) + if (!attach_menu || !detach_menu) { - gAttachPieMenu->addSeparator(); + continue; } - } - if (gDetachBodyPartPieMenus[i]) - { - gDetachPieMenu->appendPieMenu( gDetachBodyPartPieMenus[i] ); - } - else - { - BOOL attachment_found = FALSE; - for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); - iter != mAttachmentPoints.end(); - ++iter) + std::multimap attachment_pie_menu_map; + + // gather up all attachment points assigned to this group, and throw into map sorted by pie slice number + for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); + ++iter) { LLViewerJointAttachment* attachment = iter->second; - if (attachment->getGroup() == i) + if (attachment && attachment->getGroup() == group) { - gDetachPieMenu->addChild(new LLMenuItemCallGL(attachment->getName(), - &handle_detach_from_avatar, object_attached, attachment)); - - attachment_found = TRUE; - break; + // use multimap to provide a partial order off of the pie slice key + S32 pie_index = attachment->getPieSlice(); + attachment_pie_menu_map.insert(std::make_pair(pie_index, iter->first)); } } - if (!attachment_found) + // add in requested order to pie menu, inserting separators as necessary + for (std::multimap::iterator attach_it = attachment_pie_menu_map.begin(); + attach_it != attachment_pie_menu_map.end(); ++attach_it) { - gDetachPieMenu->addSeparator(); + if (!context) // Singu Note: Separators are only needed to keep slices of pies from moving + { + S32 requested_pie_slice = attach_it->first; + while ((S32)attach_menu->getItemCount() < requested_pie_slice) + { + attach_menu->addSeparator(); + detach_menu->addSeparator(); + } + } + S32 attach_index = attach_it->second; + + LLViewerJointAttachment* attachment = get_if_there(mAttachmentPoints, attach_index, (LLViewerJointAttachment*)NULL); + if (attachment) + { + // [RLVa:KB] - Checked: 2009-07-06 (RLVa-1.0.0c) + // We need the userdata param to disable options in this pie menu later on + LLMenuItemCallGL* item = new LLMenuItemCallGL(LLTrans::getString(attachment->getName()), + NULL, object_selected_and_point_valid, attachment); + // [/RLVa:KB] + // LLMenuItemCallGL* item = new LLMenuItemCallGL(LLTrans::getString(attachment->getName()), + // NULL, object_selected_and_point_valid); + attach_menu->addChild(item); + item->addListener(gMenuHolder->getListenerByName("Object.AttachToAvatar"), "on_click", attach_index); + detach_menu->addChild(new LLMenuItemCallGL(LLTrans::getString(attachment->getName()), + &handle_detach_from_avatar, + object_attached, attachment)); + } } } } - // add screen attachments - for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); - iter != mAttachmentPoints.end(); - ++iter) - { - LLViewerJointAttachment* attachment = iter->second; - if (attachment->getGroup() == 8) - { - LLMenuItemCallGL* item; -// [RLVa:KB] - Checked: 2009-07-06 (RLVa-1.0.0c) - // We need the userdata param to disable options in this pie menu later on - item = new LLMenuItemCallGL(attachment->getName(), - NULL, - object_selected_and_point_valid, attachment); -// [/RLVa:KB] -// item = new LLMenuItemCallGL(attachment->getName(), -// NULL, -// object_selected_and_point_valid); - item->addListener(gMenuHolder->getListenerByName("Object.AttachToAvatar"), "on_click", iter->first); - gAttachScreenPieMenu->addChild(item); - gDetachScreenPieMenu->addChild(new LLMenuItemCallGL(attachment->getName(), - &handle_detach_from_avatar, object_attached, attachment)); - } - } + //buildContextMenus can be called whenever "LiruUseContextMenus" setting changes. Clear out Edit->Attach/Detach menus before (re)populating them. + gAttachSubMenu->empty(); + gDetachSubMenu->empty(); for (S32 pass = 0; pass < 2; pass++) { @@ -456,85 +518,23 @@ BOOL LLVOAvatarSelf::buildMenus() continue; } // RELEASE-RLVa: random comment because we want know if LL ever changes this to not include "attachment" as userdata - LLMenuItemCallGL* item = new LLMenuItemCallGL(attachment->getName(), + LLMenuItemCallGL* item = new LLMenuItemCallGL(LLTrans::getString(attachment->getName()), NULL, &object_selected_and_point_valid, &attach_label, attachment); item->addListener(gMenuHolder->getListenerByName("Object.AttachToAvatar"), "on_click", iter->first); gAttachSubMenu->addChild(item); - gDetachSubMenu->addChild(new LLMenuItemCallGL(attachment->getName(), + gDetachSubMenu->addChild(new LLMenuItemCallGL(LLTrans::getString(attachment->getName()), &handle_detach_from_avatar, object_attached, &detach_label, attachment)); } - if (pass == 0) + if (!context && pass == 0) { // put separator between non-hud and hud attachments gAttachSubMenu->addSeparator(); gDetachSubMenu->addSeparator(); } } - - for (S32 group = 0; group < 8; group++) - { - // skip over groups that don't have sub menus - if (!gAttachBodyPartPieMenus[group] || !gDetachBodyPartPieMenus[group]) - { - continue; - } - - std::multimap attachment_pie_menu_map; - - // gather up all attachment points assigned to this group, and throw into map sorted by pie slice number - for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); - iter != mAttachmentPoints.end(); - ++iter) - { - LLViewerJointAttachment* attachment = iter->second; - if(attachment->getGroup() == group) - { - // use multimap to provide a partial order off of the pie slice key - S32 pie_index = attachment->getPieSlice(); - attachment_pie_menu_map.insert(std::make_pair(pie_index, iter->first)); - } - } - - // add in requested order to pie menu, inserting separators as necessary - S32 cur_pie_slice = 0; - for (std::multimap::iterator attach_it = attachment_pie_menu_map.begin(); - attach_it != attachment_pie_menu_map.end(); ++attach_it) - { - S32 requested_pie_slice = attach_it->first; - S32 attach_index = attach_it->second; - while (cur_pie_slice < requested_pie_slice) - { - gAttachBodyPartPieMenus[group]->addSeparator(); - gDetachBodyPartPieMenus[group]->addSeparator(); - cur_pie_slice++; - } - - LLViewerJointAttachment* attachment = get_if_there(mAttachmentPoints, attach_index, (LLViewerJointAttachment*)NULL); - if (attachment) - { -// [RLVa:KB] - Checked: 2009-07-06 (RLVa-1.0.0c) - // We need the userdata param to disable options in this pie menu later on - LLMenuItemCallGL* item = new LLMenuItemCallGL(attachment->getName(), - NULL, object_selected_and_point_valid, attachment); -// [/RLVa:KB] -// LLMenuItemCallGL* item = new LLMenuItemCallGL(attachment->getName(), -// NULL, object_selected_and_point_valid); - gAttachBodyPartPieMenus[group]->addChild(item); - item->addListener(gMenuHolder->getListenerByName("Object.AttachToAvatar"), "on_click", attach_index); - gDetachBodyPartPieMenus[group]->addChild(new LLMenuItemCallGL(attachment->getName(), - &handle_detach_from_avatar, - object_attached, attachment)); - cur_pie_slice++; - } - } - } - - init_meshes_and_morphs_menu(); - - return TRUE; } void LLVOAvatarSelf::cleanup() @@ -548,6 +548,9 @@ void LLVOAvatarSelf::cleanup() LLVOAvatarSelf::~LLVOAvatarSelf() { cleanup(); +// [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7) + delete mAttachmentSignal; +// [/RLVa:KB] } /** @@ -592,15 +595,31 @@ void LLVOAvatarSelf::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) // virtual LLJoint *LLVOAvatarSelf::getJoint(const std::string &name) { - if (mScreenp) + // - findJoint Opt + LLJoint* jointp = LLVOAvatar::getJoint(name); + if (!jointp && mScreenp) { - LLJoint* jointp = mScreenp->findJoint(name); - if (jointp) return jointp; + jointp = mScreenp->findJoint(name); + if (jointp) + { + joint_map_t::value_type entry; + strncpy(entry.first, name.c_str(), sizeof(entry.first)); + entry.second = jointp; + mJointMap.emplace_back(entry); + } } - return LLVOAvatar::getJoint(name); + return jointp; + + // + //if (mScreenp) + //{ + // LLJoint* jointp = mScreenp->findJoint(name); + // if (jointp) return jointp; + //} + //return LLVOAvatar::getJoint(name); } // virtual -BOOL LLVOAvatarSelf::setVisualParamWeight(const LLVisualParam *which_param, F32 weight, BOOL upload_bake ) +BOOL LLVOAvatarSelf::setVisualParamWeight(const LLVisualParam *which_param, F32 weight, bool upload_bake ) { if (!which_param) { @@ -611,7 +630,7 @@ BOOL LLVOAvatarSelf::setVisualParamWeight(const LLVisualParam *which_param, F32 } // virtual -BOOL LLVOAvatarSelf::setVisualParamWeight(const char* param_name, F32 weight, BOOL upload_bake ) +BOOL LLVOAvatarSelf::setVisualParamWeight(const char* param_name, F32 weight, bool upload_bake ) { if (!param_name) { @@ -622,27 +641,19 @@ BOOL LLVOAvatarSelf::setVisualParamWeight(const char* param_name, F32 weight, BO } // virtual -BOOL LLVOAvatarSelf::setVisualParamWeight(S32 index, F32 weight, BOOL upload_bake ) +BOOL LLVOAvatarSelf::setVisualParamWeight(S32 index, F32 weight, bool upload_bake ) { LLViewerVisualParam *param = (LLViewerVisualParam*) LLCharacter::getVisualParam(index); return setParamWeight(param,weight,upload_bake); } -BOOL LLVOAvatarSelf::setParamWeight(const LLViewerVisualParam *param, F32 weight, BOOL upload_bake ) +BOOL LLVOAvatarSelf::setParamWeight(const LLViewerVisualParam *param, F32 weight, bool upload_bake ) { if (!param) { return FALSE; } -#if 0 - // FIXME DRANO - kludgy way to avoid overwriting avatar state from wearables. - if (isUsingServerBakes() && !isUsingLocalAppearance()) - { - return FALSE; - } -#endif - if (param->getCrossWearable()) { LLWearableType::EType type = (LLWearableType::EType)param->getWearableType(); @@ -666,13 +677,8 @@ void LLVOAvatarSelf::updateVisualParams() LLVOAvatar::updateVisualParams(); } -/*virtual*/ -void LLVOAvatarSelf::idleUpdateAppearanceAnimation() +void LLVOAvatarSelf::writeWearablesToAvatar() { - // Animate all top-level wearable visual parameters - gAgentWearables.animateAllWearableParams(calcMorphAmount(), FALSE); - - // apply wearable visual params to avatar for (U32 type = 0; type < LLWearableType::WT_COUNT; type++) { LLWearable *wearable = gAgentWearables.getTopWearable((LLWearableType::EType)type); @@ -682,6 +688,17 @@ void LLVOAvatarSelf::idleUpdateAppearanceAnimation() } } +} + +/*virtual*/ +void LLVOAvatarSelf::idleUpdateAppearanceAnimation() +{ + // Animate all top-level wearable visual parameters + gAgentWearables.animateAllWearableParams(calcMorphAmount(), FALSE); + + // Apply wearable visual params to avatar + writeWearablesToAvatar(); + //allow avatar to process updates LLVOAvatar::idleUpdateAppearanceAnimation(); @@ -696,6 +713,13 @@ void LLVOAvatarSelf::requestStopMotion(LLMotion* motion) gAgent.requestStopMotion(motion); } +// virtual +bool LLVOAvatarSelf::hasMotionFromSource(const LLUUID& source_id) +{ + AnimSourceIterator motion_it = mAnimationSources.find(source_id); + return motion_it != mAnimationSources.end(); +} + // virtual void LLVOAvatarSelf::stopMotionFromSource(const LLUUID& source_id) { @@ -712,53 +736,6 @@ void LLVOAvatarSelf::stopMotionFromSource(const LLUUID& source_id) } } -//virtual -U32 LLVOAvatarSelf::processUpdateMessage(LLMessageSystem *mesgsys, - void **user_data, - U32 block_num, - const EObjectUpdateType update_type, - LLDataPacker *dp) -{ - U32 retval = LLVOAvatar::processUpdateMessage(mesgsys,user_data,block_num,update_type,dp); - -#if 0 - // DRANO - it's not clear this does anything useful. If we wait - // until an appearance message has been received, we already have - // the texture ids. If we don't wait, we don't yet know where to - // look for baked textures, because we haven't received the - // appearance version data from the appearance message. This looks - // like an old optimization that's incompatible with server-side - // texture baking. - - // FIXME DRANO - skipping in the case of !mFirstAppearanceMessageReceived prevents us from trying to - // load textures before we know where they come from (ie, from baking service or not); - // unknown impact on performance. - if (mInitialBakesLoaded == false && retval == 0x0 && mFirstAppearanceMessageReceived) - { - // call update textures to force the images to be created - updateMeshTextures(); - - // unpack the texture UUIDs to the texture slots - retval = unpackTEMessage(mesgsys, _PREHASH_ObjectData, (S32) block_num); - - // need to trigger a few operations to get the avatar to use the new bakes - for (U32 i = 0; i < mBakedTextureDatas.size(); i++) - { - const LLAvatarAppearanceDefines::ETextureIndex te = mBakedTextureDatas[i].mTextureIndex; - LLUUID texture_id = getTEImage(te)->getID(); - setNewBakedTexture(te, texture_id); - mInitialBakeIDs[i] = texture_id; - } - - onFirstTEMessageReceived(); - - mInitialBakesLoaded = true; - } -#endif - - return retval; -} - void LLVOAvatarSelf::setLocalTextureTE(U8 te, LLViewerTexture* image, U32 index) { if (te >= TEX_NUM_INDICES) @@ -796,7 +773,7 @@ void LLVOAvatarSelf::removeMissingBakedTextures() if (!tex || tex->isMissingAsset()) { LLViewerTexture *imagep = LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT_AVATAR); - if (imagep) + if (imagep && imagep != tex) { setTEImage(te, imagep); removed = TRUE; @@ -820,6 +797,12 @@ void LLVOAvatarSelf::removeMissingBakedTextures() } } +void LLVOAvatarSelf::onSimulatorFeaturesReceived(const LLUUID& region_id) +{ + LL_INFOS("Avatar") << "simulator features received, setting hover based on region props" << LL_ENDL; + setHoverIfRegionEnabled(); +} + //virtual void LLVOAvatarSelf::updateRegion(LLViewerRegion *regionp) { @@ -835,9 +818,20 @@ void LLVOAvatarSelf::updateRegion(LLViewerRegion *regionp) // Diagnostic info //LLVector3d pos_from_new_region = getPositionGlobal(); - //llinfos << "pos_from_old_region is " << global_pos_from_old_region + //LL_INFOS() << "pos_from_old_region is " << global_pos_from_old_region // << " while pos_from_new_region is " << pos_from_new_region - // << llendl; + // << LL_ENDL; + + // Update hover height, or schedule callback, based on whether + // it's supported in this region. + if (regionp->simulatorFeaturesReceived()) + { + setHoverIfRegionEnabled(); + } + else + { + regionp->setSimulatorFeaturesReceivedCallback(boost::bind(&LLVOAvatarSelf::onSimulatorFeaturesReceived,this,_1)); + } } if (!regionp || (regionp->getHandle() != mLastRegionHandle)) @@ -855,7 +849,7 @@ void LLVOAvatarSelf::updateRegion(LLViewerRegion *regionp) LLViewerStats::getInstance()->setStat(LLViewerStats::ST_CROSSING_MAX, max); // Diagnostics - llinfos << "Region crossing took " << (F32)(delta * 1000.0) << " ms " << llendl; + LL_INFOS() << "Region crossing took " << (F32)(delta * 1000.0) << " ms " << LL_ENDL; } if (regionp) { @@ -864,6 +858,7 @@ void LLVOAvatarSelf::updateRegion(LLViewerRegion *regionp) } mRegionCrossingTimer.reset(); LLViewerObject::updateRegion(regionp); + gAgent.setIsCrossingRegion(false); // Attachments getting lost on TP } //-------------------------------------------------------------------- @@ -872,9 +867,9 @@ void LLVOAvatarSelf::updateRegion(LLViewerRegion *regionp) //virtual void LLVOAvatarSelf::idleUpdateTractorBeam() { - - - if(gSavedSettings.getBOOL("DisablePointAtAndBeam")) + // + static LLCachedControl disable_pointat_effect("DisablePointAtAndBeam"); + if (disable_pointat_effect) { return; } @@ -943,7 +938,6 @@ void LLVOAvatarSelf::idleUpdateTractorBeam() mBeam->setPositionGlobal(pick.mPosGlobal); } - } if (mBeamTimer.getElapsedTimeF32() > 0.25f) { @@ -953,13 +947,14 @@ void LLVOAvatarSelf::idleUpdateTractorBeam() } } } + //----------------------------------------------------------------------------- // restoreMeshData() //----------------------------------------------------------------------------- // virtual void LLVOAvatarSelf::restoreMeshData() { - //llinfos << "Restoring" << llendl; + //LL_INFOS() << "Restoring" << LL_ENDL; mMeshValid = TRUE; updateJointLODs(); updateAttachmentVisibility(gAgentCamera.getCameraMode()); @@ -1040,13 +1035,6 @@ void LLVOAvatarSelf::wearableUpdated( LLWearableType::EType type, BOOL upload_re } } } - - // Physics type has no associated baked textures, but change of params needs to be sent to - // other avatars. - if (type == LLWearableType::WT_PHYSICS) - { - gAgent.sendAgentSetAppearance(); - } } //----------------------------------------------------------------------------- @@ -1068,44 +1056,6 @@ BOOL LLVOAvatarSelf::isWearingAttachment(const LLUUID& inv_item_id) const return FALSE; } -//----------------------------------------------------------------------------- -BOOL LLVOAvatarSelf::attachmentWasRequested(const LLUUID& inv_item_id) const -{ - const F32 REQUEST_EXPIRATION_SECONDS = 5.0; // any request older than this is ignored/removed. - std::map::iterator it = mAttachmentRequests.find(inv_item_id); - if (it != mAttachmentRequests.end()) - { - const LLTimer& request_time = it->second; - F32 request_time_elapsed = request_time.getElapsedTimeF32(); - if (request_time_elapsed > REQUEST_EXPIRATION_SECONDS) - { - mAttachmentRequests.erase(it); - return FALSE; - } - else - { - return TRUE; - } - } - else - { - return FALSE; - } -} - -//----------------------------------------------------------------------------- -void LLVOAvatarSelf::addAttachmentRequest(const LLUUID& inv_item_id) -{ - LLTimer current_time; - mAttachmentRequests[inv_item_id] = current_time; -} - -//----------------------------------------------------------------------------- -void LLVOAvatarSelf::removeAttachmentRequest(const LLUUID& inv_item_id) -{ - mAttachmentRequests.erase(inv_item_id); -} - //----------------------------------------------------------------------------- // getWornAttachment() //----------------------------------------------------------------------------- @@ -1147,9 +1097,19 @@ LLViewerJointAttachment* LLVOAvatarSelf::getWornAttachmentPoint(const LLUUID& id } // [/RLVa:KB] -const std::string LLVOAvatarSelf::getAttachedPointName(const LLUUID& inv_item_id) const +bool LLVOAvatarSelf::getAttachedPointName(const LLUUID& inv_item_id, std::string& name) const { + if (!gInventory.getItem(inv_item_id)) + { + name = "ATTACHMENT_MISSING_ITEM"; + return false; + } const LLUUID& base_inv_item_id = gInventory.getLinkedItemID(inv_item_id); + if (!gInventory.getItem(base_inv_item_id)) + { + name = "ATTACHMENT_MISSING_BASE_ITEM"; + return false; + } for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin(); iter != mAttachmentPoints.end(); ++iter) @@ -1157,11 +1117,13 @@ const std::string LLVOAvatarSelf::getAttachedPointName(const LLUUID& inv_item_id const LLViewerJointAttachment* attachment = iter->second; if (attachment->getAttachedObject(base_inv_item_id)) { - return attachment->getName(); + name = attachment->getName(); + return true; } } - return LLStringUtil::null; + name = "ATTACHMENT_NOT_ATTACHED"; + return false; } //virtual @@ -1182,8 +1144,6 @@ const LLViewerJointAttachment *LLVOAvatarSelf::attachObject(LLViewerObject *view { const LLUUID& attachment_id = viewer_object->getAttachmentItemID(); LLAppearanceMgr::instance().registerAttachment(attachment_id); - // Clear any pending requests once the attachment arrives. - removeAttachmentRequest(attachment_id); updateLODRiggedAttachments(); // [RLVa:KB] - Checked: 2010-08-22 (RLVa-1.2.1a) | Modified: RLVa-1.2.1a @@ -1201,7 +1161,6 @@ const LLViewerJointAttachment *LLVOAvatarSelf::attachObject(LLViewerObject *view gRlvAttachmentLocks.updateLockedHUD(); } // [/RLVa:KB] - } return attachment; @@ -1214,24 +1173,20 @@ BOOL LLVOAvatarSelf::detachObject(LLViewerObject *viewer_object) // [RLVa:KB] - Checked: 2010-03-05 (RLVa-1.2.0a) | Added: RLVa-1.2.0a // NOTE: RLVa event handlers should be invoked *before* LLVOAvatar::detachObject() calls LLViewerJointAttachment::removeObject() - + if (rlv_handler_t::isEnabled()) { for (attachment_map_t::const_iterator itAttachPt = mAttachmentPoints.begin(); itAttachPt != mAttachmentPoints.end(); ++itAttachPt) { const LLViewerJointAttachment* pAttachPt = itAttachPt->second; if (pAttachPt->isObjectAttached(viewer_object)) { - if (rlv_handler_t::isEnabled()) - { - RlvAttachmentLockWatchdog::instance().onDetach(viewer_object, pAttachPt); - gRlvHandler.onDetach(viewer_object, pAttachPt); - } - if (mAttachmentSignal) - { - (*mAttachmentSignal)(viewer_object, pAttachPt, ACTION_DETACH); - } + RlvAttachmentLockWatchdog::instance().onDetach(viewer_object, pAttachPt); + gRlvHandler.onDetach(viewer_object, pAttachPt); + } + if (mAttachmentSignal) + { + (*mAttachmentSignal)(viewer_object, pAttachPt, ACTION_DETACH); } - break; } } // [/RLVa:KB] @@ -1263,7 +1218,7 @@ BOOL LLVOAvatarSelf::detachObject(LLViewerObject *viewer_object) // Update COF contents, don't trigger appearance update. if (!isValid()) { - llinfos << "removeItemLinks skipped, avatar is under destruction" << llendl; + LL_INFOS() << "removeItemLinks skipped, avatar is under destruction" << LL_ENDL; } else { @@ -1468,7 +1423,7 @@ BOOL LLVOAvatarSelf::isLocalTextureDataAvailable(const LLViewerTexLayerSet* laye //----------------------------------------------------------------------------- BOOL LLVOAvatarSelf::isLocalTextureDataFinal(const LLViewerTexLayerSet* layerset) const { - const U32 desired_tex_discard_level = gSavedSettings.getU32("TextureDiscardLevel"); + static LLCachedControl desired_tex_discard_level(gSavedSettings, "TextureDiscardLevel"); // const U32 desired_tex_discard_level = 0; // hack to not bake textures on lower discard levels. for (U32 i = 0; i < mBakedTextureDatas.size(); i++) @@ -1500,9 +1455,10 @@ BOOL LLVOAvatarSelf::isLocalTextureDataFinal(const LLViewerTexLayerSet* layerset return FALSE; } + BOOL LLVOAvatarSelf::isAllLocalTextureDataFinal() const { - const U32 desired_tex_discard_level = gSavedSettings.getU32("TextureDiscardLevel"); + static LLCachedControl desired_tex_discard_level(gSavedSettings, "TextureDiscardLevel"); // const U32 desired_tex_discard_level = 0; // hack to not bake textures on lower discard levels for (U32 i = 0; i < mBakedTextureDatas.size(); i++) @@ -1591,8 +1547,8 @@ BOOL LLVOAvatarSelf::isTextureVisible(LLAvatarAppearanceDefines::ETextureIndex t return LLVOAvatar::isTextureVisible(type); } - U32 index = gAgentWearables.getWearableIndex(wearable); - return isTextureVisible(type,index); + U32 index; + return gAgentWearables.getWearableIndex(wearable, index) && isTextureVisible(type, index); } @@ -1644,7 +1600,7 @@ void LLVOAvatarSelf::invalidateComposite( LLTexLayerSet* layerset, BOOL upload_r { return; } - // llinfos << "LLVOAvatar::invalidComposite() " << layerset->getBodyRegionName() << llendl; + // LL_INFOS() << "LLVOAvatar::invalidComposite() " << layerset->getBodyRegionName() << LL_ENDL; layer_set->requestUpdate(); layer_set->invalidateMorphMasks(); @@ -1797,7 +1753,7 @@ void LLVOAvatarSelf::setLocalTexture(ETextureIndex type, LLViewerTexture* src_te { if (type >= TEX_NUM_INDICES) { - llerrs << "Tried to set local texture with invalid type: (" << (U32) type << ", " << index << ")" << llendl; + LL_ERRS() << "Tried to set local texture with invalid type: (" << (U32) type << ", " << index << ")" << LL_ENDL; return; } LLWearableType::EType wearable_type = LLAvatarAppearanceDictionary::getInstance()->getTEWearableType(type); @@ -1810,7 +1766,7 @@ void LLVOAvatarSelf::setLocalTexture(ETextureIndex type, LLViewerTexture* src_te local_tex_obj = getLocalTextureObject(type,index); if (!local_tex_obj) { - llerrs << "Unable to create LocalTextureObject for wearable type & index: (" << (U32) wearable_type << ", " << index << ")" << llendl; + LL_ERRS() << "Unable to create LocalTextureObject for wearable type & index: (" << (U32) wearable_type << ", " << index << ")" << LL_ENDL; return; } @@ -1872,7 +1828,7 @@ void LLVOAvatarSelf::setBakedReady(LLAvatarAppearanceDefines::ETextureIndex type // virtual void LLVOAvatarSelf::dumpLocalTextures() const { - llinfos << "Local Textures:" << llendl; + LL_INFOS() << "Local Textures:" << LL_ENDL; /* ETextureIndex baked_equiv[] = { TEX_UPPER_BAKED, @@ -1896,22 +1852,22 @@ void LLVOAvatarSelf::dumpLocalTextures() const #if LL_RELEASE_FOR_DOWNLOAD // End users don't get to trivially see avatar texture IDs, makes textures // easier to steal. JC - llinfos << "LocTex " << name << ": Baked " << llendl; + LL_INFOS() << "LocTex " << name << ": Baked " << LL_ENDL; #else - llinfos << "LocTex " << name << ": Baked " << getTEImage(baked_equiv)->getID() << llendl; + LL_INFOS() << "LocTex " << name << ": Baked " << getTEImage(baked_equiv)->getID() << LL_ENDL; #endif } else if (local_tex_obj && local_tex_obj->getImage() != NULL) { if (local_tex_obj->getImage()->getID() == IMG_DEFAULT_AVATAR) { - llinfos << "LocTex " << name << ": None" << llendl; + LL_INFOS() << "LocTex " << name << ": None" << LL_ENDL; } else { const LLViewerFetchedTexture* image = dynamic_cast( local_tex_obj->getImage() ); - llinfos << "LocTex " << name << ": " + LL_INFOS() << "LocTex " << name << ": " << "Discard " << image->getDiscardLevel() << ", " << "(" << image->getWidth() << ", " << image->getHeight() << ") " #if !LL_RELEASE_FOR_DOWNLOAD @@ -1920,12 +1876,12 @@ void LLVOAvatarSelf::dumpLocalTextures() const << image->getID() << " " #endif << "Priority: " << image->getDecodePriority() - << llendl; + << LL_ENDL; } } else { - llinfos << "LocTex " << name << ": No LLViewerTexture" << llendl; + LL_INFOS() << "LocTex " << name << ": No LLViewerTexture" << LL_ENDL; } } } @@ -1981,7 +1937,7 @@ void LLVOAvatarSelf::dumpTotalLocalTextureByteCount() { S32 gl_bytes = 0; gAgentAvatarp->getLocalTextureByteCount(&gl_bytes); - llinfos << "Total Avatar LocTex GL:" << (gl_bytes/1024) << "KB" << llendl; + LL_INFOS() << "Total Avatar LocTex GL:" << (gl_bytes/1024) << "KB" << LL_ENDL; } BOOL LLVOAvatarSelf::getIsCloud() const @@ -2005,12 +1961,12 @@ BOOL LLVOAvatarSelf::getIsCloud() const { if (do_warn) { - llinfos << "Self is clouded due to missing one or more required body parts: " + LL_INFOS() << "Self is clouded due to missing one or more required body parts: " << (shape_count ? "" : "SHAPE ") << (hair_count ? "" : "HAIR ") << (eye_count ? "" : "EYES ") << (skin_count ? "" : "SKIN ") - << llendl; + << LL_ENDL; } return TRUE; } @@ -2019,7 +1975,7 @@ BOOL LLVOAvatarSelf::getIsCloud() const { if (do_warn) { - llinfos << "Self is clouded because of no hair texture" << llendl; + LL_INFOS() << "Self is clouded because of no hair texture" << LL_ENDL; } return TRUE; } @@ -2031,7 +1987,7 @@ BOOL LLVOAvatarSelf::getIsCloud() const { if (do_warn) { - llinfos << "Self is clouded because lower textures not baked" << llendl; + LL_INFOS() << "Self is clouded because lower textures not baked" << LL_ENDL; } return TRUE; } @@ -2041,7 +1997,7 @@ BOOL LLVOAvatarSelf::getIsCloud() const { if (do_warn) { - llinfos << "Self is clouded because upper textures not baked" << llendl; + LL_INFOS() << "Self is clouded because upper textures not baked" << LL_ENDL; } return TRUE; } @@ -2061,14 +2017,14 @@ BOOL LLVOAvatarSelf::getIsCloud() const { if (do_warn) { - llinfos << "Self is clouded because texture at index " << i - << " (texture index is " << texture_data.mTextureIndex << ") is not loaded" << llendl; + LL_INFOS() << "Self is clouded because texture at index " << i + << " (texture index is " << texture_data.mTextureIndex << ") is not loaded" << LL_ENDL; } return TRUE; } } - lldebugs << "Avatar de-clouded" << llendl; + LL_DEBUGS() << "Avatar de-clouded" << LL_ENDL; } return FALSE; } @@ -2076,7 +2032,10 @@ BOOL LLVOAvatarSelf::getIsCloud() const /*static*/ void LLVOAvatarSelf::debugOnTimingLocalTexLoaded(BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata) { - gAgentAvatarp->debugTimingLocalTexLoaded(success, src_vi, src, aux_src, discard_level, final, userdata); + if (gAgentAvatarp.notNull()) + { + gAgentAvatarp->debugTimingLocalTexLoaded(success, src_vi, src, aux_src, discard_level, final, userdata); + } } void LLVOAvatarSelf::debugTimingLocalTexLoaded(BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata) @@ -2189,7 +2148,7 @@ void LLVOAvatarSelf::dumpAllTextures() const if (!layerset_buffer) continue; vd_text += verboseDebugDumpLocalTextureDataInfo(layerset); } - LL_DEBUGS("Avatar") << vd_text << llendl; + LL_DEBUGS("Avatar") << vd_text << LL_ENDL; } const std::string LLVOAvatarSelf::debugDumpLocalTextureDataInfo(const LLViewerTexLayerSet* layerset) const @@ -2260,28 +2219,9 @@ const std::string LLVOAvatarSelf::debugDumpAllLocalTextureDataInfo() const return text; } - -#if 0 -// Dump avatar metrics data. -LLSD LLVOAvatarSelf::metricsData() -{ - // runway - add region info - LLSD result; - result["rez_status"] = LLVOAvatar::rezStatusToString(getRezzedStatus()); - result["timers"]["debug_existence"] = mDebugExistenceTimer.getElapsedTimeF32(); - result["timers"]["ruth_debug"] = mRuthDebugTimer.getElapsedTimeF32(); - result["timers"]["ruth"] = mRuthTimer.getElapsedTimeF32(); - result["timers"]["invisible"] = mInvisibleTimer.getElapsedTimeF32(); - result["timers"]["fully_loaded"] = mFullyLoadedTimer.getElapsedTimeF32(); - result["startup"] = LLStartUp::getPhases().dumpPhases(); - - return result; -} -#endif - -extern AIHTTPTimeoutPolicy appearanceChangeMetricsResponder_timeout; class ViewerAppearanceChangeMetricsResponder: public LLHTTPClient::ResponderWithResult { + LOG_CLASS(ViewerAppearanceChangeMetricsResponder); public: ViewerAppearanceChangeMetricsResponder( S32 expected_sequence, volatile const S32 & live_sequence, @@ -2292,7 +2232,8 @@ class ViewerAppearanceChangeMetricsResponder: public LLHTTPClient::ResponderWith { } - /*virtual*/ void result(LLSD const& content) +private: + /* virtual */ void httpSuccess() { LL_DEBUGS("Avatar") << "OK" << LL_ENDL; if (mLiveSequence == mExpectedSequence) @@ -2300,11 +2241,12 @@ class ViewerAppearanceChangeMetricsResponder: public LLHTTPClient::ResponderWith mReportingStarted = true; } } - /*virtual*/ void error(U32 status, std::string const& reason) + + /* virtual */ void httpFailure() { - LL_WARNS("Avatar") << "Failed " << status << " reason " << reason << LL_ENDL; + // if we add retry, this should be removed from the httpFailure case + LL_WARNS("Avatar") << dumpResponse() << LL_ENDL; } - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return appearanceChangeMetricsResponder_timeout; } /*virtual*/ char const* getName(void) const { return "AppearanceChangeMetricsResponder"; } private: S32 mExpectedSequence; @@ -2456,44 +2398,29 @@ void LLVOAvatarSelf::sendViewerAppearanceChangeMetrics() } } -extern AIHTTPTimeoutPolicy checkAgentAppearanceServiceResponder_timeout; class CheckAgentAppearanceServiceResponder: public LLHTTPClient::ResponderHeadersOnly { public: - CheckAgentAppearanceServiceResponder() - { - } - - virtual ~CheckAgentAppearanceServiceResponder() - { - } + CheckAgentAppearanceServiceResponder() {} - /*virtual*/ void completedHeaders(U32 status, std::string const& reason, AIHTTPReceivedHeaders const& headers) + virtual ~CheckAgentAppearanceServiceResponder() {} + + /*virtual*/ void completedHeaders() { - if (200 <= status && status < 300) + if (isGoodStatus(mStatus)) { - LL_DEBUGS("Avatar") << "status OK" << llendl; + LL_DEBUGS("Avatar") << "status OK" << LL_ENDL; } else { if (isAgentAvatarValid()) { - LL_DEBUGS("Avatar") << "failed, will rebake" << llendl; + LL_DEBUGS("Avatar") << "failed, will rebake" << LL_ENDL; forceAppearanceUpdate(); } } } - // Error - /*virtual*//* void error(U32 status, const std::string& reason) - { - if (isAgentAvatarValid()) - { - LL_DEBUGS("Avatar") << "failed, will rebake" << llendl; - forceAppearanceUpdate(); - } - } */ - static void forceAppearanceUpdate() { // Trying to rebake immediately after crossing region boundary @@ -2502,7 +2429,6 @@ class CheckAgentAppearanceServiceResponder: public LLHTTPClient::ResponderHeader doAfterInterval(force_bake_all_textures, 5.0); } - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return checkAgentAppearanceServiceResponder_timeout; } /*virtual*/ char const* getName(void) const { return "CheckAgentAppearanceServiceResponder"; } }; @@ -2550,7 +2476,7 @@ BOOL LLVOAvatarSelf::canGrabBakedTexture(EBakedTextureIndex baked_index) const // Check if the texture hasn't been baked yet. if (!isTextureDefined(tex_index, 0)) { - lldebugs << "getTEImage( " << (U32) tex_index << " )->getID() == IMG_DEFAULT_AVATAR" << llendl; + LL_DEBUGS() << "getTEImage( " << (U32) tex_index << " )->getID() == IMG_DEFAULT_AVATAR" << LL_ENDL; return FALSE; } @@ -2569,7 +2495,7 @@ BOOL LLVOAvatarSelf::canGrabBakedTexture(EBakedTextureIndex baked_index) const const ETextureIndex t_index = (*iter); LLWearableType::EType wearable_type = LLAvatarAppearanceDictionary::getTEWearableType(t_index); U32 count = gAgentWearables.getWearableCount(wearable_type); - lldebugs << "Checking index " << (U32) t_index << " count: " << count << llendl; + LL_DEBUGS() << "Checking index " << (U32) t_index << " count: " << count << LL_ENDL; for (U32 wearable_index = 0; wearable_index < count; ++wearable_index) { @@ -2591,11 +2517,11 @@ BOOL LLVOAvatarSelf::canGrabBakedTexture(EBakedTextureIndex baked_index) const asset_id_matches); BOOL can_grab = FALSE; - lldebugs << "item count for asset " << texture_id << ": " << items.count() << llendl; - if (items.count()) + LL_DEBUGS() << "item count for asset " << texture_id << ": " << items.size() << LL_ENDL; + if (items.size()) { // search for full permissions version - for (S32 i = 0; i < items.count(); i++) + for (U32 i = 0; i < items.size(); i++) { LLViewerInventoryItem* itemp = items[i]; if (itemp->getIsFullPerm()) @@ -2632,15 +2558,11 @@ void LLVOAvatarSelf::addLocalTextureStats( ETextureIndex type, LLViewerFetchedTe { F32 desired_pixels; desired_pixels = llmin(mPixelArea, (F32)getTexImageArea()); - - // DRANO what priority should wearable-based textures have? - if (isUsingLocalAppearance()) - { - imagep->setBoostLevel(getAvatarBoostLevel()); - imagep->setAdditionalDecodePriority(SELF_ADDITIONAL_PRI) ; - } + + imagep->setBoostLevel(getAvatarBoostLevel()); + imagep->setAdditionalDecodePriority(SELF_ADDITIONAL_PRI) ; imagep->resetTextureStats(); - imagep->setMaxVirtualSizeResetInterval(MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL); + imagep->setMaxVirtualSizeResetInterval(MAX_TEXTURE_VIRTUAL_SIZE_RESET_INTERVAL); imagep->addTextureStats( desired_pixels / texel_area_ratio ); imagep->forceUpdateBindStats() ; if (imagep->getDiscardLevel() < 0) @@ -2702,7 +2624,7 @@ void LLVOAvatarSelf::setNewBakedTexture( ETextureIndex te, const LLUUID& uuid ) { // Baked textures live on other sims. LLHost target_host = getObjectHost(); - setTEImage( te, LLViewerTextureManager::getFetchedTextureFromHost( uuid, target_host ) ); + setTEImage( te, LLViewerTextureManager::getFetchedTextureFromHost( uuid, FTT_HOST_BAKE, target_host ) ); updateMeshTextures(); dirtyMesh(); @@ -2710,16 +2632,16 @@ void LLVOAvatarSelf::setNewBakedTexture( ETextureIndex te, const LLUUID& uuid ) /* switch(te) case TEX_HEAD_BAKED: - llinfos << "New baked texture: HEAD" << llendl; */ + LL_INFOS() << "New baked texture: HEAD" << LL_ENDL; */ const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = LLAvatarAppearanceDictionary::getInstance()->getTexture(te); if (texture_dict->mIsBakedTexture) { debugBakedTextureUpload(texture_dict->mBakedTextureIndex, TRUE); // FALSE for start of upload, TRUE for finish. - llinfos << "New baked texture: " << texture_dict->mName << " UUID: " << uuid <mName << " UUID: " << uuid <getBakedTextures().begin(); @@ -2818,7 +2740,7 @@ void LLVOAvatarSelf::outputRezDiagnostics() const if (!layerset) continue; const LLViewerTexLayerSetBuffer *layerset_buffer = layerset->getViewerComposite(); if (!layerset_buffer) continue; - LL_DEBUGS("Avatar") << layerset_buffer->dumpTextureInfo() << llendl; + LL_DEBUGS("Avatar") << layerset_buffer->dumpTextureInfo() << LL_ENDL; } dumpAllTextures(); @@ -2826,7 +2748,7 @@ void LLVOAvatarSelf::outputRezDiagnostics() const void LLVOAvatarSelf::outputRezTiming(const std::string& msg) const { - LL_INFOS("Avatar") + LL_DEBUGS("Avatar") << avString() << llformat("%s. Time from avatar creation: %.2f", msg.c_str(), mDebugSelfLoadTimer.getElapsedTimeF32()) << LL_ENDL; @@ -2858,11 +2780,11 @@ void LLVOAvatarSelf::setCachedBakedTexture( ETextureIndex te, const LLUUID& uuid { if (mInitialBakeIDs[i] == uuid) { - llinfos << "baked texture correctly loaded at login! " << i << llendl; + LL_INFOS() << "baked texture correctly loaded at login! " << i << LL_ENDL; } else { - llwarns << "baked texture does not match id loaded at login!" << i << llendl; + LL_WARNS() << "baked texture does not match id loaded at login!" << i << LL_ENDL; } mInitialBakeIDs[i] = LLUUID::null; } @@ -2898,7 +2820,7 @@ void LLVOAvatarSelf::processRebakeAvatarTextures(LLMessageSystem* msg, void**) LLViewerTexLayerSet* layer_set = gAgentAvatarp->getLayerSet(index); if (layer_set) { - llinfos << "TAT: rebake - matched entry " << (S32)index << llendl; + LL_INFOS() << "TAT: rebake - matched entry " << (S32)index << LL_ENDL; gAgentAvatarp->invalidateComposite(layer_set, TRUE); found = TRUE; LLViewerStats::getInstance()->incStat(LLViewerStats::ST_TEX_REBAKES); @@ -2922,7 +2844,7 @@ void LLVOAvatarSelf::processRebakeAvatarTextures(LLMessageSystem* msg, void**) void LLVOAvatarSelf::forceBakeAllTextures(bool slam_for_debug) { - llinfos << "TAT: forced full rebake. " << llendl; + LL_INFOS() << "TAT: forced full rebake. " << LL_ENDL; for (U32 i = 0; i < mBakedTextureDatas.size(); i++) { @@ -2941,7 +2863,7 @@ void LLVOAvatarSelf::forceBakeAllTextures(bool slam_for_debug) } else { - llwarns << "TAT: NO LAYER SET FOR " << (S32)baked_index << llendl; + LL_WARNS() << "TAT: NO LAYER SET FOR " << (S32)baked_index << LL_ENDL; } } @@ -2960,6 +2882,8 @@ void LLVOAvatarSelf::requestLayerSetUpdate(ETextureIndex index ) if( mUpperBodyLayerSet ) mUpperBodyLayerSet->requestUpdate(); */ const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = LLAvatarAppearanceDictionary::getInstance()->getTexture(index); + if (!texture_dict) + return; if (!texture_dict->mIsLocalTexture || !texture_dict->mIsUsedByBakedTexture) return; const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex; @@ -2976,7 +2900,7 @@ LLViewerTexLayerSet* LLVOAvatarSelf::getLayerSet(ETextureIndex index) const case TEX_HEAD_BODYPAINT: return mHeadLayerSet; */ const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = LLAvatarAppearanceDictionary::getInstance()->getTexture(index); - if (texture_dict->mIsUsedByBakedTexture) + if (texture_dict && texture_dict->mIsUsedByBakedTexture) { const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex; return getLayerSet(baked_index); @@ -3005,6 +2929,11 @@ void LLVOAvatarSelf::onCustomizeStart(bool disable_camera_switch) { if (isAgentAvatarValid()) { + if (!gAgentAvatarp->mEndCustomizeCallback.get()) + { + gAgentAvatarp->mEndCustomizeCallback = new LLUpdateAppearanceOnDestroy; + } + gAgentAvatarp->mIsEditingAppearance = true; gAgentAvatarp->mUseLocalAppearance = true; @@ -3045,13 +2974,19 @@ void LLVOAvatarSelf::onCustomizeEnd(bool disable_camera_switch) gAgentCamera.resetView(); } - if (gAgent.getRegion() && gAgent.getRegion()->getCentralBakeVersion()) - { - LLAppearanceMgr::instance().requestServerAppearanceUpdate(); - } + // Dereferencing the previous callback will cause + // updateAppearanceFromCOF to be called, whenever all refs + // have resolved. + gAgentAvatarp->mEndCustomizeCallback = NULL; } } +// virtual +bool LLVOAvatarSelf::shouldRenderRigged() const +{ + return gAgent.needsRenderAvatar(); +} + // HACK: this will null out the avatar's local texture IDs before the TE message is sent // to ensure local texture IDs are not sent to other clients in the area. // this is a short-term solution. The long term solution will be to not set the texture @@ -3098,98 +3033,61 @@ bool LLVOAvatarSelf::sendAppearanceMessage(LLMessageSystem *mesgsys) const } //------------------------------------------------------------------------ -// needsRenderBeam() +// sendHoverHeight() //------------------------------------------------------------------------ -BOOL LLVOAvatarSelf::needsRenderBeam() +void LLVOAvatarSelf::sendHoverHeight() const { - if (gNoRender) - { - return FALSE; - } - LLTool *tool = LLToolMgr::getInstance()->getCurrentTool(); + std::string url = gAgent.getRegion()->getCapability("AgentPreferences"); - BOOL is_touching_or_grabbing = (tool == LLToolGrab::getInstance() && LLToolGrab::getInstance()->isEditing()); - if (LLToolGrab::getInstance()->getEditingObject() && - LLToolGrab::getInstance()->getEditingObject()->isAttachment()) + if (!url.empty()) { - // don't render selection beam on hud objects - is_touching_or_grabbing = FALSE; - } - return is_touching_or_grabbing || (mState & AGENT_STATE_EDITING && LLSelectMgr::getInstance()->shouldShowSelection()); -} + LLSD update = LLSD::emptyMap(); + const LLVector3& hover_offset = getHoverOffset(); + update["hover_height"] = hover_offset[2]; -// static -void LLVOAvatarSelf::deleteScratchTextures() -{ - if(gAuditTexture) - { - S32 total_tex_size = sScratchTexBytes ; - S32 tex_size = SCRATCH_TEX_WIDTH * SCRATCH_TEX_HEIGHT ; + LL_DEBUGS("Avatar") << avString() << "sending hover height value " << hover_offset[2] << LL_ENDL; - if( sScratchTexNames.checkData( GL_LUMINANCE ) ) - { - LLImageGL::decTextureCounter(tex_size, 1, LLViewerTexture::AVATAR_SCRATCH_TEX) ; - total_tex_size -= tex_size ; - } - if( sScratchTexNames.checkData( GL_ALPHA ) ) - { - LLImageGL::decTextureCounter(tex_size, 1, LLViewerTexture::AVATAR_SCRATCH_TEX) ; - total_tex_size -= tex_size ; - } - if( sScratchTexNames.checkData( GL_COLOR_INDEX ) ) - { - LLImageGL::decTextureCounter(tex_size, 1, LLViewerTexture::AVATAR_SCRATCH_TEX) ; - total_tex_size -= tex_size ; - } - if( sScratchTexNames.checkData( LLRender::sGLCoreProfile ? GL_RG : GL_LUMINANCE_ALPHA ) ) - { - LLImageGL::decTextureCounter(tex_size, 2, LLViewerTexture::AVATAR_SCRATCH_TEX) ; - total_tex_size -= 2 * tex_size ; - } - if( sScratchTexNames.checkData( GL_RGB ) ) - { - LLImageGL::decTextureCounter(tex_size, 3, LLViewerTexture::AVATAR_SCRATCH_TEX) ; - total_tex_size -= 3 * tex_size ; - } - if( sScratchTexNames.checkData( GL_RGBA ) ) - { - LLImageGL::decTextureCounter(tex_size, 4, LLViewerTexture::AVATAR_SCRATCH_TEX) ; - total_tex_size -= 4 * tex_size ; - } - //others - while(total_tex_size > 0) - { - LLImageGL::decTextureCounter(tex_size, 4, LLViewerTexture::AVATAR_SCRATCH_TEX) ; - total_tex_size -= 4 * tex_size ; - } + // *TODO: - this class doesn't really do anything, could just use a base + // class responder if nothing else gets added. + // (comment from removed Responder) + LLHTTPClient::post(url, update, new LLHTTPClient::ResponderIgnore); + + mLastHoverOffsetSent = hover_offset; } +} - for( LLGLuint* namep = sScratchTexNames.getFirstData(); - namep; - namep = sScratchTexNames.getNextData() ) +void LLVOAvatarSelf::setHoverOffset(const LLVector3& hover_offset, bool send_update) +{ + if (getHoverOffset() != hover_offset) { - LLImageGL::deleteTextures(LLTexUnit::TT_TEXTURE, 0, -1, 1, (U32 *)namep ); - stop_glerror(); + LL_INFOS("Avatar") << avString() << " setting hover due to change " << hover_offset[2] << LL_ENDL; + LLVOAvatar::setHoverOffset(hover_offset, send_update); } - - if( sScratchTexBytes ) + if (send_update && (hover_offset != mLastHoverOffsetSent)) { - lldebugs << "Clearing Scratch Textures " << (sScratchTexBytes/1024) << "KB" << llendl; - - sScratchTexNames.deleteAllData(); - sScratchTexLastBindTime.deleteAllData(); - LLImageGL::sGlobalTextureMemoryInBytes -= sScratchTexBytes; - sScratchTexBytes = 0; + LL_INFOS("Avatar") << avString() << " sending hover due to change " << hover_offset[2] << LL_ENDL; + sendHoverHeight(); } } -// static -void LLVOAvatarSelf::dumpScratchTextureByteCount() +//------------------------------------------------------------------------ +// needsRenderBeam() +//------------------------------------------------------------------------ +BOOL LLVOAvatarSelf::needsRenderBeam() { - llinfos << "Scratch Texture GL: " << (sScratchTexBytes/1024) << "KB" << llendl; + LLTool *tool = LLToolMgr::getInstance()->getCurrentTool(); + + BOOL is_touching_or_grabbing = (tool == LLToolGrab::getInstance() && LLToolGrab::getInstance()->isEditing()); + if (LLToolGrab::getInstance()->getEditingObject() && + LLToolGrab::getInstance()->getEditingObject()->isAttachment()) + { + // don't render selection beam on hud objects + is_touching_or_grabbing = FALSE; + } + return is_touching_or_grabbing || (getAttachmentState() & AGENT_STATE_EDITING && LLSelectMgr::getInstance()->shouldShowSelection()); } -void dump_visual_param(LLAPRFile& file, LLVisualParam const* viewer_param, F32 value); +void dump_visual_param(apr_file_t* file, LLVisualParam const* viewer_param, F32 value); void LLVOAvatarSelf::dumpWearableInfo(LLAPRFile& outfile) { @@ -3217,7 +3115,7 @@ void LLVOAvatarSelf::dumpWearableInfo(LLAPRFile& outfile) it != v_params.end(); ++it) { LLVisualParam *param = *it; - dump_visual_param(outfile, param, param->getWeight()); + dump_visual_param(file, param, param->getWeight()); } } } @@ -3232,18 +3130,10 @@ LLVector3 LLVOAvatarSelf::getLegacyAvatarOffset() const static LLCachedControl z_off("AscentAvatarZModifier"); LLVector3 offset(x_off,y_off,z_off); -// [RLVa:KB] Custom blah blah - if(rlv_handler_t::isEnabled()) - { - F32 rlva_z_offs = RlvSettings::getAvatarOffsetZ(); - if(fabs(rlva_z_offs) > F_APPROXIMATELY_ZERO) - offset.mV[VZ] = rlva_z_offs; - } -// [/RLVa:KB] if(on_pose_stand) offset.mV[VZ] += 7.5f; - return offset; + return mAvatarOffset + offset; } // static @@ -3274,3 +3164,23 @@ void LLVOAvatarSelf::setInvisible(bool invisible) gAgent.sendAgentSetAppearance(); } } + +void LLVOAvatarSelf::handleTeleportFinished() +{ + for (attachment_map_t::iterator it = mAttachmentPoints.begin(); it != mAttachmentPoints.end(); ++it) + { + LLViewerJointAttachment* attachment = it->second; + if (attachment && attachment->getIsHUDAttachment()) + { + typedef LLViewerJointAttachment::attachedobjs_vec_t object_vec_t; + const object_vec_t& obj_list = attachment->mAttachedObjects; + for (object_vec_t::const_iterator it2 = obj_list.begin(); it2 != obj_list.end(); ++it2) + { + if(*it2) + { + (*it2)->dirtySpatialGroup(true); + } + } + } + } +} diff --git a/indra/newview/llvoavatarself.h b/indra/newview/llvoavatarself.h index 99e45bcff5..7d9f9d12ad 100644 --- a/indra/newview/llvoavatarself.h +++ b/indra/newview/llvoavatarself.h @@ -28,10 +28,13 @@ #ifndef LL_LLVOAVATARSELF_H #define LL_LLVOAVATARSELF_H +#include "llavatarappearancedefines.h" #include "llviewertexture.h" #include "llvoavatar.h" +#include struct LocalTextureData; +class LLInventoryCallback; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -63,6 +66,7 @@ class LLVOAvatarSelf : virtual ~LLVOAvatarSelf(); virtual void markDead(); virtual void initInstance(); // Called after construction to initialize the class. + void buildContextMenus(); void cleanup(); protected: /*virtual*/ BOOL loadAvatar(); @@ -83,6 +87,9 @@ class LLVOAvatarSelf : // LLViewerObject interface and related //-------------------------------------------------------------------- public: + boost::signals2::connection mRegionChangedSlot; + + void onSimulatorFeaturesReceived(const LLUUID& region_id); /*virtual*/ void updateRegion(LLViewerRegion *regionp); /*virtual*/ void idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time); @@ -90,25 +97,21 @@ class LLVOAvatarSelf : // LLCharacter interface and related //-------------------------------------------------------------------- public: + /*virtual*/ bool hasMotionFromSource(const LLUUID& source_id); /*virtual*/ void stopMotionFromSource(const LLUUID& source_id); /*virtual*/ void requestStopMotion(LLMotion* motion); /*virtual*/ LLJoint* getJoint(const std::string &name); - /*virtual*/ BOOL setVisualParamWeight(const LLVisualParam *which_param, F32 weight, BOOL upload_bake = FALSE ); - /*virtual*/ BOOL setVisualParamWeight(const char* param_name, F32 weight, BOOL upload_bake = FALSE ); - /*virtual*/ BOOL setVisualParamWeight(S32 index, F32 weight, BOOL upload_bake = FALSE ); + /*virtual*/ BOOL setVisualParamWeight(const LLVisualParam *which_param, F32 weight, bool upload_bake = false ); + /*virtual*/ BOOL setVisualParamWeight(const char* param_name, F32 weight, bool upload_bake = false ); + /*virtual*/ BOOL setVisualParamWeight(S32 index, F32 weight, bool upload_bake = false ); /*virtual*/ void updateVisualParams(); + void writeWearablesToAvatar(); /*virtual*/ void idleUpdateAppearanceAnimation(); - /*virtual*/ U32 processUpdateMessage(LLMessageSystem *mesgsys, - void **user_data, - U32 block_num, - const EObjectUpdateType update_type, - LLDataPacker *dp); - private: // helper function. Passed in param is assumed to be in avatar's parameter list. - BOOL setParamWeight(const LLViewerVisualParam *param, F32 weight, BOOL upload_bake = FALSE ); + BOOL setParamWeight(const LLViewerVisualParam *param, F32 weight, bool upload_bake = false ); @@ -117,8 +120,8 @@ class LLVOAvatarSelf : *******************************************************************************/ private: - LLUUID mInitialBakeIDs[6]; - bool mInitialBakesLoaded; + LLUUID mInitialBakeIDs[LLAvatarAppearanceDefines::BAKED_NUM_INDICES]; + //bool mInitialBakesLoaded; /******************************************************************************** @@ -136,6 +139,7 @@ class LLVOAvatarSelf : public: /*virtual*/ BOOL updateCharacter(LLAgent &agent); /*virtual*/ void idleUpdateTractorBeam(); + bool checkStuckAppearance(); //-------------------------------------------------------------------- // Loading state @@ -265,17 +269,6 @@ class LLVOAvatarSelf : const LLUUID& grabBakedTexture(LLAvatarAppearanceDefines::EBakedTextureIndex baked_index) const; BOOL canGrabBakedTexture(LLAvatarAppearanceDefines::EBakedTextureIndex baked_index) const; - - //-------------------------------------------------------------------- - // Scratch textures (used for compositing) - //-------------------------------------------------------------------- -public: - static void deleteScratchTextures(); -private: - static S32 sScratchTexBytes; - static LLMap< LLGLenum, LLGLuint*> sScratchTexNames; - static LLMap< LLGLenum, F32*> sScratchTexLastBindTime; - /** Textures ** ** *******************************************************************************/ @@ -306,14 +299,11 @@ class LLVOAvatarSelf : public: void updateAttachmentVisibility(U32 camera_mode); BOOL isWearingAttachment(const LLUUID& inv_item_id) const; - BOOL attachmentWasRequested(const LLUUID& inv_item_id) const; - void addAttachmentRequest(const LLUUID& inv_item_id); - void removeAttachmentRequest(const LLUUID& inv_item_id); LLViewerObject* getWornAttachment(const LLUUID& inv_item_id); + bool getAttachedPointName(const LLUUID& inv_item_id, std::string& name) const; // [RLVa:KB] - Checked: 2009-12-18 (RLVa-1.1.0i) | Added: RLVa-1.1.0i LLViewerJointAttachment* getWornAttachmentPoint(const LLUUID& inv_item_id) const; // [/RLVa:KB] - const std::string getAttachedPointName(const LLUUID& inv_item_id) const; /*virtual*/ const LLViewerJointAttachment *attachObject(LLViewerObject *viewer_object); /*virtual*/ BOOL detachObject(LLViewerObject *viewer_object); static BOOL detachAttachmentIntoInventory(const LLUUID& item_id); @@ -324,8 +314,6 @@ class LLVOAvatarSelf : boost::signals2::connection setAttachmentCallback(const attachment_signal_t::slot_type& cb); // [/RLVa:KB] private: - // Track attachments that have been requested but have not arrived yet. - mutable std::map mAttachmentRequests; // [RLVa:KB] - Checked: 2012-07-28 (RLVa-1.4.7) attachment_signal_t* mAttachmentSignal; // [/RLVa:KB] @@ -348,13 +336,25 @@ class LLVOAvatarSelf : public: static void onCustomizeStart(bool disable_camera_switch = false); static void onCustomizeEnd(bool disable_camera_switch = false); + LLPointer mEndCustomizeCallback; //-------------------------------------------------------------------- // Visibility //-------------------------------------------------------------------- + + /* virtual */ bool shouldRenderRigged() const; + public: bool sendAppearanceMessage(LLMessageSystem *mesgsys) const; + // -- care and feeding of hover height. + void setHoverIfRegionEnabled(bool send_update = true); + void sendHoverHeight() const; + /*virtual*/ void setHoverOffset(const LLVector3& hover_offset, bool send_update=true); + +private: + mutable LLVector3 mLastHoverOffsetSent; + public: LLVector3 getLegacyAvatarOffset() const; @@ -373,7 +373,6 @@ class LLVOAvatarSelf : public: static void dumpTotalLocalTextureByteCount(); void dumpLocalTextures() const; - static void dumpScratchTextureByteCount(); void dumpWearableInfo(LLAPRFile& outfile); //-------------------------------------------------------------------- @@ -428,6 +427,11 @@ class LLVOAvatarSelf : public: static void onChangeSelfInvisible(bool invisible); void setInvisible(bool invisible); +private: + void handleTeleportFinished(); +private: + boost::signals2::connection mTeleportFinishedSlot; + }; extern LLPointer gAgentAvatarp; diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp index f21b876fa4..4ac1b14004 100644 --- a/indra/newview/llvocache.cpp +++ b/indra/newview/llvocache.cpp @@ -110,7 +110,7 @@ LLVOCacheEntry::LLVOCacheEntry(LLAPRFile* apr_file) // We've got a bogus size, skip reading it. // We won't bother seeking, because the rest of this file // is likely bogus, and will be tossed anyway. - llwarns << "Bogus cache entry, size " << size << ", aborting!" << llendl; + LL_WARNS() << "Bogus cache entry, size " << size << ", aborting!" << LL_ENDL; success = FALSE; } } @@ -169,7 +169,7 @@ LLDataPackerBinaryBuffer *LLVOCacheEntry::getDP(U32 crc) if ( (mCRC != crc) ||(mDP.getBufferSize() == 0)) { - //llinfos << "Not getting cache entry, invalid!" << llendl; + //LL_INFOS() << "Not getting cache entry, invalid!" << LL_ENDL; return NULL; } mHitCount++; @@ -185,12 +185,12 @@ void LLVOCacheEntry::recordHit() void LLVOCacheEntry::dump() const { - llinfos << "local " << mLocalID + LL_INFOS() << "local " << mLocalID << " crc " << mCRC << " hits " << mHitCount << " dupes " << mDupeCount << " change " << mCRCChangeCount - << llendl; + << LL_ENDL; } BOOL LLVOCacheEntry::writeToFile(LLAPRFile* apr_file) const @@ -295,13 +295,13 @@ void LLVOCache::initCache(ELLPath location, U32 size, U32 cache_version) { if(!mEnabled) { - llwarns << "Not initializing cache: Cache is currently disabled." << llendl; + LL_WARNS() << "Not initializing cache: Cache is currently disabled." << LL_ENDL; return ; } if(mInitialized) { - llwarns << "Cache already initialized." << llendl; + LL_WARNS() << "Cache already initialized." << LL_ENDL; return ; } mInitialized = TRUE ; @@ -333,15 +333,15 @@ void LLVOCache::removeCache(ELLPath location) { if(mReadOnly) { - llwarns << "Not removing cache at " << location << ": Cache is currently in read-only mode." << llendl; + LL_WARNS() << "Not removing cache at " << location << ": Cache is currently in read-only mode." << LL_ENDL; return ; } - llinfos << "about to remove the object cache due to settings." << llendl ; + LL_INFOS() << "about to remove the object cache due to settings." << LL_ENDL ; std::string mask = "*"; std::string cache_dir = gDirUtilp->getExpandedFilename(location, object_cache_dirname); - llinfos << "Removing cache at " << cache_dir << llendl; + LL_INFOS() << "Removing cache at " << cache_dir << LL_ENDL; gDirUtilp->deleteFilesInDir(cache_dir, mask); //delete all files LLFile::rmdir(cache_dir); @@ -354,14 +354,14 @@ void LLVOCache::removeCache() llassert_always(mInitialized) ; if(mReadOnly) { - llwarns << "Not clearing object cache: Cache is currently in read-only mode." << llendl; + LL_WARNS() << "Not clearing object cache: Cache is currently in read-only mode." << LL_ENDL; return ; } - llinfos << "about to remove the object cache due to some error." << llendl ; + LL_INFOS() << "about to remove the object cache due to some error." << LL_ENDL ; std::string mask = "*"; - llinfos << "Removing cache at " << mObjectCacheDirName << llendl; + LL_INFOS() << "Removing cache at " << mObjectCacheDirName << LL_ENDL; gDirUtilp->deleteFilesInDir(mObjectCacheDirName, mask); clearCacheInMemory() ; @@ -433,7 +433,7 @@ void LLVOCache::removeFromCache(HeaderEntryInfo* entry) { if(mReadOnly) { - llwarns << "Not removing cache for handle " << entry->mHandle << ": Cache is currently in read-only mode." << llendl; + LL_WARNS() << "Not removing cache for handle " << entry->mHandle << ": Cache is currently in read-only mode." << LL_ENDL; return ; } @@ -448,7 +448,7 @@ void LLVOCache::readCacheHeader() { if(!mEnabled) { - llwarns << "Not reading cache header: Cache is currently disabled." << llendl; + LL_WARNS() << "Not reading cache header: Cache is currently disabled." << LL_ENDL; return; } @@ -478,7 +478,7 @@ void LLVOCache::readCacheHeader() if(!success) //failed { - llwarns << "Error reading cache header entry. (entry_index=" << mNumEntries << ")" << llendl; + LL_WARNS() << "Error reading cache header entry. (entry_index=" << mNumEntries << ")" << LL_ENDL; delete entry ; entry = NULL ; break ; @@ -506,7 +506,7 @@ void LLVOCache::readCacheHeader() //for(header_entry_queue_t::iterator iter = mHeaderEntryQueue.begin() ; success && iter != mHeaderEntryQueue.end(); ++iter) //{ // getObjectCacheFilename((*iter)->mHandle, name) ; - // llinfos << name << llendl ; + // LL_INFOS() << name << LL_ENDL ; //} //----------- } @@ -531,13 +531,13 @@ void LLVOCache::writeCacheHeader() { if (!mEnabled) { - llwarns << "Not writing cache header: Cache is currently disabled." << llendl; + LL_WARNS() << "Not writing cache header: Cache is currently disabled." << LL_ENDL; return; } if(mReadOnly) { - llwarns << "Not writing cache header: Cache is currently in read-only mode." << llendl; + LL_WARNS() << "Not writing cache header: Cache is currently in read-only mode." << LL_ENDL; return; } @@ -591,7 +591,7 @@ void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca { if(!mEnabled) { - llwarns << "Not reading cache for handle " << handle << "): Cache is currently disabled." << llendl; + LL_WARNS() << "Not reading cache for handle " << handle << "): Cache is currently disabled." << LL_ENDL; return ; } llassert_always(mInitialized); @@ -599,7 +599,7 @@ void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca handle_entry_map_t::iterator iter = mHandleEntryMap.find(handle) ; if(iter == mHandleEntryMap.end()) //no cache { - llwarns << "No handle map entry for " << handle << llendl; + LL_WARNS() << "No handle map entry for " << handle << LL_ENDL; return ; } @@ -616,7 +616,7 @@ void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca { if(cache_id != id) { - llinfos << "Cache ID doesn't match for this region, discarding"<< llendl; + LL_INFOS() << "Cache ID doesn't match for this region, discarding"<< LL_ENDL; success = false ; } @@ -632,7 +632,7 @@ void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca LLVOCacheEntry* entry = new LLVOCacheEntry(&apr_file); if (!entry->getLocalID()) { - llwarns << "Aborting cache file load for " << filename << ", cache file corruption!" << llendl; + LL_WARNS() << "Aborting cache file load for " << filename << ", cache file corruption!" << LL_ENDL; delete entry ; success = false ; break ; @@ -673,14 +673,14 @@ void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry: { if(!mEnabled) { - llwarns << "Not writing cache for handle " << handle << "): Cache is currently disabled." << llendl; + LL_WARNS() << "Not writing cache for handle " << handle << "): Cache is currently disabled." << LL_ENDL; return ; } llassert_always(mInitialized); if(mReadOnly) { - llwarns << "Not writing cache for handle " << handle << "): Cache is currently in read-only mode." << llendl; + LL_WARNS() << "Not writing cache for handle " << handle << "): Cache is currently in read-only mode." << LL_ENDL; return ; } @@ -715,13 +715,13 @@ void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry: //update cache header if(!updateEntry(entry)) { - llwarns << "Failed to update cache header index " << entry->mIndex << ". handle = " << handle << llendl; + LL_WARNS() << "Failed to update cache header index " << entry->mIndex << ". handle = " << handle << LL_ENDL; return ; //update failed. } if(!dirty_cache) { - llwarns << "Skipping write to cache for handle " << handle << ": cache not dirty" << llendl; + LL_WARNS() << "Skipping write to cache for handle " << handle << ": cache not dirty" << LL_ENDL; return ; //nothing changed, no need to update. } diff --git a/indra/newview/llvocache.h b/indra/newview/llvocache.h index 6f2fd45713..9fe14375aa 100644 --- a/indra/newview/llvocache.h +++ b/indra/newview/llvocache.h @@ -35,7 +35,6 @@ #include "lluuid.h" #include "lldatapacker.h" -#include "lldlinked.h" #include "lldir.h" diff --git a/indra/newview/llvoclouds.cpp b/indra/newview/llvoclouds.cpp index 59f1b959a1..93bfa29cbf 100644 --- a/indra/newview/llvoclouds.cpp +++ b/indra/newview/llvoclouds.cpp @@ -114,10 +114,10 @@ LLDrawable* LLVOClouds::createDrawable(LLPipeline *pipeline) return mDrawable; } -static LLFastTimer::DeclareTimer FTM_UPDATE_CLOUDS("Cloud Update"); +static LLTrace::BlockTimerStatHandle FTM_UPDATE_CLOUDS("Cloud Update"); BOOL LLVOClouds::updateGeometry(LLDrawable *drawable) { - LLFastTimer ftm(FTM_UPDATE_CLOUDS); + LL_RECORD_BLOCK_TIME(FTM_UPDATE_CLOUDS); dirtySpatialGroup(); @@ -142,7 +142,6 @@ BOOL LLVOClouds::updateGeometry(LLDrawable *drawable) group->setState(LLSpatialGroup::GEOM_DIRTY); } drawable->setNumFaces(0, NULL, getTEImage(0)); - LLPipeline::sCompiles++; return TRUE; } @@ -164,7 +163,7 @@ BOOL LLVOClouds::updateGeometry(LLDrawable *drawable) facep = drawable->getFace(face_indx); if (!facep) { - llwarns << "No facep for index " << face_indx << llendl; + LL_WARNS() << "No facep for index " << face_indx << LL_ENDL; continue; } @@ -186,7 +185,7 @@ BOOL LLVOClouds::updateGeometry(LLDrawable *drawable) facep = drawable->getFace(face_indx); if (!facep) { - llwarns << "No facep for index " << face_indx << llendl; + LL_WARNS() << "No facep for index " << face_indx << LL_ENDL; continue; } @@ -195,7 +194,6 @@ BOOL LLVOClouds::updateGeometry(LLDrawable *drawable) } mDrawable->movePartition(); - LLPipeline::sCompiles++; return TRUE; } @@ -208,6 +206,7 @@ void LLVOClouds::getGeometry(S32 idx, LLStrider& normalsp, LLStrider& texcoordsp, LLStrider& colorsp, + LLStrider& emissivep, LLStrider& indicesp) { @@ -296,7 +295,8 @@ void LLVOClouds::updateDrawable(BOOL force_damped) clearChanged(SHIFTED); } -LLCloudPartition::LLCloudPartition() +LLCloudPartition::LLCloudPartition(LLViewerRegion* region) + : LLParticlePartition(region) { mDrawableType = LLPipeline::RENDER_TYPE_CLASSIC_CLOUDS; mPartitionType = LLViewerRegion::PARTITION_CLOUD; diff --git a/indra/newview/llvoclouds.h b/indra/newview/llvoclouds.h index 089f3efc10..95e9dc331d 100644 --- a/indra/newview/llvoclouds.h +++ b/indra/newview/llvoclouds.h @@ -60,6 +60,7 @@ class LLVOClouds : public LLAlphaObject LLStrider& normalsp, LLStrider& texcoordsp, LLStrider& colorsp, + LLStrider& emissivep, LLStrider& indicesp); /*virtual*/ BOOL isActive() const; // Whether this object needs to do an idleUpdate. diff --git a/indra/newview/llvograss.cpp b/indra/newview/llvograss.cpp index f1ca2c6a37..e39dedba40 100644 --- a/indra/newview/llvograss.cpp +++ b/indra/newview/llvograss.cpp @@ -81,7 +81,6 @@ LLVOGrass::SpeciesNames LLVOGrass::sSpeciesNames; LLVOGrass::LLVOGrass(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp) : LLAlphaObject(id, pcode, regionp) { - mPatch = NULL; mLastPatchUpdateTime = 0; mGrassVel.clearVec(); mGrassBend.clearVec(); @@ -103,15 +102,15 @@ LLVOGrass::~LLVOGrass() void LLVOGrass::updateSpecies() { - mSpecies = mState; + mSpecies = getAttachmentState(); if (!sSpeciesTable.count(mSpecies)) { - llinfos << "Unknown grass type, substituting grass type." << llendl; + LL_INFOS() << "Unknown grass type, substituting grass type." << LL_ENDL; SpeciesMap::const_iterator it = sSpeciesTable.begin(); mSpecies = (*it).first; } - setTEImage(0, LLViewerTextureManager::getFetchedTexture(sSpeciesTable[mSpecies]->mTextureID, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE)); + setTEImage(0, LLViewerTextureManager::getFetchedTexture(sSpeciesTable[mSpecies]->mTextureID, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE)); } @@ -129,7 +128,7 @@ void LLVOGrass::initClass() if (!grass_def_grass.parseFile(xml_filename)) { - llerrs << "Failed to parse grass file." << llendl; + LL_ERRS() << "Failed to parse grass file." << LL_ENDL; return; } @@ -141,7 +140,7 @@ void LLVOGrass::initClass() { if (!grass_def->hasName("grass")) { - llwarns << "Invalid grass definition node " << grass_def->getName() << llendl; + LL_WARNS() << "Invalid grass definition node " << grass_def->getName() << LL_ENDL; continue; } F32 F32_val; @@ -153,13 +152,13 @@ void LLVOGrass::initClass() static LLStdStringHandle species_id_string = LLXmlTree::addAttributeString("species_id"); if (!grass_def->getFastAttributeS32(species_id_string, species)) { - llwarns << "No species id defined" << llendl; + LL_WARNS() << "No species id defined" << LL_ENDL; continue; } if (species < 0) { - llwarns << "Invalid species id " << species << llendl; + LL_WARNS() << "Invalid species id " << species << LL_ENDL; continue; } @@ -190,7 +189,7 @@ void LLVOGrass::initClass() if (sSpeciesTable.count(species)) { - llinfos << "Grass species " << species << " already defined! Duplicate discarded." << llendl; + LL_INFOS() << "Grass species " << species << " already defined! Duplicate discarded." << LL_ENDL; delete newGrass; continue; } @@ -211,7 +210,7 @@ void LLVOGrass::initClass() std::string name; static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name"); grass_def->getFastAttributeString(name_string, name); - llwarns << "Incomplete definition of grass " << name << llendl; + LL_WARNS() << "Incomplete definition of grass " << name << LL_ENDL; } } @@ -282,7 +281,7 @@ U32 LLVOGrass::processUpdateMessage(LLMessageSystem *mesgsys, ||(getAcceleration().lengthSquared() > 0.f) ||(getAngularVelocity().lengthSquared() > 0.f)) { - llinfos << "ACK! Moving grass!" << llendl; + LL_INFOS() << "ACK! Moving grass!" << LL_ENDL; setVelocity(LLVector3::zero); setAcceleration(LLVector3::zero); setAngularVelocity(LLVector3::zero); @@ -331,7 +330,8 @@ void LLVOGrass::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) return; } - if (mPatch && (mLastPatchUpdateTime != mPatch->getLastUpdateTime())) + const auto& patch = mPatch.lock(); + if (patch && (mLastPatchUpdateTime != patch->getLastUpdateTime())) { gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE); } @@ -437,11 +437,11 @@ LLDrawable* LLVOGrass::createDrawable(LLPipeline *pipeline) return mDrawable; } -static LLFastTimer::DeclareTimer FTM_UPDATE_GRASS("Update Grass"); +static LLTrace::BlockTimerStatHandle FTM_UPDATE_GRASS("Update Grass"); BOOL LLVOGrass::updateGeometry(LLDrawable *drawable) { - LLFastTimer ftm(FTM_UPDATE_GRASS); + LL_RECORD_BLOCK_TIME(FTM_UPDATE_GRASS); dirtySpatialGroup(); @@ -469,7 +469,7 @@ void LLVOGrass::plantBlades() // This is bad, but not the end of the world. if (!sSpeciesTable.count(mSpecies)) { - llinfos << "Unknown grass species " << mSpecies << llendl; + LL_INFOS() << "Unknown grass species " << mSpecies << LL_ENDL; return; } @@ -492,7 +492,6 @@ void LLVOGrass::plantBlades() mDepth = (face->mCenterLocal - LLViewerCamera::getInstance()->getOrigin())*LLViewerCamera::getInstance()->getAtAxis(); mDrawable->setPosition(face->mCenterLocal); mDrawable->movePartition(); - LLPipeline::sCompiles++; } void LLVOGrass::getGeometry(S32 idx, @@ -500,6 +499,7 @@ void LLVOGrass::getGeometry(S32 idx, LLStrider& normalsp, LLStrider& texcoordsp, LLStrider& colorsp, + LLStrider& emissivep, LLStrider& indicesp) { if(!mNumBlades)//stop rendering grass @@ -507,9 +507,10 @@ void LLVOGrass::getGeometry(S32 idx, return ; } - mPatch = mRegionp->getLand().resolvePatchRegion(getPositionRegion()); - if (mPatch) - mLastPatchUpdateTime = mPatch->getLastUpdateTime(); + const auto& patch = mRegionp->getLand().resolvePatchRegion(getPositionRegion()); + if (patch) + mLastPatchUpdateTime = patch->getLastUpdateTime(); + mPatch = patch; LLVector3 position; // Create random blades of grass with gaussian distribution @@ -619,7 +620,6 @@ void LLVOGrass::getGeometry(S32 idx, index_offset += 8; } - LLPipeline::sCompiles++; } U32 LLVOGrass::getPartitionType() const @@ -627,8 +627,8 @@ U32 LLVOGrass::getPartitionType() const return LLViewerRegion::PARTITION_GRASS; } -LLGrassPartition::LLGrassPartition() -: LLSpatialPartition(LLDrawPoolAlpha::VERTEX_DATA_MASK | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, GL_STREAM_DRAW_ARB) +LLGrassPartition::LLGrassPartition(LLViewerRegion* regionp) +: LLSpatialPartition(LLDrawPoolAlpha::VERTEX_DATA_MASK | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, GL_STREAM_DRAW_ARB, regionp) { mDrawableType = LLPipeline::RENDER_TYPE_GRASS; mPartitionType = LLViewerRegion::PARTITION_GRASS; @@ -646,10 +646,10 @@ void LLGrassPartition::addGeometryCount(LLSpatialGroup* group, U32& vertex_count mFaceList.clear(); LLViewerCamera* camera = LLViewerCamera::getInstance(); - OctreeGuard guard(group->mOctreeNode); + OctreeGuard guard(group->getOctreeNode()); for (LLSpatialGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i) { - LLDrawable* drawablep = *i; + LLDrawable* drawablep = (LLDrawable*)(*i)->getDrawable(); if (drawablep->isDead()) { @@ -696,11 +696,11 @@ void LLGrassPartition::addGeometryCount(LLSpatialGroup* group, U32& vertex_count } } -static LLFastTimer::DeclareTimer FTM_REBUILD_GRASS_VB("Grass VB"); +static LLTrace::BlockTimerStatHandle FTM_REBUILD_GRASS_VB("Grass VB"); void LLGrassPartition::getGeometry(LLSpatialGroup* group) { - LLFastTimer ftm(FTM_REBUILD_GRASS_VB); + LL_RECORD_BLOCK_TIME(FTM_REBUILD_GRASS_VB); std::sort(mFaceList.begin(), mFaceList.end(), LLFace::CompareDistanceGreater()); @@ -733,7 +733,11 @@ void LLGrassPartition::getGeometry(LLSpatialGroup* group) facep->setIndicesIndex(index_count); facep->setVertexBuffer(buffer); facep->setPoolType(LLDrawPool::POOL_ALPHA); - object->getGeometry(facep->getTEOffset(), verticesp, normalsp, texcoordsp, colorsp, indicesp); + + //dummy parameter (unused by this implementation) + LLStrider emissivep; + + object->getGeometry(facep->getTEOffset(), verticesp, normalsp, texcoordsp, colorsp, emissivep, indicesp); vertex_count += facep->getGeomCount(); index_count += facep->getIndicesCount(); @@ -763,8 +767,9 @@ void LLGrassPartition::getGeometry(LLSpatialGroup* group) LLDrawInfo* info = new LLDrawInfo(start,end,count,offset,facep->getTexture(), //facep->getTexture(), buffer, fullbright); - info->mExtents[0] = group->mObjectExtents[0]; - info->mExtents[1] = group->mObjectExtents[1]; + const LLVector4a* bounds = group->getObjectExtents(); + info->mExtents[0] = bounds[0]; + info->mExtents[1] = bounds[1]; info->mVSize = vsize; draw_vec.push_back(info); //for alpha sorting @@ -772,6 +777,11 @@ void LLGrassPartition::getGeometry(LLSpatialGroup* group) } } + if(vertex_count > 0) + { + buffer->validateRange(0, vertex_count - 1, index_count, 0); + } + buffer->flush(); mFaceList.clear(); } @@ -789,8 +799,8 @@ void LLVOGrass::updateDrawable(BOOL force_damped) } // virtual -BOOL LLVOGrass::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, S32 face, BOOL pick_transparent, S32 *face_hitp, - LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal) +BOOL LLVOGrass::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, S32 face, BOOL pick_transparent, BOOL pick_rigged, S32 *face_hitp, + LLVector4a* intersection,LLVector2* tex_coord, LLVector4a* normal, LLVector4a* tangent) { BOOL ret = FALSE; @@ -801,7 +811,8 @@ BOOL LLVOGrass::lineSegmentIntersect(const LLVector3& start, const LLVector3& en return FALSE; } - LLVector3 dir = end-start; + LLVector4a dir; + dir.setSub(end, start); mPatch = mRegionp->getLand().resolvePatchRegion(getPositionRegion()); @@ -869,23 +880,31 @@ BOOL LLVOGrass::lineSegmentIntersect(const LLVector3& start, const LLVector3& en U32 idx0 = 0,idx1 = 0,idx2 = 0; - if (LLTriangleRayIntersect(v[0], v[1], v[2], start, dir, a, b, t, FALSE)) + LLVector4a v0a,v1a,v2a,v3a; + + v0a.load3(v[0].mV); + v1a.load3(v[1].mV); + v2a.load3(v[2].mV); + v3a.load3(v[3].mV); + + + if (LLTriangleRayIntersect(v0a, v1a, v2a, start, dir, a, b, t)) { hit = TRUE; idx0 = 0; idx1 = 1; idx2 = 2; } - else if (LLTriangleRayIntersect(v[1], v[3], v[2], start, dir, a, b, t, FALSE)) + else if (LLTriangleRayIntersect(v1a, v3a, v2a, start, dir, a, b, t)) { hit = TRUE; idx0 = 1; idx1 = 3; idx2 = 2; } - else if (LLTriangleRayIntersect(v[2], v[1], v[0], start, dir, a, b, t, FALSE)) + else if (LLTriangleRayIntersect(v2a, v1a, v0a, start, dir, a, b, t)) { normal1 = -normal1; hit = TRUE; idx0 = 2; idx1 = 1; idx2 = 0; } - else if (LLTriangleRayIntersect(v[2], v[3], v[1], start, dir, a, b, t, FALSE)) + else if (LLTriangleRayIntersect(v2a, v3a, v1a, start, dir, a, b, t)) { normal1 = -normal1; hit = TRUE; @@ -908,7 +927,8 @@ BOOL LLVOGrass::lineSegmentIntersect(const LLVector3& start, const LLVector3& en closest_t = t; if (intersection != NULL) { - *intersection = start+dir*closest_t; + dir.mul(closest_t); + intersection->setAdd(start, dir); } if (tex_coord != NULL) @@ -918,7 +938,7 @@ BOOL LLVOGrass::lineSegmentIntersect(const LLVector3& start, const LLVector3& en if (normal != NULL) { - *normal = normal1; + normal->load3(normal1.mV); } ret = TRUE; } diff --git a/indra/newview/llvograss.h b/indra/newview/llvograss.h index 1e1c97ea58..f4f1da6fe2 100644 --- a/indra/newview/llvograss.h +++ b/indra/newview/llvograss.h @@ -34,7 +34,6 @@ #define LL_LLVOGRASS_H #include "llviewerobject.h" -#include "lldarray.h" #include class LLSurfacePatch; @@ -69,6 +68,7 @@ class LLVOGrass : public LLAlphaObject LLStrider& normalsp, LLStrider& texcoordsp, LLStrider& colorsp, + LLStrider& emissivep, LLStrider& indicesp); void updateFaceSize(S32 idx) { } @@ -81,14 +81,15 @@ class LLVOGrass : public LLAlphaObject /*virtual*/ BOOL isActive() const; // Whether this object needs to do an idleUpdate. /*virtual*/ void idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time); - /*virtual*/ BOOL lineSegmentIntersect(const LLVector3& start, const LLVector3& end, + /*virtual*/ BOOL lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, S32 face = -1, // which face to check, -1 = ALL_SIDES BOOL pick_transparent = FALSE, + BOOL pick_rigged = FALSE, S32* face_hit = NULL, // which face was hit - LLVector3* intersection = NULL, // return the intersection point + LLVector4a* intersection = NULL, // return the intersection point LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point - LLVector3* normal = NULL, // return the surface normal at the intersection point - LLVector3* bi_normal = NULL // return the surface bi-normal at the intersection point + LLVector4a* normal = NULL, // return the surface normal at the intersection point + LLVector4a* tangent = NULL // return the surface tangent at the intersection point ); static S32 sMaxGrassSpecies; @@ -107,7 +108,7 @@ class LLVOGrass : public LLAlphaObject F32 mBladeSizeX; F32 mBladeSizeY; - LLSurfacePatch *mPatch; // Stores the land patch where the grass is centered + std::weak_ptr mPatch; // Stores the land patch where the grass is centered U64 mLastPatchUpdateTime; diff --git a/indra/newview/llvoground.cpp b/indra/newview/llvoground.cpp index 97b7418b40..6ffb580cd1 100644 --- a/indra/newview/llvoground.cpp +++ b/indra/newview/llvoground.cpp @@ -156,6 +156,5 @@ BOOL LLVOGround::updateGeometry(LLDrawable *drawable) *(texCoordsp++) = LLVector2(0.5f, 0.5f); face->getVertexBuffer()->flush(); - LLPipeline::sCompiles++; return TRUE; } diff --git a/indra/newview/llvoicechannel.cpp b/indra/newview/llvoicechannel.cpp index 1e4c68b798..4acfad1eb2 100644 --- a/indra/newview/llvoicechannel.cpp +++ b/indra/newview/llvoicechannel.cpp @@ -35,28 +35,14 @@ extern AIHTTPTimeoutPolicy voiceCallCapResponder_timeout; - -LLVoiceChannel::voice_channel_map_t LLVoiceChannel::sVoiceChannelMap; -LLVoiceChannel::voice_channel_map_uri_t LLVoiceChannel::sVoiceChannelURIMap; -LLVoiceChannel* LLVoiceChannel::sCurrentVoiceChannel = NULL; -LLVoiceChannel* LLVoiceChannel::sSuspendedVoiceChannel = NULL; -LLVoiceChannel::channel_changed_signal_t LLVoiceChannel::sCurrentVoiceChannelChangedSignal; - -BOOL LLVoiceChannel::sSuspended = FALSE; - -// -// Constants -// -const U32 DEFAULT_RETRIES_COUNT = 3; - - class LLVoiceCallCapResponder : public LLHTTPClient::ResponderWithResult { public: LLVoiceCallCapResponder(const LLUUID& session_id) : mSessionID(session_id) {}; - /*virtual*/ void error(U32 status, const std::string& reason); // called with bad status codes - /*virtual*/ void result(const LLSD& content); + // called with bad status codes + virtual void httpFailure(void); + virtual void httpSuccess(void); /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return voiceCallCapResponder_timeout; } /*virtual*/ char const* getName(void) const { return "LLVoiceCallCapResponder"; } @@ -65,59 +51,29 @@ class LLVoiceCallCapResponder : public LLHTTPClient::ResponderWithResult }; -void LLVoiceCallCapResponder::error(U32 status, const std::string& reason) -{ - LL_WARNS("Voice") << "LLVoiceCallCapResponder error [status:" - << status << "]: " << reason << LL_ENDL; - LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(mSessionID); - if ( channelp ) - { - if ( 403 == status ) - { - //403 == no ability - LLNotificationsUtil::add( - "VoiceNotAllowed", - channelp->getNotifyArgs()); - } - else - { - LLNotificationsUtil::add( - "VoiceCallGenericError", - channelp->getNotifyArgs()); - } - channelp->deactivate(); - } -} +LLVoiceChannel::voice_channel_map_t LLVoiceChannel::sVoiceChannelMap; +LLVoiceChannel::voice_channel_map_uri_t LLVoiceChannel::sVoiceChannelURIMap; +LLVoiceChannel* LLVoiceChannel::sCurrentVoiceChannel = nullptr; +LLVoiceChannel* LLVoiceChannel::sSuspendedVoiceChannel = nullptr; +LLVoiceChannel::channel_changed_signal_t LLVoiceChannel::sCurrentVoiceChannelChangedSignal; -void LLVoiceCallCapResponder::result(const LLSD& content) -{ - LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(mSessionID); - if (channelp) - { - // *TODO: DEBUG SPAM - LLSD::map_const_iterator iter; - for(iter = content.beginMap(); iter != content.endMap(); ++iter) - { - LL_DEBUGS("Voice") << "LLVoiceCallCapResponder::result got " - << iter->first << LL_ENDL; - } +BOOL LLVoiceChannel::sSuspended = FALSE; - channelp->setChannelInfo( - content["voice_credentials"]["channel_uri"].asString(), - content["voice_credentials"]["channel_credentials"].asString()); - } -} +// +// Constants +// +const U32 DEFAULT_RETRIES_COUNT = 3; // // LLVoiceChannel // LLVoiceChannel::LLVoiceChannel(const LLUUID& session_id, const std::string& session_name) : + mCallDirection(OUTGOING_CALL), mSessionID(session_id), mState(STATE_NO_CHANNEL_INFO), mSessionName(session_name), - mCallDirection(OUTGOING_CALL), - mIgnoreNextSessionLeave(FALSE), - mCallEndedByAgent(false) + mCallEndedByAgent(false), + mIgnoreNextSessionLeave(FALSE) { mNotifyArgs["VOICE_CHANNEL_NAME"] = mSessionName; @@ -202,19 +158,9 @@ void LLVoiceChannel::handleStatusChange(EStatusType type) switch(type) { case STATUS_LOGIN_RETRY: - //mLoginNotificationHandle = LLNotifyBox::showXml("VoiceLoginRetry")->getHandle(); - LLNotificationsUtil::add("VoiceLoginRetry"); + // no user notice break; case STATUS_LOGGED_IN: - //if (!mLoginNotificationHandle.isDead()) - //{ - // LLNotifyBox* notifyp = (LLNotifyBox*)mLoginNotificationHandle.get(); - // if (notifyp) - // { - // notifyp->close(); - // } - // mLoginNotificationHandle.markDead(); - //} break; case STATUS_LEFT_CHANNEL: if (callStarted() && !mIgnoreNextSessionLeave && !sSuspended) @@ -275,11 +221,11 @@ void LLVoiceChannel::deactivate() //Default mic is OFF when leaving voice calls if (gSavedSettings.getBOOL("AutoDisengageMic") && - sCurrentVoiceChannel == this && - LLVoiceClient::getInstance()->getUserPTTState()) + sCurrentVoiceChannel == this /*&& + LLVoiceClient::getInstance()->getUserPTTState()*/) // Singu Note: This could be false, but we still need to do this. { gSavedSettings.setBOOL("PTTCurrentlyEnabled", true); - LLVoiceClient::getInstance()->inputUserControlState(true); + LLVoiceClient::getInstance()->setUserPTTState(false); } } LLVoiceClient::getInstance()->removeObserver(this); @@ -345,7 +291,7 @@ LLVoiceChannel* LLVoiceChannel::getChannelByID(const LLUUID& session_id) voice_channel_map_t::iterator found_it = sVoiceChannelMap.find(session_id); if (found_it == sVoiceChannelMap.end()) { - return NULL; + return nullptr; } else { @@ -359,7 +305,7 @@ LLVoiceChannel* LLVoiceChannel::getChannelByURI(std::string uri) voice_channel_map_uri_t::iterator found_it = sVoiceChannelURIMap.find(uri); if (found_it == sVoiceChannelURIMap.end()) { - return NULL; + return nullptr; } else { @@ -412,7 +358,7 @@ void LLVoiceChannel::doSetState(const EState& new_state) mState = new_state; if (!mStateChangedCallback.empty()) - mStateChangedCallback(old_state, mState, mCallDirection, mCallEndedByAgent); + mStateChangedCallback(old_state, mState, mCallDirection, mCallEndedByAgent, mSessionID); } //static @@ -663,6 +609,50 @@ void LLVoiceChannelGroup::setState(EState state) } } +void LLVoiceCallCapResponder::httpFailure(void) +{ + LL_WARNS("Voice") << "LLVoiceCallCapResponder error [status:" + << mStatus << "]: " << mReason << LL_ENDL; + LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(mSessionID); + if ( channelp ) + { + if ( 403 == mStatus ) + { + //403 == no ability + LLNotificationsUtil::add( + "VoiceNotAllowed", + channelp->getNotifyArgs()); + } + else + { + LLNotificationsUtil::add( + "VoiceCallGenericError", + channelp->getNotifyArgs()); + } + channelp->deactivate(); + } +} + +void LLVoiceCallCapResponder::httpSuccess(void) +{ + LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(mSessionID); + if (channelp) + { + // *TODO: DEBUG SPAM + LLSD::map_const_iterator iter; + for(iter = mContent.beginMap(); iter != mContent.endMap(); ++iter) + { + LL_DEBUGS("Voice") << "LLVoiceCallCapResponder::result got " + << iter->first << LL_ENDL; + } + + channelp->setChannelInfo( + mContent["voice_credentials"]["channel_uri"].asString(), + mContent["voice_credentials"]["channel_credentials"].asString()); + } +} + + // // LLVoiceChannelProximal // @@ -685,6 +675,13 @@ void LLVoiceChannelProximal::activate() // we're connected to a non-spatial channel, so disconnect. LLVoiceClient::getInstance()->leaveNonSpatialChannel(); } + + // Singu Note: Mic default state is OFF for local voice + if (LLVoiceClient::getInstance()->getUserPTTState() && LLVoiceClient::getInstance()->getPTTIsToggle() && gSavedSettings.getBOOL("AutoDisengageMic")) + { + LLVoiceClient::getInstance()->inputUserControlState(true); + } + LLVoiceChannel::activate(); } @@ -715,6 +712,7 @@ void LLVoiceChannelProximal::handleStatusChange(EStatusType status) // do not notify user when leaving proximal channel return; case STATUS_VOICE_DISABLED: + LLVoiceClient::getInstance()->setUserPTTState(false); //skip showing "Voice not available at your current location" when agent voice is disabled (EXT-4749) if(LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking()) { @@ -932,7 +930,7 @@ void LLVoiceChannelP2P::setState(EState state) { // you only "answer" voice invites in p2p mode // so provide a special purpose message here - if (mReceivedCall && state == STATE_RINGING) + if (state == STATE_RINGING) { gIMMgr->addSystemMessage(mSessionID, "answering", mNotifyArgs); doSetState(state); diff --git a/indra/newview/llvoicechannel.h b/indra/newview/llvoicechannel.h index 55dcf0f072..cf389d9713 100644 --- a/indra/newview/llvoicechannel.h +++ b/indra/newview/llvoicechannel.h @@ -49,7 +49,7 @@ class LLVoiceChannel : public LLVoiceClientStatusObserver OUTGOING_CALL } EDirection; - typedef boost::signals2::signal state_changed_signal_t; + typedef boost::signals2::signal state_changed_signal_t; // on current channel changed signal typedef boost::function channel_changed_callback_t; @@ -58,7 +58,6 @@ class LLVoiceChannel : public LLVoiceClientStatusObserver static boost::signals2::connection setCurrentVoiceChannelChangedCallback(channel_changed_callback_t cb, bool at_front = false); - LLVoiceChannel(const LLUUID& session_id, const std::string& session_name); virtual ~LLVoiceChannel(); @@ -202,4 +201,3 @@ class LLVoiceChannelP2P : public LLVoiceChannelGroup }; #endif // LL_VOICECHANNEL_H - diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp index dd1b7c6624..c98d19f823 100644 --- a/indra/newview/llvoiceclient.cpp +++ b/indra/newview/llvoiceclient.cpp @@ -1,3 +1,5 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com /** * @file llvoiceclient.cpp * @brief Voice client delegation class implementation. @@ -35,6 +37,7 @@ #include "llnotificationsutil.h" #include "llsdserialize.h" #include "llkeyboard.h" +#include "rlvhandler.h" const F32 LLVoiceClient::OVERDRIVEN_POWER_LEVEL = 0.7f; @@ -50,7 +53,7 @@ class LLVoiceHandler : public LLCommandHandler // requests will be throttled from a non-trusted browser LLVoiceHandler() : LLCommandHandler("voice", UNTRUSTED_THROTTLE) {} - bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web) + bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web) override { if (params[0].asString() == "effects") { @@ -110,10 +113,10 @@ std::string LLVoiceClientStatusObserver::status2string(LLVoiceClientStatusObserv LLVoiceClient::LLVoiceClient() : - mVoiceModule(NULL), - m_servicePump(NULL), - mVoiceEffectEnabled(LLCachedControl(gSavedSettings, "VoiceMorphingEnabled")), - mVoiceEffectDefault(LLCachedControl(gSavedPerAccountSettings, "VoiceEffectDefault")), + mVoiceModule(nullptr), + m_servicePump(nullptr), + mVoiceEffectEnabled(LLCachedControl(gSavedSettings, "VoiceMorphingEnabled", true)), + mVoiceEffectDefault(LLCachedControl(gSavedPerAccountSettings, "VoiceEffectDefault", "00000000-0000-0000-0000-000000000000")), mPTTDirty(true), mPTT(true), mUsePTT(true), @@ -152,18 +155,17 @@ void LLVoiceClient::userAuthorized(const std::string& user_id, const LLUUID &age } else { - mVoiceModule = NULL; + mVoiceModule = nullptr; return; } mVoiceModule->init(m_servicePump); mVoiceModule->userAuthorized(user_id, agentID); } - void LLVoiceClient::terminate() { if (mVoiceModule) mVoiceModule->terminate(); - mVoiceModule = NULL; + mVoiceModule = nullptr; } const LLVoiceVersionInfo LLVoiceClient::getVersion() @@ -191,7 +193,10 @@ void LLVoiceClient::updateSettings() updateMicMuteLogic(); - if (mVoiceModule) mVoiceModule->updateSettings(); + if (mVoiceModule) + { + mVoiceModule->updateSettings(); + } } //-------------------------------------------------- @@ -304,7 +309,7 @@ const LLVoiceDeviceList& LLVoiceClient::getRenderDevices() //-------------------------------------------------- // participants -void LLVoiceClient::getParticipantList(std::set &participants) +void LLVoiceClient::getParticipantList(uuid_set_t &participants) { if (mVoiceModule) { @@ -312,7 +317,7 @@ void LLVoiceClient::getParticipantList(std::set &participants) } else { - participants = std::set(); + participants = uuid_set_t(); } } @@ -393,24 +398,36 @@ void LLVoiceClient::setNonSpatialChannel( const std::string &uri, const std::string &credentials) { - if (mVoiceModule) mVoiceModule->setNonSpatialChannel(uri, credentials); + if (mVoiceModule) + { + mVoiceModule->setNonSpatialChannel(uri, credentials); + } } void LLVoiceClient::setSpatialChannel( const std::string &uri, const std::string &credentials) { - if (mVoiceModule) mVoiceModule->setSpatialChannel(uri, credentials); + if (mVoiceModule) + { + mVoiceModule->setSpatialChannel(uri, credentials); + } } void LLVoiceClient::leaveNonSpatialChannel() { - if (mVoiceModule) mVoiceModule->leaveNonSpatialChannel(); + if (mVoiceModule) + { + mVoiceModule->leaveNonSpatialChannel(); + } } void LLVoiceClient::leaveChannel(void) { - if (mVoiceModule) mVoiceModule->leaveChannel(); + if (mVoiceModule) + { + mVoiceModule->leaveChannel(); + } } std::string LLVoiceClient::getCurrentChannel() @@ -496,7 +513,10 @@ bool LLVoiceClient::voiceEnabled() void LLVoiceClient::setVoiceEnabled(bool enabled) { - if (mVoiceModule) mVoiceModule->setVoiceEnabled(enabled); + if (mVoiceModule) + { + mVoiceModule->setVoiceEnabled(enabled); + } } void LLVoiceClient::updateMicMuteLogic() @@ -526,6 +546,8 @@ void LLVoiceClient::setLipSyncEnabled(BOOL enabled) BOOL LLVoiceClient::lipSyncEnabled() { + if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWNAMETAGS)) return false; // RLVa:LF - You get nothing now! + if (mVoiceModule) { return mVoiceModule->lipSyncEnabled(); @@ -540,6 +562,7 @@ void LLVoiceClient::setMuteMic(bool muted) { mMuteMic = muted; updateMicMuteLogic(); + mMicroChangedSignal(); } @@ -550,6 +573,7 @@ void LLVoiceClient::setUserPTTState(bool ptt) { mUserPTTState = ptt; updateMicMuteLogic(); + mMicroChangedSignal(); } bool LLVoiceClient::getUserPTTState() @@ -632,31 +656,32 @@ void LLVoiceClient::keyDown(KEY key, MASK mask) return; } - if(!mPTTIsMiddleMouse) + if(!mPTTIsMiddleMouse && mPTTKey != KEY_NONE) { - bool down = (mPTTKey != KEY_NONE) - && gKeyboard->getKeyDown(mPTTKey); - inputUserControlState(down); + bool down = gKeyboard->getKeyDown(mPTTKey); + if (down) + { + inputUserControlState(down); + } } } void LLVoiceClient::keyUp(KEY key, MASK mask) { - if(!mPTTIsMiddleMouse) + if(!mPTTIsMiddleMouse && mPTTKey != KEY_NONE) { - bool down = (mPTTKey != KEY_NONE) - && gKeyboard->getKeyDown(mPTTKey); - inputUserControlState(down); + bool down = gKeyboard->getKeyDown(mPTTKey); + if (!down) + { + inputUserControlState(down); + } } } void LLVoiceClient::middleMouseState(bool down) { if(mPTTIsMiddleMouse) { - if(mPTTIsMiddleMouse) - { inputUserControlState(down); - } } } @@ -711,14 +736,7 @@ BOOL LLVoiceClient::isParticipantAvatar(const LLUUID& id) BOOL LLVoiceClient::isOnlineSIP(const LLUUID& id) { - if (mVoiceModule) - { - return mVoiceModule->isOnlineSIP(id); - } - else - { return FALSE; - } } BOOL LLVoiceClient::getIsSpeaking(const LLUUID& id) @@ -842,10 +860,11 @@ LLVoiceEffectInterface* LLVoiceClient::getVoiceEffectInterface() const class LLViewerRequiredVoiceVersion : public LLHTTPNode { static BOOL sAlertedUser; - virtual void post( + + void post( LLHTTPNode::ResponsePtr response, const LLSD& context, - const LLSD& input) const + const LLSD& input) const override { //You received this messsage (most likely on region cross or //teleport) @@ -872,10 +891,10 @@ class LLViewerRequiredVoiceVersion : public LLHTTPNode class LLViewerParcelVoiceInfo : public LLHTTPNode { - virtual void post( + void post( LLHTTPNode::ResponsePtr response, const LLSD& context, - const LLSD& input) const + const LLSD& input) const override { //the parcel you are in has changed something about its //voice information diff --git a/indra/newview/llvoiceclient.h b/indra/newview/llvoiceclient.h index 761a1a768a..1c2640085c 100644 --- a/indra/newview/llvoiceclient.h +++ b/indra/newview/llvoiceclient.h @@ -139,7 +139,7 @@ class LLVoiceModuleInterface virtual LLVoiceDeviceList& getCaptureDevices()=0; virtual LLVoiceDeviceList& getRenderDevices()=0; - virtual void getParticipantList(std::set &participants)=0; + virtual void getParticipantList(uuid_set_t &participants)=0; virtual bool isParticipant(const LLUUID& speaker_id)=0; //@} @@ -198,7 +198,6 @@ class LLVoiceModuleInterface //@{ virtual BOOL getVoiceEnabled(const LLUUID& id)=0; // true if we've received data for this avatar virtual std::string getDisplayName(const LLUUID& id)=0; - virtual BOOL isOnlineSIP(const LLUUID &id)=0; virtual BOOL isParticipantAvatar(const LLUUID &id)=0; virtual BOOL getIsSpeaking(const LLUUID& id)=0; virtual BOOL getIsModeratorMuted(const LLUUID& id)=0; @@ -302,6 +301,9 @@ class LLVoiceClient: public LLSingleton LLVoiceClient(); ~LLVoiceClient(); + typedef boost::signals2::signal micro_changed_signal_t; + micro_changed_signal_t mMicroChangedSignal; + void init(LLPumpIO *pump); // Call this once at application startup (creates connector) void terminate(); // Call this to clean up during shutdown @@ -400,6 +402,8 @@ class LLVoiceClient: public LLSingleton void keyUp(KEY key, MASK mask); void middleMouseState(bool down); + boost::signals2::connection MicroChangedCallback(const micro_changed_signal_t::slot_type& cb ) { return mMicroChangedSignal.connect(cb); } + ///////////////////////////// // Accessors for data related to nearby speakers @@ -416,7 +420,7 @@ class LLVoiceClient: public LLSingleton ///////////////////////////// BOOL getAreaVoiceDisabled(); // returns true if the area the avatar is in is speech-disabled. // Use this to determine whether to show a "no speech" icon in the menu bar. - void getParticipantList(std::set &participants); + void getParticipantList(uuid_set_t &participants); bool isParticipant(const LLUUID& speaker_id); ////////////////////////// @@ -455,6 +459,7 @@ class LLVoiceClient: public LLSingleton LLVoiceModuleInterface* mVoiceModule; LLPumpIO *m_servicePump; + LLCachedControl mVoiceEffectEnabled; LLCachedControl mVoiceEffectDefault; diff --git a/indra/newview/llvoiceremotectrl.cpp b/indra/newview/llvoiceremotectrl.cpp index 1863020f96..fb6988378d 100644 --- a/indra/newview/llvoiceremotectrl.cpp +++ b/indra/newview/llvoiceremotectrl.cpp @@ -49,14 +49,7 @@ LLVoiceRemoteCtrl::LLVoiceRemoteCtrl (const std::string& name) : LLPanel(name) { setIsChrome(TRUE); - if (gSavedSettings.getBOOL("ShowVoiceChannelPopup")) - { - LLUICtrlFactory::getInstance()->buildPanel(this, "panel_voice_remote_expanded.xml"); - } - else - { - LLUICtrlFactory::getInstance()->buildPanel(this, "panel_voice_remote.xml"); - } + LLUICtrlFactory::getInstance()->buildPanel(this, gSavedSettings.getBOOL("ShowVoiceChannelPopup") ? "panel_voice_remote_expanded.xml" : "panel_voice_remote.xml"); setFocusRoot(TRUE); } @@ -73,7 +66,6 @@ BOOL LLVoiceRemoteCtrl::postBuild() mTalkBtn->setMouseUpCallback(boost::bind(&LLVoiceRemoteCtrl::onBtnTalkReleased)); mTalkLockBtn = getChild("ptt_lock"); - mTalkLockBtn->setClickedCallback(boost::bind(&LLVoiceRemoteCtrl::onBtnLock,this)); mSpeakersBtn = getChild("speakers_btn"); mSpeakersBtn->setClickedCallback(boost::bind(&LLVoiceRemoteCtrl::onClickSpeakers)); @@ -92,12 +84,12 @@ BOOL LLVoiceRemoteCtrl::postBuild() voice_channel_bg->setClickedCallback(boost::bind(&LLVoiceRemoteCtrl::onClickVoiceChannel)); mVoiceVolIcon.connect(this,"voice_volume"); - mShowChanBtn.connect(this,"show_channel"); return TRUE; } void LLVoiceRemoteCtrl::draw() { + // Singu TODO: I'm pretty sure voice channel changing can be done outside of draw call ~Liru BOOL voice_active = FALSE; LLVoiceChannel* channelp = LLVoiceChannel::getCurrentVoiceChannel(); if (channelp) @@ -108,15 +100,13 @@ void LLVoiceRemoteCtrl::draw() mTalkBtn->setEnabled(voice_active); mTalkLockBtn->setEnabled(voice_active); - static LLCachedControl ptt_currently_enabled("PTTCurrentlyEnabled",false); // propagate ptt state to button display, if (!mTalkBtn->hasMouseCapture()) { // not in push to talk mode, or push to talk is active means I'm talking - mTalkBtn->setToggleState(!ptt_currently_enabled || LLVoiceClient::getInstance()->getUserPTTState()); + mTalkBtn->setToggleState(!mTalkLockBtn->getToggleState() || LLVoiceClient::getInstance()->getUserPTTState()); } mSpeakersBtn->setToggleState(LLFloaterActiveSpeakers::instanceVisible(LLSD())); - mTalkLockBtn->setToggleState(!ptt_currently_enabled); std::string talk_blip_image; if (LLVoiceClient::getInstance()->getIsSpeaking(gAgent.getID())) @@ -154,7 +144,7 @@ void LLVoiceRemoteCtrl::draw() LLIconCtrl* icon = mVoiceVolIcon; if (icon) { - icon->setImage(talk_blip_image); + icon->setValue(talk_blip_image); } LLFloater* voice_floater = LLFloaterChatterBox::getInstance()->getCurrentVoiceFloater(); @@ -185,7 +175,7 @@ void LLVoiceRemoteCtrl::draw() LLIconCtrl* voice_channel_icon = findChild("voice_channel_icon"); if (voice_channel_icon && voice_floater) { - voice_channel_icon->setImage(voice_floater->getString("voice_icon")); + voice_channel_icon->setValue(voice_floater->getString("voice_icon")); } if (voice_channel_bg) @@ -207,19 +197,6 @@ void LLVoiceRemoteCtrl::draw() } } - LLButton* expand_button = mShowChanBtn; - if (expand_button) - { - if (expand_button->getToggleState()) - { - expand_button->setImageOverlay(std::string("arrow_down.tga")); - } - else - { - expand_button->setImageOverlay(std::string("arrow_up.tga")); - } - } - LLPanel::draw(); } @@ -250,27 +227,13 @@ void LLVoiceRemoteCtrl::onBtnTalkReleased() } } -void LLVoiceRemoteCtrl::onBtnLock(void* user_data) -{ - LLVoiceRemoteCtrl* remotep = (LLVoiceRemoteCtrl*)user_data; - - gSavedSettings.setBOOL("PTTCurrentlyEnabled", !remotep->mTalkLockBtn->getToggleState()); -} - //static void LLVoiceRemoteCtrl::onClickPopupBtn(void* user_data) { LLVoiceRemoteCtrl* remotep = (LLVoiceRemoteCtrl*)user_data; remotep->deleteAllChildren(); - if (gSavedSettings.getBOOL("ShowVoiceChannelPopup")) - { - LLUICtrlFactory::getInstance()->buildPanel(remotep, "panel_voice_remote_expanded.xml"); - } - else - { - LLUICtrlFactory::getInstance()->buildPanel(remotep, "panel_voice_remote.xml"); - } + LLUICtrlFactory::getInstance()->buildPanel(remotep, gSavedSettings.getBOOL("ShowVoiceChannelPopup") ? "panel_voice_remote_expanded.xml" : "panel_voice_remote.xml"); gOverlayBar->layoutButtons(); } diff --git a/indra/newview/llvoiceremotectrl.h b/indra/newview/llvoiceremotectrl.h index 69ea20ae10..f6ea337050 100644 --- a/indra/newview/llvoiceremotectrl.h +++ b/indra/newview/llvoiceremotectrl.h @@ -48,7 +48,6 @@ class LLVoiceRemoteCtrl : public LLPanel /*virtual*/ BOOL postBuild(); /*virtual*/ void draw(); - static void onBtnLock(void* user_data); static void onBtnTalkHeld(); static void onBtnTalkReleased(); static void onBtnTalkClicked(); @@ -62,7 +61,6 @@ class LLVoiceRemoteCtrl : public LLPanel LLButton* mTalkLockBtn; LLButton* mSpeakersBtn; CachedUICtrl mVoiceVolIcon; - CachedUICtrl mShowChanBtn; }; #endif // LL_LLVOICEREMOTECTRL_H diff --git a/indra/newview/llvoicevisualizer.cpp b/indra/newview/llvoicevisualizer.cpp index 0547b4504c..bfed1afcf1 100644 --- a/indra/newview/llvoicevisualizer.cpp +++ b/indra/newview/llvoicevisualizer.cpp @@ -142,7 +142,7 @@ LLVoiceVisualizer::LLVoiceVisualizer( const U8 type ) for (int i=0; igetSizeFast(_PREHASH_Effect, blocknum, _PREHASH_TypeData); if (size != 1) { - llwarns << "Voice effect with bad size " << size << llendl; + LL_WARNS() << "Voice effect with bad size " << size << LL_ENDL; return; } mesgsys->getBinaryDataFast(_PREHASH_Effect, _PREHASH_TypeData, packed_data, 1, blocknum); diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index edfecf6819..dccd0242c3 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -61,9 +61,6 @@ // for base64 decoding #include "apr_base64.h" -extern AIHTTPTimeoutPolicy vivoxVoiceAccountProvisionResponder_timeout; -extern AIHTTPTimeoutPolicy vivoxVoiceClientCapResponder_timeout; - #define USE_SESSION_GROUPS 0 const F32 VOLUME_SCALE_VIVOX = 0.01f; @@ -116,17 +113,19 @@ static int scale_speaker_volume(float volume) class LLVivoxVoiceAccountProvisionResponder : public LLHTTPClient::ResponderWithResult { + LOG_CLASS(LLVivoxVoiceAccountProvisionResponder); public: LLVivoxVoiceAccountProvisionResponder(int retries) { mRetries = retries; } - /*virtual*/ void error(U32 status, const std::string& reason) +private: + /* virtual */ void httpFailure() { LL_WARNS("Voice") << "ProvisionVoiceAccountRequest returned an error, " << ( (mRetries > 0) ? "retrying" : "too many retries (giving up)" ) - << status << "]: " << reason << LL_ENDL; + << " " << dumpResponse() << LL_ENDL; if ( mRetries > 0 ) { @@ -138,14 +137,19 @@ class LLVivoxVoiceAccountProvisionResponder : } } - /*virtual*/ void result(const LLSD& content) + /* virtual */ void httpSuccess() { - std::string voice_sip_uri_hostname; std::string voice_account_server_uri; - LL_DEBUGS("Voice") << "ProvisionVoiceAccountRequest response:" << ll_pretty_print_sd(content) << LL_ENDL; + LL_DEBUGS("Voice") << "ProvisionVoiceAccountRequest response:" << dumpResponse() << LL_ENDL; + const LLSD& content = getContent(); + if (!content.isMap()) + { + failureResult(HTTP_INTERNAL_ERROR_OTHER, "Malformed response contents", content); + return; + } if(content.has("voice_sip_uri_hostname")) voice_sip_uri_hostname = content["voice_sip_uri_hostname"].asString(); @@ -158,10 +162,8 @@ class LLVivoxVoiceAccountProvisionResponder : content["password"].asString(), voice_sip_uri_hostname, voice_account_server_uri); - } - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return vivoxVoiceAccountProvisionResponder_timeout; } /*virtual*/ char const* getName(void) const { return "LLVivoxVoiceAccountProvisionResponder"; } private: @@ -177,49 +179,43 @@ class LLVivoxVoiceClientMuteListObserver : public LLMuteListObserver /* virtual */ void onChange() { LLVivoxVoiceClient::getInstance()->muteListChanged();} }; -class LLVivoxVoiceClientFriendsObserver : public LLFriendObserver -{ -public: - /* virtual */ void changed(U32 mask) { LLVivoxVoiceClient::getInstance()->updateFriends(mask);} -}; static LLVivoxVoiceClientMuteListObserver mutelist_listener; static bool sMuteListListener_listening = false; -static LLVivoxVoiceClientFriendsObserver *friendslist_listener = NULL; - /////////////////////////////////////////////////////////////////////////////////////////////// class LLVivoxVoiceClientCapResponder : public LLHTTPClient::ResponderWithResult { + LOG_CLASS(LLVivoxVoiceClientCapResponder); public: LLVivoxVoiceClientCapResponder(LLVivoxVoiceClient::state requesting_state) : mRequestingState(requesting_state) {}; - /*virtual*/ void error(U32 status, const std::string& reason); // called with bad status codes - /*virtual*/ void result(const LLSD& content); - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return vivoxVoiceClientCapResponder_timeout; } - /*virtual*/ char const* getName(void) const { return "LLVivoxVoiceClientCapResponder"; } - private: + // called with bad status codes + /*virtual*/ void httpFailure(); + /*virtual*/ void httpSuccess(); + /*virtual*/ char const* getName() const { return "LLVivoxVoiceClientCapResponder"; } + LLVivoxVoiceClient::state mRequestingState; // state }; -void LLVivoxVoiceClientCapResponder::error(U32 status, const std::string& reason) +void LLVivoxVoiceClientCapResponder::httpFailure() { - LL_WARNS("Voice") << "LLVivoxVoiceClientCapResponder error [status:" - << status << "]: " << reason << LL_ENDL; + LL_WARNS("Voice") << dumpResponse() << LL_ENDL; LLVivoxVoiceClient::getInstance()->sessionTerminate(); } -void LLVivoxVoiceClientCapResponder::result(const LLSD& content) +void LLVivoxVoiceClientCapResponder::httpSuccess() { LLSD::map_const_iterator iter; - LL_DEBUGS("Voice") << "ParcelVoiceInfoRequest response:" << ll_pretty_print_sd(content) << LL_ENDL; + LL_DEBUGS("Voice") << "ParcelVoiceInfoRequest response:" << dumpResponse() << LL_ENDL; std::string uri; std::string credentials; + const LLSD& content = getContent(); if ( content.has("voice_credentials") ) { LLSD voice_credentials = content["voice_credentials"]; @@ -302,6 +298,7 @@ LLVivoxVoiceClient::LLVivoxVoiceClient() : mSessionTerminateRequested(false), mRelogRequested(false), mConnected(false), + mTerminateDaemon(false), mPump(NULL), mSpatialJoiningNum(0), @@ -355,6 +352,7 @@ LLVivoxVoiceClient::LLVivoxVoiceClient() : mCaptureBufferRecording(false), mCaptureBufferRecorded(false), mCaptureBufferPlaying(false), + mShutdownComplete(true), mPlayRequestCount(0), mAvatarNameCacheConnection() @@ -410,6 +408,14 @@ void LLVivoxVoiceClient::terminate() { logout(); connectorShutdown(); +#ifdef LL_WINDOWS + S32 count = 0; + while (!mShutdownComplete && 10 > ++count) + { + stateMachine(); + _sleep(1000); + } +#endif // LL_WINDOW closeSocket(); // Need to do this now -- bad things happen if the destructor does it later. cleanUp(); } @@ -424,7 +430,6 @@ void LLVivoxVoiceClient::terminate() void LLVivoxVoiceClient::cleanUp() { deleteAllSessions(); - deleteAllBuddies(); deleteAllVoiceFonts(); deleteVoiceFontTemplates(); } @@ -502,18 +507,25 @@ bool LLVivoxVoiceClient::writeString(const std::string &str) void LLVivoxVoiceClient::connectorCreate() { std::ostringstream stream; - std::string logpath = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ""); std::string loglevel = "0"; // Transition to stateConnectorStarted when the connector handle comes back. setState(stateConnectorStarting); - std::string savedLogLevel = gSavedSettings.getString("VivoxDebugLevel"); + std::string logpath = gSavedSettings.getString("VivoxLogDirectory"); + if (logpath.empty()) + { + logpath = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ""); + } + if (LLStringUtil::endsWith(logpath, gDirUtilp->getDirDelimiter())) + { + logpath.resize(logpath.size()-1); + } - if(savedLogLevel != "-1") + std::string savedLogLevel = gSavedSettings.getString("VivoxDebugLevel"); + if(savedLogLevel != "0") { LL_DEBUGS("Voice") << "creating connector with logging enabled" << LL_ENDL; - loglevel = "10"; } stream @@ -531,13 +543,14 @@ void LLVivoxVoiceClient::connectorCreate() stream << "" - << "" << logpath << "" - << "Connector" - << ".log" - << "" << loglevel << "" + << "" << logpath << "" + << "Connector" + << ".log" + << "" << loglevel << "" << "" - << "SecondLifeViewer.1" - << "\n\n\n"; + << "" //Name can cause problems per vivox. + << "12" + << "\n\n\n"; writeString(stream.str()); } @@ -555,6 +568,7 @@ void LLVivoxVoiceClient::connectorShutdown() << "" << "\n\n\n"; + mShutdownComplete = false; mConnectorHandle.clear(); writeString(stream.str()); @@ -575,25 +589,25 @@ void LLVivoxVoiceClient::requestVoiceAccountProvision(S32 retries) { LLViewerRegion *region = gAgent.getRegion(); - if ( region && (mVoiceEnabled || !mIsInitialized)) + // If we've not received the capability yet, return. + // the password will remain empty, so we'll remain in + // stateIdle + if ( region && + region->capabilitiesReceived() && + (mVoiceEnabled || !mIsInitialized)) { std::string url = region->getCapability("ProvisionVoiceAccountRequest"); - if ( url.empty() ) + if ( !url.empty() ) { - // we've not received the capability yet, so return. - // the password will remain empty, so we'll remain in - // stateIdle - return; - } - - LLHTTPClient::post( - url, - LLSD(), - new LLVivoxVoiceAccountProvisionResponder(retries)); + LLHTTPClient::post( + url, + LLSD(), + new LLVivoxVoiceAccountProvisionResponder(retries)); - setState(stateConnectorStart); + setState(stateConnectorStart); + } } } @@ -746,7 +760,7 @@ void LLVivoxVoiceClient::stateMachine() setVoiceEnabled(false); } - if(mVoiceEnabled || !mIsInitialized) + if(mVoiceEnabled || (!mIsInitialized && !mTerminateDaemon) ) { updatePosition(); } @@ -759,11 +773,12 @@ void LLVivoxVoiceClient::stateMachine() if((getState() != stateDisabled) && (getState() != stateDisableCleanup)) { // User turned off voice support. Send the cleanup messages, close the socket, and reset. - if(!mConnected) + if(!mConnected || mTerminateDaemon) { // if voice was turned off after the daemon was launched but before we could connect to it, we may need to issue a kill. LL_INFOS("Voice") << "Disabling voice before connection to daemon, terminating." << LL_ENDL; killGateway(); + mTerminateDaemon = false; } logout(); @@ -804,7 +819,7 @@ void LLVivoxVoiceClient::stateMachine() // Voice is locked out, we must not launch the vivox daemon. setState(stateJail); } - else if(!isGatewayRunning()) + else if(!isGatewayRunning() && gSavedSettings.getBOOL("EnableVoiceChat")) { if (true) // production build, not test { @@ -815,12 +830,13 @@ void LLVivoxVoiceClient::stateMachine() // using glib first. char *voice_path = g_find_program_in_path ("SLVoice"); std::string exe_path; - if (voice_path) { + if (voice_path) + { exe_path = llformat("%s", voice_path); free(voice_path); - } else { - exe_path = gDirUtilp->getExecutableDir() + gDirUtilp->getDirDelimiter() + "SLVoice"; } + else + exe_path = gDirUtilp->getExecutableDir() + gDirUtilp->getDirDelimiter() + "SLVoice"; #else // *FIX:Mani - Using the executable dir instead // of mAppRODataDir, the working directory from which the app @@ -842,14 +858,53 @@ void LLVivoxVoiceClient::stateMachine() { // vivox executable exists. Build the command line and launch the daemon. std::string args, cmd; - // SLIM SDK: these arguments are no longer necessary. -// std::string args = " -p tcp -h -c"; + std::string loglevel = gSavedSettings.getString("VivoxDebugLevel"); +// Singu Note: omit shutdown timeout for Linux, as we are using 2.x version of the SDK there +// Singu TODO: Remove this when the Vivox SDK 4.x is working on Linux +#ifndef LL_LINUX + std::string shutdown_timeout = gSavedSettings.getString("VivoxShutdownTimeout"); +#endif + if(loglevel.empty()) + { + loglevel = "0"; // turn logging off completely + } + + args += " -ll "; +// Singu Note: hard code log level to -1 for Linux, as we are using 2.x version of the SDK there +// Singu TODO: Remove this when the Vivox SDK 4.x is working on Linux +#if LL_LINUX + args += "-1"; +#else + args += loglevel; +#endif + std::string log_folder = gSavedSettings.getString("VivoxLogDirectory"); + + if (log_folder.empty()) + { + log_folder = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ""); + } + if (LLStringUtil::endsWith(log_folder, gDirUtilp->getDirDelimiter())) + { + log_folder.resize(log_folder.size()-1); + } + args += " -lf "; + args += '"' + log_folder + '"'; + +// Singu Note: omit shutdown timeout for Linux, as we are using 2.x version of the SDK there +// Singu TODO: Remove this when the Vivox SDK 4.x is working on Linux +#ifndef LL_LINUX + if(!shutdown_timeout.empty()) + { + args += " -st "; + args += shutdown_timeout; + } +#endif - // If we allow multiple instances of the viewer to start the voice - // daemon, set TEMPORARY random voice port + // If we allow multiple instances of the viewer to start the voicedaemon if (gSavedSettings.getBOOL("VoiceMultiInstance")) { + // Set TEMPORARY random voice port LLControlVariable* voice_port = gSavedSettings.getControl("VoicePort"); if (voice_port) { @@ -857,19 +912,7 @@ void LLVivoxVoiceClient::stateMachine() S32 port_nr = 30000 + ll_rand(20000); voice_port->setValue(LLSD(port_nr), DO_NOT_PERSIST); } - } - - if(loglevel.empty()) - { - loglevel = "-1"; // turn logging off completely - } - - args += " -ll "; - args += loglevel; - - // Tell voice gateway to listen to a specific port - if (gSavedSettings.getBOOL("VoiceMultiInstance")) - { + // Tell voice gateway to listen to a specific port args += llformat(" -i 127.0.0.1:%u", gSavedSettings.getU32("VoicePort")); } @@ -1288,6 +1331,7 @@ void LLVivoxVoiceClient::stateMachine() std::stringstream errs; errs << mVoiceAccountServerURI << "\n:UDP: 3478, 3479, 5060, 5062, 12000-17000"; args["HOSTID"] = errs.str(); + mTerminateDaemon = true; LLNotificationsUtil::add("NoVoiceConnect", args); } else @@ -1338,12 +1382,6 @@ void LLVivoxVoiceClient::stateMachine() setState(stateVoiceFontsReceived); } - // request the current set of block rules (we'll need them when updating the friends list) - accountListBlockRulesSendMessage(); - - // request the current set of auto-accept rules - accountListAutoAcceptRulesSendMessage(); - // Set up the mute list observer if it hasn't been set up already. if((!sMuteListListener_listening)) { @@ -1351,13 +1389,6 @@ void LLVivoxVoiceClient::stateMachine() sMuteListListener_listening = true; } - // Set up the friends list observer if it hasn't been set up already. - if(friendslist_listener == NULL) - { - friendslist_listener = new LLVivoxVoiceClientFriendsObserver; - LLAvatarTracker::instance().addObserver(friendslist_listener); - } - // Set the initial state of mic mute, local speaker volume, etc. { std::ostringstream stream; @@ -1427,9 +1458,7 @@ void LLVivoxVoiceClient::stateMachine() case stateNoChannel: LL_DEBUGS("Voice") << "State No Channel" << LL_ENDL; mSpatialJoiningNum = 0; - // Do this here as well as inside sendPositionalUpdate(). - // Otherwise, if you log in but don't join a proximal channel (such as when your login location has voice disabled), your friends list won't sync. - sendFriendsListUpdates(); + if(mSessionTerminateRequested || (!mVoiceEnabled && mIsInitialized)) { @@ -1500,7 +1529,7 @@ void LLVivoxVoiceClient::stateMachine() { // Notify observers to let them know there is problem with voice notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_VOICE_DISABLED); - llwarns << "There seems to be problem with connection to voice server. Disabling voice chat abilities." << llendl; + LL_WARNS() << "There seems to be problem with connection to voice server. Disabling voice chat abilities." << LL_ENDL; } // Increase mSpatialJoiningNum only for spatial sessions- it's normal to reach this case for @@ -1626,7 +1655,6 @@ void LLVivoxVoiceClient::stateMachine() mUpdateTimer.setTimerExpirySec(UPDATE_THROTTLE_SECONDS); sendPositionalUpdate(); } - mIsInitialized = true; } break; @@ -1661,7 +1689,7 @@ void LLVivoxVoiceClient::stateMachine() // Always reset the terminate request flag when we get here. mSessionTerminateRequested = false; - if((mVoiceEnabled || !mIsInitialized) && !mRelogRequested) + if((mVoiceEnabled || !mIsInitialized) && !mRelogRequested && !LLApp::isExiting()) { // Just leaving a channel, go back to stateNoChannel (the "logged in but have no channel" state). setState(stateNoChannel); @@ -1704,6 +1732,7 @@ void LLVivoxVoiceClient::stateMachine() //MARK: stateConnectorStopping case stateConnectorStopping: // waiting for connector stop // The handler for the Connector.InitiateShutdown response will transition from here to stateConnectorStopped. + mShutdownComplete = true; break; //MARK: stateConnectorStopped @@ -1801,7 +1830,7 @@ void LLVivoxVoiceClient::loginSendMessage() << "" << mAccountName << "" << "" << mAccountPassword << "" << "VerifyAnswer" - << "true" + << "false" << "Application" << "5" << (autoPostCrashDumps?"true":"") @@ -1837,42 +1866,6 @@ void LLVivoxVoiceClient::logoutSendMessage() } } -void LLVivoxVoiceClient::accountListBlockRulesSendMessage() -{ - if(!mAccountHandle.empty()) - { - std::ostringstream stream; - - LL_DEBUGS("Voice") << "requesting block rules" << LL_ENDL; - - stream - << "" - << "" << mAccountHandle << "" - << "" - << "\n\n\n"; - - writeString(stream.str()); - } -} - -void LLVivoxVoiceClient::accountListAutoAcceptRulesSendMessage() -{ - if(!mAccountHandle.empty()) - { - std::ostringstream stream; - - LL_DEBUGS("Voice") << "requesting auto-accept rules" << LL_ENDL; - - stream - << "" - << "" << mAccountHandle << "" - << "" - << "\n\n\n"; - - writeString(stream.str()); - } -} - void LLVivoxVoiceClient::sessionGroupCreateSendMessage() { if(!mAccountHandle.empty()) @@ -2638,14 +2631,15 @@ void LLVivoxVoiceClient::sendPositionalUpdate(void) if(mAudioSession && (mAudioSession->mVolumeDirty || mAudioSession->mMuteDirty)) { - participantMap::iterator iter = mAudioSession->mParticipantsByURI.begin(); + // Singu Note: mParticipantList has replaced mParticipantsByURI. + participantList::iterator iter = mAudioSession->mParticipantList.begin(); mAudioSession->mVolumeDirty = false; mAudioSession->mMuteDirty = false; - for(; iter != mAudioSession->mParticipantsByURI.end(); iter++) + for(; iter != mAudioSession->mParticipantList.end(); iter++) { - participantState *p = iter->second; + participantState *p = &*iter; if(p->mVolumeDirty) { @@ -2653,7 +2647,7 @@ void LLVivoxVoiceClient::sendPositionalUpdate(void) if(!p->mIsSelf) { // scale from the range 0.0-1.0 to vivox volume in the range 0-100 - S32 volume = llround(p->mVolume / VOLUME_SCALE_VIVOX); + S32 volume = ll_pos_round(p->mVolume / VOLUME_SCALE_VIVOX); bool mute = p->mOnMuteList; if(mute) @@ -2672,7 +2666,7 @@ void LLVivoxVoiceClient::sendPositionalUpdate(void) mute = true; } - LL_DEBUGS("Voice") << "Setting volume/mute for avatar " << p->mAvatarID << " to " << volume << (mute?"/true":"/false") << LL_ENDL; + LL_DEBUGS("Voice") << "Setting volume/mute for avatar " << p->mAvatarID << " to " << volume << (mute ? "/true" : "/false") << LL_ENDL; // SLIM SDK: Send both volume and mute commands. @@ -2708,9 +2702,6 @@ void LLVivoxVoiceClient::sendPositionalUpdate(void) writeString(stream.str()); } - // Friends list updates can be huge, especially on the first voice login of an account with lots of friends. - // Batching them all together can choke SLVoice, so send them in separate writes. - sendFriendsListUpdates(); } void LLVivoxVoiceClient::buildSetCaptureDevice(std::ostringstream &stream) @@ -2808,275 +2799,6 @@ void LLVivoxVoiceClient::buildLocalAudioUpdates(std::ostringstream &stream) } -void LLVivoxVoiceClient::checkFriend(const LLUUID& id) -{ - buddyListEntry *buddy = findBuddy(id); - - // Make sure we don't add a name before it's been looked up. - LLAvatarName av_name; - if(LLAvatarNameCache::get(id, &av_name)) - { - // *NOTE: We feed legacy names to Vivox because we don't know if their service - // can support a mix of new and old clients with different sorts of names. - std::string name = av_name.getLegacyName(); - - if(buddy) - { - // This buddy is already in both lists (vivox buddies and avatar cache). - // Trust the avatar cache more for the display name (vivox display name are notoriously wrong) - buddy->mDisplayName = name; - } - else - { - // This buddy was not in the vivox list, needs to be added. - buddy = addBuddy(sipURIFromID(id), name); - buddy->mUUID = id; - } - - const LLRelationship* relationInfo = LLAvatarTracker::instance().getBuddyInfo(id); - buddy->mCanSeeMeOnline = (relationInfo && relationInfo->isRightGrantedTo(LLRelationship::GRANT_ONLINE_STATUS)); - // In all the above cases, the buddy is in the SL friends list and tha name has been resolved (which is how we got here). - buddy->mNameResolved = true; - buddy->mInSLFriends = true; - } - else - { - // This name hasn't been looked up yet in the avatar cache. Don't do anything with this buddy list entry until it has. - if(buddy) - { - buddy->mNameResolved = false; - } - // Initiate a lookup. - // The "lookup completed" callback will ensure that the friends list is rechecked after it completes. - lookupName(id); - } -} - -void LLVivoxVoiceClient::clearAllLists() -{ - // FOR TESTING ONLY - - // This will send the necessary commands to delete ALL buddies, autoaccept rules, and block rules SLVoice tells us about. - buddyListMap::iterator buddy_it; - for(buddy_it = mBuddyListMap.begin(); buddy_it != mBuddyListMap.end();) - { - buddyListEntry *buddy = buddy_it->second; - buddy_it++; - - std::ostringstream stream; - - if(buddy->mInVivoxBuddies) - { - // delete this entry from the vivox buddy list - buddy->mInVivoxBuddies = false; - LL_DEBUGS("Voice") << "delete " << buddy->mURI << " (" << buddy->mDisplayName << ")" << LL_ENDL; - stream << "" - << "" << mAccountHandle << "" - << "" << buddy->mURI << "" - << "\n\n\n"; - } - - if(buddy->mHasBlockListEntry) - { - // Delete the associated block list entry (so the block list doesn't fill up with junk) - buddy->mHasBlockListEntry = false; - stream << "" - << "" << mAccountHandle << "" - << "" << buddy->mURI << "" - << "\n\n\n"; - } - if(buddy->mHasAutoAcceptListEntry) - { - // Delete the associated auto-accept list entry (so the auto-accept list doesn't fill up with junk) - buddy->mHasAutoAcceptListEntry = false; - stream << "" - << "" << mAccountHandle << "" - << "" << buddy->mURI << "" - << "\n\n\n"; - } - - writeString(stream.str()); - - } -} - -void LLVivoxVoiceClient::sendFriendsListUpdates() -{ - if(mBuddyListMapPopulated && mBlockRulesListReceived && mAutoAcceptRulesListReceived && mFriendsListDirty) - { - mFriendsListDirty = false; - - if(0) - { - // FOR TESTING ONLY -- clear all buddy list, block list, and auto-accept list entries. - clearAllLists(); - return; - } - - LL_INFOS("Voice") << "Checking vivox buddy list against friends list..." << LL_ENDL; - - buddyListMap::iterator buddy_it; - for(buddy_it = mBuddyListMap.begin(); buddy_it != mBuddyListMap.end(); buddy_it++) - { - // reset the temp flags in the local buddy list - buddy_it->second->mInSLFriends = false; - } - - // correlate with the friends list - { - LLCollectAllBuddies collect; - LLAvatarTracker::instance().applyFunctor(collect); - LLCollectAllBuddies::buddy_map_t::const_iterator it = collect.mOnline.begin(); - LLCollectAllBuddies::buddy_map_t::const_iterator end = collect.mOnline.end(); - - for ( ; it != end; ++it) - { - checkFriend(it->second); - } - it = collect.mOffline.begin(); - end = collect.mOffline.end(); - for ( ; it != end; ++it) - { - checkFriend(it->second); - } - } - - LL_INFOS("Voice") << "Sending friend list updates..." << LL_ENDL; - - for(buddy_it = mBuddyListMap.begin(); buddy_it != mBuddyListMap.end();) - { - buddyListEntry *buddy = buddy_it->second; - buddy_it++; - - // Ignore entries that aren't resolved yet. - if(buddy->mNameResolved) - { - std::ostringstream stream; - - if(buddy->mInSLFriends && !buddy->mInVivoxBuddies) - { - if(mNumberOfAliases > 0) - { - // Add (or update) this entry in the vivox buddy list - buddy->mInVivoxBuddies = true; - LL_DEBUGS("Voice") << "add/update " << buddy->mURI << " (" << buddy->mDisplayName << ")" << LL_ENDL; - stream - << "" - << "" << mAccountHandle << "" - << "" << buddy->mURI << "" - << "" << buddy->mDisplayName << "" - << "" // Without this, SLVoice doesn't seem to parse the command. - << "0" - << "\n\n\n"; - } - } - else if(!buddy->mInSLFriends) - { - // This entry no longer exists in your SL friends list. Remove all traces of it from the Vivox buddy list. - if(buddy->mInVivoxBuddies) - { - // delete this entry from the vivox buddy list - buddy->mInVivoxBuddies = false; - LL_DEBUGS("Voice") << "delete " << buddy->mURI << " (" << buddy->mDisplayName << ")" << LL_ENDL; - stream << "" - << "" << mAccountHandle << "" - << "" << buddy->mURI << "" - << "\n\n\n"; - } - - if(buddy->mHasBlockListEntry) - { - // Delete the associated block list entry, if any - buddy->mHasBlockListEntry = false; - stream << "" - << "" << mAccountHandle << "" - << "" << buddy->mURI << "" - << "\n\n\n"; - } - if(buddy->mHasAutoAcceptListEntry) - { - // Delete the associated auto-accept list entry, if any - buddy->mHasAutoAcceptListEntry = false; - stream << "" - << "" << mAccountHandle << "" - << "" << buddy->mURI << "" - << "\n\n\n"; - } - } - - if(buddy->mInSLFriends) - { - - if(buddy->mCanSeeMeOnline) - { - // Buddy should not be blocked. - - // If this buddy doesn't already have either a block or autoaccept list entry, we'll update their status when we receive a SubscriptionEvent. - - // If the buddy has a block list entry, delete it. - if(buddy->mHasBlockListEntry) - { - buddy->mHasBlockListEntry = false; - stream << "" - << "" << mAccountHandle << "" - << "" << buddy->mURI << "" - << "\n\n\n"; - - - // If we just deleted a block list entry, add an auto-accept entry. - if(!buddy->mHasAutoAcceptListEntry) - { - buddy->mHasAutoAcceptListEntry = true; - stream << "" - << "" << mAccountHandle << "" - << "" << buddy->mURI << "" - << "0" - << "\n\n\n"; - } - } - } - else - { - // Buddy should be blocked. - - // If this buddy doesn't already have either a block or autoaccept list entry, we'll update their status when we receive a SubscriptionEvent. - - // If this buddy has an autoaccept entry, delete it - if(buddy->mHasAutoAcceptListEntry) - { - buddy->mHasAutoAcceptListEntry = false; - stream << "" - << "" << mAccountHandle << "" - << "" << buddy->mURI << "" - << "\n\n\n"; - - // If we just deleted an auto-accept entry, add a block list entry. - if(!buddy->mHasBlockListEntry) - { - buddy->mHasBlockListEntry = true; - stream << "" - << "" << mAccountHandle << "" - << "" << buddy->mURI << "" - << "1" - << "\n\n\n"; - } - } - } - - if(!buddy->mInSLFriends && !buddy->mInVivoxBuddies) - { - // Delete this entry from the local buddy list. This should NOT invalidate the iterator, - // since it has already been incremented to the next entry. - deleteBuddy(buddy->mURI); - } - - } - writeString(stream.str()); - } - } - } -} - ///////////////////////////// // Response/Event handlers @@ -3090,6 +2812,7 @@ void LLVivoxVoiceClient::connectorCreateResponse(int statusCode, std::string &st std::stringstream errs; errs << mVoiceAccountServerURI << "\n:UDP: 3478, 3479, 5060, 5062, 12000-17000"; args["HOSTID"] = errs.str(); + mTerminateDaemon = true; LLNotificationsUtil::add("NoVoiceConnect", args); } else @@ -3098,6 +2821,7 @@ void LLVivoxVoiceClient::connectorCreateResponse(int statusCode, std::string &st LL_INFOS("Voice") << "Connector.Create succeeded, Vivox SDK version is " << versionID << LL_ENDL; mVoiceVersion.serverVersion = versionID; mConnectorHandle = connectorHandle; + mTerminateDaemon = false; if(getState() == stateConnectorStarting) { setState(stateConnectorStarted); @@ -3111,7 +2835,7 @@ void LLVivoxVoiceClient::loginResponse(int statusCode, std::string &statusString // Status code of 20200 means "bad password". We may want to special-case that at some point. - if ( statusCode == 401 ) + if ( statusCode == HTTP_UNAUTHORIZED ) { // Login failure which is probably caused by the delay after a user's password being updated. LL_INFOS("Voice") << "Account.Login response failure (" << statusCode << "): " << statusString << LL_ENDL; @@ -3613,7 +3337,7 @@ void LLVivoxVoiceClient::mediaStreamUpdatedEvent( switch(statusCode) { case 0: - case 200: + case HTTP_OK: // generic success // Don't change the saved error code (it may have been set elsewhere) break; @@ -3775,15 +3499,8 @@ void LLVivoxVoiceClient::participantRemovedEvent( sessionState *session = findSession(sessionHandle); if(session) { - participantState *participant = session->findParticipant(uriString); - if(participant) - { - session->removeParticipant(participant); - } - else - { - LL_DEBUGS("Voice") << "unknown participant " << uriString << LL_ENDL; - } + // Singu Note: removeParticipant now internally finds the entry. More efficient. Other option is to add a find procedure that returns an iterator. + session->removeParticipant(uriString); } else { @@ -3847,6 +3564,11 @@ void LLVivoxVoiceClient::participantUpdatedEvent( */ LLVoiceChannel* voice_cnl = LLVoiceChannel::getCurrentVoiceChannel(); + // Singu Note: This block is different so we also update the active speaker list. + // also initialize voice moderate_mode depend on Agent's participant. See EXT-6937. + // *TODO: remove once a way to request the current voice channel moderation mode is implemented. + bool moderate = gAgentID == participant->mAvatarID; + // ignore session ID of local chat if (voice_cnl && voice_cnl->getSessionID().notNull()) { @@ -3859,100 +3581,29 @@ void LLVivoxVoiceClient::participantUpdatedEvent( { speaker_manager->update(true); - // also initialize voice moderate_mode depend on Agent's participant. See EXT-6937. - // *TODO: remove once a way to request the current voice channel moderation mode is implemented. - if (gAgent.getID() == participant->mAvatarID) + if (moderate) { speaker_manager->initVoiceModerateMode(); } } } - } - else - { - LL_WARNS("Voice") << "unknown participant: " << uriString << LL_ENDL; - } - } - else - { - LL_INFOS("Voice") << "unknown session " << sessionHandle << LL_ENDL; - } -} - -void LLVivoxVoiceClient::buddyPresenceEvent( - std::string &uriString, - std::string &alias, - std::string &statusString, - std::string &applicationString) -{ - buddyListEntry *buddy = findBuddy(uriString); - - if(buddy) - { - LL_DEBUGS("Voice") << "Presence event for " << buddy->mDisplayName << " status \"" << statusString << "\", application \"" << applicationString << "\""<< LL_ENDL; - LL_DEBUGS("Voice") << "before: mOnlineSL = " << (buddy->mOnlineSL?"true":"false") << ", mOnlineSLim = " << (buddy->mOnlineSLim?"true":"false") << LL_ENDL; - - if(applicationString.empty()) - { - // This presence event is from a client that doesn't set up the Application string. Do things the old-skool way. - // NOTE: this will be needed to support people who aren't on the 3010-class SDK yet. - - if ( stricmp("Unknown", statusString.c_str())== 0) - { - // User went offline with a non-SLim-enabled viewer. - buddy->mOnlineSL = false; - } - else if ( stricmp("Online", statusString.c_str())== 0) + else if (voice_cnl) // Local { - // User came online with a non-SLim-enabled viewer. - buddy->mOnlineSL = true; - } - else - { - // If the user is online through SLim, their status will be "Online-slc", "Away", or something else. - // NOTE: we should never see this unless someone is running an OLD version of SLim -- the versions that should be in use now all set the application string. - buddy->mOnlineSLim = true; - } - } - else if(applicationString.find("SecondLifeViewer") != std::string::npos) - { - // This presence event is from a viewer that sets the application string - if ( stricmp("Unknown", statusString.c_str())== 0) - { - // Viewer says they're offline - buddy->mOnlineSL = false; - } - else - { - // Viewer says they're online - buddy->mOnlineSL = true; + LLLocalSpeakerMgr::instance().update(true); } + // Always update active speakers + auto& inst(LLActiveSpeakerMgr::instance()); + inst.update(true); + if (moderate) inst.initVoiceModerateMode(); } else { - // This presence event is from something which is NOT the SL viewer (assume it's SLim). - if ( stricmp("Unknown", statusString.c_str())== 0) - { - // SLim says they're offline - buddy->mOnlineSLim = false; - } - else - { - // SLim says they're online - buddy->mOnlineSLim = true; - } + LL_WARNS("Voice") << "unknown participant: " << uriString << LL_ENDL; } - - LL_DEBUGS("Voice") << "after: mOnlineSL = " << (buddy->mOnlineSL?"true":"false") << ", mOnlineSLim = " << (buddy->mOnlineSLim?"true":"false") << LL_ENDL; - - // HACK -- increment the internal change serial number in the LLRelationship (without changing the actual status), so the UI notices the change. - LLAvatarTracker::instance().setBuddyOnline(buddy->mUUID,LLAvatarTracker::instance().isBuddyOnline(buddy->mUUID)); - - notifyFriendObservers(); } else { - LL_DEBUGS("Voice") << "Presence for unknown buddy " << uriString << LL_ENDL; + LL_INFOS("Voice") << "unknown session " << sessionHandle << LL_ENDL; } } @@ -4073,7 +3724,7 @@ void LLVivoxVoiceClient::messageEvent( sessionState *session = findSession(sessionHandle); if(session) { - bool is_do_not_disturb = gAgent.getBusy(); + bool is_do_not_disturb = gAgent.isDoNotDisturb(); bool is_muted = LLMuteList::getInstance()->isMuted(session->mCallerID, session->mName, LLMute::flagTextChat); bool is_linden = LLMuteList::getInstance()->isLinden(session->mName); LLChat chat; @@ -4145,100 +3796,33 @@ void LLVivoxVoiceClient::sessionNotificationEvent(std::string &sessionHandle, st } } -void LLVivoxVoiceClient::subscriptionEvent(std::string &buddyURI, std::string &subscriptionHandle, std::string &alias, std::string &displayName, std::string &applicationString, std::string &subscriptionType) -{ - buddyListEntry *buddy = findBuddy(buddyURI); - - if(!buddy) - { - // Couldn't find buddy by URI, try converting the alias... - if(!alias.empty()) - { - LLUUID id; - if(IDFromName(alias, id)) - { - buddy = findBuddy(id); - } - } - } - - if(buddy) - { - std::ostringstream stream; - - if(buddy->mCanSeeMeOnline) - { - // Sending the response will create an auto-accept rule - buddy->mHasAutoAcceptListEntry = true; - } - else - { - // Sending the response will create a block rule - buddy->mHasBlockListEntry = true; - } - - if(buddy->mInSLFriends) - { - buddy->mInVivoxBuddies = true; - } - - stream - << "" - << "" << mAccountHandle << "" - << "" << buddy->mURI << "" - << "" << (buddy->mCanSeeMeOnline?"Allow":"Hide") << "" - << ""<< (buddy->mInSLFriends?"1":"0")<< "" - << "" << subscriptionHandle << "" - << "" - << "\n\n\n"; - - writeString(stream.str()); - } -} - void LLVivoxVoiceClient::auxAudioPropertiesEvent(F32 energy) { LL_DEBUGS("Voice") << "got energy " << energy << LL_ENDL; mTuningEnergy = energy; } -void LLVivoxVoiceClient::buddyListChanged() -{ - // This is called after we receive a BuddyAndGroupListChangedEvent. - mBuddyListMapPopulated = true; - mFriendsListDirty = true; -} - void LLVivoxVoiceClient::muteListChanged() { // The user's mute list has been updated. Go through the current participant list and sync it with the mute list. if(mAudioSession) { - participantMap::iterator iter = mAudioSession->mParticipantsByURI.begin(); + // Singu Note: mParticipantList has replaced mParticipantsByURI. + participantList::iterator iter = mAudioSession->mParticipantList.begin(); - for(; iter != mAudioSession->mParticipantsByURI.end(); iter++) + for(; iter != mAudioSession->mParticipantList.end(); iter++) { - participantState *p = iter->second; - // Check to see if this participant is on the mute list already - if(p->updateMuteState()) + if(iter->updateMuteState()) mAudioSession->mVolumeDirty = true; } } } -void LLVivoxVoiceClient::updateFriends(U32 mask) -{ - if(mask & (LLFriendObserver::ADD | LLFriendObserver::REMOVE | LLFriendObserver::POWERS)) - { - // Just resend the whole friend list to the daemon - mFriendsListDirty = true; - } -} - ///////////////////////////// // Managing list of participants -LLVivoxVoiceClient::participantState::participantState(const std::string &uri) : +// Singu Note: Extended the ctor. +LLVivoxVoiceClient::participantState::participantState(const std::string &uri, const LLUUID& id, bool isAv) : mURI(uri), mPTT(false), mIsSpeaking(false), @@ -4250,69 +3834,51 @@ LLVivoxVoiceClient::participantState::participantState(const std::string &uri) : mOnMuteList(false), mVolumeSet(false), mVolumeDirty(false), - mAvatarIDValid(false), - mIsSelf(false) + mAvatarIDValid(isAv), + mIsSelf(false), + mAvatarID(id) { } LLVivoxVoiceClient::participantState *LLVivoxVoiceClient::sessionState::addParticipant(const std::string &uri) { - participantState *result = NULL; - bool useAlternateURI = false; - - // Note: this is mostly the body of LLVivoxVoiceClient::sessionState::findParticipant(), but since we need to know if it - // matched the alternate SIP URI (so we can add it properly), we need to reproduce it here. - { - participantMap::iterator iter = mParticipantsByURI.find(uri); - - if(iter == mParticipantsByURI.end()) - { - if(!mAlternateSIPURI.empty() && (uri == mAlternateSIPURI)) - { - // This is a p2p session (probably with the SLIM client) with an alternate URI for the other participant. - // Use mSIPURI instead, since it will be properly encoded. - iter = mParticipantsByURI.find(mSIPURI); - useAlternateURI = true; - } - } + // Singu Note: If findParticipant returns non-null then alt uri stuff doesn't matter. Prior LL code was silly. + // Additonally, mParticipantList has replaced both mParticipantsByURI and mParticipantsByUUID, meaning we don't have two maps to maintain any longer. + + if (participantState* p = findParticipant(uri)) + return p; - if(iter != mParticipantsByURI.end()) - { - result = iter->second; - } - } + const std::string& desired_uri = (!mAlternateSIPURI.empty() && (uri == mAlternateSIPURI)) ? mSIPURI : uri; - if(!result) { // participant isn't already in one list or the other. - result = new participantState(useAlternateURI?mSIPURI:uri); - mParticipantsByURI.insert(participantMap::value_type(result->mURI, result)); mParticipantsChanged = true; // Try to do a reverse transform on the URI to get the GUID back. { LLUUID id; - if(LLVivoxVoiceClient::getInstance()->IDFromName(result->mURI, id)) + if (LLVivoxVoiceClient::getInstance()->IDFromName(desired_uri, id)) { - result->mAvatarIDValid = true; - result->mAvatarID = id; + mParticipantList.push_back(participantState(desired_uri, id, true)); } else { // Create a UUID by hashing the URI, but do NOT set mAvatarIDValid. // This indicates that the ID will not be in the name cache. - result->mAvatarID.generate(uri); + id.generate(uri); + mParticipantList.push_back(participantState(desired_uri, id, false)); } } + participantState* result = &mParticipantList.back(); - if(result->updateMuteState()) + if (result->updateMuteState()) { mMuteDirty = true; } - mParticipantsByUUID.insert(participantUUIDMap::value_type(result->mAvatarID, result)); - + // Singu Note: mParticipantsByUUID is dead. Keep it that way. + if (LLSpeakerVolumeStorage::getInstance()->getSpeakerVolume(result->mAvatarID, result->mVolume)) { result->mVolumeDirty = true; @@ -4320,9 +3886,9 @@ LLVivoxVoiceClient::participantState *LLVivoxVoiceClient::sessionState::addParti } LL_DEBUGS("Voice") << "participant \"" << result->mURI << "\" added." << LL_ENDL; - } - return result; + return result; + } } bool LLVivoxVoiceClient::participantState::updateMuteState() @@ -4346,35 +3912,25 @@ bool LLVivoxVoiceClient::participantState::isAvatar() return mAvatarIDValid; } -void LLVivoxVoiceClient::sessionState::removeParticipant(LLVivoxVoiceClient::participantState *participant) +// Singu Note: The only real necessary call to this immediatley followed a findParticipant call. +// Thus, just do the lookup here. It's faster to find the iterator only one time. +// Additonally, mParticipantList has replaced both mParticipantsByURI and mParticipantsByUUID, meaning we don't have two maps to maintain any longer. +void LLVivoxVoiceClient::sessionState::removeParticipant(const std::string& uri) { - if(participant) + participantList::iterator iter = std::find_if(mParticipantList.begin(), mParticipantList.end(), boost::bind(&participantList::value_type::mURI, _1) == uri); + if (iter != mParticipantList.end()) { - participantMap::iterator iter = mParticipantsByURI.find(participant->mURI); - participantUUIDMap::iterator iter2 = mParticipantsByUUID.find(participant->mAvatarID); - - LL_DEBUGS("Voice") << "participant \"" << participant->mURI << "\" (" << participant->mAvatarID << ") removed." << LL_ENDL; - - if(iter == mParticipantsByURI.end()) - { - LL_ERRS("Voice") << "Internal error: participant " << participant->mURI << " not in URI map" << LL_ENDL; - } - else if(iter2 == mParticipantsByUUID.end()) - { - LL_ERRS("Voice") << "Internal error: participant ID " << participant->mAvatarID << " not in UUID map" << LL_ENDL; - } - else if(iter->second != iter2->second) - { - LL_ERRS("Voice") << "Internal error: participant mismatch!" << LL_ENDL; - } - else + vector_replace_with_last(mParticipantList, iter); + if (mParticipantList.empty() || mParticipantList.capacity() - mParticipantList.size() > 16) { - mParticipantsByURI.erase(iter); - mParticipantsByUUID.erase(iter2); - - delete participant; - mParticipantsChanged = true; + mParticipantList.shrink_to_fit(); } + mParticipantsChanged = true; + LL_DEBUGS("Voice") << "participant \"" << uri << "\" (" << iter->mAvatarID << ") removed." << LL_ENDL; + } + else + { + LL_DEBUGS("Voice") << "unknown participant " << uri << LL_ENDL; } } @@ -4382,87 +3938,72 @@ void LLVivoxVoiceClient::sessionState::removeAllParticipants() { LL_DEBUGS("Voice") << "called" << LL_ENDL; - while(!mParticipantsByURI.empty()) - { - removeParticipant(mParticipantsByURI.begin()->second); - } - - if(!mParticipantsByUUID.empty()) - { - LL_ERRS("Voice") << "Internal error: empty URI map, non-empty UUID map" << LL_ENDL; - } + // Singu Note: mParticipantList has replaced both mParticipantsByURI and mParticipantsByUUID, meaning we don't have two maps to maintain any longer. + mParticipantList.clear(); + mParticipantList.shrink_to_fit(); } -void LLVivoxVoiceClient::getParticipantList(std::set &participants) +void LLVivoxVoiceClient::getParticipantList(uuid_set_t &participants) { if(mAudioSession) { - for(participantUUIDMap::iterator iter = mAudioSession->mParticipantsByUUID.begin(); - iter != mAudioSession->mParticipantsByUUID.end(); + // Singu Note: mParticipantList has replaced mParticipantsByURI. + for (participantList::iterator iter = mAudioSession->mParticipantList.begin(); + iter != mAudioSession->mParticipantList.end(); iter++) { - participants.insert(iter->first); + participants.insert(iter->mAvatarID); } } } bool LLVivoxVoiceClient::isParticipant(const LLUUID &speaker_id) { - if(mAudioSession) - { - return (mAudioSession->mParticipantsByUUID.find(speaker_id) != mAudioSession->mParticipantsByUUID.end()); - } - return false; + // Singu Note: findParticipantByID does the same thing. If null, returns false. + return findParticipantByID(speaker_id); } - LLVivoxVoiceClient::participantState *LLVivoxVoiceClient::sessionState::findParticipant(const std::string &uri) { - participantState *result = NULL; - - participantMap::iterator iter = mParticipantsByURI.find(uri); + // Singu Note: mParticipantList has replaced mParticipantsByURI. + participantList& vec = mParticipantList; + participantList::iterator iter = std::find_if(vec.begin(), vec.end(), boost::bind(&participantList::value_type::mURI, _1) == uri); - if(iter == mParticipantsByURI.end()) + if(iter == vec.end()) { if(!mAlternateSIPURI.empty() && (uri == mAlternateSIPURI)) { // This is a p2p session (probably with the SLIM client) with an alternate URI for the other participant. // Look up the other URI - iter = mParticipantsByURI.find(mSIPURI); + iter = std::find_if(vec.begin(), vec.end(), boost::bind(&participantList::value_type::mURI, _1) == mSIPURI); } } - if(iter != mParticipantsByURI.end()) + if (iter != mParticipantList.end()) { - result = iter->second; + return &*iter; } - return result; + return NULL; } LLVivoxVoiceClient::participantState* LLVivoxVoiceClient::sessionState::findParticipantByID(const LLUUID& id) { - participantState * result = NULL; - participantUUIDMap::iterator iter = mParticipantsByUUID.find(id); + // Singu Note: mParticipantList has replaced mParticipantsByUUID. + participantList& vec = mParticipantList; + participantList::iterator iter = std::find_if(vec.begin(), vec.end(), boost::bind(&participantList::value_type::mAvatarID, _1) == id); - if(iter != mParticipantsByUUID.end()) + if(iter != mParticipantList.end()) { - result = iter->second; + return &*iter; } - return result; + return NULL; } LLVivoxVoiceClient::participantState* LLVivoxVoiceClient::findParticipantByID(const LLUUID& id) { - participantState * result = NULL; - - if(mAudioSession) - { - result = mAudioSession->findParticipantByID(id); - } - - return result; + return mAudioSession ? mAudioSession->findParticipantByID(id) : NULL; } @@ -4835,34 +4376,6 @@ bool LLVivoxVoiceClient::answerInvite(std::string &sessionHandle) return false; } -BOOL LLVivoxVoiceClient::isOnlineSIP(const LLUUID &id) -{ - bool result = false; - buddyListEntry *buddy = findBuddy(id); - if(buddy) - { - result = buddy->mOnlineSLim; - LL_DEBUGS("Voice") << "Buddy " << buddy->mDisplayName << " is SIP " << (result?"online":"offline") << LL_ENDL; - } - - if(!result) - { - // This user isn't on the buddy list or doesn't show online status through the buddy list, but could be a participant in an existing session if they initiated a text IM. - sessionState *session = findSession(id); - if(session && !session->mHandle.empty()) - { - if((session->mTextStreamState != streamStateUnknown) || (session->mMediaStreamState > streamStateIdle)) - { - LL_DEBUGS("Voice") << "Open session with " << id << " found, returning SIP online state" << LL_ENDL; - // we have a p2p text session open with this user, so by definition they're online. - result = true; - } - } - } - - return result; -} - bool LLVivoxVoiceClient::isVoiceWorking() const { //Added stateSessionTerminated state to avoid problems with call in parcels with disabled voice (EXT-4758) @@ -5970,224 +5483,6 @@ void LLVivoxVoiceClient::verifySessionState(void) } } -LLVivoxVoiceClient::buddyListEntry::buddyListEntry(const std::string &uri) : - mURI(uri) -{ - mOnlineSL = false; - mOnlineSLim = false; - mCanSeeMeOnline = true; - mHasBlockListEntry = false; - mHasAutoAcceptListEntry = false; - mNameResolved = false; - mInVivoxBuddies = false; - mInSLFriends = false; -} - -void LLVivoxVoiceClient::processBuddyListEntry(const std::string &uri, const std::string &displayName) -{ - buddyListEntry *buddy = addBuddy(uri, displayName); - buddy->mInVivoxBuddies = true; -} - -LLVivoxVoiceClient::buddyListEntry *LLVivoxVoiceClient::addBuddy(const std::string &uri) -{ - std::string empty; - buddyListEntry *buddy = addBuddy(uri, empty); - if(buddy->mDisplayName.empty()) - { - buddy->mNameResolved = false; - } - return buddy; -} - -LLVivoxVoiceClient::buddyListEntry *LLVivoxVoiceClient::addBuddy(const std::string &uri, const std::string &displayName) -{ - buddyListEntry *result = NULL; - buddyListMap::iterator iter = mBuddyListMap.find(uri); - - if(iter != mBuddyListMap.end()) - { - // Found a matching buddy already in the map. - LL_DEBUGS("Voice") << "adding existing buddy " << uri << LL_ENDL; - result = iter->second; - } - - if(!result) - { - // participant isn't already in one list or the other. - LL_DEBUGS("Voice") << "adding new buddy " << uri << LL_ENDL; - result = new buddyListEntry(uri); - result->mDisplayName = displayName; - - if (!IDFromName(uri, result->mUUID)) - { - LL_DEBUGS("Voice") << "Couldn't find ID for buddy " << uri << " (\"" << displayName << "\")" << LL_ENDL; - } - - mBuddyListMap.insert(buddyListMap::value_type(result->mURI, result)); - } - - return result; -} - -LLVivoxVoiceClient::buddyListEntry *LLVivoxVoiceClient::findBuddy(const std::string &uri) -{ - buddyListEntry *result = NULL; - buddyListMap::iterator iter = mBuddyListMap.find(uri); - if(iter != mBuddyListMap.end()) - { - result = iter->second; - } - - return result; -} - -LLVivoxVoiceClient::buddyListEntry *LLVivoxVoiceClient::findBuddy(const LLUUID &id) -{ - buddyListEntry *result = NULL; - buddyListMap::iterator iter; - - for(iter = mBuddyListMap.begin(); iter != mBuddyListMap.end(); iter++) - { - if(iter->second->mUUID == id) - { - result = iter->second; - break; - } - } - - return result; -} - -LLVivoxVoiceClient::buddyListEntry *LLVivoxVoiceClient::findBuddyByDisplayName(const std::string &name) -{ - buddyListEntry *result = NULL; - buddyListMap::iterator iter; - - for(iter = mBuddyListMap.begin(); iter != mBuddyListMap.end(); iter++) - { - if(iter->second->mDisplayName == name) - { - result = iter->second; - break; - } - } - - return result; -} - -void LLVivoxVoiceClient::deleteBuddy(const std::string &uri) -{ - buddyListMap::iterator iter = mBuddyListMap.find(uri); - if(iter != mBuddyListMap.end()) - { - LL_DEBUGS("Voice") << "deleting buddy " << uri << LL_ENDL; - buddyListEntry *buddy = iter->second; - mBuddyListMap.erase(iter); - delete buddy; - } - else - { - LL_DEBUGS("Voice") << "attempt to delete nonexistent buddy " << uri << LL_ENDL; - } - -} - -void LLVivoxVoiceClient::deleteAllBuddies(void) -{ - while(!mBuddyListMap.empty()) - { - deleteBuddy(mBuddyListMap.begin()->first); - } - - // Don't want to correlate with friends list when we've emptied the buddy list. - mBuddyListMapPopulated = false; - - // Don't want to correlate with friends list when we've reset the block rules. - mBlockRulesListReceived = false; - mAutoAcceptRulesListReceived = false; -} - -void LLVivoxVoiceClient::deleteAllBlockRules(void) -{ - // Clear the block list entry flags from all local buddy list entries - buddyListMap::iterator buddy_it; - for(buddy_it = mBuddyListMap.begin(); buddy_it != mBuddyListMap.end(); buddy_it++) - { - buddy_it->second->mHasBlockListEntry = false; - } -} - -void LLVivoxVoiceClient::deleteAllAutoAcceptRules(void) -{ - // Clear the auto-accept list entry flags from all local buddy list entries - buddyListMap::iterator buddy_it; - for(buddy_it = mBuddyListMap.begin(); buddy_it != mBuddyListMap.end(); buddy_it++) - { - buddy_it->second->mHasAutoAcceptListEntry = false; - } -} - -void LLVivoxVoiceClient::addBlockRule(const std::string &blockMask, const std::string &presenceOnly) -{ - buddyListEntry *buddy = NULL; - - // blockMask is the SIP URI of a friends list entry - buddyListMap::iterator iter = mBuddyListMap.find(blockMask); - if(iter != mBuddyListMap.end()) - { - LL_DEBUGS("Voice") << "block list entry for " << blockMask << LL_ENDL; - buddy = iter->second; - } - - if(buddy == NULL) - { - LL_DEBUGS("Voice") << "block list entry for unknown buddy " << blockMask << LL_ENDL; - buddy = addBuddy(blockMask); - } - - if(buddy != NULL) - { - buddy->mHasBlockListEntry = true; - } -} - -void LLVivoxVoiceClient::addAutoAcceptRule(const std::string &autoAcceptMask, const std::string &autoAddAsBuddy) -{ - buddyListEntry *buddy = NULL; - - // blockMask is the SIP URI of a friends list entry - buddyListMap::iterator iter = mBuddyListMap.find(autoAcceptMask); - if(iter != mBuddyListMap.end()) - { - LL_DEBUGS("Voice") << "auto-accept list entry for " << autoAcceptMask << LL_ENDL; - buddy = iter->second; - } - - if(buddy == NULL) - { - LL_DEBUGS("Voice") << "auto-accept list entry for unknown buddy " << autoAcceptMask << LL_ENDL; - buddy = addBuddy(autoAcceptMask); - } - - if(buddy != NULL) - { - buddy->mHasAutoAcceptListEntry = true; - } -} - -void LLVivoxVoiceClient::accountListBlockRulesResponse(int statusCode, const std::string &statusString) -{ - // Block list entries were updated via addBlockRule() during parsing. Just flag that we're done. - mBlockRulesListReceived = true; -} - -void LLVivoxVoiceClient::accountListAutoAcceptRulesResponse(int statusCode, const std::string &statusString) -{ - // Block list entries were updated via addBlockRule() during parsing. Just flag that we're done. - mAutoAcceptRulesListReceived = true; -} - void LLVivoxVoiceClient::addObserver(LLVoiceClientParticipantObserver* observer) { mParticipantObservers.insert(observer); @@ -6249,9 +5544,10 @@ void LLVivoxVoiceClient::notifyStatusObservers(LLVoiceClientStatusObserver::ESta { switch(mAudioSession->mErrorStatusCode) { - case 404: // NOT_FOUND + case HTTP_NOT_FOUND: // NOT_FOUND + // *TODO: Should this be 503? case 480: // TEMPORARILY_UNAVAILABLE - case 408: // REQUEST_TIMEOUT + case HTTP_REQUEST_TIME_OUT: // REQUEST_TIMEOUT // call failed because other user was not available // treat this as an error case status = LLVoiceClientStatusObserver::ERROR_NOT_AVAILABLE; @@ -6330,17 +5626,12 @@ void LLVivoxVoiceClient::onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name) { mAvatarNameCacheConnection.disconnect(); - std::string display_name = av_name.mDisplayName; + std::string display_name = av_name.getDisplayName(); avatarNameResolved(agent_id, display_name); } void LLVivoxVoiceClient::avatarNameResolved(const LLUUID &id, const std::string &name) { - // If the avatar whose name just resolved is on our friends list, resync the friends list. - if(LLAvatarTracker::instance().getBuddyInfo(id) != NULL) - { - mFriendsListDirty = true; - } // Iterate over all sessions. for(sessionIterator iter = sessionsBegin(); iter != sessionsEnd(); iter++) { @@ -6859,7 +6150,6 @@ void LLVivoxVoiceClient::removeObserver(LLVoiceEffectObserver* observer) { mVoiceFontObservers.erase(observer); } - void LLVivoxVoiceClient::notifyVoiceFontObservers() { LL_DEBUGS("Voice") << "Notifying voice effect observers. Lists changed: " << mVoiceFontListDirty << LL_ENDL; @@ -7085,7 +6375,7 @@ LLVivoxProtocolParser::~LLVivoxProtocolParser() XML_ParserFree(parser); } -static LLFastTimer::DeclareTimer FTM_VIVOX_PROCESS("Vivox Process"); +static LLTrace::BlockTimerStatHandle FTM_VIVOX_PROCESS("Vivox Process"); // virtual LLIOPipe::EStatus LLVivoxProtocolParser::process_impl( @@ -7095,7 +6385,7 @@ LLIOPipe::EStatus LLVivoxProtocolParser::process_impl( LLSD& context, LLPumpIO* pump) { - LLFastTimer t(FTM_VIVOX_PROCESS); + LL_RECORD_BLOCK_TIME(FTM_VIVOX_PROCESS); LLBufferStream istr(channels, buffer.get()); std::ostringstream ostr; while (istr.good()) @@ -7248,18 +6538,6 @@ void LLVivoxProtocolParser::StartTag(const char *tag, const char **attr) { deviceString.clear(); } - else if (!stricmp("Buddies", tag)) - { - LLVivoxVoiceClient::getInstance()->deleteAllBuddies(); - } - else if (!stricmp("BlockRules", tag)) - { - LLVivoxVoiceClient::getInstance()->deleteAllBlockRules(); - } - else if (!stricmp("AutoAcceptRules", tag)) - { - LLVivoxVoiceClient::getInstance()->deleteAllAutoAcceptRules(); - } else if (!stricmp("SessionFont", tag)) { id = 0; @@ -7391,24 +6669,10 @@ void LLVivoxProtocolParser::EndTag(const char *tag) { LLVivoxVoiceClient::getInstance()->addRenderDevice(deviceString); } - else if (!stricmp("Buddy", tag)) - { - // NOTE : Vivox does *not* give reliable display name for Buddy tags - // We don't take those very seriously as a result... - LLVivoxVoiceClient::getInstance()->processBuddyListEntry(uriString, displayNameString); - } - else if (!stricmp("BlockRule", tag)) - { - LLVivoxVoiceClient::getInstance()->addBlockRule(blockMask, presenceOnly); - } else if (!stricmp("BlockMask", tag)) blockMask = string; else if (!stricmp("PresenceOnly", tag)) presenceOnly = string; - else if (!stricmp("AutoAcceptRule", tag)) - { - LLVivoxVoiceClient::getInstance()->addAutoAcceptRule(autoAcceptMask, autoAddAsBuddy); - } else if (!stricmp("AutoAcceptMask", tag)) autoAcceptMask = string; else if (!stricmp("AutoAddAsBuddy", tag)) @@ -7640,16 +6904,6 @@ void LLVivoxProtocolParser::processResponse(std::string tag) LLVivoxVoiceClient::getInstance()->auxAudioPropertiesEvent(energy); } - else if (!stricmp(eventTypeCstr, "BuddyPresenceEvent")) - { - LLVivoxVoiceClient::getInstance()->buddyPresenceEvent(uriString, alias, statusString, applicationString); - } - else if (!stricmp(eventTypeCstr, "BuddyAndGroupListChangedEvent")) - { - // The buddy list was updated during parsing. - // Need to recheck against the friends list. - LLVivoxVoiceClient::getInstance()->buddyListChanged(); - } else if (!stricmp(eventTypeCstr, "BuddyChangedEvent")) { /* @@ -7672,10 +6926,6 @@ void LLVivoxProtocolParser::processResponse(std::string tag) { LLVivoxVoiceClient::getInstance()->sessionNotificationEvent(sessionHandle, uriString, notificationType); } - else if (!stricmp(eventTypeCstr, "SubscriptionEvent")) - { - LLVivoxVoiceClient::getInstance()->subscriptionEvent(uriString, subscriptionHandle, alias, displayNameString, applicationString, subscriptionType); - } else if (!stricmp(eventTypeCstr, "SessionUpdatedEvent")) { /* @@ -7703,6 +6953,9 @@ void LLVivoxProtocolParser::processResponse(std::string tag) */ // We don't need to process this, but we also shouldn't warn on it, since that confuses people. } + else if (!stricmp(eventTypeCstr, "VoiceServiceConnectionStateChangedEvent")) + { // Yet another ignored event + } else { LL_WARNS("VivoxProtocolParser") << "Unknown event type " << eventTypeString << LL_ENDL; @@ -7739,14 +6992,6 @@ void LLVivoxProtocolParser::processResponse(std::string tag) { LLVivoxVoiceClient::getInstance()->connectorShutdownResponse(statusCode, statusString); } - else if (!stricmp(actionCstr, "Account.ListBlockRules.1")) - { - LLVivoxVoiceClient::getInstance()->accountListBlockRulesResponse(statusCode, statusString); - } - else if (!stricmp(actionCstr, "Account.ListAutoAcceptRules.1")) - { - LLVivoxVoiceClient::getInstance()->accountListAutoAcceptRulesResponse(statusCode, statusString); - } else if (!stricmp(actionCstr, "Session.Set3DPosition.1")) { // We don't need to process these, but they're so spammy we don't want to log them. diff --git a/indra/newview/llvoicevivox.h b/indra/newview/llvoicevivox.h index e9c2339933..9cdf4126c5 100644 --- a/indra/newview/llvoicevivox.h +++ b/indra/newview/llvoicevivox.h @@ -88,7 +88,7 @@ class LLVivoxVoiceClient : public LLSingleton, virtual LLVoiceDeviceList& getRenderDevices(); //@} - virtual void getParticipantList(std::set &participants); + virtual void getParticipantList(uuid_set_t &participants); virtual bool isParticipant(const LLUUID& speaker_id); // Send a text message to the specified user, initiating the session if necessary. @@ -111,7 +111,7 @@ class LLVivoxVoiceClient : public LLSingleton, //////////////////////////// /// @name Channel stuff //@{ - // returns true if the user is currently in a proximal (local spatial) channel. + // returns true iff the user is currently in a proximal (local spatial) channel. // Note that gestures should only fire if this returns true. virtual bool inProximalChannel(); @@ -163,7 +163,6 @@ class LLVivoxVoiceClient : public LLSingleton, //@{ virtual BOOL getVoiceEnabled(const LLUUID& id); // true if we've received data for this avatar virtual std::string getDisplayName(const LLUUID& id); - virtual BOOL isOnlineSIP(const LLUUID &id); virtual BOOL isParticipantAvatar(const LLUUID &id); virtual BOOL getIsSpeaking(const LLUUID& id); virtual BOOL getIsModeratorMuted(const LLUUID& id); @@ -247,7 +246,8 @@ class LLVivoxVoiceClient : public LLSingleton, struct participantState { public: - participantState(const std::string &uri); + // Singu Note: Extended the ctor. + participantState(const std::string &uri, const LLUUID& id, bool isAv); bool updateMuteState(); // true if mute state has changed bool isAvatar(); @@ -271,9 +271,9 @@ class LLVivoxVoiceClient : public LLSingleton, bool mAvatarIDValid; bool mIsSelf; }; - - typedef std::map participantMap; - typedef std::map participantUUIDMap; + + // Singu Note: participantList has replaced both participantMap and participantUUIDMap. + typedef std::vector participantList; struct sessionState { @@ -284,7 +284,8 @@ class LLVivoxVoiceClient : public LLSingleton, participantState *addParticipant(const std::string &uri); // Note: after removeParticipant returns, the participant* that was passed to it will have been deleted. // Take care not to use the pointer again after that. - void removeParticipant(participantState *participant); + // Singu Note: removeParticipant now internally finds the entry. More efficient. Other option is to add a find procedure that returns an iterator. + void removeParticipant(const std::string& uri); void removeAllParticipants(); participantState *findParticipant(const std::string &uri); @@ -326,8 +327,8 @@ class LLVivoxVoiceClient : public LLSingleton, bool mMuteDirty; bool mParticipantsChanged; - participantMap mParticipantsByURI; - participantUUIDMap mParticipantsByUUID; + // Singu Note: mParticipantList has replaced both mParticipantsByURI and mParticipantsByUUID. + participantList mParticipantList; LLUUID mVoiceFontID; }; @@ -470,14 +471,10 @@ class LLVivoxVoiceClient : public LLSingleton, void participantRemovedEvent(std::string &sessionHandle, std::string &sessionGroupHandle, std::string &uriString, std::string &alias, std::string &nameString); void participantUpdatedEvent(std::string &sessionHandle, std::string &sessionGroupHandle, std::string &uriString, std::string &alias, bool isModeratorMuted, bool isSpeaking, int volume, F32 energy); void auxAudioPropertiesEvent(F32 energy); - void buddyPresenceEvent(std::string &uriString, std::string &alias, std::string &statusString, std::string &applicationString); void messageEvent(std::string &sessionHandle, std::string &uriString, std::string &alias, std::string &messageHeader, std::string &messageBody, std::string &applicationString); void sessionNotificationEvent(std::string &sessionHandle, std::string &uriString, std::string ¬ificationType); - void subscriptionEvent(std::string &buddyURI, std::string &subscriptionHandle, std::string &alias, std::string &displayName, std::string &applicationString, std::string &subscriptionType); - void buddyListChanged(); void muteListChanged(); - void updateFriends(U32 mask); ///////////////////////////// // Sending updates of current state @@ -568,24 +565,6 @@ class LLVivoxVoiceClient : public LLSingleton, typedef std::map buddyListMap; - // This should be called when parsing a buddy list entry sent by SLVoice. - void processBuddyListEntry(const std::string &uri, const std::string &displayName); - - buddyListEntry *addBuddy(const std::string &uri); - buddyListEntry *addBuddy(const std::string &uri, const std::string &displayName); - buddyListEntry *findBuddy(const std::string &uri); - buddyListEntry *findBuddy(const LLUUID &id); - buddyListEntry *findBuddyByDisplayName(const std::string &name); - void deleteBuddy(const std::string &uri); - void deleteAllBuddies(void); - - void deleteAllBlockRules(void); - void addBlockRule(const std::string &blockMask, const std::string &presenceOnly); - void deleteAllAutoAcceptRules(void); - void addAutoAcceptRule(const std::string &autoAcceptMask, const std::string &autoAddAsBuddy); - void accountListBlockRulesResponse(int statusCode, const std::string &statusString); - void accountListAutoAcceptRulesResponse(int statusCode, const std::string &statusString); - ///////////////////////////// // session control messages @@ -663,6 +642,8 @@ class LLVivoxVoiceClient : public LLSingleton, LLSocket::ptr_t mSocket; bool mConnected; + // We should kill the voice daemon in case of connection alert + bool mTerminateDaemon; LLPumpIO *mPump; friend class LLVivoxProtocolParser; @@ -754,8 +735,7 @@ class LLVivoxVoiceClient : public LLSingleton, void buildSetCaptureDevice(std::ostringstream &stream); void buildSetRenderDevice(std::ostringstream &stream); - void clearAllLists(); - void checkFriend(const LLUUID& id); + void sendFriendsListUpdates(); // start a text IM session with the specified user @@ -898,6 +878,7 @@ class LLVivoxVoiceClient : public LLSingleton, bool mCaptureBufferRecording; // A voice sample is being captured. bool mCaptureBufferRecorded; // A voice sample is captured in the buffer ready to play. bool mCaptureBufferPlaying; // A voice sample is being played. + bool mShutdownComplete; LLTimer mCaptureTimer; LLUUID mPreviewVoiceFont; diff --git a/indra/newview/llvopartgroup.cpp b/indra/newview/llvopartgroup.cpp index f164364937..310558b648 100644 --- a/indra/newview/llvopartgroup.cpp +++ b/indra/newview/llvopartgroup.cpp @@ -49,14 +49,16 @@ #include "llviewerregion.h" #include "pipeline.h" #include "llspatialpartition.h" +#include "llglslshader.h" const F32 MAX_PART_LIFETIME = 120.f; -extern U64 gFrameTime; +extern U64MicrosecondsImplicit gFrameTime; LLPointer LLVOPartGroup::sVB = NULL; S32 LLVOPartGroup::sVBSlotFree[]; S32* LLVOPartGroup::sVBSlotCursor = NULL; +//S32 LLVOPartGroup::sVBSlotCursor = 0; void LLVOPartGroup::initClass() { @@ -71,7 +73,9 @@ void LLVOPartGroup::initClass() //static void LLVOPartGroup::restoreGL() { - sVB = new LLVertexBuffer(VERTEX_DATA_MASK, GL_STREAM_DRAW_ARB); + + //TODO: optimize out binormal mask here. Specular and normal coords as well. + sVB = new LLVertexBuffer(VERTEX_DATA_MASK | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2, GL_STREAM_DRAW_ARB); U32 count = LL_MAX_PARTICLE_COUNT; sVB->allocateBuffer(count*4, count*6, true); @@ -137,6 +141,8 @@ S32 LLVOPartGroup::findAvailableVBSlot() sVBSlotCursor++; return ret; + + //return sVBSlotCursor++; } bool ll_is_part_idx_allocated(S32 idx, S32* start, S32* end) @@ -152,6 +158,7 @@ bool ll_is_part_idx_allocated(S32 idx, S32* start, S32* end) //allocated (not in free list) return true; + //return false; } //static @@ -189,17 +196,28 @@ BOOL LLVOPartGroup::isActive() const F32 LLVOPartGroup::getBinRadius() { - return mScale.mV[0]*2.f; + return mViewerPartGroupp->getBoxSide(); } void LLVOPartGroup::updateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax) { const LLVector3& pos_agent = getPositionAgent(); - newMin.load3( (pos_agent - mScale).mV); - newMax.load3( (pos_agent + mScale).mV); - LLVector4a pos; - pos.load3(pos_agent.mV); - mDrawable->setPositionGroup(pos); + + LLVector4a scale; + LLVector4a p; + + p.load3(pos_agent.mV); + + scale.splat(mScale.mV[0]+mViewerPartGroupp->getBoxSide()*0.5f); + + newMin.setSub(p, scale); + newMax.setAdd(p,scale); + + llassert(newMin.isFinite3()); + llassert(newMax.isFinite3()); + + llassert(p.isFinite3()); + mDrawable->setPositionGroup(p); } void LLVOPartGroup::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) @@ -238,6 +256,37 @@ LLDrawable* LLVOPartGroup::createDrawable(LLPipeline *pipeline) const F32 MAX_PARTICLE_AREA_SCALE = 0.02f; // some tuned constant, limits on how much particle area to draw + LLUUID LLVOPartGroup::getPartOwner(S32 idx) + { + LLUUID ret = LLUUID::null; + + if (idx < (S32) mViewerPartGroupp->mParticles.size()) + { + ret = mViewerPartGroupp->mParticles[idx]->mPartSourcep->getOwnerUUID(); + } + + return ret; + } + + LLUUID LLVOPartGroup::getPartSource(S32 idx) + { + LLUUID ret = LLUUID::null; + + if (idx < (S32) mViewerPartGroupp->mParticles.size()) + { + LLViewerPart* part = mViewerPartGroupp->mParticles[idx]; + if (part && part->mPartSourcep.notNull() && + part->mPartSourcep->mSourceObjectp.notNull()) + { + LLViewerObject* source = part->mPartSourcep->mSourceObjectp; + ret = source->getID(); + } + } + + return ret; + } + + F32 LLVOPartGroup::getPartSize(S32 idx) { if (idx < (S32) mViewerPartGroupp->mParticles.size()) @@ -248,15 +297,25 @@ F32 LLVOPartGroup::getPartSize(S32 idx) return 0.f; } +void LLVOPartGroup::getBlendFunc(S32 idx, U32& src, U32& dst) +{ + if (idx < (S32) mViewerPartGroupp->mParticles.size()) + { + LLViewerPart* part = mViewerPartGroupp->mParticles[idx]; + src = part->mBlendFuncSource; + dst = part->mBlendFuncDest; + } +} + LLVector3 LLVOPartGroup::getCameraPosition() const { return gAgentCamera.getCameraPositionAgent(); } -static LLFastTimer::DeclareTimer FTM_UPDATE_PARTICLES("Update Particles"); +static LLTrace::BlockTimerStatHandle FTM_UPDATE_PARTICLES("Update Particles"); BOOL LLVOPartGroup::updateGeometry(LLDrawable *drawable) { - LLFastTimer ftm(FTM_UPDATE_PARTICLES); + LL_RECORD_BLOCK_TIME(FTM_UPDATE_PARTICLES); dirtySpatialGroup(); @@ -281,7 +340,6 @@ BOOL LLVOPartGroup::updateGeometry(LLDrawable *drawable) group->setState(LLSpatialGroup::GEOM_DIRTY); } drawable->setNumFaces(0, NULL, getTEImage(0)); - LLPipeline::sCompiles++; return TRUE; } @@ -307,19 +365,52 @@ BOOL LLVOPartGroup::updateGeometry(LLDrawable *drawable) mDepth = 0.f; S32 i = 0 ; LLVector3 camera_agent = getCameraPosition(); + + F32 max_scale = 0.f; + + for (i = 0 ; i < (S32)mViewerPartGroupp->mParticles.size(); i++) { const LLViewerPart *part = mViewerPartGroupp->mParticles[i]; + + //remember the largest particle + max_scale = llmax(max_scale, part->mScale.mV[0], part->mScale.mV[1]); + + if (part->mFlags & LLPartData::LL_PART_RIBBON_MASK) + { //include ribbon segment length in scale + const LLVector3* pos_agent = NULL; + if (part->mParent) + { + pos_agent = &(part->mParent->mPosAgent); + } + else if (part->mPartSourcep.notNull()) + { + pos_agent = &(part->mPartSourcep->mPosAgent); + } + + if (pos_agent) + { + F32 dist = (*pos_agent-part->mPosAgent).length(); + + max_scale = llmax(max_scale, dist); + } + } + LLVector3 part_pos_agent(part->mPosAgent); LLVector3 at(part_pos_agent - camera_agent); + F32 camera_dist_squared = at.lengthSquared(); F32 inv_camera_dist_squared; if (camera_dist_squared > 1.f) inv_camera_dist_squared = 1.f / camera_dist_squared; else inv_camera_dist_squared = 1.f; + + llassert(std::isfinite(inv_camera_dist_squared)); + llassert(!std::isnan(inv_camera_dist_squared)); + F32 area = part->mScale.mV[0] * part->mScale.mV[1] * inv_camera_dist_squared; tot_area = llmax(tot_area, area); @@ -333,7 +424,7 @@ BOOL LLVOPartGroup::updateGeometry(LLDrawable *drawable) facep = drawable->getFace(i); if (!facep) { - llwarns << "No face found for index " << i << "!" << llendl; + LL_WARNS() << "No face found for index " << i << "!" << LL_ENDL; continue; } @@ -379,35 +470,136 @@ BOOL LLVOPartGroup::updateGeometry(LLDrawable *drawable) LLFace* facep = drawable->getFace(i); if (!facep) { - llwarns << "No face found for index " << i << "!" << llendl; + LL_WARNS() << "No face found for index " << i << "!" << LL_ENDL; continue; } facep->setTEOffset(i); facep->setSize(0, 0); } + //record max scale (used to stretch bounding box for visibility culling) + + mScale.set(max_scale, max_scale, max_scale); + mDrawable->movePartition(); - LLPipeline::sCompiles++; return TRUE; } -void LLVOPartGroup::getGeometry(S32 idx, - LLStrider& verticesp, - LLStrider& normalsp, - LLStrider& texcoordsp, - LLStrider& colorsp, - LLStrider& indicesp) + +BOOL LLVOPartGroup::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, + S32 face, + BOOL pick_transparent, + BOOL pick_rigged, + S32* face_hit, + LLVector4a* intersection, + LLVector2* tex_coord, + LLVector4a* normal, + LLVector4a* bi_normal) { - if (idx >= (S32) mViewerPartGroupp->mParticles.size()) + LLVector4a dir; + dir.setSub(end, start); + + F32 closest_t = 2.f; + BOOL ret = FALSE; + + for (U32 idx = 0; idx < mViewerPartGroupp->mParticles.size(); ++idx) { - return; + const LLViewerPart &part = *((LLViewerPart*) (mViewerPartGroupp->mParticles[idx])); + + LLVector4a v[4]; + LLStrider verticesp; + verticesp = v; + + getGeometry(part, verticesp); + + F32 a,b,t; + if (LLTriangleRayIntersect(v[0], v[1], v[2], start, dir, a,b,t) || + LLTriangleRayIntersect(v[1], v[3], v[2], start, dir, a,b,t)) + { + if (t >= 0.f && + t <= 1.f && + t < closest_t) + { + ret = TRUE; + closest_t = t; + if (face_hit) + { + *face_hit = idx; + } + + if (intersection) + { + LLVector4a intersect = dir; + intersect.mul(closest_t); + intersection->setAdd(intersect, start); + } + } + } } - const LLViewerPart &part = *((LLViewerPart*) (mViewerPartGroupp->mParticles[idx])); + return ret; +} + +void LLVOPartGroup::getGeometry(const LLViewerPart& part, + LLStrider& verticesp) +{ + if (part.mFlags & LLPartData::LL_PART_RIBBON_MASK) + { + LLVector4a axis, pos, paxis, ppos; + F32 scale, pscale; - LLVector4a part_pos_agent; - part_pos_agent.load3(part.mPosAgent.mV); - LLVector4a camera_agent; + pos.load3(part.mPosAgent.mV); + axis.load3(part.mAxis.mV); + scale = part.mScale.mV[0]; + + if (part.mParent) + { + ppos.load3(part.mParent->mPosAgent.mV); + paxis.load3(part.mParent->mAxis.mV); + pscale = part.mParent->mScale.mV[0]; + } + else + { //use source object as position + + if (part.mPartSourcep->mSourceObjectp.notNull()) + { + LLVector3 v = LLVector3(0,0,1); + v *= part.mPartSourcep->mSourceObjectp->getRenderRotation(); + paxis.load3(v.mV); + ppos.load3(part.mPartSourcep->mPosAgent.mV); + pscale = part.mStartScale.mV[0]; + } + else + { //no source object, no parent, nothing to draw + ppos = pos; + pscale = scale; + paxis = axis; + } + } + + LLVector4a p0, p1, p2, p3; + + scale *= 0.5f; + pscale *= 0.5f; + + axis.mul(scale); + paxis.mul(pscale); + + p0.setAdd(pos, axis); + p1.setSub(pos,axis); + p2.setAdd(ppos, paxis); + p3.setSub(ppos, paxis); + + (*verticesp++) = p2; + (*verticesp++) = p3; + (*verticesp++) = p0; + (*verticesp++) = p1; + } + else + { + LLVector4a part_pos_agent; + part_pos_agent.load3(part.mPosAgent.mV); + LLVector4a camera_agent; camera_agent.load3(getCameraPosition().mV); LLVector4a at; at.setSub(part_pos_agent, camera_agent); @@ -451,52 +643,105 @@ void LLVOPartGroup::getGeometry(S32 idx, right.normalize3fast(); } - right.mul(0.5f*part.mScale.mV[0]); - up.mul(0.5f*part.mScale.mV[1]); + right.mul(0.5f*part.mScale.mV[0]); + up.mul(0.5f*part.mScale.mV[1]); + + + //HACK -- the verticesp->mV[3] = 0.f here are to set the texture index to 0 (particles don't use texture batching, maybe they should) + // this works because there is actually a 4th float stored after the vertex position which is used as a texture index + // also, somebody please VECTORIZE THIS + + LLVector4a ppapu; + LLVector4a ppamu; + + ppapu.setAdd(part_pos_agent, up); + ppamu.setSub(part_pos_agent, up); + + verticesp->setSub(ppapu, right); + (*verticesp++).getF32ptr()[3] = 0.f; + verticesp->setSub(ppamu, right); + (*verticesp++).getF32ptr()[3] = 0.f; + verticesp->setAdd(ppapu, right); + (*verticesp++).getF32ptr()[3] = 0.f; + verticesp->setAdd(ppamu, right); + (*verticesp++).getF32ptr()[3] = 0.f; + } +} + + +void LLVOPartGroup::getGeometry(S32 idx, + LLStrider& verticesp, + LLStrider& normalsp, + LLStrider& texcoordsp, + LLStrider& colorsp, + LLStrider& emissivep, + LLStrider& indicesp) +{ + if (idx >= (S32) mViewerPartGroupp->mParticles.size()) + { + return; + } + + const LLViewerPart &part = *((LLViewerPart*) (mViewerPartGroupp->mParticles[idx])); - LLVector3 normal = -LLViewerCamera::getInstance()->getXAxis(); + getGeometry(part, verticesp); - //HACK -- the verticesp->mV[3] = 0.f here are to set the texture index to 0 (particles don't use texture batching, maybe they should) - // this works because there is actually a 4th float stored after the vertex position which is used as a texture index - // also, somebody please VECTORIZE THIS + LLColor4U pcolor; + LLColor4U color = part.mColor; - LLVector4a ppapu; - LLVector4a ppamu; + LLColor4U pglow; - ppapu.setAdd(part_pos_agent, up); - ppamu.setSub(part_pos_agent, up); + if (part.mFlags & LLPartData::LL_PART_RIBBON_MASK) + { //make sure color blends properly + if (part.mParent) + { + pglow = part.mParent->mGlow; + pcolor = part.mParent->mColor; + } + else + { + pglow = LLColor4U(0, 0, 0, (U8) ll_round(255.f*part.mStartGlow)); + pcolor = part.mStartColor; + } + } + else + { + pglow = part.mGlow; + pcolor = color; + } - verticesp->setSub(ppapu, right); - (*verticesp++).getF32ptr()[3] = 0.f; - verticesp->setSub(ppamu, right); - (*verticesp++).getF32ptr()[3] = 0.f; - verticesp->setAdd(ppapu, right); - (*verticesp++).getF32ptr()[3] = 0.f; - verticesp->setAdd(ppamu, right); - (*verticesp++).getF32ptr()[3] = 0.f; + *colorsp++ = pcolor; + *colorsp++ = pcolor; + *colorsp++ = color; + *colorsp++ = color; + + //Only add emissive attributes if glowing (doing it for all particles is INCREDIBLY inefficient as it leads to a second, slower, render pass.) + if (LLGLSLShader::sNoFixedFunction && (pglow.mV[3] > 0 || part.mGlow.mV[3] > 0)) + { //only write glow if it is not zero + *emissivep++ = pglow; + *emissivep++ = pglow; + *emissivep++ = part.mGlow; + *emissivep++ = part.mGlow; + } - *colorsp++ = part.mColor; - *colorsp++ = part.mColor; - *colorsp++ = part.mColor; - *colorsp++ = part.mColor; if (!(part.mFlags & LLPartData::LL_PART_EMISSIVE_MASK)) { //not fullbright, needs normal + LLVector3 normal = -LLViewerCamera::getInstance()->getXAxis(); *normalsp++ = normal; *normalsp++ = normal; *normalsp++ = normal; *normalsp++ = normal; } } - U32 LLVOPartGroup::getPartitionType() const { return LLViewerRegion::PARTITION_PARTICLE; } -LLParticlePartition::LLParticlePartition() -: LLSpatialPartition(LLDrawPoolAlpha::VERTEX_DATA_MASK | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, GL_STREAM_DRAW_ARB) +LLParticlePartition::LLParticlePartition(LLViewerRegion* regionp) +: LLSpatialPartition(LLDrawPoolAlpha::VERTEX_DATA_MASK | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, GL_STREAM_DRAW_ARB, regionp) { mRenderPass = LLRenderPass::PASS_ALPHA; mDrawableType = LLPipeline::RENDER_TYPE_PARTICLES; @@ -505,18 +750,18 @@ LLParticlePartition::LLParticlePartition() mLODPeriod = 1; } -LLHUDParticlePartition::LLHUDParticlePartition() : - LLParticlePartition() +LLHUDParticlePartition::LLHUDParticlePartition(LLViewerRegion* regionp) : + LLParticlePartition(regionp) { mDrawableType = LLPipeline::RENDER_TYPE_HUD_PARTICLES; mPartitionType = LLViewerRegion::PARTITION_HUD_PARTICLE; } -static LLFastTimer::DeclareTimer FTM_REBUILD_PARTICLE_VBO("Particle VBO"); +static LLTrace::BlockTimerStatHandle FTM_REBUILD_PARTICLE_VBO("Particle VBO"); void LLParticlePartition::rebuildGeom(LLSpatialGroup* group) { - if (group->isDead() || !group->isState(LLSpatialGroup::GEOM_DIRTY)) + if (group->isDead() || !group->hasState(LLSpatialGroup::GEOM_DIRTY)) { return; } @@ -527,7 +772,7 @@ void LLParticlePartition::rebuildGeom(LLSpatialGroup* group) group->mLastUpdateViewAngle = group->mViewAngle; } - LLFastTimer ftm(FTM_REBUILD_PARTICLE_VBO); + LL_RECORD_BLOCK_TIME(FTM_REBUILD_PARTICLE_VBO); group->clearDrawMap(); @@ -548,7 +793,7 @@ void LLParticlePartition::rebuildGeom(LLSpatialGroup* group) else { group->mVertexBuffer = NULL; - group->mBufferMap.clear(); + group->mBufferVec.clear(); } group->mLastUpdateTime = gFrameTimeSeconds; @@ -562,10 +807,10 @@ void LLParticlePartition::addGeometryCount(LLSpatialGroup* group, U32& vertex_co mFaceList.clear(); LLViewerCamera* camera = LLViewerCamera::getInstance(); - OctreeGuard guard(group->mOctreeNode); + OctreeGuard guard(group->getOctreeNode()); for (LLSpatialGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i) { - LLDrawable* drawablep = *i; + LLDrawable* drawablep = (LLDrawable*)(*i)->getDrawable(); if (drawablep->isDead()) { @@ -602,11 +847,11 @@ void LLParticlePartition::addGeometryCount(LLSpatialGroup* group, U32& vertex_co } -static LLFastTimer::DeclareTimer FTM_REBUILD_PARTICLE_GEOM("Particle Geom"); +static LLTrace::BlockTimerStatHandle FTM_REBUILD_PARTICLE_GEOM("Particle Geom"); void LLParticlePartition::getGeometry(LLSpatialGroup* group) { - LLFastTimer ftm(FTM_REBUILD_PARTICLE_GEOM); + LL_RECORD_BLOCK_TIME(FTM_REBUILD_PARTICLE_GEOM); std::sort(mFaceList.begin(), mFaceList.end(), LLFace::CompareDistanceGreater()); @@ -622,10 +867,13 @@ void LLParticlePartition::getGeometry(LLSpatialGroup* group) LLStrider normalsp; LLStrider texcoordsp; LLStrider colorsp; + LLStrider emissivep; buffer->getVertexStrider(verticesp); buffer->getNormalStrider(normalsp); buffer->getColorStrider(colorsp); + buffer->getEmissiveStrider(emissivep); + LLSpatialGroup::drawmap_elem_t& draw_vec = group->mDrawMap[mRenderPass]; @@ -658,9 +906,19 @@ void LLParticlePartition::getGeometry(LLSpatialGroup* group) LLStrider cur_norm = normalsp + geom_idx; LLStrider cur_tc = texcoordsp + geom_idx; LLStrider cur_col = colorsp + geom_idx; + LLStrider cur_glow = emissivep + geom_idx; - object->getGeometry(facep->getTEOffset(), cur_vert, cur_norm, cur_tc, cur_col, cur_idx); + LLColor4U* start_glow = cur_glow.get(); + + object->getGeometry(facep->getTEOffset(), cur_vert, cur_norm, cur_tc, cur_col, cur_glow, cur_idx); + BOOL has_glow = FALSE; + + if (cur_glow.get() != start_glow) + { + has_glow = TRUE; + } + llassert(facep->getGeomCount() == 4); llassert(facep->getIndicesCount() == 6); @@ -675,24 +933,37 @@ void LLParticlePartition::getGeometry(LLSpatialGroup* group) bool batched = false; - if (idx >= 0 && - draw_vec[idx]->mTexture == facep->getTexture() && - draw_vec[idx]->mFullbright == fullbright) + U32 bf_src = LLRender::BF_SOURCE_ALPHA; + U32 bf_dst = LLRender::BF_ONE_MINUS_SOURCE_ALPHA; + + object->getBlendFunc(facep->getTEOffset(), bf_src, bf_dst); + + + if (idx >= 0) { - if (draw_vec[idx]->mEnd == facep->getGeomIndex()-1) - { - batched = true; - draw_vec[idx]->mCount += facep->getIndicesCount(); - draw_vec[idx]->mEnd += facep->getGeomCount(); - draw_vec[idx]->mVSize = llmax(draw_vec[idx]->mVSize, vsize); - } - else if (draw_vec[idx]->mStart == facep->getGeomIndex()+facep->getGeomCount()+1) + LLDrawInfo* info = draw_vec[idx]; + + if (info->mTexture == facep->getTexture() && + info->mHasGlow == has_glow && + info->mFullbright == fullbright && + info->mBlendFuncDst == bf_dst && + info->mBlendFuncSrc == bf_src) { - batched = true; - draw_vec[idx]->mCount += facep->getIndicesCount(); - draw_vec[idx]->mStart -= facep->getGeomCount(); - draw_vec[idx]->mOffset = facep->getIndicesStart(); - draw_vec[idx]->mVSize = llmax(draw_vec[idx]->mVSize, vsize); + if (draw_vec[idx]->mEnd == facep->getGeomIndex()-1) + { + batched = true; + info->mCount += facep->getIndicesCount(); + info->mEnd += facep->getGeomCount(); + info->mVSize = llmax(draw_vec[idx]->mVSize, vsize); + } + else if (draw_vec[idx]->mStart == facep->getGeomIndex()+facep->getGeomCount()+1) + { + batched = true; + info->mCount += facep->getIndicesCount(); + info->mStart -= facep->getGeomCount(); + info->mOffset = facep->getIndicesStart(); + info->mVSize = llmax(draw_vec[idx]->mVSize, vsize); + } } } @@ -706,13 +977,23 @@ void LLParticlePartition::getGeometry(LLSpatialGroup* group) LLDrawInfo* info = new LLDrawInfo(start,end,count,offset,facep->getTexture(), //facep->getTexture(), buffer, fullbright); - info->mExtents[0] = group->mObjectExtents[0]; - info->mExtents[1] = group->mObjectExtents[1]; + const LLVector4a* bounds = group->getBounds(); + info->mExtents[0] = bounds[0]; + info->mExtents[1] = bounds[1]; info->mVSize = vsize; + info->mBlendFuncDst = bf_dst; + info->mBlendFuncSrc = bf_src; + info->mHasGlow = has_glow; + info->mParticle = TRUE; draw_vec.push_back(info); //for alpha sorting facep->setDrawInfo(info); } + + if(facep->getGeomCount() > 0) + { + buffer->validateRange(facep->getGeomIndex(), facep->getGeomIndex() + facep->getGeomCount() - 1, facep->getIndicesCount(), facep->getIndicesStart()); + } } mFaceList.clear(); diff --git a/indra/newview/llvopartgroup.h b/indra/newview/llvopartgroup.h index ecf149c67c..4f8d144689 100644 --- a/indra/newview/llvopartgroup.h +++ b/indra/newview/llvopartgroup.h @@ -50,6 +50,7 @@ class LLVOPartGroup : public LLAlphaObject static LLPointer sVB; static S32 sVBSlotFree[LL_MAX_PARTICLE_COUNT]; static S32* sVBSlotCursor; + //static S32 sVBSlotCursor; static void initClass(); static void restoreGL(); @@ -63,6 +64,7 @@ class LLVOPartGroup : public LLAlphaObject LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR | + LLVertexBuffer::MAP_EMISSIVE | LLVertexBuffer::MAP_TEXTURE_INDEX }; @@ -75,20 +77,38 @@ class LLVOPartGroup : public LLAlphaObject virtual void updateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax); virtual U32 getPartitionType() const; + /*virtual*/ BOOL lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, + S32 face, + BOOL pick_transparent, + BOOL pick_rigged, + S32* face_hit, + LLVector4a* intersection, + LLVector2* tex_coord, + LLVector4a* normal, + LLVector4a* tangent); + /*virtual*/ void setPixelAreaAndAngle(LLAgent &agent); /*virtual*/ void updateTextures(); /*virtual*/ LLDrawable* createDrawable(LLPipeline *pipeline); /*virtual*/ BOOL updateGeometry(LLDrawable *drawable); + void getGeometry(const LLViewerPart& part, + LLStrider& verticesp); + void getGeometry(S32 idx, LLStrider& verticesp, LLStrider& normalsp, LLStrider& texcoordsp, LLStrider& colorsp, + LLStrider& emissivep, LLStrider& indicesp); void updateFaceSize(S32 idx) { } F32 getPartSize(S32 idx); + void getBlendFunc(S32 idx, U32& src, U32& dst); + LLUUID getPartOwner(S32 idx); + LLUUID getPartSource(S32 idx); + void setViewerPartGroup(LLViewerPartGroup *part_groupp) { mViewerPartGroupp = part_groupp; } LLViewerPartGroup* getViewerPartGroup() { return mViewerPartGroupp; } diff --git a/indra/newview/llvosky.cpp b/indra/newview/llvosky.cpp index ea222c34da..6854acb629 100644 --- a/indra/newview/llvosky.cpp +++ b/indra/newview/llvosky.cpp @@ -216,7 +216,8 @@ LLSkyTex::LLSkyTex() : void LLSkyTex::init() { - mSkyData = new LLColor4[sResolution * sResolution]; + // Singu Note: Store as unsigned to avoid casting. + mSkyData = new LLColor4U[sResolution * sResolution]; mSkyDirs = new LLVector3[sResolution * sResolution]; for (S32 i = 0; i < 2; ++i) @@ -286,8 +287,7 @@ void LLSkyTex::create(const F32 brightness) const S32 basic_offset = (i * sResolution + j); S32 offset = basic_offset * sComponents; U32* pix = (U32*)(data + offset); - LLColor4U temp = LLColor4U(mSkyData[basic_offset]); - *pix = temp.mAll; + *pix = mSkyData[basic_offset].mAll; } } createGLImage(sCurrent); @@ -298,8 +298,7 @@ void LLSkyTex::create(const F32 brightness) void LLSkyTex::createGLImage(S32 which) { - mTexture[which]->setNeedsAlphaAndPickMask(false); //Needed, else analyzeAlpha is called every frame for each texture. - mTexture[which]->createGLTexture(0, mImageRaw[which], 0, TRUE, LLViewerTexture::LOCAL); + mTexture[which]->createGLTexture(0, mImageRaw[which], nullptr, TRUE, LLGLTexture::LOCAL); mTexture[which]->setAddressMode(LLTexUnit::TAM_CLAMP); } @@ -385,9 +384,9 @@ LLVOSky::LLVOSky(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp) mSun.setIntensity(SUN_INTENSITY); mMoon.setIntensity(0.1f * SUN_INTENSITY); - mSunTexturep = LLViewerTextureManager::getFetchedTexture(gSunTextureID, TRUE, LLGLTexture::BOOST_UI); + mSunTexturep = LLViewerTextureManager::getFetchedTexture(gSunTextureID, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_UI); mSunTexturep->setAddressMode(LLTexUnit::TAM_CLAMP); - mMoonTexturep = LLViewerTextureManager::getFetchedTexture(gMoonTextureID, TRUE, LLGLTexture::BOOST_UI); + mMoonTexturep = LLViewerTextureManager::getFetchedTexture(gMoonTextureID, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_UI); mMoonTexturep->setAddressMode(LLTexUnit::TAM_CLAMP); mBloomTexturep = LLViewerTextureManager::getFetchedTexture(IMG_BLOOM1); mBloomTexturep->setNoDelete() ; @@ -479,9 +478,9 @@ void LLVOSky::restoreGL() { mSkyTex[i].restoreGL(); } - mSunTexturep = LLViewerTextureManager::getFetchedTexture(gSunTextureID, TRUE, LLGLTexture::BOOST_UI); + mSunTexturep = LLViewerTextureManager::getFetchedTexture(gSunTextureID, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_UI); mSunTexturep->setAddressMode(LLTexUnit::TAM_CLAMP); - mMoonTexturep = LLViewerTextureManager::getFetchedTexture(gMoonTextureID, TRUE, LLGLTexture::BOOST_UI); + mMoonTexturep = LLViewerTextureManager::getFetchedTexture(gMoonTextureID, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_UI); mMoonTexturep->setAddressMode(LLTexUnit::TAM_CLAMP); mBloomTexturep = LLViewerTextureManager::getFetchedTexture(IMG_BLOOM1); mBloomTexturep->setNoDelete() ; @@ -1247,7 +1246,7 @@ void LLVOSky::createDummyVertexBuffer() } } -static LLFastTimer::DeclareTimer FTM_RENDER_FAKE_VBO_UPDATE("Fake VBO Update"); +static LLTrace::BlockTimerStatHandle FTM_RENDER_FAKE_VBO_UPDATE("Fake VBO Update"); void LLVOSky::updateDummyVertexBuffer() { @@ -1260,7 +1259,7 @@ void LLVOSky::updateDummyVertexBuffer() return ; } - LLFastTimer t(FTM_RENDER_FAKE_VBO_UPDATE) ; + LL_RECORD_BLOCK_TIME(FTM_RENDER_FAKE_VBO_UPDATE) ; if(!mFace[FACE_DUMMY] || !mFace[FACE_DUMMY]->getVertexBuffer()) createDummyVertexBuffer() ; @@ -1273,11 +1272,11 @@ void LLVOSky::updateDummyVertexBuffer() //---------------------------------- //end of fake vertex buffer updating //---------------------------------- -static LLFastTimer::DeclareTimer FTM_GEO_SKY("Sky Geometry"); +static LLTrace::BlockTimerStatHandle FTM_GEO_SKY("Sky Geometry"); BOOL LLVOSky::updateGeometry(LLDrawable *drawable) { - LLFastTimer ftm(FTM_GEO_SKY); + LL_RECORD_BLOCK_TIME(FTM_GEO_SKY); if (mFace[FACE_REFLECTION] == NULL) { LLDrawPoolWater *poolp = (LLDrawPoolWater*) gPipeline.getPool(LLDrawPool::POOL_WATER); @@ -1411,8 +1410,6 @@ BOOL LLVOSky::updateGeometry(LLDrawable *drawable) { setDrawRefl(-1); } - - LLPipeline::sCompiles++; return TRUE; } @@ -1519,10 +1516,10 @@ BOOL LLVOSky::updateHeavenlyBodyGeometry(LLDrawable *drawable, const S32 f, cons *indicesp++ = index_offset + 2; *indicesp++ = index_offset + 3; - *(colorsp++) = LLColor4::white; - *(colorsp++) = LLColor4::white; - *(colorsp++) = LLColor4::white; - *(colorsp++) = LLColor4::white; + *(colorsp++) = LLColor4U::white; + *(colorsp++) = LLColor4U::white; + *(colorsp++) = LLColor4U::white; + *(colorsp++) = LLColor4U::white; facep->getVertexBuffer()->flush(); diff --git a/indra/newview/llvosky.h b/indra/newview/llvosky.h index 2a150eccb9..37793b8d20 100644 --- a/indra/newview/llvosky.h +++ b/indra/newview/llvosky.h @@ -42,28 +42,28 @@ // Will clean these up at some point... // -const F32 HORIZON_DIST = 1024.0f; -const F32 SKY_BOX_MULT = 16.0f; -const F32 HEAVENLY_BODY_DIST = HORIZON_DIST - 10.f; -const F32 HEAVENLY_BODY_FACTOR = 0.1f; -const F32 HEAVENLY_BODY_SCALE = HEAVENLY_BODY_DIST * HEAVENLY_BODY_FACTOR; -const F32 EARTH_RADIUS = 6.4e6f; // exact radius = 6.37 x 10^6 m -const F32 ATM_EXP_FALLOFF = 0.000126f; -const F32 ATM_SEA_LEVEL_NDENS = 2.55e25f; +constexpr F32 HORIZON_DIST = 1024.0f; +constexpr F32 SKY_BOX_MULT = 16.0f; +constexpr F32 HEAVENLY_BODY_DIST = HORIZON_DIST - 10.f; +constexpr F32 HEAVENLY_BODY_FACTOR = 0.1f; +constexpr F32 HEAVENLY_BODY_SCALE = HEAVENLY_BODY_DIST * HEAVENLY_BODY_FACTOR; +constexpr F32 EARTH_RADIUS = 6.4e6f; // exact radius = 6.37 x 10^6 m +constexpr F32 ATM_EXP_FALLOFF = 0.000126f; +constexpr F32 ATM_SEA_LEVEL_NDENS = 2.55e25f; // Somewhat arbitrary: -const F32 ATM_HEIGHT = 100000.f; +constexpr F32 ATM_HEIGHT = 100000.f; -const F32 FIRST_STEP = 5000.f; -const F32 INV_FIRST_STEP = 1.f/FIRST_STEP; -const S32 NO_STEPS = 15; -const F32 INV_NO_STEPS = 1.f/NO_STEPS; +constexpr F32 FIRST_STEP = 5000.f; +constexpr F32 INV_FIRST_STEP = 1.f/FIRST_STEP; +constexpr S32 NO_STEPS = 15; +constexpr F32 INV_NO_STEPS = 1.f/NO_STEPS; // constants used in calculation of scattering coeff of clear air -const F32 sigma = 0.035f; -const F32 fsigma = (6.f + 3.f * sigma) / (6.f-7.f*sigma); -const F64 Ndens = 2.55e25; -const F64 Ndens2 = Ndens*Ndens; +constexpr F32 sigma = 0.035f; +constexpr F32 fsigma = (6.f + 3.f * sigma) / (6.f-7.f*sigma); +constexpr F64 Ndens = 2.55e25; +constexpr F64 Ndens2 = Ndens*Ndens; // HACK: Allow server to change sun and moon IDs. // I can't figure out how to pass the appropriate @@ -118,7 +118,8 @@ class LLSkyTex static S32 sComponents; LLPointer mTexture[2]; LLPointer mImageRaw[2]; - LLColor4 *mSkyData; + // Singu Note: Store as unsigned to avoid casting. + LLColor4U *mSkyData; LLVector3 *mSkyDirs; // Cache of sky direction vectors static S32 sCurrent; static F32 sInterpVal; diff --git a/indra/newview/llvosurfacepatch.cpp b/indra/newview/llvosurfacepatch.cpp index 465df0465d..99312e1ca5 100644 --- a/indra/newview/llvosurfacepatch.cpp +++ b/indra/newview/llvosurfacepatch.cpp @@ -78,7 +78,7 @@ class LLVertexBufferTerrain : public LLVertexBuffer if ((data_mask & type_mask) != data_mask) { - llerrs << "LLVertexBuffer::setupVertexBuffer missing required components for supplied data mask." << llendl; + LL_ERRS() << "LLVertexBuffer::setupVertexBuffer missing required components for supplied data mask." << LL_ENDL; } if (data_mask & MAP_NORMAL) @@ -103,10 +103,10 @@ class LLVertexBufferTerrain : public LLVertexBuffer glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], (void*)(base + mOffsets[TYPE_TEXCOORD1])); glClientActiveTextureARB(GL_TEXTURE0_ARB); } - if (data_mask & MAP_BINORMAL) + if (data_mask & MAP_TANGENT) { glClientActiveTextureARB(GL_TEXTURE2_ARB); - glTexCoordPointer(3,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_BINORMAL], (void*)(base + mOffsets[TYPE_BINORMAL])); + glTexCoordPointer(3,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TANGENT], (void*)(base + mOffsets[TYPE_TANGENT])); glClientActiveTextureARB(GL_TEXTURE0_ARB); } if (data_mask & MAP_TEXCOORD0) @@ -218,7 +218,7 @@ LLDrawable *LLVOSurfacePatch::createDrawable(LLPipeline *pipeline) return mDrawable; } -static LLFastTimer::DeclareTimer FTM_UPDATE_TERRAIN("Update Terrain"); +static LLTrace::BlockTimerStatHandle FTM_UPDATE_TERRAIN("Update Terrain"); void LLVOSurfacePatch::updateGL() { @@ -230,7 +230,7 @@ void LLVOSurfacePatch::updateGL() BOOL LLVOSurfacePatch::updateGeometry(LLDrawable *drawable) { - LLFastTimer ftm(FTM_UPDATE_TERRAIN); + LL_RECORD_BLOCK_TIME(FTM_UPDATE_TERRAIN); dirtySpatialGroup(TRUE); @@ -267,18 +267,19 @@ BOOL LLVOSurfacePatch::updateGeometry(LLDrawable *drawable) length = patch_width / render_stride; - if (mPatchp->getNeighborPatch(NORTH)) + LLSurfacePatch* neighborPatch; + if (neighborPatch = mPatchp->getNeighborPatch(NORTH)) { - north_stride = mPatchp->getNeighborPatch(NORTH)->getRenderStride(); + north_stride = neighborPatch->getRenderStride(); } else { north_stride = render_stride; } - if (mPatchp->getNeighborPatch(EAST)) + if (neighborPatch = mPatchp->getNeighborPatch(EAST)) { - east_stride = mPatchp->getNeighborPatch(EAST)->getRenderStride(); + east_stride = neighborPatch->getRenderStride(); } else { @@ -297,7 +298,7 @@ void LLVOSurfacePatch::updateFaceSize(S32 idx) { if (idx != 0) { - llwarns << "Terrain partition requested invalid face!!!" << llendl; + LL_WARNS() << "Terrain partition requested invalid face!!!" << LL_ENDL; return; } @@ -942,8 +943,8 @@ void LLVOSurfacePatch::getGeomSizesEast(const S32 stride, const S32 east_stride, } } -BOOL LLVOSurfacePatch::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, S32 face, BOOL pick_transparent, S32 *face_hitp, - LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal) +BOOL LLVOSurfacePatch::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, S32 face, BOOL pick_transparent, BOOL pick_rigged, S32 *face_hitp, + LLVector4a* intersection,LLVector2* tex_coord, LLVector4a* normal, LLVector4a* tangent) { @@ -952,7 +953,9 @@ BOOL LLVOSurfacePatch::lineSegmentIntersect(const LLVector3& start, const LLVect return FALSE; } - LLVector3 delta = end-start; + LLVector4a da; + da.setSub(end, start); + LLVector3 delta(da.getF32ptr()); LLVector3 pdelta = delta; pdelta.mV[2] = 0; @@ -961,7 +964,9 @@ BOOL LLVOSurfacePatch::lineSegmentIntersect(const LLVector3& start, const LLVect F32 tdelta = 1.f/plength; - LLVector3 origin = start - mRegionp->getOriginAgent(); + LLVector3 v_start(start.getF32ptr()); + + LLVector3 origin = v_start - mRegionp->getOriginAgent(); if (mRegionp->getLandHeightRegion(origin) > origin.mV[2]) { @@ -1016,12 +1021,12 @@ BOOL LLVOSurfacePatch::lineSegmentIntersect(const LLVector3& start, const LLVect { sample.mV[2] = mRegionp->getLandHeightRegion(sample); } - *intersection = sample + mRegionp->getOriginAgent(); + intersection->load3((sample + mRegionp->getOriginAgent()).mV); } if (normal) { - *normal = mRegionp->getLand().resolveNormalGlobal(mRegionp->getPosGlobalFromRegion(sample)); + normal->load3((mRegionp->getLand().resolveNormalGlobal(mRegionp->getPosGlobalFromRegion(sample))).mV); } return TRUE; @@ -1058,8 +1063,8 @@ U32 LLVOSurfacePatch::getPartitionType() const return LLViewerRegion::PARTITION_TERRAIN; } -LLTerrainPartition::LLTerrainPartition() -: LLSpatialPartition(LLDrawPoolTerrain::VERTEX_DATA_MASK, FALSE, GL_DYNAMIC_DRAW_ARB) +LLTerrainPartition::LLTerrainPartition(LLViewerRegion* regionp) +: LLSpatialPartition(LLDrawPoolTerrain::VERTEX_DATA_MASK, FALSE, GL_DYNAMIC_DRAW_ARB, regionp) { mOcclusionEnabled = FALSE; mInfiniteFarClip = TRUE; @@ -1072,10 +1077,10 @@ LLVertexBuffer* LLTerrainPartition::createVertexBuffer(U32 type_mask, U32 usage) return new LLVertexBufferTerrain(); } -static LLFastTimer::DeclareTimer FTM_REBUILD_TERRAIN_VB("Terrain VB"); +static LLTrace::BlockTimerStatHandle FTM_REBUILD_TERRAIN_VB("Terrain VB"); void LLTerrainPartition::getGeometry(LLSpatialGroup* group) { - LLFastTimer ftm(FTM_REBUILD_TERRAIN_VB); + LL_RECORD_BLOCK_TIME(FTM_REBUILD_TERRAIN_VB); LLVertexBuffer* buffer = group->mVertexBuffer; diff --git a/indra/newview/llvosurfacepatch.h b/indra/newview/llvosurfacepatch.h index 7637be8679..e073e9df77 100644 --- a/indra/newview/llvosurfacepatch.h +++ b/indra/newview/llvosurfacepatch.h @@ -85,14 +85,15 @@ class LLVOSurfacePatch : public LLStaticViewerObject void dirtyPatch(); void dirtyGeom(); - /*virtual*/ BOOL lineSegmentIntersect(const LLVector3& start, const LLVector3& end, + /*virtual*/ BOOL lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, S32 face = -1, // which face to check, -1 = ALL_SIDES BOOL pick_transparent = FALSE, + BOOL pick_rigged = FALSE, S32* face_hit = NULL, // which face was hit - LLVector3* intersection = NULL, // return the intersection point + LLVector4a* intersection = NULL, // return the intersection point LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point - LLVector3* normal = NULL, // return the surface normal at the intersection point - LLVector3* bi_normal = NULL // return the surface bi-normal at the intersection point + LLVector4a* normal = NULL, // return the surface normal at the intersection point + LLVector4a* tangent = NULL // return the surface tangent at the intersection point ); BOOL mDirtiedPatch; diff --git a/indra/newview/llvotree.cpp b/indra/newview/llvotree.cpp index a4d57e2d30..16ccc97b59 100644 --- a/indra/newview/llvotree.cpp +++ b/indra/newview/llvotree.cpp @@ -49,14 +49,16 @@ #include "llagentcamera.h" #include "lldrawable.h" #include "llface.h" +#include "llselectmgr.h" #include "llviewercamera.h" #include "llviewertexturelist.h" #include "llviewerobjectlist.h" #include "llviewerregion.h" #include "llworld.h" -#include "noise.h" +#include "llperlin.h" #include "pipeline.h" #include "llspatialpartition.h" +//#include "llviewerwindow.h" #include "llnotificationsutil.h" #include "raytrace.h" #include "llglslshader.h" @@ -105,6 +107,10 @@ LLVOTree::~LLVOTree() delete[] mData; mData = NULL; } + for(std::vector >::iterator iter = mDrawList.begin(); iter != mDrawList.end(); iter++) + { + delete (*iter)->mModelMatrix; + } } //static @@ -122,7 +128,7 @@ void LLVOTree::initClass() if (!tree_def_tree.parseFile(xml_filename)) { - llerrs << "Failed to parse tree file." << llendl; + LL_ERRS() << "Failed to parse tree file." << LL_ENDL; } LLXmlTreeNode* rootp = tree_def_tree.getRoot(); @@ -133,7 +139,7 @@ void LLVOTree::initClass() { if (!tree_def->hasName("tree")) { - llwarns << "Invalid tree definition node " << tree_def->getName() << llendl; + LL_WARNS() << "Invalid tree definition node " << tree_def->getName() << LL_ENDL; continue; } F32 F32_val; @@ -148,19 +154,19 @@ void LLVOTree::initClass() static LLStdStringHandle species_id_string = LLXmlTree::addAttributeString("species_id"); if (!tree_def->getFastAttributeS32(species_id_string, species)) { - llwarns << "No species id defined" << llendl; + LL_WARNS() << "No species id defined" << LL_ENDL; continue; } if (species < 0) { - llwarns << "Invalid species id " << species << llendl; + LL_WARNS() << "Invalid species id " << species << LL_ENDL; continue; } if (sSpeciesTable.count(species)) { - llwarns << "Tree species " << species << " already defined! Duplicate discarded." << llendl; + LL_WARNS() << "Tree species " << species << " already defined! Duplicate discarded." << LL_ENDL; continue; } @@ -256,7 +262,7 @@ void LLVOTree::initClass() std::string name; static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name"); tree_def->getFastAttributeString(name_string, name); - llwarns << "Incomplete definition of tree " << name << llendl; + LL_WARNS() << "Incomplete definition of tree " << name << LL_ENDL; } } @@ -298,7 +304,7 @@ U32 LLVOTree::processUpdateMessage(LLMessageSystem *mesgsys, ||(getAcceleration().lengthSquared() > 0.f) ||(getAngularVelocity().lengthSquared() > 0.f)) { - llinfos << "ACK! Moving tree!" << llendl; + LL_INFOS() << "ACK! Moving tree!" << LL_ENDL; setVelocity(LLVector3::zero); setAcceleration(LLVector3::zero); setAngularVelocity(LLVector3::zero); @@ -330,9 +336,9 @@ U32 LLVOTree::processUpdateMessage(LLMessageSystem *mesgsys, // // Load Species-Specific data // - static const S32 MAX_TREE_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL = 32 ; //frames. - mTreeImagep = LLViewerTextureManager::getFetchedTexture(sSpeciesTable[mSpecies]->mTextureID, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); - mTreeImagep->setMaxVirtualSizeResetInterval(MAX_TREE_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL); //allow to wait for at most 16 frames to reset virtual size. + static const S32 MAX_TREE_TEXTURE_VIRTUAL_SIZE_RESET_INTERVAL = 32 ; //frames. + mTreeImagep = LLViewerTextureManager::getFetchedTexture(sSpeciesTable[mSpecies]->mTextureID, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); + mTreeImagep->setMaxVirtualSizeResetInterval(MAX_TREE_TEXTURE_VIRTUAL_SIZE_RESET_INTERVAL); //allow to wait for at most 16 frames to reset virtual size. mBranchLength = sSpeciesTable[mSpecies]->mBranchLength; mTrunkLength = sSpeciesTable[mSpecies]->mTrunkLength; @@ -356,12 +362,52 @@ U32 LLVOTree::processUpdateMessage(LLMessageSystem *mesgsys, void LLVOTree::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) { + const U16 FRAMES_PER_WIND_UPDATE = 20; // How many frames between wind update per tree + const F32 TREE_WIND_SENSITIVITY = 0.005f; + const F32 TREE_TRUNK_STIFFNESS = 0.1f; + if (mDead || !(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_TREE))) { return; } - - S32 trunk_LOD = sMAX_NUM_TREE_LOD_LEVELS ; + + static LLCachedControl sRenderAnimateTrees(gSavedSettings, "RenderAnimateTrees"); + if (sRenderAnimateTrees) + { + F32 mass_inv; + + // For all tree objects, update the trunk bending with the current wind + // Walk sprite list in order away from viewer + if (!(mFrameCount % FRAMES_PER_WIND_UPDATE)) + { + // If needed, Get latest wind for this tree + mWind = mRegionp->mWind.getVelocity(getPositionRegion()); + } + mFrameCount++; + + mass_inv = 1.f/(5.f + mDepth*mBranches*0.2f); + mTrunkVel += (mWind * mass_inv * TREE_WIND_SENSITIVITY); // Pull in direction of wind + mTrunkVel -= (mTrunkBend * mass_inv * TREE_TRUNK_STIFFNESS); // Restoring force in direction of trunk + mTrunkBend += mTrunkVel; + mTrunkVel *= 0.99f; // Add damping + + if (mTrunkBend.length() > 1.f) + { + mTrunkBend.normalize(); + } + + if (mTrunkVel.length() > 1.f) + { + mTrunkVel.normalize(); + } + } + else + { + mTrunkBend.clear(); + mTrunkVel.clear(); + } + + S32 trunk_LOD = sMAX_NUM_TREE_LOD_LEVELS; F32 app_angle = getAppAngle()*LLVOTree::sTreeFactor; for (S32 j = 0; j < sMAX_NUM_TREE_LOD_LEVELS; j++) @@ -373,41 +419,49 @@ void LLVOTree::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) } } - if (mReferenceBuffer.isNull()) + if (!sRenderAnimateTrees) { - gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE); - } - else if (trunk_LOD != mTrunkLOD) - { - gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, FALSE); - } - else - { - // we're not animating but we may *still* need to - // regenerate the mesh if we moved, since position - // and rotation are baked into the mesh. - // *TODO: I don't know what's so special about trees - // that they don't get REBUILD_POSITION automatically - // at a higher level. - const LLVector3 &this_position = getPositionRegion(); - if (this_position != mLastPosition) + if (mReferenceBuffer.isNull()) + { + gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE); + } + else if (trunk_LOD != mTrunkLOD) { - gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_POSITION); - mLastPosition = this_position; + gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, FALSE); } else { - const LLQuaternion &this_rotation = getRotation(); - - if (this_rotation != mLastRotation) + // we're not animating but we may *still* need to + // regenerate the mesh if we moved, since position + // and rotation are baked into the mesh. + // *TODO: I don't know what's so special about trees + // that they don't get REBUILD_POSITION automatically + // at a higher level. + const LLVector3 &this_position = getPositionRegion(); + if (this_position != mLastPosition) { gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_POSITION); - mLastRotation = this_rotation; + mLastPosition = this_position; + } + else + { + const LLQuaternion &this_rotation = getRotation(); + + if (this_rotation != mLastRotation) + { + gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_POSITION); + mLastRotation = this_rotation; + } } } } + else + { + gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, FALSE); + } mTrunkLOD = trunk_LOD; + //return TRUE; } const F32 TREE_BLEND_MIN = 1.f; @@ -494,11 +548,22 @@ LLDrawable* LLVOTree::createDrawable(LLPipeline *pipeline) const S32 LEAF_INDICES = 24; const S32 LEAF_VERTICES = 16; -static LLFastTimer::DeclareTimer FTM_UPDATE_TREE("Update Tree"); +static LLTrace::BlockTimerStatHandle FTM_UPDATE_TREE("Update Tree"); + +void LLVOTree::resetVertexBuffers() +{ + mReferenceBuffer = NULL; +} BOOL LLVOTree::updateGeometry(LLDrawable *drawable) { - LLFastTimer ftm(FTM_UPDATE_TREE); + LL_RECORD_BLOCK_TIME(FTM_UPDATE_TREE); + + for(std::vector >::iterator iter = mDrawList.begin(); iter != mDrawList.end(); iter++) + { + delete (*iter)->mModelMatrix; + } + mDrawList.clear(); if(mTrunkLOD >= sMAX_NUM_TREE_LOD_LEVELS) //do not display the tree. { @@ -540,8 +605,8 @@ BOOL LLVOTree::updateGeometry(LLDrawable *drawable) max_indices += sLODIndexCount[lod]; max_vertices += sLODVertexCount[lod]; } - - mReferenceBuffer = new LLVertexBuffer(LLDrawPoolTree::VERTEX_DATA_MASK, 0); + + mReferenceBuffer = new LLVertexBuffer(LLDrawPoolTree::VERTEX_DATA_MASK, GL_STATIC_DRAW_ARB); mReferenceBuffer->allocateBuffer(max_vertices, max_indices, TRUE); LLStrider vertices; @@ -712,8 +777,8 @@ BOOL LLVOTree::updateGeometry(LLDrawable *drawable) slices = sLODSlices[lod]; F32 base_radius = 0.65f; F32 top_radius = base_radius * sSpeciesTable[mSpecies]->mTaper; - //llinfos << "Species " << ((U32) mSpecies) << ", taper = " << sSpeciesTable[mSpecies].mTaper << llendl; - //llinfos << "Droop " << mDroop << ", branchlength: " << mBranchLength << llendl; + //LL_INFOS() << "Species " << ((U32) mSpecies) << ", taper = " << sSpeciesTable[mSpecies].mTaper << LL_ENDL; + //LL_INFOS() << "Droop " << mDroop << ", branchlength: " << mBranchLength << LL_ENDL; F32 angle = 0; F32 angle_inc = 360.f/(slices-1); F32 z = 0.f; @@ -781,7 +846,7 @@ BOOL LLVOTree::updateGeometry(LLDrawable *drawable) sin(nangle * DEG_TO_RAD)*start_radius*nvec_scale, z*nvec_scalez); // First and last slice at 0 radius (to bring in top/bottom of structure) - radius = start_radius + turbulence3((F32*)&nvec.mV, (F32)fractal_depth)*noise_scale; + radius = start_radius + LLPerlinNoise::turbulence(nvec, (F32)fractal_depth)*noise_scale; if (slices - 1 == j) { @@ -847,20 +912,18 @@ BOOL LLVOTree::updateGeometry(LLDrawable *drawable) //generate tree mesh updateMesh(); - + return TRUE; } void LLVOTree::updateMesh() { - LLMatrix4 matrix; - // Translate to tree base HACK - adjustment in Z plants tree underground const LLVector3 &pos_region = getPositionRegion(); //gGL.translatef(pos_agent.mV[VX], pos_agent.mV[VY], pos_agent.mV[VZ] - 0.1f); - LLMatrix4 trans_mat; - trans_mat.setTranslation(pos_region.mV[VX], pos_region.mV[VY], pos_region.mV[VZ] - 0.1f); - trans_mat *= matrix; + LLMatrix4a trans_mat; + trans_mat.setIdentity(); + trans_mat.setTranslate_affine(pos_region - LLVector3(0.f,0.f,0.1f)); // Rotate to tree position and bend for current trunk/wind // Note that trunk stiffness controls the amount of bend at the trunk as @@ -873,16 +936,12 @@ void LLVOTree::updateMesh() LLQuaternion(90.f*DEG_TO_RAD, LLVector4(0,0,1)) * getRotation(); - LLMatrix4 rot_mat(rot); - rot_mat *= trans_mat; - F32 radius = getScale().magVec()*0.05f; - LLMatrix4 scale_mat; - scale_mat.mMatrix[0][0] = - scale_mat.mMatrix[1][1] = - scale_mat.mMatrix[2][2] = radius; + LLMatrix4a rot_mat = trans_mat; + rot_mat.mul(LLQuaternion2(rot)); - scale_mat *= rot_mat; + F32 radius = getScale().magVec()*0.05f; + rot_mat.applyScale_affine(radius); // const F32 THRESH_ANGLE_FOR_BILLBOARD = 15.f; // const F32 BLEND_RANGE_FOR_BILLBOARD = 3.f; @@ -899,78 +958,102 @@ void LLVOTree::updateMesh() LLFace* facep = mDrawable->getFace(0); if (!facep) return; - LLVertexBuffer* buff = new LLVertexBuffer(LLDrawPoolTree::VERTEX_DATA_MASK, GL_STATIC_DRAW_ARB); - buff->allocateBuffer(vert_count, index_count, TRUE); - facep->setVertexBuffer(buff); - LLStrider vertices; - LLStrider normals; + LLStrider vertices; + LLStrider normals; LLStrider tex_coords; LLStrider indices; U16 idx_offset = 0; - buff->getVertexStrider(vertices); - buff->getNormalStrider(normals); - buff->getTexCoord0Strider(tex_coords); - buff->getIndexStrider(indices); + LLVertexBuffer* buff = NULL; - genBranchPipeline(vertices, normals, tex_coords, indices, idx_offset, scale_mat, mTrunkLOD, stop_depth, mDepth, mTrunkDepth, 1.0, mTwist, droop, mBranches, alpha); + static LLCachedControl sRenderAnimateTrees("RenderAnimateTrees", false); + if (sRenderAnimateTrees) + { + facep->setVertexBuffer(NULL); + } + else + { + buff = new LLVertexBuffer(LLDrawPoolTree::VERTEX_DATA_MASK, GL_STATIC_DRAW_ARB); + buff->allocateBuffer(vert_count, index_count, TRUE); + facep->setVertexBuffer(buff); + + buff->getVertexStrider(vertices); + buff->getNormalStrider(normals); + buff->getTexCoord0Strider(tex_coords); + buff->getIndexStrider(indices); + } + + genBranchPipeline(vertices, normals, tex_coords, indices, idx_offset, rot_mat, mTrunkLOD, stop_depth, mDepth, mTrunkDepth, 1.0, mTwist, droop, mBranches, alpha); - mReferenceBuffer->flush(); - buff->flush(); + if(buff) + { + mReferenceBuffer->flush(); + buff->flush(); + } } -void LLVOTree::appendMesh(LLStrider& vertices, - LLStrider& normals, +void LLVOTree::appendMesh(LLStrider& vertices, + LLStrider& normals, LLStrider& tex_coords, LLStrider& indices, U16& cur_idx, - LLMatrix4& matrix, - LLMatrix4& norm_mat, + LLMatrix4a& matrix, + LLMatrix4a& norm_mat, S32 vert_start, S32 vert_count, S32 index_count, S32 index_offset) { - LLStrider v; - LLStrider n; + LLStrider v; + LLStrider n; LLStrider t; LLStrider idx; - mReferenceBuffer->getVertexStrider(v); - mReferenceBuffer->getNormalStrider(n); - mReferenceBuffer->getTexCoord0Strider(t); - mReferenceBuffer->getIndexStrider(idx); - - //copy/transform vertices into mesh - check - for (S32 i = 0; i < vert_count; i++) - { - U16 index = vert_start + i; - *vertices++ = v[index] * matrix; - LLVector3 norm = n[index] * norm_mat; - norm.normalize(); - *normals++ = norm; - *tex_coords++ = t[index]; - } - - //copy offset indices into mesh - check - for (S32 i = 0; i < index_count; i++) + static LLCachedControl sRenderAnimateTrees(gSavedSettings, "RenderAnimateTrees"); + if(sRenderAnimateTrees) //Instead of manipulating the vbo, use the reference vbo and apply the transformation matrix to the matrix stack at draw-time. { - U16 index = index_offset + i; - *indices++ = idx[index]-vert_start+cur_idx; + LLDrawInfo* draw_info = new LLDrawInfo(vert_start,vert_start+vert_count-1,index_count,index_offset,NULL,mReferenceBuffer); + draw_info->mModelMatrix = new LLMatrix4a(matrix); //Make sure these are deleted before clearing/destructing mDrawList! + mDrawList.push_back(draw_info); } + else + { + mReferenceBuffer->getVertexStrider(v); + mReferenceBuffer->getNormalStrider(n); + mReferenceBuffer->getTexCoord0Strider(t); + mReferenceBuffer->getIndexStrider(idx); + + //copy/transform vertices into mesh - check + for (S32 i = 0; i < vert_count; i++) + { + U16 index = vert_start + i; + matrix.affineTransform(v[index],*vertices++); + LLVector4a& norm = *normals++; + norm_mat.perspectiveTransform(n[index],norm); + norm.normalize3fast(); + *tex_coords++ = t[index]; + } - //increment index offset - check - cur_idx += vert_count; + //copy offset indices into mesh - check + for (S32 i = 0; i < index_count; i++) + { + U16 index = index_offset + i; + *indices++ = idx[index]-vert_start+cur_idx; + } + + //increment index offset - check + cur_idx += vert_count; + } } -void LLVOTree::genBranchPipeline(LLStrider& vertices, - LLStrider& normals, +void LLVOTree::genBranchPipeline(LLStrider& vertices, + LLStrider& normals, LLStrider& tex_coords, LLStrider& indices, U16& index_offset, - LLMatrix4& matrix, + LLMatrix4a& matrix, S32 trunk_LOD, S32 stop_level, U16 depth, @@ -999,46 +1082,44 @@ void LLVOTree::genBranchPipeline(LLStrider& vertices, { llassert(sLODIndexCount[trunk_LOD] > 0); width = scale * length * aspect; - LLMatrix4 scale_mat; - scale_mat.mMatrix[0][0] = width; - scale_mat.mMatrix[1][1] = width; - scale_mat.mMatrix[2][2] = scale*length; - scale_mat *= matrix; - glh::matrix4f norm((F32*) scale_mat.mMatrix); - LLMatrix4 norm_mat = LLMatrix4(norm.inverse().transpose().m); + LLMatrix4a scale_mat = matrix; + scale_mat.applyScale_affine(width,width,scale*length); + LLMatrix4a norm_mat = scale_mat; norm_mat.invert(); + norm_mat.transpose(); + appendMesh(vertices, normals, tex_coords, indices, index_offset, scale_mat, norm_mat, sLODVertexOffset[trunk_LOD], sLODVertexCount[trunk_LOD], sLODIndexCount[trunk_LOD], sLODIndexOffset[trunk_LOD]); } - + + LLMatrix4a trans_matrix = matrix; + trans_matrix.applyTranslation_affine(0.f,0.f,scale*length); + const LLMatrix4a& trans_mat = trans_matrix; + // Recurse to create more branches for (S32 i=0; i < (S32)branches; i++) { - LLMatrix4 trans_mat; - trans_mat.setTranslation(0,0,scale*length); - trans_mat *= matrix; LLQuaternion rot = LLQuaternion(20.f*DEG_TO_RAD, LLVector4(0.f, 0.f, 1.f)) * LLQuaternion(droop*DEG_TO_RAD, LLVector4(0.f, 1.f, 0.f)) * LLQuaternion(((constant_twist + ((i%2==0)?twist:-twist))*i)*DEG_TO_RAD, LLVector4(0.f, 0.f, 1.f)); - - LLMatrix4 rot_mat(rot); - rot_mat *= trans_mat; + + LLMatrix4a rot_mat = trans_mat; + rot_mat.mul(LLQuaternion2(rot)); genBranchPipeline(vertices, normals, tex_coords, indices, index_offset, rot_mat, trunk_LOD, stop_level, depth - 1, 0, scale*mScaleStep, twist, droop, branches, alpha); } // Recurse to continue trunk if (trunk_depth) { - LLMatrix4 trans_mat; - trans_mat.setTranslation(0,0,scale*length); - trans_mat *= matrix; - LLMatrix4 rot_mat(70.5f*DEG_TO_RAD, LLVector4(0,0,1)); - rot_mat *= trans_mat; // rotate a bit around Z when ascending + static const LLMatrix4a srot_mat = gGL.genRot(70.5f,0.f,0.f,1.f); + LLMatrix4a rot_mat; + rot_mat.setMul(trans_mat, srot_mat); // rotate a bit around Z when ascending + genBranchPipeline(vertices, normals, tex_coords, indices, index_offset, rot_mat, trunk_LOD, stop_level, depth, trunk_depth-1, scale*mScaleStep, twist, droop, branches, alpha); } } @@ -1048,15 +1129,12 @@ void LLVOTree::genBranchPipeline(LLStrider& vertices, // Append leaves as two 90 deg crossed quads with leaf textures // { - LLMatrix4 scale_mat; - scale_mat.mMatrix[0][0] = - scale_mat.mMatrix[1][1] = - scale_mat.mMatrix[2][2] = scale*mLeafScale; - - scale_mat *= matrix; + LLMatrix4a scale_mat = matrix; + scale_mat.applyScale_affine(scale*mLeafScale); - glh::matrix4f norm((F32*) scale_mat.mMatrix); - LLMatrix4 norm_mat = LLMatrix4(norm.inverse().transpose().m); + LLMatrix4a norm_mat = scale_mat; + norm_mat.invert(); + norm_mat.transpose(); appendMesh(vertices, normals, tex_coords, indices, index_offset, scale_mat, norm_mat, 0, LEAF_VERTICES, LEAF_INDICES, 0); } @@ -1100,132 +1178,6 @@ void LLVOTree::calcNumVerts(U32& vert_count, U32& index_count, S32 trunk_LOD, S3 } } -U32 LLVOTree::drawBranchPipeline(LLMatrix4& matrix, U16* indicesp, S32 trunk_LOD, S32 stop_level, U16 depth, U16 trunk_depth, F32 scale, F32 twist, F32 droop, F32 branches, F32 alpha) -{ - U32 ret = 0; - // - // Draws a tree by recursing, drawing branches and then a 'leaf' texture. - // If stop_level = -1, simply draws the whole tree as a billboarded texture - // - - static F32 constant_twist; - static F32 width = 0; - - //F32 length = ((scale == 1.f)? mTrunkLength:mBranchLength); - //F32 aspect = ((scale == 1.f)? mTrunkAspect:mBranchAspect); - F32 length = ((trunk_depth || (scale == 1.f))? mTrunkLength:mBranchLength); - F32 aspect = ((trunk_depth || (scale == 1.f))? mTrunkAspect:mBranchAspect); - - constant_twist = 360.f/branches; - - if (!LLPipeline::sReflectionRender && stop_level >= 0) - { - // - // Draw the tree using recursion - // - if (depth > stop_level) - { - { - llassert(sLODIndexCount[trunk_LOD] > 0); - width = scale * length * aspect; - LLMatrix4 scale_mat; - scale_mat.mMatrix[0][0] = width; - scale_mat.mMatrix[1][1] = width; - scale_mat.mMatrix[2][2] = scale*length; - scale_mat *= matrix; - - gGL.loadMatrix((F32*) scale_mat.mMatrix); - gGL.syncMatrices(); - glDrawElements(GL_TRIANGLES, sLODIndexCount[trunk_LOD], GL_UNSIGNED_SHORT, indicesp + sLODIndexOffset[trunk_LOD]); - gPipeline.addTrianglesDrawn(LEAF_INDICES); - stop_glerror(); - ret += sLODIndexCount[trunk_LOD]; - } - - // Recurse to create more branches - for (S32 i=0; i < (S32)branches; i++) - { - LLMatrix4 trans_mat; - trans_mat.setTranslation(0,0,scale*length); - trans_mat *= matrix; - - LLQuaternion rot = - LLQuaternion(20.f*DEG_TO_RAD, LLVector4(0.f, 0.f, 1.f)) * - LLQuaternion(droop*DEG_TO_RAD, LLVector4(0.f, 1.f, 0.f)) * - LLQuaternion(((constant_twist + ((i%2==0)?twist:-twist))*i)*DEG_TO_RAD, LLVector4(0.f, 0.f, 1.f)); - - LLMatrix4 rot_mat(rot); - rot_mat *= trans_mat; - - ret += drawBranchPipeline(rot_mat, indicesp, trunk_LOD, stop_level, depth - 1, 0, scale*mScaleStep, twist, droop, branches, alpha); - } - // Recurse to continue trunk - if (trunk_depth) - { - LLMatrix4 trans_mat; - trans_mat.setTranslation(0,0,scale*length); - trans_mat *= matrix; - - LLMatrix4 rot_mat(70.5f*DEG_TO_RAD, LLVector4(0,0,1)); - rot_mat *= trans_mat; // rotate a bit around Z when ascending - ret += drawBranchPipeline(rot_mat, indicesp, trunk_LOD, stop_level, depth, trunk_depth-1, scale*mScaleStep, twist, droop, branches, alpha); - } - } - else - { - // - // Draw leaves as two 90 deg crossed quads with leaf textures - // - { - LLMatrix4 scale_mat; - scale_mat.mMatrix[0][0] = - scale_mat.mMatrix[1][1] = - scale_mat.mMatrix[2][2] = scale*mLeafScale; - - scale_mat *= matrix; - - - gGL.loadMatrix((F32*) scale_mat.mMatrix); - gGL.syncMatrices(); - glDrawElements(GL_TRIANGLES, LEAF_INDICES, GL_UNSIGNED_SHORT, indicesp); - gPipeline.addTrianglesDrawn(LEAF_INDICES); - stop_glerror(); - ret += LEAF_INDICES; - } - } - } - else - { - // - // Draw the tree as a single billboard texture - // - - LLMatrix4 scale_mat; - scale_mat.mMatrix[0][0] = - scale_mat.mMatrix[1][1] = - scale_mat.mMatrix[2][2] = mBillboardScale*mBillboardRatio; - - scale_mat *= matrix; - - gGL.matrixMode(LLRender::MM_TEXTURE); - gGL.translatef(0.0, -0.5, 0.0); - gGL.matrixMode(LLRender::MM_MODELVIEW); - - gGL.loadMatrix((F32*) scale_mat.mMatrix); - gGL.syncMatrices(); - glDrawElements(GL_TRIANGLES, LEAF_INDICES, GL_UNSIGNED_SHORT, indicesp); - gPipeline.addTrianglesDrawn(LEAF_INDICES); - stop_glerror(); - ret += LEAF_INDICES; - - gGL.matrixMode(LLRender::MM_TEXTURE); - gGL.loadIdentity(); - gGL.matrixMode(LLRender::MM_MODELVIEW); - } - - return ret; -} - void LLVOTree::updateRadius() { if (mDrawable.isNull()) @@ -1253,8 +1205,8 @@ void LLVOTree::updateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax) mDrawable->setPositionGroup(pos); } -BOOL LLVOTree::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, S32 face, BOOL pick_transparent, S32 *face_hitp, - LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal) +BOOL LLVOTree::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, S32 face, BOOL pick_transparent, BOOL pick_rigged, S32 *face_hitp, + LLVector4a* intersection,LLVector2* tex_coord, LLVector4a* normal, LLVector4a* tangent) { @@ -1283,16 +1235,19 @@ BOOL LLVOTree::lineSegmentIntersect(const LLVector3& start, const LLVector3& end LLVector3 pos, norm; - if (linesegment_tetrahedron(start, end, center, size, quat, pos, norm)) + LLVector3 start3(start.getF32ptr()); + LLVector3 end3(end.getF32ptr()); + + if (linesegment_tetrahedron(start3, end3, center, size, quat, pos, norm)) { if (intersection) { - *intersection = pos; + intersection->load3(pos.mV); } if (normal) { - *normal = norm; + normal->load3(norm.mV); } return TRUE; } @@ -1305,8 +1260,8 @@ U32 LLVOTree::getPartitionType() const return LLViewerRegion::PARTITION_TREE; } -LLTreePartition::LLTreePartition() -: LLSpatialPartition(0, FALSE, GL_DYNAMIC_DRAW_ARB) +LLTreePartition::LLTreePartition(LLViewerRegion* regionp) +: LLSpatialPartition(0, FALSE, GL_DYNAMIC_DRAW_ARB, regionp) { mDrawableType = LLPipeline::RENDER_TYPE_TREE; mPartitionType = LLViewerRegion::PARTITION_TREE; @@ -1314,3 +1269,116 @@ LLTreePartition::LLTreePartition() mLODPeriod = 1; } +void LLVOTree::generateSilhouetteVertices(std::vector &vertices, + std::vector &normals, + const LLVector3& obj_cam_vec, + const LLMatrix4a& local_matrix_, + const LLMatrix4a& normal_matrix) +{ + vertices.clear(); + normals.clear(); + + F32 height = mBillboardScale; // *mBillboardRatio * 0.5; + F32 width = height * mTrunkAspect; + + LLMatrix4 local_matrix(local_matrix_.getF32ptr()); + + LLVector3 position1 = LLVector3(-width * 0.5, 0, 0) * local_matrix; + LLVector3 position2 = LLVector3(-width * 0.5, 0, height) * local_matrix; + LLVector3 position3 = LLVector3(width * 0.5, 0, height) * local_matrix; + LLVector3 position4 = LLVector3(width * 0.5, 0, 0) * local_matrix; + + LLVector3 position5 = LLVector3(0, -width * 0.5, 0) * local_matrix; + LLVector3 position6 = LLVector3(0, -width * 0.5, height) * local_matrix; + LLVector3 position7 = LLVector3(0, width * 0.5, height) * local_matrix; + LLVector3 position8 = LLVector3(0, width * 0.5, 0) * local_matrix; + + LLVector3 normal = (position1 - position2) % (position2 - position3); + normal.normalize(); + + vertices.push_back(position1); + normals.push_back(normal); + vertices.push_back(position2); + normals.push_back(normal); + + vertices.push_back(position2); + normals.push_back(normal); + vertices.push_back(position3); + normals.push_back(normal); + + vertices.push_back(position3); + normals.push_back(normal); + vertices.push_back(position4); + normals.push_back(normal); + + vertices.push_back(position4); + normals.push_back(normal); + vertices.push_back(position1); + normals.push_back(normal); + + normal = (position5 - position6) % (position6 - position7); + normal.normalize(); + + vertices.push_back(position5); + normals.push_back(normal); + vertices.push_back(position6); + normals.push_back(normal); + + vertices.push_back(position6); + normals.push_back(normal); + vertices.push_back(position7); + normals.push_back(normal); + + vertices.push_back(position7); + normals.push_back(normal); + vertices.push_back(position8); + normals.push_back(normal); + + vertices.push_back(position8); + normals.push_back(normal); + vertices.push_back(position5); + normals.push_back(normal); +} + +void LLVOTree::generateSilhouette(LLSelectNode* nodep, const LLVector3& view_point) +{ + LLVector3 position; + LLQuaternion rotation; + + if (mDrawable->isActive()) + { + if (mDrawable->isSpatialRoot()) + { + position = LLVector3(); + rotation = LLQuaternion(); + } + else + { + position = mDrawable->getPosition(); + rotation = mDrawable->getRotation(); + } + } + else + { + position = getPosition() + getRegion()->getOriginAgent(); + rotation = getRotation(); + } + + // trees have bizzare scaling rules... because it's cool to make needless exceptions + // PS: the trees are the last remaining tidbit of Philip's code. take a look sometime. + F32 radius = getScale().length() * 0.05f; + LLVector3 scale = LLVector3(1, 1, 1) * radius; + + // compose final matrix + LLMatrix4 local_matrix; + local_matrix.initAll(scale, rotation, position); + LLMatrix4a lmat; + lmat.loadu(local_matrix); + LLMatrix4a nmat; + nmat.setIdentity(); + + generateSilhouetteVertices(nodep->mSilhouetteVertices, nodep->mSilhouetteNormals, + LLVector3(0, 0, 0), lmat, nmat); + + nodep->mSilhouetteExists = TRUE; +} diff --git a/indra/newview/llvotree.h b/indra/newview/llvotree.h index f905030308..54f629c407 100644 --- a/indra/newview/llvotree.h +++ b/indra/newview/llvotree.h @@ -34,11 +34,11 @@ #define LL_LLVOTREE_H #include "llviewerobject.h" -#include "lldarray.h" #include "xform.h" class LLFace; class LLDrawPool; +class LLSelectNode; class LLViewerFetchedTexture; class LLVOTree : public LLViewerObject @@ -76,6 +76,7 @@ class LLVOTree : public LLViewerObject /*virtual*/ BOOL updateGeometry(LLDrawable *drawable); /*virtual*/ void updateSpatialExtents(LLVector4a &min, LLVector4a &max); + void resetVertexBuffers(); virtual U32 getPartitionType() const; void updateRadius(); @@ -84,24 +85,24 @@ class LLVOTree : public LLViewerObject void updateMesh(); - void appendMesh(LLStrider& vertices, - LLStrider& normals, + void appendMesh(LLStrider& vertices, + LLStrider& normals, LLStrider& tex_coords, LLStrider& indices, U16& idx_offset, - LLMatrix4& matrix, - LLMatrix4& norm_mat, + LLMatrix4a& matrix, + LLMatrix4a& norm_mat, S32 vertex_offset, S32 vertex_count, S32 index_count, S32 index_offset); - void genBranchPipeline(LLStrider& vertices, - LLStrider& normals, + void genBranchPipeline(LLStrider& vertices, + LLStrider& normals, LLStrider& tex_coords, LLStrider& indices, U16& index_offset, - LLMatrix4& matrix, + LLMatrix4a& matrix, S32 trunk_LOD, S32 stop_level, U16 depth, @@ -112,18 +113,18 @@ class LLVOTree : public LLViewerObject F32 branches, F32 alpha); - U32 drawBranchPipeline(LLMatrix4& matrix, U16* indicesp, S32 trunk_LOD, S32 stop_level, U16 depth, U16 trunk_depth, F32 scale, F32 twist, F32 droop, F32 branches, F32 alpha); - - - /*virtual*/ BOOL lineSegmentIntersect(const LLVector3& start, const LLVector3& end, + /*virtual*/ BOOL lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, S32 face = -1, // which face to check, -1 = ALL_SIDES BOOL pick_transparent = FALSE, + BOOL pick_rigged = FALSE, S32* face_hit = NULL, // which face was hit - LLVector3* intersection = NULL, // return the intersection point + LLVector4a* intersection = NULL, // return the intersection point LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point - LLVector3* normal = NULL, // return the surface normal at the intersection point - LLVector3* bi_normal = NULL // return the surface bi-normal at the intersection point + LLVector4a* normal = NULL, // return the surface normal at the intersection point + LLVector4a* tangent = NULL // return the surface tangent at the intersection point ); + + void generateSilhouette(LLSelectNode* nodep, const LLVector3& view_point); static S32 sMaxTreeSpecies; @@ -162,6 +163,7 @@ class LLVOTree : public LLViewerObject friend class LLDrawPoolTree; protected: LLVector3 mTrunkBend; // Accumulated wind (used for blowing trees) + LLVector3 mTrunkVel; // LLVector3 mWind; LLPointer mReferenceBuffer; //reference geometry for generating tree mesh @@ -192,6 +194,8 @@ class LLVOTree : public LLViewerObject U32 mFrameCount; + std::vector > mDrawList; + typedef std::map SpeciesMap; static SpeciesMap sSpeciesTable; @@ -201,6 +205,13 @@ class LLVOTree : public LLViewerObject static S32 sLODVertexCount[4]; static S32 sLODSlices[4]; static F32 sLODAngles[4]; + +private: + void generateSilhouetteVertices(std::vector &vertices, + std::vector &normals, + const LLVector3& view_vec, + const LLMatrix4a& mat, + const LLMatrix4a& norm_mat); }; #endif diff --git a/indra/newview/llvotreenew.h b/indra/newview/llvotreenew.h index 426470101d..b4a2fe67c2 100644 --- a/indra/newview/llvotreenew.h +++ b/indra/newview/llvotreenew.h @@ -34,7 +34,6 @@ #define LL_LLVOTREENEW_H #include "llviewerobject.h" -#include "lldarray.h" #include "xform.h" #include "lltreeparams.h" @@ -140,7 +139,7 @@ class LLVOTreeNew : public LLViewerObject U32 mOffsets[MAX_VARS][MAX_RES]; // offsets for the partial branch pieces // local section frames for this branch LLMatrix4 mFrames[MAX_VARS][(MAX_RES*(MAX_RES + 1))/2]; // (0...n) + (1...n) + ... + (n-1..n) - LLDynamicArray mFaceNormals; + std::vector mFaceNormals; }; diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 947ae0138a..722aaca160 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -40,6 +40,7 @@ #include "llviewercontrol.h" #include "lldir.h" #include "llflexibleobject.h" +#include "llfloaterinspect.h" #include "llfloatertools.h" #include "llmaterialid.h" #include "llmaterialtable.h" @@ -60,6 +61,7 @@ #include "llspatialpartition.h" #include "llhudmanager.h" #include "llflexibleobject.h" +#include "llskinningutil.h" #include "llsky.h" #include "lltexturefetch.h" #include "llvector4a.h" @@ -81,8 +83,11 @@ #include "lldatapacker.h" #include "llviewershadermgr.h" #include "llvoavatar.h" +#include "llcontrolavatar.h" +#include "llvoavatarself.h" #include "llvocache.h" #include "llmaterialmgr.h" +#include "llsculptidsize.h" // [RLVa:KB] - Checked: 2010-04-04 (RLVa-1.2.0d) #include "rlvhandler.h" @@ -92,6 +97,7 @@ const S32 MIN_QUIET_FRAMES_COALESCE = 30; const F32 FORCE_SIMPLE_RENDER_AREA = 512.f; const F32 FORCE_CULL_AREA = 8.f; +U32 JOINT_COUNT_REQUIRED_FOR_FULLRIG = 1; BOOL gAnimateTextures = TRUE; //extern BOOL gHideSelectedObjects; @@ -105,9 +111,9 @@ S32 LLVOVolume::mRenderComplexity_current = 0; LLPointer LLVOVolume::sObjectMediaClient = NULL; LLPointer LLVOVolume::sObjectMediaNavigateClient = NULL; -static LLFastTimer::DeclareTimer FTM_GEN_TRIANGLES("Generate Triangles"); -static LLFastTimer::DeclareTimer FTM_GEN_VOLUME("Generate Volumes"); -static LLFastTimer::DeclareTimer FTM_VOLUME_TEXTURES("Volume Textures"); +static LLTrace::BlockTimerStatHandle FTM_GEN_TRIANGLES("Generate Triangles"); +static LLTrace::BlockTimerStatHandle FTM_GEN_VOLUME("Generate Volumes"); +static LLTrace::BlockTimerStatHandle FTM_VOLUME_TEXTURES("Volume Textures"); // Implementation class of LLMediaDataClientObject. See llmediadataclient.h class LLMediaDataClientObjectImpl : public LLMediaDataClientObject @@ -220,6 +226,9 @@ LLVOVolume::LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *re mFaceMappingChanged = FALSE; mLOD = MIN_LOD; + mLODDistance = 0.0f; + mLODAdjustedDistance = 0.0f; + mLODRadius = 0.0f; mTextureAnimp = NULL; mVolumeChanged = FALSE; mVObjRadius = LLVector3(1,1,0.5f).length(); @@ -230,8 +239,9 @@ LLVOVolume::LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *re mMediaImplList.resize(getNumTEs()); mLastFetchedMediaVersion = -1; - mIndexInTex = 0; + memset(&mIndexInTex, 0, sizeof(S32) * LLRender::NUM_VOLUME_TEXTURE_CHANNELS); mMDCImplCount = 0; + mLastRiggingInfoLOD = -1; } LLVOVolume::~LLVOVolume() @@ -241,6 +251,8 @@ LLVOVolume::~LLVOVolume() delete mVolumeImpl; mVolumeImpl = NULL; + gMeshRepo.unregisterMesh(this); + if(!mMediaImplList.empty()) { for(U32 i = 0 ; i < mMediaImplList.size() ; i++) @@ -253,10 +265,16 @@ LLVOVolume::~LLVOVolume() } } +LLVOVolume* LLVOVolume::asVolume() +{ + return this; +} + void LLVOVolume::markDead() { if (!mDead) { + LLSculptIDSize::instance().rem(getVolume()->getParams().getSculptID()); if(getMDCImplCount() > 0) { LLMediaDataClientObject::ptr_t obj = new LLMediaDataClientObjectImpl(const_cast(this), false); @@ -272,7 +290,12 @@ void LLVOVolume::markDead() if (mSculptTexture.notNull()) { - mSculptTexture->removeVolume(this); + mSculptTexture->removeVolume(LLRender::SCULPT_TEX, this); + } + + if (mLightTexture.notNull()) + { + mLightTexture->removeVolume(LLRender::LIGHT_TEX, this); } } @@ -320,7 +343,7 @@ U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys, U8 sculpt_type = 0; if (isSculpted()) { - LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT); + const LLSculptParams *sculpt_params = getSculptParams(); sculpt_id = sculpt_params->getSculptTexture(); sculpt_type = sculpt_params->getSculptType(); } @@ -340,6 +363,7 @@ U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys, if (!mTextureAnimp) { mTextureAnimp = new LLViewerTextureAnim(this); + mTexAnimMode = 0; } else { @@ -348,7 +372,7 @@ U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys, mTextureAnimp->reset(); } } - mTexAnimMode = 0; + mTextureAnimp->unpackTAMessage(mesgsys, block_num); } else @@ -399,8 +423,8 @@ U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys, BOOL res = LLVolumeMessage::unpackVolumeParams(&volume_params, *dp); if (!res) { - llwarns << "Bogus volume parameters in object " << getID() << llendl; - llwarns << getRegion()->getOriginGlobal() << llendl; + LL_WARNS() << "Bogus volume parameters in object " << getID() << LL_ENDL; + LL_WARNS() << getRegion()->getOriginGlobal() << LL_ENDL; } volume_params.setSculptID(sculpt_id, sculpt_type); @@ -414,14 +438,14 @@ U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys, { // There's something bogus in the data that we're unpacking. dp->dumpBufferToLog(); - llwarns << "Flushing cache files" << llendl; + LL_WARNS() << "Flushing cache files" << LL_ENDL; if(LLVOCache::hasInstance() && getRegion()) { LLVOCache::getInstance()->removeEntry(getRegion()->getHandle()) ; } - llwarns << "Bogus TE data in " << getID() << llendl; + LL_WARNS() << "Bogus TE data in " << getID() << LL_ENDL; } else { @@ -461,6 +485,11 @@ U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys, mFaceMappingChanged = TRUE; mTexAnimMode = 0; } + + if (value & 0x400) + { //particle system (new) + unpackParticleSource(*dp, mOwnerID, false); + } } else { @@ -469,7 +498,7 @@ U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys, { U8 tdpbuffer[1024]; LLDataPackerBinaryBuffer tdp(tdpbuffer, 1024); - mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_TextureEntry, tdpbuffer, 0, block_num); + mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_TextureEntry, tdpbuffer, 0, block_num, 1024); S32 result = unpackTEMessage(tdp); if (result & teDirtyBits) { @@ -557,29 +586,28 @@ void LLVOVolume::animateTextures() if (!facep->mTextureMatrix) { - facep->mTextureMatrix = new LLMatrix4(); + facep->mTextureMatrix = new LLMatrix4a(); } - LLMatrix4& tex_mat = *facep->mTextureMatrix; + LLMatrix4a& tex_mat = *facep->mTextureMatrix; tex_mat.setIdentity(); LLVector3 trans ; { - trans.set(LLVector3(off_s+0.5f, off_t+0.5f, 0.f)); - tex_mat.translate(LLVector3(-0.5f, -0.5f, 0.f)); + trans.set(LLVector3(off_s+0.5f, off_t+0.5f, 0.f)); + tex_mat.setTranslate_affine(LLVector3(-0.5f, -0.5f, 0.f)); } - LLVector3 scale(scale_s, scale_t, 1.f); - LLQuaternion quat; - quat.setQuat(rot, 0, 0, -1.f); + LLVector3 scale(scale_s, scale_t, 1.f); + + tex_mat.setMul(gGL.genRot(rot*RAD_TO_DEG,0.f,0.f,-1.f),tex_mat); //left mul - tex_mat.rotate(quat); + LLMatrix4a scale_mat; + scale_mat.setIdentity(); + scale_mat.applyScale_affine(scale); + tex_mat.setMul(scale_mat, tex_mat); //left mul - LLMatrix4 mat; - mat.initAll(scale, LLQuaternion(), LLVector3()); - tex_mat *= mat; - - tex_mat.translate(trans); - } + tex_mat.translate_affine(trans); + } } else { @@ -669,7 +697,7 @@ BOOL LLVOVolume::isVisible() const void LLVOVolume::updateTextureVirtualSize(bool forced) { - LLFastTimer ftm(FTM_VOLUME_TEXTURES); + LL_RECORD_BLOCK_TIME(FTM_VOLUME_TEXTURES); // Update the pixel area of all faces if(mDrawable.isNull()) @@ -832,9 +860,9 @@ void LLVOVolume::updateTextureVirtualSize(bool forced) if (getLightTextureID().notNull()) { - LLLightImageParams* params = (LLLightImageParams*) getParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE); + const LLLightImageParams* params = getLightImageParams(); LLUUID id = params->getLightTexture(); - mLightTexture = LLViewerTextureManager::getFetchedTexture(id); + mLightTexture = LLViewerTextureManager::getFetchedTexture(id, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_ALM); if (mLightTexture.notNull()) { F32 rad = getLightRadius(); @@ -905,6 +933,12 @@ LLFace* LLVOVolume::addFace(S32 f) { const LLTextureEntry* te = getTE(f); LLViewerTexture* imagep = getTEImage(f); + if (te->getMaterialParams().notNull()) + { + LLViewerTexture* normalp = getTENormalMap(f); + LLViewerTexture* specularp = getTESpecularMap(f); + return mDrawable->addFace(te, imagep, normalp, specularp); + } return mDrawable->addFace(te, imagep); } @@ -953,13 +987,14 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams ¶ms_in, const S32 detail, bo // if it's a mesh if ((volume_params.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH) { //meshes might not have all LODs, get the force detail to best existing LOD - LLUUID mesh_id = volume_params.getSculptID(); - - lod = gMeshRepo.getActualMeshLOD(volume_params, lod); - if (lod == -1) + if (NO_LOD != lod) { - is404 = TRUE; - lod = 0; + lod = gMeshRepo.getActualMeshLOD(volume_params, lod); + if (lod == -1) + { + is404 = TRUE; + lod = 0; + } } } } @@ -971,7 +1006,7 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams ¶ms_in, const S32 detail, bo setParameterEntryInUse(LLNetworkData::PARAMS_FLEXIBLE, TRUE, false); if (!mVolumeImpl) { - LLFlexibleObjectData* data = (LLFlexibleObjectData*)getParameterEntry(LLNetworkData::PARAMS_FLEXIBLE); + LLFlexibleObjectData* data = (LLFlexibleObjectData*)getFlexibleObjectData(); mVolumeImpl = new LLVolumeImplFlexible(this, data); } } @@ -993,7 +1028,7 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams ¶ms_in, const S32 detail, bo if (is404) { - setIcon(LLViewerTextureManager::getFetchedTextureFromFile("inv_item_mesh.tga", TRUE, LLGLTexture::BOOST_UI)); + setIcon(LLViewerTextureManager::getFetchedTextureFromFile("inv_item_mesh.tga", FTT_LOCAL_FILE, TRUE, LLGLTexture::BOOST_UI)); //render prim proxy when mesh loading attempts give up volume_params.setSculptID(LLUUID::null, LL_SCULPT_TYPE_NONE); @@ -1053,13 +1088,19 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams ¶ms_in, const S32 detail, bo { //already cached break; } - volume->genBinormals(i); + volume->genTangents(i); LLFace::cacheFaceInVRAM(face); } } + return TRUE; } + else if (NO_LOD == lod) + { + LLSculptIDSize::instance().resetSizeSum(volume_params.getSculptID()); + } + return FALSE; } @@ -1069,11 +1110,11 @@ void LLVOVolume::updateSculptTexture() if (isSculpted() && !isMesh()) { - LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT); + const LLSculptParams *sculpt_params = getSculptParams(); LLUUID id = sculpt_params->getSculptTexture(); if (id.notNull()) { - mSculptTexture = LLViewerTextureManager::getFetchedTexture(id, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); + mSculptTexture = LLViewerTextureManager::getFetchedTexture(id, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); } } else @@ -1085,20 +1126,44 @@ void LLVOVolume::updateSculptTexture() { if (old_sculpt.notNull()) { - old_sculpt->removeVolume(this); + old_sculpt->removeVolume(LLRender::SCULPT_TEX, this); } if (mSculptTexture.notNull()) { - mSculptTexture->addVolume(this); + mSculptTexture->addVolume(LLRender::SCULPT_TEX, this); } } + +} +void LLVOVolume::updateVisualComplexity() +{ + LLVOAvatar* avatar = getAvatarAncestor(); + if (avatar) + { + avatar->updateVisualComplexity(); + } + LLVOAvatar* rigged_avatar = getAvatar(); + if(rigged_avatar && (rigged_avatar != avatar)) + { + rigged_avatar->updateVisualComplexity(); + } } void LLVOVolume::notifyMeshLoaded() { mSculptChanged = TRUE; gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, TRUE); + + if (getAvatar() && !isAnimatedObject()) + { + getAvatar()->addAttachmentOverridesForObject(this); + } + if (getControlAvatar() && isAnimatedObject()) + { + getControlAvatar()->addAttachmentOverridesForObject(this); + } + updateVisualComplexity(); } // sculpt replaces generate() for sculpted surfaces @@ -1116,7 +1181,13 @@ void LLVOVolume::sculpt() S32 max_discard = mSculptTexture->getMaxDiscardLevel(); if (discard_level > max_discard) - discard_level = max_discard; // clamp to the best we can do + { + discard_level = max_discard; // clamp to the best we can do + } + if(discard_level > MAX_DISCARD_LEVEL) + { + return; //we think data is not ready yet. + } S32 current_discard = getVolume()->getSculptLevel() ; if(current_discard < -2) @@ -1124,9 +1195,9 @@ void LLVOVolume::sculpt() static S32 low_sculpty_discard_warning_count = 100; if (++low_sculpty_discard_warning_count >= 100) { // Log first time, then every 100 afterwards otherwise this can flood the logs - llwarns << "WARNING!!: Current discard for sculpty " << mSculptTexture->getID() + LL_WARNS() << "WARNING!!: Current discard for sculpty " << mSculptTexture->getID() << " at " << current_discard - << " is less than -2." << llendl; + << " is less than -2." << LL_ENDL; low_sculpty_discard_warning_count = 0; } @@ -1138,9 +1209,9 @@ void LLVOVolume::sculpt() static S32 high_sculpty_discard_warning_count = 100; if (++high_sculpty_discard_warning_count >= 100) { // Log first time, then every 100 afterwards otherwise this can flood the logs - llwarns << "WARNING!!: Current discard for sculpty " << mSculptTexture->getID() + LL_WARNS() << "WARNING!!: Current discard for sculpty " << mSculptTexture->getID() << " at " << current_discard - << " is more than than allowed max of " << MAX_DISCARD_LEVEL << llendl; + << " is more than than allowed max of " << MAX_DISCARD_LEVEL << LL_ENDL; high_sculpty_discard_warning_count = 0; } @@ -1167,12 +1238,12 @@ void LLVOVolume::sculpt() sculpt_data = raw_image->getData(); } - getVolume()->sculpt(sculpt_width, sculpt_height, sculpt_components, sculpt_data, discard_level); + getVolume()->sculpt(sculpt_width, sculpt_height, sculpt_components, sculpt_data, discard_level, mSculptTexture->isMissingAsset()); //notify rebuild any other VOVolumes that reference this sculpty volume - for (S32 i = 0; i < mSculptTexture->getNumVolumes(); ++i) + for (S32 i = 0; i < mSculptTexture->getNumVolumes(LLRender::SCULPT_TEX); ++i) { - LLVOVolume* volume = (*(mSculptTexture->getVolumeList()))[i]; + LLVOVolume* volume = (*(mSculptTexture->getVolumeList(LLRender::SCULPT_TEX)))[i]; if (volume != this && volume->getVolume() == getVolume()) { gPipeline.markRebuild(volume->mDrawable, LLDrawable::REBUILD_GEOMETRY, FALSE); @@ -1181,18 +1252,18 @@ void LLVOVolume::sculpt() } } -S32 LLVOVolume::computeLODDetail(F32 distance, F32 radius) +S32 LLVOVolume::computeLODDetail(F32 distance, F32 radius, F32 lod_factor) { S32 cur_detail; if (LLPipeline::sDynamicLOD) { // We've got LOD in the profile, and in the twist. Use radius. - F32 tan_angle = (LLVOVolume::sLODFactor*radius)/distance; - cur_detail = LLVolumeLODGroup::getDetailFromTan(llround(tan_angle, 0.01f)); + F32 tan_angle = (lod_factor*radius)/distance; + cur_detail = LLVolumeLODGroup::getDetailFromTan(ll_round(tan_angle, 0.01f)); } else { - cur_detail = llclamp((S32) (sqrtf(radius)*LLVOVolume::sLODFactor*4.f), 0, 3); + cur_detail = llclamp((S32) (sqrtf(radius)*lod_factor*4.f), 0, 3); } return cur_detail; } @@ -1208,20 +1279,61 @@ BOOL LLVOVolume::calcLOD() F32 radius; F32 distance; + F32 lod_factor = LLVOVolume::sLODFactor; if (mDrawable->isState(LLDrawable::RIGGED) && getAvatar() && getAvatar()->mDrawable) { LLVOAvatar* avatar = getAvatar(); + // Not sure how this can really happen, but alas it does. Better exit here than crashing. + if( !avatar || !avatar->mDrawable ) + { + return FALSE; + } + distance = avatar->mDrawable->mDistanceWRTCamera; - radius = avatar->getBinRadius(); + + + if (avatar->isControlAvatar()) + { + // MAINT-7926 Handle volumes in an animated object as a special case + const LLVector3* box = avatar->getLastAnimExtents(); + LLVector3 diag = box[1] - box[0]; + radius = diag.magVec() * 0.5f; + LL_DEBUGS("DynamicBox") << avatar->getFullname() << " diag " << diag << " radius " << radius << LL_ENDL; + } + else + { + // Volume in a rigged mesh attached to a regular avatar. + // Note this isn't really a radius, so distance calcs are off by factor of 2 + //radius = avatar->getBinRadius(); + // SL-937: add dynamic box handling for rigged mesh on regular avatars. + const LLVector3* box = avatar->getLastAnimExtents(); + LLVector3 diag = box[1] - box[0]; + radius = diag.magVec(); // preserve old BinRadius behavior - 2x off + LL_DEBUGS("DynamicBox") << avatar->getFullname() << " diag " << diag << " radius " << radius << LL_ENDL; + } + if (distance <= 0.f || radius <= 0.f) + { + LL_DEBUGS("DynamicBox","CalcLOD") << "avatar distance/radius uninitialized, skipping" << LL_ENDL; + return FALSE; + } } else { distance = mDrawable->mDistanceWRTCamera; - radius = getVolume()->mLODScaleBias.scaledVec(getScale()).length(); + radius = getVolume() ? getVolume()->mLODScaleBias.scaledVec(getScale()).length() : getScale().length(); + if (distance <= 0.f || radius <= 0.f) + { + LL_DEBUGS("DynamicBox","CalcLOD") << "non-avatar distance/radius uninitialized, skipping" << LL_ENDL; + return FALSE; + } } + //hold onto unmodified distance for debugging + //F32 debug_distance = distance; + mLODDistance = distance; + mLODRadius = radius; distance *= sDistanceFactor; F32 rampDist = LLVOVolume::sLODFactor * 2; @@ -1235,28 +1347,34 @@ BOOL LLVOVolume::calcLOD() // DON'T Compensate for field of view changing on FOV zoom. distance *= F_PI/3.f; - cur_detail = computeLODDetail(llround(distance, 0.01f), - llround(radius, 0.01f)); + + mLODAdjustedDistance = distance; + + if (isHUDAttachment()) + { + // HUDs always show at highest detail + cur_detail = 3; + } + else + { + cur_detail = computeLODDetail(ll_round(distance, 0.01f), ll_round(radius, 0.01f), lod_factor); + } if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_LOD_INFO) && mDrawable->getFace(0)) { - //setDebugText(llformat("%.2f:%.2f, %d", debug_distance, radius, cur_detail)); - - setDebugText(llformat("%d", mDrawable->getFace(0)->getTextureIndex())); + // This is a debug display for LODs. Please don't put the texture index here. + setDebugText(llformat("%d", cur_detail)); } if (cur_detail != mLOD) { - mAppAngle = llround((F32) atan2( mDrawable->getRadius(), mDrawable->mDistanceWRTCamera) * RAD_TO_DEG, 0.01f); + mAppAngle = ll_round((F32) atan2( mDrawable->getRadius(), mDrawable->mDistanceWRTCamera) * RAD_TO_DEG, 0.01f); mLOD = cur_detail; return TRUE; } - else - { - return FALSE; - } + return FALSE; } BOOL LLVOVolume::updateLOD() @@ -1266,7 +1384,16 @@ BOOL LLVOVolume::updateLOD() return FALSE; } - BOOL lod_changed = calcLOD(); + BOOL lod_changed = FALSE; + + if (!LLSculptIDSize::instance().isUnloaded(getVolume()->getParams().getSculptID())) + { + lod_changed = calcLOD(); + } + else + { + return FALSE; + } if (lod_changed) { @@ -1316,7 +1443,8 @@ BOOL LLVOVolume::setDrawableParent(LLDrawable* parentp) void LLVOVolume::updateFaceFlags() { - for (S32 i = 0; i < getVolume()->getNumFaces(); i++) + // There's no guarantee that getVolume()->getNumFaces() == mDrawable->getNumFaces() + for (S32 i = 0; i < getVolume()->getNumFaces() && i < mDrawable->getNumFaces(); i++) { LLFace *face = mDrawable->getFace(i); if (face) @@ -1346,7 +1474,8 @@ void LLVOVolume::updateFaceFlags() BOOL LLVOVolume::setParent(LLViewerObject* parent) { BOOL ret = FALSE ; - if (parent != getParent()) + LLViewerObject *old_parent = (LLViewerObject*) getParent(); + if (parent != old_parent) { ret = LLViewerObject::setParent(parent); if (ret && mDrawable) @@ -1354,6 +1483,7 @@ BOOL LLVOVolume::setParent(LLViewerObject* parent) gPipeline.markMoved(mDrawable); gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE); } + onReparent(old_parent, parent); } return ret ; @@ -1379,6 +1509,11 @@ void LLVOVolume::regenFaces() facep->setTEOffset(i); facep->setTexture(getTEImage(i)); + if (facep->getTextureEntry()->getMaterialParams().notNull()) + { + facep->setNormalMap(getTENormalMap(i)); + facep->setSpecularMap(getTESpecularMap(i)); + } facep->setViewerObject(this); // If the face had media on it, this will have broken the link between the LLViewerMediaTexture and the face. @@ -1404,7 +1539,7 @@ void LLVOVolume::regenFaces() BOOL LLVOVolume::genBBoxes(BOOL force_global) { - BOOL res = TRUE; + bool res = true; LLVector4a min,max; @@ -1413,30 +1548,71 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global) BOOL rebuild = mDrawable->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION | LLDrawable::REBUILD_RIGGED); - // bool rigged = false; + if (getRiggedVolume()) + { + // MAINT-8264 - better to use the existing call in calling + // func LLVOVolume::updateGeometry() if we can detect when + // updates needed, set REBUILD_RIGGED accordingly. + + // Without the flag, this will remove unused rigged volumes, which we are not currently very aggressive about. + updateRiggedVolume(); + } + LLVolume* volume = mRiggedVolume; if (!volume) { volume = getVolume(); } - for (S32 i = 0; i < getVolume()->getNumVolumeFaces(); i++) + bool any_valid_boxes = false; + + static LLCachedControl sh_override_rigged_bounds("SHOverrideRiggedBounds", false); + if (sh_override_rigged_bounds && isAttachment() && (mDrawable->isState(LLDrawable::RIGGED) || isRiggedMesh())) + { + LLVOAvatar* root = getAvatar(); + if (root) + { + any_valid_boxes = true; + static const LLVector3 PAD_SIZE(.1f, .1f, .1f); + LLVector3 minpos = -PAD_SIZE; + LLVector3 maxpos = PAD_SIZE; + min.load3(minpos.mV,1.f); + max.load3(maxpos.mV, 1.f); + } + } + if (!any_valid_boxes) { +// There's no guarantee that getVolume()->getNumFaces() == mDrawable->getNumFaces() + for (S32 i = 0; + i < getVolume()->getNumVolumeFaces() && i < mDrawable->getNumFaces() && i < getNumTEs(); + i++) { LLFace *face = mDrawable->getFace(i); if (!face) { continue; } - res &= face->genVolumeBBoxes(*volume, i, - mRelativeXform, mRelativeXformInvTrans, + bool face_res = face->genVolumeBBoxes(*volume, i, + mRelativeXform, (mVolumeImpl && mVolumeImpl->isVolumeGlobal()) || force_global); + // Singu note: Don't let one bad face to ruin the whole volume. &= bad. |= good. + res &= face_res; + // MAINT-8264 - ignore bboxes of ill-formed faces. + if (!face_res) + { + continue; + } if (rebuild) { - if (i == 0) + if (getRiggedVolume()) + { + LL_DEBUGS("RiggedBox") << "rebuilding box, face " << i << " extents " << face->mExtents[0] << ", " << face->mExtents[1] << LL_ENDL; + } + if (!any_valid_boxes) { min = face->mExtents[0]; max = face->mExtents[1]; + any_valid_boxes = true; } else { @@ -1445,18 +1621,30 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global) } } } - - if (rebuild) + } + + if (any_valid_boxes) + { + if (rebuild) + { + if (getRiggedVolume()) + { + LL_DEBUGS("RiggedBox") << "rebuilding got extents " << min << ", " << max << LL_ENDL; + } + mDrawable->setSpatialExtents(min, max); + min.add(max); + min.mul(0.5f); + mDrawable->setPositionGroup(min); + } + + updateRadius(); + mDrawable->movePartition(); + } + else { - mDrawable->setSpatialExtents(min,max); - min.add(max); - min.mul(0.5f); - mDrawable->setPositionGroup(min); + LL_DEBUGS("RiggedBox") << "genBBoxes failed to find any valid face boxes" << LL_ENDL; } - updateRadius(); - mDrawable->movePartition(); - return res; } @@ -1482,109 +1670,134 @@ void LLVOVolume::updateRelativeXform(bool force_identity) { //rigged volume (which is in agent space) is used for generating bounding boxes etc //inverse of render matrix should go to partition space mRelativeXform = getRenderMatrix(); - - F32* dst = (F32*) mRelativeXformInvTrans.mMatrix; - F32* src = (F32*) mRelativeXform.mMatrix; - dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; - dst[3] = src[4]; dst[4] = src[5]; dst[5] = src[6]; - dst[6] = src[8]; dst[7] = src[9]; dst[8] = src[10]; - + mRelativeXformInvTrans = mRelativeXform; mRelativeXform.invert(); mRelativeXformInvTrans.transpose(); } else if (drawable->isActive() || force_identity) { // setup relative transforms - LLQuaternion delta_rot; - LLVector3 delta_pos, delta_scale; - - //matrix from local space to parent relative/global space - bool use_identity = force_identity || drawable->isSpatialRoot(); - delta_rot = use_identity ? LLQuaternion() : mDrawable->getRotation(); - delta_pos = use_identity ? LLVector3(0,0,0) : mDrawable->getPosition(); - delta_scale = mDrawable->getScale(); - // Vertex transform (4x4) - LLVector3 x_axis = LLVector3(delta_scale.mV[VX], 0.f, 0.f) * delta_rot; - LLVector3 y_axis = LLVector3(0.f, delta_scale.mV[VY], 0.f) * delta_rot; - LLVector3 z_axis = LLVector3(0.f, 0.f, delta_scale.mV[VZ]) * delta_rot; - - mRelativeXform.initRows(LLVector4(x_axis, 0.f), - LLVector4(y_axis, 0.f), - LLVector4(z_axis, 0.f), - LLVector4(delta_pos, 1.f)); + bool use_identity = force_identity || drawable->isSpatialRoot(); - - // compute inverse transpose for normals - // mRelativeXformInvTrans.setRows(x_axis, y_axis, z_axis); - // mRelativeXformInvTrans.invert(); - // mRelativeXformInvTrans.setRows(x_axis, y_axis, z_axis); - // grumble - invert is NOT a matrix invert, so we do it by hand: - - LLMatrix3 rot_inverse = LLMatrix3(~delta_rot); - - LLMatrix3 scale_inverse; - scale_inverse.setRows(LLVector3(1.0, 0.0, 0.0) / delta_scale.mV[VX], - LLVector3(0.0, 1.0, 0.0) / delta_scale.mV[VY], - LLVector3(0.0, 0.0, 1.0) / delta_scale.mV[VZ]); - - - mRelativeXformInvTrans = rot_inverse * scale_inverse; + if(use_identity) + { + mRelativeXform.setIdentity(); + mRelativeXform.applyScale_affine(mDrawable->getScale()); + } + else + { + mRelativeXform = LLQuaternion2(mDrawable->getRotation()); + mRelativeXform.applyScale_affine(mDrawable->getScale()); + mRelativeXform.setTranslate_affine(mDrawable->getPosition()); + } + mRelativeXformInvTrans = mRelativeXform; + mRelativeXformInvTrans.invert(); mRelativeXformInvTrans.transpose(); } else { - LLVector3 pos = getPosition(); - LLVector3 scale = getScale(); - LLQuaternion rot = getRotation(); - + LLVector4a pos; + pos.load3(getPosition().mV); + LLQuaternion2 rot(getRotation()); if (mParent) { - pos *= mParent->getRotation(); - pos += mParent->getPosition(); - rot *= mParent->getRotation(); + LLMatrix4a lrot = LLQuaternion2(mParent->getRotation()); + lrot.rotate(pos,pos); + LLVector4a lpos; + lpos.load3(mParent->getPosition().mV); + pos.add(lpos); + rot.mul(LLQuaternion2(mParent->getRotation())); } - - //LLViewerRegion* region = getRegion(); - //pos += region->getOriginAgent(); - - LLVector3 x_axis = LLVector3(scale.mV[VX], 0.f, 0.f) * rot; - LLVector3 y_axis = LLVector3(0.f, scale.mV[VY], 0.f) * rot; - LLVector3 z_axis = LLVector3(0.f, 0.f, scale.mV[VZ]) * rot; - - mRelativeXform.initRows(LLVector4(x_axis, 0.f), - LLVector4(y_axis, 0.f), - LLVector4(z_axis, 0.f), - LLVector4(pos, 1.f)); - - // compute inverse transpose for normals - LLMatrix3 rot_inverse = LLMatrix3(~rot); - - LLMatrix3 scale_inverse; - scale_inverse.setRows(LLVector3(1.0, 0.0, 0.0) / scale.mV[VX], - LLVector3(0.0, 1.0, 0.0) / scale.mV[VY], - LLVector3(0.0, 0.0, 1.0) / scale.mV[VZ]); - - - mRelativeXformInvTrans = rot_inverse * scale_inverse; + mRelativeXform = rot; + mRelativeXform.applyScale_affine(getScale()); + mRelativeXform.setTranslate_affine(LLVector3(pos.getF32ptr())); + + mRelativeXformInvTrans = mRelativeXform; + mRelativeXformInvTrans.invert(); mRelativeXformInvTrans.transpose(); } } -static LLFastTimer::DeclareTimer FTM_GEN_FLEX("Generate Flexies"); -static LLFastTimer::DeclareTimer FTM_UPDATE_PRIMITIVES("Update Primitives"); -static LLFastTimer::DeclareTimer FTM_UPDATE_RIGGED_VOLUME("Update Rigged"); +static LLTrace::BlockTimerStatHandle FTM_GEN_FLEX("Generate Flexies"); +static LLTrace::BlockTimerStatHandle FTM_UPDATE_PRIMITIVES("Update Primitives"); +static LLTrace::BlockTimerStatHandle FTM_UPDATE_RIGGED_VOLUME("Update Rigged"); + +bool LLVOVolume::lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled) +{ + bool regen_faces = false; + + LLVolume *old_volumep, *new_volumep; + F32 old_lod, new_lod; + S32 old_num_faces, new_num_faces ; + + old_volumep = getVolume(); + old_lod = old_volumep->getDetail(); + old_num_faces = old_volumep->getNumFaces() ; + old_volumep = NULL ; + + { + LL_RECORD_BLOCK_TIME(FTM_GEN_VOLUME); + const LLVolumeParams &volume_params = getVolume()->getParams(); + setVolume(volume_params, 0); + } + + new_volumep = getVolume(); + new_lod = new_volumep->getDetail(); + new_num_faces = new_volumep->getNumFaces() ; + new_volumep = NULL ; + + if ((new_lod != old_lod) || mSculptChanged) + { + if (mDrawable->isState(LLDrawable::RIGGED)) + { + updateVisualComplexity(); + } + + compiled = TRUE; + sNumLODChanges += new_num_faces ; + + if((S32)getNumTEs() != getVolume()->getNumFaces()) + { + setNumTEs(getVolume()->getNumFaces()); //mesh loading may change number of faces. + } + + drawable->setState(LLDrawable::REBUILD_VOLUME); // for face->genVolumeTriangles() + + { + LL_RECORD_BLOCK_TIME(FTM_GEN_TRIANGLES); + regen_faces = new_num_faces != old_num_faces || mNumFaces != (S32)getNumTEs(); + if (regen_faces) + { + regenFaces(); + } + + if (mSculptChanged) + { //changes in sculpt maps can thrash an object bounding box without + //triggering a spatial group bounding box update -- force spatial group + //to update bounding boxes + LLSpatialGroup* group = mDrawable->getSpatialGroup(); + if (group) + { + group->unbound(); + } + } + } + } + + return regen_faces; +} BOOL LLVOVolume::updateGeometry(LLDrawable *drawable) { - LLFastTimer t(FTM_UPDATE_PRIMITIVES); + LL_RECORD_BLOCK_TIME(FTM_UPDATE_PRIMITIVES); if (mDrawable->isState(LLDrawable::REBUILD_RIGGED)) { { - LLFastTimer t(FTM_UPDATE_RIGGED_VOLUME); + LL_RECORD_BLOCK_TIME(FTM_UPDATE_RIGGED_VOLUME); updateRiggedVolume(); } genBBoxes(FALSE); @@ -1595,7 +1808,7 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable) { BOOL res; { - LLFastTimer t(FTM_GEN_FLEX); + LL_RECORD_BLOCK_TIME(FTM_GEN_FLEX); res = mVolumeImpl->doUpdateGeometry(drawable); } updateFaceFlags(); @@ -1621,85 +1834,45 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable) { dirtySpatialGroup(drawable->isState(LLDrawable::IN_REBUILD_Q1)); - compiled = TRUE; + bool was_regen_faces = false; if (mVolumeChanged) { - LLFastTimer ftm(FTM_GEN_VOLUME); - LLVolumeParams volume_params = getVolume()->getParams(); - setVolume(volume_params, 0); + was_regen_faces = lodOrSculptChanged(drawable, compiled); drawable->setState(LLDrawable::REBUILD_VOLUME); } - + else if (mSculptChanged || mLODChanged) { - LLFastTimer t(FTM_GEN_TRIANGLES); + compiled = TRUE; + was_regen_faces = lodOrSculptChanged(drawable, compiled); + } + + if (!was_regen_faces) { + LL_RECORD_BLOCK_TIME(FTM_GEN_TRIANGLES); regenFaces(); - genBBoxes(FALSE); } + + genBBoxes(FALSE); } - else if ((mLODChanged) || (mSculptChanged)) + else if (mLODChanged || mSculptChanged) { dirtySpatialGroup(drawable->isState(LLDrawable::IN_REBUILD_Q1)); - - LLVolume *old_volumep, *new_volumep; - F32 old_lod, new_lod; - S32 old_num_faces, new_num_faces ; - - old_volumep = getVolume(); - old_lod = old_volumep->getDetail(); - old_num_faces = old_volumep->getNumFaces() ; - old_volumep = NULL ; - + compiled = TRUE; + lodOrSculptChanged(drawable, compiled); + + if(drawable->isState(LLDrawable::REBUILD_RIGGED | LLDrawable::RIGGED)) { - LLFastTimer ftm(FTM_GEN_VOLUME); - LLVolumeParams volume_params = getVolume()->getParams(); - setVolume(volume_params, 0); + updateRiggedVolume(false); } + genBBoxes(FALSE); - new_volumep = getVolume(); - new_lod = new_volumep->getDetail(); - new_num_faces = new_volumep->getNumFaces() ; - new_volumep = NULL ; - - if ((new_lod != old_lod) || mSculptChanged) - { - compiled = TRUE; - sNumLODChanges += new_num_faces ; - - if((S32)getNumTEs() != getVolume()->getNumFaces()) - { - setNumTEs(getVolume()->getNumFaces()); //mesh loading may change number of faces. - } - - drawable->setState(LLDrawable::REBUILD_VOLUME); // for face->genVolumeTriangles() - - { - LLFastTimer t(FTM_GEN_TRIANGLES); - if (new_num_faces != old_num_faces || mNumFaces != (S32)getNumTEs()) - { - regenFaces(); - } - genBBoxes(FALSE); - - if (mSculptChanged) - { //changes in sculpt maps can thrash an object bounding box without - //triggering a spatial group bounding box update -- force spatial group - //to update bounding boxes - LLSpatialGroup* group = mDrawable->getSpatialGroup(); - if (group) - { - group->unbound(); - } - } - } - } } // it has its own drawable (it's moved) or it has changed UVs or it has changed xforms from global<->local else { compiled = TRUE; // All it did was move or we changed the texture coordinate offset - LLFastTimer t(FTM_GEN_TRIANGLES); + LL_RECORD_BLOCK_TIME(FTM_GEN_TRIANGLES); genBBoxes(FALSE); } @@ -1710,7 +1883,7 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable) { LLPipeline::sCompiles++; } - + mVolumeChanged = FALSE; mLODChanged = FALSE; mSculptChanged = FALSE; @@ -1721,6 +1894,11 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable) void LLVOVolume::updateFaceSize(S32 idx) { + if( mDrawable->getNumFaces() <= idx ) + { + return; + } + LLFace* facep = mDrawable->getFace(idx); if (facep) { @@ -1770,7 +1948,7 @@ void LLVOVolume::setNumTEs(const U8 num_tes) } else if(old_num_tes > num_tes && mMediaImplList.size() > num_tes) //old faces removed { - U8 end = mMediaImplList.size() ; + size_t end = mMediaImplList.size() ; for(U8 i = num_tes; i < end ; i++) { removeMediaImpl(i) ; @@ -1832,7 +2010,7 @@ S32 LLVOVolume::setTEColor(const U8 te, const LLColor4& color) const LLTextureEntry *tep = getTE(te); if (!tep) { - llwarns << "No texture entry for te " << (S32)te << ", object " << mID << llendl; + LL_WARNS("MaterialTEs") << "No texture entry for te " << (S32)te << ", object " << mID << LL_ENDL; } else if (color != tep->getColor()) { @@ -1984,26 +2162,259 @@ S32 LLVOVolume::setTEMaterialID(const U8 te, const LLMaterialID& pMaterialID) return res; } -S32 LLVOVolume::setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams) -{ - S32 res = LLViewerObject::setTEMaterialParams(te, pMaterialParams); - LL_DEBUGS("MaterialTEs") << "te " << (S32)te << " material " << ((pMaterialParams) ? pMaterialParams->asLLSD() : LLSD("null")) << " res " << res - << ( LLSelectMgr::getInstance()->getSelection()->contains(const_cast(this), te) ? " selected" : " not selected" ) - << LL_ENDL; - setChanged(ALL_CHANGED); - if (!mDrawable.isNull()) - { - gPipeline.markTextured(mDrawable); - gPipeline.markRebuild(mDrawable,LLDrawable::REBUILD_ALL); - } - mFaceMappingChanged = TRUE; - return TEM_CHANGE_TEXTURE; -} +bool LLVOVolume::notifyAboutCreatingTexture(LLViewerTexture *texture) +{ //Ok, here we have confirmation about texture creation, check our wait-list + //and make changes, or return false -S32 LLVOVolume::setTEScale(const U8 te, const F32 s, const F32 t) -{ - S32 res = LLViewerObject::setTEScale(te, s, t); - if (res) + std::pair range = mWaitingTextureInfo.equal_range(texture->getID()); + + typedef std::map map_te_material; + map_te_material new_material; + + for(mmap_UUID_MAP_t::iterator range_it = range.first; range_it != range.second; ++range_it) + { + LLMaterialPtr cur_material = getTEMaterialParams(range_it->second.te); + + //here we just interesting in DIFFUSE_MAP only! + if(cur_material.notNull() && LLRender::DIFFUSE_MAP == range_it->second.map && GL_RGBA != texture->getPrimaryFormat()) + { //ok let's check the diffuse mode + switch(cur_material->getDiffuseAlphaMode()) + { + case LLMaterial::DIFFUSE_ALPHA_MODE_BLEND: + case LLMaterial::DIFFUSE_ALPHA_MODE_EMISSIVE: + case LLMaterial::DIFFUSE_ALPHA_MODE_MASK: + { //uups... we have non 32 bit texture with LLMaterial::DIFFUSE_ALPHA_MODE_* => LLMaterial::DIFFUSE_ALPHA_MODE_NONE + + LLMaterialPtr mat = NULL; + map_te_material::iterator it = new_material.find(range_it->second.te); + if(new_material.end() == it) { + mat = new LLMaterial(cur_material->asLLSD()); + new_material.insert(map_te_material::value_type(range_it->second.te, mat)); + } else { + mat = it->second; + } + + mat->setDiffuseAlphaMode(LLMaterial::DIFFUSE_ALPHA_MODE_NONE); + + } break; + } //switch + } //if + } //for + + //setup new materials + for(map_te_material::const_iterator it = new_material.begin(), end = new_material.end(); it != end; ++it) + { + LLMaterialMgr::getInstance()->put(getID(), it->first, *it->second); + LLViewerObject::setTEMaterialParams(it->first, it->second); + } + + //clear wait-list + mWaitingTextureInfo.erase(range.first, range.second); + + return 0 != new_material.size(); +} + +bool LLVOVolume::notifyAboutMissingAsset(LLViewerTexture *texture) +{ //Ok, here if we wait information about texture and it's missing + //then depending from the texture map (diffuse, normal, or specular) + //make changes in material and confirm it. If not return false. + std::pair range = mWaitingTextureInfo.equal_range(texture->getID()); + if(range.first == range.second) return false; + + typedef std::map map_te_material; + map_te_material new_material; + + for(mmap_UUID_MAP_t::iterator range_it = range.first; range_it != range.second; ++range_it) + { + LLMaterialPtr cur_material = getTEMaterialParams(range_it->second.te); + if (cur_material.isNull()) + continue; + + switch(range_it->second.map) + { + case LLRender::DIFFUSE_MAP: + { + if(LLMaterial::DIFFUSE_ALPHA_MODE_NONE != cur_material->getDiffuseAlphaMode()) + { //missing texture + !LLMaterial::DIFFUSE_ALPHA_MODE_NONE => LLMaterial::DIFFUSE_ALPHA_MODE_NONE + LLMaterialPtr mat = NULL; + map_te_material::iterator it = new_material.find(range_it->second.te); + if(new_material.end() == it) { + mat = new LLMaterial(cur_material->asLLSD()); + new_material.insert(map_te_material::value_type(range_it->second.te, mat)); + } else { + mat = it->second; + } + + mat->setDiffuseAlphaMode(LLMaterial::DIFFUSE_ALPHA_MODE_NONE); + } + } break; + case LLRender::NORMAL_MAP: + { //missing texture => reset material texture id + LLMaterialPtr mat = NULL; + map_te_material::iterator it = new_material.find(range_it->second.te); + if(new_material.end() == it) { + mat = new LLMaterial(cur_material->asLLSD()); + new_material.insert(map_te_material::value_type(range_it->second.te, mat)); + } else { + mat = it->second; + } + + mat->setNormalID(LLUUID::null); + } break; + case LLRender::SPECULAR_MAP: + { //missing texture => reset material texture id + LLMaterialPtr mat = NULL; + map_te_material::iterator it = new_material.find(range_it->second.te); + if(new_material.end() == it) { + mat = new LLMaterial(cur_material->asLLSD()); + new_material.insert(map_te_material::value_type(range_it->second.te, mat)); + } else { + mat = it->second; + } + + mat->setSpecularID(LLUUID::null); + } break; + case LLRender::NUM_TEXTURE_CHANNELS: + //nothing to do, make compiler happy + break; + } //switch + } //for + + //setup new materials + for(map_te_material::const_iterator it = new_material.begin(), end = new_material.end(); it != end; ++it) + { + LLMaterialMgr::getInstance()->setLocalMaterial(getRegion()->getRegionID(), it->second); + LLViewerObject::setTEMaterialParams(it->first, it->second); + } + + //clear wait-list + mWaitingTextureInfo.erase(range.first, range.second); + + return 0 != new_material.size(); +} + +S32 LLVOVolume::setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams) +{ + LLMaterialPtr pMaterial = const_cast(pMaterialParams); + + if(pMaterialParams) + { //check all of them according to material settings + + LLViewerTexture *img_diffuse = getTEImage(te); + LLViewerTexture *img_normal = getTENormalMap(te); + LLViewerTexture *img_specular = getTESpecularMap(te); + + llassert(NULL != img_diffuse); + + LLMaterialPtr new_material = NULL; + + //diffuse + if(NULL != img_diffuse) + { //guard + if(0 == img_diffuse->getPrimaryFormat() && !img_diffuse->isMissingAsset()) + { //ok here we don't have information about texture, let's belief and leave material settings + //but we remember this case + mWaitingTextureInfo.insert(mmap_UUID_MAP_t::value_type(img_diffuse->getID(), material_info(LLRender::DIFFUSE_MAP, te))); + } + else + { + bool bSetDiffuseNone = false; + if(img_diffuse->isMissingAsset()) + { + bSetDiffuseNone = true; + } + else + { + switch(pMaterialParams->getDiffuseAlphaMode()) + { + case LLMaterial::DIFFUSE_ALPHA_MODE_BLEND: + case LLMaterial::DIFFUSE_ALPHA_MODE_EMISSIVE: + case LLMaterial::DIFFUSE_ALPHA_MODE_MASK: + { //all of them modes available only for 32 bit textures + LLTextureEntry* tex_entry = getTE(te); + bool bIsBakedImageId = false; + if (tex_entry && LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::isBakedImageId(tex_entry->getID())) + { + bIsBakedImageId = true; + } + if (GL_RGBA != img_diffuse->getPrimaryFormat() && !bIsBakedImageId) + { + bSetDiffuseNone = true; + } + } break; + } + } //else + + + if(bSetDiffuseNone) + { //upps... we should substitute this material with LLMaterial::DIFFUSE_ALPHA_MODE_NONE + new_material = new LLMaterial(pMaterialParams->asLLSD()); + new_material->setDiffuseAlphaMode(LLMaterial::DIFFUSE_ALPHA_MODE_NONE); + } + } + } + + //normal + if(LLUUID::null != pMaterialParams->getNormalID()) + { + if(img_normal && img_normal->isMissingAsset() && img_normal->getID() == pMaterialParams->getNormalID()) + { + if(!new_material) { + new_material = new LLMaterial(pMaterialParams->asLLSD()); + } + new_material->setNormalID(LLUUID::null); + } + else if(NULL == img_normal || 0 == img_normal->getPrimaryFormat()) + { //ok here we don't have information about texture, let's belief and leave material settings + //but we remember this case + mWaitingTextureInfo.insert(mmap_UUID_MAP_t::value_type(pMaterialParams->getNormalID(), material_info(LLRender::NORMAL_MAP,te))); + } + + } + + + //specular + if(LLUUID::null != pMaterialParams->getSpecularID()) + { + if(img_specular && img_specular->isMissingAsset() && img_specular->getID() == pMaterialParams->getSpecularID()) + { + if(!new_material) { + new_material = new LLMaterial(pMaterialParams->asLLSD()); + } + new_material->setSpecularID(LLUUID::null); + } + else if(NULL == img_specular || 0 == img_specular->getPrimaryFormat()) + { //ok here we don't have information about texture, let's belief and leave material settings + //but we remember this case + mWaitingTextureInfo.insert(mmap_UUID_MAP_t::value_type(pMaterialParams->getSpecularID(), material_info(LLRender::SPECULAR_MAP, te))); + } + } + + if(new_material) { + pMaterial = new_material; + LLMaterialMgr::getInstance()->setLocalMaterial(getRegion()->getRegionID(), pMaterial); + } + } + + S32 res = LLViewerObject::setTEMaterialParams(te, pMaterial); + + LL_DEBUGS("MaterialTEs") << "te " << (S32)te << " material " << ((pMaterial) ? pMaterial->asLLSD() : LLSD("null")) << " res " << res + << ( LLSelectMgr::getInstance()->getSelection()->contains(const_cast(this), te) ? " selected" : " not selected" ) + << LL_ENDL; + setChanged(ALL_CHANGED); + if (!mDrawable.isNull()) + { + gPipeline.markTextured(mDrawable); + gPipeline.markRebuild(mDrawable,LLDrawable::REBUILD_ALL); + } + mFaceMappingChanged = TRUE; + return TEM_CHANGE_TEXTURE; +} + +S32 LLVOVolume::setTEScale(const U8 te, const F32 s, const F32 t) +{ + S32 res = LLViewerObject::setTEScale(te, s, t); + if (res) { gPipeline.markTextured(mDrawable); mFaceMappingChanged = TRUE; @@ -2120,14 +2531,12 @@ void LLVOVolume::updateObjectMediaData(const LLSD &media_data_array, const std:: if ( (S32)fetched_version > mLastFetchedMediaVersion) { mLastFetchedMediaVersion = fetched_version; - //llinfos << "updating:" << this->getID() << " " << ll_pretty_print_sd(media_data_array) << llendl; + //LL_INFOS() << "updating:" << this->getID() << " " << ll_pretty_print_sd(media_data_array) << LL_ENDL; - LLSD::array_const_iterator iter = media_data_array.beginArray(); - LLSD::array_const_iterator end = media_data_array.endArray(); U8 texture_index = 0; - for (; iter != end; ++iter, ++texture_index) + for (auto const& entry : media_data_array.array()) { - syncMediaData(texture_index, *iter, false/*merge*/, false/*ignore_agent*/); + syncMediaData(texture_index++, entry, false/*merge*/, false/*ignore_agent*/); } } } @@ -2148,7 +2557,7 @@ void LLVOVolume::syncMediaData(S32 texture_index, const LLSD &media_data, bool m LL_DEBUGS("MediaOnAPrim") << "BEFORE: texture_index = " << texture_index << " hasMedia = " << te->hasMedia() << " : " - << ((NULL == te->getMediaData()) ? "NULL MEDIA DATA" : ll_pretty_print_sd(te->getMediaData()->asLLSD())) << llendl; + << ((NULL == te->getMediaData()) ? "NULL MEDIA DATA" : ll_pretty_print_sd(te->getMediaData()->asLLSD())) << LL_ENDL; std::string previous_url; LLMediaEntry* mep = te->getMediaData(); @@ -2190,7 +2599,7 @@ void LLVOVolume::syncMediaData(S32 texture_index, const LLSD &media_data, bool m LL_DEBUGS("MediaOnAPrim") << "AFTER: texture_index = " << texture_index << " hasMedia = " << te->hasMedia() << " : " - << ((NULL == te->getMediaData()) ? "NULL MEDIA DATA" : ll_pretty_print_sd(te->getMediaData()->asLLSD())) << llendl; + << ((NULL == te->getMediaData()) ? "NULL MEDIA DATA" : ll_pretty_print_sd(te->getMediaData()->asLLSD())) << LL_ENDL; } void LLVOVolume::mediaNavigateBounceBack(U8 texture_index) @@ -2231,7 +2640,9 @@ void LLVOVolume::mediaNavigateBounceBack(U8 texture_index) LL_WARNS("MediaOnAPrim") << "FAILED to bounce back URL \"" << url << "\" -- unloading impl" << LL_ENDL; impl->setMediaFailed(true); } - else { + // Make sure we are not bouncing to url we came from + else if (impl->getCurrentMediaURL() != url) + { // Okay, navigate now LL_INFOS("MediaOnAPrim") << "bouncing back to URL: " << url << LL_ENDL; impl->navigateTo(url, "", false, true); @@ -2543,32 +2954,48 @@ S32 LLVOVolume::getFaceIndexWithMediaImpl(const LLViewerMediaImpl* media_impl, S void LLVOVolume::setLightTextureID(LLUUID id) { + LLViewerTexture* old_texturep = getLightTexture(); // same as mLightTexture, but inits if nessesary if (id.notNull()) { if (!hasLightTexture()) { setParameterEntryInUse(LLNetworkData::PARAMS_LIGHT_IMAGE, TRUE, true); } - LLLightImageParams* param_block = (LLLightImageParams*) getParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE); + else if (old_texturep) + { + old_texturep->removeVolume(LLRender::LIGHT_TEX, this); + } + LLLightImageParams* param_block = (LLLightImageParams*)getLightImageParams(); if (param_block && param_block->getLightTexture() != id) { param_block->setLightTexture(id); parameterChanged(LLNetworkData::PARAMS_LIGHT_IMAGE, true); } + LLViewerTexture* tex = getLightTexture(); + if (tex) + { + tex->addVolume(LLRender::LIGHT_TEX, this); // new texture + } + else + { + LL_WARNS() << "Can't get light texture for ID " << id.asString() << LL_ENDL; + } } - else + else if (hasLightTexture()) { - if (hasLightTexture()) + if (old_texturep) { - setParameterEntryInUse(LLNetworkData::PARAMS_LIGHT_IMAGE, FALSE, true); - mLightTexture = NULL; + old_texturep->removeVolume(LLRender::LIGHT_TEX, this); } + setParameterEntryInUse(LLNetworkData::PARAMS_LIGHT_IMAGE, FALSE, true); + parameterChanged(LLNetworkData::PARAMS_LIGHT_IMAGE, true); + mLightTexture = NULL; } } void LLVOVolume::setSpotLightParams(LLVector3 params) { - LLLightImageParams* param_block = (LLLightImageParams*) getParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE); + LLLightImageParams* param_block = (LLLightImageParams*)getLightImageParams(); if (param_block && param_block->getParams() != params) { param_block->setParams(params); @@ -2578,7 +3005,8 @@ void LLVOVolume::setSpotLightParams(LLVector3 params) void LLVOVolume::setIsLight(BOOL is_light) { - if (is_light != getIsLight()) + BOOL was_light = getIsLight(); + if (is_light != was_light) { if (is_light) { @@ -2604,7 +3032,7 @@ void LLVOVolume::setIsLight(BOOL is_light) void LLVOVolume::setLightColor(const LLColor3& color) { - LLLightParams *param_block = (LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT); + LLLightParams *param_block = (LLLightParams *)getLightParams(); if (param_block) { if (param_block->getColor() != color) @@ -2619,7 +3047,7 @@ void LLVOVolume::setLightColor(const LLColor3& color) void LLVOVolume::setLightIntensity(F32 intensity) { - LLLightParams *param_block = (LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT); + LLLightParams *param_block = (LLLightParams *)getLightParams(); if (param_block) { if (param_block->getColor().mV[3] != intensity) @@ -2632,7 +3060,7 @@ void LLVOVolume::setLightIntensity(F32 intensity) void LLVOVolume::setLightRadius(F32 radius) { - LLLightParams *param_block = (LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT); + LLLightParams *param_block = (LLLightParams *)getLightParams(); if (param_block) { if (param_block->getRadius() != radius) @@ -2645,7 +3073,7 @@ void LLVOVolume::setLightRadius(F32 radius) void LLVOVolume::setLightFalloff(F32 falloff) { - LLLightParams *param_block = (LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT); + LLLightParams *param_block = (LLLightParams *)getLightParams(); if (param_block) { if (param_block->getFalloff() != falloff) @@ -2658,7 +3086,7 @@ void LLVOVolume::setLightFalloff(F32 falloff) void LLVOVolume::setLightCutoff(F32 cutoff) { - LLLightParams *param_block = (LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT); + LLLightParams *param_block = (LLLightParams *)getLightParams(); if (param_block) { if (param_block->getCutoff() != cutoff) @@ -2673,12 +3101,12 @@ void LLVOVolume::setLightCutoff(F32 cutoff) BOOL LLVOVolume::getIsLight() const { - return getParameterEntryInUse(LLNetworkData::PARAMS_LIGHT); + return getLightParams() != nullptr; } LLColor3 LLVOVolume::getLightBaseColor() const { - const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT); + const LLLightParams *param_block = getLightParams(); if (param_block) { return LLColor3(param_block->getColor()); @@ -2691,7 +3119,7 @@ LLColor3 LLVOVolume::getLightBaseColor() const LLColor3 LLVOVolume::getLightColor() const { - const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT); + const LLLightParams *param_block = getLightParams(); if (param_block) { return LLColor3(param_block->getColor()) * param_block->getColor().mV[3]; @@ -2704,13 +3132,10 @@ LLColor3 LLVOVolume::getLightColor() const LLUUID LLVOVolume::getLightTextureID() const { - if (getParameterEntryInUse(LLNetworkData::PARAMS_LIGHT_IMAGE)) + const LLLightImageParams *param_block = getLightImageParams(); + if (param_block) { - const LLLightImageParams *param_block = (const LLLightImageParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE); - if (param_block) - { - return param_block->getLightTexture(); - } + return param_block->getLightTexture(); } return LLUUID::null; @@ -2719,13 +3144,10 @@ LLUUID LLVOVolume::getLightTextureID() const LLVector3 LLVOVolume::getSpotLightParams() const { - if (getParameterEntryInUse(LLNetworkData::PARAMS_LIGHT_IMAGE)) + const LLLightImageParams *param_block = getLightImageParams(); + if (param_block) { - const LLLightImageParams *param_block = (const LLLightImageParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE); - if (param_block) - { - return param_block->getParams(); - } + return param_block->getParams(); } return LLVector3(); @@ -2762,7 +3184,7 @@ void LLVOVolume::updateSpotLightPriority() bool LLVOVolume::isLightSpotlight() const { - LLLightImageParams* params = (LLLightImageParams*) getParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE); + const LLLightImageParams* params = getLightImageParams(); if (params) { return params->isLightSpotlight(); @@ -2779,7 +3201,7 @@ LLViewerTexture* LLVOVolume::getLightTexture() { if (mLightTexture.isNull() || id != mLightTexture->getID()) { - mLightTexture = LLViewerTextureManager::getFetchedTexture(id); + mLightTexture = LLViewerTextureManager::getFetchedTexture(id, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_ALM); } } else @@ -2792,7 +3214,7 @@ LLViewerTexture* LLVOVolume::getLightTexture() F32 LLVOVolume::getLightIntensity() const { - const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT); + const LLLightParams *param_block = getLightParams(); if (param_block) { return param_block->getColor().mV[3]; @@ -2805,7 +3227,7 @@ F32 LLVOVolume::getLightIntensity() const F32 LLVOVolume::getLightRadius() const { - const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT); + const LLLightParams *param_block = getLightParams(); if (param_block) { return param_block->getRadius(); @@ -2818,7 +3240,7 @@ F32 LLVOVolume::getLightRadius() const F32 LLVOVolume::getLightFalloff() const { - const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT); + const LLLightParams *param_block = getLightParams(); if (param_block) { return param_block->getFalloff(); @@ -2831,7 +3253,7 @@ F32 LLVOVolume::getLightFalloff() const F32 LLVOVolume::getLightCutoff() const { - const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT); + const LLLightParams *param_block = getLightParams(); if (param_block) { return param_block->getCutoff(); @@ -2854,7 +3276,7 @@ U32 LLVOVolume::getVolumeInterfaceID() const BOOL LLVOVolume::isFlexible() const { - if (getParameterEntryInUse(LLNetworkData::PARAMS_FLEXIBLE)) + if (getFlexibleObjectData()) { LLVolume* volume = getVolume(); if (volume && volume->getParams().getPathParams().getCurveType() != LL_PCODE_PATH_FLEXIBLE) @@ -2873,7 +3295,7 @@ BOOL LLVOVolume::isFlexible() const BOOL LLVOVolume::isSculpted() const { - if (getParameterEntryInUse(LLNetworkData::PARAMS_SCULPT)) + if (getSculptParams()) { return TRUE; } @@ -2885,7 +3307,7 @@ BOOL LLVOVolume::isMesh() const { if (isSculpted()) { - LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT); + const LLSculptParams *sculpt_params = getSculptParams(); U8 sculpt_type = sculpt_params->getSculptType(); if ((sculpt_type & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH) @@ -2900,7 +3322,7 @@ BOOL LLVOVolume::isMesh() const BOOL LLVOVolume::hasLightTexture() const { - if (getParameterEntryInUse(LLNetworkData::PARAMS_LIGHT_IMAGE)) + if (getLightImageParams()) { return TRUE; } @@ -2973,6 +3395,205 @@ BOOL LLVOVolume::setIsFlexible(BOOL is_flexible) return res; } +const LLMeshSkinInfo* LLVOVolume::getSkinInfo() const +{ + if (getVolume()) + { + return gMeshRepo.getSkinInfo(getVolume()->getParams().getSculptID(), this); + } + else + { + return NULL; + } +} + +// virtual +BOOL LLVOVolume::isRiggedMesh() const +{ + return isMesh() && getSkinInfo(); +} + +//---------------------------------------------------------------------------- +U32 LLVOVolume::getExtendedMeshFlags() const +{ + const LLExtendedMeshParams *param_block = getExtendedMeshParams(); + if (param_block) + { + return param_block->getFlags(); + } + else + { + return 0; + } +} + +void LLVOVolume::onSetExtendedMeshFlags(U32 flags) +{ + + // The isAnySelected() check was needed at one point to prevent + // graphics problems. These are now believed to be fixed so the + // check has been disabled. + if (/*!getRootEdit()->isAnySelected() &&*/ mDrawable.notNull()) + { + // Need to trigger rebuildGeom(), which is where control avatars get created/removed + getRootEdit()->recursiveMarkForUpdate(TRUE); + } + if (isAttachment() && getAvatarAncestor()) + { + updateVisualComplexity(); + if (flags & LLExtendedMeshParams::ANIMATED_MESH_ENABLED_FLAG) + { + // Making a rigged mesh into an animated object + getAvatarAncestor()->updateAttachmentOverrides(); + } + else + { + // Making an animated object into a rigged mesh + getAvatarAncestor()->updateAttachmentOverrides(); + } + } +} + +void LLVOVolume::setExtendedMeshFlags(U32 flags) +{ + U32 curr_flags = getExtendedMeshFlags(); + if (curr_flags != flags) + { + bool in_use = true; + setParameterEntryInUse(LLNetworkData::PARAMS_EXTENDED_MESH, in_use, true); + LLExtendedMeshParams *param_block = (LLExtendedMeshParams *)getExtendedMeshParams(); + if (param_block) + { + param_block->setFlags(flags); + } + parameterChanged(LLNetworkData::PARAMS_EXTENDED_MESH, true); + LL_DEBUGS("AnimatedObjects") << this + << " new flags " << flags << " curr_flags " << curr_flags + << ", calling onSetExtendedMeshFlags()" + << LL_ENDL; + onSetExtendedMeshFlags(flags); + } +} + +bool LLVOVolume::canBeAnimatedObject() const +{ + F32 est_tris = recursiveGetEstTrianglesMax(); + if (est_tris < 0 || est_tris > getAnimatedObjectMaxTris()) + { + return false; + } + return true; +} + +bool LLVOVolume::isAnimatedObject() const +{ + LLVOVolume *root_vol = (LLVOVolume*)getRootEdit(); + bool root_is_animated_flag = root_vol->getExtendedMeshFlags() & LLExtendedMeshParams::ANIMATED_MESH_ENABLED_FLAG; + return root_is_animated_flag; +} + +// Called any time parenting changes for a volume. Update flags and +// control av accordingly. This is called after parent has been +// changed to new_parent, but before new_parent's mChildList has changed. + +// virtual +void LLVOVolume::onReparent(LLViewerObject *old_parent, LLViewerObject *new_parent) +{ + if (new_parent && !new_parent->isAvatar()) + { + if (mControlAvatar.notNull()) + { + // Here an animated object is being made the child of some + // other prim. Should remove the control av from the child. + LLControlAvatar *av = mControlAvatar; + mControlAvatar = NULL; + av->markForDeath(); + } + } + LLVOVolume *old_volp = old_parent ? old_parent->asVolume() : nullptr; + if (old_volp && old_volp->isAnimatedObject()) + { + if (old_volp->getControlAvatar()) + { + // We have been removed from an animated object, need to do cleanup. + old_volp->getControlAvatar()->updateAttachmentOverrides(); + old_volp->getControlAvatar()->updateAnimations(); + } + } +} + +// This needs to be called after onReparent(), because mChildList is +// not updated until the end of LLViewerObject::addChild() + +// virtual +void LLVOVolume::afterReparent() +{ + { + LL_DEBUGS("AnimatedObjects") << "new child added for parent " + << ((LLViewerObject*)getParent())->getID() << LL_ENDL; + } + + if (isAnimatedObject() && getControlAvatar()) + { + LL_DEBUGS("AnimatedObjects") << "adding attachment overrides, parent is animated object " + << ((LLViewerObject*)getParent())->getID() << LL_ENDL; + + // MAINT-8239 - doing a full rebuild whenever parent is set + // makes the joint overrides load more robustly. In theory, + // addAttachmentOverrides should be sufficient, but in + // practice doing a full rebuild helps compensate for + // notifyMeshLoaded() not being called reliably enough. + + // was: getControlAvatar()->addAttachmentOverridesForObject(this); + //getControlAvatar()->rebuildAttachmentOverrides(); + getControlAvatar()->updateAnimations(); + } + else + { + LL_DEBUGS("AnimatedObjects") << "not adding overrides, parent: " + << ((LLViewerObject*)getParent())->getID() + << " isAnimated: " << isAnimatedObject() << " cav " + << getControlAvatar() << LL_ENDL; + } +} + +//---------------------------------------------------------------------------- +static LLTrace::BlockTimerStatHandle FTM_VOVOL_RIGGING_INFO("VOVol Rigging Info"); + +void LLVOVolume::updateRiggingInfo() +{ + LL_RECORD_BLOCK_TIME(FTM_VOVOL_RIGGING_INFO); + if (isRiggedMesh()) + { + const LLMeshSkinInfo* skin = getSkinInfo(); + LLVOAvatar *avatar = getAvatar(); + LLVolume *volume = getVolume(); + if (skin && avatar && volume) + { + LL_DEBUGS("RigSpammish") << "starting, vovol " << this << " lod " << getLOD() << " last " << mLastRiggingInfoLOD << LL_ENDL; + if (getLOD()>mLastRiggingInfoLOD || getLOD()==3) + { + // Rigging info may need update + mJointRiggingInfoTab.clear(); + for (S32 f = 0; f < volume->getNumVolumeFaces(); ++f) + { + LLVolumeFace& vol_face = volume->getVolumeFace(f); + LLSkinningUtil::updateRiggingInfo(skin, avatar, vol_face); + if (vol_face.mJointRiggingInfoTab.size()>0) + { + mJointRiggingInfoTab.merge(vol_face.mJointRiggingInfoTab); + } + } + // Keep the highest LOD info available. + mLastRiggingInfoLOD = getLOD(); + LL_DEBUGS("RigSpammish") << "updated rigging info for LLVOVolume " + << this << " lod " << mLastRiggingInfoLOD + << LL_ENDL; + } + } + } +} + //---------------------------------------------------------------------------- void LLVOVolume::generateSilhouette(LLSelectNode* nodep, const LLVector3& view_point) @@ -2986,7 +3607,7 @@ void LLVOVolume::generateSilhouette(LLSelectNode* nodep, const LLVector3& view_p //transform view vector into volume space view_vector -= getRenderPosition(); - mDrawable->mDistanceWRTCamera = view_vector.length(); + //mDrawable->mDistanceWRTCamera = view_vector.length(); LLQuaternion worldRot = getRenderRotation(); view_vector = view_vector * ~worldRot; if (!isVolumeGlobal()) @@ -2997,10 +3618,10 @@ void LLVOVolume::generateSilhouette(LLSelectNode* nodep, const LLVector3& view_p } updateRelativeXform(); - LLMatrix4 trans_mat = mRelativeXform; + LLMatrix4a trans_mat = mRelativeXform; if (mDrawable->isStatic()) { - trans_mat.translate(getRegion()->getOriginAgent()); + trans_mat.translate_affine(getRegion()->getOriginAgent()); } volume->generateSilhouetteVertices(nodep->mSilhouetteVertices, nodep->mSilhouetteNormals, view_vector, trans_mat, mRelativeXformInvTrans, nodep->getTESelectMask()); @@ -3034,7 +3655,7 @@ void LLVOVolume::updateRadius() BOOL LLVOVolume::isAttachment() const { - return mState != 0 ; + return mAttachmentState != 0 ; } BOOL LLVOVolume::isHUDAttachment() const @@ -3042,12 +3663,12 @@ BOOL LLVOVolume::isHUDAttachment() const // *NOTE: we assume hud attachment points are in defined range // since this range is constant for backwards compatibility // reasons this is probably a reasonable assumption to make - S32 attachment_id = ATTACHMENT_ID_FROM_STATE(mState); + S32 attachment_id = ATTACHMENT_ID_FROM_STATE(mAttachmentState); return ( attachment_id >= 31 && attachment_id <= 38 ); } -const LLMatrix4 LLVOVolume::getRenderMatrix() const +const LLMatrix4a& LLVOVolume::getRenderMatrix() const { if (mDrawable->isActive() && !mDrawable->isRoot()) { @@ -3115,16 +3736,25 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const path_params = volume_params.getPathParams(); profile_params = volume_params.getProfileParams(); - F32 weighted_triangles = -1.0; - getStreamingCost(NULL, NULL, &weighted_triangles); - - if (weighted_triangles > 0.0) + LLMeshCostData costs; + if (getCostData(costs)) { - num_triangles = (U32)(weighted_triangles); + if (isAnimatedObject() && isRiggedMesh()) + { + // Scaling here is to make animated object vs + // non-animated object ARC proportional to the + // corresponding calculations for streaming cost. + num_triangles = (ANIMATED_OBJECT_COST_PER_KTRI * 0.001 * costs.getEstTrisForStreamingCost())/0.06; + } + else + { + F32 radius = getScale().length()*0.5f; + num_triangles = costs.getRadiusWeightedTris(radius); + } } } - if (num_triangles == 0) + if (num_triangles <= 0) { num_triangles = 4; } @@ -3135,15 +3765,14 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const { // base cost is dependent on mesh complexity // note that 3 is the highest LOD as of the time of this coding. - S32 size = gMeshRepo.getMeshSize(volume_params.getSculptID(),3); + S32 size = gMeshRepo.getMeshSize(volume_params.getSculptID(), getLOD()); if ( size > 0) { - if (gMeshRepo.getSkinInfo(volume_params.getSculptID(), this)) + if (isRiggedMesh()) { // weighted attachment - 1 point for every 3 bytes weighted_mesh = 1; } - } else { @@ -3153,7 +3782,7 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const } else { - const LLSculptParams *sculpt_params = (LLSculptParams *) getParameterEntry(LLNetworkData::PARAMS_SCULPT); + const LLSculptParams *sculpt_params = getSculptParams(); LLUUID sculpt_id = sculpt_params->getSculptTexture(); if (textures.find(sculpt_id) == textures.end()) { @@ -3312,6 +3941,13 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const shame += media_faces * ARC_MEDIA_FACE_COST; } + // Streaming cost for animated objects includes a fixed cost + // per linkset. Add a corresponding charge here translated into + // triangles, but not weighted by any graphics properties. + if (isAnimatedObject() && isRootEdit()) + { + shame += (ANIMATED_OBJECT_BASE_COST/0.06) * 5.0f; + } if (shame > mRenderComplexity_current) { mRenderComplexity_current = (S32)shame; @@ -3320,15 +3956,65 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const return (U32)shame; } -F32 LLVOVolume::getStreamingCost(S32* bytes, S32* visible_bytes, F32* unscaled_value) const +F32 LLVOVolume::getEstTrianglesMax() const +{ + if (isMesh() && getVolume()) + { + return gMeshRepo.getEstTrianglesMax(getVolume()->getParams().getSculptID()); + } + return 0.f; +} + +F32 LLVOVolume::getEstTrianglesStreamingCost() const +{ + if (isMesh() && getVolume()) + { + return gMeshRepo.getEstTrianglesStreamingCost(getVolume()->getParams().getSculptID()); + } + return 0.f; +} + +F32 LLVOVolume::getStreamingCost() const { F32 radius = getScale().length()*0.5f; + F32 linkset_base_cost = 0.f; - if (isMesh()) - { - LLSD& header = gMeshRepo.getMeshHeader(getVolume()->getParams().getSculptID()); + LLMeshCostData costs; + if (getCostData(costs)) + { + if (isAnimatedObject() && isRootEdit()) + { + // Root object of an animated object has this to account for skeleton overhead. + linkset_base_cost = ANIMATED_OBJECT_BASE_COST; + } + if (isMesh()) + { + if (isAnimatedObject() && isRiggedMesh()) + { + return linkset_base_cost + costs.getTriangleBasedStreamingCost(); + } + else + { + return linkset_base_cost + costs.getRadiusBasedStreamingCost(radius); + } + } + else + { + return linkset_base_cost + costs.getRadiusBasedStreamingCost(radius); + } + } + else + { + return 0.f; + } +} - return LLMeshRepository::getStreamingCost(header, radius, bytes, visible_bytes, mLOD, unscaled_value); +// virtual +bool LLVOVolume::getCostData(LLMeshCostData& costs) const +{ + if (isMesh()) + { + return gMeshRepo.getCostData(getVolume()->getParams().getSculptID(), costs); } else { @@ -3342,8 +4028,8 @@ F32 LLVOVolume::getStreamingCost(S32* bytes, S32* visible_bytes, F32* unscaled_v header["medium_lod"]["size"] = counts[2] * 10; header["high_lod"]["size"] = counts[3] * 10; - return LLMeshRepository::getStreamingCost(header, radius, NULL, NULL, -1, unscaled_value); - } + return LLMeshRepository::getCostData(header, costs); + } } //static @@ -3413,6 +4099,21 @@ void LLVOVolume::parameterChanged(U16 param_type, LLNetworkData* data, BOOL in_u { mVolumeImpl->onParameterChanged(param_type, data, in_use, local_origin); } + if (!local_origin && param_type == LLNetworkData::PARAMS_EXTENDED_MESH) + { + U32 extended_mesh_flags = getExtendedMeshFlags(); + bool enabled = (extended_mesh_flags & LLExtendedMeshParams::ANIMATED_MESH_ENABLED_FLAG); + bool was_enabled = (getControlAvatar() != NULL); + if (enabled != was_enabled) + { + LL_DEBUGS("AnimatedObjects") << this + << " calling onSetExtendedMeshFlags, enabled " << (U32) enabled + << " was_enabled " << (U32) was_enabled + << " local_origin " << (U32) local_origin + << LL_ENDL; + onSetExtendedMeshFlags(extended_mesh_flags); + } + } if (mDrawable.notNull()) { BOOL is_light = getIsLight(); @@ -3426,10 +4127,17 @@ void LLVOVolume::parameterChanged(U16 param_type, LLNetworkData* data, BOOL in_u void LLVOVolume::setSelected(BOOL sel) { LLViewerObject::setSelected(sel); - if (mDrawable.notNull()) - { - markForUpdate(TRUE); - } + if (isAnimatedObject()) + { + getRootEdit()->recursiveMarkForUpdate(TRUE); + } + else + { + if (mDrawable.notNull()) + { + markForUpdate(TRUE); + } + } } void LLVOVolume::updateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax) @@ -3492,7 +4200,12 @@ F32 LLVOVolume::getBinRadius() } else if (mDrawable->isStatic()) { - radius = llmax((S32) mDrawable->getRadius(), 1)*size_factor; + F32 szf = size_factor; + + radius = llmax(mDrawable->getRadius(), szf); + + radius = powf(radius, 1.f+szf/radius); + radius *= 1.f + mDrawable->mDistanceWRTCamera * distance_factor[1]; radius += mDrawable->mDistanceWRTCamera * distance_factor[0]; } @@ -3529,7 +4242,7 @@ void LLVOVolume::onShift(const LLVector4a &shift_vector) updateRelativeXform(); } -const LLMatrix4& LLVOVolume::getWorldMatrix(LLXformMatrix* xform) const +const LLMatrix4a& LLVOVolume::getWorldMatrix(LLXformMatrix* xform) const { if (mVolumeImpl) { @@ -3538,6 +4251,12 @@ const LLMatrix4& LLVOVolume::getWorldMatrix(LLXformMatrix* xform) const return xform->getWorldMatrix(); } +void LLVOVolume::markForUpdate(BOOL priority) +{ + LLViewerObject::markForUpdate(priority); + mVolumeChanged = TRUE; +} + LLVector3 LLVOVolume::agentPositionToVolume(const LLVector3& pos) const { LLVector3 ret = pos - getRenderPosition(); @@ -3588,9 +4307,8 @@ LLVector3 LLVOVolume::volumeDirectionToAgent(const LLVector3& dir) const return ret; } - -BOOL LLVOVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, S32 face, BOOL pick_transparent, S32 *face_hitp, - LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal) +BOOL LLVOVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, S32 face, BOOL pick_transparent, BOOL pick_rigged, S32 *face_hitp, + LLVector4a* intersection,LLVector2* tex_coord, LLVector4a* normal, LLVector4a* tangent) { if (!mbCanSelect || @@ -3615,39 +4333,39 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& e if (mDrawable->isState(LLDrawable::RIGGED)) { - static const LLCachedControl allow_mesh_picking("SGAllowRiggedMeshSelection"); - if (allow_mesh_picking && gFloaterTools->getVisible() && getAvatar()->isSelf()) + if (pick_rigged) { - updateRiggedVolume(); - //genBBoxes(FALSE); + updateRiggedVolume(true); volume = mRiggedVolume; transform = false; } else - { //cannot pick rigged attachments on other avatars or when not in build mode + { return FALSE; } } if (volume) { - LLVector3 v_start, v_end, v_dir; - + LLVector4a local_start = start; + LLVector4a local_end = end; + if (transform) { - v_start = agentPositionToVolume(start); - v_end = agentPositionToVolume(end); - } - else - { - v_start = start; - v_end = end; - } + LLVector3 v_start(start.getF32ptr()); + LLVector3 v_end(end.getF32ptr()); - LLVector3 p; - LLVector3 n; + v_start = agentPositionToVolume(v_start); + v_end = agentPositionToVolume(v_end); + + local_start.load3(v_start.mV); + local_end.load3(v_end.mV); + } + + LLVector4a p; + LLVector4a n; LLVector2 tc; - LLVector3 bn; + LLVector4a tn; if (intersection != NULL) { @@ -3664,9 +4382,9 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& e n = *normal; } - if (bi_normal != NULL) + if (tangent != NULL) { - bn = *bi_normal; + tn = *tangent; } S32 face_hit = -1; @@ -3692,18 +4410,40 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& e continue; } - face_hit = volume->lineSegmentIntersect(v_start, v_end, i, - &p, &tc, &n, &bn); + face_hit = volume->lineSegmentIntersect(local_start, local_end, i, + &p, &tc, &n, &tn); if (face_hit >= 0 && mDrawable->getNumFaces() > face_hit) { LLFace* face = mDrawable->getFace(face_hit); - if (face && - (pick_transparent || !face->getTexture() || !face->getTexture()->hasGLTexture() || face->getTexture()->getMask(face->surfaceToTexture(tc, p, n)))) + bool ignore_alpha = false; + + const LLTextureEntry* te = face->getTextureEntry(); + if (te) { - v_end = p; - if (face_hitp != NULL) + LLMaterial* mat = te->getMaterialParams(); + if (mat) + { + U8 mode = mat->getDiffuseAlphaMode(); + + if (mode == LLMaterial::DIFFUSE_ALPHA_MODE_EMISSIVE || + mode == LLMaterial::DIFFUSE_ALPHA_MODE_NONE) + { + ignore_alpha = true; + } + } + } + + if (face && + (ignore_alpha || + pick_transparent || + !face->getTexture() || + !face->getTexture()->hasGLTexture() || + face->getTexture()->getMask(face->surfaceToTexture(tc, p, n)))) + { + local_end = p; + if (face_hitp != NULL) { *face_hitp = face_hit; } @@ -3712,7 +4452,9 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& e { if (transform) { - *intersection = volumePositionToAgent(p); // must map back to agent space + LLVector3 v_p(p.getF32ptr()); + + intersection->load3(volumePositionToAgent(v_p).mV); // must map back to agent space } else { @@ -3724,27 +4466,36 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& e { if (transform) { - *normal = volumeDirectionToAgent(n); + LLVector3 v_n(n.getF32ptr()); + normal->load3(volumeDirectionToAgent(v_n).mV); } else { *normal = n; } - - (*normal).normVec(); + (*normal).normalize3fast(); } - if (bi_normal != NULL) + if (tangent != NULL) { if (transform) { - *bi_normal = volumeDirectionToAgent(bn); + LLVector3 v_tn(tn.getF32ptr()); + + LLVector4a trans_tangent; + trans_tangent.load3(volumeDirectionToAgent(v_tn).mV); + + LLVector4Logical mask; + mask.clear(); + mask.setElement<3>(); + + tangent->setSelectWithMask(mask, tn, trans_tangent); } else { - *bi_normal = bn; + *tangent = tn; } - (*bi_normal).normVec(); + (*tangent).normalize3fast(); } if (tex_coord != NULL) @@ -3763,10 +4514,8 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& e bool LLVOVolume::treatAsRigged() { - return gFloaterTools->getVisible() && - isAttachment() && - getAvatar() && - getAvatar()->isSelf() && + return isSelected() && + (isAttachment() || isAnimatedObject()) && mDrawable.notNull() && mDrawable->isState(LLDrawable::RIGGED); } @@ -3785,12 +4534,12 @@ void LLVOVolume::clearRiggedVolume() } } -void LLVOVolume::updateRiggedVolume() +void LLVOVolume::updateRiggedVolume(bool force_update) { //Update mRiggedVolume to match current animation frame of avatar. //Also update position/size in octree. - if (!treatAsRigged()) + if ((!force_update) && (!treatAsRigged())) { clearRiggedVolume(); @@ -3798,9 +4547,7 @@ void LLVOVolume::updateRiggedVolume() } LLVolume* volume = getVolume(); - - const LLMeshSkinInfo* skin = gMeshRepo.getSkinInfo(volume->getParams().getSculptID(), this); - + const LLMeshSkinInfo* skin = getSkinInfo(); if (!skin) { clearRiggedVolume(); @@ -3826,8 +4573,8 @@ void LLVOVolume::updateRiggedVolume() } -static LLFastTimer::DeclareTimer FTM_SKIN_RIGGED("Skin"); -static LLFastTimer::DeclareTimer FTM_RIGGED_OCTREE("Octree"); +static LLTrace::BlockTimerStatHandle FTM_SKIN_RIGGED("Skin"); +static LLTrace::BlockTimerStatHandle FTM_RIGGED_OCTREE("Octree"); void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, const LLVolume* volume) { @@ -3849,27 +4596,34 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons } } + U64 frame = LLFrameTimer::getFrameCount(); if (copy) { copyVolumeFaces(volume); } + else if (avatar && avatar->areAnimationsPaused()) + { + frame = avatar->getMotionController().getPausedFrame(); + } + if (frame == mFrame) + { + return; + } + mFrame = frame; //build matrix palette - static const size_t kMaxJoints = 64; + static const size_t kMaxJoints = LL_MAX_JOINTS_PER_MESH_OBJECT; + + LLMatrix4a mat[kMaxJoints]; + U32 maxJoints = LLSkinningUtil::getMeshJointCount(skin); + LLSkinningUtil::initSkinningMatrixPalette(mat, maxJoints, skin, avatar, true); - LLMatrix4a mp[kMaxJoints]; - LLMatrix4* mat = (LLMatrix4*) mp; - U32 maxJoints = llmin(skin->mJointNames.size(), kMaxJoints); - for (U32 j = 0; j < maxJoints; ++j) - { - LLJoint* joint = avatar->getJoint(skin->mJointNames[j]); - if (joint) - { - mat[j] = skin->mInvBindMatrix[j]; - mat[j] *= joint->getWorldMatrix(); - } - } + LLMatrix4a bind_shape_matrix; + bind_shape_matrix.loadu(skin->mBindShapeMatrix); + + LLVector4a av_pos; + av_pos.load3(avatar->getPosition().mV); for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i) { @@ -3883,56 +4637,27 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons { continue; } - - LLMatrix4a bind_shape_matrix; - bind_shape_matrix.loadu(skin->mBindShapeMatrix); + LLSkinningUtil::checkSkinWeights(weight, dst_face.mNumVertices, skin); LLVector4a* pos = dst_face.mPositions; if( pos && dst_face.mExtents ) { - LLFastTimer t(FTM_SKIN_RIGGED); + LL_RECORD_BLOCK_TIME(FTM_SKIN_RIGGED); + U32 max_joints = LLSkinningUtil::getMaxJointCount(); for (U32 j = 0; j < (U32)dst_face.mNumVertices; ++j) { LLMatrix4a final_mat; - final_mat.clear(); - - S32 idx[4]; - - LLVector4 wght; - - F32 scale = 0.f; - for (U32 k = 0; k < 4; k++) - { - F32 w = weight[j][k]; - - idx[k] = (S32) floorf(w); - wght[k] = w - floorf(w); - scale += wght[k]; - } - - wght *= 1.f/scale; - - for (U32 k = 0; k < 4; k++) - { - F32 w = wght[k]; - - LLMatrix4a src; - // Ensure ref'd bone is in our clamped array of mats - llassert(idx[k] < kMaxJoints); - // clamp k to kMaxJoints to avoid reading garbage off stack in release - src.setMul(mp[idx[(k < kMaxJoints) ? k : 0]], w); - final_mat.add(src); - } - + LLSkinningUtil::getPerVertexSkinMatrix(weight[j].getF32ptr(), mat, false, final_mat, max_joints); LLVector4a& v = vol_face.mPositions[j]; + LLVector4a t; - LLVector4a dst; bind_shape_matrix.affineTransform(v, t); - final_mat.affineTransform(t, dst); - pos[j] = dst; + final_mat.affineTransform(t, pos[j]); + + pos[j].add(av_pos); // Algorithm tweaked to stop hosing up normals. } //update bounding box @@ -3954,7 +4679,7 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons } { - LLFastTimer t(FTM_RIGGED_OCTREE); + LL_RECORD_BLOCK_TIME(FTM_RIGGED_OCTREE); delete dst_face.mOctree; dst_face.mOctree = NULL; @@ -3973,12 +4698,17 @@ U32 LLVOVolume::getPartitionType() const { return LLViewerRegion::PARTITION_HUD; } + else if (isAttachment()) + { + return LLViewerRegion::PARTITION_ATTACHMENT; + } return LLViewerRegion::PARTITION_VOLUME; } -LLVolumePartition::LLVolumePartition() -: LLSpatialPartition(LLVOVolume::VERTEX_DATA_MASK, TRUE, GL_DYNAMIC_DRAW_ARB) +LLVolumePartition::LLVolumePartition(LLViewerRegion* regionp) +: LLSpatialPartition(LLVOVolume::VERTEX_DATA_MASK, TRUE, GL_DYNAMIC_DRAW_ARB, regionp), +LLVolumeGeometryManager() { mLODPeriod = 32; mDepthMask = FALSE; @@ -3988,8 +4718,9 @@ LLVolumePartition::LLVolumePartition() mBufferUsage = GL_DYNAMIC_DRAW_ARB; } -LLVolumeBridge::LLVolumeBridge(LLDrawable* drawablep) -: LLSpatialBridge(drawablep, TRUE, LLVOVolume::VERTEX_DATA_MASK) +LLVolumeBridge::LLVolumeBridge(LLDrawable* drawablep, LLViewerRegion* regionp) +: LLSpatialBridge(drawablep, TRUE, LLVOVolume::VERTEX_DATA_MASK, regionp), +LLVolumeGeometryManager() { mDepthMask = FALSE; mLODPeriod = 32; @@ -4001,15 +4732,43 @@ LLVolumeBridge::LLVolumeBridge(LLDrawable* drawablep) mSlopRatio = 0.25f; } -bool can_batch_texture(LLFace* facep) +LLAttachmentBridge::LLAttachmentBridge(LLDrawable* drawablep, LLViewerRegion* regionp) + : LLVolumeBridge(drawablep, regionp) { + mPartitionType = LLViewerRegion::PARTITION_ATTACHMENT; +} + +bool can_batch_texture(const LLFace* facep) +{ + static const LLCachedControl alt_batching("SHAltBatching",true); + + if(!alt_batching) + { if (facep->getTextureEntry()->getBumpmap()) { //bump maps aren't worked into texture batching yet return false; } - if (facep->getTexture() && facep->getTexture()->getPrimaryFormat() == GL_ALPHA) - { //can't batch invisiprims + if (facep->getTextureEntry()->getMaterialParams().notNull()) + { //materials don't work with texture batching yet + return false; + } + + if (facep->isState(LLFace::TEXTURE_ANIM) && facep->getVirtualSize() > MIN_TEX_ANIM_SIZE) + { //texture animation breaks batches + return false; + } + } + else + { + + if (facep->getPoolType() == LLDrawPool::POOL_BUMP && (facep->getTextureEntry()->getBumpmap() > 0 && facep->getTextureEntry()->getBumpmap() < 18)) + { //bump maps aren't worked into texture batching yet + return false; + } + + if (LLPipeline::sRenderDeferred && (facep->getPoolType() == LLDrawPool::POOL_ALPHA || facep->getPoolType() == LLDrawPool::POOL_MATERIALS) && facep->getTextureEntry()->getMaterialParams().notNull()) + { //materials don't work with texture batching yet return false; } @@ -4017,15 +4776,84 @@ bool can_batch_texture(LLFace* facep) { //texture animation breaks batches return false; } + } return true; } -static LLFastTimer::DeclareTimer FTM_REGISTER_FACE("Register Face"); +const static U32 MAX_FACE_COUNT = 4096U; +int32_t LLVolumeGeometryManager::sInstanceCount = 0; +LLFace** LLVolumeGeometryManager::sFullbrightFaces = NULL; +LLFace** LLVolumeGeometryManager::sBumpFaces = NULL; +LLFace** LLVolumeGeometryManager::sSimpleFaces = NULL; +LLFace** LLVolumeGeometryManager::sNormFaces = NULL; +LLFace** LLVolumeGeometryManager::sSpecFaces = NULL; +LLFace** LLVolumeGeometryManager::sNormSpecFaces = NULL; +LLFace** LLVolumeGeometryManager::sAlphaFaces = NULL; + +LLVolumeGeometryManager::LLVolumeGeometryManager() + : LLGeometryManager() +{ + llassert(sInstanceCount >= 0); + if (sInstanceCount == 0) + { + allocateFaces(MAX_FACE_COUNT); + } + + ++sInstanceCount; +} + +LLVolumeGeometryManager::~LLVolumeGeometryManager() +{ + llassert(sInstanceCount > 0); + --sInstanceCount; + + if (sInstanceCount <= 0) + { + freeFaces(); + sInstanceCount = 0; + } +} + +void LLVolumeGeometryManager::allocateFaces(U32 pMaxFaceCount) +{ + sFullbrightFaces = static_cast(ll_aligned_malloc<64>(pMaxFaceCount*sizeof(LLFace*))); + sBumpFaces = static_cast(ll_aligned_malloc<64>(pMaxFaceCount*sizeof(LLFace*))); + sSimpleFaces = static_cast(ll_aligned_malloc<64>(pMaxFaceCount*sizeof(LLFace*))); + sNormFaces = static_cast(ll_aligned_malloc<64>(pMaxFaceCount*sizeof(LLFace*))); + sSpecFaces = static_cast(ll_aligned_malloc<64>(pMaxFaceCount*sizeof(LLFace*))); + sNormSpecFaces = static_cast(ll_aligned_malloc<64>(pMaxFaceCount*sizeof(LLFace*))); + sAlphaFaces = static_cast(ll_aligned_malloc<64>(pMaxFaceCount*sizeof(LLFace*))); +} + +void LLVolumeGeometryManager::freeFaces() +{ + ll_aligned_free<64>(sFullbrightFaces); + ll_aligned_free<64>(sBumpFaces); + ll_aligned_free<64>(sSimpleFaces); + ll_aligned_free<64>(sNormFaces); + ll_aligned_free<64>(sSpecFaces); + ll_aligned_free<64>(sNormSpecFaces); + ll_aligned_free<64>(sAlphaFaces); + + sFullbrightFaces = NULL; + sBumpFaces = NULL; + sSimpleFaces = NULL; + sNormFaces = NULL; + sSpecFaces = NULL; + sNormSpecFaces = NULL; + sAlphaFaces = NULL; +} + +static LLTrace::BlockTimerStatHandle FTM_REGISTER_FACE("Register Face"); void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, U32 type) { - LLFastTimer t(FTM_REGISTER_FACE); + LL_RECORD_BLOCK_TIME(FTM_REGISTER_FACE); + //if (type == LLRenderPass::PASS_ALPHA && facep->getTextureEntry()->getMaterialParams().notNull() && !facep->getVertexBuffer()->hasDataType(LLVertexBuffer::TYPE_TANGENT)) + //{ + // LL_WARNS("RenderMaterials") << "Oh no! No binormals for this alpha blended face!" << LL_ENDL; + //} // if (facep->getViewerObject()->isSelected() && gHideSelectedObjects) // [RLVa:KB] - Checked: 2010-11-29 (RLVa-1.3.0c) | Modified: RLVa-1.3.0c @@ -4039,30 +4867,45 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, return; } + if(!facep->mShinyInAlpha) + facep->mShinyInAlpha = (type == LLRenderPass::PASS_FULLBRIGHT_SHINY) || + (type == LLRenderPass::PASS_SHINY) || + (LLPipeline::sRenderDeferred && type == LLRenderPass::PASS_BUMP) || + (LLPipeline::sRenderDeferred && type == LLRenderPass::PASS_SIMPLE); + //add face to drawmap LLSpatialGroup::drawmap_elem_t& draw_vec = group->mDrawMap[type]; S32 idx = draw_vec.size()-1; - BOOL fullbright = (type == LLRenderPass::PASS_FULLBRIGHT) || - (type == LLRenderPass::PASS_INVISIBLE) || + static const LLCachedControl alt_batching("SHAltBatching",true); + BOOL fullbright; + if(!alt_batching) + { + fullbright = (type == LLRenderPass::PASS_FULLBRIGHT) || (type == LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK) || (type == LLRenderPass::PASS_ALPHA && facep->isState(LLFace::FULLBRIGHT)) || (facep->getTextureEntry()->getFullbright()); + } + else + { + fullbright = facep->isState(LLFace::FULLBRIGHT); + } + if (!fullbright && type != LLRenderPass::PASS_GLOW && !facep->getVertexBuffer()->hasDataType(LLVertexBuffer::TYPE_NORMAL)) { - llwarns << "Non fullbright face has no normals!" << llendl; + LL_WARNS() << "Non fullbright face has no normals!" << LL_ENDL; return; } - const LLMatrix4* tex_mat = NULL; + const LLMatrix4a* tex_mat = NULL; if (facep->isState(LLFace::TEXTURE_ANIM) && facep->getVirtualSize() > MIN_TEX_ANIM_SIZE) { tex_mat = facep->mTextureMatrix; } - const LLMatrix4* model_mat = NULL; + const LLMatrix4a* model_mat = NULL; LLDrawable* drawable = facep->getDrawable(); @@ -4079,21 +4922,56 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, model_mat = &(drawable->getRegion()->mRenderMatrix); } + if(model_mat && model_mat->isIdentity()) + { + model_mat = NULL; + } + //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; + LLMaterial* mat = facep->getTextureEntry()->getMaterialParams().get(); + U32 pool_type = facep->getPoolType(); + + bool cmp_bump = (type == LLRenderPass::PASS_BUMP) || (type == LLRenderPass::PASS_POST_BUMP); + bool cmp_mat = (!alt_batching) || LLPipeline::sRenderDeferred && + ((pool_type == LLDrawPool::POOL_MATERIALS) || (pool_type == LLDrawPool::POOL_ALPHA)) || + pool_type == LLDrawPool::POOL_ALPHA_MASK || pool_type == LLDrawPool::POOL_FULLBRIGHT_ALPHA_MASK; + bool cmp_shiny = (!alt_batching) ? !!mat : (mat && cmp_mat); + bool cmp_fullbright = !alt_batching || cmp_shiny || pool_type == LLDrawPool::POOL_ALPHA; + + U8 bump = facep->getTextureEntry()->getBumpmap(); + U8 shiny = facep->getTextureEntry()->getShiny(); + LLViewerTexture* tex = facep->getTexture(); U8 index = facep->getTextureIndex(); - LLMaterialID mat_id = facep->getTextureEntry()->getMaterialID(); + //LLMaterial* mat = facep->getTextureEntry()->getMaterialParams().get(); bool batchable = false; + U32 shader_mask = 0xFFFFFFFF; //no shader + + if (mat && cmp_mat) + { + if (type == LLRenderPass::PASS_ALPHA) + { + shader_mask = mat->getShaderMask(LLMaterial::DIFFUSE_ALPHA_MODE_BLEND); + } + else + { + shader_mask = mat->getShaderMask(); + } + } + if (index < 255 && idx >= 0) { - if (index < draw_vec[idx]->mTextureList.size()) + if (cmp_mat && (mat || draw_vec[idx]->mMaterial)) + { //can't batch textures when materials are present (yet) + batchable = false; + } + else if (index < draw_vec[idx]->mTextureList.size()) { if (draw_vec[idx]->mTextureList[index].isNull()) { @@ -4110,7 +4988,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, batchable = true; } } - + if (idx >= 0 && draw_vec[idx]->mVertexBuffer == facep->getVertexBuffer() && draw_vec[idx]->mEnd == facep->getGeomIndex()-1 && @@ -4119,10 +4997,15 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, draw_vec[idx]->mEnd - draw_vec[idx]->mStart + facep->getGeomCount() <= (U32) gGLManager.mGLMaxVertexRange && draw_vec[idx]->mCount + facep->getIndicesCount() <= (U32) gGLManager.mGLMaxIndexRange && #endif - draw_vec[idx]->mFullbright == fullbright && - draw_vec[idx]->mBump == bump && + (!cmp_mat || draw_vec[idx]->mMaterial == mat) && + //draw_vec[idx]->mMaterialID == mat_id && + (!cmp_fullbright || draw_vec[idx]->mFullbright == fullbright) && + (!cmp_bump || draw_vec[idx]->mBump == bump) && + (!cmp_shiny || draw_vec[idx]->mShiny == shiny) && + //(!mat || (draw_vec[idx]->mShiny == shiny)) && // need to break batches when a material is shared, but legacy settings are different draw_vec[idx]->mTextureMatrix == tex_mat && - draw_vec[idx]->mModelMatrix == model_mat) + draw_vec[idx]->mModelMatrix == model_mat && + (!cmp_mat || draw_vec[idx]->mShaderMask == shader_mask)) { draw_vec[idx]->mCount += facep->getIndicesCount(); draw_vec[idx]->mEnd += facep->getGeomCount(); @@ -4133,7 +5016,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, draw_vec[idx]->mTextureList.resize(index+1); draw_vec[idx]->mTextureList[index] = tex; } - draw_vec[idx]->validate(); + //draw_vec[idx]->validate(); update_min_max(draw_vec[idx]->mExtents[0], draw_vec[idx]->mExtents[1], facep->mExtents[0]); update_min_max(draw_vec[idx]->mExtents[0], draw_vec[idx]->mExtents[1], facep->mExtents[1]); } @@ -4150,6 +5033,60 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, draw_vec.push_back(draw_info); draw_info->mTextureMatrix = tex_mat; draw_info->mModelMatrix = model_mat; + + draw_info->mBump = bump; + draw_info->mShiny = shiny; + + float alpha[4] = + { + 0.00f, + 0.25f, + 0.5f, + 0.75f + }; + float spec = alpha[shiny & TEM_SHINY_MASK]; + LLVector4 specColor(spec, spec, spec, spec); + draw_info->mSpecColor = specColor; + draw_info->mEnvIntensity = spec; + draw_info->mSpecularMap = NULL; + draw_info->mMaterial = mat; + draw_info->mShaderMask = shader_mask; + + if (cmp_mat && mat) + { + //draw_info->mMaterialID = mat_id; + + // We have a material. Update our draw info accordingly. + + if (!mat->getSpecularID().isNull()) + { + LLVector4 specColor; + specColor.mV[0] = mat->getSpecularLightColor().mV[0] * (1.f / 255.f); + specColor.mV[1] = mat->getSpecularLightColor().mV[1] * (1.f / 255.f); + specColor.mV[2] = mat->getSpecularLightColor().mV[2] * (1.f / 255.f); + specColor.mV[3] = llmax(0.0000f, mat->getSpecularLightExponent() * (1.f / 255.f)); + draw_info->mSpecColor = specColor; + draw_info->mEnvIntensity = mat->getEnvironmentIntensity() * (1.f / 255.f); + draw_info->mSpecularMap = facep->getViewerObject()->getTESpecularMap(facep->getTEOffset()); + } + + draw_info->mAlphaMaskCutoff = mat->getAlphaMaskCutoff() * (1.f / 255.f); + draw_info->mDiffuseAlphaMode = mat->getDiffuseAlphaMode(); + draw_info->mNormalMap = facep->getViewerObject()->getTENormalMap(facep->getTEOffset()); + + } + else + { + if (type == LLRenderPass::PASS_GRASS) + { + draw_info->mAlphaMaskCutoff = 0.5f; + } + else + { + draw_info->mAlphaMaskCutoff = 0.33f; + } + } + if (type == LLRenderPass::PASS_ALPHA) { //for alpha sorting facep->setDrawInfo(draw_info); @@ -4162,7 +5099,8 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, draw_info->mTextureList.resize(index+1); draw_info->mTextureList[index] = tex; } - draw_info->validate(); + + //draw_info->validate(); } } @@ -4171,9 +5109,9 @@ void LLVolumeGeometryManager::getGeometry(LLSpatialGroup* group) } -static LLFastTimer::DeclareTimer FTM_REBUILD_VOLUME_VB("Volume VB"); -static LLFastTimer::DeclareTimer FTM_REBUILD_VOLUME_FACE_LIST("Build Face List"); -static LLFastTimer::DeclareTimer FTM_REBUILD_VOLUME_GEN_DRAW_INFO("Gen Draw Info"); +static LLTrace::BlockTimerStatHandle FTM_REBUILD_VOLUME_VB("Volume VB"); +static LLTrace::BlockTimerStatHandle FTM_REBUILD_VOLUME_FACE_LIST("Build Face List"); +static LLTrace::BlockTimerStatHandle FTM_REBUILD_VOLUME_GEN_DRAW_INFO("Gen Draw Info"); static LLDrawPoolAvatar* get_avatar_drawpool(LLViewerObject* vobj) { @@ -4202,6 +5140,81 @@ static LLDrawPoolAvatar* get_avatar_drawpool(LLViewerObject* vobj) return NULL; } +void handleRenderAutoMuteByteLimitChanged(const LLSD& new_value) +{ + static LLCachedControl render_auto_mute_byte_limit(gSavedSettings, "RenderAutoMuteByteLimit", 0U); + + if (0 != render_auto_mute_byte_limit) + { + //for unload + LLSculptIDSize::container_BY_SIZE_view::iterator + itL = LLSculptIDSize::instance().getSizeInfo().get().lower_bound(render_auto_mute_byte_limit), + itU = LLSculptIDSize::instance().getSizeInfo().get().end(); + + for (; itL != itU; ++itL) + { + const LLSculptIDSize::Info &nfo = *itL; + LLVOVolume *pVVol = nfo.getPtrLLDrawable()->getVOVolume(); + if (pVVol + && !pVVol->isDead() + && pVVol->isAttachment() + && !pVVol->getAvatar()->isSelf() + && LLVOVolume::NO_LOD != pVVol->getLOD() + ) + { + //postponed + pVVol->markForUnload(); + LLSculptIDSize::instance().addToUnloaded(nfo.getSculptId()); + } + } + + //for load if it was unload + itL = LLSculptIDSize::instance().getSizeInfo().get().begin(); + itU = LLSculptIDSize::instance().getSizeInfo().get().upper_bound(render_auto_mute_byte_limit); + + for (; itL != itU; ++itL) + { + const LLSculptIDSize::Info &nfo = *itL; + LLVOVolume *pVVol = nfo.getPtrLLDrawable()->getVOVolume(); + if (pVVol + && !pVVol->isDead() + && pVVol->isAttachment() + && !pVVol->getAvatar()->isSelf() + && LLVOVolume::NO_LOD == pVVol->getLOD() + ) + { + LLSculptIDSize::instance().remFromUnloaded(nfo.getSculptId()); + pVVol->updateLOD(); + pVVol->markForUpdate(TRUE); + } + } + } + else + { + LLSculptIDSize::instance().clearUnloaded(); + + LLSculptIDSize::container_BY_SIZE_view::iterator + itL = LLSculptIDSize::instance().getSizeInfo().get().begin(), + itU = LLSculptIDSize::instance().getSizeInfo().get().end(); + + for (; itL != itU; ++itL) + { + const LLSculptIDSize::Info &nfo = *itL; + LLVOVolume *pVVol = nfo.getPtrLLDrawable()->getVOVolume(); + if (pVVol + && !pVVol->isDead() + && pVVol->isAttachment() + && !pVVol->getAvatar()->isSelf() + && LLVOVolume::NO_LOD == pVVol->getLOD() + ) + { + pVVol->updateLOD(); + pVVol->markForUpdate(TRUE); + } + } + } +} + void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) { if (LLPipeline::sSkipUpdate) @@ -4216,63 +5229,58 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) group->mLastUpdateViewAngle = group->mViewAngle; - if (!group->isState(LLSpatialGroup::GEOM_DIRTY | LLSpatialGroup::ALPHA_DIRTY)) + if (!group->hasState(LLSpatialGroup::GEOM_DIRTY | LLSpatialGroup::ALPHA_DIRTY)) { - if (group->isState(LLSpatialGroup::MESH_DIRTY) && !LLPipeline::sDelayVBUpdate) + if (group->hasState(LLSpatialGroup::MESH_DIRTY) && !LLPipeline::sDelayVBUpdate) { rebuildMesh(group); } return; } - LLFastTimer ftm(FTM_REBUILD_VOLUME_VB); + LL_RECORD_BLOCK_TIME(FTM_REBUILD_VOLUME_VB); group->mBuilt = 1.f; - LLVOAvatar* pAvatarVO = NULL; + LLSpatialBridge* bridge = group->getSpatialPartition()->asBridge(); + LLViewerObject *vobj = NULL; + LLVOVolume *vol_obj = NULL; - LLSpatialBridge* bridge = group->mSpatialPartition->asBridge(); if (bridge) { - if (bridge->mAvatar.isNull()) - { - LLViewerObject* vobj = bridge->mDrawable->getVObj(); - if (vobj) - { - bridge->mAvatar = vobj->getAvatar(); - } - } - - pAvatarVO = bridge->mAvatar; - } - - if (pAvatarVO) - { - pAvatarVO->mAttachmentGeometryBytes -= group->mGeometryBytes; - pAvatarVO->mAttachmentSurfaceArea -= group->mSurfaceArea; + vobj = bridge->mDrawable->getVObj(); + vol_obj = vobj ? vobj->asVolume() : nullptr; } + if (vol_obj) + { + vol_obj->updateVisualComplexity(); + } group->mGeometryBytes = 0; group->mSurfaceArea = 0; //cache object box size since it might be used for determining visibility - group->mObjectBoxSize = group->mObjectBounds[1].getLength3().getF32(); + const LLVector4a* bounds = group->getObjectBounds(); + group->mObjectBoxSize = bounds[1].getLength3().getF32(); group->clearDrawMap(); mFaceList.clear(); + + U32 fullbright_count = 0; + U32 bump_count = 0; + U32 simple_count = 0; + U32 alpha_count = 0; + U32 norm_count = 0; + U32 spec_count = 0; + U32 normspec_count = 0; - std::vector fullbright_faces; - std::vector bump_faces; - std::vector simple_faces; - - std::vector alpha_faces; - U32 useage = group->mSpatialPartition->mBufferUsage; + U32 useage = group->getSpatialPartition()->mBufferUsage; static const LLCachedControl render_max_vbo_size("RenderMaxVBOSize", 512); static const LLCachedControl render_max_node_size("RenderMaxNodeSize",8192); - U32 max_vertices = (render_max_vbo_size*1024)/LLVertexBuffer::calcVertexSize(group->mSpatialPartition->mVertexDataMask); - U32 max_total = (render_max_node_size*1024)/LLVertexBuffer::calcVertexSize(group->mSpatialPartition->mVertexDataMask); + U32 max_vertices = (render_max_vbo_size*1024)/LLVertexBuffer::calcVertexSize(group->getSpatialPartition()->mVertexDataMask); + U32 max_total = (render_max_node_size*1024)/LLVertexBuffer::calcVertexSize(group->getSpatialPartition()->mVertexDataMask); max_vertices = llmin(max_vertices, (U32) 65535); U32 cur_total = 0; @@ -4280,15 +5288,15 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) bool emissive = false; { - LLFastTimer t(FTM_REBUILD_VOLUME_FACE_LIST); + LL_RECORD_BLOCK_TIME(FTM_REBUILD_VOLUME_FACE_LIST); //get all the faces into a list - OctreeGuard guard(group->mOctreeNode); + OctreeGuard guard(group->getOctreeNode()); for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter) { - LLDrawable* drawablep = *drawable_iter; + LLDrawable* drawablep = (LLDrawable*)(*drawable_iter)->getDrawable(); - if (drawablep->isDead() || drawablep->isState(LLDrawable::FORCE_INVISIBLE) ) + if (!drawablep || drawablep->isDead() || drawablep->isState(LLDrawable::FORCE_INVISIBLE) ) { continue; } @@ -4318,20 +5326,31 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) group->mSurfaceArea += volume->getSurfaceArea() * llmax(llmax(scale.mV[0], scale.mV[1]), scale.mV[2]); } + vobj->updateControlAvatar(); llassert_always(vobj); vobj->updateTextureVirtualSize(true); vobj->preRebuild(); drawablep->clearState(LLDrawable::HAS_ALPHA); - bool rigged = vobj->isAttachment() && - vobj->isMesh() && - gMeshRepo.getSkinInfo(vobj->getVolume()->getParams().getSculptID(), vobj); - - bool bake_sunlight = LLPipeline::sBakeSunlight && drawablep->isStatic(); - - bool is_rigged = false; - + if (vobj->isRiggedMesh() && + ((vobj->isAnimatedObject() && vobj->getControlAvatar()) || + (!vobj->isAnimatedObject() && vobj->getAvatar()))) + { + vobj->getAvatar()->addAttachmentOverridesForObject(vobj, NULL, false); + } + + // Standard rigged mesh attachments: + bool rigged = !vobj->isAnimatedObject() && vobj->isRiggedMesh() && vobj->isAttachment(); + // Animated objects. Have to check for isRiggedMesh() to + // exclude static objects in animated object linksets. + rigged = rigged || (vobj->isAnimatedObject() && vobj->isRiggedMesh() && + vobj->getControlAvatar() && vobj->getControlAvatar()->mPlaying); + + bool any_rigged_face = false; + + static const LLCachedControl alt_batching("SHAltBatching",true); + //for each face for (S32 i = 0; i < drawablep->getNumFaces(); i++) { @@ -4358,65 +5377,17 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) } facep->setState(LLFace::RIGGED); - is_rigged = true; + any_rigged_face = true; //get drawpool of avatar with rigged face LLDrawPoolAvatar* pool = get_avatar_drawpool(vobj); - - //Determine if we've received skininfo that contains an - //alternate bind matrix - if it does then apply the translational component - //to the joints of the avatar. - bool pelvisGotSet = false; - - if ( pAvatarVO ) - { - LLUUID currentId = vobj->getVolume()->getParams().getSculptID(); - const LLMeshSkinInfo* pSkinData = gMeshRepo.getSkinInfo( currentId, vobj ); - if ( pSkinData ) - { - const int bindCnt = pSkinData->mAlternateBindMatrix.size(); - if ( bindCnt > 0 ) - { - const int jointCnt = pSkinData->mJointNames.size(); - const F32 pelvisZOffset = pSkinData->mPelvisOffset; - bool fullRig = (jointCnt>=20) ? true : false; - if ( fullRig ) - { - for ( int i=0; imJointNames[i].c_str(); - //llinfos<<"joint name "<getJoint( lookingForJoint ); - if ( pJoint && pJoint->getId() != currentId ) - { - pJoint->setId( currentId ); - const LLVector3& jointPos = pSkinData->mAlternateBindMatrix[i].getTranslation(); - //Set the joint position - pJoint->storeCurrentXform( jointPos ); - //If joint is a pelvis then handle old/new pelvis to foot values - if ( lookingForJoint == "mPelvis" ) - { - pJoint->storeCurrentXform( jointPos ); - if ( !pAvatarVO->hasPelvisOffset() ) - { - pAvatarVO->setPelvisOffset( true, jointPos, pelvisZOffset ); - //Trigger to rebuild viewer AV - pelvisGotSet = true; - } - } - } - } - } - } - } - } - //If we've set the pelvis to a new position we need to also rebuild some information that the - //viewer does at launch (e.g. body size etc.) - if ( pelvisGotSet ) + // FIXME should this be inside the face loop? + // doesn't seem to depend on any per-face state. + /*if ( pAvatarVO ) { - pAvatarVO->postPelvisSetRecalc(); - } + pAvatarVO->addAttachmentOverridesForObject(vobj); + }*/ if (pool) { @@ -4440,8 +5411,29 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) } LLMaterial* mat = te->getMaterialParams().get(); + + if(!alt_batching) + { + if (mat && LLPipeline::sRenderDeferred) + { + U8 alpha_mode = mat->getDiffuseAlphaMode(); + + bool is_alpha = type == LLDrawPool::POOL_ALPHA && + (alpha_mode == LLMaterial::DIFFUSE_ALPHA_MODE_BLEND || + te->getColor().mV[3] < 0.999f); + + if (is_alpha) + { //this face needs alpha blending, override alpha mode + alpha_mode = LLMaterial::DIFFUSE_ALPHA_MODE_BLEND; + } - if (mat) + if (!is_alpha || te->getColor().mV[3] > 0.f) // //only add the face if it will actually be visible + { + U32 mask = mat->getShaderMask(alpha_mode); + pool->addRiggedFace(facep, mask); + } + } + else if (mat) { bool fullbright = te->getFullbright(); bool is_alpha = type == LLDrawPool::POOL_ALPHA; @@ -4449,7 +5441,6 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) bool can_be_shiny = mode == LLMaterial::DIFFUSE_ALPHA_MODE_NONE || mode == LLMaterial::DIFFUSE_ALPHA_MODE_EMISSIVE; - bool is_deferred_simple = LLPipeline::sRenderDeferred && !fullbright; if (mode == LLMaterial::DIFFUSE_ALPHA_MODE_MASK && te->getColor().mV[3] >= 0.999f) { pool->addRiggedFace(facep, fullbright ? LLDrawPoolAvatar::RIGGED_FULLBRIGHT : LLDrawPoolAvatar::RIGGED_SIMPLE); @@ -4460,21 +5451,18 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) { pool->addRiggedFace(facep, fullbright ? LLDrawPoolAvatar::RIGGED_FULLBRIGHT_ALPHA : LLDrawPoolAvatar::RIGGED_ALPHA); } - is_deferred_simple = false; } - else if (gPipeline.canUseVertexShaders() + else if (LLGLSLShader::sNoFixedFunction && LLPipeline::sRenderBump && te->getShiny() && can_be_shiny) { - pool->addRiggedFace(facep, fullbright ? LLDrawPoolAvatar::RIGGED_FULLBRIGHT_SHINY : !LLPipeline::sRenderDeferred ? LLDrawPoolAvatar::RIGGED_SHINY : LLDrawPoolAvatar::RIGGED_SIMPLE); + pool->addRiggedFace(facep, fullbright ? LLDrawPoolAvatar::RIGGED_FULLBRIGHT_SHINY : LLDrawPoolAvatar::RIGGED_SHINY); } else { pool->addRiggedFace(facep, fullbright ? LLDrawPoolAvatar::RIGGED_FULLBRIGHT : LLDrawPoolAvatar::RIGGED_SIMPLE); } - if(is_deferred_simple) - pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_SIMPLE); } else { @@ -4538,6 +5526,68 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) } } } + } + else + { + if(type == LLDrawPool::POOL_ALPHA) + { + if(te->getColor().mV[3] > 0.f) + { + U32 mask = te->getFullbright() ? LLDrawPoolAvatar::RIGGED_FULLBRIGHT_ALPHA : LLDrawPoolAvatar::RIGGED_ALPHA; + if (mat && LLPipeline::sRenderDeferred) + { + if(te->getColor().mV[3] < 0.999f || mat->getDiffuseAlphaMode() == LLMaterial::DIFFUSE_ALPHA_MODE_BLEND) + mask = mat->getShaderMask(LLMaterial::DIFFUSE_ALPHA_MODE_BLEND); + else + mask = mat->getShaderMask(); + } + pool->addRiggedFace(facep, mask); + } + } + else if(!LLPipeline::sRenderDeferred) + { + if(type == LLDrawPool::POOL_FULLBRIGHT || type == LLDrawPool::POOL_FULLBRIGHT_ALPHA_MASK) + { + pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT); + } + else if(type == LLDrawPool::POOL_SIMPLE || type == LLDrawPool::POOL_ALPHA_MASK) + { + pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE); + } + else if(type == LLDrawPool::POOL_BUMP) //Either shiny, or bump (which isn't used in non-deferred) + { + if(te->getShiny()) + pool->addRiggedFace(facep, te->getFullbright() ? LLDrawPoolAvatar::RIGGED_FULLBRIGHT_SHINY : LLDrawPoolAvatar::RIGGED_SHINY); + else + pool->addRiggedFace(facep, te->getFullbright() ? LLDrawPoolAvatar::RIGGED_FULLBRIGHT : LLDrawPoolAvatar::RIGGED_SIMPLE); + } + else + { + pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE); + } + } + + else + { + //Annoying exception to the rule. getPoolTypeFromTE will return POOL_ALPHA_MASK for legacy bumpmaps, but there is no POOL_ALPHA_MASK in deferred. + if (type == LLDrawPool::POOL_MATERIALS || ((type == LLDrawPool::POOL_ALPHA_MASK || type == LLDrawPool::POOL_FULLBRIGHT_ALPHA_MASK) && mat)) + { + pool->addRiggedFace(facep, mat->getShaderMask()); + } + else if (type == LLDrawPool::POOL_FULLBRIGHT || type == LLDrawPool::POOL_FULLBRIGHT_ALPHA_MASK) + { + pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT); + } + else if (type == LLDrawPool::POOL_BUMP && te->getBumpmap()) + { + pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_BUMP); + } + else + { + pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_SIMPLE); + } + } + } } continue; @@ -4582,48 +5632,104 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) } } + bool force_fullbright = group->isHUDGroup(); BOOL force_simple = (facep->getPixelArea() < FORCE_SIMPLE_RENDER_AREA); U32 type = gPipeline.getPoolTypeFromTE(te, tex); + + if(!alt_batching) + { if (type != LLDrawPool::POOL_ALPHA && force_simple) { type = LLDrawPool::POOL_SIMPLE; } - facep->setPoolType(type); - - if (vobj->isHUDAttachment()) + } + else { + if (force_fullbright || te->getFullbright()) facep->setState(LLFace::FULLBRIGHT); - } - if (vobj->mTextureAnimp && vobj->mTexAnimMode) + if ( type == LLDrawPool::POOL_ALPHA ) { - if (vobj->mTextureAnimp->mFace <= -1) + if(facep->canRenderAsMask()) { - S32 face; - for (face = 0; face < vobj->getNumTEs(); face++) + if (facep->isState(LLFace::FULLBRIGHT)) { - LLFace * facep = drawablep->getFace(face); - if (facep) - { - facep->setState(LLFace::TEXTURE_ANIM); - } + type = LLDrawPool::POOL_FULLBRIGHT_ALPHA_MASK; } - } - else if (vobj->mTextureAnimp->mFace < vobj->getNumTEs()) - { - LLFace * facep = drawablep->getFace(vobj->mTextureAnimp->mFace); - if (facep) + else + { + type = LLDrawPool::POOL_ALPHA_MASK; + } + } + } + else if (force_fullbright) //Hud is done in a forward render. Fullbright cannot be shared with simple. + { + LLMaterial* mat = te->getMaterialParams().get(); + if (type == LLDrawPool::POOL_ALPHA_MASK || (mat && mat->getDiffuseAlphaMode() == LLMaterial::DIFFUSE_ALPHA_MODE_MASK ) ) + { + type = LLDrawPool::POOL_FULLBRIGHT_ALPHA_MASK; + } + else + { + type = LLDrawPool::POOL_FULLBRIGHT; + } + } + else if(force_simple && type != LLDrawPool::POOL_FULLBRIGHT && (!LLPipeline::sRenderDeferred && (type != LLDrawPool::POOL_ALPHA_MASK && type != LLDrawPool::POOL_FULLBRIGHT_ALPHA_MASK))) + { + type = LLDrawPool::POOL_SIMPLE; + } + } + + facep->setPoolType(type); + + if(!alt_batching) + { + if (vobj->isHUDAttachment()) + { + facep->setState(LLFace::FULLBRIGHT); + } + } + /*LLColor4 clr = facep->getFaceColor(); + LLColor4U clru = LLColor4U(ll_round(clr.mV[0] * 255.f), ll_round(clr.mV[0] * 255.f), ll_round(clr.mV[0] * 255.f), ll_round(clr.mV[0] * 255.f)); + if(clru.mV[0] == 164 && clru.mV[1] == 106 && clr.mV[2] == 65) + { + LL_INFOS() << "Facepool = " << type << " alpha = " << clr.mV[3] << LL_ENDL; + }*/ + + if (vobj->mTextureAnimp && vobj->mTexAnimMode) + { + if (vobj->mTextureAnimp->mFace <= -1) + { + S32 face; + for (face = 0; face < vobj->getNumTEs(); face++) + { + LLFace * facep = drawablep->getFace(face); + if (facep) + { + facep->setState(LLFace::TEXTURE_ANIM); + } + } + } + else if (vobj->mTextureAnimp->mFace < vobj->getNumTEs()) + { + LLFace * facep = drawablep->getFace(vobj->mTextureAnimp->mFace); + if (facep) { facep->setState(LLFace::TEXTURE_ANIM); } } } - if (type == LLDrawPool::POOL_ALPHA) + if(!alt_batching) { + if (type == LLDrawPool::POOL_ALPHA) + { if (facep->canRenderAsMask()) { //can be treated as alpha mask - simple_faces.push_back(facep); + if (simple_count < MAX_FACE_COUNT) + { + sSimpleFaces[simple_count++] = facep; + } } else { @@ -4631,7 +5737,10 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) { //only treat as alpha in the pipeline if < 100% transparent drawablep->setState(LLDrawable::HAS_ALPHA); } - alpha_faces.push_back(facep); + if (alpha_count < MAX_FACE_COUNT) + { + sAlphaFaces[alpha_count++] = facep; + } } } else @@ -4640,42 +5749,223 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) { facep->mLastUpdateTime = gFrameTimeSeconds; } - if (gPipeline.canUseWindLightShadersOnObjects() && LLPipeline::sRenderBump) { - if (te->getBumpmap()) - { //needs normal + binormal - bump_faces.push_back(facep); + // Singu Note: Don't check the materials ID, as doing such causes a mismatch between rebuildGeom and genDrawInfo. + // If we did check, then genDrawInfo would be more lenient than rebuildGeom on deciding if a face verts should have material-related attributes, + // which would result in a face with a vertex buffer that fails to meet shader attribute requirements. + if (LLPipeline::sRenderDeferred && te->getMaterialParams().notNull() /* && !te->getMaterialID().isNull()*/) + { + LLMaterial* mat = te->getMaterialParams().get(); + if (mat->getNormalID().notNull()) + { + if (mat->getSpecularID().notNull()) + { //has normal and specular maps (needs texcoord1, texcoord2, and tangent) + if (normspec_count < MAX_FACE_COUNT) + { + sNormSpecFaces[normspec_count++] = facep; + } + } + else + { //has normal map (needs texcoord1 and tangent) + if (norm_count < MAX_FACE_COUNT) + { + sNormFaces[norm_count++] = facep; + } + } + } + else if (mat->getSpecularID().notNull()) + { //has specular map but no normal map, needs texcoord2 + if (spec_count < MAX_FACE_COUNT) + { + sSpecFaces[spec_count++] = facep; + } + } + else + { //has neither specular map nor normal map, only needs texcoord0 + if (simple_count < MAX_FACE_COUNT) + { + sSimpleFaces[simple_count++] = facep; + } + } + } + else if (te->getBumpmap()) + { //needs normal + tangent + if (bump_count < MAX_FACE_COUNT) + { + sBumpFaces[bump_count++] = facep; + } } else if (te->getShiny() || !te->getFullbright()) { //needs normal - simple_faces.push_back(facep); + if (simple_count < MAX_FACE_COUNT) + { + sSimpleFaces[simple_count++] = facep; + } } else { //doesn't need normal facep->setState(LLFace::FULLBRIGHT); - fullbright_faces.push_back(facep); + if (fullbright_count < MAX_FACE_COUNT) + { + sFullbrightFaces[fullbright_count++] = facep; + } } } else { if (te->getBumpmap() && LLPipeline::sRenderBump) - { //needs normal + binormal - bump_faces.push_back(facep); + { //needs normal + tangent + if (bump_count < MAX_FACE_COUNT) + { + sBumpFaces[bump_count++] = facep; + } } else if ((te->getShiny() && LLPipeline::sRenderBump) || - !(te->getFullbright() || bake_sunlight)) + !(te->getFullbright())) { //needs normal - simple_faces.push_back(facep); + if (simple_count < MAX_FACE_COUNT) + { + sSimpleFaces[simple_count++] = facep; + } } else { //doesn't need normal facep->setState(LLFace::FULLBRIGHT); - fullbright_faces.push_back(facep); + if (fullbright_count < MAX_FACE_COUNT) + { + sFullbrightFaces[fullbright_count++] = facep; + } + } + } + } + } + else + { + LLFace*** cur_type = NULL; + U32* cur_count = NULL; + + if (type == LLDrawPool::POOL_ALPHA) + { + cur_type = &sAlphaFaces; + cur_count = &alpha_count; + + if (te->getColor().mV[3] > 0.f) + { //only treat as alpha in the pipeline if < 100% transparent + drawablep->setState(LLDrawable::HAS_ALPHA); + } + + LLMaterial* mat = te->getMaterialParams().get(); + if(mat && LLPipeline::sRenderDeferred) + { + if (mat->getNormalID().notNull()) + { + if (mat->getSpecularID().notNull()) + { //has normal and specular maps (needs texcoord1, texcoord2, and tangent) + cur_type = &sNormSpecFaces; + cur_count = &normspec_count; + } + else + { //has normal map (needs texcoord1 and tangent) + cur_type = &sNormFaces; + cur_count = &norm_count; + } + } + else if (mat->getSpecularID().notNull()) + { //has specular map but no normal map, needs texcoord2 + cur_type = &sSpecFaces; + cur_count = &spec_count; + } + } + } + else if(type == LLDrawPool::POOL_ALPHA_MASK) + { + cur_type = &sSimpleFaces; + cur_count = &simple_count; + } + else if(type == LLDrawPool::POOL_FULLBRIGHT_ALPHA_MASK) + { + cur_type = &sFullbrightFaces; + cur_count = &fullbright_count; + } + else + { + if (drawablep->isState(LLDrawable::REBUILD_VOLUME)) + { + facep->mLastUpdateTime = gFrameTimeSeconds; + } + + if (type == LLDrawPool::POOL_BUMP) + { //needs normal + tangent + if(te->getBumpmap() > 0 && te->getBumpmap() < 18) + { + cur_type = &sBumpFaces; + cur_count = &bump_count; } + else if(te->getShiny()) + { + cur_type = &sSimpleFaces; + cur_count = &simple_count; + } + } + else if (type == LLDrawPool::POOL_SIMPLE) + { //needs normal + tangent + cur_type = &sSimpleFaces; + cur_count = &simple_count; + } + else if (type == LLDrawPool::POOL_FULLBRIGHT) + { //doesn't need normal... + if(LLPipeline::sRenderBump && te->getShiny()) //unless it's shiny.. + { + cur_type = &sSimpleFaces; + cur_count = &simple_count; + } + else + { + cur_type = &sFullbrightFaces; + cur_count = &fullbright_count; + } + } + /*Singu Note: Don't check the materials ID, as doing such causes a mismatch between rebuildGeom and genDrawInfo. + If we did check, then genDrawInfo would be more lenient than rebuildGeom on deciding if a face verts should have material-related attributes, + which would result in a face with a vertex buffer that fails to meet shader attribute requirements.*/ + else if(type == LLDrawPool::POOL_MATERIALS) + { + LLMaterial* mat = te->getMaterialParams().get(); + if (mat->getNormalID().notNull()) + { + if (mat->getSpecularID().notNull()) + { //has normal and specular maps (needs texcoord1, texcoord2, and tangent) + cur_type = &sNormSpecFaces; + cur_count = &normspec_count; + } + else + { //has normal map (needs texcoord1 and tangent) + cur_type = &sNormFaces; + cur_count = &norm_count; + } + } + else if (mat->getSpecularID().notNull()) + { //has specular map but no normal map, needs texcoord2 + cur_type = &sSpecFaces; + cur_count = &spec_count; + } + else + { //has neither specular map nor normal map, only needs texcoord0 + cur_type = &sSimpleFaces; + cur_count = &simple_count; + } + } + else + { + LL_ERRS() << "Unknown pool type: " << type << LL_ENDL; } } + llassert_always(cur_type); + if(*cur_count < MAX_FACE_COUNT) + (*cur_type)[(*cur_count)++] = facep; + } } else { //face has no renderable geometry @@ -4683,13 +5973,21 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) } } - if (is_rigged) + if (any_rigged_face) { - drawablep->setState(LLDrawable::RIGGED); + if (!drawablep->isState(LLDrawable::RIGGED)) + { + drawablep->setState(LLDrawable::RIGGED); + + //first time this is drawable is being marked as rigged, + // do another LoD update to use avatar bounding box + vobj->updateLOD(); + } } else { drawablep->clearState(LLDrawable::RIGGED); + vobj->updateRiggedVolume(); } } } @@ -4699,43 +5997,40 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) //PROCESS NON-ALPHA FACES U32 simple_mask = LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_COLOR; U32 alpha_mask = simple_mask | 0x80000000; //hack to give alpha verts their own VBO - U32 bump_mask = LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_COLOR; + U32 bump_mask = simple_mask | LLVertexBuffer::MAP_TEXCOORD1; U32 fullbright_mask = LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_COLOR; - if (emissive) - { //emissive faces are present, include emissive byte to preserve batching - simple_mask = simple_mask | LLVertexBuffer::MAP_EMISSIVE; - alpha_mask = alpha_mask | LLVertexBuffer::MAP_EMISSIVE; - bump_mask = bump_mask | LLVertexBuffer::MAP_EMISSIVE; - fullbright_mask = fullbright_mask | LLVertexBuffer::MAP_EMISSIVE; - } + U32 norm_mask = simple_mask | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TANGENT; + U32 normspec_mask = norm_mask | LLVertexBuffer::MAP_TEXCOORD2; + U32 spec_mask = simple_mask | LLVertexBuffer::MAP_TEXCOORD2; - bool batch_textures = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT) > 1; + BOOL batch_textures = LLGLSLShader::sNoFixedFunction; - if (batch_textures) - { - bump_mask |= LLVertexBuffer::MAP_BINORMAL; - genDrawInfo(group, simple_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, simple_faces, FALSE, TRUE); - genDrawInfo(group, fullbright_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, fullbright_faces, FALSE, TRUE); - genDrawInfo(group, bump_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, bump_faces, FALSE, TRUE); - genDrawInfo(group, alpha_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, alpha_faces, TRUE, TRUE); - } - else - { - genDrawInfo(group, simple_mask, simple_faces); - genDrawInfo(group, fullbright_mask, fullbright_faces); - genDrawInfo(group, bump_mask, bump_faces, FALSE, TRUE); - genDrawInfo(group, alpha_mask, alpha_faces, TRUE); - } - + U32 additional_flags = 0x0; + if(batch_textures) + additional_flags |= LLVertexBuffer::MAP_TEXTURE_INDEX; + if (LLPipeline::sRenderDeferred) + bump_mask = norm_mask; + + //emissive faces are present, include emissive byte to preserve batching + if(emissive) + additional_flags |= LLVertexBuffer::MAP_EMISSIVE; + + genDrawInfo(group, simple_mask | additional_flags, sSimpleFaces, simple_count, FALSE, batch_textures); + genDrawInfo(group, fullbright_mask | additional_flags, sFullbrightFaces, fullbright_count, FALSE, batch_textures); + genDrawInfo(group, alpha_mask | additional_flags, sAlphaFaces, alpha_count, TRUE, batch_textures); + genDrawInfo(group, bump_mask | additional_flags, sBumpFaces, bump_count, FALSE); + genDrawInfo(group, norm_mask | additional_flags, sNormFaces, norm_count, FALSE); + genDrawInfo(group, spec_mask | additional_flags, sSpecFaces, spec_count, FALSE); + genDrawInfo(group, normspec_mask | additional_flags, sNormSpecFaces, normspec_count, FALSE); if (!LLPipeline::sDelayVBUpdate) { //drawables have been rebuilt, clear rebuild status - OctreeGuard guard(group->mOctreeNode); + OctreeGuard guard(group->getOctreeNode()); for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter) { - LLDrawable* drawablep = *drawable_iter; + LLDrawable* drawablep = (LLDrawable*)(*drawable_iter)->getDrawable(); drawablep->clearState(LLDrawable::REBUILD_ALL); } } @@ -4750,12 +6045,6 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) } mFaceList.clear(); - - if (pAvatarVO) - { - pAvatarVO->mAttachmentGeometryBytes += group->mGeometryBytes; - pAvatarVO->mAttachmentSurfaceArea += group->mSurfaceArea; - } } @@ -4763,24 +6052,30 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group) { llassert(group); static int warningsCount = 20; - if (group && group->isState(LLSpatialGroup::MESH_DIRTY) && !group->isState(LLSpatialGroup::GEOM_DIRTY)) + if (group && group->hasState(LLSpatialGroup::MESH_DIRTY) && !group->hasState(LLSpatialGroup::GEOM_DIRTY)) { - LLFastTimer ftm(FTM_REBUILD_VOLUME_VB); - LLFastTimer t(FTM_REBUILD_VOLUME_GEN_DRAW_INFO); //make sure getgeometryvolume shows up in the right place in timers - S32 num_mapped_vertex_buffer = LLVertexBuffer::sMappedCount ; + LL_RECORD_BLOCK_TIME(FTM_REBUILD_VOLUME_VB); + LL_RECORD_BLOCK_TIME(FTM_REBUILD_VOLUME_GEN_DRAW_INFO); //make sure getgeometryvolume shows up in the right place in timers group->mBuilt = 1.f; - std::set mapped_buffers; + OctreeGuard guard(group->getOctreeNode()); + S32 num_mapped_vertex_buffer = LLVertexBuffer::sMappedCount ; + + const U32 MAX_BUFFER_COUNT = 4096; + static LLVertexBuffer* locked_buffer[MAX_BUFFER_COUNT]; + + U32 buffer_count = 0; - OctreeGuard guard(group->mOctreeNode); for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter) { - LLDrawable* drawablep = *drawable_iter; + LLDrawable* drawablep = (LLDrawable*)(*drawable_iter)->getDrawable(); - if (!drawablep->isDead() && drawablep->isState(LLDrawable::REBUILD_ALL) && !drawablep->isState(LLDrawable::RIGGED) ) + if (drawablep && !drawablep->isDead() && drawablep->isState(LLDrawable::REBUILD_ALL) && !drawablep->isState(LLDrawable::RIGGED) ) { LLVOVolume* vobj = drawablep->getVOVolume(); + if (vobj->isNoLOD()) continue; + vobj->preRebuild(); if (drawablep->isState(LLDrawable::ANIMATED_CHILD)) @@ -4807,9 +6102,9 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group) } - if (buff->isLocked()) + if (buff->isLocked() && buffer_count < MAX_BUFFER_COUNT) { - mapped_buffers.insert(buff); + locked_buffer[buffer_count++] = buff; } } } @@ -4825,7 +6120,7 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group) } } - for (std::set::iterator iter = mapped_buffers.begin(); iter != mapped_buffers.end(); ++iter) + for (LLVertexBuffer** iter = locked_buffer, ** end_iter = locked_buffer+buffer_count; iter != end_iter; ++iter) { (*iter)->flush(); } @@ -4843,13 +6138,17 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group) { if (++warningsCount > 20) // Do not spam the log file uselessly... { - llwarns << "Not all mapped vertex buffers are unmapped!" << llendl ; + LL_WARNS() << "Not all mapped vertex buffers are unmapped!" << LL_ENDL ; warningsCount = 1; } - OctreeGuard guard(group->mOctreeNode); + OctreeGuard guard(group->getOctreeNode()); for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter) { - LLDrawable* drawablep = *drawable_iter; + LLDrawable* drawablep = (LLDrawable*)(*drawable_iter)->getDrawable(); + if(!drawablep) + { + continue; + } for (S32 i = 0; i < drawablep->getNumFaces(); ++i) { LLFace* face = drawablep->getFace(i); @@ -4875,38 +6174,92 @@ struct CompareBatchBreakerModified { bool operator()(const LLFace* const& lhs, const LLFace* const& rhs) { + static const LLCachedControl alt_batching("SHAltBatching",true); + if(!alt_batching) + { + const LLTextureEntry* lte = lhs->getTextureEntry(); + const LLTextureEntry* rte = rhs->getTextureEntry(); + + if (lte->getBumpmap() != rte->getBumpmap()) + { + return lte->getBumpmap() < rte->getBumpmap(); + } + else if (lte->getFullbright() != rte->getFullbright()) + { + return lte->getFullbright() < rte->getFullbright(); + } + else if (LLPipeline::sRenderDeferred && lte->getMaterialParams() != rte->getMaterialParams()) + { + return lte->getMaterialParams() < rte->getMaterialParams(); + } + else if (LLPipeline::sRenderDeferred && (lte->getMaterialParams() == rte->getMaterialParams()) && (lte->getShiny() != rte->getShiny())) + { + return lte->getShiny() < rte->getShiny(); + } + else + { + return lhs->getTexture() < rhs->getTexture(); + } + } + else + { + const LLTextureEntry* lte = lhs->getTextureEntry(); const LLTextureEntry* rte = rhs->getTextureEntry(); - if (lte->getBumpmap() != rte->getBumpmap()) + bool batch_left = can_batch_texture(lhs); + bool batch_right = can_batch_texture(rhs); + + if (lhs->getPoolType() != rhs->getPoolType()) { - return lte->getBumpmap() < rte->getBumpmap(); + return lhs->getPoolType() < rhs->getPoolType(); } - else if (lte->getFullbright() != rte->getFullbright()) + else if(batch_left != batch_right) //Move non-batchable faces together. { - return lte->getFullbright() < rte->getFullbright(); + return !(batch_left < batch_right); + } + + static const LLCachedControl sh_fullbright_deferred("SHFullbrightDeferred",true); + bool batch_shiny = (!LLPipeline::sRenderDeferred || (sh_fullbright_deferred && lhs->isState(LLFace::FULLBRIGHT))) && lhs->getPoolType() == LLDrawPool::POOL_BUMP; + bool batch_fullbright = sh_fullbright_deferred || !LLPipeline::sRenderDeferred && lhs->getPoolType() == LLDrawPool::POOL_ALPHA; + + if (batch_fullbright && lhs->isState(LLFace::FULLBRIGHT) != rhs->isState(LLFace::FULLBRIGHT)) + { + return lhs->isState(LLFace::FULLBRIGHT) < rhs->isState(LLFace::FULLBRIGHT); + } + else if(batch_shiny && !lte->getShiny() != !rte->getShiny()) + { + return !lte->getShiny() < !rte->getShiny(); + } + else if(lhs->getPoolType() == LLDrawPool::POOL_MATERIALS && lte->getMaterialParams().get() != rte->getMaterialParams().get()) + { + return lte->getMaterialParams().get() < rte->getMaterialParams().get(); + } + else if(lhs->getPoolType() == LLDrawPool::POOL_BUMP && lte->getBumpmap() != rte->getBumpmap()) + { + return lte->getBumpmap() < rte->getBumpmap(); } else { return lhs->getTexture() < rhs->getTexture(); } - + } } }; -static LLFastTimer::DeclareTimer FTM_GEN_DRAW_INFO_SORT("Draw Info Face Sort"); -static LLFastTimer::DeclareTimer FTM_GEN_DRAW_INFO_FACE_SIZE("Face Sizing"); -static LLFastTimer::DeclareTimer FTM_GEN_DRAW_INFO_ALLOCATE("Allocate VB"); -static LLFastTimer::DeclareTimer FTM_GEN_DRAW_INFO_FIND_VB("Find VB"); -static LLFastTimer::DeclareTimer FTM_GEN_DRAW_INFO_RESIZE_VB("Resize VB"); +static LLTrace::BlockTimerStatHandle FTM_GEN_DRAW_INFO_SORT("Draw Info Face Sort"); +static LLTrace::BlockTimerStatHandle FTM_GEN_DRAW_INFO_FACE_SIZE("Face Sizing"); +static LLTrace::BlockTimerStatHandle FTM_GEN_DRAW_INFO_ALLOCATE("Allocate VB"); +static LLTrace::BlockTimerStatHandle FTM_GEN_DRAW_INFO_FIND_VB("Find VB"); +static LLTrace::BlockTimerStatHandle FTM_GEN_DRAW_INFO_RESIZE_VB("Resize VB"); -void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::vector& faces, BOOL distance_sort, BOOL batch_textures) +void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace** faces, U32 face_count, BOOL distance_sort, BOOL batch_textures) { - LLFastTimer t(FTM_REBUILD_VOLUME_GEN_DRAW_INFO); + LL_RECORD_BLOCK_TIME(FTM_REBUILD_VOLUME_GEN_DRAW_INFO); U32 buffer_usage = group->mBufferUsage; @@ -4923,104 +6276,88 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std:: //calculate maximum number of vertices to store in a single buffer static const LLCachedControl render_max_vbo_size("RenderMaxVBOSize", 512); - U32 max_vertices = (render_max_vbo_size*1024)/LLVertexBuffer::calcVertexSize(group->mSpatialPartition->mVertexDataMask); + U32 max_vertices = (render_max_vbo_size*1024)/LLVertexBuffer::calcVertexSize(group->getSpatialPartition()->mVertexDataMask); max_vertices = llmin(max_vertices, (U32) 65535); { - LLFastTimer t(FTM_GEN_DRAW_INFO_SORT); + LL_RECORD_BLOCK_TIME(FTM_GEN_DRAW_INFO_SORT); if (!distance_sort) { //sort faces by things that break batches - std::sort(faces.begin(), faces.end(), CompareBatchBreakerModified()); + std::sort(faces, faces+face_count, CompareBatchBreakerModified()); } else { //sort faces by distance - std::sort(faces.begin(), faces.end(), LLFace::CompareDistanceGreater()); + std::sort(faces, faces+face_count, LLFace::CompareDistanceGreater()); } } - + bool hud_group = group->isHUDGroup() ; - std::vector::iterator face_iter = faces.begin(); + LLFace** face_iter = faces; + LLFace** end_faces = faces+face_count; - LLSpatialGroup::buffer_map_t buffer_map; + LLSpatialGroup::buffer_vec_t buffer_vec; - LLViewerTexture* last_tex = NULL; - S32 buffer_index = 0; - - if (distance_sort) - { - buffer_index = -1; - } - - S32 texture_index_channels = 1; - - if (gGLManager.mGLSLVersionMajor > 1 || gGLManager.mGLSLVersionMinor >= 30) - { - static const LLCachedControl no_texture_indexing("ShyotlUseLegacyTextureBatching",false); - if(!no_texture_indexing) - texture_index_channels = LLGLSLShader::sIndexedTextureChannels-1; //always reserve one for shiny for now just for simplicity; - } + S32 texture_index_channels = llmax(LLGLSLShader::sIndexedTextureChannels-1,1); //always reserve one for shiny for now just for simplicity if (LLPipeline::sRenderDeferred && distance_sort) { texture_index_channels = gDeferredAlphaProgram.mFeatures.mIndexedTextureChannels; } - static const LLCachedControl max_texture_index("RenderMaxTextureIndex",1); - texture_index_channels = llmin(texture_index_channels, (S32) max_texture_index.get()); - - //NEVER use more than 16 texture index channels (workaround for prevalent driver bug) - texture_index_channels = llmin(texture_index_channels, 16); + bool flexi = false; - while (face_iter != faces.end()) + while (face_iter != end_faces) { //pull off next face LLFace* facep = *face_iter; LLViewerTexture* tex = facep->getTexture(); + LLMaterialPtr mat = facep->getTextureEntry()->getMaterialParams(); - if (distance_sort) + static const LLCachedControl alt_batching("SHAltBatching",true); + if (!alt_batching && distance_sort) { tex = NULL; } - if (last_tex == tex) - { - buffer_index++; - } - else - { - last_tex = tex; - buffer_index = 0; - } - - bool bake_sunlight = LLPipeline::sBakeSunlight && facep->getDrawable()->isStatic(); - U32 index_count = facep->getIndicesCount(); U32 geom_count = facep->getGeomCount(); + flexi = flexi || facep->getViewerObject()->getVolume()->isUnique(); + //sum up vertices needed for this render batch - std::vector::iterator i = face_iter; + LLFace** i = face_iter; ++i; + + if(!alt_batching) + { + const U32 MAX_TEXTURE_COUNT = 32; + static LLViewerTexture* texture_list[MAX_TEXTURE_COUNT]; - std::vector texture_list; + U32 texture_count = 0; { - LLFastTimer t(FTM_GEN_DRAW_INFO_FACE_SIZE); + LL_RECORD_BLOCK_TIME(FTM_GEN_DRAW_INFO_FACE_SIZE); if (batch_textures) { U8 cur_tex = 0; facep->setTextureIndex(cur_tex); - texture_list.push_back(tex); + if (texture_count < MAX_TEXTURE_COUNT) + { + texture_list[texture_count++] = tex; + } if (can_batch_texture(facep)) - { - while (i != faces.end()) + { //populate texture_list with any textures that can be batched + //move i to the next unbatchable face + while (i != end_faces) { facep = *i; if (!can_batch_texture(facep)) { //face is bump mapped or has an animated texture matrix -- can't //batch more than 1 texture at a time + facep->setTextureIndex(0); break; } if (facep->getTexture() != tex) @@ -5028,7 +6365,7 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std:: if (distance_sort) { //textures might be out of order, see if texture exists in current batch bool found = false; - for (U32 tex_idx = 0; tex_idx < texture_list.size(); ++tex_idx) + for (U32 tex_idx = 0; tex_idx < texture_count; ++tex_idx) { if (facep->getTexture() == texture_list[tex_idx]) { @@ -5040,7 +6377,7 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std:: if (!found) { - cur_tex = texture_list.size(); + cur_tex = texture_count; } } else @@ -5055,7 +6392,10 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std:: tex = facep->getTexture(); - texture_list.push_back(tex); + if (texture_count < MAX_TEXTURE_COUNT) + { + texture_list[texture_count++] = tex; + } } if (geom_count + facep->getGeomCount() > max_vertices) @@ -5064,6 +6404,9 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std:: } ++i; + + flexi = flexi || facep->getViewerObject()->getVolume()->isUnique(); + index_count += facep->getIndicesCount(); geom_count += facep->getGeomCount(); @@ -5071,11 +6414,18 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std:: } tex = texture_list[0]; } + else + { + facep->setTextureIndex(0); + } } else { - while (i != faces.end() && - (LLPipeline::sTextureBindTest || (distance_sort || (*i)->getTexture() == tex))) + while (i != end_faces && + (LLPipeline::sTextureBindTest || + (distance_sort || + ((*i)->getTexture() == tex && + ((*i)->getTextureEntry()->getMaterialParams() == mat))))) { facep = *i; @@ -5092,6 +6442,140 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std:: ++i; index_count += facep->getIndicesCount(); geom_count += facep->getGeomCount(); + + flexi = flexi || facep->getViewerObject()->getVolume()->isUnique(); + } + } + } + + } + else + { + LL_RECORD_BLOCK_TIME(FTM_GEN_DRAW_INFO_FACE_SIZE); + + if (batch_textures) + { + facep->setTextureIndex(0); + + if(can_batch_texture(facep)) + { + static const U8 MAX_TEXTURE_COUNT = 32; + static LLViewerTexture* texture_list[MAX_TEXTURE_COUNT]; + U8 texture_count = 1; + U8 cur_tex = 0; + texture_list[0] = tex; + U8 pool = facep->getPoolType(); + + while (i != end_faces) + { + facep = *i; + if ( !can_batch_texture(facep) || !(facep) || (geom_count + facep->getGeomCount() > max_vertices) || pool != facep->getPoolType() ) + { //cut batches on geom count too big + break; + } + else + { + if(facep->getTexture() != tex) + { + bool reused = false; + if(distance_sort) //Alpha faces aren't sorted by batch criteria, but rather distance WRT camera. + { + for(U8 j = 0; j < texture_count; ++j) + { + if(texture_list[j] == facep->getTexture()) + { + tex = facep->getTexture(); + cur_tex = j; + reused = true; + break; + } + } + } + if(!reused) + { + if(++texture_count > llmin((U8)texture_index_channels,MAX_TEXTURE_COUNT)) + break; + cur_tex = texture_count - 1; + tex = facep->getTexture(); + texture_list[cur_tex] = tex; + } + } + facep->setTextureIndex(cur_tex); + flexi = flexi || facep->getViewerObject()->getVolume()->isUnique(); + index_count += facep->getIndicesCount(); + geom_count += facep->getGeomCount(); + } + ++i; + } + } + } + else + { + //face has no texture index + facep->mDrawInfo = NULL; + facep->setTextureIndex(255); + + while (i != end_faces && + (LLPipeline::sTextureBindTest || + (distance_sort || + ((*i)->getTexture() == tex && + ((*i)->getTextureEntry()->getMaterialParams() == mat))))) + { + facep = *i; + + if (geom_count + facep->getGeomCount() > max_vertices) + { //cut batches on geom count too big + break; + } + //face has no texture index + facep->mDrawInfo = NULL; + facep->setTextureIndex(255); + flexi = flexi || facep->getViewerObject()->getVolume()->isUnique(); + index_count += facep->getIndicesCount(); + geom_count += facep->getGeomCount(); + ++i; + } + } + } + + if (flexi && buffer_usage && buffer_usage != GL_STREAM_DRAW_ARB) + { + buffer_usage = GL_STREAM_DRAW_ARB; + } + + // Singu Note: Catch insufficient vbos right when they are created. Easier to debug. + if(gDebugGL) + { + if (LLPipeline::sRenderDeferred && + (*face_iter)->getTextureEntry()->getMaterialParams().get() && + ((*face_iter)->getPoolType() == LLDrawPool::POOL_ALPHA || + (*face_iter)->getPoolType() == LLDrawPool::POOL_MATERIALS )) + { + LLMaterial* mat = (*face_iter)->getTextureEntry()->getMaterialParams().get(); + + U32 shader_mask; + if((*face_iter)->getPoolType() == LLDrawPool::POOL_ALPHA) + shader_mask = mat->getShaderMask(LLMaterial::DIFFUSE_ALPHA_MODE_BLEND); + else + shader_mask = mat->getShaderMask(); + + if(shader_mask != 1 && shader_mask != 5 && shader_mask != 9 && shader_mask != 13) + { + LLGLSLShader* shader = &(gDeferredMaterialProgram[shader_mask]); + + if((mask & shader->mAttributeMask) != shader->mAttributeMask) + { + for (U32 i = 0; i < LLVertexBuffer::TYPE_MAX; ++i) + { + U32 attrib_mask = 1 << i; + if((shader->mAttributeMask & attrib_mask) && !(mask & attrib_mask)) + { + const std::string& type_name = LLVertexBuffer::getTypeName(i); + LL_WARNS() << " Missing: " << type_name << LL_ENDL; + } + } + LL_ERRS() << "Face VBO missing required materials attributes." << LL_ENDL; + } } } } @@ -5100,15 +6584,14 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std:: LLVertexBuffer* buffer = NULL; { - LLFastTimer t(FTM_GEN_DRAW_INFO_ALLOCATE); + LL_RECORD_BLOCK_TIME(FTM_GEN_DRAW_INFO_ALLOCATE); buffer = createVertexBuffer(mask, buffer_usage); buffer->allocateBuffer(geom_count, index_count, TRUE); } group->mGeometryBytes += buffer->getSize() + buffer->getIndicesSize(); - - buffer_map[mask][*face_iter].push_back(buffer); + get_val_in_pair_vec(get_val_in_pair_vec(buffer_vec, mask),*face_iter).push_back(buffer); //add face geometry @@ -5124,14 +6607,15 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std:: if (batch_textures && facep->getTextureIndex() == 255) { - llerrs << "Invalid texture index." << llendl; + LL_ERRS() << "Invalid texture index." << LL_ENDL; } { //for debugging, set last time face was updated vs moved facep->updateRebuildFlags(); - if (!LLPipeline::sDelayVBUpdate) + //Singu Note: Moved to after registerFace calls, as those update LLFace::mShinyInAlpha, which is needed before updating the vertex buffer. + /*if (!LLPipeline::sDelayVBUpdate) { //copy face geometry into vertex buffer LLDrawable* drawablep = facep->getDrawable(); LLVOVolume* vobj = drawablep->getVOVolume(); @@ -5149,21 +6633,24 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std:: if (!facep->getGeometryVolume(*volume, te_idx, vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), index_offset,true)) { - llwarns << "Failed to get geometry for face!" << llendl; + LL_WARNS() << "Failed to get geometry for face!" << LL_ENDL; } if (drawablep->isState(LLDrawable::ANIMATED_CHILD)) { vobj->updateRelativeXform(false); } - } + }*/ } - index_offset += facep->getGeomCount(); - indices_index += facep->getIndicesCount(); + facep->mShinyInAlpha = false; + + static const LLCachedControl alt_batching("SHAltBatching",true); //append face to appropriate render batch + if(!alt_batching) + { BOOL force_simple = facep->getPixelArea() < FORCE_SIMPLE_RENDER_AREA; BOOL fullbright = facep->isState(LLFace::FULLBRIGHT); if ((mask & LLVertexBuffer::MAP_NORMAL) == 0) @@ -5191,8 +6678,97 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std:: mode == LLMaterial::DIFFUSE_ALPHA_MODE_EMISSIVE; } - bool use_legacy_bump = te->getBumpmap(); - if (mat) + bool use_legacy_bump = te->getBumpmap() && (te->getBumpmap() < 18) && (!mat || mat->getNormalID().isNull()); + bool opaque = te->getColor().mV[3] >= 0.999f; + + if (mat && LLPipeline::sRenderDeferred && !hud_group) + { + bool material_pass = false; + + // do NOT use 'fullbright' for this logic or you risk sending + // things without normals down the materials pipeline and will + // render poorly if not crash NORSPEC-240,314 + // + if (te->getFullbright()) + { + if (mat->getDiffuseAlphaMode() == LLMaterial::DIFFUSE_ALPHA_MODE_MASK) + { + if (opaque) + { + registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK); + } + else + { + registerFace(group, facep, LLRenderPass::PASS_ALPHA); + } + } + else if (is_alpha) + { + registerFace(group, facep, LLRenderPass::PASS_ALPHA); + } + else + { + if (mat->getEnvironmentIntensity() > 0 || + te->getShiny() > 0) + { + material_pass = true; + } + else + { + registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT); + } + } + } + /*else if (no_materials) + { + registerFace(group, facep, LLRenderPass::PASS_SIMPLE); + }*/ + else if (!opaque) //Just use opaque instead of te->getColorblahblah + { + registerFace(group, facep, LLRenderPass::PASS_ALPHA); + } + else if (use_legacy_bump) + { + // we have a material AND legacy bump settings, but no normal map + registerFace(group, facep, LLRenderPass::PASS_BUMP); + } + else + { + material_pass = true; + } + + if (material_pass) + { + static const U32 pass[] = + { + LLRenderPass::PASS_MATERIAL, + LLRenderPass::PASS_ALPHA, //LLRenderPass::PASS_MATERIAL_ALPHA, + LLRenderPass::PASS_MATERIAL_ALPHA_MASK, + LLRenderPass::PASS_MATERIAL_ALPHA_EMISSIVE, + LLRenderPass::PASS_SPECMAP, + LLRenderPass::PASS_ALPHA, //LLRenderPass::PASS_SPECMAP_BLEND, + LLRenderPass::PASS_SPECMAP_MASK, + LLRenderPass::PASS_SPECMAP_EMISSIVE, + LLRenderPass::PASS_NORMMAP, + LLRenderPass::PASS_ALPHA, //LLRenderPass::PASS_NORMMAP_BLEND, + LLRenderPass::PASS_NORMMAP_MASK, + LLRenderPass::PASS_NORMMAP_EMISSIVE, + LLRenderPass::PASS_NORMSPEC, + LLRenderPass::PASS_ALPHA, //LLRenderPass::PASS_NORMSPEC_BLEND, + LLRenderPass::PASS_NORMSPEC_MASK, + LLRenderPass::PASS_NORMSPEC_EMISSIVE, + }; + + U32 mask = mat->getShaderMask(); + + llassert(mask < sizeof(pass)/sizeof(U32)); + + mask = llmin(mask, (U32)(sizeof(pass)/sizeof(U32)-1)); + + registerFace(group, facep, pass[mask]); + } + } + else if (mat) { U8 mode = mat->getDiffuseAlphaMode(); if (te->getColor().mV[3] < 0.999f) @@ -5208,12 +6784,12 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std:: { registerFace(group, facep, LLRenderPass::PASS_ALPHA); } - else if (gPipeline.canUseVertexShaders() + else if (LLGLSLShader::sNoFixedFunction && LLPipeline::sRenderBump && te->getShiny() && can_be_shiny) { - registerFace(group, facep, fullbright ? LLRenderPass::PASS_FULLBRIGHT_SHINY : (!LLPipeline::sRenderDeferred || hud_group) ? LLRenderPass::PASS_SHINY : LLRenderPass::PASS_SIMPLE); + registerFace(group, facep, fullbright ? LLRenderPass::PASS_FULLBRIGHT_SHINY : LLRenderPass::PASS_SHINY); } else { @@ -5243,17 +6819,12 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std:: registerFace(group, facep, LLRenderPass::PASS_ALPHA); } } - else if (gPipeline.canUseVertexShaders() + else if (LLGLSLShader::sNoFixedFunction && LLPipeline::sRenderBump && te->getShiny() && can_be_shiny) { //shiny - if (tex->getPrimaryFormat() == GL_ALPHA) - { //invisiprim+shiny - registerFace(group, facep, LLRenderPass::PASS_INVISI_SHINY); - registerFace(group, facep, LLRenderPass::PASS_INVISIBLE); - } - else if (LLPipeline::sRenderDeferred && !hud_group) + if (LLPipeline::sRenderDeferred && !hud_group) { //deferred rendering if (te->getFullbright()) { //register in post deferred fullbright shiny pass @@ -5284,11 +6855,7 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std:: } else { //not alpha and not shiny - if (!is_alpha && tex->getPrimaryFormat() == GL_ALPHA) - { //invisiprim - registerFace(group, facep, LLRenderPass::PASS_INVISIBLE); - } - else if (fullbright || bake_sunlight) + if (fullbright) { //fullbright if (mat && mat->getDiffuseAlphaMode() == LLMaterial::DIFFUSE_ALPHA_MODE_MASK) { @@ -5324,7 +6891,7 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std:: } - if (!gPipeline.canUseVertexShaders() && + if (!LLGLSLShader::sNoFixedFunction && !is_alpha && te->getShiny() && LLPipeline::sRenderBump) @@ -5344,39 +6911,203 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std:: registerFace(group, facep, LLRenderPass::PASS_BUMP); } } + if (!is_alpha && LLPipeline::sRenderGlow && te->getGlow() > 0.f) + { + registerFace(group, facep, LLRenderPass::PASS_GLOW); + } + } + else + { + const LLTextureEntry* te = facep->getTextureEntry(); + tex = facep->getTexture(); + + bool is_alpha = facep->getPoolType() == LLDrawPool::POOL_ALPHA; + bool is_shiny_shader = facep->getPoolType() == LLDrawPool::POOL_BUMP && LLGLSLShader::sNoFixedFunction && te->getShiny(); + bool is_shiny_fixed = facep->getPoolType() == LLDrawPool::POOL_BUMP && !LLGLSLShader::sNoFixedFunction && te->getShiny(); + bool is_fullbright = facep->isState(LLFace::FULLBRIGHT); + if (facep->getPoolType() == LLDrawPool::POOL_MATERIALS) + { + U32 pass[] = + { + LLRenderPass::PASS_MATERIAL, + LLRenderPass::PASS_ALPHA, //LLRenderPass::PASS_MATERIAL_ALPHA, + LLRenderPass::PASS_MATERIAL_ALPHA_MASK, + LLRenderPass::PASS_MATERIAL_ALPHA_EMISSIVE, + LLRenderPass::PASS_SPECMAP, + LLRenderPass::PASS_ALPHA, //LLRenderPass::PASS_SPECMAP_BLEND, + LLRenderPass::PASS_SPECMAP_MASK, + LLRenderPass::PASS_SPECMAP_EMISSIVE, + LLRenderPass::PASS_NORMMAP, + LLRenderPass::PASS_ALPHA, //LLRenderPass::PASS_NORMMAP_BLEND, + LLRenderPass::PASS_NORMMAP_MASK, + LLRenderPass::PASS_NORMMAP_EMISSIVE, + LLRenderPass::PASS_NORMSPEC, + LLRenderPass::PASS_ALPHA, //LLRenderPass::PASS_NORMSPEC_BLEND, + LLRenderPass::PASS_NORMSPEC_MASK, + LLRenderPass::PASS_NORMSPEC_EMISSIVE, + }; + + U32 mask = mat->getShaderMask(); + + llassert(mask < sizeof(pass)/sizeof(U32)); + + mask = llmin(mask, (U32)(sizeof(pass)/sizeof(U32)-1)); + + registerFace(group, facep, pass[mask]); + } + else if (facep->getPoolType() == LLDrawPool::POOL_ALPHA) + { + // can we safely treat this as an alpha mask? + if (facep->getFaceColor().mV[3] <= 0.f) + { //100% transparent, don't render unless we're highlighting transparent + registerFace(group, facep, LLRenderPass::PASS_ALPHA_INVISIBLE); + } + else + { + registerFace(group, facep, LLRenderPass::PASS_ALPHA); + } + } + else if (facep->getPoolType() == LLDrawPool::POOL_ALPHA_MASK) + { + registerFace(group, facep, LLRenderPass::PASS_ALPHA_MASK); + } + else if (facep->getPoolType() == LLDrawPool::POOL_FULLBRIGHT_ALPHA_MASK) + { + registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK); + } + else + { + if (facep->getPoolType() == LLDrawPool::POOL_SIMPLE) + { + registerFace(group, facep, LLRenderPass::PASS_SIMPLE); + } + else if (facep->getPoolType() == LLDrawPool::POOL_FULLBRIGHT) + { + registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT); + } + else if (facep->getPoolType() == LLDrawPool::POOL_BUMP) + { + llassert_always(mask & LLVertexBuffer::MAP_NORMAL); + + bool is_bump = te->getBumpmap() > 0 && te->getBumpmap() < 18; + + if(is_bump && LLPipeline::sRenderDeferred) + { + llassert_always(mask & LLVertexBuffer::MAP_TANGENT); + } + if(is_shiny_shader || is_shiny_fixed) + { + llassert_always(mask & LLVertexBuffer::MAP_NORMAL); + } + + if(LLPipeline::sRenderDeferred) + { + static const LLCachedControl sh_fullbright_deferred("SHFullbrightDeferred",true); + if(sh_fullbright_deferred && is_fullbright) + { + registerFace(group, facep, is_shiny_shader ? LLRenderPass::PASS_FULLBRIGHT_SHINY : LLRenderPass::PASS_FULLBRIGHT); + if(is_bump) + { + registerFace(group, facep, LLRenderPass::PASS_POST_BUMP); + } + } + else + { + //is_bump should always be true. + registerFace(group, facep, is_bump ? LLRenderPass::PASS_BUMP : LLRenderPass::PASS_SIMPLE); + } + } + else + { + if (is_fullbright ) + { + registerFace(group, facep, is_shiny_shader ? LLRenderPass::PASS_FULLBRIGHT_SHINY : LLRenderPass::PASS_FULLBRIGHT); + } + else + { + registerFace(group, facep, is_shiny_shader ? LLRenderPass::PASS_SHINY : LLRenderPass::PASS_SIMPLE); + } + + if(is_bump) + registerFace(group, facep, LLRenderPass::PASS_BUMP); + + if(is_shiny_fixed) + registerFace(group, facep, LLRenderPass::PASS_SHINY); + } + } + } if (!is_alpha && LLPipeline::sRenderGlow && te->getGlow() > 0.f) { registerFace(group, facep, LLRenderPass::PASS_GLOW); } + } + + //Singu Note: LLFace::mShinyInAlpha has been updated by now. We're good to go. + if (!LLPipeline::sDelayVBUpdate) + { //copy face geometry into vertex buffer + LLDrawable* drawablep = facep->getDrawable(); + LLVOVolume* vobj = drawablep->getVOVolume(); + LLVolume* volume = vobj->getVolume(); + + if (drawablep->isState(LLDrawable::ANIMATED_CHILD)) + { + vobj->updateRelativeXform(true); + } + + U32 te_idx = facep->getTEOffset(); + + llassert(!facep->isState(LLFace::RIGGED)); + + if (!facep->getGeometryVolume(*volume, te_idx, + vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), index_offset,true)) + { + LL_WARNS() << "Failed to get geometry for face!" << LL_ENDL; + } + + if (drawablep->isState(LLDrawable::ANIMATED_CHILD)) + { + vobj->updateRelativeXform(false); + } + } + + index_offset += facep->getGeomCount(); + indices_index += facep->getIndicesCount(); ++face_iter; } + if(index_offset > 0) + { + buffer->validateRange(0, index_offset - 1, indices_index, 0); + } + buffer->flush(); } - group->mBufferMap[mask].clear(); - for (LLSpatialGroup::buffer_texture_map_t::iterator i = buffer_map[mask].begin(); i != buffer_map[mask].end(); ++i) + auto buffVec = get_val_in_pair_vec(group->mBufferVec, mask); + buffVec.clear(); + auto map = get_val_in_pair_vec(buffer_vec, mask); + for (LLSpatialGroup::buffer_texture_vec_t::iterator i = map.begin(); i != map.end(); ++i) { - group->mBufferMap[mask][i->first] = i->second; + get_val_in_pair_vec(buffVec, i->first) = i->second; } } void LLGeometryManager::addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32 &index_count) { //initialize to default usage for this partition - U32 usage = group->mSpatialPartition->mBufferUsage; + U32 usage = group->getSpatialPartition()->mBufferUsage; //clear off any old faces mFaceList.clear(); //for each drawable - OctreeGuard guard(group->mOctreeNode); + OctreeGuard guard(group->getOctreeNode()); for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter) { - LLDrawable* drawablep = *drawable_iter; + LLDrawable* drawablep = (LLDrawable*)(*drawable_iter)->getDrawable(); if (drawablep->isDead()) { @@ -5416,7 +7147,8 @@ void LLGeometryManager::addGeometryCount(LLSpatialGroup* group, U32 &vertex_coun group->mBufferUsage = usage; } -LLHUDPartition::LLHUDPartition() +LLHUDPartition::LLHUDPartition(LLViewerRegion* regionp) + : LLBridgePartition(regionp) { mPartitionType = LLViewerRegion::PARTITION_HUD; mDrawableType = LLPipeline::RENDER_TYPE_HUD; @@ -5424,9 +7156,4 @@ LLHUDPartition::LLHUDPartition() mLODPeriod = 1; } -void LLHUDPartition::shift(const LLVector4a &offset) -{ - //HUD objects don't shift with region crossing. That would be silly. -} - diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h index 029096ef67..db91548e8b 100644 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -61,9 +61,10 @@ enum LLVolumeInterfaceType class LLRiggedVolume : public LLVolume { + U64 mFrame; public: LLRiggedVolume(const LLVolumeParams& params) - : LLVolume(params, 0.f) + : LLVolume(params, 0.f), mFrame(-1) { } @@ -86,14 +87,14 @@ class LLVolumeInterface virtual bool isVolumeUnique() const = 0; // Do we need a unique LLVolume instance? virtual bool isVolumeGlobal() const = 0; // Are we in global space? virtual bool isActive() const = 0; // Is this object currently active? - virtual const LLMatrix4& getWorldMatrix(LLXformMatrix* xform) const = 0; + virtual const LLMatrix4a& getWorldMatrix(LLXformMatrix* xform) const = 0; virtual void updateRelativeXform(bool force_identity = false) = 0; virtual U32 getID() const = 0; virtual void preRebuild() = 0; }; // Class which embodies all Volume objects (with pcode LL_PCODE_VOLUME) -class LLVOVolume : public LLViewerObject +class LLVOVolume final : public LLViewerObject { LOG_CLASS(LLVOVolume); protected: @@ -113,9 +114,21 @@ class LLVOVolume : public LLViewerObject (1 << LLVertexBuffer::TYPE_COLOR) }; + void* operator new(size_t size) + { + return ll_aligned_malloc_16(size); + } + + void operator delete(void* ptr) + { + ll_aligned_free_16(ptr); + } + public: LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp); - /*virtual*/ void markDead(); // Override (and call through to parent) to clean up media references + + LLVOVolume* asVolume() final; + /*virtual*/ void markDead() override; // Override (and call through to parent) to clean up media references /*virtual*/ LLDrawable* createDrawable(LLPipeline *pipeline); @@ -132,24 +145,30 @@ class LLVOVolume : public LLViewerObject void generateSilhouette(LLSelectNode* nodep, const LLVector3& view_point); /*virtual*/ BOOL setParent(LLViewerObject* parent); S32 getLOD() const { return mLOD; } + void setNoLOD() { mLOD = NO_LOD; mLODChanged = TRUE; } + bool isNoLOD() const { return NO_LOD == mLOD; } const LLVector3 getPivotPositionAgent() const; - const LLMatrix4& getRelativeXform() const { return mRelativeXform; } - const LLMatrix3& getRelativeXformInvTrans() const { return mRelativeXformInvTrans; } - /*virtual*/ const LLMatrix4 getRenderMatrix() const; + const LLMatrix4a& getRelativeXform() const { return mRelativeXform; } + const LLMatrix4a& getRelativeXformInvTrans() const { return mRelativeXformInvTrans; } + /*virtual*/ const LLMatrix4a& getRenderMatrix() const; typedef std::map texture_cost_t; U32 getRenderCost(texture_cost_t &textures) const; - /*virtual*/ F32 getStreamingCost(S32* bytes = NULL, S32* visible_bytes = NULL, F32* unscaled_value = NULL) const; + /*virtual*/ F32 getEstTrianglesMax() const; + /*virtual*/ F32 getEstTrianglesStreamingCost() const; + /* virtual*/ F32 getStreamingCost() const; + /*virtual*/ bool getCostData(LLMeshCostData& costs) const; /*virtual*/ U32 getTriangleCount(S32* vcount = NULL) const; /*virtual*/ U32 getHighLODTriangleCount(); - /*virtual*/ BOOL lineSegmentIntersect(const LLVector3& start, const LLVector3& end, + /*virtual*/ BOOL lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, S32 face = -1, // which face to check, -1 = ALL_SIDES BOOL pick_transparent = FALSE, + BOOL pick_rigged = FALSE, S32* face_hit = NULL, // which face was hit - LLVector3* intersection = NULL, // return the intersection point + LLVector4a* intersection = NULL, // return the intersection point LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point - LLVector3* normal = NULL, // return the surface normal at the intersection point - LLVector3* bi_normal = NULL // return the surface bi-normal at the intersection point + LLVector4a* normal = NULL, // return the surface normal at the intersection point + LLVector4a* tangent = NULL // return the surface tangent at the intersection point ); LLVector3 agentPositionToVolume(const LLVector3& pos) const; @@ -161,9 +180,11 @@ class LLVOVolume : public LLViewerObject BOOL getVolumeChanged() const { return mVolumeChanged; } /*virtual*/ F32 getRadius() const { return mVObjRadius; }; - const LLMatrix4& getWorldMatrix(LLXformMatrix* xform) const; + const LLMatrix4a& getWorldMatrix(LLXformMatrix* xform) const; - void markForUpdate(BOOL priority) { LLViewerObject::markForUpdate(priority); mVolumeChanged = TRUE; } + void markForUpdate(BOOL priority); + void markForUnload() { LLViewerObject::markForUnload(TRUE); mVolumeChanged = TRUE; } + void faceMappingChanged() { mFaceMappingChanged=TRUE; }; /*virtual*/ void onShift(const LLVector4a &shift_vector); // Called when the drawable shifts @@ -205,10 +226,10 @@ class LLVOVolume : public LLViewerObject /*virtual*/ BOOL setMaterial(const U8 material); void setTexture(const S32 face); - S32 getIndexInTex() const {return mIndexInTex ;} + S32 getIndexInTex(U32 ch) const {return mIndexInTex[ch];} /*virtual*/ BOOL setVolume(const LLVolumeParams &volume_params, const S32 detail, bool unique_volume = false); void updateSculptTexture(); - void setIndexInTex(S32 index) { mIndexInTex = index ;} + void setIndexInTex(U32 ch, S32 index) { mIndexInTex[ch] = index ;} void sculpt(); static void rebuildMeshAssetCallback(LLVFS *vfs, const LLUUID& asset_uuid, @@ -262,13 +283,28 @@ class LLVOVolume : public LLViewerObject virtual BOOL isFlexible() const; virtual BOOL isSculpted() const; virtual BOOL isMesh() const; + virtual BOOL isRiggedMesh() const; virtual BOOL hasLightTexture() const; BOOL isVolumeGlobal() const; BOOL canBeFlexible() const; BOOL setIsFlexible(BOOL is_flexible); - + const LLMeshSkinInfo* getSkinInfo() const; + + // Extended Mesh Properties + U32 getExtendedMeshFlags() const; + void onSetExtendedMeshFlags(U32 flags); + void setExtendedMeshFlags(U32 flags); + bool canBeAnimatedObject() const; + bool isAnimatedObject() const; + virtual void onReparent(LLViewerObject *old_parent, LLViewerObject *new_parent); + virtual void afterReparent(); + + //virtual + void updateRiggingInfo(); + S32 mLastRiggingInfoLOD; + // Functions that deal with media, or media navigation // Update this object's media data with the given media data array @@ -306,6 +342,8 @@ class LLVOVolume : public LLViewerObject // tag: vaa emerald local_asset_browser void setSculptChanged(BOOL has_changed) { mSculptChanged = has_changed; } + // Flag any corresponding avatars as needing update. + void updateVisualComplexity(); void notifyMeshLoaded(); // Returns 'true' iff the media data for this object is in flight @@ -320,7 +358,7 @@ class LLVOVolume : public LLViewerObject //rigged volume update (for raycasting) - void updateRiggedVolume(); + void updateRiggedVolume(bool force_update = false); LLRiggedVolume* getRiggedVolume(); //returns true if volume should be treated as a rigged volume @@ -334,7 +372,7 @@ class LLVOVolume : public LLViewerObject void clearRiggedVolume(); protected: - S32 computeLODDetail(F32 distance, F32 radius); + S32 computeLODDetail(F32 distance, F32 radius, F32 lod_factor); BOOL calcLOD(); LLFace* addFace(S32 face_index); void updateTEData(); @@ -347,6 +385,10 @@ class LLVOVolume : public LLViewerObject void cleanUpMediaImpls(); void addMediaImpl(LLViewerMediaImpl* media_impl, S32 texture_index) ; void removeMediaImpl(S32 texture_index) ; + +private: + bool lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled); + public: static S32 getRenderComplexityMax() {return mRenderComplexity_last;} @@ -354,6 +396,9 @@ class LLVOVolume : public LLViewerObject LLViewerTextureAnim *mTextureAnimp; U8 mTexAnimMode; + F32 mLODDistance; + F32 mLODAdjustedDistance; + F32 mLODRadius; private: friend class LLDrawable; friend class LLFace; @@ -364,8 +409,8 @@ class LLVOVolume : public LLViewerObject BOOL mLODChanged; BOOL mSculptChanged; F32 mSpotLightPriority; - LLMatrix4 mRelativeXform; - LLMatrix3 mRelativeXformInvTrans; + LL_ALIGN_16(LLMatrix4a mRelativeXform); + LL_ALIGN_16(LLMatrix4a mRelativeXformInvTrans); BOOL mVolumeChanged; F32 mVObjRadius; LLVolumeInterface *mVolumeImpl; @@ -373,7 +418,7 @@ class LLVOVolume : public LLViewerObject LLPointer mLightTexture; media_list_t mMediaImplList; S32 mLastFetchedMediaVersion; // as fetched from the server, starts as -1 - S32 mIndexInTex; + S32 mIndexInTex[LLRender::NUM_VOLUME_TEXTURE_CHANNELS]; S32 mMDCImplCount; LLPointer mRiggedVolume; @@ -391,6 +436,26 @@ class LLVOVolume : public LLViewerObject static S32 sNumLODChanges; friend class LLVolumeImplFlexible; + +public: + bool notifyAboutCreatingTexture(LLViewerTexture *texture); + bool notifyAboutMissingAsset(LLViewerTexture *texture); + +private: + struct material_info + { + LLRender::eTexIndex map; + U8 te; + + material_info(LLRender::eTexIndex map_, U8 te_) + : map(map_) + , te(te_) + {} + }; + + typedef std::multimap mmap_UUID_MAP_t; + mmap_UUID_MAP_t mWaitingTextureInfo; + }; #endif // LL_LLVOVOLUME_H diff --git a/indra/newview/llvowater.cpp b/indra/newview/llvowater.cpp index 049a89d1af..7e97a601d0 100644 --- a/indra/newview/llvowater.cpp +++ b/indra/newview/llvowater.cpp @@ -74,7 +74,10 @@ LLVOWater::LLVOWater(const LLUUID &id, { // Terrain must draw during selection passes so it can block objects behind it. mbCanSelect = FALSE; - setScale(LLVector3(256.f, 256.f, 0.f)); // Hack for setting scale for bounding boxes/visibility. +// Aurora Sim + //setScale(LLVector3(256.f, 256.f, 0.f)); // Hack for setting scale for bounding boxes/visibility. + setScale(LLVector3(mRegionp->getWidth(), mRegionp->getWidth(), 0.f)); +// Aurora Sim mUseTexture = TRUE; mIsEdgePatch = FALSE; @@ -130,11 +133,11 @@ LLDrawable *LLVOWater::createDrawable(LLPipeline *pipeline) return mDrawable; } -static LLFastTimer::DeclareTimer FTM_UPDATE_WATER("Update Water"); +static LLTrace::BlockTimerStatHandle FTM_UPDATE_WATER("Update Water"); BOOL LLVOWater::updateGeometry(LLDrawable *drawable) { - LLFastTimer ftm(FTM_UPDATE_WATER); + LL_RECORD_BLOCK_TIME(FTM_UPDATE_WATER); LLFace *face; if (drawable->getNumFaces() < 1) @@ -163,7 +166,7 @@ BOOL LLVOWater::updateGeometry(LLDrawable *drawable) static const LLCachedControl render_transparent_water("RenderTransparentWater",false); static const LLCachedControl water_subdiv("SianaVoidWaterSubdivision", 16); - const S32 size = (render_transparent_water && LLGLSLShader::sNoFixedFunction) ? water_subdiv : 1; + const S32 size = ((render_transparent_water || LLPipeline::sRenderDeferred) && LLGLSLShader::sNoFixedFunction) ? water_subdiv : 1; const S32 num_quads = size * size; face->setSize(vertices_per_quad * num_quads, indices_per_quad * num_quads); @@ -244,7 +247,6 @@ BOOL LLVOWater::updateGeometry(LLDrawable *drawable) buff->flush(); mDrawable->movePartition(); - LLPipeline::sCompiles++; return TRUE; } @@ -305,15 +307,16 @@ U32 LLVOVoidWater::getPartitionType() const return LLViewerRegion::PARTITION_VOIDWATER; } -LLWaterPartition::LLWaterPartition() -: LLSpatialPartition(0, FALSE, GL_DYNAMIC_DRAW_ARB) +LLWaterPartition::LLWaterPartition(LLViewerRegion* regionp) +: LLSpatialPartition(0, FALSE, GL_DYNAMIC_DRAW_ARB, regionp) { mInfiniteFarClip = TRUE; mDrawableType = LLPipeline::RENDER_TYPE_WATER; mPartitionType = LLViewerRegion::PARTITION_WATER; } -LLVoidWaterPartition::LLVoidWaterPartition() +LLVoidWaterPartition::LLVoidWaterPartition(LLViewerRegion* regionp) + : LLWaterPartition(regionp) { //mOcclusionEnabled = FALSE; mDrawableType = LLPipeline::RENDER_TYPE_VOIDWATER; diff --git a/indra/newview/llvowlsky.cpp b/indra/newview/llvowlsky.cpp index a0c303bf94..8e4cec604e 100644 --- a/indra/newview/llvowlsky.cpp +++ b/indra/newview/llvowlsky.cpp @@ -307,11 +307,11 @@ void LLVOWLSky::restoreGL() gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE); } -static LLFastTimer::DeclareTimer FTM_GEO_SKY("Sky Geometry"); +static LLTrace::BlockTimerStatHandle FTM_GEO_SKY("Sky Geometry"); BOOL LLVOWLSky::updateGeometry(LLDrawable * drawable) { - LLFastTimer ftm(FTM_GEO_SKY); + LL_RECORD_BLOCK_TIME(FTM_GEO_SKY); LLStrider vertices; LLStrider texCoords; LLStrider indices; @@ -327,7 +327,7 @@ BOOL LLVOWLSky::updateGeometry(LLDrawable * drawable) if(!success) { - llerrs << "Failed updating WindLight sky geometry." << llendl; + LL_ERRS() << "Failed updating WindLight sky geometry." << LL_ENDL; } buildFanBuffer(vertices, texCoords, indices); @@ -351,7 +351,7 @@ BOOL LLVOWLSky::updateGeometry(LLDrawable * drawable) // round up to a whole number of segments const U32 strips_segments = (total_stacks+stacks_per_seg-1) / stacks_per_seg; - llinfos << "WL Skydome strips in " << strips_segments << " batches." << llendl; + LL_INFOS() << "WL Skydome strips in " << strips_segments << " batches." << LL_ENDL; mStripsVerts.resize(strips_segments, NULL); @@ -390,7 +390,7 @@ BOOL LLVOWLSky::updateGeometry(LLDrawable * drawable) if(!success) { - llerrs << "Failed updating WindLight sky geometry." << llendl; + LL_ERRS() << "Failed updating WindLight sky geometry." << LL_ENDL; } // fill it @@ -399,7 +399,7 @@ BOOL LLVOWLSky::updateGeometry(LLDrawable * drawable) // and unlock the buffer segment->flush(); } - llinfos << "completed in " << llformat("%.2f", timer.getElapsedTimeF32()) << "seconds" << llendl; + LL_INFOS() << "completed in " << llformat("%.2f", timer.getElapsedTimeF32()) << "seconds" << LL_ENDL; } #else mStripsVerts = new LLVertexBuffer(LLDrawPoolWLSky::SKY_VERTEX_DATA_MASK, GL_STATIC_DRAW_ARB); @@ -484,8 +484,6 @@ BOOL LLVOWLSky::updateGeometry(LLDrawable * drawable) updateStarColors(); updateStarGeometry(drawable); - LLPipeline::sCompiles++; - return TRUE; } @@ -790,7 +788,7 @@ BOOL LLVOWLSky::updateStarGeometry(LLDrawable *drawable) if(!success) { - llerrs << "Failed updating star geometry." << llendl; + LL_ERRS() << "Failed updating star geometry." << LL_ENDL; } // *TODO: fix LLStrider with a real prefix increment operator so it can be @@ -799,7 +797,7 @@ BOOL LLVOWLSky::updateStarGeometry(LLDrawable *drawable) if (mStarVertices.size() < getStarsNumVerts()) { - llerrs << "Star reference geometry insufficient." << llendl; + LL_ERRS() << "Star reference geometry insufficient." << LL_ENDL; } for (U32 vtx = 0; vtx < getStarsNumVerts(); ++vtx) diff --git a/indra/newview/llwatchdog.cpp b/indra/newview/llwatchdog.cpp index 9af050c4c2..c8f9bfc3b0 100644 --- a/indra/newview/llwatchdog.cpp +++ b/indra/newview/llwatchdog.cpp @@ -227,7 +227,7 @@ void LLWatchdog::run() if(current_run_delta > (WATCHDOG_SLEEP_TIME_USEC * TIME_ELAPSED_MULTIPLIER)) { - llinfos << "Watchdog thread delayed: resetting entries." << llendl; + LL_INFOS() << "Watchdog thread delayed: resetting entries." << LL_ENDL; std::for_each(mSuspects.begin(), mSuspects.end(), std::mem_fun(&LLWatchdogEntry::reset) @@ -249,7 +249,7 @@ void LLWatchdog::run() mTimer->stop(); } - llinfos << "Watchdog detected error:" << llendl; + LL_INFOS() << "Watchdog detected error:" << LL_ENDL; mKillerCallback(); } } diff --git a/indra/newview/llwatchdog.h b/indra/newview/llwatchdog.h index 1a10e331dc..9ad803d99d 100644 --- a/indra/newview/llwatchdog.h +++ b/indra/newview/llwatchdog.h @@ -33,7 +33,10 @@ #ifndef LL_LLTHREADWATCHDOG_H #define LL_LLTHREADWATCHDOG_H +#ifndef BOOST_FUNCTION_HPP_INCLUDED #include +#define BOOST_FUNCTION_HPP_INCLUDED +#endif #ifndef LL_TIMER_H #include "lltimer.h" diff --git a/indra/newview/llwaterparammanager.cpp b/indra/newview/llwaterparammanager.cpp index 2e05207cc8..7646620794 100644 --- a/indra/newview/llwaterparammanager.cpp +++ b/indra/newview/llwaterparammanager.cpp @@ -76,6 +76,14 @@ #include "llagentcamera.h" +static LLStaticHashedString sLightNorm ("lightnorm"); +static LLStaticHashedString sCamPosLocal("camPosLocal"); +static LLStaticHashedString sWaterFogColor("waterFogColor"); +static LLStaticHashedString sWaterPlane("waterPlane"); +static LLStaticHashedString sWaterFogDensity("waterFogDensity"); +static LLStaticHashedString sWaterFogKS("waterFogKS"); +static LLStaticHashedString sDistanceMultiplier("distance_multiplier"); + LLWaterParamManager::LLWaterParamManager() : mFogColor(22.f/255.f, 43.f/255.f, 54.f/255.f, 0.0f, 0.0f, "waterFogColor", "WaterFogColor"), mFogDensity(4, "waterFogDensity", 2), @@ -108,7 +116,7 @@ void LLWaterParamManager::loadAllPresets() void LLWaterParamManager::loadPresetsFromDir(const std::string& dir) { - LL_INFOS2("AppInit", "Shaders") << "Loading water presets from " << dir << LL_ENDL; + LL_INFOS("AppInit", "Shaders") << "Loading water presets from " << dir << LL_ENDL; LLDirIterator dir_iter(dir, "*.xml"); while (1) @@ -122,7 +130,7 @@ void LLWaterParamManager::loadPresetsFromDir(const std::string& dir) std::string path = dir + file; if (!loadPreset(path)) { - llwarns << "Error loading water preset from " << path << llendl; + LL_WARNS() << "Error loading water preset from " << path << LL_ENDL; } } } @@ -138,7 +146,7 @@ bool LLWaterParamManager::loadPreset(const std::string& path) return false; } - LL_DEBUGS2("AppInit", "Shaders") << "Loading water " << name << LL_ENDL; + LL_DEBUGS("AppInit", "Shaders") << "Loading water " << name << LL_ENDL; LLSD params_data; LLPointer parser = new LLSDXMLParser(); @@ -298,7 +306,7 @@ bool LLWaterParamManager::savePresetToNotecard(const std::string & name) void LLWaterParamManager::propagateParameters(void) { // bind the variables only if we're using shaders - if(gPipeline.canUseVertexShaders()) + if(LLGLSLShader::sNoFixedFunction) { std::vector::iterator shaders_iter=mShaderList.begin(); for(; shaders_iter != mShaderList.end(); ++shaders_iter) @@ -320,12 +328,12 @@ void LLWaterParamManager::updateShaderUniforms(LLGLSLShader * shader) if (shader->mShaderGroup == LLGLSLShader::SG_WATER) { shader->uniform4fv(LLViewerShaderMgr::LIGHTNORM, 1, LLWLParamManager::getInstance()->getRotatedLightDir().mV); - shader->uniform3fv("camPosLocal", 1, LLViewerCamera::getInstance()->getOrigin().mV); - shader->uniform4fv("waterFogColor", 1, LLDrawPoolWater::sWaterFogColor.mV); - shader->uniform4fv("waterPlane", 1, mWaterPlane.mV); - shader->uniform1f("waterFogDensity", getFogDensity()); - shader->uniform1f("waterFogKS", mWaterFogKS); - shader->uniform1f("distance_multiplier", 0); + shader->uniform3fv(LLShaderMgr::WL_CAMPOSLOCAL, 1, LLViewerCamera::getInstance()->getOrigin().mV); + shader->uniform4fv(LLShaderMgr::WATER_FOGCOLOR, 1, LLDrawPoolWater::sWaterFogColor.mV); + shader->uniform4fv(LLShaderMgr::WATER_WATERPLANE, 1, mWaterPlane.mV); + shader->uniform1f(LLShaderMgr::WATER_FOGDENSITY, getFogDensity()); + shader->uniform1f(LLShaderMgr::WATER_FOGKS, mWaterFogKS); + shader->uniform1f(LLViewerShaderMgr::DISTANCE_MULTIPLIER, 0); } } @@ -333,7 +341,7 @@ void LLWaterParamManager::applyParams(const LLSD& params, bool interpolate) { if (params.size() == 0) { - llwarns << "Undefined water params" << llendl; + LL_WARNS() << "Undefined water params" << LL_ENDL; return; } @@ -347,7 +355,7 @@ void LLWaterParamManager::applyParams(const LLSD& params, bool interpolate) } } -static LLFastTimer::DeclareTimer FTM_UPDATE_WATERPARAM("Update Water Params"); +static LLTrace::BlockTimerStatHandle FTM_UPDATE_WATERPARAM("Update Water Params"); void LLWaterParamManager::updateShaderLinks() { @@ -359,13 +367,13 @@ void LLWaterParamManager::updateShaderLinks() if (shaders_iter->mProgramObject != 0 && shaders_iter->mShaderGroup == LLGLSLShader::SG_WATER) { - if( glGetUniformLocationARB(shaders_iter->mProgramObject,"lightnorm")>=0 || - glGetUniformLocationARB(shaders_iter->mProgramObject,"camPosLocal")>=0 || - glGetUniformLocationARB(shaders_iter->mProgramObject,"waterFogColor")>=0 || - glGetUniformLocationARB(shaders_iter->mProgramObject,"waterPlane")>=0 || - glGetUniformLocationARB(shaders_iter->mProgramObject,"waterFogDensity")>=0 || - glGetUniformLocationARB(shaders_iter->mProgramObject,"waterFogKS")>=0 || - glGetUniformLocationARB(shaders_iter->mProgramObject,"distance_multiplier")>=0) + if( shaders_iter->getUniformLocation(sLightNorm) >=0 || + shaders_iter->getUniformLocation(sCamPosLocal) >=0 || + shaders_iter->getUniformLocation(sWaterFogColor) >=0 || + shaders_iter->getUniformLocation(sWaterPlane) >=0 || + shaders_iter->getUniformLocation(sWaterFogDensity) >=0 || + shaders_iter->getUniformLocation(sWaterFogKS) >=0 || + shaders_iter->getUniformLocation(sDistanceMultiplier) >=0) mShaderList.push_back(&(*shaders_iter)); } } @@ -373,7 +381,7 @@ void LLWaterParamManager::updateShaderLinks() void LLWaterParamManager::update(LLViewerCamera * cam) { - LLFastTimer ftm(FTM_UPDATE_WATERPARAM); + LL_RECORD_BLOCK_TIME(FTM_UPDATE_WATERPARAM); // update the shaders and the menu propagateParameters(); @@ -387,27 +395,26 @@ void LLWaterParamManager::update(LLViewerCamera * cam) stop_glerror(); // only do this if we're dealing with shaders - if(gPipeline.canUseVertexShaders()) + if(LLGLSLShader::sNoFixedFunction) { //transform water plane to eye space - glh::vec3f norm(0.f, 0.f, 1.f); - glh::vec3f p(0.f, 0.f, gAgent.getRegion()->getWaterHeight()+0.1f); + LLVector4a enorm(0.f, 0.f, 1.f); + LLVector4a ep(0.f, 0.f, gAgent.getRegion()->getWaterHeight()+0.1f); - F32 modelView[16]; - for (U32 i = 0; i < 16; i++) - { - modelView[i] = (F32) gGLModelView[i]; - } + const LLMatrix4a& mat = gGLModelView; + LLMatrix4a invtrans = mat; + invtrans.invert(); + invtrans.transpose(); + + invtrans.perspectiveTransform(enorm,enorm); + enorm.normalize3fast(); + mat.affineTransform(ep,ep); - glh::matrix4f mat(modelView); - glh::matrix4f invtrans = mat.inverse().transpose(); - glh::vec3f enorm; - glh::vec3f ep; - invtrans.mult_matrix_vec(norm, enorm); - enorm.normalize(); - mat.mult_matrix_vec(p, ep); + ep.setAllDot3(ep,enorm); + ep.negate(); + enorm.copyComponent<3>(ep); - mWaterPlane = LLVector4(enorm.v[0], enorm.v[1], enorm.v[2], -ep.dot(enorm)); + mWaterPlane.set(enorm.getF32ptr()); LLVector3 sunMoonDir; if (gSky.getSunDirection().mV[2] > LLSky::NIGHTTIME_ELEVATION_COS) diff --git a/indra/newview/llwearablelist.cpp b/indra/newview/llwearablelist.cpp index 43685188d9..6efd8aab25 100644 --- a/indra/newview/llwearablelist.cpp +++ b/indra/newview/llwearablelist.cpp @@ -98,7 +98,23 @@ void LLWearableList::processGetAssetReply( const char* filename, const LLAssetID { BOOL isNewWearable = FALSE; LLWearableArrivedData* data = (LLWearableArrivedData*) userdata; - LLViewerWearable* wearable = NULL; // NULL indicates failure +// LLViewerWearable* wearable = NULL; // NULL indicates failure +// [SL:KB] - Patch: Appearance-Misc | Checked: 2010-08-13 (Catznip-2.1) + LLViewerWearable* wearable = get_if_there(LLWearableList::instance().mList, uuid, (LLViewerWearable*)NULL); + if (wearable) + { + LL_DEBUGS("Wearable") << "processGetAssetReply()" << LL_ENDL; + LL_DEBUGS("Wearable") << wearable << LL_ENDL; + + if(data->mCallback) + { + data->mCallback(wearable, data->mUserdata); + } + delete data; + + return; + } +// [/SL:KB] LLAvatarAppearance *avatarp = data->mAvatarp; if( !filename ) @@ -217,7 +233,7 @@ void LLWearableList::processGetAssetReply( const char* filename, const LLAssetID LLViewerWearable* LLWearableList::createCopy(const LLViewerWearable* old_wearable, const std::string& new_name, const std::string& new_description) { - lldebugs << "LLWearableList::createCopy()" << llendl; + LL_DEBUGS() << "LLWearableList::createCopy()" << LL_ENDL; LLViewerWearable *wearable = generateNewWearable(); wearable->copyDataFrom(old_wearable); @@ -237,7 +253,7 @@ LLViewerWearable* LLWearableList::createCopy(const LLViewerWearable* old_wearabl LLViewerWearable* LLWearableList::createNewWearable( LLWearableType::EType type, LLAvatarAppearance *avatarp ) { - lldebugs << "LLWearableList::createNewWearable()" << llendl; + LL_DEBUGS() << "LLWearableList::createNewWearable()" << LL_ENDL; LLViewerWearable *wearable = generateNewWearable(); wearable->setType( type, avatarp ); diff --git a/indra/newview/llweb.cpp b/indra/newview/llweb.cpp index 514db939c3..b99ff33509 100644 --- a/indra/newview/llweb.cpp +++ b/indra/newview/llweb.cpp @@ -41,23 +41,23 @@ #include "llagent.h" #include "llappviewer.h" #include "llfloaterwebcontent.h" +#include "hippogridmanager.h" #include "llparcel.h" #include "llsd.h" +#include "llalertdialog.h" #include "llui.h" #include "lluri.h" +#include "llversioninfo.h" #include "llviewercontrol.h" -#include "llviewermedia.h" #include "llviewernetwork.h" #include "llviewerparcelmgr.h" #include "llviewerregion.h" #include "llviewerwindow.h" #include "llnotificationsutil.h" -#include "llalertdialog.h" - -#include "sgversion.h" bool on_load_url_external_response(const LLSD& notification, const LLSD& response, bool async ); + class URLLoader : public LLAlertDialog::URLLoader { virtual void load(const std::string& url , bool force_open_externally) @@ -126,7 +126,7 @@ void LLWeb::loadURLExternal(const std::string& url, bool async, const std::strin if(gSavedSettings.getBOOL("DisableExternalBrowser")) { // Don't open an external browser under any circumstances. - llwarns << "Blocked attempt to open external browser." << llendl; + LL_WARNS() << "Blocked attempt to open external browser." << LL_ENDL; return; } @@ -208,26 +208,27 @@ std::string LLWeb::escapeURL(const std::string& url) return escaped_url; } +std::string getLoginUriDomain(); //static std::string LLWeb::expandURLSubstitutions(const std::string &url, const LLSD &default_subs) { - gCurrentVersion = llformat("%s %d.%d.%d.%d", - gVersionChannel, - gVersionMajor, - gVersionMinor, - gVersionPatch, - gVersionBuild ); - LLSD substitution = default_subs; - substitution["VERSION"] = gCurrentVersion; - substitution["VERSION_MAJOR"] = gVersionMajor; - substitution["VERSION_MINOR"] = gVersionMinor; - substitution["VERSION_PATCH"] = gVersionPatch; - substitution["VERSION_BUILD"] = gVersionBuild; - substitution["CHANNEL"] = gVersionChannel; - substitution["GRID"] = LLViewerLogin::getInstance()->getGridLabel(); - substitution["GRID_LOWERCASE"] = utf8str_tolower(LLViewerLogin::getInstance()->getGridLabel()); + substitution["VERSION"] = LLVersionInfo::getVersion(); + substitution["VERSION_MAJOR"] = LLVersionInfo::getMajor(); + substitution["VERSION_MINOR"] = LLVersionInfo::getMinor(); + substitution["VERSION_PATCH"] = LLVersionInfo::getPatch(); + substitution["VERSION_BUILD"] = LLVersionInfo::getBuild(); + substitution["CHANNEL"] = LLVersionInfo::getChannel(); + const HippoGridInfo* grid(gHippoGridManager->getCurrentGrid()); + std::string gridId(grid->isSecondLife() ? getLoginUriDomain() : grid->getGridName()); + if (grid->isSecondLife()) + { + gridId = gridId.substr(0, gridId.find('.')); + } + + substitution["GRID"] = gridId; + substitution["GRID_LOWERCASE"] = utf8str_tolower(gridId); substitution["OS"] = LLAppViewer::instance()->getOSInfo().getOSStringSimple(); substitution["SESSION_ID"] = gAgent.getSessionID(); substitution["FIRST_LOGIN"] = gAgent.isFirstLogin(); @@ -258,8 +259,7 @@ std::string LLWeb::expandURLSubstitutions(const std::string &url, { parcel_id = parcel->getLocalID(); } - substitution["PARCEL_ID"] = llformat("%d", parcel_id); - + substitution["PARCEL_ID"] = fmt::to_string(parcel_id); // expand all of the substitution strings and escape the url std::string expanded_url = url; LLStringUtil::format(expanded_url, substitution); diff --git a/indra/newview/llwebprofile.cpp b/indra/newview/llwebprofile.cpp index 7286766c65..db258fbdb8 100644 --- a/indra/newview/llwebprofile.cpp +++ b/indra/newview/llwebprofile.cpp @@ -32,14 +32,13 @@ #include "llbufferstream.h" #include "llhttpclient.h" #include "llimagepng.h" -#include "llplugincookiestore.h" +//#include "llplugincookiestore.h" // newview #include "llpanelprofile.h" // getProfileURL (this is the original location LL put it). #include "llviewermedia.h" // FIXME: don't use LLViewerMedia internals -// third-party JSONCPP -#include // JSONCPP +#include "llsdjson.h" /* * Workflow: @@ -69,29 +68,24 @@ class LLWebProfileResponders::ConfigResponder : public LLHTTPClient::ResponderWi { } - /*virtual*/ void completedRaw( - U32 status, - const std::string& reason, - const LLChannelDescriptors& channels, - const buffer_ptr_t& buffer) + /*virtual*/ void completedRaw(LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) { LLBufferStream istr(channels, buffer.get()); std::stringstream strstrm; strstrm << istr.rdbuf(); const std::string body = strstrm.str(); - if (status != 200) + if (mStatus != HTTP_OK) { - llwarns << "Failed to get upload config (" << status << ")" << llendl; + LL_WARNS() << "Failed to get upload config (" << mStatus << ')' << LL_ENDL; LLWebProfile::reportImageUploadStatus(false); return; } - Json::Value root; - Json::Reader reader; - if (!reader.parse(body, root)) + auto root = LlsdFromJsonString(body); + if (root.isUndefined()) { - llwarns << "Failed to parse upload config: " << reader.getFormatedErrorMessages() << llendl; + LL_WARNS() << "Failed to get valid json body" << LL_ENDL; LLWebProfile::reportImageUploadStatus(false); return; } @@ -100,27 +94,19 @@ class LLWebProfileResponders::ConfigResponder : public LLHTTPClient::ResponderWi // *TODO: increase timeout or handle HTTP_INTERNAL_ERROR_* time errors. // Convert config to LLSD. - const Json::Value data = root["data"]; + const auto data = root["data"]; const std::string upload_url = root["url"].asString(); - LLSD config; - config["acl"] = data["acl"].asString(); - config["AWSAccessKeyId"] = data["AWSAccessKeyId"].asString(); - config["Content-Type"] = data["Content-Type"].asString(); - config["key"] = data["key"].asString(); - config["policy"] = data["policy"].asString(); - config["success_action_redirect"] = data["success_action_redirect"].asString(); - config["signature"] = data["signature"].asString(); - config["add_loc"] = data.get("add_loc", "0").asString(); - config["caption"] = data.get("caption", "").asString(); + LLSD config = data; + if (!data.has("add_loc")) config["add_loc"] = "0"; + if (!data.has("caption")) config["caption"] = LLStringUtil::null; // Do the actual image upload using the configuration. - LL_DEBUGS("Snapshots") << "Got upload config, POSTing image to " << upload_url << ", config=[" << config << "]" << LL_ENDL; + LL_DEBUGS("Snapshots") << "Got upload config, POSTing image to " << upload_url << ", config=[" << config << ']' << LL_ENDL; LLWebProfile::post(mImagep, config, upload_url); } protected: /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return webProfileResponders_timeout; } - /*virtual*/ bool followRedir(void) const { return true; } /*virtual*/ char const* getName(void) const { return "LLWebProfileResponders::ConfigResponder"; } private: @@ -134,15 +120,11 @@ class LLWebProfileResponders::PostImageRedirectResponder : public LLHTTPClient:: LOG_CLASS(LLWebProfileResponders::PostImageRedirectResponder); public: - /*virtual*/ void completedRaw( - U32 status, - const std::string& reason, - const LLChannelDescriptors& channels, - const buffer_ptr_t& buffer) + /*virtual*/ void completedRaw(LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) { - if (status != 200) + if (mStatus != HTTP_OK) { - llwarns << "Failed to upload image: " << status << " " << reason << llendl; + LL_WARNS() << "Failed to upload image: " << mStatus << ' ' << mReason << LL_ENDL; LLWebProfile::reportImageUploadStatus(false); return; } @@ -151,13 +133,12 @@ class LLWebProfileResponders::PostImageRedirectResponder : public LLHTTPClient:: std::stringstream strstrm; strstrm << istr.rdbuf(); const std::string body = strstrm.str(); - llinfos << "Image uploaded." << llendl; - LL_DEBUGS("Snapshots") << "Uploading image succeeded. Response: [" << body << "]" << LL_ENDL; + LL_INFOS() << "Image uploaded." << LL_ENDL; + LL_DEBUGS("Snapshots") << "Uploading image succeeded. Response: [" << body << ']' << LL_ENDL; LLWebProfile::reportImageUploadStatus(true); } protected: - /*virtual*/ bool followRedir(void) const { return true; } /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return webProfileResponders_timeout; } /*virtual*/ char const* getName(void) const { return "LLWebProfileResponders::PostImageRedirectResponder"; } @@ -175,40 +156,38 @@ class LLWebProfileResponders::PostImageResponder : public LLHTTPClient::Responde public: /*virtual*/ bool needsHeaders(void) const { return true; } - /*virtual*/ void completedHeaders(U32 status, std::string const& reason, AIHTTPReceivedHeaders const& received_headers) + /*virtual*/ void completedHeaders(void) { // Server abuses 303 status; Curl can't handle it because it tries to resent // the just uploaded data, which fails // (CURLE_SEND_FAIL_REWIND: Send failed since rewinding of the data stream failed). // Handle it manually. - if (status == 303) + if (mStatus == HTTP_SEE_OTHER) { AIHTTPHeaders headers; headers.addHeader("Accept", "*/*"); headers.addHeader("Cookie", LLWebProfile::getAuthCookie()); headers.addHeader("User-Agent", LLViewerMedia::getCurrentUserAgent()); std::string redir_url; - received_headers.getFirstValue("location", redir_url); + mReceivedHeaders.getFirstValue("location", redir_url); LL_DEBUGS("Snapshots") << "Got redirection URL: " << redir_url << LL_ENDL; LLHTTPClient::get(redir_url, new LLWebProfileResponders::PostImageRedirectResponder, headers); } else { - llwarns << "Unexpected POST status: " << status << " " << reason << llendl; - LL_DEBUGS("Snapshots") << "received_headers: [" << received_headers << "]" << LL_ENDL; + LL_WARNS() << "Unexpected POST status: " << mStatus << ' ' << mReason << LL_ENDL; + LL_DEBUGS("Snapshots") << "received_headers: [" << mReceivedHeaders << ']' << LL_ENDL; LLWebProfile::reportImageUploadStatus(false); } } // Override just to suppress warnings. - /*virtual*/ void completedRaw(U32 status, const std::string& reason, - const LLChannelDescriptors& channels, - const buffer_ptr_t& buffer) + /*virtual*/ void completedRaw(LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) { } protected: - /*virtual*/ bool redirect_status_ok(void) const { return true; } + /*virtual*/ bool pass_redirect_status(void) const { return true; } /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return webProfileResponders_timeout; } /*virtual*/ char const* getName(void) const { return "LLWebProfileResponders::PostImageResponder"; } }; @@ -247,7 +226,7 @@ void LLWebProfile::post(LLPointer image, const LLSD& config, c { if (dynamic_cast(image.get()) == 0) { - llwarns << "Image to upload is not a PNG" << llendl; + LL_WARNS() << "Image to upload is not a PNG" << LL_ENDL; llassert(dynamic_cast(image.get()) != 0); return; } @@ -302,7 +281,7 @@ void LLWebProfile::post(LLPointer image, const LLSD& config, c size_t size = body_size + image->getDataSize() + footer_size; // postRaw() takes ownership of the buffer and releases it later. - char* data = new char [size]; + U8* data = new U8 [size]; memcpy(data, body.str().data(), body_size); // Insert the image data. memcpy(data + body_size, image->getData(), image->getDataSize()); diff --git a/indra/newview/llwind.cpp b/indra/newview/llwind.cpp index 2b0f0d9693..62df312c70 100644 --- a/indra/newview/llwind.cpp +++ b/indra/newview/llwind.cpp @@ -47,10 +47,9 @@ #include "patch_code.h" // viewer -#include "noise.h" #include "v4color.h" #include "llagent.h" -#include "llworld.h" +#include "llviewerregion.h" const F32 CLOUD_DIVERGENCE_COEF = 0.5f; @@ -254,7 +253,10 @@ LLVector3 LLWind::getVelocity(const LLVector3 &pos_region) LLVector3 pos_clamped_region(pos_region); - F32 region_width_meters = LLWorld::getInstance()->getRegionWidthInMeters(); +// Aurora Sim + //F32 region_width_meters = LLWorld::getInstance()->getRegionWidthInMeters(); + F32 region_width_meters = gAgent.getRegion()->getWidth(); +// Aurora Sim if (pos_clamped_region.mV[VX] < 0.f) { @@ -321,7 +323,7 @@ LLVector3 LLWind::getCloudVelocity(const LLVector3 &pos_region) LLVector3 pos_clamped_region(pos_region); - F32 region_width_meters = LLWorld::getInstance()->getRegionWidthInMeters(); + F32 region_width_meters = gAgent.getRegion()->getWidth(); if (pos_clamped_region.mV[VX] < 0.f) { diff --git a/indra/newview/llwindebug.cpp b/indra/newview/llwindebug.cpp index 5c7ee642d6..446b9b96f5 100644 --- a/indra/newview/llwindebug.cpp +++ b/indra/newview/llwindebug.cpp @@ -2,98 +2,35 @@ * @file llwindebug.cpp * @brief Windows debugging functions * - * $LicenseInfo:firstyear=2004&license=viewergpl$ - * - * Copyright (c) 2004-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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 -#include #include "llwindebug.h" -#include "llviewercontrol.h" #include "lldir.h" -#include "llsd.h" -#include "llsdserialize.h" #pragma warning(disable: 4200) //nonstandard extension used : zero-sized array in struct/union #pragma warning(disable: 4100) //unreferenced formal parameter - -/* -LLSD Block for Windows Dump Information - - - Platform - - Process - - Module - - DateModified - - ExceptionCode - - ExceptionRead/WriteAddress - - Instruction - - Registers - - - EIP - ... - - - Call Stack - - - - ModuleName - - ModuleBaseAddress - - ModuleOffsetAddress - - Parameters - - - - - - - - - -*/ - - -extern void (*gCrashCallback)(void); - // based on dbghelp.h typedef BOOL (WINAPI *MINIDUMPWRITEDUMP)(HANDLE hProcess, DWORD dwPid, HANDLE hFile, MINIDUMP_TYPE DumpType, CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, @@ -103,527 +40,6 @@ typedef BOOL (WINAPI *MINIDUMPWRITEDUMP)(HANDLE hProcess, DWORD dwPid, HANDLE hF MINIDUMPWRITEDUMP f_mdwp = NULL; -#undef UNICODE - -static LPTOP_LEVEL_EXCEPTION_FILTER gFilterFunc = NULL; - -HMODULE hDbgHelp; - -// Tool Help functions. -typedef HANDLE (WINAPI * CREATE_TOOL_HELP32_SNAPSHOT)(DWORD dwFlags, DWORD th32ProcessID); -typedef BOOL (WINAPI * MODULE32_FIRST)(HANDLE hSnapshot, LPMODULEENTRY32 lpme); -typedef BOOL (WINAPI * MODULE32_NEST)(HANDLE hSnapshot, LPMODULEENTRY32 lpme); - -CREATE_TOOL_HELP32_SNAPSHOT CreateToolhelp32Snapshot_; -MODULE32_FIRST Module32First_; -MODULE32_NEST Module32Next_; - -#define DUMP_SIZE_MAX 8000 //max size of our dump -#define CALL_TRACE_MAX ((DUMP_SIZE_MAX - 2000) / (MAX_PATH + 40)) //max number of traced calls -#define NL L"\r\n" //new line - - -typedef struct STACK -{ - STACK * Ebp; - PBYTE Ret_Addr; - DWORD Param[0]; -} STACK, * PSTACK; - -BOOL WINAPI Get_Module_By_Ret_Addr(PBYTE Ret_Addr, LPWSTR Module_Name, PBYTE & Module_Addr); -void WINAPI Get_Call_Stack(const EXCEPTION_RECORD* exception_record, - const CONTEXT* context_record, - LLSD& info); - -void printError( CHAR* msg ) -{ - DWORD eNum; - TCHAR sysMsg[256]; - TCHAR* p; - - eNum = GetLastError( ); - FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, eNum, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language - sysMsg, 256, NULL ); - - // Trim the end of the line and terminate it with a null - p = sysMsg; - while( ( *p > 31 ) || ( *p == 9 ) ) - ++p; - do { *p-- = 0; } while( ( p >= sysMsg ) && - ( ( *p == '.' ) || ( *p < 33 ) ) ); - - // Display the message - printf( "\n WARNING: %s failed with error %d (%s)", msg, eNum, sysMsg ); -} - -BOOL GetProcessThreadIDs(DWORD process_id, std::vector& thread_ids) -{ - HANDLE hThreadSnap = INVALID_HANDLE_VALUE; - THREADENTRY32 te32; - - // Take a snapshot of all running threads - hThreadSnap = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 ); - if( hThreadSnap == INVALID_HANDLE_VALUE ) - return( FALSE ); - - // Fill in the size of the structure before using it. - te32.dwSize = sizeof(THREADENTRY32 ); - - // Retrieve information about the first thread, - // and exit if unsuccessful - if( !Thread32First( hThreadSnap, &te32 ) ) - { - printError( "Thread32First" ); // Show cause of failure - CloseHandle( hThreadSnap ); // Must clean up the snapshot object! - return( FALSE ); - } - - // Now walk the thread list of the system, - // and display information about each thread - // associated with the specified process - do - { - if( te32.th32OwnerProcessID == process_id ) - { - thread_ids.push_back(te32.th32ThreadID); - } - } while( Thread32Next(hThreadSnap, &te32 ) ); - -// Don't forget to clean up the snapshot object. - CloseHandle( hThreadSnap ); - return( TRUE ); -} - -BOOL GetThreadCallStack(DWORD thread_id, LLSD& info) -{ - if(GetCurrentThreadId() == thread_id) - { - // Early exit for the current thread. - // Suspending the current thread would be a bad idea. - // Plus you can't retrieve a valid current thread context. - return false; - } - - HANDLE thread_handle = INVALID_HANDLE_VALUE; - thread_handle = OpenThread(THREAD_ALL_ACCESS, FALSE, thread_id); - if(INVALID_HANDLE_VALUE == thread_handle) - { - return FALSE; - } - - BOOL result = false; - if(-1 != SuspendThread(thread_handle)) - { - CONTEXT context_struct; - context_struct.ContextFlags = CONTEXT_FULL; - if(GetThreadContext(thread_handle, &context_struct)) - { - Get_Call_Stack(NULL, &context_struct, info); - result = true; - } - ResumeThread(thread_handle); - } - else - { - // Couldn't suspend thread. - } - - CloseHandle(thread_handle); - return result; -} - - -//Windows Call Stack Construction idea from -//http://www.codeproject.com/tools/minidump.asp - -// **************************************************************************************** -BOOL WINAPI Get_Module_By_Ret_Addr(PBYTE Ret_Addr, LPWSTR Module_Name, PBYTE & Module_Addr) -// **************************************************************************************** -// Find module by Ret_Addr (address in the module). -// Return Module_Name (full path) and Module_Addr (start address). -// Return TRUE if found. -{ - MODULEENTRY32 M = {sizeof(M)}; - HANDLE hSnapshot; - - bool found = false; - - if (CreateToolhelp32Snapshot_) - { - hSnapshot = CreateToolhelp32Snapshot_(TH32CS_SNAPMODULE, 0); - - if ((hSnapshot != INVALID_HANDLE_VALUE) && - Module32First_(hSnapshot, &M)) - { - do - { - if (DWORD(Ret_Addr - M.modBaseAddr) < M.modBaseSize) - { - lstrcpyn(Module_Name, M.szExePath, MAX_PATH); - Module_Addr = M.modBaseAddr; - found = true; - break; - } - } while (Module32Next_(hSnapshot, &M)); - } - - CloseHandle(hSnapshot); - } - - return found; -} //Get_Module_By_Ret_Addr - -bool has_valid_call_before(PDWORD cur_stack_loc) -{ - PBYTE p_first_byte = (PBYTE)(*cur_stack_loc - 1); - PBYTE p_second_byte = (PBYTE)(*cur_stack_loc -2); - PBYTE p_fifth_byte = (PBYTE)(*cur_stack_loc - 5); - PBYTE p_sixth_byte = (PBYTE)(*cur_stack_loc - 6); - - // make sure we can read it - if(IsBadReadPtr(p_sixth_byte, 6 * sizeof(BYTE))) - { - return false; - } - - // check for 9a + 4 bytes - if(*p_fifth_byte == 0x9A) - { - return true; - } - - // Check for E8 + 4 bytes and last byte is 00 or FF - if(*p_fifth_byte == 0xE8 && (*p_first_byte == 0x00 || *p_first_byte == 0xFF)) - { - return true; - } - - // the other is six bytes - if(*p_sixth_byte == 0xFF || *p_second_byte == 0xFF) - { - return true; - } - - return false; -} - -PBYTE get_valid_frame(PBYTE esp) -{ - PDWORD cur_stack_loc = NULL; - const int max_search = 400; - WCHAR module_name[MAX_PATH]; - PBYTE module_addr = 0; - - // round to highest multiple of four - esp = (esp + (4 - ((int)esp % 4)) % 4); - - // scroll through stack a few hundred places. - for (cur_stack_loc = (PDWORD) esp; cur_stack_loc < (PDWORD)esp + max_search; cur_stack_loc += 1) - { - // if you can read the pointer, - if (IsBadReadPtr(cur_stack_loc, sizeof(PDWORD))) - { - continue; - } - - // check if it's in a module - if (!Get_Module_By_Ret_Addr((PBYTE)*cur_stack_loc, module_name, module_addr)) - { - continue; - } - - // check if the code before the instruction ptr is a call - if(!has_valid_call_before(cur_stack_loc)) - { - continue; - } - - // if these all pass, return that ebp, otherwise continue till we're dead - return (PBYTE)(cur_stack_loc - 1); - } - - return NULL; -} - -bool shouldUseStackWalker(PSTACK Ebp, int max_depth) -{ - WCHAR Module_Name[MAX_PATH]; - PBYTE Module_Addr = 0; - int depth = 0; - - while (depth < max_depth) - { - if (IsBadReadPtr(Ebp, sizeof(PSTACK)) || - IsBadReadPtr(Ebp->Ebp, sizeof(PSTACK)) || - Ebp->Ebp < Ebp || - Ebp->Ebp - Ebp > 0xFFFFFF || - IsBadCodePtr(FARPROC(Ebp->Ebp->Ret_Addr)) || - !Get_Module_By_Ret_Addr(Ebp->Ebp->Ret_Addr, Module_Name, Module_Addr)) - { - return true; - } - depth++; - Ebp = Ebp->Ebp; - } - - return false; -} - -// ****************************************************************** -void WINAPI Get_Call_Stack(const EXCEPTION_RECORD* exception_record, - const CONTEXT* context_record, - LLSD& info) -// ****************************************************************** -// Fill Str with call stack info. -// pException can be either GetExceptionInformation() or NULL. -// If pException = NULL - get current call stack. -{ - LPWSTR Module_Name = new WCHAR[MAX_PATH]; - PBYTE Module_Addr = 0; - LLSD params; - PBYTE Esp = NULL; - LLSD tmp_info; - - bool fake_frame = false; - bool ebp_used = false; - const int HEURISTIC_MAX_WALK = 20; - int heuristic_walk_i = 0; - int Ret_Addr_I = 0; - - STACK Stack = {0, 0}; - PSTACK Ebp; - - if (exception_record && context_record) //fake frame for exception address - { - Stack.Ebp = (PSTACK)(context_record->Ebp); - Stack.Ret_Addr = (PBYTE)exception_record->ExceptionAddress; - Ebp = &Stack; - Esp = (PBYTE) context_record->Esp; - fake_frame = true; - } - else if(context_record) - { - Ebp = (PSTACK)(context_record->Ebp); - Esp = (PBYTE)(context_record->Esp); - } - else - { - Ebp = (PSTACK)&exception_record - 1; //frame addr of Get_Call_Stack() - Esp = (PBYTE)&exception_record; - - // Skip frame of Get_Call_Stack(). - if (!IsBadReadPtr(Ebp, sizeof(PSTACK))) - Ebp = Ebp->Ebp; //caller ebp - } - - // Trace CALL_TRACE_MAX calls maximum - not to exceed DUMP_SIZE_MAX. - // Break trace on wrong stack frame. - for (Ret_Addr_I = 0; - heuristic_walk_i < HEURISTIC_MAX_WALK && - Ret_Addr_I < CALL_TRACE_MAX && !IsBadReadPtr(Ebp, sizeof(PSTACK)) && !IsBadCodePtr(FARPROC(Ebp->Ret_Addr)); - Ret_Addr_I++) - { - // If module with Ebp->Ret_Addr found. - if (Get_Module_By_Ret_Addr(Ebp->Ret_Addr, Module_Name, Module_Addr)) - { - // Save module's address and full path. - tmp_info["CallStack"][Ret_Addr_I]["ModuleName"] = ll_convert_wide_to_string(Module_Name,CP_ACP); - tmp_info["CallStack"][Ret_Addr_I]["ModuleAddress"] = (int)Module_Addr; - tmp_info["CallStack"][Ret_Addr_I]["CallOffset"] = (int)(Ebp->Ret_Addr - Module_Addr); - - // Save 5 params of the call. We don't know the real number of params. - if (fake_frame && !Ret_Addr_I) //fake frame for exception address - params[0] = "Exception Offset"; - else if (!IsBadReadPtr(Ebp, sizeof(PSTACK) + 5 * sizeof(DWORD))) - { - for(int j = 0; j < 5; ++j) - { - params[j] = (int)Ebp->Param[j]; - } - } - tmp_info["CallStack"][Ret_Addr_I]["Parameters"] = params; - } - - tmp_info["CallStack"][Ret_Addr_I]["ReturnAddress"] = (int)Ebp->Ret_Addr; - - // get ready for next frame - // Set ESP to just after return address. Not the real esp, but just enough after the return address - if(!fake_frame) { - Esp = (PBYTE)Ebp + 8; - } - else - { - fake_frame = false; - } - - // is next ebp valid? - // only run if we've never found a good ebp - // and make sure the one after is valid as well - if( !ebp_used && - shouldUseStackWalker(Ebp, 2)) - { - heuristic_walk_i++; - PBYTE new_ebp = get_valid_frame(Esp); - if (new_ebp != NULL) - { - Ebp = (PSTACK)new_ebp; - } - } - else - { - ebp_used = true; - Ebp = Ebp->Ebp; - } - } -/* TODO remove or turn this code back on to edit the stack after i see a few raw ones. -Palmer - // Now go back through and edit out heuristic stacks that could very well be bogus. - // Leave the top and the last 3 stack chosen by the heuristic, however. - if(heuristic_walk_i > 2) - { - info["CallStack"][0] = tmp_info["CallStack"][0]; - std::string ttest = info["CallStack"][0]["ModuleName"]; - for(int cur_frame = 1; - (cur_frame + heuristic_walk_i - 2 < Ret_Addr_I); - ++cur_frame) - { - // edit out the middle heuristic found frames - info["CallStack"][cur_frame] = tmp_info["CallStack"][cur_frame + heuristic_walk_i - 2]; - } - } - else - { - info = tmp_info; - } -*/ - info = tmp_info; - info["HeuristicWalkI"] = heuristic_walk_i; - info["EbpUsed"] = ebp_used; - -} //Get_Call_Stack - -// *********************************** -void WINAPI Get_Version_Str(LLSD& info) -// *********************************** -// Fill Str with Windows version. -{ - OSVERSIONINFOEX V = {sizeof(OSVERSIONINFOEX)}; //EX for NT 5.0 and later - - if (!GetVersionEx((POSVERSIONINFO)&V)) - { - ZeroMemory(&V, sizeof(V)); - V.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); - GetVersionEx((POSVERSIONINFO)&V); - } - - if (V.dwPlatformId != VER_PLATFORM_WIN32_NT) - V.dwBuildNumber = LOWORD(V.dwBuildNumber); //for 9x HIWORD(dwBuildNumber) = 0x04xx - - info["Platform"] = llformat("Windows: %d.%d.%d, SP %d.%d, Product Type %d", //SP - service pack, Product Type - VER_NT_WORKSTATION,... - V.dwMajorVersion, V.dwMinorVersion, V.dwBuildNumber, V.wServicePackMajor, V.wServicePackMinor, V.wProductType); -} //Get_Version_Str - -// ************************************************************* -LLSD WINAPI Get_Exception_Info(PEXCEPTION_POINTERS pException) -// ************************************************************* -// Allocate Str[DUMP_SIZE_MAX] and return Str with dump, if !pException - just return call stack in Str. -{ - LLSD info; - LPWSTR Str; - int Str_Len; -// int i; - LPWSTR Module_Name = new WCHAR[MAX_PATH]; - PBYTE Module_Addr; - HANDLE hFile; - FILETIME Last_Write_Time; - FILETIME Local_File_Time; - SYSTEMTIME T; - - Str = new WCHAR[DUMP_SIZE_MAX]; - Str_Len = 0; - if (!Str) - return NULL; - - Get_Version_Str(info); - - GetModuleFileName(NULL, Str, MAX_PATH); - info["Process"] = ll_convert_wide_to_string(Str,CP_ACP); - info["ThreadID"] = (S32)GetCurrentThreadId(); - - // If exception occurred. - if (pException) - { - EXCEPTION_RECORD & E = *pException->ExceptionRecord; - CONTEXT & C = *pException->ContextRecord; - - // If module with E.ExceptionAddress found - save its path and date. - if (Get_Module_By_Ret_Addr((PBYTE)E.ExceptionAddress, Module_Name, Module_Addr)) - { - info["Module"] = ll_convert_wide_to_string(Module_Name,CP_ACP); - - if ((hFile = CreateFile(Module_Name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE) - { - if (GetFileTime(hFile, NULL, NULL, &Last_Write_Time)) - { - FileTimeToLocalFileTime(&Last_Write_Time, &Local_File_Time); - FileTimeToSystemTime(&Local_File_Time, &T); - - info["DateModified"] = llformat("%02d/%02d/%d", T.wMonth, T.wDay, T.wYear); - } - CloseHandle(hFile); - } - } - else - { - info["ExceptionAddr"] = (int)E.ExceptionAddress; - } - - info["ExceptionCode"] = (int)E.ExceptionCode; - - /* - //TODO: Fix this - if (E.ExceptionCode == EXCEPTION_ACCESS_VIOLATION) - { - // Access violation type - Write/Read. - LLSD exception_info; - exception_info["Type"] = E.ExceptionInformation[0] ? "Write" : "Read"; - exception_info["Address"] = llformat("%08x", E.ExceptionInformation[1]); - info["Exception Information"] = exception_info; - } - */ - - - // Save instruction that caused exception. - /* - std::string str; - for (i = 0; i < 16; i++) - str += llformat(" %02X", PBYTE(E.ExceptionAddress)[i]); - info["Instruction"] = str; - */ - LLSD registers; - registers["EAX"] = (int)C.Eax; - registers["EBX"] = (int)C.Ebx; - registers["ECX"] = (int)C.Ecx; - registers["EDX"] = (int)C.Edx; - registers["ESI"] = (int)C.Esi; - registers["EDI"] = (int)C.Edi; - registers["ESP"] = (int)C.Esp; - registers["EBP"] = (int)C.Ebp; - registers["EIP"] = (int)C.Eip; - registers["EFlags"] = (int)C.EFlags; - info["Registers"] = registers; - } //if (pException) - - // Save call stack info. - Get_Call_Stack(pException->ExceptionRecord, pException->ContextRecord, info); - - return info; -} //Get_Exception_Info - -#define UNICODE - class LLMemoryReserve { public: @@ -663,66 +79,23 @@ void LLMemoryReserve::release() static LLMemoryReserve gEmergencyMemoryReserve; -#ifndef _M_IX86 - #error "The following code only works for x86!" -#endif -LPTOP_LEVEL_EXCEPTION_FILTER WINAPI MyDummySetUnhandledExceptionFilter( - LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter) -{ - if(lpTopLevelExceptionFilter == gFilterFunc) - return gFilterFunc; - llinfos << "Someone tried to set the exception filter. Listing call stack modules" << llendl; - LLSD cs_info; - Get_Call_Stack(NULL, NULL, cs_info); - - if(cs_info.has("CallStack") && cs_info["CallStack"].isArray()) - { - LLSD cs = cs_info["CallStack"]; - for(LLSD::array_iterator i = cs.beginArray(); - i != cs.endArray(); - ++i) - { - llinfos << "Module: " << (*i)["ModuleName"] << llendl; - } - } - - return gFilterFunc; -} - -BOOL PreventSetUnhandledExceptionFilter() +LONG NTAPI vectoredHandler(PEXCEPTION_POINTERS exception_infop) { - HMODULE hKernel32 = LoadLibrary(_T("kernel32.dll")); - if (hKernel32 == NULL) - return FALSE; - - void *pOrgEntry = GetProcAddress(hKernel32, "SetUnhandledExceptionFilter"); - if(pOrgEntry == NULL) - return FALSE; - - unsigned char newJump[ 100 ]; - DWORD dwOrgEntryAddr = (DWORD)pOrgEntry; - dwOrgEntryAddr += 5; // add 5 for 5 op-codes for jmp far - void *pNewFunc = &MyDummySetUnhandledExceptionFilter; - DWORD dwNewEntryAddr = (DWORD) pNewFunc; - DWORD dwRelativeAddr = dwNewEntryAddr - dwOrgEntryAddr; - - newJump[ 0 ] = 0xE9; // JMP absolute - memcpy(&newJump[ 1 ], &dwRelativeAddr, sizeof(pNewFunc)); - SIZE_T bytesWritten; - BOOL bRet = WriteProcessMemory(GetCurrentProcess(), - pOrgEntry, newJump, sizeof(pNewFunc) + 1, &bytesWritten); - return bRet; + LLWinDebug::instance().generateMinidump(exception_infop); + return EXCEPTION_CONTINUE_SEARCH; } // static -void LLWinDebug::initExceptionHandler(LPTOP_LEVEL_EXCEPTION_FILTER filter_func) +void LLWinDebug::init() { - static bool s_first_run = true; // Load the dbghelp dll now, instead of waiting for the crash. // Less potential for stack mangling + // Don't install vectored exception handler if being debugged. + if(IsDebuggerPresent()) return; + if (s_first_run) { // First, try loading from the directory that the app resides in. @@ -753,161 +126,68 @@ void LLWinDebug::initExceptionHandler(LPTOP_LEVEL_EXCEPTION_FILTER filter_func) gEmergencyMemoryReserve.reserve(); s_first_run = false; - } - - // Try to get Tool Help library functions. - HMODULE hKernel32; - hKernel32 = GetModuleHandle(_T("KERNEL32")); - CreateToolhelp32Snapshot_ = (CREATE_TOOL_HELP32_SNAPSHOT)GetProcAddress(hKernel32, "CreateToolhelp32Snapshot"); - Module32First_ = (MODULE32_FIRST)GetProcAddress(hKernel32, "Module32FirstW"); - Module32Next_ = (MODULE32_NEST)GetProcAddress(hKernel32, "Module32NextW"); - - LPTOP_LEVEL_EXCEPTION_FILTER prev_filter; - prev_filter = SetUnhandledExceptionFilter(filter_func); - - // *REMOVE:Mani - //PreventSetUnhandledExceptionFilter(); - if(prev_filter != gFilterFunc) - { - LL_WARNS("AppInit") - << "Replacing unknown exception (" << (void *)prev_filter << ") with (" << (void *)filter_func << ") !" << LL_ENDL; + // Add this exeption hanlder to save windows style minidump. + AddVectoredExceptionHandler(0, &vectoredHandler); } - - gFilterFunc = filter_func; } -bool LLWinDebug::checkExceptionHandler() +void LLWinDebug::writeDumpToFile(MINIDUMP_TYPE type, MINIDUMP_EXCEPTION_INFORMATION *ExInfop, const std::string& filename) { - bool ok = true; - LPTOP_LEVEL_EXCEPTION_FILTER prev_filter; - prev_filter = SetUnhandledExceptionFilter(gFilterFunc); - - if (prev_filter != gFilterFunc) + // Temporary fix to switch out the code that writes the DMP file. + // Fix coming that doesn't write a mini dump file for regular C++ exceptions. + const bool enable_write_dump_file = false; + if ( enable_write_dump_file ) { - LL_WARNS("AppInit") << "Our exception handler (" << (void *)gFilterFunc << ") replaced with " << prev_filter << "!" << LL_ENDL; - ok = false; - } - - if (prev_filter == NULL) - { - ok = FALSE; - if (gFilterFunc == NULL) + if(f_mdwp == NULL || gDirUtilp == NULL) { - LL_WARNS("AppInit") << "Exception handler uninitialized." << LL_ENDL; + return; } else { - LL_WARNS("AppInit") << "Our exception handler (" << (void *)gFilterFunc << ") replaced with NULL!" << LL_ENDL; - } - } + std::string dump_path = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, filename); - return ok; -} + HANDLE hFile = CreateFileA(dump_path.c_str(), + GENERIC_WRITE, + FILE_SHARE_WRITE, + NULL, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL); -void LLWinDebug::writeDumpToFile(MINIDUMP_TYPE type, MINIDUMP_EXCEPTION_INFORMATION *ExInfop, const std::string& filename) -{ - if(f_mdwp == NULL || gDirUtilp == NULL) - { - return; - //write_debug("No way to generate a minidump, no MiniDumpWriteDump function!\n"); - } - else - { - std::string dump_path = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, filename); - - HANDLE hFile = CreateFileA(dump_path.c_str(), - GENERIC_WRITE, - FILE_SHARE_WRITE, - NULL, - CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL, - NULL); + if (hFile != INVALID_HANDLE_VALUE) + { + // Write the dump, ignoring the return value + f_mdwp(GetCurrentProcess(), + GetCurrentProcessId(), + hFile, + type, + ExInfop, + NULL, + NULL); - if (hFile != INVALID_HANDLE_VALUE) - { - // Write the dump, ignoring the return value - f_mdwp(GetCurrentProcess(), - GetCurrentProcessId(), - hFile, - type, - ExInfop, - NULL, - NULL); + CloseHandle(hFile); + } - CloseHandle(hFile); } - } } // static -void LLWinDebug::generateCrashStacks(struct _EXCEPTION_POINTERS *exception_infop) +void LLWinDebug::generateMinidump(struct _EXCEPTION_POINTERS *exception_infop) { - // *NOTE:Mani - This method is no longer the exception handler. - // Its called from viewer_windows_exception_handler() and other places. - - // - // Let go of a bunch of reserved memory to give library calls etc - // a chance to execute normally in the case that we ran out of - // memory. - // - LLSD info; std::string dump_path = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLifeException"); - std::string log_path = dump_path + ".log"; - if (exception_infop) { // Since there is exception info... Release the hounds. gEmergencyMemoryReserve.release(); - LLControlVariable* save_minimap = gSavedSettings.getControl("SaveMinidump"); - if(save_minimap && save_minimap->getValue().asBoolean()) - { - _MINIDUMP_EXCEPTION_INFORMATION ExInfo; - - ExInfo.ThreadId = ::GetCurrentThreadId(); - ExInfo.ExceptionPointers = exception_infop; - ExInfo.ClientPointers = NULL; - - writeDumpToFile(MiniDumpNormal, &ExInfo, "SecondLife.dmp"); - writeDumpToFile((MINIDUMP_TYPE)(MiniDumpWithDataSegs | MiniDumpWithIndirectlyReferencedMemory), &ExInfo, "SecondLifePlus.dmp"); - } + _MINIDUMP_EXCEPTION_INFORMATION ExInfo; - info = Get_Exception_Info(exception_infop); + ExInfo.ThreadId = ::GetCurrentThreadId(); + ExInfo.ExceptionPointers = exception_infop; + ExInfo.ClientPointers = NULL; + writeDumpToFile((MINIDUMP_TYPE)(MiniDumpWithDataSegs | MiniDumpWithIndirectlyReferencedMemory), &ExInfo, "SecondLife.dmp"); } - - LLSD threads; - std::vector thread_ids; - GetProcessThreadIDs(GetCurrentProcessId(), thread_ids); - - for(std::vector::iterator th_itr = thread_ids.begin(); - th_itr != thread_ids.end(); - ++th_itr) - { - LLSD thread_info; - if(*th_itr != GetCurrentThreadId()) - { - GetThreadCallStack(*th_itr, thread_info); - } - - if(thread_info) - { - threads[llformat("ID %d", *th_itr)] = thread_info; - } - } - - info["Threads"] = threads; - - llofstream out_file(log_path); - LLSDSerialize::toPrettyXML(info, out_file); - out_file.close(); -} - -void LLWinDebug::clearCrashStacks() -{ - LLSD info; - std::string dump_path = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLifeException.log"); - LLFile::remove(dump_path); } diff --git a/indra/newview/llwindebug.h b/indra/newview/llwindebug.h index f4a6a2d54d..3837825d31 100644 --- a/indra/newview/llwindebug.h +++ b/indra/newview/llwindebug.h @@ -2,31 +2,25 @@ * @file llwindebug.h * @brief LLWinDebug class header file * - * $LicenseInfo:firstyear=2004&license=viewergpl$ - * - * Copyright (c) 2004-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * 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. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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 * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -36,40 +30,14 @@ #include "stdtypes.h" #include -class LLWinDebug +class LLWinDebug: + public LLSingleton { public: - - /** - * @brief initialize the llwindebug exception filter callback - * - * Hand a windows unhandled exception filter to LLWinDebug - * This method should only be called to change the - * exception filter used by llwindebug. - * - * Setting filter_func to NULL will clear any custom filters. - **/ - static void initExceptionHandler(LPTOP_LEVEL_EXCEPTION_FILTER filter_func); - - /** - * @brief check the status of the exception filter. - * - * Resets unhandled exception filter to the filter specified - * w/ initExceptionFilter). - * Returns false if the exception filter was modified. - * - * *NOTE:Mani In the past mozlib has been accused of - * overriding the exception filter. If the mozlib filter - * is required, perhaps we can chain calls from our - * filter to mozlib's. - **/ - static bool checkExceptionHandler(); - - static void generateCrashStacks(struct _EXCEPTION_POINTERS *pExceptionInfo = NULL); - static void clearCrashStacks(); // Delete the crash stack file(s). - - static void writeDumpToFile(MINIDUMP_TYPE type, MINIDUMP_EXCEPTION_INFORMATION *ExInfop, const std::string& filename); + static void init(); + static void generateMinidump(struct _EXCEPTION_POINTERS *pExceptionInfo = NULL); private: + static void writeDumpToFile(MINIDUMP_TYPE type, MINIDUMP_EXCEPTION_INFORMATION *ExInfop, const std::string& filename); }; #endif // LL_LLWINDEBUG_H diff --git a/indra/newview/llwlanimator.cpp b/indra/newview/llwlanimator.cpp index 953898fe62..1c8f211271 100644 --- a/indra/newview/llwlanimator.cpp +++ b/indra/newview/llwlanimator.cpp @@ -267,7 +267,7 @@ std::string LLWLAnimator::timeToString(F32 curTime) // get hours and minutes hours = (S32) (24.0 * curTime); curTime -= ((F32) hours / 24.0f); - min = llround(24.0f * 60.0f * curTime); + min = ll_pos_round(24.0f * 60.0f * curTime); // handle case where it's 60 if(min == 60) diff --git a/indra/newview/llwldaycycle.cpp b/indra/newview/llwldaycycle.cpp index 5235334f9b..6e9fb490a9 100644 --- a/indra/newview/llwldaycycle.cpp +++ b/indra/newview/llwldaycycle.cpp @@ -46,7 +46,7 @@ LLWLDayCycle::~LLWLDayCycle() void LLWLDayCycle::loadDayCycle(const LLSD& day_data, LLWLParamKey::EScope scope) { - lldebugs << "Loading day cycle (day_data.size() = " << day_data.size() << ", scope = " << scope << ")" << llendl; + LL_DEBUGS() << "Loading day cycle (day_data.size() = " << day_data.size() << ", scope = " << scope << ")" << LL_ENDL; mTimeMap.clear(); // add each key frame @@ -128,7 +128,7 @@ LLSD LLWLDayCycle::loadDayCycleFromPath(const std::string& file_path) void LLWLDayCycle::saveDayCycle(const std::string & fileName) { std::string pathName(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight/days", fileName)); - //llinfos << "Saving WindLight settings to " << pathName << llendl; + //LL_INFOS() << "Saving WindLight settings to " << pathName << LL_ENDL; save(pathName); } @@ -154,7 +154,7 @@ LLSD LLWLDayCycle::asLLSD() day_data.append(key); } - lldebugs << "Dumping day cycle (" << mTimeMap.size() << ") to LLSD: " << day_data << llendl; + LL_DEBUGS() << "Dumping day cycle (" << mTimeMap.size() << ") to LLSD: " << day_data << LL_ENDL; return day_data; } @@ -169,7 +169,7 @@ bool LLWLDayCycle::getSkyRefs(std::map& refs) const const LLWLParamKey& key = iter->second; if (!wl_mgr.getParamSet(key, refs[key])) { - llwarns << "Cannot find sky [" << key.name << "] referenced by a day cycle" << llendl; + LL_WARNS() << "Cannot find sky [" << key.name << "] referenced by a day cycle" << LL_ENDL; result = false; } } @@ -192,7 +192,7 @@ bool LLWLDayCycle::getSkyMap(LLSD& sky_map) const void LLWLDayCycle::clearKeyframes() { - lldebugs << "Clearing key frames" << llendl; + LL_DEBUGS() << "Clearing key frames" << LL_ENDL; mTimeMap.clear(); } @@ -219,12 +219,12 @@ bool LLWLDayCycle::addKeyframe(F32 newTime, LLWLParamKey frame) if(mTimeMap.find(newTime) == mTimeMap.end()) { mTimeMap.insert(std::pair(newTime, frame)); - lldebugs << "Adding key frame (" << newTime << ", " << frame.toLLSD() << ")" << llendl; + LL_DEBUGS() << "Adding key frame (" << newTime << ", " << frame.toLLSD() << ")" << LL_ENDL; return true; } // otherwise, don't add, and return error - llwarns << "Error adding key frame (" << newTime << ", " << frame.toLLSD() << ")" << llendl; + LL_WARNS() << "Error adding key frame (" << newTime << ", " << frame.toLLSD() << ")" << LL_ENDL; return false; } @@ -235,7 +235,7 @@ bool LLWLDayCycle::changeKeyTime(F32 oldTime, F32 newTime) bool LLWLDayCycle::changeKeyframeTime(F32 oldTime, F32 newTime) { - lldebugs << "Changing key frame time (" << oldTime << " => " << newTime << ")" << llendl; + LL_DEBUGS() << "Changing key frame time (" << oldTime << " => " << newTime << ")" << LL_ENDL; // just remove and add back LLWLParamKey frame = mTimeMap[oldTime]; @@ -243,7 +243,7 @@ bool LLWLDayCycle::changeKeyframeTime(F32 oldTime, F32 newTime) bool stat = removeKeyframe(oldTime); if(stat == false) { - lldebugs << "Failed to change key frame time (" << oldTime << " => " << newTime << ")" << llendl; + LL_DEBUGS() << "Failed to change key frame time (" << oldTime << " => " << newTime << ")" << LL_ENDL; return stat; } @@ -257,7 +257,7 @@ bool LLWLDayCycle::changeKeyParam(F32 time, const std::string & name) bool LLWLDayCycle::changeKeyframeParam(F32 time, LLWLParamKey key) { - lldebugs << "Changing key frame param (" << time << ", " << key.toLLSD() << ")" << llendl; + LL_DEBUGS() << "Changing key frame param (" << time << ", " << key.toLLSD() << ")" << LL_ENDL; // just remove and add back // make sure param exists @@ -265,7 +265,7 @@ bool LLWLDayCycle::changeKeyframeParam(F32 time, LLWLParamKey key) bool stat = LLWLParamManager::getInstance()->getParamSet(key, tmp); if(stat == false) { - lldebugs << "Failed to change key frame param (" << time << ", " << key.toLLSD() << ")" << llendl; + LL_DEBUGS() << "Failed to change key frame param (" << time << ", " << key.toLLSD() << ")" << LL_ENDL; return stat; } @@ -276,7 +276,7 @@ bool LLWLDayCycle::changeKeyframeParam(F32 time, LLWLParamKey key) bool LLWLDayCycle::removeKeyframe(F32 time) { - lldebugs << "Removing key frame (" << time << ")" << llendl; + LL_DEBUGS() << "Removing key frame (" << time << ")" << LL_ENDL; // look for the time. If there, erase it std::map::iterator mIt = mTimeMap.find(time); @@ -320,7 +320,7 @@ bool LLWLDayCycle::getKeyedParam(F32 time, LLWLParamSet& param) } // return error if not found - lldebugs << "Key " << time << " not found" << llendl; + LL_DEBUGS() << "Key " << time << " not found" << LL_ENDL; return false; } @@ -335,7 +335,7 @@ bool LLWLDayCycle::getKeyedParamName(F32 time, std::string & name) } // return error if not found - lldebugs << "Key " << time << " not found" << llendl; + LL_DEBUGS() << "Key " << time << " not found" << LL_ENDL; return false; } @@ -347,7 +347,7 @@ bool LLWLDayCycle::hasReferencesTo(const LLWLParamKey& keyframe) const void LLWLDayCycle::removeReferencesTo(const LLWLParamKey& keyframe) { - lldebugs << "Removing references to key frame " << keyframe.toLLSD() << llendl; + LL_DEBUGS() << "Removing references to key frame " << keyframe.toLLSD() << LL_ENDL; F32 keytime = 0.f; // Avoid compiler warning. bool might_exist; do diff --git a/indra/newview/llwlhandlers.cpp b/indra/newview/llwlhandlers.cpp index e6eb7299c6..dd11408455 100644 --- a/indra/newview/llwlhandlers.cpp +++ b/indra/newview/llwlhandlers.cpp @@ -101,7 +101,7 @@ LLEnvironmentRequestResponder::LLEnvironmentRequestResponder() { mID = ++sCount; } -/*virtual*/ void LLEnvironmentRequestResponder::result(const LLSD& unvalidated_content) +/*virtual*/ void LLEnvironmentRequestResponder::httpSuccess(void) { LL_INFOS("WindlightCaps") << "Received region windlight settings" << LL_ENDL; @@ -113,22 +113,22 @@ LLEnvironmentRequestResponder::LLEnvironmentRequestResponder() { LL_WARNS("WindlightCaps") << "Ignoring responder. Current region is invalid." << LL_ENDL; } - else if (unvalidated_content[0]["regionID"].asUUID().isNull()) + else if (mContent[0]["regionID"].asUUID().isNull()) { LL_WARNS("WindlightCaps") << "Ignoring responder. Response from invalid region." << LL_ENDL; } - else if (unvalidated_content[0]["regionID"].asUUID() != gAgent.getRegion()->getRegionID()) + else if (mContent[0]["regionID"].asUUID() != gAgent.getRegion()->getRegionID()) { LL_WARNS("WindlightCaps") << "Not in the region from where this data was received (wanting " - << gAgent.getRegion()->getRegionID() << " but got " << unvalidated_content[0]["regionID"].asUUID() + << gAgent.getRegion()->getRegionID() << " but got " << mContent[0]["regionID"].asUUID() << ") - ignoring..." << LL_ENDL; } else { - LLEnvManagerNew::getInstance()->onRegionSettingsResponse(unvalidated_content); + LLEnvManagerNew::getInstance()->onRegionSettingsResponse(mContent); } } -/*virtual*/ void LLEnvironmentRequestResponder::error(U32 status, const std::string& reason) +/*virtual*/ void LLEnvironmentRequestResponder::httpFailure(void) { LL_INFOS("WindlightCaps") << "Got an error, not using region windlight..." << LL_ENDL; LLEnvManagerNew::getInstance()->onRegionSettingsResponse(LLSD()); @@ -158,7 +158,7 @@ bool LLEnvironmentApply::initiateRequest(const LLSD& content) sLastUpdate = current; // Send update request. - std::string url = gAgent.getRegion()->getCapability("EnvironmentSettings"); + std::string url = gAgent.getRegionCapability("EnvironmentSettings"); if (url.empty()) { LL_WARNS("WindlightCaps") << "Applying windlight settings not supported" << LL_ENDL; @@ -174,33 +174,33 @@ bool LLEnvironmentApply::initiateRequest(const LLSD& content) /**** * LLEnvironmentApplyResponder ****/ -/*virtual*/ void LLEnvironmentApplyResponder::result(const LLSD& content) +/*virtual*/ void LLEnvironmentApplyResponder::httpSuccess(void) { - if (content["regionID"].asUUID() != gAgent.getRegion()->getRegionID()) + if (mContent["regionID"].asUUID() != gAgent.getRegion()->getRegionID()) { LL_WARNS("WindlightCaps") << "No longer in the region where data was sent (currently " - << gAgent.getRegion()->getRegionID() << ", reply is from " << content["regionID"].asUUID() + << gAgent.getRegion()->getRegionID() << ", reply is from " << mContent["regionID"].asUUID() << "); ignoring..." << LL_ENDL; return; } - else if (content["success"].asBoolean()) + else if (mContent["success"].asBoolean()) { - LL_DEBUGS("WindlightCaps") << "Success in applying windlight settings to region " << content["regionID"].asUUID() << LL_ENDL; + LL_DEBUGS("WindlightCaps") << "Success in applying windlight settings to region " << mContent["regionID"].asUUID() << LL_ENDL; LLEnvManagerNew::instance().onRegionSettingsApplyResponse(true); } else { - LL_WARNS("WindlightCaps") << "Region couldn't apply windlight settings! Reason from sim: " << content["fail_reason"].asString() << LL_ENDL; + LL_WARNS("WindlightCaps") << "Region couldn't apply windlight settings! Reason from sim: " << mContent["fail_reason"].asString() << LL_ENDL; LLSD args(LLSD::emptyMap()); - args["FAIL_REASON"] = content["fail_reason"].asString(); + args["FAIL_REASON"] = mContent["fail_reason"].asString(); LLNotificationsUtil::add("WLRegionApplyFail", args); LLEnvManagerNew::instance().onRegionSettingsApplyResponse(false); } } -/*virtual*/ void LLEnvironmentApplyResponder::error(U32 status, const std::string& reason) +/*virtual*/ void LLEnvironmentApplyResponder::httpFailure(void) { std::stringstream msg; - msg << reason << " (Code " << status << ")"; + msg << mReason << " (Code " << mStatus << ")"; LL_WARNS("WindlightCaps") << "Couldn't apply windlight settings to region! Reason: " << msg.str() << LL_ENDL; diff --git a/indra/newview/llwlhandlers.h b/indra/newview/llwlhandlers.h index 969e188b64..6194400a07 100644 --- a/indra/newview/llwlhandlers.h +++ b/indra/newview/llwlhandlers.h @@ -33,7 +33,6 @@ #ifndef LL_LLWLHANDLERS_H #define LL_LLWLHANDLERS_H -#include "llviewerprecompiledheaders.h" #include "llhttpclient.h" class AIHTTPTimeoutPolicy; @@ -56,8 +55,8 @@ class LLEnvironmentRequestResponder: public LLHTTPClient::ResponderWithResult { LOG_CLASS(LLEnvironmentRequestResponder); public: - /*virtual*/ void result(const LLSD& content); - /*virtual*/ void error(U32 status, const std::string& reason); + /*virtual*/ void httpSuccess(void); + /*virtual*/ void httpFailure(void); /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return environmentRequestResponder_timeout; } /*virtual*/ char const* getName(void) const { return "LLEnvironmentRequestResponder"; } @@ -99,9 +98,9 @@ class LLEnvironmentApplyResponder : public LLHTTPClient::ResponderWithResult * fail_reason : string * } */ - /*virtual*/ void result(const LLSD& content); + /*virtual*/ void httpSuccess(void); - /*virtual*/ void error(U32 status, const std::string& reason); // non-200 errors only + /*virtual*/ void httpFailure(void); /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return environmentApplyResponder_timeout; } /*virtual*/ char const* getName(void) const { return "LLEnvironmentApplyResponder"; } diff --git a/indra/newview/llwlparammanager.cpp b/indra/newview/llwlparammanager.cpp index 95eba470f3..b5c01ff0b5 100644 --- a/indra/newview/llwlparammanager.cpp +++ b/indra/newview/llwlparammanager.cpp @@ -150,12 +150,12 @@ void LLWLParamManager::clearParamSetsOfScope(LLWLParamKey::EScope scope) // side effect: applies changes to all internal structures! std::map LLWLParamManager::finalizeFromDayCycle(LLWLParamKey::EScope scope) { - lldebugs << "mDay before finalizing:" << llendl; + LL_DEBUGS() << "mDay before finalizing:" << LL_ENDL; { for (std::map::iterator iter = mDay.mTimeMap.begin(); iter != mDay.mTimeMap.end(); ++iter) { LLWLParamKey& key = iter->second; - lldebugs << iter->first << "->" << key.name << llendl; + LL_DEBUGS() << iter->first << "->" << key.name << LL_ENDL; } } @@ -241,12 +241,12 @@ std::map LLWLParamManager::finalizeFromDayCycle(LLWL final_references[new_key] = iter->second; } - lldebugs << "mDay after finalizing:" << llendl; + LL_DEBUGS() << "mDay after finalizing:" << LL_ENDL; { for (std::map::iterator iter = mDay.mTimeMap.begin(); iter != mDay.mTimeMap.end(); ++iter) { LLWLParamKey& key = iter->second; - lldebugs << iter->first << "->" << key.name << llendl; + LL_DEBUGS() << iter->first << "->" << key.name << LL_ENDL; } } @@ -268,9 +268,7 @@ void LLWLParamManager::addAllSkies(const LLWLParamKey::EScope scope, const LLSD& { for(LLSD::map_const_iterator iter = sky_presets.beginMap(); iter != sky_presets.endMap(); ++iter) { - LLWLParamSet set; - set.setAll(iter->second); - mParamList[LLWLParamKey(iter->first, scope)] = set; + setParamSet(LLWLParamKey(iter->first, scope), iter->second); } } @@ -294,7 +292,7 @@ void LLWLParamManager::loadAllPresets() void LLWLParamManager::loadPresetsFromDir(const std::string& dir) { - LL_INFOS2("AppInit", "Shaders") << "Loading sky presets from " << dir << LL_ENDL; + LL_INFOS("AppInit", "Shaders") << "Loading sky presets from " << dir << LL_ENDL; LLDirIterator dir_iter(dir, "*.xml"); while (1) @@ -308,7 +306,7 @@ void LLWLParamManager::loadPresetsFromDir(const std::string& dir) std::string path = dir + file; if (!loadPreset(path)) { - llwarns << "Error loading sky preset from " << path << llendl; + LL_WARNS() << "Error loading sky preset from " << path << LL_ENDL; } } } @@ -324,7 +322,7 @@ bool LLWLParamManager::loadPreset(const std::string& path) return false; } - LL_DEBUGS2("AppInit", "Shaders") << "Loading sky " << name << LL_ENDL; + LL_DEBUGS("AppInit", "Shaders") << "Loading sky " << name << LL_ENDL; LLSD params_data; LLPointer parser = new LLSDXMLParser(); @@ -373,8 +371,8 @@ void LLWLParamManager::updateShaderUniforms(LLGLSLShader * shader) if (shader->mShaderGroup == LLGLSLShader::SG_DEFAULT) { - shader->uniform4fv(LLViewerShaderMgr::LIGHTNORM, 1, mRotatedLightDir.mV); - shader->uniform3fv("camPosLocal", 1, LLViewerCamera::getInstance()->getOrigin().mV); + shader->uniform4fv(LLShaderMgr::LIGHTNORM, 1, mRotatedLightDir.mV); + shader->uniform3fv(LLShaderMgr::WL_CAMPOSLOCAL, 1, LLViewerCamera::getInstance()->getOrigin().mV); } else if (shader->mShaderGroup == LLGLSLShader::SG_SKY) @@ -382,7 +380,7 @@ void LLWLParamManager::updateShaderUniforms(LLGLSLShader * shader) shader->uniform4fv(LLViewerShaderMgr::LIGHTNORM, 1, mClampedLightDir.mV); } - shader->uniform1f("scene_light_strength", mSceneLightStrength); + shader->uniform1f(LLShaderMgr::SCENE_LIGHT_STRENGTH, mSceneLightStrength); } @@ -405,11 +403,11 @@ void LLWLParamManager::updateShaderLinks() } } -static LLFastTimer::DeclareTimer FTM_UPDATE_WLPARAM("Update Windlight Params"); +static LLTrace::BlockTimerStatHandle FTM_UPDATE_WLPARAM("Update Windlight Params"); void LLWLParamManager::propagateParameters(void) { - LLFastTimer ftm(FTM_UPDATE_WLPARAM); + LL_RECORD_BLOCK_TIME(FTM_UPDATE_WLPARAM); LLVector4 sunDir; LLVector4 moonDir; @@ -474,7 +472,7 @@ void LLWLParamManager::propagateParameters(void) void LLWLParamManager::update(LLViewerCamera * cam) { - LLFastTimer ftm(FTM_UPDATE_WLPARAM); + LL_RECORD_BLOCK_TIME(FTM_UPDATE_WLPARAM); // update clouds, sun, and general mCurParams.updateCloudScrolling(); @@ -534,7 +532,7 @@ bool LLWLParamManager::applySkyParams(const LLSD& params, bool interpolate /*= f { if (params.size() == 0) { - llwarns << "Undefined sky params" << llendl; + LL_WARNS() << "Undefined sky params" << LL_ENDL; return false; } @@ -606,9 +604,9 @@ bool LLWLParamManager::hasParamSet(const LLWLParamKey& key) return getParamSet(key, dummy); } -bool LLWLParamManager::setParamSet(const std::string& name, LLWLParamSet& param) +bool LLWLParamManager::setParamSet(const std::string& name, LLWLParamSet& param, LLEnvKey::EScope scope) { - const LLWLParamKey key(name, LLEnvKey::SCOPE_LOCAL); + const LLWLParamKey key(name, scope); return setParamSet(key, param); } @@ -621,9 +619,9 @@ bool LLWLParamManager::setParamSet(const LLWLParamKey& key, LLWLParamSet& param) return true; } -bool LLWLParamManager::setParamSet(const std::string& name, const LLSD & param) +bool LLWLParamManager::setParamSet(const std::string& name, const LLSD & param, LLEnvKey::EScope scope) { - const LLWLParamKey key(name, LLEnvKey::SCOPE_LOCAL); + const LLWLParamKey key(name, scope); return setParamSet(key, param); } @@ -656,7 +654,7 @@ bool LLWLParamManager::removeParamSet(const LLWLParamKey& key, bool delete_from_ if (key.scope == LLEnvKey::SCOPE_REGION) { - llwarns << "Removing region skies not supported" << llendl; + LL_WARNS() << "Removing region skies not supported" << LL_ENDL; llassert(key.scope == LLEnvKey::SCOPE_LOCAL); return false; } @@ -793,7 +791,7 @@ void LLWLParamManager::initHack() if (!LLDayCycleManager::instance().getPreset(preferred_day, mDay)) { // Fall back to default. - llwarns << "No day cycle named " << preferred_day << ", falling back to defaults" << llendl; + LL_WARNS() << "No day cycle named " << preferred_day << ", falling back to defaults" << LL_ENDL; mDay.loadDayCycleFromFile("Default.xml"); // *TODO: Fix user preferences accordingly. @@ -803,7 +801,7 @@ void LLWLParamManager::initHack() std::string sky = LLEnvManagerNew::instance().getSkyPresetName(); if (!getParamSet(LLWLParamKey(sky, LLWLParamKey::SCOPE_LOCAL), mCurParams)) { - llwarns << "No sky preset named " << sky << ", falling back to defaults" << llendl; + LL_WARNS() << "No sky preset named " << sky << ", falling back to defaults" << LL_ENDL; getParamSet(LLWLParamKey("Default", LLWLParamKey::SCOPE_LOCAL), mCurParams); // *TODO: Fix user preferences accordingly. diff --git a/indra/newview/llwlparammanager.h b/indra/newview/llwlparammanager.h index d244d4c479..8318f0414d 100644 --- a/indra/newview/llwlparammanager.h +++ b/indra/newview/llwlparammanager.h @@ -205,11 +205,11 @@ class LLWLParamManager : public LLSingleton bool hasParamSet(const LLWLParamKey& key); /// set the param in the list with a new param - bool setParamSet(const std::string& name, LLWLParamSet& param); + bool setParamSet(const std::string& name, LLWLParamSet& param, LLEnvKey::EScope scope = LLEnvKey::SCOPE_LOCAL); bool setParamSet(const LLWLParamKey& key, LLWLParamSet& param); /// set the param in the list with a new param - bool setParamSet(const std::string& name, LLSD const & param); + bool setParamSet(const std::string& name, LLSD const & param, LLEnvKey::EScope scope = LLEnvKey::SCOPE_LOCAL); bool setParamSet(const LLWLParamKey& key, LLSD const & param); /// gets rid of a parameter and any references to it diff --git a/indra/newview/llwlparamset.cpp b/indra/newview/llwlparamset.cpp index 8691a245c9..0e2769df26 100644 --- a/indra/newview/llwlparamset.cpp +++ b/indra/newview/llwlparamset.cpp @@ -44,31 +44,49 @@ #include +static LLStaticHashedString sStarBrightness("star_brightness"); +static LLStaticHashedString sPresetNum("preset_num"); +static LLStaticHashedString sSunAngle("sun_angle"); +static LLStaticHashedString sEastAngle("east_angle"); +static LLStaticHashedString sEnableCloudScroll("enable_cloud_scroll"); +static LLStaticHashedString sCloudScrollRate("cloud_scroll_rate"); +static LLStaticHashedString sLightNorm("lightnorm"); +static LLStaticHashedString sCloudDensity("cloud_pos_density1"); +static LLStaticHashedString sCloudScale("cloud_scale"); +static LLStaticHashedString sCloudShadow("cloud_shadow"); +static LLStaticHashedString sDensityMultiplier("density_multiplier"); +static LLStaticHashedString sDistanceMultiplier("distance_multiplier"); +static LLStaticHashedString sHazeDensity("haze_density"); +static LLStaticHashedString sHazeHorizon("haze_horizon"); +static LLStaticHashedString sMaxY("max_y"); + LLWLParamSet::LLWLParamSet(void) : mName("Unnamed Preset"), mCloudScrollXOffset(0.f), mCloudScrollYOffset(0.f) {} -static LLFastTimer::DeclareTimer FTM_WL_PARAM_UPDATE("WL Param Update"); +static LLTrace::BlockTimerStatHandle FTM_WL_PARAM_UPDATE("WL Param Update"); void LLWLParamSet::update(LLGLSLShader * shader) const { - LLFastTimer t(FTM_WL_PARAM_UPDATE); - - for(LLSD::map_const_iterator i = mParamValues.beginMap(); - i != mParamValues.endMap(); - ++i) + LL_RECORD_BLOCK_TIME(FTM_WL_PARAM_UPDATE); + LLSD::map_const_iterator i = mParamValues.beginMap(); + std::vector::const_iterator n = mParamHashedNames.begin(); + for(;(i != mParamValues.endMap()) && (n != mParamHashedNames.end());++i, n++) { - const std::string& param = i->first; + const LLStaticHashedString& param = *n; - if( param == "star_brightness" || param == "preset_num" || param == "sun_angle" || - param == "east_angle" || param == "enable_cloud_scroll" || - param == "cloud_scroll_rate" || param == "lightnorm" ) + // check that our pre-hashed names are still tracking the mParamValues map correctly + // + llassert(param.String() == i->first); + + if (param == sStarBrightness || param == sPresetNum || param == sSunAngle || + param == sEastAngle || param == sEnableCloudScroll || + param == sCloudScrollRate || param == sLightNorm ) { continue; } - - if(param == "cloud_pos_density1") + else if (param == sCloudDensity) { LLVector4 val; val.mV[0] = F32(i->second[0].asReal()) + mCloudScrollXOffset; @@ -80,55 +98,58 @@ void LLWLParamSet::update(LLGLSLShader * shader) const shader->uniform4fv(param, 1, val.mV); stop_glerror(); } - else if (param == "cloud_scale" || param == "cloud_shadow" || - param == "density_multiplier" || param == "distance_multiplier" || - param == "haze_density" || param == "haze_horizon" || - param == "max_y" ) - { - F32 val = (F32) i->second[0].asReal(); - - stop_glerror(); - shader->uniform1f(param, val); - stop_glerror(); - } else // param is the uniform name { // handle all the different cases - if (i->second.isArray() && i->second.size() == 4) + if (i->second.isArray()) { - LLVector4 val; - - val.mV[0] = (F32) i->second[0].asReal(); - val.mV[1] = (F32) i->second[1].asReal(); - val.mV[2] = (F32) i->second[2].asReal(); - val.mV[3] = (F32) i->second[3].asReal(); - stop_glerror(); - shader->uniform4fv(param, 1, val.mV); + // Switch statement here breaks msbuild for some reason + if (i->second.size() == 4) + { + LLVector4 val( + i->second[0].asFloat(), + i->second[1].asFloat(), + i->second[2].asFloat(), + i->second[3].asFloat() + ); + shader->uniform4fv(param, 1, val.mV); + } + else if (i->second.size() == 3) + { + shader->uniform3f(param, + i->second[0].asFloat(), + i->second[1].asFloat(), + i->second[2].asFloat()); + } + else if (i->second.size() == 2) + { + shader->uniform2f(param, + i->second[0].asFloat(), + i->second[1].asFloat()); + } + else if (i->second.size() == 1) + { + shader->uniform1f(param, i->second[0].asFloat()); + } stop_glerror(); } else if (i->second.isReal()) { - F32 val = (F32) i->second.asReal(); - stop_glerror(); - shader->uniform1f(param, val); + shader->uniform1f(param, i->second.asFloat()); stop_glerror(); } else if (i->second.isInteger()) { - S32 val = (S32) i->second.asInteger(); - stop_glerror(); - shader->uniform1i(param, val); + shader->uniform1i(param, i->second.asInteger()); stop_glerror(); } else if (i->second.isBoolean()) { - S32 val = (i->second.asBoolean() ? 1 : 0); - stop_glerror(); - shader->uniform1i(param, val); + shader->uniform1i(param, i->second.asBoolean() ? 1 : 0); stop_glerror(); } } @@ -136,9 +157,9 @@ void LLWLParamSet::update(LLGLSLShader * shader) const } void LLWLParamSet::set(const std::string& paramName, float x) -{ +{ // handle case where no array - if(mParamValues[paramName].isReal()) + if(mParamValues.isUndefined() || mParamValues[paramName].isReal()) { mParamValues[paramName] = x; } @@ -246,7 +267,7 @@ void LLWLParamSet::setSunAngle(float val) val = F_TWO_PI * num; } - mParamValues["sun_angle"] = val; + set("sun_angle", val); } @@ -260,7 +281,7 @@ void LLWLParamSet::setEastAngle(float val) val = F_TWO_PI * num; } - mParamValues["east_angle"] = val; + set("east_angle", val); } void LLWLParamSet::mix(LLWLParamSet& src, LLWLParamSet& dest, F32 weight) @@ -273,7 +294,7 @@ void LLWLParamSet::mix(LLWLParamSet& src, LLWLParamSet& dest, F32 weight) F32 cloudPos1Y = (F32) mParamValues["cloud_pos_density1"][1].asReal(); F32 cloudPos2X = (F32) mParamValues["cloud_pos_density2"][0].asReal(); F32 cloudPos2Y = (F32) mParamValues["cloud_pos_density2"][1].asReal(); - F32 cloudCover = (F32) mParamValues["cloud_shadow"][0].asReal(); + F32 cloudCover = (F32) mParamValues["cloud_shadow"].asReal(); LLSD srcVal; LLSD destVal; @@ -362,11 +383,9 @@ void LLWLParamSet::mix(LLWLParamSet& src, LLWLParamSet& dest, F32 weight) // now setup the sun properly // reset those cloud positions - mParamValues["cloud_pos_density1"][0] = cloudPos1X; - mParamValues["cloud_pos_density1"][1] = cloudPos1Y; - mParamValues["cloud_pos_density2"][0] = cloudPos2X; - mParamValues["cloud_pos_density2"][1] = cloudPos2Y; - mParamValues["cloud_shadow"][0] = cloudCover; + set("cloud_pos_density1", cloudPos1X, cloudPos1Y); + set("cloud_pos_density2", cloudPos2X, cloudPos2Y); + set("cloud_shadow", cloudCover); } void LLWLParamSet::updateCloudScrolling(void) @@ -384,3 +403,23 @@ void LLWLParamSet::updateCloudScrolling(void) mCloudScrollYOffset += F32(delta_t * (getCloudScrollY() - 10.f) / 100.f); } } + +void LLWLParamSet::updateHashedNames() +{ + mParamHashedNames.clear(); + // Iterate through values + for(LLSD::map_iterator iter = mParamValues.beginMap(); iter != mParamValues.endMap(); ++iter) + { + LLStaticHashedString param(iter->first); + mParamHashedNames.push_back(param); + if (iter->second.isArray() && (param == sCloudScale || param == sCloudShadow || + param == sDensityMultiplier || param == sDistanceMultiplier || + param == sHazeDensity || param == sHazeHorizon || + param == sMaxY)) + { + // Params are incorrect in the XML files. These SHOULD be F32, not arrays. + iter->second.assign(iter->second[0]); + } + } +} + diff --git a/indra/newview/llwlparamset.h b/indra/newview/llwlparamset.h index 6e04ac1100..afede29f1b 100644 --- a/indra/newview/llwlparamset.h +++ b/indra/newview/llwlparamset.h @@ -38,6 +38,7 @@ #include "v4math.h" #include "v4color.h" +#include "llstaticstringtable.h" class LLWLParamSet; class LLGLSLShader; @@ -54,9 +55,12 @@ class LLWLParamSet { private: LLSD mParamValues; - + std::vector mParamHashedNames; + float mCloudScrollXOffset, mCloudScrollYOffset; + void updateHashedNames(); + public: LLWLParamSet(); @@ -184,6 +188,8 @@ inline void LLWLParamSet::setAll(const LLSD& val) if(val.isMap()) { mParamValues = val; } + + updateHashedNames(); } inline const LLSD& LLWLParamSet::getAll() @@ -192,7 +198,7 @@ inline const LLSD& LLWLParamSet::getAll() } inline void LLWLParamSet::setStarBrightness(float val) { - mParamValues["star_brightness"] = val; + set("star_brightness", val); } inline F32 LLWLParamSet::getStarBrightness() { @@ -207,7 +213,6 @@ inline F32 LLWLParamSet::getEastAngle() { return (F32) mParamValues["east_angle"].asReal(); } - inline void LLWLParamSet::setEnableCloudScrollX(bool val) { mParamValues["enable_cloud_scroll"][0] = val; } diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp index 5c8c8f4a85..b27055552c 100644 --- a/indra/newview/llworld.cpp +++ b/indra/newview/llworld.cpp @@ -62,12 +62,14 @@ #include "pipeline.h" #include "llappviewer.h" // for do_disconnect() #include "llpacketring.h" +#include "hippogridmanager.h" #include #include #include #include + // // Globals // @@ -81,12 +83,19 @@ const S32 WORLD_PATCH_SIZE = 16; extern LLColor4U MAX_WATER_COLOR; -const U32 LLWorld::mWidth = 256; +// Aurora Sim +//const U32 LLWorld::mWidth = 256; +U32 LLWorld::mWidth = 256; +U32 LLWorld::mLength = 256; +// Aurora Sim // meters/point, therefore mWidth * mScale = meters per edge const F32 LLWorld::mScale = 1.f; -const F32 LLWorld::mWidthInMeters = mWidth * mScale; +// Aurora Sim +//const F32 LLWorld::mWidthInMeters = mWidth * mScale; +F32 LLWorld::mWidthInMeters = mWidth * mScale; +// Aurora Sim // // Functions @@ -128,11 +137,12 @@ void LLWorld::destroyClass() { mHoleWaterObjects.clear(); gObjectList.destroy(); - for(region_list_t::iterator region_it = mRegionList.begin(); region_it != mRegionList.end(); ) + for(region_list_t::iterator region_it = mRegionList.begin(), region_it_end(mRegionList.end()); region_it != region_it_end; ) { LLViewerRegion* region_to_delete = *region_it++; removeRegion(region_to_delete->getHost()); } + if(LLVOCache::hasInstance()) { LLVOCache::getInstance()->destroyClass() ; @@ -144,46 +154,70 @@ void LLWorld::destroyClass() { mEdgeWaterObjects[i] = NULL; } + + //make all visible drawbles invisible. + LLDrawable::incrementVisible(); + +} + +void LLWorld::setRegionSize(const U32& width, const U32& length) +{ + mWidth = width ? width : 256; // Width of 0 is really 256 + mLength = length ? length : 256; // Length of 0 is really 256 + mWidthInMeters = mWidth * mScale; } LLViewerRegion* LLWorld::addRegion(const U64 ®ion_handle, const LLHost &host) { - llinfos << "Add region with handle: " << region_handle << " on host " << host << llendl; + LL_INFOS() << "Add region with handle: " << region_handle << " on host " << host << LL_ENDL; LLViewerRegion *regionp = getRegionFromHandle(region_handle); + std::string seedUrl; if (regionp) { - llinfos << "Region exists, removing it " << llendl; LLHost old_host = regionp->getHost(); // region already exists! if (host == old_host && regionp->isAlive()) { // This is a duplicate for the same host and it's alive, don't bother. + LL_INFOS() << "Region already exists and is alive, using existing region" << LL_ENDL; return regionp; } if (host != old_host) { - llwarns << "LLWorld::addRegion exists, but old host " << old_host - << " does not match new host " << host << llendl; + LL_WARNS() << "LLWorld::addRegion exists, but old host " << old_host + << " does not match new host " << host + << ", removing old region and creating new" << LL_ENDL; } if (!regionp->isAlive()) { - llwarns << "LLWorld::addRegion exists, but isn't alive" << llendl; + LL_WARNS() << "LLWorld::addRegion exists, but isn't alive. Removing old region and creating new" << LL_ENDL; } + // Save capabilities seed URL + seedUrl = regionp->getCapability("Seed"); + // Kill the old host, and then we can continue on and add the new host. We have to kill even if the host // matches, because all the agent state for the new camera is completely different. removeRegion(old_host); } + else + { + LL_INFOS() << "Region does not exist, creating new one" << LL_ENDL; + } U32 iindex = 0; U32 jindex = 0; from_region_handle(region_handle, &iindex, &jindex); - S32 x = (S32)(iindex/mWidth); - S32 y = (S32)(jindex/mWidth); - llinfos << "Adding new region (" << x << ":" << y << ")" << llendl; - llinfos << "Host: " << host << llendl; +// Aurora Sim + //S32 x = (S32)(iindex/mWidth); + //S32 y = (S32)(jindex/mWidth); + S32 x = (S32)(iindex/256); //MegaRegion + S32 y = (S32)(jindex/256); //MegaRegion +// Aurora Sim + LL_INFOS() << "Adding new region (" << x << ":" << y << ")" + << " on host: " << host << LL_ENDL; LLVector3d origin_global; @@ -196,7 +230,12 @@ LLViewerRegion* LLWorld::addRegion(const U64 ®ion_handle, const LLHost &host) getRegionWidthInMeters() ); if (!regionp) { - llerrs << "Unable to create new region!" << llendl; + LL_ERRS() << "Unable to create new region!" << LL_ENDL; + } + + if ( !seedUrl.empty() ) + { + regionp->setCapability("Seed", seedUrl); } //Classic clouds @@ -231,13 +270,43 @@ LLViewerRegion* LLWorld::addRegion(const U64 ®ion_handle, const LLHost &host) { adj_x = region_x + width * gDirAxes[dir][0]; adj_y = region_y + width * gDirAxes[dir][1]; - to_region_handle(adj_x, adj_y, &adj_handle); - neighborp = getRegionFromHandle(adj_handle); - if (neighborp) + if (mWidth == 256 && mLength == 256) + { + to_region_handle(adj_x, adj_y, &adj_handle); + neighborp = getRegionFromHandle(adj_handle); + if (neighborp) + { + //LL_INFOS() << "Connecting " << region_x << ":" << region_y << " -> " << adj_x << ":" << adj_y << LL_ENDL; + regionp->connectNeighbor(neighborp, dir); + } + } + else // Unconventional region size { - //llinfos << "Connecting " << region_x << ":" << region_y << " -> " << adj_x << ":" << adj_y << llendl; - regionp->connectNeighbor(neighborp, dir); + LLViewerRegion* last_neighborp = NULL; + if(gDirAxes[dir][0] < 0) adj_x = region_x - WORLD_PATCH_SIZE; + if(gDirAxes[dir][1] < 0) adj_y = region_y - WORLD_PATCH_SIZE; + + for (S32 offset = 0; offset < width; offset += WORLD_PATCH_SIZE) + { + to_region_handle(adj_x, adj_y, &adj_handle); + neighborp = getRegionFromHandle(adj_handle); + + if (neighborp && last_neighborp != neighborp) + { + //LL_INFOS() << "Connecting " << region_x << ":" << region_y << " -> " << adj_x << ":" << adj_y << LL_ENDL; + regionp->connectNeighbor(neighborp, dir); + last_neighborp = neighborp; + } + + if (dir == NORTH || dir == SOUTH) + adj_x += WORLD_PATCH_SIZE; + else if (dir == EAST || dir == WEST) + adj_y += WORLD_PATCH_SIZE; + else if (dir == NORTHEAST || dir == NORTHWEST || dir == SOUTHWEST || dir == SOUTHEAST) + break; + + } } } @@ -254,31 +323,31 @@ void LLWorld::removeRegion(const LLHost &host) LLViewerRegion *regionp = getRegion(host); if (!regionp) { - llwarns << "Trying to remove region that doesn't exist!" << llendl; + LL_WARNS() << "Trying to remove region that doesn't exist!" << LL_ENDL; return; } if (regionp == gAgent.getRegion()) { - for (region_list_t::iterator iter = mRegionList.begin(); - iter != mRegionList.end(); ++iter) + for (region_list_t::iterator iter = mRegionList.begin(), iter_end(mRegionList.end()); + iter != iter_end; ++iter) { LLViewerRegion* reg = *iter; - llwarns << "RegionDump: " << reg->getName() + LL_WARNS() << "RegionDump: " << reg->getName() << " " << reg->getHost() << " " << reg->getOriginGlobal() - << llendl; + << LL_ENDL; } - llwarns << "Agent position global " << gAgent.getPositionGlobal() + LL_WARNS() << "Agent position global " << gAgent.getPositionGlobal() << " agent " << gAgent.getPositionAgent() - << llendl; + << LL_ENDL; - llwarns << "Regions visited " << gAgent.getRegionsVisited() << llendl; + LL_WARNS() << "Regions visited " << gAgent.getRegionsVisited() << LL_ENDL; - llwarns << "gFrameTimeSeconds " << gFrameTimeSeconds << llendl; + LL_WARNS() << "gFrameTimeSeconds " << gFrameTimeSeconds << LL_ENDL; - llwarns << "Disabling region " << regionp->getName() << " that agent is in!" << llendl; + LL_WARNS() << "Disabling region " << regionp->getName() << " that agent is in!" << LL_ENDL; LLAppViewer::instance()->forceDisconnect(LLTrans::getString("YouHaveBeenDisconnected")); regionp->saveObjectCache() ; //force to save objects here in case that the object cache is about to be destroyed. @@ -286,7 +355,7 @@ void LLWorld::removeRegion(const LLHost &host) } from_region_handle(regionp->getHandle(), &x, &y); - llinfos << "Removing region " << x << ":" << y << llendl; + LL_INFOS() << "Removing region " << x << ":" << y << LL_ENDL; mRegionList.remove(regionp); mActiveRegionList.remove(regionp); @@ -294,20 +363,21 @@ void LLWorld::removeRegion(const LLHost &host) mVisibleRegionList.remove(regionp); mRegionRemovedSignal(regionp); + + updateWaterObjects(); + //double check all objects of this region are removed. gObjectList.clearAllMapObjectsInRegion(regionp) ; //llassert_always(!gObjectList.hasMapObjectInRegion(regionp)) ; - updateWaterObjects(); - - delete regionp; + delete regionp; // - Use after free fix? } LLViewerRegion* LLWorld::getRegion(const LLHost &host) { - for (region_list_t::iterator iter = mRegionList.begin(); - iter != mRegionList.end(); ++iter) + for (region_list_t::iterator iter = mRegionList.begin(), iter_end(mRegionList.end()); + iter != iter_end; ++iter) { LLViewerRegion* regionp = *iter; if (regionp->getHost() == host) @@ -325,8 +395,8 @@ LLViewerRegion* LLWorld::getRegionFromPosAgent(const LLVector3 &pos) LLViewerRegion* LLWorld::getRegionFromPosGlobal(const LLVector3d &pos) { - for (region_list_t::iterator iter = mRegionList.begin(); - iter != mRegionList.end(); ++iter) + for (region_list_t::iterator iter = mRegionList.begin(), iter_end = mRegionList.end(); + iter != iter_end; ++iter) { LLViewerRegion* regionp = *iter; if (regionp->pointInRegionGlobal(pos)) @@ -409,11 +479,24 @@ LLVector3d LLWorld::clipToVisibleRegions(const LLVector3d &start_pos, const LLVe LLViewerRegion* LLWorld::getRegionFromHandle(const U64 &handle) { - for (region_list_t::iterator iter = mRegionList.begin(); - iter != mRegionList.end(); ++iter) +// Aurora Sim + U32 x, y; + from_region_handle(handle, &x, &y); +// Aurora Sim + + for (region_list_t::iterator iter = mRegionList.begin(), iter_end(mRegionList.end()); + iter != iter_end; ++iter) { LLViewerRegion* regionp = *iter; - if (regionp->getHandle() == handle) +// Aurora Sim + //if (regionp->getHandle() == handle) + U32 checkRegionX, checkRegionY; + F32 checkRegionWidth = regionp->getWidth(); + from_region_handle(regionp->getHandle(), &checkRegionX, &checkRegionY); + + if (x >= checkRegionX && x < (checkRegionX + checkRegionWidth) && + y >= checkRegionY && y < (checkRegionY + checkRegionWidth)) +// Aurora Sim { return regionp; } @@ -423,8 +506,8 @@ LLViewerRegion* LLWorld::getRegionFromHandle(const U64 &handle) LLViewerRegion* LLWorld::getRegionFromID(const LLUUID& region_id) { - for (region_list_t::iterator iter = mRegionList.begin(); - iter != mRegionList.end(); ++iter) + for (region_list_t::iterator iter = mRegionList.begin(), iter_end(mRegionList.end()); + iter != iter_end; ++iter) { LLViewerRegion* regionp = *iter; if (regionp->getRegionID() == region_id) @@ -450,8 +533,8 @@ void LLWorld::updateAgentOffset(const LLVector3d &offset_global) BOOL LLWorld::positionRegionValidGlobal(const LLVector3d &pos_global) { - for (region_list_t::iterator iter = mRegionList.begin(); - iter != mRegionList.end(); ++iter) + for (region_list_t::iterator iter = mRegionList.begin(), iter_end(mRegionList.end()); + iter != iter_end; ++iter) { LLViewerRegion* regionp = *iter; if (regionp->pointInRegionGlobal(pos_global)) @@ -599,7 +682,7 @@ LLSurfacePatch * LLWorld::resolveLandPatchGlobal(const LLVector3d &pos_global) return NULL; } - return regionp->getLand().resolvePatchGlobal(pos_global); + return regionp->getLand().resolvePatchGlobal(pos_global).get(); } @@ -620,8 +703,8 @@ void LLWorld::updateVisibilities() F32 cur_far_clip = LLViewerCamera::getInstance()->getFar(); // Go through the culled list and check for visible regions (region is visible if land is visible) - for (region_list_t::iterator iter = mCulledRegionList.begin(); - iter != mCulledRegionList.end(); ) + for (region_list_t::iterator iter = mCulledRegionList.begin(), iter_end(mCulledRegionList.end()); + iter != iter_end; ) { region_list_t::iterator curiter = iter++; LLViewerRegion* regionp = *curiter; @@ -630,7 +713,8 @@ void LLWorld::updateVisibilities() if (part) { LLSpatialGroup* group = (LLSpatialGroup*) part->mOctree->getListener(0); - if (LLViewerCamera::getInstance()->AABBInFrustum(group->mBounds[0], group->mBounds[1])) + const LLVector4a* bounds = group->getBounds(); + if (LLViewerCamera::getInstance()->AABBInFrustum(bounds[0], bounds[1])) { mCulledRegionList.erase(curiter); mVisibleRegionList.push_back(regionp); @@ -639,8 +723,8 @@ void LLWorld::updateVisibilities() } // Update all of the visible regions - for (region_list_t::iterator iter = mVisibleRegionList.begin(); - iter != mVisibleRegionList.end(); ) + for (region_list_t::iterator iter = mVisibleRegionList.begin(), iter_end(mVisibleRegionList.end()); + iter != iter_end; ) { region_list_t::iterator curiter = iter++; LLViewerRegion* regionp = *curiter; @@ -653,13 +737,11 @@ void LLWorld::updateVisibilities() if (part) { LLSpatialGroup* group = (LLSpatialGroup*) part->mOctree->getListener(0); - if (LLViewerCamera::getInstance()->AABBInFrustum(group->mBounds[0], group->mBounds[1])) + const LLVector4a* bounds = group->getBounds(); + if (LLViewerCamera::getInstance()->AABBInFrustum(bounds[0], bounds[1])) { regionp->calculateCameraDistance(); - if (!gNoRender) - { - regionp->getLand().updatePatchVisibilities(gAgent); - } + regionp->getLand().updatePatchVisibilities(gAgent); } else { @@ -681,8 +763,8 @@ void LLWorld::updateRegions(F32 max_update_time) BOOL did_one = FALSE; // Perform idle time updates for the regions (and associated surfaces) - for (region_list_t::iterator iter = mActiveRegionList.begin()/*mRegionList.begin()*/; - iter != mActiveRegionList.end()/*mRegionList.end()*/; ++iter) + for (region_list_t::iterator iter = mActiveRegionList.begin()/*mRegionList.begin()*/, iter_end(mActiveRegionList.end()/*mRegionList.end()*/); + iter != iter_end; ++iter) { LLViewerRegion* regionp = *iter; F32 max_time = max_update_time - update_timer.getElapsedTimeF32(); @@ -696,6 +778,17 @@ void LLWorld::updateRegions(F32 max_update_time) } } + +void LLWorld::clearAllVisibleObjects() +{ + for (region_list_t::iterator iter = mRegionList.begin(); + iter != mRegionList.end(); ++iter) + { + //clear all cached visible objects. + (*iter)->clearCachedVisibleObjects(); + } +} + void LLWorld::updateParticles() { static const LLCachedControl freeze_time("FreezeTime",false); @@ -722,8 +815,9 @@ void LLWorld::updateClouds(const F32 dt) { // Update all the cloud puff positions, and timer based stuff // such as death decay + region_list_t::iterator iter_end(mActiveRegionList.end()); for (region_list_t::iterator iter = mActiveRegionList.begin(); - iter != mActiveRegionList.end(); ++iter) + iter != iter_end; ++iter) { LLViewerRegion* regionp = *iter; regionp->mCloudLayer.updatePuffs(dt); @@ -731,7 +825,7 @@ void LLWorld::updateClouds(const F32 dt) // Reshuffle who owns which puffs for (region_list_t::iterator iter = mActiveRegionList.begin(); - iter != mActiveRegionList.end(); ++iter) + iter != iter_end; ++iter) { LLViewerRegion* regionp = *iter; regionp->mCloudLayer.updatePuffOwnership(); @@ -739,7 +833,7 @@ void LLWorld::updateClouds(const F32 dt) // Add new puffs for (region_list_t::iterator iter = mActiveRegionList.begin(); - iter != mActiveRegionList.end(); ++iter) + iter != iter_end; ++iter) { LLViewerRegion* regionp = *iter; regionp->mCloudLayer.updatePuffCount(); @@ -753,8 +847,8 @@ LLCloudGroup* LLWorld::findCloudGroup(const LLCloudPuff &puff) { // Update all the cloud puff positions, and timer based stuff // such as death decay - for (region_list_t::iterator iter = mActiveRegionList.begin(); - iter != mActiveRegionList.end(); ++iter) + for (region_list_t::iterator iter = mActiveRegionList.begin(), iter_end(mActiveRegionList.end()); + iter != iter_end; ++iter) { LLViewerRegion* regionp = *iter; LLCloudGroup *groupp = regionp->mCloudLayer.findCloudGroup(puff); @@ -768,14 +862,13 @@ LLCloudGroup* LLWorld::findCloudGroup(const LLCloudPuff &puff) } #endif - void LLWorld::renderPropertyLines() { S32 region_count = 0; S32 vertex_count = 0; - for (region_list_t::iterator iter = mVisibleRegionList.begin(); - iter != mVisibleRegionList.end(); ++iter) + for (region_list_t::iterator iter = mVisibleRegionList.begin(), iter_end(mVisibleRegionList.end()); + iter != iter_end; ++iter) { LLViewerRegion* regionp = *iter; region_count++; @@ -789,8 +882,8 @@ void LLWorld::updateNetStats() F32 bits = 0.f; U32 packets = 0; - for (region_list_t::iterator iter = mActiveRegionList.begin(); - iter != mActiveRegionList.end(); ++iter) + for (region_list_t::iterator iter = mActiveRegionList.begin(), iter_end(mActiveRegionList.end()); + iter != iter_end; ++iter) { LLViewerRegion* regionp = *iter; regionp->updateNetStats(); @@ -827,12 +920,12 @@ void LLWorld::updateNetStats() void LLWorld::printPacketsLost() { - llinfos << "Simulators:" << llendl; - llinfos << "----------" << llendl; + LL_INFOS() << "Simulators:" << LL_ENDL; + LL_INFOS() << "----------" << LL_ENDL; LLCircuitData *cdp = NULL; - for (region_list_t::iterator iter = mActiveRegionList.begin(); - iter != mActiveRegionList.end(); ++iter) + for (region_list_t::iterator iter = mActiveRegionList.begin(), iter_end(mActiveRegionList.end()); + iter != iter_end; ++iter) { LLViewerRegion* regionp = *iter; cdp = gMessageSystem->mCircuitInfo.findCircuit(regionp->getHost()); @@ -840,8 +933,8 @@ void LLWorld::printPacketsLost() { LLVector3d range = regionp->getCenterGlobal() - gAgent.getPositionGlobal(); - llinfos << regionp->getHost() << ", range: " << range.length() - << " packets lost: " << cdp->getPacketsLost() << llendl; + LL_INFOS() << regionp->getHost() << ", range: " << range.length() + << " packets lost: " << cdp->getPacketsLost() << LL_ENDL; } } } @@ -862,7 +955,10 @@ F32 LLWorld::getLandFarClip() const void LLWorld::setLandFarClip(const F32 far_clip) { - static S32 const rwidth = (S32)REGION_WIDTH_U32; +// Aurora Sim + //static S32 const rwidth = (S32)REGION_WIDTH_U32; + S32 const rwidth = (S32)getRegionWidthInMeters(); +// Aurora Sim S32 const n1 = (llceil(mLandFarClip) - 1) / rwidth; S32 const n2 = (llceil(far_clip) - 1) / rwidth; bool need_water_objects_update = n1 != n2; @@ -879,7 +975,7 @@ void LLWorld::setLandFarClip(const F32 far_clip) // a (possibly) new water height. Update it in our local copy. void LLWorld::waterHeightRegionInfo(std::string const& sim_name, F32 water_height) { - for (region_list_t::iterator iter = mRegionList.begin(); iter != mRegionList.end(); ++iter) + for (region_list_t::iterator iter = mRegionList.begin(), iter_end(mRegionList.end()); iter != iter_end; ++iter) { if ((*iter)->getName() == sim_name) { @@ -933,12 +1029,14 @@ void LLWorld::updateWaterObjects() } if (mRegionList.empty()) { - llwarns << "No regions!" << llendl; + LL_WARNS() << "No regions!" << LL_ENDL; return; } + LLViewerRegion const* regionp = gAgent.getRegion(); + // Region width in meters. - S32 const rwidth = (S32)REGION_WIDTH_U32; + S32 const rwidth = (S32)regionp->getWidth(); // The distance we might see into the void // when standing on the edge of a region, in meters. @@ -955,15 +1053,14 @@ void LLWorld::updateWaterObjects() S32 const range = nsims * rwidth; // Get South-West corner of current region. - LLViewerRegion const* regionp = gAgent.getRegion(); U32 region_x, region_y; from_region_handle(regionp->getHandle(), ®ion_x, ®ion_y); // The min. and max. coordinates of the South-West corners of the Hole water objects. S32 const min_x = (S32)region_x - range; S32 const min_y = (S32)region_y - range; - S32 const max_x = (S32)region_x + range; - S32 const max_y = (S32)region_y + range; + S32 const max_x = (S32)region_x + rwidth-256 + range; + S32 const max_y = (S32)region_y + rwidth-256 + range; // Attempt to determine a sensible water height for all the // Hole Water objects. @@ -1051,7 +1148,7 @@ void LLWorld::updateWaterObjects() // Count the found coastline. F32 new_water_height = water_heights[index]; LL_DEBUGS("WaterHeight") << " This is void; counting coastline with water height of " << new_water_height << LL_ENDL; - S32 new_water_height_cm = llround(new_water_height * 100); + S32 new_water_height_cm = ll_round(new_water_height * 100); int count = (water_height_counts[new_water_height_cm] += 1); // Just use the lowest water height: this is mainly about the horizon water, // and whatever we do, we don't want it to be possible to look under the water @@ -1102,22 +1199,22 @@ void LLWorld::updateWaterObjects() LL_DEBUGS("WaterHeight") << " Found a new region (name: " << new_region_found->getName() << "; water height: " << water_heights[cindex] << " m)!" << LL_ENDL; } } - llinfos << "Number of connected regions: " << number_of_connected_regions << " (" << uninitialized_regions << + LL_INFOS() << "Number of connected regions: " << number_of_connected_regions << " (" << uninitialized_regions << " uninitialized); number of regions bordering Hole water: " << bordering_hole << - "; number of regions bordering Edge water: " << bordering_edge << llendl; - llinfos << "Coastline count (height, count): "; + "; number of regions bordering Edge water: " << bordering_edge << LL_ENDL; + LL_INFOS() << "Coastline count (height, count): "; bool first = true; for (std::map::iterator iter = water_height_counts.begin(); iter != water_height_counts.end(); ++iter) { - if (!first) llcont << ", "; - llcont << "(" << (iter->first / 100.f) << ", " << iter->second << ")"; + if (!first) LL_CONT << ", "; + LL_CONT << "(" << (iter->first / 100.f) << ", " << iter->second << ")"; first = false; } - llcont << llendl; - llinfos << "Water height used for Hole and Edge water objects: " << water_height << llendl; + LL_CONT << LL_ENDL; + LL_INFOS() << "Water height used for Hole and Edge water objects: " << water_height << LL_ENDL; // Update all Region water objects. - for (region_list_t::iterator iter = mRegionList.begin(); iter != mRegionList.end(); ++iter) + for (region_list_t::iterator iter = mRegionList.begin(), iter_end(mRegionList.end()); iter != iter_end; ++iter) { LLViewerRegion* regionp = *iter; LLVOWater* waterp = regionp->getLand().getWaterObj(); @@ -1142,19 +1239,19 @@ void LLWorld::updateWaterObjects() // the current regions water height. F32 const box_height = 1024; F32 const water_center_z = water_height + box_height / 2; - + const S32 step = 256; // Create new Hole water objects within 'range' where there is no region. - for (S32 x = min_x; x <= max_x; x += rwidth) + for (S32 x = min_x; x <= max_x; x += step) { - for (S32 y = min_y; y <= max_y; y += rwidth) + for (S32 y = min_y; y <= max_y; y += step) { U64 region_handle = to_region_handle(x, y); if (!getRegionFromHandle(region_handle)) { LLVOWater* waterp = (LLVOWater*)gObjectList.createObjectViewer(LLViewerObject::LL_VO_VOID_WATER, gAgent.getRegion()); waterp->setUseTexture(FALSE); - waterp->setPositionGlobal(LLVector3d(x + rwidth / 2, y + rwidth / 2, water_center_z)); - waterp->setScale(LLVector3((F32)rwidth, (F32)rwidth, box_height)); + waterp->setPositionGlobal(LLVector3d(x + step / 2, y + step / 2, water_center_z)); + waterp->setScale(LLVector3((F32)step, (F32)step, box_height)); gPipeline.createObject(waterp); mHoleWaterObjects.push_back(waterp); } @@ -1162,10 +1259,10 @@ void LLWorld::updateWaterObjects() } // Center of the region. - S32 const center_x = region_x + rwidth / 2; - S32 const center_y = region_y + rwidth / 2; + S32 const center_x = region_x + step / 2; + S32 const center_y = region_y + step / 2; // Width of the area with Hole water objects. - S32 const width = rwidth + 2 * range; + S32 const width = step + 2 * range; S32 const horizon_extend = 2048 + 512 - range; // Legacy value. // The overlap is needed to get rid of sky pixels being visible between the // Edge and Hole water object at greater distances (due to floating point @@ -1232,8 +1329,8 @@ U64 LLWorld::getSpaceTimeUSec() const void LLWorld::requestCacheMisses() { - for (region_list_t::iterator iter = mRegionList.begin(); - iter != mRegionList.end(); ++iter) + for (region_list_t::iterator iter = mRegionList.begin(), iter_end(mRegionList.end()); + iter != iter_end; ++iter) { LLViewerRegion* regionp = *iter; regionp->requestCacheMisses(); @@ -1243,8 +1340,8 @@ void LLWorld::requestCacheMisses() void LLWorld::getInfo(LLSD& info) { LLSD region_info; - for (region_list_t::iterator iter = mRegionList.begin(); - iter != mRegionList.end(); ++iter) + for (region_list_t::iterator iter = mRegionList.begin(), iter_end(mRegionList.end()); + iter != iter_end; ++iter) { LLViewerRegion* regionp = *iter; regionp->getInfo(region_info); @@ -1255,8 +1352,8 @@ void LLWorld::getInfo(LLSD& info) void LLWorld::disconnectRegions() { LLMessageSystem* msg = gMessageSystem; - for (region_list_t::iterator iter = mRegionList.begin(); - iter != mRegionList.end(); ++iter) + for (region_list_t::iterator iter = mRegionList.begin(), iter_end(mRegionList.end()); + iter != iter_end; ++iter) { LLViewerRegion* regionp = *iter; if (regionp == gAgent.getRegion()) @@ -1265,7 +1362,7 @@ void LLWorld::disconnectRegions() continue; } - llinfos << "Sending AgentQuitCopy to: " << regionp->getHost() << llendl; + LL_INFOS() << "Sending AgentQuitCopy to: " << regionp->getHost() << LL_ENDL; msg->newMessageFast(_PREHASH_AgentQuitCopy); msg->nextBlockFast(_PREHASH_AgentData); msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); @@ -1276,11 +1373,20 @@ void LLWorld::disconnectRegions() } } -static LLFastTimer::DeclareTimer FTM_ENABLE_SIMULATOR("Enable Sim"); +static LLTrace::BlockTimerStatHandle FTM_ENABLE_SIMULATOR("Enable Sim"); void process_enable_simulator(LLMessageSystem *msg, void **user_data) { - LLFastTimer t(FTM_ENABLE_SIMULATOR); + LL_RECORD_BLOCK_TIME(FTM_ENABLE_SIMULATOR); + + if (!gAgent.getRegion()) + return; + + static LLCachedControl connectToNeighbors(gSavedSettings, "AlchemyConnectToNeighbors"); + if ((!connectToNeighbors) && ((gAgent.getTeleportState() == LLAgent::TELEPORT_LOCAL) + || (gAgent.getTeleportState() == LLAgent::TELEPORT_NONE))) + return; + // enable the appropriate circuit for this simulator and // add its values into the gSimulator structure U64 handle; @@ -1296,10 +1402,20 @@ void process_enable_simulator(LLMessageSystem *msg, void **user_data) // Viewer trusts the simulator. msg->enableCircuit(sim, TRUE); +// Aurora Sim + if (!gHippoGridManager->getConnectedGrid()->isSecondLife()) + { + U32 region_size_x = 256; + msg->getU32Fast(_PREHASH_SimulatorInfo, _PREHASH_RegionSizeX, region_size_x); + U32 region_size_y = 256; + msg->getU32Fast(_PREHASH_SimulatorInfo, _PREHASH_RegionSizeY, region_size_y); + LLWorld::getInstance()->setRegionSize(region_size_x, region_size_y); + } +// Aurora Sim LLWorld::getInstance()->addRegion(handle, sim); // give the simulator a message it can use to get ip and port - llinfos << "simulator_enable() Enabling " << sim << " with code " << msg->getOurCircuitCode() << llendl; + LL_INFOS() << "simulator_enable() Enabling " << sim << " with code " << msg->getOurCircuitCode() << LL_ENDL; msg->newMessageFast(_PREHASH_UseCircuitCode); msg->nextBlockFast(_PREHASH_CircuitCode); msg->addU32Fast(_PREHASH_Code, msg->getOurCircuitCode()); @@ -1327,7 +1443,7 @@ class LLEstablishAgentCommunication : public LLHTTPNode !input["body"].has("sim-ip-and-port") || !input["body"].has("seed-capability")) { - llwarns << "invalid parameters" << llendl; + LL_WARNS() << "invalid parameters" << LL_ENDL; return; } @@ -1336,10 +1452,12 @@ class LLEstablishAgentCommunication : public LLHTTPNode LLViewerRegion* regionp = LLWorld::getInstance()->getRegion(sim); if (!regionp) { - llwarns << "Got EstablishAgentCommunication for unknown region " - << sim << llendl; + LL_WARNS() << "Got EstablishAgentCommunication for unknown region " + << sim << LL_ENDL; return; } + LL_DEBUGS("CrossingCaps") << "Calling setSeedCapability from LLEstablishAgentCommunication::post. Seed cap == " + << input["body"]["seed-capability"] << LL_ENDL; regionp->setSeedCapability(input["body"]["seed-capability"]); } }; @@ -1350,7 +1468,7 @@ void process_disable_simulator(LLMessageSystem *mesgsys, void **user_data) { LLHost host = mesgsys->getSender(); - //llinfos << "Disabling simulator with message from " << host << llendl; + //LL_INFOS() << "Disabling simulator with message from " << host << LL_ENDL; LLWorld::getInstance()->removeRegion(host); mesgsys->disableCircuit(host); @@ -1363,8 +1481,8 @@ void process_region_handshake(LLMessageSystem* msg, void** user_data) LLViewerRegion* regionp = LLWorld::getInstance()->getRegion(host); if (!regionp) { - llwarns << "Got region handshake for unknown region " - << host << llendl; + LL_WARNS() << "Got region handshake for unknown region " + << host << LL_ENDL; return; } @@ -1437,7 +1555,7 @@ void send_agent_resume() LLAppViewer::instance()->resumeMainloopTimeout(); } -static LLVector3d unpackLocalToGlobalPosition(U32 compact_local, const LLVector3d& region_origin) +LLVector3d unpackLocalToGlobalPosition(U32 compact_local, const LLVector3d& region_origin) { LLVector3d pos_local; @@ -1448,7 +1566,7 @@ static LLVector3d unpackLocalToGlobalPosition(U32 compact_local, const LLVector3 return region_origin + pos_local; } -void LLWorld::getAvatars(std::vector* avatar_ids, std::vector* positions, const LLVector3d& relative_to, F32 radius) const +void LLWorld::getAvatars(uuid_vec_t* avatar_ids, std::vector* positions, const LLVector3d& relative_to, F32 radius) const { F32 radius_squared = radius * radius; @@ -1469,37 +1587,36 @@ void LLWorld::getAvatars(std::vector* avatar_ids, std::vectorisDead() && !pVOAvatar->isSelf() && !pVOAvatar->mIsDummy) { + LLVector3d pos_global = pVOAvatar->getPositionGlobal(); LLUUID uuid = pVOAvatar->getID(); - if(!uuid.isNull()) + + if (!uuid.isNull() + && dist_vec_squared(pos_global, relative_to) <= radius_squared) { - LLVector3d pos_global = pVOAvatar->getPositionGlobal(); - if(dist_vec_squared(pos_global, relative_to) <= radius_squared) + if(positions != NULL) { - if(positions != NULL) - { - positions->push_back(pos_global); - } - if(avatar_ids !=NULL) - { - avatar_ids->push_back(uuid); - } + positions->push_back(pos_global); + } + if(avatar_ids !=NULL) + { + avatar_ids->push_back(uuid); } } } } // region avatars added for situations where radius is greater than RenderFarClip - for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); - iter != LLWorld::getInstance()->getRegionList().end(); ++iter) + for (LLWorld::region_list_t::const_iterator iter = getRegionList().begin(); + iter != getRegionList().end(); ++iter) { LLViewerRegion* regionp = *iter; const LLVector3d& origin_global = regionp->getOriginGlobal(); - S32 count = regionp->mMapAvatars.count(); + S32 count = regionp->mMapAvatars.size(); for (S32 i = 0; i < count; i++) { - LLVector3d pos_global = unpackLocalToGlobalPosition(regionp->mMapAvatars.get(i), origin_global); + LLVector3d pos_global = unpackLocalToGlobalPosition(regionp->mMapAvatars.at(i), origin_global); if(dist_vec_squared(pos_global, relative_to) <= radius_squared) { - LLUUID uuid = regionp->mMapAvatarIDs.get(i); + LLUUID uuid = regionp->mMapAvatarIDs.at(i); // if this avatar doesn't already exist in the list, add it if(uuid.notNull() && avatar_ids != NULL && std::find(avatar_ids->begin(), avatar_ids->end(), uuid) == avatar_ids->end()) { @@ -1514,6 +1631,56 @@ void LLWorld::getAvatars(std::vector* avatar_ids, std::vectorempty()) + { + umap->clear(); + } + // get the list of avatars from the character list first, so distances are correct + // when agent is above 1020m and other avatars are nearby + for (std::vector::iterator iter = LLCharacter::sInstances.begin(); + iter != LLCharacter::sInstances.end(); ++iter) + { + LLVOAvatar* pVOAvatar = (LLVOAvatar*) *iter; + + if (!pVOAvatar->isDead() && !pVOAvatar->isSelf() && !pVOAvatar->mIsDummy) + { + LLVector3d pos_global = pVOAvatar->getPositionGlobal(); + LLUUID uuid = pVOAvatar->getID(); + + if (!uuid.isNull() + && dist_vec_squared(pos_global, relative_to) <= radius_squared) + { + umap->emplace(uuid, pos_global); + } + } + } + // region avatars added for situations where radius is greater than RenderFarClip + for (LLWorld::region_list_t::const_iterator iter = getRegionList().begin(); + iter != getRegionList().end(); ++iter) + { + LLViewerRegion* regionp = *iter; + const LLVector3d& origin_global = regionp->getOriginGlobal(); + S32 count = regionp->mMapAvatars.size(); + for (S32 i = 0; i < count; i++) + { + LLVector3d pos_global = unpackLocalToGlobalPosition(regionp->mMapAvatars.at(i), origin_global); + if(dist_vec_squared(pos_global, relative_to) <= radius_squared) + { + LLUUID uuid = regionp->mMapAvatarIDs.at(i); + // if this avatar doesn't already exist in the list, add it + if(uuid.notNull()) + { + umap->emplace(uuid, pos_global); + } + } + } + } +} + bool LLWorld::isRegionListed(const LLViewerRegion* region) const { region_list_t::const_iterator it = find(mRegionList.begin(), mRegionList.end(), region); diff --git a/indra/newview/llworld.h b/indra/newview/llworld.h index 8cdaeae4e6..1620a92415 100644 --- a/indra/newview/llworld.h +++ b/indra/newview/llworld.h @@ -114,6 +114,9 @@ class LLWorld : public LLSingleton LLSurfacePatch * resolveLandPatchGlobal(const LLVector3d &position); LLVector3 resolveLandNormalGlobal(const LLVector3d &position); // absolute frame + // update region size + void setRegionSize(const U32& width = 0, const U32& length = 0); + U32 getRegionWidthInPoints() const { return mWidth; } F32 getRegionScale() const { return mScale; } @@ -154,6 +157,7 @@ class LLWorld : public LLSingleton void getInfo(LLSD& info); + void clearAllVisibleObjects(); public: typedef std::list region_list_t; const region_list_t& getRegionList() const { return mActiveRegionList; } @@ -164,10 +168,15 @@ class LLWorld : public LLSingleton // All arguments are optional. Given containers will be emptied and then filled. // Not supplying origin or radius input returns data on all avatars in the known regions. void getAvatars( - std::vector* avatar_ids = NULL, + uuid_vec_t* avatar_ids = NULL, std::vector* positions = NULL, const LLVector3d& relative_to = LLVector3d(), F32 radius = FLT_MAX) const; + typedef boost::unordered_map pos_map_t; + void getAvatars(pos_map_t* map, + const LLVector3d& relative_to = LLVector3d(), + F32 radius = FLT_MAX) const; + // Returns 'true' if the region is in mRegionList, // 'false' if the region has been removed due to region change // or if the circuit to this simulator had been lost. @@ -182,12 +191,19 @@ class LLWorld : public LLSingleton region_remove_signal_t mRegionRemovedSignal; // Number of points on edge - static const U32 mWidth; +// Aurora Sim + //static const U32 mWidth; + static U32 mWidth; + static U32 mLength; +// Aurora Sim // meters/point, therefore mWidth * mScale = meters per edge static const F32 mScale; - static const F32 mWidthInMeters; +// Aurora Sim + //static const F32 mWidthInMeters; + static F32 mWidthInMeters; +// Aurora Sim F32 mLandFarClip; // Far clip distance for land. LLPatchVertexArray mLandPatch; diff --git a/indra/newview/llworldmap.cpp b/indra/newview/llworldmap.cpp index b153cfafdf..61a8d976bb 100644 --- a/indra/newview/llworldmap.cpp +++ b/indra/newview/llworldmap.cpp @@ -43,6 +43,7 @@ #include "llmapresponders.h" #include "llviewercontrol.h" #include "llfloaterworldmap.h" +#include "lltexturecache.h" #include "lltracker.h" #include "llviewertexturelist.h" #include "llviewerregion.h" @@ -53,7 +54,7 @@ bool LLWorldMap::sGotMapURL = false; // Timers to temporise database requests -const F32 AGENTS_UPDATE_TIMER = 60.0; // Seconds between 2 agent requests for a region +const F32 AGENTS_UPDATE_TIMER = 30.0; // Seconds between 2 agent requests for a region const F32 REQUEST_ITEMS_TIMER = 10.f * 60.f; // Seconds before we consider re-requesting item data for the grid //--------------------------------------------------------------------------- @@ -84,20 +85,27 @@ LLSimInfo::LLSimInfo(U64 handle) mAccess(0x0), mRegionFlags(0x0), mFirstAgentRequest(true), +// Aurora Sim mSizeX(REGION_WIDTH_UNITS), mSizeY(REGION_WIDTH_UNITS), +// Aurora Sim mAlpha(0.f) { } void LLSimInfo::setLandForSaleImage (LLUUID image_id) { + const bool is_whitecore = gHippoGridManager->getConnectedGrid()->isWhiteCore(); + if (is_whitecore && mMapImageID[SIM_LAYER_OVERLAY].isNull() && image_id.notNull() && gTextureList.findImage(image_id, TEX_LIST_STANDARD)) + LLAppViewer::getTextureCache()->removeFromCache(image_id); + mMapImageID[SIM_LAYER_OVERLAY] = image_id; // Fetch the image if (mMapImageID[SIM_LAYER_OVERLAY].notNull()) { - mLayerImage[SIM_LAYER_OVERLAY] = LLViewerTextureManager::getFetchedTexture(mMapImageID[SIM_LAYER_OVERLAY], MIPMAP_TRUE, LLGLTexture::BOOST_MAP, LLViewerTexture::LOD_TEXTURE); + mLayerImage[SIM_LAYER_OVERLAY] = LLViewerTextureManager::getFetchedTexture(mMapImageID[SIM_LAYER_OVERLAY], FTT_DEFAULT, MIPMAP_TRUE, LLGLTexture::BOOST_MAP, LLViewerTexture::LOD_TEXTURE); + if (is_whitecore) mLayerImage[SIM_LAYER_OVERLAY]->forceImmediateUpdate(); mLayerImage[SIM_LAYER_OVERLAY]->setAddressMode(LLTexUnit::TAM_CLAMP); } else @@ -111,7 +119,7 @@ LLPointer LLSimInfo::getLandForSaleImage () if (mLayerImage[SIM_LAYER_OVERLAY].isNull() && mMapImageID[SIM_LAYER_OVERLAY].notNull()) { // Fetch the image if it hasn't been done yet (unlikely but...) - mLayerImage[SIM_LAYER_OVERLAY] = LLViewerTextureManager::getFetchedTexture(mMapImageID[SIM_LAYER_OVERLAY], MIPMAP_TRUE, LLGLTexture::BOOST_MAP, LLViewerTexture::LOD_TEXTURE); + mLayerImage[SIM_LAYER_OVERLAY] = LLViewerTextureManager::getFetchedTexture(mMapImageID[SIM_LAYER_OVERLAY], FTT_DEFAULT, MIPMAP_TRUE, LLGLTexture::BOOST_MAP, LLViewerTexture::LOD_TEXTURE); mLayerImage[SIM_LAYER_OVERLAY]->setAddressMode(LLTexUnit::TAM_CLAMP); } if (!mLayerImage[SIM_LAYER_OVERLAY].isNull()) @@ -376,11 +384,28 @@ LLSimInfo* LLWorldMap::simInfoFromPosGlobal(const LLVector3d& pos_global) LLSimInfo* LLWorldMap::simInfoFromHandle(const U64 handle) { - sim_info_map_t::iterator it = mSimInfoMap.find(handle); + sim_info_map_t::const_iterator it = mSimInfoMap.find(handle); if (it != mSimInfoMap.end()) { return it->second; } + +// Aurora Sim + U32 x = 0, y = 0; + from_region_handle(handle, &x, &y); + for (it = mSimInfoMap.begin(); it != mSimInfoMap.end(); ++it) + { + U32 checkRegionX, checkRegionY; + from_region_handle((*it).first, &checkRegionX, &checkRegionY); + + LLSimInfo* info = (*it).second; + if (x >= checkRegionX && x < (checkRegionX + info->getSizeX()) && + y >= checkRegionY && y < (checkRegionY + info->getSizeY())) + { + return info; + } + } +// Aurora Sim return NULL; } @@ -437,12 +462,12 @@ void LLWorldMap::sendMapLayerRequest() { LLSD body; body["Flags"] = (LLSD::Integer)flags; - //llinfos << "LLWorldMap::sendMapLayerRequest via capability" << llendl; + //LL_INFOS() << "LLWorldMap::sendMapLayerRequest via capability" << LL_ENDL; LLHTTPClient::post(url, body, new LLMapLayerResponder); } else { - //llinfos << "LLWorldMap::sendMapLayerRequest via message system" << llendl; + //LL_INFOS() << "LLWorldMap::sendMapLayerRequest via message system" << LL_ENDL; LLMessageSystem* msg = gMessageSystem; // Request for layer @@ -462,7 +487,7 @@ void LLWorldMap::sendMapLayerRequest() // public static void LLWorldMap::processMapLayerReply(LLMessageSystem* msg, void**) { - //llinfos << "LLWorldMap::processMapLayerReply from message system" << llendl; + //LL_INFOS() << "LLWorldMap::processMapLayerReply from message system" << LL_ENDL; U32 agent_flags; msg->getU32Fast(_PREHASH_AgentData, _PREHASH_Flags, agent_flags); @@ -470,7 +495,7 @@ void LLWorldMap::processMapLayerReply(LLMessageSystem* msg, void**) U32 layer = flagsToLayer(agent_flags); if (layer != SIM_LAYER_COMPOSITE) { - llwarns << "Invalid or out of date map image type returned!" << llendl; + LL_WARNS() << "Invalid or out of date map image type returned!" << LL_ENDL; return; } @@ -492,7 +517,7 @@ void LLWorldMap::processMapLayerReply(LLMessageSystem* msg, void**) msg->getU32Fast(_PREHASH_LayerData, _PREHASH_Top, top, block); msg->getU32Fast(_PREHASH_LayerData, _PREHASH_Bottom, bottom, block); - new_layer.LayerImage = LLViewerTextureManager::getFetchedTexture(new_layer.LayerImageID, MIPMAP_TRUE, LLGLTexture::BOOST_MAP, LLViewerTexture::LOD_TEXTURE); + new_layer.LayerImage = LLViewerTextureManager::getFetchedTexture(new_layer.LayerImageID, FTT_MAP_TILE, MIPMAP_TRUE, LLGLTexture::BOOST_MAP, LLViewerTexture::LOD_TEXTURE); gGL.getTexUnit(0)->bind(new_layer.LayerImage.get()); new_layer.LayerImage->setAddressMode(LLTexUnit::TAM_CLAMP); @@ -538,7 +563,10 @@ void LLWorldMap::reloadItems(bool force) // static public // Insert a region in the region map // returns true if region inserted, false otherwise -bool LLWorldMap::insertRegion(U32 x_world, U32 y_world, U32 x_size, U32 y_size, U32 agent_flags, std::string& name, LLUUID& image_id, U32 accesscode, U32 region_flags) +// Aurora Sim +//bool LLWorldMap::insertRegion(U32 x_world, U32 y_world, std::string& name, LLUUID& image_id, U32 accesscode, U64 region_flags) +bool LLWorldMap::insertRegion(U32 x_world, U32 y_world, U16 x_size, U16 y_size, std::string& name, LLUUID& image_id, U32 accesscode, U64 region_flags) +// Aurora Sim { // This region doesn't exist if (accesscode == 255) @@ -562,17 +590,14 @@ bool LLWorldMap::insertRegion(U32 x_world, U32 y_world, U32 x_size, U32 y_size, { siminfo = LLWorldMap::getInstance()->createSimInfoFromHandle(handle); } - - siminfo->setName( name ); - siminfo->setAccess( accesscode ); - siminfo->setRegionFlags( region_flags ); - //siminfo->setWaterHeight((F32) water_height); - U32 layer = flagsToLayer(agent_flags); - if (layer == SIM_LAYER_OVERLAY) - siminfo->setLandForSaleImage(image_id); - else if(layer < SIM_LAYER_COUNT) - siminfo->setMapImageID( image_id, layer ); - siminfo->setSize( x_size, y_size ); + siminfo->setName(name); + siminfo->setAccess(accesscode); + siminfo->setRegionFlags(region_flags); + // siminfo->setWaterHeight((F32) water_height); + siminfo->setLandForSaleImage(image_id); +// Aurora Sim + siminfo->setSize(x_size, y_size); +// Aurora Sim // Handle the location tracking (for teleport, UI feedback and info display) if (LLWorldMap::getInstance()->isTrackingInRectangle( x_world, y_world, x_world + REGION_WIDTH_UNITS, y_world + REGION_WIDTH_UNITS)) @@ -677,9 +702,12 @@ bool LLWorldMap::insertItem(U32 x_world, U32 y_world, std::string& name, LLUUID& case MAP_ITEM_LAND_FOR_SALE: // land for sale case MAP_ITEM_LAND_FOR_SALE_ADULT: // adult land for sale { - new_item.setTooltip(llformat("%d sq. m. %s%d", extra, + new_item.setTooltip(llformat("%d sq. m. %s%d (%.1f %s/sq. m.)", extra, gHippoGridManager->getConnectedGrid()->getCurrencySymbol().c_str(), - extra2)); + extra2, + (extra > 0) ? ((F32)extra2 / extra) : 0.f, + gHippoGridManager->getConnectedGrid()->getCurrencySymbol().c_str())); + if (type == MAP_ITEM_LAND_FOR_SALE) { siminfo->insertLandForSale(new_item); @@ -687,11 +715,11 @@ bool LLWorldMap::insertItem(U32 x_world, U32 y_world, std::string& name, LLUUID& else if (type == MAP_ITEM_LAND_FOR_SALE_ADULT) { siminfo->insertLandForSaleAdult(new_item); - } - break; } - case MAP_ITEM_CLASSIFIED: // classifieds - { + break; + } + case MAP_ITEM_CLASSIFIED: // classifieds + { //DEPRECATED: no longer used break; } diff --git a/indra/newview/llworldmap.h b/indra/newview/llworldmap.h index fd654316db..17e312b1f5 100644 --- a/indra/newview/llworldmap.h +++ b/indra/newview/llworldmap.h @@ -142,9 +142,11 @@ class LLSimInfo // Setters void setName(std::string& name) { mName = name; } +// Aurora Sim + void setSize(U16 sizeX, U16 sizeY) { mSizeX = sizeX; mSizeY = sizeY; } +// Aurora Sim void setAccess (U32 accesscode) { mAccess = accesscode; } void setRegionFlags (U32 region_flags) { mRegionFlags = region_flags; } - void setSize(U16 sizeX, U16 sizeY) { mSizeX = sizeX; mSizeY = sizeY; } void setAlpha(F32 alpha) { mAlpha = alpha; } void setLandForSaleImage (LLUUID image_id); @@ -155,13 +157,18 @@ class LLSimInfo const std::string getFlagsString() const { return LLViewerRegion::regionFlagsToString(mRegionFlags); } const U64 getRegionFlags() const { return mRegionFlags; } const std::string getAccessString() const { return LLViewerRegion::accessToString((U8)mAccess); } + const std::string getShortAccessString() const { return LLViewerRegion::accessToShortString(static_cast(mAccess)); } // + const std::string getAccessIcon() const { return LLViewerRegion::getAccessIcon(static_cast(mAccess)); } const U8 getAccess() const { return mAccess; } const S32 getAgentCount() const; // Compute the total agents count LLPointer getLandForSaleImage(); // Get the overlay image, fetch it if necessary const F32 getAlpha() const { return mAlpha; } +// Aurora Sim + const U64& getHandle() const { return mHandle; } const U16 getSizeX() const { return mSizeX; } const U16 getSizeY() const { return mSizeY; } +// Aurora Sim bool isName(const std::string& name) const; bool isDown() { return (mAccess == SIM_ACCESS_DOWN); } bool isPG() { return (mAccess <= SIM_ACCESS_PG); } @@ -193,7 +200,12 @@ class LLSimInfo const LLSimInfo::item_info_list_t& getAgentLocation() const { return mAgentLocations; } private: - U64 mHandle; + U64 mHandle; // This is a hash of the X and Y world coordinates of the SW corner of the sim +// Aurora Sim + U16 mSizeX; + U16 mSizeY; +// Aurora Sim + std::string mName; F64 mAgentsUpdateTime; // Time stamp giving the last time the agents information was requested for that region @@ -201,8 +213,6 @@ class LLSimInfo U32 mAccess; // Down/up and maturity rating of the region U32 mRegionFlags; - U16 mSizeX; - U16 mSizeY; F32 mAlpha; @@ -235,8 +245,12 @@ struct LLWorldMapLayer // We request region data on the world by "blocks" of (MAP_BLOCK_SIZE x MAP_BLOCK_SIZE) regions // This is to reduce the number of requests to the asset DB and get things in big "blocks" -const S32 MAP_MAX_SIZE = 2048; -const S32 MAP_BLOCK_SIZE = 4; +// Aurora Sim +//const S32 MAP_MAX_SIZE = 2048; +//const S32 MAP_BLOCK_SIZE = 4; +const S32 MAP_MAX_SIZE = 16384; +const S32 MAP_BLOCK_SIZE = 16; +// Aurora Sim const S32 MAP_BLOCK_RES = (MAP_MAX_SIZE / MAP_BLOCK_SIZE); class LLWorldMap : public LLSingleton @@ -262,7 +276,10 @@ class LLWorldMap : public LLSingleton // Insert a region and items in the map global instance // Note: x_world and y_world in world coordinates (meters) - static bool insertRegion(U32 x_world, U32 y_world, U32 x_size, U32 y_size, U32 agent_flags, std::string& name, LLUUID& image_id, U32 accesscode, U32 region_flags); +// Aurora Sim + static bool insertRegion(U32 x_world, U32 y_world, std::string& name, LLUUID& uuid, U32 accesscode, U64 region_flags); + static bool insertRegion(U32 x_world, U32 y_world, U16 x_size, U16 y_size, std::string& name, LLUUID& uuid, U32 accesscode, U64 region_flags); +// Aurora Sim static bool insertItem(U32 x_world, U32 y_world, std::string& name, LLUUID& uuid, U32 type, S32 extra, S32 extra2); // Get info on sims (region) : note that those methods only search the range of loaded sims (the one that are being browsed) diff --git a/indra/newview/llworldmapmessage.cpp b/indra/newview/llworldmapmessage.cpp index 5729bcb11c..66cd1209ee 100644 --- a/indra/newview/llworldmapmessage.cpp +++ b/indra/newview/llworldmapmessage.cpp @@ -74,10 +74,10 @@ void LLWorldMapMessage::sendItemRequest(U32 type, U64 handle) void LLWorldMapMessage::sendNamedRegionRequest(std::string region_name) { - //LL_INFOS("World Map") << "LLWorldMap::sendNamedRegionRequest()" << LL_ENDL; + //LL_INFOS("WorldMap") << LL_ENDL; LLMessageSystem* msg = gMessageSystem; - // Request for layer + // Request for region data msg->newMessageFast(_PREHASH_MapNameRequest); msg->nextBlockFast(_PREHASH_AgentData); msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); @@ -95,7 +95,7 @@ void LLWorldMapMessage::sendNamedRegionRequest(std::string region_name, const std::string& callback_url, bool teleport) // immediately teleport when result returned { - //LL_INFOS("World Map") << "LLWorldMap::sendNamedRegionRequest()" << LL_ENDL; + //LL_INFOS("WorldMap") << LL_ENDL; mSLURLRegionName = region_name; mSLURLRegionHandle = 0; mSLURL = callback_url; @@ -110,7 +110,7 @@ void LLWorldMapMessage::sendHandleRegionRequest(U64 region_handle, const std::string& callback_url, bool teleport) // immediately teleport when result returned { - //LL_INFOS("World Map") << "LLWorldMap::sendHandleRegionRequest()" << LL_ENDL; + //LL_INFOS("WorldMap") << LL_ENDL; mSLURLRegionName.clear(); mSLURLRegionHandle = region_handle; mSLURL = callback_url; @@ -123,13 +123,12 @@ void LLWorldMapMessage::sendHandleRegionRequest(U64 region_handle, U16 grid_x = (U16)(global_x / REGION_WIDTH_UNITS); U16 grid_y = (U16)(global_y / REGION_WIDTH_UNITS); - sendMapBlockRequest(grid_x, grid_y, grid_x, grid_y, true, LAYER_FLAG); + sendMapBlockRequest(grid_x, grid_y, grid_x, grid_y, true); } -// public void LLWorldMapMessage::sendMapBlockRequest(U16 min_x, U16 min_y, U16 max_x, U16 max_y, bool return_nonexistent, S32 layer) { - //LL_INFOS("World Map") << "LLWorldMap::sendMapBlockRequest()" << ", min = (" << min_x << ", " << min_y << "), max = (" << max_x << ", " << max_y << "), nonexistent = " << return_nonexistent << LL_ENDL; + //LL_INFOS("WorldMap" << " min = (" << min_x << ", " << min_y << "), max = (" << max_x << ", " << max_y << ", nonexistent = " << return_nonexistent << LL_ENDL; LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_MapBlockRequest); msg->nextBlockFast(_PREHASH_AgentData); @@ -157,12 +156,12 @@ void LLWorldMapMessage::processMapBlockReply(LLMessageSystem* msg, void**) U32 layer = flagsToLayer(agent_flags); if (layer >= SIM_LAYER_COUNT) { - llwarns << "Invalid map image type returned! layer = " << agent_flags << llendl; + LL_WARNS() << "Invalid map image type returned! layer = " << agent_flags << LL_ENDL; return; } S32 num_blocks = msg->getNumberOfBlocksFast(_PREHASH_Data); - //LL_INFOS("World Map") << "LLWorldMap::processMapBlockReply(), num_blocks = " << num_blocks << LL_ENDL; + //LL_INFOS("WorldMap") << "num_blocks = " << num_blocks << LL_ENDL; bool found_null_sim = false; @@ -170,8 +169,10 @@ void LLWorldMapMessage::processMapBlockReply(LLMessageSystem* msg, void**) { U16 x_regions; U16 y_regions; +// Aurora Sim U16 x_size = 256; U16 y_size = 256; +// Aurora Sim std::string name; U8 accesscode; U32 region_flags; @@ -186,6 +187,7 @@ void LLWorldMapMessage::processMapBlockReply(LLMessageSystem* msg, void**) // msg->getU8Fast(_PREHASH_Data, _PREHASH_WaterHeight, water_height, block); // msg->getU8Fast(_PREHASH_Data, _PREHASH_Agents, agents, block); msg->getUUIDFast(_PREHASH_Data, _PREHASH_MapImageID, image_id, block); +// Aurora Sim if(msg->getNumberOfBlocksFast(_PREHASH_Size) > 0) { msg->getU16Fast(_PREHASH_Size, _PREHASH_SizeX, x_size, block); @@ -196,6 +198,7 @@ void LLWorldMapMessage::processMapBlockReply(LLMessageSystem* msg, void**) x_size = 256; y_size = 256; } +// Aurora Sim U32 x_world = (U32)(x_regions) * REGION_WIDTH_UNITS; U32 y_world = (U32)(y_regions) * REGION_WIDTH_UNITS; @@ -209,7 +212,10 @@ void LLWorldMapMessage::processMapBlockReply(LLMessageSystem* msg, void**) continue; // Insert that region in the world map, if failure, flag it as a "null_sim" - if (!(LLWorldMap::getInstance()->insertRegion(x_world, y_world, x_size, y_size, agent_flags, name, image_id, (U32)accesscode, region_flags))) +// Aurora Sim + //if (!(LLWorldMap::getInstance()->insertRegion(x_world, y_world, name, image_id, (U32)accesscode, region_flags))) + if (!(LLWorldMap::getInstance()->insertRegion(x_world, y_world, x_size, y_size, name, image_id, (U32)accesscode, region_flags))) +// Aurora Sim { found_null_sim = true; } @@ -232,7 +238,6 @@ void LLWorldMapMessage::processMapBlockReply(LLMessageSystem* msg, void**) url_callback_t callback = LLWorldMapMessage::getInstance()->mSLURLCallback; if(callback != NULL) { - // Check if we reached the requested region if ((LLStringUtil::compareInsensitive(LLWorldMapMessage::getInstance()->mSLURLRegionName, name)==0) || (LLWorldMapMessage::getInstance()->mSLURLRegionHandle == handle)) @@ -257,7 +262,7 @@ void LLWorldMapMessage::processMapBlockReply(LLMessageSystem* msg, void**) // public static void LLWorldMapMessage::processMapItemReply(LLMessageSystem* msg, void**) { - //LL_INFOS("World Map") << "LLWorldMap::processMapItemReply()" << LL_ENDL; + //LL_INFOS("WorldMap") << LL_ENDL; U32 type; msg->getU32Fast(_PREHASH_RequestData, _PREHASH_ItemType, type); diff --git a/indra/newview/llworldmapview.cpp b/indra/newview/llworldmapview.cpp index b9a7293152..5fd4821dd3 100644 --- a/indra/newview/llworldmapview.cpp +++ b/indra/newview/llworldmapview.cpp @@ -149,10 +149,10 @@ void LLWorldMapView::initClass() sHomeImage = LLUI::getUIImage("map_home.tga"); sTelehubImage = LLUI::getUIImage("map_telehub.tga"); sInfohubImage = LLUI::getUIImage("map_infohub.tga"); - sEventImage = LLUI::getUIImage("map_event.tga"); - sEventMatureImage = LLUI::getUIImage("map_event_mature.tga"); + sEventImage = LLUI::getUIImage("Parcel_PG_Light"); + sEventMatureImage = LLUI::getUIImage("Parcel_M_Light"); // To Do: update the image resource for adult events. - sEventAdultImage = LLUI::getUIImage("map_event_adult.tga"); + sEventAdultImage = LLUI::getUIImage("Parcel_R_Light"); sTrackCircleImage = LLUI::getUIImage("map_track_16.tga"); sTrackArrowImage = LLUI::getUIImage("direction_arrow.tga"); @@ -337,8 +337,8 @@ void LLWorldMapView::draw() mVisibleRegions.clear(); // animate pan if necessary - sPanX = lerp(sPanX, sTargetPanX, LLCriticalDamp::getInterpolant(0.1f)); - sPanY = lerp(sPanY, sTargetPanY, LLCriticalDamp::getInterpolant(0.1f)); + sPanX = lerp(sPanX, sTargetPanX, LLSmoothInterpolation::getInterpolant(0.1f)); + sPanY = lerp(sPanY, sTargetPanY, LLSmoothInterpolation::getInterpolant(0.1f)); const S32 width = getRect().getWidth(); const S32 height = getRect().getHeight(); @@ -433,11 +433,11 @@ void LLWorldMapView::draw() gGL.color4f(0.2f, 0.0f, 0.0f, 0.4f); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gGL.begin(LLRender::QUADS); + gGL.begin(LLRender::TRIANGLE_STRIP); gGL.vertex2f(left, top); gGL.vertex2f(left, bottom); - gGL.vertex2f(right, bottom); gGL.vertex2f(right, top); + gGL.vertex2f(right, bottom); gGL.end(); gGL.blendFunc(LLRender::BF_SOURCE_ALPHA, LLRender::BF_ONE_MINUS_SOURCE_ALPHA); } @@ -467,23 +467,23 @@ void LLWorldMapView::draw() if (overlayimage) { // Inform the fetch mechanism of the size we need - S32 draw_size = llround(sMapScale); - overlayimage->setKnownDrawSize( llround(draw_size * LLUI::getScaleFactor().mV[VX] * ((F32)info->getSizeX() / REGION_WIDTH_METERS)), - llround(draw_size * LLUI::getScaleFactor().mV[VY] * ((F32)info->getSizeY() / REGION_WIDTH_METERS))); + S32 draw_size = ll_round(sMapScale); + overlayimage->setKnownDrawSize( ll_round(draw_size * LLUI::getScaleFactor().mV[VX] * ((F32)info->getSizeX() / REGION_WIDTH_METERS)), + ll_round(draw_size * LLUI::getScaleFactor().mV[VY] * ((F32)info->getSizeY() / REGION_WIDTH_METERS))); // Draw something whenever we have enough info if (overlayimage->hasGLTexture() && !overlayimage->isMissingAsset() && overlayimage->getID() != IMG_DEFAULT) { gGL.getTexUnit(0)->bind(overlayimage); gGL.color4f(1.f, 1.f, 1.f, alpha); - gGL.begin(LLRender::QUADS); + gGL.begin(LLRender::TRIANGLE_STRIP); gGL.texCoord2f(0.f, 1.f); gGL.vertex3f(left, top, -0.5f); gGL.texCoord2f(0.f, 0.f); gGL.vertex3f(left, bottom, -0.5f); - gGL.texCoord2f(1.f, 0.f); - gGL.vertex3f(right, bottom, -0.5f); gGL.texCoord2f(1.f, 1.f); gGL.vertex3f(right, top, -0.5f); + gGL.texCoord2f(1.f, 0.f); + gGL.vertex3f(right, bottom, -0.5f); gGL.end(); } } @@ -525,6 +525,13 @@ void LLWorldMapView::draw() llfloor(left + 3), llfloor(bottom + 2), LLColor4::white, LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::DROP_SHADOW); + static const LLCachedControl show_region_positions("SFMapShowRegionPositions"); + if (show_region_positions) + font->renderUTF8( + llformat("(%d, %d)", llfloor(info->getGlobalOrigin().mdV[VX]/256), llfloor(info->getGlobalOrigin().mdV[VY])/256), 0, + llfloor(left + 3), llfloor(bottom + 14), + LLColor4::white, + LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::DROP_SHADOW); } } } @@ -575,11 +582,11 @@ void LLWorldMapView::draw() gGL.color4f(0.5f, 0.0f, 0.0f, 0.4f); else gGL.color4f(0.2f, .2f, 0.2f, 0.4f); - gGL.begin(LLRender::QUADS); + gGL.begin(LLRender::TRIANGLE_STRIP); gGL.vertex2f(base_left+padding, base_top-padding); gGL.vertex2f(base_left+padding, base_bottom+padding); + gGL.vertex2f(base_right - padding, base_top - padding); gGL.vertex2f(base_right-padding, base_bottom+padding); - gGL.vertex2f(base_right-padding, base_top-padding); gGL.end(); if(it != LLWorldMap::getInstance()->getMapBlockEnd(SIM_LAYER_OVERLAY)) { @@ -603,11 +610,11 @@ void LLWorldMapView::draw() gGL.color4f(0.0f, 0.5f, 0.0f, 0.4f); else gGL.color4f(0.4f, 0.0f, 0.0f, 0.4f); - gGL.begin(LLRender::QUADS); + gGL.begin(LLRender::TRIANGLE_STRIP); gGL.vertex2f(block_left+padding, block_top-padding); gGL.vertex2f(block_left+padding, block_bottom+padding); + gGL.vertex2f(block_right - padding, block_top - padding); gGL.vertex2f(block_right-padding, block_bottom+padding); - gGL.vertex2f(block_right-padding, block_top-padding); gGL.end(); for(U32 sim_x=0;sim_xgetLineHeight())); // offset vertically by one line, to avoid overlap with target tracking + ll_round(LLFontGL::getFontSansSerifSmall()->getLineHeight())); // offset vertically by one line, to avoid overlap with target tracking } // Show your viewing angle @@ -734,7 +741,7 @@ void LLWorldMapView::draw() } // turn off the scissor - LLGLDisable no_scissor(GL_SCISSOR_TEST); + LLGLDisable no_scissor; updateDirections(); @@ -816,8 +823,8 @@ void LLWorldMapView::drawLegacyBackgroundLayers(S32 width, S32 height) { } current_image->setBoostLevel(LLGLTexture::BOOST_MAP); - current_image->setKnownDrawSize(llround(pix_width * LLUI::getScaleFactor().mV[VX]), - llround(pix_height * LLUI::getScaleFactor().mV[VY])); + current_image->setKnownDrawSize(ll_round(pix_width * LLUI::getScaleFactor().mV[VX]), + ll_round(pix_height * LLUI::getScaleFactor().mV[VY])); if (!current_image->hasGLTexture()) //Still loading. { @@ -833,29 +840,29 @@ void LLWorldMapView::drawLegacyBackgroundLayers(S32 width, S32 height) { // Draw map image into RGB gGL.setColorMask(true, false); gGL.color4f(1.f, 1.f, 1.f, 1.f); - gGL.begin(LLRender::QUADS); + gGL.begin(LLRender::TRIANGLE_STRIP); gGL.texCoord2f(0.0f, 1.0f); gGL.vertex3f(left, top, -1.0f); gGL.texCoord2f(0.0f, 0.0f); gGL.vertex3f(left, bottom, -1.0f); - gGL.texCoord2f(1.0f, 0.0f); - gGL.vertex3f(right, bottom, -1.0f); gGL.texCoord2f(1.0f, 1.0f); gGL.vertex3f(right, top, -1.0f); + gGL.texCoord2f(1.0f, 0.0f); + gGL.vertex3f(right, bottom, -1.0f); gGL.end(); // draw an alpha of 1 where the sims are visible gGL.setColorMask(false, true); gGL.color4f(1.f, 1.f, 1.f, 1.f); - gGL.begin(LLRender::QUADS); + gGL.begin(LLRender::TRIANGLE_STRIP); gGL.texCoord2f(0.0f, 1.0f); gGL.vertex2f(left, top); gGL.texCoord2f(0.0f, 0.0f); gGL.vertex2f(left, bottom); - gGL.texCoord2f(1.0f, 0.0f); - gGL.vertex2f(right, bottom); gGL.texCoord2f(1.0f, 1.0f); gGL.vertex2f(right, top); + gGL.texCoord2f(1.0f, 0.0f); + gGL.vertex2f(right, bottom); gGL.end(); gGL.setColorMask(true, true); @@ -883,7 +890,7 @@ F32 LLWorldMapView::drawLegacySimTile(LLSimInfo& sim_info, S32 left, S32 top, S3 (textures_requested_this_tick < MAX_REQUEST_PER_TICK))) { textures_requested_this_tick++; - simimage = sim_info.mLayerImage[SIM_LAYER_COMPOSITE] = LLViewerTextureManager::getFetchedTexture(sim_info.mMapImageID[SIM_LAYER_COMPOSITE], MIPMAP_TRUE, LLGLTexture::BOOST_MAP, LLViewerTexture::LOD_TEXTURE); + simimage = sim_info.mLayerImage[SIM_LAYER_COMPOSITE] = LLViewerTextureManager::getFetchedTexture(sim_info.mMapImageID[SIM_LAYER_COMPOSITE], FTT_MAP_TILE, MIPMAP_TRUE, LLGLTexture::BOOST_MAP, LLViewerTexture::LOD_TEXTURE); simimage->setAddressMode(LLTexUnit::TAM_CLAMP); } } @@ -898,29 +905,29 @@ F32 LLWorldMapView::drawLegacySimTile(LLSimInfo& sim_info, S32 left, S32 top, S3 if (!sim_drawable || sim_fetching) sim_info.setAlpha( 0.f ); else if (llabs(sim_info.getAlpha() - fade_target) > ALPHA_CUTOFF) //This gives us a nice fade when a visible sims texture finishes loading, or visiblity has changed. - sim_info.setAlpha(lerp(sim_info.getAlpha(), fade_target, LLCriticalDamp::getInterpolant(0.15f))); + sim_info.setAlpha(lerp(sim_info.getAlpha(), fade_target, LLSmoothInterpolation::getInterpolant(0.15f))); F32 alpha = sim_info.getAlpha(); //call setKnownDrawSize if image is still loading, or its actually being drawn. if(sim_fetching || alpha >= ALPHA_CUTOFF) { - S32 draw_size = llround(sMapScale); - simimage->setKnownDrawSize( llround(draw_size * LLUI::getScaleFactor().mV[VX] * ((F32)sim_info.getSizeX() / REGION_WIDTH_METERS)), - llround(draw_size * LLUI::getScaleFactor().mV[VY] * ((F32)sim_info.getSizeY() / REGION_WIDTH_METERS))); + S32 draw_size = ll_round(sMapScale); + simimage->setKnownDrawSize( ll_round(draw_size * LLUI::getScaleFactor().mV[VX] * ((F32)sim_info.getSizeX() / REGION_WIDTH_METERS)), + ll_round(draw_size * LLUI::getScaleFactor().mV[VY] * ((F32)sim_info.getSizeY() / REGION_WIDTH_METERS))); simimage->setBoostLevel(LLGLTexture::BOOST_MAP); if(alpha >= ALPHA_CUTOFF) { gGL.getTexUnit(0)->bind(simimage); gGL.color4f(1.f, 1.f, 1.f, alpha); - gGL.begin(LLRender::QUADS); + gGL.begin(LLRender::TRIANGLE_STRIP); gGL.texCoord2f(0.f, 1.f); gGL.vertex2f(left, top); gGL.texCoord2f(0.f, 0.f); gGL.vertex2f(left, bottom); - gGL.texCoord2f(1.f, 0.f); - gGL.vertex2f(right, bottom); gGL.texCoord2f(1.f, 1.f); gGL.vertex2f(right, top); + gGL.texCoord2f(1.f, 0.f); + gGL.vertex2f(right, bottom); gGL.end(); } } @@ -1038,15 +1045,15 @@ bool LLWorldMapView::drawMipmapLevel(S32 width, S32 height, S32 level, bool load gGL.getTexUnit(0)->bind(simimage.get()); simimage->setAddressMode(LLTexUnit::TAM_CLAMP); gGL.color4f(1.f, 1.0f, 1.0f, 1.0f); - gGL.begin(LLRender::QUADS); + gGL.begin(LLRender::TRIANGLE_STRIP); gGL.texCoord2f(0.f, 1.f); gGL.vertex3f(left, top, 0.f); gGL.texCoord2f(0.f, 0.f); gGL.vertex3f(left, bottom, 0.f); - gGL.texCoord2f(1.f, 0.f); - gGL.vertex3f(right, bottom, 0.f); gGL.texCoord2f(1.f, 1.f); gGL.vertex3f(right, top, 0.f); + gGL.texCoord2f(1.f, 0.f); + gGL.vertex3f(right, bottom, 0.f); gGL.end(); #if DEBUG_DRAW_TILE drawTileOutline(level, top, left, bottom, right); @@ -1121,8 +1128,8 @@ void LLWorldMapView::drawGenericItem(const LLItemInfo& item, LLUIImagePtr image) void LLWorldMapView::drawImage(const LLVector3d& global_pos, LLUIImagePtr image, const LLColor4& color) { LLVector3 pos_map = globalPosToView( global_pos ); - image->draw(llround(pos_map.mV[VX] - image->getWidth() /2.f), - llround(pos_map.mV[VY] - image->getHeight()/2.f), + image->draw(ll_round(pos_map.mV[VX] - image->getWidth() /2.f), + ll_round(pos_map.mV[VY] - image->getHeight()/2.f), color); } @@ -1131,8 +1138,8 @@ void LLWorldMapView::drawImageStack(const LLVector3d& global_pos, LLUIImagePtr i LLVector3 pos_map = globalPosToView( global_pos ); for(U32 i=0; idraw(llround(pos_map.mV[VX] - image->getWidth() /2.f), - llround(pos_map.mV[VY] - image->getHeight()/2.f + i*offset), + image->draw(ll_round(pos_map.mV[VX] - image->getWidth() /2.f), + ll_round(pos_map.mV[VY] - image->getHeight()/2.f + i*offset), color); } } @@ -1204,7 +1211,7 @@ void LLWorldMapView::drawAgents() { F32 agents_scale = (sMapScale * 0.9f) / 256.f; - LLColor4 avatar_color = gColors.getColor( "MapAvatar" ); + LLColor4 avatar_color = gSavedSettings.getColor( "MapAvatar" ); // LLColor4 friend_color = gColors.getColor( "MapFriend" ); for (handle_list_t::iterator iter = mVisibleRegions.begin(); iter != mVisibleRegions.end(); ++iter) @@ -1243,9 +1250,9 @@ void LLWorldMapView::drawFrustum() F32 half_width_pixels = half_width_meters * meters_to_pixels; // Compute the frustum coordinates. Take the UI scale into account. - static LLCachedControl ui_scale_factor("UIScaleFactor"); - F32 ctr_x = (getLocalRect().getWidth() * 0.5f + sPanX) * ui_scale_factor; - F32 ctr_y = (getLocalRect().getHeight() * 0.5f + sPanY) * ui_scale_factor; + LLVector2 ui_scale_factor = gViewerWindow->getUIScale(); + F32 ctr_x = (getLocalRect().getWidth() * 0.5f + sPanX) * ui_scale_factor.mV[VX]; + F32 ctr_y = (getLocalRect().getHeight() * 0.5f + sPanY) * ui_scale_factor.mV[VY]; gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); @@ -1316,8 +1323,8 @@ void LLWorldMapView::drawTracking(const LLVector3d& pos_global, const LLColor4& const std::string& label, const std::string& tooltip, S32 vert_offset ) { LLVector3 pos_local = globalPosToView( pos_global ); - S32 x = llround( pos_local.mV[VX] ); - S32 y = llround( pos_local.mV[VY] ); + S32 x = ll_round( pos_local.mV[VX] ); + S32 y = ll_round( pos_local.mV[VY] ); LLFontGL* font = LLFontGL::getFontSansSerifSmall(); S32 text_x = x; S32 text_y = (S32)(y - sTrackCircleImage->getHeight()/2 - font->getLineHeight()); @@ -1349,7 +1356,7 @@ void LLWorldMapView::drawTracking(const LLVector3d& pos_global, const LLColor4& const S32 TEXT_PADDING = DEFAULT_TRACKING_ARROW_SIZE + 2; S32 half_text_width = llfloor(font->getWidthF32(label) * 0.5f); text_x = llclamp(text_x, half_text_width + TEXT_PADDING, getRect().getWidth() - half_text_width - TEXT_PADDING); - text_y = llclamp(text_y + vert_offset, TEXT_PADDING + vert_offset, getRect().getHeight() - llround(font->getLineHeight()) - TEXT_PADDING - vert_offset); + text_y = llclamp(text_y + vert_offset, TEXT_PADDING + vert_offset, getRect().getHeight() - ll_round(font->getLineHeight()) - TEXT_PADDING - vert_offset); //if (label != "") // [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.4.5) | Added: RLVa-1.0.0 @@ -1477,8 +1484,8 @@ static void drawDot(F32 x_pixels, F32 y_pixels, if(-HEIGHT_THRESHOLD <= relative_z && relative_z <= HEIGHT_THRESHOLD) { - dot_image->draw(llround(x_pixels) - dot_image->getWidth()/2, - llround(y_pixels) - dot_image->getHeight()/2, + dot_image->draw(ll_round(x_pixels) - dot_image->getWidth()/2, + ll_round(y_pixels) - dot_image->getHeight()/2, color); } else @@ -1533,9 +1540,9 @@ void LLWorldMapView::drawAvatar(F32 x_pixels, dot_image = sAvatarAboveImage; } - S32 dot_width = llround(dot_radius * 2.f); - dot_image->draw(llround(x_pixels - dot_radius), - llround(y_pixels - dot_radius), + S32 dot_width = ll_round(dot_radius * 2.f); + dot_image->draw(ll_round(x_pixels - dot_radius), + ll_round(y_pixels - dot_radius), dot_width, dot_width, color); @@ -1562,8 +1569,8 @@ void LLWorldMapView::drawIconName(F32 x_pixels, const std::string& second_line) { const S32 VERT_PAD = 8; - S32 text_x = llround(x_pixels); - S32 text_y = llround(y_pixels + S32 text_x = ll_round(x_pixels); + S32 text_y = ll_round(y_pixels - BIG_DOT_RADIUS - VERT_PAD); @@ -1577,7 +1584,7 @@ void LLWorldMapView::drawIconName(F32 x_pixels, LLFontGL::NORMAL, LLFontGL::DROP_SHADOW); - text_y -= llround(LLFontGL::getFontSansSerif()->getLineHeight()); + text_y -= ll_round(LLFontGL::getFontSansSerif()->getLineHeight()); // render text LLFontGL::getFontSansSerif()->renderUTF8(second_line, 0, @@ -1681,12 +1688,10 @@ void LLWorldMapView::drawTrackingCircle( const LLRect& rect, S32 x, S32 y, const end_theta -= angle_adjust_y; } - gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.pushMatrix(); - gGL.translatef((F32)x, (F32)y, 0.f); + gGL.pushUIMatrix(); + gGL.translateUI(x, y, 0.f); gl_washer_segment_2d(inner_radius, outer_radius, start_theta, end_theta, 40, color, color); - gGL.popMatrix(); - + gGL.popUIMatrix(); } // static @@ -1751,8 +1756,8 @@ void LLWorldMapView::setDirectionPos( LLTextBox* text_box, F32 rotation ) F32 radius = llmin( map_half_height - text_half_height, map_half_width - text_half_width ); text_box->setOrigin( - llround(map_half_width - text_half_width + radius * cos( rotation )), - llround(map_half_height - text_half_height + radius * sin( rotation )) ); + ll_round(map_half_width - text_half_width + radius * cos( rotation )), + ll_round(map_half_height - text_half_height + radius * sin( rotation )) ); } @@ -1800,8 +1805,8 @@ void LLWorldMapView::reshape( S32 width, S32 height, BOOL called_from_parent ) bool LLWorldMapView::checkItemHit(S32 x, S32 y, LLItemInfo& item, LLUUID* id, bool track) { LLVector3 pos_view = globalPosToView(item.getGlobalPosition()); - S32 item_x = llround(pos_view.mV[VX]); - S32 item_y = llround(pos_view.mV[VY]); + S32 item_x = ll_round(pos_view.mV[VX]); + S32 item_y = ll_round(pos_view.mV[VY]); if (x < item_x - BIG_DOT_RADIUS) return false; if (x > item_x + BIG_DOT_RADIUS) return false; @@ -1976,8 +1981,8 @@ BOOL LLWorldMapView::handleMouseDown( S32 x, S32 y, MASK mask ) { gFocusMgr.setMouseCapture( this ); - mMouseDownPanX = llround(sPanX); - mMouseDownPanY = llround(sPanY); + mMouseDownPanX = ll_round(sPanX); + mMouseDownPanY = ll_round(sPanY); mMouseDownX = x; mMouseDownY = y; sHandledLastClick = TRUE; @@ -2092,7 +2097,7 @@ BOOL LLWorldMapView::handleHover( S32 x, S32 y, MASK mask ) { gViewerWindow->setCursor( UI_CURSOR_CROSS ); } - lldebugst(LLERR_USER_INPUT) << "hover handled by LLWorldMapView" << llendl; + LL_DEBUGS("UserInput") << "hover handled by LLWorldMapView" << LL_ENDL; return TRUE; } } @@ -2137,6 +2142,7 @@ BOOL LLWorldMapView::handleDoubleClick( S32 x, S32 y, MASK mask ) } default: { + if (!gSavedSettings.getBOOL("DoubleClickTeleportMap")) return true; if (LLWorldMap::getInstance()->isTracking()) { LLWorldMap::getInstance()->setTrackingDoubleClick(); diff --git a/indra/newview/llworldmipmap.cpp b/indra/newview/llworldmipmap.cpp index 66ee60d475..6de118940b 100644 --- a/indra/newview/llworldmipmap.cpp +++ b/indra/newview/llworldmipmap.cpp @@ -198,7 +198,7 @@ LLPointer LLWorldMipmap::loadObjectsTile(U32 grid_x, U32 // END DEBUG //LL_INFOS("World Map") << "LLWorldMipmap::loadObjectsTile(), URL = " << imageurl << LL_ENDL; - LLPointer img = LLViewerTextureManager::getFetchedTextureFromUrl(imageurl, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); + LLPointer img = LLViewerTextureManager::getFetchedTextureFromUrl(imageurl, FTT_MAP_TILE, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); img->setBoostLevel(LLGLTexture::BOOST_MAP); // Return the smart pointer diff --git a/indra/newview/llxmlrpcresponder.cpp b/indra/newview/llxmlrpcresponder.cpp index dac69a7f1c..2dc56449ad 100644 --- a/indra/newview/llxmlrpcresponder.cpp +++ b/indra/newview/llxmlrpcresponder.cpp @@ -45,7 +45,6 @@ #include "llappviewer.h" -#include "hippogridmanager.h" #include "aicurleasyrequeststatemachine.h" #ifdef CWDEBUG @@ -163,15 +162,15 @@ void XMLRPCResponder::completed_headers(U32 status, std::string const& reason, A mTransferInfo = *info; } // Call base class implementation. - LegacyPolledResponder::completed_headers(status, reason, info); + ResponderWithCompleted::completed_headers(status, reason, info); } -void XMLRPCResponder::completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) +void XMLRPCResponder::completedRaw(LLChannelDescriptors const& channels, buffer_ptr_t const& buffer) { - if (mCode == CURLE_OK) + if (mCode == CURLE_OK && !is_internal_http_error(mStatus)) { mBufferSize = buffer->count(channels.in()); - if (200 <= status && status < 400) + if (200 <= mStatus && mStatus < 400) { char* ptr = NULL; char* buf = NULL; @@ -213,6 +212,7 @@ LLXMLRPCValue XMLRPCResponder::responseValue(void) const } #ifdef AI_UNUSED +#include "hippogridmanager.h" void LLXMLRPCTransaction::Impl::setStatus(Status status, const std::string& message, const std::string& uri) { diff --git a/indra/newview/llxmlrpcresponder.h b/indra/newview/llxmlrpcresponder.h index 4a5f290771..5ee44794bb 100644 --- a/indra/newview/llxmlrpcresponder.h +++ b/indra/newview/llxmlrpcresponder.h @@ -90,7 +90,7 @@ class LLXMLRPCValue XMLRPC_VALUE mV; }; -class XMLRPCResponder : public LLHTTPClient::LegacyPolledResponder { +class XMLRPCResponder : public LLHTTPClient::ResponderWithCompleted { private: AITransferInfo mTransferInfo; S32 mBufferSize; @@ -110,7 +110,7 @@ class XMLRPCResponder : public LLHTTPClient::LegacyPolledResponder { /*virtual*/ bool forbidReuse(void) const { return true; } /*virtual*/ void received_HTTP_header(void) { mReceivedHTTPHeader = true; LLHTTPClient::ResponderBase::received_HTTP_header(); } /*virtual*/ void completed_headers(U32 status, std::string const& reason, AITransferInfo* info); - /*virtual*/ void completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer); + /*virtual*/ void completedRaw(LLChannelDescriptors const& channels, buffer_ptr_t const& buffer); /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return XMLRPCResponder_timeout; } /*virtual*/ char const* getName(void) const { return "XMLRPCResponder"; } }; diff --git a/indra/newview/m7wlinterface.cpp b/indra/newview/m7wlinterface.cpp index 7906ab81a0..e57bf4c05c 100644 --- a/indra/newview/m7wlinterface.cpp +++ b/indra/newview/m7wlinterface.cpp @@ -51,12 +51,12 @@ void M7WindlightInterface::receiveMessage(LLMessageSystem* msg) for (int i = 0; i<250; ++i){ wldump << "\\x" << hex[((U8)buf[i]&0xF0)>>4] << hex[(U8)buf[i]&0x0F]; } - llinfos << "Received LightShare data: " << wldump.str() << llendl; + LL_INFOS() << "Received LightShare data: " << wldump.str() << LL_ENDL; #endif char default_windlight[] = "\x00\x00\x80\x40\x00\x00\x18\x42\x00\x00\x80\x42\x00\x00\x80\x40\x00\x00\x80\x3e\x00\x00\x00\x40\x00\x00\x00\x40\x00\x00\x00\x40\xcd\xcc\xcc\x3e\x00\x00\x00\x3f\x8f\xc2\xf5\x3c\xcd\xcc\x4c\x3e\x0a\xd7\x23\x3d\x66\x66\x86\x3f\x3d\x0a\xd7\xbe\x7b\x14\x8e\x3f\xe1\x7a\x94\xbf\x82\x2d\xed\x49\x9a\x6c\xf6\x1c\xcb\x89\x6d\xf5\x4f\x42\xcd\xf4\x00\x00\x80\x3e\x00\x00\x80\x3e\x0a\xd7\xa3\x3e\x0a\xd7\xa3\x3e\x5c\x8f\x42\x3e\x8f\xc2\xf5\x3d\xae\x47\x61\x3e\x5c\x8f\xc2\x3e\x5c\x8f\xc2\x3e\x33\x33\x33\x3f\xec\x51\x38\x3e\xcd\xcc\x4c\x3f\x8f\xc2\x75\x3e\xb8\x1e\x85\x3e\x9a\x99\x99\x3e\x9a\x99\x99\x3e\xd3\x4d\xa2\x3e\x33\x33\xb3\x3e\x33\x33\xb3\x3e\x33\x33\xb3\x3e\x33\x33\xb3\x3e\x00\x00\x00\x00\xcd\xcc\xcc\x3d\x00\x00\xe0\x3f\x00\x00\x80\x3f\x00\x00\x00\x00\x85\xeb\xd1\x3e\x85\xeb\xd1\x3e\x85\xeb\xd1\x3e\x85\xeb\xd1\x3e\x00\x00\x80\x3f\x14\xae\x07\x3f\x00\x00\x80\x3f\x71\x3d\x8a\x3e\x3d\x0a\xd7\x3e\x00\x00\x80\x3f\x14\xae\x07\x3f\x8f\xc2\xf5\x3d\xcd\xcc\x4c\x3e\x0a\xd7\x23\x3c\x45\x06\x00"; if(!memcmp(default_windlight, buf, sizeof(default_windlight))) { - llinfos << "LightShare matches default" << llendl; + LL_INFOS() << "LightShare matches default" << LL_ENDL; receiveReset(); return; } @@ -110,17 +110,17 @@ void M7WindlightInterface::receiveMessage(LLMessageSystem* msg) mWindlight.set("ambient", wl->ambient.red * 3.0f, wl->ambient.green * 3.0f, wl->ambient.blue * 3.0f, wl->ambient.alpha * 3.0f); mWindlight.set("blue_horizon", wl->horizon.red * 2.0f, wl->horizon.green *2.0f, wl->horizon.blue * 2.0f, wl->horizon.alpha * 2.0f); mWindlight.set("blue_density", wl->blueDensity.red * 2.0f, wl->blueDensity.green * 2.0f, wl->blueDensity.blue * 2.0f, wl->blueDensity.alpha * 2.0f); - mWindlight.set("haze_horizon", wl->hazeHorizon, wl->hazeHorizon, wl->hazeHorizon, 1.f); - mWindlight.set("haze_density", wl->hazeDensity, wl->hazeDensity, wl->hazeDensity, 1.f); - mWindlight.set("cloud_shadow", wl->cloudCoverage, wl->cloudCoverage, wl->cloudCoverage, wl->cloudCoverage); + mWindlight.set("haze_horizon", wl->hazeHorizon); + mWindlight.set("haze_density", wl->hazeDensity); + mWindlight.set("cloud_shadow", wl->cloudCoverage); mWindlight.set("density_multiplier", wl->densityMultiplier / 1000.0f); - mWindlight.set("distance_multiplier", wl->distanceMultiplier, wl->distanceMultiplier, wl->distanceMultiplier, wl->distanceMultiplier); + mWindlight.set("distance_multiplier", wl->distanceMultiplier); mWindlight.set("max_y",(F32)wl->maxAltitude); mWindlight.set("cloud_color", wl->cloudColor.red, wl->cloudColor.green, wl->cloudColor.blue, wl->cloudColor.alpha); mWindlight.set("cloud_pos_density1", wl->cloudXYDensity.X, wl->cloudXYDensity.Y, wl->cloudXYDensity.Z); mWindlight.set("cloud_pos_density2", wl->cloudDetailXYDensity.X, wl->cloudDetailXYDensity.Y, wl->cloudDetailXYDensity.Z); - mWindlight.set("cloud_scale", wl->cloudScale, 0.f, 0.f, 1.f); - mWindlight.set("gamma", wl->sceneGamma, wl->sceneGamma, wl->sceneGamma, 0.0f); + mWindlight.set("cloud_scale", wl->cloudScale); + mWindlight.set("gamma", wl->sceneGamma); mWindlight.set("glow",(2 - wl->sunGlowSize) * 20 , 0.f, -wl->sunGlowFocus * 5); mWindlight.setCloudScrollX(wl->cloudScrollX + 10.0f); mWindlight.setCloudScrollY(wl->cloudScrollY + 10.0f); @@ -136,7 +136,7 @@ void M7WindlightInterface::receiveMessage(LLMessageSystem* msg) void M7WindlightInterface::receiveReset() { - llinfos << "Received LightShare reset" << llendl; + LL_INFOS() << "Received LightShare reset" << LL_ENDL; mHasOverride = false; LLEnvManagerNew::getInstance()->usePrefs(); } diff --git a/indra/newview/macview_Prefix.h b/indra/newview/macview_Prefix.h index 8cbabb5103..c3f0c6e6ff 100644 --- a/indra/newview/macview_Prefix.h +++ b/indra/newview/macview_Prefix.h @@ -76,7 +76,7 @@ #include "llfloatertools.h" #include "llhudeffectlookat.h" #include "llhudmanager.h" -#include "llinventoryview.h" +#include "llpanelmaininventory.h" #include "lljoystickbutton.h" #include "llmenugl.h" #include "llmorphview.h" diff --git a/indra/newview/noise.cpp b/indra/newview/noise.cpp deleted file mode 100644 index df8922e546..0000000000 --- a/indra/newview/noise.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/** - * @file noise.cpp - * @brief Perlin noise routines for procedural textures, etc - * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "noise.h" - -#include "llrand.h" - -// static -#define B 0x100 -S32 p[B + B + 2]; -F32 g3[B + B + 2][3]; -F32 g2[B + B + 2][2]; -F32 g1[B + B + 2]; -S32 gNoiseStart = 1; - - -F32 noise2(F32 *vec) -{ - U8 bx0, bx1, by0, by1; - U32 b00, b10, b01, b11; - F32 rx0, rx1, ry0, ry1, *q, sx, sy, a, b, u, v; - S32 i, j; - - if (gNoiseStart) { - gNoiseStart = 0; - init(); - } - - - fast_setup(*vec, bx0, bx1, rx0, rx1); - fast_setup(*(vec + 1), by0, by1, ry0, ry1); - - i = *(p + bx0); - j = *(p + bx1); - - b00 = *(p + i + by0); - b10 = *(p + j + by0); - b01 = *(p + i + by1); - b11 = *(p + j + by1); - - sx = s_curve(rx0); - sy = s_curve(ry0); - - - q = *(g2 + b00); - u = fast_at2(rx0, ry0, q); - q = *(g2 + b10); - v = fast_at2(rx1, ry0, q); - a = lerp_m(sx, u, v); - - q = *(g2 + b01); - u = fast_at2(rx0,ry1,q); - q = *(g2 + b11); - v = fast_at2(rx1,ry1,q); - b = lerp_m(sx, u, v); - - return lerp_m(sy, a, b); -} - diff --git a/indra/newview/noise.h b/indra/newview/noise.h deleted file mode 100644 index 0cc558a8ea..0000000000 --- a/indra/newview/noise.h +++ /dev/null @@ -1,363 +0,0 @@ -/** - * @file noise.h - * @brief Perlin noise routines for procedural textures, etc - * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#ifndef LL_NOISE_H -#define LL_NOISE_H - -#include "llmath.h" - -F32 turbulence2(F32 *v, F32 freq); -F32 turbulence3(float *v, float freq); -F32 clouds3(float *v, float freq); -F32 noise2(float *vec); -F32 noise3(float *vec); - -inline F32 bias(F32 a, F32 b) -{ - return (F32)pow(a, (F32)(log(b) / log(0.5f))); -} - -inline F32 gain(F32 a, F32 b) -{ - F32 p = (F32) (log(1.f - b) / log(0.5f)); - - if (a < .001f) - return 0.f; - else if (a > .999f) - return 1.f; - if (a < 0.5f) - return (F32)(pow(2 * a, p) / 2.f); - else - return (F32)(1.f - pow(2 * (1.f - a), p) / 2.f); -} - -inline F32 turbulence2(F32 *v, F32 freq) -{ - F32 t, vec[2]; - - for (t = 0.f ; freq >= 1.f ; freq *= 0.5f) { - vec[0] = freq * v[0]; - vec[1] = freq * v[1]; - t += noise2(vec)/freq; - } - return t; -} - -inline F32 turbulence3(F32 *v, F32 freq) -{ - F32 t, vec[3]; - - for (t = 0.f ; freq >= 1.f ; freq *= 0.5f) { - vec[0] = freq * v[0]; - vec[1] = freq * v[1]; - vec[2] = freq * v[2]; - t += noise3(vec)/freq; -// t += fabs(noise3(vec)) / freq; // Like snow - bubbly at low frequencies -// t += sqrt(fabs(noise3(vec))) / freq; // Better at low freq -// t += (noise3(vec)*noise3(vec)) / freq; - } - return t; -} - -inline F32 clouds3(F32 *v, F32 freq) -{ - F32 t, vec[3]; - - for (t = 0.f ; freq >= 1.f ; freq *= 0.5f) { - vec[0] = freq * v[0]; - vec[1] = freq * v[1]; - vec[2] = freq * v[2]; - //t += noise3(vec)/freq; -// t += fabs(noise3(vec)) / freq; // Like snow - bubbly at low frequencies -// t += sqrt(fabs(noise3(vec))) / freq; // Better at low freq - t += (noise3(vec)*noise3(vec)) / freq; - } - return t; -} - -/* noise functions over 1, 2, and 3 dimensions */ - -#define B 0x100 -#define BM 0xff - -#define N 0x1000 -#define NF32 (4096.f) -#define NP 12 /* 2^N */ -#define NM 0xfff - -extern S32 p[B + B + 2]; -extern F32 g3[B + B + 2][3]; -extern F32 g2[B + B + 2][2]; -extern F32 g1[B + B + 2]; -extern S32 gNoiseStart; - -static void init(void); - -#define s_curve(t) ( t * t * (3.f - 2.f * t) ) - -#define lerp_m(t, a, b) ( a + t * (b - a) ) - -#define setup_noise(i,b0,b1,r0,r1)\ - t = vec[i] + N;\ - b0 = (lltrunc(t)) & BM;\ - b1 = (b0+1) & BM;\ - r0 = t - lltrunc(t);\ - r1 = r0 - 1.f; - - -inline void fast_setup(F32 vec, U8 &b0, U8 &b1, F32 &r0, F32 &r1) -{ - S32 t_S32; - - r1 = vec + NF32; - t_S32 = lltrunc(r1); - b0 = (U8)t_S32; - b1 = b0 + 1; - r0 = r1 - t_S32; - r1 = r0 - 1.f; -} - -inline F32 noise1(const F32 arg) -{ - int bx0, bx1; - F32 rx0, rx1, sx, t, u, v, vec[1]; - - vec[0] = arg; - if (gNoiseStart) { - gNoiseStart = 0; - init(); - } - - setup_noise(0, bx0,bx1, rx0,rx1); - - sx = s_curve(rx0); - - u = rx0 * g1[ p[ bx0 ] ]; - v = rx1 * g1[ p[ bx1 ] ]; - - return lerp_m(sx, u, v); -} - -inline F32 fast_at2(F32 rx, F32 ry, F32 *q) -{ - return rx * (*q) + ry * (*(q + 1)); -} - - - -inline F32 fast_at3(F32 rx, F32 ry, F32 rz, F32 *q) -{ - return rx * (*q) + ry * (*(q + 1)) + rz * (*(q + 2)); -} - - - -inline F32 noise3(F32 *vec) -{ - U8 bx0, bx1, by0, by1, bz0, bz1; - S32 b00, b10, b01, b11; - F32 rx0, rx1, ry0, ry1, rz0, rz1, *q, sy, sz, a, b, c, d, t, u, v; - S32 i, j; - - if (gNoiseStart) { - gNoiseStart = 0; - init(); - } - - fast_setup(*vec, bx0,bx1, rx0,rx1); - fast_setup(*(vec + 1), by0,by1, ry0,ry1); - fast_setup(*(vec + 2), bz0,bz1, rz0,rz1); - - i = p[ bx0 ]; - j = p[ bx1 ]; - - b00 = p[ i + by0 ]; - b10 = p[ j + by0 ]; - b01 = p[ i + by1 ]; - b11 = p[ j + by1 ]; - - t = s_curve(rx0); - sy = s_curve(ry0); - sz = s_curve(rz0); - - q = g3[ b00 + bz0 ]; - u = fast_at3(rx0,ry0,rz0,q); - q = g3[ b10 + bz0 ]; - v = fast_at3(rx1,ry0,rz0,q); - a = lerp_m(t, u, v); - - q = g3[ b01 + bz0 ]; - u = fast_at3(rx0,ry1,rz0,q); - q = g3[ b11 + bz0 ]; - v = fast_at3(rx1,ry1,rz0,q); - b = lerp_m(t, u, v); - - c = lerp_m(sy, a, b); - - q = g3[ b00 + bz1 ]; - u = fast_at3(rx0,ry0,rz1,q); - q = g3[ b10 + bz1 ]; - v = fast_at3(rx1,ry0,rz1,q); - a = lerp_m(t, u, v); - - q = g3[ b01 + bz1 ]; - u = fast_at3(rx0,ry1,rz1,q); - q = g3[ b11 + bz1 ]; - v = fast_at3(rx1,ry1,rz1,q); - b = lerp_m(t, u, v); - - d = lerp_m(sy, a, b); - - return lerp_m(sz, c, d); -} - - -/* -F32 noise3(F32 *vec) -{ - int bx0, bx1, by0, by1, bz0, bz1, b00, b10, b01, b11; - F32 rx0, rx1, ry0, ry1, rz0, rz1, *q, sy, sz, a, b, c, d, t, u, v; - S32 i, j; - - if (gNoiseStart) { - gNoiseStart = 0; - init(); - } - - setup_noise(0, bx0,bx1, rx0,rx1); - setup_noise(1, by0,by1, ry0,ry1); - setup_noise(2, bz0,bz1, rz0,rz1); - - i = p[ bx0 ]; - j = p[ bx1 ]; - - b00 = p[ i + by0 ]; - b10 = p[ j + by0 ]; - b01 = p[ i + by1 ]; - b11 = p[ j + by1 ]; - - t = s_curve(rx0); - sy = s_curve(ry0); - sz = s_curve(rz0); - -#define at3(rx,ry,rz) ( rx * q[0] + ry * q[1] + rz * q[2] ) - - q = g3[ b00 + bz0 ] ; u = at3(rx0,ry0,rz0); - q = g3[ b10 + bz0 ] ; v = at3(rx1,ry0,rz0); - a = lerp_m(t, u, v); - - q = g3[ b01 + bz0 ] ; u = at3(rx0,ry1,rz0); - q = g3[ b11 + bz0 ] ; v = at3(rx1,ry1,rz0); - b = lerp_m(t, u, v); - - c = lerp_m(sy, a, b); - - q = g3[ b00 + bz1 ] ; u = at3(rx0,ry0,rz1); - q = g3[ b10 + bz1 ] ; v = at3(rx1,ry0,rz1); - a = lerp_m(t, u, v); - - q = g3[ b01 + bz1 ] ; u = at3(rx0,ry1,rz1); - q = g3[ b11 + bz1 ] ; v = at3(rx1,ry1,rz1); - b = lerp_m(t, u, v); - - d = lerp_m(sy, a, b); - - return lerp_m(sz, c, d); -} -*/ - -static void normalize2(F32 v[2]) -{ - F32 s; - - s = 1.f/(F32)sqrt(v[0] * v[0] + v[1] * v[1]); - v[0] = v[0] * s; - v[1] = v[1] * s; -} - -static void normalize3(F32 v[3]) -{ - F32 s; - - s = 1.f/(F32)sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); - v[0] = v[0] * s; - v[1] = v[1] * s; - v[2] = v[2] * s; -} - -static void init(void) -{ - // we want repeatable noise (e.g. for stable terrain texturing), so seed with known value - srand(42); - int i, j, k; - - for (i = 0 ; i < B ; i++) { - p[i] = i; - - g1[i] = (F32)((rand() % (B + B)) - B) / B; - - for (j = 0 ; j < 2 ; j++) - g2[i][j] = (F32)((rand() % (B + B)) - B) / B; - normalize2(g2[i]); - - for (j = 0 ; j < 3 ; j++) - g3[i][j] = (F32)((rand() % (B + B)) - B) / B; - normalize3(g3[i]); - } - - while (--i) { - k = p[i]; - p[i] = p[j = rand() % B]; - p[j] = k; - } - - for (i = 0 ; i < B + 2 ; i++) { - p[B + i] = p[i]; - g1[B + i] = g1[i]; - for (j = 0 ; j < 2 ; j++) - g2[B + i][j] = g2[i][j]; - for (j = 0 ; j < 3 ; j++) - g3[B + i][j] = g3[i][j]; - } - - // reintroduce entropy - srand(time(NULL)); // Flawfinder: ignore -} - -#undef B -#undef BM -#undef N -#undef NF32 -#undef NP -#undef NM - -#endif // LL_NOISE_ diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index c57ab42197..db626588ed 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -109,6 +109,8 @@ #include "llwaterparammanager.h" #include "llspatialpartition.h" #include "llmutelist.h" +#include "llfloatertools.h" +#include "llpanelface.h" // [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a) #include "rlvhandler.h" @@ -129,7 +131,7 @@ void check_stack_depth(S32 stack_depth) } else { - llerrs << "GL matrix stack corrupted!" << llendl; + LL_ERRS() << "GL matrix stack corrupted!" << LL_ENDL; } } } @@ -150,11 +152,19 @@ const F32 BACKLIGHT_DAY_MAGNITUDE_OBJECT = 0.1f; const F32 BACKLIGHT_NIGHT_MAGNITUDE_OBJECT = 0.08f; const S32 MAX_ACTIVE_OBJECT_QUIET_FRAMES = 40; const S32 MAX_OFFSCREEN_GEOMETRY_CHANGES_PER_FRAME = 10; -const U32 REFLECTION_MAP_RES = 128; -const U32 DEFERRED_VB_MASK = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TEXCOORD1; +const U32 NOISE_MAP_RES = 256; +const U32 AUX_VB_MASK = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TEXCOORD1; // Max number of occluders to search for. JC const S32 MAX_OCCLUDER_COUNT = 2; +enum { + LIGHT_MODE_NORMAL, + LIGHT_MODE_EDIT, + LIGHT_MODE_BACKLIGHT, + LIGHT_MODE_PREVIEW +}; + + extern S32 gBoxFrame; //extern BOOL gHideSelectedObjects; extern BOOL gDisplaySwapBuffers; @@ -168,57 +178,62 @@ BOOL gAvatarBacklight = FALSE; BOOL gDebugPipeline = FALSE; LLPipeline gPipeline; -const LLMatrix4* gGLLastMatrix = NULL; - -LLFastTimer::DeclareTimer FTM_RENDER_GEOMETRY("Geometry"); -LLFastTimer::DeclareTimer FTM_RENDER_GRASS("Grass"); -LLFastTimer::DeclareTimer FTM_RENDER_INVISIBLE("Invisible"); -LLFastTimer::DeclareTimer FTM_RENDER_OCCLUSION("Occlusion"); -LLFastTimer::DeclareTimer FTM_RENDER_SHINY("Shiny"); -LLFastTimer::DeclareTimer FTM_RENDER_SIMPLE("Simple"); -LLFastTimer::DeclareTimer FTM_RENDER_TERRAIN("Terrain"); -LLFastTimer::DeclareTimer FTM_RENDER_TREES("Trees"); -LLFastTimer::DeclareTimer FTM_RENDER_UI("UI"); -LLFastTimer::DeclareTimer FTM_RENDER_WATER("Water"); -LLFastTimer::DeclareTimer FTM_RENDER_WL_SKY("Windlight Sky"); -LLFastTimer::DeclareTimer FTM_RENDER_ALPHA("Alpha Objects"); -LLFastTimer::DeclareTimer FTM_RENDER_CHARACTERS("Avatars"); -LLFastTimer::DeclareTimer FTM_RENDER_BUMP("Bump"); -LLFastTimer::DeclareTimer FTM_RENDER_FULLBRIGHT("Fullbright"); -LLFastTimer::DeclareTimer FTM_RENDER_GLOW("Glow"); -LLFastTimer::DeclareTimer FTM_GEO_UPDATE("Geo Update"); -LLFastTimer::DeclareTimer FTM_PIPELINE_CREATE("Pipeline Create"); -LLFastTimer::DeclareTimer FTM_POOLRENDER("RenderPool"); -LLFastTimer::DeclareTimer FTM_POOLS("Pools"); -LLFastTimer::DeclareTimer FTM_DEFERRED_POOLRENDER("RenderPool (Deferred)"); -LLFastTimer::DeclareTimer FTM_DEFERRED_POOLS("Pools (Deferred)"); -LLFastTimer::DeclareTimer FTM_POST_DEFERRED_POOLRENDER("RenderPool (Post)"); -LLFastTimer::DeclareTimer FTM_POST_DEFERRED_POOLS("Pools (Post)"); -LLFastTimer::DeclareTimer FTM_RENDER_BLOOM_FBO("First FBO"); -LLFastTimer::DeclareTimer FTM_STATESORT("Sort Draw State"); -LLFastTimer::DeclareTimer FTM_PIPELINE("Pipeline"); -LLFastTimer::DeclareTimer FTM_CLIENT_COPY("Client Copy"); -LLFastTimer::DeclareTimer FTM_RENDER_DEFERRED("Deferred Shading"); - - -static LLFastTimer::DeclareTimer FTM_STATESORT_DRAWABLE("Sort Drawables"); -static LLFastTimer::DeclareTimer FTM_STATESORT_POSTSORT("Post Sort"); +const LLMatrix4a* gGLLastMatrix = NULL; + +LLTrace::BlockTimerStatHandle FTM_RENDER_GEOMETRY("Geometry"); +LLTrace::BlockTimerStatHandle FTM_RENDER_GRASS("Grass"); +LLTrace::BlockTimerStatHandle FTM_RENDER_OCCLUSION("Occlusion"); +LLTrace::BlockTimerStatHandle FTM_RENDER_SHINY("Shiny"); +LLTrace::BlockTimerStatHandle FTM_RENDER_SIMPLE("Simple"); +LLTrace::BlockTimerStatHandle FTM_RENDER_TERRAIN("Terrain"); +LLTrace::BlockTimerStatHandle FTM_RENDER_TREES("Trees"); +LLTrace::BlockTimerStatHandle FTM_RENDER_UI("UI"); +LLTrace::BlockTimerStatHandle FTM_RENDER_WATER("Water"); +LLTrace::BlockTimerStatHandle FTM_RENDER_WL_SKY("Windlight Sky"); +LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA("Alpha Objects"); +LLTrace::BlockTimerStatHandle FTM_RENDER_CHARACTERS("Avatars"); +LLTrace::BlockTimerStatHandle FTM_RENDER_BUMP("Bump"); +LLTrace::BlockTimerStatHandle FTM_RENDER_MATERIALS("Materials"); +LLTrace::BlockTimerStatHandle FTM_RENDER_FULLBRIGHT("Fullbright"); +LLTrace::BlockTimerStatHandle FTM_RENDER_GLOW("Glow"); +LLTrace::BlockTimerStatHandle FTM_GEO_UPDATE("Geo Update"); +LLTrace::BlockTimerStatHandle FTM_PIPELINE_CREATE("Pipeline Create"); +LLTrace::BlockTimerStatHandle FTM_POOLRENDER("RenderPool"); +LLTrace::BlockTimerStatHandle FTM_POOLS("Pools"); +LLTrace::BlockTimerStatHandle FTM_DEFERRED_POOLRENDER("RenderPool (Deferred)"); +LLTrace::BlockTimerStatHandle FTM_DEFERRED_POOLS("Pools (Deferred)"); +LLTrace::BlockTimerStatHandle FTM_POST_DEFERRED_POOLRENDER("RenderPool (Post)"); +LLTrace::BlockTimerStatHandle FTM_POST_DEFERRED_POOLS("Pools (Post)"); +LLTrace::BlockTimerStatHandle FTM_RENDER_BLOOM_FBO("First FBO"); +LLTrace::BlockTimerStatHandle FTM_STATESORT("Sort Draw State"); +LLTrace::BlockTimerStatHandle FTM_PIPELINE("Pipeline"); +LLTrace::BlockTimerStatHandle FTM_CLIENT_COPY("Client Copy"); +LLTrace::BlockTimerStatHandle FTM_RENDER_DEFERRED("Deferred Shading"); + + +static LLTrace::BlockTimerStatHandle FTM_STATESORT_DRAWABLE("Sort Drawables"); +static LLTrace::BlockTimerStatHandle FTM_STATESORT_POSTSORT("Post Sort"); + +static LLStaticHashedString sDelta("delta"); +static LLStaticHashedString sDistFactor("dist_factor"); //---------------------------------------- std::string gPoolNames[] = { // Correspond to LLDrawpool enum render type "NONE", - "POOL_SIMPLE", "POOL_GROUND", + "POOL_TERRAIN", + "POOL_SIMPLE", "POOL_FULLBRIGHT", "POOL_BUMP", - "POOL_TERRAIN", + "POOL_MATERIALS", "POOL_TREE", // Singu Note: Before sky for zcull. + "POOL_ALPHA_MASK", + "POOL_FULLBRIGHT_ALPHA_MASK", "POOL_SKY", "POOL_WL_SKY", "POOL_GRASS", - "POOL_INVISIBLE", "POOL_AVATAR", "POOL_VOIDWATER", "POOL_WATER", @@ -232,60 +247,44 @@ void drawBoxOutline(const LLVector3& pos, const LLVector3& size); U32 nhpo2(U32 v); LLVertexBuffer* ll_create_cube_vb(U32 type_mask, U32 usage); -glh::matrix4f glh_copy_matrix(F32* src) -{ - glh::matrix4f ret; - ret.set_value(src); - return ret; -} - -glh::matrix4f glh_get_current_modelview() +const LLMatrix4a& glh_get_current_modelview() { - return glh_copy_matrix(gGLModelView); + return gGLModelView; } -glh::matrix4f glh_get_current_projection() +const LLMatrix4a& glh_get_current_projection() { - return glh_copy_matrix(gGLProjection); + return gGLProjection; } -glh::matrix4f glh_get_last_modelview() +inline const LLMatrix4a& glh_get_last_modelview() { - return glh_copy_matrix(gGLLastModelView); + return gGLLastModelView; } -glh::matrix4f glh_get_last_projection() +inline const LLMatrix4a& glh_get_last_projection() { - return glh_copy_matrix(gGLLastProjection); + return gGLLastProjection; } -void glh_copy_matrix(const glh::matrix4f& src, F32* dst) +void glh_set_current_modelview(const LLMatrix4a& mat) { - for (U32 i = 0; i < 16; i++) - { - dst[i] = src.m[i]; - } + gGLModelView = mat; } -void glh_set_current_modelview(const glh::matrix4f& mat) +void glh_set_current_projection(const LLMatrix4a& mat) { - glh_copy_matrix(mat, gGLModelView); + gGLProjection = mat; } -void glh_set_current_projection(glh::matrix4f& mat) +inline void glh_set_last_modelview(const LLMatrix4a& mat) { - glh_copy_matrix(mat, gGLProjection); + gGLLastModelView = mat; } -glh::matrix4f gl_ortho(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat znear, GLfloat zfar) +void glh_set_last_projection(const LLMatrix4a& mat) { - glh::matrix4f ret( - 2.f/(right-left), 0.f, 0.f, -(right+left)/(right-left), - 0.f, 2.f/(top-bottom), 0.f, -(top+bottom)/(top-bottom), - 0.f, 0.f, -2.f/(zfar-znear), -(zfar+znear)/(zfar-znear), - 0.f, 0.f, 0.f, 1.f); - - return ret; + gGLLastProjection = mat; } void display_update_camera(bool tiling=false); @@ -304,14 +303,13 @@ BOOL LLPipeline::sRenderParticleBeacons = FALSE; BOOL LLPipeline::sRenderSoundBeacons = FALSE; BOOL LLPipeline::sRenderBeacons = FALSE; BOOL LLPipeline::sRenderHighlight = TRUE; +LLRender::eTexIndex LLPipeline::sRenderHighlightTextureChannel = LLRender::DIFFUSE_MAP; BOOL LLPipeline::sForceOldBakedUpload = FALSE; S32 LLPipeline::sUseOcclusion = 0; BOOL LLPipeline::sDelayVBUpdate = FALSE; BOOL LLPipeline::sAutoMaskAlphaDeferred = TRUE; BOOL LLPipeline::sAutoMaskAlphaNonDeferred = FALSE; -BOOL LLPipeline::sDisableShaders = FALSE; BOOL LLPipeline::sRenderBump = TRUE; -BOOL LLPipeline::sBakeSunlight = FALSE; BOOL LLPipeline::sNoAlpha = FALSE; BOOL LLPipeline::sUseFarClip = TRUE; BOOL LLPipeline::sShadowRender = FALSE; @@ -320,6 +318,7 @@ BOOL LLPipeline::sWaterReflections = FALSE; BOOL LLPipeline::sRenderGlow = FALSE; BOOL LLPipeline::sReflectionRender = FALSE; BOOL LLPipeline::sImpostorRender = FALSE; +BOOL LLPipeline::sImpostorRenderAlphaDepthPass = FALSE; BOOL LLPipeline::sUnderWaterRender = FALSE; BOOL LLPipeline::sTextureBindTest = FALSE; BOOL LLPipeline::sRenderFrameTest = FALSE; @@ -329,6 +328,7 @@ BOOL LLPipeline::sRenderDeferred = FALSE; BOOL LLPipeline::sMemAllocationThrottled = FALSE; S32 LLPipeline::sVisibleLightCount = 0; F32 LLPipeline::sMinRenderSize = 0.f; +BOOL LLPipeline::sRenderingHUDs = FALSE; static LLCullResult* sCull = NULL; @@ -348,9 +348,9 @@ void validate_framebuffer_object(); bool addDeferredAttachments(LLRenderTarget& target) { - static const LLCachedControl SHPrecisionDeferredNormals("SHPrecisionDeferredNormals",false); - return target.addColorAttachment(GL_RGBA) && //specular - target.addColorAttachment(SHPrecisionDeferredNormals ? GL_RGB10_A2 : GL_RGBA); //normal+z + //static const LLCachedControl SHPrecisionDeferredNormals("SHPrecisionDeferredNormals",false); //DEAD + return target.addColorAttachment(GL_SRGB8_ALPHA8) && //specular + target.addColorAttachment(GL_RGB10_A2); //normal+z } LLPipeline::LLPipeline() : @@ -363,14 +363,7 @@ LLPipeline::LLPipeline() : mMeanBatchSize(0), mTrianglesDrawn(0), mNumVisibleNodes(0), - mVerticesRelit(0), - mLightingChanges(0), - mGeometryChanges(0), - mNumVisibleFaces(0), - mInitialized(FALSE), - mVertexShadersEnabled(FALSE), - mVertexShadersLoaded(0), mTransformFeedbackPrimitives(0), mRenderDebugFeatureMask(0), mRenderDebugMask(0), @@ -379,6 +372,7 @@ LLPipeline::LLPipeline() : mGroupQ1Locked(false), mGroupQ2Locked(false), mResetVertexBuffers(false), + mInRenderPass(false), mLastRebuildPool(NULL), mAlphaPool(NULL), mSkyPool(NULL), @@ -386,45 +380,35 @@ LLPipeline::LLPipeline() : mWaterPool(NULL), mGroundPool(NULL), mSimplePool(NULL), + mGrassPool(NULL), + mAlphaMaskPool(NULL), + mFullbrightAlphaMaskPool(NULL), mFullbrightPool(NULL), - mInvisiblePool(NULL), mGlowPool(NULL), mBumpPool(NULL), + mMaterialsPool(NULL), mWLSkyPool(NULL), mLightMask(0), - mLightMovingMask(0), - mLightingDetail(0) -{ - mNoiseMap = 0; - mTrueNoiseMap = 0; - mLightFunc = 0; -} + mLightMode(LIGHT_MODE_NORMAL) +{} void LLPipeline::init() { refreshCachedSettings(); - gOctreeMaxCapacity = gSavedSettings.getU32("OctreeMaxNodeCapacity"); - gOctreeReserveCapacity = llmin(gSavedSettings.getU32("OctreeReserveNodeCapacity"),U32(512)); - sDynamicLOD = gSavedSettings.getBOOL("RenderDynamicLOD"); - sRenderBump = gSavedSettings.getBOOL("RenderObjectBump"); - LLVertexBuffer::sUseStreamDraw = gSavedSettings.getBOOL("ShyotlRenderUseStreamVBO"); - LLVertexBuffer::sUseVAO = gSavedSettings.getBOOL("RenderUseVAO") && gSavedSettings.getBOOL("VertexShaderEnable"); //Temporary workaround for vaos being broken when shaders are off - LLVertexBuffer::sPreferStreamDraw = gSavedSettings.getBOOL("RenderPreferStreamDraw"); - sRenderAttachedLights = gSavedSettings.getBOOL("RenderAttachedLights"); - sRenderAttachedParticles = gSavedSettings.getBOOL("RenderAttachedParticles"); - - mInitialized = TRUE; + mInitialized = true; stop_glerror(); //create render pass pools getPool(LLDrawPool::POOL_ALPHA); getPool(LLDrawPool::POOL_SIMPLE); + getPool(LLDrawPool::POOL_ALPHA_MASK); + getPool(LLDrawPool::POOL_FULLBRIGHT_ALPHA_MASK); getPool(LLDrawPool::POOL_GRASS); getPool(LLDrawPool::POOL_FULLBRIGHT); - getPool(LLDrawPool::POOL_INVISIBLE); getPool(LLDrawPool::POOL_BUMP); + getPool(LLDrawPool::POOL_MATERIALS); getPool(LLDrawPool::POOL_GLOW); LLViewerStats::getInstance()->mTrianglesDrawnStat.reset(); @@ -468,30 +452,33 @@ void LLPipeline::init() mBackfaceCull = TRUE; stop_glerror(); - + // Enable features - + LLViewerShaderMgr::instance()->setShaders(); stop_glerror(); + for (U32 i = 0; i < 2; ++i) { mSpotLightFade[i] = 1.f; } - setLightingDetail(-1); + updateLocalLightingEnabled(); gSavedSettings.getControl("RenderAutoMaskAlphaDeferred")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); gSavedSettings.getControl("RenderAutoMaskAlphaNonDeferred")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); gSavedSettings.getControl("RenderUseFarClip")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); gSavedSettings.getControl("RenderAvatarMaxVisible")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); //gSavedSettings.getControl("RenderDelayVBUpdate")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); gSavedSettings.getControl("UseOcclusion")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("VertexShaderEnable")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderDeferred")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + //gSavedSettings.getControl("VertexShaderEnable")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); //Already registered to handleSetShaderChanged + //gSavedSettings.getControl("RenderDeferred")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); //Already registered to handleSetShaderChanged gSavedSettings.getControl("RenderFSAASamples")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("RenderAvatarVP")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("WindLightUseAtmosShaders")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + //gSavedSettings.getControl("RenderAvatarVP")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); //Already registered to handleSetShaderChanged + //gSavedSettings.getControl("WindLightUseAtmosShaders")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); //Already registered to handleSetShaderChanged + + gGL.init(); } LLPipeline::~LLPipeline() @@ -531,11 +518,11 @@ void LLPipeline::cleanup() if (!mTerrainPools.empty()) { - llwarns << "Terrain Pools not cleaned up" << llendl; + LL_WARNS() << "Terrain Pools not cleaned up" << LL_ENDL; } if (!mTreePools.empty()) { - llwarns << "Tree Pools not cleaned up" << llendl; + LL_WARNS() << "Tree Pools not cleaned up" << LL_ENDL; } delete mAlphaPool; @@ -552,8 +539,6 @@ void LLPipeline::cleanup() mSimplePool = NULL; delete mFullbrightPool; mFullbrightPool = NULL; - delete mInvisiblePool; - mInvisiblePool = NULL; delete mGlowPool; mGlowPool = NULL; delete mBumpPool; @@ -570,7 +555,8 @@ void LLPipeline::cleanup() mInitialized = FALSE; - mDeferredVB = NULL; + mAuxScreenRectVB = NULL; + mCubeVB = NULL; } @@ -584,7 +570,7 @@ void LLPipeline::destroyGL() resetDrawOrders(); - resetVertexBuffers(); + releaseVertexBuffers(); releaseGLBuffers(); @@ -605,7 +591,7 @@ void LLPipeline::destroyGL() } } -static LLFastTimer::DeclareTimer FTM_RESIZE_SCREEN_TEXTURE("Resize Screen Texture"); +static LLTrace::BlockTimerStatHandle FTM_RESIZE_SCREEN_TEXTURE("Resize Screen Texture"); //static void LLPipeline::throttleNewMemoryAllocation(BOOL disable) @@ -627,20 +613,38 @@ void LLPipeline::throttleNewMemoryAllocation(BOOL disable) void LLPipeline::resizeScreenTexture() { - LLFastTimer ft(FTM_RESIZE_SCREEN_TEXTURE); - if (gPipeline.canUseVertexShaders() && assertInitialized()) + LL_RECORD_BLOCK_TIME(FTM_RESIZE_SCREEN_TEXTURE); + if (LLGLSLShader::sNoFixedFunction && assertInitialized()) { GLuint resX = gViewerWindow->getWorldViewWidthRaw(); GLuint resY = gViewerWindow->getWorldViewHeightRaw(); +// [RLVa:KB] - Checked: 2014-02-23 (RLVa-1.4.10) + U32 resMod = gSavedSettings.getU32("RenderResolutionDivisor"), resAdjustedX = resX, resAdjustedY = resY; + if ( (resMod > 1) && (resMod < resX) && (resMod < resY) ) + { + resAdjustedX /= resMod; + resAdjustedY /= resMod; + } + + if ( (resAdjustedX != mScreen.getWidth()) || (resAdjustedY != mScreen.getHeight()) ) +// [/RLVa:KB] +// if ((resX != mScreen.getWidth()) || (resY != mScreen.getHeight())) + { + releaseScreenBuffers(); if (!allocateScreenBuffer(resX,resY)) - { //FAILSAFE: screen buffer allocation failed, disable deferred rendering if it's enabled + { +#if PROBABLE_FALSE_DISABLES_OF_ALM_HERE + //FAILSAFE: screen buffer allocation failed, disable deferred rendering if it's enabled //NOTE: if the session closes successfully after this call, deferred rendering will be // disabled on future sessions if (LLPipeline::sRenderDeferred) { gSavedSettings.setBOOL("RenderDeferred", FALSE); LLPipeline::refreshCachedSettings(); + + } +#endif } } } @@ -653,7 +657,7 @@ void LLPipeline::allocatePhysicsBuffer() if (mPhysicsDisplay.getWidth() != resX || mPhysicsDisplay.getHeight() != resY) { - mPhysicsDisplay.allocate(resX, resY, GL_RGBA, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE); + mPhysicsDisplay.allocate(resX, resY, GL_RGBA, TRUE, FALSE, LLTexUnit::TT_TEXTURE, FALSE); } } @@ -703,7 +707,6 @@ LLPipeline::eFBOStatus LLPipeline::doAllocateScreenBuffer(U32 resX, U32 resY) // - on failure, shrink number of samples and try again // - if not multisampled, shrink resolution and try again (favor X resolution over Y) // Make sure to call "releaseScreenBuffers" after each failure to cleanup the partially loaded state - eFBOStatus ret = FBO_SUCCESS_FULLRES; if (!allocateScreenBuffer(resX, resY, samples)) { @@ -742,7 +745,7 @@ LLPipeline::eFBOStatus LLPipeline::doAllocateScreenBuffer(U32 resX, U32 resY) releaseScreenBuffers(); } - llwarns << "Unable to allocate screen buffer at any resolution!" << llendl; + LL_WARNS() << "Unable to allocate screen buffer at any resolution!" << LL_ENDL; } return ret; @@ -750,6 +753,8 @@ LLPipeline::eFBOStatus LLPipeline::doAllocateScreenBuffer(U32 resX, U32 resY) bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples) { + mAuxScreenRectVB = NULL; + refreshCachedSettings(); U32 res_mod = gSavedSettings.getU32("RenderResolutionDivisor"); if (res_mod > 1 && res_mod < resX && res_mod < resY) @@ -760,24 +765,41 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples) mSampleBuffer.release(); mScreen.release(); + mFinalScreen.release(); + + mDeferredDownsampledDepth.release(); if (LLPipeline::sRenderDeferred) { - S32 shadow_detail = gSavedSettings.getS32("RenderShadowDetail"); - BOOL ssao = gSavedSettings.getBOOL("RenderDeferredSSAO"); - BOOL RenderDepthOfField = gSavedSettings.getBOOL("RenderDepthOfField"); + static const LLCachedControl shadow_detail("RenderShadowDetail",0); + static const LLCachedControl ssao ("RenderDeferredSSAO",false); + static const LLCachedControl RenderDepthOfField("RenderDepthOfField",false); static const LLCachedControl RenderShadowResolutionScale("RenderShadowResolutionScale",1.0f); + static const LLCachedControl RenderSSAOResolutionScale("SHRenderSSAOResolutionScale",.5f); + const U32 occlusion_divisor = 3; //allocate deferred rendering color buffers - if (!mDeferredScreen.allocate(resX, resY, GL_RGBA, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, FALSE)) return false; - if (!mDeferredDepth.allocate(resX, resY, 0, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE)) return false; + if (!mDeferredScreen.allocate(resX, resY, GL_SRGB8_ALPHA8, TRUE, TRUE, LLTexUnit::TT_TEXTURE, FALSE)) return false; + if (!mDeferredDepth.allocate(resX, resY, 0, TRUE, FALSE, LLTexUnit::TT_TEXTURE, FALSE)) return false; if (!addDeferredAttachments(mDeferredScreen)) return false; + + GLuint screenFormat = GL_RGBA16; + if (gGLManager.mIsATI) + { + screenFormat = GL_RGBA12; + } - if (!mScreen.allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE)) return false; + if (gGLManager.mGLVersion < 4.f && gGLManager.mIsNVIDIA) + { + screenFormat = GL_RGBA16F_ARB; + } + + if (!mScreen.allocate(resX, resY, screenFormat, FALSE, FALSE, LLTexUnit::TT_TEXTURE, FALSE)) return false; + if (!mFinalScreen.allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_TEXTURE, FALSE)) return false; if (samples > 0) { - if (!mFXAABuffer.allocate(nhpo2(resX), nhpo2(resY), GL_RGBA, FALSE, FALSE, LLTexUnit::TT_TEXTURE, FALSE)) return false; + if (!mFXAABuffer.allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_TEXTURE, FALSE)) return false; } else { @@ -786,7 +808,12 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples) if (shadow_detail > 0 || ssao || RenderDepthOfField || samples > 0) { //only need mDeferredLight for shadows OR ssao OR dof OR fxaa - if (!mDeferredLight.allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE)) return false; + if (!mDeferredLight.allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_TEXTURE, FALSE)) return false; + if(ssao) + { + F32 scale = llclamp(RenderSSAOResolutionScale.get(),.01f,1.f); + if( scale < 1.f && !mDeferredDownsampledDepth.allocate(llceil(F32(resX)*scale), llceil(F32(resY)*scale), 0, TRUE, FALSE, LLTexUnit::TT_TEXTURE, FALSE) ) return false; + } } else { @@ -800,7 +827,7 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples) U32 sun_shadow_map_width = ((U32(resX*scale)+1)&~1); // must be even to avoid a stripe in the horizontal shadow blur for (U32 i = 0; i < 4; i++) { - if (!mShadow[i].allocate(sun_shadow_map_width,U32(resY*scale), 0, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE)) return false; + if (!mShadow[i].allocate(sun_shadow_map_width,U32(resY*scale), 0, TRUE, FALSE, LLTexUnit::TT_TEXTURE)) return false; } } else @@ -811,7 +838,7 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples) } } - U32 width = nhpo2(U32(resX*scale))/2; + U32 width = (U32) (resX*scale); U32 height = width; if (shadow_detail > 1) @@ -846,14 +873,15 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples) } mFXAABuffer.release(); mScreen.release(); + mFinalScreen.release(); mDeferredScreen.release(); //make sure to release any render targets that share a depth buffer with mDeferredScreen first mDeferredDepth.release(); - - - if (!mScreen.allocate(resX, resY, GL_RGBA, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, FALSE)) return false; - if(samples > 1) + mDeferredDownsampledDepth.release(); + + if (!mScreen.allocate(resX, resY, GL_RGBA, TRUE, TRUE, LLTexUnit::TT_TEXTURE, FALSE)) return false; + if(samples > 1 && mScreen.getFBO()) { - if(mSampleBuffer.allocate(resX,resY,GL_RGBA,TRUE,TRUE,LLTexUnit::TT_RECT_TEXTURE,FALSE,samples)) + if(mSampleBuffer.allocate(resX,resY,GL_RGBA,TRUE,TRUE,LLTexUnit::TT_TEXTURE,FALSE,samples)) mScreen.setSampleBuffer(&mSampleBuffer); else { @@ -867,6 +895,8 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples) if (LLPipeline::sRenderDeferred) { //share depth buffer between deferred targets mDeferredScreen.shareDepthBuffer(mScreen); + mDeferredScreen.shareDepthBuffer(mFinalScreen); + //mDeferredScreen.shareDepthBuffer(mDeferredLight); /*for (U32 i = 0; i < 3; i++) { //share stencil buffer with screen space lightmap to stencil out sky if (mDeferredLight[i].getTexture(0)) @@ -883,29 +913,63 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples) return true; } +bool LLPipeline::isRenderDeferredCapable() +{ + return gGLManager.mHasFramebufferObject && + LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") && + LLFeatureManager::getInstance()->isFeatureAvailable("RenderAvatarVP") && //Hardware Skinning. Deferred forces RenderAvatarVP to true + LLFeatureManager::getInstance()->isFeatureAvailable("VertexShaderEnable") && //Basic Shaders + LLFeatureManager::getInstance()->isFeatureAvailable("WindLightUseAtmosShaders") && //Atmospheric Shaders + LLFeatureManager::getInstance()->isFeatureAvailable("VertexShaderEnable"); +} + +bool LLPipeline::isRenderDeferredDesired() +{ + return isRenderDeferredCapable() && + gSavedSettings.getBOOL("RenderDeferred") && + gSavedSettings.getBOOL("VertexShaderEnable") && + gSavedSettings.getBOOL("WindLightUseAtmosShaders"); +} + //static void LLPipeline::updateRenderDeferred() { - sRenderDeferred = (gSavedSettings.getBOOL("RenderDeferred") && - LLRenderTarget::sUseFBO && - LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") && - gSavedSettings.getBOOL("VertexShaderEnable") && - gSavedSettings.getBOOL("RenderAvatarVP") && - gSavedSettings.getBOOL("WindLightUseAtmosShaders") && - !gUseWireframe); - if (sRenderDeferred) + bool deferred = (bool(LLRenderTarget::sUseFBO && + LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") && + LLPipeline::sRenderBump && + isRenderDeferredDesired())) && + !gUseWireframe; + + sRenderDeferred = deferred; + if (deferred) { //must render glow when rendering deferred since post effect pass is needed to present any lighting at all - sRenderGlow = TRUE; + sRenderGlow = true; } } + + //static void LLPipeline::refreshCachedSettings() { + LLRenderTarget::sUseFBO = gSavedSettings.getBOOL("RenderUseFBO") || LLPipeline::sRenderDeferred; LLPipeline::sAutoMaskAlphaDeferred = gSavedSettings.getBOOL("RenderAutoMaskAlphaDeferred"); LLPipeline::sAutoMaskAlphaNonDeferred = gSavedSettings.getBOOL("RenderAutoMaskAlphaNonDeferred"); LLPipeline::sUseFarClip = gSavedSettings.getBOOL("RenderUseFarClip"); LLVOAvatar::sMaxVisible = (U32)gSavedSettings.getS32("RenderAvatarMaxVisible"); //LLPipeline::sDelayVBUpdate = gSavedSettings.getBOOL("RenderDelayVBUpdate"); + gOctreeMaxCapacity = gSavedSettings.getU32("OctreeMaxNodeCapacity"); + gOctreeMinSize = gSavedSettings.getF32("OctreeMinimumNodeSize"); + gOctreeReserveCapacity = llmin(gSavedSettings.getU32("OctreeReserveNodeCapacity"), U32(512)); + LLPipeline::sDynamicLOD = gSavedSettings.getBOOL("RenderDynamicLOD"); + LLPipeline::sRenderBump = gSavedSettings.getBOOL("RenderObjectBump"); + LLVertexBuffer::sUseStreamDraw = gSavedSettings.getBOOL("ShyotlRenderUseStreamVBO"); + LLVertexBuffer::sEnableVBOs = gSavedSettings.getBOOL("RenderVBOEnable"); + LLVertexBuffer::sUseVAO = gSavedSettings.getBOOL("RenderUseVAO") && gSavedSettings.getBOOL("VertexShaderEnable"); //Temporary workaround for vaos being broken when shaders are off + LLVertexBuffer::sDisableVBOMapping = LLVertexBuffer::sEnableVBOs;// && gSavedSettings.getBOOL("RenderVBOMappingDisable") ; //Temporary workaround for vbo mapping being straight up broken + LLVertexBuffer::sPreferStreamDraw = gSavedSettings.getBOOL("RenderPreferStreamDraw"); + LLPipeline::sRenderAttachedLights = gSavedSettings.getBOOL("RenderAttachedLights"); + LLPipeline::sRenderAttachedParticles = gSavedSettings.getBOOL("RenderAttachedParticles"); + LLPipeline::sTextureBindTest = gSavedSettings.getBOOL("RenderDebugTextureBind"); LLPipeline::sUseOcclusion = (!gUseWireframe @@ -913,26 +977,75 @@ void LLPipeline::refreshCachedSettings() && LLFeatureManager::getInstance()->isFeatureAvailable("UseOcclusion") && gSavedSettings.getBOOL("UseOcclusion") && gGLManager.mHasOcclusionQuery) ? 2 : 0; - - updateRenderDeferred(); } -void LLPipeline::releaseGLBuffers() +void LLPipeline::releaseOcclusionBuffers() { - assertInitialized(); - - if (mNoiseMap) + for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); + iter != LLWorld::getInstance()->getRegionList().end(); ++iter) + { + LLViewerRegion* region = *iter; + for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) + { + LLSpatialPartition* part = region->getSpatialPartition(i); + if (part) + { + part->resetVertexBuffers(); + } + } + } +} +void LLPipeline::releaseVertexBuffers() +{ + mCubeVB = NULL; + mAuxScreenRectVB = NULL; + + for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); + iter != LLWorld::getInstance()->getRegionList().end(); ++iter) { - LLImageGL::deleteTextures(LLTexUnit::TT_TEXTURE, GL_RGB16F_ARB, 0, 1, &mNoiseMap); - mNoiseMap = 0; + LLViewerRegion* region = *iter; + for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) + { + LLSpatialPartition* part = region->getSpatialPartition(i); + if (part) + { + part->resetVertexBuffers(); + } + } } - if (mTrueNoiseMap) + resetDrawOrders(); + + gSky.resetVertexBuffers(); + + LLVOPartGroup::destroyGL(); + + if (LLPostProcess::instanceExists()) + LLPostProcess::getInstance()->destroyGL(); + + LLVOPartGroup::destroyGL(); + + //delete all name pool caches + LLGLNamePool::cleanupPools(); + + gGL.resetVertexBuffers(); + + LLVertexBuffer::cleanupClass(); + + if (LLVertexBuffer::sGLCount > 0) { - LLImageGL::deleteTextures(LLTexUnit::TT_TEXTURE, GL_RGB16F_ARB, 0, 1, &mTrueNoiseMap); - mTrueNoiseMap = 0; + LL_WARNS() << "VBO wipe failed -- " << LLVertexBuffer::sGLCount << " buffers remaining. " << LLVertexBuffer::sCount << LL_ENDL; } + LLVertexBuffer::unbind(); +} + +void LLPipeline::releaseGLBuffers() +{ + assertInitialized(); + + mNoiseMap.reset(); + releaseLUTBuffers(); mWaterRef.release(); @@ -954,30 +1067,24 @@ void LLPipeline::releaseGLBuffers() void LLPipeline::releaseLUTBuffers() { - if (mLightFunc) - { - LLImageGL::deleteTextures(LLTexUnit::TT_TEXTURE, GL_R8, 0, 1, &mLightFunc); - mLightFunc = 0; - } + mLightFunc.reset(); } void LLPipeline::releaseScreenBuffers() { mScreen.release(); + mFinalScreen.release(); mFXAABuffer.release(); mPhysicsDisplay.release(); mDeferredScreen.release(); mDeferredDepth.release(); + mDeferredDownsampledDepth.release(); mDeferredLight.release(); - - //mHighlight.release(); for (U32 i = 0; i < 6; i++) { mShadow[i].release(); } - - mSampleBuffer.release(); } @@ -986,15 +1093,30 @@ void LLPipeline::createGLBuffers() stop_glerror(); assertInitialized(); - updateRenderDeferred(); + bool materials_in_water = false; + +#if MATERIALS_IN_REFLECTIONS + materials_in_water = gSavedSettings.getS32("RenderWaterMaterials"); +#endif if (LLPipeline::sWaterReflections) { //water reflection texture U32 res = (U32) llmax(gSavedSettings.getS32("RenderWaterRefResolution"), 512); - mWaterRef.allocate(res,res,GL_RGBA,TRUE,FALSE); - //always use FBO for mWaterDis so it can be used for avatar texture bakes - mWaterDis.allocate(res,res,GL_RGBA,TRUE,FALSE,LLTexUnit::TT_TEXTURE, true); + // Set up SRGB targets if we're doing deferred-path reflection rendering + // + if (LLPipeline::sRenderDeferred && materials_in_water) + { + mWaterRef.allocate(res,res,GL_SRGB8_ALPHA8,TRUE,FALSE); + //always use FBO for mWaterDis so it can be used for avatar texture bakes + mWaterDis.allocate(res,res,GL_SRGB8_ALPHA8,TRUE,FALSE,LLTexUnit::TT_TEXTURE, true); + } + else + { + mWaterRef.allocate(res,res,GL_RGBA,TRUE,FALSE); + //always use FBO for mWaterDis so it can be used for avatar texture bakes + mWaterDis.allocate(res,res,GL_RGBA,TRUE,FALSE,LLTexUnit::TT_TEXTURE, true); + } } @@ -1031,36 +1153,20 @@ void LLPipeline::createGLBuffers() { if (!mNoiseMap) { - const U32 noiseRes = 128; - LLVector3 noise[noiseRes*noiseRes]; + std::array noise; F32 scaler = gSavedSettings.getF32("RenderDeferredNoise")/100.f; - for (U32 i = 0; i < noiseRes*noiseRes; ++i) + for (auto& val : noise) { - noise[i] = LLVector3(ll_frand()-0.5f, ll_frand()-0.5f, 0.f); - noise[i].normVec(); - noise[i].mV[2] = ll_frand()*scaler+1.f-scaler/2.f; + val = LLVector3(ll_frand()-0.5f, ll_frand()-0.5f, 0.f); + val.normVec(); + val.mV[2] = ll_frand()*scaler+1.f-scaler/2.f; } - LLImageGL::generateTextures(LLTexUnit::TT_TEXTURE, GL_RGB16F_ARB, 1, &mNoiseMap); + mNoiseMap = LLImageGL::createTextureName(); - gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mNoiseMap); - LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_RGB16F_ARB, noiseRes, noiseRes, GL_RGB, GL_FLOAT, noise, false); - gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); - } - - if (!mTrueNoiseMap) - { - const U32 noiseRes = 128; - F32 noise[noiseRes*noiseRes*3]; - for (U32 i = 0; i < noiseRes*noiseRes*3; i++) - { - noise[i] = ll_frand()*2.0-1.0; - } - - LLImageGL::generateTextures(LLTexUnit::TT_TEXTURE, GL_RGB16F_ARB, 1, &mTrueNoiseMap); - gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mTrueNoiseMap); - LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_RGB16F_ARB, noiseRes, noiseRes, GL_RGB,GL_FLOAT, noise, false); + gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mNoiseMap->getTexName()); + LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_RGB16F_ARB, NOISE_MAP_RES, NOISE_MAP_RES, GL_RGB, GL_FLOAT, noise.data()); gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); } @@ -1078,8 +1184,9 @@ void LLPipeline::createLUTBuffers() { U32 lightResX = gSavedSettings.getU32("RenderSpecularResX"); U32 lightResY = gSavedSettings.getU32("RenderSpecularResY"); - U8* ls = new U8[lightResX*lightResY]; - static const LLCachedControl specExp("RenderSpecularExponent"); + //U8* ls = new U8[lightResX*lightResY]; + F32* ls = new F32[lightResX*lightResY]; + //static const LLCachedControl specExp("RenderSpecularExponent"); // Calculate the (normalized) Blinn-Phong specular lookup texture. for (U32 y = 0; y < lightResY; ++y) { @@ -1088,7 +1195,7 @@ void LLPipeline::createLUTBuffers() ls[y*lightResX+x] = 0; F32 sa = (F32) x/(lightResX-1); F32 spec = (F32) y/(lightResY-1); - F32 n = spec * spec * specExp; + F32 n = spec * spec * 368;//specExp; // Nothing special here. Just your typical blinn-phong term. spec = powf(sa, n); @@ -1102,7 +1209,7 @@ void LLPipeline::createLUTBuffers() // Always sample at a 1.0/2.2 curve. // This "Gamma corrects" our specular term, boosting our lower exponent reflections. - spec = powf(spec, 1.f/2.2f); + ls[y*lightResX+x] = spec; // Easy fix for our dynamic range problem: divide by 6 here, multiply by 6 in our shaders. // This allows for our specular term to exceed a value of 1 in our shaders. @@ -1110,15 +1217,24 @@ void LLPipeline::createLUTBuffers() // Technically, we could just use an R16F texture, but driver support for R16F textures can be somewhat spotty at times. // This works remarkably well for higher specular exponents, though banding can sometimes be seen on lower exponents. // Combined with a bit of noise and trilinear filtering, the banding is hardly noticable. - ls[y*lightResX+x] = (U8)(llclamp(spec * (1.f / 6), 0.f, 1.f) * 255); + //ls[y*lightResX+x] = (U8)(llclamp(spec * (1.f / 6), 0.f, 1.f) * 255); } } - LLImageGL::generateTextures(LLTexUnit::TT_TEXTURE, GL_R8, 1, &mLightFunc); - gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mLightFunc); - LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_R8, lightResX, lightResY, GL_RED, GL_UNSIGNED_BYTE, ls, false); + U32 pix_format = GL_R16F; +#if LL_DARWIN + // Need to work around limited precision with 10.6.8 and older drivers + // + pix_format = GL_R32F; +#endif + mLightFunc = LLImageGL::createTextureName(); + gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mLightFunc->getTexName()); + LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, pix_format, lightResX, lightResY, GL_RED, GL_FLOAT, ls); + //LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_UNSIGNED_BYTE, lightResX, lightResY, GL_RED, GL_UNSIGNED_BYTE, ls, false); gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_TRILINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); delete [] ls; } @@ -1130,10 +1246,7 @@ void LLPipeline::restoreGL() { assertInitialized(); - if (mVertexShadersEnabled) - { - LLViewerShaderMgr::instance()->setShaders(); - } + LLViewerShaderMgr::instance()->setShaders(); for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); iter != LLWorld::getInstance()->getRegionList().end(); ++iter) @@ -1149,32 +1262,12 @@ void LLPipeline::restoreGL() } } - resetLocalLights(); //Default all gl light parameters. Fixes light brightness problems on fullscren toggle -} - - -BOOL LLPipeline::canUseVertexShaders() -{ - static const std::string vertex_shader_enable_feature_string = "VertexShaderEnable"; - - if (sDisableShaders || - !gGLManager.mHasVertexShader || - !gGLManager.mHasFragmentShader || - !LLFeatureManager::getInstance()->isFeatureAvailable(vertex_shader_enable_feature_string) || - (assertInitialized() && mVertexShadersLoaded != 1) ) - { - return FALSE; - } - else - { - return TRUE; - } + updateLocalLightingEnabled(); //Default all gl light parameters. Fixes light brightness problems on fullscren toggle } BOOL LLPipeline::canUseWindLightShaders() const { - return (!LLPipeline::sDisableShaders && - gWLSkyProgram.mProgramObject != 0 && + return (gWLSkyProgram.mProgramObject != 0 && LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_WINDLIGHT) > 1); } @@ -1192,13 +1285,11 @@ BOOL LLPipeline::canUseAntiAliasing() const void LLPipeline::unloadShaders() { LLViewerShaderMgr::instance()->unloadShaders(); - - mVertexShadersLoaded = 0; } void LLPipeline::assertInitializedDoError() { - llerrs << "LLPipeline used when uninitialized." << llendl; + LL_ERRS() << "LLPipeline used when uninitialized." << LL_ENDL; } //============================================================================ @@ -1208,55 +1299,32 @@ void LLPipeline::enableShadows(const BOOL enable_shadows) //should probably do something here to wrangle shadows.... } -S32 LLPipeline::getMaxLightingDetail() const -{ - /*if (mVertexShaderLevel[SHADER_OBJECT] >= LLDrawPoolSimple::SHADER_LEVEL_LOCAL_LIGHTS) - { - return 3; - } - else*/ - { - return 1; - } -} - -S32 LLPipeline::setLightingDetail(S32 level) +void LLPipeline::updateLocalLightingEnabled() { refreshCachedSettings(); - if (level < 0) - { - if (gSavedSettings.getBOOL("RenderLocalLights")) - { - level = 1; - } - else - { - level = 0; - } - } - level = llclamp(level, 0, getMaxLightingDetail()); + static const LLCachedControl render_local_lights("RenderLocalLights", true); //Bugfix: If setshaders was called with RenderLocalLights off then enabling RenderLocalLights later will not work. Reloading shaders fixes this. - if (level != mLightingDetail && mVertexShadersLoaded) + if (render_local_lights != mLightingEnabled) { - LLViewerShaderMgr::instance()->setShaders(); + mLightingEnabled = render_local_lights; + if (LLGLSLShader::sNoFixedFunction) + LLViewerShaderMgr::instance()->setShaders(); } - mLightingDetail = level; - return mLightingDetail; } -class LLOctreeDirtyTexture : public LLOctreeTraveler +class LLOctreeDirtyTexture : public OctreeTraveler { public: const std::set& mTextures; LLOctreeDirtyTexture(const std::set& textures) : mTextures(textures) { } - virtual void visit(const LLOctreeNode* node) + virtual void visit(const OctreeNode* node) { LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0); - if (!group->isState(LLSpatialGroup::GEOM_DIRTY) && !group->isEmpty()) + if (!group->hasState(LLSpatialGroup::GEOM_DIRTY) && !group->isEmpty()) { for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i) { @@ -1328,12 +1396,16 @@ LLDrawPool *LLPipeline::findPool(const U32 type, LLViewerTexture *tex0) poolp = mGrassPool; break; - case LLDrawPool::POOL_FULLBRIGHT: - poolp = mFullbrightPool; + case LLDrawPool::POOL_ALPHA_MASK: + poolp = mAlphaMaskPool; + break; + + case LLDrawPool::POOL_FULLBRIGHT_ALPHA_MASK: + poolp = mFullbrightAlphaMaskPool; break; - case LLDrawPool::POOL_INVISIBLE: - poolp = mInvisiblePool; + case LLDrawPool::POOL_FULLBRIGHT: + poolp = mFullbrightPool; break; case LLDrawPool::POOL_GLOW: @@ -1351,7 +1423,9 @@ LLDrawPool *LLPipeline::findPool(const U32 type, LLViewerTexture *tex0) case LLDrawPool::POOL_BUMP: poolp = mBumpPool; break; - + case LLDrawPool::POOL_MATERIALS: + poolp = mMaterialsPool; + break; case LLDrawPool::POOL_ALPHA: poolp = mAlphaPool; break; @@ -1377,7 +1451,7 @@ LLDrawPool *LLPipeline::findPool(const U32 type, LLViewerTexture *tex0) default: llassert(0); - llerrs << "Invalid Pool Type in LLPipeline::findPool() type=" << type << llendl; + LL_ERRS() << "Invalid Pool Type in LLPipeline::findPool() type=" << type << LL_ENDL; break; } @@ -1393,6 +1467,7 @@ LLDrawPool *LLPipeline::getPool(const U32 type, LLViewerTexture *tex0) return poolp; } + LLDrawPool *new_poolp = LLDrawPool::createPool(type, tex0); addPool( new_poolp ); @@ -1423,36 +1498,92 @@ U32 LLPipeline::getPoolTypeFromTE(const LLTextureEntry* te, LLViewerTexture* ima { alpha = alpha || (imagep->getComponents() == 4 && imagep->getType() != LLViewerTexture::MEDIA_TEXTURE) || (imagep->getComponents() == 2); } - + if (alpha && mat) { switch (mat->getDiffuseAlphaMode()) { - case 1: + case LLMaterial::DIFFUSE_ALPHA_MODE_BLEND: alpha = true; // Material's alpha mode is set to blend. Toss it into the alpha draw pool. break; - case 0: //alpha mode set to none, never go to alpha pool - case 3: //alpha mode set to emissive, never go to alpha pool + case LLMaterial::DIFFUSE_ALPHA_MODE_NONE: //alpha mode set to none, never go to alpha pool + case LLMaterial::DIFFUSE_ALPHA_MODE_EMISSIVE: //alpha mode set to emissive, never go to alpha pool alpha = color_alpha; break; default: //alpha mode set to "mask", go to alpha pool if fullbright - alpha = color_alpha; // Material's alpha mode is set to none, mask, or emissive. Toss it into the opaque material draw pool. + alpha = color_alpha; // Material's alpha mode is set to mask, or default. Toss it into the opaque material draw pool. break; } } + static const LLCachedControl alt_batching("SHAltBatching",true); + + if(!alt_batching) + { if (alpha) { return LLDrawPool::POOL_ALPHA; } - else if ((te->getBumpmap() || te->getShiny())) + else if ((te->getBumpmap() || te->getShiny()) && (!mat || mat->getNormalID().isNull())) { return LLDrawPool::POOL_BUMP; } + else if (mat && !alpha) + { + return LLDrawPool::POOL_MATERIALS; + } + else + { + return LLDrawPool::POOL_SIMPLE; + } + } + else + { + static const LLCachedControl sh_fullbright_deferred("SHFullbrightDeferred",true); + + //Bump goes into bump pool unless using deferred and there's a normal map that takes precedence. + bool legacy_bump = (!LLPipeline::sRenderDeferred || !mat || mat->getNormalID().isNull()) && LLPipeline::sRenderBump && te->getBumpmap() && te->getBumpmap() < 18; + if (alpha) + { + return LLDrawPool::POOL_ALPHA; + } + else if (mat && mat->getDiffuseAlphaMode() == LLMaterial::DIFFUSE_ALPHA_MODE_MASK) + { + if(!LLPipeline::sRenderDeferred || legacy_bump) + { + return te->getFullbright() ? LLDrawPool::POOL_FULLBRIGHT_ALPHA_MASK : LLDrawPool::POOL_ALPHA_MASK; + } + else if(te->getFullbright() && !mat->getEnvironmentIntensity() && !te->getShiny()) + { + return LLDrawPool::POOL_FULLBRIGHT_ALPHA_MASK; + } + return LLDrawPool::POOL_MATERIALS; + } + else if (legacy_bump) + { + return LLDrawPool::POOL_BUMP; + } + else if(LLPipeline::sRenderDeferred && mat) + { + if(te->getFullbright() && !mat->getEnvironmentIntensity() && !te->getShiny()) + { + return sh_fullbright_deferred ? LLDrawPool::POOL_FULLBRIGHT : LLDrawPool::POOL_SIMPLE; + } + return LLDrawPool::POOL_MATERIALS; + } + else if((sh_fullbright_deferred || !LLPipeline::sRenderDeferred) && te->getFullbright()) + { + return (LLPipeline::sRenderBump && te->getShiny()) ? LLDrawPool::POOL_BUMP : LLDrawPool::POOL_FULLBRIGHT; + } + else if (!LLPipeline::sRenderDeferred && LLPipeline::sRenderBump && te->getShiny()) + { + return LLDrawPool::POOL_BUMP; //Shiny goes into bump pool when not using deferred rendering. + } else { return LLDrawPool::POOL_SIMPLE; } + } } @@ -1467,14 +1598,12 @@ void LLPipeline::allocDrawable(LLViewerObject *vobj) { if(!vobj) { - llerrs << "Null object passed to allocDrawable!" << llendl; + LL_ERRS() << "Null object passed to allocDrawable!" << LL_ENDL; } - LLDrawable *drawable = new LLDrawable(); + LLDrawable *drawable = new LLDrawable(vobj); vobj->mDrawable = drawable; - drawable->mVObjp = vobj; - //encompass completely sheared objects by taking //the most extreme point possible (<1,1,0.5>) drawable->setRadius(LLVector3(1,1,0.5f).scaleVec(vobj->getScale()).length()); @@ -1486,15 +1615,15 @@ void LLPipeline::allocDrawable(LLViewerObject *vobj) } -static LLFastTimer::DeclareTimer FTM_UNLINK("Unlink"); -static LLFastTimer::DeclareTimer FTM_REMOVE_FROM_MOVE_LIST("Movelist"); -static LLFastTimer::DeclareTimer FTM_REMOVE_FROM_SPATIAL_PARTITION("Spatial Partition"); -static LLFastTimer::DeclareTimer FTM_REMOVE_FROM_LIGHT_SET("Light Set"); -//static LLFastTimer::DeclareTimer FTM_REMOVE_FROM_HIGHLIGHT_SET("Highlight Set"); +static LLTrace::BlockTimerStatHandle FTM_UNLINK("Unlink"); +static LLTrace::BlockTimerStatHandle FTM_REMOVE_FROM_MOVE_LIST("Movelist"); +static LLTrace::BlockTimerStatHandle FTM_REMOVE_FROM_SPATIAL_PARTITION("Spatial Partition"); +static LLTrace::BlockTimerStatHandle FTM_REMOVE_FROM_LIGHT_SET("Light Set"); +//static LLTrace::BlockTimerStatHandle FTM_REMOVE_FROM_HIGHLIGHT_SET("Highlight Set"); void LLPipeline::unlinkDrawable(LLDrawable *drawable) { - LLFastTimer t(FTM_UNLINK); + LL_RECORD_BLOCK_TIME(FTM_UNLINK); assertInitialized(); @@ -1503,7 +1632,7 @@ void LLPipeline::unlinkDrawable(LLDrawable *drawable) // Based on flags, remove the drawable from the queues that it's on. if (drawablep->isState(LLDrawable::ON_MOVE_LIST)) { - LLFastTimer t(FTM_REMOVE_FROM_MOVE_LIST); + LL_RECORD_BLOCK_TIME(FTM_REMOVE_FROM_MOVE_LIST); LLDrawable::drawable_vector_t::iterator iter = std::find(mMovedList.begin(), mMovedList.end(), drawablep); if (iter != mMovedList.end()) { @@ -1513,19 +1642,19 @@ void LLPipeline::unlinkDrawable(LLDrawable *drawable) if (drawablep->getSpatialGroup()) { - LLFastTimer t(FTM_REMOVE_FROM_SPATIAL_PARTITION); - if (!drawablep->getSpatialGroup()->mSpatialPartition->remove(drawablep, drawablep->getSpatialGroup())) + LL_RECORD_BLOCK_TIME(FTM_REMOVE_FROM_SPATIAL_PARTITION); + if (!drawablep->getSpatialGroup()->getSpatialPartition()->remove(drawablep, drawablep->getSpatialGroup())) { #ifdef LL_RELEASE_FOR_DOWNLOAD - llwarns << "Couldn't remove object from spatial group!" << llendl; + LL_WARNS() << "Couldn't remove object from spatial group!" << LL_ENDL; #else - llerrs << "Couldn't remove object from spatial group!" << llendl; + LL_ERRS() << "Couldn't remove object from spatial group!" << LL_ENDL; #endif } } { - LLFastTimer t(FTM_REMOVE_FROM_LIGHT_SET); + LL_RECORD_BLOCK_TIME(FTM_REMOVE_FROM_LIGHT_SET); mLights.erase(drawablep); for (light_set_t::iterator iter = mNearbyLights.begin(); @@ -1558,7 +1687,7 @@ void LLPipeline::unlinkDrawable(LLDrawable *drawable) //static void LLPipeline::removeMutedAVsLights(LLVOAvatar* muted_avatar) { - LLFastTimer t(FTM_REMOVE_FROM_LIGHT_SET); + LL_RECORD_BLOCK_TIME(FTM_REMOVE_FROM_LIGHT_SET); for (light_set_t::iterator iter = gPipeline.mNearbyLights.begin(); iter != gPipeline.mNearbyLights.end();) { @@ -1594,7 +1723,7 @@ U32 LLPipeline::addObject(LLViewerObject *vobj) void LLPipeline::createObjects(F32 max_dtime) { - LLFastTimer ftm(FTM_PIPELINE_CREATE); + LL_RECORD_BLOCK_TIME(FTM_PIPELINE_CREATE); LLTimer update_timer; @@ -1626,7 +1755,7 @@ void LLPipeline::createObject(LLViewerObject* vobj) } else { - llerrs << "Redundant drawable creation!" << llendl; + LL_ERRS() << "Redundant drawable creation!" << LL_ENDL; } llassert(drawablep); @@ -1658,6 +1787,8 @@ void LLPipeline::resetFrameStats() { assertInitialized(); + sCompiles = 0; + LLViewerStats::getInstance()->mTrianglesDrawnStat.addValue(mTrianglesDrawn/1000.f); if (mBatchCount > 0) @@ -1665,11 +1796,6 @@ void LLPipeline::resetFrameStats() mMeanBatchSize = gPipeline.mTrianglesDrawn/gPipeline.mBatchCount; } mTrianglesDrawn = 0; - sCompiles = 0; - mVerticesRelit = 0; - mLightingChanges = 0; - mGeometryChanges = 0; - mNumVisibleFaces = 0; if (mOldRenderDebugMask != mRenderDebugMask) { @@ -1689,7 +1815,7 @@ void LLPipeline::updateMoveDampedAsync(LLDrawable* drawablep) } if (!drawablep) { - llerrs << "updateMove called with NULL drawablep" << llendl; + LL_ERRS() << "updateMove called with NULL drawablep" << LL_ENDL; return; } if (drawablep->isState(LLDrawable::EARLY_MOVE)) @@ -1720,7 +1846,7 @@ void LLPipeline::updateMoveNormalAsync(LLDrawable* drawablep) } if (!drawablep) { - llerrs << "updateMove called with NULL drawablep" << llendl; + LL_ERRS() << "updateMove called with NULL drawablep" << LL_ENDL; return; } if (drawablep->isState(LLDrawable::EARLY_MOVE)) @@ -1777,12 +1903,12 @@ void LLPipeline::updateMovedList(LLDrawable::drawable_vector_t& moved_list) } } -static LLFastTimer::DeclareTimer FTM_OCTREE_BALANCE("Balance Octree"); -static LLFastTimer::DeclareTimer FTM_UPDATE_MOVE("Update Move"); +static LLTrace::BlockTimerStatHandle FTM_OCTREE_BALANCE("Balance Octree"); +static LLTrace::BlockTimerStatHandle FTM_UPDATE_MOVE("Update Move"); void LLPipeline::updateMove() { - LLFastTimer t(FTM_UPDATE_MOVE); + LL_RECORD_BLOCK_TIME(FTM_UPDATE_MOVE); static const LLCachedControl freeze_time("FreezeTime",false); if (freeze_time) @@ -1793,8 +1919,8 @@ void LLPipeline::updateMove() assertInitialized(); { - static LLFastTimer::DeclareTimer ftm("Retexture"); - LLFastTimer t(ftm); + static LLTrace::BlockTimerStatHandle ftm("Retexture"); + LL_RECORD_BLOCK_TIME(ftm); for (LLDrawable::drawable_set_t::iterator iter = mRetexturedList.begin(); iter != mRetexturedList.end(); ++iter) @@ -1809,14 +1935,14 @@ void LLPipeline::updateMove() } { - static LLFastTimer::DeclareTimer ftm("Moved List"); - LLFastTimer t(ftm); + static LLTrace::BlockTimerStatHandle ftm("Moved List"); + LL_RECORD_BLOCK_TIME(ftm); updateMovedList(mMovedList); } //balance octrees { - LLFastTimer ot(FTM_OCTREE_BALANCE); + LL_RECORD_BLOCK_TIME(FTM_OCTREE_BALANCE); for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); iter != LLWorld::getInstance()->getRegionList().end(); ++iter) @@ -1899,9 +2025,9 @@ void check_references(LLSpatialGroup* group, LLDrawable* drawable) { for (LLSpatialGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i) { - if (drawable == *i) + if (drawable == (LLDrawable*)(*i)->getDrawable()) { - llerrs << "LLDrawable deleted while actively reference by LLPipeline." << llendl; + LL_ERRS() << "LLDrawable deleted while actively reference by LLPipeline." << LL_ENDL; } } } @@ -1912,7 +2038,7 @@ void check_references(LLDrawable* drawable, LLFace* face) { if (drawable->getFace(i) == face) { - llerrs << "LLFace deleted while actively referenced by LLPipeline." << llendl; + LL_ERRS() << "LLFace deleted while actively referenced by LLPipeline." << LL_ENDL; } } } @@ -1921,9 +2047,12 @@ void check_references(LLSpatialGroup* group, LLFace* face) { for (LLSpatialGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i) { - LLDrawable* drawable = *i; + LLDrawable* drawable = (LLDrawable*)(*i)->getDrawable(); + if(drawable) + { check_references(drawable, face); - } + } +} } void LLPipeline::checkReferences(LLFace* face) @@ -1985,7 +2114,7 @@ void LLPipeline::checkReferences(LLDrawable* drawable) { if (drawable == *iter) { - llerrs << "LLDrawable deleted while actively referenced by LLPipeline." << llendl; + LL_ERRS() << "LLDrawable deleted while actively referenced by LLPipeline." << LL_ENDL; } } } @@ -2002,7 +2131,7 @@ void check_references(LLSpatialGroup* group, LLDrawInfo* draw_info) LLDrawInfo* params = *j; if (params == draw_info) { - llerrs << "LLDrawInfo deleted while actively referenced by LLPipeline." << llendl; + LL_ERRS() << "LLDrawInfo deleted while actively referenced by LLPipeline." << LL_ENDL; } } } @@ -2044,7 +2173,7 @@ void LLPipeline::checkReferences(LLSpatialGroup* group) { if (group == *iter) { - llerrs << "LLSpatialGroup deleted while actively referenced by LLPipeline." << llendl; + LL_ERRS() << "LLSpatialGroup deleted while actively referenced by LLPipeline." << LL_ENDL; } } @@ -2052,7 +2181,7 @@ void LLPipeline::checkReferences(LLSpatialGroup* group) { if (group == *iter) { - llerrs << "LLSpatialGroup deleted while actively referenced by LLPipeline." << llendl; + LL_ERRS() << "LLSpatialGroup deleted while actively referenced by LLPipeline." << LL_ENDL; } } @@ -2060,7 +2189,7 @@ void LLPipeline::checkReferences(LLSpatialGroup* group) { if (group == *iter) { - llerrs << "LLSpatialGroup deleted while actively referenced by LLPipeline." << llendl; + LL_ERRS() << "LLSpatialGroup deleted while actively referenced by LLPipeline." << LL_ENDL; } } } @@ -2101,7 +2230,7 @@ BOOL LLPipeline::getVisibleExtents(LLCamera& camera, LLVector3& min, LLVector3& min = LLVector3(X,X,X); max = LLVector3(-X,-X,-X); - U32 saved_camera_id = LLViewerCamera::sCurCameraID; + LLViewerCamera::eCameraID saved_camera_id = LLViewerCamera::sCurCameraID; LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD; BOOL res = TRUE; @@ -2132,11 +2261,11 @@ BOOL LLPipeline::getVisibleExtents(LLCamera& camera, LLVector3& min, LLVector3& return res; } -static LLFastTimer::DeclareTimer FTM_CULL("Object Culling"); +static LLTrace::BlockTimerStatHandle FTM_CULL("Object Culling"); void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_clip, LLPlane* planep) { - LLFastTimer t(FTM_CULL); + LL_RECORD_BLOCK_TIME(FTM_CULL); grabReferences(result); @@ -2145,8 +2274,7 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl BOOL to_texture = LLPipeline::sUseOcclusion > 1 && !hasRenderType(LLPipeline::RENDER_TYPE_HUD) && LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD && - gPipeline.canUseVertexShaders() && - sRenderGlow; + LLGLSLShader::sNoFixedFunction; if (to_texture) { @@ -2160,14 +2288,15 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl gGL.matrixMode(LLRender::MM_PROJECTION); gGL.pushMatrix(); - gGL.loadMatrix(gGLLastProjection); + gGL.loadMatrix(glh_get_last_projection()); gGL.matrixMode(LLRender::MM_MODELVIEW); gGL.pushMatrix(); gGLLastMatrix = NULL; - gGL.loadMatrix(gGLLastModelView); + gGL.loadMatrix(glh_get_last_modelview()); - LLGLDisable blend(GL_BLEND); - LLGLDisable test(GL_ALPHA_TEST); + LLGLDisable blend; + LLGLDisable test; + LLGLDisable stencil; gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); @@ -2198,14 +2327,14 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl } } - glh::matrix4f modelview = glh_get_last_modelview(); - glh::matrix4f proj = glh_get_last_projection(); + const LLMatrix4a& modelview = glh_get_last_modelview(); + const LLMatrix4a& proj = glh_get_last_projection(); LLGLUserClipPlane clip(plane, modelview, proj, water_clip != 0 && LLPipeline::sReflectionRender); LLGLDepthTest depth(GL_TRUE, GL_FALSE); bool bound_shader = false; - if (gPipeline.canUseVertexShaders() && LLGLSLShader::sCurBoundShader == 0) + if (LLGLSLShader::sNoFixedFunction && LLGLSLShader::sCurBoundShader == 0) { //if no shader is currently bound, use the occlusion shader instead of fixed function if we can // (shadow render uses a special shader that clamps to clip planes) bound_shader = true; @@ -2313,15 +2442,16 @@ void LLPipeline::markNotCulled(LLSpatialGroup* group, LLCamera& camera) return; } + const LLVector4a* bounds = group->getBounds(); if (sMinRenderSize > 0.f && - llmax(llmax(group->mBounds[1][0], group->mBounds[1][1]), group->mBounds[1][2]) < sMinRenderSize) + llmax(llmax(bounds[1][0], bounds[1][1]), bounds[1][2]) < sMinRenderSize) { return; } assertInitialized(); - if (!group->mSpatialPartition->mRenderByGroup) + if (!group->getSpatialPartition()->mRenderByGroup) { //render by drawable sCull->pushDrawableGroup(group); } @@ -2356,9 +2486,56 @@ void LLPipeline::markOccluder(LLSpatialGroup* group) } } +void LLPipeline::downsampleDepthBuffer(LLRenderTarget& source, LLRenderTarget& dest, LLRenderTarget* scratch_space) +{ + LLGLSLShader* last_shader = LLGLSLShader::sCurBoundShaderPtr; + + LLGLSLShader* shader = NULL; + + if (scratch_space) + { + scratch_space->copyContents(source, + 0, 0, source.getWidth(), source.getHeight(), + 0, 0, scratch_space->getWidth(), scratch_space->getHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST); + } + + dest.bindTarget(); + dest.clear(GL_DEPTH_BUFFER_BIT); + + shader = &gDownsampleDepthProgram; + shader->bind(); + shader->uniform2f(sDelta, 1.f/source.getWidth(), 1.f/source.getHeight()); + + gGL.getTexUnit(0)->bind(scratch_space ? scratch_space : &source, TRUE); + + { + LLGLDepthTest depth(GL_TRUE, GL_TRUE, GL_ALWAYS); + drawFullScreenRect(); + } + + dest.flush(); + + if (last_shader) + { + last_shader->bind(); + } + else + { + shader->unbind(); + } +} + +void LLPipeline::doOcclusion(LLCamera& camera, LLRenderTarget& source, LLRenderTarget& dest, LLRenderTarget* scratch_space) +{ + downsampleDepthBuffer(source, dest, scratch_space); + dest.bindTarget(); + doOcclusion(camera); + dest.flush(); +} + void LLPipeline::doOcclusion(LLCamera& camera) { - if (LLGLSLShader::sNoFixedFunction && LLPipeline::sUseOcclusion > 1 && sCull->hasOcclusionGroups()) + if (LLGLSLShader::sNoFixedFunction && LLPipeline::sUseOcclusion > 1 && !LLSpatialPartition::sTeleportRequested && sCull->hasOcclusionGroups()) { LLVertexBuffer::unbind(); @@ -2370,12 +2547,12 @@ void LLPipeline::doOcclusion(LLCamera& camera) { gGL.setColorMask(false, false); } - LLGLDisable blend(GL_BLEND); - LLGLDisable test(GL_ALPHA_TEST); + LLGLDisable blend; + LLGLDisable test; gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); LLGLDepthTest depth(GL_TRUE, GL_FALSE); - LLGLDisable cull(GL_CULL_FACE); + LLGLDisable cull; bool bind_shader = LLGLSLShader::sNoFixedFunction && LLGLSLShader::sCurBoundShader == 0; @@ -2426,19 +2603,18 @@ BOOL LLPipeline::updateDrawableGeom(LLDrawable* drawablep, BOOL priority) if (update_complete && assertInitialized()) { drawablep->setState(LLDrawable::BUILT); - mGeometryChanges++; } return update_complete; } -static LLFastTimer::DeclareTimer FTM_SEED_VBO_POOLS("Seed VBO Pool"); +static LLTrace::BlockTimerStatHandle FTM_SEED_VBO_POOLS("Seed VBO Pool"); -static LLFastTimer::DeclareTimer FTM_UPDATE_GL("Update GL"); +static LLTrace::BlockTimerStatHandle FTM_UPDATE_GL("Update GL"); void LLPipeline::updateGL() { { - LLFastTimer t(FTM_UPDATE_GL); + LL_RECORD_BLOCK_TIME(FTM_UPDATE_GL); while (!LLGLUpdate::sGLQ.empty()) { LLGLUpdate* glu = LLGLUpdate::sGLQ.front(); @@ -2449,7 +2625,7 @@ void LLPipeline::updateGL() } { //seed VBO Pools - LLFastTimer t(FTM_SEED_VBO_POOLS); + LL_RECORD_BLOCK_TIME(FTM_SEED_VBO_POOLS); LLVertexBuffer::seedPools(); } } @@ -2492,6 +2668,9 @@ void LLPipeline::clearRebuildGroups() iter != mGroupQ2.end(); ++iter) { LLSpatialGroup* group = *iter; + if (group == nullptr) { + LL_WARNS() << "Null spatial group in Pipeline::mGroupQ2." << LL_ENDL; + } // If the group contains HUD objects, save the group if (group->isHUDGroup()) @@ -2513,16 +2692,62 @@ void LLPipeline::clearRebuildGroups() mGroupQ2Locked = false; } -static LLFastTimer::DeclareTimer FTM_REBUILD_PRIORITY_GROUPS("Rebuild Priority Groups"); - -void LLPipeline::rebuildPriorityGroups() +void LLPipeline::clearRebuildDrawables() { - LLFastTimer t(FTM_REBUILD_PRIORITY_GROUPS); - LLTimer update_timer; - - assertInitialized(); - - gMeshRepo.notifyLoadedMeshes(); + // Clear all drawables on the priority build queue, + for (LLDrawable::drawable_list_t::iterator iter = mBuildQ1.begin(); + iter != mBuildQ1.end(); ++iter) + { + LLDrawable* drawablep = *iter; + if (drawablep && !drawablep->isDead()) + { + drawablep->clearState(LLDrawable::IN_REBUILD_Q2); + drawablep->clearState(LLDrawable::IN_REBUILD_Q1); + } + } + mBuildQ1.clear(); + + // clear drawables on the non-priority build queue + for (LLDrawable::drawable_list_t::iterator iter = mBuildQ2.begin(); + iter != mBuildQ2.end(); ++iter) + { + LLDrawable* drawablep = *iter; + if (!drawablep->isDead()) + { + drawablep->clearState(LLDrawable::IN_REBUILD_Q2); + } + } + mBuildQ2.clear(); + + //clear all moving bridges + for (LLDrawable::drawable_vector_t::iterator iter = mMovedBridge.begin(); + iter != mMovedBridge.end(); ++iter) + { + LLDrawable *drawablep = *iter; + drawablep->clearState(LLDrawable::EARLY_MOVE | LLDrawable::MOVE_UNDAMPED | LLDrawable::ON_MOVE_LIST | LLDrawable::ANIMATED_CHILD); + } + mMovedBridge.clear(); + + //clear all moving drawables + for (LLDrawable::drawable_vector_t::iterator iter = mMovedList.begin(); + iter != mMovedList.end(); ++iter) + { + LLDrawable *drawablep = *iter; + drawablep->clearState(LLDrawable::EARLY_MOVE | LLDrawable::MOVE_UNDAMPED | LLDrawable::ON_MOVE_LIST | LLDrawable::ANIMATED_CHILD); + } + mMovedList.clear(); +} + +static LLTrace::BlockTimerStatHandle FTM_REBUILD_PRIORITY_GROUPS("Rebuild Priority Groups"); + +void LLPipeline::rebuildPriorityGroups() +{ + LL_RECORD_BLOCK_TIME(FTM_REBUILD_PRIORITY_GROUPS); + LLTimer update_timer; + + assertInitialized(); + + gMeshRepo.notifyLoadedMeshes(); mGroupQ1Locked = true; // Iterate through all drawables on the priority build queue, @@ -2540,7 +2765,7 @@ void LLPipeline::rebuildPriorityGroups() } -static LLFastTimer::DeclareTimer FTM_REBUILD_GROUPS("Rebuild Groups"); +static LLTrace::BlockTimerStatHandle FTM_REBUILD_GROUPS("Rebuild Groups"); void LLPipeline::rebuildGroups() { @@ -2549,7 +2774,7 @@ void LLPipeline::rebuildGroups() return; } - LLFastTimer t(FTM_REBUILD_GROUPS); + LL_RECORD_BLOCK_TIME(FTM_REBUILD_GROUPS); mGroupQ2Locked = true; // Iterate through some drawables on the non-priority build queue S32 size = (S32) mGroupQ2.size(); @@ -2572,7 +2797,7 @@ void LLPipeline::rebuildGroups() { group->rebuildGeom(); - if (group->mSpatialPartition->mRenderByGroup) + if (group->getSpatialPartition()->mRenderByGroup) { count++; } @@ -2588,12 +2813,12 @@ void LLPipeline::rebuildGroups() updateMovedList(mMovedBridge); } -void LLPipeline::updateGeom(F32 max_dtime) +void LLPipeline::updateGeom(F32 max_dtime, LLCamera& camera) { LLTimer update_timer; LLPointer drawablep; - LLFastTimer t(FTM_GEO_UPDATE); + LL_RECORD_BLOCK_TIME(FTM_GEO_UPDATE); assertInitialized(); @@ -2628,6 +2853,11 @@ void LLPipeline::updateGeom(F32 max_dtime) } } + if (drawablep->isUnload()) + { + drawablep->unload(); + drawablep->clearState(LLDrawable::FOR_UNLOAD); + } if (updateDrawableGeom(drawablep, TRUE)) { drawablep->clearState(LLDrawable::IN_REBUILD_Q1); @@ -2650,7 +2880,7 @@ void LLPipeline::updateGeom(F32 max_dtime) S32 count = 0; - max_dtime = llmax(update_timer.getElapsedTimeF32()+0.001f, max_dtime); + max_dtime = llmax(update_timer.getElapsedTimeF32()+0.001f, F32SecondsImplicit(max_dtime)); LLSpatialGroup* last_group = NULL; LLSpatialBridge* last_bridge = NULL; @@ -2689,6 +2919,9 @@ void LLPipeline::updateGeom(F32 max_dtime) } updateMovedList(mMovedBridge); + calcNearbyLights(camera); + mLightMode = LIGHT_MODE_NORMAL; + setupHWLights(); } void LLPipeline::markVisible(LLDrawable *drawablep, LLCamera& camera) @@ -2738,13 +2971,13 @@ void LLPipeline::markMoved(LLDrawable *drawablep, BOOL damped_motion) { if (!drawablep) { - //llerrs << "Sending null drawable to moved list!" << llendl; + //LL_ERRS() << "Sending null drawable to moved list!" << LL_ENDL; return; } if (drawablep->isDead()) { - llwarns << "Marking NULL or dead drawable moved!" << llendl; + LL_WARNS() << "Marking NULL or dead drawable moved!" << LL_ENDL; return; } @@ -2799,14 +3032,15 @@ void LLPipeline::markShift(LLDrawable *drawablep) } } -static LLFastTimer::DeclareTimer FTM_SHIFT_DRAWABLE("Shift Drawable"); -static LLFastTimer::DeclareTimer FTM_SHIFT_OCTREE("Shift Octree"); -static LLFastTimer::DeclareTimer FTM_SHIFT_HUD("Shift HUD"); +static LLTrace::BlockTimerStatHandle FTM_SHIFT_DRAWABLE("Shift Drawable"); +static LLTrace::BlockTimerStatHandle FTM_SHIFT_OCTREE("Shift Octree"); +static LLTrace::BlockTimerStatHandle FTM_SHIFT_HUD("Shift HUD"); void LLPipeline::shiftObjects(const LLVector3 &offset) { assertInitialized(); + gGL.syncContextState(); glClear(GL_DEPTH_BUFFER_BIT); gDepthDirty = TRUE; @@ -2814,7 +3048,7 @@ void LLPipeline::shiftObjects(const LLVector3 &offset) offseta.load3(offset.mV); { - LLFastTimer t(FTM_SHIFT_DRAWABLE); + LL_RECORD_BLOCK_TIME(FTM_SHIFT_DRAWABLE); for (LLDrawable::drawable_vector_t::iterator iter = mShiftList.begin(); iter != mShiftList.end(); iter++) { @@ -2830,7 +3064,7 @@ void LLPipeline::shiftObjects(const LLVector3 &offset) } { - LLFastTimer t(FTM_SHIFT_OCTREE); + LL_RECORD_BLOCK_TIME(FTM_SHIFT_OCTREE); for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); iter != LLWorld::getInstance()->getRegionList().end(); ++iter) { @@ -2847,7 +3081,7 @@ void LLPipeline::shiftObjects(const LLVector3 &offset) } { - LLFastTimer t(FTM_SHIFT_HUD); + LL_RECORD_BLOCK_TIME(FTM_SHIFT_HUD); LLHUDText::shiftAll(offset); LLHUDNameTag::shiftAll(offset); } @@ -2881,10 +3115,10 @@ void LLPipeline::markPartitionMove(LLDrawable* drawable) } } -static LLFastTimer::DeclareTimer FTM_PROCESS_PARTITIONQ("PartitionQ"); +static LLTrace::BlockTimerStatHandle FTM_PROCESS_PARTITIONQ("PartitionQ"); void LLPipeline::processPartitionQ() { - LLFastTimer t(FTM_PROCESS_PARTITIONQ); + LL_RECORD_BLOCK_TIME(FTM_PROCESS_PARTITIONQ); for (LLDrawable::drawable_list_t::iterator iter = mPartitionQ.begin(); iter != mPartitionQ.end(); ++iter) { LLDrawable* drawable = *iter; @@ -2906,23 +3140,23 @@ void LLPipeline::markMeshDirty(LLSpatialGroup* group) void LLPipeline::markRebuild(LLSpatialGroup* group, BOOL priority) { - if (group && !group->isDead() && group->mSpatialPartition) + if (group && !group->isDead() && group->getSpatialPartition()) { - if (group->mSpatialPartition->mPartitionType == LLViewerRegion::PARTITION_HUD) + if (group->getSpatialPartition()->mPartitionType == LLViewerRegion::PARTITION_HUD) { priority = TRUE; } if (priority) { - if (!group->isState(LLSpatialGroup::IN_BUILD_Q1)) + if (!group->hasState(LLSpatialGroup::IN_BUILD_Q1)) { llassert_always(!mGroupQ1Locked); mGroupQ1.push_back(group); group->setState(LLSpatialGroup::IN_BUILD_Q1); - if (group->isState(LLSpatialGroup::IN_BUILD_Q2)) + if (group->hasState(LLSpatialGroup::IN_BUILD_Q2)) { LLSpatialGroup::sg_vector_t::iterator iter = std::find(mGroupQ2.begin(), mGroupQ2.end(), group); if (iter != mGroupQ2.end()) @@ -2933,13 +3167,13 @@ void LLPipeline::markRebuild(LLSpatialGroup* group, BOOL priority) } } } - else if (!group->isState(LLSpatialGroup::IN_BUILD_Q2 | LLSpatialGroup::IN_BUILD_Q1)) + else if (!group->hasState(LLSpatialGroup::IN_BUILD_Q2 | LLSpatialGroup::IN_BUILD_Q1)) { llassert_always(!mGroupQ2Locked); - //llerrs << "Non-priority updates not yet supported!" << llendl; + //LL_ERRS() << "Non-priority updates not yet supported!" << LL_ENDL; /*if (std::find(mGroupQ2.begin(), mGroupQ2.end(), group) != mGroupQ2.end()) { - llerrs << "WTF?" << llendl; + LL_ERRS() << "WTF?" << LL_ENDL; }*/ mGroupQ2.push_back(group); group->setState(LLSpatialGroup::IN_BUILD_Q2); @@ -2977,7 +3211,7 @@ void LLPipeline::markRebuild(LLDrawable *drawablep, LLDrawable::EDrawableFlags f } } -static LLFastTimer::DeclareTimer FTM_RESET_DRAWORDER("Reset Draw Order"); +static LLTrace::BlockTimerStatHandle FTM_RESET_DRAWORDER("Reset Draw Order"); void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result) { @@ -2991,11 +3225,11 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result) LLPipeline::END_RENDER_TYPES)) { //clear faces from face pools - LLFastTimer t(FTM_RESET_DRAWORDER); + LL_RECORD_BLOCK_TIME(FTM_RESET_DRAWORDER); gPipeline.resetDrawOrders(); } - LLFastTimer ftm(FTM_STATESORT); + LL_RECORD_BLOCK_TIME(FTM_STATESORT); //LLVertexBuffer::unbind(); @@ -3011,10 +3245,10 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result) else { group->setVisible(); - OctreeGuard guard(group->mOctreeNode); + OctreeGuard guard(group->getOctreeNode()); for (LLSpatialGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i) { - markVisible(*i, camera); + markVisible((LLDrawable*)(*i)->getDrawable(), camera); } if (!sDelayVBUpdate) @@ -3080,7 +3314,7 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result) } { - LLFastTimer ftm(FTM_STATESORT_DRAWABLE); + LL_RECORD_BLOCK_TIME(FTM_STATESORT_DRAWABLE); for (LLCullResult::drawable_iterator iter = sCull->beginVisibleList(); iter != sCull->endVisibleList(); ++iter) { @@ -3099,10 +3333,10 @@ void LLPipeline::stateSort(LLSpatialGroup* group, LLCamera& camera) { if (!sSkipUpdate && group->changeLOD()) { - OctreeGuard guard(group->mOctreeNode); + OctreeGuard guard(group->getOctreeNode()); for (LLSpatialGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i) { - LLDrawable* drawablep = *i; + LLDrawable* drawablep = (LLDrawable*)(*i)->getDrawable(); stateSort(drawablep, camera); } @@ -3216,9 +3450,6 @@ void LLPipeline::stateSort(LLDrawable* drawablep, LLCamera& camera) } } } - - - mNumVisibleFaces += drawablep->getNumFaces(); } @@ -3228,10 +3459,11 @@ void forAllDrawables(LLCullResult::sg_iterator begin, { for (LLCullResult::sg_iterator i = begin; i != end; ++i) { - OctreeGuard guard((*i)->mOctreeNode); - for (LLSpatialGroup::element_iter j = (*i)->getDataBegin(); j != (*i)->getDataEnd(); ++j) + LLSpatialGroup* group = (*i).get(); + OctreeGuard guard(group->getOctreeNode()); + for (LLSpatialGroup::element_iter j = group->getDataBegin(); j != group->getDataEnd(); ++j) { - func(*j); + func((LLDrawable*)(*j)->getDrawable()); } } } @@ -3431,11 +3663,11 @@ void updateParticleActivity(LLDrawable *drawablep); void LLPipeline::postSort(LLCamera& camera) { - LLFastTimer ftm(FTM_STATESORT_POSTSORT); + LL_RECORD_BLOCK_TIME(FTM_STATESORT_POSTSORT); assertInitialized(); - llpushcallstacks ; + LL_PUSH_CALLSTACKS(); //rebuild drawable geometry for (LLCullResult::sg_iterator i = sCull->beginDrawableGroups(); i != sCull->endDrawableGroups(); ++i) { @@ -3446,12 +3678,12 @@ void LLPipeline::postSort(LLCamera& camera) group->rebuildGeom(); } } - llpushcallstacks ; + LL_PUSH_CALLSTACKS(); //rebuild groups sCull->assertDrawMapsEmpty(); rebuildPriorityGroups(); - llpushcallstacks ; + LL_PUSH_CALLSTACKS(); //build render map @@ -3468,7 +3700,7 @@ void LLPipeline::postSort(LLCamera& camera) continue; } - if (group->isState(LLSpatialGroup::NEW_DRAWINFO) && group->isState(LLSpatialGroup::GEOM_DIRTY)) + if (group->hasState(LLSpatialGroup::NEW_DRAWINFO) && group->hasState(LLSpatialGroup::GEOM_DIRTY)) { //no way this group is going to be drawable without a rebuild group->rebuildGeom(); } @@ -3506,7 +3738,7 @@ void LLPipeline::postSort(LLCamera& camera) if (alpha != group->mDrawMap.end()) { //store alpha groups for sorting - LLSpatialBridge* bridge = group->mSpatialPartition->asBridge(); + LLSpatialBridge* bridge = group->getSpatialPartition()->asBridge(); if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD) { if (bridge) @@ -3562,7 +3794,7 @@ void LLPipeline::postSort(LLCamera& camera) std::sort(sCull->beginAlphaGroups(), sCull->endAlphaGroups(), LLSpatialGroup::CompareDepthGreater()); } - llpushcallstacks ; + LL_PUSH_CALLSTACKS(); forAllVisibleDrawables(updateParticleActivity); //for llfloateravatarlist @@ -3647,7 +3879,7 @@ void LLPipeline::postSort(LLCamera& camera) forAllVisibleDrawables(renderSoundHighlights); } } - llpushcallstacks ; + LL_PUSH_CALLSTACKS(); // If managing your telehub, draw beacons at telehub and currently selected spawnpoint. if (LLFloaterTelehub::renderBeacons()) { @@ -3658,6 +3890,8 @@ void LLPipeline::postSort(LLCamera& camera) { mSelectedFaces.clear(); + LLPipeline::setRenderHighlightTextureChannel(gFloaterTools->getPanelFace()->getTextureChannelToEdit()); + // Draw face highlights for selected faces. if (LLSelectMgr::getInstance()->getTEMode()) { @@ -3681,19 +3915,18 @@ void LLPipeline::postSort(LLCamera& camera) } //LLSpatialGroup::sNoDelete = FALSE; - llpushcallstacks ; + LL_PUSH_CALLSTACKS(); } void render_hud_elements() { - LLFastTimer t(FTM_RENDER_UI); - gPipeline.disableLights(); + LL_RECORD_BLOCK_TIME(FTM_RENDER_UI); - LLGLDisable fog(GL_FOG); + LLGLDisable fog; LLGLSUIDefault gls_ui; - LLGLEnable stencil(GL_STENCIL_TEST); + LLGLEnable stencil; glStencilFunc(GL_ALWAYS, 255, 0xFFFFFFFF); glStencilMask(0xFFFFFFFF); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); @@ -3709,7 +3942,7 @@ void render_hud_elements() if (!LLPipeline::sReflectionRender && gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI)) { static const LLCachedControl RenderFSAASamples("RenderFSAASamples",0); - LLGLEnable multisample(RenderFSAASamples > 0 ? GL_MULTISAMPLE_ARB : 0); + LLGLEnable multisample(RenderFSAASamples > 0); gViewerWindow->renderSelections(FALSE, FALSE, FALSE); // For HUD version in render_ui_3d() // Draw the tracking overlays @@ -3740,67 +3973,100 @@ void render_hud_elements() gGL.flush(); } -void LLPipeline::renderHighlights() +// Singu Note: Created to avoid redundant code. +void renderSelectedFaces(LLGLSLShader& shader, std::vector &selected_faces, LLViewerTexture* tex, LLColor4 color, LLRender::eTexIndex channel, LLRender::eTexIndex active_channel = LLRender::NUM_TEXTURE_CHANNELS) { - assertInitialized(); - - // Draw 3D UI elements here (before we clear the Z buffer in POOL_HUD) - // Render highlighted faces. - LLGLSPipelineAlpha gls_pipeline_alpha; - LLColor4 color(1.f, 1.f, 1.f, 0.5f); - LLGLEnable color_mat(GL_COLOR_MATERIAL); - disableLights(); - if ((LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_INTERFACE) > 0)) { - gHighlightProgram.bind(); - gGL.diffuseColor4f(1,1,1,0.5f); + shader.bind(); } + + bool active = active_channel == LLRender::NUM_TEXTURE_CHANNELS || channel == active_channel; - if (hasRenderDebugFeatureMask(RENDER_DEBUG_FEATURE_SELECTED)) + if(!active) //Draw 'faded out' overlay for selected faces that aren't applicable to current channel being edited. + color.mV[3] *= .5f; + + for (std::vector::iterator it = selected_faces.begin(); it != selected_faces.end(); ++it) { - // Make sure the selection image gets downloaded and decoded - if (!mFaceSelectImagep) + LLFace *facep = *it; + if (!facep || facep->getDrawable()->isDead()) { - mFaceSelectImagep = LLViewerTextureManager::getFetchedTexture(IMG_FACE_SELECT); + LL_ERRS() << "Bad face on selection" << LL_ENDL; + return; } - mFaceSelectImagep->addTextureStats((F32)MAX_IMAGE_AREA); - U32 count = mSelectedFaces.size(); - for (U32 i = 0; i < count; i++) + const LLTextureEntry* te = facep->getTextureEntry(); + LLMaterial* mat = te ? te->getMaterialParams().get() : NULL; + + if(channel == LLRender::DIFFUSE_MAP) { - LLFace *facep = mSelectedFaces[i]; - if (!facep || facep->getDrawable()->isDead()) - { - llerrs << "Bad face on selection" << llendl; - return; - } - - facep->renderSelected(mFaceSelectImagep, color); + if(active || !mat || + (active_channel == LLRender::NORMAL_MAP && mat->getNormalID().isNull()) || + (active_channel == LLRender::SPECULAR_MAP && mat->getSpecularID().isNull())) + facep->renderSelected(tex, color); + } + else if(channel == LLRender::NORMAL_MAP) + { + if(mat && mat->getNormalID().notNull()) + facep->renderSelected(tex, color); + } + else if(channel == LLRender::SPECULAR_MAP) + { + if(mat && mat->getSpecularID().notNull()) + facep->renderSelected(tex, color); } } - if (hasRenderDebugFeatureMask(RENDER_DEBUG_FEATURE_SELECTED)) + if ((LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_INTERFACE) > 0)) { - // Paint 'em red! - color.setVec(1.f, 0.f, 0.f, 0.5f); - - int count = mHighlightFaces.size(); - for (S32 i = 0; i < count; i++) - { - LLFace* facep = mHighlightFaces[i]; - facep->renderSelected(LLViewerTexture::sNullImagep, color); - } + shader.unbind(); } +} +void LLPipeline::renderHighlights() +{ + assertInitialized(); - // Contains a list of the faces of objects that are physical or - // have touch-handlers. - mHighlightFaces.clear(); + if(!hasRenderDebugFeatureMask(RENDER_DEBUG_FEATURE_SELECTED)) + return; //Nothing to draw... - if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_INTERFACE) > 0) + // Setup + if ( !mFaceSelectImagep) { - gHighlightProgram.unbind(); + mFaceSelectImagep = LLViewerTextureManager::getFetchedTexture(IMG_FACE_SELECT); } + + // Make sure the selection image gets downloaded and decoded + mFaceSelectImagep->addTextureStats((F32)MAX_IMAGE_AREA); + + // Draw 3D UI elements here (before we clear the Z buffer in POOL_HUD) + // Render highlighted faces. + LLGLSPipelineAlpha gls_pipeline_alpha; + LLGLEnable color_mat; + LLGLState light_state; + gPipeline.disableLights(light_state); + + // Singu Note: Logic here changed, and behavior changed as well. Always draw overlays of some nature over all selected faces. + // Faces that wont undergo any change if the current active channel is edited should have a 'faded' overlay + + // Temporary. If not deferred, then texcoord1 and texcoord2 are probably absent from face vbo, which LLFace::renderSelected piggybacks. + // Force to standard diffuse mode. Workaround would probably be to generate new face vbo data on the fly if required texcoord data is absent. + LLRender::eTexIndex active_channel = LLPipeline::sRenderDeferred ? sRenderHighlightTextureChannel : LLRender::NUM_TEXTURE_CHANNELS; + + // Default diffuse mapping + renderSelectedFaces(gHighlightProgram, mSelectedFaces, mFaceSelectImagep, LLColor4(1.f,1.f,1.f,.5f), LLRender::DIFFUSE_MAP, active_channel); + + // Paint 'em red! + renderSelectedFaces(gHighlightProgram, mHighlightFaces, LLViewerTexture::sNullImagep, LLColor4(1.f,0.f,0.f,.5f), LLRender::DIFFUSE_MAP); + + // Normal mapping + if(active_channel == LLRender::NORMAL_MAP) + renderSelectedFaces(gHighlightNormalProgram, mSelectedFaces, mFaceSelectImagep, LLColor4(1.f, .5f, .5f, .5f), LLRender::NORMAL_MAP); + + // Specular mapping + if(active_channel == LLRender::SPECULAR_MAP) + renderSelectedFaces(gHighlightSpecularProgram, mSelectedFaces, mFaceSelectImagep, LLColor4(0.f, .3f, 1.f, .8f), LLRender::SPECULAR_MAP); + + mHighlightFaces.clear(); } //debug use @@ -3809,21 +4075,18 @@ U32 LLPipeline::sCurRenderPoolType = 0 ; extern void check_blend_funcs(); void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate) { - LLFastTimer t(FTM_RENDER_GEOMETRY); + LL_RECORD_BLOCK_TIME(FTM_RENDER_GEOMETRY); assertInitialized(); - F32 saved_modelview[16]; - F32 saved_projection[16]; + LLMatrix4a saved_modelview; + LLMatrix4a saved_projection; //HACK: preserve/restore matrices around HUD render if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD)) { - for (U32 i = 0; i < 16; i++) - { - saved_modelview[i] = gGLModelView[i]; - saved_projection[i] = gGLProjection[i]; - } + saved_modelview = glh_get_current_modelview(); + saved_projection = glh_get_current_projection(); } /////////////////////////////////////////// @@ -3838,14 +4101,14 @@ void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate) LLVertexBuffer::unbind(); // Do verification of GL state - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - LLGLState::checkClientArrays(); + LLGLStateValidator::checkStates(); + LLGLStateValidator::checkTextureChannels(); + LLGLStateValidator::checkClientArrays(); if (mRenderDebugMask & RENDER_DEBUG_VERIFY) { if (!verify()) { - llerrs << "Pipeline verification failed!" << llendl; + LL_ERRS() << "Pipeline verification failed!" << LL_ENDL; } } @@ -3861,21 +4124,17 @@ void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate) LLGLSPipeline gls_pipeline; static const LLCachedControl RenderFSAASamples("RenderFSAASamples",0); - LLGLEnable multisample(RenderFSAASamples > 0 ? GL_MULTISAMPLE_ARB : 0); + LLGLEnable multisample(RenderFSAASamples > 0); - LLGLState gls_color_material(GL_COLOR_MATERIAL, mLightingDetail < 2); + LLGLEnable gls_color_material; // Toggle backface culling for debugging - LLGLEnable cull_face(mBackfaceCull ? GL_CULL_FACE : 0); - // Set fog + LLGLEnable cull_face(mBackfaceCull); + + // Set fog only if not using shaders and is underwater render. BOOL use_fog = hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_FOG); - LLGLEnable fog_enable(use_fog && - !gPipeline.canUseWindLightShadersOnObjects() ? GL_FOG : 0); + LLGLEnable fog_enable(use_fog && sUnderWaterRender && !LLGLSLShader::sNoFixedFunction); gSky.updateFog(camera.getFar()); - if (!use_fog) - { - sUnderWaterRender = FALSE; - } gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sDefaultImagep); LLViewerFetchedTexture::sDefaultImagep->setAddressMode(LLTexUnit::TAM_WRAP); @@ -3899,15 +4158,15 @@ void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate) } { - LLFastTimer t(FTM_POOLS); + LL_RECORD_BLOCK_TIME(FTM_POOLS); // HACK: don't calculate local lights if we're rendering the HUD! // Removing this check will cause bad flickering when there are // HUD elements being rendered AND the user is in flycam mode -nyx if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD)) { - calcNearbyLights(camera); - setupHWLights(NULL); + updateHWLightMode(LIGHT_MODE_NORMAL); + llassert(LLGLState::checkEnabled()); } BOOL occlude = sUseOcclusion > 1; @@ -3927,7 +4186,7 @@ void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate) { occlude = FALSE; gGLLastMatrix = NULL; - gGL.loadMatrix(gGLModelView); + gGL.loadMatrix(glh_get_current_modelview()); LLGLSLShader::bindNoShader(); doOcclusion(camera); } @@ -3935,15 +4194,16 @@ void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate) pool_set_t::iterator iter2 = iter1; if (hasRenderType(poolp->getType()) && poolp->getNumPasses() > 0) { - LLFastTimer t(FTM_POOLRENDER); + LL_RECORD_BLOCK_TIME(FTM_POOLRENDER); gGLLastMatrix = NULL; - gGL.loadMatrix(gGLModelView); + gGL.loadMatrix(glh_get_current_modelview()); for( S32 i = 0; i < poolp->getNumPasses(); i++ ) { LLVertexBuffer::unbind(); if(gDebugGL)check_blend_funcs(); + mInRenderPass = true; poolp->beginRenderPass(i); for (iter2 = iter1; iter2 != mPools.end(); iter2++) { @@ -3955,14 +4215,15 @@ void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate) p->render(i); } poolp->endRenderPass(i); + clearRenderPassStates(); if(gDebugGL)check_blend_funcs(); LLVertexBuffer::unbind(); if (gDebugGL) { std::string msg = llformat("%s pass %d", gPoolNames[cur_type].c_str(), i); - LLGLState::checkStates(msg); - //LLGLState::checkTextureChannels(msg); - //LLGLState::checkClientArrays(msg); + LLGLStateValidator::checkStates(msg); + //LLGLStateValidator::checkTextureChannels(msg); + //LLGLStateValidator::checkClientArrays(msg); } } } @@ -3987,30 +4248,30 @@ void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate) LLVertexBuffer::unbind(); gGLLastMatrix = NULL; - gGL.loadMatrix(gGLModelView); + gGL.loadMatrix(glh_get_current_modelview()); if (occlude) { occlude = FALSE; gGLLastMatrix = NULL; - gGL.loadMatrix(gGLModelView); + gGL.loadMatrix(glh_get_current_modelview()); LLGLSLShader::bindNoShader(); doOcclusion(camera); } } LLVertexBuffer::unbind(); - LLGLState::checkStates(); - //LLGLState::checkTextureChannels(); - //LLGLState::checkClientArrays(); + LLGLStateValidator::checkStates(); + //LLGLStateValidator::checkTextureChannels(); + //LLGLStateValidator::checkClientArrays(); //stop_glerror(); - //LLGLState::checkStates(); - //LLGLState::checkTextureChannels(); - //LLGLState::checkClientArrays(); + //LLGLStateValidator::checkStates(); + //LLGLStateValidator::checkTextureChannels(); + //LLGLStateValidator::checkClientArrays(); if (!LLPipeline::sImpostorRender) { @@ -4056,31 +4317,28 @@ void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate) //HACK: preserve/restore matrices around HUD render if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD)) { - for (U32 i = 0; i < 16; i++) - { - gGLModelView[i] = saved_modelview[i]; - gGLProjection[i] = saved_projection[i]; - } + glh_set_current_modelview(saved_modelview); + glh_set_current_projection(saved_projection); } } LLVertexBuffer::unbind(); - LLGLState::checkStates(); - //LLGLState::checkTextureChannels(); - //LLGLState::checkClientArrays(); + LLGLStateValidator::checkStates(); + //LLGLStateValidator::checkTextureChannels(); + //LLGLStateValidator::checkClientArrays(); } void LLPipeline::renderGeomDeferred(LLCamera& camera) { LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderGeomDeferred"); - LLFastTimer t(FTM_RENDER_GEOMETRY); + LL_RECORD_BLOCK_TIME(FTM_RENDER_GEOMETRY); - LLFastTimer t2(FTM_DEFERRED_POOLS); + LL_RECORD_BLOCK_TIME(FTM_DEFERRED_POOLS); - LLGLEnable cull(GL_CULL_FACE); + LLGLEnable cull; - LLGLEnable stencil(GL_STENCIL_TEST); + LLGLEnable stencil; glStencilFunc(GL_ALWAYS, 1, 0xFFFFFFFF); stop_glerror(); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); @@ -4095,14 +4353,14 @@ void LLPipeline::renderGeomDeferred(LLCamera& camera) } } - static const LLCachedControl fsaa_samples("RenderFSAASamples",0); - LLGLEnable multisample(fsaa_samples > 0 ? GL_MULTISAMPLE_ARB : 0); + static const LLCachedControl RenderFSAASamples("RenderFSAASamples",0); + LLGLEnable multisample(RenderFSAASamples > 0); LLVertexBuffer::unbind(); - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - LLGLState::checkClientArrays(); + //LLGLStateValidator::checkStates(); + //LLGLStateValidator::checkTextureChannels(); + //LLGLStateValidator::checkClientArrays(); U32 cur_type = 0; @@ -4119,14 +4377,15 @@ void LLPipeline::renderGeomDeferred(LLCamera& camera) pool_set_t::iterator iter2 = iter1; if (hasRenderType(poolp->getType()) && poolp->getNumDeferredPasses() > 0) { - LLFastTimer t(FTM_DEFERRED_POOLRENDER); + LL_RECORD_BLOCK_TIME(FTM_DEFERRED_POOLRENDER); gGLLastMatrix = NULL; - gGL.loadMatrix(gGLModelView); + gGL.loadMatrix(glh_get_current_modelview()); for( S32 i = 0; i < poolp->getNumDeferredPasses(); i++ ) { LLVertexBuffer::unbind(); + mInRenderPass = true; poolp->beginDeferredPass(i); for (iter2 = iter1; iter2 != mPools.end(); iter2++) { @@ -4139,13 +4398,14 @@ void LLPipeline::renderGeomDeferred(LLCamera& camera) p->renderDeferred(i); } poolp->endDeferredPass(i); + clearRenderPassStates(); LLVertexBuffer::unbind(); if (gDebugGL || gDebugPipeline) { - LLGLState::checkStates(); - //LLGLState::checkTextureChannels(); - //LLGLState::checkClientArrays(); + LLGLStateValidator::checkStates(); + //LLGLStateValidator::checkTextureChannels(); + //LLGLStateValidator::checkClientArrays(); } } } @@ -4166,28 +4426,27 @@ void LLPipeline::renderGeomDeferred(LLCamera& camera) } gGLLastMatrix = NULL; - gGL.loadMatrix(gGLModelView); + gGL.loadMatrix(glh_get_current_modelview()); gGL.setColorMask(true, false); } -void LLPipeline::renderGeomPostDeferred(LLCamera& camera) +void LLPipeline::renderGeomPostDeferred(LLCamera& camera, bool do_occlusion) { - LLFastTimer t(FTM_POST_DEFERRED_POOLS); + LL_RECORD_BLOCK_TIME(FTM_POST_DEFERRED_POOLS); U32 cur_type = 0; - LLGLEnable cull(GL_CULL_FACE); + LLGLEnable cull; static const LLCachedControl RenderFSAASamples("RenderFSAASamples",0); - LLGLEnable multisample(RenderFSAASamples > 0 ? GL_MULTISAMPLE_ARB : 0); + LLGLEnable multisample(RenderFSAASamples > 0); - calcNearbyLights(camera); - setupHWLights(NULL); + updateHWLightMode(LIGHT_MODE_NORMAL); gGL.setColorMask(true, false); pool_set_t::iterator iter1 = mPools.begin(); - BOOL occlude = LLPipeline::sUseOcclusion > 1; + BOOL occlude = LLPipeline::sUseOcclusion > 1 && do_occlusion; while ( iter1 != mPools.end() ) { @@ -4199,7 +4458,7 @@ void LLPipeline::renderGeomPostDeferred(LLCamera& camera) { occlude = FALSE; gGLLastMatrix = NULL; - gGL.loadMatrix(gGLModelView); + gGL.loadMatrix(glh_get_current_modelview()); LLGLSLShader::bindNoShader(); doOcclusion(camera); gGL.setColorMask(true, false); @@ -4208,14 +4467,15 @@ void LLPipeline::renderGeomPostDeferred(LLCamera& camera) pool_set_t::iterator iter2 = iter1; if (hasRenderType(poolp->getType()) && poolp->getNumPostDeferredPasses() > 0) { - LLFastTimer t(FTM_POST_DEFERRED_POOLRENDER); + LL_RECORD_BLOCK_TIME(FTM_POST_DEFERRED_POOLRENDER); gGLLastMatrix = NULL; - gGL.loadMatrix(gGLModelView); + gGL.loadMatrix(glh_get_current_modelview()); for( S32 i = 0; i < poolp->getNumPostDeferredPasses(); i++ ) { LLVertexBuffer::unbind(); + mInRenderPass = true; poolp->beginPostDeferredPass(i); for (iter2 = iter1; iter2 != mPools.end(); iter2++) { @@ -4228,11 +4488,12 @@ void LLPipeline::renderGeomPostDeferred(LLCamera& camera) p->renderPostDeferred(i); } poolp->endPostDeferredPass(i); + clearRenderPassStates(); LLVertexBuffer::unbind(); if (gDebugGL || gDebugPipeline) { - LLGLState::checkStates(); + LLGLStateValidator::checkStates(); } } } @@ -4253,17 +4514,17 @@ void LLPipeline::renderGeomPostDeferred(LLCamera& camera) } gGLLastMatrix = NULL; - gGL.loadMatrix(gGLModelView); + gGL.loadMatrix(glh_get_current_modelview()); if (occlude) { occlude = FALSE; gGLLastMatrix = NULL; - gGL.loadMatrix(gGLModelView); + gGL.loadMatrix(glh_get_current_modelview()); LLGLSLShader::bindNoShader(); doOcclusion(camera); gGLLastMatrix = NULL; - gGL.loadMatrix(gGLModelView); + gGL.loadMatrix(glh_get_current_modelview()); } } @@ -4271,7 +4532,7 @@ void LLPipeline::renderGeomShadow(LLCamera& camera) { U32 cur_type = 0; - LLGLEnable cull(GL_CULL_FACE); + LLGLEnable cull; LLVertexBuffer::unbind(); @@ -4289,11 +4550,12 @@ void LLPipeline::renderGeomShadow(LLCamera& camera) poolp->prerender() ; gGLLastMatrix = NULL; - gGL.loadMatrix(gGLModelView); + gGL.loadMatrix(glh_get_current_modelview()); for( S32 i = 0; i < poolp->getNumShadowPasses(); i++ ) { LLVertexBuffer::unbind(); + mInRenderPass = true; poolp->beginShadowPass(i); for (iter2 = iter1; iter2 != mPools.end(); iter2++) { @@ -4306,9 +4568,10 @@ void LLPipeline::renderGeomShadow(LLCamera& camera) p->renderShadow(i); } poolp->endShadowPass(i); + clearRenderPassStates(); LLVertexBuffer::unbind(); - LLGLState::checkStates(); + LLGLStateValidator::checkStates(); } } else @@ -4328,7 +4591,7 @@ void LLPipeline::renderGeomShadow(LLCamera& camera) } gGLLastMatrix = NULL; - gGL.loadMatrix(gGLModelView); + gGL.loadMatrix(glh_get_current_modelview()); } @@ -4397,18 +4660,6 @@ void LLPipeline::renderPhysicsDisplay() } } - for (LLCullResult::bridge_iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i) - { - LLSpatialBridge* bridge = *i; - if (!bridge->isDead() && hasRenderType(bridge->mDrawableType)) - { - gGL.pushMatrix(); - gGL.multMatrix((F32*)bridge->mDrawable->getRenderMatrix().mMatrix); - bridge->renderPhysicsShapes(); - gGL.popMatrix(); - } - } - gGL.flush(); if (LLGLSLShader::sNoFixedFunction) @@ -4428,7 +4679,7 @@ void LLPipeline::renderDebug() gGL.color4f(1,1,1,1); gGLLastMatrix = NULL; - gGL.loadMatrix(gGLModelView); + gGL.loadMatrix(glh_get_current_modelview()); gGL.setColorMask(true, false); bool hud_only = hasRenderType(LLPipeline::RENDER_TYPE_HUD); @@ -4441,7 +4692,7 @@ void LLPipeline::renderDebug() gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep, true); - glPointSize(8.f); + gGL.setPointSize(8.f); LLGLDepthTest depth(GL_TRUE, GL_TRUE, GL_ALWAYS); gGL.begin(LLRender::POINTS); @@ -4465,8 +4716,7 @@ void LLPipeline::renderDebug() gGL.vertex3fv(blip.mPosition.mV); } gGL.end(); - gGL.flush(); - glPointSize(1.f); + gGL.setPointSize(1.f); if (LLGLSLShader::sNoFixedFunction) { @@ -4478,6 +4728,8 @@ void LLPipeline::renderDebug() if(!mRenderDebugMask) return; + LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE, GL_LEQUAL); + // Debug stuff. for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); iter != LLWorld::getInstance()->getRegionList().end(); ++iter) @@ -4488,8 +4740,8 @@ void LLPipeline::renderDebug() LLSpatialPartition* part = region->getSpatialPartition(i); if (part) { - if ( hud_only && (part->mDrawableType == RENDER_TYPE_HUD || part->mDrawableType == RENDER_TYPE_HUD_PARTICLES) || - !hud_only && hasRenderType(part->mDrawableType) ) + if ( (hud_only && (part->mDrawableType == RENDER_TYPE_HUD || part->mDrawableType == RENDER_TYPE_HUD_PARTICLES)) || + (!hud_only && hasRenderType(part->mDrawableType)) ) { part->renderDebug(); } @@ -4503,7 +4755,7 @@ void LLPipeline::renderDebug() if (!bridge->isDead() && hasRenderType(bridge->mDrawableType)) { gGL.pushMatrix(); - gGL.multMatrix((F32*)bridge->mDrawable->getRenderMatrix().mMatrix); + gGL.multMatrix(bridge->mDrawable->getRenderMatrix()); bridge->renderDebug(); gGL.popMatrix(); } @@ -4518,9 +4770,9 @@ void LLPipeline::renderDebug() { LLVertexBuffer::unbind(); - LLGLEnable blend(GL_BLEND); + LLGLEnable blend; LLGLDepthTest depth(TRUE, FALSE); - LLGLDisable cull(GL_CULL_FACE); + LLGLDisable cull; gGL.color4f(1,1,1,1); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); @@ -4584,8 +4836,7 @@ void LLPipeline::renderDebug() //if (i == 0 || !mShadowFrustPoints[i].empty()) { //render visible point cloud - gGL.flush(); - glPointSize(8.f); + gGL.setPointSize(8.f); gGL.begin(LLRender::POINTS); F32* c = col+i*4; @@ -4598,8 +4849,7 @@ void LLPipeline::renderDebug() } gGL.end(); - gGL.flush(); - glPointSize(1.f); + gGL.setPointSize(1.f); LLVector3* ext = mShadowExtents[i]; LLVector3 pos = (ext[0]+ext[1])*0.5f; @@ -4692,13 +4942,13 @@ void LLPipeline::renderDebug() LLColor4 col; LLVertexBuffer::unbind(); - LLGLEnable blend(GL_BLEND); + LLGLEnable blend; gGL.setSceneBlendType(LLRender::BT_ALPHA); LLGLDepthTest depth(GL_TRUE, GL_FALSE); gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep); gGL.pushMatrix(); - gGL.loadMatrix(gGLModelView); + gGL.loadMatrix(glh_get_current_modelview()); gGLLastMatrix = NULL; for (LLSpatialGroup::sg_vector_t::iterator iter = mGroupQ2.begin(); iter != mGroupQ2.end(); ++iter) @@ -4709,7 +4959,7 @@ void LLPipeline::renderDebug() continue; } - LLSpatialBridge* bridge = group->mSpatialPartition->asBridge(); + LLSpatialBridge* bridge = group->getSpatialPartition()->asBridge(); if (bridge && (!bridge->mDrawable || bridge->mDrawable->isDead())) { @@ -4719,7 +4969,7 @@ void LLPipeline::renderDebug() if (bridge) { gGL.pushMatrix(); - gGL.multMatrix((F32*)bridge->mDrawable->getRenderMatrix().mMatrix); + gGL.multMatrix(bridge->mDrawable->getRenderMatrix()); } F32 alpha = llclamp((F32) (size-count)/size, 0.f, 1.f); @@ -4749,11 +4999,11 @@ void LLPipeline::renderDebug() } } -static LLFastTimer::DeclareTimer FTM_REBUILD_POOLS("Rebuild Pools"); +static LLTrace::BlockTimerStatHandle FTM_REBUILD_POOLS("Rebuild Pools"); void LLPipeline::rebuildPools() { - LLFastTimer t(FTM_REBUILD_POOLS); + LL_RECORD_BLOCK_TIME(FTM_REBUILD_POOLS); assertInitialized(); @@ -4796,7 +5046,7 @@ void LLPipeline::addToQuickLookup( LLDrawPool* new_poolp ) if (mSimplePool) { llassert(0); - llwarns << "Ignoring duplicate simple pool." << llendl; + LL_WARNS() << "Ignoring duplicate simple pool." << LL_ENDL; } else { @@ -4804,39 +5054,53 @@ void LLPipeline::addToQuickLookup( LLDrawPool* new_poolp ) } break; - case LLDrawPool::POOL_GRASS: - if (mGrassPool) + case LLDrawPool::POOL_ALPHA_MASK: + if (mAlphaMaskPool) { llassert(0); - llwarns << "Ignoring duplicate grass pool." << llendl; + LL_WARNS() << "Ignoring duplicate alpha mask pool." << LL_ENDL; + break; } else { - mGrassPool = (LLRenderPass*) new_poolp; + mAlphaMaskPool = (LLRenderPass*) new_poolp; } break; - case LLDrawPool::POOL_FULLBRIGHT: - if (mFullbrightPool) + case LLDrawPool::POOL_FULLBRIGHT_ALPHA_MASK: + if (mFullbrightAlphaMaskPool) { llassert(0); - llwarns << "Ignoring duplicate simple pool." << llendl; + LL_WARNS() << "Ignoring duplicate alpha mask pool." << LL_ENDL; + break; } else { - mFullbrightPool = (LLRenderPass*) new_poolp; + mFullbrightAlphaMaskPool = (LLRenderPass*) new_poolp; + } + break; + + case LLDrawPool::POOL_GRASS: + if (mGrassPool) + { + llassert(0); + LL_WARNS() << "Ignoring duplicate grass pool." << LL_ENDL; + } + else + { + mGrassPool = (LLRenderPass*) new_poolp; } break; - case LLDrawPool::POOL_INVISIBLE: - if (mInvisiblePool) + case LLDrawPool::POOL_FULLBRIGHT: + if (mFullbrightPool) { llassert(0); - llwarns << "Ignoring duplicate simple pool." << llendl; + LL_WARNS() << "Ignoring duplicate simple pool." << LL_ENDL; } else { - mInvisiblePool = (LLRenderPass*) new_poolp; + mFullbrightPool = (LLRenderPass*) new_poolp; } break; @@ -4844,7 +5108,7 @@ void LLPipeline::addToQuickLookup( LLDrawPool* new_poolp ) if (mGlowPool) { llassert(0); - llwarns << "Ignoring duplicate glow pool." << llendl; + LL_WARNS() << "Ignoring duplicate glow pool." << LL_ENDL; } else { @@ -4864,23 +5128,33 @@ void LLPipeline::addToQuickLookup( LLDrawPool* new_poolp ) if (mBumpPool) { llassert(0); - llwarns << "Ignoring duplicate bump pool." << llendl; + LL_WARNS() << "Ignoring duplicate bump pool." << LL_ENDL; } else { mBumpPool = new_poolp; } break; - + case LLDrawPool::POOL_MATERIALS: + if (mMaterialsPool) + { + llassert(0); + LL_WARNS() << "Ignorning duplicate materials pool." << LL_ENDL; + } + else + { + mMaterialsPool = new_poolp; + } + break; case LLDrawPool::POOL_ALPHA: if( mAlphaPool ) { llassert(0); - llwarns << "LLPipeline::addPool(): Ignoring duplicate Alpha pool" << llendl; + LL_WARNS() << "LLPipeline::addPool(): Ignoring duplicate Alpha pool" << LL_ENDL; } else { - mAlphaPool = new_poolp; + mAlphaPool = (LLDrawPoolAlpha*) new_poolp; } break; @@ -4891,7 +5165,7 @@ void LLPipeline::addToQuickLookup( LLDrawPool* new_poolp ) if( mSkyPool ) { llassert(0); - llwarns << "LLPipeline::addPool(): Ignoring duplicate Sky pool" << llendl; + LL_WARNS() << "LLPipeline::addPool(): Ignoring duplicate Sky pool" << LL_ENDL; } else { @@ -4903,7 +5177,7 @@ void LLPipeline::addToQuickLookup( LLDrawPool* new_poolp ) if( mWaterPool ) { llassert(0); - llwarns << "LLPipeline::addPool(): Ignoring duplicate Water pool" << llendl; + LL_WARNS() << "LLPipeline::addPool(): Ignoring duplicate Water pool" << LL_ENDL; } else { @@ -4915,7 +5189,7 @@ void LLPipeline::addToQuickLookup( LLDrawPool* new_poolp ) if( mGroundPool ) { llassert(0); - llwarns << "LLPipeline::addPool(): Ignoring duplicate Ground Pool" << llendl; + LL_WARNS() << "LLPipeline::addPool(): Ignoring duplicate Ground Pool" << LL_ENDL; } else { @@ -4927,7 +5201,7 @@ void LLPipeline::addToQuickLookup( LLDrawPool* new_poolp ) if( mWLSkyPool ) { llassert(0); - llwarns << "LLPipeline::addPool(): Ignoring duplicate WLSky Pool" << llendl; + LL_WARNS() << "LLPipeline::addPool(): Ignoring duplicate WLSky Pool" << LL_ENDL; } else { @@ -4937,7 +5211,7 @@ void LLPipeline::addToQuickLookup( LLDrawPool* new_poolp ) default: llassert(0); - llwarns << "Invalid Pool Type in LLPipeline::addPool()" << llendl; + LL_WARNS() << "Invalid Pool Type in LLPipeline::addPool()" << LL_ENDL; break; } } @@ -4960,6 +5234,16 @@ void LLPipeline::removeFromQuickLookup( LLDrawPool* poolp ) mSimplePool = NULL; break; + case LLDrawPool::POOL_ALPHA_MASK: + llassert(mAlphaMaskPool == poolp); + mAlphaMaskPool = NULL; + break; + + case LLDrawPool::POOL_FULLBRIGHT_ALPHA_MASK: + llassert(mFullbrightAlphaMaskPool == poolp); + mFullbrightAlphaMaskPool = NULL; + break; + case LLDrawPool::POOL_GRASS: llassert(mGrassPool == poolp); mGrassPool = NULL; @@ -4970,11 +5254,6 @@ void LLPipeline::removeFromQuickLookup( LLDrawPool* poolp ) mFullbrightPool = NULL; break; - case LLDrawPool::POOL_INVISIBLE: - llassert(mInvisiblePool == poolp); - mInvisiblePool = NULL; - break; - case LLDrawPool::POOL_WL_SKY: llassert(mWLSkyPool == poolp); mWLSkyPool = NULL; @@ -5011,7 +5290,12 @@ void LLPipeline::removeFromQuickLookup( LLDrawPool* poolp ) llassert( poolp == mBumpPool ); mBumpPool = NULL; break; - + + case LLDrawPool::POOL_MATERIALS: + llassert(poolp == mMaterialsPool); + mMaterialsPool = NULL; + break; + case LLDrawPool::POOL_ALPHA: llassert( poolp == mAlphaPool ); mAlphaPool = NULL; @@ -5037,7 +5321,7 @@ void LLPipeline::removeFromQuickLookup( LLDrawPool* poolp ) default: llassert(0); - llwarns << "Invalid Pool Type in LLPipeline::removeFromQuickLookup() type=" << poolp->getType() << llendl; + LL_WARNS() << "Invalid Pool Type in LLPipeline::removeFromQuickLookup() type=" << poolp->getType() << LL_ENDL; break; } } @@ -5057,36 +5341,35 @@ void LLPipeline::resetDrawOrders() // Once-per-frame setup of hardware lights, // including sun/moon, avatar backlight, and up to 6 local lights -void LLPipeline::setupAvatarLights(BOOL for_edit) +U8 LLPipeline::setupFeatureLights(U8 cur_count) { - assertInitialized(); + //assertInitialized(); - if (for_edit) + if (mLightMode == LIGHT_MODE_EDIT) { LLColor4 diffuse(1.f, 1.f, 1.f, 0.f); - LLVector4 light_pos_cam(-8.f, 0.25f, 10.f, 0.f); // w==0 => directional light - LLMatrix4 camera_mat = LLViewerCamera::getInstance()->getModelview(); - LLMatrix4 camera_rot(camera_mat.getMat3()); + LLVector4a light_pos_cam(-8.f, 0.25f, 10.f, 0.f); // w==0 => directional light + LLMatrix4a camera_rot = LLViewerCamera::getInstance()->getModelview(); + camera_rot.extractRotation_affine(); camera_rot.invert(); - LLVector4 light_pos = light_pos_cam * camera_rot; + LLVector4a light_pos; - light_pos.normalize(); - - LLLightState* light = gGL.getLight(1); + camera_rot.rotate(light_pos_cam,light_pos); + + light_pos.normalize3fast(); - mHWLightColors[1] = diffuse; + LLLightState* light = gGL.getLight(cur_count++); light->setDiffuse(diffuse); - light->setAmbient(LLColor4::black); light->setSpecular(LLColor4::black); - light->setPosition(light_pos); + light->setPosition(LLVector4(light_pos.getF32ptr())); light->setConstantAttenuation(1.f); light->setLinearAttenuation(0.f); light->setQuadraticAttenuation(0.f); light->setSpotExponent(0.f); light->setSpotCutoff(180.f); } - else if (gAvatarBacklight) // Always true (unless overridden in a devs .ini) + else if (mLightMode == LIGHT_MODE_BACKLIGHT) // Always true (unless overridden in a devs .ini) { LLVector3 opposite_pos = -1.f * mSunDir; LLVector3 orthog_light_pos = mSunDir % LLVector3::z_axis; @@ -5114,13 +5397,10 @@ void LLPipeline::setupAvatarLights(BOOL for_edit) } backlight_diffuse *= backlight_mag / max_component; - mHWLightColors[1] = backlight_diffuse; - - LLLightState* light = gGL.getLight(1); + LLLightState* light = gGL.getLight(cur_count++); light->setPosition(backlight_pos); light->setDiffuse(backlight_diffuse); - light->setAmbient(LLColor4::black); light->setSpecular(LLColor4::black); light->setConstantAttenuation(1.f); light->setLinearAttenuation(0.f); @@ -5128,16 +5408,69 @@ void LLPipeline::setupAvatarLights(BOOL for_edit) light->setSpotExponent(0.f); light->setSpotCutoff(180.f); } - else + else if (mLightMode == LIGHT_MODE_PREVIEW) { - LLLightState* light = gGL.getLight(1); + static LLCachedControl PreviewAmbientColor("PreviewAmbientColor"); + + LLColor4 ambient = PreviewAmbientColor; + gGL.setAmbientLightColor(ambient); - mHWLightColors[1] = LLColor4::black; + static LLCachedControl PreviewDiffuse0("PreviewDiffuse0"); + static LLCachedControl PreviewSpecular0("PreviewSpecular0"); + static LLCachedControl PreviewDiffuse1("PreviewDiffuse1"); + static LLCachedControl PreviewSpecular1("PreviewSpecular1"); + static LLCachedControl PreviewDiffuse2("PreviewDiffuse2"); + static LLCachedControl PreviewSpecular2("PreviewSpecular2"); + static LLCachedControl PreviewDirection0("PreviewDirection0"); + static LLCachedControl PreviewDirection1("PreviewDirection1"); + static LLCachedControl PreviewDirection2("PreviewDirection2"); - light->setDiffuse(LLColor4::black); - light->setAmbient(LLColor4::black); - light->setSpecular(LLColor4::black); + LLColor4 diffuse0 = PreviewDiffuse0; + LLColor4 specular0 = PreviewSpecular0; + LLColor4 diffuse1 = PreviewDiffuse1; + LLColor4 specular1 = PreviewSpecular1; + LLColor4 diffuse2 = PreviewDiffuse2; + LLColor4 specular2 = PreviewSpecular2; + + LLVector3 dir0 = PreviewDirection0; + LLVector3 dir1 = PreviewDirection1; + LLVector3 dir2 = PreviewDirection2; + + dir0.normVec(); + dir1.normVec(); + dir2.normVec(); + + LLVector4 light_pos(dir0, 0.0f); + + LLLightState* light = gGL.getLight(cur_count++); + + light->enable(); + light->setPosition(light_pos); + light->setDiffuse(diffuse0); + light->setSpecular(specular0); + light->setSpotExponent(0.f); + light->setSpotCutoff(180.f); + + light_pos = LLVector4(dir1, 0.f); + + light = gGL.getLight(cur_count++); + light->enable(); + light->setPosition(light_pos); + light->setDiffuse(diffuse1); + light->setSpecular(specular1); + light->setSpotExponent(0.f); + light->setSpotCutoff(180.f); + + light_pos = LLVector4(dir2, 0.f); + light = gGL.getLight(cur_count++); + light->enable(); + light->setPosition(light_pos); + light->setDiffuse(diffuse2); + light->setSpecular(specular2); + light->setSpotExponent(0.f); + light->setSpotCutoff(180.f); } + return cur_count; } static F32 calc_light_dist(LLVOVolume* light, const LLVector3& cam_pos, F32 max_dist) @@ -5173,26 +5506,22 @@ static F32 calc_light_dist(LLVOVolume* light, const LLVector3& cam_pos, F32 max_ //Default all gl light parameters. Used upon restoreGL. Fixes brightness problems on fullscren toggle void LLPipeline::resetLocalLights() { - if (!LLGLSLShader::sNoFixedFunction) - glEnable(GL_LIGHTING); - for (S32 i = 0; i < 8; ++i) + LLGLEnable enable; + for (S32 i = 0; i < LLRender::NUM_LIGHTS; ++i) { LLLightState *pLight = gGL.getLight(i); pLight->enable(); - pLight->setAmbient(LLColor4::black); pLight->setConstantAttenuation(0.f); pLight->setDiffuse(LLColor4::black); pLight->setLinearAttenuation(0.f); - pLight->setPosition(LLVector4(0.f,0.f,0.f,0.f)); + pLight->setPosition(LLVector4(0.f,0.f,1.f,0.f)); pLight->setQuadraticAttenuation(0.f); pLight->setSpecular(LLColor4::black); pLight->setSpotCutoff(0.f); - pLight->setSpotDirection(LLVector3(0.f,0.f,0.f)); + pLight->setSpotDirection(LLVector3(0.f,0.f,-1.f)); pLight->setSpotExponent(0.f); pLight->disable(); } - if (!LLGLSLShader::sNoFixedFunction) - glDisable(GL_LIGHTING); } void LLPipeline::calcNearbyLights(LLCamera& camera) @@ -5204,11 +5533,11 @@ void LLPipeline::calcNearbyLights(LLCamera& camera) return; } - if (mLightingDetail >= 1) + if (isLocalLightingEnabled()) { // mNearbyLight (and all light_set_t's) are sorted such that // begin() == the closest light and rbegin() == the farthest light - const S32 MAX_LOCAL_LIGHTS = 6; + const S32 MAX_LOCAL_LIGHTS = 7; // LLVector3 cam_pos = gAgentCamera.getCameraPositionAgent(); LLVector3 cam_pos = LLViewerJoystick::getInstance()->getOverrideCamera() ? camera.getOrigin() : @@ -5293,7 +5622,7 @@ void LLPipeline::calcNearbyLights(LLCamera& camera) // crazy cast so that we can overwrite the fade value // even though gcc enforces sets as const // (fade value doesn't affect sort so this is safe) - Light* farthest_light = ((Light*) (&(*(mNearbyLights.rbegin())))); + Light* farthest_light = (const_cast(&(*(mNearbyLights.rbegin())))); if (light->dist < farthest_light->dist) { if (farthest_light->fade >= 0.f) @@ -5307,68 +5636,15 @@ void LLPipeline::calcNearbyLights(LLCamera& camera) } } } - } + gatherLocalLights(); } -void LLPipeline::setupHWLights(LLDrawPool* pool) -{ - assertInitialized(); - - // Ambient - if (!LLGLSLShader::sNoFixedFunction) - { - gGL.syncMatrices(); - LLColor4 ambient = gSky.getTotalAmbientColor(); - gGL.setAmbientLightColor(ambient); - } - - // Light 0 = Sun or Moon (All objects) - { - if (gSky.getSunDirection().mV[2] >= LLSky::NIGHTTIME_ELEVATION_COS) - { - mSunDir.setVec(gSky.getSunDirection()); - mSunDiffuse.setVec(gSky.getSunDiffuseColor()); - } - else - { - mSunDir.setVec(gSky.getMoonDirection()); - mSunDiffuse.setVec(gSky.getMoonDiffuseColor()); - } - - F32 max_color = llmax(mSunDiffuse.mV[0], mSunDiffuse.mV[1], mSunDiffuse.mV[2]); - if (max_color > 1.f) - { - mSunDiffuse *= 1.f/max_color; - } - mSunDiffuse.clamp(); - - LLVector4 light_pos(mSunDir, 0.0f); - LLColor4 light_diffuse = mSunDiffuse; - mHWLightColors[0] = light_diffuse; - - LLLightState* light = gGL.getLight(0); - light->setPosition(light_pos); - light->setDiffuse(light_diffuse); - light->setAmbient(LLColor4::black); - light->setSpecular(LLColor4::black); - light->setConstantAttenuation(1.f); - light->setLinearAttenuation(0.f); - light->setQuadraticAttenuation(0.f); - light->setSpotExponent(0.f); - light->setSpotCutoff(180.f); - } - - // Light 1 = Backlight (for avatars) - // (set by enableLightsAvatar) - - S32 cur_light = 2; - - // Nearby lights = LIGHT 2-7 - mLightMovingMask = 0; - - if (mLightingDetail >= 1) +void LLPipeline::gatherLocalLights() +{ + mLocalLights.clear(); + if (isLocalLightingEnabled()) { for (light_set_t::iterator iter = mNearbyLights.begin(); iter != mNearbyLights.end(); ++iter) @@ -5379,11 +5655,7 @@ void LLPipeline::setupHWLights(LLDrawPool* pool) { continue; } - if (drawable->isState(LLDrawable::ACTIVE)) - { - mLightMovingMask |= (1<getLightColor(); light_color.mV[3] = 0.0f; @@ -5413,23 +5685,19 @@ void LLPipeline::setupHWLights(LLDrawPool* pool) F32 x = (3.f * (1.f + light->getLightFalloff())); // why this magic? probably trying to match a historic behavior. float linatten = x / (light_radius); // % of brightness at radius - mHWLightColors[cur_light] = light_color; - LLLightState* light_state = gGL.getLight(cur_light); - - light_state->setPosition(light_pos_gl); - light_state->setDiffuse(light_color); - light_state->setAmbient(LLColor4::black); - light_state->setConstantAttenuation(0.f); + LLLightStateData light_state = LLLightStateData(); + light_state.mPosition = light_pos_gl; + light_state.mDiffuse = light_color; + light_state.mConstantAtten = 0.f; + if (sRenderDeferred) { - F32 size = light_radius*1.5f; - light_state->setLinearAttenuation(size*size); - light_state->setQuadraticAttenuation(light->getLightFalloff()*0.5f+1.f); + light_state.mLinearAtten = light_radius * 1.5f; + light_state.mQuadraticAtten = light->getLightFalloff()*0.5f + 1.f; } else { - light_state->setLinearAttenuation(linatten); - light_state->setQuadraticAttenuation(0.f); + light_state.mLinearAtten = linatten; } static const LLCachedControl RenderSpotLightsInNondeferred("RenderSpotLightsInNondeferred",false); @@ -5440,266 +5708,214 @@ void LLPipeline::setupHWLights(LLDrawPool* pool) LLVector3 at_axis(0,0,-1); // this matches deferred rendering's object light direction at_axis *= quat; - light_state->setSpotDirection(at_axis); - light_state->setSpotCutoff(90.f); - light_state->setSpotExponent(2.f); - - const LLColor4 specular(0.f, 0.f, 0.f, 0.f); - light_state->setSpecular(specular); + light_state.mSpotDirection = at_axis; + light_state.mSpotCutoff = 90.f; + light_state.mSpotExponent = 2.f; + light_state.mSpecular = LLColor4::transparent; } else // omnidirectional (point) light { - light_state->setSpotExponent(0.f); - light_state->setSpotCutoff(180.f); - // we use specular.w = 1.0 as a cheap hack for the shaders to know that this is omnidirectional rather than a spotlight - const LLColor4 specular(0.f, 0.f, 0.f, 1.f); - light_state->setSpecular(specular); - } - cur_light++; - if (cur_light >= 8) - { - break; // safety + light_state.mSpecular = LLColor4::black; } + mLocalLights.push_back(light_state); } } - for ( ; cur_light < 8 ; cur_light++) - { - mHWLightColors[cur_light] = LLColor4::black; - LLLightState* light = gGL.getLight(cur_light); - - light->setDiffuse(LLColor4::black); - light->setAmbient(LLColor4::black); - light->setSpecular(LLColor4::black); - } - if (gAgentAvatarp && - gAgentAvatarp->mSpecialRenderMode == 3) - { - LLColor4 light_color = LLColor4::white; - light_color.mV[3] = 0.0f; - - LLVector3 light_pos(LLViewerCamera::getInstance()->getOrigin()); - LLVector4 light_pos_gl(light_pos, 1.0f); - - F32 light_radius = 16.f; - - F32 x = 3.f; - float linatten = x / (light_radius); // % of brightness at radius - - mHWLightColors[2] = light_color; - LLLightState* light = gGL.getLight(2); - - light->setPosition(light_pos_gl); - light->setDiffuse(light_color); - light->setAmbient(LLColor4::black); - light->setSpecular(LLColor4::black); - light->setQuadraticAttenuation(0.f); - light->setConstantAttenuation(0.f); - light->setLinearAttenuation(linatten); - light->setSpotExponent(0.f); - light->setSpotCutoff(180.f); - } +} - // Init GL state - if (!LLGLSLShader::sNoFixedFunction) +LLVector3 getSunDir() +{ + if (gSky.getSunDirection().mV[2] >= LLSky::NIGHTTIME_ELEVATION_COS) { - glDisable(GL_LIGHTING); + return gSky.getSunDirection(); } - - for (S32 i = 0; i < 8; ++i) + else { - gGL.getLight(i)->disable(); + return gSky.getMoonDirection(); } - mLightMask = 0; } -void LLPipeline::enableLights(U32 mask) + +extern U32 sLightMask; +void LLPipeline::setupHWLights() { - assertInitialized(); + static LLCachedControl LightMask("LightMask", 0xFFFFFFFF); + sLightMask = LightMask; - if (mLightingDetail == 0) + // Ambient + if (mLightMode == LIGHT_MODE_PREVIEW) { - mask &= 0xf003; // sun and backlight only (and fullbright bit) + static LLCachedControl PreviewAmbientColor("PreviewAmbientColor"); + LLColor4 ambient = PreviewAmbientColor; + gGL.setAmbientLightColor(ambient); } - if (mLightMask != mask) + else if (!LLGLSLShader::sNoFixedFunction) { - stop_glerror(); - if (!mLightMask) + LLColor4 ambient = gSky.getTotalAmbientColor(); + gGL.setAmbientLightColor(ambient); + } + + U8 cur_light = 0; + // Light 0 = Sun or Moon (All objects) + { + if (gSky.getSunDirection().mV[2] >= LLSky::NIGHTTIME_ELEVATION_COS) { - if (!LLGLSLShader::sNoFixedFunction) - { - glEnable(GL_LIGHTING); - } + mSunDir.setVec(gSky.getSunDirection()); + mSunDiffuse.setVec(gSky.getSunDiffuseColor()); + } + else + { + mSunDir.setVec(gSky.getMoonDirection()); + mSunDiffuse.setVec(gSky.getMoonDiffuseColor()); + } + + F32 max_color = llmax(mSunDiffuse.mV[0], mSunDiffuse.mV[1], mSunDiffuse.mV[2]); + if (max_color > 1.f) + { + mSunDiffuse *= 1.f/max_color; + } + mSunDiffuse.clamp(); + + LLVector4 light_pos(mSunDir, 0.0f); + LLColor4 light_diffuse = mSunDiffuse; + + LLLightState* light = gGL.getLight(cur_light++); + light->setPosition(light_pos); + light->setDiffuse(light_diffuse); + light->setSpecular(LLColor4::black); + light->setConstantAttenuation(1.f); + light->setLinearAttenuation(0.f); + light->setQuadraticAttenuation(0.f); + light->setSpotExponent(0.f); + light->setSpotCutoff(180.f); + } + + // Edit mode lights + cur_light = setupFeatureLights(cur_light); + + // Nearby lights + if (isLocalLightingEnabled()) + { + for (auto& local_light : mLocalLights) + { + gGL.getLight(cur_light++)->setState(local_light); + if (cur_light >= LLRender::NUM_LIGHTS) + break; + } + } + for (S32 i = cur_light; i < LLRender::NUM_LIGHTS; ++i) + { + //gGL.getLight(cur_light++)->setState(LLLightStateData()); + gGL.getLight(i)->disable(); + } + /*for (S32 i = 0; i < LLRender::NUM_LIGHTS; ++i) + { + gGL.getLight(i)->disable(); + } + mLightMask = 0;*/ + mHWLightCount = cur_light; +} + + +void LLPipeline::updateHWLightMode(U8 mode) +{ + if (mLightMode != mode) + { + mLightMode = mode; + setupHWLights(); + } +} + +void LLPipeline::enableLights(U32 mask, LLGLState& light_state, const LLColor4* color) +{ + if (mLightMask != mask) + { + stop_glerror(); + if (!mLightMask) + { + light_state.enable(); } if (mask) { stop_glerror(); - for (S32 i=0; i<8; i++) + for (S32 i=0; i < LLRender::NUM_LIGHTS; i++) { LLLightState* light = gGL.getLight(i); - if (mask & (1<enable(); - light->setDiffuse(mHWLightColors[i]); } else { light->disable(); - light->setDiffuse(LLColor4::black); } } stop_glerror(); } else { - if (!LLGLSLShader::sNoFixedFunction) - { - glDisable(GL_LIGHTING); - } + light_state.disable(); } mLightMask = mask; stop_glerror(); - - LLColor4 ambient = gSky.getTotalAmbientColor(); - gGL.setAmbientLightColor(ambient); } + LLColor4 ambient = color ? *color : gSky.getTotalAmbientColor(); + gGL.setAmbientLightColor(ambient); } -void LLPipeline::enableLightsStatic() +void LLPipeline::enableLightsStatic(LLGLState& light_state) { - assertInitialized(); - U32 mask = 0x01; // Sun - if (mLightingDetail >= 2) - { - mask |= mLightMovingMask; // Hardware moving lights - } - else - { - mask |= 0xff & (~2); // Hardware local lights - } - enableLights(mask); + updateHWLightMode(LIGHT_MODE_NORMAL); + enableLights(0xFFFFFFFF, light_state); } -void LLPipeline::enableLightsDynamic() +void LLPipeline::enableLightsDynamic(LLGLState& light_state) { assertInitialized(); - U32 mask = 0xff & (~2); // Local lights - enableLights(mask); - if (isAgentAvatarValid() && getLightingDetail() <= 0) + if (isAgentAvatarValid() && !isLocalLightingEnabled()) { if (gAgentAvatarp->mSpecialRenderMode == 0) // normal { - gPipeline.enableLightsAvatar(); + gPipeline.enableLightsAvatar(light_state); + return; } else if (gAgentAvatarp->mSpecialRenderMode >= 1) // anim preview { - gPipeline.enableLightsAvatarEdit(LLColor4(0.7f, 0.6f, 0.3f, 1.f)); + gPipeline.enableLightsAvatarEdit(light_state, LLColor4(0.7f, 0.6f, 0.3f, 1.f)); + return; } } + + updateHWLightMode(LIGHT_MODE_NORMAL); + enableLights(0xFFFFFFFF, light_state); } -void LLPipeline::enableLightsAvatar() +void LLPipeline::enableLightsAvatar(LLGLState& light_state) { - U32 mask = 0xff; // All lights - setupAvatarLights(FALSE); - enableLights(mask); + updateHWLightMode(gAvatarBacklight ? LIGHT_MODE_BACKLIGHT : LIGHT_MODE_NORMAL); // Avatar backlight only, set ambient + enableLights(0xFFFFFFFF, light_state); } -void LLPipeline::enableLightsPreview() +void LLPipeline::enableLightsPreview(LLGLState& light_state) { - disableLights(); - - if (!LLGLSLShader::sNoFixedFunction) - { - glEnable(GL_LIGHTING); - } - - static LLCachedControl PreviewAmbientColor("PreviewAmbientColor"); - - LLColor4 ambient = PreviewAmbientColor; - gGL.setAmbientLightColor(ambient); - - static LLCachedControl PreviewDiffuse0("PreviewDiffuse0"); - static LLCachedControl PreviewSpecular0("PreviewSpecular0"); - static LLCachedControl PreviewDiffuse1("PreviewDiffuse1"); - static LLCachedControl PreviewSpecular1("PreviewSpecular1"); - static LLCachedControl PreviewDiffuse2("PreviewDiffuse2"); - static LLCachedControl PreviewSpecular2("PreviewSpecular2"); - static LLCachedControl PreviewDirection0("PreviewDirection0"); - static LLCachedControl PreviewDirection1("PreviewDirection1"); - static LLCachedControl PreviewDirection2("PreviewDirection2"); - - LLColor4 diffuse0 = PreviewDiffuse0; - LLColor4 specular0 = PreviewSpecular0; - LLColor4 diffuse1 = PreviewDiffuse1; - LLColor4 specular1 = PreviewSpecular1; - LLColor4 diffuse2 = PreviewDiffuse2; - LLColor4 specular2 = PreviewSpecular2; - - LLVector3 dir0 = PreviewDirection0; - LLVector3 dir1 = PreviewDirection1; - LLVector3 dir2 = PreviewDirection2; - - dir0.normVec(); - dir1.normVec(); - dir2.normVec(); - - LLVector4 light_pos(dir0, 0.0f); - - LLLightState* light = gGL.getLight(1); - - light->enable(); - light->setPosition(light_pos); - light->setDiffuse(diffuse0); - light->setAmbient(LLColor4::black); - light->setSpecular(specular0); - light->setSpotExponent(0.f); - light->setSpotCutoff(180.f); - - light_pos = LLVector4(dir1, 0.f); - - light = gGL.getLight(2); - light->enable(); - light->setPosition(light_pos); - light->setDiffuse(diffuse1); - light->setAmbient(LLColor4::black); - light->setSpecular(specular1); - light->setSpotExponent(0.f); - light->setSpotCutoff(180.f); - - light_pos = LLVector4(dir2, 0.f); - light = gGL.getLight(3); - light->enable(); - light->setPosition(light_pos); - light->setDiffuse(diffuse2); - light->setAmbient(LLColor4::black); - light->setSpecular(specular2); - light->setSpotExponent(0.f); - light->setSpotCutoff(180.f); + updateHWLightMode(LIGHT_MODE_PREVIEW); + enableLights(0xFFFFFFFF, light_state); } -void LLPipeline::enableLightsAvatarEdit(const LLColor4& color) +void LLPipeline::enableLightsAvatarEdit(LLGLState& light_state, const LLColor4& color) { - U32 mask = 0x2002; // Avatar backlight only, set ambient - setupAvatarLights(TRUE); - enableLights(mask); - - gGL.setAmbientLightColor(color); + updateHWLightMode(LIGHT_MODE_EDIT); + enableLights(0xFFFFFFFF, light_state, &color); } -void LLPipeline::enableLightsFullbright(const LLColor4& color) +void LLPipeline::enableLightsFullbright(LLGLState& light_state) { - assertInitialized(); - U32 mask = 0x1000; // Non-0 mask, set ambient - enableLights(mask); - - gGL.setAmbientLightColor(color); + enableLights(0, light_state); } -void LLPipeline::disableLights() +void LLPipeline::disableLights(LLGLState& light_state) { - enableLights(0); // no lighting (full bright) -// gGL.diffuseColor4f(1.f, 1.f, 1.f, 1.f); + enableLights(0, light_state); // no lighting (full bright) } //============================================================================ @@ -5715,28 +5931,28 @@ void LLPipeline::findReferences(LLDrawable *drawablep) assertInitialized(); if (mLights.find(drawablep) != mLights.end()) { - llinfos << "In mLights" << llendl; + LL_INFOS() << "In mLights" << LL_ENDL; } if (std::find(mMovedList.begin(), mMovedList.end(), drawablep) != mMovedList.end()) { - llinfos << "In mMovedList" << llendl; + LL_INFOS() << "In mMovedList" << LL_ENDL; } if (std::find(mShiftList.begin(), mShiftList.end(), drawablep) != mShiftList.end()) { - llinfos << "In mShiftList" << llendl; + LL_INFOS() << "In mShiftList" << LL_ENDL; } if (mRetexturedList.find(drawablep) != mRetexturedList.end()) { - llinfos << "In mRetexturedList" << llendl; + LL_INFOS() << "In mRetexturedList" << LL_ENDL; } if (std::find(mBuildQ1.begin(), mBuildQ1.end(), drawablep) != mBuildQ1.end()) { - llinfos << "In mBuildQ1" << llendl; + LL_INFOS() << "In mBuildQ1" << LL_ENDL; } if (std::find(mBuildQ2.begin(), mBuildQ2.end(), drawablep) != mBuildQ2.end()) { - llinfos << "In mBuildQ2" << llendl; + LL_INFOS() << "In mBuildQ2" << LL_ENDL; } S32 count; @@ -5744,7 +5960,7 @@ void LLPipeline::findReferences(LLDrawable *drawablep) count = gObjectList.findReferences(drawablep); if (count) { - llinfos << "In other drawables: " << count << " references" << llendl; + LL_INFOS() << "In other drawables: " << count << " references" << LL_ENDL; } } @@ -5765,7 +5981,7 @@ BOOL LLPipeline::verify() if (!ok) { - llwarns << "Pipeline verify failed!" << llendl; + LL_WARNS() << "Pipeline verify failed!" << LL_ENDL; } return ok; } @@ -5903,11 +6119,11 @@ void LLPipeline::toggleRenderTypeControl(void* data) U32 bit = (1<getRegionList().begin(); + iter != LLWorld::getInstance()->getRegionList().end(); ++iter) + { + LLViewerRegion* region = *iter; + + LLSpatialPartition* part = region->getSpatialPartition(LLViewerRegion::PARTITION_PARTICLE); + if (part && hasRenderType(part->mDrawableType)) + { + LLDrawable* hit = part->lineSegmentIntersect(start, local_end, TRUE, FALSE, face_hit, &position, NULL, NULL, NULL); + if (hit) + { + drawable = hit; + local_end = position; + } + } + } + + LLVOPartGroup* ret = NULL; + if (drawable) + { + //make sure we're returning an LLVOPartGroup + llassert(drawable->getVObj()->getPCode() == LLViewerObject::LL_VO_PART_GROUP); + ret = (LLVOPartGroup*) drawable->getVObj().get(); + } + + if (intersection) + { + *intersection = position; + } + + return ret; +} + +LLViewerObject* LLPipeline::lineSegmentIntersectInWorld(const LLVector4a& start, const LLVector4a& end, BOOL pick_transparent, + bool pick_rigged, S32* face_hit, - LLVector3* intersection, // return the intersection point + LLVector4a* intersection, // return the intersection point LLVector2* tex_coord, // return the texture coordinates of the intersection point - LLVector3* normal, // return the surface normal at the intersection point - LLVector3* bi_normal // return the surface bi-normal at the intersection point + LLVector4a* normal, // return the surface normal at the intersection point + LLVector4a* tangent // return the surface tangent at the intersection point ) { LLDrawable* drawable = NULL; - LLVector3 local_end = end; + LLVector4a local_end = end; - LLVector3 position; + LLVector4a position; + position.clear(); sPickAvatar = FALSE; //LLToolMgr::getInstance()->inBuildMode() ? FALSE : TRUE; @@ -6192,6 +6459,7 @@ LLViewerObject* LLPipeline::lineSegmentIntersectInWorld(const LLVector3& start, for (U32 j = 0; j < LLViewerRegion::NUM_PARTITIONS; j++) { if ((j == LLViewerRegion::PARTITION_VOLUME) || + (j == LLViewerRegion::PARTITION_ATTACHMENT) || (j == LLViewerRegion::PARTITION_BRIDGE) || (j == LLViewerRegion::PARTITION_TERRAIN) || (j == LLViewerRegion::PARTITION_TREE) || @@ -6200,7 +6468,7 @@ LLViewerObject* LLPipeline::lineSegmentIntersectInWorld(const LLVector3& start, LLSpatialPartition* part = region->getSpatialPartition(j); if (part && hasRenderType(part->mDrawableType)) { - LLDrawable* hit = part->lineSegmentIntersect(start, local_end, pick_transparent, face_hit, &position, tex_coord, normal, bi_normal); + LLDrawable* hit = part->lineSegmentIntersect(start, local_end, pick_transparent, pick_rigged, face_hit, &position, tex_coord, normal, tangent); if (hit) { drawable = hit; @@ -6215,8 +6483,8 @@ LLViewerObject* LLPipeline::lineSegmentIntersectInWorld(const LLVector3& start, { //save hit info in case we need to restore //due to attachment override - LLVector3 local_normal; - LLVector3 local_binormal; + LLVector4a local_normal; + LLVector4a local_tangent; LLVector2 local_texcoord; S32 local_face_hit = -1; @@ -6228,14 +6496,22 @@ LLViewerObject* LLPipeline::lineSegmentIntersectInWorld(const LLVector3& start, { local_texcoord = *tex_coord; } - if (bi_normal) + if (tangent) + { + local_tangent = *tangent; + } + else { - local_binormal = *bi_normal; + local_tangent.clear(); } if (normal) { local_normal = *normal; } + else + { + local_normal.clear(); + } const F32 ATTACHMENT_OVERRIDE_DIST = 0.1f; @@ -6246,15 +6522,18 @@ LLViewerObject* LLPipeline::lineSegmentIntersectInWorld(const LLVector3& start, { LLViewerRegion* region = *iter; - LLSpatialPartition* part = region->getSpatialPartition(LLViewerRegion::PARTITION_BRIDGE); + LLSpatialPartition* part = region->getSpatialPartition(LLViewerRegion::PARTITION_ATTACHMENT); if (part && hasRenderType(part->mDrawableType)) { - LLDrawable* hit = part->lineSegmentIntersect(start, local_end, pick_transparent, face_hit, &position, tex_coord, normal, bi_normal); + LLDrawable* hit = part->lineSegmentIntersect(start, local_end, pick_transparent, pick_rigged, face_hit, &position, tex_coord, normal, tangent); if (hit) { + LLVector4a delta; + delta.setSub(position, local_end); + if (!drawable || !drawable->getVObj()->isAttachment() || - (position-local_end).magVec() > ATTACHMENT_OVERRIDE_DIST) + delta.getLength3().getF32() > ATTACHMENT_OVERRIDE_DIST) { //avatar overrides if previously hit drawable is not an attachment or //attachment is far enough away from detected intersection drawable = hit; @@ -6272,9 +6551,9 @@ LLViewerObject* LLPipeline::lineSegmentIntersectInWorld(const LLVector3& start, { *tex_coord = local_texcoord; } - if (bi_normal) + if (tangent) { - *bi_normal = local_binormal; + *tangent = local_tangent; } if (normal) { @@ -6308,13 +6587,13 @@ LLViewerObject* LLPipeline::lineSegmentIntersectInWorld(const LLVector3& start, return drawable ? drawable->getVObj().get() : NULL; } -LLViewerObject* LLPipeline::lineSegmentIntersectInHUD(const LLVector3& start, const LLVector3& end, +LLViewerObject* LLPipeline::lineSegmentIntersectInHUD(const LLVector4a& start, const LLVector4a& end, BOOL pick_transparent, S32* face_hit, - LLVector3* intersection, // return the intersection point + LLVector4a* intersection, // return the intersection point LLVector2* tex_coord, // return the texture coordinates of the intersection point - LLVector3* normal, // return the surface normal at the intersection point - LLVector3* bi_normal // return the surface bi-normal at the intersection point + LLVector4a* normal, // return the surface normal at the intersection point + LLVector4a* tangent // return the surface tangent at the intersection point ) { LLDrawable* drawable = NULL; @@ -6334,7 +6613,7 @@ LLViewerObject* LLPipeline::lineSegmentIntersectInHUD(const LLVector3& start, co LLSpatialPartition* part = region->getSpatialPartition(LLViewerRegion::PARTITION_HUD); if (part) { - LLDrawable* hit = part->lineSegmentIntersect(start, end, pick_transparent, face_hit, intersection, tex_coord, normal, bi_normal); + LLDrawable* hit = part->lineSegmentIntersect(start, end, pick_transparent, FALSE, face_hit, intersection, tex_coord, normal, tangent); if (hit) { drawable = hit; @@ -6381,110 +6660,109 @@ void LLPipeline::resetVertexBuffers(LLDrawable* drawable) void LLPipeline::resetVertexBuffers() { + // Only set to true if pipeline has been initialized (No vbo's to reset, otherwise) + //if (mInitialized) mResetVertexBuffers = true; } -static LLFastTimer::DeclareTimer FTM_RESET_VB("Reset VB"); +static LLTrace::BlockTimerStatHandle FTM_RESET_VB("Reset VB"); -void LLPipeline::doResetVertexBuffers() +void LLPipeline::doResetVertexBuffers(bool forced) { - if (!mResetVertexBuffers) + if ( !mResetVertexBuffers) { return; } - - LLFastTimer t(FTM_RESET_VB); - mResetVertexBuffers = false; - - mCubeVB = NULL; - mDeferredVB = NULL; - - for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); - iter != LLWorld::getInstance()->getRegionList().end(); ++iter) + if(!forced && LLSpatialPartition::sTeleportRequested) { - LLViewerRegion* region = *iter; - for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) + if(gAgent.getTeleportState() != LLAgent::TELEPORT_NONE) { - LLSpatialPartition* part = region->getSpatialPartition(i); - if (part) - { - part->resetVertexBuffers(); - } + return; //wait for teleporting to finish + } + else + { + //teleporting aborted + LLSpatialPartition::sTeleportRequested = FALSE; + mResetVertexBuffers = false; + return; } } - resetDrawOrders(); - - gSky.resetVertexBuffers(); - - LLVOPartGroup::destroyGL(); - - if(LLPostProcess::instanceExists()) - LLPostProcess::getInstance()->destroyGL(); - - LLVOPartGroup::destroyGL(); - - LLVertexBuffer::cleanupClass(); - - //delete all name pool caches - LLGLNamePool::cleanupPools(); - - if (LLVertexBuffer::sGLCount > 0) + LL_RECORD_BLOCK_TIME(FTM_RESET_VB); + mResetVertexBuffers = false; + releaseVertexBuffers(); + if(LLSpatialPartition::sTeleportRequested) { - llwarns << "VBO wipe failed -- " << LLVertexBuffer::sGLCount << " buffers remaining." << llendl; - } + LLSpatialPartition::sTeleportRequested = FALSE; - LLVertexBuffer::unbind(); + LLWorld::getInstance()->clearAllVisibleObjects(); + clearRebuildDrawables(); + } - sRenderBump = gSavedSettings.getBOOL("RenderObjectBump"); - LLVertexBuffer::sUseStreamDraw = gSavedSettings.getBOOL("ShyotlRenderUseStreamVBO"); - LLVertexBuffer::sUseVAO = gSavedSettings.getBOOL("RenderUseVAO") && gPipeline.canUseVertexShaders(); //Temporary workaround for vaos being broken when shaders are off - LLVertexBuffer::sPreferStreamDraw = gSavedSettings.getBOOL("RenderPreferStreamDraw"); - LLVertexBuffer::sEnableVBOs = gSavedSettings.getBOOL("RenderVBOEnable"); - LLVertexBuffer::sDisableVBOMapping = LLVertexBuffer::sEnableVBOs;// && gSavedSettings.getBOOL("RenderVBOMappingDisable") ; //Temporary workaround for vbo mapping being straight up broken - sBakeSunlight = gSavedSettings.getBOOL("RenderBakeSunlight"); - sNoAlpha = gSavedSettings.getBOOL("RenderNoAlpha"); - LLPipeline::sTextureBindTest = gSavedSettings.getBOOL("RenderDebugTextureBind"); + refreshCachedSettings(); LLVertexBuffer::initClass(LLVertexBuffer::sEnableVBOs, LLVertexBuffer::sDisableVBOMapping); LLVOPartGroup::restoreGL(); + + gGL.restoreVertexBuffers(); } void LLPipeline::renderObjects(U32 type, U32 mask, BOOL texture, BOOL batch_texture) { assertInitialized(); - gGL.loadMatrix(gGLModelView); + gGL.loadMatrix(glh_get_current_modelview()); gGLLastMatrix = NULL; mSimplePool->pushBatches(type, mask, texture, batch_texture); - gGL.loadMatrix(gGLModelView); + gGL.loadMatrix(glh_get_current_modelview()); + gGLLastMatrix = NULL; +} + +void LLPipeline::renderMaskedObjects(U32 type, U32 mask, BOOL texture, BOOL batch_texture) +{ + assertInitialized(); + gGL.loadMatrix(glh_get_current_modelview()); + gGLLastMatrix = NULL; + mAlphaMaskPool->pushMaskBatches(type, mask, texture, batch_texture); + gGL.loadMatrix(glh_get_current_modelview()); gGLLastMatrix = NULL; } + void apply_cube_face_rotation(U32 face) { + static const LLMatrix4a x_90 = gGL.genRot( 90.f, 1.f, 0.f, 0.f ); + static const LLMatrix4a y_90 = gGL.genRot( 90.f, 0.f, 1.f, 0.f ); + static const LLMatrix4a x_90_neg = gGL.genRot( -90.f, 1.f, 0.f, 0.f ); + static const LLMatrix4a y_90_neg = gGL.genRot( -90.f, 0.f, 1.f, 0.f ); + + static const LLMatrix4a x_180 = gGL.genRot( 180.f, 1.f, 0.f, 0.f ); + static const LLMatrix4a y_180 = gGL.genRot( 180.f, 0.f, 1.f, 0.f ); + static const LLMatrix4a z_180 = gGL.genRot( 180.f, 0.f, 0.f, 1.f ); + switch (face) { case 0: - gGL.rotatef(90.f, 0, 1, 0); - gGL.rotatef(180.f, 1, 0, 0); + + gGL.rotatef(y_90); + gGL.rotatef(x_180); break; case 2: - gGL.rotatef(-90.f, 1, 0, 0); + gGL.rotatef(x_90_neg); break; case 4: - gGL.rotatef(180.f, 0, 1, 0); - gGL.rotatef(180.f, 0, 0, 1); + gGL.rotatef(y_180); + gGL.rotatef(z_180); break; case 1: - gGL.rotatef(-90.f, 0, 1, 0); - gGL.rotatef(180.f, 1, 0, 0); + gGL.rotatef(y_90_neg); + gGL.rotatef(x_180); break; case 3: - gGL.rotatef(90, 1, 0, 0); + gGL.rotatef(x_90); break; case 5: - gGL.rotatef(180, 0, 0, 1); + gGL.rotatef(z_180); break; } } @@ -6500,22 +6778,22 @@ void validate_framebuffer_object() break; case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: // frame buffer not OK: probably means unsupported depth buffer format - llerrs << "Framebuffer Incomplete Missing Attachment." << llendl; + LL_ERRS() << "Framebuffer Incomplete Missing Attachment." << LL_ENDL; break; case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: //May not work on mac. Remove/ifdef if that's the case, for now. GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS missing from glext.h. // frame buffer not OK: probably means unsupported depth buffer format - llerrs << "Framebuffer Incomplete Dimensions." << llendl; + LL_ERRS() << "Framebuffer Incomplete Dimensions." << LL_ENDL; break; case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: // frame buffer not OK: probably means unsupported depth buffer format - llerrs << "Framebuffer Incomplete Attachment." << llendl; + LL_ERRS() << "Framebuffer Incomplete Attachment." << LL_ENDL; break; case GL_FRAMEBUFFER_UNSUPPORTED: /* choose different formats */ - llerrs << "Framebuffer unsupported." << llendl; + LL_ERRS() << "Framebuffer unsupported." << LL_ENDL; break; default: - llerrs << "Unknown framebuffer status." << llendl; + LL_ERRS() << "Unknown framebuffer status." << LL_ENDL; break; } } @@ -6525,10 +6803,10 @@ void LLPipeline::bindScreenToTexture() } -static LLFastTimer::DeclareTimer FTM_RENDER_BLOOM("Bloom"); +static LLTrace::BlockTimerStatHandle FTM_RENDER_BLOOM("Bloom"); void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield, bool tiling) { - if (!(gPipeline.canUseVertexShaders() && + if (!(LLGLSLShader::sNoFixedFunction && sRenderGlow)) { return; @@ -6554,34 +6832,31 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield, b static const LLCachedControl RenderFSAASamples("RenderFSAASamples",0); LLVertexBuffer::unbind(); - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); + LLGLStateValidator::checkStates(); + LLGLStateValidator::checkTextureChannels(); assertInitialized(); if (gUseWireframe) { - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + gGL.setPolygonMode(LLRender::PF_FRONT_AND_BACK, LLRender::PM_FILL); } //U32 res_mod = RenderResolutionDivisor;//.get(); - LLVector2 tc1(0,0); - LLVector2 tc2((F32) mScreen.getWidth()*2, - (F32) mScreen.getHeight()*2); - /*if (res_mod > 1) { tc2 /= (F32) res_mod; }*/ - LLFastTimer ftm(FTM_RENDER_BLOOM); + LL_RECORD_BLOCK_TIME(FTM_RENDER_BLOOM); gGL.color4f(1,1,1,1); LLGLDepthTest depth(GL_FALSE); - LLGLDisable blend(GL_BLEND); - LLGLDisable cull(GL_CULL_FACE); + LLGLDisable blend; + LLGLDisable cull; - enableLightsFullbright(LLColor4(1,1,1,1)); + LLGLState light_state; + enableLightsFullbright(light_state); gGL.matrixMode(LLRender::MM_PROJECTION); gGL.pushMatrix(); @@ -6590,11 +6865,19 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield, b gGL.pushMatrix(); gGL.loadIdentity(); - LLGLDisable test(GL_ALPHA_TEST); + LLGLDisable test; gGL.setColorMask(true, true); glClearColor(0,0,0,0); + //static LLRender::Context sOldContext = LLRender::Context(); + //const LLRender::Context& newContext = gGL.getContextSnapshot(); + //if (memcmp(&sOldContext, &newContext, sizeof(LLRender::Context)) != 0) + //{ + //newContext.printDiff(sOldContext); + //} + //sOldContext = newContext; + if (tiling && !LLPipeline::sRenderDeferred) //Need to coax this into working with deferred now that tiling is back. { gGlowCombineProgram.bind(); @@ -6604,7 +6887,7 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield, b //LLGLEnable stencil(GL_STENCIL_TEST); //glStencilFunc(GL_NOTEQUAL, 255, 0xFFFFFFFF); //glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); - //LLGLDisable blend(GL_BLEND); + //LLGLDisable blend; // If the snapshot is constructed from tiles, calculate which // tile we're in. @@ -6614,29 +6897,36 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield, b llassert(zoom_factor > 0.0); // Non-zero, non-negative. const F32 tile_size = 1.0/zoom_factor; - tc1 = tile*tile_size; // Top left texture coordinates - tc2 = (tile+LLVector2(1,1))*tile_size; // Bottom right texture coordinates + LLVector2 tc1 = tile*tile_size; // Top left texture coordinates + LLVector2 tc2 = (tile+LLVector2(1,1))*tile_size; // Bottom right texture coordinates - LLGLEnable blend(GL_BLEND); + LLGLEnable blend; gGL.setSceneBlendType(LLRender::BT_ADD); - - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.color4f(1,1,1,1); - gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); - gGL.vertex2f(-1,-1); - - gGL.texCoord2f(tc1.mV[0], tc2.mV[1]); - gGL.vertex2f(-1,1); - - gGL.texCoord2f(tc2.mV[0], tc1.mV[1]); - gGL.vertex2f(1,-1); - - gGL.texCoord2f(tc2.mV[0], tc2.mV[1]); - gGL.vertex2f(1,1); - - gGL.end(); + + LLPointer buff = new LLVertexBuffer(AUX_VB_MASK, 0); + buff->allocateBuffer(4, 0, true); + LLStrider vert; + LLStrider texcoord0, texcoord1; + buff->getVertexStrider(vert); + buff->getTexCoord0Strider(texcoord0); + buff->getTexCoord1Strider(texcoord1); + + vert[0].set(-1.f,-1.f,0.f); + vert[1].set(-1.f,1.f,0.f); + vert[2].set(1.f,-1.f,0.f); + vert[3].set(1.f,1.f,0.f); + + //Texcoord 0 is actually for texture 1, which is unbound and thus all components = 0,0,0,0. Just zero out the texcoords. + texcoord0[0] = texcoord0[1] = texcoord0[2] = texcoord0[3] = LLVector2::zero; + + texcoord1[0].set(tc1.mV[0], tc1.mV[1]); + texcoord1[1].set(tc1.mV[0], tc2.mV[1]); + texcoord1[2].set(tc2.mV[0], tc1.mV[1]); + texcoord1[3].set(tc2.mV[0], tc2.mV[1]); + + buff->setBuffer(AUX_VB_MASK); + buff->drawArrays(LLRender::TRIANGLE_STRIP, 0, 4); - gGL.flush(); gGL.setSceneBlendType(LLRender::BT_ALPHA); } @@ -6653,7 +6943,7 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield, b { { - LLFastTimer ftm(FTM_RENDER_BLOOM_FBO); + LL_RECORD_BLOCK_TIME(FTM_RENDER_BLOOM_FBO); mGlow[1].bindTarget(); mGlow[1].clear(); } @@ -6671,35 +6961,25 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield, b gGlowExtractProgram.uniform3f(LLShaderMgr::GLOW_LUM_WEIGHTS, lumWeights.mV[0], lumWeights.mV[1], lumWeights.mV[2]); gGlowExtractProgram.uniform3f(LLShaderMgr::GLOW_WARMTH_WEIGHTS, warmthWeights.mV[0], warmthWeights.mV[1], warmthWeights.mV[2]); gGlowExtractProgram.uniform1f(LLShaderMgr::GLOW_WARMTH_AMOUNT, warmthAmount); - LLGLEnable blend_on(GL_BLEND); - LLGLEnable test(GL_ALPHA_TEST); + LLGLEnable blend_on; + LLGLEnable test; gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA); - - mScreen.bindTexture(0, 0); + + LLRenderTarget& render_target = LLPipeline::sRenderDeferred ? mFinalScreen : mScreen; + render_target.bindTexture(0, 0); gGL.color4f(1,1,1,1); - gPipeline.enableLightsFullbright(LLColor4(1,1,1,1)); - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); - gGL.vertex2f(-1,-1); - - gGL.texCoord2f(tc1.mV[0], tc2.mV[1]); - gGL.vertex2f(-1,3); - - gGL.texCoord2f(tc2.mV[0], tc1.mV[1]); - gGL.vertex2f(3,-1); - - gGL.end(); + LLGLState light_state; + gPipeline.enableLightsFullbright(light_state); + + drawFullScreenRect(); - gGL.getTexUnit(0)->unbind(mScreen.getUsage()); + gGL.getTexUnit(0)->unbind(render_target.getUsage()); mGlow[1].flush(); } - tc1.setVec(0,0); - tc2.setVec(2,2); - // power of two between 1 and 1024 U32 glowResPow = RenderGlowResolutionPow; const U32 glow_res = llmax(1, @@ -6721,7 +7001,7 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield, b for (S32 i = 0; i < kernel; i++) { { - LLFastTimer ftm(FTM_RENDER_BLOOM_FBO); + LL_RECORD_BLOCK_TIME(FTM_RENDER_BLOOM_FBO); mGlow[i%2].bindTarget(); mGlow[i%2].clear(); } @@ -6737,17 +7017,7 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield, b gGlowProgram.uniform2f(LLShaderMgr::GLOW_DELTA, 0, delta); } - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); - gGL.vertex2f(-1,-1); - - gGL.texCoord2f(tc1.mV[0], tc2.mV[1]); - gGL.vertex2f(-1,3); - - gGL.texCoord2f(tc2.mV[0], tc1.mV[1]); - gGL.vertex2f(3,-1); - - gGL.end(); + drawFullScreenRect(); mGlow[i%2].flush(); } @@ -6756,18 +7026,12 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield, b /*if (LLRenderTarget::sUseFBO) { - LLFastTimer ftm(FTM_RENDER_BLOOM_FBO); + LL_RECORD_BLOCK_TIME(FTM_RENDER_BLOOM_FBO); glBindFramebuffer(GL_FRAMEBUFFER, 0); }*/ - gGLViewport[0] = gViewerWindow->getWorldViewRectRaw().mLeft; - gGLViewport[1] = gViewerWindow->getWorldViewRectRaw().mBottom; - gGLViewport[2] = gViewerWindow->getWorldViewRectRaw().getWidth(); - gGLViewport[3] = gViewerWindow->getWorldViewRectRaw().getHeight(); - glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]); - - tc2.setVec((F32) mScreen.getWidth(), - (F32) mScreen.getHeight()); + gGLViewport = gViewerWindow->getWorldViewRectRaw(); + gGL.setViewport(gGLViewport); gGL.flush(); @@ -6788,7 +7052,7 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield, b if (dof_enabled) { LLGLSLShader* shader = &gDeferredPostProgram; - LLGLDisable blend(GL_BLEND); + LLGLDisable blend; //depth of field focal plane calculations static F32 current_distance = 16.f; @@ -6815,13 +7079,18 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield, b { if (LLViewerJoystick::getInstance()->getOverrideCamera()) { //focus on point under cursor - focus_point = gDebugRaycastIntersection; + focus_point.set(gDebugRaycastIntersection.getF32ptr()); } else if (gAgentCamera.cameraMouselook()) { //focus on point under mouselook crosshairs - gViewerWindow->cursorIntersect(-1, -1, 512.f, NULL, -1, FALSE, - NULL, - &focus_point); + LLVector4a result; + result.clear(); + + gViewerWindow->cursorIntersect(-1, -1, 512.f, NULL, -1, FALSE, FALSE, + NULL, + &result); + + focus_point.set(result.getF32ptr()); } else if(gAgent.getRegion()) { @@ -6890,13 +7159,7 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield, b mDeferredLight.bindTarget(); shader = &gDeferredCoFProgram; - bindDeferredShader(*shader); - - S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mScreen.getUsage()); - if (channel > -1) - { - mScreen.bindTexture(0, channel); - } + bindDeferredShader(*shader, &mFinalScreen); shader->uniform1f(LLShaderMgr::DOF_FOCAL_DISTANCE, -subject_distance/1000.f); shader->uniform1f(LLShaderMgr::DOF_BLUR_CONSTANT, blur_constant); @@ -6905,19 +7168,9 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield, b shader->uniform1f(LLShaderMgr::DOF_MAX_COF, CameraMaxCoF); shader->uniform1f(LLShaderMgr::DOF_RES_SCALE, CameraDoFResScale); - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); - gGL.vertex2f(-1,-1); - - gGL.texCoord2f(tc1.mV[0], tc2.mV[1]); - gGL.vertex2f(-1,3); - - gGL.texCoord2f(tc2.mV[0], tc1.mV[1]); - gGL.vertex2f(3,-1); - - gGL.end(); + drawFullScreenRect(); - unbindDeferredShader(*shader); + unbindDeferredShader(*shader, &mFinalScreen); mDeferredLight.flush(); } @@ -6925,85 +7178,68 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield, b U32 dof_height = (U32) (mScreen.getHeight()*CameraDoFResScale); { //perform DoF sampling at half-res (preserve alpha channel) - mScreen.bindTarget(); - glViewport(0,0, dof_width, dof_height); + mFinalScreen.bindTarget(); + gGL.setViewport(0,0, dof_width, dof_height); gGL.setColorMask(true, false); shader = &gDeferredPostProgram; - bindDeferredShader(*shader); - S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mDeferredLight.getUsage()); - if (channel > -1) - { - mDeferredLight.bindTexture(0, channel); - } + bindDeferredShader(*shader, &mDeferredLight); shader->uniform1f(LLShaderMgr::DOF_MAX_COF, CameraMaxCoF); shader->uniform1f(LLShaderMgr::DOF_RES_SCALE, CameraDoFResScale); - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); - gGL.vertex2f(-1,-1); - - gGL.texCoord2f(tc1.mV[0], tc2.mV[1]); - gGL.vertex2f(-1,3); - - gGL.texCoord2f(tc2.mV[0], tc1.mV[1]); - gGL.vertex2f(3,-1); - - gGL.end(); + drawFullScreenRect(); - unbindDeferredShader(*shader); - mScreen.flush(); + unbindDeferredShader(*shader, &mDeferredLight); + mFinalScreen.flush(); gGL.setColorMask(true, true); } { //combine result based on alpha if (multisample) { - mDeferredScreen.bindTarget(); - glViewport(0, 0, mDeferredScreen.getWidth(), mDeferredScreen.getHeight()); + mScreen.bindTarget(); + gGL.setViewport(0, 0, mDeferredScreen.getWidth(), mDeferredScreen.getHeight()); } else { - gGLViewport[0] = gViewerWindow->getWorldViewRectRaw().mLeft; - gGLViewport[1] = gViewerWindow->getWorldViewRectRaw().mBottom; - gGLViewport[2] = gViewerWindow->getWorldViewRectRaw().getWidth(); - gGLViewport[3] = gViewerWindow->getWorldViewRectRaw().getHeight(); - glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]); + gGLViewport = gViewerWindow->getWorldViewRectRaw(); + gGL.setViewport(gGLViewport); } shader = &gDeferredDoFCombineProgram; - bindDeferredShader(*shader); + bindDeferredShader(*shader, &mFinalScreen); S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mScreen.getUsage()); if (channel > -1) { - mScreen.bindTexture(0, channel); gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); } + + if (!LLViewerCamera::getInstance()->cameraUnderWater()) + { + shader->uniform1f(LLShaderMgr::GLOBAL_GAMMA, 2.2f); + } else { + shader->uniform1f(LLShaderMgr::GLOBAL_GAMMA, 1.0f); + } shader->uniform1f(LLShaderMgr::DOF_MAX_COF, CameraMaxCoF); shader->uniform1f(LLShaderMgr::DOF_RES_SCALE, CameraDoFResScale); - shader->uniform1f(LLShaderMgr::DOF_WIDTH, dof_width-1); - shader->uniform1f(LLShaderMgr::DOF_HEIGHT, dof_height-1); + shader->uniform1f(LLShaderMgr::DOF_WIDTH, CameraDoFResScale - CameraDoFResScale / dof_width); + shader->uniform1f(LLShaderMgr::DOF_HEIGHT, CameraDoFResScale - CameraDoFResScale / dof_height); - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); - gGL.vertex2f(-1,-1); - - gGL.texCoord2f(tc1.mV[0], tc2.mV[1]); - gGL.vertex2f(-1,3); - - gGL.texCoord2f(tc2.mV[0], tc1.mV[1]); - gGL.vertex2f(3,-1); - - gGL.end(); + drawFullScreenRect(); - unbindDeferredShader(*shader); + if (channel > -1) + { + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + } + + unbindDeferredShader(*shader, &mFinalScreen); if (multisample) { - mDeferredScreen.flush(); + mScreen.flush(); } } } @@ -7011,35 +7247,37 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield, b { if (multisample) { - mDeferredScreen.bindTarget(); + mDeferredLight.bindTarget(); } LLGLSLShader* shader = &gDeferredPostNoDoFProgram; - bindDeferredShader(*shader); + bindDeferredShader(*shader, &mFinalScreen); S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mScreen.getUsage()); if (channel > -1) { - mScreen.bindTexture(0, channel); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); + } + + if (!LLViewerCamera::getInstance()->cameraUnderWater()) + { + shader->uniform1f(LLShaderMgr::GLOBAL_GAMMA, 2.2f); + } else { + shader->uniform1f(LLShaderMgr::GLOBAL_GAMMA, 1.0f); } - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); - gGL.vertex2f(-1,-1); - - gGL.texCoord2f(tc1.mV[0], tc2.mV[1]); - gGL.vertex2f(-1,3); - - gGL.texCoord2f(tc2.mV[0], tc1.mV[1]); - gGL.vertex2f(3,-1); - - gGL.end(); - - unbindDeferredShader(*shader); + drawFullScreenRect(); - if (multisample) + if (channel > -1) { - mDeferredScreen.flush(); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + } + + unbindDeferredShader(*shader, &mFinalScreen); + + if (multisample) + { + mDeferredLight.flush(); } } @@ -7048,31 +7286,29 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield, b //bake out texture2D with RGBL for FXAA shader mFXAABuffer.bindTarget(); - S32 width = mScreen.getWidth(); - S32 height = mScreen.getHeight(); - glViewport(0, 0, width, height); + LLRenderTarget& render_target = dof_enabled ? mScreen : mDeferredLight; + S32 width = render_target.getWidth(); + S32 height = render_target.getHeight(); + gGL.setViewport(0, 0, width, height); LLGLSLShader* shader = &gGlowCombineFXAAProgram; - shader->bind(); - shader->uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, width, height); + bindDeferredShader(*shader, &render_target); - S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mDeferredLight.getUsage()); + S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, render_target.getUsage()); if (channel > -1) { - mDeferredScreen.bindTexture(0, channel); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); } - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.vertex2f(-1,-1); - gGL.vertex2f(-1,3); - gGL.vertex2f(3,-1); - gGL.end(); + drawFullScreenRect(); - gGL.flush(); + if (channel > -1) + { + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + } - shader->disableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mDeferredLight.getUsage()); - shader->unbind(); + unbindDeferredShader(*shader, &render_target); mFXAABuffer.flush(); @@ -7086,26 +7322,15 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield, b gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); } - gGLViewport[0] = gViewerWindow->getWorldViewRectRaw().mLeft; - gGLViewport[1] = gViewerWindow->getWorldViewRectRaw().mBottom; - gGLViewport[2] = gViewerWindow->getWorldViewRectRaw().getWidth(); - gGLViewport[3] = gViewerWindow->getWorldViewRectRaw().getHeight(); - glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]); - - F32 scale_x = (F32) width/mFXAABuffer.getWidth(); - F32 scale_y = (F32) height/mFXAABuffer.getHeight(); - shader->uniform2f(LLShaderMgr::FXAA_TC_SCALE, scale_x, scale_y); - shader->uniform2f(LLShaderMgr::FXAA_RCP_SCREEN_RES, 1.f/width*scale_x, 1.f/height*scale_y); - shader->uniform4f(LLShaderMgr::FXAA_RCP_FRAME_OPT, -0.5f/width*scale_x, -0.5f/height*scale_y, 0.5f/width*scale_x, 0.5f/height*scale_y); - shader->uniform4f(LLShaderMgr::FXAA_RCP_FRAME_OPT2, -2.f/width*scale_x, -2.f/height*scale_y, 2.f/width*scale_x, 2.f/height*scale_y); + gGLViewport = gViewerWindow->getWorldViewRectRaw(); + gGL.setViewport(gGLViewport); + + shader->uniform2f(LLShaderMgr::FXAA_RCP_SCREEN_RES, 1.f/width, 1.f/height); + shader->uniform4f(LLShaderMgr::FXAA_RCP_FRAME_OPT, -0.5f/width, -0.5f/height, 0.5f/width, 0.5f/height); + shader->uniform4f(LLShaderMgr::FXAA_RCP_FRAME_OPT2, -2.f/width, -2.f/height, 2.f/width, 2.f/height); - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.vertex2f(-1,-1); - gGL.vertex2f(-1,3); - gGL.vertex2f(3,-1); - gGL.end(); + drawFullScreenRect(); - gGL.flush(); shader->unbind(); } } @@ -7116,33 +7341,7 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield, b tc2 /= (F32) res_mod; }*/ - U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TEXCOORD1; - LLPointer buff = new LLVertexBuffer(mask, 0); - buff->allocateBuffer(3,0,TRUE); - - LLStrider v; - LLStrider uv1; - LLStrider uv2; - - buff->getVertexStrider(v); - buff->getTexCoord0Strider(uv1); - buff->getTexCoord1Strider(uv2); - - uv1[0] = LLVector2(0, 0); - uv1[1] = LLVector2(0, 2); - uv1[2] = LLVector2(2, 0); - - uv2[0] = LLVector2(0, 0); - uv2[1] = LLVector2(0, tc2.mV[1]*2.f); - uv2[2] = LLVector2(tc2.mV[0]*2.f, 0); - - v[0] = LLVector3(-1,-1,0); - v[1] = LLVector3(-1,3,0); - v[2] = LLVector3(3,-1,0); - - buff->flush(); - - LLGLDisable blend(GL_BLEND); + LLGLDisable blend; if (LLGLSLShader::sNoFixedFunction) { @@ -7159,10 +7358,9 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield, b gGL.getTexUnit(0)->bind(&mGlow[1]); gGL.getTexUnit(1)->bind(&mScreen); - LLGLEnable multisample(RenderFSAASamples > 0 ? GL_MULTISAMPLE_ARB : 0); + LLGLEnable multisample(RenderFSAASamples > 0); - buff->setBuffer(mask); - buff->drawArrays(LLRender::TRIANGLE_STRIP, 0, 3); + drawFullScreenRect(); if (LLGLSLShader::sNoFixedFunction) { @@ -7190,25 +7388,18 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield, b gGL.setColorMask(true, false); - LLVector2 tc1(0,0); - LLVector2 tc2((F32) gViewerWindow->getWorldViewWidthRaw()*2, - (F32) gViewerWindow->getWorldViewHeightRaw()*2); - - LLGLEnable blend(GL_BLEND); + LLGLEnable blend; gGL.color4f(1,1,1,0.75f); gGL.getTexUnit(0)->bind(&mPhysicsDisplay); gGL.begin(LLRender::TRIANGLES); - gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); - gGL.vertex2f(-1,-1); - - gGL.texCoord2f(tc1.mV[0], tc2.mV[1]); - gGL.vertex2f(-1,3); - - gGL.texCoord2f(tc2.mV[0], tc1.mV[1]); - gGL.vertex2f(3,-1); - + gGL.texCoord2f(0.f, 0.f); + gGL.vertex2f(-1.f, -1.f); + gGL.texCoord2f(0.f,2.f); + gGL.vertex2f(-1.f, 3.f); + gGL.texCoord2f(2.f, 0.f); + gGL.vertex2f( 3.f, -1.f); gGL.end(); gGL.flush(); @@ -7233,16 +7424,21 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield, b LLVertexBuffer::unbind(); - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); + LLGLStateValidator::checkStates(); + LLGLStateValidator::checkTextureChannels(); } -static LLFastTimer::DeclareTimer FTM_BIND_DEFERRED("Bind Deferred"); +static LLTrace::BlockTimerStatHandle FTM_BIND_DEFERRED("Bind Deferred"); -void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index, U32 noise_map) +void LLPipeline::bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* diffuse_source, LLRenderTarget* light_source) { - LLFastTimer t(FTM_BIND_DEFERRED); + if (shader.mShaderClass != LLViewerShaderMgr::SHADER_DEFERRED && shader.mShaderClass != LLViewerShaderMgr::SHADER_INTERFACE) + { + shader.bind(); + return; + } + LL_RECORD_BLOCK_TIME(FTM_BIND_DEFERRED); static const LLCachedControl RenderDeferredSunWash("RenderDeferredSunWash",.5f); static const LLCachedControl RenderShadowNoise("RenderShadowNoise",-.0001f); @@ -7260,18 +7456,17 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index, U32 n static const LLCachedControl RenderSpotShadowBias("RenderSpotShadowBias",0.f); static const LLCachedControl RenderEdgeDepthCutoff("RenderEdgeDepthCutoff",.01f); static const LLCachedControl RenderEdgeNormCutoff("RenderEdgeNormCutoff",.25f); + static const LLCachedControl RenderSSAOResolutionScale("SHRenderSSAOResolutionScale",.5f); - if (noise_map == 0xFFFFFFFF) - { - noise_map = mNoiseMap; - } + diffuse_source = diffuse_source ? diffuse_source : &mDeferredScreen; + light_source = light_source ? light_source : &mDeferredLight; shader.bind(); S32 channel = 0; - channel = shader.enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mDeferredScreen.getUsage()); + channel = shader.enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, diffuse_source->getUsage()); if (channel > -1) { - mDeferredScreen.bindTexture(0,channel); + diffuse_source->bindTexture(0, channel); gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); } @@ -7289,10 +7484,21 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index, U32 n gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); } + S32 channel2 = shader.enableTexture(LLShaderMgr::DEFERRED_DOWNSAMPLED_DEPTH, mDeferredDepth.getUsage()); channel = shader.enableTexture(LLShaderMgr::DEFERRED_DEPTH, mDeferredDepth.getUsage()); - if (channel > -1) + if (channel > -1 || channel2 >= -1) { - gGL.getTexUnit(channel)->bind(&mDeferredDepth, TRUE); + if(channel > -1) + gGL.getTexUnit(channel)->bind(&mDeferredDepth, TRUE); + if(channel2 > -1) + { + F32 scale = llclamp(RenderSSAOResolutionScale.get(),.01f,1.f); + if(scale < 1.f) + gGL.getTexUnit(channel2)->bind(&mDeferredDownsampledDepth, TRUE); + else + gGL.getTexUnit(channel2)->bind(&mDeferredDepth, TRUE); //Bind full res depth instead, as downsampling is disabled if scale == 1.f + } + //gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); stop_glerror(); @@ -7301,42 +7507,31 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index, U32 n stop_glerror(); - glh::matrix4f projection = glh_get_current_projection(); - glh::matrix4f inv_proj = projection.inverse(); + LLMatrix4a inv_proj = glh_get_current_projection(); + inv_proj.invert(); - shader.uniformMatrix4fv(LLShaderMgr::INVERSE_PROJECTION_MATRIX, 1, FALSE, inv_proj.m); - shader.uniform4f(LLShaderMgr::VIEWPORT, (F32) gGLViewport[0], - (F32) gGLViewport[1], - (F32) gGLViewport[2], - (F32) gGLViewport[3]); + shader.uniformMatrix4fv(LLShaderMgr::INVERSE_PROJECTION_MATRIX, 1, FALSE, inv_proj.getF32ptr()); } channel = shader.enableTexture(LLShaderMgr::DEFERRED_NOISE); if (channel > -1) { - gGL.getTexUnit(channel)->bindManual(LLTexUnit::TT_TEXTURE, noise_map); + gGL.getTexUnit(channel)->bindManual(LLTexUnit::TT_TEXTURE, mNoiseMap->getTexName()); gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); } channel = shader.enableTexture(LLShaderMgr::DEFERRED_LIGHTFUNC); if (channel > -1) { - gGL.getTexUnit(channel)->bindManual(LLTexUnit::TT_TEXTURE, mLightFunc); + gGL.getTexUnit(channel)->bindManual(LLTexUnit::TT_TEXTURE, mLightFunc->getTexName()); } stop_glerror(); - channel = shader.enableTexture(LLShaderMgr::DEFERRED_LIGHT, mDeferredLight.getUsage()); + channel = shader.enableTexture(LLShaderMgr::DEFERRED_LIGHT, light_source->getUsage()); if (channel > -1) { - if (light_index > 0) - { - mScreen.bindTexture(0, channel); - } - else - { - mDeferredLight.bindTexture(0, channel); - } + light_source->bindTexture(0, channel); gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); } @@ -7350,7 +7545,7 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index, U32 n for (U32 i = 0; i < 4; i++) { - channel = shader.enableTexture(LLShaderMgr::DEFERRED_SHADOW0+i, LLTexUnit::TT_RECT_TEXTURE); + channel = shader.enableTexture(LLShaderMgr::DEFERRED_SHADOW0+i); stop_glerror(); if (channel > -1) { @@ -7360,8 +7555,8 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index, U32 n gGL.getTexUnit(channel)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); stop_glerror(); - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB); - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL); stop_glerror(); } } @@ -7386,20 +7581,12 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index, U32 n stop_glerror(); - F32 mat[16*6]; - for (U32 i = 0; i < 16; i++) + if(shader.getUniformLocation(LLShaderMgr::DEFERRED_SHADOW_MATRIX) >= 0) { - mat[i] = mSunShadowMatrix[0].m[i]; - mat[i+16] = mSunShadowMatrix[1].m[i]; - mat[i+32] = mSunShadowMatrix[2].m[i]; - mat[i+48] = mSunShadowMatrix[3].m[i]; - mat[i+64] = mSunShadowMatrix[4].m[i]; - mat[i+80] = mSunShadowMatrix[5].m[i]; - } - - shader.uniformMatrix4fv(LLShaderMgr::DEFERRED_SHADOW_MATRIX, 6, FALSE, mat); + shader.uniformMatrix4fv(LLShaderMgr::DEFERRED_SHADOW_MATRIX, 6, FALSE, mSunShadowMatrix[0].getF32ptr()); - stop_glerror(); + stop_glerror(); + } channel = shader.enableTexture(LLShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP); if (channel > -1) @@ -7409,7 +7596,7 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index, U32 n { cube_map->enable(channel); cube_map->bind(); - F32* m = gGLModelView; + const F32* m = glh_get_current_modelview().getF32ptr(); F32 mat[] = { m[0], m[1], m[2], m[4], m[5], m[6], @@ -7429,45 +7616,49 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index, U32 n F32 ssao_factor = RenderSSAOFactor; shader.uniform1f(LLShaderMgr::DEFERRED_SSAO_FACTOR, ssao_factor); - shader.uniform1f(LLShaderMgr::DEFERRED_SSAO_FACTOR_INV, 1.0/ssao_factor); + shader.uniform1f(LLShaderMgr::DEFERRED_SSAO_FACTOR_INV, 1.f/ssao_factor); LLVector3 ssao_effect = RenderSSAOEffect; shader.uniform1f(LLShaderMgr::DEFERRED_SSAO_EFFECT, ssao_effect[0]); - F32 shadow_offset_error = 1.f + RenderShadowOffsetError * fabsf(LLViewerCamera::getInstance()->getOrigin().mV[2]); - F32 shadow_bias_error = 1.f + RenderShadowBiasError * fabsf(LLViewerCamera::getInstance()->getOrigin().mV[2]); + shader.uniform2f(LLShaderMgr::DEFERRED_KERN_SCALE, 1.f / mDeferredScreen.getWidth(), 1.f / mDeferredScreen.getHeight()); + shader.uniform2f(LLShaderMgr::DEFERRED_NOISE_SCALE, mDeferredScreen.getWidth() / NOISE_MAP_RES, mDeferredScreen.getHeight() / NOISE_MAP_RES); + + //F32 shadow_offset_error = 1.f + RenderShadowOffsetError * fabsf(LLViewerCamera::getInstance()->getOrigin().mV[2]); + F32 shadow_bias_error = RenderShadowBiasError * fabsf(LLViewerCamera::getInstance()->getOrigin().mV[2])/3000.f; - shader.uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, mDeferredScreen.getWidth(), mDeferredScreen.getHeight()); shader.uniform1f(LLShaderMgr::DEFERRED_NEAR_CLIP, LLViewerCamera::getInstance()->getNear()*2.f); - shader.uniform1f (LLShaderMgr::DEFERRED_SHADOW_OFFSET, RenderShadowOffset*shadow_offset_error); - shader.uniform1f(LLShaderMgr::DEFERRED_SHADOW_BIAS, RenderShadowBias*shadow_bias_error); + shader.uniform1f (LLShaderMgr::DEFERRED_SHADOW_OFFSET, RenderShadowOffset); //*shadow_offset_error); + shader.uniform1f(LLShaderMgr::DEFERRED_SHADOW_BIAS, RenderShadowBias+shadow_bias_error); shader.uniform1f(LLShaderMgr::DEFERRED_SPOT_SHADOW_OFFSET, RenderSpotShadowOffset); shader.uniform1f(LLShaderMgr::DEFERRED_SPOT_SHADOW_BIAS, RenderSpotShadowBias); - shader.uniform3fv(LLShaderMgr::DEFERRED_SUN_DIR, 1, mTransformedSunDir.mV); + shader.uniform3fv(LLShaderMgr::DEFERRED_SUN_DIR, 1, mTransformedSunDir.getF32ptr()); shader.uniform2f(LLShaderMgr::DEFERRED_SHADOW_RES, mShadow[0].getWidth(), mShadow[0].getHeight()); shader.uniform2f(LLShaderMgr::DEFERRED_PROJ_SHADOW_RES, mShadow[4].getWidth(), mShadow[4].getHeight()); shader.uniform1f(LLShaderMgr::DEFERRED_DEPTH_CUTOFF, RenderEdgeDepthCutoff); shader.uniform1f(LLShaderMgr::DEFERRED_NORM_CUTOFF, RenderEdgeNormCutoff); - if (shader.getUniformLocation("norm_mat") >= 0) + if (shader.getUniformLocation(LLShaderMgr::DEFERRED_NORM_MATRIX) >= 0) { - glh::matrix4f norm_mat = glh_get_current_modelview().inverse().transpose(); - shader.uniformMatrix4fv("norm_mat", 1, FALSE, norm_mat.m); + LLMatrix4a norm_mat = glh_get_current_modelview(); + norm_mat.invert(); + norm_mat.transpose(); + shader.uniformMatrix4fv(LLShaderMgr::DEFERRED_NORM_MATRIX, 1, FALSE, norm_mat.getF32ptr()); } } -static LLFastTimer::DeclareTimer FTM_GI_TRACE("Trace"); -static LLFastTimer::DeclareTimer FTM_GI_GATHER("Gather"); -static LLFastTimer::DeclareTimer FTM_SUN_SHADOW("Shadow Map"); -static LLFastTimer::DeclareTimer FTM_SOFTEN_SHADOW("Shadow Soften"); -static LLFastTimer::DeclareTimer FTM_EDGE_DETECTION("Find Edges"); -static LLFastTimer::DeclareTimer FTM_LOCAL_LIGHTS("Local Lights"); -static LLFastTimer::DeclareTimer FTM_ATMOSPHERICS("Atmospherics"); -static LLFastTimer::DeclareTimer FTM_FULLSCREEN_LIGHTS("Fullscreen Lights"); -static LLFastTimer::DeclareTimer FTM_PROJECTORS("Projectors"); -static LLFastTimer::DeclareTimer FTM_POST("Post"); +static LLTrace::BlockTimerStatHandle FTM_GI_TRACE("Trace"); +static LLTrace::BlockTimerStatHandle FTM_GI_GATHER("Gather"); +static LLTrace::BlockTimerStatHandle FTM_SUN_SHADOW("Shadow Map"); +static LLTrace::BlockTimerStatHandle FTM_SOFTEN_SHADOW("Shadow Soften"); +static LLTrace::BlockTimerStatHandle FTM_EDGE_DETECTION("Find Edges"); +static LLTrace::BlockTimerStatHandle FTM_LOCAL_LIGHTS("Local Lights"); +static LLTrace::BlockTimerStatHandle FTM_ATMOSPHERICS("Atmospherics"); +static LLTrace::BlockTimerStatHandle FTM_FULLSCREEN_LIGHTS("Fullscreen Lights"); +static LLTrace::BlockTimerStatHandle FTM_PROJECTORS("Projectors"); +static LLTrace::BlockTimerStatHandle FTM_POST("Post"); void LLPipeline::renderDeferredLighting() @@ -7479,6 +7670,7 @@ void LLPipeline::renderDeferredLighting() static const LLCachedControl RenderFSAASamples("RenderFSAASamples",0); static const LLCachedControl RenderDeferredSSAO("RenderDeferredSSAO",false); + static const LLCachedControl RenderSSAOResolutionScale("SHRenderSSAOResolutionScale",.5f); static const LLCachedControl RenderShadowDetail("RenderShadowDetail",0); static const LLCachedControl RenderShadowGaussian("RenderShadowGaussian",LLVector3(3.f,2.f,0.f)); static const LLCachedControl RenderShadowBlurSize("RenderShadowBlurSize",1.4f); @@ -7487,7 +7679,7 @@ void LLPipeline::renderDeferredLighting() static const LLCachedControl RenderLocalLights("RenderLocalLights",false); { - LLFastTimer ftm(FTM_RENDER_DEFERRED); + LL_RECORD_BLOCK_TIME(FTM_RENDER_DEFERRED); LLViewerCamera* camera = LLViewerCamera::getInstance(); { @@ -7496,7 +7688,7 @@ void LLPipeline::renderDeferredLighting() 0, 0, mDeferredDepth.getWidth(), mDeferredDepth.getHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST); } - LLGLEnable multisample(RenderFSAASamples > 0 ? GL_MULTISAMPLE_ARB : 0); + LLGLEnable multisample(RenderFSAASamples > 0); if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD)) { @@ -7504,7 +7696,7 @@ void LLPipeline::renderDeferredLighting() } //ati doesn't seem to love actually using the stencil buffer on FBO's - LLGLDisable stencil(GL_STENCIL_TEST); + LLGLDisable stencil; //glStencilFunc(GL_EQUAL, 1, 0xFFFFFFFF); //glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); @@ -7513,34 +7705,15 @@ void LLPipeline::renderDeferredLighting() //draw a cube around every light LLVertexBuffer::unbind(); - LLGLEnable cull(GL_CULL_FACE); - LLGLEnable blend(GL_BLEND); + LLGLEnable cull; + LLGLEnable blend; - glh::matrix4f mat = glh_copy_matrix(gGLModelView); - - if(mDeferredVB.isNull()) { - mDeferredVB = new LLVertexBuffer(DEFERRED_VB_MASK, 0); - mDeferredVB->allocateBuffer(8, 0, true); + mTransformedSunDir.load3(getSunDir().mV); + glh_get_current_modelview().rotate(mTransformedSunDir,mTransformedSunDir); } - LLStrider vert; - mDeferredVB->getVertexStrider(vert); - LLStrider tc0; - LLStrider tc1; - mDeferredVB->getTexCoord0Strider(tc0); - mDeferredVB->getTexCoord1Strider(tc1); - vert[0].set(-1,1,0); - vert[1].set(-1,-3,0); - vert[2].set(3,1,0); - - { - setupHWLights(NULL); //to set mSunDir; - LLVector4 dir(mSunDir, 0.f); - glh::vec4f tc(dir.mV); - mat.mult_matrix_vec(tc); - mTransformedSunDir.set(tc.v); - } + llassert_always(LLGLState::checkEnabled()); gGL.pushMatrix(); gGL.loadIdentity(); @@ -7548,60 +7721,77 @@ void LLPipeline::renderDeferredLighting() gGL.pushMatrix(); gGL.loadIdentity(); + if (RenderDeferredSSAO) + { + F32 ssao_scale = llclamp(RenderSSAOResolutionScale.get(),.01f,1.f); + + LLGLDisable blend; + + //Downsample with fullscreen quad. GL_NEAREST + if(ssao_scale < 1.f) + { + mDeferredDownsampledDepth.bindTarget(); + mDeferredDownsampledDepth.clear(GL_DEPTH_BUFFER_BIT); + bindDeferredShader(gDeferredDownsampleDepthNearestProgram); + { + LLGLDepthTest depth(GL_TRUE, GL_TRUE, GL_ALWAYS); + drawFullScreenRect(); + } + mDeferredDownsampledDepth.flush(); + unbindDeferredShader(gDeferredDownsampleDepthNearestProgram); + } + + //Run SSAO + { + mScreen.bindTarget(); + glClearColor(1,1,1,1); + mScreen.clear(GL_COLOR_BUFFER_BIT); + glClearColor(0,0,0,0); + bindDeferredShader(gDeferredSSAOProgram); + if(ssao_scale < 1.f) + { + gGL.setViewport(0,0,mDeferredDownsampledDepth.getWidth(),mDeferredDownsampledDepth.getHeight()); + } + { + LLGLDepthTest depth(GL_FALSE); + drawFullScreenRect(); + } + mScreen.flush(); + unbindDeferredShader(gDeferredSSAOProgram); + } + } + if (RenderDeferredSSAO || RenderShadowDetail > 0) { mDeferredLight.bindTarget(); { //paint shadow/SSAO light map (direct lighting lightmap) - LLFastTimer ftm(FTM_SUN_SHADOW); - bindDeferredShader(gDeferredSunProgram, 0); - mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); + LL_RECORD_BLOCK_TIME(FTM_SUN_SHADOW); + bindDeferredShader(gDeferredSunProgram); glClearColor(1,1,1,1); mDeferredLight.clear(GL_COLOR_BUFFER_BIT); glClearColor(0,0,0,0); - glh::matrix4f inv_trans = glh_get_current_modelview().inverse().transpose(); + F32 ssao_scale = llclamp(RenderSSAOResolutionScale.get(), .01f, 1.f); + gDeferredSunProgram.uniform2f(LLShaderMgr::DEFERRED_SSAO_SCALE, ssao_scale, ssao_scale); - const U32 slice = 32; - F32 offset[slice*3]; - for (U32 i = 0; i < 4; i++) + //Enable bilinear filtering, as the screen tex resolution may not match current framebuffer resolution. Eg, half-res SSAO + // diffuse map should only be found if the sun shader is the SSAO variant. + S32 channel = gDeferredSunProgram.enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mScreen.getUsage()); + if (channel > -1) { - for (U32 j = 0; j < 8; j++) - { - glh::vec3f v; - v.set_value(sinf(6.284f/8*j), cosf(6.284f/8*j), -(F32) i); -#if 0 - // Singu note: the call to mult_matrix_vec can crash, because it attempts to divide by zero. - v.normalize(); - inv_trans.mult_matrix_vec(v); -#else - // However, because afterwards we normalize the vector anyway, there is an alternative - // way to calculate the same thing without the division (which happens to be faster, too). - glh::vec4f src(v, v.length()); // Make a copy of the source and extent it with its length. - glh::vec4f dst; - inv_trans.mult_matrix_vec(src, dst); // Do a normal 4D multiplication. - dst.get_value(v[0], v[1], v[2], dst[3]); // Copy the first 3 coordinates to v. - // At this point v is equal to what it used to be, except for a constant factor (v.length() * dst[3]), - // but that doesn't matter because the next step is normalizaton. The old computation would crash - // if v.length() is zero in the commented out v.normalize(), and in inv_trans.mult_matrix_vec(v) - // if dst[3] is zero (which some times happens). Now we will only crash if v.length() is zero - // and well in the next line (but this never happens). --Aleric -#endif - v.normalize(); - offset[(i*8+j)*3+0] = v.v[0]; - offset[(i*8+j)*3+1] = v.v[2]; - offset[(i*8+j)*3+2] = v.v[1]; - } + mScreen.bindTexture(0,channel); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); } - - gDeferredSunProgram.uniform3fv("offset", slice, offset); - gDeferredSunProgram.uniform2f("screenRes", mDeferredLight.getWidth(), mDeferredLight.getHeight()); { - LLGLDisable blend(GL_BLEND); + LLGLDisable blend; LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS); - stop_glerror(); - mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3); - stop_glerror(); + drawFullScreenRect(); + } + + if (channel > -1) + { + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); } unbindDeferredShader(gDeferredSunProgram); @@ -7609,9 +7799,10 @@ void LLPipeline::renderDeferredLighting() mDeferredLight.flush(); } - if (RenderDeferredSSAO) + static const LLCachedControl SHAlwaysSoftenShadows("SHAlwaysSoftenShadows",true); + if (RenderDeferredSSAO || (RenderShadowDetail > 0 && SHAlwaysSoftenShadows)) { //soften direct lighting lightmap - LLFastTimer ftm(FTM_SOFTEN_SHADOW); + LL_RECORD_BLOCK_TIME(FTM_SOFTEN_SHADOW); //blur lightmap mScreen.bindTarget(); glClearColor(1,1,1,1); @@ -7619,58 +7810,581 @@ void LLPipeline::renderDeferredLighting() glClearColor(0,0,0,0); bindDeferredShader(gDeferredBlurLightProgram); - mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); LLVector3 go = RenderShadowGaussian; const U32 kern_length = 4; F32 blur_size = RenderShadowBlurSize; F32 dist_factor = RenderShadowBlurDistFactor; - // sample symmetrically with the middle sample falling exactly on 0.0 - F32 x = 0.f; + gDeferredBlurLightProgram.uniform2f(sDelta, (blur_size * (kern_length / 2.f - 0.5f)) / mScreen.getWidth(), 0.f); + gDeferredBlurLightProgram.uniform1f(sDistFactor, dist_factor); + + { + LLGLDisable blend; + LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS); + drawFullScreenRect(); + } + + mScreen.flush(); + unbindDeferredShader(gDeferredBlurLightProgram); + + bindDeferredShader(gDeferredBlurLightProgram, &mScreen, &mScreen); + mDeferredLight.bindTarget(); + + gDeferredBlurLightProgram.uniform2f(sDelta, 0.f, (blur_size * (kern_length / 2.f - 0.5f)) / mScreen.getHeight()); + + { + LLGLDisable blend; + LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS); + drawFullScreenRect(); + } + mDeferredLight.flush(); + unbindDeferredShader(gDeferredBlurLightProgram, &mScreen, &mScreen); + } + + stop_glerror(); + gGL.popMatrix(); + stop_glerror(); + gGL.matrixMode(LLRender::MM_MODELVIEW); + stop_glerror(); + gGL.popMatrix(); + stop_glerror(); + + mScreen.bindTarget(); + // clear color buffer here - zeroing alpha (glow) is important or it will accumulate against sky + glClearColor(0,0,0,0); + mScreen.clear(GL_COLOR_BUFFER_BIT); + + if (RenderDeferredAtmospheric) + { //apply sunlight contribution + LL_RECORD_BLOCK_TIME(FTM_ATMOSPHERICS); + bindDeferredShader(LLPipeline::sUnderWaterRender ? gDeferredSoftenWaterProgram : gDeferredSoftenProgram); + { + LLGLDepthTest depth(GL_FALSE); + LLGLDisable blend; + LLGLDisable test; + + //full screen blit + gGL.pushMatrix(); + gGL.loadIdentity(); + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.pushMatrix(); + gGL.loadIdentity(); + + drawFullScreenRect(); + + gGL.popMatrix(); + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.popMatrix(); + } + + unbindDeferredShader(LLPipeline::sUnderWaterRender ? gDeferredSoftenWaterProgram : gDeferredSoftenProgram); + } + + { //render non-deferred geometry (fullbright, alpha, etc) + LLGLDisable blend; + LLGLDisable stencil; + gGL.setSceneBlendType(LLRender::BT_ALPHA); + + gPipeline.pushRenderTypeMask(); + + gPipeline.andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY, +#if ENABLE_CLASSIC_CLOUDS + LLPipeline::RENDER_TYPE_CLASSIC_CLOUDS, +#endif + LLPipeline::RENDER_TYPE_WL_CLOUDS, + LLPipeline::RENDER_TYPE_WL_SKY, + LLPipeline::END_RENDER_TYPES); + + + renderGeomPostDeferred(*LLViewerCamera::getInstance(), false); + gPipeline.popRenderTypeMask(); + } + + BOOL render_local = RenderLocalLights; + + if (render_local) + { + gGL.setSceneBlendType(LLRender::BT_ADD); + std::list fullscreen_lights; + LLDrawable::drawable_list_t spot_lights; + LLDrawable::drawable_list_t fullscreen_spot_lights; + + for (U32 i = 0; i < 2; i++) + { + mTargetShadowSpotLight[i] = NULL; + } + + std::list light_colors; + + LLVertexBuffer::unbind(); + + { + bindDeferredShader(gDeferredLightProgram); + + if (mCubeVB.isNull()) + { + mCubeVB = ll_create_cube_vb(LLVertexBuffer::MAP_VERTEX, GL_STATIC_DRAW_ARB); + } + + mCubeVB->setBuffer(LLVertexBuffer::MAP_VERTEX); + + LLGLDepthTest depth(GL_TRUE, GL_FALSE); + for (LLDrawable::drawable_set_t::iterator iter = mLights.begin(); iter != mLights.end(); ++iter) + { + LLDrawable* drawablep = *iter; + + LLVOVolume* volume = drawablep->getVOVolume(); + if (!volume) + { + continue; + } + + if (volume->isAttachment()) + { + if (!sRenderAttachedLights) + { + continue; + } + } + + const LLViewerObject *vobj = drawablep->getVObj(); + if(vobj && vobj->getAvatar() + && (vobj->getAvatar()->isTooComplex())) + { + continue; + } + + LLVector4a center; + center.load3(drawablep->getPositionAgent().mV); + const F32* c = center.getF32ptr(); + F32 s = volume->getLightRadius()*1.5f; + + LLColor3 col = volume->getLightColor(); + + if (col.magVecSquared() < 0.001f) + { + continue; + } + + if (s <= 0.001f) + { + continue; + } + + LLVector4a sa; + sa.splat(s); + if (camera->AABBInFrustumNoFarClip(center, sa) == 0) + { + continue; + } + + sVisibleLightCount++; + + const auto& camera_origin = camera->getOrigin(); + if (camera_origin.mV[0] > c[0] + s + 0.2f || + camera_origin.mV[0] < c[0] - s - 0.2f || + camera_origin.mV[1] > c[1] + s + 0.2f || + camera_origin.mV[1] < c[1] - s - 0.2f || + camera_origin.mV[2] > c[2] + s + 0.2f || + camera_origin.mV[2] < c[2] - s - 0.2f) + { //draw box if camera is outside box + if (render_local) + { + if (volume->isLightSpotlight()) + { + drawablep->getVOVolume()->updateSpotLightPriority(); + spot_lights.push_back(drawablep); + continue; + } + + LL_RECORD_BLOCK_TIME(FTM_LOCAL_LIGHTS); + gDeferredLightProgram.uniform3fv(LLShaderMgr::LIGHT_CENTER, 1, c); + gDeferredLightProgram.uniform1f(LLShaderMgr::LIGHT_SIZE, s); + gDeferredLightProgram.uniform3fv(LLShaderMgr::DIFFUSE_COLOR, 1, col.mV); + gDeferredLightProgram.uniform1f(LLShaderMgr::LIGHT_FALLOFF, volume->getLightFalloff()*0.5f); + + mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, center)); + stop_glerror(); + } + } + else + { + if (volume->isLightSpotlight()) + { + drawablep->getVOVolume()->updateSpotLightPriority(); + fullscreen_spot_lights.push_back(drawablep); + continue; + } + + glh_get_current_modelview().affineTransform(center,center); + + LLVector4 tc(center.getF32ptr()); + tc.mV[VW] = s; + fullscreen_lights.push_back(tc); + light_colors.push_back(LLVector4(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f)); + } + } + unbindDeferredShader(gDeferredLightProgram); + } + + if (!spot_lights.empty()) + { + LLGLDepthTest depth(GL_TRUE, GL_FALSE); + bindDeferredShader(gDeferredSpotLightProgram); + + mCubeVB->setBuffer(LLVertexBuffer::MAP_VERTEX); + + gDeferredSpotLightProgram.enableTexture(LLShaderMgr::DEFERRED_PROJECTION); + + for (LLDrawable::drawable_list_t::iterator iter = spot_lights.begin(); iter != spot_lights.end(); ++iter) + { + LL_RECORD_BLOCK_TIME(FTM_PROJECTORS); + LLDrawable* drawablep = *iter; + + LLVOVolume* volume = drawablep->getVOVolume(); + + LLVector4a center; + center.load3(drawablep->getPositionAgent().mV); + const F32* c = center.getF32ptr(); + F32 s = volume->getLightRadius()*1.5f; + + sVisibleLightCount++; + + setupSpotLight(gDeferredSpotLightProgram, drawablep); + + LLColor3 col = volume->getLightColor(); + + gDeferredSpotLightProgram.uniform3fv(LLShaderMgr::LIGHT_CENTER, 1, c); + gDeferredSpotLightProgram.uniform1f(LLShaderMgr::LIGHT_SIZE, s); + gDeferredSpotLightProgram.uniform3fv(LLShaderMgr::DIFFUSE_COLOR, 1, col.mV); + gDeferredSpotLightProgram.uniform1f(LLShaderMgr::LIGHT_FALLOFF, volume->getLightFalloff()*0.5f); + + mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, center)); + } + gDeferredSpotLightProgram.disableTexture(LLShaderMgr::DEFERRED_PROJECTION); + unbindDeferredShader(gDeferredSpotLightProgram); + } + + { + LLGLDepthTest depth(GL_FALSE); + + //full screen blit + gGL.pushMatrix(); + gGL.loadIdentity(); + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.pushMatrix(); + gGL.loadIdentity(); + + U32 count = 0; + + const U32 max_count = LL_DEFERRED_MULTI_LIGHT_COUNT; + LLVector4 light[max_count]; + LLVector4 col[max_count]; + + F32 far_z = 0.f; + + while (!fullscreen_lights.empty()) + { + LL_RECORD_BLOCK_TIME(FTM_FULLSCREEN_LIGHTS); + light[count] = fullscreen_lights.front(); + fullscreen_lights.pop_front(); + col[count] = light_colors.front(); + light_colors.pop_front(); + + /*col[count].mV[0] = powf(col[count].mV[0], 2.2f); + col[count].mV[1] = powf(col[count].mV[1], 2.2f); + col[count].mV[2] = powf(col[count].mV[2], 2.2f);*/ + + far_z = llmin(light[count].mV[2]-light[count].mV[3], far_z); + //col[count] = pow4fsrgb(col[count], 2.2f); + count++; + if (count == max_count || fullscreen_lights.empty()) + { + U32 idx = count-1; + bindDeferredShader(gDeferredMultiLightProgram[idx]); + gDeferredMultiLightProgram[idx].uniform1i(LLShaderMgr::MULTI_LIGHT_COUNT, count); + gDeferredMultiLightProgram[idx].uniform4fv(LLShaderMgr::MULTI_LIGHT, count, (GLfloat*) light); + gDeferredMultiLightProgram[idx].uniform4fv(LLShaderMgr::MULTI_LIGHT_COL, count, (GLfloat*) col); + gDeferredMultiLightProgram[idx].uniform1f(LLShaderMgr::MULTI_LIGHT_FAR_Z, far_z); + far_z = 0.f; + count = 0; + drawFullScreenRect(); + unbindDeferredShader(gDeferredMultiLightProgram[idx]); + } + } + + bindDeferredShader(gDeferredMultiSpotLightProgram); + + gDeferredMultiSpotLightProgram.enableTexture(LLShaderMgr::DEFERRED_PROJECTION); + + for (LLDrawable::drawable_list_t::iterator iter = fullscreen_spot_lights.begin(); iter != fullscreen_spot_lights.end(); ++iter) + { + LL_RECORD_BLOCK_TIME(FTM_PROJECTORS); + LLDrawable* drawablep = *iter; + + LLVOVolume* volume = drawablep->getVOVolume(); + + LLVector4a center; + center.load3(drawablep->getPositionAgent().mV); + F32 s = volume->getLightRadius()*1.5f; + + sVisibleLightCount++; + + glh_get_current_modelview().affineTransform(center,center); + + setupSpotLight(gDeferredMultiSpotLightProgram, drawablep); + + LLColor3 col = volume->getLightColor(); + + /*col.mV[0] = powf(col.mV[0], 2.2f); + col.mV[1] = powf(col.mV[1], 2.2f); + col.mV[2] = powf(col.mV[2], 2.2f);*/ + + gDeferredMultiSpotLightProgram.uniform3fv(LLShaderMgr::LIGHT_CENTER, 1, center.getF32ptr()); + gDeferredMultiSpotLightProgram.uniform1f(LLShaderMgr::LIGHT_SIZE, s); + gDeferredMultiSpotLightProgram.uniform3fv(LLShaderMgr::DIFFUSE_COLOR, 1, col.mV); + gDeferredMultiSpotLightProgram.uniform1f(LLShaderMgr::LIGHT_FALLOFF, volume->getLightFalloff()*0.5f); + drawFullScreenRect(); + } + + gDeferredMultiSpotLightProgram.disableTexture(LLShaderMgr::DEFERRED_PROJECTION); + unbindDeferredShader(gDeferredMultiSpotLightProgram); + + gGL.popMatrix(); + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.popMatrix(); + } + gGL.setSceneBlendType(LLRender::BT_ALPHA); + } + + gGL.setColorMask(true, true); + } + + mScreen.flush(); + + //gamma correct lighting + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.pushMatrix(); + gGL.loadIdentity(); + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.pushMatrix(); + gGL.loadIdentity(); + + { + LLGLDepthTest depth(GL_FALSE, GL_FALSE); + + mFinalScreen.bindTarget(); + // Apply gamma correction to the frame here. + gDeferredPostGammaCorrectProgram.bind(); + S32 channel = gDeferredPostGammaCorrectProgram.enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mScreen.getUsage()); + if (channel > -1) + { + mScreen.bindTexture(0,channel); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + } + + drawFullScreenRect(); + + gGL.getTexUnit(channel)->unbind(mScreen.getUsage()); + gDeferredPostGammaCorrectProgram.unbind(); + mFinalScreen.flush(); + } + + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.popMatrix(); + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.popMatrix(); + + mFinalScreen.bindTarget(); + + { //render non-deferred geometry (alpha, fullbright, glow) + LLGLDisable blend; + LLGLDisable stencil; + + pushRenderTypeMask(); + andRenderTypeMask(LLPipeline::RENDER_TYPE_ALPHA, + LLPipeline::RENDER_TYPE_FULLBRIGHT, + LLPipeline::RENDER_TYPE_VOLUME, + LLPipeline::RENDER_TYPE_GLOW, + LLPipeline::RENDER_TYPE_BUMP, + LLPipeline::RENDER_TYPE_PASS_SIMPLE, + LLPipeline::RENDER_TYPE_PASS_ALPHA, + LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK, + LLPipeline::RENDER_TYPE_PASS_BUMP, + LLPipeline::RENDER_TYPE_PASS_POST_BUMP, + LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT, + LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK, + LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY, + LLPipeline::RENDER_TYPE_PASS_GLOW, + LLPipeline::RENDER_TYPE_PASS_GRASS, + LLPipeline::RENDER_TYPE_PASS_SHINY, + LLPipeline::RENDER_TYPE_AVATAR, + LLPipeline::RENDER_TYPE_ALPHA_MASK, + LLPipeline::RENDER_TYPE_FULLBRIGHT_ALPHA_MASK, + END_RENDER_TYPES); + + renderGeomPostDeferred(*LLViewerCamera::getInstance()); + popRenderTypeMask(); + } + + { + //render highlights, etc. + renderHighlights(); + mHighlightFaces.clear(); + + renderDebug(); + + LLVertexBuffer::unbind(); + + if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI)) + { + // Render debugging beacons. + gObjectList.renderObjectBeacons(); + gObjectList.resetObjectBeacons(); + } + } + + mFinalScreen.flush(); + +} + +void LLPipeline::renderDeferredLightingToRT(LLRenderTarget* target) +{ + if (!sCull) + { + return; + } + + static const LLCachedControl RenderFSAASamples("RenderFSAASamples",0); + static const LLCachedControl RenderDeferredSSAO("RenderDeferredSSAO",false); + static const LLCachedControl RenderSSAOResolutionScale("SHRenderSSAOResolutionScale",.5f); + static const LLCachedControl RenderShadowDetail("RenderShadowDetail",0); + static const LLCachedControl RenderShadowGaussian("RenderShadowGaussian",LLVector3(3.f,2.f,0.f)); + static const LLCachedControl RenderShadowBlurSize("RenderShadowBlurSize",1.4f); + static const LLCachedControl RenderShadowBlurDistFactor("RenderShadowBlurDistFactor",.1f); + static const LLCachedControl RenderDeferredAtmospheric("RenderDeferredAtmospheric",false); + static const LLCachedControl RenderLocalLights("RenderLocalLights",false); + + { + LL_RECORD_BLOCK_TIME(FTM_RENDER_DEFERRED); + + LLViewerCamera* camera = LLViewerCamera::getInstance(); + { + LLGLDepthTest depth(GL_TRUE); + mDeferredDepth.copyContents(mDeferredScreen, 0, 0, mDeferredScreen.getWidth(), mDeferredScreen.getHeight(), + 0, 0, mDeferredDepth.getWidth(), mDeferredDepth.getHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST); + } + + LLGLEnable multisample(RenderFSAASamples > 0); + + if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD)) + { + gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD); + } + + //ati doesn't seem to love actually using the stencil buffer on FBO's + LLGLDisable stencil; + //glStencilFunc(GL_EQUAL, 1, 0xFFFFFFFF); + //glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + + gGL.setColorMask(true, true); + + //draw a cube around every light + LLVertexBuffer::unbind(); + + LLGLEnable cull; + LLGLEnable blend; + + { + mTransformedSunDir.load3(getSunDir().mV); + glh_get_current_modelview().rotate(mTransformedSunDir,mTransformedSunDir); + } + + gGL.pushMatrix(); + gGL.loadIdentity(); + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.pushMatrix(); + gGL.loadIdentity(); + + if (RenderDeferredSSAO) + { + F32 ssao_scale = llclamp(RenderSSAOResolutionScale.get(),.01f,1.f); - LLVector3 gauss[32]; // xweight, yweight, offset + LLGLDisable blend; - for (U32 i = 0; i < kern_length; i++) + //Downsample with fullscreen quad. GL_NEAREST + if(ssao_scale < 1.f) { - gauss[i].mV[0] = llgaussian(x, go.mV[0]); - gauss[i].mV[1] = llgaussian(x, go.mV[1]); - gauss[i].mV[2] = x; - x += 1.f; + mDeferredDownsampledDepth.bindTarget(); + mDeferredDownsampledDepth.clear(GL_DEPTH_BUFFER_BIT); + bindDeferredShader(gDeferredDownsampleDepthNearestProgram); + { + LLGLDepthTest depth(GL_TRUE, GL_TRUE, GL_ALWAYS); + drawFullScreenRect(); + } + mDeferredDownsampledDepth.flush(); + unbindDeferredShader(gDeferredDownsampleDepthNearestProgram); } - gDeferredBlurLightProgram.uniform2f("delta", 1.f, 0.f); - gDeferredBlurLightProgram.uniform1f("dist_factor", dist_factor); - gDeferredBlurLightProgram.uniform3fv("kern", kern_length, gauss[0].mV); - gDeferredBlurLightProgram.uniform1f("kern_scale", blur_size * (kern_length/2.f - 0.5f)); - + //Run SSAO { - LLGLDisable blend(GL_BLEND); - LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS); - stop_glerror(); - mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3); - stop_glerror(); + mScreen.bindTarget(); + glClearColor(1,1,1,1); + mScreen.clear(GL_COLOR_BUFFER_BIT); + glClearColor(0,0,0,0); + bindDeferredShader(gDeferredSSAOProgram); + if(ssao_scale < 1.f) + { + gGL.setViewport(0,0,mDeferredDownsampledDepth.getWidth(),mDeferredDownsampledDepth.getHeight()); + } + { + LLGLDepthTest depth(GL_FALSE); + drawFullScreenRect(); + } + mScreen.flush(); + unbindDeferredShader(gDeferredSSAOProgram); } - - mScreen.flush(); - unbindDeferredShader(gDeferredBlurLightProgram); + } - bindDeferredShader(gDeferredBlurLightProgram, 1); - mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); + if (RenderDeferredSSAO || RenderShadowDetail > 0) + { mDeferredLight.bindTarget(); + { //paint shadow/SSAO light map (direct lighting lightmap) + LL_RECORD_BLOCK_TIME(FTM_SUN_SHADOW); + bindDeferredShader(gDeferredSunProgram); - gDeferredBlurLightProgram.uniform2f("delta", 0.f, 1.f); + F32 ssao_scale = llclamp(RenderSSAOResolutionScale.get(), .01f, 1.f); + gDeferredSunProgram.uniform2f(LLShaderMgr::DEFERRED_SSAO_SCALE, ssao_scale, ssao_scale); - { - LLGLDisable blend(GL_BLEND); - LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS); - stop_glerror(); - mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3); - stop_glerror(); + glClearColor(1,1,1,1); + mDeferredLight.clear(GL_COLOR_BUFFER_BIT); + glClearColor(0,0,0,0); + + //Enable bilinear filtering, as the screen tex resolution may not match current framebuffer resolution. Eg, half-res SSAO + // diffuse map should only be found if the sun shader is the SSAO variant. + S32 channel = gDeferredSunProgram.enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mScreen.getUsage()); + if (channel > -1) + { + mScreen.bindTexture(0,channel); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); + } + + { + LLGLDisable blend; + LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS); + drawFullScreenRect(); + } + + if (channel > -1) + { + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + } + + unbindDeferredShader(gDeferredSunProgram); } mDeferredLight.flush(); - unbindDeferredShader(gDeferredBlurLightProgram); } - + stop_glerror(); gGL.popMatrix(); stop_glerror(); @@ -7679,23 +8393,20 @@ void LLPipeline::renderDeferredLighting() gGL.popMatrix(); stop_glerror(); - //copy depth and stencil from deferred screen - //mScreen.copyContents(mDeferredScreen, 0, 0, mDeferredScreen.getWidth(), mDeferredScreen.getHeight(), - // 0, 0, mScreen.getWidth(), mScreen.getHeight(), GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST); + target->bindTarget(); - mScreen.bindTarget(); - // clear color buffer here - zeroing alpha (glow) is important or it will accumulate against sky + //clear color buffer here - zeroing alpha (glow) is important or it will accumulate against sky glClearColor(0,0,0,0); - mScreen.clear(GL_COLOR_BUFFER_BIT); + target->clear(GL_COLOR_BUFFER_BIT); if (RenderDeferredAtmospheric) { //apply sunlight contribution - LLFastTimer ftm(FTM_ATMOSPHERICS); + LL_RECORD_BLOCK_TIME(FTM_ATMOSPHERICS); bindDeferredShader(gDeferredSoftenProgram); { LLGLDepthTest depth(GL_FALSE); - LLGLDisable blend(GL_BLEND); - LLGLDisable test(GL_ALPHA_TEST); + LLGLDisable blend; + LLGLDisable test; //full screen blit gGL.pushMatrix(); @@ -7704,9 +8415,7 @@ void LLPipeline::renderDeferredLighting() gGL.pushMatrix(); gGL.loadIdentity(); - mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); - - mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3); + drawFullScreenRect(); gGL.popMatrix(); gGL.matrixMode(LLRender::MM_MODELVIEW); @@ -7717,19 +8426,22 @@ void LLPipeline::renderDeferredLighting() } { //render non-deferred geometry (fullbright, alpha, etc) - LLGLDisable blend(GL_BLEND); - LLGLDisable stencil(GL_STENCIL_TEST); + LLGLDisable blend; + LLGLDisable stencil; gGL.setSceneBlendType(LLRender::BT_ALPHA); gPipeline.pushRenderTypeMask(); gPipeline.andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY, - LLPipeline::RENDER_TYPE_WL_CLOUDS, - LLPipeline::RENDER_TYPE_WL_SKY, - LLPipeline::END_RENDER_TYPES); +#if ENABLE_CLASSIC_CLOUDS + LLPipeline::RENDER_TYPE_CLASSIC_CLOUDS, +#endif + LLPipeline::RENDER_TYPE_WL_CLOUDS, + LLPipeline::RENDER_TYPE_WL_SKY, + LLPipeline::END_RENDER_TYPES); - renderGeomPostDeferred(*LLViewerCamera::getInstance()); + renderGeomPostDeferred(*LLViewerCamera::getInstance(), false); gPipeline.popRenderTypeMask(); } @@ -7760,7 +8472,7 @@ void LLPipeline::renderDeferredLighting() } mCubeVB->setBuffer(LLVertexBuffer::MAP_VERTEX); - + LLGLDepthTest depth(GL_TRUE, GL_FALSE); for (LLDrawable::drawable_set_t::iterator iter = mLights.begin(); iter != mLights.end(); ++iter) { @@ -7787,7 +8499,7 @@ void LLPipeline::renderDeferredLighting() F32 s = volume->getLightRadius()*1.5f; LLColor3 col = volume->getLightColor(); - + if (col.magVecSquared() < 0.001f) { continue; @@ -7806,13 +8518,14 @@ void LLPipeline::renderDeferredLighting() } sVisibleLightCount++; - - if (camera->getOrigin().mV[0] > c[0] + s + 0.2f || - camera->getOrigin().mV[0] < c[0] - s - 0.2f || - camera->getOrigin().mV[1] > c[1] + s + 0.2f || - camera->getOrigin().mV[1] < c[1] - s - 0.2f || - camera->getOrigin().mV[2] > c[2] + s + 0.2f || - camera->getOrigin().mV[2] < c[2] - s - 0.2f) + + const auto& camera_origin = camera->getOrigin(); + if (camera_origin.mV[0] > c[0] + s + 0.2f || + camera_origin.mV[0] < c[0] - s - 0.2f || + camera_origin.mV[1] > c[1] + s + 0.2f || + camera_origin.mV[1] < c[1] - s - 0.2f || + camera_origin.mV[2] > c[2] + s + 0.2f || + camera_origin.mV[2] < c[2] - s - 0.2f) { //draw box if camera is outside box if (render_local) { @@ -7823,12 +8536,15 @@ void LLPipeline::renderDeferredLighting() continue; } - LLFastTimer ftm(FTM_LOCAL_LIGHTS); + /*col.mV[0] = powf(col.mV[0], 2.2f); + col.mV[1] = powf(col.mV[1], 2.2f); + col.mV[2] = powf(col.mV[2], 2.2f);*/ + + LL_RECORD_BLOCK_TIME(FTM_LOCAL_LIGHTS); gDeferredLightProgram.uniform3fv(LLShaderMgr::LIGHT_CENTER, 1, c); - gDeferredLightProgram.uniform1f(LLShaderMgr::LIGHT_SIZE, s*s); + gDeferredLightProgram.uniform1f(LLShaderMgr::LIGHT_SIZE, s); gDeferredLightProgram.uniform3fv(LLShaderMgr::DIFFUSE_COLOR, 1, col.mV); gDeferredLightProgram.uniform1f(LLShaderMgr::LIGHT_FALLOFF, volume->getLightFalloff()*0.5f); - gGL.syncMatrices(); mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, center)); stop_glerror(); @@ -7843,10 +8559,11 @@ void LLPipeline::renderDeferredLighting() continue; } - glh::vec3f tc(c); - mat.mult_matrix_vec(tc); - - fullscreen_lights.push_back(LLVector4(tc.v[0], tc.v[1], tc.v[2], s*s)); + glh_get_current_modelview().affineTransform(center,center); + + LLVector4 tc(center.getF32ptr()); + tc.mV[VW] = s; + fullscreen_lights.push_back(tc); light_colors.push_back(LLVector4(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f)); } } @@ -7864,7 +8581,7 @@ void LLPipeline::renderDeferredLighting() for (LLDrawable::drawable_list_t::iterator iter = spot_lights.begin(); iter != spot_lights.end(); ++iter) { - LLFastTimer ftm(FTM_PROJECTORS); + LL_RECORD_BLOCK_TIME(FTM_PROJECTORS); LLDrawable* drawablep = *iter; LLVOVolume* volume = drawablep->getVOVolume(); @@ -7879,12 +8596,14 @@ void LLPipeline::renderDeferredLighting() setupSpotLight(gDeferredSpotLightProgram, drawablep); LLColor3 col = volume->getLightColor(); + /*col.mV[0] = powf(col.mV[0], 2.2f); + col.mV[1] = powf(col.mV[1], 2.2f); + col.mV[2] = powf(col.mV[2], 2.2f);*/ gDeferredSpotLightProgram.uniform3fv(LLShaderMgr::LIGHT_CENTER, 1, c); - gDeferredSpotLightProgram.uniform1f(LLShaderMgr::LIGHT_SIZE, s*s); + gDeferredSpotLightProgram.uniform1f(LLShaderMgr::LIGHT_SIZE, s); gDeferredSpotLightProgram.uniform3fv(LLShaderMgr::DIFFUSE_COLOR, 1, col.mV); gDeferredSpotLightProgram.uniform1f(LLShaderMgr::LIGHT_FALLOFF, volume->getLightFalloff()*0.5f); - gGL.syncMatrices(); mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, center)); } @@ -7892,17 +8611,7 @@ void LLPipeline::renderDeferredLighting() unbindDeferredShader(gDeferredSpotLightProgram); } - //reset mDeferredVB to fullscreen triangle - mDeferredVB->getVertexStrider(vert); - vert[0].set(-1,1,0); - vert[1].set(-1,-3,0); - vert[2].set(3,1,0); - { - bindDeferredShader(gDeferredMultiLightProgram); - - mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); - LLGLDepthTest depth(GL_FALSE); //full screen blit @@ -7914,7 +8623,7 @@ void LLPipeline::renderDeferredLighting() U32 count = 0; - const U32 max_count = 8; + const U32 max_count = LL_DEFERRED_MULTI_LIGHT_COUNT; LLVector4 light[max_count]; LLVector4 col[max_count]; @@ -7922,60 +8631,67 @@ void LLPipeline::renderDeferredLighting() while (!fullscreen_lights.empty()) { - LLFastTimer ftm(FTM_FULLSCREEN_LIGHTS); + LL_RECORD_BLOCK_TIME(FTM_FULLSCREEN_LIGHTS); light[count] = fullscreen_lights.front(); fullscreen_lights.pop_front(); col[count] = light_colors.front(); light_colors.pop_front(); - - far_z = llmin(light[count].mV[2]-sqrtf(light[count].mV[3]), far_z); - + + /*col[count].mV[0] = powf(col[count].mV[0], 2.2f); + col[count].mV[1] = powf(col[count].mV[1], 2.2f); + col[count].mV[2] = powf(col[count].mV[2], 2.2f);*/ + + far_z = llmin(light[count].mV[2]-light[count].mV[3], far_z); + //col[count] = pow4fsrgb(col[count], 2.2f); count++; if (count == max_count || fullscreen_lights.empty()) { - gDeferredMultiLightProgram.uniform1i(LLShaderMgr::MULTI_LIGHT_COUNT, count); - gDeferredMultiLightProgram.uniform4fv(LLShaderMgr::MULTI_LIGHT, count, (GLfloat*) light); - gDeferredMultiLightProgram.uniform4fv(LLShaderMgr::MULTI_LIGHT_COL, count, (GLfloat*) col); - gDeferredMultiLightProgram.uniform1f(LLShaderMgr::MULTI_LIGHT_FAR_Z, far_z); + U32 idx = count-1; + bindDeferredShader(gDeferredMultiLightProgram[idx]); + gDeferredMultiLightProgram[idx].uniform1i(LLShaderMgr::MULTI_LIGHT_COUNT, count); + gDeferredMultiLightProgram[idx].uniform4fv(LLShaderMgr::MULTI_LIGHT, count, (GLfloat*) light); + gDeferredMultiLightProgram[idx].uniform4fv(LLShaderMgr::MULTI_LIGHT_COL, count, (GLfloat*) col); + gDeferredMultiLightProgram[idx].uniform1f(LLShaderMgr::MULTI_LIGHT_FAR_Z, far_z); far_z = 0.f; count = 0; - mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3); + drawFullScreenRect(); } } - unbindDeferredShader(gDeferredMultiLightProgram); + unbindDeferredShader(gDeferredMultiLightProgram[0]); bindDeferredShader(gDeferredMultiSpotLightProgram); gDeferredMultiSpotLightProgram.enableTexture(LLShaderMgr::DEFERRED_PROJECTION); - mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); - for (LLDrawable::drawable_list_t::iterator iter = fullscreen_spot_lights.begin(); iter != fullscreen_spot_lights.end(); ++iter) { - LLFastTimer ftm(FTM_PROJECTORS); + LL_RECORD_BLOCK_TIME(FTM_PROJECTORS); LLDrawable* drawablep = *iter; LLVOVolume* volume = drawablep->getVOVolume(); - LLVector3 center = drawablep->getPositionAgent(); - F32* c = center.mV; + LLVector4a center; + center.load3(drawablep->getPositionAgent().mV); F32 s = volume->getLightRadius()*1.5f; sVisibleLightCount++; - glh::vec3f tc(c); - mat.mult_matrix_vec(tc); + glh_get_current_modelview().affineTransform(center,center); setupSpotLight(gDeferredMultiSpotLightProgram, drawablep); LLColor3 col = volume->getLightColor(); - - gDeferredMultiSpotLightProgram.uniform3fv(LLShaderMgr::LIGHT_CENTER, 1, tc.v); - gDeferredMultiSpotLightProgram.uniform1f(LLShaderMgr::LIGHT_SIZE, s*s); + + /*col.mV[0] = powf(col.mV[0], 2.2f); + col.mV[1] = powf(col.mV[1], 2.2f); + col.mV[2] = powf(col.mV[2], 2.2f);*/ + + gDeferredMultiSpotLightProgram.uniform3fv(LLShaderMgr::LIGHT_CENTER, 1, center.getF32ptr()); + gDeferredMultiSpotLightProgram.uniform1f(LLShaderMgr::LIGHT_SIZE, s); gDeferredMultiSpotLightProgram.uniform3fv(LLShaderMgr::DIFFUSE_COLOR, 1, col.mV); gDeferredMultiSpotLightProgram.uniform1f(LLShaderMgr::LIGHT_FALLOFF, volume->getLightFalloff()*0.5f); - mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3); + drawFullScreenRect(); } gDeferredMultiSpotLightProgram.disableTexture(LLShaderMgr::DEFERRED_PROJECTION); @@ -7985,23 +8701,60 @@ void LLPipeline::renderDeferredLighting() gGL.matrixMode(LLRender::MM_MODELVIEW); gGL.popMatrix(); } - gGL.setSceneBlendType(LLRender::BT_ALPHA); } gGL.setColorMask(true, true); } + mScreen.flush(); + + //gamma correct lighting + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.pushMatrix(); + gGL.loadIdentity(); + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.pushMatrix(); + gGL.loadIdentity(); + + { + LLGLDepthTest depth(GL_FALSE, GL_FALSE); + + mFinalScreen.bindTarget(); + // Apply gamma correction to the frame here. + gDeferredPostGammaCorrectProgram.bind(); + S32 channel = 0; + channel = gDeferredPostGammaCorrectProgram.enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mScreen.getUsage()); + if (channel > -1) + { + mScreen.bindTexture(0,channel); + gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + } + + drawFullScreenRect(); + + gGL.getTexUnit(channel)->unbind(mScreen.getUsage()); + gDeferredPostGammaCorrectProgram.unbind(); + mFinalScreen.flush(); + } + + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.popMatrix(); + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.popMatrix(); + + mFinalScreen.bindTarget(); + { //render non-deferred geometry (alpha, fullbright, glow) - LLGLDisable blend(GL_BLEND); - LLGLDisable stencil(GL_STENCIL_TEST); + LLGLDisable blend; + LLGLDisable stencil; pushRenderTypeMask(); andRenderTypeMask(LLPipeline::RENDER_TYPE_ALPHA, LLPipeline::RENDER_TYPE_FULLBRIGHT, - //LLPipeline::RENDER_TYPE_VOLUME, + LLPipeline::RENDER_TYPE_VOLUME, LLPipeline::RENDER_TYPE_GLOW, LLPipeline::RENDER_TYPE_BUMP, - /*LLPipeline::RENDER_TYPE_PASS_SIMPLE, //These aren't used. + LLPipeline::RENDER_TYPE_PASS_SIMPLE, LLPipeline::RENDER_TYPE_PASS_ALPHA, LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK, LLPipeline::RENDER_TYPE_PASS_BUMP, @@ -8012,34 +8765,16 @@ void LLPipeline::renderDeferredLighting() LLPipeline::RENDER_TYPE_PASS_GLOW, LLPipeline::RENDER_TYPE_PASS_GRASS, LLPipeline::RENDER_TYPE_PASS_SHINY, - LLPipeline::RENDER_TYPE_PASS_INVISIBLE, - LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY,*/ LLPipeline::RENDER_TYPE_AVATAR, + LLPipeline::RENDER_TYPE_ALPHA_MASK, + LLPipeline::RENDER_TYPE_FULLBRIGHT_ALPHA_MASK, END_RENDER_TYPES); renderGeomPostDeferred(*LLViewerCamera::getInstance()); popRenderTypeMask(); } - { - //render highlights, etc. - renderHighlights(); - mHighlightFaces.clear(); - - renderDebug(); - - LLVertexBuffer::unbind(); - - if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI)) - { - // Render debugging beacons. - gObjectList.renderObjectBeacons(); - gObjectList.resetObjectBeacons(); - } - } - - mScreen.flush(); - + } void LLPipeline::setupSpotLight(LLGLSLShader& shader, LLDrawable* drawablep) @@ -8068,12 +8803,14 @@ void LLPipeline::setupSpotLight(LLGLSLShader& shader, LLDrawable* drawablep) LLVector3 origin = np - at_axis*dist; //matrix from volume space to agent space - LLMatrix4 light_mat(quat, LLVector4(origin,1.f)); + LLMatrix4 light_mat_(quat, LLVector4(origin,1.f)); - glh::matrix4f light_to_agent((F32*) light_mat.mMatrix); - glh::matrix4f light_to_screen = glh_get_current_modelview() * light_to_agent; - - glh::matrix4f screen_to_light = light_to_screen.inverse(); + LLMatrix4a light_mat; + light_mat.loadu(light_mat_.mMatrix[0]); + LLMatrix4a light_to_screen; + light_to_screen.setMul(glh_get_current_modelview(),light_mat); + LLMatrix4a screen_to_light = light_to_screen; + screen_to_light.invert(); F32 s = volume->getLightRadius()*1.5f; F32 near_clip = dist; @@ -8084,31 +8821,29 @@ void LLPipeline::setupSpotLight(LLGLSLShader& shader, LLDrawable* drawablep) F32 fovy = fov * RAD_TO_DEG; F32 aspect = width/height; - glh::matrix4f trans(0.5f, 0.f, 0.f, 0.5f, - 0.f, 0.5f, 0.f, 0.5f, - 0.f, 0.f, 0.5f, 0.5f, - 0.f, 0.f, 0.f, 1.f); + LLVector4a p1(0, 0, -(near_clip+0.01f)); + LLVector4a p2(0, 0, -(near_clip+1.f)); - glh::vec3f p1(0, 0, -(near_clip+0.01f)); - glh::vec3f p2(0, 0, -(near_clip+1.f)); + LLVector4a screen_origin(LLVector4a::getZero()); - glh::vec3f screen_origin(0, 0, 0); + light_to_screen.affineTransform(p1,p1); + light_to_screen.affineTransform(p2,p2); + light_to_screen.affineTransform(screen_origin,screen_origin); - light_to_screen.mult_matrix_vec(p1); - light_to_screen.mult_matrix_vec(p2); - light_to_screen.mult_matrix_vec(screen_origin); + LLVector4a n; + n.setSub(p2,p1); + n.normalize3fast(); - glh::vec3f n = p2-p1; - n.normalize(); - F32 proj_range = far_clip - near_clip; - glh::matrix4f light_proj = gl_perspective(fovy, aspect, near_clip, far_clip); - screen_to_light = trans * light_proj * screen_to_light; - shader.uniformMatrix4fv(LLShaderMgr::PROJECTOR_MATRIX, 1, FALSE, screen_to_light.m); + LLMatrix4a light_proj = gGL.genPersp(fovy, aspect, near_clip, far_clip); + light_proj.setMul(gGL.genNDCtoWC(),light_proj); + screen_to_light.setMul(light_proj,screen_to_light); + + shader.uniformMatrix4fv(LLShaderMgr::PROJECTOR_MATRIX, 1, FALSE, screen_to_light.getF32ptr()); shader.uniform1f(LLShaderMgr::PROJECTOR_NEAR, near_clip); - shader.uniform3fv(LLShaderMgr::PROJECTOR_P, 1, p1.v); - shader.uniform3fv(LLShaderMgr::PROJECTOR_N, 1, n.v); - shader.uniform3fv(LLShaderMgr::PROJECTOR_ORIGIN, 1, screen_origin.v); + shader.uniform3fv(LLShaderMgr::PROJECTOR_P, 1, p1.getF32ptr()); + shader.uniform3fv(LLShaderMgr::PROJECTOR_N, 1, n.getF32ptr()); + shader.uniform3fv(LLShaderMgr::PROJECTOR_ORIGIN, 1, screen_origin.getF32ptr()); shader.uniform1f(LLShaderMgr::PROJECTOR_RANGE, proj_range); shader.uniform1f(LLShaderMgr::PROJECTOR_AMBIANCE, params.mV[2]); S32 s_idx = -1; @@ -8181,22 +8916,31 @@ void LLPipeline::setupSpotLight(LLGLSLShader& shader, LLDrawable* drawablep) } -void LLPipeline::unbindDeferredShader(LLGLSLShader &shader) +void LLPipeline::unbindDeferredShader(LLGLSLShader &shader, LLRenderTarget* diffuse_source, LLRenderTarget* light_source) { + if (shader.mShaderClass != LLViewerShaderMgr::SHADER_DEFERRED && shader.mShaderClass != LLViewerShaderMgr::SHADER_INTERFACE) + { + shader.unbind(); + return; + } + + diffuse_source = diffuse_source ? diffuse_source : &mDeferredScreen; + light_source = light_source ? light_source : &mDeferredLight; + stop_glerror(); shader.disableTexture(LLShaderMgr::DEFERRED_NORMAL, mDeferredScreen.getUsage()); - shader.disableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mDeferredScreen.getUsage()); + shader.disableTexture(LLShaderMgr::DEFERRED_DIFFUSE, diffuse_source->getUsage()); shader.disableTexture(LLShaderMgr::DEFERRED_SPECULAR, mDeferredScreen.getUsage()); - shader.disableTexture(LLShaderMgr::DEFERRED_DEPTH, mDeferredScreen.getUsage()); - shader.disableTexture(LLShaderMgr::DEFERRED_LIGHT, mDeferredLight.getUsage()); + shader.disableTexture(LLShaderMgr::DEFERRED_DEPTH, mDeferredDepth.getUsage()); + shader.disableTexture(LLShaderMgr::DEFERRED_LIGHT, light_source->getUsage()); shader.disableTexture(LLShaderMgr::DIFFUSE_MAP); shader.disableTexture(LLShaderMgr::DEFERRED_BLOOM); for (U32 i = 0; i < 4; i++) { - if (shader.disableTexture(LLShaderMgr::DEFERRED_SHADOW0+i, LLTexUnit::TT_RECT_TEXTURE) > -1) + if (shader.disableTexture(LLShaderMgr::DEFERRED_SHADOW0+i) > -1) { - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE); } } @@ -8234,7 +8978,8 @@ inline float sgn(float a) void LLPipeline::generateWaterReflection(LLCamera& camera_in) { - if (LLPipeline::sWaterReflections && assertInitialized() && LLDrawPoolWater::sNeedsReflectionUpdate) + static const LLCachedControl render_transparent_water("RenderTransparentWater",false); + if ((render_transparent_water || LLPipeline::sRenderDeferred) && LLPipeline::sWaterReflections && assertInitialized() && LLDrawPoolWater::sNeedsReflectionUpdate) { BOOL skip_avatar_update = FALSE; if (!isAgentAvatarValid() || gAgentCamera.getCameraAnimating() || gAgentCamera.getCameraMode() != CAMERA_MODE_MOUSELOOK || !LLVOAvatar::sVisibleInFirstPerson) @@ -8248,9 +8993,9 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in) } LLVertexBuffer::unbind(); - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - LLGLState::checkClientArrays(); + LLGLStateValidator::checkStates(); + LLGLStateValidator::checkTextureChannels(); + LLGLStateValidator::checkClientArrays(); LLCamera camera = camera_in; camera.setFar(camera.getFar()*0.87654321f); @@ -8258,8 +9003,7 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in) gPipeline.pushRenderTypeMask(); - glh::matrix4f projection = glh_get_current_projection(); - glh::matrix4f mat; + const LLMatrix4a projection = glh_get_current_projection(); stop_glerror(); LLPlane plane; @@ -8288,6 +9032,12 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in) water_clip = 1; } + bool materials_in_water = false; + +#if MATERIALS_IN_REFLECTIONS + materials_in_water = gSavedSettings.getS32("RenderWaterMaterials"); +#endif + if (!LLViewerCamera::getInstance()->cameraUnderWater()) { //generate planar reflection map @@ -8308,24 +9058,27 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in) gGL.pushMatrix(); - mat.set_scale(glh::vec3f(1,1,-1)); - mat.set_translate(glh::vec3f(0,0,height*2.f)); - - glh::matrix4f current = glh_get_current_modelview(); + const LLMatrix4a saved_modelview = glh_get_current_modelview(); - mat = current * mat; + LLMatrix4a mat; + mat.setIdentity(); + mat.getRow<2>().negate(); + mat.setTranslate_affine(LLVector3(0.f,0.f,height*2.f)); + mat.setMul(saved_modelview,mat); glh_set_current_modelview(mat); - gGL.loadMatrix(mat.m); + gGL.loadMatrix(mat); LLViewerCamera::updateFrustumPlanes(camera, FALSE, TRUE); - glh::matrix4f inv_mat = mat.inverse(); + LLMatrix4a inv_mat = mat; + inv_mat.invert(); - glh::vec3f origin(0,0,0); - inv_mat.mult_matrix_vec(origin); + LLVector4a origin; + origin.clear(); + inv_mat.affineTransform(origin,origin); - camera.setOrigin(origin.v); + camera.setOrigin(origin.getF32ptr()); glCullFace(GL_FRONT); @@ -8345,11 +9098,28 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in) updateCull(camera, result); stateSort(camera, result); - renderGeom(camera, TRUE); + if (LLPipeline::sRenderDeferred && materials_in_water) + { + mWaterRef.flush(); + + gPipeline.grabReferences(result); + gPipeline.mDeferredScreen.bindTarget(); + gGL.setColorMask(true, true); + glClearColor(0,0,0,0); + gPipeline.mDeferredScreen.clear(); + + renderGeomDeferred(camera); + } + else + { + renderGeom(camera, TRUE); + } gPipeline.popRenderTypeMask(); } + gGL.setColorMask(true, false); + static const LLCachedControl detail("RenderReflectionDetail",0); if (detail > 0) { //mask out selected geometry based on reflection detail @@ -8380,14 +9150,34 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in) static const LLCachedControl skip_distortion_updates("SkipReflectOcclusionUpdates",false); LLPipeline::sSkipUpdate = skip_distortion_updates; LLGLUserClipPlane clip_plane(plane, mat, projection); - LLGLDisable cull(GL_CULL_FACE); + LLGLDisable cull; updateCull(camera, ref_result, -water_clip, &plane); stateSort(camera, ref_result); + if (LLDrawPoolWater::sNeedsDistortionUpdate) { - gPipeline.grabReferences(ref_result); - renderGeom(camera); + if (detail > 0) + { + gPipeline.grabReferences(ref_result); + LLGLUserClipPlane clip_plane(plane, mat, projection); + + if (LLPipeline::sRenderDeferred && materials_in_water) + { + renderGeomDeferred(camera); + } + else + { + renderGeom(camera); + } + } + } + + if (LLPipeline::sRenderDeferred && materials_in_water) + { + gPipeline.mDeferredScreen.flush(); + renderDeferredLightingToRT(&mWaterRef); } + LLPipeline::sSkipUpdate = FALSE; gPipeline.popRenderTypeMask(); } @@ -8395,7 +9185,7 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in) glCullFace(GL_BACK); gGL.popMatrix(); mWaterRef.flush(); - glh_set_current_modelview(current); + glh_set_current_modelview(saved_modelview); LLPipeline::sUseOcclusion = occlusion; } @@ -8436,23 +9226,45 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in) if (!LLPipeline::sUnderWaterRender || LLDrawPoolWater::sNeedsReflectionUpdate) { //clip out geometry on the same side of water as the camera - mat = glh_get_current_modelview(); LLPlane plane(-pnorm, -(pd+pad)); - LLGLUserClipPlane clip_plane(plane, mat, projection); + LLGLUserClipPlane clip_plane(plane, glh_get_current_modelview(), projection); static LLCullResult result; updateCull(camera, result, water_clip, &plane); stateSort(camera, result); gGL.setColorMask(true, true); mWaterDis.clear(); + + gGL.setColorMask(true, false); + + if (LLPipeline::sRenderDeferred && materials_in_water) + { + mWaterDis.flush(); + gPipeline.mDeferredScreen.bindTarget(); + gGL.setColorMask(true, true); + glClearColor(0,0,0,0); + gPipeline.mDeferredScreen.clear(); + gPipeline.grabReferences(result); + renderGeomDeferred(camera); + } + else + { renderGeom(camera); + } + + if (LLPipeline::sRenderDeferred && materials_in_water) + { + gPipeline.mDeferredScreen.flush(); + renderDeferredLightingToRT(&mWaterDis); + } } - LLPipeline::sUnderWaterRender = FALSE; mWaterDis.flush(); + LLPipeline::sUnderWaterRender = FALSE; + } last_update = LLDrawPoolWater::sNeedsReflectionUpdate && LLDrawPoolWater::sNeedsDistortionUpdate; @@ -8460,6 +9272,7 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in) if (!LLRenderTarget::sUseFBO) { + gGL.syncContextState(); glClear(GL_DEPTH_BUFFER_BIT); } glClearColor(0.f, 0.f, 0.f, 0.f); @@ -8470,7 +9283,7 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in) LLPlane npnorm(-pnorm, -pd); LLViewerCamera::getInstance()->setUserClipPlane(npnorm); - LLGLState::checkStates(); + LLGLStateValidator::checkStates(); if (!skip_avatar_update) { @@ -8481,79 +9294,13 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in) } } -glh::matrix4f look(const LLVector3 pos, const LLVector3 dir, const LLVector3 up) -{ - glh::matrix4f ret; - - LLVector3 dirN; - LLVector3 upN; - LLVector3 lftN; - - lftN = dir % up; - lftN.normVec(); - - upN = lftN % dir; - upN.normVec(); - - dirN = dir; - dirN.normVec(); - - ret.m[ 0] = lftN[0]; - ret.m[ 1] = upN[0]; - ret.m[ 2] = -dirN[0]; - ret.m[ 3] = 0.f; - - ret.m[ 4] = lftN[1]; - ret.m[ 5] = upN[1]; - ret.m[ 6] = -dirN[1]; - ret.m[ 7] = 0.f; - - ret.m[ 8] = lftN[2]; - ret.m[ 9] = upN[2]; - ret.m[10] = -dirN[2]; - ret.m[11] = 0.f; - - ret.m[12] = -(lftN*pos); - ret.m[13] = -(upN*pos); - ret.m[14] = dirN*pos; - ret.m[15] = 1.f; - - return ret; -} - -glh::matrix4f scale_translate_to_fit(const LLVector3 min, const LLVector3 max) -{ - glh::matrix4f ret; - ret.m[ 0] = 2/(max[0]-min[0]); - ret.m[ 4] = 0; - ret.m[ 8] = 0; - ret.m[12] = -(max[0]+min[0])/(max[0]-min[0]); - - ret.m[ 1] = 0; - ret.m[ 5] = 2/(max[1]-min[1]); - ret.m[ 9] = 0; - ret.m[13] = -(max[1]+min[1])/(max[1]-min[1]); - - ret.m[ 2] = 0; - ret.m[ 6] = 0; - ret.m[10] = 2/(max[2]-min[2]); - ret.m[14] = -(max[2]+min[2])/(max[2]-min[2]); - - ret.m[ 3] = 0; - ret.m[ 7] = 0; - ret.m[11] = 0; - ret.m[15] = 1; - - return ret; -} - -static LLFastTimer::DeclareTimer FTM_SHADOW_RENDER("Render Shadows"); -static LLFastTimer::DeclareTimer FTM_SHADOW_ALPHA("Alpha Shadow"); -static LLFastTimer::DeclareTimer FTM_SHADOW_SIMPLE("Simple Shadow"); +static LLTrace::BlockTimerStatHandle FTM_SHADOW_RENDER("Render Shadows"); +static LLTrace::BlockTimerStatHandle FTM_SHADOW_ALPHA("Alpha Shadow"); +static LLTrace::BlockTimerStatHandle FTM_SHADOW_SIMPLE("Simple Shadow"); -void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera& shadow_cam, LLCullResult &result, BOOL use_shader, BOOL use_occlusion, U32 target_width) +void LLPipeline::renderShadow(const LLMatrix4a& view, const LLMatrix4a& proj, LLCamera& shadow_cam, LLCullResult &result, BOOL use_shader, BOOL use_occlusion, U32 target_width) { - LLFastTimer t(FTM_SHADOW_RENDER); + LL_RECORD_BLOCK_TIME(FTM_SHADOW_RENDER); //clip out geometry on the same side of water as the camera S32 occlude = LLPipeline::sUseOcclusion; @@ -8568,10 +9315,18 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera LLRenderPass::PASS_FULLBRIGHT, LLRenderPass::PASS_SHINY, LLRenderPass::PASS_BUMP, - LLRenderPass::PASS_FULLBRIGHT_SHINY + LLRenderPass::PASS_FULLBRIGHT_SHINY , + LLRenderPass::PASS_MATERIAL, + LLRenderPass::PASS_MATERIAL_ALPHA_EMISSIVE, + LLRenderPass::PASS_SPECMAP, + LLRenderPass::PASS_SPECMAP_EMISSIVE, + LLRenderPass::PASS_NORMMAP, + LLRenderPass::PASS_NORMMAP_EMISSIVE, + LLRenderPass::PASS_NORMSPEC, + LLRenderPass::PASS_NORMSPEC_EMISSIVE, }; - LLGLEnable cull(GL_CULL_FACE); + LLGLEnable cull; if (use_shader) { @@ -8579,15 +9334,17 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera } updateCull(shadow_cam, result); + stateSort(shadow_cam, result); + //generate shadow map gGL.matrixMode(LLRender::MM_PROJECTION); gGL.pushMatrix(); - gGL.loadMatrix(proj.m); + gGL.loadMatrix(proj); gGL.matrixMode(LLRender::MM_MODELVIEW); gGL.pushMatrix(); - gGL.loadMatrix(gGLModelView); + gGL.loadMatrix(view); //Why was glh_get_current_modelview() used instead of view? stop_glerror(); gGLLastMatrix = NULL; @@ -8611,7 +9368,7 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera gGL.diffuseColor4f(1,1,1,1); gGL.setColorMask(false, false); - LLFastTimer ftm(FTM_SHADOW_SIMPLE); + LL_RECORD_BLOCK_TIME(FTM_SHADOW_SIMPLE); gGL.getTexUnit(0)->disable(); for (U32 i = 0; i < sizeof(types)/sizeof(U32); ++i) { @@ -8636,9 +9393,8 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera } { - LLFastTimer ftm(FTM_SHADOW_ALPHA); + LL_RECORD_BLOCK_TIME(FTM_SHADOW_ALPHA); gDeferredShadowAlphaMaskProgram.bind(); - gDeferredShadowAlphaMaskProgram.setMinimumAlpha(0.598f); gDeferredShadowAlphaMaskProgram.uniform1f(LLShaderMgr::DEFERRED_SHADOW_TARGET_WIDTH, (float)target_width); U32 mask = LLVertexBuffer::MAP_VERTEX | @@ -8646,10 +9402,19 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_TEXTURE_INDEX; - renderObjects(LLRenderPass::PASS_ALPHA_MASK, mask, TRUE, TRUE); - renderObjects(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, mask, TRUE, TRUE); + renderMaskedObjects(LLRenderPass::PASS_ALPHA_MASK, mask, TRUE, TRUE); + renderMaskedObjects(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, mask, TRUE, TRUE); + gDeferredShadowAlphaMaskProgram.setMinimumAlpha(0.598f); renderObjects(LLRenderPass::PASS_ALPHA, mask, TRUE, TRUE); + + mask = mask & ~LLVertexBuffer::MAP_TEXTURE_INDEX; + gDeferredTreeShadowProgram.bind(); + renderMaskedObjects(LLRenderPass::PASS_NORMSPEC_MASK, mask); + renderMaskedObjects(LLRenderPass::PASS_MATERIAL_ALPHA_MASK, mask); + renderMaskedObjects(LLRenderPass::PASS_SPECMAP_MASK, mask); + renderMaskedObjects(LLRenderPass::PASS_NORMMAP_MASK, mask); + gDeferredTreeShadowProgram.setMinimumAlpha(0.598f); renderObjects(LLRenderPass::PASS_GRASS, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, TRUE); } @@ -8658,7 +9423,10 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera gDeferredShadowCubeProgram.bind(); gGLLastMatrix = NULL; - gGL.loadMatrix(gGLModelView); + gGL.loadMatrix(glh_get_current_modelview()); + + //LLRenderTarget& occlusion_source = mShadow[LLViewerCamera::sCurCameraID-1]; + doOcclusion(shadow_cam); if (use_shader) @@ -8678,10 +9446,10 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera LLPipeline::sShadowRender = FALSE; } -static LLFastTimer::DeclareTimer FTM_VISIBLE_CLOUD("Visible Cloud"); +static LLTrace::BlockTimerStatHandle FTM_VISIBLE_CLOUD("Visible Cloud"); BOOL LLPipeline::getVisiblePointCloud(LLCamera& camera, LLVector3& min, LLVector3& max, std::vector& fp, LLVector3 light_dir) { - LLFastTimer t(FTM_VISIBLE_CLOUD); + LL_RECORD_BLOCK_TIME(FTM_VISIBLE_CLOUD); //get point cloud of intersection of frust and min, max if (getVisibleExtents(camera, min, max)) @@ -8712,7 +9480,7 @@ BOOL LLPipeline::getVisiblePointCloud(LLCamera& camera, LLVector3& min, LLVector pp.push_back(LLVector3(max.mV[0], max.mV[1], max.mV[2])); //add corners of camera frustum - for (U32 i = 0; i < 8; i++) + for (U32 i = 0; i < LLCamera::AGENT_FRUSTRUM_NUM; i++) { pp.push_back(camera.mAgentFrustum[i]); } @@ -8739,7 +9507,7 @@ BOOL LLPipeline::getVisiblePointCloud(LLCamera& camera, LLVector3& min, LLVector for (U32 i = 0; i < 12; i++) { //for each line segment in bounding box - for (U32 j = 0; j < 6; j++) + for (U32 j = 0; j < LLCamera::AGENT_PLANE_NO_USER_CLIP_NUM; j++) { //for each plane in camera frustum const LLPlane& cp = camera.getAgentPlane(j); const LLVector3& v1 = pp[bs[i*2+0]]; @@ -8825,7 +9593,7 @@ BOOL LLPipeline::getVisiblePointCloud(LLCamera& camera, LLVector3& min, LLVector } } - for (U32 j = 0; j < 6; ++j) + for (U32 j = 0; j < LLCamera::AGENT_PLANE_NO_USER_CLIP_NUM; ++j) { const LLPlane& cp = camera.getAgentPlane(j); F32 dist = cp.dist(pp[i]); @@ -8851,7 +9619,7 @@ BOOL LLPipeline::getVisiblePointCloud(LLCamera& camera, LLVector3& min, LLVector } -static LLFastTimer::DeclareTimer FTM_GEN_SUN_SHADOW("Gen Sun Shadow"); +static LLTrace::BlockTimerStatHandle FTM_GEN_SUN_SHADOW("Gen Sun Shadow"); void LLPipeline::generateSunShadow(LLCamera& camera) { @@ -8870,7 +9638,7 @@ void LLPipeline::generateSunShadow(LLCamera& camera) return; } - LLFastTimer t(FTM_GEN_SUN_SHADOW); + LL_RECORD_BLOCK_TIME(FTM_GEN_SUN_SHADOW); BOOL skip_avatar_update = FALSE; if (!isAgentAvatarValid() || gAgentCamera.getCameraAnimating() || gAgentCamera.getCameraMode() != CAMERA_MODE_MOUSELOOK || !LLVOAvatar::sVisibleInFirstPerson) @@ -8884,13 +9652,8 @@ void LLPipeline::generateSunShadow(LLCamera& camera) gAgentAvatarp->updateAttachmentVisibility(CAMERA_MODE_THIRD_PERSON); } - F64 last_modelview[16]; - F64 last_projection[16]; - for (U32 i = 0; i < 16; i++) - { //store last_modelview of world camera - last_modelview[i] = gGLLastModelView[i]; - last_projection[i] = gGLLastProjection[i]; - } + LLMatrix4a last_modelview = glh_get_last_modelview(); + LLMatrix4a last_projection = glh_get_last_projection(); pushRenderTypeMask(); andRenderTypeMask(LLPipeline::RENDER_TYPE_SIMPLE, @@ -8913,6 +9676,22 @@ void LLPipeline::generateSunShadow(LLCamera& camera) LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT, LLPipeline::RENDER_TYPE_PASS_SHINY, LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY, + LLPipeline::RENDER_TYPE_PASS_MATERIAL, + LLPipeline::RENDER_TYPE_PASS_MATERIAL_ALPHA, + LLPipeline::RENDER_TYPE_PASS_MATERIAL_ALPHA_MASK, + LLPipeline::RENDER_TYPE_PASS_MATERIAL_ALPHA_EMISSIVE, + LLPipeline::RENDER_TYPE_PASS_SPECMAP, + LLPipeline::RENDER_TYPE_PASS_SPECMAP_BLEND, + LLPipeline::RENDER_TYPE_PASS_SPECMAP_MASK, + LLPipeline::RENDER_TYPE_PASS_SPECMAP_EMISSIVE, + LLPipeline::RENDER_TYPE_PASS_NORMMAP, + LLPipeline::RENDER_TYPE_PASS_NORMMAP_BLEND, + LLPipeline::RENDER_TYPE_PASS_NORMMAP_MASK, + LLPipeline::RENDER_TYPE_PASS_NORMMAP_EMISSIVE, + LLPipeline::RENDER_TYPE_PASS_NORMSPEC, + LLPipeline::RENDER_TYPE_PASS_NORMSPEC_BLEND, + LLPipeline::RENDER_TYPE_PASS_NORMSPEC_MASK, + LLPipeline::RENDER_TYPE_PASS_NORMSPEC_EMISSIVE, END_RENDER_TYPES); gGL.setColorMask(false, false); @@ -8920,13 +9699,14 @@ void LLPipeline::generateSunShadow(LLCamera& camera) //get sun view matrix //store current projection/modelview matrix - glh::matrix4f saved_proj = glh_get_current_projection(); - glh::matrix4f saved_view = glh_get_current_modelview(); - glh::matrix4f inv_view = saved_view.inverse(); + const LLMatrix4a saved_proj = glh_get_current_projection(); + const LLMatrix4a saved_view = glh_get_current_modelview(); + LLMatrix4a inv_view(saved_view); + inv_view.invert(); + + LLMatrix4a view[6]; + LLMatrix4a proj[6]; - glh::matrix4f view[6]; - glh::matrix4f proj[6]; - //clip contains parallel split distances for 3 splits LLVector3 clip = RenderShadowClipPlanes; @@ -8935,26 +9715,23 @@ void LLPipeline::generateSunShadow(LLCamera& camera) //far clip on last split is minimum of camera view distance and 128 mSunClipPlanes = LLVector4(clip, clip.mV[2] * clip.mV[2]/clip.mV[1]); - clip = RenderShadowOrthoClipPlanes; - mSunOrthoClipPlanes = LLVector4(clip, clip.mV[2]*clip.mV[2]/clip.mV[1]); - //currently used for amount to extrude frusta corners for constructing shadow frusta //LLVector3 n = RenderShadowNearDist; //F32 nearDist[] = { n.mV[0], n.mV[1], n.mV[2], n.mV[2] }; //put together a universal "near clip" plane for shadow frusta + LLVector3 sunDir = getSunDir(); LLPlane shadow_near_clip; { + ; LLVector3 p = gAgent.getPositionAgent(); - p += mSunDir * RenderFarClip*2.f; - shadow_near_clip.setVec(p, mSunDir); + p += sunDir * RenderFarClip*2.f; + shadow_near_clip.setVec(p, sunDir); } - LLVector3 lightDir = -mSunDir; + LLVector3 lightDir = -sunDir; lightDir.normVec(); - glh::vec3f light_dir(lightDir.mV); - //create light space camera matrix LLVector3 at = lightDir; @@ -9011,9 +9788,10 @@ void LLPipeline::generateSunShadow(LLCamera& camera) //get good split distances for frustum for (U32 i = 0; i < fp.size(); ++i) { - glh::vec3f v(fp[i].mV); - saved_view.mult_matrix_vec(v); - fp[i].setVec(v.v); + LLVector4a v; + v.load3(fp[i].mV); + saved_view.affineTransform(v,v); + fp[i].setVec(v.getF32ptr()); } min = fp[0]; @@ -9074,7 +9852,7 @@ void LLPipeline::generateSunShadow(LLCamera& camera) mShadowFrustPoints[j].clear(); } - LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_SHADOW0+j; + LLViewerCamera::sCurCameraID = LLViewerCamera::eCameraID(LLViewerCamera::CAMERA_SHADOW0+j); //restore render matrices glh_set_current_modelview(saved_view); @@ -9135,9 +9913,6 @@ void LLPipeline::generateSunShadow(LLCamera& camera) } mShadow[j].flush(); - mShadowError.mV[j] = 0.f; - mShadowFOV.mV[j] = 0.f; - continue; } @@ -9153,15 +9928,16 @@ void LLPipeline::generateSunShadow(LLCamera& camera) LLVector3 origin; //get a temporary view projection - view[j] = look(camera.getOrigin(), lightDir, -up); + view[j] = gGL.genLook(camera.getOrigin(), lightDir, -up); std::vector wpf; for (U32 i = 0; i < fp.size(); i++) { - glh::vec3f p = glh::vec3f(fp[i].mV); - view[j].mult_matrix_vec(p); - wpf.push_back(LLVector3(p.v)); + LLVector4a p; + p.load3(fp[i].mV); + view[j].affineTransform(p,p); + wpf.push_back(LLVector3(p.getF32ptr())); } min = wpf[0]; @@ -9246,24 +10022,21 @@ void LLPipeline::generateSunShadow(LLCamera& camera) bfb = lp.mV[1]-bfm*lp.mV[0]; //calculate error - mShadowError.mV[j] = 0.f; + F32 shadow_error = 0.f; for (U32 i = 0; i < wpf.size(); ++i) { F32 lx = (wpf[i].mV[1]-bfb)/bfm; - mShadowError.mV[j] += fabsf(wpf[i].mV[0]-lx); + shadow_error += fabsf(wpf[i].mV[0]-lx); } - mShadowError.mV[j] /= wpf.size(); - mShadowError.mV[j] /= size.mV[0]; + shadow_error /= wpf.size(); + shadow_error /= size.mV[0]; - if (mShadowError.mV[j] > RenderShadowErrorCutoff) + if (shadow_error > RenderShadowErrorCutoff) { //just use ortho projection - mShadowFOV.mV[j] = -1.f; origin.clearVec(); - proj[j] = gl_ortho(min.mV[0], max.mV[0], - min.mV[1], max.mV[1], - -max.mV[2], -min.mV[2]); + proj[j] = gGL.genOrtho(min.mV[0], max.mV[0], min.mV[1], max.mV[1], -max.mV[2], -min.mV[2]); } else { @@ -9302,8 +10075,6 @@ void LLPipeline::generateSunShadow(LLCamera& camera) F32 cutoff = llmin((F32) RenderShadowFOVCutoff, 1.4f); - mShadowFOV.mV[j] = fovx; - if (fovx < cutoff && fovz > cutoff) { //x is a good fit, but z is too big, move away from zp enough so that fovz matches cutoff @@ -9331,7 +10102,6 @@ void LLPipeline::generateSunShadow(LLCamera& camera) fovx = acos(fovx); fovz = acos(fovz); - mShadowFOV.mV[j] = cutoff; } @@ -9351,37 +10121,29 @@ void LLPipeline::generateSunShadow(LLCamera& camera) if (fovx > cutoff) { //just use ortho projection origin.clearVec(); - mShadowError.mV[j] = -1.f; - proj[j] = gl_ortho(min.mV[0], max.mV[0], - min.mV[1], max.mV[1], - -max.mV[2], -min.mV[2]); + proj[j] = gGL.genOrtho(min.mV[0], max.mV[0], min.mV[1], max.mV[1], -max.mV[2], -min.mV[2]); } else { //get perspective projection - view[j] = view[j].inverse(); + view[j].invert(); + LLVector4a origin_agent; + origin_agent.load3(origin.mV); - glh::vec3f origin_agent(origin.mV); - //translate view to origin - view[j].mult_matrix_vec(origin_agent); + view[j].affineTransform(origin_agent,origin_agent); - eye = LLVector3(origin_agent.v); + eye = LLVector3(origin_agent.getF32ptr()); - if (!hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA)) - { - mShadowFrustOrigin[j] = eye; - } - - view[j] = look(LLVector3(origin_agent.v), lightDir, -up); + view[j] = gGL.genLook(LLVector3(origin_agent.getF32ptr()), lightDir, -up); F32 fx = 1.f/tanf(fovx); F32 fz = 1.f/tanf(fovz); - proj[j] = glh::matrix4f(-fx, 0, 0, 0, - 0, (yfar+ynear)/(ynear-yfar), 0, (2.f*yfar*ynear)/(ynear-yfar), - 0, 0, -fz, 0, - 0, -1.f, 0, 0); + proj[j].setRow<0>(LLVector4a( -fx, 0.f, 0.f)); + proj[j].setRow<1>(LLVector4a( 0.f, (yfar+ynear)/(ynear-yfar), 0.f, -1.f)); + proj[j].setRow<2>(LLVector4a( 0.f, 0.f, -fz)); + proj[j].setRow<3>(LLVector4a( 0.f, (2.f*yfar*ynear)/(ynear-yfar), 0.f)); } } } @@ -9399,26 +10161,19 @@ void LLPipeline::generateSunShadow(LLCamera& camera) //shadow_cam.ignoreAgentFrustumPlane(LLCamera::AGENT_PLANE_NEAR); shadow_cam.getAgentPlane(LLCamera::AGENT_PLANE_NEAR).set(shadow_near_clip); - //translate and scale to from [-1, 1] to [0, 1] - glh::matrix4f trans(0.5f, 0.f, 0.f, 0.5f, - 0.f, 0.5f, 0.f, 0.5f, - 0.f, 0.f, 0.5f, 0.5f, - 0.f, 0.f, 0.f, 1.f); - glh_set_current_modelview(view[j]); glh_set_current_projection(proj[j]); - for (U32 i = 0; i < 16; i++) - { - gGLLastModelView[i] = mShadowModelview[j].m[i]; - gGLLastProjection[i] = mShadowProjection[j].m[i]; - } + glh_set_last_modelview(mShadowModelview[j]); + glh_set_last_projection(mShadowProjection[j]); mShadowModelview[j] = view[j]; mShadowProjection[j] = proj[j]; - - mSunShadowMatrix[j] = trans*proj[j]*view[j]*inv_view; + + mSunShadowMatrix[j].setMul(gGL.genNDCtoWC(),proj[j]); + mSunShadowMatrix[j].mul_affine(view[j]); + mSunShadowMatrix[j].mul_affine(inv_view); stop_glerror(); @@ -9456,7 +10211,7 @@ void LLPipeline::generateSunShadow(LLCamera& camera) //update shadow targets for (U32 i = 0; i < 2; i++) { //for each current shadow - LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_SHADOW4+i; + LLViewerCamera::sCurCameraID = LLViewerCamera::eCameraID(LLViewerCamera::CAMERA_SHADOW4 + i); if (mShadowSpotLight[i].notNull() && (mShadowSpotLight[i] == mTargetShadowSpotLight[0] || @@ -9524,9 +10279,9 @@ void LLPipeline::generateSunShadow(LLCamera& camera) LLMatrix4 mat(quat, LLVector4(origin, 1.f)); - view[i+4] = glh::matrix4f((F32*) mat.mMatrix); + view[i+4].loadu(mat.mMatrix[0]); - view[i+4] = view[i+4].inverse(); + view[i+4].invert(); //get perspective matrix F32 near_clip = dist+0.01f; @@ -9536,29 +10291,22 @@ void LLPipeline::generateSunShadow(LLCamera& camera) F32 fovy = fov * RAD_TO_DEG; F32 aspect = width/height; - - proj[i+4] = gl_perspective(fovy, aspect, near_clip, far_clip); - //translate and scale to from [-1, 1] to [0, 1] - glh::matrix4f trans(0.5f, 0.f, 0.f, 0.5f, - 0.f, 0.5f, 0.f, 0.5f, - 0.f, 0.f, 0.5f, 0.5f, - 0.f, 0.f, 0.f, 1.f); + proj[i+4] = gGL.genPersp(fovy, aspect, near_clip, far_clip); glh_set_current_modelview(view[i+4]); glh_set_current_projection(proj[i+4]); - mSunShadowMatrix[i+4] = trans*proj[i+4]*view[i+4]*inv_view; - - for (U32 j = 0; j < 16; j++) - { - gGLLastModelView[j] = mShadowModelview[i+4].m[j]; - gGLLastProjection[j] = mShadowProjection[i+4].m[j]; - } + glh_set_last_modelview(mShadowModelview[i+4]); + glh_set_last_projection(mShadowProjection[i+4]); mShadowModelview[i+4] = view[i+4]; mShadowProjection[i+4] = proj[i+4]; + mSunShadowMatrix[i+4].setMul(gGL.genNDCtoWC(),proj[i+4]); + mSunShadowMatrix[i+4].mul_affine(view[i+4]); + mSunShadowMatrix[i+4].mul_affine(inv_view); + LLCamera shadow_cam = camera; shadow_cam.setFar(far_clip); shadow_cam.setOrigin(origin); @@ -9575,7 +10323,7 @@ void LLPipeline::generateSunShadow(LLCamera& camera) static LLCullResult result[2]; - LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_SHADOW0+i+4; + LLViewerCamera::sCurCameraID = LLViewerCamera::eCameraID(LLViewerCamera::CAMERA_SHADOW0 + i + 4); renderShadow(view[i+4], proj[i+4], shadow_cam, result[i], FALSE, FALSE, target_width); @@ -9597,18 +10345,15 @@ void LLPipeline::generateSunShadow(LLCamera& camera) { glh_set_current_modelview(view[1]); glh_set_current_projection(proj[1]); - gGL.loadMatrix(view[1].m); + gGL.loadMatrix(view[1]); gGL.matrixMode(LLRender::MM_PROJECTION); - gGL.loadMatrix(proj[1].m); + gGL.loadMatrix(proj[1]); gGL.matrixMode(LLRender::MM_MODELVIEW); } gGL.setColorMask(true, false); - for (U32 i = 0; i < 16; i++) - { - gGLLastModelView[i] = last_modelview[i]; - gGLLastProjection[i] = last_projection[i]; - } + glh_set_last_modelview(last_modelview); + glh_set_last_projection(last_projection); popRenderTypeMask(); @@ -9625,7 +10370,7 @@ void LLPipeline::renderGroups(LLRenderPass* pass, U32 type, U32 mask, BOOL textu LLSpatialGroup* group = *i; if (!group->isDead() && (!sUseOcclusion || !group->isOcclusionState(LLSpatialGroup::OCCLUDED)) && - gPipeline.hasRenderType(group->mSpatialPartition->mDrawableType) && + gPipeline.hasRenderType(group->getSpatialPartition()->mDrawableType) && group->mDrawMap.find(type) != group->mDrawMap.end()) { pass->renderGroup(group,type,mask,texture); @@ -9633,17 +10378,17 @@ void LLPipeline::renderGroups(LLRenderPass* pass, U32 type, U32 mask, BOOL textu } } -static LLFastTimer::DeclareTimer FTM_IMPOSTOR_MARK_VISIBLE("Impostor Mark Visible"); -static LLFastTimer::DeclareTimer FTM_IMPOSTOR_SETUP("Impostor Setup"); -static LLFastTimer::DeclareTimer FTM_IMPOSTOR_BACKGROUND("Impostor Background"); -static LLFastTimer::DeclareTimer FTM_IMPOSTOR_ALLOCATE("Impostor Allocate"); -static LLFastTimer::DeclareTimer FTM_IMPOSTOR_RESIZE("Impostor Resize"); +static LLTrace::BlockTimerStatHandle FTM_IMPOSTOR_MARK_VISIBLE("Impostor Mark Visible"); +static LLTrace::BlockTimerStatHandle FTM_IMPOSTOR_SETUP("Impostor Setup"); +static LLTrace::BlockTimerStatHandle FTM_IMPOSTOR_BACKGROUND("Impostor Background"); +static LLTrace::BlockTimerStatHandle FTM_IMPOSTOR_ALLOCATE("Impostor Allocate"); +static LLTrace::BlockTimerStatHandle FTM_IMPOSTOR_RESIZE("Impostor Resize"); void LLPipeline::generateImpostor(LLVOAvatar* avatar) { - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - LLGLState::checkClientArrays(); + LLGLStateValidator::checkStates(); + LLGLStateValidator::checkTextureChannels(); + LLGLStateValidator::checkClientArrays(); static LLCullResult result; result.clear(); @@ -9656,33 +10401,36 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) assertInitialized(); - bool muted = avatar->isVisuallyMuted(); + bool visually_muted = avatar->isVisuallyMuted(); pushRenderTypeMask(); - if (muted) + if (visually_muted) { andRenderTypeMask(LLPipeline::RENDER_TYPE_AVATAR, END_RENDER_TYPES); } else { - andRenderTypeMask(LLPipeline::RENDER_TYPE_VOLUME, - LLPipeline::RENDER_TYPE_AVATAR, + andRenderTypeMask(LLPipeline::RENDER_TYPE_ALPHA, + LLPipeline::RENDER_TYPE_FULLBRIGHT, + LLPipeline::RENDER_TYPE_VOLUME, + LLPipeline::RENDER_TYPE_GLOW, LLPipeline::RENDER_TYPE_BUMP, - LLPipeline::RENDER_TYPE_GRASS, - LLPipeline::RENDER_TYPE_SIMPLE, - LLPipeline::RENDER_TYPE_FULLBRIGHT, - LLPipeline::RENDER_TYPE_ALPHA, - LLPipeline::RENDER_TYPE_INVISIBLE, LLPipeline::RENDER_TYPE_PASS_SIMPLE, LLPipeline::RENDER_TYPE_PASS_ALPHA, LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK, + LLPipeline::RENDER_TYPE_PASS_BUMP, + LLPipeline::RENDER_TYPE_PASS_POST_BUMP, LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT, LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK, LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY, + LLPipeline::RENDER_TYPE_PASS_GLOW, + LLPipeline::RENDER_TYPE_PASS_GRASS, LLPipeline::RENDER_TYPE_PASS_SHINY, - LLPipeline::RENDER_TYPE_PASS_INVISIBLE, - LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY, + LLPipeline::RENDER_TYPE_AVATAR, + LLPipeline::RENDER_TYPE_ALPHA_MASK, + LLPipeline::RENDER_TYPE_FULLBRIGHT_ALPHA_MASK, + LLPipeline::RENDER_TYPE_SIMPLE, END_RENDER_TYPES); } @@ -9695,7 +10443,7 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) LLViewerCamera* viewer_camera = LLViewerCamera::getInstance(); { - LLFastTimer t(FTM_IMPOSTOR_MARK_VISIBLE); + LL_RECORD_BLOCK_TIME(FTM_IMPOSTOR_MARK_VISIBLE); markVisible(avatar->mDrawable, *viewer_camera); LLVOAvatar::sUseImpostors = FALSE; @@ -9730,7 +10478,7 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) U32 resX = 0; { - LLFastTimer t(FTM_IMPOSTOR_SETUP); + LL_RECORD_BLOCK_TIME(FTM_IMPOSTOR_SETUP); const LLVector4a* ext = avatar->mDrawable->getSpatialExtents(); LLVector3 pos(avatar->getRenderPosition()+avatar->getImpostorOffset()); @@ -9761,18 +10509,19 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) F32 distance = (pos-camera.getOrigin()).length(); F32 fov = atanf(tdim.mV[1]/distance)*2.f*RAD_TO_DEG; F32 aspect = tdim.mV[0]/tdim.mV[1]; - glh::matrix4f persp = gl_perspective(fov, aspect, 1.f, 256.f); + LLMatrix4a persp = gGL.genPersp(fov, aspect, 1.f, 256.f); glh_set_current_projection(persp); - gGL.loadMatrix(persp.m); + gGL.loadMatrix(persp); gGL.matrixMode(LLRender::MM_MODELVIEW); gGL.pushMatrix(); - glh::matrix4f mat; - camera.getOpenGLTransform(mat.m); + LLMatrix4a mat; + camera.getOpenGLTransform(mat.getF32ptr()); + + mat.setMul(OGL_TO_CFR_ROTATION, mat); - mat = glh::matrix4f((GLfloat*) OGL_TO_CFR_ROTATION) * mat; + gGL.loadMatrix(mat); - gGL.loadMatrix(mat.m); glh_set_current_modelview(mat); glClearColor(0.0f,0.0f,0.0f,0.0f); @@ -9787,53 +10536,97 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) if (!avatar->mImpostor.isComplete()) { - LLFastTimer t(FTM_IMPOSTOR_ALLOCATE); - avatar->mImpostor.allocate(resX,resY,GL_RGBA,TRUE,FALSE); + LL_RECORD_BLOCK_TIME(FTM_IMPOSTOR_ALLOCATE); + if (LLPipeline::sRenderDeferred) { + avatar->mImpostor.allocate(resX,resY,GL_SRGB8_ALPHA8,TRUE,FALSE); addDeferredAttachments(avatar->mImpostor); } + else + { + avatar->mImpostor.allocate(resX,resY,GL_RGBA,TRUE,FALSE); + } gGL.getTexUnit(0)->bind(&avatar->mImpostor); gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); } - else if(resX != avatar->mImpostor.getWidth() || - resY != avatar->mImpostor.getHeight()) + else if(resX != avatar->mImpostor.getWidth() || resY != avatar->mImpostor.getHeight()) { - LLFastTimer t(FTM_IMPOSTOR_RESIZE); - avatar->mImpostor.resize(resX,resY,GL_RGBA); + LL_RECORD_BLOCK_TIME(FTM_IMPOSTOR_RESIZE); + avatar->mImpostor.resize(resX,resY); } avatar->mImpostor.bindTarget(); } + F32 old_alpha = LLDrawPoolAvatar::sMinimumAlpha; + + if (visually_muted) + { //disable alpha masking for muted avatars (get whole skin silhouette) + LLDrawPoolAvatar::sMinimumAlpha = 0.f; + } + if (LLPipeline::sRenderDeferred) { avatar->mImpostor.clear(); renderGeomDeferred(camera); + + renderGeomPostDeferred(camera); + + // Shameless hack time: render it all again, + // this time writing the depth + // values we need to generate the alpha mask below + // while preserving the alpha-sorted color rendering + // from the previous pass + // + sImpostorRenderAlphaDepthPass = true; + // depth-only here... + // + gGL.setColorMask(false,false); renderGeomPostDeferred(camera); + + sImpostorRenderAlphaDepthPass = false; + } else { - LLGLEnable scissor(GL_SCISSOR_TEST); - glScissor(0, 0, resX, resY); + LLGLEnable scissor; + gGL.setScissor(0, 0, resX, resY); avatar->mImpostor.clear(); renderGeom(camera); + + // Shameless hack time: render it all again, + // this time writing the depth + // values we need to generate the alpha mask below + // while preserving the alpha-sorted color rendering + // from the previous pass + // + sImpostorRenderAlphaDepthPass = true; + + // depth-only here... + // + gGL.setColorMask(false,false); + renderGeom(camera); + + sImpostorRenderAlphaDepthPass = false; } - + + LLDrawPoolAvatar::sMinimumAlpha = old_alpha; + { //create alpha mask based on depth buffer (grey out if muted) - LLFastTimer t(FTM_IMPOSTOR_BACKGROUND); + LL_RECORD_BLOCK_TIME(FTM_IMPOSTOR_BACKGROUND); if (LLPipeline::sRenderDeferred) { GLuint buff = GL_COLOR_ATTACHMENT0; glDrawBuffersARB(1, &buff); } - LLGLDisable blend(GL_BLEND); + LLGLDisable blend; - if (muted) + if (visually_muted) { gGL.setColorMask(true, true); } @@ -9858,21 +10651,21 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) if (LLGLSLShader::sNoFixedFunction) { - gUIProgram.bind(); + gDebugProgram.bind(); } - gGL.color4ub(64,64,64,255); - gGL.begin(LLRender::QUADS); + gGL.diffuseColor4ub(64,64,64,255); + gGL.begin(LLRender::TRIANGLE_STRIP); gGL.vertex3f(-1, -1, clip_plane); gGL.vertex3f(1, -1, clip_plane); - gGL.vertex3f(1, 1, clip_plane); gGL.vertex3f(-1, 1, clip_plane); + gGL.vertex3f(1, 1, clip_plane); gGL.end(); gGL.flush(); if (LLGLSLShader::sNoFixedFunction) { - gUIProgram.unbind(); + gDebugProgram.unbind(); } gGL.popMatrix(); @@ -9884,11 +10677,11 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) avatar->setImpostorDim(tdim); - LLVOAvatar::sUseImpostors = TRUE; + LLVOAvatar::sUseImpostors = true; sUseOcclusion = occlusion; - sReflectionRender = FALSE; - sImpostorRender = FALSE; - sShadowRender = FALSE; + sReflectionRender = false; + sImpostorRender = false; + sShadowRender = false; popRenderTypeMask(); gGL.matrixMode(LLRender::MM_PROJECTION); @@ -9898,11 +10691,12 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) avatar->mNeedsImpostorUpdate = FALSE; avatar->cacheImpostorValues(); + avatar->mLastImpostorUpdateFrameTime = gFrameTimeSeconds; LLVertexBuffer::unbind(); - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - LLGLState::checkClientArrays(); + LLGLStateValidator::checkStates(); + LLGLStateValidator::checkTextureChannels(); + LLGLStateValidator::checkClientArrays(); } BOOL LLPipeline::hasRenderBatches(const U32 type) const @@ -9952,7 +10746,7 @@ void LLPipeline::setRenderTypeMask(U32 type, ...) if (type > END_RENDER_TYPES) { - llerrs << "Invalid render type." << llendl; + LL_ERRS() << "Invalid render type." << LL_ENDL; } } @@ -9965,6 +10759,7 @@ BOOL LLPipeline::hasAnyRenderType(U32 type, ...) const { if (mRenderTypeEnabled[type]) { + va_end(args); return TRUE; } type = va_arg(args, U32); @@ -9973,7 +10768,7 @@ BOOL LLPipeline::hasAnyRenderType(U32 type, ...) const if (type > END_RENDER_TYPES) { - llerrs << "Invalid render type." << llendl; + LL_ERRS() << "Invalid render type." << LL_ENDL; } return FALSE; @@ -9990,7 +10785,7 @@ void LLPipeline::popRenderTypeMask() { if (mRenderTypeEnableStack.empty()) { - llerrs << "Depleted render type stack." << llendl; + LL_ERRS() << "Depleted render type stack." << LL_ENDL; } memcpy(mRenderTypeEnabled, mRenderTypeEnableStack.top().data(), sizeof(mRenderTypeEnabled)); @@ -10021,7 +10816,7 @@ void LLPipeline::andRenderTypeMask(U32 type, ...) if (type > END_RENDER_TYPES) { - llerrs << "Invalid render type." << llendl; + LL_ERRS() << "Invalid render type." << LL_ENDL; } for (U32 i = 0; i < LLPipeline::NUM_RENDER_TYPES; ++i) @@ -10046,7 +10841,7 @@ void LLPipeline::clearRenderTypeMask(U32 type, ...) if (type > END_RENDER_TYPES) { - llerrs << "Invalid render type." << llendl; + LL_ERRS() << "Invalid render type." << LL_ENDL; } } @@ -10141,3 +10936,21 @@ void LLPipeline::restoreHiddenObject( const LLUUID& id ) } */ +void LLPipeline::drawFullScreenRect() +{ + if(mAuxScreenRectVB.isNull()) + { + mAuxScreenRectVB = new LLVertexBuffer(AUX_VB_MASK, 0); + mAuxScreenRectVB->allocateBuffer(3, 0, true); + LLStrider vert; + mAuxScreenRectVB->getVertexStrider(vert); + + vert[0].set(-1.f,-1.f,0.f); + vert[1].set(3.f,-1.f,0.f); + vert[2].set(-1.f,3.f,0.f); + + } + mAuxScreenRectVB->setBuffer(LLVertexBuffer::MAP_VERTEX); + mAuxScreenRectVB->drawArrays(LLRender::TRIANGLES, 0, 3); +} + diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index 3bde9fbcd0..09d438b83c 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -35,13 +35,12 @@ #include "llcamera.h" #include "llerror.h" -#include "lldarrayptr.h" -#include "lldqueueptr.h" #include "lldrawpool.h" #include "llspatialpartition.h" #include "m4math.h" #include "llpointer.h" -#include "lldrawpool.h" +#include "lldrawpoolalpha.h" +#include "lldrawpoolmaterials.h" #include "llgl.h" #include "lldrawable.h" #include "llrendertarget.h" @@ -64,7 +63,11 @@ class LLRenderFunc; class LLCubeMap; class LLCullResult; class LLVOAvatar; +class LLVOPartGroup; class LLGLSLShader; +class LLDrawPoolAlpha; + +class LLMeshResponder; typedef enum e_avatar_skinning_method { @@ -76,36 +79,33 @@ BOOL compute_min_max(LLMatrix4& box, LLVector2& min, LLVector2& max); // Shouldn bool LLRayAABB(const LLVector3 ¢er, const LLVector3 &size, const LLVector3& origin, const LLVector3& dir, LLVector3 &coord, F32 epsilon = 0); BOOL setup_hud_matrices(); // use whole screen to render hud BOOL setup_hud_matrices(const LLRect& screen_region); // specify portion of screen (in pixels) to render hud attachments from (for picking) -glh::matrix4f glh_copy_matrix(F32* src); -glh::matrix4f glh_get_current_modelview(); -void glh_set_current_modelview(const glh::matrix4f& mat); -glh::matrix4f glh_get_current_projection(); -void glh_set_current_projection(glh::matrix4f& mat); -glh::matrix4f gl_ortho(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat znear, GLfloat zfar); -glh::matrix4f gl_perspective(GLfloat fovy, GLfloat aspect, GLfloat zNear, GLfloat zFar); -glh::matrix4f gl_lookat(LLVector3 eye, LLVector3 center, LLVector3 up); - -extern LLFastTimer::DeclareTimer FTM_RENDER_GEOMETRY; -extern LLFastTimer::DeclareTimer FTM_RENDER_GRASS; -extern LLFastTimer::DeclareTimer FTM_RENDER_INVISIBLE; -extern LLFastTimer::DeclareTimer FTM_RENDER_OCCLUSION; -extern LLFastTimer::DeclareTimer FTM_RENDER_SHINY; -extern LLFastTimer::DeclareTimer FTM_RENDER_SIMPLE; -extern LLFastTimer::DeclareTimer FTM_RENDER_TERRAIN; -extern LLFastTimer::DeclareTimer FTM_RENDER_TREES; -extern LLFastTimer::DeclareTimer FTM_RENDER_UI; -extern LLFastTimer::DeclareTimer FTM_RENDER_WATER; -extern LLFastTimer::DeclareTimer FTM_RENDER_WL_SKY; -extern LLFastTimer::DeclareTimer FTM_RENDER_ALPHA; -extern LLFastTimer::DeclareTimer FTM_RENDER_CHARACTERS; -extern LLFastTimer::DeclareTimer FTM_RENDER_BUMP; -extern LLFastTimer::DeclareTimer FTM_RENDER_FULLBRIGHT; -extern LLFastTimer::DeclareTimer FTM_RENDER_GLOW; -extern LLFastTimer::DeclareTimer FTM_STATESORT; -extern LLFastTimer::DeclareTimer FTM_PIPELINE; -extern LLFastTimer::DeclareTimer FTM_CLIENT_COPY; - - +const LLMatrix4a& glh_get_current_modelview(); +void glh_set_current_modelview(const LLMatrix4a& mat); +const LLMatrix4a& glh_get_current_projection(); +void glh_set_current_projection(const LLMatrix4a& mat); + +extern LLTrace::BlockTimerStatHandle FTM_RENDER_GEOMETRY; +extern LLTrace::BlockTimerStatHandle FTM_RENDER_GRASS; +extern LLTrace::BlockTimerStatHandle FTM_RENDER_OCCLUSION; +extern LLTrace::BlockTimerStatHandle FTM_RENDER_SHINY; +extern LLTrace::BlockTimerStatHandle FTM_RENDER_SIMPLE; +extern LLTrace::BlockTimerStatHandle FTM_RENDER_TERRAIN; +extern LLTrace::BlockTimerStatHandle FTM_RENDER_TREES; +extern LLTrace::BlockTimerStatHandle FTM_RENDER_UI; +extern LLTrace::BlockTimerStatHandle FTM_RENDER_WATER; +extern LLTrace::BlockTimerStatHandle FTM_RENDER_WL_SKY; +extern LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA; +extern LLTrace::BlockTimerStatHandle FTM_RENDER_CHARACTERS; +extern LLTrace::BlockTimerStatHandle FTM_RENDER_BUMP; +extern LLTrace::BlockTimerStatHandle FTM_RENDER_MATERIALS; +extern LLTrace::BlockTimerStatHandle FTM_RENDER_FULLBRIGHT; +extern LLTrace::BlockTimerStatHandle FTM_RENDER_GLOW; +extern LLTrace::BlockTimerStatHandle FTM_STATESORT; +extern LLTrace::BlockTimerStatHandle FTM_PIPELINE; +extern LLTrace::BlockTimerStatHandle FTM_CLIENT_COPY; + + +LL_ALIGN_PREFIX(16) class LLPipeline { public: @@ -115,8 +115,10 @@ class LLPipeline void destroyGL(); void restoreGL(); void resetVertexBuffers(); - void doResetVertexBuffers(); + void doResetVertexBuffers(bool forced = false); void resizeScreenTexture(); + void releaseOcclusionBuffers(); + void releaseVertexBuffers(); void releaseGLBuffers(); void releaseLUTBuffers(); void releaseScreenBuffers(); @@ -177,6 +179,12 @@ class LLPipeline // Object related methods void markVisible(LLDrawable *drawablep, LLCamera& camera); void markOccluder(LLSpatialGroup* group); + + //downsample source to dest, taking the maximum depth value per pixel in source and writing to dest + // if source's depth buffer cannot be bound for reading, a scratch space depth buffer must be provided + void downsampleDepthBuffer(LLRenderTarget& source, LLRenderTarget& dest, LLRenderTarget* scratch_space = NULL); + + void doOcclusion(LLCamera& camera, LLRenderTarget& source, LLRenderTarget& dest, LLRenderTarget* scratch_space = NULL); void doOcclusion(LLCamera& camera); void markNotCulled(LLSpatialGroup* group, LLCamera &camera); void markMoved(LLDrawable *drawablep, BOOL damped_motion = FALSE); @@ -189,21 +197,28 @@ class LLPipeline void markMeshDirty(LLSpatialGroup* group); //get the object between start and end that's closest to start. - LLViewerObject* lineSegmentIntersectInWorld(const LLVector3& start, const LLVector3& end, + LLViewerObject* lineSegmentIntersectInWorld(const LLVector4a& start, const LLVector4a& end, BOOL pick_transparent, + bool pick_rigged, S32* face_hit, // return the face hit - LLVector3* intersection = NULL, // return the intersection point + LLVector4a* intersection = NULL, // return the intersection point LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point - LLVector3* normal = NULL, // return the surface normal at the intersection point - LLVector3* bi_normal = NULL // return the surface bi-normal at the intersection point + LLVector4a* normal = NULL, // return the surface normal at the intersection point + LLVector4a* tangent = NULL // return the surface tangent at the intersection point ); - LLViewerObject* lineSegmentIntersectInHUD(const LLVector3& start, const LLVector3& end, + + //get the closest particle to start between start and end, returns the LLVOPartGroup and particle index + LLVOPartGroup* lineSegmentIntersectParticle(const LLVector4a& start, const LLVector4a& end, LLVector4a* intersection, + S32* face_hit); + + + LLViewerObject* lineSegmentIntersectInHUD(const LLVector4a& start, const LLVector4a& end, BOOL pick_transparent, S32* face_hit, // return the face hit - LLVector3* intersection = NULL, // return the intersection point + LLVector4a* intersection = NULL, // return the intersection point LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point - LLVector3* normal = NULL, // return the surface normal at the intersection point - LLVector3* bi_normal = NULL // return the surface bi-normal at the intersection point + LLVector4a* normal = NULL, // return the surface normal at the intersection point + LLVector4a* tangent = NULL // return the surface tangent at the intersection point ); // Something about these textures has changed. Dirty them. @@ -215,15 +230,9 @@ class LLPipeline void enableShadows(const BOOL enable_shadows); -// void setLocalLighting(const BOOL local_lighting); -// BOOL isLocalLightingEnabled() const; - S32 setLightingDetail(S32 level); - S32 getLightingDetail() const { return mLightingDetail; } - S32 getMaxLightingDetail() const; + void updateLocalLightingEnabled(); + bool isLocalLightingEnabled() const { return mLightingEnabled; } - void setUseVertexShaders(BOOL use_shaders); - BOOL getUseVertexShaders() const { return mVertexShadersEnabled; } - BOOL canUseVertexShaders(); BOOL canUseWindLightShaders() const; BOOL canUseWindLightShadersOnObjects() const; BOOL canUseAntiAliasing() const; @@ -242,11 +251,12 @@ class LLPipeline void createObjects(F32 max_dtime); void createObject(LLViewerObject* vobj); void processPartitionQ(); - void updateGeom(F32 max_dtime); + void updateGeom(F32 max_dtime, LLCamera& camera); void updateGL(); void rebuildPriorityGroups(); void rebuildGroups(); void clearRebuildGroups(); + void clearRebuildDrawables(); //calculate pixel area of given box from vantage point of given camera static F32 calcPixelArea(LLVector3 center, LLVector3 size, LLCamera& camera); @@ -260,6 +270,7 @@ class LLPipeline void forAllVisibleDrawables(void (*func)(LLDrawable*)); void renderObjects(U32 type, U32 mask, BOOL texture = TRUE, BOOL batch_texture = FALSE); + void renderMaskedObjects(U32 type, U32 mask, BOOL texture = TRUE, BOOL batch_texture = FALSE); void renderGroups(LLRenderPass* pass, U32 type, U32 mask, BOOL texture); void grabReferences(LLCullResult& result); @@ -274,19 +285,20 @@ class LLPipeline void renderGeom(LLCamera& camera, BOOL forceVBOUpdate = FALSE); void renderGeomDeferred(LLCamera& camera); - void renderGeomPostDeferred(LLCamera& camera); + void renderGeomPostDeferred(LLCamera& camera, bool do_occlusion=true); void renderGeomShadow(LLCamera& camera); - void bindDeferredShader(LLGLSLShader& shader, U32 light_index = 0, U32 noise_map = 0xFFFFFFFF); + void bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* diffuse_source = NULL, LLRenderTarget* light_source = NULL); void setupSpotLight(LLGLSLShader& shader, LLDrawable* drawablep); - void unbindDeferredShader(LLGLSLShader& shader); + void unbindDeferredShader(LLGLSLShader& shader, LLRenderTarget* diffuse_source = NULL, LLRenderTarget* light_source = NULL); void renderDeferredLighting(); + void renderDeferredLightingToRT(LLRenderTarget* target); void generateWaterReflection(LLCamera& camera); void generateSunShadow(LLCamera& camera); - void renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera& camera, LLCullResult& result, BOOL use_shader, BOOL use_occlusion, U32 target_width); + void renderShadow(const LLMatrix4a& view, const LLMatrix4a& proj, LLCamera& camera, LLCullResult& result, BOOL use_shader, BOOL use_occlusion, U32 target_width); void renderHighlights(); void renderDebug(); void renderPhysicsDisplay(); @@ -300,16 +312,18 @@ class LLPipeline void resetLocalLights(); //Default all gl light parameters. Used upon restoreGL. Fixes light brightness problems on fullscren toggle void calcNearbyLights(LLCamera& camera); - void setupHWLights(LLDrawPool* pool); - void setupAvatarLights(BOOL for_edit = FALSE); - void enableLights(U32 mask); - void enableLightsStatic(); - void enableLightsDynamic(); - void enableLightsAvatar(); - void enableLightsPreview(); - void enableLightsAvatarEdit(const LLColor4& color); - void enableLightsFullbright(const LLColor4& color); - void disableLights(); + void gatherLocalLights(); + void setupHWLights(); + void updateHWLightMode(U8 mode); + U8 setupFeatureLights(U8 cur_count); + void enableLights(U32 mask, LLGLState& light_state, const LLColor4* color = nullptr); + void enableLightsStatic(LLGLState& light_state); + void enableLightsDynamic(LLGLState& light_state); + void enableLightsAvatar(LLGLState& light_state); + void enableLightsPreview(LLGLState& light_state); + void enableLightsAvatarEdit(LLGLState& light_state, const LLColor4& color); + void enableLightsFullbright(LLGLState& light_state); + void disableLights(LLGLState& light_state); void shiftObjects(const LLVector3 &offset); @@ -348,6 +362,14 @@ class LLPipeline void pushRenderDebugFeatureMask(); void popRenderDebugFeatureMask(); + template + LLGLStateIface* pushRenderPassState(U8 newState = LLGLStateIface::CURRENT_STATE) { + llassert_always(mInRenderPass); + LLGLStateIface* stateObject = new LLGLState(newState); + mRenderPassStates.emplace_back(stateObject); + return stateObject; + } + static void toggleRenderType(U32 type); // For UI control of render features @@ -393,7 +415,10 @@ class LLPipeline static void setRenderHighlights(BOOL val); static void toggleRenderHighlights(void* data); static BOOL getRenderHighlights(void* data); + static void setRenderHighlightTextureChannel(LLRender::eTexIndex channel); // sets which UV setup to display in highlight overlay + static bool isRenderDeferredCapable(); + static bool isRenderDeferredDesired(); static void updateRenderDeferred(); static void refreshCachedSettings(); @@ -413,6 +438,15 @@ class LLPipeline bool assertInitialized() { const bool is_init = isInit(); if (!is_init) assertInitializedDoError(); return is_init; }; void hideDrawable( LLDrawable *pDrawable ); void unhideDrawable( LLDrawable *pDrawable ); + + void drawFullScreenRect(); + + void clearRenderPassStates() { + while (!mRenderPassStates.empty()) { + mRenderPassStates.pop_back(); + } + mInRenderPass = false; + } public: enum {GPU_CLASS_MAX = 3 }; @@ -423,13 +457,15 @@ class LLPipeline RENDER_TYPE_WL_SKY = LLDrawPool::POOL_WL_SKY, RENDER_TYPE_GROUND = LLDrawPool::POOL_GROUND, RENDER_TYPE_TERRAIN = LLDrawPool::POOL_TERRAIN, - RENDER_TYPE_SIMPLE = LLDrawPool::POOL_SIMPLE, - RENDER_TYPE_GRASS = LLDrawPool::POOL_GRASS, - RENDER_TYPE_FULLBRIGHT = LLDrawPool::POOL_FULLBRIGHT, - RENDER_TYPE_BUMP = LLDrawPool::POOL_BUMP, - RENDER_TYPE_AVATAR = LLDrawPool::POOL_AVATAR, + RENDER_TYPE_SIMPLE = LLDrawPool::POOL_SIMPLE, + RENDER_TYPE_GRASS = LLDrawPool::POOL_GRASS, + RENDER_TYPE_ALPHA_MASK = LLDrawPool::POOL_ALPHA_MASK, + RENDER_TYPE_FULLBRIGHT_ALPHA_MASK = LLDrawPool::POOL_FULLBRIGHT_ALPHA_MASK, + RENDER_TYPE_FULLBRIGHT = LLDrawPool::POOL_FULLBRIGHT, + RENDER_TYPE_BUMP = LLDrawPool::POOL_BUMP, + RENDER_TYPE_MATERIALS = LLDrawPool::POOL_MATERIALS, + RENDER_TYPE_AVATAR = LLDrawPool::POOL_AVATAR, RENDER_TYPE_TREE = LLDrawPool::POOL_TREE, - RENDER_TYPE_INVISIBLE = LLDrawPool::POOL_INVISIBLE, RENDER_TYPE_VOIDWATER = LLDrawPool::POOL_VOIDWATER, RENDER_TYPE_WATER = LLDrawPool::POOL_WATER, RENDER_TYPE_ALPHA = LLDrawPool::POOL_ALPHA, @@ -437,8 +473,6 @@ class LLPipeline RENDER_TYPE_PASS_SIMPLE = LLRenderPass::PASS_SIMPLE, RENDER_TYPE_PASS_GRASS = LLRenderPass::PASS_GRASS, RENDER_TYPE_PASS_FULLBRIGHT = LLRenderPass::PASS_FULLBRIGHT, - RENDER_TYPE_PASS_INVISIBLE = LLRenderPass::PASS_INVISIBLE, - RENDER_TYPE_PASS_INVISI_SHINY = LLRenderPass::PASS_INVISI_SHINY, RENDER_TYPE_PASS_FULLBRIGHT_SHINY = LLRenderPass::PASS_FULLBRIGHT_SHINY, RENDER_TYPE_PASS_SHINY = LLRenderPass::PASS_SHINY, RENDER_TYPE_PASS_BUMP = LLRenderPass::PASS_BUMP, @@ -447,6 +481,22 @@ class LLPipeline RENDER_TYPE_PASS_ALPHA = LLRenderPass::PASS_ALPHA, RENDER_TYPE_PASS_ALPHA_MASK = LLRenderPass::PASS_ALPHA_MASK, RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK = LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, + RENDER_TYPE_PASS_MATERIAL = LLRenderPass::PASS_MATERIAL, + RENDER_TYPE_PASS_MATERIAL_ALPHA = LLRenderPass::PASS_MATERIAL_ALPHA, + RENDER_TYPE_PASS_MATERIAL_ALPHA_MASK = LLRenderPass::PASS_MATERIAL_ALPHA_MASK, + RENDER_TYPE_PASS_MATERIAL_ALPHA_EMISSIVE= LLRenderPass::PASS_MATERIAL_ALPHA_EMISSIVE, + RENDER_TYPE_PASS_SPECMAP = LLRenderPass::PASS_SPECMAP, + RENDER_TYPE_PASS_SPECMAP_BLEND = LLRenderPass::PASS_SPECMAP_BLEND, + RENDER_TYPE_PASS_SPECMAP_MASK = LLRenderPass::PASS_SPECMAP_MASK, + RENDER_TYPE_PASS_SPECMAP_EMISSIVE = LLRenderPass::PASS_SPECMAP_EMISSIVE, + RENDER_TYPE_PASS_NORMMAP = LLRenderPass::PASS_NORMMAP, + RENDER_TYPE_PASS_NORMMAP_BLEND = LLRenderPass::PASS_NORMMAP_BLEND, + RENDER_TYPE_PASS_NORMMAP_MASK = LLRenderPass::PASS_NORMMAP_MASK, + RENDER_TYPE_PASS_NORMMAP_EMISSIVE = LLRenderPass::PASS_NORMMAP_EMISSIVE, + RENDER_TYPE_PASS_NORMSPEC = LLRenderPass::PASS_NORMSPEC, + RENDER_TYPE_PASS_NORMSPEC_BLEND = LLRenderPass::PASS_NORMSPEC_BLEND, + RENDER_TYPE_PASS_NORMSPEC_MASK = LLRenderPass::PASS_NORMSPEC_MASK, + RENDER_TYPE_PASS_NORMSPEC_EMISSIVE = LLRenderPass::PASS_NORMSPEC_EMISSIVE, // Following are object types (only used in drawable mRenderType) RENDER_TYPE_HUD = LLRenderPass::NUM_RENDER_TYPES, RENDER_TYPE_VOLUME, @@ -496,25 +546,22 @@ class LLPipeline RENDER_DEBUG_SHADOW_FRUSTA = 0x00040000, RENDER_DEBUG_SCULPTED = 0x00080000, RENDER_DEBUG_AVATAR_VOLUME = 0x00100000, - RENDER_DEBUG_BUILD_QUEUE = 0x00200000, - RENDER_DEBUG_AGENT_TARGET = 0x00400000, - RENDER_DEBUG_UPDATE_TYPE = 0x00800000, - RENDER_DEBUG_PHYSICS_SHAPES = 0x01000000, - RENDER_DEBUG_NORMALS = 0x02000000, - RENDER_DEBUG_LOD_INFO = 0x04000000, - RENDER_DEBUG_RENDER_COMPLEXITY = 0x08000000, - RENDER_DEBUG_ATTACHMENT_BYTES = 0x10000000, + RENDER_DEBUG_AVATAR_JOINTS = 0x00200000, + RENDER_DEBUG_BUILD_QUEUE = 0x00400000, + RENDER_DEBUG_AGENT_TARGET = 0x00800000, + RENDER_DEBUG_UPDATE_TYPE = 0x01000000, + RENDER_DEBUG_PHYSICS_SHAPES = 0x02000000, + RENDER_DEBUG_NORMALS = 0x04000000, + RENDER_DEBUG_LOD_INFO = 0x08000000, + RENDER_DEBUG_RENDER_COMPLEXITY = 0x10000000, + RENDER_DEBUG_ATTACHMENT_BYTES = 0x20000000, + RENDER_DEBUG_TEXEL_DENSITY = 0x40000000 }; public: LLSpatialPartition* getSpatialPartition(LLViewerObject* vobj); - void updateCamera(BOOL reset = FALSE); - - LLVector3 mFlyCamPosition; - LLQuaternion mFlyCamRotation; - BOOL mBackfaceCull; S32 mBatchCount; S32 mMatrixOpCount; @@ -524,16 +571,6 @@ class LLPipeline S32 mMeanBatchSize; S32 mTrianglesDrawn; S32 mNumVisibleNodes; - S32 mVerticesRelit; - - S32 mDebugTextureUploadCost; - S32 mDebugSculptUploadCost; - S32 mDebugMeshUploadCost; - - S32 mLightingChanges; - S32 mGeometryChanges; - - S32 mNumVisibleFaces; static S32 sCompiles; @@ -543,9 +580,7 @@ class LLPipeline static BOOL sDelayVBUpdate; static BOOL sAutoMaskAlphaDeferred; static BOOL sAutoMaskAlphaNonDeferred; - static BOOL sDisableShaders; // if TRUE, rendering will be done without shaders static BOOL sRenderBump; - static BOOL sBakeSunlight; static BOOL sNoAlpha; static BOOL sUseFarClip; static BOOL sShadowRender; @@ -555,6 +590,7 @@ class LLPipeline static BOOL sPickAvatar; static BOOL sReflectionRender; static BOOL sImpostorRender; + static BOOL sImpostorRenderAlphaDepthPass; static BOOL sUnderWaterRender; static BOOL sRenderGlow; static BOOL sTextureBindTest; @@ -565,77 +601,75 @@ class LLPipeline static BOOL sMemAllocationThrottled; static S32 sVisibleLightCount; static F32 sMinRenderSize; + static BOOL sRenderingHUDs; - //screen texture +public: + //screen texture LLRenderTarget mScreen; + LLRenderTarget mFinalScreen; LLRenderTarget mDeferredScreen; +private: LLRenderTarget mFXAABuffer; - LLRenderTarget mEdgeMap; +public: LLRenderTarget mDeferredDepth; +private: + LLRenderTarget mDeferredDownsampledDepth; LLRenderTarget mDeferredLight; +public: LLMultisampleBuffer mSampleBuffer; +private: LLRenderTarget mPhysicsDisplay; //utility buffer for rendering post effects, gets abused by renderDeferredLighting - LLPointer mDeferredVB; + LLPointer mAuxScreenRectVB; +public: //utility buffer for rendering cubes, 8 vertices are corners of a cube [-1, 1] LLPointer mCubeVB; +private: //sun shadow map LLRenderTarget mShadow[6]; std::vector mShadowFrustPoints[4]; - LLVector4 mShadowError; - LLVector4 mShadowFOV; - LLVector3 mShadowFrustOrigin[4]; +public: LLCamera mShadowCamera[8]; +private: LLVector3 mShadowExtents[4][2]; - glh::matrix4f mSunShadowMatrix[6]; - glh::matrix4f mShadowModelview[6]; - glh::matrix4f mShadowProjection[6]; - glh::matrix4f mGIMatrix; - glh::matrix4f mGIMatrixProj; - glh::matrix4f mGIModelview; - glh::matrix4f mGIProjection; - glh::matrix4f mGINormalMatrix; - glh::matrix4f mGIInvProj; - LLVector2 mGIRange; - F32 mGILightRadius; + LLMatrix4a mSunShadowMatrix[6]; + LLMatrix4a mShadowModelview[6]; + LLMatrix4a mShadowProjection[6]; LLPointer mShadowSpotLight[2]; F32 mSpotLightFade[2]; LLPointer mTargetShadowSpotLight[2]; LLVector4 mSunClipPlanes; - LLVector4 mSunOrthoClipPlanes; - - LLVector2 mScreenScale; - +public: //water reflection texture LLRenderTarget mWaterRef; //water distortion texture (refraction) LLRenderTarget mWaterDis; +private: //texture for making the glow LLRenderTarget mGlow[2]; //noise map - U32 mNoiseMap; - U32 mTrueNoiseMap; - U32 mLightFunc; + LLImageGL::GLTextureName mNoiseMap; + LLImageGL::GLTextureName mLightFunc; LLColor4 mSunDiffuse; LLVector3 mSunDir; - LLVector3 mTransformedSunDir; + LL_ALIGN_16(LLVector4a mTransformedSunDir); +public: BOOL mInitialized; BOOL mVertexShadersEnabled; - S32 mVertexShadersLoaded; // 0 = no, 1 = yes, -1 = failed U32 mTransformFeedbackPrimitives; //number of primitives expected to be generated by transform feedback -protected: +private: BOOL mRenderTypeEnabled[NUM_RENDER_TYPES]; std::stack mRenderTypeEnableStack; @@ -682,7 +716,6 @@ class LLPipeline LLDrawable::drawable_set_t mLights; light_set_t mNearbyLights; // lights near camera - LLColor4 mHWLightColors[8]; ///////////////////////////////////////////// // @@ -709,6 +742,9 @@ class LLPipeline LLDrawable::drawable_set_t mRetexturedList; + bool mInRenderPass; + std::vector< std::unique_ptr > mRenderPassStates; + ////////////////////////////////////////////////// // // Draw pools are responsible for storing all rendered data, @@ -742,17 +778,19 @@ class LLPipeline // For quick-lookups into mPools (mapped by texture pointer) std::map mTerrainPools; std::map mTreePools; - LLDrawPool* mAlphaPool; + LLDrawPoolAlpha* mAlphaPool; LLDrawPool* mSkyPool; LLDrawPool* mTerrainPool; LLDrawPool* mWaterPool; LLDrawPool* mGroundPool; LLRenderPass* mSimplePool; LLRenderPass* mGrassPool; + LLRenderPass* mAlphaMaskPool; + LLRenderPass* mFullbrightAlphaMaskPool; LLRenderPass* mFullbrightPool; - LLDrawPool* mInvisiblePool; LLDrawPool* mGlowPool; LLDrawPool* mBumpPool; + LLDrawPool* mMaterialsPool; LLDrawPool* mWLSkyPool; // Note: no need to keep an quick-lookup to avatar pools, since there's only one per avatar @@ -777,9 +815,11 @@ class LLPipeline LLPointer mFaceSelectImagep; + std::vector mLocalLights; + U8 mHWLightCount; + U8 mLightMode; U32 mLightMask; - U32 mLightMovingMask; - S32 mLightingDetail; + bool mLightingEnabled; static BOOL sRenderPhysicalBeacons; static BOOL sRenderMOAPBeacons; @@ -791,15 +831,19 @@ class LLPipeline static BOOL sRenderBeacons; static BOOL sRenderHighlight; + // Determines which set of UVs to use in highlight display + // + static LLRender::eTexIndex sRenderHighlightTextureChannel; + //debug use static U32 sCurRenderPoolType ; -}; +} LL_ALIGN_POSTFIX(16); void render_bbox(const LLVector3 &min, const LLVector3 &max); void render_hud_elements(); extern LLPipeline gPipeline; extern BOOL gDebugPipeline; -extern const LLMatrix4* gGLLastMatrix; +extern const LLMatrix4a* gGLLastMatrix; #endif diff --git a/indra/newview/qtoolalign.cpp b/indra/newview/qtoolalign.cpp index 6afa97f07e..7e537233bd 100644 --- a/indra/newview/qtoolalign.cpp +++ b/indra/newview/qtoolalign.cpp @@ -1,5 +1,5 @@ /** - * @file lltoolface.cpp + * @file qtoolalign.cpp * @brief A tool to align objects */ @@ -13,14 +13,11 @@ #include "v3math.h" // Viewer includes -#include "llagent.h" #include "llagentcamera.h" #include "llbox.h" #include "llcylinder.h" #include "llfloatertools.h" -#include "llmanip.h" #include "llselectmgr.h" -#include "lltoolcomp.h" #include "llviewercamera.h" #include "llviewercontrol.h" #include "llviewerobject.h" @@ -33,7 +30,7 @@ const F32 MANIPULATOR_SELECT_SIZE = 20.0; QToolAlign::QToolAlign() -: LLToolComposite(std::string("Align")) +: LLTool(std::string("Align")) { } @@ -48,49 +45,14 @@ BOOL QToolAlign::handleMouseDown(S32 x, S32 y, MASK mask) { if (mHighlightedAxis != -1) { - align(); + align(); } else { gViewerWindow->pickAsync(x, y, mask, pickCallback); } - - return TRUE; -} - -BOOL QToolAlign::handleMouseUp(S32 x, S32 y, MASK mask) -{ - // first, perform normal processing in case this was a quick-click - handleHover(x, y, mask); - LLSelectMgr::getInstance()->updateSelectionCenter(); - BOOL handled = FALSE; - if( hasMouseCapture() ) - { - handled = TRUE; - setMouseCapture( FALSE ); - } - return handled; -} -BOOL QToolAlign::handleDoubleClick(S32 x, S32 y, MASK mask) -{ - return FALSE; -} - -LLTool* QToolAlign::getOverrideTool(MASK mask) -{ - if (!gKeyboard->getKeyDown('A')) - { - if (mask == MASK_CONTROL) - { - return LLToolCompRotate::getInstance(); - } - else if (mask == (MASK_CONTROL | MASK_SHIFT)) - { - return LLToolCompScale::getInstance(); - } - } - return LLToolComposite::getOverrideTool(mask); + return TRUE; } void QToolAlign::pickCallback(const LLPickInfo& pick_info) @@ -140,9 +102,8 @@ void QToolAlign::handleSelect() { // no parts, please - //llwarns << "in select" << llendl; + LL_DEBUGS("ALIGNTOOL") << "in select" << LL_ENDL; LLSelectMgr::getInstance()->promoteSelectionToRoot(); - LLSelectMgr::getInstance()->updateSelectionCenter(); gFloaterTools->setStatusText("align"); } @@ -151,6 +112,7 @@ void QToolAlign::handleDeselect() { } + BOOL QToolAlign::findSelectedManipulator(S32 x, S32 y) { mHighlightedAxis = -1; @@ -161,7 +123,7 @@ BOOL QToolAlign::findSelectedManipulator(S32 x, S32 y) { LLVector4 translation(mBBox.getCenterAgent()); transform.initRotTrans(mBBox.getRotation(), translation); - LLMatrix4 cfr(OGL_TO_CFR_ROTATION); + LLMatrix4 cfr(OGL_TO_CFR_ROTATION.getF32ptr()); transform *= cfr; LLMatrix4 window_scale; F32 zoom_level = 2.f * gAgentCamera.mHUDCurZoom; @@ -174,16 +136,17 @@ BOOL QToolAlign::findSelectedManipulator(S32 x, S32 y) { transform.initAll(LLVector3(1.f, 1.f, 1.f), mBBox.getRotation(), mBBox.getCenterAgent()); - LLMatrix4 projection_matrix = LLViewerCamera::getInstance()->getProjection(); - LLMatrix4 model_matrix = LLViewerCamera::getInstance()->getModelview(); + LLMatrix4 projection_matrix( LLViewerCamera::getInstance()->getProjection().getF32ptr() ); + LLMatrix4 model_matrix( LLViewerCamera::getInstance()->getModelview().getF32ptr() ); transform *= model_matrix; transform *= projection_matrix; } - F32 half_width = (F32)gViewerWindow->getWindowWidth() / 2.f; - F32 half_height = (F32)gViewerWindow->getWindowHeight() / 2.f; + LLRect world_view_rect = gViewerWindow->getWorldViewRectScaled(); + F32 half_width = (F32)world_view_rect.getWidth() / 2.f; + F32 half_height = (F32)world_view_rect.getHeight() / 2.f; LLVector2 manip2d; LLVector2 mousePos((F32)x - half_width, (F32)y - half_height); LLVector2 delta; @@ -407,8 +370,8 @@ void QToolAlign::render() // Draw bounding box LLGLSUIDefault gls_ui; - LLGLEnable gl_blend(GL_BLEND); - LLGLEnable gls_alpha_test(GL_ALPHA_TEST); + LLGLEnable gl_blend; + LLGLEnable gls_alpha_test; LLGLDepthTest gls_depth(GL_FALSE); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); @@ -416,25 +379,24 @@ void QToolAlign::render() LLColor4 default_normal_color( 0.7f, 0.7f, 0.7f, 0.1f ); gGL.color4fv( default_normal_color.mV ); - + // LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getEditSelection(); - BOOL can_move = selection->getObjectCount() != 0; - if (can_move) + if (selection->getObjectCount() == 0) return; + struct F : public LLSelectedObjectFunctor { - struct f : public LLSelectedObjectFunctor + virtual bool apply(LLViewerObject* objectp) { - virtual bool apply(LLViewerObject* objectp) - { - return objectp->permMove() && (objectp->permModify() || !gSavedSettings.getBOOL("EditLinkedParts")); - } - } func; - can_move = selection->applyToObjects(&func); - } - if (can_move) - { - render_bbox(mBBox); - renderManipulators(); - } + if (!objectp->permMove()) return false; + if (objectp->permModify()) return true; + static const LLCachedControl edit_linked("EditLinkedParts"); + return !edit_linked; + } + } f; + if (!selection->applyToObjects(&f)) return; + // + + render_bbox(mBBox); + renderManipulators(); } // only works for our specialized (AABB, position centered) bboxes @@ -564,7 +526,7 @@ void QToolAlign::align() // check to see if it overlaps the previously placed objects BOOL overlap = FALSE; - llwarns << "i=" << i << " j=" << j << llendl; + LL_DEBUGS("ALIGNTOOL") << "i=" << i << " j=" << j << LL_ENDL; if (!mForce) // well, don't check if in force mode { @@ -577,8 +539,8 @@ void QToolAlign::align() if (overlaps_this) { - llwarns << "overlap" << new_bbox.getCenterAgent() << other_bbox.getCenterAgent() << llendl; - llwarns << "extent" << new_bbox.getExtentLocal() << other_bbox.getExtentLocal() << llendl; + LL_DEBUGS("ALIGNTOOL") << "overlap" << new_bbox.getCenterAgent() << other_bbox.getCenterAgent() << LL_ENDL; + LL_DEBUGS("ALIGNTOOL") << "extent" << new_bbox.getExtentLocal() << other_bbox.getExtentLocal() << LL_ENDL; } overlap = (overlap || overlaps_this); diff --git a/indra/newview/qtoolalign.h b/indra/newview/qtoolalign.h index 1bef073ba6..da70b34af7 100644 --- a/indra/newview/qtoolalign.h +++ b/indra/newview/qtoolalign.h @@ -8,14 +8,13 @@ #include "lltool.h" #include "llbbox.h" -#include "lltoolcomp.h" class LLViewerObject; class LLPickInfo; class LLToolSelectRect; class QToolAlign -: public LLToolComposite, public LLSingleton +: public LLTool, public LLSingleton { public: QToolAlign(); @@ -24,13 +23,9 @@ class QToolAlign virtual void handleSelect(); virtual void handleDeselect(); virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); - virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask); - virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); virtual BOOL handleHover(S32 x, S32 y, MASK mask); virtual void render(); - virtual LLTool* getOverrideTool(MASK mask); - static void pickCallback(const LLPickInfo& pick_info); private: diff --git a/indra/newview/res-sdl/ll_icon.BMP b/indra/newview/res-sdl/ll_icon.BMP deleted file mode 100644 index 4a44aafbfa..0000000000 Binary files a/indra/newview/res-sdl/ll_icon.BMP and /dev/null differ diff --git a/indra/newview/res-sdl/singularity_icon.BMP b/indra/newview/res-sdl/singularity_icon.BMP deleted file mode 100644 index 7e27d0eca4..0000000000 Binary files a/indra/newview/res-sdl/singularity_icon.BMP and /dev/null differ diff --git a/indra/newview/res-sdl/snowglobe_icon.BMP b/indra/newview/res-sdl/snowglobe_icon.BMP deleted file mode 100644 index af6eab9fe5..0000000000 Binary files a/indra/newview/res-sdl/snowglobe_icon.BMP and /dev/null differ diff --git a/indra/newview/res/Ascent_icon.png b/indra/newview/res/Ascent_icon.png deleted file mode 100644 index 92fa4158b4..0000000000 Binary files a/indra/newview/res/Ascent_icon.png and /dev/null differ diff --git a/indra/newview/res/icon1.ico b/indra/newview/res/icon1.ico deleted file mode 100644 index ad607598fa..0000000000 Binary files a/indra/newview/res/icon1.ico and /dev/null differ diff --git a/indra/newview/res/ll_icon.BMP b/indra/newview/res/ll_icon.BMP deleted file mode 100644 index 3a9964cd95..0000000000 Binary files a/indra/newview/res/ll_icon.BMP and /dev/null differ diff --git a/indra/newview/res/ll_icon.ico b/indra/newview/res/ll_icon.ico deleted file mode 100644 index c35a3fa3a3..0000000000 Binary files a/indra/newview/res/ll_icon.ico and /dev/null differ diff --git a/indra/newview/res/ll_icon.png b/indra/newview/res/ll_icon.png deleted file mode 100644 index 414b703111..0000000000 Binary files a/indra/newview/res/ll_icon.png and /dev/null differ diff --git a/indra/newview/res/singularity_icon.bmp b/indra/newview/res/singularity_icon.bmp deleted file mode 100644 index 7e27d0eca4..0000000000 Binary files a/indra/newview/res/singularity_icon.bmp and /dev/null differ diff --git a/indra/newview/res/singularity_icon.icns b/indra/newview/res/singularity_icon.icns new file mode 100644 index 0000000000..28e5a4f446 Binary files /dev/null and b/indra/newview/res/singularity_icon.icns differ diff --git a/indra/newview/res/singularity_icon.ico b/indra/newview/res/singularity_icon.ico deleted file mode 100644 index 84a455a226..0000000000 Binary files a/indra/newview/res/singularity_icon.ico and /dev/null differ diff --git a/indra/newview/res/singularity_icon.png b/indra/newview/res/singularity_icon.png index 67396b366f..ae3d64aa33 100644 Binary files a/indra/newview/res/singularity_icon.png and b/indra/newview/res/singularity_icon.png differ diff --git a/indra/newview/res/singularity_icon_bc.ico b/indra/newview/res/singularity_icon_bc.ico deleted file mode 100644 index 1287f3e209..0000000000 Binary files a/indra/newview/res/singularity_icon_bc.ico and /dev/null differ diff --git a/indra/newview/res/snowglobe_icon.BMP b/indra/newview/res/snowglobe_icon.BMP deleted file mode 100644 index 778779b1fd..0000000000 Binary files a/indra/newview/res/snowglobe_icon.BMP and /dev/null differ diff --git a/indra/newview/res/snowglobe_icon.ico b/indra/newview/res/snowglobe_icon.ico deleted file mode 100644 index 84a455a226..0000000000 Binary files a/indra/newview/res/snowglobe_icon.ico and /dev/null differ diff --git a/indra/newview/res/snowglobe_icon.png b/indra/newview/res/snowglobe_icon.png deleted file mode 100644 index 7e00cb75c3..0000000000 Binary files a/indra/newview/res/snowglobe_icon.png and /dev/null differ diff --git a/indra/newview/res/viewerRes.rc b/indra/newview/res/viewerRes.rc deleted file mode 100644 index 58d60ee33f..0000000000 --- a/indra/newview/res/viewerRes.rc +++ /dev/null @@ -1,193 +0,0 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" - -#ifdef IDC_STATIC -#undef IDC_STATIC -#endif -#define IDC_STATIC (-1) -#include "winresrc.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -// Commented out because it only compiles if you have MFC installed. -//#include "winres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (U.S.) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -#ifdef _WIN32 -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) -#endif //_WIN32 - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""winres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// Icon -// - -// Icon with lowest ID value placed first to ensure application icon -// remains consistent on all systems. -IDI_LL_ICON ICON "singularity_icon.ico" -IDI_LCD_LL_ICON ICON "singularity_icon.ico" - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -SPLASHSCREEN DIALOG 32, 32, 144, 34 -STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_VISIBLE -FONT 8, "MS Sans Serif" -BEGIN - ICON IDI_LL_ICON,IDC_STATIC,7,7,20,20 - LTEXT "Loading Second Life...",666,36,13,91,8 -END - - -///////////////////////////////////////////////////////////////////////////// -// -// DESIGNINFO -// - -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO -BEGIN - - "SPLASHSCREEN", DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 137 - VERTGUIDE, 36 - TOPMARGIN, 7 - BOTTOMMARGIN, 27 - END -END -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// Cursor -// - -TOOLGRAB CURSOR "lltoolgrab.cur" -TOOLLAND CURSOR "lltoolland.cur" -TOOLZOOMIN CURSOR "lltoolzoomin.cur" -TOOLCREATE CURSOR "lltoolcreate.cur" -ARROWDRAG CURSOR "llarrowdrag.cur" -ARROW CURSOR "llarrow.cur" -NOLOCKED CURSOR "llnolocked.cur" -ARROWLOCKED CURSOR "llarrowlocked.cur" -GRABLOCKED CURSOR "llgrablocked.cur" -TOOLROTATE CURSOR "lltoolrotate.cur" -TOOLTRANSLATE CURSOR "lltooltranslate.cur" -TOOLSCALE CURSOR "lltoolscale.cur" -TOOLCAMERA CURSOR "lltoolcamera.cur" -TOOLPAN CURSOR "lltoolpan.cur" -TOOLFOCUS CURSOR "lltoolfocus.cur" -TOOLPICKOBJECT3 CURSOR "toolpickobject3.cur" -ARROWCOPY CURSOR "arrowcop.cur" -ARROWDRAGMULTI CURSOR "llarrowdragmulti.cur" -ARROWCOPYMULTI CURSOR "arrowcopmulti.cur" -TOOLSIT CURSOR "toolsit.cur" -TOOLBUY CURSOR "toolbuy.cur" -TOOLPAY CURSOR "toolpay.cur" -TOOLOPEN CURSOR "toolopen.cur" -TOOLPIPETTE CURSOR "toolpipette.cur" -TOOLPLAY CURSOR "toolplay.cur" -TOOLPAUSE CURSOR "toolpause.cur" -TOOLMEDIAOPEN CURSOR "toolmediaopen.cur" - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,5,0,0 - PRODUCTVERSION 1,5,0,0 - FILEFLAGSMASK 0x3fL -#ifdef _DEBUG - FILEFLAGS 0x1L -#else - FILEFLAGS 0x0L -#endif - FILEOS 0x40004L - FILETYPE 0x1L - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "CompanyName", "Siana Gearz" - VALUE "FileDescription", "Singularity Viewer" - VALUE "FileVersion", "1.5.0.0" - VALUE "InternalName", "Second Life" - VALUE "LegalCopyright", "Copyright 2001-2010, Linden Research, Inc., Copyright 2010 Siana Gearz" - VALUE "OriginalFilename", "singularity.exe" - VALUE "ProductName", "Singularity Viewer" - VALUE "ProductVersion", "1.5.0.0" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END - - -///////////////////////////////////////////////////////////////////////////// -// -// Bitmap -// - -#endif // English (U.S.) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - diff --git a/indra/newview/res/viewerRes.rc.in b/indra/newview/res/viewerRes.rc.in new file mode 100644 index 0000000000..44c8104aab --- /dev/null +++ b/indra/newview/res/viewerRes.rc.in @@ -0,0 +1,180 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "windows.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""windows.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_LL_ICON ICON "viewer_icon.ico" +IDI_LCD_LL_ICON ICON "viewer_icon.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +SPLASHSCREEN DIALOG 32, 32, 144, 34 +STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_VISIBLE +FONT 8, "MS Sans Serif" +BEGIN + ICON IDI_LL_ICON,IDC_STATIC,7,7,20,20 + LTEXT "Loading ${VIEWER_CHANNEL} Viewer...",666,36,13,91,8 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + + "SPLASHSCREEN", DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 137 + VERTGUIDE, 36 + TOPMARGIN, 7 + BOTTOMMARGIN, 27 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Cursor +// + +TOOLGRAB CURSOR "lltoolgrab.cur" +TOOLLAND CURSOR "lltoolland.cur" +TOOLZOOMIN CURSOR "lltoolzoomin.cur" +TOOLCREATE CURSOR "lltoolcreate.cur" +ARROWDRAG CURSOR "llarrowdrag.cur" +ARROW CURSOR "llarrow.cur" +NOLOCKED CURSOR "llnolocked.cur" +ARROWLOCKED CURSOR "llarrowlocked.cur" +GRABLOCKED CURSOR "llgrablocked.cur" +TOOLROTATE CURSOR "lltoolrotate.cur" +TOOLTRANSLATE CURSOR "lltooltranslate.cur" +TOOLSCALE CURSOR "lltoolscale.cur" +TOOLCAMERA CURSOR "lltoolcamera.cur" +TOOLPAN CURSOR "lltoolpan.cur" +TOOLFOCUS CURSOR "lltoolfocus.cur" +TOOLPICKOBJECT3 CURSOR "toolpickobject3.cur" +ARROWCOPY CURSOR "arrowcop.cur" +ARROWDRAGMULTI CURSOR "llarrowdragmulti.cur" +ARROWCOPYMULTI CURSOR "arrowcopmulti.cur" +TOOLPIPETTE CURSOR "toolpipette.cur" +TOOLPLAY CURSOR "toolplay.cur" +TOOLPAUSE CURSOR "toolpause.cur" +TOOLMEDIAOPEN CURSOR "toolmediaopen.cur" +TOOLBUY CURSOR "toolbuy.cur" +TOOLPAY CURSOR "toolpay.cur" +TOOLOPEN CURSOR "toolopen.cur" +TOOLSIT CURSOR "toolsit.cur" + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION ${VIEWER_VERSION_MAJOR},${VIEWER_VERSION_MINOR},${VIEWER_VERSION_PATCH},${VIEWER_VERSION_REVISION} + PRODUCTVERSION ${VIEWER_VERSION_MAJOR},${VIEWER_VERSION_MINOR},${VIEWER_VERSION_PATCH},${VIEWER_VERSION_REVISION} + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "Siana Gearz" + VALUE "FileDescription", "${VIEWER_CHANNEL} Viewer" + VALUE "FileVersion", "${VIEWER_VERSION_MAJOR}.${VIEWER_VERSION_MINOR}.${VIEWER_VERSION_PATCH}.${VIEWER_VERSION_REVISION}" + VALUE "InternalName", "Second Life" + VALUE "LegalCopyright", "Copyright 2001-2010, Linden Research, Inc., Copyright 2010 Siana Gearz" + VALUE "OriginalFilename", "SingularityViewer.exe" + VALUE "ProductName", "${VIEWER_CHANNEL} Viewer" + VALUE "ProductVersion", "${VIEWER_VERSION_MAJOR}.${VIEWER_VERSION_MINOR}.${VIEWER_VERSION_PATCH}.${VIEWER_VERSION_REVISION}" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/indra/newview/res/viewerRes_bc.rc b/indra/newview/res/viewerRes_bc.rc deleted file mode 100644 index 6649c21c94..0000000000 --- a/indra/newview/res/viewerRes_bc.rc +++ /dev/null @@ -1,193 +0,0 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" - -#ifdef IDC_STATIC -#undef IDC_STATIC -#endif -#define IDC_STATIC (-1) -#include "winresrc.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -// Commented out because it only compiles if you have MFC installed. -//#include "winres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (U.S.) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -#ifdef _WIN32 -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) -#endif //_WIN32 - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""winres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// Icon -// - -// Icon with lowest ID value placed first to ensure application icon -// remains consistent on all systems. -IDI_LL_ICON ICON "singularity_icon_bc.ico" -IDI_LCD_LL_ICON ICON "singularity_icon_bc.ico" - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -SPLASHSCREEN DIALOG 32, 32, 144, 34 -STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_VISIBLE -FONT 8, "MS Sans Serif" -BEGIN - ICON IDI_LL_ICON,IDC_STATIC,7,7,20,20 - LTEXT "Loading Second Life...",666,36,13,91,8 -END - - -///////////////////////////////////////////////////////////////////////////// -// -// DESIGNINFO -// - -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO -BEGIN - - "SPLASHSCREEN", DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 137 - VERTGUIDE, 36 - TOPMARGIN, 7 - BOTTOMMARGIN, 27 - END -END -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// Cursor -// - -TOOLGRAB CURSOR "lltoolgrab.cur" -TOOLLAND CURSOR "lltoolland.cur" -TOOLZOOMIN CURSOR "lltoolzoomin.cur" -TOOLCREATE CURSOR "lltoolcreate.cur" -ARROWDRAG CURSOR "llarrowdrag.cur" -ARROW CURSOR "llarrow.cur" -NOLOCKED CURSOR "llnolocked.cur" -ARROWLOCKED CURSOR "llarrowlocked.cur" -GRABLOCKED CURSOR "llgrablocked.cur" -TOOLROTATE CURSOR "lltoolrotate.cur" -TOOLTRANSLATE CURSOR "lltooltranslate.cur" -TOOLSCALE CURSOR "lltoolscale.cur" -TOOLCAMERA CURSOR "lltoolcamera.cur" -TOOLPAN CURSOR "lltoolpan.cur" -TOOLFOCUS CURSOR "lltoolfocus.cur" -TOOLPICKOBJECT3 CURSOR "toolpickobject3.cur" -ARROWCOPY CURSOR "arrowcop.cur" -ARROWDRAGMULTI CURSOR "llarrowdragmulti.cur" -ARROWCOPYMULTI CURSOR "arrowcopmulti.cur" -TOOLSIT CURSOR "toolsit.cur" -TOOLBUY CURSOR "toolbuy.cur" -TOOLPAY CURSOR "toolpay.cur" -TOOLOPEN CURSOR "toolopen.cur" -TOOLPIPETTE CURSOR "toolpipette.cur" -TOOLPLAY CURSOR "toolplay.cur" -TOOLPAUSE CURSOR "toolpause.cur" -TOOLMEDIAOPEN CURSOR "toolmediaopen.cur" - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,5,0,0 - PRODUCTVERSION 1,5,0,0 - FILEFLAGSMASK 0x3fL -#ifdef _DEBUG - FILEFLAGS 0x1L -#else - FILEFLAGS 0x0L -#endif - FILEOS 0x40004L - FILETYPE 0x1L - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "CompanyName", "Siana Gearz" - VALUE "FileDescription", "Singularity Viewer" - VALUE "FileVersion", "1.5.0.0" - VALUE "InternalName", "Second Life" - VALUE "LegalCopyright", "Copyright 2001-2010, Linden Research, Inc., Copyright 2010 Siana Gearz" - VALUE "OriginalFilename", "singularity.exe" - VALUE "ProductName", "Singularity Viewer" - VALUE "ProductVersion", "1.5.0.0" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END - - -///////////////////////////////////////////////////////////////////////////// -// -// Bitmap -// - -#endif // English (U.S.) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - diff --git a/indra/newview/rlvactions.cpp b/indra/newview/rlvactions.cpp new file mode 100644 index 0000000000..6dd15cf49a --- /dev/null +++ b/indra/newview/rlvactions.cpp @@ -0,0 +1,161 @@ +/** + * + * Copyright (c) 2009-2016, Kitty Barnett + * + * The source code in this file is provided to you under the terms of the + * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt + * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt + * + * By copying, modifying or distributing this software, you acknowledge that + * you have read and understood your obligations described above, and agree to + * abide by those obligations. + * + */ + +#include "llviewerprecompiledheaders.h" +#include "llimview.h" +#include "llvoavatarself.h" +#include "rlvactions.h" +#include "rlvhandler.h" + +// ============================================================================ +// Communication/Avatar interaction +// + +bool RlvActions::s_BlockNamesContexts[SNC_COUNT] = { 0 }; + +// Checked: 2010-11-30 (RLVa-1.3.0) +bool RlvActions::canReceiveIM(const LLUUID& idSender) +{ + // User can receive an IM from "sender" (could be an agent or a group) if: + // - not generally restricted from receiving IMs (or the sender is an exception) + // - not specifically restricted from receiving an IM from the sender + return + (!rlv_handler_t::isEnabled()) || + ( ( (!gRlvHandler.hasBehaviour(RLV_BHVR_RECVIM)) || (gRlvHandler.isException(RLV_BHVR_RECVIM, idSender)) ) && + ( (!gRlvHandler.hasBehaviour(RLV_BHVR_RECVIMFROM)) || (!gRlvHandler.isException(RLV_BHVR_RECVIMFROM, idSender)) ) ); +} + +bool RlvActions::canSendChannel(int nChannel) +{ + return + ( (!gRlvHandler.hasBehaviour(RLV_BHVR_SENDCHANNEL)) || (gRlvHandler.isException(RLV_BHVR_SENDCHANNEL, nChannel)) ) /*&& + ( (!gRlvHandler.hasBehaviour(RLV_BHVR_SENDCHANNELEXCEPT)) || (!gRlvHandler.isException(RLV_BHVR_SENDCHANNELEXCEPT, nChannel)) )*/; +} + +// Checked: 2010-11-30 (RLVa-1.3.0) +bool RlvActions::canSendIM(const LLUUID& idRecipient) +{ + // User can send an IM to "recipient" (could be an agent or a group) if: + // - not generally restricted from sending IMs (or the recipient is an exception) + // - not specifically restricted from sending an IM to the recipient + return + (!rlv_handler_t::isEnabled()) || + ( ( (!gRlvHandler.hasBehaviour(RLV_BHVR_SENDIM)) || (gRlvHandler.isException(RLV_BHVR_SENDIM, idRecipient)) ) && + ( (!gRlvHandler.hasBehaviour(RLV_BHVR_SENDIMTO)) || (!gRlvHandler.isException(RLV_BHVR_SENDIMTO, idRecipient)) ) ); +} + +// Checked: 2011-04-12 (RLVa-1.3.0) +bool RlvActions::canStartIM(const LLUUID& idRecipient) +{ + // User can start an IM session with "recipient" (could be an agent or a group) if: + // - not generally restricted from starting IM sessions (or the recipient is an exception) + // - not specifically restricted from starting an IM session with the recipient + return + (!rlv_handler_t::isEnabled()) || + ( ( (!gRlvHandler.hasBehaviour(RLV_BHVR_STARTIM)) || (gRlvHandler.isException(RLV_BHVR_STARTIM, idRecipient)) ) && + ( (!gRlvHandler.hasBehaviour(RLV_BHVR_STARTIMTO)) || (!gRlvHandler.isException(RLV_BHVR_STARTIMTO, idRecipient)) ) ); +} + +// Handles: @chatwhisper, @chatnormal and @chatshout +EChatType RlvActions::checkChatVolume(EChatType chatType) +{ + // In vs Bhvr | whisper | normal | shout | n+w | n+s | s+w | s+n+w | + // --------------------------------------------------------------------------------- + // whisper | normal | - | - | normal | - | normal | normal | + // normal | - | whisper | - | whisper | whisper | - | whisper | + // shout | - | whisper | normal | whisper | whisper | normal | whisper | + + RlvHandler& rlvHandler = gRlvHandler; + if ( ((CHAT_TYPE_SHOUT == chatType) || (CHAT_TYPE_NORMAL == chatType)) && (rlvHandler.hasBehaviour(RLV_BHVR_CHATNORMAL)) ) + chatType = CHAT_TYPE_WHISPER; + else if ( (CHAT_TYPE_SHOUT == chatType) && (rlvHandler.hasBehaviour(RLV_BHVR_CHATSHOUT)) ) + chatType = CHAT_TYPE_NORMAL; + else if ( (CHAT_TYPE_WHISPER == chatType) && (rlvHandler.hasBehaviour(RLV_BHVR_CHATWHISPER)) ) + chatType = CHAT_TYPE_NORMAL; + return chatType; +} + +// ============================================================================ +// Movement +// + +bool RlvActions::canAcceptTpOffer(const LLUUID& idSender) +{ + return ((!gRlvHandler.hasBehaviour(RLV_BHVR_TPLURE)) || (gRlvHandler.isException(RLV_BHVR_TPLURE, idSender))) && (canStand()); +} + +bool RlvActions::autoAcceptTeleportOffer(const LLUUID& idSender) +{ + return ((idSender.notNull()) && (gRlvHandler.isException(RLV_BHVR_ACCEPTTP, idSender))) || (gRlvHandler.hasBehaviour(RLV_BHVR_ACCEPTTP)); +} + +bool RlvActions::canAcceptTpRequest(const LLUUID& idSender) +{ + return (!gRlvHandler.hasBehaviour(RLV_BHVR_TPREQUEST)) || (gRlvHandler.isException(RLV_BHVR_TPREQUEST, idSender)); +} + +bool RlvActions::autoAcceptTeleportRequest(const LLUUID& idRequester) +{ + return ((idRequester.notNull()) && (gRlvHandler.isException(RLV_BHVR_ACCEPTTPREQUEST, idRequester))) || (gRlvHandler.hasBehaviour(RLV_BHVR_ACCEPTTPREQUEST)); +} + +// ============================================================================ +// World interaction +// + +// Checked: 2010-03-07 (RLVa-1.2.0) +bool RlvActions::canStand() +{ + // NOTE: return FALSE only if we're @unsit=n restricted and the avie is currently sitting on something and TRUE for everything else + return (!gRlvHandler.hasBehaviour(RLV_BHVR_UNSIT)) || ((isAgentAvatarValid()) && (!gAgentAvatarp->isSitting())); +} + +// Checked: 2014-02-24 (RLVa-1.4.10) +bool RlvActions::canShowLocation() +{ + return !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC); +} + +// ============================================================================ +// Helper functions +// + +// Checked: 2013-05-10 (RLVa-1.4.9) +bool RlvActions::hasBehaviour(ERlvBehaviour eBhvr) +{ + return gRlvHandler.hasBehaviour(eBhvr); +} + +// Checked: 2013-05-09 (RLVa-1.4.9) +bool RlvActions::hasOpenP2PSession(const LLUUID& idAgent) +{ + const LLUUID idSession = LLIMMgr::computeSessionID(IM_NOTHING_SPECIAL, idAgent); + return (idSession.notNull()) && (LLIMMgr::instance().hasSession(idSession)); +} + +// Checked: 2013-05-09 (RLVa-1.4.9) +bool RlvActions::hasOpenGroupSession(const LLUUID& idGroup) +{ + return (idGroup.notNull()) && (LLIMMgr::instance().hasSession(idGroup)); +} + +// Checked: 2013-11-08 (RLVa-1.4.9) +bool RlvActions::isRlvEnabled() +{ + return RlvHandler::isEnabled(); +} + +// ============================================================================ diff --git a/indra/newview/rlvactions.h b/indra/newview/rlvactions.h new file mode 100644 index 0000000000..175926797e --- /dev/null +++ b/indra/newview/rlvactions.h @@ -0,0 +1,135 @@ +/** + * + * Copyright (c) 2009-2016, Kitty Barnett + * + * The source code in this file is provided to you under the terms of the + * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt + * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt + * + * By copying, modifying or distributing this software, you acknowledge that + * you have read and understood your obligations described above, and agree to + * abide by those obligations. + * + */ + +#ifndef RLV_ACTIONS_H +#define RLV_ACTIONS_H + +#include "llchat.h" +#include "rlvdefines.h" + +// ============================================================================ +// RlvActions class declaration - developer-friendly non-RLVa code facing class, use in lieu of RlvHandler whenever possible +// + +class RlvActions +{ + // ================================ + // Communication/Avatar interaction + // ================================ +public: + /* + * Returns true if the user is allowed to receive IMs from the specified sender (can be an avatar or a group) + */ + static bool canReceiveIM(const LLUUID& idSender); + + /* + * Returns true if the user is allowed to chat on the specified channel + */ + static bool canSendChannel(int nChannel); + + /* + * Returns true if the user is allowed to send IMs to the specified recipient (can be an avatar or a group) + */ + static bool canSendIM(const LLUUID& idRecipient); + + /* + * Returns true if the user is allowed to start a - P2P or group - conversation with the specified UUID. + */ + static bool canStartIM(const LLUUID& idRecipient); // @startim and @startimto + + /* + * Returns true if an avatar's name should be hidden for the requested operation/context + * (This is used to hide an avatar name in one case but not a near-identical case - such as teleporting a friend vs a nearby agent - + * in a way that limits the amount of code that needs to be changed to carry context from one function to another) + */ + enum EShowNamesContext { SNC_TELEPORTOFFER = 0, SNC_TELEPORTREQUEST, SNC_COUNT }; + static bool canShowName(EShowNamesContext eContext) { return (eContext < SNC_COUNT) ? !s_BlockNamesContexts[eContext] : false; } + static void setShowName(EShowNamesContext eContext, bool fShowName) { if ( (eContext < SNC_COUNT) && (isRlvEnabled()) ) { s_BlockNamesContexts[eContext] = !fShowName; } } + + /* + * Checks if the user is allowed to use the specified volume in (main) chat and returns the appropriate chat volume type + */ + static EChatType checkChatVolume(EChatType chatType); + +protected: + // Backwards logic so that we can initialize to 0 and it won't block when we forget to/don't check if RLVa is disabled + static bool s_BlockNamesContexts[SNC_COUNT]; + + // ======== + // Movement + // ======== +public: + /* + * Returns true if the user can accept an incoming teleport offer from the specified avatar + */ + static bool canAcceptTpOffer(const LLUUID& idSender); + + /* + * Returns true if a teleport offer from the specified avatar should be auto-accepted + * (pass the null UUID to check if all teleport offers should be auto-accepted regardless of sender) + */ + static bool autoAcceptTeleportOffer(const LLUUID& idSender); + + /* + * Returns true if the user can accept an incoming teleport request from the specified avatar + */ + static bool canAcceptTpRequest(const LLUUID& idSender); + + /* + * Returns true if a teleport request from the specified avatar should be auto-accepted + * (pass the null UUID to check if all teleport requests should be auto-accepted regardless of requester) + */ + static bool autoAcceptTeleportRequest(const LLUUID& idRequester); + + // ================= + // World interaction + // ================= +public: + /* + * Returns true if the user can stand up (returns true if the user isn't currently sitting) + */ + static bool canStand(); + + /* + * Returns true if the user can see their in-world location + */ + static bool canShowLocation(); + + // ================ + // Helper functions + // ================ +public: + /* + * Convenience function to check for a behaviour without having to include rlvhandler.h. + * Do NOT call this function if speed is important (i.e. per-frame) + */ + static bool hasBehaviour(ERlvBehaviour eBhvr); + + /* + * Returns true if a - P2P or group - IM session is open with the specified UUID + */ + static bool hasOpenP2PSession(const LLUUID& idAgent); + static bool hasOpenGroupSession(const LLUUID& idGroup); + + /* + * Convenience function to check if RLVa is enabled without having to include rlvhandler.h + */ + static bool isRlvEnabled(); +}; + +// ============================================================================ + +#endif // RLV_ACTIONS_H diff --git a/indra/newview/rlvcommon.cpp b/indra/newview/rlvcommon.cpp index e24c5f3d89..7410c58970 100644 --- a/indra/newview/rlvcommon.cpp +++ b/indra/newview/rlvcommon.cpp @@ -18,63 +18,36 @@ #include "llagent.h" #include "llagentui.h" #include "llavatarnamecache.h" +#include "llinstantmessage.h" #include "llnotificationsutil.h" +#include "llsdserialize.h" #include "lluictrlfactory.h" -#include "sgversion.h" #include "llviewermenu.h" #include "llviewerparcelmgr.h" #include "llviewermenu.h" #include "llviewerregion.h" -#include "llviewerstats.h" -#include "llvoavatar.h" #include "llworld.h" +#include "rlvactions.h" #include "rlvcommon.h" #include "rlvhelper.h" #include "rlvhandler.h" #include "rlvlocks.h" #include "../lscript/lscript_byteformat.h" //Need LSCRIPTRunTimePermissionBits and SCRIPT_PERMISSION_* -#include - -using namespace LLOldEvents; +#include // icontains +#include // regex_replace_all // ============================================================================ // RlvNotifications // -#ifdef RLV_EXTENSION_NOTIFY_BEHAVIOUR -// Checked: 2009-12-05 (RLVa-1.1.0h) | Added: RLVa-1.1.0h -/*void RlvNotifications::notifyBehaviour(ERlvBehaviour eBhvr, ERlvParamType eType) -{ - const std::string& strMsg = RlvStrings::getBehaviourNotificationString(eBhvr, eType); - if (!strMsg.empty()) - { - LLSD argsNotify; - argsNotify["MESSAGE"] = strMsg; - LLNotificationsUtil::add("SystemMessageTip", argsNotify); - } -}*/ -#endif // RLV_EXTENSION_NOTIFY_BEHAVIOUR - -// Checked: 2009-11-11 (RLVa-1.1.0a) | Added: RLVa-1.1.0a/ -/*void RlvNotifications::notifyBlockedViewXXX(const char* pstrAssetType) -{ - LLStringUtil::format_map_t argsMsg; std::string strMsg = RlvStrings::getString(RLV_STRING_BLOCKED_VIEWXXX); - argsMsg["[TYPE]"] = pstrAssetType; - LLStringUtil::format(strMsg, argsMsg); - - LLSD argsNotify; - argsNotify["MESSAGE"] = strMsg; - LLNotificationsUtil::add("SystemMessageTip", argsNotify); -} -*/ // Checked: 2009-11-13 (RLVa-1.1.0b) | Modified: RLVa-1.1.0b /* void RlvNotifications::warnGiveToRLV() { if ( (gSavedSettings.getWarning(RLV_SETTING_FIRSTUSE_GIVETORLV)) && (RlvSettings::getForbidGiveToRLV()) ) - LLNotifications::instance().add(RLV_SETTING_FIRSTUSE_GIVETORLV, LLSD(), LLSD(), &RlvUtil::onGiveToRLVConfirmation); + LLNotifications::instance().add(RLV_SETTING_FIRSTUSE_GIVETORLV, LLSD(), LLSD(), &RlvNotifications::onGiveToRLVConfirmation); } */ @@ -131,9 +104,6 @@ void RlvSettings::initClass() gSavedPerAccountSettings.getControl(RLV_SETTING_LOGINLASTLOCATION)->setHiddenFromSettingsEditor(true); #endif // RLV_EXTENSION_STARTLOCATION - if (gSavedSettings.controlExists(RLV_SETTING_AVATAROFFSET_Z)) - gSavedSettings.getControl(RLV_SETTING_AVATAROFFSET_Z)->getSignal()->connect(boost::bind(&onChangedAvatarOffset, _2)); - if (gSavedSettings.controlExists(RLV_SETTING_TOPLEVELMENU)) gSavedSettings.getControl(RLV_SETTING_TOPLEVELMENU)->getSignal()->connect(boost::bind(&onChangedMenuLevel)); @@ -147,7 +117,7 @@ void RlvSettings::initClass() { if ( (!LLApp::isQuitting()) && (gSavedPerAccountSettings.controlExists(RLV_SETTING_LOGINLASTLOCATION)) ) { - BOOL fValue = (gRlvHandler.hasBehaviour(RLV_BHVR_TPLOC)) || (!gRlvHandler.canStand()); + BOOL fValue = (gRlvHandler.hasBehaviour(RLV_BHVR_TPLOC)) || (!RlvActions::canStand()); if (gSavedPerAccountSettings.getBOOL(RLV_SETTING_LOGINLASTLOCATION) != fValue) { gSavedPerAccountSettings.setBOOL(RLV_SETTING_LOGINLASTLOCATION, fValue); @@ -187,75 +157,102 @@ bool RlvSettings::onChangedSettingBOOL(const LLSD& sdValue, bool* pfSetting) // std::vector RlvStrings::m_Anonyms; -std::map RlvStrings::m_StringMap; -#ifdef RLV_EXTENSION_NOTIFY_BEHAVIOUR -/*std::map RlvStrings::m_BhvrAddMap; -std::map RlvStrings::m_BhvrRemMap;*/ -#endif // RLV_EXTENSION_NOTIFY_BEHAVIOUR +RlvStrings::string_map_t RlvStrings::m_StringMap; +std::string RlvStrings::m_StringMapPath; -// Checked: 2010-03-09 (RLVa-1.2.0a) | Added: RLVa-1.1.0h +// Checked: 2011-11-08 (RLVa-1.5.0) void RlvStrings::initClass() { static bool fInitialized = false; if (!fInitialized) { - LLXMLNodePtr xmlRoot; - if ( (!LLUICtrlFactory::getLayeredXMLNode("rlva_strings.xml", xmlRoot)) || (xmlRoot.isNull()) || (!xmlRoot->hasName("rlva_strings")) ) + // Load the default string values + /* Singu TODO: findSkinnedFilenames/LLDir update + std::vector files = gDirUtilp->findSkinnedFilenames(LLDir::XUI, RLV_STRINGS_FILE, LLDir::ALL_SKINS); + m_StringMapPath = (!files.empty()) ? files.front() : LLStringUtil::null; + for (auto itFile = files.cbegin(); itFile != files.cend(); ++itFile) + */ + std::string itFile = gDirUtilp->findSkinnedFilename(LLUICtrlFactory::getXUIPaths().front(), RLV_STRINGS_FILE); + if (!itFile.empty()) + { + loadFromFile(itFile, false); + } + m_StringMapPath = itFile; // Singu TODO: Remove this when updating to the above LLDir impl. + + // Load the custom string overrides + loadFromFile(gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, RLV_STRINGS_FILE), true); + + // Sanity check + if ( (m_StringMap.empty()) || (m_Anonyms.empty()) ) { - RLV_ERRS << "Problem reading RLVa string XML file" << RLV_ENDL; + RLV_ERRS << "Problem parsing RLVa string XML file" << RLV_ENDL; return; } - for (LLXMLNode* pNode = xmlRoot->getFirstChild(); pNode != NULL; pNode = pNode->getNextSibling()) + fInitialized = true; + } +} + +// Checked: 2011-11-08 (RLVa-1.5.0) +void RlvStrings::loadFromFile(const std::string& strFilePath, bool fUserOverride) +{ + llifstream fileStream(strFilePath, std::ios::binary); LLSD sdFileData; + if ( (!fileStream.is_open()) || (!LLSDSerialize::fromXMLDocument(sdFileData, fileStream)) ) + return; + fileStream.close(); + + if (sdFileData.has("strings")) + { + const LLSD& sdStrings = sdFileData["strings"]; + for (LLSD::map_const_iterator itString = sdStrings.beginMap(); itString != sdStrings.endMap(); ++itString) { - if (pNode->hasName("strings")) + if ( (!itString->second.has("value")) || ((fUserOverride) && (!hasString(itString->first))) ) + continue; + + std::list& listValues = m_StringMap[itString->first]; + if (!fUserOverride) { - std::string strName; - for (LLXMLNode* pStringNode = pNode->getFirstChild(); pStringNode != NULL; pStringNode = pStringNode->getNextSibling()) - { - if ( (!pStringNode->hasName("string")) || (!pStringNode->getAttributeString("name", strName)) ) - continue; - m_StringMap[strName] = pStringNode->getTextContents(); - } + if (listValues.size() > 0) + listValues.pop_front(); + listValues.push_front(itString->second["value"].asString()); } - else if (pNode->hasName("anonyms")) + else { - for (LLXMLNode* pAnonymNode = pNode->getFirstChild(); pAnonymNode != NULL; pAnonymNode = pAnonymNode->getNextSibling()) - { - if (!pAnonymNode->hasName("anonym")) - continue; - m_Anonyms.push_back(pAnonymNode->getTextContents()); - } + while (listValues.size() > 1) + listValues.pop_back(); + listValues.push_back(itString->second["value"].asString()); } - #ifdef RLV_EXTENSION_NOTIFY_BEHAVIOUR - /*else if (pNode->hasName("behaviour-notifications")) - { - std::string strBhvr, strType; ERlvBehaviour eBhvr; - for (LLXMLNode* pNotifyNode = pNode->getFirstChild(); pNotifyNode != NULL; pNotifyNode = pNotifyNode->getNextSibling()) - { - if ( (!pNotifyNode->hasName("notification")) || (!pNotifyNode->getAttributeString("type", strType)) || - (!pNotifyNode->getAttributeString("behaviour", strBhvr)) || - ((eBhvr = RlvCommand::getBehaviourFromString(strBhvr)) == RLV_BHVR_UNKNOWN) ) - { - continue; - } - if ("add" == strType) - m_BhvrAddMap.insert(std::pair(eBhvr, pNotifyNode->getTextContents())); - else if ("rem" == strType) - m_BhvrRemMap.insert(std::pair(eBhvr, pNotifyNode->getTextContents())); - } - }*/ - #endif // RLV_EXTENSION_NOTIFY_BEHAVIOUR } - - if ( (m_StringMap.empty()) || (m_Anonyms.empty()) ) + } + if (sdFileData.has("anonyms")) + { + const LLSD& sdAnonyms = sdFileData["anonyms"]; + for (LLSD::array_const_iterator itAnonym = sdAnonyms.beginArray(); itAnonym != sdAnonyms.endArray(); ++itAnonym) { - RLV_ERRS << "Problem parsing RLVa string XML file" << RLV_ENDL; - return; + m_Anonyms.push_back((*itAnonym).asString()); } + } +} - fInitialized = true; +// Checked: 2011-11-08 (RLVa-1.5.0) +void RlvStrings::saveToFile(const std::string& strFilePath) +{ + LLSD sdFileData; + + LLSD& sdStrings = sdFileData["strings"]; + for (string_map_t::const_iterator itString = m_StringMap.begin(); itString != m_StringMap.end(); ++itString) + { + const std::list& listValues = itString->second; + if (listValues.size() > 1) + sdStrings[itString->first]["value"] = listValues.back(); } + + llofstream fileStream(strFilePath); + if (!fileStream.good()) + return; + + LLSDSerialize::toPrettyXML(sdFileData, fileStream); + fileStream.close(); } // Checked: 2009-11-11 (RLVa-1.1.0a) | Modified: RLVa-1.1.0a @@ -270,30 +267,12 @@ const std::string& RlvStrings::getAnonym(const std::string& strName) return m_Anonyms[nHash % m_Anonyms.size()]; } -#ifdef RLV_EXTENSION_NOTIFY_BEHAVIOUR -// Checked: 2009-12-05 (RLVa-1.1.0h) | Added: RLVa-1.1.0h -/*const std::string& RlvStrings::getBehaviourNotificationString(ERlvBehaviour eBhvr, ERlvParamType eType) -{ - if (RLV_TYPE_ADD == eType) - { - std::map::const_iterator itString = m_BhvrAddMap.find(eBhvr); - return (itString != m_BhvrAddMap.end()) ? itString->second : LLStringUtil::null; - } - else if (RLV_TYPE_REMOVE == eType) - { - std::map::const_iterator itString = m_BhvrRemMap.find(eBhvr); - return (itString != m_BhvrRemMap.end()) ? itString->second : LLStringUtil::null; - } - return LLStringUtil::null; -}*/ -#endif // RLV_EXTENSION_NOTIFY_BEHAVIOUR - -// Checked: 2009-11-11 (RLVa-1.1.0a) | Added: RLVa-1.1.0a +// Checked: 2011-11-08 (RLVa-1.5.0) const std::string& RlvStrings::getString(const std::string& strStringName) { static const std::string strMissing = "(Missing RLVa string)"; string_map_t::const_iterator itString = m_StringMap.find(strStringName); - return (itString != m_StringMap.end()) ? itString->second : strMissing; + return (itString != m_StringMap.end()) ? itString->second.back() : strMissing; } // Checked: 2009-11-25 (RLVa-1.1.0f) | Added: RLVa-1.1.0f @@ -322,6 +301,8 @@ const char* RlvStrings::getStringFromReturnCode(ERlvCmdRet eRet) return "unknown command"; case RLV_RET_FAILED_NOSHAREDROOT: return "missing #RLV"; + case RLV_RET_DEPRECATED: + return "deprecated"; // The following are identified by the chat verb case RLV_RET_RETAINED: case RLV_RET_SUCCESS: @@ -354,15 +335,29 @@ std::string RlvStrings::getVersionAbout() } // Checked: 2010-03-27 (RLVa-1.4.0a) | Modified: RLVa-1.1.0a -std::string RlvStrings::getVersionNum() +std::string RlvStrings::getVersionNum() { return llformat("%d%02d%02d%02d", RLV_VERSION_MAJOR, RLV_VERSION_MINOR, RLV_VERSION_PATCH, RLV_VERSION_BUILD); } -// Checked: 2010-05-26 (RLVa-1.2.0h) | Added: RLVa-1.2.0g -bool RlvStrings::hasString(const std::string& strStringName) +// Checked: 2011-11-08 (RLVa-1.5.0) +bool RlvStrings::hasString(const std::string& strStringName, bool fCheckCustom) { - return m_StringMap.find(strStringName) != m_StringMap.end(); + string_map_t::const_iterator itString = m_StringMap.find(strStringName); + return (itString != m_StringMap.end()) && ((!fCheckCustom) || (itString->second.size() > 0)); +} + +// Checked: 2011-11-08 (RLVa-1.5.0) +void RlvStrings::setCustomString(const std::string& strStringName, const std::string& strStringValue) +{ + if (!hasString(strStringName)) + return; + + std::list& listValues = m_StringMap[strStringName]; + while (listValues.size() > 1) + listValues.pop_back(); + if (!strStringValue.empty()) + listValues.push_back(strStringValue); } // ============================================================================ @@ -371,6 +366,12 @@ bool RlvStrings::hasString(const std::string& strStringName) bool RlvUtil::m_fForceTp = false; +std::string escape_for_regex(const std::string& str) +{ + using namespace boost; + return regex_replace(str, regex("[.^$|()\\[\\]{}*+?\\\\]"), "\\\\&", match_default|format_sed); +} + // Checked: 2009-07-04 (RLVa-1.0.0a) | Modified: RLVa-1.0.0a void RlvUtil::filterLocation(std::string& strUTF8Text) { @@ -378,12 +379,12 @@ void RlvUtil::filterLocation(std::string& strUTF8Text) LLWorld::region_list_t regions = LLWorld::getInstance()->getRegionList(); const std::string& strHiddenRegion = RlvStrings::getString(RLV_STRING_HIDDEN_REGION); for (LLWorld::region_list_t::const_iterator itRegion = regions.begin(); itRegion != regions.end(); ++itRegion) - boost::ireplace_all(strUTF8Text, (*itRegion)->getName(), strHiddenRegion); + boost::replace_all_regex(strUTF8Text, boost::regex("\\b" + escape_for_regex((*itRegion)->getName()) + "\\b", boost::regex::icase), strHiddenRegion); // Filter any mention of the parcel name LLViewerParcelMgr* pParcelMgr = LLViewerParcelMgr::getInstance(); if (pParcelMgr) - boost::ireplace_all(strUTF8Text, pParcelMgr->getAgentParcelName(), RlvStrings::getString(RLV_STRING_HIDDEN_PARCEL)); + boost::replace_all_regex(strUTF8Text, boost::regex("\\b" + escape_for_regex(pParcelMgr->getAgentParcelName()) + "\\b", boost::regex::icase), RlvStrings::getString(RLV_STRING_HIDDEN_PARCEL)); } // Checked: 2010-12-08 (RLVa-1.2.2c) | Modified: RLVa-1.2.2c @@ -396,28 +397,26 @@ void RlvUtil::filterNames(std::string& strUTF8Text, bool fFilterLegacy) LLAvatarName avName; if (LLAvatarNameCache::get(idAgents[idxAgent], &avName)) { - const std::string& strAnonym = RlvStrings::getAnonym(avName.mDisplayName); - - // NOTE: if the legacy first and last name are empty we get a legacy name of " " which would replace all spaces in the string - std::string strLegacyName; - if ( (fFilterLegacy) && (!avName.mLegacyFirstName.empty()) && - ((!avName.mIsDisplayNameDefault) || (LLCacheName::getDefaultLastName() == avName.mLegacyLastName)) ) - { - strLegacyName = avName.getLegacyName(); - } + const std::string& strDisplayName = escape_for_regex(avName.getDisplayName()); + bool fFilterDisplay = (strDisplayName.length() > 2); + const std::string& strLegacyName = avName.getLegacyName(); + fFilterLegacy &= (strLegacyName.length() > 2); + const std::string& strAnonym = RlvStrings::getAnonym(avName); // If the display name is a subset of the legacy name we need to filter that first, otherwise it's the other way around - if (boost::icontains(strLegacyName, avName.mDisplayName)) + if (boost::icontains(strLegacyName, strDisplayName)) { - if (!strLegacyName.empty()) - boost::ireplace_all(strUTF8Text, strLegacyName, strAnonym); - boost::ireplace_all(strUTF8Text, avName.mDisplayName, strAnonym); + if (fFilterLegacy) + boost::replace_all_regex(strUTF8Text, boost::regex("\\b" + strLegacyName + "\\b", boost::regex::icase), strAnonym); + if (fFilterDisplay) + boost::replace_all_regex(strUTF8Text, boost::regex("\\b" + strDisplayName + "\\b", boost::regex::icase), strAnonym); } else { - boost::ireplace_all(strUTF8Text, avName.mDisplayName, strAnonym); - if (!strLegacyName.empty()) - boost::ireplace_all(strUTF8Text, strLegacyName, strAnonym); + if (fFilterDisplay) + boost::replace_all_regex(strUTF8Text, boost::regex("\\b" + strDisplayName + "\\b", boost::regex::icase), strAnonym); + if (fFilterLegacy) + boost::replace_all_regex(strUTF8Text, boost::regex("\\b" + strLegacyName + "\\b", boost::regex::icase), strAnonym); } } } @@ -460,11 +459,11 @@ bool RlvUtil::isNearbyAgent(const LLUUID& idAgent) RLV_ASSERT(idAgent.notNull()); if ( (idAgent.notNull()) && (gAgent.getID() != idAgent) ) { - std::vector idAgents; + uuid_vec_t idAgents; LLWorld::getInstance()->getAvatars(&idAgents, NULL); - for (int idxAgent = 0, cntAgent = idAgents.size(); idxAgent < cntAgent; idxAgent++) - if (idAgents[idxAgent] == idAgent) + for (const auto& id : idAgents) + if (id == idAgent) return true; } return false; @@ -692,10 +691,30 @@ bool rlvPredCanNotWearItem(const LLViewerInventoryItem* pItem, ERlvWearMask eWea return !rlvPredCanWearItem(pItem, eWearMask); } -// Checked: 2010-03-22 (RLVa-1.2.0c) | Added: RLVa-1.2.0a -bool rlvPredCanRemoveItem(const LLInventoryItem* pItem) +// Checked: 2014-11-02 (RLVa-1.4.11) +bool rlvPredCanRemoveItem(const LLUUID& idItem) { - if ( (pItem) && (RlvForceWear::isWearableItem(pItem)) ) + // Check the inventory item if it's available + const LLViewerInventoryItem* pItem = gInventory.getItem(idItem); + if (pItem) + { + return rlvPredCanRemoveItem(pItem); + } + + // Temporary attachments don't have inventory items associated with them so check the attachment itself + if (isAgentAvatarValid()) + { + const LLViewerObject* pAttachObj = gAgentAvatarp->getWornAttachment(idItem); + return (pAttachObj) && (!gRlvAttachmentLocks.isLockedAttachment(pAttachObj)); + } + + return false; +} + +// Checked: 2010-03-22 (RLVa-1.2.0) +bool rlvPredCanRemoveItem(const LLViewerInventoryItem* pItem) +{ + if (pItem) { switch (pItem->getType()) { @@ -707,16 +726,14 @@ bool rlvPredCanRemoveItem(const LLInventoryItem* pItem) case LLAssetType::AT_GESTURE: return true; default: - RLV_ASSERT(false); + RLV_ASSERT(!RlvForceWear::isWearableItem(pItem)); } } - // HACK-RLVa: Until LL supports temporary attachment detection assume that no inventory item means a temporary - // attachment which are always removeable - return true; + return false; } // Checked: 2010-03-22 (RLVa-1.2.0c) | Added: RLVa-1.2.0a -bool rlvPredCanNotRemoveItem(const LLInventoryItem* pItem) +bool rlvPredCanNotRemoveItem(const LLViewerInventoryItem* pItem) { return !rlvPredCanRemoveItem(pItem); } diff --git a/indra/newview/rlvcommon.h b/indra/newview/rlvcommon.h index a767ed4459..e3dd65a6e0 100644 --- a/indra/newview/rlvcommon.h +++ b/indra/newview/rlvcommon.h @@ -46,6 +46,7 @@ class LLInventoryItem; class LLViewerInventoryCategory; class LLViewerInventoryItem; class LLViewerJointAttachment; +class LLViewerWearable; class LLWearable; // @@ -56,7 +57,7 @@ typedef std::list rlv_command_list_t; class RlvObject; struct RlvException; -typedef boost::variant RlvExceptionOption; +typedef boost::variant RlvExceptionOption; class RlvGCTimer; @@ -79,7 +80,6 @@ template inline T rlvGetPerUserSetting(const std::string& strSetting class RlvSettings { public: - static F32 getAvatarOffsetZ() { return rlvGetSetting(RLV_SETTING_AVATAROFFSET_Z, 0.0); } static bool getDebug() { return rlvGetSetting(RLV_SETTING_DEBUG, false); } static bool getCanOOC() { return fCanOOC; } static bool getForbidGiveToRLV() { return rlvGetSetting(RLV_SETTING_FORBIDGIVETORLV, true); } @@ -128,21 +128,25 @@ class RlvStrings { public: static void initClass(); + static void loadFromFile(const std::string& strFilePath, bool fDefault); + static void saveToFile(const std::string& strFilePath); static const std::string& getAnonym(const LLAvatarName& avName); // @shownames static const std::string& getAnonym(const std::string& strName); // @shownames - static const std::string& getBehaviourNotificationString(ERlvBehaviour eBhvr, ERlvParamType eType); static const std::string& getString(const std::string& strStringName); static const char* getStringFromReturnCode(ERlvCmdRet eRet); + static const std::string& getStringMapPath() { return m_StringMapPath; } static std::string getVersion(bool fLegacy = false); // @version static std::string getVersionAbout(); // Shown in Help / About static std::string getVersionNum(); // @versionnum - static bool hasString(const std::string& strStringName); + static bool hasString(const std::string& strStringName, bool fCheckCustom = false); + static void setCustomString(const std::string& strStringName, const std::string& strStringValue); protected: static std::vector m_Anonyms; - typedef std::map string_map_t; + typedef std::map > string_map_t; static string_map_t m_StringMap; + static std::string m_StringMapPath; }; // ============================================================================ @@ -239,8 +243,10 @@ struct RlvSelectIsSittingOn : public LLSelectedNodeFunctor bool rlvPredCanWearItem(const LLViewerInventoryItem* pItem, ERlvWearMask eWearMask); bool rlvPredCanNotWearItem(const LLViewerInventoryItem* pItem, ERlvWearMask eWearMask); -bool rlvPredCanRemoveItem(const LLInventoryItem* pItem); -bool rlvPredCanNotRemoveItem(const LLInventoryItem* pItem); +bool rlvPredCanRemoveItem(const LLUUID& idItem); +bool rlvPredCanRemoveItem(const LLViewerInventoryItem* pItem); +bool rlvPredCanNotRemoveItem(const LLUUID& idItem); +bool rlvPredCanNotRemoveItem(const LLViewerInventoryItem* pItem); struct RlvPredCanWearItem { @@ -258,6 +264,18 @@ struct RlvPredCanNotWearItem ERlvWearMask m_eWearMask; }; +struct RlvPredCanRemoveItem +{ + RlvPredCanRemoveItem() {} + bool operator()(const LLViewerInventoryItem* pItem) { return rlvPredCanRemoveItem(pItem); } +}; + +struct RlvPredCanNotRemoveItem +{ + RlvPredCanNotRemoveItem() {} + bool operator()(const LLViewerInventoryItem* pItem) { return rlvPredCanNotRemoveItem(pItem); } +}; + struct RlvPredIsEqualOrLinkedItem { RlvPredIsEqualOrLinkedItem(const LLViewerInventoryItem* pItem) : m_pItem(pItem) {} @@ -280,7 +298,7 @@ template struct RlvPredValuesEqual // Checked: 2010-10-31 (RLVa-1.2.2a) | Added: RLVa-1.2.2a inline const std::string& RlvStrings::getAnonym(const LLAvatarName& avName) { - return getAnonym(avName.mDisplayName); + return getAnonym(avName.getDisplayName()); } // Checked: 2010-03-26 (RLVa-1.2.0b) | Modified: RLVa-1.0.2a diff --git a/indra/newview/rlvdefines.h b/indra/newview/rlvdefines.h index 9e000ddbd8..0127fc0758 100644 --- a/indra/newview/rlvdefines.h +++ b/indra/newview/rlvdefines.h @@ -3,10 +3,10 @@ * Copyright (c) 2009-2011, Kitty Barnett * * The source code in this file is provided to you under the terms of the - * GNU General Public License, version 2.0, but WITHOUT ANY WARRANTY; + * GNU Lesser General Public License, version 2.1, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A - * PARTICULAR PURPOSE. Terms of the GPL can be found in doc/GPL-license.txt - * in this distribution, or online at http://www.gnu.org/licenses/gpl-2.0.txt + * PARTICULAR PURPOSE. Terms of the LGPL can be found in doc/LGPL-licence.txt + * in this distribution, or online at http://www.gnu.org/licenses/lgpl-2.1.txt * * By copying, modifying or distributing this software, you acknowledge that * you have read and understood your obligations described above, and agree to @@ -21,20 +21,10 @@ // Extensions // -// Comment out if you don't want the Advanced / RLVa menu (may prevent enabling some extensions or experimental features - see below) -#define RLV_ADVANCED_MENU -// Comment out if you provide your own way to enable/disable RLVa -#define RLV_ADVANCED_TOGGLE_RLVA - -// Provides access to "advanced" features through the RLVa debug menu -#define RLV_EXTENSION_FLOATER_RESTRICTIONS // Enables the Advanced / RLVa / Restrictions... floater -#define RLV_EXTENSION_HIDELOCKED // "Hide locked layers", "Hide locked attachments" and "Hide locked inventory" - // Extensions #define RLV_EXTENSION_CMD_GETSETDEBUG_EX // Extends the debug variables accessible through @getdebug_xxx/@setdebug_xxx #define RLV_EXTENSION_CMD_FINDFOLDERS // @findfolders: diff --git a/indra/newview/skins/apollo/colors.xml b/indra/newview/skins/apollo/colors.xml index 155efaceea..970076ed34 100644 --- a/indra/newview/skins/apollo/colors.xml +++ b/indra/newview/skins/apollo/colors.xml @@ -103,6 +103,7 @@ + @@ -185,7 +186,6 @@ - diff --git a/indra/newview/skins/apollo/keywords.ini b/indra/newview/skins/apollo/keywords.ini index cecc8631a8..33130fc758 100644 --- a/indra/newview/skins/apollo/keywords.ini +++ b/indra/newview/skins/apollo/keywords.ini @@ -2,128 +2,148 @@ llkeywords version 2 # sections [word .648, .882, .179] -default Name of default state that all scripts must have -state Keyword to indicate state block or state transition +default Name of default state that all scripts must have +state Keyword to indicate state block or state transition # data types [word .398, .847, .933] -integer Integer type -float Floating-point type -string String type -key Key type. Use NULL_KEY to test for empty keys -vector Vector type of 3 floats. Used to represent 3D motion, Euler angles, and color.:Access components by .x, .y. or .z -rotation Rotation type of 4 floats. Used to represent rotation.:Access components by .x, .y., .z, or .w -list List of various data types -quaternion Rotation type of 4 floats. Used to represent rotation.:Access components by .x, .y, .z, or .w +integer Integer type +float Floating-point type +string String type +key Key type. Use NULL_KEY to test for empty keys +vector Vector type of 3 floats. Used to represent 3D motion, Euler angles, and color.:Access components by .x, .y. or .z +rotation Rotation type of 4 floats. Used to represent rotation.:Access components by .x, .y., .z, or .w +list List of various data types +quaternion Rotation type of 4 floats. Used to represent rotation.:Access components by .x, .y, .z, or .w # events [word .398, .847, .933] -state_entry state_entry():Triggered on any state transition and startup -state_exit state_exit():Triggered on any state transition -touch_start touch_start(integer num_detected):Triggered by the start of agent clicking on task -touch touch(integer num_detected):Triggered while agent is clicking on task -touch_end touch_end(integer num_detected):Triggered when agent stops clicking on task -collision_start collision_start(integer num_detected):Triggered when task starts colliding with another task -collision collision(integer num_detected):Triggered while task is colliding with another task -collision_end collision_end(integer num_detected):Triggered when task stops colliding with another task -land_collision_start land_collision_start(vector pos):Triggered when task starts colliding with land -land_collision land_collision(vector pos):Triggered when task is colliding with land -land_collision_end land_collision_end(vector pos):Triggered when task stops colliding with land -timer timer():Result of the llSetTimerEvent library function call -listen listen(integer channel, string name, key id, string message):Result of the llListen library function call -sensor sensor(integer num_detected):Result of the llSensor library function call -no_sensor no_sensor():Result of the llSensor library function call -control control(key id, integer level, integer edge):Result of llTakeControls library function call -at_target at_target(integer tnum, vector targetpos, vector ourpos):Result of llTarget library function call -not_at_target not_at_target():Result of llTarget library function call -at_rot_target at_rot_target(integer tnum, rotation targetrot, rotation ourrot):Result of LLRotTarget library function call -not_at_rot_target not_at_rot_target():Result of LLRotTarget library function call -money money(key id, integer amount):Triggered when L$ is given to task -email email(string time, string address, string subj, string message, integer num_left):Triggered when task receives email -run_time_permissions run_time_permissions(integer perm):Triggered when an agent grants run time permissions to task -attach attach(key id):Triggered when task attaches or detaches from agent -dataserver dataserver(key queryid, string data):Triggered when task receives asynchronous data -moving_start moving_start():Triggered when task begins moving -moving_end moving_end():Triggered when task stops moving -on_rez on_rez(integer start_param):Triggered when task is rezzed in from inventory or another task -object_rez object_rez(key id):Triggered when task rezzes in another task -link_message link_message(integer sender_num, integer num, string str, key id):Triggered when task receives a link message via LLMessageLinked library function call -changed changed( integer change ):Triggered various event change the task:(test change with CHANGED_INVENTORY, CHANGED_COLOR, CHANGED_SHAPE, CHANGED_SCALE, CHANGED_TEXTURE, CHANGED_LINK, CHANGED_ALLOWED_DROP, CHANGED_OWNER, CHANGED_REGION, CHANGED_TELEPORT, CHANGED_REGION_START, CHANGED_MEDIA) -remote_data remote_data(integer event_type, key channel, key message_id, string sender,integer idata, string sdata):Triggered by various XML-RPC calls (event_type will be one of REMOTE_DATA_CHANNEL, REMOTE_DATA_REQUEST, REMOTE_DATA_REPLY) -http_response http_response(key request_id, integer status, list metadata, string body):Triggered when task receives a response to one of its llHTTPRequests -http_request http_request(key id, string method, string body):Triggered when task receives an http request against a public URL -transaction_result transaction_result(key id, integer success, string data): Triggered when currency is given to task -path_update path_update(integer type, list reserved):Triggered when the state of a pathfinder character changes. Note; "list reserved" is not currently used +state_entry state_entry():Triggered on any state transition and startup +state_exit state_exit():Triggered on any state transition +touch_start touch_start(integer num_detected):Triggered by the start of agent clicking on task +touch touch(integer num_detected):Triggered while agent is clicking on task +touch_end touch_end(integer num_detected):Triggered when agent stops clicking on task +collision_start collision_start(integer num_detected):Triggered when task starts colliding with another task +collision collision(integer num_detected):Triggered while task is colliding with another task +collision_end collision_end(integer num_detected):Triggered when task stops colliding with another task +land_collision_start land_collision_start(vector pos):Triggered when task starts colliding with land +land_collision land_collision(vector pos):Triggered when task is colliding with land +land_collision_end land_collision_end(vector pos):Triggered when task stops colliding with land +timer timer():Result of the llSetTimerEvent library function call +listen listen(integer channel, string name, key id, string message):Result of the llListen library function call +sensor sensor(integer num_detected):Result of the llSensor library function call +no_sensor no_sensor():Result of the llSensor library function call +control control(key id, integer level, integer edge):Result of llTakeControls library function call +at_target at_target(integer tnum, vector targetpos, vector ourpos):Result of llTarget library function call +not_at_target not_at_target():Result of llTarget library function call +at_rot_target at_rot_target(integer tnum, rotation targetrot, rotation ourrot):Result of LLRotTarget library function call +not_at_rot_target not_at_rot_target():Result of LLRotTarget library function call +money money(key id, integer amount):Triggered when L$ is given to task +email email(string time, string address, string subj, string message, integer num_left):Triggered when task receives email +run_time_permissions run_time_permissions(integer perm):Triggered when an agent grants run time permissions to task +attach attach(key id):Triggered when task attaches or detaches from agent +dataserver dataserver(key queryid, string data):Triggered when task receives asynchronous data +moving_start moving_start():Triggered when task begins moving +moving_end moving_end():Triggered when task stops moving +on_rez on_rez(integer start_param):Triggered when task is rezzed in from inventory or another task +object_rez object_rez(key id):Triggered when task rezzes in another task +link_message link_message(integer sender_num, integer num, string str, key id):Triggered when task receives a link message via LLMessageLinked library function call +changed changed( integer change ):Triggered various event change the task:(test change with CHANGED_INVENTORY, CHANGED_COLOR, CHANGED_SHAPE, CHANGED_SCALE, CHANGED_TEXTURE, CHANGED_LINK, CHANGED_ALLOWED_DROP, CHANGED_OWNER, CHANGED_REGION, CHANGED_TELEPORT, CHANGED_REGION_START, CHANGED_MEDIA) +remote_data remote_data(integer event_type, key channel, key message_id, string sender,integer idata, string sdata):Triggered by various XML-RPC calls (event_type will be one of REMOTE_DATA_CHANNEL, REMOTE_DATA_REQUEST, REMOTE_DATA_REPLY) +http_response http_response(key request_id, integer status, list metadata, string body):Triggered when task receives a response to one of its llHTTPRequests +http_request http_request(key id, string method, string body):Triggered when task receives an http request against a public URL +transaction_result transaction_result(key id, integer success, string data): Triggered when currency is given to task +path_update path_update(integer type, list reserved):Triggered when the state of a pathfinder character changes. Note; "list reserved" is not currently used +experience_permissions experience_permissions(key agent): Triggered when agent has approved an experience permissions request. This may be through interaction with the experience permission dialog or the experience profile, or automatically if the agent has previously approved the experience. +experience_permissions_denied experience_permissions_denied(key agent, integer reason): Triggered when agent has denied experience permission. reason is the reason for denial; one of the Experience Tools XP_ERROR_* errors flags. + # integer constants [word .679, .503, .996] -TRUE Integer constant for Boolean operations -FALSE Integer constant for Boolean operations -STATUS_PHYSICS Passed in the llSetStatus library function. If TRUE, object moves physically -STATUS_PHANTOM Passed in the llSetStatus library function. If TRUE, object doesn't collide with other objects -STATUS_ROTATE_X Passed in the llSetStatus library function. If FALSE, object doesn't rotate around local X axis -STATUS_ROTATE_Y Passed in the llSetStatus library function. If FALSE, object doesn't rotate around local Y axis -STATUS_ROTATE_Z Passed in the llSetStatus library function. If FALSE, object doesn't rotate around local Z axis -STATUS_SANDBOX Passed in the llSetStatus library function. If TRUE, object can't cross region boundaries or move more than 10 meters from its start location -STATUS_BLOCK_GRAB Passed in the llSetStatus library function. If TRUE, object can't be grabbed and physically dragged +TRUE Integer constant for Boolean operations +FALSE Integer constant for Boolean operations +STATUS_PHYSICS Passed in the llSetStatus library function. If TRUE, object moves physically +STATUS_PHANTOM Passed in the llSetStatus library function. If TRUE, object doesn't collide with other objects +STATUS_ROTATE_X Passed in the llSetStatus library function. If FALSE, object doesn't rotate around local X axis +STATUS_ROTATE_Y Passed in the llSetStatus library function. If FALSE, object doesn't rotate around local Y axis +STATUS_ROTATE_Z Passed in the llSetStatus library function. If FALSE, object doesn't rotate around local Z axis +STATUS_SANDBOX Passed in the llSetStatus library function. If TRUE, object can't cross region boundaries or move more than 10 meters from its start location +STATUS_BLOCK_GRAB Passed in the llSetStatus library function. If TRUE, object can't be grabbed and physically dragged STATUS_BLOCK_GRAB_OBJECT This status flag keeps the object from being moved by grabs. This flag applies to the entire linkset -STATUS_DIE_AT_EDGE Passed in the llSetStatus library function. If TRUE, objects that reach the edge of the world just die:rather than teleporting back to the owner -STATUS_RETURN_AT_EDGE Passed in the llSetStatus library function. If TRUE, script rezzed objects that reach the edge of the world:are returned rather than killed:STATUS_RETURN_AT_EDGE trumps STATUS_DIE_AT_EDGE if both are set -STATUS_CAST_SHADOWS Passed in the llSetStatus library function. If TRUE, object casts shadows on other objects - -AGENT Passed in llSensor library function to look for other Agents; DEPRECATED: Use AGENT_BY_LEGACY_NAME -AGENT_BY_LEGACY_NAME Passed in llSensor library function to look for other Agents by legacy name -AGENT_BY_USERNAME Passed in llSensor library function to look for other Agents by username -ACTIVE Passed in llSensor library function to look for moving objects -PASSIVE Passed in llSensor library function to look for objects that aren't moving -SCRIPTED Passed in llSensor library function to look for scripted objects -CONTROL_FWD Passed to llTakeControls library function and used control event handler to test for agent forward control -CONTROL_BACK Passed to llTakeControls library function and used control event handler to test for agent back control -CONTROL_LEFT Passed to llTakeControls library function and used control event handler to test for agent left control -CONTROL_RIGHT Passed to llTakeControls library function and used control event handler to test for agent right control -CONTROL_ROT_LEFT Passed to llTakeControls library function and used control event handler to test for agent rotate left control -CONTROL_ROT_RIGHT Passed to llTakeControls library function and used control event handler to test for agent rotate right control -CONTROL_UP Passed to llTakeControls library function and used control event handler to test for agent up control -CONTROL_DOWN Passed to llTakeControls library function and used control event handler to test for agent down control -CONTROL_LBUTTON Passed to llTakeControls library function and used control event handler to test for agent left button control -CONTROL_ML_LBUTTON Passed to llTakeControls library function and used control event handler to test for agent left button control with the agent in mouse look -PERMISSION_DEBIT Passed to llRequestPermissions library function to request permission to take L$ from agent's account -PERMISSION_TAKE_CONTROLS Passed to llRequestPermissions library function to request permission to take agent's controls -# PERMISSION_REMAP_CONTROLS Passed to llRequestPermissions library function to request permission to remap agent's controls (not implemented yet) -PERMISSION_TRIGGER_ANIMATION Passed to llRequestPermissions library function to request permission to trigger animation on agent -PERMISSION_ATTACH Passed to llRequestPermissions library function to request permission to attach/detach from agent -# PERMISSION_RELEASE_OWNERSHIP Passed to llRequestPermissions library function to request permission to release ownership (not implemented) -PERMISSION_CHANGE_LINKS Passed to llRequestPermissions library function to request permission to change links -# PERMISSION_CHANGE_JOINTS Passed to llRequestPermissions library function to request permission to change joints (not implemented) +STATUS_DIE_AT_EDGE Passed in the llSetStatus library function. If TRUE, objects that reach the edge of the world just die:rather than teleporting back to the owner +STATUS_RETURN_AT_EDGE Passed in the llSetStatus library function. If TRUE, script rezzed objects that reach the edge of the world:are returned rather than killed:STATUS_RETURN_AT_EDGE trumps STATUS_DIE_AT_EDGE if both are set +STATUS_CAST_SHADOWS Passed in the llSetStatus library function. If TRUE, object casts shadows on other objects + +AGENT Passed in llSensor library function to look for other Agents; DEPRECATED: Use AGENT_BY_LEGACY_NAME +AGENT_BY_LEGACY_NAME Passed in llSensor library function to look for other Agents by legacy name +AGENT_BY_USERNAME Passed in llSensor library function to look for other Agents by username +ACTIVE Passed in llSensor library function to look for moving objects +PASSIVE Passed in llSensor library function to look for objects that aren't moving +SCRIPTED Passed in llSensor library function to look for scripted objects +CONTROL_FWD Passed to llTakeControls library function and used control event handler to test for agent forward control +CONTROL_BACK Passed to llTakeControls library function and used control event handler to test for agent back control +CONTROL_LEFT Passed to llTakeControls library function and used control event handler to test for agent left control +CONTROL_RIGHT Passed to llTakeControls library function and used control event handler to test for agent right control +CONTROL_ROT_LEFT Passed to llTakeControls library function and used control event handler to test for agent rotate left control +CONTROL_ROT_RIGHT Passed to llTakeControls library function and used control event handler to test for agent rotate right control +CONTROL_UP Passed to llTakeControls library function and used control event handler to test for agent up control +CONTROL_DOWN Passed to llTakeControls library function and used control event handler to test for agent down control +CONTROL_LBUTTON Passed to llTakeControls library function and used control event handler to test for agent left button control +CONTROL_ML_LBUTTON Passed to llTakeControls library function and used control event handler to test for agent left button control with the agent in mouse look +PERMISSION_DEBIT Passed to llRequestPermissions library function to request permission to take L$ from agent's account +PERMISSION_TAKE_CONTROLS Passed to llRequestPermissions library function to request permission to take agent's controls +# PERMISSION_REMAP_CONTROLS Passed to llRequestPermissions library function to request permission to remap agent's controls (not implemented yet) +PERMISSION_TRIGGER_ANIMATION Passed to llRequestPermissions library function to request permission to trigger animation on agent +PERMISSION_ATTACH Passed to llRequestPermissions library function to request permission to attach/detach from agent +# PERMISSION_RELEASE_OWNERSHIP Passed to llRequestPermissions library function to request permission to release ownership (not implemented) +PERMISSION_CHANGE_LINKS Passed to llRequestPermissions library function to request permission to change links +# PERMISSION_CHANGE_JOINTS Passed to llRequestPermissions library function to request permission to change joints (not implemented) # PERMISSION_CHANGE_PERMISSIONS Passed to llRequestPermissions library function to request permission to change permissions -PERMISSION_TRACK_CAMERA Passed to llRequestPermissions library function to request permission to track agent's camera -PERMISSION_CONTROL_CAMERA Passed to llRequestPermissions library function to request permission to change agent's camera -PERMISSION_TELEPORT Passed to llRequestPermissions library function to request permission to teleport agent -SCRIPT_PERMISSION_SILENT_ESTATE_MANAGEMENT Passed to llRequestPermissions library function to request permission to silently modify estate access lists -PERMISSION_OVERRIDE_ANIMATIONS Passed to llRequestPermissions library function to request permission to override animations on agent -PERMISSION_RETURN_OBJECTS Passed to llRequestPermissions library function to request permission to return objects - -DEBUG_CHANNEL Chat channel reserved for debug and error messages from scripts -PUBLIC_CHANNEL Chat channel that broadcasts to all nearby users - -AGENT_FLYING Returned by llGetAgentInfo if the Agent is flying -AGENT_ATTACHMENTS Returned by llGetAgentInfo if the Agent has attachments -AGENT_SCRIPTED Returned by llGetAgentInfo if the Agent has scripted attachments -AGENT_SITTING Returned by llGetAgentInfo if the Agent is sitting -AGENT_ON_OBJECT Returned by llGetAgentInfo if the Agent is sitting on an object -AGENT_MOUSELOOK Returned by llGetAgentInfo if the Agent is in mouselook -AGENT_AWAY Returned by llGetAgentInfo if the Agent is in away mode -AGENT_WALKING Returned by llGetAgentInfo if the Agent is walking -AGENT_IN_AIR Returned by llGetAgentInfo if the Agent is in the air -AGENT_TYPING Returned by llGetAgentInfo if the Agent is typing -AGENT_CROUCHING Returned by llGetAgentInfo if the Agent is crouching -AGENT_BUSY Returned by llGetAgentInfo if the Agent is busy -AGENT_ALWAYS_RUN Returned by llGetAgentInfo if the Agent has 'Always Run' enabled -AGENT_AUTOPILOT Returned by llGetAgentInfo if the Agent is under autopilot control - -AGENT_LIST_PARCEL Passed to llGetAgentList to return only agents on the same parcel where the script is running +PERMISSION_TRACK_CAMERA Passed to llRequestPermissions library function to request permission to track agent's camera +PERMISSION_CONTROL_CAMERA Passed to llRequestPermissions library function to request permission to change agent's camera +PERMISSION_TELEPORT Passed to llRequestPermissions library function to request permission to teleport agent +SCRIPT_PERMISSION_SILENT_ESTATE_MANAGEMENT Passed to llRequestPermissions library function to request permission to silently modify estate access lists +PERMISSION_OVERRIDE_ANIMATIONS Passed to llRequestPermissions library function to request permission to override animations on agent +PERMISSION_RETURN_OBJECTS Passed to llRequestPermissions library function to request permission to return objects +XP_ERROR_NONE No error was detected. +XP_ERROR_THROTTLED The call failed due to too many recent calls. +XP_ERROR_EXPERIENCES_DISABLED The region currently has experiences disabled. +XP_ERROR_INVALID_PARAMETERS One of the string arguments was too big to fit in the key-value store. +XP_ERROR_NOT_PERMITTED This experience is not allowed to run on the current region. +XP_ERROR_NO_EXPERIENCE This script is not associated with an experience. +XP_ERROR_NOT_FOUND The sim was unable to verify the validity of the experience. Retrying after a short wait is advised. +XP_ERROR_INVALID_EXPERIENCE The script is associated with an experience that no longer exists. +XP_ERROR_EXPERIENCE_DISABLED The experience owner has temporarily disabled the experience. +XP_ERROR_EXPERIENCE_SUSPENDED The experience has been suspended by Linden Lab customer support. +XP_ERROR_UNKNOWN_ERROR An unknown error not covered by any of the other predetermined error states. +XP_ERROR_QUOTA_EXCEEDED An attempt to write data to the key-value store failed due to the data quota being met. +XP_ERROR_STORE_DISABLED The key-value store is currently disabled on this region. +XP_ERROR_STORAGE_EXCEPTION Unable to communicate with the key-value store. +XP_ERROR_KEY_NOT_FOUND The requested key does not exist. +XP_ERROR_RETRY_UPDATE A checked update failed due to an out of date request. +XP_ERROR_MATURITY_EXCEEDED The content rating of the experience exceeds that of the region. + +DEBUG_CHANNEL Chat channel reserved for debug and error messages from scripts +PUBLIC_CHANNEL Chat channel that broadcasts to all nearby users + +AGENT_FLYING Returned by llGetAgentInfo if the Agent is flying +AGENT_ATTACHMENTS Returned by llGetAgentInfo if the Agent has attachments +AGENT_SCRIPTED Returned by llGetAgentInfo if the Agent has scripted attachments +AGENT_SITTING Returned by llGetAgentInfo if the Agent is sitting +AGENT_ON_OBJECT Returned by llGetAgentInfo if the Agent is sitting on an object +AGENT_MOUSELOOK Returned by llGetAgentInfo if the Agent is in mouselook +AGENT_AWAY Returned by llGetAgentInfo if the Agent is in away mode +AGENT_WALKING Returned by llGetAgentInfo if the Agent is walking +AGENT_IN_AIR Returned by llGetAgentInfo if the Agent is in the air +AGENT_TYPING Returned by llGetAgentInfo if the Agent is typing +AGENT_CROUCHING Returned by llGetAgentInfo if the Agent is crouching +AGENT_BUSY Returned by llGetAgentInfo if the Agent is busy +AGENT_ALWAYS_RUN Returned by llGetAgentInfo if the Agent has 'Always Run' enabled +AGENT_AUTOPILOT Returned by llGetAgentInfo if the Agent is under autopilot control + +AGENT_LIST_PARCEL Passed to llGetAgentList to return only agents on the same parcel where the script is running AGENT_LIST_PARCEL_OWNER Passed to llGetAgentList to return only agents on any parcel in the region where the parcel owner is the same as the owner of the parcel under the scripted object -AGENT_LIST_REGION Passed to llGetAgentList to return any/all agents in the region +AGENT_LIST_REGION Passed to llGetAgentList to return any/all agents in the region PSYS_PART_FLAGS PSYS_PART_START_COLOR @@ -160,8 +180,8 @@ PSYS_PART_BF_SOURCE_ALPHA PSYS_PART_BF_ONE_MINUS_SOURCE_ALPHA PSYS_SRC_PATTERN -PSYS_SRC_INNERANGLE Deprecated -- Use PSYS_SRC_ANGLE_BEGIN -PSYS_SRC_OUTERANGLE Deprecated -- Use PSYS_SRC_ANGLE_END +PSYS_SRC_INNERANGLE Deprecated -- Use PSYS_SRC_ANGLE_BEGIN +PSYS_SRC_OUTERANGLE Deprecated -- Use PSYS_SRC_ANGLE_END PSYS_SRC_ANGLE_BEGIN PSYS_SRC_ANGLE_END PSYS_SRC_BURST_RATE @@ -181,408 +201,422 @@ PSYS_SRC_PATTERN_ANGLE PSYS_SRC_PATTERN_ANGLE_CONE PSYS_SRC_PATTERN_ANGLE_CONE_EMPTY -OBJECT_UNKNOWN_DETAIL Returned by llGetObjectDetails when passed an invalid object parameter type -OBJECT_NAME Used with llGetObjectDetails to get an object's name -OBJECT_DESC Used with llGetObjectDetails to get an object's description -OBJECT_POS Used with llGetObjectDetails to get an object's position -OBJECT_ROT Used with llGetObjectDetails to get an object's rotation -OBJECT_VELOCITY Used with llGetObjectDetails to get an object's velocity -OBJECT_OWNER Used with llGetObjectDetails to get an object's owner's key. Will be NULL_KEY if group owned -OBJECT_GROUP Used with llGetObjectDetails to get an object's group's key -OBJECT_CREATOR Used with llGetObjectDetails to get an object's creator's key -OBJECT_RUNNING_SCRIPT_COUNT Gets the number of running scripts attached to the object or agent -OBJECT_TOTAL_SCRIPT_COUNT Gets the number of scripts, both running and stopped, attached to the object or agent. -OBJECT_SCRIPT_MEMORY Gets the total amount of script memory allocated to the object or agent, in bytes. -OBJECT_SCRIPT_TIME Gets the total amount of average script CPU time used by the object or agent, in seconds. -OBJECT_PRIM_EQUIVALENCE Gets the prim equivalence of the object. -OBJECT_SERVER_COST Used with llGetObjectDetails to get the server cost. -OBJECT_STREAMING_COST Used with llGetObjectDetails to get the streaming (download) cost. -OBJECT_PHYSICS_COST Used with llGetObjectDetails to get the physics cost. -OBJECT_PATHFINDING_TYPE Used with llGetObjectDetails to get an object's pathfinding settings. -OBJECT_CHARACTER_TIME Used with llGetObjectDetails to get an object's average CPU time (in seconds) used by the object for navigation, if the object is a pathfinding character. Returns 0 for non-characters. -OBJECT_ROOT Used with llGetObjectDetails to get an object's root prim ID. -OBJECT_ATTACHED_POINT Used with llGetObjectDetails to get an object's attachment point. -OBJECT_RETURN_PARCEL Used with llReturnObjectsByOwner to return all objects on the same parcel as the script which are owned by 'owner'. -OBJECT_RETURN_PARCEL_OWNER Used with llReturnObjectsByOwner to return all objects owned by 'owner' which are over parcels owned by the owner of the script. -OBJECT_RETURN_REGION Used with llReturnObjectsByOwner to return all objects in the region owned by 'owner' - only works when the script is owned by the estate owner or an estate manager. - -OPT_UNKNOWN Returned object pathfinding type by llGetObjectDetails for attachments, Linden trees and grass. -OPT_LEGACY_LINKSET Returned object pathfinding type by llGetObjectDetails for movable obstacles, movable phantoms, physical, and volumedetect objects. -OPT_AVATAR Returned object pathfinding type by llGetObjectDetails for avatars. -OPT_PATHFINDING_CHARACTER Returned object pathfinding type by llGetObjectDetails for pathfinding characters. -OPT_WALKABLE Returned object pathfinding type by llGetObjectDetails for walkable objects. -OPT_STATIC_OBSTACLE Returned object pathfinding type by llGetObjectDetails for static obstacles. -OPT_MATERIAL_VOLUME Returned object pathfinding type by llGetObjectDetails for material volumes. -OPT_EXCLUSION_VOLUME Returned object pathfinding type by llGetObjectDetails for exclusion volumes. +OBJECT_UNKNOWN_DETAIL Returned by llGetObjectDetails when passed an invalid object parameter type +OBJECT_HOVER_HEIGHT This is a flag used with llGetObjectDetails to get hover height of the avatar. If no data is available, 0.0 is returned. +OBJECT_LAST_OWNER_ID Gets the object's last owner ID. +OBJECT_NAME Used with llGetObjectDetails to get an object's name +OBJECT_DESC Used with llGetObjectDetails to get an object's description +OBJECT_POS Used with llGetObjectDetails to get an object's position +OBJECT_ROT Used with llGetObjectDetails to get an object's rotation +OBJECT_VELOCITY Used with llGetObjectDetails to get an object's velocity +OBJECT_OWNER Used with llGetObjectDetails to get an object's owner's key. Will be NULL_KEY if group owned +OBJECT_GROUP Used with llGetObjectDetails to get an object's group's key +OBJECT_CLICK_ACTION This is a flag used with llGetObjectDetails to get the click action. The default is 0. +OBJECT_CREATOR Used with llGetObjectDetails to get an object's creator's key +OBJECT_RUNNING_SCRIPT_COUNT Gets the number of running scripts attached to the object or agent +OBJECT_TOTAL_SCRIPT_COUNT Gets the number of scripts, both running and stopped, attached to the object or agent. +OBJECT_SCRIPT_MEMORY Gets the total amount of script memory allocated to the object or agent, in bytes. +OBJECT_SCRIPT_TIME Gets the total amount of average script CPU time used by the object or agent, in seconds. +OBJECT_PRIM_EQUIVALENCE Gets the prim equivalence of the object. +OBJECT_SERVER_COST Used with llGetObjectDetails to get the server cost. +OBJECT_STREAMING_COST Used with llGetObjectDetails to get the streaming (download) cost. +OBJECT_PHYSICS_COST Used with llGetObjectDetails to get the physics cost. +OBJECT_PATHFINDING_TYPE Used with llGetObjectDetails to get an object's pathfinding settings. +OBJECT_BODY_SHAPE_TYPE This is a flag used with llGetObjectDetails to get the body type of the avatar, based on shape data. If no data is available, -1.0 is returned. This is normally between 0 and 1.0, with 0.5 and larger considered 'male' +OBJECT_CHARACTER_TIME Used with llGetObjectDetails to get an object's average CPU time (in seconds) used by the object for navigation, if the object is a pathfinding character. Returns 0 for non-characters. +OBJECT_ROOT Used with llGetObjectDetails to get an object's root prim ID. +OBJECT_ATTACHED_POINT Used with llGetObjectDetails to get an object's attachment point. +OBJECT_RETURN_PARCEL Used with llReturnObjectsByOwner to return all objects on the same parcel as the script which are owned by 'owner'. +OBJECT_RETURN_PARCEL_OWNER Used with llReturnObjectsByOwner to return all objects owned by 'owner' which are over parcels owned by the owner of the script. +OBJECT_RETURN_REGION Used with llReturnObjectsByOwner to return all objects in the region owned by 'owner' - only works when the script is owned by the estate owner or an estate manager. + +OPT_UNKNOWN Returned object pathfinding type by llGetObjectDetails for attachments, Linden trees and grass. +OPT_LEGACY_LINKSET Returned object pathfinding type by llGetObjectDetails for movable obstacles, movable phantoms, physical, and volumedetect objects. +OPT_AVATAR Returned object pathfinding type by llGetObjectDetails for avatars. +OPT_PATHFINDING_CHARACTER Returned object pathfinding type by llGetObjectDetails for pathfinding characters. +OPT_WALKABLE Returned object pathfinding type by llGetObjectDetails for walkable objects. +OPT_STATIC_OBSTACLE Returned object pathfinding type by llGetObjectDetails for static obstacles. +OPT_MATERIAL_VOLUME Returned object pathfinding type by llGetObjectDetails for material volumes. +OPT_EXCLUSION_VOLUME Returned object pathfinding type by llGetObjectDetails for exclusion volumes. # some vehicle params -VEHICLE_TYPE_NONE Used with llSetVehicleType to turn off vehicle support -VEHICLE_TYPE_SLED Used with llSetVehicleType to make a simple vehicle that bumps along the ground, and likes to move along its local x-axis -VEHICLE_TYPE_CAR Used with llSetVehicleType to make a vehicle that bounces along the ground but needs the motors to be driven from external controls or timer events -VEHICLE_TYPE_BOAT Used with llSetVehicleType to make a vehicle that hovers over water with lots of friction and some angular deflection -VEHICLE_TYPE_AIRPLANE Used with llSetVehicleType to make a vehicle that uses linear deflection for lift, and banking to turn, but doesn't hover -VEHICLE_TYPE_BALLOON Used with llSetVehicleType to make a vehicle that uses hover, and friction, but doesn't use deflection - -VEHICLE_REFERENCE_FRAME Rotation of vehicle axes relative to local frame - -VEHICLE_LINEAR_FRICTION_TIMESCALE A vector of timescales for exponential decay of linear velocity along the three vehicle axes -VEHICLE_ANGULAR_FRICTION_TIMESCALE A vector of timescales for exponential decay of angular velocity about the three vehicle axes -VEHICLE_LINEAR_MOTOR_DIRECTION The linear velocity that the vehicle will try to achieve -VEHICLE_LINEAR_MOTOR_OFFSET An offset from the center of mass of the vehicle where the linear motor is applied -VEHICLE_ANGULAR_MOTOR_DIRECTION The angular velocity that the vehicle will try to achieve - -VEHICLE_HOVER_HEIGHT The height the vehicle will try to hover -VEHICLE_HOVER_EFFICIENCY A slider between 0 (bouncy) and 1 (critically damped) hover behavior -VEHICLE_HOVER_TIMESCALE The period of time for the vehicle to achieve its hover height -VEHICLE_BUOYANCY A slider between 0 (no anti-gravity) and 1 (full anti-gravity) - -VEHICLE_LINEAR_DEFLECTION_EFFICIENCY A slider between 0 (no deflection) and 1 (maximum strength) -VEHICLE_LINEAR_DEFLECTION_TIMESCALE The exponential timescale for the vehicle to redirect its velocity to be along its x-axis - -VEHICLE_LINEAR_MOTOR_TIMESCALE The exponential timescale for the vehicle to achive its full linear motor velocity -VEHICLE_LINEAR_MOTOR_DECAY_TIMESCALE The exponential timescale for the linear motor's effectiveness to decay toward zero - -VEHICLE_ANGULAR_DEFLECTION_EFFICIENCY A slider between 0 (no deflection) and 1 (maximum strength) -VEHICLE_ANGULAR_DEFLECTION_TIMESCALE The exponential timescale for the vehicle to achieve full angular deflection - -VEHICLE_ANGULAR_MOTOR_TIMESCALE The exponential timescale for the vehicle to achive its full angular motor velocity -VEHICLE_ANGULAR_MOTOR_DECAY_TIMESCALE The exponential timescale for the angular motor's effectiveness to decay toward zero - -VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY A slider between 0 (bouncy) and 1 (critically damped) attraction of vehicle z-axis to world z-axis (vertical) -VEHICLE_VERTICAL_ATTRACTION_TIMESCALE The exponential timescale for the vehicle to align its z-axis to the world z-axis (vertical) - -VEHICLE_BANKING_EFFICIENCY A slider between -1 (leans out of turns), 0 (no banking), and +1 (leans into turns) -VEHICLE_BANKING_MIX A slider between 0 (static banking) and 1 (dynamic banking) -VEHICLE_BANKING_TIMESCALE The exponential timescale for the banking behavior to take full effect - -VEHICLE_FLAG_NO_DEFLECTION_UP Prevents linear deflection along world-z axis -VEHICLE_FLAG_LIMIT_ROLL_ONLY Removes vertical attraction for changes in vehicle pitch -VEHICLE_FLAG_HOVER_WATER_ONLY Hover only pays attention to water level -VEHICLE_FLAG_HOVER_TERRAIN_ONLY Hover only pays attention to terrain height -VEHICLE_FLAG_HOVER_GLOBAL_HEIGHT Hover only pays attention to global height -VEHICLE_FLAG_HOVER_UP_ONLY Hover only pushes up -VEHICLE_FLAG_LIMIT_MOTOR_UP Prevents ground vehicles from motoring into the sky -VEHICLE_FLAG_MOUSELOOK_STEER Makes vehicle try to turn toward mouselook direction -VEHICLE_FLAG_MOUSELOOK_BANK Makes vehicle try to turn toward mouselook direction assuming banking is enabled -VEHICLE_FLAG_CAMERA_DECOUPLED Causes the camera look-at axis to NOT move when the vehicle rotates - -CAMERA_PITCH (-45 to 80) (Adjusts the angular amount that the camera aims straight ahead vs. straight down, maintaining the same distance. Analogous to 'incidence'.") -CAMERA_FOCUS_OFFSET (-10 to 10) A vector that adjusts the position of the camera focus position relative to the subject -CAMERA_POSITION_LAG (0.0 to 3.0) How much the camera lags as it tries to move towards its 'ideal' position -CAMERA_FOCUS_LAG (0.0 to 3.0) How much the camera lags as it tries to aim towards the subject -CAMERA_DISTANCE (0.5 to 10) Sets how far away the camera wants to be from its subject -CAMERA_BEHINDNESS_ANGLE (0 to 180) Sets the angle in degrees within which the camera is not constrained by changes in subject rotation -CAMERA_BEHINDNESS_LAG (0.0 to 3.0) Sets how strongly the camera is forced to stay behind the target if outside of behindness angle -CAMERA_POSITION_THRESHOLD (0.0 to 4.0) Sets the radius of a sphere around the camera's ideal position within which it is not affected by subject motion -CAMERA_FOCUS_THRESHOLD (0.0 to 4.0) Sets the radius of a sphere around the camera's subject position within which its focus is not affected by subject motion -CAMERA_ACTIVE (0 or 1) Turns on or off scripted control of the camera -CAMERA_POSITION Sets the position of the camera -CAMERA_FOCUS Sets the focus (target position) of the camera -CAMERA_POSITION_LOCKED (0 or 1) Locks the camera position so it will not move -CAMERA_FOCUS_LOCKED (0 or 1) Locks the camera focus so it will not move - -INVENTORY_TEXTURE Passed to task inventory library functions to reference textures -INVENTORY_SOUND Passed to task inventory library functions to reference sounds -INVENTORY_OBJECT Passed to task inventory library functions to reference objects -INVENTORY_SCRIPT Passed to task inventory library functions to reference scripts -INVENTORY_LANDMARK Passed to task inventory library functions to reference landmarks -INVENTORY_CLOTHING Passed to task inventory library functions to reference clothing -INVENTORY_NOTECARD Passed to task inventory library functions to reference notecards -INVENTORY_BODYPART Passed to task inventory library functions to reference body parts -INVENTORY_ANIMATION Passed to task inventory library functions to reference animations -INVENTORY_GESTURE Passed to task inventory library functions to reference gestures -INVENTORY_ALL Passed to task inventory library functions to reference all inventory items -INVENTORY_NONE Returned by llGetInventoryType when no item is found - -ATTACH_CHEST Passed to llAttachToAvatar to attach task to chest -ATTACH_HEAD Passed to llAttachToAvatar to attach task to head -ATTACH_LSHOULDER Passed to llAttachToAvatar to attach task to left shoulder -ATTACH_RSHOULDER Passed to llAttachToAvatar to attach task to right shoulder -ATTACH_LHAND Passed to llAttachToAvatar to attach task to left hand -ATTACH_RHAND Passed to llAttachToAvatar to attach task to right hand -ATTACH_LFOOT Passed to llAttachToAvatar to attach task to left foot -ATTACH_RFOOT Passed to llAttachToAvatar to attach task to right foot -ATTACH_BACK Passed to llAttachToAvatar to attach task to back -ATTACH_PELVIS Passed to llAttachToAvatar to attach task to pelvis -ATTACH_MOUTH Passed to llAttachToAvatar to attach task to mouth -ATTACH_CHIN Passed to llAttachToAvatar to attach task to chin -ATTACH_LEAR Passed to llAttachToAvatar to attach task to left ear -ATTACH_REAR Passed to llAttachToAvatar to attach task to right ear -ATTACH_LEYE Passed to llAttachToAvatar to attach task to left eye -ATTACH_REYE Passed to llAttachToAvatar to attach task to right eye -ATTACH_NOSE Passed to llAttachToAvatar to attach task to nose -ATTACH_RUARM Passed to llAttachToAvatar to attach task to right upper arm -ATTACH_RLARM Passed to llAttachToAvatar to attach task to right lower arm -ATTACH_LUARM Passed to llAttachToAvatar to attach task to left upper arm -ATTACH_LLARM Passed to llAttachToAvatar to attach task to left lower arm -ATTACH_RHIP Passed to llAttachToAvatar to attach task to right hip -ATTACH_RULEG Passed to llAttachToAvatar to attach task to right upper leg -ATTACH_RLLEG Passed to llAttachToAvatar to attach task to right lower leg -ATTACH_LHIP Passed to llAttachToAvatar to attach task to left hip -ATTACH_LULEG Passed to llAttachToAvatar to attach task to left upper leg -ATTACH_LLLEG Passed to llAttachToAvatar to attach task to left lower leg -ATTACH_BELLY Passed to llAttachToAvatar to attach task to belly -ATTACH_LEFT_PEC Passed to llAttachToAvatar to attach task to left pectoral -ATTACH_RIGHT_PEC Passed to llAttachToAvatar to attach task to right pectoral -ATTACH_HUD_BOTTOM Passed to llAttachToAvatar to attach task to bottom hud area -ATTACH_HUD_BOTTOM_LEFT Passed to llAttachToAvatar to attach task to bottom left hud area -ATTACH_HUD_BOTTOM_RIGHT Passed to llAttachToAvatar to attach task to bottom right hud area -ATTACH_HUD_CENTER_1 Passed to llAttachToAvatar to attach task to center 1 hud area -ATTACH_HUD_CENTER_2 Passed to llAttachToAvatar to attach task to center 2 hud area -ATTACH_HUD_TOP_CENTER Passed to llAttachToAvatar to attach task to top center hud area -ATTACH_HUD_TOP_LEFT Passed to llAttachToAvatar to attach task to top left hud area -ATTACH_HUD_TOP_RIGHT Passed to llAttachToAvatar to attach task to top right hud area -ATTACH_NECK Passed to llAttachToAvatar to attach task to neck -ATTACH_AVATAR_CENTER Passed to llAttachToAvatar to attach task to avatar center - -LAND_LEVEL Passed to llModifyLand to level terrain -LAND_RAISE Passed to llModifyLand to raise terrain -LAND_LOWER Passed to llModifyLand to lower terrain -LAND_SMOOTH Passed to llModifyLand to smooth terrain -LAND_NOISE Passed to llModifyLand to randomize terrain -LAND_REVERT Passed to llModifyLand to revert terrain toward original state -LAND_SMALL_BRUSH Passed to llModifyLand to modify small land areas -LAND_MEDIUM_BRUSH Passed to llModifyLand to modify medium land areas -LAND_LARGE_BRUSH Passed to llModifyLand to modify large land areas - -DATA_PAYINFO Passed to llRequestAgentData to get payment status of an agent -DATA_ONLINE Passed to llRequestAgentData to determine if agent is online -DATA_NAME Passed to llRequestAgentData to get full agent name -DATA_BORN Passed to llRequestAgentData to get born on date as a string -DATA_RATING Passed to llRequestAgentData to get a comma separated sting of integer ratings -DATA_SIM_POS Passed to llRequestSimulatorData to get a string (cast to vector) of a simulator's global position -DATA_SIM_STATUS Passed to llRequestSimulatorData to get the status of a simulator -DATA_SIM_RATING Passed to llRequestSimulatorData to get the rating of a simulator - -PAYMENT_INFO_ON_FILE Used with llRequestAgentData to tell if Agent is of "Payment Info On File" status -PAYMENT_INFO_USED Used with llRequestAgentData to tell if Agent is of "Payment Info Used" status - -ANIM_ON Enable texture animation -LOOP Loop when animating textures -REVERSE Animate in the reverse direction -PING_PONG Animate forward, then reverse -SMOOTH Textures slides, instead of stepping -ROTATE Rotates the texture, instead of using frames -SCALE Scales the texture, instead of using frames - -ALL_SIDES Passed to various texture and color library functions to modify all sides - -LINK_SET Passed to various link functions to modify all blocks in the object -LINK_ROOT Passed to various link functions to modify only the root block (no effect on single block objects) -LINK_ALL_OTHERS Passed to various link functions to modify all other blocks in the object -LINK_ALL_CHILDREN Passed to various link functions to modify all child blocks in the object -LINK_THIS Passed to various link functions to modify only the calling block - -CHANGED_INVENTORY Parameter of changed event handler used to indicate change to task's inventory -CHANGED_COLOR Parameter of changed event handler used to indicate change to task's color -CHANGED_SHAPE Parameter of changed event handler used to indicate change to task's shape parameters -CHANGED_SCALE Parameter of changed event handler used to indicate change to task's scale -CHANGED_TEXTURE Parameter of changed event handler used to indicate change to task's texture -CHANGED_LINK Parameter of changed event handler used to indicate change to task's link status -CHANGED_ALLOWED_DROP Parameter of changed event handler used to indicate a user dropped an inventory item:onto task that was allowed only by llAllowInventoryDrop function call -CHANGED_OWNER Parameter of changed event handler used to indicate change to task's owner ONLY when an object is sold as original or deeded to group -CHANGED_REGION Parameter of changed event handler used to indicate the region has changed -CHANGED_TELEPORT Parameter of changed event handler used to indicate teleport has completed -CHANGED_REGION_START Parameter of changed event handler used to indicate the region has been restarted -CHANGED_MEDIA Parameter of changed event handler used to indicate that media has changed on a face of the task - -TYPE_INTEGER Indicates that the list entry is holding an integer -TYPE_FLOAT Indicates that the list entry is holding an float -TYPE_STRING Indicates that the list entry is holding an string -TYPE_KEY Indicates that the list entry is holding an key -TYPE_VECTOR Indicates that the list entry is holding an vector -TYPE_ROTATION Indicates that the list entry is holding an rotation -TYPE_INVALID Indicates that this wasn't a valid list entry - - -REMOTE_DATA_CHANNEL Value of event_type in remote_event after successful llOpenRemoteDataChannel -REMOTE_DATA_REQUEST Value of event_type in remote_event if XML-RPC request is received -REMOTE_DATA_REPLY Value of event_type in remote_event if XML-RPC reply is received - - -PRIM_NAME Sets the prim's name -PRIM_DESC Sets the prim's description -PRIM_TYPE Followed by PRIM_TYPE_BOX, PRIM_TYPE_CYLINDER, PRIM_TYPE_PRISM, PRIM_TYPE_SPHERE, PRIM_TYPE_TORUS, PRIM_TYPE_TUBE, or PRIM_TYPE_SCULPT and their arguments -PRIM_MATERIAL Followed by PRIM_MATERIAL_STONE, PRIM_MATERIAL_METAL, PRIM_MATERIAL_GLASS, PRIM_MATERIAL_WOOD, PRIM_MATERIAL_FLESH, PRIM_MATERIAL_PLASTIC, or PRIM_MATERIAL_RUBBER -PRIM_PHYSICS Sets physics to TRUE or FALSE -PRIM_FLEXIBLE Followed by TRUE or FALSE, integer softness, float gravity, float friction, float wind, float tension, and vector force -PRIM_POINT_LIGHT Followed by TRUE or FALSE, vector color, float intensity, float radius, float falloff -PRIM_TEMP_ON_REZ Sets temporary on rez to TRUE or FALSE -PRIM_PHANTOM Sets phantom to TRUE or FALSE -PRIM_CAST_SHADOWS DEPRECATED. Takes 1 parameter, an integer, but has no effect when set and always returns 0 if used in llGetPrimitiveParams -PRIM_POSITION Sets primitive position to a vector position -PRIM_SIZE Sets primitive size to a vector size -PRIM_ROTATION Sets primitive rotation -PRIM_TEXT Used to get or set the object's floating text. -PRIM_TEXTURE Followed by an integer face, key id, vector repeats, vector offsets,:and float rotation in radians -PRIM_COLOR Followed by an integer face, vector color, and float alpha -PRIM_BUMP_SHINY Followed by an integer face, one of PRIM_SHINY_NONE, PRIM_SHINY_LOW,:PRIM_SHINY_MEDIUM, or PRIM_SHINY_HIGH,:and one of PRIM_BUMP_NONE, PRIM_BUMP_BRIGHT, PRIM_BUMP_DARK, etc -PRIM_FULLBRIGHT Followed by an integer face, and TRUE or FALSE -PRIM_TEXGEN Followed by an integer face, and one of PRIM_TEXGEN_DEFAULT or PRIM_TEXGEN_PLANAR -PRIM_GLOW Followed by an integer face, and a float from 0.0 to 1.0 specifying glow amount -PRIM_POS_LOCAL Sets the prim's local position -PRIM_ROT_LOCAL Sets the prim's local rotation -PRIM_OMEGA Makes the object spin at the specified axis and rate -PRIM_LINK_TARGET Used to get or set multiple links with a single PrimParameters call. -PRIM_SLICE Get and set the 'slice' parameter of all shapes. Takes a vector parameter of the form - -PRIM_TYPE_BOX Followed by integer hole shape, vector cut, float hollow, vector twist,:vector top size, and vector top shear -PRIM_TYPE_CYLINDER Followed by integer hole shape, vector cut, float hollow, vector twist,:vector top size, and vector top shear -PRIM_TYPE_PRISM Followed by integer hole shape, vector cut, float hollow, vector twist,:vector top size, and vector top shear -PRIM_TYPE_SPHERE Followed by integer hole shape, vector cut, float hollow, vector twist,:and vector dimple -PRIM_TYPE_TORUS Followed by integer hole shape, vector cut, float hollow, vector twist,:vector hole size, vector top shear, vector advanced cut, vector taper,:float revolutions, float radius offset, and float skew -PRIM_TYPE_TUBE Followed by integer hole shape, vector cut, float hollow, vector twist,:vector hole size, vector top shear, vector advanced cut, vector taper,:float revolutions, float radius offset, and float skew -PRIM_TYPE_RING Followed by integer hole shape, vector cut, float hollow, vector twist,:vector hole size, vector top shear, vector advanced cut, vector taper,:float revolutions, float radius offset, and float skew -PRIM_TYPE_SCULPT Followed by a key/string texture uuid, and one of PRIM_SCULPT_TYPE_SPHERE, PRIM_SCULPT_TYPE_TORUS, PRIM_SCULPT_TYPE_PLANE, or PRIM_SCULPT_TYPE_CYLINDER - -PRIM_HOLE_DEFAULT Sets hole type to match the prim type -PRIM_HOLE_SQUARE Sets hole type to square -PRIM_HOLE_CIRCLE Sets hole type to circle -PRIM_HOLE_TRIANGLE Sets hole type to triangle - -PRIM_MATERIAL_STONE Sets material to stone -PRIM_MATERIAL_METAL Sets material to metal -PRIM_MATERIAL_GLASS Sets material to glass -PRIM_MATERIAL_WOOD Sets material to wood -PRIM_MATERIAL_FLESH Sets material to flesh -PRIM_MATERIAL_PLASTIC Sets material to plastic -PRIM_MATERIAL_RUBBER Sets material to rubber -PRIM_MATERIAL_LIGHT Sets material to light - -PRIM_SHINY_NONE No shininess -PRIM_SHINY_LOW Low shininess -PRIM_SHINY_MEDIUM Medium shininess -PRIM_SHINY_HIGH High shininess - -PRIM_BUMP_NONE No bump map -PRIM_BUMP_BRIGHT Generate bump map from highlights -PRIM_BUMP_DARK Generate bump map from lowlights -PRIM_BUMP_WOOD Wood bump map -PRIM_BUMP_BARK Bark bump map -PRIM_BUMP_BRICKS Brick bump map -PRIM_BUMP_CHECKER Checker bump map -PRIM_BUMP_CONCRETE Concrete bump map -PRIM_BUMP_TILE Tile bump map -PRIM_BUMP_STONE Stone bump map -PRIM_BUMP_DISKS Disk bump map -PRIM_BUMP_GRAVEL Gravel bump map -PRIM_BUMP_BLOBS Blob bump map -PRIM_BUMP_SIDING Siding bump map -PRIM_BUMP_LARGETILE Large tile bump map -PRIM_BUMP_STUCCO Stucco bump map -PRIM_BUMP_SUCTION Suction cup bump map -PRIM_BUMP_WEAVE Weave bump map - -PRIM_TEXGEN_DEFAULT Default texture mapping -PRIM_TEXGEN_PLANAR Planar texture mapping - -PRIM_SCULPT_TYPE_SPHERE Stitch edges in a sphere-like way -PRIM_SCULPT_TYPE_TORUS Stitch edges in a torus-like way -PRIM_SCULPT_TYPE_PLANE Do not stitch edges -PRIM_SCULPT_TYPE_CYLINDER Stitch edges in a cylinder-like way -PRIM_SCULPT_TYPE_MASK Mask used to determine stitching type -PRIM_SCULPT_FLAG_INVERT Flag to specify that the surface normals should be inverted -PRIM_SCULPT_FLAG_MIRROR Flag to specify that the prim should be reflected along X axis - -PRIM_PHYSICS_SHAPE_TYPE For primitive physics shape type. Followed with either PRIM_PHYSICS_SHAPE_PRIM, PRIM_PHYSICS_SHAPE_NONE or PRIM_PHYSICS_SHAPE_CONVEX. -PRIM_PHYSICS_SHAPE_PRIM Use the normal prim shape for physics (this is the default for all non-mesh objects) -PRIM_PHYSICS_SHAPE_NONE Use the convex hull of the prim shape for physics (this is the default for mesh objects) -PRIM_PHYSICS_SHAPE_CONVEX Ignore this prim in the physics shape. This cannot be applied to the root prim. - -MASK_BASE Base permissions -MASK_OWNER Owner permissions -MASK_GROUP Group permissions -MASK_EVERYONE Everyone permissions -MASK_NEXT Next owner permissions - -PERM_TRANSFER Transfer permission -PERM_MODIFY Modify permission -PERM_COPY Copy permission -PERM_MOVE Move permission -PERM_ALL Move/Modify/Copy/Transfer permissions - -PARCEL_MEDIA_COMMAND_STOP Stop media stream -PARCEL_MEDIA_COMMAND_PAUSE Pause media stream -PARCEL_MEDIA_COMMAND_PLAY Play media stream -PARCEL_MEDIA_COMMAND_LOOP Loop media stream -PARCEL_MEDIA_COMMAND_LOOP_SET Used to get or set the parcel's media loop duration -PARCEL_MEDIA_COMMAND_TEXTURE Get or set the parcel's media texture -PARCEL_MEDIA_COMMAND_URL Get or set the parcel's media url -PARCEL_MEDIA_COMMAND_TYPE Get or set the parcel's media mimetype -PARCEL_MEDIA_COMMAND_DESC Get or set the parcel's media description -PARCEL_MEDIA_COMMAND_TIME Set media stream to specific time -PARCEL_MEDIA_COMMAND_SIZE Get or set the parcel's media pixel resolution -PARCEL_MEDIA_COMMAND_AGENT Allows media stream commands to apply to only one agent -PARCEL_MEDIA_COMMAND_UNLOAD Unloads the media stream -PARCEL_MEDIA_COMMAND_AUTO_ALIGN Auto aligns the media stream to the texture size. May cause a performance hit and loss of some visual quality - -PAY_HIDE Used with llSetPayPrice to hide a button -PAY_DEFAULT Used with llSetPayPrice to use the default price for a button - -LIST_STAT_MAX Used with llListStatistics to find the largest number in a list -LIST_STAT_MIN Used with llListStatistics to find the smallest number in a list -LIST_STAT_MEAN Used with llListStatistics to find the mean of the numbers in a list -LIST_STAT_MEDIAN Used with llListStatistics to find the median of the numbers in a list -LIST_STAT_STD_DEV Used with llListStatistics to find the standard deviation of the numbers in a list -LIST_STAT_SUM Used with llListStatistics to find the sum of the numbers in a list -LIST_STAT_SUM_SQUARES Used with llListStatistics to find the sum of the squares of the numbers in a list -LIST_STAT_NUM_COUNT Used with llListStatistics to find how many numbers are in a list -LIST_STAT_GEOMETRIC_MEAN Used with llListStatistics to find the geometric mean of the numbers in a list (all numbers must be > 0) -LIST_STAT_RANGE Used with llListStatistics to find the range of the numbers in a list - -PARCEL_FLAG_ALLOW_FLY Used with llGetParcelFlags to find if a parcel allows flying -PARCEL_FLAG_ALLOW_GROUP_SCRIPTS Used with llGetParcelFlags to find if a parcel allows group scripts -PARCEL_FLAG_ALLOW_SCRIPTS Used with llGetParcelFlags to find if a parcel allows outside scripts -PARCEL_FLAG_ALLOW_LANDMARK Used with llGetParcelFlags to find if a parcel allows landmarks to be created -PARCEL_FLAG_ALLOW_TERRAFORM Used with llGetParcelFlags to find if a parcel allows anyone to terraform the land -PARCEL_FLAG_ALLOW_DAMAGE Used with llGetParcelFlags to find if a parcel allows damage -PARCEL_FLAG_ALLOW_CREATE_OBJECTS Used with llGetParcelFlags to find if a parcel allows anyone to create objects -PARCEL_FLAG_ALLOW_CREATE_GROUP_OBJECTS Used with llGetParcelFlags to find if a parcel allows group members or objects to create objects -PARCEL_FLAG_USE_ACCESS_GROUP Used with llGetParcelFlags to find if a parcel limits access to a group -PARCEL_FLAG_USE_ACCESS_LIST Used with llGetParcelFlags to find if a parcel limits access to a list of residents -PARCEL_FLAG_USE_BAN_LIST Used with llGetParcelFlags to find if a parcel uses a ban list -PARCEL_FLAG_USE_LAND_PASS_LIST Used with llGetParcelFlags to find if a parcel allows passes to be purchased -PARCEL_FLAG_LOCAL_SOUND_ONLY Used with llGetParcelFlags to find if a parcel restricts spacialized sound to the parcel -PARCEL_FLAG_RESTRICT_PUSHOBJECT Used with llGetParcelFlags to find if a parcel restricts llPushObject() calls -PARCEL_FLAG_ALLOW_ALL_OBJECT_ENTRY Used with llGetParcelFlags to find if a parcel allows all objects to enter -PARCEL_FLAG_ALLOW_GROUP_OBJECT_ENTRY Used with llGetParcelFlags to find if a parcel only allows group (and owner) objects to enter - -REGION_FLAG_ALLOW_DAMAGE Used with llGetRegionFlags to find if a region is entirely damage enabled -REGION_FLAG_FIXED_SUN Used with llGetRegionFlags to find if a region has a fixed sun position -REGION_FLAG_BLOCK_TERRAFORM Used with llGetRegionFlags to find if a region terraforming disabled -REGION_FLAG_SANDBOX Used with llGetRegionFlags to find if a region is a sandbox -REGION_FLAG_DISABLE_COLLISIONS Used with llGetRegionFlags to find if a region has disabled collisions -REGION_FLAG_DISABLE_PHYSICS Used with llGetRegionFlags to find if a region has disabled physics -REGION_FLAG_BLOCK_FLY Used with llGetRegionFlags to find if a region blocks flying -REGION_FLAG_ALLOW_DIRECT_TELEPORT Used with llGetRegionFlags to find if a region allows direct teleports -REGION_FLAG_RESTRICT_PUSHOBJECT Used with llGetRegionFlags to find if a region restricts llPushObject() calls - -HTTP_METHOD Used with llHTTPRequest to specify the method, "GET", "POST", "PUT", or "DELETE" -HTTP_MIMETYPE Used with llHTTPRequest to specify the MIME type, defaults to "text/plain" -HTTP_BODY_MAXLENGTH Used with llHTTPRequest to specify the maximum response body to return -HTTP_VERIFY_CERT Used with llHTTPRequest to specify SSL certificate verification -HTTP_BODY_TRUNCATED Used with http_response to indicate truncation point in bytes -HTTP_VERBOSE_THROTTLE Used with llHTTPRequest to shout error messages to DEBUG_CHANNEL if the outgoing request rate exceeds the server limit. -HTTP_BODY_MAXLENGTH Used with llHTTPRequest to specify the maximum body size for the date returned from the request. Mono scripts can request from 1byte to 16k, non-mono scripts can request from 1byte to 4k. The default is 2k. - -PARCEL_COUNT_TOTAL Used with llGetParcelPrimCount to get the total number of prims on the parcel -PARCEL_COUNT_OWNER Used with llGetParcelPrimCount to get the number of prims on the parcel owned by the owner -PARCEL_COUNT_GROUP Used with llGetParcelPrimCount to get the number of prims on the parcel owned by the group -PARCEL_COUNT_OTHER Used with llGetParcelPrimCount to get the number of prims on the parcel owned by others -PARCEL_COUNT_SELECTED Used with llGetParcelPrimCount to get the number of prims on the parcel currently selected or sat upon -PARCEL_COUNT_TEMP Used with llGetParcelPrimCount to get the number of prims on the parcel that are temp on rez - -PARCEL_DETAILS_NAME Used with llGetParcelDetails to get the parcel name -PARCEL_DETAILS_DESC Used with llGetParcelDetails to get the parcel description -PARCEL_DETAILS_OWNER Used with llGetParcelDetails to get the parcel owner id -PARCEL_DETAILS_GROUP Used with llGetParcelDetails to get the parcel group id -PARCEL_DETAILS_AREA Used with llGetParcelDetails to get the parcel area in square meters -PARCEL_DETAILS_ID Used with llGetParcelDetails to get the parcel id -PARCEL_DETAILS_SEE_AVATARS Used with llGetParcelDetails to get the avatars visibility setting - -STRING_TRIM_HEAD Used with llStringTrim to trim leading spaces from a string -STRING_TRIM_TAIL Used with llStringTrim to trim trailing spaces from a string -STRING_TRIM Used with llStringTrim to trim both leading and trailing spaces from a string +VEHICLE_TYPE_NONE Used with llSetVehicleType to turn off vehicle support +VEHICLE_TYPE_SLED Used with llSetVehicleType to make a simple vehicle that bumps along the ground, and likes to move along its local x-axis +VEHICLE_TYPE_CAR Used with llSetVehicleType to make a vehicle that bounces along the ground but needs the motors to be driven from external controls or timer events +VEHICLE_TYPE_BOAT Used with llSetVehicleType to make a vehicle that hovers over water with lots of friction and some angular deflection +VEHICLE_TYPE_AIRPLANE Used with llSetVehicleType to make a vehicle that uses linear deflection for lift, and banking to turn, but doesn't hover +VEHICLE_TYPE_BALLOON Used with llSetVehicleType to make a vehicle that uses hover, and friction, but doesn't use deflection + +VEHICLE_REFERENCE_FRAME Rotation of vehicle axes relative to local frame + +VEHICLE_LINEAR_FRICTION_TIMESCALE A vector of timescales for exponential decay of linear velocity along the three vehicle axes +VEHICLE_ANGULAR_FRICTION_TIMESCALE A vector of timescales for exponential decay of angular velocity about the three vehicle axes +VEHICLE_LINEAR_MOTOR_DIRECTION The linear velocity that the vehicle will try to achieve +VEHICLE_LINEAR_MOTOR_OFFSET An offset from the center of mass of the vehicle where the linear motor is applied +VEHICLE_ANGULAR_MOTOR_DIRECTION The angular velocity that the vehicle will try to achieve + +VEHICLE_HOVER_HEIGHT The height the vehicle will try to hover +VEHICLE_HOVER_EFFICIENCY A slider between 0 (bouncy) and 1 (critically damped) hover behavior +VEHICLE_HOVER_TIMESCALE The period of time for the vehicle to achieve its hover height +VEHICLE_BUOYANCY A slider between 0 (no anti-gravity) and 1 (full anti-gravity) + +VEHICLE_LINEAR_DEFLECTION_EFFICIENCY A slider between 0 (no deflection) and 1 (maximum strength) +VEHICLE_LINEAR_DEFLECTION_TIMESCALE The exponential timescale for the vehicle to redirect its velocity to be along its x-axis + +VEHICLE_LINEAR_MOTOR_TIMESCALE The exponential timescale for the vehicle to achive its full linear motor velocity +VEHICLE_LINEAR_MOTOR_DECAY_TIMESCALE The exponential timescale for the linear motor's effectiveness to decay toward zero + +VEHICLE_ANGULAR_DEFLECTION_EFFICIENCY A slider between 0 (no deflection) and 1 (maximum strength) +VEHICLE_ANGULAR_DEFLECTION_TIMESCALE The exponential timescale for the vehicle to achieve full angular deflection + +VEHICLE_ANGULAR_MOTOR_TIMESCALE The exponential timescale for the vehicle to achive its full angular motor velocity +VEHICLE_ANGULAR_MOTOR_DECAY_TIMESCALE The exponential timescale for the angular motor's effectiveness to decay toward zero + +VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY A slider between 0 (bouncy) and 1 (critically damped) attraction of vehicle z-axis to world z-axis (vertical) +VEHICLE_VERTICAL_ATTRACTION_TIMESCALE The exponential timescale for the vehicle to align its z-axis to the world z-axis (vertical) + +VEHICLE_BANKING_EFFICIENCY A slider between -1 (leans out of turns), 0 (no banking), and +1 (leans into turns) +VEHICLE_BANKING_MIX A slider between 0 (static banking) and 1 (dynamic banking) +VEHICLE_BANKING_TIMESCALE The exponential timescale for the banking behavior to take full effect + +VEHICLE_FLAG_NO_DEFLECTION_UP Prevents linear deflection along world-z axis +VEHICLE_FLAG_LIMIT_ROLL_ONLY Removes vertical attraction for changes in vehicle pitch +VEHICLE_FLAG_HOVER_WATER_ONLY Hover only pays attention to water level +VEHICLE_FLAG_HOVER_TERRAIN_ONLY Hover only pays attention to terrain height +VEHICLE_FLAG_HOVER_GLOBAL_HEIGHT Hover only pays attention to global height +VEHICLE_FLAG_HOVER_UP_ONLY Hover only pushes up +VEHICLE_FLAG_LIMIT_MOTOR_UP Prevents ground vehicles from motoring into the sky +VEHICLE_FLAG_MOUSELOOK_STEER Makes vehicle try to turn toward mouselook direction +VEHICLE_FLAG_MOUSELOOK_BANK Makes vehicle try to turn toward mouselook direction assuming banking is enabled +VEHICLE_FLAG_CAMERA_DECOUPLED Causes the camera look-at axis to NOT move when the vehicle rotates + +CAMERA_PITCH (-45 to 80) (Adjusts the angular amount that the camera aims straight ahead vs. straight down, maintaining the same distance. Analogous to 'incidence'.") +CAMERA_FOCUS_OFFSET (-10 to 10) A vector that adjusts the position of the camera focus position relative to the subject +CAMERA_POSITION_LAG (0.0 to 3.0) How much the camera lags as it tries to move towards its 'ideal' position +CAMERA_FOCUS_LAG (0.0 to 3.0) How much the camera lags as it tries to aim towards the subject +CAMERA_DISTANCE (0.5 to 10) Sets how far away the camera wants to be from its subject +CAMERA_BEHINDNESS_ANGLE (0 to 180) Sets the angle in degrees within which the camera is not constrained by changes in subject rotation +CAMERA_BEHINDNESS_LAG (0.0 to 3.0) Sets how strongly the camera is forced to stay behind the target if outside of behindness angle +CAMERA_POSITION_THRESHOLD (0.0 to 4.0) Sets the radius of a sphere around the camera's ideal position within which it is not affected by subject motion +CAMERA_FOCUS_THRESHOLD (0.0 to 4.0) Sets the radius of a sphere around the camera's subject position within which its focus is not affected by subject motion +CAMERA_ACTIVE (0 or 1) Turns on or off scripted control of the camera +CAMERA_POSITION Sets the position of the camera +CAMERA_FOCUS Sets the focus (target position) of the camera +CAMERA_POSITION_LOCKED (0 or 1) Locks the camera position so it will not move +CAMERA_FOCUS_LOCKED (0 or 1) Locks the camera focus so it will not move + +INVENTORY_TEXTURE Passed to task inventory library functions to reference textures +INVENTORY_SOUND Passed to task inventory library functions to reference sounds +INVENTORY_OBJECT Passed to task inventory library functions to reference objects +INVENTORY_SCRIPT Passed to task inventory library functions to reference scripts +INVENTORY_LANDMARK Passed to task inventory library functions to reference landmarks +INVENTORY_CLOTHING Passed to task inventory library functions to reference clothing +INVENTORY_NOTECARD Passed to task inventory library functions to reference notecards +INVENTORY_BODYPART Passed to task inventory library functions to reference body parts +INVENTORY_ANIMATION Passed to task inventory library functions to reference animations +INVENTORY_GESTURE Passed to task inventory library functions to reference gestures +INVENTORY_ALL Passed to task inventory library functions to reference all inventory items +INVENTORY_NONE Returned by llGetInventoryType when no item is found + +ATTACH_CHEST Passed to llAttachToAvatar to attach task to chest +ATTACH_HEAD Passed to llAttachToAvatar to attach task to head +ATTACH_LSHOULDER Passed to llAttachToAvatar to attach task to left shoulder +ATTACH_RSHOULDER Passed to llAttachToAvatar to attach task to right shoulder +ATTACH_LHAND Passed to llAttachToAvatar to attach task to left hand +ATTACH_RHAND Passed to llAttachToAvatar to attach task to right hand +ATTACH_LFOOT Passed to llAttachToAvatar to attach task to left foot +ATTACH_RFOOT Passed to llAttachToAvatar to attach task to right foot +ATTACH_BACK Passed to llAttachToAvatar to attach task to back +ATTACH_PELVIS Passed to llAttachToAvatar to attach task to pelvis +ATTACH_MOUTH Passed to llAttachToAvatar to attach task to mouth +ATTACH_CHIN Passed to llAttachToAvatar to attach task to chin +ATTACH_LEAR Passed to llAttachToAvatar to attach task to left ear +ATTACH_REAR Passed to llAttachToAvatar to attach task to right ear +ATTACH_LEYE Passed to llAttachToAvatar to attach task to left eye +ATTACH_REYE Passed to llAttachToAvatar to attach task to right eye +ATTACH_NOSE Passed to llAttachToAvatar to attach task to nose +ATTACH_RUARM Passed to llAttachToAvatar to attach task to right upper arm +ATTACH_RLARM Passed to llAttachToAvatar to attach task to right lower arm +ATTACH_LUARM Passed to llAttachToAvatar to attach task to left upper arm +ATTACH_LLARM Passed to llAttachToAvatar to attach task to left lower arm +ATTACH_RHIP Passed to llAttachToAvatar to attach task to right hip +ATTACH_RULEG Passed to llAttachToAvatar to attach task to right upper leg +ATTACH_RLLEG Passed to llAttachToAvatar to attach task to right lower leg +ATTACH_LHIP Passed to llAttachToAvatar to attach task to left hip +ATTACH_LULEG Passed to llAttachToAvatar to attach task to left upper leg +ATTACH_LLLEG Passed to llAttachToAvatar to attach task to left lower leg +ATTACH_BELLY Passed to llAttachToAvatar to attach task to belly +ATTACH_LEFT_PEC Passed to llAttachToAvatar to attach task to left pectoral +ATTACH_RIGHT_PEC Passed to llAttachToAvatar to attach task to right pectoral +ATTACH_HUD_BOTTOM Passed to llAttachToAvatar to attach task to bottom hud area +ATTACH_HUD_BOTTOM_LEFT Passed to llAttachToAvatar to attach task to bottom left hud area +ATTACH_HUD_BOTTOM_RIGHT Passed to llAttachToAvatar to attach task to bottom right hud area +ATTACH_HUD_CENTER_1 Passed to llAttachToAvatar to attach task to center 1 hud area +ATTACH_HUD_CENTER_2 Passed to llAttachToAvatar to attach task to center 2 hud area +ATTACH_HUD_TOP_CENTER Passed to llAttachToAvatar to attach task to top center hud area +ATTACH_HUD_TOP_LEFT Passed to llAttachToAvatar to attach task to top left hud area +ATTACH_HUD_TOP_RIGHT Passed to llAttachToAvatar to attach task to top right hud area +ATTACH_NECK Passed to llAttachToAvatar to attach task to neck +ATTACH_AVATAR_CENTER Passed to llAttachToAvatar to attach task to avatar center + +LAND_LEVEL Passed to llModifyLand to level terrain +LAND_RAISE Passed to llModifyLand to raise terrain +LAND_LOWER Passed to llModifyLand to lower terrain +LAND_SMOOTH Passed to llModifyLand to smooth terrain +LAND_NOISE Passed to llModifyLand to randomize terrain +LAND_REVERT Passed to llModifyLand to revert terrain toward original state +LAND_SMALL_BRUSH Passed to llModifyLand to modify small land areas +LAND_MEDIUM_BRUSH Passed to llModifyLand to modify medium land areas +LAND_LARGE_BRUSH Passed to llModifyLand to modify large land areas + +DATA_PAYINFO Passed to llRequestAgentData to get payment status of an agent +DATA_ONLINE Passed to llRequestAgentData to determine if agent is online +DATA_NAME Passed to llRequestAgentData to get full agent name +DATA_BORN Passed to llRequestAgentData to get born on date as a string +DATA_RATING Passed to llRequestAgentData to get a comma separated sting of integer ratings +DATA_SIM_POS Passed to llRequestSimulatorData to get a string (cast to vector) of a simulator's global position +DATA_SIM_STATUS Passed to llRequestSimulatorData to get the status of a simulator +DATA_SIM_RATING Passed to llRequestSimulatorData to get the rating of a simulator + +PAYMENT_INFO_ON_FILE Used with llRequestAgentData to tell if Agent is of "Payment Info On File" status +PAYMENT_INFO_USED Used with llRequestAgentData to tell if Agent is of "Payment Info Used" status + +ANIM_ON Enable texture animation +LOOP Loop when animating textures +REVERSE Animate in the reverse direction +PING_PONG Animate forward, then reverse +SMOOTH Textures slides, instead of stepping +ROTATE Rotates the texture, instead of using frames +SCALE Scales the texture, instead of using frames + +ALL_SIDES Passed to various texture and color library functions to modify all sides + +LINK_SET Passed to various link functions to modify all blocks in the object +LINK_ROOT Passed to various link functions to modify only the root block (no effect on single block objects) +LINK_ALL_OTHERS Passed to various link functions to modify all other blocks in the object +LINK_ALL_CHILDREN Passed to various link functions to modify all child blocks in the object +LINK_THIS Passed to various link functions to modify only the calling block + +CHANGED_INVENTORY Parameter of changed event handler used to indicate change to task's inventory +CHANGED_COLOR Parameter of changed event handler used to indicate change to task's color +CHANGED_SHAPE Parameter of changed event handler used to indicate change to task's shape parameters +CHANGED_SCALE Parameter of changed event handler used to indicate change to task's scale +CHANGED_TEXTURE Parameter of changed event handler used to indicate change to task's texture +CHANGED_LINK Parameter of changed event handler used to indicate change to task's link status +CHANGED_ALLOWED_DROP Parameter of changed event handler used to indicate a user dropped an inventory item:onto task that was allowed only by llAllowInventoryDrop function call +CHANGED_OWNER Parameter of changed event handler used to indicate change to task's owner ONLY when an object is sold as original or deeded to group +CHANGED_REGION Parameter of changed event handler used to indicate the region has changed +CHANGED_TELEPORT Parameter of changed event handler used to indicate teleport has completed +CHANGED_REGION_START Parameter of changed event handler used to indicate the region has been restarted +CHANGED_MEDIA Parameter of changed event handler used to indicate that media has changed on a face of the task + +TYPE_INTEGER Indicates that the list entry is holding an integer +TYPE_FLOAT Indicates that the list entry is holding an float +TYPE_STRING Indicates that the list entry is holding an string +TYPE_KEY Indicates that the list entry is holding an key +TYPE_VECTOR Indicates that the list entry is holding an vector +TYPE_ROTATION Indicates that the list entry is holding an rotation +TYPE_INVALID Indicates that this wasn't a valid list entry + + +REMOTE_DATA_CHANNEL Value of event_type in remote_event after successful llOpenRemoteDataChannel +REMOTE_DATA_REQUEST Value of event_type in remote_event if XML-RPC request is received +REMOTE_DATA_REPLY Value of event_type in remote_event if XML-RPC reply is received + + +PRIM_NAME Sets the prim's name +PRIM_DESC Sets the prim's description +PRIM_TYPE Followed by PRIM_TYPE_BOX, PRIM_TYPE_CYLINDER, PRIM_TYPE_PRISM, PRIM_TYPE_SPHERE, PRIM_TYPE_TORUS, PRIM_TYPE_TUBE, or PRIM_TYPE_SCULPT and their arguments +PRIM_MATERIAL Followed by PRIM_MATERIAL_STONE, PRIM_MATERIAL_METAL, PRIM_MATERIAL_GLASS, PRIM_MATERIAL_WOOD, PRIM_MATERIAL_FLESH, PRIM_MATERIAL_PLASTIC, or PRIM_MATERIAL_RUBBER +PRIM_PHYSICS Sets physics to TRUE or FALSE +PRIM_FLEXIBLE Followed by TRUE or FALSE, integer softness, float gravity, float friction, float wind, float tension, and vector force +PRIM_POINT_LIGHT Followed by TRUE or FALSE, vector color, float intensity, float radius, float falloff +PRIM_TEMP_ON_REZ Sets temporary on rez to TRUE or FALSE +PRIM_PHANTOM Sets phantom to TRUE or FALSE +PRIM_CAST_SHADOWS DEPRECATED. Takes 1 parameter, an integer, but has no effect when set and always returns 0 if used in llGetPrimitiveParams +PRIM_POSITION Sets primitive position to a vector position +PRIM_SIZE Sets primitive size to a vector size +PRIM_ROTATION Sets primitive rotation +PRIM_TEXT Used to get or set the object's floating text. +PRIM_TEXTURE Followed by an integer face, key id, vector repeats, vector offsets,:and float rotation in radians +PRIM_COLOR Followed by an integer face, vector color, and float alpha +PRIM_BUMP_SHINY Followed by an integer face, one of PRIM_SHINY_NONE, PRIM_SHINY_LOW,:PRIM_SHINY_MEDIUM, or PRIM_SHINY_HIGH,:and one of PRIM_BUMP_NONE, PRIM_BUMP_BRIGHT, PRIM_BUMP_DARK, etc +PRIM_FULLBRIGHT Followed by an integer face, and TRUE or FALSE +PRIM_TEXGEN Followed by an integer face, and one of PRIM_TEXGEN_DEFAULT or PRIM_TEXGEN_PLANAR +PRIM_GLOW Followed by an integer face, and a float from 0.0 to 1.0 specifying glow amount +PRIM_POS_LOCAL Sets the prim's local position +PRIM_ROT_LOCAL Sets the prim's local rotation +PRIM_OMEGA Makes the object spin at the specified axis and rate +PRIM_LINK_TARGET Used to get or set multiple links with a single PrimParameters call. +PRIM_SLICE Get and set the 'slice' parameter of all shapes. Takes a vector parameter of the form + +PRIM_TYPE_BOX Followed by integer hole shape, vector cut, float hollow, vector twist,:vector top size, and vector top shear +PRIM_TYPE_CYLINDER Followed by integer hole shape, vector cut, float hollow, vector twist,:vector top size, and vector top shear +PRIM_TYPE_PRISM Followed by integer hole shape, vector cut, float hollow, vector twist,:vector top size, and vector top shear +PRIM_TYPE_SPHERE Followed by integer hole shape, vector cut, float hollow, vector twist,:and vector dimple +PRIM_TYPE_TORUS Followed by integer hole shape, vector cut, float hollow, vector twist,:vector hole size, vector top shear, vector advanced cut, vector taper,:float revolutions, float radius offset, and float skew +PRIM_TYPE_TUBE Followed by integer hole shape, vector cut, float hollow, vector twist,:vector hole size, vector top shear, vector advanced cut, vector taper,:float revolutions, float radius offset, and float skew +PRIM_TYPE_RING Followed by integer hole shape, vector cut, float hollow, vector twist,:vector hole size, vector top shear, vector advanced cut, vector taper,:float revolutions, float radius offset, and float skew +PRIM_TYPE_SCULPT Followed by a key/string texture uuid, and one of PRIM_SCULPT_TYPE_SPHERE, PRIM_SCULPT_TYPE_TORUS, PRIM_SCULPT_TYPE_PLANE, or PRIM_SCULPT_TYPE_CYLINDER + +PRIM_HOLE_DEFAULT Sets hole type to match the prim type +PRIM_HOLE_SQUARE Sets hole type to square +PRIM_HOLE_CIRCLE Sets hole type to circle +PRIM_HOLE_TRIANGLE Sets hole type to triangle + +PRIM_MATERIAL_STONE Sets material to stone +PRIM_MATERIAL_METAL Sets material to metal +PRIM_MATERIAL_GLASS Sets material to glass +PRIM_MATERIAL_WOOD Sets material to wood +PRIM_MATERIAL_FLESH Sets material to flesh +PRIM_MATERIAL_PLASTIC Sets material to plastic +PRIM_MATERIAL_RUBBER Sets material to rubber +PRIM_MATERIAL_LIGHT Sets material to light + +PRIM_SHINY_NONE No shininess +PRIM_SHINY_LOW Low shininess +PRIM_SHINY_MEDIUM Medium shininess +PRIM_SHINY_HIGH High shininess + +PRIM_BUMP_NONE No bump map +PRIM_BUMP_BRIGHT Generate bump map from highlights +PRIM_BUMP_DARK Generate bump map from lowlights +PRIM_BUMP_WOOD Wood bump map +PRIM_BUMP_BARK Bark bump map +PRIM_BUMP_BRICKS Brick bump map +PRIM_BUMP_CHECKER Checker bump map +PRIM_BUMP_CONCRETE Concrete bump map +PRIM_BUMP_TILE Tile bump map +PRIM_BUMP_STONE Stone bump map +PRIM_BUMP_DISKS Disk bump map +PRIM_BUMP_GRAVEL Gravel bump map +PRIM_BUMP_BLOBS Blob bump map +PRIM_BUMP_SIDING Siding bump map +PRIM_BUMP_LARGETILE Large tile bump map +PRIM_BUMP_STUCCO Stucco bump map +PRIM_BUMP_SUCTION Suction cup bump map +PRIM_BUMP_WEAVE Weave bump map + +PRIM_TEXGEN_DEFAULT Default texture mapping +PRIM_TEXGEN_PLANAR Planar texture mapping + +PRIM_SCULPT_TYPE_SPHERE Stitch edges in a sphere-like way +PRIM_SCULPT_TYPE_TORUS Stitch edges in a torus-like way +PRIM_SCULPT_TYPE_PLANE Do not stitch edges +PRIM_SCULPT_TYPE_CYLINDER Stitch edges in a cylinder-like way +PRIM_SCULPT_TYPE_MASK Mask used to determine stitching type +PRIM_SCULPT_FLAG_INVERT Flag to specify that the surface normals should be inverted +PRIM_SCULPT_FLAG_MIRROR Flag to specify that the prim should be reflected along X axis + +PRIM_PHYSICS_SHAPE_TYPE For primitive physics shape type. Followed with either PRIM_PHYSICS_SHAPE_PRIM, PRIM_PHYSICS_SHAPE_NONE or PRIM_PHYSICS_SHAPE_CONVEX. +PRIM_PHYSICS_SHAPE_PRIM Use the normal prim shape for physics (this is the default for all non-mesh objects) +PRIM_PHYSICS_SHAPE_NONE Use the convex hull of the prim shape for physics (this is the default for mesh objects) +PRIM_PHYSICS_SHAPE_CONVEX Ignore this prim in the physics shape. This cannot be applied to the root prim. + +PRIM_SPECULAR Used to get or set the specular map texture settings of a prim's face. +PRIM_NORMAL Used to get or set the normal map texture settings of a prim's face. + +PRIM_ALPHA_MODE Used to specify how the alpha channel of the diffuse texture should affect rendering of a prims face. +PRIM_ALPHA_MODE_NONE Render the diffuse texture as though the alpha channel were nonexistent. +PRIM_ALPHA_MODE_BLEND Render the diffuse texture with alpha-blending. +PRIM_ALPHA_MODE_MASK Render the prim face in alpha-masked mode. +PRIM_ALPHA_MODE_EMISSIVE Render the prim face in emissivity mode. + +MASK_BASE Base permissions +MASK_OWNER Owner permissions +MASK_GROUP Group permissions +MASK_EVERYONE Everyone permissions +MASK_NEXT Next owner permissions + +PERM_TRANSFER Transfer permission +PERM_MODIFY Modify permission +PERM_COPY Copy permission +PERM_MOVE Move permission +PERM_ALL Move/Modify/Copy/Transfer permissions + +PARCEL_MEDIA_COMMAND_STOP Stop media stream +PARCEL_MEDIA_COMMAND_PAUSE Pause media stream +PARCEL_MEDIA_COMMAND_PLAY Play media stream +PARCEL_MEDIA_COMMAND_LOOP Loop media stream +PARCEL_MEDIA_COMMAND_LOOP_SET Used to get or set the parcel's media loop duration +PARCEL_MEDIA_COMMAND_TEXTURE Get or set the parcel's media texture +PARCEL_MEDIA_COMMAND_URL Get or set the parcel's media url +PARCEL_MEDIA_COMMAND_TYPE Get or set the parcel's media mimetype +PARCEL_MEDIA_COMMAND_DESC Get or set the parcel's media description +PARCEL_MEDIA_COMMAND_TIME Set media stream to specific time +PARCEL_MEDIA_COMMAND_SIZE Get or set the parcel's media pixel resolution +PARCEL_MEDIA_COMMAND_AGENT Allows media stream commands to apply to only one agent +PARCEL_MEDIA_COMMAND_UNLOAD Unloads the media stream +PARCEL_MEDIA_COMMAND_AUTO_ALIGN Auto aligns the media stream to the texture size. May cause a performance hit and loss of some visual quality + +PAY_HIDE Used with llSetPayPrice to hide a button +PAY_DEFAULT Used with llSetPayPrice to use the default price for a button + +LIST_STAT_MAX Used with llListStatistics to find the largest number in a list +LIST_STAT_MIN Used with llListStatistics to find the smallest number in a list +LIST_STAT_MEAN Used with llListStatistics to find the mean of the numbers in a list +LIST_STAT_MEDIAN Used with llListStatistics to find the median of the numbers in a list +LIST_STAT_STD_DEV Used with llListStatistics to find the standard deviation of the numbers in a list +LIST_STAT_SUM Used with llListStatistics to find the sum of the numbers in a list +LIST_STAT_SUM_SQUARES Used with llListStatistics to find the sum of the squares of the numbers in a list +LIST_STAT_NUM_COUNT Used with llListStatistics to find how many numbers are in a list +LIST_STAT_GEOMETRIC_MEAN Used with llListStatistics to find the geometric mean of the numbers in a list (all numbers must be > 0) +LIST_STAT_RANGE Used with llListStatistics to find the range of the numbers in a list + +PARCEL_FLAG_ALLOW_FLY Used with llGetParcelFlags to find if a parcel allows flying +PARCEL_FLAG_ALLOW_GROUP_SCRIPTS Used with llGetParcelFlags to find if a parcel allows group scripts +PARCEL_FLAG_ALLOW_SCRIPTS Used with llGetParcelFlags to find if a parcel allows outside scripts +PARCEL_FLAG_ALLOW_LANDMARK Used with llGetParcelFlags to find if a parcel allows landmarks to be created +PARCEL_FLAG_ALLOW_TERRAFORM Used with llGetParcelFlags to find if a parcel allows anyone to terraform the land +PARCEL_FLAG_ALLOW_DAMAGE Used with llGetParcelFlags to find if a parcel allows damage +PARCEL_FLAG_ALLOW_CREATE_OBJECTS Used with llGetParcelFlags to find if a parcel allows anyone to create objects +PARCEL_FLAG_ALLOW_CREATE_GROUP_OBJECTS Used with llGetParcelFlags to find if a parcel allows group members or objects to create objects +PARCEL_FLAG_USE_ACCESS_GROUP Used with llGetParcelFlags to find if a parcel limits access to a group +PARCEL_FLAG_USE_ACCESS_LIST Used with llGetParcelFlags to find if a parcel limits access to a list of residents +PARCEL_FLAG_USE_BAN_LIST Used with llGetParcelFlags to find if a parcel uses a ban list +PARCEL_FLAG_USE_LAND_PASS_LIST Used with llGetParcelFlags to find if a parcel allows passes to be purchased +PARCEL_FLAG_LOCAL_SOUND_ONLY Used with llGetParcelFlags to find if a parcel restricts spacialized sound to the parcel +PARCEL_FLAG_RESTRICT_PUSHOBJECT Used with llGetParcelFlags to find if a parcel restricts llPushObject() calls +PARCEL_FLAG_ALLOW_ALL_OBJECT_ENTRY Used with llGetParcelFlags to find if a parcel allows all objects to enter +PARCEL_FLAG_ALLOW_GROUP_OBJECT_ENTRY Used with llGetParcelFlags to find if a parcel only allows group (and owner) objects to enter + +REGION_FLAG_ALLOW_DAMAGE Used with llGetRegionFlags to find if a region is entirely damage enabled +REGION_FLAG_FIXED_SUN Used with llGetRegionFlags to find if a region has a fixed sun position +REGION_FLAG_BLOCK_TERRAFORM Used with llGetRegionFlags to find if a region terraforming disabled +REGION_FLAG_SANDBOX Used with llGetRegionFlags to find if a region is a sandbox +REGION_FLAG_DISABLE_COLLISIONS Used with llGetRegionFlags to find if a region has disabled collisions +REGION_FLAG_DISABLE_PHYSICS Used with llGetRegionFlags to find if a region has disabled physics +REGION_FLAG_BLOCK_FLY Used with llGetRegionFlags to find if a region blocks flying +REGION_FLAG_BLOCK_FLYOVER Used with llGetRegionFlags to find if a region enforces higher altitude parcel access rules +REGION_FLAG_ALLOW_DIRECT_TELEPORT Used with llGetRegionFlags to find if a region allows direct teleports +REGION_FLAG_RESTRICT_PUSHOBJECT Used with llGetRegionFlags to find if a region restricts llPushObject() calls + +HTTP_METHOD Used with llHTTPRequest to specify the method, "GET", "POST", "PUT", or "DELETE" +HTTP_MIMETYPE Used with llHTTPRequest to specify the MIME type, defaults to "text/plain" +HTTP_BODY_MAXLENGTH Used with llHTTPRequest to specify the maximum response body to return +HTTP_VERIFY_CERT Used with llHTTPRequest to specify SSL certificate verification +HTTP_BODY_TRUNCATED Used with http_response to indicate truncation point in bytes +HTTP_VERBOSE_THROTTLE Used with llHTTPRequest to shout error messages to DEBUG_CHANNEL if the outgoing request rate exceeds the server limit. +HTTP_BODY_MAXLENGTH Used with llHTTPRequest to specify the maximum body size for the date returned from the request. Mono scripts can request from 1byte to 16k, non-mono scripts can request from 1byte to 4k. The default is 2k. + +PARCEL_COUNT_TOTAL Used with llGetParcelPrimCount to get the total number of prims on the parcel +PARCEL_COUNT_OWNER Used with llGetParcelPrimCount to get the number of prims on the parcel owned by the owner +PARCEL_COUNT_GROUP Used with llGetParcelPrimCount to get the number of prims on the parcel owned by the group +PARCEL_COUNT_OTHER Used with llGetParcelPrimCount to get the number of prims on the parcel owned by others +PARCEL_COUNT_SELECTED Used with llGetParcelPrimCount to get the number of prims on the parcel currently selected or sat upon +PARCEL_COUNT_TEMP Used with llGetParcelPrimCount to get the number of prims on the parcel that are temp on rez + +PARCEL_DETAILS_NAME Used with llGetParcelDetails to get the parcel name +PARCEL_DETAILS_DESC Used with llGetParcelDetails to get the parcel description +PARCEL_DETAILS_OWNER Used with llGetParcelDetails to get the parcel owner id +PARCEL_DETAILS_GROUP Used with llGetParcelDetails to get the parcel group id +PARCEL_DETAILS_AREA Used with llGetParcelDetails to get the parcel area in square meters +PARCEL_DETAILS_ID Used with llGetParcelDetails to get the parcel id +PARCEL_DETAILS_SEE_AVATARS Used with llGetParcelDetails to get the avatars visibility setting + +STRING_TRIM_HEAD Used with llStringTrim to trim leading spaces from a string +STRING_TRIM_TAIL Used with llStringTrim to trim trailing spaces from a string +STRING_TRIM Used with llStringTrim to trim both leading and trailing spaces from a string CLICK_ACTION_NONE Used with llSetClickAction to disable the click action CLICK_ACTION_TOUCH Used with llSetClickAction to set touch as the default action when object is clicked @@ -641,77 +675,77 @@ STATUS_WHITELIST_FAILED URL failed to pass whitelist PROFILE_NONE Disables profiling PROFILE_SCRIPT_MEMORY Enables memory profiling -RC_DATA_FLAGS Option for llCastRay() followed with a bitwise combination of RC_GET_NORMAL, RC_GET_ROOT_KEY and RC_GET_LINK_NUM. -RC_DETECT_PHANTOM Option for llCastRay() followed with TRUE to detect phantom AND volume detect objects, FASLE otherwise. -RC_GET_LINK_NUM Flag used in the RC_DATA_FLAGS mask to get link numbers in llCastRay() results. -RC_GET_NORMAL Flag used in the RC_DATA_FLAGS mask to get hit normals in llCastRay() results. -RC_GET_ROOT_KEY Flag used in the RC_DATA_FLAGS mask to get root keys in llCastRay() results. -RC_MAX_HITS Option for llCastRay() followed with an integer specifying the maximum number of hits to return (must be <= 256). -RC_REJECT_TYPES Option for llCastRay() used to ignore specific types of objects, followed with a bitwise combination of RC_REJECT_AGENTS, RC_REJECT_PHYSICAL, RC_REJECT_NONPHYSICAL and RC_REJECT_LAND. -RC_REJECT_AGENTS Flag used in the RC_REJECT_TYPES mask to reject agents in llCastRay(). -RC_REJECT_PHYSICAL Flag used in the RC_REJECT_TYPES mask to reject physical objects in llCastRay(). -RC_REJECT_NONPHYSICAL Flag used in the RC_REJECT_TYPES mask to reject non-physical objects in llCastRay(). -RC_REJECT_LAND Flag used in the RC_REJECT_TYPES mask to reject land in llCastRay(). - -RCERR_CAST_TIME_EXCEEDED Returned by llCastRay() when the raycast failed because the parcel or agent has exceeded the maximum time allowed for raycasting. -RCERR_SIM_PERF_LOW Returned by llCastRay() when the raycast failed because simulator performance is low. -RCERR_UNKNOWN Returned by llCastRay() when the raycast failed for an unspecified reason. - -ESTATE_ACCESS_ALLOWED_AGENT_ADD Used with llManageEstateAccess to add an agent to this estate's allowed residents list. -ESTATE_ACCESS_ALLOWED_AGENT_REMOVE Used with llManageEstateAccess to remove an agent from this estate's allowed residents list. -ESTATE_ACCESS_ALLOWED_GROUP_ADD Used with llManageEstateAccess to add a group to this estate's allowed groups list. -ESTATE_ACCESS_ALLOWED_GROUP_REMOVE Used with llManageEstateAccess to remove a group from this estate's allowed groups list. -ESTATE_ACCESS_BANNED_AGENT_ADD Used with llManageEstateAccess to add an agent to this estate's banned residents list. -ESTATE_ACCESS_BANNED_AGENT_REMOVE Used with llManageEstateAccess to remove an agent from this estate's banned residents list. - -DENSITY For use with llSetPhysicsMaterial() as a bitwise value in its material_bits parameter, to set the density. -FRICTION For use with llSetPhysicsMaterial() as a bitwise value in its material_bits parameter, to set the friction. -RESTITUTION For use with llSetPhysicsMaterial() as a bitwise value in its material_bits parameter, to set the restitution. -GRAVITY_MULTIPLIER For use with llSetPhysicsMaterial() as a bitwise value in its material_bits parameter, to set the gravity multiplier. - -SIM_STAT_PCT_CHARS_STEPPED Option for llGetSimStats() to return the % of pathfinding characters skipped each frame, averaged over the last minute. - -KFM_COMMAND Option for llSetKeyframedMotion(), followed by one of KFM_CMD_STOP, KFM_CMD_PLAY, KFM_CMD_PAUSE. Note that KFM_COMMAND must be the only option in the list, and cannot be specified in the same function call that sets the keyframes list. -KFM_CMD_PLAY Option for llSetKeyframedMotion(), used after KFM_COMMAND to play the motion. -KFM_CMD_STOP Option for llSetKeyframedMotion(), used after KFM_COMMAND to stop the motion. -KFM_CMD_PAUSE Option for llSetKeyframedMotion(), used after KFM_COMMAND to pause the motion. -KFM_MODE Option for llSetKeyframedMotion(), used to specify the playback mode, followed by one of KFM_FORWARD, KFM_LOOP, KFM_PING_PONG or KFM_REVERSE. -KFM_FORWARD Option for llSetKeyframedMotion(), used after KFM_MODE to specify the forward playback mode. -KFM_LOOP Option for llSetKeyframedMotion(), used after KFM_MODE to specify the loop playback mode. -KFM_PING_PONG Option for llSetKeyframedMotion(), used after KFM_MODE to specify the ping pong playback mode. -KFM_REVERSE Option for llSetKeyframedMotion(), used after KFM_MODE to specify the reverse playback mode. -KFM_DATA Option for llSetKeyframedMotion(), followed by a bitwise combination of KFM_TRANSLATION and KFM_ROTATION. If you specify one or the other, you should only include translations or rotations in your keyframe list. -KFM_ROTATION Option for llSetKeyframedMotion(), used after KFM_DATA, possibly as a bitwise combination with KFM_TRANSLATION. -KFM_TRANSLATION Option for llSetKeyframedMotion(), used after KFM_DATA, possibly as a bitwise combination with KFM_ROTATION. - -CHARACTER_CMD_STOP Used with llExecCharacterCmd(). Makes the character jump. -CHARACTER_CMD_SMOOTH_STOP Used with llExecCharacterCmd(). Stops any current pathfinding operation in a smooth like fashion. -CHARACTER_CMD_JUMP Used with llExecCharacterCmd(). Stops any current pathfinding operation. - -CHARACTER_DESIRED_SPEED Speed of pursuit in meters per second. -CHARACTER_RADIUS Set collision capsule radius. -CHARACTER_LENGTH Set collision capsule length. -CHARACTER_ORIENTATION Set the character orientation. -CHARACTER_AVOIDANCE_MODE Allows you to specify that a character should not try to avoid other characters, should not try to avoid dynamic obstacles (relatively fast moving objects and avatars), or both. -CHARACTER_ACCOUNT_FOR_SKIPPED_FRAMES Defines if a character will attempt to catch up lost time if pathfinding performance is low. -PURSUIT_OFFSET Used with llPursue(). Go to a position offset from the target. -REQUIRE_LINE_OF_SIGHT Used with llPursue(). Define whether the character needs a physical line-of-sight to give chase. When enabled, the character will not pick a new target position while there is a something solid between the character and the target object/agent. -PURSUIT_FUZZ_FACTOR Used with llPursue(). Selects a random destination near the PURSUIT_OFFSET. The valid fuzz factor range is from 0 to 1, where 1 is most random. This option requires a nonzero PURSUIT_OFFSET. -PURSUIT_INTERCEPT Used with llPursue(). Define whether the character attempts to predict the target's future location. -PURSUIT_GOAL_TOLERANCE Used with llPursue(). Defines approximately how close the character must be to the current goal to consider itself to be at the desired position. The valid range is from 0.25 to 10m. -FORCE_DIRECT_PATH Used with llNavigateTo(). Makes character navigate in a straight line toward pos. May be set to TRUE or FALSE. -VERTICAL Constant to indicate that the orientation of the capsule for a Pathfinding character is vertical. -HORIZONTAL Constant to indicate that the orientation of the capsule for a Pathfinding character is horizontal. -AVOID_CHARACTERS TODO: add documentation -AVOID_DYNAMIC_OBSTACLES TODO: add documentation -AVOID_NONE TODO: add documentation +RC_DATA_FLAGS Option for llCastRay() followed with a bitwise combination of RC_GET_NORMAL, RC_GET_ROOT_KEY and RC_GET_LINK_NUM. +RC_DETECT_PHANTOM Option for llCastRay() followed with TRUE to detect phantom AND volume detect objects, FASLE otherwise. +RC_GET_LINK_NUM Flag used in the RC_DATA_FLAGS mask to get link numbers in llCastRay() results. +RC_GET_NORMAL Flag used in the RC_DATA_FLAGS mask to get hit normals in llCastRay() results. +RC_GET_ROOT_KEY Flag used in the RC_DATA_FLAGS mask to get root keys in llCastRay() results. +RC_MAX_HITS Option for llCastRay() followed with an integer specifying the maximum number of hits to return (must be <= 256). +RC_REJECT_TYPES Option for llCastRay() used to ignore specific types of objects, followed with a bitwise combination of RC_REJECT_AGENTS, RC_REJECT_PHYSICAL, RC_REJECT_NONPHYSICAL and RC_REJECT_LAND. +RC_REJECT_AGENTS Flag used in the RC_REJECT_TYPES mask to reject agents in llCastRay(). +RC_REJECT_PHYSICAL Flag used in the RC_REJECT_TYPES mask to reject physical objects in llCastRay(). +RC_REJECT_NONPHYSICAL Flag used in the RC_REJECT_TYPES mask to reject non-physical objects in llCastRay(). +RC_REJECT_LAND Flag used in the RC_REJECT_TYPES mask to reject land in llCastRay(). + +RCERR_CAST_TIME_EXCEEDED Returned by llCastRay() when the raycast failed because the parcel or agent has exceeded the maximum time allowed for raycasting. +RCERR_SIM_PERF_LOW Returned by llCastRay() when the raycast failed because simulator performance is low. +RCERR_UNKNOWN Returned by llCastRay() when the raycast failed for an unspecified reason. + +ESTATE_ACCESS_ALLOWED_AGENT_ADD Used with llManageEstateAccess to add an agent to this estate's allowed residents list. +ESTATE_ACCESS_ALLOWED_AGENT_REMOVE Used with llManageEstateAccess to remove an agent from this estate's allowed residents list. +ESTATE_ACCESS_ALLOWED_GROUP_ADD Used with llManageEstateAccess to add a group to this estate's allowed groups list. +ESTATE_ACCESS_ALLOWED_GROUP_REMOVE Used with llManageEstateAccess to remove a group from this estate's allowed groups list. +ESTATE_ACCESS_BANNED_AGENT_ADD Used with llManageEstateAccess to add an agent to this estate's banned residents list. +ESTATE_ACCESS_BANNED_AGENT_REMOVE Used with llManageEstateAccess to remove an agent from this estate's banned residents list. + +DENSITY For use with llSetPhysicsMaterial() as a bitwise value in its material_bits parameter, to set the density. +FRICTION For use with llSetPhysicsMaterial() as a bitwise value in its material_bits parameter, to set the friction. +RESTITUTION For use with llSetPhysicsMaterial() as a bitwise value in its material_bits parameter, to set the restitution. +GRAVITY_MULTIPLIER For use with llSetPhysicsMaterial() as a bitwise value in its material_bits parameter, to set the gravity multiplier. + +SIM_STAT_PCT_CHARS_STEPPED Option for llGetSimStats() to return the % of pathfinding characters skipped each frame, averaged over the last minute. + +KFM_COMMAND Option for llSetKeyframedMotion(), followed by one of KFM_CMD_STOP, KFM_CMD_PLAY, KFM_CMD_PAUSE. Note that KFM_COMMAND must be the only option in the list, and cannot be specified in the same function call that sets the keyframes list. +KFM_CMD_PLAY Option for llSetKeyframedMotion(), used after KFM_COMMAND to play the motion. +KFM_CMD_STOP Option for llSetKeyframedMotion(), used after KFM_COMMAND to stop the motion. +KFM_CMD_PAUSE Option for llSetKeyframedMotion(), used after KFM_COMMAND to pause the motion. +KFM_MODE Option for llSetKeyframedMotion(), used to specify the playback mode, followed by one of KFM_FORWARD, KFM_LOOP, KFM_PING_PONG or KFM_REVERSE. +KFM_FORWARD Option for llSetKeyframedMotion(), used after KFM_MODE to specify the forward playback mode. +KFM_LOOP Option for llSetKeyframedMotion(), used after KFM_MODE to specify the loop playback mode. +KFM_PING_PONG Option for llSetKeyframedMotion(), used after KFM_MODE to specify the ping pong playback mode. +KFM_REVERSE Option for llSetKeyframedMotion(), used after KFM_MODE to specify the reverse playback mode. +KFM_DATA Option for llSetKeyframedMotion(), followed by a bitwise combination of KFM_TRANSLATION and KFM_ROTATION. If you specify one or the other, you should only include translations or rotations in your keyframe list. +KFM_ROTATION Option for llSetKeyframedMotion(), used after KFM_DATA, possibly as a bitwise combination with KFM_TRANSLATION. +KFM_TRANSLATION Option for llSetKeyframedMotion(), used after KFM_DATA, possibly as a bitwise combination with KFM_ROTATION. + +CHARACTER_CMD_STOP Used with llExecCharacterCmd(). Makes the character jump. +CHARACTER_CMD_SMOOTH_STOP Used with llExecCharacterCmd(). Stops any current pathfinding operation in a smooth like fashion. +CHARACTER_CMD_JUMP Used with llExecCharacterCmd(). Stops any current pathfinding operation. + +CHARACTER_DESIRED_SPEED Speed of pursuit in meters per second. +CHARACTER_RADIUS Set collision capsule radius. +CHARACTER_LENGTH Set collision capsule length. +CHARACTER_ORIENTATION Set the character orientation. +CHARACTER_AVOIDANCE_MODE Allows you to specify that a character should not try to avoid other characters, should not try to avoid dynamic obstacles (relatively fast moving objects and avatars), or both. +CHARACTER_ACCOUNT_FOR_SKIPPED_FRAMES Defines if a character will attempt to catch up lost time if pathfinding performance is low. +PURSUIT_OFFSET Used with llPursue(). Go to a position offset from the target. +REQUIRE_LINE_OF_SIGHT Used with llPursue(). Define whether the character needs a physical line-of-sight to give chase. When enabled, the character will not pick a new target position while there is a something solid between the character and the target object/agent. +PURSUIT_FUZZ_FACTOR Used with llPursue(). Selects a random destination near the PURSUIT_OFFSET. The valid fuzz factor range is from 0 to 1, where 1 is most random. This option requires a nonzero PURSUIT_OFFSET. +PURSUIT_INTERCEPT Used with llPursue(). Define whether the character attempts to predict the target's future location. +PURSUIT_GOAL_TOLERANCE Used with llPursue(). Defines approximately how close the character must be to the current goal to consider itself to be at the desired position. The valid range is from 0.25 to 10m. +FORCE_DIRECT_PATH Used with llNavigateTo(). Makes character navigate in a straight line toward pos. May be set to TRUE or FALSE. +VERTICAL Constant to indicate that the orientation of the capsule for a Pathfinding character is vertical. +HORIZONTAL Constant to indicate that the orientation of the capsule for a Pathfinding character is horizontal. +AVOID_CHARACTERS TODO: add documentation +AVOID_DYNAMIC_OBSTACLES TODO: add documentation +AVOID_NONE TODO: add documentation PU_EVADE_HIDDEN Triggered when an llEvade character thinks it has hidden from its pursuer. PU_EVADE_SPOTTED Triggered when an llEvade character switches from hiding to running PU_FAILURE_INVALID_GOAL Goal is not on the navigation-mesh and cannot be reached. PU_FAILURE_INVALID_START Character cannot navigate from the current location - e.g., the character is off the navmesh or too high above it. PU_FAILURE_NO_VALID_DESTINATION There's no good place for the character to go - e.g., it is patrolling and all the patrol points are now unreachable. -PU_FAILURE_OTHER Unknown failure +PU_FAILURE_OTHER Unknown failure PU_FAILURE_TARGET_GONE Target (for llPursue or llEvade) can no longer be tracked - e.g., it left the region or is an avatar that is now more than about 30m outside the region. PU_FAILURE_UNREACHABLE Goal is no longer reachable for some reason - e.g., an obstacle blocks the path. PU_GOAL_REACHED Character has reached the goal and will stop or choose a new goal (if wandering). @@ -720,56 +754,56 @@ PU_FAILURE_NO_NAVMESH Triggered if no navmesh is available for the re PU_FAILURE_DYNAMIC_PATHFINDING_DISABLED Triggered when a character enters a region with dynamic pathfinding disabled. PU_FAILURE_PARCEL_UNREACHABLE Triggered when a character failed to enter a parcel because it is not allowed to enter, e.g. because the parcel is already full or because object entry was disabled after the navmesh was baked. -CHARACTER_TYPE Specifies which walkability coefficient will be used by this character. -CHARACTER_TYPE_A Used for character types that you prefer move in a way consistent with humanoids. -CHARACTER_TYPE_B Used for character types that you prefer move in a way consistent with wild animals or off road vehicles. -CHARACTER_TYPE_C Used for mechanical character types or road going vehicles. -CHARACTER_TYPE_D Used for character types that are not consistent with the A, B, or C type. -CHARACTER_TYPE_NONE Used to set no specific character type. - -TRAVERSAL_TYPE Controls the speed at which characters moves on terrain that is less than 100% walkable will move faster (e.g., a cat crossing a street) or slower (e.g., a car driving in a swamp). -TRAVERSAL_TYPE_SLOW TODO: add documentation -TRAVERSAL_TYPE_FAST TODO: add documentation -TRAVERSAL_TYPE_NONE TODO: add documentation - -CHARACTER_MAX_ACCEL The character's maximum acceleration rate. -CHARACTER_MAX_DECEL The character's maximum deceleration rate. -CHARACTER_MAX_ANGULAR_SPEED TODO: add documentation -CHARACTER_MAX_ANGULAR_ACCEL TODO: add documentation -CHARACTER_TURN_SPEED_MULTIPLIER TODO: add documentation -CHARACTER_DESIRED_TURN_SPEED The character's maximum speed while turning--note that this is only loosely enforced (i.e., a character may turn at higher speeds under certain conditions) -CHARACTER_MAX_TURN_RADIUS The character's turn radius when traveling at CHARACTER_DESIRED_TURN_SPEED. -CHARACTER_MAX_SPEED The character's maximum speed. Affects speed when avoiding dynamic obstacles and when traversing low-walkability objects in TRAVERSAL_TYPE_FAST mode. -CHARACTER_STAY_WITHIN_PARCEL Characters which have CHARACTER_STAY_WITHIN_PARCEL set to TRUE treat the parcel boundaries as one-way obstacles. - -PATROL_PAUSE_AT_WAYPOINTS Used with llPatrolPoints(). Defines if characters slow down and momentarily pause at each waypoint. -WANDER_PAUSE_AT_WAYPOINTS Used with llWanderWithin(). Defines if characters should pause after reaching each wander waypoint. - -CONTENT_TYPE_TEXT text/plain -CONTENT_TYPE_HTML text/html -CONTENT_TYPE_XML application/xml -CONTENT_TYPE_XHTML application/xhtml+xml -CONTENT_TYPE_ATOM application/atom+xml -CONTENT_TYPE_JSON application/json -CONTENT_TYPE_LLSD application/llsd+xml -CONTENT_TYPE_FORM application/x-www-form-urlencoded -CONTENT_TYPE_RSS application/rss+xml - -JSON_INVALID Returned by llJsonGetValue and llJsonValueType if the specifiers to do specify a valid in the json value. -JSON_OBJECT Represents a json datatype represented in LSL as a strided list of name/value pairs -JSON_ARRAY Represents a json datatype mappable to the LSL datatype "list" -JSON_NUMBER Represents a json datatype mappable to the LSL datatypes "integer" and "float" -JSON_STRING Represents a json datatype mappable to the LSL datatype "string" -JSON_TRUE Represents the constant "true" of a json value. -JSON_FALSE Represents the constant "false" of a json value. -JSON_NULL Represents the constant "null" of a json value. -JSON_APPEND Used with llJsonSetValue as a specifier to indicate appending the value to the end of the array at that level. - -ERR_GENERIC Returned by llReturnObjectsByID and llReturnObjectsByOwner in case of a general error. -ERR_PARCEL_PERMISSIONS Returned by llReturnObjectsByID and llReturnObjectsByOwner in case of a parcel owner permission error. -ERR_MALFORMED_PARAMS Returned by llReturnObjectsByID and llReturnObjectsByOwner in case of malformed parameters. -ERR_RUNTIME_PERMISSIONS Returned by llReturnObjectsByID and llReturnObjectsByOwner in case of a runtime permission error. -ERR_THROTTLED Returned by llReturnObjectsByID and llReturnObjectsByOwner in case of being throttled. +CHARACTER_TYPE Specifies which walkability coefficient will be used by this character. +CHARACTER_TYPE_A Used for character types that you prefer move in a way consistent with humanoids. +CHARACTER_TYPE_B Used for character types that you prefer move in a way consistent with wild animals or off road vehicles. +CHARACTER_TYPE_C Used for mechanical character types or road going vehicles. +CHARACTER_TYPE_D Used for character types that are not consistent with the A, B, or C type. +CHARACTER_TYPE_NONE Used to set no specific character type. + +TRAVERSAL_TYPE Controls the speed at which characters moves on terrain that is less than 100% walkable will move faster (e.g., a cat crossing a street) or slower (e.g., a car driving in a swamp). +TRAVERSAL_TYPE_SLOW TODO: add documentation +TRAVERSAL_TYPE_FAST TODO: add documentation +TRAVERSAL_TYPE_NONE TODO: add documentation + +CHARACTER_MAX_ACCEL The character's maximum acceleration rate. +CHARACTER_MAX_DECEL The character's maximum deceleration rate. +CHARACTER_MAX_ANGULAR_SPEED TODO: add documentation +CHARACTER_MAX_ANGULAR_ACCEL TODO: add documentation +CHARACTER_TURN_SPEED_MULTIPLIER TODO: add documentation +CHARACTER_DESIRED_TURN_SPEED The character's maximum speed while turning--note that this is only loosely enforced (i.e., a character may turn at higher speeds under certain conditions) +CHARACTER_MAX_TURN_RADIUS The character's turn radius when traveling at CHARACTER_DESIRED_TURN_SPEED. +CHARACTER_MAX_SPEED The character's maximum speed. Affects speed when avoiding dynamic obstacles and when traversing low-walkability objects in TRAVERSAL_TYPE_FAST mode. +CHARACTER_STAY_WITHIN_PARCEL Characters which have CHARACTER_STAY_WITHIN_PARCEL set to TRUE treat the parcel boundaries as one-way obstacles. + +PATROL_PAUSE_AT_WAYPOINTS Used with llPatrolPoints(). Defines if characters slow down and momentarily pause at each waypoint. +WANDER_PAUSE_AT_WAYPOINTS Used with llWanderWithin(). Defines if characters should pause after reaching each wander waypoint. + +CONTENT_TYPE_TEXT text/plain +CONTENT_TYPE_HTML text/html +CONTENT_TYPE_XML application/xml +CONTENT_TYPE_XHTML application/xhtml+xml +CONTENT_TYPE_ATOM application/atom+xml +CONTENT_TYPE_JSON application/json +CONTENT_TYPE_LLSD application/llsd+xml +CONTENT_TYPE_FORM application/x-www-form-urlencoded +CONTENT_TYPE_RSS application/rss+xml + +JSON_INVALID Returned by llJsonGetValue and llJsonValueType if the specifiers to do specify a valid in the json value. +JSON_OBJECT Represents a json datatype represented in LSL as a strided list of name/value pairs +JSON_ARRAY Represents a json datatype mappable to the LSL datatype "list" +JSON_NUMBER Represents a json datatype mappable to the LSL datatypes "integer" and "float" +JSON_STRING Represents a json datatype mappable to the LSL datatype "string" +JSON_TRUE Represents the constant "true" of a json value. +JSON_FALSE Represents the constant "false" of a json value. +JSON_NULL Represents the constant "null" of a json value. +JSON_APPEND Used with llJsonSetValue as a specifier to indicate appending the value to the end of the array at that level. + +ERR_GENERIC Returned by llReturnObjectsByID and llReturnObjectsByOwner in case of a general error. +ERR_PARCEL_PERMISSIONS Returned by llReturnObjectsByID and llReturnObjectsByOwner in case of a parcel owner permission error. +ERR_MALFORMED_PARAMS Returned by llReturnObjectsByID and llReturnObjectsByOwner in case of malformed parameters. +ERR_RUNTIME_PERMISSIONS Returned by llReturnObjectsByID and llReturnObjectsByOwner in case of a runtime permission error. +ERR_THROTTLED Returned by llReturnObjectsByID and llReturnObjectsByOwner in case of being throttled. # --- OpenSim and Aurora-Sim constants Below --- # OpenSim Constants (\OpenSim\Region\ScriptEngine\Shared\Api\Runtime\LSL_Constants.cs) @@ -793,26 +827,26 @@ OS_ATTACH_MSG_SCRIPT_CREATOR Used with osMessageAttachements PARCEL_DETAILS_CLAIMDATE Used with osSetParcelDetails # osGetRegionStats STATS_TIME_DILATION returned value from osGetRegionStats(), 1st of 21 items in returned list. -STATS_SIM_FPS returned value from osGetRegionStats(), 2nd of 21 items in returned list. -STATS_PHYSICS_FPS returned value from osGetRegionStats(), 3rd of 21 items in returned list. +STATS_SIM_FPS returned value from osGetRegionStats(), 2nd of 21 items in returned list. +STATS_PHYSICS_FPS returned value from osGetRegionStats(), 3rd of 21 items in returned list. STATS_AGENT_UPDATES returned value from osGetRegionStats(), 4th of 21 items in returned list. -STATS_ROOT_AGENTS returned value from osGetRegionStats(), 5th of 21 items in returned list. -STATS_CHILD_AGENTS returned value from osGetRegionStats(), 6th of 21 items in returned list. -STATS_TOTAL_PRIMS returned value from osGetRegionStats(), 7th of 21 items in returned list. -STATS_ACTIVE_PRIMS returned value from osGetRegionStats(), 8th of 21 items in returned list. +STATS_ROOT_AGENTS returned value from osGetRegionStats(), 5th of 21 items in returned list. +STATS_CHILD_AGENTS returned value from osGetRegionStats(), 6th of 21 items in returned list. +STATS_TOTAL_PRIMS returned value from osGetRegionStats(), 7th of 21 items in returned list. +STATS_ACTIVE_PRIMS returned value from osGetRegionStats(), 8th of 21 items in returned list. STATS_FRAME_MS returned value from osGetRegionStats(), 9th of 21 items in returned list. STATS_NET_MS returned value from osGetRegionStats(), 10th of 21 items in returned list. -STATS_PHYSICS_MS returned value from osGetRegionStats(), 11th of 21 items in returned list. +STATS_PHYSICS_MS returned value from osGetRegionStats(), 11th of 21 items in returned list. STATS_IMAGE_MS returned value from osGetRegionStats(), 12th of 21 items in returned list. STATS_OTHER_MS returned value from osGetRegionStats(), 13th of 21 items in returned list. STATS_IN_PACKETS_PER_SECOND returned value from osGetRegionStats(), 14th of 21 items in returned list. STATS_OUT_PACKETS_PER_SECOND returned value from osGetRegionStats(), 15th of 21 items in returned list. STATS_UNACKED_BYTES returned value from osGetRegionStats(), 16th of 21 items in returned list. -STATS_AGENT_MS returned value from osGetRegionStats(), 17th of 21 items in returned list. +STATS_AGENT_MS returned value from osGetRegionStats(), 17th of 21 items in returned list. STATS_PENDING_DOWNLOADS returned value from osGetRegionStats(), 18th of 21 items in returned list. STATS_PENDING_UPLOADS returned value from osGetRegionStats(), 19th of 21 items in returned list. -STATS_ACTIVE_SCRIPTS returned value from osGetRegionStats(), 20th of 21 items in returned list. -STATS_SCRIPT_LPS returned value from osGetRegionStats(), 21st of 21 items in returned list. +STATS_ACTIVE_SCRIPTS returned value from osGetRegionStats(), 20th of 21 items in returned list. +STATS_SCRIPT_LPS returned value from osGetRegionStats(), 21st of 21 items in returned list. # OpenSim NPC OS_NPC used by osNPC. Value 0x01000000 OS_NPC_FLY used by osNPC. Value 0 @@ -824,43 +858,43 @@ OS_NPC_NOT_OWNED used by osNPC. Value 0x2 OS_NPC_SENSE_AS_AGENT used by osNPC. Value 0x4 OS_NPC_RUNNING used by osNPC. Value 4 # Windlight/Lightshare -WL_WATER_COLOR Windlight Water Colour -WL_WATER_FOG_DENSITY_EXPONENT Windlight Water Fog Density Exponent -WL_UNDERWATER_FOG_MODIFIER Windlight Underwater Fog Modifier -WL_REFLECTION_WAVELET_SCALE Windlight Reflection Wavelet Scale -WL_FRESNEL_SCALE Windlight Fresnel Scale -WL_FRESNEL_OFFSET Windlight Fresnel Offset -WL_REFRACT_SCALE_ABOVE Windlight Refract Scale Above -WL_REFRACT_SCALE_BELOW Windlight Refract Scale Below -WL_BLUR_MULTIPLIER Windlight Blur Multiplier -WL_BIG_WAVE_DIRECTION Windlight Big Wave Direction -WL_LITTLE_WAVE_DIRECTION Windlight Little Wave Direction -WL_NORMAL_MAP_TEXTURE Windlight Normal Map Texture -WL_HORIZON Windlight Horizon Colour -WL_HAZE_HORIZON Windlight Haze Horizon -WL_BLUE_DENSITY Windlight Blue Density -WL_HAZE_DENSITY Windlight Haze Density -WL_DENSITY_MULTIPLIER Windlight Density Multiplier -WL_DISTANCE_MULTIPLIER Windlight Distance Multiplier -WL_MAX_ALTITUDE Windlight Max Altitude -WL_SUN_MOON_COLOR Windlight Sun/Moon Colour -WL_SUN_MOON_POSITION Windlight Sun/Moon Position -WL_AMBIENT Windlight Ambient Colour -WL_EAST_ANGLE Windlight Sun/Position East -WL_SUN_GLOW_FOCUS Windlight Sun Glow Focus -WL_SUN_GLOW_SIZE Windlight Sun Glow Size -WL_SCENE_GAMMA Windlight Scene Gamma -WL_STAR_BRIGHTNESS Windlight Star Brightness -WL_CLOUD_COLOR Windlight Cloud Colour -WL_CLOUD_XY_DENSITY Windlight Cloud X/Y/Density -WL_CLOUD_COVERAGE Windlight Cloud Coverage -WL_CLOUD_SCALE Windlight Cloud Scale -WL_CLOUD_DETAIL_XY_DENSITY Windlight Cloud Detail X/Y/Density -WL_CLOUD_SCROLL_X Windlight Cloud Scroll X -WL_CLOUD_SCROLL_Y Windlight Cloud Scroll Y -WL_CLOUD_SCROLL_Y_LOCK Windlight Cloud Scroll Y Lock -WL_CLOUD_SCROLL_X_LOCK Windlight Cloud Scroll X Lock -WL_DRAW_CLASSIC_CLOUDS Windlight Draw Classic Clouds +WL_WATER_COLOR Windlight Water Colour +WL_WATER_FOG_DENSITY_EXPONENT Windlight Water Fog Density Exponent +WL_UNDERWATER_FOG_MODIFIER Windlight Underwater Fog Modifier +WL_REFLECTION_WAVELET_SCALE Windlight Reflection Wavelet Scale +WL_FRESNEL_SCALE Windlight Fresnel Scale +WL_FRESNEL_OFFSET Windlight Fresnel Offset +WL_REFRACT_SCALE_ABOVE Windlight Refract Scale Above +WL_REFRACT_SCALE_BELOW Windlight Refract Scale Below +WL_BLUR_MULTIPLIER Windlight Blur Multiplier +WL_BIG_WAVE_DIRECTION Windlight Big Wave Direction +WL_LITTLE_WAVE_DIRECTION Windlight Little Wave Direction +WL_NORMAL_MAP_TEXTURE Windlight Normal Map Texture +WL_HORIZON Windlight Horizon Colour +WL_HAZE_HORIZON Windlight Haze Horizon +WL_BLUE_DENSITY Windlight Blue Density +WL_HAZE_DENSITY Windlight Haze Density +WL_DENSITY_MULTIPLIER Windlight Density Multiplier +WL_DISTANCE_MULTIPLIER Windlight Distance Multiplier +WL_MAX_ALTITUDE Windlight Max Altitude +WL_SUN_MOON_COLOR Windlight Sun/Moon Colour +WL_SUN_MOON_POSITION Windlight Sun/Moon Position +WL_AMBIENT Windlight Ambient Colour +WL_EAST_ANGLE Windlight Sun/Position East +WL_SUN_GLOW_FOCUS Windlight Sun Glow Focus +WL_SUN_GLOW_SIZE Windlight Sun Glow Size +WL_SCENE_GAMMA Windlight Scene Gamma +WL_STAR_BRIGHTNESS Windlight Star Brightness +WL_CLOUD_COLOR Windlight Cloud Colour +WL_CLOUD_XY_DENSITY Windlight Cloud X/Y/Density +WL_CLOUD_COVERAGE Windlight Cloud Coverage +WL_CLOUD_SCALE Windlight Cloud Scale +WL_CLOUD_DETAIL_XY_DENSITY Windlight Cloud Detail X/Y/Density +WL_CLOUD_SCROLL_X Windlight Cloud Scroll X +WL_CLOUD_SCROLL_Y Windlight Cloud Scroll Y +WL_CLOUD_SCROLL_Y_LOCK Windlight Cloud Scroll Y Lock +WL_CLOUD_SCROLL_X_LOCK Windlight Cloud Scroll X Lock +WL_DRAW_CLASSIC_CLOUDS Windlight Draw Classic Clouds # WL Constants added unique to Aurora-Sim WL_OK Value -1 WL_ERROR Value -2 @@ -874,74 +908,93 @@ ENABLE_GRAVITY enable_gravity. GRAVITY_FORCE_X gravity_force_x. GRAVITY_FORCE_Y gravity_force_y. GRAVITY_FORCE_Z gravity_force_z. -ADD_GRAVITY_POINT add_gravity_point. -ADD_GRAVITY_FORCE add_gravity_force. -START_TIME_REVERSAL_SAVING start_time_reversal_saving. -STOP_TIME_REVERSAL_SAVING stop_time_reversal_saving. -START_TIME_REVERSAL start_time_reversal. -STOP_TIME_REVERSAL stop_time_reversal. +ADD_GRAVITY_POINT add_gravity_point. +ADD_GRAVITY_FORCE add_gravity_force. +START_TIME_REVERSAL_SAVING start_time_reversal_saving. +STOP_TIME_REVERSAL_SAVING stop_time_reversal_saving. +START_TIME_REVERSAL start_time_reversal. +STOP_TIME_REVERSAL stop_time_reversal. # Aurora botFunctions -BOT_FOLLOW_FLAG_NONE value 0. +BOT_FOLLOW_FLAG_NONE value 0. BOT_FOLLOW_FLAG_INDEFINITELY value 1. -BOT_TAG_FIND_ALL value AllBots. +BOT_TAG_FIND_ALL value AllBots. BOT_FOLLOW_WALK value 0. BOT_FOLLOW_RUN value 1. BOT_FOLLOW_FLY value 2. -BOT_FOLLOW_TELEPORT value 3. +BOT_FOLLOW_TELEPORT value 3. BOT_FOLLOW_WAIT value 4. -BOT_FOLLOW_TRIGGER_HERE_EVENT value 1. +BOT_FOLLOW_TRIGGER_HERE_EVENT value 1. BOT_FOLLOW_FLAG_FORCEDIRECTPATH value 4. # string constants [word .679, .503, .996] -NULL_KEY Indicates an empty key -EOF Indicates the last line of a notecard was read -TEXTURE_BLANK UUID for the "Blank" texture -TEXTURE_DEFAULT Alias for TEXTURE_PLYWOOD -TEXTURE_MEDIA UUID for the "Default Media" texture -TEXTURE_PLYWOOD UUID for the default "Plywood" texture -TEXTURE_TRANSPARENT UUID for the "White - Transparent" texture +NULL_KEY Indicates an empty key +EOF Indicates the last line of a notecard was read +TEXTURE_BLANK UUID for the "Blank" texture +TEXTURE_DEFAULT Alias for TEXTURE_PLYWOOD +TEXTURE_MEDIA UUID for the "Default Media" texture +TEXTURE_PLYWOOD UUID for the default "Plywood" texture +TEXTURE_TRANSPARENT UUID for the "White - Transparent" texture + +URL_REQUEST_GRANTED Used with http_request when a public URL is successfully granted +URL_REQUEST_DENIED Used with http_request when a public URL is not available + +XP_ERROR_NONE No error was detected +XP_ERROR_THROTTLED The call failed due to too many recent calls. +XP_ERROR_EXPERIENCES_DISABLED The region currently has experiences disabled. +XP_ERROR_INVALID_PARAMETERS One of the string arguments was too big to fit in the key-value store. +XP_ERROR_NOT_PERMITTED This experience is not allowed to run on the current region. +XP_ERROR_NO_EXPERIENCE This script is not associated with an experience. +XP_ERROR_NOT_FOUND The sim was unable to verify the validity of the experience. Retrying after a short wait is advised. +XP_ERROR_INVALID_EXPERIENCE The script is associated with an experience that no longer exists. +XP_ERROR_EXPERIENCE_DISABLED The experience owner has temporarily disabled the experience. +XP_ERROR_EXPERIENCE_SUSPENDED The experience has been suspended by Linden Customer Support. +XP_ERROR_QUOTA_EXCEEDED An attempted write data to the key-value store failed due to the data quota being met. +XP_ERROR_STORE_DISABLED The key-value store is currently disabled on this region. +XP_ERROR_STORAGE_EXCEPTION Unable to communicate with the key-value store. +XP_ERROR_KEY_NOT_FOUND The requested key does not exist. +XP_ERROR_RETRY_UPDATE A checked update failed due to an out of date request. +XP_ERROR_MATURITY_EXCEEDED The request failed due to agent content preferences. +XP_ERROR_UNKNOWN_ERROR Other unknown error. -URL_REQUEST_GRANTED Used with http_request when a public URL is successfully granted -URL_REQUEST_DENIED Used with http_request when a public URL is not available # float constants [word .679, .503, .996] -PI 3.1415926535897932384626433832795 -TWO_PI 6.283185307179586476925286766559 -PI_BY_TWO 1.5707963267948966192313216916398 -DEG_TO_RAD To convert from degrees to radians -RAD_TO_DEG To convert from radians to degrees -SQRT2 1.4142135623730950488016887242097 +PI 3.1415926535897932384626433832795 +TWO_PI 6.283185307179586476925286766559 +PI_BY_TWO 1.5707963267948966192313216916398 +DEG_TO_RAD To convert from degrees to radians +RAD_TO_DEG To convert from radians to degrees +SQRT2 1.4142135623730950488016887242097 # compound constants [word .679, .503, .996] -ZERO_VECTOR <0.0, 0.0, 0.0> -ZERO_ROTATION <0.0, 0.0, 0.0, 1.0> +ZERO_VECTOR <0.0, 0.0, 0.0> +ZERO_ROTATION <0.0, 0.0, 0.0, 1.0> # flow control keywords [word .972, .148, .445] -for for loop:for (initializer; test; iteration):{: statements:} -do do loop:do:{: statements:} while (test); -while while loop:while (test):{ statements:} -if if statement:if (test):{ statements:} -else else clause:if (test):{ statements:}:else:{ statements:} -jump jump statement:jump label;: -return Leave current function or event handler +for for loop:for (initializer; test; iteration):{: statements:} +do do loop:do:{: statements:} while (test); +while while loop:while (test):{ statements:} +if if statement:if (test):{ statements:} +else else clause:if (test):{ statements:}:else:{ statements:} +jump jump statement:jump label;: +return Leave current function or event handler # flow control label [line .972, .148, .445] -@ Label:Target for jump statement +@ Label:Target for jump statement # Comment [one_sided_delimiter .457, .441, .367] -// Comment:Non-functional commentary or disabled code +// Comment:Non-functional commentary or disabled code [two_sided_delimiter .457, .441, .367] -/* */ Comment:Non-functional commentary or disabled code +/* */ Comment:Non-functional commentary or disabled code # String literals [double_quotation_marks .989, .855, .453] -" String literal +" String literal #functions are supplied by the program now diff --git a/indra/newview/skins/apollo/textures/account_id_green.tga b/indra/newview/skins/apollo/textures/account_id_green.tga deleted file mode 100644 index 9be215eed4..0000000000 Binary files a/indra/newview/skins/apollo/textures/account_id_green.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/account_id_orange.tga b/indra/newview/skins/apollo/textures/account_id_orange.tga deleted file mode 100644 index 6b41e86632..0000000000 Binary files a/indra/newview/skins/apollo/textures/account_id_orange.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/active_speakers.tga b/indra/newview/skins/apollo/textures/active_speakers.tga deleted file mode 100644 index 02d3643d7f..0000000000 Binary files a/indra/newview/skins/apollo/textures/active_speakers.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/active_voice_tab.tga b/indra/newview/skins/apollo/textures/active_voice_tab.tga deleted file mode 100644 index 2d0dfaabc5..0000000000 Binary files a/indra/newview/skins/apollo/textures/active_voice_tab.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/alpha_gradient.tga b/indra/newview/skins/apollo/textures/alpha_gradient.tga deleted file mode 100644 index 6fdba25d4e..0000000000 Binary files a/indra/newview/skins/apollo/textures/alpha_gradient.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/arrow_down.tga b/indra/newview/skins/apollo/textures/arrow_down.tga deleted file mode 100644 index 81dc9d3b6c..0000000000 Binary files a/indra/newview/skins/apollo/textures/arrow_down.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/arrow_up.tga b/indra/newview/skins/apollo/textures/arrow_up.tga deleted file mode 100644 index 22195cf7fb..0000000000 Binary files a/indra/newview/skins/apollo/textures/arrow_up.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/avatar_gone.tga b/indra/newview/skins/apollo/textures/avatar_gone.tga deleted file mode 100644 index e5c2c070bc..0000000000 Binary files a/indra/newview/skins/apollo/textures/avatar_gone.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/avatar_new.tga b/indra/newview/skins/apollo/textures/avatar_new.tga deleted file mode 100644 index 854b70c326..0000000000 Binary files a/indra/newview/skins/apollo/textures/avatar_new.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/avatar_typing.tga b/indra/newview/skins/apollo/textures/avatar_typing.tga deleted file mode 100644 index 2c549025dd..0000000000 Binary files a/indra/newview/skins/apollo/textures/avatar_typing.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/button_anim_pause_disabled.tga b/indra/newview/skins/apollo/textures/button_anim_pause_disabled.tga deleted file mode 100644 index 4d604c63c3..0000000000 Binary files a/indra/newview/skins/apollo/textures/button_anim_pause_disabled.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/button_anim_play_disabled.tga b/indra/newview/skins/apollo/textures/button_anim_play_disabled.tga deleted file mode 100644 index 444062f375..0000000000 Binary files a/indra/newview/skins/apollo/textures/button_anim_play_disabled.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/button_anim_stop_disabled.tga b/indra/newview/skins/apollo/textures/button_anim_stop_disabled.tga deleted file mode 100644 index cf1532a426..0000000000 Binary files a/indra/newview/skins/apollo/textures/button_anim_stop_disabled.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/checkerboard_transparency_bg.png b/indra/newview/skins/apollo/textures/checkerboard_transparency_bg.png deleted file mode 100644 index 9a16935204..0000000000 Binary files a/indra/newview/skins/apollo/textures/checkerboard_transparency_bg.png and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/circle.tga b/indra/newview/skins/apollo/textures/circle.tga deleted file mode 100644 index d7097e3a35..0000000000 Binary files a/indra/newview/skins/apollo/textures/circle.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/color_swatch_alpha.tga b/indra/newview/skins/apollo/textures/color_swatch_alpha.tga deleted file mode 100644 index 814a004e62..0000000000 Binary files a/indra/newview/skins/apollo/textures/color_swatch_alpha.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/crosshairs.tga b/indra/newview/skins/apollo/textures/crosshairs.tga deleted file mode 100644 index ac4d63dc59..0000000000 Binary files a/indra/newview/skins/apollo/textures/crosshairs.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/down_arrow.png b/indra/newview/skins/apollo/textures/down_arrow.png deleted file mode 100644 index 155f80c97e..0000000000 Binary files a/indra/newview/skins/apollo/textures/down_arrow.png and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/ff_edit_mine.tga b/indra/newview/skins/apollo/textures/ff_edit_mine.tga deleted file mode 100644 index 8f0c35b98f..0000000000 Binary files a/indra/newview/skins/apollo/textures/ff_edit_mine.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/ff_edit_theirs.tga b/indra/newview/skins/apollo/textures/ff_edit_theirs.tga deleted file mode 100644 index 005ada2dea..0000000000 Binary files a/indra/newview/skins/apollo/textures/ff_edit_theirs.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/ff_visible_map.tga b/indra/newview/skins/apollo/textures/ff_visible_map.tga deleted file mode 100644 index a4dad78dad..0000000000 Binary files a/indra/newview/skins/apollo/textures/ff_visible_map.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/ff_visible_online.tga b/indra/newview/skins/apollo/textures/ff_visible_online.tga deleted file mode 100644 index 74e3a4e318..0000000000 Binary files a/indra/newview/skins/apollo/textures/ff_visible_online.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/icn_active-speakers-dot-lvl0.tga b/indra/newview/skins/apollo/textures/icn_active-speakers-dot-lvl0.tga deleted file mode 100644 index 35846cef32..0000000000 Binary files a/indra/newview/skins/apollo/textures/icn_active-speakers-dot-lvl0.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/icn_active-speakers-dot-lvl1.tga b/indra/newview/skins/apollo/textures/icn_active-speakers-dot-lvl1.tga deleted file mode 100644 index 1f9f564fa9..0000000000 Binary files a/indra/newview/skins/apollo/textures/icn_active-speakers-dot-lvl1.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/icn_active-speakers-dot-lvl2.tga b/indra/newview/skins/apollo/textures/icn_active-speakers-dot-lvl2.tga deleted file mode 100644 index b2e5609f1f..0000000000 Binary files a/indra/newview/skins/apollo/textures/icn_active-speakers-dot-lvl2.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/icn_active-speakers-typing1.tga b/indra/newview/skins/apollo/textures/icn_active-speakers-typing1.tga deleted file mode 100644 index 3706c96e0f..0000000000 Binary files a/indra/newview/skins/apollo/textures/icn_active-speakers-typing1.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/icn_active-speakers-typing2.tga b/indra/newview/skins/apollo/textures/icn_active-speakers-typing2.tga deleted file mode 100644 index 0d127f9461..0000000000 Binary files a/indra/newview/skins/apollo/textures/icn_active-speakers-typing2.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/icn_active-speakers-typing3.tga b/indra/newview/skins/apollo/textures/icn_active-speakers-typing3.tga deleted file mode 100644 index 031b3ad344..0000000000 Binary files a/indra/newview/skins/apollo/textures/icn_active-speakers-typing3.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/icn_clear_lineeditor.tga b/indra/newview/skins/apollo/textures/icn_clear_lineeditor.tga deleted file mode 100644 index 8cd8310c66..0000000000 Binary files a/indra/newview/skins/apollo/textures/icn_clear_lineeditor.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/icn_media-pause.tga b/indra/newview/skins/apollo/textures/icn_media-pause.tga deleted file mode 100644 index 0713af0b40..0000000000 Binary files a/indra/newview/skins/apollo/textures/icn_media-pause.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/icn_media-pause_active.tga b/indra/newview/skins/apollo/textures/icn_media-pause_active.tga deleted file mode 100644 index 21384316a8..0000000000 Binary files a/indra/newview/skins/apollo/textures/icn_media-pause_active.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/icn_media-pause_disabled.tga b/indra/newview/skins/apollo/textures/icn_media-pause_disabled.tga deleted file mode 100644 index 4d604c63c3..0000000000 Binary files a/indra/newview/skins/apollo/textures/icn_media-pause_disabled.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/icn_media-pause_enabled.tga b/indra/newview/skins/apollo/textures/icn_media-pause_enabled.tga deleted file mode 100644 index 577f9195d0..0000000000 Binary files a/indra/newview/skins/apollo/textures/icn_media-pause_enabled.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/icn_media-play.tga b/indra/newview/skins/apollo/textures/icn_media-play.tga deleted file mode 100644 index bdd9f16110..0000000000 Binary files a/indra/newview/skins/apollo/textures/icn_media-play.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/icn_media-play_active.tga b/indra/newview/skins/apollo/textures/icn_media-play_active.tga deleted file mode 100644 index b166a4178d..0000000000 Binary files a/indra/newview/skins/apollo/textures/icn_media-play_active.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/icn_media-play_disabled.tga b/indra/newview/skins/apollo/textures/icn_media-play_disabled.tga deleted file mode 100644 index 444062f375..0000000000 Binary files a/indra/newview/skins/apollo/textures/icn_media-play_disabled.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/icn_media-play_enabled.tga b/indra/newview/skins/apollo/textures/icn_media-play_enabled.tga deleted file mode 100644 index 9ed55f829d..0000000000 Binary files a/indra/newview/skins/apollo/textures/icn_media-play_enabled.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/icn_media-stop_active.tga b/indra/newview/skins/apollo/textures/icn_media-stop_active.tga deleted file mode 100644 index 03efac206f..0000000000 Binary files a/indra/newview/skins/apollo/textures/icn_media-stop_active.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/icn_media-stop_disabled.tga b/indra/newview/skins/apollo/textures/icn_media-stop_disabled.tga deleted file mode 100644 index cf1532a426..0000000000 Binary files a/indra/newview/skins/apollo/textures/icn_media-stop_disabled.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/icn_media-stop_enabled.tga b/indra/newview/skins/apollo/textures/icn_media-stop_enabled.tga deleted file mode 100644 index 011b98c496..0000000000 Binary files a/indra/newview/skins/apollo/textures/icn_media-stop_enabled.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/icn_media.tga b/indra/newview/skins/apollo/textures/icn_media.tga deleted file mode 100644 index 43dd342c9d..0000000000 Binary files a/indra/newview/skins/apollo/textures/icn_media.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/icn_music-pause.tga b/indra/newview/skins/apollo/textures/icn_music-pause.tga deleted file mode 100644 index 548ccf4e47..0000000000 Binary files a/indra/newview/skins/apollo/textures/icn_music-pause.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/icn_music-play.tga b/indra/newview/skins/apollo/textures/icn_music-play.tga deleted file mode 100644 index 1a67d3440a..0000000000 Binary files a/indra/newview/skins/apollo/textures/icn_music-play.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/icn_music.tga b/indra/newview/skins/apollo/textures/icn_music.tga deleted file mode 100644 index 9470601dbf..0000000000 Binary files a/indra/newview/skins/apollo/textures/icn_music.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/icn_scrollbar.tga b/indra/newview/skins/apollo/textures/icn_scrollbar.tga deleted file mode 100644 index a19a8a5d1a..0000000000 Binary files a/indra/newview/skins/apollo/textures/icn_scrollbar.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/icn_scrollbar_bg.tga b/indra/newview/skins/apollo/textures/icn_scrollbar_bg.tga deleted file mode 100644 index 1e4bc7a8a3..0000000000 Binary files a/indra/newview/skins/apollo/textures/icn_scrollbar_bg.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/icn_scrollbar_thumb.tga b/indra/newview/skins/apollo/textures/icn_scrollbar_thumb.tga deleted file mode 100644 index d63c314724..0000000000 Binary files a/indra/newview/skins/apollo/textures/icn_scrollbar_thumb.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/icn_speaker-muted_dark.tga b/indra/newview/skins/apollo/textures/icn_speaker-muted_dark.tga deleted file mode 100644 index a7d29a14b9..0000000000 Binary files a/indra/newview/skins/apollo/textures/icn_speaker-muted_dark.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/icn_stop.tga b/indra/newview/skins/apollo/textures/icn_stop.tga deleted file mode 100644 index 7a53bccc2f..0000000000 Binary files a/indra/newview/skins/apollo/textures/icn_stop.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/icn_textfield_enabled.tga b/indra/newview/skins/apollo/textures/icn_textfield_enabled.tga deleted file mode 100644 index fc681a1957..0000000000 Binary files a/indra/newview/skins/apollo/textures/icn_textfield_enabled.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/icn_voice-call-end.tga b/indra/newview/skins/apollo/textures/icn_voice-call-end.tga deleted file mode 100644 index 2da4e856b4..0000000000 Binary files a/indra/newview/skins/apollo/textures/icn_voice-call-end.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/icn_voice-call-start.tga b/indra/newview/skins/apollo/textures/icn_voice-call-start.tga deleted file mode 100644 index 07701cb5a2..0000000000 Binary files a/indra/newview/skins/apollo/textures/icn_voice-call-start.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/icn_voice-groupfocus.tga b/indra/newview/skins/apollo/textures/icn_voice-groupfocus.tga deleted file mode 100644 index 9f48d4609d..0000000000 Binary files a/indra/newview/skins/apollo/textures/icn_voice-groupfocus.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/icn_voice-localchat.tga b/indra/newview/skins/apollo/textures/icn_voice-localchat.tga deleted file mode 100644 index 7cf267eaf5..0000000000 Binary files a/indra/newview/skins/apollo/textures/icn_voice-localchat.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/icn_voice-pvtfocus.tga b/indra/newview/skins/apollo/textures/icn_voice-pvtfocus.tga deleted file mode 100644 index abadb09aaf..0000000000 Binary files a/indra/newview/skins/apollo/textures/icn_voice-pvtfocus.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/icn_voice_ptt-off.tga b/indra/newview/skins/apollo/textures/icn_voice_ptt-off.tga deleted file mode 100644 index 15ecbdff95..0000000000 Binary files a/indra/newview/skins/apollo/textures/icn_voice_ptt-off.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/icn_voice_ptt-on-lvl1.tga b/indra/newview/skins/apollo/textures/icn_voice_ptt-on-lvl1.tga deleted file mode 100644 index ae72af131d..0000000000 Binary files a/indra/newview/skins/apollo/textures/icn_voice_ptt-on-lvl1.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/icn_voice_ptt-on-lvl2.tga b/indra/newview/skins/apollo/textures/icn_voice_ptt-on-lvl2.tga deleted file mode 100644 index 4dfc2dd292..0000000000 Binary files a/indra/newview/skins/apollo/textures/icn_voice_ptt-on-lvl2.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/icn_voice_ptt-on-lvl3.tga b/indra/newview/skins/apollo/textures/icn_voice_ptt-on-lvl3.tga deleted file mode 100644 index 018b0bef42..0000000000 Binary files a/indra/newview/skins/apollo/textures/icn_voice_ptt-on-lvl3.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/icn_voice_ptt-on.tga b/indra/newview/skins/apollo/textures/icn_voice_ptt-on.tga deleted file mode 100644 index 9eb6431106..0000000000 Binary files a/indra/newview/skins/apollo/textures/icn_voice_ptt-on.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/icon_auction.tga b/indra/newview/skins/apollo/textures/icon_auction.tga deleted file mode 100644 index d121833b47..0000000000 Binary files a/indra/newview/skins/apollo/textures/icon_auction.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/icon_avatar_expand.png b/indra/newview/skins/apollo/textures/icon_avatar_expand.png index 47698e9eb4..453a52c1da 100644 Binary files a/indra/newview/skins/apollo/textures/icon_avatar_expand.png and b/indra/newview/skins/apollo/textures/icon_avatar_expand.png differ diff --git a/indra/newview/skins/apollo/textures/icon_avatar_online.tga b/indra/newview/skins/apollo/textures/icon_avatar_online.tga deleted file mode 100644 index 45221213eb..0000000000 Binary files a/indra/newview/skins/apollo/textures/icon_avatar_online.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/icon_day_cycle.tga b/indra/newview/skins/apollo/textures/icon_day_cycle.tga deleted file mode 100644 index 2d5dee1e94..0000000000 Binary files a/indra/newview/skins/apollo/textures/icon_day_cycle.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/icon_diurnal.tga b/indra/newview/skins/apollo/textures/icon_diurnal.tga deleted file mode 100644 index fc720c8269..0000000000 Binary files a/indra/newview/skins/apollo/textures/icon_diurnal.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/icon_event_mature.tga b/indra/newview/skins/apollo/textures/icon_event_mature.tga deleted file mode 100644 index 61c879bc92..0000000000 Binary files a/indra/newview/skins/apollo/textures/icon_event_mature.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/icon_popular.tga b/indra/newview/skins/apollo/textures/icon_popular.tga deleted file mode 100644 index f1165b8aaa..0000000000 Binary files a/indra/newview/skins/apollo/textures/icon_popular.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/lag_status_critical.tga b/indra/newview/skins/apollo/textures/lag_status_critical.tga deleted file mode 100644 index bbc71d9e77..0000000000 Binary files a/indra/newview/skins/apollo/textures/lag_status_critical.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/lag_status_good.tga b/indra/newview/skins/apollo/textures/lag_status_good.tga deleted file mode 100644 index 680ba90f17..0000000000 Binary files a/indra/newview/skins/apollo/textures/lag_status_good.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/lag_status_warning.tga b/indra/newview/skins/apollo/textures/lag_status_warning.tga deleted file mode 100644 index 13ce3cc396..0000000000 Binary files a/indra/newview/skins/apollo/textures/lag_status_warning.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/legend.tga b/indra/newview/skins/apollo/textures/legend.tga deleted file mode 100644 index 0dbb8fda4f..0000000000 Binary files a/indra/newview/skins/apollo/textures/legend.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/lightgray.tga b/indra/newview/skins/apollo/textures/lightgray.tga deleted file mode 100644 index 2063d685aa..0000000000 Binary files a/indra/newview/skins/apollo/textures/lightgray.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/map_avatar_16.tga b/indra/newview/skins/apollo/textures/map_avatar_16.tga deleted file mode 100644 index ce129e3590..0000000000 Binary files a/indra/newview/skins/apollo/textures/map_avatar_16.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/map_avatar_32.tga b/indra/newview/skins/apollo/textures/map_avatar_32.tga deleted file mode 100644 index aebeab4093..0000000000 Binary files a/indra/newview/skins/apollo/textures/map_avatar_32.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/map_avatar_8.tga b/indra/newview/skins/apollo/textures/map_avatar_8.tga deleted file mode 100644 index 28552f2237..0000000000 Binary files a/indra/newview/skins/apollo/textures/map_avatar_8.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/map_avatar_above_32.tga b/indra/newview/skins/apollo/textures/map_avatar_above_32.tga deleted file mode 100644 index 65bd0561a7..0000000000 Binary files a/indra/newview/skins/apollo/textures/map_avatar_above_32.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/map_avatar_above_8.tga b/indra/newview/skins/apollo/textures/map_avatar_above_8.tga deleted file mode 100644 index 193428e530..0000000000 Binary files a/indra/newview/skins/apollo/textures/map_avatar_above_8.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/map_avatar_below_32.tga b/indra/newview/skins/apollo/textures/map_avatar_below_32.tga deleted file mode 100644 index 496c44b369..0000000000 Binary files a/indra/newview/skins/apollo/textures/map_avatar_below_32.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/map_avatar_below_8.tga b/indra/newview/skins/apollo/textures/map_avatar_below_8.tga deleted file mode 100644 index 9e14bfab90..0000000000 Binary files a/indra/newview/skins/apollo/textures/map_avatar_below_8.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/map_avatar_you_32.tga b/indra/newview/skins/apollo/textures/map_avatar_you_32.tga deleted file mode 100644 index 782207efd6..0000000000 Binary files a/indra/newview/skins/apollo/textures/map_avatar_you_32.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/map_avatar_you_8.tga b/indra/newview/skins/apollo/textures/map_avatar_you_8.tga deleted file mode 100644 index 61f319fd9d..0000000000 Binary files a/indra/newview/skins/apollo/textures/map_avatar_you_8.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/map_home.tga b/indra/newview/skins/apollo/textures/map_home.tga deleted file mode 100644 index 7478de371a..0000000000 Binary files a/indra/newview/skins/apollo/textures/map_home.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/map_infohub.tga b/indra/newview/skins/apollo/textures/map_infohub.tga deleted file mode 100644 index 173b93e399..0000000000 Binary files a/indra/newview/skins/apollo/textures/map_infohub.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/map_track_16.tga b/indra/newview/skins/apollo/textures/map_track_16.tga deleted file mode 100644 index 451ce24cf0..0000000000 Binary files a/indra/newview/skins/apollo/textures/map_track_16.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/map_track_8.tga b/indra/newview/skins/apollo/textures/map_track_8.tga deleted file mode 100644 index 53425ff45b..0000000000 Binary files a/indra/newview/skins/apollo/textures/map_track_8.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/media_icon.tga b/indra/newview/skins/apollo/textures/media_icon.tga deleted file mode 100644 index 289520cde8..0000000000 Binary files a/indra/newview/skins/apollo/textures/media_icon.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/minimize.tga b/indra/newview/skins/apollo/textures/minimize.tga deleted file mode 100644 index a21fd91481..0000000000 Binary files a/indra/newview/skins/apollo/textures/minimize.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/missing_asset.tga b/indra/newview/skins/apollo/textures/missing_asset.tga deleted file mode 100644 index 9a43f4db5d..0000000000 Binary files a/indra/newview/skins/apollo/textures/missing_asset.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/music_icon.tga b/indra/newview/skins/apollo/textures/music_icon.tga deleted file mode 100644 index aeaff02e0a..0000000000 Binary files a/indra/newview/skins/apollo/textures/music_icon.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/mute_icon.tga b/indra/newview/skins/apollo/textures/mute_icon.tga deleted file mode 100644 index 879b9e6188..0000000000 Binary files a/indra/newview/skins/apollo/textures/mute_icon.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/notify_box_icon.tga b/indra/newview/skins/apollo/textures/notify_box_icon.tga deleted file mode 100644 index 0672c89ee2..0000000000 Binary files a/indra/newview/skins/apollo/textures/notify_box_icon.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/notify_caution_icon.tga b/indra/newview/skins/apollo/textures/notify_caution_icon.tga deleted file mode 100644 index abc23d1d7a..0000000000 Binary files a/indra/newview/skins/apollo/textures/notify_caution_icon.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/notify_next.png b/indra/newview/skins/apollo/textures/notify_next.png index 6faa14a996..d649a47755 100644 Binary files a/indra/newview/skins/apollo/textures/notify_next.png and b/indra/newview/skins/apollo/textures/notify_next.png differ diff --git a/indra/newview/skins/apollo/textures/notify_tip_icon.tga b/indra/newview/skins/apollo/textures/notify_tip_icon.tga deleted file mode 100644 index f79a634a91..0000000000 Binary files a/indra/newview/skins/apollo/textures/notify_tip_icon.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/preview.png b/indra/newview/skins/apollo/textures/preview.png index d045ac7343..b8e2fa6601 100644 Binary files a/indra/newview/skins/apollo/textures/preview.png and b/indra/newview/skins/apollo/textures/preview.png differ diff --git a/indra/newview/skins/apollo/textures/progress_fill.tga b/indra/newview/skins/apollo/textures/progress_fill.tga deleted file mode 100644 index a913fe7627..0000000000 Binary files a/indra/newview/skins/apollo/textures/progress_fill.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/propertyline.tga b/indra/newview/skins/apollo/textures/propertyline.tga deleted file mode 100644 index 0c504eea71..0000000000 Binary files a/indra/newview/skins/apollo/textures/propertyline.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/skin_thumbnail_dark.png b/indra/newview/skins/apollo/textures/skin_thumbnail_dark.png deleted file mode 100644 index 2cac82923b..0000000000 Binary files a/indra/newview/skins/apollo/textures/skin_thumbnail_dark.png and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/skin_thumbnail_default.png b/indra/newview/skins/apollo/textures/skin_thumbnail_default.png deleted file mode 100644 index 40fe64bb49..0000000000 Binary files a/indra/newview/skins/apollo/textures/skin_thumbnail_default.png and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/skin_thumbnail_gred.png b/indra/newview/skins/apollo/textures/skin_thumbnail_gred.png deleted file mode 100644 index 827135499c..0000000000 Binary files a/indra/newview/skins/apollo/textures/skin_thumbnail_gred.png and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/skin_thumbnail_phoenix.png b/indra/newview/skins/apollo/textures/skin_thumbnail_phoenix.png deleted file mode 100644 index ab35bc0ab9..0000000000 Binary files a/indra/newview/skins/apollo/textures/skin_thumbnail_phoenix.png and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/skin_thumbnail_pslgreen.png b/indra/newview/skins/apollo/textures/skin_thumbnail_pslgreen.png deleted file mode 100644 index 73e117e9fa..0000000000 Binary files a/indra/newview/skins/apollo/textures/skin_thumbnail_pslgreen.png and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/skin_thumbnail_pslpurple.png b/indra/newview/skins/apollo/textures/skin_thumbnail_pslpurple.png deleted file mode 100644 index 902ad82b18..0000000000 Binary files a/indra/newview/skins/apollo/textures/skin_thumbnail_pslpurple.png and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/skin_thumbnail_ruby.png b/indra/newview/skins/apollo/textures/skin_thumbnail_ruby.png deleted file mode 100644 index d45e75ad04..0000000000 Binary files a/indra/newview/skins/apollo/textures/skin_thumbnail_ruby.png and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/skin_thumbnail_saphire.png b/indra/newview/skins/apollo/textures/skin_thumbnail_saphire.png deleted file mode 100644 index 7ec8e19913..0000000000 Binary files a/indra/newview/skins/apollo/textures/skin_thumbnail_saphire.png and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/skin_thumbnail_silver.png b/indra/newview/skins/apollo/textures/skin_thumbnail_silver.png deleted file mode 100644 index 51707bb9d4..0000000000 Binary files a/indra/newview/skins/apollo/textures/skin_thumbnail_silver.png and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/slim_icon_16_viewer.tga b/indra/newview/skins/apollo/textures/slim_icon_16_viewer.tga deleted file mode 100644 index 552181d36a..0000000000 Binary files a/indra/newview/skins/apollo/textures/slim_icon_16_viewer.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/sm_rounded_corners_simple.tga b/indra/newview/skins/apollo/textures/sm_rounded_corners_simple.tga deleted file mode 100644 index 85157e4612..0000000000 Binary files a/indra/newview/skins/apollo/textures/sm_rounded_corners_simple.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/smicon_warn.tga b/indra/newview/skins/apollo/textures/smicon_warn.tga deleted file mode 100644 index 90ccaa07e5..0000000000 Binary files a/indra/newview/skins/apollo/textures/smicon_warn.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/spacer24.tga b/indra/newview/skins/apollo/textures/spacer24.tga deleted file mode 100644 index c7cab6b38c..0000000000 Binary files a/indra/newview/skins/apollo/textures/spacer24.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/spacer35.tga b/indra/newview/skins/apollo/textures/spacer35.tga deleted file mode 100644 index b88bc6680a..0000000000 Binary files a/indra/newview/skins/apollo/textures/spacer35.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/spin_down_in_blue.tga b/indra/newview/skins/apollo/textures/spin_down_in_blue.tga deleted file mode 100644 index b9eb36ba9f..0000000000 Binary files a/indra/newview/skins/apollo/textures/spin_down_in_blue.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/spin_down_out_blue.tga b/indra/newview/skins/apollo/textures/spin_down_out_blue.tga deleted file mode 100644 index c9cb5e8bf6..0000000000 Binary files a/indra/newview/skins/apollo/textures/spin_down_out_blue.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/spin_up_in_blue.tga b/indra/newview/skins/apollo/textures/spin_up_in_blue.tga deleted file mode 100644 index b604b8843c..0000000000 Binary files a/indra/newview/skins/apollo/textures/spin_up_in_blue.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/spin_up_out_blue.tga b/indra/newview/skins/apollo/textures/spin_up_out_blue.tga deleted file mode 100644 index 4e3941e458..0000000000 Binary files a/indra/newview/skins/apollo/textures/spin_up_out_blue.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/status_busy.tga b/indra/newview/skins/apollo/textures/status_busy.tga deleted file mode 100644 index 7743d9c7bb..0000000000 Binary files a/indra/newview/skins/apollo/textures/status_busy.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/status_health.tga b/indra/newview/skins/apollo/textures/status_health.tga deleted file mode 100644 index 3d5f455fcd..0000000000 Binary files a/indra/newview/skins/apollo/textures/status_health.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/status_money.tga b/indra/newview/skins/apollo/textures/status_money.tga deleted file mode 100644 index d5be31fc60..0000000000 Binary files a/indra/newview/skins/apollo/textures/status_money.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/status_no_build.tga b/indra/newview/skins/apollo/textures/status_no_build.tga deleted file mode 100644 index 8e471e1851..0000000000 Binary files a/indra/newview/skins/apollo/textures/status_no_build.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/status_no_fly.tga b/indra/newview/skins/apollo/textures/status_no_fly.tga deleted file mode 100644 index cde2700ab2..0000000000 Binary files a/indra/newview/skins/apollo/textures/status_no_fly.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/status_no_push.tga b/indra/newview/skins/apollo/textures/status_no_push.tga deleted file mode 100644 index 5ccbfa50f1..0000000000 Binary files a/indra/newview/skins/apollo/textures/status_no_push.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/status_no_scripts.tga b/indra/newview/skins/apollo/textures/status_no_scripts.tga deleted file mode 100644 index 52ecdb1b84..0000000000 Binary files a/indra/newview/skins/apollo/textures/status_no_scripts.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/status_no_voice.tga b/indra/newview/skins/apollo/textures/status_no_voice.tga deleted file mode 100644 index 4ab4498cbc..0000000000 Binary files a/indra/newview/skins/apollo/textures/status_no_voice.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/status_script_debug.tga b/indra/newview/skins/apollo/textures/status_script_debug.tga deleted file mode 100644 index 6fca614835..0000000000 Binary files a/indra/newview/skins/apollo/textures/status_script_debug.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/status_search.tga b/indra/newview/skins/apollo/textures/status_search.tga deleted file mode 100644 index 3ac10c4769..0000000000 Binary files a/indra/newview/skins/apollo/textures/status_search.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/status_search_btn.png b/indra/newview/skins/apollo/textures/status_search_btn.png deleted file mode 100644 index 67f61332bc..0000000000 Binary files a/indra/newview/skins/apollo/textures/status_search_btn.png and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/status_search_btn_pressed.png b/indra/newview/skins/apollo/textures/status_search_btn_pressed.png deleted file mode 100644 index 1437273d37..0000000000 Binary files a/indra/newview/skins/apollo/textures/status_search_btn_pressed.png and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/status_voice.tga b/indra/newview/skins/apollo/textures/status_voice.tga deleted file mode 100644 index 4ab4498cbc..0000000000 Binary files a/indra/newview/skins/apollo/textures/status_voice.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/tab_background_darkpurple.tga b/indra/newview/skins/apollo/textures/tab_background_darkpurple.tga deleted file mode 100644 index 8169f98694..0000000000 Binary files a/indra/newview/skins/apollo/textures/tab_background_darkpurple.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/tab_background_lightgrey.tga b/indra/newview/skins/apollo/textures/tab_background_lightgrey.tga deleted file mode 100644 index c2f8818f73..0000000000 Binary files a/indra/newview/skins/apollo/textures/tab_background_lightgrey.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/tab_background_purple.tga b/indra/newview/skins/apollo/textures/tab_background_purple.tga deleted file mode 100644 index aa01b3cb68..0000000000 Binary files a/indra/newview/skins/apollo/textures/tab_background_purple.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/tabarea.tga b/indra/newview/skins/apollo/textures/tabarea.tga deleted file mode 100644 index 5517aebfc8..0000000000 Binary files a/indra/newview/skins/apollo/textures/tabarea.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/textures.xml b/indra/newview/skins/apollo/textures/textures.xml index 2c4b0cbea6..48fcecbfeb 100644 --- a/indra/newview/skins/apollo/textures/textures.xml +++ b/indra/newview/skins/apollo/textures/textures.xml @@ -1,382 +1,3 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/indra/newview/skins/apollo/textures/toolbar_bg.tga b/indra/newview/skins/apollo/textures/toolbar_bg.tga deleted file mode 100644 index 3a05776276..0000000000 Binary files a/indra/newview/skins/apollo/textures/toolbar_bg.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/toolbar_tab.tga b/indra/newview/skins/apollo/textures/toolbar_tab.tga deleted file mode 100644 index 5ea1a28d29..0000000000 Binary files a/indra/newview/skins/apollo/textures/toolbar_tab.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/up_arrow.png b/indra/newview/skins/apollo/textures/up_arrow.png deleted file mode 100644 index fe68ad49dc..0000000000 Binary files a/indra/newview/skins/apollo/textures/up_arrow.png and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/up_arrow.tga b/indra/newview/skins/apollo/textures/up_arrow.tga deleted file mode 100644 index c2bd8ccebf..0000000000 Binary files a/indra/newview/skins/apollo/textures/up_arrow.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/uv_test2.tga b/indra/newview/skins/apollo/textures/uv_test2.tga deleted file mode 100644 index a16000d1e4..0000000000 Binary files a/indra/newview/skins/apollo/textures/uv_test2.tga and /dev/null differ diff --git a/indra/newview/skins/apollo/textures/white.tga b/indra/newview/skins/apollo/textures/white.tga deleted file mode 100644 index 9fe68631cf..0000000000 Binary files a/indra/newview/skins/apollo/textures/white.tga and /dev/null differ diff --git a/indra/newview/skins/blackdark/colors.xml b/indra/newview/skins/blackdark/colors.xml index e076f94ebe..99773245ce 100644 --- a/indra/newview/skins/blackdark/colors.xml +++ b/indra/newview/skins/blackdark/colors.xml @@ -168,7 +168,6 @@ - diff --git a/indra/newview/skins/blackdark/textures/5748decc-f629-461c-9a36-a35a221fe21f.tga b/indra/newview/skins/blackdark/textures/5748decc-f629-461c-9a36-a35a221fe21f.tga deleted file mode 100644 index 55e3793097..0000000000 Binary files a/indra/newview/skins/blackdark/textures/5748decc-f629-461c-9a36-a35a221fe21f.tga and /dev/null differ diff --git a/indra/newview/skins/blackdark/textures/circle.tga b/indra/newview/skins/blackdark/textures/circle.tga deleted file mode 100644 index d7097e3a35..0000000000 Binary files a/indra/newview/skins/blackdark/textures/circle.tga and /dev/null differ diff --git a/indra/newview/skins/blackdark/textures/down_arrow.png b/indra/newview/skins/blackdark/textures/down_arrow.png index 46bb251f5c..07ab1a91c2 100644 Binary files a/indra/newview/skins/blackdark/textures/down_arrow.png and b/indra/newview/skins/blackdark/textures/down_arrow.png differ diff --git a/indra/newview/skins/blackdark/textures/icn_active-speakers-dot-lvl0.tga b/indra/newview/skins/blackdark/textures/icn_active-speakers-dot-lvl0.tga deleted file mode 100644 index 35846cef32..0000000000 Binary files a/indra/newview/skins/blackdark/textures/icn_active-speakers-dot-lvl0.tga and /dev/null differ diff --git a/indra/newview/skins/blackdark/textures/icn_active-speakers-dot-lvl1.tga b/indra/newview/skins/blackdark/textures/icn_active-speakers-dot-lvl1.tga deleted file mode 100644 index 1f9f564fa9..0000000000 Binary files a/indra/newview/skins/blackdark/textures/icn_active-speakers-dot-lvl1.tga and /dev/null differ diff --git a/indra/newview/skins/blackdark/textures/icn_active-speakers-dot-lvl2.tga b/indra/newview/skins/blackdark/textures/icn_active-speakers-dot-lvl2.tga deleted file mode 100644 index b2e5609f1f..0000000000 Binary files a/indra/newview/skins/blackdark/textures/icn_active-speakers-dot-lvl2.tga and /dev/null differ diff --git a/indra/newview/skins/blackdark/textures/icn_active-speakers-typing1.tga b/indra/newview/skins/blackdark/textures/icn_active-speakers-typing1.tga deleted file mode 100644 index 3706c96e0f..0000000000 Binary files a/indra/newview/skins/blackdark/textures/icn_active-speakers-typing1.tga and /dev/null differ diff --git a/indra/newview/skins/blackdark/textures/icn_active-speakers-typing2.tga b/indra/newview/skins/blackdark/textures/icn_active-speakers-typing2.tga deleted file mode 100644 index 0d127f9461..0000000000 Binary files a/indra/newview/skins/blackdark/textures/icn_active-speakers-typing2.tga and /dev/null differ diff --git a/indra/newview/skins/blackdark/textures/icn_active-speakers-typing3.tga b/indra/newview/skins/blackdark/textures/icn_active-speakers-typing3.tga deleted file mode 100644 index 031b3ad344..0000000000 Binary files a/indra/newview/skins/blackdark/textures/icn_active-speakers-typing3.tga and /dev/null differ diff --git a/indra/newview/skins/blackdark/textures/icn_clear_lineeditor.tga b/indra/newview/skins/blackdark/textures/icn_clear_lineeditor.tga deleted file mode 100644 index 8cd8310c66..0000000000 Binary files a/indra/newview/skins/blackdark/textures/icn_clear_lineeditor.tga and /dev/null differ diff --git a/indra/newview/skins/blackdark/textures/map_infohub.tga b/indra/newview/skins/blackdark/textures/map_infohub.tga deleted file mode 100644 index 173b93e399..0000000000 Binary files a/indra/newview/skins/blackdark/textures/map_infohub.tga and /dev/null differ diff --git a/indra/newview/skins/blackdark/textures/mute_icon.tga b/indra/newview/skins/blackdark/textures/mute_icon.tga deleted file mode 100644 index 879b9e6188..0000000000 Binary files a/indra/newview/skins/blackdark/textures/mute_icon.tga and /dev/null differ diff --git a/indra/newview/skins/blackdark/textures/notify_next.png b/indra/newview/skins/blackdark/textures/notify_next.png index 9b371e03e2..d14feccb11 100644 Binary files a/indra/newview/skins/blackdark/textures/notify_next.png and b/indra/newview/skins/blackdark/textures/notify_next.png differ diff --git a/indra/newview/skins/blackdark/textures/preview.png b/indra/newview/skins/blackdark/textures/preview.png index 2022d7c885..0191b4def5 100644 Binary files a/indra/newview/skins/blackdark/textures/preview.png and b/indra/newview/skins/blackdark/textures/preview.png differ diff --git a/indra/newview/skins/blackdark/textures/rounded_square.j2c b/indra/newview/skins/blackdark/textures/rounded_square.j2c deleted file mode 100644 index c3dfe8f10e..0000000000 Binary files a/indra/newview/skins/blackdark/textures/rounded_square.j2c and /dev/null differ diff --git a/indra/newview/skins/blackdark/textures/spacer24.tga b/indra/newview/skins/blackdark/textures/spacer24.tga deleted file mode 100644 index c7cab6b38c..0000000000 Binary files a/indra/newview/skins/blackdark/textures/spacer24.tga and /dev/null differ diff --git a/indra/newview/skins/blackdark/textures/spacer35.tga b/indra/newview/skins/blackdark/textures/spacer35.tga deleted file mode 100644 index b88bc6680a..0000000000 Binary files a/indra/newview/skins/blackdark/textures/spacer35.tga and /dev/null differ diff --git a/indra/newview/skins/blackdark/textures/status_search_btn.png b/indra/newview/skins/blackdark/textures/status_search_btn.png index b755f6f106..f9fbebc835 100644 Binary files a/indra/newview/skins/blackdark/textures/status_search_btn.png and b/indra/newview/skins/blackdark/textures/status_search_btn.png differ diff --git a/indra/newview/skins/blackdark/textures/status_search_btn_pressed.png b/indra/newview/skins/blackdark/textures/status_search_btn_pressed.png index c199458857..0569089924 100644 Binary files a/indra/newview/skins/blackdark/textures/status_search_btn_pressed.png and b/indra/newview/skins/blackdark/textures/status_search_btn_pressed.png differ diff --git a/indra/newview/skins/blackdark/textures/tabarea.tga b/indra/newview/skins/blackdark/textures/tabarea.tga deleted file mode 100644 index 5517aebfc8..0000000000 Binary files a/indra/newview/skins/blackdark/textures/tabarea.tga and /dev/null differ diff --git a/indra/newview/skins/blackdark/textures/textures.xml b/indra/newview/skins/blackdark/textures/textures.xml index 9f617f56b5..1d61522a18 100644 --- a/indra/newview/skins/blackdark/textures/textures.xml +++ b/indra/newview/skins/blackdark/textures/textures.xml @@ -1,385 +1,33 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + diff --git a/indra/newview/skins/blackdark/textures/up_arrow.png b/indra/newview/skins/blackdark/textures/up_arrow.png index 5c60a61db7..95a712f4a9 100644 Binary files a/indra/newview/skins/blackdark/textures/up_arrow.png and b/indra/newview/skins/blackdark/textures/up_arrow.png differ diff --git a/indra/newview/skins/blacklightblue/colors.xml b/indra/newview/skins/blacklightblue/colors.xml index ac4ad8772d..ef813f43f5 100644 --- a/indra/newview/skins/blacklightblue/colors.xml +++ b/indra/newview/skins/blacklightblue/colors.xml @@ -168,7 +168,6 @@ - diff --git a/indra/newview/skins/blacklightblue/textures/down_arrow.png b/indra/newview/skins/blacklightblue/textures/down_arrow.png index 88c8c84811..e8b4a6622e 100644 Binary files a/indra/newview/skins/blacklightblue/textures/down_arrow.png and b/indra/newview/skins/blacklightblue/textures/down_arrow.png differ diff --git a/indra/newview/skins/blacklightblue/textures/icon_diurnal.tga b/indra/newview/skins/blacklightblue/textures/icon_diurnal.tga deleted file mode 100644 index fc720c8269..0000000000 Binary files a/indra/newview/skins/blacklightblue/textures/icon_diurnal.tga and /dev/null differ diff --git a/indra/newview/skins/blacklightblue/textures/map_infohub.tga b/indra/newview/skins/blacklightblue/textures/map_infohub.tga deleted file mode 100644 index 173b93e399..0000000000 Binary files a/indra/newview/skins/blacklightblue/textures/map_infohub.tga and /dev/null differ diff --git a/indra/newview/skins/blacklightblue/textures/mute_icon.tga b/indra/newview/skins/blacklightblue/textures/mute_icon.tga deleted file mode 100644 index 879b9e6188..0000000000 Binary files a/indra/newview/skins/blacklightblue/textures/mute_icon.tga and /dev/null differ diff --git a/indra/newview/skins/blacklightblue/textures/notify_next.png b/indra/newview/skins/blacklightblue/textures/notify_next.png index 9b371e03e2..d14feccb11 100644 Binary files a/indra/newview/skins/blacklightblue/textures/notify_next.png and b/indra/newview/skins/blacklightblue/textures/notify_next.png differ diff --git a/indra/newview/skins/blacklightblue/textures/preview.png b/indra/newview/skins/blacklightblue/textures/preview.png index 57c16eaf3c..a52cee7821 100644 Binary files a/indra/newview/skins/blacklightblue/textures/preview.png and b/indra/newview/skins/blacklightblue/textures/preview.png differ diff --git a/indra/newview/skins/blacklightblue/textures/rounded_square.j2c b/indra/newview/skins/blacklightblue/textures/rounded_square.j2c deleted file mode 100644 index c3dfe8f10e..0000000000 Binary files a/indra/newview/skins/blacklightblue/textures/rounded_square.j2c and /dev/null differ diff --git a/indra/newview/skins/blacklightblue/textures/spacer24.tga b/indra/newview/skins/blacklightblue/textures/spacer24.tga deleted file mode 100644 index c7cab6b38c..0000000000 Binary files a/indra/newview/skins/blacklightblue/textures/spacer24.tga and /dev/null differ diff --git a/indra/newview/skins/blacklightblue/textures/spacer35.tga b/indra/newview/skins/blacklightblue/textures/spacer35.tga deleted file mode 100644 index b88bc6680a..0000000000 Binary files a/indra/newview/skins/blacklightblue/textures/spacer35.tga and /dev/null differ diff --git a/indra/newview/skins/blacklightblue/textures/status_search_btn.png b/indra/newview/skins/blacklightblue/textures/status_search_btn.png index 1798559e74..7bcc4ab44b 100644 Binary files a/indra/newview/skins/blacklightblue/textures/status_search_btn.png and b/indra/newview/skins/blacklightblue/textures/status_search_btn.png differ diff --git a/indra/newview/skins/blacklightblue/textures/status_search_btn_pressed.png b/indra/newview/skins/blacklightblue/textures/status_search_btn_pressed.png index c199458857..0569089924 100644 Binary files a/indra/newview/skins/blacklightblue/textures/status_search_btn_pressed.png and b/indra/newview/skins/blacklightblue/textures/status_search_btn_pressed.png differ diff --git a/indra/newview/skins/blacklightblue/textures/tabarea.tga b/indra/newview/skins/blacklightblue/textures/tabarea.tga deleted file mode 100644 index 5517aebfc8..0000000000 Binary files a/indra/newview/skins/blacklightblue/textures/tabarea.tga and /dev/null differ diff --git a/indra/newview/skins/blacklightblue/textures/textures.xml b/indra/newview/skins/blacklightblue/textures/textures.xml index 9f617f56b5..1d61522a18 100644 --- a/indra/newview/skins/blacklightblue/textures/textures.xml +++ b/indra/newview/skins/blacklightblue/textures/textures.xml @@ -1,385 +1,33 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + diff --git a/indra/newview/skins/blacklightblue/textures/up_arrow.png b/indra/newview/skins/blacklightblue/textures/up_arrow.png index 1e55b6ca73..9fb5efaebe 100644 Binary files a/indra/newview/skins/blacklightblue/textures/up_arrow.png and b/indra/newview/skins/blacklightblue/textures/up_arrow.png differ diff --git a/indra/newview/skins/blackred/colors.xml b/indra/newview/skins/blackred/colors.xml index 640ef35d9d..fc87595ae0 100644 --- a/indra/newview/skins/blackred/colors.xml +++ b/indra/newview/skins/blackred/colors.xml @@ -168,7 +168,6 @@ - diff --git a/indra/newview/skins/blackred/textures/down_arrow.png b/indra/newview/skins/blackred/textures/down_arrow.png index abd706481c..82fdc1dfdc 100644 Binary files a/indra/newview/skins/blackred/textures/down_arrow.png and b/indra/newview/skins/blackred/textures/down_arrow.png differ diff --git a/indra/newview/skins/blackred/textures/map_infohub.tga b/indra/newview/skins/blackred/textures/map_infohub.tga deleted file mode 100644 index 173b93e399..0000000000 Binary files a/indra/newview/skins/blackred/textures/map_infohub.tga and /dev/null differ diff --git a/indra/newview/skins/blackred/textures/notify_next.png b/indra/newview/skins/blackred/textures/notify_next.png index 9b371e03e2..d14feccb11 100644 Binary files a/indra/newview/skins/blackred/textures/notify_next.png and b/indra/newview/skins/blackred/textures/notify_next.png differ diff --git a/indra/newview/skins/blackred/textures/preview.png b/indra/newview/skins/blackred/textures/preview.png index 294a6a03aa..2a370e11f8 100644 Binary files a/indra/newview/skins/blackred/textures/preview.png and b/indra/newview/skins/blackred/textures/preview.png differ diff --git a/indra/newview/skins/blackred/textures/rounded_square.j2c b/indra/newview/skins/blackred/textures/rounded_square.j2c deleted file mode 100644 index c3dfe8f10e..0000000000 Binary files a/indra/newview/skins/blackred/textures/rounded_square.j2c and /dev/null differ diff --git a/indra/newview/skins/blackred/textures/status_search_btn.png b/indra/newview/skins/blackred/textures/status_search_btn.png index f6db36fbc8..4b3cb952be 100644 Binary files a/indra/newview/skins/blackred/textures/status_search_btn.png and b/indra/newview/skins/blackred/textures/status_search_btn.png differ diff --git a/indra/newview/skins/blackred/textures/status_search_btn_pressed.png b/indra/newview/skins/blackred/textures/status_search_btn_pressed.png index c199458857..0569089924 100644 Binary files a/indra/newview/skins/blackred/textures/status_search_btn_pressed.png and b/indra/newview/skins/blackred/textures/status_search_btn_pressed.png differ diff --git a/indra/newview/skins/blackred/textures/textures.xml b/indra/newview/skins/blackred/textures/textures.xml index 9f617f56b5..1d61522a18 100644 --- a/indra/newview/skins/blackred/textures/textures.xml +++ b/indra/newview/skins/blackred/textures/textures.xml @@ -1,385 +1,33 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + diff --git a/indra/newview/skins/blackred/textures/textures_new.xml b/indra/newview/skins/blackred/textures/textures_new.xml new file mode 100644 index 0000000000..1d61522a18 --- /dev/null +++ b/indra/newview/skins/blackred/textures/textures_new.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/indra/newview/skins/blackred/textures/up_arrow.png b/indra/newview/skins/blackred/textures/up_arrow.png index 6beea5fd79..ecd1911360 100644 Binary files a/indra/newview/skins/blackred/textures/up_arrow.png and b/indra/newview/skins/blackred/textures/up_arrow.png differ diff --git a/indra/newview/skins/dark/colors.xml b/indra/newview/skins/dark/colors.xml index 032351a887..4d9ce08f23 100644 --- a/indra/newview/skins/dark/colors.xml +++ b/indra/newview/skins/dark/colors.xml @@ -98,8 +98,9 @@ - - + + + @@ -183,12 +184,6 @@ - - - - - - diff --git a/indra/newview/skins/dark/textures/5748decc-f629-461c-9a36-a35a221fe21f.tga b/indra/newview/skins/dark/textures/5748decc-f629-461c-9a36-a35a221fe21f.tga deleted file mode 100644 index 55e3793097..0000000000 Binary files a/indra/newview/skins/dark/textures/5748decc-f629-461c-9a36-a35a221fe21f.tga and /dev/null differ diff --git a/indra/newview/skins/dark/textures/circle.tga b/indra/newview/skins/dark/textures/circle.tga deleted file mode 100644 index d7097e3a35..0000000000 Binary files a/indra/newview/skins/dark/textures/circle.tga and /dev/null differ diff --git a/indra/newview/skins/dark/textures/folder_arrow.tga b/indra/newview/skins/dark/textures/folder_arrow.tga deleted file mode 100644 index 77d470731b..0000000000 Binary files a/indra/newview/skins/dark/textures/folder_arrow.tga and /dev/null differ diff --git a/indra/newview/skins/dark/textures/icn_active-speakers-dot-lvl0.tga b/indra/newview/skins/dark/textures/icn_active-speakers-dot-lvl0.tga deleted file mode 100644 index 35846cef32..0000000000 Binary files a/indra/newview/skins/dark/textures/icn_active-speakers-dot-lvl0.tga and /dev/null differ diff --git a/indra/newview/skins/dark/textures/icn_active-speakers-dot-lvl1.tga b/indra/newview/skins/dark/textures/icn_active-speakers-dot-lvl1.tga deleted file mode 100644 index 1f9f564fa9..0000000000 Binary files a/indra/newview/skins/dark/textures/icn_active-speakers-dot-lvl1.tga and /dev/null differ diff --git a/indra/newview/skins/dark/textures/icn_active-speakers-dot-lvl2.tga b/indra/newview/skins/dark/textures/icn_active-speakers-dot-lvl2.tga deleted file mode 100644 index b2e5609f1f..0000000000 Binary files a/indra/newview/skins/dark/textures/icn_active-speakers-dot-lvl2.tga and /dev/null differ diff --git a/indra/newview/skins/dark/textures/icn_active-speakers-typing1.tga b/indra/newview/skins/dark/textures/icn_active-speakers-typing1.tga deleted file mode 100644 index 3706c96e0f..0000000000 Binary files a/indra/newview/skins/dark/textures/icn_active-speakers-typing1.tga and /dev/null differ diff --git a/indra/newview/skins/dark/textures/icn_active-speakers-typing2.tga b/indra/newview/skins/dark/textures/icn_active-speakers-typing2.tga deleted file mode 100644 index 0d127f9461..0000000000 Binary files a/indra/newview/skins/dark/textures/icn_active-speakers-typing2.tga and /dev/null differ diff --git a/indra/newview/skins/dark/textures/icn_active-speakers-typing3.tga b/indra/newview/skins/dark/textures/icn_active-speakers-typing3.tga deleted file mode 100644 index 031b3ad344..0000000000 Binary files a/indra/newview/skins/dark/textures/icn_active-speakers-typing3.tga and /dev/null differ diff --git a/indra/newview/skins/dark/textures/icn_clear_lineeditor.tga b/indra/newview/skins/dark/textures/icn_clear_lineeditor.tga deleted file mode 100644 index 8cd8310c66..0000000000 Binary files a/indra/newview/skins/dark/textures/icn_clear_lineeditor.tga and /dev/null differ diff --git a/indra/newview/skins/dark/textures/icn_scrollbar.tga b/indra/newview/skins/dark/textures/icn_scrollbar.tga deleted file mode 100644 index a19a8a5d1a..0000000000 Binary files a/indra/newview/skins/dark/textures/icn_scrollbar.tga and /dev/null differ diff --git a/indra/newview/skins/dark/textures/icn_toolbar_region_tracker.png b/indra/newview/skins/dark/textures/icn_toolbar_region_tracker.png new file mode 100644 index 0000000000..aef16414fd Binary files /dev/null and b/indra/newview/skins/dark/textures/icn_toolbar_region_tracker.png differ diff --git a/indra/newview/skins/dark/textures/mute_icon.tga b/indra/newview/skins/dark/textures/mute_icon.tga deleted file mode 100644 index 879b9e6188..0000000000 Binary files a/indra/newview/skins/dark/textures/mute_icon.tga and /dev/null differ diff --git a/indra/newview/skins/dark/textures/notify_next.png b/indra/newview/skins/dark/textures/notify_next.png index b57c26e265..83603835d1 100644 Binary files a/indra/newview/skins/dark/textures/notify_next.png and b/indra/newview/skins/dark/textures/notify_next.png differ diff --git a/indra/newview/skins/dark/textures/preview.png b/indra/newview/skins/dark/textures/preview.png index a9f2b8b027..bf4df71c58 100644 Binary files a/indra/newview/skins/dark/textures/preview.png and b/indra/newview/skins/dark/textures/preview.png differ diff --git a/indra/newview/skins/dark/textures/spacer24.tga b/indra/newview/skins/dark/textures/spacer24.tga deleted file mode 100644 index c7cab6b38c..0000000000 Binary files a/indra/newview/skins/dark/textures/spacer24.tga and /dev/null differ diff --git a/indra/newview/skins/dark/textures/spacer35.tga b/indra/newview/skins/dark/textures/spacer35.tga deleted file mode 100644 index b88bc6680a..0000000000 Binary files a/indra/newview/skins/dark/textures/spacer35.tga and /dev/null differ diff --git a/indra/newview/skins/dark/textures/tabarea.tga b/indra/newview/skins/dark/textures/tabarea.tga deleted file mode 100644 index 5517aebfc8..0000000000 Binary files a/indra/newview/skins/dark/textures/tabarea.tga and /dev/null differ diff --git a/indra/newview/skins/dark/textures/textures.xml b/indra/newview/skins/dark/textures/textures.xml deleted file mode 100644 index 451b700622..0000000000 --- a/indra/newview/skins/dark/textures/textures.xml +++ /dev/null @@ -1,389 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/indra/newview/skins/darkcatalan/colors.xml b/indra/newview/skins/darkcatalan/colors.xml index e2579eeee5..5c8bb76be9 100644 --- a/indra/newview/skins/darkcatalan/colors.xml +++ b/indra/newview/skins/darkcatalan/colors.xml @@ -150,8 +150,6 @@ - - @@ -184,7 +182,6 @@ - diff --git a/indra/newview/skins/darkcatalan/textures/5748decc-f629-461c-9a36-a35a221fe21f.tga b/indra/newview/skins/darkcatalan/textures/5748decc-f629-461c-9a36-a35a221fe21f.tga deleted file mode 100644 index 55e3793097..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/5748decc-f629-461c-9a36-a35a221fe21f.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/account_id_green.tga b/indra/newview/skins/darkcatalan/textures/account_id_green.tga deleted file mode 100644 index 9be215eed4..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/account_id_green.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/account_id_orange.tga b/indra/newview/skins/darkcatalan/textures/account_id_orange.tga deleted file mode 100644 index 6b41e86632..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/account_id_orange.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/active_speakers.tga b/indra/newview/skins/darkcatalan/textures/active_speakers.tga deleted file mode 100644 index 02d3643d7f..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/active_speakers.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/alpha_gradient.tga b/indra/newview/skins/darkcatalan/textures/alpha_gradient.tga deleted file mode 100644 index 6fdba25d4e..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/alpha_gradient.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/avatar_gone.tga b/indra/newview/skins/darkcatalan/textures/avatar_gone.tga deleted file mode 100644 index e5c2c070bc..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/avatar_gone.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/avatar_new.tga b/indra/newview/skins/darkcatalan/textures/avatar_new.tga deleted file mode 100644 index 854b70c326..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/avatar_new.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/checkerboard_transparency_bg.png b/indra/newview/skins/darkcatalan/textures/checkerboard_transparency_bg.png deleted file mode 100644 index 9a16935204..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/checkerboard_transparency_bg.png and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/circle.tga b/indra/newview/skins/darkcatalan/textures/circle.tga deleted file mode 100644 index d7097e3a35..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/circle.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/close_in_blue.tga b/indra/newview/skins/darkcatalan/textures/close_in_blue.tga deleted file mode 100644 index 8200eba327..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/close_in_blue.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/close_inactive_blue.tga b/indra/newview/skins/darkcatalan/textures/close_inactive_blue.tga deleted file mode 100644 index 191c5d3e80..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/close_inactive_blue.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/closebox.tga b/indra/newview/skins/darkcatalan/textures/closebox.tga deleted file mode 100644 index 294d4fb241..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/closebox.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/color_swatch_alpha.tga b/indra/newview/skins/darkcatalan/textures/color_swatch_alpha.tga deleted file mode 100644 index 814a004e62..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/color_swatch_alpha.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/combobox_arrow.tga b/indra/newview/skins/darkcatalan/textures/combobox_arrow.tga deleted file mode 100644 index ad08f32bb5..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/combobox_arrow.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/crosshairs.tga b/indra/newview/skins/darkcatalan/textures/crosshairs.tga deleted file mode 100644 index ac4d63dc59..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/crosshairs.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/darkgray.tga b/indra/newview/skins/darkcatalan/textures/darkgray.tga deleted file mode 100644 index 2063d685aa..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/darkgray.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/down_arrow.png b/indra/newview/skins/darkcatalan/textures/down_arrow.png deleted file mode 100644 index 155f80c97e..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/down_arrow.png and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/folder_arrow.tga b/indra/newview/skins/darkcatalan/textures/folder_arrow.tga deleted file mode 100644 index 77d470731b..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/folder_arrow.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/icn_active-speakers-dot-lvl0.tga b/indra/newview/skins/darkcatalan/textures/icn_active-speakers-dot-lvl0.tga deleted file mode 100644 index 35846cef32..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/icn_active-speakers-dot-lvl0.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/icn_active-speakers-dot-lvl1.tga b/indra/newview/skins/darkcatalan/textures/icn_active-speakers-dot-lvl1.tga deleted file mode 100644 index 1f9f564fa9..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/icn_active-speakers-dot-lvl1.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/icn_active-speakers-dot-lvl2.tga b/indra/newview/skins/darkcatalan/textures/icn_active-speakers-dot-lvl2.tga deleted file mode 100644 index b2e5609f1f..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/icn_active-speakers-dot-lvl2.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/icn_active-speakers-typing1.tga b/indra/newview/skins/darkcatalan/textures/icn_active-speakers-typing1.tga deleted file mode 100644 index 3706c96e0f..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/icn_active-speakers-typing1.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/icn_active-speakers-typing2.tga b/indra/newview/skins/darkcatalan/textures/icn_active-speakers-typing2.tga deleted file mode 100644 index 0d127f9461..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/icn_active-speakers-typing2.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/icn_active-speakers-typing3.tga b/indra/newview/skins/darkcatalan/textures/icn_active-speakers-typing3.tga deleted file mode 100644 index 031b3ad344..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/icn_active-speakers-typing3.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/icn_clear_lineeditor.tga b/indra/newview/skins/darkcatalan/textures/icn_clear_lineeditor.tga deleted file mode 100644 index 8cd8310c66..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/icn_clear_lineeditor.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/icn_rounded-text-field.tga b/indra/newview/skins/darkcatalan/textures/icn_rounded-text-field.tga deleted file mode 100644 index 7da504f93f..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/icn_rounded-text-field.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/icn_scrollbar.tga b/indra/newview/skins/darkcatalan/textures/icn_scrollbar.tga deleted file mode 100644 index a19a8a5d1a..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/icn_scrollbar.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/icn_scrollbar_bg.tga b/indra/newview/skins/darkcatalan/textures/icn_scrollbar_bg.tga deleted file mode 100644 index 1e4bc7a8a3..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/icn_scrollbar_bg.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/icn_scrollbar_thumb.tga b/indra/newview/skins/darkcatalan/textures/icn_scrollbar_thumb.tga deleted file mode 100644 index d63c314724..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/icn_scrollbar_thumb.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/icn_speaker-muted_dark.tga b/indra/newview/skins/darkcatalan/textures/icn_speaker-muted_dark.tga deleted file mode 100644 index a7d29a14b9..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/icn_speaker-muted_dark.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/icn_textfield_enabled.tga b/indra/newview/skins/darkcatalan/textures/icn_textfield_enabled.tga deleted file mode 100644 index fc681a1957..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/icn_textfield_enabled.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/icn_voice-call-end.tga b/indra/newview/skins/darkcatalan/textures/icn_voice-call-end.tga deleted file mode 100644 index 2da4e856b4..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/icn_voice-call-end.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/icn_voice-call-start.tga b/indra/newview/skins/darkcatalan/textures/icn_voice-call-start.tga deleted file mode 100644 index 07701cb5a2..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/icn_voice-call-start.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/icn_voice-groupfocus.tga b/indra/newview/skins/darkcatalan/textures/icn_voice-groupfocus.tga deleted file mode 100644 index 9f48d4609d..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/icn_voice-groupfocus.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/icn_voice-pvtfocus.tga b/indra/newview/skins/darkcatalan/textures/icn_voice-pvtfocus.tga deleted file mode 100644 index abadb09aaf..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/icn_voice-pvtfocus.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/icn_voice_ptt-on-lvl1.tga b/indra/newview/skins/darkcatalan/textures/icn_voice_ptt-on-lvl1.tga deleted file mode 100644 index ae72af131d..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/icn_voice_ptt-on-lvl1.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/icn_voice_ptt-on-lvl2.tga b/indra/newview/skins/darkcatalan/textures/icn_voice_ptt-on-lvl2.tga deleted file mode 100644 index 4dfc2dd292..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/icn_voice_ptt-on-lvl2.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/icn_voice_ptt-on-lvl3.tga b/indra/newview/skins/darkcatalan/textures/icn_voice_ptt-on-lvl3.tga deleted file mode 100644 index 018b0bef42..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/icn_voice_ptt-on-lvl3.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/icn_voice_ptt-on.tga b/indra/newview/skins/darkcatalan/textures/icn_voice_ptt-on.tga deleted file mode 100644 index 9eb6431106..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/icn_voice_ptt-on.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/icon_auction.tga b/indra/newview/skins/darkcatalan/textures/icon_auction.tga deleted file mode 100644 index d121833b47..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/icon_auction.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/icon_avatar_expand.png b/indra/newview/skins/darkcatalan/textures/icon_avatar_expand.png index 47698e9eb4..453a52c1da 100644 Binary files a/indra/newview/skins/darkcatalan/textures/icon_avatar_expand.png and b/indra/newview/skins/darkcatalan/textures/icon_avatar_expand.png differ diff --git a/indra/newview/skins/darkcatalan/textures/icon_day_cycle.tga b/indra/newview/skins/darkcatalan/textures/icon_day_cycle.tga deleted file mode 100644 index 2d5dee1e94..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/icon_day_cycle.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/icon_diurnal.tga b/indra/newview/skins/darkcatalan/textures/icon_diurnal.tga deleted file mode 100644 index fc720c8269..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/icon_diurnal.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/icon_event.tga b/indra/newview/skins/darkcatalan/textures/icon_event.tga deleted file mode 100644 index 7805dbce60..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/icon_event.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/icon_event_mature.tga b/indra/newview/skins/darkcatalan/textures/icon_event_mature.tga deleted file mode 100644 index 61c879bc92..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/icon_event_mature.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/icon_for_sale.tga b/indra/newview/skins/darkcatalan/textures/icon_for_sale.tga deleted file mode 100644 index 455b1aeb19..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/icon_for_sale.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/icon_group.tga b/indra/newview/skins/darkcatalan/textures/icon_group.tga deleted file mode 100644 index 22122d6cf1..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/icon_group.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/icon_groupnotice.tga b/indra/newview/skins/darkcatalan/textures/icon_groupnotice.tga deleted file mode 100644 index edf2c6180f..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/icon_groupnotice.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/icon_groupnoticeinventory.tga b/indra/newview/skins/darkcatalan/textures/icon_groupnoticeinventory.tga deleted file mode 100644 index f313906327..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/icon_groupnoticeinventory.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/icon_lock.tga b/indra/newview/skins/darkcatalan/textures/icon_lock.tga deleted file mode 100644 index 23521aa113..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/icon_lock.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/icon_place.tga b/indra/newview/skins/darkcatalan/textures/icon_place.tga deleted file mode 100644 index 2170c98499..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/icon_place.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/icon_popular.tga b/indra/newview/skins/darkcatalan/textures/icon_popular.tga deleted file mode 100644 index f1165b8aaa..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/icon_popular.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/inv_folder_animation.tga b/indra/newview/skins/darkcatalan/textures/inv_folder_animation.tga deleted file mode 100644 index 1b4df7a2d8..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/inv_folder_animation.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/inv_folder_bodypart.tga b/indra/newview/skins/darkcatalan/textures/inv_folder_bodypart.tga deleted file mode 100644 index abcb1bda71..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/inv_folder_bodypart.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/inv_folder_callingcard.tga b/indra/newview/skins/darkcatalan/textures/inv_folder_callingcard.tga deleted file mode 100644 index db7d8f7b0e..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/inv_folder_callingcard.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/inv_folder_clothing.tga b/indra/newview/skins/darkcatalan/textures/inv_folder_clothing.tga deleted file mode 100644 index d214789cb7..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/inv_folder_clothing.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/inv_folder_gesture.tga b/indra/newview/skins/darkcatalan/textures/inv_folder_gesture.tga deleted file mode 100644 index 83accbb1ea..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/inv_folder_gesture.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/inv_folder_landmark.tga b/indra/newview/skins/darkcatalan/textures/inv_folder_landmark.tga deleted file mode 100644 index 6923dd2283..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/inv_folder_landmark.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/inv_folder_lostandfound.tga b/indra/newview/skins/darkcatalan/textures/inv_folder_lostandfound.tga deleted file mode 100644 index 67f9a9a83c..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/inv_folder_lostandfound.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/inv_folder_notecard.tga b/indra/newview/skins/darkcatalan/textures/inv_folder_notecard.tga deleted file mode 100644 index 400ef3cc4e..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/inv_folder_notecard.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/inv_folder_object.tga b/indra/newview/skins/darkcatalan/textures/inv_folder_object.tga deleted file mode 100644 index c3d04bf27c..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/inv_folder_object.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/inv_folder_plain_closed.tga b/indra/newview/skins/darkcatalan/textures/inv_folder_plain_closed.tga deleted file mode 100644 index e351836e2d..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/inv_folder_plain_closed.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/inv_folder_plain_open.tga b/indra/newview/skins/darkcatalan/textures/inv_folder_plain_open.tga deleted file mode 100644 index 7bc80347b4..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/inv_folder_plain_open.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/inv_folder_script.tga b/indra/newview/skins/darkcatalan/textures/inv_folder_script.tga deleted file mode 100644 index 3e1a164da7..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/inv_folder_script.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/inv_folder_snapshot.tga b/indra/newview/skins/darkcatalan/textures/inv_folder_snapshot.tga deleted file mode 100644 index d32538d9ca..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/inv_folder_snapshot.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/inv_folder_sound.tga b/indra/newview/skins/darkcatalan/textures/inv_folder_sound.tga deleted file mode 100644 index 5e54c47746..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/inv_folder_sound.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/inv_folder_texture.tga b/indra/newview/skins/darkcatalan/textures/inv_folder_texture.tga deleted file mode 100644 index 4fe75d07df..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/inv_folder_texture.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/inv_folder_trash.tga b/indra/newview/skins/darkcatalan/textures/inv_folder_trash.tga deleted file mode 100644 index 54043e9cf7..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/inv_folder_trash.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/inv_item_animation.tga b/indra/newview/skins/darkcatalan/textures/inv_item_animation.tga deleted file mode 100644 index 2b12b28094..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/inv_item_animation.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/inv_item_attach.tga b/indra/newview/skins/darkcatalan/textures/inv_item_attach.tga deleted file mode 100644 index 0538993329..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/inv_item_attach.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/inv_item_callingcard_offline.tga b/indra/newview/skins/darkcatalan/textures/inv_item_callingcard_offline.tga deleted file mode 100644 index 44222d306c..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/inv_item_callingcard_offline.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/inv_item_callingcard_online.tga b/indra/newview/skins/darkcatalan/textures/inv_item_callingcard_online.tga deleted file mode 100644 index 42be4d2e13..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/inv_item_callingcard_online.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/inv_item_clothing.tga b/indra/newview/skins/darkcatalan/textures/inv_item_clothing.tga deleted file mode 100644 index 4c4c9391bd..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/inv_item_clothing.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/inv_item_eyes.tga b/indra/newview/skins/darkcatalan/textures/inv_item_eyes.tga deleted file mode 100644 index 053ffbe23d..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/inv_item_eyes.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/inv_item_gesture.tga b/indra/newview/skins/darkcatalan/textures/inv_item_gesture.tga deleted file mode 100644 index 52ac90c90d..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/inv_item_gesture.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/inv_item_gloves.tga b/indra/newview/skins/darkcatalan/textures/inv_item_gloves.tga deleted file mode 100644 index 26041711b4..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/inv_item_gloves.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/inv_item_hair.tga b/indra/newview/skins/darkcatalan/textures/inv_item_hair.tga deleted file mode 100644 index 03156a7b78..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/inv_item_hair.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/inv_item_jacket.tga b/indra/newview/skins/darkcatalan/textures/inv_item_jacket.tga deleted file mode 100644 index f37c593d85..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/inv_item_jacket.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/inv_item_landmark.tga b/indra/newview/skins/darkcatalan/textures/inv_item_landmark.tga deleted file mode 100644 index c161deb387..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/inv_item_landmark.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/inv_item_landmark_visited.tga b/indra/newview/skins/darkcatalan/textures/inv_item_landmark_visited.tga deleted file mode 100644 index 372a0f63ff..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/inv_item_landmark_visited.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/inv_item_notecard.tga b/indra/newview/skins/darkcatalan/textures/inv_item_notecard.tga deleted file mode 100644 index 2534d1b2a8..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/inv_item_notecard.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/inv_item_object.tga b/indra/newview/skins/darkcatalan/textures/inv_item_object.tga deleted file mode 100644 index edad15fdc7..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/inv_item_object.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/inv_item_object_multi.tga b/indra/newview/skins/darkcatalan/textures/inv_item_object_multi.tga deleted file mode 100644 index 7af666b61a..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/inv_item_object_multi.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/inv_item_pants.tga b/indra/newview/skins/darkcatalan/textures/inv_item_pants.tga deleted file mode 100644 index ec3246ea7a..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/inv_item_pants.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/inv_item_script.tga b/indra/newview/skins/darkcatalan/textures/inv_item_script.tga deleted file mode 100644 index e396d0986e..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/inv_item_script.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/inv_item_script_dangerous.tga b/indra/newview/skins/darkcatalan/textures/inv_item_script_dangerous.tga deleted file mode 100644 index 1ee742a8b6..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/inv_item_script_dangerous.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/inv_item_shape.tga b/indra/newview/skins/darkcatalan/textures/inv_item_shape.tga deleted file mode 100644 index 5d9db4e443..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/inv_item_shape.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/inv_item_shirt.tga b/indra/newview/skins/darkcatalan/textures/inv_item_shirt.tga deleted file mode 100644 index 2e1c627dad..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/inv_item_shirt.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/inv_item_shoes.tga b/indra/newview/skins/darkcatalan/textures/inv_item_shoes.tga deleted file mode 100644 index ae93bfe70b..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/inv_item_shoes.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/inv_item_skin.tga b/indra/newview/skins/darkcatalan/textures/inv_item_skin.tga deleted file mode 100644 index f0d7f2059d..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/inv_item_skin.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/inv_item_skirt.tga b/indra/newview/skins/darkcatalan/textures/inv_item_skirt.tga deleted file mode 100644 index d8f397285f..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/inv_item_skirt.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/inv_item_snapshot.tga b/indra/newview/skins/darkcatalan/textures/inv_item_snapshot.tga deleted file mode 100644 index c9d41a68db..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/inv_item_snapshot.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/inv_item_socks.tga b/indra/newview/skins/darkcatalan/textures/inv_item_socks.tga deleted file mode 100644 index dabcf6d821..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/inv_item_socks.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/inv_item_sound.tga b/indra/newview/skins/darkcatalan/textures/inv_item_sound.tga deleted file mode 100644 index efa113226b..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/inv_item_sound.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/inv_item_texture.tga b/indra/newview/skins/darkcatalan/textures/inv_item_texture.tga deleted file mode 100644 index fc5a42061e..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/inv_item_texture.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/inv_item_underpants.tga b/indra/newview/skins/darkcatalan/textures/inv_item_underpants.tga deleted file mode 100644 index e712f9c5d3..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/inv_item_underpants.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/inv_item_undershirt.tga b/indra/newview/skins/darkcatalan/textures/inv_item_undershirt.tga deleted file mode 100644 index c7b4aae786..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/inv_item_undershirt.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/lag_status_critical.tga b/indra/newview/skins/darkcatalan/textures/lag_status_critical.tga deleted file mode 100644 index bbc71d9e77..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/lag_status_critical.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/lag_status_good.tga b/indra/newview/skins/darkcatalan/textures/lag_status_good.tga deleted file mode 100644 index 680ba90f17..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/lag_status_good.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/lag_status_warning.tga b/indra/newview/skins/darkcatalan/textures/lag_status_warning.tga deleted file mode 100644 index 13ce3cc396..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/lag_status_warning.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/legend.tga b/indra/newview/skins/darkcatalan/textures/legend.tga deleted file mode 100644 index 0dbb8fda4f..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/legend.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/lightgray.tga b/indra/newview/skins/darkcatalan/textures/lightgray.tga deleted file mode 100644 index 2063d685aa..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/lightgray.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/map_avatar_16.tga b/indra/newview/skins/darkcatalan/textures/map_avatar_16.tga deleted file mode 100644 index ce129e3590..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/map_avatar_16.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/map_avatar_32.tga b/indra/newview/skins/darkcatalan/textures/map_avatar_32.tga deleted file mode 100644 index aebeab4093..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/map_avatar_32.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/map_avatar_8.tga b/indra/newview/skins/darkcatalan/textures/map_avatar_8.tga deleted file mode 100644 index 28552f2237..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/map_avatar_8.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/map_avatar_you_32.tga b/indra/newview/skins/darkcatalan/textures/map_avatar_you_32.tga deleted file mode 100644 index 782207efd6..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/map_avatar_you_32.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/map_avatar_you_8.tga b/indra/newview/skins/darkcatalan/textures/map_avatar_you_8.tga deleted file mode 100644 index 61f319fd9d..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/map_avatar_you_8.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/map_event.tga b/indra/newview/skins/darkcatalan/textures/map_event.tga deleted file mode 100644 index c229b379a2..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/map_event.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/map_event_mature.tga b/indra/newview/skins/darkcatalan/textures/map_event_mature.tga deleted file mode 100644 index 61c879bc92..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/map_event_mature.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/map_home.tga b/indra/newview/skins/darkcatalan/textures/map_home.tga deleted file mode 100644 index 7478de371a..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/map_home.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/map_infohub.tga b/indra/newview/skins/darkcatalan/textures/map_infohub.tga deleted file mode 100644 index d0134fa5fe..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/map_infohub.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/map_telehub.tga b/indra/newview/skins/darkcatalan/textures/map_telehub.tga deleted file mode 100644 index ef63a3eb72..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/map_telehub.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/map_track_16.tga b/indra/newview/skins/darkcatalan/textures/map_track_16.tga deleted file mode 100644 index 451ce24cf0..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/map_track_16.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/map_track_8.tga b/indra/newview/skins/darkcatalan/textures/map_track_8.tga deleted file mode 100644 index 53425ff45b..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/map_track_8.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/media_icon.tga b/indra/newview/skins/darkcatalan/textures/media_icon.tga deleted file mode 100644 index 289520cde8..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/media_icon.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/minimize.tga b/indra/newview/skins/darkcatalan/textures/minimize.tga deleted file mode 100644 index a21fd91481..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/minimize.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/minimize_inactive.tga b/indra/newview/skins/darkcatalan/textures/minimize_inactive.tga deleted file mode 100644 index fcd62aa35e..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/minimize_inactive.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/minimize_pressed.tga b/indra/newview/skins/darkcatalan/textures/minimize_pressed.tga deleted file mode 100644 index 0061dd5f5c..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/minimize_pressed.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/missing_asset.tga b/indra/newview/skins/darkcatalan/textures/missing_asset.tga deleted file mode 100644 index 9a43f4db5d..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/missing_asset.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/music_icon.tga b/indra/newview/skins/darkcatalan/textures/music_icon.tga deleted file mode 100644 index aeaff02e0a..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/music_icon.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/mute_icon.tga b/indra/newview/skins/darkcatalan/textures/mute_icon.tga deleted file mode 100644 index 879b9e6188..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/mute_icon.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/notify_caution_icon.tga b/indra/newview/skins/darkcatalan/textures/notify_caution_icon.tga deleted file mode 100644 index 48c76ad912..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/notify_caution_icon.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/notify_next.png b/indra/newview/skins/darkcatalan/textures/notify_next.png index 6faa14a996..d649a47755 100644 Binary files a/indra/newview/skins/darkcatalan/textures/notify_next.png and b/indra/newview/skins/darkcatalan/textures/notify_next.png differ diff --git a/indra/newview/skins/darkcatalan/textures/preview.png b/indra/newview/skins/darkcatalan/textures/preview.png index 2a9a6f5792..32c661b574 100644 Binary files a/indra/newview/skins/darkcatalan/textures/preview.png and b/indra/newview/skins/darkcatalan/textures/preview.png differ diff --git a/indra/newview/skins/darkcatalan/textures/propertyline.tga b/indra/newview/skins/darkcatalan/textures/propertyline.tga deleted file mode 100644 index 0c504eea71..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/propertyline.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/restore.tga b/indra/newview/skins/darkcatalan/textures/restore.tga deleted file mode 100644 index 87910e288e..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/restore.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/restore_inactive.tga b/indra/newview/skins/darkcatalan/textures/restore_inactive.tga deleted file mode 100644 index dbbec7ea1e..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/restore_inactive.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/restore_pressed.tga b/indra/newview/skins/darkcatalan/textures/restore_pressed.tga deleted file mode 100644 index 1922ca8815..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/restore_pressed.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/scrollbutton_down_in_blue.tga b/indra/newview/skins/darkcatalan/textures/scrollbutton_down_in_blue.tga deleted file mode 100644 index 5e73799505..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/scrollbutton_down_in_blue.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/scrollbutton_left_in_blue.tga b/indra/newview/skins/darkcatalan/textures/scrollbutton_left_in_blue.tga deleted file mode 100644 index 480842a3b5..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/scrollbutton_left_in_blue.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/scrollbutton_right_in_blue.tga b/indra/newview/skins/darkcatalan/textures/scrollbutton_right_in_blue.tga deleted file mode 100644 index 6d7f13bfcc..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/scrollbutton_right_in_blue.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/scrollbutton_up_in_blue.tga b/indra/newview/skins/darkcatalan/textures/scrollbutton_up_in_blue.tga deleted file mode 100644 index 4c6a8fe414..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/scrollbutton_up_in_blue.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/slim_icon_16_viewer.tga b/indra/newview/skins/darkcatalan/textures/slim_icon_16_viewer.tga deleted file mode 100644 index 552181d36a..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/slim_icon_16_viewer.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/sm_rounded_corners_simple.tga b/indra/newview/skins/darkcatalan/textures/sm_rounded_corners_simple.tga deleted file mode 100644 index 85157e4612..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/sm_rounded_corners_simple.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/smicon_warn.tga b/indra/newview/skins/darkcatalan/textures/smicon_warn.tga deleted file mode 100644 index 90ccaa07e5..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/smicon_warn.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/spacer24.tga b/indra/newview/skins/darkcatalan/textures/spacer24.tga deleted file mode 100644 index c7cab6b38c..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/spacer24.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/spacer35.tga b/indra/newview/skins/darkcatalan/textures/spacer35.tga deleted file mode 100644 index b88bc6680a..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/spacer35.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/startup_logo.jpg b/indra/newview/skins/darkcatalan/textures/startup_logo.jpg index 333df5779e..a2b127bc93 100644 Binary files a/indra/newview/skins/darkcatalan/textures/startup_logo.jpg and b/indra/newview/skins/darkcatalan/textures/startup_logo.jpg differ diff --git a/indra/newview/skins/darkcatalan/textures/status_busy.tga b/indra/newview/skins/darkcatalan/textures/status_busy.tga deleted file mode 100644 index 7743d9c7bb..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/status_busy.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/status_health.tga b/indra/newview/skins/darkcatalan/textures/status_health.tga deleted file mode 100644 index 3d5f455fcd..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/status_health.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/status_money.tga b/indra/newview/skins/darkcatalan/textures/status_money.tga deleted file mode 100644 index d5be31fc60..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/status_money.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/status_no_build.tga b/indra/newview/skins/darkcatalan/textures/status_no_build.tga deleted file mode 100644 index 8e471e1851..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/status_no_build.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/status_no_fly.tga b/indra/newview/skins/darkcatalan/textures/status_no_fly.tga deleted file mode 100644 index cde2700ab2..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/status_no_fly.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/status_no_push.tga b/indra/newview/skins/darkcatalan/textures/status_no_push.tga deleted file mode 100644 index 5ccbfa50f1..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/status_no_push.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/status_no_scripts.tga b/indra/newview/skins/darkcatalan/textures/status_no_scripts.tga deleted file mode 100644 index 52ecdb1b84..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/status_no_scripts.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/status_no_voice.tga b/indra/newview/skins/darkcatalan/textures/status_no_voice.tga deleted file mode 100644 index 4ab4498cbc..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/status_no_voice.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/status_script_debug.tga b/indra/newview/skins/darkcatalan/textures/status_script_debug.tga deleted file mode 100644 index 6fca614835..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/status_script_debug.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/status_search.tga b/indra/newview/skins/darkcatalan/textures/status_search.tga deleted file mode 100644 index 3ac10c4769..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/status_search.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/status_search_btn.png b/indra/newview/skins/darkcatalan/textures/status_search_btn.png deleted file mode 100644 index 67f61332bc..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/status_search_btn.png and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/status_search_btn_pressed.png b/indra/newview/skins/darkcatalan/textures/status_search_btn_pressed.png deleted file mode 100644 index 1437273d37..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/status_search_btn_pressed.png and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/status_voice.tga b/indra/newview/skins/darkcatalan/textures/status_voice.tga deleted file mode 100644 index 4ab4498cbc..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/status_voice.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/tab_background_darkpurple.tga b/indra/newview/skins/darkcatalan/textures/tab_background_darkpurple.tga deleted file mode 100644 index 8169f98694..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/tab_background_darkpurple.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/tab_background_lightgrey.tga b/indra/newview/skins/darkcatalan/textures/tab_background_lightgrey.tga deleted file mode 100644 index c2f8818f73..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/tab_background_lightgrey.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/tab_background_purple.tga b/indra/newview/skins/darkcatalan/textures/tab_background_purple.tga deleted file mode 100644 index aa01b3cb68..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/tab_background_purple.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/tabarea.tga b/indra/newview/skins/darkcatalan/textures/tabarea.tga deleted file mode 100644 index 5517aebfc8..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/tabarea.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/tearoff_pressed.tga b/indra/newview/skins/darkcatalan/textures/tearoff_pressed.tga deleted file mode 100644 index 620d109de0..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/tearoff_pressed.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/tearoffbox.tga b/indra/newview/skins/darkcatalan/textures/tearoffbox.tga deleted file mode 100644 index 0670d2e91b..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/tearoffbox.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/textures.xml b/indra/newview/skins/darkcatalan/textures/textures.xml index 2c4b0cbea6..48fcecbfeb 100644 --- a/indra/newview/skins/darkcatalan/textures/textures.xml +++ b/indra/newview/skins/darkcatalan/textures/textures.xml @@ -1,382 +1,3 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/indra/newview/skins/darkcatalan/textures/up_arrow.png b/indra/newview/skins/darkcatalan/textures/up_arrow.png index 601dc39f45..02d93c4379 100644 Binary files a/indra/newview/skins/darkcatalan/textures/up_arrow.png and b/indra/newview/skins/darkcatalan/textures/up_arrow.png differ diff --git a/indra/newview/skins/darkcatalan/textures/uv_test2.tga b/indra/newview/skins/darkcatalan/textures/uv_test2.tga deleted file mode 100644 index a16000d1e4..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/uv_test2.tga and /dev/null differ diff --git a/indra/newview/skins/darkcatalan/textures/white.tga b/indra/newview/skins/darkcatalan/textures/white.tga deleted file mode 100644 index 9fe68631cf..0000000000 Binary files a/indra/newview/skins/darkcatalan/textures/white.tga and /dev/null differ diff --git a/indra/newview/skins/darkgred/colors.xml b/indra/newview/skins/darkgred/colors.xml index 22034c2520..f79be836ea 100644 --- a/indra/newview/skins/darkgred/colors.xml +++ b/indra/newview/skins/darkgred/colors.xml @@ -100,6 +100,7 @@ + @@ -184,11 +185,6 @@ - - - - - diff --git a/indra/newview/skins/darkgred/textures/alpha_gradient.tga b/indra/newview/skins/darkgred/textures/alpha_gradient.tga deleted file mode 100644 index 6fdba25d4e..0000000000 Binary files a/indra/newview/skins/darkgred/textures/alpha_gradient.tga and /dev/null differ diff --git a/indra/newview/skins/darkgred/textures/circle.tga b/indra/newview/skins/darkgred/textures/circle.tga deleted file mode 100644 index d7097e3a35..0000000000 Binary files a/indra/newview/skins/darkgred/textures/circle.tga and /dev/null differ diff --git a/indra/newview/skins/darkgred/textures/color_swatch_alpha.tga b/indra/newview/skins/darkgred/textures/color_swatch_alpha.tga deleted file mode 100644 index 814a004e62..0000000000 Binary files a/indra/newview/skins/darkgred/textures/color_swatch_alpha.tga and /dev/null differ diff --git a/indra/newview/skins/darkgred/textures/crosshairs.tga b/indra/newview/skins/darkgred/textures/crosshairs.tga deleted file mode 100644 index ac4d63dc59..0000000000 Binary files a/indra/newview/skins/darkgred/textures/crosshairs.tga and /dev/null differ diff --git a/indra/newview/skins/darkgred/textures/direction_arrow.tga b/indra/newview/skins/darkgred/textures/direction_arrow.tga deleted file mode 100644 index f3ef1068c4..0000000000 Binary files a/indra/newview/skins/darkgred/textures/direction_arrow.tga and /dev/null differ diff --git a/indra/newview/skins/darkgred/textures/ff_edit_mine.tga b/indra/newview/skins/darkgred/textures/ff_edit_mine.tga deleted file mode 100644 index 8f0c35b98f..0000000000 Binary files a/indra/newview/skins/darkgred/textures/ff_edit_mine.tga and /dev/null differ diff --git a/indra/newview/skins/darkgred/textures/ff_edit_theirs.tga b/indra/newview/skins/darkgred/textures/ff_edit_theirs.tga deleted file mode 100644 index 005ada2dea..0000000000 Binary files a/indra/newview/skins/darkgred/textures/ff_edit_theirs.tga and /dev/null differ diff --git a/indra/newview/skins/darkgred/textures/icn_clear_lineeditor.tga b/indra/newview/skins/darkgred/textures/icn_clear_lineeditor.tga deleted file mode 100644 index 8cd8310c66..0000000000 Binary files a/indra/newview/skins/darkgred/textures/icn_clear_lineeditor.tga and /dev/null differ diff --git a/indra/newview/skins/darkgred/textures/icn_scrollbar.tga b/indra/newview/skins/darkgred/textures/icn_scrollbar.tga deleted file mode 100644 index a19a8a5d1a..0000000000 Binary files a/indra/newview/skins/darkgred/textures/icn_scrollbar.tga and /dev/null differ diff --git a/indra/newview/skins/darkgred/textures/map_avatar_above_8.tga b/indra/newview/skins/darkgred/textures/map_avatar_above_8.tga deleted file mode 100644 index 193428e530..0000000000 Binary files a/indra/newview/skins/darkgred/textures/map_avatar_above_8.tga and /dev/null differ diff --git a/indra/newview/skins/darkgred/textures/map_avatar_below_8.tga b/indra/newview/skins/darkgred/textures/map_avatar_below_8.tga deleted file mode 100644 index 9e14bfab90..0000000000 Binary files a/indra/newview/skins/darkgred/textures/map_avatar_below_8.tga and /dev/null differ diff --git a/indra/newview/skins/darkgred/textures/notify_next.png b/indra/newview/skins/darkgred/textures/notify_next.png index b57c26e265..83603835d1 100644 Binary files a/indra/newview/skins/darkgred/textures/notify_next.png and b/indra/newview/skins/darkgred/textures/notify_next.png differ diff --git a/indra/newview/skins/darkgred/textures/preview.png b/indra/newview/skins/darkgred/textures/preview.png index af76801166..598cf053c6 100644 Binary files a/indra/newview/skins/darkgred/textures/preview.png and b/indra/newview/skins/darkgred/textures/preview.png differ diff --git a/indra/newview/skins/darkgred/textures/propertyline.tga b/indra/newview/skins/darkgred/textures/propertyline.tga deleted file mode 100644 index 0c504eea71..0000000000 Binary files a/indra/newview/skins/darkgred/textures/propertyline.tga and /dev/null differ diff --git a/indra/newview/skins/darkgred/textures/tabarea.tga b/indra/newview/skins/darkgred/textures/tabarea.tga deleted file mode 100644 index 5517aebfc8..0000000000 Binary files a/indra/newview/skins/darkgred/textures/tabarea.tga and /dev/null differ diff --git a/indra/newview/skins/darkgred/textures/textures.xml b/indra/newview/skins/darkgred/textures/textures.xml deleted file mode 100644 index 451b700622..0000000000 --- a/indra/newview/skins/darkgred/textures/textures.xml +++ /dev/null @@ -1,389 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/indra/newview/skins/darkgreen/colors.xml b/indra/newview/skins/darkgreen/colors.xml new file mode 100644 index 0000000000..4745c72dd7 --- /dev/null +++ b/indra/newview/skins/darkgreen/colors.xml @@ -0,0 +1,201 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/indra/newview/skins/darkgreen/textures/0098b015-3daf-4cfe-a72f-915369ea97c2.tga b/indra/newview/skins/darkgreen/textures/0098b015-3daf-4cfe-a72f-915369ea97c2.tga new file mode 100644 index 0000000000..a563672f7b Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/0098b015-3daf-4cfe-a72f-915369ea97c2.tga differ diff --git a/indra/newview/skins/darkgreen/textures/3c18c87e-5f50-14e2-e744-f44734aa365f.tga b/indra/newview/skins/darkgreen/textures/3c18c87e-5f50-14e2-e744-f44734aa365f.tga new file mode 100644 index 0000000000..f7841968a9 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/3c18c87e-5f50-14e2-e744-f44734aa365f.tga differ diff --git a/indra/newview/skins/darkgreen/textures/7a0b1bdb-b5d9-4df5-bac2-ba230da93b5b.tga b/indra/newview/skins/darkgreen/textures/7a0b1bdb-b5d9-4df5-bac2-ba230da93b5b.tga new file mode 100644 index 0000000000..dd57c8027d Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/7a0b1bdb-b5d9-4df5-bac2-ba230da93b5b.tga differ diff --git a/indra/newview/skins/darkgreen/textures/7dabc040-ec13-2309-ddf7-4f161f6de2f4.tga b/indra/newview/skins/darkgreen/textures/7dabc040-ec13-2309-ddf7-4f161f6de2f4.tga new file mode 100644 index 0000000000..132b192ef1 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/7dabc040-ec13-2309-ddf7-4f161f6de2f4.tga differ diff --git a/indra/newview/skins/darkgreen/textures/89e9fc7c-0b16-457d-be4f-136270759c4d.tga b/indra/newview/skins/darkgreen/textures/89e9fc7c-0b16-457d-be4f-136270759c4d.tga new file mode 100644 index 0000000000..6cc9ea1942 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/89e9fc7c-0b16-457d-be4f-136270759c4d.tga differ diff --git a/indra/newview/skins/darkgreen/textures/9cad3e6d-2d6d-107d-f8ab-5ba272b5bfe1.tga b/indra/newview/skins/darkgreen/textures/9cad3e6d-2d6d-107d-f8ab-5ba272b5bfe1.tga new file mode 100644 index 0000000000..ceaaabab83 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/9cad3e6d-2d6d-107d-f8ab-5ba272b5bfe1.tga differ diff --git a/indra/newview/skins/darkgreen/textures/active_speakers.tga b/indra/newview/skins/darkgreen/textures/active_speakers.tga new file mode 100644 index 0000000000..37521d2dd0 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/active_speakers.tga differ diff --git a/indra/newview/skins/darkgreen/textures/active_voice_tab.tga b/indra/newview/skins/darkgreen/textures/active_voice_tab.tga new file mode 100644 index 0000000000..1a68c98e30 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/active_voice_tab.tga differ diff --git a/indra/newview/skins/darkgreen/textures/arrow_down.tga b/indra/newview/skins/darkgreen/textures/arrow_down.tga new file mode 100644 index 0000000000..5b05df1c29 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/arrow_down.tga differ diff --git a/indra/newview/skins/darkgreen/textures/arrow_up.tga b/indra/newview/skins/darkgreen/textures/arrow_up.tga new file mode 100644 index 0000000000..abe5c20a89 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/arrow_up.tga differ diff --git a/indra/newview/skins/darkgreen/textures/b4870163-6208-42a9-9801-93133bf9a6cd.tga b/indra/newview/skins/darkgreen/textures/b4870163-6208-42a9-9801-93133bf9a6cd.tga new file mode 100644 index 0000000000..66c9dc4e07 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/b4870163-6208-42a9-9801-93133bf9a6cd.tga differ diff --git a/indra/newview/skins/darkgreen/textures/black.tga b/indra/newview/skins/darkgreen/textures/black.tga new file mode 100644 index 0000000000..e368ea4967 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/black.tga differ diff --git a/indra/newview/skins/darkgreen/textures/btn_chatbar.tga b/indra/newview/skins/darkgreen/textures/btn_chatbar.tga new file mode 100644 index 0000000000..76008aef0c Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/btn_chatbar.tga differ diff --git a/indra/newview/skins/darkgreen/textures/btn_chatbar_selected.tga b/indra/newview/skins/darkgreen/textures/btn_chatbar_selected.tga new file mode 100644 index 0000000000..1698e72c2c Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/btn_chatbar_selected.tga differ diff --git a/indra/newview/skins/darkgreen/textures/button_anim_pause.tga b/indra/newview/skins/darkgreen/textures/button_anim_pause.tga new file mode 100644 index 0000000000..2d9f2b504c Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/button_anim_pause.tga differ diff --git a/indra/newview/skins/darkgreen/textures/button_anim_pause_selected.tga b/indra/newview/skins/darkgreen/textures/button_anim_pause_selected.tga new file mode 100644 index 0000000000..f75b97d6d2 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/button_anim_pause_selected.tga differ diff --git a/indra/newview/skins/darkgreen/textures/button_anim_play.tga b/indra/newview/skins/darkgreen/textures/button_anim_play.tga new file mode 100644 index 0000000000..37e9c7ec1d Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/button_anim_play.tga differ diff --git a/indra/newview/skins/darkgreen/textures/button_anim_play_selected.tga b/indra/newview/skins/darkgreen/textures/button_anim_play_selected.tga new file mode 100644 index 0000000000..21d1c6db9a Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/button_anim_play_selected.tga differ diff --git a/indra/newview/skins/darkgreen/textures/button_anim_stop.tga b/indra/newview/skins/darkgreen/textures/button_anim_stop.tga new file mode 100644 index 0000000000..0888969556 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/button_anim_stop.tga differ diff --git a/indra/newview/skins/darkgreen/textures/button_anim_stop_selected.tga b/indra/newview/skins/darkgreen/textures/button_anim_stop_selected.tga new file mode 100644 index 0000000000..46cce99d0c Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/button_anim_stop_selected.tga differ diff --git a/indra/newview/skins/darkgreen/textures/button_disabled_32x128.tga b/indra/newview/skins/darkgreen/textures/button_disabled_32x128.tga new file mode 100644 index 0000000000..c3f0ad7760 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/button_disabled_32x128.tga differ diff --git a/indra/newview/skins/darkgreen/textures/button_enabled_32x128.tga b/indra/newview/skins/darkgreen/textures/button_enabled_32x128.tga new file mode 100644 index 0000000000..acfa33e7f5 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/button_enabled_32x128.tga differ diff --git a/indra/newview/skins/darkgreen/textures/button_enabled_selected_32x128.tga b/indra/newview/skins/darkgreen/textures/button_enabled_selected_32x128.tga new file mode 100644 index 0000000000..3823bc1943 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/button_enabled_selected_32x128.tga differ diff --git a/indra/newview/skins/darkgreen/textures/c1e21504-f136-451d-b8e9-929037812f1d.tga b/indra/newview/skins/darkgreen/textures/c1e21504-f136-451d-b8e9-929037812f1d.tga new file mode 100644 index 0000000000..6430fce181 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/c1e21504-f136-451d-b8e9-929037812f1d.tga differ diff --git a/indra/newview/skins/darkgreen/textures/c63f124c-6340-4fbf-b59e-0869a44adb64.tga b/indra/newview/skins/darkgreen/textures/c63f124c-6340-4fbf-b59e-0869a44adb64.tga new file mode 100644 index 0000000000..8b743416e4 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/c63f124c-6340-4fbf-b59e-0869a44adb64.tga differ diff --git a/indra/newview/skins/darkgreen/textures/cam_rotate_in.tga b/indra/newview/skins/darkgreen/textures/cam_rotate_in.tga new file mode 100644 index 0000000000..d08f980593 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/cam_rotate_in.tga differ diff --git a/indra/newview/skins/darkgreen/textures/cam_rotate_out.tga b/indra/newview/skins/darkgreen/textures/cam_rotate_out.tga new file mode 100644 index 0000000000..f8f64f1df2 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/cam_rotate_out.tga differ diff --git a/indra/newview/skins/darkgreen/textures/cam_tracking_in.tga b/indra/newview/skins/darkgreen/textures/cam_tracking_in.tga new file mode 100644 index 0000000000..562c951be7 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/cam_tracking_in.tga differ diff --git a/indra/newview/skins/darkgreen/textures/cam_tracking_out.tga b/indra/newview/skins/darkgreen/textures/cam_tracking_out.tga new file mode 100644 index 0000000000..7835704d1e Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/cam_tracking_out.tga differ diff --git a/indra/newview/skins/darkgreen/textures/cam_zoom_minus_in.tga b/indra/newview/skins/darkgreen/textures/cam_zoom_minus_in.tga new file mode 100644 index 0000000000..a1da27bf89 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/cam_zoom_minus_in.tga differ diff --git a/indra/newview/skins/darkgreen/textures/cam_zoom_out.tga b/indra/newview/skins/darkgreen/textures/cam_zoom_out.tga new file mode 100644 index 0000000000..2e9519d724 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/cam_zoom_out.tga differ diff --git a/indra/newview/skins/darkgreen/textures/cam_zoom_plus_in.tga b/indra/newview/skins/darkgreen/textures/cam_zoom_plus_in.tga new file mode 100644 index 0000000000..c17d60792b Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/cam_zoom_plus_in.tga differ diff --git a/indra/newview/skins/darkgreen/textures/ce15fd63-b0b6-463c-a37d-ea6393208b3e.tga b/indra/newview/skins/darkgreen/textures/ce15fd63-b0b6-463c-a37d-ea6393208b3e.tga new file mode 100644 index 0000000000..046e696881 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/ce15fd63-b0b6-463c-a37d-ea6393208b3e.tga differ diff --git a/indra/newview/skins/darkgreen/textures/checkbox_disabled_false.tga b/indra/newview/skins/darkgreen/textures/checkbox_disabled_false.tga new file mode 100644 index 0000000000..074ded7321 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/checkbox_disabled_false.tga differ diff --git a/indra/newview/skins/darkgreen/textures/checkbox_disabled_true.tga b/indra/newview/skins/darkgreen/textures/checkbox_disabled_true.tga new file mode 100644 index 0000000000..79d25902f2 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/checkbox_disabled_true.tga differ diff --git a/indra/newview/skins/darkgreen/textures/checkbox_enabled_false.tga b/indra/newview/skins/darkgreen/textures/checkbox_enabled_false.tga new file mode 100644 index 0000000000..c29ed89c64 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/checkbox_enabled_false.tga differ diff --git a/indra/newview/skins/darkgreen/textures/checkbox_enabled_true.tga b/indra/newview/skins/darkgreen/textures/checkbox_enabled_true.tga new file mode 100644 index 0000000000..c8904bc603 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/checkbox_enabled_true.tga differ diff --git a/indra/newview/skins/darkgreen/textures/close_in_blue.tga b/indra/newview/skins/darkgreen/textures/close_in_blue.tga new file mode 100644 index 0000000000..a1a421e412 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/close_in_blue.tga differ diff --git a/indra/newview/skins/darkgreen/textures/close_inactive.tga b/indra/newview/skins/darkgreen/textures/close_inactive.tga new file mode 100644 index 0000000000..30f6e7b5ff Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/close_inactive.tga differ diff --git a/indra/newview/skins/darkgreen/textures/close_inactive_blue.tga b/indra/newview/skins/darkgreen/textures/close_inactive_blue.tga new file mode 100644 index 0000000000..30f6e7b5ff Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/close_inactive_blue.tga differ diff --git a/indra/newview/skins/darkgreen/textures/closebox.tga b/indra/newview/skins/darkgreen/textures/closebox.tga new file mode 100644 index 0000000000..96488b4da7 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/closebox.tga differ diff --git a/indra/newview/skins/darkgreen/textures/combobox_arrow.tga b/indra/newview/skins/darkgreen/textures/combobox_arrow.tga new file mode 100644 index 0000000000..d769d31055 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/combobox_arrow.tga differ diff --git a/indra/newview/skins/darkorange/textures/black.tga b/indra/newview/skins/darkgreen/textures/darkgray.tga similarity index 100% rename from indra/newview/skins/darkorange/textures/black.tga rename to indra/newview/skins/darkgreen/textures/darkgray.tga diff --git a/indra/newview/skins/darkgreen/textures/eye_button_active.tga b/indra/newview/skins/darkgreen/textures/eye_button_active.tga new file mode 100644 index 0000000000..cac3de5337 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/eye_button_active.tga differ diff --git a/indra/newview/skins/darkgreen/textures/eye_button_inactive.tga b/indra/newview/skins/darkgreen/textures/eye_button_inactive.tga new file mode 100644 index 0000000000..6ca8feec82 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/eye_button_inactive.tga differ diff --git a/indra/newview/skins/darkgreen/textures/ff9a71eb-7414-4cf8-866e-a701deb7c3cf.tga b/indra/newview/skins/darkgreen/textures/ff9a71eb-7414-4cf8-866e-a701deb7c3cf.tga new file mode 100644 index 0000000000..8b9d012a9b Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/ff9a71eb-7414-4cf8-866e-a701deb7c3cf.tga differ diff --git a/indra/newview/skins/darkgreen/textures/ff_edit_mine_button.tga b/indra/newview/skins/darkgreen/textures/ff_edit_mine_button.tga new file mode 100644 index 0000000000..01770a3c44 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/ff_edit_mine_button.tga differ diff --git a/indra/newview/skins/darkgreen/textures/ff_edit_theirs_button.tga b/indra/newview/skins/darkgreen/textures/ff_edit_theirs_button.tga new file mode 100644 index 0000000000..78a23b0b78 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/ff_edit_theirs_button.tga differ diff --git a/indra/newview/skins/darkgreen/textures/ff_online_status_button.tga b/indra/newview/skins/darkgreen/textures/ff_online_status_button.tga new file mode 100644 index 0000000000..79f2918299 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/ff_online_status_button.tga differ diff --git a/indra/newview/skins/darkgreen/textures/ff_visible_map_button.tga b/indra/newview/skins/darkgreen/textures/ff_visible_map_button.tga new file mode 100644 index 0000000000..bce9a8c617 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/ff_visible_map_button.tga differ diff --git a/indra/newview/skins/darkgreen/textures/ff_visible_online_button.tga b/indra/newview/skins/darkgreen/textures/ff_visible_online_button.tga new file mode 100644 index 0000000000..c888b08c7e Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/ff_visible_online_button.tga differ diff --git a/indra/newview/skins/darkgreen/textures/flyout_btn_left.tga b/indra/newview/skins/darkgreen/textures/flyout_btn_left.tga new file mode 100644 index 0000000000..3060d8016b Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/flyout_btn_left.tga differ diff --git a/indra/newview/skins/darkgreen/textures/flyout_btn_left_disabled.tga b/indra/newview/skins/darkgreen/textures/flyout_btn_left_disabled.tga new file mode 100644 index 0000000000..060a56bd3d Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/flyout_btn_left_disabled.tga differ diff --git a/indra/newview/skins/darkgreen/textures/flyout_btn_left_selected.tga b/indra/newview/skins/darkgreen/textures/flyout_btn_left_selected.tga new file mode 100644 index 0000000000..9965fb4164 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/flyout_btn_left_selected.tga differ diff --git a/indra/newview/skins/darkgreen/textures/flyout_btn_right.tga b/indra/newview/skins/darkgreen/textures/flyout_btn_right.tga new file mode 100644 index 0000000000..0a2354ef56 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/flyout_btn_right.tga differ diff --git a/indra/newview/skins/darkgreen/textures/flyout_btn_right_disabled.tga b/indra/newview/skins/darkgreen/textures/flyout_btn_right_disabled.tga new file mode 100644 index 0000000000..9050e1252c Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/flyout_btn_right_disabled.tga differ diff --git a/indra/newview/skins/darkgreen/textures/flyout_btn_right_selected.tga b/indra/newview/skins/darkgreen/textures/flyout_btn_right_selected.tga new file mode 100644 index 0000000000..58594daccd Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/flyout_btn_right_selected.tga differ diff --git a/indra/newview/skins/darkgreen/textures/icn_chatbar.tga b/indra/newview/skins/darkgreen/textures/icn_chatbar.tga new file mode 100644 index 0000000000..94fd6dc892 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/icn_chatbar.tga differ diff --git a/indra/newview/skins/darkgreen/textures/icn_media-pause_active.tga b/indra/newview/skins/darkgreen/textures/icn_media-pause_active.tga new file mode 100644 index 0000000000..8988829aa7 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/icn_media-pause_active.tga differ diff --git a/indra/newview/skins/darkgreen/textures/icn_media-pause_disabled.tga b/indra/newview/skins/darkgreen/textures/icn_media-pause_disabled.tga new file mode 100644 index 0000000000..4690f42561 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/icn_media-pause_disabled.tga differ diff --git a/indra/newview/skins/darkgreen/textures/icn_media-pause_enabled.tga b/indra/newview/skins/darkgreen/textures/icn_media-pause_enabled.tga new file mode 100644 index 0000000000..c01399e270 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/icn_media-pause_enabled.tga differ diff --git a/indra/newview/skins/darkgreen/textures/icn_media-play_enabled.tga b/indra/newview/skins/darkgreen/textures/icn_media-play_enabled.tga new file mode 100644 index 0000000000..accac38b02 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/icn_media-play_enabled.tga differ diff --git a/indra/newview/skins/darkgreen/textures/icn_media-stop_enabled.tga b/indra/newview/skins/darkgreen/textures/icn_media-stop_enabled.tga new file mode 100644 index 0000000000..d935fa3171 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/icn_media-stop_enabled.tga differ diff --git a/indra/newview/skins/darkgreen/textures/icn_media.tga b/indra/newview/skins/darkgreen/textures/icn_media.tga new file mode 100644 index 0000000000..2a035ba5df Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/icn_media.tga differ diff --git a/indra/newview/skins/darkgreen/textures/icn_music.tga b/indra/newview/skins/darkgreen/textures/icn_music.tga new file mode 100644 index 0000000000..81da5abcf2 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/icn_music.tga differ diff --git a/indra/newview/skins/darkgreen/textures/icn_scrollbar_bg.tga b/indra/newview/skins/darkgreen/textures/icn_scrollbar_bg.tga new file mode 100644 index 0000000000..cd484c61e8 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/icn_scrollbar_bg.tga differ diff --git a/indra/newview/skins/darkgreen/textures/icn_scrollbar_thumb.tga b/indra/newview/skins/darkgreen/textures/icn_scrollbar_thumb.tga new file mode 100644 index 0000000000..b11b1bdcdd Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/icn_scrollbar_thumb.tga differ diff --git a/indra/newview/skins/darkgreen/textures/icn_slide-groove_dark.tga b/indra/newview/skins/darkgreen/textures/icn_slide-groove_dark.tga new file mode 100644 index 0000000000..19361436ef Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/icn_slide-groove_dark.tga differ diff --git a/indra/newview/skins/darkgreen/textures/icn_slide-highlight.tga b/indra/newview/skins/darkgreen/textures/icn_slide-highlight.tga new file mode 100644 index 0000000000..0747e3ceb5 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/icn_slide-highlight.tga differ diff --git a/indra/newview/skins/darkgreen/textures/icn_slide-thumb_dark.tga b/indra/newview/skins/darkgreen/textures/icn_slide-thumb_dark.tga new file mode 100644 index 0000000000..7605b2c435 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/icn_slide-thumb_dark.tga differ diff --git a/indra/newview/skins/darkgreen/textures/icn_speaker-muted_dark.tga b/indra/newview/skins/darkgreen/textures/icn_speaker-muted_dark.tga new file mode 100644 index 0000000000..f53e8ccf3c Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/icn_speaker-muted_dark.tga differ diff --git a/indra/newview/skins/darkgreen/textures/icn_speaker_dark.tga b/indra/newview/skins/darkgreen/textures/icn_speaker_dark.tga new file mode 100644 index 0000000000..6b326cf5e0 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/icn_speaker_dark.tga differ diff --git a/indra/newview/skins/darkgreen/textures/icn_toolbar_build.tga b/indra/newview/skins/darkgreen/textures/icn_toolbar_build.tga new file mode 100644 index 0000000000..46e84efbcb Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/icn_toolbar_build.tga differ diff --git a/indra/newview/skins/darkgreen/textures/icn_toolbar_fly.tga b/indra/newview/skins/darkgreen/textures/icn_toolbar_fly.tga new file mode 100644 index 0000000000..8bd422ac58 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/icn_toolbar_fly.tga differ diff --git a/indra/newview/skins/darkgreen/textures/icn_toolbar_inventory.tga b/indra/newview/skins/darkgreen/textures/icn_toolbar_inventory.tga new file mode 100644 index 0000000000..b832ebce90 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/icn_toolbar_inventory.tga differ diff --git a/indra/newview/skins/darkgreen/textures/icn_toolbar_map.tga b/indra/newview/skins/darkgreen/textures/icn_toolbar_map.tga new file mode 100644 index 0000000000..a100f57842 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/icn_toolbar_map.tga differ diff --git a/indra/newview/skins/darkgreen/textures/icn_toolbar_minimap.tga b/indra/newview/skins/darkgreen/textures/icn_toolbar_minimap.tga new file mode 100644 index 0000000000..21149f3264 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/icn_toolbar_minimap.tga differ diff --git a/indra/newview/skins/darkgreen/textures/icn_toolbar_radar.tga b/indra/newview/skins/darkgreen/textures/icn_toolbar_radar.tga new file mode 100644 index 0000000000..d1a55ed74f Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/icn_toolbar_radar.tga differ diff --git a/indra/newview/skins/darkgreen/textures/icn_toolbar_search.tga b/indra/newview/skins/darkgreen/textures/icn_toolbar_search.tga new file mode 100644 index 0000000000..2da9704f1b Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/icn_toolbar_search.tga differ diff --git a/indra/newview/skins/darkgreen/textures/icn_toolbar_snapshot.tga b/indra/newview/skins/darkgreen/textures/icn_toolbar_snapshot.tga new file mode 100644 index 0000000000..23b97c0eb8 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/icn_toolbar_snapshot.tga differ diff --git a/indra/newview/skins/gemini/textures/black.tga b/indra/newview/skins/darkgreen/textures/lightgray.tga similarity index 100% rename from indra/newview/skins/gemini/textures/black.tga rename to indra/newview/skins/darkgreen/textures/lightgray.tga diff --git a/indra/newview/skins/darkgreen/textures/minimize.tga b/indra/newview/skins/darkgreen/textures/minimize.tga new file mode 100644 index 0000000000..35d2e9ada7 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/minimize.tga differ diff --git a/indra/newview/skins/darkgreen/textures/minimize_inactive.tga b/indra/newview/skins/darkgreen/textures/minimize_inactive.tga new file mode 100644 index 0000000000..8f09acda95 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/minimize_inactive.tga differ diff --git a/indra/newview/skins/darkgreen/textures/minimize_pressed.tga b/indra/newview/skins/darkgreen/textures/minimize_pressed.tga new file mode 100644 index 0000000000..bc03952e7d Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/minimize_pressed.tga differ diff --git a/indra/newview/skins/darkgreen/textures/move_backward_in.tga b/indra/newview/skins/darkgreen/textures/move_backward_in.tga new file mode 100644 index 0000000000..b64204eb2f Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/move_backward_in.tga differ diff --git a/indra/newview/skins/darkgreen/textures/move_backward_out.tga b/indra/newview/skins/darkgreen/textures/move_backward_out.tga new file mode 100644 index 0000000000..1acce4b7b1 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/move_backward_out.tga differ diff --git a/indra/newview/skins/darkgreen/textures/move_down_in.tga b/indra/newview/skins/darkgreen/textures/move_down_in.tga new file mode 100644 index 0000000000..904e9a8c82 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/move_down_in.tga differ diff --git a/indra/newview/skins/darkgreen/textures/move_down_out.tga b/indra/newview/skins/darkgreen/textures/move_down_out.tga new file mode 100644 index 0000000000..39bcda4c37 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/move_down_out.tga differ diff --git a/indra/newview/skins/darkgreen/textures/move_forward_in.tga b/indra/newview/skins/darkgreen/textures/move_forward_in.tga new file mode 100644 index 0000000000..d41a1e1edf Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/move_forward_in.tga differ diff --git a/indra/newview/skins/darkgreen/textures/move_forward_out.tga b/indra/newview/skins/darkgreen/textures/move_forward_out.tga new file mode 100644 index 0000000000..643c260667 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/move_forward_out.tga differ diff --git a/indra/newview/skins/darkgreen/textures/move_left_in.tga b/indra/newview/skins/darkgreen/textures/move_left_in.tga new file mode 100644 index 0000000000..f63ff2d4ae Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/move_left_in.tga differ diff --git a/indra/newview/skins/darkgreen/textures/move_left_out.tga b/indra/newview/skins/darkgreen/textures/move_left_out.tga new file mode 100644 index 0000000000..775bc151bc Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/move_left_out.tga differ diff --git a/indra/newview/skins/darkgreen/textures/move_right_in.tga b/indra/newview/skins/darkgreen/textures/move_right_in.tga new file mode 100644 index 0000000000..c85c4c3358 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/move_right_in.tga differ diff --git a/indra/newview/skins/darkgreen/textures/move_right_out.tga b/indra/newview/skins/darkgreen/textures/move_right_out.tga new file mode 100644 index 0000000000..729331d99a Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/move_right_out.tga differ diff --git a/indra/newview/skins/darkgreen/textures/move_turn_left_in.tga b/indra/newview/skins/darkgreen/textures/move_turn_left_in.tga new file mode 100644 index 0000000000..970b7f2eca Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/move_turn_left_in.tga differ diff --git a/indra/newview/skins/darkgreen/textures/move_turn_left_out.tga b/indra/newview/skins/darkgreen/textures/move_turn_left_out.tga new file mode 100644 index 0000000000..8c16775740 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/move_turn_left_out.tga differ diff --git a/indra/newview/skins/darkgreen/textures/move_turn_right_in.tga b/indra/newview/skins/darkgreen/textures/move_turn_right_in.tga new file mode 100644 index 0000000000..367deaeb90 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/move_turn_right_in.tga differ diff --git a/indra/newview/skins/darkgreen/textures/move_turn_right_out.tga b/indra/newview/skins/darkgreen/textures/move_turn_right_out.tga new file mode 100644 index 0000000000..3105adb7b0 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/move_turn_right_out.tga differ diff --git a/indra/newview/skins/darkgreen/textures/move_up_in.tga b/indra/newview/skins/darkgreen/textures/move_up_in.tga new file mode 100644 index 0000000000..f62727d90f Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/move_up_in.tga differ diff --git a/indra/newview/skins/darkgreen/textures/move_up_out.tga b/indra/newview/skins/darkgreen/textures/move_up_out.tga new file mode 100644 index 0000000000..777b221f80 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/move_up_out.tga differ diff --git a/indra/newview/skins/darkgreen/textures/notify_next.png b/indra/newview/skins/darkgreen/textures/notify_next.png new file mode 100644 index 0000000000..83603835d1 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/notify_next.png differ diff --git a/indra/newview/skins/darkgreen/textures/preview.png b/indra/newview/skins/darkgreen/textures/preview.png new file mode 100644 index 0000000000..7e17fec900 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/preview.png differ diff --git a/indra/newview/skins/darkgreen/textures/progress_fill.tga b/indra/newview/skins/darkgreen/textures/progress_fill.tga new file mode 100644 index 0000000000..bbdf5dd0b0 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/progress_fill.tga differ diff --git a/indra/newview/skins/darkgreen/textures/progressbar_fill.tga b/indra/newview/skins/darkgreen/textures/progressbar_fill.tga new file mode 100644 index 0000000000..7070343c0e Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/progressbar_fill.tga differ diff --git a/indra/newview/skins/darkgreen/textures/progressbar_track.tga b/indra/newview/skins/darkgreen/textures/progressbar_track.tga new file mode 100644 index 0000000000..3434330c14 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/progressbar_track.tga differ diff --git a/indra/newview/skins/darkgreen/textures/ptt_lock_off.tga b/indra/newview/skins/darkgreen/textures/ptt_lock_off.tga new file mode 100644 index 0000000000..cb68344692 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/ptt_lock_off.tga differ diff --git a/indra/newview/skins/darkgreen/textures/ptt_lock_on.tga b/indra/newview/skins/darkgreen/textures/ptt_lock_on.tga new file mode 100644 index 0000000000..5a7413bde5 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/ptt_lock_on.tga differ diff --git a/indra/newview/skins/darkgreen/textures/radio_active_false.tga b/indra/newview/skins/darkgreen/textures/radio_active_false.tga new file mode 100644 index 0000000000..15d5e5927b Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/radio_active_false.tga differ diff --git a/indra/newview/skins/darkgreen/textures/radio_active_true.tga b/indra/newview/skins/darkgreen/textures/radio_active_true.tga new file mode 100644 index 0000000000..cbef889139 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/radio_active_true.tga differ diff --git a/indra/newview/skins/darkgreen/textures/radio_inactive_false.tga b/indra/newview/skins/darkgreen/textures/radio_inactive_false.tga new file mode 100644 index 0000000000..48a934221e Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/radio_inactive_false.tga differ diff --git a/indra/newview/skins/darkgreen/textures/radio_inactive_true.tga b/indra/newview/skins/darkgreen/textures/radio_inactive_true.tga new file mode 100644 index 0000000000..785b3fa6de Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/radio_inactive_true.tga differ diff --git a/indra/newview/skins/darkgreen/textures/resize_handle_bottom_right_blue.tga b/indra/newview/skins/darkgreen/textures/resize_handle_bottom_right_blue.tga new file mode 100644 index 0000000000..b40ef7305c Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/resize_handle_bottom_right_blue.tga differ diff --git a/indra/newview/skins/darkgreen/textures/restore.tga b/indra/newview/skins/darkgreen/textures/restore.tga new file mode 100644 index 0000000000..904797e7e6 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/restore.tga differ diff --git a/indra/newview/skins/darkgreen/textures/restore_inactive.tga b/indra/newview/skins/darkgreen/textures/restore_inactive.tga new file mode 100644 index 0000000000..8f09acda95 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/restore_inactive.tga differ diff --git a/indra/newview/skins/darkgreen/textures/restore_pressed.tga b/indra/newview/skins/darkgreen/textures/restore_pressed.tga new file mode 100644 index 0000000000..c8ce0f9b9f Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/restore_pressed.tga differ diff --git a/indra/newview/skins/darkgreen/textures/rounded_square.tga b/indra/newview/skins/darkgreen/textures/rounded_square.tga new file mode 100644 index 0000000000..c8fc7b799f Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/rounded_square.tga differ diff --git a/indra/newview/skins/darkgreen/textures/rounded_square_soft.tga b/indra/newview/skins/darkgreen/textures/rounded_square_soft.tga new file mode 100644 index 0000000000..0e5bc79ac3 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/rounded_square_soft.tga differ diff --git a/indra/newview/skins/darkgreen/textures/scrollbutton_down_in_blue.tga b/indra/newview/skins/darkgreen/textures/scrollbutton_down_in_blue.tga new file mode 100644 index 0000000000..6a89d4ac74 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/scrollbutton_down_in_blue.tga differ diff --git a/indra/newview/skins/darkgreen/textures/scrollbutton_down_out_blue.tga b/indra/newview/skins/darkgreen/textures/scrollbutton_down_out_blue.tga new file mode 100644 index 0000000000..04e158ebad Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/scrollbutton_down_out_blue.tga differ diff --git a/indra/newview/skins/darkgreen/textures/scrollbutton_left_in_blue.tga b/indra/newview/skins/darkgreen/textures/scrollbutton_left_in_blue.tga new file mode 100644 index 0000000000..4efaa9908d Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/scrollbutton_left_in_blue.tga differ diff --git a/indra/newview/skins/darkgreen/textures/scrollbutton_left_out_blue.tga b/indra/newview/skins/darkgreen/textures/scrollbutton_left_out_blue.tga new file mode 100644 index 0000000000..4de4ca5dcc Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/scrollbutton_left_out_blue.tga differ diff --git a/indra/newview/skins/darkgreen/textures/scrollbutton_right_in_blue.tga b/indra/newview/skins/darkgreen/textures/scrollbutton_right_in_blue.tga new file mode 100644 index 0000000000..484f0469b6 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/scrollbutton_right_in_blue.tga differ diff --git a/indra/newview/skins/darkgreen/textures/scrollbutton_right_out_blue.tga b/indra/newview/skins/darkgreen/textures/scrollbutton_right_out_blue.tga new file mode 100644 index 0000000000..fca79181bc Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/scrollbutton_right_out_blue.tga differ diff --git a/indra/newview/skins/darkgreen/textures/scrollbutton_up_in_blue.tga b/indra/newview/skins/darkgreen/textures/scrollbutton_up_in_blue.tga new file mode 100644 index 0000000000..d8fd0a7cc1 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/scrollbutton_up_in_blue.tga differ diff --git a/indra/newview/skins/darkgreen/textures/scrollbutton_up_out_blue.tga b/indra/newview/skins/darkgreen/textures/scrollbutton_up_out_blue.tga new file mode 100644 index 0000000000..9112d187e2 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/scrollbutton_up_out_blue.tga differ diff --git a/indra/newview/skins/darkgreen/textures/spin_down_in_blue.tga b/indra/newview/skins/darkgreen/textures/spin_down_in_blue.tga new file mode 100644 index 0000000000..1f3dbfc3d8 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/spin_down_in_blue.tga differ diff --git a/indra/newview/skins/darkgreen/textures/spin_down_out_blue.tga b/indra/newview/skins/darkgreen/textures/spin_down_out_blue.tga new file mode 100644 index 0000000000..6728a6d9f2 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/spin_down_out_blue.tga differ diff --git a/indra/newview/skins/darkgreen/textures/spin_up_in_blue.tga b/indra/newview/skins/darkgreen/textures/spin_up_in_blue.tga new file mode 100644 index 0000000000..4bb545e0c0 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/spin_up_in_blue.tga differ diff --git a/indra/newview/skins/darkgreen/textures/spin_up_out_blue.tga b/indra/newview/skins/darkgreen/textures/spin_up_out_blue.tga new file mode 100644 index 0000000000..4a5cbcb946 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/spin_up_out_blue.tga differ diff --git a/indra/newview/skins/darkgreen/textures/square_btn_32x128.tga b/indra/newview/skins/darkgreen/textures/square_btn_32x128.tga new file mode 100644 index 0000000000..495b056563 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/square_btn_32x128.tga differ diff --git a/indra/newview/skins/darkgreen/textures/square_btn_selected_32x128.tga b/indra/newview/skins/darkgreen/textures/square_btn_selected_32x128.tga new file mode 100644 index 0000000000..0abbf56ce4 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/square_btn_selected_32x128.tga differ diff --git a/indra/newview/skins/darkgreen/textures/status_buy_currency.tga b/indra/newview/skins/darkgreen/textures/status_buy_currency.tga new file mode 100644 index 0000000000..206550cbb5 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/status_buy_currency.tga differ diff --git a/indra/newview/skins/darkgreen/textures/status_buy_currency_pressed.tga b/indra/newview/skins/darkgreen/textures/status_buy_currency_pressed.tga new file mode 100644 index 0000000000..2b82aef0ff Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/status_buy_currency_pressed.tga differ diff --git a/indra/newview/skins/darkgreen/textures/status_buy_land.tga b/indra/newview/skins/darkgreen/textures/status_buy_land.tga new file mode 100644 index 0000000000..4c4e977a84 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/status_buy_land.tga differ diff --git a/indra/newview/skins/darkgreen/textures/tab_bottom_blue.tga b/indra/newview/skins/darkgreen/textures/tab_bottom_blue.tga new file mode 100644 index 0000000000..65c9228db4 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/tab_bottom_blue.tga differ diff --git a/indra/newview/skins/darkgreen/textures/tab_bottom_selected_blue.tga b/indra/newview/skins/darkgreen/textures/tab_bottom_selected_blue.tga new file mode 100644 index 0000000000..7507edabb0 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/tab_bottom_selected_blue.tga differ diff --git a/indra/newview/skins/darkgreen/textures/tab_left.tga b/indra/newview/skins/darkgreen/textures/tab_left.tga new file mode 100644 index 0000000000..36a48bfd2e Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/tab_left.tga differ diff --git a/indra/newview/skins/darkgreen/textures/tab_left_selected.tga b/indra/newview/skins/darkgreen/textures/tab_left_selected.tga new file mode 100644 index 0000000000..2ed53bc035 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/tab_left_selected.tga differ diff --git a/indra/newview/skins/darkgreen/textures/tab_top_blue.tga b/indra/newview/skins/darkgreen/textures/tab_top_blue.tga new file mode 100644 index 0000000000..8f2625e729 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/tab_top_blue.tga differ diff --git a/indra/newview/skins/darkgreen/textures/tab_top_selected_blue.tga b/indra/newview/skins/darkgreen/textures/tab_top_selected_blue.tga new file mode 100644 index 0000000000..bab178a714 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/tab_top_selected_blue.tga differ diff --git a/indra/newview/skins/darkgreen/textures/tool_dozer.tga b/indra/newview/skins/darkgreen/textures/tool_dozer.tga new file mode 100644 index 0000000000..bc1cc7ade8 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/tool_dozer.tga differ diff --git a/indra/newview/skins/darkgreen/textures/tool_dozer_active.tga b/indra/newview/skins/darkgreen/textures/tool_dozer_active.tga new file mode 100644 index 0000000000..6099823a83 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/tool_dozer_active.tga differ diff --git a/indra/newview/skins/darkgreen/textures/tool_zoom.tga b/indra/newview/skins/darkgreen/textures/tool_zoom.tga new file mode 100644 index 0000000000..2f6a75e4b4 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/tool_zoom.tga differ diff --git a/indra/newview/skins/darkgreen/textures/tool_zoom_active.tga b/indra/newview/skins/darkgreen/textures/tool_zoom_active.tga new file mode 100644 index 0000000000..e83ca1a4b2 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/tool_zoom_active.tga differ diff --git a/indra/newview/skins/darkgreen/textures/toolbar_btn_disabled.tga b/indra/newview/skins/darkgreen/textures/toolbar_btn_disabled.tga new file mode 100644 index 0000000000..59c57fc7cd Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/toolbar_btn_disabled.tga differ diff --git a/indra/newview/skins/darkgreen/textures/toolbar_btn_enabled.tga b/indra/newview/skins/darkgreen/textures/toolbar_btn_enabled.tga new file mode 100644 index 0000000000..f005949b08 Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/toolbar_btn_enabled.tga differ diff --git a/indra/newview/skins/darkgreen/textures/toolbar_btn_selected.tga b/indra/newview/skins/darkgreen/textures/toolbar_btn_selected.tga new file mode 100644 index 0000000000..cfd577b55e Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/toolbar_btn_selected.tga differ diff --git a/indra/newview/skins/darkgreen/textures/toolbar_tab.tga b/indra/newview/skins/darkgreen/textures/toolbar_tab.tga new file mode 100644 index 0000000000..eda95f6e2d Binary files /dev/null and b/indra/newview/skins/darkgreen/textures/toolbar_tab.tga differ diff --git a/indra/newview/skins/apollo/textures/5748decc-f629-461c-9a36-a35a221fe21f.tga b/indra/newview/skins/darkgreen/textures/white.tga similarity index 100% rename from indra/newview/skins/apollo/textures/5748decc-f629-461c-9a36-a35a221fe21f.tga rename to indra/newview/skins/darkgreen/textures/white.tga diff --git a/indra/newview/skins/darkorange/colors.xml b/indra/newview/skins/darkorange/colors.xml index f3ff107f07..cb3021e93e 100644 --- a/indra/newview/skins/darkorange/colors.xml +++ b/indra/newview/skins/darkorange/colors.xml @@ -167,7 +167,6 @@ - @@ -186,12 +185,6 @@ - - - - - - diff --git a/indra/newview/skins/darkorange/textures/3c18c87e-5f50-14e2-e744-f44734aa365f.tga b/indra/newview/skins/darkorange/textures/3c18c87e-5f50-14e2-e744-f44734aa365f.tga deleted file mode 100644 index fb6dac0c3d..0000000000 Binary files a/indra/newview/skins/darkorange/textures/3c18c87e-5f50-14e2-e744-f44734aa365f.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/5748decc-f629-461c-9a36-a35a221fe21f.tga b/indra/newview/skins/darkorange/textures/5748decc-f629-461c-9a36-a35a221fe21f.tga deleted file mode 100644 index 55e3793097..0000000000 Binary files a/indra/newview/skins/darkorange/textures/5748decc-f629-461c-9a36-a35a221fe21f.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/7dabc040-ec13-2309-ddf7-4f161f6de2f4.tga b/indra/newview/skins/darkorange/textures/7dabc040-ec13-2309-ddf7-4f161f6de2f4.tga deleted file mode 100644 index 010c748c2a..0000000000 Binary files a/indra/newview/skins/darkorange/textures/7dabc040-ec13-2309-ddf7-4f161f6de2f4.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/9cad3e6d-2d6d-107d-f8ab-5ba272b5bfe1.tga b/indra/newview/skins/darkorange/textures/9cad3e6d-2d6d-107d-f8ab-5ba272b5bfe1.tga deleted file mode 100644 index e0656c901d..0000000000 Binary files a/indra/newview/skins/darkorange/textures/9cad3e6d-2d6d-107d-f8ab-5ba272b5bfe1.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/account_id_green.tga b/indra/newview/skins/darkorange/textures/account_id_green.tga deleted file mode 100644 index 9be215eed4..0000000000 Binary files a/indra/newview/skins/darkorange/textures/account_id_green.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/account_id_orange.tga b/indra/newview/skins/darkorange/textures/account_id_orange.tga deleted file mode 100644 index 6b41e86632..0000000000 Binary files a/indra/newview/skins/darkorange/textures/account_id_orange.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/active_speakers.tga b/indra/newview/skins/darkorange/textures/active_speakers.tga deleted file mode 100644 index 02d3643d7f..0000000000 Binary files a/indra/newview/skins/darkorange/textures/active_speakers.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/active_voice_tab.tga b/indra/newview/skins/darkorange/textures/active_voice_tab.tga deleted file mode 100644 index 2d0dfaabc5..0000000000 Binary files a/indra/newview/skins/darkorange/textures/active_voice_tab.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/alpha_gradient.tga b/indra/newview/skins/darkorange/textures/alpha_gradient.tga deleted file mode 100644 index 6fdba25d4e..0000000000 Binary files a/indra/newview/skins/darkorange/textures/alpha_gradient.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/alpha_gradient_2d.j2c b/indra/newview/skins/darkorange/textures/alpha_gradient_2d.j2c deleted file mode 100644 index 5de5a80a65..0000000000 Binary files a/indra/newview/skins/darkorange/textures/alpha_gradient_2d.j2c and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/arrow_down.tga b/indra/newview/skins/darkorange/textures/arrow_down.tga deleted file mode 100644 index 81dc9d3b6c..0000000000 Binary files a/indra/newview/skins/darkorange/textures/arrow_down.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/arrow_up.tga b/indra/newview/skins/darkorange/textures/arrow_up.tga deleted file mode 100644 index 22195cf7fb..0000000000 Binary files a/indra/newview/skins/darkorange/textures/arrow_up.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/avatar_gone.tga b/indra/newview/skins/darkorange/textures/avatar_gone.tga deleted file mode 100644 index e5c2c070bc..0000000000 Binary files a/indra/newview/skins/darkorange/textures/avatar_gone.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/avatar_new.tga b/indra/newview/skins/darkorange/textures/avatar_new.tga deleted file mode 100644 index 854b70c326..0000000000 Binary files a/indra/newview/skins/darkorange/textures/avatar_new.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/avatar_thumb_bkgrnd.j2c b/indra/newview/skins/darkorange/textures/avatar_thumb_bkgrnd.j2c deleted file mode 100644 index 555551ba11..0000000000 Binary files a/indra/newview/skins/darkorange/textures/avatar_thumb_bkgrnd.j2c and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/avatar_typing.tga b/indra/newview/skins/darkorange/textures/avatar_typing.tga deleted file mode 100644 index 2c549025dd..0000000000 Binary files a/indra/newview/skins/darkorange/textures/avatar_typing.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/badge_error.j2c b/indra/newview/skins/darkorange/textures/badge_error.j2c deleted file mode 100644 index e8f3da507a..0000000000 Binary files a/indra/newview/skins/darkorange/textures/badge_error.j2c and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/badge_note.j2c b/indra/newview/skins/darkorange/textures/badge_note.j2c deleted file mode 100644 index 1ab5233faf..0000000000 Binary files a/indra/newview/skins/darkorange/textures/badge_note.j2c and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/badge_ok.j2c b/indra/newview/skins/darkorange/textures/badge_ok.j2c deleted file mode 100644 index f85b880f1d..0000000000 Binary files a/indra/newview/skins/darkorange/textures/badge_ok.j2c and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/badge_warn.j2c b/indra/newview/skins/darkorange/textures/badge_warn.j2c deleted file mode 100644 index 26437ca426..0000000000 Binary files a/indra/newview/skins/darkorange/textures/badge_warn.j2c and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/checkbox_disabled_false.tga b/indra/newview/skins/darkorange/textures/checkbox_disabled_false.tga deleted file mode 100644 index 16c239227f..0000000000 Binary files a/indra/newview/skins/darkorange/textures/checkbox_disabled_false.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/checkbox_disabled_true.tga b/indra/newview/skins/darkorange/textures/checkbox_disabled_true.tga deleted file mode 100644 index 04a8d516f6..0000000000 Binary files a/indra/newview/skins/darkorange/textures/checkbox_disabled_true.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/checkbox_enabled_false.tga b/indra/newview/skins/darkorange/textures/checkbox_enabled_false.tga deleted file mode 100644 index a604a44092..0000000000 Binary files a/indra/newview/skins/darkorange/textures/checkbox_enabled_false.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/checkbox_enabled_true.tga b/indra/newview/skins/darkorange/textures/checkbox_enabled_true.tga deleted file mode 100644 index 4a1b504eaf..0000000000 Binary files a/indra/newview/skins/darkorange/textures/checkbox_enabled_true.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/checkerboard_transparency_bg.png b/indra/newview/skins/darkorange/textures/checkerboard_transparency_bg.png deleted file mode 100644 index 9a16935204..0000000000 Binary files a/indra/newview/skins/darkorange/textures/checkerboard_transparency_bg.png and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/circle.tga b/indra/newview/skins/darkorange/textures/circle.tga deleted file mode 100644 index d7097e3a35..0000000000 Binary files a/indra/newview/skins/darkorange/textures/circle.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/close_in_blue.tga b/indra/newview/skins/darkorange/textures/close_in_blue.tga deleted file mode 100644 index 8200eba327..0000000000 Binary files a/indra/newview/skins/darkorange/textures/close_in_blue.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/close_inactive_blue.tga b/indra/newview/skins/darkorange/textures/close_inactive_blue.tga deleted file mode 100644 index 191c5d3e80..0000000000 Binary files a/indra/newview/skins/darkorange/textures/close_inactive_blue.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/closebox.tga b/indra/newview/skins/darkorange/textures/closebox.tga deleted file mode 100644 index 294d4fb241..0000000000 Binary files a/indra/newview/skins/darkorange/textures/closebox.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/cloud-particle.j2c b/indra/newview/skins/darkorange/textures/cloud-particle.j2c deleted file mode 100644 index 6c03bf6d05..0000000000 Binary files a/indra/newview/skins/darkorange/textures/cloud-particle.j2c and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/color_swatch_alpha.tga b/indra/newview/skins/darkorange/textures/color_swatch_alpha.tga deleted file mode 100644 index 814a004e62..0000000000 Binary files a/indra/newview/skins/darkorange/textures/color_swatch_alpha.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/combobox_arrow.tga b/indra/newview/skins/darkorange/textures/combobox_arrow.tga deleted file mode 100644 index ad08f32bb5..0000000000 Binary files a/indra/newview/skins/darkorange/textures/combobox_arrow.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/crosshairs.tga b/indra/newview/skins/darkorange/textures/crosshairs.tga deleted file mode 100644 index ac4d63dc59..0000000000 Binary files a/indra/newview/skins/darkorange/textures/crosshairs.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/darkgray.tga b/indra/newview/skins/darkorange/textures/darkgray.tga deleted file mode 100644 index 2063d685aa..0000000000 Binary files a/indra/newview/skins/darkorange/textures/darkgray.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/direction_arrow.tga b/indra/newview/skins/darkorange/textures/direction_arrow.tga deleted file mode 100644 index f3ef1068c4..0000000000 Binary files a/indra/newview/skins/darkorange/textures/direction_arrow.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/down_arrow.png b/indra/newview/skins/darkorange/textures/down_arrow.png deleted file mode 100644 index 155f80c97e..0000000000 Binary files a/indra/newview/skins/darkorange/textures/down_arrow.png and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/eye_button_active.tga b/indra/newview/skins/darkorange/textures/eye_button_active.tga deleted file mode 100644 index 014f785a7b..0000000000 Binary files a/indra/newview/skins/darkorange/textures/eye_button_active.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/eye_button_inactive.tga b/indra/newview/skins/darkorange/textures/eye_button_inactive.tga deleted file mode 100644 index 8666f0bbe6..0000000000 Binary files a/indra/newview/skins/darkorange/textures/eye_button_inactive.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/folder_arrow.tga b/indra/newview/skins/darkorange/textures/folder_arrow.tga deleted file mode 100644 index 77d470731b..0000000000 Binary files a/indra/newview/skins/darkorange/textures/folder_arrow.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/foot_shadow.j2c b/indra/newview/skins/darkorange/textures/foot_shadow.j2c deleted file mode 100644 index f9ce9da7d1..0000000000 Binary files a/indra/newview/skins/darkorange/textures/foot_shadow.j2c and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/icn_active-speakers-dot-lvl0.tga b/indra/newview/skins/darkorange/textures/icn_active-speakers-dot-lvl0.tga deleted file mode 100644 index 35846cef32..0000000000 Binary files a/indra/newview/skins/darkorange/textures/icn_active-speakers-dot-lvl0.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/icn_active-speakers-dot-lvl1.tga b/indra/newview/skins/darkorange/textures/icn_active-speakers-dot-lvl1.tga deleted file mode 100644 index 1f9f564fa9..0000000000 Binary files a/indra/newview/skins/darkorange/textures/icn_active-speakers-dot-lvl1.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/icn_active-speakers-dot-lvl2.tga b/indra/newview/skins/darkorange/textures/icn_active-speakers-dot-lvl2.tga deleted file mode 100644 index b2e5609f1f..0000000000 Binary files a/indra/newview/skins/darkorange/textures/icn_active-speakers-dot-lvl2.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/icn_active-speakers-typing1.tga b/indra/newview/skins/darkorange/textures/icn_active-speakers-typing1.tga deleted file mode 100644 index 3706c96e0f..0000000000 Binary files a/indra/newview/skins/darkorange/textures/icn_active-speakers-typing1.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/icn_active-speakers-typing2.tga b/indra/newview/skins/darkorange/textures/icn_active-speakers-typing2.tga deleted file mode 100644 index 0d127f9461..0000000000 Binary files a/indra/newview/skins/darkorange/textures/icn_active-speakers-typing2.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/icn_active-speakers-typing3.tga b/indra/newview/skins/darkorange/textures/icn_active-speakers-typing3.tga deleted file mode 100644 index 031b3ad344..0000000000 Binary files a/indra/newview/skins/darkorange/textures/icn_active-speakers-typing3.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/icn_clear_lineeditor.tga b/indra/newview/skins/darkorange/textures/icn_clear_lineeditor.tga deleted file mode 100644 index 8cd8310c66..0000000000 Binary files a/indra/newview/skins/darkorange/textures/icn_clear_lineeditor.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/icn_rounded-text-field.tga b/indra/newview/skins/darkorange/textures/icn_rounded-text-field.tga deleted file mode 100644 index 7da504f93f..0000000000 Binary files a/indra/newview/skins/darkorange/textures/icn_rounded-text-field.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/icn_voice-call-end.tga b/indra/newview/skins/darkorange/textures/icn_voice-call-end.tga deleted file mode 100644 index 2da4e856b4..0000000000 Binary files a/indra/newview/skins/darkorange/textures/icn_voice-call-end.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/icn_voice-call-start.tga b/indra/newview/skins/darkorange/textures/icn_voice-call-start.tga deleted file mode 100644 index 07701cb5a2..0000000000 Binary files a/indra/newview/skins/darkorange/textures/icn_voice-call-start.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/icn_voice-groupfocus.tga b/indra/newview/skins/darkorange/textures/icn_voice-groupfocus.tga deleted file mode 100644 index 9f48d4609d..0000000000 Binary files a/indra/newview/skins/darkorange/textures/icn_voice-groupfocus.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/icn_voice-localchat.tga b/indra/newview/skins/darkorange/textures/icn_voice-localchat.tga deleted file mode 100644 index 7cf267eaf5..0000000000 Binary files a/indra/newview/skins/darkorange/textures/icn_voice-localchat.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/icn_voice-pvtfocus.tga b/indra/newview/skins/darkorange/textures/icn_voice-pvtfocus.tga deleted file mode 100644 index abadb09aaf..0000000000 Binary files a/indra/newview/skins/darkorange/textures/icn_voice-pvtfocus.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/icn_voice_ptt-off.tga b/indra/newview/skins/darkorange/textures/icn_voice_ptt-off.tga deleted file mode 100644 index 15ecbdff95..0000000000 Binary files a/indra/newview/skins/darkorange/textures/icn_voice_ptt-off.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/icn_voice_ptt-on-lvl1.tga b/indra/newview/skins/darkorange/textures/icn_voice_ptt-on-lvl1.tga deleted file mode 100644 index ae72af131d..0000000000 Binary files a/indra/newview/skins/darkorange/textures/icn_voice_ptt-on-lvl1.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/icn_voice_ptt-on-lvl2.tga b/indra/newview/skins/darkorange/textures/icn_voice_ptt-on-lvl2.tga deleted file mode 100644 index 4dfc2dd292..0000000000 Binary files a/indra/newview/skins/darkorange/textures/icn_voice_ptt-on-lvl2.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/icn_voice_ptt-on-lvl3.tga b/indra/newview/skins/darkorange/textures/icn_voice_ptt-on-lvl3.tga deleted file mode 100644 index 018b0bef42..0000000000 Binary files a/indra/newview/skins/darkorange/textures/icn_voice_ptt-on-lvl3.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/icn_voice_ptt-on.tga b/indra/newview/skins/darkorange/textures/icn_voice_ptt-on.tga deleted file mode 100644 index 9eb6431106..0000000000 Binary files a/indra/newview/skins/darkorange/textures/icn_voice_ptt-on.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/icon_auction.tga b/indra/newview/skins/darkorange/textures/icon_auction.tga deleted file mode 100644 index d121833b47..0000000000 Binary files a/indra/newview/skins/darkorange/textures/icon_auction.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/icon_avatar_expand.png b/indra/newview/skins/darkorange/textures/icon_avatar_expand.png index 4b7862c260..0572551dea 100644 Binary files a/indra/newview/skins/darkorange/textures/icon_avatar_expand.png and b/indra/newview/skins/darkorange/textures/icon_avatar_expand.png differ diff --git a/indra/newview/skins/darkorange/textures/icon_day_cycle.tga b/indra/newview/skins/darkorange/textures/icon_day_cycle.tga deleted file mode 100644 index 2d5dee1e94..0000000000 Binary files a/indra/newview/skins/darkorange/textures/icon_day_cycle.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/icon_diurnal.tga b/indra/newview/skins/darkorange/textures/icon_diurnal.tga deleted file mode 100644 index fc720c8269..0000000000 Binary files a/indra/newview/skins/darkorange/textures/icon_diurnal.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/icon_event.tga b/indra/newview/skins/darkorange/textures/icon_event.tga deleted file mode 100644 index 7805dbce60..0000000000 Binary files a/indra/newview/skins/darkorange/textures/icon_event.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/icon_event_mature.tga b/indra/newview/skins/darkorange/textures/icon_event_mature.tga deleted file mode 100644 index 61c879bc92..0000000000 Binary files a/indra/newview/skins/darkorange/textures/icon_event_mature.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/icon_for_sale.tga b/indra/newview/skins/darkorange/textures/icon_for_sale.tga deleted file mode 100644 index 455b1aeb19..0000000000 Binary files a/indra/newview/skins/darkorange/textures/icon_for_sale.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/icon_group.tga b/indra/newview/skins/darkorange/textures/icon_group.tga deleted file mode 100644 index 22122d6cf1..0000000000 Binary files a/indra/newview/skins/darkorange/textures/icon_group.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/icon_groupnotice.tga b/indra/newview/skins/darkorange/textures/icon_groupnotice.tga deleted file mode 100644 index edf2c6180f..0000000000 Binary files a/indra/newview/skins/darkorange/textures/icon_groupnotice.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/icon_groupnoticeinventory.tga b/indra/newview/skins/darkorange/textures/icon_groupnoticeinventory.tga deleted file mode 100644 index f313906327..0000000000 Binary files a/indra/newview/skins/darkorange/textures/icon_groupnoticeinventory.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/icon_lock.tga b/indra/newview/skins/darkorange/textures/icon_lock.tga deleted file mode 100644 index 23521aa113..0000000000 Binary files a/indra/newview/skins/darkorange/textures/icon_lock.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/icon_place.tga b/indra/newview/skins/darkorange/textures/icon_place.tga deleted file mode 100644 index 2170c98499..0000000000 Binary files a/indra/newview/skins/darkorange/textures/icon_place.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/icon_popular.tga b/indra/newview/skins/darkorange/textures/icon_popular.tga deleted file mode 100644 index f1165b8aaa..0000000000 Binary files a/indra/newview/skins/darkorange/textures/icon_popular.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/inv_folder_trash.tga b/indra/newview/skins/darkorange/textures/inv_folder_trash.tga deleted file mode 100644 index 54043e9cf7..0000000000 Binary files a/indra/newview/skins/darkorange/textures/inv_folder_trash.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/inv_item_animation.tga b/indra/newview/skins/darkorange/textures/inv_item_animation.tga deleted file mode 100644 index 2b12b28094..0000000000 Binary files a/indra/newview/skins/darkorange/textures/inv_item_animation.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/inv_item_attach.tga b/indra/newview/skins/darkorange/textures/inv_item_attach.tga deleted file mode 100644 index 0538993329..0000000000 Binary files a/indra/newview/skins/darkorange/textures/inv_item_attach.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/inv_item_callingcard_offline.tga b/indra/newview/skins/darkorange/textures/inv_item_callingcard_offline.tga deleted file mode 100644 index 44222d306c..0000000000 Binary files a/indra/newview/skins/darkorange/textures/inv_item_callingcard_offline.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/inv_item_callingcard_online.tga b/indra/newview/skins/darkorange/textures/inv_item_callingcard_online.tga deleted file mode 100644 index 42be4d2e13..0000000000 Binary files a/indra/newview/skins/darkorange/textures/inv_item_callingcard_online.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/inv_item_gesture.tga b/indra/newview/skins/darkorange/textures/inv_item_gesture.tga deleted file mode 100644 index 52ac90c90d..0000000000 Binary files a/indra/newview/skins/darkorange/textures/inv_item_gesture.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/inv_item_notecard.tga b/indra/newview/skins/darkorange/textures/inv_item_notecard.tga deleted file mode 100644 index 2534d1b2a8..0000000000 Binary files a/indra/newview/skins/darkorange/textures/inv_item_notecard.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/lag_status_critical.tga b/indra/newview/skins/darkorange/textures/lag_status_critical.tga deleted file mode 100644 index bbc71d9e77..0000000000 Binary files a/indra/newview/skins/darkorange/textures/lag_status_critical.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/lag_status_good.tga b/indra/newview/skins/darkorange/textures/lag_status_good.tga deleted file mode 100644 index 680ba90f17..0000000000 Binary files a/indra/newview/skins/darkorange/textures/lag_status_good.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/lag_status_warning.tga b/indra/newview/skins/darkorange/textures/lag_status_warning.tga deleted file mode 100644 index 13ce3cc396..0000000000 Binary files a/indra/newview/skins/darkorange/textures/lag_status_warning.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/legend.tga b/indra/newview/skins/darkorange/textures/legend.tga deleted file mode 100644 index 0dbb8fda4f..0000000000 Binary files a/indra/newview/skins/darkorange/textures/legend.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/lightgray.tga b/indra/newview/skins/darkorange/textures/lightgray.tga deleted file mode 100644 index 2063d685aa..0000000000 Binary files a/indra/newview/skins/darkorange/textures/lightgray.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/map_avatar_16.tga b/indra/newview/skins/darkorange/textures/map_avatar_16.tga deleted file mode 100644 index ce129e3590..0000000000 Binary files a/indra/newview/skins/darkorange/textures/map_avatar_16.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/map_avatar_8.tga b/indra/newview/skins/darkorange/textures/map_avatar_8.tga deleted file mode 100644 index 28552f2237..0000000000 Binary files a/indra/newview/skins/darkorange/textures/map_avatar_8.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/map_avatar_above_8.tga b/indra/newview/skins/darkorange/textures/map_avatar_above_8.tga deleted file mode 100644 index 193428e530..0000000000 Binary files a/indra/newview/skins/darkorange/textures/map_avatar_above_8.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/map_avatar_below_8.tga b/indra/newview/skins/darkorange/textures/map_avatar_below_8.tga deleted file mode 100644 index 9e14bfab90..0000000000 Binary files a/indra/newview/skins/darkorange/textures/map_avatar_below_8.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/map_avatar_you_8.tga b/indra/newview/skins/darkorange/textures/map_avatar_you_8.tga deleted file mode 100644 index 61f319fd9d..0000000000 Binary files a/indra/newview/skins/darkorange/textures/map_avatar_you_8.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/map_event.tga b/indra/newview/skins/darkorange/textures/map_event.tga deleted file mode 100644 index c229b379a2..0000000000 Binary files a/indra/newview/skins/darkorange/textures/map_event.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/map_event_mature.tga b/indra/newview/skins/darkorange/textures/map_event_mature.tga deleted file mode 100644 index 61c879bc92..0000000000 Binary files a/indra/newview/skins/darkorange/textures/map_event_mature.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/map_home.tga b/indra/newview/skins/darkorange/textures/map_home.tga deleted file mode 100644 index 7478de371a..0000000000 Binary files a/indra/newview/skins/darkorange/textures/map_home.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/map_infohub.tga b/indra/newview/skins/darkorange/textures/map_infohub.tga deleted file mode 100644 index d0134fa5fe..0000000000 Binary files a/indra/newview/skins/darkorange/textures/map_infohub.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/map_telehub.tga b/indra/newview/skins/darkorange/textures/map_telehub.tga deleted file mode 100644 index ef63a3eb72..0000000000 Binary files a/indra/newview/skins/darkorange/textures/map_telehub.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/map_track_16.tga b/indra/newview/skins/darkorange/textures/map_track_16.tga deleted file mode 100644 index 451ce24cf0..0000000000 Binary files a/indra/newview/skins/darkorange/textures/map_track_16.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/map_track_8.tga b/indra/newview/skins/darkorange/textures/map_track_8.tga deleted file mode 100644 index 53425ff45b..0000000000 Binary files a/indra/newview/skins/darkorange/textures/map_track_8.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/minimize.tga b/indra/newview/skins/darkorange/textures/minimize.tga deleted file mode 100644 index a21fd91481..0000000000 Binary files a/indra/newview/skins/darkorange/textures/minimize.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/minimize_inactive.tga b/indra/newview/skins/darkorange/textures/minimize_inactive.tga deleted file mode 100644 index fcd62aa35e..0000000000 Binary files a/indra/newview/skins/darkorange/textures/minimize_inactive.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/minimize_pressed.tga b/indra/newview/skins/darkorange/textures/minimize_pressed.tga deleted file mode 100644 index 0061dd5f5c..0000000000 Binary files a/indra/newview/skins/darkorange/textures/minimize_pressed.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/missing_asset.tga b/indra/newview/skins/darkorange/textures/missing_asset.tga deleted file mode 100644 index 9a43f4db5d..0000000000 Binary files a/indra/newview/skins/darkorange/textures/missing_asset.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/mute_icon.tga b/indra/newview/skins/darkorange/textures/mute_icon.tga deleted file mode 100644 index 879b9e6188..0000000000 Binary files a/indra/newview/skins/darkorange/textures/mute_icon.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/noentrylines.j2c b/indra/newview/skins/darkorange/textures/noentrylines.j2c deleted file mode 100644 index 93ec17659d..0000000000 Binary files a/indra/newview/skins/darkorange/textures/noentrylines.j2c and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/noentrypasslines.j2c b/indra/newview/skins/darkorange/textures/noentrypasslines.j2c deleted file mode 100644 index 800c466964..0000000000 Binary files a/indra/newview/skins/darkorange/textures/noentrypasslines.j2c and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/notify_caution_icon.tga b/indra/newview/skins/darkorange/textures/notify_caution_icon.tga deleted file mode 100644 index abc23d1d7a..0000000000 Binary files a/indra/newview/skins/darkorange/textures/notify_caution_icon.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/notify_next.png b/indra/newview/skins/darkorange/textures/notify_next.png deleted file mode 100644 index 2235d25ff4..0000000000 Binary files a/indra/newview/skins/darkorange/textures/notify_next.png and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/pixiesmall.j2c b/indra/newview/skins/darkorange/textures/pixiesmall.j2c deleted file mode 100644 index a1ff64014b..0000000000 Binary files a/indra/newview/skins/darkorange/textures/pixiesmall.j2c and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/preview.png b/indra/newview/skins/darkorange/textures/preview.png index 05bfbeb3dc..19c48b34fa 100644 Binary files a/indra/newview/skins/darkorange/textures/preview.png and b/indra/newview/skins/darkorange/textures/preview.png differ diff --git a/indra/newview/skins/darkorange/textures/propertyline.tga b/indra/newview/skins/darkorange/textures/propertyline.tga deleted file mode 100644 index 0c504eea71..0000000000 Binary files a/indra/newview/skins/darkorange/textures/propertyline.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/ptt_lock_off.tga b/indra/newview/skins/darkorange/textures/ptt_lock_off.tga deleted file mode 100644 index 09c4798070..0000000000 Binary files a/indra/newview/skins/darkorange/textures/ptt_lock_off.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/ptt_lock_on.tga b/indra/newview/skins/darkorange/textures/ptt_lock_on.tga deleted file mode 100644 index dfb8ce2841..0000000000 Binary files a/indra/newview/skins/darkorange/textures/ptt_lock_on.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/radio_active_false.tga b/indra/newview/skins/darkorange/textures/radio_active_false.tga deleted file mode 100644 index 963037392c..0000000000 Binary files a/indra/newview/skins/darkorange/textures/radio_active_false.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/radio_active_true.tga b/indra/newview/skins/darkorange/textures/radio_active_true.tga deleted file mode 100644 index f49297fd2c..0000000000 Binary files a/indra/newview/skins/darkorange/textures/radio_active_true.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/radio_inactive_false.tga b/indra/newview/skins/darkorange/textures/radio_inactive_false.tga deleted file mode 100644 index 9f9589e645..0000000000 Binary files a/indra/newview/skins/darkorange/textures/radio_inactive_false.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/radio_inactive_true.tga b/indra/newview/skins/darkorange/textures/radio_inactive_true.tga deleted file mode 100644 index ca69cc6b5d..0000000000 Binary files a/indra/newview/skins/darkorange/textures/radio_inactive_true.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/resize_handle_bottom_right_blue.tga b/indra/newview/skins/darkorange/textures/resize_handle_bottom_right_blue.tga deleted file mode 100644 index f47aacfa42..0000000000 Binary files a/indra/newview/skins/darkorange/textures/resize_handle_bottom_right_blue.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/restore.tga b/indra/newview/skins/darkorange/textures/restore.tga deleted file mode 100644 index 87910e288e..0000000000 Binary files a/indra/newview/skins/darkorange/textures/restore.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/restore_inactive.tga b/indra/newview/skins/darkorange/textures/restore_inactive.tga deleted file mode 100644 index dbbec7ea1e..0000000000 Binary files a/indra/newview/skins/darkorange/textures/restore_inactive.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/restore_pressed.tga b/indra/newview/skins/darkorange/textures/restore_pressed.tga deleted file mode 100644 index 1922ca8815..0000000000 Binary files a/indra/newview/skins/darkorange/textures/restore_pressed.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/rounded_square.j2c b/indra/newview/skins/darkorange/textures/rounded_square.j2c deleted file mode 100644 index c8bb572fa9..0000000000 Binary files a/indra/newview/skins/darkorange/textures/rounded_square.j2c and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/rounded_square_soft.j2c b/indra/newview/skins/darkorange/textures/rounded_square_soft.j2c deleted file mode 100644 index 56e56c1ec9..0000000000 Binary files a/indra/newview/skins/darkorange/textures/rounded_square_soft.j2c and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/script_error.j2c b/indra/newview/skins/darkorange/textures/script_error.j2c deleted file mode 100644 index 893cb642e7..0000000000 Binary files a/indra/newview/skins/darkorange/textures/script_error.j2c and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/scrollbutton_down_in_blue.tga b/indra/newview/skins/darkorange/textures/scrollbutton_down_in_blue.tga deleted file mode 100644 index 5e73799505..0000000000 Binary files a/indra/newview/skins/darkorange/textures/scrollbutton_down_in_blue.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/scrollbutton_down_out_blue.tga b/indra/newview/skins/darkorange/textures/scrollbutton_down_out_blue.tga deleted file mode 100644 index c5cf9bf9f9..0000000000 Binary files a/indra/newview/skins/darkorange/textures/scrollbutton_down_out_blue.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/scrollbutton_left_in_blue.tga b/indra/newview/skins/darkorange/textures/scrollbutton_left_in_blue.tga deleted file mode 100644 index 480842a3b5..0000000000 Binary files a/indra/newview/skins/darkorange/textures/scrollbutton_left_in_blue.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/scrollbutton_left_out_blue.tga b/indra/newview/skins/darkorange/textures/scrollbutton_left_out_blue.tga deleted file mode 100644 index 71aad797b0..0000000000 Binary files a/indra/newview/skins/darkorange/textures/scrollbutton_left_out_blue.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/scrollbutton_right_in_blue.tga b/indra/newview/skins/darkorange/textures/scrollbutton_right_in_blue.tga deleted file mode 100644 index 6d7f13bfcc..0000000000 Binary files a/indra/newview/skins/darkorange/textures/scrollbutton_right_in_blue.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/scrollbutton_right_out_blue.tga b/indra/newview/skins/darkorange/textures/scrollbutton_right_out_blue.tga deleted file mode 100644 index 0edc59af3e..0000000000 Binary files a/indra/newview/skins/darkorange/textures/scrollbutton_right_out_blue.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/scrollbutton_up_in_blue.tga b/indra/newview/skins/darkorange/textures/scrollbutton_up_in_blue.tga deleted file mode 100644 index 4c6a8fe414..0000000000 Binary files a/indra/newview/skins/darkorange/textures/scrollbutton_up_in_blue.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/scrollbutton_up_out_blue.tga b/indra/newview/skins/darkorange/textures/scrollbutton_up_out_blue.tga deleted file mode 100644 index 5cd5dff467..0000000000 Binary files a/indra/newview/skins/darkorange/textures/scrollbutton_up_out_blue.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/silhouette.j2c b/indra/newview/skins/darkorange/textures/silhouette.j2c deleted file mode 100644 index 3859d4cb34..0000000000 Binary files a/indra/newview/skins/darkorange/textures/silhouette.j2c and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/skin_thumbnail_dark.png b/indra/newview/skins/darkorange/textures/skin_thumbnail_dark.png deleted file mode 100644 index 2cac82923b..0000000000 Binary files a/indra/newview/skins/darkorange/textures/skin_thumbnail_dark.png and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/skin_thumbnail_default.png b/indra/newview/skins/darkorange/textures/skin_thumbnail_default.png deleted file mode 100644 index 40fe64bb49..0000000000 Binary files a/indra/newview/skins/darkorange/textures/skin_thumbnail_default.png and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/skin_thumbnail_emerald.png b/indra/newview/skins/darkorange/textures/skin_thumbnail_emerald.png deleted file mode 100644 index ab35bc0ab9..0000000000 Binary files a/indra/newview/skins/darkorange/textures/skin_thumbnail_emerald.png and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/skin_thumbnail_gred.png b/indra/newview/skins/darkorange/textures/skin_thumbnail_gred.png deleted file mode 100644 index 827135499c..0000000000 Binary files a/indra/newview/skins/darkorange/textures/skin_thumbnail_gred.png and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/skin_thumbnail_pslgreen.png b/indra/newview/skins/darkorange/textures/skin_thumbnail_pslgreen.png deleted file mode 100644 index 73e117e9fa..0000000000 Binary files a/indra/newview/skins/darkorange/textures/skin_thumbnail_pslgreen.png and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/skin_thumbnail_pslpurple.png b/indra/newview/skins/darkorange/textures/skin_thumbnail_pslpurple.png deleted file mode 100644 index 902ad82b18..0000000000 Binary files a/indra/newview/skins/darkorange/textures/skin_thumbnail_pslpurple.png and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/skin_thumbnail_ruby.png b/indra/newview/skins/darkorange/textures/skin_thumbnail_ruby.png deleted file mode 100644 index d45e75ad04..0000000000 Binary files a/indra/newview/skins/darkorange/textures/skin_thumbnail_ruby.png and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/skin_thumbnail_saphire.png b/indra/newview/skins/darkorange/textures/skin_thumbnail_saphire.png deleted file mode 100644 index 7ec8e19913..0000000000 Binary files a/indra/newview/skins/darkorange/textures/skin_thumbnail_saphire.png and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/skin_thumbnail_silver.png b/indra/newview/skins/darkorange/textures/skin_thumbnail_silver.png deleted file mode 100644 index 51707bb9d4..0000000000 Binary files a/indra/newview/skins/darkorange/textures/skin_thumbnail_silver.png and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/slim_icon_16_viewer.tga b/indra/newview/skins/darkorange/textures/slim_icon_16_viewer.tga deleted file mode 100644 index 552181d36a..0000000000 Binary files a/indra/newview/skins/darkorange/textures/slim_icon_16_viewer.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/sm_rounded_corners_simple.tga b/indra/newview/skins/darkorange/textures/sm_rounded_corners_simple.tga deleted file mode 100644 index 85157e4612..0000000000 Binary files a/indra/newview/skins/darkorange/textures/sm_rounded_corners_simple.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/smicon_warn.tga b/indra/newview/skins/darkorange/textures/smicon_warn.tga deleted file mode 100644 index 90ccaa07e5..0000000000 Binary files a/indra/newview/skins/darkorange/textures/smicon_warn.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/spacer24.tga b/indra/newview/skins/darkorange/textures/spacer24.tga deleted file mode 100644 index c7cab6b38c..0000000000 Binary files a/indra/newview/skins/darkorange/textures/spacer24.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/spacer35.tga b/indra/newview/skins/darkorange/textures/spacer35.tga deleted file mode 100644 index b88bc6680a..0000000000 Binary files a/indra/newview/skins/darkorange/textures/spacer35.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/spin_down_in_blue.tga b/indra/newview/skins/darkorange/textures/spin_down_in_blue.tga deleted file mode 100644 index b9eb36ba9f..0000000000 Binary files a/indra/newview/skins/darkorange/textures/spin_down_in_blue.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/spin_down_out_blue.tga b/indra/newview/skins/darkorange/textures/spin_down_out_blue.tga deleted file mode 100644 index c9cb5e8bf6..0000000000 Binary files a/indra/newview/skins/darkorange/textures/spin_down_out_blue.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/spin_up_in_blue.tga b/indra/newview/skins/darkorange/textures/spin_up_in_blue.tga deleted file mode 100644 index b604b8843c..0000000000 Binary files a/indra/newview/skins/darkorange/textures/spin_up_in_blue.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/spin_up_out_blue.tga b/indra/newview/skins/darkorange/textures/spin_up_out_blue.tga deleted file mode 100644 index 4e3941e458..0000000000 Binary files a/indra/newview/skins/darkorange/textures/spin_up_out_blue.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/startup_logo.j2c b/indra/newview/skins/darkorange/textures/startup_logo.j2c deleted file mode 100644 index d1b991f17f..0000000000 Binary files a/indra/newview/skins/darkorange/textures/startup_logo.j2c and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/status_busy.tga b/indra/newview/skins/darkorange/textures/status_busy.tga deleted file mode 100644 index 7743d9c7bb..0000000000 Binary files a/indra/newview/skins/darkorange/textures/status_busy.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/status_health.tga b/indra/newview/skins/darkorange/textures/status_health.tga deleted file mode 100644 index 3d5f455fcd..0000000000 Binary files a/indra/newview/skins/darkorange/textures/status_health.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/status_money.tga b/indra/newview/skins/darkorange/textures/status_money.tga deleted file mode 100644 index d5be31fc60..0000000000 Binary files a/indra/newview/skins/darkorange/textures/status_money.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/status_script_debug.tga b/indra/newview/skins/darkorange/textures/status_script_debug.tga deleted file mode 100644 index 6fca614835..0000000000 Binary files a/indra/newview/skins/darkorange/textures/status_script_debug.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/status_search.tga b/indra/newview/skins/darkorange/textures/status_search.tga deleted file mode 100644 index 3ac10c4769..0000000000 Binary files a/indra/newview/skins/darkorange/textures/status_search.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/status_search_btn.png b/indra/newview/skins/darkorange/textures/status_search_btn.png deleted file mode 100644 index 67f61332bc..0000000000 Binary files a/indra/newview/skins/darkorange/textures/status_search_btn.png and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/status_search_btn_pressed.png b/indra/newview/skins/darkorange/textures/status_search_btn_pressed.png deleted file mode 100644 index 1437273d37..0000000000 Binary files a/indra/newview/skins/darkorange/textures/status_search_btn_pressed.png and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/status_voice.tga b/indra/newview/skins/darkorange/textures/status_voice.tga deleted file mode 100644 index 4ab4498cbc..0000000000 Binary files a/indra/newview/skins/darkorange/textures/status_voice.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/tab_background_darkpurple.tga b/indra/newview/skins/darkorange/textures/tab_background_darkpurple.tga deleted file mode 100644 index 8169f98694..0000000000 Binary files a/indra/newview/skins/darkorange/textures/tab_background_darkpurple.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/tab_background_lightgrey.tga b/indra/newview/skins/darkorange/textures/tab_background_lightgrey.tga deleted file mode 100644 index c2f8818f73..0000000000 Binary files a/indra/newview/skins/darkorange/textures/tab_background_lightgrey.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/tab_background_purple.tga b/indra/newview/skins/darkorange/textures/tab_background_purple.tga deleted file mode 100644 index aa01b3cb68..0000000000 Binary files a/indra/newview/skins/darkorange/textures/tab_background_purple.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/tabarea.tga b/indra/newview/skins/darkorange/textures/tabarea.tga deleted file mode 100644 index 5517aebfc8..0000000000 Binary files a/indra/newview/skins/darkorange/textures/tabarea.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/tearoff_pressed.tga b/indra/newview/skins/darkorange/textures/tearoff_pressed.tga deleted file mode 100644 index 620d109de0..0000000000 Binary files a/indra/newview/skins/darkorange/textures/tearoff_pressed.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/tearoffbox.tga b/indra/newview/skins/darkorange/textures/tearoffbox.tga deleted file mode 100644 index 0670d2e91b..0000000000 Binary files a/indra/newview/skins/darkorange/textures/tearoffbox.tga and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/textures.xml b/indra/newview/skins/darkorange/textures/textures.xml index 41fe7a9f9b..48fcecbfeb 100644 --- a/indra/newview/skins/darkorange/textures/textures.xml +++ b/indra/newview/skins/darkorange/textures/textures.xml @@ -1,386 +1,3 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/indra/newview/skins/darkorange/textures/up_arrow.png b/indra/newview/skins/darkorange/textures/up_arrow.png index a3b6667419..42de741a8d 100644 Binary files a/indra/newview/skins/darkorange/textures/up_arrow.png and b/indra/newview/skins/darkorange/textures/up_arrow.png differ diff --git a/indra/newview/skins/darkorange/textures/uv_test1.j2c b/indra/newview/skins/darkorange/textures/uv_test1.j2c deleted file mode 100644 index 3d5b541796..0000000000 Binary files a/indra/newview/skins/darkorange/textures/uv_test1.j2c and /dev/null differ diff --git a/indra/newview/skins/darkorange/textures/white.tga b/indra/newview/skins/darkorange/textures/white.tga deleted file mode 100644 index 9fe68631cf..0000000000 Binary files a/indra/newview/skins/darkorange/textures/white.tga and /dev/null differ diff --git a/indra/newview/skins/default/colors_base.xml b/indra/newview/skins/default/colors_base.xml index f7b934f81a..070fed106c 100644 --- a/indra/newview/skins/default/colors_base.xml +++ b/indra/newview/skins/default/colors_base.xml @@ -103,6 +103,7 @@ + @@ -151,7 +152,7 @@ - + @@ -186,7 +187,6 @@ - diff --git a/indra/newview/skins/default/html/btn_purplepill_bg.png b/indra/newview/skins/default/html/btn_purplepill_bg.png index b78127ae30..d8debe7b69 100644 Binary files a/indra/newview/skins/default/html/btn_purplepill_bg.png and b/indra/newview/skins/default/html/btn_purplepill_bg.png differ diff --git a/indra/newview/skins/default/html/unabletoconnect.png b/indra/newview/skins/default/html/unabletoconnect.png index 1383516509..71cc8334a0 100644 Binary files a/indra/newview/skins/default/html/unabletoconnect.png and b/indra/newview/skins/default/html/unabletoconnect.png differ diff --git a/indra/newview/skins/default/textures/Accordion_ArrowClosed_Off.png b/indra/newview/skins/default/textures/Accordion_ArrowClosed_Off.png new file mode 100644 index 0000000000..3dfe6d4549 Binary files /dev/null and b/indra/newview/skins/default/textures/Accordion_ArrowClosed_Off.png differ diff --git a/indra/newview/skins/default/textures/Accordion_ArrowClosed_Press.png b/indra/newview/skins/default/textures/Accordion_ArrowClosed_Press.png new file mode 100644 index 0000000000..c381e8e1d5 Binary files /dev/null and b/indra/newview/skins/default/textures/Accordion_ArrowClosed_Press.png differ diff --git a/indra/newview/skins/default/textures/Accordion_ArrowOpened_Off.png b/indra/newview/skins/default/textures/Accordion_ArrowOpened_Off.png new file mode 100644 index 0000000000..1a898834c4 Binary files /dev/null and b/indra/newview/skins/default/textures/Accordion_ArrowOpened_Off.png differ diff --git a/indra/newview/skins/default/textures/Accordion_ArrowOpened_Press.png b/indra/newview/skins/default/textures/Accordion_ArrowOpened_Press.png new file mode 100644 index 0000000000..05b381bdbc Binary files /dev/null and b/indra/newview/skins/default/textures/Accordion_ArrowOpened_Press.png differ diff --git a/indra/newview/skins/default/textures/Accordion_Off.png b/indra/newview/skins/default/textures/Accordion_Off.png new file mode 100644 index 0000000000..47b63618f5 Binary files /dev/null and b/indra/newview/skins/default/textures/Accordion_Off.png differ diff --git a/indra/newview/skins/default/textures/Accordion_Over.png b/indra/newview/skins/default/textures/Accordion_Over.png new file mode 100644 index 0000000000..6dcb4401ec Binary files /dev/null and b/indra/newview/skins/default/textures/Accordion_Over.png differ diff --git a/indra/newview/skins/default/textures/Accordion_Press.png b/indra/newview/skins/default/textures/Accordion_Press.png new file mode 100644 index 0000000000..a6b17a91fb Binary files /dev/null and b/indra/newview/skins/default/textures/Accordion_Press.png differ diff --git a/indra/newview/skins/default/textures/Accordion_Selected.png b/indra/newview/skins/default/textures/Accordion_Selected.png new file mode 100644 index 0000000000..27091d3bdc Binary files /dev/null and b/indra/newview/skins/default/textures/Accordion_Selected.png differ diff --git a/indra/newview/skins/default/textures/Blank.png b/indra/newview/skins/default/textures/Blank.png new file mode 100644 index 0000000000..f38e9f9100 Binary files /dev/null and b/indra/newview/skins/default/textures/Blank.png differ diff --git a/indra/newview/skins/default/textures/Cam_Preset_Back_Off.png b/indra/newview/skins/default/textures/Cam_Preset_Back_Off.png new file mode 100644 index 0000000000..1ace20d141 Binary files /dev/null and b/indra/newview/skins/default/textures/Cam_Preset_Back_Off.png differ diff --git a/indra/newview/skins/default/textures/Cam_Preset_Back_On.png b/indra/newview/skins/default/textures/Cam_Preset_Back_On.png new file mode 100644 index 0000000000..fc7413de33 Binary files /dev/null and b/indra/newview/skins/default/textures/Cam_Preset_Back_On.png differ diff --git a/indra/newview/skins/default/textures/Cam_Preset_Front_Off.png b/indra/newview/skins/default/textures/Cam_Preset_Front_Off.png new file mode 100644 index 0000000000..19fcbb5c17 Binary files /dev/null and b/indra/newview/skins/default/textures/Cam_Preset_Front_Off.png differ diff --git a/indra/newview/skins/default/textures/Cam_Preset_Front_On.png b/indra/newview/skins/default/textures/Cam_Preset_Front_On.png new file mode 100644 index 0000000000..d40d8a1caf Binary files /dev/null and b/indra/newview/skins/default/textures/Cam_Preset_Front_On.png differ diff --git a/indra/newview/skins/default/textures/Cam_Preset_Side_Off.png b/indra/newview/skins/default/textures/Cam_Preset_Side_Off.png new file mode 100644 index 0000000000..08366b9186 Binary files /dev/null and b/indra/newview/skins/default/textures/Cam_Preset_Side_Off.png differ diff --git a/indra/newview/skins/default/textures/Cam_Preset_Side_On.png b/indra/newview/skins/default/textures/Cam_Preset_Side_On.png new file mode 100644 index 0000000000..9635186f06 Binary files /dev/null and b/indra/newview/skins/default/textures/Cam_Preset_Side_On.png differ diff --git a/indra/newview/skins/default/textures/Conv_toolbar_plus.png b/indra/newview/skins/default/textures/Conv_toolbar_plus.png new file mode 100644 index 0000000000..25a32cb2ba Binary files /dev/null and b/indra/newview/skins/default/textures/Conv_toolbar_plus.png differ diff --git a/indra/newview/skins/default/textures/Conv_toolbar_sort.png b/indra/newview/skins/default/textures/Conv_toolbar_sort.png new file mode 100644 index 0000000000..08debeb91f Binary files /dev/null and b/indra/newview/skins/default/textures/Conv_toolbar_sort.png differ diff --git a/indra/newview/skins/default/textures/Edit_Flip_X.png b/indra/newview/skins/default/textures/Edit_Flip_X.png new file mode 100644 index 0000000000..e19224d5ea Binary files /dev/null and b/indra/newview/skins/default/textures/Edit_Flip_X.png differ diff --git a/indra/newview/skins/default/textures/FMOD Logo.png b/indra/newview/skins/default/textures/FMOD Logo.png new file mode 100644 index 0000000000..3ddda90e2a Binary files /dev/null and b/indra/newview/skins/default/textures/FMOD Logo.png differ diff --git a/indra/newview/skins/default/textures/Flag.png b/indra/newview/skins/default/textures/Flag.png index 66739e9bf3..cf68046854 100644 Binary files a/indra/newview/skins/default/textures/Flag.png and b/indra/newview/skins/default/textures/Flag.png differ diff --git a/indra/newview/skins/default/textures/Inv_Post_Process.png b/indra/newview/skins/default/textures/Inv_Post_Process.png new file mode 100644 index 0000000000..2bdc31c637 Binary files /dev/null and b/indra/newview/skins/default/textures/Inv_Post_Process.png differ diff --git a/indra/newview/skins/default/textures/Inv_Settings.png b/indra/newview/skins/default/textures/Inv_Settings.png new file mode 100644 index 0000000000..49cfbe65cf Binary files /dev/null and b/indra/newview/skins/default/textures/Inv_Settings.png differ diff --git a/indra/newview/skins/default/textures/Inv_SettingsDay.png b/indra/newview/skins/default/textures/Inv_SettingsDay.png new file mode 100644 index 0000000000..2b36b1516e Binary files /dev/null and b/indra/newview/skins/default/textures/Inv_SettingsDay.png differ diff --git a/indra/newview/skins/default/textures/Inv_SettingsSky.png b/indra/newview/skins/default/textures/Inv_SettingsSky.png new file mode 100644 index 0000000000..4a85b3e8b3 Binary files /dev/null and b/indra/newview/skins/default/textures/Inv_SettingsSky.png differ diff --git a/indra/newview/skins/default/textures/Inv_SettingsWater.png b/indra/newview/skins/default/textures/Inv_SettingsWater.png new file mode 100644 index 0000000000..a0d879e441 Binary files /dev/null and b/indra/newview/skins/default/textures/Inv_SettingsWater.png differ diff --git a/indra/newview/skins/default/textures/Inv_StockFolderClosed.png b/indra/newview/skins/default/textures/Inv_StockFolderClosed.png new file mode 100644 index 0000000000..4dc484dc22 Binary files /dev/null and b/indra/newview/skins/default/textures/Inv_StockFolderClosed.png differ diff --git a/indra/newview/skins/default/textures/Inv_StockFolderOpen.png b/indra/newview/skins/default/textures/Inv_StockFolderOpen.png new file mode 100644 index 0000000000..0d140b56a7 Binary files /dev/null and b/indra/newview/skins/default/textures/Inv_StockFolderOpen.png differ diff --git a/indra/newview/skins/default/textures/Inv_Universal.png b/indra/newview/skins/default/textures/Inv_Universal.png new file mode 100644 index 0000000000..470febb9b5 Binary files /dev/null and b/indra/newview/skins/default/textures/Inv_Universal.png differ diff --git a/indra/newview/skins/default/textures/Inv_UnknownObject.png b/indra/newview/skins/default/textures/Inv_UnknownObject.png new file mode 100644 index 0000000000..2516afe7ab Binary files /dev/null and b/indra/newview/skins/default/textures/Inv_UnknownObject.png differ diff --git a/indra/newview/skins/default/textures/Inv_VersionFolderClosed.png b/indra/newview/skins/default/textures/Inv_VersionFolderClosed.png new file mode 100644 index 0000000000..e89a4d7f31 Binary files /dev/null and b/indra/newview/skins/default/textures/Inv_VersionFolderClosed.png differ diff --git a/indra/newview/skins/default/textures/Inv_VersionFolderOpen.png b/indra/newview/skins/default/textures/Inv_VersionFolderOpen.png new file mode 100644 index 0000000000..659d7d392f Binary files /dev/null and b/indra/newview/skins/default/textures/Inv_VersionFolderOpen.png differ diff --git a/indra/newview/skins/default/textures/Inv_WaterLight.png b/indra/newview/skins/default/textures/Inv_WaterLight.png index a5bc5f5490..6ba9a1786b 100644 Binary files a/indra/newview/skins/default/textures/Inv_WaterLight.png and b/indra/newview/skins/default/textures/Inv_WaterLight.png differ diff --git a/indra/newview/skins/default/textures/Inv_WindLight.png b/indra/newview/skins/default/textures/Inv_WindLight.png index 0e633a38f4..39cc20ac2d 100644 Binary files a/indra/newview/skins/default/textures/Inv_WindLight.png and b/indra/newview/skins/default/textures/Inv_WindLight.png differ diff --git a/indra/newview/skins/default/textures/MarketplaceBtn_Off.png b/indra/newview/skins/default/textures/MarketplaceBtn_Off.png new file mode 100644 index 0000000000..e603c44384 Binary files /dev/null and b/indra/newview/skins/default/textures/MarketplaceBtn_Off.png differ diff --git a/indra/newview/skins/default/textures/MarketplaceBtn_Selected.png b/indra/newview/skins/default/textures/MarketplaceBtn_Selected.png new file mode 100644 index 0000000000..fbc164123f Binary files /dev/null and b/indra/newview/skins/default/textures/MarketplaceBtn_Selected.png differ diff --git a/indra/newview/skins/default/textures/Marketplace_Dropzone_Background.png b/indra/newview/skins/default/textures/Marketplace_Dropzone_Background.png new file mode 100644 index 0000000000..9478f7b813 Binary files /dev/null and b/indra/newview/skins/default/textures/Marketplace_Dropzone_Background.png differ diff --git a/indra/newview/skins/default/textures/Parcel_Exp_Color.png b/indra/newview/skins/default/textures/Parcel_Exp_Color.png index 4813d37198..fd5c13e73d 100644 Binary files a/indra/newview/skins/default/textures/Parcel_Exp_Color.png and b/indra/newview/skins/default/textures/Parcel_Exp_Color.png differ diff --git a/indra/newview/skins/default/textures/Pathfinding_Dirty.png b/indra/newview/skins/default/textures/Pathfinding_Dirty.png index 4ed8c14427..c2a4aa4d51 100644 Binary files a/indra/newview/skins/default/textures/Pathfinding_Dirty.png and b/indra/newview/skins/default/textures/Pathfinding_Dirty.png differ diff --git a/indra/newview/skins/default/textures/Pathfinding_Disabled.png b/indra/newview/skins/default/textures/Pathfinding_Disabled.png index 09cb47edd7..4680a38f36 100644 Binary files a/indra/newview/skins/default/textures/Pathfinding_Disabled.png and b/indra/newview/skins/default/textures/Pathfinding_Disabled.png differ diff --git a/indra/newview/skins/default/textures/Progress_1.png b/indra/newview/skins/default/textures/Progress_1.png new file mode 100644 index 0000000000..69b9af5cd9 Binary files /dev/null and b/indra/newview/skins/default/textures/Progress_1.png differ diff --git a/indra/newview/skins/default/textures/Progress_10.png b/indra/newview/skins/default/textures/Progress_10.png new file mode 100644 index 0000000000..2fe5328f42 Binary files /dev/null and b/indra/newview/skins/default/textures/Progress_10.png differ diff --git a/indra/newview/skins/default/textures/Progress_11.png b/indra/newview/skins/default/textures/Progress_11.png new file mode 100644 index 0000000000..37a03fb621 Binary files /dev/null and b/indra/newview/skins/default/textures/Progress_11.png differ diff --git a/indra/newview/skins/default/textures/Progress_12.png b/indra/newview/skins/default/textures/Progress_12.png new file mode 100644 index 0000000000..243e514064 Binary files /dev/null and b/indra/newview/skins/default/textures/Progress_12.png differ diff --git a/indra/newview/skins/default/textures/Progress_2.png b/indra/newview/skins/default/textures/Progress_2.png new file mode 100644 index 0000000000..805175486f Binary files /dev/null and b/indra/newview/skins/default/textures/Progress_2.png differ diff --git a/indra/newview/skins/default/textures/Progress_3.png b/indra/newview/skins/default/textures/Progress_3.png new file mode 100644 index 0000000000..4b47177908 Binary files /dev/null and b/indra/newview/skins/default/textures/Progress_3.png differ diff --git a/indra/newview/skins/default/textures/Progress_4.png b/indra/newview/skins/default/textures/Progress_4.png new file mode 100644 index 0000000000..bdc3f886a9 Binary files /dev/null and b/indra/newview/skins/default/textures/Progress_4.png differ diff --git a/indra/newview/skins/default/textures/Progress_5.png b/indra/newview/skins/default/textures/Progress_5.png new file mode 100644 index 0000000000..3ee2d32ec2 Binary files /dev/null and b/indra/newview/skins/default/textures/Progress_5.png differ diff --git a/indra/newview/skins/default/textures/Progress_6.png b/indra/newview/skins/default/textures/Progress_6.png new file mode 100644 index 0000000000..3a5a45546e Binary files /dev/null and b/indra/newview/skins/default/textures/Progress_6.png differ diff --git a/indra/newview/skins/default/textures/Progress_7.png b/indra/newview/skins/default/textures/Progress_7.png new file mode 100644 index 0000000000..b9029cade2 Binary files /dev/null and b/indra/newview/skins/default/textures/Progress_7.png differ diff --git a/indra/newview/skins/default/textures/Progress_8.png b/indra/newview/skins/default/textures/Progress_8.png new file mode 100644 index 0000000000..357b1132f4 Binary files /dev/null and b/indra/newview/skins/default/textures/Progress_8.png differ diff --git a/indra/newview/skins/default/textures/Progress_9.png b/indra/newview/skins/default/textures/Progress_9.png new file mode 100644 index 0000000000..05c919072b Binary files /dev/null and b/indra/newview/skins/default/textures/Progress_9.png differ diff --git a/indra/newview/skins/default/textures/Refresh_Off.png b/indra/newview/skins/default/textures/Refresh_Off.png new file mode 100644 index 0000000000..1171ee3155 Binary files /dev/null and b/indra/newview/skins/default/textures/Refresh_Off.png differ diff --git a/indra/newview/skins/default/textures/Rounded_Rect.png b/indra/newview/skins/default/textures/Rounded_Rect.png index c270c28039..4da0c234ea 100644 Binary files a/indra/newview/skins/default/textures/Rounded_Rect.png and b/indra/newview/skins/default/textures/Rounded_Rect.png differ diff --git a/indra/newview/skins/default/textures/checkerboard_transparency_bg.png b/indra/newview/skins/default/textures/checkerboard_transparency_bg.png index 9a16935204..fe06d38eff 100644 Binary files a/indra/newview/skins/default/textures/checkerboard_transparency_bg.png and b/indra/newview/skins/default/textures/checkerboard_transparency_bg.png differ diff --git a/indra/newview/skins/default/textures/down_arrow.png b/indra/newview/skins/default/textures/down_arrow.png index 155f80c97e..d376d980d2 100644 Binary files a/indra/newview/skins/default/textures/down_arrow.png and b/indra/newview/skins/default/textures/down_arrow.png differ diff --git a/indra/newview/skins/default/textures/flatnormal.tga b/indra/newview/skins/default/textures/flatnormal.tga new file mode 100644 index 0000000000..6d5abd1782 Binary files /dev/null and b/indra/newview/skins/default/textures/flatnormal.tga differ diff --git a/indra/newview/skins/default/textures/go-home.png b/indra/newview/skins/default/textures/go-home.png index 058c00af4f..fc4a76c1c7 100644 Binary files a/indra/newview/skins/default/textures/go-home.png and b/indra/newview/skins/default/textures/go-home.png differ diff --git a/indra/newview/skins/default/textures/go-media-pause.png b/indra/newview/skins/default/textures/go-media-pause.png index 8aea17088a..f8ffc44a36 100644 Binary files a/indra/newview/skins/default/textures/go-media-pause.png and b/indra/newview/skins/default/textures/go-media-pause.png differ diff --git a/indra/newview/skins/default/textures/go-media-play.png b/indra/newview/skins/default/textures/go-media-play.png index daa40e3c36..b8bce12e68 100644 Binary files a/indra/newview/skins/default/textures/go-media-play.png and b/indra/newview/skins/default/textures/go-media-play.png differ diff --git a/indra/newview/skins/default/textures/go-media-skip-backwards.png b/indra/newview/skins/default/textures/go-media-skip-backwards.png index 02497b1656..16b042f36a 100644 Binary files a/indra/newview/skins/default/textures/go-media-skip-backwards.png and b/indra/newview/skins/default/textures/go-media-skip-backwards.png differ diff --git a/indra/newview/skins/default/textures/go-media-skip-forward.png b/indra/newview/skins/default/textures/go-media-skip-forward.png index 97090e1f1a..27ae7c7513 100644 Binary files a/indra/newview/skins/default/textures/go-media-skip-forward.png and b/indra/newview/skins/default/textures/go-media-skip-forward.png differ diff --git a/indra/newview/skins/default/textures/go-media-stop.png b/indra/newview/skins/default/textures/go-media-stop.png index 80a54d1b20..c951ac535a 100644 Binary files a/indra/newview/skins/default/textures/go-media-stop.png and b/indra/newview/skins/default/textures/go-media-stop.png differ diff --git a/indra/newview/skins/default/textures/go-media-unzoom.png b/indra/newview/skins/default/textures/go-media-unzoom.png index 0f45c2c9c7..42d7e69814 100644 Binary files a/indra/newview/skins/default/textures/go-media-unzoom.png and b/indra/newview/skins/default/textures/go-media-unzoom.png differ diff --git a/indra/newview/skins/default/textures/go-media-zoom.png b/indra/newview/skins/default/textures/go-media-zoom.png index b06c0fd52b..b214a88c2b 100644 Binary files a/indra/newview/skins/default/textures/go-media-zoom.png and b/indra/newview/skins/default/textures/go-media-zoom.png differ diff --git a/indra/newview/skins/default/textures/go-next.png b/indra/newview/skins/default/textures/go-next.png index b4362c1ed5..9f767fdd18 100644 Binary files a/indra/newview/skins/default/textures/go-next.png and b/indra/newview/skins/default/textures/go-next.png differ diff --git a/indra/newview/skins/default/textures/go-previous.png b/indra/newview/skins/default/textures/go-previous.png index d5a677ecd7..8cebd0eac9 100644 Binary files a/indra/newview/skins/default/textures/go-previous.png and b/indra/newview/skins/default/textures/go-previous.png differ diff --git a/indra/newview/skins/default/textures/go-reload.png b/indra/newview/skins/default/textures/go-reload.png index cb5d1b97c5..8b254921e2 100644 Binary files a/indra/newview/skins/default/textures/go-reload.png and b/indra/newview/skins/default/textures/go-reload.png differ diff --git a/indra/newview/skins/default/textures/go-stop.png b/indra/newview/skins/default/textures/go-stop.png index 08dab9a32b..0e91628f63 100644 Binary files a/indra/newview/skins/default/textures/go-stop.png and b/indra/newview/skins/default/textures/go-stop.png differ diff --git a/indra/newview/skins/default/textures/green_checkmark.png b/indra/newview/skins/default/textures/green_checkmark.png new file mode 100644 index 0000000000..eb0ba930c4 Binary files /dev/null and b/indra/newview/skins/default/textures/green_checkmark.png differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_about_land.tga b/indra/newview/skins/default/textures/icn_toolbar_about_land.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_about_land.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_about_region.tga b/indra/newview/skins/default/textures/icn_toolbar_about_region.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_about_region.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_about_viewer.tga b/indra/newview/skins/default/textures/icn_toolbar_about_viewer.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_about_viewer.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_anims_explorer.tga b/indra/newview/skins/default/textures/icn_toolbar_anims_explorer.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_anims_explorer.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_ao.tga b/indra/newview/skins/default/textures/icn_toolbar_ao.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_ao.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_appearance.tga b/indra/newview/skins/default/textures/icn_toolbar_appearance.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_appearance.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_areasearch.tga b/indra/newview/skins/default/textures/icn_toolbar_areasearch.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_areasearch.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_asset_blacklist.tga b/indra/newview/skins/default/textures/icn_toolbar_asset_blacklist.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_asset_blacklist.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_auto_replace.tga b/indra/newview/skins/default/textures/icn_toolbar_auto_replace.tga new file mode 100644 index 0000000000..0a1a235f35 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_auto_replace.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_avatar.tga b/indra/newview/skins/default/textures/icn_toolbar_avatar.tga new file mode 100644 index 0000000000..0a1a235f35 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_avatar.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_beacons.tga b/indra/newview/skins/default/textures/icn_toolbar_beacons.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_beacons.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_bumps.tga b/indra/newview/skins/default/textures/icn_toolbar_bumps.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_bumps.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_buy_currency.tga b/indra/newview/skins/default/textures/icn_toolbar_buy_currency.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_buy_currency.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_buy_land.tga b/indra/newview/skins/default/textures/icn_toolbar_buy_land.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_buy_land.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_camera_controls.tga b/indra/newview/skins/default/textures/icn_toolbar_camera_controls.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_camera_controls.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_change_buttons.tga b/indra/newview/skins/default/textures/icn_toolbar_change_buttons.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_change_buttons.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_day_cycle_editor.tga b/indra/newview/skins/default/textures/icn_toolbar_day_cycle_editor.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_day_cycle_editor.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_debug_avatar.tga b/indra/newview/skins/default/textures/icn_toolbar_debug_avatar.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_debug_avatar.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_debug_console.tga b/indra/newview/skins/default/textures/icn_toolbar_debug_console.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_debug_console.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_debug_settings.tga b/indra/newview/skins/default/textures/icn_toolbar_debug_settings.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_debug_settings.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_destinations.tga b/indra/newview/skins/default/textures/icn_toolbar_destinations.tga new file mode 100644 index 0000000000..0a1a235f35 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_destinations.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_display_name.tga b/indra/newview/skins/default/textures/icn_toolbar_display_name.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_display_name.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_edit_ui.tga b/indra/newview/skins/default/textures/icn_toolbar_edit_ui.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_edit_ui.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_env_editor.tga b/indra/newview/skins/default/textures/icn_toolbar_env_editor.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_env_editor.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_experiences.tga b/indra/newview/skins/default/textures/icn_toolbar_experiences.tga new file mode 100644 index 0000000000..0a1a235f35 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_experiences.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_fast_timers.tga b/indra/newview/skins/default/textures/icn_toolbar_fast_timers.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_fast_timers.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_favorites.tga b/indra/newview/skins/default/textures/icn_toolbar_favorites.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_favorites.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_font_test.tga b/indra/newview/skins/default/textures/icn_toolbar_font_test.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_font_test.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_frame_console.tga b/indra/newview/skins/default/textures/icn_toolbar_frame_console.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_frame_console.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_friends.tga b/indra/newview/skins/default/textures/icn_toolbar_friends.tga new file mode 100644 index 0000000000..0a1a235f35 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_friends.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_gestures.tga b/indra/newview/skins/default/textures/icn_toolbar_gestures.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_gestures.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_god_tools.tga b/indra/newview/skins/default/textures/icn_toolbar_god_tools.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_god_tools.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_grid_options.tga b/indra/newview/skins/default/textures/icn_toolbar_grid_options.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_grid_options.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_group_titles.tga b/indra/newview/skins/default/textures/icn_toolbar_group_titles.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_group_titles.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_groups.tga b/indra/newview/skins/default/textures/icn_toolbar_groups.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_groups.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_http_console.tga b/indra/newview/skins/default/textures/icn_toolbar_http_console.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_http_console.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_im.tga b/indra/newview/skins/default/textures/icn_toolbar_im.tga new file mode 100644 index 0000000000..0a1a235f35 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_im.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_inspect.tga b/indra/newview/skins/default/textures/icn_toolbar_inspect.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_inspect.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_joystick.tga b/indra/newview/skins/default/textures/icn_toolbar_joystick.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_joystick.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_local_assets.tga b/indra/newview/skins/default/textures/icn_toolbar_local_assets.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_local_assets.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_local_chat.tga b/indra/newview/skins/default/textures/icn_toolbar_local_chat.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_local_chat.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_make_outfit.tga b/indra/newview/skins/default/textures/icn_toolbar_make_outfit.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_make_outfit.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_marketplace.tga b/indra/newview/skins/default/textures/icn_toolbar_marketplace.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_marketplace.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_marketplace_listings.tga b/indra/newview/skins/default/textures/icn_toolbar_marketplace_listings.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_marketplace_listings.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_media_filter.tga b/indra/newview/skins/default/textures/icn_toolbar_media_filter.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_media_filter.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_media_ticker.tga b/indra/newview/skins/default/textures/icn_toolbar_media_ticker.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_media_ticker.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_memleak.tga b/indra/newview/skins/default/textures/icn_toolbar_memleak.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_memleak.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_message_log.tga b/indra/newview/skins/default/textures/icn_toolbar_message_log.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_message_log.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_mouselook.tga b/indra/newview/skins/default/textures/icn_toolbar_mouselook.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_mouselook.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_movement_controls.tga b/indra/newview/skins/default/textures/icn_toolbar_movement_controls.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_movement_controls.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_mute_list.tga b/indra/newview/skins/default/textures/icn_toolbar_mute_list.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_mute_list.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_my_land.tga b/indra/newview/skins/default/textures/icn_toolbar_my_land.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_my_land.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_notifications_console.tga b/indra/newview/skins/default/textures/icn_toolbar_notifications_console.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_notifications_console.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_outfits.tga b/indra/newview/skins/default/textures/icn_toolbar_outfits.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_outfits.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_pathfinding_characters.tga b/indra/newview/skins/default/textures/icn_toolbar_pathfinding_characters.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_pathfinding_characters.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_pathing_linksets.tga b/indra/newview/skins/default/textures/icn_toolbar_pathing_linksets.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_pathing_linksets.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_post_process.tga b/indra/newview/skins/default/textures/icn_toolbar_post_process.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_post_process.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_preferences.tga b/indra/newview/skins/default/textures/icn_toolbar_preferences.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_preferences.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_quit.tga b/indra/newview/skins/default/textures/icn_toolbar_quit.tga new file mode 100644 index 0000000000..0a1a235f35 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_quit.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_received_items.tga b/indra/newview/skins/default/textures/icn_toolbar_received_items.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_received_items.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_region_console.tga b/indra/newview/skins/default/textures/icn_toolbar_region_console.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_region_console.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_region_tracker.png b/indra/newview/skins/default/textures/icn_toolbar_region_tracker.png new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_region_tracker.png differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_report_abuse.tga b/indra/newview/skins/default/textures/icn_toolbar_report_abuse.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_report_abuse.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_rlv_locks.tga b/indra/newview/skins/default/textures/icn_toolbar_rlv_locks.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_rlv_locks.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_rlv_restrictions.tga b/indra/newview/skins/default/textures/icn_toolbar_rlv_restrictions.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_rlv_restrictions.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_rlv_strings.tga b/indra/newview/skins/default/textures/icn_toolbar_rlv_strings.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_rlv_strings.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_run.tga b/indra/newview/skins/default/textures/icn_toolbar_run.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_run.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_script_errors.tga b/indra/newview/skins/default/textures/icn_toolbar_script_errors.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_script_errors.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_script_info.tga b/indra/newview/skins/default/textures/icn_toolbar_script_info.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_script_info.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_sit.tga b/indra/newview/skins/default/textures/icn_toolbar_sit.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_sit.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_sound_explorer.tga b/indra/newview/skins/default/textures/icn_toolbar_sound_explorer.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_sound_explorer.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_stats.tga b/indra/newview/skins/default/textures/icn_toolbar_stats.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_stats.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_teleport_history.tga b/indra/newview/skins/default/textures/icn_toolbar_teleport_history.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_teleport_history.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_test.tga b/indra/newview/skins/default/textures/icn_toolbar_test.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_test.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_texture_category_console.tga b/indra/newview/skins/default/textures/icn_toolbar_texture_category_console.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_texture_category_console.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_texture_console.tga b/indra/newview/skins/default/textures/icn_toolbar_texture_console.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_texture_console.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_texture_size_console.tga b/indra/newview/skins/default/textures/icn_toolbar_texture_size_console.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_texture_size_console.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_tutorial.tga b/indra/newview/skins/default/textures/icn_toolbar_tutorial.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_tutorial.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_upload_perms.tga b/indra/newview/skins/default/textures/icn_toolbar_upload_perms.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_upload_perms.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_voice_effects.tga b/indra/newview/skins/default/textures/icn_toolbar_voice_effects.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_voice_effects.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_water_editor.tga b/indra/newview/skins/default/textures/icn_toolbar_water_editor.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_water_editor.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_web.tga b/indra/newview/skins/default/textures/icn_toolbar_web.tga new file mode 100644 index 0000000000..49e5d11a21 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_web.tga differ diff --git a/indra/newview/skins/default/textures/icn_toolbar_windlight.tga b/indra/newview/skins/default/textures/icn_toolbar_windlight.tga new file mode 100644 index 0000000000..0a1a235f35 Binary files /dev/null and b/indra/newview/skins/default/textures/icn_toolbar_windlight.tga differ diff --git a/indra/newview/skins/default/textures/inv_invalid.png b/indra/newview/skins/default/textures/inv_invalid.png index 5d070e4677..acefab8c41 100644 Binary files a/indra/newview/skins/default/textures/inv_invalid.png and b/indra/newview/skins/default/textures/inv_invalid.png differ diff --git a/indra/newview/skins/default/textures/inv_item_physics.png b/indra/newview/skins/default/textures/inv_item_physics.png index 360baec46d..f411622407 100644 Binary files a/indra/newview/skins/default/textures/inv_item_physics.png and b/indra/newview/skins/default/textures/inv_item_physics.png differ diff --git a/indra/newview/skins/default/textures/lock.png b/indra/newview/skins/default/textures/lock.png index d23cb4d297..0f07709084 100644 Binary files a/indra/newview/skins/default/textures/lock.png and b/indra/newview/skins/default/textures/lock.png differ diff --git a/indra/newview/skins/default/textures/materials_ui_x_24.png b/indra/newview/skins/default/textures/materials_ui_x_24.png new file mode 100644 index 0000000000..43a72ef043 Binary files /dev/null and b/indra/newview/skins/default/textures/materials_ui_x_24.png differ diff --git a/indra/newview/skins/default/textures/media_btn_back.png b/indra/newview/skins/default/textures/media_btn_back.png index 9783a03742..a93b74bc7b 100644 Binary files a/indra/newview/skins/default/textures/media_btn_back.png and b/indra/newview/skins/default/textures/media_btn_back.png differ diff --git a/indra/newview/skins/default/textures/media_btn_done.png b/indra/newview/skins/default/textures/media_btn_done.png index f407aa3580..2638d02df2 100644 Binary files a/indra/newview/skins/default/textures/media_btn_done.png and b/indra/newview/skins/default/textures/media_btn_done.png differ diff --git a/indra/newview/skins/default/textures/media_btn_forward.png b/indra/newview/skins/default/textures/media_btn_forward.png index 4e7e609802..d8f2d5c60d 100644 Binary files a/indra/newview/skins/default/textures/media_btn_forward.png and b/indra/newview/skins/default/textures/media_btn_forward.png differ diff --git a/indra/newview/skins/default/textures/media_btn_home.png b/indra/newview/skins/default/textures/media_btn_home.png index cc59ddf21e..6fd5e20ba1 100644 Binary files a/indra/newview/skins/default/textures/media_btn_home.png and b/indra/newview/skins/default/textures/media_btn_home.png differ diff --git a/indra/newview/skins/default/textures/media_btn_newwindow.png b/indra/newview/skins/default/textures/media_btn_newwindow.png index c5f9c972c3..ced106d5f3 100644 Binary files a/indra/newview/skins/default/textures/media_btn_newwindow.png and b/indra/newview/skins/default/textures/media_btn_newwindow.png differ diff --git a/indra/newview/skins/default/textures/media_btn_optimalzoom.png b/indra/newview/skins/default/textures/media_btn_optimalzoom.png index dd68edc667..19e692f3c5 100644 Binary files a/indra/newview/skins/default/textures/media_btn_optimalzoom.png and b/indra/newview/skins/default/textures/media_btn_optimalzoom.png differ diff --git a/indra/newview/skins/default/textures/media_btn_reload.png b/indra/newview/skins/default/textures/media_btn_reload.png index afbfe8f8a9..72cc54b607 100644 Binary files a/indra/newview/skins/default/textures/media_btn_reload.png and b/indra/newview/skins/default/textures/media_btn_reload.png differ diff --git a/indra/newview/skins/default/textures/media_btn_scrolldown.png b/indra/newview/skins/default/textures/media_btn_scrolldown.png index ad921d511f..149c6ba5b2 100644 Binary files a/indra/newview/skins/default/textures/media_btn_scrolldown.png and b/indra/newview/skins/default/textures/media_btn_scrolldown.png differ diff --git a/indra/newview/skins/default/textures/media_btn_scrollleft.png b/indra/newview/skins/default/textures/media_btn_scrollleft.png index a69c7e7bda..8f07aadf48 100644 Binary files a/indra/newview/skins/default/textures/media_btn_scrollleft.png and b/indra/newview/skins/default/textures/media_btn_scrollleft.png differ diff --git a/indra/newview/skins/default/textures/media_btn_scrollright.png b/indra/newview/skins/default/textures/media_btn_scrollright.png index c553449d1e..d6d58048a5 100644 Binary files a/indra/newview/skins/default/textures/media_btn_scrollright.png and b/indra/newview/skins/default/textures/media_btn_scrollright.png differ diff --git a/indra/newview/skins/default/textures/media_btn_scrollup.png b/indra/newview/skins/default/textures/media_btn_scrollup.png index ef37529274..cf87cf8fa4 100644 Binary files a/indra/newview/skins/default/textures/media_btn_scrollup.png and b/indra/newview/skins/default/textures/media_btn_scrollup.png differ diff --git a/indra/newview/skins/default/textures/media_btn_stoploading.png b/indra/newview/skins/default/textures/media_btn_stoploading.png index 8578d75477..dddf51abc4 100644 Binary files a/indra/newview/skins/default/textures/media_btn_stoploading.png and b/indra/newview/skins/default/textures/media_btn_stoploading.png differ diff --git a/indra/newview/skins/default/textures/media_panel_bg.png b/indra/newview/skins/default/textures/media_panel_bg.png index 975dc3e434..6e85569882 100644 Binary files a/indra/newview/skins/default/textures/media_panel_bg.png and b/indra/newview/skins/default/textures/media_panel_bg.png differ diff --git a/indra/newview/skins/default/textures/media_panel_divider.png b/indra/newview/skins/default/textures/media_panel_divider.png index 5f947e88a9..510151aba0 100644 Binary files a/indra/newview/skins/default/textures/media_panel_divider.png and b/indra/newview/skins/default/textures/media_panel_divider.png differ diff --git a/indra/newview/skins/default/textures/media_panel_hoverrectangle.png b/indra/newview/skins/default/textures/media_panel_hoverrectangle.png index 1cdeabf582..1fc0ebf885 100644 Binary files a/indra/newview/skins/default/textures/media_panel_hoverrectangle.png and b/indra/newview/skins/default/textures/media_panel_hoverrectangle.png differ diff --git a/indra/newview/skins/default/textures/media_panel_scrollbg.png b/indra/newview/skins/default/textures/media_panel_scrollbg.png index 2b63c9f5d7..3545b70331 100644 Binary files a/indra/newview/skins/default/textures/media_panel_scrollbg.png and b/indra/newview/skins/default/textures/media_panel_scrollbg.png differ diff --git a/indra/newview/skins/default/textures/menu_separator.png b/indra/newview/skins/default/textures/menu_separator.png index 89dcdcdff5..0b1cd3c656 100644 Binary files a/indra/newview/skins/default/textures/menu_separator.png and b/indra/newview/skins/default/textures/menu_separator.png differ diff --git a/indra/newview/skins/default/textures/navbar/Arrow_Left_Off.png b/indra/newview/skins/default/textures/navbar/Arrow_Left_Off.png new file mode 100644 index 0000000000..e1f28dc9b3 Binary files /dev/null and b/indra/newview/skins/default/textures/navbar/Arrow_Left_Off.png differ diff --git a/indra/newview/skins/default/textures/navbar/Arrow_Right_Off.png b/indra/newview/skins/default/textures/navbar/Arrow_Right_Off.png new file mode 100644 index 0000000000..b38cc89ad5 Binary files /dev/null and b/indra/newview/skins/default/textures/navbar/Arrow_Right_Off.png differ diff --git a/indra/newview/skins/default/textures/navbar/BuyArrow_Over.png b/indra/newview/skins/default/textures/navbar/BuyArrow_Over.png new file mode 100644 index 0000000000..bb387c9f98 Binary files /dev/null and b/indra/newview/skins/default/textures/navbar/BuyArrow_Over.png differ diff --git a/indra/newview/skins/default/textures/navbar/BuyArrow_Press.png b/indra/newview/skins/default/textures/navbar/BuyArrow_Press.png new file mode 100644 index 0000000000..c873fe920c Binary files /dev/null and b/indra/newview/skins/default/textures/navbar/BuyArrow_Press.png differ diff --git a/indra/newview/skins/default/textures/navbar/Favorite_Link_Over.png b/indra/newview/skins/default/textures/navbar/Favorite_Link_Over.png new file mode 100644 index 0000000000..50b70e68e1 Binary files /dev/null and b/indra/newview/skins/default/textures/navbar/Favorite_Link_Over.png differ diff --git a/indra/newview/skins/default/textures/navbar/Favorite_Star_Active.png b/indra/newview/skins/default/textures/navbar/Favorite_Star_Active.png new file mode 100644 index 0000000000..27076d2f41 Binary files /dev/null and b/indra/newview/skins/default/textures/navbar/Favorite_Star_Active.png differ diff --git a/indra/newview/skins/default/textures/navbar/Favorite_Star_Off.png b/indra/newview/skins/default/textures/navbar/Favorite_Star_Off.png new file mode 100644 index 0000000000..46b68a7575 Binary files /dev/null and b/indra/newview/skins/default/textures/navbar/Favorite_Star_Off.png differ diff --git a/indra/newview/skins/default/textures/navbar/Favorite_Star_Over.png b/indra/newview/skins/default/textures/navbar/Favorite_Star_Over.png new file mode 100644 index 0000000000..310b316bb6 Binary files /dev/null and b/indra/newview/skins/default/textures/navbar/Favorite_Star_Over.png differ diff --git a/indra/newview/skins/default/textures/navbar/Favorite_Star_Press.png b/indra/newview/skins/default/textures/navbar/Favorite_Star_Press.png new file mode 100644 index 0000000000..aa178320a5 Binary files /dev/null and b/indra/newview/skins/default/textures/navbar/Favorite_Star_Press.png differ diff --git a/indra/newview/skins/default/textures/navbar/FileMenu_Divider.png b/indra/newview/skins/default/textures/navbar/FileMenu_Divider.png new file mode 100644 index 0000000000..133eb4a3c2 Binary files /dev/null and b/indra/newview/skins/default/textures/navbar/FileMenu_Divider.png differ diff --git a/indra/newview/skins/default/textures/navbar/Flag.png b/indra/newview/skins/default/textures/navbar/Flag.png new file mode 100644 index 0000000000..b027733c33 Binary files /dev/null and b/indra/newview/skins/default/textures/navbar/Flag.png differ diff --git a/indra/newview/skins/default/textures/navbar/Help_Press.png b/indra/newview/skins/default/textures/navbar/Help_Press.png new file mode 100644 index 0000000000..a5794bb31a Binary files /dev/null and b/indra/newview/skins/default/textures/navbar/Help_Press.png differ diff --git a/indra/newview/skins/default/textures/navbar/Home_Off.png b/indra/newview/skins/default/textures/navbar/Home_Off.png new file mode 100644 index 0000000000..d70de58f10 Binary files /dev/null and b/indra/newview/skins/default/textures/navbar/Home_Off.png differ diff --git a/indra/newview/skins/default/textures/navbar/Icon_Lightshare.png b/indra/newview/skins/default/textures/navbar/Icon_Lightshare.png new file mode 100644 index 0000000000..52630389b1 Binary files /dev/null and b/indra/newview/skins/default/textures/navbar/Icon_Lightshare.png differ diff --git a/indra/newview/skins/default/textures/navbar/Info_Off.png b/indra/newview/skins/default/textures/navbar/Info_Off.png new file mode 100644 index 0000000000..44a5136794 Binary files /dev/null and b/indra/newview/skins/default/textures/navbar/Info_Off.png differ diff --git a/indra/newview/skins/default/textures/navbar/Info_Over.png b/indra/newview/skins/default/textures/navbar/Info_Over.png new file mode 100644 index 0000000000..3220339a7e Binary files /dev/null and b/indra/newview/skins/default/textures/navbar/Info_Over.png differ diff --git a/indra/newview/skins/default/textures/navbar/Info_Press.png b/indra/newview/skins/default/textures/navbar/Info_Press.png new file mode 100644 index 0000000000..66494e2a41 Binary files /dev/null and b/indra/newview/skins/default/textures/navbar/Info_Press.png differ diff --git a/indra/newview/skins/default/textures/navbar/Lock.png b/indra/newview/skins/default/textures/navbar/Lock.png new file mode 100644 index 0000000000..1f3ceb9517 Binary files /dev/null and b/indra/newview/skins/default/textures/navbar/Lock.png differ diff --git a/indra/newview/skins/default/textures/navbar/NavBar_BG.png b/indra/newview/skins/default/textures/navbar/NavBar_BG.png new file mode 100644 index 0000000000..bc523f9912 Binary files /dev/null and b/indra/newview/skins/default/textures/navbar/NavBar_BG.png differ diff --git a/indra/newview/skins/default/textures/navbar/NavBar_BG_NoFav_Bevel.png b/indra/newview/skins/default/textures/navbar/NavBar_BG_NoFav_Bevel.png new file mode 100644 index 0000000000..62a8d286c0 Binary files /dev/null and b/indra/newview/skins/default/textures/navbar/NavBar_BG_NoFav_Bevel.png differ diff --git a/indra/newview/skins/default/textures/navbar/NavBar_BG_NoNav_Bevel.png b/indra/newview/skins/default/textures/navbar/NavBar_BG_NoNav_Bevel.png new file mode 100644 index 0000000000..473dcd83d6 Binary files /dev/null and b/indra/newview/skins/default/textures/navbar/NavBar_BG_NoNav_Bevel.png differ diff --git a/indra/newview/skins/default/textures/navbar/Row_Selection.png b/indra/newview/skins/default/textures/navbar/Row_Selection.png new file mode 100644 index 0000000000..0f82246aec Binary files /dev/null and b/indra/newview/skins/default/textures/navbar/Row_Selection.png differ diff --git a/indra/newview/skins/default/textures/navbar/Search.png b/indra/newview/skins/default/textures/navbar/Search.png new file mode 100644 index 0000000000..35021add61 Binary files /dev/null and b/indra/newview/skins/default/textures/navbar/Search.png differ diff --git a/indra/newview/skins/default/textures/navbar/separator.png b/indra/newview/skins/default/textures/navbar/separator.png new file mode 100644 index 0000000000..89e2807db5 Binary files /dev/null and b/indra/newview/skins/default/textures/navbar/separator.png differ diff --git a/indra/newview/skins/default/textures/noentrylines.j2c b/indra/newview/skins/default/textures/noentrylines.j2c deleted file mode 100644 index 93ec17659d..0000000000 Binary files a/indra/newview/skins/default/textures/noentrylines.j2c and /dev/null differ diff --git a/indra/newview/skins/default/textures/noentrypasslines.j2c b/indra/newview/skins/default/textures/noentrypasslines.j2c deleted file mode 100644 index 800c466964..0000000000 Binary files a/indra/newview/skins/default/textures/noentrypasslines.j2c and /dev/null differ diff --git a/indra/newview/skins/default/textures/notify_next.png b/indra/newview/skins/default/textures/notify_next.png index 2235d25ff4..7b4aba9d35 100644 Binary files a/indra/newview/skins/default/textures/notify_next.png and b/indra/newview/skins/default/textures/notify_next.png differ diff --git a/indra/newview/skins/default/textures/preview.png b/indra/newview/skins/default/textures/preview.png index 40fe64bb49..e22b1c1644 100644 Binary files a/indra/newview/skins/default/textures/preview.png and b/indra/newview/skins/default/textures/preview.png differ diff --git a/indra/newview/skins/default/textures/red_x.png b/indra/newview/skins/default/textures/red_x.png new file mode 100644 index 0000000000..1ea8e42cb7 Binary files /dev/null and b/indra/newview/skins/default/textures/red_x.png differ diff --git a/indra/newview/skins/default/textures/skin_thumbnail_default.png b/indra/newview/skins/default/textures/skin_thumbnail_default.png deleted file mode 100644 index 40fe64bb49..0000000000 Binary files a/indra/newview/skins/default/textures/skin_thumbnail_default.png and /dev/null differ diff --git a/indra/newview/skins/default/textures/skin_thumbnail_silver.png b/indra/newview/skins/default/textures/skin_thumbnail_silver.png deleted file mode 100644 index 51707bb9d4..0000000000 Binary files a/indra/newview/skins/default/textures/skin_thumbnail_silver.png and /dev/null differ diff --git a/indra/newview/skins/default/textures/status_search_btn.png b/indra/newview/skins/default/textures/status_search_btn.png index 67f61332bc..e648ba8490 100644 Binary files a/indra/newview/skins/default/textures/status_search_btn.png and b/indra/newview/skins/default/textures/status_search_btn.png differ diff --git a/indra/newview/skins/default/textures/status_search_btn_pressed.png b/indra/newview/skins/default/textures/status_search_btn_pressed.png index 1437273d37..ec4254f4d9 100644 Binary files a/indra/newview/skins/default/textures/status_search_btn_pressed.png and b/indra/newview/skins/default/textures/status_search_btn_pressed.png differ diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index 92938cd5c4..e91c1b3c35 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -1,107 +1,312 @@ + + + + + + + + + + + - - - - - - - - - - + + + + + + - - - - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + + + + + + + - + - + - - - - - - - - - - - - - - - - + + + + + + - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + - - - @@ -114,18 +319,21 @@ - + - + + + + + - @@ -135,50 +343,52 @@ + - - + + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - - - - - - + - + + @@ -209,210 +419,53 @@ - - - - - - - + + + + + + + + + + + + + - + + - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + diff --git a/indra/newview/skins/default/textures/up_arrow.png b/indra/newview/skins/default/textures/up_arrow.png index fe68ad49dc..a1a5d38233 100644 Binary files a/indra/newview/skins/default/textures/up_arrow.png and b/indra/newview/skins/default/textures/up_arrow.png differ diff --git a/indra/newview/skins/default/textures/world/BeaconArrow.png b/indra/newview/skins/default/textures/world/BeaconArrow.png new file mode 100644 index 0000000000..ac7993f09b Binary files /dev/null and b/indra/newview/skins/default/textures/world/BeaconArrow.png differ diff --git a/indra/newview/skins/default/textures/world/CameraDragDot.png b/indra/newview/skins/default/textures/world/CameraDragDot.png new file mode 100644 index 0000000000..786f0de914 Binary files /dev/null and b/indra/newview/skins/default/textures/world/CameraDragDot.png differ diff --git a/indra/newview/skins/default/textures/world/NoEntryLines.png b/indra/newview/skins/default/textures/world/NoEntryLines.png new file mode 100644 index 0000000000..d16f69a459 Binary files /dev/null and b/indra/newview/skins/default/textures/world/NoEntryLines.png differ diff --git a/indra/newview/skins/default/textures/world/NoEntryPassLines.png b/indra/newview/skins/default/textures/world/NoEntryPassLines.png new file mode 100644 index 0000000000..87ed0b3958 Binary files /dev/null and b/indra/newview/skins/default/textures/world/NoEntryPassLines.png differ diff --git a/indra/newview/skins/default/xui/de/floater_about.xml b/indra/newview/skins/default/xui/de/floater_about.xml index 75e60e0a37..ad0eae39de 100644 --- a/indra/newview/skins/default/xui/de/floater_about.xml +++ b/indra/newview/skins/default/xui/de/floater_about.xml @@ -1,14 +1,11 @@ - + -
    @@ -85,18 +85,18 @@ + + diff --git a/indra/newview/skins/default/xui/en-us/floater_buy_currency.xml b/indra/newview/skins/default/xui/en-us/floater_buy_currency.xml index 07a341e827..a0ea720937 100644 --- a/indra/newview/skins/default/xui/en-us/floater_buy_currency.xml +++ b/indra/newview/skins/default/xui/en-us/floater_buy_currency.xml @@ -26,11 +26,11 @@ left="0" name="step_1" width="64" /> - Contacting LindeX... + Contacting currency exchange... - Buy [CURRENCY] on the LindeX currency exchange + Buy [CURRENCY] on the currency exchange @@ -46,7 +46,7 @@ - for approx. US$ [USD] + for approx. [REALCURRENCY] [USD] @@ -91,6 +91,6 @@ Increase the amount to buy. + + + Object Info + Name: [NAME] + Exportable Prims: [COUNT]/[TOTAL] + Exportable Textures: [COUNT]/[TOTAL] + + + Options + + + + + TGA + PNG + J2C + BMP + JPG + + + + + + + + diff --git a/indra/newview/skins/default/xui/en-us/floater_destinations.xml b/indra/newview/skins/default/xui/en-us/floater_destinations.xml new file mode 100644 index 0000000000..a5c6c07ace --- /dev/null +++ b/indra/newview/skins/default/xui/en-us/floater_destinations.xml @@ -0,0 +1,26 @@ + + + + diff --git a/indra/newview/skins/default/xui/en-us/floater_directory.xml b/indra/newview/skins/default/xui/en-us/floater_directory.xml index 434b849ac9..16a703de18 100644 --- a/indra/newview/skins/default/xui/en-us/floater_directory.xml +++ b/indra/newview/skins/default/xui/en-us/floater_directory.xml @@ -1,10 +1,69 @@ + + + Searching... + + + None Found. + + + + + Loading... + Done + http://search.secondlife.com/ Loading... Done - http://secondlife.com/app/search/notfound.html "http://secondlife.com/app/showcase/index.php?" - Linden Location + Official Location Arts and Culture @@ -612,7 +681,7 @@ To buy direct, visit the land and click on the place name in the title bar. label="Search" label_selected="Search" left="121" mouse_opaque="true" name="Search" width="95" /> @@ -674,7 +743,7 @@ To buy direct, visit the land and click on the place name in the title bar. + multi_select="false" name="results" search_column="2" width="339" menu_num="1"> @@ -690,26 +759,12 @@ To buy direct, visit the land and click on the place name in the title bar. - - - Loading... - Done - http://search.secondlife.com/ - http://search.secondlife.com/ - - - - - Searching... - - - None Found. - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/indra/newview/skins/default/xui/en-us/floater_merchant_outbox.xml b/indra/newview/skins/default/xui/en-us/floater_merchant_outbox.xml deleted file mode 100644 index 62d84d7c04..0000000000 --- a/indra/newview/skins/default/xui/en-us/floater_merchant_outbox.xml +++ /dev/null @@ -1,147 +0,0 @@ - - - No folders - 1 folder - [NUM] folders - Sending folders... - Initializing... - - - - Loading... - - - - - - - - Drag items here to create folders - - - - + diff --git a/indra/newview/skins/default/xui/en-us/floater_preview_gesture.xml b/indra/newview/skins/default/xui/en-us/floater_preview_gesture.xml index c17398f9d8..9ddf12f2c0 100644 --- a/indra/newview/skins/default/xui/en-us/floater_preview_gesture.xml +++ b/indra/newview/skins/default/xui/en-us/floater_preview_gesture.xml @@ -24,14 +24,14 @@ name="trigger_label"> Trigger: - Replace with: - @@ -101,8 +101,10 @@ unless you add wait steps. name="active_check" tool_tip="Active gestures can be triggered by chatting their trigger phrases or pressing their hot keys. Gestures usually become inactive when there is a key binding conflict." width="100" /> - + diff --git a/indra/newview/skins/default/xui/en-us/floater_script_ed_panel.xml b/indra/newview/skins/default/xui/en-us/floater_script_ed_panel.xml index 9e51475955..ed618c914e 100644 --- a/indra/newview/skins/default/xui/en-us/floater_script_ed_panel.xml +++ b/indra/newview/skins/default/xui/en-us/floater_script_ed_panel.xml @@ -4,7 +4,7 @@ Loading... @@ -17,7 +17,7 @@ + multi_select="true" name="lsl errors" width="492" /> @@ -32,38 +32,23 @@ - - + + - - - - - - - - - - - - + + + + + + + + + + + + - + True - + False - - - - @@ -43,7 +40,10 @@ max_val="10000000" name="val_spinner_4" visible="false" width="120"> - diff --git a/indra/newview/skins/default/xui/en-us/floater_snapshot.xml b/indra/newview/skins/default/xui/en-us/floater_snapshot.xml index 9e78bb6d3b..5345bd16fd 100644 --- a/indra/newview/skins/default/xui/en-us/floater_snapshot.xml +++ b/indra/newview/skins/default/xui/en-us/floater_snapshot.xml @@ -1,6 +1,6 @@ File size: [SIZE] KB @@ -8,22 +8,21 @@ Target - - + + Post to profile feed - - + + Send via email - - - Save to inventory ([UPLOADFEE]) - - + + + Save to inventory + + Save to hard drive - - - + @@ -294,6 +306,9 @@ image_unselected="object_grass.tga" label="" label_selected="" left_delta="23" mouse_opaque="true" name="ToolGrass" scale_image="TRUE" tool_tip="Grass" width="24" /> + + + Random [DESC] [NUM] + Nothing selected. + font="SansSerifSmall" halign="right" height="16" font-style="UNDERLINE" + mouse_opaque="true" name="selection_count" v_pad="0" width="143"/> @@ -429,54 +447,43 @@ follows="left|top|right" font="SansSerifSmall" height="16" left="88" max_length="127" mouse_opaque="true" name="Object Description" select_all_on_focus_received="true" width="172" /> + Creator: - + mouse_opaque="true" name="Creator Name" v_pad="0" rlv_sensitive="true"> Thrax Linden - - - - - - - + diff --git a/indra/newview/skins/default/xui/en-us/floater_tos.xml b/indra/newview/skins/default/xui/en-us/floater_tos.xml index 5451b35ef8..437ed18920 100644 --- a/indra/newview/skins/default/xui/en-us/floater_tos.xml +++ b/indra/newview/skins/default/xui/en-us/floater_tos.xml @@ -29,7 +29,7 @@ you must accept the agreement. height="340" left="16" max_length="65536" mouse_opaque="true" trusted_content="true" name="tos_html" - start_url="data:text/html,%3Chtml%3E%3Chead%3E%3C/head%3E%3Cbody text=%22000000%22%3E%3Ch2%3E Loading %3Ca%20target%3D%22_external%22%20href%3D%22http%3A//secondlife.com/app/tos/%22%3ETerms%20of%20Service%3C/a%3E...%3C/h2%3E %3C/body%3E %3C/html%3E" + start_url="data:text/html;charset=utf-8;base64,PGh0bWw+DQo8aGVhZD4NCjxzdHlsZT4NCmJvZHkgew0KICBmb250LWZhbWlseTogIkRlamEgVnUgU2FucyIsIEhlbHZldGljYSwgQXJpYWwsIHNhbnMtc2VyaWY7DQogIGNvbG9yOiAjZmZmOw0KICBiYWNrZ3JvdW5kLWNvbG9yOiByZ2IoMzEsIDMxLCAzMSk7DQp9DQphIHsNCiAgICBjb2xvcjogcmdiKDkyLCAxNzcsIDE0Nik7DQogICAgdGV4dC1kZWNvcmF0aW9uOiBub25lOw0KfQ0KI2NlbnRlcmVkIHsNCiAgcG9zaXRpb246IHJlbGF0aXZlOw0KICBmbG9hdDogbGVmdDsNCiAgdG9wOiA1MCU7DQogIGxlZnQ6IDUwJTsNCiAgdHJhbnNmb3JtOiB0cmFuc2xhdGUoLTUwJSwgLTUwJSk7DQp9DQo8L3N0eWxlPg0KPC9oZWFkPg0KPGJvZHk+DQo8ZGl2IGlkPSJjZW50ZXJlZCI+TG9hZGluZyA8YSB0YXJnZXQ9Il9leHRlcm5hbCIgaHJlZj0iaHR0cDovL3NlY29uZGxpZmUuY29tL2FwcC90b3MvIj5UZXJtcyBvZiBTZXJ2aWNlPC9hPi4uLjwvZGl2Pg0KPC9ib2R5Pg0KPC9odG1sPg==" width="568" word_wrap="true" /> http://secondlife.com/app/tos/ diff --git a/indra/newview/skins/default/xui/en-us/floater_voice_license.xml b/indra/newview/skins/default/xui/en-us/floater_voice_license.xml index 40e75b4a4d..065f6b8c09 100644 --- a/indra/newview/skins/default/xui/en-us/floater_voice_license.xml +++ b/indra/newview/skins/default/xui/en-us/floater_voice_license.xml @@ -32,9 +32,9 @@ To use voice, you must accept the license agreement. start_url="data:text/html,%3Chtml%3E%3Chead%3E%3C/head%3E%3Cbody text=%22000000%22%3E%3Ch2%3E Loading %3Ca%20target%3D%22_external%22%20href%3D%22http%3A//vivox.com/vivox_aup.html%22%3EVivox%20Acceptable%20Use%20Policy%3C/a%3E...%3C/h2%3E %3C/body%3E %3C/html%3E" width="568" word_wrap="true" /> - vivox_aup.html + https://www.vivox.com/policies/acceptable_use.html - vivox_aup.html + http://replex-viewer.github.io/pages/vivox_aup.html diff --git a/indra/newview/skins/default/xui/en-us/floater_windlight_options.xml b/indra/newview/skins/default/xui/en-us/floater_windlight_options.xml index 4a0e79fd04..9210a2c9b5 100644 --- a/indra/newview/skins/default/xui/en-us/floater_windlight_options.xml +++ b/indra/newview/skins/default/xui/en-us/floater_windlight_options.xml @@ -351,7 +351,7 @@ mouse_opaque="true" name="WLGlowB" show_text="true" value="1.0" width="200" /> + DejaVuSansCondensed.ttf + NotoSansDisplay-Regular.ttf + SourceHanSansJP-Regular.otf + SourceHanSansKR-Regular.otf + SourceHanSansCN-Regular.otf + SourceHanSansHK-Regular.otf + SourceHanSansTW-Regular.otf + YuGothR.ttc + meiryo.TTC MSGOTHIC.TTC gulim.ttc simhei.ttf ArialUni.ttf + seguisym.ttf ヒラギノ角ゴ ProN W3.otf @@ -20,14 +29,48 @@ + + DroidSans-Bold.ttf + DejaVuSansCondensed-Bold.ttf + NotoSansDisplay-Bold.ttf + SourceHanSansJP-Bold.otf + SourceHanSansKR-Bold.otf + SourceHanSansCN-Bold.otf + SourceHanSansHK-Bold.otf + SourceHanSansTW-Bold.otf + + DroidSans.ttf - + font_style="BOLD"> DroidSans-Bold.ttf + DejaVuSansCondensed-Bold.ttf + NotoSansDisplay-Bold.ttf + SourceHanSansJP-Bold.otf + SourceHanSansKR-Bold.otf + SourceHanSansCN-Bold.otf + SourceHanSansHK-Bold.otf + SourceHanSansTW-Bold.otf + + + + DejaVuSansCondensed-Oblique.ttf + NotoSansDisplay-Italic.ttf + + + + DejaVuSansCondensed-BoldOblique.ttf + NotoSansDisplay-BoldItalic.ttf - DejaVuSans.ttf + DejaVuSansCondensed.ttf - DejaVuSansBold.ttf + DejaVuSansCondensed-Bold.ttf - DejaVuSansOblique.ttf + DejaVuSansCondensed-Oblique.ttf - DejaVuSansBoldOblique.ttf + DejaVuSansCondensed-BoldOblique.ttf - diff --git a/indra/newview/skins/default/xui/en-us/menu_avs_list.xml b/indra/newview/skins/default/xui/en-us/menu_avs_list.xml index 402c5ca7be..17350a7d07 100644 --- a/indra/newview/skins/default/xui/en-us/menu_avs_list.xml +++ b/indra/newview/skins/default/xui/en-us/menu_avs_list.xml @@ -4,66 +4,139 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/indra/newview/skins/default/xui/en-us/menu_experiences.xml b/indra/newview/skins/default/xui/en-us/menu_experiences.xml new file mode 100644 index 0000000000..421eda40a1 --- /dev/null +++ b/indra/newview/skins/default/xui/en-us/menu_experiences.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/indra/newview/skins/default/xui/en-us/menu_groups_list.xml b/indra/newview/skins/default/xui/en-us/menu_groups_list.xml new file mode 100644 index 0000000000..67c84ed544 --- /dev/null +++ b/indra/newview/skins/default/xui/en-us/menu_groups_list.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/indra/newview/skins/default/xui/en-us/menu_inventory.xml b/indra/newview/skins/default/xui/en-us/menu_inventory.xml index 886c349848..dd516bc28c 100644 --- a/indra/newview/skins/default/xui/en-us/menu_inventory.xml +++ b/indra/newview/skins/default/xui/en-us/menu_inventory.xml @@ -1,6 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -25,6 +74,9 @@ name="Task Remove" width="128"> + + + @@ -42,6 +94,9 @@ + + + @@ -105,6 +160,9 @@ mouse_opaque="true" name="New Alpha" width="128"> + + + @@ -224,6 +282,9 @@ name="Delete" width="128"> + + + @@ -240,6 +301,7 @@ mouse_opaque="true" name="Replace Outfit" width="128"> + @@ -253,7 +315,7 @@ - + - + @@ -339,14 +401,15 @@ - - + + - - + + + + + diff --git a/indra/newview/skins/default/xui/en-us/menu_local_avs.xml b/indra/newview/skins/default/xui/en-us/menu_local_avs.xml new file mode 100644 index 0000000000..87e6272f48 --- /dev/null +++ b/indra/newview/skins/default/xui/en-us/menu_local_avs.xml @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/indra/newview/skins/default/xui/en-us/menu_login.xml b/indra/newview/skins/default/xui/en-us/menu_login.xml index 8b4e4ff866..f20f5d0814 100644 --- a/indra/newview/skins/default/xui/en-us/menu_login.xml +++ b/indra/newview/skins/default/xui/en-us/menu_login.xml @@ -13,6 +13,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -21,13 +47,17 @@ - - - + + + + + diff --git a/indra/newview/skins/default/xui/en-us/menu_marketplace_view.xml b/indra/newview/skins/default/xui/en-us/menu_marketplace_view.xml new file mode 100644 index 0000000000..2a266f5fb0 --- /dev/null +++ b/indra/newview/skins/default/xui/en-us/menu_marketplace_view.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/indra/newview/skins/default/xui/en-us/menu_media_ctrl.xml b/indra/newview/skins/default/xui/en-us/menu_media_ctrl.xml index ca9deedcc6..bc1cb29ca9 100644 --- a/indra/newview/skins/default/xui/en-us/menu_media_ctrl.xml +++ b/indra/newview/skins/default/xui/en-us/menu_media_ctrl.xml @@ -1,6 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/indra/newview/skins/default/xui/en-us/menu_mini_map.xml b/indra/newview/skins/default/xui/en-us/menu_mini_map.xml index c870268ce7..dfa3450df8 100644 --- a/indra/newview/skins/default/xui/en-us/menu_mini_map.xml +++ b/indra/newview/skins/default/xui/en-us/menu_mini_map.xml @@ -1,73 +1,116 @@ - + - + - + - - - + + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + - - - - - - - + + - + - + - + - + - - - - - + + + + + + + + + + diff --git a/indra/newview/skins/default/xui/en-us/menu_nameeditor_avatar.xml b/indra/newview/skins/default/xui/en-us/menu_nameeditor_avatar.xml new file mode 100644 index 0000000000..7f7f6995aa --- /dev/null +++ b/indra/newview/skins/default/xui/en-us/menu_nameeditor_avatar.xml @@ -0,0 +1,3 @@ + + + diff --git a/indra/newview/skins/default/xui/en-us/menu_nameeditor_group.xml b/indra/newview/skins/default/xui/en-us/menu_nameeditor_group.xml new file mode 100644 index 0000000000..cd237eee95 --- /dev/null +++ b/indra/newview/skins/default/xui/en-us/menu_nameeditor_group.xml @@ -0,0 +1,3 @@ + + + diff --git a/indra/newview/skins/default/xui/en-us/menu_objects_list.xml b/indra/newview/skins/default/xui/en-us/menu_objects_list.xml new file mode 100644 index 0000000000..ef7619d5e7 --- /dev/null +++ b/indra/newview/skins/default/xui/en-us/menu_objects_list.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/indra/newview/skins/default/xui/en-us/menu_objects_list_owners.xml b/indra/newview/skins/default/xui/en-us/menu_objects_list_owners.xml new file mode 100644 index 0000000000..cf21c07562 --- /dev/null +++ b/indra/newview/skins/default/xui/en-us/menu_objects_list_owners.xml @@ -0,0 +1,143 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/indra/newview/skins/default/xui/en-us/menu_pie_attachment.xml b/indra/newview/skins/default/xui/en-us/menu_pie_attachment.xml index 03b0b0fdf9..ba3fb21058 100644 --- a/indra/newview/skins/default/xui/en-us/menu_pie_attachment.xml +++ b/indra/newview/skins/default/xui/en-us/menu_pie_attachment.xml @@ -19,8 +19,8 @@ - - + + @@ -55,7 +55,7 @@ - + @@ -68,6 +68,34 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/indra/newview/skins/default/xui/en-us/menu_pie_avatar.xml b/indra/newview/skins/default/xui/en-us/menu_pie_avatar.xml index c57ab30592..8ea82e222e 100644 --- a/indra/newview/skins/default/xui/en-us/menu_pie_avatar.xml +++ b/indra/newview/skins/default/xui/en-us/menu_pie_avatar.xml @@ -17,11 +17,11 @@ - + - + @@ -32,7 +32,18 @@ - + + + + + + + + + + + + @@ -56,9 +64,12 @@ - + + + + diff --git a/indra/newview/skins/default/xui/en-us/menu_pie_object.xml b/indra/newview/skins/default/xui/en-us/menu_pie_object.xml index 940729207e..776b8d01d1 100644 --- a/indra/newview/skins/default/xui/en-us/menu_pie_object.xml +++ b/indra/newview/skins/default/xui/en-us/menu_pie_object.xml @@ -24,7 +24,7 @@ - + @@ -37,15 +37,29 @@ - - + + + - - - + + + + + + + + + + + + + + + + @@ -60,18 +74,13 @@ - - - - - - - + + - - - + + + @@ -81,7 +90,7 @@ - + @@ -92,7 +101,7 @@ - + @@ -102,7 +111,7 @@ - + diff --git a/indra/newview/skins/default/xui/en-us/menu_pie_self.xml b/indra/newview/skins/default/xui/en-us/menu_pie_self.xml index 9b35ae1f3e..81ee09fd6f 100644 --- a/indra/newview/skins/default/xui/en-us/menu_pie_self.xml +++ b/indra/newview/skins/default/xui/en-us/menu_pie_self.xml @@ -1,109 +1,122 @@ - - - - - - - - - + + + + + + + + - - - - + + + - - - - + + + - - - - + + + - - - - + + + - - - - + + + - - - - - + + + + - - - - - + + + + - - - + + - - - - + + + - - - - + + + - - - + + + - - + - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - + + + + diff --git a/indra/newview/skins/default/xui/en-us/menu_radar.xml b/indra/newview/skins/default/xui/en-us/menu_radar.xml index 5552f27c99..fc1a00689d 100644 --- a/indra/newview/skins/default/xui/en-us/menu_radar.xml +++ b/indra/newview/skins/default/xui/en-us/menu_radar.xml @@ -43,27 +43,56 @@ + + + + + + + + - + - - + + - + + + + + + + + + + + + + - + + - + + + + + + + + + @@ -89,6 +118,27 @@ + + + + + + + + + + + + + + + + + + + + + @@ -115,6 +165,10 @@ + + + + @@ -129,14 +183,18 @@ - + - + @@ -156,10 +214,6 @@ - - - - @@ -172,6 +226,14 @@ + + + + + + + + diff --git a/indra/newview/skins/default/xui/en-us/menu_texteditor.xml b/indra/newview/skins/default/xui/en-us/menu_texteditor.xml new file mode 100644 index 0000000000..8292d8d911 --- /dev/null +++ b/indra/newview/skins/default/xui/en-us/menu_texteditor.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/indra/newview/skins/default/xui/en-us/menu_url_agent.xml b/indra/newview/skins/default/xui/en-us/menu_url_agent.xml new file mode 100644 index 0000000000..da88c9fced --- /dev/null +++ b/indra/newview/skins/default/xui/en-us/menu_url_agent.xml @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/indra/newview/skins/default/xui/en-us/menu_url_email.xml b/indra/newview/skins/default/xui/en-us/menu_url_email.xml new file mode 100644 index 0000000000..cfd91a65d5 --- /dev/null +++ b/indra/newview/skins/default/xui/en-us/menu_url_email.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + diff --git a/indra/newview/skins/default/xui/en-us/menu_url_experience.xml b/indra/newview/skins/default/xui/en-us/menu_url_experience.xml new file mode 100644 index 0000000000..7ab1c710ff --- /dev/null +++ b/indra/newview/skins/default/xui/en-us/menu_url_experience.xml @@ -0,0 +1,11 @@ + + + + + + + diff --git a/indra/newview/skins/default/xui/en-us/menu_url_group.xml b/indra/newview/skins/default/xui/en-us/menu_url_group.xml new file mode 100644 index 0000000000..7200b6e035 --- /dev/null +++ b/indra/newview/skins/default/xui/en-us/menu_url_group.xml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/indra/newview/skins/default/xui/en-us/menu_url_http.xml b/indra/newview/skins/default/xui/en-us/menu_url_http.xml new file mode 100644 index 0000000000..ed2d714352 --- /dev/null +++ b/indra/newview/skins/default/xui/en-us/menu_url_http.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/indra/newview/skins/default/xui/en-us/menu_url_inventory.xml b/indra/newview/skins/default/xui/en-us/menu_url_inventory.xml new file mode 100644 index 0000000000..f1b4acbbb7 --- /dev/null +++ b/indra/newview/skins/default/xui/en-us/menu_url_inventory.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + diff --git a/indra/newview/skins/default/xui/en-us/menu_url_map.xml b/indra/newview/skins/default/xui/en-us/menu_url_map.xml new file mode 100644 index 0000000000..4cad974448 --- /dev/null +++ b/indra/newview/skins/default/xui/en-us/menu_url_map.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + diff --git a/indra/newview/skins/default/xui/en-us/menu_url_object_owner.xml b/indra/newview/skins/default/xui/en-us/menu_url_object_owner.xml new file mode 100644 index 0000000000..3ee8b614b8 --- /dev/null +++ b/indra/newview/skins/default/xui/en-us/menu_url_object_owner.xml @@ -0,0 +1,113 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/indra/newview/skins/default/xui/en-us/menu_url_objectim.xml b/indra/newview/skins/default/xui/en-us/menu_url_objectim.xml new file mode 100644 index 0000000000..6ec0dac59c --- /dev/null +++ b/indra/newview/skins/default/xui/en-us/menu_url_objectim.xml @@ -0,0 +1,110 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/indra/newview/skins/default/xui/en-us/menu_url_parcel.xml b/indra/newview/skins/default/xui/en-us/menu_url_parcel.xml new file mode 100644 index 0000000000..372454835a --- /dev/null +++ b/indra/newview/skins/default/xui/en-us/menu_url_parcel.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + diff --git a/indra/newview/skins/default/xui/en-us/menu_url_slapp.xml b/indra/newview/skins/default/xui/en-us/menu_url_slapp.xml new file mode 100644 index 0000000000..7fdb07d9ee --- /dev/null +++ b/indra/newview/skins/default/xui/en-us/menu_url_slapp.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + diff --git a/indra/newview/skins/default/xui/en-us/menu_url_slurl.xml b/indra/newview/skins/default/xui/en-us/menu_url_slurl.xml new file mode 100644 index 0000000000..8d3900228c --- /dev/null +++ b/indra/newview/skins/default/xui/en-us/menu_url_slurl.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/indra/newview/skins/default/xui/en-us/menu_url_teleport.xml b/indra/newview/skins/default/xui/en-us/menu_url_teleport.xml new file mode 100644 index 0000000000..f1b3ad5faa --- /dev/null +++ b/indra/newview/skins/default/xui/en-us/menu_url_teleport.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + diff --git a/indra/newview/skins/default/xui/en-us/menu_viewer.xml b/indra/newview/skins/default/xui/en-us/menu_viewer.xml index 192d3ff7ba..b83ffe4f6b 100644 --- a/indra/newview/skins/default/xui/en-us/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en-us/menu_viewer.xml @@ -5,31 +5,31 @@ - - + - - + - - + - - - + - - - - - - + - + @@ -274,7 +269,7 @@ - + @@ -284,18 +279,18 @@ - + - + + + + @@ -323,9 +321,12 @@ mouse_opaque="true" name="separator" width="211" /> - - + + + + + @@ -333,8 +334,8 @@ - - + + @@ -356,11 +357,6 @@ - - - - - + - - - + + + - - + + @@ -511,7 +508,7 @@ - + @@ -537,6 +534,11 @@ + @@ -549,6 +551,38 @@ mouse_opaque="true" name="Set Busy" width="185"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -564,18 +598,21 @@ + userdata="WebLaunchAccountHistory,https://accounts.secondlife.com/transaction_history/" /> + userdata="WebLaunchJoinNow,https://secondlife.com/my/account/index.php" /> + + + - - + label="Marketplace Listings..." + name="MarketplaceListings"> + + @@ -583,12 +620,32 @@ - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -613,39 +670,49 @@ - - - + + + - - + + + - - + + + - - + + + - + + + - + - + - + @@ -897,7 +964,7 @@ - @@ -911,6 +978,11 @@ left="0" mouse_opaque="true" name="Official Linden Blog..." width="166"> + + + + + @@ -919,8 +991,7 @@ - + @@ -930,11 +1001,7 @@ width="166"> - - - - + @@ -942,56 +1009,64 @@ left="0" mouse_opaque="true" name="Public Issue Tracker..." width="166"> + + - + userdata="WebLaunchSinguIssue,http://links.singularityviewer.org/?to=issues" /> - + + + + - + + - + + userdata="WebLaunchSinguIssue,https://singularityviewer.atlassian.net/secure/CreateIssue!default.jspa?issuetype=1" /> - + - + + + + - + @@ -1004,13 +1079,25 @@ - + + + + + - - + + + + + + + + + @@ -1023,18 +1110,18 @@ + + + + - - + + - - - - - - + + diff --git a/indra/newview/skins/default/xui/en-us/mime_types_linux.xml b/indra/newview/skins/default/xui/en-us/mime_types_linux.xml index e95b371d00..22a0024874 100644 --- a/indra/newview/skins/default/xui/en-us/mime_types_linux.xml +++ b/indra/newview/skins/default/xui/en-us/mime_types_linux.xml @@ -7,7 +7,7 @@ none - media_plugin_webkit + media_plugin_cef + + + + none/none + + + icn_media_web.tga + + + No media here + + + + false + + + false + +
  • ...